From e30780bb72f440f14bbaa65a2b702e5dbe11c79e Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Mon, 26 Dec 2016 23:09:56 +1100 Subject: [PATCH] Update to v101r25 release. byuu says: Changelog: - Makefile: added $(windres), -lpthread to Windows port - GBA: WAITCNT.prefetch is not writable (should fix Donkey Kong: King of Swing) \[endrift\] - SMS: fixed hcounter shift value \[hex\_usr\] - SMS: emulated interrupts (reset button isn't hooked up anywhere, not sure where to put it yet) This WIP actually took a really long time because the documentation on SMS interrupts was all over the place. I'm hoping I've emulated them correctly, but I honestly have no idea. It's based off my best understanding from four or five different sources. So it's probably quite buggy. However, a few interrupts fire in Sonic the Hedgehog, so that's something to start with. Now I just have to hope I've gotten some games far enough in that I can start seeing some data in the VDP VRAM. I need that before I can start emulating graphics mode 4 to get some actual screen output. Or I can just say to hell with it and use a "Hello World" test ROM. That'd probably be smarter. --- higan/GNUmakefile | 2 +- higan/emulator/emulator.hpp | 2 +- higan/gba/cpu/cpu.cpp | 2 +- higan/gba/cpu/io.cpp | 2 +- higan/ms/cpu/cpu.cpp | 23 +++++++++++++- higan/ms/cpu/cpu.hpp | 8 ++++- higan/ms/vdp/io.cpp | 16 ++++++++-- higan/ms/vdp/vdp.cpp | 46 +++++++++++++++++++++------- higan/ms/vdp/vdp.hpp | 18 +++++++++-- higan/processor/z80/instruction.cpp | 7 +++++ higan/processor/z80/instructions.cpp | 3 +- higan/processor/z80/z80.cpp | 34 ++++++++++++++++++++ higan/processor/z80/z80.hpp | 2 ++ higan/target-tomoko/GNUmakefile | 3 +- 14 files changed, 144 insertions(+), 24 deletions(-) diff --git a/higan/GNUmakefile b/higan/GNUmakefile index acac7eb2..69268f1c 100644 --- a/higan/GNUmakefile +++ b/higan/GNUmakefile @@ -24,7 +24,7 @@ ifeq ($(platform),windows) else link += -mwindows endif - link += -mthreads -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 + link += -mthreads -lpthread -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 link += -Wl,-enable-auto-import link += -Wl,-enable-runtime-pseudo-reloc else ifeq ($(platform),macosx) diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index b36f6e41..0326ba99 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -12,7 +12,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "101.24"; + static const string Version = "101.25"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/gba/cpu/cpu.cpp b/higan/gba/cpu/cpu.cpp index 248baed2..ea44274f 100644 --- a/higan/gba/cpu/cpu.cpp +++ b/higan/gba/cpu/cpu.cpp @@ -148,7 +148,7 @@ auto CPU::power() -> void { for(auto& swait : regs.wait.control.swait) swait = 0; regs.wait.control.phi = 0; regs.wait.control.prefetch = 0; - regs.wait.control.gametype = 0; + regs.wait.control.gametype = 0; //0 = GBA, 1 = GBC regs.postboot = 0; regs.mode = Registers::Mode::Normal; regs.clock = 0; diff --git a/higan/gba/cpu/io.cpp b/higan/gba/cpu/io.cpp index cf683757..4860eb40 100644 --- a/higan/gba/cpu/io.cpp +++ b/higan/gba/cpu/io.cpp @@ -383,7 +383,7 @@ auto CPU::writeIO(uint32 addr, uint8 data) -> void { regs.wait.control.swait[2] = data.bit (2); regs.wait.control.phi = data.bit (3); regs.wait.control.prefetch = data.bit (6); - regs.wait.control.gametype = data.bit (7); + //regs.wait.control.gametype is read-only return; //IME diff --git a/higan/ms/cpu/cpu.cpp b/higan/ms/cpu/cpu.cpp index 4067b174..7a609893 100644 --- a/higan/ms/cpu/cpu.cpp +++ b/higan/ms/cpu/cpu.cpp @@ -10,11 +10,24 @@ auto CPU::Enter() -> void { auto CPU::main() -> void { #if 1 + static uint64 instructionsExecuted = 0; if(instructionsExecuted < 20) print(disassemble(r.pc), "\n"); instructionsExecuted++; #endif + //note: SMS1 extbus value is random; SMS2+ is pulled high ($ff) + + if(state.nmiLine) { + state.nmiLine = 0; //edge-sensitive + irq(0, 0x0066, 0xff); + } + + if(state.intLine) { + //level-sensitive + irq(1, 0x0038, 0xff); + } + instruction(); } @@ -24,6 +37,14 @@ auto CPU::step(uint clocks) -> void { synchronize(psg); } +auto CPU::setNMI(bool value) -> void { + state.nmiLine = value; +} + +auto CPU::setINT(bool value) -> void { + state.intLine = value; +} + auto CPU::power() -> void { Z80::bus = &MasterSystem::bus; Z80::power(); @@ -33,7 +54,7 @@ auto CPU::reset() -> void { Z80::reset(); create(CPU::Enter, system.colorburst()); - instructionsExecuted = 0; + memory::fill(&state, sizeof(State)); } } diff --git a/higan/ms/cpu/cpu.hpp b/higan/ms/cpu/cpu.hpp index b5411a40..6a580752 100644 --- a/higan/ms/cpu/cpu.hpp +++ b/higan/ms/cpu/cpu.hpp @@ -5,11 +5,17 @@ struct CPU : Processor::Z80, Thread { auto main() -> void; auto step(uint clocks) -> void; + auto setNMI(bool value) -> void; + auto setINT(bool value) -> void; + auto power() -> void; auto reset() -> void; private: - uint64 instructionsExecuted; + struct State { + boolean nmiLine; + boolean intLine; + } state; }; extern CPU cpu; diff --git a/higan/ms/vdp/io.cpp b/higan/ms/vdp/io.cpp index 6b6ff01b..bce2c07f 100644 --- a/higan/ms/vdp/io.cpp +++ b/higan/ms/vdp/io.cpp @@ -14,7 +14,7 @@ auto VDP::vcounter() -> uint8 { } auto VDP::hcounter() -> uint8 { - uint hcounter = io.hcounter >> 2; + uint hcounter = io.hcounter >> 1; return hcounter <= 233 ? hcounter : hcounter - 86; } @@ -29,7 +29,19 @@ auto VDP::data() -> uint8 { auto VDP::status() -> uint8 { io.controlLatch = 0; - return 0x00; + uint8 result = 0x00; + result |= io.intFrame << 7; + result |= io.spriteOverflow << 6; + result |= io.spriteCollision << 5; + result |= io.fifthSprite << 0; + + io.intLine = 0; + io.intFrame = 0; + io.spriteOverflow = 0; + io.spriteCollision = 0; + io.fifthSprite = 0; + + return result; } auto VDP::data(uint8 data) -> void { diff --git a/higan/ms/vdp/vdp.cpp b/higan/ms/vdp/vdp.cpp index 3233216f..ecd1d270 100644 --- a/higan/ms/vdp/vdp.cpp +++ b/higan/ms/vdp/vdp.cpp @@ -10,30 +10,54 @@ auto VDP::Enter() -> void { } auto VDP::main() -> void { - for(uint y : range(262)) { - for(uint x : range(684)) { - step(1); + if(io.vcounter <= vlines()) { + if(io.lcounter-- == 0) { + io.lcounter = io.lineCounter; + io.intLine = 1; } - if(y == 240) scheduler.exit(Scheduler::Event::Frame); } + + if(io.vcounter == vlines() + 1) { + io.lcounter = io.lineCounter; + io.intFrame = 1; + } + + for(uint x : range(684)) { + step(1); + } + + if(io.vcounter == 240) scheduler.exit(Scheduler::Event::Frame); } auto VDP::step(uint clocks) -> void { - if(++io.hcounter == 684) { - io.hcounter = 0; - if(++io.vcounter == 262) { - io.vcounter = 0; + while(clocks--) { + if(++io.hcounter == 684) { + io.hcounter = 0; + if(++io.vcounter == 262) { + io.vcounter = 0; + } } - } - Thread::step(clocks); - synchronize(cpu); + cpu.setINT((io.lineInterrupts && io.intLine) || (io.frameInterrupts && io.intFrame)); + Thread::step(1); + synchronize(cpu); + } } auto VDP::refresh() -> void { Emulator::video.refresh(buffer, 256 * sizeof(uint32), 256, 240); } +auto VDP::vlines() -> uint { + if(io.lines240) return 240; + if(io.lines224) return 224; + return 192; +} + +auto VDP::vblank() -> bool { + return io.vcounter >= vlines(); +} + auto VDP::power() -> void { } diff --git a/higan/ms/vdp/vdp.hpp b/higan/ms/vdp/vdp.hpp index 7859d7e6..79d5d03a 100644 --- a/higan/ms/vdp/vdp.hpp +++ b/higan/ms/vdp/vdp.hpp @@ -6,6 +6,9 @@ struct VDP : Thread { auto step(uint clocks) -> void; auto refresh() -> void; + auto vlines() -> uint; + auto vblank() -> bool; + auto power() -> void; auto reset() -> void; @@ -25,9 +28,20 @@ private: uint8 cram[0x40]; struct IO { - uint vcounter; - uint hcounter; + uint vcounter; //vertical counter + uint hcounter; //horizontal counter + uint lcounter; //line counter + //interrupt flags + bool intLine; + bool intFrame; + + //status flags + bool spriteOverflow; + bool spriteCollision; + uint5 fifthSprite; + + //latches bool controlLatch; uint16 controlData; uint2 code; diff --git a/higan/processor/z80/instruction.cpp b/higan/processor/z80/instruction.cpp index a60bbe14..1368f35a 100644 --- a/higan/processor/z80/instruction.cpp +++ b/higan/processor/z80/instruction.cpp @@ -2,6 +2,13 @@ auto Z80::instruction() -> void { auto code = opcode(); if(code == 0xdd) { r.hlp = &r.ix; return; } if(code == 0xfd) { r.hlp = &r.iy; return; } + + if(r.ei) { + r.ei = 0; + r.iff1 = 1; + r.iff2 = 1; + } + instruction__(code); r.hlp = &r.hl; } diff --git a/higan/processor/z80/instructions.cpp b/higan/processor/z80/instructions.cpp index 1ceed70f..30720c1a 100644 --- a/higan/processor/z80/instructions.cpp +++ b/higan/processor/z80/instructions.cpp @@ -433,8 +433,7 @@ auto Z80::instructionDJNZ_e() -> void { } auto Z80::instructionEI() -> void { - r.iff1 = 1; - r.iff2 = 1; + r.ei = 1; //raise IFF1, IFF2 after the next instruction } auto Z80::instructionEX_rr_rr(uint16& x, uint16& y) -> void { diff --git a/higan/processor/z80/z80.cpp b/higan/processor/z80/z80.cpp index 8dc6eaa3..ddf2bb81 100644 --- a/higan/processor/z80/z80.cpp +++ b/higan/processor/z80/z80.cpp @@ -17,6 +17,40 @@ auto Z80::reset() -> void { r.hlp = &r.hl; } +auto Z80::irq(bool maskable, uint16 pc, uint8 extbus) -> bool { + if(maskable && !r.iff1) return false; + + push(r.pc); + + switch(r.im) { + + case 0: { + //external data bus ($ff = RST $38) + r.pc = extbus; + break; + } + + case 1: { + //constant address + r.pc = pc; + break; + } + + case 2: { + //vector table with external data bus + uint16 addr = (r.ir.byte.hi << 8) | extbus; + r.pc = read(addr + 0) << 0; + r.pc |= read(addr + 1) << 8; + break; + } + + } + + r.iff1 = 0; + if(maskable) r.iff2 = 0; + return true; +} + auto Z80::parity(uint8 value) const -> bool { value ^= value >> 4; value ^= value >> 2; diff --git a/higan/processor/z80/z80.hpp b/higan/processor/z80/z80.hpp index 6da942d1..b5bf0372 100644 --- a/higan/processor/z80/z80.hpp +++ b/higan/processor/z80/z80.hpp @@ -18,6 +18,7 @@ struct Z80 { auto power() -> void; auto reset() -> void; + auto irq(bool maskable, uint16 vector = 0x0000, uint8 extbus = 0xff) -> bool; auto parity(uint8) const -> bool; //memory.cpp @@ -203,6 +204,7 @@ struct Z80 { uint16 sp; uint16 pc; + boolean ei; //EI instruction executed boolean halt; //HALT instruction executed boolean iff1; //interrupt flip-flop 1 boolean iff2; //interrupt flip-flop 2 diff --git a/higan/target-tomoko/GNUmakefile b/higan/target-tomoko/GNUmakefile index 5569af92..dbcb4f4b 100644 --- a/higan/target-tomoko/GNUmakefile +++ b/higan/target-tomoko/GNUmakefile @@ -20,6 +20,7 @@ ifeq ($(platform),windows) ruby += video.direct3d video.wgl video.directdraw video.gdi ruby += audio.wasapi audio.xaudio2 audio.directsound ruby += input.windows + windres := windres else ifeq ($(platform),macosx) ruby += video.cgl ruby += audio.openal @@ -62,7 +63,7 @@ obj/ui-tools.o: $(ui)/tools/tools.cpp $(call rwildcard,$(ui)/) obj/ui-presentation.o: $(ui)/presentation/presentation.cpp $(call rwildcard,$(ui)/) obj/ui-resource.o: - windres data/resource.rc obj/ui-resource.o + $(windres) data/resource.rc obj/ui-resource.o # targets build: $(objects)