1
\$\begingroup\$

In the following UVM testbench, I needed to make the sequence item, and hence the rest of the UVM components parametrized because the DUT is parametrized. I define 2 sequences: the base sequence 'MySeq' and a derived sequence 'MyConsecSubFrmSeq'. Also there is the base test class 'MyTest', and derived test class 'MyConsecSubFrmTest', in which I override the sequence class with MyConsecSubFrmSeq class.

Yet when running the testbench, setting UVM_TESTNAME to MyConsecSubFrmTest, I see that the sequence class isn't overridden, and the base sequence 'MySeq' is run instead. What is wrong here?

package MyTest;
import uvm_pkg::*;
`include "uvm_macros.svh"
class FrmCfg extends uvm_object;
  rand bit [6:0] ResBlks; // Number of resource blocks (NRB)
  rand bit [2:0] NumTXAnt; // Number of TX antennas at base station
  rand integer FFTSize; // FFT size
  function string convert2string();

    $sformat(convert2string, "FFT size: %0d", FFTSize);
  endfunction

  function new(string name="FrmCfg");
    super.new(name);
  endfunction

  `uvm_object_param_utils_begin(FrmCfg)
    `uvm_field_int(ResBlks, UVM_DEFAULT)
    `uvm_field_int(NumTXAnt, UVM_DEFAULT)
    `uvm_field_int(FFTSize, UVM_DEFAULT)
  `uvm_object_utils_end
endclass: FrmCfg

class MyTxn #(
  parameter IQSIZE=13, // I/Q size
  parameter RXANT_NUM=1 // Number of Rx antennas
) extends uvm_sequence_item;
  rand FrmCfg cfg;
  rand bit [3:0] SubFrmIdx;

  function string convert2string;
    $sformat(convert2string, "%s", cfg.convert2string());
    $sformat(convert2string, "%s idx=%0d", convert2string, SubFrmIdx);
  endfunction

  function new(string name="MyTxn");
    super.new(name);
    cfg = FrmCfg::type_id::create("cfg");
  endfunction

  task display;
    `uvm_info("FRM", convert2string, UVM_MEDIUM)
  endtask

  `uvm_object_param_utils_begin(MyTxn#(IQSIZE, RXANT_NUM))
    `uvm_field_object(cfg, UVM_DEFAULT)
    `uvm_field_int(SubFrmIdx, UVM_DEFAULT)
  `uvm_object_utils_end

endclass: MyTxn 

class MySeq #(
  parameter IQSIZE=13, // I/Q size
  parameter RXANT_NUM=1 // Number of Rx antennas
) extends uvm_sequence #(MyTxn#(IQSIZE, RXANT_NUM));
  `uvm_object_param_utils(MySeq#(IQSIZE, RXANT_NUM))
  rand bit [3:0] SubFrmIdx;
  rand FrmCfg cfg;
  constraint cons {
    SubFrmIdx < 10;
    cfg.FFTSize == 2048;
  }

  function new(string name="MySeq");
    super.new(name);
    cfg = FrmCfg::type_id::create("cfg");
  endfunction

  virtual function string convert2string;
    $sformat(convert2string, "idx=%0d", SubFrmIdx);
    $sformat(convert2string, "%s %s", convert2string, cfg.convert2string());
  endfunction

  task body();
    `uvm_info("REDMPSEQ", convert2string, UVM_MEDIUM)
    req = MyTxn#(IQSIZE, RXANT_NUM)::type_id::create("req");

    req.cfg.copy(cfg);
    req.cfg.rand_mode(0);

    `uvm_rand_send_with(req, {SubFrmIdx == local::SubFrmIdx;})

  endtask: body
endclass: MySeq

class MyConsecSubFrmSeq #(
  parameter IQSIZE=13, // I/Q size
  parameter RXANT_NUM=1 // Number of Rx antennas
) extends MySeq#(IQSIZE, RXANT_NUM);
  `uvm_object_param_utils(MyConsecSubFrmSeq#(IQSIZE, RXANT_NUM))
  randc integer unsigned SubFrmCnt;
  randc bit [3:0] StartSubFrmIdx;
  constraint conseq_cons {
    StartSubFrmIdx < 10;
  }

  function new(string name="MySeqConsecSubFrm");
    super.new(name);
  endfunction

  virtual function string convert2string;
    $sformat(convert2string, "%s", super.convert2string());
    $sformat(convert2string, "%s, start idx=%0d",convert2string, StartSubFrmIdx);
  endfunction

  task body();
    MySeq #(
      .IQSIZE(IQSIZE),
      .RXANT_NUM(RXANT_NUM)
    ) seq;
    `uvm_info("REDMP_CONSEC_SUBFRM_SEQ", convert2string, UVM_MEDIUM)
    seq = MySeq#(IQSIZE, RXANT_NUM)::type_id::create("subfrm_seq");
    seq.cfg.copy(cfg);
    seq.cfg.rand_mode(0);
    SubFrmIdx = StartSubFrmIdx;
    repeat(SubFrmCnt) begin
      SubFrmIdx++;
      SubFrmIdx%=10;
      `uvm_rand_send_with(seq, {SubFrmIdx == local::SubFrmIdx; })
    end
  endtask: body
endclass: MyConsecSubFrmSeq

class MyDrv #(
  parameter IQSIZE=13, // I/Q size
  parameter RXANT_NUM=1 // Number of Rx antennas
) extends uvm_driver#(MyTxn#(IQSIZE, RXANT_NUM));
  `uvm_component_param_utils(MyDrv#(IQSIZE, RXANT_NUM))

  function new(string name="MyDrv", uvm_component parent=null);
    super.new(name, parent);
  endfunction

  task run_phase(uvm_phase phase);
      seq_item_port.get_next_item(req);
      req.display;
      seq_item_port.item_done();
  endtask: run_phase
endclass: MyDrv

class MySqr #(
  parameter IQSIZE=13, // I/Q size
  parameter RXANT_NUM=1 // Number of Rx antennas
) extends uvm_sequencer #(MyTxn#(IQSIZE, RXANT_NUM));
  `uvm_component_param_utils(MySqr#(IQSIZE, RXANT_NUM))

  function new(string name="MySqr", uvm_component parent=null);
    super.new(name, parent);
  endfunction

endclass: MySqr

class MyAgent #(
  parameter IQSIZE=13, // I/Q size
  parameter RXANT_NUM=1 // Number of Rx antennas
) extends uvm_agent;
  `uvm_component_param_utils(MyAgent#(IQSIZE, RXANT_NUM))
  MySqr#(IQSIZE, RXANT_NUM) sqr;
  MyDrv#(
    .IQSIZE(IQSIZE),
    .RXANT_NUM(RXANT_NUM)
  ) drv;
  uvm_analysis_port #(MyTxn#(IQSIZE, RXANT_NUM)) dut_in_txn_port;
  uvm_analysis_port #(MyTxn#(IQSIZE, RXANT_NUM)) dut_out_txn_port;

  function new(string name="MyAgent", uvm_component parent=null);
    super.new(name, parent);
  endfunction

  function void build_phase(uvm_phase phase);
      sqr = MySqr#(IQSIZE, RXANT_NUM)::type_id::create("sqr", this);
      drv = MyDrv#(
              .IQSIZE(IQSIZE),
              .RXANT_NUM(RXANT_NUM)
            )::type_id::create("drv", this);
  endfunction: build_phase

  function void connect_phase(uvm_phase phase);
    if(get_is_active() == UVM_ACTIVE)
      drv.seq_item_port.connect(sqr.seq_item_export);
  endfunction: connect_phase

endclass: MyAgent

