Is there a way to define something like a C struct in Verilog - struct

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?

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.

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.

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

Related

call by reference in verilog code

I am trying to change a c++ code into verilog HDL.
I want to write a module that changes one of its inputs. (some how like call by reference in c++)
as I know there is no way to write a call by reference module in verilog (I can't use systemverilog)
Here is a code that I wrote and it works. are there any better ways to do this?!
my problme is that the register I want to be call by reference is a big array. this way duplicates the registers and has a lot of cost.
module testbench();
reg a;
wire b;
reg clk;
initial begin
a = 0;
clk = 0;
#10
clk = 1;
end
test test_instance(
.a(a),
.clk(clk),
.aOut(b)
);
always#(*)begin
a = b;
end
endmodule
module test(
input a,
input clk,
output reg aOut
);
always #(posedge clk) begin
if (a == 0)begin
a = 1;
aOut = a;
end
end
endmodule
Verilog is not a software programming language; it is a hardware description language. The inputs to a module are pieces of metal (wires, tracks, pins); the outputs from a module are pieces of metal. If you want a port that is both an input and an output you can use an inout. However, inout ports are best avoided; it is usually much better to use separate inputs and outputs.
A Verilog module is not a software function. Nothing is copied to the inputs; nothing is copied from the outputs. A Verilog module is a lump of hardware: it has inputs (pieces of metal carrying information in) and outputs (pieces of metal carrying information out).
Your are right to say that you can use either pass-by-copy or pass-by-reference in SystemVerilog. If you wish to pass a large data structure into a function or into/out of a task, then passing by reference may save simulation time.
By reference means by address, so to translate this to hdl directly you would either need to provide a way for the module to get on that bus and perform transactions based on that address.
Or better, if you need this as an input take each of the items in the struct and make individual inputs from them. If it is pass by reference because it is an output or is also an output, then you create individual outputs for each of the items in the struct. The module then distinguishes between the input version of that sub item and output version of that sub item.
my.thing.x = my.thing.x + 1;
becomes something like
my_thing_x_output = my_thing_x_input + 1;

Verilog data types

I am studying verilog as part of my university course however my module lecturer left so I was hoping for some help here,
An example we have been given for a parametric n-bit gray to binary code converter, as follows:
module bin_n_gray #(parameter n=4) (input [n-1 : 0] gray, output [n-1 : 0] bin);
integer i;
always # (*)
for(i = 0; i < n; i = i+1)
bin[i] = ^(gray >> i);
endmodule
My question:
As the bin[i] variable is on the left hand side of an assignment statement within an # always block shouldn't this variable be declared as output reg [n-1 : 0] bin?
As I thought that a variable on the left hand side of an assignment statement of a process block i.e always / initial should be declared as a reg datatype?
As the bin[i] variable is on the left hand side of an assignment statement within an '# always' block shouldn't this variable be declared as 'output reg [n-1 : 0] bin?
Yes, it should require the reg as you say, at least according to Xilinx XST. The code as given in your question errs when synthesizing using that tool (and is missing an unrelated semicolon).
First let's begin by understanding what a procedural block in Verilog is, exactly (with the assumption that we're using Verilog to develop hardware, such as an FPGA design). Procedural blocks are always blocks (of two types, combinational and sequential) as well as few other types of blocks we won't cover here. The first thing to know is that in a procedural block, the only assignments allowed are those that have a reg on the left hand side.
This doesn't necessarily mean that a physical register/flipflop will be created. In this case, one will not be. The reason is the declaration of the block as always # (*). This declaration means that the process is combinational (i.e. not sequential, not having any internal state or clock signal). As a result, no physical flip-flops are created.
Alternatively, you can have a procedural block declared as always # (posedge some_clock_signal). This means that sequential logic is created, and physical flip-flops (or other means of storage such as the distributed memory in FPGA lookup tables) may be used. The takeaway is that you're still declaring as reg there, but now you're actually creating registers.
There is one case where you use wire (or output), which is by continuous assignment (for example, assign a = b & c), which falls outside a procedural block. In this example, I'm using generate to do the same thing as the loop in your original code:
module bin_n_gray #(parameter n=4) (input [n-1 : 0] gray, output [n-1 : 0] bin);
genvar i;
generate
for (i=0; i < n; i=i+1)
begin: graydecoder // arbitrary label needed by generate syntax
assign bin[i] = ^(gray >> i);
end
endgenerate
endmodule

How to write a module with variable number of ports in Verilog

