mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-10-05 03:51:33 +02:00
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 >_>
206 lines
4.5 KiB
C++
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
|