class MyEnv #(
  parameter IQSIZE=13, // I/Q size
  parameter RXANT_NUM=1 // Number of Rx antennas
) extends uvm_env;
  `uvm_component_param_utils(MyEnv#(IQSIZE, RXANT_NUM))
  MyAgent#(
    .IQSIZE(IQSIZE),
    .RXANT_NUM(RXANT_NUM)
  ) agent;

  function new(string name="MyEnv", uvm_component parent=null);
    super.new(name, parent);
  endfunction

  function void build_phase(uvm_phase phase);
    agent = MyAgent#(
               .IQSIZE(IQSIZE),
               .RXANT_NUM(RXANT_NUM)
             )::type_id::create("agent", this);
  endfunction: build_phase

endclass: MyEnv
class MyParamTest #(
  parameter IQSIZE=13, // I/Q size
  parameter RXANT_NUM=1 // Number of Rx antennas
) extends uvm_test;
  `uvm_component_param_utils(MyParamTest#(IQSIZE, RXANT_NUM))
  MyEnv#(
    .IQSIZE(IQSIZE),
    .RXANT_NUM(RXANT_NUM)
  ) env;

  function new(string name="MyParamTest", uvm_component parent=null);
    super.new(name, parent);
  endfunction

  function void build_phase(uvm_phase phase);
    env = MyEnv#(
            .IQSIZE(IQSIZE),
            .RXANT_NUM(RXANT_NUM)
          )::type_id::create("env", this);
  endfunction: build_phase

  task run_phase(uvm_phase phase);
    MySeq#(IQSIZE, RXANT_NUM) seq;
    phase.raise_objection(this);
    seq = MySeq#(IQSIZE, RXANT_NUM)::type_id::create("seq");
    seq.randomize();
    seq.start(env.agent.sqr);
    phase.drop_objection(this);
  endtask: run_phase
  function void end_of_elaboration_phase(uvm_phase phase);
    this.print();
    factory.print();
  endfunction: end_of_elaboration_phase

endclass: MyParamTest

class MyConsecSubFrmParamTest #(
  parameter IQSIZE=13, // I/Q size
  parameter RXANT_NUM=1 // Number of Rx antennas
) extends MyParamTest#(IQSIZE, RXANT_NUM);
  `uvm_component_param_utils(MyConsecSubFrmParamTest#(IQSIZE, RXANT_NUM))

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    uvm_resource_db #(bit) :: set ("", "FullFrame", 1);
  endfunction: build_phase

  function new(string name="MyConsecSubFrmParamTest", uvm_component parent=null);
    super.new(name, parent);
  endfunction

  virtual function void end_of_elaboration_phase(uvm_phase phase);
    set_inst_override_by_type ("seq",
                               MySeq#(IQSIZE, RXANT_NUM)::get_type(),
                               MyConsecSubFrmSeq#(IQSIZE, RXANT_NUM)::get_type());
    super.end_of_elaboration_phase(phase);

  endfunction: end_of_elaboration_phase

endclass: MyConsecSubFrmParamTest

endpackage: MyTest

module t;
  import MyTest::*;
import uvm_pkg::*;
`include "uvm_macros.svh"
  parameter IQSIZE = 13;
  parameter RXANT_NUM=1; // Number of Rx antennas

  reg Clk;
/*myDUT #(
  .IQSIZE(IQSIZE),
  .RXANT_NUM(RXANT_NUM)
) uDUT (
  // Clock & reset:
  .Clk(Clk),
  ....
*/

initial begin
  Clk <= 0;
  forever #(5) Clk = ~Clk;
end

`define UnParamClass(UnParamClassName, ParamClassName, IQSizeVal, RXAntVal) \
class UnParamClassName extends ParamClassName#(IQSizeVal, RXAntVal); \
  `uvm_component_utils(UnParamClassName) \
  function new(string name="UnParamClassName", uvm_component parent=null); \
    super.new(name, parent); \
  endfunction \
