Jump to content


  • Posts

  • Joined

  • Last visited

  • Days Won


joniale last won the day on February 5 2016

joniale had the most liked content!

Recent Profile Visitors

942 profile views

joniale's Achievements


Member (1/2)



  1. From http://www.asic-world.com/systemverilog/literal_values4.html string a; a = "This is multi line comment \n and this is second line"; /* Outputs: a = This is multi line comment^M and this is second line */ //You will have ^M which is the dos character for new line. if you write to a file with this line. If you want to avoid that, then the next solution should be used string tmg ={" \n" , "//periodic signal intf.KEYCONTROL_CLK \n" , "fork\n" , " begin\n" , " the_clock = 0;\n" , " forever begin\n" , " if(the_clock == 0)\n" , " #(5000000/2 * 1ps);\n" , " else\n" , " #((5000000-5000000/2) * 1ps);\n" , " the_clock=~the_clock;\n" , " end\n" , " end\n" , "join_none\n"}; $display ( tmg); Obviously, the second example is recommended
  2. A good tutorial to understand how to embedd Python in C https://www6.software.ibm.com/developerworks/education/l-pythonscript/l-pythonscript-ltr.pdf Then you can search how to use DPI with C to be able to use C in systemverilog. Sure, There is a lot of DPI examples in your vendor EDA simulator folder.
  3. Hi again, I want to report another minor issue. the issue is applicable in case you want a layering sequence for registers in AXI. I mean what is described here: https://www.mentor.com/products/fv/resources/overview/a-new-class-of-registers-2e32ca83-d5ee-4e34-8880-c006be7e537f As you can see a layering sequence allows you to create randomized register accesses that are not possible with the adapter and the default uvm_reg_map. This is needed to test that registers are written/read correctly with different AXI accessed than the fix accesses done by the uvm library. In that case you have to disable your adapter (being null) to avoid the bus_write and bus_read functions as described in the paper of the link. Unfortunately, the function "is_indv_accessible" needs an "adapter". That means you cannot access is_individual_accessible field flag of your register model, in case you are using the sequence layering methodology. To workaround this problem and be able to use UVM_FIELD kind accesses, we can redirect all uvm_reg_field write/read fuctions with a custom uvm_reg_field read/write functions(this can be done with settypeoverride by type all uvm_reg_field classes). In those new custom_reg_field functions you can, 1. redirect the field call to a register type call with the same inputs and second use the extension to pass in the redirected REGISTER write/read the uvm_reg_item corresponding to the original FIELD access. Afterwards, you can check in the sequence layer if the UVM_REG register request item has an extension containing a FIELD!=null. If that is the case, it means the register access is not a register access but in fact a redirected FIELD access. That field access can be processed in your layering sequence, that creates the stimuli needed for that field. //////// However, the correct way would be that uvm retrieves the "supports_byte_enable" information not from the adapter but from uvm_reg_map. In other words, i think that the configuration flags "supports_byte_enable" and "provides_responses" should be declared inside the uvm_reg_map and not inside the adapter. Besides, there should be set and get functions for those signals so that these can be set from the environment or from the adapter itself. I hope i have explained the issue. Best regards, Jonathan
  4. Hi experts, I have the following question about vertical reusability and null sequencers. I have a sequence that stimulates a sub block inside a TOP block. I have verified first the separated sub block. Therefore, i had a testbench for the sub block that has of course VC interfaces and registers. I would like to have a clear way of coding to allow vertical reusability of the sequence that test the sub block. In other words, i would like how to code the sub sequence so that i can start that sequence from a TOP module afterwards. I see the following problems 1)The TOP test bench will not have the interfaces (VCs) for the sub block. 2)The registers will be accessed through the TOP interface but not the sub interface. I can solve the 2 point by creating a new register model and connecting the predictor/adapter of the top. At the same time, i can overwrite the register model used in the sub block sequence so that it uses the new register TOP block handler correctly.---:OK However for the point one, it is more difficult. Theoretically, the sequence should ignore all the VCs of the sub block that are not used anymore. Now the sub block is driven by the TOP DUT and not by a test bench VC. How should a write the sequence so that these VC accesses are ignored in case a TOP sequence calling the old subsequence?. I though that any uvm_do macro that is performed to a VC that is not declared would be ignored but that is not the case... The only idea it comes to me is to code the sub-sequence with an if asking if the VC exists (not null). If it exists, then go ahead, but if it doesn´t assume that this access will be done by a TOP DUT and ignore it! Is this the right way to do this? How can you reuse your old sub sequence from the top sequence? Is there any methodology? Any link? Thanks in advance Jonathan
  5. Here my two cents, In my opinion, it would be good that UVM would do the backdoor access not as it currently does. It would be good that once provided the hdl_path to a field, the UVM library somehow would be able to generate an unique interface for that hdl_path and a bind that correspond to that interface. That generated interface should be published to the config data base and would be available in any part of your design through the ConfigDB. Of course, the UVM backdoor functions would still be able to do the checks they do now, for example, check that the register is not being accessed by the frontdoor/busy. The difference is that they will update the values over an interface that is published with a logic name in the configdatabase. Having the fields as interfaces in the config data base have the advantage that the user can download that interface handler in the scoreboard and performs things like waiting for an event/trigger on that signal. In other words, signal change detection which is very useful for interrupts. I understand that UVM cannot create code/an interface for you. However, UVM can define a macro for this. I think working with an interface exposer in the config data base is a lot easier and intuitive for interrupt handling on registers. In relation to the topic. I just detect any write on registers using the TLM channel of the reg predictor (a monitor is connected to the predictor and the predictor makes the updates in the register model (explicit implementation)). That TLM channel is triggered on any register change. Then, i ask the name of the register and if it is a READ or a WRITE. Best regards, Jonathan
  6. Hi, Here my two cents. Cloning of register blocks is not intended in UVM. Therefore, there are several checkers that warns you about that. One way to do this is implementing a custom clone function inside the register block for each field. This is something that can be done with some perl scripting (if you have many registers and fields). See a small snip on how to do that (only with one register and field EXPECTED_SUM_2) class hmac_sha256_regblock extends uvm_reg_block; `uvm_object_utils(hmac_sha256_regblock) //This function has been included in the automatic generated register block from UVM using the script typedef hmac_sha256_regblock this_regblocktype; virtual function this_regblocktype clone_reg_block(input int clone_mode=0, input string unique_regblockstr_id="dummy"); automatic this_regblocktype dummyregblock; dummyregblock = this_regblocktype::type_id::create($sformatf( "hmac_sha256_regblock_%s",unique_regblockstr_id)); dummyregblock.build(); if ((clone_mode==0)||(clone_mode==1)) begin dummyregblock.inst_EXPECTED_SUM_2.EXPECTED_SUM_2.set(this.inst_EXPECTED_SUM_2.EXPECTED_SUM_2.get()); end if ((clone_mode==0)||(clone_mode==2)) begin assert(dummyregblock.inst_EXPECTED_SUM_2.EXPECTED_SUM_2.predict(this.inst_EXPECTED_SUM_2.EXPECTED_SUM_2.get_mirrored_value()) ); end return dummyregblock; endfunction:clone_reg_block rand EXPECTED_SUM_2 inst_EXPECTED_SUM_2; // Computation settings ..... endclass In your sequence you can call the clone function in the following way m_regblock_cloned_base = REGBLOCK.clone_reg_block(0); This will create a frozen/dummy block that has the same values that you had for the register model at that point of the simulation. I hope it helps Jonathan
  7. 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
  8. 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
  9. 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?
  10. 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
  11. There are some problems on adding objections in the Master driver and monitor. (slave should not have objections as they are reactive) See https://verificationacademy.com/forums/uvm/question-regarding-dropping-objections-once-stopsequences-issued-sequencer 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 http://www.dvteclipse.com/uvm-1.2_Public_API/uvm_pkg-uvm_test_done_objection.html. 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). https://verificationacademy.com/forums/ovm/raise/drop-objections-issues-reset https://verificationacademy.com/cookbook/endoftest 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 http://www.edaplayground.com/x/2Ny If you don't want to use UVM 1.2 you can implement your own objection counter in the driver.
  12. 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.
  13. 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 https://verificationacademy.com/cookbook/sequences/generation
  • Create New...