Verilog設計演習
Download
1 / 92

Verilog - PowerPoint PPT Presentation


  • 156 Views
  • Uploaded on

Verilog設計演習 Ⅰ   入 門 編 広島県立西部工業技術センター. 1.作業ディレクトリの作成  まず、エクスプローラを起動し、  ルートディレクトリの下にseminarというディレクトリを、  その下にVerilogというディレクトリを作成して下さい。 ( DOS/V の場合) C:¥seminar¥Verilog (98の場合) A:¥seminar¥Verilog 以下、Verilog演習で作成するファイルはVerilogの下に作ります。 それ以外の、ディレクトリには何も作らないで下さい。. A. B. F. C. D.

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about 'Verilog ' - cameo


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

Verilog設計演習Ⅰ  入 門 編広島県立西部工業技術センター


1.作業ディレクトリの作成

 まず、エクスプローラを起動し、

 ルートディレクトリの下にseminarというディレクトリを、

 その下にVerilogというディレクトリを作成して下さい。

(DOS/Vの場合)

C:¥seminar¥Verilog

(98の場合)

A:¥seminar¥Verilog

以下、Verilog演習で作成するファイルはVerilogの下に作ります。

それ以外の、ディレクトリには何も作らないで下さい。


2.Verilogの基本ブロック

例題1 aoiゲート  aoi.v

module aoi(a,b,c,d,f);

input a,b,c,d;

output f;

assign f=~((a & b)|(c & d));

endmodule


1)verilogの基本ブロックはモジュール。

(2)モジュールはキーワードmoduleではじまり,endmoduleで終わる。

(3)キーワードmoduleの次にモジュール名と(ポートリスト);がつづく。

(4)ポートリストに書いた信号名の入出力宣言を次に行う。

入 力 = input

出 力 = output

双方向 = inout

(5)入出力宣言とendmoduleの間にモジュールの本体機能を書く。

endmoduleにはセミコロン;はいらない。

(6)簡単な本体機能は,信号代入文assignを使って記述する。

assign 左辺 = 右辺

(7)Verilogのビット演算子は,C言語と同じ。

& AND 小林テキストP64 表3.2

| OR

~ NOT

^ EX-OR

(8)わかりやすい様に( )を使ってよい。


クイックロジック社QuickWorks

配置配線ツールSpDE

兼 統合化環境

回路図入力

SYNARIO

論理合成

Synplify

Verilogシミュレータ

SILOSⅢ

Verilog学習

VHDL学習

HDLエディタ

ターボライタ


3.SpDEの起動

 スタート - プログラム - QuickLogic ー SpDEで

SpDEを起動します。


4.HDLエディタの起動

SpDEのツールバーから、HDLエディタのアイコン   を

押して、HDLエディタを起動し、クリエイトアイコン   を押す。


5.Verilogコードの入力、保存

 例題1のVerilogコードを入力し、FileーSaveAsメニューから

¥seminar¥verilogの下に、ファイル名aoi.vで保存する。

 拡張子が定まると、module、inputなどのVerilogキーワード

が紺色でハイライトされます。紺色は見にくいのでHDLエディタの

  WindowーColorsーKeyword

で、青色に変更して下さい。

File-ExitでHDLエディタを終了し、SpDEに戻ります。

6.論理合成Synplifyの起動

 SpdeのFile-Import-Verilogメニューから

¥seminar¥verilog¥aoi.vを指定し、論理合成ツールを

起動します。


7.ターゲットデバイスの指定と論理合成

 RUNボタンのすぐ上のChangeボタンを押して、

Partをp8x12b、Packageをpl44に変更し、OKを押します。

次に、RUNボタンを押して、論理合成をかけます。


8.エラーの修正

 ソースファイルにエラーがあると、下の画面で停止します。

ViewLogボタンでエラー内容を確認した後、Editボタンを

押して、HDLエディタを再度起動し、エラー箇所を修正します。


9.論理合成プロジェクトの保存

 エラーがなければDoneが表示されて、下の画面で停止します。

「はい」を選んで論理合成プロジェクトを保存し、SpDEに戻ります。


10.配置配線の実行

 SpDEのツールバーからRunToolsアイコン   を押して、

配置配線を実行します。途中、RUNと「いいえ」を選択します。


11.配置配線結果の確認

 SpDEツールバーからFullFitアイコン   を選択し、

チップ全体を表示させます。


 次に、View-NormalFitメニューを選択し、Zカーソルを 次に、View-NormalFitメニューを選択し、Zカーソルを

回路のある部分でクリックして、回路部分を拡大表示します。

 さらに拡大したければZoomInアイコン   を使います。


 回路部分のみを拡大すると、下図のようになります。 回路部分のみを拡大すると、下図のようになります。

台形印のセレクタはr=s・p+s・qを表しますので、全体として

a・b=1またはc・d=1の時 f=0

それ以外の時         f=1

となり、最初のVerilogコードを満す回路が生成されていること

が分かります。

入力s  出力r

 0     p

 1     q

※論理合成結果を確認したら、

File-Saveメニューで結果を

保存します。


AB 回路部分のみを拡大すると、下図のようになります。

CD

12.基本ブロック(続き)

 HDLエディタを起動し、aoi.vを次のように修正します。

module aoi(a,b,c,d,f);

input a,b,c,d;

output f;

// assign f=~((a & b)|(c & d));

wire ab,cd,o;

assign ab=a & b;

assign cd=c & d;

assign o =ab | cd;

assign f = ~o;

endmodule


(1)やや複雑な機能を記述する時は, 回路部分のみを拡大すると、下図のようになります。wireで宣言した

   ローカル信号を使うこともできる。

ab,cd,o

(2)1ビット幅のwireは宣言なしでも使える。暗黙宣言。

   後出の複数ビット幅のwireは宣言が必要。

(3)//は1行のみのコメント行。

/*・・・・・*/は複数行にわたるコメント行である。

修正が終わったらソースコードを保存し、論理合成をかけて

配置配線を実行して下さい。結果は同じになります。


問題1 回路部分のみを拡大すると、下図のようになります。

 インバータLS04.vを設計し、結果を確認しなさい。

