同期回路の設計。 Verilog HDLのクイックスタート

インターネットでは、Verilog HDLの紹介を含む多くの記事を見つけることができます。 それらはすべて、言語の構文とセマンティクスを説明していますが、残念ながら、デジタル回路の設計で使用される基本的なパラダイムを開示していません。 Java言語の構文を説明するが、オブジェクト指向設計については何も語らないことを想像してください。 OOPに精通している場合、このような入門書で十分ですが、Cのみを知っている場合は、「古い方法」で記述し、複雑なメソッドを持つ巨大なクラスを作成する可能性が高くなります。



このようなことは、デジタル回路とハードウェア記述言語を勉強しているプログラマーで起こります。 言語の単純な構文をすぐに理解し、ハードウェアエンジニアの観点からは頭がおかしい構成について説明し始めます。 私の学生の中には、クロックサイクルごとに「バブルソーティング」を書いた人、スタートごとに異なる動作をするクレイジーな非同期回路、窓の外のさまざまな天気、何時間もかけて思いやりに満ちた巨大な組み合わせの仕切りがありました。



入門書を読む時間がないが、欲求または

いくつかの単純な回路を設計する必要があるため、デジタル回路を設計するための主要な現代のパラダイムである同期回路について、この短い紹介を書くことにしました。 そして、それらの記述に使用される言語の1つについて。

この記事は初心者を対象としています。 テキストを理解するには、最低限の知識が必要です-同期Dトリガーとゲートの理解。



同期回路



同期デジタル回路は、ゲート、回路(ネット)、およびフリップフロップで構成されます。 同期回路には、すべてのメモリ要素(トリガー)を制御する単一の同期信号があります。



正式には、同期回路は次のように定義できます。

同期回路は、次の条件を満たすゲート、トリガー、信号伝搬回路で構成されるデジタル回路Cです。



同期回路の例を図に示します。





非同期回線の例を次に示します。





既存のほとんどすべてのデジタル回路は同期であるか、非同期チャネルを介して相互作用する複数の同期回路で構成されています。 同期回路が普及している理由は、信号の伝播時間の分析が簡単だからです。 タイミング解析は別の記事のトピックですが、この問題について簡単に触れておく必要があります。



関数R = A + B + 1を実装する次のスキームを検討してください。





レジスタA、B、およびRは、同期信号(clk)のリーディングエッジに沿った入力Dで値を保存します。 clk値が0から1に変化するその時点で。



信号は加算器(およびその他の組み合わせ要素)を瞬時に伝播しませんが、ゲートからの最大パス(クリティカルパス)の長さに応じた遅延で伝播します。 要素の複雑さから。 たとえば、加算器のクリティカルパスは転送信号を通過して高次になります(「列」で合計を計算することを想像してください)。



最初の0.がすべてのレジスタに書き込まれ、入力1と4に最初に値1と4、次に2と1が入力されたと仮定すると、回路のタイムダイアグラムは次のようになります。







clkの最初のエッジで、値1と4がレジスタAとBに書き込まれます。信号が加算器を伝搬した後、結果値1 + 4 + 1 = 6がワイヤt1に表示されます。 次に、clkの2番目のエッジで、結果がレジスタRに書き込まれ、新しい入力値がレジスタAおよびBに書き込まれます。



ここで、clk信号の周期が半分になったと仮定します。 その後、正しいデータがt1に現れる前に、信号clkの2番目のエッジがレジスタRに現れます。 つまり 回路は正しく機能しません!



ここから、同期回路の正しい動作の基本的な規則に従います。



回路内のクリティカルパスを通る遅延は、同期信号の周期よりも短くする必要があります。



クリティカルパスは、レジスタの出力から入力までの回路内の最長パスです。 帰納法は、同期回路の最大の欠点の1つを特徴付けるこの規則から導出されます。



同期回路は、回路内で決定的に決定された周波数で動作します。



