verilog中的优先级编码器

时间:2015-04-09 04:23:06

标签: verilog encoder

我对verilog有些新手,我尝试运行此代码,但它给了我一个错误:

module enc(in,out);
  input [7:0] in;
  output [3:0] out;
  reg i;
  reg [3:0] out;

  always @*
    begin
      for (i=0;i<7;i=i+1)
        begin
          if ((in[i]==1) && (in[7:i+1]==0))
            out = i;
          else
            out = 0;
        end
    end
endmodule

我认为它在[7:i + 1]中抱怨但我不明白为什么? 有人可以建议..

修改 好吧所以我不愿意使用X,因为他们遇到了很多问题。我正在考虑将代码修改为:

module enc(in,out);
  input [7:0] in;
  output [2:0] out;
  reg i;
  reg [2:0] out,temp;

  always @*
    begin
      temp = 0;
      for (i=0;i<8;i=i+1)
        begin
          if (in[i]==1)
            temp = i;
        end
      out = temp;
    end
endmodule

你认为这会奏效吗?我目前无法访问模拟器..

6 个答案:

答案 0 :(得分:1)

如果两个或多个位满足条件,则优先级编码器意味着将优先级赋予一位。查看代码,您似乎希望在使用向上计数器时优先考虑LSB。每次看都会分配out,所以即使你可以编译,最终的结果也是6或0。

对于LSB优先级编码器,首先使用out的默认值启动并使用向下计数器:

module enc (
    input wire [7:0] in,
    output reg [2:0] out
  );
  integer i;
  always @* begin
    out = 0; // default value if 'in' is all 0's
    for (i=7; i>=0; i=i-1)
        if (in[i]) out = i;
  end
endmodule

答案 1 :(得分:1)

如果您只对模拟感兴趣,那么线性循环方法应该没问题,例如

    out = 0;
    for (i = W - 1; i > 0; i = i - 1) begin
      if (in[i] && !out)
        out = i;
    end

如果你也关心表现,问题会变得更有趣。我曾尝试过编写参数化优先编码器here的不同方法。事实证明,Synopsys甚至可以从上面的脑死循环中生成有效的实现,但其他工具链需要显式生成魔法。以下是该链接的摘录:

    output [WIDTH_LOG - 1:0] msb;

    wire [WIDTH_LOG*WIDTH - 1:0] ors;
    assign ors[WIDTH_LOG*WIDTH - 1:(WIDTH_LOG - 1)*WIDTH] = x;

    genvar w, i;
    integer j;

    generate
      for (w = WIDTH_LOG - 1; w >= 0; w = w - 1) begin
        assign msb[w] = |ors[w*WIDTH + 2*(1 << w) - 1:w*WIDTH + (1 << w)];
        if (w > 0) begin
          assign ors[(w - 1)*WIDTH + (1 << w) - 1:(w - 1)*WIDTH] = msb[w] ? ors[w*WIDTH + 2*(1 << w) - 1:w*WIDTH + (1 << w)] : ors[w*WIDTH + (1 << w) - 1:w*WIDTH];
        end
      end
    endgenerate

答案 2 :(得分:0)

为了能够在part-slice后缀中使用变量索引,必须将for块括在一个generate块中,如下所示:

gen var i;
generate
for (i=0;i<7;i=i+1) begin :gen_slices
  always @* begin
    ... do whatever with in[7:i+1]
  end
end

问题在于,将它写入您的模块,它的编写方式会导致其他错误。你重写的模块看起来像这样(警告:这也行不通)

module enc (
  input wire [7:0] in,
  output reg [2:0] out  // I believe you wanted this to be 3 bits width, not 4.
  );

  genvar i; //a generate block needs a genvar
  generate
    for (i=0;i<7;i=i+1) begin :gen_block
      always @* begin
        if (in[i]==1'b1 && in[7:i+1]=='b0) // now this IS allowed :)
          out = i;
        else
          out = 3'b0;
      end
    end
  endgenerate
endmodule

这将引发一个综合错误,即out来自多个来源。这意味着分配给out的值同时来自多个来源,这是不允许的。

这是因为for块展开了类似这样的内容:

always @* begin
  if (in[0]==1'b1 && in[7:1]=='b0)
    out = 0;
  else
    out = 3'b0;
end
always @* begin
  if (in[1]==1'b1 && in[7:2]=='b0)
    out = 1;
  else
    out = 3'b0;
end
always @* begin
  if (in[2]==1'b1 && in[7:3]=='b0)
    out = 2;
  else
    out = 3'b0;
end
.... and so on...

现在你有多个组合块(always @*)试图将值设置为out。所有这些都将同时工作,并且所有这些都会尝试将out块的具体值设为if块评估为truefalse。回想一下,每个if语句的条件与其他if条件相互排斥(即只有一个if必须评估为true)。

因此,如果if块不会分配它,那么快速而又脏的方法来避免这种多源情况(我确信有更优雅的方法来解决这个问题)就是让它变为高阻抗一个值。像这样:

module enc (
  input wire [7:0] in,
  output reg [2:0] out  // I believe you wanted this to be 3 bits width, not 4.
  );

  genvar i; //a generate block needs a genvar
  generate
    for (i=0;i<7;i=i+1) begin :gen_block
      always @* begin
        if (in[i]==1'b1 && in[7:i+1]=='b0) // now this IS allowed :)
          out = i;
        else
          out = 3'bZZZ;
      end
    end
  endgenerate
  always @* begin
    if (in[7])  // you missed the case in which in[7] is high
      out = 3'd7;
    else
      out = 3'bZZZ;
  end
endmodule

另一方面,如果您只需要一个优先编码器,并且您的设计使用固定宽度和小宽度的输入和输出,您可以编写您的编码器:

module enc (
  input wire [7:0] in,
  output reg [2:0] out
  );

  always @* begin
    casex (in)
      8'b1xxxxxxx : out = 3'd7;
      8'b01xxxxxx : out = 3'd6;
      8'b001xxxxx : out = 3'd5;
      8'b0001xxxx : out = 3'd4;
      8'b00001xxx : out = 3'd3;
      8'b000001xx : out = 3'd2;
      8'b0000001x : out = 3'd1;
      8'b00000001 : out = 3'd0;
      default     : out = 3'd0;
    endcase
  end
endmodule

(虽然似乎有理由不在设计中使用casex。请阅读@Tim在其他问题中发表的评论:How can I assign a "don't care" value to an output in a combinational module in Verilog

总结:我担心我没有针对你的要求的防弹设计(如果我们考虑到蒂姆在评论中链接的论文的内容),但至少,你现在知道为什么{{在部分切片后缀中不允许使用1}}。


另一方面,你可以通过研究我给出的代码作为另一个SO问题的答案来完成一半的工作。在这种情况下,模块的工作方式类似于优先级编码器,参数化且没有i语句,只有输出不是二进制,而是单热编码。 How to parameterize a case statement with don't cares?

答案 3 :(得分:0)

所以我编辑的解决方案有效......多么愚蠢!我忘了宣布reg [2:0] i;而是写了reg i; 谢谢大家

答案 4 :(得分:0)

帅哥,我必须告诉你,您所有的解决方案要么太复杂,要么无法合成,或者实施到慢速多路复用器中。 OpenCores的Alexej Bolshakov于2015年8月23日上传了基于OR元素的出色参数化编码器。无多路复用器,可100%合成。他的代码(采用我的小格式):

module encoder #(
  parameter LINES = 16,
  parameter WIDTH = $clog2(LINES)
)(
  input      [LINES-1:0] unitary_in,
  output wor [WIDTH-1:0] binary_out
);

genvar i, j;

generate
for (i = 0; i < LINES; i = i + 1)
  begin: loop_i
    for (j = 0; j < WIDTH; j = j + 1)
    begin: loop_j
    if (i[j])
      assign binary_out[j] = unitary_in[i];
    end 
  end
endgenerate

endmodule

RTL viewer screenshotModel-Sim screenshot

答案 5 :(得分:0)

此解决方案将输入分为四个块,并检查第一个非零块。以相同的方式进一步细分该块。这是相当有效的。

// find position of most significant 1 bit in 64 bits input
// (system verilog)
module bitscan(
    input  logic [63:0] in,  // number input
    output logic [5:0]  out, // bit position output
    output logic zeroout     // indicates if input is zero
);

logic [63:0] m0;  // intermediates
logic [15:0] m1;
logic [3:0]  m2;
logic [5:0]  r;

always_comb begin
    m0 = in;
    // choose between four 16-bit blocks
    if (|m0[63:48]) begin
        m1 = m0[63:48];
        r[5:4] = 3;
    end else if (|m0[47:32]) begin
        m1 = m0[47:32];
        r[5:4] = 2;
    end else if (|m0[31:16]) begin
        m1 = m0[31:16];
        r[5:4] = 1;
    end else begin
        m1 = m0[15:0];
        r[5:4] = 0;
    end

    // choose between four 4-bit blocks
    if (|m1[15:12]) begin
        m2 = m1[15:12];
        r[3:2] = 3;
    end else if (|m0[11:8]) begin
        m2 = m1[11:8];
        r[3:2] = 2;
    end else if (|m0[7:4]) begin
        m2 = m1[7:4];
        r[3:2] = 1;
    end else begin
        m2 = m1[3:0];
        r[3:2] = 0;
    end

    // choose between four remaining bits    
    if      (m2[3]) r[1:0] = 3;
    else if (m2[2]) r[1:0] = 2;
    else if (m2[1]) r[1:0] = 1;
    else            r[1:0] = 0;

    out = r;
    zeroout = ~|m2;
end 
endmodule

这是另一种使用资源较少的解决方案:

module bitscan4 (
    input logic [63:0] in,
    output logic  [5:0] out,
    output logic  zout
);
logic [63:0] m0;
logic [3:0]  m1;
logic [3:0]  m2;
logic [5:0]  r;

always_comb begin
    r = 0;
    m0 = in;
    if (|m0[63:48]) begin
        r[5:4] = 3;
        m1[3] = |m0[63:60];
        m1[2] = |m0[59:56];
        m1[1] = |m0[55:53];
        m1[0] = |m0[51:48];        
    end else if (|m0[47:32]) begin
        r[5:4] = 2;
        m1[3] = |m0[47:44];
        m1[2] = |m0[43:40];
        m1[1] = |m0[39:36];
        m1[0] = |m0[35:32];
    end else if (|m0[31:16]) begin
        r[5:4] = 1;
        m1[3] = |m0[31:28];
        m1[2] = |m0[27:24];
        m1[1] = |m0[23:20];
        m1[0] = |m0[19:16];
    end else begin
        r[5:4] = 0;
        m1[3] = |m0[15:12];
        m1[2] = |m0[11:8];
        m1[1] = |m0[7:4];
        m1[0] = |m0[3:0]; 
    end

    if (m1[3]) begin
        r[3:2] = 3;
    end else if (m1[2]) begin
        r[3:2] = 2;
    end else if (m1[1]) begin
        r[3:2] = 1;
    end else begin
        r[3:2] = 0;
    end

    m2 = m0[{r[5:2],2'b0}+: 4];

    if      (m2[3]) r[1:0] = 3;
    else if (m2[2]) r[1:0] = 2;
    else if (m2[1]) r[1:0] = 1;
    else            r[1:0] = 0;

    zout = ~|m2;
    out = r;
end 

endmodule