diff --git a/bsnes/Makefile b/bsnes/Makefile index d415b9d8d..800ea930d 100755 --- a/bsnes/Makefile +++ b/bsnes/Makefile @@ -1,11 +1,11 @@ include nall/Makefile snes := snes gameboy := gameboy -profile := accuracy +profile := performance ui := ui # debugger -options := debugger +options := # compiler c := $(compiler) -std=gnu99 diff --git a/bsnes/snes/alt/smp/core.cpp b/bsnes/snes/alt/smp/core.cpp index dba9ccd22..ae119f701 100755 --- a/bsnes/snes/alt/smp/core.cpp +++ b/bsnes/snes/alt/smp/core.cpp @@ -1,94 +1,136 @@ void SMP::op_io() { - timer0.tick(); - timer1.tick(); - timer2.tick(); } uint8 SMP::op_read(uint16 addr) { - timer0.tick(); - timer1.tick(); - timer2.tick(); - if((addr & 0xfff0) == 0x00f0) return mmio_read(addr); if((addr & 0xffc0) == 0xffc0 && status.iplrom_enable) return iplrom[addr & 0x3f]; return apuram[addr]; } void SMP::op_write(uint16 addr, uint8 data) { - timer0.tick(); - timer1.tick(); - timer2.tick(); - if((addr & 0xfff0) == 0x00f0) mmio_write(addr, data); apuram[addr] = data; //all writes go to RAM, even MMIO writes } -#define op_readpc() op_read(regs.pc++) -#define op_readdp(addr) op_read((regs.p.p << 8) + addr) -#define op_writedp(addr, data) op_write((regs.p.p << 8) + addr, data) - -#define OP_ADJUST_DP(func) \ - dp = op_readpc(); \ - rd = op_readdp(dp); \ - rd = func(rd); \ - op_writedp(dp, rd); - -#define OP_ADJUST_REG(func, target) \ - op_io(); \ - target = func(target); - -#define OP_BRANCH(condition) \ - rd = op_readpc(); \ - if(condition) { \ - op_io(); \ - op_io(); \ - regs.pc += (int8)rd; \ - } - -#define OP_MOV_DP_REG(source) \ - dp = op_readpc(); \ - op_readdp(dp); \ - op_writedp(dp, source); - -#define OP_MOV_REG_CONST(target) \ - target = op_readpc(); \ - regs.p.n = (target & 0x80); \ - regs.p.z = (target == 0); - -#define OP_MOV_REG_DP(target) \ - sp = op_readpc(); \ - target = op_readdp(sp); \ - regs.p.n = (target & 0x80); \ - regs.p.z = (target == 0); - -#define OP_MOV_REG_REG(target, source) \ - op_io(); \ - target = source; \ - regs.p.n = (target & 0x80); \ - regs.p.z = (target == 0); - -#define OP_READ_REG_DP(func, target) \ - dp = op_readpc(); \ - rd = op_readdp(dp); \ - target = func(target, rd); +//TODO: +//* untaken conditional branches should subtract from opcode's cycle overhead void SMP::op_step() { - unsigned opcode = op_readpc(); - op_io(); + #define op_readpc() op_read(regs.pc++) + #define op_readdp(addr) op_read((regs.p.p << 8) + addr) + #define op_writedp(addr, data) op_write((regs.p.p << 8) + addr, data) +//#define op_readsp() op_read(0x0100 | ++regs.sp) +//#define op_writesp(data) op_write(0x0100 | regs.sp--, data) + #define op_readsp() stackram[++regs.sp] + #define op_writesp(data) stackram[regs.sp--] = data + static unsigned rd, wr, dp, sp, ya, bit; - static unsigned rd, wr, dp, sp; + unsigned opcode = op_readpc(); switch(opcode) { case 0x00: //nop + op_io(); break; - case 0x10: //bpl $rr - OP_BRANCH(regs.p.n == 0) + case 0xef: //sleep + case 0xff: //stop + regs.pc--; break; - case 0x1d: //dec x - OP_ADJUST_REG(fn_dec, regs.x) +// +// batch +// + + case 0x01: case 0x11: case 0x21: case 0x31: case 0x41: case 0x51: case 0x61: case 0x71: + case 0x81: case 0x91: case 0xa1: case 0xb1: case 0xc1: case 0xd1: case 0xe1: case 0xf1: //tcall vector + dp = 0xffde - ((opcode >> 4) << 1); + rd = op_read(dp + 0) << 0; + rd |= op_read(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writesp(regs.pc >> 8); + op_writesp(regs.pc >> 0); + regs.pc = rd; + break; + + case 0x02: case 0x22: case 0x42: case 0x62: case 0x82: case 0xa2: case 0xc2: case 0xe2: //setB $dp + dp = op_readpc(); + rd = op_readdp(dp) | (1 << (opcode >> 5)); + op_writedp(dp, rd); + break; + + case 0x12: case 0x32: case 0x52: case 0x72: case 0x92: case 0xb2: case 0xd2: case 0xf2: //clrB $dp + dp = op_readpc(); + rd = op_readdp(dp) &~ (1 << (opcode >> 5)); + op_writedp(dp, rd); + break; + + case 0x03: case 0x23: case 0x43: case 0x63: case 0x83: case 0xa3: case 0xc3: case 0xe3: //bbsB $dp,$rr + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & (1 << (opcode >> 5))) == 0) break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; + + case 0x13: case 0x33: case 0x53: case 0x73: case 0x93: case 0xb3: case 0xd3: case 0xf3: //bbcB $dp,$rr + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & (1 << (opcode >> 5))) != 0) break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; + + case 0x20: op_io(); regs.p.p = 0; break; //clrp + case 0x40: op_io(); regs.p.p = 1; break; //setp + case 0x60: op_io(); regs.p.c = 0; break; //clrc + case 0x80: op_io(); regs.p.c = 1; break; //setc + case 0xe0: op_io(); regs.p.v = 0; break; //clrv + // + case 0xa0: op_io(); op_io(); regs.p.i = 1; break; //ei + case 0xc0: op_io(); op_io(); regs.p.i = 0; break; //di + // + case 0xed: op_io(); op_io(); regs.p.c = !regs.p.c; break; //notc + +// +// jump +// + +#define OP_BRANCH_IF(condition) \ + rd = op_readpc(); \ + if((condition) == false) break; \ + op_io(); \ + op_io(); \ + regs.pc += (int8)rd; \ + break; + case 0x10: OP_BRANCH_IF(regs.p.n == 0); //bpl $rr + case 0x30: OP_BRANCH_IF(regs.p.n == 1); //bmi $rr + case 0x50: OP_BRANCH_IF(regs.p.v == 0); //bvc $rr + case 0x70: OP_BRANCH_IF(regs.p.v == 1); //bvs $rr + case 0x90: OP_BRANCH_IF(regs.p.c == 0); //bcc $rr + case 0xb0: OP_BRANCH_IF(regs.p.c == 1); //bcs $rr + case 0xd0: OP_BRANCH_IF(regs.p.z == 0); //bne $rr + case 0xf0: OP_BRANCH_IF(regs.p.z == 1); //beq $rr + + case 0x0f: //brk + rd = op_read(0xffde) << 0; + rd |= op_read(0xffdf) << 8; + op_io(); + op_io(); + op_writesp(regs.pc >> 8); + op_writesp(regs.pc >> 0); + op_writesp(regs.p); + regs.pc = rd; + regs.p.b = 1; + regs.p.i = 0; break; case 0x1f: //jmp ($aaaa,x) @@ -108,26 +150,437 @@ void SMP::op_step() { regs.pc += (int8)rd; break; - case 0x5d: //mov x,a - OP_MOV_REG_REG(regs.x, regs.a) + case 0x3f: //call $addr + rd = op_readpc() << 0; + rd |= op_readpc() << 8; + op_io(); + op_io(); + op_io(); + op_writesp(regs.pc >> 8); + op_writesp(regs.pc >> 0); + regs.pc = rd; break; - case 0x78: //cmp $dp,#$ss + case 0x4f: //pcall $ff00+$dp rd = op_readpc(); + op_io(); + op_io(); + op_writesp(regs.pc >> 8); + op_writesp(regs.pc >> 0); + regs.pc = 0xff00 | rd; + break; + + case 0x5f: //jmp $addr + rd = op_readpc() << 0; + rd |= op_readpc() << 8; + regs.pc = rd; + break; + + case 0x6f: //ret + rd = op_readsp() << 0; + rd |= op_readsp() << 8; + op_io(); + op_io(); + regs.pc = rd; + break; + + case 0x7f: //reti + regs.p = op_readsp(); + rd = op_readsp() << 0; + rd |= op_readsp() << 8; + op_io(); + op_io(); + regs.pc = rd; + break; + + case 0x2e: //cbne $dp,$rr + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if(regs.a == sp) break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; + + case 0x6e: //dbnz $dp,$rr dp = op_readpc(); wr = op_readdp(dp); - fn_cmp(wr, rd); + op_writedp(dp, --wr); + rd = op_readpc(); + if(wr == 0) break; op_io(); + op_io(); + regs.pc += (int8)rd; break; - case 0x7d: //mov a,x - OP_MOV_REG_REG(regs.a, regs.x) + case 0xde: //cbne $dp+x,$rr + dp = op_readpc(); + op_io(); + sp = op_readdp(dp + regs.x); + rd = op_readpc(); + op_io(); + if(regs.a == sp) break; + op_io(); + op_io(); + regs.pc += (int8)rd; break; - case 0x7e: //cmp y,$dp - OP_READ_REG_DP(fn_cmp, regs.y) + case 0xfe: //dbz y,$rr + rd = op_readpc(); + op_io(); + regs.y--; + op_io(); + if(regs.y == 0) break; + op_io(); + op_io(); + regs.pc += (int8)rd; break; +// +// stack +// + +#define OP_PUSH_REG(source) \ + op_io(); \ + op_io(); \ + op_writesp(source); \ + break; + case 0x0d: OP_PUSH_REG(regs.p); //push p + case 0x2d: OP_PUSH_REG(regs.a); //push a + case 0x4d: OP_PUSH_REG(regs.x); //push x + case 0x6d: OP_PUSH_REG(regs.y); //push y + +#define OP_POP_REG(target) \ + op_io(); \ + op_io(); \ + target = op_readsp(); \ + break; + case 0x8e: OP_POP_REG(regs.p); //pop p + case 0xae: OP_POP_REG(regs.a); //pop a + case 0xce: OP_POP_REG(regs.x); //pop x + case 0xee: OP_POP_REG(regs.y); //pop y + +// +// ALU +// + + case 0x9e: //div ya,x + op_io(); op_io(); op_io(); op_io(); + op_io(); op_io(); op_io(); op_io(); + op_io(); op_io(); op_io(); + ya = regs.ya; + regs.p.v = !!(regs.y >= regs.x); + regs.p.h = !!((regs.y & 15) >= (regs.x & 15)); + if(regs.y < (regs.x << 1)) { + regs.a = ya / regs.x; + regs.y = ya % regs.x; + } else { + regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x); + regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x); + } + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; + + case 0xcf: //mul ya + op_io(); op_io(); op_io(); op_io(); + op_io(); op_io(); op_io(); op_io(); + ya = regs.y * regs.a; + regs.a = ya; + regs.y = ya >> 8; + regs.p.n = (regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; + +// +// read +// + +#define OP_READ_REG_DP(func, target) \ + dp = op_readpc(); \ + rd = op_readdp(dp); \ + target = func(target, rd); \ + break; + case 0x04: OP_READ_REG_DP(fn_or, regs.a); //or a,$dp + case 0x24: OP_READ_REG_DP(fn_and, regs.a); //and a,$dp + case 0x44: OP_READ_REG_DP(fn_eor, regs.a); //eor a,$dp + case 0x64: OP_READ_REG_DP(fn_cmp, regs.a); //cmp a,$dp + case 0x84: OP_READ_REG_DP(fn_adc, regs.a); //adc a,$dp + case 0xa4: OP_READ_REG_DP(fn_sbc, regs.a); //sbc a,$dp + // + case 0x3e: OP_READ_REG_DP(fn_cmp, regs.x); //cmp x,$dp + case 0x7e: OP_READ_REG_DP(fn_cmp, regs.y); //cmp y,$dp + +#define OP_READ_REG_ADDR(func, target) \ + dp = op_readpc() << 0; \ + dp |= op_readpc() << 8; \ + rd = op_read(dp); \ + target = func(target, rd); \ + break; + case 0x05: OP_READ_REG_ADDR(fn_or, regs.a); //or a,$addr + case 0x25: OP_READ_REG_ADDR(fn_and, regs.a); //and a,$addr + case 0x45: OP_READ_REG_ADDR(fn_eor, regs.a); //eor a,$addr + case 0x65: OP_READ_REG_ADDR(fn_cmp, regs.a); //cmp a,$addr + case 0x85: OP_READ_REG_ADDR(fn_adc, regs.a); //adc a,$addr + case 0xa5: OP_READ_REG_ADDR(fn_sbc, regs.a); //sbc a,$addr + // + case 0x1e: OP_READ_REG_ADDR(fn_cmp, regs.x); //cmp x,$addr + case 0x5e: OP_READ_REG_ADDR(fn_cmp, regs.y); //cmp y,$addr + +#define OP_READ_A_IX(func) \ + op_io(); \ + rd = op_readdp(regs.x); \ + regs.a = func(regs.a, rd); \ + break; + case 0x06: OP_READ_A_IX(fn_or ); //or a,(x) + case 0x26: OP_READ_A_IX(fn_and); //and a,(x) + case 0x46: OP_READ_A_IX(fn_eor); //eor a,(x) + case 0x66: OP_READ_A_IX(fn_cmp); //cmp a,(x) + case 0x86: OP_READ_A_IX(fn_adc); //adc a,(x) + case 0xa6: OP_READ_A_IX(fn_sbc); //sbc a,(x) + +#define OP_READ_A_IDPX(func) \ + dp = op_readpc() + regs.x; \ + op_io(); \ + sp = op_readdp(dp + 0) << 0; \ + sp |= op_readdp(dp + 1) << 8; \ + rd = op_read(sp); \ + regs.a = func(regs.a, rd); \ + break; + case 0x07: OP_READ_A_IDPX(fn_or ); //or a,($dp+x) + case 0x27: OP_READ_A_IDPX(fn_and); //and a,($dp+x) + case 0x47: OP_READ_A_IDPX(fn_eor); //eor a,($dp+x) + case 0x67: OP_READ_A_IDPX(fn_cmp); //cmp a,($dp+x) + case 0x87: OP_READ_A_IDPX(fn_adc); //adc a,($dp+x) + case 0xa7: OP_READ_A_IDPX(fn_sbc); //sbc a,($dp+x) + +#define OP_READ_REG_CONST(func, target) \ + rd = op_readpc(); \ + target = func(target, rd); \ + break; + case 0x08: OP_READ_REG_CONST(fn_or, regs.a); //or a,#$ss + case 0x28: OP_READ_REG_CONST(fn_and, regs.a); //and a,#$ss + case 0x48: OP_READ_REG_CONST(fn_eor, regs.a); //eor a,#$ss + case 0x68: OP_READ_REG_CONST(fn_cmp, regs.a); //cmp a,#$ss + case 0x88: OP_READ_REG_CONST(fn_adc, regs.a); //adc a,#$ss + case 0xa8: OP_READ_REG_CONST(fn_sbc, regs.a); //sbc a,#$ss + // + case 0xad: OP_READ_REG_CONST(fn_cmp, regs.y); //cmp y,#$ss + case 0xc8: OP_READ_REG_CONST(fn_cmp, regs.x); //cmp x,#$ss + +#define OP_READ_DP_DP(func) \ + sp = op_readpc(); \ + rd = op_readdp(sp); \ + dp = op_readpc(); \ + wr = op_readdp(dp); \ + wr = func(wr, rd); + case 0x09: OP_READ_DP_DP(fn_or ); op_writedp(dp, wr); break; //or $dp,$dp + case 0x29: OP_READ_DP_DP(fn_and); op_writedp(dp, wr); break; //and $dp,$dp + case 0x49: OP_READ_DP_DP(fn_eor); op_writedp(dp, wr); break; //eor $dp,$dp + case 0x69: OP_READ_DP_DP(fn_cmp); op_io(); break; //cmp $dp,$dp + case 0x89: OP_READ_DP_DP(fn_adc); op_writedp(dp, wr); break; //adc $dp,$dp + case 0xa9: OP_READ_DP_DP(fn_sbc); op_writedp(dp, wr); break; //sbc $dp,$dp + +#define OP_READ_A_DPX(func) \ + dp = op_readpc(); \ + op_io(); \ + rd = op_readdp(dp + regs.x); \ + regs.a = func(regs.a, rd); \ + break; + case 0x14: OP_READ_A_DPX(fn_or ); //or a,$dp+x + case 0x34: OP_READ_A_DPX(fn_and); //and a,$dp+x + case 0x54: OP_READ_A_DPX(fn_eor); //eor a,$dp+x + case 0x74: OP_READ_A_DPX(fn_cmp); //cmp a,$dp+x + case 0x94: OP_READ_A_DPX(fn_adc); //adc a,$dp+x + case 0xb4: OP_READ_A_DPX(fn_sbc); //sbc a,$dp+x + +#define OP_READ_A_ADDRR(func, source) \ + dp = op_readpc() << 0; \ + dp |= op_readpc() << 8; \ + op_io(); \ + rd = op_read(dp + source); \ + regs.a = func(regs.a, rd); \ + break; + case 0x15: OP_READ_A_ADDRR(fn_or , regs.x); //or a,$dp+x + case 0x16: OP_READ_A_ADDRR(fn_or , regs.y); //or a,$dp+y + case 0x35: OP_READ_A_ADDRR(fn_and, regs.x); //and a,$dp+x + case 0x36: OP_READ_A_ADDRR(fn_and, regs.y); //and a,$dp+y + case 0x55: OP_READ_A_ADDRR(fn_eor, regs.x); //eor a,$dp+x + case 0x56: OP_READ_A_ADDRR(fn_eor, regs.y); //eor a,$dp+y + case 0x75: OP_READ_A_ADDRR(fn_cmp, regs.x); //cmp a,$dp+x + case 0x76: OP_READ_A_ADDRR(fn_cmp, regs.y); //cmp a,$dp+y + case 0x95: OP_READ_A_ADDRR(fn_adc, regs.x); //adc a,$dp+x + case 0x96: OP_READ_A_ADDRR(fn_adc, regs.y); //adc a,$dp+y + case 0xb5: OP_READ_A_ADDRR(fn_sbc, regs.x); //sbc a,$dp+x + case 0xb6: OP_READ_A_ADDRR(fn_sbc, regs.y); //sbc a,$dp+y + +#define OP_READ_A_IDPY(func) \ + dp = op_readpc(); \ + op_io(); \ + sp = op_readdp(dp + 0) << 0; \ + sp |= op_readdp(dp + 1) << 8; \ + rd = op_read(sp + regs.y); \ + regs.a = func(regs.a, rd); \ + break; + case 0x17: OP_READ_A_IDPY(fn_or ); //or a,($dp)+y + case 0x37: OP_READ_A_IDPY(fn_and); //and a,($dp)+y + case 0x57: OP_READ_A_IDPY(fn_eor); //eor a,($dp)+y + case 0x77: OP_READ_A_IDPY(fn_cmp); //cmp a,($dp)+y + case 0x97: OP_READ_A_IDPY(fn_adc); //adc a,($dp)+y + case 0xb7: OP_READ_A_IDPY(fn_sbc); //sbc a,($dp)+y + +#define OP_READ_DP_CONST(func) \ + rd = op_readpc(); \ + dp = op_readpc(); \ + wr = op_readdp(dp); \ + wr = func(wr, rd); + case 0x18: OP_READ_DP_CONST(fn_or ); op_writedp(dp, wr); break; //or $dp,#$ss + case 0x38: OP_READ_DP_CONST(fn_and); op_writedp(dp, wr); break; //and $dp,#$ss + case 0x58: OP_READ_DP_CONST(fn_eor); op_writedp(dp, wr); break; //eor $dp,#$ss + case 0x78: OP_READ_DP_CONST(fn_cmp); op_io(); break; //cmp $dp,#$ss + case 0x98: OP_READ_DP_CONST(fn_adc); op_writedp(dp, wr); break; //adc $dp,#$ss + case 0xb8: OP_READ_DP_CONST(fn_sbc); op_writedp(dp, wr); break; //sbc $dp,#$ss + +#define OP_READ_IX_IY(func) \ + op_io(); \ + rd = op_readdp(regs.y); \ + wr = op_readdp(regs.x); \ + wr = func(wr, rd); + case 0x19: OP_READ_IX_IY(fn_or ); op_writedp(regs.x, wr); break; //or (x),(y) + case 0x39: OP_READ_IX_IY(fn_and); op_writedp(regs.x, wr); break; //and (x),(y) + case 0x59: OP_READ_IX_IY(fn_eor); op_writedp(regs.x, wr); break; //eor (x),(y) + case 0x79: OP_READ_IX_IY(fn_cmp); op_io(); break; //cmp (x),(y) + case 0x99: OP_READ_IX_IY(fn_adc); op_writedp(regs.x, wr); break; //adc (x),(y) + case 0xb9: OP_READ_IX_IY(fn_sbc); op_writedp(regs.x, wr); break; //sbc (x),(y) + +#define OP_READ_YA_DP(func) \ + dp = op_readpc(); \ + rd = op_readdp(dp + 0) << 0; \ + op_io(); \ + rd |= op_readdp(dp + 1) << 8; \ + regs.ya = func(regs.ya, rd); \ + break; + case 0x7a: OP_READ_YA_DP(fn_addw); //addw $dp + case 0x9a: OP_READ_YA_DP(fn_subw); //subw $dp + +// +// move +// + +#define OP_MOV_REG_REG(target, source) \ + op_io(); \ + target = source; \ + regs.p.n = (target & 0x80); \ + regs.p.z = (target == 0); \ + break; + case 0x5d: OP_MOV_REG_REG(regs.x, regs.a ); //mov x,a + case 0x7d: OP_MOV_REG_REG(regs.a, regs.x ); //mov a,x + case 0x9d: OP_MOV_REG_REG(regs.x, regs.sp); //mov x,sp + case 0xdd: OP_MOV_REG_REG(regs.a, regs.y ); //mov a,y + case 0xfd: OP_MOV_REG_REG(regs.y, regs.a ); //mov y,a + +#define OP_MOV_REG_CONST(target) \ + target = op_readpc(); \ + regs.p.n = (target & 0x80); \ + regs.p.z = (target == 0); \ + break; + case 0x8d: OP_MOV_REG_CONST(regs.y); //mov y,#$ss + case 0xcd: OP_MOV_REG_CONST(regs.x); //mov x,#$ss + case 0xe8: OP_MOV_REG_CONST(regs.a); //mov a,#$ss + +#define OP_MOV_DP_REG(source) \ + dp = op_readpc(); \ + op_readdp(dp); \ + op_writedp(dp, source); \ + break; + case 0xc4: OP_MOV_DP_REG(regs.a); //mov $dp,a + case 0xcb: OP_MOV_DP_REG(regs.y); //mov $dp,y + case 0xd8: OP_MOV_DP_REG(regs.x); //mov $dp,x + +#define OP_MOV_ADDR_REG(source) \ + dp = op_readpc() << 0; \ + dp |= op_readpc() << 8; \ + op_read(dp); \ + op_write(dp, source); \ + break; + case 0xc5: OP_MOV_ADDR_REG(regs.a); //mov $addr,a + case 0xc9: OP_MOV_ADDR_REG(regs.x); //mov $addr,x + case 0xcc: OP_MOV_ADDR_REG(regs.y); //mov $addr,y + +#define OP_MOV_DPR_REG(target, source) \ + dp = op_readpc(); \ + op_io(); \ + dp += source; \ + op_readdp(dp); \ + op_writedp(dp, target); \ + break; + case 0xd4: OP_MOV_DPR_REG(regs.a, regs.x); //mov $dp+a,x + case 0xd9: OP_MOV_DPR_REG(regs.x, regs.y); //mov $dp+x,y + case 0xdb: OP_MOV_DPR_REG(regs.y, regs.x); //mov $dp+y,x + +#define OP_MOV_ADDRR_A(source) \ + dp = op_readpc() << 0; \ + dp |= op_readpc() << 8; \ + op_io(); \ + dp += source; \ + op_read(dp); \ + op_write(dp, regs.a); \ + break; + case 0xd5: OP_MOV_ADDRR_A(regs.x); //mov $addr+x,a + case 0xd6: OP_MOV_ADDRR_A(regs.y); //mov $addr+y,a + +#define OP_MOV_REG_DP(target) \ + sp = op_readpc(); \ + target = op_readdp(sp); \ + regs.p.n = (target & 0x80); \ + regs.p.z = (target == 0); \ + break; + case 0xe4: OP_MOV_REG_DP(regs.a); //mov a,$dp + case 0xeb: OP_MOV_REG_DP(regs.y); //mov y,$dp + case 0xf8: OP_MOV_REG_DP(regs.x); //mov x,$dp + +#define OP_MOV_REG_ADDR(target) \ + sp = op_readpc() << 0; \ + sp |= op_readpc() << 8; \ + target = op_read(sp); \ + regs.p.n = (target & 0x80); \ + regs.p.z = (target == 0); \ + break; + case 0xe5: OP_MOV_REG_ADDR(regs.a); //mov a,$addr + case 0xe9: OP_MOV_REG_ADDR(regs.x); //mov x,$addr + case 0xec: OP_MOV_REG_ADDR(regs.y); //mov y,$addr + + case 0xe6: //mov a,(x) + op_io(); + regs.a = op_readdp(regs.x); + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; + +#define OP_MOV_REG_DPR(target, source) \ + sp = op_readpc(); \ + op_io(); \ + target = op_readdp(sp + source); \ + regs.p.n = (target & 0x80); \ + regs.p.z = (target == 0); \ + break; + case 0xf4: OP_MOV_REG_DPR(regs.a, regs.x); //mov a,$dp+x + case 0xf9: OP_MOV_REG_DPR(regs.x, regs.y); //mov x,$dp+y + case 0xfb: OP_MOV_REG_DPR(regs.y, regs.x); //mov y,$dp+x + +#define OP_MOV_A_ADDRR(source) \ + sp = op_readpc() << 0; \ + sp |= op_readpc() << 8; \ + op_io(); \ + regs.a = op_read(sp + source); \ + regs.p.n = (regs.a & 0x80); \ + regs.p.z = (regs.a == 0); \ + break; + case 0xf5: OP_MOV_A_ADDRR(regs.x); //mov a,$addr+x + case 0xf6: OP_MOV_A_ADDRR(regs.y); //mov a,$addr+y + case 0x8f: //mov $dp,#$ss rd = op_readpc(); dp = op_readpc(); @@ -135,8 +588,10 @@ void SMP::op_step() { op_writedp(dp, rd); break; - case 0xab: //inc $dp - OP_ADJUST_DP(fn_inc) + case 0xaf: //mov (x)+,a + op_io(); + op_io(); + op_writedp(regs.x++, regs.a); break; case 0xba: //movw ya,$dp @@ -153,8 +608,12 @@ void SMP::op_step() { regs.sp = regs.x; break; - case 0xc4: //mov $dd,a - OP_MOV_DP_REG(regs.a) + case 0xbf: //mov a,(x)+ + op_io(); + regs.a = op_readdp(regs.x++); + op_io(); + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); break; case 0xc6: //mov (x),a @@ -163,16 +622,14 @@ void SMP::op_step() { op_writedp(regs.x, regs.a); break; - case 0xcb: //mov $dp,y - OP_MOV_DP_REG(regs.y) - break; - - case 0xcd: //mov x,#$ss - OP_MOV_REG_CONST(regs.x) - break; - - case 0xd0: //bne $rr - OP_BRANCH(regs.p.z == 0) + case 0xc7: //mov ($dp+x),a + sp = op_readpc(); + op_io(); + sp += regs.x; + dp = op_readdp(sp + 0) << 0; + dp |= op_readdp(sp + 1) << 8; + op_read(dp); + op_write(dp, regs.a); break; case 0xd7: //mov ($dp)+y,a @@ -192,43 +649,245 @@ void SMP::op_step() { op_writedp(dp + 1, regs.y); break; - case 0xdd: //mov a,y - OP_MOV_REG_REG(regs.a, regs.y) + case 0xe7: //mov a,($dp+x) + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp + 0) << 0; + sp |= op_readdp(dp + 1) << 8; + regs.a = op_read(sp); + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); break; - case 0xe4: //mov y,$dp - OP_MOV_REG_DP(regs.a) + case 0xf7: //mov a,($dp)+y + dp = op_readpc(); + op_io(); + sp = op_readdp(dp + 0) << 0; + sp |= op_readdp(dp + 1) << 8; + regs.a = op_read(sp + regs.y); + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); break; - case 0xe8: //mov a,#$ss - OP_MOV_REG_CONST(regs.a) + case 0xfa: //mov $dp,$dp + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + op_writedp(dp, rd); break; - case 0xeb: //mov y,$dp - OP_MOV_REG_DP(regs.y) +// +// read/modify/write +// + +#define OP_ADJUST_DP(func) \ + dp = op_readpc(); \ + rd = op_readdp(dp); \ + rd = func(rd); \ + op_writedp(dp, rd); \ + break; + case 0x0b: OP_ADJUST_DP(fn_asl); //asl $dp + case 0x2b: OP_ADJUST_DP(fn_rol); //rol $dp + case 0x4b: OP_ADJUST_DP(fn_lsr); //lsr $dp + case 0x6b: OP_ADJUST_DP(fn_ror); //ror $dp + case 0x8b: OP_ADJUST_DP(fn_dec); //dec $dp + case 0xab: OP_ADJUST_DP(fn_inc); //inc $dp + +#define OP_ADJUST_ADDR(func) \ + dp = op_readpc() << 0; \ + dp |= op_readpc() << 8; \ + rd = op_read(dp); \ + rd = func(rd); \ + op_write(dp, rd); \ + break; + case 0x0c: OP_ADJUST_ADDR(fn_asl); //asl $addr + case 0x2c: OP_ADJUST_ADDR(fn_rol); //rol $addr + case 0x4c: OP_ADJUST_ADDR(fn_lsr); //lsr $addr + case 0x6c: OP_ADJUST_ADDR(fn_ror); //ror $addr + case 0x8c: OP_ADJUST_ADDR(fn_dec); //dec $addr + case 0xac: OP_ADJUST_ADDR(fn_inc); //inc $addr + +#define OP_ADJUSTW_DP(adjust) \ + dp = op_readpc(); \ + rd = op_readdp(dp) << 0; \ + rd += adjust; \ + op_writedp(dp++, rd); \ + rd += op_readdp(dp) << 8; \ + op_writedp(dp, rd >> 8); \ + regs.p.n = (rd & 0x8000); \ + regs.p.z = (rd == 0); \ + break; + case 0x1a: OP_ADJUSTW_DP(-1); //decw $dp + case 0x3a: OP_ADJUSTW_DP(+1); //incw $dp + +#define OP_ADJUST_DPX(func) \ + dp = op_readpc(); \ + op_io(); \ + rd = op_readdp(dp + regs.x); \ + rd = func(rd); \ + op_writedp(dp + regs.x, rd); \ + break; + case 0x1b: OP_ADJUST_DPX(fn_asl); //asl $dp+x + case 0x3b: OP_ADJUST_DPX(fn_rol); //rol $dp+x + case 0x5b: OP_ADJUST_DPX(fn_lsr); //lsr $dp+x + case 0x7b: OP_ADJUST_DPX(fn_ror); //ror $dp+x + case 0x9b: OP_ADJUST_DPX(fn_dec); //dec $dp+x + case 0xbb: OP_ADJUST_DPX(fn_inc); //inc $dp+x + +#define OP_ADJUST_REG(func, target) \ + op_io(); \ + target = func(target); \ + break; + case 0x1c: OP_ADJUST_REG(fn_asl, regs.a); //asl a + case 0x3c: OP_ADJUST_REG(fn_rol, regs.a); //rol a + case 0x5c: OP_ADJUST_REG(fn_lsr, regs.a); //lsr a + case 0x7c: OP_ADJUST_REG(fn_ror, regs.a); //ror a + case 0x9c: OP_ADJUST_REG(fn_dec, regs.a); //dec a + case 0xbc: OP_ADJUST_REG(fn_inc, regs.a); //inc a + + case 0x1d: OP_ADJUST_REG(fn_dec, regs.x); //dec x + case 0x3d: OP_ADJUST_REG(fn_inc, regs.x); //inc x + + case 0xdc: OP_ADJUST_REG(fn_dec, regs.y); //dec y + case 0xfc: OP_ADJUST_REG(fn_inc, regs.y); //inc y + +// +// bit manipulation +// + +#define OP_OR1_BIT(op) \ + dp = op_readpc() << 0; \ + dp |= op_readpc() << 8; \ + bit = dp >> 13; \ + dp &= 0x1fff; \ + rd = op_read(dp); \ + op_io(); \ + regs.p.c = regs.p.c = ((bool)(rd & (1 << bit)) ^ op); \ + break; + case 0x0a: OP_OR1_BIT(0); //or1 c,$addr:bit + case 0x2a: OP_OR1_BIT(1); //or1 c,!$addr:bit + +#define OP_AND1_BIT(op) \ + dp = op_readpc() << 0; \ + dp |= op_readpc() << 8; \ + bit = dp >> 13; \ + dp &= 0x1fff; \ + rd = op_read(dp); \ + regs.p.c = regs.p.c & ((bool)(rd & (1 << bit)) ^ op); \ + break; + case 0x4a: OP_AND1_BIT(0); //and1 c,$addr:bit + case 0x6a: OP_AND1_BIT(1); //and1 c,!$addr:bit + + case 0x8a: //eor1 c,$addr:bit + dp = op_readpc() << 0; + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_read(dp); + op_io(); + regs.p.c = regs.p.c ^ (bool)(rd & (1 << bit)); break; - case 0xfc: //inc y - OP_ADJUST_REG(fn_inc, regs.y) + case 0xaa: //mov1 c,$addr:bit + sp = op_readpc() << 0; + sp |= op_readpc() << 8; + bit = sp >> 13; + sp &= 0x1fff; + rd = op_read(sp); + regs.p.c = (rd & (1 << bit)); break; - default: - static bool stop = false; - regs.pc--; - if(stop == false) { - stop = true; - print("Unknown opcode @ ", hex<4>(regs.pc), ":", hex<2>(opcode), "\n"); - char buffer[4096]; - disassemble_opcode(buffer, regs.pc); - print(buffer, "\n"); + case 0xca: //mov1 $addr:bit,c + dp = op_readpc() << 0; + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_read(dp); + regs.p.c ? rd |= (1 << bit) : rd &=~ (1 << bit); + op_io(); + op_write(dp, rd); + break; + + case 0xea: //not1 c,$addr:bit + dp = op_readpc() << 0; + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_read(dp); + rd ^= 1 << bit; + op_write(dp, rd); + break; + +// +// miscellaneous +// + +#define OP_TADJUST_ADDR(mathop) \ + dp = op_readpc() << 0; \ + dp |= op_readpc() << 8; \ + rd = op_read(dp); \ + regs.p.n = ((regs.a - rd) & 0x80); \ + regs.p.z = ((regs.a - rd) == 0); \ + op_read(dp); \ + op_write(dp, rd mathop regs.a); \ + break; + case 0x0e: OP_TADJUST_ADDR(| ); //tset $addr,a + case 0x4e: OP_TADJUST_ADDR(&~); //tclr $addr,a + + case 0x5a: //cmpw ya,$dp + dp = op_readpc(); + rd = op_readdp(dp + 0) << 0; + rd |= op_readdp(dp + 1) << 8; + fn_cmpw(regs.ya, rd); + break; + + case 0x9f: //xcn a + op_io(); op_io(); op_io(); op_io(); + regs.a = (regs.a >> 4) | (regs.a << 4); + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; + + case 0xbe: //das + op_io(); + op_io(); + if(!regs.p.c || (regs.a) > 0x99) { + regs.a -= 0x60; + regs.p.c = 0; } + if(!regs.p.h || (regs.a & 15) > 0x09) { + regs.a -= 0x06; + } + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); break; + + case 0xdf: //daa + op_io(); + op_io(); + if(regs.p.c || (regs.a) > 0x99) { + regs.a += 0x60; + regs.p.c = 1; + } + if(regs.p.h || (regs.a & 15) > 0x09) { + regs.a += 0x06; + } + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; + } - step(cycle_table[opcode]); + timer0.tick(cycle_count_table[opcode]); + timer1.tick(cycle_count_table[opcode]); + timer2.tick(cycle_count_table[opcode]); + + clock += cycle_table_cpu[opcode]; + dsp.clock -= cycle_table_dsp[opcode]; + synchronize_dsp(); } -const unsigned SMP::cycle_table[256] = { +const unsigned SMP::cycle_count_table[256] = { #define c 12 //0 1 2 3 4 5 6 7 8 9 A B C D E F 2,8,4,7, 3,4,3,6, 2,6,5,4, 5,4,6,8, //0 diff --git a/bsnes/snes/alt/smp/core.hpp b/bsnes/snes/alt/smp/core.hpp index 62ce7a2bb..1e28a309d 100755 --- a/bsnes/snes/alt/smp/core.hpp +++ b/bsnes/snes/alt/smp/core.hpp @@ -2,7 +2,9 @@ alwaysinline void op_io(); debugvirtual alwaysinline uint8 op_read(uint16 addr); debugvirtual alwaysinline void op_write(uint16 addr, uint8 data); debugvirtual alwaysinline void op_step(); -static const unsigned cycle_table[256]; +static const unsigned cycle_count_table[256]; +uint64 cycle_table_cpu[256]; +unsigned cycle_table_dsp[256]; uint8 fn_adc (uint8 x, uint8 y); uint16 fn_addw(uint16 x, uint16 y); diff --git a/bsnes/snes/alt/smp/debugger/debugger.hpp b/bsnes/snes/alt/smp/debugger/debugger.hpp index d5d28e538..811aa4c6f 100755 --- a/bsnes/snes/alt/smp/debugger/debugger.hpp +++ b/bsnes/snes/alt/smp/debugger/debugger.hpp @@ -19,4 +19,9 @@ public: SMPDebugger(); ~SMPDebugger(); + + //disassembler + void disassemble_opcode(char *output, uint16 addr); + inline uint8 disassemble_read(uint16 addr); + inline uint16 relb(int8 offset, int op_len); }; diff --git a/bsnes/snes/alt/smp/disassembler.cpp b/bsnes/snes/alt/smp/debugger/disassembler.cpp similarity index 100% rename from bsnes/snes/alt/smp/disassembler.cpp rename to bsnes/snes/alt/smp/debugger/disassembler.cpp diff --git a/bsnes/snes/alt/smp/smp.cpp b/bsnes/snes/alt/smp/smp.cpp index e285e229f..903eb1afd 100755 --- a/bsnes/snes/alt/smp/smp.cpp +++ b/bsnes/snes/alt/smp/smp.cpp @@ -5,6 +5,7 @@ namespace SNES { #if defined(DEBUGGER) #include "debugger/debugger.cpp" + #include "debugger/disassembler.cpp" SMPDebugger smp; #else SMP smp; @@ -12,22 +13,15 @@ namespace SNES { #include "algorithms.cpp" #include "core.cpp" -#include "disassembler.cpp" #include "iplrom.cpp" #include "memory.cpp" #include "timing.cpp" -void SMP::step(unsigned clocks) { - clock += clocks * (uint64)cpu.frequency; - dsp.clock -= clocks; - synchronize_dsp(); -} - void SMP::synchronize_cpu() { if(CPU::Threaded == true) { if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread); } else { - //while(clock >= 0) cpu.enter(); + while(clock >= 0) cpu.enter(); } } @@ -40,17 +34,22 @@ void SMP::synchronize_dsp() { } void SMP::enter() { - op_step(); + while(clock < 0) op_step(); } void SMP::power() { - Processor::frequency = system.apu_frequency() / 24; + Processor::frequency = system.apu_frequency(); Processor::clock = 0; timer0.target = 0; timer1.target = 0; timer2.target = 0; + for(unsigned n = 0; n < 256; n++) { + cycle_table_dsp[n] = (cycle_count_table[n] * 24); + cycle_table_cpu[n] = (cycle_count_table[n] * 24) * cpu.frequency; + } + reset(); } @@ -58,7 +57,7 @@ void SMP::reset() { for(unsigned n = 0x0000; n <= 0xffff; n++) apuram[n] = 0x00; regs.pc = 0xffc0; - regs.sp = 0x00ef; + regs.sp = 0xef; regs.a = 0x00; regs.x = 0x00; regs.y = 0x00; @@ -69,14 +68,6 @@ void SMP::reset() { status.dsp_counter = 0; status.timer_step = 3; - //$00f0 - status.clock_speed = 0; - status.timer_speed = 0; - status.timers_enable = true; - status.ram_disable = false; - status.ram_writable = true; - status.timers_disable = false; - //$00f1 status.iplrom_enable = true; @@ -89,9 +80,40 @@ void SMP::reset() { } void SMP::serialize(serializer &s) { + Processor::serialize(s); + + s.array(apuram, 64 * 1024); + + s.integer(regs.pc); + s.integer(regs.sp); + s.integer(regs.a); + s.integer(regs.x); + s.integer(regs.y); + + s.integer(regs.p.n); + s.integer(regs.p.v); + s.integer(regs.p.p); + s.integer(regs.p.b); + s.integer(regs.p.h); + s.integer(regs.p.i); + s.integer(regs.p.z); + s.integer(regs.p.c); + + s.integer(status.clock_counter); + s.integer(status.dsp_counter); + s.integer(status.timer_step); + + s.integer(status.iplrom_enable); + + s.integer(status.dsp_addr); + + s.integer(status.ram00f8); + s.integer(status.ram00f9); } SMP::SMP() { + apuram = new uint8[64 * 1024]; + stackram = apuram + 0x0100; } SMP::~SMP() { diff --git a/bsnes/snes/alt/smp/smp.hpp b/bsnes/snes/alt/smp/smp.hpp index 935441782..4531c1781 100755 --- a/bsnes/snes/alt/smp/smp.hpp +++ b/bsnes/snes/alt/smp/smp.hpp @@ -1,16 +1,19 @@ class SMP : public Processor { public: static const uint8 iplrom[64]; - uint8 apuram[64 * 1024]; + uint8 *apuram; + uint8 *stackram; enum : bool { Threaded = false }; - alwaysinline void step(unsigned clocks); alwaysinline void synchronize_cpu(); alwaysinline void synchronize_dsp(); unsigned port_read(unsigned port); void port_write(unsigned port, unsigned data); + unsigned mmio_read(unsigned addr); + void mmio_write(unsigned addr, unsigned data); + void enter(); void power(); void reset(); @@ -41,7 +44,7 @@ public: struct Regs { uint16 pc; - uint16 sp; + uint8 sp; union { uint16 ya; struct { uint8 order_lsb2(a, y); }; @@ -56,14 +59,6 @@ public: unsigned dsp_counter; unsigned timer_step; - //$00f0 - unsigned clock_speed; - unsigned timer_speed; - bool timers_enable; - bool ram_disable; - bool ram_writable; - bool timers_disable; - //$00f1 bool iplrom_enable; @@ -85,21 +80,13 @@ public: bool enable; unsigned target; - void tick(); + void tick(unsigned clocks); void synchronize(); }; - Timer<192> timer0; - Timer<192> timer1; - Timer< 24> timer2; - - unsigned mmio_read(unsigned addr); - void mmio_write(unsigned addr, unsigned data); - - //disassembler - void disassemble_opcode(char *output, uint16 addr); - inline uint8 disassemble_read(uint16 addr); - inline uint16 relb(int8 offset, int op_len); + Timer<64> timer0; + Timer<64> timer1; + Timer< 8> timer2; }; #if defined(DEBUGGER) diff --git a/bsnes/snes/alt/smp/timing.cpp b/bsnes/snes/alt/smp/timing.cpp index ff092f3c5..4d64d86b2 100755 --- a/bsnes/snes/alt/smp/timing.cpp +++ b/bsnes/snes/alt/smp/timing.cpp @@ -1,7 +1,7 @@ template -void SMP::Timer::tick() { +void SMP::Timer::tick(unsigned clocks) { //stage 0 increment - stage0_ticks += smp.status.timer_step; + stage0_ticks += clocks; if(stage0_ticks < timer_frequency) return; stage0_ticks -= timer_frequency; diff --git a/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp index 19d35a3ef..81b4893b9 100755 --- a/bsnes/snes/snes.hpp +++ b/bsnes/snes/snes.hpp @@ -1,7 +1,7 @@ namespace SNES { namespace Info { static const char Name[] = "bsnes"; - static const char Version[] = "078.01"; + static const char Version[] = "078.02"; static const unsigned SerializerVersion = 19; } }