# Generate gate with a parametrized number of inputs

I'm trying to generate a multi-input gate for which the inputs can be selected when the design is elaborated.

Let me give an example to (hopefully) make this more clear:

module selectable_xor(input [7:0] in, output out);

parameter [7:0] SELECT = 8'b10010100;

// this should be generated for the default value of SELECT:
assign out = in[7] ^ in[4] ^ in[2]

endmodule


So, out should be the output of a XOR gate which has those bits of in as input for which the corresponding bit in SELECT is set.

I'm attempting something like the following:

generate
genvar gen_i;
assign out = 1'b0;

for (gen_i = 0; gen_i < 8; gen_i = gen_i + 1)
if (SELECT[gen_i])
assign out = out ^ in[gen_i];
endgenerate


But this produces undefined values for the out signal.

Is there any good way to generate a gate with a variable number of inputs in Verilog?

PS: About the use case: I'm trying to implement a LFSR for which the polynomial is a parameter.

Edit: The consensus seems to be that I should use the following equivalent expression and trust the synthesizer to optimize it to the circuit I want:

assign out = ^(in & SELECT);


Although I do trust that any decent synthesizer will be able to do this, I still would like to know if there is a way in Verilog to actually code this circuit myself.

Consider that, instead of the XOR-gate above, I wanted to code an OR-gate. The equivalent expression is:

assign out = |(in & SELECT);


Ok, that's practically the same as for the XOR-gate. For an AND-gate, however, the expression is different:

assign out = &(in | ~SELECT);


My point is that for every type of gate, I might have to come up with a different equivalent expression. I'd rather have a general way to code a gate for which the inputs can be parametrized because then I can use the same technique for any type of gate.

Edit 2: Since my bounty expires tomorrow, I will edit this question one more time to bump it. This is a comment I left to explain what I want which I hope will be more visible in the question's body:

What I want has nothing to do with physical resources. When I talk about "gates" I mean the Verilog concept. I want to be able to define a gate with inputs depending on some parameter. More specifically, I want this gate to have in[i] as an input iff SELECT[i] is set. I do not want an equivalent expression that might be optimized to the gate I want. As I've said before, this equivalent expression might as well be implemented as 8 AND-gates and an 8-input XOR-gate because that's what's actually coded. I hope this clarifies things :-)

-
You still haven't added any new information that explains exactly what result you're hoping to get from this, which is what would make it possible to answer this question. It sounds like you want to explicitly control the allocation of physical resources on the chip, but that's a process that's very dependent on the chip technology you're targeting. As @pjc50 has already pointed out, there are no "gates" on most FPGAs, just LUTs (look-up tables). While there may be a way to instantiate and define the contents of a LUT in Verilog, that would be specific to the toolchain provided by the vendor. – Dave Tweed Jan 14 '13 at 2:50
@DaveTweed: What I want has nothing to do with physical resources. When I talk about "gates" I mean the Verilog concept. I want to be able to define a gate with inputs depending on some parameter. More specifically, I want this gate to have in[i] as an input iff SELECT[i] is set. I do not want an equivalent expression that might be optimized to the gate I want. As I've said before, this equivalent expression might as well be implemented as 8 AND-gates and an 8-input XOR-gate because that's what's actually coded. I hope this clarifies things :-) – Job Jan 15 '13 at 9:01

If I understood your question correctly, I think the following module does what you want. You can very simply specify the gate by its operator (^,&,|, etc) and nothing else. Plus only the desired assignments are generated (which is I think what you are looking for).

timescale 1 ns / 1 ps

module selectable_gate(input [7:0] in, output out);

parameter [7:0] SELECT = 8'b10010100;

function integer count_ones;
input [7:0] v;
integer ret;
integer i;
begin
ret = 0;
for(i=0;i<8;i=i+1) begin
if (v[i]) begin
ret = ret+1;
end
end
count_ones = ret;
end
endfunction

function integer nth_one;
input integer n;
input [7:0] v;
integer i,ret,cnt;
begin
ret = -1;
cnt = 0;
for(i=0;i<8;i=i+1) begin
if (v[i]) begin
if (cnt == n) begin
ret = i;
end
cnt = cnt+1;
end
end
nth_one = ret;
end
endfunction