1ナノ秒の遅延で回路内に数千の組み合わせパスがあると想像してください。 そして、2ナノ秒の遅延を伴う1つの方法。 この唯一の方法のため、回路は500 MHzの周波数でクロックする必要がありますが、ギガヘルツで動作する可能性があります。 したがって、同期回路を設計するとき、長い組み合わせチェーンはレジスタによってコンベアステージに分割されます。 たとえば、AMD Bulldozerプロセッサでは、組み合わせパスの平均長は12〜14 FO4相当ゲート(4インバータを搭載したユニットサイズインバータに相当する遅延)です。



この欠点にもかかわらず、同期回路は非常に普及しています。 同期回路は、時間分析によって簡単に自動化できます。 回路が正しく動作できる周波数は、プログラム(一時アナライザー)によって自動的に決定されます。 開発者がこれらの詳細から離れることができる場合、同期回路はレジスタ間の一連の転送によって指定できます。 回路の記述に対するこのアプローチ-レジスタ転送ロジック(RTL)は、デジタル回路の論理の記述の主流になりました。 たとえば、この例の回路は、次の転送によって説明できます。



A = in0

B = in1

R = A+B+1









各クロックで、in0がレジスタAに書き込まれ、in1がレジスタBに書き込まれ、A + B + 1がレジスタRに書き込まれます。RTL回路をテキストとして記述する考え方は、ハードウェア記述言語であるVerilog HLDおよびVHDLの根底にあります。 それらの1つをよりよく知る時間です。



Verilog HDLの同期回路の説明



モジュール


Verilog上のプログラムは、回路の説明でもあり、モジュール(モジュール)、より正確には、モジュールのインスタンス(モジュールインスタンス)で構成されています。 モジュールは、ワイヤが突き出した「ブラックボックス」、つまりポートと考えることができます。 ポートには、入力(入力)、出力(出力)、および双方向(入力)の3つのタイプがあります。 ほとんどの場合、最初の2種類のポートが使用されます。 3つの状態とオープンドレインの出力に基づいて双方向バスをモデル化するには、双方向ポートが必要です。 それらは考慮しません。



ポートのリストは、モジュールヘッダーに記載されています。 たとえば、次の空のモジュールを考えてみましょう。



module blackbox // module - , blackbox -

(

input a, b, c // a,b,c

input [7:0] bus, // bus - 8-

output [7:0] bus_out // bus_out, 8-

);

//



endmodule // endmodule - ,









モジュールの本体には、その機能が記述されています。 このモジュールは空で、そのポートはどこにも接続されていません。 モジュールの機能の説明に移る前に、Verilogの基本的なデータタイプを紹介します。



データ型


Verilogには、ハードウェアをシミュレートするためのタイプと、Cからコピーされた標準的な算術データタイプの2種類のタイプがあります。 最初のクラスのみを検討します。なぜなら、 回路内の信号のモデル化に使用されるのは彼です。



Verilogでは、信号は4つの値を取ることができます。



ほとんどのVerilogモジュールは、 wireregの 2つの主要なデータタイプを使用します。 名前から、 wireはワイヤをモデル化し、 regはレジスタであるように見えるかもしれませんが、後で示すように、これは完全に真実ではありません。 2つのタイプの存在は、言語の設計におけるバグです。Verilogの最新バージョンであるSystemVerilogには、すべての場合に使用できる汎用タイプのロジックがあります。



それぞれのタイプを個別に検討してください。



ワイヤー



ワイヤタイプは、状態を「保存」できない信号をシミュレートするために使用されます。 たとえば、組み合わせ回路の出力の値は、入力の値によって完全に決定されます。 入力の値が変化すると、出力の値も変化します。 状態は保存されません。 ワイヤタイプは、連続割り当て操作-assignとともに使用されます。 連続割り当てでは、割り当ての右側の変数の値が変更されるたびに、左側の変数の値が更新されます。 たとえば、単純な組み合わせ回路は次のように記述できます。

