#include #include #include #include "defc.h" enum modes { none = 0, reg = 1 << 1, indir_reg = 1 << 2, reg_imm = 1 << 3, relative = 1 << 4 }; static word32 to_hex(const char *iter, const char *end) { word32 rv = 0; while(iter != end) { char c = *iter++; rv <<= 4; if (isdigit(c)) rv |= c - '0'; else rv |= (c | 0x20) - 'a' + 10; } return rv; } const char *ltrim(const char *cp) { while (isspace(*cp)) ++cp; return cp; } /*!re2c re2c:define:YYCTYPE = char; re2c:yyfill:enable = 0; eol = "\x00"; ws = [ \t]; x = [A-Fa-f0-9]; */ const char *parse_pc(const char *cp, uint32_t *pc) { const char *YYCURSOR = cp; const char *YYMARKER = NULL; const char *YYCTXMARKER = NULL; if (isspace(*cp)) return ltrim(cp); /*!re2c * { return NULL; } x{4} ':' { *pc &= 0xff0000; *pc |= to_hex(cp, YYCURSOR - 1); goto next; } x{6} ':' { *pc = to_hex(cp, YYCURSOR - 1); goto next; } x{2} '/' x{4} ':' { uint32_t tmp = to_hex(cp, cp + 2) << 16; tmp |= to_hex(cp + 3, YYCURSOR - 1); *pc = tmp; goto next; } */ next: return ltrim(YYCURSOR); } const char *parse_opcode(const char *cp, int *opcode, int *mode) { int op = -1; int m = 0; unsigned c; const char *YYCURSOR = cp; const char *YYMARKER = NULL; const char *YYCTXMARKER = NULL; /* TODO - db, dw ? */ /*!re2c * { return NULL; } 'set' { op = 0x10; m = reg_imm; goto next; } 'ld' { op = 0x20; m = reg | indir_reg; goto next; } 'st' { op = 0x30; m = reg | indir_reg; goto next; } 'ldd' { op = 0x60; m = indir_reg; goto next; } 'std' { op = 0x70; m = indir_reg; goto next; } 'pop' { op = 0x80; m = indir_reg; goto next; } 'stp' { op = 0x90; m = indir_reg; goto next; } 'add' { op = 0xa0; m = reg; goto next; } 'sub' { op = 0xb0; m = reg; goto next; } 'popd' { op = 0xc0; m = indir_reg; goto next; } 'cpr' { op = 0xd0; m = reg; goto next; } 'inr' { op = 0xe0; m = reg; goto next; } 'dcr' { op = 0xf0; m = reg; goto next; } 'rtn' { op = 0x00; goto next; } 'br' { op = 0x01; m = relative; goto next; } 'bnc' { op = 0x02; m = relative; goto next; } 'bc' { op = 0x03; m = relative; goto next; } 'bp' { op = 0x04; m = relative; goto next; } 'bm' { op = 0x05; m = relative; goto next; } 'bz' { op = 0x06; m = relative; goto next; } 'bnz' { op = 0x07; m = relative; goto next; } 'bm1' { op = 0x08; m = relative; goto next; } 'bnm1' { op = 0x09; m = relative; goto next; } 'bk' { op = 0x0a; goto next; } 'rs' { op = 0x0b; goto next; } 'bs' { op = 0x0c; m = relative; goto next; } */ next: c = *YYCURSOR; if (c && !isspace(c)) return NULL; *opcode = op; *mode = m; return ltrim(YYCURSOR); } const char *parse_register(const char *cp, int *opcode) { const char *YYCURSOR = cp; const char *YYMARKER = NULL; const char *YYCTXMARKER = NULL; /*!re2c * { return NULL; } 'R' ([0-9]{1,2}) { int r = 0; for(cp = cp + 1; cp < YYCURSOR; ++cp) { r = r * 10 + *cp - '0'; } if (r > 15) return NULL; *opcode |= r; goto next; } /* 'R' x { int r = to_hex(cp + 1, YYCURSOR); *opcode |= r; goto next; } */ 'ACC' { *opcode |= 0x00; goto next; } 'PC' { *opcode |= 0x0f; goto next; } 'SR' { *opcode |= 0x0e; goto next; } */ next: return ltrim(YYCURSOR); } const char *parse_address(const char *cp, int *address, int pc) { const char *YYCURSOR = cp; const char *YYMARKER = NULL; const char *YYCTXMARKER = NULL; int ea = 0; /*!re2c * { return NULL; } '*' { ea = pc; goto next; } '*' [+-] x{1,4} { ea = to_hex(cp + 2, YYCURSOR); if (cp[1] == '+') ea += pc; else ea -= pc; goto next; } x{1,4} { ea = to_hex(cp, YYCURSOR); goto next; } */ next: *address = ea & 0xffff; return ltrim(YYCURSOR); } uint32_t sweet16_disasm(uint32_t addr, int lines) { unsigned op; const char *opcode; unsigned mode = none; unsigned operand; unsigned x; int i; uint8_t bytes[4]; while (lines--) { unsigned size = 0; uint32_t pc = addr; op = get_memory_c(addr++, 0); bytes[size++] = op; switch (op >> 4) { case 0x00: switch(op) { case 0x00: opcode = "RTN"; break; case 0x01: opcode = "BR"; mode = relative; break; case 0x02: opcode = "BNC"; mode = relative; break; case 0x03: opcode = "BC"; mode = relative; break; case 0x04: opcode = "BP"; mode = relative; break; case 0x05: opcode = "BM"; mode = relative; break; case 0x06: opcode = "BZ"; mode = relative; break; case 0x07: opcode = "BNZ"; mode = relative; break; case 0x08: opcode = "BM1"; mode = relative; break; case 0x09: opcode = "BNM1"; mode = relative; break; case 0x0a: opcode = "BK"; break; case 0x0b: opcode = "RS"; break; case 0x0c: opcode = "BS"; mode = relative; break; case 0x0d: opcode = "???"; break; case 0x0e: opcode = "???"; break; case 0x0f: opcode = "???"; break; } break; case 0x01: opcode = "SET"; mode = reg_imm; break; case 0x02: opcode = "LD"; mode = reg; break; case 0x03: opcode = "ST"; mode = reg; break; case 0x04: opcode = "LD"; mode = indir_reg; break; case 0x05: opcode = "ST"; mode = indir_reg; break; case 0x06: opcode = "LDD"; mode = indir_reg; break; case 0x07: opcode = "STD"; mode = indir_reg; break; case 0x08: opcode = "POP"; mode = indir_reg; break; case 0x09: opcode = "STP"; mode = indir_reg; break; case 0x0a: opcode = "ADD"; mode = reg; break; case 0x0b: opcode = "SUB"; mode = reg; break; case 0x0c: opcode = "POPD"; mode = indir_reg; break; case 0x0d: opcode = "CPR"; mode = reg; break; case 0x0e: opcode = "INR"; mode = reg; break; case 0x0f: opcode = "DCR"; mode = reg; break; } switch(mode) { case none: case reg: case indir_reg: break; case relative: operand = (int8_t)get_memory_c(addr++, 0); bytes[size++] = operand; operand += addr; operand &= 0xffff; break; case reg_imm: operand = get_memory16_c(addr, 0); addr += 2; bytes[size++] = operand & 0xff; bytes[size++] = operand >> 8; break; } x = printf("%02x/%04x:", pc >> 16, pc & 0xffff); for (i = 0; i < size; ++i) { x += printf(" %02x", bytes[i]); } for( ; x < 20; ++x) fputc(' ', stdout); printf("%-5s", opcode); switch(mode) { case none: break; case reg: x += printf("R%d", op & 0x0f); break; case indir_reg: x += printf("@R%d", op & 0x0f); break; case relative: x += printf("%04x", operand); break; case reg_imm: x += printf("R%d, %04x", op & 0x0f, operand); break; } fputc('\n', stdout); } return addr; } static int error(int offset, const char *msg) { while (offset > 0) { fputc(' ', stderr); --offset; } fputs(" ^", stderr); fputs(msg, stderr); fputc('\n', stderr); return -1; } int parse_line(const char *cp, uint32_t *pc) { uint32_t addr = *pc; int opcode; int operand; int indir = 0; int mode = 0; int i; unsigned offset = 0; const char *start = cp; uint8_t bytes[3]; int size = 0; cp = parse_pc(cp, &addr); if (!cp) return error(0, "error"); offset = cp - start; /* label only? */ if (!*cp) { *pc = addr; return 0; } cp = parse_opcode(cp, &opcode, &mode); if (!cp) return error(offset, "bad opcode"); offset = cp - start; if (mode & (reg | indir_reg | reg_imm)) { if (*cp == '@') { indir = 1; ++cp; } cp = parse_register(cp, &opcode); if (!cp) return error(offset, "bad register"); offset = cp - start; /* cleanup indir */ /* LD / ST */ if (indir && mode == (reg|indir_reg)) { opcode += 0x20; mode = indir_reg; } if ((mode == indir_reg) != indir) return error(offset, "bad operand"); } bytes[size++] = opcode; if (mode == reg_imm) { if (*cp++ != ',') return error(offset, "expected ,"); cp = ltrim(cp); offset = cp - start; } if (mode & (relative | reg_imm)) { cp = parse_address(cp, &operand, addr); if (!cp) return error(offset, "bad operand"); offset = cp - start; if (mode == relative) { int tmp = (addr + 2) & 0xffff; operand -= tmp; if (operand > 127 || operand < -128) return error(offset, "out of range"); bytes[size++] = operand; } else { bytes[size++] = operand & 0xff; bytes[size++] = operand >> 8; } } if (!cp) return error(offset, "bad operand"); for (i = 0; i < size; ++i) { set_memory_c(addr + i, bytes[i], 0); } *pc = addr + size; fputs("\r\x1b[A\x1b[K", stdout); sweet16_disasm(addr, 1); return 1; } extern char *x_readline(const char *prompt); uint32_t sweet16_asm_shell(uint32_t addr) { printf("%02x/%04x:\n", addr >> 16, addr & 0xffff); for(;;) { const char *cp = x_readline("!!"); if (!cp || !*cp) return addr; parse_line(cp, &addr); } }