MSX:ダブルバッファリング手法メモ
ダブルバッファリング : 画面の乱れを抑制するためのテクニック
Double buffering : Anti Flicker display technique.
githubにおいてあるメモからの転載
github.com
目次
という順番で、ダブルバッファリング手法についてメモしていきます。
Warning 👉 パレットテーブルを使わない!
カラーパレットテーブル という 邪魔者 VRAM全域を無駄なく使用したい場合には、配置を変更できないパレットテーブルが邪魔になります。
このメモは COLOR=(n,r,g,b) や COLOR=RESTORE などのパレット操作BASIC命令を使わない 前提で書かれていますので、もしこれらの命令を使用したい場合は、 各テーブルアドレスの配置に工夫が必要になります。
前置き
問題
毎フレーム画面を書き換えている場合、 VBLANK期間中に処理が収まらないと画面が乱れてしまいます。
特に、スプライトアトリビュートテーブルは おかしな位置におかしなスプライトが表示されるなど、 とても激しい乱れが発生します。
VDPの表示期間中に書き換えると、意図しない中途半端な状態で表示が実行されてしまうためです。
ですので、VRAM書き込みをVBLANK期間内に完了させる必要があるのですが、 実際に、VBLANK期間内に全てのVRAM書き込み処理を収めるのは非常に難しい事が多いです。
Note
スプライトの表示管理
SCREEN4以降のスプライトモード2では、スプライトアトリビュートテーブル+スプライトカラーテーブルへの書き込みが必要なので、 64バイト+512バイトをVBLANK期間内に転送する必要があります。
👉 この転送量はかなり厳しめです。 👉 turboRは理論上不可能となっています。
turboRではI/Oを使用したVRAM書き込みがMSX2+以前より遅くなっています ので、 スプライトアトリビュートテーブル+スプライトカラーテーブルの書き込みを VBLANK期間内に収める事が不可能 になってしまいました。
対処法
「表示切替 」または 「表示スワップ 」または 「ダブルバッファリング 」 と呼ばれる手法を使用します。
この手法を使うと、VBLANK期間外に書き込んでも表示が乱れないようになります。
VRAMの空き領域へ書き込み
書き込みが終わったら、書き込み終わった領域を表示ベースアドレスに設定する
表示に使用されていない領域に書き込みをすれば、表示期間中であっても表示に悪影響が起きません。
そして全ての書き込みが終わったら表示用アドレスを変更することで瞬時に表示が変化します。
(SCREEN5以降の裏ページ書き込み&表示切替テクニックもこの手法に該当します)
VDPはキャラクタ(グラフィック)やスプライトデータを表示する際に参照するVRAMアドレスを指定する機能があります。これをベースアドレス設定と言います。
ベースアドレスの種類は、スプライト(パターンジェネレータ、アトリビュート+カラー)、キャラクタ(パターンジェネレータ、パターンカラー、パターンネーム)などがあります。
→ ダブルバッファ手法のための基礎知識
利点
この手法の優れた点は、通常の処理からの追加コストが低い事です。
追加・変更は
書き込み開始VRAMアドレスの変更
書き込み完了後のVDPレジスタ書き込み(アドレス指定)
のみとなります。
処理の効率化によって、VSYNC待ちが少なく、VSYNC処理が軽くなります。
■ メインループ
メイン処理
VRAM書き込み
VSYNC処理完了待ち
■ VSYNC割り込み
VRAM書き込みまで完了していれば、表示ベースアドレス変更(一瞬)
BGM等の処理(タイミング安定)
ダブルバッファを使わない場合
■ メインループ
メイン処理
VSYNC処理完了待ち
■ VSYNC割り込み
メイン処理が終わっていれば、VRAM転送(VBLANK期間を超えると表示化け)
BGM処理(VRAM転送量によってもたつき)
副作用
表示期間中に切り替えても良いのですが、 表示期間中に切り替えるとそのラインを境に表示が切り替わるのでティアリングが発生します。
ティアリングが気になる場合は次のVSYNCを待ってから表示を切り替えます。 ただし、表示の反映が1フレーム遅れます。
また、VRAMの空き容量が必要になります。 VSYNCを待つ間に新しいフレームの描画を行いたい場合、 タイミングによっては、「表示中」「表示待ち」「裏で書き換え」の3つのバッファが必要になる可能性もあります。 (トリプルバッファリング)
基礎知識
テーブル名
内容
パターン ネーム テーブル
画面(X,Y)に表示されるキャラクタ コードのテーブル。
パターン カラー テーブル
キャラクタ コード毎の色テーブル または 画面座標毎の色テーブル
パターン ジェネレータ テーブル
キャラクタ コード毎のドット パターン テーブル
スプライト アトリビュート テーブル
スプライト番号毎の表示情報テーブル
スプライト カラー テーブル
スプライト番号毎の色テーブル
スプライト パターン ジェネレータ テーブル
スプライト パターン番号毎のドット パターン テーブル
各テーブルは、ベースアドレスをVDPへ設定することで、表示に使用するVRAMアドレスを変更できます。
ベースアドレスは画面モードによって、アドレスの設定単位に制限があります。
参考:MSX Datapack wiki計画 4章 V9938の画面モード
カラーパレットテーブル という 邪魔者
VRAMの空き領域をフルに使いたい場合、 (微妙な位置に配置され、移動もできない)カラーパレットテーブルが邪魔になります。
カラーパレットテーブルは本来VDPに必要な領域ではなく、 BASICのCOLOR=(n,r,g,b)命令やCOLOR=RESTORE命令でのパレット操作でのみ使用されます。
これらの命令を使わずに、VDPレジスタ操作で直接カラーパレット設定するようにすれば、 邪魔なカラーパレットテーブルを無視できるようになります。
デフォルトのベースアドレス
参考:MSX Datapack wiki - VRAMマップ
画面モード
パターンジェネレータ
パターンネーム
カラー/ブリンク
SCREEN 0 40行
$0800-$0FFF ($800)
$0000-$03BF($3C0)
なし
SCREEN 0 80行
$1000-$17FF ($800)
$0000-$03BF($3C0)
$0800-$090D ($19E)
SCREEN 3
$0000-$07FF ($800)
$0800-$0AFF ($300)
なし
SCREEN 1
$0000-$07FF ($800)
$1800-$1AFF ($300)
$2000-$201F ($20)
SCREEN 2
$0000-$17FF ($1800)
$1800-$1AFF ($300)
$2000-$37FF ($800)
SCREEN 4
$0000-$17FF ($1800)
$1800-$1AFF ($300)
$2000-$37FF ($800)
SCREEN 5/6 212行
なし
$0000-$69FF ($6A00)
なし
SCREEN 5/6 192行
なし
$0000-$5FFF ($6000)
なし
SCREEN 7/8 212行
なし
$0000-$D3FF ($D400)
なし
SCREEN 7/8 192行
なし
$0000-$BFFF ($C000)
なし
画面モード
スプライトアトリビュート
スプライトパターン
スプライトカラー
SCREEN 0
なし
なし
なし
SCREEN 3
$1B00-$1B7F ($80)
$3800-$3FFF ($800)
なし
SCREEN 1
$1B00-$1B7F ($80)
$3800-$3FFF ($800)
なし
SCREEN 2
$1B00-$1B7F ($80)
$3800-$3FFF ($800)
なし
SCREEN 4
$1E00-$1E7F ($80)
$3800-$3FFF ($800)
$1C00-$1DFF ($200)
SCREEN 5/6
$7600-$767F ($80)
$7800-$7FFF ($800)
$7400-$75FF ($200)
SCREEN 7/8
$FA00-$FA7F ($80)
$F000-$F7FF ($800)
$F800-$F9FF ($200)
※ SCREEN9はSCREEN5/6と同じ ※ SCREEN10/11/12はSCREEN7/8と同じ
ベースアドレスの設定可能な単位
参考:MSX Datapack wiki - V9938の画面モード
画面モード
パターンジェネレータ
パターンネーム
カラー/ブリンク
SCREEN 0 40行
$800
$400
なし
SCREEN 0 80行
$800
$1000
$200
SCREEN 3
$800
$400
なし
SCREEN 1
$800
$400
$40
SCREEN 2
$800
$400
$2000
SCREEN 4
$800
$400
$2000
SCREEN 5/6
なし
$8000
なし
SCREEN 7/8
なし
$10000
なし
参考:MSX Datapack wiki - VDP - レジスタの機能
スプライトモード
スプライトアトリビュート
スプライトパターン
スプライトカラー
スプライトモード 1
$80
$800
なし
スプライトモード 2
$400 * n + $200
$800
$400
BASICでの書き込み先の変更
アセンブラであれば書き込み先アドレスは任意で指定していますが、 BASICは各命令の書き込み先を変更する命令はSET PAGEしかありません。
ですが、ワークエリアの値を変更することでBASIC命令の書き込み先VRAMアドレスを変更できます。
⚠️ ただし、パターンカラーテーブルについてはBASICからの書き込み先変更方法がわかりません。
名称
アドレス
サイズ
内容
NAMBAS
$F922
2
現在のパターンネームテーブルのベースアドレス
CGPBAS
$F924
2
現在のパターンジェネレータテーブルのベースアドレス
PATBAS
$F926
2
現在のスプライトジェネレータテーブルのベースアドレス
ATRBAS
$F928
2
現在のスプライトアトリビュートテーブルのベースアドレス
👉 スプライトカラーテーブルはスプライトアトリビュートテーブルと連動します。 (スプライトアトリビュートテーブル - $200になる)
例)書き込み先パターンネームテーブルを&H2000にしたい場合は、POKE &HF922,0:POKE &HF923,&H20
スプライト表示
表示座標X、Y、表示パターン番号、表示色について、まとめて表示変更する場合。
スプライトモード1 - SCREEN1/2/3
スプライトモード1ではスプライトアトリビュートテーブルのみを操作すればよいので簡単です。
■ スプライトアトリビュートテーブル
レジスタ
bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
計算式
VDP R#5
A14
A13
A12
A11
A10
A9
A8
A7
(ad / $80) AND $FF
VDP R#11
0
0
0
0
0
0
A16
A15
ad / $8000
サイズは32*4=128で$80バイト。
ベースアドレスの単位は$80バイト。
ベースアドレスは パターンネームテーブルもダブルバッファにすることを考慮すると、$1B00と$1F00を使うのが楽ではないでしょうか。
$1B00 : R#5=$36,R#11=0
$1F00 : R#5=$3E,R#11=0
' ** BASIC SAMPLE **
' PG:ページ番号
' PG=0 : base address = &H1B00
' PG=1 : base address = &H1F00
VDP(5)=&H36+PG*8
VDP(12)=0
'※ VDP R#11 は BASICでは VDP(12)
' (VDP S#0 が VDP(8) なので以降は番号が1つずれる)
; ** ASM SAMPLE **
WRTVDP: equ $0047
;===============================================
; change sprite attribute base address
;===============================================
; in a = page no
; 0 : base address = $1B00
; 1 : base address = $1F00
CHG_SPRATR: add a,a
add a,a
add a,a ; a = PAGE * 8
add a,$36 ; a = $36 + PAGE * 8
ld b,a
ld c,5
call WRTVDP
xor a
ld c,11
call WRTVDP
ret
スプライトモード2
スプライトモード2の場合、スプライトカラーテーブルが別に必要で、データサイズが大きいのがネックになります。
■ スプライトアトリビュートテーブル
レジスタ
bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
計算式
VDP R#5
A14
A13
A12
A11
A10
1
1
1
((ad / $80) AND $FF) OR 7
VDP R#11
0
0
0
0
0
0
A16
A15
ad / $8000
サイズは32*4=128で$80バイト。
ベースアドレスは$200を先頭に$400単位。 → $200+$400 * n
■ スプライトカラーテーブル
サイズは32*16=512で$200。
ベースアドレスはスプライトアトリビュートテーブル - $200。
スプライトカラーテーブルはスプライト番号に対応して16バイトずつ。
Warning ※ スプライトパターン番号ではなくスプライト番号に対応する
スプライトモード2 - SCREEN4
VRAM 16KB($0000 ~ $4000)の範囲ではVRAMの空き領域がないので、ダブルバッファを確保することはできません。 ですが、MSX2以降の機能なのでVRAMは最低でも64KB($0000 ~ $FFFF)が使えます。
単純に+$4000するのが簡単かもしれません。
$1E00 : R#5=$3F,R#11=0
$5E00 : R#5=$BF,R#11=0
' ** BASIC SAMPLE **
' PG:ページ番号
' PG=0 : atr = &H1E00, color = &H1C00
' PG=1 : atr = &H5E00, color = &H5C00
VDP(5)=&H3F+PG*&H80
VDP(12)=0
'※ VDP R#11 は BASICでは VDP(12)
' (VDP S#0 が VDP(8) なので以降は番号が1つずれる)
; ** ASM SAMPLE **
WRTVDP: equ $0047
;===============================================
; change sprite attribute base address
;===============================================
; in a = page no
; 0 : atr = $1B00, color = $1C00
; 1 : atr = $1C00, color = $5C00
CHG_SPRATR: rlca ; a = a * $80
add a,$3F ; a = $3F + PAGE * $80
ld b,a
ld c,5
call WRTVDP
xor a
ld c,11
call WRTVDP
ret
スプライトモード2 - SCREEN5/6/9 (212ライン)
縦スクロールを使わない場合、 ピクセルデータが $0000 ~ $69FF の範囲だけなので、
$7200 : R#5=$E7,R#11=0
$7600 : R#5=$EF,R#11=0(デフォルト)
を使用することができます。
' ** BASIC SAMPLE 1 **
' PG:ページ番号
' PG=0 : atr = &H7600, color = &H7400
' PG=1 : atr = &H7200, color = &H7000
VDP(5)=&HEF-PG*8
VDP(12)=1 ' +&H8000
'※ VDP R#11 は BASICでは VDP(12)
' (VDP S#0 が VDP(8) なので以降は番号が1つずれる)
; ** ASM SAMPLE 1 **
WRTVDP: equ $0047
;===============================================
; change sprite attribute base address
;===============================================
; in a = page no
; 0 : atr = $7600, color = $7400
; 1 : atr = $7200, color = $7000
CHG_SPRATR: add a,a
add a,a
add a,a ; a = PAGE * 8
cpl ; a = -PAGE * 8
add a,$EF ; a = $EF - PAGE * 8
ld b,a
ld c,5
call WRTVDP
xor a
ld c,11
call WRTVDP
ret
スプライトモード2 - SCREEN5/6/9 (256ライン)
縦スクロールで256ライン全てを使う場合、 ピクセル表示だけで $0000 ~ $7FFF まで ページ0の範囲を全て使用してしまうので、 ページ0にスプライトテーブルを配置することができません。
この場合は、別ページにスプライトテーブルを確保します。
$B200 : R#5=$E7,R#11=1
$B600 : R#5=$EF,R#11=1(デフォルト+$8000)
' ** BASIC SAMPLE 2 **
' PG:ページ番号
' PG=0 : atr = &HB600, color = &HB400
' PG=1 : atr = &HB200, color = &HB000
VDP(5)=&HEF-PG*8
VDP(12)=1 ' +&H8000
'※ VDP R#11 は BASICでは VDP(12)
' (VDP S#0 が VDP(8) なので以降は番号が1つずれる)
; ** ASM SAMPLE 2 **
WRTVDP: equ $0047
;===============================================
; change sprite attribute base address
;===============================================
; in a = page no
; 0 : atr = $B600, color = $B400
; 1 : atr = $B200, color = $B000
CHG_SPRATR: add a,a
add a,a
add a,a ; a = PAGE * 8
cpl ; a = -PAGE * 8
add a,$EF ; a = $EF - PAGE * 8
ld b,a
ld c,5
call WRTVDP
ld a,1 ; +$8000
ld c,11
call WRTVDP
ret
スプライトモード2 - SCREEN7/8/9/10/11/12 (212ライン)
縦スクロールを使わない場合、 ピクセルデータが $0000 ~ $D3FF の範囲なので、
$FA00 : R#5=$F7,R#11=1(デフォルト)
$FE00 : R#5=$FF,R#11=1
を使用することができます。
' ** BASIC SAMPLE 1 **
' PG:ページ番号
' PG=0 : atr = &HFA00, color = &HF800
' PG=1 : atr = &HFE00, color = &HFC00
VDP(5)=&HF7+PG*8
VDP(12)=1 ' +&H8000
'※ VDP R#11 は BASICでは VDP(12)
' (VDP S#0 が VDP(8) なので以降は番号が1つずれる)
; ** ASM SAMPLE 1 **
WRTVDP: equ $0047
;===============================================
; change sprite attribute base address
;===============================================
; in a = page no
; 0 : atr = $FA00, color = $F800
; 1 : atr = $FE00, color = $FC00
CHG_SPRATR: add a,a
add a,a
add a,a ; a = PAGE * 8
add a,$F7 ; a = $F7 + PAGE * 8
ld b,a
ld c,5
call WRTVDP
ld a,1 ; +$8000
ld c,11
call WRTVDP
ret
スプライトモード2 - SCREEN7/8/9/10/11/12 (256ライン)
縦スクロールを使用する場合、 ピクセルデータだけで $0000 ~ $FFFF まで ページ0の範囲を全て使用してしまうので、 ページ0にスプライトテーブルを配置することができません。
この場合は、別ページにスプライトテーブルを確保します。
$1FA00 : R#5=$F7,R#11=3(デフォルト+$10000)
$1FE00 : R#5=$FF,R#11=3
' ** BASIC SAMPLE 1 **
' PG:ページ番号
' PG=0 : atr = &H1FA00, color = &H1F800
' PG=1 : atr = &H1FE00, color = &H1FC00
VDP(5)=&HF7+PG*8
VDP(12)=3 ' +&H18000
'※ VDP R#11 は BASICでは VDP(12)
' (VDP S#0 が VDP(8) なので以降は番号が1つずれる)
; ** ASM SAMPLE 1 **
WRTVDP: equ $0047
;===============================================
; change sprite attribute base address
;===============================================
; in a = page no
; 0 : atr = $1FA00, color = $1F800
; 1 : atr = $1FE00, color = $1FC00
CHG_SPRATR: add a,a
add a,a
add a,a ; a = PAGE * 8
add a,$F7 ; a = $F7 + PAGE * 8
ld b,a
ld c,5
call WRTVDP
ld a,3 ; +$18000
ld c,11
call WRTVDP
ret
スプライトパターンデータ書き換え
■ スプライト パターン ジェネレータ テーブル(参考用)
レジスタ
bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
計算式
VDP R#6
0
0
A16
A15
A14
A13
A12
A11
ad / $800
スプライトパターンジェネレータの切り替え手法はベースアドレスの変更ではなく、 スプライトパターンの数がスプライト同時表示可能数の2倍以上なのを利用して、 半分ずつ使用します。
16x16の場合パターン64個なので、 32個*2ページのパターンバッファとして扱い、 スプライト番号ひとつにつき表示パターン番号と作業用(非表示)パターン番号の2個を割り当てる。 という手法を紹介します。
全部を毎回書き換えても良いのですが、 32個のワークを用意して個別に表示に使用するパターン番号を管理するのが良いかと思います。
BASICでの例
前準備
パターンNを書き換えたら
表示例
PUTSPRITE P,(X(P),Y(P)),C(P),PT(P)
8x8の場合は、64番以降は固定パターンなどとするとよいかもしれません。
テキスト/キャラ表示
キャラクタコードテーブルのダブルバッファリングについて。
テキスト/キャラ表示 - SCREEN 0/1/2/3/4
※ SCREEN0はWIDTH40の場合。
■ パターン ネーム テーブル
レジスタ
bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
計算式
VDP R#2
0
A16
A15
A14
A13
A12
A11
A10
ad / $400
参考例)
画面モード
基本
裏
備考
SCREEN 0
$0000 : R#2=$00
$0400 : R#2=$01
追加で$1000 + $400 * n の 12個(計14個)
SCREEN 1
$1800 : R#2=$06
$1C00 : R#2=$07
$800 + $400 * n で 計12個
SCREEN 2
$1800 : R#2=$06
$1C00 : R#2=$07
空き領域に余裕がない
SCREEN 3
$0000 : R#2=$00
$0C00 : R#2=$30
$800 + $400 * n で 12個確保可能
SCREEN 4
$1800 : R#2=$06
$5800 : R#2=$16
スプライトと同じく +$4000 を使用する
テキスト/キャラ表示 - SCREEN 0 WIDTH80
■ パターン ネーム テーブル
レジスタ
bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
計算式
VDP R#2
0
A16
A15
A14
A13
A12
1
1
ad / $1000 OR 3
設定可能なアドレスは
$0000 : R#2=$03
$1000 : R#2=$07
$2000 : R#2=$0B
$3000 : R#2=$0F
ですが、 パターンジェネレータテーブルがあるので $1000 は使えません。$1000も使いたい場合は、パターンジェネレータテーブルを移動させてください。
パターン ジェネレータ テーブル を移動させる場合 候補は
$1800 : R#4=$03
$2800 : R#4=$05
$3800 : R#4=$07
になります。
Warning※ パターン ジェネレータに設定したアドレス-$800の位置はパターン ネーム テーブルには使用できません。
■ カラー(ブリンク) テーブル (SCREEN 0 WIDTH 80)
レジスタ
bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
計算式
VDP R#3
A13
A12
A11
A10
A9
1
1
1
ad / $40 OR 3
VDP R#10
0
0
0
0
0
A16
A15
A14
ad / &H4000
カラー(ブリンク)テーブルも座標に紐づけられているので、 こちらもダブルバッファにする場合があります。
候補は
$800 : R#4=$23, R#10=0
$A00 : R#4=$27, R#10=0
ビットマップ表示 - SCREEN 5/6/9
■ パターン ネーム テーブル
レジスタ
bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
計算式
VDP R#2
0
A16
A15
1
1
1
1
1
ad / $8000
BASICならSET PAGE命令で簡単に管理可能です。
ビットマップ表示 - SCREEN 7/8/10/11/12
■ パターン ネーム テーブル
レジスタ
bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
計算式
VDP R#2
0
A16
1
1
1
1
1
1
ad / $10000
BASICならSET PAGE命令で簡単に管理可能です。
キャラクタパターン書き換え
■ パターン ジェネレータ テーブル (SCREEN 0/1/3)
レジスタ
bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
計算式
VDP R#4
0
0
A16
A15
A14
A13
A12
A11
ad / $800
■ パターン ジェネレータ テーブル (SCREEN 2/4)
レジスタ
bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
計算式
VDP R#4
0
0
A16
A15
A14
A13
1
1
INT(ad / $2000) * 4 + 3
VRAMに余裕があるのはSCREEN 0, 1, 3 のみです。
SCREEN2/4はA12,A11は0扱いで、8KByte($2000)単位での指定になります。
SCREEN 4 は、VRAMが 64KB 以上あるので、割と自由です。
参考例)
画面モード
基本
裏
備考
SCREEN 0 width 40
$0800 : R#4=$01
$1000 : R#4=$02
余裕があるので良い感じに配置する
SCREEN 0 width 80
$1000 : R#4=$02
$1800 : R#4=$03
$800 + $1000 * n が安定
SCREEN 1
$3800 : R#4=$07
$3000 : R#4=$06
多少余裕あり
SCREEN 2
$3800 : R#4=$07
無理
空き領域に余裕がない
SCREEN 3
$3800 : R#4=$07
$3000 : R#4=$06
多少余裕あり
SCREEN 4
$3800 : R#4=$07
$7380 : R#4=$0F
スプライトと同じく +$4000 を使用する
■ カラー テーブル (SCREEN 1)
レジスタ
bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
計算式
VDP R#3
A13
A12
A11
A10
A9
A8
A7
A6
ad / $40
VDP R#10
0
0
0
0
0
A16
A15
A14
ad / $4000
SCREEN1の場合、カラーテーブルもダブルバッファにする事があるかもしれません。
8キャラ毎に色を設定するので、サイズは256/8=32で$20
設定単位は$40
候補は、
$2000 : R#3=$80, R#10=0
$2040 : R#3=$81, R#10=0
■ カラー テーブル (SCREEN 2/4)
レジスタ
bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
計算式
VDP R#3
A13
1
1
1
1
1
1
1
INT(ad / $2000) * $80 + $7F
VDP R#10
0
0
0
0
0
A16
A15
A14
ad / $4000
SCREEN2/4の場合はパターンジェネレータ同様に8KByte($2000)単位での指定。
SCREEN2では余剰領域が無さ過ぎて複数用意するのは厳しいと思います。
SCREEN4であれば+$4000を利用する等が考えられます。
SAMPLE - スプライトモード2 サンプル
Warning Sensitive Contets ※ R15注意 https://github.com/uniskie/MSX_MISC_TOOLS/tree/main/LOADSRD/samples/.sensitive/KUONAI
1ラインにスプライトが8個以上並んでも消えたままにならずに点滅するようにしたサンプル。
事例紹介
説明しようとした時のラクガキ
わかりづらい🤤