o add bsnes

This commit is contained in:
optixx
2009-04-08 21:29:36 +02:00
parent bcb4a055e9
commit 27b58a09f2
413 changed files with 71887 additions and 0 deletions

17
bsnes/cpu/cpu.cpp Executable file
View File

@@ -0,0 +1,17 @@
#include <../base.hpp>
#define CPU_CPP
#include "dcpu.cpp"
void CPU::power() {
cpu_version = snes.config.cpu.version;
}
void CPU::reset() {
}
CPU::CPU() {
}
CPU::~CPU() {
}

74
bsnes/cpu/cpu.hpp Executable file
View File

@@ -0,0 +1,74 @@
class CPU : public MMIO {
public:
virtual void enter() = 0;
//CPU version number
//* 1 and 2 are known
//* reported by $4210
//* affects timing (DRAM refresh, HDMA init, etc)
uint8 cpu_version;
virtual uint8 pio() = 0;
virtual bool joylatch() = 0;
virtual uint8 port_read(uint8 port) = 0;
virtual void port_write(uint8 port, uint8 value) = 0;
#include "cpuregs.hpp"
regs_t regs;
virtual void scanline() = 0;
virtual void power();
virtual void reset();
/*****
* 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
OPTYPE_DPY, //dp,y
OPTYPE_IDP, //(dp)
OPTYPE_IDPX, //(dp,x)
OPTYPE_IDPY, //(dp),y
OPTYPE_ILDP, //[dp]
OPTYPE_ILDPY, //[dp],y
OPTYPE_ADDR, //addr
OPTYPE_ADDRX, //addr,x
OPTYPE_ADDRY, //addr,y
OPTYPE_IADDRX, //(addr,x)
OPTYPE_ILADDR, //[addr]
OPTYPE_LONG, //long
OPTYPE_LONGX, //long, x
OPTYPE_SR, //sr,s
OPTYPE_ISRY, //(sr,s),y
OPTYPE_ADDR_PC, //pbr:addr
OPTYPE_IADDR_PC, //pbr:(addr)
OPTYPE_RELB, //relb
OPTYPE_RELW, //relw
};
void disassemble_opcode(char *output);
uint8 dreadb(uint32 addr);
uint16 dreadw(uint32 addr);
uint32 dreadl(uint32 addr);
uint32 decode(uint8 offset_type, uint32 addr);
uint8 opcode_length();
CPU();
virtual ~CPU();
};

74
bsnes/cpu/cpuregs.hpp Executable file
View File

@@ -0,0 +1,74 @@
struct flag_t {
bool n, v, m, x, d, i, z, c;
inline operator unsigned() const {
return (n << 7) + (v << 6) + (m << 5) + (x << 4)
+ (d << 3) + (i << 2) + (z << 1) + (c << 0);
}
inline unsigned operator=(uint8_t data) {
n = data & 0x80; v = data & 0x40; m = data & 0x20; x = data & 0x10;
d = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01;
return data;
}
inline unsigned operator|=(unsigned data) { return operator=(operator unsigned() | data); }
inline unsigned operator^=(unsigned data) { return operator=(operator unsigned() ^ data); }
inline unsigned operator&=(unsigned data) { return operator=(operator unsigned() & data); }
flag_t() : n(0), v(0), m(0), x(0), d(0), i(0), z(0), c(0) {}
};
struct reg16_t {
union {
uint16 w;
struct { uint8 order_lsb2(l, h); };
};
inline operator unsigned() const { return w; }
inline unsigned operator = (unsigned i) { return w = i; }
inline unsigned operator |= (unsigned i) { return w |= i; }
inline unsigned operator ^= (unsigned i) { return w ^= i; }
inline unsigned operator &= (unsigned i) { return w &= i; }
inline unsigned operator <<= (unsigned i) { return w <<= i; }
inline unsigned operator >>= (unsigned i) { return w >>= i; }
inline unsigned operator += (unsigned i) { return w += i; }
inline unsigned operator -= (unsigned i) { return w -= i; }
inline unsigned operator *= (unsigned i) { return w *= i; }
inline unsigned operator /= (unsigned i) { return w /= i; }
inline unsigned operator %= (unsigned i) { return w %= i; }
reg16_t() : w(0) {}
};
struct reg24_t {
union {
uint32 d;
struct { uint16 order_lsb2(w, wh); };
struct { uint8 order_lsb4(l, h, b, bh); };
};
inline operator unsigned() const { return d; }
inline unsigned operator = (unsigned i) { return d = uclip<24>(i); }
inline unsigned operator |= (unsigned i) { return d = uclip<24>(d | i); }
inline unsigned operator ^= (unsigned i) { return d = uclip<24>(d ^ i); }
inline unsigned operator &= (unsigned i) { return d = uclip<24>(d & i); }
inline unsigned operator <<= (unsigned i) { return d = uclip<24>(d << i); }
inline unsigned operator >>= (unsigned i) { return d = uclip<24>(d >> i); }
inline unsigned operator += (unsigned i) { return d = uclip<24>(d + i); }
inline unsigned operator -= (unsigned i) { return d = uclip<24>(d - i); }
inline unsigned operator *= (unsigned i) { return d = uclip<24>(d * i); }
inline unsigned operator /= (unsigned i) { return d = uclip<24>(d / i); }
inline unsigned operator %= (unsigned i) { return d = uclip<24>(d % i); }
reg24_t() : d(0) {}
};
struct regs_t {
reg24_t pc;
reg16_t a, x, y, s, d;
flag_t p;
uint8_t db, mdr;
bool e;
regs_t() : db(0), mdr(0), e(false) {}
};

483
bsnes/cpu/dcpu.cpp Executable file
View File

@@ -0,0 +1,483 @@
#ifdef CPU_CPP
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 bus.read(addr);
}
uint16 CPU::dreadw(uint32 addr) {
uint16 r;
r = dreadb((addr + 0) & 0xffffff) << 0;
r |= dreadb((addr + 1) & 0xffffff) << 8;
return r;
}
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:
r = (regs.d + (addr & 0xffff)) & 0xffff;
break;
case OPTYPE_DPX:
r = (regs.d + regs.x + (addr & 0xffff)) & 0xffff;
break;
case OPTYPE_DPY:
r = (regs.d + regs.y + (addr & 0xffff)) & 0xffff;
break;
case OPTYPE_IDP:
addr = (regs.d + (addr & 0xffff)) & 0xffff;
r = (regs.db << 16) + dreadw(addr);
break;
case OPTYPE_IDPX:
addr = (regs.d + regs.x + (addr & 0xffff)) & 0xffff;
r = (regs.db << 16) + dreadw(addr);
break;
case OPTYPE_IDPY:
addr = (regs.d + (addr & 0xffff)) & 0xffff;
r = (regs.db << 16) + dreadw(addr) + regs.y;
break;
case OPTYPE_ILDP:
addr = (regs.d + (addr & 0xffff)) & 0xffff;
r = dreadl(addr);
break;
case OPTYPE_ILDPY:
addr = (regs.d + (addr & 0xffff)) & 0xffff;
r = dreadl(addr) + regs.y;
break;
case OPTYPE_ADDR:
r = (regs.db << 16) + (addr & 0xffff);
break;
case OPTYPE_ADDR_PC:
r = (regs.pc.b << 16) + (addr & 0xffff);
break;
case OPTYPE_ADDRX:
r = (regs.db << 16) + (addr & 0xffff) + regs.x;
break;
case OPTYPE_ADDRY:
r = (regs.db << 16) + (addr & 0xffff) + regs.y;
break;
case OPTYPE_IADDR_PC:
r = (regs.pc.b << 16) + (addr & 0xffff);
break;
case OPTYPE_IADDRX:
r = (regs.pc.b << 16) + ((addr + regs.x) & 0xffff);
break;
case OPTYPE_ILADDR:
r = addr;
break;
case OPTYPE_LONG:
r = addr;
break;
case OPTYPE_LONGX:
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) + 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 & 0xffffff);
}
void CPU::disassemble_opcode(char *output) {
static reg24_t pc;
char t[256];
char *s = output;
if(in_opcode() == true) {
strcpy(s, "?????? <CPU within opcode>");
return;
}
pc.d = regs.pc.d;
sprintf(s, "%.6x ", (uint32)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 #$%.2x ", op8); break;
case 0x01: sprintf(t, "ora ($%.2x,x) [$%.6x]", op8, decode(OPTYPE_IDPX, op8)); break;
case 0x02: sprintf(t, "cop #$%.2x ", op8); break;
case 0x03: sprintf(t, "ora $%.2x,s [$%.6x]", op8, decode(OPTYPE_SR, op8)); break;
case 0x04: sprintf(t, "tsb $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0x05: sprintf(t, "ora $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0x06: sprintf(t, "asl $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0x07: sprintf(t, "ora [$%.2x] [$%.6x]", op8, decode(OPTYPE_ILDP, op8)); break;
case 0x08: sprintf(t, "php "); break;
case 0x09: if(a8)sprintf(t, "ora #$%.2x ", op8);
else sprintf(t, "ora #$%.4x ", op16); break;
case 0x0a: sprintf(t, "asl a "); break;
case 0x0b: sprintf(t, "phd "); break;
case 0x0c: sprintf(t, "tsb $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0x0d: sprintf(t, "ora $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0x0e: sprintf(t, "asl $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0x0f: sprintf(t, "ora $%.6x [$%.6x]", op24, decode(OPTYPE_LONG, op24)); break;
case 0x10: sprintf(t, "bpl $%.4x [$%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break;
case 0x11: sprintf(t, "ora ($%.2x),y [$%.6x]", op8, decode(OPTYPE_IDPY, op8)); break;
case 0x12: sprintf(t, "ora ($%.2x) [$%.6x]", op8, decode(OPTYPE_IDP, op8)); break;
case 0x13: sprintf(t, "ora ($%.2x,s),y [$%.6x]", op8, decode(OPTYPE_ISRY, op8)); break;
case 0x14: sprintf(t, "trb $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0x15: sprintf(t, "ora $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
case 0x16: sprintf(t, "asl $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
case 0x17: sprintf(t, "ora [$%.2x],y [$%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break;
case 0x18: sprintf(t, "clc "); break;
case 0x19: sprintf(t, "ora $%.4x,y [$%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break;
case 0x1a: sprintf(t, "inc "); break;
case 0x1b: sprintf(t, "tcs "); break;
case 0x1c: sprintf(t, "trb $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0x1d: sprintf(t, "ora $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
case 0x1e: sprintf(t, "asl $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
case 0x1f: sprintf(t, "ora $%.6x,x [$%.6x]", op24, decode(OPTYPE_LONGX, op24)); break;
case 0x20: sprintf(t, "jsr $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR_PC, op16)); break;
case 0x21: sprintf(t, "and ($%.2x,x) [$%.6x]", op8, decode(OPTYPE_IDPX, op8)); break;
case 0x22: sprintf(t, "jsl $%.6x [$%.6x]", op24, decode(OPTYPE_LONG, op24)); break;
case 0x23: sprintf(t, "and $%.2x,s [$%.6x]", op8, decode(OPTYPE_SR, op8)); break;
case 0x24: sprintf(t, "bit $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0x25: sprintf(t, "and $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0x26: sprintf(t, "rol $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0x27: sprintf(t, "and [$%.2x] [$%.6x]", op8, decode(OPTYPE_ILDP, op8)); break;
case 0x28: sprintf(t, "plp "); break;
case 0x29: if(a8)sprintf(t, "and #$%.2x ", op8);
else sprintf(t, "and #$%.4x ", op16); break;
case 0x2a: sprintf(t, "rol a "); break;
case 0x2b: sprintf(t, "pld "); break;
case 0x2c: sprintf(t, "bit $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0x2d: sprintf(t, "and $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0x2e: sprintf(t, "rol $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0x2f: sprintf(t, "and $%.6x [$%.6x]", op24, decode(OPTYPE_LONG, op24)); break;
case 0x30: sprintf(t, "bmi $%.4x [$%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break;
case 0x31: sprintf(t, "and ($%.2x),y [$%.6x]", op8, decode(OPTYPE_IDPY, op8)); break;
case 0x32: sprintf(t, "and ($%.2x) [$%.6x]", op8, decode(OPTYPE_IDP, op8)); break;
case 0x33: sprintf(t, "and ($%.2x,s),y [$%.6x]", op8, decode(OPTYPE_ISRY, op8)); break;
case 0x34: sprintf(t, "bit $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
case 0x35: sprintf(t, "and $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
case 0x36: sprintf(t, "rol $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
case 0x37: sprintf(t, "and [$%.2x],y [$%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break;
case 0x38: sprintf(t, "sec "); break;
case 0x39: sprintf(t, "and $%.4x,y [$%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break;
case 0x3a: sprintf(t, "dec "); break;
case 0x3b: sprintf(t, "tsc "); break;
case 0x3c: sprintf(t, "bit $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
case 0x3d: sprintf(t, "and $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
case 0x3e: sprintf(t, "rol $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
case 0x3f: sprintf(t, "and $%.6x,x [$%.6x]", op24, decode(OPTYPE_LONGX, op24)); break;
case 0x40: sprintf(t, "rti "); break;
case 0x41: sprintf(t, "eor ($%.2x,x) [$%.6x]", op8, decode(OPTYPE_IDPX, op8)); break;
case 0x42: sprintf(t, "wdm "); break;
case 0x43: sprintf(t, "eor $%.2x,s [$%.6x]", op8, decode(OPTYPE_SR, op8)); break;
case 0x44: sprintf(t, "mvp $%.2x,$%.2x ", op1, op8); break;
case 0x45: sprintf(t, "eor $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0x46: sprintf(t, "lsr $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0x47: sprintf(t, "eor [$%.2x] [$%.6x]", op8, decode(OPTYPE_ILDP, op8)); break;
case 0x48: sprintf(t, "pha "); break;
case 0x49: if(a8)sprintf(t, "eor #$%.2x ", op8);
else sprintf(t, "eor #$%.4x ", op16); break;
case 0x4a: sprintf(t, "lsr a "); break;
case 0x4b: sprintf(t, "phk "); break;
case 0x4c: sprintf(t, "jmp $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR_PC, op16)); break;
case 0x4d: sprintf(t, "eor $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0x4e: sprintf(t, "lsr $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0x4f: sprintf(t, "eor $%.6x [$%.6x]", op24, decode(OPTYPE_LONG, op24)); break;
case 0x50: sprintf(t, "bvc $%.4x [$%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break;
case 0x51: sprintf(t, "eor ($%.2x),y [$%.6x]", op8, decode(OPTYPE_IDPY, op8)); break;
case 0x52: sprintf(t, "eor ($%.2x) [$%.6x]", op8, decode(OPTYPE_IDP, op8)); break;
case 0x53: sprintf(t, "eor ($%.2x,s),y [$%.6x]", op8, decode(OPTYPE_ISRY, op8)); break;
case 0x54: sprintf(t, "mvn $%.2x,$%.2x ", op1, op8); break;
case 0x55: sprintf(t, "eor $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
case 0x56: sprintf(t, "lsr $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
case 0x57: sprintf(t, "eor [$%.2x],y [$%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break;
case 0x58: sprintf(t, "cli "); break;
case 0x59: sprintf(t, "eor $%.4x,y [$%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break;
case 0x5a: sprintf(t, "phy "); break;
case 0x5b: sprintf(t, "tcd "); break;
case 0x5c: sprintf(t, "jml $%.6x [$%.6x]", op24, decode(OPTYPE_LONG, op24)); break;
case 0x5d: sprintf(t, "eor $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
case 0x5e: sprintf(t, "lsr $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
case 0x5f: sprintf(t, "eor $%.6x,x [$%.6x]", op24, decode(OPTYPE_LONGX, op24)); break;
case 0x60: sprintf(t, "rts "); break;
case 0x61: sprintf(t, "adc ($%.2x,x) [$%.6x]", op8, decode(OPTYPE_IDPX, op8)); break;
case 0x62: sprintf(t, "per $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0x63: sprintf(t, "adc $%.2x,s [$%.6x]", op8, decode(OPTYPE_SR, op8)); break;
case 0x64: sprintf(t, "stz $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0x65: sprintf(t, "adc $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0x66: sprintf(t, "ror $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0x67: sprintf(t, "adc [$%.2x] [$%.6x]", op8, decode(OPTYPE_ILDP, op8)); break;
case 0x68: sprintf(t, "pla "); break;
case 0x69: if(a8)sprintf(t, "adc #$%.2x ", op8);
else sprintf(t, "adc #$%.4x ", op16); break;
case 0x6a: sprintf(t, "ror a "); break;
case 0x6b: sprintf(t, "rtl "); break;
case 0x6c: sprintf(t, "jmp ($%.4x) [$%.6x]", op16, decode(OPTYPE_IADDR_PC, op16)); break;
case 0x6d: sprintf(t, "adc $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0x6e: sprintf(t, "ror $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0x6f: sprintf(t, "adc $%.6x [$%.6x]", op24, decode(OPTYPE_LONG, op24)); break;
case 0x70: sprintf(t, "bvs $%.4x [$%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break;
case 0x71: sprintf(t, "adc ($%.2x),y [$%.6x]", op8, decode(OPTYPE_IDPY, op8)); break;
case 0x72: sprintf(t, "adc ($%.2x) [$%.6x]", op8, decode(OPTYPE_IDP, op8)); break;
case 0x73: sprintf(t, "adc ($%.2x,s),y [$%.6x]", op8, decode(OPTYPE_ISRY, op8)); break;
case 0x74: sprintf(t, "stz $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
case 0x75: sprintf(t, "adc $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
case 0x76: sprintf(t, "ror $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
case 0x77: sprintf(t, "adc [$%.2x],y [$%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break;
case 0x78: sprintf(t, "sei "); break;
case 0x79: sprintf(t, "adc $%.4x,y [$%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break;
case 0x7a: sprintf(t, "ply "); break;
case 0x7b: sprintf(t, "tdc "); break;
case 0x7c: sprintf(t, "jmp ($%.4x,x) [$%.6x]", op16, decode(OPTYPE_IADDRX, op16)); break;
case 0x7d: sprintf(t, "adc $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
case 0x7e: sprintf(t, "ror $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
case 0x7f: sprintf(t, "adc $%.6x,x [$%.6x]", op24, decode(OPTYPE_LONGX, op24)); break;
case 0x80: sprintf(t, "bra $%.4x [$%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break;
case 0x81: sprintf(t, "sta ($%.2x,x) [$%.6x]", op8, decode(OPTYPE_IDPX, op8)); break;
case 0x82: sprintf(t, "brl $%.4x [$%.6x]", uint16(decode(OPTYPE_RELW, op16)), decode(OPTYPE_RELW, op16)); break;
case 0x83: sprintf(t, "sta $%.2x,s [$%.6x]", op8, decode(OPTYPE_SR, op8)); break;
case 0x84: sprintf(t, "sty $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0x85: sprintf(t, "sta $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0x86: sprintf(t, "stx $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0x87: sprintf(t, "sta [$%.2x] [$%.6x]", op8, decode(OPTYPE_ILDP, op8)); break;
case 0x88: sprintf(t, "dey "); break;
case 0x89: if(a8)sprintf(t, "bit #$%.2x ", op8);
else sprintf(t, "bit #$%.4x ", op16); break;
case 0x8a: sprintf(t, "txa "); break;
case 0x8b: sprintf(t, "phb "); break;
case 0x8c: sprintf(t, "sty $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0x8d: sprintf(t, "sta $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0x8e: sprintf(t, "stx $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0x8f: sprintf(t, "sta $%.6x [$%.6x]", op24, decode(OPTYPE_LONG, op24)); break;
case 0x90: sprintf(t, "bcc $%.4x [$%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break;
case 0x91: sprintf(t, "sta ($%.2x),y [$%.6x]", op8, decode(OPTYPE_IDPY, op8)); break;
case 0x92: sprintf(t, "sta ($%.2x) [$%.6x]", op8, decode(OPTYPE_IDP, op8)); break;
case 0x93: sprintf(t, "sta ($%.2x,s),y [$%.6x]", op8, decode(OPTYPE_ISRY, op8)); break;
case 0x94: sprintf(t, "sty $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
case 0x95: sprintf(t, "sta $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
case 0x96: sprintf(t, "stx $%.2x,y [$%.6x]", op8, decode(OPTYPE_DPY, op8)); break;
case 0x97: sprintf(t, "sta [$%.2x],y [$%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break;
case 0x98: sprintf(t, "tya "); break;
case 0x99: sprintf(t, "sta $%.4x,y [$%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break;
case 0x9a: sprintf(t, "txs "); break;
case 0x9b: sprintf(t, "txy "); break;
case 0x9c: sprintf(t, "stz $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0x9d: sprintf(t, "sta $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
case 0x9e: sprintf(t, "stz $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
case 0x9f: sprintf(t, "sta $%.6x,x [$%.6x]", op24, decode(OPTYPE_LONGX, op24)); break;
case 0xa0: if(x8)sprintf(t, "ldy #$%.2x ", op8);
else sprintf(t, "ldy #$%.4x ", op16); break;
case 0xa1: sprintf(t, "lda ($%.2x,x) [$%.6x]", op8, decode(OPTYPE_IDPX, op8)); break;
case 0xa2: if(x8)sprintf(t, "ldx #$%.2x ", op8);
else sprintf(t, "ldx #$%.4x ", op16); break;
case 0xa3: sprintf(t, "lda $%.2x,s [$%.6x]", op8, decode(OPTYPE_SR, op8)); break;
case 0xa4: sprintf(t, "ldy $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0xa5: sprintf(t, "lda $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0xa6: sprintf(t, "ldx $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0xa7: sprintf(t, "lda [$%.2x] [$%.6x]", op8, decode(OPTYPE_ILDP, op8)); break;
case 0xa8: sprintf(t, "tay "); break;
case 0xa9: if(a8)sprintf(t, "lda #$%.2x ", op8);
else sprintf(t, "lda #$%.4x ", op16); break;
case 0xaa: sprintf(t, "tax "); break;
case 0xab: sprintf(t, "plb "); break;
case 0xac: sprintf(t, "ldy $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0xad: sprintf(t, "lda $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0xae: sprintf(t, "ldx $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0xaf: sprintf(t, "lda $%.6x [$%.6x]", op24, decode(OPTYPE_LONG, op24)); break;
case 0xb0: sprintf(t, "bcs $%.4x [$%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break;
case 0xb1: sprintf(t, "lda ($%.2x),y [$%.6x]", op8, decode(OPTYPE_IDPY, op8)); break;
case 0xb2: sprintf(t, "lda ($%.2x) [$%.6x]", op8, decode(OPTYPE_IDP, op8)); break;
case 0xb3: sprintf(t, "lda ($%.2x,s),y [$%.6x]", op8, decode(OPTYPE_ISRY, op8)); break;
case 0xb4: sprintf(t, "ldy $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
case 0xb5: sprintf(t, "lda $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
case 0xb6: sprintf(t, "ldx $%.2x,y [$%.6x]", op8, decode(OPTYPE_DPY, op8)); break;
case 0xb7: sprintf(t, "lda [$%.2x],y [$%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break;
case 0xb8: sprintf(t, "clv "); break;
case 0xb9: sprintf(t, "lda $%.4x,y [$%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break;
case 0xba: sprintf(t, "tsx "); break;
case 0xbb: sprintf(t, "tyx "); break;
case 0xbc: sprintf(t, "ldy $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
case 0xbd: sprintf(t, "lda $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
case 0xbe: sprintf(t, "ldx $%.4x,y [$%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break;
case 0xbf: sprintf(t, "lda $%.6x,x [$%.6x]", op24, decode(OPTYPE_LONGX, op24)); break;
case 0xc0: if(x8)sprintf(t, "cpy #$%.2x ", op8);
else sprintf(t, "cpy #$%.4x ", op16); break;
case 0xc1: sprintf(t, "cmp ($%.2x,x) [$%.6x]", op8, decode(OPTYPE_IDPX, op8)); break;
case 0xc2: sprintf(t, "rep #$%.2x ", op8); break;
case 0xc3: sprintf(t, "cmp $%.2x,s [$%.6x]", op8, decode(OPTYPE_SR, op8)); break;
case 0xc4: sprintf(t, "cpy $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0xc5: sprintf(t, "cmp $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0xc6: sprintf(t, "dec $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0xc7: sprintf(t, "cmp [$%.2x] [$%.6x]", op8, decode(OPTYPE_ILDP, op8)); break;
case 0xc8: sprintf(t, "iny "); break;
case 0xc9: if(a8)sprintf(t, "cmp #$%.2x ", op8);
else sprintf(t, "cmp #$%.4x ", op16); break;
case 0xca: sprintf(t, "dex "); break;
case 0xcb: sprintf(t, "wai "); break;
case 0xcc: sprintf(t, "cpy $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0xcd: sprintf(t, "cmp $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0xce: sprintf(t, "dec $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0xcf: sprintf(t, "cmp $%.6x [$%.6x]", op24, decode(OPTYPE_LONG, op24)); break;
case 0xd0: sprintf(t, "bne $%.4x [$%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break;
case 0xd1: sprintf(t, "cmp ($%.2x),y [$%.6x]", op8, decode(OPTYPE_IDPY, op8)); break;
case 0xd2: sprintf(t, "cmp ($%.2x) [$%.6x]", op8, decode(OPTYPE_IDP, op8)); break;
case 0xd3: sprintf(t, "cmp ($%.2x,s),y [$%.6x]", op8, decode(OPTYPE_ISRY, op8)); break;
case 0xd4: sprintf(t, "pei ($%.2x) [$%.6x]", op8, decode(OPTYPE_IDP, op8)); break;
case 0xd5: sprintf(t, "cmp $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
case 0xd6: sprintf(t, "dec $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
case 0xd7: sprintf(t, "cmp [$%.2x],y [$%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break;
case 0xd8: sprintf(t, "cld "); break;
case 0xd9: sprintf(t, "cmp $%.4x,y [$%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break;
case 0xda: sprintf(t, "phx "); break;
case 0xdb: sprintf(t, "stp "); break;
case 0xdc: sprintf(t, "jmp [$%.4x] [$%.6x]", op16, decode(OPTYPE_ILADDR, op16)); break;
case 0xdd: sprintf(t, "cmp $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
case 0xde: sprintf(t, "dec $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
case 0xdf: sprintf(t, "cmp $%.6x,x [$%.6x]", op24, decode(OPTYPE_LONGX, op24)); break;
case 0xe0: if(x8)sprintf(t, "cpx #$%.2x ", op8);
else sprintf(t, "cpx #$%.4x ", op16); break;
case 0xe1: sprintf(t, "sbc ($%.2x,x) [$%.6x]", op8, decode(OPTYPE_IDPX, op8)); break;
case 0xe2: sprintf(t, "sep #$%.2x ", op8); break;
case 0xe3: sprintf(t, "sbc $%.2x,s [$%.6x]", op8, decode(OPTYPE_SR, op8)); break;
case 0xe4: sprintf(t, "cpx $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0xe5: sprintf(t, "sbc $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0xe6: sprintf(t, "inc $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
case 0xe7: sprintf(t, "sbc [$%.2x] [$%.6x]", op8, decode(OPTYPE_ILDP, op8)); break;
case 0xe8: sprintf(t, "inx "); break;
case 0xe9: if(a8)sprintf(t, "sbc #$%.2x ", op8);
else sprintf(t, "sbc #$%.4x ", op16); break;
case 0xea: sprintf(t, "nop "); break;
case 0xeb: sprintf(t, "xba "); break;
case 0xec: sprintf(t, "cpx $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0xed: sprintf(t, "sbc $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0xee: sprintf(t, "inc $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0xef: sprintf(t, "sbc $%.6x [$%.6x]", op24, decode(OPTYPE_LONG, op24)); break;
case 0xf0: sprintf(t, "beq $%.4x [$%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break;
case 0xf1: sprintf(t, "sbc ($%.2x),y [$%.6x]", op8, decode(OPTYPE_IDPY, op8)); break;
case 0xf2: sprintf(t, "sbc ($%.2x) [$%.6x]", op8, decode(OPTYPE_IDP, op8)); break;
case 0xf3: sprintf(t, "sbc ($%.2x,s),y [$%.6x]", op8, decode(OPTYPE_ISRY, op8)); break;
case 0xf4: sprintf(t, "pea $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
case 0xf5: sprintf(t, "sbc $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
case 0xf6: sprintf(t, "inc $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
case 0xf7: sprintf(t, "sbc [$%.2x],y [$%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break;
case 0xf8: sprintf(t, "sed "); break;
case 0xf9: sprintf(t, "sbc $%.4x,y [$%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break;
case 0xfa: sprintf(t, "plx "); break;
case 0xfb: sprintf(t, "xce "); break;
case 0xfc: sprintf(t, "jsr ($%.4x,x) [$%.6x]", op16, decode(OPTYPE_IADDRX, op16)); break;
case 0xfd: sprintf(t, "sbc $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
case 0xfe: sprintf(t, "inc $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
case 0xff: sprintf(t, "sbc $%.6x,x [$%.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:%.4x X:%.4x Y:%.4x S:%.4x D:%.4x DB:%.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');
} 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');
}
strcat(s, t);
strcat(s, " ");
sprintf(t, "V:%3d H:%4d", ppu.vcounter(), ppu.hcounter());
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.
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
2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0x3n
1,2,2,2, 3,2,2,2, 1,5,1,1, 3,3,3,4, //0x4n
2,2,2,2, 3,2,2,2, 1,3,1,1, 4,3,3,4, //0x5n
1,2,3,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0x6n
2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0x7n
2,2,3,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0x8n
2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0x9n
6,2,6,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0xan
2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0xbn
6,2,2,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0xcn
2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0xdn
6,2,2,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0xen
2,2,2,2, 3,2,2,2, 1,3,1,1, 3,3,3,4 //0xfn
};
if(in_opcode() == true) {
return 0;
}
op = dreadb(regs.pc.d);
len = op_len_tbl[op];
if(len == 5) return (regs.e || regs.p.m) ? 2 : 3;
if(len == 6) return (regs.e || regs.p.x) ? 2 : 3;
return len;
}
#endif //ifdef CPU_CPP

4
bsnes/cpu/scpu/core/cc.sh Executable file
View File

@@ -0,0 +1,4 @@
g++ -c scpugen.cpp -I../../../lib
g++ -c ../../../lib/nall/string.cpp -I../../../lib
g++ -o scpugen scpugen.o string.o
rm *.o

1
bsnes/cpu/scpu/core/clean.sh Executable file
View File

@@ -0,0 +1 @@
rm scpugen

90
bsnes/cpu/scpu/core/core.cpp Executable file
View File

@@ -0,0 +1,90 @@
#ifdef SCPU_CPP
#include "opfn.cpp"
void sCPU::enter() {
initialize:
//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);
loop:
if(status.interrupt_pending) {
status.interrupt_pending = false;
if(status.nmi_pending) {
status.nmi_pending = false;
status.interrupt_vector = (regs.e == false ? 0xffea : 0xfffa);
} else if(status.irq_pending) {
status.irq_pending = false;
status.interrupt_vector = (regs.e == false ? 0xffee : 0xfffe);
}
op_irq();
}
tracer.trace_cpuop(); //traces CPU opcode (only if tracer is enabled)
status.in_opcode = true;
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;
goto loop;
}
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(status.interrupt_vector + 0);
regs.pc.b = 0x00;
regs.p.i = 1;
regs.p.d = 0;
rd.h = op_read(status.interrupt_vector + 1);
regs.pc.w = rd.w;
}
//immediate, 2-cycle opcodes with I/O cycle will become bus read
//when an IRQ is to be triggered immediately after opcode completion
//this affects the following opcodes:
// clc, cld, cli, clv, sec, sed, sei,
// tax, tay, txa, txy, tya, tyx,
// tcd, tcs, tdc, tsc, tsx, txs,
// inc, inx, iny, dec, dex, dey,
// asl, lsr, rol, ror, nop, xce.
alwaysinline void sCPU::op_io_irq() {
if(status.interrupt_pending) {
//IRQ pending, modify I/O cycle to bus read cycle, do not increment PC
op_read(regs.pc.d);
} else {
op_io();
}
}
alwaysinline void sCPU::op_io_cond2() {
if(regs.d.l != 0x00) {
op_io();
}
}
alwaysinline void sCPU::op_io_cond4(uint16 x, uint16 y) {
if(!regs.p.x || (x & 0xff00) != (y & 0xff00)) {
op_io();
}
}
alwaysinline void sCPU::op_io_cond6(uint16 addr) {
if(regs.e && (regs.pc.w & 0xff00) != (addr & 0xff00)) {
op_io();
}
}
#endif

54
bsnes/cpu/scpu/core/core.hpp Executable file
View File

@@ -0,0 +1,54 @@
reg24_t aa, rd;
uint8_t dp, sp;
void op_irq();
inline 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_irq();
void op_io_cond2();
void op_io_cond4(uint16 x, uint16 y);
void op_io_cond6(uint16 addr);

298
bsnes/cpu/scpu/core/op_misc.b Executable file
View File

@@ -0,0 +1,298 @@
nop(0xea) {
1:last_cycle();
op_io_irq();
}
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(true) op_io();
}
wai(0xcb) {
//last_cycle() will clear status.wai_lock once an NMI / IRQ edge is reached
1:status.wai_lock = true;
while(status.wai_lock) {
last_cycle();
op_io();
}
2:op_io();
}
xce(0xfb) {
1:last_cycle();
op_io_irq();
bool carry = regs.p.c;
regs.p.c = regs.e;
regs.e = carry;
if(regs.e) {
regs.p |= 0x30;
regs.s.h = 0x01;
}
if(regs.p.x) {
regs.x.h = 0x00;
regs.y.h = 0x00;
}
}
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_irq();
$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_irq();
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_irq();
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_irq();
regs.s.w = regs.a.w;
if(regs.e) regs.s.h = 0x01;
}
tdc(0x7b) {
1:last_cycle();
op_io_irq();
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_irq();
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_irq();
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_irq();
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) {
1:op_io();
2:if(!$1)op_writestack(regs.$2.h);
3:last_cycle();
op_writestack(regs.$2.l);
}
phd(0x0b) {
1:op_io();
2:op_writestackn(regs.d.h);
3:last_cycle();
op_writestackn(regs.d.l);
if(regs.e) regs.s.h = 0x01;
}
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) {
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);
}
pld(0x2b) {
1:op_io();
2:op_io();
3:regs.d.l = op_readstackn();
4:last_cycle();
regs.d.h = op_readstackn();
regs.p.n = !!(regs.d.w & 0x8000);
regs.p.z = (regs.d.w == 0);
if(regs.e) regs.s.h = 0x01;
}
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_writestackn(aa.h);
4:last_cycle();
op_writestackn(aa.l);
if(regs.e) regs.s.h = 0x01;
}
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_writestackn(aa.h);
6:last_cycle();
op_writestackn(aa.l);
if(regs.e) regs.s.h = 0x01;
}
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_writestackn(rd.h);
5:last_cycle();
op_writestackn(rd.l);
if(regs.e) regs.s.h = 0x01;
}

539
bsnes/cpu/scpu/core/op_misc.cpp Executable file
View File

@@ -0,0 +1,539 @@
#ifdef SCPU_CPP
//nop
case 0xea: {
last_cycle();
op_io_irq();
} 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(true) op_io();
} break;
//wai
case 0xcb: {
//last_cycle() will clear status.wai_lock once an NMI / IRQ edge is reached
status.wai_lock = true;
while(status.wai_lock) {
last_cycle();
op_io();
}
op_io();
} break;
//xce
case 0xfb: {
last_cycle();
op_io_irq();
bool carry = regs.p.c;
regs.p.c = regs.e;
regs.e = carry;
if(regs.e) {
regs.p |= 0x30;
regs.s.h = 0x01;
}
if(regs.p.x) {
regs.x.h = 0x00;
regs.y.h = 0x00;
}
} break;
//clc
case 0x18: {
last_cycle();
op_io_irq();
regs.p.c = 0;
} break;
//cld
case 0xd8: {
last_cycle();
op_io_irq();
regs.p.d = 0;
} break;
//cli
case 0x58: {
last_cycle();
op_io_irq();
regs.p.i = 0;
} break;
//clv
case 0xb8: {
last_cycle();
op_io_irq();
regs.p.v = 0;
} break;
//sec
case 0x38: {
last_cycle();
op_io_irq();
regs.p.c = 1;
} break;
//sed
case 0xf8: {
last_cycle();
op_io_irq();
regs.p.d = 1;
} break;
//sei
case 0x78: {
last_cycle();
op_io_irq();
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_irq();
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_irq();
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_irq();
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_irq();
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_irq();
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_irq();
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_irq();
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_irq();
regs.s.w = regs.a.w;
if(regs.e) regs.s.h = 0x01;
} break;
//tdc
case 0x7b: {
last_cycle();
op_io_irq();
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_irq();
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_irq();
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_irq();
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();
op_writestackn(regs.d.h);
last_cycle();
op_writestackn(regs.d.l);
if(regs.e) regs.s.h = 0x01;
} 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();
regs.d.l = op_readstackn();
last_cycle();
regs.d.h = op_readstackn();
regs.p.n = !!(regs.d.w & 0x8000);
regs.p.z = (regs.d.w == 0);
if(regs.e) regs.s.h = 0x01;
} 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_writestackn(aa.h);
last_cycle();
op_writestackn(aa.l);
if(regs.e) regs.s.h = 0x01;
} break;
//pei
case 0xd4: {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp);
aa.h = op_readdp(dp + 1);
op_writestackn(aa.h);
last_cycle();
op_writestackn(aa.l);
if(regs.e) regs.s.h = 0x01;
} break;
//per
case 0x62: {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
rd.w = regs.pc.d + (int16)aa.w;
op_writestackn(rd.h);
last_cycle();
op_writestackn(rd.l);
if(regs.e) regs.s.h = 0x01;
} break;
#endif

163
bsnes/cpu/scpu/core/op_pc.b Executable file
View File

@@ -0,0 +1,163 @@
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_writestackn(regs.pc.b);
4:op_io();
5:aa.b = op_readpc();
6:regs.pc.w--;
op_writestackn(regs.pc.h);
7:last_cycle();
op_writestackn(regs.pc.l);
regs.pc.d = aa.d & 0xffffff;
if(regs.e) regs.s.h = 0x01;
}
jsr_iaddrx(0xfc) {
1:aa.l = op_readpc();
2:op_writestackn(regs.pc.h);
3:op_writestackn(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;
if(regs.e) regs.s.h = 0x01;
}
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_readstackn();
4:rd.h = op_readstackn();
5:last_cycle();
rd.b = op_readstackn();
regs.pc.d = rd.d & 0xffffff;
regs.pc.w++;
if(regs.e) regs.s.h = 0x01;
}

279
bsnes/cpu/scpu/core/op_pc.cpp Executable file
View File

@@ -0,0 +1,279 @@
#ifdef SCPU_CPP
//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_writestackn(regs.pc.b);
op_io();
aa.b = op_readpc();
regs.pc.w--;
op_writestackn(regs.pc.h);
last_cycle();
op_writestackn(regs.pc.l);
regs.pc.d = aa.d & 0xffffff;
if(regs.e) regs.s.h = 0x01;
} break;
//jsr_iaddrx
case 0xfc: {
aa.l = op_readpc();
op_writestackn(regs.pc.h);
op_writestackn(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;
if(regs.e) regs.s.h = 0x01;
} 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_readstackn();
rd.h = op_readstackn();
last_cycle();
rd.b = op_readstackn();
regs.pc.d = rd.d & 0xffffff;
regs.pc.w++;
if(regs.e) regs.s.h = 0x01;
} break;
#endif

317
bsnes/cpu/scpu/core/op_read.b Executable 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);
}

1654
bsnes/cpu/scpu/core/op_read.cpp Executable file

File diff suppressed because it is too large Load Diff

181
bsnes/cpu/scpu/core/op_rmw.b Executable 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_irq();
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_irq();
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_irq();
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_irq();
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_irq();
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_irq();
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);
}

573
bsnes/cpu/scpu/core/op_rmw.cpp Executable file
View File

@@ -0,0 +1,573 @@
#ifdef SCPU_CPP
//inc
case 0x1a: {
last_cycle();
op_io_irq();
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_irq();
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_irq();
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_irq();
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_irq();
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_irq();
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_irq();
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_irq();
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_irq();
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_irq();
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;
#endif

181
bsnes/cpu/scpu/core/op_write.b Executable file
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();
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();
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();
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);
}

293
bsnes/cpu/scpu/core/op_write.cpp Executable file
View File

@@ -0,0 +1,293 @@
#ifdef SCPU_CPP
//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();
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();
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();
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();
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;
#endif

371
bsnes/cpu/scpu/core/opfn.cpp Executable file
View File

@@ -0,0 +1,371 @@
#ifdef SCPU_CPP
//op_read
inline void sCPU::op_adc_b() {
int 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;
if(n0 > 9) {
n0 = (n0 - 10) & 15;
n1++;
}
n1 += ((rd.l >> 4) & 15);
if(n1 > 9) {
n1 = (n1 - 10) & 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() {
int 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 = (n0 - 10) & 15;
n1++;
}
n1 += ((rd.w >> 4) & 15);
if(n1 > 9) {
n1 = (n1 - 10) & 15;
n2++;
}
n2 += ((rd.w >> 8) & 15);
if(n2 > 9) {
n2 = (n2 - 10) & 15;
n3++;
}
n3 += ((rd.w >> 12) & 15);
if(n3 > 9) {
n3 = (n3 - 10) & 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() {
int 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() {
int 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() {
int 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() {
int 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() {
int 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() {
int 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() {
int 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() {
int 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() {
unsigned carry = (unsigned)regs.p.c;
regs.p.c = rd.l & 0x80;
rd.l = (rd.l << 1) | carry;
regs.p.n = rd.l & 0x80;
regs.p.z = rd.l == 0;
}
inline void sCPU::op_rol_w() {
unsigned carry = (unsigned)regs.p.c;
regs.p.c = rd.w & 0x8000;
rd.w = (rd.w << 1) | carry;
regs.p.n = rd.w & 0x8000;
regs.p.z = rd.w == 0;
}
inline void sCPU::op_ror_b() {
unsigned carry = (unsigned)regs.p.c << 7;
regs.p.c = rd.l & 1;
rd.l = carry | (rd.l >> 1);
regs.p.n = rd.l & 0x80;
regs.p.z = rd.l == 0;
}
inline void sCPU::op_ror_w() {
unsigned carry = (unsigned)regs.p.c << 15;
regs.p.c = rd.w & 1;
rd.w = carry | (rd.w >> 1);
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;
}
#endif //ifdef SCPU_CPP

12
bsnes/cpu/scpu/core/scpugen.cpp Executable file
View File

@@ -0,0 +1,12 @@
#define CLASS_NAME "sCPU"
#include <tool/opgen_switch.cpp>
int main() {
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");
return 0;
}

271
bsnes/cpu/scpu/dma/dma.cpp Executable file
View File

@@ -0,0 +1,271 @@
#ifdef SCPU_CPP
void sCPU::dma_add_clocks(unsigned clocks) {
status.dma_clocks += clocks;
add_clocks(clocks);
}
bool sCPU::dma_addr_valid(uint32 abus) {
//reads from B-bus or S-CPU registers are invalid
if((abus & 0x40ff00) == 0x2100) return false; //$[00-3f|80-bf]:[2100-21ff]
if((abus & 0x40fe00) == 0x4000) return false; //$[00-3f|80-bf]:[4000-41ff]
if((abus & 0x40ffe0) == 0x4200) return false; //$[00-3f|80-bf]:[4200-421f]
if((abus & 0x40ff80) == 0x4300) return false; //$[00-3f|80-bf]:[4300-437f]
return true;
}
uint8 sCPU::dma_read(uint32 abus) {
if(dma_addr_valid(abus) == false) return 0x00; //does not return S-CPU MDR
return bus.read(abus);
}
void sCPU::dma_transfer(bool direction, uint8 bbus, uint32 abus) {
if(direction == 0) {
//a->b transfer (to $21xx)
if(bbus == 0x80 && ((abus & 0xfe0000) == 0x7e0000 || (abus & 0x40e000) == 0x0000)) {
//illegal WRAM->WRAM transfer (bus conflict)
//read most likely occurs; no write occurs
//read is irrelevent, as it cannot be observed by software
dma_add_clocks(8);
} else {
dma_add_clocks(4);
uint8 data = dma_read(abus);
dma_add_clocks(4);
bus.write(0x2100 | bbus, data);
}
} else {
//b->a transfer (from $21xx)
if(bbus == 0x80 && ((abus & 0xfe0000) == 0x7e0000 || (abus & 0x40e000) == 0x0000)) {
//illegal WRAM->WRAM transfer (bus conflict)
//no read occurs; write does occur
dma_add_clocks(8);
bus.write(abus, 0x00); //does not write S-CPU MDR
} else {
dma_add_clocks(4);
uint8 data = bus.read(0x2100 | bbus);
dma_add_clocks(4);
if(dma_addr_valid(abus) == true) {
bus.write(abus, data);
}
}
}
cycle_edge();
}
/*****
* address calculation functions
*****/
uint8 sCPU::dma_bbus(uint8 i, uint8 index) {
switch(channel[i].xfermode) { default:
case 0: return (channel[i].destaddr); //0
case 1: return (channel[i].destaddr + (index & 1)); //0,1
case 2: return (channel[i].destaddr); //0,0
case 3: return (channel[i].destaddr + ((index >> 1) & 1)); //0,0,1,1
case 4: return (channel[i].destaddr + (index & 3)); //0,1,2,3
case 5: return (channel[i].destaddr + (index & 1)); //0,1,0,1
case 6: return (channel[i].destaddr); //0,0 [2]
case 7: return (channel[i].destaddr + ((index >> 1) & 1)); //0,0,1,1 [3]
}
}
inline 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;
}
inline uint32 sCPU::hdma_addr(uint8 i) {
return (channel[i].srcbank << 16) | (channel[i].hdma_addr++);
}
inline uint32 sCPU::hdma_iaddr(uint8 i) {
return (channel[i].hdma_ibank << 16) | (channel[i].hdma_iaddr++);
}
/*****
* DMA functions
*****/
uint8 sCPU::dma_enabled_channels() {
uint8 r = 0;
for(unsigned i = 0; i < 8; i++) {
if(channel[i].dma_enabled) r++;
}
return r;
}
void sCPU::dma_run() {
dma_add_clocks(8);
cycle_edge();
for(unsigned i = 0; i < 8; i++) {
if(channel[i].dma_enabled == false) continue;
dma_add_clocks(8);
cycle_edge();
unsigned index = 0;
do {
dma_transfer(channel[i].direction, dma_bbus(i, index++), dma_addr(i));
} while(channel[i].dma_enabled && --channel[i].xfersize);
channel[i].dma_enabled = false;
}
status.irq_lock = true;
event.enqueue(2, EventIrqLockRelease);
}
/*****
* HDMA functions
*****/
inline bool sCPU::hdma_active(uint8 i) {
return (channel[i].hdma_enabled && !channel[i].hdma_completed);
}
inline bool sCPU::hdma_active_after(uint8 i) {
for(unsigned n = i + 1; n < 8; n++) {
if(hdma_active(n) == true) return true;
}
return false;
}
inline uint8 sCPU::hdma_enabled_channels() {
uint8 r = 0;
for(unsigned i = 0; i < 8; i++) {
if(channel[i].hdma_enabled) r++;
}
return r;
}
inline uint8 sCPU::hdma_active_channels() {
uint8 r = 0;
for(unsigned i = 0; i < 8; i++) {
if(hdma_active(i) == true) r++;
}
return r;
}
void sCPU::hdma_update(uint8 i) {
channel[i].hdma_line_counter = dma_read(hdma_addr(i));
dma_add_clocks(8);
channel[i].hdma_completed = (channel[i].hdma_line_counter == 0);
channel[i].hdma_do_transfer = !channel[i].hdma_completed;
if(channel[i].hdma_indirect) {
channel[i].hdma_iaddr = dma_read(hdma_addr(i)) << 8;
dma_add_clocks(8);
if(!channel[i].hdma_completed || hdma_active_after(i)) {
channel[i].hdma_iaddr >>= 8;
channel[i].hdma_iaddr |= dma_read(hdma_addr(i)) << 8;
dma_add_clocks(8);
}
}
}
void sCPU::hdma_run() {
dma_add_clocks(8);
for(unsigned i = 0; i < 8; i++) {
if(hdma_active(i) == false) continue;
channel[i].dma_enabled = false; //HDMA run during DMA will stop DMA mid-transfer
if(channel[i].hdma_do_transfer) {
static const unsigned transfer_length[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
unsigned length = transfer_length[channel[i].xfermode];
for(unsigned index = 0; index < length; index++) {
unsigned addr = !channel[i].hdma_indirect ? hdma_addr(i) : hdma_iaddr(i);
dma_transfer(channel[i].direction, dma_bbus(i, index), addr);
}
}
}
for(unsigned i = 0; i < 8; i++) {
if(hdma_active(i) == false) continue;
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);
} else {
dma_add_clocks(8);
}
}
status.irq_lock = true;
event.enqueue(2, EventIrqLockRelease);
}
void sCPU::hdma_init_reset() {
for(unsigned i = 0; i < 8; i++) {
channel[i].hdma_completed = false;
channel[i].hdma_do_transfer = false;
}
}
void sCPU::hdma_init() {
dma_add_clocks(8);
for(unsigned i = 0; i < 8; i++) {
if(!channel[i].hdma_enabled) continue;
channel[i].dma_enabled = false; //HDMA init during DMA will stop DMA mid-transfer
channel[i].hdma_addr = channel[i].srcaddr;
hdma_update(i);
}
status.irq_lock = true;
event.enqueue(2, EventIrqLockRelease);
}
/*****
* power / reset functions
*****/
void sCPU::dma_power() {
for(unsigned i = 0; i < 8; i++) {
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;
}
}
void sCPU::dma_reset() {
for(unsigned i = 0; i < 8; i++) {
channel[i].dma_enabled = false;
channel[i].hdma_enabled = false;
channel[i].hdma_completed = false;
channel[i].hdma_do_transfer = false;
}
}
#endif //ifdef SCPU_CPP

