Help us understand the problem. What is going on with this article?

ビット幅が異なる信号間のアサイン

More than 1 year has passed since last update.

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

  1. 言語仕様としてはエラーなのですが、実際の対応はシミュレータ依存のようです。この記事を書くにあたり複数のシミュレータで確認しましたが、特にオプション指定しない場合はVCSとIcarusではエラー、Incisiveでは警告、Riviera Proではそのまま動作となりました。ツールのバージョンやオプション指定でも変わるかもしれません。 

triggerfish
ASIC職人です。デザイナですが検証もやります。ネタとしては検証のほうが書きやすいので、そちらが記事のメインになると思います。入門記事よりはプロの方が実務で役に立つような記事を目指しています。内容に不明点がありましたら遠慮なく質問をお願いいたします!
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした