bsnes/bsnes/sfc/coprocessor/sa1/bwram.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

133 lines
4.1 KiB
C++

auto SA1::BWRAM::conflict() const -> bool {
if(configuration.hacks.coprocessor.delayedSync) return false;
if((cpu.r.mar & 0x40e000) == 0x006000) return true; //00-3f,80-bf:6000-7fff
if((cpu.r.mar & 0xf00000) == 0x400000) return true; //40-4f:0000-ffff
return false;
}
auto SA1::BWRAM::read(uint address, uint8 data) -> uint8 {
if(!size()) return data;
address = bus.mirror(address, size());
return WritableMemory::read(address, data);
}
auto SA1::BWRAM::write(uint address, uint8 data) -> void {
if(!size()) return;
address = bus.mirror(address, size());
return WritableMemory::write(address, data);
}
//note: addresses are translated prior to invoking this function:
//00-3f,80-bf:6000-7fff size=0x2000 => 00:0000-1fff
//40-4f:0000-ffff => untranslated
auto SA1::BWRAM::readCPU(uint address, uint8 data) -> uint8 {
cpu.synchronizeCoprocessors();
if(address < 0x2000) { //$00-3f,80-bf:6000-7fff
address = sa1.mmio.sbm * 0x2000 + (address & 0x1fff);
}
if(dma) return sa1.dmaCC1Read(address);
return read(address, data);
}
auto SA1::BWRAM::writeCPU(uint address, uint8 data) -> void {
cpu.synchronizeCoprocessors();
if(address < 0x2000) { //$00-3f,80-bf:6000-7fff
address = sa1.mmio.sbm * 0x2000 + (address & 0x1fff);
}
//note: BW-RAM protection works only when both SWEN and CWEN are disabled.
if(!sa1.mmio.swen && !sa1.mmio.cwen && (address & 0x3ffff) < 0x100 << sa1.mmio.bwp) return;
return write(address, data);
}
auto SA1::BWRAM::readSA1(uint address, uint8 data) -> uint8 {
if(sa1.mmio.sw46 == 0) {
//$40-43:0000-ffff x 32 projection
address = (sa1.mmio.cbm & 0x1f) * 0x2000 + (address & 0x1fff);
return readLinear(address, data);
} else {
//$60-6f:0000-ffff x 128 projection
address = sa1.mmio.cbm * 0x2000 + (address & 0x1fff);
return readBitmap(address, data);
}
}
auto SA1::BWRAM::writeSA1(uint address, uint8 data) -> void {
if(sa1.mmio.sw46 == 0) {
//$40-43:0000-ffff x 32 projection
address = (sa1.mmio.cbm & 0x1f) * 0x2000 + (address & 0x1fff);
return writeLinear(address, data);
} else {
//$60-6f:0000-ffff x 128 projection
address = sa1.mmio.cbm * 0x2000 + (address & 0x1fff);
return writeBitmap(address, data);
}
}
auto SA1::BWRAM::readLinear(uint address, uint8 data) -> uint8 {
return read(address, data);
}
auto SA1::BWRAM::writeLinear(uint address, uint8 data) -> void {
//note: BW-RAM protection works only when both SWEN and CWEN are disabled.
//this is required for Kirby's Dream Land 3 to work:
//* BWPA = 02 (protect 400000-4003ff)
//* SWEN = 80 (writes enabled)
//* CWEN = 00 (writes disabled)
//KDL3 proceeds to write to 4001ax and 40032x which must succeed.
//note: BWPA also affects SA-1 protection
if(!sa1.mmio.swen && !sa1.mmio.cwen && (address & 0x3ffff) < 0x100 << sa1.mmio.bwp) return;
return write(address, data);
}
auto SA1::BWRAM::readBitmap(uint20 address, uint8 data) -> uint8 {
if(sa1.mmio.bbf == 0) {
//4bpp
uint shift = address & 1;
address >>= 1;
switch(shift) {
case 0: return read(address) >> 0 & 15;
case 1: return read(address) >> 4 & 15;
}
} else {
//2bpp
uint shift = address & 3;
address >>= 2;
switch(shift) {
case 0: return read(address) >> 0 & 3;
case 1: return read(address) >> 2 & 3;
case 2: return read(address) >> 4 & 3;
case 3: return read(address) >> 6 & 3;
}
}
unreachable;
}
auto SA1::BWRAM::writeBitmap(uint20 address, uint8 data) -> void {
if(sa1.mmio.bbf == 0) {
//4bpp
uint shift = address & 1;
address >>= 1;
switch(shift) {
case 0: data = read(address) & 0xf0 | (data & 0x0f) << 0; break;
case 1: data = read(address) & 0x0f | (data & 0x0f) << 4; break;
}
} else {
//2bpp
uint shift = address & 3;
address >>= 2;
switch(shift) {
case 0: data = read(address) & 0xfc | (data & 0x03) << 0; break;
case 1: data = read(address) & 0xf3 | (data & 0x03) << 2; break;
case 2: data = read(address) & 0xcf | (data & 0x03) << 4; break;
case 3: data = read(address) & 0x3f | (data & 0x03) << 6; break;
}
}
write(address, data);
}