BizHawk/BizHawk.Emulation/Consoles/GB/MemoryMap.cs

240 lines
6.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Consoles.GB
{
public partial class GB
{
// Flag indicating ig BIOS is mapped in.
private bool inBIOS = true;
// Memory regions (initialised at reset time)
private byte[] BIOS = new byte[1];
private byte[] ROM = new byte[1];
private byte[] WRAM = new byte[1];
private byte[] ERAM = new byte[1];
private byte[] ZRAM = new byte[1];
public byte ReadMemory(ushort addr)
{
switch (addr & 0xF000)
{
/*
[0000-3FFF] Cartridge ROM, bank 0: The first 16,384 bytes of
the cartridge program are always available at this point in the
memory map. Special circumstances apply.
*/
case 0x0000:
/*
[0000-0100] BIOS: When the CPU starts up, PC starts at
0000h, which is the start of the 256-byte GameBoy BIOS
code. Once the BIOS has run, it is removed from the memory
map, and this area of the cartridge rom becomes
addressable.
*/
if (inBIOS)
{
if (addr < 0x0100)
return BIOS[addr];
else if (addr == 0x0100)
inBIOS = false;
}
/*
[0100-014F] Cartridge header: This section of the cartridge
contains data about its name and manufacturer, and must be
written in a specific format.
*/
return ROM[addr];
case 0x1000:
case 0x2000:
case 0x3000:
return ROM[addr];
/*
[4000-7FFF] Cartridge ROM, other banks: Any subsequent 16k
"banks" of the cartridge program can be made available to the
CPU here, one by one; a chip on the cartridge is generally used
to switch between banks, and make a particular area accessible.
The smallest programs are 32k, which means that no
bank-selection chip is required.
*/
case 0x4000:
case 0x5000:
case 0x6000:
case 0x7000:
return ROM[addr];
/*
[8000-9FFF] Graphics RAM: Data required for the backgrounds and
sprites used by the graphics subsystem is held here, and can be
changed by the cartridge program.
*/
case 0x8000:
case 0x9000:
return VRAM[addr & 0x1FFF];
/*
[A000-BFFF] Cartridge (External) RAM: There is a small amount
of writeable memory available in the GameBoy; if a game is
produced that requires more RAM than is available in the
hardware, additional 8k chunks of RAM can be made addressable
here.
*/
case 0xA000:
case 0xB000:
return ERAM[addr & 0x1FFF];
/*
[C000-DFFF] Working RAM: The GameBoy's internal 8k of RAM,
which can be read from or written to by the CPU.
*/
case 0xC000:
case 0xD000:
return WRAM[addr & 0x1FFF];
/*
[E000-FDFF] Working RAM (shadow): Due to the wiring of the
GameBoy hardware, an exact copy of the working RAM is available
8k higher in the memory map. This copy is available up until
the last 512 bytes of the map, where other areas are brought
into access.
*/
case 0xE000:
return WRAM[addr & 0x1FFF];
case 0xF000:
switch (addr & 0x0F00)
{
case 0x000:
case 0x100:
case 0x200:
case 0x300:
case 0x400:
case 0x500:
case 0x600:
case 0x700:
case 0x800:
case 0x900:
case 0xA00:
case 0xB00:
case 0xC00:
case 0xD00:
return WRAM[addr & 0x1FFF];
/*
[FE00-FE9F] Graphics: sprite information: Data about
the sprites rendered by the graphics chip are held
here, including the sprites' positions and attributes.
*/
case 0xE00:
// OAM is 160 bytes, remaining bytes read as 0.
if (addr < 0xFEA0)
return OAM[addr & 0xFF];
else
return 0;
case 0xF00:
/*
[FF00-FF7F] Memory-mapped I/O: Each of the
GameBoy's subsystems (graphics, sound, etc.) has
control values, to allow programs to create effects
and use the hardware. These values are available to
the CPU directly on the address bus, in this area.
*/
if (addr < 0xFF80)
throw new NotImplementedException();
/*
[FF80-FFFF] Zero-page RAM: A high-speed area of 128
bytes of RAM is available at the top of memory.
Oddly, though this is "page" 255 of the memory, it
is referred to as page zero, since
most of the interaction between the program and
the GameBoy hardware occurs through use of this
page of memory.
*/
else
return ZRAM[addr & 0x7F];
default:
throw new ArgumentException();
}
default:
throw new ArgumentException();
}
}
public void WriteMemory(ushort addr, byte val)
{
// Writing is the same as reading with the operations reversed.
switch (addr & 0xF000)
{
case 0x0000:
if (inBIOS)
{
if (addr < 0x0100)
{
BIOS[addr] = val;
break;
}
else if (addr == 0x0100)
inBIOS = false;
}
ROM[addr] = val;
break;
case 0x1000:
case 0x2000:
case 0x3000:
ROM[addr] = val;
break;
case 0x4000:
case 0x5000:
case 0x6000:
case 0x7000:
ROM[addr] = val;
break;
case 0x8000:
case 0x9000:
VRAM[addr & 0x1FFF] = val;
break;
case 0xA000:
case 0xB000:
ERAM[addr & 0x1FFF] = val;
break;
case 0xC000:
case 0xD000:
WRAM[addr & 0x1FFF] = val;
break;
case 0xE000:
WRAM[addr & 0x1FFF] = val;
break;
case 0xF000:
switch (addr & 0x0F00)
{
case 0x000:
case 0x100:
case 0x200:
case 0x300:
case 0x400:
case 0x500:
case 0x600:
case 0x700:
case 0x800:
case 0x900:
case 0xA00:
case 0xB00:
case 0xC00:
case 0xD00:
WRAM[addr & 0x1FFF] = val;
break;
case 0xE00:
if (addr < 0xFEA0)
OAM[addr & 0xFF] = val;
break;
case 0xF00:
if (addr < 0xFF80)
throw new NotImplementedException();
else
{
ZRAM[addr & 0x7F] = val;
break;
}
}
break;
}
}
}
}