bsnes/higan/sfc/cpu/serialization.cpp

116 lines
2.8 KiB
C++
Raw Normal View History

auto CPU::serialize(serializer& s) -> void {
R65816::serialize(s);
Thread::serialize(s);
PPUcounter::serialize(s);
s.array(wram);
s.integer(cpu_version);
s.integer(status.interrupt_pending);
s.integer(status.clock_count);
s.integer(status.line_clocks);
s.integer(status.irq_lock);
s.integer(status.dram_refresh_position);
s.integer(status.dram_refreshed);
s.integer(status.hdma_init_position);
s.integer(status.hdma_init_triggered);
s.integer(status.hdma_position);
s.integer(status.hdma_triggered);
s.integer(status.nmi_valid);
s.integer(status.nmi_line);
s.integer(status.nmi_transition);
s.integer(status.nmi_pending);
s.integer(status.nmi_hold);
s.integer(status.irq_valid);
s.integer(status.irq_line);
s.integer(status.irq_transition);
s.integer(status.irq_pending);
s.integer(status.irq_hold);
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
s.integer(status.power_pending);
s.integer(status.reset_pending);
s.integer(status.dma_active);
s.integer(status.dma_counter);
s.integer(status.dma_clocks);
s.integer(status.dma_pending);
s.integer(status.hdma_pending);
s.integer(status.hdma_mode);
Update to v073r01 release. byuu says: While perhaps not perfect, pretty good is better than nothing ... I've added emulation of auto-joypad poll timing. Going off ikari_01's confirmation of what we suspected, that the strobe happens every 256 clocks, I've set up emulation as follows: Upon reset, our clock counter is reset to zero. At the start of each frame, our poll counter is reset to zero. Every 256 clocks, we call the step_auto_joypad_poll() function. If we are at V=225/240+ (based on overscan setting), we check the poll counter. At zero, we poll the actual controller and set the joypad polling flag in $4212.d0 to 1. From zero through fifteen, we read in one bit for each controller and shift it into the register. At sixteen, we turn off the joypad polling flag. The 256-clock divider allows the start point of polling for each frame to fluctuate wildly like real hardware. I count regardless of auto joypad enable, as per $4212.d0's behavior; but only poll when it's actually enabled. I do not consume any actual time from this polling. I honestly don't know if I even should, or if it manages to do it in the background. If it should consume time, then this most likely happens between opcode edges and we'll have to adjust the code a good bit. All commercial games should continue to work fine, but this will likely break some hacks/translations not tested on hardware. Without the timing emulation, reading $4218-421f before V=~228 would basically give you the valid input controller values of the previous frame. Now, like hardware, it should give you a state that is part previous frame, part current frame shifted into it. Button positions won't be reliable and will shift every 256 clocks. I've also removed the Qt GUI, and renamed ui-phoenix to just ui. This removes 400kb of source code (phoenix is a lean 130kb), and drops the archive size from 564KB to 475KB. Combined with the DSP HLE, and we've knocked off ~570KB of source cruft from the entire project. I am looking forward to not having to specify which GUI is included anymore.
2010-12-27 07:29:57 +00:00
s.integer(status.auto_joypad_active);
s.integer(status.auto_joypad_latch);
Update to v073r01 release. byuu says: While perhaps not perfect, pretty good is better than nothing ... I've added emulation of auto-joypad poll timing. Going off ikari_01's confirmation of what we suspected, that the strobe happens every 256 clocks, I've set up emulation as follows: Upon reset, our clock counter is reset to zero. At the start of each frame, our poll counter is reset to zero. Every 256 clocks, we call the step_auto_joypad_poll() function. If we are at V=225/240+ (based on overscan setting), we check the poll counter. At zero, we poll the actual controller and set the joypad polling flag in $4212.d0 to 1. From zero through fifteen, we read in one bit for each controller and shift it into the register. At sixteen, we turn off the joypad polling flag. The 256-clock divider allows the start point of polling for each frame to fluctuate wildly like real hardware. I count regardless of auto joypad enable, as per $4212.d0's behavior; but only poll when it's actually enabled. I do not consume any actual time from this polling. I honestly don't know if I even should, or if it manages to do it in the background. If it should consume time, then this most likely happens between opcode edges and we'll have to adjust the code a good bit. All commercial games should continue to work fine, but this will likely break some hacks/translations not tested on hardware. Without the timing emulation, reading $4218-421f before V=~228 would basically give you the valid input controller values of the previous frame. Now, like hardware, it should give you a state that is part previous frame, part current frame shifted into it. Button positions won't be reliable and will shift every 256 clocks. I've also removed the Qt GUI, and renamed ui-phoenix to just ui. This removes 400kb of source code (phoenix is a lean 130kb), and drops the archive size from 564KB to 475KB. Combined with the DSP HLE, and we've knocked off ~570KB of source cruft from the entire project. I am looking forward to not having to specify which GUI is included anymore.
2010-12-27 07:29:57 +00:00
s.integer(status.auto_joypad_counter);
s.integer(status.auto_joypad_clock);
Updated to v067r23 release. byuu says: Added missing $4200 IRQ lock, which fixes Chou Aniki on the fast CPU core, so slower PCs can get their brotherly love on. Added range-based controller IOBit latching to the fast CPU core, which enables Super Scope and Justifier support. Uses the priority queue as well, so there is zero speed-hit. Given the way range-testing works, the trigger point may vary by 1-2 pixels when firing at the same spot. Not really a big deal when it avoids a massive speed penalty. Fixed PAL and interlace-mode HVIRQs at V=0,H<2 on the fast CPU core. Added the dot-renderer's sprite list update-on-OAM-write functionality to the scanline-based PPU renderer. Unfortunately it looks like all the speed gain was already taken from the global dirty flag I was using before, but this certainly won't hurt speed any, so whatever. Added #ifdef to stop CoInitialize(0) on non-Windows ports. Added #ifdefs to stop gradient fade on Windows port. Not going to fuck over the Linux port aesthetic because of Qt bug #47,326,927. If there's a way to tell what Qt theme is being used, I can leave it enabled for XP/Vista themes. Moved HDMA trigger from 1104 to 1112, and reduced channel overhead from 24 to 16, to better simulate one-cycle DMA->CPU sync. Code clarity: I've re-added my varint.hpp classes, and am actively using them in the accuracy cores. So far, I haven't done anything that would detriment speed, but it is certainly cool. The APU ports exposed by the CPU and SMP now take uint2 address arguments, the CPU WRAM address register is a uint17, and the IRQ H/VTIME values are uint10. This basically allows the source to clearly convey the data sizes, and eliminates the need to manually mask values when writing to registers or reading from memory. I'm going to be doing this everywhere, and it will have a speed impact eventually, because the automation means we can't skip masks when we know the data is already masked off. Source: archive contains the launcher code, so that I can look into why it's crashing on XP tomorrow. It doesn't look like Circuit USA's flags are going to work too well with this new CPU core. Still not sure what the hell Robocop vs The Terminator is doing, I'll read through the mega SNES thread for clues tomorrow. Speedy Gonzales is definitely broken, as modifying the MDR was breaking things with my current core. Probably because the new CPU core doesn't wait for a cycle edge to trigger. I was thinking that perhaps we could keep some form of cheat codes list to work as game-specific hacks for the performance core. Keeps the hacks out of the emulator, but could allow the remaining bugs to be worked around for people who have no choice but to use the performance core.
2010-08-16 09:42:20 +00:00
s.array(status.port);
s.integer(status.wram_addr);
s.integer(status.joypad_strobe_latch);
s.integer(status.joypad1_bits);
s.integer(status.joypad2_bits);
s.integer(status.nmi_enabled);
s.integer(status.hirq_enabled);
s.integer(status.virq_enabled);
s.integer(status.auto_joypad_poll);
s.integer(status.pio);
s.integer(status.wrmpya);
s.integer(status.wrmpyb);
s.integer(status.wrdiva);
s.integer(status.wrdivb);
s.integer(status.hirq_pos);
s.integer(status.virq_pos);
s.integer(status.rom_speed);
s.integer(status.rddiv);
s.integer(status.rdmpy);
Update to v073r01 release. byuu says: While perhaps not perfect, pretty good is better than nothing ... I've added emulation of auto-joypad poll timing. Going off ikari_01's confirmation of what we suspected, that the strobe happens every 256 clocks, I've set up emulation as follows: Upon reset, our clock counter is reset to zero. At the start of each frame, our poll counter is reset to zero. Every 256 clocks, we call the step_auto_joypad_poll() function. If we are at V=225/240+ (based on overscan setting), we check the poll counter. At zero, we poll the actual controller and set the joypad polling flag in $4212.d0 to 1. From zero through fifteen, we read in one bit for each controller and shift it into the register. At sixteen, we turn off the joypad polling flag. The 256-clock divider allows the start point of polling for each frame to fluctuate wildly like real hardware. I count regardless of auto joypad enable, as per $4212.d0's behavior; but only poll when it's actually enabled. I do not consume any actual time from this polling. I honestly don't know if I even should, or if it manages to do it in the background. If it should consume time, then this most likely happens between opcode edges and we'll have to adjust the code a good bit. All commercial games should continue to work fine, but this will likely break some hacks/translations not tested on hardware. Without the timing emulation, reading $4218-421f before V=~228 would basically give you the valid input controller values of the previous frame. Now, like hardware, it should give you a state that is part previous frame, part current frame shifted into it. Button positions won't be reliable and will shift every 256 clocks. I've also removed the Qt GUI, and renamed ui-phoenix to just ui. This removes 400kb of source code (phoenix is a lean 130kb), and drops the archive size from 564KB to 475KB. Combined with the DSP HLE, and we've knocked off ~570KB of source cruft from the entire project. I am looking forward to not having to specify which GUI is included anymore.
2010-12-27 07:29:57 +00:00
s.integer(status.joy1);
s.integer(status.joy2);
s.integer(status.joy3);
s.integer(status.joy4);
s.integer(alu.mpyctr);
s.integer(alu.divctr);
s.integer(alu.shift);
for(uint i = 0; i < 8; i++) {
s.integer(channel[i].dma_enabled);
s.integer(channel[i].hdma_enabled);
s.integer(channel[i].direction);
s.integer(channel[i].indirect);
s.integer(channel[i].unused);
s.integer(channel[i].reverse_transfer);
s.integer(channel[i].fixed_transfer);
s.integer(channel[i].transfer_mode);
s.integer(channel[i].dest_addr);
s.integer(channel[i].source_addr);
s.integer(channel[i].source_bank);
s.integer(channel[i].transfer_size);
s.integer(channel[i].indirect_bank);
s.integer(channel[i].hdma_addr);
s.integer(channel[i].line_counter);
s.integer(channel[i].unknown);
s.integer(channel[i].hdma_completed);
s.integer(channel[i].hdma_do_transfer);
}
s.integer(pipe.valid);
s.integer(pipe.addr);
s.integer(pipe.data);
}