
今回はI/O命令デス。I/O命令といってもその動作はデータの転送です。8086/8088においてはMOVと変わるのは「空間」の種別のみ。他のプロセッサ、かってのライバル?68系も、現在ブイブイ言わせている?ArmやRISC-VにもI/O空間などありませぬ。みなメモリ・マップドI/Oね。でも使っているのよねI/O。
※「ぐだぐだ低レベル プログラミング」投稿順indexはこちら
※実機動作確認(といってもエミュレータなんだけれども)には以下を使用させていただいております。
x86のメモリ空間とI/O空間
他の多くのプロセッサでは、メモリ空間が唯一で、I/Oデバイスはそのメモリ空間のアドレスの一部に「割りつける」というのがスタンダードなスタイルです。さすれば、フツーのメモリアクセス命令をそのままI/Oデバイスのレジスタに対する読み書きに使えるし、それで不便もありませぬ。(まあ、とはいっても最近のRISCでも、メモリ空間とは別に天下り的な「制御レジスタ空間」的な空間あったりもするけれども。)
しかし、x86の場合、その開発時に御先祖の8ビット8080と「アセンブラ・レベルで変換可能な互換性を保つ」という大命題もあり、8080が持つメモリ空間とI/O空間の種別を省略するわけにもいかなかったものと思われます。そのような経緯を御先祖に遡れば「電卓用のチップセット」として登場した80系のルーツにいたるのだと思われます。ま、ともかく、I/O(周辺回路)とのやりとりのためのアドレス空間をメモリとは別に設けておく、というスタイルです。勿論、x86でもメモリ空間の一部にI/Oデバイスを設置することは可能です。実際、PCなどでもメモリマップドI/Oは多用されてます。
いままで練習してきた多くの命令どもは、メモリ・オペランドをとったのですが、I/O空間をアクセスするためには以下のI/O命令を使わねばなりません。
-
- IN
- OUT
- INS
- OUTS
なお、上記のうちINS、OUTSはブロック転送系の命令です。例えばFDC(フロッピイ・ディスク・コントローラ)から1セクタ256バイトを読み出して~などというとき、他のプロセッサではDMAなどを使ってFDCとメモリ上のバッファ間の転送をしたりしますが、8086/8088ではこのようなブロック入出力命令があったので、これ使ってた、などという話を聞きます。知らんけど。
以下の図は8086/8088におけるメモリ空間とI/O空間の説明図です。
左がメモリ空間です。全部で1Mバイト(20ビットアドレス)の空間があります。そのうち、一番上と下の「紫色」部分はハードウエア的に使用方法が定まっている部分です。一番上はRESET時にプログラムがスタートするアドレスです。通常ここにはジャンプ命令をおいて初期化用のコードに飛ばすことになります。ここのアドレスは固定ですが、プロセッサの世代によりCS:IPの初期値が異なる場合があるので「いろいろ」あります。
一方、8086/8088の場合、最下位には割り込みベクトルがおかれてます。0番から255番までの割り込みの発生に応じて「4*割り込み番号」の固定番地からCS:IPを取り出して割り込みハンドラに分岐することになってます。そのうち、0番から31番までの割り込みは「インテル予約」ということになっていてユーザーは勝手に使えませぬ。8086/8088の場合、0番から4番までの5個の割り込みのみ実装されてます。6番から31番は将来のためだと。実際に186以降の後継機で下から割り込み番号を使っていきますが、286が登場するとプロテクトモードのせい?で一気にかなりな数使われてます。32番以降はユーザーに開放という御約束になっているので、MS-DOSのシステムコール(API)などが下の方にありましたな。
I/O空間についても、上記の図をみると「インテル予約」部分があったのです。しかし、8086/8088的には特にハード的に実装されている部分は無かった筈。186などでは「インテル予約」使っているところがあるので、そういうケースは要注意かもです。
I/O空間にアクセスする命令共はかなりクセ強ですが、挙動は統一されてます。
-
- I/O空間からの読み出しはINまたはINS
- I/O空間への書き出しはOUTまたはOUTS
- 8ビット幅のデータの読み書きはALレジスタを使用。
- 16ビット幅のデータの読み書きはAXレジスタを使用。
- I/O空間は全部で64Kバイト。それを指定する16ビットのアドレスはDXレジスタに格納すること。
- I/O空間のうち下の256バイトのみ固定番地に対するダイレクトアドレス指定が可能。
- なおワード(16ビット)幅のI/Oレジスタは偶数番地に置く(奇数番地におくと2回のアクセスになってしまう。)
上記を踏まえてI/O命令を練習することも可能なのですが、メンドイので練習はパス。いいのかそういうことで。