VHDLについて

− プロセス文とタイミング −


井澤 裕司

(H19.5.23)


1. 同時処理文と順次処理文.

VHDLには,「 同時処理文 」と,「 順次処理文 」があります.

architecture 」本体には,「 同時処理文 」を並列に記述します.
実際の論理回路は,常に「 activeな状態 」にあるため,本来「 同時処理文 」で表現するのが自然です.
同時処理文 」に対して,「 順次処理文 」があります.

順次処理文 」は,ソフトウェアの「 逐次的な構文 」を用いて,「 ハードウェアのモデリング 」を行うものであり,
同時処理文に比べ,「 より抽象的な動作 」を直観的に記述することが可能です.
後で説明する「 プロセス文 」の内部は,この「 順次処理文 」が使用されます.
例えば,「 if文 」や「 case文 」,「 loop文 」などが,その代表的なものです.

同時処理文 」,「 順次処理文 」というのは,あくまでVHDLの「 構文を解析して,処理する手順 」が,
同時並行 」, あるいは「 順次 」を表しているのであり,
  「 信号が同時に変化するか,しないか
を表しているのではないことに,注意する必要があります.

下の 組合せ回路の例を用いて,具体的に説明しましょう.
entity inverter is
port (
A : in std_logic;
B : out std_logic;
C : out std_logic
);
end inverter;

architecture Dataflow of inverter is
begin
B <= A; 同時処理文
C <= B; 同時処理文
end Dataflow;

architecture 」の2つの代入文,
  B <= A;
   と,
  C <= B;
は,ともに「 同時処理文 」として解析されます.
信号Bへの代入 」は,「 信号Aの変化 」から「 1δ時間後 」に行われます.
一方,「 信号Cへの代入 」は,「 信号Bの変化 」から「 1δ時間後 」,すなわち,
信号Aの変化 」から「 2δ時間後 」に行われます.
このように,「 信号への代入 」は,必ずしも同時に行われるとは限りません.
なお,「 遅延時間δ 」の値は,「 0 」であり,実質的な 遅延はありません.

すなわち,上記VHDLでは回路の機能を記述しているだけであり,
具体的な回路の「 遅延時間δ 」の値については, 使用する「 ライブラリ 」 や,
FPGAの種類 」 など,「 論理合成 」の結果により決まります.
テストベンチ 」などで「 0以外の遅延量 」を設定するには,以下のように記述します.
B <= A after 5ns;
C <= B after 10ns;
これは,「 信号A 」が変化して「 5ns後 」に「 信号B 」が変化することを表しています.
同様に,「 信号B 」が変化して「 10ns後 」に「 信号C 」が変化します.
なお,2つの代入文の「 位置(前・後) 」を入れ換えても,「 等価 」であることは明らかです.

2. プロセス文について.

先に述べたように,「 architecture 」本体には,「 同時処理文 」を並列に記述します.
下の例に示すように,プロセス文が含まれる場合も,
  process(CLK) から end process;
までの記述を,1つの「 同時処理文 」とみなすことができます.

