Verilog ユーザー定義プリミティブ
nand
のような標準 Verilog プリミティブ と not
複雑なロジックを表現するには、常に簡単または十分であるとは限りません。 UDP と呼ばれる新しいプリミティブ要素 または ユーザー定義のプリミティブ 組み合わせロジックまたは順序ロジックをモデル化するように定義できます。
すべての UDP には、0、1、または X のいずれかであり、Z ではない (サポートされていない) 1 つの出力があります。値 Z を持つ入力はすべて X として扱われます。
Verilog UDP シンボル
Verilog ユーザー定義プリミティブは、module と同じレベルで記述可能 module
の間ではありません。 と endmodule
.多くの入力ポートを持つことができますが、出力ポートは常に 1 つです。双方向ポートは有効ではありません。すべてのポート信号はスカラーである必要があります。つまり、1 ビット幅でなければなりません。
ハードウェアの動作は プリミティブ として記述されます table
内の入力とそれに対応する出力のさまざまな可能な組み合わせをリストした状態テーブル および endtable
.入力信号と出力信号の値は、次の記号を使用して示されます。
シンボル | コメント |
---|---|
0 | ロジック 0 |
1 | ロジック 1 |
x | 不明、論理 0 または 1 のいずれかになります。順次 UDP の入力/出力または現在の状態として使用できます |
? | 論理 0、1、または x。どのUDPも出力できません |
- | 変更なし、UDP の出力でのみ許可 |
ab | a から b への値の変化 (a または b は 0、1、または x のいずれか) |
* | ?? と同じ、入力値の変更を示します |
r | 01 と同じ -> 入力の立ち上がりエッジ |
f | 10 と同じ -> 入力の立ち下がりエッジ |
p | 入力のポジティブ エッジの可能性。 0->1、0->x、または x->1 のいずれか |
n | 入力の立ち下がりエッジの可能性。 1->0、x->0、1->x | のいずれか
組み合わせ UDP の例
// Output should always be the first signal in port list
primitive mux (out, sel, a, b);
output out;
input sel, a, b;
table
// sel a b out
0 1 ? : 1;
0 0 ? : 0;
1 ? 0 : 0;
1 ? 1 : 1;
x 0 0 : 0;
x 1 1 : 1;
endtable
endprimitive
?
信号が 0、1、または x のいずれかであり、最終的な出力を決定する際に問題にならないことを示します。
以下に示すのは、UDP をインスタンス化し、それに入力刺激を適用するテストベンチ モジュールです。
module tb;
reg sel, a, b;
reg [2:0] dly;
wire out;
integer i;
// Instantiate the UDP - note that UDPs cannot
// be instantiated with port name connection
mux u_mux ( out, sel, a, b);
initial begin
a <= 0;
b <= 0;
$monitor("[T=%0t] a=%0b b=%0b sel=%0b out=%0b", $time, a, b, sel, out);
// Drive a, b, and sel after different random delays
for (i = 0; i < 10; i = i + 1) begin
dly = $random;
#(dly) a <= $random;
dly = $random;
#(dly) b <= $random;
dly = $random;
#(dly) sel <= $random;
end
end
endmodule
シミュレーションログ xcelium> run [T=0] a=0 b=0 sel=x out=0 [T=4] a=1 b=0 sel=x out=x [T=5] a=1 b=1 sel=x out=1 [T=10] a=1 b=1 sel=1 out=1 [T=15] a=0 b=1 sel=1 out=1 [T=28] a=0 b=0 sel=1 out=0 [T=33] a=0 b=0 sel=0 out=0 [T=38] a=1 b=0 sel=0 out=1 [T=40] a=1 b=1 sel=0 out=1 [T=51] a=1 b=1 sel=1 out=1 [T=54] a=0 b=0 sel=1 out=0 [T=62] a=1 b=0 sel=1 out=0 [T=67] a=1 b=1 sel=1 out=1 [T=72] a=0 b=1 sel=1 out=1 [T=80] a=0 b=1 sel=0 out=0 [T=84] a=0 b=0 sel=0 out=0 [T=85] a=1 b=0 sel=0 out=1 xmsim: *W,RNQUIE: Simulation is complete.
順次 UDP の例
シーケンシャル ロジックは、レベル センシティブまたはエッジ センシティブのいずれかになるため、2 種類のシーケンシャル UDP があります。出力ポートも reg
として宣言する必要があります UDP 定義内で入力し、オプションで initial
内で初期化できます
順次 UDP には、入力フィールドと出力フィールドの間に、:
で区切られた追加フィールドがあります。 現在の状態を表します。
レベル センシティブ UDP
primitive d_latch (q, clk, d);
output q;
input clk, d;
reg q;
table
// clk d q q+
1 1 : ? : 1;
1 0 : ? : 0;
0 ? : ? : -;
endtable
endprimitive
上記の表では、ハイフン -
表の最後の行の は、q+ の値に変化がないことを示します。
module tb;
reg clk, d;
reg [1:0] dly;
wire q;
integer i;
d_latch u_latch (q, clk, d);
always #10 clk = ~clk;
initial begin
clk = 0;
$monitor ("[T=%0t] clk=%0b d=%0b q=%0b", $time, clk, d, q);
#10; // To see the effect of X
for (i = 0; i < 50; i = i+1) begin
dly = $random;
#(dly) d <= $random;
end
#20 $finish;
end
endmodule
シミュレーションログ xcelium> run [T=0] clk=0 d=x q=x [T=10] clk=1 d=1 q=1 [T=13] clk=1 d=0 q=0 [T=14] clk=1 d=1 q=1 [T=17] clk=1 d=0 q=0 [T=20] clk=0 d=1 q=0 [T=28] clk=0 d=0 q=0 [T=30] clk=1 d=1 q=1 [T=38] clk=1 d=0 q=0 [T=39] clk=1 d=1 q=1 [T=40] clk=0 d=1 q=1 [T=42] clk=0 d=0 q=1 [T=47] clk=0 d=1 q=1 [T=50] clk=1 d=0 q=0 [T=55] clk=1 d=1 q=1 [T=59] clk=1 d=0 q=0 [T=60] clk=0 d=0 q=0 [T=61] clk=0 d=1 q=0 [T=64] clk=0 d=0 q=0 [T=67] clk=0 d=1 q=0 [T=70] clk=1 d=0 q=0 [T=73] clk=1 d=1 q=1 [T=74] clk=1 d=0 q=0 [T=77] clk=1 d=1 q=1 [T=79] clk=1 d=0 q=0 [T=80] clk=0 d=0 q=0 [T=84] clk=0 d=1 q=0 [T=86] clk=0 d=0 q=0 [T=87] clk=0 d=1 q=0 [T=90] clk=1 d=1 q=1 [T=91] clk=1 d=0 q=0 [T=100] clk=0 d=0 q=0 [T=110] clk=1 d=0 q=0 Simulation complete via $finish(1) at time 111 NS + 0
エッジセンシティブ UDP
以下に示す例では、D フリップフロップは Verilog ユーザー定義プリミティブとしてモデル化されています。クロックの立ち上がりエッジは 01
で指定されることに注意してください または 0?
primitive d_flop (q, clk, d);
output q;
input clk, d;
reg q;
table
// clk d q q+
// obtain output on rising edge of clk
(01) 0 : ? : 0;
(01) 1 : ? : 1;
(0?) 1 : 1 : 1;
(0?) 0 : 0 : 0;
// ignore negative edge of clk
(?0) ? : ? : -;
// ignore data changes on steady clk
? (??): ? : -;
endtable
endprimitive
テストベンチでは、UDP がインスタンス化され、ランダムな数のクロックの後にランダムな d 入力値で駆動されます。
module tb;
reg clk, d;
reg [1:0] dly;
wire q;
integer i;
d_flop u_flop (q, clk, d);
always #10 clk = ~clk;
initial begin
clk = 0;
$monitor ("[T=%0t] clk=%0b d=%0b q=%0b", $time, clk, d, q);
#10; // To see the effect of X
for (i = 0; i < 20; i = i+1) begin
dly = $random;
repeat(dly) @(posedge clk);
d <= $random;
end
#20 $finish;
end
endmodule
画像から、出力 q が 1 クロック遅延後に入力 d に追従することがわかります。これは、D フリップフロップの望ましい動作です。
シミュレーションログxcelium> run [T=0] clk=0 d=x q=x [T=10] clk=1 d=1 q=x [T=20] clk=0 d=1 q=x [T=30] clk=1 d=1 q=1 [T=40] clk=0 d=1 q=1 [T=50] clk=1 d=1 q=1 [T=60] clk=0 d=1 q=1 [T=70] clk=1 d=0 q=1 [T=80] clk=0 d=0 q=1 [T=90] clk=1 d=1 q=0 [T=100] clk=0 d=1 q=0 [T=110] clk=1 d=1 q=1 [T=120] clk=0 d=1 q=1 [T=130] clk=1 d=1 q=1 [T=140] clk=0 d=1 q=1 [T=150] clk=1 d=0 q=1 [T=160] clk=0 d=0 q=1 [T=170] clk=1 d=0 q=0 [T=180] clk=0 d=0 q=0 [T=190] clk=1 d=0 q=0 [T=200] clk=0 d=0 q=0 [T=210] clk=1 d=1 q=0 [T=220] clk=0 d=1 q=0 [T=230] clk=1 d=1 q=1 [T=240] clk=0 d=1 q=1 [T=250] clk=1 d=1 q=1 [T=260] clk=0 d=1 q=1 [T=270] clk=1 d=1 q=1 [T=280] clk=0 d=1 q=1 [T=290] clk=1 d=1 q=1 [T=300] clk=0 d=1 q=1 [T=310] clk=1 d=1 q=1 [T=320] clk=0 d=1 q=1 [T=330] clk=1 d=1 q=1 [T=340] clk=0 d=1 q=1 [T=350] clk=1 d=1 q=1 [T=360] clk=0 d=1 q=1 [T=370] clk=1 d=0 q=1 [T=380] clk=0 d=0 q=1 [T=390] clk=1 d=0 q=0 [T=400] clk=0 d=0 q=0 [T=410] clk=1 d=1 q=0 [T=420] clk=0 d=1 q=0 [T=430] clk=1 d=1 q=1 [T=440] clk=0 d=1 q=1 [T=450] clk=1 d=1 q=1 [T=460] clk=0 d=1 q=1 [T=470] clk=1 d=1 q=1 [T=480] clk=0 d=1 q=1 Simulation complete via $finish(1) at time 490 NS + 0
Verilog