public void Capture(bool afterVideoEnable)
 {
     LCDC = _bus.ReadPort(Port.LCDC);
     SCX  = _bus.ReadPort(Port.SCX);
     SCY  = _bus.ReadPort(Port.SCY);
     WX   = _bus.ReadPort(Port.WX);
     WY   = _bus.ReadPort(Port.WY);
     unsafe
     {
         if (!_bus.ColorMode)
         {
             BGP  = _bus.ReadPort(Port.BGP);
             OBP0 = _bus.ReadPort(Port.OBP0);
             OBP1 = _bus.ReadPort(Port.OBP1);
             MemoryBlock.Copy((void *)VideoMemory, _bus.VideoRam.Pointer, _bus.VideoRam.Length >> 1);
             if (afterVideoEnable)
             {
                 MemoryBlock.Copy((void *)PaletteMemory, _bus.PaletteMemory.Pointer, _bus.PaletteMemory.Length);
             }
         }
         else
         {
             MemoryBlock.Copy((void *)VideoMemory, _bus.VideoRam.Pointer, _bus.VideoRam.Length);
             MemoryBlock.Copy((void *)PaletteMemory, _bus.PaletteMemory.Pointer, _bus.PaletteMemory.Length);
         }
         MemoryBlock.Copy((void *)ObjectAttributeMemory, _bus.ObjectAttributeMemory.Pointer, _objectAttributeMemoryBlock.Length);
     }
     SuperGameBoyScreenStatus = _bus.SuperGameBoyScreenStatus;
 }
        private unsafe void HandleHdma(bool addCycles)
        {
            MemoryBlock.Copy(segmentArray[hdmaCurrentDestinationHigh] + hdmaCurrentDestinationLow, segmentArray[hdmaCurrentSourceHigh] + hdmaCurrentSourceLow, 16);

            if ((hdmaCurrentDestinationLow += 16) == 0)
            {
                hdmaCurrentDestinationHigh++;
            }
            if ((hdmaCurrentSourceLow += 16) == 0)
            {
                hdmaCurrentSourceHigh++;
            }

            hdmaActive = hdmaCurrentLength-- != 0;
            hdmaDone   = true;
            if (addCycles)
            {
                AddFixedCycles(8);
            }
        }
        private void HandleDma(byte destinationHigh, byte destinationLow, byte sourceHigh, byte sourceLow, byte length)
        {
            int fullLength = (length + 1) << 4;
            int dh         = destinationHigh,
                dl         = destinationLow,
                sh         = sourceHigh,
                sl         = sourceLow;

            do
            {
                int max = 256 - (dl > sl ? dl : sl);

                if (fullLength < max)
                {
                    max = fullLength;
                }

                unsafe { MemoryBlock.Copy(segmentArray[dh] + dl, segmentArray[sh] + sl, max); }

                fullLength -= max;
                sl         += max;
                dl         += max;

                if (sl > 0xFF)
                {
                    sl &= 0xFF;
                    sh++;
                }

                if (dl > 0xFF)
                {
                    dl &= 0xFF;
                    dh++;
                }
            }while (fullLength > 0);

            AddFixedCycles((length + 1) << 3);
        }
Exemple #4
0
 internal void DoubleBuffer_SetVRAM(int[] colors, int Offset)
 {
     //Video_Memory.Copy((int)FrameSize, colors, 0, colors.Length);
     Video_Memory.Copy(Offset, colors, 0, colors.Length);
 }
Exemple #5
0
 public void CopyVRAM(int aStart, int[] aData, int aIndex, int aCount)
 {
     LinearFrameBuffer.Copy(aStart, aData, aIndex, aCount);
 }
Exemple #6
0
        public unsafe void WritePort(byte port, byte value)
        {
            switch (port)
            {
            // Joypad
            case 0x00:                     // JOYP
                WriteJoypadRegister(value);
                break;

            // Timer Ports
            case 0x04:                     // DIV
                ResetDivider();
                break;

            case 0x05:                     // TIMA
                SetTimerValue(value);
                break;

            case 0x07:                     // TAC
                // Check the timer enable bit
                if ((value & 0x4) != 0)
                {
                    switch (value & 0x3)
                    {
                    case 0: EnableTimer(1024); break;

                    case 1: EnableTimer(16); break;

                    case 2: EnableTimer(64); break;

                    case 3: EnableTimer(256); break;
                    }
                }
                else
                {
                    DisableTimer();
                }
                portMemory[0x07] = value;
                break;

            case 0x0F:                     // IF
                requestedInterrupts = (byte)(value & 0x1F);
                break;

            case 0x4D:                     // KEY1
                if (colorMode)
                {
                    prepareSpeedSwitch = (value & 0x1) != 0;
                }
                break;

            case 0x50:                     // BLCK
                // Disables the boot ROM when 0x01 or 0x11 is written, and never re-enable it again.
                if (internalRomMapped && (value & 0x1) != 0)
                {
                    UnmapInternalRom();
                }
                break;

            case 0x70:                     // SVBK
                value &= 0x7;
                if (value == 0)
                {
                    value = 1;
                }
                if (colorMode && workRamBank != value && (!hdmaActive || hdmaCurrentSourceHigh < 0xA0 || hdmaCurrentSourceHigh >= 0xE0))
                {
                    workRamBank = value;
                    MapWorkRamBank();
                }
                break;

            case 0x75:                     // Undocumented port 0x75
                portMemory[0x75] = (byte)(0x8F | value);
                break;

            case 0xFF:                     // IE
                portMemory[0xFF] = (byte)(value & 0x1F);
                break;

            // Video Ports
            case 0x41:                     // STAT
                notifyCoincidence = (value & 0x40) != 0;
                notifyMode2       = (value & 0x20) != 0;
                notifyMode1       = (value & 0x10) != 0;
                notifyMode0       = (value & 0x08) != 0;
                break;

            case 0x44:                     // LY
                // We use a negative offset here...
                // -4 allows the interrupt to happen 4 cycles beforce the new line
                //lyOffset = lcdCycles / -HorizontalLineDuration - 4;
                // For now leave it as read only… Need to find a game tring to reset LY.
                // NB: Shantae and Prehistorik Man seem to write to this register. Need to find out what they expect from this.
                break;

            case 0x45:                     // LYC
                portMemory[0x45] = value;
                if (notifyCoincidence && value == lyRegister)
                {
                    videoNotifications |= 0x01;
                    InterruptRequest(0x02);
                }
                else
                {
                    videoNotifications &= 0x0E;
                }
                break;

            case 0x46:                     // DMA
                if (value <= 0xF1)
                {
                    MemoryBlock.Copy(objectAttributeMemory, segmentArray[value], 0xA0);
                }
                break;

            // Undocumented port used for controlling LCD operating mode
            case 0x4C:                     // LCDM
                if (colorHardware)
                {
                    // This port will be set at boot time with the value of the compatibility byte in the ROM header
                    // Bit 7 indicates color game boy functions
                    colorMode = (value & 0x80) != 0;
                    // Bit 3 indicates something too (used to enable B&W mode), but no idea about that yet.
                }
                break;

            case 0x4F:                     // VBK
                value &= 0x1;
                if (colorMode && !hdmaActive && videoRamBank != value)
                {
                    videoRamBank = value;
                    MapVideoRamBank();
                }
                break;

            case 0x51:                     // HDMA1
                hdmaSourceHigh = value;
                break;

            case 0x52:                     // HDMA2
                hdmaSourceLow = (byte)(value & 0xF0);
                break;

            case 0x53:                     // HDMA3
                hdmaDestinationHigh = (byte)(0x80 | value & 0x1F);
                break;

            case 0x54:                     // HDMA4
                hdmaDestinationLow = (byte)(value & 0xF0);
                break;

            case 0x55:                     // HDMA5
                if (colorMode)
                {
                    if (hdmaActive)
                    {
                        if ((value & 0x80) == 0)
                        {
                            hdmaActive = false;
                        }
                    }
                    else if ((value & 0x80) != 0)
                    {
                        hdmaActive                 = true;
                        hdmaCurrentSourceHigh      = hdmaSourceHigh;
                        hdmaCurrentSourceLow       = hdmaSourceLow;
                        hdmaCurrentDestinationHigh = hdmaDestinationHigh;
                        hdmaCurrentDestinationLow  = hdmaDestinationLow;
                        hdmaCurrentLength          = (byte)(value & 0x7F);
                    }
                    else
                    {
                        HandleDma(hdmaDestinationHigh, hdmaDestinationLow, hdmaSourceHigh, hdmaSourceLow, (byte)(value & 0x7F));
                    }
                }
                break;

            // Undocumented port used for palette synchronization
            case 0x6C:                     // PMAP
                if (colorHardware)
                {
                    // Information from the GBC BIOS disassembly suggests than more than being a R/W register,
                    // The R/W bit probably controls the color palette to grey palette mapping…
                    usePaletteMapping = (value & 0x1) != 0;
                    portMemory[0x6C]  = (byte)(0xFE | value & 0x01);
                }
                break;

            // Tracked audio ports
            case 0x1A:                     // NR30
                if ((value & 0x80) != 0)
                {
                    portMemory[0x1A]  = 0xFF;
                    portMemory[0x26] |= 0x04;
                }
                else
                {
                    portMemory[0x1A]  = 0x7F;
                    portMemory[0x26] &= 0xFB;
                }
                break;

            case 0x26:                     // NR52
                portMemory[0x26] = (value & 0x80) != 0 ? (byte)(0xF0 | portMemory[0x26]) : (byte)0x00;
                break;

            // Tracked video ports
            // Only in non-cgb mode
            case 0x47:                     // BGP
            case 0x48:                     // OBP0
            case 0x49:                     // OBP1
                portMemory[port] = value;  // Store the value in memory
                if (!colorMode)
                {
                    videoFrameData.VideoPortAccessList.Add(new PortAccess(frameCycles, port, value));                             // Keep track of the write
                }
                break;

            // Only in cgb mode
            case 0x68:                     // BCPS / BGPI
                if (colorHardware)
                {
                    bgpInc   = (value & 0x80) != 0;
                    bgpIndex = value & 0x3F;
                }
                break;

            case 0x69:                     // BCPD / BGPD
                if (colorHardware)
                {
                    paletteMemory[bgpIndex] = value;
                    if (usePaletteMapping)
                    {
                        videoFrameData.GreyPaletteUpdated = true;
                    }
                    videoFrameData.PaletteAccessList.Add(new PaletteAccess(frameCycles, (byte)bgpIndex, value));
                    if (bgpInc)
                    {
                        bgpIndex = (bgpIndex + 1) & 0x3F;
                    }
                }
                break;

            case 0x6A:                     // OCPS / OBPI
                if (colorHardware)
                {
                    obpInc   = (value & 0x80) != 0;
                    obpIndex = value & 0x3F;
                }
                break;

            case 0x6B:                     // OCPD / OBPD
                if (colorHardware)
                {
                    paletteMemory[0x40 | obpIndex] = value;
                    if (usePaletteMapping)
                    {
                        videoFrameData.GreyPaletteUpdated = true;
                    }
                    videoFrameData.PaletteAccessList.Add(new PaletteAccess(frameCycles, (byte)(0x40 | obpIndex), value));
                    if (obpInc)
                    {
                        obpIndex = (obpIndex + 1) & 0x3F;
                    }
                }
                break;

            // Always
            case 0x40:                     // LCDC
                if ((value & 0x80) == 0)
                {
                    DisableVideo();
                }
                else if (!lcdEnabled)
                {
                    portMemory[port] = value;
                    EnableVideo();
                    break;
                }
                goto case 0x42;

            case 0x42:                                                                            // SCY
            case 0x43:                                                                            // SCX
            case 0x4A:                                                                            // WY
            case 0x4B:                                                                            // WX
                videoFrameData.VideoPortAccessList.Add(new PortAccess(frameCycles, port, value)); // Keep track of the write
                goto default;

            default:
                portMemory[port] = value;                         // Store the value in memory
                break;
            }
        }
 public void DoubleBuffer_SetVRAM(int[] colors)
 {
     Video_Memory.Copy((int)FrameSize, colors, 0, colors.Length);
 }
