snesgfx-support mode7 direct color displays. still need an example of a mode 3 or 4 direct color usage

This commit is contained in:
zeromus 2012-09-24 07:46:54 +00:00
parent 4efea7605d
commit 52edee63d8
7 changed files with 212 additions and 25 deletions

View File

@ -138,7 +138,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
SETINI_HIRES = 31,
SETINI_OVERSCAN = 32,
SETINI_OBJ_INTERLACE = 33,
SETINI_SCREEN_INTERLACE = 34
SETINI_SCREEN_INTERLACE = 34,
//$2130 CGWSEL
CGWSEL_COLORMASK = 40,
CGWSEL_COLORSUBMASK = 41,
CGWSEL_ADDSUBMODE = 42,
CGWSEL_DIRECTCOLOR = 43,
}
public enum SNES_MEMORY : uint

View File

@ -2,6 +2,9 @@
//http://board.zsnes.com/phpBB3/viewtopic.php?f=10&t=13029&start=75 yoshis island offset per tile demos. and other demos of advanced modes
//but we wont worry about offset per tile modes here.
//helpful detailed reg list
//http://wiki.superfamicom.org/snes/show/Registers
using System;
using System.Linq;
using System.Diagnostics;
@ -143,6 +146,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
public bool SETINI_ObjInterlace { private set; get; }
public bool SETINI_ScreenInterlace { private set; get; }
public int CGWSEL_ColorMask { private set; get; }
public int CGWSEL_ColorSubMask { private set; get; }
public int CGWSEL_AddSubMode { private set; get; }
public bool CGWSEL_DirectColor { private set; get; }
public static ScreenInfo GetScreenInfo()
{
var si = new ScreenInfo();
@ -153,6 +161,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
si.SETINI_ObjInterlace = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.SETINI_OBJ_INTERLACE) == 1;
si.SETINI_ScreenInterlace = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.SETINI_SCREEN_INTERLACE) == 1;
si.CGWSEL_ColorMask = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGWSEL_COLORMASK);
si.CGWSEL_ColorSubMask = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGWSEL_COLORSUBMASK);
si.CGWSEL_AddSubMode = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGWSEL_ADDSUBMODE);
si.CGWSEL_DirectColor = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGWSEL_DIRECTCOLOR) == 1;
si.Mode.MODE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG_MODE);
si.BG.BG1.Bpp = ModeBpps[si.Mode.MODE, 0];
si.BG.BG2.Bpp = ModeBpps[si.Mode.MODE, 1];
@ -202,10 +215,28 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
return ScreenInfo.GetScreenInfo();
}
//the same basic color table that libsnes uses to convert from snes 555 to rgba32
public static int[] colortable = new int[16 * 32768];
static int[] directColorTable = new int[256]; //8bpp gfx -> rgb555
static SNESGraphicsDecoder()
{
//make directColorTable
for (int i = 0; i < 256; i++)
{
int r = i & 7;
int g = (i >> 3) & 7;
int b = (i >> 6) & 3;
r <<= 2;
g <<= 2;
b <<= 3;
int color = (b << 10) | (g << 5) | r;
directColorTable[i] = color;
}
//make colortable
//this is unlikely to change, so maybe we could precompute it to save bootup time.. benchmark it.
//alternatively, we could drag it out of libsneshawk dll
for (int l = 0; l < 16; l++)
{
for (int r = 0; r < 32; r++)
@ -476,7 +507,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
/// <summary>
/// renders the mode7 tiles to a screen with the predefined size.
/// </summary>
public void RenderMode7TilesToScreen(int* screen, int stride, bool ext)
public void RenderMode7TilesToScreen(int* screen, int stride, bool ext, bool directColor)
{
int numTiles = 256;
int tilesWide = 16;
@ -488,14 +519,17 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
int dstOfs = (ty * 8) * stride + tx * 8;
int srcOfs = i * 64;
for (int y = 0, p = 0; y < 8; y++)
{
for (int x = 0; x < 8; x++, p++)
{
screen[dstOfs + y * stride + x] = tilebuf[srcOfs + p];
}
}
}
int numPixels = numTiles * 8 * 8;
Paletteize(screen, 0, 0, numPixels);
if (directColor) DirectColorify(screen, numPixels);
else Paletteize(screen, 0, 0, numPixels);
Colorize(screen, 0, numPixels);
}
@ -541,6 +575,13 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
ret[i] = cgram[i] & 0x7FFF;
return ret;
}
public void DirectColorify(int* screen, int numPixels)
{
for (int i = 0; i < numPixels; i++)
screen[i] = directColorTable[screen[i]];
}
} //class SNESGraphicsDecoder

