ポリシー
- 記述スタイルは、設計データの一貫性を図り相互参照を容易化するものと考えています。ここではサンプルケースとして、緩やかなルール[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
FFの記述
- インスタンスを定義せず、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等)
回路デザイン > ホーム > 言語・記述スタイル 次のページ(使用プロトコル) このページのTOP ▲