mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-05 09:04:08 +00:00
cxxrtl: introduce performer
, a context object for eval()
. (breaking change)
At the moment the only thing it allows is redirecting `$print` cell output in a context-dependent manner. In the future, it will allow customizing handling of `$check` cells (where the default is to abort), of out-of-range memory accesses, and other runtime conditions with effects. This context object also allows a suitably written testbench to add Verilog-compliant `$time`/`$realtime` handling, albeit it involves the ceremony of defining a `performer` subclass. Most people will want something like this to customize `$time`: int64_t time = 0; struct : public performer { int64_t *time_ptr; int64_t time() const override { return *time_ptr; } } performer = { &time }; p_top.step(&performer);
This commit is contained in:
parent
02e3d508fa
commit
905f07c03f
|
@ -1077,7 +1077,15 @@ struct CxxrtlWorker {
|
|||
fmt.emit_cxxrtl(f, indent, [this](const RTLIL::SigSpec &sig) { dump_sigspec_rhs(sig); });
|
||||
dec_indent();
|
||||
f << indent << "};\n";
|
||||
f << indent << print_output << " << formatter(0, 0.0);\n";
|
||||
f << indent << "if (performer) {\n";
|
||||
inc_indent();
|
||||
f << indent << "performer->on_print(formatter(performer->time(), performer->realtime()));\n";
|
||||
dec_indent();
|
||||
f << indent << "} else {\n";
|
||||
inc_indent();
|
||||
f << indent << print_output << " << formatter(0, 0.0);\n";
|
||||
dec_indent();
|
||||
f << indent << "}\n";
|
||||
dec_indent();
|
||||
f << indent << "}\n";
|
||||
}
|
||||
|
@ -1497,11 +1505,11 @@ struct CxxrtlWorker {
|
|||
};
|
||||
if (buffered_inputs) {
|
||||
// If we have any buffered inputs, there's no chance of converging immediately.
|
||||
f << indent << mangle(cell) << access << "eval();\n";
|
||||
f << indent << mangle(cell) << access << "eval(performer);\n";
|
||||
f << indent << "converged = false;\n";
|
||||
assign_from_outputs(/*cell_converged=*/false);
|
||||
} else {
|
||||
f << indent << "if (" << mangle(cell) << access << "eval()) {\n";
|
||||
f << indent << "if (" << mangle(cell) << access << "eval(performer)) {\n";
|
||||
inc_indent();
|
||||
assign_from_outputs(/*cell_converged=*/true);
|
||||
dec_indent();
|
||||
|
@ -2384,7 +2392,8 @@ struct CxxrtlWorker {
|
|||
dump_reset_method(module);
|
||||
f << indent << "}\n";
|
||||
f << "\n";
|
||||
f << indent << "bool eval() override {\n";
|
||||
// No default argument, to prevent unintentional `return bb_foo::eval();` calls that drop performer.
|
||||
f << indent << "bool eval(performer *performer) override {\n";
|
||||
dump_eval_method(module);
|
||||
f << indent << "}\n";
|
||||
f << "\n";
|
||||
|
@ -2481,7 +2490,7 @@ struct CxxrtlWorker {
|
|||
f << "\n";
|
||||
f << indent << "void reset() override;\n";
|
||||
f << "\n";
|
||||
f << indent << "bool eval() override;\n";
|
||||
f << indent << "bool eval(performer *performer = nullptr) override;\n";
|
||||
f << "\n";
|
||||
f << indent << "template<class ObserverT>\n";
|
||||
f << indent << "bool commit(ObserverT &observer) {\n";
|
||||
|
@ -2520,7 +2529,7 @@ struct CxxrtlWorker {
|
|||
dump_reset_method(module);
|
||||
f << indent << "}\n";
|
||||
f << "\n";
|
||||
f << indent << "bool " << mangle(module) << "::eval() {\n";
|
||||
f << indent << "bool " << mangle(module) << "::eval(performer *performer) {\n";
|
||||
dump_eval_method(module);
|
||||
f << indent << "}\n";
|
||||
if (debug_info) {
|
||||
|
@ -2544,7 +2553,6 @@ struct CxxrtlWorker {
|
|||
RTLIL::Module *top_module = nullptr;
|
||||
std::vector<RTLIL::Module*> modules;
|
||||
TopoSort<RTLIL::Module*> topo_design;
|
||||
bool has_prints = false;
|
||||
for (auto module : design->modules()) {
|
||||
if (!design->selected_module(module))
|
||||
continue;
|
||||
|
@ -2557,8 +2565,6 @@ struct CxxrtlWorker {
|
|||
|
||||
topo_design.node(module);
|
||||
for (auto cell : module->cells()) {
|
||||
if (cell->type == ID($print))
|
||||
has_prints = true;
|
||||
if (is_internal_cell(cell->type) || is_cxxrtl_blackbox_cell(cell))
|
||||
continue;
|
||||
RTLIL::Module *cell_module = design->module(cell->type);
|
||||
|
@ -2617,8 +2623,6 @@ struct CxxrtlWorker {
|
|||
f << "#include \"" << basename(intf_filename) << "\"\n";
|
||||
else
|
||||
f << "#include <cxxrtl/cxxrtl.h>\n";
|
||||
if (has_prints)
|
||||
f << "#include <iostream>\n";
|
||||
f << "\n";
|
||||
f << "#if defined(CXXRTL_INCLUDE_CAPI_IMPL) || \\\n";
|
||||
f << " defined(CXXRTL_INCLUDE_VCD_CAPI_IMPL)\n";
|
||||
|
@ -3296,7 +3300,7 @@ struct CxxrtlBackend : public Backend {
|
|||
log(" value<8> p_i_data;\n");
|
||||
log(" wire<8> p_o_data;\n");
|
||||
log("\n");
|
||||
log(" bool eval() override;\n");
|
||||
log(" bool eval(performer *performer) override;\n");
|
||||
log(" template<class ObserverT>\n");
|
||||
log(" bool commit(ObserverT &observer);\n");
|
||||
log(" bool commit() override;\n");
|
||||
|
@ -3311,11 +3315,11 @@ struct CxxrtlBackend : public Backend {
|
|||
log(" namespace cxxrtl_design {\n");
|
||||
log("\n");
|
||||
log(" struct stderr_debug : public bb_p_debug {\n");
|
||||
log(" bool eval() override {\n");
|
||||
log(" bool eval(performer *performer) override {\n");
|
||||
log(" if (posedge_p_clk() && p_en)\n");
|
||||
log(" fprintf(stderr, \"debug: %%02x\\n\", p_i_data.data[0]);\n");
|
||||
log(" p_o_data.next = p_i_data;\n");
|
||||
log(" return bb_p_debug::eval();\n");
|
||||
log(" return bb_p_debug::eval(performer);\n");
|
||||
log(" }\n");
|
||||
log(" };\n");
|
||||
log("\n");
|
||||
|
@ -3416,7 +3420,7 @@ struct CxxrtlBackend : public Backend {
|
|||
log(" -print-output <stream>\n");
|
||||
log(" $print cells in the generated code direct their output to <stream>.\n");
|
||||
log(" must be one of \"std::cout\", \"std::cerr\". if not specified,\n");
|
||||
log(" \"std::cout\" is used.\n");
|
||||
log(" \"std::cout\" is used. explicitly provided performer overrides this.\n");
|
||||
log("\n");
|
||||
log(" -nohierarchy\n");
|
||||
log(" use design hierarchy as-is. in most designs, a top module should be\n");
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include <memory>
|
||||
#include <functional>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
// `cxxrtl::debug_item` has to inherit from `cxxrtl_object` to satisfy strict aliasing requirements.
|
||||
#include <cxxrtl/capi/cxxrtl_capi.h>
|
||||
|
@ -891,8 +892,21 @@ struct fmt_part {
|
|||
}
|
||||
};
|
||||
|
||||
// An object that can be passed to a `eval()` method in order to act on side effects.
|
||||
struct performer {
|
||||
// Called to evaluate a Verilog `$time` expression.
|
||||
virtual int64_t time() const { return 0; }
|
||||
|
||||
// Called to evaluate a Verilog `$realtime` expression.
|
||||
virtual double realtime() const { return time(); }
|
||||
|
||||
// Called when a `$print` cell is triggered.
|
||||
virtual void on_print(const std::string &output) { std::cout << output; }
|
||||
};
|
||||
|
||||
// An object that can be passed to a `commit()` method in order to produce a replay log of every state change in
|
||||
// the simulation.
|
||||
// the simulation. Unlike `performer`, `observer` does not use virtual calls as their overhead is unacceptable, and
|
||||
// a comparatively heavyweight template-based solution is justified.
|
||||
struct observer {
|
||||
// Called when the `commit()` method for a wire is about to update the `chunks` chunks at `base` with `chunks` chunks
|
||||
// at `value` that have a different bit pattern. It is guaranteed that `chunks` is equal to the wire chunk count and
|
||||
|
@ -1328,14 +1342,14 @@ struct module {
|
|||
|
||||
virtual void reset() = 0;
|
||||
|
||||
virtual bool eval() = 0;
|
||||
virtual bool commit() = 0;
|
||||
virtual bool eval(performer *performer = nullptr) = 0;
|
||||
virtual bool commit() = 0; // commit observer isn't available since it avoids virtual calls
|
||||
|
||||
size_t step() {
|
||||
size_t step(performer *performer = nullptr) {
|
||||
size_t deltas = 0;
|
||||
bool converged = false;
|
||||
do {
|
||||
converged = eval();
|
||||
converged = eval(performer);
|
||||
deltas++;
|
||||
} while (commit() && !converged);
|
||||
return deltas;
|
||||
|
|
Loading…
Reference in a new issue