FPGAでライフゲームを作りました


動画の内容

  • ランダムに初期化(see 線形帰還シフトレジスタ - Wikipedia)
  • しばらく実行(高速モード:1ステップ3msec。VGA60Hzの画面の更新が17msecなので画面1回更新されるごとに5ステップ進んでいる計算)
  • 画面をクリア、低速モード(256倍遅い)に移行
  • Rペントミノを配置するボタンを押す
  • しばらく走らせる
  • 高速モードに変える

実装

  • 読み書き用のアドレスをインクリメントする
  • 2行+3マス文の323bitのシフトレジスタに読んだデータをpushする(see シフトレジスタ - Wikipedia)
  • シフトレジスタの0, 1, 2, 160, 161, 162, 320, 321, 322の9ビットを束ねてアドレスとし、ライフゲームのルールがハードコードされた512bitのROMから1bit読む
  • 読んだ値をVRAMに書き込む

各1クロックでできるかな〜と思ったけども、画面が流れるバグ(おそらくアドレス計算が間に合わなくて1つずれたところに書き込んだと思われる)が起きたので今は各2クロックで動かしている。

なので今は 1ピクセルあたり8クロック * 160x120ピクセル / 50MHz で画面1回更新するのに3msecということになる。頑張ればもっと縮む可能性がある。

消費したリソースは、ロジックエレメントが459個(3%)、メモリが57912bit(11%)とのこと。あと9倍くらい余裕があるから、解像度を2倍にしてピクセル数を4倍にするくらい行けそうだけど、この問題をどうやって解決するか: DE0でFPGAのチップ内蔵RAMをVRAMに使おうとしたら上手く行かなかった日記

ソースコード

Verilog HDL素人が書いたソースコードはこちら: https://github.com/nishio/fpga/blob/master/lifegame.v

ちなみにさっき知ったんだけど、Verilog HDLにもfor文があるみたいですよ。(えっ

追記

さすがに酷いので単純なシフトレジスタはfor文を使って書き換えました。512行のルールテーブルは何とかならないかな。

追記

シフトレジスタの実装について、こんなことしなくても

for(i = 0; i < 322; i = i + 1) begin
	buffer[i + 1] <= buffer[i];
end

この1行でいいじゃん、という指摘を頂きました(thanks @natutan!)

buffer[1:322] <= buffer[0:321];

たしかに…それができることは知っていたのになぜ思いつかなかったか…。たぶん僕の脳の中ではまだC言語の配列みたいなイメージで捉えられているのだろうなぁ。だから「要素が323個ある配列」を1個ずらすことが「代入文1つでできる」という発想を思いつくことができなかった。