#include "defs.h" #include "fns.h" typedef ushort Parcel; typedef struct { char *mnemonic; void (*f0)(Parcel, WORD); void (*f1)(Parcel, WORD); } Opcode; static Opcode onepop[32]; static Opcode stackop[4]; static Opcode nilop[10]; static Opcode threepop[64]; static Opcode monop[16]; static char *addrmode[16]; static char *faddrmode[16]; static char *regname[32]; #define CPU 0x2C00 static Parcel cpu; static WORD src, dst; static ADDR mydot; static int myisp; static Map *mymap; static Parcel getparcel(Map *map, ulong pc, int isp) { WORD w; if (get4(map, pc & ~3, isp, &w) == 0) chkerr(); if(pc & 3) return w & 0xFFFF; return w>>16; } static Parcel getinstr(Map *map, int isp) { Parcel p; myisp = isp; mydot = dot; mymap = map; cpu = 0; p = getparcel(mymap, mydot-2, myisp); if(p == CPU) cpu = 1; errflg = 0; dotinc = sizeof(Parcel); p = getparcel(mymap, mydot, myisp); if(p == CPU){ cpu = 1; mydot += sizeof(Parcel); dotinc += sizeof(Parcel); p = getparcel(mymap, mydot, myisp); } if((p & 0x8000) == 0){ src = (p>>5) & 0x1F; dst = p & 0x1F; } else if((p & 0x4000) == 0){ src = getparcel(mymap, mydot+2, myisp); dst = getparcel(mymap, mydot+4, myisp); dotinc += 2*sizeof(Parcel); } else { src = getparcel(mymap, mydot+2, myisp)<<16; src |= getparcel(mymap, mydot+4, myisp); dst = getparcel(mymap, mydot+6, myisp)<<16; dst |= getparcel(mymap, mydot+8, myisp); dotinc += 4*sizeof(Parcel); } return p; } static void oneparcel(Parcel p) { int opcode, offset; Opcode *o; opcode = (p>>10) & 0x1F; if (opcode == 0x02) { opcode = p & 0x03; offset = ((p & 0x03FC)>>2) * 16; if (opcode == 0) /* ENTER */ offset = (((p & 0x03FC)>>2)|0xFFFFFF00) * 16; dprint("%s\tR%d", stackop[opcode].mnemonic, offset); } else if (opcode == 0x0B) { offset = p & 0x3FF; if (offset >= sizeof(nilop)/sizeof(Opcode)) dprint("niladic %lux", offset); else dprint("%s", nilop[offset].mnemonic); } else { o = &onepop[opcode]; dprint("%s\t", o->mnemonic); if (o->f0) (*o->f0)(p, src); if (o->f1) { dprint(","); (*o->f1)(p, dst); } } } static void fgen(Parcel m, WORD w) { dprint(faddrmode[m], w); } static void gen32(Parcel m, WORD w, void (*f)(Parcel, WORD)) { Symbol s; if (cpu == 0 || m != 7) { if (m < 4 || m == 12 || m == 0x0F) { if (findsym(w, CANY, &s) && s.value-w < maxoff) { if (s.class == CDATA || s.class == CTEXT) { if (m != 0x0F) dprint("*"); dprint("$%s", s.name); if (s.value-w) dprint("+%lux", s.value-w); if (s.class == CDATA) dprint("(SB)"); return; } } } if (f) (*f)(m, w); else dprint(addrmode[m], w); } else dprint("%%%s", regname[w & 0x1F]); } static void gen16(Parcel m, WORD w, void (*f)(Parcel, WORD)) { if (m < 4 || m == 12) { dprint("*$"); w = (w & 0x1FFFFFFF)|(mydot & 0xE0000000); psymoff(w, SEGDATA, "(SB)"); return; } else if(w & 0x8000) w |= 0xFFFF0000; gen32(m, w, f); } static void threeparcel(Parcel p) { int opcode; Opcode *o; opcode = (p>>8) & 0x3F; if (opcode == 0) { /* monadic */ opcode = p & 0x0F; o = &monop[opcode]; dprint("%s\t", o->mnemonic); if (o->f0) (*o->f0)(p, (src<<16)|dst); } else { o = &threepop[opcode]; dprint("%s\t", o->mnemonic); if ((p & 0xC000) == 0xC000) { /* 5-parcel */ gen32((p>>4) & 0x0F, src, o->f0); dprint(","); gen32(p & 0x0F, dst, o->f1); } else { /* 3-parcel */ gen16((p>>4) & 0x0F, src, o->f0); dprint(","); gen16(p & 0x0F, dst, o->f1); } } } void hobbitprintins(Map *map, char modifier, int isp) { Parcel p; USED(modifier); p = getinstr(map, isp); if ((p & 0x8000) == 0) oneparcel(p); else threeparcel(p); } void hobbitprintdas(Map *map, int isp) { int i; getinstr(map, isp); for (i = 0; i < dotinc; i += sizeof(Parcel)) { printparcel(getparcel(map, dot+i, myisp), 3); printc(' '); } dprint("%48t"); dotinc = 0; } static void imm10(Parcel p, WORD w) { USED(w); dprint("$%lux", (p & 0x3FF) * 4); } static void pcrel10(Parcel p, WORD w) { int offset; USED(w); offset = (((p & 0x200) ? (p|0xFFFFFE00): (p & 0x1FF))<<1); psymoff(offset + mydot, myisp, ""); dprint(" [%lx(PC)]", offset); } static void stk5(Parcel p, WORD w) { USED(p); dprint("R%d", w * 4); } static void imm5(Parcel p, WORD w) { int offset; USED(p); offset = ((w & 0x10) ? (w|0xFFFFFFF0): w); dprint("$%lux", offset); } static void uimm5(Parcel p, WORD w) { USED(p); dprint("$%lux", w & 0x1F); } static void istk5(Parcel p, WORD w) { USED(p); dprint("*R%d", w * 4); } static void wai5(Parcel p, WORD w) { USED(p); dprint("$%lux", w * 4); } static void flow32(Parcel p, WORD w) { switch ((p>>4) & 0x0F) { case 0x0C: dprint("**$"); psymoff(w, myisp, ""); break; case 0x0D: dprint("*R%d", w); break; case 0x0E: psymoff(w + mydot, myisp, ""); dprint(" [%lx(PC)]", w); break; case 0x0F: dprint("*$"); psymoff(w, myisp, ""); break; default: dprint("mode %lux, operand %lux", (p>>4) & 0x0F, w); break; } } static void word32(Parcel p, WORD w) { switch ((p>>4) & 0x0F) { case 0x0C: case 0x0D: case 0x0E: case 0x0F: gen32((p>>4) & 0x0F, w, 0); break; default: dprint("mode %lux, operand %lux", (p>>4) & 0x0F, w); break; } } static void abs32(Parcel p, WORD w) { switch ((p>>4) & 0x0F) { case 0x0E: psymoff(w + mydot, myisp, ""); dprint(" [%lx(PC)]", w); break; case 0x0F: dprint("*$"); psymoff(w, myisp, ""); break; default: dprint("mode %lux, operand %lux", (p>>4) & 0x0F, w); } } static void stk32(Parcel p, WORD w) { switch ((p>>4) & 0x0F) { case 0x0D: case 0x0E: gen32((p>>4) & 0x0F, w, 0); break; default: dprint("mode %lux, operand %lux", (p>>4) & 0x0F, w); break; } } static Opcode onepop[32] = { "KCALL", imm10, 0, "CALL", pcrel10,0, "stack", 0, 0, "JMP", pcrel10,0, "JMPFN", pcrel10,0, "JMPFY", pcrel10,0, "JMPTN", pcrel10,0, "JMPTY", pcrel10,0, "op0x08", 0, 0, "op0x09", 0, 0, "MOV", wai5, stk5, "niladic", 0, 0, "op0x0C", 0, 0, "ADD3", wai5, stk5, "AND3", imm5, stk5, "AND", stk5, stk5, "CMPEQ", imm5, stk5, "CMPGT", stk5, stk5, "CMPGT", imm5, stk5, "CMPEQ", stk5, stk5, "ADD", imm5, stk5, "ADD3", imm5, stk5, "ADD", stk5, stk5, "ADD3", stk5, stk5, "MOV", stk5, stk5, "MOV", istk5, stk5, "MOV", stk5, istk5, "MOV", istk5, istk5, "MOV", imm5, stk5, "MOVA", stk5, stk5, "SHL3", uimm5, stk5, "SHR3", uimm5, stk5, }; static Opcode stackop[4] = { "ENTER", 0, 0, "CATCH", 0, 0, "RETURN", 0, 0, "POPN", 0, 0, }; static Opcode nilop[10] = { "CPU", 0, 0, "KRET", 0, 0, "NOP", 0, 0, "FLUSHI", 0, 0, "FLUSHP", 0, 0, "CRET", 0, 0, "FLUSHD", 0, 0, "op0x07", 0, 0, "TESTV", 0, 0, "TESTC", 0, 0, }; static Opcode threepop[64] = { "monadic", 0, 0, "ORI", 0, 0, "ANDI", 0, 0, "ADDI", 0, 0, "MOVA", 0, 0, "UREM", 0, 0, "MOV", 0, 0, "DQM", 0, 0, "FNEXT", fgen, fgen, "FSCALB", 0, fgen, "op0x0A", 0, 0, "FREM", fgen, fgen, "TADD", 0, 0, "TSUB", 0, 0, "op0x0E", 0, 0, "op0x0F", 0, 0, "FSQRT", fgen, fgen, "FMOV", fgen, fgen, "FLOGB", fgen, fgen, "FCLASS", fgen, 0, "op0x14", 0, 0, "op0x15", 0, 0, "op0x16", 0, 0, "op0x17", 0, 0, "FCMPGE", fgen, fgen, "FCMPGT", fgen, fgen, "FCMPEQ", fgen, fgen, "FCMPEQN", fgen, fgen, "FCMPN", fgen, fgen, "CMPGT", 0, 0, "CMPHI", 0, 0, "CMPEQ", 0, 0, "SUB", 0, 0, "OR", 0, 0, "AND", 0, 0, "ADD", 0, 0, "XOR", 0, 0, "REM", 0, 0, "MUL", 0, 0, "DIV", 0, 0, "FSUB", fgen, fgen, "FMUL", fgen, fgen, "FDIV", fgen, fgen, "FADD", fgen, fgen, "SHR", 0, 0, "USHR", 0, 0, "SHL", 0, 0, "UDIV", 0, 0, "SUB3", 0, 0, "OR3", 0, 0, "AND3", 0, 0, "ADD3", 0, 0, "XOR3", 0, 0, "REM3", 0, 0, "MUL3", 0, 0, "DIV3", 0, 0, "FSUB3", fgen, fgen, "FMUL3", fgen, fgen, "FDIV3", fgen, fgen, "FADD3", fgen, fgen, "SHR3", 0, 0, "USHR3", 0, 0, "SHL3", 0, 0, "op0x1F", 0, 0, }; static Opcode monop[16] = { "KCALL", word32, 0, "CALL", flow32, 0, "RETURN", stk32, 0, "JMP", flow32, 0, "JMPFN", abs32, 0, "JMPFY", abs32, 0, "JMPTN", abs32, 0, "JMPTY", abs32, 0, "CATCH", word32, 0, "ENTER", word32, 0, "LDRAA", flow32, 0, "FLUSHPTE", word32, 0, "FLUSHPBE", word32, 0, "FLUSHDCE", word32, 0, "op0x0E", 0, 0, "POPN", stk32, 0, }; static char *addrmode[] = { "*$%lux.B", "*$%lux.UB", "*$%lux.H", "*$%lux.UH", "R%d.B", "R%d.UB", "R%d.H", "R%d.UH", "*R%d.B", "*R%d.UB", "*R%d.H", "*R%d.UH", "*$%lux", "R%d", "*R%d", "$%lux", }; static char *faddrmode[] = { "*$%lux.F", "*$%lux.D", "*$%lux.X", "", "R%d.F", "R%d.D", "R%d.X", "", "*R%d.F", "*R%d.D", "*R%d.X", "", "*$%lux.W", "R%d.W", "*R%d.W", "$%lux", }; static char *regname[32] = { "REG0", "MSP", "ISP", "SP", "CONFIG", "PSW", "SHAD", "VB", "STB", "FAULT", "ID", "TIMER1", "TIMER2", "REG13", "REG14", "REG15", "FPSW", "REG17", "REG18", "REG19", "REG20", "REG21", "REG22", "REG23", "REG24", "REG25", "REG26", "REG27", "REG28", "REG29", "REG30", "REG31", }; int hobbitfoll(ulong pc, ulong *foll) { ulong w; Parcel p; p = getinstr(cormap, SEGDATA); chkerr(); if ((p & 0x8000) == 0) { switch ((p>>10) & 0x1F) { case 0x01: /* CALL */ case 0x03: /* JMP */ if (p & 0x200) w = p|0xFFFFFE00; else w = p & 0x1FF; foll[0] = pc+(w<<1); return 1; case 0x04: /* JMPFN */ case 0x05: /* JMPFY */ case 0x06: /* JMPTN */ case 0x07: /* JMPTY */ if (p & 0x200) w = p|0xFFFFFE00; else w = p & 0x1FF; foll[0] = pc+2; foll[1] = pc+(w<<1); return 2; case 0x02: /* stack */ if ((p & 0x03) != 0x02) /* RETURN */ break; w = ((p & 0x03FC)>>2) * 16; get4(cormap, rget(mach->sp)+w, SEGDATA, (long *) foll); return 1; } } else if ((p & 0xFF00) == 0x8000) { /* 3-parcel monadic */ w = (src<<16)|dst; switch (p & 0x0F) { case 0x01: /* CALL */ case 0x03: /* JMP */ switch ((p>>4) & 0x0F) { case 0x0C: /* **$w */ get4(cormap, w, SEGDATA, (long *)&w); get4(cormap, w, SEGDATA, (long *)foll); return 1; case 0x0D: /* *Rw */ get4(cormap, rget(mach->sp)+w, SEGDATA, (long *) foll); return 1; case 0x0E: /* pc+w */ foll[0] = pc+w; return 1; case 0x0F: /* *$w */ get4(cormap, w, SEGDATA, (long *) foll); return 1; } break; case 0x04: /* JMPFN */ case 0x05: /* JMPFY */ case 0x06: /* JMPTN */ case 0x07: /* JMPTY */ switch ((p>>4) & 0x0F) { case 0x0E: /* pc+w */ foll[0] = pc+w; return 1; case 0x0F: /* *$w */ get4(cormap, w, SEGDATA, (long *) foll); return 1; } break; case 0x02: /* RETURN */ get4(cormap, rget(mach->sp)+w, SEGDATA, (long *) foll); return 1; } } foll[0] = pc+dotinc; return 1; }