...menustart
- Mappers and ROMs
- MMC3
- Mapper 介绍
- NROM (mapper 0)
- MMC1 , used in Nintendo's SxROM
- MMC3 , used in Nintendo's TxROM
...menuend
- iNES Header
- Bank Switching
- MMC3
- Information about the ROM
- Number of PRG banks (16k each)
- Number of CHR banks (8k, 2 tables each)
- Mirroring Type (0 = horizontal, 1 = vertical)
- Memory Mapper (0 = none, 4 = MMC3)
- Check out header.bas in the demo ROMs
- The NES can only address 64k of memory
- Only 32k is for ROM (code and data)
- Large games need to be able to swap areas of memory in and out
- Usually have a 16k bank for code and swap 16k of level data
- Memory mappers let us swap the memory
- In ROM source, you may use assembly to declare bank boundaries
- Banks usually have a base address of $8000 or $C000
asm
.org $8000 //base address
.bank 0 //0 = first bank
endasm
- iNES Mapper #4
- Extra memory capability for battery-backed save RAM
- Allows swapping 8k blocks of PRG memory
- Allows swapping 64- or 128-tile blocks of CHR pattern table
- Allows name table mirror type switching
- Common, versatile, and easy to use
- SMB2, SMB3, SOF, Megaman 3-6, many others
- Splits PRG region ($8000-$ffff) into 4 banks of 8k each
- You can swap the lower banks or the middle banks with other ROM banks.
- Upper bank is hardwired to the last bank in the ROM.
- I suggest you locate your game code in the upper banks and swap the lower banks for level data
- MMC3 Support code
- Example to swap lower 8k of PRG memory
gosub mmc3_use_lower_banks //use lower banks
set mmc3_command 6 //swap to first 8k bank
set mmc3_pagenum 0 //copy from first 8k of ROM
gosub mmc3_execute_command //swap
- Example to swap first 128 tiles of first pattern table
- Read the source file to see available commands and functions
set mmc3_command 0 //swap 2k page to PPU $0000
set mmc3_pagenum 4 //let’s copy from here
gosub mmc3_execute_command //go!
FC的CPU或PPU同时能寻址的数据大小有限.
类似于手表的日期显示,一个月虽然有30天,但我们只关心今天是几号,所以手表就负责每天转动日期转盘,把当天的日期显示在窗口中,有的手表还可以显示星期几,这样就有了两个转盘和两个窗口。
而Mapper芯片的作用就相当于手表的日期功能,给FC提供了窗口(Bank)和转盘(Rom)。
比如”魂斗罗”是256KB容量/Mapper 4/MMC3芯片,其PRG ROM为128KB(CHR ROM也是128KB)。
MMC3将CPU的寻址范围(0x8000~0xFFFF,共32KB)划分成4个窗口,每个窗口8KB($8000-$9FFF、$A000-$BFFF、$C000-$DFFF、$E000-$FFFF),也就是说MMC3具备4个8KB大小的CPU Bank。
那么,128KB的PRG ROM按照8KB的窗口大小将被分成32个Rom Bank,这就是转盘。
MMC3可以从这32个Rom Bank中按照需要选择4个显示在窗口中,这就是切Bank。CHR部分同理。
总共有三个转盘:PRG RAM、PRG和CHR,窗口的大小也不是固定的,可以是1k,2k,4k,8k,16k等,不同的Mapper芯片对于窗口的数量大小有不同的配置。
Mapper芯片需要通过写指令寄存器的方式来进行Rom Bank的切换.
- PRG ROM size:
- 16 KiB for NROM-128
- 32 KiB for NROM-256
- PRG ROM bank size: Not bankswitched
- PRG RAM: 2 or 4 KiB
- not bankswitched
- only in Family Basic (but most emulators provide 8)
- CHR capacity: 8 KiB ROM
- but most emulators support RAM
- CHR bank size: Not bankswitched
- Nametable mirroring:
- Solder pads 焊盘 select vertical or horizontal mirroring
All Banks are fixed,
- CPU $6000-$7FFF:
- Family Basic only: PRG RAM, mirrored as necessary to fill entire 8 KiB window, write protectable with an external switch
- CPU $8000-$BFFF: First 16 KB of ROM.
- CPU $C000-$FFFF: Last 16 KB of ROM (NROM-256) or mirror of $8000-$BFFF (NROM-128).
- Horizontal mirroring : 'H' disconnected, 'V' connected.
- Vertical mirroring : 'H' connected, 'V' disconnected.
- None
- Nevertheless, tile animation can be done by swapping between pattern tables $0000 and $1000 , using PPUCTRL bits 4-3 as a "poor man's CNROM".
- CPU $6000-$7FFF: 8 KB PRG RAM bank, fixed on all boards but SOROM and SXROM
- CPU $8000-$BFFF: 16 KB PRG ROM bank, either switchable or fixed to the first bank
- CPU $C000-$FFFF: 16 KB PRG ROM bank, either fixed to the last bank or switchable
- PPU $0000-$0FFF: 4 KB switchable CHR bank
- PPU $1000-$1FFF: 4 KB switchable CHR bank
Through writes to the MMC1 control register , it is possible for the program to swap the fixed and switchable PRG ROM banks , or to set up 32 KB PRG bankswitching.
but most games use the default setup, which is similar to that of UxROM : whole 32k bank switch.
- 与几乎所有其他映射器不同,MMC1通过串行端口进行配置,以减少引脚数量。
- CPU $8000-$FFFF is connected to a common shift register 公共移位寄存器.
- Writing a value with bit 7 set to any address in $8000-$FFFF clears the shift register to its initial state.
- $80-$FF -> $8000-$FFFF
- To change register's value, the CPU writes five times with bit 7 clear and a bit of the desired value in bit 0
- On the first 4 writes, the MMC1 shifts bit 0 into a shift register
- 在第五次写入时,MMC1将位0和移位寄存器内容(拼接后) 复制到 由 地址的 bit 13/14 选择的内部寄存器中,然后清零移位寄存器。
- 只有第五次写入的地址 才是有关系的地址
- 第五次写入后,移位寄存器会自动清零,因此不需要再写一次 bit7 =1 来给 移位寄存器复位了。
- 当CPU在连续的周期写入串行端口时,MMC1将忽略除第一个以外的所有写入。
- 6502 在执行 read-modify-write (RMW)指令的时候,会发生这种情况 , 比如 DEC , ROR , 这些指令会先 writing back the old value , 然后 writing the new value on the next cycle.
- Bill & Ted's Excellent Adventure , 通过 INC 一个内容是$FF 的ROM地址 来重置MMC1. MMC1 看到$FF 写入后重置,并忽略在下一个周期写入的$00.
- The reason for this is that the MMC1 has explicit logic to disregard any write cycle following another write cycle.
- To switch a bank, a program will execute code similar to the following:
;
; Sets the switchable PRG ROM bank to the value of A.
; 下面A列的 edcba 每个表示1bit, 这里为了展示方便这么写
; 下面的代码其实就是把 要切换的bank号的相关信息,放入A
; 最终这些信息会 被拷贝到 bank register
;
; A MMC1_SR MMC1_PB
setPRGBank: ; 000edcba 10000 Start with an empty shift register (SR). The 1 is used
sta $E000 ; 000edcba -> a1000 to detect when the SR has become full.
lsr a ; >0000edcb a1000
sta $E000 ; 0000edcb -> ba100
lsr a ; >00000edc ba100
sta $E000 ; 00000edc -> cba10
lsr a ; >000000ed cba10
sta $E000 ; 000000ed -> dcba1 Once a 1 is shifted into the last position, the SR is full.
lsr a ; >0000000e dcba1
sta $E000 ; 0000000e dcba1 -> edcba A write with the SR full copies D0 and the SR to a bank register
; 10000 ($E000-$FFFF means PRG bank number) and then clears the SR.
rts
注意,下面 LSB -> MSB
4bit0
-----
CPPMM
|||||
|||++- Mirroring (0: one-screen, lower bank; 1: one-screen, upper bank;
||| 2: vertical; 3: horizontal)
|++--- PRG ROM bank mode (0, 1: switch 32 KB at $8000, ignoring low bit of bank number;
| 2: fix first bank at $8000 and switch 16 KB bank at $C000;
| 3: fix last bank at $C000 and switch 16 KB bank at $8000)
+----- CHR ROM bank mode (0: switch 8 KB at a time; 1: switch two separate 4 KB banks)
- If you are using the SGROM or SNROM board to provide an environment similar to UNROM,
- with 8 KB of CHR RAM, a fixed PRG ROM bank at $C000, and a 16 KB switchable PRG ROM bank at $8000,
- do this in your init code after the mapper has been reset:
lda #$0E ; vertical mirroring, fixed $C000, 8 KB CHR pages
sta $8000 ; (use $0F instead for horizontal mirroring)
lsr a
sta $8000
lsr a
sta $8000
lsr a
sta $8000
lsr a
sta $8000
4bit0
-----
CCCCC
|||||
+++++- Select 4 KB or 8 KB CHR bank at PPU $0000 (low bit ignored in 8 KB mode)
MMC1 can do CHR banking in 4KB chunks. Known carts with CHR RAM have 8 KiB, so that makes 2 banks. RAM vs ROM doesn't make any difference for address lines. For carts with 8 KiB of CHR (be it ROM or RAM), MMC1 follows the common behavior of using only the low-order bits: the bank number is in effect ANDed with 1.
4bit0
-----
CCCCC
|||||
+++++- Select 4 KB CHR bank at PPU $1000 (ignored in 8 KB mode)
4bit0
-----
RPPPP
|||||
|++++- Select 16 KB PRG ROM bank (low bit ignored in 32 KB mode)
+----- PRG RAM chip enable (0: enabled; 1: disabled; ignored on MMC1A)
- Some revisions of the MMC1 IC might power up in a mode other than fixed-$C000, requiring that the vectors and the start of the init code be placed in all banks, much as in BxROM or AxROM or GxROM.
- Other revisions guarantee that the fixed bank is loaded at power on.
- To make sure your code works on all MMC1 revisions, put the following code in the last 16 bytes of each 16384 byte bank.
reset_stub:
sei
ldx #$FF
txs ; set the stack pointer
stx $8000 ; reset the mapper
jmp reset ; must be in $C000-$FFED
.addr nmiHandler, reset_stub, irqHandler
- Then to switch PRG ROM banks, load the bank number (0-15) into A and call this subroutine:
mmc1_load_prg_bank:
sta $E000
lsr a
sta $E000
lsr a
sta $E000
lsr a
sta $E000
lsr a
sta $E000
rts
- CPU $6000-$7FFF: 8 KB PRG RAM bank
- CPU $8000-$9FFF (or $C000-$DFFF): 8 KB switchable PRG ROM bank
- CPU $A000-$BFFF: 8 KB switchable PRG ROM bank
- CPU $C000-$DFFF (or $8000-$9FFF): 8 KB PRG ROM bank, fixed to the second-last bank
- CPU $E000-$FFFF: 8 KB PRG ROM bank, fixed to the last bank
- PPU $0000-$07FF (or $1000-$17FF): 2 KB switchable CHR bank
- PPU $0800-$0FFF (or $1800-$1FFF): 2 KB switchable CHR bank
- PPU $1000-$13FF (or $0000-$03FF): 1 KB switchable CHR bank
- PPU $1400-$17FF (or $0400-$07FF): 1 KB switchable CHR bank
- PPU $1800-$1BFF (or $0800-$0BFF): 1 KB switchable CHR bank
- PPU $1C00-$1FFF (or $0C00-$0FFF): 1 KB switchable CHR bank
- The MMC3 has 4 pairs of registers at $8000-$9FFF, $A000-$BFFF, $C000-$DFFF, and $E000-$FFFF
- even addresses ($8000, $8002, etc.) select the low register ,
- and odd addresses ($8001, $8003, etc.) select the high register in each pair.
- 这些可以分成两个独立的功能单元:
- memory mapping ($8000, $8001, $A000, $A001)
- and scanline counting ($C000, $C001, $E000, $E001).