diff --git a/bsnes.exe b/bsnes.exe new file mode 100644 index 00000000..8298aff1 Binary files /dev/null and b/bsnes.exe differ diff --git a/src/apu/apu.h b/src/apu/apu.h index 4071fe6d..177e2538 100644 --- a/src/apu/apu.h +++ b/src/apu/apu.h @@ -3,12 +3,11 @@ class APU { public: APURegs regs; +uint8 spcram[65536]; static const uint8 iplrom[64]; enum { - FLAG_N = 0x80, FLAG_V = 0x40, - FLAG_P = 0x20, FLAG_B = 0x10, - FLAG_H = 0x08, FLAG_I = 0x04, - FLAG_Z = 0x02, FLAG_C = 0x01 + FLAG_N = 0x80, FLAG_V = 0x40, FLAG_P = 0x20, FLAG_B = 0x10, + FLAG_H = 0x08, FLAG_I = 0x04, FLAG_Z = 0x02, FLAG_C = 0x01 }; virtual uint8 spcram_read (uint16 addr) = 0; @@ -17,9 +16,10 @@ static const uint8 iplrom[64]; virtual uint8 port_read (uint8 port) = 0; virtual void port_write(uint8 port, uint8 value) = 0; - virtual uint8 *get_spcram_handle() = 0; + virtual uint8 *get_spcram_handle() { return spcram; } + virtual void main() {} virtual void run() = 0; - virtual uint32 cycles_executed() = 0; + virtual uint32 clocks_executed() = 0; virtual void power() = 0; virtual void reset() = 0; @@ -28,6 +28,6 @@ static const uint8 iplrom[64]; void disassemble_opcode(char *output); inline uint16 __relb(int8 offset, int op_len); - APU() {} + APU() { memset(spcram, 0, 65536); } virtual ~APU() {} }; diff --git a/src/apu/apuregs.h b/src/apu/apuregs.h index 25d46793..95fec7dc 100644 --- a/src/apu/apuregs.h +++ b/src/apu/apuregs.h @@ -1,20 +1,18 @@ class APURegFlags { private: - template class bit { + template class bit { public: - uint8 _b; - inline operator bool() { return (_b & B); } - inline bool operator = (bool i) { (i) ? _b |= B : _b &= ~B; return (_b & B); } - inline bool operator & (bool i) { if(i)_b &= ~B; return (_b & B); } - inline bool operator &= (bool i) { if(i)_b &= ~B; return (_b & B); } - inline bool operator | (bool i) { if(i)_b |= B; return (_b & B); } - inline bool operator |= (bool i) { if(i)_b |= B; return (_b & B); } - inline bool operator ^ (bool i) { if(i)_b ^= B; return (_b & B); } - inline bool operator ^= (bool i) { if(i)_b ^= B; return (_b & B); } + uint data; + inline operator bool() { return bool(data & mask); } + inline bool operator = (const bool i) { (i) ? data |= mask : data &= ~mask; return bool(data & mask); } + inline bool operator |= (const bool i) { if(i)data |= mask; return bool(data & mask); } + inline bool operator ^= (const bool i) { if(i)data ^= mask; return bool(data & mask); } + inline bool operator &= (const bool i) { if(i)data &= mask; return bool(data & mask); } }; + public: union { - uint8 _b; + uint8 data; bit<0x80> n; bit<0x40> v; bit<0x20> p; @@ -25,12 +23,12 @@ union { bit<0x01> c; }; - APURegFlags() { _b = 0; } - inline operator uint8() { return _b; } - inline unsigned operator = (uint8 i) { _b = i; return _b; } - inline unsigned operator &= (uint8 i) { _b &= i; return _b; } - inline unsigned operator |= (uint8 i) { _b |= i; return _b; } - inline unsigned operator ^= (uint8 i) { _b ^= i; return _b; } + APURegFlags() { data = 0; } + inline operator unsigned() { return data; } + inline unsigned operator = (const uint8 i) { data = i; return data; } + inline unsigned operator |= (const uint8 i) { data |= i; return data; } + inline unsigned operator ^= (const uint8 i) { data ^= i; return data; } + inline unsigned operator &= (const uint8 i) { data &= i; return data; } }; class APURegs { @@ -38,11 +36,7 @@ public: uint16 pc; union { uint16 ya; -#ifdef ARCH_LSB - struct { uint8 a, y; }; -#else - struct { uint8 y, a; }; -#endif + struct { uint8 order_lsb2(a, y); }; }; uint8 x, sp; APURegFlags p; diff --git a/src/apu/bapu/bapu.cpp b/src/apu/bapu/bapu.cpp index 96b20185..f352e8f0 100644 --- a/src/apu/bapu/bapu.cpp +++ b/src/apu/bapu/bapu.cpp @@ -22,7 +22,7 @@ void bAPU::reset() { regs.p = 0x02; status.cycle_pos = 0; - status.cycles_executed = 0; + status.clocks_executed = 0; //$f1 status.iplrom_enabled = true; @@ -47,8 +47,6 @@ void bAPU::reset() { bAPU::bAPU() { init_op_table(); - spcram = (uint8*)malloc(65536); - t0.cycle_frequency = 128; //1.024mhz / 8khz = 128 t1.cycle_frequency = 128; //1.024mhz / 8khz = 128 t2.cycle_frequency = 16; //1.024mhz / 64khz = 16 @@ -59,6 +57,4 @@ bAPU::bAPU() { t2.target = 0; } -bAPU::~bAPU() { - if(spcram)free(spcram); -} +bAPU::~bAPU() {} diff --git a/src/apu/bapu/bapu.h b/src/apu/bapu/bapu.h index c5199c40..5941a7e0 100644 --- a/src/apu/bapu/bapu.h +++ b/src/apu/bapu/bapu.h @@ -6,7 +6,7 @@ public: struct { uint8 cycle_pos, opcode; - uint32 cycles_executed; + uint32 clocks_executed; //$f1 bool iplrom_enabled; diff --git a/src/apu/bapu/core/clean.bat b/src/apu/bapu/core/clean.bat index be7babec..d807f14d 100644 --- a/src/apu/bapu/core/clean.bat +++ b/src/apu/bapu/core/clean.bat @@ -1,8 +1 @@ @del *.exe -@del op.h -@del optable.cpp -@del op_mov.cpp -@del op_pc.cpp -@del op_read.cpp -@del op_rmw.cpp -@del op_misc.cpp diff --git a/src/apu/bapu/core/op_mov.b b/src/apu/bapu/core/op_mov.b index 43b1d58d..bbf12c75 100644 --- a/src/apu/bapu/core/op_mov.b +++ b/src/apu/bapu/core/op_mov.b @@ -2,13 +2,16 @@ mov_a_x(0x7d, a, x), mov_a_y(0xdd, a, y), mov_x_a(0x5d, x, a), mov_y_a(0xfd, y, a), -mov_x_sp(0x9d, x, sp), -mov_sp_x(0xbd, sp, x) { +mov_x_sp(0x9d, x, sp) { 1:regs.$1 = regs.$2; regs.p.n = !!(regs.$1 & 0x80); regs.p.z = (regs.$1 == 0); } +mov_sp_x(0xbd, sp, x) { +1:regs.$1 = regs.$2; +} + mov_a_const(0xe8, a), mov_x_const(0xcd, x), mov_y_const(0x8d, y) { diff --git a/src/apu/bapu/core/op_mov.cpp b/src/apu/bapu/core/op_mov.cpp index a95750b8..a344f50f 100644 --- a/src/apu/bapu/core/op_mov.cpp +++ b/src/apu/bapu/core/op_mov.cpp @@ -57,8 +57,6 @@ void bAPU::op_mov_sp_x() { switch(status.cycle_pos++) { case 1: { regs.sp = regs.x; - regs.p.n = !!(regs.sp & 0x80); - regs.p.z = (regs.sp == 0); status.cycle_pos = 0; } break; } diff --git a/src/apu/bapu/memory/memory.cpp b/src/apu/bapu/memory/memory.cpp index 7c1873ed..b901e0b9 100644 --- a/src/apu/bapu/memory/memory.cpp +++ b/src/apu/bapu/memory/memory.cpp @@ -189,11 +189,3 @@ void bAPU::stack_write(uint8 value) { spcram_write(0x0100 | regs.sp, value); regs.sp--; } - -uint8 *bAPU::get_spcram_handle() { - if(!spcram) { - alert("bAPU::get_spcram_handle() -- spcram uninitialized"); - } - - return spcram; -} diff --git a/src/apu/bapu/memory/memory.h b/src/apu/bapu/memory/memory.h index 576dc2a7..f99b04ee 100644 --- a/src/apu/bapu/memory/memory.h +++ b/src/apu/bapu/memory/memory.h @@ -1,12 +1,9 @@ enum { OPMODE_ADDR, OPMODE_DP }; -uint8 *spcram; inline uint8 spcram_read (uint16 addr); inline void spcram_write(uint16 addr, uint8 value); inline uint8 port_read (uint8 port); inline void port_write(uint8 port, uint8 value); - inline uint8 *get_spcram_handle(); - inline uint8 op_read(); inline uint8 op_read (uint8 mode, uint16 addr); inline void op_write(uint8 mode, uint16 addr, uint8 value); diff --git a/src/apu/bapu/timing/timing.cpp b/src/apu/bapu/timing/timing.cpp index 97b5be55..b1dccc34 100644 --- a/src/apu/bapu/timing/timing.cpp +++ b/src/apu/bapu/timing/timing.cpp @@ -1,14 +1,14 @@ void bAPU::add_cycles(int cycles) { - status.cycles_executed += cycles; + status.clocks_executed += cycles; t0.add_cycles(cycles); t1.add_cycles(cycles); t2.add_cycles(cycles); } -uint32 bAPU::cycles_executed() { -uint32 r = status.cycles_executed; - status.cycles_executed = 0; +uint32 bAPU::clocks_executed() { +uint32 r = status.clocks_executed; + status.clocks_executed = 0; return (r << 4) + (r << 3); } diff --git a/src/apu/bapu/timing/timing.h b/src/apu/bapu/timing/timing.h index 03d0fa3a..f39ea5a2 100644 --- a/src/apu/bapu/timing/timing.h +++ b/src/apu/bapu/timing/timing.h @@ -6,4 +6,4 @@ bool enabled; inline void add_cycles(int cycles); } t0, t1, t2; inline void add_cycles(int cycles); - inline uint32 cycles_executed(); + inline uint32 clocks_executed(); diff --git a/src/apu/sapu/core/cc.bat b/src/apu/sapu/core/cc.bat new file mode 100644 index 00000000..e9482ab9 --- /dev/null +++ b/src/apu/sapu/core/cc.bat @@ -0,0 +1,3 @@ +cl /O2 /wd4996 sapugen.cpp +@pause +@del *.obj \ No newline at end of file diff --git a/src/apu/sapu/core/clean.bat b/src/apu/sapu/core/clean.bat new file mode 100644 index 00000000..d807f14d --- /dev/null +++ b/src/apu/sapu/core/clean.bat @@ -0,0 +1 @@ +@del *.exe diff --git a/src/apu/sapu/core/core.cpp b/src/apu/sapu/core/core.cpp new file mode 100644 index 00000000..8ab44f1b --- /dev/null +++ b/src/apu/sapu/core/core.cpp @@ -0,0 +1,27 @@ +#include "opfn.cpp" +//#include "op_mov.cpp" +//#include "op_pc.cpp" +//#include "op_read.cpp" +//#include "op_rmw.cpp" +//#include "op_misc.cpp" + +void sAPU::main() { + for(;;) { + status.in_opcode = true; + +// (this->*optbl[op_readpc()])(); + switch(op_readpc()) { + #include "op_mov.cpp" + #include "op_pc.cpp" + #include "op_read.cpp" + #include "op_rmw.cpp" + #include "op_misc.cpp" + } + + status.in_opcode = false; + + #ifdef FAVOR_SPEED + co_return(); + #endif + } +} diff --git a/src/apu/sapu/core/core.h b/src/apu/sapu/core/core.h new file mode 100644 index 00000000..51918136 --- /dev/null +++ b/src/apu/sapu/core/core.h @@ -0,0 +1,24 @@ +//void (sAPU::*optbl[256])(); + +uint16 dp, sp, rd, wr, bit, ya; + bool in_opcode() { return status.in_opcode; } + + 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); + uint16 op_incw(uint16 x); + uint8 op_dec (uint8 x); + uint16 op_decw(uint16 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); + +//#include "op.h" diff --git a/src/apu/sapu/core/op_misc.b b/src/apu/sapu/core/op_misc.b new file mode 100644 index 00000000..500a380f --- /dev/null +++ b/src/apu/sapu/core/op_misc.b @@ -0,0 +1,175 @@ +nop(0x00) { +1:op_io(); +} + +sleep(0xef), +stop(0xff) { +1:op_io(); +2:op_io(); + regs.pc--; +} + +xcn(0x9f) { +1:op_io(); +2:op_io(); +3:op_io(); +4:op_io(); + regs.a = (regs.a >> 4) | (regs.a << 4); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +daa(0xdf) { +1:op_io(); +2:op_io(); + if(regs.p.c || (regs.a) > 0x99) { + regs.a += 0x60; + regs.p.c = 1; + } + if(regs.p.h || (regs.a & 15) > 0x09) { + regs.a += 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +das(0xbe) { +1:op_io(); +2:op_io(); + if(!regs.p.c || (regs.a) > 0x99) { + regs.a -= 0x60; + regs.p.c = 0; + } + if(!regs.p.h || (regs.a & 15) > 0x09) { + regs.a -= 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +clrc(0x60, regs.p.c = 0), +clrp(0x20, regs.p.p = 0), +setc(0x80, regs.p.c = 1), +setp(0x40, regs.p.p = 1) { +1:op_io(); + $1; +} + +clrv(0xe0) { +1:op_io(); + regs.p.v = 0; + regs.p.h = 0; +} + +notc(0xed) { +1:op_io(); +2:op_io(); + regs.p.c ^= 1; +} + +ei(0xa0, 1), +di(0xc0, 0) { +1:op_io(); +2:op_io(); + regs.p.i = $1; +} + +set0_dp(0x02, rd |= 0x01), +clr0_dp(0x12, rd &= ~0x01), +set1_dp(0x22, rd |= 0x02), +clr1_dp(0x32, rd &= ~0x02), +set2_dp(0x42, rd |= 0x04), +clr2_dp(0x52, rd &= ~0x04), +set3_dp(0x62, rd |= 0x08), +clr3_dp(0x72, rd &= ~0x08), +set4_dp(0x82, rd |= 0x10), +clr4_dp(0x92, rd &= ~0x10), +set5_dp(0xa2, rd |= 0x20), +clr5_dp(0xb2, rd &= ~0x20), +set6_dp(0xc2, rd |= 0x40), +clr6_dp(0xd2, rd &= ~0x40), +set7_dp(0xe2, rd |= 0x80), +clr7_dp(0xf2, rd &= ~0x80) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); +3:$1; + op_writedp(dp, rd); +} + +tset_addr_a(0x0e, |=), +tclr_addr_a(0x4e, &=~) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:rd = op_readaddr(dp); +4:op_io(); + regs.p.n = !!((rd & regs.a) & 0x80); + regs.p.z = ((rd & regs.a) == 0); + rd $1 regs.a; +5:op_writeaddr(dp, rd); +} + +push_a(0x2d, a), +push_x(0x4d, x), +push_y(0x6d, y), +push_p(0x0d, p) { +1:op_io(); +2:op_io(); +3:op_writestack(regs.$1); +} + +pop_a(0xae, a), +pop_x(0xce, x), +pop_y(0xee, y), +pop_p(0x8e, p) { +1:op_io(); +2:op_io(); +3:regs.$1 = op_readstack(); +} + +mul_ya(0xcf) { +1:op_io(); +2:op_io(); +3:op_io(); +4:op_io(); +5:op_io(); +6:op_io(); +7:op_io(); +8:op_io(); + ya = regs.y * regs.a; + regs.a = ya; + regs.y = ya >> 8; +//result is set based on y (high-byte) only + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); +} + +div_ya_x(0x9e) { +1:op_io(); +2:op_io(); +3:op_io(); +4:op_io(); +5:op_io(); +6:op_io(); +7:op_io(); +8:op_io(); +9:op_io(); +10:op_io(); +11: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)); + if(regs.y < (regs.x << 1)) { + //if quotient is <= 511 (will fit into 9-bit result) + regs.a = ya / regs.x; + regs.y = ya % regs.x; + } else { + //otherwise, the quotient won't fit into regs.p.v + regs.a + //this emulates the odd behavior of the SPC700 in this case + regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.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.z = (regs.a == 0); +} diff --git a/src/apu/sapu/core/op_misc.cpp b/src/apu/sapu/core/op_misc.cpp new file mode 100644 index 00000000..f2538f09 --- /dev/null +++ b/src/apu/sapu/core/op_misc.cpp @@ -0,0 +1,370 @@ +//nop +case 0x00: { + op_io(); +} break; + +//sleep +case 0xef: { + op_io(); + op_io(); + regs.pc--; +} break; + +//stop +case 0xff: { + op_io(); + op_io(); + regs.pc--; +} break; + +//xcn +case 0x9f: { + op_io(); + op_io(); + op_io(); + op_io(); + regs.a = (regs.a >> 4) | (regs.a << 4); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} break; + +//daa +case 0xdf: { + op_io(); + op_io(); + if(regs.p.c || (regs.a) > 0x99) { + regs.a += 0x60; + regs.p.c = 1; + } + if(regs.p.h || (regs.a & 15) > 0x09) { + regs.a += 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} break; + +//das +case 0xbe: { + op_io(); + op_io(); + if(!regs.p.c || (regs.a) > 0x99) { + regs.a -= 0x60; + regs.p.c = 0; + } + if(!regs.p.h || (regs.a & 15) > 0x09) { + regs.a -= 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} break; + +//clrc +case 0x60: { + op_io(); + regs.p.c = 0; +} break; + +//clrp +case 0x20: { + op_io(); + regs.p.p = 0; +} break; + +//setc +case 0x80: { + op_io(); + regs.p.c = 1; +} break; + +//setp +case 0x40: { + op_io(); + regs.p.p = 1; +} break; + +//clrv +case 0xe0: { + op_io(); + regs.p.v = 0; + regs.p.h = 0; +} break; + +//notc +case 0xed: { + op_io(); + op_io(); + regs.p.c ^= 1; +} break; + +//ei +case 0xa0: { + op_io(); + op_io(); + regs.p.i = 1; +} break; + +//di +case 0xc0: { + op_io(); + op_io(); + regs.p.i = 0; +} break; + +//set0_dp +case 0x02: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x01; + op_writedp(dp, rd); +} break; + +//clr0_dp +case 0x12: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x01; + op_writedp(dp, rd); +} break; + +//set1_dp +case 0x22: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x02; + op_writedp(dp, rd); +} break; + +//clr1_dp +case 0x32: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x02; + op_writedp(dp, rd); +} break; + +//set2_dp +case 0x42: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x04; + op_writedp(dp, rd); +} break; + +//clr2_dp +case 0x52: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x04; + op_writedp(dp, rd); +} break; + +//set3_dp +case 0x62: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x08; + op_writedp(dp, rd); +} break; + +//clr3_dp +case 0x72: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x08; + op_writedp(dp, rd); +} break; + +//set4_dp +case 0x82: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x10; + op_writedp(dp, rd); +} break; + +//clr4_dp +case 0x92: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x10; + op_writedp(dp, rd); +} break; + +//set5_dp +case 0xa2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x20; + op_writedp(dp, rd); +} break; + +//clr5_dp +case 0xb2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x20; + op_writedp(dp, rd); +} break; + +//set6_dp +case 0xc2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x40; + op_writedp(dp, rd); +} break; + +//clr6_dp +case 0xd2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x40; + op_writedp(dp, rd); +} break; + +//set7_dp +case 0xe2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x80; + op_writedp(dp, rd); +} break; + +//clr7_dp +case 0xf2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x80; + op_writedp(dp, rd); +} break; + +//tset_addr_a +case 0x0e: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + op_io(); + regs.p.n = !!((rd & regs.a) & 0x80); + regs.p.z = ((rd & regs.a) == 0); + rd |= regs.a; + op_writeaddr(dp, rd); +} break; + +//tclr_addr_a +case 0x4e: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + op_io(); + regs.p.n = !!((rd & regs.a) & 0x80); + regs.p.z = ((rd & regs.a) == 0); + rd &=~ regs.a; + op_writeaddr(dp, rd); +} break; + +//push_a +case 0x2d: { + op_io(); + op_io(); + op_writestack(regs.a); +} break; + +//push_x +case 0x4d: { + op_io(); + op_io(); + op_writestack(regs.x); +} break; + +//push_y +case 0x6d: { + op_io(); + op_io(); + op_writestack(regs.y); +} break; + +//push_p +case 0x0d: { + op_io(); + op_io(); + op_writestack(regs.p); +} break; + +//pop_a +case 0xae: { + op_io(); + op_io(); + regs.a = op_readstack(); +} break; + +//pop_x +case 0xce: { + op_io(); + op_io(); + regs.x = op_readstack(); +} break; + +//pop_y +case 0xee: { + op_io(); + op_io(); + regs.y = op_readstack(); +} break; + +//pop_p +case 0x8e: { + op_io(); + op_io(); + regs.p = op_readstack(); +} break; + +//mul_ya +case 0xcf: { + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + ya = regs.y * regs.a; + regs.a = ya; + regs.y = ya >> 8; +//result is set based on y (high-byte) only + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); +} break; + +//div_ya_x +case 0x9e: { + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + ya = regs.ya; +//overflow set if quotient >= 256 + 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; + regs.y = ya % regs.x; + } else { + //otherwise, the quotient won't fit into regs.p.v + regs.a + //this emulates the odd behavior of the SPC700 in this case + regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.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.z = (regs.a == 0); +} break; + diff --git a/src/apu/sapu/core/op_mov.b b/src/apu/sapu/core/op_mov.b new file mode 100644 index 00000000..19fda37a --- /dev/null +++ b/src/apu/sapu/core/op_mov.b @@ -0,0 +1,212 @@ +mov_a_x(0x7d, a, x), +mov_a_y(0xdd, a, y), +mov_x_a(0x5d, x, a), +mov_y_a(0xfd, y, a), +mov_x_sp(0x9d, x, sp) { +1:op_io(); + regs.$1 = regs.$2; + regs.p.n = !!(regs.$1 & 0x80); + regs.p.z = (regs.$1 == 0); +} + +mov_sp_x(0xbd, sp, x) { +1:op_io(); + regs.$1 = regs.$2; +} + +mov_a_const(0xe8, a), +mov_x_const(0xcd, x), +mov_y_const(0x8d, y) { +1:regs.$1 = op_readpc(); + regs.p.n = !!(regs.$1 & 0x80); + regs.p.z = (regs.$1 == 0); +} + +mov_a_ix(0xe6) { +1:op_io(); +2:regs.a = op_readdp(regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +mov_a_ixinc(0xbf) { +1:op_io(); +2:op_io(); +3:regs.a = op_readdp(regs.x++); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +mov_a_dp(0xe4, a), +mov_x_dp(0xf8, x), +mov_y_dp(0xeb, y) { +1:sp = op_readpc(); +2:regs.$1 = op_readdp(sp); + regs.p.n = !!(regs.$1 & 0x80); + regs.p.z = (regs.$1 == 0); +} + +mov_a_dpx(0xf4, a, x), +mov_x_dpy(0xf9, x, y), +mov_y_dpx(0xfb, y, x) { +1:sp = op_readpc(); +2:op_io(); +3:regs.$1 = op_readdp(sp + regs.$2); + regs.p.n = !!(regs.$1 & 0x80); + regs.p.z = (regs.$1 == 0); +} + +mov_a_addr(0xe5, a), +mov_x_addr(0xe9, x), +mov_y_addr(0xec, y) { +1:sp = op_readpc(); +2:sp |= op_readpc() << 8; +3:regs.$1 = op_readaddr(sp); + regs.p.n = !!(regs.$1 & 0x80); + regs.p.z = (regs.$1 == 0); +} + +mov_a_addrx(0xf5, x), +mov_a_addry(0xf6, y) { +1:sp = op_readpc(); +2:sp |= op_readpc() << 8; +3:op_io(); +4:regs.a = op_readaddr(sp + regs.$1); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +mov_a_idpx(0xe7) { +1:dp = op_readpc() + regs.x; +2:op_io(); +3:sp = op_readdp(dp); +4:sp |= op_readdp(dp + 1) << 8; +5:regs.a = op_readaddr(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +mov_a_idpy(0xf7) { +1:dp = op_readpc(); +2:op_io(); +3:sp = op_readdp(dp); +4:sp |= op_readdp(dp + 1) << 8; +5:regs.a = op_readaddr(sp + regs.y); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +mov_dp_dp(0xfa) { +1:sp = op_readpc(); +2:dp = op_readpc(); +3:rd = op_readdp(sp); +4:op_writedp(dp, rd); +} + +mov_dp_const(0x8f) { +1:rd = op_readpc(); +2:dp = op_readpc(); +3:op_io(); +4:op_writedp(dp, rd); +} + +mov_ix_a(0xc6) { +1:op_io(); +2:op_io(); +3:op_writedp(regs.x, regs.a); +} + +mov_ixinc_a(0xaf) { +1:op_io(); +2:op_io(); +3:op_writedp(regs.x++, regs.a); +} + +mov_dp_a(0xc4, a), +mov_dp_x(0xd8, x), +mov_dp_y(0xcb, y) { +1:dp = op_readpc(); +2:op_io(); +3:op_writedp(dp, regs.$1); +} + +mov_dpx_a(0xd4, x, a), +mov_dpy_x(0xd9, y, x), +mov_dpx_y(0xdb, x, y) { +1:dp = op_readpc(); +2:op_io(); +3:op_io(); +4:op_writedp(dp + regs.$1, regs.$2); +} + +mov_addr_a(0xc5, a), +mov_addr_x(0xc9, x), +mov_addr_y(0xcc, y) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:op_io(); +4:op_writeaddr(dp, regs.$1); +} + +mov_addrx_a(0xd5, x), +mov_addry_a(0xd6, y) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:op_io(); +4:op_io(); +5:op_writeaddr(dp + regs.$1, regs.a); +} + +mov_idpx_a(0xc7) { +1:sp = op_readpc() + regs.x; +2:op_io(); +3:dp = op_readdp(sp); +4:dp |= op_readdp(sp + 1) << 8; +5:op_io(); +6:op_writeaddr(dp, regs.a); +} + +mov_idpy_a(0xd7) { +1:sp = op_readpc(); +2:op_io(); +3:dp = op_readdp(sp); +4:dp |= op_readdp(sp + 1) << 8; +5:op_io(); +6:op_writeaddr(dp + regs.y, regs.a); +} + +movw_ya_dp(0xba) { +1:sp = op_readpc(); +2:op_io(); +3:regs.a = op_readdp(sp); +4:regs.y = op_readdp(sp + 1); + regs.p.n = !!(regs.ya & 0x8000); + regs.p.z = (regs.ya == 0); +} + +movw_dp_ya(0xda) { +1:dp = op_readpc(); +2:op_io(); +3:op_writedp(dp, regs.a); +4:op_writedp(dp + 1, regs.y); +} + +mov1_c_bit(0xaa) { +1:sp = op_readpc(); +2:sp |= op_readpc() << 8; +3:bit = sp >> 13; + sp &= 0x1fff; + rd = op_readaddr(sp); + regs.p.c = !!(rd & (1 << bit)); +} + +mov1_bit_c(0xca) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + if(regs.p.c)rd |= (1 << bit); + else rd &= ~(1 << bit); +4:op_writeaddr(dp, rd); +} diff --git a/src/apu/sapu/core/op_mov.cpp b/src/apu/sapu/core/op_mov.cpp new file mode 100644 index 00000000..45a4165b --- /dev/null +++ b/src/apu/sapu/core/op_mov.cpp @@ -0,0 +1,381 @@ +//mov_a_x +case 0x7d: { + op_io(); + regs.a = regs.x; + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} break; + +//mov_a_y +case 0xdd: { + op_io(); + regs.a = regs.y; + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} break; + +//mov_x_a +case 0x5d: { + op_io(); + regs.x = regs.a; + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); +} break; + +//mov_y_a +case 0xfd: { + op_io(); + regs.y = regs.a; + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); +} break; + +//mov_x_sp +case 0x9d: { + op_io(); + regs.x = regs.sp; + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); +} break; + +//mov_sp_x +case 0xbd: { + op_io(); + regs.sp = regs.x; +} break; + +//mov_a_const +case 0xe8: { + regs.a = op_readpc(); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} break; + +//mov_x_const +case 0xcd: { + regs.x = op_readpc(); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); +} break; + +//mov_y_const +case 0x8d: { + regs.y = op_readpc(); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); +} break; + +//mov_a_ix +case 0xe6: { + op_io(); + regs.a = op_readdp(regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} break; + +//mov_a_ixinc +case 0xbf: { + op_io(); + op_io(); + regs.a = op_readdp(regs.x++); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} break; + +//mov_a_dp +case 0xe4: { + sp = op_readpc(); + regs.a = op_readdp(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} break; + +//mov_x_dp +case 0xf8: { + sp = op_readpc(); + regs.x = op_readdp(sp); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); +} break; + +//mov_y_dp +case 0xeb: { + sp = op_readpc(); + regs.y = op_readdp(sp); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); +} break; + +//mov_a_dpx +case 0xf4: { + sp = op_readpc(); + op_io(); + regs.a = op_readdp(sp + regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} break; + +//mov_x_dpy +case 0xf9: { + sp = op_readpc(); + op_io(); + regs.x = op_readdp(sp + regs.y); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); +} break; + +//mov_y_dpx +case 0xfb: { + sp = op_readpc(); + op_io(); + regs.y = op_readdp(sp + regs.x); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); +} break; + +//mov_a_addr +case 0xe5: { + sp = op_readpc(); + sp |= op_readpc() << 8; + regs.a = op_readaddr(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} break; + +//mov_x_addr +case 0xe9: { + sp = op_readpc(); + sp |= op_readpc() << 8; + regs.x = op_readaddr(sp); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); +} break; + +//mov_y_addr +case 0xec: { + sp = op_readpc(); + sp |= op_readpc() << 8; + regs.y = op_readaddr(sp); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); +} break; + +//mov_a_addrx +case 0xf5: { + sp = op_readpc(); + sp |= op_readpc() << 8; + op_io(); + regs.a = op_readaddr(sp + regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} break; + +//mov_a_addry +case 0xf6: { + sp = op_readpc(); + sp |= op_readpc() << 8; + op_io(); + regs.a = op_readaddr(sp + regs.y); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} break; + +//mov_a_idpx +case 0xe7: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + regs.a = op_readaddr(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} break; + +//mov_a_idpy +case 0xf7: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + regs.a = op_readaddr(sp + regs.y); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} break; + +//mov_dp_dp +case 0xfa: { + sp = op_readpc(); + dp = op_readpc(); + rd = op_readdp(sp); + op_writedp(dp, rd); +} break; + +//mov_dp_const +case 0x8f: { + rd = op_readpc(); + dp = op_readpc(); + op_io(); + op_writedp(dp, rd); +} break; + +//mov_ix_a +case 0xc6: { + op_io(); + op_io(); + op_writedp(regs.x, regs.a); +} break; + +//mov_ixinc_a +case 0xaf: { + op_io(); + op_io(); + op_writedp(regs.x++, regs.a); +} break; + +//mov_dp_a +case 0xc4: { + dp = op_readpc(); + op_io(); + op_writedp(dp, regs.a); +} break; + +//mov_dp_x +case 0xd8: { + dp = op_readpc(); + op_io(); + op_writedp(dp, regs.x); +} break; + +//mov_dp_y +case 0xcb: { + dp = op_readpc(); + op_io(); + op_writedp(dp, regs.y); +} break; + +//mov_dpx_a +case 0xd4: { + dp = op_readpc(); + op_io(); + op_io(); + op_writedp(dp + regs.x, regs.a); +} break; + +//mov_dpy_x +case 0xd9: { + dp = op_readpc(); + op_io(); + op_io(); + op_writedp(dp + regs.y, regs.x); +} break; + +//mov_dpx_y +case 0xdb: { + dp = op_readpc(); + op_io(); + op_io(); + op_writedp(dp + regs.x, regs.y); +} break; + +//mov_addr_a +case 0xc5: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + op_writeaddr(dp, regs.a); +} break; + +//mov_addr_x +case 0xc9: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + op_writeaddr(dp, regs.x); +} break; + +//mov_addr_y +case 0xcc: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + op_writeaddr(dp, regs.y); +} break; + +//mov_addrx_a +case 0xd5: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + op_io(); + op_writeaddr(dp + regs.x, regs.a); +} break; + +//mov_addry_a +case 0xd6: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + op_io(); + op_writeaddr(dp + regs.y, regs.a); +} break; + +//mov_idpx_a +case 0xc7: { + sp = op_readpc() + regs.x; + op_io(); + dp = op_readdp(sp); + dp |= op_readdp(sp + 1) << 8; + op_io(); + op_writeaddr(dp, regs.a); +} break; + +//mov_idpy_a +case 0xd7: { + sp = op_readpc(); + op_io(); + dp = op_readdp(sp); + dp |= op_readdp(sp + 1) << 8; + op_io(); + op_writeaddr(dp + regs.y, regs.a); +} break; + +//movw_ya_dp +case 0xba: { + sp = op_readpc(); + op_io(); + regs.a = op_readdp(sp); + regs.y = op_readdp(sp + 1); + regs.p.n = !!(regs.ya & 0x8000); + regs.p.z = (regs.ya == 0); +} break; + +//movw_dp_ya +case 0xda: { + dp = op_readpc(); + op_io(); + op_writedp(dp, regs.a); + op_writedp(dp + 1, regs.y); +} break; + +//mov1_c_bit +case 0xaa: { + sp = op_readpc(); + sp |= op_readpc() << 8; + bit = sp >> 13; + sp &= 0x1fff; + rd = op_readaddr(sp); + regs.p.c = !!(rd & (1 << bit)); +} break; + +//mov1_bit_c +case 0xca: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + if(regs.p.c)rd |= (1 << bit); + else rd &= ~(1 << bit); + op_writeaddr(dp, rd); +} break; + diff --git a/src/apu/sapu/core/op_pc.b b/src/apu/sapu/core/op_pc.b new file mode 100644 index 00000000..49cf41ab --- /dev/null +++ b/src/apu/sapu/core/op_pc.b @@ -0,0 +1,180 @@ +bra(0x2f, 0), +beq(0xf0, !regs.p.z), +bne(0xd0, regs.p.z), +bcs(0xb0, !regs.p.c), +bcc(0x90, regs.p.c), +bvs(0x70, !regs.p.v), +bvc(0x50, regs.p.v), +bmi(0x30, !regs.p.n), +bpl(0x10, regs.p.n) { +1:rd = op_readpc(); + if($1)end; +2:op_io(); +3:op_io(); + regs.pc += (int8)rd; +} + +bbs0(0x03, 0x01, !=), +bbc0(0x13, 0x01, ==), +bbs1(0x23, 0x02, !=), +bbc1(0x33, 0x02, ==), +bbs2(0x43, 0x04, !=), +bbc2(0x53, 0x04, ==), +bbs3(0x63, 0x08, !=), +bbc3(0x73, 0x08, ==), +bbs4(0x83, 0x10, !=), +bbc4(0x93, 0x10, ==), +bbs5(0xa3, 0x20, !=), +bbc5(0xb3, 0x20, ==), +bbs6(0xc3, 0x40, !=), +bbc6(0xd3, 0x40, ==), +bbs7(0xe3, 0x80, !=), +bbc7(0xf3, 0x80, ==) { +1:dp = op_readpc(); +2:rd = op_readpc(); +3:sp = op_readdp(dp); +4:op_io(); + if((sp & $1) $2 $1)end; +5:op_io(); +6:op_io(); + regs.pc += (int8)rd; +} + +cbne_dp(0x2e) { +1:dp = op_readpc(); +2:rd = op_readpc(); +3:sp = op_readdp(dp); +4:op_io(); + if(regs.a == sp)end; +5:op_io(); +6:op_io(); + regs.pc += (int8)rd; +} + +cbne_dpx(0xde) { +1:dp = op_readpc(); +2:rd = op_readpc(); +3:op_io(); +4:sp = op_readdp(dp + regs.x); +5:op_io(); + if(regs.a == sp)end; +6:op_io(); +7:op_io(); + regs.pc += (int8)rd; +} + +dbnz_dp(0x6e) { +1:dp = op_readpc(); +2:rd = op_readpc(); +3:wr = op_readdp(dp); + wr--; +4:op_writedp(dp, wr); + if(wr == 0x00)end; +5:op_io(); +6:op_io(); + regs.pc += (int8)rd; +} + +dbnz_y(0xfe) { +1:rd = op_readpc(); +2:op_io(); + regs.y--; +3:op_io(); + if(regs.y == 0x00)end; +4:op_io(); +5:op_io(); + regs.pc += (int8)rd; +} + +jmp_addr(0x5f) { +1:rd = op_readpc(); +2:rd |= op_readpc() << 8; + regs.pc = rd; +} + +jmp_iaddrx(0x1f) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:op_io(); + dp += regs.x; +4:rd = op_readaddr(dp); +5:rd |= op_readaddr(dp + 1) << 8; + regs.pc = rd; +} + +call(0x3f) { +1:rd = op_readpc(); +2:rd |= op_readpc() << 8; +3:op_io(); +4:op_io(); +5:op_io(); +6:op_writestack(regs.pc >> 8); +7:op_writestack(regs.pc); + regs.pc = rd; +} + +pcall(0x4f) { +1:rd = op_readpc(); +2:op_io(); +3:op_io(); +4:op_writestack(regs.pc >> 8); +5:op_writestack(regs.pc); + regs.pc = 0xff00 | rd; +} + +tcall_0(0x01, 0), +tcall_1(0x11, 1), +tcall_2(0x21, 2), +tcall_3(0x31, 3), +tcall_4(0x41, 4), +tcall_5(0x51, 5), +tcall_6(0x61, 6), +tcall_7(0x71, 7), +tcall_8(0x81, 8), +tcall_9(0x91, 9), +tcall_10(0xa1, 10), +tcall_11(0xb1, 11), +tcall_12(0xc1, 12), +tcall_13(0xd1, 13), +tcall_14(0xe1, 14), +tcall_15(0xf1, 15) { +1:dp = 0xffde - ($1 << 1); + rd = op_readaddr(dp); +2:rd |= op_readaddr(dp + 1) << 8; +3:op_io(); +4:op_io(); +5:op_io(); +6:op_writestack(regs.pc >> 8); +7:op_writestack(regs.pc); + regs.pc = rd; +} + +brk(0x0f) { +1:rd = op_readaddr(0xffde); +2:rd |= op_readaddr(0xffdf) << 8; +3:op_io(); +4:op_io(); +5:op_writestack(regs.pc >> 8); +6:op_writestack(regs.pc); +7:op_writestack(regs.p); + regs.pc = rd; + regs.p.b = 1; + regs.p.i = 0; +} + +ret(0x6f) { +1:rd = op_readstack(); +2:rd |= op_readstack() << 8; +3:op_io(); +4:op_io(); + regs.pc = rd; +} + +reti(0x7f) { +1:regs.p = op_readstack(); +2:rd = op_readstack(); +3:rd |= op_readstack() << 8; +4:op_io(); +5:op_io(); + regs.pc = rd; +} diff --git a/src/apu/sapu/core/op_pc.cpp b/src/apu/sapu/core/op_pc.cpp new file mode 100644 index 00000000..e5bb27db --- /dev/null +++ b/src/apu/sapu/core/op_pc.cpp @@ -0,0 +1,604 @@ +//bra +case 0x2f: { + rd = op_readpc(); + if(0)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//beq +case 0xf0: { + rd = op_readpc(); + if(!regs.p.z)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bne +case 0xd0: { + rd = op_readpc(); + if(regs.p.z)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bcs +case 0xb0: { + rd = op_readpc(); + if(!regs.p.c)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bcc +case 0x90: { + rd = op_readpc(); + if(regs.p.c)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bvs +case 0x70: { + rd = op_readpc(); + if(!regs.p.v)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bvc +case 0x50: { + rd = op_readpc(); + if(regs.p.v)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bmi +case 0x30: { + rd = op_readpc(); + if(!regs.p.n)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bpl +case 0x10: { + rd = op_readpc(); + if(regs.p.n)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bbs0 +case 0x03: { + dp = op_readpc(); + rd = op_readpc(); + sp = op_readdp(dp); + op_io(); + if((sp & 0x01) != 0x01)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bbc0 +case 0x13: { + dp = op_readpc(); + rd = op_readpc(); + sp = op_readdp(dp); + op_io(); + if((sp & 0x01) == 0x01)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bbs1 +case 0x23: { + dp = op_readpc(); + rd = op_readpc(); + sp = op_readdp(dp); + op_io(); + if((sp & 0x02) != 0x02)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bbc1 +case 0x33: { + dp = op_readpc(); + rd = op_readpc(); + sp = op_readdp(dp); + op_io(); + if((sp & 0x02) == 0x02)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bbs2 +case 0x43: { + dp = op_readpc(); + rd = op_readpc(); + sp = op_readdp(dp); + op_io(); + if((sp & 0x04) != 0x04)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bbc2 +case 0x53: { + dp = op_readpc(); + rd = op_readpc(); + sp = op_readdp(dp); + op_io(); + if((sp & 0x04) == 0x04)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bbs3 +case 0x63: { + dp = op_readpc(); + rd = op_readpc(); + sp = op_readdp(dp); + op_io(); + if((sp & 0x08) != 0x08)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bbc3 +case 0x73: { + dp = op_readpc(); + rd = op_readpc(); + sp = op_readdp(dp); + op_io(); + if((sp & 0x08) == 0x08)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bbs4 +case 0x83: { + dp = op_readpc(); + rd = op_readpc(); + sp = op_readdp(dp); + op_io(); + if((sp & 0x10) != 0x10)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bbc4 +case 0x93: { + dp = op_readpc(); + rd = op_readpc(); + sp = op_readdp(dp); + op_io(); + if((sp & 0x10) == 0x10)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bbs5 +case 0xa3: { + dp = op_readpc(); + rd = op_readpc(); + sp = op_readdp(dp); + op_io(); + if((sp & 0x20) != 0x20)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bbc5 +case 0xb3: { + dp = op_readpc(); + rd = op_readpc(); + sp = op_readdp(dp); + op_io(); + if((sp & 0x20) == 0x20)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bbs6 +case 0xc3: { + dp = op_readpc(); + rd = op_readpc(); + sp = op_readdp(dp); + op_io(); + if((sp & 0x40) != 0x40)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bbc6 +case 0xd3: { + dp = op_readpc(); + rd = op_readpc(); + sp = op_readdp(dp); + op_io(); + if((sp & 0x40) == 0x40)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bbs7 +case 0xe3: { + dp = op_readpc(); + rd = op_readpc(); + sp = op_readdp(dp); + op_io(); + if((sp & 0x80) != 0x80)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//bbc7 +case 0xf3: { + dp = op_readpc(); + rd = op_readpc(); + sp = op_readdp(dp); + op_io(); + if((sp & 0x80) == 0x80)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//cbne_dp +case 0x2e: { + dp = op_readpc(); + rd = op_readpc(); + sp = op_readdp(dp); + op_io(); + if(regs.a == sp)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//cbne_dpx +case 0xde: { + dp = op_readpc(); + rd = op_readpc(); + op_io(); + sp = op_readdp(dp + regs.x); + op_io(); + if(regs.a == sp)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//dbnz_dp +case 0x6e: { + dp = op_readpc(); + rd = op_readpc(); + wr = op_readdp(dp); + wr--; + op_writedp(dp, wr); + if(wr == 0x00)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//dbnz_y +case 0xfe: { + rd = op_readpc(); + op_io(); + regs.y--; + op_io(); + if(regs.y == 0x00)break; + op_io(); + op_io(); + regs.pc += (int8)rd; +} break; + +//jmp_addr +case 0x5f: { + rd = op_readpc(); + rd |= op_readpc() << 8; + regs.pc = rd; +} break; + +//jmp_iaddrx +case 0x1f: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + dp += regs.x; + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + regs.pc = rd; +} break; + +//call +case 0x3f: { + rd = op_readpc(); + rd |= op_readpc() << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; +} break; + +//pcall +case 0x4f: { + rd = op_readpc(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = 0xff00 | rd; +} break; + +//tcall_0 +case 0x01: { + dp = 0xffde - (0 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; +} break; + +//tcall_1 +case 0x11: { + dp = 0xffde - (1 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; +} break; + +//tcall_2 +case 0x21: { + dp = 0xffde - (2 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; +} break; + +//tcall_3 +case 0x31: { + dp = 0xffde - (3 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; +} break; + +//tcall_4 +case 0x41: { + dp = 0xffde - (4 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; +} break; + +//tcall_5 +case 0x51: { + dp = 0xffde - (5 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; +} break; + +//tcall_6 +case 0x61: { + dp = 0xffde - (6 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; +} break; + +//tcall_7 +case 0x71: { + dp = 0xffde - (7 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; +} break; + +//tcall_8 +case 0x81: { + dp = 0xffde - (8 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; +} break; + +//tcall_9 +case 0x91: { + dp = 0xffde - (9 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; +} break; + +//tcall_10 +case 0xa1: { + dp = 0xffde - (10 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; +} break; + +//tcall_11 +case 0xb1: { + dp = 0xffde - (11 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; +} break; + +//tcall_12 +case 0xc1: { + dp = 0xffde - (12 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; +} break; + +//tcall_13 +case 0xd1: { + dp = 0xffde - (13 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; +} break; + +//tcall_14 +case 0xe1: { + dp = 0xffde - (14 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; +} break; + +//tcall_15 +case 0xf1: { + dp = 0xffde - (15 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; +} break; + +//brk +case 0x0f: { + rd = op_readaddr(0xffde); + rd |= op_readaddr(0xffdf) << 8; + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + op_writestack(regs.p); + regs.pc = rd; + regs.p.b = 1; + regs.p.i = 0; +} break; + +//ret +case 0x6f: { + rd = op_readstack(); + rd |= op_readstack() << 8; + op_io(); + op_io(); + regs.pc = rd; +} break; + +//reti +case 0x7f: { + regs.p = op_readstack(); + rd = op_readstack(); + rd |= op_readstack() << 8; + op_io(); + op_io(); + regs.pc = rd; +} break; + diff --git a/src/apu/sapu/core/op_read.b b/src/apu/sapu/core/op_read.b new file mode 100644 index 00000000..f5ebff01 --- /dev/null +++ b/src/apu/sapu/core/op_read.b @@ -0,0 +1,199 @@ +adc_a_const(0x88, adc, a), +and_a_const(0x28, and, a), +cmp_a_const(0x68, cmp, a), +cmp_x_const(0xc8, cmp, x), +cmp_y_const(0xad, cmp, y), +eor_a_const(0x48, eor, a), +or_a_const(0x08, or, a), +sbc_a_const(0xa8, sbc, a) { +1:rd = op_readpc(); + regs.$2 = op_$1(regs.$2, rd); +} + +adc_a_ix(0x86, adc), +and_a_ix(0x26, and), +cmp_a_ix(0x66, cmp), +eor_a_ix(0x46, eor), +or_a_ix(0x06, or), +sbc_a_ix(0xa6, sbc) { +1:rd = op_readdp(regs.x); +2:op_io(); + regs.a = op_$1(regs.a, rd); +} + +adc_a_dp(0x84, adc, a), +and_a_dp(0x24, and, a), +cmp_a_dp(0x64, cmp, a), +cmp_x_dp(0x3e, cmp, x), +cmp_y_dp(0x7e, cmp, y), +eor_a_dp(0x44, eor, a), +or_a_dp(0x04, or, a), +sbc_a_dp(0xa4, sbc, a) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); + regs.$2 = op_$1(regs.$2, rd); +} + +adc_a_dpx(0x94, adc), +and_a_dpx(0x34, and), +cmp_a_dpx(0x74, cmp), +eor_a_dpx(0x54, eor), +or_a_dpx(0x14, or), +sbc_a_dpx(0xb4, sbc) { +1:dp = op_readpc(); +2:op_io(); +3:rd = op_readdp(dp + regs.x); + regs.a = op_$1(regs.a, rd); +} + +adc_a_addr(0x85, adc, a), +and_a_addr(0x25, and, a), +cmp_a_addr(0x65, cmp, a), +cmp_x_addr(0x1e, cmp, x), +cmp_y_addr(0x5e, cmp, y), +eor_a_addr(0x45, eor, a), +or_a_addr(0x05, or, a), +sbc_a_addr(0xa5, sbc, a) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:rd = op_readaddr(dp); + regs.$2 = op_$1(regs.$2, rd); +} + +adc_a_addrx(0x95, adc, x), +adc_a_addry(0x96, adc, y), +and_a_addrx(0x35, and, x), +and_a_addry(0x36, and, y), +cmp_a_addrx(0x75, cmp, x), +cmp_a_addry(0x76, cmp, y), +eor_a_addrx(0x55, eor, x), +eor_a_addry(0x56, eor, y), +or_a_addrx(0x15, or, x), +or_a_addry(0x16, or, y), +sbc_a_addrx(0xb5, sbc, x), +sbc_a_addry(0xb6, sbc, y) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:op_io(); +4:rd = op_readaddr(dp + regs.$2); + regs.a = op_$1(regs.a, rd); +} + +adc_a_idpx(0x87, adc), +and_a_idpx(0x27, and), +cmp_a_idpx(0x67, cmp), +eor_a_idpx(0x47, eor), +or_a_idpx(0x07, or), +sbc_a_idpx(0xa7, sbc) { +1:dp = op_readpc() + regs.x; +2:op_io(); +3:sp = op_readdp(dp); +4:sp |= op_readdp(dp + 1) << 8; +5:rd = op_readaddr(sp); + regs.a = op_$1(regs.a, rd); +} + +adc_a_idpy(0x97, adc), +and_a_idpy(0x37, and), +cmp_a_idpy(0x77, cmp), +eor_a_idpy(0x57, eor), +or_a_idpy(0x17, or), +sbc_a_idpy(0xb7, sbc) { +1:dp = op_readpc(); +2:op_io(); +3:sp = op_readdp(dp); +4:sp |= op_readdp(dp + 1) << 8; +5:rd = op_readaddr(sp + regs.y); + regs.a = op_$1(regs.a, rd); +} + +adc_ix_iy(0x99, adc, 1), +and_ix_iy(0x39, and, 1), +cmp_ix_iy(0x79, cmp, 0), +eor_ix_iy(0x59, eor, 1), +or_ix_iy(0x19, or, 1), +sbc_ix_iy(0xb9, sbc, 1) { +1:wr = op_readdp(regs.x); +2:rd = op_readdp(regs.y); +3:op_io(); + wr = op_$1(wr, rd); +4:($2) ? op_writedp(regs.x, wr) : op_io(); +} + +adc_dp_dp(0x89, adc, 1), +and_dp_dp(0x29, and, 1), +cmp_dp_dp(0x69, cmp, 0), +eor_dp_dp(0x49, eor, 1), +or_dp_dp(0x09, or, 1), +sbc_dp_dp(0xa9, sbc, 1) { +1:sp = op_readpc(); +2:dp = op_readpc(); +3:wr = op_readdp(dp); +4:rd = op_readdp(sp); +5:wr = op_$1(wr, rd); + ($2) ? op_writedp(dp, wr) : op_io(); +} + +adc_dp_const(0x98, adc, 1), +and_dp_const(0x38, and, 1), +cmp_dp_const(0x78, cmp, 0), +eor_dp_const(0x58, eor, 1), +or_dp_const(0x18, or, 1), +sbc_dp_const(0xb8, sbc, 1) { +1:rd = op_readpc(); +2:dp = op_readpc(); +3:wr = op_readdp(dp); +4:wr = op_$1(wr, rd); + ($2) ? op_writedp(dp, wr) : op_io(); +} + +addw_ya_dp(0x7a, addw), +cmpw_ya_dp(0x5a, cmpw), +subw_ya_dp(0x9a, subw) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); +3:rd |= op_readdp(dp + 1) << 8; +4:op_io(); + regs.ya = op_$1(regs.ya, rd); +} + +and1_bit(0x4a, !!), +and1_notbit(0x6a, !) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + regs.p.c = regs.p.c & $1(rd & (1 << bit)); +} + +eor1_bit(0x8a) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); +4:op_io(); + regs.p.c = regs.p.c ^ !!(rd & (1 << bit)); +} + +not1_bit(0xea) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + rd ^= (1 << bit); +4:op_writeaddr(dp, rd); +} + +or1_bit(0x0a, !!), +or1_notbit(0x2a, !) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); +4:op_io(); + regs.p.c = regs.p.c | $1(rd & (1 << bit)); +} diff --git a/src/apu/sapu/core/op_read.cpp b/src/apu/sapu/core/op_read.cpp new file mode 100644 index 00000000..ec14a189 --- /dev/null +++ b/src/apu/sapu/core/op_read.cpp @@ -0,0 +1,745 @@ +//adc_a_const +case 0x88: { + rd = op_readpc(); + regs.a = op_adc(regs.a, rd); +} break; + +//and_a_const +case 0x28: { + rd = op_readpc(); + regs.a = op_and(regs.a, rd); +} break; + +//cmp_a_const +case 0x68: { + rd = op_readpc(); + regs.a = op_cmp(regs.a, rd); +} break; + +//cmp_x_const +case 0xc8: { + rd = op_readpc(); + regs.x = op_cmp(regs.x, rd); +} break; + +//cmp_y_const +case 0xad: { + rd = op_readpc(); + regs.y = op_cmp(regs.y, rd); +} break; + +//eor_a_const +case 0x48: { + rd = op_readpc(); + regs.a = op_eor(regs.a, rd); +} break; + +//or_a_const +case 0x08: { + rd = op_readpc(); + regs.a = op_or(regs.a, rd); +} break; + +//sbc_a_const +case 0xa8: { + rd = op_readpc(); + regs.a = op_sbc(regs.a, rd); +} break; + +//adc_a_ix +case 0x86: { + rd = op_readdp(regs.x); + op_io(); + regs.a = op_adc(regs.a, rd); +} break; + +//and_a_ix +case 0x26: { + rd = op_readdp(regs.x); + op_io(); + regs.a = op_and(regs.a, rd); +} break; + +//cmp_a_ix +case 0x66: { + rd = op_readdp(regs.x); + op_io(); + regs.a = op_cmp(regs.a, rd); +} break; + +//eor_a_ix +case 0x46: { + rd = op_readdp(regs.x); + op_io(); + regs.a = op_eor(regs.a, rd); +} break; + +//or_a_ix +case 0x06: { + rd = op_readdp(regs.x); + op_io(); + regs.a = op_or(regs.a, rd); +} break; + +//sbc_a_ix +case 0xa6: { + rd = op_readdp(regs.x); + op_io(); + regs.a = op_sbc(regs.a, rd); +} break; + +//adc_a_dp +case 0x84: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_adc(regs.a, rd); +} break; + +//and_a_dp +case 0x24: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_and(regs.a, rd); +} break; + +//cmp_a_dp +case 0x64: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_cmp(regs.a, rd); +} break; + +//cmp_x_dp +case 0x3e: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.x = op_cmp(regs.x, rd); +} break; + +//cmp_y_dp +case 0x7e: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.y = op_cmp(regs.y, rd); +} break; + +//eor_a_dp +case 0x44: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_eor(regs.a, rd); +} break; + +//or_a_dp +case 0x04: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_or(regs.a, rd); +} break; + +//sbc_a_dp +case 0xa4: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_sbc(regs.a, rd); +} break; + +//adc_a_dpx +case 0x94: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_adc(regs.a, rd); +} break; + +//and_a_dpx +case 0x34: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_and(regs.a, rd); +} break; + +//cmp_a_dpx +case 0x74: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_cmp(regs.a, rd); +} break; + +//eor_a_dpx +case 0x54: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_eor(regs.a, rd); +} break; + +//or_a_dpx +case 0x14: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_or(regs.a, rd); +} break; + +//sbc_a_dpx +case 0xb4: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_sbc(regs.a, rd); +} break; + +//adc_a_addr +case 0x85: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_adc(regs.a, rd); +} break; + +//and_a_addr +case 0x25: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_and(regs.a, rd); +} break; + +//cmp_a_addr +case 0x65: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_cmp(regs.a, rd); +} break; + +//cmp_x_addr +case 0x1e: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.x = op_cmp(regs.x, rd); +} break; + +//cmp_y_addr +case 0x5e: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.y = op_cmp(regs.y, rd); +} break; + +//eor_a_addr +case 0x45: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_eor(regs.a, rd); +} break; + +//or_a_addr +case 0x05: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_or(regs.a, rd); +} break; + +//sbc_a_addr +case 0xa5: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_sbc(regs.a, rd); +} break; + +//adc_a_addrx +case 0x95: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_adc(regs.a, rd); +} break; + +//adc_a_addry +case 0x96: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_adc(regs.a, rd); +} break; + +//and_a_addrx +case 0x35: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_and(regs.a, rd); +} break; + +//and_a_addry +case 0x36: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_and(regs.a, rd); +} break; + +//cmp_a_addrx +case 0x75: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_cmp(regs.a, rd); +} break; + +//cmp_a_addry +case 0x76: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_cmp(regs.a, rd); +} break; + +//eor_a_addrx +case 0x55: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_eor(regs.a, rd); +} break; + +//eor_a_addry +case 0x56: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_eor(regs.a, rd); +} break; + +//or_a_addrx +case 0x15: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_or(regs.a, rd); +} break; + +//or_a_addry +case 0x16: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_or(regs.a, rd); +} break; + +//sbc_a_addrx +case 0xb5: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_sbc(regs.a, rd); +} break; + +//sbc_a_addry +case 0xb6: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_sbc(regs.a, rd); +} break; + +//adc_a_idpx +case 0x87: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_adc(regs.a, rd); +} break; + +//and_a_idpx +case 0x27: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_and(regs.a, rd); +} break; + +//cmp_a_idpx +case 0x67: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_cmp(regs.a, rd); +} break; + +//eor_a_idpx +case 0x47: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_eor(regs.a, rd); +} break; + +//or_a_idpx +case 0x07: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_or(regs.a, rd); +} break; + +//sbc_a_idpx +case 0xa7: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_sbc(regs.a, rd); +} break; + +//adc_a_idpy +case 0x97: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_adc(regs.a, rd); +} break; + +//and_a_idpy +case 0x37: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_and(regs.a, rd); +} break; + +//cmp_a_idpy +case 0x77: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_cmp(regs.a, rd); +} break; + +//eor_a_idpy +case 0x57: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_eor(regs.a, rd); +} break; + +//or_a_idpy +case 0x17: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_or(regs.a, rd); +} break; + +//sbc_a_idpy +case 0xb7: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_sbc(regs.a, rd); +} break; + +//adc_ix_iy +case 0x99: { + wr = op_readdp(regs.x); + rd = op_readdp(regs.y); + op_io(); + wr = op_adc(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); +} break; + +//and_ix_iy +case 0x39: { + wr = op_readdp(regs.x); + rd = op_readdp(regs.y); + op_io(); + wr = op_and(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); +} break; + +//cmp_ix_iy +case 0x79: { + wr = op_readdp(regs.x); + rd = op_readdp(regs.y); + op_io(); + wr = op_cmp(wr, rd); + (0) ? op_writedp(regs.x, wr) : op_io(); +} break; + +//eor_ix_iy +case 0x59: { + wr = op_readdp(regs.x); + rd = op_readdp(regs.y); + op_io(); + wr = op_eor(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); +} break; + +//or_ix_iy +case 0x19: { + wr = op_readdp(regs.x); + rd = op_readdp(regs.y); + op_io(); + wr = op_or(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); +} break; + +//sbc_ix_iy +case 0xb9: { + wr = op_readdp(regs.x); + rd = op_readdp(regs.y); + op_io(); + wr = op_sbc(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); +} break; + +//adc_dp_dp +case 0x89: { + sp = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + rd = op_readdp(sp); + wr = op_adc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); +} break; + +//and_dp_dp +case 0x29: { + sp = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + rd = op_readdp(sp); + wr = op_and(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); +} break; + +//cmp_dp_dp +case 0x69: { + sp = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + rd = op_readdp(sp); + wr = op_cmp(wr, rd); + (0) ? op_writedp(dp, wr) : op_io(); +} break; + +//eor_dp_dp +case 0x49: { + sp = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + rd = op_readdp(sp); + wr = op_eor(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); +} break; + +//or_dp_dp +case 0x09: { + sp = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + rd = op_readdp(sp); + wr = op_or(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); +} break; + +//sbc_dp_dp +case 0xa9: { + sp = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + rd = op_readdp(sp); + wr = op_sbc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); +} break; + +//adc_dp_const +case 0x98: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_adc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); +} break; + +//and_dp_const +case 0x38: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_and(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); +} break; + +//cmp_dp_const +case 0x78: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_cmp(wr, rd); + (0) ? op_writedp(dp, wr) : op_io(); +} break; + +//eor_dp_const +case 0x58: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_eor(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); +} break; + +//or_dp_const +case 0x18: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_or(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); +} break; + +//sbc_dp_const +case 0xb8: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_sbc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); +} break; + +//addw_ya_dp +case 0x7a: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= op_readdp(dp + 1) << 8; + op_io(); + regs.ya = op_addw(regs.ya, rd); +} break; + +//cmpw_ya_dp +case 0x5a: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= op_readdp(dp + 1) << 8; + op_io(); + regs.ya = op_cmpw(regs.ya, rd); +} break; + +//subw_ya_dp +case 0x9a: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= op_readdp(dp + 1) << 8; + op_io(); + regs.ya = op_subw(regs.ya, rd); +} break; + +//and1_bit +case 0x4a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + regs.p.c = regs.p.c & !!(rd & (1 << bit)); +} break; + +//and1_notbit +case 0x6a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + regs.p.c = regs.p.c & !(rd & (1 << bit)); +} break; + +//eor1_bit +case 0x8a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + op_io(); + regs.p.c = regs.p.c ^ !!(rd & (1 << bit)); +} break; + +//not1_bit +case 0xea: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + rd ^= (1 << bit); + op_writeaddr(dp, rd); +} break; + +//or1_bit +case 0x0a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + op_io(); + regs.p.c = regs.p.c | !!(rd & (1 << bit)); +} break; + +//or1_notbit +case 0x2a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + op_io(); + regs.p.c = regs.p.c | !(rd & (1 << bit)); +} break; + diff --git a/src/apu/sapu/core/op_rmw.b b/src/apu/sapu/core/op_rmw.b new file mode 100644 index 00000000..e412ad93 --- /dev/null +++ b/src/apu/sapu/core/op_rmw.b @@ -0,0 +1,61 @@ +inc_a(0xbc, inc, a), +inc_x(0x3d, inc, x), +inc_y(0xfc, inc, y), +dec_a(0x9c, dec, a), +dec_x(0x1d, dec, x), +dec_y(0xdc, dec, y), +asl_a(0x1c, asl, a), +lsr_a(0x5c, lsr, a), +rol_a(0x3c, rol, a), +ror_a(0x7c, ror, a) { +1:op_io(); + regs.$2 = op_$1(regs.$2); +} + +inc_dp(0xab, inc), +dec_dp(0x8b, dec), +asl_dp(0x0b, asl), +lsr_dp(0x4b, lsr), +rol_dp(0x2b, rol), +ror_dp(0x6b, ror) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); +3:rd = op_$1(rd); + op_writedp(dp, rd); +} + +inc_dpx(0xbb, inc), +dec_dpx(0x9b, dec), +asl_dpx(0x1b, asl), +lsr_dpx(0x5b, lsr), +rol_dpx(0x3b, rol), +ror_dpx(0x7b, ror) { +1:dp = op_readpc(); +2:op_io(); +3:rd = op_readdp(dp + regs.x); +4:rd = op_$1(rd); + op_writedp(dp + regs.x, rd); +} + +inc_addr(0xac, inc), +dec_addr(0x8c, dec), +asl_addr(0x0c, asl), +lsr_addr(0x4c, lsr), +rol_addr(0x2c, rol), +ror_addr(0x6c, ror) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:rd = op_readaddr(dp); +4:rd = op_$1(rd); + op_writeaddr(dp, rd); +} + +incw_dp(0x3a, incw), +decw_dp(0x1a, decw) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); +3:rd |= op_readdp(dp + 1) << 8; +4:rd = op_$1(rd); + op_writedp(dp + 1, rd >> 8); +5:op_writedp(dp, rd); +} diff --git a/src/apu/sapu/core/op_rmw.cpp b/src/apu/sapu/core/op_rmw.cpp new file mode 100644 index 00000000..832e0ec8 --- /dev/null +++ b/src/apu/sapu/core/op_rmw.cpp @@ -0,0 +1,236 @@ +//inc_a +case 0xbc: { + op_io(); + regs.a = op_inc(regs.a); +} break; + +//inc_x +case 0x3d: { + op_io(); + regs.x = op_inc(regs.x); +} break; + +//inc_y +case 0xfc: { + op_io(); + regs.y = op_inc(regs.y); +} break; + +//dec_a +case 0x9c: { + op_io(); + regs.a = op_dec(regs.a); +} break; + +//dec_x +case 0x1d: { + op_io(); + regs.x = op_dec(regs.x); +} break; + +//dec_y +case 0xdc: { + op_io(); + regs.y = op_dec(regs.y); +} break; + +//asl_a +case 0x1c: { + op_io(); + regs.a = op_asl(regs.a); +} break; + +//lsr_a +case 0x5c: { + op_io(); + regs.a = op_lsr(regs.a); +} break; + +//rol_a +case 0x3c: { + op_io(); + regs.a = op_rol(regs.a); +} break; + +//ror_a +case 0x7c: { + op_io(); + regs.a = op_ror(regs.a); +} break; + +//inc_dp +case 0xab: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_inc(rd); + op_writedp(dp, rd); +} break; + +//dec_dp +case 0x8b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_dec(rd); + op_writedp(dp, rd); +} break; + +//asl_dp +case 0x0b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_asl(rd); + op_writedp(dp, rd); +} break; + +//lsr_dp +case 0x4b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_lsr(rd); + op_writedp(dp, rd); +} break; + +//rol_dp +case 0x2b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_rol(rd); + op_writedp(dp, rd); +} break; + +//ror_dp +case 0x6b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_ror(rd); + op_writedp(dp, rd); +} break; + +//inc_dpx +case 0xbb: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_inc(rd); + op_writedp(dp + regs.x, rd); +} break; + +//dec_dpx +case 0x9b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_dec(rd); + op_writedp(dp + regs.x, rd); +} break; + +//asl_dpx +case 0x1b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_asl(rd); + op_writedp(dp + regs.x, rd); +} break; + +//lsr_dpx +case 0x5b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_lsr(rd); + op_writedp(dp + regs.x, rd); +} break; + +//rol_dpx +case 0x3b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_rol(rd); + op_writedp(dp + regs.x, rd); +} break; + +//ror_dpx +case 0x7b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_ror(rd); + op_writedp(dp + regs.x, rd); +} break; + +//inc_addr +case 0xac: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_inc(rd); + op_writeaddr(dp, rd); +} break; + +//dec_addr +case 0x8c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_dec(rd); + op_writeaddr(dp, rd); +} break; + +//asl_addr +case 0x0c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_asl(rd); + op_writeaddr(dp, rd); +} break; + +//lsr_addr +case 0x4c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_lsr(rd); + op_writeaddr(dp, rd); +} break; + +//rol_addr +case 0x2c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_rol(rd); + op_writeaddr(dp, rd); +} break; + +//ror_addr +case 0x6c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_ror(rd); + op_writeaddr(dp, rd); +} break; + +//incw_dp +case 0x3a: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= op_readdp(dp + 1) << 8; + rd = op_incw(rd); + op_writedp(dp + 1, rd >> 8); + op_writedp(dp, rd); +} break; + +//decw_dp +case 0x1a: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= op_readdp(dp + 1) << 8; + rd = op_decw(rd); + op_writedp(dp + 1, rd >> 8); + op_writedp(dp, rd); +} break; + diff --git a/src/apu/sapu/core/opfn.cpp b/src/apu/sapu/core/opfn.cpp new file mode 100644 index 00000000..abe7c0a7 --- /dev/null +++ b/src/apu/sapu/core/opfn.cpp @@ -0,0 +1,138 @@ +uint8 sAPU::op_adc(uint8 x, uint8 y) { +int16 r = x + y + regs.p.c; + regs.p.n = !!(r & 0x80); + regs.p.v = !!(~(x ^ y) & (y ^ (uint8)r) & 0x80); + regs.p.h = !!((x ^ y ^ (uint8)r) & 0x10); + regs.p.z = ((uint8)r == 0); + regs.p.c = (r > 0xff); + return r; +} + +uint16 sAPU::op_addw(uint16 x, uint16 y) { +int16 r; + regs.p.c = 0; + r = op_adc(x, y); + r |= op_adc(x >> 8, y >> 8) << 8; + regs.p.z = ((uint16)r == 0); + return r; +} + +uint8 sAPU::op_and(uint8 x, uint8 y) { + x &= y; + regs.p.n = !!(x & 0x80); + regs.p.z = (x == 0); + return x; +} + +uint8 sAPU::op_cmp(uint8 x, uint8 y) { +int16 r = x - y; + regs.p.n = !!(r & 0x80); + regs.p.z = ((uint8)r == 0); + regs.p.c = (r >= 0); + return x; +} + +uint16 sAPU::op_cmpw(uint16 x, uint16 y) { +int32 r = x - y; + regs.p.n = !!(r & 0x8000); + regs.p.z = ((uint16)r == 0); + regs.p.c = (r >= 0); + return x; +} + +uint8 sAPU::op_eor(uint8 x, uint8 y) { + x ^= y; + regs.p.n = !!(x & 0x80); + regs.p.z = (x == 0); + return x; +} + +uint8 sAPU::op_or(uint8 x, uint8 y) { + x |= y; + regs.p.n = !!(x & 0x80); + regs.p.z = (x == 0); + return x; +} + +uint8 sAPU::op_sbc(uint8 x, uint8 y) { +int16 r = x - y - !regs.p.c; + regs.p.n = !!(r & 0x80); + regs.p.v = !!((x ^ y) & (x ^ (uint8)r) & 0x80); + regs.p.h = !((x ^ y ^ (uint8)r) & 0x10); + regs.p.z = ((uint8)r == 0); + regs.p.c = (r >= 0); + return r; +} + +uint16 sAPU::op_subw(uint16 x, uint16 y) { +int16 r; + regs.p.c = 1; + r = op_sbc(x, y); + r |= op_sbc(x >> 8, y >> 8) << 8; + regs.p.z = ((uint16)r == 0); + return r; +} + +uint8 sAPU::op_inc(uint8 x) { + x++; + regs.p.n = !!(x & 0x80); + regs.p.z = (x == 0); + return x; +} + +uint16 sAPU::op_incw(uint16 x) { + x++; + regs.p.n = !!(x & 0x8000); + regs.p.z = (x == 0); + return x; +} + +uint8 sAPU::op_dec(uint8 x) { + x--; + regs.p.n = !!(x & 0x80); + regs.p.z = (x == 0); + return x; +} + +uint16 sAPU::op_decw(uint16 x) { + x--; + regs.p.n = !!(x & 0x8000); + regs.p.z = (x == 0); + return x; +} + +uint8 sAPU::op_asl(uint8 x) { + regs.p.c = !!(x & 0x80); + x <<= 1; + regs.p.n = !!(x & 0x80); + regs.p.z = (x == 0); + return x; +} + +uint8 sAPU::op_lsr(uint8 x) { + regs.p.c = !!(x & 0x01); + x >>= 1; + regs.p.n = !!(x & 0x80); + regs.p.z = (x == 0); + return x; +} + +uint8 sAPU::op_rol(uint8 x) { +uint8 c = regs.p.c; + regs.p.c = !!(x & 0x80); + x <<= 1; + x |= c; + regs.p.n = !!(x & 0x80); + regs.p.z = (x == 0); + return x; +} + +uint8 sAPU::op_ror(uint8 x) { +uint8 c = (regs.p.c)?0x80:0x00; + regs.p.c = !!(x & 0x01); + x >>= 1; + x |= c; + regs.p.n = !!(x & 0x80); + regs.p.z = (x == 0); + return x; +} diff --git a/src/apu/sapu/core/sapugen.cpp b/src/apu/sapu/core/sapugen.cpp new file mode 100644 index 00000000..d8d49606 --- /dev/null +++ b/src/apu/sapu/core/sapugen.cpp @@ -0,0 +1,18 @@ +#define CLASS_NAME "sAPU" +#include "../../../lib/opgen_s.cpp" + +int main() { +//fph = fopen("op.h", "wb"); +//fpt = fopen("optable.cpp", "wb"); + + generate("op_mov.cpp", "op_mov.b"); + generate("op_pc.cpp", "op_pc.b"); + generate("op_read.cpp", "op_read.b"); + generate("op_rmw.cpp", "op_rmw.b"); + generate("op_misc.cpp", "op_misc.b"); + +//fclose(fph); +//fclose(fpt); + + return 0; +} diff --git a/src/apu/sapu/memory/memory.cpp b/src/apu/sapu/memory/memory.cpp new file mode 100644 index 00000000..e1e6a019 --- /dev/null +++ b/src/apu/sapu/memory/memory.cpp @@ -0,0 +1,197 @@ +uint8 sAPU::spcram_read(uint16 addr) { +uint8 r; + if((addr & 0xfff0) == 0x00f0) { + //addr >= 0x00f0 && addr <= 0x00ff + switch(addr) { + case 0xf0: //TEST -- operation unknown, supposedly returns 0x00 + r = 0x00; + break; + case 0xf1: //CONTROL -- write-only register, always returns 0x00 + r = 0x00; + break; + case 0xf2: //DSPADDR + r = status.dsp_addr; + break; + case 0xf3: //DSPDATA + //0x80-0xff is a read-only mirror of 0x00-0x7f + r = r_dsp->read(status.dsp_addr & 0x7f); + break; + case 0xf4: //CPUIO0 + case 0xf5: //CPUIO1 + case 0xf6: //CPUIO2 + case 0xf7: //CPUIO3 + #ifdef FAVOR_SPEED + co_return(); + #endif + r = r_cpu->port_read(addr & 3); + break; + case 0xf8: //??? + case 0xf9: //??? -- Mapped to SPCRAM + r = spcram[addr]; + break; + case 0xfa: //T0TARGET + case 0xfb: //T1TARGET + case 0xfc: //T2TARGET -- write-only registers, always return 0x00 + r = 0x00; + break; + case 0xfd: //T0OUT -- 4-bit counter value + r = t0.stage3_ticks & 15; + t0.stage3_ticks = 0; + break; + case 0xfe: //T1OUT -- 4-bit counter value + r = t1.stage3_ticks & 15; + t1.stage3_ticks = 0; + break; + case 0xff: //T2OUT -- 4-bit counter value + r = t2.stage3_ticks & 15; + t2.stage3_ticks = 0; + break; + } + } else if(addr < 0xffc0) { + r = spcram[addr]; + } else { + if(status.iplrom_enabled == true) { + r = iplrom[addr & 0x3f]; + } else { + r = spcram[addr]; + } + } + +#ifdef DEBUGGER + snes->notify(SNES::SPCRAM_READ, addr, r); +#endif + return r; +} + +void sAPU::spcram_write(uint16 addr, uint8 data) { + if((addr & 0xfff0) == 0x00f0) { + //addr >= 0x00f0 && addr >= 0x00ff + switch(addr) { + case 0xf0: //TEST -- operation unknown + break; + case 0xf1: //CONTROL + status.iplrom_enabled = !!(data & 0x80); + + //one-time clearing of APU port read registers, + //emulated by simulating CPU writes of 0x00 + if(data & 0x20) { + r_cpu->port_write(2, 0x00); + r_cpu->port_write(3, 0x00); + } + if(data & 0x10) { + r_cpu->port_write(0, 0x00); + r_cpu->port_write(1, 0x00); + } + + //0->1 transistion resets timers + if(t2.enabled == false && (data & 0x04)) { + t2.stage2_ticks = 0; + t2.stage3_ticks = 0; + } + t2.enabled = !!(data & 0x04); + + if(t1.enabled == false && (data & 0x02)) { + t1.stage2_ticks = 0; + t1.stage3_ticks = 0; + } + t1.enabled = !!(data & 0x02); + + if(t0.enabled == false && (data & 0x01)) { + t0.stage2_ticks = 0; + t0.stage3_ticks = 0; + } + t0.enabled = !!(data & 0x01); + break; + case 0xf2: //DSPADDR + status.dsp_addr = data; + break; + case 0xf3: //DSPDATA + //0x80-0xff is a read-only mirror of 0x00-0x7f + if(status.dsp_addr < 0x80) { + r_dsp->write(status.dsp_addr & 0x7f, data); + } + break; + case 0xf4: //CPUIO0 + case 0xf5: //CPUIO1 + case 0xf6: //CPUIO2 + case 0xf7: //CPUIO3 + #ifdef FAVOR_SPEED + co_return(); + #endif + port_write(addr & 3, data); + break; + case 0xf8: //??? + case 0xf9: //??? - Mapped to SPCRAM + spcram[addr] = data; + break; + case 0xfa: //T0TARGET + t0.target = data; + break; + case 0xfb: //T1TARGET + t1.target = data; + break; + case 0xfc: //T2TARGET + t2.target = data; + break; + case 0xfd: //T0OUT + case 0xfe: //T1OUT + case 0xff: //T2OUT -- read-only registers + break; + } + } else { + //writes to $ffc0-$ffff always go to spcram, + //even if the iplrom is enabled. + spcram[addr] = data; + } + +#ifdef DEBUGGER + snes->notify(SNES::SPCRAM_WRITE, addr, data); +#endif +} + +uint8 sAPU::port_read(uint8 port) { + return spcram[0xf4 + (port & 3)]; +} + +void sAPU::port_write(uint8 port, uint8 data) { + spcram[0xf4 + (port & 3)] = data; +} + +// + +void sAPU::op_io() { + add_clocks(24); + tick_timers(); +//co_return(); +} + +uint8 sAPU::op_read(uint16 addr) { + add_clocks(8); +#ifdef FAVOR_ACCURACY + co_return(); +#endif +uint8 r = spcram_read(addr); + add_clocks(16); + tick_timers(); + return r; +} + +void sAPU::op_write(uint16 addr, uint8 data) { + add_clocks(24); + tick_timers(); +#ifdef FAVOR_ACCURACY + co_return(); +#endif + spcram_write(addr, data); +} + +// + +uint8 sAPU::op_readpc () { return op_read(regs.pc++); } +uint8 sAPU::op_readstack () { return op_read(0x0100 | ++regs.sp); } +void sAPU::op_writestack(uint8 data) { op_write(0x0100 | regs.sp--, data); } +uint8 sAPU::op_readaddr (uint16 addr) { return op_read(addr); } + +void sAPU::op_writeaddr (uint16 addr, uint8 data) { op_write(addr, data); } +uint8 sAPU::op_readdp (uint8 addr) { return op_read((uint(regs.p.p) << 8) + addr); } +void sAPU::op_writedp (uint8 addr, uint8 data) { op_write((uint(regs.p.p) << 8) + addr, data); } diff --git a/src/apu/sapu/memory/memory.h b/src/apu/sapu/memory/memory.h new file mode 100644 index 00000000..aa2298a3 --- /dev/null +++ b/src/apu/sapu/memory/memory.h @@ -0,0 +1,24 @@ + uint8 spcram_read (uint16 addr); + void spcram_write(uint16 addr, uint8 data); + + inline uint8 port_read (uint8 port); + inline void port_write(uint8 port, uint8 data); + +/***** + * core APU bus functions + *****/ + inline void op_io (); + inline uint8 op_read (uint16 addr); + inline void op_write(uint16 addr, uint8 data); + +/***** + * helper memory addressing functions used by APU core + *****/ + inline uint8 op_readpc (); + inline uint8 op_readstack (); + inline void op_writestack(uint8 data); + inline uint8 op_readaddr (uint16 addr); + + inline void op_writeaddr (uint16 addr, uint8 data); + inline uint8 op_readdp (uint8 addr); + inline void op_writedp (uint8 addr, uint8 data); diff --git a/src/apu/sapu/sapu.cpp b/src/apu/sapu/sapu.cpp new file mode 100644 index 00000000..ba22ce6c --- /dev/null +++ b/src/apu/sapu/sapu.cpp @@ -0,0 +1,73 @@ +#include "../../base.h" + +#include "core/core.cpp" +#include "memory/memory.cpp" +#include "timing/timing.cpp" + +void sapu_entry_point() { + r_apu->main(); +} + +void sAPU::run() { + co_call(thread); +} + +void sAPU::power() { + memset(spcram, 0x00, 65536); + reset(); +} + +void sAPU::reset() { + if(thread)co_delete(thread); + thread = co_create(sapu_entry_point, 65536); + + regs.pc = 0xffc0; + regs.a = 0x00; + regs.x = 0x00; + regs.y = 0x00; + regs.sp = 0xef; + regs.p = 0x02; + + status.clocks_executed = 0; + +//$f1 + status.iplrom_enabled = true; + +//$f2 + status.dsp_addr = 0x00; + + t0.enabled = false; + t1.enabled = false; + t2.enabled = false; + + t0.stage1_ticks = 0; + t1.stage1_ticks = 0; + t2.stage1_ticks = 0; + + t0.stage2_ticks = 0; + t1.stage2_ticks = 0; + t2.stage2_ticks = 0; + + t0.stage3_ticks = 0; + t1.stage3_ticks = 0; + t2.stage3_ticks = 0; +} + +sAPU::sAPU() { +//#include "core/optable.cpp" + + thread = 0; + + t0.cycle_frequency = 128; //1.024mhz / 8khz = 128 + t1.cycle_frequency = 128; //1.024mhz / 8khz = 128 + t2.cycle_frequency = 16; //1.024mhz / 64khz = 16 + +//targets not initialized/changed upon reset + t0.target = 0; + t1.target = 0; + t2.target = 0; +} + +sAPU::~sAPU() { + if(thread)co_delete(thread); +} diff --git a/src/apu/sapu/sapu.h b/src/apu/sapu/sapu.h new file mode 100644 index 00000000..d191ea00 --- /dev/null +++ b/src/apu/sapu/sapu.h @@ -0,0 +1,32 @@ +class sAPU : public APU { +public: +#include "core/core.h" +#include "memory/memory.h" +#include "timing/timing.h" + +thread_t thread; + +struct { + uint8 opcode; + bool in_opcode; + +//timing + uint32 clocks_executed; + +//$f1 + bool iplrom_enabled; + +//$f2 + uint8 dsp_addr; +} status; + +//sapu.cpp + void main(); + + void run(); + void power(); + void reset(); + + sAPU(); + ~sAPU(); +}; diff --git a/src/apu/sapu/timing/timing.cpp b/src/apu/sapu/timing/timing.cpp new file mode 100644 index 00000000..ebc696c8 --- /dev/null +++ b/src/apu/sapu/timing/timing.cpp @@ -0,0 +1,35 @@ +void sAPU::add_clocks(int clocks) { + status.clocks_executed += clocks; +} + +uint32 sAPU::clocks_executed() { +uint32 r = status.clocks_executed; + status.clocks_executed = 0; + return r; +} + +//occurs once every 24 clocks (once every APU opcode cycle) +void sAPU::tick_timers() { + t0.tick(); + t1.tick(); + t2.tick(); +} + +void sAPU::sAPUTimer::tick() { +//stage 1 increment + stage1_ticks++; + if(stage1_ticks < cycle_frequency)return; + + stage1_ticks -= cycle_frequency; + if(enabled == false)return; + +//stage 2 increment + stage2_ticks++; + + if(stage2_ticks != target)return; + +//stage 3 increment + stage2_ticks = 0; + stage3_ticks++; + stage3_ticks &= 15; +} diff --git a/src/apu/sapu/timing/timing.h b/src/apu/sapu/timing/timing.h new file mode 100644 index 00000000..d7a06e83 --- /dev/null +++ b/src/apu/sapu/timing/timing.h @@ -0,0 +1,11 @@ +class sAPUTimer { +public: +uint8 cycle_frequency, target; +uint8 stage1_ticks, stage2_ticks, stage3_ticks; +bool enabled; + inline void tick(); +} t0, t1, t2; + + inline void add_clocks(int clocks); + inline void tick_timers(); + inline uint32 clocks_executed(); diff --git a/src/base.h b/src/base.h index 080a24d2..50d2e473 100644 --- a/src/base.h +++ b/src/base.h @@ -1,29 +1,32 @@ -#define BSNES_VERSION "0.016" -#define BSNES_TITLE "bsnes v" BSNES_VERSION +#define BSNES_VERSION "0.016.27a" +#define BSNES_TITLE "bsnes v" BSNES_VERSION #define MEMCORE bMemBus -#define CPUCORE bCPU -#define APUCORE bAPU +#define CPUCORE sCPU +#define APUCORE sAPU #define DSPCORE bDSP #define PPUCORE bPPU +//#define FAVOR_ACCURACY +#define FAVOR_SPEED + //game genie + pro action replay code support (~1-3% speed hit) #define CHEAT_SYSTEM //enable GZ, ZIP format support -//#define GZIP_SUPPORT +#define GZIP_SUPPORT //enable JMA support -//#define JMA_SUPPORT +#define JMA_SUPPORT //debugging extensions (~10% speed hit) -#define DEBUGGER +//#define DEBUGGER //snes core polymorphism //(allow mem/cpu/apu/ppu overriding, ~10% speed hit) //#define POLYMORPHISM -//this should be declared in the port-specific makefiles +//this should be declared in the port-specific makefile //#define ARCH_LSB //#define ARCH_MSB @@ -43,6 +46,7 @@ #error "unknown architecture" #endif +#include "lib/libco_x86.h" #include "lib/libbase.h" #include "lib/libvector.h" #include "lib/libstring.h" @@ -58,8 +62,18 @@ inline uint16 read16(uint8 *addr, uint pos) { } //platform-specific global functions -void alert(char *s, ...); -void dprintf(char *s, ...); +void alert(char *, ...); +void dprintf(char *, ...); +void dprintf(uint, char *, ...); + +namespace source { + enum { + none = 0, + debug, + cpu, + apu, + }; +}; //various class interfaces #include "interface.h" diff --git a/src/cart/cart.cpp b/src/cart/cart.cpp index f2dcd936..f8f5d7ad 100644 --- a/src/cart/cart.cpp +++ b/src/cart/cart.cpp @@ -4,9 +4,12 @@ void Cartridge::read_header() { cart.srtc = false; cart.sdd1 = false; cart.c4 = false; + cart.dsp1 = false; cart.dsp2 = false; cart.obc1 = false; + cart.dsp1_mapper = 0; + if(cart.header_index == 0x7fc0 && cart.rom_size >= 0x401000) { cart.mapper = EXLOROM; } else if(cart.header_index == 0x7fc0 && rom[cart.header_index + MAPPER] == 0x32) { @@ -33,6 +36,28 @@ uint8 rom_type = rom[cart.header_index + ROM_TYPE]; cart.c4 = true; } + if((mapper == 0x20 || mapper == 0x21) && rom_type == 0x03) { + cart.dsp1 = true; + } + + if(mapper == 0x30 && rom_type == 0x05) { + cart.dsp1 = true; + } + + if(mapper == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) { + cart.dsp1 = true; + } + + if(cart.dsp1 == true) { + if((mapper & 0x2f) == 0x20 && rom_size <= 0x100000) { + cart.dsp1_mapper = DSP1_LOROM_1MB; + } else if((mapper & 0x2f) == 0x20) { + cart.dsp1_mapper = DSP1_LOROM_2MB; + } else if((mapper & 0x2f) == 0x21) { + cart.dsp1_mapper = DSP1_HIROM; + } + } + if(mapper == 0x20 && rom_type == 0x05) { cart.dsp2 = true; } @@ -41,7 +66,7 @@ uint8 rom_type = rom[cart.header_index + ROM_TYPE]; cart.obc1 = true; } - cart.cart_mmio = cart.c4 | cart.dsp2 | cart.obc1; + cart.cart_mmio = cart.c4 | cart.dsp1 | cart.dsp2 | cart.obc1; if(rom[cart.header_index + SRAM_SIZE] & 7) { cart.sram_size = 1024 << (rom[cart.header_index + SRAM_SIZE] & 7); @@ -67,7 +92,7 @@ int32 score_lo = 0, score_ex = 0; if(rom_size < 0x010000) { - //cart too small to be anything else + //cart too small to be anything but lorom cart.header_index = 0x007fc0; return; } diff --git a/src/cart/cart.h b/src/cart/cart.h index e0df6e40..3daaa463 100644 --- a/src/cart/cart.h +++ b/src/cart/cart.h @@ -28,6 +28,11 @@ enum { HIROM = 0x21, EXLOROM = 0x22, EXHIROM = 0x25, + +//special chip memory mappers + DSP1_LOROM_1MB = 1, + DSP1_LOROM_2MB = 2, + DSP1_HIROM = 3, }; struct { @@ -47,8 +52,11 @@ struct { bool srtc; bool sdd1; bool c4; + bool dsp1; bool dsp2; bool obc1; + + uint dsp1_mapper; } cart; void load_rom(Reader *rf); diff --git a/src/chip/dsp1/_dsp1emu.cpp b/src/chip/dsp1/_dsp1emu.cpp new file mode 100644 index 00000000..637a65ed --- /dev/null +++ b/src/chip/dsp1/_dsp1emu.cpp @@ -0,0 +1,1617 @@ +// DSP-1's emulation code +// +// Based on research by Overload, The Dumper, Neviksti and Andreas Naive +// Date: June 2006 + +////////////////////////////////////////////////////////////////// + +Dsp1::Dsp1() +{ + reset(); +} + +////////////////////////////////////////////////////////////////// + +uint8 Dsp1::getSr() const +{ + return mSr; +} + +////////////////////////////////////////////////////////////////// + +uint8 Dsp1::getDr() +{ + uint8 oDr; + + fsmStep(true, oDr); + return oDr; +} + +////////////////////////////////////////////////////////////////// + +void Dsp1::setDr(uint8 iDr) +{ + fsmStep(false, iDr); +} + +////////////////////////////////////////////////////////////////// + +void Dsp1::reset() +{ + mSr = DRC|RQM; + mDr = 0x0080; // Only a supposition. Is this correct? + mFreeze = false; + mFsmMajorState = WAIT_COMMAND; + memset(&shared, 0, sizeof(SharedData)); // another supposition +} + +////////////////////////////////////////////////////////////////// + +// Though the DSP-1 is unaware of the type of operation (read or write) +// we need to know what is being done by the program, as the class +// is responsible for maintaining the binding between the +// "external" and "internal" representations of the DR (data register). + +void Dsp1::fsmStep(bool read, uint8 &data) +{ + if (0 == (mSr&RQM)) return; + // Now RQM would be cleared; however, as this code is not to be used in + // a multithread environment, we will simply fake RQM operation. + // (The only exception would be Op1A's freeze.) + + // binding + if (read) + { + if (mSr&DRS) + data = static_cast(mDr>>8); + else + data = static_cast(mDr); + } + else + { + if (mSr&DRS) + { + mDr &= 0x00ff; + mDr |= data<<8; + } + else + { + mDr &= 0xff00; + mDr |= data; + } + } + + + switch (mFsmMajorState) + { + case WAIT_COMMAND: + mCommand = static_cast(mDr); + if (!(mCommand & 0xc0)) // valid command? + { + switch(mCommand) + { + // freeze cases + case 0x1a: + case 0x2a: + case 0x3a: + mFreeze = true; + break; + // normal cases + default: + mDataCounter=0; + mFsmMajorState = READ_DATA; + mSr &= ~DRC; + break; + } + } + break; + case READ_DATA: + mSr ^= DRS; + if (!(mSr&DRS)) + { + mReadBuffer[mDataCounter++] = static_cast(mDr); + if (mDataCounter >= mCommandTable[mCommand].reads) + { + (this->*mCommandTable[mCommand].callback)(mReadBuffer, mWriteBuffer); + if (0 != mCommandTable[mCommand].writes) // any output? + { + mDataCounter = 0; + mDr = static_cast(mWriteBuffer[mDataCounter]); + mFsmMajorState = WRITE_DATA; + } + else + { + mDr = 0x0080; // valid command completion + mFsmMajorState = WAIT_COMMAND; + mSr |= DRC; + } + } + } + break; + case WRITE_DATA: + mSr ^= DRS; + if (!(mSr&DRS)) + { + ++mDataCounter; + if (mDataCounter >= mCommandTable[mCommand].writes) + { + if ((mCommand == 0x0a)&&(mDr != 0x8000)) + { + // works in continuous mode + mReadBuffer[0]++; // next raster line + (this->*mCommandTable[mCommand].callback)(mReadBuffer, mWriteBuffer); + mDataCounter = 0; + mDr = static_cast(mWriteBuffer[mDataCounter]); + } + else + { + mDr = 0x0080; // valid command completion + mFsmMajorState = WAIT_COMMAND; + mSr |= DRC; + } + } + else + { + mDr = static_cast(mWriteBuffer[mDataCounter]); + } + } + break; + } + + + + // Now RQM would be set (except when executing Op1A -command equals 0x1a, 0x2a or 0x3a-). + if (mFreeze) + mSr &= ~RQM; +} + +////////////////////////////////////////////////////////////////// + +// The info on this table follows Overload's docs. + +const Dsp1::Command Dsp1::mCommandTable[0x40] = { + {&Dsp1::multiply, 2, 1}, //0x00 + {&Dsp1::attitudeA, 4, 0}, //0x01 + {&Dsp1::parameter, 7, 4}, //0x02 + {&Dsp1::subjectiveA, 3, 3}, //0x03 + {&Dsp1::triangle, 2, 2}, //0x04 + {&Dsp1::attitudeA, 4, 0}, //0x01 + {&Dsp1::project, 3, 3}, //0x06 + {&Dsp1::memoryTest, 1, 1}, //0x0f + {&Dsp1::radius, 3, 2}, //0x08 + {&Dsp1::objectiveA, 3, 3}, //0x0d + {&Dsp1::raster, 1, 4}, // 0x0a. This will normally work in continuous mode + {&Dsp1::scalarA, 3, 1}, //0x0b + {&Dsp1::rotate, 3, 2}, //0x0c + {&Dsp1::objectiveA, 3, 3}, //0x0d + {&Dsp1::target, 2, 2}, //0x0e + {&Dsp1::memoryTest, 1, 1}, //0x0f + + {&Dsp1::inverse, 2, 2}, //0x10 + {&Dsp1::attitudeB, 4, 0}, //0x11 + {&Dsp1::parameter, 7, 4}, //0x02 + {&Dsp1::subjectiveB, 3, 3}, //0x13 + {&Dsp1::gyrate, 6, 3}, //0x14 + {&Dsp1::attitudeB, 4, 0}, //0x11 + {&Dsp1::project, 3, 3}, //0x06 + {&Dsp1::memoryDump, 1, 1024}, //0x1f + {&Dsp1::range, 4, 1}, //0x18 + {&Dsp1::objectiveB, 3, 3}, //0x1d + {0, 0, 0}, // 0x1a; the chip freezes + {&Dsp1::scalarB, 3, 1}, //0x1b + {&Dsp1::polar, 6, 3}, //0x1c + {&Dsp1::objectiveB, 3, 3}, //0x1d + {&Dsp1::target, 2, 2}, //0x0e + {&Dsp1::memoryDump, 1, 1024}, //0x1f + + {&Dsp1::multiply2, 2, 1}, //0x20 + {&Dsp1::attitudeC, 4, 0}, //0x21 + {&Dsp1::parameter, 7, 4}, //0x02 + {&Dsp1::subjectiveC, 3, 3}, //0x23 + {&Dsp1::triangle, 2, 2}, //0x04 + {&Dsp1::attitudeC, 4, 0}, //0x21 + {&Dsp1::project, 3, 3}, //0x06 + {&Dsp1::memorySize, 1, 1}, //0x2f + {&Dsp1::distance, 3, 1}, //0x28 + {&Dsp1::objectiveC, 3, 3}, //0x2d + {0, 0, 0}, // 0x1a; the chip freezes + {&Dsp1::scalarC, 3, 1}, //0x2b + {&Dsp1::rotate, 3, 2}, //0x0c + {&Dsp1::objectiveC, 3, 3}, //0x2d + {&Dsp1::target, 2, 2}, //0x0e + {&Dsp1::memorySize, 1, 1}, //0x2f + + {&Dsp1::inverse, 2, 2}, //0x10 + {&Dsp1::attitudeA, 4, 0}, //0x01 + {&Dsp1::parameter, 7, 4}, //0x02 + {&Dsp1::subjectiveA, 3, 3}, //0x03 + {&Dsp1::gyrate, 6, 3}, //0x14 + {&Dsp1::attitudeA, 4, 0}, //0x01 + {&Dsp1::project, 3, 3}, //0x06 + {&Dsp1::memoryDump, 1, 1024}, //0x1f + {&Dsp1::range2, 4, 1}, //0x38 + {&Dsp1::objectiveA, 3, 3}, //0x0d + {0, 0, 0}, // 0x1a; the chip freezes + {&Dsp1::scalarA, 3, 1}, //0x0b + {&Dsp1::polar, 6, 3}, //0x1c + {&Dsp1::objectiveA, 3, 3}, //0x0d + {&Dsp1::target, 2, 2}, //0x0e + {&Dsp1::memoryDump, 1, 1024}, //0x1f +}; + +////////////////////////////////////////////////////////////////// + +void Dsp1::memoryTest(int16 *input, int16 *output) +{ + int16& Size = input[0]; + int16& Result = output[0]; + + Result = 0x0000; +} + +////////////////////////////////////////////////////////////////// + +void Dsp1::memoryDump(int16 *input, int16 *output) +{ + memcpy(output, DataRom, 1024); +} + +////////////////////////////////////////////////////////////////// + +void Dsp1::memorySize(int16 *input, int16 *output) +{ + int16& Size = output[0]; + + Size = 0x0100; +} + +////////////////////////////////////////////////////////////////// + +// 16-bit multiplication + +void Dsp1::multiply(int16 *input, int16 *output) +{ + int16& Multiplicand = input[0]; + int16& Multiplier = input[1]; + int16& Product = output[0]; + + Product = Multiplicand * Multiplier >> 15; +} + +////////////////////////////////////////////////////////////////// + +// 16-bit multiplication. 'Alternative' method. Can anyone check this carefully? + +void Dsp1::multiply2(int16 *input, int16 *output) +{ + int16& Multiplicand = input[0]; + int16& Multiplier = input[1]; + int16& Product = output[0]; + + Product = (Multiplicand * Multiplier >> 15)+1; +} + +////////////////////////////////////////////////////////////////// + +// This command determines the inverse of a floating point decimal number. + +void Dsp1::inverse(int16 *input, int16 *output) +{ + int16& Coefficient = input[0]; + int16& Exponent = input[1]; + int16& iCoefficient = output[0]; + int16& iExponent = output[1]; + + inverse(Coefficient, Exponent, iCoefficient, iExponent); +} + +////////////////////////////////////////////////////////////////// + +// Vector component calculation. Determines the X and Y components for a +// two-dimensional vector whose size and direction is known. +// Y = Radius * sin(Angle) +// X = Radius * cos(Angle) + +void Dsp1::triangle(int16 *input, int16 *output) +{ + int16& Angle = input[0]; + int16& Radius = input[1]; + int16& Y = output[0]; + int16& X = output[1]; + + Y = sin(Angle) * Radius >> 15; + X = cos(Angle) * Radius >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Determines the squared norm of a vector (X,Y,Z) +// The output is Radius = X^2+Y^2+Z^2 (double integer) + +void Dsp1::radius(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& RadiusLow = output[0]; + int16& RadiusHigh = output[1]; + + int32 Radius; + + Radius = (X * X + Y * Y + Z * Z) << 1; + RadiusLow = static_cast(Radius); + RadiusHigh = static_cast(Radius>>16); +} + +////////////////////////////////////////////////////////////////// + +// Vector size comparison. This command compares the size of the vector (X,Y,Z) and the distance (R) +// from a particular point, and so may be used to determine if a point is within the sphere or radius R. +// The output is D = X^2+Y^2+Z^2-R^2 + +void Dsp1::range(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& Radius = input[3]; + int16& Range = output[0]; + + Range = (X * X + Y * Y + Z * Z - Radius * Radius) >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Vector size comparison. 'Alternative' method. + +void Dsp1::range2(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& Radius = input[3]; + int16& Range = output[0]; + + Range = ((X * X + Y * Y + Z * Z - Radius * Radius) >> 15) + 1; +} + +////////////////////////////////////////////////////////////////// + +// This command calculates the norm of a (X,Y,Z) vector, or the distance from +// the point (X,Y,Z) to (0,0,0), as you prefer to see it. +// Distance = sqrt(X^2+Y^2+Z^2) +// The square root of a number 'a' is calculated by doing this: you +// write 'a' as b*2^2n, with 'b' between 1/4 and 1; then, you calculate +// c=sqrt(b) by using lineal interpolation between points of a +// look-up table and, finally, you output the result as c*2^n. + +void Dsp1::distance(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& Distance = output[0]; + + int32 Radius = X * X + Y * Y + Z * Z; + + if (Radius == 0) Distance = 0; + else + { + int16 C, E; + normalizeDouble(Radius, C, E); + if (E & 1) C = C * 0x4000 >> 15; + + int16 Pos = C * 0x0040 >> 15; + + int16 Node1 = DataRom[0x00d5 + Pos]; + int16 Node2 = DataRom[0x00d6 + Pos]; + + Distance = ((Node2 - Node1) * (C & 0x1ff) >> 9) + Node1; + +#if DSP1_VERSION < 0x0102 + if (Pos & 1) Distance -= (Node2 - Node1); +#endif + Distance >>= (E >> 1); + } +} + +////////////////////////////////////////////////////////////////// + +// Determines the (X2, Y2) coordinates obtained by rotating (X1, Y1) +// clockwise for an angle 'Angle'. The official documentation says +// 'counterclockwise', but it's obviously wrong (surprise! :P) +// +// In matrix notation: +// |X2| |cos(Angle) sin(Angle)| |X1| +// | | = | | | | +// |Y2| |-sin(Angle cos(Angle)| |Y1| + +void Dsp1::rotate(int16 *input, int16 *output) +{ + int16& Angle = input[0]; + int16& X1 = input[1]; + int16& Y1 = input[2]; + int16& X2 = output[0]; + int16& Y2 = output[1]; + + X2 = (Y1 * sin(Angle) >> 15) + (X1 * cos(Angle) >> 15); + Y2 = (Y1 * cos(Angle) >> 15) - (X1 * sin(Angle) >> 15); +} + +////////////////////////////////////////////////////////////////// + +// Calculate the coordinates (X2, Y2, Z2) obtained when rotating (X1, Y1, Z1) +// three-dimensionally. Rotation is done in the order of Az around the Z axis, +// Ay around the Y axis and Ax around the X axis. As occur with the "attitude" commands +// (see comments in the "gyrate" command), this doesn't match what explained in +// the official documentation, but it's coherent with what it is done in the "attitude" +// command (but not with the "gyrate" command). +// +// In matrix notation: +// |X2| |1 0 0 | |cosRy 0 -sinRy| | cosRz sinRz 0| |X1| +// |Y2| = |0 cosRx sinRx| | 0 1 0 | |-sinRz cosRz 0| |Y1| +// |Z2| |0 -sinRx cosRx| |sinRy 0 cosRy| | 0 0 1| |Z1| + +void Dsp1::polar(int16 *input, int16 *output) +{ + int16& Az = input[0]; + int16& Ay = input[1]; + int16& Ax = input[2]; + int16& X1 = input[3]; + int16& Y1 = input[4]; + int16& Z1 = input[5]; + int16& X2 = output[0]; + int16& Y2 = output[1]; + int16& Z2 = output[2]; + + int16 X, Y, Z; + + // Rotate Around Z + X = (Y1 * sin(Az) >> 15) + (X1 * cos(Az) >> 15); + Y = (Y1 * cos(Az) >> 15) - (X1 * sin(Az) >> 15); + X1 = X; Y1 = Y; + + // Rotate Around Y + Z = (X1 * sin(Ay) >> 15) + (Z1 * cos(Ay) >> 15); + X = (X1 * cos(Ay) >> 15) - (Z1 * sin(Ay) >> 15); + X2 = X; Z1 = Z; + + // Rotate Around X + Y = (Z1 * sin(Ax) >> 15) + (Y1 * cos(Ax) >> 15); + Z = (Z1 * cos(Ax) >> 15) - (Y1 * sin(Ax) >> 15); + Y2 = Y; Z2 = Z; +} + +////////////////////////////////////////////////////////////////// + +// Set up the elements of an "attitude matrix" (there are other ones): +// S | cosRz sinRz 0| |cosRy 0 -sinRy| |1 0 0 | +// MatrixA = - |-sinRz cosRz 0| | 0 1 0 | |0 cosRx sinRx| +// 2 | 0 0 1| |sinRy 0 cosRy| |0 -sinRx cosRx| +// This matrix is thought to be used within the following framework: +// let's suppose we define positive rotations around a system of orthogonal axes in this manner: +// a rotation of +90 degrees around axis3 converts axis2 into axis1 +// a rotation of +90 degrees around axis2 converts axis1 into axis3 +// a rotation of +90 degrees around axis1 converts axis3 into axis2 +// and let's suppose that we have defined a new orthonormal axes system (FLU) +// by doing the following operations about the standard one (XYZ): +// first rotating the XYZ system around Z by an angle Rz (obtaining X'Y'Z'), +// then rotating the resulting system around Y by an angle Ry (obtaining X''Y''Z'') +// and, finally, rotating the resulting system around X by an angle Rx (obtaining FLU) +// This FLU (forward/left/up) system represents an "attitude" and, then, the matrix here defined +// is the change of coordinates matrix that transform coordinates in the FLU +// system (the "object coordinates") into the standard XYZ system (the "global coordinates"), +// multiplied by a scale factor S/2, that is: +// |x| S |f| +// |y| * - = MatrixA * |l| +// |z| 2 |u| +// In a similar way, if we use the transpose of the matrix, we can transform global coordinates +// into object coordinates: +// |f| S |x| +// |l| * - = MatrixA_transposed * |y| +// |u| 2 |z| +// +// input[0]: S +// input[1]: Rz +// input[2]: Ry +// input[3]: Rx + +void Dsp1::attitudeA(int16 *input, int16 *output) +{ + int16& S = input[0]; + int16& Rz = input[1]; + int16& Ry = input[2]; + int16& Rx = input[3]; + + int16 SinRz = sin(Rz); + int16 CosRz = cos(Rz); + int16 SinRy = sin(Ry); + int16 CosRy = cos(Ry); + int16 SinRx = sin(Rx); + int16 CosRx = cos(Rx); + + S >>= 1; + + shared.MatrixA[0][0] = (S * CosRz >> 15) * CosRy >> 15; + shared.MatrixA[0][1] = ((S * SinRz >> 15) * CosRx >> 15) + (((S * CosRz >> 15) * SinRx >> 15) * SinRy >> 15); + shared.MatrixA[0][2] = ((S * SinRz >> 15) * SinRx >> 15) - (((S * CosRz >> 15) * CosRx >> 15) * SinRy >> 15); + + shared.MatrixA[1][0] = -((S * SinRz >> 15) * CosRy >> 15); + shared.MatrixA[1][1] = ((S * CosRz >> 15) * CosRx >> 15) - (((S * SinRz >> 15) * SinRx >> 15) * SinRy >> 15); + shared.MatrixA[1][2] = ((S * CosRz >> 15) * SinRx >> 15) + (((S * SinRz >> 15) * CosRx >> 15) * SinRy >> 15); + + shared.MatrixA[2][0] = S * SinRy >> 15; + shared.MatrixA[2][1] = -((S * SinRx >> 15) * CosRy >> 15); + shared.MatrixA[2][2] = (S * CosRx >> 15) * CosRy >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Same than 'attitudeA', but with a difference attitude matrix (matrixB) + +void Dsp1::attitudeB(int16 *input, int16 *output) +{ + int16& S = input[0]; + int16& Rz = input[1]; + int16& Ry = input[2]; + int16& Rx = input[3]; + + int16 SinRz = sin(Rz); + int16 CosRz = cos(Rz); + int16 SinRy = sin(Ry); + int16 CosRy = cos(Ry); + int16 SinRx = sin(Rx); + int16 CosRx = cos(Rx); + + S >>= 1; + + shared.MatrixB[0][0] = (S * CosRz >> 15) * CosRy >> 15; + shared.MatrixB[0][1] = ((S * SinRz >> 15) * CosRx >> 15) + (((S * CosRz >> 15) * SinRx >> 15) * SinRy >> 15); + shared.MatrixB[0][2] = ((S * SinRz >> 15) * SinRx >> 15) - (((S * CosRz >> 15) * CosRx >> 15) * SinRy >> 15); + + shared.MatrixB[1][0] = -((S * SinRz >> 15) * CosRy >> 15); + shared.MatrixB[1][1] = ((S * CosRz >> 15) * CosRx >> 15) - (((S * SinRz >> 15) * SinRx >> 15) * SinRy >> 15); + shared.MatrixB[1][2] = ((S * CosRz >> 15) * SinRx >> 15) + (((S * SinRz >> 15) * CosRx >> 15) * SinRy >> 15); + + shared.MatrixB[2][0] = S * SinRy >> 15; + shared.MatrixB[2][1] = -((S * SinRx >> 15) * CosRy >> 15); + shared.MatrixB[2][2] = (S * CosRx >> 15) * CosRy >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Same than 'attitudeA', but with a difference attitude matrix (matrixC) + +void Dsp1::attitudeC(int16 *input, int16 *output) +{ + int16& S = input[0]; + int16& Rz = input[1]; + int16& Ry = input[2]; + int16& Rx = input[3]; + + int16 SinRz = sin(Rz); + int16 CosRz = cos(Rz); + int16 SinRy = sin(Ry); + int16 CosRy = cos(Ry); + int16 SinRx = sin(Rx); + int16 CosRx = cos(Rx); + + S >>= 1; + + shared.MatrixC[0][0] = (S * CosRz >> 15) * CosRy >> 15; + shared.MatrixC[0][1] = ((S * SinRz >> 15) * CosRx >> 15) + (((S * CosRz >> 15) * SinRx >> 15) * SinRy >> 15); + shared.MatrixC[0][2] = ((S * SinRz >> 15) * SinRx >> 15) - (((S * CosRz >> 15) * CosRx >> 15) * SinRy >> 15); + + shared.MatrixC[1][0] = -((S * SinRz >> 15) * CosRy >> 15); + shared.MatrixC[1][1] = ((S * CosRz >> 15) * CosRx >> 15) - (((S * SinRz >> 15) * SinRx >> 15) * SinRy >> 15); + shared.MatrixC[1][2] = ((S * CosRz >> 15) * SinRx >> 15) + (((S * SinRz >> 15) * CosRx >> 15) * SinRy >> 15); + + shared.MatrixC[2][0] = S * SinRy >> 15; + shared.MatrixC[2][1] = -((S * SinRx >> 15) * CosRy >> 15); + shared.MatrixC[2][2] = (S * CosRx >> 15) * CosRy >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Convert global coordinates (X,Y,Z) to object coordinates (F,L,U) +// See the comment in "attitudeA" for a explanation about the calculation. +// +// input[0]: X ; input[1]: Y ; input[2]: Z +// output[0]: F ; output[1]: L ; output[2]: U + +void Dsp1::objectiveA(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& F = output[0]; + int16& L = output[1]; + int16& U = output[2]; + + F = (shared.MatrixA[0][0] * X >> 15) + (shared.MatrixA[1][0] * Y >> 15) + (shared.MatrixA[2][0] * Z >> 15); + L = (shared.MatrixA[0][1] * X >> 15) + (shared.MatrixA[1][1] * Y >> 15) + (shared.MatrixA[2][1] * Z >> 15); + U = (shared.MatrixA[0][2] * X >> 15) + (shared.MatrixA[1][2] * Y >> 15) + (shared.MatrixA[2][2] * Z >> 15); +} + +////////////////////////////////////////////////////////////////// + +// Same than 'objectiveA', but for the 'B' attitude + +void Dsp1::objectiveB(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& F = output[0]; + int16& L = output[1]; + int16& U = output[2]; + + F = (shared.MatrixB[0][0] * X >> 15) + (shared.MatrixB[1][0] * Y >> 15) + (shared.MatrixB[2][0] * Z >> 15); + L = (shared.MatrixB[0][1] * X >> 15) + (shared.MatrixB[1][1] * Y >> 15) + (shared.MatrixB[2][1] * Z >> 15); + U = (shared.MatrixB[0][2] * X >> 15) + (shared.MatrixB[1][2] * Y >> 15) + (shared.MatrixB[2][2] * Z >> 15); +} + +////////////////////////////////////////////////////////////////// + +// Same than 'objectiveA', but for the 'C' attitude + +void Dsp1::objectiveC(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& F = output[0]; + int16& L = output[1]; + int16& U = output[2]; + + F = (shared.MatrixC[0][0] * X >> 15) + (shared.MatrixC[1][0] * Y >> 15) + (shared.MatrixC[2][0] * Z >> 15); + L = (shared.MatrixC[0][1] * X >> 15) + (shared.MatrixC[1][1] * Y >> 15) + (shared.MatrixC[2][1] * Z >> 15); + U = (shared.MatrixC[0][2] * X >> 15) + (shared.MatrixC[1][2] * Y >> 15) + (shared.MatrixC[2][2] * Z >> 15); +} + +////////////////////////////////////////////////////////////////// + +// Convert object coordinates (F,L,U) to object coordinates (X,Y,Z) +// See the comment in "attitudeA" for a explanation about the calculation. +// +// input[0]: F ; input[1]: L ; input[2]: U +// output[0]: X ; output[1]: Y ; output[2]: Z + +void Dsp1::subjectiveA(int16 *input, int16 *output) +{ + int16& F = input[0]; + int16& L = input[1]; + int16& U = input[2]; + int16& X = output[0]; + int16& Y = output[1]; + int16& Z = output[2]; + + X = (shared.MatrixA[0][0] * F >> 15) + (shared.MatrixA[0][1] * L >> 15) + (shared.MatrixA[0][2] * U >> 15); + Y = (shared.MatrixA[1][0] * F >> 15) + (shared.MatrixA[1][1] * L >> 15) + (shared.MatrixA[1][2] * U >> 15); + Z = (shared.MatrixA[2][0] * F >> 15) + (shared.MatrixA[2][1] * L >> 15) + (shared.MatrixA[2][2] * U >> 15); +} + +////////////////////////////////////////////////////////////////// + +// Same than 'subjectiveA', but for the 'B' attitude + +void Dsp1::subjectiveB(int16 *input, int16 *output) +{ + int16& F = input[0]; + int16& L = input[1]; + int16& U = input[2]; + int16& X = output[0]; + int16& Y = output[1]; + int16& Z = output[2]; + + X = (shared.MatrixB[0][0] * F >> 15) + (shared.MatrixB[0][1] * L >> 15) + (shared.MatrixB[0][2] * U >> 15); + Y = (shared.MatrixB[1][0] * F >> 15) + (shared.MatrixB[1][1] * L >> 15) + (shared.MatrixB[1][2] * U >> 15); + Z = (shared.MatrixB[2][0] * F >> 15) + (shared.MatrixB[2][1] * L >> 15) + (shared.MatrixB[2][2] * U >> 15); +} + +////////////////////////////////////////////////////////////////// + +// Same than 'subjectiveA', but for the 'C' attitude + +void Dsp1::subjectiveC(int16 *input, int16 *output) +{ + int16& F = input[0]; + int16& L = input[1]; + int16& U = input[2]; + int16& X = output[0]; + int16& Y = output[1]; + int16& Z = output[2]; + + X = (shared.MatrixC[0][0] * F >> 15) + (shared.MatrixC[0][1] * L >> 15) + (shared.MatrixC[0][2] * U >> 15); + Y = (shared.MatrixC[1][0] * F >> 15) + (shared.MatrixC[1][1] * L >> 15) + (shared.MatrixC[1][2] * U >> 15); + Z = (shared.MatrixC[2][0] * F >> 15) + (shared.MatrixC[2][1] * L >> 15) + (shared.MatrixC[2][2] * U >> 15); +} + +////////////////////////////////////////////////////////////////// + +// This command calculates the inner product (S) of a vector (X,Y,Z) and +// the first column of MatrixA. It should be noted that that first column +// represent the global coordinates of an unity vector in the forward +// direction in the object coordinate system (coordinates (1,0,0) in the FLU +// axes system). +// +// input[0]: X ; input[1]: Y ; input[2]: Z +// output[0]: S + +void Dsp1::scalarA(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& S = output[0]; + + S = (X * shared.MatrixA[0][0] + Y * shared.MatrixA[1][0] + Z * shared.MatrixA[2][0]) >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Same than 'scalarA', but for the 'B' attitude + +void Dsp1::scalarB(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& S = output[0]; + + S = (X * shared.MatrixB[0][0] + Y * shared.MatrixB[1][0] + Z * shared.MatrixB[2][0]) >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Same than 'scalarA', but for the 'C' attitude + +void Dsp1::scalarC(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& S = output[0]; + + S = (X * shared.MatrixC[0][0] + Y * shared.MatrixC[1][0] + Z * shared.MatrixC[2][0]) >> 15; +} + +////////////////////////////////////////////////////////////////// + +// This command determines the final attitude angles after the body with attitude angles (Ax, Ay, Az) with +// respect to the global coordinates is rotated by the minor angular displacements (DeltaF, DeltaL, DeltaU). +// It means that the XYZ axes are rotated by (Ax, Ay, Az) to obtain the FLU axes and, then, these +// are rotated by (DeltaF, DeltaL, DeltaU). The command calculates and return the new FLU angles respect to the +// XYZ system (Rx, Ry, Rz) +// The formulae are: +// Rx = Ax + (DeltaU*sin(Ay)+DeltaF*cos(Ay)) +// Ry = Ay + DeltaL - tan(Ax)*(DeltaU*cos(Ay)+DeltaF*sin(Ay)) +// Rz = Az + sec(Ax)*(DeltaU*cos(Ay)-DeltaF*sin(Ay)) +// +// Now the discussion: according to the official documentation, as described in various commands, you pass from +// XYZ to FLU by doing the rotations in the order Y, X, Z. In this command, the formulae are coherent with the +// fact that Y is the first axis to do a rotation around it. However, in the "attitude" command, while the official +// document describe it that way, we have discovered, when reverse engineering the command, that the calculated +// matrix do the rotation around Y in the second place. This incoherent behaviour of various commands is, in my +// opinion, a pretty severe implementation error. However, if you only use small "minor displacements", the error term +// introduced by that incoherence should be almost negligible. + +void Dsp1::gyrate(int16 *input, int16 *output) +{ + int16& Az = input[0]; + int16& Ax = input[1]; + int16& Ay = input[2]; + int16& U = input[3]; + int16& F = input[4]; + int16& L = input[5]; + int16& Rz = output[0]; + int16& Rx = output[1]; + int16& Ry = output[2]; + + int16 CSec, ESec, CSin, C, E; + int16 SinAy = sin(Ay); + int16 CosAy = cos(Ay); + + inverse(cos(Ax), 0, CSec, ESec); + + // Rotation Around Z + normalizeDouble(U * CosAy - F * SinAy, C, E); + + E = ESec - E; + + normalize(C * CSec >> 15, C, E); + + Rz = Az + denormalizeAndClip(C, E); + + // Rotation Around X + Rx = Ax + (U * SinAy >> 15) + (F * CosAy >> 15); + + // Rotation Around Y + normalizeDouble(U * CosAy + F * SinAy, C, E); + + E = ESec - E; + + normalize(sin(Ax), CSin, E); + + normalize(-(C * (CSec * CSin >> 15) >> 15), C, E); + + Ry = Ay + denormalizeAndClip(C, E) + L; +} + +////////////////////////////////////////////////////////////////// + +const int16 Dsp1::MaxAZS_Exp[16] = { + 0x38b4, 0x38b7, 0x38ba, 0x38be, 0x38c0, 0x38c4, 0x38c7, 0x38ca, + 0x38ce, 0x38d0, 0x38d4, 0x38d7, 0x38da, 0x38dd, 0x38e0, 0x38e4 +}; + +////////////////////////////////////////////////////////////////// + + +// Set-up the projection framework. Besides returning some values, it store in RAM some values that +// will be used by the other three projection commands (raster, target an project) +// Input: +// (Fx, Fy, Fz)-> coordinates of base point (global coordinates) +// Lfe-> distance between the base point and the viewpoint (center of projection) +// Les-> distance between the base point and the screen +// Aas-> azimuth angle (0º is east; 90ª is north) +// Azs-> zenith angle (0º is zenith) +// Output: +// Vof-> raster line of imaginary center (whatever it means ;) ) +// Vva-> raster line representing the horizon line +// (Cx, Cy)-> coordinates of the projection of the center of the screen over the ground (ground coordinates) + +void Dsp1::parameter(int16 *input, int16 *output) +{ + int16& Fx = input[0]; + int16& Fy = input[1]; + int16& Fz = input[2]; + int16& Lfe = input[3]; + int16& Les = input[4]; + int16& Aas = input[5]; + int16& Azs = input[6]; + int16& Vof = output[0]; + int16& Vva = output[1]; + int16& Cx = output[2]; + int16& Cy = output[3]; + + int16 CSec, C, E; + int16 LfeNx, LfeNy, LfeNz; + int16 LesNx, LesNy, LesNz; + + // Copy Zenith angle for clipping + int16 AZS = Azs; + + // Store Les and his coefficient and exponent when normalized + shared.Les = Les; + shared.E_Les=0; + normalize(Les, shared.C_Les, shared.E_Les); + + // Store Sine and Cosine of Azimuth and Zenith angle + shared.SinAas = sin(Aas); + shared.CosAas = cos(Aas); + shared.SinAzs = sin(Azs); + shared.CosAzs = cos(Azs); + + // normal vector to the screen (norm 1, points toward the center of projection) + shared.Nx = shared.SinAzs * -shared.SinAas >> 15; + shared.Ny = shared.SinAzs * shared.CosAas >> 15; + shared.Nz = shared.CosAzs * 0x7fff >> 15; + + // horizontal vector of the screen (Hz=0, norm 1, points toward the right of the screen) + shared.Hx = shared.CosAas*0x7fff>>15; + shared.Hy = shared.SinAas*0x7fff>>15; + + // vertical vector of the screen (norm 1, points toward the top of the screen) + shared.Vx = shared.CosAzs*-shared.SinAas>>15; + shared.Vy = shared.CosAzs*shared.CosAas>>15; + shared.Vz = -shared.SinAzs*0x7fff>>15; + + LfeNx = Lfe*shared.Nx>>15; + LfeNy = Lfe*shared.Ny>>15; + LfeNz = Lfe*shared.Nz>>15; + + // Center of Projection + shared.CentreX = Fx+LfeNx; + shared.CentreY = Fy+LfeNy; + shared.CentreZ = Fz+LfeNz; + + LesNx = Les*shared.Nx>>15; + LesNy = Les*shared.Ny>>15; + LesNz = Les*shared.Nz>>15; + + // center of the screen (global coordinates) + shared.Gx=shared.CentreX-LesNx; + shared.Gy=shared.CentreY-LesNy; + shared.Gz=shared.CentreZ-LesNz; + + + E = 0; + normalize(shared.CentreZ, C, E); + + shared.CentreZ_C = C; + shared.CentreZ_E = E; + + // Determine clip boundary and clip Zenith angle if necessary + // (Why to clip? Maybe to avoid the screen can only show sky with no ground? Only a guess...) + int16 MaxAZS = MaxAZS_Exp[-E]; + + if (AZS < 0) { + MaxAZS = -MaxAZS; + if (AZS < MaxAZS + 1) AZS = MaxAZS + 1; + } else { + if (AZS > MaxAZS) AZS = MaxAZS; + } + + // Store Sine and Cosine of clipped Zenith angle + shared.SinAZS = sin(AZS); + shared.CosAZS = cos(AZS); + + // calculate the separation of (cx, cy) from the projection of + // the 'centre of projection' over the ground... (CentreZ*tg(AZS)) + inverse(shared.CosAZS, 0, shared.SecAZS_C1, shared.SecAZS_E1); + normalize(C * shared.SecAZS_C1 >> 15, C, E); + E += shared.SecAZS_E1; + C = denormalizeAndClip(C, E) * shared.SinAZS >> 15; + + // ... and then take into account the position of the centre of + // projection and the azimuth angle + shared.CentreX += C * shared.SinAas >> 15; + shared.CentreY -= C * shared.CosAas >> 15; + + Cx = shared.CentreX; + Cy = shared.CentreY; + + // Raster number of imaginary center and horizontal line + Vof = 0; + + if ((Azs != AZS) || (Azs == MaxAZS)) + { + // correct vof and vva when Azs is outside the 'non-clipping interval' + // we have only some few Taylor coefficients, so we cannot guess which ones + // are the approximated functions and, what is worse, we don't know why + // the own clipping stuff (and, particularly, this correction) is done + if (Azs == -32768) Azs = -32767; + + C = Azs - MaxAZS; + if (C >= 0) C--; + int16 Aux = ~(C << 2); + + // Vof += x+(1/3)*x^3, where x ranges from 0 to PI/4 when Azs-MaxAZS goes from 0 to 0x2000 + C = Aux * DataRom[0x0328] >> 15; + C = (C * Aux >> 15) + DataRom[0x0327]; + Vof -= (C * Aux >> 15) * Les >> 15; + + // CosAZS *= 1+(1/2)*x^2+(5/24)*x^24, where x ranges from 0 to PI/4 when Azs-MaxAZS goes from 0 to 0x2000 + C = Aux * Aux >> 15; + Aux = (C * DataRom[0x0324] >> 15) + DataRom[0x0325]; + shared.CosAZS += (C * Aux >> 15) * shared.CosAZS >> 15; + } + + // vertical offset of the screen with regard to the horizontal plane + // containing the centre of projection + shared.VOffset = Les * shared.CosAZS >> 15; + + // The horizon line (the line in the screen that is crossed by the horizon plane + // -the horizontal plane containing the 'centre of projection'-), + // will be at distance Les*cotg(AZS) from the centre of the screen. This is difficult + // to explain but easily seen in a graph. To better see it, consider it in this way: + // Les*tg(AZS-90), draw some lines and apply basic trigonometry. ;) + inverse(shared.SinAZS, 0, CSec, E); + normalize(shared.VOffset, C, E); + normalize(C * CSec >> 15, C, E); + + if (C == -32768) { C >>= 1; E++; } + + Vva = denormalizeAndClip(-C, E); + + // Store Secant of clipped Zenith angle + inverse(shared.CosAZS, 0, shared.SecAZS_C2, shared.SecAZS_E2); +} + +////////////////////////////////////////////////////////////////// + +// Calculates the matrix which transform an object situated on a raster line (Vs) into +// his projection over the ground. The modified SecAZS is used here, so +// i don't understand the fine details, but, basically, it's done +// this way: The vertical offset between the point of projection and the +// raster line is calculated (Vs*SinAzs>>15)+VOffset, then the height of +// the center of projection is measured in that units (*CentreZ_C). If, now +// you consider the "reference case" (center of projection at an unit of height), +// the projection of a thin strip containing the raster line will have the same +// width (as the raster line would be on the ground in this case, but will suffer a +// change of scale in height (as the ground and the vertical axis would form an angle of 180º-Azs). +// This scale factor, when the angle 'center of screen-center of projection-raster line' is small, +// can be aproximated by the one of the center of the screen, 1/cos(Azs).(**) (Here is when it's used +// SecAZS). By last, you have to consider the effect of the azimuth angle Aas, and you are done. +// +// Using matrix notation: +// |A B| Centre_ZS | cos(Aas) -sin(Aas)| |1 0| +// ProjectionMatrix = | | = ----------- * | | * | | +// |C D| Vs*sin(Azs) |sin(Aas) cos(Aas)| |0 sec(Azs)| +// +// (**) +// If Les=1, the vertical offset between the center +// of projection and the center of the screen is Cos(Azs); then, if the vertical +// offset is 1, the ratio of the projection over the ground respect to the +// line on the screen is 1/cos(Azs). + +void Dsp1::raster(int16 *input, int16 *output) +{ + int16& Vs = input[0]; + int16& An = output[0]; + int16& Bn = output[1]; + int16& Cn = output[2]; + int16& Dn = output[3]; + + int16 C, E, C1, E1; + + inverse((Vs * shared.SinAzs >> 15) + shared.VOffset, 7, C, E); + + E += shared.CentreZ_E; + C1 = C * shared.CentreZ_C >> 15; + + E1 = E + shared.SecAZS_E2; + + normalize(C1, C, E); + C = denormalizeAndClip(C, E); + + An = C * shared.CosAas >> 15; + Cn = C * shared.SinAas >> 15; + + normalize(C1 * shared.SecAZS_C2 >> 15, C, E1); + C = denormalizeAndClip(C, E1); + + Bn = C * -shared.SinAas >> 15; + Dn = C * shared.CosAas >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Calculate the projection over the ground of a selected point of screen +// It simply apply the projection matrix described in the "Raster" command +// to the vector (H,V) transposed, and add the result to the position of +// the centre of projection. +// The only special point to take into account is the directions on the screen: +// H is positive rightward, but V is positive downward; this is why +// the signs take that configuration + +void Dsp1::target(int16 *input, int16 *output) +{ + int16& H = input[0]; + int16& V = input[1]; + int16& X = output[0]; + int16& Y = output[1]; + + int16 C, E, C1, E1; + + inverse((V * shared.SinAzs >> 15) + shared.VOffset, 8, C, E); + + E += shared.CentreZ_E; + C1 = C * shared.CentreZ_C >> 15; + + E1 = E + shared.SecAZS_E1; + + H <<= 8; + normalize(C1, C, E); + C = denormalizeAndClip(C, E) * H >> 15; + + X = shared.CentreX + (C * shared.CosAas >> 15); + Y = shared.CentreY - (C * shared.SinAas >> 15); + + V <<= 8; + normalize(C1 * shared.SecAZS_C1 >> 15, C, E1); + C = denormalizeAndClip(C, E1) * V >> 15; + + X += C * -shared.SinAas >> 15; + Y += C * shared.CosAas >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Calculation of the projection over the screen (H,V) of an object (X,Y,Z) and his +// 'enlargement ratio' (M). The positive directions on the screen are as described +// in the targe command. M is scaled down by 2^-7, that is, M==0x0100 means ratio 1:1 + + void Dsp1::project(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& H = output[0]; + int16& V = output[1]; + int16& M = output[2]; + + int32 aux, aux4; + int16 E, E2, E3, E4, E5, refE, E6, E7; + int16 C2, C4, C6, C8, C9, C10, C11, C12, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25, C26; + int16 Px, Py, Pz; + + E4=E3=E2=E=E5=0; + + normalizeDouble(int32(X)-shared.Gx, Px, E4); + normalizeDouble(int32(Y)-shared.Gy, Py, E); + normalizeDouble(int32(Z)-shared.Gz, Pz, E3); + Px>>=1; E4--; // to avoid overflows when calculating the scalar products + Py>>=1; E--; + Pz>>=1; E3--; + + refE = (E>15); + C8=- (Py*shared.Ny>>15); + C9=- (Pz*shared.Nz>>15); + C12=C11+C8+C9; // this cannot overflow! + + aux4=C12; // de-normalization with 32-bits arithmetic + refE = 16-refE; // refE can be up to 3 + if (refE>=0) + aux4 <<=(refE); + else + aux4 >>=-(refE); + if (aux4==-1) aux4 = 0; // why? + aux4>>=1; + + aux = static_cast(shared.Les) + aux4; // Les - the scalar product of P with the normal vector of the screen + normalizeDouble(aux, C10, E2); + E2 = 15-E2; + + inverse(C10, 0, C4, E4); + C2=C4*shared.C_Les>>15; // scale factor + + + // H + E7=0; + C16= (Px*shared.Hx>>15); + C20= (Py*shared.Hy>>15); + C17=C16+C20; // scalar product of P with the normalized horizontal vector of the screen... + + C18=C17*C2>>15; // ... multiplied by the scale factor + normalize(C18, C19, E7); + H=denormalizeAndClip(C19, shared.E_Les-E2+refE+E7); + + // V + E6=0; + C21 = Px*shared.Vx>>15; + C22 = Py*shared.Vy>>15; + C23 = Pz*shared.Vz>>15; + C24=C21+C22+C23; // scalar product of P with the normalized vertical vector of the screen... + + C26=C24*C2>>15; // ... multiplied by the scale factor + normalize(C26, C25, E6); + V=denormalizeAndClip(C25, shared.E_Les-E2+refE+E6); + + // M + normalize(C2, C6, E4); + M=denormalizeAndClip(C6, E4+shared.E_Les-E2-7); // M is the scale factor divided by 2^7 +} + +////////////////////////////////////////////////////////////////// + +// Calculate the sine of the input parameter +// this is done by linear interpolation between +// the points of a look-up table + +int16 Dsp1::sin(int16 Angle) +{ + if (Angle < 0) { + if (Angle == -32768) return 0; + return -sin(-Angle); + } + int32 S = SinTable[Angle >> 8] + (MulTable[Angle & 0xff] * SinTable[0x40 + (Angle >> 8)] >> 15); + if (S > 32767) S = 32767; + return (int16) S; +} + +////////////////////////////////////////////////////////////////// + +// Calculate the cosine of the input parameter. +// It's used the same method than in sin(int16) + +int16 Dsp1::cos(int16 Angle) +{ + if (Angle < 0) { + if (Angle == -32768) return -32768; + Angle = -Angle; + } + int32 S = SinTable[0x40 + (Angle >> 8)] - (MulTable[Angle & 0xff] * SinTable[Angle >> 8] >> 15); + if (S < -32768) S = -32767; + return (int16) S; +} + +////////////////////////////////////////////////////////////////// + +// Determines the inverse of a floating point decimal number +// iCoefficient*2^iExponent = 1/(Coefficient*2^Exponent), with the output +// normalized (iCoefficient represents a number whose absolute value is between 1/2 and 1) +// To invert 'Coefficient' a first initial guess is taken from a look-up table +// and, then, two iterations of the Newton method (applied to the function +// f(x)=1/(2*x)-Coefficient) are done. This results in a close approximation (iCoefficient) to a number 'y' +// that verify Coefficient*y=1/2. This is why you have to correct the exponent by one +// unit at the end. + +void Dsp1::inverse(int16 Coefficient, int16 Exponent, int16 &iCoefficient, int16 &iExponent) +{ + // Step One: Division by Zero + if (Coefficient == 0x0000) + { + iCoefficient = 0x7fff; + iExponent = 0x002f; + } + else + { + int16 Sign = 1; + + // Step Two: Remove Sign + if (Coefficient < 0) + { + if (Coefficient < -32767) Coefficient = -32767; + Coefficient = -Coefficient; + Sign = -1; + } + + // Step Three: Normalize + while (Coefficient < 0x4000) + { + Coefficient <<= 1; + Exponent--; + } + + // Step Four: Special Case + if (Coefficient == 0x4000) + if (Sign == 1) iCoefficient = 0x7fff; + else { + iCoefficient = -0x4000; + Exponent--; + } + else { + // Step Five: Initial Guess + int16 i = DataRom[((Coefficient - 0x4000) >> 7) + 0x0065]; + + // Step Six: Iterate Newton's Method + i = (i + (-i * (Coefficient * i >> 15) >> 15)) << 1; + i = (i + (-i * (Coefficient * i >> 15) >> 15)) << 1; + + iCoefficient = i * Sign; + } + + iExponent = 1 - Exponent; + } +} + +////////////////////////////////////////////////////////////////// + +int16 Dsp1::denormalizeAndClip(int16 C, int16 E) +{ + if (E > 0) { + if (C > 0) return 32767; else if (C < 0) return -32767; + } else { + if (E < 0) return C * DataRom[0x0031 + E] >> 15; + } + return C; +} + +////////////////////////////////////////////////////////////////// + +// Normalize the input number (m), understood as ranging from -1 to 1, +// to the form: Coefficient*2^Exponent, +// where the absolute value of Coefficient is >= 1/2 +// (Coefficient>=0x4000 or Coefficient <= (int16)0xc001) + +void Dsp1::normalize(int16 m, int16 &Coefficient, int16 &Exponent) +{ + int16 i = 0x4000; + int16 e = 0; + + if (m < 0) + while ((m & i) && i) + { + i >>= 1; + e++; + } + else + while (!(m & i) && i) + { + i >>= 1; + e++; + } + + if (e > 0) + Coefficient = m * DataRom[0x21 + e] << 1; + else + Coefficient = m; + + Exponent -= e; +} + +////////////////////////////////////////////////////////////////// + +// Same than 'normalize' but with an int32 input + +void Dsp1::normalizeDouble(int32 Product, int16 &Coefficient, int16 &Exponent) +{ + int16 n = Product & 0x7fff; + int16 m = Product >> 15; + int16 i = 0x4000; + int16 e = 0; + + if (m < 0) + while ((m & i) && i) + { + i >>= 1; + e++; + } + else + while (!(m & i) && i) + { + i >>= 1; + e++; + } + + if (e > 0) + { + Coefficient = m * DataRom[0x0021 + e] << 1; + + if (e < 15) + Coefficient += n * DataRom[0x0040 - e] >> 15; + else + { + i = 0x4000; + + if (m < 0) + while ((n & i) && i) + { + i >>= 1; + e++; + } + else + while (!(n & i) && i) + { + i >>= 1; + e++; + } + + if (e > 15) + Coefficient = n * DataRom[0x0012 + e] << 1; + else + Coefficient += n; + } + } + else + Coefficient = m; + + Exponent = e; +} + +////////////////////////////////////////////////////////////////// + +// Shift to the right + +int16 Dsp1::shiftR(int16 C, int16 E) +{ + return (C * DataRom[0x0031 + E] >> 15); +} + +////////////////////////////////////////////////////////////////// + +// this is, indeed, only part of the Data ROM +const int16 Dsp1::SinTable[256] = { + 0x0000, 0x0324, 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2, + 0x18f8, 0x1c0b, 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11, + 0x30fb, 0x33de, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a, + 0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842, + 0x5a82, 0x5cb4, 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6, + 0x6a6d, 0x6c24, 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504, + 0x7641, 0x776c, 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3, + 0x7d8a, 0x7e1d, 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6, + 0x7fff, 0x7ff6, 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, + 0x7d8a, 0x7ce3, 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, + 0x7641, 0x7504, 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, + 0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, + 0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, + 0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, + 0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, + 0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, + -0x0000, -0x0324, -0x0647, -0x096a, -0x0c8b, -0x0fab, -0x12c8, -0x15e2, + -0x18f8, -0x1c0b, -0x1f19, -0x2223, -0x2528, -0x2826, -0x2b1f, -0x2e11, + -0x30fb, -0x33de, -0x36ba, -0x398c, -0x3c56, -0x3f17, -0x41ce, -0x447a, + -0x471c, -0x49b4, -0x4c3f, -0x4ebf, -0x5133, -0x539b, -0x55f5, -0x5842, + -0x5a82, -0x5cb4, -0x5ed7, -0x60ec, -0x62f2, -0x64e8, -0x66cf, -0x68a6, + -0x6a6d, -0x6c24, -0x6dca, -0x6f5f, -0x70e2, -0x7255, -0x73b5, -0x7504, + -0x7641, -0x776c, -0x7884, -0x798a, -0x7a7d, -0x7b5d, -0x7c29, -0x7ce3, + -0x7d8a, -0x7e1d, -0x7e9d, -0x7f09, -0x7f62, -0x7fa7, -0x7fd8, -0x7ff6, + -0x7fff, -0x7ff6, -0x7fd8, -0x7fa7, -0x7f62, -0x7f09, -0x7e9d, -0x7e1d, + -0x7d8a, -0x7ce3, -0x7c29, -0x7b5d, -0x7a7d, -0x798a, -0x7884, -0x776c, + -0x7641, -0x7504, -0x73b5, -0x7255, -0x70e2, -0x6f5f, -0x6dca, -0x6c24, + -0x6a6d, -0x68a6, -0x66cf, -0x64e8, -0x62f2, -0x60ec, -0x5ed7, -0x5cb4, + -0x5a82, -0x5842, -0x55f5, -0x539b, -0x5133, -0x4ebf, -0x4c3f, -0x49b4, + -0x471c, -0x447a, -0x41ce, -0x3f17, -0x3c56, -0x398c, -0x36ba, -0x33de, + -0x30fb, -0x2e11, -0x2b1f, -0x2826, -0x2528, -0x2223, -0x1f19, -0x1c0b, + -0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324}; + + ////////////////////////////////////////////////////////////////// + +// Optimised for Performance + const int16 Dsp1::MulTable[256] = { + 0x0000, 0x0003, 0x0006, 0x0009, 0x000c, 0x000f, 0x0012, 0x0015, + 0x0019, 0x001c, 0x001f, 0x0022, 0x0025, 0x0028, 0x002b, 0x002f, + 0x0032, 0x0035, 0x0038, 0x003b, 0x003e, 0x0041, 0x0045, 0x0048, + 0x004b, 0x004e, 0x0051, 0x0054, 0x0057, 0x005b, 0x005e, 0x0061, + 0x0064, 0x0067, 0x006a, 0x006d, 0x0071, 0x0074, 0x0077, 0x007a, + 0x007d, 0x0080, 0x0083, 0x0087, 0x008a, 0x008d, 0x0090, 0x0093, + 0x0096, 0x0099, 0x009d, 0x00a0, 0x00a3, 0x00a6, 0x00a9, 0x00ac, + 0x00af, 0x00b3, 0x00b6, 0x00b9, 0x00bc, 0x00bf, 0x00c2, 0x00c5, + 0x00c9, 0x00cc, 0x00cf, 0x00d2, 0x00d5, 0x00d8, 0x00db, 0x00df, + 0x00e2, 0x00e5, 0x00e8, 0x00eb, 0x00ee, 0x00f1, 0x00f5, 0x00f8, + 0x00fb, 0x00fe, 0x0101, 0x0104, 0x0107, 0x010b, 0x010e, 0x0111, + 0x0114, 0x0117, 0x011a, 0x011d, 0x0121, 0x0124, 0x0127, 0x012a, + 0x012d, 0x0130, 0x0133, 0x0137, 0x013a, 0x013d, 0x0140, 0x0143, + 0x0146, 0x0149, 0x014d, 0x0150, 0x0153, 0x0156, 0x0159, 0x015c, + 0x015f, 0x0163, 0x0166, 0x0169, 0x016c, 0x016f, 0x0172, 0x0175, + 0x0178, 0x017c, 0x017f, 0x0182, 0x0185, 0x0188, 0x018b, 0x018e, + 0x0192, 0x0195, 0x0198, 0x019b, 0x019e, 0x01a1, 0x01a4, 0x01a8, + 0x01ab, 0x01ae, 0x01b1, 0x01b4, 0x01b7, 0x01ba, 0x01be, 0x01c1, + 0x01c4, 0x01c7, 0x01ca, 0x01cd, 0x01d0, 0x01d4, 0x01d7, 0x01da, + 0x01dd, 0x01e0, 0x01e3, 0x01e6, 0x01ea, 0x01ed, 0x01f0, 0x01f3, + 0x01f6, 0x01f9, 0x01fc, 0x0200, 0x0203, 0x0206, 0x0209, 0x020c, + 0x020f, 0x0212, 0x0216, 0x0219, 0x021c, 0x021f, 0x0222, 0x0225, + 0x0228, 0x022c, 0x022f, 0x0232, 0x0235, 0x0238, 0x023b, 0x023e, + 0x0242, 0x0245, 0x0248, 0x024b, 0x024e, 0x0251, 0x0254, 0x0258, + 0x025b, 0x025e, 0x0261, 0x0264, 0x0267, 0x026a, 0x026e, 0x0271, + 0x0274, 0x0277, 0x027a, 0x027d, 0x0280, 0x0284, 0x0287, 0x028a, + 0x028d, 0x0290, 0x0293, 0x0296, 0x029a, 0x029d, 0x02a0, 0x02a3, + 0x02a6, 0x02a9, 0x02ac, 0x02b0, 0x02b3, 0x02b6, 0x02b9, 0x02bc, + 0x02bf, 0x02c2, 0x02c6, 0x02c9, 0x02cc, 0x02cf, 0x02d2, 0x02d5, + 0x02d8, 0x02db, 0x02df, 0x02e2, 0x02e5, 0x02e8, 0x02eb, 0x02ee, + 0x02f1, 0x02f5, 0x02f8, 0x02fb, 0x02fe, 0x0301, 0x0304, 0x0307, + 0x030b, 0x030e, 0x0311, 0x0314, 0x0317, 0x031a, 0x031d, 0x0321}; + +////////////////////////////////////////////////////////////////// + +// Data ROM, as logged from a DSP-1B with the 0x1f command; +// it contains the tables and constants used by the commands. +// The tables used are: two shift tables (0x022-0x031 and 0x031-0x040 -this last one +// with an error in 0x03c which has survived to all the DSP-1 revisions-); a inverse +// table (used as initial guess) at 0x065-0x0e4; a square root table (used also +// as initial guess) at 0x0e5-0x115; two sin and cos tables (used as nodes to construct +// a interpolation curve) at, respectively, 0x116-0x197 and 0x196-0x215. +// As a curiosity, in the positions 0x21c-0x31c it's contained a +// 257-points arccos table that, apparently, have been not used anywhere +// (maybe for the MaxAZS_Exp table?). + const uint16 Dsp1::DataRom[1024] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, + 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, + 0x4000, 0x7fff, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, + 0x0100, 0x0080, 0x0040, 0x0020, 0x0001, 0x0008, 0x0004, 0x0002, + 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8000, 0xffe5, 0x0100, 0x7fff, 0x7f02, 0x7e08, + 0x7d12, 0x7c1f, 0x7b30, 0x7a45, 0x795d, 0x7878, 0x7797, 0x76ba, + 0x75df, 0x7507, 0x7433, 0x7361, 0x7293, 0x71c7, 0x70fe, 0x7038, + 0x6f75, 0x6eb4, 0x6df6, 0x6d3a, 0x6c81, 0x6bca, 0x6b16, 0x6a64, + 0x69b4, 0x6907, 0x685b, 0x67b2, 0x670b, 0x6666, 0x65c4, 0x6523, + 0x6484, 0x63e7, 0x634c, 0x62b3, 0x621c, 0x6186, 0x60f2, 0x6060, + 0x5fd0, 0x5f41, 0x5eb5, 0x5e29, 0x5d9f, 0x5d17, 0x5c91, 0x5c0c, + 0x5b88, 0x5b06, 0x5a85, 0x5a06, 0x5988, 0x590b, 0x5890, 0x5816, + 0x579d, 0x5726, 0x56b0, 0x563b, 0x55c8, 0x5555, 0x54e4, 0x5474, + 0x5405, 0x5398, 0x532b, 0x52bf, 0x5255, 0x51ec, 0x5183, 0x511c, + 0x50b6, 0x5050, 0x4fec, 0x4f89, 0x4f26, 0x4ec5, 0x4e64, 0x4e05, + 0x4da6, 0x4d48, 0x4cec, 0x4c90, 0x4c34, 0x4bda, 0x4b81, 0x4b28, + 0x4ad0, 0x4a79, 0x4a23, 0x49cd, 0x4979, 0x4925, 0x48d1, 0x487f, + 0x482d, 0x47dc, 0x478c, 0x473c, 0x46ed, 0x469f, 0x4651, 0x4604, + 0x45b8, 0x456c, 0x4521, 0x44d7, 0x448d, 0x4444, 0x43fc, 0x43b4, + 0x436d, 0x4326, 0x42e0, 0x429a, 0x4255, 0x4211, 0x41cd, 0x4189, + 0x4146, 0x4104, 0x40c2, 0x4081, 0x4040, 0x3fff, 0x41f7, 0x43e1, + 0x45bd, 0x478d, 0x4951, 0x4b0b, 0x4cbb, 0x4e61, 0x4fff, 0x5194, + 0x5322, 0x54a9, 0x5628, 0x57a2, 0x5914, 0x5a81, 0x5be9, 0x5d4a, + 0x5ea7, 0x5fff, 0x6152, 0x62a0, 0x63ea, 0x6530, 0x6672, 0x67b0, + 0x68ea, 0x6a20, 0x6b53, 0x6c83, 0x6daf, 0x6ed9, 0x6fff, 0x7122, + 0x7242, 0x735f, 0x747a, 0x7592, 0x76a7, 0x77ba, 0x78cb, 0x79d9, + 0x7ae5, 0x7bee, 0x7cf5, 0x7dfa, 0x7efe, 0x7fff, 0x0000, 0x0324, + 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2, 0x18f8, 0x1c0b, + 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11, 0x30fb, 0x33de, + 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a, 0x471c, 0x49b4, + 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842, 0x5a82, 0x5cb4, + 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6, 0x6a6d, 0x6c24, + 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504, 0x7641, 0x776c, + 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3, 0x7d8a, 0x7e1d, + 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6, 0x7fff, 0x7ff6, + 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, 0x7d8a, 0x7ce3, + 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, 0x7641, 0x7504, + 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, 0x6a6d, 0x68a6, + 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, 0x5a82, 0x5842, + 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, 0x471c, 0x447a, + 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, 0x30fb, 0x2e11, + 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, 0x18f8, 0x15e2, + 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, 0x7fff, 0x7ff6, + 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, 0x7d8a, 0x7ce3, + 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, 0x7641, 0x7504, + 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, 0x6a6d, 0x68a6, + 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, 0x5a82, 0x5842, + 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, 0x471c, 0x447a, + 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, 0x30fb, 0x2e11, + 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, 0x18f8, 0x15e2, + 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, 0x0000, 0xfcdc, + 0xf9b9, 0xf696, 0xf375, 0xf055, 0xed38, 0xea1e, 0xe708, 0xe3f5, + 0xe0e7, 0xdddd, 0xdad8, 0xd7da, 0xd4e1, 0xd1ef, 0xcf05, 0xcc22, + 0xc946, 0xc674, 0xc3aa, 0xc0e9, 0xbe32, 0xbb86, 0xb8e4, 0xb64c, + 0xb3c1, 0xb141, 0xaecd, 0xac65, 0xaa0b, 0xa7be, 0xa57e, 0xa34c, + 0xa129, 0x9f14, 0x9d0e, 0x9b18, 0x9931, 0x975a, 0x9593, 0x93dc, + 0x9236, 0x90a1, 0x8f1e, 0x8dab, 0x8c4b, 0x8afc, 0x89bf, 0x8894, + 0x877c, 0x8676, 0x8583, 0x84a3, 0x83d7, 0x831d, 0x8276, 0x81e3, + 0x8163, 0x80f7, 0x809e, 0x8059, 0x8028, 0x800a, 0x6488, 0x0080, + 0x03ff, 0x0116, 0x0002, 0x0080, 0x4000, 0x3fd7, 0x3faf, 0x3f86, + 0x3f5d, 0x3f34, 0x3f0c, 0x3ee3, 0x3eba, 0x3e91, 0x3e68, 0x3e40, + 0x3e17, 0x3dee, 0x3dc5, 0x3d9c, 0x3d74, 0x3d4b, 0x3d22, 0x3cf9, + 0x3cd0, 0x3ca7, 0x3c7f, 0x3c56, 0x3c2d, 0x3c04, 0x3bdb, 0x3bb2, + 0x3b89, 0x3b60, 0x3b37, 0x3b0e, 0x3ae5, 0x3abc, 0x3a93, 0x3a69, + 0x3a40, 0x3a17, 0x39ee, 0x39c5, 0x399c, 0x3972, 0x3949, 0x3920, + 0x38f6, 0x38cd, 0x38a4, 0x387a, 0x3851, 0x3827, 0x37fe, 0x37d4, + 0x37aa, 0x3781, 0x3757, 0x372d, 0x3704, 0x36da, 0x36b0, 0x3686, + 0x365c, 0x3632, 0x3609, 0x35df, 0x35b4, 0x358a, 0x3560, 0x3536, + 0x350c, 0x34e1, 0x34b7, 0x348d, 0x3462, 0x3438, 0x340d, 0x33e3, + 0x33b8, 0x338d, 0x3363, 0x3338, 0x330d, 0x32e2, 0x32b7, 0x328c, + 0x3261, 0x3236, 0x320b, 0x31df, 0x31b4, 0x3188, 0x315d, 0x3131, + 0x3106, 0x30da, 0x30ae, 0x3083, 0x3057, 0x302b, 0x2fff, 0x2fd2, + 0x2fa6, 0x2f7a, 0x2f4d, 0x2f21, 0x2ef4, 0x2ec8, 0x2e9b, 0x2e6e, + 0x2e41, 0x2e14, 0x2de7, 0x2dba, 0x2d8d, 0x2d60, 0x2d32, 0x2d05, + 0x2cd7, 0x2ca9, 0x2c7b, 0x2c4d, 0x2c1f, 0x2bf1, 0x2bc3, 0x2b94, + 0x2b66, 0x2b37, 0x2b09, 0x2ada, 0x2aab, 0x2a7c, 0x2a4c, 0x2a1d, + 0x29ed, 0x29be, 0x298e, 0x295e, 0x292e, 0x28fe, 0x28ce, 0x289d, + 0x286d, 0x283c, 0x280b, 0x27da, 0x27a9, 0x2777, 0x2746, 0x2714, + 0x26e2, 0x26b0, 0x267e, 0x264c, 0x2619, 0x25e7, 0x25b4, 0x2581, + 0x254d, 0x251a, 0x24e6, 0x24b2, 0x247e, 0x244a, 0x2415, 0x23e1, + 0x23ac, 0x2376, 0x2341, 0x230b, 0x22d6, 0x229f, 0x2269, 0x2232, + 0x21fc, 0x21c4, 0x218d, 0x2155, 0x211d, 0x20e5, 0x20ad, 0x2074, + 0x203b, 0x2001, 0x1fc7, 0x1f8d, 0x1f53, 0x1f18, 0x1edd, 0x1ea1, + 0x1e66, 0x1e29, 0x1ded, 0x1db0, 0x1d72, 0x1d35, 0x1cf6, 0x1cb8, + 0x1c79, 0x1c39, 0x1bf9, 0x1bb8, 0x1b77, 0x1b36, 0x1af4, 0x1ab1, + 0x1a6e, 0x1a2a, 0x19e6, 0x19a1, 0x195c, 0x1915, 0x18ce, 0x1887, + 0x183f, 0x17f5, 0x17ac, 0x1761, 0x1715, 0x16c9, 0x167c, 0x162e, + 0x15df, 0x158e, 0x153d, 0x14eb, 0x1497, 0x1442, 0x13ec, 0x1395, + 0x133c, 0x12e2, 0x1286, 0x1228, 0x11c9, 0x1167, 0x1104, 0x109e, + 0x1036, 0x0fcc, 0x0f5f, 0x0eef, 0x0e7b, 0x0e04, 0x0d89, 0x0d0a, + 0x0c86, 0x0bfd, 0x0b6d, 0x0ad6, 0x0a36, 0x098d, 0x08d7, 0x0811, + 0x0736, 0x063e, 0x0519, 0x039a, 0x0000, 0x7fff, 0x0100, 0x0080, + 0x021d, 0x00c8, 0x00ce, 0x0048, 0x0a26, 0x277a, 0x00ce, 0x6488, + 0x14ac, 0x0001, 0x00f9, 0x00fc, 0x00ff, 0x00fc, 0x00f9, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}; + +////////////////////////////////////////////////////////////////// + diff --git a/src/chip/dsp1/_dsp1emu.h b/src/chip/dsp1/_dsp1emu.h new file mode 100644 index 00000000..537ba9a8 --- /dev/null +++ b/src/chip/dsp1/_dsp1emu.h @@ -0,0 +1,126 @@ +// DSP-1's emulation code +// +// Based on research by Overload, The Dumper, Neviksti and Andreas Naive +// Date: June 2006 + +#ifndef __DSP1EMUL_H +#define __DSP1EMUL_H + +#define DSP1_VERSION 0x0102 + +class Dsp1 +{ + public: + // The DSP-1 status register has 16 bits, but only + // the upper 8 bits can be accessed from an external device, so all these + // positions are referred to the upper byte (bits D8 to D15) + enum SrFlags {DRC=0x04, DRS=0x10, RQM=0x80}; + + // According to Overload's docs, these are the meanings of the flags: + // DRC: The Data Register Control (DRC) bit specifies the data transfer length to and from the host CPU. + // 0: Data transfer to and from the DSP-1 is 16 bits. + // 1: Data transfer to and from the DSP-1 is 8 bits. + // DRS: The Data Register Status (DRS) bit indicates the data transfer status in the case of transfering 16-bit data. + // 0: Data transfer has terminated. + // 1: Data transfer in progress. + // RQM: The Request for Master (RQM) indicates that the DSP1 is requesting host CPU for data read/write. + // 0: Internal Data Register Transfer. + // 1: External Data Register Transfer. + + Dsp1(); + uint8 getSr() const; // return the status register's high byte + uint8 getDr(); + void setDr(uint8 iDr); + void reset(); + + private: + enum FsmMajorState {WAIT_COMMAND, READ_DATA, WRITE_DATA}; + enum MaxDataAccesses {MAX_READS=7, MAX_WRITES=1024}; + + struct Command { + void (Dsp1::*callback)(int16 *, int16 *); + unsigned int reads; + unsigned int writes; + }; + + static const Command mCommandTable[]; + static const int16 MaxAZS_Exp[16]; + static const int16 SinTable[]; + static const int16 MulTable[]; + static const uint16 DataRom[]; + + struct SharedData { // some RAM variables shared between commands + int16 MatrixA[3][3]; // attitude matrix A + int16 MatrixB[3][3]; + int16 MatrixC[3][3]; + int16 CentreX, CentreY, CentreZ; // center of projection + int16 CentreZ_C, CentreZ_E; + int16 VOffset; // vertical offset of the screen with regard to the centre of projection + int16 Les, C_Les, E_Les; + int16 SinAas, CosAas; + int16 SinAzs, CosAzs; + int16 SinAZS, CosAZS; + int16 SecAZS_C1, SecAZS_E1; + int16 SecAZS_C2, SecAZS_E2; + int16 Nx, Ny, Nz; // normal vector to the screen (norm 1, points toward the center of projection) + int16 Gx, Gy, Gz; // center of the screen (global coordinates) + int16 Hx, Hy; // horizontal vector of the screen (Hz=0, norm 1, points toward the right of the screen) + int16 Vx, Vy, Vz; // vertical vector of the screen (norm 1, points toward the top of the screen) + + } shared; + + uint8 mSr; // status register + uint16 mDr; // "internal" representation of the data register + FsmMajorState mFsmMajorState; // current major state of the FSM + uint8 mCommand; // current command processed by the FSM + uint8 mDataCounter; // #uint16 read/writes counter used by the FSM + int16 mReadBuffer[MAX_READS]; + int16 mWriteBuffer[MAX_WRITES]; + bool mFreeze; // need explanation? ;) + + void fsmStep(bool read, uint8 &data); // FSM logic + + // commands + void memoryTest(int16 *input, int16 *output); + void memoryDump(int16 *input, int16 *output); + void memorySize(int16 *input, int16 *output); + void multiply(int16* input, int16* output); + void multiply2(int16* input, int16* output); + void inverse(int16 *input, int16 *output); + void triangle(int16 *input, int16 *output); + void radius(int16 *input, int16 *output); + void range(int16 *input, int16 *output); + void range2(int16 *input, int16 *output); + void distance(int16 *input, int16 *output); + void rotate(int16 *input, int16 *output); + void polar(int16 *input, int16 *output); + void attitudeA(int16 *input, int16 *output); + void attitudeB(int16 *input, int16 *output); + void attitudeC(int16 *input, int16 *output); + void objectiveA(int16 *input, int16 *output); + void objectiveB(int16 *input, int16 *output); + void objectiveC(int16 *input, int16 *output); + void subjectiveA(int16 *input, int16 *output); + void subjectiveB(int16 *input, int16 *output); + void subjectiveC(int16 *input, int16 *output); + void scalarA(int16 *input, int16 *output); + void scalarB(int16 *input, int16 *output); + void scalarC(int16 *input, int16 *output); + void gyrate(int16 *input, int16 *output); + void parameter(int16 *input, int16 *output); + void raster(int16 *input, int16 *output); + void target(int16 *input, int16 *output); + void project(int16 *input, int16 *output); + + // auxiliar functions + int16 sin(int16 Angle); + int16 cos(int16 Angle); + void inverse(int16 Coefficient, int16 Exponent, int16 &iCoefficient, int16 &iExponent); + int16 denormalizeAndClip(int16 C, int16 E); + void normalize(int16 m, int16 &Coefficient, int16 &Exponent); + void normalizeDouble(int32 Product, int16 &Coefficient, int16 &Exponent); + int16 shiftR(int16 C, int16 E); +}; + +#endif + diff --git a/src/chip/dsp1/dsp1.cpp b/src/chip/dsp1/dsp1.cpp new file mode 100644 index 00000000..31539697 --- /dev/null +++ b/src/chip/dsp1/dsp1.cpp @@ -0,0 +1,54 @@ +#include "../../base.h" +#include "dsp1emu.cpp" + +void DSP1::init() {} +void DSP1::enable() {} + +void DSP1::power() { + reset(); +} + +void DSP1::reset() { + dsp1.reset(); +} + +/***** + * addr_decode() + * determine whether address is accessing + * data register (DR) or status register (SR) + * -- 0 (false) = DR + * -- 1 (true ) = SR + * + * note: there is no need to bounds check addresses, + * as memory mapper will not allow DSP1 accesses outside + * of expected ranges + *****/ +bool DSP1::addr_decode(uint16 addr) { + switch(cartridge.cart.dsp1_mapper) { + + case Cartridge::DSP1_LOROM_1MB: + //$[20-3f]:[8000-bfff] = DR, $[20-3f]:[c000-ffff] = SR + return (addr >= 0xc000); + + case Cartridge::DSP1_LOROM_2MB: + //$[60-6f]:[0000-3fff] = DR, $[60-6f]:[4000-7fff] = SR + return (addr >= 0x4000); + + case Cartridge::DSP1_HIROM: + //$[00-1f]:[6000-6fff] = DR, $[00-1f]:[7000-7fff] = SR + return (addr >= 0x7000); + + } + + return 0; +} + +uint8 DSP1::read(uint16 addr) { + return (addr_decode(addr) == 0) ? dsp1.getDr() : dsp1.getSr(); +} + +void DSP1::write(uint16 addr, uint8 data) { + if(addr_decode(addr) == 0) { + dsp1.setDr(data); + } +} diff --git a/src/chip/dsp1/dsp1.h b/src/chip/dsp1/dsp1.h new file mode 100644 index 00000000..50477f31 --- /dev/null +++ b/src/chip/dsp1/dsp1.h @@ -0,0 +1,16 @@ +#include "dsp1emu.h" + +class DSP1 { +private: +Dsp1 dsp1; + +public: + void init(); + void enable(); + void power(); + void reset(); + + bool addr_decode(uint16 addr); + uint8 read (uint16 addr); + void write(uint16 addr, uint8 data); +}; diff --git a/src/chip/dsp1/dsp1emu.cpp b/src/chip/dsp1/dsp1emu.cpp new file mode 100644 index 00000000..720c7977 --- /dev/null +++ b/src/chip/dsp1/dsp1emu.cpp @@ -0,0 +1,1622 @@ +// DSP-1's emulation code +// +// Based on research by Overload, The Dumper, Neviksti and Andreas Naive +// Date: June 2006 + +////////////////////////////////////////////////////////////////// + +Dsp1::Dsp1() +{ + reset(); +} + +////////////////////////////////////////////////////////////////// + +uint8 Dsp1::getSr() +{ + mSrLowByteAccess = ~mSrLowByteAccess; + if (mSrLowByteAccess) + return 0; + else + return mSr; +} + +////////////////////////////////////////////////////////////////// + +uint8 Dsp1::getDr() +{ + uint8 oDr; + + fsmStep(true, oDr); + return oDr; +} + +////////////////////////////////////////////////////////////////// + +void Dsp1::setDr(uint8 iDr) +{ + fsmStep(false, iDr); +} + +////////////////////////////////////////////////////////////////// + +void Dsp1::reset() +{ + mSr = DRC|RQM; + mSrLowByteAccess = false; + mDr = 0x0080; // Only a supposition. Is this correct? + mFreeze = false; + mFsmMajorState = WAIT_COMMAND; + memset(&shared, 0, sizeof(SharedData)); // another supposition +} + +////////////////////////////////////////////////////////////////// + +// Though the DSP-1 is unaware of the type of operation (read or write) +// we need to know what is being done by the program, as the class +// is responsible for maintaining the binding between the +// "external" and "internal" representations of the DR (data register). + +void Dsp1::fsmStep(bool read, uint8 &data) +{ + if (0 == (mSr&RQM)) return; + // Now RQM would be cleared; however, as this code is not to be used in + // a multithread environment, we will simply fake RQM operation. + // (The only exception would be Op1A's freeze.) + + // binding + if (read) + { + if (mSr&DRS) + data = static_cast(mDr>>8); + else + data = static_cast(mDr); + } + else + { + if (mSr&DRS) + { + mDr &= 0x00ff; + mDr |= data<<8; + } + else + { + mDr &= 0xff00; + mDr |= data; + } + } + + + switch (mFsmMajorState) + { + case WAIT_COMMAND: + mCommand = static_cast(mDr); + if (!(mCommand & 0xc0)) // valid command? + { + switch(mCommand) + { + // freeze cases + case 0x1a: + case 0x2a: + case 0x3a: + mFreeze = true; + break; + // normal cases + default: + mDataCounter=0; + mFsmMajorState = READ_DATA; + mSr &= ~DRC; + break; + } + } + break; + case READ_DATA: + mSr ^= DRS; + if (!(mSr&DRS)) + { + mReadBuffer[mDataCounter++] = static_cast(mDr); + if (mDataCounter >= mCommandTable[mCommand].reads) + { + (this->*mCommandTable[mCommand].callback)(mReadBuffer, mWriteBuffer); + if (0 != mCommandTable[mCommand].writes) // any output? + { + mDataCounter = 0; + mDr = static_cast(mWriteBuffer[mDataCounter]); + mFsmMajorState = WRITE_DATA; + } + else + { + mDr = 0x0080; // valid command completion + mFsmMajorState = WAIT_COMMAND; + mSr |= DRC; + } + } + } + break; + case WRITE_DATA: + mSr ^= DRS; + if (!(mSr&DRS)) + { + ++mDataCounter; + if (mDataCounter >= mCommandTable[mCommand].writes) + { + if ((mCommand == 0x0a)&&(mDr != 0x8000)) + { + // works in continuous mode + mReadBuffer[0]++; // next raster line + (this->*mCommandTable[mCommand].callback)(mReadBuffer, mWriteBuffer); + mDataCounter = 0; + mDr = static_cast(mWriteBuffer[mDataCounter]); + } + else + { + mDr = 0x0080; // valid command completion + mFsmMajorState = WAIT_COMMAND; + mSr |= DRC; + } + } + else + { + mDr = static_cast(mWriteBuffer[mDataCounter]); + } + } + break; + } + + + + // Now RQM would be set (except when executing Op1A -command equals 0x1a, 0x2a or 0x3a-). + if (mFreeze) + mSr &= ~RQM; +} + +////////////////////////////////////////////////////////////////// + +// The info on this table follows Overload's docs. + +const Dsp1::Command Dsp1::mCommandTable[0x40] = { + {&Dsp1::multiply, 2, 1}, //0x00 + {&Dsp1::attitudeA, 4, 0}, //0x01 + {&Dsp1::parameter, 7, 4}, //0x02 + {&Dsp1::subjectiveA, 3, 3}, //0x03 + {&Dsp1::triangle, 2, 2}, //0x04 + {&Dsp1::attitudeA, 4, 0}, //0x01 + {&Dsp1::project, 3, 3}, //0x06 + {&Dsp1::memoryTest, 1, 1}, //0x0f + {&Dsp1::radius, 3, 2}, //0x08 + {&Dsp1::objectiveA, 3, 3}, //0x0d + {&Dsp1::raster, 1, 4}, // 0x0a. This will normally work in continuous mode + {&Dsp1::scalarA, 3, 1}, //0x0b + {&Dsp1::rotate, 3, 2}, //0x0c + {&Dsp1::objectiveA, 3, 3}, //0x0d + {&Dsp1::target, 2, 2}, //0x0e + {&Dsp1::memoryTest, 1, 1}, //0x0f + + {&Dsp1::inverse, 2, 2}, //0x10 + {&Dsp1::attitudeB, 4, 0}, //0x11 + {&Dsp1::parameter, 7, 4}, //0x02 + {&Dsp1::subjectiveB, 3, 3}, //0x13 + {&Dsp1::gyrate, 6, 3}, //0x14 + {&Dsp1::attitudeB, 4, 0}, //0x11 + {&Dsp1::project, 3, 3}, //0x06 + {&Dsp1::memoryDump, 1, 1024}, //0x1f + {&Dsp1::range, 4, 1}, //0x18 + {&Dsp1::objectiveB, 3, 3}, //0x1d + {0, 0, 0}, // 0x1a; the chip freezes + {&Dsp1::scalarB, 3, 1}, //0x1b + {&Dsp1::polar, 6, 3}, //0x1c + {&Dsp1::objectiveB, 3, 3}, //0x1d + {&Dsp1::target, 2, 2}, //0x0e + {&Dsp1::memoryDump, 1, 1024}, //0x1f + + {&Dsp1::multiply2, 2, 1}, //0x20 + {&Dsp1::attitudeC, 4, 0}, //0x21 + {&Dsp1::parameter, 7, 4}, //0x02 + {&Dsp1::subjectiveC, 3, 3}, //0x23 + {&Dsp1::triangle, 2, 2}, //0x04 + {&Dsp1::attitudeC, 4, 0}, //0x21 + {&Dsp1::project, 3, 3}, //0x06 + {&Dsp1::memorySize, 1, 1}, //0x2f + {&Dsp1::distance, 3, 1}, //0x28 + {&Dsp1::objectiveC, 3, 3}, //0x2d + {0, 0, 0}, // 0x1a; the chip freezes + {&Dsp1::scalarC, 3, 1}, //0x2b + {&Dsp1::rotate, 3, 2}, //0x0c + {&Dsp1::objectiveC, 3, 3}, //0x2d + {&Dsp1::target, 2, 2}, //0x0e + {&Dsp1::memorySize, 1, 1}, //0x2f + + {&Dsp1::inverse, 2, 2}, //0x10 + {&Dsp1::attitudeA, 4, 0}, //0x01 + {&Dsp1::parameter, 7, 4}, //0x02 + {&Dsp1::subjectiveA, 3, 3}, //0x03 + {&Dsp1::gyrate, 6, 3}, //0x14 + {&Dsp1::attitudeA, 4, 0}, //0x01 + {&Dsp1::project, 3, 3}, //0x06 + {&Dsp1::memoryDump, 1, 1024}, //0x1f + {&Dsp1::range2, 4, 1}, //0x38 + {&Dsp1::objectiveA, 3, 3}, //0x0d + {0, 0, 0}, // 0x1a; the chip freezes + {&Dsp1::scalarA, 3, 1}, //0x0b + {&Dsp1::polar, 6, 3}, //0x1c + {&Dsp1::objectiveA, 3, 3}, //0x0d + {&Dsp1::target, 2, 2}, //0x0e + {&Dsp1::memoryDump, 1, 1024}, //0x1f +}; + +////////////////////////////////////////////////////////////////// + +void Dsp1::memoryTest(int16 *input, int16 *output) +{ + int16& Size = input[0]; + int16& Result = output[0]; + + Result = 0x0000; +} + +////////////////////////////////////////////////////////////////// + +void Dsp1::memoryDump(int16 *input, int16 *output) +{ + memcpy(output, DataRom, 1024); +} + +////////////////////////////////////////////////////////////////// + +void Dsp1::memorySize(int16 *input, int16 *output) +{ + int16& Size = output[0]; + + Size = 0x0100; +} + +////////////////////////////////////////////////////////////////// + +// 16-bit multiplication + +void Dsp1::multiply(int16 *input, int16 *output) +{ + int16& Multiplicand = input[0]; + int16& Multiplier = input[1]; + int16& Product = output[0]; + + Product = Multiplicand * Multiplier >> 15; +} + +////////////////////////////////////////////////////////////////// + +// 16-bit multiplication. 'Alternative' method. Can anyone check this carefully? + +void Dsp1::multiply2(int16 *input, int16 *output) +{ + int16& Multiplicand = input[0]; + int16& Multiplier = input[1]; + int16& Product = output[0]; + + Product = (Multiplicand * Multiplier >> 15)+1; +} + +////////////////////////////////////////////////////////////////// + +// This command determines the inverse of a floating point decimal number. + +void Dsp1::inverse(int16 *input, int16 *output) +{ + int16& Coefficient = input[0]; + int16& Exponent = input[1]; + int16& iCoefficient = output[0]; + int16& iExponent = output[1]; + + inverse(Coefficient, Exponent, iCoefficient, iExponent); +} + +////////////////////////////////////////////////////////////////// + +// Vector component calculation. Determines the X and Y components for a +// two-dimensional vector whose size and direction is known. +// Y = Radius * sin(Angle) +// X = Radius * cos(Angle) + +void Dsp1::triangle(int16 *input, int16 *output) +{ + int16& Angle = input[0]; + int16& Radius = input[1]; + int16& Y = output[0]; + int16& X = output[1]; + + Y = sin(Angle) * Radius >> 15; + X = cos(Angle) * Radius >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Determines the squared norm of a vector (X,Y,Z) +// The output is Radius = X^2+Y^2+Z^2 (double integer) + +void Dsp1::radius(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& RadiusLow = output[0]; + int16& RadiusHigh = output[1]; + + int32 Radius; + + Radius = (X * X + Y * Y + Z * Z) << 1; + RadiusLow = static_cast(Radius); + RadiusHigh = static_cast(Radius>>16); +} + +////////////////////////////////////////////////////////////////// + +// Vector size comparison. This command compares the size of the vector (X,Y,Z) and the distance (R) +// from a particular point, and so may be used to determine if a point is within the sphere or radius R. +// The output is D = X^2+Y^2+Z^2-R^2 + +void Dsp1::range(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& Radius = input[3]; + int16& Range = output[0]; + + Range = (X * X + Y * Y + Z * Z - Radius * Radius) >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Vector size comparison. 'Alternative' method. + +void Dsp1::range2(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& Radius = input[3]; + int16& Range = output[0]; + + Range = ((X * X + Y * Y + Z * Z - Radius * Radius) >> 15) + 1; +} + +////////////////////////////////////////////////////////////////// + +// This command calculates the norm of a (X,Y,Z) vector, or the distance from +// the point (X,Y,Z) to (0,0,0), as you prefer to see it. +// Distance = sqrt(X^2+Y^2+Z^2) +// The square root of a number 'a' is calculated by doing this: you +// write 'a' as b*2^2n, with 'b' between 1/4 and 1; then, you calculate +// c=sqrt(b) by using lineal interpolation between points of a +// look-up table and, finally, you output the result as c*2^n. + +void Dsp1::distance(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& Distance = output[0]; + + int32 Radius = X * X + Y * Y + Z * Z; + + if (Radius == 0) Distance = 0; + else + { + int16 C, E; + normalizeDouble(Radius, C, E); + if (E & 1) C = C * 0x4000 >> 15; + + int16 Pos = C * 0x0040 >> 15; + + int16 Node1 = DataRom[0x00d5 + Pos]; + int16 Node2 = DataRom[0x00d6 + Pos]; + + Distance = ((Node2 - Node1) * (C & 0x1ff) >> 9) + Node1; + +#if DSP1_VERSION < 0x0102 + if (Pos & 1) Distance -= (Node2 - Node1); +#endif + Distance >>= (E >> 1); + } +} + +////////////////////////////////////////////////////////////////// + +// Determines the (X2, Y2) coordinates obtained by rotating (X1, Y1) +// clockwise for an angle 'Angle'. The official documentation says +// 'counterclockwise', but it's obviously wrong (surprise! :P) +// +// In matrix notation: +// |X2| |cos(Angle) sin(Angle)| |X1| +// | | = | | | | +// |Y2| |-sin(Angle cos(Angle)| |Y1| + +void Dsp1::rotate(int16 *input, int16 *output) +{ + int16& Angle = input[0]; + int16& X1 = input[1]; + int16& Y1 = input[2]; + int16& X2 = output[0]; + int16& Y2 = output[1]; + + X2 = (Y1 * sin(Angle) >> 15) + (X1 * cos(Angle) >> 15); + Y2 = (Y1 * cos(Angle) >> 15) - (X1 * sin(Angle) >> 15); +} + +////////////////////////////////////////////////////////////////// + +// Calculate the coordinates (X2, Y2, Z2) obtained when rotating (X1, Y1, Z1) +// three-dimensionally. Rotation is done in the order of Az around the Z axis, +// Ay around the Y axis and Ax around the X axis. As occur with the "attitude" commands +// (see comments in the "gyrate" command), this doesn't match what explained in +// the official documentation, but it's coherent with what it is done in the "attitude" +// command (but not with the "gyrate" command). +// +// In matrix notation: +// |X2| |1 0 0 | |cosRy 0 -sinRy| | cosRz sinRz 0| |X1| +// |Y2| = |0 cosRx sinRx| | 0 1 0 | |-sinRz cosRz 0| |Y1| +// |Z2| |0 -sinRx cosRx| |sinRy 0 cosRy| | 0 0 1| |Z1| + +void Dsp1::polar(int16 *input, int16 *output) +{ + int16& Az = input[0]; + int16& Ay = input[1]; + int16& Ax = input[2]; + int16& X1 = input[3]; + int16& Y1 = input[4]; + int16& Z1 = input[5]; + int16& X2 = output[0]; + int16& Y2 = output[1]; + int16& Z2 = output[2]; + + int16 X, Y, Z; + + // Rotate Around Z + X = (Y1 * sin(Az) >> 15) + (X1 * cos(Az) >> 15); + Y = (Y1 * cos(Az) >> 15) - (X1 * sin(Az) >> 15); + X1 = X; Y1 = Y; + + // Rotate Around Y + Z = (X1 * sin(Ay) >> 15) + (Z1 * cos(Ay) >> 15); + X = (X1 * cos(Ay) >> 15) - (Z1 * sin(Ay) >> 15); + X2 = X; Z1 = Z; + + // Rotate Around X + Y = (Z1 * sin(Ax) >> 15) + (Y1 * cos(Ax) >> 15); + Z = (Z1 * cos(Ax) >> 15) - (Y1 * sin(Ax) >> 15); + Y2 = Y; Z2 = Z; +} + +////////////////////////////////////////////////////////////////// + +// Set up the elements of an "attitude matrix" (there are other ones): +// S | cosRz sinRz 0| |cosRy 0 -sinRy| |1 0 0 | +// MatrixA = - |-sinRz cosRz 0| | 0 1 0 | |0 cosRx sinRx| +// 2 | 0 0 1| |sinRy 0 cosRy| |0 -sinRx cosRx| +// This matrix is thought to be used within the following framework: +// let's suppose we define positive rotations around a system of orthogonal axes in this manner: +// a rotation of +90 degrees around axis3 converts axis2 into axis1 +// a rotation of +90 degrees around axis2 converts axis1 into axis3 +// a rotation of +90 degrees around axis1 converts axis3 into axis2 +// and let's suppose that we have defined a new orthonormal axes system (FLU) +// by doing the following operations about the standard one (XYZ): +// first rotating the XYZ system around Z by an angle Rz (obtaining X'Y'Z'), +// then rotating the resulting system around Y by an angle Ry (obtaining X''Y''Z'') +// and, finally, rotating the resulting system around X by an angle Rx (obtaining FLU) +// This FLU (forward/left/up) system represents an "attitude" and, then, the matrix here defined +// is the change of coordinates matrix that transform coordinates in the FLU +// system (the "object coordinates") into the standard XYZ system (the "global coordinates"), +// multiplied by a scale factor S/2, that is: +// |x| S |f| +// |y| * - = MatrixA * |l| +// |z| 2 |u| +// In a similar way, if we use the transpose of the matrix, we can transform global coordinates +// into object coordinates: +// |f| S |x| +// |l| * - = MatrixA_transposed * |y| +// |u| 2 |z| +// +// input[0]: S +// input[1]: Rz +// input[2]: Ry +// input[3]: Rx + +void Dsp1::attitudeA(int16 *input, int16 *output) +{ + int16& S = input[0]; + int16& Rz = input[1]; + int16& Ry = input[2]; + int16& Rx = input[3]; + + int16 SinRz = sin(Rz); + int16 CosRz = cos(Rz); + int16 SinRy = sin(Ry); + int16 CosRy = cos(Ry); + int16 SinRx = sin(Rx); + int16 CosRx = cos(Rx); + + S >>= 1; + + shared.MatrixA[0][0] = (S * CosRz >> 15) * CosRy >> 15; + shared.MatrixA[0][1] = ((S * SinRz >> 15) * CosRx >> 15) + (((S * CosRz >> 15) * SinRx >> 15) * SinRy >> 15); + shared.MatrixA[0][2] = ((S * SinRz >> 15) * SinRx >> 15) - (((S * CosRz >> 15) * CosRx >> 15) * SinRy >> 15); + + shared.MatrixA[1][0] = -((S * SinRz >> 15) * CosRy >> 15); + shared.MatrixA[1][1] = ((S * CosRz >> 15) * CosRx >> 15) - (((S * SinRz >> 15) * SinRx >> 15) * SinRy >> 15); + shared.MatrixA[1][2] = ((S * CosRz >> 15) * SinRx >> 15) + (((S * SinRz >> 15) * CosRx >> 15) * SinRy >> 15); + + shared.MatrixA[2][0] = S * SinRy >> 15; + shared.MatrixA[2][1] = -((S * SinRx >> 15) * CosRy >> 15); + shared.MatrixA[2][2] = (S * CosRx >> 15) * CosRy >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Same than 'attitudeA', but with a difference attitude matrix (matrixB) + +void Dsp1::attitudeB(int16 *input, int16 *output) +{ + int16& S = input[0]; + int16& Rz = input[1]; + int16& Ry = input[2]; + int16& Rx = input[3]; + + int16 SinRz = sin(Rz); + int16 CosRz = cos(Rz); + int16 SinRy = sin(Ry); + int16 CosRy = cos(Ry); + int16 SinRx = sin(Rx); + int16 CosRx = cos(Rx); + + S >>= 1; + + shared.MatrixB[0][0] = (S * CosRz >> 15) * CosRy >> 15; + shared.MatrixB[0][1] = ((S * SinRz >> 15) * CosRx >> 15) + (((S * CosRz >> 15) * SinRx >> 15) * SinRy >> 15); + shared.MatrixB[0][2] = ((S * SinRz >> 15) * SinRx >> 15) - (((S * CosRz >> 15) * CosRx >> 15) * SinRy >> 15); + + shared.MatrixB[1][0] = -((S * SinRz >> 15) * CosRy >> 15); + shared.MatrixB[1][1] = ((S * CosRz >> 15) * CosRx >> 15) - (((S * SinRz >> 15) * SinRx >> 15) * SinRy >> 15); + shared.MatrixB[1][2] = ((S * CosRz >> 15) * SinRx >> 15) + (((S * SinRz >> 15) * CosRx >> 15) * SinRy >> 15); + + shared.MatrixB[2][0] = S * SinRy >> 15; + shared.MatrixB[2][1] = -((S * SinRx >> 15) * CosRy >> 15); + shared.MatrixB[2][2] = (S * CosRx >> 15) * CosRy >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Same than 'attitudeA', but with a difference attitude matrix (matrixC) + +void Dsp1::attitudeC(int16 *input, int16 *output) +{ + int16& S = input[0]; + int16& Rz = input[1]; + int16& Ry = input[2]; + int16& Rx = input[3]; + + int16 SinRz = sin(Rz); + int16 CosRz = cos(Rz); + int16 SinRy = sin(Ry); + int16 CosRy = cos(Ry); + int16 SinRx = sin(Rx); + int16 CosRx = cos(Rx); + + S >>= 1; + + shared.MatrixC[0][0] = (S * CosRz >> 15) * CosRy >> 15; + shared.MatrixC[0][1] = ((S * SinRz >> 15) * CosRx >> 15) + (((S * CosRz >> 15) * SinRx >> 15) * SinRy >> 15); + shared.MatrixC[0][2] = ((S * SinRz >> 15) * SinRx >> 15) - (((S * CosRz >> 15) * CosRx >> 15) * SinRy >> 15); + + shared.MatrixC[1][0] = -((S * SinRz >> 15) * CosRy >> 15); + shared.MatrixC[1][1] = ((S * CosRz >> 15) * CosRx >> 15) - (((S * SinRz >> 15) * SinRx >> 15) * SinRy >> 15); + shared.MatrixC[1][2] = ((S * CosRz >> 15) * SinRx >> 15) + (((S * SinRz >> 15) * CosRx >> 15) * SinRy >> 15); + + shared.MatrixC[2][0] = S * SinRy >> 15; + shared.MatrixC[2][1] = -((S * SinRx >> 15) * CosRy >> 15); + shared.MatrixC[2][2] = (S * CosRx >> 15) * CosRy >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Convert global coordinates (X,Y,Z) to object coordinates (F,L,U) +// See the comment in "attitudeA" for a explanation about the calculation. +// +// input[0]: X ; input[1]: Y ; input[2]: Z +// output[0]: F ; output[1]: L ; output[2]: U + +void Dsp1::objectiveA(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& F = output[0]; + int16& L = output[1]; + int16& U = output[2]; + + F = (shared.MatrixA[0][0] * X >> 15) + (shared.MatrixA[1][0] * Y >> 15) + (shared.MatrixA[2][0] * Z >> 15); + L = (shared.MatrixA[0][1] * X >> 15) + (shared.MatrixA[1][1] * Y >> 15) + (shared.MatrixA[2][1] * Z >> 15); + U = (shared.MatrixA[0][2] * X >> 15) + (shared.MatrixA[1][2] * Y >> 15) + (shared.MatrixA[2][2] * Z >> 15); +} + +////////////////////////////////////////////////////////////////// + +// Same than 'objectiveA', but for the 'B' attitude + +void Dsp1::objectiveB(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& F = output[0]; + int16& L = output[1]; + int16& U = output[2]; + + F = (shared.MatrixB[0][0] * X >> 15) + (shared.MatrixB[1][0] * Y >> 15) + (shared.MatrixB[2][0] * Z >> 15); + L = (shared.MatrixB[0][1] * X >> 15) + (shared.MatrixB[1][1] * Y >> 15) + (shared.MatrixB[2][1] * Z >> 15); + U = (shared.MatrixB[0][2] * X >> 15) + (shared.MatrixB[1][2] * Y >> 15) + (shared.MatrixB[2][2] * Z >> 15); +} + +////////////////////////////////////////////////////////////////// + +// Same than 'objectiveA', but for the 'C' attitude + +void Dsp1::objectiveC(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& F = output[0]; + int16& L = output[1]; + int16& U = output[2]; + + F = (shared.MatrixC[0][0] * X >> 15) + (shared.MatrixC[1][0] * Y >> 15) + (shared.MatrixC[2][0] * Z >> 15); + L = (shared.MatrixC[0][1] * X >> 15) + (shared.MatrixC[1][1] * Y >> 15) + (shared.MatrixC[2][1] * Z >> 15); + U = (shared.MatrixC[0][2] * X >> 15) + (shared.MatrixC[1][2] * Y >> 15) + (shared.MatrixC[2][2] * Z >> 15); +} + +////////////////////////////////////////////////////////////////// + +// Convert object coordinates (F,L,U) to object coordinates (X,Y,Z) +// See the comment in "attitudeA" for a explanation about the calculation. +// +// input[0]: F ; input[1]: L ; input[2]: U +// output[0]: X ; output[1]: Y ; output[2]: Z + +void Dsp1::subjectiveA(int16 *input, int16 *output) +{ + int16& F = input[0]; + int16& L = input[1]; + int16& U = input[2]; + int16& X = output[0]; + int16& Y = output[1]; + int16& Z = output[2]; + + X = (shared.MatrixA[0][0] * F >> 15) + (shared.MatrixA[0][1] * L >> 15) + (shared.MatrixA[0][2] * U >> 15); + Y = (shared.MatrixA[1][0] * F >> 15) + (shared.MatrixA[1][1] * L >> 15) + (shared.MatrixA[1][2] * U >> 15); + Z = (shared.MatrixA[2][0] * F >> 15) + (shared.MatrixA[2][1] * L >> 15) + (shared.MatrixA[2][2] * U >> 15); +} + +////////////////////////////////////////////////////////////////// + +// Same than 'subjectiveA', but for the 'B' attitude + +void Dsp1::subjectiveB(int16 *input, int16 *output) +{ + int16& F = input[0]; + int16& L = input[1]; + int16& U = input[2]; + int16& X = output[0]; + int16& Y = output[1]; + int16& Z = output[2]; + + X = (shared.MatrixB[0][0] * F >> 15) + (shared.MatrixB[0][1] * L >> 15) + (shared.MatrixB[0][2] * U >> 15); + Y = (shared.MatrixB[1][0] * F >> 15) + (shared.MatrixB[1][1] * L >> 15) + (shared.MatrixB[1][2] * U >> 15); + Z = (shared.MatrixB[2][0] * F >> 15) + (shared.MatrixB[2][1] * L >> 15) + (shared.MatrixB[2][2] * U >> 15); +} + +////////////////////////////////////////////////////////////////// + +// Same than 'subjectiveA', but for the 'C' attitude + +void Dsp1::subjectiveC(int16 *input, int16 *output) +{ + int16& F = input[0]; + int16& L = input[1]; + int16& U = input[2]; + int16& X = output[0]; + int16& Y = output[1]; + int16& Z = output[2]; + + X = (shared.MatrixC[0][0] * F >> 15) + (shared.MatrixC[0][1] * L >> 15) + (shared.MatrixC[0][2] * U >> 15); + Y = (shared.MatrixC[1][0] * F >> 15) + (shared.MatrixC[1][1] * L >> 15) + (shared.MatrixC[1][2] * U >> 15); + Z = (shared.MatrixC[2][0] * F >> 15) + (shared.MatrixC[2][1] * L >> 15) + (shared.MatrixC[2][2] * U >> 15); +} + +////////////////////////////////////////////////////////////////// + +// This command calculates the inner product (S) of a vector (X,Y,Z) and +// the first column of MatrixA. It should be noted that that first column +// represent the global coordinates of an unity vector in the forward +// direction in the object coordinate system (coordinates (1,0,0) in the FLU +// axes system). +// +// input[0]: X ; input[1]: Y ; input[2]: Z +// output[0]: S + +void Dsp1::scalarA(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& S = output[0]; + + S = (X * shared.MatrixA[0][0] + Y * shared.MatrixA[1][0] + Z * shared.MatrixA[2][0]) >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Same than 'scalarA', but for the 'B' attitude + +void Dsp1::scalarB(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& S = output[0]; + + S = (X * shared.MatrixB[0][0] + Y * shared.MatrixB[1][0] + Z * shared.MatrixB[2][0]) >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Same than 'scalarA', but for the 'C' attitude + +void Dsp1::scalarC(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& S = output[0]; + + S = (X * shared.MatrixC[0][0] + Y * shared.MatrixC[1][0] + Z * shared.MatrixC[2][0]) >> 15; +} + +////////////////////////////////////////////////////////////////// + +// This command determines the final attitude angles after the body with attitude angles (Ax, Ay, Az) with +// respect to the global coordinates is rotated by the minor angular displacements (DeltaF, DeltaL, DeltaU). +// It means that the XYZ axes are rotated by (Ax, Ay, Az) to obtain the FLU axes and, then, these +// are rotated by (DeltaF, DeltaL, DeltaU). The command calculates and return the new FLU angles respect to the +// XYZ system (Rx, Ry, Rz) +// The formulae are: +// Rx = Ax + (DeltaU*sin(Ay)+DeltaF*cos(Ay)) +// Ry = Ay + DeltaL - tan(Ax)*(DeltaU*cos(Ay)+DeltaF*sin(Ay)) +// Rz = Az + sec(Ax)*(DeltaU*cos(Ay)-DeltaF*sin(Ay)) +// +// Now the discussion: according to the official documentation, as described in various commands, you pass from +// XYZ to FLU by doing the rotations in the order Y, X, Z. In this command, the formulae are coherent with the +// fact that Y is the first axis to do a rotation around it. However, in the "attitude" command, while the official +// document describe it that way, we have discovered, when reverse engineering the command, that the calculated +// matrix do the rotation around Y in the second place. This incoherent behaviour of various commands is, in my +// opinion, a pretty severe implementation error. However, if you only use small "minor displacements", the error term +// introduced by that incoherence should be almost negligible. + +void Dsp1::gyrate(int16 *input, int16 *output) +{ + int16& Az = input[0]; + int16& Ax = input[1]; + int16& Ay = input[2]; + int16& U = input[3]; + int16& F = input[4]; + int16& L = input[5]; + int16& Rz = output[0]; + int16& Rx = output[1]; + int16& Ry = output[2]; + + int16 CSec, ESec, CSin, C, E; + int16 SinAy = sin(Ay); + int16 CosAy = cos(Ay); + + inverse(cos(Ax), 0, CSec, ESec); + + // Rotation Around Z + normalizeDouble(U * CosAy - F * SinAy, C, E); + + E = ESec - E; + + normalize(C * CSec >> 15, C, E); + + Rz = Az + denormalizeAndClip(C, E); + + // Rotation Around X + Rx = Ax + (U * SinAy >> 15) + (F * CosAy >> 15); + + // Rotation Around Y + normalizeDouble(U * CosAy + F * SinAy, C, E); + + E = ESec - E; + + normalize(sin(Ax), CSin, E); + + normalize(-(C * (CSec * CSin >> 15) >> 15), C, E); + + Ry = Ay + denormalizeAndClip(C, E) + L; +} + +////////////////////////////////////////////////////////////////// + +const int16 Dsp1::MaxAZS_Exp[16] = { + 0x38b4, 0x38b7, 0x38ba, 0x38be, 0x38c0, 0x38c4, 0x38c7, 0x38ca, + 0x38ce, 0x38d0, 0x38d4, 0x38d7, 0x38da, 0x38dd, 0x38e0, 0x38e4 +}; + +////////////////////////////////////////////////////////////////// + + +// Set-up the projection framework. Besides returning some values, it store in RAM some values that +// will be used by the other three projection commands (raster, target an project) +// Input: +// (Fx, Fy, Fz)-> coordinates of base point (global coordinates) +// Lfe-> distance between the base point and the viewpoint (center of projection) +// Les-> distance between the base point and the screen +// Aas-> azimuth angle (0º is east; 90ª is north) +// Azs-> zenith angle (0º is zenith) +// Output: +// Vof-> raster line of imaginary center (whatever it means ;) ) +// Vva-> raster line representing the horizon line +// (Cx, Cy)-> coordinates of the projection of the center of the screen over the ground (ground coordinates) + +void Dsp1::parameter(int16 *input, int16 *output) +{ + int16& Fx = input[0]; + int16& Fy = input[1]; + int16& Fz = input[2]; + int16& Lfe = input[3]; + int16& Les = input[4]; + int16& Aas = input[5]; + int16& Azs = input[6]; + int16& Vof = output[0]; + int16& Vva = output[1]; + int16& Cx = output[2]; + int16& Cy = output[3]; + + int16 CSec, C, E; + int16 LfeNx, LfeNy, LfeNz; + int16 LesNx, LesNy, LesNz; + + // Copy Zenith angle for clipping + int16 AZS = Azs; + + // Store Les and his coefficient and exponent when normalized + shared.Les = Les; + shared.E_Les=0; + normalize(Les, shared.C_Les, shared.E_Les); + + // Store Sine and Cosine of Azimuth and Zenith angle + shared.SinAas = sin(Aas); + shared.CosAas = cos(Aas); + shared.SinAzs = sin(Azs); + shared.CosAzs = cos(Azs); + + // normal vector to the screen (norm 1, points toward the center of projection) + shared.Nx = shared.SinAzs * -shared.SinAas >> 15; + shared.Ny = shared.SinAzs * shared.CosAas >> 15; + shared.Nz = shared.CosAzs * 0x7fff >> 15; + + // horizontal vector of the screen (Hz=0, norm 1, points toward the right of the screen) + shared.Hx = shared.CosAas*0x7fff>>15; + shared.Hy = shared.SinAas*0x7fff>>15; + + // vertical vector of the screen (norm 1, points toward the top of the screen) + shared.Vx = shared.CosAzs*-shared.SinAas>>15; + shared.Vy = shared.CosAzs*shared.CosAas>>15; + shared.Vz = -shared.SinAzs*0x7fff>>15; + + LfeNx = Lfe*shared.Nx>>15; + LfeNy = Lfe*shared.Ny>>15; + LfeNz = Lfe*shared.Nz>>15; + + // Center of Projection + shared.CentreX = Fx+LfeNx; + shared.CentreY = Fy+LfeNy; + shared.CentreZ = Fz+LfeNz; + + LesNx = Les*shared.Nx>>15; + LesNy = Les*shared.Ny>>15; + LesNz = Les*shared.Nz>>15; + + // center of the screen (global coordinates) + shared.Gx=shared.CentreX-LesNx; + shared.Gy=shared.CentreY-LesNy; + shared.Gz=shared.CentreZ-LesNz; + + + E = 0; + normalize(shared.CentreZ, C, E); + + shared.CentreZ_C = C; + shared.CentreZ_E = E; + + // Determine clip boundary and clip Zenith angle if necessary + // (Why to clip? Maybe to avoid the screen can only show sky with no ground? Only a guess...) + int16 MaxAZS = MaxAZS_Exp[-E]; + + if (AZS < 0) { + MaxAZS = -MaxAZS; + if (AZS < MaxAZS + 1) AZS = MaxAZS + 1; + } else { + if (AZS > MaxAZS) AZS = MaxAZS; + } + + // Store Sine and Cosine of clipped Zenith angle + shared.SinAZS = sin(AZS); + shared.CosAZS = cos(AZS); + + // calculate the separation of (cx, cy) from the projection of + // the 'centre of projection' over the ground... (CentreZ*tg(AZS)) + inverse(shared.CosAZS, 0, shared.SecAZS_C1, shared.SecAZS_E1); + normalize(C * shared.SecAZS_C1 >> 15, C, E); + E += shared.SecAZS_E1; + C = denormalizeAndClip(C, E) * shared.SinAZS >> 15; + + // ... and then take into account the position of the centre of + // projection and the azimuth angle + shared.CentreX += C * shared.SinAas >> 15; + shared.CentreY -= C * shared.CosAas >> 15; + + Cx = shared.CentreX; + Cy = shared.CentreY; + + // Raster number of imaginary center and horizontal line + Vof = 0; + + if ((Azs != AZS) || (Azs == MaxAZS)) + { + // correct vof and vva when Azs is outside the 'non-clipping interval' + // we have only some few Taylor coefficients, so we cannot guess which ones + // are the approximated functions and, what is worse, we don't know why + // the own clipping stuff (and, particularly, this correction) is done + if (Azs == -32768) Azs = -32767; + + C = Azs - MaxAZS; + if (C >= 0) C--; + int16 Aux = ~(C << 2); + + // Vof += x+(1/3)*x^3, where x ranges from 0 to PI/4 when Azs-MaxAZS goes from 0 to 0x2000 + C = Aux * DataRom[0x0328] >> 15; + C = (C * Aux >> 15) + DataRom[0x0327]; + Vof -= (C * Aux >> 15) * Les >> 15; + + // CosAZS *= 1+(1/2)*x^2+(5/24)*x^24, where x ranges from 0 to PI/4 when Azs-MaxAZS goes from 0 to 0x2000 + C = Aux * Aux >> 15; + Aux = (C * DataRom[0x0324] >> 15) + DataRom[0x0325]; + shared.CosAZS += (C * Aux >> 15) * shared.CosAZS >> 15; + } + + // vertical offset of the screen with regard to the horizontal plane + // containing the centre of projection + shared.VOffset = Les * shared.CosAZS >> 15; + + // The horizon line (the line in the screen that is crossed by the horizon plane + // -the horizontal plane containing the 'centre of projection'-), + // will be at distance Les*cotg(AZS) from the centre of the screen. This is difficult + // to explain but easily seen in a graph. To better see it, consider it in this way: + // Les*tg(AZS-90), draw some lines and apply basic trigonometry. ;) + inverse(shared.SinAZS, 0, CSec, E); + normalize(shared.VOffset, C, E); + normalize(C * CSec >> 15, C, E); + + if (C == -32768) { C >>= 1; E++; } + + Vva = denormalizeAndClip(-C, E); + + // Store Secant of clipped Zenith angle + inverse(shared.CosAZS, 0, shared.SecAZS_C2, shared.SecAZS_E2); +} + +////////////////////////////////////////////////////////////////// + +// Calculates the matrix which transform an object situated on a raster line (Vs) into +// his projection over the ground. The modified SecAZS is used here, so +// i don't understand the fine details, but, basically, it's done +// this way: The vertical offset between the point of projection and the +// raster line is calculated (Vs*SinAzs>>15)+VOffset, then the height of +// the center of projection is measured in that units (*CentreZ_C). If, now +// you consider the "reference case" (center of projection at an unit of height), +// the projection of a thin strip containing the raster line will have the same +// width (as the raster line would be on the ground in this case, but will suffer a +// change of scale in height (as the ground and the vertical axis would form an angle of 180º-Azs). +// This scale factor, when the angle 'center of screen-center of projection-raster line' is small, +// can be aproximated by the one of the center of the screen, 1/cos(Azs).(**) (Here is when it's used +// SecAZS). By last, you have to consider the effect of the azimuth angle Aas, and you are done. +// +// Using matrix notation: +// |A B| Centre_ZS | cos(Aas) -sin(Aas)| |1 0| +// ProjectionMatrix = | | = ----------- * | | * | | +// |C D| Vs*sin(Azs) |sin(Aas) cos(Aas)| |0 sec(Azs)| +// +// (**) +// If Les=1, the vertical offset between the center +// of projection and the center of the screen is Cos(Azs); then, if the vertical +// offset is 1, the ratio of the projection over the ground respect to the +// line on the screen is 1/cos(Azs). + +void Dsp1::raster(int16 *input, int16 *output) +{ + int16& Vs = input[0]; + int16& An = output[0]; + int16& Bn = output[1]; + int16& Cn = output[2]; + int16& Dn = output[3]; + + int16 C, E, C1, E1; + + inverse((Vs * shared.SinAzs >> 15) + shared.VOffset, 7, C, E); + + E += shared.CentreZ_E; + C1 = C * shared.CentreZ_C >> 15; + + E1 = E + shared.SecAZS_E2; + + normalize(C1, C, E); + C = denormalizeAndClip(C, E); + + An = C * shared.CosAas >> 15; + Cn = C * shared.SinAas >> 15; + + normalize(C1 * shared.SecAZS_C2 >> 15, C, E1); + C = denormalizeAndClip(C, E1); + + Bn = C * -shared.SinAas >> 15; + Dn = C * shared.CosAas >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Calculate the projection over the ground of a selected point of screen +// It simply apply the projection matrix described in the "Raster" command +// to the vector (H,V) transposed, and add the result to the position of +// the centre of projection. +// The only special point to take into account is the directions on the screen: +// H is positive rightward, but V is positive downward; this is why +// the signs take that configuration + +void Dsp1::target(int16 *input, int16 *output) +{ + int16& H = input[0]; + int16& V = input[1]; + int16& X = output[0]; + int16& Y = output[1]; + + int16 C, E, C1, E1; + + inverse((V * shared.SinAzs >> 15) + shared.VOffset, 8, C, E); + + E += shared.CentreZ_E; + C1 = C * shared.CentreZ_C >> 15; + + E1 = E + shared.SecAZS_E1; + + H <<= 8; + normalize(C1, C, E); + C = denormalizeAndClip(C, E) * H >> 15; + + X = shared.CentreX + (C * shared.CosAas >> 15); + Y = shared.CentreY - (C * shared.SinAas >> 15); + + V <<= 8; + normalize(C1 * shared.SecAZS_C1 >> 15, C, E1); + C = denormalizeAndClip(C, E1) * V >> 15; + + X += C * -shared.SinAas >> 15; + Y += C * shared.CosAas >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Calculation of the projection over the screen (H,V) of an object (X,Y,Z) and his +// 'enlargement ratio' (M). The positive directions on the screen are as described +// in the targe command. M is scaled down by 2^-7, that is, M==0x0100 means ratio 1:1 + + void Dsp1::project(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& H = output[0]; + int16& V = output[1]; + int16& M = output[2]; + + int32 aux, aux4; + int16 E, E2, E3, E4, E5, refE, E6, E7; + int16 C2, C4, C6, C8, C9, C10, C11, C12, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25, C26; + int16 Px, Py, Pz; + + E4=E3=E2=E=E5=0; + + normalizeDouble(int32(X)-shared.Gx, Px, E4); + normalizeDouble(int32(Y)-shared.Gy, Py, E); + normalizeDouble(int32(Z)-shared.Gz, Pz, E3); + Px>>=1; E4--; // to avoid overflows when calculating the scalar products + Py>>=1; E--; + Pz>>=1; E3--; + + refE = (E>15); + C8=- (Py*shared.Ny>>15); + C9=- (Pz*shared.Nz>>15); + C12=C11+C8+C9; // this cannot overflow! + + aux4=C12; // de-normalization with 32-bits arithmetic + refE = 16-refE; // refE can be up to 3 + if (refE>=0) + aux4 <<=(refE); + else + aux4 >>=-(refE); + if (aux4==-1) aux4 = 0; // why? + aux4>>=1; + + aux = static_cast(shared.Les) + aux4; // Les - the scalar product of P with the normal vector of the screen + normalizeDouble(aux, C10, E2); + E2 = 15-E2; + + inverse(C10, 0, C4, E4); + C2=C4*shared.C_Les>>15; // scale factor + + + // H + E7=0; + C16= (Px*shared.Hx>>15); + C20= (Py*shared.Hy>>15); + C17=C16+C20; // scalar product of P with the normalized horizontal vector of the screen... + + C18=C17*C2>>15; // ... multiplied by the scale factor + normalize(C18, C19, E7); + H=denormalizeAndClip(C19, shared.E_Les-E2+refE+E7); + + // V + E6=0; + C21 = Px*shared.Vx>>15; + C22 = Py*shared.Vy>>15; + C23 = Pz*shared.Vz>>15; + C24=C21+C22+C23; // scalar product of P with the normalized vertical vector of the screen... + + C26=C24*C2>>15; // ... multiplied by the scale factor + normalize(C26, C25, E6); + V=denormalizeAndClip(C25, shared.E_Les-E2+refE+E6); + + // M + normalize(C2, C6, E4); + M=denormalizeAndClip(C6, E4+shared.E_Les-E2-7); // M is the scale factor divided by 2^7 +} + +////////////////////////////////////////////////////////////////// + +// Calculate the sine of the input parameter +// this is done by linear interpolation between +// the points of a look-up table + +int16 Dsp1::sin(int16 Angle) +{ + if (Angle < 0) { + if (Angle == -32768) return 0; + return -sin(-Angle); + } + int32 S = SinTable[Angle >> 8] + (MulTable[Angle & 0xff] * SinTable[0x40 + (Angle >> 8)] >> 15); + if (S > 32767) S = 32767; + return (int16) S; +} + +////////////////////////////////////////////////////////////////// + +// Calculate the cosine of the input parameter. +// It's used the same method than in sin(int16) + +int16 Dsp1::cos(int16 Angle) +{ + if (Angle < 0) { + if (Angle == -32768) return -32768; + Angle = -Angle; + } + int32 S = SinTable[0x40 + (Angle >> 8)] - (MulTable[Angle & 0xff] * SinTable[Angle >> 8] >> 15); + if (S < -32768) S = -32767; + return (int16) S; +} + +////////////////////////////////////////////////////////////////// + +// Determines the inverse of a floating point decimal number +// iCoefficient*2^iExponent = 1/(Coefficient*2^Exponent), with the output +// normalized (iCoefficient represents a number whose absolute value is between 1/2 and 1) +// To invert 'Coefficient' a first initial guess is taken from a look-up table +// and, then, two iterations of the Newton method (applied to the function +// f(x)=1/(2*x)-Coefficient) are done. This results in a close approximation (iCoefficient) to a number 'y' +// that verify Coefficient*y=1/2. This is why you have to correct the exponent by one +// unit at the end. + +void Dsp1::inverse(int16 Coefficient, int16 Exponent, int16 &iCoefficient, int16 &iExponent) +{ + // Step One: Division by Zero + if (Coefficient == 0x0000) + { + iCoefficient = 0x7fff; + iExponent = 0x002f; + } + else + { + int16 Sign = 1; + + // Step Two: Remove Sign + if (Coefficient < 0) + { + if (Coefficient < -32767) Coefficient = -32767; + Coefficient = -Coefficient; + Sign = -1; + } + + // Step Three: Normalize + while (Coefficient < 0x4000) + { + Coefficient <<= 1; + Exponent--; + } + + // Step Four: Special Case + if (Coefficient == 0x4000) + if (Sign == 1) iCoefficient = 0x7fff; + else { + iCoefficient = -0x4000; + Exponent--; + } + else { + // Step Five: Initial Guess + int16 i = DataRom[((Coefficient - 0x4000) >> 7) + 0x0065]; + + // Step Six: Iterate Newton's Method + i = (i + (-i * (Coefficient * i >> 15) >> 15)) << 1; + i = (i + (-i * (Coefficient * i >> 15) >> 15)) << 1; + + iCoefficient = i * Sign; + } + + iExponent = 1 - Exponent; + } +} + +////////////////////////////////////////////////////////////////// + +int16 Dsp1::denormalizeAndClip(int16 C, int16 E) +{ + if (E > 0) { + if (C > 0) return 32767; else if (C < 0) return -32767; + } else { + if (E < 0) return C * DataRom[0x0031 + E] >> 15; + } + return C; +} + +////////////////////////////////////////////////////////////////// + +// Normalize the input number (m), understood as ranging from -1 to 1, +// to the form: Coefficient*2^Exponent, +// where the absolute value of Coefficient is >= 1/2 +// (Coefficient>=0x4000 or Coefficient <= (int16)0xc001) + +void Dsp1::normalize(int16 m, int16 &Coefficient, int16 &Exponent) +{ + int16 i = 0x4000; + int16 e = 0; + + if (m < 0) + while ((m & i) && i) + { + i >>= 1; + e++; + } + else + while (!(m & i) && i) + { + i >>= 1; + e++; + } + + if (e > 0) + Coefficient = m * DataRom[0x21 + e] << 1; + else + Coefficient = m; + + Exponent -= e; +} + +////////////////////////////////////////////////////////////////// + +// Same than 'normalize' but with an int32 input + +void Dsp1::normalizeDouble(int32 Product, int16 &Coefficient, int16 &Exponent) +{ + int16 n = Product & 0x7fff; + int16 m = Product >> 15; + int16 i = 0x4000; + int16 e = 0; + + if (m < 0) + while ((m & i) && i) + { + i >>= 1; + e++; + } + else + while (!(m & i) && i) + { + i >>= 1; + e++; + } + + if (e > 0) + { + Coefficient = m * DataRom[0x0021 + e] << 1; + + if (e < 15) + Coefficient += n * DataRom[0x0040 - e] >> 15; + else + { + i = 0x4000; + + if (m < 0) + while ((n & i) && i) + { + i >>= 1; + e++; + } + else + while (!(n & i) && i) + { + i >>= 1; + e++; + } + + if (e > 15) + Coefficient = n * DataRom[0x0012 + e] << 1; + else + Coefficient += n; + } + } + else + Coefficient = m; + + Exponent = e; +} + +////////////////////////////////////////////////////////////////// + +// Shift to the right + +int16 Dsp1::shiftR(int16 C, int16 E) +{ + return (C * DataRom[0x0031 + E] >> 15); +} + +////////////////////////////////////////////////////////////////// + +// this is, indeed, only part of the Data ROM +const int16 Dsp1::SinTable[256] = { + 0x0000, 0x0324, 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2, + 0x18f8, 0x1c0b, 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11, + 0x30fb, 0x33de, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a, + 0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842, + 0x5a82, 0x5cb4, 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6, + 0x6a6d, 0x6c24, 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504, + 0x7641, 0x776c, 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3, + 0x7d8a, 0x7e1d, 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6, + 0x7fff, 0x7ff6, 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, + 0x7d8a, 0x7ce3, 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, + 0x7641, 0x7504, 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, + 0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, + 0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, + 0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, + 0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, + 0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, + -0x0000, -0x0324, -0x0647, -0x096a, -0x0c8b, -0x0fab, -0x12c8, -0x15e2, + -0x18f8, -0x1c0b, -0x1f19, -0x2223, -0x2528, -0x2826, -0x2b1f, -0x2e11, + -0x30fb, -0x33de, -0x36ba, -0x398c, -0x3c56, -0x3f17, -0x41ce, -0x447a, + -0x471c, -0x49b4, -0x4c3f, -0x4ebf, -0x5133, -0x539b, -0x55f5, -0x5842, + -0x5a82, -0x5cb4, -0x5ed7, -0x60ec, -0x62f2, -0x64e8, -0x66cf, -0x68a6, + -0x6a6d, -0x6c24, -0x6dca, -0x6f5f, -0x70e2, -0x7255, -0x73b5, -0x7504, + -0x7641, -0x776c, -0x7884, -0x798a, -0x7a7d, -0x7b5d, -0x7c29, -0x7ce3, + -0x7d8a, -0x7e1d, -0x7e9d, -0x7f09, -0x7f62, -0x7fa7, -0x7fd8, -0x7ff6, + -0x7fff, -0x7ff6, -0x7fd8, -0x7fa7, -0x7f62, -0x7f09, -0x7e9d, -0x7e1d, + -0x7d8a, -0x7ce3, -0x7c29, -0x7b5d, -0x7a7d, -0x798a, -0x7884, -0x776c, + -0x7641, -0x7504, -0x73b5, -0x7255, -0x70e2, -0x6f5f, -0x6dca, -0x6c24, + -0x6a6d, -0x68a6, -0x66cf, -0x64e8, -0x62f2, -0x60ec, -0x5ed7, -0x5cb4, + -0x5a82, -0x5842, -0x55f5, -0x539b, -0x5133, -0x4ebf, -0x4c3f, -0x49b4, + -0x471c, -0x447a, -0x41ce, -0x3f17, -0x3c56, -0x398c, -0x36ba, -0x33de, + -0x30fb, -0x2e11, -0x2b1f, -0x2826, -0x2528, -0x2223, -0x1f19, -0x1c0b, + -0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324}; + + ////////////////////////////////////////////////////////////////// + +// Optimised for Performance + const int16 Dsp1::MulTable[256] = { + 0x0000, 0x0003, 0x0006, 0x0009, 0x000c, 0x000f, 0x0012, 0x0015, + 0x0019, 0x001c, 0x001f, 0x0022, 0x0025, 0x0028, 0x002b, 0x002f, + 0x0032, 0x0035, 0x0038, 0x003b, 0x003e, 0x0041, 0x0045, 0x0048, + 0x004b, 0x004e, 0x0051, 0x0054, 0x0057, 0x005b, 0x005e, 0x0061, + 0x0064, 0x0067, 0x006a, 0x006d, 0x0071, 0x0074, 0x0077, 0x007a, + 0x007d, 0x0080, 0x0083, 0x0087, 0x008a, 0x008d, 0x0090, 0x0093, + 0x0096, 0x0099, 0x009d, 0x00a0, 0x00a3, 0x00a6, 0x00a9, 0x00ac, + 0x00af, 0x00b3, 0x00b6, 0x00b9, 0x00bc, 0x00bf, 0x00c2, 0x00c5, + 0x00c9, 0x00cc, 0x00cf, 0x00d2, 0x00d5, 0x00d8, 0x00db, 0x00df, + 0x00e2, 0x00e5, 0x00e8, 0x00eb, 0x00ee, 0x00f1, 0x00f5, 0x00f8, + 0x00fb, 0x00fe, 0x0101, 0x0104, 0x0107, 0x010b, 0x010e, 0x0111, + 0x0114, 0x0117, 0x011a, 0x011d, 0x0121, 0x0124, 0x0127, 0x012a, + 0x012d, 0x0130, 0x0133, 0x0137, 0x013a, 0x013d, 0x0140, 0x0143, + 0x0146, 0x0149, 0x014d, 0x0150, 0x0153, 0x0156, 0x0159, 0x015c, + 0x015f, 0x0163, 0x0166, 0x0169, 0x016c, 0x016f, 0x0172, 0x0175, + 0x0178, 0x017c, 0x017f, 0x0182, 0x0185, 0x0188, 0x018b, 0x018e, + 0x0192, 0x0195, 0x0198, 0x019b, 0x019e, 0x01a1, 0x01a4, 0x01a8, + 0x01ab, 0x01ae, 0x01b1, 0x01b4, 0x01b7, 0x01ba, 0x01be, 0x01c1, + 0x01c4, 0x01c7, 0x01ca, 0x01cd, 0x01d0, 0x01d4, 0x01d7, 0x01da, + 0x01dd, 0x01e0, 0x01e3, 0x01e6, 0x01ea, 0x01ed, 0x01f0, 0x01f3, + 0x01f6, 0x01f9, 0x01fc, 0x0200, 0x0203, 0x0206, 0x0209, 0x020c, + 0x020f, 0x0212, 0x0216, 0x0219, 0x021c, 0x021f, 0x0222, 0x0225, + 0x0228, 0x022c, 0x022f, 0x0232, 0x0235, 0x0238, 0x023b, 0x023e, + 0x0242, 0x0245, 0x0248, 0x024b, 0x024e, 0x0251, 0x0254, 0x0258, + 0x025b, 0x025e, 0x0261, 0x0264, 0x0267, 0x026a, 0x026e, 0x0271, + 0x0274, 0x0277, 0x027a, 0x027d, 0x0280, 0x0284, 0x0287, 0x028a, + 0x028d, 0x0290, 0x0293, 0x0296, 0x029a, 0x029d, 0x02a0, 0x02a3, + 0x02a6, 0x02a9, 0x02ac, 0x02b0, 0x02b3, 0x02b6, 0x02b9, 0x02bc, + 0x02bf, 0x02c2, 0x02c6, 0x02c9, 0x02cc, 0x02cf, 0x02d2, 0x02d5, + 0x02d8, 0x02db, 0x02df, 0x02e2, 0x02e5, 0x02e8, 0x02eb, 0x02ee, + 0x02f1, 0x02f5, 0x02f8, 0x02fb, 0x02fe, 0x0301, 0x0304, 0x0307, + 0x030b, 0x030e, 0x0311, 0x0314, 0x0317, 0x031a, 0x031d, 0x0321}; + +////////////////////////////////////////////////////////////////// + +// Data ROM, as logged from a DSP-1B with the 0x1f command; +// it contains the tables and constants used by the commands. +// The tables used are: two shift tables (0x022-0x031 and 0x031-0x040 -this last one +// with an error in 0x03c which has survived to all the DSP-1 revisions-); a inverse +// table (used as initial guess) at 0x065-0x0e4; a square root table (used also +// as initial guess) at 0x0e5-0x115; two sin and cos tables (used as nodes to construct +// a interpolation curve) at, respectively, 0x116-0x197 and 0x196-0x215. +// As a curiosity, in the positions 0x21c-0x31c it's contained a +// 257-points arccos table that, apparently, have been not used anywhere +// (maybe for the MaxAZS_Exp table?). + const uint16 Dsp1::DataRom[1024] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, + 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, + 0x4000, 0x7fff, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, + 0x0100, 0x0080, 0x0040, 0x0020, 0x0001, 0x0008, 0x0004, 0x0002, + 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8000, 0xffe5, 0x0100, 0x7fff, 0x7f02, 0x7e08, + 0x7d12, 0x7c1f, 0x7b30, 0x7a45, 0x795d, 0x7878, 0x7797, 0x76ba, + 0x75df, 0x7507, 0x7433, 0x7361, 0x7293, 0x71c7, 0x70fe, 0x7038, + 0x6f75, 0x6eb4, 0x6df6, 0x6d3a, 0x6c81, 0x6bca, 0x6b16, 0x6a64, + 0x69b4, 0x6907, 0x685b, 0x67b2, 0x670b, 0x6666, 0x65c4, 0x6523, + 0x6484, 0x63e7, 0x634c, 0x62b3, 0x621c, 0x6186, 0x60f2, 0x6060, + 0x5fd0, 0x5f41, 0x5eb5, 0x5e29, 0x5d9f, 0x5d17, 0x5c91, 0x5c0c, + 0x5b88, 0x5b06, 0x5a85, 0x5a06, 0x5988, 0x590b, 0x5890, 0x5816, + 0x579d, 0x5726, 0x56b0, 0x563b, 0x55c8, 0x5555, 0x54e4, 0x5474, + 0x5405, 0x5398, 0x532b, 0x52bf, 0x5255, 0x51ec, 0x5183, 0x511c, + 0x50b6, 0x5050, 0x4fec, 0x4f89, 0x4f26, 0x4ec5, 0x4e64, 0x4e05, + 0x4da6, 0x4d48, 0x4cec, 0x4c90, 0x4c34, 0x4bda, 0x4b81, 0x4b28, + 0x4ad0, 0x4a79, 0x4a23, 0x49cd, 0x4979, 0x4925, 0x48d1, 0x487f, + 0x482d, 0x47dc, 0x478c, 0x473c, 0x46ed, 0x469f, 0x4651, 0x4604, + 0x45b8, 0x456c, 0x4521, 0x44d7, 0x448d, 0x4444, 0x43fc, 0x43b4, + 0x436d, 0x4326, 0x42e0, 0x429a, 0x4255, 0x4211, 0x41cd, 0x4189, + 0x4146, 0x4104, 0x40c2, 0x4081, 0x4040, 0x3fff, 0x41f7, 0x43e1, + 0x45bd, 0x478d, 0x4951, 0x4b0b, 0x4cbb, 0x4e61, 0x4fff, 0x5194, + 0x5322, 0x54a9, 0x5628, 0x57a2, 0x5914, 0x5a81, 0x5be9, 0x5d4a, + 0x5ea7, 0x5fff, 0x6152, 0x62a0, 0x63ea, 0x6530, 0x6672, 0x67b0, + 0x68ea, 0x6a20, 0x6b53, 0x6c83, 0x6daf, 0x6ed9, 0x6fff, 0x7122, + 0x7242, 0x735f, 0x747a, 0x7592, 0x76a7, 0x77ba, 0x78cb, 0x79d9, + 0x7ae5, 0x7bee, 0x7cf5, 0x7dfa, 0x7efe, 0x7fff, 0x0000, 0x0324, + 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2, 0x18f8, 0x1c0b, + 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11, 0x30fb, 0x33de, + 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a, 0x471c, 0x49b4, + 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842, 0x5a82, 0x5cb4, + 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6, 0x6a6d, 0x6c24, + 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504, 0x7641, 0x776c, + 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3, 0x7d8a, 0x7e1d, + 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6, 0x7fff, 0x7ff6, + 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, 0x7d8a, 0x7ce3, + 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, 0x7641, 0x7504, + 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, 0x6a6d, 0x68a6, + 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, 0x5a82, 0x5842, + 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, 0x471c, 0x447a, + 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, 0x30fb, 0x2e11, + 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, 0x18f8, 0x15e2, + 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, 0x7fff, 0x7ff6, + 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, 0x7d8a, 0x7ce3, + 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, 0x7641, 0x7504, + 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, 0x6a6d, 0x68a6, + 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, 0x5a82, 0x5842, + 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, 0x471c, 0x447a, + 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, 0x30fb, 0x2e11, + 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, 0x18f8, 0x15e2, + 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, 0x0000, 0xfcdc, + 0xf9b9, 0xf696, 0xf375, 0xf055, 0xed38, 0xea1e, 0xe708, 0xe3f5, + 0xe0e7, 0xdddd, 0xdad8, 0xd7da, 0xd4e1, 0xd1ef, 0xcf05, 0xcc22, + 0xc946, 0xc674, 0xc3aa, 0xc0e9, 0xbe32, 0xbb86, 0xb8e4, 0xb64c, + 0xb3c1, 0xb141, 0xaecd, 0xac65, 0xaa0b, 0xa7be, 0xa57e, 0xa34c, + 0xa129, 0x9f14, 0x9d0e, 0x9b18, 0x9931, 0x975a, 0x9593, 0x93dc, + 0x9236, 0x90a1, 0x8f1e, 0x8dab, 0x8c4b, 0x8afc, 0x89bf, 0x8894, + 0x877c, 0x8676, 0x8583, 0x84a3, 0x83d7, 0x831d, 0x8276, 0x81e3, + 0x8163, 0x80f7, 0x809e, 0x8059, 0x8028, 0x800a, 0x6488, 0x0080, + 0x03ff, 0x0116, 0x0002, 0x0080, 0x4000, 0x3fd7, 0x3faf, 0x3f86, + 0x3f5d, 0x3f34, 0x3f0c, 0x3ee3, 0x3eba, 0x3e91, 0x3e68, 0x3e40, + 0x3e17, 0x3dee, 0x3dc5, 0x3d9c, 0x3d74, 0x3d4b, 0x3d22, 0x3cf9, + 0x3cd0, 0x3ca7, 0x3c7f, 0x3c56, 0x3c2d, 0x3c04, 0x3bdb, 0x3bb2, + 0x3b89, 0x3b60, 0x3b37, 0x3b0e, 0x3ae5, 0x3abc, 0x3a93, 0x3a69, + 0x3a40, 0x3a17, 0x39ee, 0x39c5, 0x399c, 0x3972, 0x3949, 0x3920, + 0x38f6, 0x38cd, 0x38a4, 0x387a, 0x3851, 0x3827, 0x37fe, 0x37d4, + 0x37aa, 0x3781, 0x3757, 0x372d, 0x3704, 0x36da, 0x36b0, 0x3686, + 0x365c, 0x3632, 0x3609, 0x35df, 0x35b4, 0x358a, 0x3560, 0x3536, + 0x350c, 0x34e1, 0x34b7, 0x348d, 0x3462, 0x3438, 0x340d, 0x33e3, + 0x33b8, 0x338d, 0x3363, 0x3338, 0x330d, 0x32e2, 0x32b7, 0x328c, + 0x3261, 0x3236, 0x320b, 0x31df, 0x31b4, 0x3188, 0x315d, 0x3131, + 0x3106, 0x30da, 0x30ae, 0x3083, 0x3057, 0x302b, 0x2fff, 0x2fd2, + 0x2fa6, 0x2f7a, 0x2f4d, 0x2f21, 0x2ef4, 0x2ec8, 0x2e9b, 0x2e6e, + 0x2e41, 0x2e14, 0x2de7, 0x2dba, 0x2d8d, 0x2d60, 0x2d32, 0x2d05, + 0x2cd7, 0x2ca9, 0x2c7b, 0x2c4d, 0x2c1f, 0x2bf1, 0x2bc3, 0x2b94, + 0x2b66, 0x2b37, 0x2b09, 0x2ada, 0x2aab, 0x2a7c, 0x2a4c, 0x2a1d, + 0x29ed, 0x29be, 0x298e, 0x295e, 0x292e, 0x28fe, 0x28ce, 0x289d, + 0x286d, 0x283c, 0x280b, 0x27da, 0x27a9, 0x2777, 0x2746, 0x2714, + 0x26e2, 0x26b0, 0x267e, 0x264c, 0x2619, 0x25e7, 0x25b4, 0x2581, + 0x254d, 0x251a, 0x24e6, 0x24b2, 0x247e, 0x244a, 0x2415, 0x23e1, + 0x23ac, 0x2376, 0x2341, 0x230b, 0x22d6, 0x229f, 0x2269, 0x2232, + 0x21fc, 0x21c4, 0x218d, 0x2155, 0x211d, 0x20e5, 0x20ad, 0x2074, + 0x203b, 0x2001, 0x1fc7, 0x1f8d, 0x1f53, 0x1f18, 0x1edd, 0x1ea1, + 0x1e66, 0x1e29, 0x1ded, 0x1db0, 0x1d72, 0x1d35, 0x1cf6, 0x1cb8, + 0x1c79, 0x1c39, 0x1bf9, 0x1bb8, 0x1b77, 0x1b36, 0x1af4, 0x1ab1, + 0x1a6e, 0x1a2a, 0x19e6, 0x19a1, 0x195c, 0x1915, 0x18ce, 0x1887, + 0x183f, 0x17f5, 0x17ac, 0x1761, 0x1715, 0x16c9, 0x167c, 0x162e, + 0x15df, 0x158e, 0x153d, 0x14eb, 0x1497, 0x1442, 0x13ec, 0x1395, + 0x133c, 0x12e2, 0x1286, 0x1228, 0x11c9, 0x1167, 0x1104, 0x109e, + 0x1036, 0x0fcc, 0x0f5f, 0x0eef, 0x0e7b, 0x0e04, 0x0d89, 0x0d0a, + 0x0c86, 0x0bfd, 0x0b6d, 0x0ad6, 0x0a36, 0x098d, 0x08d7, 0x0811, + 0x0736, 0x063e, 0x0519, 0x039a, 0x0000, 0x7fff, 0x0100, 0x0080, + 0x021d, 0x00c8, 0x00ce, 0x0048, 0x0a26, 0x277a, 0x00ce, 0x6488, + 0x14ac, 0x0001, 0x00f9, 0x00fc, 0x00ff, 0x00fc, 0x00f9, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}; + +////////////////////////////////////////////////////////////////// + diff --git a/src/chip/dsp1/dsp1emu.h b/src/chip/dsp1/dsp1emu.h new file mode 100644 index 00000000..c89e57d7 --- /dev/null +++ b/src/chip/dsp1/dsp1emu.h @@ -0,0 +1,127 @@ +// DSP-1's emulation code +// +// Based on research by Overload, The Dumper, Neviksti and Andreas Naive +// Date: June 2006 + +#ifndef __DSP1EMUL_H +#define __DSP1EMUL_H + +#define DSP1_VERSION 0x0102 + +class Dsp1 +{ + public: + // The DSP-1 status register has 16 bits, but only + // the upper 8 bits can be accessed from an external device, so all these + // positions are referred to the upper byte (bits D8 to D15) + enum SrFlags {DRC=0x04, DRS=0x10, RQM=0x80}; + + // According to Overload's docs, these are the meanings of the flags: + // DRC: The Data Register Control (DRC) bit specifies the data transfer length to and from the host CPU. + // 0: Data transfer to and from the DSP-1 is 16 bits. + // 1: Data transfer to and from the DSP-1 is 8 bits. + // DRS: The Data Register Status (DRS) bit indicates the data transfer status in the case of transfering 16-bit data. + // 0: Data transfer has terminated. + // 1: Data transfer in progress. + // RQM: The Request for Master (RQM) indicates that the DSP1 is requesting host CPU for data read/write. + // 0: Internal Data Register Transfer. + // 1: External Data Register Transfer. + + Dsp1(); + uint8 getSr(); // return the status register's high byte + uint8 getDr(); + void setDr(uint8 iDr); + void reset(); + + private: + enum FsmMajorState {WAIT_COMMAND, READ_DATA, WRITE_DATA}; + enum MaxDataAccesses {MAX_READS=7, MAX_WRITES=1024}; + + struct Command { + void (Dsp1::*callback)(int16 *, int16 *); + unsigned int reads; + unsigned int writes; + }; + + static const Command mCommandTable[]; + static const int16 MaxAZS_Exp[16]; + static const int16 SinTable[]; + static const int16 MulTable[]; + static const uint16 DataRom[]; + + struct SharedData { // some RAM variables shared between commands + int16 MatrixA[3][3]; // attitude matrix A + int16 MatrixB[3][3]; + int16 MatrixC[3][3]; + int16 CentreX, CentreY, CentreZ; // center of projection + int16 CentreZ_C, CentreZ_E; + int16 VOffset; // vertical offset of the screen with regard to the centre of projection + int16 Les, C_Les, E_Les; + int16 SinAas, CosAas; + int16 SinAzs, CosAzs; + int16 SinAZS, CosAZS; + int16 SecAZS_C1, SecAZS_E1; + int16 SecAZS_C2, SecAZS_E2; + int16 Nx, Ny, Nz; // normal vector to the screen (norm 1, points toward the center of projection) + int16 Gx, Gy, Gz; // center of the screen (global coordinates) + int16 Hx, Hy; // horizontal vector of the screen (Hz=0, norm 1, points toward the right of the screen) + int16 Vx, Vy, Vz; // vertical vector of the screen (norm 1, points toward the top of the screen) + + } shared; + + uint8 mSr; // status register + int mSrLowByteAccess; + uint16 mDr; // "internal" representation of the data register + FsmMajorState mFsmMajorState; // current major state of the FSM + uint8 mCommand; // current command processed by the FSM + uint8 mDataCounter; // #uint16 read/writes counter used by the FSM + int16 mReadBuffer[MAX_READS]; + int16 mWriteBuffer[MAX_WRITES]; + bool mFreeze; // need explanation? ;) + + void fsmStep(bool read, uint8 &data); // FSM logic + + // commands + void memoryTest(int16 *input, int16 *output); + void memoryDump(int16 *input, int16 *output); + void memorySize(int16 *input, int16 *output); + void multiply(int16* input, int16* output); + void multiply2(int16* input, int16* output); + void inverse(int16 *input, int16 *output); + void triangle(int16 *input, int16 *output); + void radius(int16 *input, int16 *output); + void range(int16 *input, int16 *output); + void range2(int16 *input, int16 *output); + void distance(int16 *input, int16 *output); + void rotate(int16 *input, int16 *output); + void polar(int16 *input, int16 *output); + void attitudeA(int16 *input, int16 *output); + void attitudeB(int16 *input, int16 *output); + void attitudeC(int16 *input, int16 *output); + void objectiveA(int16 *input, int16 *output); + void objectiveB(int16 *input, int16 *output); + void objectiveC(int16 *input, int16 *output); + void subjectiveA(int16 *input, int16 *output); + void subjectiveB(int16 *input, int16 *output); + void subjectiveC(int16 *input, int16 *output); + void scalarA(int16 *input, int16 *output); + void scalarB(int16 *input, int16 *output); + void scalarC(int16 *input, int16 *output); + void gyrate(int16 *input, int16 *output); + void parameter(int16 *input, int16 *output); + void raster(int16 *input, int16 *output); + void target(int16 *input, int16 *output); + void project(int16 *input, int16 *output); + + // auxiliar functions + int16 sin(int16 Angle); + int16 cos(int16 Angle); + void inverse(int16 Coefficient, int16 Exponent, int16 &iCoefficient, int16 &iExponent); + int16 denormalizeAndClip(int16 C, int16 E); + void normalize(int16 m, int16 &Coefficient, int16 &Exponent); + void normalizeDouble(int32 Product, int16 &Coefficient, int16 &Exponent); + int16 shiftR(int16 C, int16 E); +}; + +#endif + diff --git a/src/chip/dsp2/dsp2.h b/src/chip/dsp2/dsp2.h index 1c3b9a45..a506454c 100644 --- a/src/chip/dsp2/dsp2.h +++ b/src/chip/dsp2/dsp2.h @@ -1,13 +1,13 @@ class DSP2 { public: struct { - bool waiting_for_command; - uint command; - uint in_count, in_index; - uint out_count, out_index; + bool waiting_for_command; + uint command; + uint in_count, in_index; + uint out_count, out_index; - uint8 parameters[512]; - uint8 output[512]; + uint8 parameters[512]; + uint8 output[512]; uint8 op05transparent; bool op05haslen; @@ -20,6 +20,7 @@ struct { int op0doutlen; int op0dinlen; } status; + void init(); void enable(); void power(); diff --git a/src/config/config.cpp b/src/config/config.cpp index 624cf2e7..a486fdd9 100644 --- a/src/config/config.cpp +++ b/src/config/config.cpp @@ -55,7 +55,7 @@ void SNES::VideoColorAdjust::set(uint32 _data) { Setting SNES::ntsc_merge_fields(&config_file, "snes.ntsc_merge_fields", "Merge fields in NTSC video filter\n" "Set to true if using filter at any refresh rate other than 60hz\n" -"", false, Setting::TRUE_FALSE); +"", true, Setting::TRUE_FALSE); Setting SNES::mute(&config_file, "snes.mute", "Mutes SNES audio output when enabled", false, Setting::TRUE_FALSE); diff --git a/src/cpu/bcpu/bcpu.cpp b/src/cpu/bcpu/bcpu.cpp index 8d5dae8c..d7f8ae3d 100644 --- a/src/cpu/bcpu/bcpu.cpp +++ b/src/cpu/bcpu/bcpu.cpp @@ -27,11 +27,11 @@ void bCPU::run() { if(!run_state.irq && !run_state.stp) { if(time.nmi_pending == true) { time.nmi_pending = false; - aa.w = 0xffea; + aa.w = (regs.e == false) ? 0xffea : 0xfffa; run_state.irq = true; } else if(time.irq_pending == true) { time.irq_pending = false; - aa.w = 0xffee; + aa.w = (regs.e == false) ? 0xffee : 0xfffe; run_state.irq = true; } } @@ -41,9 +41,9 @@ void bCPU::run() { } void bCPU::scanline() { - time.hdma_triggered = false; + time.hdma_triggered = (vcounter() <= (!overscan() ? 224 : 239)) ? false : true; - if(vcounter() == (overscan() == false ? 227 : 242) && status.auto_joypad_poll == true) { + if(vcounter() == (!overscan() ? 227 : 242) && status.auto_joypad_poll == true) { snes->poll_input(SNES::DEV_JOYPAD1); snes->poll_input(SNES::DEV_JOYPAD2); //When the SNES auto-polls the joypads, it writes 1, then 0 to @@ -93,9 +93,6 @@ void bCPU::reset() { regs.e = 1; regs.mdr = 0x00; -//simulate pbr:pc push during reset irq vector - regs.s.l -= 3; - time_reset(); mmio_reset(); dma_reset(); diff --git a/src/cpu/bcpu/bcpu.h b/src/cpu/bcpu/bcpu.h index 9018027e..fd0dbef4 100644 --- a/src/cpu/bcpu/bcpu.h +++ b/src/cpu/bcpu/bcpu.h @@ -82,7 +82,7 @@ struct { inline uint8 pio_status(); inline void run(); - inline uint32 cycles_executed(); + inline uint32 clocks_executed(); inline void scanline(); inline void frame(); inline void power(); diff --git a/src/cpu/bcpu/bcpu_exec.cpp b/src/cpu/bcpu/bcpu_exec.cpp index 3020aff9..427f9e4f 100644 --- a/src/cpu/bcpu/bcpu_exec.cpp +++ b/src/cpu/bcpu/bcpu_exec.cpp @@ -1,8 +1,8 @@ void bCPU::last_cycle() { //DMV27: keep previous nmi value, //to allow wai and irq to work properly - time.nmi_pending = nmi_test() || time.nmi_pending; - time.irq_pending = irq_test(); + time.nmi_pending |= nmi_test(); + time.irq_pending |= irq_test(); } void bCPU::pre_exec_cycle() { @@ -56,12 +56,7 @@ static int z; status.hdma_state = HDMASTATE_IDMASYNC3; break; case HDMASTATE_IDMASYNC3: - channel[z].hdma_active = channel[z].hdma_enabled; - if(channel[z].hdma_enabled) { - channel[z].hdma_addr = channel[z].srcaddr; - hdma_update(z); //updates status.hdma_cycle_count - } - if(++z < 8)break; + hdma_init(); if(!run_state.dma) { status.hdma_state = HDMASTATE_ICPUSYNC; } else { @@ -89,7 +84,7 @@ static int z; status.hdma_state = HDMASTATE_DMASYNC3; break; case HDMASTATE_DMASYNC3: - if(channel[z].hdma_active) { + if(channel[z].hdma_line_counter) { add_cycles(8); status.hdma_cycle_count += 8; } @@ -126,7 +121,7 @@ static int z; status.dma_state = DMASTATE_DMASYNC3; break; case DMASTATE_DMASYNC3: - if(channel[z].active == true) { + if(channel[z].dma_enabled == true) { add_cycles(8); status.dma_cycle_count += 8; } diff --git a/src/cpu/bcpu/bcpu_int.cpp b/src/cpu/bcpu/bcpu_int.cpp index d2ee6e5f..3c4e8b69 100644 --- a/src/cpu/bcpu/bcpu_int.cpp +++ b/src/cpu/bcpu/bcpu_int.cpp @@ -32,7 +32,7 @@ void bCPU::irq_run() { break; case 5: //emulation-mode irqs clear brk bit 0x10 - stack_write((regs.e) ? (regs.p & ~0x10) : regs.p); + stack_write(regs.e ? (regs.p & ~0x10) : regs.p); break; case 6: //todo: test if NMI can override IRQ here... @@ -83,6 +83,5 @@ _true: time.irq_transition = 0; run_state.wai = false; - if(regs.p.i)return false; - return true; + return (regs.p.i) ? false : true; } diff --git a/src/cpu/bcpu/bcpu_mmio.cpp b/src/cpu/bcpu/bcpu_mmio.cpp index d2a03a7c..0b3b0c6d 100644 --- a/src/cpu/bcpu/bcpu_mmio.cpp +++ b/src/cpu/bcpu/bcpu_mmio.cpp @@ -329,12 +329,12 @@ uint8 bCPU::mmio_r43xb(uint8 i) { uint8 bCPU::mmio_read(uint16 addr) { //APU - if(addr >= 0x2140 && addr <= 0x217f) { + if((addr & 0xffc0) == 0x2140) { //$2140-$217f return r_apu->port_read(addr & 3); } //HDMA - if(addr >= 0x4300 && addr <= 0x437f) { + if((addr & 0xff80) == 0x4300) { //$4300-$437f uint i = (addr >> 4) & 7; switch(addr & 0xf) { case 0x0: return mmio_r43x0(i); @@ -457,6 +457,7 @@ void bCPU::mmio_w4202(uint8 value) { status.mul_a = value; } +//WRMPYB void bCPU::mmio_w4203(uint8 value) { status.mul_b = value; status.r4216 = status.mul_a * status.mul_b; @@ -464,7 +465,7 @@ void bCPU::mmio_w4203(uint8 value) { //WRDIVL void bCPU::mmio_w4204(uint8 value) { - status.div_a = (status.div_a & 0xff00) | value; + status.div_a = (status.div_a & 0xff00) | (value); } //WRDIVH @@ -504,6 +505,7 @@ void bCPU::mmio_w420a(uint8 value) { } //DMAEN +//DMA enable does not disable active HDMA channels void bCPU::mmio_w420b(uint8 value) { if(value != 0x00) { run_state.dma = true; @@ -511,11 +513,9 @@ void bCPU::mmio_w420b(uint8 value) { } for(int i = 0; i < 8; i++) { - if(value & (1 << i)) { - //DMA enable does not disable active HDMA channels - channel[i].active = true; - channel[i].read_index = 0; - } + channel[i].dma_enabled = bool(value & (1 << i)); + //TODO: clearing read_index may interfere with DMA+HDMA occurring simultaneously + if(channel[i].dma_enabled)channel[i].read_index = 0; } } @@ -523,7 +523,6 @@ void bCPU::mmio_w420b(uint8 value) { void bCPU::mmio_w420c(uint8 value) { for(int i = 0; i < 8; i++) { channel[i].hdma_enabled = bool(value & (1 << i)); - channel[i].hdma_active = bool(value & (1 << i)); } } @@ -599,13 +598,13 @@ void bCPU::mmio_w43xb(uint8 value, uint8 i) { void bCPU::mmio_write(uint16 addr, uint8 data) { //APU - if(addr >= 0x2140 && addr <= 0x217f) { + if((addr & 0xffc0) == 0x2140) { //$2140-$217f port_write(addr & 3, data); return; } //HDMA - if(addr >= 0x4300 && addr <= 0x437f) { + if((addr & 0xff80) == 0x4300) { //$4300-$437f uint i = (addr >> 4) & 7; switch(addr & 0xf) { case 0x0: mmio_w43x0(data, i); return; diff --git a/src/cpu/bcpu/core/clean.bat b/src/cpu/bcpu/core/clean.bat index eeb92f44..d807f14d 100644 --- a/src/cpu/bcpu/core/clean.bat +++ b/src/cpu/bcpu/core/clean.bat @@ -1,8 +1 @@ @del *.exe -@del op_misc.cpp -@del op_pc.cpp -@del op_read.cpp -@del op_rmw.cpp -@del op_write.cpp -@del optable.cpp -@del op.h diff --git a/src/cpu/bcpu/dma/dma.cpp b/src/cpu/bcpu/dma/dma.cpp index b7442b28..259fd45d 100644 --- a/src/cpu/bcpu/dma/dma.cpp +++ b/src/cpu/bcpu/dma/dma.cpp @@ -31,6 +31,20 @@ uint8 r; } } +uint8 bCPU::dma_bbus(uint8 i, uint8 index) { + switch(channel[i].xfermode) { + default: + case 0: return (channel[i].destaddr); break; //0 + case 1: return (channel[i].destaddr + (index & 1)); break; //0,1 + case 2: return (channel[i].destaddr); break; //0,0 + case 3: return (channel[i].destaddr + ((index >> 1) & 1)); break; //0,0,1,1 + case 4: return (channel[i].destaddr + (index & 3)); break; //0,1,2,3 + case 5: return (channel[i].destaddr + (index & 1)); break; //0,1,0,1 + case 6: return (channel[i].destaddr); break; //0,0 [2] + case 7: return (channel[i].destaddr + ((index >> 1) & 1)); break; //0,0,1,1 [3] + } +} + void bCPU::dma_add_cycles(uint32 cycles) { status.dma_cycle_count += cycles; } @@ -53,19 +67,19 @@ uint32 r; return r; } -void bCPU::dma_cputommio(uint8 i, uint8 index) { - if(sdd1->dma_active() == true) { - r_mem->write(0x2100 | ((channel[i].destaddr + index) & 0xff), sdd1->dma_read()); +void bCPU::dma_cputommio(uint8 i, uint8 bbus) { + if(cartridge.cart.sdd1 == true && sdd1->dma_active() == true) { + r_mem->write(0x2100 | bbus, sdd1->dma_read()); } else { - dma_transfer_byte(0, ((channel[i].destaddr + index) & 0xff), dma_addr(i)); + dma_transfer_byte(0, bbus, dma_addr(i)); } add_cycles(8); channel[i].xfersize--; } -void bCPU::dma_mmiotocpu(uint8 i, uint8 index) { - dma_transfer_byte(1, ((channel[i].destaddr + index) & 0xff), dma_addr(i)); +void bCPU::dma_mmiotocpu(uint8 i, uint8 bbus) { + dma_transfer_byte(1, bbus, dma_addr(i)); add_cycles(8); channel[i].xfersize--; @@ -81,30 +95,19 @@ void bCPU::dma_write(uint8 i, uint8 index) { void bCPU::dma_run() { for(int i = 0; i < 8; i++) { - if(channel[i].active == false)continue; + if(channel[i].dma_enabled == false)continue; //first byte transferred? - if(channel[i].read_index == 0) { + if(cartridge.cart.sdd1 == true && channel[i].read_index == 0) { sdd1->dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr), channel[i].xfersize); } - switch(channel[i].xfermode) { - case 0: dma_write(i, 0); break; //0 - case 1: dma_write(i, channel[i].read_index & 1); break; //0,1 - case 2: dma_write(i, 0); break; //0,0 - case 3: dma_write(i, (channel[i].read_index >> 1) & 1); break; //0,0,1,1 - case 4: dma_write(i, channel[i].read_index & 3); break; //0,1,2,3 - case 5: dma_write(i, channel[i].read_index & 1); break; //0,1,0,1 - case 6: dma_write(i, 0); break; //0,0 [2] - case 7: dma_write(i, (channel[i].read_index >> 1) & 1); break; //0,0,1,1 [3] - } - - channel[i].read_index++; + dma_write(i, dma_bbus(i, channel[i].read_index++)); dma_add_cycles(8); if(channel[i].xfersize == 0) { - channel[i].active = false; + channel[i].dma_enabled = false; } return; @@ -121,23 +124,6 @@ uint32 bCPU::hdma_iaddr(uint8 i) { return (channel[i].hdma_ibank << 16) | (channel[i].hdma_iaddr++); } -uint16 bCPU::hdma_mmio(uint8 i) { -uint8 l = channel[i].read_index; -uint16 index; - switch(channel[i].xfermode) { - case 0: index = 0; break; //0 - case 1: index = l & 1; break; //0,1 - case 2: index = 0; break; //0,0 - case 3: index = (l >> 1) & 1; break; //0,0,1,1 - case 4: index = l & 3; break; //0,1,2,3 - case 5: index = l & 1; break; //0,1,0,1 - case 6: index = 0; break; //0,0 [2] - case 7: index = (l >> 1) & 1; break; //0,0,1,1 [3] - } - - return (0x2100 | ((channel[i].destaddr + index) & 0xff)); -} - void bCPU::hdma_update(uint8 i) { channel[i].hdma_line_counter = r_mem->read(hdma_addr(i)); add_cycles(8); @@ -150,7 +136,7 @@ void bCPU::hdma_update(uint8 i) { } if(channel[i].hdma_line_counter == 0) { - channel[i].hdma_active = false; + channel[i].hdma_completed = true; channel[i].hdma_do_transfer = false; return; } @@ -168,13 +154,13 @@ void bCPU::hdma_update(uint8 i) { void bCPU::hdma_run() { static uint8 hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 }; for(int i = 0; i < 8; i++) { - if(!channel[i].hdma_enabled || !channel[i].hdma_active)continue; + if(!channel[i].hdma_enabled || channel[i].hdma_completed)continue; if(channel[i].hdma_do_transfer) { int xferlen = hdma_xferlen[channel[i].xfermode]; for(channel[i].read_index = 0; channel[i].read_index < xferlen; channel[i].read_index++) { if(bool(config::cpu.hdma_enable) == true) { - dma_transfer_byte(channel[i].direction, hdma_mmio(i), + dma_transfer_byte(channel[i].direction, dma_bbus(i, channel[i].read_index), channel[i].hdma_indirect ? hdma_iaddr(i) : hdma_addr(i)); } add_cycles(8); @@ -190,6 +176,15 @@ static uint8 hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 }; } } +void bCPU::hdma_init() { + for(int i = 0; i < 8; i++) { + if(!channel[i].hdma_enabled)continue; + + channel[i].hdma_addr = channel[i].srcaddr; + hdma_update(i); + } +} + uint8 bCPU::hdma_enabled_channels() { int r = 0; for(int i = 0; i < 8; i++) { @@ -201,7 +196,7 @@ int r = 0; uint8 bCPU::hdma_active_channels() { int r = 0; for(int i = 0; i < 8; i++) { - if(channel[i].hdma_enabled && channel[i].hdma_active)r++; + if(channel[i].hdma_enabled && !channel[i].hdma_completed)r++; } return r; } @@ -215,7 +210,7 @@ int r = 0; void bCPU::hdmainit_activate() { for(int i = 0; i < 8; i++) { - channel[i].hdma_active = false; + channel[i].hdma_completed = false; channel[i].hdma_do_transfer = false; } @@ -240,7 +235,7 @@ void bCPU::dma_reset() { for(int i = 0; i < 8; i++) { channel[i].read_index = 0; - channel[i].active = false; + channel[i].dma_enabled = false; channel[i].hdma_enabled = false; channel[i].dmap = 0xff; channel[i].direction = 1; @@ -259,7 +254,7 @@ void bCPU::dma_reset() { channel[i].hdma_line_counter = 0xff; channel[i].hdma_unknown = 0xff; - channel[i].hdma_active = false; + channel[i].hdma_completed = false; channel[i].hdma_do_transfer = false; } } diff --git a/src/cpu/bcpu/dma/dma.h b/src/cpu/bcpu/dma/dma.h index 2a123703..fd0ba726 100644 --- a/src/cpu/bcpu/dma/dma.h +++ b/src/cpu/bcpu/dma/dma.h @@ -2,7 +2,7 @@ struct { uint32 read_index; //set to 0 at beginning of DMA/HDMA //$420b - bool active; + bool dma_enabled; //$420c bool hdma_enabled; //$43x0 @@ -33,7 +33,7 @@ struct { uint8 hdma_unknown; //hdma-specific - bool hdma_active; + bool hdma_completed; //for this frame bool hdma_do_transfer; uint8 hdma_current_channel; @@ -41,10 +41,12 @@ struct { } channel[8]; inline void dma_transfer_byte(bool direction, uint8 bbus, uint32 abus); + inline uint8 dma_bbus(uint8 i, uint8 index); inline void dma_add_cycles(uint32 cycles); inline void hdma_add_cycles(uint32 cycles); inline void dma_run(); inline void hdma_run(); + inline void hdma_init(); inline void hdma_update(uint8 i); inline uint8 hdma_enabled_channels(); inline uint8 hdma_active_channels(); @@ -56,5 +58,4 @@ struct { inline uint32 dma_addr(uint8 i); inline uint32 hdma_addr(uint8 i); inline uint32 hdma_iaddr(uint8 i); - inline uint16 hdma_mmio(uint8 i); inline void dma_reset(); diff --git a/src/cpu/bcpu/timing/timing.cpp b/src/cpu/bcpu/timing/timing.cpp index 6e84f6a3..1f857f59 100644 --- a/src/cpu/bcpu/timing/timing.cpp +++ b/src/cpu/bcpu/timing/timing.cpp @@ -48,15 +48,16 @@ uint16 hc = 2 + offset; bool bCPU::irq_trigger_pos_match(uint32 offset) { uint16 v = status.virq_pos; uint16 hc = (status.hirq_enabled) ? status.hirq_pos : 0; +uint16 vlimit = region_scanlines() >> 1; //positions that can never be latched -//region_scanlines() = 262/NTSC, 312/PAL +//region_scanlines() = 525/NTSC, 625/PAL //PAL results are unverified on hardware if(v == 240 && hc == 339 && interlace() == false && interlace_field() == 1)return false; - if(v == (region_scanlines() - 1) && hc == 339 && interlace() == false)return false; - if(v == region_scanlines() && interlace() == false)return false; - if(v == region_scanlines() && hc == 339)return false; - if(v > region_scanlines())return false; + if(v == (vlimit - 1) && hc == 339 && interlace() == false)return false; + if(v == vlimit && interlace() == false)return false; + if(v == vlimit && hc == 339)return false; + if(v > vlimit)return false; if(hc > 339)return false; hc = (hc != 0) ? ((hc << 2) + 14) : 10; @@ -88,15 +89,16 @@ void bCPU::update_nmi() { void bCPU::update_irq() { int vpos = status.virq_pos; int hpos = (status.hirq_enabled) ? status.hirq_pos : 0; +int vlimit = region_scanlines() >> 1; //positions that can never be latched //region_scanlines() = 262/NTSC, 312/PAL //PAL results are unverified on hardware if(vpos == 240 && hpos == 339 && interlace() == false && interlace_field() == 1)goto _nolatch; - if(vpos == (region_scanlines() - 1) && hpos == 339 && interlace() == false)goto _nolatch; - if(vpos == region_scanlines() && interlace() == false)goto _nolatch; - if(vpos == region_scanlines() && hpos == 339)goto _nolatch; - if(vpos > region_scanlines())goto _nolatch; + if(vpos == (vlimit - 1) && hpos == 339 && interlace() == false)goto _nolatch; + if(vpos == vlimit && interlace() == false)goto _nolatch; + if(vpos == vlimit && hpos == 339)goto _nolatch; + if(vpos > vlimit)goto _nolatch; if(hpos > 339)goto _nolatch; hpos = (hpos != 0) ? ((hpos << 2) + 14) : 10; @@ -201,9 +203,9 @@ void bCPU::inc_vcounter() { time.interlace_field ^= 1; if(interlace() == true && interlace_field() == 0) { - time.frame_lines = time.region_scanlines + 1; + time.frame_lines = (time.region_scanlines >> 1) + 1; } else { - time.frame_lines = time.region_scanlines; + time.frame_lines = (time.region_scanlines >> 1); } } @@ -233,7 +235,7 @@ uint16 bCPU::get_hcounter() { return (time.hc - ((time.hc > 1292) << 1) - ((time.hc > 1310) << 1)) >> 2; } -uint32 bCPU::cycles_executed() { +uint32 bCPU::clocks_executed() { uint32 r = status.cycles_executed; status.cycles_executed = 0; return r; @@ -248,18 +250,16 @@ void bCPU::cycle_edge() { } if(time.hdma_triggered == false) { - if(time.v <= (overscan() ? 239 : 224)) { - if(time.hc >= 1106) { - time.hdma_triggered = true; - hdma_activate(); - } + //hdma_triggered only set to false for v <= (overscan ? 239 : 224) + if(time.hc >= 1106) { + time.hdma_triggered = true; + hdma_activate(); } } } void bCPU::add_cycles(int cycles) { status.cycles_executed += cycles; - poll_interrupts(cycles); if(time.hc + cycles >= time.line_cycles) { @@ -267,7 +267,6 @@ void bCPU::add_cycles(int cycles) { time.hc = 0; inc_vcounter(); - poll_interrupts(cycles); if(time.v == 0) { frame(); @@ -279,8 +278,20 @@ void bCPU::add_cycles(int cycles) { r_ppu->scanline(); snes->scanline(); time.line_rendered = false; + + poll_interrupts(cycles); } + time.hc += cycles; + + if(time.dram_refreshed == false) { + if(time.hc >= time.dram_refresh_pos) { + time.dram_refreshed = true; + add_cycles(40); + return; + } + } +/* if(time.dram_refreshed == false) { if(time.hc + cycles >= time.dram_refresh_pos) { time.dram_refreshed = true; @@ -299,19 +310,19 @@ void bCPU::add_cycles(int cycles) { } } } - +*/ if(time.line_rendered == false) { //rendering should start at H=18 (+256=274), but since the //current PPU emulation renders the entire scanline at once, //PPU register changes mid-scanline do not show up. //therefore, wait a few dots before rendering the scanline - if(time.hc + cycles >= (48 * 4)) { + if(time.hc >= (48 * 4)) { time.line_rendered = true; r_ppu->render_scanline(); } } - time.hc += cycles; +//time.hc += cycles; } void bCPU::time_reset() { @@ -347,12 +358,12 @@ void bCPU::time_reset() { switch(region) { case NTSC: - time.region_scanlines = 262; + time.region_scanlines = 525; break; case PAL: - time.region_scanlines = 312; + time.region_scanlines = 625; break; } - time.frame_lines = time.region_scanlines; + time.frame_lines = time.region_scanlines >> 1; } diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 915a06b0..8026f73d 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -12,9 +12,9 @@ uint8 cpu_version; virtual uint16 vcounter() = 0; virtual uint16 hcounter() = 0; virtual uint16 hcycles() = 0; - virtual bool overscan() = 0; virtual bool interlace() = 0; virtual bool interlace_field() = 0; + virtual bool overscan() = 0; virtual uint16 region_scanlines() = 0; virtual void set_interlace(bool r) = 0; virtual void set_overscan (bool r) = 0; @@ -30,14 +30,32 @@ CPURegs regs; FLAG_Z = 0x02, FLAG_C = 0x01 }; virtual uint8 pio_status() = 0; + virtual void main() {} virtual void run() = 0; - virtual uint32 cycles_executed() = 0; + virtual uint32 clocks_executed() = 0; virtual void scanline() = 0; virtual void frame() = 0; virtual void power() = 0; virtual void reset() = 0; -//opcode disassembler +/***** + * in opcode-based CPU emulators, the main emulation routine + * will only be able to call the disassemble_opcode() function + * on clean opcode edges. but with cycle-based CPU emulators, + * the CPU may be in the middle of executing an opcode when the + * emulator (e.g. debugger) wants to disassemble an opcode. this + * would mean that important registers may not reflect what they + * did at the start of the opcode (especially regs.pc), so in + * cycle-based emulators, this function should be overridden to + * reflect whether or not an opcode has only been partially + * executed. if not, the debugger should abort attempts to skip, + * disable, or disassemble the current opcode. + *****/ + virtual bool in_opcode() { return false; } + +/***** + * opcode disassembler + *****/ enum { OPTYPE_DP = 0, //dp OPTYPE_DPX, //dp,x @@ -57,16 +75,17 @@ enum { OPTYPE_SR, //sr,s OPTYPE_ISRY, //(sr,s),y OPTYPE_ADDR_PC, //pbr:addr - OPTYPE_IADDR_PC //pbr:(addr) + OPTYPE_IADDR_PC, //pbr:(addr) + OPTYPE_RELB, //relb + OPTYPE_RELW, //relw }; -//see dcpu.cpp for notes on this function - virtual bool in_opcode(); void disassemble_opcode(char *output); - uint32 resolve_offset(uint8 offset_type, uint32 addr); + uint8 dreadb(uint32 addr); + uint16 dreadw(uint32 addr); + uint32 dreadl(uint32 addr); + uint32 decode(uint8 offset_type, uint32 addr); uint8 opcode_length(); - uint16 __relb(int8 offset); - uint16 __relw(int16 offset); CPU(); virtual ~CPU() {} diff --git a/src/cpu/cpuregs.h b/src/cpu/cpuregs.h index bf5207cb..62852687 100644 --- a/src/cpu/cpuregs.h +++ b/src/cpu/cpuregs.h @@ -1,20 +1,18 @@ class CPURegFlags { private: - template class bit { + template class bit { public: - uint8 _b; - inline operator bool() { return (_b & B); } - inline bool operator = (bool i) { (i) ? _b |= B : _b &= ~B; return (_b & B); } - inline bool operator & (bool i) { if(i)_b &= ~B; return (_b & B); } - inline bool operator &= (bool i) { if(i)_b &= ~B; return (_b & B); } - inline bool operator | (bool i) { if(i)_b |= B; return (_b & B); } - inline bool operator |= (bool i) { if(i)_b |= B; return (_b & B); } - inline bool operator ^ (bool i) { if(i)_b ^= B; return (_b & B); } - inline bool operator ^= (bool i) { if(i)_b ^= B; return (_b & B); } + uint data; + inline operator bool() { return bool(data & mask); } + inline bool operator = (const bool i) { (i) ? data |= mask : data &= ~mask; return bool(data & mask); } + inline bool operator |= (const bool i) { if(i)data |= mask; return bool(data & mask); } + inline bool operator ^= (const bool i) { if(i)data ^= mask; return bool(data & mask); } + inline bool operator &= (const bool i) { if(i)data &= mask; return bool(data & mask); } }; + public: union { - uint8 _b; + uint8 data; bit<0x80> n; bit<0x40> v; bit<0x20> m, p; @@ -25,64 +23,57 @@ union { bit<0x01> c; }; - CPURegFlags() { _b = 0; } - inline operator uint8() { return _b; } - inline unsigned operator = (uint8 i) { _b = i; return _b; } - inline unsigned operator &= (uint8 i) { _b &= i; return _b; } - inline unsigned operator |= (uint8 i) { _b |= i; return _b; } - inline unsigned operator ^= (uint8 i) { _b ^= i; return _b; } + CPURegFlags() { data = 0; } + inline operator unsigned() { return data; } + inline unsigned operator = (const uint8 i) { data = i; return data; } + inline unsigned operator |= (const uint8 i) { data |= i; return data; } + inline unsigned operator ^= (const uint8 i) { data ^= i; return data; } + inline unsigned operator &= (const uint8 i) { data &= i; return data; } }; class CPUReg16 { public: union { uint16 w; -#ifdef ARCH_LSB - struct { uint8 l, h; }; -#else - struct { uint8 h, l; }; -#endif + struct { uint8 order_lsb2(l, h); }; }; CPUReg16() { w = 0; } - inline operator uint16() { return w; } - inline unsigned operator = (uint16 i) { w = i; return w; } - inline unsigned operator += (uint16 i) { w += i; return w; } - inline unsigned operator -= (uint16 i) { w -= i; return w; } - inline unsigned operator *= (uint16 i) { w *= i; return w; } - inline unsigned operator /= (uint16 i) { w /= i; return w; } - inline unsigned operator &= (uint16 i) { w &= i; return w; } - inline unsigned operator |= (uint16 i) { w |= i; return w; } - inline unsigned operator ^= (uint16 i) { w ^= i; return w; } - inline unsigned operator <<= (uint16 i) { w <<= i; return w; } - inline unsigned operator >>= (uint16 i) { w >>= i; return w; } + inline operator unsigned() { return w; } + template inline unsigned operator = (const T i) { w = i; return w; } + template inline unsigned operator |= (const T i) { w |= i; return w; } + template inline unsigned operator ^= (const T i) { w ^= i; return w; } + template inline unsigned operator &= (const T i) { w &= i; return w; } + template inline unsigned operator <<= (const T i) { w <<= i; return w; } + template inline unsigned operator >>= (const T i) { w >>= i; return w; } + template inline unsigned operator += (const T i) { w += i; return w; } + template inline unsigned operator -= (const T i) { w -= i; return w; } + template inline unsigned operator *= (const T i) { w *= i; return w; } + template inline unsigned operator /= (const T i) { w /= i; return w; } + template inline unsigned operator %= (const T i) { w %= i; return w; } }; class CPUReg24 { public: union { uint32 d; -#ifdef ARCH_LSB - struct { uint16 w, null_w; }; - struct { uint8 l, h, b, null_b; }; -#else - struct { uint16 null_w, w; }; - struct { uint8 null_b, b, h, l; }; -#endif + struct { uint16 order_lsb2(w, wh); }; + struct { uint8 order_lsb4(l, h, b, bh); }; }; CPUReg24() { d = 0; } - inline operator uint32() { return (d & 0xffffff); } - inline unsigned operator = (uint16 i) { d = i; return d; } - inline unsigned operator += (uint16 i) { d += i; return d; } - inline unsigned operator -= (uint16 i) { d -= i; return d; } - inline unsigned operator *= (uint16 i) { d *= i; return d; } - inline unsigned operator /= (uint16 i) { d /= i; return d; } - inline unsigned operator &= (uint16 i) { d &= i; return d; } - inline unsigned operator |= (uint16 i) { d |= i; return d; } - inline unsigned operator ^= (uint16 i) { d ^= i; return d; } - inline unsigned operator <<= (uint16 i) { d <<= i; return d; } - inline unsigned operator >>= (uint16 i) { d >>= i; return d; } + inline operator unsigned() { return d; } + template inline unsigned operator = (const T i) { d = uclip<24>(i); return d; } + template inline unsigned operator |= (const T i) { d = uclip<24>(d | i); return d; } + template inline unsigned operator ^= (const T i) { d = uclip<24>(d ^ i); return d; } + template inline unsigned operator &= (const T i) { d = uclip<24>(d & i); return d; } + template inline unsigned operator <<= (const T i) { d = uclip<24>(d << i); return d; } + template inline unsigned operator >>= (const T i) { d = uclip<24>(d >> i); return d; } + template inline unsigned operator += (const T i) { d = uclip<24>(d + i); return d; } + template inline unsigned operator -= (const T i) { d = uclip<24>(d - i); return d; } + template inline unsigned operator *= (const T i) { d = uclip<24>(d * i); return d; } + template inline unsigned operator /= (const T i) { d = uclip<24>(d / i); return d; } + template inline unsigned operator %= (const T i) { d = uclip<24>(d % i); return d; } }; class CPURegs { @@ -90,8 +81,8 @@ public: CPUReg24 pc; CPUReg16 a, x, y, s, d; CPURegFlags p; -uint8 db; -uint8 mdr; //memory data register (openbus) -bool e; +uint8 db; +uint8 mdr; +bool e; CPURegs() { db = 0; mdr = 0x00; e = false; } }; diff --git a/src/cpu/dcpu.cpp b/src/cpu/dcpu.cpp index 8a3952ae..5a6ed51e 100644 --- a/src/cpu/dcpu.cpp +++ b/src/cpu/dcpu.cpp @@ -1,30 +1,28 @@ -//this is a virtual function. -//in opcode-based CPU emulators, the main emulation routine -//will only be able to call the disassemble_opcode() function -//on clean opcode edges. but with cycle-based CPU emulators, -//the CPU may be in the middle of executing an opcode when the -//emulator (e.g. debugger) wants to disassemble an opcode. this -//would mean that important registers may not reflect what they -//did at the start of the opcode (especially regs.pc), so in -//cycle-based emulators, this function should be overridden to -//reflect whether or not an opcode has only been partially -//executed. if not, the debugger should abort attempts to skip, -//disable, or disassemble the current opcode. -bool CPU::in_opcode() { return false; } - -uint16 CPU::__relb(int8 offset) { -uint32 addr; - addr = (regs.pc.d & 0xff0000) | ((regs.pc.d + 2) & 0xffff); - return addr + offset; +uint8 CPU::dreadb(uint32 addr) { + if((addr & 0x40ffff) >= 0x2000 && (addr & 0x40ffff) <= 0x5fff) { + //$[00-3f|80-bf]:[2000-5fff] + //do not read MMIO registers within debugger + return 0x00; + } + return r_mem->read(addr); } -uint16 CPU::__relw(int16 offset) { -uint32 addr; - addr = (regs.pc.d & 0xff0000) | ((regs.pc.d + 3) & 0xffff); - return addr + offset; +uint16 CPU::dreadw(uint32 addr) { +uint16 r; + r = dreadb((addr + 0) & 0xffffff) << 0; + r |= dreadb((addr + 1) & 0xffffff) << 8; + return r; } -uint32 CPU::resolve_offset(uint8 offset_type, uint32 addr) { +uint32 CPU::dreadl(uint32 addr) { +uint32 r; + r = dreadb((addr + 0) & 0xffffff) << 0; + r |= dreadb((addr + 1) & 0xffffff) << 8; + r |= dreadb((addr + 2) & 0xffffff) << 16; + return r; +} + +uint32 CPU::decode(uint8 offset_type, uint32 addr) { uint32 r = 0; switch(offset_type) { case OPTYPE_DP: @@ -38,23 +36,23 @@ uint32 r = 0; break; case OPTYPE_IDP: addr = (regs.d + (addr & 0xffff)) & 0xffff; - r = (regs.db << 16) + r_mem->read_word(addr); + r = (regs.db << 16) + dreadw(addr); break; case OPTYPE_IDPX: addr = (regs.d + regs.x + (addr & 0xffff)) & 0xffff; - r = (regs.db << 16) + r_mem->read_word(addr); + r = (regs.db << 16) + dreadw(addr); break; case OPTYPE_IDPY: addr = (regs.d + (addr & 0xffff)) & 0xffff; - r = (regs.db << 16) + r_mem->read_word(addr) + regs.y; + r = (regs.db << 16) + dreadw(addr) + regs.y; break; case OPTYPE_ILDP: addr = (regs.d + (addr & 0xffff)) & 0xffff; - r = r_mem->read_long(addr); + r = dreadl(addr); break; case OPTYPE_ILDPY: addr = (regs.d + (addr & 0xffff)) & 0xffff; - r = r_mem->read_long(addr) + regs.y; + r = dreadl(addr) + regs.y; break; case OPTYPE_ADDR: r = (regs.db << 16) + (addr & 0xffff); @@ -75,31 +73,37 @@ uint32 r = 0; r = (regs.pc.b << 16) + ((addr + regs.x) & 0xffff); break; case OPTYPE_ILADDR: - r = addr & 0xffffff; + r = addr; break; case OPTYPE_LONG: - r = addr & 0xffffff; + r = addr; break; case OPTYPE_LONGX: - r = (addr + regs.x) & 0xffffff; + r = (addr + regs.x); break; case OPTYPE_SR: r = (regs.s + (addr & 0xff)) & 0xffff; break; case OPTYPE_ISRY: addr = (regs.s + (addr & 0xff)) & 0xffff; - r = (regs.db << 16) + r_mem->read_word(addr) + regs.y; + r = (regs.db << 16) + dreadw(addr) + regs.y; + break; + case OPTYPE_RELB: + r = (regs.pc.b << 16) + ((regs.pc.w + 2) & 0xffff); + r += int8(addr); + break; + case OPTYPE_RELW: + r = (regs.pc.b << 16) + ((regs.pc.w + 3) & 0xffff); + r += int16(addr); break; } - return r; + return(r & 0xffffff); } void CPU::disassemble_opcode(char *output) { -char *s; -char t[256]; -uint8 op, op0, op1, op2; static CPUReg24 pc; - s = output; +char t[256]; +char *s = output; if(in_opcode() == true) { strcpy(s, "?????? "); @@ -107,332 +111,334 @@ static CPUReg24 pc; } pc.d = regs.pc.d; - sprintf(s, "%0.6x ", pc.d); + sprintf(s, "%0.6x ", uint32(pc.d)); - op = r_mem->read(pc.d); pc.w++; - op0 = r_mem->read(pc.d); pc.w++; - op1 = r_mem->read(pc.d); pc.w++; - op2 = r_mem->read(pc.d); +uint8 op = dreadb(pc.d); pc.w++; +uint8 op0 = dreadb(pc.d); pc.w++; +uint8 op1 = dreadb(pc.d); pc.w++; +uint8 op2 = dreadb(pc.d); +#define op8 ((op0)) +#define op16 ((op0) | (op1 << 8)) +#define op24 ((op0) | (op1 << 8) | (op2 << 16)) +#define a8 (regs.e || regs.p.m) +#define x8 (regs.e || regs.p.x) switch(op) { - case 0x00:sprintf(t, "brk #$%0.2x ", op0);break; - case 0x01:sprintf(t, "ora ($%0.2x,x) [$%0.6x]", op0, resolve_offset(OPTYPE_IDPX, op0));break; - case 0x02:sprintf(t, "cop #$%0.2x ", op0);break; - case 0x03:sprintf(t, "ora $%0.2x,s [$%0.6x]", op0, resolve_offset(OPTYPE_SR, op0));break; - case 0x04:sprintf(t, "tsb $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0x05:sprintf(t, "ora $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0x06:sprintf(t, "asl $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0x07:sprintf(t, "ora [$%0.2x] [$%0.6x]", op0, resolve_offset(OPTYPE_ILDP, op0));break; - case 0x08:sprintf(t, "php ");break; - case 0x09: - if(regs.p.m)sprintf(t, "ora #$%0.2x ", op0); - else sprintf(t, "ora #$%0.4x ", op0|op1<<8);break; - case 0x0a:sprintf(t, "asl a ");break; - case 0x0b:sprintf(t, "phd ");break; - case 0x0c:sprintf(t, "tsb $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0x0d:sprintf(t, "ora $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0x0e:sprintf(t, "asl $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0x0f:sprintf(t, "ora $%0.6x [$%0.6x]", op0|op1<<8|op2<<16, resolve_offset(OPTYPE_LONG, (op0|op1<<8|op2<<16)));break; - case 0x10:sprintf(t, "bpl $%0.4x [$%0.6x]", __relb(op0)&0xffff, __relb(op0)&0xffffff);break; - case 0x11:sprintf(t, "ora ($%0.2x),y [$%0.6x]", op0, resolve_offset(OPTYPE_IDPY, op0));break; - case 0x12:sprintf(t, "ora ($%0.2x) [$%0.6x]", op0, resolve_offset(OPTYPE_IDP, op0));break; - case 0x13:sprintf(t, "ora ($%0.2x,s),y [$%0.6x]", op0, resolve_offset(OPTYPE_ISRY, op0));break; - case 0x14:sprintf(t, "trb $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0x15:sprintf(t, "ora $%0.2x,x [$%0.6x]", op0, resolve_offset(OPTYPE_DPX, op0));break; - case 0x16:sprintf(t, "asl $%0.2x,x [$%0.6x]", op0, resolve_offset(OPTYPE_DPX, op0));break; - case 0x17:sprintf(t, "ora [$%0.2x],y [$%0.6x]", op0, resolve_offset(OPTYPE_ILDPY, op0));break; - case 0x18:sprintf(t, "clc ");break; - case 0x19:sprintf(t, "ora $%0.4x,y [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRY, (op0|op1<<8)));break; - case 0x1a:sprintf(t, "inc ");break; - case 0x1b:sprintf(t, "tcs ");break; - case 0x1c:sprintf(t, "trb $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0x1d:sprintf(t, "ora $%0.4x,x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRX, (op0|op1<<8)));break; - case 0x1e:sprintf(t, "asl $%0.4x,x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRX, (op0|op1<<8)));break; - case 0x1f:sprintf(t, "ora $%0.6x,x [$%0.6x]", op0|op1<<8|op2<<16, resolve_offset(OPTYPE_LONGX, (op0|op1<<8|op2<<16)));break; - case 0x20:sprintf(t, "jsr $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR_PC, (op0|op1<<8)));break; - case 0x21:sprintf(t, "and ($%0.2x,x) [$%0.6x]", op0, resolve_offset(OPTYPE_IDPX, op0));break; - case 0x22:sprintf(t, "jsl $%0.6x [$%0.6x]", op0|op1<<8|op2<<16, resolve_offset(OPTYPE_LONG, (op0|op1<<8|op2<<16)));break; - case 0x23:sprintf(t, "and $%0.2x,s [$%0.6x]", op0, resolve_offset(OPTYPE_SR, op0));break; - case 0x24:sprintf(t, "bit $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0x25:sprintf(t, "and $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0x26:sprintf(t, "rol $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0x27:sprintf(t, "and [$%0.2x] [$%0.6x]", op0, resolve_offset(OPTYPE_ILDP, op0));break; - case 0x28:sprintf(t, "plp ");break; - case 0x29: - if(regs.p.m)sprintf(t, "and #$%0.2x ", op0); - else sprintf(t, "and #$%0.4x ", op0|op1<<8);break; - case 0x2a:sprintf(t, "rol a ");break; - case 0x2b:sprintf(t, "pld ");break; - case 0x2c:sprintf(t, "bit $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0x2d:sprintf(t, "and $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0x2e:sprintf(t, "rol $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0x2f:sprintf(t, "and $%0.6x [$%0.6x]", op0|op1<<8|op2<<16, resolve_offset(OPTYPE_LONG, (op0|op1<<8|op2<<16)));break; - case 0x30:sprintf(t, "bmi $%0.4x [$%0.6x]", __relb(op0)&0xffff, __relb(op0)&0xffffff);break; - case 0x31:sprintf(t, "and ($%0.2x),y [$%0.6x]", op0, resolve_offset(OPTYPE_IDPY, op0));break; - case 0x32:sprintf(t, "and ($%0.2x) [$%0.6x]", op0, resolve_offset(OPTYPE_IDP, op0));break; - case 0x33:sprintf(t, "and ($%0.2x,s),y [$%0.6x]", op0, resolve_offset(OPTYPE_ISRY, op0));break; - case 0x34:sprintf(t, "bit $%0.2x,x [$%0.6x]", op0, resolve_offset(OPTYPE_DPX, op0));break; - case 0x35:sprintf(t, "and $%0.2x,x [$%0.6x]", op0, resolve_offset(OPTYPE_DPX, op0));break; - case 0x36:sprintf(t, "rol $%0.2x,x [$%0.6x]", op0, resolve_offset(OPTYPE_DPX, op0));break; - case 0x37:sprintf(t, "and [$%0.2x],y [$%0.6x]", op0, resolve_offset(OPTYPE_ILDPY, op0));break; - case 0x38:sprintf(t, "sec ");break; - case 0x39:sprintf(t, "and $%0.4x,y [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRY, (op0|op1<<8)));break; - case 0x3a:sprintf(t, "dec ");break; - case 0x3b:sprintf(t, "tsc ");break; - case 0x3c:sprintf(t, "bit $%0.4x,x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRX, (op0|op1<<8)));break; - case 0x3d:sprintf(t, "and $%0.4x,x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRX, (op0|op1<<8)));break; - case 0x3e:sprintf(t, "rol $%0.4x,x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRX, (op0|op1<<8)));break; - case 0x3f:sprintf(t, "and $%0.6x,x [$%0.6x]", op0|op1<<8|op2<<16, resolve_offset(OPTYPE_LONGX, (op0|op1<<8|op2<<16)));break; - case 0x40:sprintf(t, "rti ");break; - case 0x41:sprintf(t, "eor ($%0.2x,x) [$%0.6x]", op0, resolve_offset(OPTYPE_IDPX, op0));break; - case 0x42:sprintf(t, "wdm ");break; - case 0x43:sprintf(t, "eor $%0.2x,s [$%0.6x]", op0, resolve_offset(OPTYPE_SR, op0));break; - case 0x44:sprintf(t, "mvp $%0.2x,$%0.2x ", op1, op0);break; - case 0x45:sprintf(t, "eor $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0x46:sprintf(t, "lsr $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0x47:sprintf(t, "eor [$%0.2x] [$%0.6x]", op0, resolve_offset(OPTYPE_ILDP, op0));break; - case 0x48:sprintf(t, "pha ");break; - case 0x49: - if(regs.p.m)sprintf(t, "eor #$%0.2x ", op0); - else sprintf(t, "eor #$%0.4x ", op0|op1<<8);break; - case 0x4a:sprintf(t, "lsr a ");break; - case 0x4b:sprintf(t, "phk ");break; - case 0x4c:sprintf(t, "jmp $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR_PC, (op0|op1<<8)));break; - case 0x4d:sprintf(t, "eor $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0x4e:sprintf(t, "lsr $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0x4f:sprintf(t, "eor $%0.6x [$%0.6x]", op0|op1<<8|op2<<16, resolve_offset(OPTYPE_LONG, (op0|op1<<8|op2<<16)));break; - case 0x50:sprintf(t, "bvc $%0.4x [$%0.6x]", __relb(op0)&0xffff, __relb(op0)&0xffffff);break; - case 0x51:sprintf(t, "eor ($%0.2x),y [$%0.6x]", op0, resolve_offset(OPTYPE_IDPY, op0));break; - case 0x52:sprintf(t, "eor ($%0.2x) [$%0.6x]", op0, resolve_offset(OPTYPE_IDP, op0));break; - case 0x53:sprintf(t, "eor ($%0.2x,s),y [$%0.6x]", op0, resolve_offset(OPTYPE_ISRY, op0));break; - case 0x54:sprintf(t, "mvn $%0.2x,$%0.2x ", op1, op0);break; - case 0x55:sprintf(t, "eor $%0.2x,x [$%0.6x]", op0, resolve_offset(OPTYPE_DPX, op0));break; - case 0x56:sprintf(t, "lsr $%0.2x,x [$%0.6x]", op0, resolve_offset(OPTYPE_DPX, op0));break; - case 0x57:sprintf(t, "eor [$%0.2x],y [$%0.6x]", op0, resolve_offset(OPTYPE_ILDPY, op0));break; - case 0x58:sprintf(t, "cli ");break; - case 0x59:sprintf(t, "eor $%0.4x,y [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRY, (op0|op1<<8)));break; - case 0x5a:sprintf(t, "phy ");break; - case 0x5b:sprintf(t, "tcd ");break; - case 0x5c:sprintf(t, "jml $%0.6x [$%0.6x]", op0|op1<<8|op2<<16, resolve_offset(OPTYPE_LONG, (op0|op1<<8|op2<<16)));break; - case 0x5d:sprintf(t, "eor $%0.4x,x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRX, (op0|op1<<8)));break; - case 0x5e:sprintf(t, "lsr $%0.4x,x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRX, (op0|op1<<8)));break; - case 0x5f:sprintf(t, "eor $%0.6x,x [$%0.6x]", op0|op1<<8|op2<<16, resolve_offset(OPTYPE_LONGX, (op0|op1<<8|op2<<16)));break; - case 0x60:sprintf(t, "rts ");break; - case 0x61:sprintf(t, "adc ($%0.2x,x) [$%0.6x]", op0, resolve_offset(OPTYPE_IDPX, op0));break; - case 0x62:sprintf(t, "per $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0x63:sprintf(t, "adc $%0.2x,s [$%0.6x]", op0, resolve_offset(OPTYPE_SR, op0));break; - case 0x64:sprintf(t, "stz $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0x65:sprintf(t, "adc $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0x66:sprintf(t, "ror $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0x67:sprintf(t, "adc [$%0.2x] [$%0.6x]", op0, resolve_offset(OPTYPE_ILDP, op0));break; - case 0x68:sprintf(t, "pla ");break; - case 0x69: - if(regs.p.m)sprintf(t, "adc #$%0.2x ", op0); - else sprintf(t, "adc #$%0.4x ", op0|op1<<8);break; - case 0x6a:sprintf(t, "ror a ");break; - case 0x6b:sprintf(t, "rtl ");break; - case 0x6c:sprintf(t, "jmp ($%0.4x) [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_IADDR_PC, (op0|op1<<8)));break; - case 0x6d:sprintf(t, "adc $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0x6e:sprintf(t, "ror $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0x6f:sprintf(t, "adc $%0.6x [$%0.6x]", op0|op1<<8|op2<<16, resolve_offset(OPTYPE_LONG, (op0|op1<<8|op2<<16)));break; - case 0x70:sprintf(t, "bvs $%0.4x [$%0.6x]", __relb(op0)&0xffff, __relb(op0)&0xffffff);break; - case 0x71:sprintf(t, "adc ($%0.2x),y [$%0.6x]", op0, resolve_offset(OPTYPE_IDPY, op0));break; - case 0x72:sprintf(t, "adc ($%0.2x) [$%0.6x]", op0, resolve_offset(OPTYPE_IDP, op0));break; - case 0x73:sprintf(t, "adc ($%0.2x,s),y [$%0.6x]", op0, resolve_offset(OPTYPE_ISRY, op0));break; - case 0x74:sprintf(t, "stz $%0.2x,x [$%0.6x]", op0, resolve_offset(OPTYPE_DPX, op0));break; - case 0x75:sprintf(t, "adc $%0.2x,x [$%0.6x]", op0, resolve_offset(OPTYPE_DPX, op0));break; - case 0x76:sprintf(t, "ror $%0.2x,x [$%0.6x]", op0, resolve_offset(OPTYPE_DPX, op0));break; - case 0x77:sprintf(t, "adc [$%0.2x],y [$%0.6x]", op0, resolve_offset(OPTYPE_ILDPY, op0));break; - case 0x78:sprintf(t, "sei ");break; - case 0x79:sprintf(t, "adc $%0.4x,y [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRY, (op0|op1<<8)));break; - case 0x7a:sprintf(t, "ply ");break; - case 0x7b:sprintf(t, "tdc ");break; - case 0x7c:sprintf(t, "jmp ($%0.4x,x) [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_IADDRX, (op0|op1<<8)));break; - case 0x7d:sprintf(t, "adc $%0.4x,x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRX, (op0|op1<<8)));break; - case 0x7e:sprintf(t, "ror $%0.4x,x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRX, (op0|op1<<8)));break; - case 0x7f:sprintf(t, "adc $%0.6x,x [$%0.6x]", op0|op1<<8|op2<<16, resolve_offset(OPTYPE_LONGX, (op0|op1<<8|op2<<16)));break; - case 0x80:sprintf(t, "bra $%0.4x [$%0.6x]", __relb(op0)&0xffff, __relb(op0)&0xffffff);break; - case 0x81:sprintf(t, "sta ($%0.2x,x) [$%0.6x]", op0, resolve_offset(OPTYPE_IDPX, op0));break; - case 0x82:sprintf(t, "brl $%0.4x [$%0.6x]", __relw(op0|op1<<8)&0xffff, __relw(op0|op1<<8)&0xffffff);break; - case 0x83:sprintf(t, "sta $%0.2x,s [$%0.6x]", op0, resolve_offset(OPTYPE_SR, op0));break; - case 0x84:sprintf(t, "sty $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0x85:sprintf(t, "sta $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0x86:sprintf(t, "stx $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0x87:sprintf(t, "sta [$%0.2x] [$%0.6x]", op0, resolve_offset(OPTYPE_ILDP, op0));break; - case 0x88:sprintf(t, "dey ");break; - case 0x89: - if(regs.p.m)sprintf(t, "bit #$%0.2x ", op0); - else sprintf(t, "bit #$%0.4x ", op0|op1<<8);break; - case 0x8a:sprintf(t, "txa ");break; - case 0x8b:sprintf(t, "phb ");break; - case 0x8c:sprintf(t, "sty $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0x8d:sprintf(t, "sta $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0x8e:sprintf(t, "stx $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0x8f:sprintf(t, "sta $%0.6x [$%0.6x]", op0|op1<<8|op2<<16, resolve_offset(OPTYPE_LONG, (op0|op1<<8|op2<<16)));break; - case 0x90:sprintf(t, "bcc $%0.4x [$%0.6x]", __relb(op0)&0xffff, __relb(op0)&0xffffff);break; - case 0x91:sprintf(t, "sta ($%0.2x),y [$%0.6x]", op0, resolve_offset(OPTYPE_IDPY, op0));break; - case 0x92:sprintf(t, "sta ($%0.2x) [$%0.6x]", op0, resolve_offset(OPTYPE_IDP, op0));break; - case 0x93:sprintf(t, "sta ($%0.2x,s),y [$%0.6x]", op0, resolve_offset(OPTYPE_ISRY, op0));break; - case 0x94:sprintf(t, "sty $%0.2x,x [$%0.6x]", op0, resolve_offset(OPTYPE_DPX, op0));break; - case 0x95:sprintf(t, "sta $%0.2x,x [$%0.6x]", op0, resolve_offset(OPTYPE_DPX, op0));break; - case 0x96:sprintf(t, "stx $%0.2x,y [$%0.6x]", op0, resolve_offset(OPTYPE_DPY, op0));break; - case 0x97:sprintf(t, "sta [$%0.2x],y [$%0.6x]", op0, resolve_offset(OPTYPE_ILDPY, op0));break; - case 0x98:sprintf(t, "tya ");break; - case 0x99:sprintf(t, "sta $%0.4x,y [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRY, (op0|op1<<8)));break; - case 0x9a:sprintf(t, "txs ");break; - case 0x9b:sprintf(t, "txy ");break; - case 0x9c:sprintf(t, "stz $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0x9d:sprintf(t, "sta $%0.4x,x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRX, (op0|op1<<8)));break; - case 0x9e:sprintf(t, "stz $%0.4x,x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRX, (op0|op1<<8)));break; - case 0x9f:sprintf(t, "sta $%0.6x,x [$%0.6x]", op0|op1<<8|op2<<16, resolve_offset(OPTYPE_LONGX, (op0|op1<<8|op2<<16)));break; - case 0xa0: - if(regs.p.x)sprintf(t, "ldy #$%0.2x ", op0); - else sprintf(t, "ldy #$%0.4x ", op0|op1<<8);break; - case 0xa1:sprintf(t, "lda ($%0.2x,x) [$%0.6x]", op0, resolve_offset(OPTYPE_IDPX, op0));break; - case 0xa2: - if(regs.p.x)sprintf(t, "ldx #$%0.2x ", op0); - else sprintf(t, "ldx #$%0.4x ", op0|op1<<8);break; - case 0xa3:sprintf(t, "lda $%0.2x,s [$%0.6x]", op0, resolve_offset(OPTYPE_SR, op0));break; - case 0xa4:sprintf(t, "ldy $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0xa5:sprintf(t, "lda $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0xa6:sprintf(t, "ldx $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0xa7:sprintf(t, "lda [$%0.2x] [$%0.6x]", op0, resolve_offset(OPTYPE_ILDP, op0));break; - case 0xa8:sprintf(t, "tay ");break; - case 0xa9: - if(regs.p.m)sprintf(t, "lda #$%0.2x ", op0); - else sprintf(t, "lda #$%0.4x ", op0|op1<<8);break; - case 0xaa:sprintf(t, "tax ");break; - case 0xab:sprintf(t, "plb ");break; - case 0xac:sprintf(t, "ldy $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0xad:sprintf(t, "lda $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0xae:sprintf(t, "ldx $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0xaf:sprintf(t, "lda $%0.6x [$%0.6x]", op0|op1<<8|op2<<16, resolve_offset(OPTYPE_LONG, (op0|op1<<8|op2<<16)));break; - case 0xb0:sprintf(t, "bcs $%0.4x [$%0.6x]", __relb(op0)&0xffff, __relb(op0)&0xffffff);break; - case 0xb1:sprintf(t, "lda ($%0.2x),y [$%0.6x]", op0, resolve_offset(OPTYPE_IDPY, op0));break; - case 0xb2:sprintf(t, "lda ($%0.2x) [$%0.6x]", op0, resolve_offset(OPTYPE_IDP, op0));break; - case 0xb3:sprintf(t, "lda ($%0.2x,s),y [$%0.6x]", op0, resolve_offset(OPTYPE_ISRY, op0));break; - case 0xb4:sprintf(t, "ldy $%0.2x,x [$%0.6x]", op0, resolve_offset(OPTYPE_DPX, op0));break; - case 0xb5:sprintf(t, "lda $%0.2x,x [$%0.6x]", op0, resolve_offset(OPTYPE_DPX, op0));break; - case 0xb6:sprintf(t, "ldx $%0.2x,y [$%0.6x]", op0, resolve_offset(OPTYPE_DPY, op0));break; - case 0xb7:sprintf(t, "lda [$%0.2x],y [$%0.6x]", op0, resolve_offset(OPTYPE_ILDPY, op0));break; - case 0xb8:sprintf(t, "clv ");break; - case 0xb9:sprintf(t, "lda $%0.4x,y [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRY, (op0|op1<<8)));break; - case 0xba:sprintf(t, "tsx ");break; - case 0xbb:sprintf(t, "tyx ");break; - case 0xbc:sprintf(t, "ldy $%0.4x,x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRX, (op0|op1<<8)));break; - case 0xbd:sprintf(t, "lda $%0.4x,x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRX, (op0|op1<<8)));break; - case 0xbe:sprintf(t, "ldx $%0.4x,y [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRY, (op0|op1<<8)));break; - case 0xbf:sprintf(t, "lda $%0.6x,x [$%0.6x]", op0|op1<<8|op2<<16, resolve_offset(OPTYPE_LONGX, (op0|op1<<8|op2<<16)));break; - case 0xc0: - if(regs.p.x)sprintf(t, "cpy #$%0.2x ", op0); - else sprintf(t, "cpy #$%0.4x ", op0|op1<<8);break; - case 0xc1:sprintf(t, "cmp ($%0.2x,x) [$%0.6x]", op0, resolve_offset(OPTYPE_IDPX, op0));break; - case 0xc2:sprintf(t, "rep #$%0.2x ", op0);break; - case 0xc3:sprintf(t, "cmp $%0.2x,s [$%0.6x]", op0, resolve_offset(OPTYPE_SR, op0));break; - case 0xc4:sprintf(t, "cpy $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0xc5:sprintf(t, "cmp $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0xc6:sprintf(t, "dec $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0xc7:sprintf(t, "cmp [$%0.2x] [$%0.6x]", op0, resolve_offset(OPTYPE_ILDP, op0));break; - case 0xc8:sprintf(t, "iny ");break; - case 0xc9: - if(regs.p.m)sprintf(t, "cmp #$%0.2x ", op0); - else sprintf(t, "cmp #$%0.4x ", op0|op1<<8);break; - case 0xca:sprintf(t, "dex ");break; - case 0xcb:sprintf(t, "wai ");break; - case 0xcc:sprintf(t, "cpy $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0xcd:sprintf(t, "cmp $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0xce:sprintf(t, "dec $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0xcf:sprintf(t, "cmp $%0.6x [$%0.6x]", op0|op1<<8|op2<<16, resolve_offset(OPTYPE_LONG, (op0|op1<<8|op2<<16)));break; - case 0xd0:sprintf(t, "bne $%0.4x [$%0.6x]", __relb(op0)&0xffff, __relb(op0)&0xffffff);break; - case 0xd1:sprintf(t, "cmp ($%0.2x),y [$%0.6x]", op0, resolve_offset(OPTYPE_IDPY, op0));break; - case 0xd2:sprintf(t, "cmp ($%0.2x) [$%0.6x]", op0, resolve_offset(OPTYPE_IDP, op0));break; - case 0xd3:sprintf(t, "cmp ($%0.2x,s),y [$%0.6x]", op0, resolve_offset(OPTYPE_ISRY, op0));break; - case 0xd4:sprintf(t, "pei ($%0.2x) [$%0.6x]", op0, resolve_offset(OPTYPE_IDP, op0));break; - case 0xd5:sprintf(t, "cmp $%0.2x,x [$%0.6x]", op0, resolve_offset(OPTYPE_DPX, op0));break; - case 0xd6:sprintf(t, "dec $%0.2x,x [$%0.6x]", op0, resolve_offset(OPTYPE_DPX, op0));break; - case 0xd7:sprintf(t, "cmp [$%0.2x],y [$%0.6x]", op0, resolve_offset(OPTYPE_ILDPY, op0));break; - case 0xd8:sprintf(t, "cld ");break; - case 0xd9:sprintf(t, "cmp $%0.4x,y [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRY, (op0|op1<<8)));break; - case 0xda:sprintf(t, "phx ");break; - case 0xdb:sprintf(t, "stp ");break; - case 0xdc:sprintf(t, "jmp [$%0.4x] [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ILADDR, (op0|op1<<8)));break; - case 0xdd:sprintf(t, "cmp $%0.4x,x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRX, (op0|op1<<8)));break; - case 0xde:sprintf(t, "dec $%0.4x,x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRX, (op0|op1<<8)));break; - case 0xdf:sprintf(t, "cmp $%0.6x,x [$%0.6x]", op0|op1<<8|op2<<16, resolve_offset(OPTYPE_LONGX, (op0|op1<<8|op2<<16)));break; - case 0xe0: - if(regs.p.x)sprintf(t, "cpx #$%0.2x ", op0); - else sprintf(t, "cpx #$%0.4x ", op0|op1<<8);break; - case 0xe1:sprintf(t, "sbc ($%0.2x,x) [$%0.6x]", op0, resolve_offset(OPTYPE_IDPX, op0));break; - case 0xe2:sprintf(t, "sep #$%0.2x ", op0);break; - case 0xe3:sprintf(t, "sbc $%0.2x,s [$%0.6x]", op0, resolve_offset(OPTYPE_SR, op0));break; - case 0xe4:sprintf(t, "cpx $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0xe5:sprintf(t, "sbc $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0xe6:sprintf(t, "inc $%0.2x [$%0.6x]", op0, resolve_offset(OPTYPE_DP, op0));break; - case 0xe7:sprintf(t, "sbc [$%0.2x] [$%0.6x]", op0, resolve_offset(OPTYPE_ILDP, op0));break; - case 0xe8:sprintf(t, "inx ");break; - case 0xe9: - if(regs.p.m)sprintf(t, "sbc #$%0.2x ", op0); - else sprintf(t, "sbc #$%0.4x ", op0|op1<<8);break; - case 0xea:sprintf(t, "nop ");break; - case 0xeb:sprintf(t, "xba ");break; - case 0xec:sprintf(t, "cpx $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0xed:sprintf(t, "sbc $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0xee:sprintf(t, "inc $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0xef:sprintf(t, "sbc $%0.6x [$%0.6x]", op0|op1<<8|op2<<16, resolve_offset(OPTYPE_LONG, (op0|op1<<8|op2<<16)));break; - case 0xf0:sprintf(t, "beq $%0.4x [$%0.6x]", __relb(op0)&0xffff, __relb(op0)&0xffffff);break; - case 0xf1:sprintf(t, "sbc ($%0.2x),y [$%0.6x]", op0, resolve_offset(OPTYPE_IDPY, op0));break; - case 0xf2:sprintf(t, "sbc ($%0.2x) [$%0.6x]", op0, resolve_offset(OPTYPE_IDP, op0));break; - case 0xf3:sprintf(t, "sbc ($%0.2x,s),y [$%0.6x]", op0, resolve_offset(OPTYPE_ISRY, op0));break; - case 0xf4:sprintf(t, "pea $%0.4x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDR, (op0|op1<<8)));break; - case 0xf5:sprintf(t, "sbc $%0.2x,x [$%0.6x]", op0, resolve_offset(OPTYPE_DPX, op0));break; - case 0xf6:sprintf(t, "inc $%0.2x,x [$%0.6x]", op0, resolve_offset(OPTYPE_DPX, op0));break; - case 0xf7:sprintf(t, "sbc [$%0.2x],y [$%0.6x]", op0, resolve_offset(OPTYPE_ILDPY, op0));break; - case 0xf8:sprintf(t, "sed ");break; - case 0xf9:sprintf(t, "sbc $%0.4x,y [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRY, (op0|op1<<8)));break; - case 0xfa:sprintf(t, "plx ");break; - case 0xfb:sprintf(t, "xce ");break; - case 0xfc:sprintf(t, "jsr ($%0.4x,x) [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_IADDRX, (op0|op1<<8)));break; - case 0xfd:sprintf(t, "sbc $%0.4x,x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRX, (op0|op1<<8)));break; - case 0xfe:sprintf(t, "inc $%0.4x,x [$%0.6x]", op0|op1<<8, resolve_offset(OPTYPE_ADDRX, (op0|op1<<8)));break; - case 0xff:sprintf(t, "sbc $%0.6x,x [$%0.6x]", op0|op1<<8|op2<<16, resolve_offset(OPTYPE_LONGX, (op0|op1<<8|op2<<16)));break; + case 0x00: sprintf(t, "brk #$%0.2x ", op8); break; + case 0x01: sprintf(t, "ora ($%0.2x,x) [$%0.6x]", op8, decode(OPTYPE_IDPX, op8)); break; + case 0x02: sprintf(t, "cop #$%0.2x ", op8); break; + case 0x03: sprintf(t, "ora $%0.2x,s [$%0.6x]", op8, decode(OPTYPE_SR, op8)); break; + case 0x04: sprintf(t, "tsb $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x05: sprintf(t, "ora $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x06: sprintf(t, "asl $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x07: sprintf(t, "ora [$%0.2x] [$%0.6x]", op8, decode(OPTYPE_ILDP, op8)); break; + case 0x08: sprintf(t, "php "); break; + case 0x09: if(a8)sprintf(t, "ora #$%0.2x ", op8); + else sprintf(t, "ora #$%0.4x ", op16); break; + case 0x0a: sprintf(t, "asl a "); break; + case 0x0b: sprintf(t, "phd "); break; + case 0x0c: sprintf(t, "tsb $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x0d: sprintf(t, "ora $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x0e: sprintf(t, "asl $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x0f: sprintf(t, "ora $%0.6x [$%0.6x]", op24, decode(OPTYPE_LONG, op24)); break; + case 0x10: sprintf(t, "bpl $%0.4x [$%0.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break; + case 0x11: sprintf(t, "ora ($%0.2x),y [$%0.6x]", op8, decode(OPTYPE_IDPY, op8)); break; + case 0x12: sprintf(t, "ora ($%0.2x) [$%0.6x]", op8, decode(OPTYPE_IDP, op8)); break; + case 0x13: sprintf(t, "ora ($%0.2x,s),y [$%0.6x]", op8, decode(OPTYPE_ISRY, op8)); break; + case 0x14: sprintf(t, "trb $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x15: sprintf(t, "ora $%0.2x,x [$%0.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x16: sprintf(t, "asl $%0.2x,x [$%0.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x17: sprintf(t, "ora [$%0.2x],y [$%0.6x]", op8, decode(OPTYPE_ILDPY, op8)); break; + case 0x18: sprintf(t, "clc "); break; + case 0x19: sprintf(t, "ora $%0.4x,y [$%0.6x]", op16, decode(OPTYPE_ADDRY, op16)); break; + case 0x1a: sprintf(t, "inc "); break; + case 0x1b: sprintf(t, "tcs "); break; + case 0x1c: sprintf(t, "trb $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x1d: sprintf(t, "ora $%0.4x,x [$%0.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x1e: sprintf(t, "asl $%0.4x,x [$%0.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x1f: sprintf(t, "ora $%0.6x,x [$%0.6x]", op24, decode(OPTYPE_LONGX, op24)); break; + case 0x20: sprintf(t, "jsr $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR_PC, op16)); break; + case 0x21: sprintf(t, "and ($%0.2x,x) [$%0.6x]", op8, decode(OPTYPE_IDPX, op8)); break; + case 0x22: sprintf(t, "jsl $%0.6x [$%0.6x]", op24, decode(OPTYPE_LONG, op24)); break; + case 0x23: sprintf(t, "and $%0.2x,s [$%0.6x]", op8, decode(OPTYPE_SR, op8)); break; + case 0x24: sprintf(t, "bit $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x25: sprintf(t, "and $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x26: sprintf(t, "rol $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x27: sprintf(t, "and [$%0.2x] [$%0.6x]", op8, decode(OPTYPE_ILDP, op8)); break; + case 0x28: sprintf(t, "plp "); break; + case 0x29: if(a8)sprintf(t, "and #$%0.2x ", op8); + else sprintf(t, "and #$%0.4x ", op16); break; + case 0x2a: sprintf(t, "rol a "); break; + case 0x2b: sprintf(t, "pld "); break; + case 0x2c: sprintf(t, "bit $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x2d: sprintf(t, "and $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x2e: sprintf(t, "rol $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x2f: sprintf(t, "and $%0.6x [$%0.6x]", op24, decode(OPTYPE_LONG, op24)); break; + case 0x30: sprintf(t, "bmi $%0.4x [$%0.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break; + case 0x31: sprintf(t, "and ($%0.2x),y [$%0.6x]", op8, decode(OPTYPE_IDPY, op8)); break; + case 0x32: sprintf(t, "and ($%0.2x) [$%0.6x]", op8, decode(OPTYPE_IDP, op8)); break; + case 0x33: sprintf(t, "and ($%0.2x,s),y [$%0.6x]", op8, decode(OPTYPE_ISRY, op8)); break; + case 0x34: sprintf(t, "bit $%0.2x,x [$%0.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x35: sprintf(t, "and $%0.2x,x [$%0.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x36: sprintf(t, "rol $%0.2x,x [$%0.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x37: sprintf(t, "and [$%0.2x],y [$%0.6x]", op8, decode(OPTYPE_ILDPY, op8)); break; + case 0x38: sprintf(t, "sec "); break; + case 0x39: sprintf(t, "and $%0.4x,y [$%0.6x]", op16, decode(OPTYPE_ADDRY, op16)); break; + case 0x3a: sprintf(t, "dec "); break; + case 0x3b: sprintf(t, "tsc "); break; + case 0x3c: sprintf(t, "bit $%0.4x,x [$%0.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x3d: sprintf(t, "and $%0.4x,x [$%0.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x3e: sprintf(t, "rol $%0.4x,x [$%0.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x3f: sprintf(t, "and $%0.6x,x [$%0.6x]", op24, decode(OPTYPE_LONGX, op24)); break; + case 0x40: sprintf(t, "rti "); break; + case 0x41: sprintf(t, "eor ($%0.2x,x) [$%0.6x]", op8, decode(OPTYPE_IDPX, op8)); break; + case 0x42: sprintf(t, "wdm "); break; + case 0x43: sprintf(t, "eor $%0.2x,s [$%0.6x]", op8, decode(OPTYPE_SR, op8)); break; + case 0x44: sprintf(t, "mvp $%0.2x,$%0.2x ", op1, op8); break; + case 0x45: sprintf(t, "eor $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x46: sprintf(t, "lsr $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x47: sprintf(t, "eor [$%0.2x] [$%0.6x]", op8, decode(OPTYPE_ILDP, op8)); break; + case 0x48: sprintf(t, "pha "); break; + case 0x49: if(a8)sprintf(t, "eor #$%0.2x ", op8); + else sprintf(t, "eor #$%0.4x ", op16); break; + case 0x4a: sprintf(t, "lsr a "); break; + case 0x4b: sprintf(t, "phk "); break; + case 0x4c: sprintf(t, "jmp $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR_PC, op16)); break; + case 0x4d: sprintf(t, "eor $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x4e: sprintf(t, "lsr $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x4f: sprintf(t, "eor $%0.6x [$%0.6x]", op24, decode(OPTYPE_LONG, op24)); break; + case 0x50: sprintf(t, "bvc $%0.4x [$%0.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break; + case 0x51: sprintf(t, "eor ($%0.2x),y [$%0.6x]", op8, decode(OPTYPE_IDPY, op8)); break; + case 0x52: sprintf(t, "eor ($%0.2x) [$%0.6x]", op8, decode(OPTYPE_IDP, op8)); break; + case 0x53: sprintf(t, "eor ($%0.2x,s),y [$%0.6x]", op8, decode(OPTYPE_ISRY, op8)); break; + case 0x54: sprintf(t, "mvn $%0.2x,$%0.2x ", op1, op8); break; + case 0x55: sprintf(t, "eor $%0.2x,x [$%0.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x56: sprintf(t, "lsr $%0.2x,x [$%0.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x57: sprintf(t, "eor [$%0.2x],y [$%0.6x]", op8, decode(OPTYPE_ILDPY, op8)); break; + case 0x58: sprintf(t, "cli "); break; + case 0x59: sprintf(t, "eor $%0.4x,y [$%0.6x]", op16, decode(OPTYPE_ADDRY, op16)); break; + case 0x5a: sprintf(t, "phy "); break; + case 0x5b: sprintf(t, "tcd "); break; + case 0x5c: sprintf(t, "jml $%0.6x [$%0.6x]", op24, decode(OPTYPE_LONG, op24)); break; + case 0x5d: sprintf(t, "eor $%0.4x,x [$%0.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x5e: sprintf(t, "lsr $%0.4x,x [$%0.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x5f: sprintf(t, "eor $%0.6x,x [$%0.6x]", op24, decode(OPTYPE_LONGX, op24)); break; + case 0x60: sprintf(t, "rts "); break; + case 0x61: sprintf(t, "adc ($%0.2x,x) [$%0.6x]", op8, decode(OPTYPE_IDPX, op8)); break; + case 0x62: sprintf(t, "per $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x63: sprintf(t, "adc $%0.2x,s [$%0.6x]", op8, decode(OPTYPE_SR, op8)); break; + case 0x64: sprintf(t, "stz $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x65: sprintf(t, "adc $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x66: sprintf(t, "ror $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x67: sprintf(t, "adc [$%0.2x] [$%0.6x]", op8, decode(OPTYPE_ILDP, op8)); break; + case 0x68: sprintf(t, "pla "); break; + case 0x69: if(a8)sprintf(t, "adc #$%0.2x ", op8); + else sprintf(t, "adc #$%0.4x ", op16); break; + case 0x6a: sprintf(t, "ror a "); break; + case 0x6b: sprintf(t, "rtl "); break; + case 0x6c: sprintf(t, "jmp ($%0.4x) [$%0.6x]", op16, decode(OPTYPE_IADDR_PC, op16)); break; + case 0x6d: sprintf(t, "adc $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x6e: sprintf(t, "ror $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x6f: sprintf(t, "adc $%0.6x [$%0.6x]", op24, decode(OPTYPE_LONG, op24)); break; + case 0x70: sprintf(t, "bvs $%0.4x [$%0.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break; + case 0x71: sprintf(t, "adc ($%0.2x),y [$%0.6x]", op8, decode(OPTYPE_IDPY, op8)); break; + case 0x72: sprintf(t, "adc ($%0.2x) [$%0.6x]", op8, decode(OPTYPE_IDP, op8)); break; + case 0x73: sprintf(t, "adc ($%0.2x,s),y [$%0.6x]", op8, decode(OPTYPE_ISRY, op8)); break; + case 0x74: sprintf(t, "stz $%0.2x,x [$%0.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x75: sprintf(t, "adc $%0.2x,x [$%0.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x76: sprintf(t, "ror $%0.2x,x [$%0.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x77: sprintf(t, "adc [$%0.2x],y [$%0.6x]", op8, decode(OPTYPE_ILDPY, op8)); break; + case 0x78: sprintf(t, "sei "); break; + case 0x79: sprintf(t, "adc $%0.4x,y [$%0.6x]", op16, decode(OPTYPE_ADDRY, op16)); break; + case 0x7a: sprintf(t, "ply "); break; + case 0x7b: sprintf(t, "tdc "); break; + case 0x7c: sprintf(t, "jmp ($%0.4x,x) [$%0.6x]", op16, decode(OPTYPE_IADDRX, op16)); break; + case 0x7d: sprintf(t, "adc $%0.4x,x [$%0.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x7e: sprintf(t, "ror $%0.4x,x [$%0.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x7f: sprintf(t, "adc $%0.6x,x [$%0.6x]", op24, decode(OPTYPE_LONGX, op24)); break; + case 0x80: sprintf(t, "bra $%0.4x [$%0.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break; + case 0x81: sprintf(t, "sta ($%0.2x,x) [$%0.6x]", op8, decode(OPTYPE_IDPX, op8)); break; + case 0x82: sprintf(t, "brl $%0.4x [$%0.6x]", uint16(decode(OPTYPE_RELW, op16)), decode(OPTYPE_RELW, op16)); break; + case 0x83: sprintf(t, "sta $%0.2x,s [$%0.6x]", op8, decode(OPTYPE_SR, op8)); break; + case 0x84: sprintf(t, "sty $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x85: sprintf(t, "sta $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x86: sprintf(t, "stx $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x87: sprintf(t, "sta [$%0.2x] [$%0.6x]", op8, decode(OPTYPE_ILDP, op8)); break; + case 0x88: sprintf(t, "dey "); break; + case 0x89: if(a8)sprintf(t, "bit #$%0.2x ", op8); + else sprintf(t, "bit #$%0.4x ", op16); break; + case 0x8a: sprintf(t, "txa "); break; + case 0x8b: sprintf(t, "phb "); break; + case 0x8c: sprintf(t, "sty $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x8d: sprintf(t, "sta $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x8e: sprintf(t, "stx $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x8f: sprintf(t, "sta $%0.6x [$%0.6x]", op24, decode(OPTYPE_LONG, op24)); break; + case 0x90: sprintf(t, "bcc $%0.4x [$%0.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break; + case 0x91: sprintf(t, "sta ($%0.2x),y [$%0.6x]", op8, decode(OPTYPE_IDPY, op8)); break; + case 0x92: sprintf(t, "sta ($%0.2x) [$%0.6x]", op8, decode(OPTYPE_IDP, op8)); break; + case 0x93: sprintf(t, "sta ($%0.2x,s),y [$%0.6x]", op8, decode(OPTYPE_ISRY, op8)); break; + case 0x94: sprintf(t, "sty $%0.2x,x [$%0.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x95: sprintf(t, "sta $%0.2x,x [$%0.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x96: sprintf(t, "stx $%0.2x,y [$%0.6x]", op8, decode(OPTYPE_DPY, op8)); break; + case 0x97: sprintf(t, "sta [$%0.2x],y [$%0.6x]", op8, decode(OPTYPE_ILDPY, op8)); break; + case 0x98: sprintf(t, "tya "); break; + case 0x99: sprintf(t, "sta $%0.4x,y [$%0.6x]", op16, decode(OPTYPE_ADDRY, op16)); break; + case 0x9a: sprintf(t, "txs "); break; + case 0x9b: sprintf(t, "txy "); break; + case 0x9c: sprintf(t, "stz $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x9d: sprintf(t, "sta $%0.4x,x [$%0.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x9e: sprintf(t, "stz $%0.4x,x [$%0.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x9f: sprintf(t, "sta $%0.6x,x [$%0.6x]", op24, decode(OPTYPE_LONGX, op24)); break; + case 0xa0: if(x8)sprintf(t, "ldy #$%0.2x ", op8); + else sprintf(t, "ldy #$%0.4x ", op16); break; + case 0xa1: sprintf(t, "lda ($%0.2x,x) [$%0.6x]", op8, decode(OPTYPE_IDPX, op8)); break; + case 0xa2: if(x8)sprintf(t, "ldx #$%0.2x ", op8); + else sprintf(t, "ldx #$%0.4x ", op16); break; + case 0xa3: sprintf(t, "lda $%0.2x,s [$%0.6x]", op8, decode(OPTYPE_SR, op8)); break; + case 0xa4: sprintf(t, "ldy $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0xa5: sprintf(t, "lda $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0xa6: sprintf(t, "ldx $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0xa7: sprintf(t, "lda [$%0.2x] [$%0.6x]", op8, decode(OPTYPE_ILDP, op8)); break; + case 0xa8: sprintf(t, "tay "); break; + case 0xa9: if(a8)sprintf(t, "lda #$%0.2x ", op8); + else sprintf(t, "lda #$%0.4x ", op16); break; + case 0xaa: sprintf(t, "tax "); break; + case 0xab: sprintf(t, "plb "); break; + case 0xac: sprintf(t, "ldy $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0xad: sprintf(t, "lda $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0xae: sprintf(t, "ldx $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0xaf: sprintf(t, "lda $%0.6x [$%0.6x]", op24, decode(OPTYPE_LONG, op24)); break; + case 0xb0: sprintf(t, "bcs $%0.4x [$%0.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break; + case 0xb1: sprintf(t, "lda ($%0.2x),y [$%0.6x]", op8, decode(OPTYPE_IDPY, op8)); break; + case 0xb2: sprintf(t, "lda ($%0.2x) [$%0.6x]", op8, decode(OPTYPE_IDP, op8)); break; + case 0xb3: sprintf(t, "lda ($%0.2x,s),y [$%0.6x]", op8, decode(OPTYPE_ISRY, op8)); break; + case 0xb4: sprintf(t, "ldy $%0.2x,x [$%0.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0xb5: sprintf(t, "lda $%0.2x,x [$%0.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0xb6: sprintf(t, "ldx $%0.2x,y [$%0.6x]", op8, decode(OPTYPE_DPY, op8)); break; + case 0xb7: sprintf(t, "lda [$%0.2x],y [$%0.6x]", op8, decode(OPTYPE_ILDPY, op8)); break; + case 0xb8: sprintf(t, "clv "); break; + case 0xb9: sprintf(t, "lda $%0.4x,y [$%0.6x]", op16, decode(OPTYPE_ADDRY, op16)); break; + case 0xba: sprintf(t, "tsx "); break; + case 0xbb: sprintf(t, "tyx "); break; + case 0xbc: sprintf(t, "ldy $%0.4x,x [$%0.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0xbd: sprintf(t, "lda $%0.4x,x [$%0.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0xbe: sprintf(t, "ldx $%0.4x,y [$%0.6x]", op16, decode(OPTYPE_ADDRY, op16)); break; + case 0xbf: sprintf(t, "lda $%0.6x,x [$%0.6x]", op24, decode(OPTYPE_LONGX, op24)); break; + case 0xc0: if(x8)sprintf(t, "cpy #$%0.2x ", op8); + else sprintf(t, "cpy #$%0.4x ", op16); break; + case 0xc1: sprintf(t, "cmp ($%0.2x,x) [$%0.6x]", op8, decode(OPTYPE_IDPX, op8)); break; + case 0xc2: sprintf(t, "rep #$%0.2x ", op8); break; + case 0xc3: sprintf(t, "cmp $%0.2x,s [$%0.6x]", op8, decode(OPTYPE_SR, op8)); break; + case 0xc4: sprintf(t, "cpy $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0xc5: sprintf(t, "cmp $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0xc6: sprintf(t, "dec $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0xc7: sprintf(t, "cmp [$%0.2x] [$%0.6x]", op8, decode(OPTYPE_ILDP, op8)); break; + case 0xc8: sprintf(t, "iny "); break; + case 0xc9: if(a8)sprintf(t, "cmp #$%0.2x ", op8); + else sprintf(t, "cmp #$%0.4x ", op16); break; + case 0xca: sprintf(t, "dex "); break; + case 0xcb: sprintf(t, "wai "); break; + case 0xcc: sprintf(t, "cpy $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0xcd: sprintf(t, "cmp $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0xce: sprintf(t, "dec $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0xcf: sprintf(t, "cmp $%0.6x [$%0.6x]", op24, decode(OPTYPE_LONG, op24)); break; + case 0xd0: sprintf(t, "bne $%0.4x [$%0.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break; + case 0xd1: sprintf(t, "cmp ($%0.2x),y [$%0.6x]", op8, decode(OPTYPE_IDPY, op8)); break; + case 0xd2: sprintf(t, "cmp ($%0.2x) [$%0.6x]", op8, decode(OPTYPE_IDP, op8)); break; + case 0xd3: sprintf(t, "cmp ($%0.2x,s),y [$%0.6x]", op8, decode(OPTYPE_ISRY, op8)); break; + case 0xd4: sprintf(t, "pei ($%0.2x) [$%0.6x]", op8, decode(OPTYPE_IDP, op8)); break; + case 0xd5: sprintf(t, "cmp $%0.2x,x [$%0.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0xd6: sprintf(t, "dec $%0.2x,x [$%0.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0xd7: sprintf(t, "cmp [$%0.2x],y [$%0.6x]", op8, decode(OPTYPE_ILDPY, op8)); break; + case 0xd8: sprintf(t, "cld "); break; + case 0xd9: sprintf(t, "cmp $%0.4x,y [$%0.6x]", op16, decode(OPTYPE_ADDRY, op16)); break; + case 0xda: sprintf(t, "phx "); break; + case 0xdb: sprintf(t, "stp "); break; + case 0xdc: sprintf(t, "jmp [$%0.4x] [$%0.6x]", op16, decode(OPTYPE_ILADDR, op16)); break; + case 0xdd: sprintf(t, "cmp $%0.4x,x [$%0.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0xde: sprintf(t, "dec $%0.4x,x [$%0.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0xdf: sprintf(t, "cmp $%0.6x,x [$%0.6x]", op24, decode(OPTYPE_LONGX, op24)); break; + case 0xe0: if(x8)sprintf(t, "cpx #$%0.2x ", op8); + else sprintf(t, "cpx #$%0.4x ", op16); break; + case 0xe1: sprintf(t, "sbc ($%0.2x,x) [$%0.6x]", op8, decode(OPTYPE_IDPX, op8)); break; + case 0xe2: sprintf(t, "sep #$%0.2x ", op8); break; + case 0xe3: sprintf(t, "sbc $%0.2x,s [$%0.6x]", op8, decode(OPTYPE_SR, op8)); break; + case 0xe4: sprintf(t, "cpx $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0xe5: sprintf(t, "sbc $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0xe6: sprintf(t, "inc $%0.2x [$%0.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0xe7: sprintf(t, "sbc [$%0.2x] [$%0.6x]", op8, decode(OPTYPE_ILDP, op8)); break; + case 0xe8: sprintf(t, "inx "); break; + case 0xe9: if(a8)sprintf(t, "sbc #$%0.2x ", op8); + else sprintf(t, "sbc #$%0.4x ", op16); break; + case 0xea: sprintf(t, "nop "); break; + case 0xeb: sprintf(t, "xba "); break; + case 0xec: sprintf(t, "cpx $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0xed: sprintf(t, "sbc $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0xee: sprintf(t, "inc $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0xef: sprintf(t, "sbc $%0.6x [$%0.6x]", op24, decode(OPTYPE_LONG, op24)); break; + case 0xf0: sprintf(t, "beq $%0.4x [$%0.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break; + case 0xf1: sprintf(t, "sbc ($%0.2x),y [$%0.6x]", op8, decode(OPTYPE_IDPY, op8)); break; + case 0xf2: sprintf(t, "sbc ($%0.2x) [$%0.6x]", op8, decode(OPTYPE_IDP, op8)); break; + case 0xf3: sprintf(t, "sbc ($%0.2x,s),y [$%0.6x]", op8, decode(OPTYPE_ISRY, op8)); break; + case 0xf4: sprintf(t, "pea $%0.4x [$%0.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0xf5: sprintf(t, "sbc $%0.2x,x [$%0.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0xf6: sprintf(t, "inc $%0.2x,x [$%0.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0xf7: sprintf(t, "sbc [$%0.2x],y [$%0.6x]", op8, decode(OPTYPE_ILDPY, op8)); break; + case 0xf8: sprintf(t, "sed "); break; + case 0xf9: sprintf(t, "sbc $%0.4x,y [$%0.6x]", op16, decode(OPTYPE_ADDRY, op16)); break; + case 0xfa: sprintf(t, "plx "); break; + case 0xfb: sprintf(t, "xce "); break; + case 0xfc: sprintf(t, "jsr ($%0.4x,x) [$%0.6x]", op16, decode(OPTYPE_IADDRX, op16)); break; + case 0xfd: sprintf(t, "sbc $%0.4x,x [$%0.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0xfe: sprintf(t, "inc $%0.4x,x [$%0.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0xff: sprintf(t, "sbc $%0.6x,x [$%0.6x]", op24, decode(OPTYPE_LONGX, op24)); break; } +#undef op8 +#undef op16 +#undef op24 +#undef a8 +#undef x8 + strcat(s, t); strcat(s, " "); sprintf(t, "A:%0.4x X:%0.4x Y:%0.4x S:%0.4x D:%0.4x DB:%0.2x ", regs.a.w, regs.x.w, regs.y.w, regs.s.w, regs.d.w, regs.db); strcat(s, t); + if(regs.e) { sprintf(t, "%c%c%c%c%c%c%c%c", - (regs.p.n)?'N':'n', (regs.p.v)?'V':'v', - (regs.p.m)?'1':'0', (regs.p.x)?'B':'b', - (regs.p.d)?'D':'d', (regs.p.i)?'I':'i', - (regs.p.z)?'Z':'z', (regs.p.c)?'C':'c'); + (regs.p.n) ? 'N' : 'n', (regs.p.v) ? 'V' : 'v', + (regs.p.m) ? '1' : '0', (regs.p.x) ? 'B' : 'b', + (regs.p.d) ? 'D' : 'd', (regs.p.i) ? 'I' : 'i', + (regs.p.z) ? 'Z' : 'z', (regs.p.c) ? 'C' : 'c'); } else { sprintf(t, "%c%c%c%c%c%c%c%c", - (regs.p.n)?'N':'n', (regs.p.v)?'V':'v', - (regs.p.m)?'M':'m', (regs.p.x)?'X':'x', - (regs.p.d)?'D':'d', (regs.p.i)?'I':'i', - (regs.p.z)?'Z':'z', (regs.p.c)?'C':'c'); + (regs.p.n) ? 'N' : 'n', (regs.p.v) ? 'V' : 'v', + (regs.p.m) ? 'M' : 'm', (regs.p.x) ? 'X' : 'x', + (regs.p.d) ? 'D' : 'd', (regs.p.i) ? 'I' : 'i', + (regs.p.z) ? 'Z' : 'z', (regs.p.c) ? 'C' : 'c'); } + strcat(s, t); } -/* - opcode_length() retrieves the length of the next opcode - to be executed. It is used by the debugger to step over, - disable, and proceed cpu opcodes. - - 5 and 6 are special cases, 5 is used for #consts based on - the A register size, 6 for the X/Y register size. the - rest are literal sizes. There's no need to test for - emulation mode, as regs.p.m/regs.p.x should *always* be - set in emulation mode. -*/ +/***** + * opcode_length() retrieves the length of the next opcode + * to be executed. It is used by the debugger to step over, + * disable and proceed cpu opcodes. + * + * 5 and 6 are special cases, 5 is used for #consts based on + * the A register size, 6 for the X/Y register size. the + * rest are literal sizes. There's no need to test for + * emulation mode, as regs.p.m/regs.p.x should *always* be + * set in emulation mode. + *****/ uint8 CPU::opcode_length() { uint8 op, len; static uint8 op_len_tbl[256] = { //0,1,2,3, 4,5,6,7, 8,9,a,b, c,d,e,f + 2,2,2,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0x0n 2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0x1n 3,2,4,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0x2n @@ -457,9 +463,9 @@ static uint8 op_len_tbl[256] = { return 0; } - op = r_mem->read(regs.pc.d); + op = dreadb(regs.pc.d); len = op_len_tbl[op]; - if(len == 5)return (regs.p.m)?2:3; - if(len == 6)return (regs.p.x)?2:3; + if(len == 5)return (regs.e || regs.p.m) ? 2 : 3; + if(len == 6)return (regs.e || regs.p.x) ? 2 : 3; return len; } diff --git a/src/cpu/scpu/core/cc.bat b/src/cpu/scpu/core/cc.bat new file mode 100644 index 00000000..de7d9674 --- /dev/null +++ b/src/cpu/scpu/core/cc.bat @@ -0,0 +1,3 @@ +cl /O2 scpugen.cpp +@pause +@del *.obj \ No newline at end of file diff --git a/src/cpu/scpu/core/clean.bat b/src/cpu/scpu/core/clean.bat new file mode 100644 index 00000000..d807f14d --- /dev/null +++ b/src/cpu/scpu/core/clean.bat @@ -0,0 +1 @@ +@del *.exe diff --git a/src/cpu/scpu/core/core.cpp b/src/cpu/scpu/core/core.cpp new file mode 100644 index 00000000..7e5c059f --- /dev/null +++ b/src/cpu/scpu/core/core.cpp @@ -0,0 +1,71 @@ +#include "opfn.cpp" +//#include "op_read.cpp" +//#include "op_write.cpp" +//#include "op_rmw.cpp" +//#include "op_pc.cpp" +//#include "op_misc.cpp" + +void sCPU::main() { + for(;;) { + status.in_opcode = true; + + if(event.irq) { + event.irq = false; + if(status.nmi_pending == true) { + status.nmi_pending = false; + event.irq_vector = (regs.e == false) ? 0xffea : 0xfffa; + } else if(status.irq_pending == true) { + status.irq_pending = false; + event.irq_vector = (regs.e == false) ? 0xffee : 0xfffe; + } + op_irq(); + } + +// (this->*optbl[op_readpc()])(); + switch(op_readpc()) { + #include "op_read.cpp" + #include "op_write.cpp" + #include "op_rmw.cpp" + #include "op_pc.cpp" + #include "op_misc.cpp" + } + + status.in_opcode = false; + opcode_edge(); + } +} + +void sCPU::op_irq() { + op_read(regs.pc.d); + op_io(); + if(!regs.e)op_writestack(regs.pc.b); + op_writestack(regs.pc.h); + op_writestack(regs.pc.l); + op_writestack(regs.e ? (regs.p & ~0x10) : regs.p); + rd.l = op_read(event.irq_vector + 0); + regs.pc.b = 0x00; + regs.p.i = 1; + regs.p.d = 0; + rd.h = op_read(event.irq_vector + 1); + regs.pc.w = rd.w; + +#ifdef DEBUGGER + status.in_opcode = false; + snes->notify(SNES::CPU_EXEC_OPCODE_END); + status.in_opcode = true; +#endif +} + +// + +void sCPU::op_io_cond2() { + if(regs.d.l != 0x00)op_io(); +} + +void sCPU::op_io_cond4(uint16 x, uint16 y) { + if(!regs.p.x && (x & 0xff00) != (y & 0xff00))op_io(); +} + +void sCPU::op_io_cond6(uint16 addr) { + if(regs.e && (regs.pc.w & 0xff00) != (addr & 0xff00))op_io(); +} diff --git a/src/cpu/scpu/core/core.h b/src/cpu/scpu/core/core.h new file mode 100644 index 00000000..cf2ff9e0 --- /dev/null +++ b/src/cpu/scpu/core/core.h @@ -0,0 +1,58 @@ +//void (sCPU::*optbl[256])(); + +CPUReg24 aa, rd; +uint8 dp, sp; + + inline void main(); + inline void op_irq(); + + bool in_opcode() { return status.in_opcode; } + +//op_read + void op_adc_b(); + void op_adc_w(); + void op_and_b(); + void op_and_w(); + void op_bit_b(); + void op_bit_w(); + void op_cmp_b(); + void op_cmp_w(); + void op_cpx_b(); + void op_cpx_w(); + void op_cpy_b(); + void op_cpy_w(); + void op_eor_b(); + void op_eor_w(); + void op_lda_b(); + void op_lda_w(); + void op_ldx_b(); + void op_ldx_w(); + void op_ldy_b(); + void op_ldy_w(); + void op_ora_b(); + void op_ora_w(); + void op_sbc_b(); + void op_sbc_w(); +//op_rmw + void op_inc_b(); + void op_inc_w(); + void op_dec_b(); + void op_dec_w(); + void op_asl_b(); + void op_asl_w(); + void op_lsr_b(); + void op_lsr_w(); + void op_rol_b(); + void op_rol_w(); + void op_ror_b(); + void op_ror_w(); + void op_trb_b(); + void op_trb_w(); + void op_tsb_b(); + void op_tsb_w(); + + void op_io_cond2(); + void op_io_cond4(uint16 x, uint16 y); + void op_io_cond6(uint16 addr); + +//#include "op.h" diff --git a/src/cpu/scpu/core/op_misc.b b/src/cpu/scpu/core/op_misc.b new file mode 100644 index 00000000..19d12f31 --- /dev/null +++ b/src/cpu/scpu/core/op_misc.b @@ -0,0 +1,276 @@ +nop(0xea) { +1:last_cycle(); + op_io(); +} + +wdm(0x42) { +1:last_cycle(); + op_readpc(); +} + +xba(0xeb) { +1:op_io(); +2:last_cycle(); + op_io(); + regs.a.l ^= regs.a.h; + regs.a.h ^= regs.a.l; + regs.a.l ^= regs.a.h; + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); +} + +mvn(0x54, ++), +mvp(0x44, --) { +1:dp = op_readpc(); +2:sp = op_readpc(); +3:regs.db = dp; + rd.l = op_readlong((sp << 16) | regs.x.w); +4:op_writelong((dp << 16) | regs.y.w, rd.l); +5:op_io(); + if(regs.p.x) { regs.x.l$1; regs.y.l$1; } + else { regs.x.w$1; regs.y.w$1; } +6:last_cycle(); + op_io(); + if(regs.a.w--)regs.pc.w -= 3; +} + +brk(0x00, 0xfffe, 0xffff, 0xffe6, 0xffe7), +cop(0x02, 0xfff4, 0xfff5, 0xffe4, 0xffe5) { +1:op_readpc(); +2:if(!regs.e)op_writestack(regs.pc.b); +3:op_writestack(regs.pc.h); +4:op_writestack(regs.pc.l); +5:op_writestack(regs.p); +6:rd.l = op_readlong((regs.e) ? $1 : $3); + regs.pc.b = 0x00; + regs.p.i = 1; + regs.p.d = 0; +7:last_cycle(); + rd.h = op_readlong((regs.e) ? $2 : $4); + regs.pc.w = rd.w; +} + +stp(0xdb) { +1:op_io(); +2:last_cycle(); + while(1) { + op_io(); + co_return(); + } +} + +wai(0xcb) { +1:op_io(); + event.wai = true; +2:last_cycle(); + op_io(); +3:while(event.wai) { + last_cycle(); + op_io(); + co_return(); + } +} + +xce(0xfb) { +1:last_cycle(); + op_io(); +bool c = regs.p.c; + regs.p.c = regs.e; + regs.e = c; + if(regs.e) { + regs.p |= 0x30; + regs.x.h = 0x00; + regs.y.h = 0x00; + regs.s.h = 0x01; + } +} + +clc(0x18, regs.p.c = 0), +cld(0xd8, regs.p.d = 0), +cli(0x58, regs.p.i = 0), +clv(0xb8, regs.p.v = 0), +sec(0x38, regs.p.c = 1), +sed(0xf8, regs.p.d = 1), +sei(0x78, regs.p.i = 1) { +1:last_cycle(); + op_io(); + $1; +} + +rep(0xc2, &=~), +sep(0xe2, |=) { +1:rd.l = op_readpc(); +2:last_cycle(); + op_io(); + regs.p $1 rd.l; + if(regs.e)regs.p |= 0x30; + if(regs.p.x) { + regs.x.h = 0x00; + regs.y.h = 0x00; + } +} + +tax(0xaa, regs.p.x, x, a), +tay(0xa8, regs.p.x, y, a), +txa(0x8a, regs.p.m, a, x), +txy(0x9b, regs.p.x, y, x), +tya(0x98, regs.p.m, a, y), +tyx(0xbb, regs.p.x, x, y) { +1:last_cycle(); + op_io(); + if($1) { + regs.$2.l = regs.$3.l; + regs.p.n = !!(regs.$2.l & 0x80); + regs.p.z = (regs.$2.l == 0); + } else { + regs.$2.w = regs.$3.w; + regs.p.n = !!(regs.$2.w & 0x8000); + regs.p.z = (regs.$2.w == 0); + } +} + +tcd(0x5b) { +1:last_cycle(); + op_io(); + regs.d.w = regs.a.w; + regs.p.n = !!(regs.d.w & 0x8000); + regs.p.z = (regs.d.w == 0); +} + +tcs(0x1b) { +1:last_cycle(); + op_io(); + regs.s.w = regs.a.w; + if(regs.e)regs.s.h = 0x01; +} + +tdc(0x7b) { +1:last_cycle(); + op_io(); + regs.a.w = regs.d.w; + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); +} + +tsc(0x3b) { +1:last_cycle(); + op_io(); + regs.a.w = regs.s.w; + if(regs.e) { + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); + } else { + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); + } +} + +tsx(0xba) { +1:last_cycle(); + op_io(); + if(regs.p.x) { + regs.x.l = regs.s.l; + regs.p.n = !!(regs.x.l & 0x80); + regs.p.z = (regs.x.l == 0); + } else { + regs.x.w = regs.s.w; + regs.p.n = !!(regs.x.w & 0x8000); + regs.p.z = (regs.x.w == 0); + } +} + +txs(0x9a) { +1:last_cycle(); + op_io(); + if(regs.e) { + regs.s.l = regs.x.l; + } else { + regs.s.w = regs.x.w; + } +} + +pha(0x48, regs.p.m, a), +phx(0xda, regs.p.x, x), +phy(0x5a, regs.p.x, y), +phd(0x0b, 0, d) { +1:op_io(); +2:if(!$1)op_writestack(regs.$2.h); +3:last_cycle(); + op_writestack(regs.$2.l); +} + +phb(0x8b, regs.db), +phk(0x4b, regs.pc.b), +php(0x08, regs.p) { +1:op_io(); +2:last_cycle(); + op_writestack($1); +} + +pla(0x68, regs.p.m, a), +plx(0xfa, regs.p.x, x), +ply(0x7a, regs.p.x, y), +pld(0x2b, 0, d) { +1:op_io(); +2:op_io(); +3:if($1)last_cycle(); + regs.$2.l = op_readstack(); + if($1) { + regs.p.n = !!(regs.$2.l & 0x80); + regs.p.z = (regs.$2.l == 0); + end; + } +4:last_cycle(); + regs.$2.h = op_readstack(); + regs.p.n = !!(regs.$2.w & 0x8000); + regs.p.z = (regs.$2.w == 0); +} + +plb(0xab) { +1:op_io(); +2:op_io(); +3:last_cycle(); + regs.db = op_readstack(); + regs.p.n = !!(regs.db & 0x80); + regs.p.z = (regs.db == 0); +} + +plp(0x28) { +1:op_io(); +2:op_io(); +3:last_cycle(); + regs.p = op_readstack(); + if(regs.e)regs.p |= 0x30; + if(regs.p.x) { + regs.x.h = 0x00; + regs.y.h = 0x00; + } +} + +pea(0xf4) { +1:aa.l = op_readpc(); +2:aa.h = op_readpc(); +3:op_writestack(aa.h); +4:last_cycle(); + op_writestack(aa.l); +} + +pei(0xd4) { +1:dp = op_readpc(); +2:op_io_cond2(); +3:aa.l = op_readdp(dp); +4:aa.h = op_readdp(dp + 1); +5:op_writestack(aa.h); +6:last_cycle(); + op_writestack(aa.l); +} + +per(0x62) { +1:aa.l = op_readpc(); +2:aa.h = op_readpc(); +3:op_io(); + rd.w = regs.pc.d + (int16)aa.w; +4:op_writestack(rd.h); +5:last_cycle(); + op_writestack(rd.l); +} diff --git a/src/cpu/scpu/core/op_misc.cpp b/src/cpu/scpu/core/op_misc.cpp new file mode 100644 index 00000000..632e2b21 --- /dev/null +++ b/src/cpu/scpu/core/op_misc.cpp @@ -0,0 +1,530 @@ +//nop +case 0xea: { + last_cycle(); + op_io(); +} break; + +//wdm +case 0x42: { + last_cycle(); + op_readpc(); +} break; + +//xba +case 0xeb: { + op_io(); + last_cycle(); + op_io(); + regs.a.l ^= regs.a.h; + regs.a.h ^= regs.a.l; + regs.a.l ^= regs.a.h; + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); +} break; + +//mvn +case 0x54: { + dp = op_readpc(); + sp = op_readpc(); + regs.db = dp; + rd.l = op_readlong((sp << 16) | regs.x.w); + op_writelong((dp << 16) | regs.y.w, rd.l); + op_io(); + if(regs.p.x) { regs.x.l++; regs.y.l++; } + else { regs.x.w++; regs.y.w++; } + last_cycle(); + op_io(); + if(regs.a.w--)regs.pc.w -= 3; +} break; + +//mvp +case 0x44: { + dp = op_readpc(); + sp = op_readpc(); + regs.db = dp; + rd.l = op_readlong((sp << 16) | regs.x.w); + op_writelong((dp << 16) | regs.y.w, rd.l); + op_io(); + if(regs.p.x) { regs.x.l--; regs.y.l--; } + else { regs.x.w--; regs.y.w--; } + last_cycle(); + op_io(); + if(regs.a.w--)regs.pc.w -= 3; +} break; + +//brk +case 0x00: { + op_readpc(); + if(!regs.e)op_writestack(regs.pc.b); + op_writestack(regs.pc.h); + op_writestack(regs.pc.l); + op_writestack(regs.p); + rd.l = op_readlong((regs.e) ? 0xfffe : 0xffe6); + regs.pc.b = 0x00; + regs.p.i = 1; + regs.p.d = 0; + last_cycle(); + rd.h = op_readlong((regs.e) ? 0xffff : 0xffe7); + regs.pc.w = rd.w; +} break; + +//cop +case 0x02: { + op_readpc(); + if(!regs.e)op_writestack(regs.pc.b); + op_writestack(regs.pc.h); + op_writestack(regs.pc.l); + op_writestack(regs.p); + rd.l = op_readlong((regs.e) ? 0xfff4 : 0xffe4); + regs.pc.b = 0x00; + regs.p.i = 1; + regs.p.d = 0; + last_cycle(); + rd.h = op_readlong((regs.e) ? 0xfff5 : 0xffe5); + regs.pc.w = rd.w; +} break; + +//stp +case 0xdb: { + op_io(); + last_cycle(); + while(1) { + op_io(); + co_return(); + } +} break; + +//wai +case 0xcb: { + op_io(); + event.wai = true; + last_cycle(); + op_io(); + while(event.wai) { + last_cycle(); + op_io(); + co_return(); + } +} break; + +//xce +case 0xfb: { + last_cycle(); + op_io(); +bool c = regs.p.c; + regs.p.c = regs.e; + regs.e = c; + if(regs.e) { + regs.p |= 0x30; + regs.x.h = 0x00; + regs.y.h = 0x00; + regs.s.h = 0x01; + } +} break; + +//clc +case 0x18: { + last_cycle(); + op_io(); + regs.p.c = 0; +} break; + +//cld +case 0xd8: { + last_cycle(); + op_io(); + regs.p.d = 0; +} break; + +//cli +case 0x58: { + last_cycle(); + op_io(); + regs.p.i = 0; +} break; + +//clv +case 0xb8: { + last_cycle(); + op_io(); + regs.p.v = 0; +} break; + +//sec +case 0x38: { + last_cycle(); + op_io(); + regs.p.c = 1; +} break; + +//sed +case 0xf8: { + last_cycle(); + op_io(); + regs.p.d = 1; +} break; + +//sei +case 0x78: { + last_cycle(); + op_io(); + regs.p.i = 1; +} break; + +//rep +case 0xc2: { + rd.l = op_readpc(); + last_cycle(); + op_io(); + regs.p &=~ rd.l; + if(regs.e)regs.p |= 0x30; + if(regs.p.x) { + regs.x.h = 0x00; + regs.y.h = 0x00; + } +} break; + +//sep +case 0xe2: { + rd.l = op_readpc(); + last_cycle(); + op_io(); + regs.p |= rd.l; + if(regs.e)regs.p |= 0x30; + if(regs.p.x) { + regs.x.h = 0x00; + regs.y.h = 0x00; + } +} break; + +//tax +case 0xaa: { + last_cycle(); + op_io(); + if(regs.p.x) { + regs.x.l = regs.a.l; + regs.p.n = !!(regs.x.l & 0x80); + regs.p.z = (regs.x.l == 0); + } else { + regs.x.w = regs.a.w; + regs.p.n = !!(regs.x.w & 0x8000); + regs.p.z = (regs.x.w == 0); + } +} break; + +//tay +case 0xa8: { + last_cycle(); + op_io(); + if(regs.p.x) { + regs.y.l = regs.a.l; + regs.p.n = !!(regs.y.l & 0x80); + regs.p.z = (regs.y.l == 0); + } else { + regs.y.w = regs.a.w; + regs.p.n = !!(regs.y.w & 0x8000); + regs.p.z = (regs.y.w == 0); + } +} break; + +//txa +case 0x8a: { + last_cycle(); + op_io(); + if(regs.p.m) { + regs.a.l = regs.x.l; + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); + } else { + regs.a.w = regs.x.w; + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); + } +} break; + +//txy +case 0x9b: { + last_cycle(); + op_io(); + if(regs.p.x) { + regs.y.l = regs.x.l; + regs.p.n = !!(regs.y.l & 0x80); + regs.p.z = (regs.y.l == 0); + } else { + regs.y.w = regs.x.w; + regs.p.n = !!(regs.y.w & 0x8000); + regs.p.z = (regs.y.w == 0); + } +} break; + +//tya +case 0x98: { + last_cycle(); + op_io(); + if(regs.p.m) { + regs.a.l = regs.y.l; + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); + } else { + regs.a.w = regs.y.w; + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); + } +} break; + +//tyx +case 0xbb: { + last_cycle(); + op_io(); + if(regs.p.x) { + regs.x.l = regs.y.l; + regs.p.n = !!(regs.x.l & 0x80); + regs.p.z = (regs.x.l == 0); + } else { + regs.x.w = regs.y.w; + regs.p.n = !!(regs.x.w & 0x8000); + regs.p.z = (regs.x.w == 0); + } +} break; + +//tcd +case 0x5b: { + last_cycle(); + op_io(); + regs.d.w = regs.a.w; + regs.p.n = !!(regs.d.w & 0x8000); + regs.p.z = (regs.d.w == 0); +} break; + +//tcs +case 0x1b: { + last_cycle(); + op_io(); + regs.s.w = regs.a.w; + if(regs.e)regs.s.h = 0x01; +} break; + +//tdc +case 0x7b: { + last_cycle(); + op_io(); + regs.a.w = regs.d.w; + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); +} break; + +//tsc +case 0x3b: { + last_cycle(); + op_io(); + regs.a.w = regs.s.w; + if(regs.e) { + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); + } else { + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); + } +} break; + +//tsx +case 0xba: { + last_cycle(); + op_io(); + if(regs.p.x) { + regs.x.l = regs.s.l; + regs.p.n = !!(regs.x.l & 0x80); + regs.p.z = (regs.x.l == 0); + } else { + regs.x.w = regs.s.w; + regs.p.n = !!(regs.x.w & 0x8000); + regs.p.z = (regs.x.w == 0); + } +} break; + +//txs +case 0x9a: { + last_cycle(); + op_io(); + if(regs.e) { + regs.s.l = regs.x.l; + } else { + regs.s.w = regs.x.w; + } +} break; + +//pha +case 0x48: { + op_io(); + if(!regs.p.m)op_writestack(regs.a.h); + last_cycle(); + op_writestack(regs.a.l); +} break; + +//phx +case 0xda: { + op_io(); + if(!regs.p.x)op_writestack(regs.x.h); + last_cycle(); + op_writestack(regs.x.l); +} break; + +//phy +case 0x5a: { + op_io(); + if(!regs.p.x)op_writestack(regs.y.h); + last_cycle(); + op_writestack(regs.y.l); +} break; + +//phd +case 0x0b: { + op_io(); + if(!0)op_writestack(regs. d.h); + last_cycle(); + op_writestack(regs. d.l); +} break; + +//phb +case 0x8b: { + op_io(); + last_cycle(); + op_writestack(regs.db); +} break; + +//phk +case 0x4b: { + op_io(); + last_cycle(); + op_writestack(regs.pc.b); +} break; + +//php +case 0x08: { + op_io(); + last_cycle(); + op_writestack(regs.p); +} break; + +//pla +case 0x68: { + op_io(); + op_io(); + if(regs.p.m)last_cycle(); + regs.a.l = op_readstack(); + if(regs.p.m) { + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); + break; + } + last_cycle(); + regs.a.h = op_readstack(); + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); +} break; + +//plx +case 0xfa: { + op_io(); + op_io(); + if(regs.p.x)last_cycle(); + regs.x.l = op_readstack(); + if(regs.p.x) { + regs.p.n = !!(regs.x.l & 0x80); + regs.p.z = (regs.x.l == 0); + break; + } + last_cycle(); + regs.x.h = op_readstack(); + regs.p.n = !!(regs.x.w & 0x8000); + regs.p.z = (regs.x.w == 0); +} break; + +//ply +case 0x7a: { + op_io(); + op_io(); + if(regs.p.x)last_cycle(); + regs.y.l = op_readstack(); + if(regs.p.x) { + regs.p.n = !!(regs.y.l & 0x80); + regs.p.z = (regs.y.l == 0); + break; + } + last_cycle(); + regs.y.h = op_readstack(); + regs.p.n = !!(regs.y.w & 0x8000); + regs.p.z = (regs.y.w == 0); +} break; + +//pld +case 0x2b: { + op_io(); + op_io(); + if(0)last_cycle(); + regs. d.l = op_readstack(); + if(0) { + regs.p.n = !!(regs. d.l & 0x80); + regs.p.z = (regs. d.l == 0); + break; + } + last_cycle(); + regs. d.h = op_readstack(); + regs.p.n = !!(regs. d.w & 0x8000); + regs.p.z = (regs. d.w == 0); +} break; + +//plb +case 0xab: { + op_io(); + op_io(); + last_cycle(); + regs.db = op_readstack(); + regs.p.n = !!(regs.db & 0x80); + regs.p.z = (regs.db == 0); +} break; + +//plp +case 0x28: { + op_io(); + op_io(); + last_cycle(); + regs.p = op_readstack(); + if(regs.e)regs.p |= 0x30; + if(regs.p.x) { + regs.x.h = 0x00; + regs.y.h = 0x00; + } +} break; + +//pea +case 0xf4: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_writestack(aa.h); + last_cycle(); + op_writestack(aa.l); +} break; + +//pei +case 0xd4: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + op_writestack(aa.h); + last_cycle(); + op_writestack(aa.l); +} break; + +//per +case 0x62: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io(); + rd.w = regs.pc.d + (int16)aa.w; + op_writestack(rd.h); + last_cycle(); + op_writestack(rd.l); +} break; + diff --git a/src/cpu/scpu/core/op_pc.b b/src/cpu/scpu/core/op_pc.b new file mode 100644 index 00000000..7b126675 --- /dev/null +++ b/src/cpu/scpu/core/op_pc.b @@ -0,0 +1,160 @@ +bcc(0x90, !regs.p.c), +bcs(0xb0, regs.p.c), +bne(0xd0, !regs.p.z), +beq(0xf0, regs.p.z), +bpl(0x10, !regs.p.n), +bmi(0x30, regs.p.n), +bvc(0x50, !regs.p.v), +bvs(0x70, regs.p.v) { +1:if(!$1)last_cycle(); + rd.l = op_readpc(); + if($1) { + aa.w = regs.pc.d + (int8)rd.l; + regs.pc.w = aa.w; + } else { + end; + } +2:op_io_cond6(aa.w); +3:last_cycle(); + op_io(); +} + +bra(0x80) { +1:rd.l = op_readpc(); + aa.w = regs.pc.d + (int8)rd.l; + regs.pc.w = aa.w; +2:op_io_cond6(aa.w); +3:last_cycle(); + op_io(); +} + +brl(0x82) { +1:rd.l = op_readpc(); +2:rd.h = op_readpc(); +3:last_cycle(); + op_io(); + regs.pc.w = regs.pc.d + (int16)rd.w; +} + +jmp_addr(0x4c) { +1:rd.l = op_readpc(); +2:last_cycle(); + rd.h = op_readpc(); + regs.pc.w = rd.w; +} + +jmp_long(0x5c) { +1:rd.l = op_readpc(); +2:rd.h = op_readpc(); +3:last_cycle(); + rd.b = op_readpc(); + regs.pc.d = rd.d & 0xffffff; +} + +jmp_iaddr(0x6c) { +1:aa.l = op_readpc(); +2:aa.h = op_readpc(); +3:rd.l = op_readaddr(aa.w); +4:last_cycle(); + rd.h = op_readaddr(aa.w + 1); + regs.pc.w = rd.w; +} + +jmp_iaddrx(0x7c) { +1:aa.l = op_readpc(); +2:aa.h = op_readpc(); +3:op_io(); +4:rd.l = op_readpbr(aa.w + regs.x.w); +5:last_cycle(); + rd.h = op_readpbr(aa.w + regs.x.w + 1); + regs.pc.w = rd.w; +} + +jmp_iladdr(0xdc) { +1:aa.l = op_readpc(); +2:aa.h = op_readpc(); +3:rd.l = op_readaddr(aa.w); +4:rd.h = op_readaddr(aa.w + 1); +5:last_cycle(); + rd.b = op_readaddr(aa.w + 2); + regs.pc.d = rd.d & 0xffffff; +} + +jsr_addr(0x20) { +1:aa.l = op_readpc(); +2:aa.h = op_readpc(); +3:op_io(); +4:regs.pc.w--; + op_writestack(regs.pc.h); +5:last_cycle(); + op_writestack(regs.pc.l); + regs.pc.w = aa.w; +} + +jsr_long(0x22) { +1:aa.l = op_readpc(); +2:aa.h = op_readpc(); +3:op_writestack(regs.pc.b); +4:op_io(); +5:aa.b = op_readpc(); +6:regs.pc.w--; + op_writestack(regs.pc.h); +7:last_cycle(); + op_writestack(regs.pc.l); + regs.pc.d = aa.d & 0xffffff; +} + +jsr_iaddrx(0xfc) { +1:aa.l = op_readpc(); +2:op_writestack(regs.pc.h); +3:op_writestack(regs.pc.l); +4:aa.h = op_readpc(); +5:op_io(); +6:rd.l = op_readpbr(aa.w + regs.x.w); +7:last_cycle(); + rd.h = op_readpbr(aa.w + regs.x.w + 1); + regs.pc.w = rd.w; +} + +rti(0x40) { +1:op_io(); +2:op_io(); +3:regs.p = op_readstack(); + if(regs.e)regs.p |= 0x30; + if(regs.p.x) { + regs.x.h = 0x00; + regs.y.h = 0x00; + } +4:rd.l = op_readstack(); +5:if(regs.e)last_cycle(); + rd.h = op_readstack(); + if(regs.e) { + regs.pc.w = rd.w; + end; + } +6:last_cycle(); + rd.b = op_readstack(); + regs.pc.d = rd.d & 0xffffff; +} + +rts(0x60) { +1:op_io(); +2:op_io(); +3:rd.l = op_readstack(); +4:rd.h = op_readstack(); +5:last_cycle(); + op_io(); + regs.pc.w = rd.w; + regs.pc.w++; +} + +rtl(0x6b) { +1:op_io(); +2:op_io(); +3:rd.l = op_readstack(); +4:rd.h = op_readstack(); +5:last_cycle(); + rd.b = op_readstack(); + regs.pc.d = rd.d & 0xffffff; + regs.pc.w++; +} diff --git a/src/cpu/scpu/core/op_pc.cpp b/src/cpu/scpu/core/op_pc.cpp new file mode 100644 index 00000000..14a4c74e --- /dev/null +++ b/src/cpu/scpu/core/op_pc.cpp @@ -0,0 +1,273 @@ +//bcc +case 0x90: { + if(!!regs.p.c)last_cycle(); + rd.l = op_readpc(); + if(!regs.p.c) { + aa.w = regs.pc.d + (int8)rd.l; + regs.pc.w = aa.w; + } else { + break; + } + op_io_cond6(aa.w); + last_cycle(); + op_io(); +} break; + +//bcs +case 0xb0: { + if(!regs.p.c)last_cycle(); + rd.l = op_readpc(); + if(regs.p.c) { + aa.w = regs.pc.d + (int8)rd.l; + regs.pc.w = aa.w; + } else { + break; + } + op_io_cond6(aa.w); + last_cycle(); + op_io(); +} break; + +//bne +case 0xd0: { + if(!!regs.p.z)last_cycle(); + rd.l = op_readpc(); + if(!regs.p.z) { + aa.w = regs.pc.d + (int8)rd.l; + regs.pc.w = aa.w; + } else { + break; + } + op_io_cond6(aa.w); + last_cycle(); + op_io(); +} break; + +//beq +case 0xf0: { + if(!regs.p.z)last_cycle(); + rd.l = op_readpc(); + if(regs.p.z) { + aa.w = regs.pc.d + (int8)rd.l; + regs.pc.w = aa.w; + } else { + break; + } + op_io_cond6(aa.w); + last_cycle(); + op_io(); +} break; + +//bpl +case 0x10: { + if(!!regs.p.n)last_cycle(); + rd.l = op_readpc(); + if(!regs.p.n) { + aa.w = regs.pc.d + (int8)rd.l; + regs.pc.w = aa.w; + } else { + break; + } + op_io_cond6(aa.w); + last_cycle(); + op_io(); +} break; + +//bmi +case 0x30: { + if(!regs.p.n)last_cycle(); + rd.l = op_readpc(); + if(regs.p.n) { + aa.w = regs.pc.d + (int8)rd.l; + regs.pc.w = aa.w; + } else { + break; + } + op_io_cond6(aa.w); + last_cycle(); + op_io(); +} break; + +//bvc +case 0x50: { + if(!!regs.p.v)last_cycle(); + rd.l = op_readpc(); + if(!regs.p.v) { + aa.w = regs.pc.d + (int8)rd.l; + regs.pc.w = aa.w; + } else { + break; + } + op_io_cond6(aa.w); + last_cycle(); + op_io(); +} break; + +//bvs +case 0x70: { + if(!regs.p.v)last_cycle(); + rd.l = op_readpc(); + if(regs.p.v) { + aa.w = regs.pc.d + (int8)rd.l; + regs.pc.w = aa.w; + } else { + break; + } + op_io_cond6(aa.w); + last_cycle(); + op_io(); +} break; + +//bra +case 0x80: { + rd.l = op_readpc(); + aa.w = regs.pc.d + (int8)rd.l; + regs.pc.w = aa.w; + op_io_cond6(aa.w); + last_cycle(); + op_io(); +} break; + +//brl +case 0x82: { + rd.l = op_readpc(); + rd.h = op_readpc(); + last_cycle(); + op_io(); + regs.pc.w = regs.pc.d + (int16)rd.w; +} break; + +//jmp_addr +case 0x4c: { + rd.l = op_readpc(); + last_cycle(); + rd.h = op_readpc(); + regs.pc.w = rd.w; +} break; + +//jmp_long +case 0x5c: { + rd.l = op_readpc(); + rd.h = op_readpc(); + last_cycle(); + rd.b = op_readpc(); + regs.pc.d = rd.d & 0xffffff; +} break; + +//jmp_iaddr +case 0x6c: { + aa.l = op_readpc(); + aa.h = op_readpc(); + rd.l = op_readaddr(aa.w); + last_cycle(); + rd.h = op_readaddr(aa.w + 1); + regs.pc.w = rd.w; +} break; + +//jmp_iaddrx +case 0x7c: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io(); + rd.l = op_readpbr(aa.w + regs.x.w); + last_cycle(); + rd.h = op_readpbr(aa.w + regs.x.w + 1); + regs.pc.w = rd.w; +} break; + +//jmp_iladdr +case 0xdc: { + aa.l = op_readpc(); + aa.h = op_readpc(); + rd.l = op_readaddr(aa.w); + rd.h = op_readaddr(aa.w + 1); + last_cycle(); + rd.b = op_readaddr(aa.w + 2); + regs.pc.d = rd.d & 0xffffff; +} break; + +//jsr_addr +case 0x20: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io(); + regs.pc.w--; + op_writestack(regs.pc.h); + last_cycle(); + op_writestack(regs.pc.l); + regs.pc.w = aa.w; +} break; + +//jsr_long +case 0x22: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_writestack(regs.pc.b); + op_io(); + aa.b = op_readpc(); + regs.pc.w--; + op_writestack(regs.pc.h); + last_cycle(); + op_writestack(regs.pc.l); + regs.pc.d = aa.d & 0xffffff; +} break; + +//jsr_iaddrx +case 0xfc: { + aa.l = op_readpc(); + op_writestack(regs.pc.h); + op_writestack(regs.pc.l); + aa.h = op_readpc(); + op_io(); + rd.l = op_readpbr(aa.w + regs.x.w); + last_cycle(); + rd.h = op_readpbr(aa.w + regs.x.w + 1); + regs.pc.w = rd.w; +} break; + +//rti +case 0x40: { + op_io(); + op_io(); + regs.p = op_readstack(); + if(regs.e)regs.p |= 0x30; + if(regs.p.x) { + regs.x.h = 0x00; + regs.y.h = 0x00; + } + rd.l = op_readstack(); + if(regs.e)last_cycle(); + rd.h = op_readstack(); + if(regs.e) { + regs.pc.w = rd.w; + break; + } + last_cycle(); + rd.b = op_readstack(); + regs.pc.d = rd.d & 0xffffff; +} break; + +//rts +case 0x60: { + op_io(); + op_io(); + rd.l = op_readstack(); + rd.h = op_readstack(); + last_cycle(); + op_io(); + regs.pc.w = rd.w; + regs.pc.w++; +} break; + +//rtl +case 0x6b: { + op_io(); + op_io(); + rd.l = op_readstack(); + rd.h = op_readstack(); + last_cycle(); + rd.b = op_readstack(); + regs.pc.d = rd.d & 0xffffff; + regs.pc.w++; +} break; + diff --git a/src/cpu/scpu/core/op_read.b b/src/cpu/scpu/core/op_read.b new file mode 100644 index 00000000..1b3d986f --- /dev/null +++ b/src/cpu/scpu/core/op_read.b @@ -0,0 +1,317 @@ +adc_const(0x69, adc, regs.p.m), +and_const(0x29, and, regs.p.m), +cmp_const(0xc9, cmp, regs.p.m), +cpx_const(0xe0, cpx, regs.p.x), +cpy_const(0xc0, cpy, regs.p.x), +eor_const(0x49, eor, regs.p.m), +lda_const(0xa9, lda, regs.p.m), +ldx_const(0xa2, ldx, regs.p.x), +ldy_const(0xa0, ldy, regs.p.x), +ora_const(0x09, ora, regs.p.m), +sbc_const(0xe9, sbc, regs.p.m) { +1:if($2)last_cycle(); + rd.l = op_readpc(); + if($2) { op_$1_b(); end; } +2:last_cycle(); + rd.h = op_readpc(); + op_$1_w(); +} + +adc_addr(0x6d, adc, regs.p.m), +and_addr(0x2d, and, regs.p.m), +bit_addr(0x2c, bit, regs.p.m), +cmp_addr(0xcd, cmp, regs.p.m), +cpx_addr(0xec, cpx, regs.p.x), +cpy_addr(0xcc, cpy, regs.p.x), +eor_addr(0x4d, eor, regs.p.m), +lda_addr(0xad, lda, regs.p.m), +ldx_addr(0xae, ldx, regs.p.x), +ldy_addr(0xac, ldy, regs.p.x), +ora_addr(0x0d, ora, regs.p.m), +sbc_addr(0xed, sbc, regs.p.m) { +1:aa.l = op_readpc(); +2:aa.h = op_readpc(); +3:if($2)last_cycle(); + rd.l = op_readdbr(aa.w); + if($2) { op_$1_b(); end; } +4:last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_$1_w(); +} + +adc_addrx(0x7d, adc, regs.p.m), +and_addrx(0x3d, and, regs.p.m), +bit_addrx(0x3c, bit, regs.p.m), +cmp_addrx(0xdd, cmp, regs.p.m), +eor_addrx(0x5d, eor, regs.p.m), +lda_addrx(0xbd, lda, regs.p.m), +ldy_addrx(0xbc, ldy, regs.p.x), +ora_addrx(0x1d, ora, regs.p.m), +sbc_addrx(0xfd, sbc, regs.p.m) { +1:aa.l = op_readpc(); +2:aa.h = op_readpc(); +3:op_io_cond4(aa.w, aa.w + regs.x.w); +4:if($2)last_cycle(); + rd.l = op_readdbr(aa.w + regs.x.w); + if($2) { op_$1_b(); end; } +5:last_cycle(); + rd.h = op_readdbr(aa.w + regs.x.w + 1); + op_$1_w(); +} + +adc_addry(0x79, adc, regs.p.m), +and_addry(0x39, and, regs.p.m), +cmp_addry(0xd9, cmp, regs.p.m), +eor_addry(0x59, eor, regs.p.m), +lda_addry(0xb9, lda, regs.p.m), +ldx_addry(0xbe, ldx, regs.p.x), +ora_addry(0x19, ora, regs.p.m), +sbc_addry(0xf9, sbc, regs.p.m) { +1:aa.l = op_readpc(); +2:aa.h = op_readpc(); +3:op_io_cond4(aa.w, aa.w + regs.y.w); +4:if($2)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if($2) { op_$1_b(); end; } +5:last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_$1_w(); +} + +adc_long(0x6f, adc, regs.p.m), +and_long(0x2f, and, regs.p.m), +cmp_long(0xcf, cmp, regs.p.m), +eor_long(0x4f, eor, regs.p.m), +lda_long(0xaf, lda, regs.p.m), +ora_long(0x0f, ora, regs.p.m), +sbc_long(0xef, sbc, regs.p.m) { +1:aa.l = op_readpc(); +2:aa.h = op_readpc(); +3:aa.b = op_readpc(); +4:if($2)last_cycle(); + rd.l = op_readlong(aa.d); + if($2) { op_$1_b(); end; } +5:last_cycle(); + rd.h = op_readlong(aa.d + 1); + op_$1_w(); +} + +adc_longx(0x7f, adc, regs.p.m), +and_longx(0x3f, and, regs.p.m), +cmp_longx(0xdf, cmp, regs.p.m), +eor_longx(0x5f, eor, regs.p.m), +lda_longx(0xbf, lda, regs.p.m), +ora_longx(0x1f, ora, regs.p.m), +sbc_longx(0xff, sbc, regs.p.m) { +1:aa.l = op_readpc(); +2:aa.h = op_readpc(); +3:aa.b = op_readpc(); +4:if($2)last_cycle(); + rd.l = op_readlong(aa.d + regs.x.w); + if($2) { op_$1_b(); end; } +5:last_cycle(); + rd.h = op_readlong(aa.d + regs.x.w + 1); + op_$1_w(); +} + +adc_dp(0x65, adc, regs.p.m), +and_dp(0x25, and, regs.p.m), +bit_dp(0x24, bit, regs.p.m), +cmp_dp(0xc5, cmp, regs.p.m), +cpx_dp(0xe4, cpx, regs.p.x), +cpy_dp(0xc4, cpy, regs.p.x), +eor_dp(0x45, eor, regs.p.m), +lda_dp(0xa5, lda, regs.p.m), +ldx_dp(0xa6, ldx, regs.p.x), +ldy_dp(0xa4, ldy, regs.p.x), +ora_dp(0x05, ora, regs.p.m), +sbc_dp(0xe5, sbc, regs.p.m) { +1:dp = op_readpc(); +2:op_io_cond2(); +3:if($2)last_cycle(); + rd.l = op_readdp(dp); + if($2) { op_$1_b(); end; } +4:last_cycle(); + rd.h = op_readdp(dp + 1); + op_$1_w(); +} + +adc_dpx(0x75, adc, regs.p.m), +and_dpx(0x35, and, regs.p.m), +bit_dpx(0x34, bit, regs.p.m), +cmp_dpx(0xd5, cmp, regs.p.m), +eor_dpx(0x55, eor, regs.p.m), +lda_dpx(0xb5, lda, regs.p.m), +ldy_dpx(0xb4, ldy, regs.p.x), +ora_dpx(0x15, ora, regs.p.m), +sbc_dpx(0xf5, sbc, regs.p.m) { +1:dp = op_readpc(); +2:op_io_cond2(); +3:op_io(); +4:if($2)last_cycle(); + rd.l = op_readdp(dp + regs.x.w); + if($2) { op_$1_b(); end; } +5:last_cycle(); + rd.h = op_readdp(dp + regs.x.w + 1); + op_$1_w(); +} + +ldx_dpy(0xb6, ldx, regs.p.x) { +1:dp = op_readpc(); +2:op_io_cond2(); +3:op_io(); +4:if($2)last_cycle(); + rd.l = op_readdp(dp + regs.y.w); + if($2) { op_$1_b(); end; } +5:last_cycle(); + rd.h = op_readdp(dp + regs.y.w + 1); + op_$1_w(); +} + +adc_idp(0x72, adc, regs.p.m), +and_idp(0x32, and, regs.p.m), +cmp_idp(0xd2, cmp, regs.p.m), +eor_idp(0x52, eor, regs.p.m), +lda_idp(0xb2, lda, regs.p.m), +ora_idp(0x12, ora, regs.p.m), +sbc_idp(0xf2, sbc, regs.p.m) { +1:dp = op_readpc(); +2:op_io_cond2(); +3:aa.l = op_readdp(dp); +4:aa.h = op_readdp(dp + 1); +5:if($2)last_cycle(); + rd.l = op_readdbr(aa.w); + if($2) { op_$1_b(); end; } +6:last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_$1_w(); +} + +adc_idpx(0x61, adc, regs.p.m), +and_idpx(0x21, and, regs.p.m), +cmp_idpx(0xc1, cmp, regs.p.m), +eor_idpx(0x41, eor, regs.p.m), +lda_idpx(0xa1, lda, regs.p.m), +ora_idpx(0x01, ora, regs.p.m), +sbc_idpx(0xe1, sbc, regs.p.m) { +1:dp = op_readpc(); +2:op_io_cond2(); +3:op_io(); +4:aa.l = op_readdp(dp + regs.x.w); +5:aa.h = op_readdp(dp + regs.x.w + 1); +6:if($2)last_cycle(); + rd.l = op_readdbr(aa.w); + if($2) { op_$1_b(); end; } +7:last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_$1_w(); +} + +adc_idpy(0x71, adc, regs.p.m), +and_idpy(0x31, and, regs.p.m), +cmp_idpy(0xd1, cmp, regs.p.m), +eor_idpy(0x51, eor, regs.p.m), +lda_idpy(0xb1, lda, regs.p.m), +ora_idpy(0x11, ora, regs.p.m), +sbc_idpy(0xf1, sbc, regs.p.m) { +1:dp = op_readpc(); +2:op_io_cond2(); +3:aa.l = op_readdp(dp); +4:aa.h = op_readdp(dp + 1); +5:op_io_cond4(aa.w, aa.w + regs.y.w); +6:if($2)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if($2) { op_$1_b(); end; } +7:last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_$1_w(); +} + +adc_ildp(0x67, adc, regs.p.m), +and_ildp(0x27, and, regs.p.m), +cmp_ildp(0xc7, cmp, regs.p.m), +eor_ildp(0x47, eor, regs.p.m), +lda_ildp(0xa7, lda, regs.p.m), +ora_ildp(0x07, ora, regs.p.m), +sbc_ildp(0xe7, sbc, regs.p.m) { +1:dp = op_readpc(); +2:op_io_cond2(); +3:aa.l = op_readdp(dp); +4:aa.h = op_readdp(dp + 1); +5:aa.b = op_readdp(dp + 2); +6:if($2)last_cycle(); + rd.l = op_readlong(aa.d); + if($2) { op_$1_b(); end; } +7:last_cycle(); + rd.h = op_readlong(aa.d + 1); + op_$1_w(); +} + +adc_ildpy(0x77, adc, regs.p.m), +and_ildpy(0x37, and, regs.p.m), +cmp_ildpy(0xd7, cmp, regs.p.m), +eor_ildpy(0x57, eor, regs.p.m), +lda_ildpy(0xb7, lda, regs.p.m), +ora_ildpy(0x17, ora, regs.p.m), +sbc_ildpy(0xf7, sbc, regs.p.m) { +1:dp = op_readpc(); +2:op_io_cond2(); +3:aa.l = op_readdp(dp); +4:aa.h = op_readdp(dp + 1); +5:aa.b = op_readdp(dp + 2); +6:if($2)last_cycle(); + rd.l = op_readlong(aa.d + regs.y.w); + if($2) { op_$1_b(); end; } +7:last_cycle(); + rd.h = op_readlong(aa.d + regs.y.w + 1); + op_$1_w(); +} + +adc_sr(0x63, adc, regs.p.m), +and_sr(0x23, and, regs.p.m), +cmp_sr(0xc3, cmp, regs.p.m), +eor_sr(0x43, eor, regs.p.m), +lda_sr(0xa3, lda, regs.p.m), +ora_sr(0x03, ora, regs.p.m), +sbc_sr(0xe3, sbc, regs.p.m) { +1:sp = op_readpc(); +2:op_io(); +3:if($2)last_cycle(); + rd.l = op_readsp(sp); + if($2) { op_$1_b(); end; } +4:last_cycle(); + rd.h = op_readsp(sp + 1); + op_$1_w(); +} + +adc_isry(0x73, adc), +and_isry(0x33, and), +cmp_isry(0xd3, cmp), +eor_isry(0x53, eor), +lda_isry(0xb3, lda), +ora_isry(0x13, ora), +sbc_isry(0xf3, sbc) { +1:sp = op_readpc(); +2:op_io(); +3:aa.l = op_readsp(sp); +4:aa.h = op_readsp(sp + 1); +5:op_io(); +6:if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_$1_b(); end; } +7:last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_$1_w(); +} + +bit_const(0x89) { +1:if(regs.p.m)last_cycle(); + rd.l = op_readpc(); + if(regs.p.m) { + regs.p.z = ((rd.l & regs.a.l) == 0); + end; + } +2:last_cycle(); + rd.h = op_readpc(); + regs.p.z = ((rd.w & regs.a.w) == 0); +} diff --git a/src/cpu/scpu/core/op_read.cpp b/src/cpu/scpu/core/op_read.cpp new file mode 100644 index 00000000..fee2eda8 --- /dev/null +++ b/src/cpu/scpu/core/op_read.cpp @@ -0,0 +1,1651 @@ +//adc_const +case 0x69: { + if(regs.p.m)last_cycle(); + rd.l = op_readpc(); + if(regs.p.m) { op_adc_b(); break; } + last_cycle(); + rd.h = op_readpc(); + op_adc_w(); +} break; + +//and_const +case 0x29: { + if(regs.p.m)last_cycle(); + rd.l = op_readpc(); + if(regs.p.m) { op_and_b(); break; } + last_cycle(); + rd.h = op_readpc(); + op_and_w(); +} break; + +//cmp_const +case 0xc9: { + if(regs.p.m)last_cycle(); + rd.l = op_readpc(); + if(regs.p.m) { op_cmp_b(); break; } + last_cycle(); + rd.h = op_readpc(); + op_cmp_w(); +} break; + +//cpx_const +case 0xe0: { + if(regs.p.x)last_cycle(); + rd.l = op_readpc(); + if(regs.p.x) { op_cpx_b(); break; } + last_cycle(); + rd.h = op_readpc(); + op_cpx_w(); +} break; + +//cpy_const +case 0xc0: { + if(regs.p.x)last_cycle(); + rd.l = op_readpc(); + if(regs.p.x) { op_cpy_b(); break; } + last_cycle(); + rd.h = op_readpc(); + op_cpy_w(); +} break; + +//eor_const +case 0x49: { + if(regs.p.m)last_cycle(); + rd.l = op_readpc(); + if(regs.p.m) { op_eor_b(); break; } + last_cycle(); + rd.h = op_readpc(); + op_eor_w(); +} break; + +//lda_const +case 0xa9: { + if(regs.p.m)last_cycle(); + rd.l = op_readpc(); + if(regs.p.m) { op_lda_b(); break; } + last_cycle(); + rd.h = op_readpc(); + op_lda_w(); +} break; + +//ldx_const +case 0xa2: { + if(regs.p.x)last_cycle(); + rd.l = op_readpc(); + if(regs.p.x) { op_ldx_b(); break; } + last_cycle(); + rd.h = op_readpc(); + op_ldx_w(); +} break; + +//ldy_const +case 0xa0: { + if(regs.p.x)last_cycle(); + rd.l = op_readpc(); + if(regs.p.x) { op_ldy_b(); break; } + last_cycle(); + rd.h = op_readpc(); + op_ldy_w(); +} break; + +//ora_const +case 0x09: { + if(regs.p.m)last_cycle(); + rd.l = op_readpc(); + if(regs.p.m) { op_ora_b(); break; } + last_cycle(); + rd.h = op_readpc(); + op_ora_w(); +} break; + +//sbc_const +case 0xe9: { + if(regs.p.m)last_cycle(); + rd.l = op_readpc(); + if(regs.p.m) { op_sbc_b(); break; } + last_cycle(); + rd.h = op_readpc(); + op_sbc_w(); +} break; + +//adc_addr +case 0x6d: { + aa.l = op_readpc(); + aa.h = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_adc_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_adc_w(); +} break; + +//and_addr +case 0x2d: { + aa.l = op_readpc(); + aa.h = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_and_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_and_w(); +} break; + +//bit_addr +case 0x2c: { + aa.l = op_readpc(); + aa.h = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_bit_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_bit_w(); +} break; + +//cmp_addr +case 0xcd: { + aa.l = op_readpc(); + aa.h = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_cmp_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_cmp_w(); +} break; + +//cpx_addr +case 0xec: { + aa.l = op_readpc(); + aa.h = op_readpc(); + if(regs.p.x)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.x) { op_cpx_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_cpx_w(); +} break; + +//cpy_addr +case 0xcc: { + aa.l = op_readpc(); + aa.h = op_readpc(); + if(regs.p.x)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.x) { op_cpy_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_cpy_w(); +} break; + +//eor_addr +case 0x4d: { + aa.l = op_readpc(); + aa.h = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_eor_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_eor_w(); +} break; + +//lda_addr +case 0xad: { + aa.l = op_readpc(); + aa.h = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_lda_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_lda_w(); +} break; + +//ldx_addr +case 0xae: { + aa.l = op_readpc(); + aa.h = op_readpc(); + if(regs.p.x)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.x) { op_ldx_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_ldx_w(); +} break; + +//ldy_addr +case 0xac: { + aa.l = op_readpc(); + aa.h = op_readpc(); + if(regs.p.x)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.x) { op_ldy_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_ldy_w(); +} break; + +//ora_addr +case 0x0d: { + aa.l = op_readpc(); + aa.h = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_ora_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_ora_w(); +} break; + +//sbc_addr +case 0xed: { + aa.l = op_readpc(); + aa.h = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_sbc_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_sbc_w(); +} break; + +//adc_addrx +case 0x7d: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.x.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.x.w); + if(regs.p.m) { op_adc_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.x.w + 1); + op_adc_w(); +} break; + +//and_addrx +case 0x3d: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.x.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.x.w); + if(regs.p.m) { op_and_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.x.w + 1); + op_and_w(); +} break; + +//bit_addrx +case 0x3c: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.x.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.x.w); + if(regs.p.m) { op_bit_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.x.w + 1); + op_bit_w(); +} break; + +//cmp_addrx +case 0xdd: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.x.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.x.w); + if(regs.p.m) { op_cmp_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.x.w + 1); + op_cmp_w(); +} break; + +//eor_addrx +case 0x5d: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.x.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.x.w); + if(regs.p.m) { op_eor_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.x.w + 1); + op_eor_w(); +} break; + +//lda_addrx +case 0xbd: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.x.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.x.w); + if(regs.p.m) { op_lda_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.x.w + 1); + op_lda_w(); +} break; + +//ldy_addrx +case 0xbc: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.x.w); + if(regs.p.x)last_cycle(); + rd.l = op_readdbr(aa.w + regs.x.w); + if(regs.p.x) { op_ldy_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.x.w + 1); + op_ldy_w(); +} break; + +//ora_addrx +case 0x1d: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.x.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.x.w); + if(regs.p.m) { op_ora_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.x.w + 1); + op_ora_w(); +} break; + +//sbc_addrx +case 0xfd: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.x.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.x.w); + if(regs.p.m) { op_sbc_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.x.w + 1); + op_sbc_w(); +} break; + +//adc_addry +case 0x79: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.y.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_adc_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_adc_w(); +} break; + +//and_addry +case 0x39: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.y.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_and_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_and_w(); +} break; + +//cmp_addry +case 0xd9: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.y.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_cmp_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_cmp_w(); +} break; + +//eor_addry +case 0x59: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.y.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_eor_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_eor_w(); +} break; + +//lda_addry +case 0xb9: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.y.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_lda_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_lda_w(); +} break; + +//ldx_addry +case 0xbe: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.y.w); + if(regs.p.x)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.x) { op_ldx_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_ldx_w(); +} break; + +//ora_addry +case 0x19: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.y.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_ora_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_ora_w(); +} break; + +//sbc_addry +case 0xf9: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.y.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_sbc_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_sbc_w(); +} break; + +//adc_long +case 0x6f: { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d); + if(regs.p.m) { op_adc_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + 1); + op_adc_w(); +} break; + +//and_long +case 0x2f: { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d); + if(regs.p.m) { op_and_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + 1); + op_and_w(); +} break; + +//cmp_long +case 0xcf: { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d); + if(regs.p.m) { op_cmp_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + 1); + op_cmp_w(); +} break; + +//eor_long +case 0x4f: { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d); + if(regs.p.m) { op_eor_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + 1); + op_eor_w(); +} break; + +//lda_long +case 0xaf: { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d); + if(regs.p.m) { op_lda_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + 1); + op_lda_w(); +} break; + +//ora_long +case 0x0f: { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d); + if(regs.p.m) { op_ora_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + 1); + op_ora_w(); +} break; + +//sbc_long +case 0xef: { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d); + if(regs.p.m) { op_sbc_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + 1); + op_sbc_w(); +} break; + +//adc_longx +case 0x7f: { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d + regs.x.w); + if(regs.p.m) { op_adc_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + regs.x.w + 1); + op_adc_w(); +} break; + +//and_longx +case 0x3f: { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d + regs.x.w); + if(regs.p.m) { op_and_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + regs.x.w + 1); + op_and_w(); +} break; + +//cmp_longx +case 0xdf: { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d + regs.x.w); + if(regs.p.m) { op_cmp_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + regs.x.w + 1); + op_cmp_w(); +} break; + +//eor_longx +case 0x5f: { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d + regs.x.w); + if(regs.p.m) { op_eor_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + regs.x.w + 1); + op_eor_w(); +} break; + +//lda_longx +case 0xbf: { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d + regs.x.w); + if(regs.p.m) { op_lda_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + regs.x.w + 1); + op_lda_w(); +} break; + +//ora_longx +case 0x1f: { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d + regs.x.w); + if(regs.p.m) { op_ora_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + regs.x.w + 1); + op_ora_w(); +} break; + +//sbc_longx +case 0xff: { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d + regs.x.w); + if(regs.p.m) { op_sbc_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + regs.x.w + 1); + op_sbc_w(); +} break; + +//adc_dp +case 0x65: { + dp = op_readpc(); + op_io_cond2(); + if(regs.p.m)last_cycle(); + rd.l = op_readdp(dp); + if(regs.p.m) { op_adc_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + 1); + op_adc_w(); +} break; + +//and_dp +case 0x25: { + dp = op_readpc(); + op_io_cond2(); + if(regs.p.m)last_cycle(); + rd.l = op_readdp(dp); + if(regs.p.m) { op_and_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + 1); + op_and_w(); +} break; + +//bit_dp +case 0x24: { + dp = op_readpc(); + op_io_cond2(); + if(regs.p.m)last_cycle(); + rd.l = op_readdp(dp); + if(regs.p.m) { op_bit_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + 1); + op_bit_w(); +} break; + +//cmp_dp +case 0xc5: { + dp = op_readpc(); + op_io_cond2(); + if(regs.p.m)last_cycle(); + rd.l = op_readdp(dp); + if(regs.p.m) { op_cmp_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + 1); + op_cmp_w(); +} break; + +//cpx_dp +case 0xe4: { + dp = op_readpc(); + op_io_cond2(); + if(regs.p.x)last_cycle(); + rd.l = op_readdp(dp); + if(regs.p.x) { op_cpx_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + 1); + op_cpx_w(); +} break; + +//cpy_dp +case 0xc4: { + dp = op_readpc(); + op_io_cond2(); + if(regs.p.x)last_cycle(); + rd.l = op_readdp(dp); + if(regs.p.x) { op_cpy_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + 1); + op_cpy_w(); +} break; + +//eor_dp +case 0x45: { + dp = op_readpc(); + op_io_cond2(); + if(regs.p.m)last_cycle(); + rd.l = op_readdp(dp); + if(regs.p.m) { op_eor_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + 1); + op_eor_w(); +} break; + +//lda_dp +case 0xa5: { + dp = op_readpc(); + op_io_cond2(); + if(regs.p.m)last_cycle(); + rd.l = op_readdp(dp); + if(regs.p.m) { op_lda_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + 1); + op_lda_w(); +} break; + +//ldx_dp +case 0xa6: { + dp = op_readpc(); + op_io_cond2(); + if(regs.p.x)last_cycle(); + rd.l = op_readdp(dp); + if(regs.p.x) { op_ldx_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + 1); + op_ldx_w(); +} break; + +//ldy_dp +case 0xa4: { + dp = op_readpc(); + op_io_cond2(); + if(regs.p.x)last_cycle(); + rd.l = op_readdp(dp); + if(regs.p.x) { op_ldy_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + 1); + op_ldy_w(); +} break; + +//ora_dp +case 0x05: { + dp = op_readpc(); + op_io_cond2(); + if(regs.p.m)last_cycle(); + rd.l = op_readdp(dp); + if(regs.p.m) { op_ora_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + 1); + op_ora_w(); +} break; + +//sbc_dp +case 0xe5: { + dp = op_readpc(); + op_io_cond2(); + if(regs.p.m)last_cycle(); + rd.l = op_readdp(dp); + if(regs.p.m) { op_sbc_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + 1); + op_sbc_w(); +} break; + +//adc_dpx +case 0x75: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readdp(dp + regs.x.w); + if(regs.p.m) { op_adc_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + regs.x.w + 1); + op_adc_w(); +} break; + +//and_dpx +case 0x35: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readdp(dp + regs.x.w); + if(regs.p.m) { op_and_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + regs.x.w + 1); + op_and_w(); +} break; + +//bit_dpx +case 0x34: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readdp(dp + regs.x.w); + if(regs.p.m) { op_bit_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + regs.x.w + 1); + op_bit_w(); +} break; + +//cmp_dpx +case 0xd5: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readdp(dp + regs.x.w); + if(regs.p.m) { op_cmp_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + regs.x.w + 1); + op_cmp_w(); +} break; + +//eor_dpx +case 0x55: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readdp(dp + regs.x.w); + if(regs.p.m) { op_eor_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + regs.x.w + 1); + op_eor_w(); +} break; + +//lda_dpx +case 0xb5: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readdp(dp + regs.x.w); + if(regs.p.m) { op_lda_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + regs.x.w + 1); + op_lda_w(); +} break; + +//ldy_dpx +case 0xb4: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + if(regs.p.x)last_cycle(); + rd.l = op_readdp(dp + regs.x.w); + if(regs.p.x) { op_ldy_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + regs.x.w + 1); + op_ldy_w(); +} break; + +//ora_dpx +case 0x15: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readdp(dp + regs.x.w); + if(regs.p.m) { op_ora_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + regs.x.w + 1); + op_ora_w(); +} break; + +//sbc_dpx +case 0xf5: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readdp(dp + regs.x.w); + if(regs.p.m) { op_sbc_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + regs.x.w + 1); + op_sbc_w(); +} break; + +//ldx_dpy +case 0xb6: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + if(regs.p.x)last_cycle(); + rd.l = op_readdp(dp + regs.y.w); + if(regs.p.x) { op_ldx_b(); break; } + last_cycle(); + rd.h = op_readdp(dp + regs.y.w + 1); + op_ldx_w(); +} break; + +//adc_idp +case 0x72: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_adc_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_adc_w(); +} break; + +//and_idp +case 0x32: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_and_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_and_w(); +} break; + +//cmp_idp +case 0xd2: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_cmp_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_cmp_w(); +} break; + +//eor_idp +case 0x52: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_eor_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_eor_w(); +} break; + +//lda_idp +case 0xb2: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_lda_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_lda_w(); +} break; + +//ora_idp +case 0x12: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_ora_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_ora_w(); +} break; + +//sbc_idp +case 0xf2: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_sbc_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_sbc_w(); +} break; + +//adc_idpx +case 0x61: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + aa.l = op_readdp(dp + regs.x.w); + aa.h = op_readdp(dp + regs.x.w + 1); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_adc_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_adc_w(); +} break; + +//and_idpx +case 0x21: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + aa.l = op_readdp(dp + regs.x.w); + aa.h = op_readdp(dp + regs.x.w + 1); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_and_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_and_w(); +} break; + +//cmp_idpx +case 0xc1: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + aa.l = op_readdp(dp + regs.x.w); + aa.h = op_readdp(dp + regs.x.w + 1); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_cmp_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_cmp_w(); +} break; + +//eor_idpx +case 0x41: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + aa.l = op_readdp(dp + regs.x.w); + aa.h = op_readdp(dp + regs.x.w + 1); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_eor_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_eor_w(); +} break; + +//lda_idpx +case 0xa1: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + aa.l = op_readdp(dp + regs.x.w); + aa.h = op_readdp(dp + regs.x.w + 1); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_lda_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_lda_w(); +} break; + +//ora_idpx +case 0x01: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + aa.l = op_readdp(dp + regs.x.w); + aa.h = op_readdp(dp + regs.x.w + 1); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_ora_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_ora_w(); +} break; + +//sbc_idpx +case 0xe1: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + aa.l = op_readdp(dp + regs.x.w); + aa.h = op_readdp(dp + regs.x.w + 1); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w); + if(regs.p.m) { op_sbc_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + 1); + op_sbc_w(); +} break; + +//adc_idpy +case 0x71: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + op_io_cond4(aa.w, aa.w + regs.y.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_adc_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_adc_w(); +} break; + +//and_idpy +case 0x31: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + op_io_cond4(aa.w, aa.w + regs.y.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_and_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_and_w(); +} break; + +//cmp_idpy +case 0xd1: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + op_io_cond4(aa.w, aa.w + regs.y.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_cmp_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_cmp_w(); +} break; + +//eor_idpy +case 0x51: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + op_io_cond4(aa.w, aa.w + regs.y.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_eor_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_eor_w(); +} break; + +//lda_idpy +case 0xb1: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + op_io_cond4(aa.w, aa.w + regs.y.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_lda_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_lda_w(); +} break; + +//ora_idpy +case 0x11: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + op_io_cond4(aa.w, aa.w + regs.y.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_ora_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_ora_w(); +} break; + +//sbc_idpy +case 0xf1: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + op_io_cond4(aa.w, aa.w + regs.y.w); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_sbc_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_sbc_w(); +} break; + +//adc_ildp +case 0x67: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d); + if(regs.p.m) { op_adc_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + 1); + op_adc_w(); +} break; + +//and_ildp +case 0x27: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d); + if(regs.p.m) { op_and_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + 1); + op_and_w(); +} break; + +//cmp_ildp +case 0xc7: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d); + if(regs.p.m) { op_cmp_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + 1); + op_cmp_w(); +} break; + +//eor_ildp +case 0x47: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d); + if(regs.p.m) { op_eor_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + 1); + op_eor_w(); +} break; + +//lda_ildp +case 0xa7: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d); + if(regs.p.m) { op_lda_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + 1); + op_lda_w(); +} break; + +//ora_ildp +case 0x07: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d); + if(regs.p.m) { op_ora_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + 1); + op_ora_w(); +} break; + +//sbc_ildp +case 0xe7: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d); + if(regs.p.m) { op_sbc_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + 1); + op_sbc_w(); +} break; + +//adc_ildpy +case 0x77: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d + regs.y.w); + if(regs.p.m) { op_adc_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + regs.y.w + 1); + op_adc_w(); +} break; + +//and_ildpy +case 0x37: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d + regs.y.w); + if(regs.p.m) { op_and_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + regs.y.w + 1); + op_and_w(); +} break; + +//cmp_ildpy +case 0xd7: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d + regs.y.w); + if(regs.p.m) { op_cmp_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + regs.y.w + 1); + op_cmp_w(); +} break; + +//eor_ildpy +case 0x57: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d + regs.y.w); + if(regs.p.m) { op_eor_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + regs.y.w + 1); + op_eor_w(); +} break; + +//lda_ildpy +case 0xb7: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d + regs.y.w); + if(regs.p.m) { op_lda_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + regs.y.w + 1); + op_lda_w(); +} break; + +//ora_ildpy +case 0x17: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d + regs.y.w); + if(regs.p.m) { op_ora_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + regs.y.w + 1); + op_ora_w(); +} break; + +//sbc_ildpy +case 0xf7: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); + if(regs.p.m)last_cycle(); + rd.l = op_readlong(aa.d + regs.y.w); + if(regs.p.m) { op_sbc_b(); break; } + last_cycle(); + rd.h = op_readlong(aa.d + regs.y.w + 1); + op_sbc_w(); +} break; + +//adc_sr +case 0x63: { + sp = op_readpc(); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readsp(sp); + if(regs.p.m) { op_adc_b(); break; } + last_cycle(); + rd.h = op_readsp(sp + 1); + op_adc_w(); +} break; + +//and_sr +case 0x23: { + sp = op_readpc(); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readsp(sp); + if(regs.p.m) { op_and_b(); break; } + last_cycle(); + rd.h = op_readsp(sp + 1); + op_and_w(); +} break; + +//cmp_sr +case 0xc3: { + sp = op_readpc(); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readsp(sp); + if(regs.p.m) { op_cmp_b(); break; } + last_cycle(); + rd.h = op_readsp(sp + 1); + op_cmp_w(); +} break; + +//eor_sr +case 0x43: { + sp = op_readpc(); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readsp(sp); + if(regs.p.m) { op_eor_b(); break; } + last_cycle(); + rd.h = op_readsp(sp + 1); + op_eor_w(); +} break; + +//lda_sr +case 0xa3: { + sp = op_readpc(); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readsp(sp); + if(regs.p.m) { op_lda_b(); break; } + last_cycle(); + rd.h = op_readsp(sp + 1); + op_lda_w(); +} break; + +//ora_sr +case 0x03: { + sp = op_readpc(); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readsp(sp); + if(regs.p.m) { op_ora_b(); break; } + last_cycle(); + rd.h = op_readsp(sp + 1); + op_ora_w(); +} break; + +//sbc_sr +case 0xe3: { + sp = op_readpc(); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readsp(sp); + if(regs.p.m) { op_sbc_b(); break; } + last_cycle(); + rd.h = op_readsp(sp + 1); + op_sbc_w(); +} break; + +//adc_isry +case 0x73: { + sp = op_readpc(); + op_io(); + aa.l = op_readsp(sp); + aa.h = op_readsp(sp + 1); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_adc_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_adc_w(); +} break; + +//and_isry +case 0x33: { + sp = op_readpc(); + op_io(); + aa.l = op_readsp(sp); + aa.h = op_readsp(sp + 1); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_and_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_and_w(); +} break; + +//cmp_isry +case 0xd3: { + sp = op_readpc(); + op_io(); + aa.l = op_readsp(sp); + aa.h = op_readsp(sp + 1); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_cmp_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_cmp_w(); +} break; + +//eor_isry +case 0x53: { + sp = op_readpc(); + op_io(); + aa.l = op_readsp(sp); + aa.h = op_readsp(sp + 1); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_eor_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_eor_w(); +} break; + +//lda_isry +case 0xb3: { + sp = op_readpc(); + op_io(); + aa.l = op_readsp(sp); + aa.h = op_readsp(sp + 1); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_lda_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_lda_w(); +} break; + +//ora_isry +case 0x13: { + sp = op_readpc(); + op_io(); + aa.l = op_readsp(sp); + aa.h = op_readsp(sp + 1); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_ora_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_ora_w(); +} break; + +//sbc_isry +case 0xf3: { + sp = op_readpc(); + op_io(); + aa.l = op_readsp(sp); + aa.h = op_readsp(sp + 1); + op_io(); + if(regs.p.m)last_cycle(); + rd.l = op_readdbr(aa.w + regs.y.w); + if(regs.p.m) { op_sbc_b(); break; } + last_cycle(); + rd.h = op_readdbr(aa.w + regs.y.w + 1); + op_sbc_w(); +} break; + +//bit_const +case 0x89: { + if(regs.p.m)last_cycle(); + rd.l = op_readpc(); + if(regs.p.m) { + regs.p.z = ((rd.l & regs.a.l) == 0); + break; + } + last_cycle(); + rd.h = op_readpc(); + regs.p.z = ((rd.w & regs.a.w) == 0); +} break; + diff --git a/src/cpu/scpu/core/op_rmw.b b/src/cpu/scpu/core/op_rmw.b new file mode 100644 index 00000000..d3b8b2f1 --- /dev/null +++ b/src/cpu/scpu/core/op_rmw.b @@ -0,0 +1,181 @@ +inc(0x1a, regs.p.m, a), +inx(0xe8, regs.p.x, x), +iny(0xc8, regs.p.x, y) { +1:last_cycle(); + op_io(); + if($1) { + regs.$2.l++; + regs.p.n = !!(regs.$2.l & 0x80); + regs.p.z = (regs.$2.l == 0); + } else { + regs.$2.w++; + regs.p.n = !!(regs.$2.w & 0x8000); + regs.p.z = (regs.$2.w == 0); + } +} + +dec(0x3a, regs.p.m, a), +dex(0xca, regs.p.x, x), +dey(0x88, regs.p.x, y) { +1:last_cycle(); + op_io(); + if($1) { + regs.$2.l--; + regs.p.n = !!(regs.$2.l & 0x80); + regs.p.z = (regs.$2.l == 0); + } else { + regs.$2.w--; + regs.p.n = !!(regs.$2.w & 0x8000); + regs.p.z = (regs.$2.w == 0); + } +} + +asl(0x0a) { +1:last_cycle(); + op_io(); + if(regs.p.m) { + regs.p.c = !!(regs.a.l & 0x80); + regs.a.l <<= 1; + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); + } else { + regs.p.c = !!(regs.a.w & 0x8000); + regs.a.w <<= 1; + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); + } +} + +lsr(0x4a) { +1:last_cycle(); + op_io(); + if(regs.p.m) { + regs.p.c = regs.a.l & 1; + regs.a.l >>= 1; + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); + } else { + regs.p.c = regs.a.w & 1; + regs.a.w >>= 1; + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); + } +} + +rol(0x2a) { +1:last_cycle(); + op_io(); + uint16 c = regs.p.c; + if(regs.p.m) { + regs.p.c = !!(regs.a.l & 0x80); + regs.a.l <<= 1; + regs.a.l |= c; + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); + } else { + regs.p.c = !!(regs.a.w & 0x8000); + regs.a.w <<= 1; + regs.a.w |= c; + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); + } +} + +ror(0x6a) { +1:last_cycle(); + op_io(); + uint16 c; + if(regs.p.m) { + c = (regs.p.c)?0x80:0; + regs.p.c = regs.a.l & 1; + regs.a.l >>= 1; + regs.a.l |= c; + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); + } else { + c = (regs.p.c)?0x8000:0; + regs.p.c = regs.a.w & 1; + regs.a.w >>= 1; + regs.a.w |= c; + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); + } +} + +inc_addr(0xee, inc), +dec_addr(0xce, dec), +asl_addr(0x0e, asl), +lsr_addr(0x4e, lsr), +rol_addr(0x2e, rol), +ror_addr(0x6e, ror), +trb_addr(0x1c, trb), +tsb_addr(0x0c, tsb) { +1:aa.l = op_readpc(); +2:aa.h = op_readpc(); +3:rd.l = op_readdbr(aa.w); +4:if(!regs.p.m)rd.h = op_readdbr(aa.w + 1); +5:op_io(); + if(regs.p.m) { op_$1_b(); } + else { op_$1_w(); +6:op_writedbr(aa.w + 1, rd.h); } +7:last_cycle(); + op_writedbr(aa.w, rd.l); +} + +inc_addrx(0xfe, inc), +dec_addrx(0xde, dec), +asl_addrx(0x1e, asl), +lsr_addrx(0x5e, lsr), +rol_addrx(0x3e, rol), +ror_addrx(0x7e, ror) { +1:aa.l = op_readpc(); +2:aa.h = op_readpc(); +3:op_io(); +4:rd.l = op_readdbr(aa.w + regs.x.w); +5:if(!regs.p.m)rd.h = op_readdbr(aa.w + regs.x.w + 1); +6:op_io(); + if(regs.p.m) { op_$1_b(); } + else { op_$1_w(); +7:op_writedbr(aa.w + regs.x.w + 1, rd.h); } +8:last_cycle(); + op_writedbr(aa.w + regs.x.w, rd.l); +} + +inc_dp(0xe6, inc), +dec_dp(0xc6, dec), +asl_dp(0x06, asl), +lsr_dp(0x46, lsr), +rol_dp(0x26, rol), +ror_dp(0x66, ror), +trb_dp(0x14, trb), +tsb_dp(0x04, tsb) { +1:dp = op_readpc(); +2:op_io_cond2(); +3:rd.l = op_readdp(dp); +4:if(!regs.p.m)rd.h = op_readdp(dp + 1); +5:op_io(); + if(regs.p.m) { op_$1_b(); } + else { op_$1_w(); +6:op_writedp(dp + 1, rd.h); } +7:last_cycle(); + op_writedp(dp, rd.l); +} + +inc_dpx(0xf6, inc), +dec_dpx(0xd6, dec), +asl_dpx(0x16, asl), +lsr_dpx(0x56, lsr), +rol_dpx(0x36, rol), +ror_dpx(0x76, ror) { +1:dp = op_readpc(); +2:op_io_cond2(); +3:op_io(); +4:rd.l = op_readdp(dp + regs.x.w); +5:if(!regs.p.m)rd.h = op_readdp(dp + regs.x.w + 1); +6:op_io(); + if(regs.p.m) { op_$1_b(); } + else { op_$1_w(); +7:op_writedp(dp + regs.x.w + 1, rd.h); } +8:last_cycle(); + op_writedp(dp + regs.x.w, rd.l); +} diff --git a/src/cpu/scpu/core/op_rmw.cpp b/src/cpu/scpu/core/op_rmw.cpp new file mode 100644 index 00000000..7924a1ab --- /dev/null +++ b/src/cpu/scpu/core/op_rmw.cpp @@ -0,0 +1,570 @@ +//inc +case 0x1a: { + last_cycle(); + op_io(); + if(regs.p.m) { + regs.a.l++; + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); + } else { + regs.a.w++; + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); + } +} break; + +//inx +case 0xe8: { + last_cycle(); + op_io(); + if(regs.p.x) { + regs.x.l++; + regs.p.n = !!(regs.x.l & 0x80); + regs.p.z = (regs.x.l == 0); + } else { + regs.x.w++; + regs.p.n = !!(regs.x.w & 0x8000); + regs.p.z = (regs.x.w == 0); + } +} break; + +//iny +case 0xc8: { + last_cycle(); + op_io(); + if(regs.p.x) { + regs.y.l++; + regs.p.n = !!(regs.y.l & 0x80); + regs.p.z = (regs.y.l == 0); + } else { + regs.y.w++; + regs.p.n = !!(regs.y.w & 0x8000); + regs.p.z = (regs.y.w == 0); + } +} break; + +//dec +case 0x3a: { + last_cycle(); + op_io(); + if(regs.p.m) { + regs.a.l--; + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); + } else { + regs.a.w--; + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); + } +} break; + +//dex +case 0xca: { + last_cycle(); + op_io(); + if(regs.p.x) { + regs.x.l--; + regs.p.n = !!(regs.x.l & 0x80); + regs.p.z = (regs.x.l == 0); + } else { + regs.x.w--; + regs.p.n = !!(regs.x.w & 0x8000); + regs.p.z = (regs.x.w == 0); + } +} break; + +//dey +case 0x88: { + last_cycle(); + op_io(); + if(regs.p.x) { + regs.y.l--; + regs.p.n = !!(regs.y.l & 0x80); + regs.p.z = (regs.y.l == 0); + } else { + regs.y.w--; + regs.p.n = !!(regs.y.w & 0x8000); + regs.p.z = (regs.y.w == 0); + } +} break; + +//asl +case 0x0a: { + last_cycle(); + op_io(); + if(regs.p.m) { + regs.p.c = !!(regs.a.l & 0x80); + regs.a.l <<= 1; + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); + } else { + regs.p.c = !!(regs.a.w & 0x8000); + regs.a.w <<= 1; + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); + } +} break; + +//lsr +case 0x4a: { + last_cycle(); + op_io(); + if(regs.p.m) { + regs.p.c = regs.a.l & 1; + regs.a.l >>= 1; + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); + } else { + regs.p.c = regs.a.w & 1; + regs.a.w >>= 1; + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); + } +} break; + +//rol +case 0x2a: { + last_cycle(); + op_io(); + uint16 c = regs.p.c; + if(regs.p.m) { + regs.p.c = !!(regs.a.l & 0x80); + regs.a.l <<= 1; + regs.a.l |= c; + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); + } else { + regs.p.c = !!(regs.a.w & 0x8000); + regs.a.w <<= 1; + regs.a.w |= c; + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); + } +} break; + +//ror +case 0x6a: { + last_cycle(); + op_io(); + uint16 c; + if(regs.p.m) { + c = (regs.p.c)?0x80:0; + regs.p.c = regs.a.l & 1; + regs.a.l >>= 1; + regs.a.l |= c; + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); + } else { + c = (regs.p.c)?0x8000:0; + regs.p.c = regs.a.w & 1; + regs.a.w >>= 1; + regs.a.w |= c; + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); + } +} break; + +//inc_addr +case 0xee: { + aa.l = op_readpc(); + aa.h = op_readpc(); + rd.l = op_readdbr(aa.w); + if(!regs.p.m)rd.h = op_readdbr(aa.w + 1); + op_io(); + if(regs.p.m) { op_inc_b(); } + else { op_inc_w(); + op_writedbr(aa.w + 1, rd.h); } + last_cycle(); + op_writedbr(aa.w, rd.l); +} break; + +//dec_addr +case 0xce: { + aa.l = op_readpc(); + aa.h = op_readpc(); + rd.l = op_readdbr(aa.w); + if(!regs.p.m)rd.h = op_readdbr(aa.w + 1); + op_io(); + if(regs.p.m) { op_dec_b(); } + else { op_dec_w(); + op_writedbr(aa.w + 1, rd.h); } + last_cycle(); + op_writedbr(aa.w, rd.l); +} break; + +//asl_addr +case 0x0e: { + aa.l = op_readpc(); + aa.h = op_readpc(); + rd.l = op_readdbr(aa.w); + if(!regs.p.m)rd.h = op_readdbr(aa.w + 1); + op_io(); + if(regs.p.m) { op_asl_b(); } + else { op_asl_w(); + op_writedbr(aa.w + 1, rd.h); } + last_cycle(); + op_writedbr(aa.w, rd.l); +} break; + +//lsr_addr +case 0x4e: { + aa.l = op_readpc(); + aa.h = op_readpc(); + rd.l = op_readdbr(aa.w); + if(!regs.p.m)rd.h = op_readdbr(aa.w + 1); + op_io(); + if(regs.p.m) { op_lsr_b(); } + else { op_lsr_w(); + op_writedbr(aa.w + 1, rd.h); } + last_cycle(); + op_writedbr(aa.w, rd.l); +} break; + +//rol_addr +case 0x2e: { + aa.l = op_readpc(); + aa.h = op_readpc(); + rd.l = op_readdbr(aa.w); + if(!regs.p.m)rd.h = op_readdbr(aa.w + 1); + op_io(); + if(regs.p.m) { op_rol_b(); } + else { op_rol_w(); + op_writedbr(aa.w + 1, rd.h); } + last_cycle(); + op_writedbr(aa.w, rd.l); +} break; + +//ror_addr +case 0x6e: { + aa.l = op_readpc(); + aa.h = op_readpc(); + rd.l = op_readdbr(aa.w); + if(!regs.p.m)rd.h = op_readdbr(aa.w + 1); + op_io(); + if(regs.p.m) { op_ror_b(); } + else { op_ror_w(); + op_writedbr(aa.w + 1, rd.h); } + last_cycle(); + op_writedbr(aa.w, rd.l); +} break; + +//trb_addr +case 0x1c: { + aa.l = op_readpc(); + aa.h = op_readpc(); + rd.l = op_readdbr(aa.w); + if(!regs.p.m)rd.h = op_readdbr(aa.w + 1); + op_io(); + if(regs.p.m) { op_trb_b(); } + else { op_trb_w(); + op_writedbr(aa.w + 1, rd.h); } + last_cycle(); + op_writedbr(aa.w, rd.l); +} break; + +//tsb_addr +case 0x0c: { + aa.l = op_readpc(); + aa.h = op_readpc(); + rd.l = op_readdbr(aa.w); + if(!regs.p.m)rd.h = op_readdbr(aa.w + 1); + op_io(); + if(regs.p.m) { op_tsb_b(); } + else { op_tsb_w(); + op_writedbr(aa.w + 1, rd.h); } + last_cycle(); + op_writedbr(aa.w, rd.l); +} break; + +//inc_addrx +case 0xfe: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io(); + rd.l = op_readdbr(aa.w + regs.x.w); + if(!regs.p.m)rd.h = op_readdbr(aa.w + regs.x.w + 1); + op_io(); + if(regs.p.m) { op_inc_b(); } + else { op_inc_w(); + op_writedbr(aa.w + regs.x.w + 1, rd.h); } + last_cycle(); + op_writedbr(aa.w + regs.x.w, rd.l); +} break; + +//dec_addrx +case 0xde: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io(); + rd.l = op_readdbr(aa.w + regs.x.w); + if(!regs.p.m)rd.h = op_readdbr(aa.w + regs.x.w + 1); + op_io(); + if(regs.p.m) { op_dec_b(); } + else { op_dec_w(); + op_writedbr(aa.w + regs.x.w + 1, rd.h); } + last_cycle(); + op_writedbr(aa.w + regs.x.w, rd.l); +} break; + +//asl_addrx +case 0x1e: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io(); + rd.l = op_readdbr(aa.w + regs.x.w); + if(!regs.p.m)rd.h = op_readdbr(aa.w + regs.x.w + 1); + op_io(); + if(regs.p.m) { op_asl_b(); } + else { op_asl_w(); + op_writedbr(aa.w + regs.x.w + 1, rd.h); } + last_cycle(); + op_writedbr(aa.w + regs.x.w, rd.l); +} break; + +//lsr_addrx +case 0x5e: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io(); + rd.l = op_readdbr(aa.w + regs.x.w); + if(!regs.p.m)rd.h = op_readdbr(aa.w + regs.x.w + 1); + op_io(); + if(regs.p.m) { op_lsr_b(); } + else { op_lsr_w(); + op_writedbr(aa.w + regs.x.w + 1, rd.h); } + last_cycle(); + op_writedbr(aa.w + regs.x.w, rd.l); +} break; + +//rol_addrx +case 0x3e: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io(); + rd.l = op_readdbr(aa.w + regs.x.w); + if(!regs.p.m)rd.h = op_readdbr(aa.w + regs.x.w + 1); + op_io(); + if(regs.p.m) { op_rol_b(); } + else { op_rol_w(); + op_writedbr(aa.w + regs.x.w + 1, rd.h); } + last_cycle(); + op_writedbr(aa.w + regs.x.w, rd.l); +} break; + +//ror_addrx +case 0x7e: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io(); + rd.l = op_readdbr(aa.w + regs.x.w); + if(!regs.p.m)rd.h = op_readdbr(aa.w + regs.x.w + 1); + op_io(); + if(regs.p.m) { op_ror_b(); } + else { op_ror_w(); + op_writedbr(aa.w + regs.x.w + 1, rd.h); } + last_cycle(); + op_writedbr(aa.w + regs.x.w, rd.l); +} break; + +//inc_dp +case 0xe6: { + dp = op_readpc(); + op_io_cond2(); + rd.l = op_readdp(dp); + if(!regs.p.m)rd.h = op_readdp(dp + 1); + op_io(); + if(regs.p.m) { op_inc_b(); } + else { op_inc_w(); + op_writedp(dp + 1, rd.h); } + last_cycle(); + op_writedp(dp, rd.l); +} break; + +//dec_dp +case 0xc6: { + dp = op_readpc(); + op_io_cond2(); + rd.l = op_readdp(dp); + if(!regs.p.m)rd.h = op_readdp(dp + 1); + op_io(); + if(regs.p.m) { op_dec_b(); } + else { op_dec_w(); + op_writedp(dp + 1, rd.h); } + last_cycle(); + op_writedp(dp, rd.l); +} break; + +//asl_dp +case 0x06: { + dp = op_readpc(); + op_io_cond2(); + rd.l = op_readdp(dp); + if(!regs.p.m)rd.h = op_readdp(dp + 1); + op_io(); + if(regs.p.m) { op_asl_b(); } + else { op_asl_w(); + op_writedp(dp + 1, rd.h); } + last_cycle(); + op_writedp(dp, rd.l); +} break; + +//lsr_dp +case 0x46: { + dp = op_readpc(); + op_io_cond2(); + rd.l = op_readdp(dp); + if(!regs.p.m)rd.h = op_readdp(dp + 1); + op_io(); + if(regs.p.m) { op_lsr_b(); } + else { op_lsr_w(); + op_writedp(dp + 1, rd.h); } + last_cycle(); + op_writedp(dp, rd.l); +} break; + +//rol_dp +case 0x26: { + dp = op_readpc(); + op_io_cond2(); + rd.l = op_readdp(dp); + if(!regs.p.m)rd.h = op_readdp(dp + 1); + op_io(); + if(regs.p.m) { op_rol_b(); } + else { op_rol_w(); + op_writedp(dp + 1, rd.h); } + last_cycle(); + op_writedp(dp, rd.l); +} break; + +//ror_dp +case 0x66: { + dp = op_readpc(); + op_io_cond2(); + rd.l = op_readdp(dp); + if(!regs.p.m)rd.h = op_readdp(dp + 1); + op_io(); + if(regs.p.m) { op_ror_b(); } + else { op_ror_w(); + op_writedp(dp + 1, rd.h); } + last_cycle(); + op_writedp(dp, rd.l); +} break; + +//trb_dp +case 0x14: { + dp = op_readpc(); + op_io_cond2(); + rd.l = op_readdp(dp); + if(!regs.p.m)rd.h = op_readdp(dp + 1); + op_io(); + if(regs.p.m) { op_trb_b(); } + else { op_trb_w(); + op_writedp(dp + 1, rd.h); } + last_cycle(); + op_writedp(dp, rd.l); +} break; + +//tsb_dp +case 0x04: { + dp = op_readpc(); + op_io_cond2(); + rd.l = op_readdp(dp); + if(!regs.p.m)rd.h = op_readdp(dp + 1); + op_io(); + if(regs.p.m) { op_tsb_b(); } + else { op_tsb_w(); + op_writedp(dp + 1, rd.h); } + last_cycle(); + op_writedp(dp, rd.l); +} break; + +//inc_dpx +case 0xf6: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + rd.l = op_readdp(dp + regs.x.w); + if(!regs.p.m)rd.h = op_readdp(dp + regs.x.w + 1); + op_io(); + if(regs.p.m) { op_inc_b(); } + else { op_inc_w(); + op_writedp(dp + regs.x.w + 1, rd.h); } + last_cycle(); + op_writedp(dp + regs.x.w, rd.l); +} break; + +//dec_dpx +case 0xd6: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + rd.l = op_readdp(dp + regs.x.w); + if(!regs.p.m)rd.h = op_readdp(dp + regs.x.w + 1); + op_io(); + if(regs.p.m) { op_dec_b(); } + else { op_dec_w(); + op_writedp(dp + regs.x.w + 1, rd.h); } + last_cycle(); + op_writedp(dp + regs.x.w, rd.l); +} break; + +//asl_dpx +case 0x16: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + rd.l = op_readdp(dp + regs.x.w); + if(!regs.p.m)rd.h = op_readdp(dp + regs.x.w + 1); + op_io(); + if(regs.p.m) { op_asl_b(); } + else { op_asl_w(); + op_writedp(dp + regs.x.w + 1, rd.h); } + last_cycle(); + op_writedp(dp + regs.x.w, rd.l); +} break; + +//lsr_dpx +case 0x56: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + rd.l = op_readdp(dp + regs.x.w); + if(!regs.p.m)rd.h = op_readdp(dp + regs.x.w + 1); + op_io(); + if(regs.p.m) { op_lsr_b(); } + else { op_lsr_w(); + op_writedp(dp + regs.x.w + 1, rd.h); } + last_cycle(); + op_writedp(dp + regs.x.w, rd.l); +} break; + +//rol_dpx +case 0x36: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + rd.l = op_readdp(dp + regs.x.w); + if(!regs.p.m)rd.h = op_readdp(dp + regs.x.w + 1); + op_io(); + if(regs.p.m) { op_rol_b(); } + else { op_rol_w(); + op_writedp(dp + regs.x.w + 1, rd.h); } + last_cycle(); + op_writedp(dp + regs.x.w, rd.l); +} break; + +//ror_dpx +case 0x76: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + rd.l = op_readdp(dp + regs.x.w); + if(!regs.p.m)rd.h = op_readdp(dp + regs.x.w + 1); + op_io(); + if(regs.p.m) { op_ror_b(); } + else { op_ror_w(); + op_writedp(dp + regs.x.w + 1, rd.h); } + last_cycle(); + op_writedp(dp + regs.x.w, rd.l); +} break; + diff --git a/src/cpu/scpu/core/op_write.b b/src/cpu/scpu/core/op_write.b new file mode 100644 index 00000000..a962d5d7 --- /dev/null +++ b/src/cpu/scpu/core/op_write.b @@ -0,0 +1,181 @@ +sta_addr(0x8d, regs.p.m, regs.a.w), +stx_addr(0x8e, regs.p.x, regs.x.w), +sty_addr(0x8c, regs.p.x, regs.y.w), +stz_addr(0x9c, regs.p.m, 0x0000) { +1:aa.l = op_readpc(); +2:aa.h = op_readpc(); +3:if($1)last_cycle(); + op_writedbr(aa.w, $2); + if($1)end; +4:last_cycle(); + op_writedbr(aa.w + 1, $2 >> 8); +} + +sta_addrx(0x9d, regs.p.m, regs.a.w), +stz_addrx(0x9e, regs.p.m, 0x0000) { +1:aa.l = op_readpc(); +2:aa.h = op_readpc(); +3:op_io_cond4(aa.w, aa.w + regs.x.w); +4:if($1)last_cycle(); + op_writedbr(aa.w + regs.x.w, $2); + if($1)end; +5:last_cycle(); + op_writedbr(aa.w + regs.x.w + 1, $2 >> 8); +} + +sta_addry(0x99) { +1:aa.l = op_readpc(); +2:aa.h = op_readpc(); +3:op_io_cond4(aa.w, aa.w + regs.y.w); +4:if(regs.p.m)last_cycle(); + op_writedbr(aa.w + regs.y.w, regs.a.l); + if(regs.p.m)end; +5:last_cycle(); + op_writedbr(aa.w + regs.y.w + 1, regs.a.h); +} + +sta_long(0x8f) { +1:aa.l = op_readpc(); +2:aa.h = op_readpc(); +3:aa.b = op_readpc(); +4:if(regs.p.m)last_cycle(); + op_writelong(aa.d, regs.a.l); + if(regs.p.m)end; +5:last_cycle(); + op_writelong(aa.d + 1, regs.a.h); +} + +sta_longx(0x9f) { +1:aa.l = op_readpc(); +2:aa.h = op_readpc(); +3:aa.b = op_readpc(); +4:if(regs.p.m)last_cycle(); + op_writelong(aa.d + regs.x.w, regs.a.l); + if(regs.p.m)end; +5:last_cycle(); + op_writelong(aa.d + regs.x.w + 1, regs.a.h); +} + +sta_dp(0x85, regs.p.m, regs.a.w), +stx_dp(0x86, regs.p.x, regs.x.w), +sty_dp(0x84, regs.p.x, regs.y.w), +stz_dp(0x64, regs.p.m, 0x0000) { +1:dp = op_readpc(); +2:op_io_cond2(); +3:if($1)last_cycle(); + op_writedp(dp, $2); + if($1)end; +4:last_cycle(); + op_writedp(dp + 1, $2 >> 8); +} + +sta_dpx(0x95, regs.p.m, regs.a.w), +sty_dpx(0x94, regs.p.x, regs.y.w), +stz_dpx(0x74, regs.p.m, 0x0000) { +1:dp = op_readpc(); +2:op_io_cond2(); +3:op_io(); +4:if($1)last_cycle(); + op_writedp(dp + regs.x.w, $2); + if($1)end; +5:last_cycle(); + op_writedp(dp + regs.x.w + 1, $2 >> 8); +} + +stx_dpy(0x96) { +1:dp = op_readpc(); +2:op_io_cond2(); +3:op_io(); +4:if(regs.p.x)last_cycle(); + op_writedp(dp + regs.y.w, regs.x.l); + if(regs.p.x)end; +5:last_cycle(); + op_writedp(dp + regs.y.w + 1, regs.x.h); +} + +sta_idp(0x92) { +1:dp = op_readpc(); +2:op_io_cond2(); +3:aa.l = op_readdp(dp); +4:aa.h = op_readdp(dp + 1); +5:if(regs.p.m)last_cycle(); + op_writedbr(aa.w, regs.a.l); + if(regs.p.m)end; +6:last_cycle(); + op_writedbr(aa.w + 1, regs.a.h); +} + +sta_ildp(0x87) { +1:dp = op_readpc(); +2:op_io_cond2(); +3:aa.l = op_readdp(dp); +4:aa.h = op_readdp(dp + 1); +5:aa.b = op_readdp(dp + 2); +6:if(regs.p.m)last_cycle(); + op_writelong(aa.d, regs.a.l); + if(regs.p.m)end; +7:last_cycle(); + op_writelong(aa.d + 1, regs.a.h); +} + +sta_idpx(0x81) { +1:dp = op_readpc(); +2:op_io_cond2(); +3:op_io(); +4:aa.l = op_readdp(dp + regs.x.w); +5:aa.h = op_readdp(dp + regs.x.w + 1); +6:if(regs.p.m)last_cycle(); + op_writedbr(aa.w, regs.a.l); + if(regs.p.m)end; +7:last_cycle(); + op_writedbr(aa.w + 1, regs.a.h); +} + +sta_idpy(0x91) { +1:dp = op_readpc(); +2:op_io_cond2(); +3:aa.l = op_readdp(dp); +4:aa.h = op_readdp(dp + 1); +5:op_io_cond4(aa.w, aa.w + regs.y.w); +6:if(regs.p.m)last_cycle(); + op_writedbr(aa.w + regs.y.w, regs.a.l); + if(regs.p.m)end; +7:last_cycle(); + op_writedbr(aa.w + regs.y.w + 1, regs.a.h); +} + +sta_ildpy(0x97) { +1:dp = op_readpc(); +2:op_io_cond2(); +3:aa.l = op_readdp(dp); +4:aa.h = op_readdp(dp + 1); +5:aa.b = op_readdp(dp + 2); +6:if(regs.p.m)last_cycle(); + op_writelong(aa.d + regs.y.w, regs.a.l); + if(regs.p.m)end; +7:last_cycle(); + op_writelong(aa.d + regs.y.w + 1, regs.a.h); +} + +sta_sr(0x83) { +1:sp = op_readpc(); +2:op_io(); +3:if(regs.p.m)last_cycle(); + op_writesp(sp, regs.a.l); + if(regs.p.m)end; +4:last_cycle(); + op_writesp(sp + 1, regs.a.h); +} + +sta_isry(0x93) { +1:sp = op_readpc(); +2:op_io(); +3:aa.l = op_readsp(sp); +4:aa.h = op_readsp(sp + 1); +5:op_io(); +6:if(regs.p.m)last_cycle(); + op_writedbr(aa.w + regs.y.w, regs.a.l); + if(regs.p.m)end; +7:last_cycle(); + op_writedbr(aa.w + regs.y.w + 1, regs.a.h); +} diff --git a/src/cpu/scpu/core/op_write.cpp b/src/cpu/scpu/core/op_write.cpp new file mode 100644 index 00000000..64cb6336 --- /dev/null +++ b/src/cpu/scpu/core/op_write.cpp @@ -0,0 +1,290 @@ +//sta_addr +case 0x8d: { + aa.l = op_readpc(); + aa.h = op_readpc(); + if(regs.p.m)last_cycle(); + op_writedbr(aa.w, regs.a.w); + if(regs.p.m)break; + last_cycle(); + op_writedbr(aa.w + 1, regs.a.w >> 8); +} break; + +//stx_addr +case 0x8e: { + aa.l = op_readpc(); + aa.h = op_readpc(); + if(regs.p.x)last_cycle(); + op_writedbr(aa.w, regs.x.w); + if(regs.p.x)break; + last_cycle(); + op_writedbr(aa.w + 1, regs.x.w >> 8); +} break; + +//sty_addr +case 0x8c: { + aa.l = op_readpc(); + aa.h = op_readpc(); + if(regs.p.x)last_cycle(); + op_writedbr(aa.w, regs.y.w); + if(regs.p.x)break; + last_cycle(); + op_writedbr(aa.w + 1, regs.y.w >> 8); +} break; + +//stz_addr +case 0x9c: { + aa.l = op_readpc(); + aa.h = op_readpc(); + if(regs.p.m)last_cycle(); + op_writedbr(aa.w, 0x0000); + if(regs.p.m)break; + last_cycle(); + op_writedbr(aa.w + 1, 0x0000 >> 8); +} break; + +//sta_addrx +case 0x9d: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.x.w); + if(regs.p.m)last_cycle(); + op_writedbr(aa.w + regs.x.w, regs.a.w); + if(regs.p.m)break; + last_cycle(); + op_writedbr(aa.w + regs.x.w + 1, regs.a.w >> 8); +} break; + +//stz_addrx +case 0x9e: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.x.w); + if(regs.p.m)last_cycle(); + op_writedbr(aa.w + regs.x.w, 0x0000); + if(regs.p.m)break; + last_cycle(); + op_writedbr(aa.w + regs.x.w + 1, 0x0000 >> 8); +} break; + +//sta_addry +case 0x99: { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.y.w); + if(regs.p.m)last_cycle(); + op_writedbr(aa.w + regs.y.w, regs.a.l); + if(regs.p.m)break; + last_cycle(); + op_writedbr(aa.w + regs.y.w + 1, regs.a.h); +} break; + +//sta_long +case 0x8f: { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); + if(regs.p.m)last_cycle(); + op_writelong(aa.d, regs.a.l); + if(regs.p.m)break; + last_cycle(); + op_writelong(aa.d + 1, regs.a.h); +} break; + +//sta_longx +case 0x9f: { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); + if(regs.p.m)last_cycle(); + op_writelong(aa.d + regs.x.w, regs.a.l); + if(regs.p.m)break; + last_cycle(); + op_writelong(aa.d + regs.x.w + 1, regs.a.h); +} break; + +//sta_dp +case 0x85: { + dp = op_readpc(); + op_io_cond2(); + if(regs.p.m)last_cycle(); + op_writedp(dp, regs.a.w); + if(regs.p.m)break; + last_cycle(); + op_writedp(dp + 1, regs.a.w >> 8); +} break; + +//stx_dp +case 0x86: { + dp = op_readpc(); + op_io_cond2(); + if(regs.p.x)last_cycle(); + op_writedp(dp, regs.x.w); + if(regs.p.x)break; + last_cycle(); + op_writedp(dp + 1, regs.x.w >> 8); +} break; + +//sty_dp +case 0x84: { + dp = op_readpc(); + op_io_cond2(); + if(regs.p.x)last_cycle(); + op_writedp(dp, regs.y.w); + if(regs.p.x)break; + last_cycle(); + op_writedp(dp + 1, regs.y.w >> 8); +} break; + +//stz_dp +case 0x64: { + dp = op_readpc(); + op_io_cond2(); + if(regs.p.m)last_cycle(); + op_writedp(dp, 0x0000); + if(regs.p.m)break; + last_cycle(); + op_writedp(dp + 1, 0x0000 >> 8); +} break; + +//sta_dpx +case 0x95: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + if(regs.p.m)last_cycle(); + op_writedp(dp + regs.x.w, regs.a.w); + if(regs.p.m)break; + last_cycle(); + op_writedp(dp + regs.x.w + 1, regs.a.w >> 8); +} break; + +//sty_dpx +case 0x94: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + if(regs.p.x)last_cycle(); + op_writedp(dp + regs.x.w, regs.y.w); + if(regs.p.x)break; + last_cycle(); + op_writedp(dp + regs.x.w + 1, regs.y.w >> 8); +} break; + +//stz_dpx +case 0x74: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + if(regs.p.m)last_cycle(); + op_writedp(dp + regs.x.w, 0x0000); + if(regs.p.m)break; + last_cycle(); + op_writedp(dp + regs.x.w + 1, 0x0000 >> 8); +} break; + +//stx_dpy +case 0x96: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + if(regs.p.x)last_cycle(); + op_writedp(dp + regs.y.w, regs.x.l); + if(regs.p.x)break; + last_cycle(); + op_writedp(dp + regs.y.w + 1, regs.x.h); +} break; + +//sta_idp +case 0x92: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + if(regs.p.m)last_cycle(); + op_writedbr(aa.w, regs.a.l); + if(regs.p.m)break; + last_cycle(); + op_writedbr(aa.w + 1, regs.a.h); +} break; + +//sta_ildp +case 0x87: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); + if(regs.p.m)last_cycle(); + op_writelong(aa.d, regs.a.l); + if(regs.p.m)break; + last_cycle(); + op_writelong(aa.d + 1, regs.a.h); +} break; + +//sta_idpx +case 0x81: { + dp = op_readpc(); + op_io_cond2(); + op_io(); + aa.l = op_readdp(dp + regs.x.w); + aa.h = op_readdp(dp + regs.x.w + 1); + if(regs.p.m)last_cycle(); + op_writedbr(aa.w, regs.a.l); + if(regs.p.m)break; + last_cycle(); + op_writedbr(aa.w + 1, regs.a.h); +} break; + +//sta_idpy +case 0x91: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + op_io_cond4(aa.w, aa.w + regs.y.w); + if(regs.p.m)last_cycle(); + op_writedbr(aa.w + regs.y.w, regs.a.l); + if(regs.p.m)break; + last_cycle(); + op_writedbr(aa.w + regs.y.w + 1, regs.a.h); +} break; + +//sta_ildpy +case 0x97: { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); + if(regs.p.m)last_cycle(); + op_writelong(aa.d + regs.y.w, regs.a.l); + if(regs.p.m)break; + last_cycle(); + op_writelong(aa.d + regs.y.w + 1, regs.a.h); +} break; + +//sta_sr +case 0x83: { + sp = op_readpc(); + op_io(); + if(regs.p.m)last_cycle(); + op_writesp(sp, regs.a.l); + if(regs.p.m)break; + last_cycle(); + op_writesp(sp + 1, regs.a.h); +} break; + +//sta_isry +case 0x93: { + sp = op_readpc(); + op_io(); + aa.l = op_readsp(sp); + aa.h = op_readsp(sp + 1); + op_io(); + if(regs.p.m)last_cycle(); + op_writedbr(aa.w + regs.y.w, regs.a.l); + if(regs.p.m)break; + last_cycle(); + op_writedbr(aa.w + regs.y.w + 1, regs.a.h); +} break; + diff --git a/src/cpu/scpu/core/opfn.cpp b/src/cpu/scpu/core/opfn.cpp new file mode 100644 index 00000000..d14252e2 --- /dev/null +++ b/src/cpu/scpu/core/opfn.cpp @@ -0,0 +1,377 @@ +//op_read +inline void sCPU::op_adc_b() { +int32 r = regs.a.l + rd.l + regs.p.c; + if(regs.p.d) { + uint8 n0 = (regs.a.l ) & 15; + uint8 n1 = (regs.a.l >> 4) & 15; + n0 += ((rd.l) & 15) + regs.p.c; + if(n0 > 9) { + n0 -= 10; + n0 &= 15; + n1++; + } + n1 += ((rd.l >> 4) & 15); + if(n1 > 9) { + n1 -= 10; + n1 &= 15; + regs.p.c = 1; + } else { + regs.p.c = 0; + } + r = (n1 << 4) | (n0); + } else { + r = regs.a.l + rd.l + regs.p.c; + regs.p.c = (r > 0xff); + } + regs.p.n = !!(r & 0x80); + regs.p.v = !!(~(regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80); + regs.p.z = ((uint8)r == 0); + regs.a.l = r; +} + +inline void sCPU::op_adc_w() { +int32 r; + if(regs.p.d) { + uint8 n0 = (regs.a.w ) & 15; + uint8 n1 = (regs.a.w >> 4) & 15; + uint8 n2 = (regs.a.w >> 8) & 15; + uint8 n3 = (regs.a.w >> 12) & 15; + n0 += ((rd.w) & 15) + regs.p.c; + if(n0 > 9) { + n0 -= 10; + n0 &= 15; + n1++; + } + n1 += ((rd.w >> 4) & 15); + if(n1 > 9) { + n1 -= 10; + n1 &= 15; + n2++; + } + n2 += ((rd.w >> 8) & 15); + if(n2 > 9) { + n2 -= 10; + n2 &= 15; + n3++; + } + n3 += ((rd.w >> 12) & 15); + if(n3 > 9) { + n3 -= 10; + n3 &= 15; + regs.p.c = 1; + } else { + regs.p.c = 0; + } + r = (n3 << 12) | (n2 << 8) | (n1 << 4) | (n0); + } else { + r = regs.a.w + rd.w + regs.p.c; + regs.p.c = (r > 0xffff); + } + regs.p.n = !!(r & 0x8000); + regs.p.v = !!(~(regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000); + regs.p.z = ((uint16)r == 0); + regs.a.w = r; +} + +inline void sCPU::op_and_b() { + regs.a.l &= rd.l; + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); +} + +inline void sCPU::op_and_w() { + regs.a.w &= rd.w; + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); +} + +inline void sCPU::op_bit_b() { + regs.p.n = !!(rd.l & 0x80); + regs.p.v = !!(rd.l & 0x40); + regs.p.z = ((rd.l & regs.a.l) == 0); +} + +inline void sCPU::op_bit_w() { + regs.p.n = !!(rd.w & 0x8000); + regs.p.v = !!(rd.w & 0x4000); + regs.p.z = ((rd.w & regs.a.w) == 0); +} + +inline void sCPU::op_cmp_b() { +int32 r = regs.a.l - rd.l; + regs.p.n = !!(r & 0x80); + regs.p.z = ((uint8)r == 0); + regs.p.c = (r >= 0); +} + +inline void sCPU::op_cmp_w() { +int32 r = regs.a.w - rd.w; + regs.p.n = !!(r & 0x8000); + regs.p.z = ((uint16)r == 0); + regs.p.c = (r >= 0); +} + +inline void sCPU::op_cpx_b() { +int32 r = regs.x.l - rd.l; + regs.p.n = !!(r & 0x80); + regs.p.z = ((uint8)r == 0); + regs.p.c = (r >= 0); +} + +inline void sCPU::op_cpx_w() { +int32 r = regs.x.w - rd.w; + regs.p.n = !!(r & 0x8000); + regs.p.z = ((uint16)r == 0); + regs.p.c = (r >= 0); +} + +inline void sCPU::op_cpy_b() { +int32 r = regs.y.l - rd.l; + regs.p.n = !!(r & 0x80); + regs.p.z = ((uint8)r == 0); + regs.p.c = (r >= 0); +} + +inline void sCPU::op_cpy_w() { +int32 r = regs.y.w - rd.w; + regs.p.n = !!(r & 0x8000); + regs.p.z = ((uint16)r == 0); + regs.p.c = (r >= 0); +} + +inline void sCPU::op_eor_b() { + regs.a.l ^= rd.l; + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); +} + +inline void sCPU::op_eor_w() { + regs.a.w ^= rd.w; + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); +} + +inline void sCPU::op_lda_b() { + regs.a.l = rd.l; + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); +} + +inline void sCPU::op_lda_w() { + regs.a.w = rd.w; + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); +} + +inline void sCPU::op_ldx_b() { + regs.x.l = rd.l; + regs.p.n = !!(regs.x.l & 0x80); + regs.p.z = (regs.x.l == 0); +} + +inline void sCPU::op_ldx_w() { + regs.x.w = rd.w; + regs.p.n = !!(regs.x.w & 0x8000); + regs.p.z = (regs.x.w == 0); +} + +inline void sCPU::op_ldy_b() { + regs.y.l = rd.l; + regs.p.n = !!(regs.y.l & 0x80); + regs.p.z = (regs.y.l == 0); +} + +inline void sCPU::op_ldy_w() { + regs.y.w = rd.w; + regs.p.n = !!(regs.y.w & 0x8000); + regs.p.z = (regs.y.w == 0); +} + +inline void sCPU::op_ora_b() { + regs.a.l |= rd.l; + regs.p.n = !!(regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); +} + +inline void sCPU::op_ora_w() { + regs.a.w |= rd.w; + regs.p.n = !!(regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); +} + +inline void sCPU::op_sbc_b() { +int32 r; + if(regs.p.d) { + uint8 n0 = (regs.a.l ) & 15; + uint8 n1 = (regs.a.l >> 4) & 15; + n0 -= ((rd.l ) & 15) + !regs.p.c; + n1 -= ((rd.l >> 4) & 15); + if(n0 > 9) { + n0 += 10; + n1--; + } + if(n1 > 9) { + n1 += 10; + regs.p.c = 0; + } else { + regs.p.c = 1; + } + r = (n1 << 4) | (n0); + } else { + r = regs.a.l - rd.l - !regs.p.c; + regs.p.c = (r >= 0); + } + regs.p.n = !!(r & 0x80); + regs.p.v = !!((regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80); + regs.p.z = ((uint8)r == 0); + regs.a.l = r; +} + +inline void sCPU::op_sbc_w() { +int32 r; + if(regs.p.d) { + uint8 n0 = (regs.a.w ) & 15; + uint8 n1 = (regs.a.w >> 4) & 15; + uint8 n2 = (regs.a.w >> 8) & 15; + uint8 n3 = (regs.a.w >> 12) & 15; + n0 -= ((rd.w ) & 15) + !regs.p.c; + n1 -= ((rd.w >> 4) & 15); + n2 -= ((rd.w >> 8) & 15); + n3 -= ((rd.w >> 12) & 15); + if(n0 > 9) { + n0 += 10; + n1--; + } + if(n1 > 9) { + n1 += 10; + n2--; + } + if(n2 > 9) { + n2 += 10; + n3--; + } + if(n3 > 9) { + n3 += 10; + regs.p.c = 0; + } else { + regs.p.c = 1; + } + r = (n3 << 12) | (n2 << 8) | (n1 << 4) | (n0); + } else { + r = regs.a.w - rd.w - !regs.p.c; + regs.p.c = (r >= 0); + } + regs.p.n = !!(r & 0x8000); + regs.p.v = !!((regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000); + regs.p.z = ((uint16)r == 0); + regs.a.w = r; +} + +//op_rmw +inline void sCPU::op_inc_b() { + rd.l++; + regs.p.n = !!(rd.l & 0x80); + regs.p.z = (rd.l == 0); +} + +inline void sCPU::op_inc_w() { + rd.w++; + regs.p.n = !!(rd.w & 0x8000); + regs.p.z = (rd.w == 0); +} + +inline void sCPU::op_dec_b() { + rd.l--; + regs.p.n = !!(rd.l & 0x80); + regs.p.z = (rd.l == 0); +} + +inline void sCPU::op_dec_w() { + rd.w--; + regs.p.n = !!(rd.w & 0x8000); + regs.p.z = (rd.w == 0); +} + +inline void sCPU::op_asl_b() { + regs.p.c = !!(rd.l & 0x80); + rd.l <<= 1; + regs.p.n = !!(rd.l & 0x80); + regs.p.z = (rd.l == 0); +} + +inline void sCPU::op_asl_w() { + regs.p.c = !!(rd.w & 0x8000); + rd.w <<= 1; + regs.p.n = !!(rd.w & 0x8000); + regs.p.z = (rd.w == 0); +} + +inline void sCPU::op_lsr_b() { + regs.p.c = rd.l & 1; + rd.l >>= 1; + regs.p.n = !!(rd.l & 0x80); + regs.p.z = (rd.l == 0); +} + +inline void sCPU::op_lsr_w() { + regs.p.c = rd.w & 1; + rd.w >>= 1; + regs.p.n = !!(rd.w & 0x8000); + regs.p.z = (rd.w == 0); +} + +inline void sCPU::op_rol_b() { +uint16 c = regs.p.c; + regs.p.c = !!(rd.l & 0x80); + rd.l <<= 1; + rd.l |= c; + regs.p.n = !!(rd.l & 0x80); + regs.p.z = (rd.l == 0); +} + +inline void sCPU::op_rol_w() { +uint16 c = regs.p.c; + regs.p.c = !!(rd.w & 0x8000); + rd.w <<= 1; + rd.w |= c; + regs.p.n = !!(rd.w & 0x8000); + regs.p.z = (rd.w == 0); +} + +inline void sCPU::op_ror_b() { +uint16 c = (regs.p.c)?0x80:0; + regs.p.c = rd.l & 1; + rd.l >>= 1; + rd.l |= c; + regs.p.n = !!(rd.l & 0x80); + regs.p.z = (rd.l == 0); +} + +inline void sCPU::op_ror_w() { +uint16 c = (regs.p.c)?0x8000:0; + regs.p.c = rd.w & 1; + rd.w >>= 1; + rd.w |= c; + regs.p.n = !!(rd.w & 0x8000); + regs.p.z = (rd.w == 0); +} + +inline void sCPU::op_trb_b() { + regs.p.z = ((rd.l & regs.a.l) == 0); + rd.l &= ~regs.a.l; +} + +inline void sCPU::op_trb_w() { + regs.p.z = ((rd.w & regs.a.w) == 0); + rd.w &= ~regs.a.w; +} + +inline void sCPU::op_tsb_b() { + regs.p.z = ((rd.l & regs.a.l) == 0); + rd.l |= regs.a.l; +} + +inline void sCPU::op_tsb_w() { + regs.p.z = ((rd.w & regs.a.w) == 0); + rd.w |= regs.a.w; +} diff --git a/src/cpu/scpu/core/scpugen.cpp b/src/cpu/scpu/core/scpugen.cpp new file mode 100644 index 00000000..2047cecd --- /dev/null +++ b/src/cpu/scpu/core/scpugen.cpp @@ -0,0 +1,18 @@ +#define CLASS_NAME "sCPU" +#include "../../../lib/opgen_s.cpp" + +int main() { +//fph = fopen("op.h", "wb"); +//fpt = fopen("optable.cpp", "wb"); + + generate("op_read.cpp", "op_read.b"); + generate("op_write.cpp", "op_write.b"); + generate("op_rmw.cpp", "op_rmw.b"); + generate("op_pc.cpp", "op_pc.b"); + generate("op_misc.cpp", "op_misc.b"); + +//fclose(fph); +//fclose(fpt); + + return 0; +} diff --git a/src/cpu/scpu/dma/dma.cpp b/src/cpu/scpu/dma/dma.cpp new file mode 100644 index 00000000..fdb3838d --- /dev/null +++ b/src/cpu/scpu/dma/dma.cpp @@ -0,0 +1,252 @@ +/***** + * used by both DMA and HDMA + * prevents transfer across same bus (a->a or b->b) + * + * DMA address bus a cannot read from or write to the following addresses : + * $[00-3f|80-bf]:21[00-ff]
+ * $[00-3f|80-bf]:43[00-7f] + * $[00-3f|80-bf]:420b + * $[00-3f|80-bf]:420c + * + * DMA address bus b cannot read from $2180 + *****/ +void sCPU::dma_transfer(bool direction, uint8 bbus, uint32 abus) { +uint8 r; + if(direction == 0) { //a->b + if((abus & 0x40ff00) == 0x2100 || (abus & 0x40ff80) == 0x4300 || + (abus & 0x40ffff) == 0x420b || (abus & 0x40ffff) == 0x420c) { + r = r_cpu->regs.mdr; //invalid reads return open bus + } else { + r = r_mem->read(abus); + } + r_mem->write(0x2100 | bbus, r); + } else { //b->a + uint8 r = (bbus == 0x80) ? r_cpu->regs.mdr : r_mem->read(0x2100 | bbus); + if((abus & 0x40ff00) == 0x2100 || (abus & 0x40ff80) == 0x4300 || + (abus & 0x40ffff) == 0x420b || (abus & 0x40ffff) == 0x420c)return; + r_mem->write(abus, r); + } + + add_clocks(8); + co_return(); + cycle_edge(); +} + +/***** + * address calculation functions + *****/ + +uint8 sCPU::dma_bbus(uint8 i, uint8 index) { + switch(channel[i].xfermode) { + default: + case 0: return (channel[i].destaddr); break; //0 + case 1: return (channel[i].destaddr + (index & 1)); break; //0,1 + case 2: return (channel[i].destaddr); break; //0,0 + case 3: return (channel[i].destaddr + ((index >> 1) & 1)); break; //0,0,1,1 + case 4: return (channel[i].destaddr + (index & 3)); break; //0,1,2,3 + case 5: return (channel[i].destaddr + (index & 1)); break; //0,1,0,1 + case 6: return (channel[i].destaddr); break; //0,0 [2] + case 7: return (channel[i].destaddr + ((index >> 1) & 1)); break; //0,0,1,1 [3] + } +} + +uint32 sCPU::dma_addr(uint8 i) { +uint32 r = (channel[i].srcbank << 16) | (channel[i].srcaddr); + + if(channel[i].fixedxfer == false) { + if(channel[i].reversexfer == false) { + channel[i].srcaddr++; + } else { + channel[i].srcaddr--; + } + } + + return r; +} + +uint32 sCPU::hdma_addr(uint8 i) { + return (channel[i].srcbank << 16) | (channel[i].hdma_addr++); +} + +uint32 sCPU::hdma_iaddr(uint8 i) { + return (channel[i].hdma_ibank << 16) | (channel[i].hdma_iaddr++); +} + +/***** + * DMA functions + *****/ + +void sCPU::dma_transfertobusb(uint8 i, uint8 bbus) { + if(cartridge.cart.sdd1 == true && sdd1->dma_active() == true) { + r_mem->write(0x2100 | bbus, sdd1->dma_read()); + } else { + dma_transfer(0, bbus, dma_addr(i)); + } + channel[i].xfersize--; +} + +void sCPU::dma_transfertobusa(uint8 i, uint8 bbus) { + dma_transfer(1, bbus, dma_addr(i)); + channel[i].xfersize--; +} + +void sCPU::dma_write(uint8 i, uint8 index) { +//cannot use dma_transfer() directly, +//due to current S-DD1 implementation + if(channel[i].direction == 0) { + dma_transfertobusb(i, index); + } else { + dma_transfertobusa(i, index); + } +} + +void sCPU::dma_run() { + add_clocks(18); + + for(int i = 0; i < 8; i++) { + if(channel[i].dma_enabled == false)continue; + + if(cartridge.cart.sdd1 == true) { + sdd1->dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr), + channel[i].xfersize); + } + + uint index = 0; + do { + dma_write(i, dma_bbus(i, index++)); + } while(channel[i].xfersize); + + channel[i].dma_enabled = false; + } +} + +/***** + * HDMA functions + *****/ + +bool sCPU::hdma_active(uint8 i) { + return (channel[i].hdma_enabled && !channel[i].hdma_completed); +} + +uint8 sCPU::hdma_enabled_channels() { +uint8 r = 0; + for(int i = 0; i < 8; i++) { + if(channel[i].hdma_enabled)r++; + } + return r; +} + +uint8 sCPU::hdma_active_channels() { +uint8 r = 0; + for(int i = 0; i < 8; i++) { + if(hdma_active(i) == true)r++; + } + return r; +} + +void sCPU::hdma_update(uint8 i) { + channel[i].hdma_line_counter = r_mem->read(hdma_addr(i)); + add_clocks(8); + + if(channel[i].hdma_indirect) { + channel[i].hdma_iaddr = r_mem->read(hdma_addr(i)) << 8; + add_clocks(8); + } + + if(channel[i].hdma_line_counter == 0) { + channel[i].hdma_completed = true; + channel[i].hdma_do_transfer = false; + return; + } + + channel[i].hdma_do_transfer = true; + + if(channel[i].hdma_indirect) { + channel[i].hdma_iaddr >>= 8; + channel[i].hdma_iaddr |= r_mem->read(hdma_addr(i)) << 8; + add_clocks(8); + } +} + +void sCPU::hdma_run() { + if(hdma_active_channels() == 0)return; + + add_clocks(18); + +static uint8 hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 }; + for(int i = 0; i < 8; i++) { + if(hdma_active(i) == false)continue; + + if(channel[i].hdma_do_transfer) { + int xferlen = hdma_xferlen[channel[i].xfermode]; + for(int index = 0; index < xferlen; index++) { + if(bool(config::cpu.hdma_enable) == true) { + dma_transfer(channel[i].direction, dma_bbus(i, index), + !channel[i].hdma_indirect ? hdma_addr(i) : hdma_iaddr(i)); + } else { + add_clocks(8); + co_return(); + cycle_edge(); + } + } + } + + channel[i].hdma_line_counter--; + channel[i].hdma_do_transfer = bool(channel[i].hdma_line_counter & 0x80); + if((channel[i].hdma_line_counter & 0x7f) == 0) { + hdma_update(i); + } + } +} + +void sCPU::hdma_init() { + for(int i = 0; i < 8; i++) { + channel[i].hdma_completed = false; + channel[i].hdma_do_transfer = false; + } + + if(hdma_enabled_channels() == 0)return; + + add_clocks(18); + + for(int i = 0; i < 8; i++) { + if(!channel[i].hdma_enabled)continue; + + channel[i].hdma_addr = channel[i].srcaddr; + hdma_update(i); + } +} + +/***** + * power / reset functions + *****/ + +void sCPU::dma_reset() { + for(int i = 0; i < 8; i++) { + channel[i].dma_enabled = false; + channel[i].hdma_enabled = false; + + channel[i].dmap = 0xff; + channel[i].direction = 1; + channel[i].hdma_indirect = true; + channel[i].reversexfer = true; + channel[i].fixedxfer = true; + channel[i].xfermode = 7; + + channel[i].destaddr = 0xff; + + channel[i].srcaddr = 0xffff; + channel[i].srcbank = 0xff; + + channel[i].xfersize = 0xffff; + //channel[i].hdma_iaddr = 0xffff; //union with xfersize + channel[i].hdma_ibank = 0xff; + + channel[i].hdma_addr = 0xffff; + channel[i].hdma_line_counter = 0xff; + channel[i].unknown = 0xff; + + channel[i].hdma_completed = false; + channel[i].hdma_do_transfer = false; + } +} diff --git a/src/cpu/scpu/dma/dma.h b/src/cpu/scpu/dma/dma.h new file mode 100644 index 00000000..fa8fc6f4 --- /dev/null +++ b/src/cpu/scpu/dma/dma.h @@ -0,0 +1,67 @@ +struct { +//$420b + bool dma_enabled; + +//$420c + bool hdma_enabled; + +//$43x0 + uint8 dmap; + bool direction; + bool hdma_indirect; + bool reversexfer; + bool fixedxfer; + uint8 xfermode; + +//$43x1 + uint8 destaddr; + +//$43x2-$43x3 + uint16 srcaddr; + +//$43x4 + uint8 srcbank; + +//$43x5-$43x6 + union { + uint16 xfersize; + uint16 hdma_iaddr; + }; + +//$43x7 + uint8 hdma_ibank; + +//$43x8-$43x9 + uint16 hdma_addr; + +//$43xa + uint8 hdma_line_counter; + +//$43xb/$43xf + uint8 unknown; + +//internal variables + bool hdma_completed; + bool hdma_do_transfer; +} channel[8]; + + void dma_transfer(bool direction, uint8 bbus, uint32 abus); + + uint8 dma_bbus(uint8 i, uint8 index); + uint32 dma_addr(uint8 i); + uint32 hdma_addr(uint8 i); + uint32 hdma_iaddr(uint8 i); + + void dma_transfertobusb(uint8 i, uint8 bbus); + void dma_transfertobusa(uint8 i, uint8 bbus); + void dma_write(uint8 i, uint8 index); + void dma_run(); + + bool hdma_active(uint8 i); + uint8 hdma_enabled_channels(); + uint8 hdma_active_channels(); + void hdma_update(uint8 i); + void hdma_run(); + void hdma_init(); + + void dma_reset(); diff --git a/src/cpu/scpu/memory/memory.cpp b/src/cpu/scpu/memory/memory.cpp new file mode 100644 index 00000000..c48de22e --- /dev/null +++ b/src/cpu/scpu/memory/memory.cpp @@ -0,0 +1,38 @@ +/***** + * These 3 functions control bus timing for the CPU. + * cpu_io is an I/O cycle, and always 6 clock cycles long. + * mem_read / mem_write indicate memory access bus cycles. + * they are either 6, 8, or 12 bus cycles long, depending + * both on location and the $420d.d0 FastROM enable bit. + *****/ + +void sCPU::op_io() { + status.clock_count = 6; + add_clocks(6); +//co_return(); + cycle_edge(); +} + +uint8 sCPU::op_read(uint32 addr) { + status.clock_count = r_mem->speed(addr); + add_clocks(status.clock_count - 4); +#ifdef FAVOR_ACCURACY + co_return(); +#endif + regs.mdr = r_mem->read(addr); + add_clocks(4); + cycle_edge(); + return regs.mdr; +} + +void sCPU::op_write(uint32 addr, uint8 data) { + status.clock_count = r_mem->speed(addr); + add_clocks(status.clock_count); +#ifdef FAVOR_ACCURACY + co_return(); +#endif +//below needs to be verified on hardware +//regs.mdr = data; + r_mem->write(addr, data); + cycle_edge(); +} diff --git a/src/cpu/scpu/memory/memory.h b/src/cpu/scpu/memory/memory.h new file mode 100644 index 00000000..96e9592b --- /dev/null +++ b/src/cpu/scpu/memory/memory.h @@ -0,0 +1,33 @@ +/***** + * CPU<>APU communication ports + *****/ +uint8 apu_port[4]; + uint8 port_read (uint8 port) { return apu_port[port & 3]; } + void port_write(uint8 port, uint8 data) { apu_port[port & 3] = data; } + +/***** + * core CPU bus functions + *****/ + void op_io(); + uint8 op_read (uint32 addr); + void op_write(uint32 addr, uint8 data); + +/***** + * helper memory addressing functions used by CPU core + *****/ + uint8 op_readpc () { return op_read((regs.pc.b << 16) + regs.pc.w++); } + uint8 op_readstack() { (regs.e) ? regs.s.l++ : regs.s.w++; return op_read(regs.s.w); } + uint8 op_readaddr (uint32 addr) { return op_read(uclip<16>(addr)); } + uint8 op_readlong (uint32 addr) { return op_read(uclip<24>(addr)); } + uint8 op_readdbr (uint32 addr) { return op_read(uclip<24>((regs.db << 16) + addr)); } + uint8 op_readpbr (uint32 addr) { return op_read((regs.pc.b << 16) + uclip<16>(addr)); } + uint8 op_readdp (uint32 addr) { return op_read(uclip<16>(regs.d + uclip<16>(addr))); } + uint8 op_readsp (uint32 addr) { return op_read(uclip<16>(regs.s + uclip<16>(addr))); } + + void op_writestack(uint8 data) { op_write(regs.s.w, data); (regs.e) ? regs.s.l-- : regs.s.w--; } + void op_writeaddr (uint32 addr, uint8 data) { op_write(uclip<16>(addr), data); } + void op_writelong (uint32 addr, uint8 data) { op_write(uclip<24>(addr), data); } + void op_writedbr (uint32 addr, uint8 data) { op_write(uclip<24>((regs.db << 16) + addr), data); } + void op_writepbr (uint32 addr, uint8 data) { op_write((regs.pc.b << 16) + uclip<16>(addr), data); } + void op_writedp (uint32 addr, uint8 data) { op_write(uclip<16>(regs.d + uclip<16>(addr)), data); } + void op_writesp (uint32 addr, uint8 data) { op_write(uclip<16>(regs.s + uclip<16>(addr)), data); } diff --git a/src/cpu/scpu/mmio/mmio.cpp b/src/cpu/scpu/mmio/mmio.cpp new file mode 100644 index 00000000..7d15c294 --- /dev/null +++ b/src/cpu/scpu/mmio/mmio.cpp @@ -0,0 +1,669 @@ +uint8 sCPU::pio_status() { + return status.pio; +} + +/***** + * WRAM data registers + *****/ + +//WMDATA +uint8 sCPU::mmio_r2180() { +uint8 r = r_mem->read(0x7e0000 | status.wram_addr++); + status.wram_addr &= 0x01ffff; + return r; +} + +//WMDATA +void sCPU::mmio_w2180(uint8 data) { + r_mem->write(0x7e0000 | status.wram_addr++, data); + status.wram_addr &= 0x01ffff; +} + +//WMADDL +void sCPU::mmio_w2181(uint8 data) { + status.wram_addr = (status.wram_addr & 0xffff00) | (data); + status.wram_addr &= 0x01ffff; +} + +//WMADDM +void sCPU::mmio_w2182(uint8 data) { + status.wram_addr = (status.wram_addr & 0xff00ff) | (data << 8); + status.wram_addr &= 0x01ffff; +} + +//WMADDH +void sCPU::mmio_w2183(uint8 data) { + status.wram_addr = (status.wram_addr & 0x00ffff) | (data << 16); + status.wram_addr &= 0x01ffff; +} + +/***** + * Joypad registers + *****/ + +//JOYSER0 +//7-2 = MDR +//1-0 = Joypad serial data +/***** + * The joypad contains a small bit shifter that has 16 bits. + * Reading from 4016 reads one bit from this buffer, then moves + * the buffer left one, and adds a '1' to the rightmost bit. + * Writing a one to $4016 will fill the buffer with the current + * joypad button states, and lock the bit shifter at position + * zero. All reads will be the first buffer state, or 'B'. + * A zero must be written back to $4016 to unlock the buffer, + * so that reads will increment the bit shifting position. + *****/ +uint8 sCPU::mmio_r4016() { +uint8 r = regs.mdr & 0xfc; + if(status.joypad_strobe_latch == 1) { + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_B)); + } else { + switch(status.joypad1_read_pos) { + case 0: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_B)); break; + case 1: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_Y)); break; + case 2: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_SELECT)); break; + case 3: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_START)); break; + case 4: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_UP)); break; + case 5: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_DOWN)); break; + case 6: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_LEFT)); break; + case 7: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_RIGHT)); break; + case 8: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_A)); break; + case 9: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_X)); break; + case 10: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_L)); break; + case 11: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_R)); break; + case 12: break; + case 13: break; + case 14: break; + case 15: break; //bits 12-15 always return 0 + //all subsequent reads return joypad connection status + case 16: r |= 1; break; //joypad connected bit + } + if(++status.joypad1_read_pos > 16)status.joypad1_read_pos = 16; + } + + return r; +} + +//JOYSER1 +//7-5 = MDR +//4-2 = Always 1 (pins are connected to GND) +//1-0 = Joypad serial data +uint8 sCPU::mmio_r4017() { +uint8 r = (regs.mdr & 0xe0) | 0x1c; + if(status.joypad_strobe_latch == 1) { + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_B)); + } else { + switch(status.joypad2_read_pos) { + case 0: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_B)); break; + case 1: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_Y)); break; + case 2: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_SELECT)); break; + case 3: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_START)); break; + case 4: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_UP)); break; + case 5: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_DOWN)); break; + case 6: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_LEFT)); break; + case 7: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_RIGHT)); break; + case 8: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_A)); break; + case 9: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_X)); break; + case 10: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_L)); break; + case 11: r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_R)); break; + case 12: break; + case 13: break; + case 14: break; + case 15: break; //bits 12-15 always return 0 + //all subsequent reads return joypad connection status + case 16: r |= 1; break; //joypad connected bit + } + if(++status.joypad2_read_pos > 16)status.joypad2_read_pos = 16; + } + + return r; +} + +//JOY1L +//TODO: handle reads during joypad polling (v=225-227) +uint8 sCPU::mmio_r4218() { +uint8 r = 0x00; + if(status.auto_joypad_poll == false)return 0x00; //can't read joypad if auto polling not enabled + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_A)) << 7; + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_X)) << 6; + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_L)) << 5; + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_R)) << 4; + return r; +} + +//JOY1H +uint8 sCPU::mmio_r4219() { +uint8 r = 0x00; + if(status.auto_joypad_poll == false)return 0x00; //can't read joypad if auto polling not enabled + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_B)) << 7; + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_Y)) << 6; + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_SELECT)) << 5; + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_START)) << 4; + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_UP)) << 3; + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_DOWN)) << 2; + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_LEFT)) << 1; + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_RIGHT)); + return r; +} + +//JOY2L +uint8 sCPU::mmio_r421a() { +uint8 r = 0x00; + if(status.auto_joypad_poll == false)return 0x00; //can't read joypad if auto polling not enabled + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_A)) << 7; + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_X)) << 6; + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_L)) << 5; + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_R)) << 4; + return r; +} + +//JOY2H +uint8 sCPU::mmio_r421b() { +uint8 r = 0x00; + if(status.auto_joypad_poll == false)return 0x00; //can't read joypad if auto polling not enabled + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_B)) << 7; + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_Y)) << 6; + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_SELECT)) << 5; + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_START)) << 4; + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_UP)) << 3; + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_DOWN)) << 2; + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_LEFT)) << 1; + r |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_RIGHT)); + return r; +} + +//JOYSER0 +//bit 0 is shared between JOYSER0 and JOYSER1, therefore +//strobing $4016.d0 affects both controller port latches. +//$4017 bit 0 writes are ignored. +void sCPU::mmio_w4016(uint8 data) { + status.joypad_strobe_latch = bool(data & 1); + + if(status.joypad_strobe_latch == 1) { + snes->poll_input(SNES::DEV_JOYPAD1); + snes->poll_input(SNES::DEV_JOYPAD2); + status.joypad1_read_pos = 0; + status.joypad2_read_pos = 0; + } +} + +/***** + * NMI / IRQ registers + *****/ + +//RDNMI +//7 = NMI acknowledge +//6-4 = MDR +//3-0 = CPU (5a22) version +uint8 sCPU::mmio_r4210() { +uint8 r = (regs.mdr & 0x70); + r |= uint8(!status.nmi_read) << 7; + + if(!nmi_read_pos_match(0) && !nmi_read_pos_match(2)) { + status.nmi_read = 1; + } + + r |= (cpu_version & 0x0f); + return r; +} + +//TIMEUP +//7 = IRQ acknowledge +//6-0 = MDR +uint8 sCPU::mmio_r4211() { +uint8 r = (regs.mdr & 0x7f); + r |= uint8(!status.irq_read) << 7; + + if(!irq_read_pos_match(0) && !irq_read_pos_match(2)) { + status.irq_read = 1; + status.irq_line = 1; + status.irq_transition = 0; + } + + return r; +} + +//HVBJOY +//7 = VBLANK acknowledge +//6 = HBLANK acknowledge +//5-1 = MDR +//0 = JOYPAD acknowledge +uint8 sCPU::mmio_r4212() { +uint8 r = (regs.mdr & 0x3e); +uint16 vs = !overscan() ? 225 : 240; + +//auto joypad polling + if(status.hclock >= vs && status.hclock <= (vs + 2))r |= 0x01; + +//hblank + if(status.hclock <= 2 || status.hclock >= 1096)r |= 0x40; + +//vblank + if(status.vcounter >= vs)r |= 0x80; + + return r; +} + +//NMITIMEN +void sCPU::mmio_w4200(uint8 data) { + status.nmi_enabled = bool(data & 0x80); + status.virq_enabled = bool(data & 0x20); + status.hirq_enabled = bool(data & 0x10); + status.auto_joypad_poll = bool(data & 0x01); + + if(status.nmi_read == 0) { + if(status.nmi_line == 1 && !status.nmi_enabled == 0) { + status.nmi_transition = 1; + } + status.nmi_line = !status.nmi_enabled; + } + + if(status.virq_enabled == false && status.hirq_enabled == false) { + status.irq_line = 1; + status.irq_read = 1; + status.irq_transition = 0; + } + + update_interrupts(); +} + +//HTIMEL +void sCPU::mmio_w4207(uint8 data) { + status.hirq_pos = (status.hirq_pos & 0xff00) | (data); + update_interrupts(); +} + +//HTIMEH +void sCPU::mmio_w4208(uint8 data) { + status.hirq_pos = (status.hirq_pos & 0x00ff) | (data << 8); + update_interrupts(); +} + +//VTIMEL +void sCPU::mmio_w4209(uint8 data) { + status.virq_pos = (status.virq_pos & 0xff00) | (data); + update_interrupts(); +} + +//VTIMEH +void sCPU::mmio_w420a(uint8 data) { + status.virq_pos = (status.virq_pos & 0x00ff) | (data << 8); + update_interrupts(); +} + +/***** + * I/O registers + ****/ + +//RDIO +uint8 sCPU::mmio_r4213() { + return status.pio; +} + +//WRIO +void sCPU::mmio_w4201(uint8 data) { + if((status.pio & 0x80) && !(data & 0x80)) { + r_ppu->latch_counters(); + } + status.pio = data; +} + +/***** + * Math registers (multiplication and division) + *****/ + +//RDDIVL +uint8 sCPU::mmio_r4214() { + return status.r4214; +} + +//RDDIVH +uint8 sCPU::mmio_r4215() { + return status.r4214 >> 8; +} + +//RDMPYL +uint8 sCPU::mmio_r4216() { + return status.r4216; +} + +//RDMPYH +uint8 sCPU::mmio_r4217() { + return status.r4216 >> 8; +} + +//WRMPYA +void sCPU::mmio_w4202(uint8 data) { + status.mul_a = data; +} + +//WRMPYB +void sCPU::mmio_w4203(uint8 data) { + status.mul_b = data; + status.r4216 = status.mul_a * status.mul_b; +} + +//WRDIVL +void sCPU::mmio_w4204(uint8 data) { + status.div_a = (status.div_a & 0xff00) | (data); +} + +//WRDIVH +void sCPU::mmio_w4205(uint8 data) { + status.div_a = (status.div_a & 0x00ff) | (data << 8); +} + +//WRDIVB +void sCPU::mmio_w4206(uint8 data) { + status.div_b = data; + status.r4214 = (status.div_b) ? status.div_a / status.div_b : 0xffff; + status.r4216 = (status.div_b) ? status.div_a % status.div_b : status.div_a; +} + +/***** + * DMA / HDMA registers + *****/ + +//DMAPx +uint8 sCPU::mmio_r43x0(uint8 i) { + return channel[i].dmap; +} + +//BBADx +uint8 sCPU::mmio_r43x1(uint8 i) { + return channel[i].destaddr; +} + +//A1TxL +uint8 sCPU::mmio_r43x2(uint8 i) { + return channel[i].srcaddr; +} + +//A1TxH +uint8 sCPU::mmio_r43x3(uint8 i) { + return channel[i].srcaddr >> 8; +} + +//A1Bx +uint8 sCPU::mmio_r43x4(uint8 i) { + return channel[i].srcbank; +} + +//DASxL +//union { uint16 xfersize; uint16 hdma_iaddr; }; +uint8 sCPU::mmio_r43x5(uint8 i) { + return channel[i].xfersize; +} + +//DASxH +//union { uint16 xfersize; uint16 hdma_iaddr; }; +uint8 sCPU::mmio_r43x6(uint8 i) { + return channel[i].xfersize >> 8; +} + +//DASBx +uint8 sCPU::mmio_r43x7(uint8 i) { + return channel[i].hdma_ibank; +} + +//A2AxL +uint8 sCPU::mmio_r43x8(uint8 i) { + return channel[i].hdma_addr; +} + +//A2AxH +uint8 sCPU::mmio_r43x9(uint8 i) { + return channel[i].hdma_addr >> 8; +} + +//NTRLx +uint8 sCPU::mmio_r43xa(uint8 i) { + return channel[i].hdma_line_counter; +} + +//??? +uint8 sCPU::mmio_r43xb(uint8 i) { + return channel[i].unknown; +} + +//DMAEN +//Note: DMA enable does not disable active HDMA channels +void sCPU::mmio_w420b(uint8 data) { + for(int i = 0; i < 8; i++) { + channel[i].dma_enabled = bool(data & (1 << i)); + } + if(data)dma_run(); //temporary +} + +//HDMAEN +void sCPU::mmio_w420c(uint8 data) { + for(int i = 0; i < 8; i++) { + channel[i].hdma_enabled = bool(data & (1 << i)); + } +} + +//MEMSEL +void sCPU::mmio_w420d(uint8 data) { + r_mem->set_speed(data & 1); +} + +//DMAPx +void sCPU::mmio_w43x0(uint8 i, uint8 data) { + channel[i].dmap = data; + channel[i].direction = bool(data & 0x80); + channel[i].hdma_indirect = bool(data & 0x40); + channel[i].reversexfer = bool(data & 0x10); + channel[i].fixedxfer = bool(data & 0x08); + channel[i].xfermode = data & 7; +} + +//DDBADx +void sCPU::mmio_w43x1(uint8 i, uint8 data) { + channel[i].destaddr = data; +} + +//A1TxL +void sCPU::mmio_w43x2(uint8 i, uint8 data) { + channel[i].srcaddr = (channel[i].srcaddr & 0xff00) | (data); +} + +//A1TxH +void sCPU::mmio_w43x3(uint8 i, uint8 data) { + channel[i].srcaddr = (channel[i].srcaddr & 0x00ff) | (data << 8); +} + +//A1Bx +void sCPU::mmio_w43x4(uint8 i, uint8 data) { + channel[i].srcbank = data; +} + +//DASxL +//union { uint16 xfersize; uint16 hdma_iaddr; }; +void sCPU::mmio_w43x5(uint8 i, uint8 data) { + channel[i].xfersize = (channel[i].xfersize & 0xff00) | (data); +} + +//DASxH +//union { uint16 xfersize; uint16 hdma_iaddr; }; +void sCPU::mmio_w43x6(uint8 i, uint8 data) { + channel[i].xfersize = (channel[i].xfersize & 0x00ff) | (data << 8); +} + +//DASBx +void sCPU::mmio_w43x7(uint8 i, uint8 data) { + channel[i].hdma_ibank = data; +} + +//A2AxL +void sCPU::mmio_w43x8(uint8 i, uint8 data) { + channel[i].hdma_addr = (channel[i].hdma_addr & 0xff00) | (data); +} + +//A2AxH +void sCPU::mmio_w43x9(uint8 i, uint8 data) { + channel[i].hdma_addr = (channel[i].hdma_addr & 0x00ff) | (data << 8); +} + +//NTRLx +void sCPU::mmio_w43xa(uint8 i, uint8 data) { + channel[i].hdma_line_counter = data; +} + +//??? +void sCPU::mmio_w43xb(uint8 i, uint8 data) { + channel[i].unknown = data; +} + +/***** + * reset / read / write + *****/ + +void sCPU::mmio_reset() { +//$2181-$2183 + status.wram_addr = 0x000000; + +//$4016-$4017 + status.joypad_strobe_latch = 0; + status.joypad1_read_pos = 0; + status.joypad2_read_pos = 0; + +//$4200 + status.nmi_enabled = false; + status.hirq_enabled = false; + status.virq_enabled = false; + status.auto_joypad_poll = false; + +//$4201 + status.pio = 0xff; + +//$4202-$4203 + status.mul_a = 0xff; + status.mul_b = 0xff; + +//$4204-$4206 + status.div_a = 0xffff; + status.div_b = 0xff; + +//$4207-$420a + status.hirq_pos = 0x01ff; + status.virq_pos = 0x01ff; + +//$4214-$4217 + status.r4214 = 0x0000; + status.r4216 = 0x0000; +} + +uint8 sCPU::mmio_read(uint16 addr) { +//APU + if((addr & 0xffc0) == 0x2140) { //$2140-$217f + #ifdef FAVOR_SPEED + co_return(); + #endif + return r_apu->port_read(addr & 3); + } + +//DMA + if((addr & 0xff80) == 0x4300) { //$4300-$437f + uint i = (addr >> 4) & 7; + switch(addr & 0xf) { + case 0x0: return mmio_r43x0(i); + case 0x1: return mmio_r43x1(i); + case 0x2: return mmio_r43x2(i); + case 0x3: return mmio_r43x3(i); + case 0x4: return mmio_r43x4(i); + case 0x5: return mmio_r43x5(i); + case 0x6: return mmio_r43x6(i); + case 0x7: return mmio_r43x7(i); + case 0x8: return mmio_r43x8(i); + case 0x9: return mmio_r43x9(i); + case 0xa: return mmio_r43xa(i); + case 0xb: return mmio_r43xb(i); + case 0xc: return regs.mdr; //unmapped + case 0xd: return regs.mdr; //unmapped + case 0xe: return regs.mdr; //unmapped + case 0xf: return mmio_r43xb(i); //mirror of $43xb + } + } + + switch(addr) { + case 0x2180: return mmio_r2180(); + case 0x4016: return mmio_r4016(); + case 0x4017: return mmio_r4017(); + case 0x4210: return mmio_r4210(); + case 0x4211: return mmio_r4211(); + case 0x4212: return mmio_r4212(); + case 0x4213: return mmio_r4213(); + case 0x4214: return mmio_r4214(); + case 0x4215: return mmio_r4215(); + case 0x4216: return mmio_r4216(); + case 0x4217: return mmio_r4217(); + case 0x4218: return mmio_r4218(); + case 0x4219: return mmio_r4219(); + case 0x421a: return mmio_r421a(); + case 0x421b: return mmio_r421b(); + case 0x421c: return 0x00; + case 0x421d: return 0x00; + case 0x421e: return 0x00; + case 0x421f: return 0x00; + } + + return regs.mdr; +} + +void sCPU::mmio_write(uint16 addr, uint8 data) { +//APU + if((addr & 0xffc0) == 0x2140) { //$2140-$217f + #ifdef FAVOR_SPEED + co_return(); + #endif + port_write(addr & 3, data); + return; + } + +//DMA + if((addr & 0xff80) == 0x4300) { //$4300-$437f + uint i = (addr >> 4) & 7; + switch(addr & 0xf) { + case 0x0: mmio_w43x0(i, data); return; + case 0x1: mmio_w43x1(i, data); return; + case 0x2: mmio_w43x2(i, data); return; + case 0x3: mmio_w43x3(i, data); return; + case 0x4: mmio_w43x4(i, data); return; + case 0x5: mmio_w43x5(i, data); return; + case 0x6: mmio_w43x6(i, data); return; + case 0x7: mmio_w43x7(i, data); return; + case 0x8: mmio_w43x8(i, data); return; + case 0x9: mmio_w43x9(i, data); return; + case 0xa: mmio_w43xa(i, data); return; + case 0xb: mmio_w43xb(i, data); return; + case 0xc: return; //unmapped + case 0xd: return; //unmapped + case 0xe: return; //unmapped + case 0xf: mmio_w43xb(i, data); return; //mirror of $43xb + } + } + + switch(addr) { + case 0x2180: mmio_w2180(data); return; + case 0x2181: mmio_w2181(data); return; + case 0x2182: mmio_w2182(data); return; + case 0x2183: mmio_w2183(data); return; + case 0x4016: mmio_w4016(data); return; + case 0x4017: return; //unmapped + case 0x4200: mmio_w4200(data); return; + case 0x4201: mmio_w4201(data); return; + case 0x4202: mmio_w4202(data); return; + case 0x4203: mmio_w4203(data); return; + case 0x4204: mmio_w4204(data); return; + case 0x4205: mmio_w4205(data); return; + case 0x4206: mmio_w4206(data); return; + case 0x4207: mmio_w4207(data); return; + case 0x4208: mmio_w4208(data); return; + case 0x4209: mmio_w4209(data); return; + case 0x420a: mmio_w420a(data); return; + case 0x420b: mmio_w420b(data); return; + case 0x420c: mmio_w420c(data); return; + case 0x420d: mmio_w420d(data); return; + } +} diff --git a/src/cpu/scpu/mmio/mmio.h b/src/cpu/scpu/mmio/mmio.h new file mode 100644 index 00000000..5de8a113 --- /dev/null +++ b/src/cpu/scpu/mmio/mmio.h @@ -0,0 +1,65 @@ + void mmio_reset(); + uint8 mmio_read (uint16 addr); + void mmio_write(uint16 addr, uint8 data); + + uint8 pio_status(); + + uint8 mmio_r2180(); + uint8 mmio_r4016(); + uint8 mmio_r4017(); + uint8 mmio_r4210(); + uint8 mmio_r4211(); + uint8 mmio_r4212(); + uint8 mmio_r4213(); + uint8 mmio_r4214(); + uint8 mmio_r4215(); + uint8 mmio_r4216(); + uint8 mmio_r4217(); + uint8 mmio_r4218(); + uint8 mmio_r4219(); + uint8 mmio_r421a(); + uint8 mmio_r421b(); + uint8 mmio_r43x0(uint8 i); + uint8 mmio_r43x1(uint8 i); + uint8 mmio_r43x2(uint8 i); + uint8 mmio_r43x3(uint8 i); + uint8 mmio_r43x4(uint8 i); + uint8 mmio_r43x5(uint8 i); + uint8 mmio_r43x6(uint8 i); + uint8 mmio_r43x7(uint8 i); + uint8 mmio_r43x8(uint8 i); + uint8 mmio_r43x9(uint8 i); + uint8 mmio_r43xa(uint8 i); + uint8 mmio_r43xb(uint8 i); + + void mmio_w2180(uint8 data); + void mmio_w2181(uint8 data); + void mmio_w2182(uint8 data); + void mmio_w2183(uint8 data); + void mmio_w4016(uint8 data); + void mmio_w4200(uint8 data); + void mmio_w4201(uint8 data); + void mmio_w4202(uint8 data); + void mmio_w4203(uint8 data); + void mmio_w4204(uint8 data); + void mmio_w4205(uint8 data); + void mmio_w4206(uint8 data); + void mmio_w4207(uint8 data); + void mmio_w4208(uint8 data); + void mmio_w4209(uint8 data); + void mmio_w420a(uint8 data); + void mmio_w420b(uint8 data); + void mmio_w420c(uint8 data); + void mmio_w420d(uint8 data); + void mmio_w43x0(uint8 i, uint8 data); + void mmio_w43x1(uint8 i, uint8 data); + void mmio_w43x2(uint8 i, uint8 data); + void mmio_w43x3(uint8 i, uint8 data); + void mmio_w43x4(uint8 i, uint8 data); + void mmio_w43x5(uint8 i, uint8 data); + void mmio_w43x6(uint8 i, uint8 data); + void mmio_w43x7(uint8 i, uint8 data); + void mmio_w43x8(uint8 i, uint8 data); + void mmio_w43x9(uint8 i, uint8 data); + void mmio_w43xa(uint8 i, uint8 data); + void mmio_w43xb(uint8 i, uint8 data); diff --git a/src/cpu/scpu/scpu.cpp b/src/cpu/scpu/scpu.cpp new file mode 100644 index 00000000..0f4cedcf --- /dev/null +++ b/src/cpu/scpu/scpu.cpp @@ -0,0 +1,64 @@ +#include "../../base.h" + +#include "core/core.cpp" +#include "dma/dma.cpp" +#include "memory/memory.cpp" +#include "mmio/mmio.cpp" +#include "timing/timing.cpp" + +void scpu_entry_point() { + r_cpu->main(); +} + +void sCPU::run() { + co_call(thread); +} + +void sCPU::power() { + status.region = bool(snes->region()); + + regs.a = regs.x = regs.y = 0x0000; + regs.s = 0x01ff; + reset(); +} + +void sCPU::reset() { + if(thread)co_delete(thread); + thread = co_create(scpu_entry_point, 65536); + + regs.pc.d = 0x000000; + regs.pc.l = r_mem->read(0xfffc); + regs.pc.h = r_mem->read(0xfffd); + +//some registers are not fully reset by SNES + regs.x.h = 0x00; + regs.y.h = 0x00; + regs.s.h = 0x01; + regs.d = 0x0000; + regs.db = 0x00; + regs.p = 0x34; + regs.e = 1; + regs.mdr = 0x00; + + event.wai = false; + event.irq = false; + event.irq_vector = 0xfffc; //reset vector address + + mmio_reset(); + dma_reset(); + timing_reset(); + + apu_port[0] = 0x00; + apu_port[1] = 0x00; + apu_port[2] = 0x00; + apu_port[3] = 0x00; +} + +sCPU::sCPU() { +//#include "core/optable.cpp" + thread = 0; +} + +sCPU::~sCPU() { + if(thread)co_delete(thread); +} diff --git a/src/cpu/scpu/scpu.h b/src/cpu/scpu/scpu.h new file mode 100644 index 00000000..cf00c438 --- /dev/null +++ b/src/cpu/scpu/scpu.h @@ -0,0 +1,84 @@ +class sCPU : public CPU { +public: +#include "core/core.h" +#include "dma/dma.h" +#include "memory/memory.h" +#include "mmio/mmio.h" +#include "timing/timing.h" + +thread_t thread; + +struct { + bool wai; + bool irq; + uint16 irq_vector; +} event; + +struct { +//core + uint8 opcode; + bool in_opcode; + + uint clock_count; + uint clocks_executed; + +//timing + bool region; + uint16 region_scanlines; + uint16 vcounter, hcounter, hclock; + bool interlace, interlace_field; + bool overscan; + uint16 field_lines, line_clocks; + + bool line_rendered; + bool dram_refreshed; + bool hdmainit_triggered; + bool hdma_triggered; + + int16 nmi_read_pos, nmi_line_pos; + bool nmi_read, nmi_line, nmi_transition; + bool nmi_pending; + + int16 irq_read_pos, irq_line_pos; + bool irq_read, irq_line, irq_transition; + bool irq_pending; + +//mmio + +//$2181-$2183 + uint32 wram_addr; + +//$4016-$4017 + bool joypad_strobe_latch; + uint8 joypad1_read_pos, joypad2_read_pos; + +//$4200 + bool nmi_enabled; + bool hirq_enabled, virq_enabled; + bool auto_joypad_poll; + +//$4201 + uint8 pio; + +//$4202-$4203 + uint8 mul_a, mul_b; + +//$4204-$4206 + uint16 div_a; + uint8 div_b; + +//$4207-$420a + uint16 hirq_pos, virq_pos; + +//$4214-$4217 + uint16 r4214; + uint16 r4216; +} status; + + void run(); + void power(); + void reset(); + + sCPU(); + ~sCPU(); +}; diff --git a/src/cpu/scpu/timing/irq.cpp b/src/cpu/scpu/timing/irq.cpp new file mode 100644 index 00000000..187bf015 --- /dev/null +++ b/src/cpu/scpu/timing/irq.cpp @@ -0,0 +1,162 @@ +void sCPU::update_interrupts() { + if(status.vcounter == (!overscan() ? 225 : 240)) { + status.nmi_read_pos = 2; + status.nmi_line_pos = 6; + } else { + status.nmi_read_pos = -64; + status.nmi_line_pos = -64; + } + + if(irq_pos_valid() == false) { + status.irq_read_pos = -64; + status.irq_line_pos = -64; + return; + } + +uint vpos = status.virq_pos; +uint hpos = (status.hirq_enabled) ? status.hirq_pos : 0; + hpos = (hpos != 0) ? ((hpos << 2) + 14) : 10; + if(hpos >= status.line_clocks) { + hpos -= status.line_clocks; + if(++vpos >= status.field_lines) { + vpos = 0; + } + } + + if((status.virq_enabled == true && status.vcounter == vpos) || status.virq_enabled == false) { + status.irq_read_pos = hpos; + } else { + status.irq_read_pos = -64; + } + + hpos += 4; + if(hpos >= status.line_clocks) { + hpos -= status.line_clocks; + if(++vpos >= status.field_lines) { + vpos = 0; + } + } + + if((status.virq_enabled == true && status.vcounter == vpos) || status.virq_enabled == false) { + status.irq_line_pos = hpos; + } else { + status.irq_line_pos = -64; + } +} + +void sCPU::poll_interrupts(int clocks) { +int16 start, end; + if(status.hclock == 0) { + start = -1; + end = clocks; + } else { + start = status.hclock; + end = status.hclock + clocks; + } + +//NMI read test + if(start < status.nmi_read_pos && status.nmi_read_pos <= end) { + //nmi_read lowers even when NMI interrupts are disabled via $4200.d7 + status.nmi_read = 0; + } + +//NMI line test + if(start < status.nmi_line_pos && status.nmi_line_pos <= end) { + if(status.nmi_enabled == true) { + if(status.nmi_line == 1) { + status.nmi_transition = 1; + } + status.nmi_line = 0; + } + } + +//IRQ read test + if(start < status.irq_read_pos && status.irq_read_pos <= end) { + if(status.virq_enabled == true || status.hirq_enabled == true) { + status.irq_read = 0; + } + } + +//IRQ line test + if(start < status.irq_line_pos && status.irq_line_pos <= end) { + if(status.virq_enabled == true || status.hirq_enabled == true) { + status.irq_line = 0; + status.irq_transition = 1; + } + } +} + +bool sCPU::nmi_read_pos_match(uint offset) { +uint16 v = !overscan() ? 225 : 240; +uint16 h = 2 + offset; + return (status.vcounter == v && status.hclock == h); +} + +bool sCPU::irq_read_pos_match(uint offset) { + if(irq_pos_valid() == false)return false; + +uint vpos = status.virq_pos; +uint hpos = (status.hirq_enabled) ? status.hirq_pos : 0; + hpos = (hpos != 0) ? ((hpos << 2) + 14) : 10; + hpos += offset; + if(hpos >= status.line_clocks) { + hpos -= status.line_clocks; + if(++vpos >= status.field_lines) { + vpos = 0; + } + } + + if((status.virq_enabled == true && status.vcounter == vpos) || status.virq_enabled == false) { + return (status.hclock == hpos); + } + + return false; +} + +bool sCPU::irq_pos_valid() { +uint vpos = status.virq_pos; +uint hpos = (status.hirq_enabled) ? status.hirq_pos : 0; +uint vlimit = region_scanlines() >> 1; +//positions that can never be latched +//vlimit = 262/NTSC, 312/PAL +//PAL results are unverified on hardware + if(vpos == 240 && hpos == 339 && interlace() == false && interlace_field() == 1)return false; + if(vpos == (vlimit - 1) && hpos == 339 && interlace() == false)return false; + if(vpos == vlimit && interlace() == false)return false; + if(vpos == vlimit && hpos == 339)return false; + if(vpos > vlimit)return false; + if(hpos > 339)return false; + + return true; +} + +bool sCPU::nmi_test() { + if(status.nmi_transition == 0)return false; + + status.nmi_transition = 0; + event.wai = false; + return true; +} + +bool sCPU::irq_test() { + if(status.irq_transition == 1)goto irq_trigger; + + if(status.irq_read == 0) { + if(status.irq_line == 1 && (irq_read_pos_match(0) || irq_read_pos_match(2))) { + return false; + } + goto irq_trigger; + } + + if(status.irq_line == 0) { + status.irq_line = 1; + goto irq_trigger; + } + + return false; + +irq_trigger: + status.irq_transition = 0; + event.wai = false; + return (regs.p.i) ? false : true; +} diff --git a/src/cpu/scpu/timing/timing.cpp b/src/cpu/scpu/timing/timing.cpp new file mode 100644 index 00000000..f2b43980 --- /dev/null +++ b/src/cpu/scpu/timing/timing.cpp @@ -0,0 +1,206 @@ +#define ntsc_color_burst_phase_shift_scanline() \ + (status.region == SNES::NTSC && status.vcounter == 240 && \ + status.interlace == false && status.interlace_field == 1) + +#include "irq.cpp" + +uint16 sCPU::vcounter() { return status.vcounter; } +uint16 sCPU::hcycles() { return status.hclock; } + +bool sCPU::interlace() { return status.interlace; } +bool sCPU::interlace_field() { return status.interlace_field; } +bool sCPU::overscan() { return status.overscan; } +uint16 sCPU::region_scanlines() { return status.region_scanlines; } + +void sCPU::set_interlace(bool r) { status.interlace = r; update_interrupts(); } +void sCPU::set_overscan (bool r) { status.overscan = r; update_interrupts(); } + +/***** + * One PPU dot = 4 CPU clocks + * + * PPU dots 323 and 327 are 6 CPU clocks long. + * This does not apply to NTSC non-interlace scanline 240 on odd fields. This is + * because the PPU skips one dot to alter the color burst phase of the video signal. + * + * Dot 323 range = { 1292, 1294, 1296 } + * Dot 327 range = { 1310, 1312, 1314 } + *****/ +uint16 sCPU::hcounter() { + if(ntsc_color_burst_phase_shift_scanline() == true) { + return (status.hclock >> 2); + } + return (status.hclock - ((status.hclock > 1292) << 1) - ((status.hclock > 1310) << 1)) >> 2; +} + +void sCPU::add_clocks(uint clocks) { + status.clocks_executed += clocks; + poll_interrupts(clocks); + + if(status.hclock + clocks >= status.line_clocks) { + clocks = (status.hclock + clocks) - status.line_clocks; + status.hclock = 0; + scanline(); + poll_interrupts(clocks); + } + + status.hclock += clocks; + + if(status.dram_refreshed == false) { + if(status.hclock >= 530) { + status.dram_refreshed = true; + add_clocks(40); + return; + } + } +} + +void sCPU::scanline() { + if(++status.vcounter >= status.field_lines) { + frame(); + } + + status.line_clocks = (ntsc_color_burst_phase_shift_scanline() == false) ? 1364 : 1360; + +//dram refresh occurs once every scanline + status.dram_refreshed = false; + +//hdma triggers once every visible scanline + status.line_rendered = + status.hdma_triggered = (status.vcounter <= (!overscan() ? 224 : 239)) ? false : true; + + r_ppu->scanline(); + snes->scanline(); + + update_interrupts(); + + if(status.vcounter == (!overscan() ? 227 : 242) && status.auto_joypad_poll == true) { + snes->poll_input(SNES::DEV_JOYPAD1); + snes->poll_input(SNES::DEV_JOYPAD2); + //When the SNES auto-polls the joypads, it writes 1, then 0 to + //$4016, then reads from each 16 times to get the joypad state + //information. As a result, the joypad read positions are set + //to 16 after such a poll. Position 16 is the controller + //connected status bit. + status.joypad1_read_pos = 16; + status.joypad2_read_pos = 16; + } +} + +void sCPU::frame() { + status.nmi_read = 1; + status.nmi_line = 1; + status.nmi_transition = 0; + + status.vcounter = 0; + status.interlace_field ^= 1; + status.field_lines = (status.region_scanlines >> 1); +//interlaced even fields have one extra scanline +//(263+262=525 NTSC, 313+312=625 PAL) + if(status.interlace == true && status.interlace_field == 0)status.field_lines++; + status.hdmainit_triggered = false; + + r_ppu->frame(); + snes->frame(); +} + +/***** + * opcode_edge() + *****/ +void sCPU::opcode_edge() { +#ifdef FAVOR_SPEED + co_return(); +#endif + if(status.line_rendered == false) { + if(status.hclock >= 128) { + status.line_rendered = true; + r_ppu->render_scanline(); + } + } +} + +/***** + * cycle_edge() + * + * Used to test for HDMA, which can trigger on the edge of every opcode cycle. + *****/ +void sCPU::cycle_edge() { + if(status.hdmainit_triggered == false) { + if(status.hclock >= 12 || status.vcounter) { + status.hdmainit_triggered = true; + hdma_init(); + } + } + + if(status.hdma_triggered == false) { + if(status.hclock >= 1106) { + status.hdma_triggered = true; + hdma_run(); + } + } +} + +/***** + * last_cycle() + * + * Used to test for NMI/IRQ, which can trigger on the edge of every opcode. + * Test one cycle early to simulate two-stage pipeline of x816 CPU. + *****/ +void sCPU::last_cycle() { + status.nmi_pending |= nmi_test(); + status.irq_pending |= irq_test(); + + event.irq = (status.nmi_pending || status.irq_pending); +} + +/***** + * clocks_executed() + * + * Return number of clocks executed since last call to this function. + * Used by class SNES to control CPU<>APU synchronization. + *****/ +uint32 sCPU::clocks_executed() { +uint32 r = status.clocks_executed; + status.clocks_executed = 0; + return r; +} + +void sCPU::timing_reset() { + status.clock_count = 0; + status.clocks_executed = 0; + + status.vcounter = 0; + status.hcounter = 0; + status.hclock = 0; + + status.interlace = 0; + status.interlace_field = 0; + status.overscan = false; + status.region_scanlines = (status.region == SNES::NTSC) ? 525 : 625; + + status.field_lines = status.region_scanlines >> 1; + status.line_clocks = 1364; + + status.line_rendered = false; + status.dram_refreshed = false; + status.hdmainit_triggered = false; + status.hdma_triggered = false; + + status.nmi_read = 1; + status.nmi_line = 1; + status.nmi_transition = 0; + status.nmi_pending = false; + + status.irq_read = 1; + status.irq_line = 1; + status.irq_transition = 0; + status.irq_pending = false; + + update_interrupts(); + +//initial latch values for $213c/$213d +//[x]0035 : [y]0000 (53.0 -> 212) [lda $2137] +//[x]0038 : [y]0000 (56.5 -> 226) [nop : lda $2137] + add_clocks(186); +} + +#undef ntsc_color_burst_phase_shift_scanline diff --git a/src/cpu/scpu/timing/timing.h b/src/cpu/scpu/timing/timing.h new file mode 100644 index 00000000..4cd2d322 --- /dev/null +++ b/src/cpu/scpu/timing/timing.h @@ -0,0 +1,30 @@ + uint16 vcounter(); + uint16 hcounter(); + uint16 hcycles(); + + bool interlace(); + bool interlace_field(); + bool overscan(); + uint16 region_scanlines(); + + void set_interlace(bool r); + void set_overscan(bool r); + + void add_clocks(uint clocks); + void scanline(); + void frame(); + + void opcode_edge(); + void cycle_edge(); + void last_cycle(); + uint32 clocks_executed(); + void timing_reset(); + +//irq.cpp + void update_interrupts(); + void poll_interrupts(int clocks); + bool nmi_read_pos_match(uint offset); + bool irq_read_pos_match(uint offset); + bool irq_pos_valid(); + bool nmi_test(); + bool irq_test(); diff --git a/src/dsp/bdsp/bdsp.cpp b/src/dsp/bdsp/bdsp.cpp index a6a546a8..2a0d1c4e 100644 --- a/src/dsp/bdsp/bdsp.cpp +++ b/src/dsp/bdsp/bdsp.cpp @@ -19,143 +19,132 @@ void bDSP::writew(uint16 addr, uint16 data) { } uint8 bDSP::read(uint8 addr) { -int i, v, n; addr &= 127; - v = addr >> 4; - n = addr & 15; +int v = addr >> 4; +int n = addr & 15; switch(addr) { - case 0x00:case 0x10:case 0x20:case 0x30: - case 0x40:case 0x50:case 0x60:case 0x70: + case 0x00: case 0x10: case 0x20: case 0x30: + case 0x40: case 0x50: case 0x60: case 0x70: return voice[v].VOLL; - case 0x01:case 0x11:case 0x21:case 0x31: - case 0x41:case 0x51:case 0x61:case 0x71: + case 0x01: case 0x11: case 0x21: case 0x31: + case 0x41: case 0x51: case 0x61: case 0x71: return voice[v].VOLR; - case 0x02:case 0x12:case 0x22:case 0x32: - case 0x42:case 0x52:case 0x62:case 0x72: - return voice[v].PITCH >> 8; - case 0x03:case 0x13:case 0x23:case 0x33: - case 0x43:case 0x53:case 0x63:case 0x73: + case 0x02: case 0x12: case 0x22: case 0x32: + case 0x42: case 0x52: case 0x62: case 0x72: return voice[v].PITCH; - case 0x04:case 0x14:case 0x24:case 0x34: - case 0x44:case 0x54:case 0x64:case 0x74: + case 0x03: case 0x13: case 0x23: case 0x33: + case 0x43: case 0x53: case 0x63: case 0x73: + return voice[v].PITCH >> 8; + case 0x04: case 0x14: case 0x24: case 0x34: + case 0x44: case 0x54: case 0x64: case 0x74: return voice[v].SRCN; - case 0x05:case 0x15:case 0x25:case 0x35: - case 0x45:case 0x55:case 0x65:case 0x75: + case 0x05: case 0x15: case 0x25: case 0x35: + case 0x45: case 0x55: case 0x65: case 0x75: return voice[v].ADSR1; - case 0x06:case 0x16:case 0x26:case 0x36: - case 0x46:case 0x56:case 0x66:case 0x76: + case 0x06: case 0x16: case 0x26: case 0x36: + case 0x46: case 0x56: case 0x66: case 0x76: return voice[v].ADSR2; - case 0x07:case 0x17:case 0x27:case 0x37: - case 0x47:case 0x57:case 0x67:case 0x77: + case 0x07: case 0x17: case 0x27: case 0x37: + case 0x47: case 0x57: case 0x67: case 0x77: return voice[v].GAIN; - case 0x08:case 0x18:case 0x28:case 0x38: - case 0x48:case 0x58:case 0x68:case 0x78: + case 0x08: case 0x18: case 0x28: case 0x38: + case 0x48: case 0x58: case 0x68: case 0x78: return voice[v].ENVX; - case 0x09:case 0x19:case 0x29:case 0x39: - case 0x49:case 0x59:case 0x69:case 0x79: + case 0x09: case 0x19: case 0x29: case 0x39: + case 0x49: case 0x59: case 0x69: case 0x79: return voice[v].OUTX; - case 0x0f:case 0x1f:case 0x2f:case 0x3f: - case 0x4f:case 0x5f:case 0x6f:case 0x7f: + case 0x0f: case 0x1f: case 0x2f: case 0x3f: + case 0x4f: case 0x5f: case 0x6f: case 0x7f: return status.FIR[v]; - case 0x0c:return status.MVOLL; - case 0x1c:return status.MVOLR; - case 0x2c:return status.EVOLL; - case 0x3c:return status.EVOLR; - case 0x4c:return status.KON; - case 0x5c:return status.KOFF; - case 0x6c:return status.FLG; - case 0x7c:return status.ENDX; + case 0x0c: return status.MVOLL; + case 0x1c: return status.MVOLR; + case 0x2c: return status.EVOLL; + case 0x3c: return status.EVOLR; + case 0x4c: return status.KON; + case 0x5c: return status.KOFF; + case 0x6c: return status.FLG; + case 0x7c: return status.ENDX; - case 0x0d:return status.EFB; - case 0x2d:return status.PMON; - case 0x3d:return status.NON; - case 0x4d:return status.EON; - case 0x5d:return status.DIR; - case 0x6d:return status.ESA; - case 0x7d:return status.EDL; + case 0x0d: return status.EFB; + case 0x2d: return status.PMON; + case 0x3d: return status.NON; + case 0x4d: return status.EON; + case 0x5d: return status.DIR; + case 0x6d: return status.ESA; + case 0x7d: return status.EDL; } return dspram[addr]; } void bDSP::write(uint8 addr, uint8 data) { -int i, v, n; //0x80-0xff is a read-only mirror of 0x00-0x7f if(addr & 0x80)return; - v = addr >> 4; - n = addr & 15; +int v = addr >> 4; +int n = addr & 15; switch(addr) { - case 0x00:case 0x10:case 0x20:case 0x30: - case 0x40:case 0x50:case 0x60:case 0x70: + case 0x00: case 0x10: case 0x20: case 0x30: + case 0x40: case 0x50: case 0x60: case 0x70: voice[v].VOLL = data; break; - case 0x01:case 0x11:case 0x21:case 0x31: - case 0x41:case 0x51:case 0x61:case 0x71: + case 0x01: case 0x11: case 0x21: case 0x31: + case 0x41: case 0x51: case 0x61: case 0x71: voice[v].VOLR = data; break; - case 0x02:case 0x12:case 0x22:case 0x32: - case 0x42:case 0x52:case 0x62:case 0x72: + case 0x02: case 0x12: case 0x22: case 0x32: + case 0x42: case 0x52: case 0x62: case 0x72: voice[v].PITCH &= 0xff00; voice[v].PITCH |= data; break; - case 0x03:case 0x13:case 0x23:case 0x33: - case 0x43:case 0x53:case 0x63:case 0x73: + case 0x03: case 0x13: case 0x23: case 0x33: + case 0x43: case 0x53: case 0x63: case 0x73: voice[v].PITCH &= 0x00ff; voice[v].PITCH |= data << 8; break; - case 0x04:case 0x14:case 0x24:case 0x34: - case 0x44:case 0x54:case 0x64:case 0x74: + case 0x04: case 0x14: case 0x24: case 0x34: + case 0x44: case 0x54: case 0x64: case 0x74: voice[v].SRCN = data; break; - //below is anomie's code, but TRAC says writing SRCN doesn't affect anything until a - //BRR-with-end block is encountered, where it loads the loop address from the new SRCN - //anomie's code breaks MK2 sound completely... - if(voice[v].SRCN != data) { - voice[v].SRCN = data; - voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2) + ((voice[v].brr_looped) ? 2 : 0)); - voice[v].brr_index = 0; - } - break; - case 0x05:case 0x15:case 0x25:case 0x35: - case 0x45:case 0x55:case 0x65:case 0x75: + case 0x05: case 0x15: case 0x25: case 0x35: + case 0x45: case 0x55: case 0x65: case 0x75: voice[v].ADSR1 = data; voice[v].AdjustEnvelope(); break; - case 0x06:case 0x16:case 0x26:case 0x36: - case 0x46:case 0x56:case 0x66:case 0x76: + case 0x06: case 0x16: case 0x26: case 0x36: + case 0x46: case 0x56: case 0x66: case 0x76: voice[v].ADSR2 = data; //sustain_level = 0-7, 7 is a special case handled by ATTACK envx mode voice[v].env_sustain = (voice[v].ADSR_sus_level() + 1) << 8; voice[v].AdjustEnvelope(); break; - case 0x07:case 0x17:case 0x27:case 0x37: - case 0x47:case 0x57:case 0x67:case 0x77: + case 0x07: case 0x17: case 0x27: case 0x37: + case 0x47: case 0x57: case 0x67: case 0x77: voice[v].GAIN = data; voice[v].AdjustEnvelope(); break; - case 0x08:case 0x18:case 0x28:case 0x38: - case 0x48:case 0x58:case 0x68:case 0x78: + case 0x08: case 0x18: case 0x28: case 0x38: + case 0x48: case 0x58: case 0x68: case 0x78: voice[v].ENVX = data; break; - case 0x09:case 0x19:case 0x29:case 0x39: - case 0x49:case 0x59:case 0x69:case 0x79: + case 0x09: case 0x19: case 0x29: case 0x39: + case 0x49: case 0x59: case 0x69: case 0x79: voice[v].OUTX = data; break; - case 0x0f:case 0x1f:case 0x2f:case 0x3f: - case 0x4f:case 0x5f:case 0x6f:case 0x7f: + case 0x0f: case 0x1f: case 0x2f: case 0x3f: + case 0x4f: case 0x5f: case 0x6f: case 0x7f: status.FIR[v] = data; break; - case 0x0c:status.MVOLL = data;break; - case 0x1c:status.MVOLR = data;break; - case 0x2c:status.EVOLL = data;break; - case 0x3c:status.EVOLR = data;break; + case 0x0c: status.MVOLL = data; break; + case 0x1c: status.MVOLR = data; break; + case 0x2c: status.EVOLL = data; break; + case 0x3c: status.EVOLR = data; break; case 0x4c: status.KON = data; @@ -179,12 +168,12 @@ int i, v, n; status.ENDX = 0; break; - case 0x0d:status.EFB = data;break; - case 0x2d:status.PMON = data;break; - case 0x3d:status.NON = data;break; - case 0x4d:status.EON = data;break; - case 0x5d:status.DIR = data;break; - case 0x6d:status.ESA = data;break; + case 0x0d: status.EFB = data; break; + case 0x2d: status.PMON = data; break; + case 0x3d: status.NON = data; break; + case 0x4d: status.EON = data; break; + case 0x5d: status.DIR = data; break; + case 0x6d: status.ESA = data; break; case 0x7d: status.EDL = data; @@ -196,11 +185,10 @@ int i, v, n; } void bDSP::power() { -int v; spcram = r_apu->get_spcram_handle(); memset(dspram, 0x00, 128); - for(v=0;v<8;v++) { + for(int v = 0; v < 8; v++) { voice[v].VOLL = 0; voice[v].VOLR = 0; voice[v].PITCH = 0; @@ -230,7 +218,6 @@ int v; } void bDSP::reset() { -int v; status.KON = 0x00; status.KOFF = 0x00; status.FLG |= 0xe0; @@ -245,7 +232,7 @@ int v; status.echo_index = 0; status.fir_buffer_index = 0; - for(v=0;v<8;v++) { + for(int v = 0; v < 8; v++) { voice[v].ENVX = 0; voice[v].OUTX = 0; @@ -273,28 +260,7 @@ int v; dsp_counter = 0; } -int32 bDSP::clamp(int32 bits, int32 x) { -int32 b = 1 << (bits - 1); - if(x > (b - 1)) { - return (b - 1); - } else if(x < -b) { - return -b; - } else { - return x; - } -} - -int32 bDSP::clip(int32 bits, int32 x) { -int32 b = 1 << (bits - 1); - if(x & b) { - return x | ~(b - 1); - } else { - return x & (b - 1); - } -} - uint32 bDSP::run() { -int v, d; uint8 pmon; int32 sample; int32 msamplel, msampler; @@ -302,10 +268,8 @@ int32 esamplel, esampler; int32 fir_samplel, fir_sampler; pmon = status.PMON & ~status.NON & ~1; -//if(!(dsp_counter++ & 1) && status.key_flag) { -//TRAC believes KON/KOFF is polled every sample. further testing is needed - if(status.key_flag) { - for(v=0;v<8;v++) { + if(!(dsp_counter++ & 1) && status.key_flag) { + for(int v = 0; v < 8; v++) { uint8 mask = 1 << v; if(status.soft_reset()) { if(voice[v].env_state != SILENCE) { @@ -318,7 +282,6 @@ int32 fir_samplel, fir_sampler; voice[v].AdjustEnvelope(); } } else if(status.kon & mask) { - //new KON code status.ENDX &= ~mask; status.kon &= ~mask; @@ -334,9 +297,6 @@ int32 fir_samplel, fir_sampler; voice[v].AdjustEnvelope(); } } -//old KON code, breaks sound effects in DL / SFA2 -// status.ENDX &= ~status.kon; -// status.kon = 0; status.key_flag = false; } @@ -351,7 +311,7 @@ int32 fir_samplel, fir_sampler; msamplel = msampler = 0; esamplel = esampler = 0; - for(v=0;v<8;v++) { + for(int v = 0; v < 8; v++) { if(voice[v].brr_index < -1) { voice[v].brr_index++; voice[v].OUTX = voice[v].outx = 0; @@ -380,11 +340,6 @@ int32 fir_samplel, fir_sampler; if(voice[v].brr_index == 0) { voice[v].brr_header = readb(voice[v].brr_ptr); -//moving status.ENDX bit set into == BRR_END condition per DMV27 - //if(voice[v].brr_header_flags() & BRR_END) { - // status.ENDX |= (1 << v); - //} - if(voice[v].brr_header_flags() == BRR_END) { status.ENDX |= (1 << v); voice[v].env_state = SILENCE; @@ -396,9 +351,9 @@ int32 fir_samplel, fir_sampler; if(voice[v].env_state != SILENCE) { sample = readb(voice[v].brr_ptr + 1 + (voice[v].brr_index >> 1)); if(voice[v].brr_index & 1) { - sample = clip(4, sample); + sample = sclip<4>(sample); } else { - sample = clip(4, sample >> 4); + sample = sclip<4>(sample >> 4); } if(voice[v].brr_header_shift() <= 12) { @@ -423,7 +378,7 @@ int32 fir_samplel, fir_sampler; break; } - S(0) = sample = clip(15, clamp(16, sample)); + S(0) = sample = sclip<15>(sclamp<16>(sample)); } else { S(0) = sample = 0; } @@ -431,7 +386,6 @@ int32 fir_samplel, fir_sampler; if(++voice[v].brr_index > 15) { voice[v].brr_index = 0; if(voice[v].brr_header_flags() & BRR_END) { - //below condition added by DMV27 if(voice[v].brr_header_flags() & BRR_LOOP) { status.ENDX |= (1 << v); } @@ -502,7 +456,7 @@ int32 fir_samplel, fir_sampler; if(voice[v].envx >= 0x7ff) { voice[v].envx = 0x7ff; - //attack raises to max. envx, if sustain is also set to max. envx, skip decay phase + //attack raises to max envx. if sustain is also set to max envx, skip decay phase voice[v].env_state = ((voice[v].env_sustain == 0x800) ? SUSTAIN : DECAY); voice[v].AdjustEnvelope(); } @@ -521,15 +475,15 @@ int32 fir_samplel, fir_sampler; //gaussian interpolation / noise if(status.NON & (1 << v)) { - sample = clip(15, status.noise_sample); + sample = sclip<15>(status.noise_sample); } else { - d = voice[v].pitch_ctr >> 4; //-256 <= sample <= -1 + int32 d = voice[v].pitch_ctr >> 4; //-256 <= sample <= -1 sample = ((GaussTable[ -1-d] * S(-3)) >> 11); sample += ((GaussTable[255-d] * S(-2)) >> 11); sample += ((GaussTable[512+d] * S(-1)) >> 11); - sample = clip (15, sample); + sample = sclip <15>(sample); sample += ((GaussTable[256+d] * S( 0)) >> 11); - sample = clamp(15, sample); + sample = sclamp<15>(sample); } #undef S @@ -579,8 +533,8 @@ int32 fir_samplel, fir_sampler; esamplel += (fir_samplel * status.EFB) >> 14; esampler += (fir_sampler * status.EFB) >> 14; - esamplel = clamp(16, esamplel); - esampler = clamp(16, esampler); + esamplel = sclamp<16>(esamplel); + esampler = sclamp<16>(esampler); writew((status.ESA << 8) + status.echo_index, esamplel); writew((status.ESA << 8) + status.echo_index + 2, esampler); @@ -600,11 +554,11 @@ int32 fir_samplel, fir_sampler; msamplel += (fir_samplel * status.EVOLL) >> 14; msampler += (fir_sampler * status.EVOLR) >> 14; - msamplel = clamp(16, msamplel); - msampler = clamp(16, msampler); + msamplel = sclamp<16>(msamplel); + msampler = sclamp<16>(msampler); } - return (uint32)(((uint16)msamplel) | ((uint16)msampler << 16)); + return uint32( uint16(msamplel) | (uint16(msampler) << 16) ); } bDSP::bDSP() {} diff --git a/src/dsp/bdsp/bdsp.h b/src/dsp/bdsp/bdsp.h index bc07632a..3570827b 100644 --- a/src/dsp/bdsp/bdsp.h +++ b/src/dsp/bdsp/bdsp.h @@ -5,10 +5,7 @@ uint8 *spcram; uint32 dsp_counter; -enum { - BRR_END = 1, - BRR_LOOP = 2 -}; +enum { BRR_END = 1, BRR_LOOP = 2 }; uint8 readb (uint16 addr); uint16 readw (uint16 addr); @@ -74,9 +71,9 @@ struct Status { uint8 fir_buffer_index; //functions - bool soft_reset() { return !!(FLG & 0x80); } - bool mute() { return !!(FLG & 0x40); } - bool echo_write() { return !(FLG & 0x20); } + bool soft_reset() { return bool(FLG & 0x80); } + bool mute() { return bool(FLG & 0x40); } + bool echo_write() { return !(FLG & 0x20); } } status; struct Voice { @@ -116,7 +113,7 @@ struct Voice { uint8 brr_header_filter() { return (brr_header >> 2) & 3; } uint8 brr_header_flags() { return brr_header & 3; } - bool ADSR_enabled() { return !!(ADSR1 & 0x80); } + bool ADSR_enabled() { return bool(ADSR1 & 0x80); } uint8 ADSR_decay() { return (ADSR1 >> 4) & 7; } uint8 ADSR_attack() { return ADSR1 & 15; } uint8 ADSR_sus_level() { return ADSR2 >> 5; } @@ -147,10 +144,10 @@ struct Voice { } } else if(GAIN & 0x80) { switch(GAIN & 0x60) { - case 0x00:env_mode = LINEAR_DEC; break; - case 0x20:env_mode = EXP_DEC; break; - case 0x40:env_mode = LINEAR_INC; break; - case 0x60:env_mode = BENT_INC; break; + case 0x00: env_mode = LINEAR_DEC; break; + case 0x20: env_mode = EXP_DEC; break; + case 0x40: env_mode = LINEAR_INC; break; + case 0x60: env_mode = BENT_INC; break; } env_rate = RateTable[GAIN & 0x1f]; } else { @@ -161,8 +158,6 @@ struct Voice { } } voice[8]; - int32 clamp(int32 bits, int32 x); - int32 clip (int32 bits, int32 x); public: uint8 read (uint8 addr); void write(uint8 addr, uint8 data); diff --git a/src/interface.h b/src/interface.h index ed50cd3c..d91e9bbc 100644 --- a/src/interface.h +++ b/src/interface.h @@ -19,9 +19,11 @@ #include "memory/bmemory/bmemory.h" #include "cpu/cpu.h" +#include "cpu/scpu/scpu.h" #include "cpu/bcpu/bcpu.h" #include "apu/apu.h" +#include "apu/sapu/sapu.h" #include "apu/bapu/bapu.h" #include "dsp/dsp.h" @@ -35,6 +37,7 @@ #include "chip/srtc/srtc.h" #include "chip/sdd1/sdd1.h" #include "chip/c4/c4.h" +#include "chip/dsp1/dsp1.h" #include "chip/dsp2/dsp2.h" #include "chip/obc1/obc1.h" @@ -51,12 +54,13 @@ extern MMIO mmio_unmapped; extern APUCORE deref(apu); extern DSPCORE deref(dsp); extern PPUCORE deref(ppu); - #endif +#endif extern SNES *snes; extern SRTC *srtc; extern SDD1 *sdd1; extern C4 *c4; +extern DSP1 *dsp1; extern DSP2 *dsp2; extern OBC1 *obc1; @@ -85,6 +89,7 @@ SNES *snes; SRTC *srtc; SDD1 *sdd1; C4 *c4; +DSP1 *dsp1; DSP2 *dsp2; OBC1 *obc1; diff --git a/src/lib/libbase.h b/src/lib/libbase.h index a829a38d..a8de1d46 100644 --- a/src/lib/libbase.h +++ b/src/lib/libbase.h @@ -1,10 +1,29 @@ /* - libbase : version 0.07 ~byuu (04/21/06) + libbase : version 0.08 ~byuu (07/08/06) */ #ifndef __LIBBASE #define __LIBBASE +#ifdef _MSC_VER +//disable libc deprecation warnings in MSVC 2k5+ +#pragma warning(disable:4996) +#endif + +/***** + * inline expansion + *****/ + +#ifdef _MSC_VER + #define noinline __declspec(noinline) + #define inline inline + #define forceinline __forceinline +#else + #define noinline + #define inline inline + #define forceinline inline +#endif + #include #include #include @@ -17,14 +36,19 @@ #endif #ifndef TRUE -#define TRUE 1 +#define TRUE !FALSE #endif #define SafeFree(__n) if(__n) { free(__n); __n = 0; } #define SafeDelete(__n) if(__n) { delete(__n); __n = 0; } #define SafeRelease(__n) if(__n) { __n->Release(); __n = 0; } +/***** + * typedefs + *****/ + typedef unsigned int uint; +typedef signed int sint; typedef unsigned char byte; typedef unsigned short word; @@ -42,16 +66,151 @@ typedef signed short int16; typedef signed long int32; typedef signed long long int64; -template void swap(T &x, T &y) { + +/***** + * templates + *****/ + +template inline void swap(T &x, T &y) { T z = x; x = y; y = z; } -template T bound_range(T &x, Targ min, Targ max) { +template inline T minmax(const T x) { return (x < T(min)) ? T(min) : (x > T(max)) ? T(max) : x; } +template inline unsigned uclamp(const unsigned x) { +enum { m = (1 << bits) - 1 }; + return (x > m) ? m : x; +} + +template inline unsigned uclip(const unsigned x) { +enum { m = (1 << bits) - 1 }; + return (x & m); +} + +template inline signed sclamp(const signed x) { +enum { b = 1 << (bits - 1), m = (1 << (bits - 1)) - 1 }; + return (x > m) ? m : (x < -b) ? -b : x; +} + +//requires compiler SAR (shift arithmetic right) support +template inline signed sclip(const signed x) { +enum { s = sizeof(x) * 8 - bits }; + return (x << s) >> s; +} + +//use this if compiler uses SLR (shift logical right) +//template inline signed sclip(const signed x) { +//enum { b = 1 << (bits - 1), m = (1 << (bits - 1)) - 1 }; +// return (x & b) ? (x | ~m) : (x & m); +//} + +template class uint_t { +private: +base data; + +public: + inline operator unsigned() const { return data; } + inline unsigned operator ++(int) { base r = data; data = uclip(data + 1); return r; } + inline unsigned operator --(int) { base r = data; data = uclip(data - 1); return r; } + inline unsigned operator ++() { data = uclip(data + 1); return data; } + inline unsigned operator --() { data = uclip(data - 1); return data; } + template inline unsigned operator =(const T i) { data = uclip(i); return data; } + template inline unsigned operator |=(const T i) { data = uclip(data | i); return data; } + template inline unsigned operator ^=(const T i) { data = uclip(data ^ i); return data; } + template inline unsigned operator &=(const T i) { data = uclip(data & i); return data; } + template inline unsigned operator<<=(const T i) { data = uclip(data << i); return data; } + template inline unsigned operator>>=(const T i) { data = uclip(data >> i); return data; } + template inline unsigned operator +=(const T i) { data = uclip(data + i); return data; } + template inline unsigned operator -=(const T i) { data = uclip(data - i); return data; } + template inline unsigned operator *=(const T i) { data = uclip(data * i); return data; } + template inline unsigned operator /=(const T i) { data = uclip(data / i); return data; } + template inline unsigned operator %=(const T i) { data = uclip(data % i); return data; } + + inline uint_t() : data(0) {} + inline uint_t(const base i) : data(uclip(i)) {} +}; + +template class int_t { +private: +base data; + +public: + inline operator signed() const { return data; } + inline signed operator ++(int) { base r = data; data = sclip(data + 1); return r; } + inline signed operator --(int) { base r = data; data = sclip(data - 1); return r; } + inline signed operator ++() { data = sclip(data + 1); return data; } + inline signed operator --() { data = sclip(data - 1); return data; } + template inline signed operator =(const T i) { data = sclip(i); return data; } + template inline signed operator |=(const T i) { data = sclip(data | i); return data; } + template inline signed operator ^=(const T i) { data = sclip(data ^ i); return data; } + template inline signed operator &=(const T i) { data = sclip(data & i); return data; } + template inline signed operator<<=(const T i) { data = sclip(data << i); return data; } + template inline signed operator>>=(const T i) { data = sclip(data >> i); return data; } + template inline signed operator +=(const T i) { data = sclip(data + i); return data; } + template inline signed operator -=(const T i) { data = sclip(data - i); return data; } + template inline signed operator *=(const T i) { data = sclip(data * i); return data; } + template inline signed operator /=(const T i) { data = sclip(data / i); return data; } + template inline signed operator %=(const T i) { data = sclip(data % i); return data; } + + inline int_t() : data(0) {} + inline int_t(const base i) : data(sclip(i)) {} +}; + +typedef uint_t<24> uint24; +typedef int_t<24> int24; +typedef uint_t<48, uint64> uint48; +typedef int_t<48, int64> int48; + +/***** + * endian wrappers + *****/ + +#ifndef ARCH_MSB +//little-endian: uint8[] { 0x01, 0x02, 0x03, 0x04 } = 0x04030201 +#define order_lsb2(a,b) a,b +#define order_lsb3(a,b,c) a,b,c +#define order_lsb4(a,b,c,d) a,b,c,d +#define order_lsb5(a,b,c,d,e) a,b,c,d,e +#define order_lsb6(a,b,c,d,e,f) a,b,c,d,e,f +#define order_lsb7(a,b,c,d,e,f,g) a,b,c,d,e,f,g +#define order_lsb8(a,b,c,d,e,f,g,h) a,b,c,d,e,f,g,h +#define order_msb2(a,b) b,a +#define order_msb3(a,b,c) c,b,a +#define order_msb4(a,b,c,d) d,c,b,a +#define order_msb5(a,b,c,d,e) e,d,c,b,a +#define order_msb6(a,b,c,d,e,f) f,e,d,c,b,a +#define order_msb7(a,b,c,d,e,f,g) g,f,e,d,c,b,a +#define order_msb8(a,b,c,d,e,f,g,h) h,g,f,e,d,c,b,a +#define order_lsbit8(b0,b1,b2,b3,b4,b5,b6,b7) b7:1,b6:1,b5:1,b4:1,b3:1,b2:1,b1:1,b0:1 +#define order_msbit8(b7,b6,b5,b4,b3,b2,b1,b0) b0:1,b1:1,b2:1,b3:1,b4:1,b5:1,b6:1,b7:1 +#else +//big-endian: uint8[] { 0x01, 0x02, 0x03, 0x04 } = 0x01020304 +#define order_lsb2(a,b) b,a +#define order_lsb3(a,b,c) c,b,a +#define order_lsb4(a,b,c,d) d,c,b,a +#define order_lsb5(a,b,c,d,e) e,d,c,b,a +#define order_lsb6(a,b,c,d,e,f) f,e,d,c,b,a +#define order_lsb7(a,b,c,d,e,f,g) g,f,e,d,c,b,a +#define order_lsb8(a,b,c,d,e,f,g,h) h,g,f,e,d,c,b,a +#define order_msb2(a,b) a,b +#define order_msb3(a,b,c) a,b,c +#define order_msb4(a,b,c,d) a,b,c,d +#define order_msb5(a,b,c,d,e) a,b,c,d,e +#define order_msb6(a,b,c,d,e,f) a,b,c,d,e,f +#define order_msb7(a,b,c,d,e,f,g) a,b,c,d,e,f,g +#define order_msb8(a,b,c,d,e,f,g,h) a,b,c,d,e,f,g,h +#define order_lsbit8(b7,b6,b5,b4,b3,b2,b1,b0) b0:1,b1:1,b2:1,b3:1,b4:1,b5:1,b6:1,b7:1 +#define order_msbit8(b0,b1,b2,b3,b4,b5,b6,b7) b7:1,b6:1,b5:1,b4:1,b3:1,b2:1,b1:1,b0:1 +#endif + +/***** + * libc extensions + *****/ + inline bool fexists(const char *fn) { FILE *fp = fopen(fn, "rb"); if(!fp)return false; @@ -79,6 +238,11 @@ uint32 size = ftell(fp); return size; } +/***** + * crc32 calculation + * TODO: create libhash and move this code there + *****/ + const uint32 crc32_table[256] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, diff --git a/src/lib/libco_win32.cpp b/src/lib/libco_win32.cpp new file mode 100644 index 00000000..c6fbaf1b --- /dev/null +++ b/src/lib/libco_win32.cpp @@ -0,0 +1,68 @@ +/* + libco_win32 : version 0.04 ~byuu (05/11/06) + win32-x86 implementation of libco +*/ + +#define WINVER 0x0400 +#define _WIN32_WINNT 0x0400 +#include + +#include "libco.h" + +namespace libco_win32 { + bool co_enabled = false; + int co_stackptr = 0; + thread_t co_stack[4096]; + + void __stdcall coentry_proc(void *coentry) { + thread_p main = (thread_p)coentry; + main(); + } +}; + +extern "C" void co_init() { + if(libco_win32::co_enabled == true)return; + libco_win32::co_enabled = true; + + ConvertThreadToFiber(0); +} + +extern "C" void co_term() { +/***** +//ConverFiberToThread() only exists in WinXP+ + + if(libco_win32::co_enabled == false)return; + libco_win32::co_enabled = false; + + ConvertFiberToThread(); +*****/ +} + +extern "C" thread_t co_active() { + if(libco_win32::co_enabled == false)co_init(); + + return GetCurrentFiber(); +} + +extern "C" thread_t co_create(thread_p coentry, unsigned int heapsize) { + if(libco_win32::co_enabled == false)co_init(); + + return CreateFiber(heapsize, libco_win32::coentry_proc, (void*)coentry); +} + +extern "C" void co_delete(thread_t cothread) { + DeleteFiber(cothread); +} + +extern "C" void co_jump(thread_t cothread) { + SwitchToFiber(cothread); +} + +extern "C" void co_call(thread_t cothread) { + libco_win32::co_stack[libco_win32::co_stackptr++] = co_active(); + co_jump(cothread); +} + +extern "C" void co_return() { + co_jump(libco_win32::co_stack[--libco_win32::co_stackptr]); +} diff --git a/src/lib/libco_x86.asm b/src/lib/libco_x86.asm new file mode 100644 index 00000000..dfb9a2a8 --- /dev/null +++ b/src/lib/libco_x86.asm @@ -0,0 +1,215 @@ +;***** +;libco_x86 : version 0.06 ~byuu (05/21/06) +;cross-platform x86 implementation of libco +; +;context save/restore adheres to c/c++ ABI +;for x86 win32, linux and freebsd +; +;context saves esp+ebp+esi+edi+ebx +;context ignores eax+ecx+edx +;context ignores st([0-7])+xmm[0-15] +;context ignores all else +;***** + +section .data + +align 4 +co_initialized dd 0 +co_active_context dd 0 + +section .code + +;***** +;linker-specific name decorations +;***** +%define malloc _malloc +%define free _free + +%define co_init @co_init@0 +%define co_term @co_term@0 +%define co_active @co_active@0 +%define co_create @co_create@8 +%define co_delete @co_delete@4 +%define co_jump @co_jump@4 +%define co_call @co_call@4 +%define co_return @co_return@0 + +extern malloc +extern free + +global co_init +global co_term +global co_active +global co_create +global co_delete +global co_jump +global co_call +global co_return + +;***** +;extern "C" void __fastcall co_init(); +;***** + +align 16 +co_init: + cmp dword[co_initialized],0 ;only run co_init once + jne .end + inc dword[co_initialized] + +;create context for main thread + mov ecx,0 ;entry point for main thread is not needed + mov edx,256 ;main thread uses default program stack + call co_create + mov dword[co_active_context],eax +.end + ret + +;***** +;extern "C" void __fastcall co_term(); +;***** + +align 16 +co_term: + ret + +;***** +;extern "C" thread_t __fastcall co_active(); +;return = eax +;***** + +align 16 +co_active: + cmp dword[co_initialized],0 ;make sure co_init has been called + jne .next + call co_init +.next: + mov eax,dword[co_active_context] + ret + +;***** +;extern "C" thread_t __fastcall co_create(thread_p coentry, unsigned int heapsize); +;ecx = coentry +;edx = heapsize +;return = eax +;***** + +align 16 +co_create: + cmp dword[co_initialized],0 ;make sure co_init has been called + jne .next + push ecx + push edx + call co_init + pop edx + pop ecx +.next: + +;create heap space (stack + register storage) + add edx,28 ;+8(esp+prev_call_context)+4(coentry)+16(stack_align) + push ecx + push edx + call malloc + pop edx + pop ecx + + add edx,eax ;set edx to point to top of stack heap + and edx,0xfffffff0 ;force 16-byte alignment of stack heap + +;store thread entry point + registers so that first call to co_jump will go to coentry + mov dword[edx-4],ecx ;edx=*stack,ecx=coentry + mov dword[edx-8],0 + mov dword[edx-12],0 + mov dword[edx-16],0 + mov dword[edx-20],0 + sub edx,20 + +;initialize context memory heap + mov dword[eax],edx ;thread_t[0-3] = stack heap pointer (esp) + mov dword[eax+4],0 ;thread_t[4-7] = (null) pointer to prev_call_context + + ret ;return allocated memory block as thread handle + +;***** +;extern "C" void __fastcall co_delete(thread_t cothread); +;ecx = cothread +;***** + +align 16 +co_delete: + push ecx + call free + add esp,4 + ret + +;***** +;extern "C" void __fastcall co_jump(thread_t cothread); +;ecx = cothread +;***** + +align 16 +co_jump: + mov eax,dword[co_active_context] ;backup current context + mov dword[co_active_context],ecx ;set new active context + + push ebp + push esi + push edi + push ebx + mov dword[eax],esp + + mov esp,dword[ecx] + pop ebx + pop edi + pop esi + pop ebp + + ret + +;***** +;extern "C" void __fastcall co_call(thread_t cothread); +;ecx = cothread +;***** + +align 16 +co_call: + mov eax,dword[co_active_context] ;backup current context + mov dword[co_active_context],ecx ;set new active context + mov dword[ecx+4],eax + + push ebp + push esi + push edi + push ebx + mov dword[eax],esp + + mov esp,dword[ecx] + pop ebx + pop edi + pop esi + pop ebp + + ret + +;***** +;extern "C" void __fastcall co_return(); +;***** + +align 16 +co_return: + mov eax,dword[co_active_context] ;backup current context + mov ecx,dword[eax+4] ;restore pre-call context + mov dword[co_active_context],ecx ;set new active context + + push ebp + push esi + push edi + push ebx + mov dword[eax],esp + + mov esp,dword[ecx] + pop ebx + pop edi + pop esi + pop ebp + + ret diff --git a/src/lib/libco_x86.h b/src/lib/libco_x86.h new file mode 100644 index 00000000..dba5d185 --- /dev/null +++ b/src/lib/libco_x86.h @@ -0,0 +1,15 @@ +/* + libco_x86 : version 0.06 ~byuu (05/21/2006) +*/ + +typedef void (*thread_t); +typedef void (*thread_p)(); + +extern "C" void __fastcall co_init(); +extern "C" void __fastcall co_term(); +extern "C" thread_t __fastcall co_active(); +extern "C" thread_t __fastcall co_create(thread_p coentry, unsigned int heapsize); +extern "C" void __fastcall co_delete(thread_t cothread); +extern "C" void __fastcall co_jump(thread_t cothread); +extern "C" void __fastcall co_call(thread_t cothread); +extern "C" void __fastcall co_return(); diff --git a/src/lib/libconfig.h b/src/lib/libconfig.h index 380b2cb1..c7c2fa5f 100644 --- a/src/lib/libconfig.h +++ b/src/lib/libconfig.h @@ -1,5 +1,5 @@ /* - libconfig : version 0.07 ~byuu (02/10/06) + libconfig : version 0.08 ~byuu (07/02/06) */ #ifndef __LIBCONFIG @@ -19,17 +19,7 @@ class Config; // class T : public Setting { public: SettingOperators(T); } t; // t = 0; // -> t.set(0); #define SettingOperators(__name) \ - inline __name &operator=(const bool _data) { set((uint)_data); return *this; } \ - inline __name &operator=(const uint _data) { set(_data); return *this; } \ - inline __name &operator=(const uint8 _data) { set(_data); return *this; } \ - inline __name &operator=(const uint16 _data) { set(_data); return *this; } \ - inline __name &operator=(const uint32 _data) { set(_data); return *this; } \ - inline __name &operator=(const int _data) { set(_data); return *this; } \ - inline __name &operator=(const int8 _data) { set(_data); return *this; } \ - inline __name &operator=(const int16 _data) { set(_data); return *this; } \ - inline __name &operator=(const int32 _data) { set(_data); return *this; } \ - inline __name &operator=(const float _data) { set((uint)_data); return *this; } \ - inline __name &operator=(const double _data) { set((uint)_data); return *this; } \ + template inline __name &operator=(const T x) { set(T(x)); return *this; } \ void toggle() { data ^= 1; set(data); } \ __name(Config *_parent, char *_name, char *_desc, uint _data, uint _type) : \ Setting(_parent, _name, _desc, _data, _type) {} \ @@ -44,17 +34,19 @@ uint data, type, def; public: enum { - TRUE_FALSE, - ENABLED_DISABLED, - ON_OFF, - YES_NO, - DEC, - HEX, - HEX8, - HEX16, - HEX24, - HEX32, - STR + BOOL = 0, + BOOLEAN = 0, + TRUE_FALSE = 0, + ENABLED_DISABLED = 1, + ON_OFF = 2, + YES_NO = 3, + DEC = 4, + HEX = 5, + HEX8 = 6, + HEX16 = 7, + HEX24 = 8, + HEX32 = 9, + STR = 10, }; char *name, *desc; substring char_data, char_def; @@ -68,29 +60,14 @@ substring char_data, char_def; Setting(Config *_parent, char *_name, char *_desc, uint _data, uint _type); Setting(Config *_parent, char *_name, char *_desc, char *_data); - inline operator bool() { return (bool)get(); } - inline operator uint() { return get(); } - inline operator uint8() { return get(); } - inline operator uint16() { return get(); } - inline operator uint32() { return get(); } - inline operator int() { return get(); } - inline operator int8() { return get(); } - inline operator int16() { return get(); } - inline operator int32() { return get(); } - inline operator float() { return (float) get(); } - inline operator double() { return (double)get(); } - - inline Setting &operator=(const bool _data) { set((uint)_data); return *this; } - inline Setting &operator=(const uint _data) { set(_data); return *this; } - inline Setting &operator=(const uint8 _data) { set(_data); return *this; } - inline Setting &operator=(const uint16 _data) { set(_data); return *this; } - inline Setting &operator=(const uint32 _data) { set(_data); return *this; } - inline Setting &operator=(const int _data) { set(_data); return *this; } - inline Setting &operator=(const int8 _data) { set(_data); return *this; } - inline Setting &operator=(const int16 _data) { set(_data); return *this; } - inline Setting &operator=(const int32 _data) { set(_data); return *this; } - inline Setting &operator=(const float _data) { set((uint)_data); return *this; } - inline Setting &operator=(const double _data) { set((uint)_data); return *this; } + template inline operator T() { return T(get()); } + template inline Setting &operator=(const T x) { set(T(x)); return *this; } + template inline bool operator==(const T x) { return T(get()) == x; } + template inline bool operator!=(const T x) { return T(get()) != x; } + template inline bool operator>=(const T x) { return T(get()) >= x; } + template inline bool operator> (const T x) { return T(get()) > x; } + template inline bool operator<=(const T x) { return T(get()) <= x; } + template inline bool operator< (const T x) { return T(get()) < x; } }; class Config { diff --git a/src/lib/libstring.cpp b/src/lib/libstring.cpp index eb0893d9..712beb63 100644 --- a/src/lib/libstring.cpp +++ b/src/lib/libstring.cpp @@ -8,10 +8,7 @@ substring::substring() { } substring::~substring() { - if(s) { - free(s); - s = 0; - } + SafeFree(s); } void string::addto(uint num) { @@ -32,8 +29,7 @@ string::string() { } string::~string() { -int i; - for(i=listcount-1;i>=0;i--) { + for(int i = listcount - 1; i >= 0; i--) { delete((substring*)list[i]); } } @@ -65,7 +61,7 @@ int strcmp(const char *dest, substring &src) { return strcmp(dest, strptr(src)); int strcmp(substring &dest, substring &src) { return strcmp(strptr(dest), strptr(src)); } int __stricmp(const char *dest, const char *src) { - while(*dest && *src) { + while(*dest) { if(chrlower(*dest) != chrlower(*src))break; dest++; src++; @@ -86,6 +82,12 @@ bool strimatch(substring &dest, const char *src) { return strimatch(strptr(dest) bool strimatch(const char *dest, substring &src) { return strimatch(dest, strptr(src)); } bool strimatch(substring &dest, substring &src) { return strimatch(strptr(dest), strptr(src)); } +void strcpy(substring &dest, const char src) { + if(1 > dest.size) { strresize(dest, 1); } + dest.s[0] = src; + dest.s[1] = 0; +} + void strcpy(substring &dest, const char *src) { int srclen = strlen(src); if(srclen > dest.size) { strresize(dest, srclen); } @@ -106,15 +108,20 @@ int srclen = strlen(src); void strncpy(substring &dest, substring &src, uint32 length) { strncpy(dest, strptr(src), length); } void strset(substring &dest, uint pos, uint8 c) { -char *s; if(pos > dest.size) { strresize(dest, pos); } dest.s[pos] = c; } +void strcat(substring &dest, const char src) { +int length = strlen(dest); + if(length + 1 > dest.size) { strresize(dest, length + 1); } + dest.s[length] = src; + dest.s[length + 1] = 0; +} + void strcat(substring &dest, const char *src) { -int srclen, destlen; - srclen = strlen(src); - destlen = strlen(dest.s); +int srclen = strlen(src); +int destlen = strlen(dest); if(srclen + destlen > dest.size) { strresize(dest, srclen + destlen); } strcat(dest.s, src); } @@ -143,26 +150,30 @@ int i, sl = strlen(dest.s); s[i] = 0; } -void strlower(char *str) { - while(*str) { - *str = chrlower(*str); - str++; +char *strlower(char *str) { +uint i = 0; + while(str[i]) { + str[i] = chrlower(str[i]); + i++; } + return str; } -void strlower(substring &str) { strlower(strptr(str)); } +substring &strlower(substring &str) { strlower(strptr(str)); return str; } -void strupper(char *str) { - while(*str) { - *str = chrupper(*str); - str++; +char *strupper(char *str) { +uint i = 0; + while(str[i]) { + str[i] = chrupper(str[i]); + i++; } + return str; } -void strupper(substring &str) { strupper(strptr(str)); } +substring &strupper(substring &str) { strupper(strptr(str)); return str; } bool strpos(const char *str, const char *key, uint &pos) { -int i, ssl = strlen(str), ksl = strlen(key); +int ssl = strlen(str), ksl = strlen(key); if(ksl > ssl)return false; - for(i = 0; i <= ssl - ksl; i++) { + for(int i = 0; i <= ssl - ksl; i++) { if(!memcmp(str + i, key, ksl)) { pos = i; return true; @@ -175,13 +186,12 @@ bool strpos(const char *str, substring &key, uint &pos) { return strpos(str, str bool strpos(substring &str, substring &key, uint &pos) { return strpos(strptr(str), strptr(key), pos); } bool qstrpos(const char *str, const char *key, uint &pos) { -int i, z, ssl = strlen(str), ksl = strlen(key); -uint8 x; +int ssl = strlen(str), ksl = strlen(key); if(ksl > ssl)return false; - for(i = 0; i <= ssl - ksl;) { - x = str[i]; + for(int i = 0; i <= ssl - ksl;) { + uint8 x = str[i]; if(x == '\"' || x == '\'') { - z = i++; + uint8 z = i++; while(str[i] != x && i < ssl)i++; if(i >= ssl)i = z; } @@ -220,9 +230,9 @@ int i, ssl = strlen(str), ksl = strlen(key); bool strbegin(substring &str, const char *key) { return strbegin(strptr(str), key); } bool stribegin(const char *str, const char *key) { -int i, ssl = strlen(str), ksl = strlen(key); +int ssl = strlen(str), ksl = strlen(key); if(ksl > ssl)return false; - for(i=0;i= 'A' && str[i] <= 'Z') { if(str[i] != key[i] && str[i]+0x20 != key[i])return false; } else if(str[i] >= 'a' && str[i] <= 'z') { @@ -236,16 +246,16 @@ int i, ssl = strlen(str), ksl = strlen(key); bool stribegin(substring &str, const char *key) { return stribegin(strptr(str), key); } bool strend(const char *str, const char *key) { -int i, ssl = strlen(str), ksl = strlen(key); +int ssl = strlen(str), ksl = strlen(key); if(ksl > ssl)return false; return (!memcmp(str + ssl - ksl, key, ksl)); } bool strend(substring &str, const char *key) { return strend(strptr(str), key); } bool striend(const char *str, const char *key) { -int i, z, ssl = strlen(str), ksl = strlen(key); +int ssl = strlen(str), ksl = strlen(key); if(ksl > ssl)return false; - for(i=ssl-ksl, z=0;i= 'A' && str[i] <= 'Z') { if(str[i] != key[z] && str[i]+0x20 != key[z])return false; } else if(str[i] >= 'a' && str[i] <= 'z') { @@ -298,7 +308,7 @@ void strirtrim(substring &str, const char *key) { strirtrim(strptr(str), key); } //does not work on type char* because function increases string length void strquote(substring &str) { -static string t; +static substring t; strcpy(t, "\""); strcat(t, str); strcat(t, "\""); @@ -316,7 +326,7 @@ int i, ssl = strlen(str); else return false; //now remove them - for(i=0;i num)mask /= 10; + while(mask > 1) { + str[0] = '0'; + while(num >= mask) { str[0]++; num -= mask; } + str++; + mask /= 10; + } + str[0] = '0' + num; + str++; + str[0] = 0; + return pstr; +} + +substring &utoa(substring &str, uint num) { + if(str.size < 16) { strresize(str, 16); } + utoa(strptr(str), num); + return str; +} + +char *itoa(char *str, uint num) { +char *pstr = str; + if(num < 0) { + str[0] = '-'; + str++; + num = abs(int(num)); + } + utoa(str, num); + return pstr; +} + +substring &itoa(substring &str, uint num) { + if(str.size < 16) { strresize(str, 16); } + itoa(strptr(str), num); + return str; +} + +char *htoa(char *str, uint num) { +char *pstr = str; +uint mask = 28, r; + while(mask && ((num >> mask) & 15) == 0)mask -= 4; + while(mask) { + r = (num >> mask) & 15; + str[0] = (r < 10) ? ('0' + r) : ('a' + r - 10); + str++; + mask -= 4; + } + r = num & 15; + str[0] = (r < 10) ? ('0' + r) : ('a' + r - 10); + str++; + str[0] = 0; + return pstr; +} + +substring &htoa(substring &str, uint num) { + if(str.size < 16) { strresize(str, 16); } + htoa(strptr(str), num); + return str; +} + +char *uhtoa(char *str, uint num) { +char *pstr = str; +uint mask = 28, r; + while(mask && ((num >> mask) & 15) == 0)mask -= 4; + while(mask) { + r = (num >> mask) & 15; + str[0] = (r < 10) ? ('0' + r) : ('A' + r - 10); + str++; + mask -= 4; + } + r = num & 15; + str[0] = (r < 10) ? ('0' + r) : ('A' + r - 10); + str++; + str[0] = 0; + return pstr; +} + +substring &uhtoa(substring &str, uint num) { + if(str.size < 16) { strresize(str, 16); } + uhtoa(strptr(str), num); + return str; +} + +char *btoa(char *str, uint num) { +char *pstr = str; +uint mask = 0x80000000; + while(mask && (num & mask) == 0)mask >>= 1; + while(mask > 1) { + str[0] = (num & mask) ? '1' : '0'; + str++; + mask >>= 1; + } + str[0] = (num & mask) ? '1' : '0'; + str++; + str[0] = 0; + return pstr; +} + +substring &btoa(substring &str, uint num) { + if(str.size < 48) { strresize(str, 48); } + btoa(strptr(str), num); + return str; +} + #include "libstring_math.cpp" #include "libstring_split.cpp" #include "libstring_replace.cpp" diff --git a/src/lib/libstring.h b/src/lib/libstring.h index 933687e6..52e93558 100644 --- a/src/lib/libstring.h +++ b/src/lib/libstring.h @@ -1,5 +1,5 @@ /* - libstring : version 0.10 ~byuu (03/05/06) + libstring : version 0.11 ~byuu (07/02/06) */ #ifndef __LIBSTRING @@ -51,6 +51,7 @@ void strncpy(substring &dest, substring &src, uint32 length); void strset(substring &dest, uint pos, uint8 c); +void strcat(substring &dest, const char src); void strcat(substring &dest, const char *src); void strcat(substring &dest, substring &src); @@ -59,11 +60,11 @@ void strinsert(substring &dest, substring &src, uint pos); void strremove(substring &dest, uint start, uint length = 0); -void strlower(char *str); -void strlower(substring &str); +char *strlower(char *str); +substring &strlower(substring &str); -void strupper(char *str); -void strupper(substring &str); +char *strupper(char *str); +substring &strupper(substring &str); bool strpos(const char *str, const char *key, uint &pos); bool strpos(substring &str, const char *key, uint &pos); @@ -125,17 +126,32 @@ uint strbin(substring &str); int sstrbin(const char *str); int sstrbin(substring &str); +char *utoa(char *str, uint num); +substring &utoa(substring &str, uint num); + +char *itoa(char *str, uint num); +substring &itoa(substring &str, uint num); + +char *htoa(char *str, uint num); +substring &htoa(substring &str, uint num); + +char *uhtoa(char *str, uint num); +substring &uhtoa(substring &str, uint num); + +char *btoa(char *str, uint num); +substring &btoa(substring &str, uint num); + uint strmath(const char *in_str); uint strmath(substring &in_str); bool strmathentity(const char *str); bool strmathentity(substring &str); -void replace(substring &str, const char *key, const char *token); -void replace(substring &str, const char *key, substring &token); +substring &replace(substring &str, const char *key, const char *token); +substring &replace(substring &str, const char *key, substring &token); -void qreplace(substring &str, const char *key, const char *token); -void qreplace(substring &str, const char *key, substring &token); +substring &qreplace(substring &str, const char *key, const char *token); +substring &qreplace(substring &str, const char *key, substring &token); void split(string &dest, const char *key, const char *src); void split(string &dest, const char *key, substring &src); @@ -143,7 +159,8 @@ void split(string &dest, const char *key, substring &src); void qsplit(string &dest, const char *key, const char *src); void qsplit(string &dest, const char *key, substring &src); -void sprintf(substring &str, const char *s, ...); +uint vsprintf(substring &str, const char *s, va_list args); +uint sprintf(substring &str, const char *s, ...); class substring { public: @@ -175,14 +192,7 @@ uint listcount, count; //inline char* operator*() { return strptr(str(0)); } //inline operator char*() { return str(0).s; } inline operator substring&() { return str(0); } - inline substring& operator[](uint i) { return str(i); } - inline substring& operator[](uint8 i) { return str(i); } - inline substring& operator[](uint16 i) { return str(i); } - inline substring& operator[](uint32 i) { return str(i); } - inline substring& operator[](int i) { return str(i); } - inline substring& operator[](int8 i) { return str(i); } - inline substring& operator[](int16 i) { return str(i); } - inline substring& operator[](int32 i) { return str(i); } + template inline substring& operator[](T i) { return str(i); } string(); ~string(); diff --git a/src/lib/libstring_replace.cpp b/src/lib/libstring_replace.cpp index 88df3c91..39290656 100644 --- a/src/lib/libstring_replace.cpp +++ b/src/lib/libstring_replace.cpp @@ -1,8 +1,8 @@ -void replace(substring &str, const char *key, const char *token) { +substring &replace(substring &str, const char *key, const char *token) { int i, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str); uint replace_count = 0, size = ssl; char *data; - if(ksl > ssl)return; + if(ksl > ssl)return str; if(tsl > ksl) { //the new string may be longer than the old string... for(i=0;i<=ssl-ksl;) { //so let's find out how big of a string we'll need... if(!memcmp(str.s + i, key, ksl)) { @@ -26,15 +26,16 @@ char *data; data[z] = 0; strcpy(str, data); free(data); + return str; } -void replace(substring &str, const char *key, substring &token) { replace(str, key, strptr(token)); } +substring &replace(substring &str, const char *key, substring &token) { return replace(str, key, strptr(token)); } -void qreplace(substring &str, const char *key, const char *token) { +substring &qreplace(substring &str, const char *key, const char *token) { int i, l, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str); uint replace_count = 0, size = ssl; uint8 x; char *data; - if(ksl > ssl)return; + if(ksl > ssl)return str; if(tsl > ksl) { for(i=0;i<=ssl-ksl;) { x = str.s[i]; @@ -80,5 +81,6 @@ char *data; data[z] = 0; strcpy(str, data); free(data); + return str; } -void qreplace(substring &str, const char *key, substring &token) { qreplace(str, key, strptr(token)); } +substring &qreplace(substring &str, const char *key, substring &token) { return qreplace(str, key, strptr(token)); } diff --git a/src/lib/libstring_sprintf.cpp b/src/lib/libstring_sprintf.cpp index 0844a2b7..956fec31 100644 --- a/src/lib/libstring_sprintf.cpp +++ b/src/lib/libstring_sprintf.cpp @@ -1,69 +1,202 @@ -void numtobin(char *s, uint num) { -uint mask = 0x80000000, len = 0, z = 0; - for(;mask;mask>>=1,len++) { if(num&mask)break; } - len = 32 - len; - do { - if(num&(1<<(len-1)))s[z++] = '1'; - else s[z++] = '0'; - }while(--len); - s[z] = 0; +uint sprintf(substring &str, const char *s, ...) { +va_list args; + va_start(args, s); +uint length = vsprintf(str, s, args); + va_end(args); + return length; } -void sprintf(substring &str, const char *s, ...) { -va_list args; -char t[2], n[256]; -int i, l, sl, z; -uint8 pad_type, pad_len; -uint32 num; -char *r; - va_start(args, s); +uint vsprintf(substring &str, const char *s, va_list args) { +bool leftalign; +bool showbase; +char positivesign; +char pad; +uint width; +bool useprecision; +uint precision; +char modifier; +char type; + +uint32 vararg32; +uint64 vararg64; +char *varptr; +char varstr[256]; +uint varstrlen; + strcpy(str, ""); - for(i=0;i= '0' && s[i+2] <= '9')) { - pad_type = 1; - if(s[i+3] >= '0' && s[i+3] <= '9') { pad_len = (s[i+2]-'0')*10 + (s[i+3]-'0'); i+=4; } - else { pad_len = (s[i+2]-'0'); i+=3; } - } - else if(s[i] >= '0' && s[i] <= '9') { - pad_type = 2; - if(s[i+1] >= '0' && s[i+1] <= '9') { pad_len = (s[i]-'0')*10 + (s[i+1]-'0'); i+=2; } - else { pad_len = (s[i]-'0'); i+=1; } - } - else { pad_type = 0; } - if(s[i] == 'd') { - num = va_arg(args, uint32); - sprintf(n, "%d", num); - } else if(s[i] == 'x') { - num = va_arg(args, uint32); - sprintf(n, "%x", num); - } else if(s[i] == 'b') { - num = va_arg(args, uint32); - numtobin(n, num); - } else if(s[i] == 's') { - r = va_arg(args, char*); - } + //flags + leftalign = false; + positivesign = 0; + showbase = false; - if(pad_type != 0) { - if(s[i] == 's')sl = strlen(r); - else sl = strlen(n); - if(sl < pad_len) { - while(sl < pad_len) { - strcat(str, (pad_type == 1)?"0":" "); - sl++; - } + while(s[i]) { + if(s[i] == '-') { + leftalign = true; + i++; + } else if(s[i] == '+') { + positivesign = '+'; + i++; + } else if(s[i] == ' ') { + positivesign = ' '; + i++; + } else if(s[i] == '#') { + showbase = true; + i++; + } else { + break; } } - if(s[i] == 's')strcat(str, r); - else strcat(str, n); - } else { - t[0] = s[i]; - t[1] = 0; - strcat(str, t); + //zero padding + if(s[i] == '0') { + pad = '0'; + i++; + } else { + pad = ' '; + } + + //width + width = 0; + if(s[i] == '*') { + width = va_arg(args, uint32); + i++; + } else { + while(s[i]) { + if(s[i] < '0' || s[i] > '9')break; + width *= 10; + width += s[i++] - '0'; + } + } + if(width == 0)width = 1; + + //precision + useprecision = false; + precision = 0; + if(s[i] == '.') { + useprecision = true; + i++; + + if(s[i] == '*') { + precision = va_arg(args, uint32); + i++; + } else { + while(s[i]) { + if(s[i] < '0' || s[i] > '9')break; + precision *= 10; + precision += s[i++] - '0'; + } + } + } + if(precision == 0)precision = 1; + + //modifier + if(s[i] == 'h') { + modifier = 'h'; + i++; + } else if(s[i] == 'l') { + modifier = 'l'; + i++; + } else if(s[i] == 'L') { + modifier = 'L'; + i++; + } + + //type + type = s[i++]; + switch(type) { + + case 'c': { + //character + vararg32 = va_arg(args, uint32); + + if(leftalign == false) { while(width-- > 1)strcat(str, pad); } + strcat(str, char(vararg32)); + if(leftalign == true) { while(width-- > 1)strcat(str, pad); } + } break; + + case 's': { + //string + varptr = va_arg(args, char*); + + varstrlen = strlen(varptr); + if(useprecision && precision < varstrlen)varstrlen = precision; + if(leftalign == false) { while(width-- > varstrlen)strcat(str, pad); } + uint index = 0; + //todo: optimize to a fixed-width strcat + while(index < varstrlen)strcat(str, varptr[index++]); + if(leftalign == true) { while(width-- > varstrlen)strcat(str, pad); } + } break; + + case 'd': + case 'i': + case 'u': + case 'x': + case 'X': { + //signed integer + vararg32 = va_arg(args, uint32); + + if(type == 'd' || type == 'i') { + itoa(varstr, vararg32); + } else if(type == 'u') { + utoa(varstr, vararg32); + } else if(type == 'x') { + htoa(varstr, vararg32); + } else if(type == 'X') { + uhtoa(varstr, vararg32); + } + + uint basestrlen = strlen(varstr); + varstrlen = (useprecision && precision > basestrlen) ? precision : basestrlen; + + if(type == 'd' || type == 'i') { + if(int32(vararg32) >= 0 && positivesign) { varstrlen++; } + } + + if(type == 'x' || type == 'X') { + if(showbase) { varstrlen += 2; } + } + + if(leftalign == false) { while(width-- > varstrlen)strcat(str, pad); } + if(type == 'd' || type == 'i') { + if(int32(vararg32) >= 0 && positivesign) { strcat(str, positivesign); } + } + if(type == 'x' || type == 'X') { + if(showbase)strcat(str, (type == 'x') ? "0x" : "0X"); + } + if(useprecision) { + while(basestrlen < precision) { strcat(str, "0"); basestrlen++; } + } + strcat(str, varstr); + if(leftalign == true) { while(width-- > varstrlen)strcat(str, pad); } + } break; + + case 'p': { + //todo: add 64-bit pointer support + vararg32 = va_arg(args, uint32); + + strcpy(varstr, "00000000"); + uint index = 8; + htoa(varstr + index, vararg32); + varstrlen = strlen(varstr + index); + index -= 8 - varstrlen; + + if(leftalign == false) { while(width-- > 8)strcat(str, pad); } + strcat(str, varstr + index); + if(leftalign == true) { while(width-- > 8)strcat(str, pad); } + } break; + + } } } - va_end(args); + return strlen(str); } diff --git a/src/lib/libwin32.cpp b/src/lib/libwin32.cpp index 309878a4..a06c4d40 100644 --- a/src/lib/libwin32.cpp +++ b/src/lib/libwin32.cpp @@ -25,6 +25,9 @@ va_list args; MessageBox(0, str, "bsnes", MB_OK); } +uint GetScreenWidth() { return GetSystemMetrics(SM_CXSCREEN); } +uint GetScreenHeight() { return GetSystemMetrics(SM_CYSCREEN); } + void ShowCursor() { if(global::cursor_visible == false) { global::cursor_visible = true; diff --git a/src/lib/libwin32.h b/src/lib/libwin32.h index 5056c77c..0c3ead34 100644 --- a/src/lib/libwin32.h +++ b/src/lib/libwin32.h @@ -9,6 +9,7 @@ #define WINVER 0x0400 #define _WIN32_WINNT 0x0400 +#define _WIN32_IE 0x0400 #include #include #include @@ -27,6 +28,8 @@ Font font_default; }; void alert(char *s, ...); +uint GetScreenWidth(); +uint GetScreenHeight(); void ShowCursor(); void HideCursor(); void ParseStyleParam(const char *style, string &output); diff --git a/src/lib/opgen_s.cpp b/src/lib/opgen_s.cpp new file mode 100644 index 00000000..af2077cb --- /dev/null +++ b/src/lib/opgen_s.cpp @@ -0,0 +1,135 @@ +#include "libbase.h" +#include "libstring.h" +#include "libstring.cpp" + +FILE *fp; + +string data, line, part, subpart; +string output_op; + +struct _op_list { + string name, arg; +} op_list[64]; + +int32 op_count, line_num; + +void clear_op_list() { + op_count = 0; + for(int i = 0; i < 64; i++) { + strcpy(op_list[i].name, ""); + for(int l = 0; l < 8; l++) { + strcpy(op_list[i].arg[l], ""); + } + } +} + +void gen_begin() { +int i = line_num; +char t[4096]; + clear_op_list(); + while(1) { + int z = op_count++; + strcpy(part, line[i]); + strrtrim(part, "),"); + strrtrim(part, ") {"); + split(subpart, "(", part); + strcpy(op_list[z].name, subpart[0]); + split(part, ", ", subpart[1]); + for(int l = 0; l < count(part); l++) { + strcpy(op_list[z].arg[l], part[l]); + } + if(strend(line[i], " {"))break; + i++; + } + + strcpy(output_op, "//$$\r\ncase $0: {\r\n"); + line_num = i + 1; +} + +void update_line(int i) { + replace(line[i], "end;", "break;"); +} + +void gen_op() { +int i = line_num, n, c; +char t[4096]; + while(1) { + if(strmatch(line[i], "}"))break; + + //remove cycle number + n = strdec(line[i]); + sprintf(t, "%d:", n); + strltrim(line[i], t); + //sprintf(t, "//%d:\r\n", n); + //strcat(output_op, t); + + update_line(i); + if(!strmatch(line[i], "")) { + strcat(output_op, " "); + strcat(output_op, line[i]); + strcat(output_op, "\r\n"); + } + + i++; + while(1) { + if(strptr(line[i])[1] == ':' || strptr(line[i])[2] == ':' || strmatch(line[i], "}"))break; + + update_line(i); + strcat(output_op, line[i]); + strcat(output_op, "\r\n"); + + i++; + } + } + + strcat(output_op, "} break;"); + line_num = i + 1; +} + +void gen_end() { +string t; + for(int i = 0; i < op_count; i++) { + strcpy(t, output_op); + replace(t, "$$", op_list[i].name); + replace(t, "$0", op_list[i].arg[0]); + replace(t, "$1", op_list[i].arg[1]); + replace(t, "$2", op_list[i].arg[2]); + replace(t, "$3", op_list[i].arg[3]); + replace(t, "$4", op_list[i].arg[4]); + replace(t, "$5", op_list[i].arg[5]); + replace(t, "$6", op_list[i].arg[6]); + replace(t, "$7", op_list[i].arg[7]); + fprintf(fp, "%s\r\n\r\n", strptr(t)); + } +} + +void generate(char *dest, char *src) { + fp = fopen(src, "rb"); + + fseek(fp, 0, SEEK_END); +int fsize = ftell(fp); + fseek(fp, 0, SEEK_SET); +char *buf = (char*)malloc(fsize + 1); + fread(buf, 1, fsize, fp); + fclose(fp); + buf[fsize] = 0; + + strcpy(data, buf); + free(buf); + replace(data, "\r\n", "\n"); + split(line, "\n", data); + + fp = fopen(dest, "wb"); + + line_num = 0; + while(line_num < count(line)) { + while(strmatch(line[line_num], "") && line_num < count(line))line_num++; + if(line_num >= count(line))break; + + gen_begin(); + gen_op(); + gen_end(); + } + + fclose(fp); +} diff --git a/src/lib/opgen_so.cpp b/src/lib/opgen_so.cpp new file mode 100644 index 00000000..c8acd0a3 --- /dev/null +++ b/src/lib/opgen_so.cpp @@ -0,0 +1,147 @@ +#include "libbase.h" +#include "libstring.h" +#include "libstring.cpp" + +FILE *fp, *fph, *fpt; + +string data, line, part, subpart; +string output_table, output_header, output_op; + +struct _op_list { + string name, arg; +} op_list[64]; + +int32 op_count, line_num; + +void clear_op_list() { + op_count = 0; + for(int i = 0; i < 64; i++) { + strcpy(op_list[i].name, ""); + for(int l = 0; l < 8; l++) { + strcpy(op_list[i].arg[l], ""); + } + } +} + +void gen_header() { +int i = line_num; +char t[4096]; + clear_op_list(); + while(1) { + int z = op_count++; + strcpy(part, line[i]); + strrtrim(part, "),"); + strrtrim(part, ") {"); + split(subpart, "(", part); + strcpy(op_list[z].name, subpart[0]); + split(part, ", ", subpart[1]); + for(int l = 0; l < count(part); l++) { + strcpy(op_list[z].arg[l], part[l]); + } + if(strend(line[i], " {"))break; + i++; + } + + sprintf(output_op, "void " CLASS_NAME "::op_$$() {\r\n"); + sprintf(output_header, "void op_$$();\r\n"); + sprintf(output_table, "optbl[$0] = &" CLASS_NAME "::op_$$;\r\n"); + + line_num = i + 1; +} + +void update_line(int i) { +char t[4096]; + replace(line[i], "end;", "return;"); +} + +void gen_op() { +int i = line_num, n, c; +char t[4096]; + while(1) { + if(strmatch(line[i], "}"))break; + + n = strdec(line[i]); + sprintf(t, "%d:", n); + strltrim(line[i], t); + //sprintf(t, " case %d: {\r\n", n); + //strcat(output_op, t); + + update_line(i); + if(!strmatch(line[i], "")) { + strcat(output_op, " "); + strcat(output_op, line[i]); + strcat(output_op, "\r\n"); + } + + i++; + while(1) { + if(strptr(line[i])[1] == ':' || strptr(line[i])[2] == ':' || strmatch(line[i], "}"))break; + + update_line(i); + strcat(output_op, line[i]); + strcat(output_op, "\r\n"); + + i++; + } + } + + strcat(output_op, "}"); + line_num = i + 1; +} + +void gen_final() { +string t; + for(int i = 0; i < op_count; i++) { + strcpy(t, output_op); + replace(t, "$$", op_list[i].name); + replace(t, "$0", op_list[i].arg[0]); + replace(t, "$1", op_list[i].arg[1]); + replace(t, "$2", op_list[i].arg[2]); + replace(t, "$3", op_list[i].arg[3]); + replace(t, "$4", op_list[i].arg[4]); + replace(t, "$5", op_list[i].arg[5]); + replace(t, "$6", op_list[i].arg[6]); + replace(t, "$7", op_list[i].arg[7]); + fprintf(fp, "%s\r\n\r\n", strptr(t)); + + strcpy(t, output_header); + replace(t, "$$", op_list[i].name); + fprintf(fph, "%s", strptr(t)); + + strcpy(t, output_table); + replace(t, "$$", op_list[i].name); + replace(t, "$0", op_list[i].arg[0]); + fprintf(fpt, "%s", strptr(t)); + } +} + +void generate(char *dest, char *src) { + fp = fopen(src, "rb"); + + fseek(fp, 0, SEEK_END); +int fsize = ftell(fp); + fseek(fp, 0, SEEK_SET); +char *buf = (char*)malloc(fsize + 1); + fread(buf, 1, fsize, fp); + fclose(fp); + buf[fsize] = 0; + + strcpy(data, buf); + free(buf); + replace(data, "\r\n", "\n"); + split(line, "\n", data); + + fp = fopen(dest, "wb"); + + line_num = 0; + while(line_num < count(line)) { + while(strmatch(line[line_num], "") && line_num < count(line))line_num++; + if(line_num >= count(line))break; + + gen_header(); + gen_op(); + gen_final(); + } + + fclose(fp); +} diff --git a/src/memory/bmemory/bmemory.cpp b/src/memory/bmemory/bmemory.cpp index 26554b35..f53a637b 100644 --- a/src/memory/bmemory/bmemory.cpp +++ b/src/memory/bmemory/bmemory.cpp @@ -16,19 +16,27 @@ char t[256]; if(cartridge.cart.srtc)strcat(t, "S-RTC, "); if(cartridge.cart.sdd1)strcat(t, "S-DD1, "); if(cartridge.cart.c4) strcat(t, "Cx4, "); + if(cartridge.cart.dsp1)strcat(t, "DSP-1, "); if(cartridge.cart.dsp2)strcat(t, "DSP-2, "); if(cartridge.cart.obc1)strcat(t, "OBC-1, "); strrtrim(t, ", "); dprintf("* Coprocessor(s) : %s", (strlen(t) == 0) ? "None" : t); - dprintf("* Reset:%0.4x NMI:%0.4x IRQ:%0.4x BRK[n]:%0.4x COP[n]:%0.4x BRK[e]:%0.4x COP[e]:%0.4x", - rom[index + 0x3c] | (rom[index + 0x3d] << 8), //Reset - rom[index + 0x2a] | (rom[index + 0x2b] << 8), //NMI - rom[index + 0x2e] | (rom[index + 0x2f] << 8), //IRQ - rom[index + 0x26] | (rom[index + 0x27] << 8), //BRK[n] - rom[index + 0x24] | (rom[index + 0x25] << 8), //COP[n] - rom[index + 0x3e] | (rom[index + 0x3f] << 8), //BRK[e] - rom[index + 0x34] | (rom[index + 0x35] << 8) //COP[e] + dprintf("* Reset:%0.4x NMI[n]:%0.4x IRQ[n]:%0.4x BRK[n]:%0.4x COP[n]:%0.4x", + read16(rom, index + 0x3c), //Reset + read16(rom, index + 0x2a), //NMI + read16(rom, index + 0x2e), //IRQ + read16(rom, index + 0x26), //BRK + read16(rom, index + 0x24) //COP ); +//BRK[e] should be $fff6, however emulation mode brk is technically not supported. +//this needs verification, but I believe brk jumps to IRQ[e] vector. + dprintf("* NMI[e]:%0.4x IRQ[e]:%0.4x BRK[e]:%0.4x COP[e]:%0.4x", + read16(rom, index + 0x3a), //NMI + read16(rom, index + 0x3e), //IRQ + read16(rom, index + 0x3e), //BRK + read16(rom, index + 0x34) //COP + ); + dprintf("* CRC32 : %0.8x", cartridge.cart.crc32); dprintf(""); cart_map_reset(); @@ -46,6 +54,7 @@ char t[256]; if(cartridge.cart.sdd1)cart_map_sdd1(); if(cartridge.cart.c4) cart_map_c4(); + if(cartridge.cart.dsp1)cart_map_dsp1(); if(cartridge.cart.dsp2)cart_map_dsp2(); if(cartridge.cart.obc1)cart_map_obc1(); diff --git a/src/memory/bmemory/bmemory.h b/src/memory/bmemory/bmemory.h index 2485e8e4..fbf519a1 100644 --- a/src/memory/bmemory/bmemory.h +++ b/src/memory/bmemory/bmemory.h @@ -33,6 +33,8 @@ enum { TYPE_WRAM, TYPE_MMIO, TYPE_CART }; void write_sdd1 (uint32 addr, uint8 data); uint8 read_c4 (uint32 addr); void write_c4 (uint32 addr, uint8 data); + uint8 read_dsp1 (uint32 addr); + void write_dsp1 (uint32 addr, uint8 data); uint8 read_dsp2 (uint32 addr); void write_dsp2 (uint32 addr, uint8 data); uint8 read_obc1 (uint32 addr); @@ -44,6 +46,7 @@ enum { TYPE_WRAM, TYPE_MMIO, TYPE_CART }; void cart_map_sdd1(); void cart_map_c4(); + void cart_map_dsp1(); void cart_map_dsp2(); void cart_map_obc1(); diff --git a/src/memory/bmemory/bmemory_mapper_generic.cpp b/src/memory/bmemory/bmemory_mapper_generic.cpp index 0cda00a8..f4c55914 100644 --- a/src/memory/bmemory/bmemory_mapper_generic.cpp +++ b/src/memory/bmemory/bmemory_mapper_generic.cpp @@ -1,3 +1,19 @@ +/***** + * Generic LoROM / HiROM / ExHiROM / ExLoROM mapping + * + * Must map the following regions : + * $[00-3f]:[6000-ffff] + * $[40-7d]:[0000-ffff] + * $[80-bf]:[6000-ffff] + * $[c0-ff]:[0000-ffff] + * + * The following regions will be ignored / overwritten : + * $[00-3f]:[0000-1fff] WRAM + * $[00-3f]:[2000-5fff] MMIO + * $[7e-7f]:[0000-ffff] WRAM + * $[80-bf]:[0000-1fff] WRAM + * $[80-bf]:[2000-5fff] MMIO + *****/ void bMemBus::cart_map_generic(uint type) { uint32 P0_size, P1_size, ROM_mask, ROM_size, SRAM_size; ROM_size = cartridge.cart.rom_size; @@ -26,6 +42,12 @@ uint32 P0_size, P1_size, ROM_mask, ROM_size, SRAM_size; //layout I can create using only ROM header information. Additional accuracy //requires PCB identification. + //Unmapped region + //$[00-1f|80-9f]:[6000-7fff] + if((bank & 0x7f) >= 0x00 && (bank & 0x7f) <= 0x1f && (addr & 0xe000) == 0x6000) { + continue; + } + //HiROM SRAM region //$[20-3f|a0-bf]:[6000-7fff] if((bank & 0x7f) >= 0x20 && (bank & 0x7f) <= 0x3f && (addr & 0xe000) == 0x6000) { @@ -41,7 +63,7 @@ uint32 P0_size, P1_size, ROM_mask, ROM_size, SRAM_size; //LoROM SRAM region //$[70-7f|f0-ff]:[0000-7fff] - //Note: RAM is remapped over $[7e-7f]:[0000-ffff] + //Note: WRAM is remapped over $[7e-7f]:[0000-ffff] if((bank & 0x7f) >= 0x70 && (bank & 0x7f) <= 0x7f && (addr & 0x8000) == 0x0000) { if(SRAM_size == 0)continue; @@ -118,6 +140,34 @@ void bMemBus::cart_map_c4() { } } +void bMemBus::cart_map_dsp1() { + if(cartridge.cart.dsp1_mapper == Cartridge::DSP1_LOROM_1MB) { + //$[20-3f]:[8000-ffff] + for(uint bank = 0x20; bank <= 0x3f; bank++) { + for(uint page = 0x80; page <= 0xff; page++) { + page_read [(bank << 8) + page] = &bMemBus::read_dsp1; + page_write[(bank << 8) + page] = &bMemBus::write_dsp1; + } + } + } else if(cartridge.cart.dsp1_mapper == Cartridge::DSP1_LOROM_2MB) { + //$[60-6f]:[0000-7fff] + for(uint bank = 0x60; bank <= 0x6f; bank++) { + for(uint page = 0x00; page <= 0x7f; page++) { + page_read [(bank << 8) + page] = &bMemBus::read_dsp1; + page_write[(bank << 8) + page] = &bMemBus::write_dsp1; + } + } + } else if(cartridge.cart.dsp1_mapper == Cartridge::DSP1_HIROM) { + //$[00-1f]:[6000-7fff] + for(uint bank = 0x00; bank <= 0x1f; bank++) { + for(uint page = 0x60; page <= 0x7f; page++) { + page_read [(bank << 8) + page] = &bMemBus::read_dsp1; + page_write[(bank << 8) + page] = &bMemBus::write_dsp1; + } + } + } +} + void bMemBus::cart_map_dsp2() { //$[20-3f]:[6000-6fff|8000-bfff] for(uint bank = 0x20; bank <= 0x3f; bank++) { diff --git a/src/memory/bmemory/bmemory_rw.cpp b/src/memory/bmemory/bmemory_rw.cpp index 4e18d41d..99fac6e8 100644 --- a/src/memory/bmemory/bmemory_rw.cpp +++ b/src/memory/bmemory/bmemory_rw.cpp @@ -54,6 +54,9 @@ void bMemBus::write_sdd1(uint32 addr, uint8 data) { uint8 bMemBus::read_c4 (uint32 addr) { return c4->read(addr); } void bMemBus::write_c4(uint32 addr, uint8 data) { c4->write(addr, data); } +uint8 bMemBus::read_dsp1 (uint32 addr) { return dsp1->read(addr); } +void bMemBus::write_dsp1(uint32 addr, uint8 data) { dsp1->write(addr, data); } + uint8 bMemBus::read_dsp2 (uint32 addr) { return dsp2->read(addr); } void bMemBus::write_dsp2(uint32 addr, uint8 data) { dsp2->write(addr, data); } diff --git a/src/memory/memory.h b/src/memory/memory.h index da6af50f..805f6270 100644 --- a/src/memory/memory.h +++ b/src/memory/memory.h @@ -29,9 +29,9 @@ private: uint8 *speed_table, speed_table_slowrom[32768], speed_table_fastrom[32768]; - inline uint8 calc_speed(uint32 addr, bool fast); + uint8 calc_speed(uint32 addr, bool fast); public: - inline uint8 speed(uint32 addr) { return speed_table[addr >> 9]; } + uint8 speed(uint32 addr) { return speed_table[addr >> 9]; } void set_speed(bool fast); virtual void load_cart() = 0; diff --git a/src/ppu/bppu/bppu_mmio.cpp b/src/ppu/bppu/bppu_mmio.cpp index d90eddf9..440f9085 100644 --- a/src/ppu/bppu/bppu_mmio.cpp +++ b/src/ppu/bppu/bppu_mmio.cpp @@ -23,18 +23,14 @@ bool bPPU::vram_can_read() { uint16 v = r_cpu->vcounter(); uint16 hc = r_cpu->hcycles(); -uint16 ls; - if(r_cpu->interlace() && !r_cpu->interlace_field()) { - ls = r_cpu->region_scanlines(); - } else { - ls = r_cpu->region_scanlines() - 1; - } +uint16 ls = (r_cpu->region_scanlines() >> 1) - 1; + if(r_cpu->interlace() && !r_cpu->interlace_field())ls++; if(v == ls && hc == 1362)return false; - if(v < (r_cpu->overscan() ? 239 : 224))return false; + if(v < (!r_cpu->overscan() ? 224 : 239))return false; - if(v == (r_cpu->overscan() ? 239 : 224)) { + if(v == (!r_cpu->overscan() ? 224 : 239)) { if(hc == 1362)return true; return false; } diff --git a/src/ppu/bppu/bppu_render.h b/src/ppu/bppu/bppu_render.h index 87bbb79f..7e7de347 100644 --- a/src/ppu/bppu/bppu_render.h +++ b/src/ppu/bppu/bppu_render.h @@ -44,8 +44,9 @@ void build_window_tables(uint8 bg); //bppu_render_bg.cpp struct { - uint16 tw, th; //tile width, height - uint16 mx, my; //screen mask x, y + uint16 tw, th; //tile width, height + uint16 mx, my; //screen mask x, y + uint16 scx, scy; //sc index offsets } bg_info[4]; inline void update_bg_info(); diff --git a/src/ppu/bppu/bppu_render_bg.cpp b/src/ppu/bppu/bppu_render_bg.cpp index f9f99014..d5a7d400 100644 --- a/src/ppu/bppu/bppu_render_bg.cpp +++ b/src/ppu/bppu/bppu_render_bg.cpp @@ -3,26 +3,27 @@ void bPPU::update_bg_info() { for(int bg = 0; bg < 4; bg++) { bg_info[bg].th = (regs.bg_tilesize[bg]) ? 4 : 3; bg_info[bg].tw = (regs.hires) ? 4 : bg_info[bg].th; + bg_info[bg].mx = (bg_info[bg].th == 4) ? (line.width << 1) : line.width; bg_info[bg].my = bg_info[bg].mx; if(regs.bg_scsize[bg] & 0x01)bg_info[bg].mx <<= 1; if(regs.bg_scsize[bg] & 0x02)bg_info[bg].my <<= 1; bg_info[bg].mx--; bg_info[bg].my--; + + bg_info[bg].scy = (regs.bg_scsize[bg] & 0x02) ? (32 << 5) : 0; + bg_info[bg].scx = (regs.bg_scsize[bg] & 0x01) ? (32 << 5) : 0; + if(regs.bg_scsize[bg] == 3)bg_info[bg].scy <<= 1; } } uint16 bPPU::bg_get_tile(uint8 bg, uint16 x, uint16 y) { -uint16 pos; - x &= bg_info[bg].mx; - y &= bg_info[bg].my; + x = (x & bg_info[bg].mx) >> bg_info[bg].tw; + y = (y & bg_info[bg].my) >> bg_info[bg].th; - x >>= bg_info[bg].tw; - y >>= bg_info[bg].th; - - pos = (regs.bg_scsize[bg] & 2) ? ((y & 0x20) << ((regs.bg_scsize[bg] & 1) ? 6 : 5)) : 0; - pos += (regs.bg_scsize[bg] & 1) ? ((x & 0x20) << 5) : 0; - pos += ((y & 31) << 5) + (x & 31); +uint16 pos = ((y & 0x1f) << 5) + (x & 0x1f); + if(y & 0x20)pos += bg_info[bg].scy; + if(x & 0x20)pos += bg_info[bg].scx; return read16(vram, regs.bg_scaddr[bg] + (pos << 1)); } @@ -56,11 +57,11 @@ void bPPU::render_line_bg(uint8 bg, uint8 color_depth, uint8 pri0_pos, uint8 pri bool bg_enabled = regs.bg_enabled[bg]; bool bgsub_enabled = regs.bgsub_enabled[bg]; -uint16 opt_valid_bit = (bg == BG1) ? 0x2000 : ((bg == BG2) ? 0x4000 : 0x0000); +uint16 opt_valid_bit = (bg == BG1) ? 0x2000 : (bg == BG2) ? 0x4000 : 0x0000; uint8 bgpal_index = (regs.bg_mode == 0) ? (bg << 5) : 0; -uint8 pal_size = (color_depth == 2) ? 256 : ((color_depth == 1) ? 16 : 4); -uint16 tile_mask = (color_depth == 2) ? 0x03ff : ((color_depth == 1) ? 0x07ff : 0x0fff); +uint8 pal_size = 2 << color_depth; //<<2 (*4), <<4 (*16), <<8 (*256) +uint16 tile_mask = 0x0fff >> color_depth; //0x0fff, 0x07ff, 0x03ff //4 + color_depth = >>(4-6) -- / {16, 32, 64 } bytes/tile //index is a tile number count to add to base tile number uint tiledata_index = regs.bg_tdaddr[bg] >> (4 + color_depth); @@ -95,7 +96,7 @@ uint8 *tile_ptr; uint xpos, ypos; uint16 hoffset, voffset, opt_x, col; bool mirror_x, mirror_y; -bool is_opt_mode = (config::ppu.opt_enable) && (regs.bg_mode == 2 || regs.bg_mode == 4 || regs.bg_mode == 6); +bool is_opt_mode = (config::ppu.opt_enable == true) && (regs.bg_mode == 2 || regs.bg_mode == 4 || regs.bg_mode == 6); build_window_tables(bg); uint8 *wt_main = window[bg].main; @@ -170,7 +171,7 @@ int32 prev_x = -1, prev_y = -1; } pal_num = ((t >> 10) & 7); - pal_index = (pal_num * pal_size) + bgpal_index; + pal_index = bgpal_index + (pal_num << pal_size); ypos = mosaic_y & 7; if(mirror_y)ypos ^= 7; //invert y tile pos diff --git a/src/ppu/bppu/bppu_render_mode7.cpp b/src/ppu/bppu/bppu_render_mode7.cpp index a396df8a..6d09416e 100644 --- a/src/ppu/bppu/bppu_render_mode7.cpp +++ b/src/ppu/bppu/bppu_render_mode7.cpp @@ -25,16 +25,15 @@ void bPPU::render_line_mode7(uint8 bg, uint8 pri0_pos, uint8 pri1_pos) { int32 px, py; int32 tx, ty, tile, palette; -int32 a = int32(int16(regs.m7a)); -int32 b = int32(int16(regs.m7b)); -int32 c = int32(int16(regs.m7c)); -int32 d = int32(int16(regs.m7d)); +int32 a = sclip<15>(regs.m7a); //int32(int16(regs.m7a)); +int32 b = sclip<15>(regs.m7b); //int32(int16(regs.m7b)); +int32 c = sclip<15>(regs.m7c); //int32(int16(regs.m7c)); +int32 d = sclip<15>(regs.m7d); //int32(int16(regs.m7d)); -int32 cx = (int32(regs.m7x) << 19) >> 19; -int32 cy = (int32(regs.m7y) << 19) >> 19; -int32 hofs = (int32(regs.m7_hofs) << 19) >> 19; -//+1 breaks FF5 title screen mirror alignment... -int32 vofs = (int32(regs.m7_vofs + 0) << 19) >> 19; +int32 cx = sclip<13>(regs.m7x); //(int32(regs.m7x) << 19) >> 19; +int32 cy = sclip<13>(regs.m7y); //(int32(regs.m7y) << 19) >> 19; +int32 hofs = sclip<13>(regs.m7_hofs); //(int32(regs.m7_hofs) << 19) >> 19; +int32 vofs = sclip<13>(regs.m7_vofs); //(int32(regs.m7_vofs + 0) << 19) >> 19; int _pri, _x; bool _bg_enabled = regs.bg_enabled[bg]; @@ -59,6 +58,10 @@ uint16 *mtable_x, *mtable_y; int32 psx = ((a * CLIP(hofs - cx)) & ~63) + ((b * CLIP(vofs - cy)) & ~63) + ((b * mtable_y[y]) & ~63) + (cx << 8); int32 psy = ((c * CLIP(hofs - cx)) & ~63) + ((d * CLIP(vofs - cy)) & ~63) + ((d * mtable_y[y]) & ~63) + (cy << 8); +//suggestion by TRAC, difference can be no greater than 1 bit (due to rounding) from above, +//but verification would be good... +//int32 psx = ((a * CLIP(hofs - cx)) & ~63) + ((b * (CLIP(vofs - cy) + mtable_y[y])) & ~63) + (cx << 8); +//int32 psy = ((c * CLIP(hofs - cx)) & ~63) + ((d * (CLIP(vofs - cy) + mtable_y[y])) & ~63) + (cy << 8); for(int32 x = 0; x < 256; x++) { px = psx + (a * mtable_x[x]); py = psy + (c * mtable_x[x]); diff --git a/src/ppu/bppu/bppu_render_oam.cpp b/src/ppu/bppu/bppu_render_oam.cpp index 9bb31884..7d71961d 100644 --- a/src/ppu/bppu/bppu_render_oam.cpp +++ b/src/ppu/bppu/bppu_render_oam.cpp @@ -26,9 +26,12 @@ uint8 *tableA = oam, *tableB = oam + 512; break; case 6: sprite_list[i].width = (!size) ? 16 : 32; sprite_list[i].height = (!size) ? 32 : 64; + if(regs.oam_interlace && !size)sprite_list[i].height = 16; + //32x64 height is not affected by oam_interlace setting break; case 7: sprite_list[i].width = (!size) ? 16 : 32; sprite_list[i].height = (!size) ? 32 : 32; + if(regs.oam_interlace && !size)sprite_list[i].height = 16; break; } @@ -48,40 +51,35 @@ uint8 *tableA = oam, *tableB = oam + 512; bool bPPU::is_sprite_on_scanline() { //if sprite is entirely offscreen and doesn't wrap around to the left side of the screen, -//then it is not counted. 256 is correct, and not 255 -- as one might first expect - if(spr->x > 256 && (spr->x + spr->width) < 512)return false; - - if(regs.oam_interlace == false) { - if(line.y >= spr->y && line.y < (spr->y + spr->height)) { - return true; - } else if((spr->y + spr->height) >= 256 && line.y < ((spr->y + spr->height) & 255)) { - return true; - } - } else { - if(line.y >= spr->y && line.y < (spr->y + (spr->height >> 1))) { - return true; - } else if((spr->y + (spr->height >> 1)) >= 256 && line.y < ((spr->y + (spr->height >> 1)) & 255)) { - return true; - } - } +//then it is not counted. this *should* be 256, and not 255, even though dot 256 is offscreen. + if(spr->x > 256 && (spr->x + spr->width - 1) < 512)return false; +int spr_height = (regs.oam_interlace == false) ? (spr->height) : (spr->height >> 1); + if(line.y >= spr->y && line.y < (spr->y + spr_height))return true; + if((spr->y + spr_height) >= 256 && line.y < ((spr->y + spr_height) & 255))return true; return false; } void bPPU::load_oam_tiles() { uint16 tile_width = spr->width >> 3; int x = spr->x; -int y = (spr->vflip) ? ((spr->height - 1) - (line.y - spr->y)) : (line.y - spr->y); - -//todo: verify below code is hardware-accurate -//specifically, is interlace_field added for oam_interlace mode? +int y = line.y - spr->y; if(regs.oam_interlace == true) { y <<= 1; - if(line.interlace && line.width == 512) { - y += line.interlace_field; + } + + if(spr->vflip == true) { + if(spr->width == spr->height) { + y = (spr->height - 1) - y; + } else { + y = (y < spr->width) ? ((spr->width - 1) - y) : (spr->width + ((spr->width - 1) - (y - spr->width))); } } + if(regs.oam_interlace == true) { + y = (spr->vflip == false) ? (y + line.interlace_field) : (y - line.interlace_field); + } + x &= 511; y &= 255; @@ -95,47 +93,39 @@ uint16 chry = (spr->character >> 4) & 15; chry &= 15; chry <<= 4; -int i, n, sx, mx, pos; - for(i=0;i= 257 && (sx + 7) < 512)continue; + for(uint tx = 0; tx < tile_width; tx++) { + uint sx = (x + (tx << 3)) & 511; + if(sx > 256 && (sx + 7) < 512)continue; //ignore sprites that are offscreen if(regs.oam_tilecount++ > 34)break; - n = regs.oam_tilecount - 1; + uint n = regs.oam_tilecount - 1; oam_tilelist[n].x = sx; oam_tilelist[n].y = y; oam_tilelist[n].pri = spr->priority; - oam_tilelist[n].pal = (spr->palette << 4) + 128; + oam_tilelist[n].pal = 128 + (spr->palette << 4); oam_tilelist[n].hflip = spr->hflip; - mx = (oam_tilelist[n].hflip) ? ((tile_width - 1) - i) : i; - pos = tdaddr + ((chry + ((chrx + mx) & 15)) << 5); + uint mx = (spr->hflip == false) ? tx : ((tile_width - 1) - tx); + uint pos = tdaddr + ((chry + ((chrx + mx) & 15)) << 5); oam_tilelist[n].tile = (pos >> 5) & 0x07ff; } } void bPPU::render_oam_tile(int tile_num) { -uint8 *oam_td, *oam_td_state, *tile_ptr; -oam_tileitem *t = &oam_tilelist[tile_num]; - oam_td = (uint8*)bg_tiledata[COLORDEPTH_16]; - oam_td_state = (uint8*)bg_tiledata_state[COLORDEPTH_16]; +oam_tileitem *t = &oam_tilelist[tile_num]; +uint8 *oam_td = (uint8*)bg_tiledata[COLORDEPTH_16]; +uint8 *oam_td_state = (uint8*)bg_tiledata_state[COLORDEPTH_16]; if(oam_td_state[t->tile] == 1) { render_bg_tile(COLORDEPTH_16, t->tile); } -int x, sx, col; - sx = t->x; - tile_ptr = (uint8*)oam_td + (t->tile << 6) + ((t->y & 7) << 3); - for(x=0;x<8;x++) { +uint sx = t->x; +uint8 *tile_ptr = (uint8*)oam_td + (t->tile << 6) + ((t->y & 7) << 3); + for(uint x = 0; x < 8; x++) { sx &= 511; if(sx < 256) { - col = *(tile_ptr + ((t->hflip) ? (7 - x) : x)); + uint col = *(tile_ptr + ((t->hflip == false) ? x : (7 - x))); if(col) { col += t->pal; oam_line_pal[sx] = col; @@ -152,8 +142,9 @@ void bPPU::render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 regs.oam_itemcount = 0; regs.oam_tilecount = 0; memset(oam_line_pri, OAM_PRI_NONE, 256); - memset(oam_itemlist, 0xff, 32); + for(int s = 0; s < 34; s++)oam_tilelist[s].tile = 0xffff; + for(int s = 0; s < 128; s++) { spr = &sprite_list[(s + regs.oam_firstsprite) & 127]; if(is_sprite_on_scanline() == false)continue; @@ -161,8 +152,6 @@ void bPPU::render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 oam_itemlist[regs.oam_itemcount - 1] = (s + regs.oam_firstsprite) & 127; } - for(int s = 0; s < 34; s++)oam_tilelist[s].tile = 0xffff; - for(int s = 31; s >= 0; s--) { if(oam_itemlist[s] == 0xff)continue; spr = &sprite_list[oam_itemlist[s]]; @@ -213,17 +202,11 @@ bool bgsub_enabled = regs.bgsub_enabled[OAM]; uint8 *wt_main = window[OAM].main; uint8 *wt_sub = window[OAM].sub; -int pri; +int pri_tbl[4] = { pri0_pos, pri1_pos, pri2_pos, pri3_pos }; for(int x = 0; x < 256; x++) { if(oam_line_pri[x] == OAM_PRI_NONE)continue; - switch(oam_line_pri[x]) { - case 0: pri = pri0_pos; break; - case 1: pri = pri1_pos; break; - case 2: pri = pri2_pos; break; - case 3: pri = pri3_pos; break; - } - + int pri = pri_tbl[oam_line_pri[x]]; if(bg_enabled == true && !wt_main[x]) { setpixel_main(x); } if(bgsub_enabled == true && !wt_sub[x]) { setpixel_sub(x); } } diff --git a/src/sdl/Makefile b/src/sdl/Makefile index 0afba2ea..c49a9f84 100644 --- a/src/sdl/Makefile +++ b/src/sdl/Makefile @@ -4,14 +4,14 @@ CFLAGS = -O3 -fomit-frame-pointer -ffast-math CXXFLAGS = $(CFLAGS) -fno-rtti OBJS = sdlmain.o \ libstring.o libconfig.o libbpf.o \ - reader.o cart.o cheat.o \ + reader.o cart.o \ memory.o bmemory.o \ cpu.o bcpu.o \ apu.o bapu.o \ bdsp.o \ ppu.o bppu.o \ snes.o \ - srtc.o sdd1.o c4.o dsp2.o obc1.o \ + srtc.o sdd1.o c4.o \ adler32.o compress.o crc32.o deflate.o gzio.o inffast.o \ inflate.o inftrees.o ioapi.o trees.o unzip.o zip.o zutil.o \ jma.o jcrc32.o lzmadec.o 7zlzma.o iiostrm.o inbyte.o lzma.o winout.o @@ -89,9 +89,6 @@ reader.o: ../reader/*.cpp ../reader/*.h cart.o: ../cart/*.cpp ../cart/*.h $(CXX) $(CXXFLAGS) -c ../cart/cart.cpp -cheat.o: ../cheat/*.cpp ../cheat/*.h - $(CXX) $(CXXFLAGS) -c ../cheat/cheat.cpp - ############ ### snes ### ############ @@ -110,12 +107,6 @@ sdd1.o: ../chip/sdd1/*.cpp ../chip/sdd1/*.h c4.o: ../chip/c4/*.cpp ../chip/c4/*.h $(CXX) $(CXXFLAGS) -c ../chip/c4/c4.cpp -dsp2.o: ../chip/dsp2/*.cpp ../chip/dsp2/*.h - $(CXX) $(CXXFLAGS) -c ../chip/dsp2/dsp2.cpp - -obc1.o: ../chip/obc1/*.cpp ../chip/obc1/*.h - $(CXX) $(CXXFLAGS) -c ../chip/obc1/obc1.cpp - ############ ### zlib ### ############ diff --git a/src/sdl/Makefile.win32 b/src/sdl/Makefile.win32 index c230f138..f25aff99 100644 --- a/src/sdl/Makefile.win32 +++ b/src/sdl/Makefile.win32 @@ -1,5 +1,5 @@ CC = cl -CFLAGS = /nologo /O2 /EHsc /wd4996 +CFLAGS = /nologo /O2 /EHsc OBJS = sdlmain.obj \ libstring.obj libconfig.obj libbpf.obj \ reader.obj cart.obj \ diff --git a/src/sdl/bsnes_sdl.cfg b/src/sdl/bsnes_sdl.cfg new file mode 100644 index 00000000..cc1ac3db --- /dev/null +++ b/src/sdl/bsnes_sdl.cfg @@ -0,0 +1,98 @@ +# Default path to look for ROM files in ("" = use default directory) +# (default = "") +fs.rom_path = "" + +# Default path for all save RAM files ("" = use current directory) +# (default = "") +fs.sram_path = "" + +# Extension to be used for all save RAM files +# (default = "srm") +fs.sram_ext = "srm" + +# Applies contrast adjust filter to video output when enabled +# Works by lowering the brightness of darker colors, +# while leaving brighter colors alone; thus reducing saturation +# (default = true) +snes.video_color_curve = true + +# Selects color adjustment filter for video output +# 0 = Normal (no filter, rgb555) +# 1 = Grayscale mode (l5) +# 2 = VGA mode (rgb332) +# 3 = Genesis mode (rgb333) +# (default = 0) +snes.video_color_adjust_mode = 0 + +# Mutes SNES audio output when enabled +# (default = false) +snes.mute = true + +# Enable fullscreen mode at startup +# (default = false) +video.fullscreen = false + +# Window / Fullscreen width +# (default = 320) +video.display_width = 320 + +# Window / Fullscreen height +# (default = 240) +video.display_height = 240 + +# SNES video output width +# (default = 256) +video.output_width = 256 + +# SNES video output height +# (default = 223) +video.output_height = 223 + +# Joypad1 up +# (default = 0x111) +input.joypad1.up = 0x111 + +# Joypad1 down +# (default = 0x112) +input.joypad1.down = 0x112 + +# Joypad1 left +# (default = 0x114) +input.joypad1.left = 0x114 + +# Joypad1 right +# (default = 0x113) +input.joypad1.right = 0x113 + +# Joypad1 A +# (default = 0x78) +input.joypad1.a = 0x78 + +# Joypad1 B +# (default = 0x7a) +input.joypad1.b = 0x7a + +# Joypad1 X +# (default = 0x73) +input.joypad1.x = 0x73 + +# Joypad1 Y +# (default = 0x61) +input.joypad1.y = 0x61 + +# Joypad1 L +# (default = 0x64) +input.joypad1.l = 0x64 + +# Joypad1 R +# (default = 0x63) +input.joypad1.r = 0x63 + +# Joypad1 select +# (default = 0x12f) +input.joypad1.select = 0x12f + +# Joypad1 start +# (default = 0xd) +input.joypad1.start = 0xd + diff --git a/src/sdl/sdlmain.cpp b/src/sdl/sdlmain.cpp index ff05cace..317829f9 100644 --- a/src/sdl/sdlmain.cpp +++ b/src/sdl/sdlmain.cpp @@ -122,9 +122,9 @@ SDL_Event event; atexit(SDL_Quit); set_window_info(); screen = SDL_SetVideoMode(config::video.display_width, config::video.display_height, 16, - SDL_SWSURFACE | ((config::video.fullscreen) ? SDL_FULLSCREEN : 0)); + SDL_HWSURFACE | ((config::video.fullscreen) ? SDL_FULLSCREEN : 0)); if(!screen) { alert("Failed to initialize SDL"); goto _end; } - backbuffer = SDL_CreateRGBSurface(SDL_SWSURFACE, 512, 448, 16, 0xf800, 0x07e0, 0x001f, 0x0000); + backbuffer = SDL_CreateRGBSurface(SDL_HWSURFACE, 512, 448, 16, 0xf800, 0x07e0, 0x001f, 0x0000); if(!backbuffer) { alert("Failed to initialize SDL"); goto _end; } SDL_WM_SetCaption(BSNES_TITLE, 0); diff --git a/src/snes/snes.cpp b/src/snes/snes.cpp index 0ad3ce4a..59c9bb6e 100644 --- a/src/snes/snes.cpp +++ b/src/snes/snes.cpp @@ -6,19 +6,19 @@ #include "input/input.cpp" void SNES::run() { - if(apusync.cycles < 0) { + if(sync.counter <= 0) { r_cpu->run(); - apusync.cycles += apusync.apu_multbl[r_cpu->cycles_executed()]; + uint32 clocks = r_cpu->clocks_executed(); + sync.counter += sync.apu_multbl[clocks]; } else { r_apu->run(); - uint32 cycles = r_apu->cycles_executed(); - apusync.dsp += cycles; - apusync.cycles -= apusync.cpu_multbl[cycles]; - + uint32 clocks = r_apu->clocks_executed(); + sync.counter -= sync.cpu_multbl[clocks]; //1024000(SPC700) / 32000(DSP) = 32spc/dsp ticks //24576000(Sound clock crystal) / 32000(DSP) = 768crystal/dsp ticks - while(apusync.dsp >= 768) { - apusync.dsp -= 768; + sync.dsp_counter += clocks; + while(sync.dsp_counter >= 768) { + sync.dsp_counter -= 768; audio_update(r_dsp->run()); } } @@ -35,12 +35,14 @@ void SNES::init() { srtc = new SRTC(); sdd1 = new SDD1(); c4 = new C4(); + dsp1 = new DSP1(); dsp2 = new DSP2(); obc1 = new OBC1(); srtc->init(); sdd1->init(); c4->init(); + dsp1->init(); dsp2->init(); obc1->init(); @@ -62,6 +64,7 @@ void SNES::power() { if(cartridge.cart.srtc)srtc->power(); if(cartridge.cart.sdd1)sdd1->power(); if(cartridge.cart.c4) c4->power(); + if(cartridge.cart.dsp1)dsp1->power(); if(cartridge.cart.dsp2)dsp2->power(); if(cartridge.cart.obc1)obc1->power(); @@ -69,15 +72,14 @@ void SNES::power() { for(int i = 0x2100; i <= 0x213f; i++)r_mem->set_mmio_mapper(i, r_ppu); for(int i = 0x2140; i <= 0x217f; i++)r_mem->set_mmio_mapper(i, r_cpu); for(int i = 0x2180; i <= 0x2183; i++)r_mem->set_mmio_mapper(i, r_cpu); -//input - r_mem->set_mmio_mapper(0x4016, r_cpu); - r_mem->set_mmio_mapper(0x4017, r_cpu); + for(int i = 0x4016; i <= 0x4017; i++)r_mem->set_mmio_mapper(i, r_cpu); for(int i = 0x4200; i <= 0x421f; i++)r_mem->set_mmio_mapper(i, r_cpu); for(int i = 0x4300; i <= 0x437f; i++)r_mem->set_mmio_mapper(i, r_cpu); if(cartridge.cart.srtc)srtc->enable(); if(cartridge.cart.sdd1)sdd1->enable(); if(cartridge.cart.c4) c4->enable(); + if(cartridge.cart.dsp1)dsp1->enable(); if(cartridge.cart.dsp2)dsp2->enable(); if(cartridge.cart.obc1)obc1->enable(); @@ -85,7 +87,8 @@ void SNES::power() { } void SNES::reset() { - apusync.cycles = -apusync.cpu_multbl[32]; + sync.counter = -sync.cpu_multbl[32]; + sync.dsp_counter = 0; r_cpu->reset(); r_apu->reset(); @@ -96,6 +99,7 @@ void SNES::reset() { if(cartridge.cart.srtc)srtc->reset(); if(cartridge.cart.sdd1)sdd1->reset(); if(cartridge.cart.c4) c4->reset(); + if(cartridge.cart.dsp1)dsp1->reset(); if(cartridge.cart.dsp2)dsp2->reset(); if(cartridge.cart.obc1)obc1->reset(); @@ -137,17 +141,13 @@ uint8 SNES::region() { return snes_region; } **************/ void SNES::update_timing() { - apusync.cycles = 0; - if(snes_region == NTSC) { - apusync.cpu_freq = 21477272 >> 3; - } else if(snes_region == PAL) { - apusync.cpu_freq = 21281370 >> 3; - } - apusync.apu_freq = 24576000 >> 3; + sync.counter = 0; + sync.cpu_freq = (snes_region == NTSC) ? 21477272 : 21281370; + sync.apu_freq = 24576000; - for(int i = 0; i < 1024; i++) { - apusync.cpu_multbl[i] = i * apusync.cpu_freq; - apusync.apu_multbl[i] = i * apusync.apu_freq; + for(int64 i = 0; i < 1024; i++) { + sync.cpu_multbl[i] = i * sync.cpu_freq; + sync.apu_multbl[i] = i * sync.apu_freq; } } diff --git a/src/snes/snes.h b/src/snes/snes.h index 2cb8b9b2..9124e003 100644 --- a/src/snes/snes.h +++ b/src/snes/snes.h @@ -2,20 +2,17 @@ class VideoFilter; class SNES { protected: -bool is_debugger_enabled; +bool is_debugger_enabled; +uint8 snes_region; -uint8 snes_region; - -//APU synchronization +//CPU<>APU synchronization struct { - int32 cpu_freq, apu_freq; - int32 cpu_multbl[1024], apu_multbl[1024]; - int32 cycles; + int64 counter, dsp_counter; + int64 cpu_freq, apu_freq; + int64 cpu_multbl[1024], apu_multbl[1024]; +} sync; - int32 dsp; -} apusync; - -void update_timing(); + void update_timing(); public: enum { NTSC = 0, PAL = 1 }; @@ -23,6 +20,7 @@ enum { NTSC = 0, PAL = 1 }; //system functions virtual inline void run(); virtual inline void runtoframe(); + virtual void init(); virtual void term(); virtual void power(); @@ -32,8 +30,8 @@ enum { NTSC = 0, PAL = 1 }; virtual void scanline(); //PAL/NTSC - uint8 region(); - void set_region(uint8 new_region); + uint8 region(); + void set_region(uint8 new_region); #include "video/video.h" #include "audio/audio.h" diff --git a/src/snes/video/filter_ntsc.cpp b/src/snes/video/filter_ntsc.cpp index c94a0f42..d38edd5b 100644 --- a/src/snes/video/filter_ntsc.cpp +++ b/src/snes/video/filter_ntsc.cpp @@ -5,7 +5,7 @@ NtscVideoFilter::NtscVideoFilter() { ntsc = 0; //to do: defer initialization? - adjust(0, 0, 0, 0, 0, bool(config::snes.ntsc_merge_fields), 0); //snes->color_lookup_table); + adjust(0, 0, 0, 0, 0, bool(config::snes.ntsc_merge_fields), 0); } NtscVideoFilter::~NtscVideoFilter() { @@ -50,13 +50,12 @@ int const out_height = height; result_width = out_width; result_height = out_height; burst ^= burst_toggle; - pitch >>= 1; if(!scanline_widths) { if(width == 256) { - snes_ntsc_blit(ntsc, data, pitch, burst, out_width, out_height, output, output_pitch); + snes_ntsc_blit(ntsc, data, (pitch >> 1), burst, out_width, out_height, output, output_pitch); } else { - snes_ntsc_blit_hires(ntsc, data, pitch, burst, out_width, out_height, output, output_pitch); + snes_ntsc_blit_hires(ntsc, data, (pitch >> 1), burst, out_width, out_height, output, output_pitch); } } else { //blit multiple scanlines of same width, rather than one at a time @@ -66,14 +65,14 @@ int const out_height = height; while(1) { if(run_width != scanline_widths[line] || line >= out_height) { - uint16 const *in = (uint16*)((char*)data + pitch * run_start); - uint16 *out = (uint16*)((char*)output + output_pitch * run_start); + uint16 const *in = (uint16*)((uint8*)data + pitch * run_start); + uint16 *out = (uint16*)((uint8*)output + output_pitch * run_start); int height = line - run_start; int line_burst = (burst + run_start) % 3; if(run_width == 256) { - snes_ntsc_blit(ntsc, in, pitch, line_burst, out_width, height, out, output_pitch); + snes_ntsc_blit(ntsc, in, (pitch >> 1), line_burst, out_width, height, out, output_pitch); } else { - snes_ntsc_blit_hires(ntsc, in, pitch, line_burst, out_width, height, out, output_pitch); + snes_ntsc_blit_hires(ntsc, in, (pitch >> 1), line_burst, out_width, height, out, output_pitch); } if(line >= out_height)break; run_width = scanline_widths[line]; diff --git a/src/snes/video/filter_ntsc_core.cpp b/src/snes/video/filter_ntsc_core.cpp index 4ac5a6e5..9466b225 100644 --- a/src/snes/video/filter_ntsc_core.cpp +++ b/src/snes/video/filter_ntsc_core.cpp @@ -1,4 +1,3 @@ - /* snes_ntsc 0.2.1. http://www.slack.net/~ant/ */ /* compilable in C or C++; just change the file extension */ diff --git a/src/snes/video/filter_ntsc_core.h b/src/snes/video/filter_ntsc_core.h index df1418fe..fa6ad8a7 100644 --- a/src/snes/video/filter_ntsc_core.h +++ b/src/snes/video/filter_ntsc_core.h @@ -1,4 +1,3 @@ - /* SNES NTSC composite video to RGB emulator/blitter */ /* snes_ntsc 0.2.1 */ diff --git a/src/snes/video/video_colortable.cpp b/src/snes/video/video_colortable.cpp index b330a050..fcf4acbf 100644 --- a/src/snes/video/video_colortable.cpp +++ b/src/snes/video/video_colortable.cpp @@ -10,19 +10,19 @@ double lmin, lmax; lmin = 0.0 - double(int32(config::snes.contrast)); lmax = 255.0 + double(int32(config::snes.contrast)); int32 result = int32(lmin + double(input) * ((lmax - lmin) / 256.0)); - input = bound_range(result, 0, 255); + input = minmax<0, 255>(result); } void SNES::brightness_adjust(int32 &input) { int32 result; result = input + int32(config::snes.brightness); - input = bound_range(result, 0, 255); + input = minmax<0, 255>(result); } void SNES::gamma_adjust(int32 &input) { int32 result; result = int32(pow((double(input + 1) / 256.0), double(config::snes.gamma) / 100.0) * 256.0); - input = bound_range(result, 0, 255); + input = minmax<0, 255>(result); } void SNES::update_color_lookup_table() { @@ -55,14 +55,14 @@ uint32 col; r = int32(double(l) * (1.0 + 0.300)); g = int32(double(l) * (1.0 - 0.055)); b = int32(double(l) * (1.0 - 0.225)); - r = bound_range(r, 0, 255); - g = bound_range(g, 0, 255); - b = bound_range(b, 0, 255); + r = minmax<0, 255>(r); + g = minmax<0, 255>(g); + b = minmax<0, 255>(b); } if(bool(config::snes.grayscale) == true) { l = int32(double(r) * kr + double(g) * kg + double(b) * kb); - l = bound_range(l, 0, 255); + l = minmax<0, 255>(l); r = g = b = l; } diff --git a/src/win/Makefile b/src/win/Makefile index 653d3e0e..c4e56da1 100644 --- a/src/win/Makefile +++ b/src/win/Makefile @@ -1,16 +1,21 @@ CC = cl -CFLAGS = /nologo /O2 /arch:SSE2 /wd4996 -#CFLAGS = /nologo /O2 /GL /EHsc /wd4996 +AS = nasm +CFLAGS = /nologo /O2 /arch:SSE2 +#CFLAGS = /nologo /O2 /GL /arch:SSE2 +#CFLAGS = /nologo /O2 /GL /EHsc +COMPILE = $(CC) $(CFLAGS) /c +ASSEMBLE = $(AS) -f win32 + OBJS = main.obj \ - libstring.obj libconfig.obj libbpf.obj \ + libco.obj libstring.obj libconfig.obj libbpf.obj \ reader.obj cart.obj cheat.obj \ memory.obj bmemory.obj \ - cpu.obj bcpu.obj \ - apu.obj bapu.obj \ + cpu.obj scpu.obj bcpu.obj \ + apu.obj sapu.obj bapu.obj \ bdsp.obj \ ppu.obj bppu.obj \ snes.obj \ - srtc.obj sdd1.obj c4.obj dsp2.obj obc1.obj + srtc.obj sdd1.obj c4.obj dsp1.obj dsp2.obj obc1.obj # adler32.obj compress.obj crc32.obj deflate.obj gzio.obj inffast.obj \ # inflate.obj inftrees.obj ioapi.obj trees.obj unzip.obj zip.obj zutil.obj \ # jma.obj jcrc32.obj lzmadec.obj 7zlzma.obj iiostrm.obj inbyte.obj lzma.obj winout.obj @@ -35,104 +40,118 @@ clean: ### win32-specific ### ###################### main.obj: *.cpp *.h video/* audio/* input/* settings/* debugger/* ../config/* - $(CC) $(CFLAGS) /c main.cpp + $(COMPILE) main.cpp ################# ### libraries ### ################# +libco.obj: ../lib/* + $(ASSEMBLE) -o libco.obj ../lib/libco_x86.asm + libstring.obj: ../lib/*.cpp ../lib/*.h - $(CC) $(CFLAGS) /c ../lib/libstring.cpp + $(COMPILE) ../lib/libstring.cpp + libconfig.obj: ../lib/*.cpp ../lib/*.h - $(CC) $(CFLAGS) /c ../lib/libconfig.cpp + $(COMPILE) ../lib/libconfig.cpp + libbpf.obj: ../lib/*.cpp ../lib/*.h - $(CC) $(CFLAGS) /c ../lib/libbpf.cpp + $(COMPILE) ../lib/libbpf.cpp ############## ### memory ### ############## memory.obj: ../memory/memory.cpp ../memory/memory.h - $(CC) $(CFLAGS) /c ../memory/memory.cpp + $(COMPILE) ../memory/memory.cpp bmemory.obj: ../memory/bmemory/* - $(CC) $(CFLAGS) /c ../memory/bmemory/bmemory.cpp + $(COMPILE) ../memory/bmemory/bmemory.cpp ########### ### cpu ### ########### -cpu.obj: ../cpu/*.cpp ../cpu/*.h - $(CC) $(CFLAGS) /c ../cpu/cpu.cpp +cpu.obj: ../cpu/* + $(COMPILE) ../cpu/cpu.cpp + +scpu.obj: ../cpu/scpu/* ../cpu/scpu/core/* ../cpu/scpu/dma/* ../cpu/scpu/memory/* ../cpu/scpu/mmio/* ../cpu/scpu/timing/* + $(COMPILE) ../cpu/scpu/scpu.cpp bcpu.obj: ../cpu/bcpu/* - $(CC) $(CFLAGS) /c ../cpu/bcpu/bcpu.cpp + $(COMPILE) ../cpu/bcpu/bcpu.cpp ########### ### apu ### ########### apu.obj: ../apu/* - $(CC) $(CFLAGS) /c ../apu/apu.cpp + $(COMPILE) ../apu/apu.cpp + +sapu.obj: ../apu/sapu/* ../apu/sapu/core/* ../apu/sapu/memory/* ../apu/sapu/timing/* + $(COMPILE) ../apu/sapu/sapu.cpp bapu.obj: ../apu/bapu/* - $(CC) $(CFLAGS) /c ../apu/bapu/bapu.cpp + $(COMPILE) ../apu/bapu/bapu.cpp ########### ### dsp ### ########### bdsp.obj: ../dsp/bdsp/* - $(CC) $(CFLAGS) /c ../dsp/bdsp/bdsp.cpp + $(COMPILE) ../dsp/bdsp/bdsp.cpp ########### ### ppu ### ########### ppu.obj: ../ppu/*.cpp ../ppu/*.h - $(CC) $(CFLAGS) /c ../ppu/ppu.cpp + $(COMPILE) ../ppu/ppu.cpp bppu.obj: ../ppu/bppu/* - $(CC) $(CFLAGS) /c ../ppu/bppu/bppu.cpp + $(COMPILE) ../ppu/bppu/bppu.cpp ################# ### utilities ### ################# reader.obj: ../reader/*.cpp ../reader/*.h - $(CC) $(CFLAGS) /c ../reader/reader.cpp + $(COMPILE) ../reader/reader.cpp cart.obj: ../cart/*.cpp ../cart/*.h - $(CC) $(CFLAGS) /c ../cart/cart.cpp + $(COMPILE) ../cart/cart.cpp cheat.obj: ../cheat/*.cpp ../cheat/*.h - $(CC) $(CFLAGS) /c ../cheat/cheat.cpp + $(COMPILE) ../cheat/cheat.cpp ############ ### snes ### ############ snes.obj: ../snes/* ../snes/video/* ../snes/audio/* ../snes/input/* - $(CC) $(CFLAGS) /c ../snes/snes.cpp + $(COMPILE) ../snes/snes.cpp ##################### ### special chips ### ##################### -srtc.obj: ../chip/srtc/*.cpp ../chip/srtc/*.h - $(CC) $(CFLAGS) /c ../chip/srtc/srtc.cpp +srtc.obj: ../chip/srtc/* + $(COMPILE) ../chip/srtc/srtc.cpp -sdd1.obj: ../chip/sdd1/*.cpp ../chip/sdd1/*.h - $(CC) $(CFLAGS) /c ../chip/sdd1/sdd1.cpp +sdd1.obj: ../chip/sdd1/* + $(COMPILE) ../chip/sdd1/sdd1.cpp -c4.obj: ../chip/c4/*.cpp ../chip/c4/*.h - $(CC) $(CFLAGS) /c ../chip/c4/c4.cpp +c4.obj: ../chip/c4/* + $(COMPILE) ../chip/c4/c4.cpp -dsp2.obj: ../chip/dsp2/*.cpp ../chip/dsp2/*.h - $(CC) $(CFLAGS) /c ../chip/dsp2/dsp2.cpp +dsp1.obj: ../chip/dsp1/* + $(COMPILE) ../chip/dsp1/dsp1.cpp -obc1.obj: ../chip/obc1/*.cpp ../chip/obc1/*.h - $(CC) $(CFLAGS) /c ../chip/obc1/obc1.cpp +dsp2.obj: ../chip/dsp2/* + $(COMPILE) ../chip/dsp2/dsp2.cpp + +obc1.obj: ../chip/obc1/* + $(COMPILE) ../chip/obc1/obc1.cpp ############ ### zlib ### ############ adler32.obj: ../reader/zlib/*.c ../reader/zlib/*.h - $(CC) $(CFLAGS) /c ../reader/zlib/*.c + $(COMPILE) ../reader/zlib/*.c ########### ### jma ### ########### jma.obj: ../reader/jma/*.cpp ../reader/jma/*.h - $(CC) $(CFLAGS) /c ../reader/jma/*.cpp + $(COMPILE) ../reader/jma/*.cpp diff --git a/src/win/audio/dsound.cpp b/src/win/audio/dsound.cpp index 8d22be23..9af01646 100644 --- a/src/win/audio/dsound.cpp +++ b/src/win/audio/dsound.cpp @@ -4,7 +4,7 @@ void AudioDS::run(uint32 sample) { if(data.buffer_pos >= data.samples_per_frame) { uint32 pos, size; void *buffer; - if((bool)config::system.regulate_speed == true) { + if(bool(config::system.regulate_speed) == true) { do { dsb_b->GetCurrentPosition(&pos, 0); data.read_buffer = pos / data.buffer_size; diff --git a/src/win/bsnes.cpp b/src/win/bsnes.cpp index 2dc63305..f776eeb5 100644 --- a/src/win/bsnes.cpp +++ b/src/win/bsnes.cpp @@ -49,6 +49,14 @@ void bSNES::run() { } void bSNES::video_run() { +//temporary code to try and fix input buffer stalls +static int sync_counter = 0; + if(++sync_counter >= 30) { + Sleep(1); + sync_counter = 0; + } +//remove above code after testing + if(r_ppu->status.frames_updated) { char s[512], t[512]; r_ppu->status.frames_updated = false; diff --git a/src/win/config.cpp b/src/win/config.cpp index dda4a5e9..57aefb4b 100644 --- a/src/win/config.cpp +++ b/src/win/config.cpp @@ -13,26 +13,18 @@ Setting System::speed_fastest (&config_file, "system.speed_fastest", "Fastest s struct Video { static Setting renderer; - static Setting profile; - static Setting profile_windowed_default, profile_fullscreen_default; - static Setting profile_0, profile_1, profile_2, profile_3, profile_4; - static Setting profile_5, profile_6, profile_7, profile_8, profile_9; + static Setting profile, fullscreen; + static Setting profile_0, profile_1, profile_2, profile_3; + static Setting profile_4, profile_5, profile_6, profile_7; static Setting use_vram, triple_buffering; static Setting pscanline_intensity, iscanline_intensity; - - struct Filter { - static Setting software, hardware; - } filter; } video; Setting Video::renderer(&config_file, "video.renderer", "Video renderer\n" "\"dd\" (DirectDraw7 -- faster, less features)\n" "\"d3d\" (Direct3D9 -- slower, more features)", "d3d"); -Setting Video::profile(0, "video.profile", "", 2, Setting::DEC); -Setting Video::profile_windowed_default(&config_file, "video.profile_windowed_default", - "Windowed profile to select for Alt+Enter", 2, Setting::DEC); -Setting Video::profile_fullscreen_default(&config_file, "video.profile_fullscreen_default", - "Fullscreen profile to select for Alt+Enter", 9, Setting::DEC); +Setting Video::profile(&config_file, "video.profile", "", 2, Setting::DEC); +Setting Video::fullscreen(0, "video.fullscreen", "", false, Setting::TRUE_FALSE); /* software_filter * hardware_filter @@ -49,22 +41,19 @@ Setting Video::profile_fullscreen_default(&config_file, "video.profile_fullscree * refresh_rate * triple_buffering */ -Setting Video::profile_0(&config_file, "video.profile_0", "Video profile 0 configuration\n" +Setting Video::profile_0(&config_file, "video.profile_0", "Video profile 0-7 configuration\n" "Please use bsnes GUI configuration editor to modify video profile settings\n" "Format: software_filter;hardware_filter;video_standard;multiplier-1;correct_aspect_ratio;\n" - " enable_scanlines;manual_render_size;render_width;render_height;fullscreen;\n" + " enable_scanlines;manual_render_size;render_width;render_height;\n" " resolution_width;resolution_height;refresh_rate;triple_buffering" - "", "0;0;0;0;false;false;false;256;224;false;320;240;0;false"); -Setting Video::profile_1(&config_file, "video.profile_1", "", "0;0;0;1;false;false;false;512;448;false;640;480;0;false"); -Setting Video::profile_2(&config_file, "video.profile_2", "", "0;1;0;1;true;false;false;597;448;false;640;480;0;false"); -Setting Video::profile_3(&config_file, "video.profile_3", "", "0;1;0;2;true;false;false;896;672;false;1024;768;0;false"); -Setting Video::profile_4(&config_file, "video.profile_4", "", "0;1;0;3;true;false;false;1195;896;false;1280;960;0;false"); - -Setting Video::profile_5(&config_file, "video.profile_5", "", "0;0;0;0;false;false;false;256;224;true;320;240;0;false"); -Setting Video::profile_6(&config_file, "video.profile_6", "", "0;0;0;1;false;false;false;512;448;true;640;480;0;false"); -Setting Video::profile_7(&config_file, "video.profile_7", "", "0;1;0;1;true;false;false;597;448;true;640;480;0;false"); -Setting Video::profile_8(&config_file, "video.profile_8", "", "0;1;0;2;true;false;false;896;672;true;1024;768;0;false"); -Setting Video::profile_9(&config_file, "video.profile_9", "", "0;1;0;3;true;false;false;1195;896;true;1280;960;0;false"); + "", "0;0;0;0;false;false;false;256;224;0;0;0;false"); +Setting Video::profile_1(&config_file, "video.profile_1", "", "0;0;0;1;false;false;false;512;448;0;0;0;false"); +Setting Video::profile_2(&config_file, "video.profile_2", "", "0;1;0;1;true;false;false;597;448;0;0;0;false"); +Setting Video::profile_3(&config_file, "video.profile_3", "", "0;1;0;2;true;false;false;896;672;0;0;0;false"); +Setting Video::profile_4(&config_file, "video.profile_4", "", "0;1;0;3;true;false;false;1195;896;0;0;0;false"); +Setting Video::profile_5(&config_file, "video.profile_5", "", "0;0;0;0;false;false;false;256;224;0;0;0;false"); +Setting Video::profile_6(&config_file, "video.profile_6", "", "0;0;0;0;false;false;false;256;224;0;0;0;false"); +Setting Video::profile_7(&config_file, "video.profile_7", "", "0;0;0;0;false;false;false;256;224;0;0;0;false"); Setting Video::use_vram(&config_file, "video.use_vram", "Use Video RAM instead of System RAM", true, Setting::TRUE_FALSE); Setting Video::triple_buffering(&config_file, "video.triple_buffering", "Use triple buffering", false, Setting::TRUE_FALSE); @@ -74,14 +63,6 @@ Setting Video::pscanline_intensity(&config_file, "video.pscanline_intensity", Setting Video::iscanline_intensity(&config_file, "video.iscanline_intensity", "Interlace scanline intensity", 50, Setting::DEC); -Setting Video::Filter::software(&config_file, "video.filter.software", "Software video filter\n" - "0 = Direct\n" - "1 = Scale2x\n", 0, Setting::DEC); - -Setting Video::Filter::hardware(&config_file, "video.filter.hardware", "Hardware video filter\n" - "0 = Pixel\n" - "1 = Bilinear", 1, Setting::DEC); - struct Input { static Setting axis_resistance; struct Joypad1 { diff --git a/src/win/debugger/ui_debugger.cpp b/src/win/debugger/ui_debugger.cpp index 56e30d52..3cd94565 100644 --- a/src/win/debugger/ui_debugger.cpp +++ b/src/win/debugger/ui_debugger.cpp @@ -15,6 +15,24 @@ bool DebugWindow::Event(EventInfo &info) { } else if(bsnes->get_state() == bSNES::STOP) { bsnes->set_state(bSNES::RUN); } + } else if(info.control == &ConsoleMsgDebug) { + output.debug ^= 1; + ConsoleMsgDebug.Check(output.debug); + } else if(info.control == &ConsoleMsgCPU) { + output.cpu ^= 1; + ConsoleMsgCPU.Check(output.cpu); + } else if(info.control == &ConsoleMsgAPU) { + output.apu ^= 1; + ConsoleMsgAPU.Check(output.apu); + } else if(info.control == &ConsoleTrace) { + output.trace ^= 1; + ConsoleTrace.Check(output.trace); + if(output.trace == true) { + output.fp = fopen("trace.log", "wb"); + } else { + fclose(output.fp); + output.fp = 0; + } } } break; @@ -36,9 +54,30 @@ char t[250 * 132]; Console.SetSelection(0, -1); //scroll cursor to bottom of window } -void DebugWindow::Print(const char *str) { +void DebugWindow::Print(uint source, const char *str) { if(!hwnd)return; + switch(source) { + case source::none: + break; + case source::debug: + if(output.debug == false)return; + break; + case source::cpu: + if(output.cpu == false)return; + break; + case source::apu: + if(output.apu == false)return; + break; + } + + if(output.trace == true) { + fprintf(output.fp, "%s\r\n", str); + + //only debug messages are printed to console while tracing is enabled + if(source != source::none && source != source::debug)return; + } + for(uint i = 0; i < buffer.count - 1; i++) { strcpy(buffer.line[i], buffer.line[i + 1]); } @@ -125,7 +164,33 @@ int x = 5, y = 5; APUDisable.Create(this, "visible|left", x + 165, y + 35, 80, 20, " Disable"); y += 66; + ConsoleGroup.Create(this, "visible", x, y, 250, 70, "Console output"); + ConsoleMsgDebug.Create(this, "visible", x + 5, y + 15, 80, 15, "Debug"); + ConsoleMsgCPU.Create(this, "visible", x + 85, y + 15, 80, 15, "CPU"); + ConsoleMsgAPU.Create(this, "visible", x + 165, y + 15, 80, 15, "APU"); + ConsoleTrace.Create(this, "visible", x + 5, y + 35, 240, 15, "Enable trace logging"); + ConsoleTraceMask.Create(this, "visible|disabled", x + 5, y + 50, 240, 15, "Mask duplicate instructions"); + ConsoleMsgDebug.Check(output.debug); + ConsoleMsgCPU.Check(output.cpu); + ConsoleMsgAPU.Check(output.apu); + ConsoleTrace.Check(output.trace); + ConsoleTraceMask.Check(output.trace_mask); + buffer.count = uint(config::debugger.console_lines); buffer.count = (buffer.count < 20) ? 20 : (buffer.count > 250) ? 250 : buffer.count; Clear(); } + +DebugWindow::DebugWindow() { + output.debug = true; + output.cpu = true; + output.apu = true; + + output.fp = 0; + output.trace = false; + output.trace_mask = false; +} + +DebugWindow::~DebugWindow() { + if(output.fp)fclose(output.fp); +} diff --git a/src/win/debugger/ui_debugger.h b/src/win/debugger/ui_debugger.h index 1cf852f3..ec348e51 100644 --- a/src/win/debugger/ui_debugger.h +++ b/src/win/debugger/ui_debugger.h @@ -21,20 +21,39 @@ Button APUSkip; Editbox APUTraceNum; Button APUTrace; Button APUDisable; +Groupbox ConsoleGroup; +Checkbox ConsoleMsgDebug; +Checkbox ConsoleMsgCPU; +Checkbox ConsoleMsgAPU; +Checkbox ConsoleTrace; +Checkbox ConsoleTraceMask; struct { uint count; char line[250][128]; } buffer; +struct { + bool debug; + bool cpu; + bool apu; + + FILE *fp; + bool trace; + bool trace_mask; +} output; + bool Event(EventInfo &info); void Update(); - void Print(const char *str); + void Print(uint source, const char *str); void Clear(); void SetState(uint state); void Show(); void Setup(); + + DebugWindow(); + ~DebugWindow(); } wDebug; diff --git a/src/win/event.cpp b/src/win/event.cpp index 42679dda..67390cfc 100644 --- a/src/win/event.cpp +++ b/src/win/event.cpp @@ -24,7 +24,7 @@ void capture_screenshot() { } void set_video_profile(uint profile) { - if(profile > 9)profile = 0; + if(profile > 7)profile = 0; config::video.profile = profile; uiVideo->update_video_profile(); @@ -37,16 +37,16 @@ void set_video_profile(uint profile) { wMain.CheckMenuItem(MENU_SETTINGS_VIDEOPROFILE_5, profile == 5); wMain.CheckMenuItem(MENU_SETTINGS_VIDEOPROFILE_6, profile == 6); wMain.CheckMenuItem(MENU_SETTINGS_VIDEOPROFILE_7, profile == 7); - wMain.CheckMenuItem(MENU_SETTINGS_VIDEOPROFILE_8, profile == 8); - wMain.CheckMenuItem(MENU_SETTINGS_VIDEOPROFILE_9, profile == 9); } void toggle_fullscreen() { - if(uiVideo->active_profile_is_fullscreen() == false) { - set_video_profile(config::video.profile_fullscreen_default); - } else { - set_video_profile(config::video.profile_windowed_default); + config::video.fullscreen.toggle(); + if(bool(config::video.fullscreen) == true) { + wSettings.Hide(); + wAbout.Hide(); + debugger.deactivate(); } + event::set_video_profile(config::video.profile); } void load_rom() { diff --git a/src/win/main.cpp b/src/win/main.cpp index 49238639..c1907460 100644 --- a/src/win/main.cpp +++ b/src/win/main.cpp @@ -21,9 +21,22 @@ va_list args; vsprintf(str, s, args); va_end(args); #ifdef DEBUGGER - wDebug.Print(str); + wDebug.Print(source::none, str); #else - fprintf(stdout, "%s\r\n", str); + fprintf(stdout, "[%3d] %s\r\n", source::none, str); +#endif +} + +void dprintf(uint source, char *s, ...) { +char str[4096]; +va_list args; + va_start(args, s); + vsprintf(str, s, args); + va_end(args); +#ifdef DEBUGGER + wDebug.Print(source, str); +#else + fprintf(stdout, "[%3d] %s\r\n", source, str); #endif } diff --git a/src/win/settings/ui_videosettings.cpp b/src/win/settings/ui_videosettings.cpp index 49a8db2d..284ac758 100644 --- a/src/win/settings/ui_videosettings.cpp +++ b/src/win/settings/ui_videosettings.cpp @@ -3,11 +3,7 @@ bool VideoSettingsWindow::Event(EventInfo &info) { case EVENT_CHANGED: case EVENT_CLICKED: { - if(info.control == &WinProfile) { - config::video.profile_windowed_default = WinProfile.GetSelection(); - } else if(info.control == &FullProfile) { - config::video.profile_fullscreen_default = FullProfile.GetSelection(); - } else if(info.control == &VideoProfile) { + if(info.control == &VideoProfile) { LoadSettings(VideoProfile.GetSelection()); } else if(info.control == &ApplySettings) { SaveSettings(VideoProfile.GetSelection()); @@ -34,7 +30,6 @@ VideoSettings *v = &video_settings[profile]; ManualRenderSize.Check(v->manual_render_size); RenderWidth.SetText("%d", v->render_width); RenderHeight.SetText("%d", v->render_height); - Fullscreen.Check(v->fullscreen); FullResWidth.SetText("%d", v->resolution_width); FullResHeight.SetText("%d", v->resolution_height); FullResHz.SetText("%d", v->refresh_rate); @@ -55,7 +50,6 @@ char t[64 + 1]; v->render_width = strdec(t); RenderHeight.GetText(t, 64); v->render_height = strdec(t); - v->fullscreen = Fullscreen.Checked(); FullResWidth.GetText(t, 64); v->resolution_width = strdec(t); FullResHeight.GetText(t, 64); @@ -74,8 +68,6 @@ char t[64 + 1]; } void VideoSettingsWindow::Show() { - WinProfile.SetSelection(config::video.profile_windowed_default); - FullProfile.SetSelection(config::video.profile_fullscreen_default); VideoProfile.SetSelection(config::video.profile); LoadSettings(config::video.profile); Window::Show(); @@ -86,25 +78,14 @@ void VideoSettingsWindow::Setup() { Header.SetFont(global::font_header); int x = 15, y = 30; - WinProfileLabel.Create(this, "visible", x, y + 3, 135, 15, "Default windowed profile:"); - WinProfile.Create(this, "visible", x + 135, y, 90, 200, - "Profile 0|Profile 1|Profile 2|Profile 3|Profile 4|" - "Profile 5|Profile 6|Profile 7|Profile 8|Profile 9"); - - FullProfileLabel.Create(this, "visible", x + 235, y + 3, 135, 15, "Default fullscreen profile:"); - FullProfile.Create(this, "visible", x + 370, y, 90, 200, - "Profile 0|Profile 1|Profile 2|Profile 3|Profile 4|" - "Profile 5|Profile 6|Profile 7|Profile 8|Profile 9"); - y += 25; - VideoProfileLabel.Create(this, "visible", x, y + 3, 135, 15, "Video profile to configure:"); VideoProfile.Create(this, "visible", x + 135, y, 90, 200, - "Profile 0|Profile 1|Profile 2|Profile 3|Profile 4|" - "Profile 5|Profile 6|Profile 7|Profile 8|Profile 9"); + "Profile 1|Profile 2|Profile 3|Profile 4|" + "Profile 5|Profile 6|Profile 7|Profile 8"); y += 25; - Separator1.Create(this, "visible|sunken", x, y + 5, 460, 3); - y += 15; + Separator1.Create(this, "visible|sunken", x, y + 1, 460, 3); + y += 9; SoftwareFilterLabel.Create(this, "visible", x, y + 3, 85, 15, "Software filter:"); SoftwareFilter.Create(this, "visible", x + 85, y, 140, 200, @@ -134,13 +115,10 @@ int x = 15, y = 30; RenderWidth.Create(this, "visible|edge", x + 90, y, 50, 20); RenderHeightLabel.Create(this, "visible", x + 150, y + 3, 90, 15, "Render height:"); RenderHeight.Create(this, "visible|edge", x + 240, y, 50, 20); - y += 22; + y += 25; - Separator2.Create(this, "visible|sunken", x, y + 5, 460, 3); - y += 15; - - Fullscreen.Create(this, "visible|auto", x, y, 460, 15, "Fullscreen (hit Esc or F11 to exit)"); - y += 15; + Separator1.Create(this, "visible|sunken", x, y, 460, 3); + y += 8; FullResWidthLabel.Create(this, "visible", x, y + 3, 90, 15, "Resolution width:"); FullResWidth.Create(this, "visible|edge", x + 90, y, 50, 20); @@ -157,7 +135,7 @@ int x = 15, y = 30; SelectProfile.Create(this, "visible", x + 125, y, 120, 25, "Set as active profile"); y += 25; - for(int i = 0; i < 10; i++) { + for(int i = 0; i < 8; i++) { load_video_settings(i); } } diff --git a/src/win/settings/ui_videosettings.h b/src/win/settings/ui_videosettings.h index 64348de0..bb47a951 100644 --- a/src/win/settings/ui_videosettings.h +++ b/src/win/settings/ui_videosettings.h @@ -1,10 +1,6 @@ class VideoSettingsWindow : public Window { public: Label Header; -Label WinProfileLabel; -Combobox WinProfile; -Label FullProfileLabel; -Combobox FullProfile; Label VideoProfileLabel; Combobox VideoProfile; Label Separator1; @@ -24,7 +20,6 @@ Editbox RenderWidth; Label RenderHeightLabel; Editbox RenderHeight; Label Separator2; -Checkbox Fullscreen; Label FullResWidthLabel; Editbox FullResWidth; Label FullResHeightLabel; diff --git a/src/win/ui.h b/src/win/ui.h index 16762c44..6fdec92a 100644 --- a/src/win/ui.h +++ b/src/win/ui.h @@ -26,12 +26,9 @@ MENU_SETTINGS, MENU_SETTINGS_VIDEOPROFILE_2, MENU_SETTINGS_VIDEOPROFILE_3, MENU_SETTINGS_VIDEOPROFILE_4, - //--- MENU_SETTINGS_VIDEOPROFILE_5, MENU_SETTINGS_VIDEOPROFILE_6, MENU_SETTINGS_VIDEOPROFILE_7, - MENU_SETTINGS_VIDEOPROFILE_8, - MENU_SETTINGS_VIDEOPROFILE_9, MENU_SETTINGS_FRAMESKIP, MENU_SETTINGS_FRAMESKIP_0, //--- diff --git a/src/win/ui_main.cpp b/src/win/ui_main.cpp index 19108a7d..ca355bef 100644 --- a/src/win/ui_main.cpp +++ b/src/win/ui_main.cpp @@ -47,44 +47,37 @@ bool MainWindow::Event(EventInfo &info) { uint key = info.control_id; bool ctrl = uiInput->keydown(keymap->lctrl) || uiInput->keydown(keymap->rctrl); if(key == keymap->esc) { - if(uiVideo->settings.fullscreen == false) { + if(bool(config::video.fullscreen) == false) { ShowMenu(!MenuVisible()); Center(); } else { - event::set_video_profile(config::video.profile_windowed_default); + config::video.fullscreen = false; + event::set_video_profile(config::video.profile); } } else if(key == keymap->f11) { - if(uiVideo->settings.fullscreen == false) { - event::set_video_profile(config::video.profile_fullscreen_default); - } else { - event::set_video_profile(config::video.profile_windowed_default); - } + event::toggle_fullscreen(); } else if(key == keymap->f12) { if(bsnes->get_state() == bSNES::RUN) { bsnes->set_state(bSNES::STOP); } else if(bsnes->get_state() == bSNES::STOP) { bsnes->set_state(bSNES::RUN); } - } else if(key == keymap->numpad_0 && ctrl) { + } else if(key == keymap->num_1 && ctrl) { event::set_video_profile(0); - } else if(key == keymap->numpad_1 && ctrl) { + } else if(key == keymap->num_2 && ctrl) { event::set_video_profile(1); - } else if(key == keymap->numpad_2 && ctrl) { + } else if(key == keymap->num_3 && ctrl) { event::set_video_profile(2); - } else if(key == keymap->numpad_3 && ctrl) { + } else if(key == keymap->num_4 && ctrl) { event::set_video_profile(3); - } else if(key == keymap->numpad_4 && ctrl) { + } else if(key == keymap->num_5 && ctrl) { event::set_video_profile(4); - } else if(key == keymap->numpad_5 && ctrl) { + } else if(key == keymap->num_6 && ctrl) { event::set_video_profile(5); - } else if(key == keymap->numpad_6 && ctrl) { + } else if(key == keymap->num_7 && ctrl) { event::set_video_profile(6); - } else if(key == keymap->numpad_7 && ctrl) { + } else if(key == keymap->num_8 && ctrl) { event::set_video_profile(7); - } else if(key == keymap->numpad_8 && ctrl) { - event::set_video_profile(8); - } else if(key == keymap->numpad_9 && ctrl) { - event::set_video_profile(9); } else if((key == keymap->minus && !ctrl) || key == keymap->numpad_minus) { if(frameskip > 0)SetFrameskip(frameskip - 1); } else if((key == keymap->plus && !ctrl) || key == keymap->numpad_plus) { @@ -156,9 +149,7 @@ bool MainWindow::Event(EventInfo &info) { case MENU_SETTINGS_VIDEOPROFILE_4: case MENU_SETTINGS_VIDEOPROFILE_5: case MENU_SETTINGS_VIDEOPROFILE_6: - case MENU_SETTINGS_VIDEOPROFILE_7: - case MENU_SETTINGS_VIDEOPROFILE_8: - case MENU_SETTINGS_VIDEOPROFILE_9: { + case MENU_SETTINGS_VIDEOPROFILE_7: { event::set_video_profile(info.control_id - MENU_SETTINGS_VIDEOPROFILE_0); } break; @@ -258,16 +249,14 @@ char t[128]; AddMenuGroup("&Settings"); AddMenuGroup("&Video Profile"); - AddMenuItem(MENU_SETTINGS_VIDEOPROFILE_0, "Profile &0"); - AddMenuItem(MENU_SETTINGS_VIDEOPROFILE_1, "Profile &1"); - AddMenuItem(MENU_SETTINGS_VIDEOPROFILE_2, "Profile &2"); - AddMenuItem(MENU_SETTINGS_VIDEOPROFILE_3, "Profile &3"); - AddMenuItem(MENU_SETTINGS_VIDEOPROFILE_4, "Profile &4"); - AddMenuItem(MENU_SETTINGS_VIDEOPROFILE_5, "Profile &5"); - AddMenuItem(MENU_SETTINGS_VIDEOPROFILE_6, "Profile &6"); - AddMenuItem(MENU_SETTINGS_VIDEOPROFILE_7, "Profile &7"); - AddMenuItem(MENU_SETTINGS_VIDEOPROFILE_8, "Profile &8"); - AddMenuItem(MENU_SETTINGS_VIDEOPROFILE_9, "Profile &9"); + AddMenuItem(MENU_SETTINGS_VIDEOPROFILE_0, "Profile &1"); + AddMenuItem(MENU_SETTINGS_VIDEOPROFILE_1, "Profile &2"); + AddMenuItem(MENU_SETTINGS_VIDEOPROFILE_2, "Profile &3"); + AddMenuItem(MENU_SETTINGS_VIDEOPROFILE_3, "Profile &4"); + AddMenuItem(MENU_SETTINGS_VIDEOPROFILE_4, "Profile &5"); + AddMenuItem(MENU_SETTINGS_VIDEOPROFILE_5, "Profile &6"); + AddMenuItem(MENU_SETTINGS_VIDEOPROFILE_6, "Profile &7"); + AddMenuItem(MENU_SETTINGS_VIDEOPROFILE_7, "Profile &8"); EndMenuGroup(); AddMenuGroup("&Frameskip"); @@ -325,7 +314,7 @@ char t[128]; CheckMenuItem(MENU_SETTINGS_MUTE, config::snes.mute); CheckMenuItem(MENU_SETTINGS_SPEED_REGULATION_ENABLE, config::system.regulate_speed); - event::set_video_profile(config::video.profile_windowed_default); + event::set_video_profile(config::video.profile); SetFrameskip(0); SetRegulationSpeed(2); diff --git a/src/win/video/d3d.cpp b/src/win/video/d3d.cpp index b5a0f8ab..f0c55607 100644 --- a/src/win/video/d3d.cpp +++ b/src/win/video/d3d.cpp @@ -14,37 +14,39 @@ HRESULT hr; } memset(&presentation, 0, sizeof(presentation)); - presentation.Flags = 0; - if(settings.triple_buffering == false) { - presentation.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; + presentation.Flags = D3DPRESENTFLAG_VIDEO; + presentation.SwapEffect = (settings.triple_buffering == true) ? + D3DSWAPEFFECT_FLIP : D3DSWAPEFFECT_DISCARD; + presentation.hDeviceWindow = wMain.hwnd; + presentation.BackBufferCount = (settings.triple_buffering == true) ? 2 : 1; + presentation.MultiSampleType = D3DMULTISAMPLE_NONE; + presentation.MultiSampleQuality = 0; + presentation.EnableAutoDepthStencil = false; + presentation.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + presentation.PresentationInterval = (settings.triple_buffering == true) ? + D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE; + presentation.FullScreen_RefreshRateInHz = settings.refresh_rate; + + if(bool(config::video.fullscreen) == false) { + presentation.Windowed = true; + presentation.BackBufferFormat = D3DFMT_UNKNOWN; + presentation.BackBufferWidth = 0; + presentation.BackBufferHeight = 0; + } else { + presentation.Windowed = false; + presentation.BackBufferFormat = D3DFMT_R5G6B5; + presentation.BackBufferWidth = settings.resolution_width; + presentation.BackBufferHeight = settings.resolution_height; } - presentation.Flags |= D3DPRESENTFLAG_VIDEO; - presentation.Windowed = (settings.fullscreen == false); - presentation.SwapEffect = (settings.triple_buffering == true) ? - D3DSWAPEFFECT_FLIP : D3DSWAPEFFECT_DISCARD; - presentation.hDeviceWindow = wMain.hwnd; - presentation.BackBufferFormat = (settings.fullscreen) ? D3DFMT_X8R8G8B8 : D3DFMT_UNKNOWN; - presentation.BackBufferWidth = (settings.fullscreen) ? settings.resolution_width : 0; - presentation.BackBufferHeight = (settings.fullscreen) ? settings.resolution_height : 0; - presentation.BackBufferCount = (settings.triple_buffering == true) ? 2 : 1; - presentation.MultiSampleType = D3DMULTISAMPLE_NONE; - presentation.MultiSampleQuality = 0; - presentation.EnableAutoDepthStencil = false; - presentation.AutoDepthStencilFormat = D3DFMT_UNKNOWN; - presentation.PresentationInterval = (settings.triple_buffering == true) ? - D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE; - presentation.FullScreen_RefreshRateInHz = (settings.fullscreen == true) ? settings.refresh_rate : D3DPRESENT_RATE_DEFAULT; hr = lpd3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wMain.hwnd, - D3DCREATE_HARDWARE_VERTEXPROCESSING, &presentation, &device); + D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentation, &device); if(hr != D3D_OK) { alert("Failed to create Direct3D9 device"); return false; } -/***** - * detect device capabilities - *****/ +//detect device capabilities device->GetDeviceCaps(&d3dcaps); if(d3dcaps.MaxTextureWidth < 1024 || d3dcaps.MaxTextureWidth < 1024) { alert("Error: Direct3D renderer requires that the video card supports textures up to 1024x1024.\n" @@ -52,8 +54,8 @@ HRESULT hr; "", d3dcaps.MaxTextureWidth, d3dcaps.MaxTextureHeight); return false; } - caps.dynamic = !!(d3dcaps.Caps2 & D3DCAPS2_DYNAMICTEXTURES); - caps.addresswrap = !!(d3dcaps.TextureAddressCaps & D3DPTADDRESSCAPS_WRAP); + caps.dynamic = bool(d3dcaps.Caps2 & D3DCAPS2_DYNAMICTEXTURES); + caps.addresswrap = bool(d3dcaps.TextureAddressCaps & D3DPTADDRESSCAPS_WRAP); caps.stretchrect = (d3dcaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) && (d3dcaps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFPOINT) && (d3dcaps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFPOINT) && @@ -74,8 +76,7 @@ HRESULT hr; flags.lock = D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD; } -//this is required to allow window menu to be visible in fullscreen mode - device->SetDialogBoxMode(settings.triple_buffering == false); + device->SetDialogBoxMode(false); device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); diff --git a/src/win/video/ddraw.cpp b/src/win/video/ddraw.cpp index 94178560..bb860163 100644 --- a/src/win/video/ddraw.cpp +++ b/src/win/video/ddraw.cpp @@ -1,5 +1,3 @@ -#include "ddraw_present.cpp" - bool VideoDD::update_video_profile() { term(); @@ -10,7 +8,7 @@ bool VideoDD::update_video_profile() { lpdd->QueryInterface(IID_IDirectDraw7, (void**)&lpdd7); SafeRelease(lpdd); - if(settings.fullscreen) { + if(bool(config::video.fullscreen) == true) { lpdd7->SetCooperativeLevel(wMain.hwnd, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE); lpdd7->SetDisplayMode(settings.resolution_width, settings.resolution_height, 16, settings.refresh_rate, 0); } else { @@ -105,13 +103,78 @@ DDBLTFX fx; backbuffer->Blt(0, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &fx); surface->Blt (0, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &fx); - if(settings.fullscreen == true) { + if(bool(config::video.fullscreen) == true) { screen->Flip(0, DDFLIP_WAIT); backbuffer->Blt(0, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &fx); screen->Flip(0, DDFLIP_WAIT); } } +//create screen and backbuffer surfaces +void VideoDD::create_presentation() { + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + + if(bool(config::video.fullscreen) == true) { + ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + ddsd.dwBackBufferCount = (settings.triple_buffering == true) ? 2 : 1; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; + lpdd7->CreateSurface(&ddsd, &screen, 0); + + memset(&ddscaps, 0, sizeof(DDSCAPS2)); + ddscaps.dwCaps = DDSCAPS_BACKBUFFER; + screen->GetAttachedSurface(&ddscaps, &backbuffer); + } else { + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + lpdd7->CreateSurface(&ddsd, &screen, 0); + + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + if(bool(config::video.use_vram) == true) { + ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; + } else { + ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; + } + + ddsd.dwWidth = settings.render_width; + ddsd.dwHeight = settings.render_height; + lpdd7->CreateSurface(&ddsd, &backbuffer, 0); + } +} + +void VideoDD::redraw() { +HRESULT hr; +RECT rd, rs; + snes->get_video_info(&vi); + SetRect(&rs, 0, 0, vi.width, vi.height); + + if(bool(config::video.fullscreen) == true) { + SetRect(&rd, settings.rx, settings.ry, settings.rx + settings.rw, settings.ry + settings.rh); + backbuffer->Blt(&rd, surface, &rs, DDBLT_WAIT, 0); + hr = screen->Flip(0, DDFLIP_WAIT); + } else { + POINT p = { 0, 0 }; + ClientToScreen(wMain.hwnd, &p); + GetClientRect(wMain.hwnd, &rd); + OffsetRect(&rd, p.x, p.y); + + hr = screen->Blt(&rd, surface, &rs, DDBLT_WAIT, 0); + } + + if(hr == DDERR_SURFACELOST) { + screen->Restore(); + backbuffer->Restore(); + surface->Restore(); + } +} + +void VideoDD::update() { + redraw(); +} + void VideoDD::init() {} void VideoDD::term() { diff --git a/src/win/video/ddraw_present.cpp b/src/win/video/ddraw_present.cpp deleted file mode 100644 index eda7bb3a..00000000 --- a/src/win/video/ddraw_present.cpp +++ /dev/null @@ -1,64 +0,0 @@ -//create screen and backbuffer surfaces -void VideoDD::create_presentation() { - memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); - ddsd.dwSize = sizeof(DDSURFACEDESC2); - - if(settings.fullscreen == true) { - ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; - ddsd.dwBackBufferCount = 2; - ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; - lpdd7->CreateSurface(&ddsd, &screen, 0); - - memset(&ddscaps, 0, sizeof(DDSCAPS2)); - ddscaps.dwCaps = DDSCAPS_BACKBUFFER; - screen->GetAttachedSurface(&ddscaps, &backbuffer); - } else { - ddsd.dwFlags = DDSD_CAPS; - ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - lpdd7->CreateSurface(&ddsd, &screen, 0); - - memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); - ddsd.dwSize = sizeof(DDSURFACEDESC2); - ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; - if(bool(config::video.use_vram) == true) { - ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; - } else { - ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; - } - - ddsd.dwWidth = settings.render_width; - ddsd.dwHeight = settings.render_height; - lpdd7->CreateSurface(&ddsd, &backbuffer, 0); - } -} - -void VideoDD::redraw() { -HRESULT hr; -RECT rd, rs; - snes->get_video_info(&vi); - SetRect(&rs, 0, 0, vi.width, vi.height); - - if(settings.fullscreen == true) { - SetRect(&rd, settings.rx, settings.ry, settings.rx + settings.rw, settings.ry + settings.rh); - backbuffer->Blt(&rd, surface, &rs, DDBLT_WAIT, 0); - hr = screen->Flip(0, DDFLIP_WAIT); - } else { - POINT p = { 0, 0 }; - ClientToScreen(wMain.hwnd, &p); - GetClientRect(wMain.hwnd, &rd); - OffsetRect(&rd, p.x, p.y); - - hr = screen->Blt(&rd, surface, &rs, DDBLT_WAIT, 0); - } - - if(hr == DDERR_SURFACELOST) { - screen->Restore(); - backbuffer->Restore(); - surface->Restore(); - } -} - -void VideoDD::update() { - redraw(); -} diff --git a/src/win/video/video.cpp b/src/win/video/video.cpp index 3f4f7b73..55cf11a2 100644 --- a/src/win/video/video.cpp +++ b/src/win/video/video.cpp @@ -1,6 +1,6 @@ void load_video_settings(uint profile) { string line, part; - if(profile > 9)profile = 0; + if(profile > 7)profile = 0; switch(profile) { case 0: strcpy(line, config::video.profile_0.sget()); break; @@ -11,8 +11,6 @@ string line, part; case 5: strcpy(line, config::video.profile_5.sget()); break; case 6: strcpy(line, config::video.profile_6.sget()); break; case 7: strcpy(line, config::video.profile_7.sget()); break; - case 8: strcpy(line, config::video.profile_8.sget()); break; - case 9: strcpy(line, config::video.profile_9.sget()); break; } split(part, ";", line); @@ -27,17 +25,19 @@ int i = 0; v->manual_render_size = strmatch(part[i++], "true"); v->render_width = strdec(part[i++]); v->render_height = strdec(part[i++]); - v->fullscreen = strmatch(part[i++], "true"); v->resolution_width = strdec(part[i++]); v->resolution_height = strdec(part[i++]); v->refresh_rate = strdec(part[i++]); v->triple_buffering = strmatch(part[i++], "true"); + + if(v->render_width < 256)v->render_width = 256; + if(v->render_height < 224)v->render_height = 224; } void save_video_settings(uint profile) { string line; char part[64]; - if(profile > 9)profile = 0; + if(profile > 7)profile = 0; VideoSettings *v = &video_settings[profile]; strcpy(line, ""); @@ -50,7 +50,6 @@ VideoSettings *v = &video_settings[profile]; sprintf(part, "%s", v->manual_render_size ? "true" : "false"); strcat(line, part); strcat(line, ";"); sprintf(part, "%d", v->render_width); strcat(line, part); strcat(line, ";"); sprintf(part, "%d", v->render_height); strcat(line, part); strcat(line, ";"); - sprintf(part, "%s", v->fullscreen ? "true" : "false"); strcat(line, part); strcat(line, ";"); sprintf(part, "%d", v->resolution_width); strcat(line, part); strcat(line, ";"); sprintf(part, "%d", v->resolution_height); strcat(line, part); strcat(line, ";"); sprintf(part, "%d", v->refresh_rate); strcat(line, part); strcat(line, ";"); @@ -65,14 +64,12 @@ VideoSettings *v = &video_settings[profile]; case 5: config::video.profile_5.sset(strptr(line)); break; case 6: config::video.profile_6.sset(strptr(line)); break; case 7: config::video.profile_7.sset(strptr(line)); break; - case 8: config::video.profile_8.sset(strptr(line)); break; - case 9: config::video.profile_9.sset(strptr(line)); break; } } void Video::update_video_settings() { uint profile = uint(config::video.profile); - if(profile > 9)profile = 0; + if(profile > 7)profile = 0; load_video_settings(profile); VideoSettings *v = &video_settings[profile]; @@ -94,13 +91,12 @@ VideoSettings *v = &video_settings[profile]; } settings.hardware_filter = v->hardware_filter; - settings.fullscreen = v->fullscreen; settings.triple_buffering = v->triple_buffering; settings.enable_scanlines = v->enable_scanlines; - if(settings.fullscreen == true) { - settings.resolution_width = v->resolution_width; - settings.resolution_height = v->resolution_height; + if(bool(config::video.fullscreen) == true) { + settings.resolution_width = (v->resolution_width) ? v->resolution_width : GetScreenWidth(); + settings.resolution_height = (v->resolution_height) ? v->resolution_height : GetScreenHeight(); settings.refresh_rate = v->refresh_rate; } else { settings.resolution_width = settings.render_width; @@ -119,7 +115,7 @@ VideoSettings *v = &video_settings[profile]; void Video::update_window() { string t; - if(settings.fullscreen == true) { + if(bool(config::video.fullscreen) == true) { strcpy(t, "topmost|popup"); if(wMain.Visible())strcat(t, "|visible"); wMain.HideMenu(); diff --git a/src/win/video/video.h b/src/win/video/video.h index 405837ee..6a127ea5 100644 --- a/src/win/video/video.h +++ b/src/win/video/video.h @@ -13,12 +13,11 @@ struct VideoSettings { bool manual_render_size; uint render_width; uint render_height; - bool fullscreen; uint resolution_width; uint resolution_height; uint refresh_rate; bool triple_buffering; -} video_settings[10]; +} video_settings[8]; void load_video_settings(uint profile); void save_video_settings(uint profile); @@ -32,7 +31,6 @@ struct { uint render_height; uint hardware_filter; - bool fullscreen; bool triple_buffering; bool enable_scanlines; @@ -47,7 +45,6 @@ struct { } settings; void update_video_settings(); void update_window(); - bool active_profile_is_fullscreen() { return settings.fullscreen; } virtual uint16 *lock(uint32 &pitch) = 0; virtual void unlock() = 0;