エピ24 MZ80のディスプレイ表示のこと
***
エピ24 MZ80のディスプレイ表示のこと
***
MZ80のディスプレイ表示に関するROMルーチンには、次のものがあります(0000h〜0047h の範囲ではね)。
0006h: LETNL (CR) 090Eh
0009h: _____ (CR2) 0918h
000Ch: PRNTS (SPACE) 0920h
000Fh: _____ (TAB10) 0926h
0012h: PRNT_ (PRNT) 0935h
0015h: MSG__ (MSG) 0981h
0018h: _____ (MSG2) 0999h
"_____" は取説に未記載のルーチンです。名前が無いルーチンがあるので () 内に名前を付けました。右端はジャンプ先の番地です。0000h〜0047h には JP 命令が集まっているのです。それで 0000h〜0047h がROMルーチン一覧になっていて、分かり易くて良いですね。
各ルーチンの処理は、...。
CR は改行で、次の行の先頭にカーソルを移動します。CR2 はカーソルの位置が行頭以外なら改行します。
SPACE はスペースを表示してカーソルを1つ右に進めます。TAB10 は 10 刻みのタブです。
PRNT は A をアスキーコードとして表示します。カーソル制御(→,↑,←,↓,H,C,改行)します。
MSG は [DE] 番地からの文字列(0Dhで終端)を表示します。改行を除くカーソル制御をします。MSG2 はカーソル制御しない MSG です。SP5030の LIST 命令文では MSG2 を使うのでしょう。だからプログラムリストにはカーソル制御の文字が載っているのですよ。
0000h〜0047h の他には、ディスプレイ表示(0DB5h)とカーソル制御(0DDCh)があります。この2つは GETL でコールしてましたね。なお 0DDCh は取説で "?DPCT" として記載していて、0DB5h は未記載です。
それでね。これらのルーチンの関係を整理してみたいと思います。
***
最初は MSG と MSG2 です。元は機械語ですが、出来る限り簡略化してスクリプト風にしました。
def MSG(DE): #0015h,0981h
push AF; push BC; push DE
while(1):
B=05h; _0DA6h()
while(B>0):
if [DE]==0Dh: jp _0FDFh # =POPs&RET
_0946h(C=[DE]); # ★★★
inc DE; dec B
def MSG2(DE): #0018h,0999h
push AF; push BC; push DE
while(1):
B=05h; _0DA6h()
while(B>0):
if [DE]==0Dh: jp _0FDFh # =POPs&RET
A=_0BB9h(A=[DE]); _0970h(A); # ★★★
inc DE; dec B
_0FDF:
pop DE; pop BC; pop AF; ret
この2つはほぼ同じコードで、違いは ★★★ の行だけです。
MSG は 0946h のルーチンをコールして、MSG2 は 0BB9h と 0970h をコールします。
0946h と 0970h が文字を処理するルーチンで、0BB9h はアスキーコードをディスプレイコードに変換するルーチンです。後述しますね。
0DA6h は垂直ブランク検出です。垂直ブランクを検出後、5文字を処理したら次の垂直ブランクを待ちます。ブランク時間は割と短いのですね。
1文字を処理したら inc DE して、[DE]==0Dh になったら終了で 0FDFh にジャンプします。0FDFh は POP して RET するルーチンです。MSG, MSG2 以外のルーチンでも使っている共通のルーチンです。
*
0946h と 0970h のルーチンです。意味を変えない範囲でロジックを整理しています。
def _0946(C):
A=_0BB9h(A=C) # コード変換
if A in [C0h..C6h]:
_0DDCh(A) # カーソル制御
if A==C3h: [1194h]=([1194h]+1)%80 # [→]
elif A in [C5h,C6h]: [1194h]=00h # [H],[C]
elif (A&F0h)!=F0h:
_0970(A); # ディスプレイ表示へ
ret
def _0970(A):
_0DB5h(A) # ディスプレイ表示
[1194h]=([1194h]+1)%80
ret
0946h は引数の C をディスプレイコードに変換して、C0h〜C6h なら 0DDCh のルーチンでカーソル制御、F0h〜FFh はリターンのみで、他は画面表示します。
0970h は引数の A をディスプレイコードとして、0DB5h のルーチンで画面表示します。
0DB5h と 0DDCh は GETL で出てきたルーチンです。GETL ではキー入力された文字のエコーバックで DEL, INS, Kana, Eisu, CR(C7h〜CAh, CDh)もカーソル制御していたのと違いますね。カナ/英数の制御などは不要でしょうけど、改行ならあっても良いよね。でも MSG() では 0Dh を文字列の終端としているので改行できないのです。
1194h 番地はカーソル位置の2行分のX座標(0〜79)です。エピ5で登場しました。
画面表示すると +1 して 80 になったら0に戻します。カーソル制御の [→] (C3h) でも +1 です。
[H] と [C] はカーソル位置をホーム位置(0,0)に戻すので [1194h] を 00h にします。
でもね。[←] (C4h) のカーソル制御したときには [1194h] は -1 しないのかな? 不思議な感じ。
*
ふと気になったのですが。プリンタに印刷するときの横幅はどうなるんだろう? もしかして80文字あるのかな。
*
0BB9h のコード変換は
def _0BB9h(A):
if A<10h: A=F0h
else: A=[0BD6h+A-10h]
ret
です。引数の A はアスキーコードで、10h〜FFh なら 0BC6h 番地のテーブルを参照するのですね。A が 00h〜0Fh なら F0h です。
右側のディスプレイコードで、緑色はアスキーコードから変換できるコードです。マゼンダは変換できないコードです。
あれ? ということは、ディスプレイ制御の C0h は 0946h では処理できないの? ...、C0h に対応するアスキーコードは、10h とか空いているから用意できたから、やらない理由があるのかな、...。謎。
カナのところなんて ”チ,コ,ソ,シ,イ,...” だよ。理由は分かるけど変態的。
***
次は CR と CR2 です。
def CR(): # 0006h,090Eh
[1194h]=00h; _0DDCh(A=CDh); ret
def CR2(): # 0009h,0918h
if [1194h]!=00h: jp _0006h
ret
CR は CDh のカーソル制御を行う。CR2 は [1194h]!=00h なら CR する。
[1194h]!=00h はカーソル位置の見た目が左端(X=0)か否かを意味していなくて。CR2 とは何をしたいのか議論が必要な感じがします。
CR で 0DDCh をコールして RET するならジャンプすれば良いよね。CR2 は 090Eh にジャンプすれば良いのにね。
***
残りです。
def PRNT(A): #0012h,0935h
if A==0Dh: jp _090Eh
push BC; C=A; B=A; _0DA6h(); _0946h(C);
A=B; pop BC; ret
def SPACE(): #000Ch,0920h
_0935h(A=20h); ret
def TAB10(): #000Fh,0926h
_0926:
_000Ch(); A=[1194h]
if A==00h: ret
_092E:
A -= 0Ah
jr C, _0926h
jr NZ, _092Eh
ret
PRNT は 0Dh なら CR(090Eh)にジャンプして、その他は 0946h です。0946h は改行をカーソル制御しないで画面表示するからですね。
SPACE は PRNT(0935h)をコール。コールして RET するならジャンプする方が良いですね。
TAB10 は SPACE(000Ch)をコール。000Ch でなくて 0920h の方が良いですよ。
もはや処理速度を気にしてなさそうですが。
*
...、昔のタブは 10 刻みだったのかしらん? 機械式のタイプライタならタブストップの設定次第だけどさ。パソコンなら8か4だと思ってた。
***
**
*
SP1002のディスプレイ表示は、結局のところ
0DB5h: ディスプレイ表示
0DDCh: カーソル制御
の2つのルーチンが基礎になっていることが分かりました。
コード変換とかカーソル制御の有無とか 1194h の処置とかありますが、それらは飾りに過ぎませんです。
この2つのルーチンを調べなければなりません。...が、次回ね!
*
次回は明後日? そんな先の事はわからない。
***
間違いの指摘とか疑問とか、ご意見・ご感想とかありましたら、どうぞ感想欄に!
***
2026.5.8 エピタイ修正




