いろいろとバタバタあって前回から だいぶ間が空いてしまったが,スプライトをさらに改良してみよう.
以下の機能を追加したい.
タイリングはキャラクタを画面いっぱいに敷き詰めて表示する機能で, 背景などを描くのに利用できる.反転は左右と上下が行えるようにする.
ただ前回のコードでは, y座標の計算をスプライト16個ぶん全部をベタで書いているので, 回路規模がでかくなっている.ここにさらにタイリングの処理とかも入れると, さらに規模がでかくなってまた論理合成できなくなったりすると困る (というのもあるが,コードをいろいろいじくるときに,16個ぶんを触るのは ひじょーにめんどくさい,というのもある)ので, なんとか縮小化したい.y座標の計算はHSYNCの間に行っているので, 計算回路を独立させて16個のスプライトぶんの計算をクロックに合わせて 順次行うようにすることで,回路を共通化できるように思う.
で,作成したのがこんな感じ.
sprite.v
ycalc.v
memory.v
rx.v
s3astarter.ucf
y座標の計算を ycalc.v としてモジュール化して独立させている. ycalc.v はy座標の情報を与えると1クロックかけてそのキャラクタが有効か無効か (その行の上に存在しているかどうか)を判断し, 有効ならばイネーブルフラグを1にして,読み込むべきアドレスを返す (無効ならばイネーブルフラグをゼロにして返す). さらに次のクロックでメモリモジュールからデータを読み込む. これらの動作を16スプライトぶんだけ,パイプライン状に順次行う. 前回のコードと比べてずいぶんすっきり.
memory.v はx,y方向の反転情報(rx,ry)を受け取り,それに応じてデータを反転させて 返すように改良している.これらの反転処理は sprite.v の中で行うことも できるけど,memory.v でやってしまったほうがすっきりしそうだし, memory.v に rx,ry を渡すだけならば回路規模も小さく済みそう (sprite.v の内部でキャラクタごとに行うと16個ぶんの処理が必要. memory.v の内部で行うならば1個ぶんの処理で済む.回路を共通化していることの メリットなわけだ).
実はついでに回転も考えているのだが,ひとまず実装していない. あと rx.v にはとくに変更は無い.
テストプログラムは3種類を用意した.
まず,反転表示を試してみる.スタータキットを起動してダウンロードし, FreeBSDのPC上で reverse.c をコンパイルし実行.
左右,上下の反転ができている.よしよし.
次にタイリングのテスト.tiling.c をコンパイルし実行.
ちょっとわかりにくいのだけど,一番左上のキャラクタがタイリングされて 画面じゅうに敷き詰められている.
これは拡大したところ.うまく重ね合わせができている. ちなみにタイリングは画面全体だけでなく,x方向のみとかy方向のみ 行うこともできる.
デモを実行してみる.
川(?)の上をキャラクタがてきとうに動くようなかんじ. とりあえずちゃんと動いているようだ.
ところで今回書いてみて気づいたことなのだけど, y座標の計算に関してはHSYNCの間に順次行うことでモジュールを 共通化できるのだけど,x座標の計算に関してはそうはいかない. なぜならスプライトのキャラクタは重ね合わせが行われるが, 基本的にはすべてのキャラクタの計算をドット毎に行わなければならないため, x座標の計算に関してはすべてのキャラクタぶんを同時に行う必要があるからだ (実際には遅延が積み重ならないように,sprite.v では16個ぶんをずらして パイプライン化しているが,同時に16個ぶんを行っていることに変わりは無い). ということでx座標の計算に関しては共通化できないのだけれど, これはスプライト数を増やしたいときに回路規模が膨れ上がる原因になってしまう. このためたとえばスプライト数128個とかの実現が難しくなってしまう. (ついでにいうならパイプライン化のための先読みクロック数が多く必要に なってしまい,HSYNCの間だけでは間に合わなくなってしまうかもしれない)
で,この対策として,以下のような方法が考えられる.
このようにバッファをキャラクタ数ぶん用意するのではなく, 4個とか少なめに用意することで,x座標の計算ロジックをキャラクタ数ぶん 用意する必要が無くなるので,回路を大幅に節約できる. もうすこし回路を工夫すれば,スプライト数を増やしたい場合にも, キャラクタ情報の保存用メモリを増やすだけでほぼ済むようになるかもしれない. それならば,スプライト数128個とかも実現可能だろう.
しかしこの方法,すぐにわかることだが,横方向にバッファ数以上のキャラクタが 並ぶと,優先順位の低いキャラクタは(その行だけ)表示されないことに なってしまうのだな.
よく知らないのだけどその昔MSXでは,横方向に5つ以上(だっけ?) のキャラクタが並ぶと表示されなくなるといった仕様があったらしい. きっとこんなようなことが原因になっているんだろうなあ,と思う.
えーと,スプライトはこのへんでとりあえずひと段落かな. 次はちょっと他にやりたいことがあるので,そっちをやろうかな.