MMC3
- iNES mapper IDs: 004, 118, 119
- PRG ROM capacity: 512K
- PRG ROM page size: 8 KiB
- PRG RAM: 8 KiB
- CHR capacity: 256 KiB ROM
- CHR page size: 1 KiB
- Nametable mirroring mode: Programmable, vertical or horizontal mirroring
PRG ROM memory map
Form explanation:
+-------------+-------------------+
| | Bank Selection |
| CPU MEM |-------------------|
| ADDR. | Mode 0 | Mode 1 |
+-------------+---------+---------+
| $8000-$9FFF | R6 | (-2) |
+-------------+---------+---------+
| $A000-$BFFF | R7 | R7 |
+-------------+---------+---------+
| $C000-$DFFF | (-2) | R6 |
+-------------+---------+---------+
| $E000-$FFFF | (-1) | (-1) |
+-------------+---------+---------+
Code explanation:
constexpr const unsigned A14 = 0x4000;
int bank_no = 0;
if (prg_bank_mode1)
addr ^= A14; // $0800 <--> $0c00
switch ((addr & 0x7fff) / 8192) {
case 0: bank_no = R[6]; break;
case 1: bank_no = R[7]; break;
case 2: bank_no = -2; break;
case 3: bank_no = -1; break;
}
prg_addr = bank_no < 0 ? prg_rom.size() : 0;
prg_addr += bank_no * 8192 + addr & 8191;
Graphical explanation:
Mode 0
------
...
+--------+ |--------|
$8000 | 8 KB |~~~~~~~~~~>| 8 KB |
|--------| |--------|
$A000 | 8 KB |~~~~~~~~~~>| 8 KB |
|--------| |--------|
$C000 | 8 KB |------. | 8 KB |
|--------| | |--------|
$E000 | 8 KB |---. | ...
+--------+ | | |--------|
| `--->| 8 KB |
| |--------|
`------>| 8 KB |
+--------+
Mode 1
------
...
+--------+ |--------|
$8000 | 8 KB |------. | 8 KB |
|--------| | |--------|
$A000 | 8 KB |~~~~~~|~~~>| 8 KB |
|--------| | |--------|
$C000 | 8 KB |~~~~~~|~~~>| 8 KB |
|--------| | |--------|
$E000 | 8 KB |---. | ...
+--------+ | | |--------|
| `--->| 8 KB |
| |--------|
`------>| 8 KB |
+--------+
CHR ROM memory map
Form explanation:
+-------------+---------------------+
| | Bank Selection |
| PPU MEM |---------------------|
| ADDR. | A12 Inv. | A12 Inv. |
| | = 0 | = 1 |
+-------------+----------+----------+
| $0000-$03FF | | R2 |
+-------------+ R0 +----------|
| $0400-$07FF | | R3 |
+-------------+----------+----------+
| $0800-$0BFF | | R4 |
+-------------+ R1 |----------|
| $0C00-$0FFF | | R5 |
+-------------+----------+----------+
| $1000-$13FF | R2 | |
+-------------+----------+ R0 |
| $1400-$17FF | R3 | |
+-------------+----------+----------+
| $1800-$1BFF | R4 | |
+-------------+----------+ R1 |
| $1C00-$1FFF | R5 | |
+-------------+----------+----------+
The lowest bits of R0 and R1 are treated as 0, so R0 and R1 can only select even memory pages. The size of each page is 1KB, so R0 and R1 can actually map 2KB of memory respectively
code explanation
constexpr const unsigned A12 = 0x1000;
int bank_no = 0;
int offset = addr & 0x03ff;
if (A12_inv)
addr ^= A12;
if (addr < 0x1000) {
offset = addr & 0x07ff;
bank_no = R[addr / 2048] & ~1;
} else {
bank_no = R[2 + (addr & 0x0fff) / 1024];
}
chr_addr = bank_no * 1024 + offset;
Graphical explanation:
A12 Inversion = 0
-----------------
+--------+
$0000 | 2 KB |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.
| | |
|--------| |
$0800 | 2 KB |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~. |
| | ... | |
|--------| |--------+--------| | |
$1000 | 1 KB |~~~~~~~~~~~~~~~~>| 1 KB | | | |
|--------| |--------+ 2 KB |<~~~~~' |
$1400 | 1 KB |~~~~~~~~~~~~~~~~>| 1 KB | | |
|--------| |--------+--------| |
$1800 | 1 KB |~~~~~~~~~~~~~~~~>| 1 KB | | |
|--------| |--------+ 2 KB |<~~~~~~~~~'
$1C00 | 1 KB |~~~~~~~~~~~~~~~~>| 1 KB | |
+--------+ |--------+--------|
...
A12 Inversion = 1
-----------------
...
+--------+ |--------+--------|
$0000 | 1 KB |~~~~~~~~~~~~~~~~>| 1 KB | |
|--------| |--------+ 2 KB |<~~~~~~~~~.
$0400 | 1 KB |~~~~~~~~~~~~~~~~>| 1 KB | | |
|--------| |--------+--------| |
$0800 | 1 KB |~~~~~~~~~~~~~~~~>| 1 KB | | |
|--------| |--------+ 2 KB |<~~~~~. |
$0C00 | 1 KB |~~~~~~~~~~~~~~~~>| 1 KB | | | |
|--------| |--------+--------| | |
$1000 | 2 KB | ... | |
| |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' |
|--------| |
$1800 | 2 KB |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
| |
+--------+