From f6303518d5a23ed18de64ec13d38cf6a217d9477 Mon Sep 17 00:00:00 2001 From: byuu <2107894+byuu@users.noreply.github.com> Date: Fri, 2 Aug 2019 04:45:06 +0900 Subject: [PATCH] v108.4 * ~4.6% speedup (with the fast PPU) * fix out-of-bounds DSP memory access [Sour] --- bsnes/emulator/emulator.hpp | 4 +- .../processor/wdc65816/instructions-read.cpp | 12 +-- .../processor/wdc65816/instructions-write.cpp | 12 +-- bsnes/processor/wdc65816/memory.cpp | 26 +++-- bsnes/processor/wdc65816/wdc65816.hpp | 38 ++++---- bsnes/sfc/coprocessor/sa1/memory.cpp | 4 +- bsnes/sfc/coprocessor/sa1/sa1.hpp | 4 +- bsnes/sfc/cpu/cpu.cpp | 2 +- bsnes/sfc/cpu/cpu.hpp | 4 +- bsnes/sfc/cpu/memory.cpp | 4 +- bsnes/sfc/cpu/timing.cpp | 2 +- bsnes/sfc/dsp/SPC_DSP.cpp | 2 +- bsnes/sfc/ppu-fast/ppu.cpp | 2 +- bsnes/sfc/ppu/counter/counter-inline.hpp | 97 +++++++++++-------- bsnes/sfc/ppu/counter/counter.hpp | 24 +++-- bsnes/sfc/ppu/counter/serialization.cpp | 16 +-- bsnes/sfc/ppu/ppu.cpp | 2 +- 17 files changed, 138 insertions(+), 117 deletions(-) mode change 100644 => 100755 bsnes/sfc/ppu/counter/counter-inline.hpp mode change 100644 => 100755 bsnes/sfc/ppu/counter/counter.hpp diff --git a/bsnes/emulator/emulator.hpp b/bsnes/emulator/emulator.hpp index 9bcba588..2595793b 100644 --- a/bsnes/emulator/emulator.hpp +++ b/bsnes/emulator/emulator.hpp @@ -31,13 +31,13 @@ using namespace nall; namespace Emulator { static const string Name = "bsnes"; - static const string Version = "108.3"; + static const string Version = "108.4"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "https://byuu.org"; //incremented only when serialization format changes - static const string SerializerVersion = "108.2"; + static const string SerializerVersion = "108.4"; namespace Constants { namespace Colorburst { diff --git a/bsnes/processor/wdc65816/instructions-read.cpp b/bsnes/processor/wdc65816/instructions-read.cpp index 1e4a07fc..e364725b 100755 --- a/bsnes/processor/wdc65816/instructions-read.cpp +++ b/bsnes/processor/wdc65816/instructions-read.cpp @@ -45,7 +45,7 @@ auto WDC65816::instructionLongRead8(alu8 op, r16 I) -> void { V.l = fetch(); V.h = fetch(); V.b = fetch(); -L W.l = read(V.d + I.w + 0); +L W.l = readLong(V.d + I.w + 0); alu(W.l); } @@ -53,8 +53,8 @@ auto WDC65816::instructionLongRead16(alu16 op, r16 I) -> void { V.l = fetch(); V.h = fetch(); V.b = fetch(); - W.l = read(V.d + I.w + 0); -L W.h = read(V.d + I.w + 1); + W.l = readLong(V.d + I.w + 0); +L W.h = readLong(V.d + I.w + 1); alu(W.w); } @@ -157,7 +157,7 @@ auto WDC65816::instructionIndirectLongRead8(alu8 op, r16 I) -> void { V.l = readDirectN(U.l + 0); V.h = readDirectN(U.l + 1); V.b = readDirectN(U.l + 2); -L W.l = read(V.d + I.w + 0); +L W.l = readLong(V.d + I.w + 0); alu(W.l); } @@ -167,8 +167,8 @@ auto WDC65816::instructionIndirectLongRead16(alu16 op, r16 I) -> void { V.l = readDirectN(U.l + 0); V.h = readDirectN(U.l + 1); V.b = readDirectN(U.l + 2); - W.l = read(V.d + I.w + 0); -L W.h = read(V.d + I.w + 1); + W.l = readLong(V.d + I.w + 0); +L W.h = readLong(V.d + I.w + 1); alu(W.w); } diff --git a/bsnes/processor/wdc65816/instructions-write.cpp b/bsnes/processor/wdc65816/instructions-write.cpp index 2fc5dc26..f2851ed6 100755 --- a/bsnes/processor/wdc65816/instructions-write.cpp +++ b/bsnes/processor/wdc65816/instructions-write.cpp @@ -30,15 +30,15 @@ auto WDC65816::instructionLongWrite8(r16 I) -> void { V.l = fetch(); V.h = fetch(); V.b = fetch(); -L write(V.d + I.w + 0, A.l); +L writeLong(V.d + I.w + 0, A.l); } auto WDC65816::instructionLongWrite16(r16 I) -> void { V.l = fetch(); V.h = fetch(); V.b = fetch(); - write(V.d + I.w + 0, A.l); -L write(V.d + I.w + 1, A.h); + writeLong(V.d + I.w + 0, A.l); +L writeLong(V.d + I.w + 1, A.h); } auto WDC65816::instructionDirectWrite8(r16 F) -> void { @@ -130,7 +130,7 @@ auto WDC65816::instructionIndirectLongWrite8(r16 I) -> void { V.l = readDirectN(U.l + 0); V.h = readDirectN(U.l + 1); V.b = readDirectN(U.l + 2); -L write(V.d + I.w + 0, A.l); +L writeLong(V.d + I.w + 0, A.l); } auto WDC65816::instructionIndirectLongWrite16(r16 I) -> void { @@ -139,8 +139,8 @@ auto WDC65816::instructionIndirectLongWrite16(r16 I) -> void { V.l = readDirectN(U.l + 0); V.h = readDirectN(U.l + 1); V.b = readDirectN(U.l + 2); - write(V.d + I.w + 0, A.l); -L write(V.d + I.w + 1, A.h); + writeLong(V.d + I.w + 0, A.l); +L writeLong(V.d + I.w + 1, A.h); } auto WDC65816::instructionStackWrite8() -> void { diff --git a/bsnes/processor/wdc65816/memory.cpp b/bsnes/processor/wdc65816/memory.cpp index 3f748236..4f603740 100644 --- a/bsnes/processor/wdc65816/memory.cpp +++ b/bsnes/processor/wdc65816/memory.cpp @@ -50,31 +50,39 @@ auto WDC65816::pushN(uint8 data) -> void { } auto WDC65816::readDirect(uint address) -> uint8 { - if(EF && !D.l) return read(D.w | uint8(address)); - return read(uint16(D.w + address)); + if(EF && !D.l) return read(D.w | address & 0xff); + return read(D.w + address & 0xffff); } auto WDC65816::writeDirect(uint address, uint8 data) -> void { - if(EF && !D.l) return write(D.w | uint8(address), data); - write(uint16(D.w + address), data); + if(EF && !D.l) return write(D.w | address & 0xff, data); + write(D.w + address & 0xffff, data); } auto WDC65816::readDirectN(uint address) -> uint8 { - return read(uint16(D.w + address)); + return read(D.w + address & 0xffff); } auto WDC65816::readBank(uint address) -> uint8 { - return read((B << 16) + address); + return read((B << 16) + address & 0xffffff); } auto WDC65816::writeBank(uint address, uint8 data) -> void { - write((B << 16) + address, data); + write((B << 16) + address & 0xffffff, data); +} + +auto WDC65816::readLong(uint address) -> uint8 { + return read(address & 0xffffff); +} + +auto WDC65816::writeLong(uint address, uint8 data) -> void { + write(address & 0xffffff, data); } auto WDC65816::readStack(uint address) -> uint8 { - return read(uint16(S.w + address)); + return read(S.w + address & 0xffff); } auto WDC65816::writeStack(uint address, uint8 data) -> void { - write(uint16(S.w + address), data); + write(S.w + address & 0xffff, data); } diff --git a/bsnes/processor/wdc65816/wdc65816.hpp b/bsnes/processor/wdc65816/wdc65816.hpp index 4fd2db2d..eac2b55f 100755 --- a/bsnes/processor/wdc65816/wdc65816.hpp +++ b/bsnes/processor/wdc65816/wdc65816.hpp @@ -10,8 +10,8 @@ struct WDC65816 { virtual auto idle() -> void = 0; virtual auto idleBranch() -> void {} virtual auto idleJump() -> void {} - virtual auto read(uint24 addr) -> uint8 = 0; - virtual auto write(uint24 addr, uint8 data) -> void = 0; + virtual auto read(uint addr) -> uint8 = 0; + virtual auto write(uint addr, uint8 data) -> void = 0; virtual auto lastCycle() -> void = 0; virtual auto interruptPending() const -> bool = 0; virtual auto interrupt() -> void; @@ -44,22 +44,24 @@ struct WDC65816 { auto power() -> void; //memory.cpp - inline auto idleIRQ() -> void; - inline auto idle2() -> void; - inline auto idle4(uint16 x, uint16 y) -> void; - inline auto idle6(uint16 address) -> void; - inline auto fetch() -> uint8; - inline auto pull() -> uint8; - auto push(uint8 data) -> void; - inline auto pullN() -> uint8; - inline auto pushN(uint8 data) -> void; - inline auto readDirect(uint address) -> uint8; - inline auto writeDirect(uint address, uint8 data) -> void; - inline auto readDirectN(uint address) -> uint8; - inline auto readBank(uint address) -> uint8; - inline auto writeBank(uint address, uint8 data) -> void; - inline auto readStack(uint address) -> uint8; - inline auto writeStack(uint address, uint8 data) -> void; + alwaysinline auto idleIRQ() -> void; + alwaysinline auto idle2() -> void; + alwaysinline auto idle4(uint16 x, uint16 y) -> void; + alwaysinline auto idle6(uint16 address) -> void; + alwaysinline auto fetch() -> uint8; + alwaysinline auto pull() -> uint8; + auto push(uint8 data) -> void; + alwaysinline auto pullN() -> uint8; + alwaysinline auto pushN(uint8 data) -> void; + alwaysinline auto readDirect(uint address) -> uint8; + alwaysinline auto writeDirect(uint address, uint8 data) -> void; + alwaysinline auto readDirectN(uint address) -> uint8; + alwaysinline auto readBank(uint address) -> uint8; + alwaysinline auto writeBank(uint address, uint8 data) -> void; + alwaysinline auto readLong(uint address) -> uint8; + alwaysinline auto writeLong(uint address, uint8 data) -> void; + alwaysinline auto readStack(uint address) -> uint8; + alwaysinline auto writeStack(uint address, uint8 data) -> void; //algorithms.cpp using alu8 = auto (WDC65816::*)( uint8) -> uint8; diff --git a/bsnes/sfc/coprocessor/sa1/memory.cpp b/bsnes/sfc/coprocessor/sa1/memory.cpp index bf4a28f8..d82d974b 100644 --- a/bsnes/sfc/coprocessor/sa1/memory.cpp +++ b/bsnes/sfc/coprocessor/sa1/memory.cpp @@ -18,7 +18,7 @@ auto SA1::idleBranch() -> void { if(r.pc.d & 1) idleJump(); } -auto SA1::read(uint24 address) -> uint8 { +auto SA1::read(uint address) -> uint8 { r.mar = address; uint8 data = r.mdr; @@ -62,7 +62,7 @@ auto SA1::read(uint24 address) -> uint8 { return data; } -auto SA1::write(uint24 address, uint8 data) -> void { +auto SA1::write(uint address, uint8 data) -> void { r.mar = address; r.mdr = data; diff --git a/bsnes/sfc/coprocessor/sa1/sa1.hpp b/bsnes/sfc/coprocessor/sa1/sa1.hpp index f4807c2a..c493ce6b 100644 --- a/bsnes/sfc/coprocessor/sa1/sa1.hpp +++ b/bsnes/sfc/coprocessor/sa1/sa1.hpp @@ -38,8 +38,8 @@ struct SA1 : Processor::WDC65816, Thread { alwaysinline auto idle() -> void override; alwaysinline auto idleJump() -> void override; alwaysinline auto idleBranch() -> void override; - alwaysinline auto read(uint24 address) -> uint8 override; - alwaysinline auto write(uint24 address, uint8 data) -> void override; + alwaysinline auto read(uint address) -> uint8 override; + alwaysinline auto write(uint address, uint8 data) -> void override; auto readVBR(uint address, uint8 data = 0) -> uint8; auto readDisassembler(uint address) -> uint8 override; diff --git a/bsnes/sfc/cpu/cpu.cpp b/bsnes/sfc/cpu/cpu.cpp index f198da93..5020183a 100644 --- a/bsnes/sfc/cpu/cpu.cpp +++ b/bsnes/sfc/cpu/cpu.cpp @@ -109,7 +109,7 @@ auto CPU::power(bool reset) -> void { alu = {}; status = {}; - status.lineClocks = lineclocks(); + status.lineClocks = hperiod(); status.dramRefreshPosition = (version == 1 ? 530 : 538); status.hdmaSetupPosition = (version == 1 ? 12 + 8 - dmaCounter() : 12 + dmaCounter()); status.hdmaPosition = 1104; diff --git a/bsnes/sfc/cpu/cpu.hpp b/bsnes/sfc/cpu/cpu.hpp index 5c11202a..5ecacad9 100644 --- a/bsnes/sfc/cpu/cpu.hpp +++ b/bsnes/sfc/cpu/cpu.hpp @@ -25,8 +25,8 @@ struct CPU : Processor::WDC65816, Thread, PPUcounter { //memory.cpp auto idle() -> void override; - auto read(uint24 addr) -> uint8 override; - auto write(uint24 addr, uint8 data) -> void override; + auto read(uint addr) -> uint8 override; + auto write(uint addr, uint8 data) -> void override; auto readDisassembler(uint addr) -> uint8 override; //io.cpp diff --git a/bsnes/sfc/cpu/memory.cpp b/bsnes/sfc/cpu/memory.cpp index 254cc529..55a2227c 100644 --- a/bsnes/sfc/cpu/memory.cpp +++ b/bsnes/sfc/cpu/memory.cpp @@ -6,7 +6,7 @@ auto CPU::idle() -> void { aluEdge(); } -auto CPU::read(uint24 address) -> uint8 { +auto CPU::read(uint address) -> uint8 { status.irqLock = false; if(address & 0x408000) { @@ -46,7 +46,7 @@ auto CPU::read(uint24 address) -> uint8 { return data; } -auto CPU::write(uint24 address, uint8 data) -> void { +auto CPU::write(uint address, uint8 data) -> void { status.irqLock = false; aluEdge(); diff --git a/bsnes/sfc/cpu/timing.cpp b/bsnes/sfc/cpu/timing.cpp index 08dadd82..46f80245 100644 --- a/bsnes/sfc/cpu/timing.cpp +++ b/bsnes/sfc/cpu/timing.cpp @@ -82,7 +82,7 @@ auto CPU::step(uint clocks) -> void { //called by ppu.tick() when Hcounter=0 auto CPU::scanline() -> void { - status.lineClocks = lineclocks(); + status.lineClocks = hperiod(); //forcefully sync S-CPU to other processors, in case chips are not communicating synchronizeSMP(); diff --git a/bsnes/sfc/dsp/SPC_DSP.cpp b/bsnes/sfc/dsp/SPC_DSP.cpp index 6d4f3094..91f17c9e 100644 --- a/bsnes/sfc/dsp/SPC_DSP.cpp +++ b/bsnes/sfc/dsp/SPC_DSP.cpp @@ -415,7 +415,7 @@ MISC_CLOCK( 30 ) inline VOICE_CLOCK( V1 ) { - m.t_dir_addr = m.t_dir * 0x100 + m.t_srcn * 4; + m.t_dir_addr = (m.t_dir * 0x100 + m.t_srcn * 4) & 0xffff; m.t_srcn = VREG(v->regs,srcn); } inline VOICE_CLOCK( V2 ) diff --git a/bsnes/sfc/ppu-fast/ppu.cpp b/bsnes/sfc/ppu-fast/ppu.cpp index 912ed20f..9ae5bca6 100644 --- a/bsnes/sfc/ppu-fast/ppu.cpp +++ b/bsnes/sfc/ppu-fast/ppu.cpp @@ -100,7 +100,7 @@ auto PPU::main() -> void { } } - step(lineclocks() - hcounter()); + step(hperiod() - hcounter()); } auto PPU::scanline() -> void { diff --git a/bsnes/sfc/ppu/counter/counter-inline.hpp b/bsnes/sfc/ppu/counter/counter-inline.hpp old mode 100644 new mode 100755 index 7c3e7ec1..687a7fad --- a/bsnes/sfc/ppu/counter/counter-inline.hpp +++ b/bsnes/sfc/ppu/counter/counter-inline.hpp @@ -1,71 +1,84 @@ -//this should only be called by CPU::PPUcounter::tick(); -//keeps track of previous counter positions in history table auto PPUcounter::tick() -> void { - status.hcounter += 2; //increment by smallest unit of time - if(status.hcounter == lineclocks()) { - status.hcounter = 0; - vcounterTick(); + time.hcounter += 2; //increment by smallest unit of time. + if(time.hcounter == hperiod()) { + last.hperiod = hperiod(); + time.hcounter = 0; + tickScanline(); } - - history.index = (history.index + 1) & 2047; - history.field [history.index] = status.field; - history.vcounter[history.index] = status.vcounter; - history.hcounter[history.index] = status.hcounter; } -//this should only be called by PPU::PPUcounter::tick(n); -//allows stepping by more than the smallest unit of time auto PPUcounter::tick(uint clocks) -> void { - status.hcounter += clocks; - if(status.hcounter >= lineclocks()) { - status.hcounter -= lineclocks(); - vcounterTick(); + time.hcounter += clocks; + if(time.hcounter >= hperiod()) { + last.hperiod = hperiod(); + time.hcounter -= hperiod(); + tickScanline(); } } -//internal -auto PPUcounter::vcounterTick() -> void { - if(++status.vcounter == 128) status.interlace = ppu.interlace(); - if(vcounter() == (Region::NTSC() ? 262 : 312) + (interlace() && !field())) { - status.vcounter = 0; - status.field ^= 1; +auto PPUcounter::tickScanline() -> void { + if(++time.vcounter == 128) { + //it's not important when this is captured: it is only needed at V=240 or V=311. + time.interlace = ppu.interlace(); + time.vperiod += interlace() && !field(); } - status.lineclocks = 1364; - //NTSC and PAL scanlines rates would not match up with color clocks if every scanline were 1364 clocks - //to offset for this error, NTSC has one short scanline, and PAL has one long scanline - if(Region::NTSC() && interlace() == 0 && field() == 1 && vcounter() == 240) status.lineclocks -= 4; - if(Region::PAL() && interlace() == 1 && field() == 1 && vcounter() == 311) status.lineclocks += 4; + + if(vcounter() == vperiod()) { + last.vperiod = vperiod(); + //this may be off by one until V=128, hence why vperiod() is a private function. + time.vperiod = Region::NTSC() ? 262 : 312; + time.vcounter = 0; + time.field ^= 1; + } + + time.hperiod = 1364; + //NTSC and PAL scanline rates would not match up with color clocks if every scanline were 1364 clocks. + //to offset for this error, NTSC has one short scanline, and PAL has one long scanline. + if(Region::NTSC() && interlace() == 0 && field() == 1 && vcounter() == 240) time.hperiod -= 4; + if(Region::PAL() && interlace() == 1 && field() == 1 && vcounter() == 311) time.hperiod += 4; if(scanline) scanline(); } -auto PPUcounter::interlace() const -> bool { return status.interlace; } -auto PPUcounter::field() const -> bool { return status.field; } -auto PPUcounter::vcounter() const -> uint { return status.vcounter; } -auto PPUcounter::hcounter() const -> uint { return status.hcounter; } -auto PPUcounter::lineclocks() const -> uint { return status.lineclocks; } +auto PPUcounter::interlace() const -> bool { return time.interlace; } +auto PPUcounter::field() const -> bool { return time.field; } +auto PPUcounter::vcounter() const -> uint { return time.vcounter; } +auto PPUcounter::hcounter() const -> uint { return time.hcounter; } +auto PPUcounter::vperiod() const -> uint { return time.vperiod; } +auto PPUcounter::hperiod() const -> uint { return time.hperiod; } -auto PPUcounter::field(uint offset) const -> bool { return history.field[(history.index - (offset >> 1)) & 2047]; } -auto PPUcounter::vcounter(uint offset) const -> uint { return history.vcounter[(history.index - (offset >> 1)) & 2047]; } -auto PPUcounter::hcounter(uint offset) const -> uint { return history.hcounter[(history.index - (offset >> 1)) & 2047]; } +auto PPUcounter::vcounter(uint offset) const -> uint { + if(offset <= hcounter()) return vcounter(); + if(vcounter() > 0) return vcounter() - 1; + return last.vperiod - 1; +} -//one PPU dot = 4 CPU clocks +auto PPUcounter::hcounter(uint offset) const -> uint { + if(offset <= hcounter()) return hcounter() - offset; + return hcounter() + last.hperiod - offset; +} + +//one PPU dot = 4 CPU clocks. // //PPU dots 323 and 327 are 6 CPU clocks long. //this does not apply to NTSC non-interlace scanline 240 on odd fields. this is //because the PPU skips one dot to alter the color burst phase of the video signal. +//it is not known what happens for PAL 1368 clock scanlines. // //dot 323 range = {1292, 1294, 1296} //dot 327 range = {1310, 1312, 1314} auto PPUcounter::hdot() const -> uint { - if(lineclocks() == 1360) { - return (hcounter() >> 2); + if(hperiod() == 1360) { + return hcounter() >> 2; } else { - return (hcounter() - ((hcounter() > 1292) << 1) - ((hcounter() > 1310) << 1)) >> 2; + return hcounter() - ((hcounter() > 1292) << 1) - ((hcounter() > 1310) << 1) >> 2; } } auto PPUcounter::reset() -> void { - status = {}; - history = {}; + time = {}; + last = {}; + + time.vperiod = last.vperiod = Region::NTSC() ? 262 : 312; + time.hperiod = last.hperiod = 1364; } diff --git a/bsnes/sfc/ppu/counter/counter.hpp b/bsnes/sfc/ppu/counter/counter.hpp old mode 100644 new mode 100755 index 3073996c..d4e53710 --- a/bsnes/sfc/ppu/counter/counter.hpp +++ b/bsnes/sfc/ppu/counter/counter.hpp @@ -12,16 +12,17 @@ struct PPUcounter { alwaysinline auto tick() -> void; - alwaysinline auto tick(uint clocks) -> void; + alwaysinline auto tick(uint clocks) -> void; private: + alwaysinline auto tickScanline() -> void; public: alwaysinline auto interlace() const -> bool; alwaysinline auto field() const -> bool; alwaysinline auto vcounter() const -> uint; alwaysinline auto hcounter() const -> uint; - alwaysinline auto hdot() const -> uint; - alwaysinline auto lineclocks() const -> uint; + alwaysinline auto hdot() const -> uint; private: + alwaysinline auto vperiod() const -> uint; public: + alwaysinline auto hperiod() const -> uint; - alwaysinline auto field(uint offset) const -> bool; alwaysinline auto vcounter(uint offset) const -> uint; alwaysinline auto hcounter(uint offset) const -> uint; @@ -31,20 +32,17 @@ struct PPUcounter { function scanline; private: - alwaysinline auto vcounterTick() -> void; - struct { bool interlace = 0; bool field = 0; + uint vperiod = 0; + uint hperiod = 0; uint vcounter = 0; uint hcounter = 0; - uint lineclocks = 1364; - } status; + } time; struct { - uint index = 0; - bool field[2048] = {}; - uint vcounter[2048] = {}; - uint hcounter[2048] = {}; - } history; + uint vperiod = 0; + uint hperiod = 0; + } last; }; diff --git a/bsnes/sfc/ppu/counter/serialization.cpp b/bsnes/sfc/ppu/counter/serialization.cpp index 3dae5c70..aa798afd 100644 --- a/bsnes/sfc/ppu/counter/serialization.cpp +++ b/bsnes/sfc/ppu/counter/serialization.cpp @@ -1,11 +1,11 @@ auto PPUcounter::serialize(serializer& s) -> void { - s.integer(status.interlace); - s.integer(status.field); - s.integer(status.vcounter); - s.integer(status.hcounter); + s.integer(time.interlace); + s.integer(time.field); + s.integer(time.vperiod); + s.integer(time.hperiod); + s.integer(time.vcounter); + s.integer(time.hcounter); - s.array(history.field); - s.array(history.vcounter); - s.array(history.hcounter); - s.integer(history.index); + s.integer(last.vperiod); + s.integer(last.hperiod); } diff --git a/bsnes/sfc/ppu/ppu.cpp b/bsnes/sfc/ppu/ppu.cpp index 7c2b15ab..0d8db633 100644 --- a/bsnes/sfc/ppu/ppu.cpp +++ b/bsnes/sfc/ppu/ppu.cpp @@ -90,7 +90,7 @@ auto PPU::main() -> void { obj.tilefetch(); } - step(lineclocks() - hcounter()); + step(hperiod() - hcounter()); } auto PPU::load() -> bool {