NES(Famicom)のメモリマップです。本体側と主要なカートリッジ種別でのメモリマップを紹介します。
NES(Famicom)本体にはプログラムを格納するメモリ(ここでは以降『メインメモリ』)と ビデオ出力に使用されるメモリ(以降『ビデオメモリ』)の2系統からなります。 そしてこのメモリの一部はカートリッジ側に接続されています。
アドレス範囲 | 内容 |
---|---|
$0000-$00FF | RAM(0ページ) |
$0100-$01FF | RAM(スタック) |
$0200-$07FF | RAM |
$0800-$1FFF | $0000-$07FFのミラー |
$2000-$2007 | I/O #0(ビデオ) |
$2008-$3FFF | I/O #0のミラー |
$4000-$4017 | I/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-$3F0F | BGパレット |
$3F10-$3F1F | スプライトパレット |
$3F20-$3FFF | $3F00-$3F1Fのミラー |
$4000-$FFFF | $0000-$3FFFのミラー |
メモリにはミラーになっている部分が多くあります。これらはハードウェア的には同じ場所 (つまりアドレスラインが浮いている)です。ミラー部分へのアクセスは基本的には避けるべきでしょう。
カートリッジには基本的にプログラムを格納したPRG-ROMとビデオメモリのキャラクタパターン格納に使用される RAMもしくはCHR-ROMの2つからなります。しかし、プログラムに使用できるメモリ空間が32KByteととても狭いため、 初期のカートリッジを除いてバンク切り替えによる拡張が行われています。 これらカートリッジの種別をエミュレータではマッパーと呼んでいます。
マッパー#0はバンク切り替えのない最も基本的なカートリッジです。32KByteもしくは16KByteのPRG-ROMと 8KByteのCHR-ROMからなります。 ネームテーブルの配置は物理的に結線されネームテーブルの拡張は行われていません。
一部のカートリッジではメモリ不足の対策としてCHR-ROMの一部をプログラムに使用し、 本体RAM空間にロードしているものもあります。
アドレス範囲 | 内容 |
---|---|
$4020-$7FFF | (マップされません) |
$8000-$BFFF | 低位PRG-ROM(16KByteROMでは$C000-$FFFFのミラー) |
$C000-$FFFF | 高位PRG-ROM |
アドレス範囲 | 内容 |
---|---|
$0000-$0FFF | パターンテーブル#0 |
$1000-$1FFF | パターンテーブル#1 |
マッパー#1は【任天堂MMC1】と呼ばれるマッパーで、バッテリーバックアップRAMなどを備えた 高機能マッパーです。ただ、操作が複雑なのでここでは割愛。
マッパー#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はCHR-ROMをバンク切り替えするマッパーです。【CN-ROM】ともいいます。 CHR-ROMを8KB以上もち、$8000-$FFFFのカートリッジ側メモリ空間にバンク番号を書き込むと CHR-ROM全体が入れ替わります。
単純にCHR-ROMが入れ替わるだけなのでキャラクタ容量をとりあえず増やしたい場合には、 マッパー#2のように展開ルーチンを書いたりする手間もかからず、 切り替えも高速なので便利。
こちらはCHR-ROM全交換のバンク切り替えなので74HC161のみで構成されてるみたいです。
I/Oの操作はメモリ空間にマップされたI/Oレジスタを操作することにより行います。 $2000-$2007にPPU関連、$4000以降にサウンドやパッドなどが割り当てられています。 マッパーによっては$4008以降の本体側で割り当てられていない空間に拡張I/Oを搭載していることもあります。
I/Oレジスタには書き込みや読み込みしかできないレジスタがあります。 間違った使用をした場合は動作が不定なだけでなく故障の原因になる恐れがあります。
アドレス | アクセス種別 | 内容 |
---|---|---|
$2000 | W |
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:基準ネームテーブル |
$2001 | W |
PPUコントロールレジスタ2 bit#5-7:カラー強調(000:強調なし) bit#4:スプライト表示(1:表示) bit#3:BG表示(1:表示) bit#2:BGクリップ(1:クリップなし) bit#1:スプライトクリップ(1:クリップなし) bit#0:出力モード(0:カラー / 1:モノクロ) |
$2002 | R |
PPUステータスレジスタ bit#7:VBlank(1:VBlank中 ただし、Read後0クリアされる) bit#6:#0スプライトヒット bit#5:スキャンラインスプライト bit#4:VRAM書き込みフラグ bit#0-3:未使用 |
$2003 | W |
スプライトRAMアドレスレジスタ $2004を使ってスプライトRAMにアクセスする場合にアドレスを指定する。 (通常は$4014のDMAでまとめて転送することが多い) |
$2004 | W |
スプライトRAMアクセス $2003のアドレスにデータを書き込む際に使用。 (通常は$4014のDMAでまとめて転送することが多い) |
$2005 | W2 |
スクロール(2度書きレジスタ) X,Y方向のVRAMスクロール量を書き込む。 $2002を読むとリセットされ、その後X方向スクロール値、Y方向スクロール値の順に書き込む。 |
$2006 | W2 |
VRAMアドレスレジスタ(2度書きレジスタ) $2007を使ってビデオメモリにアクセスする際にアドレスをセットする。 $2002を読むとリセットされ、その後上位アドレス、下位アドレスの順に書き込む。 |
$2007 | R/W |
VRAMアクセス $2006で指定されたビデオメモリにアクセスする。 |
アドレス | アクセス種別 | 内容 |
---|---|---|
$4000 | W |
矩形波ch1コントロールレジスタ1 bit#7-6:Duty比 bit#5:Decayループ/長さカウンタ無効 bit#4:Decay無効 bit#3-0:ボリューム/Decayレート |
$4001 | W |
矩形波ch1コントロールレジスタ2 bit#7:スイープ有効 bit#6-4:スイープレート bit#3:スイープ方向(1:decrease/0:increase) bit#2-0:スイープシフト量 |
$4002 | W |
矩形波ch1周波数レジスタ1 周波数下位ビット |
$4003 | W |
矩形波ch1周波数レジスタ2 bit#7-3:長さカウンタレジスタ bit#2-0:周波数上位ビット |
$4004 | W |
矩形波ch2コントロールレジスタ1 bit#7-6:Duty比 bit#5:Decayループ/長さカウンタ無効 bit#4:Decay無効 bit#3-0:ボリューム/Decayレート |
$4005 | W |
矩形波ch2コントロールレジスタ2 bit#7:スイープ有効 bit#6-4:スイープレート bit#3:スイープ方向(1:decrease/0:increase) bit#2-0:スイープシフト量 |
$4006 | W |
矩形波ch2周波数レジスタ1 周波数下位ビット |
$4007 | W |
矩形波ch2周波数レジスタ2 bit#7-3:長さカウンタレジスタ bit#2-0:周波数上位ビット |
$4008 | W |
三角波リニアカウンタ bit#7:リニアカウンタスタート bit#6-0:リニアカウンタ |
$400A | W |
三角波周波数レジスタ1 周波数下位ビット |
$400B | W |
三角波周波数レジスタ2 bit#7-3:長さカウンタレジスタ bit#2-0:周波数上位ビット |
$400C | W |
ノイズコントロールレジスタ bit#5:Decayループ/長さカウンタ無効 bit#4:Decay無効 bit#3-0:ボリューム/Decayレート |
$400E | W |
ノイズ周波数レジスタ bit#7:乱数モード(0:32Kbit/1:93bit) bit#3-0:周波数選択 |
$400F | W |
ノイズ 長さカウンタレジスタ bit#7-3:長さカウンタレジスタ |
$4010 | W |
DMCコントロールレジスタ bit#7:IRQ有効 bit#6:ループ再生 bit#3-0:周波数選択 |
$4011 | W |
DMCデルタカウンタレジスタ |
$4012 | W |
DMC-DMAアドレスレジスタ DMCの先頭アドレスはこのアドレスにセットした値を左6シフトし$C000に加算したアドレスになります。 |
$4013 | W |
DMC-DMAデータサイズレジスタ このアドレスにセットした値*16+1がデータサイズになります。 |
$4014 | W |
スプライトDMA スプライトレジスタに転送するページアドレスを指定。 (スプライトDMAは512クロック消費します) |
$4015 | R/W |
サウンドレジスタ bit#7:DMC-IRQステータス bit#4:DMC再生開始 bit#3:ノイズch有効 bit#2:三角波ch有効 bit#1:矩形波ch2有効 bit#0:矩形波ch1有効 |
$4016 | R/W |
PAD#1 I/O このレジスタに1,0の順に書き込むとPAD#1の状態がbit#0にシリアル出力されます。 出力順序はA/B/Select/Start/Up/Down/Left/Rightの順。 bit#4は光線銃のトリガー, bit#3は光線銃のスプライトヒット(らしい) |
$4017 | R |
$4016で初期化作業(1,0を書き込む)を行った後に読むとPAD#2の状態が$4016と同様に出力されます。 FamicomのPAD#2にはStart/Selectがないので0が出力されます。NESやAV仕様ファミコンにはあります。 FamicomのPAD#2-MICは入力があれば$4016のbit#2が1になります。 |