/* This file is in the public domain. */ #include #include #include "machine.h" #include "fnprintf.h" typedef struct instr INSTR; #define CF_VG (CF_MSPEC+0) #define CF_JT (CF_MSPEC+1) struct instr { const char *name; unsigned int variant; #define V_6502 1 #define V_G65SC802 2 #define M_6502 (V_6502) #define M_G65SC802 (V_6502|V_G65SC802) unsigned char addrmode; #define AM_IMM 1 /* #$aa */ #define AM_ABS 2 /* $bbaa */ #define AM_ABSLONG 3 /* $ccbbaa */ #define AM_DIRECT 4 /* $aa */ #define AM_ACC 5 /* A */ #define AM_IMPLIED 6 /* (nil) */ #define AM_DIR_IND_INX 7 /* ($aa),Y */ #define AM_DIR_IND_INX_LONG 8 /* [$aa],Y */ #define AM_DIR_INX_IND 9 /* ($aa,X) */ #define AM_DIR_INX_X 10 /* $aa,X */ #define AM_DIR_INX_Y 11 /* $aa,Y */ #define AM_ABS_INX_X 12 /* $bbaa,X */ #define AM_ABS_INX_Y 13 /* $bbaa,Y */ #define AM_ABSLONG_INX_X 14 /* $ccbbaa,X */ #define AM_RELATIVE 15 /* aa is signed branch offset from next instr */ #define AM_RELATIVE_LONG 16 /* bbaa is signed branch offset from next instr */ #define AM_ABS_IND 17 /* ($bbaa) */ #define AM_DIR_IND 18 /* ($aa) */ #define AM_DIR_IND_LONG 19 /* [$aa] */ #define AM_ABS_INX_IND 20 /* ($bbaa,X) */ #define AM_STACK 21 /* (nil) */ #define AM_STK_REL 22 /* $aa,S */ #define AM_STK_REL_IND_INX 23 /* ($aa,S),Y */ #define AM_BLOCK 24 /* $aa,Y,$bb,X,A */ unsigned char nbytes; } ; #define G V_G65SC802 #define _ V_6502 static INSTR instrs[256] = { { /*00*/ "brk", _, AM_IMPLIED }, { /*01*/ "ora", _, AM_DIR_INX_IND }, { /*02*/ "cop", G, AM_STACK }, { /*03*/ "ora", G, AM_STK_REL }, { /*04*/ "tsb", G, AM_DIRECT }, { /*05*/ "ora", _, AM_DIRECT }, { /*06*/ "asl", _, AM_DIRECT }, { /*07*/ "ora", G, AM_DIR_IND_LONG }, { /*08*/ "php", _, AM_STACK }, { /*09*/ "ora", _, AM_IMM }, { /*0a*/ "asl", _, AM_ACC }, { /*0b*/ "phd", G, AM_STACK }, { /*0c*/ "tsb", G, AM_ABS }, { /*0d*/ "ora", _, AM_ABS }, { /*0e*/ "asl", _, AM_ABS }, { /*0f*/ "ora", G, AM_ABSLONG }, { /*10*/ "bpl", _, AM_RELATIVE }, { /*11*/ "ora", _, AM_DIR_IND_INX }, { /*12*/ "ora", G, AM_DIR_IND }, { /*13*/ "ora", G, AM_STK_REL_IND_INX }, { /*14*/ "trb", G, AM_DIRECT }, { /*15*/ "ora", _, AM_DIR_INX_X }, { /*16*/ "asl", _, AM_DIR_INX_X }, { /*17*/ "ora", G, AM_DIR_IND_INX_LONG }, { /*18*/ "clc", _, AM_IMPLIED }, { /*19*/ "ora", _, AM_ABS_INX_Y }, { /*1a*/ "inc", G, AM_ACC }, { /*1b*/ "tcs", G, AM_IMPLIED }, { /*1c*/ "trb", G, AM_ACC }, { /*1d*/ "ora", _, AM_ABS_INX_X }, { /*1e*/ "asl", _, AM_ABS_INX_X }, { /*1f*/ "ora", G, AM_ABSLONG_INX_X }, { /*20*/ "jsr", _, AM_ABS }, { /*21*/ "and", _, AM_DIR_INX_IND }, { /*22*/ "jsl", G, AM_ABSLONG }, { /*23*/ "and", G, AM_STK_REL }, { /*24*/ "bit", _, AM_DIRECT }, { /*25*/ "and", _, AM_DIRECT }, { /*26*/ "rol", _, AM_DIRECT }, { /*27*/ "and", G, AM_DIR_IND_LONG }, { /*28*/ "plp", _, AM_STACK }, { /*29*/ "and", _, AM_IMM }, { /*2a*/ "rol", _, AM_ACC }, { /*2b*/ "pld", G, AM_STACK }, { /*2c*/ "bit", _, AM_ABS }, { /*2d*/ "and", _, AM_ABS }, { /*2e*/ "rol", _, AM_ABS }, { /*2f*/ "and", G, AM_ABSLONG }, { /*30*/ "bmi", _, AM_RELATIVE }, { /*31*/ "and", _, AM_DIR_IND_INX }, { /*32*/ "and", G, AM_DIR_IND }, { /*33*/ "and", G, AM_STK_REL_IND_INX }, { /*34*/ "bit", G, AM_DIR_INX_X }, { /*35*/ "and", _, AM_DIR_INX_X }, { /*36*/ "rol", _, AM_DIR_INX_X }, { /*37*/ "and", G, AM_DIR_IND_INX_LONG }, { /*38*/ "sec", _, AM_IMPLIED }, { /*39*/ "and", _, AM_ABS_INX_Y }, { /*3a*/ "dec", G, AM_ACC }, { /*3b*/ "tsc", G, AM_IMPLIED }, { /*3c*/ "bit", G, AM_ABS_INX_X }, { /*3d*/ "and", _, AM_ABS_INX_X }, { /*3e*/ "rol", _, AM_ABS_INX_X }, { /*3f*/ "and", G, AM_ABSLONG_INX_X }, { /*40*/ "rti", _, AM_STACK }, { /*41*/ "eor", _, AM_DIR_INX_IND }, { /*42*/ 0, 0, AM_IMPLIED }, { /*43*/ "eor", G, AM_STK_REL }, { /*44*/ "mvp", G, AM_BLOCK }, { /*45*/ "eor", _, AM_DIRECT }, { /*46*/ "lsr", _, AM_DIRECT }, { /*47*/ "eor", G, AM_DIR_IND_LONG }, { /*48*/ "pha", _, AM_STACK }, { /*49*/ "eor", _, AM_IMM }, { /*4a*/ "lsr", _, AM_ACC }, { /*4b*/ "phk", G, AM_STACK }, { /*4c*/ "jmp", _, AM_ABS }, { /*4d*/ "eor", _, AM_ABS }, { /*4e*/ "lsr", _, AM_ABS }, { /*4f*/ "eor", G, AM_ABSLONG }, { /*50*/ "bvc", _, AM_RELATIVE }, { /*51*/ "eor", _, AM_DIR_IND_INX }, { /*52*/ "eor", G, AM_DIR_IND }, { /*53*/ "eor", G, AM_STK_REL_IND_INX }, { /*54*/ "mvn", G, AM_BLOCK }, { /*55*/ "eor", _, AM_DIR_INX_X }, { /*56*/ "lsr", _, AM_DIR_INX_X }, { /*57*/ "eor", G, AM_DIR_IND_INX_LONG }, { /*58*/ "cli", _, AM_IMPLIED }, { /*59*/ "eor", _, AM_ABS_INX_Y }, { /*5a*/ "phy", G, AM_STACK }, { /*5b*/ "tcd", G, AM_IMPLIED }, { /*5c*/ "jmp", G, AM_ABSLONG }, { /*5d*/ "eor", _, AM_ABS_INX_X }, { /*5e*/ "lsr", _, AM_ABS_INX_X }, { /*5f*/ "eor", G, AM_ABSLONG_INX_X }, { /*60*/ "rts", _, AM_STACK }, { /*61*/ "adc", _, AM_DIR_INX_IND }, { /*62*/ "per", G, AM_STACK }, { /*63*/ "adc", G, AM_STK_REL }, { /*64*/ "stz", G, AM_DIRECT }, { /*65*/ "adc", _, AM_DIRECT }, { /*66*/ "ror", _, AM_DIRECT }, { /*67*/ "adc", G, AM_DIR_IND_LONG }, { /*68*/ "pla", _, AM_STACK }, { /*69*/ "adc", _, AM_IMM }, { /*6a*/ "ror", _, AM_ACC }, { /*6b*/ "rtl", G, AM_STACK }, { /*6c*/ "jmp", _, AM_ABS_IND }, { /*6d*/ "adc", _, AM_ABS }, { /*6e*/ "ror", _, AM_ABS }, { /*6f*/ "adc", G, AM_ABSLONG }, { /*70*/ "bvs", _, AM_RELATIVE }, { /*71*/ "adc", _, AM_DIR_IND_INX }, { /*72*/ "adc", G, AM_DIR_IND }, { /*73*/ "adc", G, AM_STK_REL_IND_INX }, { /*74*/ "stz", G, AM_DIR_INX_X }, { /*75*/ "adc", _, AM_DIR_INX_X }, { /*76*/ "ror", _, AM_DIR_INX_X }, { /*77*/ "adc", G, AM_DIR_IND_INX_LONG }, { /*78*/ "sei", _, AM_IMPLIED }, { /*79*/ "adc", _, AM_ABS_INX_Y }, { /*7a*/ "ply", G, AM_STACK }, { /*7b*/ "tdc", G, AM_IMPLIED }, { /*7c*/ "jmp", G, AM_ABS_INX_IND }, { /*7d*/ "adc", _, AM_ABS_INX_X }, { /*7e*/ "ror", _, AM_ABS_INX_X }, { /*7f*/ "adc", G, AM_ABSLONG_INX_X }, { /*80*/ "bra", G, AM_RELATIVE }, { /*81*/ "sta", _, AM_DIR_INX_IND }, { /*82*/ "brl", G, AM_RELATIVE_LONG }, { /*83*/ "sta", G, AM_STK_REL }, { /*84*/ "sty", _, AM_DIRECT }, { /*85*/ "sta", _, AM_DIRECT }, { /*86*/ "stx", _, AM_DIRECT }, { /*87*/ "sta", G, AM_DIR_IND_LONG }, { /*88*/ "dey", _, AM_IMPLIED }, { /*89*/ "bit", G, AM_IMM }, { /*8a*/ "txa", _, AM_IMPLIED }, { /*8b*/ "phb", G, AM_STACK }, { /*8c*/ "sty", _, AM_ABS }, { /*8d*/ "sta", _, AM_ABS }, { /*8e*/ "stx", _, AM_ABS }, { /*8f*/ "sta", G, AM_ABSLONG }, { /*90*/ "bcc", _, AM_RELATIVE }, { /*91*/ "sta", _, AM_DIR_IND_INX }, { /*92*/ "sta", G, AM_DIR_IND }, { /*93*/ "sta", G, AM_STK_REL_IND_INX }, { /*94*/ "sty", _, AM_DIR_INX_X }, { /*95*/ "sta", _, AM_DIR_INX_X }, { /*96*/ "stx", _, AM_DIR_INX_Y }, { /*97*/ "sta", G, AM_DIR_IND_INX_LONG }, { /*98*/ "tya", _, AM_IMPLIED }, { /*99*/ "sta", _, AM_ABS_INX_Y }, { /*9a*/ "txs", _, AM_IMPLIED }, { /*9b*/ "txy", G, AM_IMPLIED }, { /*9c*/ "stz", G, AM_ABS }, { /*9d*/ "sta", _, AM_ABS_INX_X }, { /*9e*/ "stz", G, AM_ABS_INX_X }, { /*9f*/ "sta", G, AM_ABSLONG_INX_X }, { /*a0*/ "ldy", _, AM_IMM }, { /*a1*/ "lda", _, AM_DIR_INX_IND }, { /*a2*/ "ldx", _, AM_IMM }, { /*a3*/ "lda", G, AM_STK_REL }, { /*a4*/ "ldy", _, AM_DIRECT }, { /*a5*/ "lda", _, AM_DIRECT }, { /*a6*/ "ldx", _, AM_DIRECT }, { /*a7*/ "lda", G, AM_DIR_IND_LONG }, { /*a8*/ "tay", _, AM_IMPLIED }, { /*a9*/ "lda", _, AM_IMM }, { /*aa*/ "tax", _, AM_IMPLIED }, { /*ab*/ "plb", G, AM_STACK }, { /*ac*/ "ldy", _, AM_ABS }, { /*ad*/ "lda", _, AM_ABS }, { /*ae*/ "ldx", _, AM_ABS }, { /*af*/ "lda", G, AM_ABSLONG }, { /*b0*/ "bcs", _, AM_RELATIVE }, { /*b1*/ "lda", _, AM_DIR_IND_INX }, { /*b2*/ "lda", G, AM_DIR_IND }, { /*b3*/ "lda", G, AM_STK_REL_IND_INX }, { /*b4*/ "ldy", _, AM_DIR_INX_X }, { /*b5*/ "lda", _, AM_DIR_INX_X }, { /*b6*/ "ldx", _, AM_DIR_INX_Y }, { /*b7*/ "lda", G, AM_DIR_IND_INX_LONG }, { /*b8*/ "clv", _, AM_IMPLIED }, { /*b9*/ "lda", _, AM_ABS_INX_Y }, { /*ba*/ "tsx", _, AM_IMPLIED }, { /*bb*/ "tyx", G, AM_IMPLIED }, { /*bc*/ "ldy", _, AM_ABS_INX_X }, { /*bd*/ "lda", _, AM_ABS_INX_X }, { /*be*/ "ldx", _, AM_ABS_INX_Y }, { /*bf*/ "lda", G, AM_ABSLONG_INX_X }, { /*c0*/ "cpy", _, AM_IMM }, { /*c1*/ "cmp", _, AM_DIR_INX_IND }, { /*c2*/ "rep", G, AM_IMM }, { /*c3*/ "cmp", G, AM_STK_REL }, { /*c4*/ "cpy", _, AM_DIRECT }, { /*c5*/ "cmp", _, AM_DIRECT }, { /*c6*/ "dec", _, AM_DIRECT }, { /*c7*/ "cmp", G, AM_DIR_IND_LONG }, { /*c8*/ "iny", _, AM_IMPLIED }, { /*c9*/ "cmp", _, AM_IMM }, { /*ca*/ "dex", _, AM_IMPLIED }, { /*cb*/ "wai", G, AM_IMPLIED }, { /*cc*/ "cpy", _, AM_ABS }, { /*cd*/ "cmp", _, AM_ABS }, { /*ce*/ "dec", _, AM_ABS }, { /*cf*/ "cmp", G, AM_ABSLONG }, { /*d0*/ "bne", _, AM_RELATIVE }, { /*d1*/ "cmp", _, AM_DIR_IND_INX }, { /*d2*/ "cmp", G, AM_DIR_IND }, { /*d3*/ "cmp", G, AM_STK_REL_IND_INX }, { /*d4*/ "pei", G, AM_STACK }, { /*d5*/ "cmp", _, AM_DIR_INX_X }, { /*d6*/ "dec", _, AM_DIR_INX_X }, { /*d7*/ "cmp", G, AM_DIR_IND_INX_LONG }, { /*d8*/ "cld", _, AM_IMPLIED }, { /*d9*/ "cmp", _, AM_ABS_INX_Y }, { /*da*/ "phx", G, AM_STACK }, { /*db*/ "stp", G, AM_IMPLIED }, { /*dc*/ "jml", G, AM_ABS_IND }, { /*dd*/ "cmp", _, AM_ABS_INX_X }, { /*de*/ "dec", _, AM_ABS_INX_X }, { /*df*/ "cmp", G, AM_ABSLONG_INX_X }, { /*e0*/ "cpx", _, AM_IMM }, { /*e1*/ "sbc", _, AM_DIR_INX_IND }, { /*e2*/ "sep", G, AM_IMM }, { /*e3*/ "sbc", G, AM_STK_REL }, { /*e4*/ "cpx", _, AM_DIRECT }, { /*e5*/ "sbc", _, AM_DIRECT }, { /*e6*/ "inc", _, AM_DIRECT }, { /*e7*/ "sbc", G, AM_DIR_IND_LONG }, { /*e8*/ "inx", _, AM_IMPLIED }, { /*e9*/ "sbc", _, AM_IMM }, { /*ea*/ "nop", _, AM_IMPLIED }, { /*eb*/ "xba", G, AM_IMPLIED }, { /*ec*/ "cpx", _, AM_ABS }, { /*ed*/ "sbc", _, AM_ABS }, { /*ee*/ "inc", _, AM_ABS }, { /*ef*/ "sbc", G, AM_ABSLONG }, { /*f0*/ "beq", _, AM_RELATIVE }, { /*f1*/ "sbc", _, AM_DIR_IND_INX }, { /*f2*/ "sbc", G, AM_DIR_IND }, { /*f3*/ "sbc", G, AM_STK_REL_IND_INX }, { /*f4*/ "pea", G, AM_STACK }, { /*f5*/ "sbc", _, AM_DIR_INX_X }, { /*f6*/ "inc", _, AM_DIR_INX_X }, { /*f7*/ "sbc", G, AM_DIR_IND_INX_LONG }, { /*f8*/ "sed", _, AM_IMPLIED }, { /*f9*/ "sbc", _, AM_ABS_INX_Y }, { /*fa*/ "plx", G, AM_STACK }, { /*fb*/ "xce", G, AM_IMPLIED }, { /*fc*/ "jsr", G, AM_ABS_INX_IND }, { /*fd*/ "sbc", _, AM_ABS_INX_X }, { /*fe*/ "inc", _, AM_ABS_INX_X }, { /*ff*/ "sbc", G, AM_ABSLONG_INX_X } }; #undef G #undef _ static int max_nbytes; static void print_with_symbol(void (*fn)(char), ADDR a, const char *fmt) { SYMBOL *s; s = symbol_for_addr(a); if (s) { fnprintf(fn,"%s",s->name); } else { fnprintf(fn,fmt,(unsigned long int)a); } maybe_print_stringptr(fn,a); } static int do_dis_inst(ADDR addr, void (*fn)(char), CFLAG flg, int mkind) { unsigned char opc; int i; addr -= corebase; if (addr >= coresize) return(-1); opc = corefetchu(addr,1); if ( !(instrs[opc].variant & mkind) || (addr+instrs[opc].nbytes > coresize) ) { flags[addr] = CF_BYTE; return(0); } for (i=0;i0;i--) flags[addr+i] = CF_PREV; return(instrs[opc].nbytes); } static void print_signed(void (*fn)(char), unsigned short int v, unsigned short int signbit) { if (v & signbit) { fnprintf(fn,"-%d",(signbit<<1)-v); } else { fnprintf(fn,"+%d",v); } } static void print_z_value(void (*fn)(char), int z) { switch (z) { case 0: fnprintf(fn,"off"); break; case 1: fnprintf(fn,"stat"); break; default: fnprintf(fn,"%d",z*2); break; } } static int do_dis_vg(ADDR addr, void (*fn)(char)) { unsigned short int op; unsigned short int op2; addr -= corebase; if (addr+2 > coresize) return(-1); op = corefetchu(addr,2); if (op & 0xe000) { fnprintf(fn,"%04x ",op); switch (op >> 13) { case 1: fnprintf(fn," vhalt"); break; case 2: fnprintf(fn," vsdraw x="); print_signed(fn,(op<<1)&0x3e,0x20); fnprintf(fn," y="); print_signed(fn,(op>>7)&0x3e,0x20); fnprintf(fn," z="); print_z_value(fn,(op>>5)&7); break; case 3: if (op & 0x1000) { fnprintf(fn," vscale b=%d l=%d",(op>>8)&7,op&0x00ff); } else { fnprintf(fn," vstat z=%d c=%d sparkle=%d",(op>>4)&15,op&15,(op>>11)&1); } break; case 4: fnprintf(fn," vcentre"); break; case 5: fnprintf(fn," vjsr $%04x",(op&0x1fff)<<1); if (op == 0xa000) fnprintf(fn," (halt)"); break; case 6: fnprintf(fn," vrts"); break; case 7: fnprintf(fn," vjmp $%04x",(op&0x1fff)<<1); if (op == 0xe000) fnprintf(fn," (halt)"); break; } flags[addr+1] = CF_PREV; return(2); } else { if (addr+4 > coresize) return(-1); op2 = corefetchu(addr+2,2); fnprintf(fn,"%04x%04x ",op,op2); fnprintf(fn," vldraw x="); print_signed(fn,op2&0x1fff,0x1000); fnprintf(fn," y="); print_signed(fn,op&0x1fff,0x1000); fnprintf(fn," z="); print_z_value(fn,op2>>13); flags[addr+1] = CF_PREV; flags[addr+2] = CF_PREV; flags[addr+3] = CF_PREV; return(4); } } static int do_dis_jt(ADDR addr, void (*fn)(char)) { addr -= corebase; if (addr+2 > coresize) return(-1); fnprintf(fn,".jump "); print_with_symbol(fn,(corefetchu(addr,2)+1)&0xffff,"$%04lx"); return(2); } static void common_init(int mkind) { int nb; int i; max_nbytes = 0; for (i=0;i<256;i++) { if (! (instrs[i].variant & mkind)) continue; switch (instrs[i].addrmode) { default: abort(); break; case AM_IMM: nb = 2; break; case AM_ABS: nb = 3; break; case AM_ABSLONG: nb = 4; break; case AM_DIRECT: nb = 2; break; case AM_ACC: nb = 1; break; case AM_IMPLIED: nb = 1; break; case AM_DIR_IND_INX: nb = 2; break; case AM_DIR_IND_INX_LONG: nb = 2; break; case AM_DIR_INX_IND: nb = 2; break; case AM_DIR_INX_X: nb = 2; break; case AM_DIR_INX_Y: nb = 2; break; case AM_ABS_INX_X: nb = 3; break; case AM_ABS_INX_Y: nb = 3; break; case AM_ABSLONG_INX_X: nb = 4; break; case AM_RELATIVE: nb = 2; break; case AM_RELATIVE_LONG: nb = 3; break; case AM_ABS_IND: nb = 3; break; case AM_DIR_IND: nb = 2; break; case AM_DIR_IND_LONG: nb = 2; break; case AM_ABS_INX_IND: nb = 3; break; case AM_STACK: nb = 1; break; case AM_STK_REL: nb = 2; break; case AM_STK_REL_IND_INX: nb = 2; break; case AM_BLOCK: nb = 3; break; } instrs[i].nbytes = nb; if (nb > max_nbytes) max_nbytes = nb; } } static void g65sc802_init(void) { common_init(M_G65SC802); } static void tempest_init(void) { common_init(M_6502); } static int g65sc802_dis(ADDR addr, void (*fn)(char)) { int rv; if (ISINST(flags[addr-corebase])) { rv = do_dis_inst(addr,fn,flags[addr-corebase],M_G65SC802); } else { fnprintf(fn,"",(unsigned long int)flags[addr-corebase]); rv = 1; } return(rv); } static int tempest_dis(ADDR addr, void (*fn)(char)) { int rv; switch (flags[addr-corebase]) { default: if (ISINST(flags[addr-corebase])) { rv = do_dis_inst(addr,fn,flags[addr-corebase],M_6502); } else { fnprintf(fn,"",(unsigned long int)flags[addr-corebase]); rv = 1; } break; case CF_VG: rv = do_dis_vg(addr,fn); break; case CF_JT: rv = do_dis_jt(addr,fn); break; } return(rv); } static unsigned long int g65sc802_fetch(const void *base, int size) #define bp(n) ((unsigned long int)(((const unsigned char *)base)[(n)])) { switch (size) { case 1: return(bp(0)); break; case 2: return((bp(1)<<8)|bp(0)); break; case 3: return((bp(2)<<16)|(bp(1)<<8)|bp(0)); break; case 4: return((bp(3)<<24)|(bp(2)<<16)|(bp(1)<<8)|bp(0)); break; } abort(); } #undef bp static void v_command(void) { if (changecur_()) return; flags[loc.u.on.aoff] = CF_VG; } static void J_command(void) { if (changecur_()) return; flags[loc.u.on.aoff] = CF_JT; } static int tempest_cmd(char ch) { switch (ch) { case 'v': v_command(); return(1); break; case 'J': J_command(); return(1); break; } return(0); } static const char *g65sc802_names[] = { "G65SC802", "g65sc802", 0 }; MACHINE machine_g65sc802 = { &g65sc802_names[0], 2, &g65sc802_init, 0, &g65sc802_dis, &g65sc802_fetch, 0 }; static const char *tempest_names[] = { "tempest", "Tempest", 0 }; MACHINE machine_tempest = { &tempest_names[0], 2, &tempest_init, &tempest_cmd, &tempest_dis, &g65sc802_fetch, 0 };