mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
379ab6991f
commit
680d16561e
|
@ -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/";
|
||||
|
|
|
@ -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;
|
|
@ -10,6 +10,7 @@ namespace Processor {
|
|||
#include "instructions.cpp"
|
||||
#include "table.cpp"
|
||||
#include "serialization.cpp"
|
||||
#include "disassembler.cpp"
|
||||
|
||||
auto GSU::power() -> void {
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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--;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -8,7 +8,6 @@ namespace SuperFamicom {
|
|||
#include "memory/memory.cpp"
|
||||
#include "mmio/mmio.cpp"
|
||||
#include "timing/timing.cpp"
|
||||
#include "disassembler/disassembler.cpp"
|
||||
|
||||
SuperFX superfx;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
|
@ -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++;
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
namespace WonderSwan {
|
||||
namespace Info {
|
||||
static const string Name = "bws";
|
||||
static const uint SerializerVersion = 0;
|
||||
static const uint SerializerVersion = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue