キーボードやタイマー、マウス操作などの割り込みハンドラで入力されてくる情報を、システムイベントという概念で一括りにして、全てを一つのFIFOに登録していき、メイン関数で区別して処理することにした。マルチタスクではないので、FIFOへ登録された順序で一つずつ処理していく。
キーボードのハード的な機構は、どうも昔からほとんど進歩してないようで、キーボードコントローラーの8042回路の状態が一々コマンドを書き込めるかをポーリングでチェックしてからになり、アセンブラで作ると、簡単な内容の割にかなり長いプログラムになってしまい、PS/2キーボードコントローラーの仕様が変に複雑で理解するのが大変で、初期化ルーチンを作るのに数日かかってしまった。
理由としては、readとwriteになぜか0x60と0x64の二つIOアドレスがあり、コマンドを書き込む時や、データを読む時にどちらのIOアドレスへアクセスすればよいか、理屈が全く分からなかった。断片的なサンプルを見て、推測して何とか動いているが、本当に正しいロジックなのか今も自信が持てない。特に、キーボードコントローラーへコマンドを書き込んだ後に、ACK(0xFA)がアウトプットポートへ返ってくるのだが、ネット上のサンプルプログラムには、ACKを待たないものもあり、おそらくそのままでは正しく動作しないと思う。意図的なのか、気付いてないのかは分からない。私自身のアセンブラプログラムでは、インプットポートへコマンドを書いたら、必ずアウトプットポート(0x60)をチェックして、0xFAが返ってくるのをチェックするようにしている。しかし問題は、ACKが返ってこない場合があって、制御バイトを読み出す要求コマンドの場合は、ACKではなく、制御バイトの設定情報がすぐに戻ってくる。つまり、どんなコマンドを書き込むかによって、操作シーケンスが変わってしまうので、自分で一つ一つ確認しながらプログラミングしなければならなかった。「マニュアルや仕様書には間違いや嘘が書いてあるから、最後に頼れるのは自分の判断力だけ」という黎明期のプログラマーの格言は今も生きているようだ。
また、モニタープログラムの初期処理で、キーボードコントローラーをリセットして、キーボードコントローラーの内部バッファをクリアしておかないと、ゴミデータをポートから受信してしまう可能性もある。それなのに、ネット上のサンプルはそんなことを全く考慮していない。まあ、参考情報なので文句は言えないが、簡単なことなのに、キーボード回路の初期化処理と、割り込みハンドラ、システムイベントFIFOも含めて、一週間以上かかった。
キーボード入力は、ブートモニター(OS)側でキーボードの状態遷移を常に把握して、大文字と小文字の判別、BSキーのカーソル移動、Shiftキーの状態変更などをしなければならなかった。キーボード回路から現在のCaps-lock状態などを読み取ることができないためだ。過去の経緯でこのような作りになっているのだろうが、これらの処理はキーボードを少し高機能化して、Caps lockとかNum lockとかの状態通知と、直接に文字コードを伝達してくれればいいのにと思う。取り敢えず、BOOT_INFOのキーボード状態を参照して、C言語のメインルーチンで、caps-lockがされたとか、shiftが押された状態を保持して、モニターのプログラム側でコントロールするしかない。これもキーボード側で状態通知をしてくれれば、かなり楽になると思うのだが、昔からの互換性の問題があって難しいのだろう。
不思議な現象にも悩まされた。エンターキーを押すと、スキャンコード以外に、0xE0というデータがキーボード割込みで入力されてきて、これはスキャンコード一覧にも載ってない。仕方がないから、無視して読み捨てにしているが、自分が何か間違った設定でもしているのではないかと、心配ではある。
それと、作り始めてから気付いたが、キーボードにも種類があり、今はVH-AD3S proのノートパソコン用で作成しているが、ノートパソコンは84キー型、デスクトップパソコンでは109キー型などで、所謂キーマップを別々に用意して、初期化処理で切り替えるようにしておかなければならない。現段階では必要ないが、拡張できるようなデータ構造とプログラミングをしておいた。また、フォントが対応してないので、表示はできないが、「かな」の入力にも対応できるようにした。
とにかくこれで、コマンドラインでの文字入力ができるようになったので、メモリダンプとか、デバッグに役立つような実行コマンドを作成しようと思っている。