public byte ReadByte(int address) { if (address < 0XFF) { return(_bios[address]); } if (address < 0x8000) { return(_cartridge.ReadByte(address)); } if (address < 0xA000) { return(_gpu.ReadByte(address)); } if (address < 0xC000) { return(_cartridge.ReadByte(address)); } if (address < 0xFE00) { return(_lowRam[address]); } if (address < 0xFEA0) { return(_gpu.ReadByte(address)); } if (address < 0xFF40) { return(_sound[address - 0xFF00]); } if (address < 0xFF80) { return(_gpu.ReadByte(address)); } if (address < 0xFFFF) // FF80 -> FFFE { return(_highRam[address & 0x7F]); } return(GetBufferArea(address)[0]); throw new NotImplementedException("MMU failed at address " + address); }
public void WriteByteTest(ushort address, byte value, byte expected) { var data = new byte[0x8000]; _cartridge = new Cartridge(data); _cartridge.WriteByte(address, value); Assert.Equal(expected, _cartridge.ReadByte(address)); }
public void ReadByteTest(ushort address, byte expected) { var data = new byte[0x8000]; if (address < data.Length) { data[address] = expected; } _cartridge = new Cartridge(data); Assert.Equal(expected, _cartridge.ReadByte(address)); }
// For debugging display public string NextThreeBytes() { return(cartridge.ReadByte(PC).ToString("X2") + " " + cartridge.ReadByte((ushort)(PC + 1)).ToString("X2") + " " + cartridge.ReadByte((ushort)(PC + 2)).ToString("X2")); }
public int ReadByte(int address) { if (address <= 0x7FFF || (address >= 0xA000 && address <= 0xBFFF)) { return(cartridge.ReadByte(address)); } else if (address >= 0x8000 && address <= 0x9FFF) { return(vRam[address - 0x8000]); } else if (address >= 0xC000 && address <= 0xDFFF) { return(wRam[address - 0xC000]); } else if (address >= 0xE000 && address <= 0xFDFF) { return(wRam[address - 0xE000]); } else if (address >= 0xFE00 && address <= 0xFEFF) { return(oam[address - 0xFE00]); } else if (address >= 0xFF80 && address <= 0xFFFE) { return(highRam[0xFF & address]); } else { switch (address) { case 0xFF00: // key pad if (keyP14) { int value = 0; if (!downKeyPressed) { value |= 0x08; } if (!upKeyPressed) { value |= 0x04; } if (!leftKeyPressed) { value |= 0x02; } if (!rightKeyPressed) { value |= 0x01; } return(value); } else if (keyP15) { int value = 0; if (!startButtonPressed) { value |= 0x08; } if (!selectButtonPressed) { value |= 0x04; } if (!bButtonPressed) { value |= 0x02; } if (!aButtonPressed) { value |= 0x01; } return(value); } break; case 0xFF04: // Timer divider return(Z80.ticks & 0xFF); case 0xFF05: // Timer counter return(Z80.timerCounter & 0xFF); case 0xFF06: // Timer modulo return(Z80.timerModulo & 0xFF); case 0xFF07: { // Time Control int value = 0; if (Z80.timerRunning) { value |= 0x04; } value |= (int)Z80.timerFrequency; return(value); } case 0xFF0F: { // Interrupt Flag (an interrupt request) int value = 0; if (Z80.keyPressedInterruptRequested) { value |= 0x10; } if (Z80.serialIOTransferCompleteInterruptRequested) { value |= 0x08; } if (Z80.timerOverflowInterruptRequested) { value |= 0x04; } if (Z80.lcdcInterruptRequested) { value |= 0x02; } if (Z80.vBlankInterruptRequested) { value |= 0x01; } return(value); } case 0xFF40: { // LCDC control int value = 0; if (Z80.lcdControlOperationEnabled) { value |= 0x80; } if (GPU.windowTileMapDisplaySelect) { value |= 0x40; } if (GPU.windowDisplayed) { value |= 0x20; } if (GPU.backgroundAndWindowTileDataSelect) { value |= 0x10; } if (GPU.backgroundTileMapDisplaySelect) { value |= 0x08; } if (GPU.largeSprites) { value |= 0x04; } if (GPU.spritesDisplayed) { value |= 0x02; } if (GPU.backgroundDisplayed) { value |= 0x01; } return(value); } case 0xFF41: { // LCDC Status int value = 0; if (GPU.lcdcLycLyCoincidenceInterruptEnabled) { value |= 0x40; } if (GPU.lcdcOamInterruptEnabled) { value |= 0x20; } if (GPU.lcdcVBlankInterruptEnabled) { value |= 0x10; } if (GPU.lcdcHBlankInterruptEnabled) { value |= 0x08; } if (GPU.ly == GPU.lyCompare) { value |= 0x04; } value |= (int)GPU.lcdcMode; return(value); } case 0xFF42: // Scroll Y return(GPU.scrollY); case 0xFF43: // Scroll X return(GPU.scrollX); case 0xFF44: // LY return(GPU.ly); case 0xFF45: // LY Compare return(GPU.lyCompare); case 0xFF47: { // Background palette GPU.invalidateAllBackgroundTilesRequest = true; int value = 0; for (int i = 3; i >= 0; i--) { value <<= 2; switch (GPU.backgroundPalette[i]) { case 0xFF000000: value |= 3; break; case 0xFF555555: value |= 2; break; case 0xFFAAAAAA: value |= 1; break; case 0xFFFFFFFF: break; } } return(value); } case 0xFF48: { // Object palette 0 GPU.invalidateAllSpriteTilesRequest = true; int value = 0; for (int i = 3; i >= 0; i--) { value <<= 2; switch (GPU.objectPallete0[i]) { case 0xFF000000: value |= 3; break; case 0xFF555555: value |= 2; break; case 0xFFAAAAAA: value |= 1; break; case 0xFFFFFFFF: break; } } return(value); } case 0xFF49: { // Object palette 1 GPU.invalidateAllSpriteTilesRequest = true; int value = 0; for (int i = 3; i >= 0; i--) { value <<= 2; switch (GPU.objectPallete1[i]) { case 0xFF000000: value |= 3; break; case 0xFF555555: value |= 2; break; case 0xFFAAAAAA: value |= 1; break; case 0xFFFFFFFF: break; } } return(value); } case 0xFF4A: // Window Y return(GPU.windowY); case 0xFF4B: // Window X return(GPU.windowX); case 0xFFFF: { // Interrupt Enable int value = 0; if (Z80.keyPressedInterruptEnabled) { value |= 0x10; } if (Z80.serialIOTransferCompleteInterruptEnabled) { value |= 0x08; } if (Z80.timerOverflowInterruptEnabled) { value |= 0x04; } if (Z80.lcdcInterruptEnabled) { value |= 0x02; } if (Z80.vBlankInterruptEnabled) { value |= 0x01; } return(value); } } } return(0); }
public byte ReadByte(ushort addr) { if (addr < 0x8000) { if (RomMapMode == MapMode.Boot && addr < bootRom?.Length) { return(bootRom[addr]); } else { return(cartridge.ReadByte(addr)); } } else if (addr < 0xA000) { return(videoRam[addr - 0x8000]); } else if (addr < 0xC000) { return(cartridge.ReadByte(addr)); } else if (addr < 0xE000) { return(workRam[addr - 0xC000]); } else if (addr < 0xFE00) { // Echo of internal RAM return(workRam[addr - 0xE000]); } else if (addr < 0xFEA0) { return(oam[addr - 0xFE00]); } else if (addr < 0xFF00) { // Empty but unusable for I/O, return default bus value 0xFF return(0xFF); } else if (addr < 0xFF4C) { ioMasks.TryGetValue(addr, out byte mask); if (addr == 0xFF00) { ioRegisters[0] = inputRegister.ReadValue(ioRegisters[0]); } return((byte)(ioRegisters[addr - 0xFF00] | mask)); } else if (addr < 0xFF80) { // Empty but unusable for I/O, return default bus value 0xFF return(0xFF); } else if (addr < 0xFFFF) { return(highRam[addr - 0xFF80]); } else if (addr == 0xFFFF) { return(interruptEnableRegister); } else { throw new ArgumentException($"Could not read from illegal memory address: {addr:X4}"); } }