diff --git a/BizHawk.Client.Common/RomLoader.cs b/BizHawk.Client.Common/RomLoader.cs
index 9a9e0338ab..d054ab86f6 100644
--- a/BizHawk.Client.Common/RomLoader.cs
+++ b/BizHawk.Client.Common/RomLoader.cs
@@ -922,6 +922,7 @@ namespace BizHawk.Client.Common
{
//core = CoreInventory.Instance["GB", "Pizza Boy"];
core = CoreInventory.Instance["GB", "Gambatte"];
+ //core = CoreInventory.Instance["GB", "SameBoy"];
}
else
{
@@ -934,7 +935,7 @@ namespace BizHawk.Client.Common
}
else
{
- core = CoreInventory.Instance["SGB", "Pizza Boy"];
+ core = CoreInventory.Instance["SGB", "SameBoy"];
}
}
break;
diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs
index 290b2429bf..21c72d1312 100644
--- a/BizHawk.Client.EmuHawk/MainForm.Events.cs
+++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs
@@ -25,6 +25,7 @@ using BizHawk.Client.EmuHawk.ToolExtensions;
using BizHawk.Emulation.Cores.Computers.AppleII;
using BizHawk.Client.ApiHawk;
using BizHawk.Emulation.Cores.Computers.Commodore64;
+using BizHawk.Emulation.Cores.Nintendo.Gameboy;
namespace BizHawk.Client.EmuHawk
{
@@ -2002,7 +2003,14 @@ namespace BizHawk.Client.EmuHawk
private void GBCoreSettingsMenuItem_Click(object sender, EventArgs e)
{
- GBPrefs.DoGBPrefsDialog(this);
+ if (Global.Emulator is Gameboy)
+ {
+ GBPrefs.DoGBPrefsDialog(this);
+ }
+ else // sameboy
+ {
+ GenericCoreConfig.DoDialog(this, "Gameboy Settings");
+ }
}
private void LoadGbInSgbMenuItem_Click(object sender, EventArgs e)
diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs
index 2274b6ce5e..611c693e20 100644
--- a/BizHawk.Client.EmuHawk/MainForm.cs
+++ b/BizHawk.Client.EmuHawk/MainForm.cs
@@ -33,6 +33,7 @@ using BizHawk.Emulation.Common.Base_Implementations;
using BizHawk.Emulation.Cores.Nintendo.SNES9X;
using BizHawk.Emulation.Cores.Consoles.SNK;
using BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive;
+using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy;
namespace BizHawk.Client.EmuHawk
{
@@ -1744,6 +1745,10 @@ namespace BizHawk.Client.EmuHawk
{
sNESToolStripMenuItem.Visible = true;
}
+ else if (Emulator is Sameboy)
+ {
+ GBSubMenu.Visible = true;
+ }
break;
case "Coleco":
ColecoSubMenu.Visible = true;
diff --git a/BizHawk.Client.EmuHawk/tools/GB/GBGPUView.cs b/BizHawk.Client.EmuHawk/tools/GB/GBGPUView.cs
index 6151c05677..8dc50567ef 100644
--- a/BizHawk.Client.EmuHawk/tools/GB/GBGPUView.cs
+++ b/BizHawk.Client.EmuHawk/tools/GB/GBGPUView.cs
@@ -9,13 +9,15 @@ using BizHawk.Emulation.Cores.Nintendo.Gameboy;
using BizHawk.Client.EmuHawk.WinFormExtensions;
using System.Collections.Generic;
using BizHawk.Emulation.Common;
+using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy;
+using BizHawk.Common;
namespace BizHawk.Client.EmuHawk
{
public partial class GBGPUView : Form, IToolFormAutoConfig
{
[RequiredService]
- public Gameboy Gb { get; private set; }
+ public IGameboyCommon Gb { get; private set; }
// TODO: freeze semantics are a bit weird: details for a mouseover or freeze are taken from the current
// state, not the state at the last callback (and so can be quite different when update is set to manual).
@@ -32,11 +34,8 @@ namespace BizHawk.Client.EmuHawk
// g' = 8.25g
// b' = 8.25b
- // gambatte doesn't modify these memory locations unless you reconstruct, so we can store
- private IntPtr _vram;
- private IntPtr _bgpal;
- private IntPtr _sppal;
- private IntPtr _oam;
+
+ private GPUMemoryAreas _memory;
private bool _cgb; // set once at start
private int _lcdc; // set at each callback
@@ -89,13 +88,9 @@ namespace BizHawk.Client.EmuHawk
_cgb = Gb.IsCGBMode();
_lcdc = 0;
- // TODO: can this be a required Emulator Service, and let the tool manage the logic of closing?
- if (!Gb.GetGPUMemoryAreas(out _vram, out _bgpal, out _sppal, out _oam))
- {
- if (Visible)
- Close();
- }
- tilespal = _bgpal;
+ _memory = Gb.GetGPU();
+
+ tilespal = _memory.Bgpal;
if (_cgb)
label4.Enabled = true;
@@ -357,112 +352,120 @@ namespace BizHawk.Client.EmuHawk
#endregion
- void ScanlineCallback(int lcdc)
+ void ScanlineCallback(byte lcdc)
{
- _lcdc = lcdc;
- // set alpha on all pixels
- unsafe
+ using (_memory.EnterExit())
{
- int* p = (int*)_bgpal;
- for (int i = 0; i < 32; i++)
- p[i] |= unchecked((int)0xff000000);
- p = (int*)_sppal;
- for (int i = 0; i < 32; i++)
- p[i] |= unchecked((int)0xff000000);
- int c = Spriteback.ToArgb();
- for (int i = 0; i < 32; i += 4)
- p[i] = c;
- }
+ var _bgpal = _memory.Bgpal;
+ var _sppal = _memory.Sppal;
+ var _oam = _memory.Oam;
+ var _vram = _memory.Vram;
- // bg maps
- if (!_cgb)
- {
- DrawBGDMG(
- bmpViewBG.BMP,
- _vram + (lcdc.Bit(3) ? 0x1c00 : 0x1800),
- _vram + (lcdc.Bit(4) ? 0x0000 : 0x1000),
- !lcdc.Bit(4),
- _bgpal);
+ _lcdc = lcdc;
+ // set alpha on all pixels
+ // TODO: RE: Spriteback, you can't muck with Sameboy in this way due to how SGB reads stuff...?
+ /*unsafe
+ {
+ int* p = (int*)_bgpal;
+ for (int i = 0; i < 32; i++)
+ p[i] |= unchecked((int)0xff000000);
+ p = (int*)_sppal;
+ for (int i = 0; i < 32; i++)
+ p[i] |= unchecked((int)0xff000000);
+ int c = Spriteback.ToArgb();
+ for (int i = 0; i < 32; i += 4)
+ p[i] = c;
+ }*/
- DrawBGDMG(
- bmpViewWin.BMP,
- _vram + (lcdc.Bit(6) ? 0x1c00 : 0x1800),
- _vram + 0x1000, // force win to second tile bank???
- true,
- _bgpal);
- }
- else
- {
- DrawBGCGB(
- bmpViewBG.BMP,
- _vram + (lcdc.Bit(3) ? 0x1c00 : 0x1800),
- _vram + (lcdc.Bit(4) ? 0x0000 : 0x1000),
- !lcdc.Bit(4),
- _bgpal);
+ // bg maps
+ if (!_cgb)
+ {
+ DrawBGDMG(
+ bmpViewBG.BMP,
+ _vram + (lcdc.Bit(3) ? 0x1c00 : 0x1800),
+ _vram + (lcdc.Bit(4) ? 0x0000 : 0x1000),
+ !lcdc.Bit(4),
+ _bgpal);
- DrawBGCGB(
- bmpViewWin.BMP,
- _vram + (lcdc.Bit(6) ? 0x1c00 : 0x1800),
- _vram + 0x1000, // force win to second tile bank???
- true,
- _bgpal);
- }
- bmpViewBG.Refresh();
- bmpViewWin.Refresh();
+ DrawBGDMG(
+ bmpViewWin.BMP,
+ _vram + (lcdc.Bit(6) ? 0x1c00 : 0x1800),
+ _vram + 0x1000, // force win to second tile bank???
+ true,
+ _bgpal);
+ }
+ else
+ {
+ DrawBGCGB(
+ bmpViewBG.BMP,
+ _vram + (lcdc.Bit(3) ? 0x1c00 : 0x1800),
+ _vram + (lcdc.Bit(4) ? 0x0000 : 0x1000),
+ !lcdc.Bit(4),
+ _bgpal);
- // tile display
- // TODO: user selects palette to use, instead of fixed palette 0
- // or possibly "smart" where, if a tile is in use, it's drawn with one of the palettes actually being used with it?
- DrawTiles(bmpViewTiles1.BMP, _vram, tilespal);
- bmpViewTiles1.Refresh();
- if (_cgb)
- {
- DrawTiles(bmpViewTiles2.BMP, _vram + 0x2000, tilespal);
- bmpViewTiles2.Refresh();
- }
+ DrawBGCGB(
+ bmpViewWin.BMP,
+ _vram + (lcdc.Bit(6) ? 0x1c00 : 0x1800),
+ _vram + 0x1000, // force win to second tile bank???
+ true,
+ _bgpal);
+ }
+ bmpViewBG.Refresh();
+ bmpViewWin.Refresh();
- // palettes
- if (_cgb)
- {
- bmpViewBGPal.ChangeBitmapSize(8, 4);
- if (bmpViewBGPal.Width != 128)
- bmpViewBGPal.Width = 128;
- bmpViewSPPal.ChangeBitmapSize(8, 4);
- if (bmpViewSPPal.Width != 128)
- bmpViewSPPal.Width = 128;
- DrawPal(bmpViewBGPal.BMP, _bgpal, 8);
- DrawPal(bmpViewSPPal.BMP, _sppal, 8);
- }
- else
- {
- bmpViewBGPal.ChangeBitmapSize(1, 4);
- if (bmpViewBGPal.Width != 16)
- bmpViewBGPal.Width = 16;
- bmpViewSPPal.ChangeBitmapSize(2, 4);
- if (bmpViewSPPal.Width != 32)
- bmpViewSPPal.Width = 32;
- DrawPal(bmpViewBGPal.BMP, _bgpal, 1);
- DrawPal(bmpViewSPPal.BMP, _sppal, 2);
- }
- bmpViewBGPal.Refresh();
- bmpViewSPPal.Refresh();
+ // tile display
+ // TODO: user selects palette to use, instead of fixed palette 0
+ // or possibly "smart" where, if a tile is in use, it's drawn with one of the palettes actually being used with it?
+ DrawTiles(bmpViewTiles1.BMP, _vram, tilespal);
+ bmpViewTiles1.Refresh();
+ if (_cgb)
+ {
+ DrawTiles(bmpViewTiles2.BMP, _vram + 0x2000, tilespal);
+ bmpViewTiles2.Refresh();
+ }
- // oam
- if (lcdc.Bit(2)) // 8x16
- {
- bmpViewOAM.ChangeBitmapSize(320, 16);
- if (bmpViewOAM.Height != 16)
- bmpViewOAM.Height = 16;
- }
- else
- {
- bmpViewOAM.ChangeBitmapSize(320, 8);
- if (bmpViewOAM.Height != 8)
- bmpViewOAM.Height = 8;
- }
- DrawOam(bmpViewOAM.BMP, _oam, _vram, _sppal, lcdc.Bit(2), _cgb);
- bmpViewOAM.Refresh();
+ // palettes
+ if (_cgb)
+ {
+ bmpViewBGPal.ChangeBitmapSize(8, 4);
+ if (bmpViewBGPal.Width != 128)
+ bmpViewBGPal.Width = 128;
+ bmpViewSPPal.ChangeBitmapSize(8, 4);
+ if (bmpViewSPPal.Width != 128)
+ bmpViewSPPal.Width = 128;
+ DrawPal(bmpViewBGPal.BMP, _bgpal, 8);
+ DrawPal(bmpViewSPPal.BMP, _sppal, 8);
+ }
+ else
+ {
+ bmpViewBGPal.ChangeBitmapSize(1, 4);
+ if (bmpViewBGPal.Width != 16)
+ bmpViewBGPal.Width = 16;
+ bmpViewSPPal.ChangeBitmapSize(2, 4);
+ if (bmpViewSPPal.Width != 32)
+ bmpViewSPPal.Width = 32;
+ DrawPal(bmpViewBGPal.BMP, _bgpal, 1);
+ DrawPal(bmpViewSPPal.BMP, _sppal, 2);
+ }
+ bmpViewBGPal.Refresh();
+ bmpViewSPPal.Refresh();
+ // oam
+ if (lcdc.Bit(2)) // 8x16
+ {
+ bmpViewOAM.ChangeBitmapSize(320, 16);
+ if (bmpViewOAM.Height != 16)
+ bmpViewOAM.Height = 16;
+ }
+ else
+ {
+ bmpViewOAM.ChangeBitmapSize(320, 8);
+ if (bmpViewOAM.Height != 8)
+ bmpViewOAM.Height = 8;
+ }
+ DrawOam(bmpViewOAM.BMP, _oam, _vram, _sppal, lcdc.Bit(2), _cgb);
+ bmpViewOAM.Refresh();
+ }
// try to run the current mouseover, to refresh if the mouse is being held over a pane while the emulator runs
// this doesn't really work well; the update rate seems to be throttled
MouseEventArgs e = new MouseEventArgs(MouseButtons.None, 0, Cursor.Position.X, Cursor.Position.Y, 0);
@@ -514,7 +517,7 @@ namespace BizHawk.Client.EmuHawk
private void buttonRefresh_Click(object sender, EventArgs e)
{
- if (cbscanline == -2 && Gb != null)
+ if (cbscanline == -2)
Gb.SetScanlineCallback(ScanlineCallback, -2);
}
@@ -614,145 +617,177 @@ namespace BizHawk.Client.EmuHawk
private unsafe void PaletteMouseover(int x, int y, bool sprite)
{
- bmpViewDetails.ChangeBitmapSize(8, 10);
- if (bmpViewDetails.Height != 80)
- bmpViewDetails.Height = 80;
- var sb = new StringBuilder();
- x /= 16;
- y /= 16;
- int* pal = (int*)(sprite ? _sppal : _bgpal) + x * 4;
- int color = pal[y];
-
- sb.AppendLine(string.Format("Palette {0}", x));
- sb.AppendLine(string.Format("Color {0}", y));
- sb.AppendLine(string.Format("(R,G,B) = ({0},{1},{2})", color >> 16 & 255, color >> 8 & 255, color & 255));
-
- var lockdata = bmpViewDetails.BMP.LockBits(new Rectangle(0, 0, 8, 10), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
- int* dest = (int*)lockdata.Scan0;
- int pitch = lockdata.Stride / sizeof(int);
-
- for (int py = 0; py < 10; py++)
+ using (_memory.EnterExit())
{
- for (int px = 0; px < 8; px++)
+ var _bgpal = _memory.Bgpal;
+ var _sppal = _memory.Sppal;
+ var _oam = _memory.Oam;
+ var _vram = _memory.Vram;
+
+ bmpViewDetails.ChangeBitmapSize(8, 10);
+ if (bmpViewDetails.Height != 80)
+ bmpViewDetails.Height = 80;
+ var sb = new StringBuilder();
+ x /= 16;
+ y /= 16;
+ int* pal = (int*)(sprite ? _sppal : _bgpal) + x * 4;
+ int color = pal[y];
+
+ sb.AppendLine(string.Format("Palette {0}", x));
+ sb.AppendLine(string.Format("Color {0}", y));
+ sb.AppendLine(string.Format("(R,G,B) = ({0},{1},{2})", color >> 16 & 255, color >> 8 & 255, color & 255));
+
+ var lockdata = bmpViewDetails.BMP.LockBits(new Rectangle(0, 0, 8, 10), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+ int* dest = (int*)lockdata.Scan0;
+ int pitch = lockdata.Stride / sizeof(int);
+
+ for (int py = 0; py < 10; py++)
{
- if (py < 8)
- *dest++ = color;
- else
- *dest++ = pal[px / 2];
+ for (int px = 0; px < 8; px++)
+ {
+ if (py < 8)
+ *dest++ = color;
+ else
+ *dest++ = pal[px / 2];
+ }
+ dest -= 8;
+ dest += pitch;
}
- dest -= 8;
- dest += pitch;
+ bmpViewDetails.BMP.UnlockBits(lockdata);
+ labelDetails.Text = sb.ToString();
+ bmpViewDetails.Refresh();
}
- bmpViewDetails.BMP.UnlockBits(lockdata);
- labelDetails.Text = sb.ToString();
- bmpViewDetails.Refresh();
}
unsafe void TileMouseover(int x, int y, bool secondbank)
{
- // todo: draw with a specific palette
- bmpViewDetails.ChangeBitmapSize(8, 8);
- if (bmpViewDetails.Height != 64)
- bmpViewDetails.Height = 64;
- var sb = new StringBuilder();
- x /= 8;
- y /= 8;
- int tileindex = y * 16 + x;
- int tileoffs = tileindex * 16;
- if (_cgb)
- sb.AppendLine(string.Format("Tile #{0} @{2}:{1:x4}", tileindex, tileoffs + 0x8000, secondbank ? 1 : 0));
- else
- sb.AppendLine(string.Format("Tile #{0} @{1:x4}", tileindex, tileoffs + 0x8000));
+ using (_memory.EnterExit())
+ {
+ var _bgpal = _memory.Bgpal;
+ var _sppal = _memory.Sppal;
+ var _oam = _memory.Oam;
+ var _vram = _memory.Vram;
- var lockdata = bmpViewDetails.BMP.LockBits(new Rectangle(0, 0, 8, 8), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
- DrawTile((byte*)_vram + tileoffs + (secondbank ? 8192 : 0), (int*)lockdata.Scan0, lockdata.Stride / sizeof(int), (int*)tilespal);
- bmpViewDetails.BMP.UnlockBits(lockdata);
- labelDetails.Text = sb.ToString();
- bmpViewDetails.Refresh();
+ // todo: draw with a specific palette
+ bmpViewDetails.ChangeBitmapSize(8, 8);
+ if (bmpViewDetails.Height != 64)
+ bmpViewDetails.Height = 64;
+ var sb = new StringBuilder();
+ x /= 8;
+ y /= 8;
+ int tileindex = y * 16 + x;
+ int tileoffs = tileindex * 16;
+ if (_cgb)
+ sb.AppendLine(string.Format("Tile #{0} @{2}:{1:x4}", tileindex, tileoffs + 0x8000, secondbank ? 1 : 0));
+ else
+ sb.AppendLine(string.Format("Tile #{0} @{1:x4}", tileindex, tileoffs + 0x8000));
+
+ var lockdata = bmpViewDetails.BMP.LockBits(new Rectangle(0, 0, 8, 8), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+ DrawTile((byte*)_vram + tileoffs + (secondbank ? 8192 : 0), (int*)lockdata.Scan0, lockdata.Stride / sizeof(int), (int*)tilespal);
+ bmpViewDetails.BMP.UnlockBits(lockdata);
+ labelDetails.Text = sb.ToString();
+ bmpViewDetails.Refresh();
+ }
}
unsafe void TilemapMouseover(int x, int y, bool win)
{
- bmpViewDetails.ChangeBitmapSize(8, 8);
- if (bmpViewDetails.Height != 64)
- bmpViewDetails.Height = 64;
- var sb = new StringBuilder();
- bool secondmap = win ? _lcdc.Bit(6) : _lcdc.Bit(3);
- int mapoffs = secondmap ? 0x1c00 : 0x1800;
- x /= 8;
- y /= 8;
- mapoffs += y * 32 + x;
- byte* mapbase = (byte*)_vram + mapoffs;
- int tileindex = mapbase[0];
- if (win || !_lcdc.Bit(4)) // 0x9000 base
- if (tileindex < 128)
- tileindex += 256; // compute all if from 0x8000 base
- int tileoffs = tileindex * 16;
- var lockdata = bmpViewDetails.BMP.LockBits(new Rectangle(0, 0, 8, 8), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
- if (!_cgb)
+ using (_memory.EnterExit())
{
- sb.AppendLine(string.Format("{0} Map ({1},{2}) @{3:x4}", win ? "Win" : "BG", x, y, mapoffs + 0x8000));
- sb.AppendLine(string.Format(" Tile #{0} @{1:x4}", tileindex, tileoffs + 0x8000));
- DrawTile((byte*)_vram + tileoffs, (int*)lockdata.Scan0, lockdata.Stride / sizeof(int), (int*)_bgpal);
- }
- else
- {
- int tileext = mapbase[8192];
+ var _bgpal = _memory.Bgpal;
+ var _sppal = _memory.Sppal;
+ var _oam = _memory.Oam;
+ var _vram = _memory.Vram;
- sb.AppendLine(string.Format("{0} Map ({1},{2}) @{3:x4}", win ? "Win" : "BG", x, y, mapoffs + 0x8000));
- sb.AppendLine(string.Format(" Tile #{0} @{2}:{1:x4}", tileindex, tileoffs + 0x8000, tileext.Bit(3) ? 1 : 0));
- sb.AppendLine(string.Format(" Palette {0}", tileext & 7));
- sb.AppendLine(string.Format(" Flags {0}{1}{2}", tileext.Bit(5) ? 'H' : ' ', tileext.Bit(6) ? 'V' : ' ', tileext.Bit(7) ? 'P' : ' '));
- DrawTileHv((byte*)_vram + tileoffs + (tileext.Bit(3) ? 8192 : 0), (int*)lockdata.Scan0, lockdata.Stride / sizeof(int), (int*)_bgpal + 4 * (tileext & 7), tileext.Bit(5), tileext.Bit(6));
+ bmpViewDetails.ChangeBitmapSize(8, 8);
+ if (bmpViewDetails.Height != 64)
+ bmpViewDetails.Height = 64;
+ var sb = new StringBuilder();
+ bool secondmap = win ? _lcdc.Bit(6) : _lcdc.Bit(3);
+ int mapoffs = secondmap ? 0x1c00 : 0x1800;
+ x /= 8;
+ y /= 8;
+ mapoffs += y * 32 + x;
+ byte* mapbase = (byte*)_vram + mapoffs;
+ int tileindex = mapbase[0];
+ if (win || !_lcdc.Bit(4)) // 0x9000 base
+ if (tileindex < 128)
+ tileindex += 256; // compute all if from 0x8000 base
+ int tileoffs = tileindex * 16;
+ var lockdata = bmpViewDetails.BMP.LockBits(new Rectangle(0, 0, 8, 8), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+ if (!_cgb)
+ {
+ sb.AppendLine(string.Format("{0} Map ({1},{2}) @{3:x4}", win ? "Win" : "BG", x, y, mapoffs + 0x8000));
+ sb.AppendLine(string.Format(" Tile #{0} @{1:x4}", tileindex, tileoffs + 0x8000));
+ DrawTile((byte*)_vram + tileoffs, (int*)lockdata.Scan0, lockdata.Stride / sizeof(int), (int*)_bgpal);
+ }
+ else
+ {
+ int tileext = mapbase[8192];
+
+ sb.AppendLine(string.Format("{0} Map ({1},{2}) @{3:x4}", win ? "Win" : "BG", x, y, mapoffs + 0x8000));
+ sb.AppendLine(string.Format(" Tile #{0} @{2}:{1:x4}", tileindex, tileoffs + 0x8000, tileext.Bit(3) ? 1 : 0));
+ sb.AppendLine(string.Format(" Palette {0}", tileext & 7));
+ sb.AppendLine(string.Format(" Flags {0}{1}{2}", tileext.Bit(5) ? 'H' : ' ', tileext.Bit(6) ? 'V' : ' ', tileext.Bit(7) ? 'P' : ' '));
+ DrawTileHv((byte*)_vram + tileoffs + (tileext.Bit(3) ? 8192 : 0), (int*)lockdata.Scan0, lockdata.Stride / sizeof(int), (int*)_bgpal + 4 * (tileext & 7), tileext.Bit(5), tileext.Bit(6));
+ }
+ bmpViewDetails.BMP.UnlockBits(lockdata);
+ labelDetails.Text = sb.ToString();
+ bmpViewDetails.Refresh();
}
- bmpViewDetails.BMP.UnlockBits(lockdata);
- labelDetails.Text = sb.ToString();
- bmpViewDetails.Refresh();
}
unsafe void SpriteMouseover(int x, int y)
{
- bool tall = _lcdc.Bit(2);
- x /= 8;
- y /= 8;
- bmpViewDetails.ChangeBitmapSize(8, tall ? 16 : 8);
- if (bmpViewDetails.Height != bmpViewDetails.BMP.Height * 8)
- bmpViewDetails.Height = bmpViewDetails.BMP.Height * 8;
- var sb = new StringBuilder();
+ using (_memory.EnterExit())
+ {
+ var _bgpal = _memory.Bgpal;
+ var _sppal = _memory.Sppal;
+ var _oam = _memory.Oam;
+ var _vram = _memory.Vram;
- byte* oament = (byte*)_oam + 4 * x;
- int sy = oament[0];
- int sx = oament[1];
- int tilenum = oament[2];
- int flags = oament[3];
- bool hflip = flags.Bit(5);
- bool vflip = flags.Bit(6);
- if (tall)
- tilenum = vflip ? tilenum | 1 : tilenum & ~1;
- int tileoffs = tilenum * 16;
- sb.AppendLine(string.Format("Sprite #{0} @{1:x4}", x, 4 * x + 0xfe00));
- sb.AppendLine(string.Format(" (x,y) = ({0},{1})", sx, sy));
- var lockdata = bmpViewDetails.BMP.LockBits(new Rectangle(0, 0, 8, tall ? 16 : 8), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
- if (_cgb)
- {
- sb.AppendLine(string.Format(" Tile #{0} @{2}:{1:x4}", y == 1 ? tilenum ^ 1 : tilenum, tileoffs + 0x8000, flags.Bit(3) ? 1 : 0));
- sb.AppendLine(string.Format(" Palette {0}", flags & 7));
- DrawTileHv((byte*)_vram + tileoffs + (flags.Bit(3) ? 8192 : 0), (int*)lockdata.Scan0, lockdata.Stride / sizeof(int), (int*)_sppal + 4 * (flags & 7), hflip, vflip);
+ bool tall = _lcdc.Bit(2);
+ x /= 8;
+ y /= 8;
+ bmpViewDetails.ChangeBitmapSize(8, tall ? 16 : 8);
+ if (bmpViewDetails.Height != bmpViewDetails.BMP.Height * 8)
+ bmpViewDetails.Height = bmpViewDetails.BMP.Height * 8;
+ var sb = new StringBuilder();
+
+ byte* oament = (byte*)_oam + 4 * x;
+ int sy = oament[0];
+ int sx = oament[1];
+ int tilenum = oament[2];
+ int flags = oament[3];
+ bool hflip = flags.Bit(5);
+ bool vflip = flags.Bit(6);
if (tall)
- DrawTileHv((byte*)_vram + (tileoffs ^ 16) + (flags.Bit(3) ? 8192 : 0), (int*)(lockdata.Scan0 + lockdata.Stride * 8), lockdata.Stride / sizeof(int), (int*)_sppal + 4 * (flags & 7), hflip, vflip);
+ tilenum = vflip ? tilenum | 1 : tilenum & ~1;
+ int tileoffs = tilenum * 16;
+ sb.AppendLine(string.Format("Sprite #{0} @{1:x4}", x, 4 * x + 0xfe00));
+ sb.AppendLine(string.Format(" (x,y) = ({0},{1})", sx, sy));
+ var lockdata = bmpViewDetails.BMP.LockBits(new Rectangle(0, 0, 8, tall ? 16 : 8), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+ if (_cgb)
+ {
+ sb.AppendLine(string.Format(" Tile #{0} @{2}:{1:x4}", y == 1 ? tilenum ^ 1 : tilenum, tileoffs + 0x8000, flags.Bit(3) ? 1 : 0));
+ sb.AppendLine(string.Format(" Palette {0}", flags & 7));
+ DrawTileHv((byte*)_vram + tileoffs + (flags.Bit(3) ? 8192 : 0), (int*)lockdata.Scan0, lockdata.Stride / sizeof(int), (int*)_sppal + 4 * (flags & 7), hflip, vflip);
+ if (tall)
+ DrawTileHv((byte*)_vram + (tileoffs ^ 16) + (flags.Bit(3) ? 8192 : 0), (int*)(lockdata.Scan0 + lockdata.Stride * 8), lockdata.Stride / sizeof(int), (int*)_sppal + 4 * (flags & 7), hflip, vflip);
+ }
+ else
+ {
+ sb.AppendLine(string.Format(" Tile #{0} @{1:x4}", y == 1 ? tilenum ^ 1 : tilenum, tileoffs + 0x8000));
+ sb.AppendLine(string.Format(" Palette {0}", flags.Bit(4) ? 1 : 0));
+ DrawTileHv((byte*)_vram + tileoffs, (int*)lockdata.Scan0, lockdata.Stride / sizeof(int), (int*)_sppal + (flags.Bit(4) ? 4 : 0), hflip, vflip);
+ if (tall)
+ DrawTileHv((byte*)_vram + (tileoffs ^ 16), (int*)(lockdata.Scan0 + lockdata.Stride * 8), lockdata.Stride / sizeof(int), (int*)_sppal + 4 * (flags.Bit(4) ? 4 : 0), hflip, vflip);
+ }
+ sb.AppendLine(string.Format(" Flags {0}{1}{2}", hflip ? 'H' : ' ', vflip ? 'V' : ' ', flags.Bit(7) ? 'P' : ' '));
+ bmpViewDetails.BMP.UnlockBits(lockdata);
+ labelDetails.Text = sb.ToString();
+ bmpViewDetails.Refresh();
}
- else
- {
- sb.AppendLine(string.Format(" Tile #{0} @{1:x4}", y == 1 ? tilenum ^ 1 : tilenum, tileoffs + 0x8000));
- sb.AppendLine(string.Format(" Palette {0}", flags.Bit(4) ? 1 : 0));
- DrawTileHv((byte*)_vram + tileoffs, (int*)lockdata.Scan0, lockdata.Stride / sizeof(int), (int*)_sppal + (flags.Bit(4) ? 4 : 0), hflip, vflip);
- if (tall)
- DrawTileHv((byte*)_vram + (tileoffs ^ 16), (int*)(lockdata.Scan0 + lockdata.Stride * 8), lockdata.Stride / sizeof(int), (int*)_sppal + 4 * (flags.Bit(4) ? 4 : 0), hflip, vflip);
- }
- sb.AppendLine(string.Format(" Flags {0}{1}{2}", hflip ? 'H' : ' ', vflip ? 'V' : ' ', flags.Bit(7) ? 'P' : ' '));
- bmpViewDetails.BMP.UnlockBits(lockdata);
- labelDetails.Text = sb.ToString();
- bmpViewDetails.Refresh();
}
private void bmpViewBG_MouseEnter(object sender, EventArgs e)
@@ -882,9 +917,9 @@ namespace BizHawk.Client.EmuHawk
else if (e.Button == MouseButtons.Left)
{
if (sender == bmpViewBGPal)
- tilespal = _bgpal + e.X / 16 * 16;
+ tilespal = _memory.Bgpal + e.X / 16 * 16;
else if (sender == bmpViewSPPal)
- tilespal = _sppal + e.X / 16 * 16;
+ tilespal = _memory.Sppal + e.X / 16 * 16;
}
}
diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
index 64328b3723..a7b4a3b804 100644
--- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
+++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
@@ -539,7 +539,9 @@
+
+
@@ -1310,6 +1312,8 @@
+
+
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
index 9e04730e4a..864cdd856d 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
@@ -439,7 +439,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
#region ppudebug
- public bool GetGPUMemoryAreas(out IntPtr vram, out IntPtr bgpal, out IntPtr sppal, out IntPtr oam)
+ public GPUMemoryAreas GetGPU()
{
IntPtr _vram = IntPtr.Zero;
IntPtr _bgpal = IntPtr.Zero;
@@ -451,23 +451,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|| !LibGambatte.gambatte_getmemoryarea(GambatteState, LibGambatte.MemoryAreas.sppal, ref _sppal, ref unused)
|| !LibGambatte.gambatte_getmemoryarea(GambatteState, LibGambatte.MemoryAreas.oam, ref _oam, ref unused))
{
- vram = IntPtr.Zero;
- bgpal = IntPtr.Zero;
- sppal = IntPtr.Zero;
- oam = IntPtr.Zero;
- return false;
+ throw new InvalidOperationException("Unexpected error in gambatte_getmemoryarea");
}
- vram = _vram;
- bgpal = _bgpal;
- sppal = _sppal;
- oam = _oam;
- return true;
- }
+ return new GPUMemoryAreas(_vram, _oam, _sppal, _bgpal);
- ///
- ///
- /// current value of register $ff40 (LCDC)
- public delegate void ScanlineCallback(int lcdc);
+ }
///
/// set up callback
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/IGameboyCommon.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/IGameboyCommon.cs
index fa236b8f47..b874919ad7 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/IGameboyCommon.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/IGameboyCommon.cs
@@ -1,4 +1,6 @@
-using System;
+using BizHawk.Common;
+using BizHawk.Emulation.Common;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -6,8 +8,49 @@ using System.Threading.Tasks;
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
{
- public interface IGameboyCommon
+ ///
+ ///
+ /// current value of register $ff40 (LCDC)
+ public delegate void ScanlineCallback(byte lcdc);
+
+ public interface IGameboyCommon : ISpecializedEmulatorService
{
bool IsCGBMode();
+ GPUMemoryAreas GetGPU();
+
+ ///
+ /// set up callback
+ ///
+ /// scanline. -1 = end of frame, -2 = RIGHT NOW
+ void SetScanlineCallback(ScanlineCallback callback, int line);
+ }
+
+ public class GPUMemoryAreas : IMonitor
+ {
+ public IntPtr Vram { get; }
+ public IntPtr Oam { get; }
+ public IntPtr Sppal { get; }
+ public IntPtr Bgpal { get; }
+
+ private readonly IMonitor _monitor;
+
+ public GPUMemoryAreas(IntPtr vram, IntPtr oam, IntPtr sppal, IntPtr bgpal, IMonitor monitor = null)
+ {
+ Vram = vram;
+ Oam = oam;
+ Sppal = sppal;
+ Bgpal = bgpal;
+ _monitor = monitor;
+ }
+
+ public void Enter()
+ {
+ _monitor?.Enter();
+ }
+
+ public void Exit()
+ {
+ _monitor?.Exit();
+ }
}
}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibSameboy.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibSameboy.cs
new file mode 100644
index 0000000000..405635404c
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibSameboy.cs
@@ -0,0 +1,55 @@
+using BizHawk.Common.BizInvoke;
+using BizHawk.Emulation.Cores.Waterbox;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
+{
+ public abstract class LibSameboy : LibWaterboxCore
+ {
+ [Flags]
+ public enum Buttons : uint
+ {
+ A = 0x01,
+ B = 0x02,
+ SELECT = 0x04,
+ START = 0x08,
+ RIGHT = 0x10,
+ LEFT = 0x20,
+ UP = 0x40,
+ DOWN = 0x80
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public new class FrameInfo : LibWaterboxCore.FrameInfo
+ {
+ public long Time;
+ public Buttons Keys;
+ }
+
+ [BizImport(CC)]
+ public abstract bool Init(bool cgb, byte[] spc, int spclen);
+
+ [BizImport(CC)]
+ public abstract void GetGpuMemory(IntPtr[] ptrs);
+
+ [BizImport(CC)]
+ public abstract void SetScanlineCallback(ScanlineCallback callback, int ly);
+
+ [BizImport(CC)]
+ public abstract byte GetIoReg(byte port);
+
+ [BizImport(CC)]
+ public abstract void PutSaveRam();
+
+ [BizImport(CC)]
+ public abstract void GetSaveRam();
+
+ [BizImport(CC)]
+ public abstract bool HasSaveRam();
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Pizza.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Pizza.cs
index 52b966647b..90fecb3b99 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Pizza.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Pizza.cs
@@ -13,7 +13,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
{
[Core("Pizza Boy", "Davide Berra", true, true, "c7bc6ee376028b3766de8d7a02e60ab794841f45",
"https://github.com/davideberra/emu-pizza/", false)]
- public class Pizza : WaterboxCore, IGameboyCommon
+ public class Pizza : WaterboxCore
{
private LibPizza _pizza;
private readonly bool _sgb;
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Sameboy.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Sameboy.cs
new file mode 100644
index 0000000000..c9d5269710
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Sameboy.cs
@@ -0,0 +1,298 @@
+using BizHawk.Common;
+using BizHawk.Emulation.Common;
+using BizHawk.Emulation.Cores.Properties;
+using BizHawk.Emulation.Cores.Waterbox;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
+{
+ [Core("SameBoy", "LIJI32", true, false, "efc11783c7fb6da66e1dd084e41ba6a85c0bd17e",
+ "https://sameboy.github.io/", false)]
+ public class Sameboy : WaterboxCore,
+ IGameboyCommon, ISaveRam,
+ ISettable