問題2

 NANDゲートLS00.vを設計し、結果を確認しなさい。

問題3

 NORゲートLS02.vを設計し、結果を確認しなさい。


SEL 回路部分のみを拡大すると、下図のようになります。

g2

g3

FB

g1

AOI

SELB

13.階層設計

例題2 マルチプレクサ mux2.v

`include "aoi.v"

module inv(a,f);

input a;

output f;

assign f=~a;

endmodule

module mux2(sel,a,b,f);

input sel,a,b;

output f;

inv g1 (sel,selb);

aoi g2 (sel,a,selb,b,fb);

inv g3 (.a(fb),.f(f));

endmodule


(1) 回路部分のみを拡大すると、下図のようになります。もっと複雑な回路記述には階層設計を使う。

(2) 階層設計は,複数のモジュール宣言と

モジュールインスタンスで行う。

(3) 複数モジュールの宣言は,

invの様に,同一ファイル内に書いても良いし,

aoiの様に,別ファイルに書いて,`includeしても良い。

(4) モジュールインスタンスは,サブルーチンコールの様なもので,

モジュール名 インスタンス名(ポートリスト);

の形式で行う。上の例では,g1,g2,g3がインスタンス名。


(5)  回路部分のみを拡大すると、下図のようになります。モジュールインスタンスのポートリストは上位モジュールと

下位モジュールを接続するもので,

g1,g2の様に,並びによる接続が一般的。

g3の様に,名前による接続も使える。

(6) 出力信号を接続しない時はカンマを余分に書く。

(7) 上の例ではselbとfbは,暗黙宣言されたwireである。

※ `はバック・シングル・クォートで

DOSVでは shift + @

98 では shift + ^

shift + 7 ではないことに注意。


例題2を入力し、論理合成、配置配線を実行します。例題2を入力し、論理合成、配置配線を実行します。

結果は、論理圧縮の効果で例題1より簡単になり、

下図のようになります。

sel=1なら f=a

sel=0なら f=b

となっています。

sel


14.条件付きassign文例題2を入力し、論理合成、配置配線を実行します。

例題3 セレクタ mux21.v

module mux21(sel,a,b,f);

input sel,a,b;

output f;

assign f=sel ? a:b;

endmodule

mux21

sel

(1) 例題2(mux2.v)では階層設計を説明するため,複雑な書き方を

   したが,セレクタ自体はもっと簡単に記述できる。

(2)assign文にはC言語の3項演算子(条件演算子ともいう)に似た

  条件付きassign文があり,

assign 左辺=(条件式1) ? (右辺1) : (右辺2);

  が使える。

(3)上の例では,sel=1ならf=a,sel=0ならf=bになる。


15.always文とif文例題2を入力し、論理合成、配置配線を実行します。

例題3 セレクタ mux21.v

module mux21(sel,a,b,f);

input sel,a,b;

output f;

reg f;

[email protected](sel or a or b) begin

if(sel==1'b1) f=a;

else f=b;

end

endmodule

mux21

sel

(1)3項演算子よりも,わかりやすいif文もあるが,

module-endmodule間に,ダイレクトには記述できない。

  上の例のように,alwaysブロックの中で記述する。


(2)例題2を入力し、論理合成、配置配線を実行します。always文は

[email protected](信号名) begin

:

:

end   ←セミコロンがないのに注意

の形で記述し,( )内の信号名の値が変化したときのみ評価される。

つまり,( )内にはalwaysブロックとしての入力信号を記述する。

正しくはセンシティビティ・リストという。

 複数の入力信号が有る時は,カンマではなく

orで区切って記述する。

(3)alwaysブロックで組合せ回路を生成する場合,入力信号を

全てセンシティビティ・リストに記述しなければならない。

 (順序回路の場合はそうとは限らない)


(4)例題2を入力し、論理合成、配置配線を実行します。alwaysブロック内では,if文,case文が使え,

if(条件式) 式1; else 式2;

 と書く。多重if文も使える。

if(条件式1) 式1;

else if(条件式2) 式2;

else 式3;

(5)条件式に使う関係演算子はC言語と同じで

== 等しい > 大    >= 以上

!= 等しくない < 小    <= 以下

が使え,かつ,それらの論理演算

&& 論理積 || 論理和    ! 論理否定

も使える。

(6)1ビット幅の定数は

1,0,1'b1,1'b0

と書く。 ' はSHIFT+7です。


(7)最も重要なのは,例題2を入力し、論理合成、配置配線を実行します。alwaysブロック内での

・信号代入には,assign文は使わないこと。

・代入文の左辺にくる信号は,レジスタ宣言

 しなければならないこと。

である。上の例では f がこれにあたる。

(8)上の例からわかる様に,生成される回路が組合せ回路で

 あってもレジスタ宣言が必要である。逆に言うと,レジスタ宣言

 してもフリップフロップが必ず生成されるわけではない。

(9)if文で全ての条件が列挙されていれば,つまり,

ifの数だけelseがあれば,組合せ回路が,

  そうでなければ,順序回路が生成される。

例題3を入力し、論理合成、配置配線を実行します。

結果は例題2と同じになります。


 Verilog設計演習例題2を入力し、論理合成、配置配線を実行します。Ⅱ シミュレーション編広島県立西部工業技術センター


1.テスト・フィクスチャの準備例題2を入力し、論理合成、配置配線を実行します。

 例題3の設計mux21.vを、Verilogシミュレータを用いて

検証します。

 設計検証用テストパターンを発生させるVerilogコードのことを

テスト・フィクスチャと呼びます。拡張子は通常 .tf を使います。

 HDLエディタでmux21.vを開いた状態で、

HDLー GenerateTestBench

を実行すると、テストフィクスチャの雛形mux21.tfが生成されます。

(遅いマシンでは数分かかることも有ります。)

(1) `timescale 1ns/1ns

(2) module t;

(3) reg sel,a,b;

(4) wire f;

(5) mux21 m (.sel(sel),.a(a),.b(b),.f(f));

(6) // Enter fixture code here

(7) endmodule // t


