bsnes/higan/sfc/smp/memory.cpp

202 lines
4.5 KiB
C++

alwaysinline auto SMP::ramRead(uint16 addr) -> uint8 {
if(addr >= 0xffc0 && status.iplromEnable) return iplrom[addr & 0x3f];
if(status.ramDisable) return 0x5a; //0xff on mini-SNES
return apuram[addr];
}
alwaysinline auto SMP::ramWrite(uint16 addr, uint8 data) -> void {
//writes to $ffc0-$ffff always go to apuram, even if the iplrom is enabled
if(status.ramWritable && !status.ramDisable) apuram[addr] = data;
}
auto SMP::portRead(uint2 port) const -> uint8 {
return apuram[0xf4 + port];
}
auto SMP::portWrite(uint2 port, uint8 data) -> void {
apuram[0xf4 + port] = data;
}
auto SMP::busRead(uint16 addr) -> uint8 {
uint result;
switch(addr) {
case 0xf0: //TEST -- write-only register
return 0x00;
case 0xf1: //CONTROL -- write-only register
return 0x00;
case 0xf2: //DSPADDR
return status.dspAddr;
case 0xf3: //DSPDATA
//0x80-0xff are read-only mirrors of 0x00-0x7f
return dsp.read(status.dspAddr & 0x7f);
case 0xf4: //CPUIO0
case 0xf5: //CPUIO1
case 0xf6: //CPUIO2
case 0xf7: //CPUIO3
synchronizeCPU();
return cpu.portRead(addr);
case 0xf8: //RAM0
return status.ram00f8;
case 0xf9: //RAM1
return status.ram00f9;
case 0xfa: //T0TARGET
case 0xfb: //T1TARGET
case 0xfc: //T2TARGET -- write-only registers
return 0x00;
case 0xfd: //T0OUT -- 4-bit counter value
result = timer0.stage3;
timer0.stage3 = 0;
return result;
case 0xfe: //T1OUT -- 4-bit counter value
result = timer1.stage3;
timer1.stage3 = 0;
return result;
case 0xff: //T2OUT -- 4-bit counter value
result = timer2.stage3;
timer2.stage3 = 0;
return result;
}
return ramRead(addr);
}
auto SMP::busWrite(uint16 addr, uint8 data) -> void {
switch(addr) {
case 0xf0: //TEST
if(regs.p.p) break; //writes only valid when P flag is clear
status.clockSpeed = (data >> 6) & 3;
status.timerSpeed = (data >> 4) & 3;
status.timersEnable = data & 0x08;
status.ramDisable = data & 0x04;
status.ramWritable = data & 0x02;
status.timersDisable = data & 0x01;
status.timerStep = (1 << status.clockSpeed) + (2 << status.timerSpeed);
timer0.synchronizeStage1();
timer1.synchronizeStage1();
timer2.synchronizeStage1();
break;
case 0xf1: //CONTROL
status.iplromEnable = data & 0x80;
if(data & 0x30) {
//one-time clearing of APU port read registers,
//emulated by simulating CPU writes of 0x00
synchronizeCPU();
if(data & 0x20) {
cpu.portWrite(2, 0x00);
cpu.portWrite(3, 0x00);
}
if(data & 0x10) {
cpu.portWrite(0, 0x00);
cpu.portWrite(1, 0x00);
}
}
//0->1 transistion resets timers
if(!timer2.enable && (data & 0x04)) {
timer2.stage2 = 0;
timer2.stage3 = 0;
}
timer2.enable = data & 0x04;
if(!timer1.enable && (data & 0x02)) {
timer1.stage2 = 0;
timer1.stage3 = 0;
}
timer1.enable = data & 0x02;
if(!timer0.enable && (data & 0x01)) {
timer0.stage2 = 0;
timer0.stage3 = 0;
}
timer0.enable = data & 0x01;
break;
case 0xf2: //DSPADDR
status.dspAddr = data;
break;
case 0xf3: //DSPDATA
if(status.dspAddr & 0x80) break; //0x80-0xff are read-only mirrors of 0x00-0x7f
dsp.write(status.dspAddr & 0x7f, data);
break;
case 0xf4: //CPUIO0
case 0xf5: //CPUIO1
case 0xf6: //CPUIO2
case 0xf7: //CPUIO3
synchronizeCPU();
portWrite(addr, data);
break;
case 0xf8: //RAM0
status.ram00f8 = data;
break;
case 0xf9: //RAM1
status.ram00f9 = data;
break;
case 0xfa: //T0TARGET
timer0.target = data;
break;
case 0xfb: //T1TARGET
timer1.target = data;
break;
case 0xfc: //T2TARGET
timer2.target = data;
break;
case 0xfd: //T0OUT
case 0xfe: //T1OUT
case 0xff: //T2OUT -- read-only registers
break;
}
ramWrite(addr, data); //all writes, even to MMIO registers, appear on bus
}
auto SMP::op_io() -> void {
addClocks(24);
cycleEdge();
}
auto SMP::op_read(uint16 addr) -> uint8 {
addClocks(12);
uint8 data = busRead(addr);
addClocks(12);
cycleEdge();
debugger.op_read(addr, data);
return data;
}
auto SMP::op_write(uint16 addr, uint8 data) -> void {
addClocks(24);
busWrite(addr, data);
cycleEdge();
debugger.op_write(addr, data);
}
auto SMP::disassembler_read(uint16 addr) -> uint8 {
if((addr & 0xfff0) == 0x00f0) return 0x00;
if((addr & 0xffc0) == 0xffc0 && status.iplromEnable) return iplrom[addr & 0x3f];
return apuram[addr];
}