bsnes/higan/sfc/coprocessor/sdd1/sdd1.cpp

150 lines
4.0 KiB
C++

#include <sfc/sfc.hpp>
namespace SuperFamicom {
SDD1 sdd1;
#include "decompressor.cpp"
#include "serialization.cpp"
auto SDD1::init() -> void {
}
void SDD1::load() {
}
auto SDD1::unload() -> void {
rom.reset();
ram.reset();
}
auto SDD1::power() -> void {
//hook S-CPU DMA MMIO registers to gather information for struct dma[];
//buffer address and transfer size information for use in SDD1::mcu_read()
bus.map({&SDD1::dmaRead, &sdd1}, {&SDD1::dmaWrite, &sdd1}, "00-3f,80-bf:4300-437f");
r4800 = 0x00;
r4801 = 0x00;
r4804 = 0x00;
r4805 = 0x01;
r4806 = 0x02;
r4807 = 0x03;
for(auto n : range(8)) {
dma[n].addr = 0;
dma[n].size = 0;
}
dmaReady = false;
}
auto SDD1::read(uint24 addr, uint8 data) -> uint8 {
addr = 0x4800 | addr.bits(0,3);
switch(addr) {
case 0x4800: return r4800;
case 0x4801: return r4801;
case 0x4804: return r4804;
case 0x4805: return r4805;
case 0x4806: return r4806;
case 0x4807: return r4807;
}
//00-3f,80-bf:4802-4803,4808-480f falls through to ROM
return rom.read(addr);
}
auto SDD1::write(uint24 addr, uint8 data) -> void {
addr = 0x4800 | addr.bits(0,3);
switch(addr) {
case 0x4800: r4800 = data; break;
case 0x4801: r4801 = data; break;
case 0x4804: r4804 = data & 0x8f; break;
case 0x4805: r4805 = data & 0x8f; break;
case 0x4806: r4806 = data & 0x8f; break;
case 0x4807: r4807 = data & 0x8f; break;
}
}
auto SDD1::dmaRead(uint24 addr, uint8 data) -> uint8 {
return cpu.readDMA(addr, data);
}
auto SDD1::dmaWrite(uint24 addr, uint8 data) -> void {
uint channel = addr.bits(4,6);
switch(addr.bits(0,3)) {
case 2: dma[channel].addr.byte(0) = data; break;
case 3: dma[channel].addr.byte(1) = data; break;
case 4: dma[channel].addr.byte(2) = data; break;
case 5: dma[channel].size.byte(0) = data; break;
case 6: dma[channel].size.byte(1) = data; break;
}
return cpu.writeDMA(addr, data);
}
auto SDD1::mmcRead(uint24 addr) -> uint8 {
switch(addr.bits(20,21)) {
case 0: return rom.read(r4804.bits(0,3) << 20 | addr.bits(0,19)); //c0-cf:0000-ffff
case 1: return rom.read(r4805.bits(0,3) << 20 | addr.bits(0,19)); //d0-df:0000-ffff
case 2: return rom.read(r4806.bits(0,3) << 20 | addr.bits(0,19)); //e0-ef:0000-ffff
case 3: return rom.read(r4807.bits(0,3) << 20 | addr.bits(0,19)); //f0-ff:0000-ffff
}
unreachable;
}
//map address=00-3f,80-bf:8000-ffff
//map address=c0-ff:0000-ffff
auto SDD1::mcuromRead(uint24 addr, uint8 data) -> uint8 {
//map address=00-3f,80-bf:8000-ffff
if(!addr.bit(22)) {
if(!addr.bit(23) && addr.bit(21) && r4805.bit(7)) addr.bit(21) = 0; //20-3f:8000-ffff
if( addr.bit(23) && addr.bit(21) && r4807.bit(7)) addr.bit(21) = 0; //a0-bf:8000-ffff
addr = addr.bits(16,21) << 15 | addr.bits(0,14);
return rom.read(addr);
}
//map address=c0-ff:0000-ffff
if(r4800 & r4801) {
//at least one channel has S-DD1 decompression enabled ...
for(auto n : range(8)) {
if(r4800.bit(n) && r4801.bit(n)) {
//S-DD1 always uses fixed transfer mode, so address will not change during transfer
if(addr == dma[n].addr) {
if(!dmaReady) {
//prepare streaming decompression
decompressor.init(addr);
dmaReady = true;
}
//fetch a decompressed byte; once finished, disable channel and invalidate buffer
data = decompressor.read();
if(--dma[n].size == 0) {
dmaReady = false;
r4801.bit(n) = 0;
}
return data;
} //address matched
} //channel enabled
} //channel loop
} //S-DD1 decompressor enabled
//S-DD1 decompression mode inactive; return ROM data
return mmcRead(addr);
}
auto SDD1::mcuromWrite(uint24 addr, uint8 data) -> void {
}
//map address=00-3f,80-bf:6000-7fff mask=0xe000
//map address=70-73:0000-ffff mask=0x8000
auto SDD1::mcuramRead(uint24 addr, uint8 data) -> uint8 {
return ram.read(addr.bits(0,12), data);
}
auto SDD1::mcuramWrite(uint24 addr, uint8 data) -> void {
return ram.write(addr.bits(0,12), data);
}
}