Our jelly-bean tasting business became very successful, so we decided to expand our business into partnership with another jelly-bean taster. During the process of the merger, however, we found that the partner had slightly different register structure than ours. We want to access the partner’s registers through the back door without modifying the register model we already have. But, how do we specify the HDL paths?
Partnership (DUT)
This is how the new DUT (jelly_bean_partnership
) looks.
The partnership module includes our old jelly_bean_taster
as well as the new jelly_bean_partner
. We also added a new signal called taster_id
, which selects either taster
or partner
, to the jelly_bean_if
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | module jelly_bean_partnership( jelly_bean_if.slave_mp jb_if ); import jelly_bean_pkg::*; jelly_bean_if jb_if0( jb_if.clk ); jelly_bean_if jb_if1( jb_if.clk ); jelly_bean_taster taster ( jb_if0 ); jelly_bean_partner partner( jb_if1 ); always @* begin jb_if0.flavor = jb_if.flavor; jb_if1.flavor = jb_if.flavor; jb_if0.color = jb_if.color; jb_if1.color = jb_if.color; jb_if0.sugar_free = jb_if.sugar_free; jb_if1.sugar_free = jb_if.sugar_free; jb_if0.sour = jb_if.sour; jb_if1.sour = jb_if.sour; if ( jb_if.taster_id == 0 ) begin jb_if0.command = jb_if.command; jb_if1.command = NO_OP; jb_if.taste = jb_if0.taste; end else begin jb_if0.command = NO_OP; jb_if1.command = jb_if.command; jb_if.taste = jb_if1.taste; end end // always @ * endmodule: jelly_bean_partnership |
Partner
The partner module does jelly-bean tasting in a similar way as the jelly_bean_taster
. It has the equivalent registers as the jelly_bean_taster
, but its structure is different. In particular:
- The partner has one 5-bit consolidated
color_and_flavor
register (line 5). - The
sour
andsugar_free
registers are within another module instance calledextra
(lines 37 and 38).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | module jelly_bean_partner( jelly_bean_if.slave_mp jb_if ); import jelly_bean_pkg::*; reg [1:0] taste; reg [4:0] color_and_flavor; reg [1:0] command; jelly_bean_extra extra(); initial begin color_and_flavor = 0; extra.sugar_free = 0; extra.sour = 0; command = 0; taste = 0; end always @ ( posedge jb_if.clk ) begin command < = jb_if.command; if ( jb_if.command == JB_WRITE ) begin color_and_flavor <= { jb_if.color, jb_if.flavor }; extra.sugar_free <= jb_if.sugar_free; extra.sour <= jb_if.sour; end else if ( jb_if.command == JB_READ ) begin jb_if.taste <= #2ns taste; end end always @ ( posedge jb_if.clk ) begin if ( jb_if.flavor == CHOCOLATE && jb_if.sour ) taste <= YUCKY; else if ( jb_if.flavor != NO_FLAVOR ) taste <= YUMMY; end endmodule: jelly_bean_partner module jelly_bean_extra; reg sugar_free; reg sour;endmodule: jelly_bean_extra |
Register Model
The top-level register block (jelly_bean_partnership_reg_block
) instantiates two jelly_bean_reg_block
s we created before; one (jb_reg_blocks[0]
) for the taster and the other (jb_reg_block[1]
) for the partner.
Then we set the HDL path of the jb_reg_blocks[0]
to be "taster"
(line 16), which matches the instance name of the jelly_bean_taster
in the jelly_bean_partnership
module (see the line 7 of the jelly_bean_partnership
above). Similarly, we set the HDL path of the jb_reg_blocks[1]
to be "partner"
(line 21), which matches the instance name of the jelly_bean_partner
in the jelly_bean_partnership
module (see the line 8 of the jelly_bean_partnership
above).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | class jelly_bean_partnership_reg_block extends uvm_reg_block; `uvm_object_utils( jelly_bean_partnership_reg_block ) rand jelly_bean_reg_block jb_reg_blocks[2]; uvm_reg_map reg_map; function new( string name = "jelly_bean_partnership_reg_block" ); super.new( .name( name ), .has_coverage( UVM_NO_COVERAGE ) ); endfunction: new virtual function void build(); reg_map = create_map( .name( "reg_map" ), .base_addr( 8'h00 ), .n_bytes( 1 ), .endian( UVM_LITTLE_ENDIAN ) ); jb_reg_blocks[0] = jelly_bean_reg_block::type_id::create( "jb_reg_blocks[0]" ); jb_reg_blocks[0].configure( .parent( this ), .hdl_path( "taster" ) ); jb_reg_blocks[0].build(); reg_map.add_submap( .child_map( jb_reg_blocks[0].reg_map ), .offset( 0 ) ); jb_reg_blocks[1] = jelly_bean_reg_block::type_id::create( "jb_reg_blocks[1]" ); jb_reg_blocks[1].configure( .parent( this ), .hdl_path( "partner" ) ); jb_reg_blocks[1].build(); reg_map.add_submap( .child_map( jb_reg_blocks[1].reg_map ), .offset( 2 ) ); endfunction: build endclass: jelly_bean_partnership_reg_block |
Setting HDL Paths
Now we are ready to instantiate the top-level register model. Firstly, we set the HDL path of the top-level register block to be "top.dut"
(line 18 of jelly_bean_base_test
below) assuming we have the following top-level test-bench .
module top; import uvm_pkg::*; reg clk; jelly_bean_if jb_if( clk ); jelly_bean_partnership dut( jb_if ); // DUT // ... omit ... endmodule: top |
Then, we set the HDL path slices to the partner’s recipe register (lines 22 to 24). Note that we cleared the HDL path of the jb_recipe_reg
on the line 21 before setting the slices. This is because the reused jelly_bean_recipe_reg
already has HDL path slices, which do not match the HDL paths of the partner (If you are interested, please see the lines 66 to 69 of the jelly_bean_recipe_reg
in Register Access through the Back Door.).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | class jelly_bean_base_test extends uvm_test; `uvm_component_utils( jelly_bean_base_test ) jelly_bean_env jb_env; jelly_bean_env_config jb_env_cfg; jelly_bean_agent_config jb_agent_cfg; jelly_bean_partnership_reg_block jb_partnership_reg_block; function new( string name, uvm_component parent ); super.new( name, parent ); endfunction: new function void build_phase( uvm_phase phase ); jelly_bean_recipe_reg jb_recipe_reg; super.build_phase( phase ); jb_partnership_reg_block = jelly_bean_partnership_reg_block::type_id::create( "jb_partnership_reg_block" ); jb_partnership_reg_block.configure( .hdl_path( "top.dut" ) ); jb_partnership_reg_block.build(); jb_recipe_reg = jb_partnership_reg_block.jb_reg_blocks[1].jb_recipe_reg; // shorthand jb_recipe_reg.clear_hdl_path(); jb_recipe_reg.add_hdl_path_slice( .name( "color_and_flavor" ), .offset( 0 ), .size( 5 ) ); jb_recipe_reg.add_hdl_path_slice( .name( "extra.sugar_free" ), .offset( 5 ), .size( 1 ) ); jb_recipe_reg.add_hdl_path_slice( .name( "extra.sour" ), .offset( 6 ), .size( 1 ) ); jb_partnership_reg_block.lock_model(); // finalize the address mapping // ... omit ... endclass: jelly_bean_base_test |
The following table summarizes the overall HDL paths we have defined for the partner’s recipe register.
Model | jb_partnership_reg_block |
jb_reg_block[1] |
jb_recipe_reg |
---|---|---|---|
Path | top.dut |
partner |
color_and_flavor |
Path | top.dut |
partner |
extra.sugar_free |
Path | top.dut |
partner |
extra.sour |
The partner’s taste register uses the same HDL path (taste
) we had already defined in the jelly_bean_taste_reg
.
Model | jb_partnership_reg_block |
jb_reg_block[1] |
jb_taste_reg |
---|---|---|---|
Path | top.dut |
partner |
taste |
FYI, the following tables summarize the overall HDL paths we have for the taster.
Model | jb_partnership_reg_block |
jb_reg_block[0] |
jb_recipe_reg |
---|---|---|---|
Path | top.dut |
taster |
flavor |
Path | top.dut |
taster |
color |
Path | top.dut |
taster |
sugar_free |
Path | top.dut |
taster |
sour |
Model | jb_partnership_reg_block |
jb_reg_block[0] |
jb_taste_reg |
---|---|---|---|
Path | top.dut |
taster |
taste |
Register Sequence
Let’s verify the HDL paths using the following sequence. We have three backdoor writes in the sequence (highlighted).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | class jelly_bean_reg_sequence extends uvm_reg_sequence; `uvm_object_utils( jelly_bean_reg_sequence ) function new( string name = "" ); super.new( name ); endfunction: new virtual task body(); jelly_bean_partnership_reg_block jb_partnership_reg_block; jelly_bean_reg_block partner_reg_block; flavor_e flavor; color_e color; bit sugar_free; bit sour; uvm_status_e status; uvm_reg_data_t value; $cast( jb_partnership_reg_block, model ); partner_reg_block = jb_partnership_reg_block.jb_reg_blocks[1]; // shorthand sugar_free = 0; sour = 1; // back-door writes flavor = BLUEBERRY; color = BLUE; poke_reg( partner_reg_block.jb_recipe_reg, status, { sour, sugar_free, color, flavor } ); // 'h5A #10ns ; flavor = BUBBLE_GUM; color = GREEN; write_reg( partner_reg_block.jb_recipe_reg, status, { sour, sugar_free, color, flavor }, UVM_BACKDOOR ); // 'h53 #10ns ; flavor = CHOCOLATE; color = RED; partner_reg_block.jb_recipe_reg.write( status, { sour, sugar_free, color, flavor }, UVM_BACKDOOR, .parent( this ) ); // 'h4C #10ns ; endtask: body endclass: jelly_bean_reg_sequence |
Simulation
When you run a simulation, you should see the result like this:
# KERNEL: UVM_INFO /home/build/vlib1/vlib/uvm-1.2/src/reg/uvm_reg.svh(2820) @ 0: reporter [RegModel] Poked register "jb_partnership_reg_block.jb_reg_blocks[1].jb_recipe_reg": 'h000000000000005a# KERNEL: UVM_INFO @ 10: reporter [RegModel] Wrote register via DPI backdoor: jb_partnership_reg_block.jb_reg_blocks[1].jb_recipe_reg=0x53# KERNEL: UVM_INFO @ 20: reporter [RegModel] Wrote register via DPI backdoor: jb_partnership_reg_block.jb_reg_blocks[1].jb_recipe_reg=0x4c |
I hope this article helped you to clarify the HDL path.
You can view and run the code on EDA Playground.
Hello Keisuke,
All your tutorials are very helpful.
In the file “jelly_bean_reg_sequence”, I am getting error in the line number 11 and 12. And the error is:
# ** Error: jelly_bean_reg_sequence.sv(11): near “;”: syntax error, unexpected ‘;’, expecting ‘(‘
# ** Error: jelly_bean_reg_sequence.sv(12): near “;”: syntax error, unexpected ‘;’, expecting ‘(‘
Please help me to rectify this error. I am using the Questsim.
Thanks
Sunil
Did you
import jelly_bean_pkg::*;
?