Skip to content

Commit

Permalink
[svsim] End Verilator simulation on $finish (#4702)
Browse files Browse the repository at this point in the history
Fix a bug in how Verilator simulations work in svsim where the simulation
would _not_ terminate when a `$finish` was called.  This seems to be a bug
in Verilator where it will not terminate the simulation (as mandated by
the Verilog spec) unless you are running with time delays.

Fixes #4700.

Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
  • Loading branch information
seldridge authored Feb 19, 2025
1 parent 1904574 commit 36e4957
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 8 deletions.
23 changes: 16 additions & 7 deletions svsim/src/main/resources/simulation-driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ void initTestBenchScope() { testbenchScope = svGetScope(); }
#ifdef __cplusplus
extern "C" {
#endif
extern void run_simulation(int timesteps);
extern int run_simulation(int timesteps);
extern void simulation_main(int argc, const char **argv);
#ifdef __cplusplus
}
Expand Down Expand Up @@ -672,7 +672,8 @@ static void processCommand() {
if (*lineCursor != '\n') {
failWithError("Unexpected data at end of RUN command.");
}
run_simulation(time);
if (run_simulation(time))
receivedDone = true;

sendAck();
break;
Expand Down Expand Up @@ -757,9 +758,15 @@ static void processCommand() {
}

(*tickingPort.setter)(inPhaseValue);
run_simulation(timestepsPerPhase);
if (run_simulation(timestepsPerPhase)) {
receivedDone = true;
break;
}
(*tickingPort.setter)(outOfPhaseValue);
run_simulation(timestepsPerPhase);
if (run_simulation(timestepsPerPhase)) {
receivedDone = true;
break;
}
}

cycles--; // Consume the unbalanced increment from the while condition
Expand Down Expand Up @@ -926,16 +933,18 @@ void simulation_main(int argc, char const **argv) {
delete context;
}

void run_simulation(int delay) {
int run_simulation(int delay) {
if(!delay) {
testbench->eval_step();
return;
return context->gotFinish();
}
testbench->eval();
if (context->gotFinish())
return context->gotFinish();
context->timeInc(delay);
return 0;
}

} // extern "C"

#endif // SVSIM_ENABLE_VERILATOR_SUPPORT

4 changes: 3 additions & 1 deletion svsim/src/main/scala/Workspace.scala
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,12 @@ final class Workspace(
l(" export \"DPI-C\" task run_simulation;")
l(" task run_simulation;")
l(" input int timesteps;")
l(" output int done;")
l(" #timesteps;")
l(" done = 0;")
l(" endtask")
l(" `else")
l(" import \"DPI-C\" function void run_simulation(int timesteps);")
l(" import \"DPI-C\" function int run_simulation(int timesteps);")
l(" `endif")
l()

Expand Down
6 changes: 6 additions & 0 deletions svsim/src/test/resources/Finish.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Finish(input clock);

always @ (posedge clock)
$finish;

endmodule
33 changes: 33 additions & 0 deletions svsim/src/test/scala/BackendSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,39 @@ trait BackendSpec extends AnyFunSpec with Matchers {
}
}
}

it("ends the simulation on '$finish' (#4700)") {
workspace.reset()
workspace.elaborateFinishTest()
workspace.generateAdditionalSources()
simulation = workspace.compile(
backend
)(
workingDirectoryTag = name,
commonSettings = CommonCompilationSettings(),
backendSpecificSettings = compilationSettings,
customSimulationWorkingDirectory = None,
verbose = false
)
simulation.run(
verbose = false,
executionScriptLimit = None
) { controller =>
val clock = controller.port("clock")
clock.tick(
inPhaseValue = 0,
outOfPhaseValue = 1,
timestepsPerPhase = 1,
maxCycles = 8,
sentinel = None
)
}
val re = ".*Verilog \\$finish.*".r
new BufferedReader(new FileReader(s"${simulation.workingDirectoryPath}/simulation-log.txt")).lines
.filter(re.matches(_))
.toArray
.size must be(1)
}
}
}
}
15 changes: 15 additions & 0 deletions svsim/src/test/scala/Resources.scala
Original file line number Diff line number Diff line change
Expand Up @@ -131,5 +131,20 @@ object Resources {
)
)
}
def elaborateFinishTest(): Unit = {
workspace.addPrimarySourceFromResource(getClass, "/Finish.sv")
workspace.elaborate(
ModuleInfo(
name = "Finish",
ports = Seq(
new ModuleInfo.Port(
name = "clock",
isSettable = true,
isGettable = false
)
)
)
)
}
}
}

0 comments on commit 36e4957

Please sign in to comment.