Jump to content


  • Posts

  • Joined

  • Last visited

Recent Profile Visitors

724 profile views

kaushalmodi's Achievements


Member (1/2)



  1. +1 Where do I find all the UVM bug reports? https://accellera.mantishub.io/my_view_page.php seems to be listing only the SystemVerilog workinggroup bugs. Update: I just learned that the UVM Mantis bugs are hidden by default to the public (I wonder why!). You can see them only after you get a 'reporter' level account on the Accellera Mantishub. To do so, send an email to the email address listed in https://www.accellera.org/images/activities/committees/uvm/Reporting_bugs_and_enhancement_requests_for_UVM_2015.pdf to get that "special" access (quoted "special" because I do not understand why bug reports should be made private.. it's understood that creating new bug reports requires some kind of account, but why need one when one wants to just read them).
  2. Here's the same example that can be directly run on EDA Playground: https://www.edaplayground.com/x/4Ydz
  3. Here is a minimal example to reproduce this bug: // Time-stamp: <2019-09-13 08:40:25 kmodi> // Original Author : Kaushal Modi // File Name : begin_time_end_time.sv // Description : Minimal reproducible example to show the issue with // begin_time and end_time of transactions begin of // time type instead of realtime. // Run command : For Cadence: // xrun -uvm -uvmhome CDNS-1.2 begin_time_end_time.sv // Command should be similar for other vendors. // *** Fix is to replace the time type with realtime type everywhere // *** where $realtime value is assigned to a variable in the entire UVM // *** code. `timescale 1ns/1ps `include "uvm_macros.svh" import uvm_pkg::*; module top; initial begin $timeformat(-12, 0, "ps", 7); // units, precision, suffix, min field width run_test("my_test"); end endmodule : top class my_tr extends uvm_sequence_item; static int id; `uvm_object_utils_begin(my_tr) `uvm_field_int(id, UVM_DEFAULT | UVM_DEC) `uvm_object_utils_end function new(string name = "my_tr"); begin super.new(name); id++; end endfunction // new endclass : my_tr class my_test extends uvm_test; `uvm_component_utils(my_test) function new(string name = "my_test", uvm_component parent = null); super.new(name, parent); endfunction : new virtual task run_phase(uvm_phase phase); begin super.run_phase(phase); phase.raise_objection(this, $sformatf("%s: At the beginning of run phase", get_type_name())); repeat (1) begin automatic my_tr tr; automatic realtime actual_begin_time, actual_end_time; tr = my_tr::type_id::create("tr"); actual_begin_time = $realtime; void'(begin_tr(tr)); #1ps; // Commenting out this line and uncommenting the next line will mask the bug // #1ns; // If the time increments is done in full time steps (`timescale 1ns/1ps), this bug is masked actual_end_time = $realtime; end_tr(tr); tr.print(); assert (actual_begin_time == tr.get_begin_time()) else `uvm_error("BEGIN_TIME_MISMATCH", $sformatf("Actual begin time (%t) != begin_time recorded in tr (%t)", actual_begin_time, tr.get_begin_time())); assert (actual_end_time == tr.get_end_time())else `uvm_error("END_TIME_MISMATCH", $sformatf("Actual end time (%t) != end_time recorded in tr (%t)", actual_end_time, tr.get_end_time())); end phase.drop_objection(this); end endtask : run_phase endclass : my_test
  4. Hello all, Today, I ended up in a situation where the transaction boxes in Cadence Simvision will not at the exact time where they were supposed to be. This resulted in a drift of the boxes represented in the waves. On looking closer, the box begin time happened only at 1ns resolution, whereas my agent package's resolution and even the default simulation timescale was 1ns/1ps. So I expected the boxes' begin times to be possible at 1ps resolution (not 1ns). Here are the prints from the uvm_info debug statements in my agent monitor: UVM_INFO @2832.523ns ch0_TX_QEC_OUT: after end_tr of micro_tr :DEBUG_TR UVM_INFO @2832.523ns ch0_TX_QEC_OUT: before begin_tr of micro_tr :DEBUG_TR UVM_INFO @2832.523ns ch0_TX_QEC_OUT: after begin_tr of micro_tr :DEBUG_TR UVM_INFO @2833.540ns ch0_TX_QEC_OUT: after wait for slave_cb :DEBUG_TR UVM_INFO @2833.540ns ch0_TX_QEC_OUT: before write of micro_tr :DEBUG_TR UVM_INFO @2833.540ns ch0_TX_QEC_OUT: before end_tr of micro_tr :DEBUG_TR UVM_INFO @2833.540ns ch0_TX_QEC_OUT: after end_tr of micro_tr :DEBUG_TR UVM_INFO @2833.540ns ch0_TX_QEC_OUT: before begin_tr of micro_tr :DEBUG_TR The attached figure shows how it looks in waves. When I then printed tr_micro.print() I saw that the begin_time and end_time variables in there had lost the precision in picoseconds! So I start grepping UVM source code to see how the begin_time was assigned, and I find this: function integer uvm_transaction::m_begin_tr (time begin_time=0, integer parent_handle=0); time tmp_time = (begin_time == 0) ? $realtime : begin_time; uvm_recorder parent_recorder; I believe the bug is wherever in UVM the $realtime is assigned to a time type variable. If the time type is refactored to realtime type, this issue will be fixed. With the clock period of 1.018ns, I expected each transaction box to be 1.018ns wide. But with this loss of precision in begin_time and end_time, the transaction recording happens incorrectly and shows grossly wrong transaction representation in the waves. This is highlighted with the fact that the clock period (1.018ns) is close to the timescale step of 1ns. Here is a minimal SystemVerilog example that shows the information loss in time when $realtime value is assigned to a time variable: `timescale 1ns/1ps module top; //In uvm_transaction.svh (UVM 1.2), we have: // // // function integer uvm_transaction::m_begin_tr (time begin_time=0, // integer parent_handle=0); // time tmp_time = (begin_time == 0) ? $realtime : begin_time; // // .. // //This example shows how when $realtime is assign to tmp_time of //type time, all the precision is lost. So above is as good as //assigning the time from $time instead of $realtime. // function void print_now(); realtime nowr; time now; begin nowr = $realtime; now = $realtime; // "now" loses the 1ps resolution compared to "nowr" $display("time: %t, realtime: %t", now, nowr); end endfunction : print_now initial begin $timeformat(-9, 3, " ns", 11); // units, precision, suffix_string, minimum_field_width print_now(); // -> time: 0.000 ns, realtime: 0.000 ns #1.1; print_now(); // -> time: 1.000 ns, realtime: 1.100 ns #1.23; print_now(); // -> time: 2.000 ns, realtime: 2.330 ns #1.456; print_now(); // -> time: 4.000 ns, realtime: 3.786 ns $finish; end endmodule : top
  5. Here's a minor update with respect to point (1) in my above summary. I had to do: mem_tr = spi_mem_tr::type_id::create(.name("mem_tr"), .contxt(get_full_name())); instead of mem_tr = spi_mem_tr::type_id::create({get_full_name(), ".mem_tr"}); With the latter, I get an SDI/Verilog warning saying: Message! [SDI/Verilog] In sdiT::transactionTypeT ctor, the transaction name had illegal characters. Those characters have been replaced. Here's the new name: 'uvm_test_top_env_spi_m[0]_reg2spi_adapter_mem_tr' ... Message! [SDI/Verilog] In sdiT::transactionTypeT ctor, the transaction name had illegal characters. Those characters have been replaced. Here's the new name: 'uvm_test_top_env_spi_m[1]_reg2spi_adapter_mem_tr' But the overrides still worked. Now with that fixed (by not using get_full_name() or "." in the "name" argument, mem_tr.get_full_name() now prints just "mem_tr". But the overrides still work!! This is very confusing.
  6. Hi Tudor, Thanks for your immense help. I was finally able to get the overrides work with these changes: (1) Append the full name to the transaction objects generated in the adapter: mem_tr = spi_mem_tr::type_id::create({get_full_name(), ".mem_tr"}); (2) Append the full name even to the adapter object generated in the SPI env: reg2spi_adapter = spi_master_reg_adapter::type_id::create({get_full_name(), ".reg2spi_adapter"}); (3) Finally set the instance overrides as usual in the base test: set_inst_override_by_type ( .relative_inst_path("env.spi_m[0].*"), .original_type(spi_mem_tr::get_type()), .override_type(spi_mem_ext_tr::get_type())); set_inst_override_by_type ( .relative_inst_path("env.spi_m[1].*"), .original_type(spi_mem_tr::get_type()), .override_type(spi2_mem_ext_tr::get_type())); Once again, I really appreciate the help you provided. Thanks!
  7. Thank you. It now makes sense why that full path of "env..." did not work. So I thought that the below would fix that. But it is not.. Below code is in the "SPI env" component whose objects are "spi_m[0]" and "spi_m[1]". reg2spi_adapter = spi_master_reg_adapter::type_id::create(.name("reg2spi_adapter"), .contxt(get_full_name())); `uvm_info("DEBUG_FULL_NAME", $sformatf("Full name of this spi_env obj is %s", this.get_full_name()), UVM_MEDIUM) `uvm_info("DEBUG_FULL_NAME", $sformatf("Full name of the new reg2spi_adapter obj is %s", reg2spi_adapter.get_full_name()), UVM_MEDIUM) Inside the "new" function of the "spi_master_reg_adapter" class, I have: `uvm_info("DEBUG_FULL_NAME", $sformatf("Full name of this adapter obj is %s", this.get_full_name()), UVM_MEDIUM) But still, this is what gets printed (formatting changed from default using a custom report server): UVM_INFO @ 0ns Full name of this adapter obj is reg2spi_adapter :DEBUG_FULL_NAME UVM_INFO @ 0ns Full name of this spi_env obj is uvm_test_top.env.spi_m[0] :DEBUG_FULL_NAME UVM_INFO @ 0ns Full name of the new reg2spi_adapter obj is reg2spi_adapter :DEBUG_FULL_NAME UVM_INFO @ 0ns Full name of this adapter obj is reg2spi_adapter :DEBUG_FULL_NAME UVM_INFO @ 0ns Full name of this spi_env obj is uvm_test_top.env.spi_m[1] :DEBUG_FULL_NAME UVM_INFO @ 0ns Full name of the new reg2spi_adapter obj is reg2spi_adapter :DEBUG_FULL_NAME I am curious why the below does not work; I am specifying the env's "get_full_name()" as the context: reg2spi_adapter = spi_master_reg_adapter::type_id::create(.name("reg2spi_adapter"), .contxt(get_full_name()));
  8. Hi Tudor, Thanks for the reply. I have tried something similar. But that doesn't work. Here's is some code to show what I tried. In the adapter class where I create the transaction objects: mem_tr = spi_mem_tr::type_id::create(.name("mem_tr"), .contxt(get_full_name())); In the base test where I do the overrides: spi_mem_tr::type_id::set_inst_override(.override_type(spi_mem_ext_tr::get_type()) , .inst_path("env.spi_m[0].reg2spi_adapter.*") , .parent(null)); spi_mem_tr::type_id::set_inst_override(.override_type(spi2_mem_ext_tr::get_type()) , .inst_path("env.spi_m[1].reg2spi_adapter.*") , .parent(null)); Note that I have fixed the order of the arguments to set_inst_override; the parent argument is the last argument. To avoid confusion, I am using named argument association. The difference here is that we have a VIP that wraps the SPI adapter, and I have 2 instances spi_m[0] and spi_m[1] of the same VIP class. the mem_tr objects are created inside the reg2spi_adapter. Even then, the overrides do not work at all.
  9. Hello, We have a test bench environment where we have 2 objects of the same SPI env class. The SPI env sets the sequencer for the RAL model as follows: reg_model.default_map.set_sequencer(spi_master_agt.mem_sqr, reg2spi_adapter); The transaction type handled by the spi_master_agt.mem_sqr is spi_mem_tr. Now I need to extend the spi_mem_tr to spi_mem_tr_1 and spi_mem_tr_2, and then override spi_mem_tr with those separately for the 2 objects of the SPI env class. // Below does not work set_inst_override_by_type ( .relative_inst_path("env.spi_m[0].*"), // Here spi_m[0] is the first instance of the SPI env .original_type(spi_mem_tr::get_type()), .override_type(spi_mem_tr_1::get_type())); set_inst_override_by_type ( .relative_inst_path("env.spi_m[1].*"), // Here spi_m[1] is the second instance of the SPI env .original_type(spi_mem_tr::get_type()), .override_type(spi_mem_tr_2::get_type())); // This does not work too! set_inst_override_by_type ( .relative_inst_path("env.*"), .original_type(spi_mem_tr::get_type()), .override_type(spi_mem_tr_1::get_type())); // Even this does not work! // So looks like "inst" override by type does not work for tr objects in RAL // connecting agents? set_inst_override_by_type ( .relative_inst_path("*"), .original_type(spi_mem_tr::get_type()), .override_type(spi_mem_tr_1::get_type())); // Other the other hand, below works, BUT that overrides the tr in both SPI env objects // That is not what I want; I need to override using different types for the // two SPI env objects spi_mem_tr::type_id::set_type_override(spi_mem_tr_1::get_type()); Questions: Is it possible to do instance specific overrides over transaction class inside the SPI agent connecting to my RAL model? If so, what is the correct way to set the relative_inst_path? If not, are there any hacks to achieve the same? The fact that the global type override does work gives me some hope.
  10. As rustagi said, you can extend the uvm_report_server and have your own compose_message function. Here's what I do to have a filename without path and to customize other parts of the message too. class custom_report_server extends uvm_report_server; virtual function string compose_message ( uvm_severity severity, string name, string id, string message, string filename, int line ); // Declare function-internal vars string filename_nopath = ""; uvm_severity_type severity_type = uvm_severity_type'( severity ); begin // Extract just the file name, remove the preceeding path foreach(filename[i]) begin if (filename[i]=="/") filename_nopath = ""; else filename_nopath = {filename_nopath, filename[i]}; end // number of initial spaces in the second line // = 8 + 1(space) + 1(@) + 7 + 2("ns") + 3(spaces) + 2(indentation) = 24 return $psprintf( "%-8s @%7tns%3s\"%s\" >%s(%0d)\n%24s%s [%s]", severity_type.name(), $time/1000.00, " ", name, filename_nopath, line, " ", message, id ); end endfunction: compose_message endclass: custom_report_server I would then put this in the base test. It is up to you where you want the new server to be effective: before build, before run, etc. virtual function void build_phase(uvm_phase phase); // Set the custom report server to output the uvm_info messages in custom format custom_report_server my_server = new; uvm_report_server::set_server( my_server ); super.build_phase(phase); ...... endfunction
  • Create New...