• Content count

  • Joined

  • Last visited

Everything posted by joniale

  1. Hi , To whom may correspond I think there is some kind of error in the UVM 1.1d register model. I have been experimenting with the UVM register model and i have seen the following code in uvm_reg_map.svh task uvm_reg_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; Xget_bus_infoX(rw, map_info, n_bits_init, lsb, skip); 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]; /* 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; The code continues but the interesting part is already there. Lets assume we have a register with 4 bytes and 1byte per address granularity (byte_addressing). Now, we do a FIELD access of 8bits length (the first byte of a register). The field is configured "individual_accessible, so UVM should only access that FIELD. The reg2bus should generate that byte request to be written. In other words, the vector "addrs" should have only one byte address. Going to the code, i see that initially the addrs has the 4 address ( the whole register) and when it comes to the "if (rw.element_kind == UVM_FIELD) begin" and it will pop_back()/remove all the exceeding bytes that doesn't need to complete "n_bits_init" of the field access. The problem is here: UVM has //while (addrs.size() > (n_bits_init/(bus_width*8) + 1)) and i think it should be while (addrs.size() > ((n_bits_init-1)/(bus_width*8) + 1)) //ejonalv possible error in UVM? check That is because in case we want to write 8 bits, it will calculate 8/8+1=2 address in the UVM version, but in fact it should require only 1 address. This is of course applicable for the READ variation. Did i misunderstand something? It is very hard to go through the register model without proper documentation in the code. I am looking forward your answer Best Regards Jonathan
  2. You can avoid the display of the warning coming from the regmodel using the UVM component function uvm_top.set_report_severity_id_action(UVM_WARNING, "RegModel", UVM_NO_ACTION); However, this will disable all warnings coming from RegModel ID. Best regards, Jonathan
  3. Dear Accellera developers, I have been working with the register model since some weeks. I have tried to understand how the adapters were supposed to be used for all the possible combinations of accesses and register definitions. After those weeks I still have some questions. Lets assume we have a register of 32bits with 3 fields. The databytes per address granularity is 1 databyte per increment of address. In other words, each address increment corresponds to one data byte written . That means that a 32bit register comprises 4 address per register. We have a protocol like AXI that supports byte enable masking. The first field covers only the first data byte of the register. When writing the first field of the register, then our AXI monitor sends one xfer that writes only one byte to the reg_predictor. On the other side, the register predictor that uses the bus2reg function of the adapter, will see that bus access and will try to update the register. I have seen that the UVM library calls bus2reg only once per bus TLM channel transfer. I have seen that the register that outputs bus2reg starts a bus collection process. I have seen that the register update will be done if: 1) the address is inside a register address: if (rw.addr == map_info.addr) begin 2) the bus collector reached the number of bytes needed to complete a register: if (predict_info.addr.num() == map_info.addr.size()) begin I have seen that in case the bus collector doesn´t have all the needed xfers to complete a register (if (predict_info.addr.num() == map_info.addr.size()) begin), a break will stop the loop over the addresses. From the previous information, I guess that the intention with the "write" function of the predictor was, that the monitor provides as many xfers that the collector will always complete all the bytes inside a register. Is that correct? Now come the question with the summary. The write function of the register predictor will be called only once. The bus2reg of the register predictor will be called only once. The collector of the write function in the register predictor will collect only once. The condition: "if (predict_info.addr.num() == map_info.addr.size()" will never be true because the register collected field has a size of 1 byte and the total register has a size of 4 bytes. At least it will not be true until the 4 predict_info addresses are received in the write function. How it is supposed to update fields within the UVM register model? We think we can come around to this problem if we call the write() function for each byte with 3 byte_enables set to zero and one set to 1. Is the monitor supposed to split the 32bit AXI data on the bus into bytes to send those to the register predictor? Could you explain me the concept behind field write and field update of the register model in this context. Are my assumptions and understanding wrong? Any help would be appreciated. Do you have an example for this situation? Looking forward your answer Joachim and Jonathan
  4. In case you are using a direct VC burst I guess the way to do this is by expanding/padding the original partial access to a register and make it access the whole register. The padding can make use of byte_en to flag those extra bytes as dummy. This can be done, either in the monitor or by overwritting the uvm_reg_predictor class (creating a split/padding adapter function). In case you use the UVM register write function to write a field of a register: With the configuration 1byte per address and a register of 4 bytes. First field in the first byte. The reason why the monitor sends only one byte to the reg_predictor is because the reg2bus function is not forced to do a complete register access. There is a configuration parameter for the fields called " individually_accessible " If two fields share their address they should have both "individually_accessible"=0 (set to zero/non individual accessible). Once this is done, UVM will read previous complete register value and make an OR with the new field value. This is in order to keep previous values in a complete register access. The documentation says:// individually_accessible shows if this field can be written individually, i.e. without affecting other fields in the containing register. "individually_accessible" is the last parameter in the configure function of the field: . e.g. this.BLK_PKG_TEST3_F.configure(this, 10, 20, "RW", 0, 10'h3F, 1, 1, 0); When you do that you will receive the following warning: UVM_WARNING verilog_src/uvm-1.1d/src/reg/uvm_reg_field.svh(1716) @ 900000 ps: reporter [RegModel] Individual field access not available for field 'ral_sys_airqc_rm_top0.info_registers.BLK_PKG_TEST.BLK_PKG_TEST0_F'. Accessing complete register instead. With this, UVM will force the adapter reg2bus to generate a bus that write the whole register. Other fields will have previous values merged with your new field value so that the complete register access doesn't modify other fields. (forcing reg2bus full register will solve the bus2reg collecting part) Something important to remark is that the definition of "individually_accessible" is in fact not applicable to our example. In our example, each field is "individually accessible" because we have a "bytes per address" of 1 byte and each field is in a different byte address. That means this is somehow a hack or a trick and not really a good solution. Besides, you will have a nasty WARNING. Next questions are, why UVM has not different warning/error codes inside register model to be able to mask those warnings individually? why UVM has not implemented a general solution that takes in mind direct VC register updates (e.g. other VHDL block) and not limiting its usage to their UVM register access functions?
  5. There are some problems on adding objections in the Master driver and monitor. (slave should not have objections as they are reactive) See This problem is seen once you start doing asynchronous reset. If you do that then you have to drop the objections in a controlled way (if you currently has an ongoing xfer/raised objection on the driver). This would be difficult if you are using the disable fork or stop_sequences method for controlling the reset. These two methods, stop the process on the driver but they don't affect the objections. I would recommend to control the objections only in your test. That is to say, let the user decide when should the simulation be finished independently on the low level driver status. Moreover, the user should have enough mechanism to wait for responses or wait for the end of a processing xfer on the driver before dropping the objections in the test so the user is still under control. There are ways to kill/drop all the objections like the function force_stop() under However, i will not recommend to use that because this kill not only one specific driver objections but all objections. (Reset could be used only under a specific region on your design and the whole design) Verification academy recommends to do only objections on the test (to end the test). If you want to include the objections in the driver, then you have to drop the objections in the cleanup phase after your reset. You can do this only if there is a raised objection. `uvm_info("PHASE OBJECTION COUNT", $sformatf("%0d", phase.get_objection_count(this)), UVM_LOW); See an example of the new UVM 1.2 features about objections If you don't want to use UVM 1.2 you can implement your own objection counter in the driver.
  6. Here a small example of code: First, an example to create a byte dynamic array from a string. The dynamic array of bytes contains the ASCII CODE number representation of each character. The advantage is that this can be for example be randomized but strings cannot be randomized. (created doing e.g. for(i=0;i<stringvar.len(); i++) begin byte_din_array = {byte_din_array ,stringvar[i]}; //stringvar[i] will return empty byte if the index would be beyond the string length //The advantage of using stringvar[i] instead of stringvar.atoi(i) is that //the string can have all ASCII characters and not just numbers. //Disadvantage is that the byte contains the ASCII CODE "number" //representation of the character and that is not human readable end ). Here is the example to convert the dynamic array of bytes back in a concatenated string. You may have used the previous dynamic array to be partly randomized (with constraints) inside an xfer or changed in post_randomize. function string convert_byte_array2string(byte stringdescriptionholder[]); automatic string temp_str=""; automatic byte byte_temp; automatic string str_test; for ( int unsigned i = 0; i<stringdescriptionholder.size(); i++) begin i=i;//debug breakpoint byte_temp = stringdescriptionholder[i]; str_test = string'(byte_temp); //the "string cast" will convert the numeric ASCII representation in a string character temp_str = {temp_str,str_test}; end return temp_str; endfunction If you want more information about strings i recommend to read the section 3.7 of the Systemverilog LRM (2012) . It is about the string data types and explain the built-in methods used with string data types.
  7. Just to put it clearly you cannot change the parameters dynamically. That would not work. That is to say Your address in: class b_seq #(parameter bit [16:0] address = 0) extends base_seq need to be a constant or static not changing in the run_phase. In other words, a virtual sequencer or the task that will start this sequence cannot use a variable for this. If you want to pass info between seq classes you can just create rand class variables and set them with randomize with before you execute the sequence. you can also use `uvm_do_on_with(xfer_or_seq,sequencer {address==32'hABCD}); The following info should help