View File

@ -138,6 +138,15 @@
this.label2193813 = new System.Windows.Forms.Label();
this.checkScreenInterlace = new System.Windows.Forms.CheckBox();
this.radioButton6 = new System.Windows.Forms.RadioButton();
this.label22 = new System.Windows.Forms.Label();
this.txtScreenCGWSEL_ColorMask = new System.Windows.Forms.TextBox();
this.txtScreenCGWSEL_ColorSubMask = new System.Windows.Forms.TextBox();
this.label2893719831 = new System.Windows.Forms.Label();
this.txtScreenCGWSEL_MathFixed = new System.Windows.Forms.TextBox();
this.label25 = new System.Windows.Forms.Label();
this.label23 = new System.Windows.Forms.Label();
this.checkScreenCGWSEL_DirectColor = new System.Windows.Forms.CheckBox();
this.label27 = new System.Windows.Forms.Label();
this.paletteViewer = new BizHawk.MultiClient.SNESGraphicsViewer();
this.viewer = new BizHawk.MultiClient.SNESGraphicsViewer();
this.menuStrip1.SuspendLayout();
@ -324,6 +333,15 @@
//
// groupBox2
//
this.groupBox2.Controls.Add(this.label25);
this.groupBox2.Controls.Add(this.txtScreenCGWSEL_MathFixed);
this.groupBox2.Controls.Add(this.label2893719831);
this.groupBox2.Controls.Add(this.txtScreenCGWSEL_ColorSubMask);
this.groupBox2.Controls.Add(this.label23);
this.groupBox2.Controls.Add(this.txtScreenCGWSEL_ColorMask);
this.groupBox2.Controls.Add(this.label22);
this.groupBox2.Controls.Add(this.label27);
this.groupBox2.Controls.Add(this.checkScreenCGWSEL_DirectColor);
this.groupBox2.Controls.Add(this.label2193813);
this.groupBox2.Controls.Add(this.checkScreenInterlace);
this.groupBox2.Controls.Add(this.label123812831);
@ -353,7 +371,7 @@
this.groupBox2.Controls.Add(this.label5);
this.groupBox2.Location = new System.Drawing.Point(0, 0);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(229, 160);
this.groupBox2.Size = new System.Drawing.Size(229, 165);
this.groupBox2.TabIndex = 16;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Screen";
@ -539,7 +557,7 @@
this.groupBox1.Controls.Add(this.txtBG1SizeInTiles);
this.groupBox1.Controls.Add(this.label2);
this.groupBox1.Controls.Add(this.txtBG1SizeBits);
this.groupBox1.Location = new System.Drawing.Point(0, 166);
this.groupBox1.Location = new System.Drawing.Point(0, 168);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(229, 245);
this.groupBox1.TabIndex = 3;
@ -900,7 +918,8 @@
"4bpp tiles",
"8bpp tiles",
"Mode7 tiles",
"Mode7Ext tiles"});
"Mode7Ext tiles",
"Mode7 tiles (DC)"});
this.comboDisplayType.Location = new System.Drawing.Point(6, 8);
this.comboDisplayType.Name = "comboDisplayType";
this.comboDisplayType.Size = new System.Drawing.Size(107, 21);
@ -1237,7 +1256,7 @@
// label20
//
this.label20.AutoSize = true;
this.label20.Location = new System.Drawing.Point(1, 50);
this.label20.Location = new System.Drawing.Point(2, 73);
this.label20.Name = "label20";
this.label20.Size = new System.Drawing.Size(42, 13);
this.label20.TabIndex = 21;
@ -1247,7 +1266,7 @@
//
this.checkScreenExtbg.AutoSize = true;
this.checkScreenExtbg.Enabled = false;
this.checkScreenExtbg.Location = new System.Drawing.Point(10, 66);
this.checkScreenExtbg.Location = new System.Drawing.Point(11, 89);
this.checkScreenExtbg.Name = "checkScreenExtbg";
this.checkScreenExtbg.Size = new System.Drawing.Size(15, 14);
this.checkScreenExtbg.TabIndex = 22;
@ -1256,7 +1275,7 @@
// label21
//
this.label21.AutoSize = true;
this.label21.Location = new System.Drawing.Point(24, 66);
this.label21.Location = new System.Drawing.Point(25, 89);
this.label21.Name = "label21";
this.label21.Size = new System.Drawing.Size(43, 13);
this.label21.TabIndex = 23;
@ -1265,7 +1284,7 @@
// label18391
//
this.label18391.AutoSize = true;
this.label18391.Location = new System.Drawing.Point(24, 80);
this.label18391.Location = new System.Drawing.Point(25, 103);
this.label18391.Name = "label18391";
this.label18391.Size = new System.Drawing.Size(40, 13);
this.label18391.TabIndex = 25;
@ -1275,7 +1294,7 @@
//
this.checkScreenHires.AutoSize = true;
this.checkScreenHires.Enabled = false;
this.checkScreenHires.Location = new System.Drawing.Point(10, 80);
this.checkScreenHires.Location = new System.Drawing.Point(11, 103);
this.checkScreenHires.Name = "checkScreenHires";
this.checkScreenHires.Size = new System.Drawing.Size(15, 14);
this.checkScreenHires.TabIndex = 24;
@ -1284,7 +1303,7 @@
// label198129381279841
//
this.label198129381279841.AutoSize = true;
this.label198129381279841.Location = new System.Drawing.Point(24, 94);
this.label198129381279841.Location = new System.Drawing.Point(25, 117);
this.label198129381279841.Name = "label198129381279841";
this.label198129381279841.Size = new System.Drawing.Size(47, 13);
this.label198129381279841.TabIndex = 27;
@ -1294,7 +1313,7 @@
//
this.checkScreenOverscan.AutoSize = true;
this.checkScreenOverscan.Enabled = false;
this.checkScreenOverscan.Location = new System.Drawing.Point(10, 94);
this.checkScreenOverscan.Location = new System.Drawing.Point(11, 117);
this.checkScreenOverscan.Name = "checkScreenOverscan";
this.checkScreenOverscan.Size = new System.Drawing.Size(15, 14);
this.checkScreenOverscan.TabIndex = 26;
@ -1303,7 +1322,7 @@
// label123812831
//
this.label123812831.AutoSize = true;
this.label123812831.Location = new System.Drawing.Point(24, 107);
this.label123812831.Location = new System.Drawing.Point(25, 130);
this.label123812831.Name = "label123812831";
this.label123812831.Size = new System.Drawing.Size(49, 13);
this.label123812831.TabIndex = 29;
@ -1313,7 +1332,7 @@
//
this.checkScreenObjInterlace.AutoSize = true;
this.checkScreenObjInterlace.Enabled = false;
this.checkScreenObjInterlace.Location = new System.Drawing.Point(10, 107);
this.checkScreenObjInterlace.Location = new System.Drawing.Point(11, 130);
this.checkScreenObjInterlace.Name = "checkScreenObjInterlace";
this.checkScreenObjInterlace.Size = new System.Drawing.Size(15, 14);
this.checkScreenObjInterlace.TabIndex = 28;
@ -1322,7 +1341,7 @@
// label2193813
//
this.label2193813.AutoSize = true;
this.label2193813.Location = new System.Drawing.Point(24, 120);
this.label2193813.Location = new System.Drawing.Point(25, 143);
this.label2193813.Name = "label2193813";
this.label2193813.Size = new System.Drawing.Size(48, 13);
this.label2193813.TabIndex = 31;
@ -1332,7 +1351,7 @@
//
this.checkScreenInterlace.AutoSize = true;
this.checkScreenInterlace.Enabled = false;
this.checkScreenInterlace.Location = new System.Drawing.Point(10, 120);
this.checkScreenInterlace.Location = new System.Drawing.Point(11, 143);
this.checkScreenInterlace.Name = "checkScreenInterlace";
this.checkScreenInterlace.Size = new System.Drawing.Size(15, 14);
this.checkScreenInterlace.TabIndex = 30;
@ -1350,6 +1369,94 @@
this.radioButton6.Text = "Mode7Ext";
this.radioButton6.UseVisualStyleBackColor = true;
//
// label22
//
this.label22.AutoSize = true;
this.label22.Location = new System.Drawing.Point(72, 73);
this.label22.Name = "label22";
this.label22.Size = new System.Drawing.Size(53, 13);
this.label22.TabIndex = 32;
this.label22.Text = "CGWSEL";
//
// txtScreenCGWSEL_ColorMask
//
this.txtScreenCGWSEL_ColorMask.BackColor = System.Drawing.Color.LightGreen;
this.txtScreenCGWSEL_ColorMask.Location = new System.Drawing.Point(75, 86);
this.txtScreenCGWSEL_ColorMask.Multiline = true;
this.txtScreenCGWSEL_ColorMask.Name = "txtScreenCGWSEL_ColorMask";
this.txtScreenCGWSEL_ColorMask.ReadOnly = true;
this.txtScreenCGWSEL_ColorMask.Size = new System.Drawing.Size(15, 17);
this.txtScreenCGWSEL_ColorMask.TabIndex = 39;
this.txtScreenCGWSEL_ColorMask.Text = "00";
//
// txtScreenCGWSEL_ColorSubMask
//
this.txtScreenCGWSEL_ColorSubMask.BackColor = System.Drawing.Color.LightGreen;
this.txtScreenCGWSEL_ColorSubMask.Location = new System.Drawing.Point(75, 104);
this.txtScreenCGWSEL_ColorSubMask.Multiline = true;
this.txtScreenCGWSEL_ColorSubMask.Name = "txtScreenCGWSEL_ColorSubMask";
this.txtScreenCGWSEL_ColorSubMask.ReadOnly = true;
this.txtScreenCGWSEL_ColorSubMask.Size = new System.Drawing.Size(15, 17);
this.txtScreenCGWSEL_ColorSubMask.TabIndex = 41;
this.txtScreenCGWSEL_ColorSubMask.Text = "00";
//
// label2893719831
//
this.label2893719831.AutoSize = true;
this.label2893719831.Location = new System.Drawing.Point(91, 106);
this.label2893719831.Name = "label2893719831";
this.label2893719831.Size = new System.Drawing.Size(76, 13);
this.label2893719831.TabIndex = 42;
this.label2893719831.Text = "ColorSubMask";
//
// txtScreenCGWSEL_MathFixed
//
this.txtScreenCGWSEL_MathFixed.BackColor = System.Drawing.Color.LightGreen;
this.txtScreenCGWSEL_MathFixed.Location = new System.Drawing.Point(75, 123);
this.txtScreenCGWSEL_MathFixed.Multiline = true;
this.txtScreenCGWSEL_MathFixed.Name = "txtScreenCGWSEL_MathFixed";
this.txtScreenCGWSEL_MathFixed.ReadOnly = true;
this.txtScreenCGWSEL_MathFixed.Size = new System.Drawing.Size(15, 17);
this.txtScreenCGWSEL_MathFixed.TabIndex = 43;
this.txtScreenCGWSEL_MathFixed.Text = "00";
//
// label25
//
this.label25.AutoSize = true;
this.label25.Location = new System.Drawing.Point(91, 125);
this.label25.Name = "label25";
this.label25.Size = new System.Drawing.Size(61, 13);
this.label25.TabIndex = 44;
this.label25.Text = "Math/Fixed";
//
// label23
//
this.label23.AutoSize = true;
this.label23.Location = new System.Drawing.Point(91, 88);
this.label23.Name = "label23";
this.label23.Size = new System.Drawing.Size(57, 13);
this.label23.TabIndex = 40;
this.label23.Text = "ColorMask";
//
// checkScreenCGWSEL_DirectColor
//
this.checkScreenCGWSEL_DirectColor.AutoSize = true;
this.checkScreenCGWSEL_DirectColor.Enabled = false;
this.checkScreenCGWSEL_DirectColor.Location = new System.Drawing.Point(76, 142);
this.checkScreenCGWSEL_DirectColor.Name = "checkScreenCGWSEL_DirectColor";
this.checkScreenCGWSEL_DirectColor.Size = new System.Drawing.Size(15, 14);
this.checkScreenCGWSEL_DirectColor.TabIndex = 30;
this.checkScreenCGWSEL_DirectColor.UseVisualStyleBackColor = true;
//
// label27
//
this.label27.AutoSize = true;
this.label27.Location = new System.Drawing.Point(90, 142);
this.label27.Name = "label27";
this.label27.Size = new System.Drawing.Size(59, 13);
this.label27.TabIndex = 31;
this.label27.Text = "DirectColor";
//
// paletteViewer
//
this.paletteViewer.BackColor = System.Drawing.Color.Transparent;
@ -1521,5 +1628,14 @@
private System.Windows.Forms.Label label2193813;
private System.Windows.Forms.CheckBox checkScreenInterlace;
private System.Windows.Forms.RadioButton radioButton6;
private System.Windows.Forms.TextBox txtScreenCGWSEL_ColorMask;
private System.Windows.Forms.Label label22;
private System.Windows.Forms.Label label2893719831;
private System.Windows.Forms.TextBox txtScreenCGWSEL_ColorSubMask;
private System.Windows.Forms.Label label25;
private System.Windows.Forms.TextBox txtScreenCGWSEL_MathFixed;
private System.Windows.Forms.Label label23;
private System.Windows.Forms.Label label27;
private System.Windows.Forms.CheckBox checkScreenCGWSEL_DirectColor;
}
}

