image/svg+xml
  • Contents
      • Back
      • Digital Basics
      • Verilog
      • Verification
      • SystemVerilog
      • UVM
Most Popular
Verification
  Testbench Evolution
  Constraint Random Verification
  Verification Techniques
  Verification Plan
  Code Coverage

Verilog
  Data Types
  Basic Constructs
  Behavioral Modeling
  Gate Modeling
  Simulation Basics
  Design Examples

SystemVerilog
  Data Types
  Class
  Interface
  Constraints and more!
  Testbench Examples

UVM
  Sequences
  Testbench Components
  TLM Tutorial
  Register Model Tutorial
  Testbench Examples

Digital Fundamentals
  Binary Arithmetic
  Boolean Logic
  Karnaugh Maps
  Combinational Logic
  Sequential Logic




Reporting Functions

In Introduction, we saw that most of the verification components are inherited from uvm_report_object and hence they already have functions and methods to display messages.

Calling Functions

There are four basic reporting functions that can be used with different verbosity levels.


	uvm_report_* ("TAG", $sformatf ("[Enter the display message]"), VERBOSITY_LEVEL);

where * can be either info, error, warning, fatal. UVM has six levels of verbosity with each one represented by an integer.



typedef enum {
   UVM_NONE    = 0,
   UVM_LOW     = 100,
   UVM_MEDIUM  = 200,
   UVM_HIGH    = 300,
   UVM_FULL    = 400,
   UVM_DEBUG   = 500
} uvm_verbosity;

Read more: Reporting Functions

Sequencer and Monitor

In Data and Driver, we added a data packet and driver, but that model has the following drawbacks:

  • Limited verification components
  • Data packet is generated inside the Driver
  • Protocol used to send data is hard coded in the driver class
  • Data packet had a custom display function
Now, we'll add a sequencer and a monitor to the environment. The sequencer will generate, randomize data packets and send it to the driver. The driver will extract necessary information from the data packet and toggle DUT ports via the virtual interface handle. The monitor simply observes the transactions happening across the interface signals and converts it back into data packet format which can be sent to other verification components, if any.


Testbench

sequencer and monitor sequencer-monitor

Data

Previously we used to register a new object class with the factory using `uvm_object_utils. If we register it as shown below, we'll be able to utilize the automation features of UVM. That means, we don't have to explicitly write a display function as we did before, or write copy/clone/compare functions for each uvm_object inherited class.


`uvm_object_utils_begin (my_data)
	`uvm_field_int (data, UVM_ALL_ON)
	`uvm_field_int (addr, UVM_ALL_ON)
`uvm_object_utils_end
So, if we want to print out the contents in the class, all we need to do is call the print () method. We can specify the format in which data should be printed - table, line, tree, etc



data_obj.print ();
data_obj.print (uvm_default_line_printer);
data_obj.print (uvm_default_tree_printer);
data_obj.print (uvm_default_table_printer);

Driver

Since we extended the driver from uvm_driver class, it will have handles to the TLM interface. TLM stands for Transaction Level Modeling. For now, all you need to know is that it is a port that can be connected with another TLM interface. You may also refer to TLM tutorial. Usually we connect this with the sequencer, because that's where the data packets are generated. get_next_item () is a task in the TLM object seq_item_port which will get an item from the interface. drive_item is a user defined, protocol specific task that will do the pin wiggling of the DUT. After data is driven out, the driver will indicate back to the sequencer that it has finished the process by calling the function item_done.


Sequence

We need a sequence for the sequencer to operate on, and a base_sequence can be coded as


class base_sequence extends uvm_sequence;
	`uvm_object_utils (base_sequence)

	my_data  data_obj;
	int unsigned      n_times;

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

	// Raise an objection if started as the root sequence
	virtual task pre_body ();
		if (starting_phase != null)
			starting_phase.raise_objection (this);
	endtask

