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.
This commit is contained in:
Tim Allen 2016-04-03 21:17:20 +10:00
parent 25eaaa82f4
commit 06d44b4878
24 changed files with 152 additions and 132 deletions

View File

@ -6,7 +6,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "097.31";
static const string Version = "097.32";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

@ -30,7 +30,7 @@ auto CPU::synchronizeSMP() -> void {
if(SMP::Threaded == true) {
if(smp.clock < 0) co_switch(smp.thread);
} else {
while(smp.clock < 0) smp.enter();
while(smp.clock < 0) smp.main();
}
}
@ -38,7 +38,7 @@ auto CPU::synchronizePPU() -> void {
if(PPU::Threaded == true) {
if(ppu.clock < 0) co_switch(ppu.thread);
} else {
while(ppu.clock < 0) ppu.enter();
while(ppu.clock < 0) ppu.main();
}
}
@ -54,29 +54,24 @@ auto CPU::synchronizeDevices() -> void {
if(device.controllerPort2->clock < 0) co_switch(device.controllerPort2->thread);
}
auto CPU::Enter() -> void { cpu.enter(); }
auto CPU::Enter() -> void {
while(true) scheduler.synchronize(), cpu.main();
}
auto CPU::enter() -> void {
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::CPU) {
scheduler.sync = Scheduler::SynchronizeMode::All;
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
if(status.nmi_pending) {
status.nmi_pending = false;
regs.vector = (regs.e == false ? 0xffea : 0xfffa);
op_irq();
}
if(status.irq_pending) {
status.irq_pending = false;
regs.vector = (regs.e == false ? 0xffee : 0xfffe);
op_irq();
}
op_exec();
auto CPU::main() -> void {
if(status.nmi_pending) {
status.nmi_pending = false;
regs.vector = (regs.e == false ? 0xffea : 0xfffa);
interrupt();
}
if(status.irq_pending) {
status.irq_pending = false;
regs.vector = (regs.e == false ? 0xffee : 0xfffe);
interrupt();
}
instruction();
}
auto CPU::enable() -> void {

View File

@ -11,17 +11,19 @@ struct CPU : Processor::R65816, Thread, public PPUcounter {
auto pio() -> uint8;
auto joylatch() -> bool;
auto interrupt_pending() -> bool;
auto interruptPending() const -> bool;
auto port_read(uint8 port) -> uint8;
auto port_write(uint8 port, uint8 data) -> void;
auto dmaPortRead(uint24 addr, uint8 data) -> uint8;
auto dmaPortWrite(uint24 addr, uint8 data) -> void;
auto mmio_read(uint addr, uint8 data) -> uint8;
auto mmio_write(uint addr, uint8 data) -> void;
auto op_io() -> void;
auto op_read(uint addr) -> uint8;
auto op_write(uint addr, uint8 data) -> void;
auto io() -> void;
auto read(uint24 addr) -> uint8;
auto write(uint24 addr, uint8 data) -> void;
auto enter() -> void;
auto main() -> void;
auto enable() -> void;
auto power() -> void;
auto reset() -> void;
@ -37,7 +39,7 @@ private:
//timing
auto queue_event(uint id) -> void;
auto last_cycle() -> void;
auto lastCycle() -> void;
auto add_clocks(uint clocks) -> void;
auto scanline() -> void;
auto run_auto_joypad_poll() -> void;
@ -89,8 +91,8 @@ private:
uint8 source_bank;
union {
uint16 transfer_size;
uint16 indirect_addr;
uint16_t transfer_size;
uint16_t indirect_addr;
};
uint8 indirect_bank;

View File

@ -28,7 +28,7 @@ auto CPU::dma_transfer(bool direction, uint8 bbus, uint abus) -> void {
add_clocks(8);
dma_write(dma_transfer_valid(bbus, abus), 0x2100 | bbus, data);
} else {
uint8 data = dma_transfer_valid(bbus, abus) ? bus.read(0x2100 | bbus, regs.mdr) : 0x00;
uint8 data = dma_transfer_valid(bbus, abus) ? bus.read(0x2100 | bbus, regs.mdr) : (uint8)0x00;
add_clocks(8);
dma_write(dma_addr_valid(abus), abus, data);
}

View File

@ -6,7 +6,7 @@ auto CPU::joylatch() -> bool {
return status.joypad_strobe_latch;
}
auto CPU::interrupt_pending() -> bool {
auto CPU::interruptPending() const -> bool {
return false;
}
@ -18,17 +18,17 @@ auto CPU::port_write(uint8 port, uint8 data) -> void {
port_data[port & 3] = data;
}
auto CPU::op_io() -> void {
auto CPU::io() -> void {
add_clocks(6);
}
auto CPU::op_read(uint addr) -> uint8 {
auto CPU::read(uint24 addr) -> uint8 {
regs.mdr = bus.read(addr, regs.mdr);
add_clocks(speed(addr));
return regs.mdr;
}
auto CPU::op_write(uint addr, uint8 data) -> void {
auto CPU::write(uint24 addr, uint8 data) -> void {
add_clocks(speed(addr));
bus.write(addr, regs.mdr = data);
}

View File

@ -1,3 +1,11 @@
auto CPU::dmaPortRead(uint24 addr, uint8 data) -> uint8 {
return mmio_read(addr, data);
}
auto CPU::dmaPortWrite(uint24 addr, uint8 data) -> void {
return mmio_write(addr, data);
}
auto CPU::mmio_read(uint addr, uint8 data) -> uint8 {
if((addr & 0xffc0) == 0x2140) {
synchronizeSMP();
@ -186,7 +194,7 @@ auto CPU::mmio_write(uint addr, uint8 data) -> void {
case 0x4206: {
status.wrdivb = data;
status.rddiv = status.wrdivb ? status.wrdiva / status.wrdivb : 0xffff;
status.rdmpy = status.wrdivb ? status.wrdiva % status.wrdivb : status.wrdiva;
status.rdmpy = status.wrdivb ? status.wrdiva % status.wrdivb : (uint)status.wrdiva;
return;
}

View File

@ -5,7 +5,7 @@ auto CPU::queue_event(uint id) -> void {
}
}
auto CPU::last_cycle() -> void {
auto CPU::lastCycle() -> void {
if(status.irq_lock) {
status.irq_lock = false;
return;

View File

@ -2,6 +2,7 @@
namespace SuperFamicom {
#include <sfc/dsp/audio.cpp>
DSP dsp;
#include "serialization.cpp"
@ -17,13 +18,13 @@ auto DSP::step(uint clocks) -> void {
auto DSP::synchronizeSMP() -> void {
if(SMP::Threaded == true) {
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(smp.thread);
if(clock >= 0 && !scheduler.synchronizing()) co_switch(smp.thread);
} else {
while(clock >= 0) smp.enter();
while(clock >= 0) smp.main();
}
}
auto DSP::enter() -> void {
auto DSP::main() -> void {
spc_dsp.run(1);
step(24);

View File

@ -1,3 +1,5 @@
#include <sfc/dsp/audio.hpp>
#include "SPC_DSP.h"
struct DSP : Thread {
@ -12,7 +14,7 @@ struct DSP : Thread {
auto read(uint8 addr) -> uint8;
auto write(uint8 addr, uint8 data) -> void;
auto enter() -> void;
auto main() -> void;
auto power() -> void;
auto reset() -> void;
@ -22,7 +24,7 @@ struct DSP : Thread {
private:
SPC_DSP spc_dsp;
int16 samplebuffer[8192];
int16_t samplebuffer[8192];
bool channel_enabled[8];
};

View File

@ -2,6 +2,7 @@
namespace SuperFamicom {
#include <sfc/ppu/video.cpp>
PPU ppu;
#include "memory/memory.cpp"
@ -49,55 +50,50 @@ auto PPU::step(uint clocks) -> void {
auto PPU::synchronizeCPU() -> void {
if(CPU::Threaded == true) {
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
} else {
while(clock >= 0) cpu.enter();
while(clock >= 0) cpu.main();
}
}
auto PPU::Enter() -> void { ppu.enter(); }
auto PPU::Enter() -> void {
while(true) scheduler.synchronize(), ppu.main();
}
auto PPU::enter() -> void {
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
auto PPU::main() -> void {
//H = 0 (initialize)
scanline();
add_clocks(10);
//H = 10 (cache mode7 registers + OAM address reset)
cache.m7_hofs = regs.m7_hofs;
cache.m7_vofs = regs.m7_vofs;
cache.m7a = regs.m7a;
cache.m7b = regs.m7b;
cache.m7c = regs.m7c;
cache.m7d = regs.m7d;
cache.m7x = regs.m7x;
cache.m7y = regs.m7y;
if(vcounter() == (!overscan() ? 225 : 240)) {
if(regs.display_disabled == false) {
regs.oam_addr = regs.oam_baseaddr << 1;
regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
}
//H = 0 (initialize)
scanline();
add_clocks(10);
//H = 10 (cache mode7 registers + OAM address reset)
cache.m7_hofs = regs.m7_hofs;
cache.m7_vofs = regs.m7_vofs;
cache.m7a = regs.m7a;
cache.m7b = regs.m7b;
cache.m7c = regs.m7c;
cache.m7d = regs.m7d;
cache.m7x = regs.m7x;
cache.m7y = regs.m7y;
if(vcounter() == (!overscan() ? 225 : 240)) {
if(regs.display_disabled == false) {
regs.oam_addr = regs.oam_baseaddr << 1;
regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
}
}
add_clocks(502);
//H = 512 (render)
render_scanline();
add_clocks(640);
//H = 1152 (cache OBSEL)
if(cache.oam_basesize != regs.oam_basesize) {
cache.oam_basesize = regs.oam_basesize;
sprite_list_valid = false;
}
cache.oam_nameselect = regs.oam_nameselect;
cache.oam_tdaddr = regs.oam_tdaddr;
add_clocks(lineclocks() - 1152); //seek to start of next scanline
}
add_clocks(502);
//H = 512 (render)
render_scanline();
add_clocks(640);
//H = 1152 (cache OBSEL)
if(cache.oam_basesize != regs.oam_basesize) {
cache.oam_basesize = regs.oam_basesize;
sprite_list_valid = false;
}
cache.oam_nameselect = regs.oam_nameselect;
cache.oam_tdaddr = regs.oam_tdaddr;
add_clocks(lineclocks() - 1152); //seek to start of next scanline
}
auto PPU::add_clocks(uint clocks) -> void {
@ -131,7 +127,8 @@ auto PPU::scanline() -> void {
}
if(line == 241) {
scheduler.exit(Scheduler::ExitReason::FrameEvent);
video.refresh();
scheduler.exit(Scheduler::Event::Frame);
}
}
@ -401,6 +398,8 @@ auto PPU::reset() -> void {
regs.bg_y[1] = 0;
regs.bg_y[2] = 0;
regs.bg_y[3] = 0;
video.reset();
}
auto PPU::layer_enable(uint layer, uint priority, bool enable) -> void {

View File

@ -1,3 +1,5 @@
#include <sfc/ppu/video.hpp>
struct PPU : Thread, public PPUcounter {
enum : bool { Threaded = true };
@ -23,7 +25,7 @@ struct PPU : Thread, public PPUcounter {
auto scanline() -> void;
auto render_scanline() -> void;
auto frame() -> void;
auto enter() -> void;
auto main() -> void;
auto enable() -> void;
auto power() -> void;
auto reset() -> void;

View File

@ -5,7 +5,7 @@ auto PPU::update_bg_info() -> void {
for(unsigned bg = 0; bg < 4; bg++) {
bg_info[bg].th = (regs.bg_tilesize[bg] ? 4 : 3);
bg_info[bg].tw = (hires ? 4 : bg_info[bg].th);
bg_info[bg].tw = (hires ? 4 : (uint)bg_info[bg].th);
bg_info[bg].mx = (bg_info[bg].th == 4 ? (width << 1) : width);
bg_info[bg].my = bg_info[bg].mx;
@ -96,7 +96,7 @@ auto PPU::render_line_bg(uint8 pri0_pos, uint8 pri1_pos) -> void {
bool mirror_x, mirror_y;
const uint8* tile_ptr;
const uint16* mtable = mosaic_table[regs.mosaic_enabled[bg] ? regs.mosaic_size : 0];
const uint16* mtable = mosaic_table[regs.mosaic_enabled[bg] ? (uint)regs.mosaic_size : 0];
const bool is_opt_mode = (mode == 2 || mode == 4 || mode == 6);
const bool is_direct_color_mode = (regs.direct_color == true && bg == BG1 && (mode == 3 || mode == 4));

View File

@ -118,12 +118,12 @@ auto PPU::flush_pixel_cache() -> void {
}
auto PPU::alloc_tiledata_cache() -> void {
bg_tiledata[TILE_2BIT] = new uint8_t[262144]();
bg_tiledata[TILE_4BIT] = new uint8_t[131072]();
bg_tiledata[TILE_8BIT] = new uint8_t[ 65536]();
bg_tiledata_state[TILE_2BIT] = new uint8_t[ 4096]();
bg_tiledata_state[TILE_4BIT] = new uint8_t[ 2048]();
bg_tiledata_state[TILE_8BIT] = new uint8_t[ 1024]();
bg_tiledata[TILE_2BIT] = new uint8[262144]();
bg_tiledata[TILE_4BIT] = new uint8[131072]();
bg_tiledata[TILE_8BIT] = new uint8[ 65536]();
bg_tiledata_state[TILE_2BIT] = new uint8[ 4096]();
bg_tiledata_state[TILE_4BIT] = new uint8[ 2048]();
bg_tiledata_state[TILE_8BIT] = new uint8[ 1024]();
}
//marks all tiledata cache entries as dirty

View File

@ -44,13 +44,13 @@ auto PPU::render_line_mode7(uint8 pri0_pos, uint8 pri1_pos) -> void {
uint16* mtable_x;
uint16* mtable_y;
if(bg == BG1) {
mtable_x = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? regs.mosaic_size : 0];
mtable_y = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? regs.mosaic_size : 0];
mtable_x = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? (uint)regs.mosaic_size : 0];
mtable_y = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? (uint)regs.mosaic_size : 0];
} else { //bg == BG2
//Mode7 EXTBG BG2 uses BG1 mosaic enable to control vertical mosaic,
//and BG2 mosaic enable to control horizontal mosaic...
mtable_x = (uint16*)mosaic_table[(regs.mosaic_enabled[BG2] == true) ? regs.mosaic_size : 0];
mtable_y = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? regs.mosaic_size : 0];
mtable_x = (uint16*)mosaic_table[(regs.mosaic_enabled[BG2] == true) ? (uint)regs.mosaic_size : 0];
mtable_y = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? (uint)regs.mosaic_size : 0];
}
int32 psx = ((a * CLIP(hofs - cx)) & ~63) + ((b * CLIP(vofs - cy)) & ~63) + ((b * mtable_y[y]) & ~63) + (cx << 8);
@ -108,7 +108,7 @@ auto PPU::render_line_mode7(uint8 pri0_pos, uint8 pri1_pos) -> void {
if(!palette) continue;
_x = (regs.mode7_hflip == false) ? (x) : (255 - x);
_x = (regs.mode7_hflip == false) ? ((uint)x) : (255 - x);
uint32 col;
if(regs.direct_color == true && bg == BG1) {

View File

@ -69,7 +69,7 @@ auto PPU::is_sprite_on_scanline() -> bool {
sprite_item* spr = &sprite_list[active_sprite];
if(spr->x > 256 && (spr->x + spr->width - 1) < 512) return false;
int spr_height = (regs.oam_interlace == false) ? (spr->height) : (spr->height >> 1);
int spr_height = (regs.oam_interlace == false) ? ((uint)spr->height) : (spr->height >> 1);
if(line >= spr->y && line < (spr->y + spr_height)) return true;
if((spr->y + spr_height) >= 256 && line < ((spr->y + spr_height) & 255)) return true;
return false;

View File

@ -111,7 +111,7 @@ auto PPU::Background::render() -> void {
hscroll = regs.hoffset;
vscroll = regs.voffset;
uint y = (regs.mosaic == 0 ? self.vcounter() : mosaic_voffset);
uint y = (regs.mosaic == 0 ? (uint)self.vcounter() : mosaic_voffset);
if(hires) {
hscroll <<= 1;
if(self.regs.interlace) y = (y << 1) + self.field();

View File

@ -14,7 +14,7 @@ auto PPU::Background::render_mode7() -> void {
int hofs = sclip<13>(self.regs.mode7_hoffset);
int vofs = sclip<13>(self.regs.mode7_voffset);
int y = (self.regs.mode7_vflip == false ? self.vcounter() : 255 - self.vcounter());
int y = (self.regs.mode7_vflip == false ? (uint)self.vcounter() : 255 - self.vcounter());
uint16* mosaic_x;
uint16* mosaic_y;

View File

@ -2,6 +2,7 @@
namespace SuperFamicom {
#include <sfc/ppu/video.cpp>
PPU ppu;
#include "mmio/mmio.cpp"
@ -39,28 +40,24 @@ auto PPU::step(uint clocks) -> void {
auto PPU::synchronizeCPU() -> void {
if(CPU::Threaded == true) {
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
} else {
while(clock >= 0) cpu.enter();
while(clock >= 0) cpu.main();
}
}
auto PPU::Enter() -> void { ppu.enter(); }
auto PPU::Enter() -> void {
while(true) scheduler.synchronize(), ppu.main();
}
auto PPU::enter() -> void {
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
scanline();
if(vcounter() < display.height && vcounter()) {
add_clocks(512);
render_scanline();
add_clocks(lineclocks() - 512);
} else {
add_clocks(lineclocks());
}
auto PPU::main() -> void {
scanline();
if(vcounter() < display.height && vcounter()) {
add_clocks(512);
render_scanline();
add_clocks(lineclocks() - 512);
} else {
add_clocks(lineclocks());
}
}
@ -93,7 +90,8 @@ auto PPU::scanline() -> void {
if(vcounter() == display.height && regs.display_disable == false) sprite.address_reset();
if(vcounter() == 241) {
scheduler.exit(Scheduler::ExitReason::FrameEvent);
video.refresh();
scheduler.exit(Scheduler::Event::Frame);
}
}
@ -126,6 +124,7 @@ auto PPU::reset() -> void {
mmio_reset();
display.interlace = false;
display.overscan = false;
video.reset();
}
auto PPU::layer_enable(uint layer, uint priority, bool enable) -> void {

View File

@ -1,3 +1,5 @@
#include <sfc/ppu/video.hpp>
struct PPU : Thread, public PPUcounter {
enum : bool { Threaded = true };
@ -11,7 +13,7 @@ struct PPU : Thread, public PPUcounter {
auto interlace() const -> bool;
auto overscan() const -> bool;
auto enter() -> void;
auto main() -> void;
auto enable() -> void;
auto power() -> void;
auto reset() -> void;

View File

@ -21,7 +21,7 @@ auto SMP::synchronizeCPU() -> void {
if(CPU::Threaded == true) {
//if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
} else {
while(clock >= 0) cpu.enter();
while(clock >= 0) cpu.main();
}
}
@ -29,11 +29,11 @@ auto SMP::synchronizeDSP() -> void {
if(DSP::Threaded == true) {
//if(dsp.clock < 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(dsp.thread);
} else {
while(dsp.clock < 0) dsp.enter();
while(dsp.clock < 0) dsp.main();
}
}
auto SMP::enter() -> void {
auto SMP::main() -> void {
while(clock < 0) op_step();
}

View File

@ -12,7 +12,7 @@ struct SMP : Thread {
auto mmio_read(uint addr) -> uint;
auto mmio_write(uint addr, uint data) -> void;
auto enter() -> void;
auto main() -> void;
auto power() -> void;
auto reset() -> void;
@ -69,8 +69,8 @@ struct SMP : Thread {
uint16 pc;
uint8 sp;
union {
uint16 ya;
struct { uint8 order_lsb2(a, y); };
uint16_t ya;
struct { uint8_t order_lsb2(a, y); };
};
uint8 x;
Flags p;

View File

@ -66,16 +66,21 @@ auto CPU::main() -> void {
status.interrupt_pending = false;
if(status.nmi_pending) {
status.nmi_pending = false;
regs.vector = (regs.e == false ? 0xffea : 0xfffa);
regs.vector = !regs.e ? 0xffea : 0xfffa;
interrupt();
debugger.op_nmi();
} else if(status.irq_pending) {
status.irq_pending = false;
regs.vector = (regs.e == false ? 0xffee : 0xfffe);
regs.vector = !regs.e ? 0xffee : 0xfffe;
interrupt();
debugger.op_irq();
} else if(status.reset_pending) {
status.reset_pending = false;
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);
@ -146,6 +151,9 @@ auto CPU::power() -> void {
channel.line_counter = 0xff;
channel.unknown = 0xff;
}
status.power_pending = true;
status.interrupt_pending = true;
}
auto CPU::reset() -> void {
@ -255,7 +263,7 @@ auto CPU::reset() -> void {
status.irq_pending = false;
status.irq_hold = false;
status.reset_pending = true;
status.reset_pending = !status.power_pending;
status.interrupt_pending = true;
status.dma_active = false;

View File

@ -123,6 +123,7 @@ privileged:
bool irq_pending;
bool irq_hold;
bool power_pending;
bool reset_pending;
//DMA

View File

@ -35,6 +35,7 @@ auto CPU::serialize(serializer& s) -> void {
s.integer(status.irq_pending);
s.integer(status.irq_hold);
s.integer(status.power_pending);
s.integer(status.reset_pending);
s.integer(status.dma_active);