(1)timescale文はシミュレーションの時間単位を定めるもので、(1)timescale文はシミュレーションの時間単位を定めるもので、

  /の前がこのモジュール内での時間記述#の時間単位、

  /の後ろがシミュレーション時に使用される時間精度

  になります。この例ではいずれも1nsになります。

(2)テストフィクスチャのモジュールには、ポートリストが有りません。

  モジュール名は何でもかまいませんが、ここでは t です。

(3)元の設計データの入力信号は、このモジュール内では値を代入

  するので、レジスタ宣言します。

(4)出力信号は観測するだけなので、ワイヤ宣言します。

(5)元の設計データをモジュールインスタンスとして、呼び出します。

  信号の接続には、名前による接続が行われていますが、

  並びによる接続でも構いません。

(6)この位置に、実際のテストパターン用コードを追加します。


`timescale 1ns/1ns(1)timescale文はシミュレーションの時間単位を定めるもので、

module t;

reg sel,a,b;

wire f;

mux21 m (.sel(sel),.a(a),.b(b),.f(f));

// Enter fixture code here

initial begin

sel=0; a=0; b=0;

#100 sel=0; a=0; b=1;

#100 sel=0; a=1; b=0;

#100 sel=0; a=1; b=1;

#100 sel=1; a=0; b=0;

#100 sel=1; a=0; b=1;

#100 sel=1; a=1; b=0;

#100 sel=1; a=1; b=1;

end

endmodule // t

 それでは、6行目の位置に

右の四角の部分を追加して

テスト・フィクスチャを完成さ

せてから、mux21.tfとして

保存して下さい。

 この例で分かるように、テスト

フィクスチャでの信号値の代入

には、initial文を使用します。

 意味としては、

sel,a,bの初期値として

全て0を代入した後、100ns

毎に異なる値を代入しています。


2.機能シミュレーション(Pre-Layout)2.機能シミュレーション(Pre-Layout)

(1)SpDEのツールバーから、シミュレータのアイコン   を

押して、SILOS3を起動します。

 シミュレーションタイプでPre-Layoutを選択します。

テストフィクスチャがmux21.tf、

トップレベルモジュールがmux21.vになっていることを

確認後、OKを押して下さい。


(2)mux21.vは論理合成のチェックを通っているので、(2)mux21.vは論理合成のチェックを通っているので、

エラーがあるとすればmux21.tfの方です。

 エラーがあるとoutputウインドウにエラーメッセージが表示され、

下の画面で停止するので、キャンセルを押します。

 outputウインドウにエラーがなければ、(4)に進みます。


(3)エラーメッセージを確認後、SILOS3のFileーOpenメニュー(3)エラーメッセージを確認後、SILOS3のFileーOpenメニュー

からmux21.tfを選択し、エラー箇所を修正します。

 修正が終わったら、SILOS3のFile-Saveで保存し、

mux21.tfウインドウのアイコン化ボタン   でアイコン化します。

 Load/Reloadアイコン   を押して、修正結果をSILOS3に

反映させます。

 outputウインドウにエラーが無ければ、GOアイコン   を

押して(4)に進みます。

 outputウインドウにエラーが有れば、エラーメッセージを確認後

アイコン化していたmux21.tfを通常の大きさに戻し、

修正を繰り返します。


(4)テストフィクスチャにエラーが無ければ、下の画面で停止します(4)テストフィクスチャにエラーが無ければ、下の画面で停止します

ので、シミュレーション時間1000nsを入力し、OKを押します。


(5)エラーが無ければ、outputウインドウに(5)エラーが無ければ、outputウインドウに

32 State changes on observable nets.

Simulation stopped at the end of time 1.000us.が表示されるので

データアナライザのアイコン   を押して、波形表示ウインドウ

を開きます。


次に、モジュールエクスプローラのアイコン   を押して、次に、モジュールエクスプローラのアイコン   を押して、

t:tのa,b,f,selを選択後、マウス右クリックから

AddSignaltoAnalyzerを選ぶと、波形が表示されます。


 データアナライザ・ウインドウをアクティブにしてから、 データアナライザ・ウインドウをアクティブにしてから、

View-ZoomAllを選ぶと、波形全体が表示されます。

sel=0の時f=b、   sel=1の時f=aを確認します。


(1)データアナライザ・ウインドウの時間軸上で、マウス右クリックし、(1)データアナライザ・ウインドウの時間軸上で、マウス右クリックし、

timescaleを選んで、切りの良い値を入れれば、時間軸を見やすい

値に変更できます。

(2)波形上でマウスを左クリックすると、青色の第1カーソル、

右クリックすると、赤色の第2カーソルを置くことができます。

各カーソルの時間および時間差がT1,T2,Tdeltaで表示されます。

(3)信号名を選択後、カーソルスキャン・アイコン           を

押すと、カーソルが選択信号の変化点に移動します。

 この機能を使って、入力信号a,b,selと出力信号fの時間差を

測定してみると、Tdelta=0になります。

 これは、現在表示している結果が、遅延時間情報の入っていない

機能シミュレーション(Pre Layout)であるためです。

 結果を確認したら、SILO3のFile-Exitを選び、途中、「はい」を

選んで終了します。


3.遅延シミュレーション(Post-Layout)3.遅延シミュレーション(Post-Layout)

 再びSpDEのツールバーから、シミュレータのアイコン   を

押して、SILOS3を起動します。

 今度はシミュレーションタイプでPost-Layoutを選択します。

テストフィクスチャがmux21.tf、 SDFがmux21.sdf、

トップレベルモジュールがmux21.vq になっていることを

確認後、OKを押して下さい。


1000nsを確認後、OKを押します。3.遅延シミュレーション(Post-Layout)


outputウインドウに3.遅延シミュレーション(Post-Layout)92 State changes on observable nets.

Simulation stopped at the end of time 1000.000ns.が表示され、

モジュールエクスプローラ、データアナライザウインドウも表示

されるので、ズームオール   で波形全体を表示させます。


(1)波形上でマウスを左クリックすると、青色の第1カーソル、(1)波形上でマウスを左クリックすると、青色の第1カーソル、

右クリックすると、赤色の第2カーソルを置くことができます。

各カーソルの時間および時間差がT1,T2,Tdeltaで表示されます。

(2)信号名を選択後、カーソルスキャン・アイコン           を

押すと、カーソルが選択信号の変化点に移動します。

 この機能を使って、入力信号a,b,selと出力信号fの時間差を

測定してみると、今度はTdelta=9ns程度が表示されます。

 これは、現在表示している結果が、遅延時間情報(mux21.sdf)

を考慮した遅延シミュレーション(Post Layout)であるためです。

 また、Verilogコードも元のmux21.vではなく、配置配線ツール

の出力したmux21.vqが使用されています。

SDFはスタンダード・ディレイ・フォーマットといい、遅延時間情報の

標準フォーマットです。

 結果を確認したら、SILO3のFile-Exitを選び、終了します。

興味があれば、*.sdf、*.vqをエディタで開いて見て下さい。


遅延シミュレーションの結果(1)波形上でマウスを左クリックすると、青色の第1カーソル、


問題4 インバータLS04.vのテストパターンを設計し、問題4 インバータLS04.vのテストパターンを設計し、

     機能シミュレーションと遅延シミュレーションを

 実行しなさい。

問題5 NANDゲートLS00.vのテストパターンを設計し、

     機能シミュレーションと遅延シミュレーションを

 実行しなさい。

問題6 NORゲートLS02.vのテストパターンを設計し、

     機能シミュレーションと遅延シミュレーションを

 実行しなさい。


4.ピン配置の指定問題4 インバータLS04.vのテストパターンを設計し、

 ピン配置は配置配線ツールが遅延時間や配線効率を考慮して

最適に近いものに自動配置するので、これを使うのが無難です。

 しかし、設計の最終段階に近く、プリント基板の変更ができない

場合などは、次の方法でピン配置を直接指定することも可能です。

 SpDEのTools-Optionsメニューから、BackAnnotationタブ

を選択し、FixPlacementのIOcellsをチェックonにします。


 OKを選択後、RunToolsアイコン   を押して、配置配線を 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";


 論理合成Synplifyを立ち上げて、Addボタンを押します。 論理合成Synplifyを立ち上げて、Addボタンを押します。

ファイルの種類をPropertyFiles(*.sc*)にして、

mux21.scpを選択し、「開く」を押します。


 SourceFilesにmux21.scpが追加されたことを確認後、 SourceFilesにmux21.scpが追加されたことを確認後、

RUNを押して論理合成をかけます。

 途中「はい」とOKを選択すると、mux21.scpで指定した

ピン配置での配置配線が実行されます。


Verilog設計演習 SourceFilesにmux21.scpが追加されたことを確認後、Ⅲ  基 礎 編広島県立西部工業技術センター


1.ビット幅のある信号の表現 SourceFilesにmux21.scpが追加されたことを確認後、

例題1 コンパレータ comp.v

module comp(a,b,eq,ge,le);

parameter n=4;

input [n-1:0] a,b;

output eq,ge,le;

reg eq,ge,le;

[email protected](a or b) begin

if(a==b) eq=1; else eq=0;

if(a>=b) ge=1; else ge=0;

if(a<=b) le=1; else le=0;

end

endmodule

comp

ge

eq

le


 SourceFilesにmux21.scpが追加されたことを確認後、1)今までは1ビット幅の信号だけ扱ってきたが,

  ビット幅のある信号も扱える。input,output宣言時に

[MSB:LSB] 信号名,信号名;

  とすれば良い。

  同じビット幅,ビットオーダーの信号は1行で宣言できる。

[15:0] [8:1]

[1:16] [0:7]

  のいずれも使える。MSB,LSBの値の大小にかかわらず,

  左端がMSB,右端がLSBである。

(2)ビット幅を変更しやすくするためにparameterを使うことができる。


例題1の続き SourceFilesにmux21.scpが追加されたことを確認後、

module comp(a,b,eq,ge,le);

parameter n=4;

input [n-1:0] a,b;

output eq,ge,le;

assign eq=(a==b);

assign ge=(a>=b);

assign le=(a<=b);

endmodule

comp

ge

eq

le

(3)上の例の様に,コンパレータ等はif文よりもassign文の方が

コンパクトに記述できる。


例題1のテストフィクスチャ comp.tf例題1のテストフィクスチャ comp.tf

`timescale 1ns/1ns

module t;

parameter n=4;

reg [n-1:0] a,b;

wire eq,ge,le;

integer i,j;

comp m (.a(a),.b(b),.eq(eq),.ge(ge),.le(le));

// Enter fixture code here

initial begin

for(i=0;i<16;i=i+1) begin

a=i;

for(j=0;j<16;j=j+1) begin b=j; #100;end

end

end

endmodule // t

(1)initial文の中では

integer宣言した i 、jを用いた

forループが使えます。

i++ではないことに注意。


decode例題1のテストフィクスチャ comp.tf

enb

adr

2.case文とビット幅のある定数

例題2 デコーダ decoder.v

module decoder(enb,adr,y);

input enb;

input [2:0] adr;

output [7:0] y;

reg [7:0] y;

always @(enb or adr) begin

if(!enb)

case(adr)

3'b000: y=8'b11111110;

3'b001: y=8'b11111101;

3'b010: y=8'b11111011;

3'b011: y=8'b11110111;

3'b100: y=8'b11101111;

3'b101: y=8'b11011111;

3'b110: y=8'b10111111;

3'b111: y=8'b01111111;

endcase

else y=8'b11111111;

end

endmodule


(1)デコーダは,例題1のテストフィクスチャ comp.tfif文を並べて書くこともできるが,

case文を使った方がわかりやすい。

case(信号名)

ケース1:式1;

ケース2:式2;

:

:

default:式n;

endcase

と記述する。endcaseにはセミコロンはつけない。

(2)ビット幅のある定数は,

( 2進数)3'b001,8'b1111_1101,8'bZZZZ_ZZZZ

(16進数)3'h1,8'hfc,8'hZZと書く。

'の前はビット幅である。

(3)if文の条件(!enb)は,本来(~enb)と書くべきであるが,

(!enb)も許される。

(4)else y=8'b11111111; が無いとラッチが生成されるので注意。


initial begin例題1のテストフィクスチャ comp.tf

enb=0;

for(i=0;i<8;i=i+1) begin

adr=i; #100;

end

enb=1;

for(i=0;i<8;i=i+1) begin

adr=i; #100;

end

end

endmodule // t

例題2のテストフィクスチャ decoder.tf

`timescale 1ns/1ns

module t;

reg enb;

reg [2:0] adr;

wire [7:0] y;

integer i;

decoder m (.enb(enb),.adr(adr),.y(y));

// Enter fixture code here


3.算術演算子と連接演算子例題1のテストフィクスチャ comp.tf

例題3 アダー adder.v

module adder(cin,a,b,cout,s);

parameter n=4;

input cin;

input [n-1:0]a,b;

output [n-1:0]s;

output cout;

// assign {cout,s}=a+b+cin;

reg [n-1:0]s;

reg cout;

[email protected](a or b or cin) begin

{cout,s}=a+b+cin;

end

endmodule

adder

cin

cout

(1)加算器,減算器,乗算器を生成するのに算術演算子+、-、*が使える。

(2)加算結果には,キャリ出力がつきものであるが,連接演算子{ , }を使って

{cout,s}=a+b+cin;

とわかりやすく記述できる。


例題3のテストフィクスチャ adder.tf例題3のテストフィクスチャ adder.tf

`timescale 1ns/1ns

module t;

parameter n=4;

reg cin;

reg [n-1:0]a,b;

wire [n-1:0]s;

wire cout;

integer i;

adder m (.cin(cin),.a(a),.b(b),.cout(cout),.s(s));

// Enter fixture code here

initial begin

cin=0;

for(i=0;i<256;i=i+1) begin

{a,b}=i; #100;

end

cin=1;

for(i=0;i<256;i=i+1) begin

{a,b}=i; #100;

end

end

endmodule // t

このテストフィクスチャでは連接演算子を使って、二重ループを一重ループで済ませています。


通常例題3のテストフィクスチャ adder.tf

 FF

clk

同期

クリア

 FF

qsc

clk

sclr

非同期

クリア

 FF

qac

clk

aclr

イネーブル

機能付

 FF

qen

clk

enb

4.フリップフロップの記述

例題4 フリップフロップ dff.v

module dff(d,clk,sclr,aclr,enb,q,qsc,qac,qen);

input d,clk,sclr,aclr,enb;

output q,qsc,qac,qen;

reg q,qsc,qac,qen;

// simple ff //

[email protected](posedge clk)

q <= d;

// sync clear ff //

[email protected](posedge clk)

if(~sclr) qsc <= 0;

else qsc <= d;

// async clear ff //

[email protected](posedge clk or negedge aclr)

if(~aclr) qac <= 0;

else qac <= d;

// enb ff //

[email protected](posedge clk)

if(enb) qen <= d;

endmodule


(1)フリップフロップの生成には 例題3のテストフィクスチャ adder.tf

[email protected](posedge clk)

  を使う。clk信号の立ち上がりエッジでalways文が実行される。

  立ち下がり動作のFFにはnegedgeを使います。

(2)同期クリア信号は,[email protected](信号名)の

  センシティビティ・リストに記述しない。

(3)非同期クリア信号は,センシティビティ・リストに記述する。

  aclrが正論理なら、posedgeを使います。

(4)イネーブル信号は同期クリア信号と同じ。

(5)この例で用いている<=はノンブロッキング代入文と呼ばれ,

  順序回路では,これを使った方がよい。

=はブロッキング代入文と呼ばれ組合せ回路用。

  但し,上の例では全て=にしても同じ回路が生成される。


例題4のテストフィクスチャ dff.tf例題3のテストフィクスチャ adder.tf

module t;

reg d,clk,sclr,aclr,enb;

wire q,qsc,qac,qen;

dff m (.d(d),.clk(clk),

.sclr(sclr),.aclr(aclr),.enb(enb),

.q(q),.qsc(qsc),.qac(qac),.qen(qen));

// Enter fixture code here

initial begin

clk=0;

forever begin

#50; clk=~clk;

end

end

initial begin

aclr=1; sclr=1; enb=1; d=1;

#125 d=0;

#200 d=1;

#300 aclr=0;sclr=0;enb=0;

#200 d=0;

#300 aclr=1;sclr=1;enb=1;

#200 d=1;

end

endmodule // t

※クロック生成の無限ループにはforever

 を使うことができる。


fall例題3のテストフィクスチャ adder.tf

q1

q2

clk

5.ブロッキング代入文とノンブロッキング代入文

例題5 エッジ検出 edg.v

module edg(clk,d,reset,rise,fall);

input clk,d,reset;

output rise,fall;

reg q1,q2;

[email protected](posedge clk) begin

if(!reset) begin q1=0; end

elsebeginq1=d; end

end

[email protected](posedge clk) begin

if(!reset) beginq2=0; end

elsebeginq2=q1; end

end

assign rise= q1 & !q2;

assign fall=!q1 & q2;

endmodule

rise


(1)スイッチが押された時,1回だけある動作をさせたい時など,(1)スイッチが押された時,1回だけある動作をさせたい時など,

入力信号の立ち上がり,立ち下がりを検出する手段として,

図のようなエッジ検出回路が使用される。

(2)このrise,fall検出回路を1つのalways文で実現しようとすれば,

<= ノンブロッキング      = ブロッキング

の違いがわかる。上記の四角の部分は下記に置き換えられるが、

<=の代わりに、=を使うと,q1とq2が同じになり,rise,fallも消える。

[email protected](posedge clk) begin

if(!reset) begin q1<=0; q2<=0;end

elsebegin q1<=d; q2<=q1;end

end

(3)ノンブロッキング<=は、各右辺の処理が終了してから代入処理

が行われる。記述の順番に動作が影響されないので順序回路向き。

(4)ブロッキング=は、一つの代入処理が終了するまで次の処理が

行われない。記述の順番に動作が影響される。組合せ回路向き。


例題5のテストフィクスチャ (1)スイッチが押された時,1回だけある動作をさせたい時など,edg.tf

