In SystemVerilog, force and release statements allow overriding any signal during simulation. This makes them very useful for verification, debugging and testbench execution, where they can be used to introduce errors to test features such as Dual-core Lockstep or to get the design back to a state that took a lot of time to reach.
So far, the open source Verilator RTL simulator has been using compile-time resolution of forced values. While sufficient for simple cases, this static approach can’t handle conditional forces or multiple forces targeting the same Left-Hand Side values. Antmicro’s new approach uses a sorted vector of overrides to store active force assignments, which streamlines the process of looking up and updating the forced ranges of a signal. It also allowed us to easily enable function calls on the Right-Hand Side.
In this article we describe Antmicro’s implementation of force/release statement support and other related developments that bring Verilator closer to the IEEE1800-2023 SystemVerilog standard.

Procedural continuous assignments in SystemVerilog
In SystemVerilog, as in any other hardware description programming language, an assignment has two parts, Left-Hand Side (LHS) and Right-Hand Side (RHS). The RHS can contain any expression that is evaluated to a final value, net or variable, while the LHS indicates a net or variable being updated. Procedural continuous assignments (assign/deassign, force/release) are declared inside procedural blocks, and allow expressions to be continuously assigned to nets or variables.
The force and release statements were introduced in the IEEE 1364-2001 Verilog standard. They allow overriding the drivers of any signal with another continuous driver, as shown in the example below:
wire a = b;
// here we expect at all times that a has the same value as b
force a = c;
// from now on, we expect it at all times to have the value of c
release a;
// from now on, we again expect it at all times to have the value of bThey can also be used to force a variable or net to a procedurally driven signal:
logic b = 0;
logic a = b;
// a has once-assigned value of b=0
b = 1;
// a still has value of 0, does not update
force a = c;
// from now on, we expect it at all times to have the value of c
a = d; // this has no effect
release a;
// a retains the value it had at the moment of releasing
a = d; // this has the effect of assigning the value of d once to aIn the following more complicated example, you can see the hierarchy between force/release, assign/deassign, continuous, and procedural assignments:
module top;
reg a=0,b=1;
reg [1:0] r;
initial begin
$monitor("%0t a=%b, b=%b, r=%b", $time,
a, b, r);
r = 1'b0; // 0 a=0, b=1, r=00
#1 assign r = 1'b1; // 1 a=0, b=1, r=01
#1 r = 1'b0; // ignored
#1 deassign r;
#1 r = 1'b0; // 4 a=0, b=1, r=00
#1 assign r = a;
#1 a = 1'b1; // 6 a=1, b=1, r=01
#1 a = 1'b0; // 7 a=0, b=1, r=00
#1 force r = a + b; // 8 a=0, b=1, r=01
#1 a = 1'b0; b = 1'b0; // 9 a=0, b=0, r=00
#1 a = 1'b1; b = 1'b1; // 10 a=1, b=1, r=10
#1 assign r = b; // masked by force
#1 r = 2'b11; // ignored
#1 release r; // 13 a=1, b=1, r=01
#1 b = 1'b0; // 14 a=1, b=0, r=00
end
endmoduleassign statements (e.g. in line 8) take precedence over regular procedural assignments, while force statements (line 15) override existing continuous, procedural, or continuous procedural assignments until a release statement is executed. Although force assignments are not synthesizable, they are very useful for testing corner cases or specific bugs, without having to change any RTL code.
Support for force/release statements in Verilator
Antmicro’s implementation replaces the previous per-object shadow signal model with runtime force tracking. The main goal was to support all kinds of force/release scenarios defined by the IEEE1 800-2023 specification, especially force statements under a conditional, such as:
`define IMPURE_ONE |($random | $random)
module top;
wire a;
reg b;
initial begin
if (`IMPURE_ONE == 1) force a = 1;
if (`IMPURE_ONE == 0) force a = b;
b = 0;
#1 $display(a);
release a;
end
endmoduleThis requires keeping track of the current state, i.e. which force statement is currently active and on what range, which changes dynamically during simulation.
For each forced signal, Verilator now creates a VlForceVec class object that stores the active forced ranges as a sorted, non-overlapping set of ranges. Each entry contains the destination range, a pointer to the RHS shadow storage, and the RHS offset corresponding to the destination index 0. This approach did not show meaningful regression in terms of full verilate/build time or simulation performance. For more details about the implementation, refer to the GitHub Pull Request.
Following up on this work, we also implemented support for function calls on the RHS of force, as well as procedural continuous assign/deassign statements.
Open source-driven RTL testing and verification with Verilator
Antmicro’s implementation of force/release statement support, which was partially developed within the EU-funded TRISTAN project aimed at improving RISC-V tooling, is included in Verilator’s 5.048 release.
If you would like to learn more about the efforts described in this article as well as other recent developments around Verilator, check out Antmicro’s talk at FOSSi Foundation’s Latch-Up conference. We offer comprehensive engineering services for customizing and extending Verilator, even for large designs and niche use cases. Reach out to us at contact@antmicro.com to discuss your project.
