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