Created
March 5, 2022 06:28
-
-
Save ueno1969/db4c2ebfe354bb1df3074f6fab9f1a21 to your computer and use it in GitHub Desktop.
PC 8001 Z80 カラードットスクロール 処理部
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;============================== | |
; 描画関連 | |
;============================== | |
initVram: | |
ld hl, Vram.topAddr2 | |
ld (NextVramAddr), hl | |
ret | |
; 現在のスクロール位置を元に、指定した文字位置のMapVramアドレスを得る | |
; Input | |
; HL=MapVramのTopアドレス | |
; C=何文字目かの指定 | |
; Output | |
; HL=MapVRAM上のアドレス | |
; BC=ずれ位置 | |
getMapVramPos: | |
ld a, (vMapOffset) | |
add a, c | |
and MapVram.lineMask | |
ld c, a | |
ld b, 0 | |
add hl, bc | |
ret | |
; ================================================= | |
; MapVram1のスクロール位置右端に次マップデータを書く | |
; ================================================= | |
setRightMapNormalData: | |
; 65 + 51 * 25 - 5 = 1585 | |
ld hl, MapVram1.top | |
ld c, MapVram.lineSize - 1 | |
call getMapVramPos | |
; hl = 次のMapVramの右端 | |
ld de, NextMapByteData | |
ld bc, MapVram.next | |
; hl = マップVRam書き込み位置 | |
; de = 次データワーク | |
; bc = 次の行へのずれバイト数 | |
ld ixh, ScrHByte | |
.loop | |
ld a, (de) | |
inc de | |
ld (hl), a | |
add hl, bc | |
dec ixh | |
jr nz, .loop | |
ret | |
; ================================================= | |
; MapVram2のスクロール位置右端に次マップデータ | |
; シフトデータを書く | |
; ================================================= | |
; setRightMapShiftData2: | |
; ; 56 + 94 + 103 * 25 - 5 = 2720 | |
; ld hl, MapVram2.top | |
; ld c, MapVram.lineSize - 1 | |
; call getMapVramPos ; 右端を得る | |
; ld iy, MapVram1.top | |
; add iy, bc | |
; ld bc, MapVram.next | |
; ld de, NextMapByteData | |
; ; iy=MapVram1 スクロール端 | |
; ; hl=MapVram2 スクロール端 | |
; ; de=次データワーク | |
; ; bc=次の行へのずれバイト数 | |
; ld ixh, MapVram.lines | |
; .loop | |
; ld a, (iy + 0) | |
; ld (hl), a | |
; ld a, (de) | |
; rrd | |
; add hl, bc | |
; add iy, bc | |
; inc de | |
; dec ixh | |
; jr nz, .loop | |
; ret | |
setRightMapShiftData: | |
; 104 + 88 * 25 - 5 = 2299 | |
ld h, MapVram2.top / 256 | |
ld d, MapVram1.top / 256 | |
ld a, (vMapOffset) | |
add a, MapVram.lineSize - 1 | |
and MapVram.lineMask | |
ld l, a | |
ld e, a | |
push de ; MapVram1 | |
ld bc, NextMapByteData | |
ld de, MapVram.next | |
exx | |
pop hl ; MapVram1 | |
ld de, MapVram.next | |
; hl=MapVram1 スクロール端 | |
; de=MapVram.next | |
; b=ループカウンタ | |
; hl'=MapVram2 スクロール端 | |
; de'=MapVram.next | |
; bc'=次データワーク | |
ld b, ScrHByte | |
.loop | |
ld a, (hl) | |
exx | |
ld (hl), a | |
ld a, (bc) | |
inc bc | |
rrd | |
add hl, de | |
exx | |
add hl, de | |
djnz .loop | |
ret | |
setInitMap2: | |
; 次マップデータ設定をマップの先頭アドレスに設定 | |
ld ix, NextMapData.workTop | |
ld hl, MapData.addr | |
call getMapAddr | |
; hl = マップデータアドレステーブルのエリア先頭 | |
ld b, ScrHByte | |
xor a | |
; マップ処理用ワークを初期化 | |
; 長さ0にして初回にマップデータを読み取るようにする | |
.initLoop | |
; push hl | |
ld (ix + NextMapData.length), a | |
LD_DE_HLM | |
ld (ix + NextMapData.nextAddrH), d | |
ld (ix + NextMapData.nextAddrL), e | |
REPT NextMapData.next | |
inc ix | |
ENDM | |
; pop hl | |
; inc hl | |
; inc hl | |
djnz .initLoop | |
; 64列分のマップ初期値設定 | |
ld a, 1 | |
ld b, ScrWByte | |
.normalHloop | |
push bc | |
; 次のデータをワークに作成してマップデータに転送 | |
ld (vMapOffset), a ; マップデータオフセット設定 | |
call putNextMapData | |
call setRightMapNormalData | |
ld a, (vMapOffset) | |
inc a | |
pop bc | |
djnz .normalHloop | |
; MapVram2初期化 | |
; 右端は初期化なし。最初の表示前に値が入る | |
ld hl, MapVram2.top | |
ld de, MapVram1.top | |
ld iyh, MapVram.lines | |
.shiftVloop | |
ld b, MapVram.lineSize - 1 | |
.shiftHloop | |
; 元データを4ビットシフトさせる | |
ld a, (de) | |
ld c, a | |
inc de | |
ld a, (de) | |
ld (hl), c | |
rrd | |
inc hl | |
djnz .shiftHloop | |
inc hl | |
inc de | |
dec iyh | |
jr nz, .shiftVloop | |
call setRightMapShiftData | |
; スクロール関連初期値設定 | |
xor a | |
ld (vMapOffset), a | |
ld (MapScrollCount), a | |
ret | |
GetIxNextAddrDE MACRO | |
ld d, (ix + NextMapData.nextAddrH) | |
ld e, (ix + NextMapData.nextAddrL) | |
ENDM | |
PutIxNextAddrDE MACRO | |
ld (ix + NextMapData.nextAddrH), d | |
ld (ix + NextMapData.nextAddrL), e | |
ENDM | |
; ================================================= | |
; 1列分のマップデータをデコード | |
; ================================================= | |
; | |
; noLength: [0b 111, 3, 1], | |
; oneByteLength: [0b 011, 3, 3], | |
; fourByteLength: [0b 101, 3, 6], | |
; pattern4-0: [0b0001, 3, 0], | |
; pattern4-1: [0b1001, 3, 0], | |
; pattern8-0: [0b 00, 1, 0], | |
; pattern8-1 : [0b 10, 1, 0], | |
putNextMapData: | |
; hl = 次列のデータを書き込むワーク | |
; ix = マップバイトデータの次データ管理ワーク | |
ld hl, NextMapByteData | |
ld ix, NextMapData.workTop | |
ld b, ScrHByte | |
.loop | |
push bc | |
ld a, (ix + NextMapData.length) | |
or a | |
call z, decodeMapData | |
ld b, (ix + NextMapData.type) | |
srl b | |
jr nc, .pattern8 ; if 0b------x0 | |
srl b | |
jr c, .l0l1 ; if 0b----x11 | |
srl b | |
jr c, .l4 ; if 0b-----101 | |
; jr .pattern4 ; if 0b----x011 | |
.pattern4 ; pattern8と同じ | |
.pattern8 | |
push hl | |
srl b | |
jr c, .ptodd ; 奇数列 | |
.pteven ; 偶数列 | |
ld hl, TileData0.data | |
jr .ptset | |
.ptodd | |
ld hl, TileData1.data | |
.ptset | |
; a = 長さ | |
ld c, a | |
; index番号からアドレスを算出 0~127 | |
ld a, (ix + NextMapData.data) | |
; hl <- TileDataのトップアドレス + (index +1) * 4 - length | |
inc a | |
add a, a ; index * 2 | |
ld e, a | |
ld d, 0 | |
add hl, de ; hl + index * 2 | |
add hl, de ; hl + index * 2 | |
ld e, c | |
sbc hl, bc ; hl - length; | |
; hl = タイルデータアドレス | |
ld a, (hl) | |
pop hl | |
ld (hl), a | |
; jp .next | |
.next | |
inc hl ; 次の行のワークへ | |
; 長さを-1 | |
dec (ix + NextMapData.length) | |
REPT NextMapData.next | |
inc ix | |
ENDM | |
pop bc | |
djnz .loop | |
ret | |
; djnzの範囲が-128を超えるので、ここに書く | |
.l0l1 | |
srl b | |
jr nc, .l1 | |
; jr .l0 | |
.l0 | |
GetIxNextAddrDE | |
ld a, (de) | |
inc de | |
ld (hl), a | |
PutIxNextAddrDE | |
jp .next | |
.l1 | |
ld a, (ix + NextMapData.data) | |
ld (hl), a | |
jp .next | |
.l4 | |
GetIxNextAddrDE | |
ld c, a | |
ld a, (de) | |
inc de | |
ld (hl), a | |
ld a, c | |
dec a | |
jr z, .l4next | |
; 残り長さが4の倍数の場合、データアドレスを戻す | |
and 3 | |
jr z, .l4REPT | |
jp .l4next | |
.l4REPT | |
dec de | |
dec de | |
dec de | |
dec de | |
.l4next | |
PutIxNextAddrDE | |
jp .next | |
; 次のマップデータをデコードして次データ管理ワークに書き込む | |
; Input | |
; ix=データ管理ワークトップ | |
; Output | |
; a=マップデータ長さ | |
; b=マップデータ関連データ | |
; c=マップデータ種別 | |
; de=次のマップデータアドレス | |
; ixのメモリを上記値で更新する | |
; 破壊: | |
; a, bc, de, iyh | |
decodeMapData: | |
ld e, (ix + NextMapData.nextAddrL) | |
ld d, (ix + NextMapData.nextAddrH) | |
ld a, (de) | |
inc de | |
srl a | |
jr nc, .pattern8 ; if xx0 | |
srl a | |
jr c, .decode1 ; if x11 | |
; x01 | |
srl a | |
jr nc, .pattern4 ; if 001 | |
; if 101 | |
.l4 | |
or a | |
jr nz, .l4_set | |
ld a, (de) ; 長さ取得 | |
inc de | |
sub 5 | |
.l4_set | |
add a, 5 ; 1が6バイト連続 | |
ld iyh, a | |
; de <- de + (4 - a) % 4) | |
; a=0,4 -> 0 | |
; a=1,5 -> 3 | |
; a=2,6 -> 2 | |
; a=3,7 -> 1 | |
ex de, hl | |
neg | |
and 3 ; cy = 0 | |
ld c, a | |
ld b, 0 | |
add hl, bc | |
ex de, hl | |
ld a, iyh | |
ld c, MapDataType.cl4 | |
jp .allType | |
.decode1 | |
srl a | |
jr nc, .l1 ; if 011 | |
; if 111 | |
.l0 | |
ld c, MapDataType.cl0 | |
or a | |
jr nz, .allType | |
ld a, (de) ; 長さ取得 | |
inc de | |
jr .allType | |
.l1 | |
or a | |
jr nz, .l1_set | |
ld a, (de) ; 長さ取得 | |
inc de | |
sub 2 ; 長さ調整 | |
.l1_set | |
add a, 2 ; 値が1の場合は3バイト連続 | |
ld c, a | |
ld a, (de) ; マップデータ | |
inc de | |
ld b, a | |
ld a, c | |
ld c, MapDataType.cl1 | |
jp .allType | |
.pattern4 | |
srl a | |
jr c, .p4odd ; 奇数列 | |
.p4even ; 偶数列 | |
ld c, MapDataType.cp40 | |
jp .p4set | |
.p4odd | |
ld c, MapDataType.cp41 | |
.p4set | |
ld b, a ; index | |
ld a, 4 | |
jp .allType | |
.pattern8 | |
srl a | |
jr c, .p8odd ; 奇数列 | |
.p8even ; 偶数列 | |
ld c, MapDataType.cp80 | |
jp .p8set | |
.p8odd | |
ld c, MapDataType.cp81 | |
.p8set | |
; 長さが8バイトから始まるため、 | |
; インデックス番号を一つ先にして開始データを合わせる | |
inc a | |
ld b, a ; index | |
ld a, 8 | |
; jr .allType | |
.allType | |
ld (ix + NextMapData.type), c | |
ld (ix + NextMapData.data), b | |
ld (ix + NextMapData.length), a | |
ld (ix + NextMapData.nextAddrL), e | |
ld (ix + NextMapData.nextAddrH), d | |
ret | |
; ================================================= | |
; アトリビュートの次データのワークをクリアする | |
; ================================================= | |
setInitAttr: | |
ld hl, AttributeData | |
call getMapAddr | |
; hl = アトリビュートデータアドレステーブルのエリア先頭 | |
ld ix, NextMapAttrWork | |
ld c, 0 ; 残り長さ1設定 | |
ld b, ScrHByte | |
.loop | |
; 次のアトリビュートデータアドレスを設定する | |
ld e, (hl) | |
inc hl | |
ld d, (hl) | |
inc hl | |
ld (ix + NextMapAttr.nextAddrL), e | |
ld (ix + NextMapAttr.nextAddrH), d | |
ld (ix + NextMapAttr.length), c | |
inc ix | |
djnz .loop | |
ret | |
; ================================================= | |
; アトリビュートエリア設定 | |
; ================================================= | |
setAttr: | |
ld ix, NextMapAttrWork | |
ld hl, AttrVram.top | |
ld iyh, ScrHByte | |
.vloop | |
ld iyl, Vram.attrMax - 1 ; Attr変更回数 | |
ld e, (ix + NextMapAttr.nextAddrL) | |
ld d, (ix + NextMapAttr.nextAddrH) | |
ld c, (ix + NextMapAttr.color) | |
ld a, (ix + NextMapAttr.length) | |
; 1色目 | |
or a | |
jp nz, .notDecode | |
; 前のデータが終わっていたら次のデータを読む | |
call decodeAttrData | |
ld (ix + NextMapAttr.nextAddrL), e | |
ld (ix + NextMapAttr.nextAddrH), d | |
ld (ix + NextMapAttr.color), c | |
ld (ix + NextMapAttr.length), a | |
.notDecode | |
ld (hl), c ; カラーコード | |
inc l | |
; a = X座標(0 ~ ScrWByte - 1)で次の位置を管理 | |
cp ScrWByte | |
jr nc, .attrLineEnd ; if 画面端まで同色 | |
ld (hl), a ; X座標 | |
inc hl | |
ld b, a | |
; 2色目以降のループ | |
; de=アトリビュートデータアドレス | |
; hl=AttrVramアドレス | |
; b=X座標 | |
.hloop | |
call decodeAttrData | |
ld (hl), c | |
inc l | |
dec iyl | |
; マップでアトリビュートが最大になることはないはず(コード化時にチェックする) | |
; jr z, .attrMaxEnd | |
add a, b | |
jr c, .attrLineEnd ; if 画面端まで同色 | |
cp ScrWByte | |
jr nc, .attrLineEnd ; if 画面端まで同色 | |
ld b, a | |
ld (hl), a ; X座標 | |
inc hl | |
jp .hloop | |
; アトリビュート最大 | |
; マップ表示右端まで指定してアトリビュート終了 | |
.attrMaxEnd | |
ld (hl), ScrWByte | |
jp .hloopend | |
; マップ表示アトリビュートデータ終了、残りを白で埋める | |
.attrLineEnd | |
; ld a, AttrColor.white | |
ld a, AttrColor.cwhite ; 一旦外部はキャラで | |
ld c, Vram.dataWidth ; 残りは $50, 白で埋める | |
ld (hl), ScrWByte | |
ld b, iyl | |
dec b | |
jr z, .hloopend | |
.attrLineEndLoop | |
inc hl | |
ld (hl), a | |
inc l | |
ld (hl), c | |
djnz .attrLineEndLoop | |
; attrの最後は常にWhiteのまま | |
.hloopend | |
; 次のアトリビュート | |
inc l | |
.decLen | |
dec (ix + NextMapAttr.length) | |
.decLenJp | |
call vSyncCount | |
inc ix | |
dec iyh | |
jp nz, .vloop | |
ret | |
; アトリビュート圧縮データのデコード | |
; Input | |
; de=データアドレス | |
; Output | |
; de=次データアドレス | |
; c=アトリビュートデータ | |
; a=長さ | |
decodeAttrData: | |
ld a, (de) | |
; * 0b0aaallll 長さが16バイト未満 | |
; * 0b1aaa1100 , length 長さが16バイト以上の場合 | |
sla a | |
jr nc, .short | |
ld c, a ; アトリビュートデータ | |
inc de | |
ld a, (de) | |
inc de | |
ret | |
.short | |
and AttrColor.colorMask | |
or AttrColor.Semigraphic | |
ld c, a ; アトリビュートデータ | |
ld a, (de) | |
inc de | |
and 00001111b | |
ret | |
; マップの行位置を元にマップデータやアトリビュートアドレスを計算する | |
; hl データテーブルの先頭位置 | |
; Output データアドレス | |
; 破壊 a, bc | |
getMapAddr: | |
ld a, (CurrentMapLine) | |
add a, a | |
ld c, a | |
ld b, 0 | |
add hl, bc | |
ret | |
; ------------------- | |
; 転送機能 | |
; ------------------- | |
; ================================================= | |
; シフト無し表示 | |
; ================================================= | |
transMapVram1: | |
ld hl, MapVram1.top | |
jr transMap | |
; ================================================= | |
; シフトあり表示 | |
; ================================================= | |
transMapVram2: | |
ld hl, MapVram2.top | |
; jp transMap | |
; ================================================= | |
; マップデータの転送 | |
; hl = MapVramトップアドレス | |
; ================================================= | |
transMap: | |
push hl | |
ld a, (vMapOffset) ; a=マップデータのずれ | |
ld c, a | |
add a, a | |
ld e, a | |
ld d, 0 | |
; 左側は a回 LDIを減らすため、 a*2バイト後ろをコール | |
ld hl, transLdi.maxData | |
add hl, de ; cy = 0になる | |
ld (.ldiLeftAddr), hl | |
; 右側は、a回 LDIするため、末尾から、a*2バイト目をコール | |
ld hl, transLdi.end | |
sbc hl, de ; cy = 0 | |
ld (.ldiRightAddr), hl | |
; deに裏VRAMの転送開始アドレスをセット | |
ld hl, (NextVramAddr) | |
ld a, MapVram.lineSize | |
sub c | |
ld c, a | |
ld b, d ; d = 0 , bc = 64 - (vMapOffset) | |
add hl, bc | |
ex de, hl | |
pop hl | |
; hl = MapVram1 or 2 | |
; de = 裏VRAM、転送開始アドレス | |
; ldiのコールアドレスは設定済み | |
ld ixh, ScrHByte | |
; ループ内のState 28105 | |
; (17 + 16 * 64 + 10) + 29 + 29 + 15) * 25 + 5 | |
.vloop | |
; 右側転送 | |
.ldiRightAddr equ $ + 1 | |
call transLdi.maxData ; State: 17(call) + 16 * n + 10(ret) | |
; deを左端に | |
; State: 29 | |
ex de, hl | |
ld bc, -ScrWByte & $FFFF | |
add hl, bc | |
ex de, hl | |
.ldiLeftAddr equ $ + 1 | |
call transLdi.end ; State: 17(call) + 16 * n + 10(ret) | |
; de を次の行に | |
; State: 29 | |
ex de, hl | |
ld bc, Vram.lineSize | |
add hl, bc | |
ex de, hl | |
; State: 15/20 | |
dec ixh | |
jp nz, .vloop | |
jp transAttr | |
; ================================================= | |
; アトリビュートデータを AttrVram から Vram に転送 | |
; ================================================= | |
transAttr: | |
ld hl, (NextVramAddr) | |
ld bc, Vram.dataWidth + 1 | |
add hl, bc | |
ex de, hl ; de = アトリビュートの2バイト目 | |
ld hl, AttrVram.top | |
ld a, Vram.lines | |
.vloop | |
; ld bc, Vram.attrWidth | |
call transLdi.attr | |
; deを次の行へ | |
ex de, hl | |
ld bc, Vram.lineSize - AttrVram.lineSize | |
add hl, bc | |
ex de, hl | |
dec a | |
jr nz, .vloop | |
ret | |
; ================================================= | |
; LDIの羅列 | |
; ================================================= | |
transLdi: | |
.attrByte equ AttrVram.lineSize ; アトリビュートの転送バイト | |
.dataByteRest equ ScrWByte - .attrByte ; データエリアの最大バイト数に足りない分 | |
; 最大64バイト転送 | |
.maxData | |
REPT transLdi.dataByteRest | |
ldi | |
ENDM | |
; アトリビュートデータをVRAMに転送 | |
.attr | |
; AttrVramの文字数を転送する | |
REPT transLdi.attrByte | |
ldi | |
ENDM | |
.end | |
ret | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment