Search code examples
verilogfpgahdl

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?


Solution

  • 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