using System; using BizHawk.Common.BufferExtensions; using BizHawk.Emulation.Common; /* $FFFF Interrupt Enable Flag $FF80-$FFFE Zero Page - 127 bytes $FF00-$FF7F Hardware I/O Registers $FEA0-$FEFF Unusable Memory $FE00-$FE9F OAM - Object Attribute Memory $E000-$FDFF Echo RAM - Reserved, Do Not Use $D000-$DFFF Internal RAM - Bank 1-7 (switchable - CGB only) $C000-$CFFF Internal RAM - Bank 0 (fixed) $A000-$BFFF Cartridge RAM (If Available) $9C00-$9FFF BG Map Data 2 $9800-$9BFF BG Map Data 1 $8000-$97FF Character RAM $4000-$7FFF Cartridge ROM - Switchable Banks 1-xx $0150-$3FFF Cartridge ROM - Bank 0 (fixed) $0100-$014F Cartridge Header Area $0000-$00FF Restart and Interrupt Vectors */ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { public partial class GBHawk { public byte ReadMemory(ushort addr) { MemoryCallbacks.CallReads(addr, "System Bus"); addr_access = addr; if (ppu.DMA_start) { // some of gekkio's tests require these to be accessible during DMA if (addr < 0x8000) { if (ppu.DMA_addr < 0x80) { return 0xFF; } else { return mapper.ReadMemory(addr); } } else if ((addr >= 0xE000) && (addr < 0xF000)) { return RAM[addr - 0xE000]; } else if ((addr >= 0xF000) && (addr < 0xFE00)) { return RAM[(RAM_Bank * 0x1000) + (addr - 0xF000)]; } else if ((addr >= 0xFE00) && (addr < 0xFEA0) && ppu.DMA_OAM_access) { return OAM[addr - 0xFE00]; } else if ((addr >= 0xFF00) && (addr < 0xFF80)) // The game GOAL! Requires Hardware Regs to be accessible { return Read_Registers(addr); } else if ((addr >= 0xFF80)) { return ZP_RAM[addr - 0xFF80]; } return 0xFF; } if (addr < 0x900) { if (addr < 0x100) { // return Either BIOS ROM or Game ROM if ((GB_bios_register & 0x1) == 0) { return _bios[addr]; // Return BIOS } else { return mapper.ReadMemory(addr); } } else if (addr >= 0x200) { // return Either BIOS ROM or Game ROM if (((GB_bios_register & 0x1) == 0) && is_GBC) { return _bios[addr]; // Return BIOS } else { return mapper.ReadMemory(addr); } } else { return mapper.ReadMemory(addr); } } else if (addr < 0x8000) { return mapper.ReadMemory(addr); } else if (addr < 0xA000) { if (ppu.VRAM_access_read) { return VRAM[(VRAM_Bank * 0x2000) + (addr - 0x8000)]; } else { return 0xFF; } } else if (addr < 0xC000) { return mapper.ReadMemory(addr); } else if (addr < 0xD000) { return RAM[addr - 0xC000]; } else if (addr < 0xE000) { return RAM[(RAM_Bank * 0x1000) + (addr - 0xD000)]; } else if (addr < 0xF000) { return RAM[addr - 0xE000]; } else if (addr < 0xFE00) { return RAM[(RAM_Bank * 0x1000) + (addr - 0xF000)]; } else if (addr < 0xFEA0) { if (ppu.OAM_access_read) { return OAM[addr - 0xFE00]; } else { return 0xFF; } } else if (addr < 0xFF00) { // unmapped memory, returns 0xFF return 0xFF; } else if (addr < 0xFF80) { return Read_Registers(addr); } else if (addr < 0xFFFF) { return ZP_RAM[addr - 0xFF80]; } else { return Read_Registers(addr); } } public void WriteMemory(ushort addr, byte value) { MemoryCallbacks.CallWrites(addr, "System Bus"); addr_access = addr; if (ppu.DMA_start) { // some of gekkio's tests require this to be accessible during DMA if ((addr >= 0xE000) && (addr < 0xF000)) { RAM[addr - 0xE000] = value; } else if ((addr >= 0xF000) && (addr < 0xFE00)) { RAM[(RAM_Bank * 0x1000) + (addr - 0xF000)] = value; } else if ((addr >= 0xFE00) && (addr < 0xFEA0) && ppu.DMA_OAM_access) { OAM[addr - 0xFE00] = value; } else if ((addr >= 0xFF00) && (addr < 0xFF80)) // The game GOAL! Requires Hardware Regs to be accessible { Write_Registers(addr, value); } else if ((addr >= 0xFF80)) { ZP_RAM[addr - 0xFF80] = value; } return; } if (addr < 0x900) { if (addr < 0x100) { if ((GB_bios_register & 0x1) == 0) { // No Writing to BIOS } else { mapper.WriteMemory(addr, value); } } else if (addr >= 0x200) { if (((GB_bios_register & 0x1) == 0) && is_GBC) { // No Writing to BIOS } else { mapper.WriteMemory(addr, value); } } else { mapper.WriteMemory(addr, value); } } else if (addr < 0x8000) { mapper.WriteMemory(addr, value); } else if (addr < 0xA000) { if (ppu.VRAM_access_write) { VRAM[(VRAM_Bank * 0x2000) + (addr - 0x8000)] = value; } } else if (addr < 0xC000) { mapper.WriteMemory(addr, value); } else if (addr < 0xD000) { RAM[addr - 0xC000] = value; } else if (addr < 0xE000) { RAM[(RAM_Bank * 0x1000) + (addr - 0xD000)] = value; } else if (addr < 0xF000) { RAM[addr - 0xE000] = value; } else if (addr < 0xFE00) { RAM[(RAM_Bank * 0x1000) + (addr - 0xF000)] = value; } else if (addr < 0xFEA0) { if (ppu.OAM_access_write) { OAM[addr - 0xFE00] = value; } } else if (addr < 0xFF00) { // unmapped, writing has no effect } else if (addr < 0xFF80) { Write_Registers(addr, value); } else if (addr < 0xFFFF) { ZP_RAM[addr - 0xFF80] = value; } else { Write_Registers(addr, value); } } public byte PeekMemory(ushort addr) { if (ppu.DMA_start) { // some of gekkio's tests require these to be accessible during DMA if (addr < 0x8000) { if (ppu.DMA_addr < 0x80) { return 0xFF; } else { return mapper.ReadMemory(addr); } } else if ((addr >= 0xE000) && (addr < 0xF000)) { return RAM[addr - 0xE000]; } else if ((addr >= 0xF000) && (addr < 0xFE00)) { return RAM[(RAM_Bank * 0x1000) + (addr - 0xF000)]; } else if ((addr >= 0xFE00) && (addr < 0xFEA0) && ppu.DMA_OAM_access) { return OAM[addr - 0xFE00]; } else if ((addr >= 0xFF00) && (addr < 0xFF80)) // The game GOAL! Requires Hardware Regs to be accessible { return Read_Registers(addr); } else if ((addr >= 0xFF80)) { return ZP_RAM[addr - 0xFF80]; } return 0xFF; } if (addr < 0x900) { if (addr < 0x100) { // return Either BIOS ROM or Game ROM if ((GB_bios_register & 0x1) == 0) { return _bios[addr]; // Return BIOS } else { return mapper.ReadMemory(addr); } } else if (addr >= 0x200) { // return Either BIOS ROM or Game ROM if (((GB_bios_register & 0x1) == 0) && is_GBC) { return _bios[addr]; // Return BIOS } else { return mapper.ReadMemory(addr); } } else { return mapper.ReadMemory(addr); } } else if (addr < 0x8000) { return mapper.PeekMemory(addr); } else if (addr < 0xA000) { if (ppu.VRAM_access_read) { return VRAM[(VRAM_Bank * 0x2000) + (addr - 0x8000)]; } else { return 0xFF; } } else if (addr < 0xC000) { return mapper.PeekMemory(addr); } else if (addr < 0xD000) { return RAM[addr - 0xC000]; } else if (addr < 0xE000) { return RAM[(RAM_Bank * 0x1000) + (addr - 0xD000)]; } else if (addr < 0xF000) { return RAM[addr - 0xE000]; } else if (addr < 0xFE00) { return RAM[(RAM_Bank * 0x1000) + (addr - 0xF000)]; } else if (addr < 0xFEA0) { if (ppu.OAM_access_read) { return OAM[addr - 0xFE00]; } else { return 0xFF; } } else if (addr < 0xFF00) { // unmapped memory, returns 0xFF return 0xFF; } else if (addr < 0xFF80) { return Read_Registers(addr); } else if (addr < 0xFFFF) { return ZP_RAM[addr - 0xFF80]; } else { return Read_Registers(addr); } } } }