# How to make a very large lookup table in Verilog?

I have a requirement to make a verilog module that takes a Gray code integer i and returns the Gray coded integer i-1 using combinatorial logic only. When I look up examples of Gray decoding, for instance, a lot of them use sequential logic. I also need it to work on integers of size >20 bits.

The solution I came up with is to write a Python script that generates a verilog file for the appropriate bit width. I first tried using a big case statement in an always @(*) block as in this 3-bit example:

module gray_decrement(input [2:0] x, output [2:0] xm1);

always @(*) begin
case( x )
3'b001: xm1 = 3'b000;
3'b011: xm1 = 3'b001;
3'b010: xm1 = 3'b011;
3'b110: xm1 = 3'b010;
3'b111: xm1 = 3'b110;
3'b101: xm1 = 3'b111;
3'b100: xm1 = 3'b101;
default: xm1 = 0;
endcase
end
endmodule


That doesn't compile with an Error (10137): Verilog HDL Procedural Assignment error at graycode.v(1051): object "xm1" on left-hand side of assignment must have a variable data type. If I make xm1 an output reg it doesn't synthesize how I need it to. So I went back and redid it as a really big assign statement using the ? operator as in this 3-bit example:

module gray_decrement(input [2:0] x, output [2:0] xm1);

assign xm1 = x == 3'b001 ? 3'b000 :
x == 3'b011 ? 3'b001 :
x == 3'b010 ? 3'b011 :
x == 3'b110 ? 3'b010 :
x == 3'b111 ? 3'b110 :
x == 3'b101 ? 3'b111 :
x == 3'b100 ? 3'b101 :
3'd0;

endmodule


This works great and synthesizes properly, but after 10 bits (i.e. 1024 elements in my nested ? operation), Quartus errors out with parser stack overflow error.

So the question is what is the best way to extend my assign statement so that it could have ~2^20 lines in it? Is there some generate magic that I could use since the arithmetic is dirt simple? Or will I have to do some of the logic simplification in my Python preprocessor?

• In VHDL you'd simply declare a constant array and initialise it in the declaration. Surely Verilog would let you do the same? Jan 6 at 23:04
• Your first example errors because you must use a variable data type on the left hand side in a procedural block - i.e. xml must be a variable (reg,integer,etc.), not a net (wire). Outputs default to being wire unless otherwise specified. Jan 6 at 23:31

Your first example errors because you must use a variable data type on the left hand side in a procedural block.

xml is the left hand side of the assignment, and so must be a variable (reg,integer,etc.), not a net (wire). Outputs default to being wire unless otherwise specified. You can fix this with an output reg [2:0] xml in your port declaration list.

Alternatively, given you are basically describing a ROM, you can use an initial block to set the default values for your lookup table:

localparam SIZE = 1024;
reg [2:0] rom [SIZE-1:0];

initial begin
end

assign xm1 = rom[x];


Alternatively, given you are using Quartus, you could use a MIF file:

localparam SIZE = 1024;
(* ram_init_file = "rominit.mif" *) reg [2:0] rom [SIZE-1:0];
assign xm1 = rom[x];


Finally, and perhaps more simply, your mapping can easily be described algorithmically:

module gray_decrement #(
parameter WIDTH = 3
)(
input  [WIDTH-1:0] x,
output [WIDTH-1:0] xm1
);

genvar i;
generate

// First convert to binary
wire [WIDTH-1:0] bin;
assign bin[WIDTH-1] = x[WIDTH-1];
for (i = 1; i < WIDTH; i = i + 1) begin : gray2bin
localparam idx = WIDTH-1-i;
assign bin[idx] = x[idx] ^ bin[idx+1];
end

// Then subtract one
wire [WIDTH-1:0] binm1;
assign binm1 = bin - {{{WIDTH-1}{1'b0}},1'b1};

// Then convert back to gray code
assign xm1[WIDTH-1] = binm1[WIDTH-1];
for (i = 1; i < WIDTH; i = i + 1) begin : bin2gray
localparam idx = WIDTH-1-i;
assign xm1[idx] = binm1[idx] ^ binm1[idx+1];
end

endgenerate

endmodule


The above should optimise away to a lookup table which should decrement the gray code value.

(As a side note, your lookup table is wrong - the default value should be 4 not 0, otherwise a value of 0 maps to 0, and nothing maps to 4).

• Thanks, the generate-based code was the solution I was looking for. Jan 7 at 18:00