71
bsnes/cpu/scpu/dma/dma.hpp Executable file
View File

@@ -0,0 +1,71 @@
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_add_clocks(unsigned clocks);
bool dma_addr_valid(uint32 abus);
uint8 dma_read(uint32 abus);
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);
uint8 dma_enabled_channels();
void dma_run();
bool hdma_active(uint8 i);
bool hdma_active_after(uint8 i);
uint8 hdma_enabled_channels();
uint8 hdma_active_channels();
void hdma_update(uint8 i);
void hdma_run();
void hdma_init_reset();
void hdma_init();
void dma_power();
void dma_reset();

125
bsnes/cpu/scpu/memory/memory.cpp Executable file
View File

@@ -0,0 +1,125 @@
#ifdef SCPU_CPP
/*****
* 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;
precycle_edge();
add_clocks(6);
cycle_edge();
}
uint8 sCPU::op_read(uint32 addr) {
status.clock_count = bus.speed(addr);
precycle_edge();
add_clocks(status.clock_count - 4);
regs.mdr = bus.read(addr);
add_clocks(4);
cycle_edge();
return regs.mdr;
}
void sCPU::op_write(uint32 addr, uint8 data) {
status.clock_count = bus.speed(addr);
precycle_edge();
add_clocks(status.clock_count);
regs.mdr = data;
bus.write(addr, regs.mdr);
cycle_edge();
}
//
alwaysinline uint8 sCPU::op_readpc() {
return op_read((regs.pc.b << 16) + regs.pc.w++);
}
alwaysinline uint8 sCPU::op_readstack() {
if(regs.e) {
regs.s.l++;
} else {
regs.s.w++;
}
return op_read(regs.s.w);
}
alwaysinline uint8 sCPU::op_readstackn() {
return op_read(++regs.s.w);
}
alwaysinline uint8 sCPU::op_readaddr(uint32 addr) {
return op_read(addr & 0xffff);
}
alwaysinline uint8 sCPU::op_readlong(uint32 addr) {
return op_read(addr & 0xffffff);
}
alwaysinline uint8 sCPU::op_readdbr(uint32 addr) {
return op_read(((regs.db << 16) + addr) & 0xffffff);
}
alwaysinline uint8 sCPU::op_readpbr(uint32 addr) {
return op_read((regs.pc.b << 16) + (addr & 0xffff));
}
alwaysinline uint8 sCPU::op_readdp(uint32 addr) {
if(regs.e && regs.d.l == 0x00) {
return op_read((regs.d & 0xff00) + ((regs.d + (addr & 0xffff)) & 0xff));
} else {
return op_read((regs.d + (addr & 0xffff)) & 0xffff);
}
}
alwaysinline uint8 sCPU::op_readsp(uint32 addr) {
return op_read((regs.s + (addr & 0xffff)) & 0xffff);
}
alwaysinline void sCPU::op_writestack(uint8 data) {
op_write(regs.s.w, data);
if(regs.e) {
regs.s.l--;
} else {
regs.s.w--;
}
}
alwaysinline void sCPU::op_writestackn(uint8 data) {
op_write(regs.s.w--, data);
}
alwaysinline void sCPU::op_writeaddr(uint32 addr, uint8 data) {
op_write(addr & 0xffff, data);
}
alwaysinline void sCPU::op_writelong(uint32 addr, uint8 data) {
op_write(addr & 0xffffff, data);
}
alwaysinline void sCPU::op_writedbr(uint32 addr, uint8 data) {
op_write(((regs.db << 16) + addr) & 0xffffff, data);
}
alwaysinline void sCPU::op_writepbr(uint32 addr, uint8 data) {
op_write((regs.pc.b << 16) + (addr & 0xffff), data);
}
alwaysinline void sCPU::op_writedp(uint32 addr, uint8 data) {
if(regs.e && regs.d.l == 0x00) {
op_write((regs.d & 0xff00) + ((regs.d + (addr & 0xffff)) & 0xff), data);
} else {
op_write((regs.d + (addr & 0xffff)) & 0xffff, data);
}
}
alwaysinline void sCPU::op_writesp(uint32 addr, uint8 data) {
op_write((regs.s + (addr & 0xffff)) & 0xffff, data);
}
#endif //ifdef SCPU_CPP

View File

@@ -0,0 +1,35 @@
/*****
* 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 ();
uint8 op_readstack ();
uint8 op_readstackn();
uint8 op_readaddr (uint32 addr);
uint8 op_readlong (uint32 addr);
uint8 op_readdbr (uint32 addr);
uint8 op_readpbr (uint32 addr);
uint8 op_readdp (uint32 addr);
uint8 op_readsp (uint32 addr);
void op_writestack (uint8 data);
void op_writestackn(uint8 data);
void op_writeaddr (uint32 addr, uint8 data);
void op_writelong (uint32 addr, uint8 data);
void op_writedbr (uint32 addr, uint8 data);
void op_writepbr (uint32 addr, uint8 data);
void op_writedp (uint32 addr, uint8 data);
void op_writesp (uint32 addr, uint8 data);

534
bsnes/cpu/scpu/mmio/mmio.cpp Executable file
View File

@@ -0,0 +1,534 @@
#ifdef SCPU_CPP
uint8 sCPU::pio() { return status.pio; }
bool sCPU::joylatch() { return status.joypad_strobe_latch; }
//WMDATA
uint8 sCPU::mmio_r2180() {
uint8 r = bus.read(0x7e0000 | status.wram_addr);
status.wram_addr = (status.wram_addr + 1) & 0x01ffff;
return r;
}
//WMDATA
void sCPU::mmio_w2180(uint8 data) {
bus.write(0x7e0000 | status.wram_addr, data);
status.wram_addr = (status.wram_addr + 1) & 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;
}
//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 = !!(data & 1);
if(status.joypad_strobe_latch == 1) {
snes.input.poll();
}
}
//JOYSER0
//7-2 = MDR
//1-0 = Joypad serial data
//
//TODO: test whether strobe latch of zero returns
//realtime or buffered status of joypadN.b
uint8 sCPU::mmio_r4016() {
uint8 r = regs.mdr & 0xfc;
r |= snes.input.port_read(0) & 3;
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;
r |= snes.input.port_read(1) & 3;
return r;
}
//NMITIMEN
void sCPU::mmio_w4200(uint8 data) {
status.auto_joypad_poll = !!(data & 0x01);
nmitimen_update(data);
}
//WRIO
void sCPU::mmio_w4201(uint8 data) {
if((status.pio & 0x80) && !(data & 0x80)) {
ppu.latch_counters();
}
status.pio = data;
}
//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;
status.alu_lock = true;
event.enqueue(snes.config.cpu.alu_mul_delay, EventAluLockRelease);
}
//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;
status.alu_lock = true;
event.enqueue(snes.config.cpu.alu_div_delay, EventAluLockRelease);
}
//HTIMEL
void sCPU::mmio_w4207(uint8 data) {
status.hirq_pos = (status.hirq_pos & ~0xff) | (data);
status.hirq_pos &= 0x01ff;
}
//HTIMEH
void sCPU::mmio_w4208(uint8 data) {
status.hirq_pos = (status.hirq_pos & 0xff) | (data << 8);
status.hirq_pos &= 0x01ff;
}
//VTIMEL
void sCPU::mmio_w4209(uint8 data) {
status.virq_pos = (status.virq_pos & ~0xff) | (data);
status.virq_pos &= 0x01ff;
}
//VTIMEH
void sCPU::mmio_w420a(uint8 data) {
status.virq_pos = (status.virq_pos & 0xff) | (data << 8);
status.virq_pos &= 0x01ff;
}
//DMAEN
void sCPU::mmio_w420b(uint8 data) {
for(unsigned i = 0; i < 8; i++) {
channel[i].dma_enabled = data & (1 << i);
}
if(data) status.dma_pending = true;
}
//HDMAEN
void sCPU::mmio_w420c(uint8 data) {
for(unsigned i = 0; i < 8; i++) {
channel[i].hdma_enabled = data & (1 << i);
}
}
//MEMSEL
void sCPU::mmio_w420d(uint8 data) {
bus.set_speed(data & 1);
}
//RDNMI
//7 = NMI acknowledge
//6-4 = MDR
//3-0 = CPU (5a22) version
uint8 sCPU::mmio_r4210() {
uint8 r = (regs.mdr & 0x70);
r |= (uint8)(rdnmi()) << 7;
r |= (cpu_version & 0x0f);
return r;
}
//TIMEUP
//7 = IRQ acknowledge
//6-0 = MDR
uint8 sCPU::mmio_r4211() {
uint8 r = (regs.mdr & 0x7f);
r |= (uint8)(timeup()) << 7;
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 = ppu.overscan() == false ? 225 : 240;
//auto joypad polling
if(ppu.vcounter() >= vs && ppu.vcounter() <= (vs + 2))r |= 0x01;
//hblank
if(ppu.hcounter() <= 2 || ppu.hcounter() >= 1096)r |= 0x40;
//vblank
if(ppu.vcounter() >= vs)r |= 0x80;
return r;
}
//RDIO
uint8 sCPU::mmio_r4213() {
return status.pio;
}
//RDDIVL
uint8 sCPU::mmio_r4214() {
if(status.alu_lock) return 0;
return status.r4214;
}
//RDDIVH
uint8 sCPU::mmio_r4215() {
if(status.alu_lock) return 0;
return status.r4214 >> 8;
}
//RDMPYL
uint8 sCPU::mmio_r4216() {
if(status.alu_lock) return 0;
return status.r4216;
}
//RDMPYH
uint8 sCPU::mmio_r4217() {
if(status.alu_lock) return 0;
return status.r4216 >> 8;
}
//TODO: handle reads during joypad polling (v=225-227)
uint8 sCPU::mmio_r4218() { return status.joy1l; } //JOY1L
uint8 sCPU::mmio_r4219() { return status.joy1h; } //JOY1H
uint8 sCPU::mmio_r421a() { return status.joy2l; } //JOY2L
uint8 sCPU::mmio_r421b() { return status.joy2h; } //JOY2H
uint8 sCPU::mmio_r421c() { return status.joy3l; } //JOY3L
uint8 sCPU::mmio_r421d() { return status.joy3h; } //JOY3H
uint8 sCPU::mmio_r421e() { return status.joy4l; } //JOY4L
uint8 sCPU::mmio_r421f() { return status.joy4h; } //JOY4H
//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;
}
//DMAPx
void sCPU::mmio_w43x0(uint8 i, uint8 data) {
channel[i].dmap = data;
channel[i].direction = !!(data & 0x80);
channel[i].hdma_indirect = !!(data & 0x40);
channel[i].reversexfer = !!(data & 0x10);
channel[i].fixedxfer = !!(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;
}
void sCPU::mmio_power() {
}
void sCPU::mmio_reset() {
//$2181-$2183
status.wram_addr = 0x000000;
//$4016-$4017
status.joypad_strobe_latch = 0;
status.joypad1_bits = ~0;
status.joypad2_bits = ~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;
//$4218-$421f
status.joy1l = 0x00;
status.joy1h = 0x00;
status.joy2l = 0x00;
status.joy2h = 0x00;
status.joy3l = 0x00;
status.joy3h = 0x00;
status.joy4l = 0x00;
status.joy4h = 0x00;
}
uint8 sCPU::mmio_read(unsigned addr) {
addr &= 0xffff;
//APU
if((addr & 0xffc0) == 0x2140) { //$2140-$217f
scheduler.sync_cpusmp();
return smp.port_read(addr & 3);
}
//DMA
if((addr & 0xff80) == 0x4300) { //$4300-$437f
unsigned 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 mmio_r421c();
case 0x421d: return mmio_r421d();
case 0x421e: return mmio_r421e();
case 0x421f: return mmio_r421f();
}
return regs.mdr;
}
void sCPU::mmio_write(unsigned addr, uint8 data) {
addr &= 0xffff;
//APU
if((addr & 0xffc0) == 0x2140) { //$2140-$217f
scheduler.sync_cpusmp();
port_write(addr & 3, data);
return;
}
//DMA
if((addr & 0xff80) == 0x4300) { //$4300-$437f
unsigned 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;
}
}
#endif //ifdef SCPU_CPP

71
bsnes/cpu/scpu/mmio/mmio.hpp Executable file
View File

@@ -0,0 +1,71 @@
void mmio_power();
void mmio_reset();
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
uint8 pio();
bool joylatch();
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_r421c();
uint8 mmio_r421d();
uint8 mmio_r421e();
uint8 mmio_r421f();
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);

61
bsnes/cpu/scpu/scpu.cpp Executable file
View File

@@ -0,0 +1,61 @@
#include <../base.hpp>
#define SCPU_CPP
#include <nall/priorityqueue.hpp>
priority_queue<unsigned> event(512, bind(&sCPU::queue_event, &cpu));
#include "core/core.cpp"
#include "dma/dma.cpp"
#include "memory/memory.cpp"
#include "mmio/mmio.cpp"
#include "timing/timing.cpp"
void sCPU::power() {
CPU::power();
regs.a = regs.x = regs.y = 0x0000;
regs.s = 0x01ff;
mmio_power();
dma_power();
timing_power();
reset();
}
void sCPU::reset() {
CPU::reset();
regs.pc.d = 0x000000;
regs.pc.l = bus.read(0xfffc);
regs.pc.h = bus.read(0xfffd);
//note: 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;
status.wai_lock = false;
status.interrupt_pending = false;
status.interrupt_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() {
}
sCPU::~sCPU() {
}

94
bsnes/cpu/scpu/scpu.hpp Executable file
View File

@@ -0,0 +1,94 @@
class sCPU : public CPU {
public:
void enter();
#include "core/core.hpp"
#include "dma/dma.hpp"
#include "memory/memory.hpp"
#include "mmio/mmio.hpp"
#include "timing/timing.hpp"
enum DmaState { DmaInactive, DmaRun, DmaCpuSync };
struct {
//core
uint8 opcode;
bool in_opcode;
bool wai_lock;
bool interrupt_pending;
uint16 interrupt_vector;
unsigned clock_count;
unsigned line_clocks;
//timing
bool irq_lock;
bool alu_lock;
unsigned dram_refresh_position;
bool nmi_valid;
bool nmi_line;
bool nmi_transition;
bool nmi_pending;
bool nmi_hold;
bool irq_valid;
bool irq_line;
bool irq_transition;
bool irq_pending;
bool irq_hold;
//DMA
unsigned dma_counter;
unsigned dma_clocks;
bool dma_pending;
bool hdma_pending;
bool hdma_mode; //0 = init, 1 = run
DmaState dma_state;
//MMIO
//$2181-$2183
uint32 wram_addr;
//$4016-$4017
bool joypad_strobe_latch;
uint32 joypad1_bits;
uint32 joypad2_bits;
//$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;
//$4218-$421f
uint8 joy1l, joy1h;
uint8 joy2l, joy2h;
uint8 joy3l, joy3h;
uint8 joy4l, joy4h;
} status;
void power();
void reset();
sCPU();
~sCPU();
};

35
bsnes/cpu/scpu/timing/event.cpp Executable file
View File

@@ -0,0 +1,35 @@
#ifdef SCPU_CPP
void sCPU::queue_event(unsigned id) {
switch(id) {
//interrupts triggered during (H)DMA do not trigger immediately after
case EventIrqLockRelease: {
status.irq_lock = false;
} break;
//ALU multiplication / division results are not immediately calculated;
//the exact formula for the calculations are unknown, but this lock at least
//allows emulation to avoid returning to fully computed results too soon.
case EventAluLockRelease: {
status.alu_lock = false;
} break;
//S-CPU WRAM consists of two 64kbyte DRAM chips, which must be refreshed
//once per scanline to avoid memory decay.
case EventDramRefresh: {
add_clocks(40);
} break;
//HDMA init routine; occurs once per frame
case EventHdmaInit: {
cycle_edge_state |= EventFlagHdmaInit;
} break;
//HDMA run routine; occurs once per scanline
case EventHdmaRun: {
cycle_edge_state |= EventFlagHdmaRun;
} break;
}
}
#endif

107
bsnes/cpu/scpu/timing/irq.cpp Executable file
View File

@@ -0,0 +1,107 @@
#ifdef SCPU_CPP
//called once every four clock cycles;
//as NMI steps by scanlines (divisible by 4) and IRQ by PPU 4-cycle dots.
//
//ppu.(vh)counter(n) returns the value of said counters n-clocks before current time;
//it is used to emulate hardware communication delay between opcode and interrupt units.
void sCPU::poll_interrupts() {
//NMI hold
if(status.nmi_hold) {
status.nmi_hold = false;
if(status.nmi_enabled) status.nmi_transition = true;
}
//NMI test
bool nmi_valid = (ppu.vcounter(2) >= (!ppu.overscan() ? 225 : 240));
if(!status.nmi_valid && nmi_valid) {
//0->1 edge sensitive transition
status.nmi_line = true;
status.nmi_hold = true; //hold /NMI for four cycles
} else if(status.nmi_valid && !nmi_valid) {
//1->0 edge sensitive transition
status.nmi_line = false;
}
status.nmi_valid = nmi_valid;
//IRQ hold
status.irq_hold = false;
if(status.irq_line) {
if(status.virq_enabled || status.hirq_enabled) status.irq_transition = true;
}
//IRQ test
bool irq_valid = (status.virq_enabled || status.hirq_enabled);
if(irq_valid) {
if((status.virq_enabled && ppu.vcounter(10) != (status.virq_pos))
|| (status.hirq_enabled && ppu.hcounter(10) != (status.hirq_pos + 1) * 4)
|| (status.virq_pos && ppu.vcounter(6) == 0) //IRQs cannot trigger on last dot of field
) irq_valid = false;
}
if(!status.irq_valid && irq_valid) {
//0->1 edge sensitive transition
status.irq_line = true;
status.irq_hold = true; //hold /IRQ for four cycles
}
status.irq_valid = irq_valid;
}
void sCPU::nmitimen_update(uint8 data) {
bool nmi_enabled = status.nmi_enabled;
bool virq_enabled = status.virq_enabled;
bool hirq_enabled = status.hirq_enabled;
status.nmi_enabled = data & 0x80;
status.virq_enabled = data & 0x20;
status.hirq_enabled = data & 0x10;
//0->1 edge sensitive transition
if(!nmi_enabled && status.nmi_enabled && status.nmi_line) {
status.nmi_transition = true;
}
//?->1 level sensitive transition
if(status.virq_enabled && !status.hirq_enabled && status.irq_line) {
status.irq_transition = true;
}
if(!status.virq_enabled && !status.hirq_enabled) {
status.irq_line = false;
status.irq_transition = false;
}
status.irq_lock = true;
event.enqueue(2, EventIrqLockRelease);
}
bool sCPU::rdnmi() {
bool result = status.nmi_line;
if(!status.nmi_hold) {
status.nmi_line = false;
}
return result;
}
bool sCPU::timeup() {
bool result = status.irq_line;
if(!status.irq_hold) {
status.irq_line = false;
status.irq_transition = false;
}
return result;
}
bool sCPU::nmi_test() {
if(!status.nmi_transition) return false;
status.nmi_transition = false;
status.wai_lock = false;
return true;
}
bool sCPU::irq_test() {
if(!status.irq_transition) return false;
status.irq_transition = false;
status.wai_lock = false;
return !regs.p.i;
}
#endif

View File

@@ -0,0 +1,28 @@
#ifdef SCPU_CPP
void sCPU::run_auto_joypad_poll() {
uint16 joy1 = 0, joy2 = 0, joy3 = 0, joy4 = 0;
for(unsigned i = 0; i < 16; i++) {
uint8 port0 = snes.input.port_read(0);
uint8 port1 = snes.input.port_read(1);
joy1 |= (port0 & 1) ? (0x8000 >> i) : 0;
joy2 |= (port1 & 1) ? (0x8000 >> i) : 0;
joy3 |= (port0 & 2) ? (0x8000 >> i) : 0;
joy4 |= (port1 & 2) ? (0x8000 >> i) : 0;
}
status.joy1l = joy1;
status.joy1h = joy1 >> 8;
status.joy2l = joy2;
status.joy2h = joy2 >> 8;
status.joy3l = joy3;
status.joy3h = joy3 >> 8;
status.joy4l = joy4;
status.joy4h = joy4 >> 8;
}
#endif

166
bsnes/cpu/scpu/timing/timing.cpp Executable file
View File

@@ -0,0 +1,166 @@
#ifdef SCPU_CPP
#include "event.cpp"
#include "irq.cpp"
#include "joypad.cpp"
unsigned sCPU::dma_counter() {
return (status.dma_counter + ppu.hcounter()) & 7;
}
void sCPU::add_clocks(unsigned clocks) {
event.tick(clocks);
unsigned ticks = clocks >> 1;
while(ticks--) {
ppu.tick();
if((ppu.hcounter() & 2) == 0) {
snes.input.tick();
} else {
poll_interrupts();
}
}
scheduler.addclocks_cpu(clocks);
}
void sCPU::scanline() {
status.dma_counter = (status.dma_counter + status.line_clocks) & 7;
status.line_clocks = ppu.lineclocks();
if(ppu.vcounter() == 0) {
//hdma init triggers once every frame
event.enqueue(cpu_version == 1 ? 12 + 8 - dma_counter() : 12 + dma_counter(), EventHdmaInit);
}
//dram refresh occurs once every scanline
if(cpu_version == 2) status.dram_refresh_position = 530 + 8 - dma_counter();
event.enqueue(status.dram_refresh_position, EventDramRefresh);
//hdma triggers once every visible scanline
if(ppu.vcounter() <= (ppu.overscan() == false ? 224 : 239)) {
event.enqueue(1104, EventHdmaRun);
}
if(status.auto_joypad_poll == true && ppu.vcounter() == (ppu.overscan() == false ? 227 : 242)) {
snes.input.poll();
run_auto_joypad_poll();
}
}
//used for H/DMA bus synchronization
void sCPU::precycle_edge() {
if(status.dma_state == DmaCpuSync) {
add_clocks(status.clock_count - (status.dma_clocks % status.clock_count));
status.dma_state = DmaInactive;
}
}
//used to test for H/DMA, which can trigger on the edge of every opcode cycle.
void sCPU::cycle_edge() {
while(cycle_edge_state) {
switch(bit::lowest(cycle_edge_state)) {
case EventFlagHdmaInit: {
hdma_init_reset();
if(hdma_enabled_channels()) {
status.hdma_pending = true;
status.hdma_mode = 0;
}
} break;
case EventFlagHdmaRun: {
if(hdma_active_channels()) {
status.hdma_pending = true;
status.hdma_mode = 1;
}
} break;
}
cycle_edge_state = bit::clear_lowest(cycle_edge_state);
}
//H/DMA pending && DMA inactive?
//.. Run one full CPU cycle
//.. HDMA pending && HDMA enabled ? DMA sync + HDMA run
//.. DMA pending && DMA enabled ? DMA sync + DMA run
//.... HDMA during DMA && HDMA enabled ? DMA sync + HDMA run
//.. Run one bus CPU cycle
//.. CPU sync
if(status.dma_state == DmaRun) {
if(status.hdma_pending) {
status.hdma_pending = false;
if(hdma_enabled_channels()) {
dma_add_clocks(8 - dma_counter()); //DMA sync
status.hdma_mode == 0 ? hdma_init() : hdma_run();
if(!dma_enabled_channels()) status.dma_state = DmaCpuSync;
}
}
if(status.dma_pending) {
status.dma_pending = false;
if(dma_enabled_channels()) {
dma_add_clocks(8 - dma_counter()); //DMA sync
dma_run();
status.dma_state = DmaCpuSync;
}
}
}
if(status.dma_state == DmaInactive) {
if(status.dma_pending || status.hdma_pending) {
status.dma_clocks = 0;
status.dma_state = DmaRun;
}
}
}
//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.
//
//status.irq_lock is used to simulate hardware delay before interrupts can
//trigger during certain events (immediately after DMA, writes to $4200, etc)
void sCPU::last_cycle() {
if(!status.irq_lock) {
status.nmi_pending |= nmi_test();
status.irq_pending |= irq_test();
status.interrupt_pending = (status.nmi_pending || status.irq_pending);
}
}
void sCPU::timing_power() {
}
void sCPU::timing_reset() {
event.reset();
status.clock_count = 0;
status.line_clocks = ppu.lineclocks();
status.irq_lock = false;
status.alu_lock = false;
status.dram_refresh_position = (cpu_version == 1 ? 530 : 538);
event.enqueue(status.dram_refresh_position, EventDramRefresh);
status.nmi_valid = false;
status.nmi_line = false;
status.nmi_transition = false;
status.nmi_pending = false;
status.nmi_hold = false;
status.irq_valid = false;
status.irq_line = false;
status.irq_transition = false;
status.irq_pending = false;
status.irq_hold = false;
status.dma_counter = 0;
status.dma_clocks = 0;
status.dma_pending = false;
status.hdma_pending = false;
status.hdma_mode = 0;
status.dma_state = DmaInactive;
cycle_edge_state = 0;
}
#endif

View File

@@ -0,0 +1,41 @@
enum {
EventNone,
EventIrqLockRelease,
EventAluLockRelease,
EventDramRefresh,
EventHdmaInit,
EventHdmaRun,
//cycle edge
EventFlagHdmaInit = 1 << 0,
EventFlagHdmaRun = 1 << 1,
};
unsigned cycle_edge_state;
//timing.cpp
unsigned dma_counter();
void add_clocks(unsigned clocks);
void scanline();
alwaysinline void precycle_edge();
alwaysinline void cycle_edge();
void last_cycle();
void timing_power();
void timing_reset();
//irq.cpp
alwaysinline void poll_interrupts();
void nmitimen_update(uint8 data);
bool rdnmi();
bool timeup();
alwaysinline bool nmi_test();
alwaysinline bool irq_test();
//joypad.cpp
void run_auto_joypad_poll();
//event.cpp
void queue_event(unsigned); //priorityqueue callback function