映像データを出力ポートに滞りなく書きこまねばならないのですが、どのくらいの速度でなければならないのでしょう。水平方向192ドットを、水平映像期間48μs=384クロックで出力するので、1ドット当たり2クロックにすればよいのです。
この速度はプログラムをいくら効率よく書いてもループ(分岐)を使った時点で達成はできません。分岐命令は、後方分岐(ループ)の場合それだけで2クロックを消費してしまうからです。そこで、ループを「展開する」ことにしました。ループを展開するというのは同じ命令をループの回数だけずらっと並べて書くということで、当然プログラムの容量は増大します。


ループの展開をすれば1ドット出力に2クロックを使うことができます。しかし2クロックしかありませんから、これとてもいくつかの工夫をしなくてはなりません。
- 汎用レジスタにあらかじめ映像データを用意しておく。
- 1つめのクロックでポート出力を完了させ、
- 次の1クロックで汎用レジスタ内の映像データを1ビット(左)シフトする。
また、出力命令のOUTは1クロックで完了するのですが、8ビットいっぺんに出力されます。8ビットマイコンなんで当たり前のことですね。その中の1ビットだけ出力したい(変化させたい)という場合、通常はポートを8ビットで読んで→狙ったビットをクリアし→狙ったビット以外の部分を0でマスクしたデータと論理和し→ポートに書き戻すとか、ビットクリア/ビットセット命令を分岐で使い分けたりと結構面倒なもので、とても1クロックで済むような話ではありません。
そこで、出力ポートの他のビットを無視すなわち未使用にすることにしました。そうすると面倒くさい1ビット書き換え処理が全く不要になり、単に8ビットいっぺんに出力するだけで済んでしまうのです。以前「映像出力がポートの最上位ビットであることと、同じポートの他のビットに出力が割り当てられていないことがとても重要」と書いたのはこのためだったのです。
これらを図で示すと下記のようになります。

8ビット分のループ展開(マクロ定義)
- .macro vout8px
- out PORTB, @0 ; +1=1 output bit7
- lsl @0 ; +1=2
- out PORTB, @0 ; +1=3 output bit6
- lsl @0 ; +1=4
- out PORTB, @0 ; +1=5 output bit5
- lsl @0 ; +1=6
- out PORTB, @0 ; +1=7 output bit4
- lsl @0 ; +1=8
- out PORTB, @0 ; +1=9 output bit3
- lsl @0 ; +1=10
- out PORTB, @0 ; +1=11 output bit2
- lsl @0 ; +1=12
- out PORTB, @0 ; +1=13 output bit1
- lsl @0 ; +1=14
- out PORTB, @0 ; +1=15 output bit0
- clr @0 ; +1=16 clear this segment for next timing
- .endmacro
24レジスタ分のループ展開
- vout8px r0 ; 16*24=384cycles(visible period)
- vout8px r1
- vout8px r2
- vout8px r3
- vout8px r4
- vout8px r5
- vout8px r6
- vout8px r7
- vout8px r8
- vout8px r9
- vout8px r10
- vout8px r11
- vout8px r12
- vout8px r13
- vout8px r14
- vout8px r15
- vout8px r16
- vout8px r17
- vout8px r18
- vout8px r19
- vout8px r20
- vout8px r21
- vout8px r22
- vout8px r23
- out PORTB, r23 ; 0+1=1 set to blank level
最後のOUT命令は描画が終わったら背景の黒レベルにもどす処理です。これをやらないと右端のドットが1だった場合、白い線が画面の右端までびよ~んと尾を引いてしまいます。