MMM01

From Tauwasser's Wiki
Jump to: navigation, search

Nintendo's MMM01 can be used to address up to 64 Mbit of ROM and 1 Mbit of SRAM depending on the mode MMM01 is set to.

Pinout

MMM01 Pinout.png
Pin No. Name Type Comment
28 VCC PWR 5V supply
12 GND PWR Ground supply
5–11 D6–D0 I Data Bus
3 RD I Low-Active Read Enable
1 WR I Low-Active Write Enable
4 CS I Low-Active Chip Select
2 RESET I Low-Active Asynchronous Reset
13–15 A15–A13 I Address Bus
15, 29, 27, 21–17, 22 RA22–RA14 O Upper ROM Address Lines
26–23 AA16–AA13 O Upper RAM Address Lines
32 ROM_CS O Low-Active ROM Chip Select
31 RAM_CS O Low-Active RAM Chip Select
30 RAM_CS O High-Active RAM Chip Select

Footprint: QFP80P900X900-32

Remarks: All I/O pins are protected via diodes to VCC/GND. D6..D0, A15..A13, RD, WR, CS are internally pulled down with ~50 kΩ

Registers

Write-Accessible Registers:

  • 0x0000-0x1FFF: RAM Enable register
  • 0x2000-0x3FFF: ROM Bank register
  • 0x4000-0x5FFF: RAM Bank register
  • 0x6000-0x7FFF: Mode register

RAM Enable Register

XX D6 D5 D4 D3 D2 D1 D0    0x00 @ reset
    | \___/ \_________/
    |   |        \-------- RAM Enable
    |   \----------------- Ram Bank #WE AA14..AA13
    \--------------------- Map Enable

  • RAM Enable: A value of 0x0A enables SRAM access, all other values disable SRAM access.
  • RAM Bank #WE: Low-Active Write-Enable lines for the two least-significant RAM bank bits in #RAM Bank Register. Can only be written when Map Enable is reset.
  • Map Enable: Setting this bit will disable write access to special register bits and disable the forced ROM Address line masking. Can only be written when Map Enable is reset.

ROM Bank Register

XX D6 D5 D4 D3 D2 D1 D0    0x00 @ reset
   \___/ \____________/
     |           \-------- ROM Bank RA18..RA14
     \-------------------- ROM Bank RA20..RA19

  • ROM Bank RA18..RA14: These bits select the lower ROM address lines. The written value is zero-adjusted before output on RA18–RA14 based only on bits not masked by ROM Bank #WE/Mask RA18..RA15 in #Mode Register.
  • ROM Bank RA20..RA19: These bits select the middle ROM address lines or the lower RAM address lines depending on the multiplex setting in the #Mode Register. Can only be written when Map Enable in #RAM Enable Register is reset.

RAM Bank Register

XX D6 D5 D4 D3 D2 D1 D0    0x00 @ reset
    | \___/ \___/ \___/
    |   |     |     \----- RAM Bank AA14..AA13
    |   |     \----------- RAM Bank AA16..AA15
    |   \----------------- ROM Bank RA22..RA21
    \--------------------- MBC1 Mode #WE

  • RAM Bank AA14..AA13: These bits select the middle ROM address lines or the lower RAM address lines depending on the multiplex setting in the #Mode Register. The MBC1 mode settings still apply, see #Mode Register.
  • RAM Bank AA16..AA15: These bits select the upper RAM address lines. Can only be written when Map Enable in #RAM Enable Register is reset.
  • ROM Bank RA22..RA21: These bits select the upper ROM address lines. Can only be written when Map Enable in #RAM Enable Register is reset.
  • MBC1 Mode #WE: Low-Active Write Enable for MBC1 Mode in #Mode Register. Can only be written when Map Enable in #RAM Enable Register is reset.

Mode Register

XX D6 D5 D4 D3 D2 D1 D0    0x00 @ reset
    | \_________/  |  |
    |      |       |  \--- MBC1 Mode
    |      |       \------ Unknown
    |      \-------------- ROM Bank #WE/Mask RA18..RA15
    \--------------------- Multiplexer for AA14..AA13 and RA20..RA19

  • MBC1 Mode: Selects the MBC1 operating mode. 0 for 16 Mbit/64 kbit mode and 1 for 4 MBit/256 kbit. Can only be written when MBC1 Mode #WE in #RAM Bank Register is reset.
  • Unknown: Setting or resetting this bit had no observable effect.
  • ROM Bank #WE/Mask RA18..RA15: Low-Active Write-Enable for RA18..RA15 in #ROM Bank Register as well as mask for zero-adjusting RA18..RA15. Can only be written when Map Enable in #RAM Enable Register is reset.
  • Multiplexer: The multiplexer will switch the bits output to pins AA14..AA13 and RA20..RA19. Barring MBC1 Mode logic: when reset, pins will be driven from register contents; when set, pins will be driven from the other register, i.e. RA20..RA19 will be driven by #RAM Bank Register and AA14..AA13 will be driven by #ROM Bank Register. Can only be written when Map Enable in #RAM Enable Register is reset.

