门级 Verilog:有条件的,生成门输入

Gate Level Verilog: Conditional, generate gate inputs

我正在研究二进制解码器并尝试参数化地址大小。这是一个项目要求,这是在门级 verilog 中进行的。

有没有办法根据ADDR_SIZE生成第二个generate语句中的i[k]语句?

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

所以如果 ADDR_SIZE = 4,唯一会改变的是:

 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]
      );

或者如果 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]
      );

因为它是解码器,所以我接受二进制输入 2^ADDR_SIZE(默认为 5)。根据输入的二进制值,相应的输出线将被驱动为高电平,因此如果 in = 5'b00001,out = 32'b...0000001(点全为零。只有最低有效位为高)。如果输入 = 5'b00011,输出 = 32'b...0000100.

该部分已完成,并在以下代码中使用 5 位地址。我现在正在努力做到,如果我设置 ADDR_SIZE = 4,我的输入现在是 4'b,我的输出现在是 16'b。这大部分都有效,每个输出行只是 in 或 inNot 的 AND,具体取决于位置。

取出所有这些生成的代码后,我实际上是在问我如何才能执行以下操作。同样,这在结构 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

如果您只想使用门级别,我的建议是使用递归调用自身较小版本的模块。例如:

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

注意my_and未优化。根据您的目标最大大小和 and 的输入,您可能需要考虑让递归方法有条件地分成三个或四个子切片的组。

然后为 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明显更简单:

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