VHDL設計演習 Ⅰ 入 門 編 広島県立西部工業技術センター
DESCRIPTION
VHDL設計演習 Ⅰ 入 門 編 広島県立西部工業技術センター. 1.作業ディレクトリの作成 まず、エクスプローラを起動し、 ルートディレクトリの下にseminarというディレクトリを、 その下にVHDLというディレクトリを作成して下さい。 ( DOS/V の場合) C:¥seminar¥VHDL (98の場合) A:¥seminar¥VHDL 以下、VHDL演習で作成するファイルはVHDLの下に作ります。 それ以外の、ディレクトリには何も作らないで下さい。. A. B. F. C. D. 2.VHDLの基本ブロック. - PowerPoint PPT PresentationTRANSCRIPT
1
VHDL設計演習
Ⅰ 入 門 編
広島県立西部工業技術センター
2
1.作業ディレクトリの作成
まず、エクスプローラを起動し、 ルートディレクトリの下にseminarというディレクトリを、 その下にVHDLというディレクトリを作成して下さい。
( DOS/V の場合)C:¥seminar¥VHDL
(98の場合)A:¥seminar¥VHDL
以下、VHDL演習で作成するファイルはVHDLの下に作ります。それ以外の、ディレクトリには何も作らないで下さい。
3
2.VHDLの基本ブロック例題1 aoiゲート aoi.vhdlibrary ieee;use ieee.std_logic_1164.all;
entity aoi is port(a,b,c,d:in std_logic; f :out std_logic);end aoi;
architecture aoi_body of aoi isbegin
f<=not((a and b)or(c and d));end aoi_body;
ABCD
F
4
(1) VHDL の基本ブロックはエンティティとアーキテクチャ。 (2)エンティティは
ブロックの名前(これをエンティティ名と呼ぶ。)入出力ピン名とその方向,ビット幅など
ブロックを外部から見た場合の仕様を記述する部分。(3)アーキテクチャはブロックの内部表現, 論理回路としての構造を記述する部分。(4)上の例ではaoiがエンティティ名、aoi _ bodyがアーキテクチャ名。(5) library は使用するライブラリ名を, use はライブラリ中の使用するパッケージ名を宣言する。 両方とも決まり文句と思ってよい。 (6)入出力ピン宣言はエンティティの port 部分で行い,
入 力 = in std_logic 出 力 = out std_logic
双方向 = inout std_logic(7)簡単な機能は,信号代入文 <= で記述する。 (8) VHDL のビット演算子は論理演算子と共用で
and or not xor が使える。(9)わかりやすい様に ( ) を使ってよい。参照:長谷川テキストp17~23
5
クイックロジック社QuickWorks
論理合成Synplify
VerilogシミュレータSILOSⅢ
HDLエディタターボライタ
配置配線ツールSpDE兼 統合化環境
回路図入力SYNARIO
Verilog学習
VHDL学習
6
3.SpDEの起動 スタート - プログラム - QuickLogic ー SpDEでSpDEを起動します。
7
4.HDLエディタの起動
SpDEのツールバーから、HDLエディタのアイコン を押して、HDLエディタを起動し、クリエイトアイコン を押す。
8
5.VHDLコードの入力、保存
例題1のVHDLコードを入力し、FileーSaveAsメニューから¥seminar¥VHDLの下に、ファイル名aoi.vhdで保存する。
拡張子が定まると、 entity 、 architecture などのVHDLキーワードが紺色でハイライトされます。紺色は見にくいのでHDLエディタの Window-ColorsーKeywordで、青色に変更して下さい。
File-ExitでHDLエディタを終了し、SpDEに戻ります。
6.論理合成Synplifyの起動 SpdeのFile-Import- VHDL メニューから¥seminar¥VHDL¥aoi.vhdを指定し、論理合成ツールを起動します。
9
7.ターゲットデバイスの指定と論理合成 RUNボタンのすぐ上のChangeボタンを押して、Partをp8x12b、Packageをpl44に変更し、OKを押します。次に、RUNボタンを押して、論理合成をかけます。
10
8.エラーの修正 ソースファイルにエラーがあると、下の画面で停止します。ViewLogボタンでエラー内容を確認した後、Editボタンを押して、HDLエディタを再度起動し、エラー箇所を修正します。
11
9.論理合成プロジェクトの保存 エラーがなければDoneが表示されて、下の画面で停止します。「はい」を選んで論理合成プロジェクトを保存し、SpDEに戻ります。
12
10.配置配線の実行 SpDEのツールバーからRunToolsアイコン を押して、配置配線を実行します。途中、RUNと「いいえ」を選択します。
13
11.配置配線結果の確認 SpDEツールバーからFullFitアイコン を選択し、チップ全体を表示させます。
14
次に、View-NormalFitメニューを選択し、Zカーソルを回路のある部分でクリックして、回路部分を拡大表示します。 さらに拡大したければZoomInアイコン を使います。
15
ab
cd
f
回路部分のみを拡大すると、下図のようになります。台形印のセレクタはr=s・p+s・qを表しますので、全体として
a・b=1またはc・d=1の時 f=0それ以外の時 f=1
となり、最初の VHDL コードを満す回路が生成されていることが分かります。
r
s
p
q
入力s 出力r 0 p 1 q
※論理合成結果を確認したら、File-Saveメニューで結果を保存します。
16
12.ここで、この後のシミュレーションのために、シミュレータ・タイプを変更しておきます。 SpDEツールバーからToolOptionsボタン を押して、BackAnnotationタブのSimulatorを
Vital3.0 Compliantに変更してから、SaveSettingしてから、OKを押します、
17
library ieee;use ieee.std_logic_1164.all;
entity aoi is port(a,b,c,d:in std_logic; f :out std_logic);end aoi;
architecture aoi_body of aoi issignal ab,cd,o:std_logic;
begin-- f<=not((a and b)or(c and d));
ab<=a and b;cd<=c and d;o <=ab or cd;f <= not o;
end aoi_body;
13.基本ブロック(続き) HDLエディタを起動し、aoi.vhdを次のように修正します。
ABCD
F
AB
CD
O
18
(1)やや複雑な機能は、 signal 宣言したローカル信号を使う ことができる。上の例では ab,cd,o がローカル信号。 ローカル信号はアーキテクチャ内部でのみ有効。
(2) VHDL には暗黙宣言はない。
(3) -- は1行のみのコメント行。 VHDLには、Verilogの/* */の様に 複数行を一度にコメントアウトする方法はない。
修正が終わったらソースコードを保存し、論理合成をかけて配置配線を実行して下さい。結果は同じになります。
19
問題1 インバータLS04.vhdを設計し、結果を確認しなさい。 問題2 NANDゲートLS00.vhdを設計し、結果を確認しなさい。
問題3 NORゲートLS02.vhdを設計し、結果を確認しなさい。
20
14.階層設計例題2 マルチプレクサ mux2.vhdlibrary ieee;use ieee.std_logic_1164.all;-- inverter ---entity inv is
port(a:in std_logic; f:out std_logic);
end inv;architecture inv_body of inv isbegin
f<=not a;end inv_body;---------------------------------------library ieee;use ieee.std_logic_1164.all;-- multiplexer --entity mux2 is
port(sel,a,b:in std_logic; f :out std_logic);
end mux2;
architecture mux2_body of mux2 is component inv
port(a:in std_logic; f:out std_logic);
end component; component aoi port(a,b,c,d:in std_logic; f :out std_logic); end component; signal selb,o:std_logic;begin g1:inv port map(sel,selb); g2:aoi port map(sel,a,selb,b,o); g3:inv port map(o,f);end mux2_body;
g1g2 g3
SELBO
SELA
B
AOI F
21
(1)もっと複雑な回路記述には、階層設計を使う。
(2)階層設計は複数のエンティティ,アーキテクチャ宣言と コンポーネント宣言およびコンポーネントインスタンスを使う。
(3)複数のエンティティ,アーキテクチャ宣言は inv の様に同一ファイル内に書いても良いし, aoi の様に別ファイルに書いても良い。 ただし、 library と use はエンティティ毎に必要。
(4)コンポーネントインスタンスは,サブルーチンコールの様なもので, g1 , g2 , g3 の様に
インスタンス名 : コンポーネント名 port map(ポートリスト ); の形式で行う。 verilog とは順序が逆なのに注意。
参照:長谷川テキストp24~26
22
(5)コンポーネントインスタンスのポートリストは、 呼び出す側と呼び出される側のポートを接続するもので, 上の例の様に並びによる接続が一般的。
次の例の様に名前による接続も使える。 g3:inv port map(a=>o,f=>f);
出力信号を接続しない場合は、予約語 open を使う。
(6)コンポーネント・インスタンスをするためには, アーキテクチャ内で予めコンポーネント宣言して おかなければならない。
component コンポーネント名port(ポートリスト );
end component; の形式で行う。エンティティ宣言から is を取ったのと同じ形式。 C言語のプロトタイプ宣言に似た概念。 コンポーネント宣言時の信号名は、エンティティ宣言時と 同じであること。
23
(7)メインブロックmux2のサブブロックaoiは、別ファイルに入って いるので、下図のようにSynplifyで2つのファイルを指定して 論理合成します。ファイルを追加するにはAddボタンを使います。 この時、メインのmux2が一番下に来るように指定します。
24
例題2を入力し、論理合成、配置配線を実行します。結果は、論理圧縮の効果で例題1より簡単になり、下図のようになります。
sel=1なら f=asel=0なら f=b
となっています。
a
b
sel
f
25
15.条件付き信号代入文例題3 セレクタ mux21.vhd
library ieee;use ieee.std_logic_1164.all;-- multiplexer --entity mux21 is
port(sel,a,b:in std_logic; f :out std_logic);
end mux21;
architecture v1 of mux21 isbegin
f <= a when (sel='1') else b;end v1;
selab
f
mux21
※後のシミュレーションの為にファイル名、エンティティ名とも必ず、mux21にして下さい。 ファイル名とエンティティ名が一致しないと、遅延シミュレーション時にエラーが出ます。
26
(1)前の例 (mux2) では,階層設計を説明するため,複雑な 書き方をしたが,セレクタ自体はもっと簡単に記述できる。
(2)信号代入文 <= には,C言語の条件演算子に似た 条件付信号代入文があり,
左辺 <=(右辺1 ) when (条件式 ) else (右辺2 ); が使える。
(3)上の例では, sel=1 なら f=a , sel=0 なら f=b になる。
(4)条件式に使う関係演算子は = 等しい > 大 >= 以上/= 等しくない < 小 <= 以下
が使え,それらの論理演算 AND 論理積 OR 論理和 NOT 論理否定
も使える。
(5)1ビット幅の定数は '1' '0' と書く。
27
16.process文とif文例題3 セレクタ mux21.vhd
library ieee;use ieee.std_logic_1164.all;-- multiplexer --entity mux21 is
port(sel,a,b:in std_logic; f :out std_logic);
end mux21;
architecture v2 of mux21 isbegin
process(sel,a,b) beginif(sel='1') then f<=a;
else f<=b;end if;
end process;end v2;
selab
f
mux21
28
(1)条件演算子よりもわかりやすい if 文もあるが, アーキテクチャ内にダイレクトに書くことはできない。 上の例の様に process ブロックの中で記述する。 ( verilog の always ブロックに相当)
(2) process 文は process( 信号名 ) begin :end process;
の形で記述し, ( ) 内の信号名が変化したときのみ評価される。 つまり ( ) 内には process ブロックとしての入力信号を記述する。 これをセンシティビティ・リストという。 複数の入力信号が有る場合は,カンマで区切って記述する。
(3) process ブロックで組合せ回路を生成する場合,入力信号を全てセンシティビティ・リストに記述しなければならない。 (順序回路の場合はそうとは限らない。)
29
(4) process ブロック内では, if 文, case 文が使え if(条件式) then 式1 ; else 式2 ;end if;
と書く。( then と end if がある点が, verilog と違う)。 多重 if は,
if(条件式1) then 式1 ;elsif(条件式2) then 式2 ; else 式3 ;
end if; と書く。 elseif でない点に、特に注意。
(5) if 文で全ての条件が列挙されていれば組合せ回路, そうでなければ順序回路が生成されるのは verilog と同じ。
例題3を入力し、論理合成、配置配線を実行します。結果は例題2と同じになります。
30
VHDL設計演習
Ⅱ シミュレーション編
広島県立西部工業技術センター
31
1.テスト・ベンチの準備 例題3の設計mux21.vhdを、VHDLシミュレータを用いて検証します。 設計検証用テストパターンを発生させるVHDLコードのことをテスト・ベンチと呼びます。拡張子は通常 .tb を使います。 HDLエディタでmux21.vhdを開いた状態で、
HDLー GenerateTestBenchを実行すると、テストベンチの雛形mux21.tbが生成されます。※遅いマシンでは数分かかることもあります。 library ieee; use ieee.std_logic_1164.all;①ENTITY TestBench IS END TestBench;②ARCHITECTURE HTWTestBench OF TestBench IS
③COMPONENT mux21 PORT (sel,a,b:in std_logic; f :out std_logic);
END COMPONENT;④SIGNAL selSignal,aSignal,bSignal: std_logic;④SIGNAL fSignal : std_logic;
BEGIN ⑤U1 : mux21 PORT MAP (sel => selSignal, a => aSignal, b => bSignal, f => fSignal); ⑥②END HTWTestBench;
32
①テストベンチのエンティティには、ポートリストが有りません。 エンティティ名は何でもかまいませんが、ここでは TestBench です。
②アーキテクチャ名は何でもかまいませんが、 ここでは HTWTestBench です。
③シミュレーション対象である mux21 をコンポーネント宣言します。
④入力信号、出力信号ともに、シグナル宣言します。信号名は 元の信号名に Signal をつけたものが自動生成されています。
⑤シミュレーション対象mux21をコンポーネント・インスタンスとして、 呼び出します。信号の接続には、名前による接続が行われていま すが、並びによる接続でも構いません。
⑥この位置に、実際のテストパターン用コードを追加します。
33
それでは、⑥の位置に下記を追加して、テストベンチを完成させてから、mux21.tbとして保存して下さい。
process beginselSignal <='0'; aSignal <='0'; bSignal <='0'; wait for 100ns;selSignal <='0'; aSignal <='0'; bSignal <='1'; wait for 100ns;selSignal <='0'; aSignal <='1'; bSignal <='0'; wait for 100ns;selSignal <='0'; aSignal <='1'; bSignal <='1'; wait for 100ns;
selSignal <='1'; aSignal <='0'; bSignal <='0'; wait for 100ns;selSignal <='1'; aSignal <='0'; bSignal <='1'; wait for 100ns;selSignal <='1'; aSignal <='1'; bSignal <='0'; wait for 100ns;selSignal <='1'; aSignal <='1'; bSignal <='1'; wait for 100ns;wait;
end process;
この例で分かるように、テストベンチでの信号値の代入にはprocess文とwait文を使用します。 意味としては、sel,a,bの初期値として全て0を代入した後、100ns毎に異なる値を代入しています。最後のwaitが無いと、800ns毎に同じ信号入力が繰り返されてしまいます。
34
2.機能シミュレーション(Pre-Layout)(1)QuickWorksにはVHDLシミュレータは付属していないので、Accolade社のPeakVHDLを使います。 スタート ー プログラム ー Accolade PeakVHDL
ー PeakVHDL Version4 でPeakVHDLを立ち上げます。
35
(2)PeakVHDLは拡張子が*.vh*のファイルしか入力できない ので、エクスプローラでテストベンチmux21.tbのファイル名を mux21.tb.vhdに変更して下さい。 (重要!!)(3)PeakVHDLのNewProjectアイコン を押して、新しいプロ ジェクトをオープンし、File-SaveProjectAsでこのプロジェクト に名前を付けます。ここでは¥seminar¥VHDL¥mux21.acc として保存します。
36
(4)AddModuleアイコン を押して、mux21.vhdとmux21.tb.vhdを選択します。
37
(5)Rebuildアイコン を押して、階層構造の再構築をし、モジュールの前に+マークが付くことを確認します。
38
(6)オプションボタン を押して、Optionsウインドウを表示させます。 ①Compileタブの compile only if out of date をチェック無 ②Linkタブ の link only if out of date をチェック無 ③Simulateタブの Run to time を1000
Time unit を ns ④Systemタブの Save options as default をチェック有に設定してから、OKを押して下さい。
③以外は1回だけ行えば、結構です。③はこれから行うシミュレーション時間を1000nsに設定するものですので、別の設計をシミュレーションするなど、シミュレーションすべき時間が変わった場合は、適宜、変更します。
※シミュレーション時間は波形表示ウインドウ(10)で マウス右ボタンのoptionsからも変更できます。
39
①
②
③
④
40
(7)mux21.tb.vhdをクリックして、ハイライトした状態で
シミュレーションボタン を押します。エラーがあるとトランスクリプト・ウインドウにエラーメッセージが表示されます。エラーがなければ、(9)に進みます。
41
(8)mux21.vhdは論理合成のチェックを通っているので、エラーがあるとすれば、mux21.tb.vhdの方です。
エラーメッセージを確認後、mux21.tb.vhdをダブルクリックすると、エディタが立ち上がるので、エラー箇所を修正します。
修正が終わったら、File-SaveModuleで保存し、mux21.tb.vhdウインドウのアイコン化ボタン でアイコン化します。
シミュレーションボタン を押して、エラーがなければ、(9)に進みます。
エラーが有れば、エラーメッセージ確認後、アイコン化していたmux21.tb.vhdを通常の大きさに戻し、修正を繰り返します。
42
(9)エラーがなければ、下の画面で停止するので、AddPrimariesボタンとCloseボタンを、この順番に押します。
43
(10)下の画面で停止するので、GOボタン を押します。 波形の一部が表示されるので、PeakSimウインドウの ツールバーからView-ZoomAllを選び、波形全体を 表示させます。
44
(11)sel=0の時 f=b、 sel=1の時 f=a を確認します。
ZoomINボタン を押して拡大しても、入力信号 a,b、selと出力信号fには時間差がありません。これは、現在表示している結果が遅延時間情報の入っていない機能シミュレーション(Pre Layout)である為です。 結果を確認したら、PeakSimウインドウを閉じた後、SaveProjectアイコン を押して、プロジェクトを保存します。
45
3.遅延シミュレーション(Post-Layout)
PeakVHDLで遅延シミュレーションを行うには、デバイスメーカ各社が供給するVITALライブラリを、以下の(1)~(4)の手順でPeakVHDL用にコンパイルする必要があります。 VITALは Vhdl Initiative Toward Asic Libaray の頭文字で、VHDLで遅延シミュレーションをするための手法の総称です。(1)~(4)は1度だけ実行すれば、以後は必要ありません。
(1)まず、エクスプローラを起動して、 ¥ACC-EDA¥LIB4の下に QLOGIC というディレクトリを作成します。 次に、クイックロジック社の供給するVITALライブラリ ¥PASIC¥SPDE¥DATA¥QLVTL95.VHDを、今作成したディレクトリ ¥ACC-EDA¥LIB4¥QLOGICにコピーします。
46
(2)PeakVHDLのツールバーから、NewProject を押して、新しいプロジェクトをオープンし、File-SaveAsで ¥ACC-EDA¥LIB4¥QLOGIC¥QLOGIC.accとして名前を付けて、保存します。
47
(3)AddModuleアイコン でQLVTL95.VHDを追加し、
Rebuildアイコン でモジュールの前に+マークが付くことを、確認します。
48
(3)QLVTL95.VHDをクリックしてハイライトした状態で、Optionアイコン を押して、CompileタブのCompile into Libraryに QLPRIMS を設定します。
49
(4)QLVTL95.VHDをクリックしてハイライトした状態で、コンパイル を押します。 エラーが無いことを確認後、SaveProjectアイコン を押して、このプロジェクトを保存します。これでライブラリQLPRIMSができました。
50
(5)ここからmux21.vhdの遅延シミュレーションを始めます。NewProjectアイコン を押して、新しいプロジェクトをオープンし、File-SaveAsで ¥seminar¥vhdl¥mux21vtl.accと名前を付けて、保存します。
51
(6)AddModuleアイコン を押して、mux21.tb.vhd とmux21.vhq (vhdでないことに注意)を追加し、Rebuildアイコン でモジュールの前に+マークが付くことを確認します。mux21.vhqが見つからない場合は、入門編の12を確認します。
52
(7)Optionsボタン を押して、SystemタブのSystem Library Pathを
c:\acc-eda\lib4;c:\acc-eda\lib4\qlogic;に設定します。(2番目のc:の前にスペースを入れないこと。)
53
(8)LinkタブのSDF File Name を mux21.sdfSDF Instance Path を U1SDF Timing を Max
に設定します。
54
(9)あとは機能シミュレーションの時と同様に、mux21.tb.vhdをクリックしてハイライトした状態で、シミュレーションボタン を押して、シミュレーションを開始します。 結果は下の様に、入力信号a,bと出力信号fとの間に時間差9ns程度が観測されます。 これは現在表示している結果が、遅延時間情報(mux21.sdf)を考慮した遅延シミュレーション(Post Layout)であるためです。 また、VHDLコードも配置配線ツールの出力したmux21.vhqを使用しています。SDFはスタンダード・ディレイ・フォーマットと呼び、遅延時間情報の標準フォーマットです。 興味があれば*.sdf、*.vhqをエディタで開いて見て下さい。
55
(10)結果を確認したら、PeakSimウインドウを閉じた後、SaveProjectアイコン を押して、プロジェクトを保存します。
機能シミュレーションのプロジェクトはmux21.acc遅延シミュレーションのプロジェクトはmux21vtl.accとして保存されています。 遅延シミュレーションを実行した後、機能シミュレーションを実行しようとすると、リンクエラーが出ることがありますが、この時はCleanProjectアイコン を押せば、リンクエラーを回避できます。 これ以外にも、意味不明のエラーが出る場合はCleanProjectアイコン を試して見て下さい。
※*.vhq内のエンティティ名には、自動的に主ファイル名が採用 されるので、*.vでエンティティ名と主ファイル名が一致していな いと、コンポーネントが見つからない旨のエラーが出る。※シミュレータタイプがVITAL3.0ではなく、VITALになっていると VITALライブラリが無い旨のエラーが出る。※System Library Pathの途中に、スペースが入っていると、 QLPRIMSライブラリが無い旨のエラーが出る。
56
問題4 インバータLS04.vhdのテストパターンを設計し、 機能シミュレーションと遅延シミュレーションを
実行しなさい。
問題5 NANDゲートLS00.vhdのテストパターンを設計し、 機能シミュレーションと遅延シミュレーションを
実行しなさい。
問題6 NORゲートLS02.vhdのテストパターンを設計し、 機能シミュレーションと遅延シミュレーションを
実行しなさい。
57
4.ピン配置の指定 ピン配置は配置配線ツールが遅延時間や配線効率を考慮して最適に近いものに自動配置するので、これを使うのが無難です。 しかし、設計の最終段階に近く、プリント基板の変更ができない場合などは、次の方法でピン配置を直接指定することも可能です。 SpDEのTools-Optionsメニューから、BackAnnotationタブを選択し、FixPlacementのIOcellsをチェックonにします。
58
OKを選択後、RunToolsアイコン を押して、配置配線を実行すると、ピン配置情報mux21.scpが生成されます。 現在、ピン16,17,18,19が割り当てられていることを確認します。(マシンによっては異なることも有ります。)エディタで ql_placement 以下のピン番号を変更し、保存します。#mux21.scp#Synplicity Synthesis pin location command file#Automatically generated by SpDE version SpDE 7.0#Date: 8/10/98 at 10:02#
#---Fixed I/O cells---portprop f ql_placement="IO2";portprop a ql_placement="IO3";portprop sel ql_placement="IO4";portprop b ql_placement="IO5";
59
論理合成Synplifyを立ち上げて、Addボタンを押します。ファイルの種類をPropertyFiles(*.sc*)にして、mux21.scpを選択し、「開く」を押します。
60
SourceFilesにmux21.scpが追加されたことを確認後、RUNを押して論理合成をかけます。 途中「はい」とOKを選択し、RunToolアイコン を押すと、mux21.scpで指定したピン配置での配置配線が実行されます。
61
VHDL設計演習
Ⅲ 基 礎 編
広島県立西部工業技術センター
62
1.ビット幅のある信号の表現
例題1 コンパレータ comp.vhdlibrary ieee;use ieee.std_logic_1164.all;
entity comp isgeneric(n:integer :=4);port(a,b:in std_logic_vector(n-1 downto 0); eq,ge,le:out std_logic);
end comp;
architecture v1 of comp isbegin
eq <= '1' when (a= b) else '0';ge <= '1' when (a>=b) else '0';le <= '1' when (a<=b) else '0';
end v1;
a
b
geeqle
4
4
comp
63
------------------------------------architecture v2 of comp isbegin
process(a,b) beginif(a= b) then eq<='1'; else eq<='0'; end if;if(a>=b) then ge<='1'; else ge<='0'; end if;if(a<=b) then le<='1'; else le<='0'; end if;
end process;end v2;
(1)1つのエンティティは複数のアーキテクチャを持つことができる。 上の例ではcompがエンティティで、v1とv2がアーキテクチャ。 明示的にアーキテクチャを指定する場合はコンフィグレーション 文を使うが,シンプリファイライトはコンフィグレーションをサポ ートしていない。 上の例では v2 の方がコンパイルされる。
64
(2)今までは1ビット幅の信号だけ扱ってきたが,ビット幅の ある信号も扱える。 in , out 宣言で
std_logic_vector(15 downto 0) あるいは,
std_logic_vector(0 to 15) を使う。 MSB は左, LSB は右。 MSB>LSB なら downto を, MSB<LSB なら to を使う。
(3)ビット幅を変更しやすくするためには generic(n:integer :=4);
を使う。
(4)上の例の様にコンパレータ等は、 if 文よりも条件付信号 代入文の方がコンパクトに記述できる。
65
例題1のテストベンチ comp.tb.vhdlibrary ieee;use ieee.std_logic_1164.all;use ieee.std_logic_arith.all; …①
ENTITY TestBench ISEND TestBench;
ARCHITECTURE HTWTestBench OF TestBench IS
COMPONENT comp GENERIC (n:integer :=4); PORT (a,b:in std_logic_vector(n-1 downto 0);
eq,ge,le:out std_logic);END COMPONENT;
constant n:integer:=4; …② SIGNAL aSignal,bSignal: std_logic_vector(n-1 downto 0);
SIGNAL eqSignal,geSignal,leSignal: std_logic;
66
BEGIN U1 : comp
GENERIC MAP (n => 4)PORT MAP (a => aSignal, b => bSignal, eq => eqSignal, ge => geSignal, le => leSignal);
process begin …③L1:for i in 0 to 15 loop …④
aSignal <=conv_std_logic_vector(i,4); …⑤ L2:for j in 0 to 15 loop …⑥
bSignal <=conv_std_logic_vector(j,4); …⑦wait for 100ns;
end loop L2;end loop L1;wait;
end process;END HTWTestBench;
67
①あとで、関数 conv_std_logic_vector ()を使うために必要です。
②次の行のSignal宣言に出てくる n のために必要です。
③このprocess文が、実際のテストパターンを発生させます。
④回数指定の繰り返しは for…loop で記述します。ラベル名:for ループ変数 in 初期値 to 終了値 loop
:end loop ラベル名;
※ループ変数 i は宣言が不要です。ラベル名は省略可能。
⑤関数 conv_std_logic_vector ()を使って、整数 i を4ビット幅の std_logic_vector に変換してから、 aSignal に代入します。 VHDLは型チェックが厳しいので、直接代入はできません。
68
⑥整数 j のループです。⑦整数 j を型変換したあと、 bSignal に代入します。
シミュレーション時間は、100ns × 16 × 16=25600ns以上に設定します。結果は下図のようになります。
69
2.case文とビット幅のある定数例題2 デコーダ decoder.vhdlibrary ieee;use ieee.std_logic_1164.all;
entity decoder is port(enb:in std_logic; adr:in std_logic_vector(2 downto 0); y :out std_logic_vector(7 downto 0));end decoder;
decode
adr
enby
3
8
architecture v1 of decoder isbegin process(enb,adr) begin if(enb='0') then case(adr) is when "000" => y<="11111110"; when "001" => y<="11111101"; when "010" => y<="11111011"; when "011" => y<="11110111"; when "100" => y<="11101111"; when "101" => y<="11011111"; when "110" => y<="10111111"; when others => y<="01111111"; end case; else y<="11111111"; end if; end process;end v1;
70
(1)デコーダは, if 文を並べて書くこともできるが, case 文を使った方がわかりやすい。
case( 信号名 ) iswhen ケース1 => 式1 ;when ケース2 => 式2 ; : :when others => 式n ;
end case; と記述する。 others は列記したケース以外、全ての場合とい う意味です。これが無いとラッチを生成する処理系もある。
(2)ビット幅のある定数は,( 2進数) B"001" B"1111_1110"(16進数) X"FC"
と書く。2進数を表す B は省略できる。
(3) else y<= "11111111" がないと,ラッチが生成される。
71
例題2のテストベンチ decoder.tb.vhdlibrary ieee;use ieee.std_logic_1164.all;use ieee.std_logic_arith.all;
ENTITY TestBench ISEND TestBench;
ARCHITECTURE HTWTestBench OF TestBench IS
COMPONENT decoder PORT (enb:in std_logic;
adr:in std_logic_vector(2 downto 0); y :out std_logic_vector(7 downto 0));
END COMPONENT;
SIGNAL enbSignal: std_logic;SIGNAL adrSignal: std_logic_vector(2 downto 0);SIGNAL ySignal : std_logic_vector(7 downto 0);
BEGIN U1 : decoder
PORT MAP (enb => enbSignal, adr => adrSignal, y => ySignal);
72
process beginenbSignal <='0';for i in 0 to 7 loop adrSignal <=conv_std_logic_vector(i,3); wait for 100ns;end loop;
enbSignal <='1';for i in 0 to 7 loop adrSignal <=conv_std_logic_vector(i,3); wait for 100ns;end loop;wait;
end process;END HTWTestBench;シミュレーション時間=2000ns
73
3.算術演算子と連接子例題3 アダー adder.vhd
library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;
entity adder is generic (n :integer :=4); port(cin :in std_logic; a,b :in std_logic_vector(n-1 downto 0); cout:out std_logic; s :out std_logic_vector(n-1 downto 0));end adder;
adderab
cin
s
cout
44
4
74
architecture v1 of adder is signal ax,bx,cx,sx:std_logic_vector(n downto 0);begin
ax(n downto 0)<= '0' & a(n-1 downto 0);bx(n downto 0)<= '0' & b(n-1 downto 0);cx <= (0=>cin, others=>'0');
sx <= ax+bx+cx;s(n-1 downto 0)<= sx(n-1 downto 0);cout <= sx(n);
end v1;--------------------------------------------------------------architecture v2 of adder is signal sx:std_logic_vector(n downto 0);begin
sx <= ('0' & a)+('0' & b)+cin;s <= sx(n-1 downto 0);cout <= sx(n);
end v2;
75
(1)加算器,減算器,乗算器を生成するのに算術演算子 +、ー、*が使える。
(2)算術演算子を使うためには, use ieee.std_logic_unsigned.all; 符号なし算術演算パッケージ
または, use ieee.std_logic_signed.all; 符号有り算術演算パッケージ
が必要。
(3)キャリ入出力 cin,cout がなければ s <= a + b;
とコンパクトに記述できる。
(4) verilog の連接演算子 { , } に相当するものは VHDL では 連接子 ( & ) であるが, verilog の様に信号代入文の左辺 には使えないのでアーキテクチャ v2 の様に, a,b より1ビット多いローカル信号 sx を使って記述するしかない。参照:長谷川テキストp28~30
76
また, VHDL は型チェックが厳しく,左辺と右辺のビット幅が 異なると,代入できないので,
sx <= a+b+cin; はエラーになってしまう。
(5)アーキテクチャ v2 も,コンパイラによっては通らないかもしれない。 なぜなら, sx と cin のビット幅が違うためである。そのときは(6)の ように書く。
(6)0ビット目が cin で,他のビットが全て0の幅nビットの信号は, アーキテクチャ v1 の様に
(0 => cin , others => '0') と書く。これは,集合体と呼ばれ,0ビット目に限らず,ビット位置を 指定してビット幅のある信号を記述するのに使われる。 ただし,集合体の要素としては,ビット幅1のものしか書けない。 つまり, ('0',a) はエラーになる。 参照:長谷川テキストp28~30
77
例題3のテストベンチ adder.tb.vhdlibrary ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;use ieee.std_logic_arith.all;
ENTITY TestBench ISEND TestBench;
ARCHITECTURE HTWTestBench OF TestBench IS
COMPONENT adder GENERIC (n :integer :=4); PORT (cin :in std_logic; a,b :in std_logic_vector(n-1 downto 0); cout:out std_logic; s :out std_logic_vector(n-1 downto 0));END COMPONENT;
constant n:integer:=4;SIGNAL cinSignal : std_logic;SIGNAL aSignal,bSignal : std_logic_vector(n-1 downto 0);SIGNAL coutSignal: std_logic;SIGNAL sSignal : std_logic_vector(n-1 downto 0);
BEGIN U1 : adder GENERIC MAP (n => 4)
PORT MAP (cin => cinSignal, a => aSignal, b => bSignal, cout => coutSignal, s => sSignal);
78
process begin cinSignal <='0';L1:for i in 0 to 15 loop
aSignal <=conv_std_logic_vector(i,4);L2:for j in 0 to 15 loop
bSignal <=conv_std_logic_vector(j,4); wait for 100ns;end loop L2;
end loop L1; cinSignal <='1';L3:for i in 0 to 15 loop
aSignal <=conv_std_logic_vector(i,4);L4:for j in 0 to 15 loop
bSignal <=conv_std_logic_vector(j,4); wait for 100ns;end loop L4;
end loop L3; wait;end process;
END HTWTestBench;シミュレーション時間=16x16x2x100ns=51200ns
79
4.フリップフロップの記述例題4 フリップフロップ dff.vhdlibrary ieee;use ieee.std_logic_1164.all;
entity dff is port(d,clk,sclr,aclr,enb:in std_logic; q,qsc,qac,qen:out std_logic);end dff;
dclk
qsc
sclr
同期クリア FF
dclk
q通常 FF
architecture RTL of dff isbegin -- simple ff --- process(clk) begin if(clk'event and clk='1') then q <= d; end if; end process;
-- sync clear ff --- process(clk) begin if(clk'event and clk='1') then
if(sclr='0') then qsc <= '0'; else qsc <= d;
end if;end if;
end process;
80
-- async clear ff -- process(clk,aclr) begin if (aclr='0') then qac <= '0'; elsif(clk'event and clk='1') then qac <= d; end if; end process;
-- enb ff -- process(clk) begin if(clk'event and clk='1') then
if(enb='1') then qen <= d; end if;
end if; end process;end RTL;
dclk
qen
enb
イネーブル機能付 FF
dclk
qac
aclr
非同期クリア FF
81
(1)フリップフロップの生成には,上の例の様に if(clk'event and clk='1') then
を使う。 if 文なので process ブロックの中で使う。
(2)同期クリア信号は, process( 信号名 ) のセンシティビティ・リストには記述しないで,はじめの if 文の条件にクロックイベントを次の if 文の条件にクリア信号を記述する。
(3)非同期クリア信号は,センシティビティ・リストに記述するとともに はじめの if 文の条件にクリア信号を, 次の elsif 文の条件に,クロックイベントを記述する。
(4)イネーブル信号は,同期クリア信号同じ考え方。 つまり、センシティビティ・リストには記述しないで, はじめの if 文の条件にクロックイベントを 次の if 文の条件にイネーブル信号を記述する。
82
例題4のテストベンチ dff.tb.vhdlibrary ieee;use ieee.std_logic_1164.all;
ENTITY TestBench ISEND TestBench;
ARCHITECTURE HTWTestBench OF TestBench IS
COMPONENT dff PORT (d,clk,sclr,aclr,enb:in std_logic;
q,qsc,qac,qen:out std_logic);END COMPONENT;
SIGNAL dSignal,clkSignal,sclrSignal,aclrSignal,enbSignal: std_logic;SIGNAL qSignal,qscSignal,qacSignal,qenSignal: std_logic;
BEGIN U1 : dff PORT MAP (d => dSignal, clk => clkSignal,
sclr => sclrSignal, aclr => aclrSignal, enb => enbSignal, q => qSignal, qsc => qscSignal, qac => qacSignal, qen => qenSignal);
process beginclkSignal <='0';loop …①クロック生成には for 無しloop が使える。
wait for 50ns;clkSignal <=not clkSignal;
end loop;end process;
83
process beginaclrSignal <='1'; sclrSignal <='1'; enbSignal <='1'; dSignal <='1'; wait for 125ns;dSignal <='0'; wait for 200ns;dSignal <='1'; wait for 300ns;aclrSignal <='0'; sclrSignal <='0'; enbSignal <='0'; wait for 200ns;dSignal <='0'; wait for 300ns;aclrSignal <='1'; sclrSignal <='1'; enbSignal <='1'; wait for 200ns;dSignal <='1';wait;
end process;END HTWTestBench;シミュレーション時間=2000ns
84
5.エッジ検出回路の記述例題5 エッジ検出 edg.vhdlibrary ieee;use ieee.std_logic_1164.all;
entity edg is port(clk,d,reset:in std_logic; rise,fall:out std_logic);end edg;
architecture v1 of edg is signal q1,q2:std_logic;begin process(clk) begin if(clk'event and clk='1') then if(reset='0') then q1<='0'; q2<='0'; else q1<=d; q2<=q1; end if; end if; end process;
rise<= q1 and (not q2); fall <=(not q1) and q2 ;end v1;
riseclk
d q1 q2
fall
reset
85
(1)スイッチが押された時,1回だけある動作をさせたい時など, 入力信号の立ち上がり,立ち下がりを検出する手段として, 図のようなエッジ検出回路が使用される。
(2)VHDLでは立ち下がり,立ち上がりエッジの検出は 上の例の様に書ける。
(3)VHDLの場合、 q1 用と q2 用の process ブロックを分けても, 分けなくても同じ論理合成結果が得られる。 Verilogの場合は、ブロックを分けるか分けないか、また =を使うか、<=を使うかで論理合成結果が異なる。
86
例題5のテストベンチ edg.tb.vhdlibrary ieee;use ieee.std_logic_1164.all;
ENTITY TestBench ISEND TestBench;
ARCHITECTURE HTWTestBench OF TestBench IS
COMPONENT edg PORT (clk,d,reset:in std_logic; rise,fall:out std_logic);END COMPONENT;
SIGNAL clkSignal,dSignal,resetSignal: std_logic; SIGNAL riseSignal,fallSignal: std_logic;
BEGIN U1 : edg PORT MAP (clk => clkSignal, d => dSignal, reset => resetSignal,
rise => riseSignal, fall => fallSignal); clock:process begin …① processにも名前が付けられる。
clkSignal <='0';loop wait for 50ns;
clkSignal <= not clkSignal; end loop; end process;
87
d_reset:process begin resetSignal <='0'; dSignal <='0'; wait for 75ns; resetSignal <='1'; wait for 200ns; dSignal <='1'; wait for 300ns; dSignal <='0'; wait for 400ns; dSignal <='1'; wait for 400ns; dSignal <='0'; wait; end process;END HTWTestBench;
シミュレーション時間=2000ns
88
6.同期クリア付きカウンタ例題6 countsc.vhdlibrary ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;
entity countsc isport(clk,clr:in std_logic; count :out std_logic_vector(3 downto 0)); …②
end countsc;
architecture countsc_body of countsc issignal count_tmp:std_logic_vector(3 downto 0);
begin count <= count_tmp; …③process(clk) begin
if(clk'event and clk='1') thenif(clr='0') then count_tmp <= "0000";
else count_tmp <= count_tmp+1; end if;end if;
end process;end countsc_body;
4countclk
clr
countsc
89
(1)同期クリア付カウンタは同期クリアFFのクリア信号の書き方と 算術演算子 + の応用である。
(2)同期クリア信号はイベントリストに記述しないで、 最初のif文の条件にクロックイベントを、 次のif文の条件に同期クリア信号を記述する。
(4)重要なのは VHDL の out 宣言された信号(この例では count )は, アーキテクチャ内部で,読み出し参照できない点である。
(5)信号代入文の左辺には,もちろん書けるので count_tmp の様に, ローカル信号を宣言し,再代入してやればよい。
(小テスト)これを10進カウンタにするには、どうすればよいか。
90
例題6のテストベンチ countsc.tb.vhdlibrary ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;
ENTITY TestBench ISEND TestBench;
ARCHITECTURE HTWTestBench OF TestBench IS
COMPONENT countsc PORT (clk,clr:in std_logic;
count :out std_logic_vector(3 downto 0));END COMPONENT; SIGNAL clkSignal:std_logic:='0'; …① SIGNAL clrSignal:std_logic:='1'; …① SIGNAL countSignal : std_logic_vector(3 downto 0);BEGIN U1 : countsc
PORT MAP (clk => clkSignal, clr => clrSignal, count => countSignal);clrSignal<='0' after 125ns, '1' after 325ns; …②clkSignal<=(not clkSignal) after 50ns; …③
END HTWTestBench;
91
①シグナルの初期値は、シグナル宣言時に与えることも可能。 =や<=ではなく、:=であることに注意。
②簡単なシグナル値は、カンマで区切って与えることができる。 wait forの場合は相対時間であったが、afterの場合は 絶対時間であることに注意。この例では、clrの初期値は1で、 125nsで0,325nsで1になる。
③初期値を与えたクロック信号はprocess文で囲まなくても、 この書き方で50ns毎に反転する信号になる。
④同期クリアなので、clr=0の次のclk立ち上がりでcount=0と なることを確認する。
92
7.非同期クリア付きカウンタ例題7 countac.vhdlibrary ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;
entity countac isport(clk,clr:in std_logic; count :out std_logic_vector(3 downto 0));
end countac;
architecture countac_body of countac issignal count_tmp:std_logic_vector(3 downto 0);
begin count <= count_tmp;process(clk,clr) begin
if(clr='0') then count_tmp <= "0000";elsif(clk'event and clk='1') then count_tmp <= count_tmp+1;end if;
end process;end countac_body;
4countclk
clr
countac
93
例題7のテストベンチ countac.tb.vhdlibrary ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;
ENTITY TestBench ISEND TestBench;
ARCHITECTURE HTWTestBench OF TestBench IS
COMPONENT countac PORT (clk,clr:in std_logic;
count :out std_logic_vector(3 downto 0));END COMPONENT; SIGNAL clkSignal:std_logic:='0'; SIGNAL clrSignal:std_logic:='1'; SIGNAL countSignal : std_logic_vector(3 downto 0);BEGIN U1 : countac
PORT MAP (clk => clkSignal, clr => clrSignal, count => countSignal);clrSignal<='0' after 125ns, '1' after 325ns;clkSignal<=(not clkSignal) after 50ns;
END HTWTestBench;
94
(1)非同期クリア付カウンタは非同期クリアFFのクリア信号の 書き方と算術演算子 + の応用である。
(2)非同期クリア信号は、イベントリストに記述すると共に 、 はじめのif文の条件にクリア信号を、 次のelsif文の条件にクロックイベントを記述する。
(2)テストベンチは同期クリア付きカウンタと同じもの。 非同期クリアなので、clr=0と同時に、count=0となっている ことを確認する。
(小テスト)これにキャリー入出力をつけるにはどうすればよいか。
95
8.ステートマシンの記述例題8 state.vhd
library ieee;use ieee.std_logic_1164.all;
entity state is port(clk,a,res:in std_logic; ss:out std_logic_vector(1 downto 0));end state;architecture v1 of state is signal ss_tmp:std_logic_vector(1 downto 0); constant s00:std_logic_vector(1 downto 0):=B"00"; constant s01:std_logic_vector(1 downto 0):=B"01"; constant s10:std_logic_vector(1 downto 0):=B"10"; constant s11:std_logic_vector(1 downto 0):=B"11";
a a
a
a
a
a
1
S00
S01
S11
S10
96
begin ss<=ss_tmp; process(clk) begin if(clk'event and clk='1') then
if(res='0') then ss_tmp<=s00; else case(ss_tmp) is
when s00=> if(a='1') then ss_tmp<=s01; else ss_tmp<=s10; end if;when s01=> if(a='1') then ss_tmp<=s11; end if;when s10=> if(a='0') then ss_tmp<=s11; end if;when s11=> ss_tmp<=s00;
end case; end if; end if; end process;end v1;(1) VHDL のステートマシン記述では,ステートの値は
① type宣言した論理的な値 ② constant宣言した物理的な値
のどちらかを用いる。 (2)上の例では,ステートの値を出力として観測したいので, constant宣言した物理的な値を用いている。
97
(2)このステートマシンは,Verilogの時と同様に s00 が初期状態で,
入力 a=1 なら s00 → s01 → s11 (但し, s01 で a=0 なら, s01 のまま) ↑ │ └─────┘ 入力 a=0 なら s00 → s10 → s11 (但し , s10 で a=1 なら, s10 のまま) ↑ │ └─────┘と回るものです。 case 文を使えば,上述のようにすっきり書けます。
(3) case 文の when に続くケース値にステートマシンのステート値を 記述することになるが,これは process ブロック内の読み出し参 照にあたるので,カウンタの時と同様に,ローカル信号 ss_tmp を 宣言し使っている。
98
(4)ステートの値を直接,出力として観測する必要がなければ, type 宣言した論理的な値を用いても良い。 この場合,アーキテクチャは次のように記述する。
architecture v2 of state istype st_val is (s00,s01,s10,s11);signal st:st_val;
beginprocess(clk) begin : ss_tmp を : st に書き換えたものend process;process(st) begin : st と出力の : 関係の記述end process;
end v2;
99
例題8のテストベンチ state.tb.vhdlibrary ieee;use ieee.std_logic_1164.all;
ENTITY TestBench ISEND TestBench;
ARCHITECTURE HTWTestBench OF TestBench IS
COMPONENT state PORT (clk,a,res:in std_logic; ss:out std_logic_vector(1 downto 0));END COMPONENT; SIGNAL clkSignal,aSignal,resSignal: std_logic; SIGNAL ssSignal: std_logic_vector(1 downto 0);BEGIN U1 : state
PORT MAP (clk => clkSignal,a => aSignal, res => resSignal,ss => ssSignal); clock:process begin
clkSignal<='0';loop wait for 50ns; clkSignal<=not clkSignal; end loop;
end process;
100
other:process begin resSignal<='0'; aSignal<='0'; wait for 100ns; resSignal<='1'; wait for 700ns; resSignal<='0'; aSignal<='1'; wait for 100ns; resSignal<='1'; wait; end process;END HTWTestBench;
101
9.トライステート出力例題9 triout.vhd
library ieee;use ieee.std_logic_1164.all;
entity triout is port(a,oe:in std_logic; y :out std_logic);end triout;
architecture v1 of triout isbegin y<=a when oe='1' else 'Z';end v1;
a y
oe
architecture v2 of triout isbegin process(a, oe) begin
if(oe='1') then y <=a; else y <='Z';end if;
end process;end v2;
102
(1)トライステート出力、双方向バスの記述は実用的なLSIを 設計する上でさけて通れない。
(2)1ビットのハイインピーダンスは 'Z' と書く。 8ビットは X "ZZ" または B"ZZZZ_ZZZZ" と書く。 ただし、PeakVHDLではX "ZZ" は使えない。 (others => 'Z') と書けば、ビット幅に無関係に使える。
(3)トライステート出力は, V1のように、条件付信号代入文で記述しても良いし、 V2のように、process文とif文で記述しても良い。
(4)トライステート出力は out 宣言する。
103
例題9のテストベンチ triout.tb.vhdlibrary ieee;use ieee.std_logic_1164.all;
ENTITY TestBench ISEND TestBench;
ARCHITECTURE HTWTestBench OF TestBench IS
COMPONENT triout PORT (a,oe:in std_logic; y :out std_logic);END COMPONENT; SIGNAL aSignal:std_logic:='0'; SIGNAL oeSignal:std_logic:='0'; SIGNAL ySignal : std_logic;
104
BEGIN U1 : triout
PORT MAP (a => aSignal, oe => oeSignal, y => ySignal);
aSignal <=(not aSignal) after 100ns;oeSignal <= '1' after 450ns;
END HTWTestBench;
105
10.双方向バスの記述例題10 bidir.vhdlibrary ieee;use ieee.std_logic_1164.all;entity bidir is
port(rd,wr:in std_logic; db :inout std_logic);
end bidir;architecture v1 of bidir is
signal idb,odb:std_logic;begin
idb<=db;db <= odb when(rd='0') else 'Z'; process(wr) begin
if(wr'event and wr='1') then odb<=idb; end if;
end process;end v1;
rd
wr
db idb
odb
D Q
106
architecture v2 of bidir issignal idb,odb:std_logic;
beginidb<=db;process(odb , rd) begin
if(rd=‘0’) then db<=odb; else db<=‘Z’; end if;end process;
process(wr) beginif(wr'event and wr='1') then odb<=idb; end if;
end process;end v2;
(1)双方向バスも, V1のように条件付信号代入文で記述しても良いし、 V2のようにprocess文とif文で記述しても良い。 ※ Verilog の always 文では,トライステート出力は書けたが, 双方向バスは書けなかった。
(2)双方向バスは inout 宣言する。
107
例題10のテストベンチ bidir.tb.vhd
library ieee;use ieee.std_logic_1164.all;ENTITY TestBench ISEND TestBench;
ARCHITECTURE HTWTestBench OF TestBench ISCOMPONENT bidir PORT (rd,wr:in std_logic;
db :inout std_logic);END COMPONENT; SIGNAL rdSignal,wrSignal: std_logic; SIGNAL dbSignal : std_logic; signal rd_data:std_logic; BEGIN U1 : bidir PORT MAP (rd => rdSignal,
wr => wrSignal, db => dbSignal);
108
process procedure wr_proc(wr_dt:in std_logic) is begin
dbSignal <= wr_dt; wait for 50ns; wrSignal <='0'; wait for 50ns; wrSignal <='1'; wait for 50ns; dbSignal <='Z'; wait for 50ns;
end procedure; procedure rd_proc(signal rd_dt:out std_logic) is
beginrdSignal <='0'; wait for 100ns;rd_dt <= dbSignal;rdSignal <='1'; wait for 100ns;
end procedure; begin rdSignal <='1'; wrSignal <='1'; dbSignal <='Z'; wait for 100ns; wr_proc('1'); rd_proc(rd_data); report"time="&time'image(NOW); report"rd_data="&std_logic'image(rd_data);
wait for 100ns; wr_proc('0'); rd_proc(rd_data); report"time="&time'image(NOW); report"rd_data="&std_logic'image(rd_data); wait; end process;END HTWTestBench;
0 50 100 150 200db wr_dt Zwr
0 50 100 150 200 rdrd_dt 前の値 rd↑時の db の値
109
(1)プロシージャはテストベンチで使用されるサブルーチン。
(2)プロシージャはキーワードprocedureで始まり、 end procedure;で終わる。
(3)キーワードprocedureの次に、プロシージャ名を書く。 上の例ではでは wr_proc と rd_proc がプロシージャ名。
(4)プロシージャ名の続きの( )内で引数宣言を行う。wr_procでは、std_logic型の入力引数wr_dt rd_procでは、std_logic型の出力引数rd_dt
が宣言されている。値をメインルーチンに戻すときはrd_dtのようにsignal宣言する。
(5)上の例ではprocess文のメインルーチンから、 wr_procとrd_procを2回づつコールして、 データバスから1と0の書込み、読出しの確認をしている。
110
(6)report文はメッセージを出力する命令であり、 NOWは現在時刻を返す関数です。 信号値などをreport文で表示するときは、型’image(変数)を 使って、型タイプの変数を文字列に変換してから表示します。
111
VHDL設計演習
Ⅳ 応 用 編
広島県立西部工業技術センター
112
1.ストップウオッチの設計 次の回路図のハードウエアを用意しています。
14
24
37
+51/100秒
+51/10秒
+5 1秒
+5+5
+5
+5
10秒
1k
1k
1k
1k
7
7
7
7
100k
100k
0.1μ
0.1μ
START
START
STOP
STOP
100HzCLK GND
VCC
LED4
LED3
LED2
LED1
MACH210
WATCH
1143
1021
13811 10 9
44,22
1,12,23,34
93
20
30
43
g
a
e d c h COM2
f g a bCOM1
a
bf
g
ce
hd
7セグメント LED
TLR306
(アノードコモン)
LEDi[0]
LEDi[2]
LEDi[4]
LEDi[6]
g abcdef
h
h
LEDi[5]
LEDi[3]
LEDi[1]
(i=1~4)
COM2COM1
(問題1)100Hzの方形波をカウントして、下記の仕様の4桁ストップウオッチをVHDLで記述しなさい。
startスイッチを押すと、カウント開始stopスイッチを押すと、カウント停止両方同時に押すと、リセット
(問題2) startスイッチだけで、スタート、ストップ、リセットができる仕様に変更しなさい。
113
①エンティティ digit は LED一桁に相当するサブモジュールで、カウンタ部と7セグメントデコーダ部で構成されています。②カウンタ部は clk をクロック、 resを正論理の同期クリア信号とする4ビットカウンタです。10進カウンタなので、9の次は0に戻らなければなりません。③キャリー入力が有り、かつカウント値が9の時、キャリー出力が出なければなりません。
library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;entity digit is port(clk,res,cin:in std_logic; cout:out std_logic; led :out std_logic_vector(6 downto 0));end digit; architecture v1 of digit is signal dgt:std_logic_vector(3 downto 0);begin process(clk) begin if( and ) then
if( ) then dgt<=X"0"; elsif(cin='1' and ) then dgt<=dgt+1; elsif(cin='1' and dgt =X"9") then dgt<=X"0"; end if; end if; end process; cout<=cin when( ) else '0';
①
②
③
114
process(dgt) begincase(dgt) is
when X"0"=> led<= not B"011_1111"; --3f;when X"1"=> led<= not B"000_0110"; --06;when X"2"=> led<= ;when X"3"=> led<= ;when X"4"=> led<= ;when X"5"=> led<= ;when X"6"=> led<= ;when X"7"=> led<= ;when X"8"=> led<= ;when X"9"=> led<= ;when others=> led<= ;
end case; end process;end v1;
④7セグメントデコーダ部は、カウント値を数字表示用データに変換する組合せ回路です。④
115
⑤エンティティ watch1 がメインモジュールでreset,count,display の3つの状態を遷移するステートマシンです。条件は下記の通り。
start のみで count へstop のみで display へ両方で reset へ
library ieee;use ieee.std_logic_1164.all;
entity watch is port(start,stop,clk:in std_logic; led1,led2,led3,led4
:out std_logic_vector(6 downto 0));end watch;architecture v1 of watch is component digit port(clk,res,cin:in std_logic; cout:out std_logic; led :out std_logic_vector(6 downto 0)); end component; signal dres,enb1,enb2,enb3,enb4:std_logic; signal state:std_logic_vector(1 downto 0);
constant reset:std_logic_vector(1 downto 0):="00"; constant count:std_logic_vector(1 downto 0):="01"; constant display:std_logic_vector(1 downto 0):="10";
⑤
⑤
116
digit4 enb4 digit3 enb3 digit2 enb2 digit1 enb1
begin process(clk) begin if(clk'event and clk='1') then if(start='1' and stop='1') then state<=reset; elsif( and ) then state<=count; elsif( and ) then state<=display; end if; end if; end process;
enb1<= ; dres<='1' when (state=reset) else '0';
digit1: digit port map(clk,dres,enb1,enb2,led1); digit2: digit port map(clk,dres, , ,led2); digit3: digit port map(clk,dres, , ,led3); digit4: digit port map(clk,dres, , ,led4);
end v1;
⑥digit1 ~ digit4 はそれぞれ digit1 1/100 秒の桁 digit2 1/10 秒の桁 digit3 1 秒の桁 digit4 10 秒の桁に相当するコンポーネントインスタンスです。
⑦enb1 ~ enb4 は digit1 ~ digit4のキャリ入力とキャリ出力を接続するローカル信号です。
⑤
⑥⑦
117
2.並列IOの設計 下記仕様の8ビット × 3ポート入出力LSI(インテル8255の簡易版)を設計しなさい。cs rd wr adr 動 作 H × × ×× 非 動 作
00 DB←PAピン L L H 01 DB←PBピン
10 DB←PCピン 11 DB←CRレジスタ 00 DB→PAレジスタ
L H ↑ 01 DB→PBレジスタ 10 DB→PCレジスタ 11 DB→CRレジスタ
CRレジスタはPA、PB、PCの入出力を決める内部レジスタ。CR(0) 0 PA=出力モード 1 PA=入力モードCR(1) 0 PB=出力モード 1 PB=入力モード CR(2) 0 PC=出力モード 1 PC=入力モード
PIO
ADR PA
CS PBRDWR PC
DB CRRES
2
8
8
8
8
RESはPA,PB,PCを全て入力モードにする負論理の非同期リセット信号。
118
並列IO pio.vhdlibrary ieee;use ieee.std_logic_1164.all;entity pio is generic(n:integer:=8); port(cs,rd,wr,res:in std_logic; adr :in std_logic_vector(1 downto 0); db,pa,pb,pc :inout std_logic_vector(n-1 downto 0));end pio;
architecture pio_body of pio is signal qa,qb,qc,cr,odb:std_logic_vector(n-1 downto 0);begin ----- internal register (reset , cs & wr) -----process(wr,res) begin
if( ) then qa<=(others=>'0'); qb<=(others=>'0'); qc<=(others=>'0'); cr<=(others=>'1');
elsif( and ) then if( ) then
case( ) is when "00"=> qa<=db; when "01"=> qb<=db;when "10"=> qc<=db; when others=> cr<=db;
end case; end if; end if;end process;
①
①qa,qb,qc,cr は wr をクロック、~res を非同期クリア信号とする FF でcs がアクティブの時、 db の値が adr で選択された qa,qb,qc,cr のいずれかに書き込まれる。
119
②
③
④
②pa は ~cr[0] を制御信号とする双方向バッファ
pb は ~cr[1] を制御信号とする双方向バッファ
pc は ~cr[2] を制御信号とする双方向バッファ
③は pa,pb,pc,cr をデータ入力 adr をセレクト信号 odb をデータ出力とする データセレクタ
④db は ~cs と ~rd の論理積を制御信号とする双方向バッファ
----- port tri-state assign -----pa<=qa when ( ) else (others => 'Z');pb<=qb when ( ) else (others => 'Z');pc<=qc when ( ) else (others => 'Z');
----- data selecter -----process( , , , , ) begin
case( ) iswhen "00"=> odb<=pa;when "01"=> odb<=pb;when "10"=> odb<=pc;when others=> odb<=cr;
end case;end process;
----- databus tri-state assign (cs & rd) ----- db<=odb when( and ) else (others => 'Z');
end pio_body;
120
PIOのテストベンチ pio.tb.vhdlibrary ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;use ieee.std_logic_arith.all;
ENTITY TestBench ISEND TestBench;
ARCHITECTURE HTWTestBench OF TestBench ISCOMPONENT pio GENERIC (n:integer:=8); PORT (cs,rd,wr,res:in std_logic; adr:in std_logic_vector(1 downto 0); db,pa,pb,pc :inout std_logic_vector(n-1 downto 0));END COMPONENT; constant n:integer:=8; SIGNAL csSignal,rdSignal,wrSignal,resSignal: std_logic; SIGNAL adrSignal : std_logic_vector(1 downto 0); SIGNAL dbSignal,paSignal,pbSignal,pcSignal : std_logic_vector(n-1 downto 0); signal rd_data:std_logic_vector(n-1 downto 0);BEGIN U1 : pio GENERIC MAP (n => 8)
PORT MAP (cs => csSignal, rd => rdSignal, wr => wrSignal, res => resSignal, adr => adrSignal, db => dbSignal,
pa => paSignal, pb => pbSignal, pc => pcSignal); paSignal <= pbSignal after 1ns; -- connect from PB to PA
121
processprocedure wr_proc(adr_dt:in std_logic_vector(1 downto 0);
wr_dt:in std_logic_vector(7 downto 0)) isbegin csSignal <='0'; adrSignal <= adr_dt; dbSignal <= wr_dt; wait for 50ns;
wrSignal <='0'; wait for 100ns;wrSignal <='1'; wait for 50ns;csSignal <='1'; adrSignal <= B"11"; dbSignal <= B"ZZZZ_ZZZZ"; wait for 50ns;
end procedure;procedure rd_proc(adr_dt:in std_logic_vector(1 downto 0);
signal rd_dt:out std_logic_vector(7 downto 0)) is begin csSignal <='0'; adrSignal <= adr_dt; wait for 50ns;
rdSignal <='0'; wait for 100ns;rd_dt <= dbSignal;rdSignal <='1'; wait for 50ns;csSignal <='1'; adrSignal <= B"11"; wait for 50ns;
end procedure;begin
csSignal <='1'; rdSignal <='1'; wrSignal <='1';dbSignal <=B"ZZZZ_ZZZZ"; resSignal <='0'; wait for 50ns;resSignal <='1'; wait for 50ns;wr_proc(B"11",X"01"); -- write CW to CRfor i in 0 to 255 loop wr_proc(B"01",conv_std_logic_vector(i,8)); -- write to PB rd_proc(B"00",rd_data); -- read from PA report "i="&integer'image(i)&" rd_data="&integer'image(conv_integer(rd_data));end loop; wait;
end process;END HTWTestBench;
122
123
解答例watch1.vhd 1/4
library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;
entity digit is port(clk,res,cin:in std_logic; cout:out std_logic; led :out std_logic_vector(6 downto 0));end digit; architecture v1 of digit is signal dgt:std_logic_vector(3 downto 0);begin process(clk) begin if(clk'event and clk='1') then
if(res='1') then dgt<=X"0"; elsif(cin='1' and dgt/=X"9") then dgt<=dgt+1; elsif(cin='1' and dgt =x"9") then dgt<=X"0"; end if; end if; end process; cout<=cin when(dgt=X"9") else '0';
124
process(dgt) begincase(dgt) is
when X"0"=> led<= not B"011_1111"; --X"3f";when X"1"=> led<= not B"000_0110"; --X"06";when X"2"=> led<= not B"101_1011"; --X"5b";when X"3"=> led<= not B"100_1111"; --X"4f";when X"4"=> led<= not B"110_0110"; --X"66";when X"5"=> led<= not B"110_1101"; --X"6d";when X"6"=> led<= not B"111_1101"; --X"7d";when X"7"=> led<= not B"010_0111"; --X"27";when X"8"=> led<= not B"111_1111"; --X"7f";when X"9"=> led<= not B"110_1111"; --X"6f";when others=> led<= not B"000_0000"; --X"00";
end case; end process;end v1;
解答例watch1.vhd 2/4
125
library ieee;use ieee.std_logic_1164.all;
entity watch is port(start,stop,clk:in std_logic; led1,led2,led3,led4:out std_logic_vector(6 downto 0));end watch;architecture v1 of watch is component digit port(clk,res,cin:in std_logic; cout:out std_logic; led :out std_logic_vector(6 downto 0)); end component; signal dres,enb1,enb2,enb3,enb4:std_logic; signal state:std_logic_vector(1 downto 0); constant reset:std_logic_vector(1 downto 0):="00"; constant count:std_logic_vector(1 downto 0):="01"; constant display:std_logic_vector(1 downto 0):="10";
解答例watch1.vhd 3/4
126
begin process(clk) begin if(clk'event and clk='1') then if(start='1' and stop='1') then state<=reset; elsif(start='1' and stop='0') then state<=count; elsif(start='0' and stop='1') then state<=display; end if; end if; end process;
enb1<=state(0); dres<='1' when (state=reset) else '0';
digit1: digit port map(clk,dres,enb1,enb2,led1); digit2: digit port map(clk,dres,enb2,enb3,led2); digit3: digit port map(clk,dres,enb3,enb4,led3); digit4: digit port map(clk,dres,enb4,open,led4);
end v1;
解答例watch1.vhd 4/4
127
library ieee;use ieee.std_logic_1164.all;entity pio is generic(n:integer:=8); port(cs,rd,wr,res:in std_logic; adr :in std_logic_vector(1 downto 0); db,pa,pb,pc :inout std_logic_vector(n-1 downto 0));end pio;
architecture pio_body of pio is signal qa,qb,qc,cr,odb:std_logic_vector(n-1 downto 0);begin ----- internal register (reset , cs & wr) -----process(wr,res) begin
if(res='0') then qa<=(others=>'0'); qb<=(others=>'0');qc<=(others=>'0'); cr<=(others=>'1');
elsif(wr'event and wr='1') then if(cs='0') then
case(adr) is when "00"=> qa<=db; when "01"=> qb<=db;when "10"=> qc<=db; when others=> cr<=db;
end case; end if; end if;end process;
解答例pio.vhd 1/2
128
----- port tri-state assign -----pa<=qa when (cr(0)='0') else (others => 'Z');pb<=qb when (cr(1)='0') else (others => 'Z');pc<=qc when (cr(2)='0') else (others => 'Z');
----- data selecter -----process(adr,pa,pb,pc,cr) begin
case(adr) iswhen "00"=> odb<=pa;when "01"=> odb<=pb;when "10"=> odb<=pc;when others=> odb<=cr;
end case;end process;
----- databus tri-state assign (cs & rd) ----- db<=odb when(cs='0' and rd='0') else (others => 'Z');
end pio_body;
解答例pio.vhd 2/2