天野 hunga@am.ics.keio.ac.jp コンピュータ基礎 入出力 天野 hunga@am.ics.keio.ac.jp
データを保存するレジスタ、制御用のレジスタを持つ I/O:入出力デバイス 一時的に データを保存するレジスタ、制御用のレジスタを持つ CPU I/O ②外部との データ転送 制御方法 ①どのように 接続するか? 命令 メモリ データ メモリ I/O: CPUと外界のやりとりを制御 一時的にデータを蓄えるバッファ を持つハードウェアモジュール
メモリマップトI/O 0000 メモリ領域 CPU I/O 8000 命令 メモリ データ メモリ I/O領域 データメモリと同じアドレス空間に I/Oのレジスタを割り付け、同じバス 上で接続する FFFF
プログラムドI/O (Isolate I/O、Separate I/O) 0000 CPU I/O I/O領域 メモリ領域 独立したバスを持つ I/O命令を持つ IN 0 OUT 1 など、、 =独立した番号空間を 持つ 命令 メモリ データ メモリ FFFF
メモリマップトI/O vs.プログラムドI/O 命令の種類が減る ハードウェアが減る どのような構造のCPUでも使える プログラムドI/O メモリアドレス空間中にI/Oの虫食いができない I/O中にメモリアクセスが可能 Intel 86系はプログラムドI/Oでも実際にはメモリマップトI/Oで動いている
I/Oデバイス コントロールレジスタ 外界 CPUのバス ステータスレジスタ メモリに書くように 書き込む データレジスタ メモリから読むのと 同じように読み出す データレジスタ: データの一時的な保存場所 コントロールレジスタ: I/Oに対する指示を覚えておく場所 ステータスレジスタ:I/Oの状態を覚えておく場所 データレジスタは双方向を同じ番地に割りあえてる場合もある コントロールレジスタとステータスレジスタは同じ番地を割り当てる場合もある
例:UART 8251 パラレル/シリアル変換を行うI/O モデム・端末インタフェースRS232C用 5bit-8bit単位でシリアル転送を行う ボーレートはさほど高くない(最大でも10Mbps) 現在でもIPとしてFPGA内で良く利用される
シリアル転送フォーマット Stop bit Start bit D0 D1 DN P Start bit: 0にして開始を示す
コントロールレジスタと ステータスレジスタ EP PEN L2 L1 0 0 L2 L1 0 0 5bit 0 1 6bit 0 7bit 1 1 8bit EP: Even Parity 1: Even 0: Odd PEN: Parity Enable 1: Enable Rx RDY Tx RDY ステータスレジスタ TxRDY: 送信終了、送信バッファ(ダブルバッファ)に書き込み可能 RxRDY:受信終了、受信バッファから読み出し可能
ハンドシェイク(送信) TxRDY フラグ I/O 1 TxRDY=1ならば バッファ利用可能 書き込み
ハンドシェイク(送信) TxRDY フラグ I/O 1 TxRDY=0ならば TxRDY=0の時には バッファ中にデータが存在 1 TxRDY=0ならば バッファ中にデータが存在 出力 TxRDY=0の時には 次のデータを書き込む ことができない
ハンドシェイク(送信) TxRDY フラグ I/O 1 再び TxRDY=1ならば バッファ利用可能 書き込み 以降繰り返し
ハンドシェイク(受信) RxRDY フラグ I/O 1 1の時は次のデータの 書き込みができない ステータスレジスタの RxRDY=1ならば バッファから読み出し 可能
フラグを使ってハザードを防ぐ RAWハザード:Read After Writeハザード 値が書き込まれるのを待って読み込む 二重読みを防ぐ WARハザード:Write After Readハザード 値を読む前に書きこまれることがないようにする 書き潰しを防ぐ WAWハザード:Write After Writeハザード これも書き潰しだが、WARがなければ普通大丈夫
演習のI/Oインタフェース ディスプレイを想定 0x8000: ASCIIコードを書き込むと出力される man asciiで表示されるのでLinux端末でやってみて! 0x8000: 書くとデータレジスタ 読むとステータスレジスタ 最下位ビットがTxRDY, 送信完了すると1になる
例題プログラム LDHI r0,#0x80 LOOP: LD r1,(r0) BEZ r1,LOOP LDI r1,#0x41 ST r1,(r0) → これでASCIIコード0x41:Aが出力される TxRDYが1になるまで ループ → ポーリング Busy Wait
演習1 データメモリの0番地から並んでいる5個のデータをディスプレイから表示せよ。
さて、ここまでのI/O 16ビットのデータのうちのほんの一部しか使ってない ビジーウェイトって、CPUは回ってばかりで馬鹿みたい ステータスは1ビット データでも8ビット → バイトアドレッシングの導入 ビジーウェイトって、CPUは回ってばかりで馬鹿みたい → 割り込みの導入
バイトアドレッシング 16ビット幅の場合 8ビット単位でアドレスを振る→今のCPUでは最も一般的な方法 LSB MSB LSB MSB 1 1 1 2 3 3 2 4 5 5 4 6 7 7 6 8 9 9 8 A B B A C D D C E F F E End End Big Endian POCOは こっち Little Endian 統一されていない データの順番が変わって大変なことになることも、、、 最近は電源投入時にどちらかをセットする方法が一般化
バイトアドレッシング 32ビット幅の場合 LSB MSB LSB MSB 1 2 3 3 2 1 4 5 6 7 7 6 5 4 8 9 A 1 2 3 3 2 1 4 5 6 7 7 6 5 4 8 9 A B B A 9 8 C D E F F E D C Little Endian End Big Endian End 64ビットデータでも同様
LB Load Byte 00000 ddd sss 01100 LDと同様R型 MSB LSB 1 2 3 4 5 レジスタr0-r7 6 1 2 3 4 5 レジスタr0-r7 6 7 8 9 1 A B C D 符号拡張 E F End 8bitを16ビットに拡張する →CPU内では標準サイズで扱うのが RISCの原則
LBU Load Byte Unsigned 00000 ddd sss 01101 MSB LSB 1 2 3 4 5 レジスタr0-r7 1 2 3 4 5 レジスタr0-r7 6 7 8 9 1 A B C D Zero拡張 E F End 8bitを16ビットに拡張する →CPU内では標準サイズで扱うのが RISCの原則
SB Store Byte 00000 ddd sss 01011 MSB LSB 1 2 3 4 5 レジスタr0-r7 6 7 8 9 1 2 3 4 5 レジスタr0-r7 6 7 8 9 A B C D E F End 16ビットレジスタの下位8ビットを切って メモリに格納 → 上位8ビットは無視 プログラマの責任! SBUは存在しない
ミスアラインメント MSB LSB 1 LD r0,(r1) r1=0 2 3 4 5 1 レジスタr0-r7 6 7 8 9 1 LD r0,(r1) r1=0 2 3 4 5 1 レジスタr0-r7 6 7 8 9 偶数番地は問題ない MSB LSB 1 LD r0,(r1) r1=1 2 3 4 5 1 2 レジスタr0-r7 6 7 8 9 奇数番地だと2回アクセスしてくっつける必要がある →ミスアラインメント
ミスアラインメントを許すか? 許す利点: 許す欠点: 一般に命令では許さない。データではケースバイケース メモリ利用効率が向上する レガシーコードがコンパイルしなおさずに動く 許す欠点: 動作速度が遅くなる メモリを2回アクセスしなければならない ハードウェアが複雑になる バイトをシフトしてくっつける必要がある シフト操作自体はLBの時点で必要だが、、、 一般に命令では許さない。データではケースバイケース POCOでは命令、データ共に許さないことにする
割り込み(Interrupt) I/O側からCPUに対して割り込みを要求 CPUはこれを受け付けると自動的にPCを割り込み処理ルーチンの先頭に変更 戻り番地はどこかに保存 割り込み処理ルーチンを実行、終了後リターン命令で元のルーチンに戻る → 元のルーチンは割り込みが起きたことがなかったかのように実行しなければならない
割り込みの実行 メインルーチン EI (Enable Interrupt) 割り込み処理ルーチン 割り込み 要求信号 RTI (Return from Interrupt) サブルーチンコールとの違いは、どこで呼ばれるか 分からない点にある
割り込み関係の命令 EINT Enable Interrupt 00000 XXXXXX 01110 Xはdon’t care 割り込みを許可する RTI Return from Interrupt 00000 XXXXXX 01111 PC ← IARにし、割り込みを許可する
割り込みの実現方法 割り込み処理のとび先番地 戻り番地の格納手法 固定番地 POCOではff00とした テーブル引き 割り込み処理ルーチンの先頭でどのI/Oが要求を出したか調べる必要がある テーブル引き I/O毎に飛び先を変えることができる 戻り番地の格納手法 特殊なレジスタ POCOではIAR(Interrupt Address Register) ハードウェアスタック
割り込みの実装 VDD 割り込み要求線 オープンドレイン どれかがLならばL CPU intreq I/O I/O I/O オープンドレインの割り込み線を使って割り込み要求を 発生する。 割り込み処理ルーチンに飛ぶときに割り込みを禁止 → 割り込みが掛かり続けることを防止
CPUによる入力 CPU LB I/O SB メモリ LBで一度レジスタにとってきて SBでメモリにしまう
CPUによる出力 CPU SB I/O LB メモリ LBで一度レジスタにとってきて SBでI/Oのデータレジスタへ出力
Direct Memory Access(DMA) CPU DMA要求 許可、 バスを開放 I/O I/Oがアドレスを指定し、 直接メモリとデータをやりとり メモリ 終了後はバスを開放し、 CPUに割り込みを掛ける CPUはDMAが掛かったことを 知らない
演習2 MSB LSB 0x0 0x80 0x12 0x2 0x34 0x56 0x4 0x78 0x9a 0x6 0xbc 0xde Big Endianのバイトアドレッシングを仮定する 以下のプログラムを実行した時のレジスタr1の値の変化を示せ LDI r0,#0 LB r1,(r0) LBU r1,(r0) LD r1,(r0) ADDI r0,#5