uvm_sequence is indirectly a derivative of uvm_object and hence we have registered it with the factory using `uvm_object_utils. Every sequence has body () task which will execute patterns and consume simulation time. You guessed it right, this is where we put our code for a sequence. The pre_body () task will automatically be called (unless it is configured to be skipped) before the body() task and it's a good place to raise an objection to let the testbench know that the sequence has items still pending for execution.



	virtual task body ();
		`uvm_info ("BASE_SEQ", $sformatf ("Starting body of %s", this.get_name()), UVM_MEDIUM)
		data_obj = my_data::type_id::create ("data_obj");

		repeat (n_times) begin
			start_item (data_obj);
			assert (data_obj.randomize ());
			finish_item (data_obj);
		end
		`uvm_info (get_type_name (), $sformatf ("Sequence %s is over", this.get_name()), UVM_MEDIUM)
	endtask
      
	// Drop objection if started as the root sequence
	virtual task post_body ();
		if (starting_phase != null) 
			starting_phase.drop_objection (this);
	endtask
endclass

Within the body() task, we can use start_item () and finish_item() methods to send the data object to the driver. Note that finish_item() will be over only after the driver calls item_done. After the body() method is over, objection is dropped and simulation proceeds to the next phase.


Sequencer

The sequencer is NOT required to be derived from uvm_sequencer, but instead can be instantiated directly as an object of uvm_sequencer parameterized to handle a specific data type. This is done in env class, where driver and monitor are instantiated.


uvm_sequencer #(my_data) m_seqr0;

The important part now is to connect the sequencer with the driver in the connect_phase () method.


m_drv0.seq_item_port.connect (m_seqr0.seq_item_export);

Simulation Output

----------------------------------------------------------------
CDNS-UVM-1.1d (14.10-s004)
(C) 2007-2013 Mentor Graphics Corporation
(C) 2007-2013 Cadence Design Systems, Inc.
(C) 2006-2013 Synopsys, Inc.
(C) 2011-2013 Cypress Semiconductor Corp.
----------------------------------------------------------------
UVM_INFO @ 0: reporter [RNTST] Running test base_test...
UVM_INFO @ 0: reporter [UVMTOP] UVM testbench topology:
------------------------------------------------------------
Name                     Type                    Size  Value
------------------------------------------------------------
uvm_test_top             base_test               -     @2629
  m_top_env              my_env                  -     @208
    m_drv0               my_driver               -     @202
      rsp_port           uvm_analysis_port       -     @2828
      seq_item_port      uvm_seq_item_pull_port  -     @2777
    m_mon0               my_monitor              -     @2728
    m_seqr0              uvm_sequencer           -     @2859
      rsp_export         uvm_analysis_export     -     @2949
      seq_item_export    uvm_seq_item_pull_imp   -     @3497
      arbitration_queue  array                   0     -
      lock_queue         array                   0     -
      num_last_reqs      integral                32    'd1
      num_last_rsps      integral                32    'd1
------------------------------------------------------------

UVM_INFO ./tb/my_pkg.sv(88) @ 0: uvm_test_top.m_top_env.m_drv0 [my_driver] Applying initial reset
UVM_INFO ./tb/my_pkg.sv(92) @ 390000: uvm_test_top.m_top_env.m_drv0 [my_driver] DUT is now out of reset
UVM_INFO ./tb/my_pkg.sv(99) @ 390000: uvm_test_top.m_top_env.m_drv0 [my_driver] Waiting for data from sequencer
UVM_INFO ./tb/my_pkg.sv(186) @ 390000: uvm_test_top.m_top_env.m_seqr0@@base_sequence [BASE_SEQ] Starting body of base_sequence
UVM_INFO ./tb/my_pkg.sv(194) @ 390000: uvm_test_top.m_top_env.m_seqr0@@base_sequence [base_sequence] Sequence base_sequence is over
UVM_INFO ./tb/my_pkg.sv(118) @ 390000: uvm_test_top.m_top_env.m_drv0 [my_driver] Finished DUT simulation

--- UVM Report catcher Summary ---


Number of demoted UVM_FATAL reports  :    0
Number of demoted UVM_ERROR reports  :    0
Number of demoted UVM_WARNING reports:    0
Number of caught UVM_FATAL reports   :    0
Number of caught UVM_ERROR reports   :    0
Number of caught UVM_WARNING reports :    0

--- UVM Report Summary ---

** Report counts by severity
UVM_INFO :    8
UVM_WARNING :    0
UVM_ERROR :    0
UVM_FATAL :    0
** Report counts by id
[BASE_SEQ]     1
[RNTST]     1
[UVMTOP]     1
[base_sequence]     1
[my_driver]     4
Simulation complete via $finish(1) at time 390 NS + 139

Go to the final step Agent and Scoreboard

Using get() and put()

In the previous article, we saw how a UVM driver gets the next item by the calling get_next_item method, and how it informs the sequencer that the current item is done. Although this is the preferred way for driver-sequencer communications, UVM also gives us an alternative for a more complex implementation.

The other way is for the driver to use the get method to receive the next item and later use put to give a response item back to the sequencer.

driver-sequencer-get-and-put-flow

What is the driver code for get and put calls ?


class my_driver extends uvm_driver #(my_data);
   `uvm_component_utils (my_driver)

   virtual task run_phase(uvm_phase phase);
      super.run_phase(phase);

	  // 1. Get an item from the sequencer using "get" method
      seq_item_port.get(req);

	  // 2. For simplicity, lets assume the driver drives the item and consumes 20ns of simulation time
      #20;

	  // 3. After the driver is done, assume it gets back a read data called 8'hAA from the DUT
	  // Assign the read data into the "request" sequence_item object
      req.data = 8'hAA;

	  // 4. Call the "put" method to send the request item back to the sequencer
      seq_item_port.put(req);
   endtask
endclass

How does the sequence start and stop an item ?


class my_sequence extends uvm_sequence #(my_data);
  `uvm_object_utils (my_sequence)

  // Create a sequence item object handle to store the sequence_item contents
  my_data tx;

  virtual task body();
  	// 1. Create the sequence item using standard factory calls
    tx = my_data::type_id::create("tx");
    
    // 2. Start this item on the current sequencer
    start_item(tx);
    
    // 3. Do late randomization since the class handle pointers are the same
    tx.randomize();
    
    // 4. Finish executing the item from the sequence perspective
    // The driver could still be actively driving and waiting for response
    finish_item(tx);
    
    // 5. Because "finish_item" does not indicate that the driver has finished driving the item,
    // the sequence has to wait until the driver explicitly tells the sequencer that the item is over
    // So, wait unitl the sequence gets a response back from the sequencer.
    get_response(tx);
    
    `uvm_info ("SEQ", $sformatf("get_response() fn call done rsp addr=0x%0h data=0x%0h, exit seq", tx.addr, tx.data), UVM_MEDIUM)
  endtask
endclass 

Example

To illustrate how the get and put method calls between driver and sequencer work, let us build a simple testbench structure like the one shown below.

uvm-driver-sequencer-get-put-testbench

Define a sequence item

To keep things simple, let us define a transaction object class that will become the sequence item used for sequencer-driver communication. Assume that this sequence item contains two variables called addr and data.


// Note that this class is dervide from "uvm_sequence_item"
class my_data extends uvm_sequence_item;
  rand bit [7:0]   data;
  rand bit [7:0]   addr;

	// Rest of the class contents come here ...
endclass

Define the driver

The uvm_driver is parameterized to accept a class object of the type my_data and the driver is expected to unpack this class object and drive the signals appropriately to the DUT via the interface.


class my_driver extends uvm_driver #(my_data);
   `uvm_component_utils (my_driver)

   virtual task run_phase(uvm_phase phase);
      super.run_phase(phase);
      
      // 1. Get sequence item from the sequencer using "get" method.
      // "req" is a pre-defined variable that comes with the class "uvm_driver"
      `uvm_info ("DRIVER", $sformatf ("Waiting for data from sequencer"), UVM_MEDIUM)
      seq_item_port.get(req);
      
      // 2. Assume that the driver drives this data during this time. For our purpose let's consider that the driver
      // consumes 20ns of simulation time
      `uvm_info ("DRIVER", $sformatf ("Start driving tx addr=0x%0h data=0x%0h", req.addr, req.data), UVM_MEDIUM)
      #20;
      
      // 3. Lets also assume that the DUT returned some read data back to the driver, which needs to be sent back
      // to the sequence. Note that read data is put into the same "request" class object handle 
      `uvm_info ("DRIVER", $sformatf ("#20 delay over, curr data=0x%0h", req.data), UVM_MEDIUM)
      req.data = 8'hAA;
      
      // 4. The driver calls the "put" method and sends back the response data to the sequencer
      `uvm_info ("DRIVER", $sformatf ("About to call put() with new data=0x%0h", req.data), UVM_MEDIUM)
      seq_item_port.put(req);
      `uvm_info ("DRIVER", $sformatf ("Finish driving tx addr=0x%0h data=0x%0h", req.addr, req.data), UVM_MEDIUM)
   endtask
endclass

Define the sequence

A sequence item is always started using the start_item and finish_item methods.


class my_sequence extends uvm_sequence #(my_data);
  	// Rest of the sequence code

  	virtual task body();
  		// 1. Create a sequence item of the given type. Note that this sequence has an internal
  		// variable called "req" which can be directly used as well instead of "tx"
  		my_data tx = my_data::type_id::create("tx");
    	`uvm_info ("SEQ", $sformatf("About to call start_item"), UVM_MEDIUM)
    	
    	// 2. Start the item on the sequencer which will send this to the driver
    	start_item(tx);
    	`uvm_info ("SEQ", $sformatf("start_item() fn call done"), UVM_MEDIUM)
    	
    	// 3. Do some late randomization to create a different content in this transaction object
    	tx.randomize();
    	`uvm_info ("SEQ", $sformatf("tx randomized with addr=0x%0h data=0x%0h", tx.addr, tx.data), UVM_MEDIUM)
    	
    	// 4. Call finish_item to let driver continue driving the transaction object or sequence item
    	finish_item(tx);
    	`uvm_info ("SEQ", $sformatf("finish_item() fn call done, wait for rsp"), UVM_MEDIUM)
    	
    	// 5. Wait for the driver to finish driving the object, and respond back with a response object
    	// The transaction is said to be complete at this point. This task is blocking in nature and hence
    	// the sequence will end only after the driver returns a response item.
    	get_response(tx);
    	`uvm_info ("SEQ", $sformatf("get_response() fn call done rsp addr=0x%0h data=0x%0h, exit seq", tx.addr, tx.data), UVM_MEDIUM)
  	endtask
endclass

Define the test class

To keep things simple, let us directly create instances of the driver and sequencer inside the test class.

Driver and Sequencer should be instantiated inside an agent. An agent is instantiated in an environment and the the environment in turn should be created in the test.


class base_test extends uvm_test;
	// Rest of the test code is here

	// The sequencer is parameterized to accept objects of type "my_data" only
  	my_driver                	m_drv0;
  	uvm_sequencer #(my_data) 	m_seqr0;
  	my_sequence   				m_seq;

	// Build the sequencer and driver components
  	virtual function void build_phase(uvm_phase phase);
     	super.build_phase(phase);
     	m_drv0 = my_driver::type_id::create ("m_drv0", this);
     	m_seqr0 = uvm_sequencer#(my_data)::type_id::create ("m_seqr0", this);
  	endfunction
  
   	// Connect the sequencer "export" to the driver's "port"
   	virtual function void connect_phase (uvm_phase phase);
     	super.connect_phase (phase);
     	m_drv0.seq_item_port.connect (m_seqr0.seq_item_export);
   	endfunction

	// Start the sequence on the given sequencer
  	virtual task run_phase(uvm_phase phase);
    	m_seq = my_sequence::type_id::create("m_seq");
    	phase.raise_objection(this);
    	m_seq.start(m_seqr0);
    	phase.drop_objection(this);
  	endtask
endclass

Note that finish_item finished at time 0ns even before the driver started doing the pin wiggling (assumed to happen during the 20ns delay in this example). The get_response method is done at time 20ns when the driver sends back the response item.

It is also evident from the log that the data modified in the request packet within the driver can be obtained inside the sequence.

 Simulation Log
UVM_INFO @ 0: reporter [RNTST] Running test base_test...
UVM_INFO testbench.sv(33) @ 0: uvm_test_top.m_top_env.m_drv0 [DRIVER] Waiting for data from sequencer
UVM_INFO testbench.sv(76) @ 0: uvm_test_top.m_top_env.m_seqr0@@m_seq [SEQ] About to call start_item
UVM_INFO testbench.sv(78) @ 0: uvm_test_top.m_top_env.m_seqr0@@m_seq [SEQ] start_item() fn call done
UVM_INFO testbench.sv(80) @ 0: uvm_test_top.m_top_env.m_seqr0@@m_seq [SEQ] tx randomized with addr=0x8f data=0x1d
UVM_INFO testbench.sv(35) @ 0: uvm_test_top.m_top_env.m_drv0 [DRIVER] Start driving tx addr=0x8f data=0x1d
UVM_INFO testbench.sv(82) @ 0: uvm_test_top.m_top_env.m_seqr0@@m_seq [SEQ] finish_item() fn call done, wait for rsp
UVM_INFO testbench.sv(37) @ 20: uvm_test_top.m_top_env.m_drv0 [DRIVER] #20 delay over, curr data=0x1d
UVM_INFO testbench.sv(39) @ 20: uvm_test_top.m_top_env.m_drv0 [DRIVER] About to call put() with new data=0xaa
UVM_INFO testbench.sv(41) @ 20: uvm_test_top.m_top_env.m_drv0 [DRIVER] Finish driving tx addr=0x8f data=0xaa
UVM_INFO testbench.sv(84) @ 20: uvm_test_top.m_top_env.m_seqr0@@m_seq [SEQ] get_response() fn call done rsp addr=0x8f data=0xaa, exit seq
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_objection.svh(1271) @ 20: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_report_server.svh(847) @ 20: reporter [UVM/REPORT/SERVER] 
--- UVM Report Summary ---

Data and Driver

In the previous session, we had a simple testbench structure with only test and environment.That was just enough to utilize a UVM component, and print "Hello UVM". But, in a normal testbench we would have a data element that gets routed through different verification components. So, in this part, we will create a "data" packet object and send it to the "driver".

Read more: Data and Driver

Hello UVM !

Class hierarchy was discussed in the previous session. Now, let's try to construct a testbench that will print out "Hello UVM". We'll keep the testbench simple with only two main components.

  • Test
  • Environment

Testbench Setup

The testbench structure is setup as shown in the image below, with the environment instantiated inside the test and the DUT interacting with the test via the DUT interface.


simple UVM testbench

DUT

The DUT is a simple memory module that will accept data into the memory array upon a write transaction and provide data at the output ports for a read transaction. It has the following ports


module dut (   
               input    clk,                 // Clock at some freq
               input    rstn,                // Active Low  Sync Reset
               input    wr,                  // Active High Write
               input    en,                  // Module Enable
               input    wdata,               // Write Data
               input    addr,                // Address

               output   rdata                // Read Data
            );		

Interface

Let's put all the signals of the DUT inside an interface and use an interface handle to access the signals. The interface is defined as below.


interface dut_if (input clk);

   logic          rstn;
   logic [7:0]    wdata;
   logic [7:0]    rdata;
   logic [7:0]    addr;
   logic          wr;
   logic          en;

endinterface  

DUT Wrapper

It'll be easier to instantiate the DUT in the top level module if we put a wrapper around it.


module dut_wrapper (dut_if _if);

   // Instantiate the design module and connect interface signals to DUT
   dut   dsn0     (  .clk     (_if.clk),
                     .rstn    (_if.rstn),
                     .wr      (_if.wr),
                     .en      (_if.en),
                     .wdata   (_if.wdata),
                     .addr    (_if.addr),
                     .rdata   (_if.rdata));

endmodule

With the DUT wrapper, instantiating at the top level reduces to a single line.


dut_wrapper    dut_wr0  (._if (dut_if1));

Watch how to install Modelsim and run Hello World !

Test

The test is an object of uvm_test and contains the environment. The interface handle is obtained from the top level module and will pass it to all components inside the environment. The test will also decide on what sequence to run when simulation is started. This is very convenient because now you have the ability to create multiple tests that can choose from a library of sequences wihtout having to edit the code in the testbench. Let's break the class test and go through each line.


class base_test extends uvm_test;

We have defined a class called base_test that inherits all the properties and methods from uvm_test. Now, we have to register this component with the UVM factory for it to work properly by calling the macro `uvm_component_utils because test is a derivative of uvm_component.


	`uvm_component_utils (base_test)

Now, we'll create an object of the environment and a virtual interface handle that can be made to point to the correct interface.


    my_env   m_top_env;
    virtual  dut_if dut_vi;

Next, we'll code the constructor new () with arguments name and parent (default is set to null).


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

Then, the build phase is defined to instantiate an object of the environment, and collect the interface from top level module. Note that we have called the parent's build phase first using super keyword. The line that contains type_id is the preferred way to create objects of classes in UVM. This is because it uses factory methods to create the object that can be easily substituted/modified later on. Note that you can also create an object using the new () method, but that does not make object instantiation flexible enough and hence is not recommended. The line that contains uvm_config_db is the new way of setting and retrieving variable values in UVM. In C, you would have declared the variable to be global and it can be accessed from anywhere, in any header/C file. In UVM, variables can be put inside the database and make it available to selected components and only those components will be able to access the variable value. So, in this case we are trying to get the dut_if object from the database.


     virtual function void build_phase (uvm_phase phase);
         super.build_phase (phase);

         m_top_env  = my_env::type_id::create ("m_top_env", this);
      
         if (! uvm_config_db #(virtual dut_if) :: get (this, "", "dut_if", dut_vi)) begin
            `uvm_error (get_type_name (), "DUT Interface not found !")
         end
      endfunction : build_phase

