VLSI-SV-K1-3 by kasueducationalsociety




   iTechnology & Learning is the only online-training portal that trains the fresh
   engineers on the advanced verification methodologies and System Verilog.
   In addition to the advanced Digital Design Methodology, Verilog, VHDL, ASIC &
   FPGA's design flows, STA and CMOS fundamentals, we provide home self
   learning materials to the requested candidates and our portal is open 24/7 for any
   assistance:please- mail_us@ kasu.ravi.sankar.reddy@gmail.com                    or
   call us:917200507523.

                                        iTechnology & Learning
  S.NO                        TOPIC    START   END
    1       INTERFACE
    2       PORTS
    4       CLOCKING BLOCK
    6       SVTB N VERILOG DUT
OVER VIEW                   OVERVIEW
The communication between blocks of a digital system is a critical area. In Verilog, modules are
connected using module ports. For large modules, this is not productive as it involves

  Manually connecting hundreds of ports may lead to errors.
  Detailed knowledge of all the port is required.
  Difficult to change if the design changes.
  More time consuming.
  Most port declaration work is duplicated in many modules.

Let us see a verilog example:

  module Dut (input clk, read, enable,
         Input [7:0] addr,
         output [7:0] data);
    assign data = temp1 ? temp2 : temp3 ;
    always @(posedge clk)
    module Testbench(input clk,
         Output read, enable,
         output [7:0] addr,
         input [7:0] data );
Integrating the above two modules in top module.
1 module top();
2 reg clk;
3 wire read, enable;
4 wire [7:0] addr;
5 wire [7:0] data;
7 Dut D (clk,read,enable,Addr,data);
9 Testbench TB(clk,read,enable,Addr,data);
11 endmodule

All the connection clk, read, enable, addr, data are done manually. Line 7 and 9 has same code structure
which is duplicating work. If a new port is added, it needs changes in DUT ports, TestBench Ports, and in
7, 10 lines of Top module. This is time-consuming and maintaining it is complex as the port lists

To resolve the above issues, SystemVerilog added a new powerful features called interface. Interface
encapsulates the interconnection and communication between blocks.

Interface declaration for the above example:

  interface intf #(parameter BW = 8)(input clk);
    logic read, enable;
    logic [BW -1 :0] addr,data;
  endinterface :intf
Here the signals read, enable, addr, data are grouped in to "intf". Interfaces can have direction as input,
output and inout also. In the above example, clk signal is used as input to interface. Interfaces can also
have parameters like modules. Interface declaration is just like a module declaration. Uses keywords
interface, endinterface for defining. Inside a module, use hierarchical names for signals in an interface.

TIP: Use wire type in case of multiple drivers. Use logic type in case of a single driver.
Let use see the DUT and Testbench modules using the above declared interface.

 module Dut (intf dut_if); // declaring the interface

   always @(posedge dut_if.clk)
     if(dut_if.read) // sampling the signal
      $display(" Read is asserted");


 module Testbench(intf tb_if);

     tb_if.read = 0;
     repeat(3) #20 tb_if.read = ~tb_if.read;// driving a signal

Integrating the above two modules in top module.

 module top();
   bit clk;

      forever #5 clk = ~clk;

   intf bus_if(clk); // interface instantiation
   Dut d(bus_if); // use interface for connecting D and TB
   Testbench TB (bus_if);


See, how much code we got reduced in this small example itself. In the above example, I demonstrated
the connectivity between DUT and TestBench. Interfaces can also be used for connectivity between the
DUT sub modules also.

Advantages Of Using Inteface:

   An interface can be passed as single item.
   It allows structured information flow between blocks.
   It can contain anything that could be in a module except other module definitions or instance.
   Port definitions are independent from modules.
   Increases the reusability.
   It Interface can be declared in a separate file and can be compiled separately.
   Interfaces can contain tasks and functions; with this methods shared by all modules connecting to this
information can be in one place.
   Interface can contain protocol checking using assertions and functional coverage blocks.
   Reduces errors which can cause during module connections.
   Easy to add or remove a signal. Easy maintainability.
Interface Ports

In the previous example, signal clk is declared as port to the interface. Interface Ports work similar to the
module ports. Members of port list can be connected externally by name or position when the interface
is instantiated as shown in line 3 of module top code.


In the above example, we did not mention the direction of signals. The direction of the clk signal in input
for both the Dut and Testbench modules. But for the rest of the signals, the direction is not same. To
specify the direction of the signal w.r.t module which uses interface instead of port list, modports are
used. Modport restrict interface access within a module based on the direction declared. Directions of
signals are specified as seen from the module. In the modeport list, only signal names are used.

Let us see the modport usage with the previous example. 2 mod port definitions are needed, one for
DUT and other for TestBench.

Interface declaration for the above example:

  interface intf (input clk);
    logic read, enable,
    logic [7:0] addr,data;

    modport dut (input read,enable,addr,output data);
    modport tb (output read,enable,addr,input data);
  endinterface :intf

In this example, the modport name selects the appropriate directional information for the interface
signals accessed in the module header. Modport selection can be done in two ways. One at Module
declaration , other at instantication.
Modport Selection Duing Module Definition.

 module Dut (intf.dut dut_if); // declaring the interface with modport
   assign dut_if.data = temp1 ? temp2 : temp3 ; // using the signal in interface
   always @(posedge intf.clk)

 module Testbench(intf.tb tb_if);

 1 module top();
 2 logic clk;
 3 intf bus_if(clk); // interface instantiation
 4 Dut d(bus_if); // Pass the interface
 5 Testbench TB (Bus_if); // Pass the interface
 6 endmodule

Modport Selection Duing Module Instance.

  module Dut (intf dut_if); // declaring the interface
    assign dut_if.data = temp1 ? temp2 : temp3 ; // using the signal in interface
    always @(posedge intf.clk)

  module Testbench(intf tb_if);
  1 module top();
  2 logic clk;
  3 intf bus_if(clk); // interface instantiation
  4 Dut d(bus_if.dut); // Pass the modport into the module
  5 Testbench TB (Bus_if.tb); // Pass the modport into the module
  6 endmodule

A mod port can also define expressions. They can also define their own names. Module can use the
modport declared name. For example

  modport dut (input read,enable,.addr(2),output .d(data[1:5]);

  module dut(intf.dut dut_if);
  assign dut_if.d = temp; // using the signal name declared by modport.


Methods In Interfaces

Interfaces can include task and function definitions. This allows a more abstract level of modeling.

  interface intf (input clk);
    logic read, enable,
    logic [7:0] addr,data;

     task masterRead(input logic [7:0] raddr); // masterRead method
     endtask: masterRead

     task slaveRead; // slaveRead method
     endtask: slaveRead

  endinterface :intf

Clocking Blocks

SystemVerilog adds the clocking block that identifies clock signals, and captures the timing and
synchronization requirements of the blocks being modeled. A clocking block assembles signals that are
synchronous to a particular clock, and makes their timing explicit. The clocking block is a key element in
a cycle-based methodology, which enables users to write testbenches at a higher level of abstraction.
Simulation is faster with cycle based methodology.

Depending on the environment, a testbench can contain one or more clocking blocks, each containing
its own clock plus an arbitrary number of signals. These operations are as follows:

    Synchronous events
    Input sampling
    Synchronous drives

  clocking cb @(posedge clk);
    default input #10ns output #2ns;

    output read,enable,addr;
    input negedge data;

In the above example, the first line declares a clocking block called cb that is to be clocked on the
positive edge of the signal clk. The second line specifies that by default all signals in the clocking block
shall use a 10ns input skew and a 2ns output skew by default. The next line adds three output signals to
the clocking block: read, enable and addr. The fourth line adds the signal data to the clocking block as
input. Fourth line also contains negedge which overrides the skew ,so that data is sampled on the
negedge of the clk.


If an input skew is specified then the signal is sampled at skew time units before the clock event. If
output skew is specified, then output (or inout) signals are driven skew time units after the
corresponding clock event. A skew must be a constant expression, and can be specified as a parameter.
Skew can be specified in 3 ways.
   #d : The skew is d time units. The time unit depends on the timescale of the block.
   #dns : The skew is d nano seconds.
   #1step : Sampling is done in the preponed region of current time stamp.

If skew is not specified, default input skew is 1step and output skew is 0.

Specifying a clocking block using a SystemVerilog interface can significantly reduce the amount of code
needed to connect the TestBench without race condition. Clocking blocks add an extra level of signal
hierarchy while accessing signals.

Interface declaration with clocking block:

  interface intf (input clk);
     logic read, enable,
     logic [7:0] addr,data;

     clocking cb @(posedge clock); // clocking block for testbench
       default input #10ns output #2ns;

       output read,enable,addr;
       input data;

     modport dut (input read,enable,addr,output data);
     modport tb (clocking cb); // synchronous testbench modport

  endinterface :intf
    module testbench(intf.tb tb_if);
    tb_if.cb.read <= 1; //writing to synchronous signal read

Cycle Delay

The ## operator can be used to delay execution by a specified number of clocking events, or clock
cycles. What constitutes a cycle is determined by the default clocking in effect of module, interface, or

## <integer_expression>;
##3; // wait 3 cycles
##1 tb_if.addr <= 8'h00;// waits for 1 cycle and then writes address.

Using clocking blocks,cycle delays syntax gets reduced.
Insted of writing

 repeat(3) @(posedge clock); sync_block.a <= 1;

Just use

 ##3 sync_block.a <= 1;

To schedule the assignment after 3 clocks,Just use,

 sync_block.a <= ##3 1;

To simply wait for 3 clock cycles,

 ##3; can be used.

But there may be more than one clocking block is defined in a project.
##3 waits for 3 clocks cycles,of the block which is defined as default.

 default clocking sync_block @(posedge clock);

Virtual Interfaces

Virtual interfaces provide a mechanism for separating abstract models and test programs from the
actual signals that make up the design. A virtual interface allows the same subprogram to operate on
different portions of a design, and to dynamically control the set of signals associated with the
subprogram. Instead of referring to the actual set of signals directly, users are able to manipulate a set
of virtual signals.

  1 module testbench(intf.tb tb_if);
  2 virtual interface intf.tb local_if; // virtual interface.
  3    ....
  4 task read(virtual interface intf.tb l_if) // As argument to task
  5    ....
  6 initial
  7 begin
  8      Local_if = tb_if; // initializing virtual interface.
  9      Local_if.cb.read <= 1; //writing to synchronous signal read
  10      read(Local_if); // passing interface to task.
  11 end
  12 endmodule

In the above program, local_if is just like a pointer. It represents an interface instance. Using keyword
"virtual" , virtual interfaces instance is created. It does not have any signal. But it can hold physical
interface. Tb_if is the physical interface which is allocated during compilation time. You can drive and
sample the signals in physical interface. In line 8, the physical interface tb_if is assigned to local_if. With
this , we can drive and sample the physical signals. In line 9, read signal of tb_if is accessed using local_if.

Advantages Of Virtual Interface

1) Virtual interface can be used to make the TestBench independent of the physical interface. It
allows developing the test component independent of the DUT port while working with multi port
2) With virtual interface, we can change references to physical interface dynamically. Without virtual
interfaces, all the connectivity is determined during compilation time, and therefore can't be
randomized or reconfigured.
3) In multi port environment, it allows to access the physical interfaces using array index.
4) Physical interfaces are not allowed in object oriented programming, as physical interface is
allocated at compilation time itself. Virtual interface which are set at run time allows to do object
oriented programming with signals rather than just with variables.
5) Virtual interface variables can be passed as arguments to tasks, functions, or methods.
6) Allows to use Equality ( == ) and inequality ( != ) .

A virtual interface must be initialized before it can be used, by default, it points to null. Attempting to
use an uninitialized virtual interface will result in a run-time error.

Multi Bus Interface

If you are working on protocol which has multiple sub bus protocol, there are several ways to create

      One Big single interface with all the sub protocol signals inside it. With single interface, it is easy to
pass around the whole system. You have to name all the signals with the sub protocol prefix like
pcie_enable, Eth_enable etc. Restrict the access using clocking blocks else all signals can be accessed by
all the modules using this interface. Reusability will be very less as all the sub protocols are in one

     Using multiple interfaces, one for each sub protocol, each interface for each sub bus will increase
the complexity while passing around the system. No need to prefix the sub protocol name as the sub
protocol name is reflected in the interface name itself. With this you can only pass the sub interfaces
required by other modules. All the interfaces will be reusable as each interface represents an individual

    Using one big interface with sub multiple interfaces will be easy for passing around the system.
With this the sub interfaces can be reused for other components and other designs.
Working With Verilog Dut:

There are several ways to connect the Verilog DUT to SystemVerilog TestBench. Verilog DUT has port list
where as SystemVerilog testbenchs uses interfaces. We will discuss 2 ways of connecting Verilog DUT to
SystemVerilog TestBench.

Connecting In Top:

Verilog port list can be connected during DUT instantiation using interface hibachi signal names as
shown in following code.

// DUT in Verilog
  module Dut (input clk, read, enable,
         Input [7:0] addr,
         output [7:0] data);
    assign data = temp1 ? temp2 : temp3 ;
    always @(posedge clk)

  // SystemVerilog Code
 // interface declaration with clocking block:
  interface intf (input clk);
     logic read, enable,
     logic [7:0] addr,data;

  module testbench(intf.tb tb_if);

  // integrating in top module.
  module top();
   logic clk;

    intf bus_if(clk); // interface instantiation
    Testbench TB (bus_if); // Pass the modport into the module
    Dut d(.clk(clk),       // connect the verilog
        .read(bus_if.read), // RTL port using interface hierarchy signal name.


Connecting Using A Wrapper

We can also convert the verilog module with port list in to SystemVerilog module with interface by
creating wrapper around the verilog module.

  //wrapper for verilog DUT
  module w_dut(intf wif);
    Dut d(.clk(wif.clk),       // connect the verilog
         .read(wif.read), // RTL port using interface hierarchy signal name.
  //connecting the dut wrapper and testbench in top.
  module top();
    logic clk;
    intf bus_if(clk); // interface instantiation
    w_dut d(bus_if); // instance of dut wrapper
    Testbench TB (Bus_if);

To top