KZ80マイコンを 偽MSX1へ〜PS/2キーボードMSXアダプタ

KZ80-IOB

MSXパソコンとして動かすため、キーボードを繋げたいと思います。ただ、昔ながらのマトリクス配線のキーボードを自作する元気はないのでPS/2キーボードとかを繋ぎたい。

MSXパソコンのキーボード

MSXパソコンのキーボードは、以下のような仕組みでPPI(8255)の先にキーボードマトリクスが繋がった構造になっています。(私が書き起こした図なので、間違いがあったらごめんなさい)
【2020/3/21追記】以下の図に間違いがありました。PPIでスキャンコードを受けるのはBチャンネルでした。

MSXのBIOSでは、VDPの1/60secごとのZ80 モード1割り込み(固定で0038h番地のプログラムをCall)が発生した際に、PPI(8255)の信号線を操作してキーボードスキャンを実施。押されているキーを特定してメモリー上のキー入力バッファに格納します。

キーボードスキャンの仕組みは、PPI(8255)のCポートの4本の線を0から順にカウントアップ。その先に7445 BCD to DECIMAL DECODER でBCDに対応した行信号線にわけて順にLに落とします。
その信号線にそれぞれ8個のキースイッチが付いていて、キースキャンの際に押下されていると、8ビット中の対応するビットがLに落ちます。

MSXのBIOS側ではどのビットがLかを検査すれば、どのキーが押されているかわかるという訳です。

ArduinoMEGAでMSXキーボード

ネットを検索していたら、2014年にブラジルの方がArduinoMEGAを使ってMSXキーボードの代わりをする仕組みを作られていました。
ブラジルでもMSXって売れたんですね。後から知りました。

http://msx.gouget.com.br/2014/06/24/ps2-keyboard-to-msx-with-arduino/
PS/2 Keyboard to MSX with Arduino – Video 3

上のブラジルの方は、セパレート型のMSXパソコンでキーボードがない場合ということで、PS/2キーボードとAuduinoMEGAをつかってMSXパソコン内の8255へ直結するという荒技をされています。仕組みとしては、マトリクス配線されているキーボード自体をエミュレートしてPPI(8255)にキーボードが繋がっているかのようにソフトウェアで振る舞うという仕組みです。これは行けそう。

PPI(8255)は以前 KZ80-IOB(I/Oボード)に搭載ずみですので実験できそうです。また、(たまたま)都合がよいことにKZ80-IOB(I/Oボード) REV2だとMSXのPPIのアドレスに合わせることができました。

KZ80-IOB(I/Oボード) REV2はシリアル、パラレルの石に加えて割り込みコントローラー、タイマーと合わせてLSIを4つ搭載したため、I/Oアドレスを節約するために08h番地おきにアサインするようにしてたので、たまたま設定可能だったのでした。

プログラムの方はArduinoMEGAのふんだんにある割り込み線を使って、PS/2からのシリアルクロック割り込み処理と、PPI(8255)のCポートの4本の線の信号変化による割り込み処理を行なっています。PS/2から割り込みがかかった場合は、PS/2スキャンコードをシリアル信号で取得してMSXのポートBへ渡すためのコードへ変換して内部スキャンコードテーブルへ保存。
PPI(8255)のCポートの4本の線の信号変化による割り込み処理では該当する内部スキャンコードテーブルの値をBポートへ出力します。

試作してみた

ArduinoMEGAは互換品を入手済みだったので、miniDIN 6Pコネクタなどを使って試作してみました。写真の真ん中のユニバーサル基板にminiDINコネクタが載ってます。

数字を入力すると2文字入る

上記の構成で組んだものをKZ80 偽MSX1に接続すると、0〜7の数字を入力すると2文字入力されるという事象に悩まされました。

Arduinoソフトウェアでは、PPI(8255)のCポートの値を取得して”+1″した内部スキャンテーブルのデータをBポートヘ出力するロジックとなっています。PPI(8255)のCポートの値が8だったら 内部スキャンテーブル 0番目のデータをポートBヘ出力….ということで、MSXがスキャンしてきたポートより1つ先のデータを返す仕様のようです。

以下のようなロジックへ変更したところうまく動いたので、どうも テンキー用のスキャンコード9とか10が渡ってきているような気が….(まだ腹に落ちてないです…)

void blink()
{
    if (PIND>=9) { 
      noInterrupts();
      PORTC = 255;      
      interrupts();
    }else if (PIND==8) { 
      noInterrupts();
      PORTC = keyboard.MSX_KB_Matrix(0);
      interrupts();
    } else {
      noInterrupts(); // Deactivate interruptions to avoid keyboard matrix corruption
      PORTC = keyboard.MSX_KB_Matrix(PIND+1); // 8 bits of the Matrix on PORT C (PIN
      interrupts();   // Activate interruptions
    }  
}

今後の野望

いまだ、最初の写真のようにバラックでPS/2キーボードをつないでいるので、今後はArduinoMEGAではなく、ATmega328Pを使って同じ動きをするPS/2-MSXキーボード・インターフェースボードを作ってみたいと思っています。
たぶん私にソフトウェアを作れるかが鍵だと思うんですが….(自信なし)