ハードウェアの動作記述では並列に動作する回路を記述できます。したがってソフトウェアのプログラミング言語と比較すると、時間の概念が特徴的です。前述したシグナルへの代入「<=」は、正確には「同期代入」と呼ばれます。1つのアーキテクチャ内に記述された同期代入文は全て同時に代入が反映されます。例えば、
Z <= X and Y;
という記述の場合、処理系は右辺の変数に値の変化(イベント) があるかどうか調べ、もしあれば、Δ時間 (微小時間) 後の左辺の値を更新します。時刻tのシグナル「X」の値をX(t)と書くと、この式は
Z(t+Δ) = X(t) and Y(t)
という意味になります。
VHDLのプロセス文では、下図の「process()」の中の信号「S1」「D0」「D1」のうち、いずれかの値が変化したときにプロセス文の記述が実行されます。このカッコ内をセンシティビティ・リストと呼びます。最終行まで実行するとまた上に戻り、次にこれらの信号の値が変化するまで動作を停止します。
例えば、「mux21.vhd」の「Y」への代入文をあえてプロセス文で記述すると以下のようになります。
process (S1, D0, D1) begin if S1 = '0' then Y <= D0; else Y <= D1; end if; end process; |
「process」の次に記述されているセンシティビティリスト中の変数が変化した時に、この記述(プロセス)が実行されます。1つのプロセス文で複数のシグナルへの代入を記述できますが、前述のように、代入は全て同時に反映されます。例えば、プロセス中に
Y <= X;Z <= Y;
という記述がある場合、「Z」に代入される「Y」の値は、上の行で「X」の値を代入される前の「Y」の値です。このような代入文のほかに、以下の表にあるような順次処理文(シーケンシャル文)は、プロセス文の中で記述することになります。
|
課題:上記のプロセス文を使って「mux_21.vhd」を書き直し、アナライズ、シミュレーション、論理合成を行って下さい。そしてプロセス文を使わない場合と比べて何がどのように異なるのかを検証して下さい。
答え
基本的には、シグナルを駆動するプロセス (ドライバ) は唯一です。つまり、1つのシグナルに対して、複数のプロセス (あるいはプロセス外の代入文) で代入を行なうことはできません。
なお組合せ回路の出力は、現在の入力の値のみに依存して決まります。組合せ回路をプロセス文で記述する場合は、プロセス中で参照しているすべての変数をセンシティビティリストに入れ、また、すべての条件を網羅して代入文を記述する必要があります。入力が変化しても代入が行なわれない場合があると、出力のシグナルの値は変化しないことになるため、過去の値を保持する必要があり、順序回路となってしまいます。この点は誤りやすく、設計者の予期しない記憶素子が合成されてしまうことがあるので、十分に注意する必要があります。組合せ回路を記述していることを確実にするためには、プロセスを使わず代入文や条件付き代入文を使うとよいのですが、同じ条件の下で変化するシグナルがいくつかある場合には、プロセスのほうが全体の記述が簡潔になることが多いのです。
ある程度大規模な回路の設計では、まとまった機能単位で 1 つのエンティティを設計し、上位のエンティティでそれを部品として用いるといった「階層設計」を行なうのが普通です。VHDLでは、コンポーネントの呼び出しを用いて階層的な設計を記述します。
以下に2 ビットカウンタを2つ用いた 4 ビットカウンタの記述例を示します。前節の「counter2」を「C1, C2」として 2 つ用い、「C1」の出力が「"11"」になった時に「C2」をカウントアップします。上位のアーキテクチャでは、中で用いるエンティティを「component」として宣言し、どの設計を用いるかを「for」文で指定します。この部品の実体「C1, C2」の結線関係は「port map」により指定します。
-- counter4.vhd library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity counter4 is port (reset, clk, input: in std_logic; y: out std_logic_vector(3 downto 0)); end counter4; architecture structure1 of counter4 is component counter2 port (reset, clk, input: in std_logic; y0, y1: out std_logic); end component; for C1, C2: counter2 use entity work.counter2(behavior1); signal C2in: std_logic; signal y0, y1: std_logic; begin C1: counter2 port map (reset => reset, clk => clk, input => input, y0 => y0, y1 => y1); y(0) <= y0; y(1) <= y1; C2in <= y0 and y1; C2: counter2 port map (reset => reset, clk => clk, input => C2in, y0 => y(2), y1 => y(3)); end structure1; |
構造記述を用いた 4 ビットカウンタ「counter4.vhd」
課題:この「counter4.vhd」について、アナライズ、シミュレーション、論理合成を行って下さい。またFPGAへダウンロードできるように書き直し、ボード上で動作を検証して下さい。
答え