エピ26 MZ80のカーソル制御のこと(続) - 1173h番地を整理
***
エピ26 MZ80のカーソル制御のこと(続) - 1173h番地を整理
***
カーソル制御について調べていましたが、謎が多すぎて先に進めなくなりました。実は1つの謎を放置して先に進んだら、謎が次の謎を呼び出していてね。クリーピングコインは仲間を呼んだ!
冷却して、リークメモリのフラッシュもしたので再度挑戦をしてみます。
1173h 番地のことを整理して、残る C7h [DEL] と C8h [INS] に取り組みましょう。
***
1173h 番地について見直しました。
00h なら未接続で、00h 以外なら接続中を意味するのは間違いないはずです。
ですが、どの行と接しているのかを誤解していました。
正しくは、
[1173h+Y+0]!=00h ならば、Yは「前行」と接続中
[1173h+Y+1]!=00h ならば、Yは「次行」と接続中
です。なお Y=[1172h] です。Y は 0〜24 の範囲です。
次のように並べて見たら、[1173h+Y+1] は Y と Y+1 の行の接続の有無を示すのだな、と分かった感じになりました。どうでしょうか?
[1173h] 0 [1173h+1] 1 [1173h+2] 2 [1173h+3] ...
... [1173h+23] 23 [1173h+24] 24 [1173h+25], [1173h+26]
なお。[1173h] と [1173h+25], [1173h+26] が用意されているのは、ディスプレイ表示やスクロールアップの処理の都合のようです。これがあると条件分岐を減らせるのです。番兵くんみたいだ。
*
復習していて気が付いたのです。GETL で取得する行は 1173h を参照して、
if [1173h+Y+0]!=00h: BC=0050h; H=Y-1; L=00h
elif [1173h+Y+1]!=00h: BC=0050h; H=Y; L=00h
else: BC=0028h; H=Y; L=00h
とするのです。(X=L,Y=H) の座標から [BC] バイトを取得する。つまり、前行と接続中なら Y-1 と Y の2行を、次行と接続中なら Y と Y+1 の2行を、どちらとも未接続なら Y の1行を取得する。
*
ディスプレイ表示 0DB5h を再確認します。X=[1171h], Y=[1172h] です。
if X==27h and [1173h+Y+0]==00h:
[1173h+Y+1]=01h
[1173h+Y+2]=00h
X=39 で1文字を表示して、カーソル位置を次の行の先頭に移動する場合、
・前行と未接続なら次行と接続中にして、次行は、次行未接続にする。
・前行と接続中なら更新しない。
...、と言うことです。
ある Y について [1173h+Y+1] が 01h であるときは [1173h+Y+0] と [1173h+Y+2] は 00h であるのです。
01h の前後は必ず 00h であり、01h は連続しない。...、3行の連結はしない。
*
境界値についてチェックします。境界テストは基本です。
[1173h+0] は、0DB5h のルーチンで 01h になることは無いですね。Y=0 の前行は無いですから当然ね。
[1173h+1] は 01h なることはある。それでスクロールアップで [1173h+0] が 01h になったら、2回目のスクロールアップをする。01h のあとは 00h なので3回目は無くて [1173h+0] は 00h になる。
[1173h+24] は 01h になる。X=39,Y=23 でディスプレイ表示して Y=24 の行と接続したとき。
[1173h+25] は X=39,Y=24 でディスプレイ表示したら 01h になり、[1173h+26] は 00h になる。続いて [→] の制御でスクロールアップして [1173h+25] は 00h になる。Y=24 の次行は無いから未接続でOK!
*
これでスッキリしました。
*
**
***
C7 [DEL] です。MZ80の [DEL] は、Back Space のことです。MZ80には Delete キーは無いのよ。
_0EF8: #C7 [DEL]
if [1171h]==0000h: jp _0FDEh # POPs&RET, if X=0,Y=0
elif [1171h]!=00h: jp _0F1Dh # if X!=0
elif [1173h+[1172h]]!=00h: jp _0F1Dh # if 前行接続中
else: # X==0 and 前行未接続
HL=_0FB1h() # カーソルの番地をHLにセット
_0DA6h(); dec HL; [HL]=00h # (X=39,Y-=1)を00hに
jp 0EAEh # [←]
_0F1D: # X!=0 or 前行接続中
if [1173h+[1172h]+1]==00h: # if 次行と未接続
BC=28h-[1171h]
else:
BC=50h-[1171h]
HL=_0FB1h(); DE=HL-1; _0DA6h(); LDIR; dec HL; [HL]=00h
jp 0EAEh # [←]
X,Y座標と前後の接続状態による処理分岐は、ゆっくり読めば分かりますね。
0F1Dh のルーチンでは [DEL] するとカーソル位置以降の文字が左に移動するので、その際に1行分なのか2行分なのかを 1173h で判定していますけど。前行接続中なら次行とは未接続であることを考慮すれば、分かるよね。
***
BASICの環境は、パソコンのフルスクリーン・エディタとは違うことが良く分かりますね。
***
C8h [INS] です。カーソル位置以降を1つ右に移動して、カーソル位置をスペースにします。
_0F49: #C8h [INS]
if [1173h+[1172h]+1]!=00h: # 次行と未接続
C=00h; H=[1172h]; L=27h
else:
C=01h; H=[1172h]+1; L=27h
# HLは行末か次行の末
HL=_0FB4h(HL) # XY座標を番地に変換
if [HL]!=00h: # 行末が詰まっているとINSできない
jp _0FDEh # POPs&RET
# 以下で B,HL,DE をセットして転送(LDDR相当の処理)
B=27h-[1171h]
if C!=00h: B=B+28h #28h=40
DE=HL; HL=HL-1; _0DA6h()
while(B>0):
[DE]=[HL]; [HL]=00h; dec HL; dec DE; dec B
jp _0FDEh # POPs&RET
なるほどネ、と言う感じです。
ループの中で [HL]=00h と毎回ゼロクリアしているのは、ループ終了後にすれば良いのではないかな。
***
**
*
謎は解けた。いよいよキャスティング完了か?
***
間違いの指摘とか疑問とか、ご意見・ご感想とかありましたら、どうぞ感想欄に!
***
2026.5.3 微推敲
2026.5.8 エピタイ修正




