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); }
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); }
public void CopyVRAM(int aStart, int[] aData, int aIndex, int aCount) { LinearFrameBuffer.Copy(aStart, aData, aIndex, aCount); }
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); }
/// <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; }