UVM Tutorial for Candy Lovers – 24. Register Access through the Back Door

Last Updated: February 14, 2015 (fixed broken EDA Playground link)

This post will add back-door access to the registers defined in Register Abstraction. With a few additional lines of code, you can access the registers through the back door.

DUT

We use the same DUT (jelly_bean_taster) as defined in Register Abstraction. The DUT has two registers as shown below.

DUT Registers
DUT Registers
The DUT defines each field of the registers as reg (lines 4 to 8).

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
module jelly_bean_taster( jelly_bean_if.slave_mp jb_if );
  import jelly_bean_pkg::*;
 
  reg [1:0] taste;  // TASTE  register  reg [2:0] flavor; // RECIPE register  reg [1:0] color;  reg       sugar_free;  reg       sour; 
  reg [1:0] command;
 
  initial begin
    flavor     = 0;
    color      = 0;
    sugar_free = 0;
    sour       = 0;
    command    = 0;
    taste      = 0;
  end
 
  always @ ( posedge jb_if.clk ) begin
    if ( jb_if.command == JB_WRITE ) begin
      flavor     < = jb_if.flavor;
      color      <= jb_if.color;
      sugar_free <= jb_if.sugar_free;
      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_taster

Testbench

The top-level testbench instantiates the jelly_bean_taster as the dut (line 6).

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
module top;
  import uvm_pkg::*;
 
  reg clk;
  jelly_bean_if     jb_if( clk );
  jelly_bean_taster dut( jb_if ); // DUT 
  initial begin // clock
    clk = 1;
    forever #5ns clk = ! clk;
  end
 
  initial begin // waveform
    $dumpfile( "dump.vcd" );
    $dumpvars( 0, top );
  end
 
  initial begin
    uvm_config_db#( virtual jelly_bean_if )::set( .cntxt( null ),
                                                  .inst_name( "uvm_test_top*" ),
                                                  .field_name( "jb_if" ),
                                                  .value( jb_if ) );
    run_test();
  end
endmodule: top

Register Block

To access the DUT registers through the back door, we need to inform the register block about its corresponding HDL path (line 27). In our case, the hierarchical HDL path corresponding to the register block is "top.dut".

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
class jelly_bean_reg_block extends uvm_reg_block;
  `uvm_object_utils( jelly_bean_reg_block )
 
  rand jelly_bean_recipe_reg jb_recipe_reg;
  rand jelly_bean_taste_reg  jb_taste_reg;
  uvm_reg_map                reg_map;
 
  function new( string name = "jelly_bean_reg_block" );
    super.new( .name( name ), .has_coverage( UVM_NO_COVERAGE ) );
  endfunction: new
 
  virtual function void build();
    jb_recipe_reg = jelly_bean_recipe_reg::type_id::create( "jb_recipe_reg" );
    jb_recipe_reg.configure( .blk_parent( this ) );
    jb_recipe_reg.build();
 
    jb_taste_reg = jelly_bean_taste_reg::type_id::create( "jb_taste_reg" );
    jb_taste_reg.configure( .blk_parent( this ) );
    jb_taste_reg.build();
 
    reg_map = create_map( .name( "reg_map" ), .base_addr( 8'h00 ), 
                          .n_bytes( 1 ), .endian( UVM_LITTLE_ENDIAN ) );
    reg_map.add_reg( .rg( jb_recipe_reg ), .offset( 8'h00 ), .rights( "WO" ) );
    reg_map.add_reg( .rg( jb_taste_reg  ), .offset( 8'h01 ), .rights( "RO" ) );
 
    // for back-door access
    add_hdl_path( .path( "top.dut" ) ); 
    lock_model(); // finalize the address mapping
  endfunction: build
endclass: jelly_bean_reg_block

Registers

We also need to inform each register abstraction class about the HDL path to the register field (line 31). In our case, the taste register field corresponds to the taste reg in the DUT.

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
class jelly_bean_taste_reg extends uvm_reg;
  `uvm_object_utils( jelly_bean_taste_reg )
 
  rand uvm_reg_field taste;
 
  //----------------------------------------------------------------------------
  // Function: new
  //----------------------------------------------------------------------------
 
  function new( string name = "jelly_bean_taste_reg" );
     super.new( .name( name ), .n_bits( 2 ), .has_coverage( UVM_NO_COVERAGE ) );
  endfunction: new
 
  //----------------------------------------------------------------------------
  // Function: build
  //----------------------------------------------------------------------------
 
  virtual function void build();
    taste = uvm_reg_field::type_id::create( "taste" );
    taste.configure( .parent                 ( this ), 
                     .size                   ( 2    ), 
                     .lsb_pos                ( 0    ), 
                     .access                 ( "RO" ), 
                     .volatile               ( 1    ),
                     .reset                  ( 0    ), 
                     .has_reset              ( 1    ), 
                     .is_rand                ( 0    ), 
                     .individually_accessible( 0    ) );
 
    // for back-door access
    add_hdl_path_slice( .name( "taste" ), .offset( 0 ), .size( 2 ) );  endfunction: build