`timescale 1ns/1ns

module t;

reg clk,d,reset;

wire rise,fall;

edg m (.clk(clk),.d(d),.reset(reset),

.rise(rise),.fall(fall));

// Enter fixture code here

initial beginclk=0;

forever begin

#50 clk=~clk;

end

end

initial begin

reset=0; d=0;

#75 reset=1;

#200 d=1;

#300 d=0;

#400 d=1;

#400 d=0;

end

endmodule // t


(1)スイッチが押された時,1回だけある動作をさせたい時など,

clk

count

clr

6.同期クリア付きカウンタ

例題6 countsc.v

module countsc(clk,clr,count);

input clk,clr;

output [3:0]count; reg [3:0]count;

[email protected](posedge clk) begin

if(!clr) count <= 0;

else count <=count+1;

end

endmodule

countsc

(1)同期クリア付カウンタは,同期クリアFFのクリア信号の書き方と,

 算術演算子+の応用であり,上の例の様にかける。

 順序回路なので代入には、ノンブロッキングを使った方が良い。

(小テスト)これを10進カウンタにするには、どうすればよいか。


例題6のテストフィクスチャ countsc.tf例題6のテストフィクスチャ countsc.tf

`timescale 1ns/1ns

module t;

reg clk,clr;

wire [3:0]count;

countsc m (.clk(clk),.clr(clr),.count(count));

// Enter fixture code here

initial begin clk=0;

forever begin

#50; clk=~clk;

end

end

initial begin

clr=1;

#125; clr=0;

#200; clr=1;

end

endmodule // t


例題6のテストフィクスチャ countsc.tf

clk

count

clr

countac

7.非同期クリア付きカウンタ

例題7 countac.v

module countac(clk,clr,count);

input clk,clr;

output [3:0]count; reg [3:0]count;

[email protected](posedge clkornegedgeclr) begin

if(!clr) count <= 0;

else count <=count+1;

end

endmodule

(1)非同期クリア付カウンタは,非同期クリアFFのクリア信号の

  書き方と,算術演算子+の応用であり,上の例の様にかける。

  順序回路なので代入には、ノンブロッキングを使った方が良い。

(小テスト)これにキャリー入出力を付けるには、どうすればよいか。


例題7のテストフィクスチャ countac.tf例題7のテストフィクスチャ countac.tf

`timescale 1ns/1ns

module t;

reg clk,clr;

wire [3:0]count;

countac m (.clk(clk),.clr(clr),.count(count));

// Enter fixture code here

initial begin clk=0;

forever begin

#50; clk=~clk;

end

end

initial begin

clr=1;

#125; clr=0;

#200; clr=1;

end

endmodule // t


8.ステートマシンの記述例題7のテストフィクスチャ countac.tf

例題8 state.v

module state(clk,a,res,ss);

input clk,a,res;

output [1:0]ss;

reg [1:0]ss;

parameter s00=2'b00;

parameter s01=2'b01;

parameter s10=2'b10;

parameter s11=2'b11;

[email protected](posedge clk) begin

if(~res) ss=s00;

else case(ss)

s00: if(a) ss=s01; else ss=s10;

s01: if(a) ss=s11;

s10: if(~a) ss=s11;

s11: ss=s00;

endcase

end

endmodule

S11

S01

S10

S00


例題7のテストフィクスチャ countac.tf1)verilogのステートマシン記述では,上の例の様に

  ステートの値は,parameterを使って,物理的な値を割り当てます。

(2)このステートマシンは,s00が初期状態で,

 入力 a=1なら s00 → s01 → s11  (但し,s01でa=0なら,s01のまま)

↑ │

└─────┘

 入力 a=0なら s00 → s10 → s11  (但し ,s10でa=1なら,s10のまま)

↑ │

└─────┘

と回るものです。case文を使えば,上述のようにすっきり書けます。

(3)ステートマシンには、出力値が

ステート値のみに依存するムーア型と

入力値とステート値に依存するミーリー型

がありますが、ここでは深くは述べません。


例題8のテストフィクスチャ state.tf例題8のテストフィクスチャ state.tf

`timescale 1ns/1ns

module t;

reg clk,a,res;

wire [1:0]ss;

state m (.clk(clk),.a(a),.res(res),.ss(ss));

// Enter fixture code here

initial begin

clk=0;

forever begin

#50; clk=~clk;

end

end

initial begin

res=0;a=0;

#100; res=1;

#700; res=0;a=1;

#100; res=1;

end

endmodule // t


9.トライステート出力例題8のテストフィクスチャ state.tf

例題9 triout.v

module triout(a,oe,y);

input a,oe;

output y;

assign y=oe? a: 1'bZ;

endmodule

oe

(1)トライステート出力、双方向バスの記述は実用的なLSIを

  設計する上でさけて通れない。

(2)1ビットのハイインピーダンスは1'bZと書く。

Zだけではローカル信号になるので注意。

8ビットは 8'bZZZZ_ZZZZ または 8'hZZ

(3)トライステート出力は,上の例の様に条件付assign文で記述する。

  トライステート出力はoutput宣言する。

(小問題)if文を使って、トライステート出力を記述しなさい。


例題9のテストフィクスチャ triout.tf例題9のテストフィクスチャ triout.tf

`timescale 1ns/1ns

module t;

reg a,oe;

wire y;

integer i;

triout m (.a(a),.oe(oe),.y(y));

// Enter fixture code here

initial begin

oe=0; #450;

oe=1; #500;

end

initial begin

a=0;

for(i=0;i<10;i=i+1)

#100 a=~a;

end

endmodule // t


rd例題9のテストフィクスチャ triout.tf

odb

idb

db

wr

10.双方向バスの記述

例題10 bidir.v

module bidir(rd,wr,db);

input rd,wr;

inoutdb;

wire idb;

reg odb;

assign idb=db;

[email protected](posedge wr)

odb<=idb;

assign db=rd? 1'bZ : odb;

endmodule

D Q

(1)双方向バスも,上の例の様に条件付assign文で記述する。

  双方向バスはinout宣言する。

(2)if文を使って書こうとしても、双方向バスはうまくいかない。


0 50 100 150 200例題9のテストフィクスチャ triout.tf

rd

rd_dt 前の値   rd↑時のdbの値

0 50 100 150 200

db wr_dt Z

wr

例題10のテストフィクスチャ 

bidir.tf

`timescale 1ns/1ns

module t;

reg rd,wr;

wire db;

reg rd_data;

bidir m (.rd(rd),.wr(wr),.db(db));

// Enter fixture code here

task wr_task;

input wr_dt;

begin

force db=wr_dt; #50;

wr=0; #50;

wr=1; #50;

release db; #50;

end

endtask

task rd_task;

output rd_dt;

begin

rd=0; #100;

rd_dt=db;

rd=1; #100;

end

endtask

initial begin

rd=1; wr=1; db=1'bZ;

#100; wr_task(1); rd_task(rd_data);

$display("time=%4d rd_data=%b",

$time,rd_data);

#100; wr_task(0); rd_task(rd_data);

$display("time=%4d rd_data=%b",

$time,rd_data);

end

endmodule // t


(1)タスクはテストフィクスチャで使用されるサブルーチン。(1)タスクはテストフィクスチャで使用されるサブルーチン。

(2)タスクはキーワードtaskで始まり、endtaskで終わる。

(3)キーワードtaskの次に、タスク名を書く。

  上の例ではでは wr_task と rd_task がタスク名。

(4)タスク名の次に引数宣言を行う。

wr_taskでは、入力引数wr_dt 

rd_taskでは、出力引数rd_dt

が宣言されている。

(5)上の例ではinitial文のメインルーチンから、

 wr_taskとrd_taskを2回づつコールして、

 データバスから1と0の書込み、読出しの確認をしている。


(6)双方向バスdbはテストフィクスチャ内では、ワイヤ宣言する。(6)双方向バスdbはテストフィクスチャ内では、ワイヤ宣言する。

(7)双方向バスdbの初期値=Zとする。(Zは代入可能)

(8)双方向バスdbにZ以外の値を代入するときは、force文を使う。

(9)強制代入を解除するときは、release文を使う。

(10)$displayはoutputウインドウに値を表示するための

  システムタスクであり、書式はC言語のprintf文と同じ。

  $timeは現在時刻を表すシステム関数。


Verilog設計演習(6)双方向バスdbはテストフィクスチャ内では、ワイヤ宣言する。Ⅳ  応 用 編広島県立西部工業技術センター


1.ストップウオッチの設計(6)双方向バスdbはテストフィクスチャ内では、ワイヤ宣言する。

 次の回路図のハードウエアを用意しています。

(問題1)

100Hzの方形波をカウントして、下記の仕様の4桁ストップ

ウオッチをVerilog-HDLで記述しなさい。

startスイッチを押すと、カウント開始

stopスイッチを押すと、カウント停止

両方同時に押すと、リセット

(問題2)

 startスイッチだけで、スタート、ストップ、リセットができる

仕様に変更しなさい。


①module digit(clk,res,cin,cout,led);(6)双方向バスdbはテストフィクスチャ内では、ワイヤ宣言する。

input clk,res,cin;

output cout;

output [6:0]led;

reg [3:0]dgt;

reg [6:0]led;

[email protected]( clk) begin

if( ) dgt<=0;

else if(cin && ( )) dgt<=dgt+1;

else if(cin && (dgt==9)) dgt<=0;

end

③assign cout=cin & ( );

[email protected](dgt) begin

case(dgt)

0: led=~7'h3f; 1: led=~7'h06;

2: led= ; 3: led= ;

4: led= ; 5: led= ;

6: led= ; 7: led= ;

8: led= ; 9: led= ;

default: led=~7’h00;

endcase

end

endmodule

①モジュールdigitはLED一桁に相当す

るサブモジュールで、カウンタ部と7セグ

メントデコーダ部で構成されています。

②カウンタ部はclkをクロック、resを正論

理の同期クリア信号とする4ビットカウン

タです。10進カウンタなので、9の次は

0に戻らなければなりません。

③キャリー入力が有り、かつカウント値が9の時、キャリー出力が出なければなりません。

④7セグメントデコーダ部は、カウント値を数字表示用データに変換する組合せ回路です。


digit4(6)双方向バスdbはテストフィクスチャ内では、ワイヤ宣言する。

digit3

digit2

digit1

enb4

enb3

enb2

enb1

⑤module watch1(start,stop,clk,led1,led2,led3,led4);

input start,stop,clk;

output [6:0]led1,led2,led3,led4;

reg [1:0]state;

wire dres,enb1,enb2,enb3,enb4;

⑤parameter reset=2'b00;

parameter count=2'b01;

parameter display=2'b10;

[email protected](posedge clk) begin

if(start & stop) state=reset;

else if(& ) state=count;

else if(& ) state=display;

end

assign enb1=();

assign dres=(state==reset);

⑥digit digit1(clk,dres,enb1,enb2,led1);

⑦digit digit2(clk,dres,,,led2);

digit digit3(clk,dres,,,led3);

digit digit4(clk,dres,,,led4);

endmodule

⑤モジュールwatch1がメインモジュールで

reset,count,displayの3つの状態を遷移する

ステートマシンです。条件は下記の通り。

startのみでcountへ

stopのみでdisplayへ

両方でresetへ

⑥digit1~digit4はそれぞれ

digit1 1/100秒の桁

digit2 1/10秒の桁

digit3 1秒の桁

digit4 10秒の桁

に相当するモジュールインスタンスです。

⑦enb1~enb4はdigit1~digit4のキャリ入力

とキャリ出力を接続するローカル信号です。


2.並列IOの設計(6)双方向バスdbはテストフィクスチャ内では、ワイヤ宣言する。

 下記仕様の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    PB

RD

WR    PC

DB   CR

RES

RESはPA,PB,PCを全て

入力モードにする負論理の

非同期リセット信号。


並列IO  pio.v(6)双方向バスdbはテストフィクスチャ内では、ワイヤ宣言する。

module pio(cs,rd,wr,adr,res,db,pa,pb,pc);

parameter n=8;

input cs,rd,wr,res;

input [1:0]adr;

inout [n-1:0]db,pa,pb,pc;

reg [n-1:0]qa,qb,qc,cr,odb;

