bsnes/higan/sfc/cpu/cpu.cpp

277 lines
6.7 KiB
C++
Raw Normal View History

#include <sfc/sfc.hpp>
namespace SuperFamicom {
CPU cpu;
#include "dma.cpp"
#include "memory.cpp"
#include "mmio.cpp"
#include "timing.cpp"
#include "irq.cpp"
#include "joypad.cpp"
#include "serialization.cpp"
auto CPU::interruptPending() const -> bool { return status.interrupt_pending; }
auto CPU::pio() const -> uint8 { return status.pio; }
auto CPU::joylatch() const -> bool { return status.joypad_strobe_latch; }
CPU::CPU() {
PPUcounter::scanline = {&CPU::scanline, this};
}
auto CPU::step(uint clocks) -> void {
smp.clock -= clocks * (uint64)smp.frequency;
ppu.clock -= clocks;
Update to v098r01 release. byuu says: Changelog: - SFC: balanced profile removed - SFC: performance profile removed - SFC: code for handling non-threaded CPU, SMP, DSP, PPU removed - SFC: Coprocessor, Controller (and expansion port) shared Thread code merged to SFC::Cothread - Cothread here just means "Thread with CPU affinity" (couldn't think of a better name, sorry) - SFC: CPU now has vector<Thread*> coprocessors, peripherals; - this is the beginning of work to allow expansion port devices to be dynamically changed at run-time - ruby: all audio drivers default to 48000hz instead of 22050hz now if no frequency is assigned - note: the WASAPI driver can default to whatever the native frequency is; doesn't have to be 48000hz - tomoko: removed the ability to change the frequency from the UI (but it will display the frequency used) - tomoko: removed the timing settings panel - the goal is to work toward smooth video via adaptive sync - the model is broken by not being in control of the audio frequency anyway - it's further broken by PAL running at 50hz and WSC running at 75hz - it was always broken anyway by SNES interlace timing varying from progressive timing - higan: audio/ stub created (for now, it's just nall/dsp/ moved here and included as a header) - higan: video/ stub created - higan/GNUmakefile: now includes build rules for essential components (libco, emulator, audio, video) The audio changes are in preparation to merge wareya's awesome WASAPI work without the need for the nall/dsp resampler.
2016-04-09 03:40:12 +00:00
for(auto coprocessor : coprocessors) {
coprocessor->clock -= clocks * (uint64)coprocessor->frequency;
}
Update to v098r01 release. byuu says: Changelog: - SFC: balanced profile removed - SFC: performance profile removed - SFC: code for handling non-threaded CPU, SMP, DSP, PPU removed - SFC: Coprocessor, Controller (and expansion port) shared Thread code merged to SFC::Cothread - Cothread here just means "Thread with CPU affinity" (couldn't think of a better name, sorry) - SFC: CPU now has vector<Thread*> coprocessors, peripherals; - this is the beginning of work to allow expansion port devices to be dynamically changed at run-time - ruby: all audio drivers default to 48000hz instead of 22050hz now if no frequency is assigned - note: the WASAPI driver can default to whatever the native frequency is; doesn't have to be 48000hz - tomoko: removed the ability to change the frequency from the UI (but it will display the frequency used) - tomoko: removed the timing settings panel - the goal is to work toward smooth video via adaptive sync - the model is broken by not being in control of the audio frequency anyway - it's further broken by PAL running at 50hz and WSC running at 75hz - it was always broken anyway by SNES interlace timing varying from progressive timing - higan: audio/ stub created (for now, it's just nall/dsp/ moved here and included as a header) - higan: video/ stub created - higan/GNUmakefile: now includes build rules for essential components (libco, emulator, audio, video) The audio changes are in preparation to merge wareya's awesome WASAPI work without the need for the nall/dsp resampler.
2016-04-09 03:40:12 +00:00
for(auto peripheral : peripherals) {
peripheral->clock -= clocks * (uint64)peripheral->frequency;
}
synchronizePeripherals();
}
auto CPU::synchronizeSMP() -> void {
Update to v098r01 release. byuu says: Changelog: - SFC: balanced profile removed - SFC: performance profile removed - SFC: code for handling non-threaded CPU, SMP, DSP, PPU removed - SFC: Coprocessor, Controller (and expansion port) shared Thread code merged to SFC::Cothread - Cothread here just means "Thread with CPU affinity" (couldn't think of a better name, sorry) - SFC: CPU now has vector<Thread*> coprocessors, peripherals; - this is the beginning of work to allow expansion port devices to be dynamically changed at run-time - ruby: all audio drivers default to 48000hz instead of 22050hz now if no frequency is assigned - note: the WASAPI driver can default to whatever the native frequency is; doesn't have to be 48000hz - tomoko: removed the ability to change the frequency from the UI (but it will display the frequency used) - tomoko: removed the timing settings panel - the goal is to work toward smooth video via adaptive sync - the model is broken by not being in control of the audio frequency anyway - it's further broken by PAL running at 50hz and WSC running at 75hz - it was always broken anyway by SNES interlace timing varying from progressive timing - higan: audio/ stub created (for now, it's just nall/dsp/ moved here and included as a header) - higan: video/ stub created - higan/GNUmakefile: now includes build rules for essential components (libco, emulator, audio, video) The audio changes are in preparation to merge wareya's awesome WASAPI work without the need for the nall/dsp resampler.
2016-04-09 03:40:12 +00:00
if(smp.clock < 0) co_switch(smp.thread);
}
auto CPU::synchronizePPU() -> void {
Update to v098r01 release. byuu says: Changelog: - SFC: balanced profile removed - SFC: performance profile removed - SFC: code for handling non-threaded CPU, SMP, DSP, PPU removed - SFC: Coprocessor, Controller (and expansion port) shared Thread code merged to SFC::Cothread - Cothread here just means "Thread with CPU affinity" (couldn't think of a better name, sorry) - SFC: CPU now has vector<Thread*> coprocessors, peripherals; - this is the beginning of work to allow expansion port devices to be dynamically changed at run-time - ruby: all audio drivers default to 48000hz instead of 22050hz now if no frequency is assigned - note: the WASAPI driver can default to whatever the native frequency is; doesn't have to be 48000hz - tomoko: removed the ability to change the frequency from the UI (but it will display the frequency used) - tomoko: removed the timing settings panel - the goal is to work toward smooth video via adaptive sync - the model is broken by not being in control of the audio frequency anyway - it's further broken by PAL running at 50hz and WSC running at 75hz - it was always broken anyway by SNES interlace timing varying from progressive timing - higan: audio/ stub created (for now, it's just nall/dsp/ moved here and included as a header) - higan: video/ stub created - higan/GNUmakefile: now includes build rules for essential components (libco, emulator, audio, video) The audio changes are in preparation to merge wareya's awesome WASAPI work without the need for the nall/dsp resampler.
2016-04-09 03:40:12 +00:00
if(ppu.clock < 0) co_switch(ppu.thread);
}
auto CPU::synchronizeCoprocessors() -> void {
Update to v098r01 release. byuu says: Changelog: - SFC: balanced profile removed - SFC: performance profile removed - SFC: code for handling non-threaded CPU, SMP, DSP, PPU removed - SFC: Coprocessor, Controller (and expansion port) shared Thread code merged to SFC::Cothread - Cothread here just means "Thread with CPU affinity" (couldn't think of a better name, sorry) - SFC: CPU now has vector<Thread*> coprocessors, peripherals; - this is the beginning of work to allow expansion port devices to be dynamically changed at run-time - ruby: all audio drivers default to 48000hz instead of 22050hz now if no frequency is assigned - note: the WASAPI driver can default to whatever the native frequency is; doesn't have to be 48000hz - tomoko: removed the ability to change the frequency from the UI (but it will display the frequency used) - tomoko: removed the timing settings panel - the goal is to work toward smooth video via adaptive sync - the model is broken by not being in control of the audio frequency anyway - it's further broken by PAL running at 50hz and WSC running at 75hz - it was always broken anyway by SNES interlace timing varying from progressive timing - higan: audio/ stub created (for now, it's just nall/dsp/ moved here and included as a header) - higan: video/ stub created - higan/GNUmakefile: now includes build rules for essential components (libco, emulator, audio, video) The audio changes are in preparation to merge wareya's awesome WASAPI work without the need for the nall/dsp resampler.
2016-04-09 03:40:12 +00:00
for(auto coprocessor : coprocessors) {
if(coprocessor->clock < 0) co_switch(coprocessor->thread);
}
}
Update to v098r01 release. byuu says: Changelog: - SFC: balanced profile removed - SFC: performance profile removed - SFC: code for handling non-threaded CPU, SMP, DSP, PPU removed - SFC: Coprocessor, Controller (and expansion port) shared Thread code merged to SFC::Cothread - Cothread here just means "Thread with CPU affinity" (couldn't think of a better name, sorry) - SFC: CPU now has vector<Thread*> coprocessors, peripherals; - this is the beginning of work to allow expansion port devices to be dynamically changed at run-time - ruby: all audio drivers default to 48000hz instead of 22050hz now if no frequency is assigned - note: the WASAPI driver can default to whatever the native frequency is; doesn't have to be 48000hz - tomoko: removed the ability to change the frequency from the UI (but it will display the frequency used) - tomoko: removed the timing settings panel - the goal is to work toward smooth video via adaptive sync - the model is broken by not being in control of the audio frequency anyway - it's further broken by PAL running at 50hz and WSC running at 75hz - it was always broken anyway by SNES interlace timing varying from progressive timing - higan: audio/ stub created (for now, it's just nall/dsp/ moved here and included as a header) - higan: video/ stub created - higan/GNUmakefile: now includes build rules for essential components (libco, emulator, audio, video) The audio changes are in preparation to merge wareya's awesome WASAPI work without the need for the nall/dsp resampler.
2016-04-09 03:40:12 +00:00
auto CPU::synchronizePeripherals() -> void {
for(auto peripheral : peripherals) {
if(peripheral->clock < 0) co_switch(peripheral->thread);
}
}
auto CPU::Enter() -> void {
while(true) scheduler.synchronize(), cpu.main();
}
auto CPU::main() -> void {
if(status.interrupt_pending) {
status.interrupt_pending = false;
if(status.nmi_pending) {
status.nmi_pending = false;
Update to v097r32 release. byuu says: Changelog: - bsnes-accuracy emulates reset vector properly[1] - bsnes-balanced compiles once more - bsnes-performance compiles once more The balanced and performance profiles are fixed for the last time. They will be removed for v098r01. Please test this WIP as much as you can. I intend to release v098 soon. I know save states are a little unstable for the WS/WSC, but they work well enough for a release. If I can't figure it out soon, I'm going to post v098 anyway. [1] this one's been a really long time coming, but ... one of the bugs I found when I translated Tekkaman Blade was that my translation patch would crash every now and again when you hit the reset button on a real SNES, but it always worked upon power on. Turns out that while power-on initializes the stack register to $01ff, reset does things a little bit differently. Reset actually triggers the reset interrupt vector after putting the CPU into emulation mode, but it doesn't initialize the stack pointer. The net effect is that the stack high byte is set to $01, and the low byte is left as it was. And then the reset vector runs, which pushes the low 16-bits of the program counter, plus the processor flags, onto the stack frame. So you can actually tell where the game was at when the system was reset ... sort of. It's a really weird behavior to be sure. But here's the catch: say you're hacking a game, and so you hook the reset vector with jsl showMyTranslationCreditsSplashScreen, and inside this new subroutine, you then perform whatever bytes you hijacked, and then initialize the stack frame to go about your business drawing the screen, and when you're done, you return via rtl. Generally, this works fine. But if S={0100, 0101, or 0102}, then the stack will wrap due to being in emulation mode at reset. So it will write to {0100, 01ff, 01fe}. But now in your subroutine, you enable native mode. So when you return from your subroutine hijack, it reads the return address from {01ff, 0200, 0201} instead of the expected {01ff, 0100, 0101}. Thus, you get an invalid address back, and you "return" to the wrong location, and your program dies. The odds of this happening depend on how the game handles S, but generally speaking, it's a ~1:85 chance. By emulating this behavior, I'll likely expose this bug in many ROM hacks that do splash screen hooks like this, including my own Tekkaman Blade translation. And it's also very possible that there are commercial games that screw this up as well. But, it's what the real system does. So if any crashes start happening as of this WIP upon resetting the game, well ... it'd happen on real hardware, too.
2016-04-03 11:17:20 +00:00
regs.vector = !regs.e ? 0xffea : 0xfffa;
interrupt();
debugger.op_nmi();
} else if(status.irq_pending) {
status.irq_pending = false;
Update to v097r32 release. byuu says: Changelog: - bsnes-accuracy emulates reset vector properly[1] - bsnes-balanced compiles once more - bsnes-performance compiles once more The balanced and performance profiles are fixed for the last time. They will be removed for v098r01. Please test this WIP as much as you can. I intend to release v098 soon. I know save states are a little unstable for the WS/WSC, but they work well enough for a release. If I can't figure it out soon, I'm going to post v098 anyway. [1] this one's been a really long time coming, but ... one of the bugs I found when I translated Tekkaman Blade was that my translation patch would crash every now and again when you hit the reset button on a real SNES, but it always worked upon power on. Turns out that while power-on initializes the stack register to $01ff, reset does things a little bit differently. Reset actually triggers the reset interrupt vector after putting the CPU into emulation mode, but it doesn't initialize the stack pointer. The net effect is that the stack high byte is set to $01, and the low byte is left as it was. And then the reset vector runs, which pushes the low 16-bits of the program counter, plus the processor flags, onto the stack frame. So you can actually tell where the game was at when the system was reset ... sort of. It's a really weird behavior to be sure. But here's the catch: say you're hacking a game, and so you hook the reset vector with jsl showMyTranslationCreditsSplashScreen, and inside this new subroutine, you then perform whatever bytes you hijacked, and then initialize the stack frame to go about your business drawing the screen, and when you're done, you return via rtl. Generally, this works fine. But if S={0100, 0101, or 0102}, then the stack will wrap due to being in emulation mode at reset. So it will write to {0100, 01ff, 01fe}. But now in your subroutine, you enable native mode. So when you return from your subroutine hijack, it reads the return address from {01ff, 0200, 0201} instead of the expected {01ff, 0100, 0101}. Thus, you get an invalid address back, and you "return" to the wrong location, and your program dies. The odds of this happening depend on how the game handles S, but generally speaking, it's a ~1:85 chance. By emulating this behavior, I'll likely expose this bug in many ROM hacks that do splash screen hooks like this, including my own Tekkaman Blade translation. And it's also very possible that there are commercial games that screw this up as well. But, it's what the real system does. So if any crashes start happening as of this WIP upon resetting the game, well ... it'd happen on real hardware, too.
2016-04-03 11:17:20 +00:00
regs.vector = !regs.e ? 0xffee : 0xfffe;
interrupt();
debugger.op_irq();
} else if(status.reset_pending) {
status.reset_pending = false;
Update to v097r32 release. byuu says: Changelog: - bsnes-accuracy emulates reset vector properly[1] - bsnes-balanced compiles once more - bsnes-performance compiles once more The balanced and performance profiles are fixed for the last time. They will be removed for v098r01. Please test this WIP as much as you can. I intend to release v098 soon. I know save states are a little unstable for the WS/WSC, but they work well enough for a release. If I can't figure it out soon, I'm going to post v098 anyway. [1] this one's been a really long time coming, but ... one of the bugs I found when I translated Tekkaman Blade was that my translation patch would crash every now and again when you hit the reset button on a real SNES, but it always worked upon power on. Turns out that while power-on initializes the stack register to $01ff, reset does things a little bit differently. Reset actually triggers the reset interrupt vector after putting the CPU into emulation mode, but it doesn't initialize the stack pointer. The net effect is that the stack high byte is set to $01, and the low byte is left as it was. And then the reset vector runs, which pushes the low 16-bits of the program counter, plus the processor flags, onto the stack frame. So you can actually tell where the game was at when the system was reset ... sort of. It's a really weird behavior to be sure. But here's the catch: say you're hacking a game, and so you hook the reset vector with jsl showMyTranslationCreditsSplashScreen, and inside this new subroutine, you then perform whatever bytes you hijacked, and then initialize the stack frame to go about your business drawing the screen, and when you're done, you return via rtl. Generally, this works fine. But if S={0100, 0101, or 0102}, then the stack will wrap due to being in emulation mode at reset. So it will write to {0100, 01ff, 01fe}. But now in your subroutine, you enable native mode. So when you return from your subroutine hijack, it reads the return address from {01ff, 0200, 0201} instead of the expected {01ff, 0100, 0101}. Thus, you get an invalid address back, and you "return" to the wrong location, and your program dies. The odds of this happening depend on how the game handles S, but generally speaking, it's a ~1:85 chance. By emulating this behavior, I'll likely expose this bug in many ROM hacks that do splash screen hooks like this, including my own Tekkaman Blade translation. And it's also very possible that there are commercial games that screw this up as well. But, it's what the real system does. So if any crashes start happening as of this WIP upon resetting the game, well ... it'd happen on real hardware, too.
2016-04-03 11:17:20 +00:00
addClocks(132);
regs.vector = 0xfffc;
interrupt();
} else if(status.power_pending) {
status.power_pending = false;
addClocks(186);
regs.pc.l = bus.read(0xfffc, regs.mdr);
regs.pc.h = bus.read(0xfffd, regs.mdr);
}
}
debugger.op_exec(regs.pc.d);
instruction();
}
auto CPU::enable() -> void {
function<auto (uint24, uint8) -> uint8> reader;
function<auto (uint24, uint8) -> void> writer;
reader = {&CPU::apuPortRead, this};
writer = {&CPU::apuPortWrite, this};
bus.map(reader, writer, 0x00, 0x3f, 0x2140, 0x217f);
bus.map(reader, writer, 0x80, 0xbf, 0x2140, 0x217f);
reader = {&CPU::cpuPortRead, this};
writer = {&CPU::cpuPortWrite, this};
bus.map(reader, writer, 0x00, 0x3f, 0x2180, 0x2183);
bus.map(reader, writer, 0x80, 0xbf, 0x2180, 0x2183);
Update to v091r05 release. [No prior releases were posted to the WIP thread. -Ed.] byuu says: Super Famicom mapping system has been reworked as discussed with the mask= changes. offset becomes base, mode is gone. Also added support for comma-separated fields in the address fields, to reduce the number of map lines needed. <?xml version="1.0" encoding="UTF-8"?> <cartridge region="NTSC"> <superfx revision="2"> <rom name="program.rom" size="0x200000"/> <ram name="save.rwm" size="0x8000"/> <map id="io" address="00-3f,80-bf:3000-32ff"/> <map id="rom" address="00-3f:8000-ffff" mask="0x8000"/> <map id="rom" address="40-5f:0000-ffff"/> <map id="ram" address="00-3f,80-bf:6000-7fff" size="0x2000"/> <map id="ram" address="70-71:0000-ffff"/> </superfx> </cartridge> Or in BML: cartridge region=NTSC superfx revision=2 rom name=program.rom size=0x200000 ram name=save.rwm size=0x8000 map id=io address=00-3f,80-bf:3000-32ff map id=rom address=00-3f:8000-ffff mask=0x8000 map id=rom address=40-5f:0000-ffff map id=ram address=00-3f,80-bf:6000-7fff size=0x2000 map id=ram address=70-71:0000-ffff As a result of the changes, old mappings will no longer work. The above XML example will run Super Mario World 2: Yoshi's Island. Otherwise, you'll have to write your own. All that's left now is to work some sort of database mapping system in, so I can start dumping carts en masse. The NES changes that FitzRoy asked for are mostly in as well. Also, part of the reason I haven't released a WIP ... but fuck it, I'm not going to wait forever to post a new WIP. I've added a skeleton driver to emulate Campus Challenge '92 and Powerfest '94. There's no actual emulation, except for the stuff I can glean from looking at the pictures of the board. It has a DSP-1 (so SR/DR registers), four ROMs that map in and out, RAM, etc. I've also added preliminary mapping to upload high scores to a website, but obviously I need the ROMs first.
2012-10-09 08:25:32 +00:00
bus.map(reader, writer, 0x00, 0x3f, 0x4016, 0x4017);
bus.map(reader, writer, 0x80, 0xbf, 0x4016, 0x4017);
Update to v091r05 release. [No prior releases were posted to the WIP thread. -Ed.] byuu says: Super Famicom mapping system has been reworked as discussed with the mask= changes. offset becomes base, mode is gone. Also added support for comma-separated fields in the address fields, to reduce the number of map lines needed. <?xml version="1.0" encoding="UTF-8"?> <cartridge region="NTSC"> <superfx revision="2"> <rom name="program.rom" size="0x200000"/> <ram name="save.rwm" size="0x8000"/> <map id="io" address="00-3f,80-bf:3000-32ff"/> <map id="rom" address="00-3f:8000-ffff" mask="0x8000"/> <map id="rom" address="40-5f:0000-ffff"/> <map id="ram" address="00-3f,80-bf:6000-7fff" size="0x2000"/> <map id="ram" address="70-71:0000-ffff"/> </superfx> </cartridge> Or in BML: cartridge region=NTSC superfx revision=2 rom name=program.rom size=0x200000 ram name=save.rwm size=0x8000 map id=io address=00-3f,80-bf:3000-32ff map id=rom address=00-3f:8000-ffff mask=0x8000 map id=rom address=40-5f:0000-ffff map id=ram address=00-3f,80-bf:6000-7fff size=0x2000 map id=ram address=70-71:0000-ffff As a result of the changes, old mappings will no longer work. The above XML example will run Super Mario World 2: Yoshi's Island. Otherwise, you'll have to write your own. All that's left now is to work some sort of database mapping system in, so I can start dumping carts en masse. The NES changes that FitzRoy asked for are mostly in as well. Also, part of the reason I haven't released a WIP ... but fuck it, I'm not going to wait forever to post a new WIP. I've added a skeleton driver to emulate Campus Challenge '92 and Powerfest '94. There's no actual emulation, except for the stuff I can glean from looking at the pictures of the board. It has a DSP-1 (so SR/DR registers), four ROMs that map in and out, RAM, etc. I've also added preliminary mapping to upload high scores to a website, but obviously I need the ROMs first.
2012-10-09 08:25:32 +00:00
bus.map(reader, writer, 0x00, 0x3f, 0x4200, 0x421f);
bus.map(reader, writer, 0x80, 0xbf, 0x4200, 0x421f);
reader = {&CPU::dmaPortRead, this};
writer = {&CPU::dmaPortWrite, this};
Update to v091r05 release. [No prior releases were posted to the WIP thread. -Ed.] byuu says: Super Famicom mapping system has been reworked as discussed with the mask= changes. offset becomes base, mode is gone. Also added support for comma-separated fields in the address fields, to reduce the number of map lines needed. <?xml version="1.0" encoding="UTF-8"?> <cartridge region="NTSC"> <superfx revision="2"> <rom name="program.rom" size="0x200000"/> <ram name="save.rwm" size="0x8000"/> <map id="io" address="00-3f,80-bf:3000-32ff"/> <map id="rom" address="00-3f:8000-ffff" mask="0x8000"/> <map id="rom" address="40-5f:0000-ffff"/> <map id="ram" address="00-3f,80-bf:6000-7fff" size="0x2000"/> <map id="ram" address="70-71:0000-ffff"/> </superfx> </cartridge> Or in BML: cartridge region=NTSC superfx revision=2 rom name=program.rom size=0x200000 ram name=save.rwm size=0x8000 map id=io address=00-3f,80-bf:3000-32ff map id=rom address=00-3f:8000-ffff mask=0x8000 map id=rom address=40-5f:0000-ffff map id=ram address=00-3f,80-bf:6000-7fff size=0x2000 map id=ram address=70-71:0000-ffff As a result of the changes, old mappings will no longer work. The above XML example will run Super Mario World 2: Yoshi's Island. Otherwise, you'll have to write your own. All that's left now is to work some sort of database mapping system in, so I can start dumping carts en masse. The NES changes that FitzRoy asked for are mostly in as well. Also, part of the reason I haven't released a WIP ... but fuck it, I'm not going to wait forever to post a new WIP. I've added a skeleton driver to emulate Campus Challenge '92 and Powerfest '94. There's no actual emulation, except for the stuff I can glean from looking at the pictures of the board. It has a DSP-1 (so SR/DR registers), four ROMs that map in and out, RAM, etc. I've also added preliminary mapping to upload high scores to a website, but obviously I need the ROMs first.
2012-10-09 08:25:32 +00:00
bus.map(reader, writer, 0x00, 0x3f, 0x4300, 0x437f);
bus.map(reader, writer, 0x80, 0xbf, 0x4300, 0x437f);
reader = [](uint24 addr, uint8) -> uint8 { return cpu.wram[addr]; };
writer = [](uint24 addr, uint8 data) -> void { cpu.wram[addr] = data; };
Update to v091r05 release. [No prior releases were posted to the WIP thread. -Ed.] byuu says: Super Famicom mapping system has been reworked as discussed with the mask= changes. offset becomes base, mode is gone. Also added support for comma-separated fields in the address fields, to reduce the number of map lines needed. <?xml version="1.0" encoding="UTF-8"?> <cartridge region="NTSC"> <superfx revision="2"> <rom name="program.rom" size="0x200000"/> <ram name="save.rwm" size="0x8000"/> <map id="io" address="00-3f,80-bf:3000-32ff"/> <map id="rom" address="00-3f:8000-ffff" mask="0x8000"/> <map id="rom" address="40-5f:0000-ffff"/> <map id="ram" address="00-3f,80-bf:6000-7fff" size="0x2000"/> <map id="ram" address="70-71:0000-ffff"/> </superfx> </cartridge> Or in BML: cartridge region=NTSC superfx revision=2 rom name=program.rom size=0x200000 ram name=save.rwm size=0x8000 map id=io address=00-3f,80-bf:3000-32ff map id=rom address=00-3f:8000-ffff mask=0x8000 map id=rom address=40-5f:0000-ffff map id=ram address=00-3f,80-bf:6000-7fff size=0x2000 map id=ram address=70-71:0000-ffff As a result of the changes, old mappings will no longer work. The above XML example will run Super Mario World 2: Yoshi's Island. Otherwise, you'll have to write your own. All that's left now is to work some sort of database mapping system in, so I can start dumping carts en masse. The NES changes that FitzRoy asked for are mostly in as well. Also, part of the reason I haven't released a WIP ... but fuck it, I'm not going to wait forever to post a new WIP. I've added a skeleton driver to emulate Campus Challenge '92 and Powerfest '94. There's no actual emulation, except for the stuff I can glean from looking at the pictures of the board. It has a DSP-1 (so SR/DR registers), four ROMs that map in and out, RAM, etc. I've also added preliminary mapping to upload high scores to a website, but obviously I need the ROMs first.
2012-10-09 08:25:32 +00:00
bus.map(reader, writer, 0x00, 0x3f, 0x0000, 0x1fff, 0x002000);
bus.map(reader, writer, 0x80, 0xbf, 0x0000, 0x1fff, 0x002000);
bus.map(reader, writer, 0x7e, 0x7f, 0x0000, 0xffff, 0x020000);
Update to v074r10 release. byuu says: Major WIP, countless changes. I really went to town on cleaning up the source today with all kinds of new ideas. I'll post the ones I remember, use diff -ru to get the rest. What I like the most is my new within template: template<unsigned lo, unsigned hi> alwaysinline bool within(unsigned addr) { static const unsigned mask = ~(hi ^ lo); return (addr & mask) == lo; } Before, you would see code like this: if((addr & 0xe0e000) == 0x206000) { //$20-3f:6000-7fff The comment is basically necessary, and you have to trust that the mask is right, or do the math yourself. Now, it looks like this: if(within<0x20, 0x3f, 0x6000, 0x7fff>(addr)) { That's the same as within<0x206000, 0x3f7fff>, I just made an SNES-variant to more closely simulate my XML mapping style: 20-3f:6000-7fff. Now obviously this has limitations, it only works in base-2 and it can't manage some tricky edge cases like (addr & 0x408000) == 0x008000 for 00-3f|80-bf:8000-ffff. But for the most part, I'll be using this where I can. The Game Boy is fully ported over to it (via the MBCs), but the SNES only has the BS-X town cartridge moved over so far. SuperFX and SA-1 at the very least could benefit. Next up, since the memory map is now static, there's really no reason to remap the entire thing at power-on and reset. So it is now set up at cartridge load and that's it. I moved the CPU/PPU/WRAM mapping out of memory.cpp and into their respective processors. A bit of duplication only because there are multiple processor cores for the different profiles, but I'm not worried about that. This is also going to be necessary to fix the debugger. Next, Coprocessor::enable() actually does what I initially intended it to now: it is called once to turn a chip on after cartridge load. It's not called on power cycle anymore. This should help fix power-cycle on my serial simulation code, and was needed to map the bus exactly one time. Although most stuff is mapped through XML, some chips still need some manual hooks for monitoring and such (eg S-DD1.) Next, I've started killing off memory::, it was initially an over-reaction to the question of where to put APURAM (in the SMP or DSP?). The idea was to have this namespace that contained all memory for everything. But it was very annoying and tedious, and various chips ignored the convention anyway like ST-0011 RAM, which couldn't work anyway since it is natively uint16 and not uint8. Cx4 will need 24-bit RAM eventually, too. There's 8->24-bit functions in there now, because the HLE code is hideous. So far, all the cartridge.cpp memory:: types have been destroyed. memory::cartrom, memory::cartram become cartridge.rom and cartridge.ram. memory::cartrtc was moved into the SRTC and SPC7110 classes directly. memory::bsxflash was moved into BSXFlash. memory::bsxram and memory::bsxpram were moved into BSXCartridge (the town cartridge). memory::st[AB](rom|ram) were moved into a new area, snes/chip/sufamiturbo. The snes/chip moniker really doesn't work so well, since it also has base units, and the serial communications stuff which is through the controller port, but oh well, now it also has the base structure for the Sufami Turbo cartridge too. So now we have sufamiturbo.slotA.rom, sufamiturbo.slotB.ram, etc. Next, the ST-0010/ST-0011 actually save the data RAM to disk. This wasn't at all compatible with my old system, and I didn't want to keep adding memory types to check inside the main UI cartridge RAM loading and saving routines. So I built a NonVolatileRAM vector inside SNES::Cartridge, and any chip that has memory it wants to save and load from disk can append onto it : data, size, id ("srm", "rtc", "nec", etc) and slot (0 = cartridge, 1 = slot A, 2 = slot B) To load and save memory, we just do a simple: foreach(memory, SNES::cartridge.nvram) load/saveMemory(memory). As a result, you can now keep your save games in F1 Race of Champions II and Hayazashi Nidan Morita Shougi. Technically I think Metal Combat should work this way as well, having the RAM being part of the chip itself, but for now that chip just writes directly into cartridge.ram, so it also technically saves to disk for now. To avoid a potential conflict with a manipulated memory map, BS-X SRAM and PSRAM are now .bss and .bsp, and not .srm and .psr. Honestly I don't like .srm as an extension either, but it doesn't bother me enough to break save RAM compatibility with other emulators, so don't worry about that changing. I finally killed off MappedRAM initializing size to ~0 (-1U). A size of zero means there is no memory there just the same. This was an old holdover for handling MMIO mapping, if I recall correctly. Something about a size of zero on MMIO-Memory objects causing it to wrap the address, so ~0 would let it map direct addresses ... or something. Whatever, that's not needed at all anymore. BSXBase becomes BSXSatellaview, and I've defaulted the device to being attached since it won't affect non-BSX games anyway. Eventually the GUI needs to make that an option. BSXCart becomes BSXCartridge. BSXFlash remains unchanged. I probably need to make Coprocessor::disable() functions now to free up memory on unload, but it shouldn't hurt anything the way it is. libsnes is most definitely broken to all hell and back now, and the debugger is still shot. I suppose we'll need some tricky code to work with the old ID system, and we'll need to add some more IDs for the new memory types.
2011-01-24 08:59:45 +00:00
}
auto CPU::power() -> void {
for(auto& byte : wram) byte = random(0x55);
//CPU
regs.a = regs.x = regs.y = 0x0000;
regs.s = 0x01ff;
//DMA
for(auto& channel : this->channel) {
channel.direction = 1;
channel.indirect = true;
channel.unused = true;
channel.reverse_transfer = true;
channel.fixed_transfer = true;
channel.transfer_mode = 7;
channel.dest_addr = 0xff;
channel.source_addr = 0xffff;
channel.source_bank = 0xff;
channel.transfer_size = 0xffff;
channel.indirect_bank = 0xff;
channel.hdma_addr = 0xffff;
channel.line_counter = 0xff;
channel.unknown = 0xff;
}
Update to v097r32 release. byuu says: Changelog: - bsnes-accuracy emulates reset vector properly[1] - bsnes-balanced compiles once more - bsnes-performance compiles once more The balanced and performance profiles are fixed for the last time. They will be removed for v098r01. Please test this WIP as much as you can. I intend to release v098 soon. I know save states are a little unstable for the WS/WSC, but they work well enough for a release. If I can't figure it out soon, I'm going to post v098 anyway. [1] this one's been a really long time coming, but ... one of the bugs I found when I translated Tekkaman Blade was that my translation patch would crash every now and again when you hit the reset button on a real SNES, but it always worked upon power on. Turns out that while power-on initializes the stack register to $01ff, reset does things a little bit differently. Reset actually triggers the reset interrupt vector after putting the CPU into emulation mode, but it doesn't initialize the stack pointer. The net effect is that the stack high byte is set to $01, and the low byte is left as it was. And then the reset vector runs, which pushes the low 16-bits of the program counter, plus the processor flags, onto the stack frame. So you can actually tell where the game was at when the system was reset ... sort of. It's a really weird behavior to be sure. But here's the catch: say you're hacking a game, and so you hook the reset vector with jsl showMyTranslationCreditsSplashScreen, and inside this new subroutine, you then perform whatever bytes you hijacked, and then initialize the stack frame to go about your business drawing the screen, and when you're done, you return via rtl. Generally, this works fine. But if S={0100, 0101, or 0102}, then the stack will wrap due to being in emulation mode at reset. So it will write to {0100, 01ff, 01fe}. But now in your subroutine, you enable native mode. So when you return from your subroutine hijack, it reads the return address from {01ff, 0200, 0201} instead of the expected {01ff, 0100, 0101}. Thus, you get an invalid address back, and you "return" to the wrong location, and your program dies. The odds of this happening depend on how the game handles S, but generally speaking, it's a ~1:85 chance. By emulating this behavior, I'll likely expose this bug in many ROM hacks that do splash screen hooks like this, including my own Tekkaman Blade translation. And it's also very possible that there are commercial games that screw this up as well. But, it's what the real system does. So if any crashes start happening as of this WIP upon resetting the game, well ... it'd happen on real hardware, too.
2016-04-03 11:17:20 +00:00
status.power_pending = true;
status.interrupt_pending = true;
}
auto CPU::reset() -> void {
create(Enter, system.cpuFrequency());
coprocessors.reset();
PPUcounter::reset();
//CPU
regs.pc = 0x000000;
regs.x.h = 0x00;
regs.y.h = 0x00;
regs.s.h = 0x01;
regs.d = 0x0000;
regs.db = 0x00;
regs.p = 0x34;
regs.e = 1;
regs.mdr = 0x00;
regs.wai = false;
regs.vector = 0xfffc; //reset vector address
//$2140-217f
for(auto& port : status.port) port = 0x00;
//$2181-$2183
status.wram_addr = 0x000000;
//$4016-$4017
status.joypad_strobe_latch = 0;
status.joypad1_bits = ~0;
status.joypad2_bits = ~0;
//$4200
status.nmi_enabled = false;
status.hirq_enabled = false;
status.virq_enabled = false;
status.auto_joypad_poll = false;
//$4201
status.pio = 0xff;
//$4202-$4203
status.wrmpya = 0xff;
status.wrmpyb = 0xff;
//$4204-$4206
status.wrdiva = 0xffff;
status.wrdivb = 0xff;
//$4207-$420a
status.hirq_pos = 0x01ff;
status.virq_pos = 0x01ff;
//$420d
status.rom_speed = 8;
//$4214-$4217
status.rddiv = 0x0000;
status.rdmpy = 0x0000;
//$4218-$421f
status.joy1 = 0x0000;
status.joy2 = 0x0000;
status.joy3 = 0x0000;
status.joy4 = 0x0000;
//ALU
alu.mpyctr = 0;
alu.divctr = 0;
alu.shift = 0;
//DMA
for(auto& channel : this->channel) {
channel.dma_enabled = false;
channel.hdma_enabled = false;
channel.hdma_completed = false;
channel.hdma_do_transfer = false;
}
pipe.valid = false;
pipe.addr = 0;
pipe.data = 0;
//Timing
status.clock_count = 0;
status.line_clocks = lineclocks();
status.irq_lock = false;
status.dram_refresh_position = (cpu_version == 1 ? 530 : 538);
status.dram_refreshed = false;
status.hdma_init_position = (cpu_version == 1 ? 12 + 8 - dmaCounter() : 12 + dmaCounter());
status.hdma_init_triggered = false;
status.hdma_position = 1104;
status.hdma_triggered = false;
status.nmi_valid = false;
status.nmi_line = false;
status.nmi_transition = false;
status.nmi_pending = false;
status.nmi_hold = false;
status.irq_valid = false;
status.irq_line = false;
status.irq_transition = false;
status.irq_pending = false;
status.irq_hold = false;
Update to v097r32 release. byuu says: Changelog: - bsnes-accuracy emulates reset vector properly[1] - bsnes-balanced compiles once more - bsnes-performance compiles once more The balanced and performance profiles are fixed for the last time. They will be removed for v098r01. Please test this WIP as much as you can. I intend to release v098 soon. I know save states are a little unstable for the WS/WSC, but they work well enough for a release. If I can't figure it out soon, I'm going to post v098 anyway. [1] this one's been a really long time coming, but ... one of the bugs I found when I translated Tekkaman Blade was that my translation patch would crash every now and again when you hit the reset button on a real SNES, but it always worked upon power on. Turns out that while power-on initializes the stack register to $01ff, reset does things a little bit differently. Reset actually triggers the reset interrupt vector after putting the CPU into emulation mode, but it doesn't initialize the stack pointer. The net effect is that the stack high byte is set to $01, and the low byte is left as it was. And then the reset vector runs, which pushes the low 16-bits of the program counter, plus the processor flags, onto the stack frame. So you can actually tell where the game was at when the system was reset ... sort of. It's a really weird behavior to be sure. But here's the catch: say you're hacking a game, and so you hook the reset vector with jsl showMyTranslationCreditsSplashScreen, and inside this new subroutine, you then perform whatever bytes you hijacked, and then initialize the stack frame to go about your business drawing the screen, and when you're done, you return via rtl. Generally, this works fine. But if S={0100, 0101, or 0102}, then the stack will wrap due to being in emulation mode at reset. So it will write to {0100, 01ff, 01fe}. But now in your subroutine, you enable native mode. So when you return from your subroutine hijack, it reads the return address from {01ff, 0200, 0201} instead of the expected {01ff, 0100, 0101}. Thus, you get an invalid address back, and you "return" to the wrong location, and your program dies. The odds of this happening depend on how the game handles S, but generally speaking, it's a ~1:85 chance. By emulating this behavior, I'll likely expose this bug in many ROM hacks that do splash screen hooks like this, including my own Tekkaman Blade translation. And it's also very possible that there are commercial games that screw this up as well. But, it's what the real system does. So if any crashes start happening as of this WIP upon resetting the game, well ... it'd happen on real hardware, too.
2016-04-03 11:17:20 +00:00
status.reset_pending = !status.power_pending;
status.interrupt_pending = true;
status.dma_active = false;
status.dma_counter = 0;
status.dma_clocks = 0;
status.dma_pending = false;
status.hdma_pending = false;
status.hdma_mode = 0;
status.auto_joypad_active = false;
status.auto_joypad_latch = false;
status.auto_joypad_counter = 0;
status.auto_joypad_clock = 0;
}
}