3

Verilog で、合成可能なパラメータ化されたプライオリティ エンコーダを作成しようとしています。具体的には、ベクトル内の最下位の 1 を見つけて、その 1 だけを含むベクトルを返したいと考えています。次に例を示します。

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

したがって、ベクトルが 4 ビット幅の場合、コードは次のようになります。

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 ステートメントのさまざまな配置を試みましたが、すべて成功しませんでした。これの適切な構文を知っている人はいますか? ケースステートメントの実装またはその他の代替手段も問題ありません。ありがとう。

4

4 に答える 4

2

generate の仕組みを誤解していると思います。generate/endgenerate ペアの間で適切な置換を行ってコードを出力するのは、テキスト プリプロセッサではありません。ペア内に完全な構文エンティティが必要です。現時点ではシミュレーターにアクセスできませんが、これでうまくいくかもしれません (まったくテストされていません)。

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 ループで最初に設定されたビットをテストし、その結果をデコードします。

于 2013-02-25T23:57:13.677 に答える
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
于 2013-02-26T01:36:13.530 に答える
1

これはあなたが望む方法をシミュレートしますが、合成可能ではありません(それが要件であるかどうかを指定しませんでした):

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

always @* begin
    least_one = '0;
    for (int i=ADDR_WIDTH-1; i>=0; i--) begin
        if (in[i]) least_one = 2**i;
    end
end

endmodule

SystemVerilog コンストラクトを使用することに注意してください。

于 2013-02-26T01:48:16.420 に答える
1

個人的には、次のコード ブロックが気に入っています。

これを試すこともできます (読みやすくするために余分な上位ビットを削除します) が、潜在的な互換性の問題を回避するために、2 の賛辞を明示的に行うのが好きです。

を割り当てます = で & (-1*in);

于 2014-02-09T07:55:28.123 に答える