The function get () has arguments in the order ['context', 'instance_name', 'field_name', 'variable_to store_value'].

We can also print out the topology of the environment after the build and connect phases.


	virtual function void end_of_elaboration_phase (uvm_phase phase);
 		uvm_top.print_topology ();
 	endfunction

In the start_of_simulation_phase you can specify the sequence that a particular sequencer has to operate on.

Environment

All we do in the environment is to print out a message "Hello UVM !"


class my_env extends uvm_env ;
	`uvm_component_utils (my_env)
   
	function new (string name, uvm_component parent);
		super.new (name, parent);
	endfunction : new
   
	function void build_phase (uvm_phase phase);
		super.build_phase (phase);
	endfunction : build_phase
   
	task run_phase (uvm_phase phase);
		set_report_verbosity_level (UVM_MEDIUM);
		uvm_report_info      (get_name(), $sformatf ("Hello UVM ! Simulation has started."), UVM_MEDIUM, `__FILE__, `__LINE__);
		`uvm_info   (get_name(), $sformatf("Finishing up with run_phase ... "), UVM_LOW)
	endtask : run_phase
endclass : my_env
 Simulation Log
----------------------------------------------------------------
CDNS-UVM-1.1d (14.10-s004)
(C) 2007-2013 Mentor Graphics Corporation
(C) 2007-2013 Cadence Design Systems, Inc.
(C) 2006-2013 Synopsys, Inc.
(C) 2011-2013 Cypress Semiconductor Corp.
----------------------------------------------------------------
UVM_INFO @ 0: reporter [RNTST] Running test base_test...
UVM_INFO @ 0: reporter [UVMTOP] UVM testbench topology:
------------------------------------
Name          Type       Size  Value
------------------------------------
uvm_test_top  base_test  -     @2601
  m_top_env   my_env     -     @201