endclass: UnParamClassName
`UnParamClass(MyTest, MyParamTest, IQSIZE, RXANT_NUM)
`UnParamClass(MyConsecSubFrmTest, MyConsecSubFrmParamTest, IQSIZE, RXANT_NUM)

initial begin
  run_test();
end
endmodule: t
# vsim -c "+UVM_TESTNAME=MyConsecSubFrmTest" t
# UVM_INFO verilog_src/questa_uvm_pkg-1.2/src/questa_uvm_pkg.sv(215) @ 0: reporter [Questa UVM] QUESTA_UVM-1.2.3
# UVM_INFO verilog_src/questa_uvm_pkg-1.2/src/questa_uvm_pkg.sv(216) @ 0: reporter [Questa UVM]  questa_uvm::init(+struct)
# UVM_INFO @ 0: reporter [RNTST] Running test MyConsecSubFrmTest...
# --------------------------------------------------------------
# Name                       Type                    Size  Value
# --------------------------------------------------------------
# uvm_test_top               MyConsecSubFrmTest      -     @466 
#   env                      uvm_env                 -     @473 
#     agent                  uvm_agent               -     @483 
#       drv                  uvm_driver #(REQ,RSP)   -     @599 
#         rsp_port           uvm_analysis_port       -     @614 
#         seq_item_port      uvm_seq_item_pull_port  -     @606 
#       sqr                  uvm_sequencer           -     @490 
#         rsp_export         uvm_analysis_export     -     @497 
#         seq_item_export    uvm_seq_item_pull_imp   -     @591 
#         arbitration_queue  array                   0     -    
#         lock_queue         array                   0     -    
#         num_last_reqs      integral                32    'd1  
#         num_last_rsps      integral                32    'd1  
# --------------------------------------------------------------
# 
#### Factory Configuration (*)
# 
# Instance Overrides:
# 
#   Requested Type  Override Path     Override Type
#   --------------  ----------------  -------------
#   <unknown>       uvm_test_top.seq  <unknown>
# 
# No type overrides are registered with this factory
# 
# All types registered with the factory: 50 total
# (types without type names will not be printed)
# 
#   Type Name
#   ---------
#   MyConsecSubFrmTest
#   MyTest
#   questa_uvm_recorder
# (*) Types with no associated type name will be printed as <unknown>
# 
####
# 
# UVM_INFO t.sv(76) @ 0: uvm_test_top.env.agent.sqr@@seq [REDMPSEQ] idx=2 FFT size: 2048
# UVM_INFO t.sv(43) @ 0: uvm_test_top.env.agent.sqr@@seq.req [FRM] FFT size: 2048 idx=2
# UVM_INFO verilog_src/uvm-1.1d/src/base/uvm_objection.svh(1267) @ 0: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase
# 
# --- UVM Report Summary ---
# 
# ** Report counts by severity
# UVM_INFO :    6
# UVM_WARNING :    0
# UVM_ERROR :    0
# UVM_FATAL :    0
# ** Report counts by id
# [FRM]     1
# [Questa UVM]     2
# [REDMPSEQ]     1
# [RNTST]     1
# [TEST_DONE]     1

I tried changing the override to:

set_inst_override_by_type({get_fullname(),".seq"}
                           MySeq#(IQSIZE, RXANT_NUM)::get_type(),
                           MyConsecSubFrmSeq#(IQSIZE, RXANT_NUM)::get_type());

which as far as I understand, is functionally equivalent to the original code, yet I got this in the simulation log:

# Instance Overrides: 
#   Requested Type  Override Path     Override Type
#   --------------  ----------------  -------------
#   <unknown>       uvm_top_seq.uvm_test_top.seq  <unknown>
# 
\$\endgroup\$

3 Answers 3

1
\$\begingroup\$

I believe set_inst_override_by_type should be used with components (that have known paths in the hierarchy), while with the objects, set_type_override_by_type is used instead.

But for your specific scenario, I think a known workaround could help, by adding a second argument in the creation of the seq object in MyParamTest::run_phase():

seq = MySeq#(IQSIZE, RXANT_NUM)::type_id::create("seq",this);
\$\endgroup\$
2
  • \$\begingroup\$ جزاك الله خيراً. That worked. Could you explain the rationale behind this workaround please ? \$\endgroup\$ Commented Jul 10, 2023 at 3:10
  • \$\begingroup\$ جزانا وإياكم The workaround just set parent this to the created seq instance, to let it have specific hierarchy path (uvm_root in your case) so set_inst_override_by_type can be used with it. \$\endgroup\$ Commented Jul 10, 2023 at 8:27
1
\$\begingroup\$

When I use set_type_override_by_type instead of set_inst_override_by_type in MyConsecSubFrmParamTest, I see evidence of the extended sequence being used in the log:

set_type_override_by_type(
                           MySeq#(IQSIZE, RXANT_NUM)::get_type(),
                           MyConsecSubFrmSeq#(IQSIZE, RXANT_NUM)::get_type());

The log shows the UVM_INFO message from MyConsecSubFrmSeq ([REDMP_CONSEC_SUBFRM_SEQ]):

UVM_INFO tb.sv(111) @ 0: uvm_test_top.env.agent.sqr@@seq 
    [REDMP_CONSEC_SUBFRM_SEQ] idx=3 FFT size: 2048, start idx=0

I am not sure why set_inst_override_by_type is not working; perhaps the relative_inst_path string is not set to the correct value.

\$\endgroup\$
3
  • \$\begingroup\$ Thanks, but that doesn't help, as it causes all instances of MySeq (even the ones used in MyConsecSubFrmSeq) to be overridden by MyConsecSubFrmSeq \$\endgroup\$ Commented Jul 4, 2023 at 23:40
  • \$\begingroup\$ I added info in the main question regarding the path hint, since I am not able to put code in the comments. \$\endgroup\$ Commented Jul 6, 2023 at 1:08
  • \$\begingroup\$ I understand that this is not what you suggested, but this experiment (which is supposed to be functionally equivalent to my original code) shows that there is some sort of discrepancy. \$\endgroup\$ Commented Jul 8, 2023 at 0:33
0
\$\begingroup\$

It seems that the issue lies in the way you are attempting to override the sequence class in the MyConsecSubFrmParamTest test class. Instead of using the set_inst_override_by_type method, you should use the set_type_override method to override the sequence class.

Here's the modified code snippet that should resolve the issue:

class MyConsecSubFrmParamTest #(
  parameter IQSIZE=13, // I/Q size
  parameter RXANT_NUM=1 // Number of Rx antennas
) extends MyParamTest#(IQSIZE, RXANT_NUM);
  `uvm_component_param_utils(MyConsecSubFrmParamTest#(IQSIZE, RXANT_NUM))

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    uvm_resource_db #(bit)::set("", "FullFrame", 1);
  endfunction: build_phase

  function new(string name="MyConsecSubFrmParamTest", uvm_component parent=null);
    super.new(name, parent);
  endfunction

  virtual function void end_of_elaboration_phase(uvm_phase phase);
    set_type_override_by_type(MySeq#(IQSIZE, RXANT_NUM)::get_type(),
                              MyConsecSubFrmSeq#(IQSIZE, RXANT_NUM)::get_type());
    super.end_of_elaboration_phase(phase);
  endfunction: end_of_elaboration_phase
endclass: MyConsecSubFrmParamTest

With this modification, the MyConsecSubFrmSeq sequence class should be correctly overridden in the MyConsecSubFrmParamTest test class, and it will be used instead of the base MySeq sequence class when running the test.

\$\endgroup\$
1
  • \$\begingroup\$ Please see the comment I've made on @toolic's answer \$\endgroup\$ Commented Jul 10, 2023 at 1:23

Not the answer you're looking for? Browse other questions tagged or ask your own question.