From 06d44b48780c5eab6e15d9ce0ce27db71c6b4323 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Sun, 3 Apr 2016 21:17:20 +1000 Subject: [PATCH] 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. --- higan/emulator/emulator.hpp | 2 +- higan/sfc/alt/cpu/cpu.cpp | 41 ++++----- higan/sfc/alt/cpu/cpu.hpp | 18 ++-- higan/sfc/alt/cpu/dma.cpp | 2 +- higan/sfc/alt/cpu/memory.cpp | 8 +- higan/sfc/alt/cpu/mmio.cpp | 10 ++- higan/sfc/alt/cpu/timing.cpp | 2 +- higan/sfc/alt/dsp/dsp.cpp | 7 +- higan/sfc/alt/dsp/dsp.hpp | 6 +- higan/sfc/alt/ppu-balanced/ppu.cpp | 85 +++++++++---------- higan/sfc/alt/ppu-balanced/ppu.hpp | 4 +- higan/sfc/alt/ppu-balanced/render/bg.cpp | 4 +- higan/sfc/alt/ppu-balanced/render/cache.cpp | 12 +-- higan/sfc/alt/ppu-balanced/render/mode7.cpp | 10 +-- higan/sfc/alt/ppu-balanced/render/oam.cpp | 2 +- .../ppu-performance/background/background.cpp | 2 +- .../alt/ppu-performance/background/mode7.cpp | 2 +- higan/sfc/alt/ppu-performance/ppu.cpp | 35 ++++---- higan/sfc/alt/ppu-performance/ppu.hpp | 4 +- higan/sfc/alt/smp/smp.cpp | 6 +- higan/sfc/alt/smp/smp.hpp | 6 +- higan/sfc/cpu/cpu.cpp | 14 ++- higan/sfc/cpu/cpu.hpp | 1 + higan/sfc/cpu/serialization.cpp | 1 + 24 files changed, 152 insertions(+), 132 deletions(-) diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 6e403b74..20b0e3c4 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -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/"; diff --git a/higan/sfc/alt/cpu/cpu.cpp b/higan/sfc/alt/cpu/cpu.cpp index 60f9680a..eb72cfc0 100644 --- a/higan/sfc/alt/cpu/cpu.cpp +++ b/higan/sfc/alt/cpu/cpu.cpp @@ -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 { diff --git a/higan/sfc/alt/cpu/cpu.hpp b/higan/sfc/alt/cpu/cpu.hpp index 1fab7a3b..10cbef28 100644 --- a/higan/sfc/alt/cpu/cpu.hpp +++ b/higan/sfc/alt/cpu/cpu.hpp @@ -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; diff --git a/higan/sfc/alt/cpu/dma.cpp b/higan/sfc/alt/cpu/dma.cpp index 50691a01..6b7a8361 100644 --- a/higan/sfc/alt/cpu/dma.cpp +++ b/higan/sfc/alt/cpu/dma.cpp @@ -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); } diff --git a/higan/sfc/alt/cpu/memory.cpp b/higan/sfc/alt/cpu/memory.cpp index 961043f2..92bd3ff5 100644 --- a/higan/sfc/alt/cpu/memory.cpp +++ b/higan/sfc/alt/cpu/memory.cpp @@ -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); } diff --git a/higan/sfc/alt/cpu/mmio.cpp b/higan/sfc/alt/cpu/mmio.cpp index 386019d0..d1279791 100644 --- a/higan/sfc/alt/cpu/mmio.cpp +++ b/higan/sfc/alt/cpu/mmio.cpp @@ -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; } diff --git a/higan/sfc/alt/cpu/timing.cpp b/higan/sfc/alt/cpu/timing.cpp index 741e7ab1..866ab32f 100644 --- a/higan/sfc/alt/cpu/timing.cpp +++ b/higan/sfc/alt/cpu/timing.cpp @@ -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; diff --git a/higan/sfc/alt/dsp/dsp.cpp b/higan/sfc/alt/dsp/dsp.cpp index 71fa8102..26e092f1 100644 --- a/higan/sfc/alt/dsp/dsp.cpp +++ b/higan/sfc/alt/dsp/dsp.cpp @@ -2,6 +2,7 @@ namespace SuperFamicom { +#include 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); diff --git a/higan/sfc/alt/dsp/dsp.hpp b/higan/sfc/alt/dsp/dsp.hpp index 92c116e9..fe786799 100644 --- a/higan/sfc/alt/dsp/dsp.hpp +++ b/higan/sfc/alt/dsp/dsp.hpp @@ -1,3 +1,5 @@ +#include + #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]; }; diff --git a/higan/sfc/alt/ppu-balanced/ppu.cpp b/higan/sfc/alt/ppu-balanced/ppu.cpp index 43ed24e8..5e4b950c 100644 --- a/higan/sfc/alt/ppu-balanced/ppu.cpp +++ b/higan/sfc/alt/ppu-balanced/ppu.cpp @@ -2,6 +2,7 @@ namespace SuperFamicom { +#include 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 { diff --git a/higan/sfc/alt/ppu-balanced/ppu.hpp b/higan/sfc/alt/ppu-balanced/ppu.hpp index 9f2305f5..60b84746 100644 --- a/higan/sfc/alt/ppu-balanced/ppu.hpp +++ b/higan/sfc/alt/ppu-balanced/ppu.hpp @@ -1,3 +1,5 @@ +#include + 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; diff --git a/higan/sfc/alt/ppu-balanced/render/bg.cpp b/higan/sfc/alt/ppu-balanced/render/bg.cpp index 54ad3a41..f508fd12 100644 --- a/higan/sfc/alt/ppu-balanced/render/bg.cpp +++ b/higan/sfc/alt/ppu-balanced/render/bg.cpp @@ -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)); diff --git a/higan/sfc/alt/ppu-balanced/render/cache.cpp b/higan/sfc/alt/ppu-balanced/render/cache.cpp index 8bedcbe9..06dc1119 100644 --- a/higan/sfc/alt/ppu-balanced/render/cache.cpp +++ b/higan/sfc/alt/ppu-balanced/render/cache.cpp @@ -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 diff --git a/higan/sfc/alt/ppu-balanced/render/mode7.cpp b/higan/sfc/alt/ppu-balanced/render/mode7.cpp index f4bff7c9..5de69f27 100644 --- a/higan/sfc/alt/ppu-balanced/render/mode7.cpp +++ b/higan/sfc/alt/ppu-balanced/render/mode7.cpp @@ -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) { diff --git a/higan/sfc/alt/ppu-balanced/render/oam.cpp b/higan/sfc/alt/ppu-balanced/render/oam.cpp index b5eae808..732d0952 100644 --- a/higan/sfc/alt/ppu-balanced/render/oam.cpp +++ b/higan/sfc/alt/ppu-balanced/render/oam.cpp @@ -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; diff --git a/higan/sfc/alt/ppu-performance/background/background.cpp b/higan/sfc/alt/ppu-performance/background/background.cpp index 852a48b1..9896c9e4 100644 --- a/higan/sfc/alt/ppu-performance/background/background.cpp +++ b/higan/sfc/alt/ppu-performance/background/background.cpp @@ -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(); diff --git a/higan/sfc/alt/ppu-performance/background/mode7.cpp b/higan/sfc/alt/ppu-performance/background/mode7.cpp index a53dbcbb..74e66ae9 100644 --- a/higan/sfc/alt/ppu-performance/background/mode7.cpp +++ b/higan/sfc/alt/ppu-performance/background/mode7.cpp @@ -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; diff --git a/higan/sfc/alt/ppu-performance/ppu.cpp b/higan/sfc/alt/ppu-performance/ppu.cpp index a4f9e406..964343de 100644 --- a/higan/sfc/alt/ppu-performance/ppu.cpp +++ b/higan/sfc/alt/ppu-performance/ppu.cpp @@ -2,6 +2,7 @@ namespace SuperFamicom { +#include 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 { diff --git a/higan/sfc/alt/ppu-performance/ppu.hpp b/higan/sfc/alt/ppu-performance/ppu.hpp index 6bb622f6..60f9538f 100644 --- a/higan/sfc/alt/ppu-performance/ppu.hpp +++ b/higan/sfc/alt/ppu-performance/ppu.hpp @@ -1,3 +1,5 @@ +#include + 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; diff --git a/higan/sfc/alt/smp/smp.cpp b/higan/sfc/alt/smp/smp.cpp index c4bf48af..7e500b5f 100644 --- a/higan/sfc/alt/smp/smp.cpp +++ b/higan/sfc/alt/smp/smp.cpp @@ -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(); } diff --git a/higan/sfc/alt/smp/smp.hpp b/higan/sfc/alt/smp/smp.hpp index 0b29459b..97613eea 100644 --- a/higan/sfc/alt/smp/smp.hpp +++ b/higan/sfc/alt/smp/smp.hpp @@ -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; diff --git a/higan/sfc/cpu/cpu.cpp b/higan/sfc/cpu/cpu.cpp index 8a6b7882..bfe2592e 100644 --- a/higan/sfc/cpu/cpu.cpp +++ b/higan/sfc/cpu/cpu.cpp @@ -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; diff --git a/higan/sfc/cpu/cpu.hpp b/higan/sfc/cpu/cpu.hpp index 627b56e0..d0f12581 100644 --- a/higan/sfc/cpu/cpu.hpp +++ b/higan/sfc/cpu/cpu.hpp @@ -123,6 +123,7 @@ privileged: bool irq_pending; bool irq_hold; + bool power_pending; bool reset_pending; //DMA diff --git a/higan/sfc/cpu/serialization.cpp b/higan/sfc/cpu/serialization.cpp index e0d49192..c946b349 100644 --- a/higan/sfc/cpu/serialization.cpp +++ b/higan/sfc/cpu/serialization.cpp @@ -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);