feat(memory): add MMU memory map and OAM DMA
This commit is contained in:
1 parent
3c947b637e
commit
de52cc23cf
2 files changed
+206
No files matched your search
@@ -0,0 +1,142 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using GameBoy.Audio;
|
||||||
|
using GameBoy.Cpu;
|
||||||
|
using GameBoy.Input;
|
||||||
|
using GameBoy.Serial;
|
||||||
|
using GameBoy.Timing;
|
||||||
|
using GameBoy.Video;
|
||||||
|
|
||||||
|
namespace GameBoy.Memory
|
||||||
|
{
|
||||||
|
public sealed class Mmu
|
||||||
|
{
|
||||||
|
private readonly Cartridge.Cartridge cartridge;
|
||||||
|
private readonly Ppu ppu;
|
||||||
|
private readonly Timer timer;
|
||||||
|
private readonly Joypad joypad;
|
||||||
|
private readonly SerialPort serial;
|
||||||
|
private readonly Apu apu;
|
||||||
|
private readonly InterruptController interrupts;
|
||||||
|
|
||||||
|
private readonly byte[] wram = new byte[0x2000];
|
||||||
|
private readonly byte[] hram = new byte[0x7F];
|
||||||
|
|
||||||
|
public OamDma? Dma;
|
||||||
|
|
||||||
|
public Mmu(
|
||||||
|
Cartridge.Cartridge cartridge,
|
||||||
|
Ppu ppu,
|
||||||
|
Timer timer,
|
||||||
|
Joypad joypad,
|
||||||
|
SerialPort serial,
|
||||||
|
Apu apu,
|
||||||
|
InterruptController interrupts)
|
||||||
|
{
|
||||||
|
this.cartridge = cartridge;
|
||||||
|
this.ppu = ppu;
|
||||||
|
this.timer = timer;
|
||||||
|
this.joypad = joypad;
|
||||||
|
this.serial = serial;
|
||||||
|
this.apu = apu;
|
||||||
|
this.interrupts = interrupts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte Read(ushort address)
|
||||||
|
{
|
||||||
|
if (address < 0x8000)
|
||||||
|
return cartridge.Read(address);
|
||||||
|
if (address < 0xA000)
|
||||||
|
return ppu.ReadVram(address);
|
||||||
|
if (address < 0xC000)
|
||||||
|
return cartridge.Read(address);
|
||||||
|
if (address < 0xE000)
|
||||||
|
return wram[address - 0xC000];
|
||||||
|
if (address < 0xFE00)
|
||||||
|
return wram[address - 0xE000];
|
||||||
|
if (address < 0xFEA0)
|
||||||
|
return ppu.ReadOam(address);
|
||||||
|
if (address < 0xFF00)
|
||||||
|
return 0xFF;
|
||||||
|
if (address < 0xFF80)
|
||||||
|
return ReadIo(address);
|
||||||
|
if (address < 0xFFFF)
|
||||||
|
return hram[address - 0xFF80];
|
||||||
|
return interrupts.Enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(ushort address, byte value)
|
||||||
|
{
|
||||||
|
if (address < 0x8000)
|
||||||
|
cartridge.Write(address, value);
|
||||||
|
else if (address < 0xA000)
|
||||||
|
ppu.WriteVram(address, value);
|
||||||
|
else if (address < 0xC000)
|
||||||
|
cartridge.Write(address, value);
|
||||||
|
else if (address < 0xE000)
|
||||||
|
wram[address - 0xC000] = value;
|
||||||
|
else if (address < 0xFE00)
|
||||||
|
wram[address - 0xE000] = value;
|
||||||
|
else if (address < 0xFEA0)
|
||||||
|
ppu.WriteOam(address, value);
|
||||||
|
else if (address < 0xFF00)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (address < 0xFF80)
|
||||||
|
WriteIo(address, value);
|
||||||
|
else if (address < 0xFFFF)
|
||||||
|
hram[address - 0xFF80] = value;
|
||||||
|
else
|
||||||
|
interrupts.Enable = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte ReadIo(ushort address)
|
||||||
|
{
|
||||||
|
if (address == 0xFF00)
|
||||||
|
return joypad.Read();
|
||||||
|
if (address == 0xFF01 || address == 0xFF02)
|
||||||
|
return serial.Read(address);
|
||||||
|
if (address >= 0xFF04 && address <= 0xFF07)
|
||||||
|
return timer.Read(address);
|
||||||
|
if (address == 0xFF0F)
|
||||||
|
return interrupts.ReadFlag();
|
||||||
|
if (address >= 0xFF10 && address <= 0xFF3F)
|
||||||
|
return apu.Read(address);
|
||||||
|
if (address == 0xFF46)
|
||||||
|
return Dma!.Page;
|
||||||
|
if (address >= 0xFF40 && address <= 0xFF4B)
|
||||||
|
return ppu.ReadRegister(address);
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteIo(ushort address, byte value)
|
||||||
|
{
|
||||||
|
if (address == 0xFF00)
|
||||||
|
joypad.Write(value);
|
||||||
|
else if (address == 0xFF01 || address == 0xFF02)
|
||||||
|
serial.Write(address, value);
|
||||||
|
else if (address >= 0xFF04 && address <= 0xFF07)
|
||||||
|
timer.Write(address, value);
|
||||||
|
else if (address == 0xFF0F)
|
||||||
|
interrupts.WriteFlag(value);
|
||||||
|
else if (address >= 0xFF10 && address <= 0xFF3F)
|
||||||
|
apu.Write(address, value);
|
||||||
|
else if (address == 0xFF46)
|
||||||
|
Dma!.Start(value);
|
||||||
|
else if (address >= 0xFF40 && address <= 0xFF4B)
|
||||||
|
ppu.WriteRegister(address, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveState(BinaryWriter writer)
|
||||||
|
{
|
||||||
|
writer.Write(wram);
|
||||||
|
writer.Write(hram);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadState(BinaryReader reader)
|
||||||
|
{
|
||||||
|
Array.Copy(reader.ReadBytes(wram.Length), wram, wram.Length);
|
||||||
|
Array.Copy(reader.ReadBytes(hram.Length), hram, hram.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
using System.IO;
|
||||||
|
using GameBoy.Video;
|
||||||
|
|
||||||
|
namespace GameBoy.Memory
|
||||||
|
{
|
||||||
|
public sealed class OamDma
|
||||||
|
{
|
||||||
|
private readonly Mmu mmu;
|
||||||
|
private readonly Ppu ppu;
|
||||||
|
|
||||||
|
private bool active;
|
||||||
|
private int index;
|
||||||
|
private int subDot;
|
||||||
|
|
||||||
|
public byte Page { get; private set; }
|
||||||
|
|
||||||
|
public OamDma(Mmu mmu, Ppu ppu)
|
||||||
|
{
|
||||||
|
this.mmu = mmu;
|
||||||
|
this.ppu = ppu;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start(byte page)
|
||||||
|
{
|
||||||
|
Page = page;
|
||||||
|
active = true;
|
||||||
|
index = 0;
|
||||||
|
subDot = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Step()
|
||||||
|
{
|
||||||
|
if (!active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
subDot++;
|
||||||
|
if (subDot < 4)
|
||||||
|
return;
|
||||||
|
|
||||||
|
subDot = 0;
|
||||||
|
ushort source = (ushort)((Page << 8) | index);
|
||||||
|
ppu.WriteOamDma(index, mmu.Read(source));
|
||||||
|
index++;
|
||||||
|
if (index == 0xA0)
|
||||||
|
active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveState(BinaryWriter writer)
|
||||||
|
{
|
||||||
|
writer.Write(active);
|
||||||
|
writer.Write(index);
|
||||||
|
writer.Write(subDot);
|
||||||
|
writer.Write(Page);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadState(BinaryReader reader)
|
||||||
|
{
|
||||||
|
active = reader.ReadBoolean();
|
||||||
|
index = reader.ReadInt32();
|
||||||
|
subDot = reader.ReadInt32();
|
||||||
|
Page = reader.ReadByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user