Update to v097r29 release.

byuu says:

Changelog:
- fixed DAS instruction (Judgment Silversword score)
- fixed [VH]TMR_FREQ writes (Judgement Silversword audio after area 20)
- fixed initialization of SP (fixes seven games that were hanging on
  startup)
- added SER_STATUS and SER_DATA stubs (fixes four games that were
  hanging on startup)
- initialized IEEP data (fixes Super Robot Taisen Compact 2 series)
  - note: you'll need to delete your internal.com in WonderSwan
    (Color).sys folders
- fixed CMPS and SCAS termination condition (fixes serious bugs in four
  games)
- set read/writeCompleted flags for EEPROM status (fixes Tetsujin 28
  Gou)
- major code cleanups to SFC/R65816 and SFC/CPU
  - mostly refactored disassembler to output strings instead of using
    char* buffer
  - unrolled all the subfolders on sfc/cpu to a single directory
  - corrected casing for all of sfc/cpu and a large portion of
    processor/r65816

I kind of went overboard on the code cleanup with this WIP. Hopefully
nothing broke. Any testing one can do with the SFC accuracy core would
be greatly appreciated.

There's still an absolutely huge amount of work left to go, but I do
want to eventually refresh the entire codebase to my current coding
style, which is extremely different from stuff that's been in higan
mostly untouched since ~2006 or so. It's dangerous and fickle work, but
if I don't do it, then the code will be a jumbled mess of several
different styles.
This commit is contained in:
Tim Allen 2016-03-26 12:56:15 +11:00
parent 379ab6991f
commit 680d16561e
59 changed files with 1815 additions and 1956 deletions

View File

@ -6,7 +6,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "097.28";
static const string Version = "097.29";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

