Fixed addressing bugs, added PPU stub, improved trace logger output, split CPU instructions to another file
This commit is contained in:
parent
5c19584019
commit
522372a365
22 changed files with 1374 additions and 1018 deletions
|
@ -32,6 +32,7 @@ void Console::Stop()
|
||||||
_runLock.WaitForRelease();
|
_runLock.WaitForRelease();
|
||||||
|
|
||||||
_cpu.reset();
|
_cpu.reset();
|
||||||
|
_ppu.reset();
|
||||||
_memoryManager.reset();
|
_memoryManager.reset();
|
||||||
_debugger.reset();
|
_debugger.reset();
|
||||||
}
|
}
|
||||||
|
@ -42,12 +43,18 @@ void Console::LoadRom(VirtualFile romFile, VirtualFile patchFile)
|
||||||
|
|
||||||
shared_ptr<BaseCartridge> cart = BaseCartridge::CreateCartridge(romFile, patchFile);
|
shared_ptr<BaseCartridge> cart = BaseCartridge::CreateCartridge(romFile, patchFile);
|
||||||
if(cart) {
|
if(cart) {
|
||||||
|
_ppu.reset(new Ppu());
|
||||||
_memoryManager.reset(new MemoryManager(cart, shared_from_this()));
|
_memoryManager.reset(new MemoryManager(cart, shared_from_this()));
|
||||||
_cpu.reset(new Cpu(_memoryManager));
|
_cpu.reset(new Cpu(_memoryManager));
|
||||||
_debugger.reset(new Debugger(_cpu, _memoryManager));
|
_debugger.reset(new Debugger(_cpu, _ppu, _memoryManager));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shared_ptr<Ppu> Console::GetPpu()
|
||||||
|
{
|
||||||
|
return _ppu;
|
||||||
|
}
|
||||||
|
|
||||||
shared_ptr<Debugger> Console::GetDebugger(bool allowStart)
|
shared_ptr<Debugger> Console::GetDebugger(bool allowStart)
|
||||||
{
|
{
|
||||||
return _debugger;
|
return _debugger;
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "../Utilities/SimpleLock.h"
|
#include "../Utilities/SimpleLock.h"
|
||||||
|
|
||||||
class Cpu;
|
class Cpu;
|
||||||
|
class Ppu;
|
||||||
class MemoryManager;
|
class MemoryManager;
|
||||||
class Debugger;
|
class Debugger;
|
||||||
enum class MemoryOperationType;
|
enum class MemoryOperationType;
|
||||||
|
@ -12,6 +13,7 @@ class Console : public std::enable_shared_from_this<Console>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
shared_ptr<Cpu> _cpu;
|
shared_ptr<Cpu> _cpu;
|
||||||
|
shared_ptr<Ppu> _ppu;
|
||||||
shared_ptr<MemoryManager> _memoryManager;
|
shared_ptr<MemoryManager> _memoryManager;
|
||||||
shared_ptr<Debugger> _debugger;
|
shared_ptr<Debugger> _debugger;
|
||||||
|
|
||||||
|
@ -24,6 +26,7 @@ public:
|
||||||
|
|
||||||
void LoadRom(VirtualFile romFile, VirtualFile patchFile);
|
void LoadRom(VirtualFile romFile, VirtualFile patchFile);
|
||||||
|
|
||||||
|
shared_ptr<Ppu> GetPpu();
|
||||||
shared_ptr<Debugger> GetDebugger(bool allowStart = true);
|
shared_ptr<Debugger> GetDebugger(bool allowStart = true);
|
||||||
|
|
||||||
void ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType type);
|
void ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType type);
|
||||||
|
|
|
@ -60,6 +60,8 @@
|
||||||
<ClInclude Include="KeyManager.h" />
|
<ClInclude Include="KeyManager.h" />
|
||||||
<ClInclude Include="MemoryManager.h" />
|
<ClInclude Include="MemoryManager.h" />
|
||||||
<ClInclude Include="MessageManager.h" />
|
<ClInclude Include="MessageManager.h" />
|
||||||
|
<ClInclude Include="Ppu.h" />
|
||||||
|
<ClInclude Include="PpuTypes.h" />
|
||||||
<ClInclude Include="stdafx.h" />
|
<ClInclude Include="stdafx.h" />
|
||||||
<ClInclude Include="TraceLogger.h" />
|
<ClInclude Include="TraceLogger.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -68,6 +70,7 @@
|
||||||
<ClCompile Include="BaseSoundManager.cpp" />
|
<ClCompile Include="BaseSoundManager.cpp" />
|
||||||
<ClCompile Include="Console.cpp" />
|
<ClCompile Include="Console.cpp" />
|
||||||
<ClCompile Include="Cpu.cpp" />
|
<ClCompile Include="Cpu.cpp" />
|
||||||
|
<ClCompile Include="Cpu.Instructions.cpp" />
|
||||||
<ClCompile Include="Debugger.cpp" />
|
<ClCompile Include="Debugger.cpp" />
|
||||||
<ClCompile Include="DisassemblyInfo.cpp" />
|
<ClCompile Include="DisassemblyInfo.cpp" />
|
||||||
<ClCompile Include="KeyManager.cpp" />
|
<ClCompile Include="KeyManager.cpp" />
|
||||||
|
|
|
@ -56,6 +56,12 @@
|
||||||
<ClInclude Include="KeyManager.h">
|
<ClInclude Include="KeyManager.h">
|
||||||
<Filter>Misc</Filter>
|
<Filter>Misc</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Ppu.h">
|
||||||
|
<Filter>SNES</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="PpuTypes.h">
|
||||||
|
<Filter>SNES</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="stdafx.cpp" />
|
<ClCompile Include="stdafx.cpp" />
|
||||||
|
@ -86,6 +92,9 @@
|
||||||
<ClCompile Include="KeyManager.cpp">
|
<ClCompile Include="KeyManager.cpp">
|
||||||
<Filter>Misc</Filter>
|
<Filter>Misc</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Cpu.Instructions.cpp">
|
||||||
|
<Filter>SNES</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="SNES">
|
<Filter Include="SNES">
|
||||||
|
|
921
Core/Cpu.Instructions.cpp
Normal file
921
Core/Cpu.Instructions.cpp
Normal file
|
@ -0,0 +1,921 @@
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "Cpu.h"
|
||||||
|
|
||||||
|
/************************
|
||||||
|
Add/substract operations
|
||||||
|
*************************/
|
||||||
|
void Cpu::Add8(uint8_t value)
|
||||||
|
{
|
||||||
|
uint32_t result;
|
||||||
|
if(CheckFlag(ProcFlags::Decimal)) {
|
||||||
|
result = (_state.A & 0x0F) + (value & 0x0F) + (_state.PS & ProcFlags::Carry);
|
||||||
|
if(result > 0x09) result += 0x06;
|
||||||
|
result = (_state.A & 0xF0) + (value & 0xF0) + (result > 0x0F ? 0x10 : 0) + (result & 0x0F);
|
||||||
|
} else {
|
||||||
|
result = (uint32_t)_state.A + value + (_state.PS & ProcFlags::Carry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(~(_state.A ^ value) & (_state.A ^ result) & 0x80) {
|
||||||
|
SetFlags(ProcFlags::Overflow);
|
||||||
|
} else {
|
||||||
|
ClearFlags(ProcFlags::Overflow);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CheckFlag(ProcFlags::Decimal) && result > 0x9F) {
|
||||||
|
result += 0x60;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearFlags(ProcFlags::Carry | ProcFlags::Negative | ProcFlags::Zero);
|
||||||
|
SetZeroNegativeFlags((uint8_t)result);
|
||||||
|
|
||||||
|
if(result & 0x100) {
|
||||||
|
SetFlags(ProcFlags::Carry);
|
||||||
|
}
|
||||||
|
|
||||||
|
_state.A = (uint8_t)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::Add16(uint16_t value)
|
||||||
|
{
|
||||||
|
uint32_t result;
|
||||||
|
if(CheckFlag(ProcFlags::Decimal)) {
|
||||||
|
result = (_state.A & 0x0F) + (value & 0x0F) + (_state.PS & ProcFlags::Carry);
|
||||||
|
|
||||||
|
if(result > 0x09) result += 0x06;
|
||||||
|
result = (_state.A & 0xF0) + (value & 0xF0) + (result > 0x0F ? 0x10 : 0) + (result & 0x0F);
|
||||||
|
|
||||||
|
if(result > 0x9F) result += 0x60;
|
||||||
|
result = (_state.A & 0xF00) + (value & 0xF00) + (result > 0xFF ? 0x100 : 0) + (result & 0xFF);
|
||||||
|
|
||||||
|
if(result > 0x9FF) result += 0x600;
|
||||||
|
result = (_state.A & 0xF000) + (value & 0xF000) + (result > 0xFFF ? 0x1000 : 0) + (result & 0xFFF);
|
||||||
|
} else {
|
||||||
|
result = (uint32_t)_state.A + value + (_state.PS & ProcFlags::Carry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(~(_state.A ^ value) & (_state.A ^ result) & 0x8000) {
|
||||||
|
SetFlags(ProcFlags::Overflow);
|
||||||
|
} else {
|
||||||
|
ClearFlags(ProcFlags::Overflow);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CheckFlag(ProcFlags::Decimal) && result > 0x9FFF) {
|
||||||
|
result += 0x6000;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearFlags(ProcFlags::Carry | ProcFlags::Negative | ProcFlags::Zero);
|
||||||
|
SetZeroNegativeFlags((uint16_t)result);
|
||||||
|
|
||||||
|
if(result & 0x10000) {
|
||||||
|
SetFlags(ProcFlags::Carry);
|
||||||
|
}
|
||||||
|
|
||||||
|
_state.A = (uint16_t)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::ADC()
|
||||||
|
{
|
||||||
|
if(CheckFlag(ProcFlags::MemoryMode8)) {
|
||||||
|
Add8(GetByteValue());
|
||||||
|
} else {
|
||||||
|
Add16(GetWordValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::Sub8(uint8_t value)
|
||||||
|
{
|
||||||
|
uint32_t result;
|
||||||
|
if(CheckFlag(ProcFlags::Decimal)) {
|
||||||
|
result = (_state.A & 0x0F) + (value & 0x0F) + (_state.PS & ProcFlags::Carry);
|
||||||
|
if(result <= 0x0F) result -= 0x06;
|
||||||
|
result = (_state.A & 0xF0) + (value & 0xF0) + (result > 0x0F ? 0x10 : 0) + (result & 0x0F);
|
||||||
|
} else {
|
||||||
|
result = (uint32_t)_state.A + value + (_state.PS & ProcFlags::Carry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(~(_state.A ^ value) & (_state.A ^ result) & 0x80) {
|
||||||
|
SetFlags(ProcFlags::Overflow);
|
||||||
|
} else {
|
||||||
|
ClearFlags(ProcFlags::Overflow);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CheckFlag(ProcFlags::Decimal) && result <= 0xFF) {
|
||||||
|
result -= 0x60;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearFlags(ProcFlags::Carry | ProcFlags::Negative | ProcFlags::Zero);
|
||||||
|
SetZeroNegativeFlags((uint8_t)result);
|
||||||
|
|
||||||
|
if(result & 0x100) {
|
||||||
|
SetFlags(ProcFlags::Carry);
|
||||||
|
}
|
||||||
|
|
||||||
|
_state.A = (uint8_t)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::Sub16(uint16_t value)
|
||||||
|
{
|
||||||
|
uint32_t result;
|
||||||
|
if(CheckFlag(ProcFlags::Decimal)) {
|
||||||
|
result = (_state.A & 0x0F) + (value & 0x0F) + (_state.PS & ProcFlags::Carry);
|
||||||
|
|
||||||
|
if(result <= 0x0F) result -= 0x06;
|
||||||
|
result = (_state.A & 0xF0) + (value & 0xF0) + (result > 0x0F ? 0x10 : 0) + (result & 0x0F);
|
||||||
|
|
||||||
|
if(result <= 0xFF) result -= 0x60;
|
||||||
|
result = (_state.A & 0xF00) + (value & 0xF00) + (result > 0xFF ? 0x100 : 0) + (result & 0xFF);
|
||||||
|
|
||||||
|
if(result <= 0xFFF) result -= 0x600;
|
||||||
|
result = (_state.A & 0xF000) + (value & 0xF000) + (result > 0xFFF ? 0x1000 : 0) + (result & 0xFFF);
|
||||||
|
} else {
|
||||||
|
result = (uint32_t)_state.A + value + (_state.PS & ProcFlags::Carry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(~(_state.A ^ value) & (_state.A ^ result) & 0x8000) {
|
||||||
|
SetFlags(ProcFlags::Overflow);
|
||||||
|
} else {
|
||||||
|
ClearFlags(ProcFlags::Overflow);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CheckFlag(ProcFlags::Decimal) && result <= 0xFFFF) {
|
||||||
|
result -= 0x6000;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearFlags(ProcFlags::Carry | ProcFlags::Negative | ProcFlags::Zero);
|
||||||
|
SetZeroNegativeFlags((uint16_t)result);
|
||||||
|
|
||||||
|
if(result & 0x10000) {
|
||||||
|
SetFlags(ProcFlags::Carry);
|
||||||
|
}
|
||||||
|
|
||||||
|
_state.A = (uint16_t)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::SBC()
|
||||||
|
{
|
||||||
|
if(CheckFlag(ProcFlags::MemoryMode8)) {
|
||||||
|
Sub8(~GetByteValue());
|
||||||
|
} else {
|
||||||
|
Sub16(~GetWordValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************
|
||||||
|
Branch operations
|
||||||
|
****************/
|
||||||
|
void Cpu::BCC()
|
||||||
|
{
|
||||||
|
BranchRelative(!CheckFlag(ProcFlags::Carry));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::BCS()
|
||||||
|
{
|
||||||
|
BranchRelative(CheckFlag(ProcFlags::Carry));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::BEQ()
|
||||||
|
{
|
||||||
|
BranchRelative(CheckFlag(ProcFlags::Zero));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::BMI()
|
||||||
|
{
|
||||||
|
BranchRelative(CheckFlag(ProcFlags::Negative));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::BNE()
|
||||||
|
{
|
||||||
|
BranchRelative(!CheckFlag(ProcFlags::Zero));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::BPL()
|
||||||
|
{
|
||||||
|
BranchRelative(!CheckFlag(ProcFlags::Negative));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::BRA()
|
||||||
|
{
|
||||||
|
BranchRelative(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::BRL()
|
||||||
|
{
|
||||||
|
_state.PC = (uint16_t)(_state.PC + (int16_t)_operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::BVC()
|
||||||
|
{
|
||||||
|
BranchRelative(!CheckFlag(ProcFlags::Overflow));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::BVS()
|
||||||
|
{
|
||||||
|
BranchRelative(CheckFlag(ProcFlags::Overflow));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::BranchRelative(bool branch)
|
||||||
|
{
|
||||||
|
int8_t offset = _operand;
|
||||||
|
if(branch) {
|
||||||
|
_state.PC = (uint16_t)(_state.PC + offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************
|
||||||
|
Set/clear flag instructions
|
||||||
|
****************************/
|
||||||
|
void Cpu::CLC()
|
||||||
|
{
|
||||||
|
ClearFlags(ProcFlags::Carry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::CLD()
|
||||||
|
{
|
||||||
|
ClearFlags(ProcFlags::Decimal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::CLI()
|
||||||
|
{
|
||||||
|
ClearFlags(ProcFlags::IrqDisable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::CLV()
|
||||||
|
{
|
||||||
|
ClearFlags(ProcFlags::Overflow);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::SEC()
|
||||||
|
{
|
||||||
|
SetFlags(ProcFlags::Carry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::SED()
|
||||||
|
{
|
||||||
|
SetFlags(ProcFlags::Decimal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::SEI()
|
||||||
|
{
|
||||||
|
SetFlags(ProcFlags::IrqDisable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::REP()
|
||||||
|
{
|
||||||
|
ClearFlags((uint8_t)_operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::SEP()
|
||||||
|
{
|
||||||
|
SetFlags((uint8_t)_operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************
|
||||||
|
Increment/decrement operations
|
||||||
|
*******************************/
|
||||||
|
void Cpu::DEX()
|
||||||
|
{
|
||||||
|
IncDecReg(_state.X, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::DEY()
|
||||||
|
{
|
||||||
|
IncDecReg(_state.Y, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::INX()
|
||||||
|
{
|
||||||
|
IncDecReg(_state.X, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::INY()
|
||||||
|
{
|
||||||
|
IncDecReg(_state.Y, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::DEC()
|
||||||
|
{
|
||||||
|
IncDec(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::INC()
|
||||||
|
{
|
||||||
|
IncDec(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::IncDecReg(uint16_t ®, int8_t offset)
|
||||||
|
{
|
||||||
|
SetRegister(reg, reg + offset, CheckFlag(ProcFlags::IndexMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::IncDec(int8_t offset)
|
||||||
|
{
|
||||||
|
if(_instAddrMode == AddrMode::Acc) {
|
||||||
|
SetRegister(_state.A, _state.A + offset, CheckFlag(ProcFlags::MemoryMode8));
|
||||||
|
} else {
|
||||||
|
if(CheckFlag(ProcFlags::MemoryMode8)) {
|
||||||
|
uint8_t value = GetByteValue() + offset;
|
||||||
|
SetZeroNegativeFlags(value);
|
||||||
|
Write(_operand, value);
|
||||||
|
} else {
|
||||||
|
uint16_t value = GetWordValue() + offset;
|
||||||
|
SetZeroNegativeFlags(value);
|
||||||
|
WriteWord(_operand, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************
|
||||||
|
Compare instructions
|
||||||
|
*********************/
|
||||||
|
void Cpu::Compare(uint16_t reg, bool eightBitMode)
|
||||||
|
{
|
||||||
|
if(eightBitMode) {
|
||||||
|
uint8_t value = GetByteValue();
|
||||||
|
if((uint8_t)reg >= value) {
|
||||||
|
SetFlags(ProcFlags::Carry);
|
||||||
|
} else {
|
||||||
|
ClearFlags(ProcFlags::Carry);
|
||||||
|
}
|
||||||
|
uint8_t result = (uint8_t)reg - value;
|
||||||
|
SetZeroNegativeFlags(result);
|
||||||
|
} else {
|
||||||
|
uint16_t value = GetWordValue();
|
||||||
|
if(reg >= value) {
|
||||||
|
SetFlags(ProcFlags::Carry);
|
||||||
|
} else {
|
||||||
|
ClearFlags(ProcFlags::Carry);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t result = reg - value;
|
||||||
|
SetZeroNegativeFlags(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::CMP()
|
||||||
|
{
|
||||||
|
Compare(_state.A, CheckFlag(ProcFlags::MemoryMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::CPX()
|
||||||
|
{
|
||||||
|
Compare(_state.X, CheckFlag(ProcFlags::IndexMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::CPY()
|
||||||
|
{
|
||||||
|
Compare(_state.Y, CheckFlag(ProcFlags::IndexMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************
|
||||||
|
Jump instructions
|
||||||
|
******************/
|
||||||
|
void Cpu::JML()
|
||||||
|
{
|
||||||
|
_state.K = (_operand >> 16) & 0xFF;
|
||||||
|
_state.PC = (uint16_t)_operand;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::JMP()
|
||||||
|
{
|
||||||
|
_state.PC = (uint16_t)_operand;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::JSL()
|
||||||
|
{
|
||||||
|
PushByte(_state.K);
|
||||||
|
PushWord(_state.PC - 1);
|
||||||
|
_state.K = (_operand >> 16) & 0xFF;
|
||||||
|
_state.PC = (uint16_t)_operand;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::JSR()
|
||||||
|
{
|
||||||
|
PushWord(_state.PC - 1);
|
||||||
|
_state.PC = (uint16_t)_operand;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::RTI()
|
||||||
|
{
|
||||||
|
if(_state.EmulationMode) {
|
||||||
|
_state.PS = PopByte(); //TODO: incorrect
|
||||||
|
_state.PC = PopWord();
|
||||||
|
} else {
|
||||||
|
_state.PS = PopByte(); //TODO: incorrect
|
||||||
|
_state.PC = PopWord();
|
||||||
|
_state.K = PopByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::RTL()
|
||||||
|
{
|
||||||
|
_state.PC = PopWord();
|
||||||
|
_state.PC++;
|
||||||
|
_state.K = PopByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::RTS()
|
||||||
|
{
|
||||||
|
_state.PC = PopWord();
|
||||||
|
_state.PC++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********
|
||||||
|
Interrupts
|
||||||
|
***********/
|
||||||
|
void Cpu::ProcessInterrupt(uint16_t vector)
|
||||||
|
{
|
||||||
|
if(_state.EmulationMode) {
|
||||||
|
PushWord(_state.PC + 1);
|
||||||
|
PushByte(_state.PS | 0x20);
|
||||||
|
|
||||||
|
SetFlags(ProcFlags::IrqDisable);
|
||||||
|
ClearFlags(ProcFlags::Decimal);
|
||||||
|
|
||||||
|
_state.PC = ReadDataWord(vector);
|
||||||
|
} else {
|
||||||
|
PushByte(_state.K);
|
||||||
|
PushWord(_state.PC + 1);
|
||||||
|
PushByte(_state.PS);
|
||||||
|
|
||||||
|
SetFlags(ProcFlags::IrqDisable);
|
||||||
|
ClearFlags(ProcFlags::Decimal);
|
||||||
|
|
||||||
|
_state.PC = ReadDataWord(vector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::BRK()
|
||||||
|
{
|
||||||
|
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyBreakVector : Cpu::BreakVector);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::COP()
|
||||||
|
{
|
||||||
|
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyCoprocessorVector : Cpu::CoprocessorVector);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************
|
||||||
|
Bitwise operations
|
||||||
|
*******************/
|
||||||
|
void Cpu::AND()
|
||||||
|
{
|
||||||
|
SetRegister(_state.A, _state.A & GetByteValue(), CheckFlag(ProcFlags::MemoryMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::EOR()
|
||||||
|
{
|
||||||
|
SetRegister(_state.A, _state.A ^ GetByteValue(), CheckFlag(ProcFlags::MemoryMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::ORA()
|
||||||
|
{
|
||||||
|
SetRegister(_state.A, _state.A | GetByteValue(), CheckFlag(ProcFlags::MemoryMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************
|
||||||
|
Shift operations
|
||||||
|
*****************/
|
||||||
|
template<typename T> T Cpu::ShiftLeft(T value)
|
||||||
|
{
|
||||||
|
T result = value << 1;
|
||||||
|
if(value & (1 << (sizeof(T) * 8 - 1))) {
|
||||||
|
SetFlags(ProcFlags::Carry);
|
||||||
|
} else {
|
||||||
|
ClearFlags(ProcFlags::Carry);
|
||||||
|
}
|
||||||
|
SetZeroNegativeFlags(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> T Cpu::RollLeft(T value)
|
||||||
|
{
|
||||||
|
T result = value << 1 | (_state.PS & ProcFlags::Carry);
|
||||||
|
if(value & (1 << (sizeof(T) * 8 - 1))) {
|
||||||
|
SetFlags(ProcFlags::Carry);
|
||||||
|
} else {
|
||||||
|
ClearFlags(ProcFlags::Carry);
|
||||||
|
}
|
||||||
|
SetZeroNegativeFlags(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> T Cpu::ShiftRight(T value)
|
||||||
|
{
|
||||||
|
T result = value >> 1;
|
||||||
|
if(value & 0x01) {
|
||||||
|
SetFlags(ProcFlags::Carry);
|
||||||
|
} else {
|
||||||
|
ClearFlags(ProcFlags::Carry);
|
||||||
|
}
|
||||||
|
SetZeroNegativeFlags(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> T Cpu::RollRight(T value)
|
||||||
|
{
|
||||||
|
T result = value >> 1 | ((_state.PS & 0x01) << (sizeof(T) * 8 - 1));
|
||||||
|
if(value & 0x01) {
|
||||||
|
SetFlags(ProcFlags::Carry);
|
||||||
|
} else {
|
||||||
|
ClearFlags(ProcFlags::Carry);
|
||||||
|
}
|
||||||
|
SetZeroNegativeFlags(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::ASL()
|
||||||
|
{
|
||||||
|
if(_instAddrMode == AddrMode::Acc) {
|
||||||
|
if(CheckFlag(ProcFlags::MemoryMode8)) {
|
||||||
|
_state.A = ShiftLeft<uint8_t>((uint8_t)_state.A);
|
||||||
|
} else {
|
||||||
|
_state.A = ShiftLeft<uint16_t>(_state.A);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(CheckFlag(ProcFlags::MemoryMode8)) {
|
||||||
|
Write(_operand, ShiftLeft<uint8_t>(GetByteValue()));
|
||||||
|
} else {
|
||||||
|
WriteWord(_operand, ShiftLeft<uint16_t>(GetWordValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::LSR()
|
||||||
|
{
|
||||||
|
if(_instAddrMode == AddrMode::Acc) {
|
||||||
|
if(CheckFlag(ProcFlags::MemoryMode8)) {
|
||||||
|
_state.A = ShiftRight<uint8_t>((uint8_t)_state.A);
|
||||||
|
} else {
|
||||||
|
_state.A = ShiftRight<uint16_t>(_state.A);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(CheckFlag(ProcFlags::MemoryMode8)) {
|
||||||
|
Write(_operand, ShiftRight<uint8_t>(GetByteValue()));
|
||||||
|
} else {
|
||||||
|
WriteWord(_operand, ShiftRight<uint16_t>(GetWordValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::ROL()
|
||||||
|
{
|
||||||
|
if(_instAddrMode == AddrMode::Acc) {
|
||||||
|
if(CheckFlag(ProcFlags::MemoryMode8)) {
|
||||||
|
_state.A = RollLeft<uint8_t>((uint8_t)_state.A);
|
||||||
|
} else {
|
||||||
|
_state.A = RollLeft<uint16_t>(_state.A);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(CheckFlag(ProcFlags::MemoryMode8)) {
|
||||||
|
Write(_operand, RollLeft<uint8_t>(GetByteValue()));
|
||||||
|
} else {
|
||||||
|
WriteWord(_operand, RollLeft<uint16_t>(GetWordValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::ROR()
|
||||||
|
{
|
||||||
|
if(_instAddrMode == AddrMode::Acc) {
|
||||||
|
if(CheckFlag(ProcFlags::MemoryMode8)) {
|
||||||
|
_state.A = RollRight<uint8_t>((uint8_t)_state.A);
|
||||||
|
} else {
|
||||||
|
_state.A = RollRight<uint16_t>(_state.A);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(CheckFlag(ProcFlags::MemoryMode8)) {
|
||||||
|
Write(_operand, RollRight<uint8_t>(GetByteValue()));
|
||||||
|
} else {
|
||||||
|
WriteWord(_operand, RollRight<uint16_t>(GetWordValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************
|
||||||
|
Move operations
|
||||||
|
****************/
|
||||||
|
void Cpu::MVN()
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::MVP()
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************
|
||||||
|
Push/pull operations
|
||||||
|
*********************/
|
||||||
|
void Cpu::PEA()
|
||||||
|
{
|
||||||
|
//Push Effective Address
|
||||||
|
PushWord((uint16_t)_operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::PEI()
|
||||||
|
{
|
||||||
|
//Push Effective Indirect address
|
||||||
|
PushWord((uint16_t)_operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::PER()
|
||||||
|
{
|
||||||
|
//Push Effective Relative address
|
||||||
|
PushWord((uint16_t)_operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::PHB()
|
||||||
|
{
|
||||||
|
PushWord(_state.DBR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::PHD()
|
||||||
|
{
|
||||||
|
PushWord(_state.D);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::PHK()
|
||||||
|
{
|
||||||
|
//"PHP, PHK, PHP, PLB, and PLP push and pull one byte from the stack"
|
||||||
|
PushByte(_state.K);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::PHP()
|
||||||
|
{
|
||||||
|
//"PHP, PHK, PHP, PLB, and PLP push and pull one byte from the stack"
|
||||||
|
PushByte(_state.PS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::PLB()
|
||||||
|
{
|
||||||
|
//"PHP, PHK, PHP, PLB, and PLP push and pull one byte from the stack"
|
||||||
|
SetRegister(_state.DBR, PopByte());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::PLD()
|
||||||
|
{
|
||||||
|
//"PHD and PLD push and pull two bytes from the stack."
|
||||||
|
SetRegister(_state.D, PopWord(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::PLP()
|
||||||
|
{
|
||||||
|
//"For PLP, (all of) the flags are pulled from the stack. Note that when the e flag is 1, the m and x flag are forced to 1, so after the PLP, both flags will still be 1 no matter what value is pulled from the stack."
|
||||||
|
if(_state.EmulationMode) {
|
||||||
|
_state.PS = PopByte() | ProcFlags::MemoryMode8 | ProcFlags::IndexMode8;
|
||||||
|
} else {
|
||||||
|
_state.PS = PopByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::PHA()
|
||||||
|
{
|
||||||
|
//"When the m flag is 0, PHA and PLA push and pull a 16-bit value, and when the m flag is 1, PHA and PLA push and pull an 8-bit value. "
|
||||||
|
PushRegister(_state.A, CheckFlag(ProcFlags::MemoryMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::PHX()
|
||||||
|
{
|
||||||
|
PushRegister(_state.X, CheckFlag(ProcFlags::IndexMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::PHY()
|
||||||
|
{
|
||||||
|
PushRegister(_state.Y, CheckFlag(ProcFlags::IndexMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::PLA()
|
||||||
|
{
|
||||||
|
//"When the m flag is 0, PHA and PLA push and pull a 16-bit value, and when the m flag is 1, PHA and PLA push and pull an 8-bit value."
|
||||||
|
PullRegister(_state.A, CheckFlag(ProcFlags::MemoryMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::PLX()
|
||||||
|
{
|
||||||
|
PullRegister(_state.X, CheckFlag(ProcFlags::IndexMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::PLY()
|
||||||
|
{
|
||||||
|
PullRegister(_state.Y, CheckFlag(ProcFlags::IndexMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::PushRegister(uint16_t reg, bool eightBitMode)
|
||||||
|
{
|
||||||
|
//"When the x flag is 0, PHX, PHY, PLX, and PLY push and pull a 16-bit value, and when the x flag is 1, PHX, PHY, PLX, and PLY push and pull an 8-bit value."
|
||||||
|
if(eightBitMode) {
|
||||||
|
PushByte((uint8_t)reg);
|
||||||
|
} else {
|
||||||
|
PushWord(reg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::PullRegister(uint16_t ®, bool eightBitMode)
|
||||||
|
{
|
||||||
|
//"When the x flag is 0, PHX, PHY, PLX, and PLY push and pull a 16-bit value, and when the x flag is 1, PHX, PHY, PLX, and PLY push and pull an 8-bit value."
|
||||||
|
if(eightBitMode) {
|
||||||
|
SetRegister(reg, PopByte(), true);
|
||||||
|
} else {
|
||||||
|
SetRegister(reg, PopWord(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
Store/load operations
|
||||||
|
**********************/
|
||||||
|
void Cpu::LoadRegister(uint16_t ®, bool eightBitMode)
|
||||||
|
{
|
||||||
|
if(eightBitMode) {
|
||||||
|
SetRegister(reg, GetByteValue(), true);
|
||||||
|
} else {
|
||||||
|
SetRegister(reg, GetWordValue(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::StoreRegister(uint16_t val, bool eightBitMode)
|
||||||
|
{
|
||||||
|
if(eightBitMode) {
|
||||||
|
Write(_operand, (uint8_t)val);
|
||||||
|
} else {
|
||||||
|
WriteWord(_operand, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::LDA()
|
||||||
|
{
|
||||||
|
//"When the m flag is 0, LDA, STA, and STZ are 16-bit operations"
|
||||||
|
LoadRegister(_state.A, CheckFlag(ProcFlags::MemoryMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::LDX()
|
||||||
|
{
|
||||||
|
//"When the x flag is 0, LDX, LDY, STX, and STY are 16-bit operations"
|
||||||
|
LoadRegister(_state.X, CheckFlag(ProcFlags::IndexMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::LDY()
|
||||||
|
{
|
||||||
|
//"When the x flag is 0, LDX, LDY, STX, and STY are 16-bit operations"
|
||||||
|
LoadRegister(_state.Y, CheckFlag(ProcFlags::IndexMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::STA()
|
||||||
|
{
|
||||||
|
//"When the m flag is 0, LDA, STA, and STZ are 16-bit operations"
|
||||||
|
StoreRegister(_state.A, CheckFlag(ProcFlags::MemoryMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::STX()
|
||||||
|
{
|
||||||
|
//"When the x flag is 0, LDX, LDY, STX, and STY are 16-bit operations"
|
||||||
|
StoreRegister(_state.X, CheckFlag(ProcFlags::IndexMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::STY()
|
||||||
|
{
|
||||||
|
//"When the x flag is 0, LDX, LDY, STX, and STY are 16-bit operations"
|
||||||
|
StoreRegister(_state.Y, CheckFlag(ProcFlags::IndexMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::STZ()
|
||||||
|
{
|
||||||
|
//"When the m flag is 0, LDA, STA, and STZ are 16-bit operations"
|
||||||
|
StoreRegister(0, CheckFlag(ProcFlags::MemoryMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************
|
||||||
|
Bit test operations
|
||||||
|
********************/
|
||||||
|
template<typename T> void Cpu::TestBits(T value)
|
||||||
|
{
|
||||||
|
ClearFlags(ProcFlags::Zero | ProcFlags::Overflow | ProcFlags::Negative);
|
||||||
|
if(((T)_state.A & value) == 0) {
|
||||||
|
SetFlags(ProcFlags::Zero);
|
||||||
|
}
|
||||||
|
if(value & (1 << (sizeof(T) * 8 - 2))) {
|
||||||
|
SetFlags(ProcFlags::Overflow);
|
||||||
|
}
|
||||||
|
if(value & (1 << (sizeof(T) * 8 - 1))) {
|
||||||
|
SetFlags(ProcFlags::Negative);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::BIT()
|
||||||
|
{
|
||||||
|
if(CheckFlag(ProcFlags::MemoryMode8)) {
|
||||||
|
TestBits<uint8_t>(GetByteValue());
|
||||||
|
} else {
|
||||||
|
TestBits<uint16_t>(GetWordValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::TRB()
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::TSB()
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************
|
||||||
|
Transfer operations
|
||||||
|
*******************/
|
||||||
|
void Cpu::TAX()
|
||||||
|
{
|
||||||
|
SetRegister(_state.X, _state.A, CheckFlag(ProcFlags::IndexMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::TAY()
|
||||||
|
{
|
||||||
|
SetRegister(_state.Y, _state.A, CheckFlag(ProcFlags::IndexMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::TCD()
|
||||||
|
{
|
||||||
|
SetRegister(_state.DBR, (uint8_t)_state.A);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::TCS()
|
||||||
|
{
|
||||||
|
_state.SP = _state.A;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::TDC()
|
||||||
|
{
|
||||||
|
SetRegister(_state.A, _state.DBR, CheckFlag(ProcFlags::MemoryMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::TSC()
|
||||||
|
{
|
||||||
|
SetRegister(_state.A, _state.SP, CheckFlag(ProcFlags::MemoryMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::TSX()
|
||||||
|
{
|
||||||
|
SetRegister(_state.X, _state.SP, CheckFlag(ProcFlags::IndexMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::TXA()
|
||||||
|
{
|
||||||
|
SetRegister(_state.A, _state.X, CheckFlag(ProcFlags::MemoryMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::TXS()
|
||||||
|
{
|
||||||
|
_state.SP = _state.X;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::TXY()
|
||||||
|
{
|
||||||
|
SetRegister(_state.Y, _state.X, CheckFlag(ProcFlags::IndexMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::TYA()
|
||||||
|
{
|
||||||
|
SetRegister(_state.A, _state.Y, CheckFlag(ProcFlags::MemoryMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::TYX()
|
||||||
|
{
|
||||||
|
SetRegister(_state.X, _state.Y, CheckFlag(ProcFlags::IndexMode8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::XBA()
|
||||||
|
{
|
||||||
|
_state.A = ((_state.A & 0xFF) << 8) | ((_state.A >> 8) & 0xFF);
|
||||||
|
SetZeroNegativeFlags((uint8_t)_state.A);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::XCE()
|
||||||
|
{
|
||||||
|
_state.EmulationMode = (_state.PS & ProcFlags::Carry) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************
|
||||||
|
No operation (NOP)
|
||||||
|
******************/
|
||||||
|
void Cpu::NOP()
|
||||||
|
{
|
||||||
|
//1-byte NOP
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::WDM()
|
||||||
|
{
|
||||||
|
//2-byte NOP
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************
|
||||||
|
Misc. operations
|
||||||
|
*****************/
|
||||||
|
void Cpu::STP()
|
||||||
|
{
|
||||||
|
//Stop the CPU
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::WAI()
|
||||||
|
{
|
||||||
|
//Wait for interrupt
|
||||||
|
}
|
970
Core/Cpu.cpp
970
Core/Cpu.cpp
File diff suppressed because it is too large
Load diff
|
@ -33,10 +33,10 @@ private:
|
||||||
Func _opTable[256];
|
Func _opTable[256];
|
||||||
AddrMode _addrMode[256];
|
AddrMode _addrMode[256];
|
||||||
|
|
||||||
uint32_t GetBank();
|
uint32_t GetProgramAddress(uint16_t addr);
|
||||||
uint32_t GetProgramAddress();
|
|
||||||
uint16_t GetDirectAddress(uint8_t baseAddress, uint16_t offset = 0, bool allowEmulationMode = true);
|
|
||||||
uint32_t GetDataAddress(uint16_t addr);
|
uint32_t GetDataAddress(uint16_t addr);
|
||||||
|
|
||||||
|
uint16_t GetDirectAddress(uint8_t baseAddress, uint16_t offset = 0, bool allowEmulationMode = true);
|
||||||
uint8_t GetOpCode();
|
uint8_t GetOpCode();
|
||||||
|
|
||||||
void DummyRead();
|
void DummyRead();
|
||||||
|
@ -57,6 +57,8 @@ private:
|
||||||
bool CheckFlag(uint8_t flag);
|
bool CheckFlag(uint8_t flag);
|
||||||
|
|
||||||
uint8_t ReadCode(uint16_t addr, MemoryOperationType type = MemoryOperationType::Read);
|
uint8_t ReadCode(uint16_t addr, MemoryOperationType type = MemoryOperationType::Read);
|
||||||
|
uint16_t ReadCodeWord(uint16_t addr, MemoryOperationType type = MemoryOperationType::Read);
|
||||||
|
|
||||||
uint8_t ReadData(uint32_t addr, MemoryOperationType type = MemoryOperationType::Read);
|
uint8_t ReadData(uint32_t addr, MemoryOperationType type = MemoryOperationType::Read);
|
||||||
uint16_t ReadDataWord(uint32_t addr, MemoryOperationType type = MemoryOperationType::Read);
|
uint16_t ReadDataWord(uint32_t addr, MemoryOperationType type = MemoryOperationType::Read);
|
||||||
uint32_t ReadDataLong(uint32_t addr, MemoryOperationType type = MemoryOperationType::Read);
|
uint32_t ReadDataLong(uint32_t addr, MemoryOperationType type = MemoryOperationType::Read);
|
||||||
|
|
|
@ -62,9 +62,11 @@ enum class AddrMode : uint8_t
|
||||||
AbsIdxX,
|
AbsIdxX,
|
||||||
AbsIdxY,
|
AbsIdxY,
|
||||||
AbsInd, //JMP only
|
AbsInd, //JMP only
|
||||||
AbsIndLng, //JMP only (unofficial)
|
AbsIndLng, //JML only
|
||||||
AbsLngIdxX,
|
AbsLngIdxX,
|
||||||
AbsLng,
|
AbsLng,
|
||||||
|
AbsJmp, //JSR/JMP only
|
||||||
|
AbsLngJmp, //JSL/JMP only
|
||||||
Acc,
|
Acc,
|
||||||
BlkMov,
|
BlkMov,
|
||||||
DirIdxIndX,
|
DirIdxIndX,
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "Debugger.h"
|
#include "Debugger.h"
|
||||||
#include "Cpu.h"
|
#include "Cpu.h"
|
||||||
|
#include "Ppu.h"
|
||||||
#include "CpuTypes.h"
|
#include "CpuTypes.h"
|
||||||
#include "DisassemblyInfo.h"
|
#include "DisassemblyInfo.h"
|
||||||
#include "TraceLogger.h"
|
#include "TraceLogger.h"
|
||||||
#include "../Utilities/HexUtilities.h"
|
#include "../Utilities/HexUtilities.h"
|
||||||
|
|
||||||
Debugger::Debugger(shared_ptr<Cpu> cpu, shared_ptr<MemoryManager> memoryManager)
|
Debugger::Debugger(shared_ptr<Cpu> cpu, shared_ptr<Ppu> ppu, shared_ptr<MemoryManager> memoryManager)
|
||||||
{
|
{
|
||||||
_cpu = cpu;
|
_cpu = cpu;
|
||||||
|
_ppu = ppu;
|
||||||
_memoryManager = memoryManager;
|
_memoryManager = memoryManager;
|
||||||
_traceLogger.reset(new TraceLogger(this, memoryManager));
|
_traceLogger.reset(new TraceLogger(this, memoryManager));
|
||||||
|
|
||||||
|
@ -24,10 +26,11 @@ void Debugger::ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType
|
||||||
if(type == MemoryOperationType::ExecOpCode) {
|
if(type == MemoryOperationType::ExecOpCode) {
|
||||||
CpuState state = _cpu->GetState();
|
CpuState state = _cpu->GetState();
|
||||||
DisassemblyInfo disassemblyInfo(state, _memoryManager.get());
|
DisassemblyInfo disassemblyInfo(state, _memoryManager.get());
|
||||||
DebugState debugState = { state };
|
DebugState debugState;
|
||||||
|
GetState(&debugState);
|
||||||
_traceLogger->Log(debugState, disassemblyInfo);
|
_traceLogger->Log(debugState, disassemblyInfo);
|
||||||
|
|
||||||
string out;
|
/*string out;
|
||||||
out += HexUtilities::ToHex(state.K) + HexUtilities::ToHex(state.PC);
|
out += HexUtilities::ToHex(state.K) + HexUtilities::ToHex(state.PC);
|
||||||
out += " ";
|
out += " ";
|
||||||
disassemblyInfo.GetDisassembly(out, _memoryManager.get());
|
disassemblyInfo.GetDisassembly(out, _memoryManager.get());
|
||||||
|
@ -43,7 +46,7 @@ void Debugger::ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType
|
||||||
" DB:$" << HexUtilities::ToHex(state.DBR) <<
|
" DB:$" << HexUtilities::ToHex(state.DBR) <<
|
||||||
" P:$" << HexUtilities::ToHex(state.PS) <<
|
" P:$" << HexUtilities::ToHex(state.PS) <<
|
||||||
std::endl;
|
std::endl;
|
||||||
//_traceLogger->Trace
|
//_traceLogger->Trace*/
|
||||||
|
|
||||||
if(_cpuStepCount > 0) {
|
if(_cpuStepCount > 0) {
|
||||||
_cpuStepCount--;
|
_cpuStepCount--;
|
||||||
|
@ -77,6 +80,12 @@ bool Debugger::IsExecutionStopped()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Debugger::GetState(DebugState *state)
|
||||||
|
{
|
||||||
|
state->Cpu = _cpu->GetState();
|
||||||
|
state->Ppu = _ppu->GetState();
|
||||||
|
}
|
||||||
|
|
||||||
shared_ptr<TraceLogger> Debugger::GetTraceLogger()
|
shared_ptr<TraceLogger> Debugger::GetTraceLogger()
|
||||||
{
|
{
|
||||||
return _traceLogger;
|
return _traceLogger;
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "CpuTypes.h"
|
#include "CpuTypes.h"
|
||||||
|
#include "PpuTypes.h"
|
||||||
|
|
||||||
class Cpu;
|
class Cpu;
|
||||||
|
class Ppu;
|
||||||
class MemoryManager;
|
class MemoryManager;
|
||||||
|
|
||||||
enum class MemoryOperationType;
|
enum class MemoryOperationType;
|
||||||
|
@ -12,7 +14,7 @@ class TraceLogger;
|
||||||
struct DebugState
|
struct DebugState
|
||||||
{
|
{
|
||||||
CpuState Cpu;
|
CpuState Cpu;
|
||||||
//PpuState ppuState;
|
PpuState Ppu;
|
||||||
//ApuState apuState;
|
//ApuState apuState;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,6 +22,7 @@ class Debugger
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
shared_ptr<Cpu> _cpu;
|
shared_ptr<Cpu> _cpu;
|
||||||
|
shared_ptr<Ppu> _ppu;
|
||||||
shared_ptr<MemoryManager> _memoryManager;
|
shared_ptr<MemoryManager> _memoryManager;
|
||||||
|
|
||||||
shared_ptr<TraceLogger> _traceLogger;
|
shared_ptr<TraceLogger> _traceLogger;
|
||||||
|
@ -28,7 +31,7 @@ private:
|
||||||
atomic<int32_t> _cpuStepCount;
|
atomic<int32_t> _cpuStepCount;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Debugger(shared_ptr<Cpu> cpu, shared_ptr<MemoryManager> memoryManager);
|
Debugger(shared_ptr<Cpu> cpu, shared_ptr<Ppu> ppu, shared_ptr<MemoryManager> memoryManager);
|
||||||
~Debugger();
|
~Debugger();
|
||||||
|
|
||||||
void ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType type);
|
void ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType type);
|
||||||
|
@ -38,5 +41,7 @@ public:
|
||||||
void Step(int32_t stepCount);
|
void Step(int32_t stepCount);
|
||||||
bool IsExecutionStopped();
|
bool IsExecutionStopped();
|
||||||
|
|
||||||
|
void GetState(DebugState *state);
|
||||||
|
|
||||||
shared_ptr<TraceLogger> GetTraceLogger();
|
shared_ptr<TraceLogger> GetTraceLogger();
|
||||||
};
|
};
|
|
@ -1,8 +1,10 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
#include <algorithm>
|
||||||
#include "DisassemblyInfo.h"
|
#include "DisassemblyInfo.h"
|
||||||
#include "CpuTypes.h"
|
#include "CpuTypes.h"
|
||||||
#include "MemoryManager.h"
|
#include "MemoryManager.h"
|
||||||
#include "../Utilities/HexUtilities.h"
|
#include "../Utilities/HexUtilities.h"
|
||||||
|
#include "../Utilities/FastString.h"
|
||||||
|
|
||||||
DisassemblyInfo::DisassemblyInfo()
|
DisassemblyInfo::DisassemblyInfo()
|
||||||
{
|
{
|
||||||
|
@ -10,6 +12,8 @@ DisassemblyInfo::DisassemblyInfo()
|
||||||
|
|
||||||
DisassemblyInfo::DisassemblyInfo(CpuState &state, MemoryManager *memoryManager)
|
DisassemblyInfo::DisassemblyInfo(CpuState &state, MemoryManager *memoryManager)
|
||||||
{
|
{
|
||||||
|
_flags = state.PS;
|
||||||
|
|
||||||
uint32_t addr = (state.K << 16) | state.PC;
|
uint32_t addr = (state.K << 16) | state.PC;
|
||||||
_byteCode[0] = memoryManager->Peek(addr);
|
_byteCode[0] = memoryManager->Peek(addr);
|
||||||
_addrMode = DisassemblyInfo::OpMode[_byteCode[0]];
|
_addrMode = DisassemblyInfo::OpMode[_byteCode[0]];
|
||||||
|
@ -19,17 +23,79 @@ DisassemblyInfo::DisassemblyInfo(CpuState &state, MemoryManager *memoryManager)
|
||||||
_byteCode[i] = memoryManager->Peek(addr+i);
|
_byteCode[i] = memoryManager->Peek(addr+i);
|
||||||
}
|
}
|
||||||
|
|
||||||
_flags = state.PS;
|
|
||||||
_emulationMode = state.EmulationMode;
|
_emulationMode = state.EmulationMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisassemblyInfo::GetDisassembly(string &out, MemoryManager *memoryManager)
|
void DisassemblyInfo::GetDisassembly(string &out, uint32_t memoryAddr)
|
||||||
{
|
{
|
||||||
out += DisassemblyInfo::OpName[_byteCode[0]];
|
FastString str;
|
||||||
out += _opSize > 1 ? " $" : " ";
|
str.Write(DisassemblyInfo::OpName[_byteCode[0]]);
|
||||||
for(int i = _opSize - 1; i > 0; i--) {
|
str.Write(' ');
|
||||||
out += HexUtilities::ToHex(_byteCode[i]);
|
|
||||||
|
uint32_t opAddr = GetOperandAddress(memoryAddr);
|
||||||
|
|
||||||
|
FastString operand;
|
||||||
|
if(_opSize > 1) {
|
||||||
|
operand.Write('$');
|
||||||
|
operand.Write(HexUtilities::ToHex(opAddr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch(_addrMode) {
|
||||||
|
case AddrMode::Abs: str.Write(operand); break;
|
||||||
|
case AddrMode::AbsIdxXInd: str.Write('(', operand, ",X)"); break;
|
||||||
|
case AddrMode::AbsIdxX: str.Write(operand, ",X"); break;
|
||||||
|
case AddrMode::AbsIdxY: str.Write(operand, ",Y"); break;
|
||||||
|
case AddrMode::AbsInd: str.Write('(', operand, ')'); break;
|
||||||
|
case AddrMode::AbsIndLng: str.Write('[', operand, ']'); break;
|
||||||
|
case AddrMode::AbsLngIdxX: str.Write(operand, ",X"); break;
|
||||||
|
case AddrMode::AbsLng: str.Write(operand); break;
|
||||||
|
case AddrMode::Acc: break;
|
||||||
|
case AddrMode::BlkMov: str.Write(operand[0], operand[1], " <- ", operand[2], operand[3]); break; //TODO
|
||||||
|
case AddrMode::DirIdxIndX: str.Write('(', operand, ",X)"); break;
|
||||||
|
case AddrMode::DirIdxX: str.Write(operand, ",X"); break;
|
||||||
|
case AddrMode::DirIdxY: str.Write(operand, ",Y"); break;
|
||||||
|
case AddrMode::DirIndIdxY: str.Write("(", operand, "),Y"); break;
|
||||||
|
case AddrMode::DirIndLngIdxY: str.Write("[", operand, "],Y"); break;
|
||||||
|
case AddrMode::DirIndLng: str.Write("[", operand, "]"); break;
|
||||||
|
case AddrMode::DirInd: str.Write("(", operand, ")"); break;
|
||||||
|
case AddrMode::Dir: str.Write(operand); break;
|
||||||
|
|
||||||
|
case AddrMode::Imm8: case AddrMode::ImmX: case AddrMode::ImmM:
|
||||||
|
str.Write('#', operand);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AddrMode::Imp: break;;
|
||||||
|
case AddrMode::RelLng: str.Write(operand);
|
||||||
|
case AddrMode::Rel: str.Write(operand);
|
||||||
|
case AddrMode::Stk: break;
|
||||||
|
case AddrMode::StkRel: str.Write(operand, ",S"); break;
|
||||||
|
case AddrMode::StkRelIndIdxY: str.Write('(', operand, ",S),Y"); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out += str.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DisassemblyInfo::GetOperandAddress(uint32_t memoryAddr)
|
||||||
|
{
|
||||||
|
uint32_t opAddr = 0;
|
||||||
|
if(_opSize == 2) {
|
||||||
|
opAddr = _byteCode[1];
|
||||||
|
} else if(_opSize == 3) {
|
||||||
|
opAddr = _byteCode[1] | (_byteCode[2] << 8);
|
||||||
|
} else if(_opSize == 4) {
|
||||||
|
opAddr = _byteCode[1] | (_byteCode[2] << 8) | (_byteCode[3] << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_addrMode == AddrMode::Rel) {
|
||||||
|
if(_opSize == 2) {
|
||||||
|
opAddr = (int8_t)opAddr + memoryAddr + 2;
|
||||||
|
} else {
|
||||||
|
opAddr = (int16_t)opAddr + memoryAddr + 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return opAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t DisassemblyInfo::GetOperandSize()
|
uint8_t DisassemblyInfo::GetOperandSize()
|
||||||
|
@ -39,12 +105,16 @@ uint8_t DisassemblyInfo::GetOperandSize()
|
||||||
case AddrMode::AbsIdxXInd: return 2;
|
case AddrMode::AbsIdxXInd: return 2;
|
||||||
case AddrMode::AbsIdxX: return 2;
|
case AddrMode::AbsIdxX: return 2;
|
||||||
case AddrMode::AbsIdxY: return 2;
|
case AddrMode::AbsIdxY: return 2;
|
||||||
|
|
||||||
case AddrMode::AbsInd: return 2;
|
case AddrMode::AbsInd: return 2;
|
||||||
case AddrMode::AbsIndLng: return 3;
|
case AddrMode::AbsIndLng: return 2;
|
||||||
|
|
||||||
case AddrMode::AbsLngIdxX: return 3;
|
case AddrMode::AbsLngIdxX: return 3;
|
||||||
case AddrMode::AbsLng: return 3;
|
case AddrMode::AbsLng: return 3;
|
||||||
|
|
||||||
case AddrMode::Acc: return 0;
|
case AddrMode::Acc: return 0;
|
||||||
case AddrMode::BlkMov: return 2;
|
case AddrMode::BlkMov: return 2;
|
||||||
|
|
||||||
case AddrMode::DirIdxIndX: return 1;
|
case AddrMode::DirIdxIndX: return 1;
|
||||||
case AddrMode::DirIdxX: return 1;
|
case AddrMode::DirIdxX: return 1;
|
||||||
case AddrMode::DirIdxY: return 1;
|
case AddrMode::DirIdxY: return 1;
|
||||||
|
@ -53,12 +123,15 @@ uint8_t DisassemblyInfo::GetOperandSize()
|
||||||
case AddrMode::DirIndLng: return 1;
|
case AddrMode::DirIndLng: return 1;
|
||||||
case AddrMode::DirInd: return 1;
|
case AddrMode::DirInd: return 1;
|
||||||
case AddrMode::Dir: return 1;
|
case AddrMode::Dir: return 1;
|
||||||
|
|
||||||
case AddrMode::Imm8: return 1;
|
case AddrMode::Imm8: return 1;
|
||||||
case AddrMode::ImmX: return _flags & ProcFlags::IndexMode8 ? 1 : 2;
|
case AddrMode::ImmX: return (_flags & ProcFlags::IndexMode8) ? 1 : 2;
|
||||||
case AddrMode::ImmM: return _flags & ProcFlags::MemoryMode8 ? 1 : 2;
|
case AddrMode::ImmM: return (_flags & ProcFlags::MemoryMode8) ? 1 : 2;
|
||||||
|
|
||||||
case AddrMode::Imp: return 0;
|
case AddrMode::Imp: return 0;
|
||||||
case AddrMode::RelLng: return 2;
|
case AddrMode::RelLng: return 2;
|
||||||
case AddrMode::Rel: return 1;
|
case AddrMode::Rel: return 1;
|
||||||
|
|
||||||
case AddrMode::Stk: return 0; //TODO
|
case AddrMode::Stk: return 0; //TODO
|
||||||
case AddrMode::StkRel: return 1;
|
case AddrMode::StkRel: return 1;
|
||||||
case AddrMode::StkRelIndIdxY: return 1;
|
case AddrMode::StkRelIndIdxY: return 1;
|
||||||
|
@ -69,8 +142,22 @@ uint8_t DisassemblyInfo::GetOperandSize()
|
||||||
|
|
||||||
void DisassemblyInfo::GetByteCode(string &out)
|
void DisassemblyInfo::GetByteCode(string &out)
|
||||||
{
|
{
|
||||||
|
FastString str;
|
||||||
for(int i = 0; i < _opSize; i++) {
|
for(int i = 0; i < _opSize; i++) {
|
||||||
out += "$" + HexUtilities::ToHex(_byteCode[i]) + ((i < _opSize - 1) ? " " : "");
|
str.Write('$', HexUtilities::ToHex(_byteCode[i]));
|
||||||
|
if(i < _opSize - 1) {
|
||||||
|
str.Write(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out += str.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t DisassemblyInfo::GetEffectiveAddress(CpuState &cpuState, MemoryManager *memoryManager)
|
||||||
|
{
|
||||||
|
uint32_t bank = (cpuState.K << 16);
|
||||||
|
//uint32_t opAddr = GetOperandAddress();
|
||||||
|
switch(_addrMode) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,19 +25,17 @@ public:
|
||||||
DisassemblyInfo();
|
DisassemblyInfo();
|
||||||
DisassemblyInfo(CpuState &state, MemoryManager *memoryManager);
|
DisassemblyInfo(CpuState &state, MemoryManager *memoryManager);
|
||||||
|
|
||||||
void GetDisassembly(string &out, MemoryManager* memoryManager);
|
void GetDisassembly(string &out, uint32_t memoryAddr);
|
||||||
|
uint32_t GetOperandAddress(uint32_t memoryAddr);
|
||||||
uint8_t GetOperandSize();
|
uint8_t GetOperandSize();
|
||||||
void GetByteCode(string &out);
|
void GetByteCode(string &out);
|
||||||
/*
|
|
||||||
int32_t GetEffectiveAddress(CpuState& cpuState, MemoryManager* memoryManager);
|
int32_t GetEffectiveAddress(CpuState &cpuState, MemoryManager *memoryManager);
|
||||||
void GetEffectiveAddressString(string &out, CpuState& cpuState, MemoryManager* memoryManager);
|
void GetEffectiveAddressString(string &out, CpuState& cpuState, MemoryManager *memoryManager);
|
||||||
|
|
||||||
/*int32_t GetMemoryValue(CpuState& cpuState, MemoryManager* memoryManager);
|
/*int32_t GetMemoryValue(CpuState& cpuState, MemoryManager* memoryManager);
|
||||||
uint16_t GetJumpDestination(uint16_t pc, MemoryManager* memoryManager);
|
uint16_t GetJumpDestination(uint16_t pc, MemoryManager* memoryManager);
|
||||||
uint16_t GetIndirectJumpDestination(MemoryManager* memoryManager);
|
uint16_t GetIndirectJumpDestination(MemoryManager* memoryManager);
|
||||||
void ToString(string &out, uint32_t memoryAddr, MemoryManager* memoryManager, bool extendZeroPage);
|
*/
|
||||||
void GetByteCode(string &out);
|
|
||||||
uint32_t GetSize();
|
|
||||||
uint16_t GetOpAddr(uint16_t memoryAddr);*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "Console.h"
|
#include "Console.h"
|
||||||
|
#include "Ppu.h"
|
||||||
#include "../Utilities/HexUtilities.h"
|
#include "../Utilities/HexUtilities.h"
|
||||||
#include "../Utilities/VirtualFile.h"
|
#include "../Utilities/VirtualFile.h"
|
||||||
|
|
||||||
|
@ -51,6 +52,28 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CpuRegisterHandler : public IMemoryHandler
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
shared_ptr<Ppu> _ppu;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CpuRegisterHandler(shared_ptr<Ppu> ppu)
|
||||||
|
{
|
||||||
|
_ppu = ppu;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Read(uint32_t addr) override
|
||||||
|
{
|
||||||
|
return _ppu->Read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write(uint32_t addr, uint8_t value) override
|
||||||
|
{
|
||||||
|
_ppu->Write(addr, value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class WorkRamHandler : public IMemoryHandler
|
class WorkRamHandler : public IMemoryHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
@ -82,12 +105,22 @@ private:
|
||||||
IMemoryHandler* _handlers[0x100 * 0x10];
|
IMemoryHandler* _handlers[0x100 * 0x10];
|
||||||
vector<unique_ptr<WorkRamHandler>> _workRamHandlers;
|
vector<unique_ptr<WorkRamHandler>> _workRamHandlers;
|
||||||
shared_ptr<BaseCartridge> _cart;
|
shared_ptr<BaseCartridge> _cart;
|
||||||
|
shared_ptr<CpuRegisterHandler> _cpuRegisterHandler;
|
||||||
|
shared_ptr<Ppu> _ppu;
|
||||||
|
|
||||||
|
uint64_t _masterClock;
|
||||||
|
uint64_t _lastMasterClock;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MemoryManager(shared_ptr<BaseCartridge> cart, shared_ptr<Console> console)
|
MemoryManager(shared_ptr<BaseCartridge> cart, shared_ptr<Console> console)
|
||||||
{
|
{
|
||||||
|
_lastMasterClock = 0;
|
||||||
|
_masterClock = 0;
|
||||||
_console = console;
|
_console = console;
|
||||||
_cart = cart;
|
_cart = cart;
|
||||||
|
_ppu = console->GetPpu();
|
||||||
|
|
||||||
|
_cpuRegisterHandler.reset(new CpuRegisterHandler(_ppu));
|
||||||
|
|
||||||
memset(_handlers, 0, sizeof(_handlers));
|
memset(_handlers, 0, sizeof(_handlers));
|
||||||
_workRam = new uint8_t[128 * 1024];
|
_workRam = new uint8_t[128 * 1024];
|
||||||
|
@ -96,6 +129,11 @@ public:
|
||||||
RegisterHandler(0x7E0000 | i, 0x7E0000 | (i + 0xFFF), _workRamHandlers[_workRamHandlers.size() - 1].get());
|
RegisterHandler(0x7E0000 | i, 0x7E0000 | (i + 0xFFF), _workRamHandlers[_workRamHandlers.size() - 1].get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i <= 0x3F; i++) {
|
||||||
|
RegisterHandler((i << 16) | 0x4000, (i << 16) | 0x5FFF, _cpuRegisterHandler.get());
|
||||||
|
RegisterHandler(((i | 0x80) << 16) | 0x4000, ((i | 0x80) << 16) | 0x5FFF, _cpuRegisterHandler.get());
|
||||||
|
}
|
||||||
|
|
||||||
RegisterHandler(0x0000, 0x0FFF, _workRamHandlers[0].get());
|
RegisterHandler(0x0000, 0x0FFF, _workRamHandlers[0].get());
|
||||||
RegisterHandler(0x1000, 0x1FFF, _workRamHandlers[1].get());
|
RegisterHandler(0x1000, 0x1FFF, _workRamHandlers[1].get());
|
||||||
|
|
||||||
|
@ -120,8 +158,51 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IncrementMasterClock(uint32_t addr)
|
||||||
|
{
|
||||||
|
//This is incredibly inaccurate
|
||||||
|
uint8_t bank = (addr & 0xFF0000) >> 8;
|
||||||
|
if(bank >= 0x40 && bank <= 0x7F) {
|
||||||
|
//Slow
|
||||||
|
_masterClock += 8;
|
||||||
|
} else if(bank >= 0xCF) {
|
||||||
|
//Slow or fast (depending on register)
|
||||||
|
//Use slow
|
||||||
|
_masterClock += 8;
|
||||||
|
} else {
|
||||||
|
uint8_t page = (addr & 0xFF00) >> 8;
|
||||||
|
if(page <= 0x1F) {
|
||||||
|
//Slow
|
||||||
|
_masterClock += 6;
|
||||||
|
} else if(page >= 0x20 && page <= 0x3F) {
|
||||||
|
//Fast
|
||||||
|
_masterClock += 6;
|
||||||
|
} else if(page == 0x40 || page == 0x41) {
|
||||||
|
//extra slow
|
||||||
|
_masterClock += 12;
|
||||||
|
} else if(page >= 0x42 && page <= 0x5F) {
|
||||||
|
//Fast
|
||||||
|
_masterClock += 6;
|
||||||
|
} else if(page >= 0x60 && page <= 0x7F) {
|
||||||
|
//Slow
|
||||||
|
_masterClock += 8;
|
||||||
|
} else {
|
||||||
|
//Slow or fast (depending on register)
|
||||||
|
//Use slow
|
||||||
|
_masterClock += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while(_lastMasterClock < _masterClock - 3) {
|
||||||
|
_ppu->Exec();
|
||||||
|
_lastMasterClock += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t Read(uint32_t addr, MemoryOperationType type)
|
uint8_t Read(uint32_t addr, MemoryOperationType type)
|
||||||
{
|
{
|
||||||
|
IncrementMasterClock(addr);
|
||||||
|
|
||||||
uint8_t value = 0;
|
uint8_t value = 0;
|
||||||
if(_handlers[addr >> 12]) {
|
if(_handlers[addr >> 12]) {
|
||||||
value = _handlers[addr >> 12]->Read(addr);
|
value = _handlers[addr >> 12]->Read(addr);
|
||||||
|
@ -146,6 +227,8 @@ public:
|
||||||
|
|
||||||
void Write(uint32_t addr, uint8_t value, MemoryOperationType type)
|
void Write(uint32_t addr, uint8_t value, MemoryOperationType type)
|
||||||
{
|
{
|
||||||
|
IncrementMasterClock(addr);
|
||||||
|
|
||||||
_console->ProcessCpuWrite(addr, value, type);
|
_console->ProcessCpuWrite(addr, value, type);
|
||||||
if(_handlers[addr >> 12]) {
|
if(_handlers[addr >> 12]) {
|
||||||
return _handlers[addr >> 12]->Write(addr, value);
|
return _handlers[addr >> 12]->Write(addr, value);
|
||||||
|
|
65
Core/Ppu.h
Normal file
65
Core/Ppu.h
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#pragma once
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "PpuTypes.h"
|
||||||
|
|
||||||
|
class Ppu
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint16_t _cycle = 0;
|
||||||
|
uint16_t _scanline = 0;
|
||||||
|
uint32_t _frameCount = 0;
|
||||||
|
bool _nmiFlag = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PpuState GetState()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
_cycle,
|
||||||
|
_scanline,
|
||||||
|
_frameCount
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void Exec()
|
||||||
|
{
|
||||||
|
if(_cycle == 340) {
|
||||||
|
_cycle = 0;
|
||||||
|
_scanline++;
|
||||||
|
|
||||||
|
if(_scanline == 225) {
|
||||||
|
_nmiFlag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_scanline == 260) {
|
||||||
|
_nmiFlag = false;
|
||||||
|
_scanline = 0;
|
||||||
|
_frameCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_cycle++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Read(uint16_t addr)
|
||||||
|
{
|
||||||
|
switch(addr) {
|
||||||
|
case 0x4210:
|
||||||
|
return _nmiFlag ? 0x80 : 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x4212:
|
||||||
|
return (
|
||||||
|
(_scanline >= 225 ? 0x80 : 0) ||
|
||||||
|
((_cycle >= 0x121 || _cycle <= 0x15) ? 0x40 : 0)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write(uint32_t addr, uint8_t value)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
9
Core/PpuTypes.h
Normal file
9
Core/PpuTypes.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
struct PpuState
|
||||||
|
{
|
||||||
|
uint16_t Cycle;
|
||||||
|
uint16_t Scanline;
|
||||||
|
uint32_t FrameCount;
|
||||||
|
};
|
|
@ -1,5 +1,6 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
#include <algorithm>
|
||||||
#include "TraceLogger.h"
|
#include "TraceLogger.h"
|
||||||
#include "DisassemblyInfo.h"
|
#include "DisassemblyInfo.h"
|
||||||
#include "Console.h"
|
#include "Console.h"
|
||||||
|
@ -26,7 +27,7 @@ TraceLogger::~TraceLogger()
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void TraceLogger::WriteValue(string &output, T value, RowPart& rowPart)
|
void TraceLogger::WriteValue(string &output, T value, RowPart& rowPart)
|
||||||
{
|
{
|
||||||
string str = rowPart.DisplayInHex ? HexUtilities::ToHex((uint32_t)value) : std::to_string(value);
|
string str = rowPart.DisplayInHex ? HexUtilities::ToHex(value) : std::to_string(value);
|
||||||
output += str;
|
output += str;
|
||||||
if(rowPart.MinWidth > (int)str.size()) {
|
if(rowPart.MinWidth > (int)str.size()) {
|
||||||
output += std::string(rowPart.MinWidth - str.size(), ' ');
|
output += std::string(rowPart.MinWidth - str.size(), ' ');
|
||||||
|
@ -94,6 +95,10 @@ void TraceLogger::SetOptions(TraceLoggerOptions options)
|
||||||
part.DataType = RowDataType::X;
|
part.DataType = RowDataType::X;
|
||||||
} else if(dataType == "Y") {
|
} else if(dataType == "Y") {
|
||||||
part.DataType = RowDataType::Y;
|
part.DataType = RowDataType::Y;
|
||||||
|
} else if(dataType == "D") {
|
||||||
|
part.DataType = RowDataType::D;
|
||||||
|
} else if(dataType == "DB") {
|
||||||
|
part.DataType = RowDataType::DB;
|
||||||
} else if(dataType == "P") {
|
} else if(dataType == "P") {
|
||||||
part.DataType = RowDataType::PS;
|
part.DataType = RowDataType::PS;
|
||||||
} else if(dataType == "SP") {
|
} else if(dataType == "SP") {
|
||||||
|
@ -159,8 +164,8 @@ void TraceLogger::GetStatusFlag(string &output, uint8_t ps, RowPart& part)
|
||||||
if(part.DisplayInHex) {
|
if(part.DisplayInHex) {
|
||||||
WriteValue(output, ps, part);
|
WriteValue(output, ps, part);
|
||||||
} else {
|
} else {
|
||||||
constexpr char activeStatusLetters[8] = { 'N', 'V', 'X', 'M', 'D', 'I', 'Z', 'C' };
|
constexpr char activeStatusLetters[8] = { 'N', 'V', 'M', 'X', 'D', 'I', 'Z', 'C' };
|
||||||
constexpr char inactiveStatusLetters[8] = { 'n', 'v', 'x', 'm', 'd', 'i', 'z', 'c' };
|
constexpr char inactiveStatusLetters[8] = { 'n', 'v', 'm', 'x', 'd', 'i', 'z', 'c' };
|
||||||
string flags;
|
string flags;
|
||||||
for(int i = 0; i < 8; i++) {
|
for(int i = 0; i < 8; i++) {
|
||||||
if(ps & 0x80) {
|
if(ps & 0x80) {
|
||||||
|
@ -174,9 +179,10 @@ void TraceLogger::GetStatusFlag(string &output, uint8_t ps, RowPart& part)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceLogger::GetTraceRow(string &output, CpuState &cpuState, DisassemblyInfo &disassemblyInfo)
|
void TraceLogger::GetTraceRow(string &output, CpuState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo)
|
||||||
{
|
{
|
||||||
int originalSize = (int)output.size();
|
int originalSize = (int)output.size();
|
||||||
|
uint32_t pcAddress = (cpuState.K << 16) | cpuState.PC;
|
||||||
for(RowPart& rowPart : _rowParts) {
|
for(RowPart& rowPart : _rowParts) {
|
||||||
switch(rowPart.DataType) {
|
switch(rowPart.DataType) {
|
||||||
case RowDataType::Text: output += rowPart.Text; break;
|
case RowDataType::Text: output += rowPart.Text; break;
|
||||||
|
@ -204,7 +210,7 @@ void TraceLogger::GetTraceRow(string &output, CpuState &cpuState, DisassemblyInf
|
||||||
}
|
}
|
||||||
|
|
||||||
//LabelManager* labelManager = _options.UseLabels ? _labelManager.get() : nullptr;
|
//LabelManager* labelManager = _options.UseLabels ? _labelManager.get() : nullptr;
|
||||||
disassemblyInfo.GetDisassembly(code, _memoryManager.get());
|
disassemblyInfo.GetDisassembly(code, pcAddress);
|
||||||
WriteValue(output, code, rowPart);
|
WriteValue(output, code, rowPart);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -233,16 +239,18 @@ void TraceLogger::GetTraceRow(string &output, CpuState &cpuState, DisassemblyInf
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RowDataType::PC: WriteValue(output, (cpuState.K << 16) | cpuState.PC, rowPart); break;
|
case RowDataType::PC: WriteValue(output, pcAddress, rowPart); break;
|
||||||
case RowDataType::A: WriteValue(output, cpuState.A, rowPart); break;
|
case RowDataType::A: WriteValue(output, cpuState.A, rowPart); break;
|
||||||
case RowDataType::X: WriteValue(output, cpuState.X, rowPart); break;
|
case RowDataType::X: WriteValue(output, cpuState.X, rowPart); break;
|
||||||
case RowDataType::Y: WriteValue(output, cpuState.Y, rowPart); break;
|
case RowDataType::Y: WriteValue(output, cpuState.Y, rowPart); break;
|
||||||
|
case RowDataType::D: WriteValue(output, cpuState.D, rowPart); break;
|
||||||
|
case RowDataType::DB: WriteValue(output, cpuState.DBR, rowPart); break;
|
||||||
case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); break;
|
case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); break;
|
||||||
case RowDataType::PS: GetStatusFlag(output, cpuState.PS, rowPart); break;
|
case RowDataType::PS: GetStatusFlag(output, cpuState.PS, rowPart); break;
|
||||||
//case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break;
|
case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break;
|
||||||
//case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break;
|
case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break;
|
||||||
//case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break;
|
case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break;
|
||||||
case RowDataType::CycleCount: WriteValue(output, cpuState.CycleCount, rowPart); break;
|
case RowDataType::CycleCount: WriteValue(output, (uint32_t)cpuState.CycleCount, rowPart); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
output += _options.UseWindowsEol ? "\r\n" : "\n";
|
output += _options.UseWindowsEol ? "\r\n" : "\n";
|
||||||
|
@ -269,7 +277,7 @@ void TraceLogger::AddRow(DisassemblyInfo &disassemblyInfo, DebugState &state)
|
||||||
{
|
{
|
||||||
_disassemblyCache[_currentPos] = disassemblyInfo;
|
_disassemblyCache[_currentPos] = disassemblyInfo;
|
||||||
_cpuStateCache[_currentPos] = state.Cpu;
|
_cpuStateCache[_currentPos] = state.Cpu;
|
||||||
//_ppuStateCache[_currentPos] = state.PPU;
|
_ppuStateCache[_currentPos] = state.Ppu;
|
||||||
_pendingLog = false;
|
_pendingLog = false;
|
||||||
|
|
||||||
if(_logCount < ExecutionLogSize) {
|
if(_logCount < ExecutionLogSize) {
|
||||||
|
@ -277,7 +285,7 @@ void TraceLogger::AddRow(DisassemblyInfo &disassemblyInfo, DebugState &state)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_logToFile) {
|
if(_logToFile) {
|
||||||
GetTraceRow(_outputBuffer, state.Cpu, disassemblyInfo);
|
GetTraceRow(_outputBuffer, state.Cpu, state.Ppu, disassemblyInfo);
|
||||||
if(_outputBuffer.size() > 32768) {
|
if(_outputBuffer.size() > 32768) {
|
||||||
_outputFile << _outputBuffer;
|
_outputFile << _outputBuffer;
|
||||||
_outputBuffer.clear();
|
_outputBuffer.clear();
|
||||||
|
@ -314,7 +322,7 @@ const char* TraceLogger::GetExecutionTrace(uint32_t lineCount)
|
||||||
auto lock = _lock.AcquireSafe();
|
auto lock = _lock.AcquireSafe();
|
||||||
lineCount = std::min(lineCount, _logCount);
|
lineCount = std::min(lineCount, _logCount);
|
||||||
memcpy(_cpuStateCacheCopy, _cpuStateCache, sizeof(_cpuStateCache));
|
memcpy(_cpuStateCacheCopy, _cpuStateCache, sizeof(_cpuStateCache));
|
||||||
//memcpy(_ppuStateCacheCopy, _ppuStateCache, sizeof(_ppuStateCache));
|
memcpy(_ppuStateCacheCopy, _ppuStateCache, sizeof(_ppuStateCache));
|
||||||
memcpy(_disassemblyCacheCopy, _disassemblyCache, sizeof(_disassemblyCache));
|
memcpy(_disassemblyCacheCopy, _disassemblyCache, sizeof(_disassemblyCache));
|
||||||
startPos = _currentPos + ExecutionLogSize - lineCount;
|
startPos = _currentPos + ExecutionLogSize - lineCount;
|
||||||
}
|
}
|
||||||
|
@ -325,7 +333,7 @@ const char* TraceLogger::GetExecutionTrace(uint32_t lineCount)
|
||||||
string byteCode;
|
string byteCode;
|
||||||
_disassemblyCacheCopy[index].GetByteCode(byteCode);
|
_disassemblyCacheCopy[index].GetByteCode(byteCode);
|
||||||
_executionTrace += byteCode + "\x1";
|
_executionTrace += byteCode + "\x1";
|
||||||
GetTraceRow(_executionTrace, _cpuStateCacheCopy[index], _disassemblyCacheCopy[index]);
|
GetTraceRow(_executionTrace, _cpuStateCacheCopy[index], _ppuStateCacheCopy[index], _disassemblyCacheCopy[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _executionTrace.c_str();
|
return _executionTrace.c_str();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "CpuTypes.h"
|
#include "CpuTypes.h"
|
||||||
|
#include "PpuTypes.h"
|
||||||
#include "DisassemblyInfo.h"
|
#include "DisassemblyInfo.h"
|
||||||
#include "../Utilities/SimpleLock.h"
|
#include "../Utilities/SimpleLock.h"
|
||||||
|
|
||||||
|
@ -32,6 +33,8 @@ enum class RowDataType
|
||||||
A,
|
A,
|
||||||
X,
|
X,
|
||||||
Y,
|
Y,
|
||||||
|
D,
|
||||||
|
DB,
|
||||||
SP,
|
SP,
|
||||||
PS,
|
PS,
|
||||||
Cycle,
|
Cycle,
|
||||||
|
@ -73,11 +76,11 @@ private:
|
||||||
uint16_t _currentPos;
|
uint16_t _currentPos;
|
||||||
uint32_t _logCount;
|
uint32_t _logCount;
|
||||||
CpuState _cpuStateCache[ExecutionLogSize] = {};
|
CpuState _cpuStateCache[ExecutionLogSize] = {};
|
||||||
//PPUDebugState _ppuStateCache[ExecutionLogSize] = {};
|
PpuState _ppuStateCache[ExecutionLogSize] = {};
|
||||||
DisassemblyInfo _disassemblyCache[ExecutionLogSize];
|
DisassemblyInfo _disassemblyCache[ExecutionLogSize];
|
||||||
|
|
||||||
CpuState _cpuStateCacheCopy[ExecutionLogSize] = {};
|
CpuState _cpuStateCacheCopy[ExecutionLogSize] = {};
|
||||||
//PPUDebugState _ppuStateCacheCopy[ExecutionLogSize] = {};
|
PpuState _ppuStateCacheCopy[ExecutionLogSize] = {};
|
||||||
DisassemblyInfo _disassemblyCacheCopy[ExecutionLogSize];
|
DisassemblyInfo _disassemblyCacheCopy[ExecutionLogSize];
|
||||||
|
|
||||||
SimpleLock _lock;
|
SimpleLock _lock;
|
||||||
|
@ -86,7 +89,7 @@ private:
|
||||||
void AddRow(DisassemblyInfo &disassemblyInfo, DebugState &state);
|
void AddRow(DisassemblyInfo &disassemblyInfo, DebugState &state);
|
||||||
//bool ConditionMatches(DebugState &state, DisassemblyInfo &disassemblyInfo, OperationInfo &operationInfo);
|
//bool ConditionMatches(DebugState &state, DisassemblyInfo &disassemblyInfo, OperationInfo &operationInfo);
|
||||||
|
|
||||||
void GetTraceRow(string &output, CpuState &cpuState, DisassemblyInfo &disassemblyInfo);
|
void GetTraceRow(string &output, CpuState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo);
|
||||||
|
|
||||||
template<typename T> void WriteValue(string &output, T value, RowPart& rowPart);
|
template<typename T> void WriteValue(string &output, T value, RowPart& rowPart);
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ namespace Mesen.GUI.Debugger
|
||||||
private string _lastFilename;
|
private string _lastFilename;
|
||||||
private EntityBinder _entityBinder = new EntityBinder();
|
private EntityBinder _entityBinder = new EntityBinder();
|
||||||
private string _previousTrace;
|
private string _previousTrace;
|
||||||
|
private UInt64 _previousCycleCount;
|
||||||
private volatile bool _refreshRunning;
|
private volatile bool _refreshRunning;
|
||||||
private bool _initialized;
|
private bool _initialized;
|
||||||
|
|
||||||
|
@ -161,13 +162,12 @@ namespace Mesen.GUI.Debugger
|
||||||
format += "[Align," + alignValue.ToString() + "] ";
|
format += "[Align," + alignValue.ToString() + "] ";
|
||||||
|
|
||||||
if(chkShowRegisters.Checked) {
|
if(chkShowRegisters.Checked) {
|
||||||
format += "A:[A,h] X:[X,h] Y:[Y,h] ";
|
format += "A:[A,4h] X:[X,4h] Y:[Y,4h] S:[SP,4h] D:[D,4h] DB:[DB,2h] ";
|
||||||
switch(cboStatusFlagFormat.GetEnumValue<StatusFlagFormat>()) {
|
switch(cboStatusFlagFormat.GetEnumValue<StatusFlagFormat>()) {
|
||||||
case StatusFlagFormat.Hexadecimal: format += "P:[P,h]"; break;
|
case StatusFlagFormat.Hexadecimal: format += "P:[P,h] "; break;
|
||||||
case StatusFlagFormat.CompactText: format += "P:[P]"; break;
|
case StatusFlagFormat.CompactText: format += "P:[P] "; break;
|
||||||
case StatusFlagFormat.Text: format += "P:[P,8]"; break;
|
case StatusFlagFormat.Text: format += "P:[P,8] "; break;
|
||||||
}
|
}
|
||||||
format += " SP:[SP,h] ";
|
|
||||||
}
|
}
|
||||||
if(chkShowPpuCycles.Checked) {
|
if(chkShowPpuCycles.Checked) {
|
||||||
format += "CYC:[Cycle,3] ";
|
format += "CYC:[Cycle,3] ";
|
||||||
|
@ -271,12 +271,10 @@ namespace Mesen.GUI.Debugger
|
||||||
Task.Run(() => {
|
Task.Run(() => {
|
||||||
//Update trace log in another thread for performance
|
//Update trace log in another thread for performance
|
||||||
//DebugState state = new DebugState();
|
//DebugState state = new DebugState();
|
||||||
//InteropEmu.DebugGetState(ref state);
|
DebugState state = DebugApi.GetState();
|
||||||
//if(_previousCycleCount != state.CPU.CycleCount || forceUpdate) {
|
if(_previousCycleCount != state.Cpu.CycleCount || forceUpdate) {
|
||||||
//TODO
|
|
||||||
if(true) {
|
|
||||||
string newTrace = DebugApi.GetExecutionTrace((UInt32)_lineCount);
|
string newTrace = DebugApi.GetExecutionTrace((UInt32)_lineCount);
|
||||||
//_previousCycleCount = state.CPU.CycleCount;
|
_previousCycleCount = state.Cpu.CycleCount;
|
||||||
_previousTrace = newTrace;
|
_previousTrace = newTrace;
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
@ -367,7 +365,7 @@ namespace Mesen.GUI.Debugger
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mnuAutoRefresh.Checked) {
|
if(mnuAutoRefresh.Checked) {
|
||||||
RefreshLog(false, false);
|
RefreshLog(true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -121,12 +121,12 @@
|
||||||
<value>17, 17</value>
|
<value>17, 17</value>
|
||||||
</metadata>
|
</metadata>
|
||||||
<metadata name="ctxMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
<metadata name="ctxMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
<value>353, 17</value>
|
<value>17, 134</value>
|
||||||
</metadata>
|
</metadata>
|
||||||
<metadata name="tmrUpdateLog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
<metadata name="tmrUpdateLog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
<value>107, 17</value>
|
<value>17, 56</value>
|
||||||
</metadata>
|
</metadata>
|
||||||
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
<value>238, 17</value>
|
<value>17, 95</value>
|
||||||
</metadata>
|
</metadata>
|
||||||
</root>
|
</root>
|
44
UI/Forms/frmMain.Designer.cs
generated
44
UI/Forms/frmMain.Designer.cs
generated
|
@ -32,11 +32,12 @@
|
||||||
this.mnuFile = new System.Windows.Forms.ToolStripMenuItem();
|
this.mnuFile = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
this.mnuOpen = new System.Windows.Forms.ToolStripMenuItem();
|
this.mnuOpen = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
this.debugToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
this.debugToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
|
this.mnuRun = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
this.mnuStep = new System.Windows.Forms.ToolStripMenuItem();
|
this.mnuStep = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
|
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
|
||||||
this.mnuDebugger = new System.Windows.Forms.ToolStripMenuItem();
|
this.mnuDebugger = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
this.mnuTraceLogger = new System.Windows.Forms.ToolStripMenuItem();
|
this.mnuTraceLogger = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
|
this.mnuRun100Instructions = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
this.mnuRun = new System.Windows.Forms.ToolStripMenuItem();
|
|
||||||
this.mnuMain.SuspendLayout();
|
this.mnuMain.SuspendLayout();
|
||||||
this.SuspendLayout();
|
this.SuspendLayout();
|
||||||
//
|
//
|
||||||
|
@ -70,7 +71,7 @@
|
||||||
//
|
//
|
||||||
this.mnuOpen.Image = global::Mesen.GUI.Properties.Resources.Folder;
|
this.mnuOpen.Image = global::Mesen.GUI.Properties.Resources.Folder;
|
||||||
this.mnuOpen.Name = "mnuOpen";
|
this.mnuOpen.Name = "mnuOpen";
|
||||||
this.mnuOpen.Size = new System.Drawing.Size(152, 22);
|
this.mnuOpen.Size = new System.Drawing.Size(103, 22);
|
||||||
this.mnuOpen.Text = "Open";
|
this.mnuOpen.Text = "Open";
|
||||||
this.mnuOpen.Click += new System.EventHandler(this.mnuOpen_Click);
|
this.mnuOpen.Click += new System.EventHandler(this.mnuOpen_Click);
|
||||||
//
|
//
|
||||||
|
@ -79,6 +80,7 @@
|
||||||
this.debugToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
this.debugToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||||
this.mnuRun,
|
this.mnuRun,
|
||||||
this.mnuStep,
|
this.mnuStep,
|
||||||
|
this.mnuRun100Instructions,
|
||||||
this.toolStripMenuItem1,
|
this.toolStripMenuItem1,
|
||||||
this.mnuDebugger,
|
this.mnuDebugger,
|
||||||
this.mnuTraceLogger});
|
this.mnuTraceLogger});
|
||||||
|
@ -86,38 +88,47 @@
|
||||||
this.debugToolStripMenuItem.Size = new System.Drawing.Size(54, 20);
|
this.debugToolStripMenuItem.Size = new System.Drawing.Size(54, 20);
|
||||||
this.debugToolStripMenuItem.Text = "Debug";
|
this.debugToolStripMenuItem.Text = "Debug";
|
||||||
//
|
//
|
||||||
|
// mnuRun
|
||||||
|
//
|
||||||
|
this.mnuRun.Name = "mnuRun";
|
||||||
|
this.mnuRun.ShortcutKeys = System.Windows.Forms.Keys.F5;
|
||||||
|
this.mnuRun.Size = new System.Drawing.Size(157, 22);
|
||||||
|
this.mnuRun.Text = "Run";
|
||||||
|
this.mnuRun.Click += new System.EventHandler(this.mnuRun_Click);
|
||||||
|
//
|
||||||
// mnuStep
|
// mnuStep
|
||||||
//
|
//
|
||||||
this.mnuStep.Name = "mnuStep";
|
this.mnuStep.Name = "mnuStep";
|
||||||
this.mnuStep.ShortcutKeys = System.Windows.Forms.Keys.F11;
|
this.mnuStep.ShortcutKeys = System.Windows.Forms.Keys.F11;
|
||||||
this.mnuStep.Size = new System.Drawing.Size(152, 22);
|
this.mnuStep.Size = new System.Drawing.Size(157, 22);
|
||||||
this.mnuStep.Text = "Step";
|
this.mnuStep.Text = "Step";
|
||||||
this.mnuStep.Click += new System.EventHandler(this.mnuStep_Click);
|
this.mnuStep.Click += new System.EventHandler(this.mnuStep_Click);
|
||||||
//
|
//
|
||||||
|
// toolStripMenuItem1
|
||||||
|
//
|
||||||
|
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
|
||||||
|
this.toolStripMenuItem1.Size = new System.Drawing.Size(154, 6);
|
||||||
|
//
|
||||||
// mnuDebugger
|
// mnuDebugger
|
||||||
//
|
//
|
||||||
this.mnuDebugger.Name = "mnuDebugger";
|
this.mnuDebugger.Name = "mnuDebugger";
|
||||||
this.mnuDebugger.Size = new System.Drawing.Size(152, 22);
|
this.mnuDebugger.Size = new System.Drawing.Size(157, 22);
|
||||||
this.mnuDebugger.Text = "Debugger";
|
this.mnuDebugger.Text = "Debugger";
|
||||||
//
|
//
|
||||||
// mnuTraceLogger
|
// mnuTraceLogger
|
||||||
//
|
//
|
||||||
this.mnuTraceLogger.Name = "mnuTraceLogger";
|
this.mnuTraceLogger.Name = "mnuTraceLogger";
|
||||||
this.mnuTraceLogger.Size = new System.Drawing.Size(152, 22);
|
this.mnuTraceLogger.Size = new System.Drawing.Size(157, 22);
|
||||||
this.mnuTraceLogger.Text = "Trace Logger";
|
this.mnuTraceLogger.Text = "Trace Logger";
|
||||||
this.mnuTraceLogger.Click += new System.EventHandler(this.mnuTraceLogger_Click);
|
this.mnuTraceLogger.Click += new System.EventHandler(this.mnuTraceLogger_Click);
|
||||||
//
|
//
|
||||||
// toolStripMenuItem1
|
// mnuRun100Instructions
|
||||||
//
|
//
|
||||||
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
|
this.mnuRun100Instructions.Name = "mnuRun100Instructions";
|
||||||
this.toolStripMenuItem1.Size = new System.Drawing.Size(149, 6);
|
this.mnuRun100Instructions.ShortcutKeys = System.Windows.Forms.Keys.F6;
|
||||||
//
|
this.mnuRun100Instructions.Size = new System.Drawing.Size(157, 22);
|
||||||
// mnuRun
|
this.mnuRun100Instructions.Text = "Run 100 ops";
|
||||||
//
|
this.mnuRun100Instructions.Click += new System.EventHandler(this.mnuRun100Instructions_Click);
|
||||||
this.mnuRun.Name = "mnuRun";
|
|
||||||
this.mnuRun.Size = new System.Drawing.Size(152, 22);
|
|
||||||
this.mnuRun.Text = "Run";
|
|
||||||
this.mnuRun.Click += new System.EventHandler(this.mnuRun_Click);
|
|
||||||
//
|
//
|
||||||
// frmMain
|
// frmMain
|
||||||
//
|
//
|
||||||
|
@ -148,5 +159,6 @@
|
||||||
private System.Windows.Forms.ToolStripMenuItem mnuOpen;
|
private System.Windows.Forms.ToolStripMenuItem mnuOpen;
|
||||||
private System.Windows.Forms.ToolStripMenuItem mnuRun;
|
private System.Windows.Forms.ToolStripMenuItem mnuRun;
|
||||||
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1;
|
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1;
|
||||||
|
private System.Windows.Forms.ToolStripMenuItem mnuRun100Instructions;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -58,5 +58,10 @@ namespace Mesen.GUI.Forms
|
||||||
{
|
{
|
||||||
DebugApi.ResumeExecution();
|
DebugApi.ResumeExecution();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void mnuRun100Instructions_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
DebugApi.Step(100);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace Mesen.GUI
|
||||||
[DllImport(DllPath)] public static extern void ReleaseDebugger();
|
[DllImport(DllPath)] public static extern void ReleaseDebugger();
|
||||||
|
|
||||||
[DllImport(DllPath)] public static extern void ResumeExecution();
|
[DllImport(DllPath)] public static extern void ResumeExecution();
|
||||||
[DllImport(DllPath)] public static extern void Step(Int32 scanCode);
|
[DllImport(DllPath)] public static extern void Step(Int32 instructionCount);
|
||||||
|
|
||||||
[DllImport(DllPath)] public static extern void StartTraceLogger([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]string filename);
|
[DllImport(DllPath)] public static extern void StartTraceLogger([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]string filename);
|
||||||
[DllImport(DllPath)] public static extern void StopTraceLogger();
|
[DllImport(DllPath)] public static extern void StopTraceLogger();
|
||||||
|
@ -27,6 +27,45 @@ namespace Mesen.GUI
|
||||||
|
|
||||||
[DllImport(DllPath, EntryPoint = "GetExecutionTrace")] private static extern IntPtr GetExecutionTraceWrapper(UInt32 lineCount);
|
[DllImport(DllPath, EntryPoint = "GetExecutionTrace")] private static extern IntPtr GetExecutionTraceWrapper(UInt32 lineCount);
|
||||||
public static string GetExecutionTrace(UInt32 lineCount) { return Utf8Marshaler.PtrToStringUtf8(DebugApi.GetExecutionTraceWrapper(lineCount)); }
|
public static string GetExecutionTrace(UInt32 lineCount) { return Utf8Marshaler.PtrToStringUtf8(DebugApi.GetExecutionTraceWrapper(lineCount)); }
|
||||||
|
|
||||||
|
[DllImport(DllPath, EntryPoint = "GetState")] private static extern void GetStateWrapper(ref DebugState state);
|
||||||
|
public static DebugState GetState()
|
||||||
|
{
|
||||||
|
DebugState state = new DebugState();
|
||||||
|
DebugApi.GetStateWrapper(ref state);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct CpuState
|
||||||
|
{
|
||||||
|
public UInt64 CycleCount;
|
||||||
|
|
||||||
|
public UInt16 A;
|
||||||
|
public UInt16 X;
|
||||||
|
public UInt16 Y;
|
||||||
|
|
||||||
|
public UInt16 SP;
|
||||||
|
public UInt16 D;
|
||||||
|
public UInt16 PC;
|
||||||
|
|
||||||
|
public byte K;
|
||||||
|
public byte DBR;
|
||||||
|
public byte PS;
|
||||||
|
[MarshalAs(UnmanagedType.I1)] public bool EmulationMode;
|
||||||
|
};
|
||||||
|
|
||||||
|
public struct PpuState
|
||||||
|
{
|
||||||
|
public UInt16 Cycle;
|
||||||
|
public UInt16 Scanline;
|
||||||
|
public UInt32 FrameCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
public struct DebugState
|
||||||
|
{
|
||||||
|
public CpuState Cpu;
|
||||||
|
public PpuState Ppu;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
|
|
Loading…
Add table
Reference in a new issue