Operation

Operating the MMM01 can be quite complex and the register contents are not straightforward. This section will detail the programming model and give example configurations.

Modes of Operation

Nintendo's MMM01 has two modes of operation mapped and unmapped. It defaults to unmapped after reset.

This is used to lock write access to the upper bits of the known MBC1 registers after base ROM and RAM banks and masks have been set up.

The only way to unmap the mapper after mapping is to reset it.

Programming Model

All registers are live, e.g. Setting the RAM Bank #WE bits and subsequently writing to RAM Bank AA14..AA13 won't work -- no matter if in mapped of unmapped state. Therefore, there is a certain order in which registers are optimally written:

  1. ROM Bank Register
  2. Mode Register
  3. RAM Register
  4. RAM Enable

Not all of Nintendo's games that use MMM01 keep with this order. However, due to the individual games' sizes and use of RAM banks, this isn't noticeable when the games don't misbehave.

Most Rom Address line changes cannot be observed in unmapped mode due to the mapper starting at ROM bank 0x1FE and 0x1FF (depending on A14) until mapped.

Map MBC1 Mode 0: 16 Mbit/64 kBit

  • R0: AA #WE = "00"
  • R1: RA20..RA19 = fix --> SRAM AA14..AA13 muxed
  • R2: AA16..AA15, RA22..RA21 = fix, MBC Mode #WE = "1"
  • R3: RA #WE = "0000", Mode = "0", Mux = "1"


Map MBC1 Mode 1: 4 Mbit/64 kBit (common)

  • R0: AA #WE = "11"
  • R1: RA20..RA19 = fix
  • R2: AA16..AA13, RA22..RA21 = fix, MBC Mode #WE = "1"
  • R3: RA #WE = "0000", Mode = "1", Mux = "0"

Map MBC1 Mode 1: 4 Mbit/64 kBit (uncommon)

  • R0: AA #WE = "11"
  • R1: RA20..RA19 = fix --> SRAM AA14..AA13 muxed
  • R2: AA16..AA13, RA22..RA21 = fix, MBC Mode #WE = "1"
  • R3: RA #WE = "0000", Mode = "1", Mux = "1"

This is probably not the intended use case.

Map MBC1 Mode 1: 4 Mbit/256 kBit

  • R0: AA #WE = "00"
  • R1: RA20..RA19 = fix
  • R2: AA16..AA15, RA22..RA21 = fix, MBC Mode #WE = "1"
  • R3: RA #WE = "0000", Mode = "1", Mux = "0"

Remarks

Unknown Bit

There is an Unknown bit in #Mode Register whose use -- if any -- could not be determined through testing. It is definitely not ROM Bank RA14 #WE as RA14 can be written at all times -- hence there cannot be a single bank mapped to both regions. It might be part of ROM Bank RA14 Mask and an Engineer might have missed that the zero-adjustment logic means that this bit is not necessary.

SRAM Enable/Disable

The most glaringly missing feature of MMM01 is an option to disable SRAM access for individual games. The Unknown bit in #Mode Register does not provide for this either. The only commercial cartridge containing MMM01 and SRAM is Momotarou Collection 2 and it sacrifices one RAM bank to make sure that one game has no chance of deleting the other's save file.

Having to spend 64 kBit to disable SRAM access seems like a waste considering a simple OR-gate could have stopped SRAM access.

Separate MBC1 Mode #WE

The MBC1 Mode #WE stands out as being separated from mapping logic. Instead, if its #WE is not deasserted, it can be freely written even in mapped mode. However, the address line multiplexing for 16 Mbit and 4 Mbit does not switch with the mode setting -- which given a fixed ROM/SRAM wiring on the cartridge -- would need to be done in order for a hypothetical 16 Mbit/256 kBit mode to be feasible.

Behavior

library IEEE;
use IEEE.std_logic_1164.all;

entity MMM01 is
	Port(
		RESET_N  : in  std_logic;
		RD_N     : in  std_logic;
		WR_N     : in  std_logic;
		CS_N     : in  std_logic;
		A        : in  std_logic_vector(15 downto 13);
		D        : in  std_logic_vector(6 downto 0);
		RA       : out std_logic_vector(22 downto 14);
		AA       : out std_logic_vector(16 downto 13);
		ROM_CS_N : out std_logic;
		RAM_CS_N : out std_logic;
		RAM_CS   : out std_logic
	);
end entity MMM01;

architecture Behavioral of MMM01 is

signal ram_enable_r    : std_logic_vector(3 downto 0);
signal ram_bank_we_n_r : std_logic_vector(1 downto 0);
signal latch_r         : std_logic_vector(0 downto 0);
signal rom_bank_r      : std_logic_vector(8 downto 0);
signal ram_bank_r      : std_logic_vector(3 downto 0);
signal mode_we_n_r     : std_logic_vector(6 downto 6);
signal mode_r          : std_logic_vector(0 downto 0);
signal rom_bank_we_n_r : std_logic_vector(4 downto 1);
signal mux_r           : std_logic_vector(0 downto 0);

