2019 年度大学入試センター試験 解説 数学Ⅰ・A2019 年度大学入試センター試験 解説 数学Ⅰ・A 第 問 9a −6a+1=(3a−1) ……ア,イ よって,A=
Verilog設計演習 Ⅰ 入 門 編...
description
Transcript of Verilog設計演習 Ⅰ 入 門 編...
1
Verilog設計演習
Ⅰ 入 門 編
広島県立西部工業技術センター
2
1.作業ディレクトリの作成
まず、エクスプローラを起動し、 ルートディレクトリの下にseminarというディレクトリを、 その下にVerilogというディレクトリを作成して下さい。
( DOS/V の場合)C:¥seminar¥Verilog
(98の場合)A:¥seminar¥Verilog
以下、Verilog演習で作成するファイルはVerilogの下に作ります。それ以外の、ディレクトリには何も作らないで下さい。
3
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
AB
CD
F
4
( 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 )わかりやすい様に ( ) を使ってよい。
5
クイックロジック社QuickWorks
論理合成Synplify
VerilogシミュレータSILOSⅢ
HDLエディタターボライタ
配置配線ツールSpDE兼 統合化環境
回路図入力SYNARIO
Verilog学習
VHDL学習
6
3.SpDEの起動 スタート - プログラム - QuickLogic ー SpDEでSpDEを起動します。
7
4.HDLエディタの起動
SpDEのツールバーから、HDLエディタのアイコン を押して、HDLエディタを起動し、クリエイトアイコン を押す。
8
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を指定し、論理合成ツールを起動します。
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
となり、最初のVerilogコードを満す回路が生成されていることが分かります。
r
s
p
q
入力s 出力r 0 p 1 q
※論理合成結果を確認したら、File-Saveメニューで結果を保存します。
16
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
ABCD
F
AB
CD
O
12.基本ブロック(続き) HDLエディタを起動し、aoi.vを次のように修正します。
17
(1)やや複雑な機能を記述する時は, wire で宣言した ローカル信号を使うこともできる。 ab,cd,o
(2)1ビット幅の wire は宣言なしでも使える。暗黙宣言。 後出の複数ビット幅の wire は宣言が必要。
(3) // は1行のみのコメント行。 /* ・・・・・ */ は複数行にわたるコメント行である。
修正が終わったらソースコードを保存し、論理合成をかけて配置配線を実行して下さい。結果は同じになります。
18
問題1 インバータLS04.vを設計し、結果を確認しなさい。 問題2 NANDゲートLS00.vを設計し、結果を確認しなさい。
問題3 NORゲートLS02.vを設計し、結果を確認しなさい。
19
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
g1g2 g3
SELB
FB
SELA
B
AOI F
20
(1) もっと複雑な回路記述には階層設計を使う。
(2) 階層設計は,複数のモジュール宣言と モジュールインスタンスで行う。
(3) 複数モジュールの宣言は, inv の様に,同一ファイル内に書いても良いし, aoi の様に,別ファイルに書いて, `include しても良い。
(4) モジュールインスタンスは,サブルーチンコールの様なもので,
モジュール名 インスタンス名 ( ポートリスト );
の形式で行う。上の例では, g1 , g2 , g3 がインスタンス名。
21
(5) モジュールインスタンスのポートリストは上位モジュールと 下位モジュールを接続するもので, g1 , g2 の様に,並びによる接続が一般的。 g3 の様に,名前による接続も使える。
(6) 出力信号を接続しない時はカンマを余分に書く。
(7) 上の例では selb と fb は,暗黙宣言された wire である。
※ ` はバック・シングル・クォートで DOSV では shift + @98 では shift + ^
shift + 7 ではないことに注意。
22
例題2を入力し、論理合成、配置配線を実行します。結果は、論理圧縮の効果で例題1より簡単になり、下図のようになります。
sel=1なら f=asel=0なら f=b
となっています。
a
b
sel
f
23
14.条件付きassign文例題3 セレクタ mux21.v module mux21(sel,a,b,f);
input sel,a,b;output f;assign f=sel ? a:b;
endmodule
selab
f
mux21
(1) 例題2 (mux2.v) では階層設計を説明するため,複雑な書き方を したが,セレクタ自体はもっと簡単に記述できる。( 2 ) assign 文にはC言語の3項演算子(条件演算子ともいう)に似た 条件付き assign 文があり,
assign 左辺= (条件式1 ) ? ( 右辺1 ) : ( 右辺2 );
が使える。(3)上の例では, sel=1 なら f=a , sel=0 なら f=b になる。
24
15.always文とif文例題3 セレクタ mux21.v module mux21(sel,a,b,f);
input sel,a,b;output f;reg f;
always@(sel or a or b) beginif(sel==1'b1) f=a;
else f=b;end
endmodule
selab
f
mux21
(1)3項演算子よりも,わかりやすい if 文もあるが, module-endmodule 間に,ダイレクトには記述できない。 上の例のように, always ブロックの中で記述する。
25
(2) always 文は always@( 信号名 ) begin : :end ←セミコロンがないのに注意
の形で記述し, ( ) 内の信号名の値が変化したときのみ評価される。つまり, ( ) 内には always ブロックとしての入力信号を記述する。正しくはセンシティビティ・リストという。 複数の入力信号が有る時は,カンマではなくor で区切って記述する。
(3) always ブロックで組合せ回路を生成する場合,入力信号を全てセンシティビティ・リストに記述しなければならない。 (順序回路の場合はそうとは限らない)
26
(4) 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です。
27
(7)最も重要なのは, always ブロック内での ・信号代入には, assign 文は使わないこと。・代入文の左辺にくる信号は,レジスタ宣言 しなければならないこと。
である。上の例では f がこれにあたる。
(8)上の例からわかる様に,生成される回路が組合せ回路で あってもレジスタ宣言が必要である。逆に言うと,レジスタ宣言 してもフリップフロップが必ず生成されるわけではない。
(9) if 文で全ての条件が列挙されていれば,つまり, if の数だけ else があれば,組合せ回路が, そうでなければ,順序回路が生成される。
例題3を入力し、論理合成、配置配線を実行します。結果は例題2と同じになります。
28
Verilog設計演習
Ⅱ シミュレーション編
広島県立西部工業技術センター
29
1.テスト・フィクスチャの準備
例題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
30
(1)timescale文はシミュレーションの時間単位を定めるもので、 /の前がこのモジュール内での時間記述#の時間単位、 /の後ろがシミュレーション時に使用される時間精度 になります。この例ではいずれも1nsになります。
(2)テストフィクスチャのモジュールには、ポートリストが有りません。 モジュール名は何でもかまいませんが、ここでは t です。
(3)元の設計データの入力信号は、このモジュール内では値を代入 するので、レジスタ宣言します。
(4)出力信号は観測するだけなので、ワイヤ宣言します。
(5)元の設計データをモジュールインスタンスとして、呼び出します。 信号の接続には、名前による接続が行われていますが、 並びによる接続でも構いません。
(6)この位置に、実際のテストパターン用コードを追加します。
31
`timescale 1ns/1nsmodule 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;
endendmodule // t
それでは、6行目の位置に右の四角の部分を追加してテスト・フィクスチャを完成させてから、mux21.tfとして保存して下さい。
この例で分かるように、テストフィクスチャでの信号値の代入には、initial文を使用します。 意味としては、sel,a,bの初期値として全て0を代入した後、100ns毎に異なる値を代入しています。
32
2.機能シミュレーション(Pre-Layout)(1)SpDEのツールバーから、シミュレータのアイコン を押して、SILOS3を起動します。 シミュレーションタイプでPre-Layoutを選択します。テストフィクスチャがmux21.tf、トップレベルモジュールがmux21.vになっていることを確認後、OKを押して下さい。
33
(2)mux21.vは論理合成のチェックを通っているので、エラーがあるとすればmux21.tfの方です。 エラーがあるとoutputウインドウにエラーメッセージが表示され、下の画面で停止するので、キャンセルを押します。 outputウインドウにエラーがなければ、(4)に進みます。
34
(3)エラーメッセージを確認後、SILOS3のFileーOpenメニューからmux21.tfを選択し、エラー箇所を修正します。 修正が終わったら、SILOS3のFile-Saveで保存し、
mux21.tfウインドウのアイコン化ボタン でアイコン化します。
Load/Reloadアイコン を押して、修正結果をSILOS3に反映させます。
outputウインドウにエラーが無ければ、GOアイコン を押して(4)に進みます。
outputウインドウにエラーが有れば、エラーメッセージを確認後アイコン化していたmux21.tfを通常の大きさに戻し、修正を繰り返します。
35
(4)テストフィクスチャにエラーが無ければ、下の画面で停止しますので、シミュレーション時間1000nsを入力し、OKを押します。
36
(5)エラーが無ければ、outputウインドウに32 State changes on observable nets.Simulation stopped at the end of time 1.000us. が表示されるのでデータアナライザのアイコン を押して、波形表示ウインドウを開きます。
37
次に、モジュールエクスプローラのアイコン を押して、t:tのa,b,f,selを選択後、マウス右クリックからAddSignaltoAnalyzerを選ぶと、波形が表示されます。
38
データアナライザ・ウインドウをアクティブにしてから、View-ZoomAllを選ぶと、波形全体が表示されます。sel=0の時f=b、 sel=1の時f=aを確認します。
39
(1)データアナライザ・ウインドウの時間軸上で、マウス右クリックし、timescaleを選んで、切りの良い値を入れれば、時間軸を見やすい値に変更できます。
(2)波形上でマウスを左クリックすると、青色の第1カーソル、右クリックすると、赤色の第2カーソルを置くことができます。各カーソルの時間および時間差がT1,T2,Tdeltaで表示されます。
(3)信号名を選択後、カーソルスキャン・アイコン を押すと、カーソルが選択信号の変化点に移動します。 この機能を使って、入力信号a,b,selと出力信号fの時間差を測定してみると、Tdelta=0になります。
これは、現在表示している結果が、遅延時間情報の入っていない機能シミュレーション(Pre Layout)であるためです。 結果を確認したら、SILO3のFile-Exitを選び、途中、「はい」を選んで終了します。
40
3.遅延シミュレーション(Post-Layout) 再びSpDEのツールバーから、シミュレータのアイコン を押して、SILOS3を起動します。 今度はシミュレーションタイプでPost-Layoutを選択します。テストフィクスチャがmux21.tf、 SDFがmux21.sdf、トップレベルモジュールがmux21.vq になっていることを確認後、OKを押して下さい。
41
1000nsを確認後、OKを押します。
42
outputウインドウに 92 State changes on observable nets.S imulation stopped at the end of time 1000.000ns. が表示され、モジュールエクスプローラ、データアナライザウインドウも表示されるので、ズームオール で波形全体を表示させます。
43
(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をエディタで開いて見て下さい。
44
遅延シミュレーションの結果
45
問題4 インバータLS04.vのテストパターンを設計し、 機能シミュレーションと遅延シミュレーションを
実行しなさい。
問題5 NANDゲートLS00.vのテストパターンを設計し、 機能シミュレーションと遅延シミュレーションを
実行しなさい。
問題6 NORゲートLS02.vのテストパターンを設計し、 機能シミュレーションと遅延シミュレーションを
実行しなさい。
46
4.ピン配置の指定 ピン配置は配置配線ツールが遅延時間や配線効率を考慮して最適に近いものに自動配置するので、これを使うのが無難です。 しかし、設計の最終段階に近く、プリント基板の変更ができない場合などは、次の方法でピン配置を直接指定することも可能です。 SpDEのTools-Optionsメニューから、BackAnnotationタブを選択し、FixPlacementのIOcellsをチェックonにします。
47
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";
48
論理合成Synplifyを立ち上げて、Addボタンを押します。ファイルの種類をPropertyFiles(*.sc*)にして、mux21.scpを選択し、「開く」を押します。
49
SourceFilesにmux21.scpが追加されたことを確認後、RUNを押して論理合成をかけます。 途中「はい」とOKを選択すると、mux21.scpで指定したピン配置での配置配線が実行されます。
50
Verilog設計演習
Ⅲ 基 礎 編
広島県立西部工業技術センター
51
1.ビット幅のある信号の表現
例題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;
always@(a or b) beginif(a==b) eq=1; else eq=0;if(a>=b) ge=1; else ge=0;if(a<=b) le=1; else le=0;
endendmodule
a
b
geeqle
4
4
comp
52
( 1 )今までは1ビット幅の信号だけ扱ってきたが, ビット幅のある信号も扱える。 input , output 宣言時に
[MSB:LSB] 信号名 , 信号名 ;
とすれば良い。 同じビット幅,ビットオーダーの信号は1行で宣言できる。
[15:0] [8:1][1:16] [0:7]
のいずれも使える。 MSB,LSB の値の大小にかかわらず, 左端が MSB ,右端が LSB である。
( 2 )ビット幅を変更しやすくするために parameter を使うことができる。
53
例題1の続き
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
a
b
geeqle
4
4
comp
( 3 )上の例の様に,コンパレータ等は if 文よりも assign 文の方がコンパクトに記述できる。
54
例題1のテストフィクスチャ comp.tf`timescale 1ns/1nsmodule 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) begina=i;for(j=0;j<16;j=j+1) begin b=j; #100; end
end endendmodule // t
(1)initial文の中ではinteger宣言した i 、jを用いたforループが使えます。i++ではないことに注意。
55
2.case文とビット幅のある定数例題2 デコーダ decoder.vmodule 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;endendmodule
decode
adr
enby
3
8
56
(1)デコーダは, if 文を並べて書くこともできるが,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; が無いとラッチが生成されるので注意。
57
例題2のテストフィクスチャ decoder.tf
`timescale 1ns/1nsmodule 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
initial beginenb=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
endendmodule // t
58
3.算術演算子と連接演算子例題3 アダー adder.vmodule 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;always@(a or b or cin) begin
{cout,s}=a+b+cin;end
endmodule
(1)加算器,減算器,乗算器を生成するのに算術演算子+、-、*が使える。 (2)加算結果には,キャリ出力がつきものであるが,連接演算子 { , } を使って
{cout,s}=a+b+cin;とわかりやすく記述できる。
adderab
cin
s
cout
44
4
59
例題3のテストフィクスチャ adder.tf
`timescale 1ns/1nsmodule 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 begincin=0;for(i=0;i<256;i=i+1) begin
{a,b}=i; #100;endcin=1;for(i=0;i<256;i=i+1) begin
{a,b}=i; #100;end
endendmodule // t
このテストフィクスチャでは連接演算子を使って、二重ループを一重ループで済ませています。
60
4.フリップフロップの記述例題4 フリップフロップ dff.vmodule 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 //always@(posedge clk)
q <= d;// sync clear ff //always@(posedge clk)
if(~sclr) qsc <= 0; else qsc <= d;
// async clear ff //always@(posedge clk or negedge aclr)
if(~aclr) qac <= 0; else qac <= d;
// enb ff //always@(posedge clk)
if(enb) qen <= d;endmodule
dclk
qac
aclr
非同期クリア FF
dclk
qsc
sclr
同期クリア FF
dclk
q通常 FF
dclk
qen
enb
イネーブル機能付 FF
61
(1)フリップフロップの生成には always@(posedge clk)
を使う。 clk 信号の立ち上がりエッジで always 文が実行される。 立ち下がり動作のFFには negedge を使います。
(2)同期クリア信号は, always@( 信号名)の センシティビティ・リストに記述しない。
(3)非同期クリア信号は,センシティビティ・リストに記述する。 aclrが正論理なら、 posedge を使います。
(4)イネーブル信号は同期クリア信号と同じ。
(5)この例で用いている <= はノンブロッキング代入文と呼ばれ, 順序回路では,これを使った方がよい。 = はブロッキング代入文と呼ばれ組合せ回路用。 但し,上の例では全て = にしても同じ回路が生成される。
62
例題4のテストフィクスチャ dff.tfmodule 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 beginclk=0;forever begin
#50; clk=~clk;end
end
initial beginaclr=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;
endendmodule // t
※クロック生成の無限ループには forever を使うことができる。
63
5.ブロッキング代入文とノンブロッキング代入文例題5 エッジ検出 edg.vmodule edg(clk,d,reset,rise,fall);input clk,d,reset;output rise,fall;reg q1,q2;
always@(posedge clk) beginif(!reset) begin q1=0; end else begin q1=d; end
end
always@(posedge clk) beginif(!reset) begin q2=0; end else begin q2=q1; end
end
assign rise= q1 & !q2;assign fall=!q1 & q2;
endmodule
riseclk
d q1 q2
fall
64
(1)スイッチが押された時,1回だけある動作をさせたい時など,入力信号の立ち上がり,立ち下がりを検出する手段として,図のようなエッジ検出回路が使用される。
( 2 )この rise,fall検出回路を1つの always 文で実現しようとすれば, <= ノンブロッキング = ブロッキング
の違いがわかる。上記の四角の部分は下記に置き換えられるが、<=の代わりに、=を使うと, q1 と q2 が同じになり, rise , fall も消える。
always@(posedge clk) beginif(!reset) begin q1<=0; q2<=0; end else begin q1<=d; q2<=q1; end
end
(3)ノンブロッキング<=は、各右辺の処理が終了してから代入処理が行われる。記述の順番に動作が影響されないので順序回路向き。
(4)ブロッキング=は、一つの代入処理が終了するまで次の処理が行われない。記述の順番に動作が影響される。組合せ回路向き。
65
例題5のテストフィクスチャ edg.tf`timescale 1ns/1nsmodule 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 begin clk=0;forever begin
#50 clk=~clk;end
end
initial beginreset=0; d=0;#75 reset=1;#200 d=1;#300 d=0;#400 d=1;#400 d=0;
endendmodule // t
66
6.同期クリア付きカウンタ例題6 countsc.vmodule countsc(clk,clr,count);input clk,clr;output [3:0]count; reg [3:0]count;
always@(posedge clk) beginif(!clr) count <= 0;else count <=count+1;
endendmodule
( 1 )同期クリア付カウンタは,同期クリアFFのクリア信号の書き方と, 算術演算子+の応用であり,上の例の様にかける。 順序回路なので代入には、ノンブロッキングを使った方が良い。
(小テスト)これを10進カウンタにするには、どうすればよいか。
4countclk
clr
countsc
67
例題6のテストフィクスチャ countsc.tf`timescale 1ns/1nsmodule 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 beginclr=1;#125; clr=0;#200; clr=1;
endendmodule // t
68
7.非同期クリア付きカウンタ例題7 countac.vmodule countac(clk,clr,count);input clk,clr;output [3:0]count; reg [3:0]count;
always@(posedge clk or negedge clr) beginif(!clr) count <= 0;else count <=count+1;
endendmodule
( 1 )非同期クリア付カウンタは,非同期クリアFFのクリア信号の 書き方と,算術演算子+の応用であり,上の例の様にかける。 順序回路なので代入には、ノンブロッキングを使った方が良い。
(小テスト)これにキャリー入出力を付けるには、どうすればよいか。
4countclk
clr
countac
69
例題7のテストフィクスチャ countac.tf
`timescale 1ns/1nsmodule 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 beginclr=1;#125; clr=0;#200; clr=1;
endendmodule // t
70
8.ステートマシンの記述例題8 state.vmodule 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;
always@(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;
endcaseendendmodule
a a
a
a
a
a
1
S00
S01
S11
S10
71
( 1 ) verilog のステートマシン記述では,上の例の様に ステートの値は, parameter を使って,物理的な値を割り当てます。
(2)このステートマシンは, s00 が初期状態で,
入力 a=1 なら s00 → s01 → s11 (但し, s01 で a=0 なら, s01 のまま) ↑ │ └─────┘ 入力 a=0 なら s00 → s10 → s11 (但し , s10 で a=1 なら, s10 のまま) ↑ │ └─────┘と回るものです。 case 文を使えば,上述のようにすっきり書けます。
(3)ステートマシンには、出力値がステート値のみに依存するムーア型と入力値とステート値に依存するミーリー型
がありますが、ここでは深くは述べません。
72
例題8のテストフィクスチャ state.tf`timescale 1ns/1nsmodule t;reg clk,a,res;wire [1:0]ss; state m (.clk(clk),.a(a),.res(res),.ss(ss)); // Enter fixture code here
initial beginclk=0;forever begin
#50; clk=~clk;end
end
initial beginres=0;a=0;#100; res=1;
#700; res=0;a=1;#100; res=1;
endendmodule // t
73
9.トライステート出力例題9 triout.vmodule triout(a,oe,y);input a,oe;output y;
assign y=oe? a: 1'bZ;endmodule
(1)トライステート出力、双方向バスの記述は実用的なLSIを 設計する上でさけて通れない。 (2)1ビットのハイインピーダンスは 1'bZ と書く。 Zだけではローカル信号になるので注意。
8ビットは 8'bZZZZ_ZZZZ または 8'hZZ(3)トライステート出力は,上の例の様に条件付 assign 文で記述する。 トライステート出力は output 宣言する。
(小問題) if 文を使って、トライステート出力を記述しなさい。
a y
oe
74
例題9のテストフィクスチャ triout.tf`timescale 1ns/1nsmodule t;reg a,oe;wire y;integer i; triout m (.a(a),.oe(oe),.y(y)); // Enter fixture code here
initial beginoe=0; #450;oe=1; #500;
end
initial begina=0;for(i=0;i<10;i=i+1)
#100 a=~a;end
endmodule // t
75
10.双方向バスの記述例題10 bidir.vmodule bidir(rd,wr,db); input rd,wr; inout db; wire idb; reg odb; assign idb=db;
always@(posedge wr)odb<=idb;
assign db=rd? 1'bZ : odb;endmodule
(1)双方向バスも,上の例の様に条件付 assign 文で記述する。 双方向バスは inout 宣言する。
(2) if 文を使って書こうとしても、双方向バスはうまくいかない。
rd
wr
db idb
odb
D Q
76
例題10のテストフィクスチャ bidir.tf`timescale 1ns/1nsmodule 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;
endendtask
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);endendmodule // t
0 50 100 150 200db wr_dt Zwr
0 50 100 150 200 rdrd_dt 前の値 rd↑時の db の値
77
(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の書込み、読出しの確認をしている。
78
(6)双方向バスdbはテストフィクスチャ内では、ワイヤ宣言する。
(7)双方向バスdbの初期値=Zとする。(Zは代入可能)
(8)双方向バスdbにZ以外の値を代入するときは、force文を使う。
(9)強制代入を解除するときは、release文を使う。
(10)$displayはoutputウインドウに値を表示するための システムタスクであり、書式はC言語のprintf文と同じ。 $timeは現在時刻を表すシステム関数。
79
Verilog設計演習
Ⅳ 応 用 編
広島県立西部工業技術センター
80
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桁ストップウオッチをVerilog-HDLで記述しなさい。
startスイッチを押すと、カウント開始stopスイッチを押すと、カウント停止両方同時に押すと、リセット
(問題2) startスイッチだけで、スタート、ストップ、リセットができる仕様に変更しなさい。
81
①module digit(clk,res,cin,cout,led); input clk,res,cin; output cout; output [6:0]led; reg [3:0]dgt; reg [6:0]led;②always@( clk) begin
if( ) dgt<=0;else if(cin && ( )) dgt<=dgt+1;else if(cin && (dgt==9)) dgt<=0;
end③assign cout=cin & ( );④always@(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セグメントデコーダ部は、カウント値を数字表示用データに変換する組合せ回路です。
82
⑤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;
⑤always@(posedge clk) beginif(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 のキャリ入力とキャリ出力を接続するローカル信号です。
digit4 enb4 digit3 enb3 digit2 enb2 digit1 enb1
83
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を全て入力モードにする負論理の非同期リセット信号。
84
並列IO pio.vmodule 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) *****/always@( or ) begin
if( )begin qa=0; qb=0; qc=0; cr=8'hFF;
endelse if( ) case( )
0:qa=db; 1:qb=db; 2:qc=db; 3:cr=db;
endcaseend
①①qa,qb,qc,cr は wr をクロック、~res を非同期クリア信号とする FF でcs がアクティブの時、 db の値が adr で選択された qa,qb,qc,cr のいずれかに書き込まれる。
85
/***** port tri-state assign *****/assign pa=( )?qa:8'hZZ;assign pb=( )?qb:8'hZZ;assign pc=( )?qc:8'hZZ;
/***** data selecter *****/always@( 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 の論理積を制御信号とする双方向バッファ
86
PIOのテストフィクスチャ pio.tf`timescale 1ns/1nsmodule 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 heretask 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;
endendtask
87
task rd_task;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;
endendtask
initial begincs=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;
endendmodule // t
88
89
①module digit(clk,res,cin,cout,led); input clk,res,cin; output cout; output [6:0]led; reg [3:0]dgt; reg [6:0]led;②always@(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);④always@(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
90
⑤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;
⑤always@(posedge clk) beginif(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
91
解答例 pio.vmodule 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) *****/always@(posedge wr or negedge res) begin
if(~res)begin qa=0; qb=0; qc=0; cr=8'hFF;
endelse if(~cs) case(adr)
0:qa=db; 1:qb=db; 2:qc=db; 3:cr=db;
endcaseend
92
/***** port tri-state assign *****/assign pa=(~cr[0])?qa:8'hZZ;assign pb=(~cr[1])?qb:8'hZZ;assign pc=(~cr[2])?qc:8'hZZ;
/***** data selecter *****/always@(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