Update to bsnes v016r27a release.

Ok, I tried converting the switch/case table to a jump table for both
CPU+APU cores. Results? EXE is 70kb larger, compile time is 5-10%
slower, and speed is identical. Needless to say I reverted that change
back. I then tried narrowing down the cause of the PGO error. Found
out it was Dai Kaijuu Monogatari. If I don't run that, I can build
with PGO. Unfortunately, this is the ROM I use to stress optimize
color add/sub. So as a result, this game will run a little slowly now
(sort of like how Chrono Trigger's OPT title screen effects were
before). But, better one game than all, right?

             byuu.org/files/bsnes_v016_wip27a.zip

 Once again, please do not submit news about this to an emulation
site. The file will be removed if I notice anyone mentioning it
anywhere.

             That will be 20-25% faster than wip27, but otherwise
everything is identical.

 DSP1: there's either a bug in op02, op06, or in the getSr/getDr/setDr
functions. We have so far been unable to spot the error and correct
it. Help is always welcome, as always. Please consider DSP-1 support
as not being there at all. I doubt any games will work right with it
right now :(

             This is how interlace works :
             I call each frame a "field", meaning even or odd fields
on your television / monitor.
             When interlace is off, I draw to the even fields every
time, so you don't notice anything.
 However, when interlace is on, I alternate between which one I draw
to each field. So depending on your frameskip, this can cause serious
problems for interlace mode. I also only physically draw to "half" the
resolution each field, much like a real TV would. This makes 512x448
mode just as fast as 512x224 mode.
 I can't think of an easy way to cheat the system with frameskipping.
Luckily, very very few games use interlace at all. Most use hires
512x224 and that's it.
This commit is contained in:
byuu 2006-07-09 05:32:10 +00:00
parent a36c26c997
commit e492268025
137 changed files with 16446 additions and 1352 deletions

BIN
bsnes.exe Normal file

Binary file not shown.

View File

@ -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() {}
};

View File

@ -1,20 +1,18 @@
class APURegFlags {
private:
template <uint8 B> class bit {
template<uint mask> 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;

View File

@ -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() {}

View File

@ -6,7 +6,7 @@ public:
struct {
uint8 cycle_pos, opcode;
uint32 cycles_executed;
uint32 clocks_executed;
//$f1
bool iplrom_enabled;

View File

@ -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

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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();

3
src/apu/sapu/core/cc.bat Normal file
View File

@ -0,0 +1,3 @@
cl /O2 /wd4996 sapugen.cpp
@pause
@del *.obj

View File

@ -0,0 +1 @@
@del *.exe

View File

@ -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
}
}

24
src/apu/sapu/core/core.h Normal file
View File

@ -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"

175
src/apu/sapu/core/op_misc.b Normal file
View File

@ -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);
}

View File

@ -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;

212
src/apu/sapu/core/op_mov.b Normal file
View File

@ -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);
}

View File

@ -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;

180
src/apu/sapu/core/op_pc.b Normal file
View File

@ -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;
}

604
src/apu/sapu/core/op_pc.cpp Normal file
View File

@ -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;

199
src/apu/sapu/core/op_read.b Normal file
View File

@ -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));
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

138
src/apu/sapu/core/opfn.cpp Normal file
View File

@ -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;
}

View File

@ -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;
}

View File

@ -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); }

View File

@ -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);

73
src/apu/sapu/sapu.cpp Normal file
View File

@ -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);
}

32
src/apu/sapu/sapu.h Normal file
View File

@ -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();
};

View File

@ -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;
}

View File

@ -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();

View File

@ -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"

View File

@ -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;
}

View File

@ -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);

1617
src/chip/dsp1/_dsp1emu.cpp Normal file

File diff suppressed because it is too large Load Diff

126
src/chip/dsp1/_dsp1emu.h Normal file
View File

@ -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

54
src/chip/dsp1/dsp1.cpp Normal file
View File

@ -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);
}
}

16
src/chip/dsp1/dsp1.h Normal file
View File

@ -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);
};

1622
src/chip/dsp1/dsp1emu.cpp Normal file

File diff suppressed because it is too large Load Diff

127
src/chip/dsp1/dsp1emu.h Normal file
View File

@ -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

View File

@ -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();

View File

@ -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);

View File

@ -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();

View File

@ -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();

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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;
}

View File

@ -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() {}

View File

