Vsim-3978: Illegal assignment to class: Why is my override parameter not fully applied in my derived class?

I’m trying to make an extended uvm_sequence class that auto-encapsulates a uvm_sequence_item so it can be forwarded to a sequencer. My aim is to forward predicted transactions from a scoreboard to a sequencer, thereby performing module emulation.

Here is the wrapper definition along with some proprietary class extensions:

virtual class k_sequence_item extends uvm_sequence_item;
   ...
endclass

virtual class k_sequencer #(type SEQ=k_sequence_item) extends uvm_sequencer #(SEQ);
   `uvm_component_utils(k_sequencer)
   ...
endclass

virtual class k_sequence_wrapper #(type SEQ=k_sequence_item) extends uvm_sequence #(SEQ);
   `uvm_object_utils(k_sequence_wrapper)

   SEQ seq;

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

   virtual function void set_sequence(SEQ seq);
      this.seq = seq;
   endfunction

   virtual task body;
      start_item(seq);
      finish_item(seq);
   endtask
endclass

Here is the comparator definition. Predicted transactions come in on refport.

virtual class k_comparator #(type SEQ=k_sequence_item) extends uvm_component;
   `uvm_component_utils(k_comparator)

   k_sequencer        #(SEQ) sqr;
   k_sequence_wrapper #(SEQ) wpr;

   uvm_analysis_export   #(SEQ) refport;
   uvm_tlm_analysis_fifo #(SEQ) expfifo;
   /* ... */

   function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      /* ... */

      refport = new("refport", this);
      expfifo = new("expfifo", this);
      /* ... */
   endfunction

   /* ... */

   function void connect_phase(uvm_phase phase);
      super.connect_phase(phase);
      refport.connect(expfifo.analysis_export);
      /* ... */
   endfunction

   /* ... */

   task run_phase(uvm_phase phase);
      /* ... */
      //
      // If we have a DUT, compare the observed transaction to the predicted
      // one.
      //
      if (sqr == null) fork
         /* ... */
      join_none else
      //
      // If we don't have a DUT, forward the expected transaction to the
      // sequencer and use the agent as an emulator.
      //
      fork
         forever begin
            expfifo.get(exp_txn);
            /* ... */
/* >>> */   wpr = k_sequence_wrapper#(SEQ)::type_id::create("wpr", this);
            wpr.set_sequence(exp_txn);
            wpr.start(sqr);
         end
         /* ... */
      join_none

      /* ... */
   endtask
endclass

With that set up, I extend this comparator class:

class transceiver_cmp extends k_comparator #(transceiver_pkt);
   `uvm_component_utils(transceiver_cmp)

   function new(string name, uvm_component parent);
      super.new(name, parent);
   endfunction
endclass

The problem line is k_sequence_wrapper…create. When I try to load this package into Questasim, I get the following error:

** Error: (vsim-3978) ...: Illegal assignment to class base.test_pkg::k_sequence_wrapper #(class base.test_pkg::transceiver_pkt) from class base.test_pkg::k_sequence_wrapper #(class base.test_pkg::k_sequence_item)

Note how the assignee variable wpr has been overridden as expected with the transceiver_pkt type, but the create call still has the type k_sequence_item from the base class. How do I correct this so the variable assignment works?

Your problem is you are not using the correct factory registration macros.
Use `uvm_component_param_utils(k_sequencer#(SEQ)) and similar *_param_utils macros for the other parametrized classes.

You should have gotten a warning similar to

** at file.sv(5): (vlog-2181) Use of a parameterized class k_sequencer as a type creates a default specialization.

That is a clue that you had referenced a parameterized class without a parameter list.

In reply to dave_59:

That fixed the problem. I’d disabled vlog-2181 to keep it from reporting on other class extensions that were intentionally written to fall back on default parameters. To be safe, I’ll reactivate this warning and use explicit parameters on all derived class declarations, even if they use defaults from the parent class.

Thanks for your help.

In reply to tonyle:

Two things that may also help

  • You can use an empty list #() to say that you want all the default parameter settings.
  • You do not always need to provide a default.
class k_sequencer #(type SEQ)

forces you to always provide an explicit override.