Beispiel #1
0
        public static byte[] GetGameboyPalette()
        {
            byte[] cgRam = new byte[512];

            //Generate a fake SNES-like palette based on the gameboy PPU state
            GbState    state = DebugApi.GetState().Gameboy;
            GbPpuState ppu   = state.Ppu;

            if (state.Type == GbType.Cgb)
            {
                for (int i = 0; i < 8 * 4; i++)
                {
                    cgRam[i * 2]     = (byte)(ppu.CgbBgPalettes[i] & 0xFF);
                    cgRam[i * 2 + 1] = (byte)(ppu.CgbBgPalettes[i] >> 8);
                }

                for (int i = 0; i < 8 * 4; i++)
                {
                    cgRam[128 + i * 2]     = (byte)(ppu.CgbObjPalettes[i] & 0xFF);
                    cgRam[128 + i * 2 + 1] = (byte)(ppu.CgbObjPalettes[i] >> 8);
                }
            }
            else
            {
                byte[,] paletteBytes = new byte[4, 2] {
                    { 0xFF, 0x7F }, { 0x18, 0x63 }, { 0x8C, 0x31 }, { 0, 0 }
                };

                Action <byte, UInt16> setPalette = (byte pal, UInt16 offset) => {
                    cgRam[offset]     = paletteBytes[pal & 0x03, 0];
                    cgRam[offset + 1] = paletteBytes[pal & 0x03, 1];
                    cgRam[offset + 2] = paletteBytes[(pal >> 2) & 0x03, 0];
                    cgRam[offset + 3] = paletteBytes[(pal >> 2) & 0x03, 1];
                    cgRam[offset + 4] = paletteBytes[(pal >> 4) & 0x03, 0];
                    cgRam[offset + 5] = paletteBytes[(pal >> 4) & 0x03, 1];
                    cgRam[offset + 6] = paletteBytes[(pal >> 6) & 0x03, 0];
                    cgRam[offset + 7] = paletteBytes[(pal >> 6) & 0x03, 1];
                };

                setPalette(ppu.BgPalette, 0);
                setPalette(ppu.ObjPalette0, 32);
                setPalette(ppu.ObjPalette1, 64);
                setPalette(0xE4, 96);
            }
            return(cgRam);
        }
Beispiel #2
0
        private void UpdateGameboyFields()
        {
            GbPpuState state          = _state.Gameboy.Ppu;
            bool       isGbc          = state.CgbEnabled;
            bool       tilemapSelect  = _options.Layer == 1 ? state.WindowTilemapSelect : state.BgTilemapSelect;
            int        tilemapAddress = tilemapSelect ? 0x1C00 : 0x1800;
            int        tilesetAddress = state.BgTileSelect ? 0x0000 : 0x1000;

            int row    = _selectedRow;
            int column = _selectedColumn;

            int  address    = tilemapAddress + (row * 32) + column;
            byte tileNumber = _vram[address & 0x1FFF];
            int  attributes = isGbc ? _vram[0x2000 | (address & 0x1FFF)] : 0;

            //Selected tile
            txtPosition.Text   = column.ToString() + ", " + row.ToString();
            txtAddress.Text    = address.ToString("X4");
            txtTileNumber.Text = tileNumber.ToString() + " ($" + tileNumber.ToString("X2") + ")";

            int tileAddress = tilesetAddress + (state.BgTileSelect ? tileNumber : (int)(sbyte)tileNumber) * 16;

            if ((attributes & 0x08) != 0)
            {
                tileAddress |= 0x2000;
            }
            txtTileAddress.Text = tileAddress.ToString("X4");

            txtPalette.Text             = (attributes & 0x07).ToString();
            chkPriorityFlag.Checked     = (attributes & 0x80) != 0;
            chkVerticalMirror.Checked   = (attributes & 0x40) != 0;
            chkHorizontalMirror.Checked = (attributes & 0x20) != 0;

            //Tilemap
            txtMapSize.Text        = "32x32";
            txtMapAddress.Text     = (0x8000 | tilemapAddress).ToString("X4");
            txtTilesetAddress.Text = (0x8000 | tilesetAddress).ToString("X4");
            txtTileSize.Text       = "8x8";
            txtBitDepth.Text       = "2";
        }