@ -1,20 +1,18 @@
class CPURegFlags {
private:
template <uint8 B> class bit {
template<uint mask> 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<typename T> inline unsigned operator = (const T i) { w = i; return w; }
template<typename T> inline unsigned operator |= (const T i) { w |= i; return w; }
template<typename T> inline unsigned operator ^= (const T i) { w ^= i; return w; }
template<typename T> inline unsigned operator &= (const T i) { w &= i; return w; }
template<typename T> inline unsigned operator <<= (const T i) { w <<= i; return w; }
template<typename T> inline unsigned operator >>= (const T i) { w >>= i; return w; }
template<typename T> inline unsigned operator += (const T i) { w += i; return w; }
template<typename T> inline unsigned operator -= (const T i) { w -= i; return w; }
template<typename T> inline unsigned operator *= (const T i) { w *= i; return w; }
template<typename T> inline unsigned operator /= (const T i) { w /= i; return w; }
template<typename T> 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<typename T> inline unsigned operator = (const T i) { d = uclip<24>(i); return d; }
template<typename T> inline unsigned operator |= (const T i) { d = uclip<24>(d | i); return d; }
template<typename T> inline unsigned operator ^= (const T i) { d = uclip<24>(d ^ i); return d; }
template<typename T> inline unsigned operator &= (const T i) { d = uclip<24>(d & i); return d; }
template<typename T> inline unsigned operator <<= (const T i) { d = uclip<24>(d << i); return d; }
template<typename T> inline unsigned operator >>= (const T i) { d = uclip<24>(d >> i); return d; }
template<typename T> inline unsigned operator += (const T i) { d = uclip<24>(d + i); return d; }
template<typename T> inline unsigned operator -= (const T i) { d = uclip<24>(d - i); return d; }
template<typename T> inline unsigned operator *= (const T i) { d = uclip<24>(d * i); return d; }
template<typename T> inline unsigned operator /= (const T i) { d = uclip<24>(d / i); return d; }
template<typename T> 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; }
};

View File

@ -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, "?????? <CPU within opcode>");
@ -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;
}

3
src/cpu/scpu/core/cc.bat Normal file
View File

@ -0,0 +1,3 @@
cl /O2 scpugen.cpp
@pause
@del *.obj

View File

@ -0,0 +1 @@
@del *.exe

View File

@ -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();
}

58
src/cpu/scpu/core/core.h Normal file
View File

@ -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"

276
src/cpu/scpu/core/op_misc.b Normal file
View File

@ -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);
}

View File

@ -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;

160
src/cpu/scpu/core/op_pc.b Normal file
View File

@ -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++;
}

273
src/cpu/scpu/core/op_pc.cpp Normal file
View File

@ -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;

317
src/cpu/scpu/core/op_read.b Normal file
View File

@ -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);
}

File diff suppressed because it is too large Load Diff

181
src/cpu/scpu/core/op_rmw.b Normal file
View File

@ -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);
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

377
src/cpu/scpu/core/opfn.cpp Normal file
View File

@ -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;
}

View File

@ -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;
}

252
src/cpu/scpu/dma/dma.cpp Normal file
View File

@ -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] <address bus b>
* $[00-3f|80-bf]:43[00-7f] <DMA control registers>
* $[00-3f|80-bf]:420b <DMA enable register>
* $[00-3f|80-bf]:420c <HDMA enable register>
*
* 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;
}
}

67
src/cpu/scpu/dma/dma.h Normal file
View File

@ -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();

View File

@ -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();
}

View File

@ -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); }

669
src/cpu/scpu/mmio/mmio.cpp Normal file
View File

@ -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;
}
}

65
src/cpu/scpu/mmio/mmio.h Normal file
View File

@ -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);

64
src/cpu/scpu/scpu.cpp Normal file
View File

@ -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);
}

84
src/cpu/scpu/scpu.h Normal file
View File

@ -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();
};

162
src/cpu/scpu/timing/irq.cpp Normal file
View File

@ -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;
}

View File

@ -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

View File

@ -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();

View File

@ -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() {}

View File

@ -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);

View File

@ -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;