endclass: jelly_bean_taste_reg

We set the HDL paths to the RECIPE register, too (lines 66 to 69). In this case, we add four HDL paths (one path per DUT reg).

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
class jelly_bean_recipe_reg extends uvm_reg;
  `uvm_object_utils( jelly_bean_recipe_reg )
 
  rand uvm_reg_field flavor;
  rand uvm_reg_field color;
  rand uvm_reg_field sugar_free;
  rand uvm_reg_field sour;
 
  constraint flavor_color_con {
    flavor.value != NO_FLAVOR;
    flavor.value == APPLE     -> color.value != BLUE;
    flavor.value == BLUEBERRY -> color.value == BLUE;
    flavor.value < = CHOCOLATE;
  }
 
  function new( string name = "jelly_bean_recipe_reg" );
    super.new( .name( name ), .n_bits( 7 ), .has_coverage( UVM_NO_COVERAGE ) );
  endfunction: new
 
  virtual function void build();
    flavor = uvm_reg_field::type_id::create( "flavor" );
    flavor.configure( .parent                 ( this ), 
                      .size                   ( 3    ), 
                      .lsb_pos                ( 0    ), 
                      .access                 ( "WO" ), 
                      .volatile               ( 0    ),
                      .reset                  ( 0    ), 
                      .has_reset              ( 1    ), 
                      .is_rand                ( 1    ), 
                      .individually_accessible( 0    ) );
 
    color = uvm_reg_field::type_id::create( "color" );
    color.configure( .parent                 ( this ), 
                     .size                   ( 2    ), 
                     .lsb_pos                ( 3    ), 
                     .access                 ( "WO" ), 
                     .volatile               ( 0    ),
                     .reset                  ( 0    ), 
                     .has_reset              ( 1    ), 
                     .is_rand                ( 1    ), 
                     .individually_accessible( 0    ) );
 
    sugar_free = uvm_reg_field::type_id::create( "sugar_free" );
    sugar_free.configure( .parent                 ( this ), 
                          .size                   ( 1    ), 
                          .lsb_pos                ( 5    ), 
                          .access                 ( "WO" ), 
                          .volatile               ( 0    ),
                          .reset                  ( 0    ), 
                          .has_reset              ( 1    ), 
                          .is_rand                ( 1    ), 
                          .individually_accessible( 0    ) );
 
    sour = uvm_reg_field::type_id::create( "sour" );
    sour.configure( .parent                 ( this ), 
                    .size                   ( 1    ), 
                    .lsb_pos                ( 6    ), 
                    .access                 ( "WO" ), 
                    .volatile               ( 0    ),
                    .reset                  ( 0    ), 
                    .has_reset              ( 1    ), 
                    .is_rand                ( 1    ), 
                    .individually_accessible( 0    ) );
 
    // for back-door access
    add_hdl_path_slice( .name( "flavor"     ), .offset( 0 ), .size( 3 ) );    add_hdl_path_slice( .name( "color"      ), .offset( 3 ), .size( 2 ) );    add_hdl_path_slice( .name( "sugar_free" ), .offset( 5 ), .size( 1 ) );    add_hdl_path_slice( .name( "sour"       ), .offset( 6 ), .size( 1 ) );  endfunction: build
endclass: jelly_bean_recipe_reg

That’s about all you need. Let’s test the back door.

Register Sequence

This sequence demonstrates several ways to access the registers through the back door. As a refresher, we access the registers through the front door first.

  1. The line 24 uses the write_reg task of the uvm_reg_sequence class to write to the RECIPE register.
  2. The line 27 uses the read_reg task of the uvm_reg_sequence class to read from the TASTE register.

Then, we write the RECIPE register through the back door in three different ways.

  1. The line 32 uses the poke_reg task of the uvm_reg_sequence class.
  2. The line 36 uses the write_reg task of the uvm_reg_sequence class with the UVM_BACKDOOR option.
  3. The line 41 uses the write task of the uvm_reg class with the UVM_BACKDOOR option.

Similarly, we read the TASTE register through the back door in three different ways.

  1. The line 46 uses the peek_reg task of the uvm_reg_sequence class.
  2. The line 49 uses the read_reg task of the uvm_reg_sequence class with the UVM_BACKDOOR option.
  3. The line 52 uses the read task of the uvm_reg class with the UVM_BACKDOOR option.
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
45
46
47
48
49
50
51
52
53
54
55
56
57
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_reg_block jb_reg_block;
    flavor_e             flavor;
    color_e              color;
    bit                  sugar_free;
    bit                  sour;
    uvm_status_e         status;
    uvm_reg_data_t       value;
 
    $cast( jb_reg_block, model );
    flavor     = APPLE;
    color      = GREEN;
    sugar_free = 0;
    sour       = 1;
 
    // front-door write
    write_reg( jb_reg_block.jb_recipe_reg, status, { sour, sugar_free, color, flavor } );  
    // front-door read
    read_reg( jb_reg_block.jb_taste_reg, status, value );    #20ns ;
 
    // back-door writes
    flavor = BLUEBERRY;
    poke_reg( jb_reg_block.jb_recipe_reg, status, { sour, sugar_free, color, flavor } );     #10ns ;
 
    flavor = BUBBLE_GUM;
    write_reg( jb_reg_block.jb_recipe_reg, status, { sour, sugar_free, color, flavor },               UVM_BACKDOOR );     #10ns ;
 
    flavor = CHOCOLATE;
    jb_reg_block.jb_recipe_reg.write( status, { sour, sugar_free, color, flavor },                                      UVM_BACKDOOR, .parent( this ) );    #10ns ;
 
    // back-door reads
    peek_reg( jb_reg_block.jb_taste_reg, status, value );    assert( value == YUMMY );
 
    read_reg( jb_reg_block.jb_taste_reg, status, value, UVM_BACKDOOR );    assert( value == YUMMY );
 
    jb_reg_block.jb_taste_reg.read( status, value, UVM_BACKDOOR, .parent( this ) );    assert( value == YUMMY );
    #10ns ;
  endtask: body
 
endclass: jelly_bean_reg_sequence

Simulation

Here is an annotated waveform. The front-door access uses the jb_if, whereas the back-door access directly updates the register value of the DUT. Note that back-door writing CHOCOLATE to the flavor field does not update the taste field of the DUT even though the DUT is supposed to respond YUCKY to the combination of sour and CHOCOLATE. This is because the DUT updates the taste field in response to the value on the jb_if, but not to the internal RECIPE register values.

Annotated Waveform
Annotated Waveform

EDA Playground

You can view and run the code on EDA Playground.

44 thoughts on “UVM Tutorial for Candy Lovers – 24. Register Access through the Back Door”

  1. Hi

    Thanks for your article on the back door. I am curious to know what is the use case of back door register access. Actually i am new to uvm and ramping on uvm RAL. If there is a status register in dut whose value change due to some input, I can equally change the status register vlaue in register model by accessing the register from the model in tb using get_reg_by_name for a particular register.
    So I am bit confused as to how and why to use the back door.

    Question2: If via a interface I change the register value then in the model which value get updated desired or mirror value or both? My requirement is to write into register and read back and compare the read value to reference value which was written earlier.

    1. Question3 : I have a generic question on the write functions to write. Is it always I need to use this function to write into register in dut and update the data in register model. I mean I have a adapter and I send a I2C write into a register via driver. So will the equvivalent register not get update in the register model? if reg data is updated Will the update be for desired and mirror value in model. Just curious to know if I always need write read and update functions to update data in model.

      Avinash

        • If you connect a uvm_reg_predictor to your I2C monitor, the desired and mirrored values of the model are updated at every I2C read/write regardless of accessing the register by RAL functions or not, because the monitor captures all I2C transactions.
        • If you use your_reg_map.set_auto_predict( .on( 1 ) ), the values of the model will be updated only when you use RAL read/write.
        1. Hi

          Thanks for your inputs.

          I have a particular register write read scenario :

          When I send 2 commands then a register is addressed and next 8 bits data is written into this register in DUT. Now how should I write the regsiter definition for this register in RAL?
          Usually I used to have one command and data. The command is the address of register and data is stored of this register.
          I am not able to get how to implement RAL register defn. for this kind of register.
          I mean address definition of this register in RAL.

          Please help.

          Avinash

          1. I think you can define the registers in RAL as if you directly access them. Then, one solution would be to implement a register adapter that converts a register read/write into two bus transactions (one for a command and the other for data), and vice versa. Let me put this into my To Do list of future articles.

      1. You can use the back-door to peek the value of registers in a DUT for the purpose of debugging or controlling a test-bench based on the peeked value. You could also use the back-door to initialize a large set of registers in a DUT, if doing so through the front-door takes too long.
      2. If you write a register through the front-door, both desired and mirrored values are updated. Please see Register Access Methods for more detail.
      1. Clarification : So you can only peek(quickly see) the data from the DUT register via back door and you cannot modify the data in that register via back door.
        Am I right ?

        Avinash

  2. Hi Shimizu,

    Thank you for writing such a great article about backdoor access. I’m new to UVM and just started to implement backdoor access on both register block level and register level.

    I have a question about if it possible for me to implement backdoor write on each bit of a register. I want to implement a bit bash test on several registers in UVM using backdoor access instead of using .start() to use apb bus and master sequencer. Is it possible? I didn’t find out any way to access each bits on registers right now.

    Thank you.

    Regards,
    Euphemia

  3. Hi.
    I need to use the registers file in 2 contexts:
    1. In the block level simulation.
    2. In the fullchip simulation.

    The path of the registers block is different in each context.

    How do you advise to set the hdl path?
    Can the add_hdl_path() method get a variable argument?
    Should I use `ifdef to distinguish between the 2 contexts?

    Thanks.
    Yoram

    1. I think the easiest way would be using the set_hdl_path_root function of the uvm_reg_block to specify the absolute HDL path to the registers. For example, you can set the block-level path as jb_reg_block.set_hdl_path_root( "dut" ), whereas you can set the chip-level path as something like jb_reg_block.set_hdl_path_root( "fullchip.dut" ).

  4. Hello Keisuke Shimizu,

    I am getting an error while accessing dutregister via backdoor as :-

    UVM_ERROR: get: unable to locate hdl path dut.flavor
    # Either the name is incorrect, or you may not have PLI/ACC visibility to that name

    I have even used the set_backdoor method within the register model but If I use it I am getting the error
    UVM_FATAL verilog_src/uvm-1.1d/src/reg/uvm_reg_backdoor.svh(329) @ 0: reporter [RegModel] uvm_reg_backdoor::write() method has not been overloaded

    whenever I am using any access method from the sequence.

    What can be the probable issue?

    Thanks in advance.

    Regards
    shreemant

  5. Hello,

    I got the issue resolved, Actually you have instantiated the DUT as “dut” in module top, however when you are setting the path in add_hdl_path method its just written as “dut”, this gives the error

    UVM_ERROR: get: unable to locate hdl path dut.flavor
    # Either the name is incorrect, or you may not have PLI/ACC visibility to that name

    Actually it should be “top.dut” .

    Please correct me if I am wrong.

    Thanks & Regards
    Shreemant

  6. Hi Keisuke San,

    I have a question on how to integrate the mulitple env together. For example, I have a spi env, and a gpio env. Each of them has there regmodel and adapter. When I have created a top_reg_model to include spi_regmodel and gpio_regmodel, and I used map.add_submap to properly pass the offset to the spi_regmodel.map, and gpio_regmodel. If I already have a spi_reg_test_seq which call reg_write(spi_regmodel.spi0, …), is there a way to reuse the test for my top_reg_model? Or do I need to rewrite to
    reg_write(top_reg_model.spi_regmodel.spi0, ….)?

    Many thanks.

    Loren

    1. You don’t need to modify the sequences at all. I assume your spi_reg_test_seq is a subclass of the uvm_reg_sequence. In your SPI test, you probably did something like:

      spi_reg_test_seq.model = spi_regmodel;

      If you modify this to something like:

      spi_reg_test_seq.model = top_reg_model.spi_regmodel;

      you should be OK.

  7. Hello,
    Thank you for this very interesting tutorial.
    I am experimenting backdoor write access in my reg_model. It works fine for all registers that have a 0 reset value, but not for registers that have a non-zero value (reset field set to e.g. ‘h86, has_reset field set to 1). For these registers, the backdoor read access works fine, but the backdoor write access leads to a wrong value. It seems the force applied on the backdoor is incorrect.
    Are you aware of known limitations with non-zero reset ? Am I missing some configuration somewhere ?
    Any help is appreciated. Thank you.
    Jean-Luc

    1. Having non-zero reset value should not affect the behavior of the back-door write. I changed my candy example to have a non-zero reset value, but both back-door read and write seemed to be fine. How did you know the back-door write did not work? By looking at the waveform? If you can post the read/write procedure you used, I might be able to figure out.

      1. Well. I have investigated this a bit further and it appeared that everything was correct until the call to uvm_hdl_deposit. And in fact, the problem is related to the simulation tool I am using (QuestaSim) and from the fact that the DUT is written in VHDL using std_ulogic_vector type. Changing to std_logic_vector solved the bug, but that was not acceptable for us. Changing the default radix for waveforms from hexadecimal to binary (sic!) magically solved the backdoor problem (I would not have imagined this without the help of Mentor support…). In the end, registers with a null reset value were passing my tests even with a wrong backdoor access. I would have found this only much later if all registers were reset to zero. That’s why annoys me most.
        The positive side is that I had to dig a little bit in the UVM code. Sometimes it is as valuable as text books ! 🙂

  8. hi ,
    thank you for this valuable tutorial……..i am getting error to run this code…what should i do?……….

    ERROR: VPI VISNOW
    Attempting to place a value into top.dut.flavor which does not have write access.
    ./dut.sv, 9:
    ERROR: VPI VISNOW
    Attempting to place a value into top.dut.color which does not have write access.
    ./dut.sv, 10:
    ERROR: VPI VISNOW
    Attempting to place a value into top.dut.sugar_free which does not have write access.
    ./dut.sv, 11:
    ERROR: VPI VISNOW
    Attempting to place a value into top.dut.sour which does not have write access.

    ———————————————————–in reg definition file……………………………
    virtual function void build();
    flavor = uvm_reg_field::type_id::create( “flavor” );
    flavor.configure( .parent ( this ),
    .size ( 3 ),
    .lsb_pos ( 0 ),
    .access ( “WO” ), //this is write accessible
    .volatile ( 0 ),
    .reset ( 0 ),
    .has_reset ( 1 ),
    .is_rand ( 1 ),
    .individually_accessible( 1 ) );

    color = uvm_reg_field::type_id::create( “color” );
    color.configure( .parent ( this ),
    .size ( 2 ),
    .lsb_pos ( 3 ),
    .access ( “WO” ), //this is write accessible
    .volatile ( 0 ),
    .reset ( 0 ),
    .has_reset ( 1 ),
    .is_rand ( 1 ),
    .individually_accessible( 1 ) );
    ——————————————————————————————————————–

  9. Hi,
    thanks for your reply…….it works …………please elaborate more operation with example like mirror(),update() etc

    thanks again for this most useful tutorial

      1. Hi,
        i got little bit idea from “Register Access Methods” .But i want some sort of coding example as you describe for backdoor operation.

        thanks

        1. This is one way of writing to a register in the DUT.

          jb_reg_block.jb_recipe_reg.write( status, { sour, sugar_free, color, flavor } );

          You can do the same thing with the update task.

          jb_reg_block.jb_recipe_reg.set( { sour, sugar_free, color, flavor } );
          jb_reg_block.jb_recipe_reg.update( status );

          One difference is that if the mirrored value of the register model is equal to the value specified by the set function, the update task won’t write to the register in the DUT (because RAL assumes the DUT already has that value). On the other hand, the write task always writes to the DUT regardless of the specified value.

          Similarly, this is one way of reading from a register in the DUT.

          jb_reg_block.jb_taste_reg.read( status, value );

          You can do the same thing with the mirror task.

          jb_reg_block.jb_taste_reg.mirror( status );
          value = jb_reg_block.jb_taste_reg.get();

          Both the read and mirror tasks always read from the DUT. You can check the read value against the current mirrored value if check is UVM_CHECK. Default is UVM_NO_CHECK.

          jb_reg_block.jb_taste_reg.mirror( status, .check( UVM_CHECK ) ); // check read value
  10. Hi Keisuke,

    Thanks for to the point explanation. Rally such a nice articles this one and Register Access Methods. Actually, I am new to the RAL and went through UVM user guide, Reference manual and src/reg/* files but finally I satisfied with these articles presented over here on RAL.

    Thanks once again. And keep writing

  11. Hi Keisuke,
    I need your help in implementing I2C protocol based Register write and read functions using UVM. I think bus2reg and reg2bus functions should be changed. Apart from these changes what else should be implemented. Please me out, how to proceed?

    Regards,
    Thiru

    1. If you already have the transaction, driver, sequencer, and monitor for the I2C, you are pretty much ready to go once you implement the reg adapter. Let me know if you have further questions.

  12. Hi Keisuke,

    I am learning UVM RAL and found your tutorials are giving me a great help to understand quickly. On the backdoor access I have a doubt,

    Suppose My testbench components are packed in test_pkg and this package is imported inside TOP module where DUT and Interfaces are instantiated. Our UVM_RAL is also inside in test_pkg. Now to give backdoor access to UVM_RAL, we’ve to provide direct RTL submodule path from TOP, but as per my knowledge we can’t access the RTL hierarchy from package. So in that case how can we use RAL?


    Harshit

  13. while implementing reg model i got several run time errors what could be the reason ??

    Error:
    UVM_INFO @ 0: reporter [RNTST] Running test hpdmc_base_test…
    # include_coverage not located
    # did you mean cvif?
    # did you mean dvif?
    # include_coverage not located
    # did you mean cvif?
    # did you mean dvif?
    # UVM_ERROR C:/questasim_10.0b/uvm-1.0p1/uvm_pkg/reg/uvm_reg.svh(1239) @ 0: reporter [RegModel] Field cke_control overlaps field reset in register “sys_r”

    Code:

    class sys_reg extends uvm_reg;
    	`uvm_object_utils(sys_reg)
    //	uvm_reg_field bypass_en; //bypass mode enable
    	uvm_reg_field reset; // reset mem
    	uvm_reg_field cke_control; //cke control, sdram
    
    
          function new(string name = "sys_reg");
            super.new(name,3,build_coverage(UVM_NO_COVERAGE));  
          endfunction
    
          virtual function void build();
           //  bypass_en = uvm_reg_field::type_id::create("bypass_en");
             this.reset = uvm_reg_field::type_id::create("reset");
             reset.configure(this, 1, 1, "RW", 1, 1'h0, 1, 1, 0);
             this.cke_control = uvm_reg_field::type_id::create("cke_control");
       
    	// bypass_en.configure(this,0,0,"RW",1,1'h0,1,1,0);	
           
    	 cke_control.configure(this,2,0, "RW", 1, 2'h0, 1, 1, 0);
    	endfunction
    endclass
    

    Remaining things done at nxt class which is not included in this code

    1. The configure function takes parent, size, lsb_pos, etc. as the arguments in this order. Your code configures the reset to be at the bit 1 of sys_reg, and the cke_control to be at bit 1 and 0. The overlapped bit 1 caused the UVM_ERROR.

  14. Hi Keishuke-san,

    I have question/comment on the hdl_path_slice specification that associates a register field with a DUT reg.
    It seems to me it would make more sense for it to be done at the instantiation of the register in reg_block and not in the definition of the register.
    I have a situation where the same register layout to be used multiple times in the register map.
    I will have one register definition and instantiate it as many times as I need within a loop in the reg_block.
    I do not have a one to one association between the register field definition and the DUT reg.

    Am I seeing this correctly? If so, is there a way to get around this?

    Thanks,
    -dam

    1. You don’t have to call the add_hdl_path_slice from within the register model. In my new article, Backdoor HDL Path, I moved up the add_hdl_path_slice to the test level. As long as you have a physical register that corresponds to the model, you should be able to specify the HDL path.

    1. Suppose you have a register block (blk_a) that has two sub-register blocks (blk_b and blk_c). Like the add_reg() adds a register to a register map, the add_submap() adds a register map to its parent register map (see the figure below).
      add_submap
      The default_map is used if no register map is specified for a register operation such as read() and write(). If you do not assign the default_map, the first register map created for a register block is assigned to the default_map.

      1. Hi Shimizu,
        Thanks for your explanation.
        I have one more doubt regarding backdoor access
        I have one IP where the registers are not in one file and they are scattered
        All these registers are brought into some module using its “input” wires
        If both the register fields and the register available in the same module (or file.v) i can specify the path
        If the register fields are coming from different modules, then how shall i specify the hierarchical path

        Please suggest in this case

        Thanks
        Sasi

        1. My new article, Backdoor HDL Path, might help. Basically, you can specify the source of the register fields like:

          your_reg.add_hdl_path_slice( "module_1.reg_1", ... );
          your_reg.add_hdl_path_slice( "module_2.reg_2", ... );

Leave a Reply