Difference between revisions of "MBC2"

From Tauwasser's Wiki
Jump to: navigation, search
(Behavior: add behavioral model)
m (I/O supply pins also supply core logic)
 
(5 intermediate revisions by the same user not shown)
Line 16: Line 16:
 
|VCC
 
|VCC
 
|PWR
 
|PWR
|I/O 5V supply
+
|I/O + logic 5V supply
 
|-
 
|-
 
|14
 
|14
 
|GND
 
|GND
 
|PWR
 
|PWR
|I/O Ground supply
+
|I/O + logic Ground supply
 
|-
 
|-
 
|21
 
|21
Line 33: Line 33:
 
|RAM Ground supply
 
|RAM Ground supply
 
|-
 
|-
|12{{ndash}}9
+
|12–9
|D3{{ndash}}D0
+
|D3–D0
 
|I/O
 
|I/O
 
|Data Bus
 
|Data Bus
Line 58: Line 58:
 
|Low-Active Asynchronous Reset
 
|Low-Active Asynchronous Reset
 
|-
 
|-
|20, 22{{ndash}}25, 8, 6{{ndash}}2
+
|20, 22–25, 8, 6–2
|A15{{ndash}}A14, A8{{ndash}}A0
+
|A15–A14, A8–A0
 
|I
 
|I
 
|Address Bus
 
|Address Bus
 
|-
 
|-
|16{{ndash}}19
+
|16–19
|RA17{{ndash}}RA14
+
|RA17–RA14
 
|O
 
|O
 
|Upper ROM Address Lines
 
|Upper ROM Address Lines
Line 86: Line 86:
 
* <tt>0b00-- ---0 ---- ----</tt>: RAM Enable register
 
* <tt>0b00-- ---0 ---- ----</tt>: RAM Enable register
 
* <tt>0b00-- ---1 ---- ----</tt>: ROM Bank register
 
* <tt>0b00-- ---1 ---- ----</tt>: ROM Bank register
 +
 +
Read-Write-Accessible Registers:
 
* <tt>0b10-- ---a aaaa aaaa</tt>: Internal RAM
 
* <tt>0b10-- ---a aaaa aaaa</tt>: Internal RAM
  
Line 108: Line 110:
 
</pre>
 
</pre>
  
ROM Bank selects which bank is mapped to 0x4000-0x7FFF. The written value is zero-adjusted before output on RA17{{ndash}}RA14.
+
ROM Bank selects which bank is mapped to 0x4000-0x7FFF. The written value is zero-adjusted before output on RA17&ndash;RA14.
  
 
= Behavior =
 
= Behavior =
 +
 +
When both {{Overline|RD}} and {{Overline|WR}} are low, MBC2 will drive 0x00 on D3..D0. The same is true for the reset state ({{Overline|RESET}} asserted). Therefore I modeled the behavior as belonging to the internal SRAM.
 +
There might be a power-up bug with MBC2. Many games do not make use of 0xA000, maybe because there really is a problem at reset.
  
 
<source lang="vhdl">
 
<source lang="vhdl">
 
library IEEE;
 
library IEEE;
 
use IEEE.std_logic_1164.all;
 
use IEEE.std_logic_1164.all;
 +
use IEEE.numeric_std.all;
  
 
entity MBC2 is
 
entity MBC2 is
Line 126: Line 132:
 
D        : inout std_logic_vector(3 downto 0);
 
D        : inout std_logic_vector(3 downto 0);
 
RA      : out  std_logic_vector(17 downto 14);
 
RA      : out  std_logic_vector(17 downto 14);
ROM_CS_N : out  std_logic;
+
ROM_CS_N : out  std_logic
 
);
 
);
 
end entity MBC2;
 
end entity MBC2;
Line 141: Line 147:
 
signal ram_enable_r_clk : std_logic;
 
signal ram_enable_r_clk : std_logic;
 
signal rom_bank_r_clk  : std_logic;
 
signal rom_bank_r_clk  : std_logic;
 +
signal ram_clk          : std_logic;
  
 
signal ram_cs_n : std_logic;
 
signal ram_cs_n : std_logic;
Line 178: Line 185:
 
rom_bank_r_clk <= '0' when (A_HI_int = "00" and A_int(8) = '1' and WR_N_int = '0') else
 
rom_bank_r_clk <= '0' when (A_HI_int = "00" and A_int(8) = '1' and WR_N_int = '0') else
 
                   '1';
 
                   '1';
 +
 +
ram_clk <= not RD_N_int or WR_N_int or ram_cs_n;
  
 
-----------------------------------------------------------------------
 
-----------------------------------------------------------------------
Line 224: Line 233:
 
WR_N_int,
 
WR_N_int,
 
RD_N_int,
 
RD_N_int,
ram_cs_n
+
ram_cs_n,
 +
ram_clk
 
)
 
)
 
begin
 
begin
Line 241: Line 251:
  
 
-- write
 
-- write
if (rising_edge(not RD_N_int and WR_N_int and ram_cs_n)) then
+
if (rising_edge(ram_clk)) then
 
 
 
ram(to_integer(unsigned(A_int))) <= D;
 
ram(to_integer(unsigned(A_int))) <= D;

Latest revision as of 05:21, 9 June 2017

Nintendo's MBC2 can be used to address up to 2 Mbit of ROM and 512×4 bit of internal RAM.

Pinout

