bsnes/bsnes/sfc/coprocessor/sa1/memory.cpp
Morilli 79770f6207 implementation of SA-1 BW-RAM protection
Manually cherry-picked ares commit 70f361094b.

Co-Authored-By: absindx <59403574+absindx@users.noreply.github.com>
2024-03-02 00:26:03 +11:00

140 lines
3.8 KiB
C++

auto SA1::idle() -> void {
step();
}
//RTx, JMx, JSx
auto SA1::idleJump() -> void {
//ROM access penalty cycle: does not apply to BWRAM or IRAM
if((r.pc.d & 0x408000) == 0x008000 //00-3f,80-bf:8000-ffff
|| (r.pc.d & 0xc00000) == 0xc00000 //c0-ff:0000-ffff
) {
step();
if(rom.conflict()) step();
}
}
//Bxx
auto SA1::idleBranch() -> void {
if(r.pc.d & 1) idleJump();
}
auto SA1::read(uint address) -> uint8 {
r.mar = address;
uint8 data = r.mdr;
if((address & 0x40fe00) == 0x002200 //00-3f,80-bf:2200-23ff
) {
step();
return r.mdr = readIOSA1(address, data);
}
if((address & 0x408000) == 0x008000 //00-3f,80-bf:8000-ffff
|| (address & 0xc00000) == 0xc00000 //c0-ff:0000-ffff
) {
step();
if(rom.conflict()) step();
return r.mdr = rom.readSA1(address, data);
}
if((address & 0x40e000) == 0x006000 //00-3f,80-bf:6000-7fff
|| (address & 0xe00000) == 0x400000 //40-5f:0000-ffff
|| (address & 0xf00000) == 0x600000 //60-6f:0000-ffff
) {
step();
step();
if(bwram.conflict()) step();
if(bwram.conflict()) step();
if((address & 1 << 22) && (address & 1 << 21)) return r.mdr = bwram.readBitmap(address, data);
if((address & 1 << 22)) return r.mdr = bwram.readLinear(address, data);
return r.mdr = bwram.readSA1(address, data);
}
if((address & 0x40f800) == 0x000000 //00-3f,80-bf:0000-07ff
|| (address & 0x40f800) == 0x003000 //00-3f,80-bf:3000-37ff
) {
step();
if(iram.conflict()) step();
if(iram.conflict()) step();
return r.mdr = iram.readSA1(address, data);
}
step();
return data;
}
auto SA1::write(uint address, uint8 data) -> void {
r.mar = address;
r.mdr = data;
if((address & 0x40fe00) == 0x002200 //00-3f,80-bf:2200-23ff
) {
step();
return writeIOSA1(address, data);
}
if((address & 0x408000) == 0x008000 //00-3f,80-bf:8000-ffff
|| (address & 0xc00000) == 0xc00000 //c0-ff:0000-ffff
) {
step();
if(rom.conflict()) step();
return rom.writeSA1(address, data);
}
if((address & 0x40e000) == 0x006000 //00-3f,80-bf:6000-7fff
|| (address & 0xe00000) == 0x400000 //40-5f:0000-ffff
|| (address & 0xf00000) == 0x600000 //60-6f:0000-ffff
) {
step();
step();
if(bwram.conflict()) step();
if(bwram.conflict()) step();
if((address & 1 << 22) && (address & 1 << 21)) return bwram.writeBitmap(address, data);
if((address & 1 << 22)) return bwram.writeLinear(address, data);
return bwram.writeSA1(address, data);
}
if((address & 0x40f800) == 0x000000 //00-3f,80-bf:0000-07ff
|| (address & 0x40f800) == 0x003000 //00-3f,80-bf:3000-37ff
) {
step();
if(iram.conflict()) step();
if(iram.conflict()) step();
return iram.writeSA1(address, data);
}
step();
return;
}
//$230c (VDPL), $230d (VDPH) use this bus to read variable-length data.
//this is used both to keep VBR-reads from accessing MMIO registers, and
//to avoid syncing the S-CPU and SA-1*; as both chips are able to access
//these ports.
auto SA1::readVBR(uint address, uint8 data) -> uint8 {
if((address & 0x408000) == 0x008000 //00-3f,80-bf:8000-ffff
|| (address & 0xc00000) == 0xc00000 //c0-ff:0000-ffff
) {
return rom.readSA1(address, data);
}
if((address & 0x40e000) == 0x006000 //00-3f,80-bf:6000-7fff
|| (address & 0xf00000) == 0x400000 //40-4f:0000-ffff
) {
return bwram.read(address, data);
}
if((address & 0x40f800) == 0x000000 //00-3f,80-bf:0000-07ff
|| (address & 0x40f800) == 0x003000 //00-3f,80-bf:3000-37ff
) {
return iram.read(address, data);
}
return 0xff;
}
auto SA1::readDisassembler(uint address) -> uint8 {
//TODO: this is a hack; SA1::read() advances the clock; whereas Bus::read() does not
//the CPU and SA1 bus are identical for ROM, but have differences in BWRAM and IRAM
return bus.read(address, r.mdr);
}