Verilogではビット幅が異なる信号を代入することが良くあります。以下のような例です。
logic [31:0] a;
logic [15:0] b, b2, b2;
logic c;
assign a = b; //アサインによる代入
always_comb begin
a = b; //alwaysで組み合わせ回路を記述する場合
end
assign a = c ? b1 : b2; //これも同様。aとb1,b2のビット幅は合わせたい
言語仕様上は左辺より右辺のビット幅が短い場合は適切にビット拡張、長い場合は切り捨てとなっています。上記の場合では、いずれもa[31:16]には0が自動的に割り当てられます。
しかし、この機能に頼ると、意図しない信号のアサインの時にミスが検出できないため、一般には左右のビット幅は合わせるのがよいコーディングスタイルとされています。
wire [31:0] a;
wire [15:0] b;
assign a = {16'b0, b};
悩むのが、ビット幅がパラメータで指定されている場合です。せっかくパラメータで、後のビット幅変更に対応できるようにしているのに、この書き方では、パラメータの値を変更する度にその部分の修正が必要になります。
localparam A_W = 32;
localparam B_W = 16;
wire [A_W - 1:0] a;
wire [B_W - 1:0] b;
assign a = {16'b0, b}; //B_Wを17にしたら右辺を{15'b0, b}に変更する必要がある
対処方法を以下にいくつか挙げます。
#ダミーのall 0/ all 1信号を定義する
泥臭いですが、どのツールでも確実に動作します。他の方法と比べて、簡単に符号拡張する方法がない点、サイズ間の矛盾チェック、下の例だとA_WよりB_Wが大きくなった場合のシミュレータによるチェックが働かないのが欠点です。何らかの理由で他の方法が適用できない場合にどうぞ。
localparam A_W = 32;
localparam B_W = 16;
wire [A_W - 1:0] a;
wire [B_W - 1:0] b;
localparam [A_W - 1 : 0] ZERO_VECTOR = {A_W{1'b0}};
assign a = {ZERO_VECTOR[A-W - 1 : B_W], b};
#parameterの値を使用して足りないビット部分を埋める
Verilogの場合のお勧めです。右辺が符号付信号の場合も簡単に符号拡張できます。パラメータの変更により右辺のほうが左辺よりも長くなってしまった場合は(A-W < B-Wの場合は)シミュレータがエラーを吐いてくれます1。
localparam A_W = 32;
localparam B_W = 16;
localparam C_W = 33;
wire [A_W - 1:0] a;
wire [B_W - 1:0] b;
wire [C_W - 1:0] c;
assign a = {{A_W - B_W{1'b0}}, b};// 0で埋める場合
assign a = {{A_W - B_W{b[B_W - 1]}}, b}; // 符号拡張
assign a = {{A_W - C_W{1'b0}}, c}; // エラー
#System Taskを使用する
System Verilogの場合のお勧めです。上記の方法では、ビット幅がparameterで定義されていない場合に対応できないのが欠点です。これに対応するにはSystem Verilogのみですが、$bits等のSystem Taskを使用する方法があります。私の知っている範囲では、全てのシミュレータ、論理合成ツールが対応しています。ツールサポートの問題さえなければこの方法が一番汎用性があります。
localparam A_W = 32;
localparam B_W = 16;
wire [A_W - 1:0] a;
wire [B_W - 1:0] b;
wire [3:0] c;
assign a = {{$bits(a) - $bits(b){1'b0}}, b}; // 0で埋める場合
assign a = {{$bits(a) - $bits(b){b[B_W - 1]}}, b}; // 符号拡張
assign a = {{$bits(a) - $bits(c){1'b0}}, c}; //ビット幅がparameterでない場合にも対応可能
#LRM
- Verilog (IEEE Std 1364-2005)
- 5.1.14 Concatenations
- System verilog (IEEE Std 1800-2012)
- 11.4.12.1 Replication operator
- 20.6.2 Expression size system function
-
言語仕様としてはエラーなのですが、実際の対応はシミュレータ依存のようです。この記事を書くにあたり複数のシミュレータで確認しましたが、特にオプション指定しない場合はVCSとIcarusではエラー、Incisiveでは警告、Riviera Proではそのまま動作となりました。ツールのバージョンやオプション指定でも変わるかもしれません。 ↩