module comb

(

input wire [7:0] a,b,

output [7:0] res // wire -, output wire [7:0] res

);



assign res = a+b+1;

endmodule













シグナルはモジュール本体内でも宣言できます:



module comb

(

input wire [7:0] a,b,

output [7:0] res

);



wire [3:0] x,y;

assign x = a[3:0] + b[3:0]; // 4 b

assign y = a[7:4] + b[7:4]; // 4 b

assign res = x+y;

endmodule












Regs



タイプregは値を格納でき、手続き型ブロックで使用されます。 Verilogのプロシージャブロックは、特定のイベントで起動するプロシージャです。 たとえば、このイベントは、クロック信号のフロントまたはシミュレーションの開始である可能性があります。 手続きブロックでは、Cのような制御構造を使用できます。





手続き型ブロックは、同期回路(メモリのある回路)と組み合わせ回路の両方をシミュレートできます。 たとえば、バイナリカウンター回路の説明を考えます。



module counter

(

input clk, reset,

output [7:0] data

);

reg [7:0] counter;



assign data = counter;



always @( posedge clk) // clk

begin

if (reset)

counter = 0;

else

counter = counter + 1;

end



endmodule












常に @( posedge clk)行は感度リストと呼ばれます。 手続き型ブロックが実行されるイベントを定義します。 このブロックは、同期信号の各立ち上がりエッジで実行されます。 したがって、ブロックはカウンタのロジックをシミュレートし、カウンタ信号はレジスタとして合成されます。



手続き型ブロックは組み合わせ回路もモデル化できます。 たとえば、次のコードは合成器に合成されます。

wire [7:0] a,b;

reg [7:0] res;



always @*

begin

res = a+b;

end







ここで、感度リストは常に @ *で、割り当て操作の右側の信号値が変更されるたびに手続きブロックが実行されることを意味します。 この場合、信号aとbが変わるたびに手続きブロックがトリガーされます。 この行と同等に、次の感度のリストがあります。



always @(a or b) // , a b









プロシージャブロックを使用して組み合わせ回路を常に記述する場合、ブロック内で変更されるすべての信号の値は、感度リスト内の信号によって完全に決定される必要があることに注意する必要があります。 そうでなければ、シンセサイザーはメモリ要素を回路に挿入する必要があります-ラッチ。



たとえば、次のプロシージャブロックを考えます。



wire a,b;

reg res;



always @*

begin

if(a & b) res = 1;

else if (!a & b) res = 0;

end









手続き単位は、b = 0の場合に何が起こるかを記述しません。b= 0の場合、resの値は、aの値に関係なく、変更すべきではありません。 したがって、次のスキームが合成されます。







原則として、回路内のラッチの出現はコードのエラーを意味します。



ノンブロッキング割り当て

プロシージャブロックの例で使用したすべての割り当ては、Verilogでは「ブロッキング」割り当てと呼ばれます。 プログラマーにとって通常の方法で機能します。



ブロックの割り当てに加えて、Verilogには手続き型ブロックで使用される別のタイプの割り当てがあります-非ブロック割り当て。演算子「<=」で示されます。 非ブロック割り当ては、宣言された場所ですぐには実行されませんが、手続きブロックから出るまで延期されます。 例を考えてみましょう:



reg a,b;

always @( posedge clk)

begin

a <= b;

b <= a;

end







この例では、各メジャーで、信号aとbが値を交換します。 合成された回路は次のようになります。







通常、レジスタの動作のロジックを記述するときは、非ブロッキング割り当てが使用されます。 組み合わせパターンを記述するために、ブロック割り当てがより頻繁に使用されます。



おわりに



これで、Verilogの簡単な紹介は終わりです。 それが誰かに役立つことを願っています。



Verilogとデジタル回路の設計についてもう少し詳しく知りたい場合は、初心者向けに次の2冊の本をお勧めします。




All Articles