Logic Design - Interfaces in SystemVerilog (part 1)

avatar

[Edit of Image1]

Introduction

Hey it's a me again @drifter1!

Today we continue with the Logic Design series on SystemVerilog in order to cover Interfaces. The topic will be split into two parts!

So, without further ado, let's get straight into it!


Getting Into Interfaces

In the context of object-oriented programming (OOP), interfaces are groups of related methods mostly left unimplemented (abstract), which the "implementing" class then implements. Similarly, for logic design, interfaces group together signals and ports which are related, representing them as a single entity. That way it's possible to avoid repetition and simplify port lists in module definitions and instantiations, improving maintainability, readability etc.


Interface Definition

An interface is defined within the interface and endinterface keywords, as shown below.

interface [interface_name] ([port_list]);
    [signal_list]
endinterface

Port and Signal Lists

The signals defined within the interface allow for communication within the interface (intra-communication), but when communication with other interfaces (inter-communication) is required then those signals should be defined in the port list.

The ports can be defined as any type, but signals within the interface should be declared as the new logic type, that SystemVerilog provides. This type allows driving both via assign statements and in procedural blocks (e.g. always block), and supports 4-states: 0, 1, X, Z values.

Additional Features

Interfaces that only have such port and signal lists are the simplest form of interfaces. In addition to those, SystemVerilog's interfaces can also become closer to class templates by consisting of functions, tasks, variables, parameters and more. Interfaces can also contain initial and always blocks, as well as assign statements.

And let's not forget to mention:

  • Modports : used to define signal direction policies
  • Clocking Blocks : used to define testbench synchronization capabilities

which will be covered in the next sections...

Using Interfaces

Interfaces can be used in port lists or within the main body of the design or testbench.

In the port list, the name of the interface has to followed by an identifier:

module module_name (
    interface_name [identifier],
    ...
);
    // main body
endmodule

Using simple dot notation (.) it's then possible to access the various signals and ports within the module's body.

Passing interfaces to module instantiations is also quite easy. For example, passing the interface by name is done as follows:

interface_name [identifier];

module_name [instance_id] (.[identifier]([identifier]));

Modports

The access to the signals defined within the interface can be restricted using a number of modport lists, which specify the port directions for each signal. These are of course not required, and when not used the nets and variables declared within the interface are simply accessed like inout ports. But, specifying the direction can allow us to have a different access restriction scheme for cases like the system, the testbench, the master and the slave in specific protocols etc. without having to specify a whole new interface for each case.

The syntax of a modport is as follows:

modport [identifier] ([port_list]);

where the port list contains the corresponding input, output and inout ports, as well as ref ports.

Using Modports

Accessing the required modport definition from the interface is done using dot notation:

.[modport_identifier]

Thus, it's possible to completely restrict the module, by specifying the corresponding modport when declaring the interface port:

module module_name (
    interface_name.[modport_identifier] [identifier],
    ...
);
    // main body
endmodule

or only restrict the port access when connecting to the port of the module using:

[identifier].[modport_identifier]

Generic Interface

It's possible to define a generic interface in a module's port list. Such a port basically allows any interface and any modport definition to be passed to it when instantiating it.

The syntax of such a port within a module is:

module module_name (
    interface [identifier],
    ...
);
    // main body
endmodule

RESOURCES:

References

  1. https://www.chipverify.com/systemverilog/systemverilog-tutorial
  2. https://www.asic-world.com/systemverilog/tutorial.html

Images

  1. https://www.flickr.com/photos/creative_stock/5227842611

Block diagrams and other visualizations were made using draw.io


Previous articles of the series

Verilog

SystemVerilog

  • From Verilog To SystemVerilog → Data Types, Arrays, Structures, Operators and Expressions
  • Control Flow → Additional Procedural Blocks, Loops, Conditional Statements, Functions and Task Features
  • Processes → Fork - Join in Verilog and SystemVerilog, Process Control (wait fork, disable fork)
  • Events → Interprocess Communication, Events (Definition, Triggering, Waiting, Sequencing, Merging, as Arguments)
  • Semaphores and Mailboxes → Semaphores (Creation, Methods), Mailboxes (Definition, Methods)

Final words | Next up

And this is actually it for today's post!

Next time we will continue with part 2, which will cover Clocking Blocks...

See Ya!

Keep on drifting!

Posted with STEMGeeks



0
0
0.000
1 comments