Fixed addressing bugs, added PPU stub, improved trace logger output, split CPU instructions to another file

This commit is contained in:
Sour 2019-02-13 13:32:21 -05:00
parent 5c19584019
commit 522372a365
22 changed files with 1374 additions and 1018 deletions

View file

@ -32,6 +32,7 @@ void Console::Stop()
_runLock.WaitForRelease();
_cpu.reset();
_ppu.reset();
_memoryManager.reset();
_debugger.reset();
}
@ -42,12 +43,18 @@ void Console::LoadRom(VirtualFile romFile, VirtualFile patchFile)
shared_ptr<BaseCartridge> cart = BaseCartridge::CreateCartridge(romFile, patchFile);
if(cart) {
_ppu.reset(new Ppu());
_memoryManager.reset(new MemoryManager(cart, shared_from_this()));
_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)
{
return _debugger;

View file

@ -4,6 +4,7 @@
#include "../Utilities/SimpleLock.h"
class Cpu;
class Ppu;
class MemoryManager;
class Debugger;
enum class MemoryOperationType;
@ -12,6 +13,7 @@ class Console : public std::enable_shared_from_this<Console>
{
private:
shared_ptr<Cpu> _cpu;
shared_ptr<Ppu> _ppu;
shared_ptr<MemoryManager> _memoryManager;
shared_ptr<Debugger> _debugger;
@ -24,6 +26,7 @@ public:
void LoadRom(VirtualFile romFile, VirtualFile patchFile);
shared_ptr<Ppu> GetPpu();
shared_ptr<Debugger> GetDebugger(bool allowStart = true);
void ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType type);

View file

@ -60,6 +60,8 @@
<ClInclude Include="KeyManager.h" />
<ClInclude Include="MemoryManager.h" />
<ClInclude Include="MessageManager.h" />
<ClInclude Include="Ppu.h" />
<ClInclude Include="PpuTypes.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="TraceLogger.h" />
</ItemGroup>
@ -68,6 +70,7 @@
<ClCompile Include="BaseSoundManager.cpp" />
<ClCompile Include="Console.cpp" />
<ClCompile Include="Cpu.cpp" />
<ClCompile Include="Cpu.Instructions.cpp" />
<ClCompile Include="Debugger.cpp" />
<ClCompile Include="DisassemblyInfo.cpp" />
<ClCompile Include="KeyManager.cpp" />

View file

@ -56,6 +56,12 @@
<ClInclude Include="KeyManager.h">
<Filter>Misc</Filter>
</ClInclude>
<ClInclude Include="Ppu.h">
<Filter>SNES</Filter>
</ClInclude>
<ClInclude Include="PpuTypes.h">
<Filter>SNES</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp" />
@ -86,6 +92,9 @@
<ClCompile Include="KeyManager.cpp">
<Filter>Misc</Filter>
</ClCompile>
<ClCompile Include="Cpu.Instructions.cpp">
<Filter>SNES</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="SNES">

921
Core/Cpu.Instructions.cpp Normal file
View 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 &reg, 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 &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) {
SetRegister(reg, PopByte(), true);
} else {
SetRegister(reg, PopWord(), false);
}
}
/*********************
Store/load operations
**********************/
void Cpu::LoadRegister(uint16_t &reg, 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
}

File diff suppressed because it is too large Load diff

View file

@ -33,10 +33,10 @@ private:
Func _opTable[256];
AddrMode _addrMode[256];
uint32_t GetBank();
uint32_t GetProgramAddress();
uint16_t GetDirectAddress(uint8_t baseAddress, uint16_t offset = 0, bool allowEmulationMode = true);
uint32_t GetProgramAddress(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();
void DummyRead();
@ -57,6 +57,8 @@ private:
bool CheckFlag(uint8_t flag);
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);
uint16_t ReadDataWord(uint32_t addr, MemoryOperationType type = MemoryOperationType::Read);
uint32_t ReadDataLong(uint32_t addr, MemoryOperationType type = MemoryOperationType::Read);

