Esempio n. 1
0
 public void WriteByte(int address, byte value)
 {
     if (address < 0x8000)
     {
         _cartridge.WriteByte(address, value);
     }
     else if (address < 0xA000)
     {
         _gpu.WriteByte(address, value);
     }
     else if (address < 0xC000)
     {
         _cartridge.WriteByte(address, value);
     }
     else if (address < 0xFE00)
     {
         _lowRam[address] = value;
     }
     else if (address < 0xFEA0)
     {
         _gpu.WriteByte(address, value);
     }
     else if (address < 0xFF40)
     {
         _sound[address - 0xFF00] = value;
     }
     else if (address < 0xFF80)
     {
         _gpu.WriteByte(address, value);
     }
     else if (address < 0xFFFF) // FF80 -> FFFE
     {
         _highRam[address & 0x7F] = value;
     }
     else
     {
         throw new InvalidOperationException("Non managed MMU access");
     }
     //if (address >= 0x8000 && address < 0xA000)
     //{
     //    int shiftedAddress = address & 0x1FFF;
     //    _gpu.VRam[shiftedAddress] = value;
     //}
     //else if (address >= 0xFF40 && address < 0xFF7F)
     //    _gpu.WriteByte(address, value);
     //else
     //{
     //    var area = GetBufferArea(address);
     //    area[0] = value;
     //}
 }
Esempio n. 2
0
        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));
        }
Esempio n. 3
0
 private void LoadMemoryFromRegister(ushort address, byte register)
 {
     cartridge.WriteByte(address, register);
     m = 2; // Two m-time taken.
 }
Esempio n. 4
0
        public void WriteByte(int address, int value)
        {
            if (address >= 0xC000 && address <= 0xDFFF)
            {
                wRam[address - 0xC000] = (byte)value;
            }
            else if (address >= 0xFE00 && address <= 0xFEFF)
            {
                oam[address - 0xFE00] = (byte)value;
            }
            else if (address >= 0xFF80 && address <= 0xFFFE)
            {
                highRam[0xFF & address] = (byte)value;
            }
            else if (address >= 0x8000 && address <= 0x9FFF)
            {
                int videoRamIndex = address - 0x8000;
                vRam[videoRamIndex] = (byte)value;
                if (address < 0x9000)
                {
                    GPU.spriteTileInvalidated[videoRamIndex >> 4] = true;
                }
                if (address < 0x9800)
                {
                    GPU.invalidateAllBackgroundTilesRequest = true;
                }
                else if (address >= 0x9C00)
                {
                    int tileIndex = address - 0x9C00;
                    GPU.backgroundTileInvalidated[tileIndex >> 5, tileIndex & 0x1F] = true;
                }
                else
                {
                    int tileIndex = address - 0x9800;
                    GPU.backgroundTileInvalidated[tileIndex >> 5, tileIndex & 0x1F] = true;
                }
            }
            else if (address <= 0x7FFF || (address >= 0xA000 && address <= 0xBFFF))
            {
                cartridge.WriteByte(address, value);
            }
            else if (address >= 0xE000 && address <= 0xFDFF)
            {
                wRam[address - 0xE000] = (byte)value;
            }
            else
            {
                switch (address)
                {
                case 0xFF00:     // key pad
                    keyP14 = (value & 0x10) != 0x10;
                    keyP15 = (value & 0x20) != 0x20;
                    break;

                case 0xFF04:     // Timer divider
                    break;

                case 0xFF05:     // Timer counter
                    Z80.timerCounter = value;
                    break;

                case 0xFF06:     // Timer modulo
                    Z80.timerModulo = value;
                    break;

                case 0xFF07:      // Time Control
                    Z80.timerRunning   = (value & 0x04) == 0x04;
                    Z80.timerFrequency = (TimerFrequencyType)(0x03 & value);
                    break;

                case 0xFF0F:     // Interrupt Flag (an interrupt request)
                    Z80.keyPressedInterruptRequested = (value & 0x10) == 0x10;
                    Z80.serialIOTransferCompleteInterruptRequested = (value & 0x08) == 0x08;
                    Z80.timerOverflowInterruptRequested            = (value & 0x04) == 0x04;
                    Z80.lcdcInterruptRequested   = (value & 0x02) == 0x02;
                    Z80.vBlankInterruptRequested = (value & 0x01) == 0x01;
                    break;

                case 0xFF40:
                {         // LCDC control
                    bool _backgroundAndWindowTileDataSelect = GPU.backgroundAndWindowTileDataSelect;
                    bool _backgroundTileMapDisplaySelect    = GPU.backgroundTileMapDisplaySelect;
                    bool _windowTileMapDisplaySelect        = GPU.windowTileMapDisplaySelect;

                    Z80.lcdControlOperationEnabled        = (value & 0x80) == 0x80;
                    GPU.windowTileMapDisplaySelect        = (value & 0x40) == 0x40;
                    GPU.windowDisplayed                   = (value & 0x20) == 0x20;
                    GPU.backgroundAndWindowTileDataSelect = (value & 0x10) == 0x10;
                    GPU.backgroundTileMapDisplaySelect    = (value & 0x08) == 0x08;
                    GPU.largeSprites        = (value & 0x04) == 0x04;
                    GPU.spritesDisplayed    = (value & 0x02) == 0x02;
                    GPU.backgroundDisplayed = (value & 0x01) == 0x01;

                    if (_backgroundAndWindowTileDataSelect != GPU.backgroundAndWindowTileDataSelect ||
                        _backgroundTileMapDisplaySelect != GPU.backgroundTileMapDisplaySelect ||
                        _windowTileMapDisplaySelect != GPU.windowTileMapDisplaySelect)
                    {
                        GPU.invalidateAllBackgroundTilesRequest = true;
                    }

                    break;
                }

                case 0xFF41:     // LCDC Status
                    GPU.lcdcLycLyCoincidenceInterruptEnabled = (value & 0x40) == 0x40;
                    GPU.lcdcOamInterruptEnabled    = (value & 0x20) == 0x20;
                    GPU.lcdcVBlankInterruptEnabled = (value & 0x10) == 0x10;
                    GPU.lcdcHBlankInterruptEnabled = (value & 0x08) == 0x08;
                    GPU.lcdcMode = (LcdcModeType)(value & 0x03);
                    break;

                case 0xFF42:     // Scroll Y;
                    GPU.scrollY = value;
                    break;

                case 0xFF43:     // Scroll X;
                    GPU.scrollX = value;
                    break;

                case 0xFF44:     // LY
                    GPU.ly = value;
                    break;

                case 0xFF45:     // LY Compare
                    GPU.lyCompare = value;
                    break;

                case 0xFF46:     // Memory Transfer
                    value <<= 8;
                    for (int i = 0; i < 0x8C; i++)
                    {
                        WriteByte(0xFE00 | i, ReadByte(value | i));
                    }
                    break;

                case 0xFF47:     // Background palette
                    Console.WriteLine("[0xFF47] = {0:X}", value);
                    for (int i = 0; i < 4; i++)
                    {
                        switch (value & 0x03)
                        {
                        case 0:
                            GPU.backgroundPalette[i] = 0xFFFFFFFF;
                            break;

                        case 1:
                            GPU.backgroundPalette[i] = 0xFFAAAAAA;
                            break;

                        case 2:
                            GPU.backgroundPalette[i] = 0xFF555555;
                            break;

                        case 3:
                            GPU.backgroundPalette[i] = 0xFF000000;
                            break;
                        }
                        value >>= 2;
                    }
                    GPU.invalidateAllBackgroundTilesRequest = true;
                    break;

                case 0xFF48:     // Object palette 0
                    for (int i = 0; i < 4; i++)
                    {
                        switch (value & 0x03)
                        {
                        case 0:
                            GPU.objectPallete0[i] = 0xFFFFFFFF;
                            break;

                        case 1:
                            GPU.objectPallete0[i] = 0xFFAAAAAA;
                            break;

                        case 2:
                            GPU.objectPallete0[i] = 0xFF555555;
                            break;

                        case 3:
                            GPU.objectPallete0[i] = 0xFF000000;
                            break;
                        }
                        value >>= 2;
                    }
                    GPU.invalidateAllSpriteTilesRequest = true;
                    break;

                case 0xFF49:     // Object palette 1
                    for (int i = 0; i < 4; i++)
                    {
                        switch (value & 0x03)
                        {
                        case 0:
                            GPU.objectPallete1[i] = 0xFFFFFFFF;
                            break;

                        case 1:
                            GPU.objectPallete1[i] = 0xFFAAAAAA;
                            break;

                        case 2:
                            GPU.objectPallete1[i] = 0xFF555555;
                            break;

                        case 3:
                            GPU.objectPallete1[i] = 0xFF000000;
                            break;
                        }
                        value >>= 2;
                    }
                    GPU.invalidateAllSpriteTilesRequest = true;
                    break;

                case 0xFF4A:     // Window Y
                    GPU.windowY = value;
                    break;

                case 0xFF4B:     // Window X
                    GPU.windowX = value;
                    break;

                case 0xFFFF:     // Interrupt Enable
                    Z80.keyPressedInterruptEnabled = (value & 0x10) == 0x10;
                    Z80.serialIOTransferCompleteInterruptEnabled = (value & 0x08) == 0x08;
                    Z80.timerOverflowInterruptEnabled            = (value & 0x04) == 0x04;
                    Z80.lcdcInterruptEnabled   = (value & 0x02) == 0x02;
                    Z80.vBlankInterruptEnabled = (value & 0x01) == 0x01;
                    break;
                }
            }
        }
