mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-22 04:57:25 -04:00
Make VerilatorSimCtrl class a singleton
The VerilatorSimCtrl class was always intended to be used only once in an application, since it sets up a global signal handler and needs to be accessible from DPI modules. This accessibility was achieved through a global variable `simctrl`. With this commit the VerilatorSimCtrl is switched to a singleton class. The instance is accessible through `VerilatorSimCtrl::GetInstance()`. The downside of that approach is that we loose the constructor arguments, and need to deal with a class which potentially hasn't top or the clock and reset signals set.
This commit is contained in:
parent
afdee5c596
commit
82e0faf50b
5 changed files with 104 additions and 61 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue