Antmicro is committed to creating new as well as improving existing open source SystemVerilog tools, aiming to continue expanding the open source silicon development ecosystem and help grow the adoption of this approach in the wider industry. Examples of our work include development of tools for fault-injection such as Faultergeist, and many contributions to Verilator, one of the most popular SystemVerilog simulators. We’ve introduced constrained randomization into Verilator, recently improved by bringing solution distribution closer to uniform, and have been consistently working towards implementing four-state logic and complete support for UVM, the cumulated efforts of which are converging in the SV Tools Project run by CHIPS Alliance, a Linux Foundation organization.
Blending our expertise as a Strategic Founding Member of RISC-V International and a frequent contributor to Verilator, in this article Antmicro explores a completely open source flow for RISC-V Design Verification, achieved by having made Verilator compatible with RISCV-DV, a widely used instruction generator for RISC-V design verification hosted by CHIPS Alliance.
RISCV-DV’s testing features include privileged mode, trap/interrupt handling, sub-program generation, mixing directed instructions with random instruction stream, and much more. RISC-V cores cannot be tested with any randomly picked instruction-length values, as usually they would be invalid. Even ISA-compliant instructions could cause unwanted behavior from the core. As such, RISCV-DV relies on constrained randomization in order to always provide valid sets of instructions, generating programs that are guaranteed to terminate, correctly manage the stack, access correct registers and memory addresses, and more. While the tool itself is open source, it used to require a proprietary SystemVerilog simulator, which somewhat limited its usability.
By introducing RISC-V compatibility in Verilator, Antmicro’s work opens another door for even more thorough testing of RISC-V-based platforms. The current version of RISCV-DV utilizes this to run CI verification, extending the number of possible RISC-V targets. While previously only the rv32imccore variation was run in CI verification, the list now also includes rv32i and multi_harts. As such, we eliminate the need for using proprietary simulators for RISCV-DV, speeding up development, design iteration, and agentic flows, thanks to Verilator enabling easier and faster scaling. What’s more, anyone can now contribute to RISCV-DV without owning a proprietary license. This article presents the work Antmicro has done in order to enable RISCV-DV support, including improvements to Verilator’s constrained randomization features, and enhancements and fixes of runtime elements.
Improvements to Verilator’s SystemVerilog parsing and compilation
To make using RISCV-DV and Verilator together possible, we’ve had to implement a variety of new features which were required by RISCV-DV.
As mentioned previously, RISCV-DV relies on constrained randomization to generate valid ISA instruction streams. As such, many of the features we’ve worked on relate to constraints. We added support for nested array and field access into constraints - when nested access is detected, the array is defined as separate variables rather than just as an array, which allows to interleave member access with array access. We additionally implemented support for associative arrays in nested access as well as nested access in foreach in constraints.
class Inner;
rand int x;
endclass
class Outer;
rand Inner in[3];
rand Inner in_assoc[string];
endclass
rand Outer out;
constraint c {
// Those expressions would result in an error before
out.in[2].x == 3;
out.in["abc"].x == 4;
foreach (out.in[i]) out.in[i].c != 45;
};Concerning dynamic arrays, we implemented handling of dynamic arrays inside solve...before functions. We also added support for rand dynamic arrays which are used inside with clauses and when randomize() is called on a different object, as previously this scenario resulted in an error. Another major addition is the support of unique constraints inside std::randomize.
rand int x;
rand int y[];
// rand dynamic arrays used inside with clauses
in.randomize() with {
x != y.size();
};
// unique constraints in std::randomize
std::randomize((y) with {
unique{y};
};
// Dynamic arrays inside solve...before
constraint c {
solve y[3] before y[2];
y[3] != 0 -> y[2] == 0
};Antmicro made several fixes in order to make RISCV-DV support in Verilator a reality. We focused on the issue of handling array size references, implementing fixes for issues with constraints that use array.size() calls inside of them. We fixed the incorrect randomized array size of a class when obj.randomize() was called on its internal object, as well as implemented a fix for the lack of array field randomization when base class array size was randomized inside a child class.
class Inner;
rand int x[];
endclass
rand Inner in;
rand int y[];
in.randomize() with {
// y array size was randomized, it shouldn't be
x[0] = y.size();
};
constraint c{
in.x.size() == 5;
// This 2nd statement wasn't affecting randomization result
in.x[5] % 3 == 0;
};Additionally, we added support for using struct arrays with $formatf, which prints their members via a format string.
typedef struct{
integer value;
} test_struct_t;
test_struct_t structs[1];
// Such call caused compilation error
string s = $sformatf("%p", structs[0]);Simulation runtime improvements
With the described implementation, the next step on the way toward RISCV-DV support in Verilator was addressing the limitations encountered during simulation runtime. To do so, we contributed a number of error fixes and feature enhancements.
Handling of constrained enumerated type rand variables involves the addition of another constraint, which should not be added if the variable is not constrained. Previously, that additional constraint was added every time - we have now corrected that so it is implemented only in the case of constrained variables. Similarly, we fixed an issue in which conditional statements inside constraints would use nonexisting variables, resulting in a runtime error.
class Sub;
typedef enum bit [1:0] {
one, two, three, four
} enum_t;
rand integer int_val;
rand enum_t en;
// In presence of any constraint and non-constrained enum
// runtime solver error occured
constraint c{
int_val != 0;
};
endclass
rand Sub sub;
rand Sub t[3];
constraint c{
foreach (t[i]) {
// Such constraint resulted in runtime solver error, due to conditionals error
if (i > 1) t[i].int_val > t[i-1].int_val;
}
};We also addressed incorrect handling of empty dynamic arrays, array reductions, and copy constructor of classes containing constraints.
rand int x[];
rand int y;
function new();
// Randomizing empty dynamic array resulted in runtime solver error
x = new[0];
endfunction
constraint d {
// Such constraint caused other constraints to not take effect, due to the array reduction issue
y + x.sum() == 200;
};Additionally, we made changes to weighted dist constraints and unique constraints, both of which contained errors that resulted in randomization issues.
typedef enum bit [2:0] {
one, two
} num_t;
rand int num;
constraint weight {
// Such distribution would cause a runtime solver error more than 50% of the time
num dist {
one := 5,
two := 4,
};
num != two;
}
rand bit[2:0] arr1[4], arr2[4];
constraint u {
// Such constraint would independently constrain both arrays,
// when values across both should be distinct
unique {arr1, arr2};
};The described changes allowed us to successfully use RISCV-DV with Verilator, creating a completely open source toolchain for verifying RISC-V designs.
Shortening the runway to tapeout with agentic AI and open source tools
With Verilator being an open source Verilog/SystemVerilog simulator, agentic verification of designs becomes significantly easier. Typically, proprietary simulators require a stricter environment, and licensing includes restrictions as well as costs - this can lead to agents being bottlenecked on auxiliary issues like license availability, rather than focusing on solving real digital design problems, only being bound by available compute. As such, open source tooling such as RISV-DV in combination with Verilator enable scaling of AI agent-based design verification to be easier, swifter, and more cost efficient. Antmicro has years of experience with both Verilator as well as aiding ASIC design productivity; our open source DV toolchain includes coverage visualization with Coverview, automatic testing and verification with testplanner, and generating boilerplate code for UVM agents with uvmdvgen. Our expertise extends to RISC-V as well, and we offer customization and modification services for RISC-V cores, and we help design modular and reusable RISC-V SoCs.
For a detailed breakdown of our ASIC-oriented services, visit our dedicated subpage. Or, contact us at contact@antmicro.com if you’e looking for commercial support for Verilator, a custom tool made for you specific use case, or wish to discuss how we can help you speed up your development process.
