From d24d4a7864f9d35d256761cad82419bf011b2992 Mon Sep 17 00:00:00 2001 From: Antonio Maiorano Date: Sat, 23 Dec 2023 01:30:35 -0500 Subject: [PATCH] Implement shift register mode "disabled" When disabled, the blank signal is controlled by the peripheral control register. This was partially hooked up already, but was just missing the last bit of actually tracking whether the shift mode was disabled or not. Fixes Sea Pup homebrew game. --- .../emulator/include/emulator/ShiftRegister.h | 18 ++++++++------ libs/emulator/src/Via.cpp | 24 ++++++++----------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/libs/emulator/include/emulator/ShiftRegister.h b/libs/emulator/include/emulator/ShiftRegister.h index 0da1702..56f743e 100644 --- a/libs/emulator/include/emulator/ShiftRegister.h +++ b/libs/emulator/include/emulator/ShiftRegister.h @@ -2,27 +2,31 @@ #include "core/Base.h" +enum class ShiftRegisterMode { + // There are actually more modes, but I think Vectrex only uses these ones + Disabled, + ShiftOutUnder02, +}; + + // The VIA's shift register, mainly responsible for driving the drawing of line patterns. It can be // loaded with an 8 bit mask that represents the pattern to be drawn, and although it's called a // "shift" register, it actually rotates its values so the pattern will repeat. class ShiftRegister { public: + void SetMode(ShiftRegisterMode mode) { m_mode = mode; } + ShiftRegisterMode Mode() const { return m_mode; } + void SetValue(uint8_t value); uint8_t ReadValue() const; bool CB2Active() const { return m_cb2Active; } - bool Enabled() const { - // For now, always return true as it seems the shift register isn't disabled by games on - // Vectrex. Also, am not sure exactly how to control the enabled state of the shift - // register; I believe it may be controlled by bit 4 of the VIA's auxiliary control register - // ($B). - return true; - } void Update(cycles_t cycles); void SetInterruptFlag(bool enabled) { m_interruptFlag = enabled; } bool InterruptFlag() const { return m_interruptFlag; } private: + ShiftRegisterMode m_mode = ShiftRegisterMode::Disabled; uint8_t m_value = 0; mutable int m_shiftCyclesLeft = 0; bool m_cb2Active = false; diff --git a/libs/emulator/src/Via.cpp b/libs/emulator/src/Via.cpp index 24c5679..44fdf72 100644 --- a/libs/emulator/src/Via.cpp +++ b/libs/emulator/src/Via.cpp @@ -5,11 +5,6 @@ #include "emulator/MemoryMap.h" namespace { - enum class ShiftRegisterMode { - // There are actually many more modes, but I think Vectrex only uses one - ShiftOutUnder02 - }; - namespace Register { enum Type { PortB = 0x0, @@ -51,10 +46,14 @@ namespace { inline ShiftRegisterMode GetShiftRegisterMode(uint8_t auxCntrl) { uint8_t result = ReadBitsWithShift(auxCntrl, ShiftRegisterModeMask, ShiftRegisterModeShift); - if (result != 0b110) { - ErrorHandler::Unsupported( - "ShiftRegisterMode expected to only support ShiftOutUnder02\n"); + switch (result) { + case 0: + return ShiftRegisterMode::Disabled; + case 0b110: + return ShiftRegisterMode::ShiftOutUnder02; } + ErrorHandler::Unsupported( + "Unexpected ShiftRegisterMode: 0x%X, forcing to ShiftOutUnder02\n", result); return ShiftRegisterMode::ShiftOutUnder02; } @@ -209,8 +208,7 @@ void Via::DoSync(cycles_t cycles, const Input& input, RenderContext& renderConte m_shiftRegister.Update(cycles); // Shift register's CB2 line drives /BLANK - //@TODO: check some flag on the shift register to know whether it's active - if (m_shiftRegister.Enabled()) { + if (m_shiftRegister.Mode() == ShiftRegisterMode::ShiftOutUnder02) { m_screen.SetBlankEnabled(m_shiftRegister.CB2Active()); } @@ -425,9 +423,7 @@ void Via::Write(uint16_t address, uint8_t value) { break; case Register::AuxCntl: { - // For now just read the shift register mode, which will assert if it's invalid/unexpected - auto shiftRegisterMode = AuxCntl::GetShiftRegisterMode(value); - (void)shiftRegisterMode; + m_shiftRegister.SetMode(AuxCntl::GetShiftRegisterMode(value)); ASSERT_MSG(AuxCntl::GetTimer1Mode(value) == TimerMode::OneShot, "t1 assumed always on one-shot mode"); @@ -450,7 +446,7 @@ void Via::Write(uint16_t address, uint8_t value) { "Top 2 bits should always be 1 (right?)"); m_periphCntl = value; - if (!m_shiftRegister.Enabled()) { + if (m_shiftRegister.Mode() == ShiftRegisterMode::Disabled) { m_screen.SetBlankEnabled(PeriphCntl::IsBlankEnabled(m_periphCntl)); } } break;