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
- 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.