bsnes/higan/pce/cpu/io.cpp

204 lines
4.7 KiB
C++

auto CPU::read(uint8 bank, uint13 addr) -> uint8 {
auto data = read_(bank, addr);
if(auto result = cheat.find(bank << 13 | addr, data)) data = result();
return data;
}
auto CPU::read_(uint8 bank, uint13 addr) -> uint8 {
//$00-7f HuCard
if(!bank.bit(7)) {
return cartridge.read(bank << 13 | addr);
}
//$f7 BRAM
if(bank == 0xf7) {
return bram[addr.bits(0,10)];
}
//$f8-fb RAM
if(bank >= 0xf8 && bank <= 0xfb) {
if(Model::PCEngine()) return ram[addr];
if(Model::SuperGrafx()) return ram[bank.bits(0,1) << 13 | addr];
}
//$ff Hardware
if(bank == 0xff) {
//$0000-03ff VDC or VPC
if((addr & 0x1c00) == 0x0000) {
HuC6280::io(); //penalty cycle
if(Model::PCEngine()) return vdc0.read(addr);
if(Model::SuperGrafx()) return vpc.read(addr);
}
//$0400-07ff VCE
if((addr & 0x1c00) == 0x0400) {
HuC6280::io(); //penalty cycle
return vce.read(addr);
}
//$0800-0bff PSG
if((addr & 0x1c00) == 0x0800) {
return io.mdr;
}
//$0c00-0fff Timer
if((addr & 0x1c00) == 0x0c00) {
return (io.mdr & 0x80) | timer.value;
}
//$1000-13ff I/O
if((addr & 0x1c00) == 0x1000) {
//note 1: Turbografx-16 games check this bit for region protection.
//yet PC Engine games do not. since we cannot tell the games apart,
//it's more compatible to always identify as a Turbografx-16 system.
//note 2: we state that the CD-ROM drive is present.
//this is so games can use its backup RAM for save data.
return (
controllerPort.device->readData() << 0
| 1 << 4
| 1 << 5
| 0 << 6 //device (0 = Turbografx-16; 1 = PC Engine)
| 0 << 7 //add-on (0 = CD-ROM; 1 = nothing)
);
}
//$1400-17ff IRQ
if((addr & 0x1c00) == 0x1400) {
if(addr.bits(0,1) == 0) {
return io.mdr;
}
if(addr.bits(0,1) == 1) {
return io.mdr;
}
if(addr.bits(0,1) == 2) {
return (
irq.disableExternal << 0
| irq.disableVDC << 1
| irq.disableTimer << 2
| (io.mdr & 0xf8)
);
}
if(addr.bits(0,1) == 3) {
bool pendingExternal = 0;
bool pendingVDC = vdc0.irqLine() | vdc1.irqLine();
bool pendingTimer = timer.irqLine();
return (
pendingExternal << 0
| pendingVDC << 1
| pendingTimer << 2
| (io.mdr & 0xf8)
);
}
}
//$1800-1bff CD-ROM
if((addr & 0x1c00) == 0x1800) {
return 0xff;
}
//$1c00-1fff unmapped
if((addr & 0x1c00) == 0x1c00) {
return 0xff;
}
}
return 0xff;
}
auto CPU::write(uint8 bank, uint13 addr, uint8 data) -> void {
//$00-7f HuCard
if(!bank.bit(7)) {
return cartridge.write(bank << 13 | addr, data);
}
//$f7 BRAM
if(bank == 0xf7) {
bram[addr.bits(0,10)] = data;
return;
}
//$f8-fb RAM
if(bank >= 0xf8 && bank <= 0xfb) {
if(Model::PCEngine()) ram[addr] = data;
if(Model::SuperGrafx()) ram[bank.bits(0,1) << 13 | addr] = data;
return;
}
//$1fe000-1fffff Hardware
if(bank == 0xff) {
//$0000-03ff VDC or VPC
if((addr & 0x1c00) == 0x0000) {
HuC6280::io(); //penalty cycle
if(Model::PCEngine()) return vdc0.write(addr, data);
if(Model::SuperGrafx()) return vpc.write(addr, data);
}
//$0400-07ff VCE
if((addr & 0x1c00) == 0x0400) {
HuC6280::io(); //penalty cycle
return vce.write(addr, data);
}
//$0800-0bff PSG
if((addr & 0x1c00) == 0x0800) {
return psg.write(addr, io.mdr = data);
}
//$0c00-0fff Timer
if((addr & 0x1c00) == 0x0c00) {
io.mdr = data;
if(!addr.bit(0)) {
timer.latch = data.bits(0,6);
} else {
timer.enable = data.bit(0);
if(timer.enable) timer.start();
}
return;
}
//$1000-13ff I/O
if((addr & 0x1c00) == 0x1000) {
io.mdr = data;
controllerPort.device->writeData(data.bits(0,1));
return;
}
//$1400-17ff IRQ
if((addr & 0x1c00) == 0x1400) {
io.mdr = data;
if(addr.bits(0,1) == 2) {
irq.disableExternal = data.bit(0);
irq.disableVDC = data.bit(1);
irq.disableTimer = data.bit(2);
return;
}
if(addr.bits(0,1) == 3) {
timer.line = 0;
return;
}
}
//$1800-1bff CD-ROM
if((addr & 0x1c00) == 0x1800) {
return;
}
//$1c00-1fff unmapped
if((addr & 0x1c00) == 0x1c00) {
return;
}
}
}
//ST0, ST1, ST2
auto CPU::store(uint2 addr, uint8 data) -> void {
HuC6280::io(); //penalty cycle
if(addr) addr++; //0,1,2 => 0,2,3
if(Model::PCEngine()) vdc0.write(addr, data);
if(Model::SuperGrafx()) vpc.store(addr, data);
}