So, here we are on Day-1 of UVM + Verilator becoming available to the public, start of democratizing chip design verification. In case you just woke-up/started on this topic, read the release of UVM + Verilator with some intricate details on the challenge on the way by Antmicro via: https://antmicro.com/blog/2023/10/running-simple-uvm-testbenches-in-verilator/
Awesome work by the folks at Antmicro and fantastic support by the ecosystem specifically Western Digital, kudos!
At AsFigo, we are committed to fueling open-source driven chip design and verification. So we took this opportunity to port a commercial-grade UVC (Universal Verification Component or a Verification IP) and ported it to compile and run on Verilator. Below are our reflections from this experiment. Get in touch with us to discuss how AsFigo can help your VIPs and testbenches to be ported to opensource EDA.
Case study:
VLBus - a simple peripheral bus intended for write/read to configuration registers (like the popular APB).
https://www.accellera.org/resources/videos/uvm-tutorial-2017 (Part-4).
UVC Code changes for Verilator:
Interface:
vlb_if.sv: Strictly speaking no change, Verilator does support clocking block, including default clocking. However, when a class-based driver/minor accesses signals via clocking block, there are some unsupported features. So please pay attention to clocking blocks!
Transaction model/SEQ item:
UVM field macros for enumerated type - `uvm_field_enum is not fully supproted, so hide it inside VERILATOR macro.
UVM Driver:
UVM Driver is responsible to drive transactions to the DUT via virtual interface. As noted in the interface section above, Verilator as of today does not support drive through a clocking block. So below is a workaround:
Another important fix in driver is the use of
"@(posedge this.vif.clk)" - instead of classical
"@(vif.cb)".
UVM Monitor:
Similar to driver, monitor sampling cannot use clocking block as of today and the restriction on use of event delay via clocking block is not supported.
Verilator's UVM support around TLM ports is still maturing and hence the REQ/RSP parameters need to be passed explicitly in sequencer. Below is a sample error you would get with a classical UVM sequencer code in Verilator:
%Error: ../../../../uvm/src/seq/uvm_sequencer.svh:156:21: Function Argument expects a CLASSREFDTYPE 'uvm_sequencer__Tz117_TBz117', got CLASSREFDTYPE 'uvm_sequencer__Tz117'
: ... note: In instance 'vlb_top.dut'
156 | seq_item_export = new ("seq_item_export", this);
| ^~~
It is not obvious, but the fix is really straight-forward as shown below:
`ifndef VERILATOR
class vlb_sequencer extends uvm_sequencer#(vlb_xactn);
`else
class vlb_sequencer extends uvm_sequencer#(vlb_xactn, vlb_xactn);
`endif // VERILATOR
We were surprised to get an error at run-time as below:
UVM_INFO @ 0: reporter [RNTST] Running test rand_test...
[0] %Error: vlb_agent.sv:54: Assertion failed in TOP.vlb_top.vlb_agent.__m_uvm_execute_field_op: 'assert' failed.
%Error: ../tb_src/vlb_agent.sv:54: Verilog $stop
The root-cause was the lack of support for `uvm_field_enum and we hid it under VERILATOR macro. However, this led to a large turn-around time as today the Verilator + UVM compile times are large. So we suggest you look for details before firing off your Verilator + UVM compile!
`ifndef VERILATOR
`uvm_field_enum(uvm_active_passive_enum, is_active,UVM_ALL_ON)
`endif // VERILATOR
`uvm_component_utils_end
UVM Test/base test:
This specific UVC was built using UVM 1.1d and the shipped version of UVM is IEEE 1800.2.2017 (To be confirmed). A subtle change is that the global variable uvm_top was removed in UVM 1.2 and hence we just hid it as below.
UVM Sequences:
Constrained random generation is still under development in Verilator. As noted in above section, this UVC used UVM 1.1d, hence the starting_phase variable needed special handling (UVM library feature/issue than Verilator's). Below is a snapshot of the fix:
Also, since it uses UVM IEEE 1800.2-2017, the popular UVM Sequence DO macros are not available. So, hide them under VERILATOR macro and use start_item/finish_item API for now.
`uvm_info (get_name(), "Sample message", UVM_HIGH)
Note on compile-times:
If you've already tried Verilator + UVM, you would have noticed very long compile times. This is not all that new, given the massive amount of code that goes into getting a UVM test run and the way compilers are built - this is how it starts. Once the functionality is at an acceptable level, you get compiler geeks and optimize, so don't feel let-down with long-compiles, grab your coffee/tea/favorite drink - while Verilator compiles your UVM.
Do yourself a favor by reading through this blog in detail and make sure you fix all these in your code before you kick-off a compile. If you find new issues, feel free to add those in the comments section!
Avoid run-time assert failure - that dreaded uvm_component_utils_begin:
The biggest surprise and time-consuming (due to the large compile times, see above) task in this porting of a real-life UVC to Verilator was the dreaded run-time error you get after some good 30 minutes of compile. Here is a sample:
UVM_INFO @ 0: reporter [RNTST] Running test rand_test...
[0] %Error: vlb_agent.sv:54: Assertion failed in TOP.vlb_top.vlb_agent.__m_uvm_execute_field_op: 'assert' failed.
%Error: ../tb_src/vlb_agent.sv:54: Verilog $stop
After few iterations/trail-and-error we narrowed it down to `uvm_component_utils_begin-endi usage. So do the following and be Verilator-friendly!
Get in touch with us to discuss how
AsFigo can help your VIPs and testbenches to be ported to opensource EDA. Below is our result after this mini-marathon.
Comments
Post a Comment