Refactor internal CPU registers + implement division register

This commit is contained in:
Sour 2019-02-17 15:37:31 -05:00
parent 1224909fb1
commit aaf147b53b
11 changed files with 144 additions and 47 deletions

View file

@ -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<BaseCartridge> 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<MemoryManager> Console::GetMemoryManager()
return _memoryManager;
}
shared_ptr<InternalRegisters> Console::GetInternalRegisters()
{
return _internalRegisters;
}
shared_ptr<Debugger> Console::GetDebugger(bool autoStart)
{
shared_ptr<Debugger> debugger = _debugger;

View file

@ -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> _spc;
shared_ptr<MemoryManager> _memoryManager;
shared_ptr<BaseCartridge> _cart;
shared_ptr<InternalRegisters> _internalRegisters;
shared_ptr<Debugger> _debugger;
shared_ptr<NotificationManager> _notificationManager;
@ -57,6 +60,7 @@ public:
shared_ptr<Spc> GetSpc();
shared_ptr<BaseCartridge> GetCartridge();
shared_ptr<MemoryManager> GetMemoryManager();
shared_ptr<InternalRegisters> GetInternalRegisters();
shared_ptr<Debugger> GetDebugger(bool autoStart = true);
bool IsRunning();

View file

@ -74,6 +74,7 @@
<ClInclude Include="IMemoryHandler.h" />
<ClInclude Include="IMessageManager.h" />
<ClInclude Include="INotificationListener.h" />
<ClInclude Include="InternalRegisters.h" />
<ClInclude Include="IRenderingDevice.h" />
<ClInclude Include="KeyManager.h" />
<ClInclude Include="MemoryDumper.h" />
@ -109,6 +110,7 @@
<ClCompile Include="DefaultVideoFilter.cpp" />
<ClCompile Include="DisassemblyInfo.cpp" />
<ClCompile Include="DmaController.cpp" />
<ClCompile Include="InternalRegisters.cpp" />
<ClCompile Include="KeyManager.cpp" />
<ClCompile Include="MemoryDumper.cpp" />
<ClCompile Include="MessageManager.cpp" />

View file

@ -155,6 +155,9 @@
<ClInclude Include="RamHandler.h">
<Filter>SNES</Filter>
</ClInclude>
<ClInclude Include="InternalRegisters.h">
<Filter>SNES</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp" />
@ -239,6 +242,9 @@
<ClCompile Include="BaseCartridge.cpp">
<Filter>SNES</Filter>
</ClCompile>
<ClCompile Include="InternalRegisters.cpp">
<Filter>SNES</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="SNES">

View file

@ -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;

View file

@ -245,5 +245,6 @@ public:
void SetNmiFlag();
void SetIrqSource(IrqSource source);
bool CheckIrqSource(IrqSource source);
void ClearIrqSource(IrqSource source);
};

View file

@ -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;
}
}

30
Core/InternalRegisters.h Normal file
View file

@ -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);
};

View file

@ -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);

View file

@ -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 = 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;

View file

@ -3,6 +3,7 @@
#include "PpuTypes.h"
class Console;
class InternalRegisters;
class Ppu
{
@ -13,32 +14,22 @@ public:
private:
shared_ptr<Console> _console;
shared_ptr<InternalRegisters> _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];