Files
bsnes/sfc/smp/memory.cpp
Tim Allen d1ffd59c29 Update to v095r04 release.
Changelog:
- S-SMP core code style updated
- S-SMP loads reset vector from IPLROM ($fffe-ffff)
- sfc/base => sfc/expansion
- system/input => system/device
- added expansion/eBoot (simulation of defparam's SNES-Boot device)
- expansion port device can now be selected from Super Famicom menu
  option
- improved GBA MROM/SRAM reading

endrift's memory test is up to 1388/1552.

Note: I added the expansion port devices to the same group as controller
ports. I also had to move "None" to the top of the list. Before v096,
I am going to have to add caching of port selections to the
configuration file, check the proper default item in the system menu,
and remove the items with no mappings from the input configuration
window. Lots of work >_>
2015-11-10 22:11:29 +11:00

206 lines
4.5 KiB
C++

#ifdef SMP_CPP
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.port_read(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.port_write(2, 0x00);
cpu.port_write(3, 0x00);
}
if(data & 0x10) {
cpu.port_write(0, 0x00);
cpu.port_write(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];
}
#endif