Skip to content

Instantly share code, notes, and snippets.

@ueno1969
Created March 5, 2022 06:28
Show Gist options
  • Save ueno1969/db4c2ebfe354bb1df3074f6fab9f1a21 to your computer and use it in GitHub Desktop.
Save ueno1969/db4c2ebfe354bb1df3074f6fab9f1a21 to your computer and use it in GitHub Desktop.
PC 8001 Z80 カラードットスクロール 処理部
;==============================
; 描画関連
;==============================
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