Refactor internal CPU registers + implement division register
This commit is contained in:
parent
1224909fb1
commit
aaf147b53b
11 changed files with 144 additions and 47 deletions
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -245,5 +245,6 @@ public:
|
|||
|
||||
void SetNmiFlag();
|
||||
void SetIrqSource(IrqSource source);
|
||||
bool CheckIrqSource(IrqSource source);
|
||||
void ClearIrqSource(IrqSource source);
|
||||
};
|
63
Core/InternalRegisters.cpp
Normal file
63
Core/InternalRegisters.cpp
Normal 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
30
Core/InternalRegisters.h
Normal 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);
|
||||
};
|
|
@ -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);
|
||||
|
|
35
Core/Ppu.cpp
35
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 = 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;
|
||||
|
|
17
Core/Ppu.h
17
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> _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];
|
||||
|
|
Loading…
Add table
Reference in a new issue