Return to Site-Index

Memory-Map of NES

NES(Famicom)のメモリマップです。本体側と主要なカートリッジ種別でのメモリマップを紹介します。

本体メモリ

NES(Famicom)本体にはプログラムを格納するメモリ(ここでは以降『メインメモリ』)と ビデオ出力に使用されるメモリ(以降『ビデオメモリ』)の2系統からなります。 そしてこのメモリの一部はカートリッジ側に接続されています。

メインメモリ
アドレス範囲内容
$0000-$00FFRAM(0ページ)
$0100-$01FFRAM(スタック)
$0200-$07FFRAM
$0800-$1FFF$0000-$07FFのミラー
$2000-$2007I/O #0(ビデオ)
$2008-$3FFFI/O #0のミラー
$4000-$4017I/O #1(サウンド/スプライトDMA/パッド)
$4018-$4FFF拡張I/Oなど
$5000-$FFFF(カートリッジ側メモリ空間)
ビデオメモリ
アドレス範囲内容
$0000-$0FFFパターンテーブル#0(カートリッジ側メモリ空間)
$1000-$1FFFパターンテーブル#1(カートリッジ側メモリ空間)
$2000-$23BFネームテーブル#0
$23C0-$23FF属性テーブル#0
$2400-$24BFネームテーブル#1
$27C0-$27FF属性テーブル#1
$2800-$2BBFネームテーブル#2(カートリッジ拡張。通常は#0のミラー)
$2BC0-$2BFF属性テーブル#2(カートリッジ拡張。通常は#0のミラー)
$2C00-$2FBFネームテーブル#3(カートリッジ拡張。通常は#1のミラー)
$2FC0-$2FFF属性テーブル#3(カートリッジ拡張。通常は#1のミラー)
$3000-$2EFF$2000-$2EFFのミラー
$3F00-$3F0FBGパレット
$3F10-$3F1Fスプライトパレット
$3F20-$3FFF$3F00-$3F1Fのミラー
$4000-$FFFF$0000-$3FFFのミラー

メモリにはミラーになっている部分が多くあります。これらはハードウェア的には同じ場所 (つまりアドレスラインが浮いている)です。ミラー部分へのアクセスは基本的には避けるべきでしょう。

カートリッジメモリ

カートリッジには基本的にプログラムを格納したPRG-ROMとビデオメモリのキャラクタパターン格納に使用される RAMもしくはCHR-ROMの2つからなります。しかし、プログラムに使用できるメモリ空間が32KByteととても狭いため、 初期のカートリッジを除いてバンク切り替えによる拡張が行われています。 これらカートリッジの種別をエミュレータではマッパーと呼んでいます。

マッパー#0

マッパー#0はバンク切り替えのない最も基本的なカートリッジです。32KByteもしくは16KByteのPRG-ROMと 8KByteのCHR-ROMからなります。 ネームテーブルの配置は物理的に結線されネームテーブルの拡張は行われていません。

一部のカートリッジではメモリ不足の対策としてCHR-ROMの一部をプログラムに使用し、 本体RAM空間にロードしているものもあります。