View file

@ -62,9 +62,11 @@ enum class AddrMode : uint8_t
AbsIdxX,
AbsIdxY,
AbsInd, //JMP only
AbsIndLng, //JMP only (unofficial)
AbsIndLng, //JML only
AbsLngIdxX,
AbsLng,
AbsJmp, //JSR/JMP only
AbsLngJmp, //JSL/JMP only
Acc,
BlkMov,
DirIdxIndX,

View file

@ -1,14 +1,16 @@
#include "stdafx.h"
#include "Debugger.h"
#include "Cpu.h"
#include "Ppu.h"
#include "CpuTypes.h"
#include "DisassemblyInfo.h"
#include "TraceLogger.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;
_ppu = ppu;
_memoryManager = 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) {
CpuState state = _cpu->GetState();
DisassemblyInfo disassemblyInfo(state, _memoryManager.get());
DebugState debugState = { state };
DebugState debugState;
GetState(&debugState);
_traceLogger->Log(debugState, disassemblyInfo);
string out;
/*string out;
out += HexUtilities::ToHex(state.K) + HexUtilities::ToHex(state.PC);
out += " ";
disassemblyInfo.GetDisassembly(out, _memoryManager.get());
@ -43,7 +46,7 @@ void Debugger::ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType
" DB:$" << HexUtilities::ToHex(state.DBR) <<
" P:$" << HexUtilities::ToHex(state.PS) <<
std::endl;
//_traceLogger->Trace
//_traceLogger->Trace*/
if(_cpuStepCount > 0) {
_cpuStepCount--;
@ -77,6 +80,12 @@ bool Debugger::IsExecutionStopped()
return false;
}
void Debugger::GetState(DebugState *state)
{
state->Cpu = _cpu->GetState();
state->Ppu = _ppu->GetState();
}
shared_ptr<TraceLogger> Debugger::GetTraceLogger()
{
return _traceLogger;

View file

@ -1,8 +1,10 @@
#pragma once
#include "stdafx.h"
#include "CpuTypes.h"
#include "PpuTypes.h"
class Cpu;
class Ppu;
class MemoryManager;
enum class MemoryOperationType;
@ -12,7 +14,7 @@ class TraceLogger;
struct DebugState
{
CpuState Cpu;
//PpuState ppuState;
PpuState Ppu;
//ApuState apuState;
};
@ -20,6 +22,7 @@ class Debugger
{
private:
shared_ptr<Cpu> _cpu;
shared_ptr<Ppu> _ppu;
shared_ptr<MemoryManager> _memoryManager;
shared_ptr<TraceLogger> _traceLogger;
@ -28,7 +31,7 @@ private:
atomic<int32_t> _cpuStepCount;
public:
Debugger(shared_ptr<Cpu> cpu, shared_ptr<MemoryManager> memoryManager);
Debugger(shared_ptr<Cpu> cpu, shared_ptr<Ppu> ppu, shared_ptr<MemoryManager> memoryManager);
~Debugger();
void ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType type);
@ -38,5 +41,7 @@ public:
void Step(int32_t stepCount);
bool IsExecutionStopped();
void GetState(DebugState *state);
shared_ptr<TraceLogger> GetTraceLogger();
};

View file

@ -1,8 +1,10 @@
#include "stdafx.h"
#include <algorithm>
#include "DisassemblyInfo.h"
#include "CpuTypes.h"
#include "MemoryManager.h"
#include "../Utilities/HexUtilities.h"
#include "../Utilities/FastString.h"
DisassemblyInfo::DisassemblyInfo()
{
@ -10,6 +12,8 @@ DisassemblyInfo::DisassemblyInfo()
DisassemblyInfo::DisassemblyInfo(CpuState &state, MemoryManager *memoryManager)
{
_flags = state.PS;
uint32_t addr = (state.K << 16) | state.PC;
_byteCode[0] = memoryManager->Peek(addr);
_addrMode = DisassemblyInfo::OpMode[_byteCode[0]];
@ -19,17 +23,79 @@ DisassemblyInfo::DisassemblyInfo(CpuState &state, MemoryManager *memoryManager)
_byteCode[i] = memoryManager->Peek(addr+i);
}
_flags = state.PS;
_emulationMode = state.EmulationMode;
}
void DisassemblyInfo::GetDisassembly(string &out, MemoryManager *memoryManager)
void DisassemblyInfo::GetDisassembly(string &out, uint32_t memoryAddr)
{
out += DisassemblyInfo::OpName[_byteCode[0]];
out += _opSize > 1 ? " $" : " ";
for(int i = _opSize - 1; i > 0; i--) {
out += HexUtilities::ToHex(_byteCode[i]);
FastString str;
str.Write(DisassemblyInfo::OpName[_byteCode[0]]);
str.Write(' ');
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()
@ -39,12 +105,16 @@ uint8_t DisassemblyInfo::GetOperandSize()
case AddrMode::AbsIdxXInd: return 2;
case AddrMode::AbsIdxX: return 2;
case AddrMode::AbsIdxY: return 2;
case AddrMode::AbsInd: return 2;
case AddrMode::AbsIndLng: return 3;
case AddrMode::AbsIndLng: return 2;
case AddrMode::AbsLngIdxX: return 3;
case AddrMode::AbsLng: return 3;
case AddrMode::Acc: return 0;
case AddrMode::BlkMov: return 2;
case AddrMode::DirIdxIndX: return 1;
case AddrMode::DirIdxX: return 1;
case AddrMode::DirIdxY: return 1;
@ -53,12 +123,15 @@ uint8_t DisassemblyInfo::GetOperandSize()
case AddrMode::DirIndLng: return 1;
case AddrMode::DirInd: return 1;
case AddrMode::Dir: return 1;
case AddrMode::Imm8: return 1;
case AddrMode::ImmX: return _flags & ProcFlags::IndexMode8 ? 1 : 2;
case AddrMode::ImmM: return _flags & ProcFlags::MemoryMode8 ? 1 : 2;
case AddrMode::ImmX: return (_flags & ProcFlags::IndexMode8) ? 1 : 2;
case AddrMode::ImmM: return (_flags & ProcFlags::MemoryMode8) ? 1 : 2;
case AddrMode::Imp: return 0;
case AddrMode::RelLng: return 2;
case AddrMode::Rel: return 1;
case AddrMode::Stk: return 0; //TODO
case AddrMode::StkRel: return 1;
case AddrMode::StkRelIndIdxY: return 1;
@ -69,8 +142,22 @@ uint8_t DisassemblyInfo::GetOperandSize()
void DisassemblyInfo::GetByteCode(string &out)
{
FastString str;
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) {
}
}

View file

@ -25,19 +25,17 @@ public:
DisassemblyInfo();
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();
void GetByteCode(string &out);
/*
int32_t GetEffectiveAddress(CpuState &cpuState, MemoryManager *memoryManager);
void GetEffectiveAddressString(string &out, CpuState& cpuState, MemoryManager *memoryManager);
/*int32_t GetMemoryValue(CpuState& cpuState, MemoryManager* memoryManager);
uint16_t GetJumpDestination(uint16_t pc, 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);*/
*/
};

View file

@ -1,6 +1,7 @@
#pragma once
#include "stdafx.h"
#include "Console.h"
#include "Ppu.h"
#include "../Utilities/HexUtilities.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
{
private:
@ -82,12 +105,22 @@ private:
IMemoryHandler* _handlers[0x100 * 0x10];
vector<unique_ptr<WorkRamHandler>> _workRamHandlers;
shared_ptr<BaseCartridge> _cart;
shared_ptr<CpuRegisterHandler> _cpuRegisterHandler;
shared_ptr<Ppu> _ppu;
uint64_t _masterClock;
uint64_t _lastMasterClock;
public:
MemoryManager(shared_ptr<BaseCartridge> cart, shared_ptr<Console> console)
{
_lastMasterClock = 0;
_masterClock = 0;
_console = console;
_cart = cart;
_ppu = console->GetPpu();
_cpuRegisterHandler.reset(new CpuRegisterHandler(_ppu));
memset(_handlers, 0, sizeof(_handlers));
_workRam = new uint8_t[128 * 1024];
@ -96,6 +129,11 @@ public:
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(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)
{
IncrementMasterClock(addr);
uint8_t value = 0;
if(_handlers[addr >> 12]) {
value = _handlers[addr >> 12]->Read(addr);
@ -146,6 +227,8 @@ public:
void Write(uint32_t addr, uint8_t value, MemoryOperationType type)
{
IncrementMasterClock(addr);
_console->ProcessCpuWrite(addr, value, type);
if(_handlers[addr >> 12]) {
return _handlers[addr >> 12]->Write(addr, value);

65
Core/Ppu.h Normal file
View 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
View file

@ -0,0 +1,9 @@
#pragma once
#include "stdafx.h"
struct PpuState
{
uint16_t Cycle;
uint16_t Scanline;
uint32_t FrameCount;
};

View file

@ -1,5 +1,6 @@
#include "stdafx.h"
#include <regex>
#include <algorithm>
#include "TraceLogger.h"
#include "DisassemblyInfo.h"
#include "Console.h"
@ -26,7 +27,7 @@ TraceLogger::~TraceLogger()
template<typename T>
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;
if(rowPart.MinWidth > (int)str.size()) {
output += std::string(rowPart.MinWidth - str.size(), ' ');
@ -94,6 +95,10 @@ void TraceLogger::SetOptions(TraceLoggerOptions options)
part.DataType = RowDataType::X;
} else if(dataType == "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") {
part.DataType = RowDataType::PS;
} else if(dataType == "SP") {
@ -159,8 +164,8 @@ void TraceLogger::GetStatusFlag(string &output, uint8_t ps, RowPart& part)
if(part.DisplayInHex) {
WriteValue(output, ps, part);
} else {
constexpr char activeStatusLetters[8] = { 'N', 'V', 'X', 'M', 'D', 'I', 'Z', 'C' };
constexpr char inactiveStatusLetters[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', 'm', 'x', 'd', 'i', 'z', 'c' };
string flags;
for(int i = 0; i < 8; i++) {
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();
uint32_t pcAddress = (cpuState.K << 16) | cpuState.PC;
for(RowPart& rowPart : _rowParts) {
switch(rowPart.DataType) {
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;
disassemblyInfo.GetDisassembly(code, _memoryManager.get());
disassemblyInfo.GetDisassembly(code, pcAddress);
WriteValue(output, code, rowPart);
break;
}
@ -233,16 +239,18 @@ void TraceLogger::GetTraceRow(string &output, CpuState &cpuState, DisassemblyInf
}
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::X: WriteValue(output, cpuState.X, 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::PS: GetStatusFlag(output, cpuState.PS, rowPart); break;
//case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break;
//case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break;
//case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break;
case RowDataType::CycleCount: WriteValue(output, cpuState.CycleCount, rowPart); break;
case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break;
case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break;
case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break;
case RowDataType::CycleCount: WriteValue(output, (uint32_t)cpuState.CycleCount, rowPart); break;
}
}
output += _options.UseWindowsEol ? "\r\n" : "\n";
@ -269,7 +277,7 @@ void TraceLogger::AddRow(DisassemblyInfo &disassemblyInfo, DebugState &state)
{
_disassemblyCache[_currentPos] = disassemblyInfo;
_cpuStateCache[_currentPos] = state.Cpu;
//_ppuStateCache[_currentPos] = state.PPU;
_ppuStateCache[_currentPos] = state.Ppu;
_pendingLog = false;
if(_logCount < ExecutionLogSize) {
@ -277,7 +285,7 @@ void TraceLogger::AddRow(DisassemblyInfo &disassemblyInfo, DebugState &state)
}
if(_logToFile) {
GetTraceRow(_outputBuffer, state.Cpu, disassemblyInfo);
GetTraceRow(_outputBuffer, state.Cpu, state.Ppu, disassemblyInfo);
if(_outputBuffer.size() > 32768) {
_outputFile << _outputBuffer;
_outputBuffer.clear();
@ -314,7 +322,7 @@ const char* TraceLogger::GetExecutionTrace(uint32_t lineCount)
auto lock = _lock.AcquireSafe();
lineCount = std::min(lineCount, _logCount);
memcpy(_cpuStateCacheCopy, _cpuStateCache, sizeof(_cpuStateCache));
//memcpy(_ppuStateCacheCopy, _ppuStateCache, sizeof(_ppuStateCache));
memcpy(_ppuStateCacheCopy, _ppuStateCache, sizeof(_ppuStateCache));
memcpy(_disassemblyCacheCopy, _disassemblyCache, sizeof(_disassemblyCache));
startPos = _currentPos + ExecutionLogSize - lineCount;
}
@ -325,7 +333,7 @@ const char* TraceLogger::GetExecutionTrace(uint32_t lineCount)
string byteCode;
_disassemblyCacheCopy[index].GetByteCode(byteCode);
_executionTrace += byteCode + "\x1";
GetTraceRow(_executionTrace, _cpuStateCacheCopy[index], _disassemblyCacheCopy[index]);
GetTraceRow(_executionTrace, _cpuStateCacheCopy[index], _ppuStateCacheCopy[index], _disassemblyCacheCopy[index]);
}
return _executionTrace.c_str();

View file

@ -1,6 +1,7 @@
#pragma once
#include "stdafx.h"
#include "CpuTypes.h"
#include "PpuTypes.h"
#include "DisassemblyInfo.h"
#include "../Utilities/SimpleLock.h"
@ -32,6 +33,8 @@ enum class RowDataType
A,
X,
Y,
D,
DB,
SP,
PS,
Cycle,
@ -73,11 +76,11 @@ private:
uint16_t _currentPos;
uint32_t _logCount;
CpuState _cpuStateCache[ExecutionLogSize] = {};
//PPUDebugState _ppuStateCache[ExecutionLogSize] = {};
PpuState _ppuStateCache[ExecutionLogSize] = {};
DisassemblyInfo _disassemblyCache[ExecutionLogSize];
CpuState _cpuStateCacheCopy[ExecutionLogSize] = {};
//PPUDebugState _ppuStateCacheCopy[ExecutionLogSize] = {};
PpuState _ppuStateCacheCopy[ExecutionLogSize] = {};
DisassemblyInfo _disassemblyCacheCopy[ExecutionLogSize];
SimpleLock _lock;
@ -86,7 +89,7 @@ private:
void AddRow(DisassemblyInfo &disassemblyInfo, DebugState &state);
//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);

View file

@ -21,6 +21,7 @@ namespace Mesen.GUI.Debugger
private string _lastFilename;
private EntityBinder _entityBinder = new EntityBinder();
private string _previousTrace;
private UInt64 _previousCycleCount;
private volatile bool _refreshRunning;
private bool _initialized;
@ -161,13 +162,12 @@ namespace Mesen.GUI.Debugger
format += "[Align," + alignValue.ToString() + "] ";
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>()) {
case StatusFlagFormat.Hexadecimal: format += "P:[P,h] "; break;
case StatusFlagFormat.CompactText: format += "P:[P] "; break;
case StatusFlagFormat.Text: format += "P:[P,8] "; break;
}
format += " SP:[SP,h] ";
}
if(chkShowPpuCycles.Checked) {
format += "CYC:[Cycle,3] ";
@ -271,12 +271,10 @@ namespace Mesen.GUI.Debugger
Task.Run(() => {
//Update trace log in another thread for performance
//DebugState state = new DebugState();
//InteropEmu.DebugGetState(ref state);
//if(_previousCycleCount != state.CPU.CycleCount || forceUpdate) {
//TODO
if(true) {
DebugState state = DebugApi.GetState();
if(_previousCycleCount != state.Cpu.CycleCount || forceUpdate) {
string newTrace = DebugApi.GetExecutionTrace((UInt32)_lineCount);
//_previousCycleCount = state.CPU.CycleCount;
_previousCycleCount = state.Cpu.CycleCount;
_previousTrace = newTrace;
int index = 0;
@ -367,7 +365,7 @@ namespace Mesen.GUI.Debugger
}
if(mnuAutoRefresh.Checked) {
RefreshLog(false, false);
RefreshLog(true, false);
}
}

View file

@ -121,12 +121,12 @@
<value>17, 17</value>
</metadata>
<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 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 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>
</root>

View file

@ -32,11 +32,12 @@
this.mnuFile = new System.Windows.Forms.ToolStripMenuItem();
this.mnuOpen = 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.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
this.mnuDebugger = new System.Windows.Forms.ToolStripMenuItem();
this.mnuTraceLogger = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
this.mnuRun = new System.Windows.Forms.ToolStripMenuItem();
this.mnuRun100Instructions = new System.Windows.Forms.ToolStripMenuItem();
this.mnuMain.SuspendLayout();
this.SuspendLayout();
//
@ -70,7 +71,7 @@
//
this.mnuOpen.Image = global::Mesen.GUI.Properties.Resources.Folder;
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.Click += new System.EventHandler(this.mnuOpen_Click);
//
@ -79,6 +80,7 @@
this.debugToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuRun,
this.mnuStep,
this.mnuRun100Instructions,
this.toolStripMenuItem1,
this.mnuDebugger,
this.mnuTraceLogger});
@ -86,38 +88,47 @@
this.debugToolStripMenuItem.Size = new System.Drawing.Size(54, 20);
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
//
this.mnuStep.Name = "mnuStep";
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.Click += new System.EventHandler(this.mnuStep_Click);
//
// toolStripMenuItem1
//
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(154, 6);
//
// 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";
//
// 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.Click += new System.EventHandler(this.mnuTraceLogger_Click);
//
// toolStripMenuItem1
// mnuRun100Instructions
//
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(149, 6);
//
// mnuRun
//
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);
this.mnuRun100Instructions.Name = "mnuRun100Instructions";
this.mnuRun100Instructions.ShortcutKeys = System.Windows.Forms.Keys.F6;
this.mnuRun100Instructions.Size = new System.Drawing.Size(157, 22);
this.mnuRun100Instructions.Text = "Run 100 ops";
this.mnuRun100Instructions.Click += new System.EventHandler(this.mnuRun100Instructions_Click);
//
// frmMain
//
@ -148,5 +159,6 @@
private System.Windows.Forms.ToolStripMenuItem mnuOpen;
private System.Windows.Forms.ToolStripMenuItem mnuRun;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1;
private System.Windows.Forms.ToolStripMenuItem mnuRun100Instructions;
}
}

View file

@ -58,5 +58,10 @@ namespace Mesen.GUI.Forms
{
DebugApi.ResumeExecution();
}
private void mnuRun100Instructions_Click(object sender, EventArgs e)
{
DebugApi.Step(100);
}
}
}

View file

@ -19,7 +19,7 @@ namespace Mesen.GUI
[DllImport(DllPath)] public static extern void ReleaseDebugger();
[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 StopTraceLogger();
@ -27,6 +27,45 @@ namespace Mesen.GUI
[DllImport(DllPath, EntryPoint = "GetExecutionTrace")] private static extern IntPtr GetExecutionTraceWrapper(UInt32 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]