先週の実験では、Verilog を用いて組合せ回路を設計した。今週は順序回路の設計を学ぶ。また、複雑な順序回路設計を体験する。
Dフリップフロップはクロック信号線が立ち上がった(0から1へ変化した)瞬間の入力D の値を記憶する記憶素子である。Dフリップフロップの回路図を図1に示す。
図1. Dフリップフロップの回路図
Verilog において Dフリップフロップを記述したいとき、この回路図をそのまま assign 文で記述してはいけない。Verilog においてフリップフロップは手続きブロックを用いて記述される。図2 に Dフロップフロップの記述例を示す。
図2. Dフリップフロップの Verilog記述
入力信号値が変化した瞬間に出力信号値が変化する組合せ回路においては always に続く @(〜)には * 印を記述した。一方、クロックが立ち上がった瞬間にのみ出力値が更新されるフリップフロップを記述するときは、@(〜)にはキーワード posedge とクロック信号名を記述する。
図2の回路をシミュレーション実験で動作検証する。図3 のような入力波形を作成する。ここで、クロック信号 CLK と入力 D の変化するタイミングがずれている。これはクロック信号と通常の入力を同時に変化させることが許されていないからである。(理由は論理回路設計についてもう少し知識を深めれば分かるだろう。ここではそういうものだと納得して欲しい。)
図3. Dフリップフロップ検証用の入力波形図
図4 に検証用モジュール記述例を示す。クロック信号について、通常の入力信号と同様に、図3の波形図を実現するような代入文を initial ブロックの中に書いても良い。しかし、それでは面倒なので、図4ではもう少し簡単な書き方をしている。クロック信号はこのように記述されるものなので、このまま覚えてしまっても良い。図4では通常の入力信号値を記述する initial ブロックとは別に always ブロックを設けている。always ブロックは initial ブロックと並列に実行される。また、initial ブロックとは異なり、ブロックの最後まで実行終了するとブロックの最初に戻り、再度実行される。つまり、この場合、まず CLK = 1 が実行され、5 ns 待ち、CLK = 0 とし、5 ns 待つ。ここで always ブロックが終わっているので、always ブロックの最初に戻る。、以降、CLK = 1 とし 5ns 待つ、CLK = 0 とし 5ns 待つという動作を initial ブロック内の $finish が実行されシミュレーションが終了するまで延々と繰り返す。なお、always ブロックの最後に遅延 (#5) を記述することは文法上許されていない。そこで、遅延に続いて、何も実行しない空文 (セミコロンだけの文) を挿入している。
... always begin // always ブロックの始まり CLK = 1; #5 CLK = 0; #5 ; // 空文 end // always ブロックの終わり initial begin // initial ブロックの始まり D = 0; #19 D = 1; #10 D = 0; #20 D = 1; #21 $finish; end // initial ブロックの終わり endmodule |
図4. Dフリップフロップの検証用モジュール記述例
先週の組合せ回路の場合と同様、手続きブロックの中には if, case などを用いた複雑な処理を書くことができる。図6は長さ4ビットのシフトレジスタの記述例である。リセット信号 RST が 1 のとき、シフトレジスタの値は全零にリセットされる。RST が 0 のとき、値がシフトする。ただし、値の更新はクロック入力 CLK が立ち上がった瞬間にのみ行われる。
図6. 4ビットシフトレジスタの Verilog記述
リセット信号付き 5進カウンタを Verilog で記述せよ。
ここでは 32x32 モノクロ画像を加工するフィルタ回路を設計し、シミュレータ上で動作させる。サンプルプログラムと画像を用意したのでダウンロードすること。
ダウンロードしたアーカイブに含まれるファイル filter.v と testbench.v はサンプルプログラムであり、サンプル画像 lena.bmp を白黒反転し、その結果を lena_dest.bmp に出力する。回路図を図7に示す。この回路はファイル testbench に記述されたモジュール TESTBENCH からなる。TESTBENCH はモジュール FILTER を含む。モジュール FILTER は filter.v に記述される。
図7. サンプルプログラムの回路図
画像 lena.bmp は 32x32 の画像であり、モジュール FILTER には各クロック毎に1行32画素が入力 S00 〜 S31 より入力される。また、加工(白黒反転)された画像が1行毎に出力 D00 〜 D31 より出力される。ここで、Si, Di はそれぞれ左から i 番目の画素であり、0〜255 の 256調である。
モジュール FILTER は TESTBENCH 内に設けられた制御回路から与えられる制御信号によって制御される。RESET はリセット信号であり、シミュレーション開始直後は 1、まもなく 0 となり、シミュレーション終了まで 0 であり続ける。IN が 1 のとき、FILTER に画像が入力される。このとき、i 行目の画像が入力されているなら、ROW の値は i となる。画像は32クロック連続して入力される。全ての行を入力し終えたら IN は 0 となる。OUT は FILTER から出力される制御信号である。OUT が 1 のとき、FILTER から画像が出力される。 OUT が 32 回 1 を出力したとき、シミュレーションは終了する。なお、このプログラムは bmp 形式のデータ出現順通り、最下行から上へと順に処理を行う。
シミュレーションは以下の手順で行うことができる。まずは、プロジェクトを作成し、プロジェクトに filter.v と testbench.v を加える。続いてサンプル画像 lena.bmp を作成したプロジェクトのディレクトリにコピーする。シミュレーションを実行する。このとき、シミュレーションは 1000ns で途中停止する。そこで "Simulation → Run All" とし、シミュレーションを最後まで実行する。プロジェクトのディレクトリに白黒反転された画像ファイル lena_dest.bmp が作成されているはずである。
以下の課題では白黒反転フィルタ以外の処理を行う回路を作成する。基本的にモジュール FILTER にのみ手を加えればよく、testbench.v にはサンプル画像名以外に手を加える必要はない。また、FILTER のモジュール名、入出力名、バス幅を変更してはいけない。FILTER の出力値はクロックと同期させて変化させる必要がある。
OUT=1 が 32回出力されない限りシミュレーションは終了しない。よって、OUT が適切に変化しない FILTER を作成したとき、シミュレーションは永遠に終わらない。終わらなそうな時は "Simulation → Break" とし、速やかにシミュレーションを強制的に終了すること。強制終了時までのシミュレーション結果が表示されるので、デバッグ時の参考とされたい。
難波 一輝 (助教・伊藤・北神・難波研究室)
工学部1号棟4階409号室、内線3255、043-290-3255、namba@ieee.org