Edited at

VHDLコーディングスタイル

More than 1 year has passed since last update.

VHDLの開発で、生産性を下げる原因が「タイミング」の複雑さ。

特に「レイテンシー」と「クロックドメイン」の整理が大切かなと。

項目
なぜか

レイテンシー
入力またはENから何クロック遅れて出力が得られるか。同期型の回路ではとても大事。

クロックドメイン
クロックが異なればラッチミスが発生する。このため特別な仕掛けが必要。
1ビットであれば、シンクロナイザーを挟む。
バスであれば長くホールドしてトリガーでラッチするなど。

自分がよく陥るトラブルはコレ


  • 信号をどのユニットで作成したか忘れる。名前を見ればどんな信号か分かるものです。でも、デバック時に信号を見て、ハテこの信号の素性はなんだっけ?どこで作った信号だったかなと確認しようとした時に、探すのが大変。

  • 信号のクロックドメインがわからなくなったり間違える。人間だもの。

  • パルスかレベルか、パルスの場合のパルス幅はいくつだったっけ?

  • パイプライン処理をしている時、このラッチの信号は、何クロック遅れだったっけ?

せめてクロックドメインやラッチのタイミングだけでもすぐ分かるようにしたいと思ったので、ハンガリアン記法風で書いています。


こんなスタイルはいかが


[クロック] 'CLK'+周波数

例) CLK10M5


  • クロックであることを明確化する。

  • 周波数や、クロックソース識別文字をつける。10.5MHzなら10M5

定番。クロックドメインを明確に意識できます。組み合わせ回路と順序回路の判別もちょっと楽。


[ラッチ] ラッチのCLKドメイン明記

例) valid_n, valid_nn, valid_n2


  • サフィックスのnはクロックドメイン識別文字。

  • 多段ラッチでディレーを作る場合は、サフィックス繰り返す、または段数の数字を付加する。

シンクロナイザーなど、異種クロックを扱う回路で、クロックの異なる信号が識別しやすくなる。

段数を明記することで信号名だけで遅延量が明確になる。

使い勝手はそこそこ。どうでしょう。


[ラベル] 体系的なユニット番号+機能

例) U9000_STATE_MACHINE, U9010_STATE_UPDATE

例) U0xxxはクロックやリセット

  U1xxxは入力ポート処理

  U4xxxはアップストリームの処理

  U6xxxはダウンストリームの処理

  U8xxxは出力ポート処理

  U9xxxは管理制御、状態管理

  

* 番号をつけるのがポイント。

* 機能ごとに大まかに番号をわりふり、近い番号をつけていく。

* 処理の流れに沿って昇順に割り当てる

* 番号は隙間をあけておく

ISEではラベルが昇順にソートされるので探しやすい。

番号に隙間をあけておくのは、あとからモジュールを追加するときのため。昔々、BASICの行番号を10単位で割り振っていたのと同じ。Xcodeのようにリファクタリング機能があれば、こんな苦労はないのですが。


[signal] プリフィックスに生成元や利用先をつける

例)t##XX, vほげほげ, i##XX, o##_XX


  • プリフィックスの##はユニット番号。

  • 特定の機能ブロックだけで使う信号にはt##をつける。valiableにはプリフィックスに'v'をつける。

  • 機能ブロックの出力には生成元を示すo###をつける

  • 特定ユニットの制御信号にはi##をつける

デバッグ時に、信号の影響や生成元を特定するのに便利。

使ってみた感じ、煩雑になるので、微妙なところ。


[ポート名] 入力と出力のプレフィックスをつける

例) inXXXX ,otYYYY

*入力のプリフィックスはin

*出力のプリフィックスはot

*クロックとリセットはCLK,RST


[signal,valiable,port,type] ハンガリアンぽい記法

例)

type st_t is(S0,S1); 状態の型

signal st_reg : st_t :=S0; 状態レジスタ

I_s16p4,Q_s16p4 バス幅16bit,小数部4bitのsignedのI,Q信号

(プレフィックス)

* a 配列

* st 状態

(サフィックス)

* t 型

* reg レジスタ

* nxt 次のクロックで設定するレジスタ値

* slv standard_logic_vector

* sバス幅p小数部 符号付固定小数

* sバス幅p小数部 符号なし固定小数


記述例


ModuleUser.vhdl

entity ModuleUser is

Port (
RST: in std_logic;
CLK: in std_logic;
otQ: out std_logic );
end ModuleUser;

architecture RTL of ModuleUser is
-- コンポーネントABCをユニットU20として実装する場合
-- U20の出力信号XXはt20_XXとつける。
signal t20_XX : ;
component ABC
port( otXX : out );
end component;

-- プロセスU30の内部信号にはt30_のプリフィックス
signal t30_count:natural;

begin
-- ユニットU20のインスタンスと出力の結線
U20_ABC:ABC
port map(otXX => o20_XX);

-- ユニットU30
U30:process(CLK) begin
if rising_edge(CLK) then
t30_count <= t30_count +1;
end if;
end process;

-- o20_XXはU20の出力信号
-- t30_countはU30の内部信号

-- ディレイ クロックドメインはn
U40:process(CLKn) begin
if rising_edge(CLKn) then
t40_XX_nn <= t40_XX_n;
t40_XX_n <= t20_XX;
end if;
end process;

end RTL;


用語など間違っているところがあるかも。

エンティティのコードを入力すると、コンポーネント宣言文とこの記法に従った出力信号などを作成するWEBページも作りました。

もっぱら自分用ですが使いたい人がいるかな...。

http://cgi1.plala.or.jp/~hbf/ppVhdl/ppVhdl.cgi