Search the Community
Showing results for tags 'Register Layer'.
-
Hi all, I got a question regarding RAL. Assuming there are 2 registers A and B whose width are 8 bits and 16 bits respectively and the bus width is 8 as well. The two UVM registers are created by new(name, 8, UVM_NO_COVERAGE) and new(name, 16, UVM_NO_COVERAGE) for defining their own width. Register A and B locate at address 0 and 1-2 as the address is byte aligned. An user defined register map is created uvm_reg_map my_map = create_map("my_map", 0, 1, UVM_LITTLE_ENDIAN, 1); my_map.add_reg(reg_A, 0, "RW"); my_map.add_reg(reg_B, 1, "RW"); After reg_B.write(status, 16'habcd, .path(UVM_FRONTDOOR)), I would expect 2 transactions with 8 bits each appearing on the bus. However, there is only one access of h'cd to address 1. The other one never comes and it ends up throwing an error "There are 1 incomplete register transactions still pending completion" which is caused by a check on outstanding register accesses pending in predictor in check phase. I tried to find out how the original data value in uvm_reg_item gets split in reg2bus() function. It seems correct that the original data in uvm_reg_item is h'abcd and split to h'cd in uvm_reg_bus_op. But again the other part of data does not come. Also tried to search for answer from other places, for instance the same issue here https://verificationacademy.com/forums/uvm/how-handle-registers-are-wider-bus, it didn't help much unfortunately. If you have any clue about this, please leave your comments. Thanks.
-
- uvm
- register model
-
(and 2 more)
Tagged with:
-
In our DUT, we have two separate independent physical interfaces (APB & I2C) (active 1 at a time) through which all registers can can be accessed, Also in our register model, we created two reg_maps, one for each APB & I2C. Now through testcase, we want only one physical interface at a time, to be subjected to default uvm sequences (i.e. uvm_reg_access_seq, uvm_reg_bit_bash_seq,etc) but it is not possible as uvm_sequence will get all the maps using get_maps(); So without over-riding the default uvm_reg_access_seq, is it possible to achieve such type of configuration in testcase itself via using uvm_reg_map or some other methods. Kindly refer following pseudo code //Pseudo Code for Scenario class dut_reg_test extends base_test; `uvm_component_uti ls(dut_reg_test) //Handle of default uvm register access sequence uvm_reg_access_seq my_reg_seq; // Select Physical Interface rand bit APB_I2C; uvm_reg_map test_map; dut_reg_model regmodel; task buid_phase (uvm_phase phase); super.build_phase(phase); // Select PHY Interface via commandline if ($value$plusargs("APB_I2C=%b", APB_I2C)) else APB_I2C = $random; if (APB_I2C) test_map = regmodel.apb else test_map = regmodel.i2c endtask : build_phase task main_phase (uvm_phase phase); //Create method for sequence my_reg_seq=uvm_single_access_seq::type_id::create("my_reg_seq"); //Randomize with selected map my_reg_seq.randomize with { maps == test_map;}); // Start default sequence my_reg_seq.start(NULL); endtask : main_phase endclass : dut_reg_test The above strategy cannot be implemented because uvm_reg_access sequence doesn't contain uvm_reg_map it's only present in uvm_reg_single_access_seq, Similar kind of limitations persists will all uvm_reg_bit_bash_seq & reset sequences. Can we have some strategy to resolve this issue ? Thanks Nikunj Hinsu
- 2 replies
-
- uvm_reg_map
- Register Layer
- (and 6 more)
-
I am trying to run the uvm builtin register sequences. I seem to have broken our usage of them in porting code from a previous project. Q1: In the past, we've started them as default sequences. Is there any way to have an error/warning appear if a 'set', such as the below, is never utilized (or 'get'-ed)? uvm_config_db#(uvm_object_wrapper)::set(this, "*.m_reg_agent.m_seq_reg.main_phase", "default_sequence", uvm_builtin_reg_test_seq::type_id::get()); I've added uvm_top.print_topology(); and uvm_config_db::dump(); and it seems the ::set should be working, but nothing is starting. Q2: Are builtin (base class) sequences automatically "::created" somehow/somewhere? (Creation/new-ing is still necessary when you setup a default sequence, right? Or is there some magic singleton-ness that happens?) Q3: My error of the moment is as follows. Your thoughts are appreciated. UVM_FATAL @ 39990: reporter@@seq [SEQ] neither the item's sequencer nor dedicated sequencer has been supplied to start item in seq always@(posedge clk), ljepson74
- 2 replies
-
- uvm_builtin_reg_test_seq
- register layer
-
(and 2 more)
Tagged with:
-
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());
- 1 reply
-
- uvm_reg_map
- uvm_reg
-
(and 1 more)
Tagged with:
-
A Register Layer read (using the built-in frontdoor) proceeds as follows: uvm_reg::read -> uvm_reg::XreadX -> uvm_reg::do_read -> uvm_reg_map::do_read -> uvm_reg_map::do_bus_read If a read request (bus_req) is expected to be completed by a completely separate read reponse (bus_rsp), the following code is executed within uvm_reg_map::do_bus_read: if (adapter.provides_responses) begin uvm_sequence_item bus_rsp; … rw.parent.get_base_response(bus_rsp); adapter.bus2reg(bus_rsp,rw_access); end The problem is that since transaction_id is not being provided to uvm_sequence_base ::get_base_response: virtual task get_base_response(output uvm_sequence_item response, input int transaction_id = -1); … if (response_queue.size() == 0) wait (response_queue.size() != 0); if (transaction_id == -1) begin response = response_queue.pop_front(); return; end forever begin queue_size = response_queue.size(); for (i = 0; i < queue_size; i++) begin if (response_queue.get_transaction_id() == transaction_id) begin $cast(response,response_queue); response_queue.delete(i); return; end end wait (response_queue.size() != queue_size); end endtask the next response provided to the sequencer will unblock get_base_response and be provided to ALL reads that have posted their requests and are waiting for a response. When that happens the first read to unblock will get the transaction (possibly not the correct one), and then the others will get null responses, and incur in Null-access runtime errors. By simply adding the transaction_id as follows: rw.parent.get_base_response(bus_rsp, bus_req.get_transaction_id()); we force get_base_response to return only after the correct response matching the request is received by the sequencer. The change will enable support for bus protocols where reads are posted and their responses may be returned out-of-order; and it should not affect simpler protocols where the read requests/responses are not interleaved. Without the (simple) change the only solutions are to: 1. Create a user-defined frontdoor; which adds significant complexity, since not all automated register model generators have to hooks register them automatically 2. Extend uvm_reg_map, override do_bus_read, and factory replace We are using solution #2. Before reporting this to the UVM Mantis I wanted to open the topic for discussion. Regards, Devaloy Muniz
-
I've run into the following issue using the built-in UVM register tests. The built-in UVM register tests (seem to) start R/W-ing immediately after top-level reset is released. This was fine, initially. See attached image "Capture". We now have some delay between the release of top-level reset and the actual reset going to the register block. This is resulting in a read occurring before reset to the rtl regblock is released, and causes the test to hang. See attached image "Capture2". Without modifying the built-in register tests/sequences, how would anyone suggest that we cleanly delay the stimulus? Perhaps I just need to make the stimulus aware of the different reset when the model/stimulus is generated, or simple add some delay to a phase before the R/W-ing starts. (The former sounds right. If that's the solution, I'll need to figure out how we're generating the model/stimulus.) I've just started hunting around for the built-in UVM register test sequences and will return to it tomorrow, but will anyone tip me off as to what names I should be searching for? thanks This has been useful, https://verificationacademy.com/cookbook/registers/builtinsequences, but it seems I need to do some more reading and hunting before I grasp how the built-in register stimulus is created and used.
- 1 reply
-
- register layer
- register
-
(and 3 more)
Tagged with: