You are on page 1of 21

Advanced

Interfaces
By Rashmi B K
Agenda
• Why we use interface?
• Testbench with physical interface.
• Testbench with virtual interface.
• Modport
• Clocking block
• Connecting the testbench to interface in port list.
• Connecting test to interface with XMR.
• Using Typedef with virtual interface
• Procedural code in interface
• Limitation of interface code
Why we use interface?
• Abstraction and Encapsulation:
• Interfaces allow you to abstract away the details of signal connections and behaviors between
modules or blocks.
• By encapsulating signals and their associated behaviors within an interface, you can hide the
implementation details from the module using the interface..

• Modularity and Reusability:


• Interfaces promote modularity in your design. You can define an interface once and then reuse
it in multiple modules or designs..

• Flexibility and Parametrization:


• Interfaces can be parameterized to accommodate different configurations or variations of the
same interface.
• Parametric interfaces allow you to adapt the interface to specific requirements easily.
• Improved Testing and Verification:
• Interfaces make it easier to define a standard set of signals for communication between
modules.
• Testbenches can use the same interface to interact with different DUTs (Design Under Test),
making it more convenient to write and reuse testbench code.

• Hierarchy and Connectivity:


• Interfaces also help in maintaining the hierarchy of the design by clearly defining the
communication points between different levels of the hierarchy.
Example code

interface MemoryInterface; module CPU;


