Debugger: Show effective address/memory value in disassembly + update trace logger to use the same code
This commit is contained in:
parent
26e90e90a1
commit
c9eb9cef52
20 changed files with 234 additions and 143 deletions
|
@ -137,7 +137,7 @@ void Console::LoadRom(VirtualFile romFile, VirtualFile patchFile)
|
||||||
|
|
||||||
_memoryManager->Initialize(shared_from_this());
|
_memoryManager->Initialize(shared_from_this());
|
||||||
|
|
||||||
_cpu.reset(new Cpu(_memoryManager));
|
_cpu.reset(new Cpu(_memoryManager.get()));
|
||||||
_memoryManager->IncrementMasterClockValue<160>();
|
_memoryManager->IncrementMasterClockValue<160>();
|
||||||
|
|
||||||
//if(_debugger) {
|
//if(_debugger) {
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
<ClInclude Include="ControlDeviceState.h" />
|
<ClInclude Include="ControlDeviceState.h" />
|
||||||
<ClInclude Include="ControlManager.h" />
|
<ClInclude Include="ControlManager.h" />
|
||||||
<ClInclude Include="Cpu.h" />
|
<ClInclude Include="Cpu.h" />
|
||||||
|
<ClInclude Include="DummyCpu.h" />
|
||||||
<ClInclude Include="ExpressionEvaluator.h" />
|
<ClInclude Include="ExpressionEvaluator.h" />
|
||||||
<ClInclude Include="RegisterHandlerB.h" />
|
<ClInclude Include="RegisterHandlerB.h" />
|
||||||
<ClInclude Include="CpuTypes.h" />
|
<ClInclude Include="CpuTypes.h" />
|
||||||
|
|
|
@ -188,6 +188,9 @@
|
||||||
<ClInclude Include="ExpressionEvaluator.h">
|
<ClInclude Include="ExpressionEvaluator.h">
|
||||||
<Filter>Debugger</Filter>
|
<Filter>Debugger</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="DummyCpu.h">
|
||||||
|
<Filter>Debugger</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="stdafx.cpp" />
|
<ClCompile Include="stdafx.cpp" />
|
||||||
|
|
|
@ -655,6 +655,7 @@ Move operations
|
||||||
****************/
|
****************/
|
||||||
void Cpu::MVN()
|
void Cpu::MVN()
|
||||||
{
|
{
|
||||||
|
#ifndef DUMMYCPU
|
||||||
_state.DBR = _operand & 0xFF;
|
_state.DBR = _operand & 0xFF;
|
||||||
uint32_t destBank = _state.DBR << 16;
|
uint32_t destBank = _state.DBR << 16;
|
||||||
uint32_t srcBank = (_operand << 8) & 0xFF0000;
|
uint32_t srcBank = (_operand << 8) & 0xFF0000;
|
||||||
|
@ -671,15 +672,17 @@ void Cpu::MVN()
|
||||||
|
|
||||||
if(_state.A != 0xFFFF) {
|
if(_state.A != 0xFFFF) {
|
||||||
//"Idle" cycles, instruction re-reads OP code and operands before every new byte
|
//"Idle" cycles, instruction re-reads OP code and operands before every new byte
|
||||||
_memoryManager->Read((_state.K << 16) | (_state.PC - 3), MemoryOperationType::Read);
|
Read((_state.K << 16) | (_state.PC - 3), MemoryOperationType::Read);
|
||||||
_memoryManager->Read((_state.K << 16) | (_state.PC - 2), MemoryOperationType::Read);
|
Read((_state.K << 16) | (_state.PC - 2), MemoryOperationType::Read);
|
||||||
_memoryManager->Read((_state.K << 16) | (_state.PC - 1), MemoryOperationType::Read);
|
Read((_state.K << 16) | (_state.PC - 1), MemoryOperationType::Read);
|
||||||
}
|
}
|
||||||
} while(_state.A != 0xFFFF);
|
} while(_state.A != 0xFFFF);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cpu::MVP()
|
void Cpu::MVP()
|
||||||
{
|
{
|
||||||
|
#ifndef DUMMYCPU
|
||||||
_state.DBR = _operand & 0xFF;
|
_state.DBR = _operand & 0xFF;
|
||||||
uint32_t destBank = _state.DBR << 16;
|
uint32_t destBank = _state.DBR << 16;
|
||||||
uint32_t srcBank = (_operand << 8) & 0xFF0000;
|
uint32_t srcBank = (_operand << 8) & 0xFF0000;
|
||||||
|
@ -696,11 +699,12 @@ void Cpu::MVP()
|
||||||
|
|
||||||
if(_state.A != 0xFFFF) {
|
if(_state.A != 0xFFFF) {
|
||||||
//"Idle" cycles, instruction re-reads OP code and operands before every new byte
|
//"Idle" cycles, instruction re-reads OP code and operands before every new byte
|
||||||
_memoryManager->Read((_state.K << 16) | (_state.PC - 3), MemoryOperationType::Read);
|
Read((_state.K << 16) | (_state.PC - 3), MemoryOperationType::Read);
|
||||||
_memoryManager->Read((_state.K << 16) | (_state.PC - 2), MemoryOperationType::Read);
|
Read((_state.K << 16) | (_state.PC - 2), MemoryOperationType::Read);
|
||||||
_memoryManager->Read((_state.K << 16) | (_state.PC - 1), MemoryOperationType::Read);
|
Read((_state.K << 16) | (_state.PC - 1), MemoryOperationType::Read);
|
||||||
}
|
}
|
||||||
} while(_state.A != 0xFFFF);
|
} while(_state.A != 0xFFFF);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************
|
/********************
|
||||||
|
|
28
Core/Cpu.cpp
28
Core/Cpu.cpp
|
@ -3,7 +3,7 @@
|
||||||
#include "Cpu.h"
|
#include "Cpu.h"
|
||||||
#include "MemoryManager.h"
|
#include "MemoryManager.h"
|
||||||
|
|
||||||
Cpu::Cpu(shared_ptr<MemoryManager> memoryManager)
|
Cpu::Cpu(MemoryManager* memoryManager)
|
||||||
{
|
{
|
||||||
_memoryManager = memoryManager;
|
_memoryManager = memoryManager;
|
||||||
_state = {};
|
_state = {};
|
||||||
|
@ -338,7 +338,9 @@ uint8_t Cpu::GetOpCode()
|
||||||
|
|
||||||
void Cpu::Idle()
|
void Cpu::Idle()
|
||||||
{
|
{
|
||||||
|
#ifndef DUMMYCPU
|
||||||
_memoryManager->IncrementMasterClockValue<6>();
|
_memoryManager->IncrementMasterClockValue<6>();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t Cpu::ReadOperandByte()
|
uint8_t Cpu::ReadOperandByte()
|
||||||
|
@ -361,10 +363,22 @@ uint32_t Cpu::ReadOperandLong()
|
||||||
return (b3 << 16) | (b2 << 8) | b1;
|
return (b3 << 16) | (b2 << 8) | b1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t Cpu::ReadCode(uint16_t addr, MemoryOperationType type)
|
uint8_t Cpu::Read(uint32_t addr, MemoryOperationType type)
|
||||||
{
|
{
|
||||||
_state.CycleCount++;
|
_state.CycleCount++;
|
||||||
return _memoryManager->Read((_state.K << 16) | addr, type);
|
|
||||||
|
#ifdef DUMMYCPU
|
||||||
|
uint8_t value = _memoryManager->Peek(addr);
|
||||||
|
LogRead(addr, value);
|
||||||
|
return value;
|
||||||
|
#else
|
||||||
|
return _memoryManager->Read(addr, type);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Cpu::ReadCode(uint16_t addr, MemoryOperationType type)
|
||||||
|
{
|
||||||
|
return Read((_state.K << 16) | addr, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t Cpu::ReadCodeWord(uint16_t addr, MemoryOperationType type)
|
uint16_t Cpu::ReadCodeWord(uint16_t addr, MemoryOperationType type)
|
||||||
|
@ -376,8 +390,7 @@ uint16_t Cpu::ReadCodeWord(uint16_t addr, MemoryOperationType type)
|
||||||
|
|
||||||
uint8_t Cpu::ReadData(uint32_t addr, MemoryOperationType type)
|
uint8_t Cpu::ReadData(uint32_t addr, MemoryOperationType type)
|
||||||
{
|
{
|
||||||
_state.CycleCount++;
|
return Read(addr & 0xFFFFFF, type);
|
||||||
return _memoryManager->Read(addr & 0xFFFFFF, type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t Cpu::ReadDataWord(uint32_t addr, MemoryOperationType type)
|
uint16_t Cpu::ReadDataWord(uint32_t addr, MemoryOperationType type)
|
||||||
|
@ -398,7 +411,12 @@ uint32_t Cpu::ReadDataLong(uint32_t addr, MemoryOperationType type)
|
||||||
void Cpu::Write(uint32_t addr, uint8_t value, MemoryOperationType type)
|
void Cpu::Write(uint32_t addr, uint8_t value, MemoryOperationType type)
|
||||||
{
|
{
|
||||||
_state.CycleCount++;
|
_state.CycleCount++;
|
||||||
|
|
||||||
|
#ifdef DUMMYCPU
|
||||||
|
LogWrite(addr, value);
|
||||||
|
#else
|
||||||
_memoryManager->Write(addr, value, type);
|
_memoryManager->Write(addr, value, type);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cpu::WriteWord(uint32_t addr, uint16_t value, MemoryOperationType type)
|
void Cpu::WriteWord(uint32_t addr, uint16_t value, MemoryOperationType type)
|
||||||
|
|
40
Core/Cpu.h
40
Core/Cpu.h
|
@ -1,4 +1,10 @@
|
||||||
#pragma once
|
#if (defined(DUMMYCPU) && !defined(__DUMMYCPU__H)) || (!defined(DUMMYCPU) && !defined(__CPU__H))
|
||||||
|
#ifdef DUMMYCPU
|
||||||
|
#define __DUMMYCPU__H
|
||||||
|
#else
|
||||||
|
#define __CPU__H
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "CpuTypes.h"
|
#include "CpuTypes.h"
|
||||||
|
|
||||||
|
@ -25,7 +31,7 @@ private:
|
||||||
|
|
||||||
typedef void(Cpu::*Func)();
|
typedef void(Cpu::*Func)();
|
||||||
|
|
||||||
shared_ptr<MemoryManager> _memoryManager;
|
MemoryManager* _memoryManager;
|
||||||
|
|
||||||
bool _immediateMode = false;
|
bool _immediateMode = false;
|
||||||
|
|
||||||
|
@ -53,6 +59,8 @@ private:
|
||||||
uint16_t ReadOperandWord();
|
uint16_t ReadOperandWord();
|
||||||
uint32_t ReadOperandLong();
|
uint32_t ReadOperandLong();
|
||||||
|
|
||||||
|
uint8_t Read(uint32_t addr, MemoryOperationType type);
|
||||||
|
|
||||||
void SetSP(uint16_t sp);
|
void SetSP(uint16_t sp);
|
||||||
void SetPS(uint8_t ps);
|
void SetPS(uint8_t ps);
|
||||||
|
|
||||||
|
@ -285,7 +293,7 @@ private:
|
||||||
void AddrMode_StkRelIndIdxY();
|
void AddrMode_StkRelIndIdxY();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Cpu(shared_ptr<MemoryManager> memoryManager);
|
Cpu(MemoryManager* memoryManager);
|
||||||
~Cpu();
|
~Cpu();
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
|
@ -295,4 +303,30 @@ public:
|
||||||
void SetIrqSource(IrqSource source);
|
void SetIrqSource(IrqSource source);
|
||||||
bool CheckIrqSource(IrqSource source);
|
bool CheckIrqSource(IrqSource source);
|
||||||
void ClearIrqSource(IrqSource source);
|
void ClearIrqSource(IrqSource source);
|
||||||
|
|
||||||
|
#ifdef DUMMYCPU
|
||||||
|
private:
|
||||||
|
uint32_t _writeCounter = 0;
|
||||||
|
uint32_t _writeAddresses[10];
|
||||||
|
uint8_t _writeValue[10];
|
||||||
|
|
||||||
|
uint32_t _readCounter = 0;
|
||||||
|
uint32_t _readAddresses[10];
|
||||||
|
uint8_t _readValue[10];
|
||||||
|
|
||||||
|
uint32_t _valueSize = 0;
|
||||||
|
|
||||||
|
void LogRead(uint32_t addr, uint8_t value);
|
||||||
|
void LogWrite(uint32_t addr, uint8_t value);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void SetDummyState(CpuState &state);
|
||||||
|
|
||||||
|
uint32_t GetWriteCount();
|
||||||
|
uint32_t GetReadCount();
|
||||||
|
void GetWriteInfo(uint32_t index, uint32_t &addr, uint8_t &value);
|
||||||
|
void GetReadInfo(uint32_t index, uint32_t &addr, uint8_t &value);
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -107,7 +107,8 @@ struct CodeLineData
|
||||||
uint8_t Flags;
|
uint8_t Flags;
|
||||||
|
|
||||||
int32_t EffectiveAddress;
|
int32_t EffectiveAddress;
|
||||||
int32_t Value;
|
uint16_t Value;
|
||||||
|
uint8_t ValueSize;
|
||||||
|
|
||||||
uint8_t ByteCode[4];
|
uint8_t ByteCode[4];
|
||||||
char Text[1000];
|
char Text[1000];
|
||||||
|
|
|
@ -71,7 +71,6 @@ void Debugger::ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType
|
||||||
|
|
||||||
DebugState debugState;
|
DebugState debugState;
|
||||||
GetState(&debugState);
|
GetState(&debugState);
|
||||||
_traceLogger->LogEffectiveAddress(_cpu->GetLastOperand());
|
|
||||||
|
|
||||||
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo);
|
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo);
|
||||||
_traceLogger->Log(debugState, disInfo);
|
_traceLogger->Log(debugState, disInfo);
|
||||||
|
|
|
@ -236,8 +236,12 @@ bool Disassembler::GetLineData(uint32_t lineIndex, CodeLineData &data)
|
||||||
GetSource(result.Address, &source, sourceLength, &cache);
|
GetSource(result.Address, &source, sourceLength, &cache);
|
||||||
disInfo = (*cache)[result.Address.Address];
|
disInfo = (*cache)[result.Address.Address];
|
||||||
|
|
||||||
|
CpuState state = _console->GetCpu()->GetState();
|
||||||
|
state.PC = (uint16_t)result.CpuAddress;
|
||||||
|
state.K = (result.CpuAddress >> 16);
|
||||||
|
|
||||||
if(!disInfo) {
|
if(!disInfo) {
|
||||||
disInfo.reset(new DisassemblyInfo(source + result.Address.Address, 0));
|
disInfo.reset(new DisassemblyInfo(source + result.Address.Address, state.PS));
|
||||||
} else {
|
} else {
|
||||||
data.Flags |= (uint8_t)LineFlags::VerifiedCode;
|
data.Flags |= (uint8_t)LineFlags::VerifiedCode;
|
||||||
}
|
}
|
||||||
|
@ -247,8 +251,14 @@ bool Disassembler::GetLineData(uint32_t lineIndex, CodeLineData &data)
|
||||||
memcpy(data.Text, text.c_str(), std::min<int>((int)text.size(), 1000));
|
memcpy(data.Text, text.c_str(), std::min<int>((int)text.size(), 1000));
|
||||||
|
|
||||||
data.OpSize = disInfo->GetOperandSize() + 1;
|
data.OpSize = disInfo->GetOperandSize() + 1;
|
||||||
data.EffectiveAddress = disInfo->GetEffectiveAddress();
|
|
||||||
data.Value = _memoryManager->Peek(result.CpuAddress);
|
MemoryManager *memoryManager = _console->GetMemoryManager().get();
|
||||||
|
data.EffectiveAddress = disInfo->GetEffectiveAddress(state, memoryManager);
|
||||||
|
if(data.EffectiveAddress >= 0) {
|
||||||
|
data.Value = disInfo->GetMemoryValue(data.EffectiveAddress, memoryManager, data.ValueSize);
|
||||||
|
} else {
|
||||||
|
data.ValueSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
disInfo->GetByteCode(data.ByteCode);
|
disInfo->GetByteCode(data.ByteCode);
|
||||||
data.Comment[0] = 0;
|
data.Comment[0] = 0;
|
||||||
|
@ -266,7 +276,7 @@ bool Disassembler::GetLineData(uint32_t lineIndex, CodeLineData &data)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t Disassembler::SearchCode(const char *searchString, int32_t startPosition, int32_t endPosition, bool searchBackwards)
|
int32_t Disassembler::SearchDisassembly(const char *searchString, int32_t startPosition, int32_t endPosition, bool searchBackwards)
|
||||||
{
|
{
|
||||||
auto lock = _disassemblyLock.AcquireSafe();
|
auto lock = _disassemblyLock.AcquireSafe();
|
||||||
int step = searchBackwards ? -1 : 1;
|
int step = searchBackwards ? -1 : 1;
|
||||||
|
|
|
@ -46,5 +46,5 @@ public:
|
||||||
uint32_t GetLineCount();
|
uint32_t GetLineCount();
|
||||||
uint32_t GetLineIndex(uint32_t cpuAddress);
|
uint32_t GetLineIndex(uint32_t cpuAddress);
|
||||||
bool GetLineData(uint32_t lineIndex, CodeLineData &data);
|
bool GetLineData(uint32_t lineIndex, CodeLineData &data);
|
||||||
int32_t SearchCode(const char* searchString, int32_t startPosition, int32_t endPosition, bool searchBackwards);
|
int32_t SearchDisassembly(const char* searchString, int32_t startPosition, int32_t endPosition, bool searchBackwards);
|
||||||
};
|
};
|
|
@ -3,6 +3,7 @@
|
||||||
#include "DisassemblyInfo.h"
|
#include "DisassemblyInfo.h"
|
||||||
#include "CpuTypes.h"
|
#include "CpuTypes.h"
|
||||||
#include "MemoryManager.h"
|
#include "MemoryManager.h"
|
||||||
|
#include "DummyCpu.h"
|
||||||
#include "../Utilities/HexUtilities.h"
|
#include "../Utilities/HexUtilities.h"
|
||||||
#include "../Utilities/FastString.h"
|
#include "../Utilities/FastString.h"
|
||||||
|
|
||||||
|
@ -17,8 +18,7 @@ DisassemblyInfo::DisassemblyInfo(uint8_t *opPointer, uint8_t cpuFlags)
|
||||||
|
|
||||||
void DisassemblyInfo::Initialize(uint8_t *opPointer, uint8_t cpuFlags)
|
void DisassemblyInfo::Initialize(uint8_t *opPointer, uint8_t cpuFlags)
|
||||||
{
|
{
|
||||||
_flags = cpuFlags;
|
_flags = cpuFlags & (ProcFlags::MemoryMode8 | ProcFlags::IndexMode8);
|
||||||
_effectiveAddress = -1;
|
|
||||||
|
|
||||||
_byteCode[0] = opPointer[0];
|
_byteCode[0] = opPointer[0];
|
||||||
_addrMode = DisassemblyInfo::OpMode[_byteCode[0]];
|
_addrMode = DisassemblyInfo::OpMode[_byteCode[0]];
|
||||||
|
@ -55,7 +55,7 @@ void DisassemblyInfo::GetDisassembly(string &out, uint32_t memoryAddr)
|
||||||
case AddrMode::AbsLng: str.Write(operand); break;
|
case AddrMode::AbsLng: str.Write(operand); break;
|
||||||
case AddrMode::AbsLngJmp: str.Write(operand); break;
|
case AddrMode::AbsLngJmp: str.Write(operand); break;
|
||||||
case AddrMode::Acc: break;
|
case AddrMode::Acc: break;
|
||||||
case AddrMode::BlkMov: str.Write(operand[1], operand[2], " -> "); str.Write(operand[3], operand[4]); break;
|
case AddrMode::BlkMov: str.Write('$', operand[1], operand[2], " -> "); str.Write('$', operand[3], operand[4]); break;
|
||||||
case AddrMode::DirIdxIndX: str.Write('(', operand, ",X)"); break;
|
case AddrMode::DirIdxIndX: str.Write('(', operand, ",X)"); break;
|
||||||
case AddrMode::DirIdxX: str.Write(operand, ",X"); break;
|
case AddrMode::DirIdxX: str.Write(operand, ",X"); break;
|
||||||
case AddrMode::DirIdxY: str.Write(operand, ",Y"); break;
|
case AddrMode::DirIdxY: str.Write(operand, ",Y"); break;
|
||||||
|
@ -177,76 +177,36 @@ void DisassemblyInfo::GetByteCode(string &out)
|
||||||
out += str.ToString();
|
out += str.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisassemblyInfo::GetEffectiveAddressString(string &out)
|
void DisassemblyInfo::GetEffectiveAddressString(string &out, CpuState &state, MemoryManager* memoryManager)
|
||||||
{
|
{
|
||||||
int32_t effectiveAddress = GetEffectiveAddress();
|
int32_t effectiveAddress = GetEffectiveAddress(state, memoryManager);
|
||||||
if(effectiveAddress >= 0) {
|
if(effectiveAddress >= 0) {
|
||||||
out += " [" + HexUtilities::ToHex24(effectiveAddress) + "]";
|
out += " [" + HexUtilities::ToHex24(effectiveAddress) + "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisassemblyInfo::SetEffectiveAddress(int32_t effectiveAddress)
|
int32_t DisassemblyInfo::GetEffectiveAddress(CpuState &state, MemoryManager *memoryManager)
|
||||||
{
|
{
|
||||||
_effectiveAddress = effectiveAddress;
|
if(_addrMode > AddrMode::ImmM && _addrMode != AddrMode::Acc && _addrMode != AddrMode::Imp && _addrMode != AddrMode::Stk && _addrMode != AddrMode::Rel && _addrMode != AddrMode::RelLng && _addrMode != AddrMode::BlkMov) {
|
||||||
}
|
DummyCpu cpu(memoryManager);
|
||||||
|
state.PS &= ~(ProcFlags::IndexMode8 | ProcFlags::MemoryMode8);
|
||||||
int32_t DisassemblyInfo::GetEffectiveAddress()
|
state.PS |= _flags;
|
||||||
{
|
cpu.SetDummyState(state);
|
||||||
if(_addrMode > AddrMode::ImmM && _addrMode != AddrMode::Acc && _addrMode != AddrMode::Imp && _addrMode != AddrMode::Stk) {
|
cpu.Exec();
|
||||||
return _effectiveAddress;
|
return cpu.GetLastOperand();
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/*auto getProgramAddress = [&state](uint16_t addr) { return (state.K << 16) | addr; };
|
uint16_t DisassemblyInfo::GetMemoryValue(uint32_t effectiveAddress, MemoryManager *memoryManager, uint8_t &valueSize)
|
||||||
auto getDataAddress = [&state](uint16_t addr) { return (state.DBR << 16) | addr; };
|
{
|
||||||
auto getDirectAddress = [&state](uint8_t baseAddress, uint16_t offset = 0, bool allowEmulationMode = true) {
|
if(_flags & ProcFlags::MemoryMode8) {
|
||||||
if(allowEmulationMode && state.EmulationMode && (state.D & 0xFF) == 0) {
|
valueSize = 1;
|
||||||
//TODO: Check if new instruction or not (PEI)
|
return memoryManager->Peek(effectiveAddress);
|
||||||
return (uint16_t)((state.D & 0xFF00) | ((baseAddress + offset) & 0xFF));
|
|
||||||
} else {
|
} else {
|
||||||
return (uint16_t)(state.D + baseAddress + offset);
|
valueSize = 2;
|
||||||
|
return memoryManager->PeekWord(effectiveAddress);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
auto getDirectAddressIndirectWord = [&state, mm, &getDirectAddress](uint8_t baseAddress, uint16_t offset = 0, bool allowEmulationMode = true) {
|
|
||||||
uint8_t b1 = mm->Peek(getDirectAddress(baseAddress, offset + 0));
|
|
||||||
uint8_t b2 = mm->Peek(getDirectAddress(baseAddress, offset + 1));
|
|
||||||
return (b2 << 8) | b1;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto getDirectAddressIndirectLong = [&state, mm, &getDirectAddress](uint8_t baseAddress, uint16_t offset = 0, bool allowEmulationMode = true) {
|
|
||||||
uint8_t b1 = mm->Peek(getDirectAddress(baseAddress, offset + 0));
|
|
||||||
uint8_t b2 = mm->Peek(getDirectAddress(baseAddress, offset + 1));
|
|
||||||
uint8_t b3 = mm->Peek(getDirectAddress(baseAddress, offset + 2));
|
|
||||||
return (b3 << 16) | (b2 << 8) | b1;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
uint32_t bank = (state.K << 16);
|
|
||||||
uint32_t opAddr = GetOperandAddress(bank | state.PC);
|
|
||||||
switch(_addrMode) {
|
|
||||||
case AddrMode::AbsIdxX: return opAddr + state.X;
|
|
||||||
case AddrMode::AbsIdxY: return opAddr + state.Y;
|
|
||||||
case AddrMode::AbsLngIdxX: return opAddr + state.X;
|
|
||||||
case AddrMode::AbsIdxXInd: return getProgramAddress(mm->PeekWord(getProgramAddress(opAddr + state.X)));
|
|
||||||
case AddrMode::AbsInd: return getProgramAddress(mm->PeekWord(opAddr));
|
|
||||||
case AddrMode::AbsIndLng: return mm->PeekLong(opAddr);
|
|
||||||
|
|
||||||
case AddrMode::BlkMov: break; //TODO
|
|
||||||
|
|
||||||
case AddrMode::Dir: return getDirectAddress(opAddr);
|
|
||||||
case AddrMode::DirIdxX: return getDirectAddress(opAddr, state.X);
|
|
||||||
case AddrMode::DirIdxY: return getDirectAddress(opAddr, state.Y);
|
|
||||||
|
|
||||||
case AddrMode::DirInd: return getDirectAddressIndirectWord(opAddr);
|
|
||||||
case AddrMode::DirIdxIndX: return getDirectAddressIndirectWord(opAddr, state.X);
|
|
||||||
case AddrMode::DirIndIdxY: return getDirectAddressIndirectWord(opAddr) + state.Y;
|
|
||||||
case AddrMode::DirIndLng: return getDirectAddressIndirectLong(opAddr);
|
|
||||||
case AddrMode::DirIndLngIdxY: return getDirectAddressIndirectLong(opAddr) + state.Y;
|
|
||||||
|
|
||||||
case AddrMode::StkRel: return opAddr + state.SP;
|
|
||||||
case AddrMode::StkRelIndIdxY: break;
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string DisassemblyInfo::OpName[256] = {
|
string DisassemblyInfo::OpName[256] = {
|
||||||
|
|
|
@ -19,7 +19,6 @@ private:
|
||||||
uint8_t _opSize;
|
uint8_t _opSize;
|
||||||
AddrMode _addrMode;
|
AddrMode _addrMode;
|
||||||
uint8_t _flags;
|
uint8_t _flags;
|
||||||
int32_t _effectiveAddress;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DisassemblyInfo();
|
DisassemblyInfo();
|
||||||
|
@ -37,13 +36,8 @@ public:
|
||||||
void GetByteCode(uint8_t copyBuffer[4]);
|
void GetByteCode(uint8_t copyBuffer[4]);
|
||||||
void GetByteCode(string &out);
|
void GetByteCode(string &out);
|
||||||
|
|
||||||
void SetEffectiveAddress(int32_t effectiveAddress);
|
void GetEffectiveAddressString(string &out, CpuState &state, MemoryManager* memoryManager);
|
||||||
void GetEffectiveAddressString(string &out);
|
int32_t GetEffectiveAddress(CpuState &state, MemoryManager *memoryManager);
|
||||||
int32_t GetEffectiveAddress();
|
uint16_t GetMemoryValue(uint32_t effectiveAddress, MemoryManager *memoryManager, uint8_t &valueSize);
|
||||||
|
|
||||||
/*int32_t GetMemoryValue(CpuState& cpuState, MemoryManager* memoryManager);
|
|
||||||
uint16_t GetJumpDestination(uint16_t pc, MemoryManager* memoryManager);
|
|
||||||
uint16_t GetIndirectJumpDestination(MemoryManager* memoryManager);
|
|
||||||
*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
55
Core/DummyCpu.h
Normal file
55
Core/DummyCpu.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
#define DUMMYCPU
|
||||||
|
#define Cpu DummyCpu
|
||||||
|
#include "Cpu.h"
|
||||||
|
#include "Cpu.cpp"
|
||||||
|
#include "Cpu.Instructions.cpp"
|
||||||
|
#undef Cpu
|
||||||
|
#undef DUMMYCPU
|
||||||
|
|
||||||
|
void DummyCpu::SetDummyState(CpuState &state)
|
||||||
|
{
|
||||||
|
_state = state;
|
||||||
|
|
||||||
|
_writeCounter = 0;
|
||||||
|
_readCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DummyCpu::GetWriteCount()
|
||||||
|
{
|
||||||
|
return _writeCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DummyCpu::GetReadCount()
|
||||||
|
{
|
||||||
|
return _readCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DummyCpu::LogRead(uint32_t addr, uint8_t value)
|
||||||
|
{
|
||||||
|
_readAddresses[_readCounter] = addr;
|
||||||
|
_readValue[_readCounter] = value;
|
||||||
|
_readCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DummyCpu::LogWrite(uint32_t addr, uint8_t value)
|
||||||
|
{
|
||||||
|
_writeAddresses[_writeCounter] = addr;
|
||||||
|
_writeValue[_writeCounter] = value;
|
||||||
|
_writeCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DummyCpu::GetWriteInfo(uint32_t index, uint32_t &addr, uint8_t &value)
|
||||||
|
{
|
||||||
|
addr = _writeAddresses[index];
|
||||||
|
value = _writeValue[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void DummyCpu::GetReadInfo(uint32_t index, uint32_t &addr, uint8_t &value)
|
||||||
|
{
|
||||||
|
addr = _readAddresses[index];
|
||||||
|
value = _readValue[index];
|
||||||
|
}
|
|
@ -185,6 +185,13 @@ uint8_t MemoryManager::Peek(uint32_t addr)
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t MemoryManager::PeekWord(uint32_t addr)
|
||||||
|
{
|
||||||
|
uint8_t lsb = Peek(addr);
|
||||||
|
uint8_t msb = Peek((addr + 1) & 0xFFFFFF);
|
||||||
|
return (msb << 8) | lsb;
|
||||||
|
}
|
||||||
|
|
||||||
void MemoryManager::Write(uint32_t addr, uint8_t value, MemoryOperationType type)
|
void MemoryManager::Write(uint32_t addr, uint8_t value, MemoryOperationType type)
|
||||||
{
|
{
|
||||||
IncrementMasterClock(addr);
|
IncrementMasterClock(addr);
|
||||||
|
|
|
@ -51,6 +51,7 @@ public:
|
||||||
uint8_t Read(uint32_t addr, MemoryOperationType type);
|
uint8_t Read(uint32_t addr, MemoryOperationType type);
|
||||||
uint8_t ReadDma(uint32_t addr);
|
uint8_t ReadDma(uint32_t addr);
|
||||||
uint8_t Peek(uint32_t addr);
|
uint8_t Peek(uint32_t addr);
|
||||||
|
uint16_t PeekWord(uint32_t addr);
|
||||||
|
|
||||||
void Write(uint32_t addr, uint8_t value, MemoryOperationType type);
|
void Write(uint32_t addr, uint8_t value, MemoryOperationType type);
|
||||||
void WriteDma(uint32_t addr, uint8_t value);
|
void WriteDma(uint32_t addr, uint8_t value);
|
||||||
|
|
|
@ -218,18 +218,28 @@ void TraceLogger::GetTraceRow(string &output, CpuState &cpuState, PpuState &ppuS
|
||||||
case RowDataType::EffectiveAddress:
|
case RowDataType::EffectiveAddress:
|
||||||
{
|
{
|
||||||
string effectiveAddress;
|
string effectiveAddress;
|
||||||
disassemblyInfo.GetEffectiveAddressString(effectiveAddress);
|
disassemblyInfo.GetEffectiveAddressString(effectiveAddress, cpuState, _memoryManager.get());
|
||||||
WriteValue(output, effectiveAddress, rowPart);
|
WriteValue(output, effectiveAddress, rowPart);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RowDataType::MemoryValue:
|
case RowDataType::MemoryValue:
|
||||||
{
|
{
|
||||||
/*int32_t value = disassemblyInfo.GetMemoryValue(cpuState, _memoryManager.get());
|
int32_t address = disassemblyInfo.GetEffectiveAddress(cpuState, _memoryManager.get());
|
||||||
if(value >= 0) {
|
if(address >= 0) {
|
||||||
output += rowPart.DisplayInHex ? "= $" : "= ";
|
uint8_t valueSize;
|
||||||
|
uint16_t value = disassemblyInfo.GetMemoryValue(address, _memoryManager.get(), valueSize);
|
||||||
|
if(rowPart.DisplayInHex) {
|
||||||
|
output += "= $";
|
||||||
|
if(valueSize == 2) {
|
||||||
|
WriteValue(output, (uint16_t)value, rowPart);
|
||||||
|
} else {
|
||||||
WriteValue(output, (uint8_t)value, rowPart);
|
WriteValue(output, (uint8_t)value, rowPart);
|
||||||
}*/
|
}
|
||||||
|
} else {
|
||||||
|
output += "= ";
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,6 +294,14 @@ void TraceLogger::AddRow(DisassemblyInfo &disassemblyInfo, DebugState &state)
|
||||||
_logCount++;
|
_logCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(_logToFile) {
|
||||||
|
GetTraceRow(_outputBuffer, _cpuStateCache[_currentPos], _ppuStateCache[_currentPos], _disassemblyCache[_currentPos]);
|
||||||
|
if(_outputBuffer.size() > 32768) {
|
||||||
|
_outputFile << _outputBuffer;
|
||||||
|
_outputBuffer.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_currentPos = (_currentPos + 1) % ExecutionLogSize;
|
_currentPos = (_currentPos + 1) % ExecutionLogSize;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -297,25 +315,6 @@ void TraceLogger::LogNonExec(OperationInfo& operationInfo)
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
void TraceLogger::LogEffectiveAddress(uint32_t effectiveAddress)
|
|
||||||
{
|
|
||||||
uint32_t pos;
|
|
||||||
if(_currentPos > 0) {
|
|
||||||
pos = _currentPos - 1;
|
|
||||||
} else {
|
|
||||||
pos = ExecutionLogSize - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
_disassemblyCache[pos].SetEffectiveAddress(effectiveAddress);
|
|
||||||
if(_logToFile) {
|
|
||||||
GetTraceRow(_outputBuffer, _cpuStateCache[pos], _ppuStateCache[pos], _disassemblyCache[pos]);
|
|
||||||
if(_outputBuffer.size() > 32768) {
|
|
||||||
_outputFile << _outputBuffer;
|
|
||||||
_outputBuffer.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TraceLogger::Log(DebugState &state, DisassemblyInfo &disassemblyInfo)
|
void TraceLogger::Log(DebugState &state, DisassemblyInfo &disassemblyInfo)
|
||||||
{
|
{
|
||||||
auto lock = _lock.AcquireSafe();
|
auto lock = _lock.AcquireSafe();
|
||||||
|
|
|
@ -97,8 +97,6 @@ public:
|
||||||
TraceLogger(Debugger* debugger, shared_ptr<MemoryManager> memoryManager);
|
TraceLogger(Debugger* debugger, shared_ptr<MemoryManager> memoryManager);
|
||||||
~TraceLogger();
|
~TraceLogger();
|
||||||
|
|
||||||
void LogEffectiveAddress(uint32_t effectiveAddress);
|
|
||||||
|
|
||||||
void Log(DebugState &state, DisassemblyInfo &disassemblyInfo);
|
void Log(DebugState &state, DisassemblyInfo &disassemblyInfo);
|
||||||
//void LogNonExec(OperationInfo& operationInfo);
|
//void LogNonExec(OperationInfo& operationInfo);
|
||||||
void SetOptions(TraceLoggerOptions options);
|
void SetOptions(TraceLoggerOptions options);
|
||||||
|
|
|
@ -39,7 +39,7 @@ extern "C"
|
||||||
DllExport void __stdcall GetDisassemblyLineData(uint32_t lineIndex, CodeLineData &data) { GetDebugger()->GetDisassembler()->GetLineData(lineIndex, data); }
|
DllExport void __stdcall GetDisassemblyLineData(uint32_t lineIndex, CodeLineData &data) { GetDebugger()->GetDisassembler()->GetLineData(lineIndex, data); }
|
||||||
DllExport uint32_t __stdcall GetDisassemblyLineCount() { return GetDebugger()->GetDisassembler()->GetLineCount(); }
|
DllExport uint32_t __stdcall GetDisassemblyLineCount() { return GetDebugger()->GetDisassembler()->GetLineCount(); }
|
||||||
DllExport uint32_t __stdcall GetDisassemblyLineIndex(uint32_t cpuAddress) { return GetDebugger()->GetDisassembler()->GetLineIndex(cpuAddress); }
|
DllExport uint32_t __stdcall GetDisassemblyLineIndex(uint32_t cpuAddress) { return GetDebugger()->GetDisassembler()->GetLineIndex(cpuAddress); }
|
||||||
DllExport int32_t __stdcall SearchDisassembly(const char* searchString, int32_t startPosition, int32_t endPosition, bool searchBackwards) { return GetDebugger()->GetDisassembler()->SearchCode(searchString, startPosition, endPosition, searchBackwards); }
|
DllExport int32_t __stdcall SearchDisassembly(const char* searchString, int32_t startPosition, int32_t endPosition, bool searchBackwards) { return GetDebugger()->GetDisassembler()->SearchDisassembly(searchString, startPosition, endPosition, searchBackwards); }
|
||||||
|
|
||||||
DllExport void __stdcall SetTraceOptions(TraceLoggerOptions options) { GetDebugger()->GetTraceLogger()->SetOptions(options); }
|
DllExport void __stdcall SetTraceOptions(TraceLoggerOptions options) { GetDebugger()->GetTraceLogger()->SetOptions(options); }
|
||||||
DllExport void __stdcall StartTraceLogger(char* filename) { GetDebugger()->GetTraceLogger()->StartLogging(filename); }
|
DllExport void __stdcall StartTraceLogger(char* filename) { GetDebugger()->GetTraceLogger()->StartLogging(filename); }
|
||||||
|
|
|
@ -21,11 +21,27 @@ namespace Mesen.GUI.Debugger
|
||||||
public string Comment;
|
public string Comment;
|
||||||
|
|
||||||
public Int32 EffectiveAddress;
|
public Int32 EffectiveAddress;
|
||||||
public Int32 Value;
|
public UInt16 Value;
|
||||||
|
public byte ValueSize;
|
||||||
|
|
||||||
public string GetEffectiveAddressString()
|
public string GetEffectiveAddressString()
|
||||||
{
|
{
|
||||||
|
if(EffectiveAddress >= 0) {
|
||||||
return "[" + EffectiveAddress.ToString("X6") + "]";
|
return "[" + EffectiveAddress.ToString("X6") + "]";
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetValueString()
|
||||||
|
{
|
||||||
|
if(ValueSize == 1) {
|
||||||
|
return " = $" + Value.ToString("X2");
|
||||||
|
} else if(ValueSize == 2) {
|
||||||
|
return " = $" + Value.ToString("X4");
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Indentation
|
public int Indentation
|
||||||
|
@ -58,6 +74,7 @@ namespace Mesen.GUI.Debugger
|
||||||
this.EffectiveAddress = data.EffectiveAddress;
|
this.EffectiveAddress = data.EffectiveAddress;
|
||||||
this.Flags = (LineFlags)data.Flags;
|
this.Flags = (LineFlags)data.Flags;
|
||||||
this.Value = data.Value;
|
this.Value = data.Value;
|
||||||
|
this.ValueSize = data.ValueSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ConvertString(byte[] stringArray)
|
private string ConvertString(byte[] stringArray)
|
||||||
|
@ -81,7 +98,8 @@ namespace Mesen.GUI.Debugger
|
||||||
public byte Flags;
|
public byte Flags;
|
||||||
|
|
||||||
public Int32 EffectiveAddress;
|
public Int32 EffectiveAddress;
|
||||||
public Int32 Value;
|
public UInt16 Value;
|
||||||
|
public byte ValueSize;
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||||
public byte[] ByteCode;
|
public byte[] ByteCode;
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace Mesen.GUI.Debugger.Controls
|
||||||
{
|
{
|
||||||
public partial class ctrlTextbox : Control
|
public partial class ctrlTextbox : Control
|
||||||
{
|
{
|
||||||
private Regex _codeRegex = new Regex("^(\\s*)([a-z]{3})([*]{0,1})($|[ ]){1}([(]{0,1})(([$][0-9a-f]*)|(#[@$:_0-9a-z]*)|([@_a-z]([@_a-z0-9])*){0,1}(\\+(\\d+)){0,1}){0,1}([)]{0,1})(,X|,Y){0,1}([)]{0,1})(.*)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
private Regex _codeRegex = new Regex("^(\\s*)([a-z]{3})([*]{0,1})($|[ ]){1}([(\\[]{0,1})(([$][0-9a-f]*)|(#[@$:_0-9a-z]*)|([@_a-z]([@_a-z0-9])*){0,1}(\\+(\\d+)){0,1}){0,1}([)\\]]{0,1})(,X|,Y){0,1}([)\\]]{0,1})(.*)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
public event EventHandler ScrollPositionChanged;
|
public event EventHandler ScrollPositionChanged;
|
||||||
public event EventHandler SelectedLineChanged;
|
public event EventHandler SelectedLineChanged;
|
||||||
private bool _disableScrollPositionChangedEvent;
|
private bool _disableScrollPositionChangedEvent;
|
||||||
|
@ -902,8 +902,6 @@ namespace Mesen.GUI.Debugger.Controls
|
||||||
private void DrawLineText(Graphics g, int currentLine, int marginLeft, int positionY, CodeLineData lineData, float codeStringLength, Color? textColor, int lineHeight)
|
private void DrawLineText(Graphics g, int currentLine, int marginLeft, int positionY, CodeLineData lineData, float codeStringLength, Color? textColor, int lineHeight)
|
||||||
{
|
{
|
||||||
string codeString = lineData.Text;
|
string codeString = lineData.Text;
|
||||||
string addressString = lineData.EffectiveAddress>= 0 ? (" [" + lineData.EffectiveAddress.ToString("X6") + "]") : "";
|
|
||||||
float addressStringLength = g.MeasureString(addressString, this.Font, int.MaxValue, StringFormat.GenericTypographic).Width;
|
|
||||||
string commentString = lineData.Comment;
|
string commentString = lineData.Comment;
|
||||||
|
|
||||||
DebugInfo info = ConfigManager.Config.Debug;
|
DebugInfo info = ConfigManager.Config.Debug;
|
||||||
|
@ -962,24 +960,15 @@ namespace Mesen.GUI.Debugger.Controls
|
||||||
int codePartCount = colors.Count;
|
int codePartCount = colors.Count;
|
||||||
|
|
||||||
List<string> parts = new List<string>() { padding, opcode, invalidStar, " ", paren1, operand, paren2, indirect, paren3 };
|
List<string> parts = new List<string>() { padding, opcode, invalidStar, " ", paren1, operand, paren2, indirect, paren3 };
|
||||||
string memoryAddress = "";
|
|
||||||
if(!string.IsNullOrWhiteSpace(addressString)) {
|
if(lineData.EffectiveAddress >= 0) {
|
||||||
colors.Add(info.CodeEffectiveAddressColor);
|
colors.Add(info.CodeEffectiveAddressColor);
|
||||||
parts.Add(addressString);
|
parts.Add(" [" + lineData.EffectiveAddress.ToString("X6") + "]");
|
||||||
memoryAddress = addressString.Substring(3).Trim();
|
|
||||||
|
|
||||||
//Update the contents of "arrayPosition" based on the address string, rather than use the one from the original address
|
|
||||||
int plusIndex = memoryAddress.IndexOf("+");
|
|
||||||
arrayPosition = plusIndex >= 0 ? memoryAddress.Substring(plusIndex+1) : "";
|
|
||||||
} else if(operand.Length > 0 && operand[0] != '#') {
|
|
||||||
memoryAddress = operand.Trim();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.ShowMemoryValues && memoryAddress.Length > 0) {
|
if(this.ShowMemoryValues && lineData.ValueSize > 0) {
|
||||||
if(lineData.Value >= 0) {
|
|
||||||
colors.Add(defaultColor);
|
colors.Add(defaultColor);
|
||||||
parts.Add(" = $" + lineData.Value.ToString("X4"));
|
parts.Add(lineData.GetValueString());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Display the rest of the line (used by trace logger)
|
//Display the rest of the line (used by trace logger)
|
||||||
|
|
Loading…
Add table
Reference in a new issue