Jump to content
IGNORED

Game Engine Building #9 - MMC1 Memory Mapping


MRN

Recommended Posts

INTRO

I had a request for MMC1 mapper information, so I thought everyone might like to read what I have to say.

This will help you figure out MMC1 memory mapping.  It assumes that you have a working knowledge
of NES programming and can understand my messed up little mind. Most of the information on this
mapper can be found on:

http://wiki.nesdev.com/w/index.php/MMC1

MMC1 will allow you to use up to 256 kB of PRG ROM and 128 kB of CHR ROM.  I think that you can use SUROM to expand up to 4 MB of PRG ROM, but this is not covered here.


First, you have to decide on what kind of configuration you want to use.  MMC1 will support PRG bank
switching in either 16kB mode or 32kB mode.  And with the 16, you can choose whether you want
the memory at $C000 or the memory at $8000 to be switched. 

Second, you have to decide on the CHR ROM switching.  MMC1 supports switching of 4kB (background or sprite tiles separately) or 8kB (switching them together).


After you decide this, you are ready to start.


INES HEADER

Notes:

-You can only have even numbers of PRG banks.  NESASM uses 8kB "banks", I'm talking about 16kB banks. 
i.e. 02 (32kB),04 (64kB),06 (96kB),08 (128kB),0A (160kB),0C (192kB),0E (224kB),10 (256kB)

-CHR banks are in multiples of 8kB banks. (important if you are using 4kB swapping.)
i.e. 01 (8kB),02 (16kB),03 (24kB),04 (32kB),05 (40kB), 06 (48kB), etc., 10 (128kB)

-MMC1 mapper number is "1" ...creative!

-Mirroring should match that used below in the initiation routine.

In this exercise, we will use:

  .inesprg $10   ; 16x 16KB PRG code
  .ineschr $10   ; 16x  8KB CHR data
  .inesmap $01   ; mapper 1 = MMC1, 4KB CHR bank swapping
  .inesmir 0   ; background mirroring


MAPPER CONTROL HEADER

This is one bite that has all the information for the mapper.  Observe:

76543210

Bits 7,6,5 - Not sure what these do.
Bit 4 - CHR ROM bank mode - (0 means switch 8kB at a time, 1 means switch the two separate 4kB banks independently)
Bit 3 - PRG ROM bank mode - (0 means switch all 32kB at once, ignores bit 2)
                            (1 means switch ONLY the 16kB specified in bit 2)
Bit 2 - PRG ROM location - (0 means switch 16kB at $C000, 1 means switch 16kB at $8000)
Bits 1,0 - Mirroring - (0 means one screen, lower bank; 1 means one screen, upper bank
                       2 means vertical; 3 means horizontal)

Here we will use LDX #%00011000

BITCH WORK!  Look above and figure out what this means.


INITIATE MAPPER

Here we load the information required by the system to run the mapper as well as the initial banks.
You have to do the 5 writes to make it work...for whatever reason.

initMMC1Mapper:
  LDA #$80                     ;this locks the PRG ROM at $C000-$FFFF to the last bank.
  STA $8000
 
  TXA                          ;uses our header to initiate the mapper
  JSR setMMC1ControlMode
 
  LDA #$02                     ;sets the CHR information for the sprites
  JSR setCHRPage0000
 
  LDA #$01                     ;sets the CHR information for the background
  JSR setCHRPage1000
 
  LDA #$03                     ;sets the PRG information
  JSR setPRGBank
 
  RTS
 
setMMC1ControlMode:
        STA $8000
        LSR A
        STA $8000
        LSR A
        STA $8000
        LSR A
        STA $8000
        LSR A
        STA $8000
  RTS
 
setCHRPage0000:
        STA $A000
        LSR A
        STA $A000
        LSR A
        STA $A000
        LSR A
        STA $A000
        LSR A
        STA $A000 
  RTS

setCHRPage1000:
        STA $C000
        LSR A
        STA $C000
        LSR A
        STA $C000
        LSR A
        STA $C000
        LSR A
        STA $C000
  RTS
 
setPRGBank:
        STA $E000
        LSR A
        STA $E000
        LSR A
        STA $E000
        LSR A
        STA $E000
        LSR A
        STA $E000
  RTS

Congrats....your program should work.

USING THE MAPPER

You can swap out banks whenever you want, even several times per NMI.  Just load the bank number you want to
use into A and call the appropriate subroutine.  Just be sure that you don't switch away information that
your program needs to run or it will die.

Weird bank numbering notes:

-CHR data is stored in 8kB for NESASM.  If you want to call the first 4kB of data from the 6th 8kB chunk,
you would use bank #$0C.  Observe, call number for 4kB chunk vs. 8kB bank number:

00-0
01-0
02-1
03-1
04-2
05-2
06-3
07-3
08-4
09-4
0A-5
0B-5
0C-6
0D-6
0E-7
0F-7
10-8
11-8
12-9
13-9
14-10
15-10
16-11
17-11
18-12
19-12
1A-13
1B-13
1C-14
1D-14
1E-15
1F-15

Clear?

-PRG info is stored in 8kB chunks in NESASM, but you call and switch 16kB banks.  If you want to call bank 26, use call number #$0D.  Observe, call number vs. bank number:

0-0,1
1-2,3
2-4,5
3-6,7
4-8,9
5-10,11
6-12,13
7-14,15
8-16,17
9-18,19
A-20,21
B-22,23
C-24,25
D-26,27
E-28,29
F-30,31

Clear?

-At the end of each 16kB bank, you have to have vectors in place or it will die.

  .org $FFFA     ;first of the three vectors starts here
  .dw NMI          ;when an NMI happens (once per frame if enabled) the 
                          ;processor will jump to the label NMI:
  .dw RESET    ;when the processor first turns on or is reset, it will jump
                           ;to the label RESET:
  .dw 0               ;external interrupt IRQ is not used in this tutorial

-Bank numbering is successive.  i.e. if you have PRG banks numbered 0-23, you would start numbering your CHR banks at 24.

-If you have, for example, a 16kB CHR file, you only have to include the starting place and NESASM will
split the banks properly. i.e. in 4kB mode:

  .bank 32
  .org $0000
  .incbin "MMC1.chr"   ;includes 16KB graphics file

This will include 4 - 4kB (or 2-8kB) banks in the assembly process.  Be sure to account for the 2 banks
in your numbering.  (see the attached ASM file.)


PRACTICAL APPLICATION

This is a little inefficient.  To use all this nonsense in something real, an example would be:

LoadBackground:

;find room info

;switch to room info table bank

;load bankground pointer

;switch to bank where background information is stored

;load background

;switch back to room info table bank

;load attribute and palette pointers

;switch to attribute/palette information bank

;load attributes/palettes

;switch back to room info table bank

;load collision detection pointer

;switch to collision detection bank

  RTS


WORKING EXAMPLE

Here we use the controller to switch banks for both CHR banks and the PRG bank.

A and B - swap out CHR information for the sprites
Select and Start - nothing
Up and Down - load a background located in different banks (the flashing is cause you are holding the button
down for more than one frame.  Just tap it.  I was too lazy to add stuff in to fix this.)
Left and Right - swap out the CHR information for the backgrounds

Download the attached file and assemble the program.  Mess around with it and try to switch out the
various buttons and banks.  Fix the flashing.  Add new backgrounds and characters...etc.

The little DOS assembler file might not work, you may have to edit it to your drive.


THE END!

I'm sure I totally screwed this up, but don't worry!  Someone will help me out if there are any mistakes.

MMC1.zip

  • Like 1
Link to comment
Share on other sites

×
×
  • Create New...