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




Verilog Sequence Detector

A very common example of an FSM is that of a sequence detector where the hardware design is expected to detect when a fixed pattern is seen in a stream of binary bits that are input to it.

Example


module det_1011 ( input clk,
                  input rstn,
                  input in,
                  output out );
  
  parameter IDLE 	= 0,
  			S1 		= 1,
  			S10 	= 2,
  			S101 	= 3,
  			S1011 	= 4;
  
  reg [2:0] cur_state, next_state;
  
  assign out = cur_state == S1011 ? 1 : 0;
  
  always @ (posedge clk) begin
    if (!rstn)
      	cur_state <= IDLE;
     else 
     	cur_state <= next_state;
  end
  
  always @ (cur_state or in) begin
    case (cur_state)
      IDLE : begin
        if (in) next_state = S1;
        else next_state = IDLE;
      end
      
      S1: begin
        if (in) next_state = IDLE;
        else 	next_state = S10;
      end
      
      S10 : begin
        if (in) next_state = S101;
        else 	next_state = IDLE;
      end
      
      S101 : begin
        if (in) next_state = S1011;
        else 	next_state = IDLE;
      end
      
      S1011: begin
        next_state = IDLE;
      end
    endcase
  end
endmodule

Testbench


module tb;
  reg 			clk, in, rstn;
  wire 			out;
  reg [1:0] l_dly;
  reg 			tb_in;
  integer 	loop = 1;
  
  always #10 clk = ~clk;
  
  det_1011 u0 ( .clk(clk), .rstn(rstn), .in(in), .out(out) );
  
  initial begin
  	clk <= 0;
    rstn <= 0;
    in <= 0;
    
    repeat (5) @ (posedge clk);
    rstn <= 1;

		// Generate a directed pattern
    @(posedge clk) in <= 1;
    @(posedge clk) in <= 0;
    @(posedge clk) in <= 1;
    @(posedge clk) in <= 1; 		// Pattern is completed
    @(posedge clk) in <= 0;
    @(posedge clk) in <= 0;
    @(posedge clk) in <= 1;
    @(posedge clk) in <= 1;
    @(posedge clk) in <= 0;
    @(posedge clk) in <= 1;
    @(posedge clk) in <= 1; 	 // Pattern completed again
    
    // Or random stimulus using a for loop that drives a random
    // value of input N times
    for (int i = 0 ; i < loop; i ++) begin
      l_dly = $random;
      repeat (l_dly) @ (posedge clk);
      tb_in = $random;
      in <= tb_in;
    end
    
    // Wait for sometime before quitting simulation
    #100 $finish;
  end
endmodule
 Simulation Log
ncsim> run
T=10 in=0 out=0
T=30 in=0 out=0
T=50 in=0 out=0
T=70 in=0 out=0
T=90 in=0 out=0
T=110 in=1
 out=0
T=130 in=0
 out=0
T=150 in=1
 out=0
T=170 in=1
 out=0
T=190 in=0 out=1
T=210 in=0 out=0
T=230 in=1 out=0
T=250 in=1
 out=0
T=270 in=0
 out=0
T=290 in=1
 out=0
T=310 in=1
 out=0
T=330 in=1 out=1
T=350 in=1 out=0
T=370 in=1 out=0
T=390 in=1 out=0
Simulation complete via $finish(1) at time 410 NS + 0

There is a bug in the design. Can you find it ?

UVM Object Copy/Clone

  1. Using automation macros
  2. Using do_copy
  3. Using clone method

uvm_object has many common functions like print, copy and compare that are available to all its child classes and can be used out of the box if UVM automation macros are used inside the class definition. In a previous article , print, do_print and use of automation macros to print were discussed.

Using automation macros

A class called Packet is defined with a single variable and registered using UVM automation macros between uvm_object_utils_begin and uvm_object_utils_end. A variable used with UVM_DEFAULT setting means that this variable will be included in all automated methods like copy, print, etc unless specifically mentioned.

An object of Packet is instantiated in another class called Object along with a bunch of other variables of different data types. Similar to the Packet class, all variables in Object are registered with UVM automation macros with the corresponding macro type. For example, string variables require `uvm_field_string.


typedef enum {FALSE, TRUE} e_bool;

class Packet extends uvm_object;
  rand bit[15:0] 	m_addr;
  
  // Automation macros
  `uvm_object_utils_begin(Packet)
  	`uvm_field_int(m_addr, UVM_DEFAULT)
  `uvm_object_utils_end
  
  function new(string name = "Packet");
    super.new(name);
  endfunction
endclass

class Object extends uvm_object;
  rand e_bool 				m_bool;
  rand bit[3:0] 			m_mode;
  rand byte 				m_data[4];
  rand shortint 			m_queue[$];
  string 					m_name;
  rand Packet 				m_pkt;
  
  constraint c_queue { m_queue.size() == 3; }
  
  function new(string name = "Object");
    super.new(name);
    m_name = name;
    m_pkt = Packet::type_id::create("m_pkt");
    m_pkt.randomize();
  endfunction
  
  `uvm_object_utils_begin(Object)
  	`uvm_field_enum(e_bool, m_bool, UVM_DEFAULT)
  	`uvm_field_int (m_mode, 		UVM_DEFAULT)
  	`uvm_field_sarray_int(m_data, 	UVM_DEFAULT)
  	`uvm_field_queue_int(m_queue, 	UVM_DEFAULT)
  	`uvm_field_string(m_name, 		UVM_DEFAULT)
  	`uvm_field_object(m_pkt, 		UVM_DEFAULT)
  `uvm_object_utils_end
endclass

Let us create a test class and create two objects of type Object , randomize both and display them first. Then contents of obj1 is copied into obj2 using the copy function. Implementation of this copy function is taken care of by the automation macros.


class base_test extends uvm_test;
  `uvm_component_utils(base_test)
  function new(string name = "base_test", uvm_component parent=null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    Object obj1 = Object::type_id::create("obj1");
    Object obj2 = Object::type_id::create("obj2");
    obj1.randomize();
    obj1.print();
    obj2.randomize();
   	obj2.print();
    
    obj2.copy(obj1);
    `uvm_info("TEST", "After copy", UVM_LOW)
    obj2.print();
  endfunction
endclass

module tb;
	initial begin
		run_test("base_test");
	end
endmodule

The first table shows the values of obj1 after randomization, the second table that of obj2 after randomization and the third one shows contents of obj2 after the copy method is called.

 Simulation Log
ncsim> run
UVM_INFO @ 0: reporter [RNTST] Running test base_test...
--------------------------------------
Name        Type          Size  Value 
--------------------------------------
obj1        Object        -     @1903 
  m_bool    e_bool        32    TRUE  
  m_mode    integral      4     'he   
  m_data    sa(integral)  4     -     
    [0]     integral      8     'hf4  
    [1]     integral      8     'he   
    [2]     integral      8     'h58  
    [3]     integral      8     'hbd  
  m_queue   da(integral)  3     -     
    [0]     integral      16    'h9ae9
    [1]     integral      16    'hd31d
    [2]     integral      16    'ha96c
  m_name    string        4     obj1  
  m_pkt     Packet        -     @1906 
    m_addr  integral      16    'h3cb6
--------------------------------------
--------------------------------------
Name        Type          Size  Value 
--------------------------------------
obj2        Object        -     @1908 
  m_bool    e_bool        32    FALSE 
  m_mode    integral      4     'he   
  m_data    sa(integral)  4     -     
    [0]     integral      8     'h60  
    [1]     integral      8     'h24  
    [2]     integral      8     'h27  
    [3]     integral      8     'hb5  
  m_queue   da(integral)  3     -     
    [0]     integral      16    'he17f
    [1]     integral      16    'h98e6
    [2]     integral      16    'h5a41
  m_name    string        4     obj2  
  m_pkt     Packet        -     @1910 
    m_addr  integral      16    'h64c1
