今回はTile Graphicsのサンプルを動かす
以下の本を読みつつ進めているFPGAでゲーム機をつくろう日記。前回はmoving ballというサンプルを実装して動かしてみて、だんだんゲームっぽくなってきた。今回は本の15章「Tile Graphics」の内容をZybo向けにカスタマイズして動かしてみた。
以下が実際に動かしてみた動画。
やっとTile Graphicsのサンプルが動いた。なんとなく映画のマトリックスっぽくてかっこいい。実機で綺麗に出力するためにROMのbitmap書き換えたり、LFSRの疑似乱数で数字を変えたりと手間はかかったが、Verilogだけでやるというのが面白い。次はいよいよ簡単なゲーム機作成に挑戦。今日は寝る #FPGA pic.twitter.com/eQCa0iMPS8
— Wakky (@wakky_free) September 16, 2020
今回のサンプルのプロジェクトは以下で公開している。ただ、LFSRの疑似乱数を発生するRTLはネット上のものを使わせてもらったが、ライセンスが不明でそのままGitHubに上げるわけにもいかない。そのため、今回はGitHubにはLFSRのコードのダミーファイルを置いておいたので、このプロジェクトを使う場合はReadmeに記載したコードの掲載先URLのコードで、ダミーファイルの中身を上書きしてください。もちろん自分で作るか、別のLFSRのコードを使ってもOK。
https://github.com/WakkyFree/FpgaGameConsole/tree/master/TileGraphics
tclファイルからプロジェクトを生成する方法はこちら。
いつものごとく、日記ではポイントだけ絞ってメモしていきます。
開発環境
Windows 10
Vivado 2020.1
Zybo(Zynq-7000)
hvsync_generator.v、detect_edge.v、MMCM IP、ピンアサインは前回と同じ
前回のMoving Ballのプロジェクトとhvsync_generator.v、detect_edge.v、mmcmのIP(clk_vga_25m)、ピンアサイン情報が記述された制約ファイル(game_console.xdc)は前回と同じ。今回変更&追加したのは
- zybo_top.v
- digit10_case.v
- lfsr.v(こちらはリンク先のVerilogコードを使用させて頂きましたm(_ _)m)
- RAM_sync.v
- test_ram1_top.v
の5つのVerilogコード。ball_absolute_top.vのベースはこの本のサンプルコード。例のごとくこのまま移植してもうまく動かなかったので、test_ram1_top.v(サンプルだとファイル名がchardisplay.vとなっていたがmodule名の定義はtest_ram1_topだったので、VivadoのSynthesis通すためにファイ名を変更)とdigit10_case.vを変更した以下では変更のポイントを書いていく。
zybo_top.vの変更箇所
こちらは前回のball_absolute_topをtest_ram1_topのモジュールに変更しただけ。そのほかは変更なし。
test_ram1_topのポイント
ベースになっているのはエミュレータのchardisplay.vというソースコードの中のtest_ram1_topのモジュール。細かい部分の解説は省くが、ポイントは2つある。
ソースコードの上から順番に見ていく。まず1点目は、以下のようなカウンターを用意し、87行目でカウンターが15になったタイミングで文字が切り替わるようにしていること。
always @ (posedge clk) begin if (reset) counter <= 4'd0; else if (v_rise) counter <= counter + 4'd1; end
画面上の数字は、RAMへの書き込みタイミングを変えて切り替えているが、カウンターを入れないと文字が高速で切り替わりすぎて、綺麗に文字が見えなかったためこのようにした。15というのは適当に決めた数値なので、もっと早く切り替えたければ15より小さい値を、もっと遅く切り替えたければ15より大きい値(ただしこの場合はcounterのビット数を大きする必要があるので注意)にすればよい。
2点目は、画面上の表示をランダムっぽく切り替えるためにLFSR(線形帰還シフトレジスタ)のRTLを使用して疑似乱数を発生させて、数字を切り替えていること。
lfsr #(.NUM_BITS(8)) lfsr_inst (.i_Clk(clk), .i_Enable(1'b1), .i_Seed_DV(1'b0), .i_Seed_Data({8{1'b0}}), // Replication .o_LFSR_Data(lfsr_adrs), .o_LFSR_Done() );
もともとのコードだとあまりきれいに数字がバラけて表示されなかったため、今回は疑似乱数を発生させてRAMにwriteするデータを変えている。LSFRについてはググって頂きたいが、今回はRTLは自作せずに冒頭でも紹介したこちらのコードを使用させて頂いた。
digit10_case.vのポイント
digit10.case.vも元々のコードから少しだけ変えている。このコードの中では、モニターに表示される0~9の各数字のビットマップが定義されているのだが、サンプルコードのままだと、モニターに表示したときに隣の数字とくっついて表示されてしまって何が表示されているのかわからない状態になっていた。
どのように変えたかはサンプルコードとGitHubに上げているコードを見比べればわかると思うが、各数字でのbitsのLSBとMSBを0にして、モニターに表示した時に隣の数字と必ず間隔があくようにしている。
動かしてみた
プロジェクトをsynthesisとimplementationしてGenerate bitstream後にFPGAに書き込んで動かすと、最初にのせた動画のように数字が画面上で良い感じに入れ替わるように表示できた。
次回だが、例のごとく16~18章はあまり動きが無いので実機での実装はやらずに読み流して、19章のRacing Gameを実装してみたいと思う。これができれば一応日記の目的であるFPGAでゲーム機をつくるという目的は果たせるかな。
FPGAでゲーム機をつくろう日記まとめ
この日記は以下でまとめています。