# メモリマップドI/O
メモリマップドI/O（英: memory-mapped I/O）とは、コンピュータ内でCPUと入出力機器の間で入出力を行う手法の一種。他の入出力手法としては、ポートマップドI/O（英: port-mapped I/O）と、メインフレームなどで独立した入出力プロセッサを使用するチャネル・コントローラ方式がある。本項目ではポートマップドI/Oについても併せて解説する。「メモリマップト」と「ト」に濁音を付けない表記も用いられる。

## 概要
メモリマップドI/Oは、アドレス空間（仮想記憶方式の場合、物理アドレス空間）上にメモリと入出力機器が共存し、メモリのリード/ライトのためのCPU命令を入出力機器にも使用する。CPUの（物理）アドレス空間には入出力のための領域が用意されているが、固定的である必要はない。例えば、コモドール64は通常のメモリと入出力機器の空間をバンク切り換えしながら使用することができる。入出力機器（あるいはそれらを束ねるコントローラ）はCPUのアドレスバスを監視し、自身のレジスタがマッピングされた空間へのCPUからのアクセスに応答する。
ポートマップドI/O(I/OマップトI/Oと呼ぶ資料やプログラムドI/Oと呼ぶ資料もある)では、入出力用の特別なCPU命令を使用する。例えば、インテルのx86には入出力専用の IN 命令と OUT 命令があり、入出力機器の1つのバイト(8-bit)あるいは16-bitの読み書きを行う(16-bit入出力機器の読み書きを行う場合、対象となる16-bit入出力機器は偶数アドレスに配置する必要がある)。入出力機器は主記憶装置とは分離したアドレス空間にあり、CPUがそのための特殊なI/Oピンを持っているか、入出力バスのピンを持っている。特殊なI/Oピンを持っている場合、通常のデータバスに入出力機器が接続されており、I/Oピンがアサートされたときにアドレスバスに出力されたポート番号をフェッチする回路によって、対応する入出力機器のレジスタがデータバスとやりとりをするようになっている。例えば、インテル8086は、マキシマムモード時にI/Oピンとしても使用されるステータス信号S2, S1, S0 （S2=0, S1=0, S0=1でリードI/O、S2=0, S1=1, S0=0でライトI/O）を持ち、バスコントローラIntel 8288への制御入力信号として使われる。

## それぞれの利点
ポートマップドI/Oは、CPUのアドレス空間が限られている場合に有効である。入出力空間がメモリ空間と分離されているため、CPUのアドレス空間を全てメモリのために使用できる。また、アセンブリ言語のプログラムを読んだとき、特別な命令を使っているため、入出力を行っている箇所が即座にわかるという利点もある。
メモリマップドI/Oは、入出力を特別扱いしないため、CPUの内部回路が簡略化され、高速化や低価格化が容易である。このため、RISCではメモリマップドI/Oを採用していることが多い。マイクロプロセッサの規模が16ビットから32ビット、さらには64ビットとなるに従って、メモリマップドI/Oのためにアドレス空間を用意することはほとんど問題にならなくなってきた。また、通常のメモリ操作命令が入出力にも使えるということは、そのCPUの持つ全てのアドレッシングモードを入出力にも使えるということを示している。

## メモリマップドI/Oの例
8ビットマイクロプロセッサを使った単純なシステムを例として説明する。アドレス線が16ビット分あれば、64Kバイトまでのメモリをアドレス指定可能である。アドレス空間の先頭32KバイトにRAMを配置し、空間の最後尾16KバイトにROMを配置する。残った中間の16Kバイトの空間を各種入出力機器に割り当てる（タイマ、カウンタ、ビデオディスプレイチップ、サウンドジェネレータなど）。バスに接続されたそれらの機器は、マッピングされたアドレスがバス上に現われたときに応答し、それ以外のアドレスは無視する。これはアドレスデコーダの仕事であり、それによってシステムのメモリマップが確立される（通常のメモリでも同じ）。マイクロプロセッサによってはメモリマップ構成にアーキテクチャ上の制限がある場合もある。例えばモステクノロジーの6502はアドレス空間最後尾の16バイトにはリセットと割り込みのためのベクター（ジャンプテーブル）がなければならないため、その部分にはROMがマッピングされていなければならない。
アドレスのデコードは完全に行う場合もあるし、部分的に行う場合もある。完全なアドレスデコードではアドレスバスの全ての線をチェックし、CPUがメモリがマッピングされていない空間にアクセスしようとしている場合に入出力機器とデータバスの接続がなされる。部分的なデコードはより単純で安価である。その場合、ある機器がアドレス空間上の複数の位置にマッピングされているように見える場合もある。しかし、実際には1つの機器であり、それは単にデコーダを簡略化した副作用でしかない。デコーダはプログラム可能な場合もあり、メモリマップを必要に応じて変更できるものもある。これは特別な手法ではなく、バンク切り換えにも応用されている手法である。
以上から、メモリマップは次のようになる:
| デバイス                        | アドレス範囲    | サイズ |
| ------------------------------- | --------------- | ------ |
| RAM                             | 000016 - 7FFF16 | 32 kB  |
| 汎用 I/O                        | 800016 - 80FF16 | 256 B  |
| サウンドコントローラ            | 900016 - 90FF16 | 256 B  |
| ビデオコントローラ/テキストVRAM | A00016 - A7FF16 | 2048 B |
| ROM                             | C00016 - FFFF16 | 16 kB  |

このメモリマップには使われていない（何もマッピングされていない）隙間がある。これも特別なことではない。右下に「16」の添え字があるアドレスは16進数による表記である。
例えば、ビデオコントローラの4番目のレジスタで画面の背景色を設定するとしたとき、CPUはその色を A00316 という位置に（通常のメモリ書き込み命令で）書き込む。同様に文字を表示したければ、テキストVRAMの所定の位置にそれを書き込む。これはビットマップ画像として文字を表示することが一般化する前には普通に行われていた手法である（テキストユーザインタフェース参照）。

## 注意点
メモリマップドI/Oはメモリと入出力機器が同じアドレス空間上に並存するが、多くの場合（少なくともハードウェア的には）全く異なる扱いをしなければならないものであることに注意が必要である。例えば、ライトバック式のキャッシュメモリを使用しているシステムでは、読み書きをしてもバス上にそれが出て行かないことがあるので、当該のアドレス空間に対してキャッシュを無効化する必要がある。さらに、入出力機器のレジスタ群はアクセスする順番が決まっていることが多く、アウト・オブ・オーダー実行の影響を受けたりなどすると入出力操作が支離滅裂になることすら考えられる。そのため多くの場合、システムに何らかの方法で順序を強制する方法が用意される。（そもそも順番だけでなく、アクセス間隔を一定以上にするために待ちが必要なこともあり、アウト・オブ・オーダー実行が問題になるようなシステム構成ではメモリマップドI/Oを採用できない）
システムに何らかの方法で順序を強制する方法として、専用命令を設ける場合がある。具体的な例としては、PowerPCの eieio（enforce in-order execution of I/O instruction）命令がある。メモリマップドI/O を実行する際に使用するための命令であり、メモリバリアとして機能する。つまり、eieio命令よりも前のロード或いはストア命令が完了してから、eieio命令の後のロード或いはストア命令が開始されることが保証される。