240 lines
6.2 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
}
|