--------------------------------------
UVM_INFO testbench.sv(60) @ 0: uvm_test_top [TEST] After copy
--------------------------------------
Name        Type          Size  Value 
--------------------------------------
obj2        Object        -     @1908 
  m_bool    e_bool        32    TRUE  
  m_mode    integral      4     'he   
  m_data    sa(integral)  4     -     
    [0]     integral      8     'hf4  
    [1]     integral      8     'he   
    [2]     integral      8     'h58  
    [3]     integral      8     'hbd  
  m_queue   da(integral)  3     -     
    [0]     integral      16    'h9ae9
    [1]     integral      16    'hd31d
    [2]     integral      16    'ha96c
  m_name    string        4     obj1  
  m_pkt     Packet        -     @1909 
    m_addr  integral      16    'h3cb6
--------------------------------------
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_report_server.svh(847) @ 0: reporter [UVM/REPORT/SERVER] 
--- UVM Report Summary ---

Automation macros introduce a lot of additional code and is not generally recommended

Using do_copy

Another way is for the user to implement do_copy method inside the child class and assign the value from each variable of the class to be copied into the current one. Note in the following example that uvm_object_utils_* macros are not used and hence the print() method we used above will not work as is. Instead another method called convert2string is implemented for both classes so that it returns the contents in a string format when called.

Just like the way print calls do_print method, a copy calls the do_copy method and implementation of the function is all that is required to be done.


typedef enum {FALSE, TRUE} e_bool;

class Packet extends uvm_object;
  rand bit[15:0] 	m_addr;
  
  // Function is used to return contents of this class in a 
  // string format
  virtual function string convert2string();
    string contents;
    contents = $sformatf("m_addr=0x%0h", m_addr);
  endfunction

  `uvm_object_utils(Packet)
  
  // Implementation of "do_copy". A generic uvm_object called "rhs"
  // is received and type casted into Packet called "_pkt". Then 
  // m_addr is copied from _pkt to the variable in current class
  virtual function void do_copy(uvm_object rhs);
    Packet _pkt;
    super.do_copy(rhs);
    $cast(_pkt, rhs);
   	m_addr = _pkt.m_addr;
    `uvm_info(get_name(), "In Packet::do_copy()", UVM_LOW)
  endfunction
  
  function new(string name = "Packet");
    super.new(name);
  endfunction
endclass

class Object extends uvm_object;
  rand e_bool 				m_bool;
  rand bit[3:0] 			m_mode;
  rand byte 				m_data[4];
  rand shortint 			m_queue[$];
  string 					m_name;
  rand Packet 				m_pkt;
  
  constraint c_queue { m_queue.size() == 3; }
  
  function new(string name = "Object");
    super.new(name);
    m_name = name;
    m_pkt = Packet::type_id::create("m_pkt");
    m_pkt.randomize();
  endfunction
  
  // Function used to return contents of this class in a 
  // string format
  virtual function string convert2string();
    string contents = "";
    $sformat(contents, "%s m_name=%s", contents, m_name);
    $sformat(contents, "%s m_bool=%s", contents, m_bool.name());
    $sformat(contents, "%s m_mode=0x%0h", contents, m_mode);
    foreach(m_data[i]) begin
      $sformat(contents, "%s m_data[%0d]=0x%0h", contents, i, m_data[i]);
    end
    return contents;
  endfunction
  
  `uvm_object_utils(Object)
  
  // "rhs" does not contain m_bool, m_mode, etc since its a parent
  // handle. So cast into child data type and access using child handle
  // Copy each field from the casted handle into local variables
  virtual function void do_copy(uvm_object rhs);
    Object _obj;
    super.do_copy(rhs);
    $cast(_obj, rhs);
    m_bool 	= _obj.m_bool;
    m_mode 	= _obj.m_mode;
    m_data 	= _obj.m_data;
    m_queue = _obj.m_queue;
    m_name 	= _obj.m_name;
    m_pkt.copy(_obj.m_pkt);
    `uvm_info(get_name(), "In Object::do_copy()", UVM_LOW)
  endfunction
endclass

Like in the earlier example, two objects are created and contents of one is copied into another. Because do_print method is not implemented and automation macros are not used, convert2string will be used to print contents of each class.


class base_test extends uvm_test;
	`uvm_component_utils(base_test)
  function new(string name = "base_test", uvm_component parent=null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    Object obj1 = Object::type_id::create("obj1");
    Object obj2 = Object::type_id::create("obj2");
    obj1.randomize();
    `uvm_info("TEST", $sformatf("Obj1.print: %s", obj1.convert2string()), UVM_LOW)
    obj2.randomize();
    `uvm_info("TEST", $sformatf("Obj2.print: %s", obj2.convert2string()), UVM_LOW)
    
    obj2.copy(obj1);
    `uvm_info("TEST", "After copy", UVM_LOW)
    `uvm_info("TEST", $sformatf("Obj2.print: %s", obj2.convert2string()), UVM_LOW)
  endfunction
endclass

module tb;
	initial begin
		run_test("base_test");
	end
endmodule
 Simulation Log
ncsim> run
UVM_INFO @ 0: reporter [RNTST] Running test base_test...
UVM_INFO testbench.sv(93) @ 0: uvm_test_top [TEST] Obj1.print:  m_name=obj1 m_bool=TRUE m_mode=0xe m_data[0]=0xf4 m_data[1]=0xe m_data[2]=0x58 m_data[3]=0xbd
UVM_INFO testbench.sv(95) @ 0: uvm_test_top [TEST] Obj2.print:  m_name=obj2 m_bool=FALSE m_mode=0xe m_data[0]=0x60 m_data[1]=0x24 m_data[2]=0x27 m_data[3]=0xb5
UVM_INFO testbench.sv(26) @ 0: reporter [m_pkt] In Packet::do_copy()
UVM_INFO testbench.sv(79) @ 0: reporter [obj2] In Object::do_copy()
UVM_INFO testbench.sv(98) @ 0: uvm_test_top [TEST] After copy
UVM_INFO testbench.sv(99) @ 0: uvm_test_top [TEST] Obj2.print:  m_name=obj1 m_bool=TRUE m_mode=0xe m_data[0]=0xf4 m_data[1]=0xe m_data[2]=0x58 m_data[3]=0xbd
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_report_server.svh(847) @ 0: reporter [UVM/REPORT/SERVER] 
--- UVM Report Summary ---

Using clone method

clone method works exactly the same as a copy method, the difference being that a clone will return an object with the copied contents. So this saves some trouble of creating the second object before copy.


class base_test extends uvm_test;
  `uvm_component_utils(base_test)
  function new(string name = "base_test", uvm_component parent=null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
  	// Create obj1, but only declare handle for obj2
    Object obj2;
    Object obj1 = Object::type_id::create("obj1");
    obj1.randomize();
    `uvm_info("TEST", $sformatf("Obj1.print: %s", obj1.convert2string()), UVM_LOW)
    
    // Use $cast to clone obj1 into obj2
    $cast(obj2, obj1.clone());
    `uvm_info("TEST", "After clone", UVM_LOW)
    `uvm_info("TEST", $sformatf("Obj2.print: %s", obj2.convert2string()), UVM_LOW)
  endfunction
endclass

module tb;
	initial begin
		run_test("base_test");
	end
endmodule
 Simulation Log
ncsim> run
UVM_INFO @ 0: reporter [RNTST] Running test base_test...
UVM_INFO testbench.sv(105) @ 0: uvm_test_top [TEST] Obj1.print:  m_name=obj1 m_bool=TRUE m_mode=0xe m_data[0]=0xf4 m_data[1]=0xe m_data[2]=0x58 m_data[3]=0xbd
UVM_INFO testbench.sv(20) @ 0: reporter [m_pkt] In Packet::do_copy()
UVM_INFO testbench.sv(86) @ 0: reporter [obj1] In Object::do_copy()
UVM_INFO testbench.sv(108) @ 0: uvm_test_top [TEST] After clone
UVM_INFO testbench.sv(109) @ 0: uvm_test_top [TEST] Obj2.print:  m_name=obj1 m_bool=TRUE m_mode=0xe m_data[0]=0xf4 m_data[1]=0xe m_data[2]=0x58 m_data[3]=0xbd
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_report_server.svh(847) @ 0: reporter [UVM/REPORT/SERVER]

SystemVerilog repeat

A given set of statements can be executed N number of times with a repeat construct.

Syntax


	repeat (<number>) 
		// Single Statement

	repeat (<number>) begin
		// Multiple Statements
	end

Example #1


module tb;
	initial begin
		repeat (5) begin
			$display ("Repeat this statement");
		end
	end
endmodule
 Simulation Log
ncsim> run
Repeat this statement
Repeat this statement
Repeat this statement
Repeat this statement
Repeat this statement
ncsim: *W,RNQUIE: Simulation is complete.

A repeat loop can also be implemented using a for loop but is more verbose. If the variable i is not required to be referenced inside the loop, a repeat loop would be more suitable.


	for (int i = 0; i < number; i++) begin
		// Code
	end

In the code shown below, we have a repeat loop to wait for a given number of clock cycles.


module tb;
	bit clk;
	always #10 clk = ~clk;
	
	initial begin
		bit [2:0] num = $random;
		
		$display ("[%0t] Repeat loop is going to start with num = %0d", $time, num);
		repeat (num) @(posedge clk);
		$display ("[%0t] Repeat loop has finished", $time);
		$finish;
	end
endmodule

In this example, the clock period is 20 ns, and the first posedge of clock happens at 10 ns. Next 3 posedge of clock happens at 30ns, 50ns and 70ns after which the initial block ends. So, this repeat loop successfully waits until 4 posedge of clocks are over.

 Simulation Log
ncsim> run
[0] Repeat loop is going to start with num = 4
[70] Repeat loop has finished
Simulation complete via $finish(1) at time 70 NS + 0

SystemVerilog Abstract Class

SystemVerilog prohibits a class declared as virtual to be directly instantiated and is called an abstract class.

Syntax


virtual class <class_name>
	// class definition
endclass

However, this class can be extended to form other sub-classes which can then be instantiated. This is useful to enforce testcase developers to always extend a base class to form another class for their needs. So base classes are usually declared asvirtual although it is not mandatory.

Normal Class Example


class BaseClass;
	int data;
	
	function new();
		data = 32'hc0de_c0de;
	endfunction
endclass

module tb;
	BaseClass base;
	initial begin
		base = new();
		$display ("data=0x%0h", base.data);
	end
endmodule

Read more: SystemVerilog Abstract Class

SystemVerilog Static Constraints

Just like static variables in a class, constraints can be declared as static. A static constraint is shared across all the class instances.

Constraints are affected by the static keyword only if they are turned on and off using constraint_mode() method. When a non-static constraint is turned off using this method, the constraint is turned off in that particular instance of the class which calls the method. But, when a static constraint is turned off and on using this method, the constraint is turned off and on in all the instances of the class.

A constraint block can be declared as static by including the static keyword in its definition.

Syntax


class [class_name];
	...
	
	static constraint [constraint_name] [definition]
endclass

Next, we'll compare non-static constraints with static constraints and see how they differ.

Read more: SystemVerilog Static Constraints

  1. SystemVerilog solve before
  2. SystemVerilog foreach Constraint
  3. SystemVerilog Implication Constraint
  4. Verilog scalar and vector
  5. Verilog case statement

Page 21 of 63

  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
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