Exemple #8
0
        /// <summary>Loads a bootstrap ROM with the specified data.</summary>
        /// <remarks>Data integrity will be checked to ensure a correct bootstrap ROM gets loaded.</remarks>
        /// <param name="hardwareType">Hardware whose bootstrap ROM should be loaded.</param>
        /// <param name="data">Data of the specified bootstrap ROM.</param>
        /// <exception cref="ArgumentOutOfRangeException">The value provided for harware type is not a valid one.</exception>
        /// <exception cref="NotSupportedException">Loading the bootstrap ROM the specified hardware is not supported.</exception>
        /// <exception cref="InvalidDataException">Data integrity check failed.</exception>
        public unsafe void LoadBootRom(HardwareType hardwareType, byte[] data)
        {
            if (data == null)
            {
                throw new ArgumentNullException();
            }
            if (!Enum.IsDefined(typeof(HardwareType), hardwareType))
            {
                throw new ArgumentOutOfRangeException();
            }

            byte[] referenceHash;
            int    requestedLength;
            byte * destination;
            // I finally found a use for C# undocumented keywords… Yeah !
            // (There are other ways to do this if really needed, but in fact it feels kinda cleaner to use this rather than another switch statement here…)
            TypedReference romLoadedField;

            switch (hardwareType)
            {
            case HardwareType.GameBoy:
                requestedLength = 0x100;
                referenceHash   = dmgRomHash;
                destination     = dmgBootMemory;
                romLoadedField  = __makeref(dmgBootRomLoaded);
                break;

            case HardwareType.SuperGameBoy:
                requestedLength = 0x100;
                referenceHash   = sgbRomHash;
                destination     = sgbBootMemory;
                romLoadedField  = __makeref(sgbBootRomLoaded);
                break;

            case HardwareType.GameBoyColor:
                // Trim the GBC rom if needed (we don't need the "decorative" empty sapce)
                if (data.Length == 0x900)
                {
                    byte[] tempData = new byte[0x800];

                    Buffer.BlockCopy(data, 0, tempData, 0, 0x100);
                    Buffer.BlockCopy(data, 0x200, tempData, 0x100, 0x700);

                    data = tempData;
                }
                requestedLength = 0x800;
                referenceHash   = cgbRomHash;
                destination     = cgbBootMemory;
                romLoadedField  = __makeref(cgbBootRomLoaded);
                break;

            default:
                throw new NotSupportedException();
            }

            var md5 = MD5.Create();

            if (data.Length != requestedLength || !Equals(md5.ComputeHash(data), referenceHash))
            {
                throw new InvalidDataException();

                fixed(byte *dataPointer = data)
                MemoryBlock.Copy((void *)destination, (void *)dataPointer, requestedLength);

                __refvalue(romLoadedField, bool) = true;
        }