ashleywinn Posted June 26, 2015 Report Share Posted June 26, 2015 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()); Quote Link to comment Share on other sites More sharing options...
uwes Posted June 26, 2015 Report Share Posted June 26, 2015 UVM12 offers for this application a generic uvm_reg_transaction_order_policy which allows you to reorder transactions before they go to the bus. /uwe function void uvm_reg_map::set_transaction_order_policy(uvm_reg_transaction_order_policy pol); // Class: uvm_reg_transaction_order_policy virtual class uvm_reg_transaction_order_policy extends uvm_object; function new(string name = "policy"); super.new(name); endfunction // Function: order // the order() function may reorder the sequence of bus transactions // produced by a single uvm_reg transaction (read/write). // This can be used in scenarios when the register width differs from // the bus width and one register access results in a series of bus transactions. // the first item (0) of the queue will be the first bus transaction (the last($) // will be the final transaction pure virtual function void order(ref uvm_reg_bus_op q[$]); endclass Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.