View File

@ -130,6 +130,10 @@ namespace BizHawk.MultiClient
checkScreenObjInterlace.Checked = si.SETINI_ObjInterlace;
checkScreenInterlace.Checked = si.SETINI_ScreenInterlace;
txtScreenCGWSEL_ColorMask.Text = si.CGWSEL_ColorMask.ToString();
txtScreenCGWSEL_ColorSubMask.Text = si.CGWSEL_ColorSubMask.ToString();
txtScreenCGWSEL_MathFixed.Text = si.CGWSEL_AddSubMode.ToString();
checkScreenCGWSEL_DirectColor.Checked = si.CGWSEL_DirectColor;
txtModeBits.Text = si.Mode.MODE.ToString();
txtScreenBG1Bpp.Text = FormatBpp(si.BG.BG1.Bpp);
@ -151,6 +155,7 @@ namespace BizHawk.MultiClient
txtBG1SCAddrBits.Text = si.BG[bgnum].SCADDR.ToString();
txtBG1SCAddrDescr.Text = FormatVramAddress(si.BG[bgnum].SCADDR << 9);
txtBG1Colors.Text = (1 << si.BG[bgnum].Bpp).ToString();
if (si.BG[bgnum].Bpp == 8 && si.CGWSEL_DirectColor) txtBG1Colors.Text = "(Direct Color)";
txtBG1TDAddrBits.Text = si.BG[bgnum].TDADDR.ToString();
txtBG1TDAddrDescr.Text = FormatVramAddress(si.BG[bgnum].TDADDR << 13);
@ -202,13 +207,19 @@ namespace BizHawk.MultiClient
{
//256 tiles
allocate(128, 128);
gd.RenderMode7TilesToScreen(pixelptr, stride / 4, false);
gd.RenderMode7TilesToScreen(pixelptr, stride / 4, false, false);
}
if (selection == "Mode7Ext tiles")
{
//256 tiles
allocate(128, 128);
gd.RenderMode7TilesToScreen(pixelptr, stride / 4, true);
gd.RenderMode7TilesToScreen(pixelptr, stride / 4, true, false);
}
if (selection == "Mode7 tiles (DC)")
{
//256 tiles
allocate(128, 128);
gd.RenderMode7TilesToScreen(pixelptr, stride / 4, false, true);
}
if (selection == "BG1" || selection == "BG2" || selection == "BG3" || selection == "BG4")
{
@ -219,6 +230,9 @@ namespace BizHawk.MultiClient
bool handled = false;
if (bg.Enabled)
{
//TODO - directColor in normal BG renderer
bool DirectColor = si.CGWSEL_DirectColor && bg.Bpp == 8; //any exceptions?
int numPixels = 0;
if (si.Mode.MODE == 7)
{
bool mode7 = bgnum == 1;
@ -228,9 +242,9 @@ namespace BizHawk.MultiClient
handled = true;
allocate(1024, 1024);
gd.DecodeMode7BG(pixelptr, stride / 4, mode7extbg);
int numPixels = 128 * 128 * 8 * 8;
gd.Paletteize(pixelptr, 0, 0, numPixels);
gd.Colorize(pixelptr, 0, numPixels);
numPixels = 128 * 128 * 8 * 8;
if (DirectColor) gd.DirectColorify(pixelptr, numPixels);
else gd.Paletteize(pixelptr, 0, 0, numPixels);
}
}
else
@ -239,15 +253,16 @@ namespace BizHawk.MultiClient
var dims = bg.ScreenSizeInPixels;
dims.Height = dims.Width = Math.Max(dims.Width, dims.Height);
allocate(dims.Width, dims.Height);
int numPixels = dims.Width * dims.Height;
numPixels = dims.Width * dims.Height;
System.Diagnostics.Debug.Assert(stride / 4 == dims.Width);
var map = gd.FetchTilemap(bg.ScreenAddr, bg.ScreenSize);
int paletteStart = 0;
gd.DecodeBG(pixelptr, stride / 4, map, bg.TiledataAddr, bg.ScreenSize, bg.Bpp, bg.TileSize, paletteStart);
gd.Paletteize(pixelptr, 0, 0, numPixels);
gd.Colorize(pixelptr, 0, numPixels);
}
gd.Colorize(pixelptr, 0, numPixels);
}
}