------------------------------------

UVM_INFO ./tb/my_pkg.sv(30) @ 0: uvm_test_top.m_top_env [m_top_env] Hello UVM ! Simulation has started.
UVM_INFO ./tb/my_pkg.sv(31) @ 0: uvm_test_top.m_top_env [m_top_env] Finishing up with run_phase ...

--- UVM Report catcher Summary ---


Number of demoted UVM_FATAL reports  :    0
Number of demoted UVM_ERROR reports  :    0
Number of demoted UVM_WARNING reports:    0
Number of caught UVM_FATAL reports   :    0
Number of caught UVM_ERROR reports   :    0
Number of caught UVM_WARNING reports :    0

--- UVM Report Summary ---

** Report counts by severity
UVM_INFO :    4
UVM_WARNING :    0
UVM_ERROR :    0
UVM_FATAL :    0
** Report counts by id
[RNTST]     1
[UVMTOP]     1
[m_top_env]     2
Simulation complete via $finish(1) at time 0 FS + 179

Go to the next step Data and Driver

  1. UVM Installation
  2. Verilog Johnson Counter
  3. SystemVerilog Loops
  4. Verilog Gray Counter
  5. Verilog Scheduling Semantics

Page 51 of 63

  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
Interview Questions
  Verilog Interview Set 1
  Verilog Interview Set 2
  Verilog Interview Set 3
  Verilog Interview Set 4
  Verilog Interview Set 5

  SystemVerilog Interview Set 1
  SystemVerilog Interview Set 2
  SystemVerilog Interview Set 3
  SystemVerilog Interview Set 4
  SystemVerilog Interview Set 5

  UVM Interview Set 1
  UVM Interview Set 2
  UVM Interview Set 3
  UVM Interview Set 4
Related Topics
  Digital Fundamentals
  Verilog Tutorial

  Verification
  SystemVerilog Tutorial
  UVM Tutorial
  • Verilog Testbench
  • Verilog Coding Style Effect
  • Verilog Conditional Statements
  • Verilog Interview Set 10
  • Synchronous FIFO
  • SystemVerilog Interview Set 10
  • SystemVerilog Interview Set 9
  • SystemVerilog Interview Set 8
  • SystemVerilog Interview Set 7
  • SystemVerilog Interview Set 6
  • UVM Singleton Object
  • UVM Component [uvm_component]
  • UVM Object [uvm_object]
  • UVM Root [uvm_root]
  • UVM Interview Set 4
© 2015 - 2023 ChipVerify
Terms and Conditions | DMCA.com Protection Status