View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
@ -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<typename T> void swap(T &x, T &y) {
/*****
* templates
*****/
template<typename T> inline void swap(T &x, T &y) {
T z = x;
x = y;
y = z;
}
template<typename T, typename Targ> T bound_range(T &x, Targ min, Targ max) {
template<int min, int max, typename T> inline T minmax(const T x) {
return (x < T(min)) ? T(min) : (x > T(max)) ? T(max) : x;
}
template<int bits> inline unsigned uclamp(const unsigned x) {
enum { m = (1 << bits) - 1 };
return (x > m) ? m : x;
}
template<int bits> inline unsigned uclip(const unsigned x) {
enum { m = (1 << bits) - 1 };
return (x & m);
}
template<int bits> 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<int bits> 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<int bits> inline signed sclip(const signed x) {
//enum { b = 1 << (bits - 1), m = (1 << (bits - 1)) - 1 };
// return (x & b) ? (x | ~m) : (x & m);
//}
template<unsigned bits, typename base = uint> class uint_t {
private:
base data;
public:
inline operator unsigned() const { return data; }
inline unsigned operator ++(int) { base r = data; data = uclip<bits>(data + 1); return r; }
inline unsigned operator --(int) { base r = data; data = uclip<bits>(data - 1); return r; }
inline unsigned operator ++() { data = uclip<bits>(data + 1); return data; }
inline unsigned operator --() { data = uclip<bits>(data - 1); return data; }
template<typename T> inline unsigned operator =(const T i) { data = uclip<bits>(i); return data; }
template<typename T> inline unsigned operator |=(const T i) { data = uclip<bits>(data | i); return data; }
template<typename T> inline unsigned operator ^=(const T i) { data = uclip<bits>(data ^ i); return data; }
template<typename T> inline unsigned operator &=(const T i) { data = uclip<bits>(data & i); return data; }
template<typename T> inline unsigned operator<<=(const T i) { data = uclip<bits>(data << i); return data; }
template<typename T> inline unsigned operator>>=(const T i) { data = uclip<bits>(data >> i); return data; }
template<typename T> inline unsigned operator +=(const T i) { data = uclip<bits>(data + i); return data; }
template<typename T> inline unsigned operator -=(const T i) { data = uclip<bits>(data - i); return data; }
template<typename T> inline unsigned operator *=(const T i) { data = uclip<bits>(data * i); return data; }
template<typename T> inline unsigned operator /=(const T i) { data = uclip<bits>(data / i); return data; }
template<typename T> inline unsigned operator %=(const T i) { data = uclip<bits>(data % i); return data; }
inline uint_t() : data(0) {}
inline uint_t(const base i) : data(uclip<bits>(i)) {}
};
template<unsigned bits, typename base = int> class int_t {
private:
base data;
public:
inline operator signed() const { return data; }
inline signed operator ++(int) { base r = data; data = sclip<bits>(data + 1); return r; }
inline signed operator --(int) { base r = data; data = sclip<bits>(data - 1); return r; }
inline signed operator ++() { data = sclip<bits>(data + 1); return data; }
inline signed operator --() { data = sclip<bits>(data - 1); return data; }
template<typename T> inline signed operator =(const T i) { data = sclip<bits>(i); return data; }
template<typename T> inline signed operator |=(const T i) { data = sclip<bits>(data | i); return data; }
template<typename T> inline signed operator ^=(const T i) { data = sclip<bits>(data ^ i); return data; }
template<typename T> inline signed operator &=(const T i) { data = sclip<bits>(data & i); return data; }
template<typename T> inline signed operator<<=(const T i) { data = sclip<bits>(data << i); return data; }
template<typename T> inline signed operator>>=(const T i) { data = sclip<bits>(data >> i); return data; }
template<typename T> inline signed operator +=(const T i) { data = sclip<bits>(data + i); return data; }
template<typename T> inline signed operator -=(const T i) { data = sclip<bits>(data - i); return data; }
template<typename T> inline signed operator *=(const T i) { data = sclip<bits>(data * i); return data; }
template<typename T> inline signed operator /=(const T i) { data = sclip<bits>(data / i); return data; }
template<typename T> inline signed operator %=(const T i) { data = sclip<bits>(data % i); return data; }
inline int_t() : data(0) {}
inline int_t(const base i) : data(sclip<bits>(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,

68
src/lib/libco_win32.cpp Normal file
View File

@ -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 <windows.h>
#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]);
}

215
src/lib/libco_x86.asm Normal file
View File

@ -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

15
src/lib/libco_x86.h Normal file
View File

@ -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();

View File

@ -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<typename T> 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<typename T> inline operator T() { return T(get()); }
template<typename T> inline Setting &operator=(const T x) { set(T(x)); return *this; }
template<typename T> inline bool operator==(const T x) { return T(get()) == x; }
template<typename T> inline bool operator!=(const T x) { return T(get()) != x; }
template<typename T> inline bool operator>=(const T x) { return T(get()) >= x; }
template<typename T> inline bool operator> (const T x) { return T(get()) > x; }
template<typename T> inline bool operator<=(const T x) { return T(get()) <= x; }
template<typename T> inline bool operator< (const T x) { return T(get()) < x; }
};
class Config {

View File

@ -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<ksl;i++) {
for(int i = 0; i < ksl; i++) {
if(str[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<ssl;i++, z++) {
for(int i = ssl - ksl, z = 0; i < ssl; i++, z++) {
if(str[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<ssl;i++) {
for(i = 0; i < ssl; i++) {
str[i] = str[i + 1];
}
str[i - 2] = 0;
@ -407,6 +417,112 @@ int sstrbin(const char *str) {
}
int sstrbin(substring &str) { return sstrbin(strptr(str)); }
char *utoa(char *str, uint num) {
char *pstr = str;
uint mask = 1000000000;
while(mask > 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"

View File

@ -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<typename T> inline substring& operator[](T i) { return str(i); }
string();
~string();

View File

@ -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)); }

View File

@ -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<strlen(s);i++) {
if(s[i] == '%') {
uint i = 0;
while(s[i]) {
if(s[i] != '%') {
strcat(str, s[i++]);
} else if(s[i + 1] == '%' || !s[i + 1]) {
strcat(str, '%');
} else { //s[i] == '%'
//format: %[flags][width][.precision][modifiers]type
i++;
if(s[i] == '0' && s[i+1] == '.' && (s[i+2] >= '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);
}

View File

@ -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;

View File

@ -9,6 +9,7 @@
#define WINVER 0x0400
#define _WIN32_WINNT 0x0400
#define _WIN32_IE 0x0400
#include <windows.h>
#include <commctrl.h>
#include <direct.h>
@ -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);

135
src/lib/opgen_s.cpp Normal file
View File

@ -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);
}

147
src/lib/opgen_so.cpp Normal file
View File

@ -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);
}

Some files were not shown because too many files have changed in this diff Show More