Reputation: 1963
I have a project, written in Verilog (importantly not SystemVerilog) which has gotten a little unmanageable due to the number of signals being passed along between different parts of the design. Since I have several modules which all need the same signals, I was thinking of trying to consolidate them into a smaller number of named objects. The questions is how to do it.
Let's say this is my contrived example:
module mymodule(sig_a_in, sig_b_in, sig_c_in, sig_d_in, sig_e_in,
sig_a_out, sig_b_out, sig_c_out, sig_d_out, sig_e_out);
input wire sig_a_in, sig_b_in, sig_c_in;
input wire [5 : 0] sig_d_in;
input wire [31 : 0] sig_e_in;
output reg sig_a_out, sig_b_out, sig_c_out;
output reg [5 : 0] sig_d_out;
output reg [31 : 0] sig_e_out;
endmodule
It is important, in my opinion, for readability that I can reference the signals by name. However, I don't want to have to pass them all individually to each module. Again, I am only using Verilog in this project so SystemVerilog constructs are not possible.
My first thought was that I would just combine them into one bus and then use defined names to reference the individual wires. This is kind of clunky, however, particularly when you add other buses into the mix. This is pretty trivial in my contrived example because the signals have an obvious implicit order, but in real life they don't.
`define SIGNAL_BUS_WIDTH 41
`define A 0
`define B 1
`define C 2
`define D 3
`define E 9
module mymodule(signal_bus_in, signal_bus_out);
input wire [`SIGNAL_BUS_WIDTH-1 : 0] signal_bus_in;
output reg [`SIGNAL_BUS_WIDTH-1 : 0] signal_bus_out;
// reference a
signal_bus_in[`A]
// reference d? Not good when names don't have an obvious order
signal_bus_in[`E-1 : `D]
endmodule
Finally, in addition to all of this, it is necessary for the tool chain to be able to distinguish which wires in the struct are being used by the module and to only synthesize those wires. Not all the modules use all the wires, so I want to avoid having extra unused paths. I think that the tools should be smart enough to do this, even in my bus example above, but I'm not completely sure.
Is there a good way to get what I want in Verilog?
Upvotes: 6
Views: 6874
Reputation: 569
To avoid relying on the preprocessor so much, you might try using localparam
and function
declarations to simulate structures. Below is a mock-up of a "mybus" structure with four fields, named A through D, of various sizes, to illustrate this idea.
You could put these supporting parameters and functions into a file that you include
only in the various modules that need to construct and destructure this kind of bus. This could perhaps allow you to use shorter names without fear of clashes.
module test ;
// Boilerplate structure size definitions -- you could automatically generate these
// with a simple script and put them into an include file.
localparam mybus_a_size = 4;
localparam mybus_a_offset = 0;
localparam mybus_b_size = 8;
localparam mybus_b_offset = mybus_a_offset + mybus_a_size;
localparam mybus_c_size = 4;
localparam mybus_c_offset = mybus_b_offset + mybus_b_size;
localparam mybus_d_size = 6;
localparam mybus_d_offset = mybus_c_offset + mybus_c_size;
localparam mybus_size = mybus_a_size + mybus_b_size + mybus_c_size + mybus_d_size;
// accessor functions, i.e., instead of bus.a you write mybus_a(bus)
function [mybus_a_size-1:0] mybus_a (input [mybus_size-1:0] in);
mybus_a = in[mybus_a_size + mybus_a_offset - 1 : mybus_a_offset];
endfunction
function [mybus_b_size-1:0] mybus_b (input [mybus_size-1:0] in);
mybus_b = in[mybus_b_size + mybus_b_offset - 1 : mybus_b_offset];
endfunction
function [mybus_c_size-1:0] mybus_c (input [mybus_size-1:0] in);
mybus_c = in[mybus_c_size + mybus_c_offset - 1 : mybus_c_offset];
endfunction
function [mybus_d_size-1:0] mybus_d (input [mybus_size-1:0] in);
mybus_d = in[mybus_d_size + mybus_d_offset - 1 : mybus_d_offset];
endfunction
// constructor function -- build a mybus out of its components
function [mybus_size-1:0] make_mybus(input [mybus_a_size-1:0] a,
input [mybus_b_size-1:0] b,
input [mybus_c_size-1:0] c,
input [mybus_d_size-1:0] d);
make_mybus = {d,c,b,a};
endfunction
// example of using this stuff
reg [mybus_size - 1 : 0] bus;
initial begin
bus = make_mybus(1,2,3,4);
$display("Hello, my bus is { a=%b, b=%b, c=%b, d=%b }", mybus_a(bus), mybus_b(bus), mybus_c(bus), mybus_d(bus));
end
endmodule
This mock up might make a good starting place. Some obvious improvements would be to generate all of this boilerplate automatically from a simple script, and to add additional constructor functions like "setters" in C++, i.e.,
set_mybus_a(mybus, 5) // set mybus.a = 5
Upvotes: 1
Reputation: 5098
You can always extend you idea a bit further by use macros to define the range of each signal rather than an endpoint:
`define WIDTH 41
`define sigA 0:0
`define sigB 1:1
`define sigC 2:2
`define sigD 8:3
`define sigE 40:9
module mymodule(signal_bus_in, signal_bus_out);
input wire [`WIDTH-1 : 0] signal_bus_in;
output reg [`WIDTH-1 : 0] signal_bus_out;
...
// signal a
signal_bus_in[`sigA];
// signal d
signal_bus_in[`sigD];
...
Of course, this isnt as easy as SystemVerilog packed structs (which is why they exist!), but it will work for what you want. Also, this added order to your lines as well, but I see no structure that wont do that; even structs will add an order to your signals. So long as you use the macros however, it doesnt really matter that there order except when you define the marcos.
Any good synthesis tool should be able to throw out any port or wire that does not drive anything or is not drive by anything, so unless you have to explicitly tell it which lines to ignore for some reason, you shouldnt worry about it synthesizing extra space for unused module pins.
Upvotes: 3
Reputation: 7556
Verilog does not have structs. IMO combining all signals in a long vector (or as you call it a bus) is your best bet. But, you can slightly improve upon your macros:
`define SIGNAL_BUS_WIDTH 41
`define A 0:0
`define B 1:1
`define C 2:2
`define D 8:3
`define E 40:9
// reference a
signal_bus_in[`A]
// reference d
signal_bus_in[`D]
// reference e
signal_bus_in[`E]
Most synthesis tools do not create extra logic for the wires that are not connected and treat them as dont cares.
Upvotes: 2