Verilog-HDL 文法(4):組み合わせ,順序回路記述 2015/09/27 |
[CategoryTop] [Prev] [Next] |
[目次]・組合せ回路記述 + assign + function + always ・順序回路記述 + always ・moduleコール + module ●組合せ回路記述 ◆assign ・assignは継続的代入(continuous assignments)を意味します。主に演算子の結合で 記述できる簡単な組合せ回路の定義に用います。 ・平たく言ってしまえば、常に接続され、変化に追従する信号です。故にこの後説明 するalwaysやinitial等の手続き型(procedural)ブロックと並列(独立)に記述されま す。 ・assignが使用できるノードはネット型のみです。つまりwire宣言した信号(ポートは 省略されているがwire型)にはassignを記述できますが、reg型には適用できません。 ┌─────────────────────────────────────┐ assign z = ~(a & b); // NAND assign z = (sel == 1)? a1 : a0; // Selector(MUX) └─────────────────────────────────────┘ ・通常は、上記のように assign が明確に記述されることで「継続的代入」を定義し ますが、wire定義時に以下のような「暗黙の継続的代入」記述が可能です。 ┌─────────────────────────────────────┐ wire mux_out = (sel)? a1 : a0; └─────────────────────────────────────┘ ・ただし、RTLを記述する担当と検証の担当が別々の場合、記述の方法が複数あると混 乱の元になるので、前者(explicitなassign記述)で統一するのがお勧めです。ちょ っとした確認のために使う小技だと思っていた方が良いでしょう。 ・また、シミュレーション記述で再度説明しますが、assign文ではディレイを記述す ることができます。下記の例はメモリ読み出しにディレイを付けたイメージです。 ┌─────────────────────────────────────┐ parameter RDELAY = 500; assign #RDELAY data = (out_en)? sram[addr] : 16'hz; └─────────────────────────────────────┘ ◆function ・functionは、assignでは記述できない複雑な論理(回路規模ではない)を記述すると きに用います。functionは大まかに以下の構成を持ちます。 ┌─────────────────────────────────────┐ function [レンジ] function_name; 入力ネット名; ローカルレジスタ名; ステートメント endfunction └─────────────────────────────────────┘ ・このようにして定義したfunctionをネットにassignし、moduleに組み込みます。 ・ステートメントには以下を使用することができます。(論理合成可能な組合せ回路記 述だけを意識した内容です) ┌─────────────────────────────────────┐ * begin 〜 end | beginからendで囲まれた複数の演算式を順番に実行します。結果的に1個のブ | ロックを形成します。ブロック内では下記のステートメントを使用することが | できます。 | +-- =演算子 | ブロッキング代入です。begin〜endブロックでブロッキング代入演算子が | 使用されている場合、演算は上から順番に行われます。 | +-- if ブロック 又は if ブロック else ブロック | 条件分岐です。下記のように記述します。 | if (sel == 1) | z = a1; | else | z = a0; | +-- case | case文です。下記のように記述します。マッチ条件とステートメントの並 | びです。ステートメントは更にブロック記述が可能です。 | case (in) | 2'b00 : dec = 4'b0001; | 2'b01 : dec = 4'b0010; | 2'b10 : dec = 4'b0100; | 2'b11 : dec = 4'b1000; | default : dec = 4'bxxxx; | endcase | +-- casez | マッチ条件に「z」を含めることができます。 | +-- casex マッチ条件に「x」又は「z」を含めることが可能です。 └─────────────────────────────────────┘ ・functionで記述したデコーダ記述例を示します。 ┌─────────────────────────────────────┐ module decoder_2_4 (in, out, en); input [1:0] in; input en; output [3:0] out; //------------------------------------- function [3:0] dec; input [1:0] in; input en; begin if (en == 1) case (in) 2'b00 : dec = 4'b0001; 2'b01 : dec = 4'b0010; 2'b10 : dec = 4'b0100; 2'b11 : dec = 4'b1000; default : dec = 4'bxxxx; endcase else dec = 4'b0000; end endfunction //------------------------------------- assign out = dec(in, en); endmodule └─────────────────────────────────────┘ ・functionで組合せ回路を記述する場合の注意点です。潜伏するエラーとなるので間 違いを発見しにくくなっています。 + 引数の不一致 * 今回の例で示したdec functionの引数はin, enですが、引数を書き忘れた 場合、コンパイラによってはエラーを検出しないことがあります。 * bit数が異なる場合(特にfunction内の信号bit数が少ない)、エラーは検出 されません。 * 引数の記述順は、function内での入力信号定義順です。引渡しの記述順を 間違えてもエラーは検出されません。(違う値が引き渡されてしまう) + マッチ条件の未記述 * functionの場合、後述のalwaysのようにマッチ条件を全て書かなくても論 理合成結果でラッチが生成されることはありませんがシミュレーションで はラッチがあるように動くので、RTLレベルとゲートレベルでシミュレーシ ョンミスマッチを起こすことがあります。 ◆always ・alwaysは一般的に順序回路記述に使用されますが、組合せ回路を記述することも可 能です。alwaysは以下の構成を持ちます。 ┌─────────────────────────────────────┐ always @ (条件信号リスト) ステートメント └─────────────────────────────────────┘ ・組合せ回路を記述する場合、使用するステートメントはfunctionで紹介したものと 同じです。 ・alwaysで記述したデコーダ記述例を示します。 ┌─────────────────────────────────────┐ module decoder_2_4 (in, out, en); input [1:0] in; input en; output [3:0] out; //------------------------------------- reg [3:0] out; always @ (in or en) begin // 複数信号は論理和 if (en == 1) case (in) 2'b00 : out = 4'b0001; 2'b01 : out = 4'b0010; 2'b10 : out = 4'b0100; 2'b11 : out = 4'b1000; default : out = 4'bxxxx; endcase else out = 4'b0000; end //------------------------------------- endmodule └─────────────────────────────────────┘ ・always文で組合せ回路を記述する場合ですが、alwaysブロック内でセンスする信号 条件の書き漏れがあった場合、論理合成時にラッチが生成されます。この結果シミ ュレーションでミスマッチが発生します。 ・さて、functionとalwaysのどちらで組合せ回路を記述すべきかという問題ですが、 両方とも記述ミスがあるとシミュレーションミスマッチが発生するのは同じという 意味で、以下の条件で選択されると思っています。 ┌─────────────────────────────────────┐ + ローカルで使用する文法チェッカの検出率が高い方 + 順序回路記述と組合せ回路記述を明確に分けたければ、function使用 + VHDLとの混合が考えられるのであれば、always使用 └─────────────────────────────────────┘ ・ちなみに私(Monpe)は自分の周りに合わせてfunction派です。 ●順序回路記述 ◆always ・順序回路の記述にはalwaysを使用します。組合せ回路のalwaysと基本は変りませんが タイミングに関するステートメントが追加されます。これらのステートメントは functionで使用することはできません。 ┌─────────────────────────────────────┐ + always @ (エッジ 信号) ステートメント * 信号の立上りエッジ(posedge)又は立下りエッジ(negedge)に同期した記述 です。 (例)always (posedge CLK or negedge RESET) 〜 + <= 演算子 : ノンブロッキング代入 * 本来begin〜endブロック内は順次実行ですが、ノンブロッキング代入を指 定した場合、並列に実行されます。 (例)reg1 = 0, reg2 = 1の場合 reg1 <= reg2; reg2 <= reg1; 値がスワップされる。reg1の値が評価される前に代入するから。順次 実行のブロッキング代入と異なる点に注意。 + ディレイの付加 * 代入の左辺又は右辺にディレイを付加できる。 * ブロッキング/ノンブロッキングは問わない。 (例)q <= #DELAY d; └─────────────────────────────────────┘ ・alwaysで記述したラッチ、フリップフロップの例を示します。 ┌─────────────────────────────────────┐ `define DELAY_UNIT 1 //ディレイ値のマクロ定義 module dff_res_async (ck, d, q, res); //クロック非同期リセットのFF input ck; input d; input res; output q; reg q; parameter DELAY = `DELAY_UNIT; //ディレイ値パラメータ定義 always @ (posedge ck or posedge res) begin //エッジセンシティブ if (res) q <= #DELAY 1'b0; else q <= #DELAY d; end endmodule module dff_res_sync (ck, d, q, res); //クロック同期リセットのFF input ck; input d; input res; output q; reg q; parameter DELAY = `DELAY_UNIT; always @ (posedge ck) begin if (res) q <= #DELAY 1'b0; else q <= #DELAY d; end endmodule module h_latch (g, d, q); //レベルセンシティブ : ラッチ input g; input d; output q; reg q; parameter DELAY = `DELAY_UNIT; always @ (g or d) if (g) q <= #DELAY d; endmodule └─────────────────────────────────────┘ ・上記の例で `define と parameter を使用しました。`define はコンパイラ指示子 でマクロを定義しています。parameterはネット型やレジスタ型以外の定数データを 扱うためのデータ型です。 ・parameter DELAY をノンブロッキング代入の遅延として使用しています。このDELAY に与える数値をマクロ定義しています。もしディレイ値を正確に設定したければマ クロを変更するだけで済むからです。 ●moduleコール ◆module ・回路の規模が大きくなれば、moduleを分割して設計を行います。つまりVerilog-HDL のmoduleは階層構造を持ちます。 ・これにはいくつかの理由があります。 + 設計の分業化による効率向上(分割統治)、検証も効率Up + 回路の単位規模を論理合成の範囲内に収める ・モジュールが小さい(大き過ぎない)場合、論理合成後はmoduleの階層を解いて、チ ップ化するのに最適な分割を行うことができます。つまり、moduleの構成はあくま で論理的な階層を意識すればOKです。(*1) ・moduleの呼出は以下の書式で行います。 ┌─────────────────────────────────────┐ モジュール名 インスタンス名 (ポートリスト); └─────────────────────────────────────┘ ・ポートリストにはmoduleでのポートリスト定義順に接続信号を並べる方法と、定義 側ポート名を明記する方法があります。 ┌─────────────────────────────────────┐ module sample (ck, data, re, we); // 記述例1 - 定義順に並べる sample sample_i1 (clk, data1, read_en, write_en); // 記述例2 - 接続ポートの明記 sample sample_i2 (.ck(clk), .re(read_en), .data(data1), .we(write_en);) └─────────────────────────────────────┘ ・尚、呼出す同種モジュールが1つだけの場合、インスタンス名とモジュール名は同一 にすることができます。 (*1)いくらでも小さくして良いというわけでもありません。この辺りは別の場(もう少し進 んでから)で話をしたいと思います。 [Revision Table] |Revision |Date |Comments |----------|-----------|----------------------------------------------------- |1.00 |2003-11-18 |初版 |1.01 |2003-11-24 |リンク追加 [end] Copyright(C) 2015 Altmo
|