Menu

Verilog 数値リテラル:2進数、16進数、10進数、サイズ付き定数

Verilogが定数をどう書くか:sized vs unsized、'b/'h/'d/'oのbase、signed数、可読性のためのアンダースコア、初心者を引っかける罠。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

sizedリテラルの構造

Verilogリテラルは最大3つの部分を持ちます:

8'b1010_1100
│  │ │
│  │ └─ 選択したbaseでの桁
│  └─── base指定子: b (2進), h (16進), d (10進), o (8進)
└────── ビット幅(10進)

左から右に読む:「8ビット値、2進で、桁は10101100」。これは10進で172、16進で0xAC、どちらの書き方でも同じビット列です。幅はコンパイラに正確に何ビット割り当てるかを伝え、baseは桁の解釈方法を伝えます。

アンダースコアは視覚的セパレータです。32'b1010_1100_0011_010132'b1010110000110101と同じです。使いましょう。

4つのbase

16進(h)は4ビットを超えるあらゆるものの標準です。2進(b)はビットパターンを直接読みたいときの標準です。10進(d)は人間にとって意味のあるカウント用。8進(o)は存在しますが、ほぼ目にしません。

16進の桁は大文字小文字を区別しません:8'hAB8'habは同じです。

値が幅に収まらない場合

桁が宣言した幅を満たさないと、Verilogは 左側にゼロ拡張 します:

8'b101       // 8'b00000101と等価 (= 5)
8'hF         // 8'h0Fと等価        (= 15)

桁が宣言した幅を 超える と、Verilogは 上位ビットを切り詰め ます(警告つき):

4'hFF        // 4'hFに切り詰め、シミュレータが警告
4'b10000     // 4'b0000に切り詰め

警告は味方です。抑制しないでください。

sized vs unsized

のない リテラル:

'd10    // unsized、デフォルトサイズ(≥32ビット)を取る
10      // これもunsized - baseなしは10進を意味する

unsizedリテラルはほとんどのツールで32ビットがデフォルトです。これはバグの一つのクラスの源です:

reg [7:0] count;
if (count == -1) ...      // -1はunsignedな32ビット; 比較がおかしくなる

修正は-1の代わりに8'hFF、または8'd255、または{8{1'b1}}と書くことです。幅指定の式で使われるリテラルは常にsizedにしてください。

unsizedリテラルが許される唯一の場所は、testbenchのforループの整数カウンタで、integerが幅広いので意外なことは起きません。

signedリテラル

デフォルトでは、sizedリテラルは unsigned です:

8'd255   // unsigned 255
8'b1111_1111   // unsigned 255 - 同じビットパターン、ただ書き方が違うだけ

リテラルをsignedとして解釈したい場合、アポストロフィの後にsを追加します:

8'sd10           // signed 10
8'sb1111_1111    // signed -1(2の補数)

sフラグが重要なのは:

  • <<<>>>演算子(算術シフト)。signedオペランドを符号拡張します。
  • signed混在式の比較演算子。
  • $signed/$unsignedキャスト。

通常のバスsignalの算術では、sは外しておきます。

XとZを含む数値リテラル

リテラル桁はx(未知)またはz(ハイインピーダンス)にできます:

8'bxは「全8ビット未知」の略記です。値が宣言された幅を満たすように伝播されます。xの桁は状態機械のdefaultケースや初期化でよく使われます。意味論はXとZの値で扱います。

sizedリテラルが実践でどこに現れるか

実際のmoduleを書き始めると、sizedリテラルはあちこちに現れます:

// バス幅
input  wire [31:0] addr;
wire [31:0] zero = 32'h0;
wire [31:0] all_ones = 32'hFFFF_FFFF;

// State encoding
localparam IDLE = 3'd0;
localparam BUSY = 3'd1;
localparam DONE = 3'd2;

// マスク
wire is_msb_set = data & 32'h8000_0000;

// 比較
if (counter == 8'd255) ...

// reset値
always @(posedge clk) begin
    if (reset) data_out <= 8'd0;
    else       data_out <= data_in;
end

パターンは一貫しています。幅を書く、baseを書く、桁を書く。手にするすべてのリテラルが同じ形です。

試運転

これでVerilog moduleが必要とする任意の定数を書くのに必要なものすべてが揃いました。データ型の話の最後の一片は、signalがきれいな0や1でないときに何が起こるか、つまりxzの値です。

よくある質問

Verilogの8'b1010の意味は?

sizedな2進リテラルです。8ビットの値で、2進表現は00001010です。アポストロフィの前の数値はビット幅で、アポストロフィの後の文字がbase(bは2進、hは16進、dは10進、oは8進)、その後の桁が値です。桁が幅に満たない場合、左側にゼロ詰めされます。

sizedとunsized数の違いは?

8'd10のようなsizedリテラルはちょうど8ビット幅です。'd10や単に10のようなunsizedリテラルはデフォルトで32ビットになり、通常多すぎます。unsizedリテラルを幅指定の式に混ぜると微妙なバグの原因になります。捨て駒のテストコード以外では、どこでもsizedリテラルを使ってください。

Verilogで16進数を書くには?

'h base指定子を使います:8'hFFは255の8ビット値です。16進の桁は大文字小文字を区別しません。8'hff8'hFFは同じです。可読性のためアンダースコアで桁をグループ化できます:32'hDEAD_BEEF。アンダースコアはパーサに無視されます。

Verilog数値でアンダースコアはどう働きますか?

アンダースコアはパーサが無視する視覚的なセパレータです。32'b1010_1100_0011_010132'b1010110000110101とまったく同じ値ですが、ずっと読みやすいです。base prefixの直後の最初の文字はアンダースコアにできませんが、それ以外の桁文字列のどこにでも置けます。

Verilogでsigned数を書くには?

アポストロフィの後にsを追加します。8'sd10は8ビット10進のsigned 10で、8'sb1111_1111はsigned -1です。デフォルトでは、sizedリテラルはunsignedです。s修飾子がそれを反転させます。ほとんどの算術はunsignedオペランドを使うので、負の値が<>>>などの演算子で本当に伝播する必要があるときだけsignedに手を出してください。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める