gateware

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit fc4a3ef24f1290d891318fdd293c5c9245bc3d1a
parent df5a81c80e88fe49c3d7bada90c93c9d5f14fd2c
Author: Brian Swetland <swetland@frotz.net>
Date:   Fri, 23 Nov 2018 17:45:50 -0800

isa16v4: rethink the instruction set architecture

- drop back to 8 registers from 16
- support three-argument alu ops across all registers
- use RISCV style immediate encoding (common s bit, etc)
- new ISA should require slightly simpler decode logic
- "ext" op loads a 12bit immediate to extend short immediates
  in the following opcode
- a16v4 and d16v4 assemble and disassemble the new ISA

Diffstat:
Adocs/isa16v4.txt | 28++++++++++++++++++++++++++++
Asrc/a16v4.c | 683+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/d16v4.c | 210+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test.s | 5+++++
4 files changed, 926 insertions(+), 0 deletions(-)

diff --git a/docs/isa16v4.txt b/docs/isa16v4.txt @@ -0,0 +1,28 @@ +instruction formats constant encodings alu opcodes +----------------------- ------------------- -------------------- + FED CBA 987 654 3210 000 add R = A + B +A fff bbb aaa ccc 0ooo 001 sub R = A - B +B sii iii aaa ccc 0ooo si6 siiiii 010 and R = A & B +C sii iii kkk ccc 0ooo si9 skkkiiiii 011 or R = A | B +D sii iii xjj jjj 0ooo si11 sjjjjjiiiii 100 xor R = A ^ B +E sii iii aaa mxx 0ooo si7 smiiiii 101 slt R = A < B +F sii iii aaa ccc 1fff si6 siiiii 110 sge R = A >= B +G sii iii jjj jjj 0ooo si12 sjjjjjjiiiii 111 mul R = A * B + +instruction encodings +--------------------- +A 0000 alu Rc, Ra, Rb Rc = Ra <fn> Rb +? 0001 <expansion> +G 0010 ext si12 Ex = 1*, Ev = si12[11:0] +C 0011 mov Rc, si9 Rc = Ex ? { Ev, si9[3:0] } : si9 +B 0100 lw Rc, [Ra, si6] Rc = mem[Ra + si6] +B 0101 sw Rc, [Ra, si6] mem[Ra + si6] = Rc +D 0110 0 b si11 PC = PC + si11 +D 0110 1 bl si11 R7 = PC + 1, PC = PC + si11 +E 0111 00 bz Ra, si7 (Ra == 0) ? PC = PC + si7 +E 0111 01 bnz Ra, si7 (Ra != 0) ? PC = PC + si7 +E 0111 10 b Ra PC = Ra +E 0111 11 bl Ra R7 = PC + 1, PC = Ra +F 1fff alu Rc, Ra, si6 Rc = Ra <fn> ( Ex ? { Ev, si6[3:0] } : si6 ) + +* Ex reset to 0 after all ops but "ext" diff --git a/src/a16v4.c b/src/a16v4.c @@ -0,0 +1,683 @@ +// Copyright 2015, Brian Swetland <swetland@frotz.net> +// Licensed under the Apache License, Version 2.0. + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <ctype.h> +#include <strings.h> +#include <string.h> + +typedef unsigned u32; +typedef unsigned short u16; + +static unsigned linenumber = 0; +static char linestring[256]; +static char *filename; + +FILE *ofp = 0; + +void die(const char *fmt, ...) { + va_list ap; + fprintf(stderr,"%s:%d: ", filename, linenumber); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr,"\n"); + if (linestring[0]) + fprintf(stderr,"%s:%d: >> %s <<\n", filename, linenumber, linestring); + exit(1); +} + +// various fields +#define _OP(n) (((n) & 15) << 0) +#define _A(n) (((n) & 7) << 7) +#define _B(n) (((n) & 7) << 10) +#define _C(n) (((n) & 7) << 4) +#define _FHI(n) (((n) & 7) << 13) +#define _FLO(n) (((n) & 7) << 0) +#define _I6(n) (((n) & 0x3F) << 10) + +// smiiiii +// siiiiiaaamxx0ooo +static inline unsigned _I7(unsigned n) { + return ((n & 0x1F) << 10) | + ((n & 0x20) << 1) | + ((n & 0x40) << 9); +} +// skkkiiiii +// siiiiikkkccc0ooo +static inline unsigned _I9(unsigned n) { + return ((n & 0x1F) << 10) | + ((n & 0xE0) << 2) | + ((n & 0x100) << 7); +} +// sjjjjjiiiii +// siiiiixjjjjj0ooo +static inline unsigned _I11(unsigned n) { + return ((n & 0x1F) << 10) | + ((n & 0x3E0) >> 1) | + ((n & 0x400) << 5); +} +// sjjjjjjiiiii +// siiiiijjjjjj0ooo +static inline unsigned _I12(unsigned n) { + return ((n & 0x1F) << 10) | + ((n & 0x7E0) >> 1) | + ((n & 0x800) << 4); +} + +int is_signed6(unsigned n) { + n &= 0xFFFFFFE0; + return ((n == 0) || (n == 0xFFFFFFE0)); +} +int is_signed7(unsigned n) { + n &= 0xFFFFFFC0; + return ((n == 0) || (n == 0xFFFFFFC0)); +} +int is_signed9(unsigned n) { + n &= 0xFFFFFF00; + return ((n == 0) || (n == 0xFFFFFF00)); +} +int is_signed11(unsigned n) { + n &= 0xFFFFFC00; + return ((n == 0) || (n == 0xFFFFFC00)); +} +int is_signed12(unsigned n) { + n &= 0xFFFFF800; + return ((n == 0) || (n == 0xFFFFF800)); +} + +u16 rom[65535]; +u16 PC = 0; + +#define TYPE_PCREL_S7 1 +#define TYPE_PCREL_S11 2 +#define TYPE_ABS_U16 3 + +struct fixup { + struct fixup *next; + unsigned pc; + unsigned type; +}; + +struct label { + struct label *next; + struct fixup *fixups; + const char *name; + unsigned pc; + unsigned defined; +}; + +struct label *labels; +struct fixup *fixups; + +void fixup_branch(const char *name, int addr, int btarget, int type) { + unsigned n; + + switch(type) { + case TYPE_PCREL_S7: + n = btarget - addr - 1; + if (!is_signed7(n)) break; + rom[addr] |= _I7(n); + return; + case TYPE_PCREL_S11: + n = btarget - addr - 1; + if (!is_signed11(n)) break; + rom[addr] |= _I11(n); + return; + case TYPE_ABS_U16: + rom[addr] = btarget; + return; + default: + die("unknown branch type %d\n",type); + } + die("label '%s' at %08x is out of range of %08x\n", name, btarget, addr); +} + +void setlabel(const char *name, unsigned pc) { + struct label *l; + struct fixup *f; + + for (l = labels; l; l = l->next) { + if (!strcasecmp(l->name, name)) { + if (l->defined) die("cannot redefine '%s'", name); + l->pc = pc; + l->defined = 1; + for (f = l->fixups; f; f = f->next) { + fixup_branch(name, f->pc, l->pc, f->type); + } + return; + } + } + l = malloc(sizeof(*l)); + l->name = strdup(name); + l->pc = pc; + l->fixups = 0; + l->defined = 1; + l->next = labels; + labels = l; +} + +const char *getlabel(unsigned pc) { + struct label *l; + for (l = labels; l; l = l->next) + if (l->pc == pc) + return l->name; + return 0; +} + +void uselabel(const char *name, unsigned pc, unsigned type) { + struct label *l; + struct fixup *f; + + for (l = labels; l; l = l->next) { + if (!strcasecmp(l->name, name)) { + if (l->defined) { + fixup_branch(name, pc, l->pc, type); + return; + } else { + goto add_fixup; + } + } + } + l = malloc(sizeof(*l)); + l->name = strdup(name); + l->pc = 0; + l->fixups = 0; + l->defined = 0; + l->next = labels; + labels = l; +add_fixup: + f = malloc(sizeof(*f)); + f->pc = pc; + f->type = type; + f->next = l->fixups; + l->fixups = f; +} + +void checklabels(void) { + struct label *l; + for (l = labels; l; l = l->next) { + if (!l->defined) { + die("undefined label '%s'", l->name); + } + } +} + +void disassemble(char *buf, unsigned pc, unsigned instr); + +void emit(unsigned instr) { + rom[PC++] = instr; +} + +void save(const char *fn) { + const char *name; + unsigned n; + char dis[128]; + + FILE *fp = fopen(fn, "w"); + if (!fp) die("cannot write to '%s'", fn); + for (n = 0; n < PC; n++) { + disassemble(dis, n, rom[n]); + name = getlabel(n); + if (name) { + fprintf(fp, "%04x // %04x: %-25s <- %s\n", rom[n], n, dis, name); + } else { + fprintf(fp, "%04x // %04x: %s\n", rom[n], n, dis); + } + } + fclose(fp); +} + +#define MAXTOKEN 32 + +enum tokens { + tEOL, + tCOMMA, tCOLON, tOBRACK, tCBRACK, tDOT, tHASH, tSTRING, tNUMBER, + tADD, tSUB, tAND, tORR, tXOR, tSLT, tSGE, tMUL, + tLW, tSW, tNOP, tNOT, tB, tBL, tBZ, tBNZ, + tMOV, tEXT, tDEBUG, + tR0, tR1, tR2, tR3, tR4, tR5, tR6, tR7, + tSP, tLR, + tEQU, tWORD, tASCII, tASCIIZ, + NUMTOKENS, +}; + +char *tnames[] = { + "<EOL>", + ",", ":", "[", "]", ".", "#", "<STRING>", "<NUMBER>", + "ADD", "SUB", "AND", "ORR", "XOR", "SLT", "SGE", "MUL", + "LW", "SW", "NOP", "NOT", "B", "BL", "BZ", "BNZ", + "MOV", "EXT", "DEBUG", + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", + "SP", "LR", + "EQU", "WORD", "STRING", "ASCIIZ" +}; + +#define FIRST_ALU_OP tADD +#define LAST_ALU_OP tMUL +#define FIRST_REGISTER tR0 +#define LAST_REGISTER tLR + +int is_reg(unsigned tok) { + return ((tok >= FIRST_REGISTER) && (tok <= LAST_REGISTER)); +} + +int is_alu_op(unsigned tok) { + return ((tok >= FIRST_ALU_OP) && (tok <= LAST_ALU_OP)); +} + +unsigned to_func(unsigned tok) { + return tok - FIRST_ALU_OP; +} + +unsigned to_reg(unsigned tok) { + if (tok == tLR) return 7; + if (tok == tSP) return 6; + return tok - FIRST_REGISTER; +} + +int is_stopchar(unsigned x) { + switch (x) { + case 0: + case ' ': + case '\t': + case '\r': + case '\n': + case ',': + case ':': + case '[': + case ']': + case '.': + case '"': + case '#': + return 1; + default: + return 0; + } +} +int is_eoschar(unsigned x) { + switch (x) { + case 0: + case '\t': + case '\r': + case '"': + return 1; + default: + return 0; + } +} + +int tokenize(char *line, unsigned *tok, unsigned *num, char **str) { + char *s; + int count = 0; + unsigned x, n, neg; + linenumber++; + + for (;;) { + x = *line; + again: + if (count == 31) die("line too complex"); + + switch (x) { + case 0: + goto alldone; + case ' ': + case '\t': + case '\r': + case '\n': + line++; + continue; + case '/': + if (line[1] == '/') + goto alldone; + case ';': + goto alldone; + case ',': + str[count] = ","; + num[count] = 0; + tok[count++] = tCOMMA; + line++; + continue; + case ':': + str[count] = ":"; + num[count] = 0; + tok[count++] = tCOLON; + line++; + continue; + case '[': + str[count] = "["; + num[count] = 0; + tok[count++] = tOBRACK; + line++; + continue; + case ']': + str[count] = "]"; + num[count] = 0; + tok[count++] = tCBRACK; + line++; + continue; + case '.': + str[count] = "."; + num[count] = 0; + tok[count++] = tDOT; + line++; + continue; + case '#': + str[count] = "#"; + num[count] = 0; + tok[count++] = tHASH; + line++; + continue; + case '"': + str[count] = ++line; + num[count] = 0; + tok[count++] = tSTRING; + while (!is_eoschar(*line)) line++; + if (*line != '"') + die("unterminated string"); + *line++ = 0; + continue; + } + + s = line++; + while (!is_stopchar(*line)) line++; + + /* save the stopchar */ + x = *line; + *line = 0; + + neg = (s[0] == '-'); + if (neg && isdigit(s[1])) s++; + + str[count] = s; + if (isdigit(s[0])) { + num[count] = strtoul(s, 0, 0); + if(neg) num[count] = -num[count]; + tok[count++] = tNUMBER; + goto again; + } + if (isalpha(s[0])) { + num[count] = 0; + for (n = tNUMBER + 1; n < NUMTOKENS; n++) { + if (!strcasecmp(s, tnames[n])) { + str[count] = tnames[n]; + tok[count++] = n; + goto again; + } + } + + while (*s) { + if (!isalnum(*s) && (*s != '_')) + die("invalid character '%c' in identifier", *s); + s++; + } + tok[count++] = tSTRING; + goto again; + } + die("invalid character '%c'", s[0]); + } + +alldone: + str[count] = ""; + num[count] = 0; + tok[count++] = tEOL; + return count; +} + +void expect(unsigned expected, unsigned got) { + if (expected != got) + die("expected %s, got %s", tnames[expected], tnames[got]); +} + +void expect_register(unsigned got) { + if (!is_reg(got)) + die("expected register, got %s", tnames[got]); +} + +#define REG(n) (tnames[FIRST_REGISTER + (n)]) + + +#define OP_ALU_RC_RA_RB 0x0000 +#define OP_EXT 0x0002 +#define OP_MOV_RC_S9 0x0003 +#define OP_LW_RC_RA_S6 0x0004 +#define OP_SW_RC_RA_S6 0x0005 +#define OP_B_S11 0x0006 +#define OP_BL_S11 0x0206 +#define OP_BZ_RA_S7 0x0007 +#define OP_BNZ_RA_S7 0x0017 +#define OP_B_RA 0x0027 +#define OP_BL_RA 0x0037 +#define OP_ALU_RC_RA_S6 0x0008 +#define OP_NOP 0x0008 + +#define ALU_ADD 0 +#define ALU_SUB 1 +#define ALU_AND 2 +#define ALU_ORR 3 +#define ALU_XOR 4 +#define ALU_SLT 5 +#define ALU_SGE 6 +#define ALU_MUL 7 + +#define T0 tok[0] +#define T1 tok[1] +#define T2 tok[2] +#define T3 tok[3] +#define T4 tok[4] +#define T5 tok[5] +#define T6 tok[6] +#define T7 tok[7] + +void assemble_line(int n, unsigned *tok, unsigned *num, char **str) { + unsigned instr = 0; + unsigned tmp; + if (T0 == tSTRING) { + if (T1 == tCOLON) { + setlabel(str[0], PC); + tok += 2; + num += 2; + str += 2; + n -= 2; + } else { + die("unexpected identifier '%s'", str[0]); + } + } + + switch(T0) { + case tEOL: + /* blank lines are fine */ + return; + case tNOP: + emit(OP_NOP); + return; + case tNOT: + /* XOR rX, rX, -1 */ + expect_register(T1); + emit(OP_ALU_RC_RA_S6 | _A(to_reg(T1)) | _C(to_reg(T1)) | _I6(-1) | ALU_XOR); + return; + case tMOV: + expect_register(T1); + expect(tCOMMA, T2); + if (is_reg(T3)) { + emit(OP_ALU_RC_RA_S6 | _C(to_reg(T1)) | _A(to_reg(T3)) | ALU_ADD); + return; + } + expect(tNUMBER, T3); + if (is_signed9(num[3])) { + emit(OP_MOV_RC_S9 | _C(to_reg(T1)) | _I9(num[3])); + return; + } else { + emit(OP_EXT | _I12((num[3] >> 4))); + emit(OP_MOV_RC_S9 | _C(to_reg(T1)) | _I9((num[3] & 15))); + } + return; + case tEXT: + expect_register(T1); + expect(tNUMBER, T2); + // range + emit(OP_EXT | _I12(num[3])); + return; + case tLW: + case tSW: + instr = (T0 == tLW ? OP_LW_RC_RA_S6 : OP_SW_RC_RA_S6); + expect_register(T1); + expect(tCOMMA, T2); + expect(tOBRACK, T3); + expect_register(T4); + if (T5 == tCOMMA) { + expect(tNUMBER, T6); + expect(tCBRACK, T7); + tmp = num[6]; + } else { + expect(tCBRACK, T5); + tmp = 0; + } + if (!is_signed6(tmp)) die("index too large"); + emit(instr | _C(to_reg(T1)) | _A(to_reg(T4)) | _I6(tmp)); + return; + case tB: + case tBL: + if (is_reg(T1)) { + instr = (T0 == tB) ? OP_B_RA : OP_BL_RA; + emit(instr | _A(to_reg(T1))); + } else { + instr = (T0 == tB) ? OP_B_S11 : OP_BL_S11; + if (T1 == tSTRING) { + emit(instr); + uselabel(str[1], PC - 1, TYPE_PCREL_S11); + } else if (T1 == tDOT) { + emit(instr | _I11(-1)); + } else { + die("expected register or address"); + } + } + return; + case tBZ: + case tBNZ: + instr = (T0 == tBZ) ? OP_BZ_RA_S7 : OP_BNZ_RA_S7; + expect_register(T1); + expect(tCOMMA, T2); + if (T3 == tSTRING) { + emit(instr | _A(to_reg(T1))); + uselabel(str[3], PC - 1, TYPE_PCREL_S7); + } else if (T3 == tDOT) { + emit(instr | _A(to_reg(T1)) | _I11(-1)); + } else { + die("expected register or address"); + } + return; + case tDEBUG: + expect_register(T1); + expect(tCOMMA, T2); + expect(tNUMBER, T3); + emit(OP_NOP); //TODO + return; + case tWORD: + tmp = 1; + for (;;) { + if (tok[tmp] == tSTRING) { + emit(0); + uselabel(str[tmp++], PC - 1, TYPE_ABS_U16); + } else { + expect(tNUMBER, tok[tmp]); + emit(num[tmp++]); + } + if (tok[tmp] != tCOMMA) + break; + tmp++; + } + return; + case tASCII: + case tASCIIZ: { + unsigned n = 0, c = 0; + const unsigned char *s = (void*) str[1]; + expect(tSTRING, tok[1]); + while (*s) { + n |= ((*s) << (c++ * 8)); + if (c == 2) { + emit(n); + n = 0; + c = 0; + } + s++; + } + emit(n); + return; + } + } + if (is_alu_op(T0)) { + expect_register(T1); + expect(T2, tCOMMA); + expect_register(T3); + expect(T4, tCOMMA); + if (T5 == tNUMBER) { + if (is_signed6(num[5])) { + emit(OP_ALU_RC_RA_S6 | _C(to_reg(T1)) | _A(to_reg(T3)) | _FLO(to_func(T0)) | _I6(num[5])); + } else { + emit(OP_EXT | _I12((num[5] >> 4))); + emit(OP_ALU_RC_RA_S6 | _C(to_reg(T1)) | _A(to_reg(T3)) | _FLO(to_func(T0)) | _I6((num[5] & 15))); + } + } else if (is_reg(T5)) { + emit(OP_ALU_RC_RA_RB | _C(to_reg(T1)) | _A(to_reg(T3)) | _B(to_reg(T5)) | _FHI(to_func(T0))); + } else { + die("expected register or #, got %s", tnames[tok[5]]); + } + return; + } + + die("HUH"); +} + +void assemble(const char *fn) { + FILE *fp; + char line[256]; + int n; + + unsigned tok[MAXTOKEN]; + unsigned num[MAXTOKEN]; + char *str[MAXTOKEN]; + char *s; + + fp = fopen(fn, "r"); + if (!fp) die("cannot open '%s'", fn); + + while (fgets(line, sizeof(line)-1, fp)) { + strcpy(linestring, line); + s = linestring; + while (*s) { + if ((*s == '\r') || (*s == '\n')) *s = 0; + else s++; + } + n = tokenize(line, tok, num, str); +#if DEBUG + { + int i + printf("%04d: (%02d) ", linenumber, n); + for (i = 0; i < n; i++) + printf("%s ", tnames[tok[i]]); + printf("\n"); + } +#endif + assemble_line(n, tok, num, str); + } +} + +int main(int argc, char **argv) { + const char *outname = "out.hex"; + filename = argv[1]; + + if (argc < 2) + die("no file specified"); + if (argc == 3) + outname = argv[2]; + + assemble(filename); + linestring[0] = 0; + checklabels(); + save(outname); + + return 0; +} diff --git a/src/d16v4.c b/src/d16v4.c @@ -0,0 +1,210 @@ +// Copyright 2015, Brian Swetland <swetland@frotz.net> +// Licensed under the Apache License, Version 2.0. + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <ctype.h> +#include <strings.h> +#include <string.h> + +typedef unsigned u32; +typedef unsigned short u16; + +char *append(char *buf, const char *s) { + while (*s) + *buf++ = *s++; + return buf; +} +char *append_u16(char *buf, unsigned n) { + sprintf(buf, "0x%04x", n & 0xFFFF); + return buf + strlen(buf); +} +char *append_int(char *buf, int n) { + sprintf(buf, "%d", n); + return buf + strlen(buf); +} + +const char *regname[] = { + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", +}; + +const char *alufunc[] = { + "ADD", "SUB", "AND", "ORR", "XOR", "SLT", "SGE", "MUL", +}; + +void printinst(char *buf, unsigned pc, unsigned instr, const char *fmt, + unsigned _ex, unsigned ev) { + unsigned tmp; + char *start = buf; + char note[64]; + note[0] = 0; + + unsigned a = (instr >> 7) & 7; + unsigned b = (instr >> 10) & 7; + unsigned c = (instr >> 4) & 7; + unsigned fhi = (instr >> 13) & 7; + unsigned flo = instr & 7; + + // immediate sub-fields + unsigned s = (instr >> 15); + unsigned i = (instr >> 10) & 0x1F; + unsigned j = (instr >> 4) & 0x3F; + unsigned k = (instr >> 7) & 7; + unsigned m = (instr >> 6) & 1; + + // immediates + int s6 = i; + int s7 = i | (m << 5); + int s9 = i | (k << 5); + int s11 = i | ((j & 0x1F) << 5); + int s12 = i | (j << 5); + + // sign-extend + if (s) { + s6 |= 0xFFFFFFE0; + s7 |= 0xFFFFFFC0; + s9 |= 0xFFFFFF00; + s11 |= 0xFFFFFC00; + s12 |= 0xFFFFF800; + } + + while (*fmt) { + unsigned ex; + if (*fmt == '+') { + ex = _ex; + fmt++; + } else { + ex = 0; + } + if (*fmt != '@') { + *buf++ = *fmt++; + continue; + } + switch (*++fmt) { + case 'A': + buf = append(buf, regname[a]); + break; + case 'B': + buf = append(buf, regname[b]); + break; + case 'C': + buf = append(buf, regname[c]); + break; + case 'F': + buf = append(buf, alufunc[fhi]); + break; + case 'f': // alt alu func + buf = append(buf, alufunc[flo]); + break; + case '6': + if (ex) { + tmp = (ev << 4) | (s6 & 15); + if (tmp & 0x8000) tmp |= 0xFFFF0000; + } else { + tmp = s6; + } + buf = append_int(buf, tmp); + sprintf(note, "(%04x)", tmp & 0xffff); + break; + case '7': + buf = append_int(buf, s7); + sprintf(note, "(%04x)", pc + s7 + 1); + break; + case '9': + if (ex) { + tmp = (ev << 4) | (s9 & 15); + if (tmp & 0x8000) tmp |= 0xFFFF0000; + } else { + tmp = s9; + } + buf = append_int(buf, tmp); + sprintf(note, "(%04x)", tmp & 0xffff); + break; + case 'b': + buf = append_int(buf, s11); + sprintf(note, "(%04x)", pc + s11 + 1); + break; + case 'c': + buf = append_int(buf, s12); + break; + case 'e': + buf = append_u16(buf, (s12 << 4) & 0xffff); + break; + case 0: + goto done; + } + fmt++; + } +done: + if (note[0]) { + while ((buf - start) < 22) *buf++ = ' '; + strcpy(buf, note); + buf += strlen(note); + } + *buf = 0; +} + +struct { + u16 mask; + u16 value; + const char *fmt; +} decode[] = { + { 0b0000000000001111, 0b0000000000000000, "@F @C, @A, @B" }, + { 0b0000000000001111, 0b0000000000000001, "UND" }, + { 0b0000000000001111, 0b0000000000000010, "EXT @e" }, + { 0b0000000000001111, 0b0000000000000011, "MOV @C, +@9" }, + { 0b0000000000001111, 0b0000000000000100, "LW @C, [@A, @6]" }, + { 0b0000000000001111, 0b0000000000000101, "SW @C, [@A, @6]" }, + { 0b0000001000001111, 0b0000000000000110, "B @b" }, + { 0b0000001000001111, 0b0000001000000110, "BL @b" }, + { 0b0000000000111111, 0b0000000000000111, "BZ @A, @7" }, + { 0b0000000000111111, 0b0000000000010111, "BNZ @A, @7" }, + { 0b1111110001111111, 0b0000000000100111, "B @A" }, + { 0b1111110001111111, 0b0000000000110111, "BL @A" }, + { 0b1111111111111111, 0b0000000000001000, "NOP" }, // ADD R0, R0, 0 + { 0b1111110000001111, 0b0000000000001000, "MOV @C, @A" }, // ADD Rc, Ra, 0 + { 0b1111110000001111, 0b1111110000001100, "NOT @C, @A" }, // XOR Rc, Ra, -1 + { 0b0000000000001000, 0b0000000000001000, "@f @C, @A, +@6" }, + { 0b0000000000000000, 0b0000000000000000, "UND" }, +}; + +static void disassemble0(char *buf, unsigned pc, unsigned instr, + unsigned ex, unsigned ev) { + int n = 0; + for (n = 0 ;; n++) { + if ((instr & decode[n].mask) == decode[n].value) { + printinst(buf, pc, instr, decode[n].fmt, ex, ev); + return; + } + } + buf[0] = 0; +} + +void disassemble(char *buf, unsigned pc, unsigned instr) { + static unsigned ex = 0; + static unsigned ev = 0; + disassemble0(buf, pc, instr, ex, ev); + if ((instr & 0xF) == 0x2) { + ex = 1; + ev = ((instr >> 10) & 0x1F) | ((instr & 0x3F0) << 1) | ((instr >> 4) & 0x800); + } else { + ex = 0; + } +} + +#ifdef STANDALONE +int main(int argc, char **argv) { + char buf[256]; + char line[1024]; + while (fgets(line, 1024, stdin)) { + unsigned insn = 0xFFFF; + unsigned ext = 0; + sscanf(line, "%04x%04x", &insn, &ext); + disassemble0(buf, 0, insn, ext >> 12, ext & 0xFFF); + printf("%s\n", buf); + fflush(stdout); + } + return 0; +} +#endif diff --git a/src/test.s b/src/test.s @@ -1,6 +1,11 @@ + mov r0, r1 + mov r1, r0 + mov r3, r7 mov r0, 0 mov r1, 1 mov r1, 7 + mov r1, 255 + mov r1, -250 mul r3, r1, r1 mov r2, 2 mov r3, 3