Beispiel #3
0
        private void UpdateGameboyTab()
        {
            GbState         gb      = _state.Gameboy;
            List <RegEntry> entries = new List <RegEntry>();

            GbPpuState ppu = gb.Ppu;

            entries.AddRange(new List <RegEntry>()
            {
                new RegEntry("$FF40", "LCD Control (LCDC)", null),
                new RegEntry("$FF40.0", "Background Enabled", ppu.BgEnabled),
                new RegEntry("$FF40.1", "Sprites Enabled", ppu.BgEnabled),
                new RegEntry("$FF40.2", "Sprite size", ppu.LargeSprites ? "8x16" : "8x8"),
                new RegEntry("$FF40.3", "BG Tilemap Select", ppu.BgTilemapSelect ? 0x9C00 : 0x9800, Format.X16),
                new RegEntry("$FF40.4", "BG Tile Select", ppu.BgTileSelect ? "$8000-$8FFF" : "$8800-$97FF"),
                new RegEntry("$FF40.5", "Window Enabled", ppu.WindowEnabled),
                new RegEntry("$FF40.6", "Window Tilemap Select", ppu.WindowTilemapSelect ? 0x9C00 : 0x9800, Format.X16),
                new RegEntry("$FF40.7", "LCD Enabled", ppu.LcdEnabled),

                new RegEntry("$FF41", "LCD Status (STAT)", null),
                new RegEntry("$FF41.0-1", "Mode", (int)ppu.Mode),
                new RegEntry("$FF41.2", "Coincidence Flag", ppu.LyCoincidenceFlag),
                new RegEntry("$FF41.3", "Mode 0 H-Blank IRQ", (ppu.Status & 0x08) != 0),
                new RegEntry("$FF41.4", "Mode 1 V-Blank IRQ", (ppu.Status & 0x10) != 0),
                new RegEntry("$FF41.5", "Mode 2 OAM IRQ", (ppu.Status & 0x20) != 0),
                new RegEntry("$FF41.6", "LYC=LY Coincidence IRQ", (ppu.Status & 0x40) != 0),

                new RegEntry("", "LCD Registers", null),
                new RegEntry("$FF42", "Scroll Y (SCY)", ppu.ScrollY, Format.X8),
                new RegEntry("$FF43", "Scroll X (SCX)", ppu.ScrollX, Format.X8),
                new RegEntry("$FF44", "Y-Coordinate (LY)", ppu.Ly, Format.X8),
                new RegEntry("$FF45", "LY Compare (LYC)", ppu.LyCompare, Format.X8),
                new RegEntry("$FF47", "BG Palette (BGP)", ppu.BgPalette, Format.X8),
                new RegEntry("$FF48", "OBJ Palette 0 (OBP0)", ppu.ObjPalette0, Format.X8),
                new RegEntry("$FF49", "OBJ Palette 1 (OBP1)", ppu.ObjPalette1, Format.X8),
                new RegEntry("$FF4A", "Window Y (WY)", ppu.WindowY, Format.X8),
                new RegEntry("$FF4B", "Window X (WX)", ppu.WindowX, Format.X8),
            });

            GbTimerState timer = gb.Timer;

            entries.AddRange(new List <RegEntry>()
            {
                new RegEntry("$FF04-7", "Timer", null),
                new RegEntry("$FF04", "DIV - Divider", timer.Divider, Format.X16),
                new RegEntry("$FF05", "TIMA - Counter", timer.Counter, Format.X8),
                new RegEntry("$FF06", "TMA - Modulo", timer.Modulo, Format.X8),
                new RegEntry("$FF07", "TAC - Control", timer.Control, Format.X8)
            });

            GbDmaControllerState dma = gb.Dma;

            entries.AddRange(new List <RegEntry>()
            {
                new RegEntry("", "DMA", null),
                new RegEntry("$FF46", "OAM DMA - Source", (dma.OamDmaSource << 8), Format.X16),
                new RegEntry("$FF51-2", "CGB - Source", dma.CgbDmaSource, Format.X16),
                new RegEntry("$FF53-4", "CGB - Destination", dma.CgbDmaDest, Format.X16),
                new RegEntry("$FF55.0-6", "CGB - Length", dma.CgbDmaLength, Format.X8),
                new RegEntry("$FF55.7", "CGB - HDMA Done", dma.CgbHdmaDone),
                new RegEntry("", "CGB - HDMA Running", dma.CgbHdmaRunning),
            });

            GbMemoryManagerState memManager = gb.MemoryManager;

            entries.AddRange(new List <RegEntry>()
            {
                new RegEntry("", "IRQ", null),
                new RegEntry("$FF0F", "IF - IRQ Flags", memManager.IrqRequests, Format.X8),
                new RegEntry("$FF0F.0", "IF - Vertical Blank IRQ", (memManager.IrqRequests & 0x01) != 0),
                new RegEntry("$FF0F.1", "IF - STAT IRQ", (memManager.IrqRequests & 0x02) != 0),
                new RegEntry("$FF0F.2", "IF - Timer IRQ", (memManager.IrqRequests & 0x04) != 0),
                new RegEntry("$FF0F.3", "IF - Serial IRQ", (memManager.IrqRequests & 0x08) != 0),
                new RegEntry("$FF0F.4", "IF - Joypad IRQ", (memManager.IrqRequests & 0x10) != 0),

                new RegEntry("$FFFF", "IE - IRQ Enabled", memManager.IrqEnabled, Format.X8),
                new RegEntry("$FFFF.0", "IE - Vertical Blank IRQ Enabled", (memManager.IrqEnabled & 0x01) != 0),
                new RegEntry("$FFFF.1", "IE - STAT IRQ Enabled", (memManager.IrqEnabled & 0x02) != 0),
                new RegEntry("$FFFF.2", "IE - Timer IRQ Enabled", (memManager.IrqEnabled & 0x04) != 0),
                new RegEntry("$FFFF.3", "IE - Serial IRQ Enabled", (memManager.IrqEnabled & 0x08) != 0),
                new RegEntry("$FFFF.4", "IE - Joypad IRQ Enabled", (memManager.IrqEnabled & 0x10) != 0),

                new RegEntry("", "Misc", null),
                new RegEntry("$FF00", "Input Select", memManager.InputSelect, Format.X8),
                new RegEntry("$FF01", "Serial Data", memManager.SerialData, Format.X8),
                new RegEntry("$FF02", "Serial Control", memManager.SerialControl, Format.X8),
                new RegEntry("", "Serial Bit Count", memManager.SerialBitCount),
            });


            GbApuState apu = gb.Apu.Common;

            entries.AddRange(new List <RegEntry>()
            {
                new RegEntry("", "APU", null),
                new RegEntry("$FF24.0-2", "Volume Right", apu.RightVolume),
                new RegEntry("$FF24.3", "External Audio Right Enabled", apu.ExtAudioRightEnabled),
                new RegEntry("$FF24.4-6", "Volume Left", apu.LeftVolume),
                new RegEntry("$FF24.7", "External Audio Left Enabled", apu.ExtAudioRightEnabled),
                new RegEntry("$FF25.0", "Right Square 1 Enabled", apu.EnableRightSq1 != 0),
                new RegEntry("$FF25.1", "Right Square 2 Enabled", apu.EnableRightSq2 != 0),
                new RegEntry("$FF25.2", "Right Wave Enabled", apu.EnableRightWave != 0),
                new RegEntry("$FF25.3", "Right Noise Enabled", apu.EnableRightNoise != 0),
                new RegEntry("$FF25.4", "Left Square 1 Enabled", apu.EnableLeftSq1 != 0),
                new RegEntry("$FF25.5", "Left Square 2 Enabled", apu.EnableLeftSq2 != 0),
                new RegEntry("$FF25.6", "Left Wave Enabled", apu.EnableLeftWave != 0),
                new RegEntry("$FF25.7", "Left Noise Enabled", apu.EnableLeftNoise != 0),
                new RegEntry("$FF26.7", "APU Enabled", apu.ApuEnabled),
                new RegEntry("", "Frame Sequencer", apu.FrameSequenceStep),
            });

            GbSquareState sq1 = gb.Apu.Square1;

            entries.AddRange(new List <RegEntry>()
            {
                new RegEntry("$FF10-$FF14", "Square 1", null),
                new RegEntry("$FF10.0-2", "Sweep Shift", sq1.SweepShift),
                new RegEntry("$FF10.3", "Sweep Negate", sq1.SweepNegate),
                new RegEntry("$FF10.4-7", "Sweep Period", sq1.SweepPeriod),

                new RegEntry("$FF11.0-5", "Length", sq1.Length),
                new RegEntry("$FF11.6-7", "Duty", sq1.Duty),

                new RegEntry("$FF12.0-2", "Envelope Period", sq1.EnvPeriod),
                new RegEntry("$FF12.3", "Envelope Increase Volume", sq1.EnvRaiseVolume),
                new RegEntry("$FF12.4-7", "Envelope Volume", sq1.EnvVolume),

                new RegEntry("$FF13+$FF14.0-2", "Frequency", sq1.Frequency),
                new RegEntry("$FF14.6", "Length Counter Enabled", sq1.LengthEnabled),
                new RegEntry("$FF14.7", "Channel Enabled", sq1.Enabled),

                new RegEntry("--", "Timer", sq1.Timer),
                new RegEntry("--", "Duty Position", sq1.DutyPos),
                new RegEntry("--", "Sweep Enabled", sq1.SweepEnabled),
                new RegEntry("--", "Sweep Frequency", sq1.SweepFreq),
                new RegEntry("--", "Sweep Timer", sq1.SweepTimer),
                new RegEntry("--", "Envelope Timer", sq1.EnvTimer),
                new RegEntry("--", "Output", sq1.Output)
            });

            GbSquareState sq2 = gb.Apu.Square2;

            entries.AddRange(new List <RegEntry>()
            {
                new RegEntry("$FF16-$FF19", "Square 2", null),
                new RegEntry("$FF16.0-5", "Length", sq2.Length),
                new RegEntry("$FF16.6-7", "Duty", sq2.Duty),

                new RegEntry("$FF17.0-2", "Envelope Period", sq2.EnvPeriod),
                new RegEntry("$FF17.3", "Envelope Increase Volume", sq2.EnvRaiseVolume),
                new RegEntry("$FF17.4-7", "Envelope Volume", sq2.EnvVolume),

                new RegEntry("$FF18+$FF19.0-2", "Frequency", sq2.Frequency),
                new RegEntry("$FF19.6", "Length Counter Enabled", sq2.LengthEnabled),
                new RegEntry("$FF19.7", "Channel Enabled", sq2.Enabled),

                new RegEntry("--", "Timer", sq2.Timer),
                new RegEntry("--", "Duty Position", sq2.DutyPos),
                new RegEntry("--", "Envelope Timer", sq2.EnvTimer),
                new RegEntry("--", "Output", sq2.Output)
            });

            GbNoiseState noise = gb.Apu.Noise;

            entries.AddRange(new List <RegEntry>()
            {
                new RegEntry("$FF20-$FF23", "Noise", null),
                new RegEntry("$FF20.0-5", "Length", noise.Length),

                new RegEntry("$FF21.0-2", "Envelope Period", noise.EnvPeriod),
                new RegEntry("$FF21.3", "Envelope Increase Volume", noise.EnvRaiseVolume),
                new RegEntry("$FF21.4-7", "Envelope Volume", noise.EnvVolume),

                new RegEntry("$FF23.0-2", "Divisor", noise.Divisor),
                new RegEntry("$FF23.3", "Short Mode", noise.ShortWidthMode),
                new RegEntry("$FF23.4-7", "Period Shift", noise.PeriodShift),

                new RegEntry("$FF24.6", "Length Counter Enabled", noise.LengthEnabled),
                new RegEntry("$FF24.7", "Channel Enabled", noise.Enabled),

                new RegEntry("--", "Timer", noise.Timer),
                new RegEntry("--", "Envelope Timer", noise.EnvTimer),
                new RegEntry("--", "Shift Register", noise.ShiftRegister, Format.X16),
                new RegEntry("--", "Output", noise.Output)
            });


            GbWaveState wave = gb.Apu.Wave;

            entries.AddRange(new List <RegEntry>()
            {
                new RegEntry("$FF1A-$FF1E", "Wave", null),
                new RegEntry("$FF1A.7", "Sound Enabled", wave.DacEnabled),

                new RegEntry("$FF1B", "Length", wave.Length),

                new RegEntry("$FF1C.5-6", "Volume", wave.Volume),

                new RegEntry("$FF1D+$FF1E.0-2", "Frequency", wave.Frequency),

                new RegEntry("$FF1E.6", "Length Counter Enabled", wave.LengthEnabled),
                new RegEntry("$FF1E.7", "Channel Enabled", wave.Enabled),

                new RegEntry("--", "Timer", wave.Timer),
                new RegEntry("--", "Sample Buffer", wave.SampleBuffer),
                new RegEntry("--", "Position", wave.Position),
                new RegEntry("--", "Output", wave.Output),
            });

            ctrlCoprocessor.UpdateState(entries);
        }
Beispiel #4
0
        public void RefreshViewer()
        {
            if (_layerBpp[_state.Ppu.BgMode, _options.Layer] == 0)
            {
                _options.Layer = 0;
            }

            if (_isGameboyMode)
            {
                DebugApi.GetGameboyTilemap(_vram, _state.Gameboy.Ppu, (ushort)(_options.Layer == 0 ? 0x1800 : 0x1C00), _tilemapData);
            }
            else
            {
                DebugApi.GetTilemap(_options, _state.Ppu, _vram, _cgram, _tilemapData);
            }

            int mapWidth  = GetWidth();
            int mapHeight = GetHeight();

            if (_tilemapImage.Width != mapWidth || _tilemapImage.Height != mapHeight)
            {
                _tilemapImage        = new Bitmap(mapWidth, mapHeight, PixelFormat.Format32bppPArgb);
                ctrlImagePanel.Image = _tilemapImage;
            }
            using (Graphics g = Graphics.FromImage(_tilemapImage)) {
                GCHandle handle = GCHandle.Alloc(_tilemapData, GCHandleType.Pinned);
                Bitmap   source = new Bitmap(mapWidth, mapHeight, 4 * 1024, PixelFormat.Format32bppPArgb, handle.AddrOfPinnedObject());
                g.DrawImage(source, 0, 0);
                handle.Free();
            }

            btnLayer1.BackColor = _options.Layer == 0 ? SystemColors.GradientActiveCaption : Color.Empty;
            btnLayer2.BackColor = _options.Layer == 1 ? SystemColors.GradientActiveCaption : Color.Empty;
            btnLayer3.BackColor = _options.Layer == 2 ? SystemColors.GradientActiveCaption : Color.Empty;
            btnLayer4.BackColor = _options.Layer == 3 ? SystemColors.GradientActiveCaption : Color.Empty;

            btnLayer1.Enabled = _layerBpp[_state.Ppu.BgMode, 0] > 0;
            btnLayer2.Enabled = _layerBpp[_state.Ppu.BgMode, 1] > 0;
            btnLayer3.Enabled = _layerBpp[_state.Ppu.BgMode, 2] > 0;
            btnLayer4.Enabled = _layerBpp[_state.Ppu.BgMode, 3] > 0;

            btnLayer1.Text  = _isGameboyMode ? "BG" : "1";
            btnLayer2.Text  = _isGameboyMode ? "Window" : "2";
            btnLayer2.Width = _isGameboyMode ? 64 : 32;

            btnLayer3.Visible = !_isGameboyMode;
            btnLayer4.Visible = !_isGameboyMode;

            lblMap.Visible       = !_isGameboyMode;
            txtMapNumber.Visible = !_isGameboyMode;
            lblValue.Visible     = !_isGameboyMode;
            txtValue.Visible     = !_isGameboyMode;

            ctrlImagePanel.ImageSize = new Size(GetWidth(), GetHeight());
            ctrlImagePanel.Selection = new Rectangle(_selectedColumn * 8, _selectedRow * 8, IsLargeTileWidth ? 16 : 8, IsLargeTileHeight ? 16 : 8);

            ctrlImagePanel.GridSizeX = chkShowTileGrid.Checked ? (IsLargeTileWidth ? 16 : 8): 0;
            ctrlImagePanel.GridSizeY = chkShowTileGrid.Checked ? (IsLargeTileHeight ? 16 : 8): 0;

            if (chkShowScrollOverlay.Checked)
            {
                if (_isGameboyMode)
                {
                    if (_options.Layer == 0)
                    {
                        GbPpuState ppu = _state.Gameboy.Ppu;
                        ctrlImagePanel.Overlay = new Rectangle(ppu.ScrollX, ppu.ScrollY, 160, 144);
                    }
                    else
                    {
                        //Hide for window, doesn't make sense to show this
                        ctrlImagePanel.Overlay = Rectangle.Empty;
                    }
                }
                else
                {
                    LayerConfig layer   = _state.Ppu.Layers[_options.Layer];
                    int         hScroll = _state.Ppu.BgMode == 7 ? (int)_state.Ppu.Mode7.HScroll : layer.HScroll;
                    int         vScroll = _state.Ppu.BgMode == 7 ? (int)_state.Ppu.Mode7.VScroll : layer.VScroll;
                    int         height  = _state.Ppu.OverscanMode ? 239 : 224;
                    ctrlImagePanel.Overlay = new Rectangle(hScroll, vScroll, IsDoubleWidthScreen ? 512 : 256, IsDoubleHeightScreen ? height * 2 : height);
                }
            }
            else
            {
                ctrlImagePanel.Overlay = Rectangle.Empty;
            }
            ctrlImagePanel.Refresh();

            if (_isGameboyMode)
            {
                UpdateGameboyFields();
            }
            else
            {
                UpdateFields();
            }
        }
