TL; DR;
This affects parameterized modules that create variable number of csrs, fields and RTL IOs - example: rv_timer. Having arrayed implementations of IOs / CSRs / FIELDS will be a lot beneficial for DV.
Taking rv_timer as an example: It has 2 parameters - number of timers and number of harts per timer. At this point, the number of timers and harts is fixed to 1 each. In future, this may increase based on need.
The RTL creates individual IOs corresponding to each timer / hart.
Example: rv_timer output port - intr_timer_expired_0_0.
As the parameter values changes, more individual IOs will be created. It will be beneficial for DV to make this an array instead. Sure, we can create the array in our testbench and use that to do our checks, however the onus still is on the DV engineer to make the change in the testbench when more such IOs are added in RTL. Had the RTL output been an array instead, NO change will be required to be made in DV and all testing will automatically adjust to the new parameter values. Designer can simply change the parameter value and run DV regression suite to confirm no breakage and wouldn't need to involve DV at all.
This problem extends to the reg hjson as well. We have rv_timer template hjson which is converted to the actual hjson that meets the current parameter value requirements (num timers = 1, num harts = 1).
The generated hjson is problematic for our DV field abstraction, which looks like this:
{ multireg: {
name: "CTRL",
desc: "Control register",
count: 1,
cname: "TIMER",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "0", name: "active", desc: "If 1, timer operates" }
],
}
},
This ends up creating a fixed field abstraction called 'active0' in the ctrl register abstraction. This is problematic for DV since it is not scalable. When num timers parameter increases, this will result in additional fields 'active1', 'active2' and so on. This makes it hard to write a generic DV code to target a particular timer, since the field model objects are unique for each timer instance. We will end up having to write an if-else loop to check the timer value and then set that particular field (or do a string based field search within the register for all accesses, which ends up being compute intensive and may slow down the simulation):
function enable_timer(int timer);
if (timer == 0) ral.ctrl.active0.set(1'b1);
else if (timer == 1) ral.ctrl.active1.set(1'b1);
...
OR
uvm_reg_field fld = ral.ctrl.get_field_by_name($sformatf("active%0d", timer));
fld.set(1'b1);
...
endfunction
The field 'active' should instead be a bit vector [NUM_TIMERS-1:0], which will make our code much simpler:
function enable_timer(int timer);
wdata = ral.ctrl.active.get(); // get previous value written
wdata |= 1 << timer;
ral.ctrl.active.set(wdata);
...
endfunction
The generated hjson is also problematic for the following register abstraction, which looks like this:
{ skipto: "0x100" },
{ name: "CFG0",
desc: "Configuration for Hart 0",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "11:0", name: "prescale", desc: "Prescaler to generate tick" },
{ bits: "23:16", name: "step", resval: "0x1", desc: "Incremental value for each tick" },
],
},
This creates a fixed register called 'cfg0' for hart # 0. When the number of harts parameter is increased, this will create additional 'cfg1', cfg2' and so on registers. This is again problematic for DV since it is not scalable. We end up having to do a string based lookup similar to the field example above.
At this point, this is a tiny bench so compute-intensiveness is not an issue. However, it might be a problematic for chip top sims or other larger parameterized IPs we might end up adding in future. Also, the string based lookup to make the DV bench generic is not an elegant solution. It would be worthwhile to invest in a better solution to this problem - perhaps enhance the reg hjson semantics to support such parameterized implementations natively, such that it creates arrayed implementations of csr and field abstractions for DV.
Thanks
Sri