diff --git a/Src/Debugger/AddressTable.h b/Src/Debugger/AddressTable.h index 29c6757..a9b1306 100644 --- a/Src/Debugger/AddressTable.h +++ b/Src/Debugger/AddressTable.h @@ -31,7 +31,6 @@ #include #include -using namespace std; #define TABLE_WIDTH 16 #define TABLE_SIZE (1 << TABLE_WIDTH) diff --git a/Src/Debugger/Breakpoint.h b/Src/Debugger/Breakpoint.h index 45f0917..0862b57 100644 --- a/Src/Debugger/Breakpoint.h +++ b/Src/Debugger/Breakpoint.h @@ -19,8 +19,8 @@ ** with Supermodel. If not, see . **/ -/* - * Breakpoint.h +/* + * Breakpoint.h */ #ifdef SUPERMODEL_DEBUGGER diff --git a/Src/Debugger/CPUDebug.cpp b/Src/Debugger/CPUDebug.cpp index f15dfde..b3ad29d 100644 --- a/Src/Debugger/CPUDebug.cpp +++ b/Src/Debugger/CPUDebug.cpp @@ -32,6 +32,8 @@ #include #include +using namespace std; + namespace Debugger { CCPUDebug::CCPUDebug(const char *cpuType, const char *cpuName, diff --git a/Src/Debugger/CPUDebug.h b/Src/Debugger/CPUDebug.h index 8ba4c95..cf55531 100644 --- a/Src/Debugger/CPUDebug.h +++ b/Src/Debugger/CPUDebug.h @@ -19,8 +19,8 @@ ** with Supermodel. If not, see . **/ -/* - * CPUDebug.h +/* + * CPUDebug.h */ #ifdef SUPERMODEL_DEBUGGER @@ -30,10 +30,8 @@ #include #include #include -using namespace std; #include "Types.h" - #include "CodeAnalyser.h" #include "AddressTable.h" #include "Breakpoint.h" @@ -220,18 +218,18 @@ namespace Debugger UINT32 pc; UINT32 opcode; - vector regs; - vector exceps; - vector inters; - vector ios; + std::vector regs; + std::vector exceps; + std::vector inters; + std::vector ios; // TODO - should use map for T=CRegion,CLabel&CComment so that look-ups via address are faster - vector regions; - vector labels; - vector comments; - vector memWatches; - vector ioWatches; - vector bps; - vector regMons; + std::vector regions; + std::vector labels; + std::vector comments; + std::vector memWatches; + std::vector ioWatches; + std::vector bps; + std::vector regMons; virtual ~CCPUDebug(); @@ -489,7 +487,7 @@ namespace Debugger CCountWatch *AddCountMemWatch(UINT32 addr, UINT32 size, bool trigRead, bool trigWrite, unsigned count); - CMatchWatch *AddMatchMemWatch(UINT32 addr, UINT32 size, bool trigRead, bool trigWrite, vector &dataSeq); + CMatchWatch *AddMatchMemWatch(UINT32 addr, UINT32 size, bool trigRead, bool trigWrite, std::vector &dataSeq); CPrintWatch *AddPrintMemWatch(UINT32 addr, UINT32 size, bool trigRead, bool trigWrite); diff --git a/Src/Debugger/CodeAnalyser.cpp b/Src/Debugger/CodeAnalyser.cpp index b91c6a5..0c31423 100644 --- a/Src/Debugger/CodeAnalyser.cpp +++ b/Src/Debugger/CodeAnalyser.cpp @@ -32,6 +32,8 @@ #include #include +using namespace std; + namespace Debugger { CEntryPoint::CEntryPoint(const CEntryPoint &other) : addr(other.addr), autoFlag(other.autoFlag) diff --git a/Src/Debugger/CodeAnalyser.h b/Src/Debugger/CodeAnalyser.h index 21c515d..8b6a32c 100644 --- a/Src/Debugger/CodeAnalyser.h +++ b/Src/Debugger/CodeAnalyser.h @@ -19,8 +19,8 @@ ** with Supermodel. If not, see . **/ -/* - * CodeAnalyser.h +/* + * CodeAnalyser.h */ #ifdef SUPERMODEL_DEBUGGER @@ -32,10 +32,8 @@ #include #include #include -using namespace std; #include "Types.h" - #include "Debugger.h" #include "AddressTable.h" @@ -136,26 +134,26 @@ namespace Debugger friend class CCodeAnalyser; private: - vector m_entryPoints; - vector m_unseenEntryAddrs; - vector m_seenIndices; - vector m_validIndices; - map m_autoLabelsMap; + std::vector m_entryPoints; + std::vector m_unseenEntryAddrs; + std::vector m_seenIndices; + std::vector m_validIndices; + std::map m_autoLabelsMap; unsigned m_acquired; CCodeAnalysis(CCodeAnalyser *aAnalyser); - CCodeAnalysis(CCodeAnalyser *aAnalyser, unsigned aTotalIndices, vector &entryPoints, vector &m_unseenEntryAddrs); + CCodeAnalysis(CCodeAnalyser *aAnalyser, unsigned aTotalIndices, std::vector &entryPoints, std::vector &m_unseenEntryAddrs); - CCodeAnalysis(CCodeAnalysis *oldAnalysis, vector &entryPoints, vector &m_unseenEntryAddrs); + CCodeAnalysis(CCodeAnalysis *oldAnalysis, std::vector &entryPoints, std::vector &m_unseenEntryAddrs); void FinishAnalysis(); public: CCodeAnalyser *analyser; - set validIndexSet; - vector autoLabels; + std::set validIndexSet; + std::vector autoLabels; ~CCodeAnalysis(); @@ -179,7 +177,7 @@ namespace Debugger CAutoLabel *GetAutoLabel(const char *subLabel); - vector GetAutoLabels(ELabelFlags flag); + std::vector GetAutoLabels(ELabelFlags flag); }; /* @@ -194,23 +192,23 @@ namespace Debugger class CCodeAnalyser { private: - vector m_codeRegions; - vector m_indexBounds; + std::vector m_codeRegions; + std::vector m_indexBounds; - vector m_customEntryAddrs; + std::vector m_customEntryAddrs; bool m_abortAnalysis; - void CheckEntryPoints(vector &entryPoints, vector &unseenEntryAddrs, vector &prevPoints, + void CheckEntryPoints(std::vector &entryPoints, std::vector &unseenEntryAddrs, std::vector &prevPoints, bool &needsAnalysis, bool &reanalyse); - void GatherEntryPoints(vector &entryPoints, vector &unseenEntryAddrs, bool &reanalyse); + void GatherEntryPoints(std::vector &entryPoints, std::vector &unseenEntryAddrs, bool &reanalyse); - void AddEntryPoint(vector &entryPoints, UINT32 addr, ELabelFlags autoFlag, const char *autoLabel); + void AddEntryPoint(std::vector &entryPoints, UINT32 addr, ELabelFlags autoFlag, const char *autoLabel); - void AnalyseCode(vector &seenIndices, vector &validIndices, set &validIndexSet, map &autoLabelsMap, UINT32 addr); + void AnalyseCode(std::vector &seenIndices, std::vector &validIndices, std::set &validIndexSet, std::map &autoLabelsMap, UINT32 addr); - void AddFlagToAddr(map &autoLabelsMap, UINT32 addr, ELabelFlags autoFlag, const char *autoLabel); + void AddFlagToAddr(std::map &autoLabelsMap, UINT32 addr, ELabelFlags autoFlag, const char *autoLabel); public: CCPUDebug *cpu; diff --git a/Src/Debugger/ConsoleDebugger.cpp b/Src/Debugger/ConsoleDebugger.cpp index b92b84c..3e4a892 100644 --- a/Src/Debugger/ConsoleDebugger.cpp +++ b/Src/Debugger/ConsoleDebugger.cpp @@ -1,2756 +1,2760 @@ -/** - ** Supermodel - ** A Sega Model 3 Arcade Emulator. - ** Copyright 2011 Bart Trzynadlowski, Nik Henson - ** - ** This file is part of Supermodel. - ** - ** Supermodel is free software: you can redistribute it and/or modify it under - ** the terms of the GNU General Public License as published by the Free - ** Software Foundation, either version 3 of the License, or (at your option) - ** any later version. - ** - ** Supermodel is distributed in the hope that it will be useful, but WITHOUT - ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - ** more details. - ** - ** You should have received a copy of the GNU General Public License along - ** with Supermodel. If not, see . - **/ - +/** + ** Supermodel + ** A Sega Model 3 Arcade Emulator. + ** Copyright 2011 Bart Trzynadlowski, Nik Henson + ** + ** This file is part of Supermodel. + ** + ** Supermodel is free software: you can redistribute it and/or modify it under + ** the terms of the GNU General Public License as published by the Free + ** Software Foundation, either version 3 of the License, or (at your option) + ** any later version. + ** + ** Supermodel is distributed in the hope that it will be useful, but WITHOUT + ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + ** more details. + ** + ** You should have received a copy of the GNU General Public License along + ** with Supermodel. If not, see . + **/ + /* * ConsoleDebugger.cpp - */ - -#ifdef SUPERMODEL_DEBUGGER - -#include "ConsoleDebugger.h" -#include "CPUDebug.h" -#include "CodeAnalyser.h" -#include "Label.h" - -#include -#include - -namespace Debugger -{ - CConsoleDebugger::CConsoleDebugger() : CDebugger(), - m_nextFrame(false), m_listDism(0), m_listMem(0), m_analyseCode(true), - m_addrFmt(HexDollar), m_portFmt(Decimal), m_dataFmt(HexDollar), - m_showLabels(true), m_labelsOverAddr(true), m_showOpCodes(false), m_memBytesPerRow(12), m_file(NULL) - { - // - } - - // TODO - tidy up this function, ie do some proper parsing of commands - it is a mess! - void CConsoleDebugger::WaitCommand(CCPUDebug *cpu) - { - m_cpu = cpu; - - UINT32 pc = m_cpu->pc; - m_listDism = (m_cpu->instrCount > 0 && pc > 10 * m_cpu->minInstrLen ? pc - 10 * m_cpu->minInstrLen : 0); - - char bpChr; - char addrStr[20]; - char labelStr[13]; - char opCodes[50]; - int codesLen; - char mnemonic[255]; - char operands[255]; - char cmd[255]; - - for (;;) - { - // Get code analyser and if available analyse code now if required - if (m_analyseCode) - { - CCodeAnalyser *analyser = m_cpu->GetCodeAnalyser(); - if (analyser->NeedsAnalysis()) - { - Print("Analysing %s...\n", m_cpu->name); - analyser->AnalyseCode(); - } - } - - // Close redirected output file, if exists - if (m_file != NULL) + */ + +#ifdef SUPERMODEL_DEBUGGER + +#include "ConsoleDebugger.h" +#include "CPUDebug.h" +#include "CodeAnalyser.h" +#include "Label.h" + +#include +#include + +using namespace std; + +namespace Debugger +{ + CConsoleDebugger::CConsoleDebugger() : CDebugger(), + m_nextFrame(false), m_listDism(0), m_listMem(0), m_analyseCode(true), + m_addrFmt(HexDollar), m_portFmt(Decimal), m_dataFmt(HexDollar), + m_showLabels(true), m_labelsOverAddr(true), m_showOpCodes(false), m_memBytesPerRow(12), m_file(NULL) + { + // + } + + // TODO - tidy up this function, ie do some proper parsing of commands - it is a mess! + void CConsoleDebugger::WaitCommand(CCPUDebug *cpu) + { + m_cpu = cpu; + + UINT32 pc = m_cpu->pc; + m_listDism = (m_cpu->instrCount > 0 && pc > 10 * m_cpu->minInstrLen ? pc - 10 * m_cpu->minInstrLen : 0); + + char bpChr; + char addrStr[20]; + char labelStr[13]; + char opCodes[50]; + int codesLen; + char mnemonic[255]; + char operands[255]; + char cmd[255]; + + for (;;) + { + // Get code analyser and if available analyse code now if required + if (m_analyseCode) + { + CCodeAnalyser *analyser = m_cpu->GetCodeAnalyser(); + if (analyser->NeedsAnalysis()) + { + Print("Analysing %s...\n", m_cpu->name); + analyser->AnalyseCode(); + } + } + + // Close redirected output file, if exists + if (m_file != NULL) { fclose(m_file); - m_file = NULL; - } - - // Get details for current PC address - bool hasLabel; - if (m_cpu->instrCount > 0) - { - m_cpu->FormatAddress(addrStr, pc); - hasLabel = GetLabelText(labelStr, 12, pc); - codesLen = m_cpu->Disassemble(pc, mnemonic, operands); - FormatOpCodes(opCodes, pc, abs(codesLen)); - } - else - { - addrStr[0] = '-'; - addrStr[1] = '\0'; - hasLabel = false; - labelStr[0] = '\0'; - opCodes[0] = '-'; - opCodes[1] = '\0'; - codesLen = 0; - } - CBreakpoint *bp = m_cpu->GetBreakpoint(pc); - bpChr = (bp != NULL ? bp->symbol : ' '); - - // Output command prompt - Print("%s%c", m_cpu->name, bpChr); - if (m_showLabels) - { - if (m_labelsOverAddr) - Print("%-12s ", (hasLabel ? labelStr : addrStr)); - else - Print("%s %-12s ", addrStr, labelStr); - } - else - Print("%s ", addrStr); - if (m_showOpCodes) - Print("[%s] ", opCodes); - if (codesLen > 0) - Print("%-*s %s > ", (int)m_cpu->maxMnemLen, mnemonic, operands); - else - Print("??? > "); - Flush(); - - // Wait for command - Read(cmd, 255); - - if (cmd[0] == '\0') - { - m_cpu->SetStepMode(StepInto); - break; - } - - // Check for redirection - char *pos = strchr(cmd, '>'); - if (pos != NULL) - { - *pos = '\0'; - pos++; - const char *mode; - if (*pos == '>') - { - mode = "ab"; - pos++; - } - else - mode = "w"; - while (*pos == ' ') - pos++; - if (*pos != '\0') - { - m_file = fopen(pos, mode); - if (m_file == NULL) - { - Error("Unable to direct output to file %s\n", pos); - continue; - } - } - else - { - Error("Missing file to direct output to\n"); - continue; - } - } - - char *token = strtok(cmd, " "); - if (ProcessToken(token, cmd)) - break; - - pc = m_cpu->pc; - } - } - - bool CConsoleDebugger::ProcessToken(const char *token, const char *cmd) - { - UINT32 pc = m_cpu->pc; - - int number; - unsigned size; - const char *sizeStr; - UINT32 addr; - UINT16 portNum; - UINT64 data; - char addrStr[50]; - char portNumStr[50]; - char dataStr[50]; - char mod[10]; - EFormat fmt; - - // - // Execution - // - if (CheckToken(token, "n", "next")) // next [=1] - { - // Parse arguments - token = strtok(NULL, " "); - if (token != NULL) - { - if (!ParseInt(token, &number) || number <= 0) - { - Error("Enter a valid instruction count.\n"); - return false; - } - - if (number > 1) - Print("Running %d instructions.\n", number); - m_cpu->SetCount(number); - } - else - m_cpu->SetStepMode(StepInto); - return true; - } - else if (CheckToken(token, "nf", "nextframe")) // nextframe [=1] - { - // Parse arguments - token = strtok(NULL, " "); - if (token != NULL) - { - if (!ParseInt(token, &number) || number <= 0) - { - Error("Enter a valid frame count.\n"); - return false; - } - - if (number > 1) - Print("Running %d frames.\n", number); - m_nextFrameCount = number; - } - else - m_nextFrameCount = 1; - m_nextFrame = true; - return true; - } - else if (CheckToken(token, "s", "stepover")) // stepover - { - m_cpu->SetStepMode(StepOver); - return true; - } - else if (CheckToken(token, "si", "stepinto")) // stepinto - { - m_cpu->SetStepMode(StepInto); - return true; - } - else if (CheckToken(token, "so", "stepout")) // stepout - { - m_cpu->SetStepMode(StepOut); - return true; - } - else if (CheckToken(token, "c", "continue")) // continue [] - { - // Parse arguments - token = strtok(NULL, " "); - if (token != NULL) - { - if (!ParseAddress(token, &addr)) - { - Error("Enter a valid address.\n"); - return false; - } - - m_cpu->FormatAddress(addrStr, addr); - Print("Continuing until %s.\n", addrStr); - m_cpu->SetUntil(addr); - } - else - m_cpu->SetContinue(); - return true; - } - else if (CheckToken(token, "spc", "setpc")) // setpc - { - // Parse arguments - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing address.\n"); - return false; - } - if (!ParseAddress(token, &addr)) - { - Error("Enter a valid address.\n"); - return false; - } - - if (!m_cpu->SetPC(addr)) - { - Error("Unable to set PC.\n"); - return false; - } - - m_cpu->FormatAddress(addrStr, addr); - Print("PC set to %s.\n", addrStr); - return true; - } - // - // CPUs - // - else if (CheckToken(token, "lc", "listcpus")) // listcpus - { - ListCPUs(); - } - else if (CheckToken(token, "sc", "switchcpu")) // switchcpu (|) - { - // Parse arguments - token = strtok(NULL, " "); - CCPUDebug *cpu; - if (!ParseCPU(token, cpu)) - return false; - - if (!cpu->IsEnabled()) - { - Error("CPU %s is currently disabled for debugging.\n", cpu->name); - return false; - } - - m_cpu = cpu; - pc = cpu->pc; - m_listDism = (cpu->instrCount > 0 && pc > 10 * cpu->minInstrLen ? pc - 10 * cpu->minInstrLen : 0); - return false; - } - else if (CheckToken(token, "dc", "disablecpu")) // disablecpu (|) - { - // Parse arguments - token = strtok(NULL, " "); - CCPUDebug *cpu; - if (!ParseCPU(token, cpu)) - return false; - - if (cpu == m_cpu) - { - Error("Cannot enable/disable debugging on current CPU.\n"); - return false; - } - cpu->SetEnabled(false); - Print("Disabled debugging on CPU %s.\n", cpu->name); - } - else if (CheckToken(token, "ec", "enablecpu")) // enablecpu (|) - { - // Parse arguments - token = strtok(NULL, " "); - CCPUDebug *cpu; - if (!ParseCPU(token, cpu)) - return false; - - if (cpu == m_cpu) - { - Error("Cannot enable/disable debugging on current CPU.\n"); - return false; - } - cpu->SetEnabled(true); - Print("Enabled debugging on CPU %s.\n", cpu->name); - } - // - // Registers - // - else if (CheckToken(token, "lr", "listregisters")) // listregisters - { - ListRegisters(); - } - else if (CheckToken(token, "pr", "printregister")) // printregister - { - // Parse arguments - token = strtok(NULL, " "); - CRegister *reg; - if (!ParseRegister(token, reg)) - return false; - - reg->GetValue(dataStr); - Print("Register %s = %s\n", reg->name, dataStr); - } - else if (CheckToken(token, "sr", "setregister")) // setregister - { - // Parse arguments - token = strtok(NULL, " "); - CRegister *reg; - if (!ParseRegister(token, reg)) - return false; - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing value to set.\n"); - return false; - } - - if (!reg->SetValue(token)) - { - Error("Unable to set value of register %s.\n", reg->name); - return false; - } - reg->GetValue(dataStr); - Print("Set register %s to %s.\n", reg->name, dataStr); - } - else if (CheckToken(token, "lm", "listmonitors")) // listmonitors - { - ListMonitors(); - } - else if (CheckToken(token, "m", "monitor") || // addmonitor - CheckToken(token, "am", "addmonitor")) - { - // Parse arguments - token = strtok(NULL, " "); - CRegister *reg; - if (!ParseRegister(token, reg)) - return false; - - m_cpu->AddRegMonitor(reg->name); - Print("Monitor added to register %s.\n", reg->name); - } - else if (CheckToken(token, "rm", "removemonitor")) // removemonitor - { - // Parse arguments - token = strtok(NULL, " "); - CRegister *reg; - if (!ParseRegister(token, reg)) - return false; - - m_cpu->RemoveRegMonitor(reg->name); - Print("Monitor for register %s removed.\n", reg->name); - } - else if (CheckToken(token, "ram", "removeallmonitors")) // removeallmonitors - { - m_cpu->RemoveAllRegMonitors(); - Print("All register monitors removed.\n"); - } - // - // Exceptions & interrupts - // - else if (CheckToken(token, "le", "listexceptions")) // listexceptions - { - ListExceptions(); - } - else if (CheckToken(token, "li", "listinterrupts")) // listinterrupts - { - ListInterrupts(); - } - else if (CheckToken(token, "t", "trap") || // addtrap ((e)xception|(i)nterrupt) - CheckToken(token, "at", "addtrap")) - { - // Parse arguments - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing type (e)xception or (i)interrupt\n"); - return false; - } - - if (CheckToken(token, "e", "exception")) - { - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing exception id.\n"); - return false; - } - CException *ex = m_cpu->GetException(token); - if (ex == NULL) - { - Error("Enter a valid exception id.\n"); - return false; - } - - ex->trap = true; - Print("Trap added for exceptions of type %s.\n", ex->id); - } - else if (CheckToken(token, "i", "interrupt")) - { - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing interrupt id.\n"); - return false; - } - CInterrupt *in = m_cpu->GetInterrupt(token); - if (in == NULL) - { - Error("Enter a valid interrupt id.\n"); - return false; - } - - in->trap = true; - Print("Trap added for interrupts of type %s.\n", in->id); - } - else - { - Error("Enter valid type (e)xception or (i)interrupt.\n"); - return false; - } - } - else if (CheckToken(token, "rt", "removetrap")) // removetrap ((e)xception|(i)nterrupt) - { - // Parse arguments - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing type (e)xception or (i)interrupt.\n"); - return false; - } - - if (CheckToken(token, "e", "exception")) - { - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing exception id.\n"); - return false; - } - CException *ex = m_cpu->GetException(token); - if (ex == NULL) - { - Error("Enter a valid exception id.\n"); - return false; - } - - ex->trap = false; - Print("Trap for exceptions of type %s removed.\n", ex->id); - } - else if (CheckToken(token, "i", "interrupt")) - { - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing interrupt id.\n"); - return false; - } - CInterrupt *in = m_cpu->GetInterrupt(token); - if (in == NULL) - { - Error("Enter a valid interrupt id.\n"); - return false; - } - - in->trap = false; - Print("Trap for interrupts ot type %s removed.\n", in->id); - } - else - { - Error("Enter a valid type (e)xception or (i)interrupt.\n"); - return false; - } - } - else if (CheckToken(token, "rat", "removealltraps")) // removealltraps [(a)ll|(e)xceptions|(i)nterrupts] - { - bool removeExs; - bool removeInts; - const char *coverage; - if (token == NULL || CheckToken(token, "a", "all")) - { - removeExs = true; - removeInts = true; - coverage = "exceptions and interrupts"; - } - else if (CheckToken(token, "e", "exceptions")) - { - removeExs = true; - removeInts = false; - coverage = "exceptions"; - } - else if (CheckToken(token, "i", "interrupts")) - { - removeExs = false; - removeInts = true; - coverage = "interrupts"; - } - else - { - Error("Enter a valid mode (a)ll, (e)xceptions or (i)nterrupts\n"); - return false; - } - - if (removeExs) - { - for (vector::iterator it = m_cpu->exceps.begin(); it != m_cpu->exceps.end(); it++) - (*it)->trap = false; - } - if (removeInts) - { - for (vector::iterator it = m_cpu->inters.begin(); it != m_cpu->inters.end(); it++) - (*it)->trap = false; - } - Print("All traps for %s removed.\n", coverage); - } - // - // Disassembly, labels & comments - // - else if (CheckToken(token, "l", "list") || // listdisassembly [=last [#=20|]] - CheckToken(token, "ld", "listdisassembly")) - { - // Get start address - UINT32 start; - token = strtok(NULL, " "); - if (token == NULL) - token = "last"; - if (stricmp(token, "last") == 0) - { - // Use end of last listing - start = m_listDism; - } - else if (!ParseAddress(token, &start)) - { - Error("Enter a valid start address.\n"); - return false; - } - - // Get end address - UINT32 end; - unsigned numInstrs; - token = strtok(NULL, " "); - if (token != NULL) - { - if (token[0] == '#') - { - if (!ParseInt(token + 1, &number) || number <= 0) - { - Error("Enter a valid number of instructions.\n"); - return false; - } - numInstrs = (unsigned)number; - end = 0xFFFFFFFF; - } - else - { - if (!ParseAddress(token, &end)) - { - Error("Enter a valid end address.\n"); - return false; - } - numInstrs = 0xFFFFFFFF; - } - } - else - { - // Default is 20 instructions after start - end = 0xFFFFFFFF; - numInstrs = 20; - } - - // List the disassembled code - m_listDism = ListDisassembly(start, end, numInstrs); - } - else if (CheckToken(token, "ll", "listlabels")) // listlabels [(d)efault|(c)ustom|(a)utos|(e)ntrypoints|e(x)cephandlers|(i)interhandlers|(j)umptargets|(l)ooppoints] - { - // Parse arguments - token = strtok(NULL, " "); - bool customLabels; - ELabelFlags labelFlags; - if (token == NULL || CheckToken(token, "d", "default")) - { - customLabels = true; - labelFlags = (ELabelFlags)(LFEntryPoint | LFExcepHandler | LFInterHandler | LFSubroutine); - } - else if (CheckToken(token, "c", "custom")) - { - customLabels = true; - labelFlags = LFNone; - } - else if (CheckToken(token, "a", "autos")) - { - customLabels = true; - labelFlags = (ELabelFlags)(LFEntryPoint | LFExcepHandler | LFInterHandler | LFSubroutine | LFJumpTarget | LFLoopPoint); - } - else if (CheckToken(token, "e", "entrypoints")) - { - customLabels = false; - labelFlags = LFEntryPoint; - } - else if (CheckToken(token, "x", "excephandlers")) - { - customLabels = false; - labelFlags = LFExcepHandler; - } - else if (CheckToken(token, "i", "interhandlers")) - { - customLabels = false; - labelFlags = LFInterHandler; - } - else if (CheckToken(token, "s", "subroutines")) - { - customLabels = false; - labelFlags = LFSubroutine; - } - else if (CheckToken(token, "j", "jumptargets")) - { - customLabels = false; - labelFlags = LFJumpTarget; - } - else if (CheckToken(token, "l", "looppoints")) - { - customLabels = false; - labelFlags = LFLoopPoint; - } - else - { - Error("Enter a valid filter (a)ll, (c)ustom, (e)ntrypoints, e(x)cephandlers, (i)interhandlers, (j)umptargets or (l)ooppoints.\n"); - return false; - } - - ListLabels(customLabels, labelFlags); - } - else if (CheckToken(token, "al", "addlabel")) // addlabel - { - // Parse arguments - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing label address.\n"); - return false; - } - else if (!ParseAddress(token, &addr)) - { - Error("Enter a valid label address.\n"); - return false; - } - - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing label name.\n"); - return false; - } - const char *name = token; - - // Add label - CLabel *label = m_cpu->AddLabel(addr, name); - m_cpu->FormatAddress(addrStr, label->addr); - Print("Label %s added at %s.\n", label->name, addrStr); - } - else if (CheckToken(token, "rl", "removelabel")) // removelabel [|] - { - // Parse arguments - token = strtok(NULL, " "); - if (token == NULL) - token = "-"; - - if (!ParseAddress(token, &addr)) - { - Error("Enter a valid label name or address.\n"); - return false; - } - - CLabel *label = m_cpu->GetLabel(addr); - if (label == NULL) - { - m_cpu->FormatAddress(addrStr, addr); - Error("No label at %s.\n", addrStr); - return false; - } - - const char *name = label->name; - m_cpu->FormatAddress(addrStr, label->addr); - Print("Custom label '%s' removed at address %s.\n", name, addrStr); - } - else if (CheckToken(token, "ral", "removealllabels")) // removealllabels - { - m_cpu->RemoveAllLabels(); - Print("All custom labels removed.\n"); - } - else if (CheckToken(token, "ac", "addcomment")) // addcomment - { - // Parse arguments - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing comment address.\n"); - return false; - } - else if (!ParseAddress(token, &addr)) - { - Error("Enter a valid comment address.\n"); - return false; - } - - char text[255]; - text[0] = '\0'; - token = strtok(NULL, " "); - while (token != NULL) - { - size_t len = strlen(text); - if (len + strlen(token) > 253) - break; - if (len > 0) - strcat(text, " "); - strcat(text, token); - token = strtok(NULL, " "); - } - if (text[0] == '\0') - { - Error("Missing comment text.\n"); - return false; - } - - // Add comment - CComment *comment = m_cpu->AddComment(addr, text); - m_cpu->FormatAddress(addrStr, comment->addr); - Print("Comment added at %s.\n", addrStr); - } - else if (CheckToken(token, "rc", "removecomment")) // removecomment [] - { - // Parse arguments - token = strtok(NULL, " "); - if (token == NULL) - token = "-"; - if (!ParseAddress(token, &addr)) - { - Error("Enter a valid comment address.\n"); - return false; - } - - m_cpu->FormatAddress(addrStr, addr); - if (m_cpu->RemoveComment(addr)) - Print("Comment at address %s removed.\n", addrStr); - else - Error("No comment at address %s.\n", addrStr); - } - else if (CheckToken(token, "rac", "removeallcomments")) // removeallcomments - { - m_cpu->RemoveAllComments(); - Print("All comments removed.\n"); - } - // - // Breakpoints - // - else if (CheckToken(token, "lb", "listbreakpoints")) // listbreakpoints - { - ListBreakpoints(); - } - else if (CheckToken(token, "b", "breakpoint") || // addbreakpoint [ [[s)imple|(c)ount )]] - CheckToken(token, "ab", "addbreakpoint")) - { - // Parse arguments - token = strtok(NULL, " "); - if (token == NULL) - token = "-"; - if (!ParseAddress(token, &addr)) - { - Error("Enter a valid address.\n"); - return false; - } - token = strtok(NULL, " "); - CBreakpoint *bp; - if (token == NULL || CheckToken(token, "s", "simple")) - bp = m_cpu->AddSimpleBreakpoint(addr); - else if (CheckToken(token, "c", "count")) - { - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing count.\n"); - return false; - } - int count; - if (!ParseInt(token, &count) || count <= 0) - { - Error("Enter a valid count.\n"); - return false; - } - - bp = m_cpu->AddCountBreakpoint(addr, count); - } - else if (CheckToken(token, "p", "print")) - bp = m_cpu->AddPrintBreakpoint(addr); - else - { - Error("Enter a valid breakpoint type (s)imple or (c)ount.\n"); - return false; - } - - m_cpu->FormatAddress(addrStr, bp->addr); - Print("Breakpoint #%d added at address %s.\n", bp->num, addrStr); - } - else if (CheckToken(token, "rb", "removebreakpoint")) // removebreakpoint [#|] - { - // Parse arguments - token = strtok(NULL, " "); - if (token == NULL) - token = "-"; - if (token[0] == '#') - { - // Remove breakpoint by number - if (!ParseInt(token + 1, &number) || number < 0 || number >= m_cpu->bps.size()) - { - Error("Enter a valid breakpoint number.\n"); - return false; - } - - // Remove breakpoint - m_cpu->RemoveBreakpoint(m_cpu->bps[number]); - Print("Breakpoint #%d removed.\n", number); - } - else - { - // Remove breakpoint by address - if (!ParseAddress(token, &addr)) - { - Error("Enter a valid address.\n"); - return false; - } - - // Remove breakpoint - m_cpu->FormatAddress(addrStr, addr); - if (m_cpu->RemoveBreakpoint(addr)) - Print("Breakpoint at address %s removed.\n", addrStr); - else - Error("No breakpoint at address %s.\n", addrStr); - } - } - else if (CheckToken(token, "rab", "removeallbreakpoints")) // removeallbreakpoints - { - m_cpu->RemoveAllBreakpoints(); - Print("All breakpoints removed.\n"); - } - // - // Memory, I/O & watches - // - else if (CheckToken(token, "ln", "listregions")) // listregions - { - ListRegions(); - } - else if (CheckToken(token, "ly", "listmemory")) // listmemory [=last [#=8|]] - { - // Get start address - UINT32 start; - token = strtok(NULL, " "); - if (token == NULL) - token = "last"; - if (stricmp(token, "last") == 0) - { - // Use end of last listing - start = m_listMem; - } - else if (!ParseAddress(token, &start)) - { - Error("Enter a valid start address.\n"); - return false; - } - - // Get end address - UINT32 end; - token = strtok(NULL, " "); - if (token != NULL) - { - if (token[0] == '#') - { - if (!ParseInt(token + 1, &number) || number <= 0) - { - Error("Enter a valid number of rows.\n"); - return false; - } - end = start + number * m_memBytesPerRow; - } - else - { - if (!ParseAddress(token, &end)) - { - Error("Enter a valid end address.\n"); - return false; - } - } - } - else - // Default is 8 rows after start - end = start + 8 * m_memBytesPerRow; - - // List the memory - m_listMem = ListMemory(start, end, m_memBytesPerRow); - } - else if (CheckToken(token, "py", "printmemory", mod, 9, "b")) // printmemory[.=b] [(h)ex|hexdo(l)lar|hex(p)osth|(d)ecimal|(b)inary] - { - // Parse arguments - if (!ParseDataSize(mod, size)) - return false; - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing address.\n"); - return false; - } - if (!ParseAddress(token, &addr)) - { - Error("Enter a valid address.\n"); - return false; - } - token = strtok(NULL, " "); - if (token != NULL) - { - if (!ParseFormat(token, fmt)) - return false; - } - else - fmt = m_dataFmt; - - // Read and print memory - char uSizeStr[12]; - sizeStr = GetDataSizeStr(size, false); - UpperFirst(uSizeStr, sizeStr); - data = m_cpu->ReadMem(addr, size); - FormatData(dataStr, fmt, size, data); - m_cpu->FormatAddress(addrStr, addr); - Print("%s data at %s = %s.\n", uSizeStr, addrStr, dataStr); - } - else if (CheckToken(token, "sy", "setmemory", mod, 9, "b")) // setmemory[.=b] - { - // Parse arguments - if (!ParseDataSize(mod, size)) - return false; - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing address.\n"); - return false; - } - if (!ParseAddress(token, &addr)) - { - Error("Enter a valid address.\n"); - return false; - } - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing value to set.\n"); - return false; - } - sizeStr = GetDataSizeStr(size, false); - if (!m_cpu->ParseData(token, size, &data)) - { - Error("Enter a valid %s value.\n", sizeStr); - return false; - } - - // Set memory - char uSizeStr[12]; - UpperFirst(uSizeStr, sizeStr); - m_cpu->WriteMem(addr, size, data); - m_cpu->FormatData(dataStr, size, data); - m_cpu->FormatAddress(addrStr, addr); - Print("Set %s data at %s to %s.\n", uSizeStr, addrStr, dataStr); - } - else if (CheckToken(token, "lo", "listios")) // listios - { - ListIOs(); - } - else if (CheckToken(token, "lw", "listmemwatches")) // listmemwatches - { - ListMemWatches(); - } - else if (CheckToken(token, "w", "memwatch", mod, 9, "b") || // addmemwatch[.=b] [((n)one|(r)ead|(w)rite|(rw)eadwrite) [((s)imple|(c)ount |(m)atch |captu(r)e |(p)rint)]] - CheckToken(token, "aw", "addmemwatch", mod, 9, "b")) - { - // Parse arguments - if (!ParseDataSize(mod, size)) - return false; - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing address.\n"); - return false; - } - if (!ParseAddress(token, &addr)) - { - Error("Enter a valid address.\n"); - return false; - } - token = strtok(NULL, " "); - bool read; - bool write; - if (token == NULL || CheckToken(token, "n", "none")) - { - read = false; - write = false; - } - else if (CheckToken(token, "r", "read")) - { - read = true; - write = false; - } - else if (CheckToken(token, "w", "write")) - { - read = false; - write = true; - } - else if (CheckToken(token, "rw", "read/write") || CheckToken(token, "wr", "write/read")) - { - read = true; - write = true; - } - else - { - Error("Enter valid read/write flags (n)one, (r)ead, (w)rite or (rw)ead/write.\n"); - return false; - } - - // Add mem watch - CWatch *watch; - token = strtok(NULL, " "); - if (token == NULL || CheckToken(token, "s", "simple")) - watch = m_cpu->AddSimpleMemWatch(addr, size, read, write); - else if (CheckToken(token, "c", "count")) - { - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing count.\n"); - return false; - } - int count; - if (!ParseInt(token, &count) || count <= 0) - { - Error("Enter a valid count.\n"); - return false; - } - watch = m_cpu->AddCountMemWatch(addr, size, read, write, count); - } - else if (CheckToken(token, "m", "match")) - { - vector dataSeq; - while ((token = strtok(NULL, " ")) != NULL) - { - if (m_cpu->ParseData(token, size, &data)) - dataSeq.push_back(data); - } - if (dataSeq.size() == 0) - { - sizeStr = GetDataSizeStr(size, false); - Error("Enter a sequence of %s data to match.", sizeStr); - return false; - } - watch = m_cpu->AddMatchMemWatch(addr, size, read, write, dataSeq); - } - else if (CheckToken(token, "r", "capture")) - { - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing maximum capture length.\n"); - return false; - } - int maxLen; - if (!ParseInt(token, &maxLen) || maxLen <= 0) - { - Error("Enter a valid maximum capture length.\n"); - return false; - } - watch = m_cpu->AddCaptureMemWatch(addr, size, read, write, maxLen); - } - else if (CheckToken(token, "p", "print")) - watch = m_cpu->AddPrintMemWatch(addr, size, read, write); - else - { - Error("Enter a valid watch type (s)imple, (c)ount, (m)atch, captu(r)e or (p)rint.\n"); - return false; - } - - m_cpu->FormatAddress(addrStr, watch->addr); - number = GetIndexOfMemWatch(watch); - Print("Memory watch #%d added at address %s.\n", number, addrStr); - } - else if (CheckToken(token, "rw", "removememwatch")) // removememwatch (#|) - { - // Parse arguments - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing watch number or address.\n"); - return false; - } - if (token[0] == '#') - { - // Remove watch by number - vector watches; - GetAllMemWatches(watches); - if (!ParseInt(token + 1, &number) || number < 0 || number >= watches.size()) - { - Error("Enter a valid watch number.\n"); - return false; - } - - // Remove watch - m_cpu->RemoveWatch(watches[number]); - Print("Memory watch #%d removed.\n", number); - } - else - { - // Remove watch by address - if (!ParseAddress(token, &addr)) - { - Error("Enter a valid address.\n"); - return false; - } - - // Remove watch - m_cpu->FormatAddress(addrStr, addr); - if (m_cpu->RemoveMemWatch(addr, 1)) - Print("Memory watch at address %s removed.\n", addrStr); - else - Error("No memory watch at address %s.\n", addrStr); - } - } - else if (CheckToken(token, "raw", "removeallmemwatches")) // removeallmemwatches - { - // Remove all memory watches - vector watches; - GetAllMemWatches(watches); - for (vector::iterator it = watches.begin(); it != watches.end(); it++) - m_cpu->RemoveWatch(*it); - Print("All memory watches removed.\n"); - } - else if (CheckToken(token, "lpw", "listportwatches")) // listportwatches - { - ListPortWatches(); - } - else if (CheckToken(token, "pw", "portwatch") || // addportwatch [((n)one|(i)nput|(o)|(io)nputoutput) [((s)imple|(c)ount |(m)atch |captu(r)e |(p)rint)]] - CheckToken(token, "apw", "addportwatch")) - { - // Parse arguments - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing port number.\n"); - return false; - } - if (!m_cpu->ParsePortNum(token, &portNum)) - { - Error("Enter a valid port number.\n"); - return false; - } - token = strtok(NULL, " "); - bool input; - bool output; - if (token == NULL || CheckToken(token, "n", "none")) - { - input = false; - output = false; - } - else if (CheckToken(token, "i", "input")) - { - input = true; - output = false; - } - else if (CheckToken(token, "o", "output")) - { - input = false; - output = true; - } - else if (CheckToken(token, "io", "input/output") || CheckToken(token, "oi", "output/input")) - { - input = true; - output = true; - } - else - { - Error("Enter valid input/output flags (n)one, (i)nput, (o)utput or (io)nput/output.\n"); - return false; - } - - // Add watch - CPortIO *port = m_cpu->GetPortIO(portNum); - CWatch *watch; - token = strtok(NULL, " "); - if (token == NULL || CheckToken(token, "s", "simple")) - watch = port->AddSimpleWatch(input, output); - else if (CheckToken(token, "c", "count")) - { - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing count.\n"); - return false; - } - int count; - if (!ParseInt(token, &count) || count <= 0) - { - Error("Enter a valid count.\n"); - return false; - } - watch = port->AddCountWatch(input, output, count); - } - else if (CheckToken(token, "m", "match")) - { - vector dataSeq; - while ((token = strtok(NULL, " ")) != NULL) - { - if (m_cpu->ParseData(token, port->dataSize, &data)) - dataSeq.push_back(data); - } - if (dataSeq.size() == 0) - { - Error("Enter a sequence of %s to match.", GetDataSizeStr(port->dataSize, false)); - return false; - } - watch = port->AddMatchWatch(input, output, dataSeq); - } - else if (CheckToken(token, "r", "capture")) - { - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing maximum capture length.\n"); - return false; - } - int maxLen; - if (!ParseInt(token, &maxLen) || maxLen <= 0) - { - Error("Enter a valid maximum capture length.\n"); - return false; - } - watch = port->AddCaptureWatch(input, output, maxLen); - } - else if (CheckToken(token, "p", "print")) - watch = port->AddPrintWatch(input, output); - else - { - Error("Enter a valid watch type (s)imple, (c)ount, (m)atch, captu(r)e or (p)rint.\n"); - return false; - } - - m_cpu->FormatPortNum(portNumStr, portNum); - number = GetIndexOfPortWatch(watch); - Print("Port watch %d added for port %u.\n", number, portNumStr); - } - else if (CheckToken(token, "rpw", "removeportwatch")) // removeportwatch (a|n|p) [NUM|PORT] - { - // Parse arguments - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing watch number or port number.\n"); - return false; - } - if (token[0] == '#') - { - // Remove watch by number - vector watches; - GetAllPortWatches(watches); - if (!ParseInt(token + 1, &number) || number < 0 || number >= watches.size()) - { - Error("Enter a valid watch number.\n"); - return false; - } - - // Remove watch - m_cpu->RemoveWatch(watches[number]); - Print("Port watch #%d removed.\n", number); - } - else - { - // Remove watch by port number - if (!m_cpu->ParsePortNum(token, &portNum)) - { - Error("Enter a valid port number.\n"); - return false; - } - - // Remove watch - CPortIO *port = m_cpu->GetPortIO(portNum); - m_cpu->FormatPortNum(portNumStr, portNum); - if (port->RemoveWatch()) - Print("Port watch for port %s removed.\n", portNumStr); - else - Error("No port watch for port %s.\n", portNumStr); - } - } - else if (CheckToken(token, "rapw", "removeallportwatches")) // removeallportwatches - { - // Remove all port watches - vector watches; - GetAllPortWatches(watches); - for (vector::iterator it = watches.begin(); it != watches.end(); it++) - m_cpu->RemoveWatch(*it); - Print("All port watches removed.\n"); - } - // - // General - // - else if (CheckToken(token, "p", "print", mod, 9, "")) // print[.=v] [(h)ex|hexdo(l)lar|hex(p)osth|(d)ecimal|(b)inary] - { - // Parse arguments - bool useDefSize; - if (mod[0] == '\0') - useDefSize = true; - else if (ParseDataSize(mod, size)) - useDefSize = false; - else - return false; - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing expression.\n"); - return false; - } - const char *expr = token; - token = strtok(NULL, " "); - if (token != NULL) - { - if (!ParseFormat(token, fmt)) - return false; - } - else - fmt = m_dataFmt; - - // Check labels and registers - CLabel *label = m_cpu->GetLabel(expr); - if (label != NULL) - { - data = label->addr; - if (useDefSize) - size = m_cpu->memBusWidth / 8; - } - else - { - CCodeAnalyser *analyser = m_cpu->GetCodeAnalyser(); - CAutoLabel *autoLabel = analyser->analysis->GetAutoLabel(expr); - if (autoLabel != NULL) - { - data = autoLabel->addr; - if (useDefSize) - size = m_cpu->memBusWidth / 8; - } - else - { - CRegister *reg = m_cpu->GetRegister(expr); - if (reg != NULL) - { - data = reg->GetValueAsInt(); - if (useDefSize) - size = reg->dataWidth / 8; - } - else - { - if (!ParseData(expr, m_dataFmt, 8, &data)) - { - Print("Unable to parse expression %s\n", expr); - return false; - } - if (useDefSize) - size = 8; - } - } - } - - char result[255]; - FormatData(result, fmt, size, data); - if (useDefSize) - Print("%s = %s\n", expr, result); - else - { - sizeStr = GetDataSizeStr(size, true); - Print("%s = %s.%s\n", expr, result, sizeStr); - } - } - else if (CheckToken(token, "cfg", "configure")) // configure - { - // Parse arguments - token = strtok(NULL, " "); - if (token == NULL) - { - // If no arguments, then print out current configuration - Print("Configuration:\n"); - Print(" %-20s %-12s %s\n", "Code Analysis", (m_analyseCode ? "On" : "Off"), "(a)nalysis"); - Print(" %-20s %-12s %s\n", "Address Format", GetFmtConfig(m_addrFmt), "a(d)dressfmt"); - Print(" %-20s %-12s %s\n", "Port Format", GetFmtConfig(m_portFmt), "(p)ortfmt"); - Print(" %-20s %-12s %s\n", "Data Format", GetFmtConfig(m_dataFmt), "da(t)afmt"); - Print(" %-20s %-12s %s\n", "Show Labels", (m_showLabels ? "On" : "Off"), "show(l)abels"); - Print(" %-20s %-12s %s\n", "Show Opcodes", (m_showOpCodes ? "On" : "Off"), "show(o)pcodes"); - Print(" %-20s %-12u %s\n", "Mem Bytes Per Row", m_memBytesPerRow, "mem(b)ytesrow"); - return false; - } - - if (CheckToken(token, "a", "analysis")) - { - token = strtok(NULL, " "); - SetBoolConfig(token, m_analyseCode); - } - else if (CheckToken(token, "d", "addressfmt")) - { - token = strtok(NULL, " "); - SetFmtConfig(token, m_addrFmt); - } - else if (CheckToken(token, "p", "portfmt")) - { - token = strtok(NULL, " "); - SetFmtConfig(token, m_portFmt); - } - else if (CheckToken(token, "t", "datafmt")) - { - token = strtok(NULL, " "); - SetFmtConfig(token, m_dataFmt); - } - else if (CheckToken(token, "l", "showlabels")) - { - token = strtok(NULL, " "); - SetBoolConfig(token, m_showLabels); - } - else if (CheckToken(token, "o", "showopcodes")) - { - token = strtok(NULL, " "); - SetBoolConfig(token, m_showOpCodes); - } - else if (CheckToken(token, "b", "membytesrow")) - { - token = strtok(NULL, " "); - SetNumConfig(token, m_memBytesPerRow); - } - else - { - Error("Enter a valid option (a)nalysis, a(d)dressfmt, (p)ortfmt, da(t)afmt, show(l)abels, show(o)pcodes, mem(b)ytesrow.\n"); - return false; - } - } - else if (CheckToken(token, "ls", "loadstate")) // loadstate - { - // Parse arguments - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing filename.\n"); - return false; - } - - if (LoadState(token)) - Print("Debugger state successfully loaded from <%s>\n", token); - else - Error("Unable to load debugger state from <%s>\n", token); - } - else if (CheckToken(token, "ss", "savestate")) // savestate - { - // Parse arguments - token = strtok(NULL, " "); - if (token == NULL) - { - Error("Missing filename.\n"); - return false; - } - - if (SaveState(token)) - Print("Debugger state successfully saved to <%s>\n", token); - else - Error("Unable to save debugger state to <%s>\n", token); - } - else if (CheckToken(token, "h", "help")) // help - { - // TODO - improve the following - const char *fmt = " %-6s %-25s %s\n"; - - Print("Debugger Commands:\n"); - - Print(" Execution:\n"); - Print(fmt, "n", "next", "[=1]"); - Print(fmt, "nf", "nextframe", "[=1]"); - Print(fmt, "s", "stepover", ""); - Print(fmt, "si", "stepinto", ""); - Print(fmt, "so", "stepout", ""); - Print(fmt, "c", "continue", "[]"); - Print(fmt, "spc", "setpc", ""); - - Print(" CPUs:\n"); - Print(fmt, "lc", "listcpus", ""); - Print(fmt, "sc", "switchcpu", "(|)"); - Print(fmt, "dc", "disablecpu", "(|)"); - Print(fmt, "ec", "enablecpu", "(|)"); - - Print(" Registers:\n"); - Print(fmt, "lr", "listregisters", ""); - Print(fmt, "pr", "printregister", ""); - Print(fmt, "sr", "setregister", " "); - Print(fmt, "lm", "listmonitors", ""); - Print(fmt, "m/am", "addmonitor", ""); - Print(fmt, "rm", "removemonitor", ""); - Print(fmt, "ram", "removeallmonitors", ""); - - Print(" Exceptions & interrupts:\n"); - Print(fmt, "le", "listexceptions", ""); - Print(fmt, "li", "listinterrupts", ""); - Print(fmt, "t/at", "addtrap", "((e)xception|(i)nterrupt) "); - Print(fmt, "rt", "removetrap", "((e)xception|(i)nterrupt) "); - Print(fmt, "rat", "removealltraps", "[(a)ll|(e)xceptions|(i)nterrupts]"); - - Print(" Disassembly, labels & comments:\n"); - Print(fmt, "l/ld", "listdisassembly", "[=last [#=20|]]"); - Print(fmt, "ll", "listlabels", "[(d)efault|(c)ustom|(a)utos|(e)ntrypoints|e(x)cephandlers|(i)interhandlers|(j)umptargets|(l)ooppoints]"); - Print(fmt, "al", "addlabel", " "); - Print(fmt, "rl", "removelabel", "[|]"); - Print(fmt, "ral", "removealllabels", ""); - Print(fmt, "ac", "addcomment", " "); - Print(fmt, "rc", "removecomment", "[]"); - Print(fmt, "rac", "removeallcomments", ""); - - Print(" Breakpoints:\n"); - Print(fmt, "lb", "listbreakpoints", ""); - Print(fmt, "b/ab", "addbreakpoint", "[ [[s)imple|(c)ount )]]"); - Print(fmt, "rb", "removebreakpoint", "[#|]"); - Print(fmt, "rab", "removeallbreakpoints", ""); - - Print(" Memory, I/O & watches:\n"); - Print(fmt, "ln", "listregions", ""); - Print(fmt, "ly", "listmemory", "[=last [#=8|]]"); - Print(fmt, "py", "printmemory[.=b]", ""); - Print(fmt, "sy", "setmemory[.=b]", " "); - Print(fmt, "lo", "listios", ""); - Print(fmt, "lw", "listmemwatches", ""); - Print(fmt, "w/aw", "addmemwatch[.=b]", " [((n)one|(r)ead|(w)rite|(rw)eadwrite) [((s)imple|(c)ount |(m)atch |captu(r)e |(p)rint)]]"); - Print(fmt, "rw", "removememwatch", "(#|)"); - Print(fmt, "raw", "removeallmemwatches", ""); - Print(fmt, "lpw", "listportwatches", ""); - Print(fmt, "pw/apw", "addportwatch", " [((n)one|(i)nput|(o)utput|(io)nputoutput) [(s)imple|(c)ount |(m)atch |captu(r)e |(p)rint]]"); - Print(fmt, "rpw", "removeportwatch", "(#|)"); - Print(fmt, "rapw", "removeallportwatches", ""); - - Print("General:\n"); - Print(fmt, "p", "print[.=v]", " [(h)ex|hexdo(l)lar|hex(p)osth|(d)ecimal|(b)inary]"); - Print(fmt, "cfg", "configure", ""); - Print(fmt, "ls", "loststate", ""); - Print(fmt, "ss", "savestate", ""); - Print(fmt, "h", "help", ""); - Print(fmt, "x", "exit", ""); - } - else if (CheckToken(token, "x", "exit")) // exit - { - Print("Exiting...\n"); - SetExit(); - return true; - } - else - Print("Unknown command '%s'.\n", token); - return false; - } - - void CConsoleDebugger::Read(char *str, size_t maxSize) - { - if (fgets(str, maxSize, stdin) != NULL) - { - char *pos = strchr(str, '\n'); - if (pos) - *pos = '\0'; - } - else - str[0] = '\0'; - } - - void CConsoleDebugger::Print(const char *fmtStr, ...) - { - va_list vl; - va_start(vl, fmtStr); - PrintVL(fmtStr, vl); - va_end(vl); - } - - void CConsoleDebugger::Error(const char *fmtStr, ...) - { - // Don't log errors to file - va_list vl; - va_start(vl, fmtStr); - vprintf(fmtStr, vl); - va_end(vl); - } - - void CConsoleDebugger::PrintVL(const char *fmtStr, va_list vl) - { - if (m_file != NULL) - vfprintf(m_file, fmtStr, vl); - else - vprintf(fmtStr, vl); - } - - void CConsoleDebugger::Flush() - { - fflush(stdout); - } - - bool CConsoleDebugger::CheckToken(const char *token, const char *simple, const char *full) - { - return stricmp(token, simple) == 0 || stricmp(token, full) == 0; - } - - bool CConsoleDebugger::CheckToken(const char *token, const char *simple, const char *full, char *modifier, size_t modSize, const char *defaultMod) - { - const char *pos = strchr(token, '.'); - if (pos == NULL) - { - strncpy(modifier, defaultMod, modSize); - modifier[modSize] = '\0'; - return CheckToken(token, simple, full); - } - else - { - pos++; - if (pos == '\0') - return false; - strncpy(modifier, pos, modSize); - modifier[modSize] = '\0'; - - char actual[255]; - size_t actSize = min(pos - token - 1, 254); - strncpy(actual, token, actSize); - actual[actSize] = '\0'; - return CheckToken(actual, simple, full); - } - } - - void CConsoleDebugger::Truncate(char *dst, size_t maxLen, const char *src) - { - strncpy(dst, src, maxLen); - if (strlen(src) > maxLen) - strncpy(&dst[maxLen - 3], "...", 3); - dst[maxLen] = '\0'; - } - - void CConsoleDebugger::UpperFirst(char *dst, const char *src) - { - if (*src != '\0') - { - *dst++ = toupper(*src++); - while (*src != '\0') - *dst++ = *src++; - } - *dst = '\0'; - } - - void CConsoleDebugger::FormatOpCodes(char *str, int addr, int codesLen) - { - char *p = str; - int i = 0; - while (i < codesLen) - { - UINT8 opCode = (UINT8)m_cpu->ReadMem(addr++, 1); - sprintf(p, "%02X", opCode); - p += 2; - i++; - } - while (i++ < m_cpu->maxInstrLen) - { - *p++ = ' '; - *p++ = ' '; - } - *p = '\0'; - } - - bool CConsoleDebugger::GetLabelText(char *str, int maxLen, UINT32 addr) - { - char labelStr[255]; - - CLabel *label = m_cpu->GetLabel(addr); - if (label != NULL) - { - Truncate(str, maxLen, label->name); - return true; - } - - if (m_analyseCode) - { - CCodeAnalyser *analyser = m_cpu->GetCodeAnalyser(); - CAutoLabel *autoLabel = analyser->analysis->GetAutoLabel(addr); - if (autoLabel != NULL && autoLabel->GetLabel(labelStr)) - { - Truncate(str, maxLen, labelStr); - return true; - } - } - - str[0] = '\0'; - return false; - } - - bool CConsoleDebugger::SetBoolConfig(const char *str, bool &cfg) - { - if (str == NULL) - { - Print("Current setting: %-12s\n", (cfg ? "On" : "Off")); - Print("Change setting with (o)n, o(f)f.\n"); - return false; - } - - if (CheckToken(str, "o", "on")) - { - cfg = true; - Print("Changed setting: On\n"); - ApplyConfig(); - return true; - } - else if (CheckToken(str, "f", "off")) - { - cfg = false; - Print("Changed setting: Off\n"); - ApplyConfig(); - return true; - } - else - { - Error("Enter a valid setting (o)n, o(f)f.\n"); - return false; - } - } - - bool CConsoleDebugger::SetNumConfig(const char *str, unsigned &cfg) - { - if (str == NULL) - { - Print("Current setting: %-12u\n", cfg); - return false; - } - - int number; - if (!ParseInt(str, &number)) - { - Error("Enter a valid number.\n"); - return false; - } - - cfg = (unsigned)number; - Print("Changed setting: %-12u\n", cfg); - ApplyConfig(); - return true; - } - - const char *CConsoleDebugger::GetFmtConfig(EFormat fmt) - { - switch (fmt) - { - case Hex0x: return "Hex (0x00)"; - case HexDollar: return "Hex ($00)"; - case HexPostH: return "Hex (00h)"; - case Decimal: return "Decimal"; - case Binary: return "Binary"; - default: return "-"; - } - } - - bool CConsoleDebugger::SetFmtConfig(const char *str, EFormat &cfg) - { - if (str == NULL) - { - Print("Current setting: %-12s\n", GetFmtConfig(cfg)); - Print("Change setting with (h)ex, hex(z)ero, hexdo(l)ar, hex(p)osth, (d)ecimal, (b)inary.\n"); - return false; - } - - if (!ParseFormat(str, cfg)) - return false; - - Print("Changed setting: %-12s\n", GetFmtConfig(cfg)); - ApplyConfig(); - return true; - } - - bool CConsoleDebugger::ParseAddress(const char *str, UINT32 *addr) - { - if (m_cpu->instrCount > 0 && CheckToken(str, "-", "current")) - { - *addr = m_cpu->pc; - return true; - } - return m_cpu->ParseAddress(str, addr); - } - - const char *CConsoleDebugger::GetDataSizeStr(unsigned dataSize, bool shortName) - { - switch (dataSize) - { - case 1: return (shortName ? "b" : "byte"); - case 2: return (shortName ? "w" : "word"); - case 4: return (shortName ? "l" : "long"); - case 8: return (shortName ? "v" : "vlong"); - default: return GetSizeString(dataSize); - } - } - - bool CConsoleDebugger::ParseDataSize(const char *str, unsigned &dataSize) - { - int num = -1; - ParseInt(str, &num); - if (CheckToken(str, "b", "byte") || num == 1) - { - dataSize = 1; - return true; - } - else if (CheckToken(str, "w", "word") || num == 2) - { - dataSize = 2; - return true; - } - else if (CheckToken(str, "l", "long") || num == 4) - { - dataSize = 4; - return true; - } - else if (CheckToken(str, "v", "verylong") || num == 8) - { - dataSize = 8; - return true; - } - else - { - Error("Enter a valid size (b)yte, (w)ord, (l)ong or (v)erylong or a number 1, 2, 4 or 8.\n"); - return false; - } - } - - bool CConsoleDebugger::ParseFormat(const char *str, EFormat &fmt) - { - if (CheckToken(str, "h", "hex")) fmt = Hex; - else if (CheckToken(str, "z", "hexzero")) fmt = Hex0x; - else if (CheckToken(str, "l", "hexdollar")) fmt = HexDollar; - else if (CheckToken(str, "p", "hexposth")) fmt = HexPostH; - else if (CheckToken(str, "d", "decimal")) fmt = Decimal; - else if (CheckToken(str, "b", "binary")) fmt = Binary; - else - { - Error("Enter a valid format (h)ex, hex(z)ero, hexdo(l)ar, hex(p)osth, (d)ecimal, (b)inary.\n"); - return false; - } - return true; - } - - bool CConsoleDebugger::ParseCPU(const char *str, CCPUDebug *&cpu) - { - if (str == NULL) - { - Error("Missing CPU name or number.\n"); - return false; - } - int cpuNum; - if (ParseInt(str, &cpuNum)) - { - if (cpuNum >= 0 && cpuNum < (int)cpus.size()) - { - cpu = cpus[cpuNum]; - return true; - } - } - cpu = GetCPU(str); - if (cpu == NULL) - { - Error("No CPU with that name or number.\n"); - return false; - } - return true; - } - - bool CConsoleDebugger::ParseRegister(const char *str, CRegister *®) - { - if (str == NULL) - { - Error("Missing register name.\n"); - return false; - } - reg = m_cpu->GetRegister(str); - if (reg == NULL) - { - Error("Enter a valid register name.\n"); - return false; - } - return true; - } - - void CConsoleDebugger::ListCPUs() - { - Print("CPUs:\n"); - if (cpus.size() == 0) - { - Print(" None\n"); - return; - } - - Print(" %-3s %-9s %-6s %-9s %-7s %-12s %-12s %-9s\n", "Num", "Name", "Type", "Debugging", "State", "Instr Count", "Total Cycles", "Frequency"); - unsigned num = 0; - double freq; - char onCPU; - const char *debugStr; - const char *stateStr; - for (vector::iterator it = cpus.begin(); it != cpus.end(); it++) - { - onCPU = (*it == m_cpu ? '*': ' '); - debugStr = ((*it)->IsEnabled() ? "Enabled" : "Disabled"); - stateStr = ((*it)->active ? "Running" : "Waiting"); - - if ((*it)->instrCount > 0) - { - if (frameCount > 0) - { - freq = ((*it)->cyclesPerPoll * 60.0) / 1000000.0; - Print("%c%-3u %-9s %-6s %-9s %-7s %12llu %12llu %6.1fMHz\n", onCPU, num++, (*it)->name, (*it)->type, debugStr, stateStr, (*it)->instrCount - 1, (*it)->totalCycles, freq); - } - else - Print("%c%-3u %-9s %-6s %-9s %-7s %12llu %12llu %9s\n", onCPU, num++, (*it)->name, (*it)->type, debugStr, stateStr, (*it)->instrCount - 1, (*it)->totalCycles, "-"); - } - else - Print("%c%-3u %-9s %-6s %-9s %-7s %12s %12s %9s\n", onCPU, num++, (*it)->name, (*it)->type, debugStr, stateStr, "-", "-", "-"); - } - } - - void CConsoleDebugger::ListRegisters() - { - Print("%s Registers:\n", m_cpu->name); - if (m_cpu->regs.size() == 0) - { - Print(" None\n"); - return; - } - - // Get groups - vector groups; - vector > regsByGroup; - size_t totalRows = 0; - for (vector::iterator it = m_cpu->regs.begin(); it != m_cpu->regs.end(); it++) - { - const char *group = (*it)->group; - // TODO - find with stricmp rather than default find - if (find(groups.begin(), groups.end(), group) == groups.end()) - { - groups.push_back(group); - regsByGroup.resize(regsByGroup.size() + 1); - } - int index = find(groups.begin(), groups.end(), group) - groups.begin(); - vector *pRegsInGroup = ®sByGroup[index]; - pRegsInGroup->push_back(*it); - totalRows = max(totalRows, pRegsInGroup->size()); - } - - // Get max label and value widths in each group and print group headers - size_t numGroups = groups.size(); - vector labelWidths(numGroups); - vector valueWidths(numGroups); - vector groupWidths(numGroups); - char valStr[50]; - Print(" "); - for (size_t index = 0; index < numGroups; index++) - { - labelWidths[index] = 0; - valueWidths[index] = 0; - - vector *pRegsInGroup = ®sByGroup[index]; - for (vector::iterator it = pRegsInGroup->begin(); it != pRegsInGroup->end(); it++) - { - labelWidths[index] = max(labelWidths[index], strlen((*it)->name)); - (*it)->GetValue(valStr); - valueWidths[index] = max(valueWidths[index], strlen(valStr)); - } - - const char *group = groups[index]; - groupWidths[index] = max(labelWidths[index] + valueWidths[index] + 3, strlen(group) + 1); - Print("%-*s", (int)groupWidths[index], group); - } - Print("\n"); - - // Print rows of register values - char rowStr[50]; - for (size_t row = 0; row < totalRows; row++) - { - Print(" "); - for (size_t index = 0; index < numGroups; index++) - { - vector *pRegsInGroup = ®sByGroup[index]; - if (row < pRegsInGroup->size()) - { - CRegister *reg = (*pRegsInGroup)[row]; - reg->GetValue(valStr); - bool hasMon = m_cpu->GetRegMonitor(reg->name) != NULL; - - sprintf(rowStr, "%c%-*s %-*s", (hasMon ? '*' : ' '), (int)labelWidths[index], reg->name, (int)valueWidths[index], valStr); - } - else - rowStr[0] = '\0'; - - Print("%-*s", (int)groupWidths[index], rowStr); - } - Print("\n"); - } - } - - void CConsoleDebugger::ListExceptions() - { - Print("%s Exceptions:\n", m_cpu->name); - if (m_cpu->exceps.size() == 0) - { - Print(" None\n"); - return; - } - - char addrStr[20]; - UINT32 handlerAddr; - for (vector::iterator it = m_cpu->exceps.begin(); it != m_cpu->exceps.end(); it++) - { - if (m_cpu->GetHandlerAddr(*it, handlerAddr)) - m_cpu->FormatAddress(addrStr, handlerAddr, true, (m_analyseCode ? LFExcepHandler : LFNone)); - else - addrStr[0] = '\0'; - Print("%c%-12s %-30s %-12s %u\n", ((*it)->trap ? '*' : ' '), (*it)->id, (*it)->name, addrStr, (*it)->count); - } - } - - void CConsoleDebugger::ListInterrupts() - { - Print("%s Interrupts:\n", m_cpu->name); - if (m_cpu->inters.size() == 0) - { - Print(" None\n"); - return; - } - - char addrStr[20]; - UINT32 handlerAddr; - for (vector::iterator it = m_cpu->inters.begin(); it != m_cpu->inters.end(); it++) - { - if (m_cpu->GetHandlerAddr(*it, handlerAddr)) - m_cpu->FormatAddress(addrStr, handlerAddr, true, (m_analyseCode ? LFInterHandler : LFNone)); - else - addrStr[0] = '\0'; - Print("%c%-12s %-30s %-12s %u\n", ((*it)->trap ? '*' : ' '), (*it)->id, (*it)->name, addrStr, (*it)->count); - } - } - - void CConsoleDebugger::ListIOs() - { - Print("%s I/O Ports:\n", m_cpu->name); - if (m_cpu->ios.size() == 0) - { - Print(" None\n"); - return; - } - - const char *group = NULL; - char locStr[255]; - char dirChar; - char inStr[50]; - char outStr[50]; - for (vector::iterator it = m_cpu->ios.begin(); it != m_cpu->ios.end(); it++) - { - // Print group heading if starting a new group - if (group == NULL || stricmp((*it)->group, group) != 0) - { - group = (*it)->group; - Print(" %s:\n", group); - } - - // Get location string (memory address or port number) - (*it)->GetLocation(locStr); - - // See whether port was last read or written - if ((*it)->inCount + (*it)->outCount > 0) - dirChar = ((*it)->last == &(*it)->lastIn ? '<' : '>'); - else - dirChar = ' '; - // Format last input - if ((*it)->inCount > 0) - m_cpu->FormatData(inStr, (*it)->dataSize, (*it)->lastIn); - else - { - inStr[0] = '*'; - inStr[1] = '\0'; - } - size_t inLen = strlen(inStr); - int inLPad = 5 - (int)inLen / 2; - int inRPad = 5 - (int)inLen + (int)inLen / 2; - // Format last output - if ((*it)->outCount > 0) - m_cpu->FormatData(outStr, (*it)->dataSize, (*it)->lastOut); - else - { - outStr[0] = '*'; - outStr[1] = '\0'; - } - size_t outLen = strlen(outStr); - int outLPad = 5 - (int)outLen / 2; - int outRPad = 5 - (int)outLen + (int)outLen / 2; - - // Print details - Print(" %c%-12s %-30s %-8s %*s%s%*s%c%*s%s%*s\n", ((*it)->watch != NULL ? '*' : ' '), locStr, (*it)->name, - GetDataSizeStr((*it)->dataSize, true), inLPad, "", inStr, inRPad, "", dirChar, outLPad, "", outStr, outRPad, ""); - } - } - - void CConsoleDebugger::ListRegions() - { - Print("%s Regions:\n", m_cpu->name); - if (m_cpu->regions.size() == 0) - { - Print(" None\n"); - return; - } - - char startStr[255]; - char endStr[255]; - for (vector::iterator it = m_cpu->regions.begin(); it != m_cpu->regions.end(); it++) - { - // Format start and end address - m_cpu->FormatAddress(startStr, (*it)->addr); - m_cpu->FormatAddress(endStr, (*it)->addrEnd); - - // Print details - Print("%c%s-%s %s\n", ((*it)->isCode ? '*' : ' '), startStr, endStr, (*it)->name); - } - } - - void CConsoleDebugger::ListLabels(bool customLabels, ELabelFlags autoLabelFlags) - { - Print("%s Labels:\n", m_cpu->name); - - unsigned count = 0; - - char addrStr[20]; - if (customLabels && m_cpu->labels.size() > 0) - { - Print(" Custom Labels:\n"); - for (vector::iterator it = m_cpu->labels.begin(); it != m_cpu->labels.end(); it++) - { - m_cpu->FormatAddress(addrStr, (*it)->addr); - Print(" %s %s\n", addrStr, (*it)->name); - count++; - } - } - - if (m_analyseCode) - { - char labelStr[255]; - CCodeAnalyser *analyser = m_cpu->GetCodeAnalyser(); - for (unsigned index = 0; index < CAutoLabel::numLabelFlags; index++) - { - ELabelFlags flag = CAutoLabel::GetLabelFlag(index); - if (!(autoLabelFlags & flag)) - continue; - vector withFlag = analyser->analysis->GetAutoLabels(flag); - if (withFlag.size() == 0) - continue; - const char *flagStr = CAutoLabel::GetFlagString(flag); - Print(" %ss:\n", flagStr); - for (vector::iterator it = withFlag.begin(); it != withFlag.end(); it++) - { - if (!(*it)->GetLabel(labelStr, flag)) - continue; - CBreakpoint *bp = m_cpu->GetBreakpoint((*it)->addr); - char bpChr = (bp != NULL ? bp->symbol : ' '); - m_cpu->FormatAddress(addrStr, (*it)->addr); - Print(" %c%s %s\n", bpChr, addrStr, labelStr); - count++; - } - } - } - - if (count == 0) - { - Print(" None\n"); - return; - } - } - - void CConsoleDebugger::GetAllMemWatches(vector &watches) - { - for (vector::iterator it = m_cpu->memWatches.begin(); it != m_cpu->memWatches.end(); it++) - watches.push_back(*it); - for (vector::iterator it = m_cpu->ioWatches.begin(); it != m_cpu->ioWatches.end(); it++) - { - if (dynamic_cast((*it)->io) != NULL) - watches.push_back(*it); - } - } - - int CConsoleDebugger::GetIndexOfMemWatch(CWatch *watch) - { - vector watches; - GetAllMemWatches(watches); - vector::iterator it = find(watches.begin(), watches.end(), watch); - if (it == watches.end()) - return -1; - return it - watches.begin(); - } - - void CConsoleDebugger::ListMemWatches() - { - Print("%s Memory Watches:\n", m_cpu->name); - - vector watches; - GetAllMemWatches(watches); - - if (watches.size() == 0) - { - Print(" None\n"); - return; - } - - Print(" %-3s %-8s %-12s %-5s %-4s %-20s %s\n", "Num", "Type", "Address", "Size", "Trig", "Value", "Info"); - - char typeStr[12]; - char addrStr[20]; - char sizeStr[20]; - const char *dSizeStr; - const char *trigStr; - char valStr[20]; - char infoStr[255]; - unsigned wNum = 0; - for (vector::iterator it = watches.begin(); it != watches.end(); it++) - { - UpperFirst(typeStr, (*it)->type); - m_cpu->FormatAddress(addrStr, (*it)->addr, true); - dSizeStr = GetDataSizeStr((*it)->size, false); - UpperFirst(sizeStr, dSizeStr); - if ((*it)->trigRead && (*it)->trigWrite) trigStr = "R/W"; - else if ((*it)->trigRead) trigStr = "R"; - else if ((*it)->trigWrite) trigStr = "W"; - else trigStr = "-"; - m_cpu->FormatData(valStr, (*it)->size, (*it)->GetValue()); - if (!(*it)->GetInfo(infoStr)) - { - infoStr[0] = '-'; - infoStr[1] = '\0'; - } - Print(" %-3u %-8s %-12s %-5s %-4s %-20s %s\n", wNum++, typeStr, addrStr, sizeStr, trigStr, valStr, infoStr); - } - } - - void CConsoleDebugger::GetAllPortWatches(vector &watches) - { - for (vector::iterator it = m_cpu->ioWatches.begin(); it != m_cpu->ioWatches.end(); it++) - { - if (dynamic_cast((*it)->io) != NULL) - watches.push_back(*it); - } - } - - int CConsoleDebugger::GetIndexOfPortWatch(CWatch *watch) - { - vector watches; - GetAllPortWatches(watches); - vector::iterator it = find(watches.begin(), watches.end(), watch); - if (it == watches.end()) - return -1; - return it - watches.begin(); - } - - void CConsoleDebugger::ListPortWatches() - { - Print("%s I/O Port Watches:\n", m_cpu->name); - - vector watches; - GetAllPortWatches(watches); - - if (watches.size() == 0) - { - Print(" None\n"); - return; - } - - Print(" %-3s %-8s %-12s %-4s %-20s %s\n", "Num", "Type", "Location", "Trig", "Last In/Out", "Info"); - - char typeStr[12]; - char locStr[255]; - const char *trigStr; - char valStr[20]; - char infoStr[255]; - unsigned wNum = 0; - for (vector::iterator it = watches.begin(); it != watches.end(); it++) - { - UpperFirst(typeStr, (*it)->type); - (*it)->io->GetLocation(locStr); - if ((*it)->trigRead && (*it)->trigWrite) trigStr = "I/O"; - else if ((*it)->trigRead) trigStr = "I"; - else if ((*it)->trigWrite) trigStr = "O"; - else trigStr = "-"; - if ((*it)->readCount + (*it)->writeCount == 0) - { - valStr[0] = '-'; - valStr[1] = '\0'; - } - else - m_cpu->FormatData(valStr, (*it)->size, (*it)->GetValue()); - if (!(*it)->GetInfo(infoStr)) - { - infoStr[0] = '-'; - infoStr[1] = '\0'; - } - Print(" %-3u %-8s %-12s %-4s %-20s %s\n", wNum++, typeStr, locStr, trigStr, valStr, infoStr); - } - } - - void CConsoleDebugger::ListBreakpoints() - { - Print("%s Breakpoints:\n", m_cpu->name); - if (m_cpu->bps.size() == 0) - { - Print(" None\n"); - return; - } - - Print(" %-3s %-8s %-12s %-20s\n", "Num", "Type", "Address", "Info"); - - char typeStr[12]; - char addrStr[20]; - char infoStr[255]; - for (vector::iterator it = m_cpu->bps.begin(); it != m_cpu->bps.end(); it++) - { - UpperFirst(typeStr, (*it)->type); - m_cpu->FormatAddress(addrStr, (*it)->addr, true, (m_analyseCode ? LFAll : LFNone)); - if (!(*it)->GetInfo(infoStr)) - { - infoStr[0] = '-'; - infoStr[1] = '\0'; - } - Print(" %-3u %-8s %-12s %-20s\n", (*it)->num, typeStr, addrStr, infoStr); - } - } - - void CConsoleDebugger::ListMonitors() - { - Print("%s Register Monitors:\n", m_cpu->name); - if (m_cpu->regMons.size() == 0) - { - Print(" None\n"); - return; - } - - char valStr[255]; - int num = 0; - for (vector::iterator it = m_cpu->regMons.begin(); it != m_cpu->regMons.end(); it++) - { - (*it)->GetBeforeValue(valStr); - Print(" %d - %s change from: %s\n", num++, (*it)->reg->name, valStr); - } - } - - UINT32 CConsoleDebugger::ListDisassembly(UINT32 start, UINT32 end, unsigned numInstrs) - { - UINT32 addr; - char startStr[20]; - char endStr[20]; - char opCodes[50]; - char mnemonic[100]; - char operands[155]; - char addrStr[20]; - char labelStr[13]; - unsigned instr; - - UINT32 pc = m_cpu->pc; - CCodeAnalyser *analyser = (m_analyseCode ? m_cpu->GetCodeAnalyser() : NULL); - - // Align address to instruction boundary - start -= start%m_cpu->minInstrLen; - - if (analyser != NULL) - { - // Use code analyser to find valid start address - if (!analyser->analysis->GetNextValidAddr(start)) - return start; - } - else - { - // In the absence of code analyser, try to align code with current PC address - if (m_cpu->instrCount > 0 && pc >= start && pc <= end) - { - unsigned count = m_cpu->instrCount; - while (start < end && count-- > 0) - { - bool okay = false; - addr = start; - instr = 0; - while (addr < end && instr < numInstrs) - { - if (addr == pc) - { - okay = true; - break; - } - int codesLen = m_cpu->GetOpLength(addr); - addr += abs(codesLen); - instr++; - } - if (okay) - break; - start += m_cpu->minInstrLen; - } - } - } - - // Get true end address - addr = start; - instr = 0; - while (addr < end && instr < numInstrs) - { - // Get instruction length - int codesLen = m_cpu->Disassemble(addr, mnemonic, operands); - // Move onto next valid instruction address - addr += abs(codesLen); - if (analyser != NULL && !analyser->analysis->GetNextValidAddr(addr)) - break; - instr++; - } - end = addr; - - // Format start and end addresses and output title - m_cpu->FormatAddress(startStr, start); - m_cpu->FormatAddress(endStr, end); - Print("%s Code %s - %s:\n", m_cpu->name, startStr, endStr); - - // Output the disassembly - addr = start; - instr = 0; - while (addr < end) - { - // Add markers for current PC address and any breakpoints - char ind[4]; - if (m_cpu->instrCount > 0 && addr == pc) - { - ind[0] = '>'; - ind[1] = '>'; - } - else - { - ind[0] = ' '; - ind[1] = ' '; - } - CBreakpoint *bp = m_cpu->GetBreakpoint(addr); - ind[2] = (bp != NULL ? bp->symbol : ' '); - ind[3] = '\0'; - - // Format current address - m_cpu->FormatAddress(addrStr, addr); - - // Get labels at address (if any) - bool hasLabel = GetLabelText(labelStr, 12, addr); - - // Get mnemonic, operands and instruction length and print them - int codesLen = m_cpu->Disassemble(addr, mnemonic, operands); - FormatOpCodes(opCodes, addr, abs(codesLen)); - - // Get comment at address (if any) - CComment *comment = m_cpu->GetComment(addr); - - // Output line - Print("%s", ind); - if (m_showLabels) - { - if (m_labelsOverAddr) - Print("%-12s ", (hasLabel ? labelStr : addrStr)); - else - Print("%s %-12s ", addrStr, labelStr); - } - else - Print("%s ", addrStr); - if (m_showOpCodes) - Print("[%s] ", opCodes); - if (codesLen > 0) - Print("%-*s %-20s", (int)m_cpu->maxMnemLen, mnemonic, operands); - else - Print("???"); - if (comment != NULL) - Print(" ; %s", comment->text); - Print("\n"); - - // Move onto next valid instruction address - addr += abs(codesLen); - if (analyser != NULL && !analyser->analysis->GetNextValidAddr(addr)) - break; - } - return end; - } - - UINT32 CConsoleDebugger::ListMemory(UINT32 start, UINT32 end, unsigned bytesPerRow) - { - char startStr[255]; - char endStr[255]; - char addrStr[20]; - char labelStr[13]; - char wChar, dChar; - UINT8 data; - - // Adjust start/end points to be on row boundary - start -= (start % bytesPerRow); - end += bytesPerRow - (end % bytesPerRow); - - // Format start and end addresses and output title - m_cpu->FormatAddress(startStr, start); - m_cpu->FormatAddress(endStr, end); - Print("%s Memory %s - %s:\n", m_cpu->name, startStr, endStr); - - UINT32 addr = start; - while (addr < end) - { - // TODO - check address going out of region or out of range - - // Format current address - m_cpu->FormatAddress(addrStr, addr); - - // Get labels at address (if any) - bool hasLabel = GetLabelText(labelStr, 12, addr); - - // Output line - if (m_showLabels) - { - if (m_labelsOverAddr) - Print(" %-12s", (hasLabel ? labelStr : addrStr)); - else - Print(" %s %-12s", addrStr, labelStr); - } - else - Print(" %s%c", addrStr); - UINT32 lAddr = addr; - for (unsigned i = 0; i < bytesPerRow; i++) - { - CWatch *watch = m_cpu->GetMemWatch(lAddr, 1); - // TODO - handling of mapped I/O - //CMappedIO *io = m_cpu->GetMappedIO(lAddr); - wChar = (watch != NULL ? watch->symbol : ' '); - //if (io != NULL) - // data = (UINT8)io->last; - //else - data = (UINT8)m_cpu->ReadMem(lAddr, 1); - Print("%c%02X", wChar, data); - lAddr++; - } - Print(" "); - lAddr = addr; - for (unsigned i = 0; i < bytesPerRow; i++) - { - // TODO - handling of mapped I/O - //CMappedIO *io = m_cpu->GetMappedIO(lAddr); - //if (io != NULL) - // data = io->last; - //else - data = (UINT8)m_cpu->ReadMem(lAddr, 1); - dChar = (data >= 32 && data <= 126 ? (char)data : '.'); - Print("%c", dChar); - lAddr++; - } - Print("\n"); - addr += bytesPerRow; - } - return addr; - } - - void CConsoleDebugger::AnalysisUpdated(CCodeAnalyser *analyser) - { - // - } - - void CConsoleDebugger::ExceptionTrapped(CException *ex) - { - PrintEvent(ex->cpu, "Exception %s (%s) trapped.\n", ex->id, ex->name); - } - - void CConsoleDebugger::InterruptTrapped(CInterrupt *in) - { - PrintEvent(in->cpu, "Interrupt %s (%s) trapped.\n", in->id, in->name); - } - - void CConsoleDebugger::MemWatchTriggered(CWatch *watch, UINT32 addr, unsigned dataSize, UINT64 data, bool isRead) - { - const char *sizeStr = GetDataSizeStr(dataSize, true); - const char *rwStr = (isRead ? "Read from" : "Write to"); - char dataStr[50]; - char addrStr[255]; - m_cpu->FormatData(dataStr, dataSize, data); - watch->cpu->FormatAddress(addrStr, addr, true); - int num = GetIndexOfMemWatch(watch); - PrintEvent(watch->cpu, "%s %s (%s.%s) triggered memory watch #%d.\n", rwStr, addrStr, dataStr, sizeStr, num); - } - - void CConsoleDebugger::IOWatchTriggered(CWatch *watch, CIO *io, UINT64 data, bool isInput) - { - const char *sizeStr = GetDataSizeStr(io->dataSize, true); - const char *ioStr = (isInput ? "Input from" : "Output to"); - char dataStr[50]; - char locStr[255]; - m_cpu->FormatData(dataStr, io->dataSize, data); - watch->io->GetLocation(locStr); - int num = GetIndexOfPortWatch(watch); - if (num >= 0) - PrintEvent(watch->cpu, "%s %s (%s.%s) triggered port watch #%d.\n", ioStr, locStr, dataStr, sizeStr, num); - else - { - num = GetIndexOfMemWatch(watch); - PrintEvent(watch->cpu, "%s %s (%s.%s) triggered memory watch #%d.\n", ioStr, locStr, dataStr, sizeStr, num); - } - } - - void CConsoleDebugger::BreakpointReached(CBreakpoint *bp) - { - PrintEvent(bp->cpu, "Breakpoint #%d triggered.\n", bp->num); - } - - void CConsoleDebugger::MonitorTriggered(CRegMonitor *regMon) - { - char valStr[255]; - CRegister *reg = regMon->reg; - reg->GetValue(valStr); - PrintEvent(reg->cpu, "Write to register %s (%s) triggered monitor.\n", reg->name, valStr); - } - - void CConsoleDebugger::ExecutionHalted(CCPUDebug *cpu, EHaltReason reason) - { - if (reason&HaltUser) - PrintEvent(cpu, "Execution halted.\n"); - } - - void CConsoleDebugger::Log(CCPUDebug *cpu, const char *typeStr, const char *fmtStr, va_list vl) - { - if (cpu != NULL) - { - char pcStr[255]; - cpu->FormatAddress(pcStr, cpu->pc, true, LFNone); - Print("%s @ %s: ", cpu->name, pcStr); - } - if (typeStr != NULL) - Print(" %s - ", typeStr); - PrintVL(fmtStr, vl); - } - - void CConsoleDebugger::Attach() - { - CDebugger::Attach(); - - ApplyConfig(); - - Attached(); - } - - void CConsoleDebugger::Detach() - { - Detaching(); - - CDebugger::Detach(); - - // Close redirected output file, if exists - if (m_file != NULL) + m_file = NULL; + } + + // Get details for current PC address + bool hasLabel; + if (m_cpu->instrCount > 0) + { + m_cpu->FormatAddress(addrStr, pc); + hasLabel = GetLabelText(labelStr, 12, pc); + codesLen = m_cpu->Disassemble(pc, mnemonic, operands); + FormatOpCodes(opCodes, pc, abs(codesLen)); + } + else + { + addrStr[0] = '-'; + addrStr[1] = '\0'; + hasLabel = false; + labelStr[0] = '\0'; + opCodes[0] = '-'; + opCodes[1] = '\0'; + codesLen = 0; + } + CBreakpoint *bp = m_cpu->GetBreakpoint(pc); + bpChr = (bp != NULL ? bp->symbol : ' '); + + // Output command prompt + Print("%s%c", m_cpu->name, bpChr); + if (m_showLabels) + { + if (m_labelsOverAddr) + Print("%-12s ", (hasLabel ? labelStr : addrStr)); + else + Print("%s %-12s ", addrStr, labelStr); + } + else + Print("%s ", addrStr); + if (m_showOpCodes) + Print("[%s] ", opCodes); + if (codesLen > 0) + Print("%-*s %s > ", (int)m_cpu->maxMnemLen, mnemonic, operands); + else + Print("??? > "); + Flush(); + + // Wait for command + Read(cmd, 255); + + if (cmd[0] == '\0') + { + m_cpu->SetStepMode(StepInto); + break; + } + + // Check for redirection + char *pos = strchr(cmd, '>'); + if (pos != NULL) + { + *pos = '\0'; + pos++; + const char *mode; + if (*pos == '>') + { + mode = "ab"; + pos++; + } + else + mode = "w"; + while (*pos == ' ') + pos++; + if (*pos != '\0') + { + m_file = fopen(pos, mode); + if (m_file == NULL) + { + Error("Unable to direct output to file %s\n", pos); + continue; + } + } + else + { + Error("Missing file to direct output to\n"); + continue; + } + } + + char *token = strtok(cmd, " "); + if (ProcessToken(token, cmd)) + break; + + pc = m_cpu->pc; + } + } + + bool CConsoleDebugger::ProcessToken(const char *token, const char *cmd) + { + UINT32 pc = m_cpu->pc; + + int number; + unsigned size; + const char *sizeStr; + UINT32 addr; + UINT16 portNum; + UINT64 data; + char addrStr[50]; + char portNumStr[50]; + char dataStr[50]; + char mod[10]; + EFormat fmt; + + // + // Execution + // + if (CheckToken(token, "n", "next")) // next [=1] + { + // Parse arguments + token = strtok(NULL, " "); + if (token != NULL) + { + if (!ParseInt(token, &number) || number <= 0) + { + Error("Enter a valid instruction count.\n"); + return false; + } + + if (number > 1) + Print("Running %d instructions.\n", number); + m_cpu->SetCount(number); + } + else + m_cpu->SetStepMode(StepInto); + return true; + } + else if (CheckToken(token, "nf", "nextframe")) // nextframe [=1] + { + // Parse arguments + token = strtok(NULL, " "); + if (token != NULL) + { + if (!ParseInt(token, &number) || number <= 0) + { + Error("Enter a valid frame count.\n"); + return false; + } + + if (number > 1) + Print("Running %d frames.\n", number); + m_nextFrameCount = number; + } + else + m_nextFrameCount = 1; + m_nextFrame = true; + return true; + } + else if (CheckToken(token, "s", "stepover")) // stepover + { + m_cpu->SetStepMode(StepOver); + return true; + } + else if (CheckToken(token, "si", "stepinto")) // stepinto + { + m_cpu->SetStepMode(StepInto); + return true; + } + else if (CheckToken(token, "so", "stepout")) // stepout + { + m_cpu->SetStepMode(StepOut); + return true; + } + else if (CheckToken(token, "c", "continue")) // continue [] + { + // Parse arguments + token = strtok(NULL, " "); + if (token != NULL) + { + if (!ParseAddress(token, &addr)) + { + Error("Enter a valid address.\n"); + return false; + } + + m_cpu->FormatAddress(addrStr, addr); + Print("Continuing until %s.\n", addrStr); + m_cpu->SetUntil(addr); + } + else + m_cpu->SetContinue(); + return true; + } + else if (CheckToken(token, "spc", "setpc")) // setpc + { + // Parse arguments + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing address.\n"); + return false; + } + if (!ParseAddress(token, &addr)) + { + Error("Enter a valid address.\n"); + return false; + } + + if (!m_cpu->SetPC(addr)) + { + Error("Unable to set PC.\n"); + return false; + } + + m_cpu->FormatAddress(addrStr, addr); + Print("PC set to %s.\n", addrStr); + return true; + } + // + // CPUs + // + else if (CheckToken(token, "lc", "listcpus")) // listcpus + { + ListCPUs(); + } + else if (CheckToken(token, "sc", "switchcpu")) // switchcpu (|) + { + // Parse arguments + token = strtok(NULL, " "); + CCPUDebug *cpu; + if (!ParseCPU(token, cpu)) + return false; + + if (!cpu->IsEnabled()) + { + Error("CPU %s is currently disabled for debugging.\n", cpu->name); + return false; + } + + m_cpu = cpu; + pc = cpu->pc; + m_listDism = (cpu->instrCount > 0 && pc > 10 * cpu->minInstrLen ? pc - 10 * cpu->minInstrLen : 0); + return false; + } + else if (CheckToken(token, "dc", "disablecpu")) // disablecpu (|) + { + // Parse arguments + token = strtok(NULL, " "); + CCPUDebug *cpu; + if (!ParseCPU(token, cpu)) + return false; + + if (cpu == m_cpu) + { + Error("Cannot enable/disable debugging on current CPU.\n"); + return false; + } + cpu->SetEnabled(false); + Print("Disabled debugging on CPU %s.\n", cpu->name); + } + else if (CheckToken(token, "ec", "enablecpu")) // enablecpu (|) + { + // Parse arguments + token = strtok(NULL, " "); + CCPUDebug *cpu; + if (!ParseCPU(token, cpu)) + return false; + + if (cpu == m_cpu) + { + Error("Cannot enable/disable debugging on current CPU.\n"); + return false; + } + cpu->SetEnabled(true); + Print("Enabled debugging on CPU %s.\n", cpu->name); + } + // + // Registers + // + else if (CheckToken(token, "lr", "listregisters")) // listregisters + { + ListRegisters(); + } + else if (CheckToken(token, "pr", "printregister")) // printregister + { + // Parse arguments + token = strtok(NULL, " "); + CRegister *reg; + if (!ParseRegister(token, reg)) + return false; + + reg->GetValue(dataStr); + Print("Register %s = %s\n", reg->name, dataStr); + } + else if (CheckToken(token, "sr", "setregister")) // setregister + { + // Parse arguments + token = strtok(NULL, " "); + CRegister *reg; + if (!ParseRegister(token, reg)) + return false; + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing value to set.\n"); + return false; + } + + if (!reg->SetValue(token)) + { + Error("Unable to set value of register %s.\n", reg->name); + return false; + } + reg->GetValue(dataStr); + Print("Set register %s to %s.\n", reg->name, dataStr); + } + else if (CheckToken(token, "lm", "listmonitors")) // listmonitors + { + ListMonitors(); + } + else if (CheckToken(token, "m", "monitor") || // addmonitor + CheckToken(token, "am", "addmonitor")) + { + // Parse arguments + token = strtok(NULL, " "); + CRegister *reg; + if (!ParseRegister(token, reg)) + return false; + + m_cpu->AddRegMonitor(reg->name); + Print("Monitor added to register %s.\n", reg->name); + } + else if (CheckToken(token, "rm", "removemonitor")) // removemonitor + { + // Parse arguments + token = strtok(NULL, " "); + CRegister *reg; + if (!ParseRegister(token, reg)) + return false; + + m_cpu->RemoveRegMonitor(reg->name); + Print("Monitor for register %s removed.\n", reg->name); + } + else if (CheckToken(token, "ram", "removeallmonitors")) // removeallmonitors + { + m_cpu->RemoveAllRegMonitors(); + Print("All register monitors removed.\n"); + } + // + // Exceptions & interrupts + // + else if (CheckToken(token, "le", "listexceptions")) // listexceptions + { + ListExceptions(); + } + else if (CheckToken(token, "li", "listinterrupts")) // listinterrupts + { + ListInterrupts(); + } + else if (CheckToken(token, "t", "trap") || // addtrap ((e)xception|(i)nterrupt) + CheckToken(token, "at", "addtrap")) + { + // Parse arguments + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing type (e)xception or (i)interrupt\n"); + return false; + } + + if (CheckToken(token, "e", "exception")) + { + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing exception id.\n"); + return false; + } + CException *ex = m_cpu->GetException(token); + if (ex == NULL) + { + Error("Enter a valid exception id.\n"); + return false; + } + + ex->trap = true; + Print("Trap added for exceptions of type %s.\n", ex->id); + } + else if (CheckToken(token, "i", "interrupt")) + { + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing interrupt id.\n"); + return false; + } + CInterrupt *in = m_cpu->GetInterrupt(token); + if (in == NULL) + { + Error("Enter a valid interrupt id.\n"); + return false; + } + + in->trap = true; + Print("Trap added for interrupts of type %s.\n", in->id); + } + else + { + Error("Enter valid type (e)xception or (i)interrupt.\n"); + return false; + } + } + else if (CheckToken(token, "rt", "removetrap")) // removetrap ((e)xception|(i)nterrupt) + { + // Parse arguments + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing type (e)xception or (i)interrupt.\n"); + return false; + } + + if (CheckToken(token, "e", "exception")) + { + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing exception id.\n"); + return false; + } + CException *ex = m_cpu->GetException(token); + if (ex == NULL) + { + Error("Enter a valid exception id.\n"); + return false; + } + + ex->trap = false; + Print("Trap for exceptions of type %s removed.\n", ex->id); + } + else if (CheckToken(token, "i", "interrupt")) + { + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing interrupt id.\n"); + return false; + } + CInterrupt *in = m_cpu->GetInterrupt(token); + if (in == NULL) + { + Error("Enter a valid interrupt id.\n"); + return false; + } + + in->trap = false; + Print("Trap for interrupts ot type %s removed.\n", in->id); + } + else + { + Error("Enter a valid type (e)xception or (i)interrupt.\n"); + return false; + } + } + else if (CheckToken(token, "rat", "removealltraps")) // removealltraps [(a)ll|(e)xceptions|(i)nterrupts] + { + bool removeExs; + bool removeInts; + const char *coverage; + if (token == NULL || CheckToken(token, "a", "all")) + { + removeExs = true; + removeInts = true; + coverage = "exceptions and interrupts"; + } + else if (CheckToken(token, "e", "exceptions")) + { + removeExs = true; + removeInts = false; + coverage = "exceptions"; + } + else if (CheckToken(token, "i", "interrupts")) + { + removeExs = false; + removeInts = true; + coverage = "interrupts"; + } + else + { + Error("Enter a valid mode (a)ll, (e)xceptions or (i)nterrupts\n"); + return false; + } + + if (removeExs) + { + for (vector::iterator it = m_cpu->exceps.begin(); it != m_cpu->exceps.end(); it++) + (*it)->trap = false; + } + if (removeInts) + { + for (vector::iterator it = m_cpu->inters.begin(); it != m_cpu->inters.end(); it++) + (*it)->trap = false; + } + Print("All traps for %s removed.\n", coverage); + } + // + // Disassembly, labels & comments + // + else if (CheckToken(token, "l", "list") || // listdisassembly [=last [#=20|]] + CheckToken(token, "ld", "listdisassembly")) + { + // Get start address + UINT32 start; + token = strtok(NULL, " "); + if (token == NULL) + token = "last"; + if (stricmp(token, "last") == 0) + { + // Use end of last listing + start = m_listDism; + } + else if (!ParseAddress(token, &start)) + { + Error("Enter a valid start address.\n"); + return false; + } + + // Get end address + UINT32 end; + unsigned numInstrs; + token = strtok(NULL, " "); + if (token != NULL) + { + if (token[0] == '#') + { + if (!ParseInt(token + 1, &number) || number <= 0) + { + Error("Enter a valid number of instructions.\n"); + return false; + } + numInstrs = (unsigned)number; + end = 0xFFFFFFFF; + } + else + { + if (!ParseAddress(token, &end)) + { + Error("Enter a valid end address.\n"); + return false; + } + numInstrs = 0xFFFFFFFF; + } + } + else + { + // Default is 20 instructions after start + end = 0xFFFFFFFF; + numInstrs = 20; + } + + // List the disassembled code + m_listDism = ListDisassembly(start, end, numInstrs); + } + else if (CheckToken(token, "ll", "listlabels")) // listlabels [(d)efault|(c)ustom|(a)utos|(e)ntrypoints|e(x)cephandlers|(i)interhandlers|(j)umptargets|(l)ooppoints] + { + // Parse arguments + token = strtok(NULL, " "); + bool customLabels; + ELabelFlags labelFlags; + if (token == NULL || CheckToken(token, "d", "default")) + { + customLabels = true; + labelFlags = (ELabelFlags)(LFEntryPoint | LFExcepHandler | LFInterHandler | LFSubroutine); + } + else if (CheckToken(token, "c", "custom")) + { + customLabels = true; + labelFlags = LFNone; + } + else if (CheckToken(token, "a", "autos")) + { + customLabels = true; + labelFlags = (ELabelFlags)(LFEntryPoint | LFExcepHandler | LFInterHandler | LFSubroutine | LFJumpTarget | LFLoopPoint); + } + else if (CheckToken(token, "e", "entrypoints")) + { + customLabels = false; + labelFlags = LFEntryPoint; + } + else if (CheckToken(token, "x", "excephandlers")) + { + customLabels = false; + labelFlags = LFExcepHandler; + } + else if (CheckToken(token, "i", "interhandlers")) + { + customLabels = false; + labelFlags = LFInterHandler; + } + else if (CheckToken(token, "s", "subroutines")) + { + customLabels = false; + labelFlags = LFSubroutine; + } + else if (CheckToken(token, "j", "jumptargets")) + { + customLabels = false; + labelFlags = LFJumpTarget; + } + else if (CheckToken(token, "l", "looppoints")) + { + customLabels = false; + labelFlags = LFLoopPoint; + } + else + { + Error("Enter a valid filter (a)ll, (c)ustom, (e)ntrypoints, e(x)cephandlers, (i)interhandlers, (j)umptargets or (l)ooppoints.\n"); + return false; + } + + ListLabels(customLabels, labelFlags); + } + else if (CheckToken(token, "al", "addlabel")) // addlabel + { + // Parse arguments + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing label address.\n"); + return false; + } + else if (!ParseAddress(token, &addr)) + { + Error("Enter a valid label address.\n"); + return false; + } + + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing label name.\n"); + return false; + } + const char *name = token; + + // Add label + CLabel *label = m_cpu->AddLabel(addr, name); + m_cpu->FormatAddress(addrStr, label->addr); + Print("Label %s added at %s.\n", label->name, addrStr); + } + else if (CheckToken(token, "rl", "removelabel")) // removelabel [|] + { + // Parse arguments + token = strtok(NULL, " "); + if (token == NULL) + token = "-"; + + if (!ParseAddress(token, &addr)) + { + Error("Enter a valid label name or address.\n"); + return false; + } + + CLabel *label = m_cpu->GetLabel(addr); + if (label == NULL) + { + m_cpu->FormatAddress(addrStr, addr); + Error("No label at %s.\n", addrStr); + return false; + } + + const char *name = label->name; + m_cpu->FormatAddress(addrStr, label->addr); + Print("Custom label '%s' removed at address %s.\n", name, addrStr); + } + else if (CheckToken(token, "ral", "removealllabels")) // removealllabels + { + m_cpu->RemoveAllLabels(); + Print("All custom labels removed.\n"); + } + else if (CheckToken(token, "ac", "addcomment")) // addcomment + { + // Parse arguments + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing comment address.\n"); + return false; + } + else if (!ParseAddress(token, &addr)) + { + Error("Enter a valid comment address.\n"); + return false; + } + + char text[255]; + text[0] = '\0'; + token = strtok(NULL, " "); + while (token != NULL) + { + size_t len = strlen(text); + if (len + strlen(token) > 253) + break; + if (len > 0) + strcat(text, " "); + strcat(text, token); + token = strtok(NULL, " "); + } + if (text[0] == '\0') + { + Error("Missing comment text.\n"); + return false; + } + + // Add comment + CComment *comment = m_cpu->AddComment(addr, text); + m_cpu->FormatAddress(addrStr, comment->addr); + Print("Comment added at %s.\n", addrStr); + } + else if (CheckToken(token, "rc", "removecomment")) // removecomment [] + { + // Parse arguments + token = strtok(NULL, " "); + if (token == NULL) + token = "-"; + if (!ParseAddress(token, &addr)) + { + Error("Enter a valid comment address.\n"); + return false; + } + + m_cpu->FormatAddress(addrStr, addr); + if (m_cpu->RemoveComment(addr)) + Print("Comment at address %s removed.\n", addrStr); + else + Error("No comment at address %s.\n", addrStr); + } + else if (CheckToken(token, "rac", "removeallcomments")) // removeallcomments + { + m_cpu->RemoveAllComments(); + Print("All comments removed.\n"); + } + // + // Breakpoints + // + else if (CheckToken(token, "lb", "listbreakpoints")) // listbreakpoints + { + ListBreakpoints(); + } + else if (CheckToken(token, "b", "breakpoint") || // addbreakpoint [ [[s)imple|(c)ount )]] + CheckToken(token, "ab", "addbreakpoint")) + { + // Parse arguments + token = strtok(NULL, " "); + if (token == NULL) + token = "-"; + if (!ParseAddress(token, &addr)) + { + Error("Enter a valid address.\n"); + return false; + } + token = strtok(NULL, " "); + CBreakpoint *bp; + if (token == NULL || CheckToken(token, "s", "simple")) + bp = m_cpu->AddSimpleBreakpoint(addr); + else if (CheckToken(token, "c", "count")) + { + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing count.\n"); + return false; + } + int count; + if (!ParseInt(token, &count) || count <= 0) + { + Error("Enter a valid count.\n"); + return false; + } + + bp = m_cpu->AddCountBreakpoint(addr, count); + } + else if (CheckToken(token, "p", "print")) + bp = m_cpu->AddPrintBreakpoint(addr); + else + { + Error("Enter a valid breakpoint type (s)imple or (c)ount.\n"); + return false; + } + + m_cpu->FormatAddress(addrStr, bp->addr); + Print("Breakpoint #%d added at address %s.\n", bp->num, addrStr); + } + else if (CheckToken(token, "rb", "removebreakpoint")) // removebreakpoint [#|] + { + // Parse arguments + token = strtok(NULL, " "); + if (token == NULL) + token = "-"; + if (token[0] == '#') + { + // Remove breakpoint by number + if (!ParseInt(token + 1, &number) || number < 0 || number >= m_cpu->bps.size()) + { + Error("Enter a valid breakpoint number.\n"); + return false; + } + + // Remove breakpoint + m_cpu->RemoveBreakpoint(m_cpu->bps[number]); + Print("Breakpoint #%d removed.\n", number); + } + else + { + // Remove breakpoint by address + if (!ParseAddress(token, &addr)) + { + Error("Enter a valid address.\n"); + return false; + } + + // Remove breakpoint + m_cpu->FormatAddress(addrStr, addr); + if (m_cpu->RemoveBreakpoint(addr)) + Print("Breakpoint at address %s removed.\n", addrStr); + else + Error("No breakpoint at address %s.\n", addrStr); + } + } + else if (CheckToken(token, "rab", "removeallbreakpoints")) // removeallbreakpoints + { + m_cpu->RemoveAllBreakpoints(); + Print("All breakpoints removed.\n"); + } + // + // Memory, I/O & watches + // + else if (CheckToken(token, "ln", "listregions")) // listregions + { + ListRegions(); + } + else if (CheckToken(token, "ly", "listmemory")) // listmemory [=last [#=8|]] + { + // Get start address + UINT32 start; + token = strtok(NULL, " "); + if (token == NULL) + token = "last"; + if (stricmp(token, "last") == 0) + { + // Use end of last listing + start = m_listMem; + } + else if (!ParseAddress(token, &start)) + { + Error("Enter a valid start address.\n"); + return false; + } + + // Get end address + UINT32 end; + token = strtok(NULL, " "); + if (token != NULL) + { + if (token[0] == '#') + { + if (!ParseInt(token + 1, &number) || number <= 0) + { + Error("Enter a valid number of rows.\n"); + return false; + } + end = start + number * m_memBytesPerRow; + } + else + { + if (!ParseAddress(token, &end)) + { + Error("Enter a valid end address.\n"); + return false; + } + } + } + else + // Default is 8 rows after start + end = start + 8 * m_memBytesPerRow; + + // List the memory + m_listMem = ListMemory(start, end, m_memBytesPerRow); + } + else if (CheckToken(token, "py", "printmemory", mod, 9, "b")) // printmemory[.=b] [(h)ex|hexdo(l)lar|hex(p)osth|(d)ecimal|(b)inary] + { + // Parse arguments + if (!ParseDataSize(mod, size)) + return false; + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing address.\n"); + return false; + } + if (!ParseAddress(token, &addr)) + { + Error("Enter a valid address.\n"); + return false; + } + token = strtok(NULL, " "); + if (token != NULL) + { + if (!ParseFormat(token, fmt)) + return false; + } + else + fmt = m_dataFmt; + + // Read and print memory + char uSizeStr[12]; + sizeStr = GetDataSizeStr(size, false); + UpperFirst(uSizeStr, sizeStr); + data = m_cpu->ReadMem(addr, size); + FormatData(dataStr, fmt, size, data); + m_cpu->FormatAddress(addrStr, addr); + Print("%s data at %s = %s.\n", uSizeStr, addrStr, dataStr); + } + else if (CheckToken(token, "sy", "setmemory", mod, 9, "b")) // setmemory[.=b] + { + // Parse arguments + if (!ParseDataSize(mod, size)) + return false; + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing address.\n"); + return false; + } + if (!ParseAddress(token, &addr)) + { + Error("Enter a valid address.\n"); + return false; + } + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing value to set.\n"); + return false; + } + sizeStr = GetDataSizeStr(size, false); + if (!m_cpu->ParseData(token, size, &data)) + { + Error("Enter a valid %s value.\n", sizeStr); + return false; + } + + // Set memory + char uSizeStr[12]; + UpperFirst(uSizeStr, sizeStr); + m_cpu->WriteMem(addr, size, data); + m_cpu->FormatData(dataStr, size, data); + m_cpu->FormatAddress(addrStr, addr); + Print("Set %s data at %s to %s.\n", uSizeStr, addrStr, dataStr); + } + else if (CheckToken(token, "lo", "listios")) // listios + { + ListIOs(); + } + else if (CheckToken(token, "lw", "listmemwatches")) // listmemwatches + { + ListMemWatches(); + } + else if (CheckToken(token, "w", "memwatch", mod, 9, "b") || // addmemwatch[.=b] [((n)one|(r)ead|(w)rite|(rw)eadwrite) [((s)imple|(c)ount |(m)atch |captu(r)e |(p)rint)]] + CheckToken(token, "aw", "addmemwatch", mod, 9, "b")) + { + // Parse arguments + if (!ParseDataSize(mod, size)) + return false; + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing address.\n"); + return false; + } + if (!ParseAddress(token, &addr)) + { + Error("Enter a valid address.\n"); + return false; + } + token = strtok(NULL, " "); + bool read; + bool write; + if (token == NULL || CheckToken(token, "n", "none")) + { + read = false; + write = false; + } + else if (CheckToken(token, "r", "read")) + { + read = true; + write = false; + } + else if (CheckToken(token, "w", "write")) + { + read = false; + write = true; + } + else if (CheckToken(token, "rw", "read/write") || CheckToken(token, "wr", "write/read")) + { + read = true; + write = true; + } + else + { + Error("Enter valid read/write flags (n)one, (r)ead, (w)rite or (rw)ead/write.\n"); + return false; + } + + // Add mem watch + CWatch *watch; + token = strtok(NULL, " "); + if (token == NULL || CheckToken(token, "s", "simple")) + watch = m_cpu->AddSimpleMemWatch(addr, size, read, write); + else if (CheckToken(token, "c", "count")) + { + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing count.\n"); + return false; + } + int count; + if (!ParseInt(token, &count) || count <= 0) + { + Error("Enter a valid count.\n"); + return false; + } + watch = m_cpu->AddCountMemWatch(addr, size, read, write, count); + } + else if (CheckToken(token, "m", "match")) + { + vector dataSeq; + while ((token = strtok(NULL, " ")) != NULL) + { + if (m_cpu->ParseData(token, size, &data)) + dataSeq.push_back(data); + } + if (dataSeq.size() == 0) + { + sizeStr = GetDataSizeStr(size, false); + Error("Enter a sequence of %s data to match.", sizeStr); + return false; + } + watch = m_cpu->AddMatchMemWatch(addr, size, read, write, dataSeq); + } + else if (CheckToken(token, "r", "capture")) + { + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing maximum capture length.\n"); + return false; + } + int maxLen; + if (!ParseInt(token, &maxLen) || maxLen <= 0) + { + Error("Enter a valid maximum capture length.\n"); + return false; + } + watch = m_cpu->AddCaptureMemWatch(addr, size, read, write, maxLen); + } + else if (CheckToken(token, "p", "print")) + watch = m_cpu->AddPrintMemWatch(addr, size, read, write); + else + { + Error("Enter a valid watch type (s)imple, (c)ount, (m)atch, captu(r)e or (p)rint.\n"); + return false; + } + + m_cpu->FormatAddress(addrStr, watch->addr); + number = GetIndexOfMemWatch(watch); + Print("Memory watch #%d added at address %s.\n", number, addrStr); + } + else if (CheckToken(token, "rw", "removememwatch")) // removememwatch (#|) + { + // Parse arguments + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing watch number or address.\n"); + return false; + } + if (token[0] == '#') + { + // Remove watch by number + vector watches; + GetAllMemWatches(watches); + if (!ParseInt(token + 1, &number) || number < 0 || number >= watches.size()) + { + Error("Enter a valid watch number.\n"); + return false; + } + + // Remove watch + m_cpu->RemoveWatch(watches[number]); + Print("Memory watch #%d removed.\n", number); + } + else + { + // Remove watch by address + if (!ParseAddress(token, &addr)) + { + Error("Enter a valid address.\n"); + return false; + } + + // Remove watch + m_cpu->FormatAddress(addrStr, addr); + if (m_cpu->RemoveMemWatch(addr, 1)) + Print("Memory watch at address %s removed.\n", addrStr); + else + Error("No memory watch at address %s.\n", addrStr); + } + } + else if (CheckToken(token, "raw", "removeallmemwatches")) // removeallmemwatches + { + // Remove all memory watches + vector watches; + GetAllMemWatches(watches); + for (vector::iterator it = watches.begin(); it != watches.end(); it++) + m_cpu->RemoveWatch(*it); + Print("All memory watches removed.\n"); + } + else if (CheckToken(token, "lpw", "listportwatches")) // listportwatches + { + ListPortWatches(); + } + else if (CheckToken(token, "pw", "portwatch") || // addportwatch [((n)one|(i)nput|(o)|(io)nputoutput) [((s)imple|(c)ount |(m)atch |captu(r)e |(p)rint)]] + CheckToken(token, "apw", "addportwatch")) + { + // Parse arguments + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing port number.\n"); + return false; + } + if (!m_cpu->ParsePortNum(token, &portNum)) + { + Error("Enter a valid port number.\n"); + return false; + } + token = strtok(NULL, " "); + bool input; + bool output; + if (token == NULL || CheckToken(token, "n", "none")) + { + input = false; + output = false; + } + else if (CheckToken(token, "i", "input")) + { + input = true; + output = false; + } + else if (CheckToken(token, "o", "output")) + { + input = false; + output = true; + } + else if (CheckToken(token, "io", "input/output") || CheckToken(token, "oi", "output/input")) + { + input = true; + output = true; + } + else + { + Error("Enter valid input/output flags (n)one, (i)nput, (o)utput or (io)nput/output.\n"); + return false; + } + + // Add watch + CPortIO *port = m_cpu->GetPortIO(portNum); + CWatch *watch; + token = strtok(NULL, " "); + if (token == NULL || CheckToken(token, "s", "simple")) + watch = port->AddSimpleWatch(input, output); + else if (CheckToken(token, "c", "count")) + { + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing count.\n"); + return false; + } + int count; + if (!ParseInt(token, &count) || count <= 0) + { + Error("Enter a valid count.\n"); + return false; + } + watch = port->AddCountWatch(input, output, count); + } + else if (CheckToken(token, "m", "match")) + { + vector dataSeq; + while ((token = strtok(NULL, " ")) != NULL) + { + if (m_cpu->ParseData(token, port->dataSize, &data)) + dataSeq.push_back(data); + } + if (dataSeq.size() == 0) + { + Error("Enter a sequence of %s to match.", GetDataSizeStr(port->dataSize, false)); + return false; + } + watch = port->AddMatchWatch(input, output, dataSeq); + } + else if (CheckToken(token, "r", "capture")) + { + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing maximum capture length.\n"); + return false; + } + int maxLen; + if (!ParseInt(token, &maxLen) || maxLen <= 0) + { + Error("Enter a valid maximum capture length.\n"); + return false; + } + watch = port->AddCaptureWatch(input, output, maxLen); + } + else if (CheckToken(token, "p", "print")) + watch = port->AddPrintWatch(input, output); + else + { + Error("Enter a valid watch type (s)imple, (c)ount, (m)atch, captu(r)e or (p)rint.\n"); + return false; + } + + m_cpu->FormatPortNum(portNumStr, portNum); + number = GetIndexOfPortWatch(watch); + Print("Port watch %d added for port %u.\n", number, portNumStr); + } + else if (CheckToken(token, "rpw", "removeportwatch")) // removeportwatch (a|n|p) [NUM|PORT] + { + // Parse arguments + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing watch number or port number.\n"); + return false; + } + if (token[0] == '#') + { + // Remove watch by number + vector watches; + GetAllPortWatches(watches); + if (!ParseInt(token + 1, &number) || number < 0 || number >= watches.size()) + { + Error("Enter a valid watch number.\n"); + return false; + } + + // Remove watch + m_cpu->RemoveWatch(watches[number]); + Print("Port watch #%d removed.\n", number); + } + else + { + // Remove watch by port number + if (!m_cpu->ParsePortNum(token, &portNum)) + { + Error("Enter a valid port number.\n"); + return false; + } + + // Remove watch + CPortIO *port = m_cpu->GetPortIO(portNum); + m_cpu->FormatPortNum(portNumStr, portNum); + if (port->RemoveWatch()) + Print("Port watch for port %s removed.\n", portNumStr); + else + Error("No port watch for port %s.\n", portNumStr); + } + } + else if (CheckToken(token, "rapw", "removeallportwatches")) // removeallportwatches + { + // Remove all port watches + vector watches; + GetAllPortWatches(watches); + for (vector::iterator it = watches.begin(); it != watches.end(); it++) + m_cpu->RemoveWatch(*it); + Print("All port watches removed.\n"); + } + // + // General + // + else if (CheckToken(token, "p", "print", mod, 9, "")) // print[.=v] [(h)ex|hexdo(l)lar|hex(p)osth|(d)ecimal|(b)inary] + { + // Parse arguments + bool useDefSize; + if (mod[0] == '\0') + useDefSize = true; + else if (ParseDataSize(mod, size)) + useDefSize = false; + else + return false; + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing expression.\n"); + return false; + } + const char *expr = token; + token = strtok(NULL, " "); + if (token != NULL) + { + if (!ParseFormat(token, fmt)) + return false; + } + else + fmt = m_dataFmt; + + // Check labels and registers + CLabel *label = m_cpu->GetLabel(expr); + if (label != NULL) + { + data = label->addr; + if (useDefSize) + size = m_cpu->memBusWidth / 8; + } + else + { + CCodeAnalyser *analyser = m_cpu->GetCodeAnalyser(); + CAutoLabel *autoLabel = analyser->analysis->GetAutoLabel(expr); + if (autoLabel != NULL) + { + data = autoLabel->addr; + if (useDefSize) + size = m_cpu->memBusWidth / 8; + } + else + { + CRegister *reg = m_cpu->GetRegister(expr); + if (reg != NULL) + { + data = reg->GetValueAsInt(); + if (useDefSize) + size = reg->dataWidth / 8; + } + else + { + if (!ParseData(expr, m_dataFmt, 8, &data)) + { + Print("Unable to parse expression %s\n", expr); + return false; + } + if (useDefSize) + size = 8; + } + } + } + + char result[255]; + FormatData(result, fmt, size, data); + if (useDefSize) + Print("%s = %s\n", expr, result); + else + { + sizeStr = GetDataSizeStr(size, true); + Print("%s = %s.%s\n", expr, result, sizeStr); + } + } + else if (CheckToken(token, "cfg", "configure")) // configure + { + // Parse arguments + token = strtok(NULL, " "); + if (token == NULL) + { + // If no arguments, then print out current configuration + Print("Configuration:\n"); + Print(" %-20s %-12s %s\n", "Code Analysis", (m_analyseCode ? "On" : "Off"), "(a)nalysis"); + Print(" %-20s %-12s %s\n", "Address Format", GetFmtConfig(m_addrFmt), "a(d)dressfmt"); + Print(" %-20s %-12s %s\n", "Port Format", GetFmtConfig(m_portFmt), "(p)ortfmt"); + Print(" %-20s %-12s %s\n", "Data Format", GetFmtConfig(m_dataFmt), "da(t)afmt"); + Print(" %-20s %-12s %s\n", "Show Labels", (m_showLabels ? "On" : "Off"), "show(l)abels"); + Print(" %-20s %-12s %s\n", "Show Opcodes", (m_showOpCodes ? "On" : "Off"), "show(o)pcodes"); + Print(" %-20s %-12u %s\n", "Mem Bytes Per Row", m_memBytesPerRow, "mem(b)ytesrow"); + return false; + } + + if (CheckToken(token, "a", "analysis")) + { + token = strtok(NULL, " "); + SetBoolConfig(token, m_analyseCode); + } + else if (CheckToken(token, "d", "addressfmt")) + { + token = strtok(NULL, " "); + SetFmtConfig(token, m_addrFmt); + } + else if (CheckToken(token, "p", "portfmt")) + { + token = strtok(NULL, " "); + SetFmtConfig(token, m_portFmt); + } + else if (CheckToken(token, "t", "datafmt")) + { + token = strtok(NULL, " "); + SetFmtConfig(token, m_dataFmt); + } + else if (CheckToken(token, "l", "showlabels")) + { + token = strtok(NULL, " "); + SetBoolConfig(token, m_showLabels); + } + else if (CheckToken(token, "o", "showopcodes")) + { + token = strtok(NULL, " "); + SetBoolConfig(token, m_showOpCodes); + } + else if (CheckToken(token, "b", "membytesrow")) + { + token = strtok(NULL, " "); + SetNumConfig(token, m_memBytesPerRow); + } + else + { + Error("Enter a valid option (a)nalysis, a(d)dressfmt, (p)ortfmt, da(t)afmt, show(l)abels, show(o)pcodes, mem(b)ytesrow.\n"); + return false; + } + } + else if (CheckToken(token, "ls", "loadstate")) // loadstate + { + // Parse arguments + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing filename.\n"); + return false; + } + + if (LoadState(token)) + Print("Debugger state successfully loaded from <%s>\n", token); + else + Error("Unable to load debugger state from <%s>\n", token); + } + else if (CheckToken(token, "ss", "savestate")) // savestate + { + // Parse arguments + token = strtok(NULL, " "); + if (token == NULL) + { + Error("Missing filename.\n"); + return false; + } + + if (SaveState(token)) + Print("Debugger state successfully saved to <%s>\n", token); + else + Error("Unable to save debugger state to <%s>\n", token); + } + else if (CheckToken(token, "h", "help")) // help + { + // TODO - improve the following + const char *fmt = " %-6s %-25s %s\n"; + + Print("Debugger Commands:\n"); + + Print(" Execution:\n"); + Print(fmt, "n", "next", "[=1]"); + Print(fmt, "nf", "nextframe", "[=1]"); + Print(fmt, "s", "stepover", ""); + Print(fmt, "si", "stepinto", ""); + Print(fmt, "so", "stepout", ""); + Print(fmt, "c", "continue", "[]"); + Print(fmt, "spc", "setpc", ""); + + Print(" CPUs:\n"); + Print(fmt, "lc", "listcpus", ""); + Print(fmt, "sc", "switchcpu", "(|)"); + Print(fmt, "dc", "disablecpu", "(|)"); + Print(fmt, "ec", "enablecpu", "(|)"); + + Print(" Registers:\n"); + Print(fmt, "lr", "listregisters", ""); + Print(fmt, "pr", "printregister", ""); + Print(fmt, "sr", "setregister", " "); + Print(fmt, "lm", "listmonitors", ""); + Print(fmt, "m/am", "addmonitor", ""); + Print(fmt, "rm", "removemonitor", ""); + Print(fmt, "ram", "removeallmonitors", ""); + + Print(" Exceptions & interrupts:\n"); + Print(fmt, "le", "listexceptions", ""); + Print(fmt, "li", "listinterrupts", ""); + Print(fmt, "t/at", "addtrap", "((e)xception|(i)nterrupt) "); + Print(fmt, "rt", "removetrap", "((e)xception|(i)nterrupt) "); + Print(fmt, "rat", "removealltraps", "[(a)ll|(e)xceptions|(i)nterrupts]"); + + Print(" Disassembly, labels & comments:\n"); + Print(fmt, "l/ld", "listdisassembly", "[=last [#=20|]]"); + Print(fmt, "ll", "listlabels", "[(d)efault|(c)ustom|(a)utos|(e)ntrypoints|e(x)cephandlers|(i)interhandlers|(j)umptargets|(l)ooppoints]"); + Print(fmt, "al", "addlabel", " "); + Print(fmt, "rl", "removelabel", "[|]"); + Print(fmt, "ral", "removealllabels", ""); + Print(fmt, "ac", "addcomment", " "); + Print(fmt, "rc", "removecomment", "[]"); + Print(fmt, "rac", "removeallcomments", ""); + + Print(" Breakpoints:\n"); + Print(fmt, "lb", "listbreakpoints", ""); + Print(fmt, "b/ab", "addbreakpoint", "[ [[s)imple|(c)ount )]]"); + Print(fmt, "rb", "removebreakpoint", "[#|]"); + Print(fmt, "rab", "removeallbreakpoints", ""); + + Print(" Memory, I/O & watches:\n"); + Print(fmt, "ln", "listregions", ""); + Print(fmt, "ly", "listmemory", "[=last [#=8|]]"); + Print(fmt, "py", "printmemory[.=b]", ""); + Print(fmt, "sy", "setmemory[.=b]", " "); + Print(fmt, "lo", "listios", ""); + Print(fmt, "lw", "listmemwatches", ""); + Print(fmt, "w/aw", "addmemwatch[.=b]", " [((n)one|(r)ead|(w)rite|(rw)eadwrite) [((s)imple|(c)ount |(m)atch |captu(r)e |(p)rint)]]"); + Print(fmt, "rw", "removememwatch", "(#|)"); + Print(fmt, "raw", "removeallmemwatches", ""); + Print(fmt, "lpw", "listportwatches", ""); + Print(fmt, "pw/apw", "addportwatch", " [((n)one|(i)nput|(o)utput|(io)nputoutput) [(s)imple|(c)ount |(m)atch |captu(r)e |(p)rint]]"); + Print(fmt, "rpw", "removeportwatch", "(#|)"); + Print(fmt, "rapw", "removeallportwatches", ""); + + Print("General:\n"); + Print(fmt, "p", "print[.=v]", " [(h)ex|hexdo(l)lar|hex(p)osth|(d)ecimal|(b)inary]"); + Print(fmt, "cfg", "configure", ""); + Print(fmt, "ls", "loadstate", ""); + Print(fmt, "ss", "savestate", ""); + Print(fmt, "h", "help", ""); + Print(fmt, "x", "exit", ""); + } + else if (CheckToken(token, "x", "exit")) // exit + { + Print("Exiting...\n"); + SetExit(); + return true; + } + else + Print("Unknown command '%s'.\n", token); + return false; + } + + void CConsoleDebugger::Read(char *str, size_t maxSize) + { + if (fgets(str, maxSize, stdin) != NULL) + { + char *pos = strchr(str, '\n'); + if (pos) + *pos = '\0'; + } + else + str[0] = '\0'; + } + + void CConsoleDebugger::Print(const char *fmtStr, ...) + { + va_list vl; + va_start(vl, fmtStr); + PrintVL(fmtStr, vl); + va_end(vl); + } + + void CConsoleDebugger::Error(const char *fmtStr, ...) + { + // Don't log errors to file + va_list vl; + va_start(vl, fmtStr); + vprintf(fmtStr, vl); + va_end(vl); + } + + void CConsoleDebugger::PrintVL(const char *fmtStr, va_list vl) + { + if (m_file != NULL) + vfprintf(m_file, fmtStr, vl); + else + vprintf(fmtStr, vl); + } + + void CConsoleDebugger::Flush() + { + fflush(stdout); + } + + bool CConsoleDebugger::CheckToken(const char *token, const char *simple, const char *full) + { + return stricmp(token, simple) == 0 || stricmp(token, full) == 0; + } + + bool CConsoleDebugger::CheckToken(const char *token, const char *simple, const char *full, char *modifier, size_t modSize, const char *defaultMod) + { + const char *pos = strchr(token, '.'); + if (pos == NULL) + { + strncpy(modifier, defaultMod, modSize); + modifier[modSize] = '\0'; + return CheckToken(token, simple, full); + } + else + { + pos++; + // BEGIN + if (*pos == '\0') + // END + return false; + strncpy(modifier, pos, modSize); + modifier[modSize] = '\0'; + + char actual[255]; + size_t actSize = min(pos - token - 1, 254); + strncpy(actual, token, actSize); + actual[actSize] = '\0'; + return CheckToken(actual, simple, full); + } + } + + void CConsoleDebugger::Truncate(char *dst, size_t maxLen, const char *src) + { + strncpy(dst, src, maxLen); + if (strlen(src) > maxLen) + strncpy(&dst[maxLen - 3], "...", 3); + dst[maxLen] = '\0'; + } + + void CConsoleDebugger::UpperFirst(char *dst, const char *src) + { + if (*src != '\0') + { + *dst++ = toupper(*src++); + while (*src != '\0') + *dst++ = *src++; + } + *dst = '\0'; + } + + void CConsoleDebugger::FormatOpCodes(char *str, int addr, int codesLen) + { + char *p = str; + int i = 0; + while (i < codesLen) + { + UINT8 opCode = (UINT8)m_cpu->ReadMem(addr++, 1); + sprintf(p, "%02X", opCode); + p += 2; + i++; + } + while (i++ < m_cpu->maxInstrLen) + { + *p++ = ' '; + *p++ = ' '; + } + *p = '\0'; + } + + bool CConsoleDebugger::GetLabelText(char *str, int maxLen, UINT32 addr) + { + char labelStr[255]; + + CLabel *label = m_cpu->GetLabel(addr); + if (label != NULL) + { + Truncate(str, maxLen, label->name); + return true; + } + + if (m_analyseCode) + { + CCodeAnalyser *analyser = m_cpu->GetCodeAnalyser(); + CAutoLabel *autoLabel = analyser->analysis->GetAutoLabel(addr); + if (autoLabel != NULL && autoLabel->GetLabel(labelStr)) + { + Truncate(str, maxLen, labelStr); + return true; + } + } + + str[0] = '\0'; + return false; + } + + bool CConsoleDebugger::SetBoolConfig(const char *str, bool &cfg) + { + if (str == NULL) + { + Print("Current setting: %-12s\n", (cfg ? "On" : "Off")); + Print("Change setting with (o)n, o(f)f.\n"); + return false; + } + + if (CheckToken(str, "o", "on")) + { + cfg = true; + Print("Changed setting: On\n"); + ApplyConfig(); + return true; + } + else if (CheckToken(str, "f", "off")) + { + cfg = false; + Print("Changed setting: Off\n"); + ApplyConfig(); + return true; + } + else + { + Error("Enter a valid setting (o)n, o(f)f.\n"); + return false; + } + } + + bool CConsoleDebugger::SetNumConfig(const char *str, unsigned &cfg) + { + if (str == NULL) + { + Print("Current setting: %-12u\n", cfg); + return false; + } + + int number; + if (!ParseInt(str, &number)) + { + Error("Enter a valid number.\n"); + return false; + } + + cfg = (unsigned)number; + Print("Changed setting: %-12u\n", cfg); + ApplyConfig(); + return true; + } + + const char *CConsoleDebugger::GetFmtConfig(EFormat fmt) + { + switch (fmt) + { + case Hex0x: return "Hex (0x00)"; + case HexDollar: return "Hex ($00)"; + case HexPostH: return "Hex (00h)"; + case Decimal: return "Decimal"; + case Binary: return "Binary"; + default: return "-"; + } + } + + bool CConsoleDebugger::SetFmtConfig(const char *str, EFormat &cfg) + { + if (str == NULL) + { + Print("Current setting: %-12s\n", GetFmtConfig(cfg)); + Print("Change setting with (h)ex, hex(z)ero, hexdo(l)ar, hex(p)osth, (d)ecimal, (b)inary.\n"); + return false; + } + + if (!ParseFormat(str, cfg)) + return false; + + Print("Changed setting: %-12s\n", GetFmtConfig(cfg)); + ApplyConfig(); + return true; + } + + bool CConsoleDebugger::ParseAddress(const char *str, UINT32 *addr) + { + if (m_cpu->instrCount > 0 && CheckToken(str, "-", "current")) + { + *addr = m_cpu->pc; + return true; + } + return m_cpu->ParseAddress(str, addr); + } + + const char *CConsoleDebugger::GetDataSizeStr(unsigned dataSize, bool shortName) + { + switch (dataSize) + { + case 1: return (shortName ? "b" : "byte"); + case 2: return (shortName ? "w" : "word"); + case 4: return (shortName ? "l" : "long"); + case 8: return (shortName ? "v" : "vlong"); + default: return GetSizeString(dataSize); + } + } + + bool CConsoleDebugger::ParseDataSize(const char *str, unsigned &dataSize) + { + int num = -1; + ParseInt(str, &num); + if (CheckToken(str, "b", "byte") || num == 1) + { + dataSize = 1; + return true; + } + else if (CheckToken(str, "w", "word") || num == 2) + { + dataSize = 2; + return true; + } + else if (CheckToken(str, "l", "long") || num == 4) + { + dataSize = 4; + return true; + } + else if (CheckToken(str, "v", "verylong") || num == 8) + { + dataSize = 8; + return true; + } + else + { + Error("Enter a valid size (b)yte, (w)ord, (l)ong or (v)erylong or a number 1, 2, 4 or 8.\n"); + return false; + } + } + + bool CConsoleDebugger::ParseFormat(const char *str, EFormat &fmt) + { + if (CheckToken(str, "h", "hex")) fmt = Hex; + else if (CheckToken(str, "z", "hexzero")) fmt = Hex0x; + else if (CheckToken(str, "l", "hexdollar")) fmt = HexDollar; + else if (CheckToken(str, "p", "hexposth")) fmt = HexPostH; + else if (CheckToken(str, "d", "decimal")) fmt = Decimal; + else if (CheckToken(str, "b", "binary")) fmt = Binary; + else + { + Error("Enter a valid format (h)ex, hex(z)ero, hexdo(l)ar, hex(p)osth, (d)ecimal, (b)inary.\n"); + return false; + } + return true; + } + + bool CConsoleDebugger::ParseCPU(const char *str, CCPUDebug *&cpu) + { + if (str == NULL) + { + Error("Missing CPU name or number.\n"); + return false; + } + int cpuNum; + if (ParseInt(str, &cpuNum)) + { + if (cpuNum >= 0 && cpuNum < (int)cpus.size()) + { + cpu = cpus[cpuNum]; + return true; + } + } + cpu = GetCPU(str); + if (cpu == NULL) + { + Error("No CPU with that name or number.\n"); + return false; + } + return true; + } + + bool CConsoleDebugger::ParseRegister(const char *str, CRegister *®) + { + if (str == NULL) + { + Error("Missing register name.\n"); + return false; + } + reg = m_cpu->GetRegister(str); + if (reg == NULL) + { + Error("Enter a valid register name.\n"); + return false; + } + return true; + } + + void CConsoleDebugger::ListCPUs() + { + Print("CPUs:\n"); + if (cpus.size() == 0) + { + Print(" None\n"); + return; + } + + Print(" %-3s %-9s %-6s %-9s %-7s %-12s %-12s %-9s\n", "Num", "Name", "Type", "Debugging", "State", "Instr Count", "Total Cycles", "Frequency"); + unsigned num = 0; + double freq; + char onCPU; + const char *debugStr; + const char *stateStr; + for (vector::iterator it = cpus.begin(); it != cpus.end(); it++) + { + onCPU = (*it == m_cpu ? '*': ' '); + debugStr = ((*it)->IsEnabled() ? "Enabled" : "Disabled"); + stateStr = ((*it)->active ? "Running" : "Waiting"); + + if ((*it)->instrCount > 0) + { + if (frameCount > 0) + { + freq = ((*it)->cyclesPerPoll * 60.0) / 1000000.0; + Print("%c%-3u %-9s %-6s %-9s %-7s %12llu %12llu %6.1fMHz\n", onCPU, num++, (*it)->name, (*it)->type, debugStr, stateStr, (*it)->instrCount - 1, (*it)->totalCycles, freq); + } + else + Print("%c%-3u %-9s %-6s %-9s %-7s %12llu %12llu %9s\n", onCPU, num++, (*it)->name, (*it)->type, debugStr, stateStr, (*it)->instrCount - 1, (*it)->totalCycles, "-"); + } + else + Print("%c%-3u %-9s %-6s %-9s %-7s %12s %12s %9s\n", onCPU, num++, (*it)->name, (*it)->type, debugStr, stateStr, "-", "-", "-"); + } + } + + void CConsoleDebugger::ListRegisters() + { + Print("%s Registers:\n", m_cpu->name); + if (m_cpu->regs.size() == 0) + { + Print(" None\n"); + return; + } + + // Get groups + vector groups; + vector > regsByGroup; + size_t totalRows = 0; + for (vector::iterator it = m_cpu->regs.begin(); it != m_cpu->regs.end(); it++) + { + const char *group = (*it)->group; + // TODO - find with stricmp rather than default find + if (find(groups.begin(), groups.end(), group) == groups.end()) + { + groups.push_back(group); + regsByGroup.resize(regsByGroup.size() + 1); + } + int index = find(groups.begin(), groups.end(), group) - groups.begin(); + vector *pRegsInGroup = ®sByGroup[index]; + pRegsInGroup->push_back(*it); + totalRows = max(totalRows, pRegsInGroup->size()); + } + + // Get max label and value widths in each group and print group headers + size_t numGroups = groups.size(); + vector labelWidths(numGroups); + vector valueWidths(numGroups); + vector groupWidths(numGroups); + char valStr[50]; + Print(" "); + for (size_t index = 0; index < numGroups; index++) + { + labelWidths[index] = 0; + valueWidths[index] = 0; + + vector *pRegsInGroup = ®sByGroup[index]; + for (vector::iterator it = pRegsInGroup->begin(); it != pRegsInGroup->end(); it++) + { + labelWidths[index] = max(labelWidths[index], strlen((*it)->name)); + (*it)->GetValue(valStr); + valueWidths[index] = max(valueWidths[index], strlen(valStr)); + } + + const char *group = groups[index]; + groupWidths[index] = max(labelWidths[index] + valueWidths[index] + 3, strlen(group) + 1); + Print("%-*s", (int)groupWidths[index], group); + } + Print("\n"); + + // Print rows of register values + char rowStr[50]; + for (size_t row = 0; row < totalRows; row++) + { + Print(" "); + for (size_t index = 0; index < numGroups; index++) + { + vector *pRegsInGroup = ®sByGroup[index]; + if (row < pRegsInGroup->size()) + { + CRegister *reg = (*pRegsInGroup)[row]; + reg->GetValue(valStr); + bool hasMon = m_cpu->GetRegMonitor(reg->name) != NULL; + + sprintf(rowStr, "%c%-*s %-*s", (hasMon ? '*' : ' '), (int)labelWidths[index], reg->name, (int)valueWidths[index], valStr); + } + else + rowStr[0] = '\0'; + + Print("%-*s", (int)groupWidths[index], rowStr); + } + Print("\n"); + } + } + + void CConsoleDebugger::ListExceptions() + { + Print("%s Exceptions:\n", m_cpu->name); + if (m_cpu->exceps.size() == 0) + { + Print(" None\n"); + return; + } + + char addrStr[20]; + UINT32 handlerAddr; + for (vector::iterator it = m_cpu->exceps.begin(); it != m_cpu->exceps.end(); it++) + { + if (m_cpu->GetHandlerAddr(*it, handlerAddr)) + m_cpu->FormatAddress(addrStr, handlerAddr, true, (m_analyseCode ? LFExcepHandler : LFNone)); + else + addrStr[0] = '\0'; + Print("%c%-12s %-30s %-12s %u\n", ((*it)->trap ? '*' : ' '), (*it)->id, (*it)->name, addrStr, (*it)->count); + } + } + + void CConsoleDebugger::ListInterrupts() + { + Print("%s Interrupts:\n", m_cpu->name); + if (m_cpu->inters.size() == 0) + { + Print(" None\n"); + return; + } + + char addrStr[20]; + UINT32 handlerAddr; + for (vector::iterator it = m_cpu->inters.begin(); it != m_cpu->inters.end(); it++) + { + if (m_cpu->GetHandlerAddr(*it, handlerAddr)) + m_cpu->FormatAddress(addrStr, handlerAddr, true, (m_analyseCode ? LFInterHandler : LFNone)); + else + addrStr[0] = '\0'; + Print("%c%-12s %-30s %-12s %u\n", ((*it)->trap ? '*' : ' '), (*it)->id, (*it)->name, addrStr, (*it)->count); + } + } + + void CConsoleDebugger::ListIOs() + { + Print("%s I/O Ports:\n", m_cpu->name); + if (m_cpu->ios.size() == 0) + { + Print(" None\n"); + return; + } + + const char *group = NULL; + char locStr[255]; + char dirChar; + char inStr[50]; + char outStr[50]; + for (vector::iterator it = m_cpu->ios.begin(); it != m_cpu->ios.end(); it++) + { + // Print group heading if starting a new group + if (group == NULL || stricmp((*it)->group, group) != 0) + { + group = (*it)->group; + Print(" %s:\n", group); + } + + // Get location string (memory address or port number) + (*it)->GetLocation(locStr); + + // See whether port was last read or written + if ((*it)->inCount + (*it)->outCount > 0) + dirChar = ((*it)->last == &(*it)->lastIn ? '<' : '>'); + else + dirChar = ' '; + // Format last input + if ((*it)->inCount > 0) + m_cpu->FormatData(inStr, (*it)->dataSize, (*it)->lastIn); + else + { + inStr[0] = '*'; + inStr[1] = '\0'; + } + size_t inLen = strlen(inStr); + int inLPad = 5 - (int)inLen / 2; + int inRPad = 5 - (int)inLen + (int)inLen / 2; + // Format last output + if ((*it)->outCount > 0) + m_cpu->FormatData(outStr, (*it)->dataSize, (*it)->lastOut); + else + { + outStr[0] = '*'; + outStr[1] = '\0'; + } + size_t outLen = strlen(outStr); + int outLPad = 5 - (int)outLen / 2; + int outRPad = 5 - (int)outLen + (int)outLen / 2; + + // Print details + Print(" %c%-12s %-30s %-8s %*s%s%*s%c%*s%s%*s\n", ((*it)->watch != NULL ? '*' : ' '), locStr, (*it)->name, + GetDataSizeStr((*it)->dataSize, true), inLPad, "", inStr, inRPad, "", dirChar, outLPad, "", outStr, outRPad, ""); + } + } + + void CConsoleDebugger::ListRegions() + { + Print("%s Regions:\n", m_cpu->name); + if (m_cpu->regions.size() == 0) + { + Print(" None\n"); + return; + } + + char startStr[255]; + char endStr[255]; + for (vector::iterator it = m_cpu->regions.begin(); it != m_cpu->regions.end(); it++) + { + // Format start and end address + m_cpu->FormatAddress(startStr, (*it)->addr); + m_cpu->FormatAddress(endStr, (*it)->addrEnd); + + // Print details + Print("%c%s-%s %s\n", ((*it)->isCode ? '*' : ' '), startStr, endStr, (*it)->name); + } + } + + void CConsoleDebugger::ListLabels(bool customLabels, ELabelFlags autoLabelFlags) + { + Print("%s Labels:\n", m_cpu->name); + + unsigned count = 0; + + char addrStr[20]; + if (customLabels && m_cpu->labels.size() > 0) + { + Print(" Custom Labels:\n"); + for (vector::iterator it = m_cpu->labels.begin(); it != m_cpu->labels.end(); it++) + { + m_cpu->FormatAddress(addrStr, (*it)->addr); + Print(" %s %s\n", addrStr, (*it)->name); + count++; + } + } + + if (m_analyseCode) + { + char labelStr[255]; + CCodeAnalyser *analyser = m_cpu->GetCodeAnalyser(); + for (unsigned index = 0; index < CAutoLabel::numLabelFlags; index++) + { + ELabelFlags flag = CAutoLabel::GetLabelFlag(index); + if (!(autoLabelFlags & flag)) + continue; + vector withFlag = analyser->analysis->GetAutoLabels(flag); + if (withFlag.size() == 0) + continue; + const char *flagStr = CAutoLabel::GetFlagString(flag); + Print(" %ss:\n", flagStr); + for (vector::iterator it = withFlag.begin(); it != withFlag.end(); it++) + { + if (!(*it)->GetLabel(labelStr, flag)) + continue; + CBreakpoint *bp = m_cpu->GetBreakpoint((*it)->addr); + char bpChr = (bp != NULL ? bp->symbol : ' '); + m_cpu->FormatAddress(addrStr, (*it)->addr); + Print(" %c%s %s\n", bpChr, addrStr, labelStr); + count++; + } + } + } + + if (count == 0) + { + Print(" None\n"); + return; + } + } + + void CConsoleDebugger::GetAllMemWatches(vector &watches) + { + for (vector::iterator it = m_cpu->memWatches.begin(); it != m_cpu->memWatches.end(); it++) + watches.push_back(*it); + for (vector::iterator it = m_cpu->ioWatches.begin(); it != m_cpu->ioWatches.end(); it++) + { + if (dynamic_cast((*it)->io) != NULL) + watches.push_back(*it); + } + } + + int CConsoleDebugger::GetIndexOfMemWatch(CWatch *watch) + { + vector watches; + GetAllMemWatches(watches); + vector::iterator it = find(watches.begin(), watches.end(), watch); + if (it == watches.end()) + return -1; + return it - watches.begin(); + } + + void CConsoleDebugger::ListMemWatches() + { + Print("%s Memory Watches:\n", m_cpu->name); + + vector watches; + GetAllMemWatches(watches); + + if (watches.size() == 0) + { + Print(" None\n"); + return; + } + + Print(" %-3s %-8s %-12s %-5s %-4s %-20s %s\n", "Num", "Type", "Address", "Size", "Trig", "Value", "Info"); + + char typeStr[12]; + char addrStr[20]; + char sizeStr[20]; + const char *dSizeStr; + const char *trigStr; + char valStr[20]; + char infoStr[255]; + unsigned wNum = 0; + for (vector::iterator it = watches.begin(); it != watches.end(); it++) + { + UpperFirst(typeStr, (*it)->type); + m_cpu->FormatAddress(addrStr, (*it)->addr, true); + dSizeStr = GetDataSizeStr((*it)->size, false); + UpperFirst(sizeStr, dSizeStr); + if ((*it)->trigRead && (*it)->trigWrite) trigStr = "R/W"; + else if ((*it)->trigRead) trigStr = "R"; + else if ((*it)->trigWrite) trigStr = "W"; + else trigStr = "-"; + m_cpu->FormatData(valStr, (*it)->size, (*it)->GetValue()); + if (!(*it)->GetInfo(infoStr)) + { + infoStr[0] = '-'; + infoStr[1] = '\0'; + } + Print(" %-3u %-8s %-12s %-5s %-4s %-20s %s\n", wNum++, typeStr, addrStr, sizeStr, trigStr, valStr, infoStr); + } + } + + void CConsoleDebugger::GetAllPortWatches(vector &watches) + { + for (vector::iterator it = m_cpu->ioWatches.begin(); it != m_cpu->ioWatches.end(); it++) + { + if (dynamic_cast((*it)->io) != NULL) + watches.push_back(*it); + } + } + + int CConsoleDebugger::GetIndexOfPortWatch(CWatch *watch) + { + vector watches; + GetAllPortWatches(watches); + vector::iterator it = find(watches.begin(), watches.end(), watch); + if (it == watches.end()) + return -1; + return it - watches.begin(); + } + + void CConsoleDebugger::ListPortWatches() + { + Print("%s I/O Port Watches:\n", m_cpu->name); + + vector watches; + GetAllPortWatches(watches); + + if (watches.size() == 0) + { + Print(" None\n"); + return; + } + + Print(" %-3s %-8s %-12s %-4s %-20s %s\n", "Num", "Type", "Location", "Trig", "Last In/Out", "Info"); + + char typeStr[12]; + char locStr[255]; + const char *trigStr; + char valStr[20]; + char infoStr[255]; + unsigned wNum = 0; + for (vector::iterator it = watches.begin(); it != watches.end(); it++) + { + UpperFirst(typeStr, (*it)->type); + (*it)->io->GetLocation(locStr); + if ((*it)->trigRead && (*it)->trigWrite) trigStr = "I/O"; + else if ((*it)->trigRead) trigStr = "I"; + else if ((*it)->trigWrite) trigStr = "O"; + else trigStr = "-"; + if ((*it)->readCount + (*it)->writeCount == 0) + { + valStr[0] = '-'; + valStr[1] = '\0'; + } + else + m_cpu->FormatData(valStr, (*it)->size, (*it)->GetValue()); + if (!(*it)->GetInfo(infoStr)) + { + infoStr[0] = '-'; + infoStr[1] = '\0'; + } + Print(" %-3u %-8s %-12s %-4s %-20s %s\n", wNum++, typeStr, locStr, trigStr, valStr, infoStr); + } + } + + void CConsoleDebugger::ListBreakpoints() + { + Print("%s Breakpoints:\n", m_cpu->name); + if (m_cpu->bps.size() == 0) + { + Print(" None\n"); + return; + } + + Print(" %-3s %-8s %-12s %-20s\n", "Num", "Type", "Address", "Info"); + + char typeStr[12]; + char addrStr[20]; + char infoStr[255]; + for (vector::iterator it = m_cpu->bps.begin(); it != m_cpu->bps.end(); it++) + { + UpperFirst(typeStr, (*it)->type); + m_cpu->FormatAddress(addrStr, (*it)->addr, true, (m_analyseCode ? LFAll : LFNone)); + if (!(*it)->GetInfo(infoStr)) + { + infoStr[0] = '-'; + infoStr[1] = '\0'; + } + Print(" %-3u %-8s %-12s %-20s\n", (*it)->num, typeStr, addrStr, infoStr); + } + } + + void CConsoleDebugger::ListMonitors() + { + Print("%s Register Monitors:\n", m_cpu->name); + if (m_cpu->regMons.size() == 0) + { + Print(" None\n"); + return; + } + + char valStr[255]; + int num = 0; + for (vector::iterator it = m_cpu->regMons.begin(); it != m_cpu->regMons.end(); it++) + { + (*it)->GetBeforeValue(valStr); + Print(" %d - %s change from: %s\n", num++, (*it)->reg->name, valStr); + } + } + + UINT32 CConsoleDebugger::ListDisassembly(UINT32 start, UINT32 end, unsigned numInstrs) + { + UINT32 addr; + char startStr[20]; + char endStr[20]; + char opCodes[50]; + char mnemonic[100]; + char operands[155]; + char addrStr[20]; + char labelStr[13]; + unsigned instr; + + UINT32 pc = m_cpu->pc; + CCodeAnalyser *analyser = (m_analyseCode ? m_cpu->GetCodeAnalyser() : NULL); + + // Align address to instruction boundary + start -= start%m_cpu->minInstrLen; + + if (analyser != NULL) + { + // Use code analyser to find valid start address + if (!analyser->analysis->GetNextValidAddr(start)) + return start; + } + else + { + // In the absence of code analyser, try to align code with current PC address + if (m_cpu->instrCount > 0 && pc >= start && pc <= end) + { + UINT64 count = m_cpu->instrCount; + while (start < end && count-- > 0) + { + bool okay = false; + addr = start; + instr = 0; + while (addr < end && instr < numInstrs) + { + if (addr == pc) + { + okay = true; + break; + } + int codesLen = m_cpu->GetOpLength(addr); + addr += abs(codesLen); + instr++; + } + if (okay) + break; + start += m_cpu->minInstrLen; + } + } + } + + // Get true end address + addr = start; + instr = 0; + while (addr < end && instr < numInstrs) + { + // Get instruction length + int codesLen = m_cpu->Disassemble(addr, mnemonic, operands); + // Move onto next valid instruction address + addr += abs(codesLen); + if (analyser != NULL && !analyser->analysis->GetNextValidAddr(addr)) + break; + instr++; + } + end = addr; + + // Format start and end addresses and output title + m_cpu->FormatAddress(startStr, start); + m_cpu->FormatAddress(endStr, end); + Print("%s Code %s - %s:\n", m_cpu->name, startStr, endStr); + + // Output the disassembly + addr = start; + instr = 0; + while (addr < end) + { + // Add markers for current PC address and any breakpoints + char ind[4]; + if (m_cpu->instrCount > 0 && addr == pc) + { + ind[0] = '>'; + ind[1] = '>'; + } + else + { + ind[0] = ' '; + ind[1] = ' '; + } + CBreakpoint *bp = m_cpu->GetBreakpoint(addr); + ind[2] = (bp != NULL ? bp->symbol : ' '); + ind[3] = '\0'; + + // Format current address + m_cpu->FormatAddress(addrStr, addr); + + // Get labels at address (if any) + bool hasLabel = GetLabelText(labelStr, 12, addr); + + // Get mnemonic, operands and instruction length and print them + int codesLen = m_cpu->Disassemble(addr, mnemonic, operands); + FormatOpCodes(opCodes, addr, abs(codesLen)); + + // Get comment at address (if any) + CComment *comment = m_cpu->GetComment(addr); + + // Output line + Print("%s", ind); + if (m_showLabels) + { + if (m_labelsOverAddr) + Print("%-12s ", (hasLabel ? labelStr : addrStr)); + else + Print("%s %-12s ", addrStr, labelStr); + } + else + Print("%s ", addrStr); + if (m_showOpCodes) + Print("[%s] ", opCodes); + if (codesLen > 0) + Print("%-*s %-20s", (int)m_cpu->maxMnemLen, mnemonic, operands); + else + Print("???"); + if (comment != NULL) + Print(" ; %s", comment->text); + Print("\n"); + + // Move onto next valid instruction address + addr += abs(codesLen); + if (analyser != NULL && !analyser->analysis->GetNextValidAddr(addr)) + break; + } + return end; + } + + UINT32 CConsoleDebugger::ListMemory(UINT32 start, UINT32 end, unsigned bytesPerRow) + { + char startStr[255]; + char endStr[255]; + char addrStr[20]; + char labelStr[13]; + char wChar, dChar; + UINT8 data; + + // Adjust start/end points to be on row boundary + start -= (start % bytesPerRow); + end += bytesPerRow - (end % bytesPerRow); + + // Format start and end addresses and output title + m_cpu->FormatAddress(startStr, start); + m_cpu->FormatAddress(endStr, end); + Print("%s Memory %s - %s:\n", m_cpu->name, startStr, endStr); + + UINT32 addr = start; + while (addr < end) + { + // TODO - check address going out of region or out of range + + // Format current address + m_cpu->FormatAddress(addrStr, addr); + + // Get labels at address (if any) + bool hasLabel = GetLabelText(labelStr, 12, addr); + + // Output line + if (m_showLabels) + { + if (m_labelsOverAddr) + Print(" %-12s", (hasLabel ? labelStr : addrStr)); + else + Print(" %s %-12s", addrStr, labelStr); + } + else + Print(" %s%c", addrStr); + UINT32 lAddr = addr; + for (unsigned i = 0; i < bytesPerRow; i++) + { + CWatch *watch = m_cpu->GetMemWatch(lAddr, 1); + // TODO - handling of mapped I/O + //CMappedIO *io = m_cpu->GetMappedIO(lAddr); + wChar = (watch != NULL ? watch->symbol : ' '); + //if (io != NULL) + // data = (UINT8)io->last; + //else + data = (UINT8)m_cpu->ReadMem(lAddr, 1); + Print("%c%02X", wChar, data); + lAddr++; + } + Print(" "); + lAddr = addr; + for (unsigned i = 0; i < bytesPerRow; i++) + { + // TODO - handling of mapped I/O + //CMappedIO *io = m_cpu->GetMappedIO(lAddr); + //if (io != NULL) + // data = io->last; + //else + data = (UINT8)m_cpu->ReadMem(lAddr, 1); + dChar = (data >= 32 && data <= 126 ? (char)data : '.'); + Print("%c", dChar); + lAddr++; + } + Print("\n"); + addr += bytesPerRow; + } + return addr; + } + + void CConsoleDebugger::AnalysisUpdated(CCodeAnalyser *analyser) + { + // + } + + void CConsoleDebugger::ExceptionTrapped(CException *ex) + { + PrintEvent(ex->cpu, "Exception %s (%s) trapped.\n", ex->id, ex->name); + } + + void CConsoleDebugger::InterruptTrapped(CInterrupt *in) + { + PrintEvent(in->cpu, "Interrupt %s (%s) trapped.\n", in->id, in->name); + } + + void CConsoleDebugger::MemWatchTriggered(CWatch *watch, UINT32 addr, unsigned dataSize, UINT64 data, bool isRead) + { + const char *sizeStr = GetDataSizeStr(dataSize, true); + const char *rwStr = (isRead ? "Read from" : "Write to"); + char dataStr[50]; + char addrStr[255]; + m_cpu->FormatData(dataStr, dataSize, data); + watch->cpu->FormatAddress(addrStr, addr, true); + int num = GetIndexOfMemWatch(watch); + PrintEvent(watch->cpu, "%s %s (%s.%s) triggered memory watch #%d.\n", rwStr, addrStr, dataStr, sizeStr, num); + } + + void CConsoleDebugger::IOWatchTriggered(CWatch *watch, CIO *io, UINT64 data, bool isInput) + { + const char *sizeStr = GetDataSizeStr(io->dataSize, true); + const char *ioStr = (isInput ? "Input from" : "Output to"); + char dataStr[50]; + char locStr[255]; + m_cpu->FormatData(dataStr, io->dataSize, data); + watch->io->GetLocation(locStr); + int num = GetIndexOfPortWatch(watch); + if (num >= 0) + PrintEvent(watch->cpu, "%s %s (%s.%s) triggered port watch #%d.\n", ioStr, locStr, dataStr, sizeStr, num); + else + { + num = GetIndexOfMemWatch(watch); + PrintEvent(watch->cpu, "%s %s (%s.%s) triggered memory watch #%d.\n", ioStr, locStr, dataStr, sizeStr, num); + } + } + + void CConsoleDebugger::BreakpointReached(CBreakpoint *bp) + { + PrintEvent(bp->cpu, "Breakpoint #%d triggered.\n", bp->num); + } + + void CConsoleDebugger::MonitorTriggered(CRegMonitor *regMon) + { + char valStr[255]; + CRegister *reg = regMon->reg; + reg->GetValue(valStr); + PrintEvent(reg->cpu, "Write to register %s (%s) triggered monitor.\n", reg->name, valStr); + } + + void CConsoleDebugger::ExecutionHalted(CCPUDebug *cpu, EHaltReason reason) + { + if (reason&HaltUser) + PrintEvent(cpu, "Execution halted.\n"); + } + + void CConsoleDebugger::Log(CCPUDebug *cpu, const char *typeStr, const char *fmtStr, va_list vl) + { + if (cpu != NULL) + { + char pcStr[255]; + cpu->FormatAddress(pcStr, cpu->pc, true, LFNone); + Print("%s @ %s: ", cpu->name, pcStr); + } + if (typeStr != NULL) + Print(" %s - ", typeStr); + PrintVL(fmtStr, vl); + } + + void CConsoleDebugger::Attach() + { + CDebugger::Attach(); + + ApplyConfig(); + + Attached(); + } + + void CConsoleDebugger::Detach() + { + Detaching(); + + CDebugger::Detach(); + + // Close redirected output file, if exists + if (m_file != NULL) { fclose(m_file); - m_file = NULL; - } - } - - void CConsoleDebugger::Poll() - { - CDebugger::Poll(); - - if (m_nextFrame) - { - if (--m_nextFrameCount == 0) - ForceBreak(true); - } - } - - void CConsoleDebugger::ApplyConfig() - { - for (vector::iterator it = cpus.begin(); it != cpus.end(); it++) - { - (*it)->addrFmt = m_addrFmt; - (*it)->portFmt = m_portFmt; - (*it)->dataFmt = m_dataFmt; - } - } - - void CConsoleDebugger::Attached() - { - // - } - - void CConsoleDebugger::Detaching() - { - // - } -} - -#endif // SUPERMODEL_DEBUGGER + m_file = NULL; + } + } + + void CConsoleDebugger::Poll() + { + CDebugger::Poll(); + + if (m_nextFrame) + { + if (--m_nextFrameCount == 0) + ForceBreak(true); + } + } + + void CConsoleDebugger::ApplyConfig() + { + for (vector::iterator it = cpus.begin(); it != cpus.end(); it++) + { + (*it)->addrFmt = m_addrFmt; + (*it)->portFmt = m_portFmt; + (*it)->dataFmt = m_dataFmt; + } + } + + void CConsoleDebugger::Attached() + { + // + } + + void CConsoleDebugger::Detaching() + { + // + } +} + +#endif // SUPERMODEL_DEBUGGER diff --git a/Src/Debugger/ConsoleDebugger.h b/Src/Debugger/ConsoleDebugger.h index 9479b7c..0427709 100644 --- a/Src/Debugger/ConsoleDebugger.h +++ b/Src/Debugger/ConsoleDebugger.h @@ -19,8 +19,8 @@ ** with Supermodel. If not, see . **/ -/* - * ConsoleDebugger.h +/* + * ConsoleDebugger.h */ #ifdef SUPERMODEL_DEBUGGER @@ -130,13 +130,13 @@ namespace Debugger void ListLabels(bool customLabels, ELabelFlags autoLabelFlags); - void GetAllMemWatches(vector &watches); + void GetAllMemWatches(std::vector &watches); int GetIndexOfMemWatch(CWatch *watch); void ListMemWatches(); - void GetAllPortWatches(vector &watches); + void GetAllPortWatches(std::vector &watches); int GetIndexOfPortWatch(CWatch *watch); diff --git a/Src/Debugger/Debugger.cpp b/Src/Debugger/Debugger.cpp index b677a87..307fc63 100644 --- a/Src/Debugger/Debugger.cpp +++ b/Src/Debugger/Debugger.cpp @@ -31,6 +31,8 @@ #include #include +using namespace std; + namespace Debugger { unsigned CDebugger::GetDataSize(UINT64 data) diff --git a/Src/Debugger/Debugger.h b/Src/Debugger/Debugger.h index 69df32c..39045ac 100644 --- a/Src/Debugger/Debugger.h +++ b/Src/Debugger/Debugger.h @@ -19,8 +19,8 @@ ** with Supermodel. If not, see . **/ -/* - * Debugger.h +/* + * Debugger.h */ #ifdef SUPERMODEL_DEBUGGER @@ -31,7 +31,6 @@ #include #include #include -using namespace std; #include "Types.h" @@ -160,7 +159,7 @@ namespace Debugger virtual void Log(CCPUDebug *cpu, const char *typeStr, const char *fmtStr, va_list vl) = 0; public: - vector cpus; + std::vector cpus; UINT64 frameCount; diff --git a/Src/Debugger/Exception.h b/Src/Debugger/Exception.h index 966fe61..948aa83 100644 --- a/Src/Debugger/Exception.h +++ b/Src/Debugger/Exception.h @@ -19,8 +19,8 @@ ** with Supermodel. If not, see . **/ -/* - * Exception.h +/* + * Exception.h */ #ifdef SUPERMODEL_DEBUGGER diff --git a/Src/Debugger/IO.cpp b/Src/Debugger/IO.cpp index c89b31f..ab71b7f 100644 --- a/Src/Debugger/IO.cpp +++ b/Src/Debugger/IO.cpp @@ -70,7 +70,7 @@ namespace Debugger return cWatch; } - CMatchWatch *CIO::AddMatchWatch(bool trigInput, bool trigOutput, vector &dataSeq) + CMatchWatch *CIO::AddMatchWatch(bool trigInput, bool trigOutput, std::vector &dataSeq) { CMatchWatch *mWatch = new CMatchWatch(cpu, this, trigInput, trigOutput, dataSeq); cpu->AddWatch(mWatch); diff --git a/Src/Debugger/IO.h b/Src/Debugger/IO.h index d5903e4..e19d9b8 100644 --- a/Src/Debugger/IO.h +++ b/Src/Debugger/IO.h @@ -1,165 +1,165 @@ -/** - ** Supermodel - ** A Sega Model 3 Arcade Emulator. - ** Copyright 2011 Bart Trzynadlowski, Nik Henson - ** - ** This file is part of Supermodel. - ** - ** Supermodel is free software: you can redistribute it and/or modify it under - ** the terms of the GNU General Public License as published by the Free - ** Software Foundation, either version 3 of the License, or (at your option) - ** any later version. - ** - ** Supermodel is distributed in the hope that it will be useful, but WITHOUT - ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - ** more details. - ** - ** You should have received a copy of the GNU General Public License along - ** with Supermodel. If not, see . - **/ - +/** + ** Supermodel + ** A Sega Model 3 Arcade Emulator. + ** Copyright 2011 Bart Trzynadlowski, Nik Henson + ** + ** This file is part of Supermodel. + ** + ** Supermodel is free software: you can redistribute it and/or modify it under + ** the terms of the GNU General Public License as published by the Free + ** Software Foundation, either version 3 of the License, or (at your option) + ** any later version. + ** + ** Supermodel is distributed in the hope that it will be useful, but WITHOUT + ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + ** more details. + ** + ** You should have received a copy of the GNU General Public License along + ** with Supermodel. If not, see . + **/ + /* * IO.h - */ - -#ifdef SUPERMODEL_DEBUGGER -#ifndef INCLUDED_IO_H -#define INCLUDED_IO_H - -#include "Types.h" - -#define MAX_LABEL_LENGTH 255 - -namespace Debugger -{ - class CCPUDebug; - class CWatch; - class CSimpleWatch; - class CCountWatch; - class CMatchWatch; - class CPrintWatch; - class CCaptureWatch; - - /* - * Base class that represents CPU input/output. - */ - class CIO - { - public: - CCPUDebug *cpu; - const char *name; - const char *group; - unsigned dataSize; - - CWatch *watch; - - unsigned inCount; - unsigned outCount; - UINT64 lastIn; - UINT64 lastOut; - UINT64 *last; - - CIO(CCPUDebug *ioCPU, const char *ioName, const char *ioGroup, unsigned ioDataSize); - - void RecordInput(UINT64 data); - - void RecordOutput(UINT64 data); - - bool CheckInput(UINT64 data); - - bool CheckOutput(UINT64 data); - - virtual void AddLabel(const char *name) = 0; - - virtual void RemoveLabel() = 0; - - CSimpleWatch *AddSimpleWatch(bool trigInput, bool trigOutput); - - CCountWatch *AddCountWatch(bool trigInput, bool trigOutput, unsigned count); - - CMatchWatch *AddMatchWatch(bool trigInput, bool trigOutput, vector &dataSeq); - - CPrintWatch *AddPrintWatch(bool trigInput, bool trigOutput); - - CCaptureWatch *AddCaptureWatch(bool trigInput, bool trigOutput, unsigned maxLen); - - bool RemoveWatch(); - - virtual void GetLocation(char *str) = 0; - - virtual UINT64 Read() = 0; - - virtual bool Write(UINT64 data) = 0; - }; - - /* - * Class that represents a CPU input/ouput port. - */ - class CPortIO : public CIO - { - private: - char labelStr[MAX_LABEL_LENGTH + 1]; - - public: - const UINT16 portNum; - - const char *label; - - CPortIO(CCPUDebug *ioCPU, const char *ioName, const char *ioGroup, unsigned ioDataSize, UINT16 ioPortNum); - - void AddLabel(const char *pLabel); - - void RemoveLabel(); - - void GetLocation(char *str); - - UINT64 Read(); - - bool Write(UINT64 data); - }; - - /* - * Class that represents CPU input/output that is mapped to a memory location. - */ - class CMappedIO : public CIO, public CAddressRef - { - public: - CMappedIO(CCPUDebug *ioCPU, const char *ioName, const char *ioGroup, unsigned ioDataSize, UINT32 ioAddr); - - bool CheckInput(UINT32 cAddr, unsigned cDataSize, UINT64 data); - - bool CheckOutput(UINT32 cAddr, unsigned cDataSize, UINT64 data); - - void AddLabel(const char *name); - - void RemoveLabel(); - - void GetLocation(char *str); - - UINT64 Read(); - - bool Write(UINT64 data); - }; - - // - // Inlined methods - // - - inline void CIO::RecordInput(UINT64 data) - { - // Keep track of data coming in - lastIn = data; - last = &lastIn; - } - - inline void CIO::RecordOutput(UINT64 data) - { - // Keep track of data going out - lastOut = data; - last = &lastOut; - } -} - -#endif // INCLUDED_IO_H + */ + +#ifdef SUPERMODEL_DEBUGGER +#ifndef INCLUDED_IO_H +#define INCLUDED_IO_H + +#include "Types.h" + +#define MAX_LABEL_LENGTH 255 + +namespace Debugger +{ + class CCPUDebug; + class CWatch; + class CSimpleWatch; + class CCountWatch; + class CMatchWatch; + class CPrintWatch; + class CCaptureWatch; + + /* + * Base class that represents CPU input/output. + */ + class CIO + { + public: + CCPUDebug *cpu; + const char *name; + const char *group; + unsigned dataSize; + + CWatch *watch; + + unsigned inCount; + unsigned outCount; + UINT64 lastIn; + UINT64 lastOut; + UINT64 *last; + + CIO(CCPUDebug *ioCPU, const char *ioName, const char *ioGroup, unsigned ioDataSize); + + void RecordInput(UINT64 data); + + void RecordOutput(UINT64 data); + + bool CheckInput(UINT64 data); + + bool CheckOutput(UINT64 data); + + virtual void AddLabel(const char *name) = 0; + + virtual void RemoveLabel() = 0; + + CSimpleWatch *AddSimpleWatch(bool trigInput, bool trigOutput); + + CCountWatch *AddCountWatch(bool trigInput, bool trigOutput, unsigned count); + + CMatchWatch *AddMatchWatch(bool trigInput, bool trigOutput, std::vector &dataSeq); + + CPrintWatch *AddPrintWatch(bool trigInput, bool trigOutput); + + CCaptureWatch *AddCaptureWatch(bool trigInput, bool trigOutput, unsigned maxLen); + + bool RemoveWatch(); + + virtual void GetLocation(char *str) = 0; + + virtual UINT64 Read() = 0; + + virtual bool Write(UINT64 data) = 0; + }; + + /* + * Class that represents a CPU input/ouput port. + */ + class CPortIO : public CIO + { + private: + char labelStr[MAX_LABEL_LENGTH + 1]; + + public: + const UINT16 portNum; + + const char *label; + + CPortIO(CCPUDebug *ioCPU, const char *ioName, const char *ioGroup, unsigned ioDataSize, UINT16 ioPortNum); + + void AddLabel(const char *pLabel); + + void RemoveLabel(); + + void GetLocation(char *str); + + UINT64 Read(); + + bool Write(UINT64 data); + }; + + /* + * Class that represents CPU input/output that is mapped to a memory location. + */ + class CMappedIO : public CIO, public CAddressRef + { + public: + CMappedIO(CCPUDebug *ioCPU, const char *ioName, const char *ioGroup, unsigned ioDataSize, UINT32 ioAddr); + + bool CheckInput(UINT32 cAddr, unsigned cDataSize, UINT64 data); + + bool CheckOutput(UINT32 cAddr, unsigned cDataSize, UINT64 data); + + void AddLabel(const char *name); + + void RemoveLabel(); + + void GetLocation(char *str); + + UINT64 Read(); + + bool Write(UINT64 data); + }; + + // + // Inlined methods + // + + inline void CIO::RecordInput(UINT64 data) + { + // Keep track of data coming in + lastIn = data; + last = &lastIn; + } + + inline void CIO::RecordOutput(UINT64 data) + { + // Keep track of data going out + lastOut = data; + last = &lastOut; + } +} + +#endif // INCLUDED_IO_H #endif // SUPERMODEL_DEBUGGER \ No newline at end of file diff --git a/Src/Debugger/Interrupt.h b/Src/Debugger/Interrupt.h index 6a40acc..551a582 100644 --- a/Src/Debugger/Interrupt.h +++ b/Src/Debugger/Interrupt.h @@ -19,8 +19,8 @@ ** with Supermodel. If not, see . **/ -/* - * Interrupt.h +/* + * Interrupt.h */ #ifdef SUPERMODEL_DEBUGGER diff --git a/Src/Debugger/Label.h b/Src/Debugger/Label.h index 219c22d..e34a63a 100644 --- a/Src/Debugger/Label.h +++ b/Src/Debugger/Label.h @@ -19,8 +19,8 @@ ** with Supermodel. If not, see . **/ -/* - * Label.h +/* + * Label.h */ #ifdef SUPERMODEL_DEBUGGER diff --git a/Src/Debugger/Register.cpp b/Src/Debugger/Register.cpp index eb680f0..e746f96 100644 --- a/Src/Debugger/Register.cpp +++ b/Src/Debugger/Register.cpp @@ -297,7 +297,7 @@ namespace Debugger { if (index >= dataWidth) exit(1); - numBits = max(numBits, index); + numBits = std::max(numBits, index); return m_bitChrs[index]; } diff --git a/Src/Debugger/Register.h b/Src/Debugger/Register.h index 125a911..f5b6513 100644 --- a/Src/Debugger/Register.h +++ b/Src/Debugger/Register.h @@ -19,8 +19,8 @@ ** with Supermodel. If not, see . **/ -/* - * Register.h +/* + * Register.h */ #ifdef SUPERMODEL_DEBUGGER diff --git a/Src/Debugger/SupermodelDebugger.cpp b/Src/Debugger/SupermodelDebugger.cpp index a0404d9..01ae992 100644 --- a/Src/Debugger/SupermodelDebugger.cpp +++ b/Src/Debugger/SupermodelDebugger.cpp @@ -599,11 +599,11 @@ namespace Debugger if (!InputIsValid(input)) continue; - idAndLabelWidth = max(idAndLabelWidth, strlen(input->id) + strlen(input->label) + 3); + idAndLabelWidth = std::max(idAndLabelWidth, strlen(input->id) + strlen(input->label) + 3); if (!input->IsVirtual()) - mappingWidth = max(mappingWidth, strlen(input->GetMapping())); + mappingWidth = std::max(mappingWidth, strlen(input->GetMapping())); } - mappingWidth = min(mappingWidth, 20); + mappingWidth = std::min(mappingWidth, 20); // Print labels, mappings and values for each input const char *groupLabel = NULL; diff --git a/Src/Debugger/SupermodelDebugger.h b/Src/Debugger/SupermodelDebugger.h index 313a344..6c0841b 100644 --- a/Src/Debugger/SupermodelDebugger.h +++ b/Src/Debugger/SupermodelDebugger.h @@ -19,8 +19,8 @@ ** with Supermodel. If not, see . **/ -/* - * SupermodelDebugger.h +/* + * SupermodelDebugger.h */ #ifdef SUPERMODEL_DEBUGGER diff --git a/Src/Debugger/Watch.cpp b/Src/Debugger/Watch.cpp index 1438726..53395dd 100644 --- a/Src/Debugger/Watch.cpp +++ b/Src/Debugger/Watch.cpp @@ -29,9 +29,10 @@ #include "Debugger.h" #include "IO.h" #include "Watch.h" - #include +using namespace std; + namespace Debugger { UINT32 CWatch::GetIOAddress(CIO *io) diff --git a/Src/Debugger/Watch.h b/Src/Debugger/Watch.h index 604791b..e4ed2ac 100644 --- a/Src/Debugger/Watch.h +++ b/Src/Debugger/Watch.h @@ -19,8 +19,8 @@ ** with Supermodel. If not, see . **/ -/* - * Watch.h +/* + * Watch.h */ #ifdef SUPERMODEL_DEBUGGER @@ -31,7 +31,6 @@ #include "Types.h" #include -using namespace std; namespace Debugger { @@ -128,9 +127,9 @@ namespace Debugger unsigned m_counter; public: - CMatchWatch(CCPUDebug *wCPU, UINT32 wAddr, unsigned wSize, bool wTrigRead, bool wTrigWrite, vector &dataSeq); + CMatchWatch(CCPUDebug *wCPU, UINT32 wAddr, unsigned wSize, bool wTrigRead, bool wTrigWrite, std::vector &dataSeq); - CMatchWatch(CCPUDebug *wCPU, CIO *wIO, bool wTrigInput, bool wTrigOutput, vector &dataSeq); + CMatchWatch(CCPUDebug *wCPU, CIO *wIO, bool wTrigInput, bool wTrigOutput, std::vector &dataSeq); ~CMatchWatch();