Images of 終刊号
記述スタイルは、設計データの一貫性を図り相互参照を容易化するものと考えています。ここではサンプルケースとして、緩やかなルール[1][2]を予め決めておきます。これらのルールを参照していただければ、少しは難解なサンプルコードも理解できるかと思います。 ルールは、経験的な部分と好みにより独自に決定しています。異なったルールへの移行はさほど難しくないと考えています。 考慮されていない部分やグレーな部分があるかもしれません。また、万人向け[3]ではないかもしれません。その程度のルールと言うことになります。 verilog HDL(IEEE1364-1995)を使用します。 回路設計において雛形のパターンは限られるため、高度な言語を採用する必要はない メジャーな言語の一つであり、市販ツールや内製ツールに対する順応性が高い 古典的な言語として将来的にも継続でき、また高度な言語への移行が比較的容易 コア周辺には、アサーションやC言語協調設計可能な上位言語の使用を検討する キャメルケースのルールを基本に命名します。 先頭ワードが小文字のLower Camel Caseを基本とする Lower Camel Case → lowerCamelCase 省略語は統一する Clear Inside Layer → clrInLyr 慣用的な略語(検索可能)は全て大文字のままでよいが、先頭ワードであった場合のみ全て小文字とする Put Identifier → putID Identifier Selector → idSel 負論理などにアンダースコアを使用する(負論理は外部端子仕様で定められない限り、論理の混乱を避けるため極力使用しない) reset → reset_n 上位階層において、モジュールの相互接続が分かるように接頭辞を付けます。 デリミター(アンダースコア)を用いるか用いないかは、相互接続の複雑性(指標はない)から判断 以下のバリエーションを参照に、同一階層内はいずれかに統一 始端モジュールに由来する接頭語を付ける モジュールXの出力信号 → xSig, x_sig 始端と終端モジュールを明示する接頭語を付ける モジュールXからモジュールYへの信号 → x_ySig 複数の終端モジュールがある場合は明示しない、もしくは特定の記号に置き換える モジュールX,WからモジュールY,Zへの信号 → xSig, w_sig モジュールY,ZからモジュールX,Wへの信号 → gSig, g_sig(gに置き換え) パイプラインステージに由来する接頭語を付ける パイプラインステージAの後段 → aSig, a_sig 端子名はモジュール名は関与させず一般的もしくは慣例的な接頭語を付ける パイプライン入力信号 → iSig パイプライン出力信号 → oSig レジスタ入力信号 → regSig clkやresetなど全体で共通するものはそのまま使用 インスタンスを作る場合、ポート接続を使用 // Instantiation modX insX ( .iData (wanData), .iVld (wanVld), .oData (nynData), .oVld (nynVld), .reset (reset), .clk (clk) ); FF出力後の論理段数を最小化、およびレイアウト境界に位置する部分であればFF入力前の論理段数も最小化するような設計を行う パラメータで代用できるものはパラメータを使う(ツールによって影響範囲が異なる場合があるため) 大文字でまとめて記述し、最上位階層のユニークなモジュール名の接頭語を加える // myDMAモジュールでKEYを定義 module myDMA(); ... `define MYDMAKEY 1 ... コアモジュール外部で定義する場合、デフォルトの定義を記載する // myDMAモジュールより上位階層でKEYを定義 module myDMA(); ... `ifdef MYDMAKEY `else `define MYDMAKEY 1 `endif 大文字でモジュールごとに定義する 階層を跨いで伝播させる場合なるべく共通名を使う module modX(argsX); ... paramter DATAWIDTH = 32 ... modY #(DATAWIDTH) insY(argsY); ... endmodule module modY(argsY); ... paramter DATAWIDTH = 16 ... modZ #(DATAWIDTH) insZ(argsZ); ... endmodule インスタンスを定義せず、Non-blocking代入文を用いる(Blocking代入文は禁止) 基本的に処理の単位ごとに手続き文を記載(always procedure) 非同期リセットを状況に応じて使用(Reset回路) 波形Viewerを用いた目視チェックのため定数遅延を与える(クロックエッジから少し遅れて変化) // FF Description (Normal) reg oVld; always @(posedge clk or negedge reset_n) if (!reset_n) // Asynchronous Reset oVld <= #1 1'b0; // Fixed Delay #1 else if (reset) // Synchronous Reset oVld <= #1 1'b0; else if (!iStall) // Enable oVld <= #1 iVld; D型FFを意識した記述が必要になる場合(Stateマシンの記述)、末尾にDを付けた変数名を使用 // FF Description (D Type FF) reg oVld; wire oVldD; always @(posedge clk or negedge reset_n) if (!reset_n) oVld <= #1 1'b0; // Reset Port else oVld <= #1 oVldD; // Data Port assign oVldD = reset ? 1'b0 : iStall ? oVld : iVld; assign文を使った継続的代入文かalways文を使ったBlocking代入文を用いる Blocking代入文では、なるべくデフォルト値を先頭で代入しておく(特にcase文を使った複雑な条件式) function文を使う場合、ローカル変数名がダブらないようにする(inputで全ての値を引き渡し) // Blocking (assign oVldD = reset ? 1'b0 : iStall ? oVld : iVld) reg oVldD; always @(reset or oVld or iVld or iStall) begin oVldD = oVld // Default set prevents from latch gen if (reset) // Synchronous Reset oVldD = 1'b0; else if (!iStall) // Enable oVldD = iVld; // else // Necessary if not default set // oVldD = iVld; end なるべく回路の高速化を意識した記述を行う // Selector wire [31:0] dataA, dataB, dataC; wire selA, selB, selC; wire [31:0] selOut; ... // assign selOut = selA ? dataA : selB ? dataB : dataC; assign selOut = {32{selA}} & dataA | {32{selB}} & dataB | {32{selC}} & dataC; ... ツール依存の記述はなるべく使用しない(synopsysのfull_caseとparallel_case等)