diff --git a/bsnes/snes/alt/smp/core.cpp b/bsnes/snes/alt/smp/core.cpp index 5fd3ea86..6e0a29b2 100755 --- a/bsnes/snes/alt/smp/core.cpp +++ b/bsnes/snes/alt/smp/core.cpp @@ -1,7 +1,7 @@ void SMP::tick() { - timer0.tick(1); - timer1.tick(1); - timer2.tick(1); + timer0.tick(); + timer1.tick(); + timer2.tick(); clock += cycle_step_cpu; dsp.clock -= 24; @@ -19,7 +19,7 @@ uint8 SMP::op_read(uint16 addr) { tick(); #endif if((addr & 0xfff0) == 0x00f0) return mmio_read(addr); - if((addr & 0xffc0) == 0xffc0 && status.iplrom_enable) return iplrom[addr & 0x3f]; + if(addr >= 0xffc0 && status.iplrom_enable) return iplrom[addr & 0x3f]; return apuram[addr]; } @@ -31,9 +31,6 @@ void SMP::op_write(uint16 addr, uint8 data) { apuram[addr] = data; //all writes go to RAM, even MMIO writes } -//TODO: -//* non-cycle accurate untaken conditional branches should subtract from opcode's cycle overhead - void SMP::op_step() { #define op_readpc() op_read(regs.pc++) #define op_readdp(addr) op_read((regs.p.p << 8) + addr) @@ -68,6 +65,8 @@ void SMP::op_step() { #include "core/op_rmw.cpp" } + //TODO: untaken branches should consume less cycles + timer0.tick(cycle_count_table[opcode]); timer1.tick(cycle_count_table[opcode]); timer2.tick(cycle_count_table[opcode]); diff --git a/bsnes/snes/alt/smp/core.hpp b/bsnes/snes/alt/smp/core.hpp deleted file mode 100755 index 65f52a59..00000000 --- a/bsnes/snes/alt/smp/core.hpp +++ /dev/null @@ -1,25 +0,0 @@ -void tick(); -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_count_table[256]; -uint64 cycle_table_cpu[256]; -unsigned cycle_table_dsp[256]; -uint64 cycle_step_cpu; - -uint8 op_adc (uint8 x, uint8 y); -uint16 op_addw(uint16 x, uint16 y); -uint8 op_and (uint8 x, uint8 y); -uint8 op_cmp (uint8 x, uint8 y); -uint16 op_cmpw(uint16 x, uint16 y); -uint8 op_eor (uint8 x, uint8 y); -uint8 op_inc (uint8 x); -uint8 op_dec (uint8 x); -uint8 op_or (uint8 x, uint8 y); -uint8 op_sbc (uint8 x, uint8 y); -uint16 op_subw(uint16 x, uint16 y); -uint8 op_asl (uint8 x); -uint8 op_lsr (uint8 x); -uint8 op_rol (uint8 x); -uint8 op_ror (uint8 x); diff --git a/bsnes/snes/alt/smp/core/generate b/bsnes/snes/alt/smp/core/generate deleted file mode 100755 index ab6b9a67..00000000 Binary files a/bsnes/snes/alt/smp/core/generate and /dev/null differ diff --git a/bsnes/snes/alt/smp/smp.cpp b/bsnes/snes/alt/smp/smp.cpp index 08a67ef0..a309db05 100755 --- a/bsnes/snes/alt/smp/smp.cpp +++ b/bsnes/snes/alt/smp/smp.cpp @@ -1,4 +1,4 @@ -#define CYCLE_ACCURATE +//#define CYCLE_ACCURATE #include diff --git a/bsnes/snes/alt/smp/smp.hpp b/bsnes/snes/alt/smp/smp.hpp index e9e6b28b..a7c14741 100755 --- a/bsnes/snes/alt/smp/smp.hpp +++ b/bsnes/snes/alt/smp/smp.hpp @@ -21,8 +21,7 @@ public: SMP(); ~SMP(); - #include "core.hpp" - +//private: struct Flags { bool n, v, p, b, h, i, z, c; @@ -75,12 +74,39 @@ public: uint8 stage2_ticks; uint8 stage3_ticks; + void tick(); void tick(unsigned clocks); }; Timer<128> timer0; Timer<128> timer1; Timer< 16> timer2; + + void tick(); + 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_count_table[256]; + uint64 cycle_table_cpu[256]; + unsigned cycle_table_dsp[256]; + uint64 cycle_step_cpu; + + uint8 op_adc (uint8 x, uint8 y); + uint16 op_addw(uint16 x, uint16 y); + uint8 op_and (uint8 x, uint8 y); + uint8 op_cmp (uint8 x, uint8 y); + uint16 op_cmpw(uint16 x, uint16 y); + uint8 op_eor (uint8 x, uint8 y); + uint8 op_inc (uint8 x); + uint8 op_dec (uint8 x); + uint8 op_or (uint8 x, uint8 y); + uint8 op_sbc (uint8 x, uint8 y); + uint16 op_subw(uint16 x, uint16 y); + uint8 op_asl (uint8 x); + uint8 op_lsr (uint8 x); + uint8 op_rol (uint8 x); + uint8 op_ror (uint8 x); }; #if defined(DEBUGGER) diff --git a/bsnes/snes/alt/smp/timing.cpp b/bsnes/snes/alt/smp/timing.cpp index f01adb3f..d278f6f4 100755 --- a/bsnes/snes/alt/smp/timing.cpp +++ b/bsnes/snes/alt/smp/timing.cpp @@ -1,3 +1,16 @@ +template +void SMP::Timer::tick() { + if(++stage1_ticks < cycle_frequency) return; + + stage1_ticks = 0; + if(enable == false) return; + + if(++stage2_ticks != target) return; + + stage2_ticks = 0; + stage3_ticks = (stage3_ticks + 1) & 15; +} + template void SMP::Timer::tick(unsigned clocks) { stage1_ticks += clocks; @@ -6,10 +19,8 @@ void SMP::Timer::tick(unsigned clocks) { stage1_ticks -= cycle_frequency; if(enable == false) return; - stage2_ticks++; - if(stage2_ticks != target) return; + if(++stage2_ticks != target) return; stage2_ticks = 0; - stage3_ticks++; - stage3_ticks &= 15; + stage3_ticks = (stage3_ticks + 1) & 15; } diff --git a/bsnes/snes/smp/core/memory.hpp b/bsnes/snes/smp/core/memory.hpp index 9af32956..4b7afba0 100755 --- a/bsnes/snes/smp/core/memory.hpp +++ b/bsnes/snes/smp/core/memory.hpp @@ -2,22 +2,14 @@ alwaysinline uint8_t op_readpc() { return op_read(regs.pc++); } -alwaysinline uint8_t op_readstack() { +alwaysinline uint8_t op_readsp() { return op_read(0x0100 | ++regs.sp); } -alwaysinline void op_writestack(uint8_t data) { +alwaysinline void op_writesp(uint8_t data) { op_write(0x0100 | regs.sp--, data); } -alwaysinline uint8_t op_readaddr(uint16_t addr) { - return op_read(addr); -} - -alwaysinline void op_writeaddr(uint16_t addr, uint8_t data) { - op_write(addr, data); -} - alwaysinline uint8_t op_readdp(uint8_t addr) { return op_read(((unsigned)regs.p.p << 8) + addr); } diff --git a/bsnes/snes/smp/core/opcode_misc.cpp b/bsnes/snes/smp/core/opcode_misc.cpp index 0f4d4ce3..533c8f96 100755 --- a/bsnes/snes/smp/core/opcode_misc.cpp +++ b/bsnes/snes/smp/core/opcode_misc.cpp @@ -31,7 +31,7 @@ void SMPcore::op_daa() { if(regs.p.h || (regs.a & 15) > 0x09) { regs.a += 0x06; } - regs.p.n = !!(regs.a & 0x80); + regs.p.n = (regs.a & 0x80); regs.p.z = (regs.a == 0); } @@ -45,7 +45,7 @@ void SMPcore::op_das() { if(!regs.p.h || (regs.a & 15) > 0x09) { regs.a -= 0x06; } - regs.p.n = !!(regs.a & 0x80); + regs.p.n = (regs.a & 0x80); regs.p.z = (regs.a == 0); } @@ -76,25 +76,25 @@ template void SMPcore::op_setbit_dp() { template void SMPcore::op_push_reg() { op_io(); op_io(); - op_writestack(regs.r[n]); + op_writesp(regs.r[n]); } void SMPcore::op_push_p() { op_io(); op_io(); - op_writestack(regs.p); + op_writesp(regs.p); } template void SMPcore::op_pop_reg() { op_io(); op_io(); - regs.r[n] = op_readstack(); + regs.r[n] = op_readsp(); } void SMPcore::op_pop_p() { op_io(); op_io(); - regs.p = op_readstack(); + regs.p = op_readsp(); } void SMPcore::op_mul_ya() { @@ -110,7 +110,7 @@ void SMPcore::op_mul_ya() { regs.a = ya; regs.y = ya >> 8; //result is set based on y (high-byte) only - regs.p.n = !!(regs.y & 0x80); + regs.p.n = (regs.y & 0x80); regs.p.z = (regs.y == 0); } @@ -128,8 +128,8 @@ void SMPcore::op_div_ya_x() { op_io(); ya = regs.ya; //overflow set if quotient >= 256 - regs.p.v = !!(regs.y >= regs.x); - regs.p.h = !!((regs.y & 15) >= (regs.x & 15)); + regs.p.v = (regs.y >= regs.x); + regs.p.h = ((regs.y & 15) >= (regs.x & 15)); if(regs.y < (regs.x << 1)) { //if quotient is <= 511 (will fit into 9-bit result) regs.a = ya / regs.x; @@ -141,7 +141,7 @@ void SMPcore::op_div_ya_x() { regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x); } //result is set based on a (quotient) only - regs.p.n = !!(regs.a & 0x80); + regs.p.n = (regs.a & 0x80); regs.p.z = (regs.a == 0); } diff --git a/bsnes/snes/smp/core/opcode_mov.cpp b/bsnes/snes/smp/core/opcode_mov.cpp index e21593c8..f1767855 100755 --- a/bsnes/snes/smp/core/opcode_mov.cpp +++ b/bsnes/snes/smp/core/opcode_mov.cpp @@ -51,7 +51,7 @@ template void SMPcore::op_mov_reg_dpr() { template void SMPcore::op_mov_reg_addr() { sp = op_readpc() << 0; sp |= op_readpc() << 8; - regs.r[n] = op_readaddr(sp); + regs.r[n] = op_read(sp); regs.p.n = (regs.r[n] & 0x80); regs.p.z = (regs.r[n] == 0); } @@ -60,7 +60,7 @@ template void SMPcore::op_mov_a_addrr() { sp = op_readpc() << 0; sp |= op_readpc() << 8; op_io(); - regs.a = op_readaddr(sp + regs.r[i]); + regs.a = op_read(sp + regs.r[i]); regs.p.n = (regs.a & 0x80); regs.p.z = (regs.a == 0); } @@ -70,7 +70,7 @@ void SMPcore::op_mov_a_idpx() { op_io(); sp = op_readdp(dp + 0) << 0; sp |= op_readdp(dp + 1) << 8; - regs.a = op_readaddr(sp); + regs.a = op_read(sp); regs.p.n = (regs.a & 0x80); regs.p.z = (regs.a == 0); } @@ -80,7 +80,7 @@ void SMPcore::op_mov_a_idpy() { op_io(); sp = op_readdp(dp + 0) << 0; sp |= op_readdp(dp + 1) << 8; - regs.a = op_readaddr(sp + regs.y); + regs.a = op_read(sp + regs.y); regs.p.n = (regs.a & 0x80); regs.p.z = (regs.a == 0); } @@ -128,8 +128,8 @@ template void SMPcore::op_mov_dpr_reg() { template void SMPcore::op_mov_addr_reg() { dp = op_readpc() << 0; dp |= op_readpc() << 8; - op_readaddr(dp); - op_writeaddr(dp, regs.r[n]); + op_read(dp); + op_write(dp, regs.r[n]); } template void SMPcore::op_mov_addrr_a() { @@ -137,8 +137,8 @@ template void SMPcore::op_mov_addrr_a() { dp |= op_readpc() << 8; op_io(); dp += regs.r[i]; - op_readaddr(dp); - op_writeaddr(dp, regs.a); + op_read(dp); + op_write(dp, regs.a); } void SMPcore::op_mov_idpx_a() { @@ -147,8 +147,8 @@ void SMPcore::op_mov_idpx_a() { sp += regs.x; dp = op_readdp(sp + 0) << 0; dp |= op_readdp(sp + 1) << 8; - op_readaddr(dp); - op_writeaddr(dp, regs.a); + op_read(dp); + op_write(dp, regs.a); } void SMPcore::op_mov_idpy_a() { @@ -157,8 +157,8 @@ void SMPcore::op_mov_idpy_a() { dp |= op_readdp(sp + 1) << 8; op_io(); dp += regs.y; - op_readaddr(dp); - op_writeaddr(dp, regs.a); + op_read(dp); + op_write(dp, regs.a); } void SMPcore::op_movw_ya_dp() { @@ -182,7 +182,7 @@ void SMPcore::op_mov1_c_bit() { sp |= op_readpc() << 8; bit = sp >> 13; sp &= 0x1fff; - rd = op_readaddr(sp); + rd = op_read(sp); regs.p.c = (rd & (1 << bit)); } @@ -191,10 +191,10 @@ void SMPcore::op_mov1_bit_c() { dp |= op_readpc() << 8; bit = dp >> 13; dp &= 0x1fff; - rd = op_readaddr(dp); + rd = op_read(dp); (regs.p.c) ? rd |= (1 << bit) : rd &= ~(1 << bit); op_io(); - op_writeaddr(dp, rd); + op_write(dp, rd); } #endif diff --git a/bsnes/snes/smp/core/opcode_pc.cpp b/bsnes/snes/smp/core/opcode_pc.cpp index b69d8416..727522c8 100755 --- a/bsnes/snes/smp/core/opcode_pc.cpp +++ b/bsnes/snes/smp/core/opcode_pc.cpp @@ -82,8 +82,8 @@ void SMPcore::op_jmp_iaddrx() { dp |= op_readpc() << 8; op_io(); dp += regs.x; - rd = op_readaddr(dp + 0) << 0; - rd |= op_readaddr(dp + 1) << 8; + rd = op_read(dp + 0) << 0; + rd |= op_read(dp + 1) << 8; regs.pc = rd; } @@ -93,8 +93,8 @@ void SMPcore::op_call() { op_io(); op_io(); op_io(); - op_writestack(regs.pc >> 8); - op_writestack(regs.pc >> 0); + op_writesp(regs.pc >> 8); + op_writesp(regs.pc >> 0); regs.pc = rd; } @@ -102,48 +102,48 @@ void SMPcore::op_pcall() { rd = op_readpc(); op_io(); op_io(); - op_writestack(regs.pc >> 8); - op_writestack(regs.pc >> 0); + op_writesp(regs.pc >> 8); + op_writesp(regs.pc >> 0); regs.pc = 0xff00 | rd; } template void SMPcore::op_tcall() { dp = 0xffde - (n << 1); - rd = op_readaddr(dp + 0) << 0; - rd |= op_readaddr(dp + 1) << 8; + rd = op_read(dp + 0) << 0; + rd |= op_read(dp + 1) << 8; op_io(); op_io(); op_io(); - op_writestack(regs.pc >> 8); - op_writestack(regs.pc >> 0); + op_writesp(regs.pc >> 8); + op_writesp(regs.pc >> 0); regs.pc = rd; } void SMPcore::op_brk() { - rd = op_readaddr(0xffde) << 0; - rd |= op_readaddr(0xffdf) << 8; + rd = op_read(0xffde) << 0; + rd |= op_read(0xffdf) << 8; op_io(); op_io(); - op_writestack(regs.pc >> 8); - op_writestack(regs.pc >> 0); - op_writestack(regs.p); + 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; } void SMPcore::op_ret() { - rd = op_readstack() << 0; - rd |= op_readstack() << 8; + rd = op_readsp() << 0; + rd |= op_readsp() << 8; op_io(); op_io(); regs.pc = rd; } void SMPcore::op_reti() { - regs.p = op_readstack(); - rd = op_readstack() << 0; - rd |= op_readstack() << 8; + regs.p = op_readsp(); + rd = op_readsp() << 0; + rd |= op_readsp() << 8; op_io(); op_io(); regs.pc = rd; diff --git a/bsnes/snes/smp/core/opcode_read.cpp b/bsnes/snes/smp/core/opcode_read.cpp index 2058cff2..25a5bc06 100755 --- a/bsnes/snes/smp/core/opcode_read.cpp +++ b/bsnes/snes/smp/core/opcode_read.cpp @@ -32,7 +32,7 @@ template void SMPcore::op_read_reg_addr() { dp = op_readpc() << 0; dp |= op_readpc() << 8; - rd = op_readaddr(dp); + rd = op_read(dp); regs.r[n] = (this->*op)(regs.r[n], rd); } @@ -41,7 +41,7 @@ void SMPcore::op_read_a_addrr() { dp = op_readpc() << 0; dp |= op_readpc() << 8; op_io(); - rd = op_readaddr(dp + regs.r[i]); + rd = op_read(dp + regs.r[i]); regs.a = (this->*op)(regs.a, rd); } @@ -51,7 +51,7 @@ void SMPcore::op_read_a_idpx() { op_io(); sp = op_readdp(dp + 0) << 0; sp |= op_readdp(dp + 1) << 8; - rd = op_readaddr(sp); + rd = op_read(sp); regs.a = (this->*op)(regs.a, rd); } @@ -61,7 +61,7 @@ void SMPcore::op_read_a_idpy() { op_io(); sp = op_readdp(dp + 0) << 0; sp |= op_readdp(dp + 1) << 8; - rd = op_readaddr(sp + regs.y); + rd = op_read(sp + regs.y); regs.a = (this->*op)(regs.a, rd); } @@ -117,7 +117,7 @@ template void SMPcore::op_and1_bit() { dp |= op_readpc() << 8; bit = dp >> 13; dp &= 0x1fff; - rd = op_readaddr(dp); + rd = op_read(dp); regs.p.c = regs.p.c & ((bool)(rd & (1 << bit)) ^ op); } @@ -126,7 +126,7 @@ void SMPcore::op_eor1_bit() { dp |= op_readpc() << 8; bit = dp >> 13; dp &= 0x1fff; - rd = op_readaddr(dp); + rd = op_read(dp); op_io(); regs.p.c = regs.p.c ^ (bool)(rd & (1 << bit)); } @@ -136,9 +136,9 @@ void SMPcore::op_not1_bit() { dp |= op_readpc() << 8; bit = dp >> 13; dp &= 0x1fff; - rd = op_readaddr(dp); + rd = op_read(dp); rd ^= 1 << bit; - op_writeaddr(dp, rd); + op_write(dp, rd); } template void SMPcore::op_or1_bit() { @@ -146,7 +146,7 @@ template void SMPcore::op_or1_bit() { dp |= op_readpc() << 8; bit = dp >> 13; dp &= 0x1fff; - rd = op_readaddr(dp); + rd = op_read(dp); op_io(); regs.p.c = regs.p.c | ((bool)(rd & (1 << bit)) ^ op); } diff --git a/bsnes/snes/smp/core/opcode_rmw.cpp b/bsnes/snes/smp/core/opcode_rmw.cpp index 103bd2db..df59f490 100755 --- a/bsnes/snes/smp/core/opcode_rmw.cpp +++ b/bsnes/snes/smp/core/opcode_rmw.cpp @@ -27,20 +27,20 @@ template void SMPcore::op_adjust_addr() { dp = op_readpc() << 0; dp |= op_readpc() << 8; - rd = op_readaddr(dp); + rd = op_read(dp); rd = (this->*op)(rd); - op_writeaddr(dp, rd); + op_write(dp, rd); } template void SMPcore::op_adjust_addr_a() { dp = op_readpc() << 0; dp |= op_readpc() << 8; - rd = op_readaddr(dp); + rd = op_read(dp); regs.p.n = ((regs.a - rd) & 0x80); regs.p.z = ((regs.a - rd) == 0); - op_readaddr(dp); - op_writeaddr(dp, (op ? rd | regs.a : rd & ~regs.a)); + op_read(dp); + op_write(dp, (op ? rd | regs.a : rd & ~regs.a)); } template diff --git a/bsnes/snes/smp/memory/memory.cpp b/bsnes/snes/smp/memory/memory.cpp index 7cd880fb..d4bab14a 100755 --- a/bsnes/snes/smp/memory/memory.cpp +++ b/bsnes/snes/smp/memory/memory.cpp @@ -20,175 +20,162 @@ void SMP::port_write(uint2 port, uint8 data) { } alwaysinline uint8 SMP::op_busread(uint16 addr) { - uint8 r; - if((addr & 0xfff0) == 0x00f0) { //00f0-00ff - switch(addr) { - case 0xf0: { //TEST -- write-only register - r = 0x00; - } break; + if((addr & 0xfff0) != 0x00f0) return ram_read(addr); - case 0xf1: { //CONTROL -- write-only register - r = 0x00; - } break; + unsigned result; - case 0xf2: { //DSPADDR - r = status.dsp_addr; - } break; + switch(addr) { + case 0xf0: //TEST -- write-only register + return 0x00; - case 0xf3: { //DSPDATA - //0x80-0xff are read-only mirrors of 0x00-0x7f - r = dsp.read(status.dsp_addr & 0x7f); - } break; + case 0xf1: //CONTROL -- write-only register + return 0x00; - case 0xf4: //CPUIO0 - case 0xf5: //CPUIO1 - case 0xf6: //CPUIO2 - case 0xf7: { //CPUIO3 - synchronize_cpu(); - r = cpu.port_read(addr); - } break; + case 0xf2: //DSPADDR + return status.dsp_addr; - case 0xf8: { //RAM0 - r = status.ram00f8; - } break; + case 0xf3: //DSPDATA + //0x80-0xff are read-only mirrors of 0x00-0x7f + return dsp.read(status.dsp_addr & 0x7f); - case 0xf9: { //RAM1 - r = status.ram00f9; - } break; + case 0xf4: //CPUIO0 + case 0xf5: //CPUIO1 + case 0xf6: //CPUIO2 + case 0xf7: //CPUIO3 + synchronize_cpu(); + return cpu.port_read(addr); - case 0xfa: //T0TARGET - case 0xfb: //T1TARGET - case 0xfc: { //T2TARGET -- write-only registers - r = 0x00; - } break; + case 0xf8: //RAM0 + return status.ram00f8; - case 0xfd: { //T0OUT -- 4-bit counter value - r = timer0.stage3_ticks & 15; - timer0.stage3_ticks = 0; - } break; + case 0xf9: //RAM1 + return status.ram00f9; - case 0xfe: { //T1OUT -- 4-bit counter value - r = timer1.stage3_ticks & 15; - timer1.stage3_ticks = 0; - } break; + case 0xfa: //T0TARGET + case 0xfb: //T1TARGET + case 0xfc: //T2TARGET -- write-only registers + return 0x00; - case 0xff: { //T2OUT -- 4-bit counter value - r = timer2.stage3_ticks & 15; - timer2.stage3_ticks = 0; - } break; - } - } else { - r = ram_read(addr); + case 0xfd: //T0OUT -- 4-bit counter value + result = timer0.stage3_ticks & 15; + timer0.stage3_ticks = 0; + return result; + + case 0xfe: //T1OUT -- 4-bit counter value + result = timer1.stage3_ticks & 15; + timer1.stage3_ticks = 0; + return result; + + case 0xff: //T2OUT -- 4-bit counter value + result = timer2.stage3_ticks & 15; + timer2.stage3_ticks = 0; + return result; } - return r; + return 0x00; //never used, avoids compiler warning } alwaysinline void SMP::op_buswrite(uint16 addr, uint8 data) { - if((addr & 0xfff0) == 0x00f0) { //$00f0-00ff - switch(addr) { - case 0xf0: { //TEST - if(regs.p.p) break; //writes only valid when P flag is clear + ram_write(addr, data); //all writes, even to MMIO registers, appear on bus + if((addr & 0xfff0) != 0x00f0) return; - 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; + switch(addr) { + case 0xf0: //TEST + if(regs.p.p) break; //writes only valid when P flag is clear - status.timer_step = (1 << status.clock_speed) + (2 << status.timer_speed); + 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; - timer0.sync_stage1(); - timer1.sync_stage1(); - timer2.sync_stage1(); - } break; + status.timer_step = (1 << status.clock_speed) + (2 << status.timer_speed); - case 0xf1: { //CONTROL - status.iplrom_enable = data & 0x80; + timer0.synchronize_stage1(); + timer1.synchronize_stage1(); + timer2.synchronize_stage1(); + break; - if(data & 0x30) { - //one-time clearing of APU port read registers, - //emulated by simulating CPU writes of 0x00 - synchronize_cpu(); - if(data & 0x20) { - cpu.port_write(2, 0x00); - cpu.port_write(3, 0x00); - } - if(data & 0x10) { - cpu.port_write(0, 0x00); - cpu.port_write(1, 0x00); - } - } + case 0xf1: //CONTROL + status.iplrom_enable = data & 0x80; - //0->1 transistion resets timers - 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: { //DSPADDR - status.dsp_addr = data; - } break; - - case 0xf3: { //DSPDATA - //0x80-0xff are read-only mirrors of 0x00-0x7f - if(!(status.dsp_addr & 0x80)) { - dsp.write(status.dsp_addr & 0x7f, data); - } - } break; - - case 0xf4: //CPUIO0 - case 0xf5: //CPUIO1 - case 0xf6: //CPUIO2 - case 0xf7: { //CPUIO3 - synchronize_cpu(); - port_write(addr, data); - } break; - - case 0xf8: { //RAM0 - status.ram00f8 = data; - } break; - - case 0xf9: { //RAM1 - status.ram00f9 = data; - } break; - - case 0xfa: { //T0TARGET - timer0.target = data; - } break; - - case 0xfb: { //T1TARGET - timer1.target = data; - } break; - - case 0xfc: { //T2TARGET - timer2.target = data; - } break; - - case 0xfd: //T0OUT - case 0xfe: //T1OUT - case 0xff: { //T2OUT -- read-only registers - } break; + if(data & 0x30) { + //one-time clearing of APU port read registers, + //emulated by simulating CPU writes of 0x00 + synchronize_cpu(); + if(data & 0x20) { + cpu.port_write(2, 0x00); + cpu.port_write(3, 0x00); + } + if(data & 0x10) { + cpu.port_write(0, 0x00); + cpu.port_write(1, 0x00); + } } - } - //all writes, even to MMIO registers, appear on bus - ram_write(addr, data); + //0->1 transistion resets timers + 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: //DSPADDR + status.dsp_addr = data; + break; + + case 0xf3: //DSPDATA + if(status.dsp_addr & 0x80) break; //0x80-0xff are read-only mirrors of 0x00-0x7f + dsp.write(status.dsp_addr & 0x7f, data); + break; + + case 0xf4: //CPUIO0 + case 0xf5: //CPUIO1 + case 0xf6: //CPUIO2 + case 0xf7: //CPUIO3 + synchronize_cpu(); + port_write(addr, data); + break; + + case 0xf8: //RAM0 + status.ram00f8 = data; + break; + + case 0xf9: //RAM1 + status.ram00f9 = data; + break; + + case 0xfa: //T0TARGET + timer0.target = data; + break; + + case 0xfb: //T1TARGET + timer1.target = data; + break; + + case 0xfc: //T2TARGET + timer2.target = data; + break; + + case 0xfd: //T0OUT + case 0xfe: //T1OUT + case 0xff: //T2OUT -- read-only registers + break; + } } void SMP::op_io() { diff --git a/bsnes/snes/smp/timing/timing.cpp b/bsnes/snes/smp/timing/timing.cpp index a69a7f3f..40374d1c 100755 --- a/bsnes/snes/smp/timing/timing.cpp +++ b/bsnes/snes/smp/timing/timing.cpp @@ -25,7 +25,7 @@ void SMP::cycle_edge() { } template -void SMP::sSMPTimer::tick() { +void SMP::Timer::tick() { //stage 0 increment stage0_ticks += smp.status.timer_step; if(stage0_ticks < timer_frequency) return; @@ -33,11 +33,11 @@ void SMP::sSMPTimer::tick() { //stage 1 increment stage1_ticks ^= 1; - sync_stage1(); + synchronize_stage1(); } -template -void SMP::sSMPTimer::sync_stage1() { +template +void SMP::Timer::synchronize_stage1() { bool new_line = stage1_ticks; if(smp.status.timers_enable == false) new_line = false; if(smp.status.timers_disable == true) new_line = false; @@ -48,13 +48,11 @@ void SMP::sSMPTimer::sync_stage1() { //stage 2 increment if(enable == false) return; - stage2_ticks++; - if(stage2_ticks != target) return; + if(++stage2_ticks != target) return; //stage 3 increment stage2_ticks = 0; stage3_ticks++; - stage3_ticks &= 15; } #endif diff --git a/bsnes/snes/smp/timing/timing.hpp b/bsnes/snes/smp/timing/timing.hpp index c87d5095..2c282455 100755 --- a/bsnes/snes/smp/timing/timing.hpp +++ b/bsnes/snes/smp/timing/timing.hpp @@ -1,21 +1,21 @@ template -class sSMPTimer { +class Timer { public: uint8 stage0_ticks; uint8 stage1_ticks; uint8 stage2_ticks; - uint8 stage3_ticks; + uint4 stage3_ticks; bool current_line; bool enable; uint8 target; void tick(); - void sync_stage1(); + void synchronize_stage1(); }; -sSMPTimer<192> timer0; -sSMPTimer<192> timer1; -sSMPTimer< 24> timer2; +Timer<192> timer0; +Timer<192> timer1; +Timer< 24> timer2; alwaysinline void add_clocks(unsigned clocks); alwaysinline void cycle_edge(); diff --git a/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp index c5e0f41d..0cafa6c0 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.03"; + static const char Version[] = "078.04"; static const unsigned SerializerVersion = 20; } } diff --git a/bsnes/ui/general/file-browser.cpp b/bsnes/ui/general/file-browser.cpp index 6482cf1f..045e1dd1 100755 --- a/bsnes/ui/general/file-browser.cpp +++ b/bsnes/ui/general/file-browser.cpp @@ -6,10 +6,12 @@ void FileBrowser::create() { browseButton.setText("..."); upButton.setText(".."); + const unsigned sq = browseButton.minimumGeometry().height; + layout.setMargin(5); pathLayout.append(pathBox, ~0, 0, 5); - pathLayout.append(browseButton, 25, 25, 5); - pathLayout.append(upButton, 25, 25 ); + pathLayout.append(browseButton, sq, sq, 5); + pathLayout.append(upButton, sq, sq ); layout.append(pathLayout, 5); layout.append(contentsBox, ~0, ~0 ); append(layout); diff --git a/bsnes/ui/general/slot-loader.cpp b/bsnes/ui/general/slot-loader.cpp index db8174c5..93efc3f0 100755 --- a/bsnes/ui/general/slot-loader.cpp +++ b/bsnes/ui/general/slot-loader.cpp @@ -10,14 +10,16 @@ void SingleSlotLoader::create() { slotBrowse.setText("..."); okButton.setText("Ok"); + const unsigned sq = baseBrowse.minimumGeometry().height; + layout.setMargin(5); baseLayout.append(baseLabel, 40, 0, 5); baseLayout.append(basePath, ~0, 0, 5); - baseLayout.append(baseBrowse, 25, 25 ); + baseLayout.append(baseBrowse, sq, sq ); layout.append(baseLayout, 5); slotLayout.append(slotLabel, 40, 0, 5); slotLayout.append(slotPath, ~0, 0, 5); - slotLayout.append(slotBrowse, 25, 25 ); + slotLayout.append(slotBrowse, sq, sq ); layout.append(slotLayout, 5); controlLayout.append(spacer, ~0, 0 ); controlLayout.append(okButton, 80, 0 ); @@ -103,18 +105,20 @@ void DoubleSlotLoader::create() { slotBBrowse.setText("..."); okButton.setText("Ok"); + const unsigned sq = baseBrowse.minimumGeometry().height; + layout.setMargin(5); baseLayout.append(baseLabel, 40, 0, 5); baseLayout.append(basePath, ~0, 0, 5); - baseLayout.append(baseBrowse, 25, 25 ); + baseLayout.append(baseBrowse, sq, sq ); layout.append(baseLayout, 5); slotALayout.append(slotALabel, 40, 0, 5); slotALayout.append(slotAPath, ~0, 0, 5); - slotALayout.append(slotABrowse, 25, 25 ); + slotALayout.append(slotABrowse, sq, sq ); layout.append(slotALayout, 5); slotBLayout.append(slotBLabel, 40, 0, 5); slotBLayout.append(slotBPath, ~0, 0, 5); - slotBLayout.append(slotBBrowse, 25, 25 ); + slotBLayout.append(slotBBrowse, sq, sq ); layout.append(slotBLayout, 5); controlLayout.append(spacer, ~0, 0 ); controlLayout.append(okButton, 80, 0 );