Esempio n. 5
0
        public void WriteByte(ushort addr, byte data, bool applySideEffects = true)
        {
            if (addr < 0x8000)
            {
                cartridge.WriteByte(addr, data);
            }
            else if (addr < 0xA000)
            {
                byte lcdControl = ioRegisters[0xFF40 - 0xFF00];
                int  lcdMode    = ioRegisters[0xFF41 - 0xFF00] & 3;
                if (!lcdControl.IsBitSet(7) || lcdMode != (int)PPU.Mode.PixelTransfer)
                {
                    // VRAM is not accessible during pixel transfer if lcd is enabled
                    videoRam[addr - 0x8000] = data;
                }
            }
            else if (addr < 0xC000)
            {
                cartridge.WriteByte(addr, data);
            }
            else if (addr < 0xE000)
            {
                workRam[addr - 0xC000] = data;
            }
            else if (addr < 0xFE00)
            {
                // Echo of internal RAM
                workRam[addr - 0xE000] = data;
            }
            else if (addr < 0xFEA0)
            {
                byte lcdControl = ioRegisters[0xFF40 - 0xFF00];
                int  lcdMode    = ioRegisters[0xFF41 - 0xFF00] & 3;
                if (!lcdControl.IsBitSet(7) || (lcdMode != (int)PPU.Mode.OamSearch && lcdMode != (int)PPU.Mode.PixelTransfer))
                {
                    // OAM not accessible during OAM search and pixel transfer
                    oam[addr - 0xFE00] = data;
                }
            }
            else if (addr < 0xFF00)
            {
                // Empty but unusable for I/O
            }
            else if (addr < 0xFF4C)
            {
                if (addr == 0xFF04 && applySideEffects)
                {
                    data = 0x00;
                    DivResetEvent?.Invoke();
                }

                if (addr == 0xFF02 && data == 0x81 && applySideEffects)
                {
                    Serial.Add(ioRegisters[1]);
                }

                if (addr == 0xFF00 && applySideEffects)
                {
                    data = (byte)((ioRegisters[0] & 0xF) | (data & 0x30));
                }
                if (addr == 0xFF46 && applySideEffects)
                {
                    LaunchDMATransfer(data);
                }
                ioRegisters[addr - 0xFF00] = data;
            }
            else if (addr < 0xFF80)
            {
                if (addr == BOOT_ROM_LOCK_ADDRESS && data == 0b1 && RomMapMode == MapMode.Boot && applySideEffects)
                {
                    RomMapMode = MapMode.Cartridge;
                }
                else
                {
                    // Empty but unusable for I/O
                }
            }