エピ22 MZ80のキースキャンのこと
***
エピ22 MZ80のキースキャンのこと
***
MZ80のROM「SP1002」にはキー入力用のルーチンとして次の3つがあります。
0003: GETL (07E6h)
001B: GETKY (08BDh)
001E: BRKEY (0A32h)
0003h 番地の GETL は1行入力用のルーチンです。キー入力は 09B3h のルーチンを呼び出して GETKY(の 08CAh のルーチン)を利用します。入力後リターン・キー押下でリターンします。SP5030のメインループから直接実行命令文やプログラムを入力する際に使うのですが、すごく多機能です。
001Bh 番地の GETKY は1文字入力ルーチンです。コールされたらキースキャンして、入力がなければ 00h を返します。入力があればキーに対応するアスキーコードを返します。でも何やら例外がありそう。
001Eh 番地の BRKEY は SHIFT+Break を検出するルーチンです。前回の最後にも出て来ましたね。
今回は GETKY を解読してみましょう。MZ80のキースキャンのことが理解できると思います。
***
GETKY はコールされると 08BDh 番地にジャンプします。
08BDh 番地のルーチンはこんな感じです。
A = _08CAh() # 本体
if A==F0h: A=00h
else: A=_0BCEh(A) # コード変換
ret
08CAh のルーチンが GETKY の本体ですね。F0h ならキー入力なしを意味して、A=00h でリターンです。F0h 以外なら 0BCEh のルーチンでアスキーコードに変換してリターン。
*
08CAh のルーチンです。処理の意味が変わらない範囲で改変と簡略化してます。
push BC; push DE; push HL
B,C = _0A50h() # キースキャン; B=入力の有無, C=ロウとカラム
if B>=80h:
if (B&040)>0: A=[0AC9h+08h+C] # シフト付
elif [1170h]==00h: A=[0AC9h+C] # 英数
else: A=[0AC9h+A0h+(C&F0h)/2+(C&0Fh)] # カナ
else:
A=F0h
pop HL; pop DE; pop BC; ret
0A50h のルーチンでキーマトリクスをスキャンします。結果は B と C です。B はビット7(D7)がキー入力の有無、ビット6(D6)がシフトキーの有無です。C はキーマトリクスのロウとカラムで、ロウ✕16+カラムです。ロウは0〜9、カラムは0〜7です。
1170h 番地はROMのワークエリアで、カナ/英数の状態です。00h=英数, 01h=カナです。
0AC9h 番地はキーマトリクスのテーブルです。最初の A0h バイトは英数とシフト付きのコード用です。シフト付きはカラムに +8 してテーブルを参照します。その後はカナのコード用です。C の値をロウ✕8+カラムに換算してテーブルを参照します。
*
0A50h のルーチンです。簡略化してます。
push DE; push HL; D=00h; B=FAh # = 1111 1010
_0A56h:
dec B
[E000h]=B # ロウを選択
if B!=EFh: # = 1110 1111
A=cpl([E001h]) # カラムを取得, ビット反転
if B==F8h: # ロウ8のとき
if A&21h!=00h: # = 0010 0001
D=D|40h # シフトあり
A=A&DEh # = 1101 1110
if A!=00h:
if A>=80h: A=07h
elif A>=40h: A=06h
elif A>=20h: A=05h
elif A>=10h: A=04h
elif A>=08h: A=03h
elif A>=04h: A=02h
elif A>=02h: A=01h
elif A>=01h: A=00h
C=(B&0Fh)*10h+A # ロウ*16+カラム
D=D|80h # キー入力あり
jp _0A56h # 次のロウへ
B=D; pop DE; pop HL; ret
ロウ9〜0と順に選択して、カラムを調べます。
ロウ8のときはシフトキーの処置をします。D5,D0 が押下なら D の D6 をセットします。それから D5,D0 はマスクします。
シフトキー以外のキーについて、カラムの各ビットをMSBから調べて最初の押下キーを採用して、それを C に入れます。それと D の D7 をセットします。
キー入力があってもキースキャンを続けます。なので最後に検出したキーが結果になります。何故かな?
同時に複数のキー入力があった場合の優先順位がありますね。ロウが小さい方が優先され、同じロウの中ではMSBに近い方が優先。例えば、キー “1” とキー “2” の同時押下なら “1” になります。“1” と “3” の同時押下なら “3” になります。
ロウ0まで調べた後、[E000h] に EFh を転送しているのが気になります。ロウの選択を解除する意味があるのかな?
*
キー “1” が押下された場合(英数で、シフトなしとして)。
ロウ0で D0 のビットがオンになります。0A50h のルーチンは、B=80h, C=00h でリターンして、08CAh のルーチンは [0AC9h+00h] を返します。
同様にして、幾つか書き出すと、
“1” ⇒ [0AC9h+00h] “3” ⇒ [0AC9h+01h] “5” ⇒ [0AC9h+02h]
“2” ⇒ [0AC9h+10h] “4” ⇒ [0AC9h+11h]
“Q” ⇒ [0AC9h+20h] “E” ⇒ [0AC9h+21h]
“W” ⇒ [0AC9h+30h]
“A” ⇒ [0AC9h+40h]
となります。0A50h のルーチンが返す C の値はロウx16+カラムですから、キーマトリクスの表を見れば明確ですね。
0AC9h 番地のデータは、...
0AC9: 21h, 23h, 25h, 27h, ...
0AD9: 22h, 24h, 26h, 28h, ...
0AE9: 11h, 05h, 14h, 15h, ...
0AF9: 17h, 12h, 19h, 09h, ...
0B09: 01h, 04h, 07h, 0ah, ...
です。つまり、
“A” ⇒ 01h
“E” ⇒ 05h
“Q” ⇒ 11h
“W” ⇒ 17h
“1” ⇒ 21h
“2” ⇒ 22h
“3” ⇒ 23h
“4” ⇒ 24h
“5” ⇒ 25h
となります。これがMZ80の取説に記載のディスプレイコードですね。
*
0BCEh のルーチンは、ディスプレイコードをアスキーコードに変換します。
push BC; push HL
A=[0CC6h+A]
pop HL; pop BC; ret
0CC6h 番地のテーブルを参照するのです。
0CC6: 20h, 41h, 42h, 43h, ...
0CD6: 50h, 51h, 52h, 53h, ...
0DE6: 30h, 31h, 32h, 33h, ...
“A” ⇒ 41h や “1” ⇒ 31h となって確かにアスキーです。
*
これで GETKY の処理を一覧できましたよ。
***
**
*
0AC9h 番地のデータは 10*16 + 10*8 = 240 バイトあります。
ですが見ていると幾らか重複するバイトがあるようです。ちゃんと調べると(R,C はロウとカラムです。"<--" は重複部分)、
|Eisu|Kana|SHFT|R,C |Key
+----+----+----+----+------
|C1h |<-- |C2h |9,2 |cursor
|C3h |<-- |C4h |8,3 |cursor
|C5h |<-- |C6h |9,0 |CLR/HOME
|C7h |<-- |C8h |8,1 |INST/DEL
|C9h |<-- |CAh |6,5 |Kana/Eisu
|CDh |<-- |<-- |8,4 |CR
|00h |<-- |<-- |9,1 |SPACE
|F0h |<-- |CBh |9,3 |Break
|F0h |<-- |<-- |8,0 |SHIFT
|F0h |<-- |<-- |8,5 |SHIFT
|F0h |<-- |<-- |8,2 |(nul)
|F0h |<-- |<-- |9,4 |(nul)
この 10 個のキーはディスプレイコードからみて特殊なキーです。残りの 78-10 = 68 個のキーはシフトやカナで別々のコードになります。
C1h〜C6h はキーに対応するディスプレイコード(文字記号)が定義されていますが、C7h〜CBh と CDh の6個はキーとは無関係な文字になっています。
それだけではなくて、C7h〜CBh と CDh はキー入力しても対応する文字は画面表示されないのです。カナ(CAh)や英数(C9h)のキーを押下するとカナ/英数の切替えとLEDの色を変える処理をするのみで画面には反映されません。他のキーも対応する処理を実行するのです。...、なので無関係な文字なのでしょう。
でも CR は対応する文字があったら便利じゃないかな? C1h〜C6h の6個は対応する文字を PRINT 文の文字列の中に入れるとカーソル制御できてね。
CCh は仲間外れ?
F0h はキー入力なしと扱われます。Break キーはシフト付きでないとキー押下したことにならないのですね。ふむふむ。
*
ディスプレイコードは 0〜255 までの 256 個あります。なので 0AC9h 番地のデータ(240 バイト)には出現しないディスプレイコードがあります。F0h も出現しない扱いして、出現しないコードを調べると 40h, 80h, C0h, CCh, CEh, CFh, DFh, E0h〜FFh でした。これらはキーボードから入力できないコードです。...、入力できても画面表示できないと言う意味で C7h〜CBh, CDh も特殊ですね。
40h と 80h, F0h はスペースで、00h と同じです。
DFh の蛇の絵文字は地底最大の作戦で出て来ました。これが動いたら楽しそう。
E0h〜EFh は何に使うのでしょうか。アスキーアート?
F1h〜FFh はMZ80のセミグラフィックで使う記号ですね。SP5030では SET 命令と RESET 命令で80x50のドットをオン・オフできます。
***
**
*
MZ80のキー入力の仕組みが分って来ましたね。
次回、特殊なキーについて追求します。まだ黒子は姿を見せないのです。
***
間違いの指摘とか疑問とか、ご意見・ご感想とかありましたら、どうぞ感想欄に!
***
2026.4.13 微推敲と図の差替
2026.4.15 微推敲
2026.4.19 加筆と微推敲
2026.4.30 長くなったので分割
2026.5.8 エピタイ修正