@ -1,6 +1,4 @@
//TODO: this belongs in processor/gsu
auto SuperFX::disassemble_opcode(char* output) -> void {
auto GSU::disassemble_opcode(char* output) -> void {
*output = 0;
if(!regs.sfr.alt2) {
@ -39,7 +37,7 @@ auto SuperFX::disassemble_opcode(char* output) -> void {
#define op1 bus_read((regs.pbr << 16) + regs.r[15] + 0)
#define op2 bus_read((regs.pbr << 16) + regs.r[15] + 1)
auto SuperFX::disassemble_alt0(char* output) -> void {
auto GSU::disassemble_alt0(char* output) -> void {
char t[256] = "";
switch(op0) {
case (0x00): sprintf(t, "stop"); break;
@ -96,7 +94,7 @@ auto SuperFX::disassemble_alt0(char* output) -> void {
strcat(output, t);
}
auto SuperFX::disassemble_alt1(char* output) -> void {
auto GSU::disassemble_alt1(char* output) -> void {
char t[256] = "";
switch(op0) {
case (0x00): sprintf(t, "stop"); break;
@ -153,7 +151,7 @@ auto SuperFX::disassemble_alt1(char* output) -> void {
strcat(output, t);
}
auto SuperFX::disassemble_alt2(char* output) -> void {
auto GSU::disassemble_alt2(char* output) -> void {
char t[256] = "";
switch(op0) {
case (0x00): sprintf(t, "stop"); break;
@ -210,7 +208,7 @@ auto SuperFX::disassemble_alt2(char* output) -> void {
strcat(output, t);
}
auto SuperFX::disassemble_alt3(char* output) -> void {
auto GSU::disassemble_alt3(char* output) -> void {
char t[256] = "";
switch(op0) {
case (0x00): sprintf(t, "stop"); break;

View File

@ -10,6 +10,7 @@ namespace Processor {
#include "instructions.cpp"
#include "table.cpp"
#include "serialization.cpp"
#include "disassembler.cpp"
auto GSU::power() -> void {
}

View File

@ -20,6 +20,9 @@ struct GSU {
virtual auto rambuffer_write(uint16 addr, uint8 data) -> void = 0;
virtual auto cache_flush() -> void = 0;
virtual auto bus_read(uint24 addr, uint8 data = 0x00) -> uint8 = 0;
virtual auto bus_write(uint24 addr, uint8 data) -> void = 0;
//gsu.cpp
auto power() -> void;
auto reset() -> void;
@ -113,6 +116,13 @@ struct GSU {
//serialization.cpp
auto serialize(serializer&) -> void;
//disassembler.cpp
auto disassemble_opcode(char* output) -> void;
auto disassemble_alt0(char* output) -> void;
auto disassemble_alt1(char* output) -> void;
auto disassemble_alt2(char* output) -> void;
auto disassemble_alt3(char* output) -> void;
};
}

View File

@ -1,123 +1,117 @@
auto R65816::dreadb(uint32 addr) -> uint8 {
auto R65816::dreadb(uint24 addr) -> uint8 {
if((addr & 0x40ffff) >= 0x2000 && (addr & 0x40ffff) <= 0x5fff) {
//$[00-3f|80-bf]:[2000-5fff]
//$00-3f|80-bf:2000-5fff
//do not read MMIO registers within debugger
return 0x00;
}
return disassembler_read(addr);
return disassemblerRead(addr);
}
auto R65816::dreadw(uint32 addr) -> uint16 {
uint16 r;
r = dreadb((addr + 0) & 0xffffff) << 0;
r |= dreadb((addr + 1) & 0xffffff) << 8;
auto R65816::dreadw(uint24 addr) -> uint16 {
uint16 data;
data.byte(0) = dreadb(addr++);
data.byte(1) = dreadb(addr++);
return data;
}
auto R65816::dreadl(uint24 addr) -> uint24 {
uint24 data;
data.byte(0) = dreadb(addr++);
data.byte(1) = dreadb(addr++);
data.byte(2) = dreadb(addr++);
return data;
}
auto R65816::decode(uint8 mode, uint24 addr) -> uint24 {
uint24 r = 0;
switch(mode) {
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;
}
auto R65816::dreadl(uint32 addr) -> uint32 {
uint32 r;
r = dreadb((addr + 0) & 0xffffff) << 0;
r |= dreadb((addr + 1) & 0xffffff) << 8;
r |= dreadb((addr + 2) & 0xffffff) << 16;
return r;
auto R65816::disassemble() -> string {
return disassemble(regs.pc.d, regs.e, regs.p.m, regs.p.x);
}
auto R65816::decode(uint8 offset_type, uint32 addr) -> uint32 {
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);
}
auto R65816::disassemble_opcode(char* output) -> void {
return disassemble_opcode(output, regs.pc.d, regs.e, regs.p.m, regs.p.x);
}
auto R65816::disassemble_opcode(char* output, uint32 addr, bool e, bool m, bool x) -> void {
static reg24_t pc;
char t[256];
char* s = output;
if(false /* in_opcode() == true */) {
strcpy(s, "?????? <CPU within opcode>");
return;
}
auto R65816::disassemble(uint24 addr, bool e, bool m, bool x) -> string {
string s;
reg24_t pc;
pc.d = addr;
sprintf(s, "%.6x ", (uint32)pc.d);
s = {hex(pc, 6), " "};
uint8 op = dreadb(pc.d); pc.w++;
uint8 op0 = dreadb(pc.d); pc.w++;
@ -130,6 +124,7 @@ auto R65816::disassemble_opcode(char* output, uint32 addr, bool e, bool m, bool
#define a8 (e || m)
#define x8 (e || x)
char t[256];
switch(op) {
case 0x00: sprintf(t, "brk #$%.2x ", op8); break;
case 0x01: sprintf(t, "ora ($%.2x,x) [%.6x]", op8, decode(OPTYPE_IDPX, op8)); break;
@ -407,26 +402,26 @@ auto R65816::disassemble_opcode(char* output, uint32 addr, bool e, bool m, bool
#undef a8
#undef x8
strcat(s, t);
strcat(s, " ");
sprintf(t, "A:%.4x X:%.4x Y:%.4x S:%.4x D:%.4x B:%.2x ",
regs.a.w, regs.x.w, regs.y.w, regs.s.w, regs.d.w, (uint8_t)regs.db);
strcat(s, t);
s.append(t, " A:{0} X:{1} Y:{2} S:{3} D:{4} B:{5} ", format{
hex(regs.a.w, 4), hex(regs.x.w, 4), hex(regs.y.w, 4),
hex(regs.s.w, 4), hex(regs.d.w, 4), hex(regs.db, 2)
});
if(regs.e) {
sprintf(t, "%c%c%c%c%c%c%c%c",
s.append(
regs.p.n ? 'N' : 'n', regs.p.v ? 'V' : 'v',
regs.p.m ? '1' : '0', regs.p.x ? 'B' : 'b',
regs.p.d ? 'D' : 'd', regs.p.i ? 'I' : 'i',
regs.p.z ? 'Z' : 'z', regs.p.c ? 'C' : 'c');
regs.p.z ? 'Z' : 'z', regs.p.c ? 'C' : 'c'
);
} else {
sprintf(t, "%c%c%c%c%c%c%c%c",
s.append(
regs.p.n ? 'N' : 'n', regs.p.v ? 'V' : 'v',
regs.p.m ? 'M' : 'm', regs.p.x ? 'X' : 'x',
regs.p.d ? 'D' : 'd', regs.p.i ? 'I' : 'i',
regs.p.z ? 'Z' : 'z', regs.p.c ? 'C' : 'c');
regs.p.z ? 'Z' : 'z', regs.p.c ? 'C' : 'c'
);
}
strcat(s, t);
return s;
}

View File

@ -1,4 +1,4 @@
enum : unsigned {
enum : uint {
OPTYPE_DP = 0, //dp
OPTYPE_DPX, //dp,x
OPTYPE_DPY, //dp,y
@ -22,9 +22,9 @@ enum : unsigned {
OPTYPE_RELW, //relw
};
auto disassemble_opcode(char* output) -> void;
auto disassemble_opcode(char* output, uint32 addr, bool e, bool m, bool x) -> void;
auto dreadb(uint32 addr) -> uint8;
auto dreadw(uint32 addr) -> uint16;
auto dreadl(uint32 addr) -> uint32;
auto decode(uint8 offset_type, uint32 addr) -> uint32;
auto disassemble() -> string;
auto disassemble(uint24 addr, bool e, bool m, bool x) -> string;
auto dreadb(uint24 addr) -> uint8;
auto dreadw(uint24 addr) -> uint16;
auto dreadl(uint24 addr) -> uint24;
auto decode(uint8 mode, uint24 addr) -> uint24;

View File

@ -1,77 +1,77 @@
alwaysinline auto op_readpc() -> uint8 {
return op_read((regs.pc.b << 16) + regs.pc.w++);
alwaysinline auto readpc() -> uint8 {
return read((regs.pc.b << 16) + regs.pc.w++);
}
alwaysinline auto op_readstack() -> uint8 {
alwaysinline auto readstack() -> uint8 {
regs.e ? regs.s.l++ : regs.s.w++;
return op_read(regs.s.w);
return read(regs.s.w);
}
alwaysinline auto op_readstackn() -> uint8 {
return op_read(++regs.s.w);
alwaysinline auto readstackn() -> uint8 {
return read(++regs.s.w);
}
alwaysinline auto op_readaddr(uint32 addr) -> uint8 {
return op_read(addr & 0xffff);
alwaysinline auto readaddr(uint32 addr) -> uint8 {
return read(addr & 0xffff);
}
alwaysinline auto op_readlong(uint32 addr) -> uint8 {
return op_read(addr & 0xffffff);
alwaysinline auto readlong(uint32 addr) -> uint8 {
return read(addr & 0xffffff);
}
alwaysinline auto op_readdbr(uint32 addr) -> uint8 {
return op_read(((regs.db << 16) + addr) & 0xffffff);
alwaysinline auto readdbr(uint32 addr) -> uint8 {
return read(((regs.db << 16) + addr) & 0xffffff);
}
alwaysinline auto op_readpbr(uint32 addr) -> uint8 {
return op_read((regs.pc.b << 16) + (addr & 0xffff));
alwaysinline auto readpbr(uint32 addr) -> uint8 {
return read((regs.pc.b << 16) + (addr & 0xffff));
}
alwaysinline auto op_readdp(uint32 addr) -> uint8 {
alwaysinline auto readdp(uint32 addr) -> uint8 {
if(regs.e && regs.d.l == 0x00) {
return op_read((regs.d & 0xff00) + ((regs.d + (addr & 0xffff)) & 0xff));
return read((regs.d & 0xff00) + ((regs.d + (addr & 0xffff)) & 0xff));
} else {
return op_read((regs.d + (addr & 0xffff)) & 0xffff);
return read((regs.d + (addr & 0xffff)) & 0xffff);
}
}
alwaysinline auto op_readsp(uint32 addr) -> uint8 {
return op_read((regs.s + (addr & 0xffff)) & 0xffff);
alwaysinline auto readsp(uint32 addr) -> uint8 {
return read((regs.s + (addr & 0xffff)) & 0xffff);
}
alwaysinline auto op_writestack(uint8 data) -> void {
op_write(regs.s.w, data);
alwaysinline auto writestack(uint8 data) -> void {
write(regs.s.w, data);
regs.e ? regs.s.l-- : regs.s.w--;
}
alwaysinline auto op_writestackn(uint8 data) -> void {
op_write(regs.s.w--, data);
alwaysinline auto writestackn(uint8 data) -> void {
write(regs.s.w--, data);
}
alwaysinline auto op_writeaddr(uint32 addr, uint8 data) -> void {
op_write(addr & 0xffff, data);
alwaysinline auto writeaddr(uint32 addr, uint8 data) -> void {
write(addr & 0xffff, data);
}
alwaysinline auto op_writelong(uint32 addr, uint8 data) -> void {
op_write(addr & 0xffffff, data);
alwaysinline auto writelong(uint32 addr, uint8 data) -> void {
write(addr & 0xffffff, data);
}
alwaysinline auto op_writedbr(uint32 addr, uint8 data) -> void {
op_write(((regs.db << 16) + addr) & 0xffffff, data);
alwaysinline auto writedbr(uint32 addr, uint8 data) -> void {
write(((regs.db << 16) + addr) & 0xffffff, data);
}
alwaysinline auto op_writepbr(uint32 addr, uint8 data) -> void {
op_write((regs.pc.b << 16) + (addr & 0xffff), data);
alwaysinline auto writepbr(uint32 addr, uint8 data) -> void {
write((regs.pc.b << 16) + (addr & 0xffff), data);
}
alwaysinline auto op_writedp(uint32 addr, uint8 data) -> void {
alwaysinline auto writedp(uint32 addr, uint8 data) -> void {
if(regs.e && regs.d.l == 0x00) {
op_write((regs.d & 0xff00) + ((regs.d + (addr & 0xffff)) & 0xff), data);
write((regs.d & 0xff00) + ((regs.d + (addr & 0xffff)) & 0xff), data);
} else {
op_write((regs.d + (addr & 0xffff)) & 0xffff, data);
write((regs.d + (addr & 0xffff)) & 0xffff, data);
}
}
alwaysinline auto op_writesp(uint32 addr, uint8 data) -> void {
op_write((regs.s + (addr & 0xffff)) & 0xffff, data);
alwaysinline auto writesp(uint32 addr, uint8 data) -> void {
write((regs.s + (addr & 0xffff)) & 0xffff, data);
}

View File

@ -1,14 +1,14 @@
auto R65816::op_nop() {
L op_io_irq();
L ioIRQ();
}
auto R65816::op_wdm() {
L op_readpc();
L readpc();
}
auto R65816::op_xba() {
op_io();
L op_io();
io();
L io();
regs.a.l ^= regs.a.h;
regs.a.h ^= regs.a.l;
regs.a.l ^= regs.a.h;
@ -17,74 +17,74 @@ L op_io();
}
auto R65816::op_move_b(signed adjust) {
dp = op_readpc();
sp = op_readpc();
dp = readpc();
sp = readpc();
regs.db = dp;
rd.l = op_readlong((sp << 16) | regs.x.w);
op_writelong((dp << 16) | regs.y.w, rd.l);
op_io();
rd.l = readlong((sp << 16) | regs.x.w);
writelong((dp << 16) | regs.y.w, rd.l);
io();
regs.x.l += adjust;
regs.y.l += adjust;
L op_io();
L io();
if(regs.a.w--) regs.pc.w -= 3;
}
auto R65816::op_move_w(signed adjust) {
dp = op_readpc();
sp = op_readpc();
dp = readpc();
sp = readpc();
regs.db = dp;
rd.l = op_readlong((sp << 16) | regs.x.w);
op_writelong((dp << 16) | regs.y.w, rd.l);
op_io();
rd.l = readlong((sp << 16) | regs.x.w);
writelong((dp << 16) | regs.y.w, rd.l);
io();
regs.x.w += adjust;
regs.y.w += adjust;
L op_io();
L io();
if(regs.a.w--) regs.pc.w -= 3;
}
auto R65816::op_interrupt_e(uint16 vector) {
op_readpc();
op_writestack(regs.pc.h);
op_writestack(regs.pc.l);
op_writestack(regs.p);
rd.l = op_readlong(vector + 0);
readpc();
writestack(regs.pc.h);
writestack(regs.pc.l);
writestack(regs.p);
rd.l = readlong(vector + 0);
regs.pc.b = 0;
regs.p.i = 1;
regs.p.d = 0;
L rd.h = op_readlong(vector + 1);
L rd.h = readlong(vector + 1);
regs.pc.w = rd.w;
}
auto R65816::op_interrupt_n(uint16 vector) {
op_readpc();
op_writestack(regs.pc.b);
op_writestack(regs.pc.h);
op_writestack(regs.pc.l);
op_writestack(regs.p);
rd.l = op_readlong(vector + 0);
readpc();
writestack(regs.pc.b);
writestack(regs.pc.h);
writestack(regs.pc.l);
writestack(regs.p);
rd.l = readlong(vector + 0);
regs.pc.b = 0x00;
regs.p.i = 1;
regs.p.d = 0;
L rd.h = op_readlong(vector + 1);
L rd.h = readlong(vector + 1);
regs.pc.w = rd.w;
}
auto R65816::op_stp() {
while(regs.wai = true) {
L op_io();
L io();
}
}
auto R65816::op_wai() {
regs.wai = true;
while(regs.wai) {
L op_io();
L io();
}
op_io();
io();
}
auto R65816::op_xce() {
L op_io_irq();
L ioIRQ();
bool carry = regs.p.c;
regs.p.c = regs.e;
regs.e = carry;
@ -98,13 +98,13 @@ L op_io_irq();
}
auto R65816::op_flag(bool& flag, bool value) {
L op_io_irq();
L ioIRQ();
flag = value;
}
auto R65816::op_pflag_e(bool mode) {
rd.l = op_readpc();
L op_io();
rd.l = readpc();
L io();
regs.p = (mode ? regs.p | rd.l : regs.p & ~rd.l);
regs.p.m = 1;
regs.p.x = 1;
@ -113,8 +113,8 @@ L op_io();
}
auto R65816::op_pflag_n(bool mode) {
rd.l = op_readpc();
L op_io();
rd.l = readpc();
L io();
regs.p = (mode ? regs.p | rd.l : regs.p & ~rd.l);
if(regs.p.x) {
regs.x.h = 0x00;
@ -123,140 +123,140 @@ L op_io();
}
auto R65816::op_transfer_b(reg16_t& from, reg16_t& to) {
L op_io_irq();
L ioIRQ();
to.l = from.l;
regs.p.n = (to.l & 0x80);
regs.p.z = (to.l == 0);
}
auto R65816::op_transfer_w(reg16_t& from, reg16_t& to) {
L op_io_irq();
L ioIRQ();
to.w = from.w;
regs.p.n = (to.w & 0x8000);
regs.p.z = (to.w == 0);
}
auto R65816::op_tcs_e() {
L op_io_irq();
L ioIRQ();
regs.s.l = regs.a.l;
}
auto R65816::op_tcs_n() {
L op_io_irq();
L ioIRQ();
regs.s.w = regs.a.w;
}
auto R65816::op_tsx_b() {
L op_io_irq();
L ioIRQ();
regs.x.l = regs.s.l;
regs.p.n = (regs.x.l & 0x80);
regs.p.z = (regs.x.l == 0);
}
auto R65816::op_tsx_w() {
L op_io_irq();
L ioIRQ();
regs.x.w = regs.s.w;
regs.p.n = (regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
}
auto R65816::op_txs_e() {
L op_io_irq();
L ioIRQ();
regs.s.l = regs.x.l;
}
auto R65816::op_txs_n() {
L op_io_irq();
L ioIRQ();
regs.s.w = regs.x.w;
}
auto R65816::op_push_b(reg16_t& reg) {
op_io();
L op_writestack(reg.l);
io();
L writestack(reg.l);
}
auto R65816::op_push_w(reg16_t& reg) {
op_io();
op_writestack(reg.h);
L op_writestack(reg.l);
io();
writestack(reg.h);
L writestack(reg.l);
}
auto R65816::op_phd_e() {
op_io();
op_writestackn(regs.d.h);
L op_writestackn(regs.d.l);
io();
writestackn(regs.d.h);
L writestackn(regs.d.l);
regs.s.h = 0x01;
}
auto R65816::op_phd_n() {
op_io();
op_writestackn(regs.d.h);
L op_writestackn(regs.d.l);
io();
writestackn(regs.d.h);
L writestackn(regs.d.l);
}
auto R65816::op_phb() {
op_io();
L op_writestack(regs.db);
io();
L writestack(regs.db);
}
auto R65816::op_phk() {
op_io();
L op_writestack(regs.pc.b);
io();
L writestack(regs.pc.b);
}
auto R65816::op_php() {
op_io();
L op_writestack(regs.p);
io();
L writestack(regs.p);
}
auto R65816::op_pull_b(reg16_t& reg) {
op_io();
op_io();
L reg.l = op_readstack();
io();
io();
L reg.l = readstack();
regs.p.n = (reg.l & 0x80);
regs.p.z = (reg.l == 0);
}
auto R65816::op_pull_w(reg16_t& reg) {
op_io();
op_io();
reg.l = op_readstack();
L reg.h = op_readstack();
io();
io();
reg.l = readstack();
L reg.h = readstack();
regs.p.n = (reg.w & 0x8000);
regs.p.z = (reg.w == 0);
}
auto R65816::op_pld_e() {
op_io();
op_io();
regs.d.l = op_readstackn();
L regs.d.h = op_readstackn();
io();
io();
regs.d.l = readstackn();
L regs.d.h = readstackn();
regs.p.n = (regs.d.w & 0x8000);
regs.p.z = (regs.d.w == 0);
regs.s.h = 0x01;
}
auto R65816::op_pld_n() {
op_io();
op_io();
regs.d.l = op_readstackn();
L regs.d.h = op_readstackn();
io();
io();
regs.d.l = readstackn();
L regs.d.h = readstackn();
regs.p.n = (regs.d.w & 0x8000);
regs.p.z = (regs.d.w == 0);
}
auto R65816::op_plb() {
op_io();
op_io();
L regs.db = op_readstack();
io();
io();
L regs.db = readstack();
regs.p.n = (regs.db & 0x80);
regs.p.z = (regs.db == 0);
}
auto R65816::op_plp_e() {
op_io();
op_io();
L regs.p = op_readstack() | 0x30;
io();
io();
L regs.p = readstack() | 0x30;
if(regs.p.x) {
regs.x.h = 0x00;
regs.y.h = 0x00;
@ -264,9 +264,9 @@ L regs.p = op_readstack() | 0x30;
}
auto R65816::op_plp_n() {
op_io();
op_io();
L regs.p = op_readstack();
io();
io();
L regs.p = readstack();
if(regs.p.x) {
regs.x.h = 0x00;
regs.y.h = 0x00;
@ -274,54 +274,54 @@ L regs.p = op_readstack();
}
auto R65816::op_pea_e() {
aa.l = op_readpc();
aa.h = op_readpc();
op_writestackn(aa.h);
L op_writestackn(aa.l);
aa.l = readpc();
aa.h = readpc();
writestackn(aa.h);
L writestackn(aa.l);
regs.s.h = 0x01;
}
auto R65816::op_pea_n() {
aa.l = op_readpc();
aa.h = op_readpc();
op_writestackn(aa.h);
L op_writestackn(aa.l);
aa.l = readpc();
aa.h = readpc();
writestackn(aa.h);
L writestackn(aa.l);
}
auto R65816::op_pei_e() {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp + 0);
aa.h = op_readdp(dp + 1);
op_writestackn(aa.h);
L op_writestackn(aa.l);
dp = readpc();
io2();
aa.l = readdp(dp + 0);
aa.h = readdp(dp + 1);
writestackn(aa.h);
L writestackn(aa.l);
regs.s.h = 0x01;
}
auto R65816::op_pei_n() {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp + 0);
aa.h = op_readdp(dp + 1);
op_writestackn(aa.h);
L op_writestackn(aa.l);
dp = readpc();
io2();
aa.l = readdp(dp + 0);
aa.h = readdp(dp + 1);
writestackn(aa.h);
L writestackn(aa.l);
}
auto R65816::op_per_e() {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
aa.l = readpc();
aa.h = readpc();
io();
rd.w = regs.pc.d + (int16)aa.w;
op_writestackn(rd.h);
L op_writestackn(rd.l);
writestackn(rd.h);
L writestackn(rd.l);
regs.s.h = 0x01;
}
auto R65816::op_per_n() {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
aa.l = readpc();
aa.h = readpc();
io();
rd.w = regs.pc.d + (int16)aa.w;
op_writestackn(rd.h);
L op_writestackn(rd.l);
writestackn(rd.h);
L writestackn(rd.l);
}

View File

@ -1,176 +1,176 @@
auto R65816::op_branch(bool flag, bool value) {
if(flag != value) {
L rd.l = op_readpc();
L rd.l = readpc();
} else {
rd.l = op_readpc();
rd.l = readpc();
aa.w = regs.pc.d + (int8)rd.l;
op_io_cond6(aa.w);
L op_io();
io6(aa.w);
L io();
regs.pc.w = aa.w;
}
}
auto R65816::op_bra() {
rd.l = op_readpc();
rd.l = readpc();
aa.w = regs.pc.d + (int8)rd.l;
op_io_cond6(aa.w);
L op_io();
io6(aa.w);
L io();
regs.pc.w = aa.w;
}
auto R65816::op_brl() {
rd.l = op_readpc();
rd.h = op_readpc();
L op_io();
rd.l = readpc();
rd.h = readpc();
L io();
regs.pc.w = regs.pc.d + (int16)rd.w;
}
auto R65816::op_jmp_addr() {
rd.l = op_readpc();
L rd.h = op_readpc();
rd.l = readpc();
L rd.h = readpc();
regs.pc.w = rd.w;
}
auto R65816::op_jmp_long() {
rd.l = op_readpc();
rd.h = op_readpc();
L rd.b = op_readpc();
rd.l = readpc();
rd.h = readpc();
L rd.b = readpc();
regs.pc.d = rd.d & 0xffffff;
}
auto R65816::op_jmp_iaddr() {
aa.l = op_readpc();
aa.h = op_readpc();
rd.l = op_readaddr(aa.w + 0);
L rd.h = op_readaddr(aa.w + 1);
aa.l = readpc();
aa.h = readpc();
rd.l = readaddr(aa.w + 0);
L rd.h = readaddr(aa.w + 1);
regs.pc.w = rd.w;
}
auto R65816::op_jmp_iaddrx() {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
rd.l = op_readpbr(aa.w + regs.x.w + 0);
L rd.h = op_readpbr(aa.w + regs.x.w + 1);
aa.l = readpc();
aa.h = readpc();
io();
rd.l = readpbr(aa.w + regs.x.w + 0);
L rd.h = readpbr(aa.w + regs.x.w + 1);
regs.pc.w = rd.w;
}
auto R65816::op_jmp_iladdr() {
aa.l = op_readpc();
aa.h = op_readpc();
rd.l = op_readaddr(aa.w + 0);
rd.h = op_readaddr(aa.w + 1);
L rd.b = op_readaddr(aa.w + 2);
aa.l = readpc();
aa.h = readpc();
rd.l = readaddr(aa.w + 0);
rd.h = readaddr(aa.w + 1);
L rd.b = readaddr(aa.w + 2);
regs.pc.d = rd.d & 0xffffff;
}
auto R65816::op_jsr_addr() {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
aa.l = readpc();
aa.h = readpc();
io();
regs.pc.w--;
op_writestack(regs.pc.h);
L op_writestack(regs.pc.l);
writestack(regs.pc.h);
L writestack(regs.pc.l);
regs.pc.w = aa.w;
}
auto R65816::op_jsr_long_e() {
aa.l = op_readpc();
aa.h = op_readpc();
op_writestackn(regs.pc.b);
op_io();
aa.b = op_readpc();
aa.l = readpc();
aa.h = readpc();
writestackn(regs.pc.b);
io();
aa.b = readpc();
regs.pc.w--;
op_writestackn(regs.pc.h);
L op_writestackn(regs.pc.l);
writestackn(regs.pc.h);
L writestackn(regs.pc.l);
regs.pc.d = aa.d & 0xffffff;
regs.s.h = 0x01;
}
auto R65816::op_jsr_long_n() {
aa.l = op_readpc();
aa.h = op_readpc();
op_writestackn(regs.pc.b);
op_io();
aa.b = op_readpc();
aa.l = readpc();
aa.h = readpc();
writestackn(regs.pc.b);
io();
aa.b = readpc();
regs.pc.w--;
op_writestackn(regs.pc.h);
L op_writestackn(regs.pc.l);
writestackn(regs.pc.h);
L writestackn(regs.pc.l);
regs.pc.d = aa.d & 0xffffff;
}
auto R65816::op_jsr_iaddrx_e() {
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 + 0);
L rd.h = op_readpbr(aa.w + regs.x.w + 1);
aa.l = readpc();
writestackn(regs.pc.h);
writestackn(regs.pc.l);
aa.h = readpc();
io();
rd.l = readpbr(aa.w + regs.x.w + 0);
L rd.h = readpbr(aa.w + regs.x.w + 1);
regs.pc.w = rd.w;
regs.s.h = 0x01;
}
auto R65816::op_jsr_iaddrx_n() {
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 + 0);
L rd.h = op_readpbr(aa.w + regs.x.w + 1);
aa.l = readpc();
writestackn(regs.pc.h);
writestackn(regs.pc.l);
aa.h = readpc();
io();
rd.l = readpbr(aa.w + regs.x.w + 0);
L rd.h = readpbr(aa.w + regs.x.w + 1);
regs.pc.w = rd.w;
}
auto R65816::op_rti_e() {
op_io();
op_io();
regs.p = op_readstack() | 0x30;
rd.l = op_readstack();
L rd.h = op_readstack();
io();
io();
regs.p = readstack() | 0x30;
rd.l = readstack();
L rd.h = readstack();
regs.pc.w = rd.w;
}
auto R65816::op_rti_n() {
op_io();
op_io();
regs.p = op_readstack();
io();
io();
regs.p = readstack();
if(regs.p.x) {
regs.x.h = 0x00;
regs.y.h = 0x00;
}
rd.l = op_readstack();
rd.h = op_readstack();
L rd.b = op_readstack();
rd.l = readstack();
rd.h = readstack();
L rd.b = readstack();
regs.pc.d = rd.d & 0xffffff;
}
auto R65816::op_rts() {
op_io();
op_io();
rd.l = op_readstack();
rd.h = op_readstack();
L op_io();
io();
io();
rd.l = readstack();
rd.h = readstack();
L io();
regs.pc.w = ++rd.w;
}
auto R65816::op_rtl_e() {
op_io();
op_io();
rd.l = op_readstackn();
rd.h = op_readstackn();
L rd.b = op_readstackn();
io();
io();
rd.l = readstackn();
rd.h = readstackn();
L rd.b = readstackn();
regs.pc.b = rd.b;
regs.pc.w = ++rd.w;
regs.s.h = 0x01;
}
auto R65816::op_rtl_n() {
op_io();
op_io();
rd.l = op_readstackn();
rd.h = op_readstackn();
L rd.b = op_readstackn();
io();
io();
rd.l = readstackn();
rd.h = readstackn();
L rd.b = readstackn();
regs.pc.b = rd.b;
regs.pc.w = ++rd.w;
}

View File

@ -1,275 +1,275 @@
auto R65816::op_read_const_b(fp op) {
L rd.l = op_readpc();
L rd.l = readpc();
call(op);
}
auto R65816::op_read_const_w(fp op) {
rd.l = op_readpc();
L rd.h = op_readpc();
rd.l = readpc();
L rd.h = readpc();
call(op);
}
auto R65816::op_read_bit_const_b() {
L rd.l = op_readpc();
L rd.l = readpc();
regs.p.z = ((rd.l & regs.a.l) == 0);
}
auto R65816::op_read_bit_const_w() {
rd.l = op_readpc();
L rd.h = op_readpc();
rd.l = readpc();
L rd.h = readpc();
regs.p.z = ((rd.w & regs.a.w) == 0);
}
auto R65816::op_read_addr_b(fp op) {
aa.l = op_readpc();
aa.h = op_readpc();
L rd.l = op_readdbr(aa.w);
aa.l = readpc();
aa.h = readpc();
L rd.l = readdbr(aa.w);
call(op);
}
auto R65816::op_read_addr_w(fp op) {
aa.l = op_readpc();
aa.h = op_readpc();
rd.l = op_readdbr(aa.w + 0);
L rd.h = op_readdbr(aa.w + 1);
aa.l = readpc();
aa.h = readpc();
rd.l = readdbr(aa.w + 0);
L rd.h = readdbr(aa.w + 1);
call(op);
}
auto R65816::op_read_addrx_b(fp op) {
aa.l = op_readpc();
aa.h = op_readpc();
op_io_cond4(aa.w, aa.w + regs.x.w);
L rd.l = op_readdbr(aa.w + regs.x.w);
aa.l = readpc();
aa.h = readpc();
io4(aa.w, aa.w + regs.x.w);
L rd.l = readdbr(aa.w + regs.x.w);
call(op);
}
auto R65816::op_read_addrx_w(fp op) {
aa.l = op_readpc();
aa.h = op_readpc();
op_io_cond4(aa.w, aa.w + regs.x.w);
rd.l = op_readdbr(aa.w + regs.x.w + 0);
L rd.h = op_readdbr(aa.w + regs.x.w + 1);
aa.l = readpc();
aa.h = readpc();
io4(aa.w, aa.w + regs.x.w);
rd.l = readdbr(aa.w + regs.x.w + 0);
L rd.h = readdbr(aa.w + regs.x.w + 1);
call(op);
}
auto R65816::op_read_addry_b(fp op) {
aa.l = op_readpc();
aa.h = op_readpc();
op_io_cond4(aa.w, aa.w + regs.y.w);
L rd.l = op_readdbr(aa.w + regs.y.w);
aa.l = readpc();
aa.h = readpc();
io4(aa.w, aa.w + regs.y.w);
L rd.l = readdbr(aa.w + regs.y.w);
call(op);
}
auto R65816::op_read_addry_w(fp op) {
aa.l = op_readpc();
aa.h = op_readpc();
op_io_cond4(aa.w, aa.w + regs.y.w);
rd.l = op_readdbr(aa.w + regs.y.w + 0);
L rd.h = op_readdbr(aa.w + regs.y.w + 1);
aa.l = readpc();
aa.h = readpc();
io4(aa.w, aa.w + regs.y.w);
rd.l = readdbr(aa.w + regs.y.w + 0);
L rd.h = readdbr(aa.w + regs.y.w + 1);
call(op);
}
auto R65816::op_read_long_b(fp op) {
aa.l = op_readpc();
aa.h = op_readpc();
aa.b = op_readpc();
L rd.l = op_readlong(aa.d);
aa.l = readpc();
aa.h = readpc();
aa.b = readpc();
L rd.l = readlong(aa.d);
call(op);
}
auto R65816::op_read_long_w(fp op) {
aa.l = op_readpc();
aa.h = op_readpc();
aa.b = op_readpc();
rd.l = op_readlong(aa.d + 0);
L rd.h = op_readlong(aa.d + 1);
aa.l = readpc();
aa.h = readpc();
aa.b = readpc();
rd.l = readlong(aa.d + 0);
L rd.h = readlong(aa.d + 1);
call(op);
}
auto R65816::op_read_longx_b(fp op) {
aa.l = op_readpc();
aa.h = op_readpc();
aa.b = op_readpc();
L rd.l = op_readlong(aa.d + regs.x.w);
aa.l = readpc();
aa.h = readpc();
aa.b = readpc();
L rd.l = readlong(aa.d + regs.x.w);
call(op);
}
auto R65816::op_read_longx_w(fp op) {
aa.l = op_readpc();
aa.h = op_readpc();
aa.b = op_readpc();
rd.l = op_readlong(aa.d + regs.x.w + 0);
L rd.h = op_readlong(aa.d + regs.x.w + 1);
aa.l = readpc();
aa.h = readpc();
aa.b = readpc();
rd.l = readlong(aa.d + regs.x.w + 0);
L rd.h = readlong(aa.d + regs.x.w + 1);
call(op);
}
auto R65816::op_read_dp_b(fp op) {
dp = op_readpc();
op_io_cond2();
L rd.l = op_readdp(dp);
dp = readpc();
io2();
L rd.l = readdp(dp);
call(op);
}
auto R65816::op_read_dp_w(fp op) {
dp = op_readpc();
op_io_cond2();
rd.l = op_readdp(dp + 0);
L rd.h = op_readdp(dp + 1);
dp = readpc();
io2();
rd.l = readdp(dp + 0);
L rd.h = readdp(dp + 1);
call(op);
}
auto R65816::op_read_dpr_b(fp op, reg16_t& reg) {
dp = op_readpc();
op_io_cond2();
op_io();
L rd.l = op_readdp(dp + reg.w);
dp = readpc();
io2();
io();
L rd.l = readdp(dp + reg.w);
call(op);
}
auto R65816::op_read_dpr_w(fp op, reg16_t& reg) {
dp = op_readpc();
op_io_cond2();
op_io();
rd.l = op_readdp(dp + reg.w + 0);
L rd.h = op_readdp(dp + reg.w + 1);
dp = readpc();
io2();
io();
rd.l = readdp(dp + reg.w + 0);
L rd.h = readdp(dp + reg.w + 1);
call(op);
}
auto R65816::op_read_idp_b(fp op) {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp + 0);
aa.h = op_readdp(dp + 1);
L rd.l = op_readdbr(aa.w);
dp = readpc();
io2();
aa.l = readdp(dp + 0);
aa.h = readdp(dp + 1);
L rd.l = readdbr(aa.w);
call(op);
}
auto R65816::op_read_idp_w(fp op) {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp + 0);
aa.h = op_readdp(dp + 1);
rd.l = op_readdbr(aa.w + 0);
L rd.h = op_readdbr(aa.w + 1);
dp = readpc();
io2();
aa.l = readdp(dp + 0);
aa.h = readdp(dp + 1);
rd.l = readdbr(aa.w + 0);
L rd.h = readdbr(aa.w + 1);
call(op);
}
auto R65816::op_read_idpx_b(fp op) {
dp = op_readpc();
op_io_cond2();
op_io();
aa.l = op_readdp(dp + regs.x.w + 0);
aa.h = op_readdp(dp + regs.x.w + 1);
L rd.l = op_readdbr(aa.w);
dp = readpc();
io2();
io();
aa.l = readdp(dp + regs.x.w + 0);
aa.h = readdp(dp + regs.x.w + 1);
L rd.l = readdbr(aa.w);
call(op);
}
auto R65816::op_read_idpx_w(fp op) {
dp = op_readpc();
op_io_cond2();
op_io();
aa.l = op_readdp(dp + regs.x.w + 0);
aa.h = op_readdp(dp + regs.x.w + 1);
rd.l = op_readdbr(aa.w + 0);
L rd.h = op_readdbr(aa.w + 1);
dp = readpc();
io2();
io();
aa.l = readdp(dp + regs.x.w + 0);
aa.h = readdp(dp + regs.x.w + 1);
rd.l = readdbr(aa.w + 0);
L rd.h = readdbr(aa.w + 1);
call(op);
}
auto R65816::op_read_idpy_b(fp op) {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp + 0);
aa.h = op_readdp(dp + 1);
op_io_cond4(aa.w, aa.w + regs.y.w);
L rd.l = op_readdbr(aa.w + regs.y.w);
dp = readpc();
io2();
aa.l = readdp(dp + 0);
aa.h = readdp(dp + 1);
io4(aa.w, aa.w + regs.y.w);
L rd.l = readdbr(aa.w + regs.y.w);
call(op);
}
auto R65816::op_read_idpy_w(fp op) {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp + 0);
aa.h = op_readdp(dp + 1);
op_io_cond4(aa.w, aa.w + regs.y.w);
rd.l = op_readdbr(aa.w + regs.y.w + 0);
L rd.h = op_readdbr(aa.w + regs.y.w + 1);
dp = readpc();
io2();
aa.l = readdp(dp + 0);
aa.h = readdp(dp + 1);
io4(aa.w, aa.w + regs.y.w);
rd.l = readdbr(aa.w + regs.y.w + 0);
L rd.h = readdbr(aa.w + regs.y.w + 1);
call(op);
}
auto R65816::op_read_ildp_b(fp op) {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp + 0);
aa.h = op_readdp(dp + 1);
aa.b = op_readdp(dp + 2);
L rd.l = op_readlong(aa.d);
dp = readpc();
io2();
aa.l = readdp(dp + 0);
aa.h = readdp(dp + 1);
aa.b = readdp(dp + 2);
L rd.l = readlong(aa.d);
call(op);
}
auto R65816::op_read_ildp_w(fp op) {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp + 0);
aa.h = op_readdp(dp + 1);
aa.b = op_readdp(dp + 2);
rd.l = op_readlong(aa.d + 0);
L rd.h = op_readlong(aa.d + 1);
dp = readpc();
io2();
aa.l = readdp(dp + 0);
aa.h = readdp(dp + 1);
aa.b = readdp(dp + 2);
rd.l = readlong(aa.d + 0);
L rd.h = readlong(aa.d + 1);
call(op);
}
auto R65816::op_read_ildpy_b(fp op) {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp + 0);
aa.h = op_readdp(dp + 1);
aa.b = op_readdp(dp + 2);
L rd.l = op_readlong(aa.d + regs.y.w);
dp = readpc();
io2();
aa.l = readdp(dp + 0);
aa.h = readdp(dp + 1);
aa.b = readdp(dp + 2);
L rd.l = readlong(aa.d + regs.y.w);
call(op);
}
auto R65816::op_read_ildpy_w(fp op) {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp + 0);
aa.h = op_readdp(dp + 1);
aa.b = op_readdp(dp + 2);
rd.l = op_readlong(aa.d + regs.y.w + 0);
L rd.h = op_readlong(aa.d + regs.y.w + 1);
dp = readpc();
io2();
aa.l = readdp(dp + 0);
aa.h = readdp(dp + 1);
aa.b = readdp(dp + 2);
rd.l = readlong(aa.d + regs.y.w + 0);
L rd.h = readlong(aa.d + regs.y.w + 1);
call(op);
}
auto R65816::op_read_sr_b(fp op) {
sp = op_readpc();
op_io();
L rd.l = op_readsp(sp);
sp = readpc();
io();
L rd.l = readsp(sp);
call(op);
}
auto R65816::op_read_sr_w(fp op) {
sp = op_readpc();
op_io();
rd.l = op_readsp(sp + 0);
L rd.h = op_readsp(sp + 1);
sp = readpc();
io();
rd.l = readsp(sp + 0);
L rd.h = readsp(sp + 1);
call(op);
}
auto R65816::op_read_isry_b(fp op) {
sp = op_readpc();
op_io();
aa.l = op_readsp(sp + 0);
aa.h = op_readsp(sp + 1);
op_io();
L rd.l = op_readdbr(aa.w + regs.y.w);
sp = readpc();
io();
aa.l = readsp(sp + 0);
aa.h = readsp(sp + 1);
io();
L rd.l = readdbr(aa.w + regs.y.w);
call(op);
}
auto R65816::op_read_isry_w(fp op) {
sp = op_readpc();
op_io();
aa.l = op_readsp(sp + 0);
aa.h = op_readsp(sp + 1);
op_io();
rd.l = op_readdbr(aa.w + regs.y.w + 0);
L rd.h = op_readdbr(aa.w + regs.y.w + 1);
sp = readpc();
io();
aa.l = readsp(sp + 0);
aa.h = readsp(sp + 1);
io();
rd.l = readdbr(aa.w + regs.y.w + 0);
L rd.h = readdbr(aa.w + regs.y.w + 1);
call(op);
}

View File

@ -1,19 +1,19 @@
auto R65816::op_adjust_imm_b(reg16_t& reg, signed adjust) {
L op_io_irq();
L ioIRQ();
reg.l += adjust;
regs.p.n = (reg.l & 0x80);
regs.p.z = (reg.l == 0);
}
auto R65816::op_adjust_imm_w(reg16_t& reg, signed adjust) {
L op_io_irq();
L ioIRQ();
reg.w += adjust;
regs.p.n = (reg.w & 0x8000);
regs.p.z = (reg.w == 0);
}
auto R65816::op_asl_imm_b() {
L op_io_irq();
L ioIRQ();
regs.p.c = (regs.a.l & 0x80);
regs.a.l <<= 1;
regs.p.n = (regs.a.l & 0x80);
@ -21,7 +21,7 @@ L op_io_irq();
}
auto R65816::op_asl_imm_w() {
L op_io_irq();
L ioIRQ();
regs.p.c = (regs.a.w & 0x8000);
regs.a.w <<= 1;
regs.p.n = (regs.a.w & 0x8000);
@ -29,7 +29,7 @@ L op_io_irq();
}
auto R65816::op_lsr_imm_b() {
L op_io_irq();
L ioIRQ();
regs.p.c = (regs.a.l & 0x01);
regs.a.l >>= 1;
regs.p.n = (regs.a.l & 0x80);
@ -37,7 +37,7 @@ L op_io_irq();
}
auto R65816::op_lsr_imm_w() {
L op_io_irq();
L ioIRQ();
regs.p.c = (regs.a.w & 0x0001);
regs.a.w >>= 1;
regs.p.n = (regs.a.w & 0x8000);
@ -45,7 +45,7 @@ L op_io_irq();
}
auto R65816::op_rol_imm_b() {
L op_io_irq();
L ioIRQ();
bool carry = regs.p.c;
regs.p.c = (regs.a.l & 0x80);
regs.a.l = (regs.a.l << 1) | carry;
@ -54,7 +54,7 @@ L op_io_irq();
}
auto R65816::op_rol_imm_w() {
L op_io_irq();
L ioIRQ();
bool carry = regs.p.c;
regs.p.c = (regs.a.w & 0x8000);
regs.a.w = (regs.a.w << 1) | carry;
@ -63,7 +63,7 @@ L op_io_irq();
}
auto R65816::op_ror_imm_b() {
L op_io_irq();
L ioIRQ();
bool carry = regs.p.c;
regs.p.c = (regs.a.l & 0x01);
regs.a.l = (carry << 7) | (regs.a.l >> 1);
@ -72,7 +72,7 @@ L op_io_irq();
}
auto R65816::op_ror_imm_w() {
L op_io_irq();
L ioIRQ();
bool carry = regs.p.c;
regs.p.c = (regs.a.w & 0x0001);
regs.a.w = (carry << 15) | (regs.a.w >> 1);
@ -81,85 +81,85 @@ L op_io_irq();
}
auto R65816::op_adjust_addr_b(fp op) {
aa.l = op_readpc();
aa.h = op_readpc();
rd.l = op_readdbr(aa.w);
op_io();
aa.l = readpc();
aa.h = readpc();
rd.l = readdbr(aa.w);
io();
call(op);
L op_writedbr(aa.w, rd.l);
L writedbr(aa.w, rd.l);
}
auto R65816::op_adjust_addr_w(fp op) {
aa.l = op_readpc();
aa.h = op_readpc();
rd.l = op_readdbr(aa.w + 0);
rd.h = op_readdbr(aa.w + 1);
op_io();
aa.l = readpc();
aa.h = readpc();
rd.l = readdbr(aa.w + 0);
rd.h = readdbr(aa.w + 1);
io();
call(op);
op_writedbr(aa.w + 1, rd.h);
L op_writedbr(aa.w + 0, rd.l);
writedbr(aa.w + 1, rd.h);
L writedbr(aa.w + 0, rd.l);
}
auto R65816::op_adjust_addrx_b(fp op) {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
rd.l = op_readdbr(aa.w + regs.x.w);
op_io();
aa.l = readpc();
aa.h = readpc();
io();
rd.l = readdbr(aa.w + regs.x.w);
io();
call(op);
L op_writedbr(aa.w + regs.x.w, rd.l);
L writedbr(aa.w + regs.x.w, rd.l);
}
auto R65816::op_adjust_addrx_w(fp op) {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
rd.l = op_readdbr(aa.w + regs.x.w + 0);
rd.h = op_readdbr(aa.w + regs.x.w + 1);
op_io();
aa.l = readpc();
aa.h = readpc();
io();
rd.l = readdbr(aa.w + regs.x.w + 0);
rd.h = readdbr(aa.w + regs.x.w + 1);
io();
call(op);
op_writedbr(aa.w + regs.x.w + 1, rd.h);
L op_writedbr(aa.w + regs.x.w + 0, rd.l);
writedbr(aa.w + regs.x.w + 1, rd.h);
L writedbr(aa.w + regs.x.w + 0, rd.l);
}
auto R65816::op_adjust_dp_b(fp op) {
dp = op_readpc();
op_io_cond2();
rd.l = op_readdp(dp);
op_io();
dp = readpc();
io2();
rd.l = readdp(dp);
io();
call(op);
L op_writedp(dp, rd.l);
L writedp(dp, rd.l);
}
auto R65816::op_adjust_dp_w(fp op) {
dp = op_readpc();
op_io_cond2();
rd.l = op_readdp(dp + 0);
rd.h = op_readdp(dp + 1);
op_io();
dp = readpc();
io2();
rd.l = readdp(dp + 0);
rd.h = readdp(dp + 1);
io();
call(op);
op_writedp(dp + 1, rd.h);
L op_writedp(dp + 0, rd.l);
writedp(dp + 1, rd.h);
L writedp(dp + 0, rd.l);
}
auto R65816::op_adjust_dpx_b(fp op) {
dp = op_readpc();
op_io_cond2();
op_io();
rd.l = op_readdp(dp + regs.x.w);
op_io();
dp = readpc();
io2();
io();
rd.l = readdp(dp + regs.x.w);
io();
call(op);
L op_writedp(dp + regs.x.w, rd.l);
L writedp(dp + regs.x.w, rd.l);
}
auto R65816::op_adjust_dpx_w(fp op) {
dp = op_readpc();
op_io_cond2();
op_io();
rd.l = op_readdp(dp + regs.x.w + 0);
rd.h = op_readdp(dp + regs.x.w + 1);
op_io();
dp = readpc();
io2();
io();
rd.l = readdp(dp + regs.x.w + 0);
rd.h = readdp(dp + regs.x.w + 1);
io();
call(op);
op_writedp(dp + regs.x.w + 1, rd.h);
L op_writedp(dp + regs.x.w + 0, rd.l);
writedp(dp + regs.x.w + 1, rd.h);
L writedp(dp + regs.x.w + 0, rd.l);
}

View File

@ -1,195 +1,195 @@
auto R65816::op_write_addr_b(reg16_t& reg) {
aa.l = op_readpc();
aa.h = op_readpc();
L op_writedbr(aa.w, reg);
aa.l = readpc();
aa.h = readpc();
L writedbr(aa.w, reg);
}
auto R65816::op_write_addr_w(reg16_t& reg) {
aa.l = op_readpc();
aa.h = op_readpc();
op_writedbr(aa.w + 0, reg >> 0);
L op_writedbr(aa.w + 1, reg >> 8);
aa.l = readpc();
aa.h = readpc();
writedbr(aa.w + 0, reg >> 0);
L writedbr(aa.w + 1, reg >> 8);
}
auto R65816::op_write_addrr_b(reg16_t& reg, reg16_t& idx) {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
L op_writedbr(aa.w + idx, reg);
aa.l = readpc();
aa.h = readpc();
io();
L writedbr(aa.w + idx, reg);
}
auto R65816::op_write_addrr_w(reg16_t& reg, reg16_t& idx) {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
op_writedbr(aa.w + idx + 0, reg >> 0);
L op_writedbr(aa.w + idx + 1, reg >> 8);
aa.l = readpc();
aa.h = readpc();
io();
writedbr(aa.w + idx + 0, reg >> 0);
L writedbr(aa.w + idx + 1, reg >> 8);
}
auto R65816::op_write_longr_b(reg16_t& idx) {
aa.l = op_readpc();
aa.h = op_readpc();
aa.b = op_readpc();
L op_writelong(aa.d + idx, regs.a.l);
aa.l = readpc();
aa.h = readpc();
aa.b = readpc();
L writelong(aa.d + idx, regs.a.l);
}
auto R65816::op_write_longr_w(reg16_t& idx) {
aa.l = op_readpc();
aa.h = op_readpc();
aa.b = op_readpc();
op_writelong(aa.d + idx + 0, regs.a.l);
L op_writelong(aa.d + idx + 1, regs.a.h);
aa.l = readpc();
aa.h = readpc();
aa.b = readpc();
writelong(aa.d + idx + 0, regs.a.l);
L writelong(aa.d + idx + 1, regs.a.h);
}
auto R65816::op_write_dp_b(reg16_t& reg) {
dp = op_readpc();
op_io_cond2();
L op_writedp(dp, reg);
dp = readpc();
io2();
L writedp(dp, reg);
}
auto R65816::op_write_dp_w(reg16_t& reg) {
dp = op_readpc();
op_io_cond2();
op_writedp(dp + 0, reg >> 0);
L op_writedp(dp + 1, reg >> 8);
dp = readpc();
io2();
writedp(dp + 0, reg >> 0);
L writedp(dp + 1, reg >> 8);
}
auto R65816::op_write_dpr_b(reg16_t& reg, reg16_t& idx) {
dp = op_readpc();
op_io_cond2();
op_io();
L op_writedp(dp + idx, reg);
dp = readpc();
io2();
io();
L writedp(dp + idx, reg);
}
auto R65816::op_write_dpr_w(reg16_t& reg, reg16_t& idx) {
dp = op_readpc();
op_io_cond2();
op_io();
op_writedp(dp + idx + 0, reg >> 0);
L op_writedp(dp + idx + 1, reg >> 8);
dp = readpc();
io2();
io();
writedp(dp + idx + 0, reg >> 0);
L writedp(dp + idx + 1, reg >> 8);
}
auto R65816::op_sta_idp_b() {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp + 0);
aa.h = op_readdp(dp + 1);
L op_writedbr(aa.w, regs.a.l);
dp = readpc();
io2();
aa.l = readdp(dp + 0);
aa.h = readdp(dp + 1);
L writedbr(aa.w, regs.a.l);
}
auto R65816::op_sta_idp_w() {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp + 0);
aa.h = op_readdp(dp + 1);
op_writedbr(aa.w + 0, regs.a.l);
L op_writedbr(aa.w + 1, regs.a.h);
dp = readpc();
io2();
aa.l = readdp(dp + 0);
aa.h = readdp(dp + 1);
writedbr(aa.w + 0, regs.a.l);
L writedbr(aa.w + 1, regs.a.h);
}
auto R65816::op_sta_ildp_b() {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp + 0);
aa.h = op_readdp(dp + 1);
aa.b = op_readdp(dp + 2);
L op_writelong(aa.d, regs.a.l);
dp = readpc();
io2();
aa.l = readdp(dp + 0);
aa.h = readdp(dp + 1);
aa.b = readdp(dp + 2);
L writelong(aa.d, regs.a.l);
}
auto R65816::op_sta_ildp_w() {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp + 0);
aa.h = op_readdp(dp + 1);
aa.b = op_readdp(dp + 2);
op_writelong(aa.d + 0, regs.a.l);
L op_writelong(aa.d + 1, regs.a.h);
dp = readpc();
io2();
aa.l = readdp(dp + 0);
aa.h = readdp(dp + 1);
aa.b = readdp(dp + 2);
writelong(aa.d + 0, regs.a.l);
L writelong(aa.d + 1, regs.a.h);
}
auto R65816::op_sta_idpx_b() {
dp = op_readpc();
op_io_cond2();
op_io();
aa.l = op_readdp(dp + regs.x.w + 0);
aa.h = op_readdp(dp + regs.x.w + 1);
L op_writedbr(aa.w, regs.a.l);
dp = readpc();
io2();
io();
aa.l = readdp(dp + regs.x.w + 0);
aa.h = readdp(dp + regs.x.w + 1);
L writedbr(aa.w, regs.a.l);
}
auto R65816::op_sta_idpx_w() {
dp = op_readpc();
op_io_cond2();
op_io();
aa.l = op_readdp(dp + regs.x.w + 0);
aa.h = op_readdp(dp + regs.x.w + 1);
op_writedbr(aa.w + 0, regs.a.l);
L op_writedbr(aa.w + 1, regs.a.h);
dp = readpc();
io2();
io();
aa.l = readdp(dp + regs.x.w + 0);
aa.h = readdp(dp + regs.x.w + 1);
writedbr(aa.w + 0, regs.a.l);
L writedbr(aa.w + 1, regs.a.h);
}
auto R65816::op_sta_idpy_b() {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp + 0);
aa.h = op_readdp(dp + 1);
op_io();
L op_writedbr(aa.w + regs.y.w, regs.a.l);
dp = readpc();
io2();
aa.l = readdp(dp + 0);
aa.h = readdp(dp + 1);
io();
L writedbr(aa.w + regs.y.w, regs.a.l);
}
auto R65816::op_sta_idpy_w() {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp + 0);
aa.h = op_readdp(dp + 1);
op_io();
op_writedbr(aa.w + regs.y.w + 0, regs.a.l);
L op_writedbr(aa.w + regs.y.w + 1, regs.a.h);
dp = readpc();
io2();
aa.l = readdp(dp + 0);
aa.h = readdp(dp + 1);
io();
writedbr(aa.w + regs.y.w + 0, regs.a.l);
L writedbr(aa.w + regs.y.w + 1, regs.a.h);
}
auto R65816::op_sta_ildpy_b() {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp + 0);
aa.h = op_readdp(dp + 1);
aa.b = op_readdp(dp + 2);
L op_writelong(aa.d + regs.y.w, regs.a.l);
dp = readpc();
io2();
aa.l = readdp(dp + 0);
aa.h = readdp(dp + 1);
aa.b = readdp(dp + 2);
L writelong(aa.d + regs.y.w, regs.a.l);
}
auto R65816::op_sta_ildpy_w() {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp + 0);
aa.h = op_readdp(dp + 1);
aa.b = op_readdp(dp + 2);
op_writelong(aa.d + regs.y.w + 0, regs.a.l);
L op_writelong(aa.d + regs.y.w + 1, regs.a.h);
dp = readpc();
io2();
aa.l = readdp(dp + 0);
aa.h = readdp(dp + 1);
aa.b = readdp(dp + 2);
writelong(aa.d + regs.y.w + 0, regs.a.l);
L writelong(aa.d + regs.y.w + 1, regs.a.h);
}
auto R65816::op_sta_sr_b() {
sp = op_readpc();
op_io();
L op_writesp(sp, regs.a.l);
sp = readpc();
io();
L writesp(sp, regs.a.l);
}
auto R65816::op_sta_sr_w() {
sp = op_readpc();
op_io();
op_writesp(sp + 0, regs.a.l);
L op_writesp(sp + 1, regs.a.h);
sp = readpc();
io();
writesp(sp + 0, regs.a.l);
L writesp(sp + 1, regs.a.h);
}
auto R65816::op_sta_isry_b() {
sp = op_readpc();
op_io();
aa.l = op_readsp(sp + 0);
aa.h = op_readsp(sp + 1);
op_io();
L op_writedbr(aa.w + regs.y.w, regs.a.l);
sp = readpc();
io();
aa.l = readsp(sp + 0);
aa.h = readsp(sp + 1);
io();
L writedbr(aa.w + regs.y.w, regs.a.l);
}
auto R65816::op_sta_isry_w() {
sp = op_readpc();
op_io();
aa.l = op_readsp(sp + 0);
aa.h = op_readsp(sp + 1);
op_io();
op_writedbr(aa.w + regs.y.w + 0, regs.a.l);
L op_writedbr(aa.w + regs.y.w + 1, regs.a.h);
sp = readpc();
io();
aa.l = readsp(sp + 0);
aa.h = readsp(sp + 1);
io();
writedbr(aa.w + regs.y.w + 0, regs.a.l);
L writedbr(aa.w + regs.y.w + 1, regs.a.h);
}

View File

@ -7,7 +7,7 @@ namespace Processor {
#include "disassembler.cpp"
#include "serialization.cpp"
#define L last_cycle();
#define L lastCycle();
#define call(op) (this->*op)()
#include "opcode_read.cpp"
@ -28,45 +28,45 @@ namespace Processor {
// tcd, tcs, tdc, tsc, tsx, txs,
// inc, inx, iny, dec, dex, dey,
// asl, lsr, rol, ror, nop, xce.
auto R65816::op_io_irq() -> void {
if(interrupt_pending()) {
auto R65816::ioIRQ() -> void {
if(interruptPending()) {
//modify I/O cycle to bus read cycle, do not increment PC
op_read(regs.pc.d);
read(regs.pc.d);
} else {
op_io();
io();
}
}
auto R65816::op_io_cond2() -> void {
auto R65816::io2() -> void {
if(regs.d.l != 0x00) {
op_io();
io();
}
}
auto R65816::op_io_cond4(uint16 x, uint16 y) -> void {
auto R65816::io4(uint16 x, uint16 y) -> void {
if(!regs.p.x || (x & 0xff00) != (y & 0xff00)) {
op_io();
io();
}
}
auto R65816::op_io_cond6(uint16 addr) -> void {
auto R65816::io6(uint16 addr) -> void {
if(regs.e && (regs.pc.w & 0xff00) != (addr & 0xff00)) {
op_io();
io();
}
}
auto R65816::op_irq() -> void {
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(regs.vector + 0);
auto R65816::interrupt() -> void {
read(regs.pc.d);
io();
if(!regs.e) writestack(regs.pc.b);
writestack(regs.pc.h);
writestack(regs.pc.l);
writestack(regs.e ? (regs.p & ~0x10) : regs.p);
rd.l = read(regs.vector + 0);
regs.pc.b = 0x00;
regs.p.i = 1;
regs.p.d = 0;
rd.h = op_read(regs.vector + 1);
rd.h = read(regs.vector + 1);
regs.pc.w = rd.w;
}

View File

@ -13,20 +13,20 @@ struct R65816 {
using fp = auto (R65816::*)() -> void;
virtual auto op_io() -> void = 0;
virtual auto op_read(uint24 addr) -> uint8 = 0;
virtual auto op_write(uint24 addr, uint8 data) -> void = 0;
virtual auto last_cycle() -> void = 0;
virtual auto interrupt_pending() -> bool = 0;
virtual auto op_irq() -> void;
virtual auto io() -> void = 0;
virtual auto read(uint24 addr) -> uint8 = 0;
virtual auto write(uint24 addr, uint8 data) -> void = 0;
virtual auto lastCycle() -> void = 0;
virtual auto interruptPending() const -> bool = 0;
virtual auto interrupt() -> void;
virtual auto disassembler_read(uint24 addr) -> uint8 { return 0u; }
virtual auto disassemblerRead(uint24 addr) -> uint8 { return 0u; }
//r65816.cpp
alwaysinline auto op_io_irq() -> void;
alwaysinline auto op_io_cond2() -> void;
alwaysinline auto op_io_cond4(uint16 x, uint16 y) -> void;
alwaysinline auto op_io_cond6(uint16 addr) -> void;
alwaysinline auto ioIRQ() -> void;
alwaysinline auto io2() -> void;
alwaysinline auto io4(uint16 x, uint16 y) -> void;
alwaysinline auto io6(uint16 addr) -> void;
//algorithms.cpp
auto op_adc_b();
@ -215,7 +215,7 @@ struct R65816 {
auto op_per_n();
//switch.cpp
auto op_exec() -> void;
auto instruction() -> void;
//serialization.cpp
auto serialize(serializer&) -> void;

View File

@ -1,4 +1,4 @@
auto R65816::op_exec() -> void {
auto R65816::instruction() -> void {
#define opA( n, o ) case n: return op_##o();
#define opAII(n, o, i, j) case n: return op_##o(i, j);
#define opE( n, o ) case n: return regs.e ? op_##o##_e() : op_##o##_n();
@ -15,7 +15,7 @@ auto R65816::op_exec() -> void {
#define opXI( n, o, i ) case n: return regs.p.x ? op_##o##_b(i) : op_##o##_w(i);
#define opXII(n, o, i, j) case n: return regs.p.x ? op_##o##_b(i, j) : op_##o##_w(i, j);
switch(op_readpc()) {
switch(readpc()) {
opEII(0x00, interrupt, 0xfffe, 0xffe6)
opMF (0x01, read_idpx, ora)
opEII(0x02, interrupt, 0xfff4, 0xffe4)

View File

@ -1,3 +1,4 @@
//todo: this is horribly broken in many cases; needs a total rewrite
auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> string {
string s;
uint20 ea = cs * 16 + ip;

View File

@ -8,7 +8,7 @@ auto V30MZ::opDecimalAdjust(bool negate) {
r.f.h = 1;
}
if(r.f.c || (al > 0x99)) {
r.al += negate ? -0x06 : 0x60;
r.al += negate ? -0x60 : 0x60;
r.f.c = 1;
}
r.f.s = r.al & 0x80;

View File

@ -51,8 +51,8 @@ auto V30MZ::opCompareString(Size size) {
alSub(size, x, y);
if(!repeat() || !--r.cx) return;
if(repeat() == RepeatWhileZero && r.f.z == 1) return;
if(repeat() == RepeatWhileNotZero && r.f.z == 0) return;
if(repeat() == RepeatWhileZero && r.f.z == 0) return;
if(repeat() == RepeatWhileNotZero && r.f.z == 1) return;
state.prefix = true;
r.ip--;
@ -98,8 +98,8 @@ auto V30MZ::opScanString(Size size) {
alSub(size, x, y);
if(!repeat() || !--r.cx) return;
if(repeat() == RepeatWhileZero && r.f.z == 1) return;
if(repeat() == RepeatWhileNotZero && r.f.z == 0) return;
if(repeat() == RepeatWhileZero && r.f.z == 0) return;
if(repeat() == RepeatWhileNotZero && r.f.z == 1) return;
state.prefix = true;
r.ip--;

View File

@ -32,7 +32,7 @@ auto V30MZ::power() -> void {
r.cx = 0x0000;
r.dx = 0x0000;
r.bx = 0x0000;
r.sp = 0x0000;
r.sp = 0x2000;
r.bp = 0x0000;
r.si = 0x0000;
r.di = 0x0000;

View File

@ -108,17 +108,17 @@ auto SA1::vbr_read(uint24 addr, uint8 data) -> uint8 {
//tick() == 2 clock ticks
//note: bus conflict delays are not emulated at this time
auto SA1::op_io() -> void {
auto SA1::io() -> void {
tick();
}
auto SA1::op_read(uint24 addr) -> uint8 {
auto SA1::read(uint24 addr) -> uint8 {
tick();
if(((addr & 0x40e000) == 0x006000) || ((addr & 0xd00000) == 0x400000)) tick();
return bus_read(addr, regs.mdr);
}
auto SA1::op_write(uint24 addr, uint8 data) -> void {
auto SA1::write(uint24 addr, uint8 data) -> void {
tick();
if(((addr & 0x40e000) == 0x006000) || ((addr & 0xd00000) == 0x400000)) tick();
bus_write(addr, regs.mdr = data);

View File

@ -2,9 +2,9 @@ auto bus_read(uint24 addr, uint8 data) -> uint8;
auto bus_write(uint24 addr, uint8 data) -> void;
auto vbr_read(uint24 addr, uint8 data = 0) -> uint8;
alwaysinline auto op_io() -> void override;
alwaysinline auto op_read(uint24 addr) -> uint8 override;
alwaysinline auto op_write(uint24 addr, uint8 data) -> void override;
alwaysinline auto io() -> void override;
alwaysinline auto read(uint24 addr) -> uint8 override;
alwaysinline auto write(uint24 addr, uint8 data) -> void override;
auto mmcrom_read(uint24 addr, uint8 data) -> uint8;
auto mmcrom_write(uint24 addr, uint8 data) -> void;

View File

@ -24,27 +24,27 @@ auto SA1::main() -> void {
if(status.interrupt_pending) {
status.interrupt_pending = false;
op_irq();
interrupt();
return;
}
op_exec();
instruction();
}
auto SA1::op_irq() -> void {
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);
auto SA1::interrupt() -> void {
read(regs.pc.d);
io();
if(!regs.e) writestack(regs.pc.b);
writestack(regs.pc.h);
writestack(regs.pc.l);
writestack(regs.e ? (regs.p & ~0x10) : regs.p);
regs.pc.w = regs.vector;
regs.pc.b = 0x00;
regs.p.i = 1;
regs.p.d = 0;
}
auto SA1::last_cycle() -> void {
auto SA1::lastCycle() -> void {
if(mmio.sa1_nmi && !mmio.sa1_nmicl) {
status.interrupt_pending = true;
regs.vector = mmio.cnv;
@ -71,7 +71,7 @@ auto SA1::last_cycle() -> void {
}
}
auto SA1::interrupt_pending() -> bool {
auto SA1::interruptPending() const -> bool {
return status.interrupt_pending;
}

View File

@ -17,11 +17,11 @@ struct SA1 : Processor::R65816, public Coprocessor {
static auto Enter() -> void;
auto main() -> void;
auto tick() -> void;
auto op_irq() -> void override;
auto interrupt() -> void override;
alwaysinline auto trigger_irq() -> void;
alwaysinline auto last_cycle() -> void override;
alwaysinline auto interrupt_pending() -> bool override;
alwaysinline auto lastCycle() -> void override;
alwaysinline auto interruptPending() const -> bool override;
auto init() -> void;
auto load() -> void;

View File

@ -69,7 +69,7 @@ auto SDD1::write(uint24 addr, uint8 data) -> void {
}
auto SDD1::dma_read(uint24 addr, uint8 data) -> uint8 {
return cpu.mmio_read(addr, data);
return cpu.dmaPortRead(addr, data);
}
auto SDD1::dma_write(uint24 addr, uint8 data) -> void {
@ -82,7 +82,7 @@ auto SDD1::dma_write(uint24 addr, uint8 data) -> void {
case 5: dma[channel].size = (dma[channel].size & 0xff00) + (data << 0); break;
case 6: dma[channel].size = (dma[channel].size & 0x00ff) + (data << 8); break;
}
return cpu.mmio_write(addr, data);
return cpu.dmaPortWrite(addr, data);
}
auto SDD1::mmc_read(uint24 addr) -> uint8 {

View File

@ -1,5 +0,0 @@
auto disassemble_opcode(char* output) -> void;
auto disassemble_alt0(char* output) -> void;
auto disassemble_alt1(char* output) -> void;
auto disassemble_alt2(char* output) -> void;
auto disassemble_alt3(char* output) -> void;

View File

@ -1,4 +1,4 @@
auto SuperFX::bus_read(unsigned addr) -> uint8 {
auto SuperFX::bus_read(uint24 addr, uint8 data) -> uint8 {
if((addr & 0xc00000) == 0x000000) { //$00-3f:0000-7fff, $00-3f:8000-ffff
while(!regs.scmr.ron && !scheduler.synchronizing()) {
step(6);
@ -22,9 +22,11 @@ auto SuperFX::bus_read(unsigned addr) -> uint8 {
}
return ram.read(addr & ram_mask);
}
return data;
}
auto SuperFX::bus_write(unsigned addr, uint8 data) -> void {
auto SuperFX::bus_write(uint24 addr, uint8 data) -> void {
if((addr & 0xe00000) == 0x600000) { //$60-7f:0000-ffff
while(!regs.scmr.ran && !scheduler.synchronizing()) {
step(6);

View File

@ -1,8 +1,8 @@
unsigned rom_mask; //rom_size - 1
unsigned ram_mask; //ram_size - 1
uint rom_mask; //rom_size - 1
uint ram_mask; //ram_size - 1
auto bus_read(unsigned addr) -> uint8;
auto bus_write(unsigned addr, uint8 data) -> void;
auto bus_read(uint24 addr, uint8 data = 0x00) -> uint8 override;
auto bus_write(uint24 addr, uint8 data) -> void override;
auto op_read(uint16 addr) -> uint8;
alwaysinline auto peekpipe() -> uint8;

View File

@ -8,7 +8,6 @@ namespace SuperFamicom {
#include "memory/memory.cpp"
#include "mmio/mmio.cpp"
#include "timing/timing.cpp"
#include "disassembler/disassembler.cpp"
SuperFX superfx;

View File

@ -7,7 +7,6 @@ struct SuperFX : Processor::GSU, Coprocessor {
#include "memory/memory.hpp"
#include "mmio/mmio.hpp"
#include "timing/timing.hpp"
#include "disassembler/disassembler.hpp"
//superfx.cpp
static auto Enter() -> void;

View File

@ -3,12 +3,17 @@
namespace SuperFamicom {
CPU cpu;
#include "dma.cpp"
#include "memory.cpp"
#include "mmio.cpp"
#include "timing.cpp"
#include "irq.cpp"
#include "joypad.cpp"
#include "serialization.cpp"
#include "dma/dma.cpp"
#include "memory/memory.cpp"
#include "mmio/mmio.cpp"
#include "timing/timing.cpp"
auto CPU::interruptPending() const -> bool { return status.interrupt_pending; }
auto CPU::pio() const -> uint8 { return status.pio; }
auto CPU::joylatch() const -> bool { return status.joypad_strobe_latch; }
CPU::CPU() {
PPUcounter::scanline = {&CPU::scanline, this};
@ -62,35 +67,38 @@ auto CPU::main() -> void {
if(status.nmi_pending) {
status.nmi_pending = false;
regs.vector = (regs.e == false ? 0xffea : 0xfffa);
op_irq();
interrupt();
debugger.op_nmi();
} else if(status.irq_pending) {
status.irq_pending = false;
regs.vector = (regs.e == false ? 0xffee : 0xfffe);
op_irq();
interrupt();
debugger.op_irq();
} else if(status.reset_pending) {
status.reset_pending = false;
add_clocks(186);
addClocks(186);
regs.pc.l = bus.read(0xfffc, regs.mdr);
regs.pc.h = bus.read(0xfffd, regs.mdr);
}
}
op_step();
}
auto CPU::op_step() -> void {
debugger.op_exec(regs.pc.d);
op_exec();
instruction();
}
auto CPU::enable() -> void {
function<auto (uint, uint8) -> uint8> reader{&CPU::mmio_read, (CPU*)&cpu};
function<auto (uint, uint8) -> void> writer{&CPU::mmio_write, (CPU*)&cpu};
function<auto (uint24, uint8) -> uint8> reader;
function<auto (uint24, uint8) -> void> writer;
bus.map(reader, writer, 0x00, 0x3f, 0x2140, 0x2183);
bus.map(reader, writer, 0x80, 0xbf, 0x2140, 0x2183);
reader = {&CPU::apuPortRead, this};
writer = {&CPU::apuPortWrite, this};
bus.map(reader, writer, 0x00, 0x3f, 0x2140, 0x217f);
bus.map(reader, writer, 0x80, 0xbf, 0x2140, 0x217f);
reader = {&CPU::cpuPortRead, this};
writer = {&CPU::cpuPortWrite, this};
bus.map(reader, writer, 0x00, 0x3f, 0x2180, 0x2183);
bus.map(reader, writer, 0x80, 0xbf, 0x2180, 0x2183);
bus.map(reader, writer, 0x00, 0x3f, 0x4016, 0x4017);
bus.map(reader, writer, 0x80, 0xbf, 0x4016, 0x4017);
@ -98,12 +106,13 @@ auto CPU::enable() -> void {
bus.map(reader, writer, 0x00, 0x3f, 0x4200, 0x421f);
bus.map(reader, writer, 0x80, 0xbf, 0x4200, 0x421f);
reader = {&CPU::dmaPortRead, this};
writer = {&CPU::dmaPortWrite, this};
bus.map(reader, writer, 0x00, 0x3f, 0x4300, 0x437f);
bus.map(reader, writer, 0x80, 0xbf, 0x4300, 0x437f);
reader = [](uint addr, uint8) -> uint8 { return cpu.wram[addr]; };
writer = [](uint addr, uint8 data) -> void { cpu.wram[addr] = data; };
reader = [](uint24 addr, uint8) -> uint8 { return cpu.wram[addr]; };
writer = [](uint24 addr, uint8 data) -> void { cpu.wram[addr] = data; };
bus.map(reader, writer, 0x00, 0x3f, 0x0000, 0x1fff, 0x002000);
bus.map(reader, writer, 0x80, 0xbf, 0x0000, 0x1fff, 0x002000);
bus.map(reader, writer, 0x7e, 0x7f, 0x0000, 0xffff, 0x020000);
@ -112,12 +121,31 @@ auto CPU::enable() -> void {
auto CPU::power() -> void {
for(auto& byte : wram) byte = random(0x55);
//CPU
regs.a = regs.x = regs.y = 0x0000;
regs.s = 0x01ff;
mmio_power();
dma_power();
timing_power();
//DMA
for(auto& channel : this->channel) {
channel.direction = 1;
channel.indirect = true;
channel.unused = true;
channel.reverse_transfer = true;
channel.fixed_transfer = true;
channel.transfer_mode = 7;
channel.dest_addr = 0xff;
channel.source_addr = 0xffff;
channel.source_bank = 0xff;
channel.transfer_size = 0xffff;
channel.indirect_bank = 0xff;
channel.hdma_addr = 0xffff;
channel.line_counter = 0xff;
channel.unknown = 0xff;
}
}
auto CPU::reset() -> void {
@ -125,7 +153,7 @@ auto CPU::reset() -> void {
coprocessors.reset();
PPUcounter::reset();
//note: some registers are not fully reset by SNES
//CPU
regs.pc = 0x000000;
regs.x.h = 0x00;
regs.y.h = 0x00;
@ -138,9 +166,109 @@ auto CPU::reset() -> void {
regs.wai = false;
regs.vector = 0xfffc; //reset vector address
mmio_reset();
dma_reset();
timing_reset();
//$2140-217f
for(auto& port : status.port) port = 0x00;
//$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.wrmpya = 0xff;
status.wrmpyb = 0xff;
//$4204-$4206
status.wrdiva = 0xffff;
status.wrdivb = 0xff;
//$4207-$420a
status.hirq_pos = 0x01ff;
status.virq_pos = 0x01ff;
//$420d
status.rom_speed = 8;
//$4214-$4217
status.rddiv = 0x0000;
status.rdmpy = 0x0000;
//$4218-$421f
status.joy1 = 0x0000;
status.joy2 = 0x0000;
status.joy3 = 0x0000;
status.joy4 = 0x0000;
//ALU
alu.mpyctr = 0;
alu.divctr = 0;
alu.shift = 0;
//DMA
for(auto& channel : this->channel) {
channel.dma_enabled = false;
channel.hdma_enabled = false;
channel.hdma_completed = false;
channel.hdma_do_transfer = false;
}
pipe.valid = false;
pipe.addr = 0;
pipe.data = 0;
//Timing
status.clock_count = 0;
status.line_clocks = lineclocks();
status.irq_lock = false;
status.dram_refresh_position = (cpu_version == 1 ? 530 : 538);
status.dram_refreshed = false;
status.hdma_init_position = (cpu_version == 1 ? 12 + 8 - dmaCounter() : 12 + dmaCounter());
status.hdma_init_triggered = false;
status.hdma_position = 1104;
status.hdma_triggered = false;
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.reset_pending = true;
status.interrupt_pending = true;
status.dma_active = false;
status.dma_counter = 0;
status.dma_clocks = 0;
status.dma_pending = false;
status.hdma_pending = false;
status.hdma_mode = 0;
status.auto_joypad_active = false;
status.auto_joypad_latch = false;
status.auto_joypad_counter = 0;
status.auto_joypad_clock = 0;
}
}

View File

@ -1,6 +1,10 @@
struct CPU : Processor::R65816, Thread, public PPUcounter {
enum : bool { Threaded = true };
auto interruptPending() const -> bool override;
auto pio() const -> uint8;
auto joylatch() const -> bool;
CPU();
alwaysinline auto step(uint clocks) -> void;
@ -12,15 +16,75 @@ struct CPU : Processor::R65816, Thread, public PPUcounter {
auto portRead(uint2 port) const -> uint8;
auto portWrite(uint2 port, uint8 data) -> void;
auto pio() -> uint8;
auto joylatch() -> bool;
alwaysinline auto interrupt_pending() -> bool { return status.interrupt_pending; }
static auto Enter() -> void;
auto main() -> void;
auto enable() -> void;
auto power() -> void;
auto reset() -> void;
//dma.cpp
auto dmaAddClocks(uint clocks) -> void;
auto dmaTransferValid(uint8 bbus, uint24 abus) -> bool;
auto dmaAddressValid(uint24 abus) -> bool;
auto dmaRead(uint24 abus) -> uint8;
auto dmaWrite(bool valid, uint addr = 0, uint8 data = 0) -> void;
auto dmaTransfer(bool direction, uint8 bbus, uint24 abus) -> void;
auto dmaAddressB(uint n, uint channel) -> uint8;
auto dmaAddress(uint n) -> uint24;
auto hdmaAddress(uint n) -> uint24;
auto hdmaIndirectAddress(uint n) -> uint24;
auto dmaEnabledChannels() -> uint;
auto hdmaActive(uint n) -> bool;
auto hdmaActiveAfter(uint s) -> bool;
auto hdmaEnabledChannels() -> uint;
auto hdmaActiveChannels() -> uint;
auto dmaRun() -> void;
auto hdmaUpdate(uint n) -> void;
auto hdmaRun() -> void;
auto hdmaInitReset() -> void;
auto hdmaInit() -> void;
//memory.cpp
auto io() -> void override;
auto read(uint24 addr) -> uint8 override;
auto write(uint24 addr, uint8 data) -> void override;
alwaysinline auto speed(uint24 addr) const -> uint;
auto disassemblerRead(uint24 addr) -> uint8 override;
//mmio.cpp
auto apuPortRead(uint24 addr, uint8 data) -> uint8;
auto cpuPortRead(uint24 addr, uint8 data) -> uint8;
auto dmaPortRead(uint24 addr, uint8 data) -> uint8;
auto apuPortWrite(uint24 addr, uint8 data) -> void;
auto cpuPortWrite(uint24 addr, uint8 data) -> void;
auto dmaPortWrite(uint24 addr, uint8 data) -> void;
//timing.cpp
auto dmaCounter() const -> uint;
auto addClocks(uint clocks) -> void;
auto scanline() -> void;
alwaysinline auto aluEdge() -> void;
alwaysinline auto dmaEdge() -> void;
alwaysinline auto lastCycle() -> void;
//irq.cpp
alwaysinline auto pollInterrupts() -> void;
auto nmitimenUpdate(uint8 data) -> void;
auto rdnmi() -> bool;
auto timeup() -> bool;
alwaysinline auto nmiTest() -> bool;
alwaysinline auto irqTest() -> bool;
//joypad.cpp
auto stepAutoJoypadPoll() -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
uint8 wram[128 * 1024];
@ -29,11 +93,6 @@ struct CPU : Processor::R65816, Thread, public PPUcounter {
privileged:
uint cpu_version = 2; //allowed: 1, 2
#include "dma/dma.hpp"
#include "memory/memory.hpp"
#include "mmio/mmio.hpp"
#include "timing/timing.hpp"
struct Status {
bool interrupt_pending;
@ -132,15 +191,65 @@ privileged:
uint shift;
} alu;
static auto Enter() -> void;
auto op_step() -> void;
struct Channel {
//$420b
bool dma_enabled;
//$420c
bool hdma_enabled;
//$43x0
bool direction;
bool indirect;
bool unused;
bool reverse_transfer;
bool fixed_transfer;
uint3 transfer_mode;
//$43x1
uint8 dest_addr;
//$43x2-$43x3
uint16 source_addr;
//$43x4
uint8 source_bank;
//$43x5-$43x6
union {
uint16_t transfer_size;
uint16_t indirect_addr;
};
//$43x7
uint8 indirect_bank;
//$43x8-$43x9
uint16 hdma_addr;
//$43xa
uint8 line_counter;
//$43xb/$43xf
uint8 unknown;
//internal state
bool hdma_completed;
bool hdma_do_transfer;
} channel[8];
struct Pipe {
bool valid;
uint addr;
uint8 data;
} pipe;
struct Debugger {
hook<void (uint24)> op_exec;
hook<void (uint24, uint8)> op_read;
hook<void (uint24, uint8)> op_write;
hook<void ()> op_nmi;
hook<void ()> op_irq;
hook<auto (uint24) -> void> op_exec;
hook<auto (uint24, uint8) -> void> op_read;
hook<auto (uint24, uint8) -> void> op_write;
hook<auto () -> void> op_nmi;
hook<auto () -> void> op_irq;
} debugger;
};

238
higan/sfc/cpu/dma.cpp Normal file
View File

@ -0,0 +1,238 @@
auto CPU::dmaAddClocks(uint clocks) -> void {
status.dma_clocks += clocks;
addClocks(clocks);
}
//=============
//memory access
//=============
auto CPU::dmaTransferValid(uint8 bbus, uint24 abus) -> bool {
//transfers from WRAM to WRAM are invalid; chip only has one address bus
if(bbus == 0x80 && ((abus & 0xfe0000) == 0x7e0000 || (abus & 0x40e000) == 0x0000)) return false;
return true;
}
auto CPU::dmaAddressValid(uint24 abus) -> bool {
//A-bus access to 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;
}
auto CPU::dmaRead(uint24 abus) -> uint8 {
if(!dmaAddressValid(abus)) return 0x00;
return bus.read(abus, regs.mdr);
}
//simulate two-stage pipeline for DMA transfers; example:
//cycle 0: read N+0
//cycle 1: write N+0 & read N+1 (parallel; one on A-bus, one on B-bus)
//cycle 2: write N+1 & read N+2 (parallel)
//cycle 3: write N+2
auto CPU::dmaWrite(bool valid, uint addr, uint8 data) -> void {
if(pipe.valid) bus.write(pipe.addr, pipe.data);
pipe.valid = valid;
pipe.addr = addr;
pipe.data = data;
}
auto CPU::dmaTransfer(bool direction, uint8 bbus, uint24 abus) -> void {
if(direction == 0) {
dmaAddClocks(4);
regs.mdr = dmaRead(abus);
dmaAddClocks(4);
dmaWrite(dmaTransferValid(bbus, abus), 0x2100 | bbus, regs.mdr);
} else {
dmaAddClocks(4);
regs.mdr = dmaTransferValid(bbus, abus) ? bus.read(0x2100 | bbus, regs.mdr) : (uint8)0x00;
dmaAddClocks(4);
dmaWrite(dmaAddressValid(abus), abus, regs.mdr);
}
}
//===================
//address calculation
//===================
auto CPU::dmaAddressB(uint n, uint index) -> uint8 {
switch(channel[n].transfer_mode) { default:
case 0: return (channel[n].dest_addr); //0
case 1: return (channel[n].dest_addr + (index & 1)); //0,1
case 2: return (channel[n].dest_addr); //0,0
case 3: return (channel[n].dest_addr + ((index >> 1) & 1)); //0,0,1,1
case 4: return (channel[n].dest_addr + (index & 3)); //0,1,2,3
case 5: return (channel[n].dest_addr + (index & 1)); //0,1,0,1
case 6: return (channel[n].dest_addr); //0,0 [2]
case 7: return (channel[n].dest_addr + ((index >> 1) & 1)); //0,0,1,1 [3]
}
}
inline auto CPU::dmaAddress(uint n) -> uint24 {
uint24 addr = channel[n].source_bank << 16 | channel[n].source_addr;
if(!channel[n].fixed_transfer) {
if(!channel[n].reverse_transfer) {
channel[n].source_addr++;
} else {
channel[n].source_addr--;
}
}
return addr;
}
inline auto CPU::hdmaAddress(uint n) -> uint24 {
return channel[n].source_bank << 16 | channel[n].hdma_addr++;
}
inline auto CPU::hdmaIndirectAddress(uint n) -> uint24 {
return channel[n].indirect_bank << 16 | channel[n].indirect_addr++;
}
//==============
//channel status
//==============
auto CPU::dmaEnabledChannels() -> uint {
uint count = 0;
for(auto n : range(8)) count += channel[n].dma_enabled;
return count;
}
inline auto CPU::hdmaActive(uint n) -> bool {
return channel[n].hdma_enabled && !channel[n].hdma_completed;
}
inline auto CPU::hdmaActiveAfter(uint s) -> bool {
for(uint n = s + 1; n < 8; n++) {
if(hdmaActive(n)) return true;
}
return false;
}
inline auto CPU::hdmaEnabledChannels() -> uint {
uint count = 0;
for(auto n : range(8)) count += channel[n].hdma_enabled;
return count;
}
inline auto CPU::hdmaActiveChannels() -> uint {
uint count = 0;
for(auto n : range(8)) count += hdmaActive(n);
return count;
}
//==============
//core functions
//==============
auto CPU::dmaRun() -> void {
dmaAddClocks(8);
dmaWrite(false);
dmaEdge();
for(auto n : range(8)) {
if(!channel[n].dma_enabled) continue;
uint index = 0;
do {
dmaTransfer(channel[n].direction, dmaAddressB(n, index++), dmaAddress(n));
dmaEdge();
} while(channel[n].dma_enabled && --channel[n].transfer_size);
dmaAddClocks(8);
dmaWrite(false);
dmaEdge();
channel[n].dma_enabled = false;
}
status.irq_lock = true;
}
auto CPU::hdmaUpdate(uint n) -> void {
dmaAddClocks(4);
regs.mdr = dmaRead(channel[n].source_bank << 16 | channel[n].hdma_addr);
dmaAddClocks(4);
dmaWrite(false);
if((channel[n].line_counter & 0x7f) == 0) {
channel[n].line_counter = regs.mdr;
channel[n].hdma_addr++;
channel[n].hdma_completed = channel[n].line_counter == 0;
channel[n].hdma_do_transfer = !channel[n].hdma_completed;
if(channel[n].indirect) {
dmaAddClocks(4);
regs.mdr = dmaRead(hdmaAddress(n));
channel[n].indirect_addr = regs.mdr << 8;
dmaAddClocks(4);
dmaWrite(false);
if(!channel[n].hdma_completed || hdmaActiveAfter(n)) {
dmaAddClocks(4);
regs.mdr = dmaRead(hdmaAddress(n));
channel[n].indirect_addr >>= 8;
channel[n].indirect_addr |= regs.mdr << 8;
dmaAddClocks(4);
dmaWrite(false);
}
}
}
}
auto CPU::hdmaRun() -> void {
dmaAddClocks(8);
dmaWrite(false);
for(auto n : range(8)) {
if(!hdmaActive(n)) continue;
channel[n].dma_enabled = false; //HDMA run during DMA will stop DMA mid-transfer
if(channel[n].hdma_do_transfer) {
static const uint transferLength[8] = {1, 2, 2, 4, 4, 4, 2, 4};
uint length = transferLength[channel[n].transfer_mode];
for(auto index : range(length)) {
uint addr = !channel[n].indirect ? hdmaAddress(n) : hdmaIndirectAddress(n);
dmaTransfer(channel[n].direction, dmaAddressB(n, index), addr);
}
}
}
for(auto n : range(8)) {
if(!hdmaActive(n)) continue;
channel[n].line_counter--;
channel[n].hdma_do_transfer = channel[n].line_counter & 0x80;
hdmaUpdate(n);
}
status.irq_lock = true;
}
auto CPU::hdmaInitReset() -> void {
for(auto n : range(8)) {
channel[n].hdma_completed = false;
channel[n].hdma_do_transfer = false;
}
}
auto CPU::hdmaInit() -> void {
dmaAddClocks(8);
dmaWrite(false);
for(auto n : range(8)) {
if(!channel[n].hdma_enabled) continue;
channel[n].dma_enabled = false; //HDMA init during DMA will stop DMA mid-transfer
channel[n].hdma_addr = channel[n].source_addr;
channel[n].line_counter = 0;
hdmaUpdate(n);
}
status.irq_lock = true;
}

View File

@ -1,285 +0,0 @@
auto CPU::dma_add_clocks(uint clocks) -> void {
status.dma_clocks += clocks;
add_clocks(clocks);
}
//=============
//memory access
//=============
auto CPU::dma_transfer_valid(uint8 bbus, uint32 abus) -> bool {
//transfers from WRAM to WRAM are invalid; chip only has one address bus
if(bbus == 0x80 && ((abus & 0xfe0000) == 0x7e0000 || (abus & 0x40e000) == 0x0000)) return false;
return true;
}
auto CPU::dma_addr_valid(uint32 abus) -> bool {
//A-bus access to 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;
}
auto CPU::dma_read(uint32 abus) -> uint8 {
if(dma_addr_valid(abus) == false) return 0x00;
return bus.read(abus, regs.mdr);
}
//simulate two-stage pipeline for DMA transfers; example:
//cycle 0: read N+0
//cycle 1: write N+0 & read N+1 (parallel; one on A-bus, one on B-bus)
//cycle 2: write N+1 & read N+2 (parallel)
//cycle 3: write N+2
auto CPU::dma_write(bool valid, uint addr, uint8 data) -> void {
if(pipe.valid) bus.write(pipe.addr, pipe.data);
pipe.valid = valid;
pipe.addr = addr;
pipe.data = data;
}
auto CPU::dma_transfer(bool direction, uint8 bbus, uint32 abus) -> void {
if(direction == 0) {
dma_add_clocks(4);
regs.mdr = dma_read(abus);
dma_add_clocks(4);
dma_write(dma_transfer_valid(bbus, abus), 0x2100 | bbus, regs.mdr);
} else {
dma_add_clocks(4);
regs.mdr = dma_transfer_valid(bbus, abus) ? bus.read(0x2100 | bbus, regs.mdr) : (uint8)0x00;
dma_add_clocks(4);
dma_write(dma_addr_valid(abus), abus, regs.mdr);
}
}
//===================
//address calculation
//===================
auto CPU::dma_bbus(uint i, uint index) -> uint8 {
switch(channel[i].transfer_mode) { default:
case 0: return (channel[i].dest_addr); //0
case 1: return (channel[i].dest_addr + (index & 1)); //0,1
case 2: return (channel[i].dest_addr); //0,0
case 3: return (channel[i].dest_addr + ((index >> 1) & 1)); //0,0,1,1
case 4: return (channel[i].dest_addr + (index & 3)); //0,1,2,3
case 5: return (channel[i].dest_addr + (index & 1)); //0,1,0,1
case 6: return (channel[i].dest_addr); //0,0 [2]
case 7: return (channel[i].dest_addr + ((index >> 1) & 1)); //0,0,1,1 [3]
}
}
inline auto CPU::dma_addr(uint i) -> uint32 {
uint32 r = (channel[i].source_bank << 16) | (channel[i].source_addr);
if(channel[i].fixed_transfer == false) {
if(channel[i].reverse_transfer == false) {
channel[i].source_addr++;
} else {
channel[i].source_addr--;
}
}
return r;
}
inline auto CPU::hdma_addr(uint i) -> uint32 {
return (channel[i].source_bank << 16) | (channel[i].hdma_addr++);
}
inline auto CPU::hdma_iaddr(uint i) -> uint32 {
return (channel[i].indirect_bank << 16) | (channel[i].indirect_addr++);
}
//==============
//channel status
//==============
auto CPU::dma_enabled_channels() -> uint8 {
uint8 r = 0;
for(uint i = 0; i < 8; i++) {
if(channel[i].dma_enabled) r++;
}
return r;
}
inline auto CPU::hdma_active(uint i) -> bool {
return (channel[i].hdma_enabled && !channel[i].hdma_completed);
}
inline auto CPU::hdma_active_after(uint i) -> bool {
for(uint n = i + 1; n < 8; n++) {
if(hdma_active(n) == true) return true;
}
return false;
}
inline auto CPU::hdma_enabled_channels() -> uint8 {
uint8 r = 0;
for(uint i = 0; i < 8; i++) {
if(channel[i].hdma_enabled) r++;
}
return r;
}
inline auto CPU::hdma_active_channels() -> uint8 {
uint8 r = 0;
for(uint i = 0; i < 8; i++) {
if(hdma_active(i) == true) r++;
}
return r;
}
//==============
//core functions
//==============
auto CPU::dma_run() -> void {
dma_add_clocks(8);
dma_write(false);
dma_edge();
for(uint i = 0; i < 8; i++) {
if(channel[i].dma_enabled == false) continue;
uint index = 0;
do {
dma_transfer(channel[i].direction, dma_bbus(i, index++), dma_addr(i));
dma_edge();
} while(channel[i].dma_enabled && --channel[i].transfer_size);
dma_add_clocks(8);
dma_write(false);
dma_edge();
channel[i].dma_enabled = false;
}
status.irq_lock = true;
}
auto CPU::hdma_update(uint i) -> void {
dma_add_clocks(4);
regs.mdr = dma_read((channel[i].source_bank << 16) | channel[i].hdma_addr);
dma_add_clocks(4);
dma_write(false);
if((channel[i].line_counter & 0x7f) == 0) {
channel[i].line_counter = regs.mdr;
channel[i].hdma_addr++;
channel[i].hdma_completed = (channel[i].line_counter == 0);
channel[i].hdma_do_transfer = !channel[i].hdma_completed;
if(channel[i].indirect) {
dma_add_clocks(4);
regs.mdr = dma_read(hdma_addr(i));
channel[i].indirect_addr = regs.mdr << 8;
dma_add_clocks(4);
dma_write(false);
if(!channel[i].hdma_completed || hdma_active_after(i)) {
dma_add_clocks(4);
regs.mdr = dma_read(hdma_addr(i));
channel[i].indirect_addr >>= 8;
channel[i].indirect_addr |= regs.mdr << 8;
dma_add_clocks(4);
dma_write(false);
}
}
}
}
auto CPU::hdma_run() -> void {
dma_add_clocks(8);
dma_write(false);
for(uint 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 uint transfer_length[8] = {1, 2, 2, 4, 4, 4, 2, 4};
uint length = transfer_length[channel[i].transfer_mode];
for(uint index = 0; index < length; index++) {
uint addr = channel[i].indirect == false ? hdma_addr(i) : hdma_iaddr(i);
dma_transfer(channel[i].direction, dma_bbus(i, index), addr);
}
}
}
for(uint i = 0; i < 8; i++) {
if(hdma_active(i) == false) continue;
channel[i].line_counter--;
channel[i].hdma_do_transfer = channel[i].line_counter & 0x80;
hdma_update(i);
}
status.irq_lock = true;
}
auto CPU::hdma_init_reset() -> void {
for(uint i = 0; i < 8; i++) {
channel[i].hdma_completed = false;
channel[i].hdma_do_transfer = false;
}
}
auto CPU::hdma_init() -> void {
dma_add_clocks(8);
dma_write(false);
for(uint 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].source_addr;
channel[i].line_counter = 0;
hdma_update(i);
}
status.irq_lock = true;
}
//==============
//initialization
//==============
auto CPU::dma_power() -> void {
for(uint i = 0; i < 8; i++) {
channel[i].direction = 1;
channel[i].indirect = true;
channel[i].unused = true;
channel[i].reverse_transfer = true;
channel[i].fixed_transfer = true;
channel[i].transfer_mode = 7;
channel[i].dest_addr = 0xff;
channel[i].source_addr = 0xffff;
channel[i].source_bank = 0xff;
channel[i].transfer_size = 0xffff;
channel[i].indirect_bank = 0xff;
channel[i].hdma_addr = 0xffff;
channel[i].line_counter = 0xff;
channel[i].unknown = 0xff;
}
}
auto CPU::dma_reset() -> void {
for(uint 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;
}
pipe.valid = false;
pipe.addr = 0;
pipe.data = 0;
}

View File

@ -1,79 +0,0 @@
struct {
//$420b
bool dma_enabled;
//$420c
bool hdma_enabled;
//$43x0
bool direction;
bool indirect;
bool unused;
bool reverse_transfer;
bool fixed_transfer;
uint3 transfer_mode;
//$43x1
uint8 dest_addr;
//$43x2-$43x3
uint16 source_addr;
//$43x4
uint8 source_bank;
//$43x5-$43x6
union {
uint16_t transfer_size;
uint16_t indirect_addr;
};
//$43x7
uint8 indirect_bank;
//$43x8-$43x9
uint16 hdma_addr;
//$43xa
uint8 line_counter;
//$43xb/$43xf
uint8 unknown;
//internal state
bool hdma_completed;
bool hdma_do_transfer;
} channel[8];
struct {
bool valid;
uint addr;
uint8 data;
} pipe;
auto dma_add_clocks(uint clocks) -> void;
auto dma_transfer_valid(uint8 bbus, uint32 abus) -> bool;
auto dma_addr_valid(uint32 abus) -> bool;
auto dma_read(uint32 abus) -> uint8;
auto dma_write(bool valid, uint addr = 0, uint8 data = 0) -> void;
auto dma_transfer(bool direction, uint8 bbus, uint32 abus) -> void;
auto dma_bbus(uint i, uint channel) -> uint8;
auto dma_addr(uint i) -> uint32;
auto hdma_addr(uint i) -> uint32;
auto hdma_iaddr(uint i) -> uint32;
auto dma_enabled_channels() -> uint8;
auto hdma_active(uint i) -> bool;
auto hdma_active_after(uint i) -> bool;
auto hdma_enabled_channels() -> uint8;
auto hdma_active_channels() -> uint8;
auto dma_run() -> void;
auto hdma_update(uint i) -> void;
auto hdma_run() -> void;
auto hdma_init_reset() -> void;
auto hdma_init() -> void;
auto dma_power() -> void;
auto dma_reset() -> void;

View File

@ -3,7 +3,7 @@
//
//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.
auto CPU::poll_interrupts() -> void {
auto CPU::pollInterrupts() -> void {
//NMI hold
if(status.nmi_hold) {
status.nmi_hold = false;
@ -44,7 +44,7 @@ auto CPU::poll_interrupts() -> void {
status.irq_valid = irq_valid;
}
auto CPU::nmitimen_update(uint8 data) -> void {
auto CPU::nmitimenUpdate(uint8 data) -> void {
bool nmi_enabled = status.nmi_enabled;
bool virq_enabled = status.virq_enabled;
bool hirq_enabled = status.hirq_enabled;
@ -87,14 +87,14 @@ auto CPU::timeup() -> bool {
return result;
}
auto CPU::nmi_test() -> bool {
auto CPU::nmiTest() -> bool {
if(!status.nmi_transition) return false;
status.nmi_transition = false;
regs.wai = false;
return true;
}
auto CPU::irq_test() -> bool {
auto CPU::irqTest() -> bool {
if(!status.irq_transition && !regs.irq) return false;
status.irq_transition = false;
regs.wai = false;

View File

@ -1,6 +1,6 @@
//called every 256 clocks; see CPU::add_clocks()
auto CPU::step_auto_joypad_poll() -> void {
if(vcounter() >= (ppu.overscan() == false ? 225 : 240)) {
//called every 256 clocks; see CPU::addClocks()
auto CPU::stepAutoJoypadPoll() -> void {
if(vcounter() >= !ppu.overscan() ? 225 : 240) {
//cache enable state at first iteration
if(status.auto_joypad_counter == 0) status.auto_joypad_latch = status.auto_joypad_poll;
status.auto_joypad_active = status.auto_joypad_counter <= 15;
@ -16,10 +16,10 @@ auto CPU::step_auto_joypad_poll() -> void {
uint2 port0 = device.controllerPort1->data();
uint2 port1 = device.controllerPort2->data();
status.joy1 = (status.joy1 << 1) | (bool)(port0 & 1);
status.joy2 = (status.joy2 << 1) | (bool)(port1 & 1);
status.joy3 = (status.joy3 << 1) | (bool)(port0 & 2);
status.joy4 = (status.joy4 << 1) | (bool)(port1 & 2);
status.joy1 = status.joy1 << 1 | port0.bit(0);
status.joy2 = status.joy2 << 1 | port1.bit(0);
status.joy3 = status.joy3 << 1 | port0.bit(1);
status.joy4 = status.joy4 << 1 | port1.bit(1);
}
status.auto_joypad_counter++;

View File

@ -6,29 +6,29 @@ auto CPU::portWrite(uint2 port, uint8 data) -> void {
status.port[port] = data;
}
auto CPU::op_io() -> void {
auto CPU::io() -> void {
status.clock_count = 6;
dma_edge();
add_clocks(6);
alu_edge();
dmaEdge();
addClocks(6);
aluEdge();
}
auto CPU::op_read(uint24 addr) -> uint8 {
auto CPU::read(uint24 addr) -> uint8 {
status.clock_count = speed(addr);
dma_edge();
add_clocks(status.clock_count - 4);
dmaEdge();
addClocks(status.clock_count - 4);
regs.mdr = bus.read(addr, regs.mdr);
add_clocks(4);
alu_edge();
addClocks(4);
aluEdge();
debugger.op_read(addr, regs.mdr);
return regs.mdr;
}
auto CPU::op_write(uint24 addr, uint8 data) -> void {
alu_edge();
auto CPU::write(uint24 addr, uint8 data) -> void {
aluEdge();
status.clock_count = speed(addr);
dma_edge();
add_clocks(status.clock_count);
dmaEdge();
addClocks(status.clock_count);
bus.write(addr, regs.mdr = data);
debugger.op_write(addr, regs.mdr);
}
@ -43,6 +43,6 @@ auto CPU::speed(uint24 addr) const -> uint {
return 12;
}
auto CPU::disassembler_read(uint24 addr) -> uint8 {
auto CPU::disassemblerRead(uint24 addr) -> uint8 {
return bus.read(addr, regs.mdr);
}

View File

@ -1,6 +0,0 @@
auto op_io() -> void override;
auto op_read(uint24 addr) -> uint8 override;
auto op_write(uint24 addr, uint8 data) -> void override;
alwaysinline auto speed(uint24 addr) const -> uint;
auto disassembler_read(uint24 addr) -> uint8 override;

345
higan/sfc/cpu/mmio.cpp Normal file
View File

@ -0,0 +1,345 @@
auto CPU::apuPortRead(uint24 addr, uint8 data) -> uint8 {
synchronizeSMP();
return smp.portRead(addr.bits(0,1));
}
auto CPU::cpuPortRead(uint24 addr, uint8 data) -> uint8 {
addr &= 0xffff;
//WMDATA
if(addr == 0x2180) {
return bus.read(0x7e0000 | status.wram_addr++, regs.mdr);
}
//JOYSER0
//7-2 = MDR
//1-0 = Joypad serial data
if(addr == 0x4016) {
uint8 r = regs.mdr & 0xfc;
r |= device.controllerPort1->data();
return r;
}
//JOYSER1
if(addr == 0x4017) {
//7-5 = MDR
//4-2 = Always 1 (pins are connected to GND)
//1-0 = Joypad serial data
uint8 r = (regs.mdr & 0xe0) | 0x1c;
r |= device.controllerPort2->data();
return r;
}
//RDNMI
if(addr == 0x4210) {
//7 = NMI acknowledge
//6-4 = MDR
//3-0 = CPU (5a22) version
uint8 r = (regs.mdr & 0x70);
r |= (uint8)(rdnmi()) << 7;
r |= (cpu_version & 0x0f);
return r;
}
//TIMEUP
if(addr == 0x4211) {
//7 = IRQ acknowledge
//6-0 = MDR
uint8 r = (regs.mdr & 0x7f);
r |= (uint8)(timeup()) << 7;
return r;
}
//HVBJOY
if(addr == 0x4212) {
//7 = VBLANK acknowledge
//6 = HBLANK acknowledge
//5-1 = MDR
//0 = JOYPAD acknowledge
uint8 r = (regs.mdr & 0x3e);
if(status.auto_joypad_active) r |= 0x01;
if(hcounter() <= 2 || hcounter() >= 1096) r |= 0x40; //hblank
if(vcounter() >= (ppu.overscan() == false ? 225 : 240)) r |= 0x80; //vblank
return r;
}
//RDIO
if(addr == 0x4213) {
return status.pio;
}
//RDDIVL
if(addr == 0x4214) {
return status.rddiv.byte(0);
}
//RDDIVH
if(addr == 0x4215) {
return status.rddiv.byte(1);
}
//RDMPYL
if(addr == 0x4216) {
return status.rdmpy.byte(0);
}
//RDMPYH
if(addr == 0x4217) {
return status.rdmpy.byte(1);
}
if(addr == 0x4218) return status.joy1.byte(0); //JOY1L
if(addr == 0x4219) return status.joy1.byte(1); //JOY1H
if(addr == 0x421a) return status.joy2.byte(0); //JOY2L
if(addr == 0x421b) return status.joy2.byte(1); //JOY2H
if(addr == 0x421c) return status.joy3.byte(0); //JOY3L
if(addr == 0x421d) return status.joy3.byte(1); //JOY3H
if(addr == 0x421e) return status.joy4.byte(0); //JOY4L
if(addr == 0x421f) return status.joy4.byte(1); //JOY4H
return data;
}
auto CPU::dmaPortRead(uint24 addr, uint8 data) -> uint8 {
auto& channel = this->channel[addr.bits(4,6)];
addr &= 0xff0f;
//DMAPx
if(addr == 0x4300) return (
channel.direction << 7
| channel.indirect << 6
| channel.unused << 5
| channel.reverse_transfer << 4
| channel.fixed_transfer << 3
| channel.transfer_mode << 0
);
//BBADx
if(addr == 0x4301) return channel.dest_addr;
//A1TxL
if(addr == 0x4302) return channel.source_addr >> 0;
//A1TxH
if(addr == 0x4303) return channel.source_addr >> 8;
//A1Bx
if(addr == 0x4304) return channel.source_bank;
//DASxL -- union { uint16 transfer_size; uint16 indirect_addr; };
if(addr == 0x4305) return channel.transfer_size >> 0;
//DASxH -- union { uint16 transfer_size; uint16 indirect_addr; };
if(addr == 0x4306) return channel.transfer_size >> 8;
//DASBx
if(addr == 0x4307) return channel.indirect_bank;
//A2AxL
if(addr == 0x4308) return channel.hdma_addr >> 0;
//A2AxH
if(addr == 0x4309) return channel.hdma_addr >> 8;
//NTRLx
if(addr == 0x430a) return channel.line_counter;
//???
if(addr == 0x430b || addr == 0x430f) return channel.unknown;
return data;
}
auto CPU::apuPortWrite(uint24 addr, uint8 data) -> void {
synchronizeSMP();
return portWrite(addr.bits(0,1), data);
}
auto CPU::cpuPortWrite(uint24 addr, uint8 data) -> void {
addr &= 0xffff;
//WMDATA
if(addr == 0x2180) {
bus.write(0x7e0000 | status.wram_addr++, data);
}
//WMADDL
if(addr == 0x2181) {
status.wram_addr.bits(0,7) = data;
}
//WMADDM
if(addr == 0x2182) {
status.wram_addr.bits(8,15) = data;
}
//WMADDH
if(addr == 0x2183) {
status.wram_addr.bit(16) = data.bit(0);
}
//JOYSER0
if(addr == 0x4016) {
//bit 0 is shared between JOYSER0 and JOYSER1, therefore
//strobing $4016.d0 affects both controller port latches.
//$4017 bit 0 writes are ignored.
device.controllerPort1->latch(data.bit(0));
device.controllerPort2->latch(data.bit(0));
}
//NMITIMEN
if(addr == 0x4200) {
status.auto_joypad_poll = data.bit(0);
nmitimenUpdate(data);
}
//WRIO
if(addr == 0x4201) {
if(status.pio.bit(7) && !data.bit(7)) ppu.latch_counters();
status.pio = data;
}
//WRMPYA
if(addr == 0x4202) {
status.wrmpya = data;
}
//WRMPYB
if(addr == 0x4203) {
status.rdmpy = 0;
if(alu.mpyctr || alu.divctr) return;
status.wrmpyb = data;
status.rddiv = (status.wrmpyb << 8) | status.wrmpya;
alu.mpyctr = 8; //perform multiplication over the next eight cycles
alu.shift = status.wrmpyb;
}
//WRDIVL
if(addr == 0x4204) {
status.wrdiva.byte(0) = data;
}
//WRDIVH
if(addr == 0x4205) {
status.wrdiva.byte(1) = data;
}
//WRDIVB
if(addr == 0x4206) {
status.rdmpy = status.wrdiva;
if(alu.mpyctr || alu.divctr) return;
status.wrdivb = data;
alu.divctr = 16; //perform division over the next sixteen cycles
alu.shift = status.wrdivb << 16;
}
//HTIMEL
if(addr == 0x4207) {
status.hirq_pos.bits(0,7) = data;
}
//HTIMEH
if(addr == 0x4208) {
status.hirq_pos.bit(8) = data.bit(0);
}
//VTIMEL
if(addr == 0x4209) {
status.virq_pos.bits(0,7) = data;
}
//VTIMEH
if(addr == 0x420a) {
status.virq_pos.bit(8) = data;
}
//DMAEN
if(addr == 0x420b) {
for(auto n : range(8)) channel[n].dma_enabled = data.bit(n);
if(data) status.dma_pending = true;
}
//HDMAEN
if(addr == 0x420c) {
for(auto n : range(8)) channel[n].hdma_enabled = data.bit(n);
}
//MEMSEL
if(addr == 0x420d) {
status.rom_speed = data.bit(0) ? 6 : 8;
}
}
auto CPU::dmaPortWrite(uint24 addr, uint8 data) -> void {
auto& channel = this->channel[addr.bits(4,6)];
addr &= 0xff0f;
//DMAPx
if(addr == 0x4300) {
channel.direction = data & 0x80;
channel.indirect = data & 0x40;
channel.unused = data & 0x20;
channel.reverse_transfer = data & 0x10;
channel.fixed_transfer = data & 0x08;
channel.transfer_mode = data & 0x07;
}
//DDBADx
if(addr == 0x4301) {
channel.dest_addr = data;
}
//A1TxL
if(addr == 0x4302) {
channel.source_addr = (channel.source_addr & 0xff00) | (data << 0);
}
//A1TxH
if(addr == 0x4303) {
channel.source_addr = (channel.source_addr & 0x00ff) | (data << 8);
}
//A1Bx
if(addr == 0x4304) {
channel.source_bank = data;
}
//DASxL -- union { uint16 transfer_size; uint16 indirect_addr; };
if(addr == 0x4305) {
channel.transfer_size = (channel.transfer_size & 0xff00) | (data << 0);
}
//DASxH -- union { uint16 transfer_size; uint16 indirect_addr; };
if(addr == 0x4306) {
channel.transfer_size = (channel.transfer_size & 0x00ff) | (data << 8);
}
//DASBx
if(addr == 0x4307) {
channel.indirect_bank = data;
}
//A2AxL
if(addr == 0x4308) {
channel.hdma_addr = (channel.hdma_addr & 0xff00) | (data << 0);
}
//A2AxH
if(addr == 0x4309) {
channel.hdma_addr = (channel.hdma_addr & 0x00ff) | (data << 8);
}
//NTRLx
if(addr == 0x430a) {
channel.line_counter = data;
}
//???
if(addr == 0x430b || addr == 0x430f) {
channel.unknown = data;
}
}

View File

@ -1,520 +0,0 @@
auto CPU::pio() -> uint8 {
return status.pio;
}
auto CPU::joylatch() -> bool {
return status.joypad_strobe_latch;
}
//WMDATA
auto CPU::mmio_r2180() -> uint8 {
return bus.read(0x7e0000 | status.wram_addr++, regs.mdr);
}
//WMDATA
auto CPU::mmio_w2180(uint8 data) -> void {
bus.write(0x7e0000 | status.wram_addr++, data);
}
//WMADDL
auto CPU::mmio_w2181(uint8 data) -> void {
status.wram_addr = (status.wram_addr & 0x01ff00) | (data << 0);
}
//WMADDM
auto CPU::mmio_w2182(uint8 data) -> void {
status.wram_addr = (status.wram_addr & 0x0100ff) | (data << 8);
}
//WMADDH
auto CPU::mmio_w2183(uint8 data) -> void {
status.wram_addr = (status.wram_addr & 0x00ffff) | (data << 16);
}
//JOYSER0
//bit 0 is shared between JOYSER0 and JOYSER1, therefore
//strobing $4016.d0 affects both controller port latches.
//$4017 bit 0 writes are ignored.
auto CPU::mmio_w4016(uint8 data) -> void {
device.controllerPort1->latch(data & 1);
device.controllerPort2->latch(data & 1);
}
//JOYSER0
//7-2 = MDR
//1-0 = Joypad serial data
auto CPU::mmio_r4016() -> uint8 {
uint8 r = regs.mdr & 0xfc;
r |= device.controllerPort1->data();
return r;
}
//JOYSER1
//7-5 = MDR
//4-2 = Always 1 (pins are connected to GND)
//1-0 = Joypad serial data
auto CPU::mmio_r4017() -> uint8 {
uint8 r = (regs.mdr & 0xe0) | 0x1c;
r |= device.controllerPort2->data();
return r;
}
//NMITIMEN
auto CPU::mmio_w4200(uint8 data) -> void {
status.auto_joypad_poll = data & 1;
nmitimen_update(data);
}
//WRIO
auto CPU::mmio_w4201(uint8 data) -> void {
if((status.pio & 0x80) && !(data & 0x80)) ppu.latch_counters();
status.pio = data;
}
//WRMPYA
auto CPU::mmio_w4202(uint8 data) -> void {
status.wrmpya = data;
}
//WRMPYB
auto CPU::mmio_w4203(uint8 data) -> void {
status.rdmpy = 0;
if(alu.mpyctr || alu.divctr) return;
status.wrmpyb = data;
status.rddiv = (status.wrmpyb << 8) | status.wrmpya;
alu.mpyctr = 8; //perform multiplication over the next eight cycles
alu.shift = status.wrmpyb;
}
//WRDIVL
auto CPU::mmio_w4204(uint8 data) -> void {
status.wrdiva = (status.wrdiva & 0xff00) | (data << 0);
}
//WRDIVH
auto CPU::mmio_w4205(uint8 data) -> void {
status.wrdiva = (status.wrdiva & 0x00ff) | (data << 8);
}
//WRDIVB
auto CPU::mmio_w4206(uint8 data) -> void {
status.rdmpy = status.wrdiva;
if(alu.mpyctr || alu.divctr) return;
status.wrdivb = data;
alu.divctr = 16; //perform division over the next sixteen cycles
alu.shift = status.wrdivb << 16;
}
//HTIMEL
auto CPU::mmio_w4207(uint8 data) -> void {
status.hirq_pos = (status.hirq_pos & 0x0100) | (data << 0);
}
//HTIMEH
auto CPU::mmio_w4208(uint8 data) -> void {
status.hirq_pos = (status.hirq_pos & 0x00ff) | (data << 8);
}
//VTIMEL
auto CPU::mmio_w4209(uint8 data) -> void {
status.virq_pos = (status.virq_pos & 0x0100) | (data << 0);
}
//VTIMEH
auto CPU::mmio_w420a(uint8 data) -> void {
status.virq_pos = (status.virq_pos & 0x00ff) | (data << 8);
}
//DMAEN
auto CPU::mmio_w420b(uint8 data) -> void {
for(unsigned i = 0; i < 8; i++) {
channel[i].dma_enabled = data & (1 << i);
}
if(data) status.dma_pending = true;
}
//HDMAEN
auto CPU::mmio_w420c(uint8 data) -> void {
for(unsigned i = 0; i < 8; i++) {
channel[i].hdma_enabled = data & (1 << i);
}
}
//MEMSEL
auto CPU::mmio_w420d(uint8 data) -> void {
status.rom_speed = (data & 1 ? 6 : 8);
}
//RDNMI
//7 = NMI acknowledge
//6-4 = MDR
//3-0 = CPU (5a22) version
auto CPU::mmio_r4210() -> uint8 {
uint8 r = (regs.mdr & 0x70);
r |= (uint8)(rdnmi()) << 7;
r |= (cpu_version & 0x0f);
return r;
}
//TIMEUP
//7 = IRQ acknowledge
//6-0 = MDR
auto CPU::mmio_r4211() -> uint8 {
uint8 r = (regs.mdr & 0x7f);
r |= (uint8)(timeup()) << 7;
return r;
}
//HVBJOY
//7 = VBLANK acknowledge
//6 = HBLANK acknowledge
//5-1 = MDR
//0 = JOYPAD acknowledge
auto CPU::mmio_r4212() -> uint8 {
uint8 r = (regs.mdr & 0x3e);
if(status.auto_joypad_active) r |= 0x01;
if(hcounter() <= 2 || hcounter() >= 1096) r |= 0x40; //hblank
if(vcounter() >= (ppu.overscan() == false ? 225 : 240)) r |= 0x80; //vblank
return r;
}
//RDIO
auto CPU::mmio_r4213() -> uint8 {
return status.pio;
}
//RDDIVL
auto CPU::mmio_r4214() -> uint8 {
return status.rddiv >> 0;
}
//RDDIVH
auto CPU::mmio_r4215() -> uint8 {
return status.rddiv >> 8;
}
//RDMPYL
auto CPU::mmio_r4216() -> uint8 {
return status.rdmpy >> 0;
}
//RDMPYH
auto CPU::mmio_r4217() -> uint8 {
return status.rdmpy >> 8;
}
auto CPU::mmio_r4218() -> uint8 { return status.joy1 >> 0; } //JOY1L
auto CPU::mmio_r4219() -> uint8 { return status.joy1 >> 8; } //JOY1H
auto CPU::mmio_r421a() -> uint8 { return status.joy2 >> 0; } //JOY2L
auto CPU::mmio_r421b() -> uint8 { return status.joy2 >> 8; } //JOY2H
auto CPU::mmio_r421c() -> uint8 { return status.joy3 >> 0; } //JOY3L
auto CPU::mmio_r421d() -> uint8 { return status.joy3 >> 8; } //JOY3H
auto CPU::mmio_r421e() -> uint8 { return status.joy4 >> 0; } //JOY4L
auto CPU::mmio_r421f() -> uint8 { return status.joy4 >> 8; } //JOY4H
//DMAPx
auto CPU::mmio_r43x0(uint8 i) -> uint8 {
return (channel[i].direction << 7)
| (channel[i].indirect << 6)
| (channel[i].unused << 5)
| (channel[i].reverse_transfer << 4)
| (channel[i].fixed_transfer << 3)
| (channel[i].transfer_mode << 0);
}
//BBADx
auto CPU::mmio_r43x1(uint8 i) -> uint8 {
return channel[i].dest_addr;
}
//A1TxL
auto CPU::mmio_r43x2(uint8 i) -> uint8 {
return channel[i].source_addr >> 0;
}
//A1TxH
auto CPU::mmio_r43x3(uint8 i) -> uint8 {
return channel[i].source_addr >> 8;
}
//A1Bx
auto CPU::mmio_r43x4(uint8 i) -> uint8 {
return channel[i].source_bank;
}
//DASxL
//union { uint16 transfer_size; uint16 indirect_addr; };
auto CPU::mmio_r43x5(uint8 i) -> uint8 {
return channel[i].transfer_size >> 0;
}
//DASxH
//union { uint16 transfer_size; uint16 indirect_addr; };
auto CPU::mmio_r43x6(uint8 i) -> uint8 {
return channel[i].transfer_size >> 8;
}
//DASBx
auto CPU::mmio_r43x7(uint8 i) -> uint8 {
return channel[i].indirect_bank;
}
//A2AxL
auto CPU::mmio_r43x8(uint8 i) -> uint8 {
return channel[i].hdma_addr >> 0;
}
//A2AxH
auto CPU::mmio_r43x9(uint8 i) -> uint8 {
return channel[i].hdma_addr >> 8;
}
//NTRLx
auto CPU::mmio_r43xa(uint8 i) -> uint8 {
return channel[i].line_counter;
}
//???
auto CPU::mmio_r43xb(uint8 i) -> uint8 {
return channel[i].unknown;
}
//DMAPx
auto CPU::mmio_w43x0(uint8 i, uint8 data) -> void {
channel[i].direction = data & 0x80;
channel[i].indirect = data & 0x40;
channel[i].unused = data & 0x20;
channel[i].reverse_transfer = data & 0x10;
channel[i].fixed_transfer = data & 0x08;
channel[i].transfer_mode = data & 0x07;
}
//DDBADx
auto CPU::mmio_w43x1(uint8 i, uint8 data) -> void {
channel[i].dest_addr = data;
}
//A1TxL
auto CPU::mmio_w43x2(uint8 i, uint8 data) -> void {
channel[i].source_addr = (channel[i].source_addr & 0xff00) | (data << 0);
}
//A1TxH
auto CPU::mmio_w43x3(uint8 i, uint8 data) -> void {
channel[i].source_addr = (channel[i].source_addr & 0x00ff) | (data << 8);
}
//A1Bx
auto CPU::mmio_w43x4(uint8 i, uint8 data) -> void {
channel[i].source_bank = data;
}
//DASxL
//union { uint16 transfer_size; uint16 indirect_addr; };
auto CPU::mmio_w43x5(uint8 i, uint8 data) -> void {
channel[i].transfer_size = (channel[i].transfer_size & 0xff00) | (data << 0);
}
//DASxH
//union { uint16 transfer_size; uint16 indirect_addr; };
auto CPU::mmio_w43x6(uint8 i, uint8 data) -> void {
channel[i].transfer_size = (channel[i].transfer_size & 0x00ff) | (data << 8);
}
//DASBx
auto CPU::mmio_w43x7(uint8 i, uint8 data) -> void {
channel[i].indirect_bank = data;
}
//A2AxL
auto CPU::mmio_w43x8(uint8 i, uint8 data) -> void {
channel[i].hdma_addr = (channel[i].hdma_addr & 0xff00) | (data << 0);
}
//A2AxH
auto CPU::mmio_w43x9(uint8 i, uint8 data) -> void {
channel[i].hdma_addr = (channel[i].hdma_addr & 0x00ff) | (data << 8);
}
//NTRLx
auto CPU::mmio_w43xa(uint8 i, uint8 data) -> void {
channel[i].line_counter = data;
}
//???
auto CPU::mmio_w43xb(uint8 i, uint8 data) -> void {
channel[i].unknown = data;
}
auto CPU::mmio_power() -> void {
}
auto CPU::mmio_reset() -> void {
//$2140-217f
for(auto& port : status.port) port = 0x00;
//$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.wrmpya = 0xff;
status.wrmpyb = 0xff;
//$4204-$4206
status.wrdiva = 0xffff;
status.wrdivb = 0xff;
//$4207-$420a
status.hirq_pos = 0x01ff;
status.virq_pos = 0x01ff;
//$420d
status.rom_speed = 8;
//$4214-$4217
status.rddiv = 0x0000;
status.rdmpy = 0x0000;
//$4218-$421f
status.joy1 = 0x0000;
status.joy2 = 0x0000;
status.joy3 = 0x0000;
status.joy4 = 0x0000;
//ALU
alu.mpyctr = 0;
alu.divctr = 0;
alu.shift = 0;
}
auto CPU::mmio_read(uint addr, uint8 data) -> uint8 {
addr &= 0xffff;
//APU
if((addr & 0xffc0) == 0x2140) { //$2140-$217f
synchronizeSMP();
return smp.portRead(addr);
}
//DMA
if((addr & 0xff80) == 0x4300) { //$4300-$437f
uint i = (addr >> 4) & 7;
switch(addr & 0xf) {
case 0x0: return mmio_r43x0(i);
case 0x1: return mmio_r43x1(i);
case 0x2: return mmio_r43x2(i);
case 0x3: return mmio_r43x3(i);
case 0x4: return mmio_r43x4(i);
case 0x5: return mmio_r43x5(i);
case 0x6: return mmio_r43x6(i);
case 0x7: return mmio_r43x7(i);
case 0x8: return mmio_r43x8(i);
case 0x9: return mmio_r43x9(i);
case 0xa: return mmio_r43xa(i);
case 0xb: return mmio_r43xb(i);
case 0xc: return regs.mdr; //unmapped
case 0xd: return regs.mdr; //unmapped
case 0xe: return regs.mdr; //unmapped
case 0xf: return mmio_r43xb(i); //mirror of $43xb
}
}
switch(addr) {
case 0x2180: return mmio_r2180();
case 0x4016: return mmio_r4016();
case 0x4017: return mmio_r4017();
case 0x4210: return mmio_r4210();
case 0x4211: return mmio_r4211();
case 0x4212: return mmio_r4212();
case 0x4213: return mmio_r4213();
case 0x4214: return mmio_r4214();
case 0x4215: return mmio_r4215();
case 0x4216: return mmio_r4216();
case 0x4217: return mmio_r4217();
case 0x4218: return mmio_r4218();
case 0x4219: return mmio_r4219();
case 0x421a: return mmio_r421a();
case 0x421b: return mmio_r421b();
case 0x421c: return mmio_r421c();
case 0x421d: return mmio_r421d();
case 0x421e: return mmio_r421e();
case 0x421f: return mmio_r421f();
}
return data;
}
auto CPU::mmio_write(uint addr, uint8 data) -> void {
addr &= 0xffff;
//APU
if((addr & 0xffc0) == 0x2140) { //$2140-$217f
synchronizeSMP();
portWrite(addr, data);
return;
}
//DMA
if((addr & 0xff80) == 0x4300) { //$4300-$437f
uint i = (addr >> 4) & 7;
switch(addr & 0xf) {
case 0x0: mmio_w43x0(i, data); return;
case 0x1: mmio_w43x1(i, data); return;
case 0x2: mmio_w43x2(i, data); return;
case 0x3: mmio_w43x3(i, data); return;
case 0x4: mmio_w43x4(i, data); return;
case 0x5: mmio_w43x5(i, data); return;
case 0x6: mmio_w43x6(i, data); return;
case 0x7: mmio_w43x7(i, data); return;
case 0x8: mmio_w43x8(i, data); return;
case 0x9: mmio_w43x9(i, data); return;
case 0xa: mmio_w43xa(i, data); return;
case 0xb: mmio_w43xb(i, data); return;
case 0xc: return; //unmapped
case 0xd: return; //unmapped
case 0xe: return; //unmapped
case 0xf: mmio_w43xb(i, data); return; //mirror of $43xb
}
}
switch(addr) {
case 0x2180: mmio_w2180(data); return;
case 0x2181: mmio_w2181(data); return;
case 0x2182: mmio_w2182(data); return;
case 0x2183: mmio_w2183(data); return;
case 0x4016: mmio_w4016(data); return;
case 0x4017: return; //unmapped
case 0x4200: mmio_w4200(data); return;
case 0x4201: mmio_w4201(data); return;
case 0x4202: mmio_w4202(data); return;
case 0x4203: mmio_w4203(data); return;
case 0x4204: mmio_w4204(data); return;
case 0x4205: mmio_w4205(data); return;
case 0x4206: mmio_w4206(data); return;
case 0x4207: mmio_w4207(data); return;
case 0x4208: mmio_w4208(data); return;
case 0x4209: mmio_w4209(data); return;
case 0x420a: mmio_w420a(data); return;
case 0x420b: mmio_w420b(data); return;
case 0x420c: mmio_w420c(data); return;
case 0x420d: mmio_w420d(data); return;
}
}

View File

@ -1,71 +0,0 @@
public:
auto mmio_read(uint addr, uint8 data) -> uint8;
auto mmio_write(uint addr, uint8 data) -> void;
privileged:
auto mmio_power() -> void;
auto mmio_reset() -> void;
auto mmio_r2180() -> uint8;
auto mmio_r4016() -> uint8;
auto mmio_r4017() -> uint8;
auto mmio_r4210() -> uint8;
auto mmio_r4211() -> uint8;
auto mmio_r4212() -> uint8;
auto mmio_r4213() -> uint8;
auto mmio_r4214() -> uint8;
auto mmio_r4215() -> uint8;
auto mmio_r4216() -> uint8;
auto mmio_r4217() -> uint8;
auto mmio_r4218() -> uint8;
auto mmio_r4219() -> uint8;
auto mmio_r421a() -> uint8;
auto mmio_r421b() -> uint8;
auto mmio_r421c() -> uint8;
auto mmio_r421d() -> uint8;
auto mmio_r421e() -> uint8;
auto mmio_r421f() -> uint8;
auto mmio_r43x0(uint8 i) -> uint8;
auto mmio_r43x1(uint8 i) -> uint8;
auto mmio_r43x2(uint8 i) -> uint8;
auto mmio_r43x3(uint8 i) -> uint8;
auto mmio_r43x4(uint8 i) -> uint8;
auto mmio_r43x5(uint8 i) -> uint8;
auto mmio_r43x6(uint8 i) -> uint8;
auto mmio_r43x7(uint8 i) -> uint8;
auto mmio_r43x8(uint8 i) -> uint8;
auto mmio_r43x9(uint8 i) -> uint8;
auto mmio_r43xa(uint8 i) -> uint8;
auto mmio_r43xb(uint8 i) -> uint8;
auto mmio_w2180(uint8 data) -> void;
auto mmio_w2181(uint8 data) -> void;
auto mmio_w2182(uint8 data) -> void;
auto mmio_w2183(uint8 data) -> void;
auto mmio_w4016(uint8 data) -> void;
auto mmio_w4200(uint8 data) -> void;
auto mmio_w4201(uint8 data) -> void;
auto mmio_w4202(uint8 data) -> void;
auto mmio_w4203(uint8 data) -> void;
auto mmio_w4204(uint8 data) -> void;
auto mmio_w4205(uint8 data) -> void;
auto mmio_w4206(uint8 data) -> void;
auto mmio_w4207(uint8 data) -> void;
auto mmio_w4208(uint8 data) -> void;
auto mmio_w4209(uint8 data) -> void;
auto mmio_w420a(uint8 data) -> void;
auto mmio_w420b(uint8 data) -> void;
auto mmio_w420c(uint8 data) -> void;
auto mmio_w420d(uint8 data) -> void;
auto mmio_w43x0(uint8 i, uint8 data) -> void;
auto mmio_w43x1(uint8 i, uint8 data) -> void;
auto mmio_w43x2(uint8 i, uint8 data) -> void;
auto mmio_w43x3(uint8 i, uint8 data) -> void;
auto mmio_w43x4(uint8 i, uint8 data) -> void;
auto mmio_w43x5(uint8 i, uint8 data) -> void;
auto mmio_w43x6(uint8 i, uint8 data) -> void;
auto mmio_w43x7(uint8 i, uint8 data) -> void;
auto mmio_w43x8(uint8 i, uint8 data) -> void;
auto mmio_w43x9(uint8 i, uint8 data) -> void;
auto mmio_w43xa(uint8 i, uint8 data) -> void;
auto mmio_w43xb(uint8 i, uint8 data) -> void;

View File

@ -1,16 +1,13 @@
#include "irq.cpp"
#include "joypad.cpp"
auto CPU::dma_counter() -> uint {
auto CPU::dmaCounter() const -> uint {
return (status.dma_counter + hcounter()) & 7;
}
auto CPU::add_clocks(uint clocks) -> void {
auto CPU::addClocks(uint clocks) -> void {
status.irq_lock = false;
uint ticks = clocks >> 1;
while(ticks--) {
tick();
if(hcounter() & 2) poll_interrupts();
if(hcounter() & 2) pollInterrupts();
}
step(clocks);
@ -18,12 +15,12 @@ auto CPU::add_clocks(uint clocks) -> void {
status.auto_joypad_clock += clocks;
if(status.auto_joypad_clock >= 256) {
status.auto_joypad_clock -= 256;
step_auto_joypad_poll();
stepAutoJoypadPoll();
}
if(status.dram_refreshed == false && hcounter() >= status.dram_refresh_position) {
if(!status.dram_refreshed && hcounter() >= status.dram_refresh_position) {
status.dram_refreshed = true;
add_clocks(40);
addClocks(40);
}
#if defined(DEBUGGER)
@ -45,14 +42,14 @@ auto CPU::scanline() -> void {
if(vcounter() == 0) {
//HDMA init triggers once every frame
status.hdma_init_position = (cpu_version == 1 ? 12 + 8 - dma_counter() : 12 + dma_counter());
status.hdma_init_position = (cpu_version == 1 ? 12 + 8 - dmaCounter() : 12 + dmaCounter());
status.hdma_init_triggered = false;
status.auto_joypad_counter = 0;
}
//DRAM refresh occurs once every scanline
if(cpu_version == 2) status.dram_refresh_position = 530 + 8 - dma_counter();
if(cpu_version == 2) status.dram_refresh_position = 530 + 8 - dmaCounter();
status.dram_refreshed = false;
//HDMA triggers once every visible scanline
@ -62,7 +59,7 @@ auto CPU::scanline() -> void {
}
}
auto CPU::alu_edge() -> void {
auto CPU::aluEdge() -> void {
if(alu.mpyctr) {
alu.mpyctr--;
if(status.rddiv & 1) status.rdmpy += alu.shift;
@ -81,7 +78,7 @@ auto CPU::alu_edge() -> void {
}
}
auto CPU::dma_edge() -> void {
auto CPU::dmaEdge() -> void {
//H/DMA pending && DMA inactive?
//.. Run one full CPU cycle
//.. HDMA pending && HDMA enabled ? DMA sync + HDMA run
@ -93,13 +90,13 @@ auto CPU::dma_edge() -> void {
if(status.dma_active == true) {
if(status.hdma_pending) {
status.hdma_pending = false;
if(hdma_enabled_channels()) {
if(!dma_enabled_channels()) {
dma_add_clocks(8 - dma_counter());
if(hdmaEnabledChannels()) {
if(!dmaEnabledChannels()) {
dmaAddClocks(8 - dmaCounter());
}
status.hdma_mode == 0 ? hdma_init() : hdma_run();
if(!dma_enabled_channels()) {
add_clocks(status.clock_count - (status.dma_clocks % status.clock_count));
status.hdma_mode == 0 ? hdmaInit() : hdmaRun();
if(!dmaEnabledChannels()) {
addClocks(status.clock_count - (status.dma_clocks % status.clock_count));
status.dma_active = false;
}
}
@ -107,10 +104,10 @@ auto CPU::dma_edge() -> void {
if(status.dma_pending) {
status.dma_pending = false;
if(dma_enabled_channels()) {
dma_add_clocks(8 - dma_counter());
dma_run();
add_clocks(status.clock_count - (status.dma_clocks % status.clock_count));
if(dmaEnabledChannels()) {
dmaAddClocks(8 - dmaCounter());
dmaRun();
addClocks(status.clock_count - (status.dma_clocks % status.clock_count));
status.dma_active = false;
}
}
@ -118,8 +115,8 @@ auto CPU::dma_edge() -> void {
if(status.hdma_init_triggered == false && hcounter() >= status.hdma_init_position) {
status.hdma_init_triggered = true;
hdma_init_reset();
if(hdma_enabled_channels()) {
hdmaInitReset();
if(hdmaEnabledChannels()) {
status.hdma_pending = true;
status.hdma_mode = 0;
}
@ -127,7 +124,7 @@ auto CPU::dma_edge() -> void {
if(status.hdma_triggered == false && hcounter() >= status.hdma_position) {
status.hdma_triggered = true;
if(hdma_active_channels()) {
if(hdmaActiveChannels()) {
status.hdma_pending = true;
status.hdma_mode = 1;
}
@ -146,55 +143,10 @@ auto CPU::dma_edge() -> void {
//
//status.irq_lock is used to simulate hardware delay before interrupts can
//trigger during certain events (immediately after DMA, writes to $4200, etc)
auto CPU::last_cycle() -> void {
if(status.irq_lock == false) {
status.nmi_pending |= nmi_test();
status.irq_pending |= irq_test();
auto CPU::lastCycle() -> void {
if(!status.irq_lock) {
status.nmi_pending |= nmiTest();
status.irq_pending |= irqTest();
status.interrupt_pending = (status.nmi_pending || status.irq_pending);
}
}
auto CPU::timing_power() -> void {
}
auto CPU::timing_reset() -> void {
status.clock_count = 0;
status.line_clocks = lineclocks();
status.irq_lock = false;
status.dram_refresh_position = (cpu_version == 1 ? 530 : 538);
status.dram_refreshed = false;
status.hdma_init_position = (cpu_version == 1 ? 12 + 8 - dma_counter() : 12 + dma_counter());
status.hdma_init_triggered = false;
status.hdma_position = 1104;
status.hdma_triggered = false;
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.reset_pending = true;
status.interrupt_pending = true;
status.dma_active = false;
status.dma_counter = 0;
status.dma_clocks = 0;
status.dma_pending = false;
status.hdma_pending = false;
status.hdma_mode = 0;
status.auto_joypad_active = false;
status.auto_joypad_latch = false;
status.auto_joypad_counter = 0;
status.auto_joypad_clock = 0;
}

View File

@ -1,24 +0,0 @@
//timing.cpp
auto dma_counter() -> uint;
auto add_clocks(uint clocks) -> void;
auto scanline() -> void;
alwaysinline auto alu_edge() -> void;
alwaysinline auto dma_edge() -> void;
alwaysinline auto last_cycle() -> void;
auto timing_power() -> void;
auto timing_reset() -> void;
//irq.cpp
alwaysinline auto poll_interrupts() -> void;
auto nmitimen_update(uint8 data) -> void;
auto rdnmi() -> bool;
auto timeup() -> bool;
alwaysinline auto nmi_test() -> bool;
alwaysinline auto irq_test() -> bool;
//joypad.cpp
auto step_auto_joypad_poll() -> void;

View File

@ -1,4 +1,6 @@
auto APU::serialize(serializer& s) -> void {
Thread::serialize(s);
s.integer(this->s.sweepClock);
s.integer(r.waveBase);
s.integer(r.speakerEnable);

View File

@ -31,6 +31,9 @@ auto Cartridge::power() -> void {
bus.map(this, 0x00c0, 0x00c8);
if(rtc.data) bus.map(this, 0x00ca, 0x00cb);
bus.map(this, 0x00cc, 0x00cd);
memory::fill(&r, sizeof(Registers));
r.romBank0 = 0xff;
r.romBank1 = 0xff;
@ -50,8 +53,11 @@ auto Cartridge::load() -> void {
rom.name = node["name"].text();
rom.size = node["size"].natural();
rom.mask = bit::round(rom.size) - 1;
if(rom.size) rom.data = new uint8[rom.mask + 1]();
if(rom.name) interface->loadRequest(ID::ROM, rom.name, true);
if(rom.size) {
rom.data = new uint8[rom.mask + 1];
memory::fill(rom.data, rom.mask + 1, 0xff);
if(rom.name) interface->loadRequest(ID::ROM, rom.name, true);
}
}
if(auto node = document["board/ram"]) {
@ -59,15 +65,20 @@ auto Cartridge::load() -> void {
ram.name = node["name"].text();
ram.size = node["size"].natural();
ram.mask = bit::round(ram.size) - 1;
if(ram.size) ram.data = new uint8[ram.mask + 1]();
if(ram.name) interface->loadRequest(ID::RAM, ram.name, false);
if(ram.size) {
ram.data = new uint8[ram.mask + 1];
memory::fill(ram.data, ram.mask + 1, 0xff);
if(ram.name) interface->loadRequest(ID::RAM, ram.name, false);
}
}
if(node["type"].text() == "eeprom") {
eeprom.setName(node["name"].text());
eeprom.setSize(node["size"].natural() / sizeof(uint16));
eeprom.erase();
if(eeprom.name()) interface->loadRequest(ID::EEPROM, eeprom.name(), false);
if(eeprom.size()) {
eeprom.erase();
if(eeprom.name()) interface->loadRequest(ID::EEPROM, eeprom.name(), false);
}
}
}
@ -75,8 +86,11 @@ auto Cartridge::load() -> void {
rtc.name = node["name"].text();
rtc.size = node["size"].natural();
rtc.mask = bit::round(rtc.size) - 1;
if(rtc.size) rtc.data = new uint8[rtc.mask + 1]();
if(rtc.name) interface->loadRequest(ID::RTC, rtc.name, false);
if(rtc.size) {
rtc.data = new uint8[rtc.mask + 1];
memory::fill(rtc.data, rtc.mask + 1, 0x00);
if(rtc.name) interface->loadRequest(ID::RTC, rtc.name, false);
}
}
information.title = document["information/title"].text();

View File

@ -31,11 +31,31 @@ struct Cartridge : Thread, IO {
//serialization.cpp
auto serialize(serializer&) -> void;
struct Information {
string manifest;
string title;
bool orientation; //0 = horizontal; 1 = vertical
string sha256;
} information;
struct Registers {
uint8 romBank0;
uint8 romBank1;
//$00c0 BANK_ROM2
uint8 romBank2;
//$00c1 BANK_SRAM
uint8 sramBank;
//$00c2 BANK_ROM0
uint8 romBank0;
//$00c3 BANK_ROM1
uint8 romBank1;
//$00cc GPO_EN
uint8 gpoEnable;
//$00cd GPO_DATA
uint8 gpoData;
} r;
struct Memory {
@ -66,13 +86,6 @@ struct Cartridge : Thread, IO {
Memory ram;
EEPROM eeprom;
RTC rtc;
struct Information {
string manifest;
string title;
bool orientation; //0 = horizontal; 1 = vertical
string sha256;
} information;
};
extern Cartridge cartridge;

View File

@ -28,6 +28,12 @@ auto Cartridge::portRead(uint16 addr) -> uint8 {
//RTC_DATA
if(addr == 0x00cb) return rtcRead();
//GPO_EN
if(addr == 0x00cc) return r.gpoEnable;
//GPO_DATA
if(addr == 0x00cd) return r.gpoData;
return 0x00;
}
@ -60,4 +66,10 @@ auto Cartridge::portWrite(uint16 addr, uint8 data) -> void {
//RTC_DATA
if(addr == 0x00cb) rtcWrite(data);
//GPO_EN
if(addr == 0x00cc) r.gpoEnable = data;
//GPO_DATA
if(addr == 0x00cd) r.gpoData = data;
}

View File

@ -122,6 +122,7 @@ auto Cartridge::rtcWrite(uint8 data) -> void {
if(rtc.command == 0x12) {
if(data.bit(6)) rtc.alarm = data; //todo: is bit6 really required to be set?
rtc.command = 0;
rtcCheckAlarm();
}
//SET_DATETIME

View File

@ -1,4 +1,6 @@
auto Cartridge::serialize(serializer& s) -> void {
Thread::serialize(s);
if(ram.size) s.array(ram.data, ram.size);
if(eeprom.size()) eeprom.serialize(s);
if(rtc.size) s.array(rtc.data, rtc.size);
@ -15,4 +17,6 @@ auto Cartridge::serialize(serializer& s) -> void {
s.integer(r.romBank1);
s.integer(r.romBank2);
s.integer(r.sramBank);
s.integer(r.gpoEnable);
s.integer(r.gpoData);
}

View File

@ -53,26 +53,14 @@ auto CPU::power() -> void {
create(CPU::Enter, 3'072'000);
bus.map(this, 0x00a0);
bus.map(this, 0x00b0);
bus.map(this, 0x00b2);
bus.map(this, 0x00b4, 0x00b6);
bus.map(this, 0x00b0, 0x00b6);
if(system.model() != Model::WonderSwan) {
bus.map(this, 0x0040, 0x0049);
bus.map(this, 0x0062);
}
r.dmaSource = 0;
r.dmaTarget = 0;
r.dmaLength = 0;
r.dmaEnable = 0;
r.dmaMode = 0;
r.interruptBase = 0;
r.interruptEnable = 0;
r.interruptStatus = 0;
r.ypadEnable = 0;
r.xpadEnable = 0;
r.buttonEnable = 0;
memory::fill(&r, sizeof(Registers));
}
}

View File

@ -55,9 +55,16 @@ struct CPU : Processor::V30MZ, Thread, IO {
//$00b0 INT_BASE
uint8 interruptBase;
//$00b1 SER_DATA
uint8 serialData;
//$00b2 INT_ENABLE
uint8 interruptEnable;
//$00b3 SER_STATUS
uint1 serialBaudRate; //0 = 9600; 1 = 38400
uint1 serialEnable;
//$00b4 INT_STATUS
uint8 interruptStatus;

View File

@ -63,9 +63,19 @@ auto CPU::portRead(uint16 addr) -> uint8 {
return r.interruptBase;
}
//SER_DATA
if(addr == 0x00b1) return r.serialData;
//INT_ENABLE
if(addr == 0x00b2) return r.interruptEnable;
//SER_STATUS
if(addr == 0x00b3) return (
1 << 2 //hack: always report send buffer as empty
| r.serialBaudRate << 6
| r.serialEnable << 7
);
//INT_STATUS
if(addr == 0x00b4) return r.interruptStatus;
@ -120,23 +130,32 @@ auto CPU::portWrite(uint16 addr, uint8 data) -> void {
return;
}
//SER_DATA
if(addr == 0x00b1) r.serialData = data;
//INT_ENABLE
if(addr == 0x00b2) {
r.interruptEnable = data;
return;
}
//SER_STATUS
if(addr == 0x00b3) {
r.serialBaudRate = data.bit(6);
r.serialEnable = data.bit(7);
}
//KEYPAD
if(addr == 0x00b5) {
r.ypadEnable = data.bit(4);
r.xpadEnable = data.bit(5);
r.buttonEnable = data.bit(6);
return;
}
//INT_ACK
if(addr == 0x00b6) {
r.interruptStatus &= ~data;
//acknowledge only edge-sensitive interrupts
r.interruptStatus &= ~(data & 0b11110010);
return;
}
}

View File

@ -1,5 +1,6 @@
auto CPU::serialize(serializer& s) -> void {
V30MZ::serialize(s);
Thread::serialize(s);
s.integer(r.dmaSource);
s.integer(r.dmaTarget);
@ -7,7 +8,10 @@ auto CPU::serialize(serializer& s) -> void {
s.integer(r.dmaEnable);
s.integer(r.dmaMode);
s.integer(r.interruptBase);
s.integer(r.serialData);
s.integer(r.interruptEnable);
s.integer(r.serialBaudRate);
s.integer(r.serialEnable);
s.integer(r.interruptStatus);
s.integer(r.ypadEnable);
s.integer(r.xpadEnable);

View File

@ -26,9 +26,9 @@ auto EEPROM::power() -> void {
r.unknown = false;
r.writeRequested = false;
r.readRequested = false;
r.writeCompleted = false;
r.readCompleted = false;
r.writeProtect = false;
r.writeCompleted = true; //hack: should require time to complete reads/writes
r.readCompleted = true; //instead; leave bits always set so games don't lock
r.writeProtect = true;
}
auto EEPROM::read(uint port) -> uint8 {
@ -134,4 +134,8 @@ auto EEPROM::execute() -> void {
}
}
auto EEPROM::operator[](uint10 addr) -> uint16& {
return _data[addr];
}
}

View File

@ -26,6 +26,8 @@ struct EEPROM {
auto read(uint) -> uint8;
auto write(uint, uint8) -> void;
auto operator[](uint10 addr) -> uint16&;
//serialization.cpp
auto serialize(serializer&) -> void;

View File

@ -262,19 +262,17 @@ auto PPU::portWrite(uint16 addr, uint8 data) -> void {
if(addr == 0x00a4) r.htimerFrequency.byte(0) = data;
if(addr == 0x00a5) r.htimerFrequency.byte(1) = data;
//VTMR_FREQ
if(addr == 0x00a6) r.vtimerFrequency.byte(0) = data;
if(addr == 0x00a7) r.vtimerFrequency.byte(1) = data;
//todo: is this correct?
if(addr == 0x00a5) {
if(addr == 0x00a4 || addr == 0x00a5) {
r.htimerEnable = true;
r.htimerRepeat = true;
r.htimerCounter = 0;
}
//todo: is this correct?
if(addr == 0x00a7) {
//VTMR_FREQ
if(addr == 0x00a6) r.vtimerFrequency.byte(0) = data;
if(addr == 0x00a7) r.vtimerFrequency.byte(1) = data;
if(addr == 0x00a6 || addr == 0x00a7) {
r.vtimerEnable = true;
r.vtimerRepeat = true;
r.vtimerCounter = 0;

View File

@ -1,4 +1,6 @@
auto PPU::serialize(serializer& s) -> void {
Thread::serialize(s);
s.integer(this->s.field);
s.integer(this->s.vclk);
s.integer(this->s.hclk);

View File

@ -33,6 +33,8 @@ auto System::load(Model model) -> void {
eeprom.setName(node["name"].text());
eeprom.setSize(node["size"].natural() / sizeof(uint16));
eeprom.erase();
//initialize user-data section
for(uint addr = 0x0030; addr <= 0x003a; addr++) eeprom[addr] = 0x0000;
interface->loadRequest(ID::SystemEEPROM, eeprom.name(), false);
}

View File

@ -6,7 +6,7 @@
namespace WonderSwan {
namespace Info {
static const string Name = "bws";
static const uint SerializerVersion = 0;
static const uint SerializerVersion = 1;
}
}