bsnes/higan/sfc/cpu/mmio.cpp

346 lines
7.3 KiB
C++
Raw Normal View History

auto CPU::apuPortRead(uint24 addr, uint8 data) -> uint8 {
synchronizeSMP();
return smp.portRead(addr.bits(0,1));
}
auto CPU::cpuPortRead(uint24 addr, uint8 data) -> uint8 {
addr &= 0xffff;
//WMDATA
if(addr == 0x2180) {
Update to v098r11 release. byuu says: Changelog: - fixed nall/path.hpp compilation issue - fixed ruby/audio/xaudio header declaration compilation issue (again) - cleaned up xaudio2.hpp file to match my coding syntax (12.5% of the file was whitespace overkill) - added null terminator entry to nall/windows/utf8.hpp argc[] array - nall/windows/guid.hpp uses the Windows API for generating the GUID - this should stop all the bug reports where two nall users were generating GUIDs at the exact same second - fixed hiro/cocoa compilation issue with uint# types - fixed major higan/sfc Super Game Boy audio latency issue - fixed higan/sfc CPU core bug with pei, [dp], [dp]+y instructions - major cleanups to higan/processor/r65816 core - merged emulation/native-mode opcodes - use camel-case naming on memory.hpp functions - simplify address masking code for memory.hpp functions - simplify a few opcodes themselves (avoid redundant copies, etc) - rename regs.* to r.* to match modern convention of other CPU cores - removed device.order<> concept from Emulator::Interface - cores will now do the translation to make the job of the UI easier - fixed plurality naming of arrays in Emulator::Interface - example: emulator.ports[p].devices[d].inputs[i] - example: vector<Medium> media - probably more surprises Major show-stoppers to the next official release: - we need to work on GB core improvements: LY=153/0 case, multiple STAT IRQs case, GBC audio output regs, etc. - we need to re-add software cursors for light guns (Super Scope, Justifier) - after the above, we need to fix the turbo button for the Super Scope I really have no idea how I want to implement the light guns. Ideally, we'd want it in higan/video, so we can support the NES Zapper with the same code. But this isn't going to be easy, because only the SNES knows when its output is interlaced, and its resolutions can vary as {256,512}x{224,240,448,480} which requires pixel doubling that was hard-coded to the SNES-specific behavior, but isn't appropriate to be exposed in higan/video.
2016-05-25 11:13:02 +00:00
return bus.read(0x7e0000 | status.wram_addr++, r.mdr);
}
//JOYSER0
//7-2 = MDR
//1-0 = Joypad serial data
if(addr == 0x4016) {
Update to v098r11 release. byuu says: Changelog: - fixed nall/path.hpp compilation issue - fixed ruby/audio/xaudio header declaration compilation issue (again) - cleaned up xaudio2.hpp file to match my coding syntax (12.5% of the file was whitespace overkill) - added null terminator entry to nall/windows/utf8.hpp argc[] array - nall/windows/guid.hpp uses the Windows API for generating the GUID - this should stop all the bug reports where two nall users were generating GUIDs at the exact same second - fixed hiro/cocoa compilation issue with uint# types - fixed major higan/sfc Super Game Boy audio latency issue - fixed higan/sfc CPU core bug with pei, [dp], [dp]+y instructions - major cleanups to higan/processor/r65816 core - merged emulation/native-mode opcodes - use camel-case naming on memory.hpp functions - simplify address masking code for memory.hpp functions - simplify a few opcodes themselves (avoid redundant copies, etc) - rename regs.* to r.* to match modern convention of other CPU cores - removed device.order<> concept from Emulator::Interface - cores will now do the translation to make the job of the UI easier - fixed plurality naming of arrays in Emulator::Interface - example: emulator.ports[p].devices[d].inputs[i] - example: vector<Medium> media - probably more surprises Major show-stoppers to the next official release: - we need to work on GB core improvements: LY=153/0 case, multiple STAT IRQs case, GBC audio output regs, etc. - we need to re-add software cursors for light guns (Super Scope, Justifier) - after the above, we need to fix the turbo button for the Super Scope I really have no idea how I want to implement the light guns. Ideally, we'd want it in higan/video, so we can support the NES Zapper with the same code. But this isn't going to be easy, because only the SNES knows when its output is interlaced, and its resolutions can vary as {256,512}x{224,240,448,480} which requires pixel doubling that was hard-coded to the SNES-specific behavior, but isn't appropriate to be exposed in higan/video.
2016-05-25 11:13:02 +00:00
uint8 v = r.mdr & 0xfc;
v |= SuperFamicom::peripherals.controllerPort1->data();
return v;
}
//JOYSER1
if(addr == 0x4017) {
//7-5 = MDR
//4-2 = Always 1 (pins are connected to GND)
//1-0 = Joypad serial data
Update to v098r11 release. byuu says: Changelog: - fixed nall/path.hpp compilation issue - fixed ruby/audio/xaudio header declaration compilation issue (again) - cleaned up xaudio2.hpp file to match my coding syntax (12.5% of the file was whitespace overkill) - added null terminator entry to nall/windows/utf8.hpp argc[] array - nall/windows/guid.hpp uses the Windows API for generating the GUID - this should stop all the bug reports where two nall users were generating GUIDs at the exact same second - fixed hiro/cocoa compilation issue with uint# types - fixed major higan/sfc Super Game Boy audio latency issue - fixed higan/sfc CPU core bug with pei, [dp], [dp]+y instructions - major cleanups to higan/processor/r65816 core - merged emulation/native-mode opcodes - use camel-case naming on memory.hpp functions - simplify address masking code for memory.hpp functions - simplify a few opcodes themselves (avoid redundant copies, etc) - rename regs.* to r.* to match modern convention of other CPU cores - removed device.order<> concept from Emulator::Interface - cores will now do the translation to make the job of the UI easier - fixed plurality naming of arrays in Emulator::Interface - example: emulator.ports[p].devices[d].inputs[i] - example: vector<Medium> media - probably more surprises Major show-stoppers to the next official release: - we need to work on GB core improvements: LY=153/0 case, multiple STAT IRQs case, GBC audio output regs, etc. - we need to re-add software cursors for light guns (Super Scope, Justifier) - after the above, we need to fix the turbo button for the Super Scope I really have no idea how I want to implement the light guns. Ideally, we'd want it in higan/video, so we can support the NES Zapper with the same code. But this isn't going to be easy, because only the SNES knows when its output is interlaced, and its resolutions can vary as {256,512}x{224,240,448,480} which requires pixel doubling that was hard-coded to the SNES-specific behavior, but isn't appropriate to be exposed in higan/video.
2016-05-25 11:13:02 +00:00
uint8 v = (r.mdr & 0xe0) | 0x1c;
v |= SuperFamicom::peripherals.controllerPort2->data();
return v;
}
//RDNMI
if(addr == 0x4210) {
//7 = NMI acknowledge
//6-4 = MDR
//3-0 = CPU (5a22) version
Update to v098r11 release. byuu says: Changelog: - fixed nall/path.hpp compilation issue - fixed ruby/audio/xaudio header declaration compilation issue (again) - cleaned up xaudio2.hpp file to match my coding syntax (12.5% of the file was whitespace overkill) - added null terminator entry to nall/windows/utf8.hpp argc[] array - nall/windows/guid.hpp uses the Windows API for generating the GUID - this should stop all the bug reports where two nall users were generating GUIDs at the exact same second - fixed hiro/cocoa compilation issue with uint# types - fixed major higan/sfc Super Game Boy audio latency issue - fixed higan/sfc CPU core bug with pei, [dp], [dp]+y instructions - major cleanups to higan/processor/r65816 core - merged emulation/native-mode opcodes - use camel-case naming on memory.hpp functions - simplify address masking code for memory.hpp functions - simplify a few opcodes themselves (avoid redundant copies, etc) - rename regs.* to r.* to match modern convention of other CPU cores - removed device.order<> concept from Emulator::Interface - cores will now do the translation to make the job of the UI easier - fixed plurality naming of arrays in Emulator::Interface - example: emulator.ports[p].devices[d].inputs[i] - example: vector<Medium> media - probably more surprises Major show-stoppers to the next official release: - we need to work on GB core improvements: LY=153/0 case, multiple STAT IRQs case, GBC audio output regs, etc. - we need to re-add software cursors for light guns (Super Scope, Justifier) - after the above, we need to fix the turbo button for the Super Scope I really have no idea how I want to implement the light guns. Ideally, we'd want it in higan/video, so we can support the NES Zapper with the same code. But this isn't going to be easy, because only the SNES knows when its output is interlaced, and its resolutions can vary as {256,512}x{224,240,448,480} which requires pixel doubling that was hard-coded to the SNES-specific behavior, but isn't appropriate to be exposed in higan/video.
2016-05-25 11:13:02 +00:00
uint8 v = (r.mdr & 0x70);
v |= (uint8)(rdnmi()) << 7;
v |= (cpu_version & 0x0f);
return v;
}
//TIMEUP
if(addr == 0x4211) {
//7 = IRQ acknowledge
//6-0 = MDR
Update to v098r11 release. byuu says: Changelog: - fixed nall/path.hpp compilation issue - fixed ruby/audio/xaudio header declaration compilation issue (again) - cleaned up xaudio2.hpp file to match my coding syntax (12.5% of the file was whitespace overkill) - added null terminator entry to nall/windows/utf8.hpp argc[] array - nall/windows/guid.hpp uses the Windows API for generating the GUID - this should stop all the bug reports where two nall users were generating GUIDs at the exact same second - fixed hiro/cocoa compilation issue with uint# types - fixed major higan/sfc Super Game Boy audio latency issue - fixed higan/sfc CPU core bug with pei, [dp], [dp]+y instructions - major cleanups to higan/processor/r65816 core - merged emulation/native-mode opcodes - use camel-case naming on memory.hpp functions - simplify address masking code for memory.hpp functions - simplify a few opcodes themselves (avoid redundant copies, etc) - rename regs.* to r.* to match modern convention of other CPU cores - removed device.order<> concept from Emulator::Interface - cores will now do the translation to make the job of the UI easier - fixed plurality naming of arrays in Emulator::Interface - example: emulator.ports[p].devices[d].inputs[i] - example: vector<Medium> media - probably more surprises Major show-stoppers to the next official release: - we need to work on GB core improvements: LY=153/0 case, multiple STAT IRQs case, GBC audio output regs, etc. - we need to re-add software cursors for light guns (Super Scope, Justifier) - after the above, we need to fix the turbo button for the Super Scope I really have no idea how I want to implement the light guns. Ideally, we'd want it in higan/video, so we can support the NES Zapper with the same code. But this isn't going to be easy, because only the SNES knows when its output is interlaced, and its resolutions can vary as {256,512}x{224,240,448,480} which requires pixel doubling that was hard-coded to the SNES-specific behavior, but isn't appropriate to be exposed in higan/video.
2016-05-25 11:13:02 +00:00
uint8 v = (r.mdr & 0x7f);
v |= (uint8)(timeup()) << 7;
return v;
}
//HVBJOY
if(addr == 0x4212) {
//7 = VBLANK acknowledge
//6 = HBLANK acknowledge
//5-1 = MDR
//0 = JOYPAD acknowledge
Update to v098r11 release. byuu says: Changelog: - fixed nall/path.hpp compilation issue - fixed ruby/audio/xaudio header declaration compilation issue (again) - cleaned up xaudio2.hpp file to match my coding syntax (12.5% of the file was whitespace overkill) - added null terminator entry to nall/windows/utf8.hpp argc[] array - nall/windows/guid.hpp uses the Windows API for generating the GUID - this should stop all the bug reports where two nall users were generating GUIDs at the exact same second - fixed hiro/cocoa compilation issue with uint# types - fixed major higan/sfc Super Game Boy audio latency issue - fixed higan/sfc CPU core bug with pei, [dp], [dp]+y instructions - major cleanups to higan/processor/r65816 core - merged emulation/native-mode opcodes - use camel-case naming on memory.hpp functions - simplify address masking code for memory.hpp functions - simplify a few opcodes themselves (avoid redundant copies, etc) - rename regs.* to r.* to match modern convention of other CPU cores - removed device.order<> concept from Emulator::Interface - cores will now do the translation to make the job of the UI easier - fixed plurality naming of arrays in Emulator::Interface - example: emulator.ports[p].devices[d].inputs[i] - example: vector<Medium> media - probably more surprises Major show-stoppers to the next official release: - we need to work on GB core improvements: LY=153/0 case, multiple STAT IRQs case, GBC audio output regs, etc. - we need to re-add software cursors for light guns (Super Scope, Justifier) - after the above, we need to fix the turbo button for the Super Scope I really have no idea how I want to implement the light guns. Ideally, we'd want it in higan/video, so we can support the NES Zapper with the same code. But this isn't going to be easy, because only the SNES knows when its output is interlaced, and its resolutions can vary as {256,512}x{224,240,448,480} which requires pixel doubling that was hard-coded to the SNES-specific behavior, but isn't appropriate to be exposed in higan/video.
2016-05-25 11:13:02 +00:00
uint8 v = (r.mdr & 0x3e);
if(status.auto_joypad_active) v |= 0x01;
if(hcounter() <= 2 || hcounter() >= 1096) v |= 0x40; //hblank
if(vcounter() >= ppu.vdisp()) v |= 0x80; //vblank
return v;
}
//RDIO
if(addr == 0x4213) {
return status.pio;
}
//RDDIVL
if(addr == 0x4214) {
return status.rddiv.byte(0);
}
//RDDIVH
if(addr == 0x4215) {
return status.rddiv.byte(1);
}
//RDMPYL
if(addr == 0x4216) {
return status.rdmpy.byte(0);
}
//RDMPYH
if(addr == 0x4217) {
return status.rdmpy.byte(1);
}
if(addr == 0x4218) return status.joy1.byte(0); //JOY1L
if(addr == 0x4219) return status.joy1.byte(1); //JOY1H
if(addr == 0x421a) return status.joy2.byte(0); //JOY2L
if(addr == 0x421b) return status.joy2.byte(1); //JOY2H
if(addr == 0x421c) return status.joy3.byte(0); //JOY3L
if(addr == 0x421d) return status.joy3.byte(1); //JOY3H
if(addr == 0x421e) return status.joy4.byte(0); //JOY4L
if(addr == 0x421f) return status.joy4.byte(1); //JOY4H
return data;
}
auto CPU::dmaPortRead(uint24 addr, uint8 data) -> uint8 {
auto& channel = this->channel[addr.bits(4,6)];
addr &= 0xff0f;
//DMAPx
if(addr == 0x4300) return (
channel.direction << 7
| channel.indirect << 6
| channel.unused << 5
| channel.reverse_transfer << 4
| channel.fixed_transfer << 3
| channel.transfer_mode << 0
);
//BBADx
if(addr == 0x4301) return channel.dest_addr;
//A1TxL
if(addr == 0x4302) return channel.source_addr >> 0;
//A1TxH
if(addr == 0x4303) return channel.source_addr >> 8;
//A1Bx
if(addr == 0x4304) return channel.source_bank;
//DASxL -- union { uint16 transfer_size; uint16 indirect_addr; };
if(addr == 0x4305) return channel.transfer_size >> 0;
//DASxH -- union { uint16 transfer_size; uint16 indirect_addr; };
if(addr == 0x4306) return channel.transfer_size >> 8;
//DASBx
if(addr == 0x4307) return channel.indirect_bank;
//A2AxL
if(addr == 0x4308) return channel.hdma_addr >> 0;
//A2AxH
if(addr == 0x4309) return channel.hdma_addr >> 8;
//NTRLx
if(addr == 0x430a) return channel.line_counter;
//???
if(addr == 0x430b || addr == 0x430f) return channel.unknown;
return data;
}
auto CPU::apuPortWrite(uint24 addr, uint8 data) -> void {
synchronizeSMP();
return portWrite(addr.bits(0,1), data);
}
auto CPU::cpuPortWrite(uint24 addr, uint8 data) -> void {
addr &= 0xffff;
//WMDATA
if(addr == 0x2180) {
bus.write(0x7e0000 | status.wram_addr++, data);
}
//WMADDL
if(addr == 0x2181) {
status.wram_addr.bits(0,7) = data;
}
//WMADDM
if(addr == 0x2182) {
status.wram_addr.bits(8,15) = data;
}
//WMADDH
if(addr == 0x2183) {
status.wram_addr.bit(16) = data.bit(0);
}
//JOYSER0
if(addr == 0x4016) {
//bit 0 is shared between JOYSER0 and JOYSER1, therefore
//strobing $4016.d0 affects both controller port latches.
//$4017 bit 0 writes are ignored.
Update to v098r03 release. byuu says: It took several hours, but I've rebuilt much of the SNES' bus memory mapping architecture. The new design unifies the cartridge string-based mapping ("00-3f,80-bf:8000-ffff") and internal bus.map calls. The map() function now has an accompanying unmap() function, and instead of a fixed 256 callbacks, it'll scan to find the first available slot. unmap() will free slots up when zero addresses reference a given slot. The controllers and expansion port are now both entirely dynamic. Instead of load/unload/power/reset, they only have the constructor (power/reset/load) and destructor (unload). What this means is you can now dynamically change even expansion port devices after the system is loaded. Note that this is incredibly dangerous and stupid, but ... oh well. The whole point of this was for 21fx. There's no way to change the expansion port device prior to loading a game, but if the 21fx isn't active, then the reset vector hijack won't work. Now you can load a 21fx game, change the expansion port device, and simply reset the system to active the device. The unification of design between controller port devices and expansion port devices is nice, and overall this results in a reduction of code (all of the Mapping stuff in Cartridge is gone, replaced with direct bus mapping.) And there's always the potential to expand this system more in the future now. The big missing feature right now is the ability to push/pop mappings. So if you look at how the 21fx does the reset vector, you might vomit a little bit. But ... it works. Also changed exit(0) to _exit(0) in the POSIX version of nall::execute. [The _exit(0) thing is an attempt to make higan not crash when it tries to launch icarus and it's not on $PATH. The theory is that higan forks, then the child tries to exec icarus and fails, so it exits, all the unique_ptrs clean up their resources and tell the X server to free things the parent process is still using. Calling _exit() prevents destructors from running, and seems to prevent the problem. -Ed.]
2016-04-09 10:21:18 +00:00
SuperFamicom::peripherals.controllerPort1->latch(data.bit(0));
SuperFamicom::peripherals.controllerPort2->latch(data.bit(0));
}
//NMITIMEN
if(addr == 0x4200) {
status.auto_joypad_poll = data.bit(0);
nmitimenUpdate(data);
}
//WRIO
if(addr == 0x4201) {
if(status.pio.bit(7) && !data.bit(7)) ppu.latchCounters();
status.pio = data;
}
//WRMPYA
if(addr == 0x4202) {
status.wrmpya = data;
}
//WRMPYB
if(addr == 0x4203) {
status.rdmpy = 0;
if(alu.mpyctr || alu.divctr) return;
status.wrmpyb = data;
status.rddiv = (status.wrmpyb << 8) | status.wrmpya;
alu.mpyctr = 8; //perform multiplication over the next eight cycles
alu.shift = status.wrmpyb;
}
//WRDIVL
if(addr == 0x4204) {
status.wrdiva.byte(0) = data;
}
//WRDIVH
if(addr == 0x4205) {
status.wrdiva.byte(1) = data;
}
//WRDIVB
if(addr == 0x4206) {
status.rdmpy = status.wrdiva;
if(alu.mpyctr || alu.divctr) return;
status.wrdivb = data;
alu.divctr = 16; //perform division over the next sixteen cycles
alu.shift = status.wrdivb << 16;
}
//HTIMEL
if(addr == 0x4207) {
status.hirq_pos.bits(0,7) = data;
}
//HTIMEH
if(addr == 0x4208) {
status.hirq_pos.bit(8) = data.bit(0);
}
//VTIMEL
if(addr == 0x4209) {
status.virq_pos.bits(0,7) = data;
}
//VTIMEH
if(addr == 0x420a) {
status.virq_pos.bit(8) = data;
}
//DMAEN
if(addr == 0x420b) {
for(auto n : range(8)) channel[n].dma_enabled = data.bit(n);
if(data) status.dma_pending = true;
}
//HDMAEN
if(addr == 0x420c) {
for(auto n : range(8)) channel[n].hdma_enabled = data.bit(n);
}
//MEMSEL
if(addr == 0x420d) {
status.rom_speed = data.bit(0) ? 6 : 8;
}
}
auto CPU::dmaPortWrite(uint24 addr, uint8 data) -> void {
auto& channel = this->channel[addr.bits(4,6)];
addr &= 0xff0f;
//DMAPx
if(addr == 0x4300) {
channel.direction = data & 0x80;
channel.indirect = data & 0x40;
channel.unused = data & 0x20;
channel.reverse_transfer = data & 0x10;
channel.fixed_transfer = data & 0x08;
channel.transfer_mode = data & 0x07;
}
//DDBADx
if(addr == 0x4301) {
channel.dest_addr = data;
}
//A1TxL
if(addr == 0x4302) {
channel.source_addr = (channel.source_addr & 0xff00) | (data << 0);
}
//A1TxH
if(addr == 0x4303) {
channel.source_addr = (channel.source_addr & 0x00ff) | (data << 8);
}
//A1Bx
if(addr == 0x4304) {
channel.source_bank = data;
}
//DASxL -- union { uint16 transfer_size; uint16 indirect_addr; };
if(addr == 0x4305) {
channel.transfer_size = (channel.transfer_size & 0xff00) | (data << 0);
}
//DASxH -- union { uint16 transfer_size; uint16 indirect_addr; };
if(addr == 0x4306) {
channel.transfer_size = (channel.transfer_size & 0x00ff) | (data << 8);
}
//DASBx
if(addr == 0x4307) {
channel.indirect_bank = data;
}
//A2AxL
if(addr == 0x4308) {
channel.hdma_addr = (channel.hdma_addr & 0xff00) | (data << 0);
}
//A2AxH
if(addr == 0x4309) {
channel.hdma_addr = (channel.hdma_addr & 0x00ff) | (data << 8);
}
//NTRLx
if(addr == 0x430a) {
channel.line_counter = data;
}
//???
if(addr == 0x430b || addr == 0x430f) {
channel.unknown = data;
}
}