x86続き。割り込みについて。CPU部分の次はその先の割り込みコントローラ。
僕を含めた世の中の多くの人の不幸は、一番最初に見た割り込みルーチンが
i8259だったことじゃないだろうか。CPU部分の複雑さに加えて、i8259の設計の
古さ。元々8080/8085用だったのを拡張したものだ。当時はレジスタがあまり使
えなかったので、その中でやりくりするためにどうしても呪文的なものになっ
てしまうし、拡張による見通しの悪さ。ここで10年来のモヤモヤを解決したい。
i8259 内部にレジスタが ISR In Service Register IMR Interrupt Mask Register IRR Interrupt Request Register. 3つある。IMRはOCW1により直接R/W可能。 ISR,IRRはOCW3コマンドを書き込んでどちらかを読むかを指定し、A0を0で読み 込む。その状態は内部に保存されているので、以降のリードは前回指定したも のが読まれる。 レジスタのアドレスは二つ。A0がActiveか否かをi8259がとっているだけで それぞれに特有の意味はない。 A0 D4 D3 0 1 0: ICW1 Initialize start. 1 0 0 : OCW1 0 0 0 : OCW2 0 0 1 : OCW3 A0がActiveの時はD0-D7全てが使えるが、A0がActiveでない時はD3,D4でコマンド を決定するため、設定に使えるのはD0,D1,D5-D7になる。 i8259のコマンドには ICW(initialization command words)1-4 OCW(operation command words)1-3 の7つがある。ICWはICW1に設定した後に順々にA0をアクティブにして書き込みを 続けることでICW2,ICW3,ICW4と設定していく。 カスケードは一段まで。カスケードしたi8259との通信ラインはCAS0 CAS1 CAS2 この3本によってそれぞれスレーブは自分宛てかどうかを判断する。 マスターの場合とスレーブの場合で、i8259内部のプログラムが異なる。これは SP#ピンをGNDに落とすか、Vccにプルアップするかで選択される。(SP Slave Program) このピンはEN#と共用になっている。EN#はバスにバッファICをつける必要があ る時に、そのバッファICにEnableを送るもの。その時はICW4のbit2で、その i8259がマスターなのか、スレーブなのかをを指定する。これはPC/ATでは使われ ていない機能。 i8259の割り込み入力ピンIR0-IR7は番号が小さいほど優先度が高い。これは 多少、設定で変更することができる。(Automatic Rotation, Specific Rotation) 動作モード Fully Nested Mode 割り込みが入るとその優先度以下の割りこみはブロックされる。特に設定しな ければこれがデフォルト。 Special Fully Nested Mode Fully Nested modeでスレーブからの割り込みが起こると、マスターはスレーブ が接続された優先度以下をブロックする。そうするとスレーブ全体でブロック されたことになるのでスレーブの中で、現在サービス中の割り込みより高い優 先度の割り込みがおきてもブロックされてしまう。このモードではそれを解決 し、マスターはスレーブの優先度未満の割り込みをブロックすることにする。 これを使った場合はEOIに注意。specific-EOIで注意深く発行する。 Automatic End of Interrupt Mode. 自動的にnon-specific EOIを2回目のINTAパルスのタイミングで発行する。 優先度付き多重割り込みを実装するならば、使わない方がいい。 Special Mask Mode 割り込みをAckしてからEOIが発行されるまでの間に、本来ブロックされる 低い優先度の割りこみを多重割りこみさせたい時に、設定する。 Automatic Rotation 優先度はIR0-IR7で固定だが、一度サービスした優先度を最低に内部的に設定 することで均等に割り込みを受けつける。 OCW2 R SL EOI 0 0 1 non-specific EOI 0 1 1 specific EOI -> L0-L2でレベルを指定 1 0 1 rotate on non-specific EOI 1 0 0 rotete in 'automatic EOI mode' (set) 0 0 0 rotate in 'automatic EOI mode' (clear) 1 1 1 rotate on specific EOI -> L0-L2でレベルを指定 1 1 0 set priority -> L0-L2で指定されたレベルが最低優先度になる。 0 1 0 nop non-specific EOI: fully nested modeの場合、割り込みサービスを受けている のは一番高い優先度のものなので、それにEOIを発行。 specific EOI: fully nested modeではない場合、必ずしもサービスを完了した のが一番高い優先度のものではないのでL1-L2でレベルを指定してEOIを発行。 Pollコマンド OCW2のPビット(2bit)をセットし、その後リードすると、D0-D2にIRRのうち 一番高い優先度が3bitにエンコードされてD0-D2にあらわれる。D7が立って いると割り込みがある。 ---------------------------------------- 実際の初期化 ---------------------------------------- // Master // Start ICW outb (0x20, ICW1_START | ICW1_IC4); + IC4を立てておくとこのICW4の設定まで進む。(しなければICW2、 あるいはICW3までになる) + !SNGL カスケードしているので立てない。カスケードしていない場合は ICW3の設定がスキップされる。 + !ADI これはMCS-80/85 (8080,8085のこと)用の設定で8086/8088用には 意味がない。 + !LTIM エッジトリガ。これはISAだからと言いたいところだけど、正確に は歴史的現実的事情か。ISAの割り込み共有については原理的には不可能じゃな いようだ。この本
に記述がある。 // ICW2 outb (0x21, 0x20); // vector address 0x20 + 8086/8088モードの場合はD3-D7にベクタを設定する。D0-D2の3bitが割り 込み番号になる。IDTは0x20からユーザが自由に使えるエリアなのでここに 設定。 // ICW3 outb (0x21, (1 << 2)); // IRQ2 is cascaded. + カスケードしているピンを指定。ICW1でSNGLならここはスキップされる。 // ICW4 outb (0x21, ICW4_AEOI | ICW4_uPM); + uPM 8086/8088モード。 + AEOI CPUからのEOIを待たずに自動的にEOIを発行。(これはこのOSが多重割 り込みなしのシンプルな設計なので) + !MS + !BUF PC/ATはSP#/EN#ピンをGND/Vccに接続した使いかたなので必ず0 + !SFNM Special Fully Nested Mode これは使わない。AEOIを使っているので。 同様にスレーブ。 // Slave // Start ICW outb (0xa0, ICW1_START | ICW1_IC4); // ICW2 (!ICW1_SNGL) outb (0xa1, 0x28); // vector address 0x28 // ICW3 (slave ID) outb (0xa1, 0x02); // my ID is 2 + スレーブの場合はICW3の設定がマスターと異なる。受信すべきIDを設定。 // ICW4 outb (0xa1, ICW4_AEOI | ICW4_uPM);// 8086 mode. Auto EOI mode. // Intialization completed. この後、OCWでは // OCW1 mask interrupt. outb (0x21, 0xff); outb (0xa1, 0xff); + OCW1:割り込みマスクの設定。まずは全部マスク OCW2はEOIの発行、優先度ローテーションの設定/解除、特定の優先度の変更 ができるが、特に設定はなし。 OCW3ではSpecial Mask Modeと、A0=0でリードした時にISRを読むかIRRを読むか の設定ができるが、特に設定はなし。
