diff options
author | Juan J. Martinez <jjm@usebox.net> | 2023-05-01 13:50:52 +0100 |
---|---|---|
committer | Juan J. Martinez <jjm@usebox.net> | 2023-05-01 13:58:09 +0100 |
commit | 8998bd04c94da08dc49ab62007da5604d53895c3 (patch) | |
tree | 43a588f7a372ce17d035536a56fd71691fa6a73f /tr8as.c | |
download | tr8vm-8998bd04c94da08dc49ab62007da5604d53895c3.tar.gz tr8vm-8998bd04c94da08dc49ab62007da5604d53895c3.zip |
Initial import
Diffstat (limited to 'tr8as.c')
-rw-r--r-- | tr8as.c | 1341 |
1 files changed, 1341 insertions, 0 deletions
@@ -0,0 +1,1341 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <strings.h> +#include <ctype.h> + +#define MAX_LINE 1024 +#define MAX_ID 0x40 +#define MAX_LABELS 0x200 +#define MAX_REFS 0x1000 + +#define FHH 2 +#define FHL 1 +#define FL 32 + +typedef struct +{ + const char *filename; + uint16_t line; +} Location; + +typedef struct +{ + char id[MAX_ID + 1]; + uint16_t addr; + Location loc; +} Label; + +typedef enum +{ + ModNone = 0, + ModLow, + ModHigh +} Mod; + +typedef struct +{ + char id[MAX_ID + 1]; + Mod mod; + uint16_t mask; + uint16_t addr; + Location loc; +} Reference; + +typedef struct +{ + uint8_t out[UINT16_MAX + 1]; + size_t size; + + uint16_t addr; + Location loc; + + Label labels[MAX_LABELS]; + uint16_t lcnt; + + Reference refs[MAX_REFS]; + uint16_t rcnt; +} As; + +typedef struct +{ + char id[5]; + uint8_t (*parse)(As *, char *); +} InstParse; + +static uint8_t error_l(const char *msg, Location *loc, const char *reason) +{ + fprintf(stderr, "%s (%s:%d): %s\n", msg, loc->filename, loc->line, reason); + return 0; +} + +static uint8_t error(const char *msg, const char *reason) +{ + if (reason == NULL) + fprintf(stderr, "error: %s\n", msg); + else + fprintf(stderr, "%s: %s\n", msg, reason); + return 0; +} + +static char * skip_whitespace(char *c) +{ + while (*c && isspace(*c)) + c++; + return c; +} + +static uint8_t isspecial(char c) +{ + return c == '$' || c == '_' || c == '.' || c == '#' || c == '<' || c == '>'; +} + +static char * next_word(char *c, char *word, uint8_t *wlen) +{ + c = skip_whitespace(c); + + *wlen = 0; + while (*c && (isalnum(*c) || isspecial(*c))) + { + word[(*wlen)++] = *c++; + if (*wlen == MAX_ID) + { + /* XXX: should be an error? */ + break; + } + } + word[*wlen] = 0; + + return c; +} + +static uint8_t next_imm(char *word, uint16_t *n) +{ + *n = 0; + + if (*word == '0') + { + /* hex */ + if (word[1] == 'x') + { + word += 2; + while (*word) + { + if (*word >= '0' && *word <= '9') + *n = (*n) * 16 + (*word - '0'); + else if (*word >= 'a' && *word <= 'f') + *n = (*n) * 16 + 10 + (*word - 'a'); + else if (*word >= 'A' && *word <= 'F') + *n = (*n) * 16 + 10 + (*word - 'A'); + else + break; + + word++; + } + return *word; + } + /* bin */ + else if (word[1] == 'b') + { + word += 2; + while (*word) + { + if (*word == '0' || *word == '1') + *n = (*n) * 2 + (*word - '0'); + else + break; + + word++; + } + return *word; + } + } + + /* dec */ + while (*word) + { + if (*word >= '0' && *word <= '9') + *n = (*n) * 10 + (*word - '0'); + else + break; + + word++; + } + + return *word; +} + +static uint8_t parse_register(char *word) +{ + if (!strcasecmp(word, "a")) + return 0; + if (!strcasecmp(word, "b")) + return 1; + if (!strcasecmp(word, "x")) + return 2; + if (!strcasecmp(word, "y")) + return 3; + + return 0xff; +} + +static Label * find_label(As *as, char *word) +{ + uint8_t i; + + for (i = 0; i < as->lcnt; i++) + if (!strcmp(word, as->labels[i].id)) + return &as->labels[i]; + + return NULL; +} + +static uint8_t new_label(As *as, char *word) +{ + if (find_label(as, word)) + return error_l("Label redefined", &as->loc, word); + + strcpy(as->labels[as->lcnt].id, word); + + as->labels[as->lcnt].loc.filename = as->loc.filename; + as->labels[as->lcnt].loc.line = as->loc.line; + as->labels[as->lcnt++].addr = as->addr; + + if (as->lcnt == MAX_LABELS) + return error("Too many labels", NULL); + + return 1; +} + +static uint8_t new_ref(As *as, char *word, uint16_t mask, uint16_t addr) +{ + Mod mod = ModNone; + char *pt = word; + + if (*pt == '<') + { + mod = ModLow; + pt++; + } + else if (*pt == '>') + { + mod = ModHigh; + pt++; + } + + if (!*pt) + return error_l("Syntax error", &as->loc, "expected label"); + + if (mask == 0xff && mod == ModNone) + return error_l("Overflow in immediate", &as->loc, word); + + strcpy(as->refs[as->rcnt].id, pt); + as->refs[as->rcnt].mod = mod; + as->refs[as->rcnt].mask = mask; + as->refs[as->rcnt].loc = as->loc; + as->refs[as->rcnt++].addr = addr; + + if (as->rcnt == MAX_REFS) + return error("Too many references", NULL); + + return 1; +} + +static uint8_t resolve(As *as) +{ + uint16_t i; + uint16_t v; + Label *label; + + for (i = 0; i < as->rcnt; i++) + { + label = find_label(as, as->refs[i].id); + if (!label) + return error_l("Unresolved reference", &as->refs[i].loc, as->refs[i].id); + + v = label->addr; + switch (as->refs[i].mod) + { + case ModLow: + v &= 0xff; + break; + case ModHigh: + v >>= 8; + break; + default: + break; + } + as->out[as->refs[i].addr] = v & 0xff; + if (as->refs[i].mask == 0xffff) + as->out[as->refs[i].addr + 1] = v >> 8; + } + + return 1; +} + +/* + * inst: instruction opcode + * p1: r1 + * p2: either FHx or r2 + * p3: either FL, r3 or immediate + */ +static void emit(As *as, uint8_t instr, uint8_t p1, uint8_t p2, uint8_t p3) +{ + as->out[as->addr++] = p3; + as->out[as->addr++] = (instr << 4) | (p1 << 2) | p2; + if (as->addr > as->size) + as->size = as->addr; +} + +static void emit_imm(As *as, uint16_t imm) +{ + as->out[as->addr++] = imm & 0xff; + as->out[as->addr++] = imm >> 8; + if (as->addr > as->size) + as->size = as->addr; +} + +static uint8_t parse_org(As *as, char *c) +{ + char word[MAX_ID + 1]; + uint8_t wlen; + + /* .org imm */ + + next_word(c, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected immediate"); + + if (next_imm(word, &as->addr)) + return error_l("Syntax error", &as->loc, word); + + if (as->addr > as->size) + as->size = as->addr; + + return 1; +} + +static uint8_t parse_db(As *as, char *c) +{ + char word[MAX_ID + 1]; + char *pt; + uint8_t wlen; + uint16_t imm = 0xff; + + /* .db imm [, imm] */ + + pt = c; + while (1) + { + pt = next_word(pt, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected immediate"); + + if (isdigit(*word)) + { + if (next_imm(word, &imm)) + return error_l("Syntax error", &as->loc, word); + + if (imm > 0xff) + return error_l("Overflow in immediate", &as->loc, word); + } + else if (!new_ref(as, word, 0xff, as->addr)) + return 0; + + as->out[as->addr++] = imm & 0xff; + if (as->addr > as->size) + as->size = as->addr; + + if (*pt == ',') + { + pt++; + continue; + } + break; + } + + return 1; +} + +static uint8_t parse_dw(As *as, char *c) +{ + char word[MAX_ID + 1]; + char *pt; + uint8_t wlen; + uint16_t imm; + + /* .dw imm [, imm] */ + + pt = c; + while (1) + { + pt = next_word(pt, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected immediate"); + + if (isdigit(*word)) + { + if (next_imm(word, &imm)) + return error_l("Syntax error", &as->loc, word); + } + else if (!new_ref(as, word, 0xffff, as->addr)) + return 0; + + as->out[as->addr++] = imm & 0xff; + as->out[as->addr++] = imm >> 8; + if (as->addr > as->size) + as->size = as->addr; + + if (*pt == ',') + { + pt++; + continue; + } + break; + } + + return 1; +} + +static uint8_t parse_nop(As *as, char *c) +{ + /* NOP */ + emit(as, 0, 0, 0, 0); + return 1; +} + +static uint8_t parse_sif(As *as, char *c) +{ + /* SIF */ + emit(as, 11, 0, FHL, 0); + return 1; +} + +static uint8_t parse_cif(As *as, char *c) +{ + /* CIF */ + emit(as, 11, 0, 0, 0); + return 1; +} + +static uint8_t parse_ccf(As *as, char *c) +{ + /* CCF */ + emit(as, 13, 0, FHH | FHL, 0); + return 1; +} + +static uint8_t parse_scf(As *as, char *c) +{ + /* SCF */ + emit(as, 13, 0, FHH, 0); + return 1; +} + +static uint8_t parse_sof(As *as, char *c) +{ + /* SOF */ + emit(as, 13, 0, FHL, 0); + return 1; +} + +static uint8_t parse_cof(As *as, char *c) +{ + /* COF */ + emit(as, 13, 0, 0, 0); + return 1; +} + +static uint8_t parse_halt(As *as, char *c) +{ + /* HALT */ + emit(as, 0, 0, FHH | FHL, 0); + return 1; +} + +static uint8_t parse_iret(As *as, char *c) +{ + /* IRET */ + emit(as, 0, 0, FHL, 0); + return 1; +} + +static uint8_t parse_ret(As *as, char *c) +{ + /* RET */ + emit(as, 0, 0, 0, FL); + return 1; +} + +static uint8_t parse_r1_r2_or_imm(As *as, char *c, uint8_t *r1, uint8_t *r2, uint16_t *imm) +{ + char word[MAX_ID + 1]; + char *pt; + uint8_t wlen; + + /* ? r1, ? */ + pt = next_word(c, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected register"); + + *r1 = parse_register(word); + if (*r1 == 0xff) + return error_l("Syntax error", &as->loc, word); + + pt = skip_whitespace(pt); + if (*pt != ',') + return error_l("Syntax error", &as->loc, "expected ,"); + pt++; + + pt = next_word(pt, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected register or immediate"); + + /* ? r1, r2 */ + *r2 = parse_register(word); + if (*r2 != 0xff) + return 1; + + /* ? r1, imm */ + if (isdigit(*word)) + { + if (next_imm(word, imm)) + return error_l("Syntax error", &as->loc, word); + + if (*imm > 0xff) + return error_l("Overflow in immediate", &as->loc, word); + } + /* AND r1, label */ + else if (!new_ref(as, word, 0xff, as->addr + 1)) + return 0; + + return 1; +} + +static uint8_t parse_r1_imm(As *as, char *c, uint8_t *r1, uint16_t *imm) +{ + char word[MAX_ID + 1]; + char *pt; + uint8_t wlen; + + /* ? r1, imm */ + pt = next_word(c, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected register"); + + *r1 = parse_register(word); + if (*r1 == 0xff) + return error_l("Syntax error", &as->loc, word); + + pt = skip_whitespace(pt); + if (*pt != ',') + return error_l("Syntax error", &as->loc, "expected ,"); + pt++; + + pt = next_word(pt, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected immediate"); + + if (!isdigit(*word)) + return error_l("Syntax error", &as->loc, "expected immediate"); + + if (next_imm(word, imm)) + return error_l("Syntax error", &as->loc, word); + + return 1; +} + +static uint8_t parse_and(As *as, char *c) +{ + uint16_t imm = 0xff; + uint8_t r1, r2; + + if (!parse_r1_r2_or_imm(as, c, &r1, &r2, &imm)) + return 0; + + if (r2 != 0xff) + /* AND r1, r2 */ + emit(as, 4, r1, FHH | FHL, (r2 << 6)); + else + /* AND r1, imm */ + emit(as, 4, r1, FHH, imm); + + return 1; +} + +static uint8_t parse_or(As *as, char *c) +{ + uint16_t imm = 0xff; + uint8_t r1, r2; + + if (!parse_r1_r2_or_imm(as, c, &r1, &r2, &imm)) + return 0; + + if (r2 != 0xff) + /* OR r1, r2 */ + emit(as, 4, r1, FHL, (r2 << 6)); + else + /* OR r1, imm */ + emit(as, 4, r1, 0, imm); + + return 1; +} + +static uint8_t parse_xor(As *as, char *c) +{ + uint16_t imm = 0xff; + uint8_t r1, r2; + + if (!parse_r1_r2_or_imm(as, c, &r1, &r2, &imm)) + return 0; + + if (r2 != 0xff) + /* XOR r1, r2 */ + emit(as, 5, r1, FHH | FHL, (r2 << 6)); + else + /* XOR r1, imm */ + emit(as, 5, r1, FHH, imm); + + return 1; +} + +static uint8_t parse_cmp(As *as, char *c) +{ + uint16_t imm = 0xff; + uint8_t r1, r2; + + if (!parse_r1_r2_or_imm(as, c, &r1, &r2, &imm)) + return 0; + + if (r2 != 0xff) + /* CMP r1, r2 */ + emit(as, 5, r1, FHL, (r2 << 6)); + else + /* CMP r1, imm */ + emit(as, 5, r1, 0, imm); + + return 1; +} + +static uint8_t parse_add(As *as, char *c) +{ + uint16_t imm = 0xff; + uint8_t r1, r2; + + if (!parse_r1_r2_or_imm(as, c, &r1, &r2, &imm)) + return 0; + + if (r2 != 0xff) + /* ADD r1, r2 */ + emit(as, 6, r1, FHH | FHL, (r2 << 6)); + else + /* ADD r1, imm */ + emit(as, 6, r1, FHH, imm); + + return 1; +} + +static uint8_t parse_sub(As *as, char *c) +{ + uint16_t imm = 0xff; + uint8_t r1, r2; + + if (!parse_r1_r2_or_imm(as, c, &r1, &r2, &imm)) + return 0; + + if (r2 != 0xff) + /* SUB r1, r2 */ + emit(as, 6, r1, FHL, (r2 << 6)); + else + /* SUB r1, imm */ + emit(as, 6, r1, 0, imm); + + return 1; +} + +static uint8_t parse_bit(As *as, char *c) +{ + uint16_t imm = 0xff; + uint8_t r1; + + /* BIT r1, imm */ + if (!parse_r1_imm(as, c, &r1, &imm)) + return 0; + + if (imm > 7) + return error_l("Immediate out of range", &as->loc, "expected bit (0-7)"); + + emit(as, 7, r1, FHH, imm); + return 1; +} + +static uint8_t parse_shl(As *as, char *c) +{ + uint16_t imm = 0xff; + uint8_t r1; + + /* SHL r1, imm */ + if (!parse_r1_imm(as, c, &r1, &imm)) + return 0; + + if (imm > 7) + return error_l("Immediate out of range", &as->loc, "expected bit (0-7)"); + + emit(as, 7, r1, FHL, imm); + return 1; +} + +static uint8_t parse_shr(As *as, char *c) +{ + uint16_t imm = 0xff; + uint8_t r1; + + /* SHR r1, imm */ + if (!parse_r1_imm(as, c, &r1, &imm)) + return 0; + + if (imm > 7) + return error_l("Immediate out of range", &as->loc, "expected bit (0-7)"); + + emit(as, 7, r1, 0, imm); + return 1; +} + +static uint8_t parse_ror(As *as, char *c) +{ + uint16_t imm = 0xff; + uint8_t r1; + + /* ROR r1, imm */ + if (!parse_r1_imm(as, c, &r1, &imm)) + return 0; + + if (imm > 7) + return error_l("Immediate out of range", &as->loc, "expected bit (0-7)"); + + emit(as, 8, r1, 0, imm); + return 1; +} + +static uint8_t parse_rol(As *as, char *c) +{ + uint16_t imm = 0xff; + uint8_t r1; + + /* ROL r1, imm */ + if (!parse_r1_imm(as, c, &r1, &imm)) + return 0; + + if (imm > 7) + return error_l("Immediate out of range", &as->loc, "expected bit (0-7)"); + + emit(as, 8, r1, FHH, imm); + return 1; +} + +static uint8_t parse_push(As *as, char *c) +{ + char word[MAX_ID + 1]; + uint8_t wlen; + uint8_t r1; + + /* PUSH r1 */ + next_word(c, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected register"); + + r1 = parse_register(word); + if (r1 == 0xff) + { + /* PUSH F */ + if (*word == 'f' || *word == 'F') + { + emit(as, 3, 0, FHH | FHL, 0); + return 1; + } + return error_l("Syntax error", &as->loc, word); + } + + emit(as, 3, r1, FHL, 0); + return 1; +} + +static uint8_t parse_port(As *as, char *c) +{ + char word[MAX_ID + 1]; + uint8_t wlen; + uint8_t r1, r2; + + /* PORT r1, r2 */ + next_word(c, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected register"); + + r1 = parse_register(word); + if (r1 == 0xff) + return error_l("Syntax error", &as->loc, word); + + next_word(c, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected register"); + + r2 = parse_register(word); + if (r2 == 0xff) + return error_l("Syntax error", &as->loc, word); + + emit(as, 0, r1, FHH, r2); + return 1; +} + +static uint8_t parse_pop(As *as, char *c) +{ + char word[MAX_ID + 1]; + uint8_t wlen; + uint8_t r1; + + /* POP r1 */ + next_word(c, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected register"); + + r1 = parse_register(word); + if (r1 == 0xff) + { + /* POP F */ + if (*word == 'f' || *word == 'F') + { + emit(as, 3, 0, FHH, 0); + return 1; + } + return error_l("Syntax error", &as->loc, word); + } + + emit(as, 3, r1, 0, 0); + return 1; +} + +static uint8_t parse_xsp(As *as, char *c) +{ + char word[MAX_ID + 1]; + uint8_t wlen; + uint8_t r1; + + /* XSP r1 */ + next_word(c, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected register"); + + r1 = parse_register(word); + if (r1 == 0xff) + return error_l("Syntax error", &as->loc, word); + + emit(as, 3, r1, 0, FL); + return 1; +} + +static uint8_t parse_inc(As *as, char *c) +{ + char word[MAX_ID + 1]; + uint8_t wlen; + uint8_t r1; + + /* INC r1 */ + next_word(c, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected register"); + + r1 = parse_register(word); + if (r1 == 0xff) + return error_l("Syntax error", &as->loc, word); + + emit(as, 11, r1, FHH | FHL, 0); + return 1; +} + +static uint8_t parse_dec(As *as, char *c) +{ + char word[MAX_ID + 1]; + uint8_t wlen; + uint8_t r1; + + /* INC r1 */ + next_word(c, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected register"); + + r1 = parse_register(word); + if (r1 == 0xff) + return error_l("Syntax error", &as->loc, word); + + emit(as, 11, r1, FHH, 0); + return 1; +} + +static uint8_t parse_bz(As *as, char *c) +{ + /* BZ */ + emit(as, 10, 0, 0, 0); + return 1; +} + +static uint8_t parse_bnz(As *as, char *c) +{ + /* BNZ */ + emit(as, 10, 0, FHH, 0); + return 1; +} + +static uint8_t parse_bc(As *as, char *c) +{ + /* BC */ + emit(as, 10, 0, 0, 1); + return 1; +} + +static uint8_t parse_bnc(As *as, char *c) +{ + /* BNC */ + emit(as, 10, 0, FHH, 1); + return 1; +} + +static uint8_t parse_bo(As *as, char *c) +{ + /* BO */ + emit(as, 10, 0, 0, 2); + return 1; +} + +static uint8_t parse_bno(As *as, char *c) +{ + /* BNO */ + emit(as, 10, 0, FHH, 2); + return 1; +} + +static uint8_t parse_bs(As *as, char *c) +{ + /* BS */ + emit(as, 10, 0, 0, 3); + return 1; +} + +static uint8_t parse_bns(As *as, char *c) +{ + /* BNS */ + emit(as, 10, 0, FHH, 3); + return 1; +} + +static uint8_t parse_bi(As *as, char *c) +{ + /* BI */ + emit(as, 10, 0, 0, 4); + return 1; +} + +static uint8_t parse_bni(As *as, char *c) +{ + /* BNI */ + emit(as, 10, 0, FHH, 4); + return 1; +} + +static uint8_t parse_indirect(As *as, char **c, uint8_t *r1, uint8_t *r2, uint16_t *imm) +{ + char word[MAX_ID + 1]; + uint8_t wlen; + + /* [r1:r2] */ + *c = next_word(*c, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected register"); + + *r1 = parse_register(word); + if (*r1 == 0xff) + { + if (imm == NULL) + return error_l("Syntax error", &as->loc, word); + + /* [SP + imm] */ + if (!strcasecmp(word, "sp")) + { + *c = skip_whitespace(*c); + if (**c != '+') + return error_l("Syntax error", &as->loc, "expected +"); + (*c)++; + + *c = next_word(*c, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected immediate"); + + if (!isdigit(*word)) + return error_l("Syntax error", &as->loc, "expected immediate"); + + if (next_imm(word, imm)) + return error_l("Syntax error", &as->loc, word); + + if (*imm > 0xff) + return error_l("Overflow in immediate", &as->loc, word); + + *c = skip_whitespace(*c); + if (**c != ']') + return error_l("Syntax error", &as->loc, "expected ]"); + (*c)++; + + return 1; + } + else + return error_l("Syntax error", &as->loc, word); + } + + *c = skip_whitespace(*c); + if (**c != ':') + return error_l("Syntax error", &as->loc, "expected :"); + + *c = next_word(*c + 1, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected register"); + + *r2 = parse_register(word); + if (*r2 == 0xff) + return error_l("Syntax error", &as->loc, word); + + *c = skip_whitespace(*c); + if (**c != ']') + return error_l("Syntax error", &as->loc, "expected ]"); + + (*c)++; + return 1; +} + +static uint8_t parse_jmp(As *as, char *c) +{ + char word[MAX_ID + 1]; + char *pt; + uint8_t wlen; + uint16_t imm = 0xffff; + uint8_t r1, r2; + + pt = skip_whitespace(c); + + /* JMP [r1:r2] */ + if (*pt == '[') + { + pt++; + if (!parse_indirect(as, &pt, &r1, &r2, NULL)) + return 0; + + emit(as, 9, r1, 0, (r2 << 6) | FL); + return 1; + } + + next_word(pt, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected label or immediate"); + + /* JMP imm */ + if (isdigit(*word)) + { + if (next_imm(word, &imm)) + return error_l("Syntax error", &as->loc, word); + } + /* JMP label */ + else if (!new_ref(as, word, 0xffff, as->addr + 2)) + return 0; + + emit(as, 9, 0, FHH, FL); + emit_imm(as, imm); + return 1; +} + +static uint8_t parse_call(As *as, char *c) +{ + char word[MAX_ID + 1]; + char *pt; + uint8_t wlen; + uint16_t imm = 0xffff; + uint8_t r1, r2; + + pt = skip_whitespace(c); + + /* CALL [r1:r2] */ + if (*pt == '[') + { + pt++; + if (!parse_indirect(as, &pt, &r1, &r2, NULL)) + return 0; + + emit(as, 9, r1, 0, (r2 << 6)); + return 1; + } + + next_word(pt, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected label or immediate"); + + /* CALL imm */ + if (isdigit(*word)) + { + if (next_imm(word, &imm)) + return error_l("Syntax error", &as->loc, word); + } + /* CALL label */ + else if (!new_ref(as, word, 0xffff, as->addr + 2)) + return 0; + + emit(as, 9, 0, FHH, 0); + emit_imm(as, imm); + return 1; +} + +static uint8_t parse_ld(As *as, char *c) +{ + char word[MAX_ID + 1]; + char *pt; + uint8_t wlen; + uint16_t imm = 0xff; + + uint8_t r1, r2, r3; + + pt = skip_whitespace(c); + /* LD [r1:r2], r3 */ + /* LD [sp + imm], r2 */ + if (*pt == '[') + { + pt++; + if (!parse_indirect(as, &pt, &r1, &r2, &imm)) + return 0; + + /* expected , */ + pt = skip_whitespace(pt); + if (*pt != ',') + return error_l("Syntax error", &as->loc, "expected ,"); + + pt = next_word(pt + 1, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected register"); + + r3 = parse_register(word); + if (r3 == 0xff) + return error_l("Syntax error", &as->loc, word); + + if (r1 == 0xff) + emit(as, 12, r3, FHH, imm); + else + emit(as, 2, r1, r2, (r3 << 6) | FL); + return 1; + } + + /* LD r1, ? */ + pt = next_word(pt, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected register"); + + r1 = parse_register(word); + if (r1 == 0xff) + return error_l("Syntax error", &as->loc, word); + + pt = skip_whitespace(pt); + if (*pt != ',') + return error_l("Syntax error", &as->loc, "expected ,"); + pt++; + + pt = skip_whitespace(pt); + /* LD r1, [r2:r3] */ + /* LD r1, [sp + imm] */ + if (*pt == '[') + { + pt++; + if (!parse_indirect(as, &pt, &r2, &r3, &imm)) + return 0; + + if (r2 == 0xff) + emit(as, 12, r1, 0, imm); + else + emit(as, 2, r2, r3, r1 << 6); + return 1; + } + + pt = next_word(pt, word, &wlen); + if (wlen == 0) + return error_l("Syntax error", &as->loc, "expected register or immediate"); + + /* LD r1, r2 */ + r2 = parse_register(word); + if (r2 != 0xff) + { + emit(as, 1, r1, FHH, (r2 << 6)); + return 1; + } + + /* LD r1, imm */ + if (isdigit(*word)) + { + if (next_imm(word, &imm)) + return error_l("Syntax error", &as->loc, word); + + if (imm > 0xff) + return error_l("Overflow in immediate", &as->loc, word); + } + /* LD r1, label */ + else if (!new_ref(as, word, 0xff, as->addr + 1)) + return 0; + + emit(as, 1, r1, 0, imm); + return 1; +} + +static InstParse insts[] = { + { ".org", parse_org }, + { ".db", parse_db }, + { ".dw", parse_dw }, + { "halt", parse_halt }, + { "push", parse_push }, + { "port", parse_port }, + { "iret", parse_iret }, + { "call", parse_call }, + { "xsp", parse_xsp }, + { "and", parse_and }, + { "cmp", parse_cmp }, + { "add", parse_add }, + { "sub", parse_sub }, + { "bit", parse_bit }, + { "shl", parse_shl }, + { "shr", parse_shr }, + { "ror", parse_ror }, + { "rol", parse_rol }, + { "xor", parse_xor }, + { "ret", parse_ret }, + { "pop", parse_pop }, + { "nop", parse_nop }, + { "inc", parse_inc }, + { "dec", parse_dec }, + { "bnz", parse_bnz }, + { "bnc", parse_bnc }, + { "bno", parse_bno }, + { "bns", parse_bns }, + { "bni", parse_bni }, + { "jmp", parse_jmp }, + { "sif", parse_sif }, + { "cif", parse_cif }, + { "ccf", parse_ccf }, + { "scf", parse_scf }, + { "sof", parse_sof }, + { "cof", parse_cof }, + { "or", parse_or }, + { "bz", parse_bz }, + { "bc", parse_bc }, + { "bo", parse_bo }, + { "bs", parse_bs }, + { "bi", parse_bi }, + { "ld", parse_ld }, + { "", NULL }, +}; + +static uint8_t parse(As *as, char *c) +{ + char word[MAX_ID + 1]; + char *pt; + uint8_t wlen; + uint8_t i; + + pt = next_word(c, word, &wlen); + if (wlen == 0) + return 1; + + /* comment */ + if (word[0] == ';') + return 1; + + /* new label */ + if (*pt == ':') + { + pt++; + + if (!new_label(as, word)) + return 0; + } + else + { + /* instructions */ + for (i = 0; insts[i].parse; i++) + if (!strcasecmp(insts[i].id, word)) + return insts[i].parse(as, pt); + printf("NOPE %s\n", word); + + return error_l("Parse error", &as->loc, word); + } + + /* EOL */ + pt = next_word(pt, word, &wlen); + if (wlen == 0) + return 1; + + /* or comment */ + if (word[0] == ';') + return 1; + + return error_l("Parse error", &as->loc, word); +} + +static uint8_t asm(As *as, const char *filename, FILE *in) +{ + char line[MAX_LINE]; + memset(as, 0, sizeof(As)); + + as->loc.filename = filename; + + while (fgets(line, MAX_LINE - 1, in)) + { + as->loc.line++; + if (!parse(as, line)) + return 0; + } + + return resolve(as); +} + +#ifdef DO_MAIN + +int main(int argc, char *argv[]) +{ + int rc = 0; + FILE *src, *out; + As as; + + if (argc < 3) + { + error("usage", "input.asm output.tr8"); + return 1; + } + src = fopen(argv[1], "rt"); + if (!src) + { + error("Failed to open input", argv[1]); + return 1; + } + + if (asm(&as, argv[1], src)) + { + out = fopen(argv[2], "wb"); + if (!out) + { + fclose(src); + error("Failed to open output", argv[2]); + return 1; + } + fwrite(as.out, as.size, 1, out); + fclose(out); + + fprintf(stderr, "%s: %lu bytes, OK\n", argv[2], as.size); + } + else + rc = 11; + + fclose(src); + return rc; +} + +#endif /* DO_MAIN */ |