In the earlier posts (Register Access through the Back Door and Backdoor HDL Path), we used configure
, add_hdl_path
and add_hdl_path_slice
, then these functions magically created the HDL paths. That’s fine as a user, but as an expert, would you like to know what happened in the back? This article peeks the back of the backdoor access.
Register Block’s HDL Paths
The register block stores its HDL paths in a queue. To be precise, it can have multiple queues (in a pool keyed by a string). The default key is "RTL"
. For example, you can specify the key when you call:
add_hdl_path( string path, string kind = "RTL" ); clear_hdl_path( string kind = "RTL" ); |
where the kind
argument is used as the key. We can specify the HDL path when we configure the register block:
configure( uvm_reg_block parent = null, string hdl_path = "" ); |
We can also have more than one HDL path by calling add_hdl_path
. If you have multiple HDL paths, you can read/write/peek/poke multiple physical registers at once (with the same value if write or poke). Note that read and peek return only the first read value on the paths even if you had multiple read values. The figure below illustrates how HDL paths are stored in the pool and the queues.
Register Model’s HDL Path Slices
Similar to the register block, the register model stores its HDL path slices in a queue, but in a slightly more complicated way. Since the slice has offset and size information, the slice is structured as uvm_hdl_path_slice
first. Then the slices that belong to the same physical register are grouped into a uvm_hdl_path_concat
object. We can have more than one uvm_hdl_path_concat
in the queue. If you have multiple uvm_hdl_path_concat
, you can read/write/peek/poke multiple physical registers at once (with the same value if write or poke). Note that read and peek return only the first read value on the paths even if you had multiple read values.
Like the register block, the register model can have multiple queues in a pool keyed by a string. The default key is "RTL"
. For example, you can specify the key when you call:
add_hdl_path ( uvm_hdl_path_slice slices[], string kind = "RTL" ); add_hdl_path_slice( string name, int offset, int size, bit first = 0, string kind = "RTL" ); clear_hdl_path ( string kind = "RTL" ); |
where the kind
argument is used as the key. Note that the add_hdl_path
takes a dynamic array of uvm_hdl_path_slice
that was mentioned above. The function creates a new uvm_hdl_path_concat
to store the specified slices. Similarly, if the first
argument of the add_hdl_path_slice
is 1
, then a new uvm_hdl_path_concat
is created to store the specified slice. The figure below illustrates how HDL paths are stored in the pool and the queues.
HDL Path of Jelly-Bean Register Block
Now we know the data structure behind the scenes, so let’s look at how our HDL paths are stored. We created three register blocks. Each register block has one HDL path.
HDL Path Slices of Jelly-Bean Register
We created four register models and each model has one HDL path concat that has one or more HDL path slices.
I hope this article helped you to understand the HDL path in more detail.