やる気が出てきましたので調べました。
このシーンの初期化命令は $da42 から始まり、 $da7f から vblank 割り込みを経由したループになっています。今回の逆アセンブルはコメントの冒頭に数値がついたら CPU cycle となります。
loop のメイン処理
DA7F: jsr $DAD2 ;sequece end, wait vblank interrupt ;wait renderring start line ldx $10 ;3, skip line count DA84: ;uses 114 cycle (last 113 cycle) / loop jsr $DAF4 ;6 + 103 cycle dex ;2 bne $DA84 ;3 or 2 ;color -> monochrome renderring line ldx $11 ;3, effective line count DA8C: ;uses 116 cycle (last 115 cycle) / loop jsr $DAFF; 6+ 57 + 42 (monochorme) + 6 cycle dex ;2 bne $DA8C ;3 or 2
loop 開始
$dad2 は renderring frame の終了処理, vblank interrupt の割り込み待ちが入っています。スクロールレジスタの bit0 を毎フレーム 0 か 1 に切り換えているのは、画面をぶるぶるさせているものと思われます。
;renderring squence end, wait vblank DAD2: ;generate noice sound? lda $11 lsr a lsr a lsr a ora #$30 sta $400C sta $4004 ;update scroll register and #$01 eor $1F sta $2005 ;scroll register port ;wait next vblank interrupt jsr $FE00 lda #$02 sta $4014 ;sprite dma register ldy #$06 DAF0: dey bne $DAF0 rts
割り込み処理
jsr $fe00 の先は、無限ループ -> 割り込み発生 -> jsr $fe00 から戻ってくるとなります。3回の pla は割り込み発生アドレス ($fe00) を破棄するために pop を 3回やってから、 rti ではなく rts を使っています。
FEEE: jmp $FEEE FECF: lda $FF FED1: sta $2000 FED4: lda $2002 FED7: pla FED8: pla FED9: pla FEDA: rts
表示調整待ち
jsr $DAF4 を伴う最初の小ループはライン単位の時間つぶしです。$da84 から次の $da84 までの消費サイクル数は私が数えたら 114 でした。解析文書によると1 line 当たりの消費サイクル数は 113.66 (1364/12) らしいので、CPU レベルの精度では適切な設定値だと思われます。
;2+ (2+3) * 0x11 + 2+2 = 91 DAF4: ldy #$12 ;2 DAF6: dey ;2 bne $DAF6 ;3 or 2 ;2 + 2 + 2 + 6 nop ;2 nop ;2 nop ;2 rts ;6
$2005 への頻繁な書き込み
jsr $DAFF を伴う2つ目の小ループは color/monochrome レジスタを切り換えるループで、モノクロになってる期間は 36 cycle です。この小ループの消費サイクル数は 116 で、ライン単位待ちより 2 cycle 多いです。このため、発生する時間が1ラインあたり 2 cycle ずれるので、1ラインあたりで右に約 1 pixel ずれたモノクロ領域が出せるものと思われます。
このループで消費サイクルを 114 にしたら長方形のモノクロ領域が表示できるかもしれません。CPU から pixel 単位の計測は精度が粗いので、途中でずれる可能も多々あり、斜めにする方が違和感がないのかもしれません。
PAL 版の FF1 が存在するかは知りませんが、仮にあった場合は消費サイクル数を 106.57 (1598/15) に合わせて調整されていると予想されます。
DAFD: nop nop ;switch monochrome/color register ;2+ (2+3) * 9 + 2+2 = 51 DAFF: ldy #$0A; 2 DB01: dey ;2 bne $DB01 ;3 or 2 ;2+4 = 6 lda #$1F ;2 sta $2001 ;4, monochrome, display sprite and tile layer ;2*3 = 6 ldy #$1E ;2 nop ;2 nop ;2 ;6*4+2*3+6 = 36 jsr $DB19 ;6+6 jsr $DB19 ;6+6 nop ;2 nop ;2 nop ;2 sty $2001 ;6 color, display sprite and tile layer DB19: rts ;6
6502 のブランチ命令 (ここでは bne) は分岐発生時に 3 cycle, 分岐なしで 2 cycle となりますが、分岐先のアドレス bit15:8 が異なると 4 cycle かかります。
$DAFD での2つの nop はこれが発生しないように調整しています。これがないと 分岐先が $DAFF, 分岐元が $DB01 になりますから、ここまで気を利かせてるんですね。すごいや Nasir.
というわけで、0番スプライトも使わずに計算してました。Vblank 割り込みの実装も無茶ですな。