全速力で1ラインの映像を出力した後は、次のライン出力の出番が来るまでのつかの間にデータを仕込みます。ソースは"draw.asm"にあります。最初に判定すべきは何のデータを仕込まなければならないのかです。つまり次に何行目を走るのかで書きだすものを変える。大くくりでは、
- 1~10行目 → サイドライン(横一本ずっと白=「1」)
- 11~226行目 → コート内部(センターライン、スコア、ボール、パドル)
- 227~236行目 → サイドライン
- ;; --- prepare next raster ---
- cpi nxline, COURT_MIN; +1=2
- brlo sideline ; +1=3
- cpi nxline, COURT_MAX; +1=4
- brlo field ; +2=6
- ;; --- draw sidelines ---
- sideline: ; draw sideline
- filrast ; (+24)
- rjmp eol
次に何行目を走るのかはnxline(ここではR27と同義)に入っています。それがコート内部にあるかどうかの比較があって、外部であればサイドラインを書くべくfilrastを実行して終わりです。filrastはマクロで、汎用レジスタR0~R23の全ビットを1に立てるだけです。これは簡単。
コート内部だったら前出の通りサイドラインとボールとスコアとパドルのデータを用意しなくてはなりません。これらは排他的ではなくて、すべて書かなければならない状態もあり得ますから1つ書いてサヨナラというわけにはいきません。全部説明するのも冗長なのでここではまずボールを書く部分を。
- ;; --- draw ball ---
- .def pos =r24
- drawball:
- lds pos, Ballt ; +2=10
- cp nxline, pos ; +1=11 skip if (line > Ball_top)
- brlo drawpad ; +1=12
- addi pos, BAL_HEI ; +1=13
- cp pos, nxline ; +1=14 skip if (line < Ball_bot)
- brlo drawpad ; +1=15 / +2=16
- .def pattern =r26
- clr zh ; +1=16
- lds zl, Ballad ; +2=18
- lds pattern, Ballpt ; +2=20
- st z, pattern ; +2=22
- com pattern ; +1=23
- std z+1, pattern ; +2=25 (r24 can be written)
次の行nxlineがボールの上辺の位置Balltと下辺の位置Ballt+BAL_HEIの間にあるかどうかの判定が冒頭にあります。なければそこにはボールがないので書く必要がないということになり、次のパドルを書きに行きます。
ボールを書く場合、ボールのバイトアドレスBalladでレジスタ番号を指定し、ボールのビットパターンBallptをそのレジスタに書き込みます。ここがAVRのアーキテクチャの特徴をうまく使った部分で、レジスタがメモリアドレスのゼロ側にマップされていることを利用しています。つまり、メモリアドレス0x0000はR0を、0x001fはR31を指し示し、この例のようにZレジスタ間接などでもあたかもSRAMをアクセスしているかのごとしです。このようにできることはデータシートには書いてなくて(探しが足りなかったのかも)、実験してみたらできてしまってラッキーでした。こいつは便利だ。AVRすごい!
ボールのビットパターンを書くと言いましたが、ボールの幅が8ドット=8ビット、レジスタが8ビット単位なので(ほとんどの場合)2つのレジスタにまたがって書かなければなりません。この例ではまず指定されたレジスタに左側を書き、次のレジスタに右側を書いています。右側のパターンはちょうど左側のパターンのビット反転になっているのが分かりますでしょうか。(だからcom命令で反転しています)
ボールの形を書く

今回はこのくらいで。次はスコアの表示です。
そうそう、ソースアーカイブにレジスタマップ(regmap.txt)を入れておいたのを忘れていました。今Excelで開いてもう少し見やすくしたイメージを下に貼っておきます。
レジスタマップ

0 件のコメント:
コメントを投稿