Verilogデータ型:ビット、ワイヤ、ロジック値を完全理解
Verilogにおけるデータ型の主な目的は、フリップフロップ内のビットのようなデータ保存要素や、ロジックゲートや順序構造を接続するワイヤのような伝送要素を表現することです。
変数が保持する値とは?
ほぼすべてのデータ型は、real と event を除き、以下の4つの値のいずれかのみを取ります:
| 0 | ロジック0、または偽条件を表す |
| 1 | ロジック1、または真条件を表す |
| x | 未知のロジック値(0か1のどちらか)を表す |
| z | ハイインピーダンス状態を表す |
これらの値がタイミング図やシミュレーション波形でどう表現されるかを示します。多くのシミュレータでは、赤 が X、中央の オレンジ がハイインピーダンス Z を表す慣習です。
Verilog値セットの意味
VerilogはフリップフロップやNAND、NORといった組み合わせ論理といったハードウェア要素を記述するため、ハードウェアに見られる値システムをモデル化する必要があります。ロジック1は電源電圧 Vdd を表し、製造プロセスノードにより0.8V〜3V以上の範囲を取ります。ロジック0は グラウンド、すなわち0Vを表します。
X または x は、その時点で値が単純に未知であり、0か1のどちらかであることを意味します。これはブール論理における「ドントケア(どちらでもよい)」を意味する X とは全く異なります。
未接続の電気回路では、何にも接続されていないワイヤのノードはハイインピーダンス状態になり、Z または z で表されます。Verilogでも、未接続のワイヤはハイインピーダンスになります。
ネットと変数
ネット と 変数 は、異なるハードウェア構造を表す2つの主要なデータ型グループで、値の割り当て方と保持の仕方が異なります。
ネット
ネット はロジックゲートなどのハードウェアエンティティ間を接続するために使われ、独自に値を保持しません。下図では、net_11 というネットがANDゲートの出力と data_0 というフリップフロップの第1入力を接続しています。同様に、ANDゲートの2入力は net_45 と net_67 に接続されています。
ネットにはそれぞれ異なる特性を持つ複数の種類がありますが、デジタル設計で最も一般的かつ広く使われる ネット は wire タイプです。wire は、単一のゲートや連続代入によって駆動される要素やネットを接続するためのVerilogデータ型です。ブレッドボード上で2つのコンポーネントを接続する電気ワイヤに似ています。
複数のネットが必要な場合、それらを束ねて単一の wire とできます。下図は4ビットのワイヤで、4つの独立した値を各ワイヤで送れます。幅が1より大きいこのようなエンティティは、次回の記事で説明するベクトルと呼ばれます。
wire [3:0] n0; // 4ビットワイヤ → これはベクトル
すでにネット、パラメータ、変数で宣言されている名前を再宣言することは違法です:
module design;
wire abc;
wire a;
wire b;
wire c;
wire abc; // Error: Identifier "abc" previously declared
assign abc = a & b | c;
endmodule
変数
一方、変数 はデータ保存要素の抽象化であり、値を保持できます。フリップフロップは保存要素の好例です。
Verilogデータ型 reg は、代入間で値を保持できるため、ハードウェアレジスタのモデリングに使用できます。reg が必ずしもフリップフロップを表すわけではなく、組み合わせ論理を表すこともあります。
その他のデータ型
integer
integer は汎用の32ビット幅変数で、ハードウェアモデリング時のその他目的で使用し、整数値を格納します。
integer count; // countは0より大きい整数値
time
time 変数は符号なし64ビット幅で、デバッグ目的でシミュレーション時間量を格納するのに使用します。realtime 変数は時間を浮動小数点量として格納します。
time end_time; // end_timeに50nsのような時間値を格納
realtime rtime; // rtime = 40.25ps
real
real 変数は浮動小数点値を格納でき、integer や reg と同様に代入可能です。
real float; // float = 12.344 - 浮動小数点数を格納
例
module testbench;
integer int_a; // 整数変数
real real_b; // 実数変数
time time_c; // 時間変数
initial begin
int_a = 32'hcafe_1234; // 整数値を代入
real_b = 0.1234567; // 浮動小数点値を代入
#20; // シミュレーション時間を20進める
time_c = $time; // 現在のシミュレーション時間を代入
// $displayシステムタスクで全変数を表示
$display ("int_a = 0x%0h", int_a);
$display ("real_b = %0.5f", real_b);
$display ("time_c = %0t", time_c);
end
endmodule
シミュレーションログ
ncsim> run int_a = 0xcafe1234 real_b = 0.12346 time_c = 20 ncsim: *W,RNQUIE: Simulation is complete.
Verilog文字列
文字列は reg に格納され、reg 変数の幅は文字列を保持するのに十分な大きさでなければなりません。文字列の各文字はASCII値を表し、1バイト必要です。変数サイズが文字列より小さい場合、文字列の左側(上位ビット)が切り捨てられます。変数サイズが大きい場合、左側にゼロがパディングされます。
// "Hello World" は11バイト必要
reg [8*11:1] str = "Hello World"; // 11バイト格納可能 → "Hello World"
reg [8*5:1] str = "Hello World"; // 5バイトのみ → 上位6バイト切り捨て → "World"
reg [8*20:1] str = "Hello World"; // 20バイト格納可能 → 左にゼロパディング → " Hello World"
上記3変数のシミュレーション例:
module testbench;
reg [8*11:1] str1;
reg [8*5:1] str2;
reg [8*20:1] str3;
initial begin
str1 = "Hello World";
str2 = "Hello World";
str3 = "Hello World";
$display ("str1 = %s", str1);
$display ("str2 = %s", str2);
$display ("str3 = %s", str3);
end
endmodule
str1 は適切なサイズで "Hello World" 全体が表示されます。str2 は5バイトしか格納できないため上位6バイトが切り捨てられ "World" のみ。str3 は11バイトより大きいため左に空白がパディングされ " Hello World" になります。
シミュレーションログ
ncsim> run str1 = Hello World str2 = World str3 = Hello World ncsim: *W,RNQUIE: Simulation is complete.
Verilog