From aaf147b53b925ea3b10636c5a9859205307ee7d4 Mon Sep 17 00:00:00 2001 From: Sour Date: Sun, 17 Feb 2019 15:37:31 -0500 Subject: [PATCH] Refactor internal CPU registers + implement division register --- Core/Console.cpp | 9 +++++- Core/Console.h | 4 +++ Core/Core.vcxproj | 2 ++ Core/Core.vcxproj.filters | 6 ++++ Core/Cpu.cpp | 9 ++++++ Core/Cpu.h | 1 + Core/InternalRegisters.cpp | 63 ++++++++++++++++++++++++++++++++++++++ Core/InternalRegisters.h | 30 ++++++++++++++++++ Core/MemoryManager.h | 15 ++++++--- Core/Ppu.cpp | 35 ++++----------------- Core/Ppu.h | 17 +++------- 11 files changed, 144 insertions(+), 47 deletions(-) create mode 100644 Core/InternalRegisters.cpp create mode 100644 Core/InternalRegisters.h diff --git a/Core/Console.cpp b/Core/Console.cpp index 32c33a5..ad09345 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -3,6 +3,7 @@ #include "Cpu.h" #include "Ppu.h" #include "Spc.h" +#include "InternalRegisters.h" #include "MemoryManager.h" #include "Debugger.h" #include "NotificationManager.h" @@ -74,6 +75,7 @@ void Console::Stop() _ppu.reset(); _spc.reset(); _cart.reset(); + _internalRegisters.reset(); _memoryManager.reset(); } @@ -84,7 +86,7 @@ void Console::LoadRom(VirtualFile romFile, VirtualFile patchFile) shared_ptr cart = BaseCartridge::CreateCartridge(romFile, patchFile); if(cart) { MessageManager::ClearLog(); - + _internalRegisters.reset(new InternalRegisters()); _ppu.reset(new Ppu(shared_from_this())); _spc.reset(new Spc(shared_from_this())); _cart = cart; @@ -152,6 +154,11 @@ shared_ptr Console::GetMemoryManager() return _memoryManager; } +shared_ptr Console::GetInternalRegisters() +{ + return _internalRegisters; +} + shared_ptr Console::GetDebugger(bool autoStart) { shared_ptr debugger = _debugger; diff --git a/Core/Console.h b/Core/Console.h index 0619197..2f37267 100644 --- a/Core/Console.h +++ b/Core/Console.h @@ -8,6 +8,7 @@ class Ppu; class Spc; class BaseCartridge; class MemoryManager; +class InternalRegisters; class Debugger; class DebugHud; class SoundMixer; @@ -24,6 +25,8 @@ private: shared_ptr _spc; shared_ptr _memoryManager; shared_ptr _cart; + shared_ptr _internalRegisters; + shared_ptr _debugger; shared_ptr _notificationManager; @@ -57,6 +60,7 @@ public: shared_ptr GetSpc(); shared_ptr GetCartridge(); shared_ptr GetMemoryManager(); + shared_ptr GetInternalRegisters(); shared_ptr GetDebugger(bool autoStart = true); bool IsRunning(); diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 222017c..7bc74a2 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -74,6 +74,7 @@ + @@ -109,6 +110,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 9bdac9d..c0662e7 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -155,6 +155,9 @@ SNES + + SNES + @@ -239,6 +242,9 @@ SNES + + SNES + diff --git a/Core/Cpu.cpp b/Core/Cpu.cpp index d1973a7..cbb2925 100644 --- a/Core/Cpu.cpp +++ b/Core/Cpu.cpp @@ -96,6 +96,15 @@ void Cpu::SetIrqSource(IrqSource source) _irqSource |= (uint8_t)source; } +bool Cpu::CheckIrqSource(IrqSource source) +{ + if(_irqSource & (uint8_t)source) { + return true; + } else { + return false; + } +} + void Cpu::ClearIrqSource(IrqSource source) { _irqSource |= (uint8_t)source; diff --git a/Core/Cpu.h b/Core/Cpu.h index bdb0129..fafc93b 100644 --- a/Core/Cpu.h +++ b/Core/Cpu.h @@ -245,5 +245,6 @@ public: void SetNmiFlag(); void SetIrqSource(IrqSource source); + bool CheckIrqSource(IrqSource source); void ClearIrqSource(IrqSource source); }; \ No newline at end of file diff --git a/Core/InternalRegisters.cpp b/Core/InternalRegisters.cpp new file mode 100644 index 0000000..4521fef --- /dev/null +++ b/Core/InternalRegisters.cpp @@ -0,0 +1,63 @@ +#include "stdafx.h" +#include "InternalRegisters.h" +#include "MessageManager.h" +#include "../Utilities/HexUtilities.h" + +uint8_t InternalRegisters::Read(uint16_t addr) +{ + switch(addr) { + case 0x4214: return (uint8_t)_divResult; + case 0x4215: return (uint8_t)(_divResult >> 8); + + case 0x4216: return (uint8_t)_multOrRemainderResult; + case 0x4217: return (uint8_t)(_multOrRemainderResult >> 8); + + default: + MessageManager::DisplayMessage("Debug", "Unimplemented register read: " + HexUtilities::ToHex(addr)); + return 0; + } +} + +void InternalRegisters::Write(uint16_t addr, uint8_t value) +{ + switch(addr) { + case 0x4200: + _enableNmi = (value & 0x80) != 0; + _enableVerticalIrq = (value & 0x20) != 0; + _enableHorizontalIrq = (value & 0x10) != 0; + + //TODO + //_autoJoypadRead = (value & 0x01) != 0; + break; + + case 0x4202: _multOperand1 = value; break; + case 0x4203: + _multOperand2 = value; + _multOrRemainderResult = _multOperand1 * _multOperand2; + break; + + case 0x4204: _dividend = (_dividend & 0xFF00) | value; break; + case 0x4205: _dividend = (_dividend & 0xFF) | (value << 8); break; + case 0x4206: + _divisor = value; + if(_divisor == 0) { + //"Division by 0 gives a quotient of $FFFF and a remainder of C." + _divResult = 0xFFFF; + _multOrRemainderResult = _dividend; + } else { + _divResult = _dividend / _divisor; + _multOrRemainderResult = _dividend % _divisor; + } + break; + + case 0x4207: _horizontalTimer = (_horizontalTimer & 0x100) | value; break; + case 0x4208: _horizontalTimer = (_horizontalTimer & 0xFF) | ((value & 0x01) << 8); break; + + case 0x4209: _verticalTimer = (_verticalTimer & 0x100) | value; break; + case 0x420A: _verticalTimer = (_verticalTimer & 0xFF) | ((value & 0x01) << 8); break; + + default: + MessageManager::DisplayMessage("Debug", "Unimplemented register write: " + HexUtilities::ToHex(addr)); + break; + } +} diff --git a/Core/InternalRegisters.h b/Core/InternalRegisters.h new file mode 100644 index 0000000..b40bd34 --- /dev/null +++ b/Core/InternalRegisters.h @@ -0,0 +1,30 @@ +#pragma once +#include "stdafx.h" + +class InternalRegisters +{ +private: + uint8_t _multOperand1 = 0; + uint8_t _multOperand2 = 0; + uint16_t _multOrRemainderResult = 0; + + uint16_t _dividend = 0; + uint8_t _divisor = 0; + uint16_t _divResult = 0; + + bool _enableNmi = false; + bool _enableHorizontalIrq = false; + bool _enableVerticalIrq = false; + uint16_t _horizontalTimer = 0x1FF; + uint16_t _verticalTimer = 0x1FF; + +public: + bool IsVerticalIrqEnabled() { return _enableVerticalIrq; } + bool IsHorizontalIrqEnabled() { return _enableHorizontalIrq; } + bool IsNmiEnabled() { return _enableNmi; } + uint16_t GetHorizontalTimer() { return _horizontalTimer; } + uint16_t GetVerticalTimer() { return _verticalTimer; } + + uint8_t Read(uint16_t addr); + void Write(uint16_t addr, uint8_t value); +}; \ No newline at end of file diff --git a/Core/MemoryManager.h b/Core/MemoryManager.h index ada3d97..5830bf8 100644 --- a/Core/MemoryManager.h +++ b/Core/MemoryManager.h @@ -6,6 +6,7 @@ #include "RamHandler.h" #include "DmaController.h" #include "BaseCartridge.h" +#include "InternalRegisters.h" #include "IMemoryHandler.h" #include "MessageManager.h" #include "../Utilities/HexUtilities.h" @@ -16,14 +17,16 @@ private: Ppu *_ppu; Spc *_spc; DmaController *_dmaController; + InternalRegisters *_regs; uint8_t *_workRam; uint32_t _wramPosition; public: - CpuRegisterHandler(Ppu *ppu, Spc *spc, DmaController *dmaController, uint8_t *workRam) + CpuRegisterHandler(Ppu *ppu, Spc *spc, DmaController *dmaController, InternalRegisters *regs, uint8_t *workRam) { _ppu = ppu; _spc = spc; + _regs = regs; _dmaController = dmaController; _workRam = workRam; @@ -35,8 +38,10 @@ public: addr &= 0xFFFF; if(addr >= 0x2140 && addr <= 0x217F) { return _spc->Read(addr & 0x03); - } else { + } else if(addr < 0x4200) { return _ppu->Read(addr); + } else { + return _regs->Read(addr); } } @@ -58,8 +63,10 @@ public: } } else if(addr == 0x420B || addr == 0x420C || addr >= 0x4300) { _dmaController->Write(addr, value); - } else { + } else if(addr < 0x4200) { _ppu->Write(addr, value); + } else { + _regs->Write(addr, value); } } }; @@ -97,7 +104,7 @@ public: _workRam = new uint8_t[MemoryManager::WorkRamSize]; _dmaController.reset(new DmaController(console->GetMemoryManager().get())); - _cpuRegisterHandler.reset(new CpuRegisterHandler(_ppu.get(), console->GetSpc().get(), _dmaController.get(), _workRam)); + _cpuRegisterHandler.reset(new CpuRegisterHandler(_ppu.get(), console->GetSpc().get(), _dmaController.get(), console->GetInternalRegisters().get(), _workRam)); memset(_handlers, 0, sizeof(_handlers)); //memset(_workRam, 0, 128 * 1024); diff --git a/Core/Ppu.cpp b/Core/Ppu.cpp index 16a5c70..bc567ec 100644 --- a/Core/Ppu.cpp +++ b/Core/Ppu.cpp @@ -4,12 +4,14 @@ #include "MemoryManager.h" #include "Cpu.h" #include "Spc.h" +#include "InternalRegisters.h" #include "VideoDecoder.h" #include "NotificationManager.h" Ppu::Ppu(shared_ptr console) { _console = console; + _regs = console->GetInternalRegisters(); _outputBuffers[0] = new uint16_t[256 * 224]; _outputBuffers[1] = new uint16_t[256 * 224]; @@ -59,7 +61,7 @@ void Ppu::Exec() _nmiFlag = true; SendFrame(); - if(_enableNmi) { + if(_regs->IsNmiEnabled()) { _console->GetCpu()->SetNmiFlag(); } } else if(_scanline == 261) { @@ -68,13 +70,13 @@ void Ppu::Exec() _frameCount++; } - if(_enableVerticalIrq && !_enableHorizontalIrq && _cycle == _verticalTimer) { + if(_regs->IsVerticalIrqEnabled() && !_regs->IsHorizontalIrqEnabled() && _scanline == _regs->GetVerticalTimer()) { //An IRQ will occur sometime just after the V Counter reaches the value set in $4209/$420A. _console->GetCpu()->SetIrqSource(IrqSource::Ppu); } } - if(_enableHorizontalIrq && _cycle == _horizontalTimer && (!_enableVerticalIrq || _scanline == _verticalTimer)) { + if(_regs->IsHorizontalIrqEnabled() && _cycle == _regs->GetHorizontalTimer() && (!_regs->IsVerticalIrqEnabled() || _scanline == _regs->GetVerticalTimer())) { //An IRQ will occur sometime just after the H Counter reaches the value set in $4207/$4208. _console->GetCpu()->SetIrqSource(IrqSource::Ppu); } @@ -181,8 +183,7 @@ uint8_t Ppu::Read(uint16_t addr) } case 0x4211: { - uint8_t value = (_irqFlag ? 0x80 : 0) | ((addr >> 8) & 0x7F); - _irqFlag = false; + uint8_t value = (_console->GetCpu()->CheckIrqSource(IrqSource::Ppu) ? 0x80 : 0) | ((addr >> 8) & 0x7F); _console->GetCpu()->ClearIrqSource(IrqSource::Ppu); return value; } @@ -193,9 +194,6 @@ uint8_t Ppu::Read(uint16_t addr) ((_cycle >= 0x121 || _cycle <= 0x15) ? 0x40 : 0) ); - case 0x4216: return (uint8_t)_multResult; - case 0x4217: return (uint8_t)(_multResult >> 8); - default: MessageManager::DisplayMessage("Debug", "Unimplemented register read: " + HexUtilities::ToHex(addr)); break; @@ -282,27 +280,6 @@ void Ppu::Write(uint32_t addr, uint8_t value) _cgramAddress = (_cgramAddress + 1) & (Ppu::CgRamSize - 1); break; - case 0x4200: - _enableNmi = (value & 0x80) != 0; - _enableVerticalIrq = (value & 0x20) != 0; - _enableHorizontalIrq = (value & 0x10) != 0; - - //TODO - //_autoJoypadRead = (value & 0x01) != 0; - break; - - case 0x4202: _multOperand1 = value; break; - case 0x4203: - _multOperand2 = value; - _multResult = _multOperand1 * _multOperand2; - break; - - case 0x4207: _horizontalTimer = (_horizontalTimer & 0x100) | value; break; - case 0x4208: _horizontalTimer = (_horizontalTimer & 0xFF) | ((value & 0x01) << 8); break; - - case 0x4209: _verticalTimer = (_verticalTimer & 0x100) | value; break; - case 0x420A: _verticalTimer = (_verticalTimer & 0xFF) | ((value & 0x01) << 8); break; - default: MessageManager::DisplayMessage("Debug", "Unimplemented register write: " + HexUtilities::ToHex(addr)); break; diff --git a/Core/Ppu.h b/Core/Ppu.h index f0572e8..a61933c 100644 --- a/Core/Ppu.h +++ b/Core/Ppu.h @@ -3,6 +3,7 @@ #include "PpuTypes.h" class Console; +class InternalRegisters; class Ppu { @@ -13,32 +14,22 @@ public: private: shared_ptr _console; + shared_ptr _regs; uint16_t _cycle = 0; uint16_t _scanline = 0; uint32_t _frameCount = 0; - bool _nmiFlag = false; - bool _enableNmi = false; - - bool _irqFlag = false; - bool _enableHorizontalIrq = false; - bool _enableVerticalIrq = false; - uint16_t _horizontalTimer = 0x1FF; - uint16_t _verticalTimer = 0x1FF; - uint8_t _bgMode = 0; LayerConfig _layerConfig[4]; + bool _nmiFlag = false; + uint8_t *_vram; uint16_t _vramAddress; uint8_t _vramIncrementValue; uint8_t _vramAddressRemapping; bool _vramAddrIncrementOnSecondReg; - - uint8_t _multOperand1 = 0; - uint8_t _multOperand2 = 0; - uint16_t _multResult = 0; uint16_t _cgramAddress; uint8_t _cgram[Ppu::CgRamSize];