A bus such as valid, ready and data repeats on every module it touches. Adding a signal then means editing every port list and every instance.
An interface groups the signals once. A modport states which side drives and which side receives each signal.
Without an interface | With an interface |
|---|---|
Every module lists valid/ready/data. | Both sides connect to one |
A new signal changes every port list. | Add the signal once in the interface. |
Direction mistakes show up late. | The modports state who may drive each signal, so a connection against them is a compile error where the tool supports interface ports. |
The interface below declares the three signals once and two modports. The producer's port has type lesson_bus_if.master, the consumer's lesson_bus_if.slave, and the top level connects one interface instance b to both.
interface lesson_bus_if;
logic valid, ready;
logic [7:0] data;
modport master (output valid, data, input ready);
modport slave (input valid, data, output ready);
endinterface
module bundled_producer (lesson_bus_if.master b);
assign b.valid = 1'b1;
assign b.data = 8'hA5;
endmodule
module bundled_consumer (lesson_bus_if.slave b, output logic [7:0] got);
assign b.ready = 1'b1;
assign got = b.valid ? b.data : 8'h00;
endmodule
module modport_connections (output wire [7:0] got);
lesson_bus_if b();
bundled_producer p (.b(b));
bundled_consumer c (.b(b), .got(got));
endmoduleRead each arrow as one signal group and the direction its driver is allowed to push it.
master: output valid, data, input ready, so the producer may assign valid and data and may only read ready.
slave: the mirror image, so the consumer may assign only ready.
One instance: both modules see the same b, so a value the producer drives is the value the consumer reads.
Driving a signal that the view declares as an input is a compile error in a tool that enforces modports:
// snippet: intentionally illegal direction, using lesson_bus_if above
module wrong_direction (lesson_bus_if.slave b);
assign b.valid = 1'b1; // illegal: valid is an input in the slave view
endmoduleKeep a fragment like this out of the legal example; compile it on its own with the interface declaration to confirm your tool rejects it.
Direction. It declares which side drives each signal, so a connection against it is caught by the compiler in tools with full interface support instead of showing up as an x in simulation.
Buses with many signals shared by several modules (memory ports and AXI-like links).
Verification environments, where one interface also connects the testbench to the DUT.
For a 2- or 3-signal link used in one place, a plain port list is simpler and works with every tool.
Where a tool does not accept interface ports, give each module scalar ports that mirror the modport directions and connect them through an interface instance, as below. Directions are then kept by review and lint, not by the compiler. If the tool lacks interfaces entirely, replace b.valid, b.ready and b.data with ordinary wires.
interface bus_if;
logic valid, ready;
logic [7:0] data;
modport master (output valid, data, input ready);
modport slave (input valid, data, output ready);
endinterface
// Port directions mirror the modports: the master side drives
// valid/data, the slave side drives ready.
module producer (output logic valid, output logic [7:0] data, input logic ready);
assign valid = 1'b1;
assign data = 8'hA5;
endmodule
module consumer (input logic valid, input logic [7:0] data, output logic ready, output logic [7:0] got);
assign ready = 1'b1;
always_comb got = valid ? data : 8'h00;
endmodule
module tb_interface;
bus_if b();
logic [7:0] got;
producer p (.valid(b.valid), .data(b.data), .ready(b.ready));
consumer c (.valid(b.valid), .data(b.data), .ready(b.ready), .got(got));
initial begin
#1;
if (got === 8'hA5) $display("PASS: interface connection works");
else $display("FAIL got=%h", got);
$finish;
end
endmoduleThe listing is a connectivity illustration, not a buffered stream. The repository snippet checker routes interface examples to Verilator.
The fallback testbench checks wiring values only. It does not check modport enforcement or a full stream protocol.