signal TMP : std_logic_vector(3 downto 0);
process (CLK)
begin
if (CLK'event and CLK = '1') then
if TMP = "1001" then
  TMP <= "0000" ; 同時処理文
else
TMP <= TMP + 1;
end if ;
end if ;
end process ;
 
COUNT <= TMP;   同時処理文
end Behavior;
したがって,信号「 COUNT 」への代入文の位置はどこでもよく,
下の図のように,「 プロセス文 」とその位置を入れ換えても等価です.
signal TMP : std_logic_vector(3 downto 0);
COUNT <= TMP;   同時処理文
 
process (CLK)
begin
if (CLK'event and CLK = '1') then
if TMP = "1001" then
  TMP <= "0000" ; 同時処理文
else
TMP <= TMP + 1;
end if ;
end if ;
end process;
end Behavior;

次に下の図を用いて, 順次処理文 を記述する プロセス文 タイミング の関係について,
整理してみましょう.

この例は,
 process(CLK) から end process;
までの1つの プロセス文 と,
 COUNT <= TMP;
という1つの代入文で構成されています.
すなわち,2つの「 同時処理文 」が含まれています.

プロセス文 」直後のカッコ内の「 信号 」を「 センシティビティ・リスト 」と呼び,
この値が変化したとき,このプロセスが「 アクティブ 」となり,A〜Dの処理を行います.

Aで,CLKの変化が「 立ち上り 」である場合は,B以降の処理を行います.
一方,「 立ち下り 」である場合は,Dに移行し,プロセスは「 スタンバイ状態 」となります.

Bでは,「 信号TMP 」の状態を調べ,その値が「 "1001" 」のときは,「 δ時間後 」,
信号TMP 」に "0000" 」を代入するよう,スケジューリングを行います.

一方,「 信号TMP 」の値が「 "1001" 」以外のときは, 信号TMP 」の値に,
1を加算した値 」を「 δ時間後 」に代入するよう,スケジューリングします.
スケジューリング 」が終わった後,Dに移行し,プロセスは「 スタンバイ状態 」となります.
ここで「 δの値 」は「 0 」で,「 遅延はない 」のですが,「 プロセスが終了 」した後に,
代入が行われることに注意して下さい.






3. Behavior レベルと Register Transfer レベル.

前節のVHDLの「 architectureの仕様 」は,「 Behavior 」となっています.

トップダウン設計では,まず「 Behaviorレベルの記述 」を行い,システムの全般的な機能を確認します.
Behaviorレベル 」のシミュレーションでは, いわゆる「 イベント・ドリブン 」という手法により,
信号代入のタイミング 」を効率的に計算します.
例えば,信号の「 CLK 」が変化したとき,「 end process; 」までの処理を,「 時間0 」で順次に実行します.

しかし,このような処理は「 ソフトウェアによるシミュレーション 」上で成立するものです.
例えば10進カウンタで,「 信号のTMP 」の値を呼び出し,これに「 1を加算 」するためには,
4bitと1bitの加算に伴う演算時間が必要です.
ゲート遅延を伴う実際の「 ハードウェア 」で実現できるものではありません.
すなわち,いわゆるテストベンチ上で,「 動作仕様 」に基づく論理や基本的なタイミングに関する
シミュレーションを行うのが目的となります.

Behaviorレベル 」の検証を終えると, VHDLのライブラリ 」等を用いて,
Register Transferレベル 」の具体的な回路構成に変換し,それらのタイミングを厳密に検証します.
下の図を用いて,「 Register Transfer レベル 」の回路の動作について説明しましょう.

Behaviorレベル 」では,クロックの立ち上りが「 すべての起点 」となっていました.
信号TMPへの代入 」は,クロックCLKの立ち上りから「 δ時間後 」に行われます.
ということは,「 信号TMPの値 」は,ほぼ1クロック前に,すでに確定していることになります.

RTレベル 」では,「 信号TMPの値 」が確定した時点を「 起点 」とします.
すなわち,「 TMPの値をチェック 」したり,「 TMPの値に1を加算 」する処理を,
ほぼ「 1クロック前 」から開始し, その結果を,「 フリップフロップ 」の「 D-FF 」を用いて,
クロック「 CLK 」の立ち上りで確定します.
D-FF 」の応答は比較的速いので,「 Behaviorレベル 」に近いシミュレーション結果が得られます.

RTレベル 」の回路設計では,「 TMPの値をチェック 」したり,「 TMPの値に1を加算 」する処理は,
すべて「 組合せ回路 」で実現します.

すなわち,下の図に示すように「 1クロック前のTMP 」の値を「 組合せ回路 」に入力し,
その出力を「 D-FF 」を用いて,波形整形します.
このような回路構成により,「 D-FF 」の出力は,「 Behaviorレベル 」の設計と同様,
CLKの立ち上り 」直後に変化する信号となります.



4. プロセス文による組合せ回路.

すべての「 組合せ回路 」は,「 同時処理文 」で表現できますが,
しばしば「 順次処理文 」が使える プロセス文 」を用いて記述されることがあります.
if-else文 」や case文 」等を用いて,回路の機能を判りやすく表現することができるためです.

このとき,以下の2点に注意する必要があります.

@ センシティビティ・リスト 」 に「 すべての入力信号 」 をもれなく記述すること.
A 「 入力のすべての状態 」に対する出力の値を,もれなく記述すること.

この条件が満たされないとき 」,入力の変化に出力が応答しないことがあり,
結果的に「 ラッチ機能 」が埋め込まれてしまうことがあるので,注意が必要です.

プロセス文の「 センシティビティ・リスト 」は,その信号が「 変化 」したとき,
それ以下の「 順次処理文 」が実行されます.
したがって,上記@とAの条件が満たされていれば,「 入力信号の変化 」に対し,
必ず「 出力信号への代入 」が行われるため,実質的に「 遅延回路 」が構成されます.

ところが,「 入力信号が変化 」しても,「 出力信号への代入 」が行われない場合は,
プロセス 」終了後,自動的に「 スタンバイ状態 」となってしまうので,入力信号に追随できません.
このため,その「 出力の値 」を保持するための「 ラッチ回路 」 が生成されてしまうわけです.

プロセス文 」 を用いて「 組合せ回路 」 を記述する場合は,上記「2条件 」 を満たしているか,
必ず確認するようして下さい.

5. 信号と変数について.

ここでは,「 信号 signal 」と,「 変数 variable 」の違いについて説明します.

それらを整理した結果を,「 下の表 」に示します.
VHDL
時間的要素
代入表現
意 味
信号
signal
あり
<=
ハードウェア的
変数
variable
なし(中間値)
:=
ソフトウェア的
信号 」は,「 配線 」や「 D-FF 」で表される「 ハードウェア 」です.
代入処理 」による「 スケジューリング 」が行われ, 一定の遅延(0も含む)の後に, その値は変化します.

一方の「 変数 」は,「 コンパイル等のソフトウェア処理 」で利用される一時的な変数であり,
信号のような「 実体 」を持たないことに注意して下さい.

6. まとめ.

本資料では,「 VHDL 」で使用される「 プロセス文 」とその「 タイミング 」の関係を中心に解説しました.

VHDL 」は,「 ソフトウェア 」的な要素と,「 ハードウェア 」的な要素を兼ね備えた言語であり,
その利用価値は極めて高いのですが,理解し難い面があると言われています.
本資料が,理解の一助となることを願っています.

なお,「 誤り 」や「 誤解されやすい記述 」がありましたら,メール等でご連絡いただければ幸いです.