diff --git a/dv/cs_registers/tb/tb_cs_registers.cc b/dv/cs_registers/tb/tb_cs_registers.cc index e41365ff..4d73c741 100644 --- a/dv/cs_registers/tb/tb_cs_registers.cc +++ b/dv/cs_registers/tb/tb_cs_registers.cc @@ -14,8 +14,9 @@ int simutil_verilator_set_mem(int index, const svLogicVecVal *val) { return 0; } int main(int argc, char **argv) { tb_cs_registers top; - VerilatorSimCtrl simctrl(top, top.clk_i, top.in_rst_ni, - VerilatorSimCtrlFlags::ResetPolarityNegative); + VerilatorSimCtrl &simctrl = VerilatorSimCtrl::GetInstance(); + simctrl.SetTop(&top, &top.clk_i, &top.in_rst_ni, + VerilatorSimCtrlFlags::ResetPolarityNegative); return simctrl.Exec(argc, argv); } diff --git a/dv/riscv_compliance/ibex_riscv_compliance.cc b/dv/riscv_compliance/ibex_riscv_compliance.cc index 0e98c804..67d49f5a 100644 --- a/dv/riscv_compliance/ibex_riscv_compliance.cc +++ b/dv/riscv_compliance/ibex_riscv_compliance.cc @@ -7,8 +7,9 @@ int main(int argc, char **argv) { ibex_riscv_compliance top; - VerilatorSimCtrl simctrl(top, top.IO_CLK, top.IO_RST_N, - VerilatorSimCtrlFlags::ResetPolarityNegative); + VerilatorSimCtrl &simctrl = VerilatorSimCtrl::GetInstance(); + simctrl.SetTop(&top, &top.IO_CLK, &top.IO_RST_N, + VerilatorSimCtrlFlags::ResetPolarityNegative); simctrl.RegisterMemoryArea("ram", "TOP.ibex_riscv_compliance.u_ram"); diff --git a/dv/verilator/simutil_verilator/cpp/verilator_sim_ctrl.cc b/dv/verilator/simutil_verilator/cpp/verilator_sim_ctrl.cc index c3e6499b..7832be99 100644 --- a/dv/verilator/simutil_verilator/cpp/verilator_sim_ctrl.cc +++ b/dv/verilator/simutil_verilator/cpp/verilator_sim_ctrl.cc @@ -27,39 +27,13 @@ struct BufferDesc { size_t length; }; -// Static pointer to a single simctrl instance used by SignalHandler -static VerilatorSimCtrl *simctrl = nullptr; - -static void SignalHandler(int sig) { - if (!simctrl) { - return; - } - - switch (sig) { - case SIGINT: - simctrl->RequestStop(true); - break; - case SIGUSR1: - if (simctrl->TracingEnabled()) { - simctrl->TraceOff(); - } else { - simctrl->TraceOn(); - } - break; - } -} - /** * Get the current simulation time * * Called by $time in Verilog, converts to double, to match what SystemC does */ double sc_time_stamp() { - if (simctrl) { - return simctrl->GetTime(); - } else { - return 0; - } + return VerilatorSimCtrl::GetInstance().GetTime(); } // DPI Exports @@ -80,12 +54,13 @@ extern void simutil_verilator_memload(const char *file); extern int simutil_verilator_set_mem(int index, const svLogicVecVal *val); } -VerilatorSimCtrl::VerilatorSimCtrl(VerilatedToplevel &top, CData &sig_clk, - CData &sig_rst, VerilatorSimCtrlFlags flags) - : top_(top), - sig_clk_(sig_clk), - sig_rst_(sig_rst), - flags_(flags), +VerilatorSimCtrl& VerilatorSimCtrl::GetInstance() { + static VerilatorSimCtrl instance; + return instance; +} + +VerilatorSimCtrl::VerilatorSimCtrl() + : top_(nullptr), time_(0), tracing_enabled_(false), tracing_enabled_changed_(false), @@ -99,6 +74,15 @@ VerilatorSimCtrl::VerilatorSimCtrl(VerilatedToplevel &top, CData &sig_clk, term_after_cycles_(0), callback_(nullptr) {} +void VerilatorSimCtrl::SetTop(VerilatedToplevel *top, CData *sig_clk, + CData *sig_rst, + VerilatorSimCtrlFlags flags) { + top_ = top; + sig_clk_ = sig_clk; + sig_rst_ = sig_rst; + flags_ = flags; +} + int VerilatorSimCtrl::Exec(int argc, char **argv) { RegisterSignalHandler(); @@ -141,9 +125,6 @@ void VerilatorSimCtrl::RunSimulation() { void VerilatorSimCtrl::RegisterSignalHandler() { struct sigaction sigIntHandler; - // Point the static simctrl pointer at this object - simctrl = this; - sigIntHandler.sa_handler = SignalHandler; sigemptyset(&sigIntHandler.sa_mask); sigIntHandler.sa_flags = 0; @@ -152,6 +133,23 @@ void VerilatorSimCtrl::RegisterSignalHandler() { sigaction(SIGUSR1, &sigIntHandler, NULL); } +void VerilatorSimCtrl::SignalHandler(int sig) { + VerilatorSimCtrl &simctrl = VerilatorSimCtrl::GetInstance(); + + switch (sig) { + case SIGINT: + simctrl.RequestStop(true); + break; + case SIGUSR1: + if (simctrl.TracingEnabled()) { + simctrl.TraceOff(); + } else { + simctrl.TraceOn(); + } + break; + } +} + void VerilatorSimCtrl::RequestStop(bool simulation_success) { request_stop_ = true; simulation_success_ &= simulation_success; @@ -177,8 +175,15 @@ bool VerilatorSimCtrl::TraceOff() { return tracing_enabled_; } +std::string VerilatorSimCtrl::GetName() const { + if (top_) { + return top_->name(); + } + return "unknown"; +} + void VerilatorSimCtrl::PrintHelp() const { - std::cout << "Execute a simulation model for " << top_.name() + std::cout << "Execute a simulation model for " << GetName() << "\n" "\n"; if (tracing_possible_) { @@ -529,14 +534,16 @@ void VerilatorSimCtrl::SetOnClockCallback(SimCtrlCallBack callback) { } void VerilatorSimCtrl::Run() { + assert(top_ && "Use SetTop() first."); + // We always need to enable this as tracing can be enabled at runtime if (tracing_possible_) { Verilated::traceEverOn(true); - top_.trace(tracer_, 99, 0); + top_->trace(tracer_, 99, 0); } // Evaluate all initial blocks, including the DPI setup routines - top_.eval(); + top_->eval(); std::cout << std::endl << "Simulation running, end by pressing CTRL-c." << std::endl; @@ -552,13 +559,13 @@ void VerilatorSimCtrl::Run() { UnsetReset(); } - sig_clk_ = !sig_clk_; + *sig_clk_ = !*sig_clk_; - if (sig_clk_ && (callback_ != nullptr)) { + if (*sig_clk_ && (callback_ != nullptr)) { callback_(time_); } - top_.eval(); + top_->eval(); time_++; Trace(); @@ -580,7 +587,7 @@ void VerilatorSimCtrl::Run() { } } - top_.final(); + top_->final(); time_end_ = std::chrono::steady_clock::now(); if (TracingEverEnabled()) { @@ -590,17 +597,17 @@ void VerilatorSimCtrl::Run() { void VerilatorSimCtrl::SetReset() { if (flags_ & ResetPolarityNegative) { - sig_rst_ = 0; + *sig_rst_ = 0; } else { - sig_rst_ = 1; + *sig_rst_ = 1; } } void VerilatorSimCtrl::UnsetReset() { if (flags_ & ResetPolarityNegative) { - sig_rst_ = 1; + *sig_rst_ = 1; } else { - sig_rst_ = 0; + *sig_rst_ = 0; } } diff --git a/dv/verilator/simutil_verilator/cpp/verilator_sim_ctrl.h b/dv/verilator/simutil_verilator/cpp/verilator_sim_ctrl.h index 9bb726db..efa9c604 100644 --- a/dv/verilator/simutil_verilator/cpp/verilator_sim_ctrl.h +++ b/dv/verilator/simutil_verilator/cpp/verilator_sim_ctrl.h @@ -39,16 +39,28 @@ struct MemArea { */ class VerilatorSimCtrl { public: - VerilatorSimCtrl(VerilatedToplevel &top, CData &clk, CData &rst_n, - VerilatorSimCtrlFlags flags = Defaults); + /** + * Get the simulation controller instance + * + * @see SetTop() + */ + static VerilatorSimCtrl& GetInstance(); + + VerilatorSimCtrl(VerilatorSimCtrl const&) = delete; + void operator=(VerilatorSimCtrl const&) = delete; + + /** + * Set the top-level design + */ + void SetTop(VerilatedToplevel *top, CData *sig_clk, CData *sig_rst, + VerilatorSimCtrlFlags flags = Defaults); /** * Setup and run the simulation (all in one) * * Use this function as high-level entry point, suitable for most use cases. * - * Exec() can be used only once per process as it registers a global signal - * handler. + * SetTop() must be called before this function. * * This function performs the following tasks: * 1. Sets up a signal handler to enable tracing to be turned on/off during @@ -64,7 +76,7 @@ class VerilatorSimCtrl { /** * A helper function to execute a standard set of run commands. * - * This function performs the followind tasks: + * This function performs the following tasks: * 1. Prints some tracer-related helper messages * 2. Runs the simulation * 3. Prints some further helper messages and statistics once the simulation @@ -110,6 +122,13 @@ class VerilatorSimCtrl { */ unsigned long GetTime() const { return time_; } + /** + * Get a name for this simulation + * + * This name is typically the name of the top-level. + */ + std::string GetName() const; + /** * Get the simulation result */ @@ -181,9 +200,9 @@ class VerilatorSimCtrl { void SetOnClockCallback(SimCtrlCallBack callback); private: - VerilatedToplevel &top_; - CData &sig_clk_; - CData &sig_rst_; + VerilatedToplevel *top_; + CData *sig_clk_; + CData *sig_rst_; VerilatorSimCtrlFlags flags_; unsigned long time_; bool tracing_enabled_; @@ -201,11 +220,25 @@ class VerilatorSimCtrl { int term_after_cycles_; SimCtrlCallBack callback_; + /** + * Default constructor + * + * Use GetInstance() instead. + */ + VerilatorSimCtrl(); + /** * Register the signal handler */ void RegisterSignalHandler(); + /** + * Signal handler callback + * + * Use RegisterSignalHandler() to setup. + */ + static void SignalHandler(int sig); + /** * Parse command line arguments * diff --git a/examples/simple_system/ibex_simple_system.cc b/examples/simple_system/ibex_simple_system.cc index ef25d76d..968127e2 100644 --- a/examples/simple_system/ibex_simple_system.cc +++ b/examples/simple_system/ibex_simple_system.cc @@ -10,8 +10,9 @@ int main(int argc, char **argv) { ibex_simple_system top; - VerilatorSimCtrl simctrl(top, top.IO_CLK, top.IO_RST_N, - VerilatorSimCtrlFlags::ResetPolarityNegative); + VerilatorSimCtrl &simctrl = VerilatorSimCtrl::GetInstance(); + simctrl.SetTop(&top, &top.IO_CLK, &top.IO_RST_N, + VerilatorSimCtrlFlags::ResetPolarityNegative); simctrl.RegisterMemoryArea("ram", "TOP.ibex_simple_system.u_ram");