Beispiel #5
0
        private void UpdateGameboyTab()
        {
            GbState         gb      = _state.Gameboy;
            List <RegEntry> entries = new List <RegEntry>();

            GbPpuState ppu = gb.Ppu;

            entries.AddRange(new List <RegEntry>()
            {
                new RegEntry("$FF40", "LCD Control (LCDC)", null),
                new RegEntry("$FF40.0", "Background Enabled", ppu.BgEnabled),
                new RegEntry("$FF40.1", "Sprites Enabled", ppu.BgEnabled),
                new RegEntry("$FF40.2", "Sprite size", ppu.LargeSprites ? "8x16" : "8x8"),
                new RegEntry("$FF40.3", "BG Tilemap Select", ppu.BgTilemapSelect ? 0x9C00 : 0x9800, Format.X16),
                new RegEntry("$FF40.4", "BG Tile Select", ppu.BgTileSelect ? "$8000-$8FFF" : "$8800-$97FF"),
                new RegEntry("$FF40.5", "Window Enabled", ppu.WindowEnabled),
                new RegEntry("$FF40.6", "Window Tilemap Select", ppu.WindowTilemapSelect ? 0x9C00 : 0x9800, Format.X16),
                new RegEntry("$FF40.7", "LCD Enabled", ppu.LcdEnabled),

                new RegEntry("$FF41", "LCD Status (STAT)", null),
                new RegEntry("$FF41.0-1", "Mode", (int)ppu.Mode),
                new RegEntry("$FF41.2", "Coincidence Flag", ppu.LyCoincidenceFlag),
                new RegEntry("$FF41.3", "Mode 0 H-Blank IRQ", (ppu.Status & 0x08) != 0),
                new RegEntry("$FF41.4", "Mode 1 V-Blank IRQ", (ppu.Status & 0x10) != 0),
                new RegEntry("$FF41.5", "Mode 2 OAM IRQ", (ppu.Status & 0x20) != 0),
                new RegEntry("$FF41.6", "LYC=LY Coincidence IRQ", (ppu.Status & 0x40) != 0),

                new RegEntry("", "LCD Registers", null),
                new RegEntry("$FF42", "Scroll Y (SCY)", ppu.ScrollY, Format.X8),
                new RegEntry("$FF43", "Scroll X (SCX)", ppu.ScrollX, Format.X8),
                new RegEntry("$FF44", "Y-Coordinate (LY)", ppu.Ly, Format.X8),
                new RegEntry("$FF45", "LY Compare (LYC)", ppu.LyCompare, Format.X8),
                new RegEntry("$FF47", "BG Palette (BGP)", ppu.BgPalette, Format.X8),
                new RegEntry("$FF48", "OBJ Palette 0 (OBP0)", ppu.ObjPalette0, Format.X8),
                new RegEntry("$FF49", "OBJ Palette 1 (OBP1)", ppu.ObjPalette1, Format.X8),
                new RegEntry("$FF4A", "Window Y (WY)", ppu.WindowY, Format.X8),
                new RegEntry("$FF4B", "Window X (WX)", ppu.WindowX, Format.X8),
            });

            GbSquareState sq1 = gb.Apu.Square1;

            entries.AddRange(new List <RegEntry>()
            {
                new RegEntry("$FF10-$FF14", "Square 1", null),
                new RegEntry("$FF10.0-2", "Sweep Shift", sq1.SweepShift),
                new RegEntry("$FF10.3", "Sweep Negate", sq1.SweepNegate),
                new RegEntry("$FF10.4-7", "Sweep Period", sq1.SweepPeriod),

                new RegEntry("$FF11.0-5", "Length", sq1.Length),
                new RegEntry("$FF11.6-7", "Duty", sq1.Duty),

                new RegEntry("$FF12.0-2", "Envelope Period", sq1.EnvPeriod),
                new RegEntry("$FF12.3", "Envelope Increase Volume", sq1.EnvRaiseVolume),
                new RegEntry("$FF12.4-7", "Envelope Volume", sq1.EnvVolume),

                new RegEntry("$FF13+$FF14.0-2", "Frequency", sq1.Frequency),
                new RegEntry("$FF14.6", "Length Counter Enabled", sq1.LengthEnabled),
                new RegEntry("$FF14.7", "Channel Enabled", sq1.Enabled),

                new RegEntry("--", "Timer", sq1.Timer),
                new RegEntry("--", "Duty Position", sq1.DutyPos),
                new RegEntry("--", "Sweep Enabled", sq1.SweepEnabled),
                new RegEntry("--", "Sweep Frequency", sq1.SweepFreq),
                new RegEntry("--", "Sweep Timer", sq1.SweepTimer),
                new RegEntry("--", "Envelope Timer", sq1.EnvTimer),
                new RegEntry("--", "Output", sq1.Output)
            });

            GbSquareState sq2 = gb.Apu.Square2;

            entries.AddRange(new List <RegEntry>()
            {
                new RegEntry("$FF16-$FF19", "Square 2", null),
                new RegEntry("$FF16.0-5", "Length", sq2.Length),
                new RegEntry("$FF16.6-7", "Duty", sq2.Duty),

                new RegEntry("$FF17.0-2", "Envelope Period", sq2.EnvPeriod),
                new RegEntry("$FF17.3", "Envelope Increase Volume", sq2.EnvRaiseVolume),
                new RegEntry("$FF17.4-7", "Envelope Volume", sq2.EnvVolume),

                new RegEntry("$FF18+$FF19.0-2", "Frequency", sq2.Frequency),
                new RegEntry("$FF19.6", "Length Counter Enabled", sq2.LengthEnabled),
                new RegEntry("$FF19.7", "Channel Enabled", sq2.Enabled),

                new RegEntry("--", "Timer", sq2.Timer),
                new RegEntry("--", "Duty Position", sq2.DutyPos),
                new RegEntry("--", "Envelope Timer", sq2.EnvTimer),
                new RegEntry("--", "Output", sq2.Output)
            });

            GbNoiseState noise = gb.Apu.Noise;

            entries.AddRange(new List <RegEntry>()
            {
                new RegEntry("$FF20-$FF23", "Noise", null),
                new RegEntry("$FF20.0-5", "Length", noise.Length),

                new RegEntry("$FF21.0-2", "Envelope Period", noise.EnvPeriod),
                new RegEntry("$FF21.3", "Envelope Increase Volume", noise.EnvRaiseVolume),
                new RegEntry("$FF21.4-7", "Envelope Volume", noise.EnvVolume),

                new RegEntry("$FF23.0-2", "Divisor", noise.Divisor),
                new RegEntry("$FF23.3", "Short Mode", noise.ShortWidthMode),
                new RegEntry("$FF23.4-7", "Period Shift", noise.PeriodShift),

                new RegEntry("$FF24.6", "Length Counter Enabled", noise.LengthEnabled),
                new RegEntry("$FF24.7", "Channel Enabled", noise.Enabled),

                new RegEntry("--", "Timer", noise.Timer),
                new RegEntry("--", "Envelope Timer", noise.EnvTimer),
                new RegEntry("--", "Shift Register", noise.ShiftRegister, Format.X16),
                new RegEntry("--", "Output", noise.Output)
            });


            GbWaveState wave = gb.Apu.Wave;

            entries.AddRange(new List <RegEntry>()
            {
                new RegEntry("$FF1A-$FF1E", "Wave", null),
                new RegEntry("$FF1A.7", "Sound Enabled", wave.DacEnabled),

                new RegEntry("$FF1B", "Length", wave.Length),

                new RegEntry("$FF1C.5-6", "Volume", wave.Volume),

                new RegEntry("$FF1D+$FF1E.0-2", "Frequency", wave.Frequency),

                new RegEntry("$FF1E.6", "Length Counter Enabled", wave.LengthEnabled),
                new RegEntry("$FF1E.7", "Channel Enabled", wave.Enabled),

                new RegEntry("--", "Timer", wave.Timer),
                new RegEntry("--", "Position", wave.SampleBuffer),
                new RegEntry("--", "Position", wave.Position),
                new RegEntry("--", "Output", wave.Output),
            });

            ctrlCoprocessor.UpdateState(entries);
        }