Electronic – Generate gate with a parametrized number of inputs

verilog

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 🙂

Best Answer

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.