Wednesday, July 26, 2023

An use case of UVM verification environment universal template 2.0

 System Verilog RTL verification

An use case of UVM verification environment universal template 2.0

UVM verification environment universal template 2.0 used in building verification of a DUT that features a handshake-controlled input and output data transfers


Introduction

In this blog post  I would like to show a use case of  UVM verification environment universal template 2.0 ( as described in one of the previous blog posts: https://asicstoic.blogspot.com/2023/07/uvm-verification-environment-universal.html)  on a DUT verified using non UVM verification environment described  also in one of the previous blog posts: https://asicstoic.blogspot.com/2023/07/uvm-like-non-uvm-verification.html

The goal of this blog post is to show how seamlessly the non UVM verification environment , especially its driver, monitor and scoreboard part can be transferred to the UVM verification environment using the UVM verification environment universal template 2.0.    


UVM verification environment  architecture



For UVM verification  of any DUT what  we need to think about is an architecture so our architecture will contain files organized in a  System Verilog UVM hierarchy as described in the previously shown  block diagram.


  • top testbench module :  testbench.sv

    • Design file 

      • DUT.sv 

    • UVM verification infrastructure files

      • Interface.sv ( SystemVerilog interface of the DUT ) 

      • UVM verification classes ( one class per/ UVM block in previously presented block diagram) :

        • test class (COMPONENT class, test.sv)

          • environment class (COMPONENT class, env.sv) 

          • scoreboard  class (COMPONENT class, scoreboard.sv)

          • agent class ( COMPONENT class, agent.sv)  

            • driver (COMPONENT class, driver.sv) 

            • monitor (COMPONENT class, monitor.sv)  

            • sequencer (COMPONENT class, sequencer.sv) 

        • sequence/sequence item ( wo OBJECT classes in one file:  sequence.sv)

DUT input and output data exchange controls using handshake interfaces is based on Producer/Consumer exchange of data. The same DUT and the handshake mechanism were already  described in one of the previous blog posts:  https://asicstoic.blogspot.com/2023/06/verilog-rtl-verification-cocotb-based.html


DUT


module SimpleDUT_hs (
    input CLK,
    input RST_N,

    input        en_din_i,
    output logic rdy_din_o,
    input [3:0]  din_i,

    input             en_dout_i,
    output logic      rdy_dout_o,
    output logic[3:0] dout_o
);

// Define the states using localparam
  localparam START_ST = 1'b0;
  localparam WR_ST    = 1'b1;

  logic next_rdy_dout;

  logic[3:0] next_dout ;

  logic state, next_state ;


  always @(posedge CLK or negedge RST_N) begin
      if (!RST_N) begin
        state      <= START_ST;
        rdy_dout_o <= 1'b0    ;
        dout_o     <= 4'd0    ;
      end else begin
        state      <= next_state     ;
        rdy_dout_o <= next_rdy_dout   ;
        dout_o     <= next_dout      ;
      end
    end


    always @(*) begin
      next_state    = state ;
      next_rdy_dout = rdy_dout_o;
      next_dout     = dout_o;

      rdy_din_o     = 1'b0;
      case(state)
////////////////////////////
        START_ST: begin
          if(en_din_i) begin
            next_dout     = din_i;
            rdy_din_o     = 1'b1;

            next_rdy_dout = 1'b1;

            next_state = WR_ST;
          end
        end

///////////////////////////
        WR_ST: begin
          case({en_din_i, en_dout_i})
            2'b00, 2'b10:
              next_state    = state ;
            2'b01: begin
              next_rdy_dout = 1'b0;
              next_state = START_ST;
            end
            2'b11: begin
              next_dout     = din_i;
              rdy_din_o     = 1'b1;
            end
          endcase

        end
      endcase
    end

endmodule



Interface

The name of the file is: interface.sv .

interface intf(input logic CLK);

  //declaring the signals
  logic        RST_N;
  logic        en_din_i;
  logic       rdy_din_o;
  logic [3:0]  din_i;

  logic        en_dout_i;
  logic       rdy_dout_o;
  logic [3:0] dout_o ;

  // misc. used in driver and present here for
  // waveform observation purposes
  integer counter, state;


endinterface


Sequence item ( or transaction ) class  template 2.0 

The first step in verifying a RTL design is defining what kind of data should be sent to the DUT.

The concept of transaction means the smallest data transfers that can be executed in a verification model.    

//Object class
class SimpleDUT_sequence_item extends uvm_sequence_item;
  `uvm_object_utils(SimpleDUT_sequence_item)

  //--------------------------------------------------------
  //Instantiation
  //--------------------------------------------------------
  // e.g.
  // rand logic reset;
  // rand logic [3:0] din_i;
  // logic [3:0] dout_o;

  //--------------------------------------------------------
  //Default Constraints
  //--------------------------------------------------------
  // e.g.
  // constraint input1_c { din_i inside {[0:15]};}


  //--------------------------------------------------------
  //Constructor
  //--------------------------------------------------------
  function new(string name = "SimpleDUT_sequence_item");
    super.new(name);

  endfunction: new

endclass: SimpleDUT_sequence_item



Sequence item ( or transaction ) class: a final solution 

class SimpleDUT_hs_sequence_item extends uvm_sequence_item;
  `uvm_object_utils(SimpleDUT_hs_sequence_item)

//1.change in relation to the correspondent 2.0 template:  1 Instantiation logic/wires/registers same as used in interface go here again and it is again straight copy from interface
// Again we are going to use this to generate random values about DUT input port values on one hand and to store the output results on the other hand. This time we are going to store the values of all handshake signals too.

  //--------------------------------------------------------
  //Instantiation
  //--------------------------------------------------------
  rand logic [3:0] din_i;
  logic [3:0] dout_o;
  rand logic  RST_N; 

  logic en_din_i; 
  logic rdy_din_o;


  logic en_dout_i;
  logic rdy_dout_o;

  //--------------------------------------------------------
  //Default Constraints
  //--------------------------------------------------------
  // 2.change in relation to the correspondent 2.0 template:
  // adding DUT function appropriate constraints of randomized input port values
  constraint input1_c { din_i inside {[0:15]};}
  constraint input2   { RST_N     inside {[0:1]};}
  //--------------------------------------------------------
  //Constructor
  //--------------------------------------------------------
  function new(string name = "SimpleDUT_hs_sequence_item");
    super.new(name);

  endfunction: new
  // 3.change in relation to the correspondent 2.0 template: adding a display method to transaction for capturing in log file generated/used transaction signals
  //  Adding display() method to display Transaction properties.
  function void display(string name);
    $display("-------------------------");
    $display("- %s ",name);
    $display("-------------------------");
    $display("- en_din_i  = %0d, rdy_din_o  = %0d, din_i  = %0d", en_din_i, rdy_din_o,  din_i );
    $display("- en_dout_i = %0d, rdy_dout_o = %0d, dout_o = %0d", en_dout_i,rdy_dout_o, dout_o);
    $display("-------------------------");
  endfunction

endclass: SimpleDUT_hs_sequence_item


Sequence class template 2.0 same as a final solution ( an OBJECT class, file: sequence.sv )

Now that we have a transaction, the next step is to create a sequence.

After a basic transaction has been specified, the verification environment will need to generate a collection of them and get them ready for  sending to the driver. This is a job for the sequence. Sequence is an ordered collection of transactions. Also the sequence shapes transactions to our needs and generates as many transactions as needed. 

class SimpleDUT_hs_base_sequence extends uvm_sequence;
  `uvm_object_utils(SimpleDUT_hs_base_sequence)
   
  SimpleDUT_hs_sequence_item reset_pkt;
 

  //--------------------------------------------------------
  //Constructor
  //--------------------------------------------------------
  function new(string name= "SimpleDUT_hs_base_sequence");
    super.new(name);
    `uvm_info("BASE_SEQ", "Inside Constructor!", UVM_HIGH)
  endfunction

  //--------------------------------------------------------
  //Body Task
  //--------------------------------------------------------
  task body();
    `uvm_info("BASE_SEQ", "Inside body task!", UVM_HIGH)
 
    reset_pkt = SimpleDUT_hs_sequence_item::type_id::create("reset_pkt");
     
    start_item(reset_pkt);
    reset_pkt.randomize() with {RST_N==0;};
     
    finish_item(reset_pkt); 
       
  endtask: body
 
endclass: SimpleDUT_hs_base_sequence


class SimpleDUT_hs_test_sequence extends SimpleDUT_hs_base_sequence;
  `uvm_object_utils(SimpleDUT_hs_test_sequence)
   
  SimpleDUT_hs_sequence_item item;
  

  //--------------------------------------------------------
  //Constructor
  //--------------------------------------------------------
  function new(string name= "SimpleDUT_test_sequence");
    super.new(name);
    `uvm_info("TEST_SEQ", "Inside Constructor!", UVM_HIGH)
  endfunction
 
 
  //--------------------------------------------------------
  //Body Task
  //--------------------------------------------------------
  task body();
    `uvm_info("TEST_SEQ", "Inside body task!", UVM_HIGH)
   
    item = SimpleDUT_hs_sequence_item::type_id::create("item");
   
    start_item(item);
    item.randomize() with {RST_N==1;};
    finish_item(item);
   
  endtask: body
 
  endclass: SimpleDUT_hs_test_sequence


Sequencer class  template 2.0 same as a final solution ( once more a Component class and file name is sequencer.sv )

The sequencer is  responsible for sending the sequences to the driver.


The easiest way to include the sequencer in UVM testbench/infrastructure template is: 


typedef uvm_sequencer#(SimpleDUT_hs_sequence_item) SimpleDUT_hs_sequencer;


  

Note*: In the sequencer we don't need the “run” phase


class SimpleDUT_hs_sequencer extends uvm_sequencer#(SimpleDUT_hs_sequence_item);
  `uvm_component_utils(SimpleDUT_hs_sequencer)

 
  //--------------------------------------------------------
  //Constructor
  //--------------------------------------------------------
  function new(string name = "SimpleDUT_hs_sequencer", uvm_component parent);
    super.new(name, parent);
    `uvm_info("SEQUENCER_CLASS", "Inside Constructor!", UVM_HIGH)

  endfunction: new


  //--------------------------------------------------------
  //Build Phase
  //--------------------------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    `uvm_info("SEQUENCER_CLASS", "Build Phase!", UVM_HIGH)

endfunction: build_phase


  //--------------------------------------------------------
  //Connect Phase
  //--------------------------------------------------------
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    `uvm_info("SEQUENCER_CLASS", "Connect Phase!", UVM_HIGH)

  endfunction: connect_phase

  endclass:     SimpleDUT_hs_sequencer


Driver class  template 2.0 ( one more Component class: file driver.sv )

The driver is a block whose role is to interact with the DUT. The driver pulls transactions from the sequencer and sends them repetitively to the signal-level interface.

The driver’s functionality should only be limited to send the necessary data to the DUT.


class SimpleDUT_driver extends uvm_driver#(SimpleDUT_sequence_item);
  `uvm_component_utils(SimpleDUT_driver)

  virtual SimpleDUT_interface vif;

  SimpleDUT_sequence_item item;

  //--------------------------------------------------------
  //Constructor
  //--------------------------------------------------------
  function new(string name = "SimpleDUT_driver", uvm_component parent);
    super.new(name, parent);
    `uvm_info("DRIVER_CLASS", "Inside Constructor!", UVM_HIGH)

  endfunction: new


  //--------------------------------------------------------
  //Build Phase
  //--------------------------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    `uvm_info("DRIVER_CLASS", "Build Phase!", UVM_HIGH)

if(!(uvm_config_db #(virtual SimpleDUT_interface)::get(this, "*", "vif", vif))) begin
      `uvm_error("DRIVER_CLASS", "Failed to get VIF from config DB!")
end

endfunction: build_phase


  //--------------------------------------------------------
  //Connect Phase
  //--------------------------------------------------------
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    `uvm_info("DRIVER_CLASS", "Connect Phase!", UVM_HIGH)

  endfunction: connect_phase


  //--------------------------------------------------------
  //Run Phase
  //--------------------------------------------------------
  task run_phase (uvm_phase phase);
    super.run_phase(phase);
    `uvm_info("DRIVER_CLASS", "Run Phase!", UVM_HIGH)

// Logic
   
      drive();

    endtask: run_phase

  //--------------------------------------------------------
  //[Method] Drive
  //--------------------------------------------------------
  task drive();
    // e.g. for our "dummy" DUT
    // forever begin

    // Create "item"
    // item = SimpleDUT_sequence_item::type_id::create("item");
    // seq_item_port.get_next_item(item);

    // @(posedge vif.clock);
    // vif.reset <= item.reset;
    // vif.din_i <= item.din_i;

    // seq_item_port.item_done();

    // end
  endtask: drive


endclass: SimpleDUT_driver


Driver class  template final solution ( file driver.sv )

class SimpleDUT_hs_driver extends uvm_driver#(SimpleDUT_hs_sequence_item);
  `uvm_component_utils(SimpleDUT_hs_driver)
virtual SimpleDUT_hs_interface vif;

  SimpleDUT_hs_sequence_item item;
  //--------------------------------------------------------
  //Constructor
  //--------------------------------------------------------
  function new(string name = "SimpleDUT_hs_driver", uvm_component parent);
    super.new(name, parent);
    `uvm_info("DRIVER_CLASS", "Inside Constructor!", UVM_HIGH)

  endfunction: new


  //--------------------------------------------------------
  //Build Phase
  //--------------------------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    `uvm_info("DRIVER_CLASS", "Build Phase!", UVM_HIGH)

if(!(uvm_config_db #(virtual SimpleDUT_hs_interface)::get(this, "*", "vif", vif))) begin
      `uvm_error("DRIVER_CLASS", "Failed to get VIF from config DB!")
end

endfunction: build_phase


  //--------------------------------------------------------
  //Connect Phase
  //--------------------------------------------------------
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    `uvm_info("DRIVER_CLASS", "Connect Phase!", UVM_HIGH)

  endfunction: connect_phase


  //--------------------------------------------------------
  //Run Phase
  //--------------------------------------------------------
  task run_phase (uvm_phase phase);
    super.run_phase(phase);
    `uvm_info("DRIVER_CLASS", "Run Phase!", UVM_HIGH)
   
   
    drive();
 
endtask: run_phase

  //--------------------------------------------------------
  //[Method] Drive
  //--------------------------------------------------------
  // 1. Change in relation to the corresponding template
  virtual task drive();
    SimpleDUT_hs_sequence_item item;
 
   
    integer j, i;
    integer num_iterations  = $urandom_range(1, 21);
    integer num_iterations2 = $urandom_range(1, 21);
     
  begin
      vif.en_din_i    = 0;
      vif.en_dout_i   = 0;

      vif.counter = 0;
      vif.state   = 0;
     
  forever begin
// Handshake control inputs reset: if there is still  output data not consumed new data is not "produced" because DUT depth of the data pipeline is 1. If there is no output data to be "consumed" both output handshake control data ports are 0    
    if(vif.rdy_dout_o)
      vif.en_din_i  = 1'b0;
    else
      vif.en_dout_i = 1'b0;
// if "counter flag is 0: pick up new transaction data, and apply its
// reset to DUT interface   
    if(vif.counter==0)
begin
  item = SimpleDUT_hs_sequence_item::type_id::create("item");
        seq_item_port.get_next_item(item);
        vif.RST_N <= item.RST_N;
end
// new transaction data is available and its reset par is applied to DUT
// now wait for one clock cycle ....   
    @(negedge vif.CLK);

// if reset is applied to DUT, do nothing just go back
// and pick up a new transaction data    
    if(!item.RST_N ) begin
      vif.en_dout_i = 0;
      vif.en_din_i  = 0;
     
      seq_item_port.item_done();
    End

     
    if(vif.counter==0 && item.RST_N ) begin
// DUT is not under reset so here there is a start of driving the current transaction to DUT interface
          vif.en_dout_i = 0;
          vif.en_din_i  = 0;
// after a random number of clock cycles ( in the range of 1 to 20)
// "produce" input data to DUT      
          num_iterations  = $urandom_range(1, 21);
          for (j = 0; j < num_iterations; j++) begin
            @(negedge vif.CLK);
          end
          @(posedge vif.CLK);
          vif.din_i     = item.din_i;
          vif.en_din_i  = 1;
     
         
          vif.state = 1;
      end
   
        case(vif.state)
          1: begin
            vif.counter = vif.counter + 1;
      if(vif.counter==2) vif.state = 2;
          end
       
          2: begin           
            if(vif.rdy_dout_o) begin
// here DUT output data is ready to  be "consumed"
// so after a random number of clock cycles ( in the range of 1 to 20)
// the DUT output data is indeed "consumed"
              vif.en_din_i  = 1'b0;
              num_iterations2 = $urandom_range(1, 21);
              for (i = 0; i < num_iterations2; i++) begin
                @(negedge vif.CLK);
              end
              vif.en_dout_i = 1;
             
              vif.counter = vif.counter + 1;
              if(vif.counter==3) vif.state = 3;
            end else begin
              vif.en_dout_i = 0 ;
            end
           
          end
         
          3: begin

            if(vif.rdy_dout_o)
              vif.en_din_i  = 1'b0;
            else begin
// After the DUT data is "consumed" pick - up next transaction data
// and repeat the whole process again.
              vif.en_dout_i = 1'b0;
              vif.counter = 0;
        vif.state = 0;
              seq_item_port.item_done();
            end
          end
         
        endcase
  end 
     
end
   
endtask: drive

endclass: SimpleDUT_hs_driver


Monitor class  template 2.0

The monitor is a self-contained model that observes the communication of the DUT with the testbench. At most, it should observe the outputs of the design and, in case of not respecting the protocol’s rules, the monitor must return an error. The monitor is a passive component, it doesn’t drive any signals into the DUT.



class SimpleDUT_monitor extends uvm_monitor;
  `uvm_component_utils(SimpleDUT_monitor)

  virtual SimpleDUT_interface vif;

  SimpleDUT_sequence_item item;

  uvm_analysis_port #(SimpleDUT_sequence_item) monitor_port;

  //--------------------------------------------------------
  //Constructor
  //--------------------------------------------------------
  function new(string name = "SimpleDUT_monitor", uvm_component parent);
    super.new(name, parent);
    `uvm_info("MONITOR_CLASS", "Inside Constructor!", UVM_HIGH)
 
  endfunction: new


  //--------------------------------------------------------
  //Build Phase
  //--------------------------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    `uvm_info("MONITOR_CLASS", "Build Phase!", UVM_HIGH)

  if(!(uvm_config_db #(virtual SimpleDUT_interface)::get(this, "*", "vif", vif))) begin
      `uvm_error("MONITOR_CLASS", "Failed to get VIF from config DB!")
end
  monitor_port = new("monitor_port", this);

endfunction: build_phase


  //--------------------------------------------------------
  //Connect Phase
  //--------------------------------------------------------
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    `uvm_info("MONITOR_CLASS", "Connect Phase!", UVM_HIGH)
 
  endfunction: connect_phase


  //--------------------------------------------------------
  //Run Phase
  //--------------------------------------------------------
  task run_phase (uvm_phase phase);
    super.run_phase(phase);
    `uvm_info("MONITOR_CLASS", "Run Phase!", UVM_HIGH)
    forever begin
      item = SimpleDUT_sequence_item::type_id::create("item");
    // e.g. monitoring logic for our dummy DUT
    //  wait(!vif.reset);
   
    //sample inputs
    //   @(posedge vif.clock);
    //   item.din_i = vif.din_i;
    //sample output
    //   item.dout_o = vif.dout_o;
    //  @(posedge vif.clock);

      monitor_port.write(item);
    end

  endtask: run_phase

endclass: SimpleDUT_monitor


Monitor class  final solution (file monitor.sv)

class SimpleDUT_hs_monitor extends uvm_monitor;
  `uvm_component_utils(SimpleDUT_hs_monitor)

  virtual SimpleDUT_hs_interface vif;

  SimpleDUT_hs_sequence_item item;

uvm_analysis_port #(SimpleDUT_hs_sequence_item) monitor_port;

// 1. change : creating mailbox handle
    mailbox mon2scb; 
  //--------------------------------------------------------
  //Constructor
  //--------------------------------------------------------
  function new(string name = "SimpleDUT_hs_monitor", uvm_component parent);
    super.new(name, parent);
    `uvm_info("MONITOR_CLASS", "Inside Constructor!", UVM_HIGH)

// 2. change: getting the mailbox handles from  environment
        this.mon2scb = mon2scb;

  endfunction: new


  //--------------------------------------------------------
  //Build Phase
  //--------------------------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    `uvm_info("MONITOR_CLASS", "Build Phase!", UVM_HIGH)

  if(!(uvm_config_db #(virtual SimpleDUT_hs_interface)::get(this, "*", "vif", vif))) begin
    `uvm_error("MONITOR_CLASS", "Failed to get VIF from config DB!")
end

    monitor_port = new("monitor_port", this);

endfunction: build_phase


  //--------------------------------------------------------
  //Connect Phase
  //--------------------------------------------------------
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    `uvm_info("MONITOR_CLASS", "Connect Phase!", UVM_HIGH)

  endfunction: connect_phase


  //--------------------------------------------------------
  //Run Phase
  //--------------------------------------------------------
  task run_phase (uvm_phase phase);
    super.run_phase(phase);
    `uvm_info("MONITOR_CLASS", "Run Phase!", UVM_HIGH)
  // Logic
  // 3. change to the corresponding template: monitoring will take place only
  // if DUT is not under reset
    wait(!vif.RST_N);
    wait(vif.RST_N);

forever begin
      item = SimpleDUT_hs_sequence_item::type_id::create("item");

// 4. change to the corresponding template       
      @(negedge vif.CLK);
        fork
          begin
// pick-up DUT input "produced" data at appropriate handshake control time
            wait(vif.rdy_dout_o && vif.en_dout_i );
            item.dout_o = vif.dout_o;
          end
         
          begin
// pick-up DUT output "consumed" data at appropriate handshake control time
            wait(vif.en_din_i && vif.rdy_din_o );
            item.din_i = vif.din_i;
          end
      join     
      @( negedge vif.CLK);
// DUT input data and a corresponding output data are passed to scoreboard
// for verification self-checking
      monitor_port.write(item);
    end

  endtask: run_phase

endclass: SimpleDUT_hs_monitor





Scoreboard template 

class SimpleDUT_scoreboard extends uvm_test;
  `uvm_component_utils(SimpleDUT_scoreboard)
   

   uvm_analysis_imp #(SimpleDUT_sequence_item, SimpleDUT_scoreboard) scoreboard_port;

  SimpleDUT_sequence_item transactions[$];

  //--------------------------------------------------------
  //Constructor
  //--------------------------------------------------------
  function new(string name = "SimpleDUT_scoreboard", uvm_component parent);
    super.new(name, parent);
    `uvm_info("SCB_CLASS", "Inside Constructor!", UVM_HIGH)

  endfunction: new


  //--------------------------------------------------------
  //Build Phase
  //--------------------------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    `uvm_info("SCB_CLASS", "Build Phase!", UVM_HIGH)

    scoreboard_port = new("scoreboard_port", this); 
endfunction: build_phase


  //--------------------------------------------------------
  //Connect Phase
  //--------------------------------------------------------
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    `uvm_info("SCB_CLASS", "Connect Phase!", UVM_HIGH)

  endfunction: connect_phase

 


  //--------------------------------------------------------
  //Write Method
  //--------------------------------------------------------
  function void write(SimpleDUT_sequence_item item);

    transactions.push_back(item);
  

  endfunction: write

  //--------------------------------------------------------
  //Run Phase
  //--------------------------------------------------------
  task run_phase (uvm_phase phase);
    super.run_phase(phase);
    `uvm_info("SCB_CLASS", "Run Phase!", UVM_HIGH)

    forever begin
      /*
      // get the packet
      // generate expected value
      // compare it with actual value
      // score the transactions accordingly
      */
      SimpleDUT_sequence_item curr_trans;

      wait((transactions.size() != 0));

      curr_trans = transactions.pop_front();

      compare(curr_trans);
   
    end

  endtask: run_phase

  //--------------------------------------------------------
  //Compare : Generate Expected Result and Compare with Actual
  //--------------------------------------------------------
  task compare(SimpleDUT_sequence_item curr_trans);
    logic [3:0] expected;
    logic [3:0] actual;
 
  expected = curr_trans.din_i;
  actual   = curr_trans.dout_o;
 
  if(actual != expected) begin
      `uvm_error("COMPARE", $sformatf("Transaction failed! ACT=%d, EXP=%d", actual, expected))end else begin
      `uvm_info("COMPARE", $sformatf("Transaction Passed! ACT=%d, EXP=%d", actual, expected), UVM_LOW)
  end
 
endtask: compare

endclass: SimpleDUT_scoreboard


Scoreboard class final solution (file : scoreboard.sv)

class SimpleDUT_hs_scoreboard extends uvm_test;
  `uvm_component_utils(SimpleDUT_hs_scoreboard)

  uvm_analysis_imp #(SimpleDUT_hs_sequence_item, SimpleDUT_hs_scoreboard) scoreboard_port;
  

// 1. change of the corresponding template:  adding access to interface to save

// handshake control ports to a transaction data 
virtual SimpleDUT_hs_interface vif;

SimpleDUT_hs_sequence_item transactions[$];

// 2. change of the corresponding template: count the number of transactions
  int no_transactions;

  //--------------------------------------------------------
  //Constructor
  //--------------------------------------------------------
  function new(string name = "SimpleDUT_hs_scoreboard", uvm_component parent);
    super.new(name, parent);
    `uvm_info("SCB_CLASS", "Inside Constructor!", UVM_HIGH)

  endfunction: new

  //--------------------------------------------------------
  //Build Phase
  //--------------------------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    `uvm_info("SCB_CLASS", "Build Phase!", UVM_HIGH)

    scoreboard_port = new("scoreboard_port", this);

// 3. change of a corresponding template:    
    if(!(uvm_config_db #(virtual SimpleDUT_hs_interface)::get(this, "*", "vif", vif))) begin
      `uvm_error("SCB_CLASS", "Failed to get VIF from config DB!")
    end

endfunction: build_phase


  //--------------------------------------------------------
  //Connect Phase
  //--------------------------------------------------------
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    `uvm_info("SCB_CLASS", "Connect Phase!", UVM_HIGH)

  endfunction: connect_phase

  //--------------------------------------------------------
  //Write Method
  //--------------------------------------------------------
  function void write(SimpleDUT_hs_sequence_item item);
   
    // 4. change of a corresponding template: adding handshake control signals to a transaction data
    item.en_din_i  = vif.en_din_i;
    item.rdy_din_o = vif.rdy_din_o;
    item.en_dout_i  = vif.en_dout_i;
    item.rdy_dout_o = vif.rdy_dout_o;

    transactions.push_back(item);
    item.display("[ Scoreboard ]");
  endfunction: write

//--------------------------------------------------------
  //Run Phase
  //--------------------------------------------------------
  task run_phase (uvm_phase phase);
    super.run_phase(phase);
    `uvm_info("SCB_CLASS", "Run Phase!", UVM_HIGH)
    forever begin
      /*
      // get the packet
      // generate expected value
      // compare it with actual value
      // score the transactions accordingly
      */
      SimpleDUT_hs_sequence_item curr_trans;

      wait((transactions.size() != 0));


      curr_trans = transactions.pop_front();


      compare(curr_trans);
   
    end

    endtask: run_phase

  //--------------------------------------------------------
  //Compare : Generate Expected Result and Compare with Actual
  //--------------------------------------------------------
  task compare(SimpleDUT_hs_sequence_item curr_trans);
    logic [3:0] expected;
    logic [3:0] actual;
 
  expected = curr_trans.din_i;
  actual   = curr_trans.dout_o;
 
    if(actual != expected) begin
      `uvm_error("COMPARE", $sformatf("Transaction failed! ACT=%d, EXP=%d", actual, expected))
    end
    else begin
      `uvm_info("COMPARE", $sformatf("Transaction Passed! ACT=%d, EXP=%d", actual, expected), UVM_LOW)
    end
 
          no_transactions++;
 
  endtask: compare

endclass: SimpleDUT_hs_scoreboard


Agent class template 2.0 same as a final solution ( once more a Component class: file agent.sv ) 

Let's create the agent class template which will be same as the environment and test class templates ( and in the same fashion all other necessary COMPONENT classes ) 

The agent class template  will have  three instance  class templates:  driver sequencer and monitor.

class SimpleDUT_hs_agent extends uvm_agent;
  `uvm_component_utils(SimpleDUT_hs_agent)

  SimpleDUT_hs_driver    drv;
  SimpleDUT_hs_monitor   mon;
  SimpleDUT_hs_sequencer seqr;
 
  SimpleDUT_hs_sequence_item item;
 
  //--------------------------------------------------------
  //Constructor
  //--------------------------------------------------------
  function new(string name = "SimpleDUT_hs_agent", uvm_component parent);
    super.new(name, parent);
    `uvm_info("AGENT_CLASS", "Inside Constructor!", UVM_HIGH)

  endfunction: new


  //--------------------------------------------------------
  //Build Phase
  //--------------------------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    `uvm_info("AGENT_CLASS", "Build Phase!", UVM_HIGH)

    drv = SimpleDUT_hs_driver::type_id::create("drv", this);
    mon = SimpleDUT_hs_monitor::type_id::create("mon", this);
    seqr = SimpleDUT_hs_sequencer::type_id::create("seqr", this);

endfunction: build_phase


  //--------------------------------------------------------
  //Connect Phase
  //--------------------------------------------------------
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    `uvm_info("AGENT_CLASS", "Connect Phase!", UVM_HIGH)

    drv.seq_item_port.connect(seqr.seq_item_export);

  endfunction: connect_phase


  //--------------------------------------------------------
  //Run Phase
  //--------------------------------------------------------
  task run_phase (uvm_phase phase);
    super.run_phase(phase);
    `uvm_info("AGENT_CLASS", "Run Phase!", UVM_HIGH)
    item = SimpleDUT_hs_sequence_item::type_id::create("item");
     
    mon.monitor_port.write(item);
  endtask: run_phase

endclass: SimpleDUT_hs_agent


Environment class template 2.0 same as a final solution ( A Component class: file env.sv)


As a friendly reminder the  environment class template  will have  instances of agent and scoreboard classes template instances  as it is planned in our UVM verification infrastructure architecture.


class SimpleDUT_hs_env extends uvm_test;
  `uvm_component_utils(SimpleDUT_hs_env)


SimpleDUT_hs_agent agnt;

SimpleDUT_hs_scoreboard scb;
//--------------------------------------------------------
  //Constructor
  //--------------------------------------------------------
  function new(string name = "SimpleDUT_hs_env", uvm_component parent);
    super.new(name, parent);
    `uvm_info("ENV_CLASS", "Inside Constructor!", UVM_HIGH)

  endfunction: new

  //--------------------------------------------------------
  //Build Phase
  //--------------------------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    `uvm_info("ENV_CLASS", "Build Phase!", UVM_HIGH)

agnt = SimpleDUT_hs_agent::type_id::create("agnt", this);
scb = SimpleDUT_hs_scoreboard::type_id::create("scb", this);
   
endfunction: build_phase

 
  //--------------------------------------------------------
  //Connect Phase
  //--------------------------------------------------------
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    `uvm_info("ENV_CLASS", "Connect Phase!", UVM_HIGH)

  agnt.mon.monitor_port.connect(scb.scoreboard_port);


  endfunction: connect_phase

 
  //--------------------------------------------------------
  //Run Phase
  //--------------------------------------------------------
  task run_phase (uvm_phase phase);
    super.run_phase(phase);
    `uvm_info("ENV_CLASS", "Run Phase!", UVM_HIGH)

  // Logic

    endtask: run_phase

endclass: SimpleDUT_hs_env


 

UVM Test Component template 2.0 same as final solution

It will have two purposes:

  • Create the env block

  • Connect the sequencer to the sequence


class SimpleDUT_hs_test extends uvm_test;
  `uvm_component_utils(SimpleDUT_hs_test)
  SimpleDUT_hs_env env;

// Instantiation two sequences
  SimpleDUT_hs_base_sequence reset_seq;
  SimpleDUT_hs_test_sequence test_seq;

       
  //--------------------------------------------------------
  // Constructor
  //--------------------------------------------------------
  function new(string name = "SimpleDUT_hs_test", uvm_component parent);
    super.new(name, parent);
    `uvm_info("TEST_CLASS", "Inside Constructor!", UVM_HIGH)
  endfunction: new

  //--------------------------------------------------------
  // Build Phase
  //--------------------------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    `uvm_info("TEST_CLASS", "Build Phase!", UVM_HIGH)


    env = SimpleDUT_hs_env::type_id::create("env", this);

   
  endfunction: build_phase

//--------------------------------------------------------
  //Connect Phase
  //--------------------------------------------------------
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    `uvm_info("TEST_CLASS", "Connect Phase!", UVM_HIGH)

  endfunction: connect_phase
  //--------------------------------------------------------
  //Run Phase
  //--------------------------------------------------------
  task run_phase (uvm_phase phase);
    super.run_phase(phase);
  `uvm_info("TEST_CLASS", "Run Phase!", UVM_HIGH)
   
    phase.raise_objection(this);

    // Constructing the reset sequence
    reset_seq = SimpleDUT_hs_base_sequence::type_id::create("reset_seq");
    reset_seq.start(env.agnt.seqr);
    

    // e.g. repeat test sequence 100 times
    repeat(100) begin
      //test_seq
      // Constructing the test sequence 
      test_seq = SimpleDUT_hs_test_sequence::type_id::create("test_seq");
      // Starting the test sequence on the sequencer on path env.agnt.seqr
      test_seq.start(env.agnt.seqr);
    end
   
    phase.drop_objection(this);


  endtask: run_phase


endclass: SimpleDUT_hs_test


testbench.sv (top testbench module )

`timescale 1ns/1ns

import uvm_pkg::*;

`include "uvm_macros.svh"


`include "interface.sv"
`include "sequence_item.sv"
`include "sequence.sv"
`include "sequencer.sv"
`include "driver.sv"
`include "monitor.sv"
`include "agent.sv"
`include "scoreboard.sv"
`include "env.sv"
`include "test.sv"

module top;

// the clock for DUT is generated  from the top testbench module so let's declare a signal clock here
logic CLK;
 
  SimpleDUT_hs_interface intf(.CLK(CLK));
 
  SimpleDUT_hs dut(
    .CLK(intf.CLK),
    .RST_N(intf.RST_N),
    .din_i(intf.din_i),
    .dout_o(intf.dout_o),
    .en_din_i(intf.en_din_i),
    .rdy_din_o(intf.rdy_din_o),
    .en_dout_i(intf.en_dout_i),
    .rdy_dout_o(intf.rdy_dout_o));
   

  //--------------------------------------------------------
  //Interface Setting
  //--------------------------------------------------------
  initial begin
    uvm_config_db #(virtual SimpleDUT_hs_interface)::set(null, "*", "vif", intf );
  end


  //Start The Test
  //--------------------------------------------------------
  initial begin
    run_test("SimpleDUT_hs_test");
  end
 
  //--------------------------------------------------------
  //Clock Generation
  //--------------------------------------------------------
  initial begin
    CLK = 0;
    #5;
    forever begin
      CLK = ~CLK;
      #2;
    end
  end
  //--------------------------------------------------------
  //Maximum Simulation Time
  //--------------------------------------------------------
  // initial begin
  //   #1000;
  //  $display("Sorry! Ran out of clock cycles!");
  //  $finish();
  // end
 
 
  //--------------------------------------------------------
  //Generate Waveforms
  //--------------------------------------------------------
  // if you want to see the waveforms you can also use the dump file  command to  tell the simulator to dump variable values so that
  // you can inspect  the waveforms after verification/simulation

  initial begin
    $dumpfile("d.vcd");
    $dumpvars();
  end
 
endmodule: top


Waveforms


Compilation/Verification log

[2023-07-26 07:25:46 UTC] vcs -licqueue '-timescale=1ns/1ns' '+vcs+flush+all' '+warn=all' '-sverilog' +incdir+$UVM_HOME/src $UVM_HOME/src/uvm.sv $UVM_HOME/src/dpi/uvm_dpi.cc -CFLAGS -DVCS design.sv testbench.sv && ./simv +vcs+lic+wait '+UVM_VERBOSITY=UVM_HIGH'



Chronologic VCS (TM)

Version S-2021.09 -- Wed Jul 26 03:25:47 2023


Copyright (c) 1991 - 2021 Synopsys, Inc.


Parsing design file 'design.sv'

Parsing design file 'testbench.sv'


Note-[SV-LCM-PPWI] Package previously wildcard imported

testbench.sv, 3

$unit

Package 'uvm_pkg' already wildcard imported.

Ignoring uvm_pkg::*

See the SystemVerilog LRM(1800-2005), section 19.2.1.


Parsing included file '/apps/vcsmx/vcs/S-2021.09//etc/uvm-1.2/src/uvm_macros.svh'.

Back to file 'testbench.sv'.

Parsing included file 'interface.sv'.

Back to file 'testbench.sv'.

Parsing included file 'sequence_item.sv'.

Back to file 'testbench.sv'.

Parsing included file 'sequence.sv'.

Back to file 'testbench.sv'.

Parsing included file 'sequencer.sv'.

Back to file 'testbench.sv'.

Parsing included file 'driver.sv'.

Back to file 'testbench.sv'.

Parsing included file 'monitor.sv'.

Back to file 'testbench.sv'.

Parsing included file 'agent.sv'.

Back to file 'testbench.sv'.

Parsing included file 'scoreboard.sv'.

Back to file 'testbench.sv'.

Parsing included file 'env.sv'.

Back to file 'testbench.sv'.

Parsing included file 'test.sv'.

Back to file 'testbench.sv'.

Top Level Modules:

top

TimeScale is 1 ns / 1 ns


Starting vcs inline pass...


6 modules and 0 UDP read.

recompiling package vcs_paramclassrepository

recompiling package _vcs_DPI_package

recompiling package uvm_pkg

recompiling module SimpleDUT_hs

recompiling module SimpleDUT_hs_interface

recompiling module top

All of 6 modules done

rm -f _cuarc*.so _csrc*.so pre_vcsobj_*.so share_vcsobj_*.so

g++ -w -pipe -m32 -DVCS -O -I/apps/vcsmx/vcs/S-2021.09/include -c /apps/vcsmx/vcs/S-2021.09//etc/uvm-1.2/src/dpi/uvm_dpi.cc

gcc -w -pipe -m32 -DVCS -O -I/apps/vcsmx/vcs/S-2021.09/include -c -o uM9F1_0x2aB.o uM9F1_0x2aB.c

if [ -x ../simv ]; then chmod a-x ../simv; fi

g++ -o ../simv -m32 -m32 -rdynamic -Wl,-rpath='$ORIGIN'/simv.daidir -Wl,-rpath=./simv.daidir -Wl,-rpath=/apps/vcsmx/vcs/S-2021.09/linux/lib -L/apps/vcsmx/vcs/S-2021.09/linux/lib -Wl,-rpath-link=./ -Wl,--no-as-needed uvm_dpi.o objs/amcQw_d.o _415_archive_1.so SIM_l.o uM9F1_0x2aB.o rmapats_mop.o rmapats.o rmar.o rmar_nd.o rmar_llvm_0_1.o rmar_llvm_0_0.o -lvirsim -lerrorinf -lsnpsmalloc -lvfs -lvcsnew -lsimprofile -luclinative /apps/vcsmx/vcs/S-2021.09/linux/lib/vcs_tls.o -Wl,-whole-archive -lvcsucli -Wl,-no-whole-archive ./../simv.daidir/vc_hdrs.o /apps/vcsmx/vcs/S-2021.09/linux/lib/vcs_save_restore_new.o /apps/vcsmx/vcs/S-2021.09/linux/lib/ctype-stubs_32.a -ldl -lc -lm -lpthread -ldl

../simv up to date

CPU time: 9.779 seconds to compile + .459 seconds to elab + .578 seconds to link

----------------------------------------------------------------

UVM-1.2.Synopsys

(C) 2007-2014 Mentor Graphics Corporation

(C) 2007-2014 Cadence Design Systems, Inc.

(C) 2006-2014 Synopsys, Inc.

(C) 2011-2013 Cypress Semiconductor Corp.

(C) 2013-2014 NVIDIA Corporation

----------------------------------------------------------------



UVM_INFO test.sv(15) @ 0: uvm_test_top [TEST_CLASS] Inside Constructor!

UVM_INFO @ 0: reporter [RNTST] Running test SimpleDUT_hs_test...

UVM_INFO test.sv(23) @ 0: uvm_test_top [TEST_CLASS] Build Phase!

UVM_INFO env.sv(13) @ 0: uvm_test_top.env [ENV_CLASS] Inside Constructor!

UVM_INFO env.sv(22) @ 0: uvm_test_top.env [ENV_CLASS] Build Phase!

UVM_INFO agent.sv(15) @ 0: uvm_test_top.env.agnt [AGENT_CLASS] Inside Constructor!

UVM_INFO scoreboard.sv(18) @ 0: uvm_test_top.env.scb [SCB_CLASS] Inside Constructor!

UVM_INFO agent.sv(25) @ 0: uvm_test_top.env.agnt [AGENT_CLASS] Build Phase!

UVM_INFO driver.sv(11) @ 0: uvm_test_top.env.agnt.drv [DRIVER_CLASS] Inside Constructor!

UVM_INFO monitor.sv(17) @ 0: uvm_test_top.env.agnt.mon [MONITOR_CLASS] Inside Constructor!

UVM_INFO sequencer.sv(10) @ 0: uvm_test_top.env.agnt.seqr [SEQUENCER_CLASS] Inside Constructor!

UVM_INFO driver.sv(21) @ 0: uvm_test_top.env.agnt.drv [DRIVER_CLASS] Build Phase!

UVM_INFO monitor.sv(30) @ 0: uvm_test_top.env.agnt.mon [MONITOR_CLASS] Build Phase!

UVM_INFO sequencer.sv(20) @ 0: uvm_test_top.env.agnt.seqr [SEQUENCER_CLASS] Build Phase!

UVM_INFO scoreboard.sv(28) @ 0: uvm_test_top.env.scb [SCB_CLASS] Build Phase!

UVM_INFO driver.sv(35) @ 0: uvm_test_top.env.agnt.drv [DRIVER_CLASS] Connect Phase!

UVM_INFO monitor.sv(46) @ 0: uvm_test_top.env.agnt.mon [MONITOR_CLASS] Connect Phase!

UVM_INFO sequencer.sv(30) @ 0: uvm_test_top.env.agnt.seqr [SEQUENCER_CLASS] Connect Phase!

UVM_INFO agent.sv(40) @ 0: uvm_test_top.env.agnt [AGENT_CLASS] Connect Phase!

UVM_INFO scoreboard.sv(44) @ 0: uvm_test_top.env.scb [SCB_CLASS] Connect Phase!

UVM_INFO env.sv(35) @ 0: uvm_test_top.env [ENV_CLASS] Connect Phase!

UVM_INFO test.sv(36) @ 0: uvm_test_top [TEST_CLASS] Connect Phase!

UVM_INFO driver.sv(45) @ 0: uvm_test_top.env.agnt.drv [DRIVER_CLASS] Run Phase!

UVM_INFO monitor.sv(56) @ 0: uvm_test_top.env.agnt.mon [MONITOR_CLASS] Run Phase!

UVM_INFO agent.sv(53) @ 0: uvm_test_top.env.agnt [AGENT_CLASS] Run Phase!

-------------------------

- [ Scoreboard ]

-------------------------

- en_din_i = 0, rdy_din_o = x, din_i = x

- en_dout_i = 0, rdy_dout_o = x, dout_o = x

-------------------------

UVM_INFO scoreboard.sv(68) @ 0: uvm_test_top.env.scb [SCB_CLASS] Run Phase!

UVM_INFO scoreboard.sv(101) @ 0: uvm_test_top.env.scb [COMPARE] Transaction Passed! ACT= x, EXP= x

UVM_INFO env.sv(48) @ 0: uvm_test_top.env [ENV_CLASS] Run Phase!

UVM_INFO test.sv(44) @ 0: uvm_test_top [TEST_CLASS] Run Phase!

UVM_INFO sequence.sv(15) @ 0: reporter@@reset_seq [BASE_SEQ] Inside Constructor!

UVM_INFO sequence.sv(25) @ 0: uvm_test_top.env.agnt.seqr@@reset_seq [BASE_SEQ] Inside body task!

UVM_INFO sequence.sv(15) @ 7: reporter@@test_seq [BASE_SEQ] Inside Constructor!

UVM_INFO sequence.sv(69) @ 7: reporter@@test_seq [TEST_SEQ] Inside Constructor!

UVM_INFO sequence.sv(77) @ 7: uvm_test_top.env.agnt.seqr@@test_seq [TEST_SEQ] Inside body task!

-------------------------

- [ Scoreboard ]

-------------------------

- en_din_i = 0, rdy_din_o = 0, din_i = 15

- en_dout_i = 0, rdy_dout_o = 0, dout_o = 15

-------------------------

UVM_INFO scoreboard.sv(101) @ 135: uvm_test_top.env.scb [COMPARE] Transaction Passed! ACT=15, EXP=15

UVM_INFO sequence.sv(15) @ 135: reporter@@test_seq [BASE_SEQ] Inside Constructor!

UVM_INFO sequence.sv(69) @ 135: reporter@@test_seq [TEST_SEQ] Inside Constructor!

UVM_INFO sequence.sv(77) @ 135: uvm_test_top.env.agnt.seqr@@test_seq [TEST_SEQ] Inside body task!

-------------------------

- [ Scoreboard ]

-------------------------

- en_din_i = 0, rdy_din_o = 0, din_i = 5

- en_dout_i = 0, rdy_dout_o = 0, dout_o = 5

-------------------------

UVM_INFO scoreboard.sv(101) @ 187: uvm_test_top.env.scb [COMPARE] Transaction Passed! ACT= 5, EXP= 5

UVM_INFO sequence.sv(15) @ 187: reporter@@test_seq [BASE_SEQ] Inside Constructor!

UVM_INFO sequence.sv(69) @ 187: reporter@@test_seq [TEST_SEQ] Inside Constructor!

UVM_INFO sequence.sv(77) @ 187: uvm_test_top.env.agnt.seqr@@test_seq [TEST_SEQ] Inside body task!


ETC. ETC.

-------------

UVM_INFO scoreboard.sv(101) @ 10635: uvm_test_top.env.scb [COMPARE] Transaction Passed! ACT= 6, EXP= 6

UVM_INFO sequence.sv(15) @ 10635: reporter@@test_seq [BASE_SEQ] Inside Constructor!

UVM_INFO sequence.sv(69) @ 10635: reporter@@test_seq [TEST_SEQ] Inside Constructor!

UVM_INFO sequence.sv(77) @ 10635: uvm_test_top.env.agnt.seqr@@test_seq [TEST_SEQ] Inside body task!

-------------------------

- [ Scoreboard ]

-------------------------

- en_din_i = 0, rdy_din_o = 0, din_i = 13

- en_dout_i = 0, rdy_dout_o = 0, dout_o = 13

-------------------------

UVM_INFO scoreboard.sv(101) @ 10747: uvm_test_top.env.scb [COMPARE] Transaction Passed! ACT=13, EXP=13

UVM_INFO /apps/vcsmx/vcs/S-2021.09//etc/uvm-1.2/src/base/uvm_objection.svh(1276) @ 10747: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase

UVM_INFO /apps/vcsmx/vcs/S-2021.09//etc/uvm-1.2/src/base/uvm_report_server.svh(904) @ 10747: reporter [UVM/REPORT/SERVER]

--- UVM Report Summary ---


** Report counts by severity

UVM_INFO : 433

UVM_WARNING : 0

UVM_ERROR : 0

UVM_FATAL : 0

** Report counts by id

[AGENT_CLASS] 4

[BASE_SEQ] 102

[COMPARE] 101

[DRIVER_CLASS] 4

[ENV_CLASS] 4

[MONITOR_CLASS] 4

[RNTST] 1

[SCB_CLASS] 4

[SEQUENCER_CLASS] 3

[TEST_CLASS] 4

[TEST_DONE] 1

[TEST_SEQ] 200

[UVM/RELNOTES] 1


$finish called from file "/apps/vcsmx/vcs/S-2021.09//etc/uvm-1.2/src/base/uvm_root.svh", line 527.

$finish at simulation time 10747

V C S S i m u l a t i o n R e p o r t

Time: 10747 ns

CPU Time: 0.660 seconds; Data structure size: 0.3Mb

Wed Jul 26 03:25:59 2023


© 2023 ASIC Stoic. All rights reserved.