/***** internal register (reset , cs & wr) *****/

[email protected](or) begin

if()begin

qa=0; qb=0;

qc=0; cr=8'hFF;

end

else if()case()

0:qa=db; 1:qb=db;

2:qc=db; 3:cr=db;

endcase

end

①qa,qb,qc,crはwrをクロック、

~resを非同期クリア信号とするFFで

csがアクティブの時、dbの値がadrで

選択されたqa,qb,qc,crのいずれか

に書き込まれる。


/***** port tri-state assign *****/(6)双方向バスdbはテストフィクスチャ内では、ワイヤ宣言する。

assign pa=()?qa:8'hZZ;

assign pb=()?qb:8'hZZ;

assign pc=()?qc:8'hZZ;

/***** data selecter *****/

[email protected](or or or or ) begin

case(adr)

0:odb=pa; 1:odb=pb; 2:odb=pc; 3:odb=cr;

endcase

end

/***** databus tri-state assign (cs & rd) *****/

assign db=(& )? odb:8'hZZ;

endmodule

②paは~cr[0]を制御信号とする双方向バッファ

pbは~cr[1]を制御信号とする双方向バッファ

pcは~cr[2]を制御信号とする双方向バッファ

③はpa,pb,pc,crをデータ入力

adrをセレクト信号

odbをデータ出力とする

  データセレクタ

④dbは~csと~rdの論理積を

制御信号とする双方向バッファ


PIOのテストフィクスチャ pio.tf(6)双方向バスdbはテストフィクスチャ内では、ワイヤ宣言する。

`timescale 1ns/1ns

module t;

reg cs,rd,wr,res;

reg [1:0]adr;

wire [7:0]db,pa,pb,pc;

integer i;

reg [7:0]rd_data;

pio m (.cs(cs),.rd(rd),.wr(wr),.adr(adr),.res(res),.db(db),.pa(pa),.pb(pb),.pc(pc));

assign pa=pb; // connect PB to PA

// Enter fixture code here

task wr_task;

input [1:0]adr_dt; input [7:0]wr_dt;

begin

cs=0; adr=adr_dt; force db=wr_dt; #50;

wr=0; #100;

wr=1; #50;

cs=1; adr=2'b11; release db; #50;

end

endtask


task rd_task;(6)双方向バスdbはテストフィクスチャ内では、ワイヤ宣言する。

input [1:0]adr_dt; output [7:0]rd_dt;

begin

cs=0; adr=adr_dt; #50;

rd=0; #100;

rd_dt=db;

rd=1; #50;

cs=1; adr=2'b11; #50;

end

endtask

initial begin

cs=1; rd=1; wr=1; adr=2'b11; db=8'bZZ; res=0; #50;

res=1; #50;

wr_task(3,1); //write CW to CR (PA=in PB,PC=out)

for(i=0;i<=255;i=i+1) begin

wr_task(1,i); // write to PB

rd_task(0,rd_data); // read from PA

$display("i=%x rd_data=%x",i,rd_data);

end

#1000; $finish;

end

endmodule // t


①module digit(clk,res,cin,cout,led);(6)双方向バスdbはテストフィクスチャ内では、ワイヤ宣言する。

input clk,res,cin;

output cout;

output [6:0]led;

reg [3:0]dgt;

reg [6:0]led;

[email protected](posedge clk) begin

if(res) dgt<=0;

else if(cin && (dgt!=9)) dgt<=dgt+1;

else if(cin && (dgt==9)) dgt<=0;

end

③assign cout=cin & (dgt==9);

[email protected](dgt) begin

case(dgt)

0: led=~7'h3f; 1: led=~7'h06;

2: led= ~7’h5b; 3: led=~7’h4f;

4: led= ~7’h66; 5: led=~7’h6d;

6: led=~7’h7d; 7: led=~7’h27;

8: led=~7’h7f; 9: led=~7’h6f;

default: led=~7’h00;

endcase

end

endmodule

解答例

watch1.v


⑤module watch1(start,stop,clk,led1,led2,led3,led4);(6)双方向バスdbはテストフィクスチャ内では、ワイヤ宣言する。

input start,stop,clk;

output [6:0]led1,led2,led3,led4;

reg [1:0]state;

wire dres,enb1,enb2,enb3,enb4;

⑤parameter reset=2'b00;

parameter count=2'b01;

parameter display=2'b10;

[email protected](posedge clk) begin

if(start & stop) state=reset;

else if(start & ~stop) state=count;

else if(~start & stop) state=display;

end

assign enb1=(state==count);

assign dres=(state==reset);

⑥digit digit1(clk,dres,enb1,enb2,led1);

⑦digit digit2(clk,dres,enb2,enb3,led2);

digit digit3(clk,dres,enb3,enb4,led3);

digit digit4(clk,dres,enb4,,led4);

endmodule


解答例(6)双方向バスdbはテストフィクスチャ内では、ワイヤ宣言する。  pio.v

module pio(cs,rd,wr,adr,res,db,pa,pb,pc);

parameter n=8;

input cs,rd,wr,res;

input [1:0]adr;

inout [n-1:0]db,pa,pb,pc;

reg [n-1:0]qa,qb,qc,cr,odb;

/***** internal register (reset , cs & wr) *****/

[email protected](posedge wr or negedge res) begin

if(~res)begin

qa=0; qb=0;

qc=0; cr=8'hFF;

end

else if(~cs)case(adr)

0:qa=db; 1:qb=db;

2:qc=db; 3:cr=db;

endcase

end


/***** port tri-state assign *****/(6)双方向バスdbはテストフィクスチャ内では、ワイヤ宣言する。

assign pa=(~cr[0])?qa:8'hZZ;

assign pb=(~cr[1])?qb:8'hZZ;

assign pc=(~cr[2])?qc:8'hZZ;

/***** data selecter *****/

[email protected](adr or pa or pb or pc or cr) begin

case(adr)

0:odb=pa; 1:odb=pb; 2:odb=pc; 3:odb=cr;

endcase

end

/***** databus tri-state assign (cs & rd) *****/

assign db=(~cs & ~rd)? odb:8'hZZ;

endmodule


ad