logic clk; // Instantiate the interface
logic rst; MemoryInterface mem_intf();
logic [31:0] address;
// Connect the interface to the memory module
logic [31:0] data;
Memory memory (
// Specify behavior using modport
.clk(mem_intf.clk),
modport master (input clk, input rst, output address, input data);
.rst(mem_intf.rst),
modport slave (input clk, input rst, input address, output data);
endinterface
.address(mem_intf.address),
.data(mem_intf.data)

module Memory (input clk, input rst, input [31:0] address, inout );
[31:0] data);
// CPU logic using the memory interface
// Memory implementation goes here
// ...
endmodule
endmodule
Testbench with physical interface
// demo interface with 2 inputs and 1 output. module tb_top(); Output:
interface demo_intf; demo_intf intf();
logic in1; ex_dut dut(intf);
initial begin
logic in2;
intf.in1 <= 1'b1;
logic out1;
intf.in2 <= 1’b0;
endinterface //demo_intf
$monitor("in1 = %b, in2 = %b, out1 =
%b",intf.in1, intf.in2, intf.out1);
// example rtl which outputs and of 2 inputs #20;
module ex_dut(demo_intf intf); intf.in1 <= 1'b1;
assign intf.out1 = intf.in1 & intf.in2; intf.in2 <= 1’b1;
endmodule $monitor("in1 = %b, in2 = %b, out1 =
%b",intf.in1, intf.in2, intf.out1);
end
endmodule
Virtual Interface
• The most common use for a virtual interface is to allow objects in a testbench to refer to
items in a replicated interface using a generic handle rather than the actual name.
• Virtual interfaces are the only mechanism that can bridge the dynamic world of objects
with the static world of modules and interfaces.
Testbench with virtual interface

interface color_ifc; module test();


Driver d; Output:
logic r,o,y,g,b,i,v; color_ifc c_ifc();
endinterface bit [6:0]r_data;
class Driver; initial begin
d = new(c_ifc);
virtual color_ifc v_ifc; // Pass interface
// Pointer to RTL instance d.send(42);
$display("sent data is 42");
function new(input virtual color_ifc c_ifc);
receive(r_data);
v_ifc = c_ifc; $display("Received data is %0d",r_data);
endfunction end
function void receive(output logic[6:0] data);
task send(input logic [6:0] data);
{v_ifc.r, v_ifc.o, v_ifc.y, v_ifc.g, v_ifc.b, v_ifc.i, data={c_ifc.r,c_ifc.o,c_ifc.y,c_ifc.g,c_ifc.b,c_ifc.i,c_
v_ifc.v}=data; ifc.v};
endfunction
endtask endmodule
endclass
Modport
• Modport is used to provide direction to signals in a interface.
• Also, It allows you to control which signals within an interface can be accessed by
modules or other interfaces.
• Advantages of Modport:
 Encapsulation and Abstraction.
 Access Control.
 Improved Readability.
 Reusability.
Example for modport
interface intf( input logic clk); module tb_top;
bit clk;
logic [7:0] data_in; intf vif(clk);
logic [7:0] data_out; sample_dut dut(vif);
logic [3:0] addr; always #10 clk = ~clk;
logic rw; initial begin: drive
// Define the modports @(negedge clk);
modport dut (input clk, input addr, rw, data_in, output vif.rw = 1'b1;
data_out); vif.addr = 4'ha;
vif.data_in = 8'h2f;
modport tb(input clk, data_out, output addr, rw, data_in); #20;
Endinterface @(negedge clk);
vif.rw = 1'b1;
vif.addr = 4'h3;
// Sample dut using interface defined above vif.data_in = 8'h11;
module sample_dut(intf.dut vif); end
reg [7:0] mem [0:15];
always@(posedge clk) begin: monitor
always @(posedge vif.clk) begin $display("Sampled signals at t = %0t", $time);
if(vif.rw) begin $strobe("rw = %b, addr = %0h, data_in= %0h, data_out =
%0h",
mem[vif.addr] <= vif.data_in; vif.rw, vif.addr, vif.data_in, vif.data_out);
end end
else begin
initial begin
vif.data_out <= mem[vif.addr]; #200;
end $finish;
end end
endmodule
endmodule
Clocking block
• Clocking blocks provide a structured way to encapsulate all clock-related logic and
constraints within a module, making the code more organized and readable.
• Clocking blocks can be defined once and reused across different modules or projects,
promoting modularity and reducing redundancy in code.
• Clocking block uses Input skew and output skew particularly for managing clock domain
crossings (CDC) and ensuring that signals meet timing requirements in a digital design.
• Input skew - If an input skew is specified then the signal is sampled at skew time units
before the clock event.
• Output skew – output signals are driven skew simulation time units after the
corresponding clock event.
interface mem_intrf(input bit clk_i,rst_i);
clocking mon_cb@(posedge clk_i);
logic valid_i;
logic ready_o; default input #0 output #0;
logic [`WIDTH-1:0] wdata_i;
input addr_i;
logic [`WIDTH-1:0]rdata_o;
logic wr_en_i; input wdata_i;
logic [`ADDR_WIDTH-1:0]addr_i;
input valid_i;
clocking bfm_cb@(posedge clk_i); input wr_en_i;
default input #0 output #1;
input ready_o;
output addr_i;// we can write addr_i
output wdata_i; input rdata_o;
output valid_i;
endclocking
output wr_en_i;
input ready_o;//we can read ready_o endinterface
input rdata_o;
endclocking
Connecting the testbench to interface in port list
interface bus_ifc(); module top;
reg [6:0]data_x;
logic [6:0]data;
bus_ifc bus();
endinterface test t1(bus);
program test(bus_ifc bus); dut d1(bus,data_x);
initial begin
initial begin data_x=67;
$display(bus.data); end
endmodule
end
endprogram
module dut(bus_ifc bus,input data_i); Output:
input [6:0]data_i;
initial begin
bus.data=data_i;
end
endmodule
Connecting test to interface with XMR
• Your test needs to connect to the physical interface in the harness, so use a cross module
reference (XMR) and a virtual interface in the program block.
• You must use a virtual interface so you can assign it the physical interface in the top level
module.
Connecting test to interface with XMR
interface bus_ifc(); module top;
reg [6:0]data_x;
logic [6:0]data; bus_ifc bus();//Instantiate the interface
endinterface test t1();
dut d1(bus,data_x);
program test(); initial begin
virtual bus_ifc v_bus=top.bus;//cross model reference data_x=67;
end
initial begin
endmodule
$display(bus.data);
end Output:
endprogram
module dut(bus_ifc bus,input data_i);
input [6:0]data_i;
initial begin
bus.data=data_i;
end
endmodule
Using Typedef with virtual interface

• We can reduce the amount of typing.


interface bus_ifc(); module top;
logic [6:0]data; reg [6:0]data_x;
endinterface bus_ifc bus();//Instantiate the interface
typedef virtual bus_ifc v_if;//using typedef for creating v_if test t1();
program test(); dut d1(bus,data_x);
v_if v_bus=top.bus;//instantiating the virtual interface initial begin
using v_if data_x=97;
initial begin end
$display(bus.data); endmodule
end
endprogram
module dut(bus_ifc bus,input data_i); Output:
input [6:0]data_i;
initial begin
bus.data=data_i;
end
endmodule
Parameterized Interfaces and Virtual Interfaces
// demo interface with 2 inputs and 1 output. module tb_top();
parameter WIDTH=3;
interface demo_intf #(.WIDTH(WIDTH))intf();
demo_intf#(WIDTH=8);//parameterized ex_dut dut(intf);
interface initial begin
$monitor("in1 = %d, in2 = %d, out1 =
logic [WIDTH-1:0]in1; %d",intf.in1, intf.in2, intf.out1);
logic [WIDTH-1:0]in2; intf.in1 <= 8;
Output:
intf.in2 <= 9;
logic [WIDTH-1:0]out1; #20;
endinterface //demo_intf intf.in1 <= 10;
intf.in2 <= 6;
// example rtl which outputs sum of 2 inputs #20;
intf.in1 <= 4;
module ex_dut(demo_intf intf);
intf.in2 <= 9;
assign intf.out1 = intf.in1 + intf.in2; end
endmodule
endmodule
Procedural code in interface
• An interface can contain code such as routines, assertions, and initial and always blocks.
• The interface block can contain the signals and also routines to perform commands such as a read
or write.
• A task or function is imported into a modport so that it is then visible to any block that uses the
modport.
• One of the limitation of procedural code in interface is not all synthesis tools can handle routines in
an interface.
• You can verify a protocol with assertions in an interface. An assertion can check for illegal
combinations, such as protocol violations and unknown values. These can display state information
and stop simulation immediately so that you can easily debug the problem.
Limitation of interface code
• Lack of Inheritance: Interfaces in SystemVerilog do not support inheritance.
• Inability to Contain Variables: An interface cannot contain variables or other data
objects. It is primarily meant for specifying the port list and the protocol between
modules.
• Limited Hierarchical Nesting: While you can nest interfaces inside modules, it's not
possible to nest them hierarchically within other interfaces. This can be restrictive when
dealing with complex hierarchical designs.
• Complexity in Interface Instantiation: When you instantiate a module that uses an
interface, you need to connect the interface signals to the corresponding signals in the
parent module explicitly.
Thank you

You might also like