MBC2 Pinout.png
Pin No. Name Type Comment
28 VCC PWR I/O + logic 5V supply
14 GND PWR I/O + logic Ground supply
21 VCC_RAM PWR RAM supply
7 GND_RAM PWR RAM Ground supply
12–9 D3–D0 I/O Data Bus
1 RD I Low-Active Read Enable
27 WR I Low-Active Write Enable
26 CS I Low-Active Chip Select
15 RESET I Low-Active Asynchronous Reset
20, 22–25, 8, 6–2 A15–A14, A8–A0 I Address Bus
16–19 RA17–RA14 O Upper ROM Address Lines
13 ROM_CS O Low-Active ROM Chip Select

Footprint: SOP127P1200X225-24

Remarks: All I/O pins are protected via diodes to VCC/GND. VCC and VCC_RAM both supply RAM -- probably depending on VCC voltage.

Registers

Write-Accessible Registers:

  • 0b00-- ---0 ---- ----: RAM Enable register
  • 0b00-- ---1 ---- ----: ROM Bank register

Read-Write-Accessible Registers:

  • 0b10-- ---a aaaa aaaa: Internal RAM

RAM Enable Register

XX XX XX XX D3 D2 D1 D0    0x00 @ reset
            \_________/
                 \-------- RAM Enable

A value of 0x0A enables RAM access, all other values disable RAM access.

ROM Bank Register

XX XX XX XX D3 D2 D1 D0    0x00 @ reset
            \_________/
                 \-------- ROM Bank

ROM Bank selects which bank is mapped to 0x4000-0x7FFF. The written value is zero-adjusted before output on RA17–RA14.

Behavior

When both RD and WR are low, MBC2 will drive 0x00 on D3..D0. The same is true for the reset state (RESET asserted). Therefore I modeled the behavior as belonging to the internal SRAM. There might be a power-up bug with MBC2. Many games do not make use of 0xA000, maybe because there really is a problem at reset.

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity MBC2 is
	Port(
		RESET_N  : in    std_logic;
		RD_N     : in    std_logic;
		WR_N     : in    std_logic;
		CS_N     : in    std_logic;
		A_HI     : in    std_logic_vector(15 downto 14);
		A        : in    std_logic_vector(8 downto 0);
		D        : inout std_logic_vector(3 downto 0);
		RA       : out   std_logic_vector(17 downto 14);
		ROM_CS_N : out   std_logic
	);
end entity MBC2;

architecture Behavioral of MBC2 is

type ram_type is array(natural range <>) of std_logic_vector(3 downto 0);

signal ram : ram_type(0 to 511);

signal ram_enable_r : std_logic_vector(3 downto 0);
signal rom_bank_r   : std_logic_vector(3 downto 0);

signal ram_enable_r_clk : std_logic;
signal rom_bank_r_clk   : std_logic;
signal ram_clk          : std_logic;

signal ram_cs_n : std_logic;

signal A_HI_int : std_logic_vector(A_HI'range);
signal A_int    : std_logic_vector(A'range);

signal RD_N_int : std_logic;
signal WR_N_int : std_logic;
signal CS_N_int : std_logic;

begin

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

A_HI_int <= A_HI and RESET_N;
A_int    <= A    and RESET_N;
RD_N_int <= RD_N and RESET_N;
WR_N_int <= WR_N and RESET_N;
CS_N_int <= CS_N and RESET_N;

ROM_CS_N <= '0' when (A_HI_int(15) = '0' and RD_N_int = '0') else
            '1';

ram_cs_n <= '0' when ((CS_N_int = '0' and A_HI_int(14) = '0' and ram_enable_r = x"A") or RESET_N = '0') else
            '1';

RA <= "0000"     when (A_HI_int(14) = '0') else
      rom_bank_r when (rom_bank_r /= "0000") else
      "0001";

ram_enable_r_clk <= '0' when (A_HI_int = "00" and A_int(8) = '0' and WR_N_int = '0') else
                    '1';

rom_bank_r_clk <= '0' when (A_HI_int = "00" and A_int(8) = '1' and WR_N_int = '0') else
                  '1';

ram_clk <= not RD_N_int or WR_N_int or ram_cs_n;

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

ram_enable_p : process (
	RESET_N,
	ram_enable_r_clk
	)
begin

	if (RESET_N = '0') then
	
		ram_enable_r <= x"0";
	
	elsif (rising_edge(ram_enable_r_clk)) then
	
		ram_enable_r <= D;
	
	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 <= "0000";
	
	elsif (rising_edge(rom_bank_r_clk)) then
	
		rom_bank_r <= D;
	
	end if;
	
end process rom_bank_p;

ram_p : process (
	A_int,
	D,
	WR_N_int,
	RD_N_int,
	ram_cs_n,
	ram_clk
	)
begin

	-- default tri-state
	D <= "ZZZZ";
	
	-- read
	if (ram_cs_n = '0' and RD_N_int = '0' and WR_N_int /= '0') then
		-- write deasserted
		D <= ram(to_integer(unsigned(A_int)));
	elsif (ram_cs_n = '0' and RD_N_int = '0') then
		-- read and write asserted
		D <= "0000";
	end if;

	-- write
	if (rising_edge(ram_clk)) then
	
		ram(to_integer(unsigned(A_int))) <= D;
	
	end if;

end process ram_p;

end architecture Behavioral;