μMC1 - Tech docs

← Back to μMC1 general

This section contains technical information for developers and hardware enthusiasts.

Components

The cartridge is composed of three basic components:

Although the SRAM for CHR-RAM has 32 KiB space, only 8 KiB of the SRAM are exposed. The reason why 4-screen was not implemented is because this mode is not commonly supported in Famiclones, and was never commercially used in MMC1 or UNROM games.

The PRG-ROM supports a socket, but it only makes sense for development cartridges. As such, the FLASH can be optionally soldered straight to the PCB.

Banks

For CPU reads, the mapper divides the memory in two banks, just like UxROM and MMC1 in mode 3:

The lower bank is writable, and thus this allows self-writability to store the current progress, or to update the current running program during development.

Registers

Just like the MMC1, and unlike all other mappers, the registers are written bit by bit, LSB-first on D0 of the CPU. They are implemented by two shift registers with no buffering (ie changes apply immediately, not only when all bits have been written), and writes go to one or the other depending on the CPU address:

Mirroring ($C000-$DFFF)

The mirroring is controlled by a 2-bit shift register, which shifts the D0 bit of the CPU on any write from $C000 to $DFFF:

Mirroring control

The 2-bit mirroring control value to mode mapping is:

Bits Mode
00 Horizontal
01 Single screen A
10 Single screen B
11 Vertical

While it might look silly and arbitrary, it is not. These values have been carefully chosen to allow both easy porting of MMC1 games, and glitch-less swaping mid-render of single screen modes, without requiring the double buffering the MMC1 had.

Sample code

; Sets vertical mirroring
setvmirr:
	LDA #$01
	STA $C000
	STA $C000
	RTS

; Sets horizontal mirroring
sethmirr:
	LDA #$00
	STA $C000
	STA $C000
	RTS

; Sets mirroring to single screen A
setmirrscra:
	LDA #$01
	STA $C000
	; LSR to make it zero
	LSR A
	STA $C000
	RTS

; Swap single screen A with single screen B
swapscratob:
	LDA #$01
	STA $C000
	RTS

The reason why single screen A is 01 and B is 10 should be evident by the code above: swapping one for the other requires feeding the shift register a single bit.

Any other 2-bit combination would’ve required to feed two bits for swapping single screen, and thus it would’ve caused visible glitches after feeding the first bit but before feeding the second.

PRG bank ($E000-$FFFF)

The PRG bank register is implemented by a 5-bit register, which is fed by the D0 during any writes to any address between $E000 and $FFFF. It allows addressing up to 512 KiB of FLASH memory.

PRG bank register

Sample code

For changing the bank, the code is pretty similar to that of the MMC1:

; Sets the current switchable bank
; Parameters:
;  - A: desired bank
setbank:
	STA $E000
	LSR A
	STA $E000
	LSR A
	STA $E000
	LSR A
	STA $E000
	LSR A
	STA $E000
	RTS