diff --git a/bsnes/Makefile b/bsnes/Makefile index 4af870869..d415b9d8d 100755 --- a/bsnes/Makefile +++ b/bsnes/Makefile @@ -5,7 +5,7 @@ profile := accuracy ui := ui # debugger -options := +options := debugger # compiler c := $(compiler) -std=gnu99 diff --git a/bsnes/snes/Makefile b/bsnes/snes/Makefile index 94cba7d5f..d9c24d55b 100755 --- a/bsnes/snes/Makefile +++ b/bsnes/snes/Makefile @@ -23,7 +23,7 @@ else ifeq ($(profile),compatibility) else ifeq ($(profile),performance) flags += -DPROFILE_PERFORMANCE snescpu := $(snes)/alt/cpu - snessmp := $(snes)/smp + snessmp := $(snes)/alt/smp snesdsp := $(snes)/alt/dsp snesppu := $(snes)/alt/ppu-performance endif diff --git a/bsnes/snes/alt/smp/algorithms.cpp b/bsnes/snes/alt/smp/algorithms.cpp new file mode 100755 index 000000000..b06a6f6d8 --- /dev/null +++ b/bsnes/snes/alt/smp/algorithms.cpp @@ -0,0 +1,122 @@ +uint8 SMP::fn_adc(uint8 x, uint8 y) { + int r = x + y + regs.p.c; + regs.p.n = r & 0x80; + regs.p.v = ~(x ^ y) & (x ^ r) & 0x80; + regs.p.h = (x ^ y ^ r) & 0x10; + regs.p.z = (uint8)r == 0; + regs.p.c = r > 0xff; + return r; +} + +uint16 SMP::fn_addw(uint16 x, uint16 y) { + uint16 r; + regs.p.c = 0; + r = fn_adc(x, y); + r |= fn_adc(x >> 8, y >> 8) << 8; + regs.p.z = r == 0; + return r; +} + +uint8 SMP::fn_and(uint8 x, uint8 y) { + x &= y; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::fn_cmp(uint8 x, uint8 y) { + int r = x - y; + regs.p.n = r & 0x80; + regs.p.z = (uint8)r == 0; + regs.p.c = r >= 0; + return x; +} + +uint16 SMP::fn_cmpw(uint16 x, uint16 y) { + int r = x - y; + regs.p.n = r & 0x8000; + regs.p.z = (uint16)r == 0; + regs.p.c = r >= 0; + return x; +} + +uint8 SMP::fn_eor(uint8 x, uint8 y) { + x ^= y; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::fn_or(uint8 x, uint8 y) { + x |= y; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::fn_sbc(uint8 x, uint8 y) { + int r = x - y - !regs.p.c; + regs.p.n = r & 0x80; + regs.p.v = (x ^ y) & (x ^ r) & 0x80; + regs.p.h = !((x ^ y ^ r) & 0x10); + regs.p.z = (uint8)r == 0; + regs.p.c = r >= 0; + return r; +} + +uint16 SMP::fn_subw(uint16 x, uint16 y) { + uint16 r; + regs.p.c = 1; + r = fn_sbc(x, y); + r |= fn_sbc(x >> 8, y >> 8) << 8; + regs.p.z = r == 0; + return r; +} + +uint8 SMP::fn_inc(uint8 x) { + x++; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::fn_dec(uint8 x) { + x--; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::fn_asl(uint8 x) { + regs.p.c = x & 0x80; + x <<= 1; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::fn_lsr(uint8 x) { + regs.p.c = x & 0x01; + x >>= 1; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::fn_rol(uint8 x) { + unsigned carry = (unsigned)regs.p.c; + regs.p.c = x & 0x80; + x = (x << 1) | carry; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::fn_ror(uint8 x) { + unsigned carry = (unsigned)regs.p.c << 7; + regs.p.c = x & 0x01; + x = carry | (x >> 1); + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} diff --git a/bsnes/snes/alt/smp/core.cpp b/bsnes/snes/alt/smp/core.cpp new file mode 100755 index 000000000..dba9ccd22 --- /dev/null +++ b/bsnes/snes/alt/smp/core.cpp @@ -0,0 +1,255 @@ +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); + +void SMP::op_step() { + unsigned opcode = op_readpc(); + op_io(); + + static unsigned rd, wr, dp, sp; + + switch(opcode) { + + case 0x00: //nop + break; + + case 0x10: //bpl $rr + OP_BRANCH(regs.p.n == 0) + break; + + case 0x1d: //dec x + OP_ADJUST_REG(fn_dec, regs.x) + break; + + case 0x1f: //jmp ($aaaa,x) + dp = op_readpc() << 0; + dp |= op_readpc() << 8; + op_io(); + dp += regs.x; + rd = op_read(dp + 0) << 0; + rd |= op_read(dp + 1) << 8; + regs.pc = rd; + break; + + case 0x2f: //bra $rr + rd = op_readpc(); + op_io(); + op_io(); + regs.pc += (int8)rd; + break; + + case 0x5d: //mov x,a + OP_MOV_REG_REG(regs.x, regs.a) + break; + + case 0x78: //cmp $dp,#$ss + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + fn_cmp(wr, rd); + op_io(); + break; + + case 0x7d: //mov a,x + OP_MOV_REG_REG(regs.a, regs.x) + break; + + case 0x7e: //cmp y,$dp + OP_READ_REG_DP(fn_cmp, regs.y) + break; + + case 0x8f: //mov $dp,#$ss + rd = op_readpc(); + dp = op_readpc(); + op_readdp(dp); + op_writedp(dp, rd); + break; + + case 0xab: //inc $dp + OP_ADJUST_DP(fn_inc) + break; + + case 0xba: //movw ya,$dp + sp = op_readpc(); + regs.a = op_readdp(sp + 0); + op_io(); + regs.y = op_readdp(sp + 1); + regs.p.n = (regs.ya & 0x8000); + regs.p.z = (regs.ya == 0); + break; + + case 0xbd: //mov sp,x + op_io(); + regs.sp = regs.x; + break; + + case 0xc4: //mov $dd,a + OP_MOV_DP_REG(regs.a) + break; + + case 0xc6: //mov (x),a + op_io(); + op_readdp(regs.x); + 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) + break; + + case 0xd7: //mov ($dp)+y,a + sp = op_readpc(); + dp = op_readdp(sp + 0) << 0; + dp |= op_readdp(sp + 1) << 8; + op_io(); + dp += regs.y; + op_read(dp); + op_write(dp, regs.a); + break; + + case 0xda: //movw $dp,ya + dp = op_readpc(); + op_readdp(dp); + op_writedp(dp + 0, regs.a); + op_writedp(dp + 1, regs.y); + break; + + case 0xdd: //mov a,y + OP_MOV_REG_REG(regs.a, regs.y) + break; + + case 0xe4: //mov y,$dp + OP_MOV_REG_DP(regs.a) + break; + + case 0xe8: //mov a,#$ss + OP_MOV_REG_CONST(regs.a) + break; + + case 0xeb: //mov y,$dp + OP_MOV_REG_DP(regs.y) + break; + + case 0xfc: //inc y + OP_ADJUST_REG(fn_inc, regs.y) + 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"); + } + break; + } + + step(cycle_table[opcode]); +} + +const unsigned SMP::cycle_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 + 4,8,4,7, 4,5,5,6, 5,5,6,5, 2,2,4,6, //1 + 2,8,4,7, 3,4,3,6, 2,6,5,4, 5,4,7,4, //2 + 4,8,4,7, 4,5,5,6, 5,5,6,5, 2,2,3,8, //3 + + 2,8,4,7, 3,4,3,6, 2,6,4,4, 5,4,6,6, //4 + 4,8,4,7, 4,5,5,6, 5,5,4,5, 2,2,4,3, //5 + 2,8,4,7, 3,4,3,6, 2,6,4,4, 5,4,7,5, //6 + 4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,3,6, //7 + + 2,8,4,7, 3,4,3,6, 2,6,5,4, 5,2,4,5, //8 + 4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,c,5, //9 + 3,8,4,7, 3,4,3,6, 2,6,4,4, 5,2,4,4, //A + 4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,3,4, //B + + 3,8,4,7, 4,5,4,7, 2,5,6,4, 5,2,4,9, //C + 4,8,4,7, 5,6,6,7, 4,5,5,5, 2,2,8,3, //D + 2,8,4,7, 3,4,3,6, 2,4,5,3, 4,3,4,1, //E + 4,8,4,7, 4,5,5,6, 3,4,5,4, 2,2,6,1, //F + + #undef c +}; diff --git a/bsnes/snes/alt/smp/core.hpp b/bsnes/snes/alt/smp/core.hpp new file mode 100755 index 000000000..62ce7a2bb --- /dev/null +++ b/bsnes/snes/alt/smp/core.hpp @@ -0,0 +1,21 @@ +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]; + +uint8 fn_adc (uint8 x, uint8 y); +uint16 fn_addw(uint16 x, uint16 y); +uint8 fn_and (uint8 x, uint8 y); +uint8 fn_cmp (uint8 x, uint8 y); +uint16 fn_cmpw(uint16 x, uint16 y); +uint8 fn_eor (uint8 x, uint8 y); +uint8 fn_inc (uint8 x); +uint8 fn_dec (uint8 x); +uint8 fn_or (uint8 x, uint8 y); +uint8 fn_sbc (uint8 x, uint8 y); +uint16 fn_subw(uint16 x, uint16 y); +uint8 fn_asl (uint8 x); +uint8 fn_lsr (uint8 x); +uint8 fn_rol (uint8 x); +uint8 fn_ror (uint8 x); diff --git a/bsnes/snes/alt/smp/debugger/debugger.cpp b/bsnes/snes/alt/smp/debugger/debugger.cpp new file mode 100755 index 000000000..9546c1182 --- /dev/null +++ b/bsnes/snes/alt/smp/debugger/debugger.cpp @@ -0,0 +1,75 @@ +#ifdef SMP_CPP + +void SMPDebugger::op_step() { + bool break_event = false; + + usage[regs.pc] |= UsageExec; + opcode_pc = regs.pc; + + opcode_edge = true; + debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00); + if(step_event && step_event() == true) { + debugger.break_event = Debugger::BreakEvent::SMPStep; + scheduler.exit(Scheduler::ExitReason::DebuggerEvent); + } + opcode_edge = false; + + SMP::op_step(); + synchronize_cpu(); +} + +uint8 SMPDebugger::op_read(uint16 addr) { + uint8 data = SMP::op_read(addr); + usage[addr] |= UsageRead; + debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Read, addr, data); + return data; +} + +void SMPDebugger::op_write(uint16 addr, uint8 data) { + SMP::op_write(addr, data); + usage[addr] |= UsageWrite; + usage[addr] &= ~UsageExec; + debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Write, addr, data); +} + +SMPDebugger::SMPDebugger() { + usage = new uint8[1 << 16](); + opcode_pc = 0xffc0; + opcode_edge = false; +} + +SMPDebugger::~SMPDebugger() { + delete[] usage; +} + +bool SMPDebugger::property(unsigned id, string &name, string &value) { + unsigned n = 0; + + #define item(name_, value_) \ + if(id == n++) { \ + name = name_; \ + value = value_; \ + return true; \ + } + + //$00f0 + item("$00f0", ""); + item("Clock Speed", (unsigned)status.clock_speed); + item("Timers Enable", status.timers_enable); + item("RAM Disable", status.ram_disable); + item("RAM Writable", status.ram_writable); + item("Timers Disable", status.timers_disable); + + //$00f1 + item("$00f1", ""); + item("IPLROM Enable", status.iplrom_enable); + + //$00f2 + item("$00f2", ""); + item("DSP Address", string("0x", hex<2>(status.dsp_addr))); + + #undef item + return false; +} + +#endif diff --git a/bsnes/snes/alt/smp/debugger/debugger.hpp b/bsnes/snes/alt/smp/debugger/debugger.hpp new file mode 100755 index 000000000..d5d28e538 --- /dev/null +++ b/bsnes/snes/alt/smp/debugger/debugger.hpp @@ -0,0 +1,22 @@ +class SMPDebugger : public SMP, public ChipDebugger { +public: + bool property(unsigned id, string &name, string &value); + + function step_event; + + enum Usage { + UsageRead = 0x80, + UsageWrite = 0x40, + UsageExec = 0x20, + }; + uint8 *usage; + uint16 opcode_pc; + bool opcode_edge; + + void op_step(); + uint8 op_read(uint16 addr); + void op_write(uint16 addr, uint8 data); + + SMPDebugger(); + ~SMPDebugger(); +}; diff --git a/bsnes/snes/alt/smp/disassembler.cpp b/bsnes/snes/alt/smp/disassembler.cpp new file mode 100755 index 000000000..fb76ae922 --- /dev/null +++ b/bsnes/snes/alt/smp/disassembler.cpp @@ -0,0 +1,304 @@ +uint8 SMP::disassemble_read(uint16 addr) { + if(addr >= 0xffc0) return smp.iplrom[addr & 0x3f]; + return smp.apuram[addr]; +} + +uint16 SMP::relb(int8 offset, int op_len) { + uint16 pc = regs.pc + op_len; + return pc + offset; +} + +void SMP::disassemble_opcode(char *output, uint16 addr) { + char *s, t[512]; + uint8 op, op0, op1; + uint16 opw, opdp0, opdp1; + s = output; + + sprintf(s, "..%.4x ", addr); + + op = disassemble_read(addr + 0); + op0 = disassemble_read(addr + 1); + op1 = disassemble_read(addr + 2); + opw = (op0) | (op1 << 8); + opdp0 = ((unsigned)regs.p.p << 8) + op0; + opdp1 = ((unsigned)regs.p.p << 8) + op1; + + strcpy(t, " "); + + switch(op) { + case 0x00: sprintf(t, "nop"); break; + case 0x01: sprintf(t, "tcall 0"); break; + case 0x02: sprintf(t, "set0 $%.3x", opdp0); break; + case 0x03: sprintf(t, "bbs0 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x04: sprintf(t, "or a,$%.3x", opdp0); break; + case 0x05: sprintf(t, "or a,$%.4x", opw); break; + case 0x06: sprintf(t, "or a,(x)"); break; + case 0x07: sprintf(t, "or a,($%.3x+x)", opdp0); break; + case 0x08: sprintf(t, "or a,#$%.2x", op0); break; + case 0x09: sprintf(t, "or $%.3x,$%.3x", opdp1, opdp0); break; + case 0x0a: sprintf(t, "or1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x0b: sprintf(t, "asl $%.3x", opdp0); break; + case 0x0c: sprintf(t, "asl $%.4x", opw); break; + case 0x0d: sprintf(t, "push p"); break; + case 0x0e: sprintf(t, "tset $%.4x,a", opw); break; + case 0x0f: sprintf(t, "brk"); break; + case 0x10: sprintf(t, "bpl $%.4x", relb(op0, 2)); break; + case 0x11: sprintf(t, "tcall 1"); break; + case 0x12: sprintf(t, "clr0 $%.3x", opdp0); break; + case 0x13: sprintf(t, "bbc0 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x14: sprintf(t, "or a,$%.3x+x", opdp0); break; + case 0x15: sprintf(t, "or a,$%.4x+x", opw); break; + case 0x16: sprintf(t, "or a,$%.4x+y", opw); break; + case 0x17: sprintf(t, "or a,($%.3x)+y", opdp0); break; + case 0x18: sprintf(t, "or $%.3x,#$%.2x", opdp1, op0); break; + case 0x19: sprintf(t, "or (x),(y)"); break; + case 0x1a: sprintf(t, "decw $%.3x", opdp0); break; + case 0x1b: sprintf(t, "asl $%.3x+x", opdp0); break; + case 0x1c: sprintf(t, "asl a"); break; + case 0x1d: sprintf(t, "dec x"); break; + case 0x1e: sprintf(t, "cmp x,$%.4x", opw); break; + case 0x1f: sprintf(t, "jmp ($%.4x+x)", opw); break; + case 0x20: sprintf(t, "clrp"); break; + case 0x21: sprintf(t, "tcall 2"); break; + case 0x22: sprintf(t, "set1 $%.3x", opdp0); break; + case 0x23: sprintf(t, "bbs1 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x24: sprintf(t, "and a,$%.3x", opdp0); break; + case 0x25: sprintf(t, "and a,$%.4x", opw); break; + case 0x26: sprintf(t, "and a,(x)"); break; + case 0x27: sprintf(t, "and a,($%.3x+x)", opdp0); break; + case 0x28: sprintf(t, "and a,#$%.2x", op0); break; + case 0x29: sprintf(t, "and $%.3x,$%.3x", opdp1, opdp0); break; + case 0x2a: sprintf(t, "or1 c,!$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x2b: sprintf(t, "rol $%.3x", opdp0); break; + case 0x2c: sprintf(t, "rol $%.4x", opw); break; + case 0x2d: sprintf(t, "push a"); break; + case 0x2e: sprintf(t, "cbne $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x2f: sprintf(t, "bra $%.4x", relb(op0, 2)); break; + case 0x30: sprintf(t, "bmi $%.4x", relb(op0, 2)); break; + case 0x31: sprintf(t, "tcall 3"); break; + case 0x32: sprintf(t, "clr1 $%.3x", opdp0); break; + case 0x33: sprintf(t, "bbc1 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x34: sprintf(t, "and a,$%.3x+x", opdp0); break; + case 0x35: sprintf(t, "and a,$%.4x+x", opw); break; + case 0x36: sprintf(t, "and a,$%.4x+y", opw); break; + case 0x37: sprintf(t, "and a,($%.3x)+y", opdp0); break; + case 0x38: sprintf(t, "and $%.3x,#$%.2x", opdp1, op0); break; + case 0x39: sprintf(t, "and (x),(y)"); break; + case 0x3a: sprintf(t, "incw $%.3x", opdp0); break; + case 0x3b: sprintf(t, "rol $%.3x+x", opdp0); break; + case 0x3c: sprintf(t, "rol a"); break; + case 0x3d: sprintf(t, "inc x"); break; + case 0x3e: sprintf(t, "cmp x,$%.3x", opdp0); break; + case 0x3f: sprintf(t, "call $%.4x", opw); break; + case 0x40: sprintf(t, "setp"); break; + case 0x41: sprintf(t, "tcall 4"); break; + case 0x42: sprintf(t, "set2 $%.3x", opdp0); break; + case 0x43: sprintf(t, "bbs2 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x44: sprintf(t, "eor a,$%.3x", opdp0); break; + case 0x45: sprintf(t, "eor a,$%.4x", opw); break; + case 0x46: sprintf(t, "eor a,(x)"); break; + case 0x47: sprintf(t, "eor a,($%.3x+x)", opdp0); break; + case 0x48: sprintf(t, "eor a,#$%.2x", op0); break; + case 0x49: sprintf(t, "eor $%.3x,$%.3x", opdp1, opdp0); break; + case 0x4a: sprintf(t, "and1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x4b: sprintf(t, "lsr $%.3x", opdp0); break; + case 0x4c: sprintf(t, "lsr $%.4x", opw); break; + case 0x4d: sprintf(t, "push x"); break; + case 0x4e: sprintf(t, "tclr $%.4x,a", opw); break; + case 0x4f: sprintf(t, "pcall $ff%.2x", op0); break; + case 0x50: sprintf(t, "bvc $%.4x", relb(op0, 2)); break; + case 0x51: sprintf(t, "tcall 5"); break; + case 0x52: sprintf(t, "clr2 $%.3x", opdp0); break; + case 0x53: sprintf(t, "bbc2 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x54: sprintf(t, "eor a,$%.3x+x", opdp0); break; + case 0x55: sprintf(t, "eor a,$%.4x+x", opw); break; + case 0x56: sprintf(t, "eor a,$%.4x+y", opw); break; + case 0x57: sprintf(t, "eor a,($%.3x)+y", opdp0); break; + case 0x58: sprintf(t, "eor $%.3x,#$%.2x", opdp1, op0); break; + case 0x59: sprintf(t, "eor (x),(y)"); break; + case 0x5a: sprintf(t, "cmpw ya,$%.3x", opdp0); break; + case 0x5b: sprintf(t, "lsr $%.3x+x", opdp0); break; + case 0x5c: sprintf(t, "lsr a"); break; + case 0x5d: sprintf(t, "mov x,a"); break; + case 0x5e: sprintf(t, "cmp y,$%.4x", opw); break; + case 0x5f: sprintf(t, "jmp $%.4x", opw); break; + case 0x60: sprintf(t, "clrc"); break; + case 0x61: sprintf(t, "tcall 6"); break; + case 0x62: sprintf(t, "set3 $%.3x", opdp0); break; + case 0x63: sprintf(t, "bbs3 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x64: sprintf(t, "cmp a,$%.3x", opdp0); break; + case 0x65: sprintf(t, "cmp a,$%.4x", opw); break; + case 0x66: sprintf(t, "cmp a,(x)"); break; + case 0x67: sprintf(t, "cmp a,($%.3x+x)", opdp0); break; + case 0x68: sprintf(t, "cmp a,#$%.2x", op0); break; + case 0x69: sprintf(t, "cmp $%.3x,$%.3x", opdp1, opdp0); break; + case 0x6a: sprintf(t, "and1 c,!$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x6b: sprintf(t, "ror $%.3x", opdp0); break; + case 0x6c: sprintf(t, "ror $%.4x", opw); break; + case 0x6d: sprintf(t, "push y"); break; + case 0x6e: sprintf(t, "dbnz $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x6f: sprintf(t, "ret"); break; + case 0x70: sprintf(t, "bvs $%.4x", relb(op0, 2)); break; + case 0x71: sprintf(t, "tcall 7"); break; + case 0x72: sprintf(t, "clr3 $%.3x", opdp0); break; + case 0x73: sprintf(t, "bbc3 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x74: sprintf(t, "cmp a,$%.3x+x", opdp0); break; + case 0x75: sprintf(t, "cmp a,$%.4x+x", opw); break; + case 0x76: sprintf(t, "cmp a,$%.4x+y", opw); break; + case 0x77: sprintf(t, "cmp a,($%.3x)+y", opdp0); break; + case 0x78: sprintf(t, "cmp $%.3x,#$%.2x", opdp1, op0); break; + case 0x79: sprintf(t, "cmp (x),(y)"); break; + case 0x7a: sprintf(t, "addw ya,$%.3x", opdp0); break; + case 0x7b: sprintf(t, "ror $%.3x+x", opdp0); break; + case 0x7c: sprintf(t, "ror a"); break; + case 0x7d: sprintf(t, "mov a,x"); break; + case 0x7e: sprintf(t, "cmp y,$%.3x", opdp0); break; + case 0x7f: sprintf(t, "reti"); break; + case 0x80: sprintf(t, "setc"); break; + case 0x81: sprintf(t, "tcall 8"); break; + case 0x82: sprintf(t, "set4 $%.3x", opdp0); break; + case 0x83: sprintf(t, "bbs4 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x84: sprintf(t, "adc a,$%.3x", opdp0); break; + case 0x85: sprintf(t, "adc a,$%.4x", opw); break; + case 0x86: sprintf(t, "adc a,(x)"); break; + case 0x87: sprintf(t, "adc a,($%.3x+x)", opdp0); break; + case 0x88: sprintf(t, "adc a,#$%.2x", op0); break; + case 0x89: sprintf(t, "adc $%.3x,$%.3x", opdp1, opdp0); break; + case 0x8a: sprintf(t, "eor1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x8b: sprintf(t, "dec $%.3x", opdp0); break; + case 0x8c: sprintf(t, "dec $%.4x", opw); break; + case 0x8d: sprintf(t, "mov y,#$%.2x", op0); break; + case 0x8e: sprintf(t, "pop p"); break; + case 0x8f: sprintf(t, "mov $%.3x,#$%.2x", opdp1, op0); break; + case 0x90: sprintf(t, "bcc $%.4x", relb(op0, 2)); break; + case 0x91: sprintf(t, "tcall 9"); break; + case 0x92: sprintf(t, "clr4 $%.3x", opdp0); break; + case 0x93: sprintf(t, "bbc4 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x94: sprintf(t, "adc a,$%.3x+x", opdp0); break; + case 0x95: sprintf(t, "adc a,$%.4x+x", opw); break; + case 0x96: sprintf(t, "adc a,$%.4x+y", opw); break; + case 0x97: sprintf(t, "adc a,($%.3x)+y", opdp0); break; + case 0x98: sprintf(t, "adc $%.3x,#$%.2x", opdp1, op0); break; + case 0x99: sprintf(t, "adc (x),(y)"); break; + case 0x9a: sprintf(t, "subw ya,$%.3x", opdp0); break; + case 0x9b: sprintf(t, "dec $%.3x+x", opdp0); break; + case 0x9c: sprintf(t, "dec a"); break; + case 0x9d: sprintf(t, "mov x,sp"); break; + case 0x9e: sprintf(t, "div ya,x"); break; + case 0x9f: sprintf(t, "xcn a"); break; + case 0xa0: sprintf(t, "ei"); break; + case 0xa1: sprintf(t, "tcall 10"); break; + case 0xa2: sprintf(t, "set5 $%.3x", opdp0); break; + case 0xa3: sprintf(t, "bbs5 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xa4: sprintf(t, "sbc a,$%.3x", opdp0); break; + case 0xa5: sprintf(t, "sbc a,$%.4x", opw); break; + case 0xa6: sprintf(t, "sbc a,(x)"); break; + case 0xa7: sprintf(t, "sbc a,($%.3x+x)", opdp0); break; + case 0xa8: sprintf(t, "sbc a,#$%.2x", op0); break; + case 0xa9: sprintf(t, "sbc $%.3x,$%.3x", opdp1, opdp0); break; + case 0xaa: sprintf(t, "mov1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0xab: sprintf(t, "inc $%.3x", opdp0); break; + case 0xac: sprintf(t, "inc $%.4x", opw); break; + case 0xad: sprintf(t, "cmp y,#$%.2x", op0); break; + case 0xae: sprintf(t, "pop a"); break; + case 0xaf: sprintf(t, "mov (x)+,a"); break; + case 0xb0: sprintf(t, "bcs $%.4x", relb(op0, 2)); break; + case 0xb1: sprintf(t, "tcall 11"); break; + case 0xb2: sprintf(t, "clr5 $%.3x", opdp0); break; + case 0xb3: sprintf(t, "bbc5 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xb4: sprintf(t, "sbc a,$%.3x+x", opdp0); break; + case 0xb5: sprintf(t, "sbc a,$%.4x+x", opw); break; + case 0xb6: sprintf(t, "sbc a,$%.4x+y", opw); break; + case 0xb7: sprintf(t, "sbc a,($%.3x)+y", opdp0); break; + case 0xb8: sprintf(t, "sbc $%.3x,#$%.2x", opdp1, op0); break; + case 0xb9: sprintf(t, "sbc (x),(y)"); break; + case 0xba: sprintf(t, "movw ya,$%.3x", opdp0); break; + case 0xbb: sprintf(t, "inc $%.3x+x", opdp0); break; + case 0xbc: sprintf(t, "inc a"); break; + case 0xbd: sprintf(t, "mov sp,x"); break; + case 0xbe: sprintf(t, "das a"); break; + case 0xbf: sprintf(t, "mov a,(x)+"); break; + case 0xc0: sprintf(t, "di"); break; + case 0xc1: sprintf(t, "tcall 12"); break; + case 0xc2: sprintf(t, "set6 $%.3x", opdp0); break; + case 0xc3: sprintf(t, "bbs6 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xc4: sprintf(t, "mov $%.3x,a", opdp0); break; + case 0xc5: sprintf(t, "mov $%.4x,a", opw); break; + case 0xc6: sprintf(t, "mov (x),a"); break; + case 0xc7: sprintf(t, "mov ($%.3x+x),a", opdp0); break; + case 0xc8: sprintf(t, "cmp x,#$%.2x", op0); break; + case 0xc9: sprintf(t, "mov $%.4x,x", opw); break; + case 0xca: sprintf(t, "mov1 $%.4x:%d,c", opw & 0x1fff, opw >> 13); break; + case 0xcb: sprintf(t, "mov $%.3x,y", opdp0); break; + case 0xcc: sprintf(t, "mov $%.4x,y", opw); break; + case 0xcd: sprintf(t, "mov x,#$%.2x", op0); break; + case 0xce: sprintf(t, "pop x"); break; + case 0xcf: sprintf(t, "mul ya"); break; + case 0xd0: sprintf(t, "bne $%.4x", relb(op0, 2)); break; + case 0xd1: sprintf(t, "tcall 13"); break; + case 0xd2: sprintf(t, "clr6 $%.3x", opdp0); break; + case 0xd3: sprintf(t, "bbc6 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xd4: sprintf(t, "mov $%.3x+x,a", opdp0); break; + case 0xd5: sprintf(t, "mov $%.4x+x,a", opw); break; + case 0xd6: sprintf(t, "mov $%.4x+y,a", opw); break; + case 0xd7: sprintf(t, "mov ($%.3x)+y,a", opdp0); break; + case 0xd8: sprintf(t, "mov $%.3x,x", opdp0); break; + case 0xd9: sprintf(t, "mov $%.3x+y,x", opdp0); break; + case 0xda: sprintf(t, "movw $%.3x,ya", opdp0); break; + case 0xdb: sprintf(t, "mov $%.3x+x,y", opdp0); break; + case 0xdc: sprintf(t, "dec y"); break; + case 0xdd: sprintf(t, "mov a,y"); break; + case 0xde: sprintf(t, "cbne $%.3x+x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xdf: sprintf(t, "daa a"); break; + case 0xe0: sprintf(t, "clrv"); break; + case 0xe1: sprintf(t, "tcall 14"); break; + case 0xe2: sprintf(t, "set7 $%.3x", opdp0); break; + case 0xe3: sprintf(t, "bbs7 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xe4: sprintf(t, "mov a,$%.3x", opdp0); break; + case 0xe5: sprintf(t, "mov a,$%.4x", opw); break; + case 0xe6: sprintf(t, "mov a,(x)"); break; + case 0xe7: sprintf(t, "mov a,($%.3x+x)", opdp0); break; + case 0xe8: sprintf(t, "mov a,#$%.2x", op0); break; + case 0xe9: sprintf(t, "mov x,$%.4x", opw); break; + case 0xea: sprintf(t, "not1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0xeb: sprintf(t, "mov y,$%.3x", opdp0); break; + case 0xec: sprintf(t, "mov y,$%.4x", opw); break; + case 0xed: sprintf(t, "notc"); break; + case 0xee: sprintf(t, "pop y"); break; + case 0xef: sprintf(t, "sleep"); break; + case 0xf0: sprintf(t, "beq $%.4x", relb(op0, 2)); break; + case 0xf1: sprintf(t, "tcall 15"); break; + case 0xf2: sprintf(t, "clr7 $%.3x", opdp0); break; + case 0xf3: sprintf(t, "bbc7 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xf4: sprintf(t, "mov a,$%.3x+x", opdp0); break; + case 0xf5: sprintf(t, "mov a,$%.4x+x", opw); break; + case 0xf6: sprintf(t, "mov a,$%.4x+y", opw); break; + case 0xf7: sprintf(t, "mov a,($%.3x)+y", opdp0); break; + case 0xf8: sprintf(t, "mov x,$%.3x", opdp0); break; + case 0xf9: sprintf(t, "mov x,$%.3x+y", opdp0); break; + case 0xfa: sprintf(t, "mov $%.3x,$%.3x", opdp1, opdp0); break; + case 0xfb: sprintf(t, "mov y,$%.3x+x", opdp0); break; + case 0xfc: sprintf(t, "inc y"); break; + case 0xfd: sprintf(t, "mov y,a"); break; + case 0xfe: sprintf(t, "dbnz y,$%.4x", relb(op0, 2)); break; + case 0xff: sprintf(t, "stop"); break; + } + + t[strlen(t)] = ' '; + strcat(s, t); + + sprintf(t, "A:%.2x X:%.2x Y:%.2x SP:01%.2x YA:%.4x ", + regs.a, regs.x, regs.y, regs.sp, (uint16)regs.ya); + strcat(s, t); + + sprintf(t, "%c%c%c%c%c%c%c%c", + regs.p.n ? 'N' : 'n', + regs.p.v ? 'V' : 'v', + regs.p.p ? 'P' : 'p', + regs.p.b ? 'B' : 'b', + regs.p.h ? 'H' : 'h', + regs.p.i ? 'I' : 'i', + regs.p.z ? 'Z' : 'z', + regs.p.c ? 'C' : 'c'); + strcat(s, t); +} diff --git a/bsnes/snes/alt/smp/iplrom.cpp b/bsnes/snes/alt/smp/iplrom.cpp new file mode 100755 index 000000000..a2ade89d9 --- /dev/null +++ b/bsnes/snes/alt/smp/iplrom.cpp @@ -0,0 +1,44 @@ +#ifdef SMP_CPP + +//this is the IPLROM for the S-SMP coprocessor. +//the S-SMP does not allow writing to the IPLROM. +//all writes are instead mapped to the extended +//RAM region, accessible when $f1.d7 is clear. + +const uint8 SMP::iplrom[64] = { +/*ffc0*/ 0xcd, 0xef, //mov x,#$ef +/*ffc2*/ 0xbd, //mov sp,x +/*ffc3*/ 0xe8, 0x00, //mov a,#$00 +/*ffc5*/ 0xc6, //mov (x),a +/*ffc6*/ 0x1d, //dec x +/*ffc7*/ 0xd0, 0xfc, //bne $ffc5 +/*ffc9*/ 0x8f, 0xaa, 0xf4, //mov $f4,#$aa +/*ffcc*/ 0x8f, 0xbb, 0xf5, //mov $f5,#$bb +/*ffcf*/ 0x78, 0xcc, 0xf4, //cmp $f4,#$cc +/*ffd2*/ 0xd0, 0xfb, //bne $ffcf +/*ffd4*/ 0x2f, 0x19, //bra $ffef +/*ffd6*/ 0xeb, 0xf4, //mov y,$f4 +/*ffd8*/ 0xd0, 0xfc, //bne $ffd6 +/*ffda*/ 0x7e, 0xf4, //cmp y,$f4 +/*ffdc*/ 0xd0, 0x0b, //bne $ffe9 +/*ffde*/ 0xe4, 0xf5, //mov a,$f5 +/*ffe0*/ 0xcb, 0xf4, //mov $f4,y +/*ffe2*/ 0xd7, 0x00, //mov ($00)+y,a +/*ffe4*/ 0xfc, //inc y +/*ffe5*/ 0xd0, 0xf3, //bne $ffda +/*ffe7*/ 0xab, 0x01, //inc $01 +/*ffe9*/ 0x10, 0xef, //bpl $ffda +/*ffeb*/ 0x7e, 0xf4, //cmp y,$f4 +/*ffed*/ 0x10, 0xeb, //bpl $ffda +/*ffef*/ 0xba, 0xf6, //movw ya,$f6 +/*fff1*/ 0xda, 0x00, //movw $00,ya +/*fff3*/ 0xba, 0xf4, //movw ya,$f4 +/*fff5*/ 0xc4, 0xf4, //mov $f4,a +/*fff7*/ 0xdd, //mov a,y +/*fff8*/ 0x5d, //mov x,a +/*fff9*/ 0xd0, 0xdb, //bne $ffd6 +/*fffb*/ 0x1f, 0x00, 0x00, //jmp ($0000+x) +/*fffe*/ 0xc0, 0xff //reset vector location ($ffc0) +}; + +#endif diff --git a/bsnes/snes/alt/smp/memory.cpp b/bsnes/snes/alt/smp/memory.cpp new file mode 100755 index 000000000..aecba7209 --- /dev/null +++ b/bsnes/snes/alt/smp/memory.cpp @@ -0,0 +1,130 @@ +unsigned SMP::port_read(unsigned addr) { + return apuram[0xf4 + (addr & 3)]; +} + +void SMP::port_write(unsigned addr, unsigned data) { + apuram[0xf4 + (addr & 3)] = data; +} + +unsigned SMP::mmio_read(unsigned addr) { + switch(addr) { + + case 0xf2: + return status.dsp_addr; + + case 0xf3: + return dsp.read(status.dsp_addr & 0x7f); + + case 0xf4: + case 0xf5: + case 0xf6: + case 0xf7: + synchronize_cpu(); + return cpu.port_read(addr); + + case 0xf8: + return status.ram00f8; + + case 0xf9: + return status.ram00f9; + + case 0xfd: { + unsigned result = timer0.stage3_ticks & 15; + timer0.stage3_ticks = 0; + return result; + } + + case 0xfe: { + unsigned result = timer1.stage3_ticks & 15; + timer1.stage3_ticks = 0; + return result; + } + + case 0xff: { + unsigned result = timer2.stage3_ticks & 15; + timer2.stage3_ticks = 0; + return result; + } + + } + + return 0x00; +} + +void SMP::mmio_write(unsigned addr, unsigned data) { + switch(addr) { + + case 0xf1: + status.iplrom_enable = data & 0x80; + + if(data & 0x30) { + synchronize_cpu(); + if(data & 0x20) { + cpu.port_write(3, 0x00); + cpu.port_write(2, 0x00); + } + if(data & 0x10) { + cpu.port_write(1, 0x00); + cpu.port_write(0, 0x00); + } + } + + if(timer2.enable == false && (data & 0x04)) { + timer2.stage2_ticks = 0; + timer2.stage3_ticks = 0; + } + timer2.enable = data & 0x04; + + if(timer1.enable == false && (data & 0x02)) { + timer1.stage2_ticks = 0; + timer1.stage3_ticks = 0; + } + timer1.enable = data & 0x02; + + if(timer0.enable == false && (data & 0x01)) { + timer0.stage2_ticks = 0; + timer0.stage3_ticks = 0; + } + timer0.enable = data & 0x01; + + break; + + case 0xf2: + status.dsp_addr = data; + break; + + case 0xf3: + if(status.dsp_addr & 0x80) break; + dsp.write(status.dsp_addr, data); + break; + + case 0xf4: + case 0xf5: + case 0xf6: + case 0xf7: + synchronize_cpu(); + port_write(addr, data); + break; + + case 0xf8: + status.ram00f8 = data; + break; + + case 0xf9: + status.ram00f9 = data; + break; + + case 0xfa: + timer0.target = data; + break; + + case 0xfb: + timer1.target = data; + break; + + case 0xfc: + timer2.target = data; + break; + + } +} diff --git a/bsnes/snes/alt/smp/smp.cpp b/bsnes/snes/alt/smp/smp.cpp new file mode 100755 index 000000000..e285e229f --- /dev/null +++ b/bsnes/snes/alt/smp/smp.cpp @@ -0,0 +1,100 @@ +#include + +#define SMP_CPP +namespace SNES { + +#if defined(DEBUGGER) + #include "debugger/debugger.cpp" + SMPDebugger smp; +#else + SMP smp; +#endif + +#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(); + } +} + +void SMP::synchronize_dsp() { + if(DSP::Threaded == true) { + if(dsp.clock < 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(dsp.thread); + } else { + while(dsp.clock < 0) dsp.enter(); + } +} + +void SMP::enter() { + op_step(); +} + +void SMP::power() { + Processor::frequency = system.apu_frequency() / 24; + Processor::clock = 0; + + timer0.target = 0; + timer1.target = 0; + timer2.target = 0; + + reset(); +} + +void SMP::reset() { + for(unsigned n = 0x0000; n <= 0xffff; n++) apuram[n] = 0x00; + + regs.pc = 0xffc0; + regs.sp = 0x00ef; + regs.a = 0x00; + regs.x = 0x00; + regs.y = 0x00; + regs.p = 0x02; + + //timing + status.clock_counter = 0; + 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; + + //$00f2 + status.dsp_addr = 0x00; + + //$00f8,$00f9 + status.ram00f8 = 0x00; + status.ram00f9 = 0x00; +} + +void SMP::serialize(serializer &s) { +} + +SMP::SMP() { +} + +SMP::~SMP() { +} + +} diff --git a/bsnes/snes/alt/smp/smp.hpp b/bsnes/snes/alt/smp/smp.hpp new file mode 100755 index 000000000..935441782 --- /dev/null +++ b/bsnes/snes/alt/smp/smp.hpp @@ -0,0 +1,110 @@ +class SMP : public Processor { +public: + static const uint8 iplrom[64]; + uint8 apuram[64 * 1024]; + + 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); + + void enter(); + void power(); + void reset(); + + void serialize(serializer&); + SMP(); + ~SMP(); + + #include "core.hpp" + + struct Flags { + bool n, v, p, b, h, i, z, c; + + alwaysinline operator unsigned() const { + return (n << 7) | (v << 6) | (p << 5) | (b << 4) + | (h << 3) | (i << 2) | (z << 1) | (c << 0); + }; + + alwaysinline unsigned operator=(unsigned data) { + n = data & 0x80; v = data & 0x40; p = data & 0x20; b = data & 0x10; + h = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01; + } + + alwaysinline unsigned operator|=(unsigned data) { return operator=(operator unsigned() | data); } + alwaysinline unsigned operator^=(unsigned data) { return operator=(operator unsigned() ^ data); } + alwaysinline unsigned operator&=(unsigned data) { return operator=(operator unsigned() & data); } + }; + + struct Regs { + uint16 pc; + uint16 sp; + union { + uint16 ya; + struct { uint8 order_lsb2(a, y); }; + }; + uint8 x; + Flags p; + } regs; + + struct Status { + //timing + unsigned clock_counter; + 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; + + //$00f2 + unsigned dsp_addr; + + //$00f8,$00f9 + unsigned ram00f8; + unsigned ram00f9; + } status; + + template + struct Timer { + unsigned stage0_ticks; + unsigned stage1_ticks; + unsigned stage2_ticks; + unsigned stage3_ticks; + bool current_line; + bool enable; + unsigned target; + + void tick(); + 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); +}; + +#if defined(DEBUGGER) + #include "debugger/debugger.hpp" + extern SMPDebugger smp; +#else + extern SMP smp; +#endif diff --git a/bsnes/snes/alt/smp/timing.cpp b/bsnes/snes/alt/smp/timing.cpp new file mode 100755 index 000000000..ff092f3c5 --- /dev/null +++ b/bsnes/snes/alt/smp/timing.cpp @@ -0,0 +1,29 @@ +template +void SMP::Timer::tick() { + //stage 0 increment + stage0_ticks += smp.status.timer_step; + if(stage0_ticks < timer_frequency) return; + stage0_ticks -= timer_frequency; + + //stage 1 increment + stage1_ticks ^= 1; + synchronize(); +} + +template +void SMP::Timer::synchronize() { + bool new_line = stage1_ticks; + bool old_line = current_line; + current_line = new_line; + if(old_line != 1 || new_line != 0) return; //only pulse on 1->0 transition + + //stage 2 increment + if(enable == false) return; + stage2_ticks++; + if(stage2_ticks != target) return; + + //stage 3 increment + stage2_ticks = 0; + stage3_ticks++; + stage3_ticks &= 15; +} diff --git a/bsnes/snes/profile-performance.hpp b/bsnes/snes/profile-performance.hpp index 8562e47be..791e74784 100755 --- a/bsnes/snes/profile-performance.hpp +++ b/bsnes/snes/profile-performance.hpp @@ -3,6 +3,6 @@ namespace Info { } #include -#include +#include #include #include diff --git a/bsnes/snes/smp/debugger/debugger.cpp b/bsnes/snes/smp/debugger/debugger.cpp index e63a4cccb..9546c1182 100755 --- a/bsnes/snes/smp/debugger/debugger.cpp +++ b/bsnes/snes/smp/debugger/debugger.cpp @@ -55,14 +55,14 @@ bool SMPDebugger::property(unsigned id, string &name, string &value) { //$00f0 item("$00f0", ""); item("Clock Speed", (unsigned)status.clock_speed); - item("Timers Enable", status.timers_enabled); - item("RAM Disable", status.ram_disabled); + item("Timers Enable", status.timers_enable); + item("RAM Disable", status.ram_disable); item("RAM Writable", status.ram_writable); - item("Timers Disable", status.timers_disabled); + item("Timers Disable", status.timers_disable); //$00f1 item("$00f1", ""); - item("IPLROM Enable", status.iplrom_enabled); + item("IPLROM Enable", status.iplrom_enable); //$00f2 item("$00f2", ""); diff --git a/bsnes/snes/smp/memory/memory.cpp b/bsnes/snes/smp/memory/memory.cpp index 0026c2450..1b3ae4b47 100755 --- a/bsnes/snes/smp/memory/memory.cpp +++ b/bsnes/snes/smp/memory/memory.cpp @@ -1,14 +1,14 @@ #ifdef SMP_CPP alwaysinline uint8 SMP::ram_read(uint16 addr) { - if(addr >= 0xffc0 && status.iplrom_enabled) return iplrom[addr & 0x3f]; - if(status.ram_disabled) return 0x5a; //0xff on mini-SNES + if(addr >= 0xffc0 && status.iplrom_enable) return iplrom[addr & 0x3f]; + if(status.ram_disable) return 0x5a; //0xff on mini-SNES return apuram[addr]; } alwaysinline void SMP::ram_write(uint16 addr, uint8 data) { //writes to $ffc0-$ffff always go to apuram, even if the iplrom is enabled - if(status.ram_writable && !status.ram_disabled) apuram[addr] = data; + if(status.ram_writable && !status.ram_disable) apuram[addr] = data; } uint8 SMP::port_read(uint2 port) const { @@ -49,11 +49,11 @@ alwaysinline uint8 SMP::op_busread(uint16 addr) { } break; case 0xf8: { //RAM0 - r = status.ram0; + r = status.ram00f8; } break; case 0xf9: { //RAM1 - r = status.ram1; + r = status.ram00f9; } break; case 0xfa: //T0TARGET @@ -90,12 +90,12 @@ alwaysinline void SMP::op_buswrite(uint16 addr, uint8 data) { case 0xf0: { //TEST if(regs.p.p) break; //writes only valid when P flag is clear - status.clock_speed = (data >> 6) & 3; - status.timer_speed = (data >> 4) & 3; - status.timers_enabled = data & 0x08; - status.ram_disabled = data & 0x04; - status.ram_writable = data & 0x02; - status.timers_disabled = data & 0x01; + status.clock_speed = (data >> 6) & 3; + status.timer_speed = (data >> 4) & 3; + status.timers_enable = data & 0x08; + status.ram_disable = data & 0x04; + status.ram_writable = data & 0x02; + status.timers_disable = data & 0x01; status.timer_step = (1 << status.clock_speed) + (2 << status.timer_speed); @@ -105,7 +105,7 @@ alwaysinline void SMP::op_buswrite(uint16 addr, uint8 data) { } break; case 0xf1: { //CONTROL - status.iplrom_enabled = data & 0x80; + status.iplrom_enable = data & 0x80; if(data & 0x30) { //one-time clearing of APU port read registers, @@ -161,11 +161,11 @@ alwaysinline void SMP::op_buswrite(uint16 addr, uint8 data) { } break; case 0xf8: { //RAM0 - status.ram0 = data; + status.ram00f8 = data; } break; case 0xf9: { //RAM1 - status.ram1 = data; + status.ram00f9 = data; } break; case 0xfa: { //T0TARGET diff --git a/bsnes/snes/smp/serialization.cpp b/bsnes/snes/smp/serialization.cpp index 4565f03bd..3a0790401 100755 --- a/bsnes/snes/smp/serialization.cpp +++ b/bsnes/snes/smp/serialization.cpp @@ -12,17 +12,17 @@ void SMP::serialize(serializer &s) { s.integer(status.clock_speed); s.integer(status.timer_speed); - s.integer(status.timers_enabled); - s.integer(status.ram_disabled); + s.integer(status.timers_enable); + s.integer(status.ram_disable); s.integer(status.ram_writable); - s.integer(status.timers_disabled); + s.integer(status.timers_disable); - s.integer(status.iplrom_enabled); + s.integer(status.iplrom_enable); s.integer(status.dsp_addr); - s.integer(status.ram0); - s.integer(status.ram1); + s.integer(status.ram00f8); + s.integer(status.ram00f9); s.integer(t0.stage0_ticks); s.integer(t0.stage1_ticks); diff --git a/bsnes/snes/smp/smp.cpp b/bsnes/snes/smp/smp.cpp index 6bb2a68f0..073e06688 100755 --- a/bsnes/snes/smp/smp.cpp +++ b/bsnes/snes/smp/smp.cpp @@ -80,20 +80,20 @@ void SMP::reset() { //$00f0 status.clock_speed = 0; status.timer_speed = 0; - status.timers_enabled = true; - status.ram_disabled = false; + status.timers_enable = true; + status.ram_disable = false; status.ram_writable = true; - status.timers_disabled = false; + status.timers_disable = false; //$00f1 - status.iplrom_enabled = true; + status.iplrom_enable = true; //$00f2 status.dsp_addr = 0x00; //$00f8,$00f9 - status.ram0 = 0x00; - status.ram1 = 0x00; + status.ram00f8 = 0x00; + status.ram00f9 = 0x00; t0.stage0_ticks = 0; t1.stage0_ticks = 0; diff --git a/bsnes/snes/smp/smp.hpp b/bsnes/snes/smp/smp.hpp index 75ece083b..41aaaf748 100755 --- a/bsnes/snes/smp/smp.hpp +++ b/bsnes/snes/smp/smp.hpp @@ -32,20 +32,20 @@ private: //$00f0 uint8 clock_speed; uint8 timer_speed; - bool timers_enabled; - bool ram_disabled; + bool timers_enable; + bool ram_disable; bool ram_writable; - bool timers_disabled; + bool timers_disable; //$00f1 - bool iplrom_enabled; + bool iplrom_enable; //$00f2 uint8 dsp_addr; //$00f8,$00f9 - uint8 ram0; - uint8 ram1; + uint8 ram00f8; + uint8 ram00f9; } status; static void Enter(); diff --git a/bsnes/snes/smp/timing/timing.cpp b/bsnes/snes/smp/timing/timing.cpp index 24cff287e..484baa192 100755 --- a/bsnes/snes/smp/timing/timing.cpp +++ b/bsnes/snes/smp/timing/timing.cpp @@ -39,8 +39,8 @@ void SMP::sSMPTimer::tick() { template void SMP::sSMPTimer::sync_stage1() { bool new_line = stage1_ticks; - if(smp.status.timers_enabled == false) new_line = false; - if(smp.status.timers_disabled == true) new_line = false; + if(smp.status.timers_enable == false) new_line = false; + if(smp.status.timers_disable == true) new_line = false; bool old_line = current_line; current_line = new_line; diff --git a/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp index 8f58a792b..19d35a3ef 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"; + static const char Version[] = "078.01"; static const unsigned SerializerVersion = 19; } } diff --git a/bsnes/ui-libsnes/libsnes.cpp b/bsnes/ui-libsnes/libsnes.cpp index 7962180ca..6153de1fc 100755 --- a/bsnes/ui-libsnes/libsnes.cpp +++ b/bsnes/ui-libsnes/libsnes.cpp @@ -14,7 +14,7 @@ struct Interface : public SNES::Interface { void video_refresh(const uint16_t *data, bool hires, bool interlace, bool overscan) { unsigned width = hires ? 512 : 256; - unsigned height = overscan ? 224 : 239; + unsigned height = overscan ? 239 : 224; if(interlace) height <<= 1; data += 9 * 1024; //skip front porch if(pvideo_refresh) return pvideo_refresh(data, width, height);