5
\$\begingroup\$

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 :-)

\$\endgroup\$
2
  • 1
    \$\begingroup\$ 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. \$\endgroup\$
    – Dave Tweed
    Jan 14, 2013 at 2:50
  • \$\begingroup\$ @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 :-) \$\endgroup\$
    – mtvec
    Jan 15, 2013 at 9:01

4 Answers 4

2
+100
\$\begingroup\$

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.

\$\endgroup\$
2
  • \$\begingroup\$ 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! \$\endgroup\$
    – mtvec
    Jan 17, 2013 at 7:23
  • \$\begingroup\$ @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. \$\endgroup\$ Jan 17, 2013 at 8:34
5
\$\begingroup\$

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.

\$\endgroup\$
1
  • \$\begingroup\$ Hehe we posted the exact same answer at the same time. Please see the concerns I added to my answer. \$\endgroup\$
    – mtvec
    Jan 8, 2013 at 10:57
1
\$\begingroup\$

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.

\$\endgroup\$
5
  • \$\begingroup\$ 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.. \$\endgroup\$
    – pjc50
    Jan 8, 2013 at 11:24
  • 1
    \$\begingroup\$ You did just code it in Verilog. I don't understand what your concern is. \$\endgroup\$
    – Dave Tweed
    Jan 8, 2013 at 13:00
  • \$\begingroup\$ @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. \$\endgroup\$
    – mtvec
    Jan 8, 2013 at 14:50
  • 2
    \$\begingroup\$ 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. \$\endgroup\$
    – dwikle
    Jan 8, 2013 at 15:02
  • \$\begingroup\$ @dwikle: I updated my answer to give some rationale as to why I want to do this in another way. \$\endgroup\$
    – mtvec
    Jan 9, 2013 at 8:00
0
\$\begingroup\$
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]
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.