From c108f5def98ad6791a051d792a8452ffd0d61d85 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 5 Mar 2020 19:09:58 -0500 Subject: [PATCH] Commentary, Closes #2177. --- bin/verilator | 37 ++++++++++++++++++++++++++-- examples/make_tracing_c/sim_main.cpp | 31 +++++++++++------------ examples/make_tracing_c/sub.v | 17 ------------- examples/make_tracing_c/top.v | 2 -- 4 files changed, 50 insertions(+), 37 deletions(-) diff --git a/bin/verilator b/bin/verilator index 1714ed230..57ae1c283 100755 --- a/bin/verilator +++ b/bin/verilator @@ -1936,6 +1936,39 @@ when your source changes it will automatically run all of these steps. See the examples directory in the distribution. +=head1 EVALUATION LOOP + +When using SystemC, when Verilator is evaluated is managed by the SystemC +kernel, and for the most part can be ignored. When using C++, the user +must call eval(), or eval_step() and eval_end_step(). + +1. When there is a single design instantiated at the C++ level that need to +evaluate, just call designp->eval(). + +2. When there are multiple designs instantiated each at the C++ level that +need to evaluate, call first_designp->eval_step() then ->eval_step() on all +other designs. Then call ->eval_end_step() on the first design then all +other designs. If there is only a single design, you would call +eval_step() then eval_end_step(); in fact eval() described above is just a +wrapper which calls these two functions. + +When eval() is called Verilator looks for changes in clock signals and +evaluates related sequential always blocks, such as computing always_ff @ +(posedge...) outputs. Then Verilator evaluates combinatorial logic. + +Note combinatorial logic is not computed before sequential always blocks +are computed (for speed reasons). Therefore it is best to set any non-clock +inputs up with a separate eval() call before changing clocks(). + +Alternatively, if all always_ff statements use only the posedge of clocks, +or all inputs go directly to always_ff statements, as is typical, then you +can change non-clock inputs on the negative edge of the input clock, which +will be faster as there will be fewer eval() calls. + +For more information on evaluation, see docs/internals.adoc in the +distribution. + + =head1 BENCHMARKING & OPTIMIZATION For best performance, run Verilator with the "-O3 --x-assign fast @@ -2212,7 +2245,7 @@ example: Note signals are read and written as member variables of the lower module. You call the eval() method to evaluate the model. When the simulation is complete call the final() method to wrap up any SystemVerilog final blocks, -and complete any assertions. +and complete any assertions. See L. =head1 CONNECTING TO SYSTEMC @@ -5335,7 +5368,7 @@ L, L, L, L, L which is the source for this document, -and internals.txt in the distribution. +and docs/internals.adoc in the distribution. =cut diff --git a/examples/make_tracing_c/sim_main.cpp b/examples/make_tracing_c/sim_main.cpp index 1e75819f4..527ff105b 100644 --- a/examples/make_tracing_c/sim_main.cpp +++ b/examples/make_tracing_c/sim_main.cpp @@ -46,7 +46,6 @@ int main(int argc, char** argv, char** env) { // Set some inputs top->reset_l = !0; - top->fastclk = 0; top->clk = 0; top->in_small = 1; top->in_quad = 0x1234; @@ -58,22 +57,22 @@ int main(int argc, char** argv, char** env) { while (!Verilated::gotFinish()) { main_time++; // Time passes... - // Toggle clocks and such - top->fastclk = !top->fastclk; - if ((main_time % 10) == 3) { - top->clk = 1; - } - if ((main_time % 10) == 8) { - top->clk = 0; - } - if (main_time > 1 && main_time < 10) { - top->reset_l = !1; // Assert reset - } else { - top->reset_l = !0; // Deassert reset - } + // Toggle a fast (time/2 period) clock + top->clk = !top->clk; - // Assign some other inputs - top->in_quad += 0x12; + // Toggle control signals on an edge that doesn't correspond + // to where the controls are sampled; in this example we do + // this only on a negedge of clk, because we know + // reset is not sampled there. + if (!top->clk) { + if (main_time > 1 && main_time < 10) { + top->reset_l = !1; // Assert reset + } else { + top->reset_l = !0; // Deassert reset + } + // Assign some other inputs + top->in_quad += 0x12; + } // Evaluate model // (If you have multiple models being simulated in the same diff --git a/examples/make_tracing_c/sub.v b/examples/make_tracing_c/sub.v index e50d43d51..553d85921 100644 --- a/examples/make_tracing_c/sub.v +++ b/examples/make_tracing_c/sub.v @@ -7,25 +7,10 @@ module sub ( input clk, - input fastclk, input reset_l ); // Example counter/flop - reg [31:0] count_f; - always_ff @ (posedge fastclk) begin - if (!reset_l) begin - /*AUTORESET*/ - // Beginning of autoreset for uninitialized flops - count_f <= 32'h0; - // End of automatics - end - else begin - count_f <= count_f + 1; - end - end - - // Another example flop reg [31:0] count_c; always_ff @ (posedge clk) begin if (!reset_l) begin @@ -37,8 +22,6 @@ module sub else begin count_c <= count_c + 1; if (count_c >= 3) begin - $display("[%0t] fastclk is %0d times faster than clk\n", - $time, count_f/count_c); // This write is a magic value the Makefile uses to make sure the // test completes successfully. $write("*-* All Finished *-*\n"); diff --git a/examples/make_tracing_c/top.v b/examples/make_tracing_c/top.v index 0dc22d9cc..ac537c68f 100644 --- a/examples/make_tracing_c/top.v +++ b/examples/make_tracing_c/top.v @@ -11,7 +11,6 @@ module top ( // Declare some signals so we can see how I/O works input clk, - input fastclk, input reset_l, output wire [1:0] out_small, @@ -31,7 +30,6 @@ module top sub sub (/*AUTOINST*/ // Inputs .clk (clk), - .fastclk (fastclk), .reset_l (reset_l)); // Print some stuff as an example