mirror of https://github.com/bsnes-emu/bsnes.git
Update to v078r04 release.
byuu says: Changelog: - file and slot load dialogs should now have perfectly square buttons that are based on the platform's default button height. - cleaned up bsnes/Accuracy SMP source code (removed old !! stuff, stage 3 timer is now uint4, memory access switch/case cleaned up, sSMPTimer->Timer, etc.) - cleaned up bsnes/Accuracy memory access functions (read/writestack -> read/writesp, read/writeaddr -> read/write) - minor optimization to bsnes/Performance SMP core in cycle-mode
This commit is contained in:
parent
7ffaeb2ac1
commit
6694a1c986
|
@ -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]);
|
||||
|
|
|
@ -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);
|
Binary file not shown.
|
@ -1,4 +1,4 @@
|
|||
#define CYCLE_ACCURATE
|
||||
//#define CYCLE_ACCURATE
|
||||
|
||||
#include <snes/snes.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)
|
||||
|
|
|
@ -1,3 +1,16 @@
|
|||
template<unsigned cycle_frequency>
|
||||
void SMP::Timer<cycle_frequency>::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<unsigned cycle_frequency>
|
||||
void SMP::Timer<cycle_frequency>::tick(unsigned clocks) {
|
||||
stage1_ticks += clocks;
|
||||
|
@ -6,10 +19,8 @@ void SMP::Timer<cycle_frequency>::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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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<int op, int value> void SMPcore::op_setbit_dp() {
|
|||
template<int n> 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<int n> 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ template<int n, int i> void SMPcore::op_mov_reg_dpr() {
|
|||
template<int n> 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<int i> 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<int n, int i> void SMPcore::op_mov_dpr_reg() {
|
|||
template<int n> 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<int i> void SMPcore::op_mov_addrr_a() {
|
||||
|
@ -137,8 +137,8 @@ template<int i> 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
|
||||
|
|
|
@ -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<int n> 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;
|
||||
|
|
|
@ -32,7 +32,7 @@ template<uint8 (SMPcore::*op)(uint8, uint8), int n>
|
|||
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<int op> 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<int op> void SMPcore::op_or1_bit() {
|
||||
|
@ -146,7 +146,7 @@ template<int op> 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);
|
||||
}
|
||||
|
|
|
@ -27,20 +27,20 @@ template<uint8 (SMPcore::*op)(uint8)>
|
|||
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<int op>
|
||||
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<int adjust>
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -25,7 +25,7 @@ void SMP::cycle_edge() {
|
|||
}
|
||||
|
||||
template<unsigned timer_frequency>
|
||||
void SMP::sSMPTimer<timer_frequency>::tick() {
|
||||
void SMP::Timer<timer_frequency>::tick() {
|
||||
//stage 0 increment
|
||||
stage0_ticks += smp.status.timer_step;
|
||||
if(stage0_ticks < timer_frequency) return;
|
||||
|
@ -33,11 +33,11 @@ void SMP::sSMPTimer<timer_frequency>::tick() {
|
|||
|
||||
//stage 1 increment
|
||||
stage1_ticks ^= 1;
|
||||
sync_stage1();
|
||||
synchronize_stage1();
|
||||
}
|
||||
|
||||
template<unsigned frequency>
|
||||
void SMP::sSMPTimer<frequency>::sync_stage1() {
|
||||
template<unsigned timer_frequency>
|
||||
void SMP::Timer<timer_frequency>::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<frequency>::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
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
template<unsigned timer_frequency>
|
||||
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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in New Issue