mirror of https://github.com/bsnes-emu/bsnes.git
202 lines
4.4 KiB
C++
202 lines
4.4 KiB
C++
alwaysinline auto SMP::readRAM(uint16 addr) -> uint8 {
|
|
if(addr >= 0xffc0 && io.iplromEnable) return iplrom[addr & 0x3f];
|
|
if(io.ramDisable) return 0x5a; //0xff on mini-SNES
|
|
return apuram[addr];
|
|
}
|
|
|
|
alwaysinline auto SMP::writeRAM(uint16 addr, uint8 data) -> void {
|
|
//writes to $ffc0-$ffff always go to apuram, even if the iplrom is enabled
|
|
if(io.ramWritable && !io.ramDisable) apuram[addr] = data;
|
|
}
|
|
|
|
auto SMP::readPort(uint2 port) const -> uint8 {
|
|
return apuram[0xf4 + port];
|
|
}
|
|
|
|
auto SMP::writePort(uint2 port, uint8 data) -> void {
|
|
apuram[0xf4 + port] = data;
|
|
}
|
|
|
|
auto SMP::readBus(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 io.dspAddr;
|
|
|
|
case 0xf3: //DSPDATA
|
|
//0x80-0xff are read-only mirrors of 0x00-0x7f
|
|
return dsp.read(io.dspAddr & 0x7f);
|
|
|
|
case 0xf4: //CPUIO0
|
|
case 0xf5: //CPUIO1
|
|
case 0xf6: //CPUIO2
|
|
case 0xf7: //CPUIO3
|
|
synchronizeCPU();
|
|
return cpu.readPort(addr);
|
|
|
|
case 0xf8: //RAM0
|
|
return io.ram00f8;
|
|
|
|
case 0xf9: //RAM1
|
|
return io.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 readRAM(addr);
|
|
}
|
|
|
|
auto SMP::writeBus(uint16 addr, uint8 data) -> void {
|
|
switch(addr) {
|
|
case 0xf0: //TEST
|
|
if(regs.p.p) break; //writes only valid when P flag is clear
|
|
|
|
io.clockSpeed = (data >> 6) & 3;
|
|
io.timerSpeed = (data >> 4) & 3;
|
|
io.timersEnable = data & 0x08;
|
|
io.ramDisable = data & 0x04;
|
|
io.ramWritable = data & 0x02;
|
|
io.timersDisable = data & 0x01;
|
|
|
|
io.timerStep = (1 << io.clockSpeed) + (2 << io.timerSpeed);
|
|
|
|
timer0.synchronizeStage1();
|
|
timer1.synchronizeStage1();
|
|
timer2.synchronizeStage1();
|
|
break;
|
|
|
|
case 0xf1: //CONTROL
|
|
io.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.writePort(2, 0x00);
|
|
cpu.writePort(3, 0x00);
|
|
}
|
|
if(data & 0x10) {
|
|
cpu.writePort(0, 0x00);
|
|
cpu.writePort(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
|
|
io.dspAddr = data;
|
|
break;
|
|
|
|
case 0xf3: //DSPDATA
|
|
if(io.dspAddr & 0x80) break; //0x80-0xff are read-only mirrors of 0x00-0x7f
|
|
dsp.write(io.dspAddr & 0x7f, data);
|
|
break;
|
|
|
|
case 0xf4: //CPUIO0
|
|
case 0xf5: //CPUIO1
|
|
case 0xf6: //CPUIO2
|
|
case 0xf7: //CPUIO3
|
|
synchronizeCPU();
|
|
writePort(addr, data);
|
|
break;
|
|
|
|
case 0xf8: //RAM0
|
|
io.ram00f8 = data;
|
|
break;
|
|
|
|
case 0xf9: //RAM1
|
|
io.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;
|
|
}
|
|
|
|
writeRAM(addr, data); //all writes, even to MMIO registers, appear on bus
|
|
}
|
|
|
|
auto SMP::idle() -> void {
|
|
step(24);
|
|
cycleEdge();
|
|
}
|
|
|
|
auto SMP::read(uint16 addr) -> uint8 {
|
|
step(12);
|
|
uint8 data = readBus(addr);
|
|
step(12);
|
|
cycleEdge();
|
|
debug(smp.read, addr, data);
|
|
return data;
|
|
}
|
|
|
|
auto SMP::write(uint16 addr, uint8 data) -> void {
|
|
step(24);
|
|
writeBus(addr, data);
|
|
cycleEdge();
|
|
debug(smp.write, addr, data);
|
|
}
|
|
|
|
auto SMP::readDisassembler(uint16 addr) -> uint8 {
|
|
if((addr & 0xfff0) == 0x00f0) return 0x00;
|
|
if((addr & 0xffc0) == 0xffc0 && io.iplromEnable) return iplrom[addr & 0x3f];
|
|
return apuram[addr];
|
|
}
|