このページはOS-Wikiのページのコピーです。
PIT 8254のページ †
- PITは「Programmable Interval Timer」の略
- AT互換機に1個、TONWSには2個(ただし8253)、PC-9801には1個(ただし8253)
- 8253にはリードバックコマンドがない(それ以外は同じ)
- AT互換機ではPITに1.19318MHzのクロックが与えられている。
- TOWNSではPITに307.2KHz(ch0-2)と1.2288MHz(ch4)のクロックが与えられている。
- さらに上位機種には1.00MHzのインターバルタイマ2がある(註:これは8254系ではない)
- PC-9801はPITに2.4576MHz(システムクロック5MHz系時)もしくは1.9968MHz(システムクロック8MHz系時)のクロックが与えられている。
関係するI/Oポート †
AT互換機 †
- 0x0040 (8bit, R/W):カウンタ0 (IRQ0用)
- 0x0041 (8bit, R/W):カウンタ1 (メインメモリ・リフレッシュ用)
- 通常はモード2でカウント0x18を設定 --- メモリやチップセットやBIOSによっては違う
- 0x0042 (8bit, R/W):カウンタ2 (BEEP用)
- 通常はモード3 --- モード2でも多分音は出るけど、音色は変わるでしょう(このカウンタをモード3以外に設定することがハード的に可能なのかも分かりませんが)
- 0x0043 (8bit, W):コントールレジスタ
- 0x0061 (8bit, R):システムポート
- bit0:カウンタ2のGATEピンの状態
- bit1:スピーカイネーブルピンの状態
- これとカウンタ2のOUT値のANDがスピーカに接続されている
- bit2:ライト時のbit2の値が読める
- bit3:ライト時のbit3の値が読める
- bit4:(メモリリフレッシュが行われるたびに値が反転)
- bit5:カウンタ2のOUTピンの状態
- bit6:(ISAのIOCHK信号がアサートされてNMIが発生すると1になる)
- bit7:(メモリパリティエラーが発生すると1になる)
- 0x0061 (8bit, W):システムポート
- bit0:カウンタ2のGATEピンへの出力値
- bit1:スピーカイネーブルピンへの出力値(1でBEEP-ON)
- bit2:(1にすると、メモリパリティエラーを検出したときにNMIが発生)
- bit3:(1にすると、ISAのIOCHK信号でNMIが発生)
- bit4-7:リザーブ(0にするのを推奨)
TOWNS †
- 上位機種は合計で8カウンタをもち、そのうちの3つがIRQ0の発生要因として使用可能
- この他にもFM音源部にタイマ割り込みがある
- とくに1.00MHzのインターバルタイマ2とフリーランタイマレジスタは非常に有用である(8254系ではないので使いやすい)
- IRQがレベルトリガになっていることも含めて、ここまでタイマ周りが優秀なハードウェアは他にはないと思われる
- 0x0040 (8bit, R/W):カウンタ0 (IRQ0用 - インターバルタイマ用)
- 0x0042 (8bit, R/W):カウンタ1 (IRQ0用 - I/O制御用)
- 0x0044 (8bit, R/W):カウンタ2 (BEEP用)
- 通常はモード3 --- モード2でも多分音は出るけど、音色は変わるでしょう(このカウンタをモード3以外に設定することがハード的に可能なのかも分かりませんが)
- 0x0046 (8bit, W):コントールレジスタ(ch0-2用)
- 0x0050 (8bit, R/W):カウンタ3 (リザーブ)
- 0x0052 (8bit, R/W):カウンタ4 (RS-232Cのボーレート用)
- 0x0054 (8bit, R/W):カウンタ5 (リザーブ)
- 0x0056 (8bit, W):コントールレジスタ(ch3-5用)
- 0x0060 (8bit, W):割込み制御レジスタ
- bit0:ch0のタイムアウト割り込み許可(0でマスク、1で許可)
- bit1:ch1のタイムアウト割り込み許可(0でマスク、1で許可)
- bit2:BEEP出力制御(1でBEEP-ON)
- bit3-6:リザーブ(0で書き込むことを強く推奨)
- bit7:1でch0のタイムアウトフラグをクリア
- 0に戻す必要はない。書き込み時に1だと、そのときにタイムアウトフラグクリア動作が行われる、ということにすぎない。0だとその動作が起きないだけ。
- TOWNSの割り込みは全てレベルトリガであり、この動作でタイムアウトフラグを下げないと、IRQ0がかかりっぱなしになる(もちろん、ch0の割り込みそのものが不要なら、bit0を0にすればよい)。
- なお、ch1にはタイムアウトフラグを下げるためのコマンドビットはない。新しいカウントを書き込むと、自動的にタイムアウトフラグが下がる。これはch1は非周期的な割り込みを扱うために用意されたものであって、毎回カウンタの書き換えが必要だろうという設計思想に基づいている(すばらしい)。カウンタを書き換える際には、カウンタだけではなく、コマンドレジスタ、カウンタ、(カウンタ)、の順にアクセスすることをおすすめする。
- 0x0060 (8bit, R):割込み要因レジスタ
- bit0:ch0のタイムアウトフラグ(1でタイムアウトしたことを示す、0はカウント中)
- bit1:ch1のタイムアウトフラグ(1でタイムアウトしたことを示す、0はカウント中)
- bit2:ch0のタイムアウト割り込み許可、の設定値が読める
- bit3:ch1のタイムアウト割り込み許可、の設定値が読める
- bit4:BEEP出力制御、の設定値が読める
- 0x0026 (16bit, R):フリーランタイマレジスタ
- bit0-15:カウント値
- これは1マイクロ秒ごとに1ずつカウントアップされるレジスタで、たとえばある処理を挟んで2回読みとって差を求めることで、65ms以内の経過時間を測定するなどができる。非常に有用であるが、HG、HR、UG以降でしか利用できない。
- 0x0068 (8bit, W):インターバルタイマ2制御レジスタ
- このレジスタは非常に有用であるが10F以降でしか利用できない
- bit0-6:リザーブ(0で書き込むことを強く推奨)
- bit7:インターバルタイマ2のタイムアウト割り込みマスク(0で許可、1でマスク)
- 0x0068 (8bit, R):インターバルタイマ2制御レジスタ
- このレジスタは非常に有用であるが10F以降でしか利用できない
- bit0-4:リザーブ
- bit5:タイムアウトフラグが0になっていないときにさらにタイムアウトすると1になる(オーバフラグ)
- bit6:タイムアウトフラグ(1でタイムアウトあり)
- bit7:インターバルタイマ2のタイムアウト割り込みマスク、の設定値が読める
- このレジスタをリードすると、リード直後にタイムアウトフラグとオーバフラグは0クリアされる
- 0x006a (16bit, R/W):インターバルタイマ2周期レジスタ
- bit0-15:割り込み周期設定値(マイクロ秒単位で設定)
- このレジスタは非常に有用であるが10F以降でしか利用できない
- 0x006c (8bit, W):1マイクロ秒WAITレジスタ
- このレジスタは非常に有用であるが10F以降でしか利用できない
- bit0-7:リザーブ(0で書き込むことを強く推奨)
- このレジスタへの書き込み動作で、1マイクロ秒のwaitがかかる
- 0x006c (8bit, R):1マイクロ秒WAITレジスタ
- このレジスタは非常に有用であるが10F以降でしか利用できない
- bit0-6:リザーブ
- bit7:常に0(ここが1だと10Fより前のモデルであることを意味する)
PC-9801 †
- 0x0071 (8bit, R/W):カウンタ0 (IRQ0用)
- 0x0073 (8bit, R/W):カウンタ1 (メインメモリ・リフレッシュ用の機種と、BEEP用の機種とがある)
- 0x0075 (8bit, R/W):カウンタ2 (BEEP用)
- 0x0077 (8bit, W):コントールレジスタ
- 0x3fdb (8bit, R/W):カウンタ1 (多くの機種のノーマルモードでは、こちらでないとアクセスできない。BEEP用)
- 0x3fdf (8bit, W):コントールレジスタ
- ここにライトすることと0x0077にライトすることは全く同じ
8254の基礎 †
- 8524は内部に16bitのカウンタを3つ持っている。それぞれに外部からクロックが与えられ(でもたいていは同一クロックを与えているようだけど)、またそれぞれを別々のモードで駆動させることができる。
- カウントは原則としてデクリメントであり、周期的なモードではカウントが0になった瞬間に設定値が再ロードされる(つまり、カウント値0という値は読み出せない)。
- ハードウェア的には、以下の3つの信号ピンが関係している(これらはカウンタの個数だけある)。
- CLK:クロック(カウンタをデクリメントするためのクロック)
- GATE:ゲート(カウンタを始動させたり一時停止させたり再開させたりするためのピン)
- OUT:アウト(カウント値によって制御されるPITの出力ピン、これがIRQのトリガになったりBEEP出力になったりしている)
- カウントは、2進数カウントモードと、BCDカウントモードがある。純粋な8254にはBCDモードがあるが、PCのチップセットに集積されたものについては、BCDモードが省略されている可能性があるのでお勧めできない。
- 8254は、現在のカウント値をラッチによって読み取ることができるが、設定値を読取る方法はない。設定値を知りたければ、カウンタを何度もリードして監視して、最大値を取得するしかない。
- リードバックコマンドを使って、少ないサンプリング数で正確な設定値を推測するテクニックもある。
- コントロールレジスタの各ビットの意味は次の通り。
- bit0:カウントモード
- bit1-3:カウントモード
- 000:モード0(ターミナルカウント)
- 001:モード1(プログラマブルワンショット)
- x10:モード2(レートジェネレータ)
- x11:モード3(方形波レートジェネレータ)
- 100:モード4(ソフトウェアトリガストローブ)
- 101:モード5(ハードウェアトリガストローブ)
- bit4-5:カウンタアクセスモード
- 11:16bitリードロード(下位8bit、上位8bitの順)
- 10:上位8bitのリードロード
- 01:下位8bitのリードロード
- 00:カウント値ラッチ
- bit6-7:カウンタチャンネル指定
- 00:カウンタ0
- 01:カウンタ1
- 10:カウンタ2
- 11:リードバックコマンド(後述)
- カウント値を設定するには、一般に以下の手順で行なう。
- コントールレジスタに設定したいチャンネルのモードを設定。直前と同じモードであっても、これを設定しないとうまく動作しないことがある。
- そして、目的のカウンタに値をセット。8bitモードなら1回のアクセスになるし、16ビットモードなら、下位8bit、上位8bitの順に書き込む。
- モード設定から、カウント値の設定完了までの間に、他のチャンネルのモード設定をしたり他のチャンネルのカウンタへ読み書きすると、設定も挙動も不定となる。
- カウント値を読み取るには、一般に次の手順で行なう。
- コントールレジスタを使って、読み取りたいチャンネルに対してラッチを実施。
- 読み取りのカウンタアクセスモードは、書き込み時のモードと同じになる。
ものぐさなひとのために †
- ぶちゃっけ、読者の多くはAT互換機でタイマーとBEEPの設定をすると思うので、そこだけをぱぱっと説明。
- IRQ0の割り込み周期変更:
- AL = 0x34; OUT(0x43, AL);
- AL = 割り込み周期の下位8bit; OUT(0x40, AL);
- AL = 割り込み周期の上位8bit; OUT(0x40, AL);
- これでおしまい。
- 割り込み周期に0を指定すると65536を指定したとみなされる。実際の割り込み頻度は、クロック/設定カウント値。つまり、1000を指定すれば、1.19318KHz。10000なら119.318Hz、といった具合。例えば11932を設定すれば、約100Hzになって、10msごとに割り込むようになるわけだ。
- BEEP音の制御:
- 音程操作:
- AL = 0xb6; OUT(0x43, AL);
- AL = 設定値の下位8bit; OUT(0x42, AL);
- AL = 設定値の上位8bit; OUT(0x42, AL);
- 設定値0は、65536として扱われる。
- これで発振される音程は、クロック/設定カウント値。つまり、1000を指定すれば、1.19318KHz。10000なら119.318Hz、といった具合。例えば2712を設定すれば、約440Hzになる。
- BEEPのON/OFF:
- これはI/Oポート0x61を使う。
- ON: IN(AL, 0x61); AL |= 0x03; AL &= 0x0f; OUT(0x61, AL);
- OFF: IN(AL, 0x61); AL &= 0xd; OUT(0x61, AL);
6つのモード †
こめんと欄 †
- ここにKさんが書いてくださった内容を参考にしてMonaのpic.cpp内のタイマの設定はかかれる予定です。 -- 'ひげぽん' 2004-01-09 (金) 21:55:07
- 少しは役に立ったようでうれしいです。 -- K 2004-01-10 (土) 00:16:17
void setTimerInterval(dword ms) {
dword timerCounter = ms * 1193.18;
outportb(0x43, 0x34);
outportb(0x40, timerCounter & 0xff);
outportb(0x40, timerCounter >> 8);
}
- タイマ割込み周期設定関数を作ってみました。引数はmsです。 -- 'ひげぽん' 2004-01-11 (日) 03:51:43
- Monaで上記の関数をテストしましたがきちんと動いているようです。 -- 'ひげぽん' 2004-01-11 (日) 17:26:52
- 実機でテストしたところカーネルが起動中に止まってしまったので現在調査中です。 -- 'ひげぽん' 2004-01-11 (日) 21:05:49
- loXIUGaA -- wQjfKSDbCLHFKXsWCWb 2008/07/28 (月) 00:44:16
|