在Verilog中生成If语句

时间:2013-02-25 23:43:07

标签: verilog

我正在尝试在Verilog中创建一个可综合的参数化优先级编码器。具体来说,我想在向量中找到最不重要的1并返回仅包含该向量的向量。例如:

IN[3:0] | OUT[4:0]
--------+---------
1010    | 00010
1111    | 00001
0100    | 00100
0000    | 10000   (special case)

因此,如果向量是四位宽,则代码为:

if (in[0]==1'b1) least_one = 1;
else if (in[1]==1'b1) least_one = 2;
else if (in[2]==1'b1) least_one = 4;
else if (in[3]==1'b1) least_one = 8;
else out = 16; // special case in==0, set carry bit

我需要一种通用的,可扩展的方法来实现这一点,因为输入/输出矢量长度是参数化的。我目前的代码是:

module least_one_onehot
#(parameter ADDR_WIDTH=4)
(output reg [ADDR_WIDTH:0] least_one,
input [ADDR_WIDTH-1:0] in);

genvar i;

always @(in) begin
    if (in[0]==1'b1) least_one = 1;
    generate for (i=1; i<ADDR_WIDTH; i=i+1) begin : U 
        else if (in[i]==1'b1) least_one = 2**i; 
        end 
        endgenerate
    else least_one = 2**ADDR_WIDTH;
    end

endmodule

当我尝试编译时,我收到以下错误:

file: least_one_onehot.v
        generate for (i=1; i<ADDR_WIDTH; i=i+1) begin : U
               |
ncvlog: *E,GIWSCP (least_one_onehot.v,10|8): Generated instantiation can only be valid within a module scope [12.1.3(IEEE 2001)].
                        else if (in[i]==1'b1) least_one = 2**i; 
                           |
ncvlog: *E,NOTSTT (least_one_onehot.v,11|6): expecting a statement [9(IEEE)].
                endgenerate
                          |
ncvlog: *E,GIWSCP (least_one_onehot.v,13|12): Generated instantiation can only be valid within a module scope [12.1.3(IEEE 2001)].
                else least_one = 2**ADDR_WIDTH;
                   |
ncvlog: *E,NOTSTT (least_one_onehot.v,14|5): expecting a statement [9(IEEE)]

我已尝试过generate,if和always语句的各种安排,但都没有成功。有人知道这个的正确语法吗?案例陈述实施或其他替代方案也可以。感谢。

3 个答案:

答案 0 :(得分:2)

我认为你误解了生成是如何工作的。它不是一个文本预处理器,它在生成/生成对之间发出代码并进行适当的替换。你必须拥有完整的语法实体。我这一分钟无法访问模拟器,但这可能会对你有用(完全未经测试)

genvar i;
generate
    for (i = 1; i < ADDR_WIDTH; i = i + 1) begin : U
        least_one[i] = in[i] & ~|in[i - 1:0];
    end
endgenerate
least_one[0] = in[0];
least_one[ADDR_WIDTH] = ~|in;

通常Verilog会抱怨非恒定的位片宽度,但由于它在生成循环中可能会起作用。

如上所述,您只需测试for循环中的第一个设置位,然后解码该结果。

答案 1 :(得分:1)

需要生成块。你可以使用:

integer i;
reg found;
always @(in) begin
  least_one = {(ADDR_WIDTH+1){1'b0}};
  found = 1'b0;
  for (i=0; i<ADDR_WIDTH; i=i+1) begin
    if (in[i]==1'b1 && found==1'b0) begin
      least_one[i] = 1'b1;
      found = 1'b1;
    end
  end
  least_one[ADDR_WIDTH] = (found==1'b0);
end

如果你真的想使用生成块,那么你需要分配每个位。

assign least_one[0] = in[0];
assign least_one[ADDR_WIDTH] = (in == {ADDR_WIDTH{1'b0}});
genvar i;
generate
  for (i=1; i<ADDR_WIDTH; i=i+1) begin : U
    assign least_one[i] = in[i] && (in[i - 1:0] == {i{1'b0}});
  end
endgenerate

答案 2 :(得分:1)

就个人而言,我喜欢以下代码块,以满足您的需求: 分配= {1'b1,in}&amp; ((〜{1'b1的,在})+ 1);

你可以试试这个(删除额外的高位以获得易读性),但我喜欢明确地做两个恭维以避免任何潜在的兼容性问题。

分配= in&amp; (-1 *中);