Operating Systems Development Series | |
Keyboard
はじめにようこそ!この章では、もう少し複雑なキーボードを取り上げます。キーボードの歴史、キーボード内部、8042 と 8048 マイクロコントローラ、そしてキーボードドライバの開発について学びます。 また、このシリーズで最初にプログラミングするデバイスでもあります。楽しみですか?ハードウェアプログラミングの仕組みはすでに学び、経験も積んでいます。 次はそれを試す番です。準備はいいですか?これはまた、1つのコントローラだけでなく、2つのコントローラで作業する必要がある最初のデバイスです。 これらのコントローラは、互いに通信し、私たちのシステムも通信します。さらに複雑なのは、両方のコントローラがそれぞれ独自のコマンドを持っていて、それを使って動作させることができることです。このため、この章では、いくつかの箇所でかなり詳しく説明しています。 また、この章には最初の対話型デモも含まれています。基本的なコマンドラインパーサです。興奮しましたか? この章はまた、デバイスドライバをより深く考察する最初の章でもあります。ハードウェアの抽象化とデバイスドライバの重要性。 以下はそのリストです。
さあ、始めよう キーボード - 歴史過去に戻るキーボードは、私たちがコンピュータに入力するために使用する入力デバイスです。 キーボードが最初に導入されたときは、典型的なタイプライターをモデルにしていました。しかし、キーボードの作りは、それを直接モデル化したものではありません。1877年にChristopher Latham Sholesによってタイプライターの特許が取得されると、いくつかのメーカーや人々がオリジナルのデザインをさらに発展させました。一連の発明を通じて進化したのが電信機です。同じ頃、1930年代には、IBMがキーパンチ(タイプライターと組み合わせたパンチカードマシン)を加算機で使っていた。初期のコンピュータのキーボードは、キーパンチと電信機の両方の設計を取り入れたものであった。 ENIAC(Electronic Numerical Integrator And Computer)は、最初の汎用コンピュータでした。ENIACは1946年にパンチカードリーダーを入力と出力の両方に使用しました。 1948年には、電気機械式タイプライターを入出力装置として使用した「BINAC(BINary Automatic Computer)」が登場した。 これらの発明から、キーボードはいつ進化したのだろうか。1964年、MIT(Fernando Corbató氏)、ベル研究所、ゼネラル・エレクトリック社が共同で、Multics(Multiplexed Information and Computing Service)マシンを開発した。 Multicsでは、新しいインターフェイスが登場したのだ。テレビと電動タイプライターに使われていたブラウン管(CRT)の技術を組み合わせて、ビデオ・ディスプレイ・ターミナル(VDT)を作ったのである。VDTは、ユーザーが入力した内容を見ることができるようにし、コンピュータをより使いやすくした。1970年代から1980年代にかけて、ほとんどのコンピューターにVDTと入力用の電子キーボードが搭載された。その後、VDTに代わってCRTやLCDのディスプレイが登場し、電子キーボードも汎用コンピュータの標準となりました。 現在、私たちはパソコンに向かうたびにキーボードを使用しています。キーボードのレイアウトのほとんどはまだタイプライターから残っており、使い方も同じです。しかし、新しい時代の電子機器のおかげで、キーボードは多くの異なる形で提供されるようになりました。一般的なプラスチック製のキーボードから、折りたたみ式やバックライト付きのキーボード、さらにはレーザーキーボードまで。 キーボードレイアウト一般的なキーボードのレイアウトは、QWERTYという文字が最初の5文字であることから、QWERTYキーボードと呼ばれています。QWERTY配列は、タイプライター時代に、初期のタイプライターが元々持っていた機械的な限界から、タイピストの入力速度を遅くするために意図的に設計されたものである。これは主に、キーを押す間隔を短くし、プリントヘッドが詰まらないように十分な時間を確保するためでした。QWERTY配列は、今日まですべてのキーボードで適応されています。 キーボード内部キーボードのキーを押すと、実際に何が起こるのでしょうか?キーボードが押したキーをどうやってプログラムに伝えるのでしょうか?今読んでいるテキストは、キーボードで入力されたものです。キーボードにはどのような機能があるのでしょうか?ちょっと見てみましょう。注:正確な情報はキーボードの種類とモデルによって異なります。ここでは、一般的な102キーボードのみを取り上げます。 ケースを開けるキーボードが複雑なプリント基板から、マイクロプロセッサーを搭載した1枚の基板になったことに驚かれるかもしれません。キーボードを開けてみると、こんな感じです。![]() はい、これだけです。いかにシンプルか、おわかりいただけるでしょう。基板が1枚、グリッドが1枚です。上の写真では、グリッドが少し見えにくいかもしれません。しかし、よく見ると、グリッド内のポイントがキーボードのキー位置と一致していることに気づくでしょう。これが「キーマトリックス」です。ほとんどのキーボードでは、キーマトリックスを構成する回路は、グリッドの各ポイントの間で途切れています。キーがキーマトリックスのある点の上にあることを知り、キーを押せば、その点のスイッチが押され、水平回路が完成し、電流が流れるようになる。キーの機械的な動きによって生じる線の振動はバウンスと呼ばれ、キーボードのマイクロプロセッサー(別名キーボード・エンコーダー)によってフィルタリングされます。少し複雑に思われるかもしれませんが、ご安心ください。次のセクションで詳しく説明します。 キーボード・エンコーダキーボードに搭載されているマイクロプロセッサーは、Intel 8048の原型となるもので、偶然にもIntelの最初のマイクロコントローラーでもある。このコントローラは、キーボード・エンコーダと呼ばれています。使用するキーボード・エンコーダは、キーボードによって大きく異なります。キーボード・エンコーダは何百種類とありますが、基本的にはどれも同じことをします。キーグリッド内の行と列は、キーボードエンコーダの8ビットI/Oポートに接続されています。キーが押されると、キーグリッド内のその位置にあるスイッチが閉じられ、電流が流れて回路が完成します。この電流は、キーボードエンコーダのピンが、キーの位置と一致する正しいポートに接続されることを可能にします。したがって、コントローラーがすべきことは、ポートをスキャンして、ポート線がアクティブかどうかをチェックすることで、キーがダウンしているかどうかを確認することです。 キーが押されていれば、キーボード・エンコーダはその位置をROM(Read Only Memory)文字マップ内で検索し、その文字のスキャン・コードを内部16バイト・メモリーに格納します。 キーボード・プロセッサには独自のタイマー、33の命令セット、さらに128Kの外部メモリーをアクセスすることが可能です。そのタイマーを使って、キーが押されているかどうかを、ユーザー入力かバウンスかで判断することができます。バウンドした場合は、通常、人間が入力できる速度よりはるかに速い。タイマーが0になったときにまだキーが押されていれば、リセットされ、その文字が内部の16バイトのバッファに挿入されます。 ここで重要なのは、私たちが通信できるキーボード・コントローラが2つあるということです。キーボードに内蔵されているキーボード・エンコーダと、マザーボードに内蔵されているキーボード・コントローラです。もう一方のコントローラについては、後で少し見ていきますので、心配しないでください;)今のところ、2つのコントローラがあり、キーボードエンコーダはそのうちの1つであることを覚えておいてください。 キーボード・エンコーダはキーボード・プロトコルで定義された方法でシステムと通信します。 見てみましょう。 キーボード・プロトコルキーボードエンコーダは、データをバイトとしてマザーボードのオンボードキーボードコントローラに送信します。送信方法は、キーボードのインターフェイスで使用されるプロトコールに依存します。これは通常、5ピンDINコネクター、6ピンMini-DINコネクター、USBコネクター、SDLコネクター、または有線(IR)インターフェースを使用したワイヤレスである。AT/XTキーボードに使用される5ピンのDINコネクターは、通常コンピューターの背面にあり、以下のような形状をしています。 ![]() 1: Clock 2: Data 3: N/A 4: Ground 5: Vcc (+5V) マザーボードは、電源ユニット(PSU)からVccとGroundピンを通じて電力を供給します。 clockピンは、キーボードのデータとシステムクロックの間の同期に使用されます。キーボードからのデータは、データピンを介してシリアルデータとして送信されます。 PS/2キーボードに使用される、より一般的な6ピンMini-DINコネクタは、非常によく似ています。 ![]() 1: Data 2: N/A 3: Ground 4: Vcc (+5V) 5: Clock 6: N/A 特に新しいことはありません。DINは特に意味はなく、これを開発した規格団体(Deutsches Institut für Normung、英語ではGerman Institute for Standardization)のことである。 SDL(Shielded Data Link)コネクタとよく似ている。 ![]() A: N/A B: Data C: Ground D: Clock E: Vcc (+5V) F: N/A ユニバーサル・シリアル・バス(USB)コネクタは、さまざまなデバイスで使用されている規格です。USBデバイスを直接操作するのは、かなり複雑なトピックです。USBは4つのピンで構成されています。1: Vcc (+5V), 2: Data-, 3: Data+, 4: Ground. USBレガシーサポートは、USBポートを搭載した最新のコンピュータのほとんどで使用されています。このため、これらのコンピュータのマザーボードは、USBキーボードやマウスをPS/2キーボードやマウスとしてエミュレートすることができます。 このため。PS/2互換インターフェイスを使用したUSBキーボードやマウスとの通信は動作します。つまり、USBキーボードやマウスをお持ちの方でも、このチュートリアルのコードとデモは、マザーボードが提供するエミュレーションのおかげで、問題なく動作します。 このように、キーボードとコンピュータの間のインターフェースは、それほど複雑ではありません。キーボードコントローラとキーボードエンコーダの間でデータをビットとして送信する方法を提供するだけです。 データはマザーボード上のオンボードまたは統合キーボードコントローラに送られます。キーボードコントローラーが制御します。 キーボードコントローラーシステムケース内のキーボードコントローラは,通常,8042キーボードコントローラをそのまま使用しています。キーボード・コントローラは、キーボードのプロトコルを介してキーボード・エンコーダとインターフェイスし、そのインターフェイス方法を提供します。ほとんどの新しいシステムでは、キーボードコントローラは独立した集積回路(IC)ではなく、フロッピーディスクコントローラ(FDC)、パラレルポートインターフェース、シリアルポートインターフェース、マウスインターフェースも収容するマザーボードのスーパー入出力(IO)コントローラの一部になっています。ほとんどの新しいシステムのスーパーIOコントローラは、マザーボードのサウスブリッジの業界標準アーキテクチャ(ISA)ではなく、低ピンカウント(LPC)バスを使用しています。スキャンコードスキャンコードとは、キーの状態を表すデータパケットです。キーが押されたり、離されたり、押さえられたりすると、スキャンコードがコンピュータに搭載されたキーボードコントローラに送信されます。スキャンコードには、2つのタイプがあります。メイクコードと ブレイクコードです。メイクコードは、キーが押されたり、押されたままになったときに送信され、ブレークコードは、キーが離されたときに送信されます。キーボードの各キーには、固有のメイクコードとブレイクコードがあります。すべてのスキャンコードを表す数字のセットが、キーボードのスキャンコードセットを構成しています。キーボードが使用できるスキャンセットは、一般に3種類あります。しかし、スキャン値はランダムであるため、どのスキャンセットを使用しているかを簡単に判断する方法はありません。このため、ルックアップテーブルを使って、スキャンコードが表すキーを決定する必要があります。 それでは、スキャンコードのテーブルを見てみましょう。注意: これらのテーブルは重要です!キーボードでどのキーが押されたかを判断するために使用します。また、これらのテーブルのスキャンコードはすべて16進数です。 これらの表はかなり大きいので、別のリソースとして置くことにしました。リソースセクションにあるテーブルをご覧ください。 例を見てみましょう。キーボードでshift+Aキーを押した場合、あなたのコンピュータに送信されるメイクコードは何でしょうか?まず、shiftキーが押され、次にAキーが押されます。次にAキーが離され、その後シフトキーが離されます。スキャンコードセットが最近のキーボードのデフォルトのスキャンコードセットであると仮定すると、左シフトキーのメイクコードは0x12、ブレークコードは0xF0と0x12になります。Aキーのメイクコードは0x1C、ブレークコードは0xF0, 0x1Cとなります。したがって、このイベントが発生すると、次のようなスキャンコードがコンピュータに送信されます。 上記を見ると、送信されるスキャンコードは0x12、0x1C、0xF0、0x1C、0xF0、および0x12であることがわかります。 キーを押したままにしておくと、そのキーはタイプミスになります。つまり、キーボードは、キーを離すか、別のキーを押すまで、キーのメイクコードを送り続けます。試してみましょう。お気に入りのテキストエディタを開き、あるキーを押したままにします。しばらくすると、同じ文字がもう一つ現れ、その後にその文字が長く続きます。タイプマティックディレイは、タイプマティックモードに入るまでの待ち時間を秒単位で、タイプマティックレートは、コンピュータに送信する1秒あたりのキャラクターメイクコードの量を決定するものです。タイペマティックモード中は、文字データのバッファリングは行われません。 複数のキーを押している場合は、最後に押したキーだけがタイペマティックモードになります。 スキャンコードはとても重要な機能です。スキャンコードがオンボードのキーボードコントローラーに送信されると、キーボードコントローラーはスキャンコードを内部メモリーに格納します。その後、キーボードコントローラは、その割り込み要求(IR)ラインをハイにトグルします。この割り込み線がプログラマブル割り込みコントローラ(PIC)によってマスクされていない場合、IRQ 1が発火します。IRQがマスクされていても、リードバッファはソフトウェアで読むことができるので、スキャンコードを読めば、今どのキーが離されたか、押されたかを判断することができる。 キーボードインタフェース。デバイスドライバの開発この章では、すでに多くのことを取り上げてきました。インターフェイスデバイスとしてのキーボードの歴史、QWERTYキーボードレイアウト、キーボードの内部を見て、キーボードがどのように機能するか、それを機能させる主要な構成要素について見てきました。また、スキャンコードセットとキーボードのプロトコルについても説明しました。まだ、すべてを理解していなくても心配しないでください。これから数回に分けて、さらに詳しく見ていきます。また、キーボード用のデバイスドライバも開発する予定です。かっこいいでしょう?このセクションのすべてのコードは、最終的なデモにも含まれます。キーボードインタフェース。ポーリングキーボードには、キーボードエンコーダとマザーボード上のキーボードコントローラの2つのコントローラがあることを、前のセクションで説明しました。この章では、1つのハードウェアデバイスを制御するために、複数の異なるコントローラとインターフェイスする必要があります。その通りです。これらのコントローラの両方と通信することができます。まあ、そんなところです。キーボードエンコーダにコマンドを送るとき、オンボードのキーボードコントローラに送りますが、キーボードプロトコルでキーボードエンコーダに再ルーティングされます。さて、これで両方のコントローラと通信できるようになりました。なんて楽しいんでしょう。両方のコントローラがお互いに動作していることを知ると、お互いに通信することもできます。キーボード・エンコーダは、オンボードのキーボード・コントローラにいろいろなコードを送って記憶させることができます。これらはスキャンコードであったり、エラーコードであったりします。これは私達がまたキーボード エンコーダーおよびオンボードのコントローラーの両方からの情報を受け取ることを可能にします。 これらの通信はすべて、IN命令とOUT命令を使用して、IOアドレス空間にマッピングされたコントローラポートに読み書きすることで行われます。これらのポートが何であるかを気にする必要はありませんが、コントローラで IO マッピングがどのように機能するかを理解することは、ここでより重要になります。 これは、キーボードとのインターフェイスの1つの方法です。コントローラと手動で通信して、キーが押されたか、上げられたか、などをチェックすることができます。これはキーボードのポーリングと呼ばれています。このように、キーボードから最後のスキャンコードを得るには、キーボードコントローラにポーリングする必要があります。 キーボードのインターフェイス割り込み要求(IRQ)PICのチュートリアルで、キーボードコントローラは割り込みラインを使用するように設定できることを覚えましたか? キーが押されたり離されたりすると、キーボードコントローラはIRQ 1を発行するように設定できます。これはキーボードとのインターフェースとして最も一般的な方法です。IRQ 1が発生したときはいつでも、スキャンコードが実際にキーボードコントローラに送信されたかどうかをテストする必要があります。これは、キーボードコントローラをポーリングして、最後のスキャンコードを取得することによって行われます。 詳細8042キーボードマイクロコントローラ![]() The original 8042 Microcontroller これは、キーボード・エンコーダとインターフェースするマイクロコントローラです。キーボード・コントローラは、もともと8042マイクロコントローラで始まったマイクロコントローラ・ファミリーの一部です。最近のコンピューターでは、キーボード・コントローラーは独立した集積回路(IC)ではなく、その機能はマザーボード自体によってエミュレートされています。つまり、コントローラーの機能はマザーボードのチップセットに統合されているのです。 キーボード・コントローラーは、2つのモードで動作することができます。AT互換モードとPS/2互換モードがあり、どちらのモードで動作させるかによって、外部とのインタフェースが異なります。 まず、コントローラの外観を見てみましょう。 ![]() はい。それです。P10-P17ピンがコントローラーの入力ポートです。P20-P27はコントローラーの出力ポートです。これらのピンの正確な意味は、コントローラの動作モードによって異なります。 これらのポートについては、コマンドで操作できるため、後で詳しく説明します。 他のほとんどのピンは、私たちにとって重要ではありません。他のピンのほとんどは、私たちにとって重要ではありません。私は、完全性を期すために、ここにそれらを加えることにしました。 XTAL 1と XTAL 2は 水晶発振器入力端子です。XTAL 1は、CLKを外部で駆動する場合、グランドに接続することもできます。同様に、XTAL 2は、CLKが外部で駆動されている場合、CLKに接続することができます。 RESETは、Low(0)にするとコントローラがリセットされます。 SSは、マイコンのシングルステップ端子です。CSは、データレジスタポートインタフェースに使用されるチップセレクト端子です。EA(No, not the company ;)は、外部アクセス入力ピンです。OTP(One Time Programmable)ROMをディセーブルし、外部からコントローラへコマンドを送信することができます。 RD出力イネーブル入力です。 データレジスタポートインタフェースに使用します。A0はコマンド/データレジスタ選択入力です。 データレジスタポートインタフェースに使用します。WRはライトイネーブル入力ラインです。 データレジスタポートインタフェースに使用します。 SYNCはクロック出力信号です。D0~D7はデータレジスタポートインタフェースで使用します。GNDはグランドピン(Vss)です。Vddは+5V 入力端子です。PROGは、I/Oエクスパンダアクセス時の8243へのアドレス/データストローブとして使用されます。Vccは、もう 1 つの +5V 入力ピンです。 キーボードコントローラは、キーボードの動作を制御するためのインターフェイスを提供します。これは、ポートI/O空間にマッピングされたポートを介してキーボード・コントローラと通信することによって行われます。ご存知のように、キーボードコントローラと通信するためには、INとOUTの命令を使い、それがどのようにマッピングされているかを知る必要があるのです。それでは、見てみましょう。 ポートマッピングi86アーキテクチャでは、キーボードと通信するために以下のポートが使用されます。
この表は悪くないと思います;)基本的にはキーボード・エンコーダにコマンドを送るには、ポート0x60にコマンド・バイトを書き込む。ただし、その前にキーボード・コントローラのステータス・レジスタのビット0(出力バッファが一杯)が0であることを確認し、安全であることを確認する必要があります。もし、キーボードコントローラのステータスレジスタのビット1(入力バッファフル)が1であれば、データは入力バッファにあり、読み出し可能な状態になっています。ポート0x60から読み出すと、キーボード・エンコーダからこのデータを取得することができます。キーボード・エンコーダから読み出されるデータは、通常、キーボードから得られるものですが、特定の値を返すようにマイクロコントローラを再プログラムすることもできます。 ポート0x64に値を書き込むと、オンボードのキーボードコントローラにコマンドバイトを送信できます。 ポート0x64から読み出すと、キーボードコントローラのステータスバイトを取得できます。 これらすべてを知っていれば、これらのコントローラとの間でコマンドバイトやデータの読み書きを行うルーチンを簡単に提供することができます。ここでは、これらのコントローラで使用されるIOポートを抽象化しています。
これらのコントローラと対話するために使用されるルーチンは、コントローラのコマンドに関するいくつかの知識が必要であるため、まだ説明しないことにします。 レジスタステータスレジスタこれは、20番目のアドレス・ラインを有効にすることを取り上げたときと同じように見えるかもしれません。ステータス・レジスタを読むには、単にI/Oポート0x64から読み込みます。返される値は、特定のフォーマットに従った8ビット値です。このフォーマットは、コントローラのモードによって少し異なります。再度、紹介します。重要なものは太字にしました。
キーボードの現在の状態を判断し、何ができて何ができないかを確認するために、ステータス・レジスタを読み込む必要があります。例えば、キーボードが接続されていない状態で、キーボードにコマンドを送ろうとは思いません。そこで、コマンドを送る前に現在の状態を読み込んでテストしたい。 また、プロセッサが命令を実行するスピードは、キーボードコントローラが応答できるスピードよりはるかに速いことも考慮する必要があります。このため、キーボードコントローラが次のコマンドに対応できるようになるのを待つ必要がある場合が多くあります。これを確認するには、ステータス・レジスタを読み込んでビット0(Output Buffer Full)をテストし、次のコマンドを送信してよいかどうかを確認する必要があります。これを行わないと、前のコマンドは破棄され、新しいコマンドが実行され始めますが、これは好ましくないかもしれません。 別のコマンドを送信したり、コントローラからデータを読み取る前に、コントローラの準備が整うのを待つことが重要です。 ステータス・レジスタの読み書きにビット・マスクを使用することができます。本章の最後のデモで使用されたものを示します。各ビットが上に示したリストの正しいビットとどのように共起しているかに注意してください。 素晴らしい!あとは、キーボードコントローラのステータスレジスタをポート0x64から読み出し、上記のビットマスクに基づいて、好きなビットをテストしてステータスをチェックするだけです。 つまり、キーボードコントローラのステータスレジスタから読み出すには、次のようにすればよいのです。
読み書きを行う。入力バッファコマンドを送信するには、まずキーボードコントローラの準備が整うのを待ちます。 これは、入力バッファが一杯になったかどうかを確認することで行われます。キーボードコントローラのステータスレジスタを読み、ビットをテストすることによって、これをテストします。もし0なら、バッファは空なので、コマンドバイトを送ります。(この情報はすべて、上に示したステータスレジスタのビットレイアウトの中にあることを思い出してください)。キーボードエンコーダは、下図に示すように非常によく似ています。キーボードエンコーダに送られるコマンドは、まずキーボードコントローラに送られることを覚えておいてください。このため、キーボード・コントローラがコマンドに対応できる状態であることを確認する必要があります。
キーボードエンコーダコマンドポート0x60にコマンドバイトを書き込むと、キーボードコントローラはその値を直接キーボードエンコーダーに送信します。以下にコマンド・バイトのリストを示します。
小さなコマンドはすべて上記の表に記載されていますが、より複雑なコマンドを詳しく見てみましょう。 コマンド0xED - 発光ダイオード(LED)の設定このコマンドは、キーボードのLEDを設定するために使用されます。ポート 0x60 に書き込まれた次のバイトは、キーボードの LED を更新し、以下に示すフォーマットに従います。
他のビットはすべて0でなければなりません。 このコマンドは、ちょっと遊んでみるのも楽しいかもしれません;)以下は、デモがキーボードのライトを更新するために使用するルーチンの例です。パラメータがtrueかfalseかによってビットをセットしたりクリアしたりしていることに注目してください。また、最初にコマンドバイトをキーボードエンコーダーに書き、次にデータバイトを書き込んでいることにも注目してください。これらは両方ともキーボードエンコーダのコマンドレジスタに送られます。KYBRD_ENC_CMD_SET_LED は0xED(私たちが使っているコマンドバイト)用の定数です。魔法は使っていません :)
コマンド 0xF0 - オルタネートスキャンコードセット(PS/2 のみ)このコマンドは、使用するスキャン・コード・セットを設定します。ポート0x60に書き込まれる次のバイトは、次のフォーマットのバイトでなければなりません。
コマンド 0xF3 - オートリピート・ディレイ・リピート・レート設定このコマンドは、オートリピートディレイとリピートレートを設定します。ポート0x60に書き込まれる次のバイトは、以下のフォーマットである必要があります。
他のビットは全て0を指定。 リターンコードご存知のように、キーボード・エンコーダは、システムのオンボード・キーボード・コントローラと通信しています。返される値のほとんどはスキャンコードですが、時にはエラーが返されることもあります。これらの値は、キーボードデコーダからポート0x60を通じてシステムに送信されます。戻り値は、以下のいずれかとなります。
オンボードキーボードコントローラコマンドこれらのコマンドのいくつかは、A20の章ですでに見ています。しかし、ここに挙げたコマンドの多くは新しいもので、中には非常に低レベルのものもあります。つまり、これらのコマンドのいくつかは、コントローラに接続された特定のラインを制御することができます。このため、コントローラのラインとキーボードデバイスとのインターフェイスを取り上げなければならなかったのです。その他のコマンドは、コントローラーの内部RAMの読み書きを行うものです。
ずいぶんたくさんのコマンドがありますね。すべてのコマンドを網羅するには、かなりの時間がかかると思いませんか?A20のコマンドは、A20の章ですでに説明しました。このシリーズでは移植性を重視しているため、上記のような一般的なコマンドのみを取り上げますが、興味のある読者はここで取り上げていないコマンドの情報を探してみてください。 次のセクションまで、サンプルコードを取り上げるつもりはありません。ここでは、コマンドそのものを取り上げ、次のセクションから参照することにします。 コマンド0x20 - コマンドバイトの読み出しとコントローラRAMの読み出し上の表を見てください。0x20〜0x3Fのコマンドは、コントローラのRAMを読み出すのに使われていることにお気づきでしょうか?それなのに、コマンド0x20は、コマンドバイトの読み出しにも使われています。どうなっているのでしょうか?実は、この2つのコマンドは同じものを指しています。コマンド・バイトは、コントローラのRAMに格納されています。つまり、コマンドバイトを読むということは、コントローラの内部RAMから読むということです。どうです? コントローラのRAMから読み出す場合、コマンドの最後の6ビットは、RAM内の読み出す場所を参照します。ある種の MCA システムでは、RAM 内の 32 のロケーションすべてにアクセスすることができます。他のシステムでは、0、0x13-0x17、0x1D、および 0x1F のバイトにのみアクセスできます。 これらの位置は次のとおりです。
コマンドバイトは、より重要なバイトである。見た目ほど複雑ではないので、ご安心ください。
このコマンドは必要ないと思うので、ルーチンは書いていません。 コマンド 0x60 - ライトコマンドバイトとコントローラ RAM の書き込みコマンドバイト 0x60 - 0x7F は、上記と非常によく似ており、上記と同じ RAM ロケーションに書き込むことができます。より重要なのは、コントローラ RAM のバイト 0(コマンドバイト、覚えていますか)を読むことで、これはコマンドバイト 0x60 を送信することで実行可能です。上記のコマンドと同様に、エンドデモのためにこのコマンドのルーチンは書かれていません。 コマンド0xAA - セルフテストこのコマンドにより、コントローラはセルフテストを実行します。このコマンドは、ポート 0x60 を通して読むことのできる出力バッファーに結果を返します。テストが成功した場合は0x55、失敗した場合は0xFCが返されます。以下はルーチンの例です。最初にキーボード・コントローラにKYBRD_CTRL_CMD_SELF_TESTコマンド(コマンド0xAA)を送信していることに注意してください。その後、キーボード・コントローラの出力バッファがデータで満たされるのを待ちます。これにより、テストが完了したかどうかがわかります。テストが完了すると、出力バッファの結果が0x55であれば真(テスト成功)、そうでなければ偽(テスト失敗)を返します。
コマンド 0xAB - インタフェーステストこのコマンドは、コントローラとキーボード間のシリアルインターフェイスをテストします。テストの結果は、ポート0x60で読み取ることができる出力バッファに格納されます。結果は以下のいずれかになります。
ご覧のように、これらはすべてハードウェアのエラーです。エラーが発生した場合は、キーボードを無効にし、リセットすることをお勧めします。それでもダメな場合は、キーボードが故障している可能性があります。 コマンド 0xAD - キーボードを無効にするこのコマンドにより、コントローラはキーボードクロックラインを無効化し、コマンドバイトのビット4(キーボードイネーブル)を設定します。コマンド・バイトのフォーマットについては、コマンド・バイトの読み出しのセクションを参照してください。つまり、このコマンドはキーボードを無効化するものです。 システムがキーボードの現在の状態を把握できるように、キーボードの現在の状態を保存しておくとよいでしょう。これはdemosのキーボードドライバで_kkybrd_disableを通して行われます。
コマンド 0xAE - キーボードの有効化このコマンドを使用すると、コントローラはキーボードクロックラインを有効にし、コマンドバイトのビット4(キーボードイネーブル)をクリアします。コマンド・バイトのフォーマットについては、「コマンド・バイトの読み出し」の項を参照してください。つまり、このコマンドはキーボードを有効にするものです。 以下は、デモのルーチンの例です。このルーチンがいかに簡単であるかに注目してください :)
コマンド 0xC0 - 入力ポートの読み込みこのコマンドは、入力ポート(コントローラ上のラインP10-P17)を読み取り、バイナリ値をポート0x64を通して読み取ることができる出力バッファにコピーします。このポートが持つラインはまだ見ていませんので、これから見ていきましょう。
上記を見ると、最近のパソコンではこのコマンドはあまり役に立たないことがわかると思いますので、複雑に見えても気にしないでください。Bit 0, 1, 2, 3 はもう使われていない。ビット4は、最近のコンピュータは512KB以上のRAMを持っているので、ほとんど役に立ちません。Bit 5は、キーボードテストのためにジャンパがインストールされているかどうかをテストするために使用されます(ほとんどのユーザーはそんなことはしませんが)。ビット6はビデオアダプターから情報を得られるので不要です。ビット7はほとんどのユーザーがキーボードのロックを望んでいないので、ほとんど必要ありません。とても便利なコマンドでしょう?ほとんどのコンピュータで使えるわけではありません。 このコマンドは非常に便利なので(あるいはそうでなくても)、私はこのコマンドのルーチンを書かないことにしました。 コマンド0xD0 - 出力ポートの読み出しこのコマンドは、コントローラの出力ポート(P2)から読み出し、その結果をポート0x64の出力バッファーに格納するよう指示します。このコマンドを発行した後にポート0x64から読み出すことで、コントローラの出力ポートのビットをチェックすることができます。コントローラの出力ポートは、コントローラのP20-P27ラインだけです(このことを前に覚えていますか?)。このコマンドが実行されると、これらのラインのバイナリ値が出力バッファに格納されます。 出力ポートのピンとその役割については、まだ説明していません。(A20の章で説明しましたが、詳細ではありません)そこで、ここで説明します。
ここまでのビットは、ほとんど意味がありませんね。これらのビットの多くは、現在のコントローラの動作に関する電子機器レベルのもので、私たちのニーズには無用のものです。最初の2行(ビット0と1)を除いては、システムをリセットするかどうか、あるいは20番目のアドレスラインを有効にするかどうかを制御します。ビット0を読んでも意味がありません。この行はアクティブ(1)でなければならず、通常動作していることを意味します。このビットがないと、システムは再起動します。したがって、ここで唯一の有用なビットはA20ラインです。これは、少なくとも読み出し動作には当てはまります。 このコマンドがポート0x64で発行されると、結果のバイトは出力バッファに置かれ、ポート0x60からバイトを読み出すことで読み出しが可能になります。 A20をすぐにでもディセーブルにしなければならない心配はない。また、キーボードからシステムをリセットする方法もあります。このため、このコマンドは私たちのニーズにはかなり有用であり、私はこのためのルーチンを書かないことにしました。 コマンド0xD1 - 出力ポートの書き込みこのコマンドは出力バッファ(ポート0x60)からバイトをコピーし、コントローラの出力ポート線にバイトを配置します。これらのラインの説明については、前のセクション(Read Output Port Command)を参照してください。ほとんどの場合、起こりうる問題を防ぐために、変更したい特定のビットをビットごとにORし、他のすべてを変更しないようにしたいと思うことでしょう。 このコマンドはいくつかの点で有用である。コントローラによって使用されるIRQを有効または無効にしたり、A20ゲートを有効または無効にしたり、あるいはビット0を設定することによってシステムをリセットしたりすることができます。繰り返しになりますが、変更可能なビットのリストについては、前のセクションを参照してください。 コマンド 0xE0 - テスト入力の読み出しこのコマンドは、コントローラのテストポート線からバイナリ値を取り出し、出力バッファに配置し、ポート0x60を介して読み取ることができるようにコピーします。テストポートは、マイクロコントローラのTEST 0と TEST 1のラインです(本章のコントローラピンアウト図を参照してください)。この章では、テストポートを説明しませんので、説明します。
このコマンドはあまり役に立たないかもしれませんが、コントローラはテストポートがより有用であるかもしれない他のフィールドで使用されるかもしれないことを思い出してください。結局のところ、それはテスト目的のために存在するのです。 コマンド 0xFE - システム・リセットコントローラ出力ポート(ピン P0)のビット 0 をパルスし、CPU をリセットします。 これは基本的に、ビット 0 をリセットするWrite Output Portコマンドを送信するのと同じことを行います。 素敵な方法でシステムをリセットしたい場合は、このコマンドを送信してください。
これはすべてのシステムで動作するとは限らないことを覚えておいてください。動作するかどうかを確認する簡単な方法は、上記のルーチンの後、プログラムがまだ実行されているかどうかを確認することです :) キーボード。繋ぎ合わせる我々は、すでにこのデモのキーボードドライバからルーチンのいくつかを見てきました。キーボード・エンコーダやコントローラとの通信、そして、有効化、無効化、テスト、LED更新、システムリセットなど、いくつかの重要な機能のルーチンを見てきました。これは素晴らしいことですが、すべてを結びつけるいくつかの重要な詳細が欠落しています。では、見ていきましょう。キーボード現在の状態を保存するご存知のように、キーボードのどのキーもいつでも押すことができます。そのため、それぞれのキーが押されているかどうかをスキャンする方法が必要です。ここで良いことは、キーボード・エンコーダがすでにこれを実現していることです!もっと簡単に言うと、キーボードエンコーダはスキャンコードを直接オンボードのキーボードコントローラに送り、IRQ 1を起動します。IRQ 1がマスクされていない限り、IRQ 1に独自の割り込みハンドラをインストールし、キーボードエンコーダからスキャンコードが送信されるたびに通知を受けることができます。これはどういうことでしょうか。キーボードコントローラにスキャンコードが送信されると、いつでも割り込みハンドラが起動されます。これはいつでも起こりうることです。 このため、ハンドラの内部でキーボードコントローラをポーリングしてスキャンコードが何であるかを何とか判断する必要があります。しかし、あるキー(caps lockキーやnum lockキーなど)が押されているときに、別の処理を行いたい場合がある。これらのキーは、押されたときにオンまたはオフになるはずだ。では、shiftなどのキーはどうでしょう?これらのキーは、押したままにしておき、キーを離したときに解放する必要があります。 このため、これらのキーの現在の状態と最後に読み取ったスキャンコードを保存しておき、IRQが復帰した後で再び読み取ることができる方法を考え出す必要があります。これは、いくつかのグローバル変数または構造体に現在の状態を格納し、単にそれらを使用することによって行うことができます。 キーボード割り込みハンドリングこれは重要です。キーストロークとキーリリースごとに、数バイト(スキャンコード)がキーボードコントローラに送信されることを覚えていますか?このとき、キーボードコントローラはプログラマブル割り込みコントローラ(PIC)に信号を送り、IRQ 1を発生させるのです。そうです、この信号によりPICはキーボード割り込みハンドラを実行するのです。割り込みハンドラの目的は、ドライバの現在の状態を更新し、ドライバとシステムで使用できる形式に変換することによってスキャンコードを解読することです。そう、それがすべてです;) 割り込みハンドラは、すべてを結びつけるものです。少し大きいのでこの文章には書きませんが、ぜひ皆さんもご覧になって、どのように動作しているかを確認してください。 キーボード初期化キーボードコントローラは、プログラマブル割り込みのIRQ 1ラインに間接的に接続されていることを思い出してください。PICでIRQを割り込みベクター32(IRQ 0)から始まるようにマッピングしたため、IRQ 1は割り込みベクター33にあります。このため、割り込みベクター33を使用するために、setvectルーチンを使用して割り込みハンドラをインストールする必要があります。他のすべてはとてもシンプルです。現在のドライバの状態(グローバルとして保存されている)をクリアして、kkybrd_set_ledsルーチンを使ってLEDをクリアするだけです。
まとめこの章はこれで終わりです。このデモを発展させて、実際に使えるようにすることは可能です。 しかし、現在できることはかなり限られています。他のプログラムを動かして仕事をさせることができたら便利だと思いませんか?ファイルシステム全体の構造を抽象化することは非常に複雑なテーマですが、1つのディスクからファイルをロードすることに焦点を当てることは可能です。しかし、問題が発生しました。最低限、ディスクからファイルをロードできるようにするためには、まずフロッピーディスクコントローラ(FDC)をプログラムしなければならないのです。これは次の章のトピックです。そこでお会いできるのを楽しみにしています。:) |