Siemens Digital Industries Software
SystemVerilog Interface Intro
A SystemVerilog interface allows us to group a number of signals together and represent them as a single port. All these signals can be declared and maintained at a single place and be easily maintained. Signals within an interface are accessed by the interface instance handle.
Interface blocks are defined and described within interface and endinterface keywords. It can be instantiated like a module with or without ports.
Interfaces can also have functions, tasks, variables, and parameters making it more like a class template. It also has the ability to define policies of directional information for different module ports via the modport construct along with testbench synchronization capabilities with clocking blocks . It can also have assertions, coverage recording and other protocol checking elements. Last but not the least, it can also contain initial and always procedures and continuous assign statements.
A module cannot be instantiated in an interface ! But an interface can be instantiated within a module.
SystemVerilog is now popular as a HDL and let's see two cases where an interface is used with the same design in both Verilog and SystemVerilog. To keep things simple in this introductory example, we'll just create a simple interface.
Interface with a Verilog Design
Let us see how an interface can be used in the testbench and connected to a standard Verilog design with a portlist. The code shown below is a design of an up-down counter in Verilog. This module accepts a parameter to decide the width of the counter. It also accepts an input load value load that is loaded into the counter only when load_en is 1.
The counter starts counting down when the input down is 1 and otherwise it counts upwards. The rollover output indicates when the counter either transitions from a max_value to 0 or a 0 to max_value.
An interface called cnt_if is declared below with a parameterizable value as the width of the counter signal. This task also has a task init() to assign values
Interface with a SystemVerilog design
Let us now see how an interface can be used in the testbench and be connected to a SystemVerilog design module. SystemVerilog allows a module to accept an interface as the portlist instead of individual signals. In the design example shown below, we have substituted the portlist of counter_ud with an interface handle which is used to define design functionality.
The design instance is passed an interface handle called cnt_if and is used to drive inputs to the design from the testbench. The same interface handle can be used to monitor outputs from the design if required.
What makes it different from Verilog ?
Verilog connects between different modules through its module ports . For large designs, this method of connection can become more time consuming and repetitious. Some of these ports may include signals related to bus protocols like AXI/AHB, clock and reset pins, signals to and from RAM/memory and to other peripheral devices.
Using Verilog Ports
This is the traditional way of port connection in Verilog.
Let us consider a scenario where there are twelve slaves in the design shown above. If there is a change made at the d_slave module ports, then the change has to be reflected in all the twelve slave instance connections in d_top as well.
Some cons of using Verilog port method for connection are :
- Tedious to trace, debug and maintain
- Too easy to make or break design functionality
- Changes in design requirements may require modifications in multiple modules
- Duplication needed in multiple modules, communication protocols, and other places
Using SystemVerilog Interface
Note that the module d_top simply uses the interface to connect with the slave instances instead of repetitively declaring connection to each signal of the slave block as shown before.
Now, if there is a change to one of the signals in the slave interface, it is automatically applied to all the instances. In SystemVerilog, the module portlist can also have a port with an interface type instead of the usual input , output and inout .
In the example below an interface named myInterface with an empty port list is created and instantiated within the top level testbench module. It is also fine to omit the parenthesis for an empty port list and instead truncate the statement with a semicolon
A single interface called if0 can be instantiated and signals within this interface should be accessed by referencing this handle. This can then be used to drive and sample signals going to the DUT.
We can also have an array of interfaces. Here this array is referred by the name wb_if which has 4 instances of the interface.
When an interface is referenced as a port, the variables and nets in it are assumed to have ref and inout access respectively. If same identifiers are used as interface instance name and port name in the design, then implicit port connections can also be used.
- Search forums
Follow along with the video below to see how to install our site as a web app on your home screen.
Note: This feature currently requires accessing the site using the built-in Safari browser.
Welcome to EDAboard.com
Welcome to our site edaboard.com is an international electronics discussion forum focused on eda software, circuits, schematics, books, theory, papers, asic, pld, 8051, dsp, network, rf, analog design, pcb, service manuals... and a whole lot more to participate you need to register. registration is free. click here to register now..
- Digital Design and Embedded Programming
- ASIC Design Methodologies and Tools (Digital)
SystemVerilog Interface signal assignment
- Thread starter ghertz
- Start date Nov 18, 2019
- Nov 18, 2019
Newbie level 5
I'd like to eliminate assignment of signals to every single instantiation of the interface -- see comments  and  in topmost code snippet. What is the best way to accomplish this? One way is to assign signal to a common interface and then use this common interface to connect to the other two interfaces -- need to try this out. Code: module top ( input [1:0] in, output [2:0] out ); //wires and registers wire [1:0] module_a_out; wire [1:0] module_b_out; //IO assignments assign out = module_a_out | module_b_out; Myinterface Myif1(); Myinterface Myif2(); //interface 1 to module a -- better way to accomplish this? assign Myif1.in = in; assign module_a_out = Myif1.out //interface 2 to module b -- better way to accomplish this? assign Myif2.in = in; assign module_b_out = Myif2.out module_a module_a (.my_if_s(Myif1)); module_b module_b (.my_if_s(Myif2)); endmodule Code: module module_a(Myinterface.S my_if_s); <something1> endmodule Code: module module_b(Myinterface.S my_if_s); <something2> endmodule Code: interface Myinterface; logic [1:0] in; logic [1:0] out; //master modport M(output in,input out); modport S(input in,output out); endinterface: Myinterface
Advanced Member level 3
A quick improvement is getting rid of the intermediate assignments using Code: assign out = Myif1.out | Myif2.out ; As you have discovered, interfaces work best is you can keep connections together as a single instance. Code: module top ( MyInterface Myif) ); module_a module_a (.my_if_s(Myif)); module_b module_b (.my_if_s(Myif)); endmodule interface Myinterface; logic [1:0] in; wor [1:0] out; //master modport M(output in,input out); modport S(input in,output out); endinterface: Myinterface module module_a(Myinterface.S my_if_s); // something assign my_if_s.out = <expression>; // get or'ed with all drivers endmodule
1. I'm trying to avoid any combination logic in the interface. I'm assuming wor would get synthesized into an OR gate. 2. What happens when a different signal from a different bus acts as a select? For example: Code: always_comb begin if(my_another_if.select == 11) begin myif.out = myif1.out; end else if(my_another_if.select == 10) begin myif.out = myif2.out; end else begin myif.out = 2'd9; end end I was thinking about breaking up the interface into 4 different interfaces as shown below. Should I be worried about using this technique ? I want to use this because I can eliminate assigning each and every input from top interface to multiple slave interface. I can do this because I'm separating the input and output part of the slave interface. And, when it comes to the slave outputs (and top level slave output), I could pass it up to the top and use the above code to get my final slave output. Am I defeating the purpose of using interfaces by using it in weird ways? And there are no mod-ports in these interface definitions. Is that a bad thing? I haven't used interfaces before. I'm afraid that as the code grows, I'll have to rethink my whole approach. Code: //slave input interface myif_s_i; logic abc; logic pqr; <no modport required> endinterface //slave output interface myif_s_o; logic abc; logic pqr; <no modport required> endinterface //master input interface myif_m_i; logic abc; logic pqr; <no modport required> endinterface //master output interface myif_m_o; logic abc; logic pqr; <no modport required> endinterface
Part and Inventory Search
Welcome to edaboard.com.
System Verilog interface
Unlike Verilog that has module ports for communication, System Verilog provides an interface construct that simply contains a bundle of sets of signals. This encapsulates signals and communicates with design, testbench components.
Advantages of SystemVerilog interfaces
- In Verilog for the addition of new signals, it has to be manually changed everywhere that module has been instantiated. System Verilog made it easier to add new signals in the interface block for existing connections.
- It has increased re-usability across the projects.
- A set of signals can be easily shared across the components bypassing its handle.
- It provides directional information (modports) and timing information (clocking blocks).
- Interfaces can contain parameters, variables, functional coverage, assertions, tasks and functions.
- Interfaces can contain procedural initial and always blocks and continuous assign statements.
Writing an Interface
A basic interface, a parameterized interface, full adder example.
To understand how interfaces can be used in the environment, a full adder is constructed using two half adders. In case any new signal has to be added (like enable), it can be easily added to the interface without touching the port list in the module.
Full adder example without using an interface
Full adder example using an interface
Interface example using clk, why is the logic data type used for the signal declaration or why bit data type is not used.
A bit data type is a 2-state data type that can have either 0 or 1 value. For incorrect RTL behavior like X or Z testbench would have sampled as 0. So, it needs a 4-state data type that can capture all 4 states 0, 1, X, or Z.
System Verilog Tutorials
SystemVerilog assignment to interface?
A virtual interface might give you what you are looking for. But it probably isn't synthesizable.
Using SystemVerilog interfaces to connect logic in Vivado Synthesis
Feb 16, 2023 • knowledge, information.
What are Interfaces?
SystemVerilog interfaces were developed to allow for easier connectivity between hierarchies in your design. One way to think of them is as collections of pins that are common to many modules. Instead of having to define many pins on each module, they are defined once in an interface, and then the interface is defined on the module instead of pins. If the set of signals is later changed, only the interface needs to change.
This allows a lot of information to be condensed into a smaller amount of lines, but it can be a little difficult to write for the first time. It can also be difficult to interpret an interface written by someone else when you are looking at it for the first time. This article will explain the basics of interfaces and how to correctly write them in Vivado.
We will be converting a small testcase without interfaces into one that uses interfaces. The example RTL stages for this will be in the last section of the article.
The schematic for the original testcase appears as follows:
In order to proceed, the interface must first be defined. All that is needed are the names of the signals that are common to the multiple modules that will be replaced by the interface. Once that list is known, the interface is declared as follows:
The code above has declared an interface called "my_int". It has also declared four signals, one bit called "sel", and three 10 bit buses called data1, data2, and result. These are the pins of the modules that will be replaced by the interface. Note that even though the "clk" signal is used in both modules, the interface is not using the clk signal. Putting control signals in an interface will work, but it is a matter of personal preference. This author prefers to leave the clock signals separate from the interface.
Using the Interface
Once the interface has been declared, it can be used like any port of a module. For lower level modules where the ports will be replaced with the interface, the coding style should be changed as follows:
Note that instead of declaring the port as an input or output, it is declared as type "my_int" which was the name given to the interface. It has also been given the instance name of int1.
Because the pins for the lower level have been removed, they can no longer be referenced the same way. Instead of referencing the pins directly, they need to be referenced in the context of the interface.
The syntax for this is "<int_name>.<pin_name>". For example, in the original RTL, the output "result" was assigned either data1 or data2 depending on the sel input.
Now, it needs to be changed to the following:
After the lower levels have been modified to change the pins to interfaces, and references to those pins have been changed to reference the interface, the upper level that instantiates those modules also needs to be modified.
Before using interfaces, the module pins at the top level would have been connected to signals that were declared in the design. So now, instead of connecting signals, we will connect interfaces. The first thing that needs to be done is to declare an interface of the same type.
The code above declares an interface of type "my_int" and gives it an instance name of "int3".
As before, all references to the signals inside this interface need to be done with the "<interface_name>.<pin_name>" syntax.
Next, the lower level is instantiated.
The RTL above instantiates the bottom2 module giving it an instance name of u1. The interface "int1" that was declared in the bottom2 module is now associated with the interface "int3" that has been declared in the upper level. After making these changes, the schematic for the design will look like the following:
After adding the interface, the tool has created the correct connections, but you might notice that the schematic looks a little odd. The data1 and data2 lines from both lower levels appear to be driving the same net. If you tunnel down into those modules, you will see that there is no multiple driver issue as one of those modules treats data1 and data2 as an input.
The reason that the schematic looks odd is that the interface created did not tell the tool which pins were acting as inputs and which were acting as outputs. When it created the connections, the tool did not know exactly how to hook up the pins, so it made the connections and later when the behavior was analyzed, the tool figured out the direction of the pins.
While this will work, it is highly recommended that input/output information for the interface be given to the tool. This is accomplished through the use of modports. Modports are declared inside of interfaces and they tell the tool which signals are inputs and which are outputs. Because different modules will have pins with different directions, multiple modports per interface are usually declared.
The syntax for a modport is:
modport <name> (<input.output> <pin name>, <input/output> <pin name>....);
For example, the following RTL creates a modport called b1, and makes the result signal an output and the other signals all inputs.
The modport is then used in the declaration of the interface in the lower level port list.
The code above tells the tool the following:
- bottom2 is going to use the interface my_int, and to give it an instance name called "int1"
- In this interface, the result will be an output
- sel, data1, and data2 will be inputs.
Once the changes are complete, the new schematic will look like the following:
This article was written to show how useful Interfaces can be in hooking up logic with similar signals, but this is not the only use for interfaces. In addition, interfaces can use many features including tasks and functions, and can even be parametrized.
We will explore these other features in future articles.
Original RTL with no interfaces:
Design with first attempt at an interface:
Design with use of modports:
- Number of Views 1.1K
- Number of Views 436
- Number of Views 2.64K
- Number of Views 3.61K
- Number of Views 791
- AXI Basics 1 - Introduction to AXI
- 72775 - Vivado IP Change Log Master Release Article
- Debugging PCIe Issues using lspci and setpci
- 65444 - Xilinx PCI Express DMA Drivers and Software Guide
- Export IP Invalid Argument / Revision Number Overflow Issue (Y2K22)
Was this article helpful?