From bab2ac812acfa99908cd453be8e6559c8170db92 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Sat, 17 Dec 2016 22:31:34 +1100 Subject: [PATCH] Update to v101r24 release. byuu says: Changelog: - SMS: extended bus mapping of in/out ports: now decoding them fully inside ms/bus - SMS: moved Z80 disassembly code from processor/z80 to ms/cpu (cosmetic) - SMS: hooked up non-functional silent PSG sample generation, so I can cap the framerate at 60fps - SMS: hooked up the VDP main loop: 684 clocks/scanline, 262 scanlines/frame (no PAL support yet) - SMS: emulated the VDP Vcounter and Hcounter polling ... hopefully it's right, as it's very bizarre - SMS: emulated VDP in/out ports (data read, data write, status read, control write, register write) - SMS: decoding and caching all VDP register flags (variable names will probably change) - nall: \#undef IN on Windows port (prevent compilation warning on processor/z80) Watching Sonic the Hedgehog, I can definitely see some VDP register writes going through, which is a good sign. Probably the big thing that's needed before I can get enough into the VDP to start showing graphics is interrupt support. And interrupts are never fun to figure out :/ What really sucks on this front is I'm flying blind on the Z80 CPU core. Without a working VDP, I can't run any Z80 test ROMs to look for CPU bugs. And the CPU is certainly too buggy still to run said test ROM anyway. I can't find any SMS emulators with trace logging from reset. Such logs vastly accelerate tracking down CPU logic bugs, so without them, it's going to take a lot longer. --- higan/emulator/emulator.hpp | 2 +- higan/ms/bus/bus.cpp | 29 +++++- higan/ms/cpu/cpu.cpp | 8 ++ higan/ms/cpu/cpu.hpp | 3 + higan/ms/psg/psg.cpp | 2 + higan/ms/psg/psg.hpp | 2 + higan/ms/vdp/io.cpp | 152 ++++++++++++++++++++++++++++ higan/ms/vdp/vdp.cpp | 26 +++-- higan/ms/vdp/vdp.hpp | 75 +++++++++++++- higan/processor/z80/instruction.cpp | 7 -- higan/processor/z80/z80.cpp | 1 - higan/processor/z80/z80.hpp | 3 - nall/platform.hpp | 3 +- 13 files changed, 279 insertions(+), 34 deletions(-) create mode 100644 higan/ms/vdp/io.cpp diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index d5d21a67..b36f6e41 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.23"; + static const string Version = "101.24"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/ms/bus/bus.cpp b/higan/ms/bus/bus.cpp index 2ff3c580..cd877301 100644 --- a/higan/ms/bus/bus.cpp +++ b/higan/ms/bus/bus.cpp @@ -15,14 +15,37 @@ auto Bus::write(uint16 addr, uint8 data) -> void { } auto Bus::in(uint8 addr) -> uint8 { - switch(addr) { - case 0x7e: return vdp.in(addr); - case 0x7f: return vdp.in(addr); + switch(addr >> 6) { + + case 0: { + return 0xff; //SMS1 = MDR, SMS2 = 0xff } + + case 1: { + return !addr.bit(0) ? vdp.vcounter() : vdp.hcounter(); + } + + case 2: { + return !addr.bit(0) ? vdp.data() : vdp.status(); + } + + } + return 0x00; } auto Bus::out(uint8 addr, uint8 data) -> void { + switch(addr >> 6) { + + case 2: { + return !addr.bit(0) ? vdp.data(data) : vdp.control(data); + } + + case 3: { + return; //unmapped + } + + } } } diff --git a/higan/ms/cpu/cpu.cpp b/higan/ms/cpu/cpu.cpp index 80b3652f..4067b174 100644 --- a/higan/ms/cpu/cpu.cpp +++ b/higan/ms/cpu/cpu.cpp @@ -9,6 +9,12 @@ auto CPU::Enter() -> void { } auto CPU::main() -> void { + #if 1 + if(instructionsExecuted < 20) + print(disassemble(r.pc), "\n"); + instructionsExecuted++; + #endif + instruction(); } @@ -26,6 +32,8 @@ auto CPU::power() -> void { auto CPU::reset() -> void { Z80::reset(); create(CPU::Enter, system.colorburst()); + + instructionsExecuted = 0; } } diff --git a/higan/ms/cpu/cpu.hpp b/higan/ms/cpu/cpu.hpp index 127e7d48..b5411a40 100644 --- a/higan/ms/cpu/cpu.hpp +++ b/higan/ms/cpu/cpu.hpp @@ -7,6 +7,9 @@ struct CPU : Processor::Z80, Thread { auto power() -> void; auto reset() -> void; + +private: + uint64 instructionsExecuted; }; extern CPU cpu; diff --git a/higan/ms/psg/psg.cpp b/higan/ms/psg/psg.cpp index 7d08d9e2..f9a96bde 100644 --- a/higan/ms/psg/psg.cpp +++ b/higan/ms/psg/psg.cpp @@ -10,6 +10,7 @@ auto PSG::Enter() -> void { auto PSG::main() -> void { step(1); + stream->sample(0.0, 0.0); } auto PSG::step(uint clocks) -> void { @@ -22,6 +23,7 @@ auto PSG::power() -> void { auto PSG::reset() -> void { create(PSG::Enter, system.colorburst()); + stream = Emulator::audio.createStream(2, system.colorburst()); } } diff --git a/higan/ms/psg/psg.hpp b/higan/ms/psg/psg.hpp index f9d20933..89ba7388 100644 --- a/higan/ms/psg/psg.hpp +++ b/higan/ms/psg/psg.hpp @@ -1,6 +1,8 @@ //TI SN76489 struct PSG : Thread { + shared_pointer stream; + static auto Enter() -> void; auto main() -> void; auto step(uint clocks) -> void; diff --git a/higan/ms/vdp/io.cpp b/higan/ms/vdp/io.cpp new file mode 100644 index 00000000..6b6ff01b --- /dev/null +++ b/higan/ms/vdp/io.cpp @@ -0,0 +1,152 @@ +auto VDP::vcounter() -> uint8 { + if(io.lines240) { + //NTSC 256x240 + return io.vcounter; + } else if(io.lines224) { + //NTSC 256x224 + return io.vcounter <= 234 ? io.vcounter : io.vcounter - 6; + } else { + //NTSC 256x192 + return io.vcounter <= 218 ? io.vcounter : io.vcounter - 6; + } + + unreachable; +} + +auto VDP::hcounter() -> uint8 { + uint hcounter = io.hcounter >> 2; + return hcounter <= 233 ? hcounter : hcounter - 86; +} + +auto VDP::data() -> uint8 { + io.controlLatch = 0; + + auto data = io.vramLatch; + io.vramLatch = vram[io.address++]; + return data; +} + +auto VDP::status() -> uint8 { + io.controlLatch = 0; + + return 0x00; +} + +auto VDP::data(uint8 data) -> void { + io.controlLatch = 0; + + if(io.code <= 2) { + vram[io.address++] = data; + } else { + cram[io.address++ & 0x3f] = data; + } +} + +auto VDP::control(uint8 data) -> void { + if(io.controlLatch == 0) { + io.controlLatch = 1; + io.address.bits(0,7) = data.bits(0,7); + return; + } else { + io.controlLatch = 0; + io.address.bits(8,13) = data.bits(0,5); + io.code.bits(0,1) = data.bits(6,7); + } + + if(io.code == 0) { + io.vramLatch = vram[io.address++]; + } + + if(io.code == 2) { + registerWrite(io.address.bits(11,8), io.address.bits(7,0)); + } +} + +auto VDP::registerWrite(uint4 addr, uint8 data) -> void { + switch(addr) { + + //mode control 1 + case 0x0: { + io.externalSync = data.bit(0); + io.extendedHeight = data.bit(1); + io.mode4 = data.bit(2); + io.spriteShift = data.bit(3); + io.lineInterrupts = data.bit(4); + io.leftClip = data.bit(5); + io.horizontalScrollLock = data.bit(6); + io.verticalScrollLock = data.bit(7); + return; + } + + //mode control 2 + case 0x1: { + io.spriteDouble = data.bit(0); + io.spriteTile = data.bit(1); + io.lines240 = data.bit(3); + io.lines224 = data.bit(4); + io.frameInterrupts = data.bit(5); + io.displayEnable = data.bit(6); + return; + } + + //name table base address + case 0x2: { + io.nameTableMask = data.bit(0); + io.nameTableAddress = data.bits(1,3); + return; + } + + //color table base address + case 0x3: { + io.colorTableAddress = data.bits(0,7); + return; + } + + //pattern table base address + case 0x4: { + io.patternTableAddress = data.bits(0,7); + return; + } + + //sprite attribute table base address + case 0x5: { + io.spriteAttributeTableMask = data.bit(0); + io.spriteAttributeTableAddress = data.bits(1,6); + return; + } + + //sprite pattern table base address + case 0x6: { + io.spritePatternTableMask = data.bits(0,1); + io.spritePatternTableAddress = data.bit(2); + return; + } + + //backdrop color + case 0x7: { + io.backdropColor = data.bits(0,3); + return; + } + + //horizontal scroll offset + case 0x8: { + io.hscroll = data.bits(0,7); + return; + } + + //vertical scroll offset + case 0x9: { + io.vscroll = data.bits(0,7); + return; + } + + //line counter + case 0xa: { + io.lineCounter = data.bits(0,7); + return; + } + + //0xb - 0xf unmapped + + } +} diff --git a/higan/ms/vdp/vdp.cpp b/higan/ms/vdp/vdp.cpp index a8998375..3233216f 100644 --- a/higan/ms/vdp/vdp.cpp +++ b/higan/ms/vdp/vdp.cpp @@ -3,6 +3,7 @@ namespace MasterSystem { VDP vdp; +#include "io.cpp" auto VDP::Enter() -> void { while(true) scheduler.synchronize(), vdp.main(); @@ -10,7 +11,7 @@ auto VDP::Enter() -> void { auto VDP::main() -> void { for(uint y : range(262)) { - for(uint x : range(342)) { + for(uint x : range(684)) { step(1); } if(y == 240) scheduler.exit(Scheduler::Event::Frame); @@ -18,6 +19,13 @@ auto VDP::main() -> void { } auto VDP::step(uint clocks) -> void { + if(++io.hcounter == 684) { + io.hcounter = 0; + if(++io.vcounter == 262) { + io.vcounter = 0; + } + } + Thread::step(clocks); synchronize(cpu); } @@ -26,23 +34,13 @@ auto VDP::refresh() -> void { Emulator::video.refresh(buffer, 256 * sizeof(uint32), 256, 240); } -auto VDP::in(uint8 addr) -> uint8 { - switch(addr) { - } - - return 0xb0; -} - -auto VDP::out(uint8 addr, uint8 data) -> void { - switch(addr) { - } -} - auto VDP::power() -> void { } auto VDP::reset() -> void { - create(VDP::Enter, system.colorburst()); + create(VDP::Enter, system.colorburst() * 15.0 / 5.0); + + memory::fill(&io, sizeof(IO)); } } diff --git a/higan/ms/vdp/vdp.hpp b/higan/ms/vdp/vdp.hpp index b0fb8fea..7859d7e6 100644 --- a/higan/ms/vdp/vdp.hpp +++ b/higan/ms/vdp/vdp.hpp @@ -6,14 +6,83 @@ struct VDP : Thread { auto step(uint clocks) -> void; auto refresh() -> void; - auto in(uint8 addr) -> uint8; - auto out(uint8 addr, uint8 data) -> void; - auto power() -> void; auto reset() -> void; + //io.cpp + auto vcounter() -> uint8; + auto hcounter() -> uint8; + auto data() -> uint8; + auto status() -> uint8; + + auto data(uint8) -> void; + auto control(uint8) -> void; + auto registerWrite(uint4 addr, uint8 data) -> void; + private: uint32 buffer[256 * 240]; + uint8 vram[0x4000]; + uint8 cram[0x40]; + + struct IO { + uint vcounter; + uint hcounter; + + bool controlLatch; + uint16 controlData; + uint2 code; + uint14 address; + + uint8 vramLatch; + + //$00 mode control 1 + bool externalSync; + bool extendedHeight; + bool mode4; + bool spriteShift; + bool lineInterrupts; + bool leftClip; + bool horizontalScrollLock; + bool verticalScrollLock; + + //$01 mode control 2 + bool spriteDouble; + bool spriteTile; + bool lines240; + bool lines224; + bool frameInterrupts; + bool displayEnable; + + //$02 name table base address + uint1 nameTableMask; + uint3 nameTableAddress; + + //$03 color table base address + uint8 colorTableAddress; + + //$04 pattern table base address + uint8 patternTableAddress; + + //$05 sprite attribute table base address + uint1 spriteAttributeTableMask; + uint6 spriteAttributeTableAddress; + + //$06 sprite pattern table base address + uint2 spritePatternTableMask; + uint1 spritePatternTableAddress; + + //$07 backdrop color + uint4 backdropColor; + + //$08 horizontal scroll offset + uint8 hscroll; + + //$09 vertical scroll offset + uint8 vscroll; + + //$0a line counter + uint8 lineCounter; + } io; }; extern VDP vdp; diff --git a/higan/processor/z80/instruction.cpp b/higan/processor/z80/instruction.cpp index 65bbd436..a60bbe14 100644 --- a/higan/processor/z80/instruction.cpp +++ b/higan/processor/z80/instruction.cpp @@ -1,11 +1,4 @@ auto Z80::instruction() -> void { - #if 1 - if(instructionsExecuted < 20) - print(disassemble(r.pc), "\n"); - #endif - - instructionsExecuted++; - auto code = opcode(); if(code == 0xdd) { r.hlp = &r.ix; return; } if(code == 0xfd) { r.hlp = &r.iy; return; } diff --git a/higan/processor/z80/z80.cpp b/higan/processor/z80/z80.cpp index 7c5117cb..8dc6eaa3 100644 --- a/higan/processor/z80/z80.cpp +++ b/higan/processor/z80/z80.cpp @@ -15,7 +15,6 @@ auto Z80::power() -> void { auto Z80::reset() -> void { memory::fill(&r, sizeof(Registers)); r.hlp = &r.hl; - instructionsExecuted = 0; } auto Z80::parity(uint8 value) const -> bool { diff --git a/higan/processor/z80/z80.hpp b/higan/processor/z80/z80.hpp index 3942ed36..6da942d1 100644 --- a/higan/processor/z80/z80.hpp +++ b/higan/processor/z80/z80.hpp @@ -212,9 +212,6 @@ struct Z80 { } r; Bus* bus = nullptr; - -private: - uint64 instructionsExecuted = 0; }; } diff --git a/nall/platform.hpp b/nall/platform.hpp index 142a52d3..9a02175b 100644 --- a/nall/platform.hpp +++ b/nall/platform.hpp @@ -59,8 +59,7 @@ namespace Math { #endif #if defined(PLATFORM_WINDOWS) - //fight Microsoft's ardent efforts at vendor lock-in - + #undef IN #undef interface #define dllexport __declspec(dllexport) #define MSG_NOSIGNAL 0