Search the Community
Showing results for tags 'UVM_REG'.
-
Hi there IPXACT needs to capture array of registers properly in a design. Currently there is only one tag ''spirit:dim" to represent an array of registers. This does not enable us to capture an array of register effectively. Consider the following cases: 1. An array of registers can be one dimensional with each element offset by offset address 0x10. 2. An Array of multidimensional registers something like this: register_1[0][0] -> 0x0 register_1[0][1] -> 0x4 register_1[1][0] -> 0x10 register_1[1][1] -> 0x14 ... likewise Is there any way to capture just the address relationship to an array instance within IP-XACT XML tags? (Without using vendorExtensions tag?) We have not been able to capture the above said information inside IPXACT XML.(using only IP-XACT tags) Requesting thoughts regarding the same. Best regards Balasubramanian G
-
Hi, I have an issue where teh DUT returns an X for register read but the reg2bus still sees it as a 0. When I was going over the uvm_reg_bus_op struct the type for data is uvm_reg_data_t which is only 2-state. Is there a way to override this argument to support 3/4-state? Maybe uvm_reg_data_logic_t? Please let me know. Thanks in advance! Vignesh
-
I have observed a register access synchronization issue in one of my simulations and want to raise this in this forum in order to get feedback if this is a bug or a misusage in some way. In the verification environment there are two register sequences running in parallel. One sequence is doing the DUT configuration and the other one is a noise sequence which switches between the different programming agents and produces some read traffic on all the programming interfaces. The issue I have observed is that the programming sequence is doing a write to a register (AHB SEQ in the image below). During this access the noise sequence randomly selects the same register to do a read access (SPI SEQ in the image). What is happening now is that the mirror(map:SPI) is waiting in the XatomicX task (uvm_reg.svh, line 2400 [Accellera-1800.2-2017-1.0 reference implementation]) for the semaphore (m_atomic). When the field write(map:AHB) finishes after some it calls the put() function of the semaphores two times. Once in the called do_write() of the parent uvm_reg (line 1775) and once in the do_write() of the uvm_reg_field itself (line 1182). This is done in "zero" time but the first put(1) already triggers the get(1) from the other thread (SPI) and the second put(1) increments the m_atomic semaphore to 1. This allows the next writes on the AHB thread to start while the read of the slower SPI thread is still ongoing. In the image I tried to visualize the parallel sequences. The issue was causing the fourth write on the AHB interface to write wrong values to the internal register because it was based on older captured data. The timing is not accurate but chosen for better visualization (all arrows would otherwise be vertical arrows). The simulation was running with a recent version of the purple EDA vendor but the semaphore handling looks ok for me (first come, first serve). I did some local modifications to uvm_reg.svh and with these changes the simulation was passing but I don't know if there are other side effect in scenarios which are not happening in our simulations. These are the modifications I did: uvm_reg.svh Removed all XatomicX() calls from uvm_reg::do_write task (line: 1591, 1633, 1775 [Accellera-1800.2-2017-1.0 reference implementation]) Changed XatomicX task () (line 2435ff) task uvm_reg::XatomicX(bit on); process m_reg_process; m_reg_process=process::self(); if (on) begin // if (m_reg_process == m_process) // return; m_atomic.get(1); m_process = m_reg_process; end else begin // Maybe a key was put back in by a spurious call to reset() void'(m_atomic.try_get(1)); m_atomic.put(1); m_process = null; end endtask: XatomicX I hope this topic is helpful. Thanks Thorsten
-
Hi, While debugging a prediction error returned by "Bit Bashing Test Sequence", I came to read the uvm_reg_map::do_bus_read/do_bus_write methods which seems incorrect when it comes to computing the "byte enable" for the bus accesses (ie data member "byte_en" of the object of type uvm_bus_reg_op created by those functions) I'm explain the issue that I think I found here-below, can you please give me your feedback (Am i wrong or not?) My understanding about "uvm_reg_map::do_bus_read/do_bus_write" methods about is that these methods are called when I request a frontdoor read/write access and I don't supply a user frontdoor sequence. these methods aimed at splitting the high level object uvm_reg_item into as many uvm_bus_reg_op as need on the real bus. part of their role is to compute bus lane "byte enable" based on length and base address for a UVM_REG and length, base address and field offset in the reg for a UVM_FIELD The "uvm_reg_map::do_bus_read/do_bus_write" code extract I'm interested in here given here below with focus on bus byte enable (rw_access.byte_en) computation: task uvm_reg_map::do_bus_write (uvm_reg_item rw, uvm_sequencer_base sequencer, uvm_reg_adapter adapter); [...] uvm_reg_byte_en_t byte_en = -1; // <= here the default value of byte_en is set to 'all ones' [...] foreach (rw.value[val_idx]) begin: foreach_value [...] /* calculate byte_enables */ if (rw.element_kind == UVM_FIELD) begin // <= here byte_en is re-computed for UVM_FIELD only, not for UVM_REG [...] end [...] foreach(addrs[i]) begin: foreach_addr [...] uvm_reg_bus_op rw_access; [...] if (rw.element_kind == UVM_FIELD) begin // <= here the slice of the computed byte_en corresponding to // the current bus address is applied to the bus (rw_access.byte_en) // for UVM_FIELD only, not for UVM_REG for (int z=0;z<bus_width;z++) rw_access.byte_en[z] = byte_en[curr_byte+z]; end [...] rw_access.byte_en = byte_en; // <= here for UVM_REG, the default 'all ones' byte_en value is applied // and for UVM_REG, the correct value of rw_access.byte_en assigned above is // erroneously overwritten [...] end: foreach_addr [...] end: foreach_value endtask: do_bus_write But the extract of code here-below shows two issues: for a read/write to a UVM_REG, the byte_en is hard coded to "all ones" which seems incorrect to me in at least 2 cases: if the bus is 4-Byte wide, a register R1 to write is 1-Byte wide and at address 1 and another register R0 is also 1-Byte wide and located at address 0, then trying to write R1, will also write R0. if the bus is 4-Byte wide, a register R0 to write is 6-Byte wide and at address 0 and another register R1 is 1-Byte wide and located at address 6, then trying to write R0, will also write R1. for a read/write to a UVM_FIELD, there's a complex computation of byte_en for the whole field , then another computation to extract the correct bus byte enable from the whole field byte_enable. Those 2 computations seems correct to me but the last assignemnt "rw_access.byte_en = byte_en;" breaks everything by systematically setting the same bus byte enables value. For a field spanning several bus addresses this is correct/acceptable for the first bus access but this incorrect for the other bus accesses. Any feedback welcome, thank you Jordan
- 3 replies
-
- uvm_reg_map
- uvm_reg
-
(and 1 more)
Tagged with:
-
We ran across an issue when updating registers containing W1C fields. Specifically, if any field of the CSR requires an update, then calling the parent register's update() results in all W1C fields being written with 1. Example: register CTL has field GO with access type W1C in bit 31. It has field CMD with access type RW in bits 3:0. Both fields have reset value of 0. So, coming out of reset, we do: CTL.CMD.set(2); CTL.update(); The actual transfer goes out with data of 32'h8000_0002. Nobody asked for bit 31, but there it is. The issue appears to be with uvm_reg_field method XupdateX. For the W1C and W0S cases, it returns a value of "~m_desired". So, desired is 0, it wants to write a 1, even if m_mirrored is already 0. I'm not sure what I would consider the 'correct' behavior here. I can see two possibilities for W1C. What I would prefer is that if I set(1), update writes a 1. But, I could also see having it such that XupdateX evaluates ~m_desired & m_mirrored.
-
Looking for suggestions on the best approach to modeling something akin the following. value1 and value0 are implemented as value_reg[31:0] in RTL. The value actually stored in this register is always whatever you wrote to it. However, what you read back, and what HW sees when it looks at this register depends on the value of value_mode. When value_mode == DIRECT, you'll read back the whatever value is physically stored in value_reg[15:0] as value0 and value_reg[31:16] as value1. When value_mode == MULT, you'll read back a computed value instead. Let quotient == value_reg[15:0] * value_reg[31:16]. Then you'll read back quotient[15:0] as value0 and quotient[31:16] as value1. Right now I've just added tasks write_value( bit [15:0] a, bit [15:0 b ), read_value( output bit [31:0] quotient ) to the register model, which look at value_mode before accessing value_reg. In both cases, write_value() just writes parameters a and b to value0 and value1 using the register model. When value_mode == DIRECT, read_value() reads value0 and value1 multiplies them and returns the result. When value_mode == MULT, read_value() reads value0 and value1, concats them and returns the result. I'm contemplating adding some kind of virtual register to the register model instead of the tasks. Then, implement the logic using either callbacks or a custom front door. It also needs to preserve support for multiple address maps. The goal is to prevent multiple scoreboards and coverage classes which are referencing these registers from having to implement the same computation. The idea of a virtual register is to provide the same uvm_reg API to the user as other registers. A side benefit is the user only makes a single call to read the 32 bit value, rather than making two calls. Cheers.
-
In my test sequence, some fields of a register are changed frequently and others are keep previous value. I wrote the code like below, register.fieldY.set(value) register.update(status) // first update ... other code regsiter.fieldY.set(new_value) register.update(status) // second update The first update was processed but the second update was not seen in the system bus. I digged into UVM manual and implementation, and found out that 'update' function doesn't update mirrored value. By change, new_value was same to reset value of fieldY. So at that time the second update was called, m_mirrored and m_desired were same. That was the reason of no bus transaction. I tried below codes, and they updated my register properly. register.fieldY.set(value) register.write(register.get(), status) register.fieldY.set(value) register.update(status) register.predict(register.get(), status) However, they look like strange for me. Why I need to set desired value explicit by getting their internal desired value? Are my solutions wrong? Are there better ways in this case?
-
There are many threads/virtual sequences in the test that will initiate register transactions through a shared register model/bus agent. I want to give specific sequences higher priority so they will complete more quickly even when the bus is fully utilized. I tried set_arbitration(SEQ_ARB_STRICT_FIFO) on the bus sequencer, but now see this fatal message from it on the first transaction: [sEQDEFPRI] Sequence default_parent_seq has illegal priority: -1 I thought that if priority is not specified, it should default to a value like 100 and thus behave the same way as SEQ_ARB_FIFO (the default). Is there something wrong with the env setup? I was planning to only set priority (to a value >100) in the virtual sequence I wanted a raised priority on, but I haven't gotten to that point yet, so feel free to comment if that will work as well. Thanks in advance!
-
- uvm_reg
- arbitration
-
(and 1 more)
Tagged with:
-
Hi, We are using snps ralgen to generate the regmodel. It appears that the ralgen creates only the default map. We would like to have 2 maps for 2 separated if masters. Is there an online example for such case? A post gen script can do one of the following 2 options: 1. add another instance of uvm_reg_map and copy/clone the ready map after finished build 2. add another instance of uvm_reg_map, and duplicate any map1.add_reg and map1.add_submap to map2 Which is preferable? Thanks! Elihai
-
Hello , I have a scenario as below , In the dut , there is a set of registers which acts as control register for different instances of same IP inside dut. There is a control register which controls the set of registers to decide which instance of IP it needs to wr/rd . I am thinking of creating a reg block for the set of registers and instantiate as per the IP instance number. But I am not sure how the reg wr/rd of each block as per the control register IP selection . Please comment on this problem . Thanks
-
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:
-
Hi, In rtl design, I have a wire [3:0] d signal. It's assigned with 4 signals declared as reg type. So my question is when I try to add hdl path slice for d what should I do? I tried to add each of the four signals as slices, then in the test backdoor write to d has problem, I can't seem to pass wdata well. Ex: env. rm. d. write(...UVM_BACKDOOR) doesn't work. The d is a register naming which I create a uvm reg for it. Any input is appreciated.
-
I added a new register to a register block, but didn't add it to the map. When I try to read it in my test I get a null pointer access in: uvm-1.2c/src/reg/uvm_reg.svh, line 2624 The bug is that get_local_map returns a null pointer and rw.map is null because it wasn't specified in the read method. But the uvm_error macro references rw.map.get_full_name() when rw.map is null.
-
Hi there A register can have different RTL implementation based on access_mode. ie., When a register REG_1 is read in backdoor, actual HDLPATH of the register would point to 'top.abc.dout'. When a register REG_1 is written in backdoor, actual HDLPATH of the register would point to 'top.abc.dout_temp' We want to program different hdlpaths to REG_1 based on access mode (READ or WRITE). Does UVM_REG provide ready-made hookups or methods like add_hdl_path_slice() methods to setup different hdlpaths to READ/WRITE backdoor access? (Inside the DPI based backdoor access itself?) I checked that write_backdoor and read_backdoor methods need to be overwritten to setup different HDLPATHs based on READ/WRITE access modes. But this involves overriding string based DPI backdoor access factory methods. I'm looking for an alternative here, if it really exists. Suggestions to this requirement, very much appreciated. Best regards Balasubramanian G
-
Dear all, I'd like to access a register via multiple physical interfaces (bfm). Is it possible to set 2 different sequencers to the registers with same address? I have read this is a known issue from this forum. Could anybody give me a good example? I'm looking for a solution that there is no problem in prediction as well as write/read of UVM_REG. Thanks & Regards,
-
Hi there From the UVM users guide, a register read access can be executed as reg_model.BLK1.REG_FILE1.REG_1.read(status, rdata); But this mandates us to know the hierarchy of the register instantiation. ie., 'reg_model.BLK1.REG_FILE1' needs to be known to execute a read on register 'REG_1'. Is it possible to perform read/write access based on address instead of this hierarchy? Something like: generic_uvm_read (.address(0x0), rdata); In otherwords, we need not even know the register type or register instantiation hierarchy to issue a read access to that register. Can this be performed with UVM_REG? Requesting thoughts here. Best regards Balasubramanian G
-
Hi there I couldn't find enough information about capturing whitebox information with respect to a register defined in IP-XACT standard. Could this be done somehow? The closest that could be found was WHITEBOX information with respect to models.(not registers) Though the register definition can be captured in IP-XACT XML, there isn't proper way to capture RTL implementation of a register in IP-XACT. Capturing RTL implementation of a register in IP-XACT XML would enable us to stitch UVM_REG backdoor access. (without vendorExtensions) We feel the urge/need to enhance IP-XACT standard regarding the same. Requesting thoughts regarding the same. Best regards Balasubramanian G
-
While playing with UVM_REG we noticed that the behavior of uvm_reg_map::get_reg_by_offset() is inconsistent. Here's a code example of what I mean: class some_block extends uvm_reg_block; some_reg my_reg; virtual function build(); // ... default_map.add_reg(my_reg, 'h10); endfunction endclass some_block my_block = new(); my_block.default_map.set_base_addr('h100); offset = my_block.my_reg.get_offset(); // offset will be 'h10 my_reg = my_block.default_map.get_reg_by_offset(offset); // my_reg will be null my_reg = my_block.default_map.get_reg_by_offset(offset + 'h100); // my reg will not be null What I mean by inconsistent is that the meaning of 'offset' is different for 'add_reg(...)' and for 'get_reg_by_offset(...)'. By just passing the offset to it, it doesn't find the register, but by passing it the offset plus the base address it finds the register. Shouldn't get_reg_by_offset not care about the address map's base address? The code above is just a snippet. The full code is available on EDAPlayground: http://www.edaplayground.com/x/3Z7
-
Hi , I have a top register model. in that some address part is defined as memory. ( ex :- 0x0,4,8 ,c registers address then 0x10 memory then 0x20,0x24,0x28 ... registers) I have another register model , which has all the registers which fit the space defined as memory in top register model. (ex: 0x10,0x14,0x18,0x1c as registers) could you please suggest me how to map them . Regards, Pavan.
-
Why is UVM_REG faster than RGM ?
-
is there a way to set_rights of uvm reg for a specific map ? (like uvm_field) if no why not ? an alternative would be: reg.get_fields(field_q) foreach(field_q[i]) field_q[i].set_rights("RO") but why not allow modification of reg access directly ?
-
One aspect that was not covered in the UVM Basics series posted by Cadence in May 2012 was the register layer (aka UVM_REG). In this new video series we are giving an overview of the concepts, components and applications of the UVM register layer. The new video series is broken up into twelve clips: Introduction Testbench Integration Adapter Predictor & Auto Predict Register Model & Generation IP-XACT Register Model Classes Register API & Sequences Access Policies Frontdoor & Backdoor Predefined Sequences Demonstration You are now registered for success! (sorry, bad pun. ) =Adam Sherilog, Cadence