View File

@ -310,12 +310,17 @@ int snes_peek_logical_register(int reg)
//$210C
case SNES_REG_BG3_TDADDR: return SNES::ppu.regs.bg_tdaddr[SNES::PPU::BG3]>>13;
case SNES_REG_BG4_TDADDR: return SNES::ppu.regs.bg_tdaddr[SNES::PPU::BG4]>>13;
//$2133 SETINI
case SNES_REG_SETINI_MODE7_EXTBG: return SNES::ppu.regs.mode7_extbg?1:0;
case SNES_REG_SETINI_HIRES: return SNES::ppu.regs.pseudo_hires?1:0;
case SNES_REG_SETINI_OVERSCAN: return SNES::ppu.regs.overscan?1:0;
case SNES_REG_SETINI_OBJ_INTERLACE: return SNES::ppu.regs.oam_interlace?1:0;
case SNES_REG_SETINI_SCREEN_INTERLACE: return SNES::ppu.regs.interlace?1:0;
//$2130 CGWSEL
case SNES_REG_CGWSEL_COLORMASK: return SNES::ppu.regs.color_mask;
case SNES_REG_CGWSEL_COLORSUBMASK: return SNES::ppu.regs.color_mask;
case SNES_REG_CGWSEL_ADDSUBMODE: return SNES::ppu.regs.addsub_mode?1:0;
case SNES_REG_CGWSEL_DIRECTCOLOR: return SNES::ppu.regs.direct_color?1:0;
}
return 0;
}

View File

@ -167,6 +167,11 @@ void snes_set_scanlineStart(snes_scanlineStart_t);
#define SNES_REG_SETINI_OVERSCAN 32
#define SNES_REG_SETINI_OBJ_INTERLACE 33
#define SNES_REG_SETINI_SCREEN_INTERLACE 34
//$2130 CGWSEL
#define SNES_REG_CGWSEL_COLORMASK 40
#define SNES_REG_CGWSEL_COLORSUBMASK 41
#define SNES_REG_CGWSEL_ADDSUBMODE 42
#define SNES_REG_CGWSEL_DIRECTCOLOR 43
int snes_peek_logical_register(int reg);