0

I'm working on a binary decoder and am trying to parameterize the address size. It is a project requirement that this be made in gate level verilog.

Is there a way to generate the i[k] statements in the second generate statement based on ADDR_SIZE?

module Decoder #(
  parameter ADDR_SIZE = 5
)(
  out,
  in
);
  input wire [ADDR_SIZE-1:0] in;
  output wire [(2**ADDR_SIZE)-1:0] out;
  wire [ADDR_SIZE-1:0] code, codeNot;

  genvar j;
  generate
    for (j = 0; j < ADDR_SIZE; j = j + 1)
    begin : bufs
      buf (code[j], in[j]);
      not(codeNot[j], in[j]);
    end
  endgenerate

  genvar i;
  generate
    for (i = 0; i < (2**ADDR_SIZE); i = i + 1)
    begin : selects
      and (out[i],
        i[0] ? codeNot[0] : code[0],
        i[1] ? codeNot[1] : code[1],
        i[2] ? codeNot[2] : code[2],
        i[3] ? codeNot[3] : code[3],
        i[4] ? codeNot[4] : code[4],
      );
    end
  endgenerate
endmodule

So if ADDR_SIZE = 4, the only thing that would change would be:

 and (out[i],
        i[0] ? codeNot[0] : code[0],
        i[1] ? codeNot[1] : code[1],
        i[2] ? codeNot[2] : code[2],
        i[3] ? codeNot[3] : code[3]
      );

Or if ADDR_SIZE = 6

 and (out[i],
        i[0] ? codeNot[0] : code[0],
        i[1] ? codeNot[1] : code[1],
        i[2] ? codeNot[2] : code[2],
        i[3] ? codeNot[3] : code[3],
        i[4] ? codeNot[4] : code[4],
        i[5] ? codeNot[5] : code[5]
      );

Since its a decoder, I'm accepting a binary input of 2^ADDR_SIZE (default to 5). Depending on what the input binary value is, the corresponding output line would be driven high, so if in = 5'b00001, out = 32'b...0000001 (dots are all zeros. only least significant bit is high). If in = 5'b00011, out = 32'b...0000100.

That part has been done and works with a 5 bit address in the following code. I'm now trying to make it so that if I set ADDR_SIZE = 4, my input is now 4'b and my output is now 16'b. Most of this works, and each output line is just an AND of either in or inNot depending on the place.

After all this generated code is taken out, I'm essentially asking how I can do the following. Again, its important this be done in Structural Verilog.

parameter ADDR_SIZE = 5

generate . . .
 and(out, a, b, c, d, e);
endgenerate

parameter ADDR_SIZE = 3

generate . . .
 and(out, a, b, c);
endgenerate

parameter ADDR_SIZE = 6

generate . . .
 and(out, a, b, c, d, e, f);
endgenerate
3
  • Welcome to Stack Overflow. Sorry - I don't understand your question. Commented Apr 28, 2016 at 11:59
  • Could you show us what the code should look like if you hand-wrote the cases for ADDR_SIZE=3 and ADDR_SIZE=4 (even if just excerpts of a few values of i)? I'm guessing a nested generate loop may be needed. Commented Apr 28, 2016 at 17:01
  • Thanks for the feedback! It's been edited now Commented Apr 28, 2016 at 18:22

1 Answer 1

0

If you want to only use gate level, my suggestion is to use a module that recursively invokes smaller versions of itself. For example:

module my_and #(parameter SIZE=4) (output out, input [SIZE-1:0] in);
generate
  if (SIZE<2) begin
    // Intentionally cause a compile error if ever selected

    // Verilog requires you to be a bit clever with your error messages 
    // Suggest using using non-existing modules instances
    non_existing_module my_and_SIZE_is_less_than_2 ();

    // SystemVerlog allows option for more meaningful message
    //$error("SIZE must be >= 2, was %0d @ %m", SIZE);
  end
  else begin
    case(SIZE)
      2 : and and2 (out, in[0], in[1]);
      3 : and and3 (out, in[0], in[1], in[2]);
      4 : and and4 (out, in[0], in[1], in[2], in[3]);
      default : begin : recursive
        wire half0, half1;
        my_and #(SIZE/2) half_0 (half0, in[SIZE/2-1:0]);
        my_and #(SIZE/2) half_1 (half1, in[SIZE-1-(SIZE%2):SIZE/2]);
        if (SIZE%2) begin : odd
          and and3 (out, half0, half1, in[SIZE-1]);
        end
        else begin : even
          and and2 (out, half0, half1);
        end
      end
    endcase
  end
endgenerate
endmodule

Note: my_and is not optimized. Depending on your target max size and inputs to an and, you may want to consider having the recursive method conditionally break into groups of three or four sub slices.

Then create a local vector for the select:

genvar i,k;
generate
  for (i = 0; i < (2**ADDR_SIZE); i = i + 1)
  begin : selects
    wire [ADDR_SIZE-1:0] local_select; // local to scope
    for(k = 0; k < ADDR_SIZE; k = k + 1)
    begin
      assign local_select[k] = i[k] ? code[k] : codeNot[k];
    end
    my_and #(ADDR_SIZE) dec(out[i], local_select);
  end
endgenerate

RTL is obviously simpler:

module Decoder #(
  parameter ADDR_SIZE = 5
)(
  output reg [(2**ADDR_SIZE)-1:0] out,
  input [ADDR_SIZE-1:0] in
);
always @* begin
  out = {(2**ADDR_SIZE){1'b0}};
  out[in] = 1'b1;
end
endmodule
Sign up to request clarification or add additional context in comments.

2 Comments

Dang, I was hoping to avoid recursion so that the design would be optimized during synthesis. Thanks!
Assuming you have a decent synthesizer, you should do your decoder as RTL, not gates, to get more optimized synthesis.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.