Programming MMC1: Difference between revisions

From NESdev Wiki
Jump to navigationJump to search
No edit summary
(→‎References: snrom-template)
 
(3 intermediate revisions by 2 users not shown)
Line 1: Line 1:
'''MMC1''' was Nintendo's first ASIC mapper for the NES.
[[MMC1]] was Nintendo's first ASIC mapper for the NES.


== Quick setup for UNROM style ==
== Quick setup for UNROM style ==
If you are using the [[SGROM]] or [[SNROM]] board to provide an environment similar to [[Programming UNROM|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:
If you are using the [[SGROM]] or [[SNROM]] board to provide an environment similar to [[Programming UNROM|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:
<source lang="6502">
 
<pre>
   lda #$0E  ; vertical mirroring, fixed $C000, 8 KB CHR pages
   lda #$0E  ; vertical mirroring, fixed $C000, 8 KB CHR pages
   sta $8000  ; (use $0F instead for horizontal mirroring)
   sta $8000  ; (use $0F instead for horizontal mirroring)
Line 14: Line 15:
   lsr a
   lsr a
   sta $8000
   sta $8000
</source>
</pre>


Games that use CHR RAM switch to another PRG bank before they [[CHR-ROM vs CHR-RAM#Switching to CHR RAM|copy tile data into CHR RAM]].
Games that use CHR RAM switch to another PRG bank before they [[CHR-ROM vs CHR-RAM#Switching to CHR RAM|copy tile data into CHR RAM]].
Line 22: Line 23:
Other revisions guarantee that the fixed bank is loaded at power on.
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. (''Barbie'' uses almost identical code.)
To make sure your code works on all MMC1 revisions, put the following code in the last 16 bytes of each 16384 byte bank. (''Barbie'' uses almost identical code.)
<source lang="6502">
 
<pre>
reset_stub:
reset_stub:
   sei
   sei
Line 30: Line 32:
   jmp reset  ; must be in $C000-$FFED
   jmp reset  ; must be in $C000-$FFED
   .addr nmiHandler, reset_stub, irqHandler
   .addr nmiHandler, reset_stub, irqHandler
</source>
</pre>


Then to switch PRG ROM banks, load the bank number (0-15) into A and call this subroutine:
Then to switch PRG ROM banks, load the bank number (0-15) into A and call this subroutine:
<source lang="6502">
 
<pre>
mmc1_load_prg_bank:
mmc1_load_prg_bank:
   sta $E000
   sta $E000
Line 45: Line 48:
   sta $E000
   sta $E000
   rts
   rts
</source>
</pre>
 
== Interrupts ==
 
If an NMI or IRQ can interrupt a series of writes, it is not easy to know what state the serial register was in before the interruption. One technique for coping with this problem involves using a flag variable to indicate that a serial write should be retried<ref>[https://forums.nesdev.org/viewtopic.php?p=132577#p132577 forum post]: thefox describes MMC1 interrupt technique used in STREEMERZ</ref>:
# The normal serial write routine should have an "interrupted" flag:
#* Clear the flag before beginning the series of writes.
#* When completed, check the flag. If an interrupt is indicated, reset the serial register, clear the interrupted flag and begin the serial writes again.
# If the NMI or IRQ needs to switch banks, it should reset the serial register and set the "interrupted" flag to indicate that it has done this.


== See also ==
== See also ==


* [[MMC1]] technical reference
* [[MMC1]] technical reference
== References ==
<references/>
== External links ==
* [https://github.com/pinobatch/snrom-template SNROM project template] by Damian Yerrick on GitHub

Latest revision as of 15:28, 2 August 2018

MMC1 was Nintendo's first ASIC mapper for the NES.

Quick setup for UNROM style

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

Games that use CHR RAM switch to another PRG bank before they copy tile data into CHR RAM.

PRG banks

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. (Barbie uses almost identical code.)

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

Interrupts

If an NMI or IRQ can interrupt a series of writes, it is not easy to know what state the serial register was in before the interruption. One technique for coping with this problem involves using a flag variable to indicate that a serial write should be retried[1]:

  1. The normal serial write routine should have an "interrupted" flag:
    • Clear the flag before beginning the series of writes.
    • When completed, check the flag. If an interrupt is indicated, reset the serial register, clear the interrupted flag and begin the serial writes again.
  2. If the NMI or IRQ needs to switch banks, it should reset the serial register and set the "interrupted" flag to indicate that it has done this.

See also

  • MMC1 technical reference

References

  1. forum post: thefox describes MMC1 interrupt technique used in STREEMERZ

External links