When does the reg2bus and bus2reg are called in UVM register test?

When does the reg2bus and bus2reg are called? Is it when the component passes the transaction to the analysis port? Or is it when the component passes the transaction to the response in the driver?

What’s happening to my testbench is that reg2bus is called once but bus2reg is called “twice”. I don’t know why is it called twice. It is happening when reading to a register.

Hello,

If ‘provide_responses’ is 1, bus2reg would be called after getting response else bus2reg would be called as soon as finish_item is done.

See below snippet from UVM src code.


      if (adapter.provides_responses) begin
        uvm_sequence_item bus_rsp;
        uvm_access_e op;
        // TODO: need to test for right trans type, if not put back in q
        rw.parent.get_base_response(bus_rsp);
        adapter.bus2reg(bus_rsp,rw_access);
      end
      else begin
        adapter.bus2reg(bus_req,rw_access);
      end

Regards,
Vinay Jain

In reply to Vinay Jain:

Hi Vinay,

Thanks for the reply.
Actually, I set provide_responses = 0 in the constructor of the adapter.
I’m also wondering why bus2reg is called twice.

I think the bus2reg is called twice because of uvm_reg_predictor.svh and uvm_reg_map.svh.
I saw it from this link:
https://verificationacademy.com/forums/uvm/uvmregadapter-bus2reg-called-twice-predictor

However, I still don’t understand why it is happening. The second bus2reg is causing an error to me.

In reply to Reuben:

uvm_reg_map called to provide response.
uvm_reg_predictor called to collect bus operation infomation.

In reply to lcf0451:

Hi lcf0451,

Does it mean that the bus transactions has been collected by my predictor but the transaction was not properly stored in the register model thus the uvm_reg_map is giving an invalid response?

In reply to Reuben:

This is what’s happening…

UVM_INFO [uvm_reg_bit_bash_seq] Verifying bits in register reg_model.memmap0.MODE_SET1 in map “reg_model.memmap0.default_map”…
UVM_INFO [uvm_reg_bit_bash_seq] …Bashing RW bit#0
UVM_INFO [uvm_reg_map] Writing 'h1 at 'h0 via map “reg_model.memmap0.default_map”…
UVM_INFO [spi_reg_adapter] reg2bus:
direction = 'h0 // WRITE
addr = 8’h0
data = 8’h1
read_data = 16’h0xxxx // This is for read

UVM_INFO [spi_reg_adapter] bus2reg:
direction = 'h0 // WRITE
addr = 8’h0
data = 8’h1
read_data = 16’hE00 // This is for read

UVM_INFO [REG_PREDICT] Observed WRITE transaction to register reg_model.memmap0.MODE_SET1: value='h1 : updated value = 'h1

UVM_INFO [spi_reg_adapter] bus2reg:
direction = 'h0 // WRITE
addr = 8’h0
data = 8’h1
read_data = 16’h0xxxx

UVM_INFO [uvm_reg_map] Wrote 'h1 at 'h0 via map “reg_model.memmap0.default_map”: UVM_IS_OK…
UVM_INFO [RegModel] Wrote register via map reg_model.memmap0.default_map: reg_model.memmap0.MODE_SET1=0x1
UVM_INFO [uvm_reg_map] Reading address 'h0 via map “reg_model.memmap0.default_map”…

UVM_INFO [spi_reg_adapter] reg2bus:
direction = 'h1 // READ
addr = 8’h0
data = 8’h0
read_data = 16’h0xxxx

UVM_INFO [spi_reg_adapter] bus2reg:
direction = 'h1 // READ
addr = 8’h0
data = 8’h0
read_data = 16’h1

UVM_INFO [REG_PREDICT] Observed READ transaction to register reg_model.memmap0.MODE_SET1: value='h1

Then another bus2reg is called here. This is where the read transaction suddenly changes its value.

UVM_INFO [spi_reg_adapter] bus2reg:
direction = 'h1 // READ
addr = 8’h0
data = 8’h0
read_data = 16’h0xxxx // This value has changed from 16’h1 for an unknown reason

UVM_INFO [uvm_reg_map] Read 'h0 at 'h0 via map “reg_model.memmap0.default_map”: UVM_IS_OK…
UVM_INFO [RegModel] Read register via map reg_model.memmap0.MODE_SET1=0
UVM_ERROR [uvm_reg_bit_bash_seq] Writing a 1 in bit #0 of register “reg_model.memmap0.MODE_SET1” with initial value 'h0000 yielded 'h0000 instead of 'h0001

I also checked the waveform and I saw that there’s no problem with the value of register MODE_SET1.

In reply to Reuben:

Hi,
As you described, the operation is ok.
In my opinion, you could track the sequence item called by uvm_reg_map,
and find when this read data is sampled and why wrong data are get.

In reply to lcf0451:

Hi, I think I solved the issue.
Before, I have both req and rsp in my driver, and the rsp is being changed while req is not.
So what I did is I removed the rsp and I only used the variable req.
Now I am not seeing this issue.

In reply to Reuben:

Hi Reuben,

Can you please elaborate the solution of the issue discussed here as you have mentioned that you have solved it.

I am facing the similar issue, when WRITEs and READs are being done on the registers…the BUIS2REG is getting called twice.
When I capture the result of READ in a local variable and displaying it…it is showing the wrong value(my local variable is getting updated for the first BUS2REG) and when the BUS2REG is getting called for the second time… with the help of the print statement which I have in the BUS2REG method it is showing the value which I am expecting but now my local variable is not getting updated because it has already been updated with a value when BUS2REG was called for the first time.
Can you please provide some insight to this issue.
Thanks in advance.

