1本のwire vs 複数
これまで見てきたsignalはすべて1ビット幅でした。実際の設計はほぼそうではありません。アドレスは16または32ビット、データバスは8または64、RGBピクセルは24です。Verilogはあらゆるsignalをマルチビットにする1つの仕組みを与えてくれます。角括弧で範囲を追加するだけです。
wire [7:0] data; // 8ビットwire、ビット7がMSB、ビット0がLSB
reg [15:0] address; // 16ビットreg
output reg [31:0] result; // 32ビットmodule出力
括弧内の数値は最上位ビットと最下位ビットの ビット位置 です。[7:0]は「このsignalは7から0までの番号のビットを持つ」という意味で、合計8ビットになります。最初の数値が高インデックス、2番目が低インデックスです。
時々[0:7]を見かけます。ビット数は同じですが、スライス目的では逆エンディアンです。[high:low]形式が業界の圧倒的な慣習です。強い理由がない限りこれに従ってください。
動作する例:8ビット加算器
各+は2つの8ビットvectorを加算して9ビットの結果を生成します。8'd10のような数値リテラルは「8ビット幅の10進数値10」を意味します。Number Literalsで扱います。
スライス:ビットを取り出す
vectorを持ったら、個々のビットや連続範囲を取り出せます:
testbenchのforce行に気を取られないでください。スライスをデモするために値を注入する方法が必要だっただけです。興味深いのはスライス自体です。
ルールはいくつか:
- スライス方向は宣言と一致しなければなりません。
[7:0]と宣言したなら[high:low]でスライスします。方向を逆にすると構文エラーになります。 - 範囲外のスライスはシミュレーションで
x(未知)を生成します。合成ツールは警告またはエラーを出すかもしれません。 - ビット選択は書いたインデックスに対して0ベースです。
data[0]は0という名前のビットで、[7:0]宣言の場合はLSBです。
可変ベースのスライス:+:と-:
よくあるニーズ:「ビットNから始まる8ビットを取り出す」。Verilogは範囲の両端を定数にすることを要求するので、data[N+7:N]を直接書けません。これを解決する構文:
data[base +: width] // baseから始まる幅widthのビット、上方向
data[base -: width] // baseから始まる幅widthのビット、下方向
幅は定数(一度に8ビット取る)ですが、ベースはランタイム式でも構いません。これがバイトアドレス可能なmemory、shift registerのタップなどに必要なものです。
配列:vectorの一歩先
vectorは単一のマルチビットsignalです。 配列 は独立にインデックス可能なvectorのコレクションです:
reg [31:0] mem [0:1023];
この宣言は2つのrangeを持ち、両者は異なる意味を持ちます:
[31:0]は packed次元 で、各ワードの幅。[0:1023]は unpacked次元 で、ワード数。
つまりmemは1024個の別々の32ビットregisterです。1つのインデックスで1つにアクセスします:
mem[5] = 32'hCAFE_BABE; // ワード5に書き込み
data = mem[address]; // `address`のワードを読み出し
これは平方数を保持する小さなmemoryです。実際の設計は同じパターンを使ってregisterファイル、ルックアップテーブル、FIFO、その他単一のvectorより大きい任意のオンチップストレージを保持します。
Packed vs Unpacked:なぜ重要か
packedとunpacked次元の分かれ方はあちこちに現れます。どちらがどちらかを知っていれば、多くのデバッグを省けます:
- packed vectorは1つのsignal。 全体を数値として扱えます:
data + 1が動き、data == 32'h0が動き、data[7:0]が動きます。 - unpacked配列は複数のsignal。 全体を数値として扱え ません :
mem + 1は構文エラーです。先に特定のワードを取り出さなければなりません。
複数のpacked次元も合法です:
reg [3:0][7:0] regs; // 4バイトをpackedして32ビットsignalに
regs[0]はバイト(下位バイト)。regs全体は32ビット。SystemVerilogでよく使います。
複数のunpacked次元は2Dのmemoryを作ります:
reg [31:0] frame [0:479][0:639]; // 480x640の32ビットピクセル
frame[y][x]で単一ピクセルにアクセスします。HDLでイメージバッファを表現する例です。
次に読むもの
これで必要な任意の幅のsignalを宣言・操作できます。次のドキュメントParametersでは、これらの幅を設定可能にし、同じmoduleが1つのinstanceでは8ビット、別では32ビットで動くようにする方法を示します。その後、リテラル数値(8'b1010_1100、32'hDEAD_BEEF)の書き方ルール、そして駆動されないときに現れるx/z値に進みます。
よくある質問
Verilogのvectorとは?
vectorはマルチビットsignalです。wireまたはregにrangeを追加して宣言します:wire [7:0] dataは8ビットwireです。括弧内の数値はビット位置で、この場合ビット7が最上位、ビット0が最下位です。個々のビット(data[3])や連続範囲(data[7:4])をスライスできます。
Verilogの[7:0]の意味は?
[7:0]はビット7からビット0までの範囲(両端含む)を宣言します。8ビットsignalで、ビット7が最上位ビットです。最初の数値が高インデックス、2番目が低インデックスです。[0:7]とリトルエンディアンに書くこともできますが、業界コードでは[high:low]形式が圧倒的に一般的な慣習です。
Verilogでビットをスライスするには?
括弧によるインデックスを使います。data[3]は1ビット選択。data[7:4]は上位4ビットを4ビットvectorとして選びます。スライス方向は宣言と同じ方向でなければなりません。[7:0]と宣言したなら[high:low]でスライスします。SystemVerilogでは可変ベースで定数幅のスライスとしてdata[3 +: 4]も追加されています。
Verilogのpackedとunpacked配列の違いは?
packed配列は連続した単一のバスです:reg [31:0] wordは1つの32ビットsignalです。unpacked配列(または「memory」)は独立したワードの集合です:reg [31:0] mem [0:1023]は1024個の別々の32ビットregisterです。unpacked配列の1ワード全体を読み書きできますが、全体を1つのsignalとして演算できません。
Verilogでmemoryを宣言するには?
reg [31:0] mem [0:1023];は1024エントリ、各32ビット幅のmemoryを宣言します。最初の括弧の組がワード幅(packed)で、2番目がワード数(unpacked)です。mem[address]でエントリにアクセスし、SystemVerilog-2005のインデックスが有効になっていればmem[address][7:0]でそのエントリのスライスを読み書きできます。