カートリッジ側メインメモリ(マッパー#0)
アドレス範囲内容
$4020-$7FFF(マップされません)
$8000-$BFFF低位PRG-ROM(16KByteROMでは$C000-$FFFFのミラー)
$C000-$FFFF高位PRG-ROM
カートリッジ側ビデオメモリ(マッパー#0)
アドレス範囲内容
$0000-$0FFFパターンテーブル#0
$1000-$1FFFパターンテーブル#1

マッパー#1

マッパー#1は【任天堂MMC1】と呼ばれるマッパーで、バッテリーバックアップRAMなどを備えた 高機能マッパーです。ただ、操作が複雑なのでここでは割愛。

マッパー#2

マッパー#2はPRG-ROMをバンク切り替えするマッパーです。【UN-ROM】ともいいます。 キャラクタパターンは8KBのRAMになっており、そこにPRG-ROMから転送します。 PRG-ROMは128KB(8Bank)か256KB(16Bank)です。

バンクの切り替えは$8000-$FFFFのカートリッジ側メモリ空間にバンク番号を書き込むと $8000-$BFFFの16KBが指定したバンクに切り替わる仕組みです。 $C000-$FFFFの16KBは常に最終バンクが選択されます。 基本的に起動直後のバンクは不定です。 バンク切り替えは4bitカウンタの74HC161とORゲートの74HC32で実装されています。 74HC161にバンク番号を保持し、74HC32でバンク番号の各bitとA14とのorをとり $C000-$FFFFハードワイヤを行っているようだ。 実機で動作させる際にはICの動作遅延を考慮して切り替え直後に少しnopでウェイトを入れるといいかも。 $C000ハードワイヤの構造などから考えてnopを入れなくても問題なさそう。

マッパー#3

マッパー#3はCHR-ROMをバンク切り替えするマッパーです。【CN-ROM】ともいいます。 CHR-ROMを8KB以上もち、$8000-$FFFFのカートリッジ側メモリ空間にバンク番号を書き込むと CHR-ROM全体が入れ替わります。

単純にCHR-ROMが入れ替わるだけなのでキャラクタ容量をとりあえず増やしたい場合には、 マッパー#2のように展開ルーチンを書いたりする手間もかからず、 切り替えも高速なので便利。

こちらはCHR-ROM全交換のバンク切り替えなので74HC161のみで構成されてるみたいです。

I/Oレジスタ

I/Oの操作はメモリ空間にマップされたI/Oレジスタを操作することにより行います。 $2000-$2007にPPU関連、$4000以降にサウンドやパッドなどが割り当てられています。 マッパーによっては$4008以降の本体側で割り当てられていない空間に拡張I/Oを搭載していることもあります。

I/Oレジスタには書き込みや読み込みしかできないレジスタがあります。 間違った使用をした場合は動作が不定なだけでなく故障の原因になる恐れがあります。

I/O #0
アドレスアクセス種別内容
$2000W PPUコントロールレジスタ1
bit#7:VBlank時にNMIを呼び出す場合は1
bit#6:PPU動作スイッチ?(資料により説明が異なる)
bit#5:スプライトサイズ(0:8x8 / 1:8x16)
bit#4:BGパターンテーブルアドレス(0:$0000 / 1:$1000)
bit#3:スプライトパターンテーブルアドレス(0:$0000 / 1:$1000)
bit#2:PPUアドレスインクリメント(0:+1 / 1:+32)
bit#0-1:基準ネームテーブル
$2001W PPUコントロールレジスタ2
bit#5-7:カラー強調(000:強調なし)
bit#4:スプライト表示(1:表示)
bit#3:BG表示(1:表示)
bit#2:BGクリップ(1:クリップなし)
bit#1:スプライトクリップ(1:クリップなし)
bit#0:出力モード(0:カラー / 1:モノクロ)
$2002R PPUステータスレジスタ
bit#7:VBlank(1:VBlank中 ただし、Read後0クリアされる)
bit#6:#0スプライトヒット
bit#5:スキャンラインスプライト
bit#4:VRAM書き込みフラグ
bit#0-3:未使用
$2003W スプライトRAMアドレスレジスタ
$2004を使ってスプライトRAMにアクセスする場合にアドレスを指定する。
(通常は$4014のDMAでまとめて転送することが多い)
$2004W スプライトRAMアクセス
$2003のアドレスにデータを書き込む際に使用。
(通常は$4014のDMAでまとめて転送することが多い)
$2005W2 スクロール(2度書きレジスタ)
X,Y方向のVRAMスクロール量を書き込む。
$2002を読むとリセットされ、その後X方向スクロール値、Y方向スクロール値の順に書き込む。
$2006W2 VRAMアドレスレジスタ(2度書きレジスタ)
$2007を使ってビデオメモリにアクセスする際にアドレスをセットする。
$2002を読むとリセットされ、その後上位アドレス、下位アドレスの順に書き込む。
$2007R/W VRAMアクセス
$2006で指定されたビデオメモリにアクセスする。
I/O #1
アドレスアクセス種別内容
$4000W 矩形波ch1コントロールレジスタ1
bit#7-6:Duty比
bit#5:Decayループ/長さカウンタ無効
bit#4:Decay無効
bit#3-0:ボリューム/Decayレート
$4001W 矩形波ch1コントロールレジスタ2
bit#7:スイープ有効
bit#6-4:スイープレート
bit#3:スイープ方向(1:decrease/0:increase)
bit#2-0:スイープシフト量
$4002W 矩形波ch1周波数レジスタ1
周波数下位ビット
$4003W 矩形波ch1周波数レジスタ2
bit#7-3:長さカウンタレジスタ
bit#2-0:周波数上位ビット
$4004W 矩形波ch2コントロールレジスタ1
bit#7-6:Duty比
bit#5:Decayループ/長さカウンタ無効
bit#4:Decay無効
bit#3-0:ボリューム/Decayレート
$4005W 矩形波ch2コントロールレジスタ2
bit#7:スイープ有効
bit#6-4:スイープレート
bit#3:スイープ方向(1:decrease/0:increase)
bit#2-0:スイープシフト量
$4006W 矩形波ch2周波数レジスタ1
周波数下位ビット
$4007W 矩形波ch2周波数レジスタ2
bit#7-3:長さカウンタレジスタ
bit#2-0:周波数上位ビット
$4008W 三角波リニアカウンタ
bit#7:リニアカウンタスタート
bit#6-0:リニアカウンタ
$400AW 三角波周波数レジスタ1
周波数下位ビット
$400BW 三角波周波数レジスタ2
bit#7-3:長さカウンタレジスタ
bit#2-0:周波数上位ビット
$400CW ノイズコントロールレジスタ
bit#5:Decayループ/長さカウンタ無効
bit#4:Decay無効
bit#3-0:ボリューム/Decayレート
$400EW ノイズ周波数レジスタ
bit#7:乱数モード(0:32Kbit/1:93bit)
bit#3-0:周波数選択
$400FW ノイズ 長さカウンタレジスタ
bit#7-3:長さカウンタレジスタ
$4010W DMCコントロールレジスタ
bit#7:IRQ有効
bit#6:ループ再生
bit#3-0:周波数選択
$4011W DMCデルタカウンタレジスタ
$4012W DMC-DMAアドレスレジスタ
DMCの先頭アドレスはこのアドレスにセットした値を左6シフトし$C000に加算したアドレスになります。
$4013W DMC-DMAデータサイズレジスタ
このアドレスにセットした値*16+1がデータサイズになります。
$4014W スプライトDMA
スプライトレジスタに転送するページアドレスを指定。
(スプライトDMAは512クロック消費します)
$4015R/W サウンドレジスタ
bit#7:DMC-IRQステータス
bit#4:DMC再生開始
bit#3:ノイズch有効
bit#2:三角波ch有効
bit#1:矩形波ch2有効
bit#0:矩形波ch1有効
$4016R/W PAD#1 I/O
このレジスタに1,0の順に書き込むとPAD#1の状態がbit#0にシリアル出力されます。
出力順序はA/B/Select/Start/Up/Down/Left/Rightの順。

bit#4は光線銃のトリガー, bit#3は光線銃のスプライトヒット(らしい)
$4017R $4016で初期化作業(1,0を書き込む)を行った後に読むとPAD#2の状態が$4016と同様に出力されます。
FamicomのPAD#2にはStart/Selectがないので0が出力されます。NESやAV仕様ファミコンにはあります。
FamicomのPAD#2-MICは入力があれば$4016のbit#2が1になります。