Best Regards,
Neith

In reply to UVM Beginner:

Just a guess.
From http://www.studio-muzzi.com/project/docs/UVMdocs_smu/uvm-1.1d/uvm__reg__map_8svh_source.html

 foreach(addrs[i]) begin: foreach_addr

         uvm_sequence_item bus_req;
         uvm_reg_bus_op rw_access;
         uvm_reg_data_t data;


         data = (value >> (curr_byte*8)) & ((1'b1 << (bus_width * 8))-1);
         
         `uvm_info(get_type_name(),
                   $sformatf("Writing 'h%0h at 'h%0h via map \"%s\"...",
                             data, addrs[i], rw.map.get_full_name()), UVM_FULL);

         if (rw.element_kind == UVM_FIELD) begin
            for (int z=0;z<bus_width;z++)
              rw_access.byte_en[z] = byte_en[curr_byte+z];
         end
         
         rw_access.kind    = rw.kind;
         rw_access.addr    = addrs[i];
         rw_access.data    = data;
         rw_access.n_bits  = (n_bits > bus_width*8) ? bus_width*8 : n_bits;
         rw_access.byte_en = byte_en;

         adapter.m_set_item(rw);
         bus_req = adapter.reg2bus(rw_access);
         adapter.m_set_item(null);
         
         if (bus_req == null)
           `uvm_fatal("RegMem",{"adapter [",adapter.get_name(),"] didnt return a bus transaction"});
         
         bus_req.set_sequencer(sequencer);
         rw.parent.start_item(bus_req,rw.prior);

         if (rw.parent != null && rw_access.addr == addrs[0])
           rw.parent.mid_do(rw);

         rw.parent.finish_item(bus_req);
         bus_req.end_event.wait_on();

         if (adapter.provides_responses) begin
            uvm_sequence_item bus_rsp;
            uvm_access_e op;
            // TODO: need to test for right trans type, if not put back in q
            rw.parent.get_base_response(bus_rsp);
            adapter.bus2reg(bus_rsp,rw_access);
         end
         else begin
            adapter.bus2reg(bus_req,rw_access);
         end

         if (rw.parent != null && rw_access.addr == addrs[addrs.size()-1])
           rw.parent.post_do(rw);

         rw.status = rw_access.status;

         `uvm_info(get_type_name(),
                   $sformatf("Wrote 'h%0h at 'h%0h via map \"%s\": %s...",
                             data, addrs[i], rw.map.get_full_name(), rw.status.name()), UVM_FULL)

         if (rw.status == UVM_NOT_OK)
           break;

         curr_byte += bus_width;
         n_bits -= bus_width * 8;

      end: foreach_addr

The reason to repeat the operation two times is that addr is an array that activate the loop.The reason to have addr as an array is that you have a register_bit_width greater than your bus_bit_width. The RAL API generates automatically for you 2 or more accesses one for the first part of your register (of bus_width size) and another for the second part of the value (which can be n_bits<=bus_bitwidth).
See how your data is updated inside the loop.

data = (value >> (curr_byte*8)) & ((1'b1 << (bus_width * 8))-1);

The reg2bus/bus2reg are called so many times depending on 2 things (there are, in fact, 2 for loops. One for value and one for addr variable):
1)[DISABLED for some API calls] the number of values you put in the vector of the write_reg API function for the specific register. Yes value can be an array!. The reason why you may put many values is to write/read consecutively different values to the same register, this is not to create a Burst to write many register. Don’t get confused. However, the UVM API disables that features putting only the first value in the register map. I don’t know why. see code

 2108 
 2109 task uvm_reg::write(output uvm_status_e      status,
 2110                     input  uvm_reg_data_t    value,
 2111                     input  uvm_path_e        path = UVM_DEFAULT_PATH,
 2112                     input  uvm_reg_map       map = null,
 2113                     input  uvm_sequence_base parent = null,
 2114                     input  int               prior = -1,
 2115                     input  uvm_object        extension = null,
 2116                     input  string            fname = "",
 2117                     input  int               lineno = 0);
 2118 
 2119    // create an abstract transaction for this operation
 2120    uvm_reg_item rw;
 2121 
 2122    XatomicX(1);
 2123 
 2124    set(value);
 2125 
 2126    rw = uvm_reg_item::type_id::create("write_item",,get_full_name());
 2127    rw.element      = this;
 2128    rw.element_kind = UVM_REG;
 2129    rw.kind         = UVM_WRITE;
 2130    rw.value[0]     = value;
 2131    rw.path         = path;
 2132    rw.map          = map;
 2133    rw.parent       = parent;
 2134    rw.prior        = prior;
 2135    rw.extension    = extension;
 2136    rw.fname        = fname;
 2137    rw.lineno       = lineno;
 2138 
 2139    do_write(rw);
 2140 
 2141    status = rw.status;
 2142 
 2143    XatomicX(0);
 2144 
 2145 endtask
  1. the number of extra_address. The number of extra_address is calculated AUTOMATICALLY. A new extra_address will be created if the register bitwidth is bigger than the bus_width. The adapter will only see a new access to a new address in order to complete the register.
    If the bitwidth is smaller than the bus_width then the byte_enable variable inside the uvm_reg_bus_op type will be automatically updated. The byte_en variable has so many bits as bytes inside of the bus_width.

A nice view of the API flow : UVM Tutorial for Candy Lovers – 17. Register Read Demystified – ClueLogic

Could it be that the reason? and please correct me if i misunderstood that behavior.