Files
GKERN/toolchain/assembler.c
T

53 lines
2.8 KiB
C
Raw Normal View History

2026-07-09 13:28:07 -04:00
#define _GNU_SOURCE
#include "assembler.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
typedef struct { const char *mnemonic; uint8_t family_id; uint8_t sub_id; uint8_t opclass; ExtKind ext_kind; } MnemonicEntry;
static const MnemonicEntry MNEMONICS[] = {
{"REGION_NEW", 4, 0, 0, EXT_STORE}, {"REGION_FILL_ASC", 5, 2, 0, EXT_NONE}, {"REGION_FILL_NOISE", 5, 3, 0, EXT_NONE}, {"REGION_FILL_CONST", 5, 4, 0, EXT_NONE},
{"ADD", 8, 0, 1, EXT_NONE}, {"HALT", 20, 0, 2, EXT_NONE}, {NULL, 0, 0, 0, EXT_NONE}
};
void asm_init(Assembler *as) { memset(as, 0, sizeof(Assembler)); }
static const MnemonicEntry *lookup_mnemonic(const char *name) { for (int i = 0; MNEMONICS[i].mnemonic != NULL; i++) if (strcasecmp(name, MNEMONICS[i].mnemonic) == 0) return &MNEMONICS[i]; return NULL; }
static int parse_operand(Assembler *as, const char *tok, uint8_t *out) {
if (tok[0] == '%' && (tok[1] == 'r' || tok[1] == 'R')) { *out = (uint8_t)atoi(tok + 2); return 0; }
*out = (uint8_t)(atoi(tok) & 0xFF); return 0;
}
static void process_line(Assembler *as, char *line) {
char *comment = strchr(line, ';'); if (comment) *comment = '\0';
while (*line && isspace(*line)) line++; if (*line == '\0') return;
char *tokens[MAX_TOKENS]; int ntokens = 0; char *save;
char *tok = strtok_r(line, " \t,\n\r", &save);
while (tok && ntokens < MAX_TOKENS) { tokens[ntokens++] = tok; tok = strtok_r(NULL, " \t,\n\r", &save); }
if (ntokens == 0) return;
char mnemonic[64]; strncpy(mnemonic, tokens[0], sizeof(mnemonic) - 1); mnemonic[63] = '\0';
const MnemonicEntry *entry = lookup_mnemonic(mnemonic);
if (!entry) { if (as->pass == 1) fprintf(stderr, "Unknown mnemonic: %s\n", mnemonic); return; }
uint8_t op_a = 0, op_b = 0;
if (ntokens >= 2) parse_operand(as, tokens[1], &op_a);
if (ntokens >= 3) parse_operand(as, tokens[2], &op_b);
uint32_t word = glyph_encode(entry->family_id, entry->sub_id, MODE_USER, entry->opclass, glyph_encode_ops(op_a, op_b));
if (as->pass == 1 && as->code_len < MAX_CODE_SIZE) as->code[as->code_len] = word;
as->code_len++;
}
int asm_assemble(Assembler *as, const char *path) {
as->filename = path;
for (int pass = 0; pass <= 1; pass++) {
as->pass = pass; if (pass == 1) as->code_len = 0;
FILE *f = fopen(path, "r"); if (!f) return -1;
char line[MAX_LINE]; as->line_num = 0;
while (fgets(line, sizeof(line), f)) { as->line_num++; process_line(as, line); }
fclose(f);
}
return 0;
}
int asm_write_gobj(Assembler *as, const char *path) {
FILE *f = fopen(path, "wb"); if (!f) return -1;
GobjHeader hdr; memcpy(hdr.magic, GOBJ_MAGIC, 8); hdr.version = GOBJ_VERSION; hdr.code_len = as->code_len; hdr.ext_len = as->ext_len;
fwrite(&hdr, sizeof(GobjHeader), 1, f); fwrite(as->code, sizeof(uint32_t), as->code_len, f);
fclose(f); return 0;
}