表示調整
閉じる
挿絵表示切替ボタン
▼配色
▼行間
▼文字サイズ
▼メニューバー
×閉じる

ブックマークに追加しました

設定
0/400
設定を保存しました
エラーが発生しました
※文字以内
ブックマークを解除しました。

エラーが発生しました。

エラーの原因がわからない場合はヘルプセンターをご確認ください。

ブックマーク機能を使うにはログインしてください。
31/37

エピ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個はキーとは無関係な文字になっています。


 挿絵(By みてみん)


 それだけではなくて、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 も特殊ですね。


 挿絵(By みてみん)

 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 エピタイ修正




評価をするにはログインしてください。
ブックマークに追加
ブックマーク機能を使うにはログインしてください。
― 新着の感想 ―
このエピソードに感想はまだ書かれていません。
感想一覧
+注意+

特に記載なき場合、掲載されている作品はすべてフィクションであり実在の人物・団体等とは一切関係ありません。
特に記載なき場合、掲載されている作品の著作権は作者にあります(一部作品除く)。
作者以外の方による作品の引用を超える無断転載は禁止しており、行った場合、著作権法の違反となります。

↑ページトップへ