signal ra_int          : std_logic_vector(4 downto 0);
signal aa_int          : std_logic_vector(1 downto 0);

signal ra_lo           : std_logic_vector(4 downto 0);
signal ra_mask         : std_logic_vector(4 downto 0);

signal ram_enable_r_clk : std_logic;
signal rom_bank_r_clk   : std_logic;
signal ram_bank_r_clk   : std_logic;
signal mode_r_clk       : std_logic;

alias rom_bank_r_lo : std_logic_vector(4 downto 0) is rom_bank_r(4 downto 0);

begin

-----------------------------------------------------------------------
-- Signal Assignments
-----------------------------------------------------------------------

ROM_CS_N <= '0' when (A(15) = '0' and RD_N = '0') else
            '1';

RAM_CS_N <= '0' when (CS_N = '0' and A(14) = '0' and ram_enable_r = x"A") else
            '1';
RAM_CS <= not RAM_CS_N;

ra_lo <= "11110" when (latch_r = "0") else
         rom_bank_r_lo;

ra_mask <= "11110" when (latch_r = "0") else
           rom_bank_we_n_r & "0";

ra_int <= "00000" when (A(14) = '0') else
          ra_lo   when ((ra_lo and not(ra_mask)) /= "00000") else
          "00001";

aa_int <= "00" when (A(14) = '0' and mode_r = "0") else
          ram_bank_r(1 downto 0);

AA(16 downto 15) <= ram_bank_r(3 downto 2);
AA(14 downto 13) <= aa_int when (mux_r = "0") else
                    rom_bank_r(6 downto 5);

RA(22 downto 21) <= "11" when (latch_r = "0") else
                    rom_bank_r(8 downto 7);

RA(20 downto 19) <= "11"   when (latch_r = "0") else
                    aa_int when (mux_r = "1") else
                    rom_bank_r(6 downto 5);

RA(18 downto 14) <= (ra_lo and ra_mask) or (ra_int and not(ra_mask));

ram_enable_r_clk <= '0' when (A = "000" and WR_N = '0') else
                    '1';

rom_bank_r_clk <= '0' when (A = "001" and WR_N = '0') else
                  '1';

ram_bank_r_clk <= '0' when (A = "010" and WR_N = '0') else
                  '1';

mode_r_clk <= '0' when (A = "011" and WR_N = '0') else
              '1';

-----------------------------------------------------------------------
-- Registers
-----------------------------------------------------------------------

ram_enable_p : process (
	RESET_N,
	ram_enable_r_clk
	)
begin

	if (RESET_N = '0') then

		ram_enable_r <= x"0";
		ram_bank_we_n_r <= "00";
		latch_r <= "0";

	elsif (rising_edge(ram_enable_r_clk)) then

		ram_enable_r <= D(3 downto 0);
		
		if (latch_r = "0") then
			ram_bank_we_n_r <= D(5 downto 4);
			latch_r <= D(6 downto 6);
		end if;

	end if;

end process ram_enable_p;

rom_bank_p : process (
	RESET_N,
	rom_bank_r_clk
	)
begin

	if (RESET_N = '0') then
		
		rom_bank_r(6 downto 0) <= "0000000";
		
	elsif (rising_edge(rom_bank_r_clk)) then
		
		rom_bank_r(0) <= D(0);
		
		for i in rom_bank_we_n_r'range loop
			if (rom_bank_we_n_r(i) = '0') then
				rom_bank_r_lo(i) <= D(i);
			end if;
		end loop;
		
		if (latch_r = "0") then
			rom_bank_r(6 downto 5) <= D(6 downto 5);
		end if;

	end if;

end process rom_bank_p;

ram_bank_p : process (
	RESET_N,
	ram_bank_r_clk
	)
begin

	if (RESET_N = '0') then

		ram_bank_r <= "0000";
		rom_bank_r(8 downto 7) <= "00";

	elsif (rising_edge(ram_bank_r_clk)) then

		for i in ram_bank_we_n_r'range loop
			if (ram_bank_we_n_r(i) = '0') then
				ram_bank_r(i) <= D(i);
			end if;
		end loop;
		
		if (latch_r = "0") then
			ram_bank_r(3 downto 2) <= D(3 downto 2);
			rom_bank_r(8 downto 7) <= D(5 downto 4);
			mode_we_n_r <= D(6 downto 6);
		end if;
	end if;

end process ram_bank_p;

mode_p : process (
	RESET_N,
	mode_r_clk
	)
begin

	if (RESET_N = '0') then

		mode_r <= "0";
		rom_bank_we_n_r <= "0000";
		mux_r <= "0";

	elsif (rising_edge(mode_r_clk)) then

		for i in mode_we_n_r'range loop
			if (mode_we_n_r(i) = '0') then
				mode_r(i) <= D(i);
			end if;
		end loop;
		
		if (latch_r = "1") then
			rom_bank_we_n_r <= D(5 downto 2);
			mux_r <= D(6 downto 6);
		end if;

	end if;

end process mode_p;

end architecture Behavioral;