Jump to content


  • Content Count

  • Joined

  • Last visited

  1. In the UVM register model, if you create a register or a field which is wider than the bus width there is no way to control what order the multiple bus operations occur to update the register/field value. In my case I was using BIG_ENDIAN addressing and the register model would always write the largest address first. My design spec required that the largest address be written last. I searched in vain for a way to change this but ended up overriding the 'do_bus_write' function in 'uvm_reg_map'. If you've run into a similar issue, here's my workaround. reversed_reg_order_map.sv `ifndef __REVERSED_REG_ORDER_MAP_SV__ `define __REVERSED_REG_ORDER_MAP_SV__ class reversed_reg_order_map extends uvm_reg_map; `uvm_object_utils(reversed_reg_order_map) function new(string name="reversed_reg_order_map"); super.new(name); endfunction extern virtual task do_write_bus_ops(uvm_reg_bus_op bus_ops[$], uvm_reg_item rw, uvm_sequencer_base sequencer, uvm_reg_adapter adapter); extern virtual task do_bus_write(uvm_reg_item rw, uvm_sequencer_base sequencer, uvm_reg_adapter adapter); endclass task reversed_reg_order_map::do_write_bus_ops(uvm_reg_bus_op bus_ops[$], uvm_reg_item rw, uvm_sequencer_base sequencer, uvm_reg_adapter adapter); foreach (bus_ops[i]) begin uvm_sequence_item bus_req; uvm_reg_bus_op rw_access; adapter.m_set_item(rw); bus_req = adapter.reg2bus(bus_ops[i]); 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 && i == 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 && i == bus_ops.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...", bus_ops[i].data, bus_ops[i].addr, rw.map.get_full_name(), rw.status.name()), UVM_FULL) if (rw.status == UVM_NOT_OK) break; end endtask task reversed_reg_order_map::do_bus_write (uvm_reg_item rw, uvm_sequencer_base sequencer, uvm_reg_adapter adapter); uvm_reg_addr_t addrs[$]; uvm_reg_map system_map = get_root_map(); int unsigned bus_width = get_n_bytes(); uvm_reg_byte_en_t byte_en = -1; uvm_reg_map_info map_info; int n_bits; int lsb; int skip; int unsigned curr_byte; int n_access_extra, n_access; int n_bits_init; uvm_reg_bus_op bus_ops[$]; Xget_bus_infoX(rw, map_info, n_bits_init, lsb, skip); addrs = map_info.addr; // `UVM_DA_TO_QUEUE(addrs,map_info.addr) // if a memory, adjust addresses based on offset if (rw.element_kind == UVM_MEM) foreach (addrs[i]) addrs[i] = addrs[i] + map_info.mem_range.stride * rw.offset; foreach (rw.value[val_idx]) begin: foreach_value uvm_reg_data_t value = rw.value[val_idx]; curr_byte = 0; /* calculate byte_enables */ if (rw.element_kind == UVM_FIELD) begin int temp_be; int idx; n_access_extra = lsb%(bus_width*8); n_access = n_access_extra + n_bits_init; temp_be = n_access_extra; value = value << n_access_extra; while(temp_be >= 8) begin byte_en[idx++] = 0; temp_be -= 8; end temp_be += n_bits_init; while(temp_be > 0) begin byte_en[idx++] = 1; temp_be -= 8; end byte_en &= (1<<idx)-1; for (int i=0; i<skip; i++) void'(addrs.pop_front()); while (addrs.size() > (n_bits_init/(bus_width*8) + 1)) void'(addrs.pop_back()); end curr_byte=0; n_bits= n_bits_init; foreach(addrs[i]) begin: foreach_addr uvm_reg_bus_op rw_access; uvm_reg_data_t data; data = (value >> (curr_byte*8)) & ((1'b1 << (bus_width * 8))-1); curr_byte += bus_width; `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; n_bits -= bus_width * 8; bus_ops.push_back(rw_access); end: foreach_addr foreach (addrs[i]) addrs[i] = addrs[i] + map_info.mem_range.stride; end: foreach_value // reverse the write order begin uvm_reg_bus_op reversed_bus_op_list[$]; foreach (bus_ops[i]) reversed_bus_op_list.push_front(bus_ops[i]); do_write_bus_ops(reversed_bus_op_list, rw, sequencer, adapter); end endtask `endif // `ifndef __REVERSED_REG_ORDER_MAP_SV__ Then I used a factory type override: set_type_override_by_type(uvm_reg_map::get_type(), reversed_reg_order_map::get_type());
  • Create New...