localparam integer w = count_ones(SELECT);
wire [w-1:0] y;

generate
genvar i;
for(i=0 ; i<w ; i=i+1) begin
assign y[i] = in[nth_one(i,SELECT)];
end
endgenerate

assign out = ^y; // specify gate here (e.g. ^y, &y, |y, etc)

endmodule;


The above module for the default SELECT = 8'b10010100 should end up generated as:

assign y[0] = in[2];
assign y[1] = in[4];
assign y[2] = in[7];
assign out  = ^y;


Which is the same as xor(in[2],in[4],in[7]).

Since genvars are always unrolled as constants inside the generates, the trick was to find constants that allow the proper conditions for the generate, and use functions for any temporary variable manipulation necessary to calculate them.

-
Great solution! This is the thing I was looking for. Just one comment, and I'm nitpicking now, but this seems to create the XOR-gates in series. The created circuit is XOR(in[7], XOR(in[4], in[2])) instead of XOR(in[2], in[4], in[7]). That is, two 2-input XOR-gates instead of one 3-input XOR-gate. I think the latter may be generated by assigning y[i] to in[nth_one(i,SELECT)] and then just doing assign out = ^y. Anyway, like I said this is nitpicking. Thanks for the great answer! – Job Jan 17 '13 at 7:23
@Job Ah, yes. I've updated the answer to describe the gate as a single operation on a vector containing only the selected inputs, instead of multiple 2-input gates. – apalopohapa Jan 17 '13 at 8:34
I think I just spotted a small bug in your code: in function nth_one, the statement ret = cnt should be ret = i. – Job Jan 17 '13 at 8:44
@Job True. Fixed. – apalopohapa Jan 17 '13 at 9:29
Great! Enjoy your bounty :-) – Job Jan 17 '13 at 10:00

Try

assign out = ^(in & parameter);


The & selects those bits which are 1 in parameter, and then ^ will XOR them all together. Those bits which are 0 in parameter will be ignored.

-
Hehe we posted the exact same answer at the same time. Please see the concerns I added to my answer. – Job Jan 8 '13 at 10:57

The following is equivalent to what I want:

assign out = ^(in & SELECT);


And I noticed that Xilinx ISE synthesizes this into a 3-input XOR-gate for the default value of SELECT which is exactly what I want.

However, since this might just as well be synthesized into 8 AND-gates and one 8-input XOR-gate, I'm still very much interested in other answers. I would like to have a way to code this in Verilog instead of having to rely on the synthesis tool.

-
Your issue is essentially that you don't trust the synthesis tool to do logic minimisation? Note that if you're targetting an FPGA, it's all lookup tables rather than actual gates.. – pjc50 Jan 8 '13 at 11:24
You did just code it in Verilog. I don't understand what your concern is. – Dave Tweed Jan 8 '13 at 13:00
@DaveTweed: My concern is that I did not code the use of a small number of XOR-gates. I coded the use of 8 AND-gates and one big XOR-gate. Although I assume any decent synthesizer will infer what I want, I'm still interested in coding this in Verilog. – Job Jan 8 '13 at 14:50
Parameters are fixed value for synthesis, so the synthesizer is doing the proper thing and optimizing for SELECT=8'b10010100. If you want the full logic, change SELECT to an input instead of a parameter. If SELECT can take on any value, the synthesizer will not be able to make that optimization. – dwikle Jan 8 '13 at 15:02
@dwikle: I updated my answer to give some rationale as to why I want to do this in another way. – Job Jan 9 '13 at 8:00
generate
genvar gen_i;
assign out = 1'b0;

for (gen_i = 0; gen_i < 8; gen_i = gen_i + 1)
if (SELECT[gen_i])
assign out = out ^ in[gen_i];
endgenerate


The problem with this code is that you have multiple assign statements going to out. I belive the following should work.

wire [8:0] tmp;
generate
genvar gen_i;
assign tmp[0] = 1'b0;

for (gen_i = 0; gen_i < 8; gen_i = gen_i + 1)
if (SELECT[gen_i])
assign tmp[i+1] = temp[i] ^ in[gen_i];
else
assign tmp[i+1] = temp[i]
endgenerate
assign out = tmp[8]
`
-