diff --git a/build/.gitignore b/build/.gitignore deleted file mode 100644 index 72e8ffc0d..000000000 --- a/build/.gitignore +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/include/RDB.h b/include/RDB.h new file mode 100644 index 000000000..33b8e0e3b --- /dev/null +++ b/include/RDB.h @@ -0,0 +1,53 @@ +// +// _RDB_h_ +// +// Copyright (C) 2017-2023 Tactical Computing Laboratories, LLC +// All Rights Reserved +// contact@tactcomplabs.com +// +// See LICENSE in the top level directory for licensing details +// + +#ifndef __REV_RDB_H__ +#define __REV_RDB_H__ + +#include + +// -- SST Headers +#include "SST.h" + +//Rev Headers +#include "RevProc.h" + +namespace SST::RevCPU{ +class RevProc; + +class RDB { + public: + RDB(SST::Cycle_t firstBreak); + ~RDB(); + + bool GetCommand(); + SST::Cycle_t GetNextBreakpoint() const {return breakCycle;}; + uint64_t GetPCBreakpoint() const {return breakPC;} + void SetNextBreakpoint(SST::Cycle_t cycle){ breakCycle = cycle;} + + void SetProcToDebug(RevProc* p){proc = p;}; + + protected: + SST::Cycle_t breakCycle; + uint64_t breakPC; + RevProc* proc; + std::vector cmdLine; + + void PrintRegister(); + void Step(); + void PrintHelp(); + void PC(); + +}; + +}; + + +#endif \ No newline at end of file diff --git a/include/RevCPU.h b/include/RevCPU.h index b2d79e307..a889e4c11 100644 --- a/include/RevCPU.h +++ b/include/RevCPU.h @@ -39,6 +39,7 @@ #include "RevNIC.h" #include "RevCoProc.h" #include "RevRand.h" +#include "RDB.h" namespace SST::RevCPU{ @@ -112,6 +113,7 @@ class RevCPU : public SST::Component{ {"trcStartCycle", "Starting tracer cycle (disables trcOp)", "0"}, {"splash", "Display the splash logo", "0"}, {"independentCoprocClock", "Enables each coprocessor to register its own clock handler", "0"}, + {"breakAtCycle", "Break execution and drop into debugger at cycle", "0"}, ) // ------------------------------------------------------- @@ -212,6 +214,7 @@ class RevCPU : public SST::Component{ unsigned RDMAPerCycle; ///< RevCPU: number of RDMA messages per cycle to inject into PAN network unsigned testStage; ///< RevCPU: controls the PAN Test harness staging unsigned testIters; ///< RevCPU: the number of message iters for each PAN Test + SST::Cycle_t breakAtCycle; ///< RevCPU: The clock cycle to drop into the debugger - RDB std::string Exe; ///< RevCPU: binary executable std::string Args; ///< RevCPU: argument list RevOpts *Opts; ///< RevCPU: Simulation options object @@ -294,6 +297,7 @@ class RevCPU : public SST::Component{ std::vector CoProcs; ///< RevCPU: CoProcessor attached to Rev SST::Clock::Handler* ClockHandler; ///< RevCPU: Clock Handler + RDB rdb; std::queue> ZeroRqst; ///< RevCPU: tracks incoming zero address put requests; pair std::list> TrackTags; ///< RevCPU: tracks the outgoing messages; pair diff --git a/include/RevProc.h b/include/RevProc.h index 4724e13a5..c8cf0ef6d 100644 --- a/include/RevProc.h +++ b/include/RevProc.h @@ -50,6 +50,7 @@ #include "RevRand.h" #include "RevProcPasskey.h" #include "RevHart.h" +#include "RDB.h" #define SYSCALL_TYPES_ONLY #include "../common/syscalls/syscalls.h" #include "../common/include/RevCommon.h" @@ -66,6 +67,8 @@ class RevProc{ /// RevProc: standard destructor ~RevProc() = default; + friend class RDB; + /// RevProc: per-processor clock function bool ClockTick( SST::Cycle_t currentCycle ); @@ -82,13 +85,16 @@ class RevProc{ bool SingleStepHart(); /// RevProc: retrieve the local PC for the correct feature set - uint64_t GetPC() const { return RegFile->GetPC(); } + uint64_t GetPC() const { return RegFile ? RegFile->GetPC() : 0; } + + /// RevProc: retrieve the local PC for the correct feature set + uint64_t GetPC(unsigned hartID) const { return IdleHarts[hartID] ? 0 : Harts[hartID]->RegFile->GetPC(); } /// RevProc: set time converter for RTC void SetTimeConverter(TimeConverter* tc) { timeConverter = tc; } /// RevProc: Debug mode read a register - bool DebugReadReg(unsigned Idx, uint64_t *Value) const; + bool DebugReadReg(unsigned Idx, uint64_t *Value, unsigned hartID) const; /// RevProc: Debug mode write a register bool DebugWriteReg(unsigned Idx, uint64_t Value) const; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4fd889cce..d3857d7a1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -22,6 +22,7 @@ set(RevCPUSrcs RevCoProc.cc RevRegFile.cc RevThread.cc + RDB.cc ) add_subdirectory(../common common) diff --git a/src/RDB.cc b/src/RDB.cc new file mode 100644 index 000000000..96e443cad --- /dev/null +++ b/src/RDB.cc @@ -0,0 +1,100 @@ + +// +// _RDB_cc_ +// +// Copyright (C) 2017-2023 Tactical Computing Laboratories, LLC +// All Rights Reserved +// contact@tactcomplabs.com +// +// See LICENSE in the top level directory for licensing details +// + +#include "RDB.h" + + +namespace SST::RevCPU{ + RDB::RDB(SST::Cycle_t firstBreak): + breakCycle(firstBreak), breakPC(0), proc(nullptr), cmdLine() { + + cmdLine.clear(); + } + + RDB::~RDB(){ + + } + + void RDB::PrintHelp(){ + std::cout << "Supported commands:" << std::endl; + std::cout << "\treg // Print Register value. num >= 32 will print all regs" << std::endl; + std::cout << "\ts // Step forward num cycles - default is one cycle" << std::endl; + std::cout << "\tpc // Execute until hart reaches pc == num" << std::endl; + std::cout << "\tc // Continue (exit debugger)" << std::endl; + } + + bool RDB::GetCommand(){ + + //Supported commands: + // reg // Print Register value + // s // Step forward num cycles - default is one cycle + // pc // Execute until hart reaches pc == num. num must be in hex + // c // Continue (exit debugger) + + std::string input; + std::stringstream line; + std::string field; + bool rtn = true; + std::cout << "Core " << proc->id << " PC: " << std::hex << proc->GetPC() << std::dec << " rdb% "; + std::getline(std::cin, input); + line.str(input); + for(field; std::getline(line, field, ' ');){ + cmdLine.push_back(field); + } + + if(cmdLine[0] == "reg"){ + PrintRegister(); + rtn = true; + }else if(cmdLine[0] == "s"){ + Step(); + rtn = false; + }else if(cmdLine[0] == "pc"){ + PC(); + rtn = true; + }else if(cmdLine[0] == "c"){ + breakCycle = 0; + rtn = false; + }else{ + std::cout << "INVALID COMMAND" << std::endl; + PrintHelp(); + rtn = true; + } + + cmdLine.clear(); + return rtn; + } + + void RDB::Step(){ + int stepCount = 1; + if(cmdLine.size() > 1){ + stepCount = std::stoi(cmdLine[1]); + } + breakCycle += stepCount; + } + + void RDB::PrintRegister(){ + uint64_t val = 0; + int reg = std::stoi(cmdLine[2]); + int hart = std::stoi(cmdLine[1]); + if(reg < _REV_NUM_REGS_){ + proc->DebugReadReg(reg, &val, hart); + std::cout << "Core " << proc->id << ":" << hart << " x" << reg << " = " << std::hex << val << std::dec << std::endl; + }else{ + std::cout << "Core " << proc->id << " x" << reg << " is out of range" << std::endl; + if(proc->RegFile) {std::cout << *(proc->RegFile);} + } + } + + void RDB::PC(){ + breakPC = std::stoi(cmdLine[2], nullptr, 16); + } + +} //namespace diff --git a/src/RevCPU.cc b/src/RevCPU.cc index f371a323c..ae283dc19 100644 --- a/src/RevCPU.cc +++ b/src/RevCPU.cc @@ -33,7 +33,7 @@ const char splash_msg[] = "\ RevCPU::RevCPU( SST::ComponentId_t id, const SST::Params& params ) : SST::Component(id), testStage(0), PrivTag(0), address(-1), EnableMemH(false), - DisableCoprocClock(false), Nic(nullptr), Ctrl(nullptr), ClockHandler(nullptr) { + DisableCoprocClock(false), Nic(nullptr), Ctrl(nullptr), ClockHandler(nullptr), rdb(0){ const int Verbosity = params.find("verbose", 0); @@ -169,6 +169,10 @@ RevCPU::RevCPU( SST::ComponentId_t id, const SST::Params& params ) const uint64_t maxHeapSize = params.find("maxHeapSize", memSize/4); Mem->SetMaxHeapSize(maxHeapSize); + // Set Breakpoint + breakAtCycle = params.find("breakAtCycle", 0); + rdb.SetNextBreakpoint(breakAtCycle); + // Load the binary into memory // TODO: Use std::nothrow to return null instead of throwing std::bad_alloc Loader = new RevLoader( Exe, Args, Mem, &output ); @@ -586,9 +590,30 @@ bool RevCPU::clockTick( SST::Cycle_t currentCycle ){ output.verbose(CALL_INFO, 8, 0, "Cycle: %" PRIu64 "\n", currentCycle); + //RDB Control + bool dbgBreak = false; + + if(currentCycle && (rdb.GetNextBreakpoint() == currentCycle)){ + dbgBreak = true; + output.verbose(CALL_INFO, 1, 0, "Breakpoint found at Cycle: %" PRIu64 "\n", currentCycle); + } + // Execute each enabled core for( size_t i=0; iGetPC(0) && (Procs[i]->GetPC(0) == rdb.GetPCBreakpoint())){ + output.verbose(CALL_INFO, 1, 0, "Breakpoint found at PC: %" PRIx64 "\n", Procs[i]->GetPC(0)); + rdb.SetProcToDebug(Procs[i]); + while(rdb.GetCommand()){}; + breakAtCycle = rdb.GetNextBreakpoint(); + } UpdateThreadAssignments(i); if( Enabled[i] ){ if( !Procs[i]->ClockTick(currentCycle) ){ diff --git a/src/RevProc.cc b/src/RevProc.cc index c37a0facd..6ac3ef831 100644 --- a/src/RevProc.cc +++ b/src/RevProc.cc @@ -1270,13 +1270,13 @@ RevInst RevProc::DecodeR4Inst(uint32_t Inst, unsigned Entry) const { return DInst; } -bool RevProc::DebugReadReg(unsigned Idx, uint64_t *Value) const { +bool RevProc::DebugReadReg(unsigned Idx, uint64_t *Value, unsigned hartID) const { if( !Halted ) return false; - if( Idx >= _REV_NUM_REGS_ ){ + if( (Idx >= _REV_NUM_REGS_) || (hartID > Harts.size() ) ){ return false; } - RevRegFile* regFile = GetRegFile(HartToExecID); + RevRegFile* regFile = GetRegFile(hartID); *Value = regFile->GetX(Idx); return true; } diff --git a/test/rev-model-options-config.py b/test/rev-model-options-config.py index d5ab7df0a..2f7471980 100644 --- a/test/rev-model-options-config.py +++ b/test/rev-model-options-config.py @@ -56,6 +56,7 @@ "startSymbol" : args.startSymbol, "enable_memH" : args.enableMemH, "args": args.args, + "breakAtCycle" : 13, "splash" : 1 })