I would like to write a module with a variable number of inputs, i.e. depending on some parameter, the result would be:
module my_module #(LENGTH)(
input clk,
input rst_n,
input [LENGTH-1:0] data_1
);
//...
endmodule
or
module my_module #(LENGTH)(
input clk,
input rst_n,
input [LENGTH-1:0] data_1,
input [LENGTH-1:0] data_2,
input [LENGTH-1:0] data_3
);
//...
endmodule
Would it be possible to do this in Verilog or Systemverilog or would I have to write a script, let's say in Python, in order to generate the code for a specific module with fixed number of inputs? (it might be more than 1000 inputs)
There are no variable number of ports in SystemVerilog, but you could use a port that is a parameterized array.
module my_module #(int LENGTH, DEPTH)(
input clk,
input rst_n,
input [LENGTH-1:0] data[DEPTH]
);
//...
endmodule
Otherwise, you would need to use a script to generate the code.
Use a two dimensional input with a parameterized size. Added a generate for loop that can be used to set signals individually. Although many operations can be done with smart array operations.
module my_module #(SIZE, LENGTH)(
input clk,
input rst_n,
input [SIZE-1:0][LENGTH-1:0] data_in_array,
output [SIZE-1:0][LENGTH-1:0] data_out_array
);
genvar N;
generate for (N=0; N<SIZE; N++) begin :la_coolOps
//Do cool operations here. For example instantiate a module for every data_in
end
//...
endmodule
Edit:
As Mehran Torki points out: The syntax above will work for SystemVerilog only. Verilog does not allow for multiple packed arrays. Use input [LENGTH*SIZE-1:0] data_in_array.
I would add to these other answers that ports are just groupings of wires. While having 3, 1-bit wires named a, b, and c might be easier to read and understand, there is no physical/logical difference between a single, 3-bit wire abc, where abc[0] corresponds to a, abc[1] corresponds to b, and abc[2] corresponds to c.
So, you can always just expand or shrink a single (or multiple) signal(s) to get however many bits you need. It may not be as neat, but it will work. In the receiving module, you can then part-select the bus in whatever manner you like. So, you could have one really long wire the shrinks or expands (wire [(SOME_PARAM*8)-1:0] my_input_wire), or with SystemVerilog an array (wire [7:0] my_input_wire[0:SOME_PARAM-1])
If this is just testbench/verification code, the other thing you could do in SystemVerilog is use a dynamic array
As others said, there is no direct way to do this, but another workaround is to use SystemVerilog interfaces, where you define all the inputs that you want in the interface definition and inside the module only use the ones that correspond to the parameter. Below is a sample:
module my_module #(LENGTH)(
input clk;
input rst_n;
output o;
interface i_data;
);
logic outValue;
generate
case (LENGTH) //Based on the value of LENGTH, use corresponding data
1: outValue = i_data.data_1;
2: outValue = i_data.data_1 + i_data.data_2;
3: outValue = i_data.data_1 + i_data.data_2 + i_data.data_3;
endcase
endgenerate
always #(posedge clk) begin
if (~rst_n)
o <= '0;
else
begin
o <= outValue;
end
endmodule
You can still use a parameterized array for data and a for-generate loop if your outputs are similar.
With System verilog we can import a package instead of having parameterization and define types in the package to be used in the portlist.
module mymodule
import mymodule_pkg::*;
(
input portlist_t portlist
);
endmodule
And define multiple copies of the package with different variants of the port list and compile whichever version is required. eg
package mymodule_pkg;
localparam LENGTH=5;
typedef struct packed {
logic [LENGTH-1:0] data_1,
logic [LENGTH-1:0] data_2,
logic [LENGTH-1:0] data_3
} portlist_t;
endpackage
As with the interface solution there will be situations where you run into issues, like having different iterations of the module instantiated together.

How to prevent ISE compiler from optmizing away my array?

I'm new to Verilog, ISE, FPGAs. I'm trying to implement a simple design into an FPGA, but the entire design is being optimized away. It is basically an 2D array with some arbitrary values. Here is the code:
module top(
output reg out
);
integer i;
integer j;
reg [5:0] array [0:99][0:31];
initial begin
for(i=0;i<100;i=i+1) begin
for(j=0;j<32;j=j+1) begin
array[i][j] = j;
out = array[i][j];
end
end
end
endmodule
It passes XST Synthesis fine, but it fails MAP in the Implementation process. Two Errors are given:
ERROR:Map:116 - The design is empty. No processing will be done.
ERROR:Map:52 - Problem encountered processing RPMs.
The entire code is being optimized away in XST. Why? What am I doing wrong?
The reason your design is being synthesized away is because you have not described any logic in your module.
The only block in your design is an initial block which is typically not used in synthesis except in limited cases; the construct mainly used for testbenches in simulation (running the Verilog through ModelSim or another simluator).
What you want is to use always blocks or assign statements to describe logic for XST to synthesize into a netlist for the FPGA to emulate. As the module you provided has neither of these constructs, no netlist can be generated, thus nothing synthesized!
In your case, it is not entirely clear what logic you want to describe as the result of your module will always have out equal to 31. If you want out to cycle through the values 0 to 31, you'll need to add some sequential logic to implement that. Search around the net for some tutorials on digital design so you have the fundamentals down (combinational logic, gates, registers, etc). Then, think about what you want the design to do and map it to those components. Then, write the Verilog that describes that design.
EDIT IN LIGHT OF COMMENTS:
The reason you are get no LUT/FF usage on the report is because the FPGA doesn't need to use any resources (or none of those resources) to implement your module. As out is tied to constant 31, it will always have the value of 1, so the FPGA only needs to tie out to Vdd (NOTE that out is not 31 because it is only a 1-bit reg). The other array values are never used nor accesses, so the FPGA synthesized them away (ie, not output needs to know the value of array[0][1] as out is a constant and no other ports exist in the design). In order to preserve the array, you need only use it to drive some output somehow. Heres a basic example to show you:
module top( input [6:0] i_in, // Used to index the array like i
input [4:0] j_in, // Used to index the array like j
output reg [5:0] out // Note, out is now big enough to store all the bits in array
);
integer i;
integer j;
reg [5:0] array[0:99][0:31];
always #(*) begin
// Set up the array, not necessarily optimal, but it works
for (i = 0; i < 100; i = i + 1) begin
for (j = 0; j < 32; j = j + 1) begin
array[i][j] = j;
end
end
// Assign the output to value in the array at position i_in, j_in
out = array[i_in][j_in];
end
endmodule
If you connect the inputs i_in and j_in to switches or something and out to 6 LEDs, you should be able to index the array with the switches and get the output on the LEDs to confirm your design.

Generate statement inside verilog task

I want to use generate statement inside a task. The following code is giving compile errors (iverilog).
task write_mem; //for generic use with 8, 16 and 32 bit mem writes
input [WIDTH-1:0] data;
input [WIDTH-1:0] addr;
output [WIDTH-1:0] MEM;
integer i;
begin
generate
genvar j;
for(j=0; j<i;j++)
MEM[addr+(i-j-1)] = data[(j*8):((j*8) + 8)-1];
endgenerate
end
endtask // write_mem
I also tried putting generate just after the line integer i, but still its producing errors. Any thoughts?
EDIT: I also tried putting genvar declaration between begin and generate statement in the above code. Its still producing compiler errors
Thanks in advance,
Jay Aurabind
What you are trying is not possible - a generate region (generate..endgenerate block) is only allowed in the module description (aka "top level"), i.e. the same level where you have parameters, wires, always- and inital-regions, etc. (see Syntax 12-5 in the IEEE Std. 1364-2005). Within a task a generate region is e.g. as invalid as an assign statement.
However, you can use a non-generate for-loop in a task (this is also synthesizeable).
Either way, you can not count from 0 to i-1 in synthesizeable code as 'i' is not constant. Also note that j++ is not valid verilog, you must write j=j+1 instead. Finally you probably want to use a nonblocking assignment (<=) instead of a blocking assignment (=), but this depends on how you intent to use this task.
genvars should be defined before the generate statement:
genvar j;
generate
for(j=0; j<i;j++)
MEM[addr+(i-j-1)] = data[(j*8):((j*8) + 8)-1];
endgenerate
Although your usage here does not look like it needs a generate statement a for loop would have done.
As pointed out by #CliffordVienna generate statements are for building hierarchy and wiring based on compile time constants. ie parameters can be changed for reusable code but are constant in a given simulation. Tasks do not contain hierarchy and therefore the use of a generate is invalid.
Any for loop that can be unrolled is synthesizable, some thing like:
task write_mem; //for generic use with 8, 16 and 32 bit mem writes
input [WIDTH-1:0] data;
input [WIDTH-1:0] addr;
output [WIDTH-1:0] mem;
integer i = WIDTH / 8; // CONSTANT
begin
for(j=0; j<i;j++) begin
mem[addr+(i-j-1)] = data[(j*8):((j*8) + 8)-1];
end
end
endtask // write_mem
Tasks are synthesizable as long as they do not contain any timing control, which yours does not. From the information given this should be synthesizable.
NB: I would separate data width and addr width, they might be the same now but you might want to move to 8 bit addressing and 16 bit data.

Resources