Implement bsnes version 115 as a new core (#2740)
* Slam all this shit in here i don't care
* no lzma pls
* un-hack things that i hacked earlier (closer to bsnes source now)
* remove more unused files
* remove more files
* get some stuff working on this weird ass branch
* do this to get actual video (holy shit it works) while palette is incorrect
* make video look correct and hopefully fix stack waterbox allocation size uh ?
* Move the new bsnes core to its own dir as a new core and get input working
* remove leftover files from old bsnes
* fix some shit for now
* make lag frame detection work
* Improve cartridge loading to hopefully make sgb work (haven't tested)
- also changes some audio buffer stuff, might be better or worse than before idk
- need to figure out the saveram stuff
- path requests might actually completely fail atm, no idea how to verify that
* refactor to use a switch instead of some weird array with function pointers
- and implement snes_get_mapper, might be helpful or smth idk
* implement entropy c++-side and delete all this useless code holy
* delete dumb unnecessary code
* implement snes_peek_logical_register c++-side
* normalize all indentation
* attempt to properly support sharprtc and epsonrtc data loading and writing
* Duplicate winforms code to add entropy support c#-side and implement layer_enable functionality
The duplicated code is just so i can have a proper window for the new bsnes core. I do not like duplicating code like this, so this should be improved if possible
* Checkpoint for the start of getting rid of the ugly api wrapper stuff
* Next checkpoint for a full api refactor
* bullshit denied
just no.
every file is either copied or manually edited or written from scratch etc.
do not. force. one indent_style on every single file.
It just does not work.
* remove the entire eMessage_CMD handling and convert to native function calls
* general improvements regarding functionality
- adds hotfixes and fast_ppu core options
- add back the alwaysDoubleSize setting
- use bsnes's own serialize function for savestating now
- generate and use the color palette only in c# cause it doesn't need to be on the c++-side
- and more cleanup like always
* somewhat implement IMemoryDomains
* Implement trace logger and cleanup more unused stuff
* Implement ISaveRam, fix controller mapping for TAStudio and remove the pwrap stuff
* Fix ISaveRam, add a controller configuration box for the new core, (hopefully) fix controller inputs
- also differentiates BG prio0 and prio1 now (with options for it)
- some minor irrelevant edits in bsnes source
* Cleanup some more and optimize a bit
* Support firmware loading and make sgb work (hopefully)
* Remove all unused files
* Add back CropSGBFrame option and cleanup snes_video_refresh logic
* Some hopefully sensible changes
* One more cleanup pass
* Change to new PortedCore attribute
necessary after the changes in 98b07c42d5
Co-authored-by: nattthebear <goyuken@gmail.com>
This commit is contained in:
parent
68ba190c2f
commit
5d20862f26
|
@ -2,6 +2,7 @@
|
|||
/snes9xgit
|
||||
|
||||
**/.vs/**
|
||||
**/.vscode/
|
||||
**/bin/**
|
||||
**/obj/**
|
||||
/output/**
|
||||
|
|
|
@ -5,6 +5,7 @@ using System.ComponentModel;
|
|||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES;
|
||||
using BizHawk.Emulation.Cores.Consoles.Sega.gpgx;
|
||||
using BizHawk.Emulation.Cores.Nintendo.BSNES;
|
||||
using BizHawk.Emulation.Cores.Nintendo.NES;
|
||||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
||||
using BizHawk.Emulation.Cores.PCEngine;
|
||||
|
@ -214,7 +215,7 @@ namespace BizHawk.Client.Common
|
|||
public void SetRenderPlanes(params bool[] args)
|
||||
{
|
||||
static bool GetSetting(bool[] settings, int index) => index >= settings.Length || settings[index];
|
||||
void SetBsnes(LibsnesCore core)
|
||||
void SetLibsnes(LibsnesCore core)
|
||||
{
|
||||
var s = core.GetSettings();
|
||||
s.ShowBG1_0 = s.ShowBG1_1 = GetSetting(args, 0);
|
||||
|
@ -227,6 +228,20 @@ namespace BizHawk.Client.Common
|
|||
s.ShowOBJ_3 = GetSetting(args, 7);
|
||||
core.PutSettings(s);
|
||||
}
|
||||
void SetBsnes(BsnesCore core)
|
||||
{
|
||||
var s = core.GetSettings();
|
||||
// TODO: This should probably support both prios inidividually but I have no idea whether changing this breaks anything
|
||||
s.ShowBG1_0 = s.ShowBG1_1 = GetSetting(args, 0);
|
||||
s.ShowBG2_0 = s.ShowBG2_1 = GetSetting(args, 1);
|
||||
s.ShowBG3_0 = s.ShowBG3_1 = GetSetting(args, 2);
|
||||
s.ShowBG4_0 = s.ShowBG4_1 = GetSetting(args, 3);
|
||||
s.ShowOBJ_0 = GetSetting(args, 4);
|
||||
s.ShowOBJ_1 = GetSetting(args, 5);
|
||||
s.ShowOBJ_2 = GetSetting(args, 6);
|
||||
s.ShowOBJ_3 = GetSetting(args, 7);
|
||||
core.PutSettings(s);
|
||||
}
|
||||
void SetCygne(WonderSwan ws)
|
||||
{
|
||||
var s = ws.GetSettings();
|
||||
|
@ -286,7 +301,10 @@ namespace BizHawk.Client.Common
|
|||
SetGPGX(gpgx);
|
||||
break;
|
||||
case LibsnesCore snes:
|
||||
SetBsnes(snes);
|
||||
SetLibsnes(snes);
|
||||
break;
|
||||
case BsnesCore bsnes:
|
||||
SetBsnes(bsnes);
|
||||
break;
|
||||
case NES nes:
|
||||
SetNesHawk(nes);
|
||||
|
|
|
@ -22,9 +22,9 @@ namespace BizHawk.Client.Common
|
|||
(new[] { "NES" },
|
||||
new[] { CoreNames.QuickNes, CoreNames.NesHawk, CoreNames.SubNesHawk }),
|
||||
(new[] { "SNES" },
|
||||
new[] { CoreNames.Faust, CoreNames.Snes9X, CoreNames.Bsnes }),
|
||||
new[] { CoreNames.Faust, CoreNames.Snes9X, CoreNames.Bsnes, CoreNames.Bsnes115 }),
|
||||
(new[] { "SGB" },
|
||||
new[] { CoreNames.SameBoy, CoreNames.Bsnes }),
|
||||
new[] { CoreNames.SameBoy, CoreNames.Bsnes, CoreNames.Bsnes115}),
|
||||
(new[] { "GB", "GBC" },
|
||||
new[] { CoreNames.Gambatte, CoreNames.GbHawk, CoreNames.SubGbHawk }),
|
||||
(new[] { "DGB" },
|
||||
|
@ -208,7 +208,7 @@ namespace BizHawk.Client.Common
|
|||
public int AlertMessageColor { get; set; } = DefaultMessagePositions.AlertMessageColor;
|
||||
public int LastInputColor { get; set; } = DefaultMessagePositions.LastInputColor;
|
||||
public int MovieInput { get; set; } = DefaultMessagePositions.MovieInput;
|
||||
|
||||
|
||||
public int DispPrescale { get; set; } = 1;
|
||||
|
||||
private static bool DetectDirectX()
|
||||
|
@ -347,4 +347,4 @@ namespace BizHawk.Client.Common
|
|||
|
||||
public bool UseStaticWindowTitles { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ using BizHawk.Emulation.Cores.Computers.SinclairSpectrum;
|
|||
using BizHawk.Emulation.Cores.Consoles.Nintendo.NDS;
|
||||
using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES;
|
||||
using BizHawk.Emulation.Cores.Intellivision;
|
||||
using BizHawk.Emulation.Cores.Nintendo.BSNES;
|
||||
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
|
||||
using BizHawk.Emulation.Cores.Nintendo.N64;
|
||||
using BizHawk.Emulation.Cores.Nintendo.NES;
|
||||
|
@ -1472,7 +1473,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
using var dlg = new NESSyncSettingsForm(this, sub.GetSyncSettings().Clone(), sub.HasMapperProperties);
|
||||
dlg.ShowDialog(this);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void BarcodeReaderMenuItem_Click(object sender, EventArgs e)
|
||||
|
@ -1656,6 +1657,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
using var form = new SNESControllerSettings(this, bsnes.GetSyncSettings().Clone());
|
||||
form.ShowDialog();
|
||||
}
|
||||
else if (Emulator is BsnesCore bsnesCore)
|
||||
{
|
||||
using var form = new BSNESControllerSettings(this, bsnesCore.GetSyncSettings().Clone());
|
||||
form.ShowDialog();
|
||||
}
|
||||
}
|
||||
|
||||
private void SnesGfxDebuggerMenuItem_Click(object sender, EventArgs e)
|
||||
|
@ -1665,9 +1671,13 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private void SnesOptionsMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (Emulator is LibsnesCore bsnes)
|
||||
if (Emulator is LibsnesCore libsnes)
|
||||
{
|
||||
SNESOptions.DoSettingsDialog(this, bsnes);
|
||||
SNESOptions.DoSettingsDialog(this, libsnes);
|
||||
}
|
||||
if (Emulator is BsnesCore bsnes)
|
||||
{
|
||||
BSNESOptions.DoSettingsDialog(this, bsnes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2144,7 +2154,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
using var form = new AmstradCpcNonSyncSettings(this, cpc.GetSettings().Clone());
|
||||
form.ShowDialog();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void HelpSubMenu_DropDownOpened(object sender, EventArgs e)
|
||||
|
|
|
@ -22,6 +22,7 @@ using BizHawk.Bizware.BizwareGL;
|
|||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores;
|
||||
using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES;
|
||||
using BizHawk.Emulation.Cores.Nintendo.BSNES;
|
||||
using BizHawk.Emulation.Cores.Nintendo.GBA;
|
||||
using BizHawk.Emulation.Cores.Nintendo.NES;
|
||||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
||||
|
@ -138,7 +139,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
tuple.Item1 == requestedExtToolDll
|
||||
|| Path.GetFileName(tuple.Item1) == requestedExtToolDll
|
||||
|| Path.GetFileNameWithoutExtension(tuple.Item1) == requestedExtToolDll);
|
||||
|
||||
|
||||
if(foundIndex != -1)
|
||||
loaded = Tools.LoadExternalToolForm(enabled[foundIndex].Item1, enabled[foundIndex].Item2, skipExtToolWarning: true);
|
||||
}
|
||||
|
@ -672,7 +673,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
_needsFullscreenOnLoad = false;
|
||||
ToggleFullscreen();
|
||||
}
|
||||
|
||||
|
||||
// Simply exit the program if the version is asked for
|
||||
if (_argParser.printVersion)
|
||||
{
|
||||
|
@ -1425,53 +1426,80 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private void SNES_ToggleBg(int layer)
|
||||
{
|
||||
if (!(Emulator is LibsnesCore || Emulator is Snes9x) || !1.RangeTo(4).Contains(layer))
|
||||
if (Emulator is not (BsnesCore or LibsnesCore or Snes9x) || !1.RangeTo(4).Contains(layer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
if (Emulator is LibsnesCore bsnes)
|
||||
switch (Emulator)
|
||||
{
|
||||
var s = bsnes.GetSettings();
|
||||
switch (layer)
|
||||
case BsnesCore bsnes:
|
||||
{
|
||||
case 1:
|
||||
result = s.ShowBG1_0 = s.ShowBG1_1 ^= true;
|
||||
break;
|
||||
case 2:
|
||||
result = s.ShowBG2_0 = s.ShowBG2_1 ^= true;
|
||||
break;
|
||||
case 3:
|
||||
result = s.ShowBG3_0 = s.ShowBG3_1 ^= true;
|
||||
break;
|
||||
case 4:
|
||||
result = s.ShowBG4_0 = s.ShowBG4_1 ^= true;
|
||||
break;
|
||||
}
|
||||
var s = bsnes.GetSettings();
|
||||
switch (layer)
|
||||
{
|
||||
case 1:
|
||||
result = s.ShowBG1_0 = s.ShowBG1_1 ^= true;
|
||||
break;
|
||||
case 2:
|
||||
result = s.ShowBG2_0 = s.ShowBG2_1 ^= true;
|
||||
break;
|
||||
case 3:
|
||||
result = s.ShowBG3_0 = s.ShowBG3_1 ^= true;
|
||||
break;
|
||||
case 4:
|
||||
result = s.ShowBG4_0 = s.ShowBG4_1 ^= true;
|
||||
break;
|
||||
}
|
||||
|
||||
bsnes.PutSettings(s);
|
||||
}
|
||||
else if (Emulator is Snes9x snes9X)
|
||||
{
|
||||
var s = snes9X.GetSettings();
|
||||
switch (layer)
|
||||
bsnes.PutSettings(s);
|
||||
break;
|
||||
}
|
||||
case LibsnesCore libsnes:
|
||||
{
|
||||
case 1:
|
||||
result = s.ShowBg0 ^= true;
|
||||
break;
|
||||
case 2:
|
||||
result = s.ShowBg1 ^= true;
|
||||
break;
|
||||
case 3:
|
||||
result = s.ShowBg2 ^= true;
|
||||
break;
|
||||
case 4:
|
||||
result = s.ShowBg3 ^= true;
|
||||
break;
|
||||
}
|
||||
var s = libsnes.GetSettings();
|
||||
switch (layer)
|
||||
{
|
||||
case 1:
|
||||
result = s.ShowBG1_0 = s.ShowBG1_1 ^= true;
|
||||
break;
|
||||
case 2:
|
||||
result = s.ShowBG2_0 = s.ShowBG2_1 ^= true;
|
||||
break;
|
||||
case 3:
|
||||
result = s.ShowBG3_0 = s.ShowBG3_1 ^= true;
|
||||
break;
|
||||
case 4:
|
||||
result = s.ShowBG4_0 = s.ShowBG4_1 ^= true;
|
||||
break;
|
||||
}
|
||||
|
||||
snes9X.PutSettings(s);
|
||||
libsnes.PutSettings(s);
|
||||
break;
|
||||
}
|
||||
case Snes9x snes9X:
|
||||
{
|
||||
var s = snes9X.GetSettings();
|
||||
switch (layer)
|
||||
{
|
||||
case 1:
|
||||
result = s.ShowBg0 ^= true;
|
||||
break;
|
||||
case 2:
|
||||
result = s.ShowBg1 ^= true;
|
||||
break;
|
||||
case 3:
|
||||
result = s.ShowBg2 ^= true;
|
||||
break;
|
||||
case 4:
|
||||
result = s.ShowBg3 ^= true;
|
||||
break;
|
||||
}
|
||||
|
||||
snes9X.PutSettings(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AddOnScreenMessage($"BG {layer} Layer {(result ? "On" : "Off")}");
|
||||
|
@ -1982,6 +2010,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
SNESSubMenu.Text = "&SNES";
|
||||
SNESSubMenu.Visible = true;
|
||||
break;
|
||||
case "SNES" when Emulator is BsnesCore bsnesCore:
|
||||
SNESSubMenu.Text = bsnesCore.IsSGB ? "&SGB" : "&SNES";
|
||||
SNESSubMenu.DropDownItems[2].Visible = false;
|
||||
SNESSubMenu.Visible = true;
|
||||
break;
|
||||
default:
|
||||
DisplayDefaultCoreMenu();
|
||||
break;
|
||||
|
@ -2637,7 +2670,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
if (Config.ClockThrottle)
|
||||
return true;
|
||||
|
||||
|
||||
AddOnScreenMessage("Unable to change speed, please switch to clock throttle");
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
using System;
|
||||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
partial class BSNESControllerSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.OkBtn = new System.Windows.Forms.Button();
|
||||
this.CancelBtn = new System.Windows.Forms.Button();
|
||||
this.Port2ComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.Port1ComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.LimitAnalogChangeCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.MouseNagLabel1 = new BizHawk.WinForms.Controls.LocLabelEx();
|
||||
this.MouseSpeedLabel1 = new BizHawk.WinForms.Controls.LocLabelEx();
|
||||
this.label5 = new BizHawk.WinForms.Controls.LocLabelEx();
|
||||
this.label4 = new BizHawk.WinForms.Controls.LocLabelEx();
|
||||
this.label1 = new BizHawk.WinForms.Controls.LocLabelEx();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// OkBtn
|
||||
//
|
||||
this.OkBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.OkBtn.Location = new System.Drawing.Point(170, 264);
|
||||
this.OkBtn.Name = "OkBtn";
|
||||
this.OkBtn.Size = new System.Drawing.Size(60, 23);
|
||||
this.OkBtn.TabIndex = 4;
|
||||
this.OkBtn.Text = "&OK";
|
||||
this.OkBtn.UseVisualStyleBackColor = true;
|
||||
this.OkBtn.Click += new System.EventHandler(this.OkBtn_Click);
|
||||
//
|
||||
// CancelBtn
|
||||
//
|
||||
this.CancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.CancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.CancelBtn.Location = new System.Drawing.Point(236, 264);
|
||||
this.CancelBtn.Name = "CancelBtn";
|
||||
this.CancelBtn.Size = new System.Drawing.Size(60, 23);
|
||||
this.CancelBtn.TabIndex = 5;
|
||||
this.CancelBtn.Text = "&Cancel";
|
||||
this.CancelBtn.UseVisualStyleBackColor = true;
|
||||
this.CancelBtn.Click += new System.EventHandler(this.CancelBtn_Click);
|
||||
//
|
||||
// Port2ComboBox
|
||||
//
|
||||
this.Port2ComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.Port2ComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.Port2ComboBox.FormattingEnabled = true;
|
||||
this.Port2ComboBox.Items.AddRange(new object[] {
|
||||
"None",
|
||||
"Gamepad",
|
||||
"Mouse"});
|
||||
this.Port2ComboBox.Location = new System.Drawing.Point(12, 104);
|
||||
this.Port2ComboBox.Name = "Port2ComboBox";
|
||||
this.Port2ComboBox.Size = new System.Drawing.Size(284, 21);
|
||||
this.Port2ComboBox.TabIndex = 20;
|
||||
this.Port2ComboBox.SelectedIndexChanged += new System.EventHandler(this.PortComboBox_SelectedIndexChanged);
|
||||
//
|
||||
// Port1ComboBox
|
||||
//
|
||||
this.Port1ComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.Port1ComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.Port1ComboBox.FormattingEnabled = true;
|
||||
this.Port1ComboBox.Items.AddRange(new object[] {
|
||||
"None",
|
||||
"Gamepad",
|
||||
"Mouse"});
|
||||
this.Port1ComboBox.Location = new System.Drawing.Point(12, 54);
|
||||
this.Port1ComboBox.Name = "Port1ComboBox";
|
||||
this.Port1ComboBox.Size = new System.Drawing.Size(284, 21);
|
||||
this.Port1ComboBox.TabIndex = 19;
|
||||
this.Port1ComboBox.SelectedIndexChanged += new System.EventHandler(this.PortComboBox_SelectedIndexChanged);
|
||||
//
|
||||
// LimitAnalogChangeCheckBox
|
||||
//
|
||||
this.LimitAnalogChangeCheckBox.AutoSize = true;
|
||||
this.LimitAnalogChangeCheckBox.Location = new System.Drawing.Point(15, 175);
|
||||
this.LimitAnalogChangeCheckBox.Name = "LimitAnalogChangeCheckBox";
|
||||
this.LimitAnalogChangeCheckBox.Size = new System.Drawing.Size(173, 17);
|
||||
this.LimitAnalogChangeCheckBox.TabIndex = 24;
|
||||
this.LimitAnalogChangeCheckBox.Text = "Limit Analog Change Sensitivity";
|
||||
this.LimitAnalogChangeCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// MouseNagLabel1
|
||||
//
|
||||
this.MouseNagLabel1.Location = new System.Drawing.Point(12, 135);
|
||||
this.MouseNagLabel1.MaximumSize = new System.Drawing.Size(300, 0);
|
||||
this.MouseNagLabel1.Name = "MouseNagLabel1";
|
||||
this.MouseNagLabel1.Text = "*Note: mouse and scope controls should be bound to an analog stick, not the mouse" +
|
||||
".";
|
||||
//
|
||||
// MouseSpeedLabel1
|
||||
//
|
||||
this.MouseSpeedLabel1.Location = new System.Drawing.Point(12, 195);
|
||||
this.MouseSpeedLabel1.MaximumSize = new System.Drawing.Size(300, 0);
|
||||
this.MouseSpeedLabel1.Name = "MouseSpeedLabel1";
|
||||
this.MouseSpeedLabel1.Text = "For casual play this should be checked.\nThe full range of values are rather unusa" +
|
||||
"ble in normal situations, but good if you need total control";
|
||||
//
|
||||
// label5
|
||||
//
|
||||
this.label5.Location = new System.Drawing.Point(12, 88);
|
||||
this.label5.Name = "label5";
|
||||
this.label5.Text = "Port 2:";
|
||||
//
|
||||
// label4
|
||||
//
|
||||
this.label4.Location = new System.Drawing.Point(12, 38);
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Text = "Port 1:";
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.Location = new System.Drawing.Point(12, 9);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Text = "SNES Controller Settings";
|
||||
//
|
||||
// BSNESControllerSettings
|
||||
//
|
||||
this.AcceptButton = this.OkBtn;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.CancelBtn;
|
||||
this.ClientSize = new System.Drawing.Size(308, 299);
|
||||
this.Controls.Add(this.MouseNagLabel1);
|
||||
this.Controls.Add(this.LimitAnalogChangeCheckBox);
|
||||
this.Controls.Add(this.MouseSpeedLabel1);
|
||||
this.Controls.Add(this.label5);
|
||||
this.Controls.Add(this.label4);
|
||||
this.Controls.Add(this.Port2ComboBox);
|
||||
this.Controls.Add(this.Port1ComboBox);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.CancelBtn);
|
||||
this.Controls.Add(this.OkBtn);
|
||||
this.Name = "BSNESControllerSettings";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Controller Settings";
|
||||
this.Load += new System.EventHandler(this.SNESControllerSettings_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button OkBtn;
|
||||
private System.Windows.Forms.Button CancelBtn;
|
||||
private BizHawk.WinForms.Controls.LocLabelEx label1;
|
||||
private BizHawk.WinForms.Controls.LocLabelEx label5;
|
||||
private BizHawk.WinForms.Controls.LocLabelEx label4;
|
||||
private System.Windows.Forms.ComboBox Port2ComboBox;
|
||||
private System.Windows.Forms.ComboBox Port1ComboBox;
|
||||
private BizHawk.WinForms.Controls.LocLabelEx MouseSpeedLabel1;
|
||||
private System.Windows.Forms.CheckBox LimitAnalogChangeCheckBox;
|
||||
private BizHawk.WinForms.Controls.LocLabelEx MouseNagLabel1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
using System.Windows.Forms;
|
||||
using BizHawk.Emulation.Cores.Nintendo.BSNES;
|
||||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
public partial class BSNESControllerSettings : Form
|
||||
{
|
||||
private readonly IMainFormForConfig _mainForm;
|
||||
private readonly BsnesCore.SnesSyncSettings _syncSettings;
|
||||
|
||||
public BSNESControllerSettings(
|
||||
IMainFormForConfig mainForm,
|
||||
BsnesCore.SnesSyncSettings syncSettings)
|
||||
{
|
||||
_mainForm = mainForm;
|
||||
_syncSettings = syncSettings;
|
||||
InitializeComponent();
|
||||
Icon = Properties.Resources.GameControllerIcon;
|
||||
}
|
||||
|
||||
private void SNESControllerSettings_Load(object sender, EventArgs e)
|
||||
{
|
||||
LimitAnalogChangeCheckBox.Checked = _syncSettings.LimitAnalogChangeSensitivity;
|
||||
|
||||
Port1ComboBox.SelectedIndex = (int) _syncSettings.LeftPort >= Port1ComboBox.Items.Count ? 0 : (int) _syncSettings.LeftPort;
|
||||
Port2ComboBox.PopulateFromEnum(_syncSettings.RightPort);
|
||||
}
|
||||
|
||||
private void OkBtn_Click(object sender, EventArgs e)
|
||||
{
|
||||
bool changed =
|
||||
_syncSettings.LeftPort != (BsnesApi.BSNES_INPUT_DEVICE) Port1ComboBox.SelectedIndex
|
||||
|| _syncSettings.RightPort != (BsnesApi.BSNES_INPUT_DEVICE) Port2ComboBox.SelectedIndex
|
||||
|| _syncSettings.LimitAnalogChangeSensitivity != LimitAnalogChangeCheckBox.Checked;
|
||||
|
||||
if (changed)
|
||||
{
|
||||
_syncSettings.LeftPort = (BsnesApi.BSNES_INPUT_DEVICE) Port1ComboBox.SelectedIndex;
|
||||
_syncSettings.RightPort = (BsnesApi.BSNES_INPUT_DEVICE) Port2ComboBox.SelectedIndex;
|
||||
_syncSettings.LimitAnalogChangeSensitivity = LimitAnalogChangeCheckBox.Checked;
|
||||
|
||||
_mainForm.PutCoreSyncSettings(_syncSettings);
|
||||
}
|
||||
|
||||
DialogResult = DialogResult.OK;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void CancelBtn_Click(object sender, EventArgs e)
|
||||
{
|
||||
_mainForm.AddOnScreenMessage("Controller settings aborted");
|
||||
DialogResult = DialogResult.Cancel;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void PortComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
var leftPort = (BsnesApi.BSNES_INPUT_DEVICE) Port1ComboBox.SelectedIndex;
|
||||
var rightPort = (BsnesApi.BSNES_INPUT_DEVICE) Port2ComboBox.SelectedIndex;
|
||||
ToggleMouseSection(leftPort == BsnesApi.BSNES_INPUT_DEVICE.Mouse || rightPort == BsnesApi.BSNES_INPUT_DEVICE.Mouse);
|
||||
}
|
||||
|
||||
private void ToggleMouseSection(bool show)
|
||||
{
|
||||
LimitAnalogChangeCheckBox.Visible =
|
||||
MouseSpeedLabel1.Visible =
|
||||
MouseNagLabel1.Visible =
|
||||
show;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
|
@ -0,0 +1,367 @@
|
|||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
partial class BSNESOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.btnOk = new System.Windows.Forms.Button();
|
||||
this.btnCancel = new System.Windows.Forms.Button();
|
||||
this.cbDoubleSize = new System.Windows.Forms.CheckBox();
|
||||
this.lblDoubleSize = new BizHawk.WinForms.Controls.LocLabelEx();
|
||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
this.lblPriority1 = new BizHawk.WinForms.Controls.LocLabelEx();
|
||||
this.lblPriority0 = new BizHawk.WinForms.Controls.LocLabelEx();
|
||||
this.Bg4_0Checkbox = new System.Windows.Forms.CheckBox();
|
||||
this.Bg3_0Checkbox = new System.Windows.Forms.CheckBox();
|
||||
this.Bg2_0Checkbox = new System.Windows.Forms.CheckBox();
|
||||
this.Bg1_0Checkbox = new System.Windows.Forms.CheckBox();
|
||||
this.Bg4_1Checkbox = new System.Windows.Forms.CheckBox();
|
||||
this.Bg3_1Checkbox = new System.Windows.Forms.CheckBox();
|
||||
this.Bg2_1Checkbox = new System.Windows.Forms.CheckBox();
|
||||
this.Bg1_1Checkbox = new System.Windows.Forms.CheckBox();
|
||||
this.Obj4Checkbox = new System.Windows.Forms.CheckBox();
|
||||
this.Obj3Checkbox = new System.Windows.Forms.CheckBox();
|
||||
this.Obj2Checkbox = new System.Windows.Forms.CheckBox();
|
||||
this.Obj1Checkbox = new System.Windows.Forms.CheckBox();
|
||||
this.EntropyBox = new System.Windows.Forms.ComboBox();
|
||||
this.lblEntropy = new BizHawk.WinForms.Controls.LocLabelEx();
|
||||
this.cbGameHotfixes = new System.Windows.Forms.CheckBox();
|
||||
this.cbFastPPU = new System.Windows.Forms.CheckBox();
|
||||
this.cbCropSGBFrame = new System.Windows.Forms.CheckBox();
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// btnOk
|
||||
//
|
||||
this.btnOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnOk.Location = new System.Drawing.Point(136, 303);
|
||||
this.btnOk.Name = "btnOk";
|
||||
this.btnOk.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnOk.TabIndex = 0;
|
||||
this.btnOk.Text = "OK";
|
||||
this.btnOk.UseVisualStyleBackColor = true;
|
||||
this.btnOk.Click += new System.EventHandler(this.BtnOk_Click);
|
||||
//
|
||||
// btnCancel
|
||||
//
|
||||
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.btnCancel.Location = new System.Drawing.Point(217, 303);
|
||||
this.btnCancel.Name = "btnCancel";
|
||||
this.btnCancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnCancel.TabIndex = 1;
|
||||
this.btnCancel.Text = "Cancel";
|
||||
this.btnCancel.UseVisualStyleBackColor = true;
|
||||
this.btnCancel.Click += new System.EventHandler(this.BtnCancel_Click);
|
||||
//
|
||||
// cbDoubleSize
|
||||
//
|
||||
this.cbDoubleSize.AutoSize = true;
|
||||
this.cbDoubleSize.Location = new System.Drawing.Point(18, 16);
|
||||
this.cbDoubleSize.Name = "cbDoubleSize";
|
||||
this.cbDoubleSize.Size = new System.Drawing.Size(178, 17);
|
||||
this.cbDoubleSize.TabIndex = 6;
|
||||
this.cbDoubleSize.Text = "Always Double-Size Framebuffer";
|
||||
this.cbDoubleSize.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// lblDoubleSize
|
||||
//
|
||||
this.lblDoubleSize.Location = new System.Drawing.Point(33, 34);
|
||||
this.lblDoubleSize.MaximumSize = new System.Drawing.Size(260, 0);
|
||||
this.lblDoubleSize.Name = "lblDoubleSize";
|
||||
this.lblDoubleSize.Text = "Some games are changing the resolution constantly (e.g. SD3) so this option can f" +
|
||||
"orce the SNES output to stay double-size always.";
|
||||
//
|
||||
// groupBox1
|
||||
//
|
||||
this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.groupBox1.Controls.Add(this.lblPriority1);
|
||||
this.groupBox1.Controls.Add(this.lblPriority0);
|
||||
this.groupBox1.Controls.Add(this.Bg4_0Checkbox);
|
||||
this.groupBox1.Controls.Add(this.Bg3_0Checkbox);
|
||||
this.groupBox1.Controls.Add(this.Bg2_0Checkbox);
|
||||
this.groupBox1.Controls.Add(this.Bg1_0Checkbox);
|
||||
this.groupBox1.Controls.Add(this.Bg4_1Checkbox);
|
||||
this.groupBox1.Controls.Add(this.Bg3_1Checkbox);
|
||||
this.groupBox1.Controls.Add(this.Bg2_1Checkbox);
|
||||
this.groupBox1.Controls.Add(this.Bg1_1Checkbox);
|
||||
this.groupBox1.Controls.Add(this.Obj4Checkbox);
|
||||
this.groupBox1.Controls.Add(this.Obj3Checkbox);
|
||||
this.groupBox1.Controls.Add(this.Obj2Checkbox);
|
||||
this.groupBox1.Controls.Add(this.Obj1Checkbox);
|
||||
this.groupBox1.Location = new System.Drawing.Point(18, 165);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(274, 132);
|
||||
this.groupBox1.TabIndex = 11;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "Display";
|
||||
//
|
||||
// lblPriority1
|
||||
//
|
||||
this.lblPriority1.Location = new System.Drawing.Point(220, 14);
|
||||
this.lblPriority1.MaximumSize = new System.Drawing.Size(100, 0);
|
||||
this.lblPriority1.Name = "lblPriority1";
|
||||
this.lblPriority1.Text = "Priority 1";
|
||||
//
|
||||
// lblPriority0
|
||||
//
|
||||
this.lblPriority0.Location = new System.Drawing.Point(162, 14);
|
||||
this.lblPriority0.MaximumSize = new System.Drawing.Size(100, 0);
|
||||
this.lblPriority0.Name = "lblPriority0";
|
||||
this.lblPriority0.Text = "Priority 0";
|
||||
this.lblPriority0.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// Bg4_0Checkbox
|
||||
//
|
||||
this.Bg4_0Checkbox.AutoSize = true;
|
||||
this.Bg4_0Checkbox.CheckAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.Bg4_0Checkbox.Location = new System.Drawing.Point(128, 99);
|
||||
this.Bg4_0Checkbox.Name = "Bg4_0Checkbox";
|
||||
this.Bg4_0Checkbox.Size = new System.Drawing.Size(62, 17);
|
||||
this.Bg4_0Checkbox.TabIndex = 11;
|
||||
this.Bg4_0Checkbox.Text = "BG 4 ";
|
||||
this.Bg4_0Checkbox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// Bg3_0Checkbox
|
||||
//
|
||||
this.Bg3_0Checkbox.AutoSize = true;
|
||||
this.Bg3_0Checkbox.CheckAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.Bg3_0Checkbox.Location = new System.Drawing.Point(128, 76);
|
||||
this.Bg3_0Checkbox.Name = "Bg3_0Checkbox";
|
||||
this.Bg3_0Checkbox.Size = new System.Drawing.Size(62, 17);
|
||||
this.Bg3_0Checkbox.TabIndex = 10;
|
||||
this.Bg3_0Checkbox.Text = "BG 3 ";
|
||||
this.Bg3_0Checkbox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// Bg2_0Checkbox
|
||||
//
|
||||
this.Bg2_0Checkbox.AutoSize = true;
|
||||
this.Bg2_0Checkbox.CheckAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.Bg2_0Checkbox.Location = new System.Drawing.Point(128, 53);
|
||||
this.Bg2_0Checkbox.Name = "Bg2_0Checkbox";
|
||||
this.Bg2_0Checkbox.Size = new System.Drawing.Size(62, 17);
|
||||
this.Bg2_0Checkbox.TabIndex = 9;
|
||||
this.Bg2_0Checkbox.Text = "BG 2 ";
|
||||
this.Bg2_0Checkbox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// Bg1_0Checkbox
|
||||
//
|
||||
this.Bg1_0Checkbox.AutoSize = true;
|
||||
this.Bg1_0Checkbox.CheckAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.Bg1_0Checkbox.Location = new System.Drawing.Point(128, 30);
|
||||
this.Bg1_0Checkbox.Name = "Bg1_0Checkbox";
|
||||
this.Bg1_0Checkbox.Size = new System.Drawing.Size(62, 17);
|
||||
this.Bg1_0Checkbox.TabIndex = 8;
|
||||
this.Bg1_0Checkbox.Text = "BG 1 ";
|
||||
this.Bg1_0Checkbox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// Bg4_1Checkbox
|
||||
//
|
||||
this.Bg4_1Checkbox.AutoSize = true;
|
||||
this.Bg4_1Checkbox.Location = new System.Drawing.Point(234, 100);
|
||||
this.Bg4_1Checkbox.Name = "Bg4_1Checkbox";
|
||||
this.Bg4_1Checkbox.Size = new System.Drawing.Size(15, 14);
|
||||
this.Bg4_1Checkbox.TabIndex = 7;
|
||||
this.Bg4_1Checkbox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// Bg3_1Checkbox
|
||||
//
|
||||
this.Bg3_1Checkbox.AutoSize = true;
|
||||
this.Bg3_1Checkbox.Location = new System.Drawing.Point(234, 77);
|
||||
this.Bg3_1Checkbox.Name = "Bg3_1Checkbox";
|
||||
this.Bg3_1Checkbox.Size = new System.Drawing.Size(15, 14);
|
||||
this.Bg3_1Checkbox.TabIndex = 6;
|
||||
this.Bg3_1Checkbox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// Bg2_1Checkbox
|
||||
//
|
||||
this.Bg2_1Checkbox.AutoSize = true;
|
||||
this.Bg2_1Checkbox.Location = new System.Drawing.Point(234, 54);
|
||||
this.Bg2_1Checkbox.Name = "Bg2_1Checkbox";
|
||||
this.Bg2_1Checkbox.Size = new System.Drawing.Size(15, 14);
|
||||
this.Bg2_1Checkbox.TabIndex = 5;
|
||||
this.Bg2_1Checkbox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// Bg1_1Checkbox
|
||||
//
|
||||
this.Bg1_1Checkbox.AutoSize = true;
|
||||
this.Bg1_1Checkbox.Location = new System.Drawing.Point(234, 31);
|
||||
this.Bg1_1Checkbox.Name = "Bg1_1Checkbox";
|
||||
this.Bg1_1Checkbox.Size = new System.Drawing.Size(15, 14);
|
||||
this.Bg1_1Checkbox.TabIndex = 4;
|
||||
this.Bg1_1Checkbox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// Obj4Checkbox
|
||||
//
|
||||
this.Obj4Checkbox.AutoSize = true;
|
||||
this.Obj4Checkbox.Location = new System.Drawing.Point(21, 99);
|
||||
this.Obj4Checkbox.Name = "Obj4Checkbox";
|
||||
this.Obj4Checkbox.Size = new System.Drawing.Size(55, 17);
|
||||
this.Obj4Checkbox.TabIndex = 3;
|
||||
this.Obj4Checkbox.Text = "OBJ 4";
|
||||
this.Obj4Checkbox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// Obj3Checkbox
|
||||
//
|
||||
this.Obj3Checkbox.AutoSize = true;
|
||||
this.Obj3Checkbox.Location = new System.Drawing.Point(21, 76);
|
||||
this.Obj3Checkbox.Name = "Obj3Checkbox";
|
||||
this.Obj3Checkbox.Size = new System.Drawing.Size(55, 17);
|
||||
this.Obj3Checkbox.TabIndex = 2;
|
||||
this.Obj3Checkbox.Text = "OBJ 3";
|
||||
this.Obj3Checkbox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// Obj2Checkbox
|
||||
//
|
||||
this.Obj2Checkbox.AutoSize = true;
|
||||
this.Obj2Checkbox.Location = new System.Drawing.Point(21, 53);
|
||||
this.Obj2Checkbox.Name = "Obj2Checkbox";
|
||||
this.Obj2Checkbox.Size = new System.Drawing.Size(55, 17);
|
||||
this.Obj2Checkbox.TabIndex = 1;
|
||||
this.Obj2Checkbox.Text = "OBJ 2";
|
||||
this.Obj2Checkbox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// Obj1Checkbox
|
||||
//
|
||||
this.Obj1Checkbox.AutoSize = true;
|
||||
this.Obj1Checkbox.Location = new System.Drawing.Point(21, 30);
|
||||
this.Obj1Checkbox.Name = "Obj1Checkbox";
|
||||
this.Obj1Checkbox.Size = new System.Drawing.Size(55, 17);
|
||||
this.Obj1Checkbox.TabIndex = 0;
|
||||
this.Obj1Checkbox.Text = "OBJ 1";
|
||||
this.Obj1Checkbox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// EntropyBox
|
||||
//
|
||||
this.EntropyBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.EntropyBox.FormattingEnabled = true;
|
||||
this.EntropyBox.Items.AddRange(new object[] {
|
||||
"None",
|
||||
"Low",
|
||||
"High"});
|
||||
this.EntropyBox.Location = new System.Drawing.Point(164, 138);
|
||||
this.EntropyBox.Name = "EntropyBox";
|
||||
this.EntropyBox.Size = new System.Drawing.Size(128, 21);
|
||||
this.EntropyBox.TabIndex = 14;
|
||||
//
|
||||
// lblEntropy
|
||||
//
|
||||
this.lblEntropy.Location = new System.Drawing.Point(249, 117);
|
||||
this.lblEntropy.Name = "lblEntropy";
|
||||
this.lblEntropy.Text = "Entropy";
|
||||
//
|
||||
// cbGameHotfixes
|
||||
//
|
||||
this.cbGameHotfixes.AutoSize = true;
|
||||
this.cbGameHotfixes.Location = new System.Drawing.Point(18, 111);
|
||||
this.cbGameHotfixes.Name = "cbGameHotfixes";
|
||||
this.cbGameHotfixes.Size = new System.Drawing.Size(93, 17);
|
||||
this.cbGameHotfixes.TabIndex = 22;
|
||||
this.cbGameHotfixes.Text = "Game hotfixes";
|
||||
this.cbGameHotfixes.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// cbFastPPU
|
||||
//
|
||||
this.cbFastPPU.AutoSize = true;
|
||||
this.cbFastPPU.Location = new System.Drawing.Point(18, 138);
|
||||
this.cbFastPPU.Name = "cbFastPPU";
|
||||
this.cbFastPPU.Size = new System.Drawing.Size(90, 17);
|
||||
this.cbFastPPU.TabIndex = 23;
|
||||
this.cbFastPPU.Text = "Use fast PPU";
|
||||
this.cbFastPPU.UseVisualStyleBackColor = true;
|
||||
this.cbFastPPU.CheckedChanged += new System.EventHandler(this.FastPPU_CheckedChanged);
|
||||
//
|
||||
// cbCropSGBFrame
|
||||
//
|
||||
this.cbCropSGBFrame.AutoSize = true;
|
||||
this.cbCropSGBFrame.Location = new System.Drawing.Point(18, 84);
|
||||
this.cbCropSGBFrame.Name = "cbCropSGBFrame";
|
||||
this.cbCropSGBFrame.Size = new System.Drawing.Size(105, 17);
|
||||
this.cbCropSGBFrame.TabIndex = 27;
|
||||
this.cbCropSGBFrame.Text = "Crop SGB Frame";
|
||||
this.cbCropSGBFrame.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// BSNESOptions
|
||||
//
|
||||
this.AcceptButton = this.btnOk;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.btnCancel;
|
||||
this.ClientSize = new System.Drawing.Size(304, 338);
|
||||
this.Controls.Add(this.cbCropSGBFrame);
|
||||
this.Controls.Add(this.cbFastPPU);
|
||||
this.Controls.Add(this.cbGameHotfixes);
|
||||
this.Controls.Add(this.lblEntropy);
|
||||
this.Controls.Add(this.EntropyBox);
|
||||
this.Controls.Add(this.groupBox1);
|
||||
this.Controls.Add(this.lblDoubleSize);
|
||||
this.Controls.Add(this.cbDoubleSize);
|
||||
this.Controls.Add(this.btnCancel);
|
||||
this.Controls.Add(this.btnOk);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "BSNESOptions";
|
||||
this.ShowIcon = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "BSNES Options";
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
this.groupBox1.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button btnOk;
|
||||
private System.Windows.Forms.Button btnCancel;
|
||||
private System.Windows.Forms.CheckBox cbDoubleSize;
|
||||
private BizHawk.WinForms.Controls.LocLabelEx lblDoubleSize;
|
||||
private System.Windows.Forms.GroupBox groupBox1;
|
||||
private System.Windows.Forms.CheckBox Bg4_1Checkbox;
|
||||
private System.Windows.Forms.CheckBox Bg3_1Checkbox;
|
||||
private System.Windows.Forms.CheckBox Bg2_1Checkbox;
|
||||
private System.Windows.Forms.CheckBox Bg1_1Checkbox;
|
||||
private System.Windows.Forms.CheckBox Obj4Checkbox;
|
||||
private System.Windows.Forms.CheckBox Obj3Checkbox;
|
||||
private System.Windows.Forms.CheckBox Obj2Checkbox;
|
||||
private System.Windows.Forms.CheckBox Obj1Checkbox;
|
||||
private System.Windows.Forms.ComboBox EntropyBox;
|
||||
private WinForms.Controls.LocLabelEx lblEntropy;
|
||||
private System.Windows.Forms.CheckBox cbGameHotfixes;
|
||||
private System.Windows.Forms.CheckBox cbFastPPU;
|
||||
private System.Windows.Forms.CheckBox Bg1_0Checkbox;
|
||||
private System.Windows.Forms.CheckBox Bg4_0Checkbox;
|
||||
private System.Windows.Forms.CheckBox Bg3_0Checkbox;
|
||||
private System.Windows.Forms.CheckBox Bg2_0Checkbox;
|
||||
private WinForms.Controls.LocLabelEx lblPriority1;
|
||||
private WinForms.Controls.LocLabelEx lblPriority0;
|
||||
private System.Windows.Forms.CheckBox cbCropSGBFrame;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
using System;
|
||||
using System.Windows.Forms;
|
||||
using BizHawk.Emulation.Cores.Nintendo.BSNES;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
public partial class BSNESOptions : Form
|
||||
{
|
||||
private BSNESOptions()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public static void DoSettingsDialog(IMainFormForConfig mainForm, BsnesCore bsnes)
|
||||
{
|
||||
var s = bsnes.GetSettings();
|
||||
var ss = bsnes.GetSyncSettings();
|
||||
using var dlg = new BSNESOptions
|
||||
{
|
||||
AlwaysDoubleSize = s.AlwaysDoubleSize,
|
||||
CropSGBFrame = s.CropSGBFrame,
|
||||
Entropy = ss.Entropy,
|
||||
Hotfixes = ss.Hotfixes,
|
||||
FastPPU = ss.FastPPU,
|
||||
ShowObj1 = s.ShowOBJ_0,
|
||||
ShowObj2 = s.ShowOBJ_1,
|
||||
ShowObj3 = s.ShowOBJ_2,
|
||||
ShowObj4 = s.ShowOBJ_3,
|
||||
ShowBg1_0 = s.ShowBG1_0,
|
||||
ShowBg1_1 = s.ShowBG1_1,
|
||||
ShowBg2_0 = s.ShowBG2_0,
|
||||
ShowBg2_1 = s.ShowBG2_1,
|
||||
ShowBg3_0 = s.ShowBG3_0,
|
||||
ShowBg3_1 = s.ShowBG3_1,
|
||||
ShowBg4_0 = s.ShowBG4_0,
|
||||
ShowBg4_1 = s.ShowBG4_1
|
||||
};
|
||||
|
||||
DialogResult result = mainForm.ShowDialogAsChild(dlg);
|
||||
if (result == DialogResult.OK)
|
||||
{
|
||||
s.AlwaysDoubleSize = dlg.AlwaysDoubleSize;
|
||||
s.CropSGBFrame = dlg.CropSGBFrame;
|
||||
ss.Entropy = dlg.Entropy;
|
||||
ss.Hotfixes = dlg.Hotfixes;
|
||||
ss.FastPPU = dlg.FastPPU;
|
||||
s.ShowOBJ_0 = dlg.ShowObj1;
|
||||
s.ShowOBJ_1 = dlg.ShowObj2;
|
||||
s.ShowOBJ_2 = dlg.ShowObj3;
|
||||
s.ShowOBJ_3 = dlg.ShowObj4;
|
||||
s.ShowBG1_0 = dlg.ShowBg1_0;
|
||||
s.ShowBG1_1 = dlg.ShowBg1_1;
|
||||
s.ShowBG2_0 = dlg.ShowBg2_0;
|
||||
s.ShowBG2_1 = dlg.ShowBg2_1;
|
||||
s.ShowBG3_0 = dlg.ShowBg3_0;
|
||||
s.ShowBG3_1 = dlg.ShowBg3_1;
|
||||
s.ShowBG4_0 = dlg.ShowBg4_0;
|
||||
s.ShowBG4_1 = dlg.ShowBg4_1;
|
||||
|
||||
mainForm.PutCoreSettings(s);
|
||||
mainForm.PutCoreSyncSettings(ss);
|
||||
}
|
||||
}
|
||||
|
||||
private bool AlwaysDoubleSize
|
||||
{
|
||||
get => cbDoubleSize.Checked;
|
||||
init => cbDoubleSize.Checked = value;
|
||||
}
|
||||
|
||||
private bool CropSGBFrame
|
||||
{
|
||||
get => cbCropSGBFrame.Checked;
|
||||
init => cbCropSGBFrame.Checked = value;
|
||||
}
|
||||
|
||||
private bool Hotfixes
|
||||
{
|
||||
get => cbGameHotfixes.Checked;
|
||||
init => cbGameHotfixes.Checked = value;
|
||||
}
|
||||
|
||||
private bool FastPPU
|
||||
{
|
||||
get => cbFastPPU.Checked;
|
||||
init => cbDoubleSize.Enabled = cbFastPPU.Checked = value;
|
||||
}
|
||||
|
||||
private BsnesApi.ENTROPY Entropy
|
||||
{
|
||||
get => (BsnesApi.ENTROPY) EntropyBox.SelectedIndex;
|
||||
init => EntropyBox.SelectedIndex = (int) value;
|
||||
}
|
||||
|
||||
private bool ShowObj1 { get => Obj1Checkbox.Checked; init => Obj1Checkbox.Checked = value; }
|
||||
private bool ShowObj2 { get => Obj2Checkbox.Checked; init => Obj2Checkbox.Checked = value; }
|
||||
private bool ShowObj3 { get => Obj3Checkbox.Checked; init => Obj3Checkbox.Checked = value; }
|
||||
private bool ShowObj4 { get => Obj4Checkbox.Checked; init => Obj4Checkbox.Checked = value; }
|
||||
|
||||
private bool ShowBg1_0 { get => Bg1_0Checkbox.Checked; init => Bg1_0Checkbox.Checked = value; }
|
||||
private bool ShowBg1_1 { get => Bg1_1Checkbox.Checked; init => Bg1_1Checkbox.Checked = value; }
|
||||
private bool ShowBg2_0 { get => Bg2_0Checkbox.Checked; init => Bg2_0Checkbox.Checked = value; }
|
||||
private bool ShowBg2_1 { get => Bg2_1Checkbox.Checked; init => Bg2_1Checkbox.Checked = value; }
|
||||
private bool ShowBg3_0 { get => Bg3_0Checkbox.Checked; init => Bg3_0Checkbox.Checked = value; }
|
||||
private bool ShowBg3_1 { get => Bg3_1Checkbox.Checked; init => Bg3_1Checkbox.Checked = value; }
|
||||
private bool ShowBg4_0 { get => Bg4_0Checkbox.Checked; init => Bg4_0Checkbox.Checked = value; }
|
||||
private bool ShowBg4_1 { get => Bg4_1Checkbox.Checked; init => Bg4_1Checkbox.Checked = value; }
|
||||
|
||||
private void BtnOk_Click(object sender, EventArgs e)
|
||||
{
|
||||
DialogResult = DialogResult.OK;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void BtnCancel_Click(object sender, EventArgs e)
|
||||
{
|
||||
DialogResult = DialogResult.Cancel;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void FastPPU_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
cbDoubleSize.Enabled = cbFastPPU.Checked;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
|
@ -24,7 +24,7 @@
|
|||
ITraceSink Sink { set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether racing is enabled
|
||||
/// Gets a value indicating whether tracing is enabled
|
||||
/// This is defined as equivalent to Sink != null
|
||||
/// It's put here because it's such a common operation to check whether it's enabled, and it's not nice to write Sink != null all over
|
||||
/// </summary>
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Cores.Waterbox;
|
||||
using BizHawk.BizInvoke;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||
{
|
||||
public abstract unsafe class BsnesCoreImpl
|
||||
{
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract void snes_set_audio_enabled(bool enabled);
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract void snes_set_video_enabled(bool enabled);
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract void snes_set_layer_enables(BsnesApi.LayerEnables layerEnables);
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract void snes_set_trace_enabled(bool enabled);
|
||||
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract BsnesApi.SNES_REGION snes_get_region();
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract BsnesApi.SNES_MAPPER snes_get_mapper();
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract void* snes_get_memory_region(int id, out int size, out int wordSize);
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract byte snes_bus_read(uint address);
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract void snes_bus_write(uint address, byte value);
|
||||
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract void snes_set_callbacks(IntPtr[] snesCallbacks);
|
||||
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract void snes_init(BsnesApi.ENTROPY entropy, BsnesApi.BSNES_INPUT_DEVICE left,
|
||||
BsnesApi.BSNES_INPUT_DEVICE right, ushort mergedBools);// bool hotfixes, bool fastPPU);
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract void snes_power();
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract void snes_term();
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract void snes_reset();
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract void snes_run();
|
||||
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract void snes_serialize(byte[] serializedData, int serializedSize);
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract void snes_unserialize(byte[] serializedData, int serializedSize);
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract int snes_serialized_size();
|
||||
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract void snes_load_cartridge_normal(string baseRomPath, byte[] romData, int romSize);
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract void snes_load_cartridge_super_gameboy(string baseRomPath, byte[] romData, byte[] sgbRomData, ulong mergedRomSizes);
|
||||
}
|
||||
|
||||
public unsafe partial class BsnesApi : IDisposable, IMonitor, IStatable
|
||||
{
|
||||
internal WaterboxHost exe;
|
||||
internal BsnesCoreImpl core;
|
||||
private readonly ICallingConventionAdapter _adapter;
|
||||
private bool _disposed;
|
||||
|
||||
public void Enter()
|
||||
{
|
||||
exe.Enter();
|
||||
}
|
||||
|
||||
public void Exit()
|
||||
{
|
||||
exe.Exit();
|
||||
}
|
||||
|
||||
private readonly List<string> _readonlyFiles = new();
|
||||
|
||||
public void AddReadonlyFile(byte[] data, string name)
|
||||
{
|
||||
// current logic potentially requests the same name twice; once for program and once for data
|
||||
// because this gets mapped to the same file, we only add it once
|
||||
if (!_readonlyFiles.Contains(name))
|
||||
{
|
||||
exe.AddReadonlyFile(data, name);
|
||||
_readonlyFiles.Add(name);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetCallbacks(SnesCallbacks callbacks)
|
||||
{
|
||||
FieldInfo[] fieldInfos = typeof(SnesCallbacks).GetFields();
|
||||
IntPtr[] functionPointerArray = new IntPtr[fieldInfos.Length];
|
||||
for (int i = 0; i < fieldInfos.Length; i++)
|
||||
{
|
||||
functionPointerArray[i] = _adapter.GetFunctionPointerForDelegate((Delegate) fieldInfos[i].GetValue(callbacks));
|
||||
}
|
||||
core.snes_set_callbacks(functionPointerArray);
|
||||
}
|
||||
|
||||
public BsnesApi(string dllPath, CoreComm comm, IEnumerable<Delegate> allCallbacks)
|
||||
{
|
||||
exe = new WaterboxHost(new WaterboxOptions
|
||||
{
|
||||
Filename = "bsnes.wbx",
|
||||
Path = dllPath,
|
||||
SbrkHeapSizeKB = 14 * 1024,
|
||||
InvisibleHeapSizeKB = 4,
|
||||
MmapHeapSizeKB = 105 * 1024, // TODO: check whether this needs to be larger; it depends on the rom size
|
||||
PlainHeapSizeKB = 0,
|
||||
SealedHeapSizeKB = 0,
|
||||
SkipCoreConsistencyCheck = comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck),
|
||||
SkipMemoryConsistencyCheck = comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck),
|
||||
});
|
||||
using (exe.EnterExit())
|
||||
{
|
||||
// Marshal checks that function pointers passed to GetDelegateForFunctionPointer are
|
||||
// _currently_ valid when created, even though they don't need to be valid until
|
||||
// the delegate is later invoked. so GetInvoker needs to be acquired within a lock.
|
||||
_adapter = CallingConventionAdapters.MakeWaterbox(allCallbacks, exe);
|
||||
this.core = BizInvoker.GetInvoker<BsnesCoreImpl>(exe, exe, _adapter);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
_disposed = true;
|
||||
exe.Dispose();
|
||||
exe = null;
|
||||
core = null;
|
||||
// serializedSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public delegate void snes_video_frame_t(ushort* data, int width, int height, int pitch);
|
||||
public delegate void snes_input_poll_t();
|
||||
public delegate short snes_input_state_t(int port, int index, int id);
|
||||
public delegate void snes_no_lag_t();
|
||||
public delegate void snes_audio_sample_t(short left, short right);
|
||||
public delegate string snes_path_request_t(int slot, string hint, bool required);
|
||||
public delegate void snes_trace_t(string disassembly, string register_info);
|
||||
|
||||
|
||||
// I cannot use a struct here because marshalling is retarded for bool (4 bytes). I honestly cannot
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class LayerEnables
|
||||
{
|
||||
public bool BG1_Prio0, BG1_Prio1;
|
||||
public bool BG2_Prio0, BG2_Prio1;
|
||||
public bool BG3_Prio0, BG3_Prio1;
|
||||
public bool BG4_Prio0, BG4_Prio1;
|
||||
public bool Obj_Prio0, Obj_Prio1, Obj_Prio2, Obj_Prio3;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class SnesCallbacks
|
||||
{
|
||||
public snes_input_poll_t inputPollCb;
|
||||
public snes_input_state_t inputStateCb;
|
||||
public snes_no_lag_t noLagCb;
|
||||
public snes_video_frame_t videoFrameCb;
|
||||
public snes_audio_sample_t audioSampleCb;
|
||||
public snes_path_request_t pathRequestCb;
|
||||
public snes_trace_t snesTraceCb;
|
||||
}
|
||||
|
||||
public void Seal()
|
||||
{
|
||||
exe.Seal();
|
||||
foreach (var s in _readonlyFiles)
|
||||
{
|
||||
exe.RemoveReadonlyFile(s);
|
||||
}
|
||||
_readonlyFiles.Clear();
|
||||
}
|
||||
|
||||
// TODO: confirm that the serializedSize is CONSTANT for any given game,
|
||||
// else this might be problematic
|
||||
// private int serializedSize;// = 284275;
|
||||
|
||||
public void SaveStateBinary(BinaryWriter writer)
|
||||
{
|
||||
// if (serializedSize == 0)
|
||||
// serializedSize = _core.snes_serialized_size();
|
||||
// TODO: do some profiling and testing to check whether this is actually better than _exe.SaveStateBinary(writer);
|
||||
// re-adding bsnes's own serialization will need to be done once it's confirmed to be deterministic, aka after libco update
|
||||
|
||||
// byte[] serializedData = new byte[serializedSize];
|
||||
// _core.snes_serialize(serializedData, serializedSize);
|
||||
// writer.Write(serializedData);
|
||||
exe.SaveStateBinary(writer);
|
||||
}
|
||||
|
||||
public void LoadStateBinary(BinaryReader reader)
|
||||
{
|
||||
// byte[] serializedData = reader.ReadBytes(serializedSize);
|
||||
// _core.snes_unserialize(serializedData, serializedSize);
|
||||
exe.LoadStateBinary(reader);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||
{
|
||||
public partial class BsnesApi
|
||||
{
|
||||
public enum SNES_MEMORY
|
||||
{
|
||||
CARTRIDGE_RAM,
|
||||
BSX_RAM,
|
||||
BSX_PRAM,
|
||||
SUFAMI_TURBO_A_RAM,
|
||||
SUFAMI_TURBO_B_RAM,
|
||||
|
||||
WRAM,
|
||||
APURAM,
|
||||
VRAM,
|
||||
// OAM, // needs some work in the core probably? or we return an objects pointer
|
||||
CGRAM,
|
||||
|
||||
CARTRIDGE_ROM
|
||||
}
|
||||
|
||||
public enum BSNES_INPUT_DEVICE
|
||||
{
|
||||
None,
|
||||
Gamepad,
|
||||
Mouse,
|
||||
SuperMultitap,
|
||||
SuperScope,
|
||||
Justifier,
|
||||
Justifiers
|
||||
}
|
||||
|
||||
public enum ENTROPY
|
||||
{
|
||||
None,
|
||||
Low,
|
||||
High
|
||||
}
|
||||
|
||||
public enum SNES_MAPPER : byte
|
||||
{
|
||||
LOROM = 0,
|
||||
HIROM = 1,
|
||||
EXLOROM = 2,
|
||||
EXHIROM = 3,
|
||||
SUPERFXROM = 4,
|
||||
SA1ROM = 5,
|
||||
SPC7110ROM = 6,
|
||||
BSCLOROM = 7,
|
||||
BSCHIROM = 8,
|
||||
BSXROM = 9,
|
||||
STROM = 10
|
||||
}
|
||||
|
||||
public enum SNES_REGION : uint
|
||||
{
|
||||
NTSC = 0,
|
||||
PAL = 1
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,309 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
||||
using static BizHawk.Emulation.Cores.Nintendo.BSNES.BsnesApi;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||
{
|
||||
public class BsnesControllers
|
||||
{
|
||||
private static IBsnesController GetController(BSNES_INPUT_DEVICE t, BsnesCore.SnesSyncSettings ss)
|
||||
{
|
||||
return t switch
|
||||
{
|
||||
BSNES_INPUT_DEVICE.None => new BsnesUnpluggedController(),
|
||||
BSNES_INPUT_DEVICE.Gamepad => new BsnesController(),
|
||||
BSNES_INPUT_DEVICE.Mouse => new BsnesMouseController
|
||||
{
|
||||
LimitAnalogChangeSensitivity = ss.LimitAnalogChangeSensitivity
|
||||
},
|
||||
BSNES_INPUT_DEVICE.SuperMultitap => new BsnesMultitapController(),
|
||||
BSNES_INPUT_DEVICE.SuperScope => new BsnesSuperScopeController(),
|
||||
BSNES_INPUT_DEVICE.Justifier => new BsnesJustifierController(false),
|
||||
BSNES_INPUT_DEVICE.Justifiers => new BsnesJustifierController(true),
|
||||
_ => throw new InvalidOperationException()
|
||||
};
|
||||
}
|
||||
|
||||
private readonly IBsnesController[] _ports;
|
||||
private readonly ControlDefUnMerger[] _mergers;
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
public BsnesControllers(BsnesCore.SnesSyncSettings ss)
|
||||
{
|
||||
_ports = new[]
|
||||
{
|
||||
GetController(ss.LeftPort, ss),
|
||||
GetController(ss.RightPort, ss)
|
||||
};
|
||||
|
||||
Definition = ControllerDefinitionMerger.GetMerged(_ports.Select(p => p.Definition), out var tmp);
|
||||
_mergers = tmp.ToArray();
|
||||
|
||||
// add buttons that the core itself will handle
|
||||
Definition.BoolButtons.Add("Reset");
|
||||
Definition.BoolButtons.Add("Power");
|
||||
Definition.Name = "SNES Controller";
|
||||
}
|
||||
|
||||
public void CoreInputPoll(IController controller)
|
||||
{
|
||||
// i hope this is correct lol
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
_ports[i].UpdateState(_mergers[i].UnMerge(controller));
|
||||
}
|
||||
}
|
||||
|
||||
public short CoreInputState(int port, int index, int id)
|
||||
{
|
||||
return _ports[port].GetState(index, id);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IBsnesController
|
||||
{
|
||||
// Updates the internal state; gets called once per frame from the core
|
||||
void UpdateState(IController controller);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the internal state; gets called potentially many times per frame
|
||||
/// </summary>
|
||||
/// <param name="index">bsnes specific value, sometimes multitap number</param>
|
||||
/// <param name="id">bsnes specific value, sometimes button number</param>
|
||||
short GetState(int index, int id);
|
||||
|
||||
ControllerDefinition Definition { get; }
|
||||
}
|
||||
|
||||
internal class BsnesController : IBsnesController
|
||||
{
|
||||
private readonly bool[] _state = new bool[12];
|
||||
|
||||
private static readonly string[] Buttons =
|
||||
{
|
||||
"0Up", "0Down", "0Left", "0Right", "0B", "0A", "0Y", "0X", "0L", "0R", "0Select", "0Start"
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, int> ButtonsOrder = new()
|
||||
{
|
||||
["0Up"] = 0,
|
||||
["0Down"] = 1,
|
||||
["0Left"] = 2,
|
||||
["0Right"] = 3,
|
||||
["0Select"] = 4,
|
||||
["0Start"] = 5,
|
||||
["0Y"] = 6,
|
||||
["0B"] = 7,
|
||||
["0X"] = 8,
|
||||
["0A"] = 9,
|
||||
["0L"] = 10,
|
||||
["0R"] = 11
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition _definition = new()
|
||||
{
|
||||
BoolButtons = Buttons.OrderBy(b => ButtonsOrder[b]).ToList()
|
||||
};
|
||||
|
||||
public ControllerDefinition Definition => _definition;
|
||||
|
||||
public void UpdateState(IController controller)
|
||||
{
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
_state[i] = controller.IsPressed(Buttons[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public short GetState(int index, int id)
|
||||
{
|
||||
if (id >= 12)
|
||||
return 0;
|
||||
|
||||
return (short) (_state[id] ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
public class BsnesMultitapController : IBsnesController
|
||||
{
|
||||
private readonly bool[,] _state = new bool[4, 12];
|
||||
|
||||
private static readonly string[] Buttons =
|
||||
{
|
||||
"Up", "Down", "Left", "Right", "B", "A", "Y", "X", "L", "R", "Select", "Start"
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, int> ButtonsOrder = new()
|
||||
{
|
||||
["Up"] = 0,
|
||||
["Down"] = 1,
|
||||
["Left"] = 2,
|
||||
["Right"] = 3,
|
||||
["Select"] = 4,
|
||||
["Start"] = 5,
|
||||
["Y"] = 6,
|
||||
["B"] = 7,
|
||||
["X"] = 8,
|
||||
["A"] = 9,
|
||||
["R"] = 10,
|
||||
["L"] = 11
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition _definition = new()
|
||||
{
|
||||
BoolButtons = Enumerable.Range(0, 4)
|
||||
.SelectMany(i => Buttons.OrderBy(b => ButtonsOrder[b])
|
||||
.Select(b => i + b))
|
||||
.ToList()
|
||||
};
|
||||
|
||||
public ControllerDefinition Definition => _definition;
|
||||
|
||||
public void UpdateState(IController controller)
|
||||
{
|
||||
for (int port = 0; port < 4; port++)
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
_state[port, i] = controller.IsPressed(port + Buttons[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public short GetState(int index, int id)
|
||||
{
|
||||
if (id >= 12 || index >= 4)
|
||||
return 0;
|
||||
|
||||
return (short) (_state[index, id] ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
public class BsnesUnpluggedController : IBsnesController
|
||||
{
|
||||
private static readonly ControllerDefinition _definition = new();
|
||||
|
||||
public ControllerDefinition Definition => _definition;
|
||||
|
||||
public void UpdateState(IController controller) { }
|
||||
|
||||
public short GetState(int index, int id) => 0;
|
||||
}
|
||||
|
||||
public class BsnesMouseController : IBsnesController
|
||||
{
|
||||
private readonly short[] _state = new short[4];
|
||||
|
||||
private static readonly ControllerDefinition _definition = new ControllerDefinition
|
||||
{ BoolButtons = { "0Mouse Left", "0Mouse Right" } }
|
||||
.AddXYPair("0Mouse {0}", AxisPairOrientation.RightAndDown, (-127).RangeTo(127), 0); //TODO verify direction against hardware, R+D inferred from behaviour in Mario Paint
|
||||
|
||||
public ControllerDefinition Definition => _definition;
|
||||
public bool LimitAnalogChangeSensitivity { get; init; } = true;
|
||||
|
||||
public void UpdateState(IController controller)
|
||||
{
|
||||
int x = controller.AxisValue("0Mouse X");
|
||||
if (LimitAnalogChangeSensitivity)
|
||||
{
|
||||
x = x.Clamp(-10, 10);
|
||||
}
|
||||
_state[0] = (short) x;
|
||||
|
||||
int y = controller.AxisValue("0Mouse Y");
|
||||
if (LimitAnalogChangeSensitivity)
|
||||
{
|
||||
y = y.Clamp(-10, 10);
|
||||
}
|
||||
_state[1] = (short) y;
|
||||
|
||||
_state[2] = (short) (controller.IsPressed("0Mouse Left") ? 1 : 0);
|
||||
_state[3] = (short) (controller.IsPressed("0Mouse Right") ? 1 : 0);
|
||||
}
|
||||
|
||||
public short GetState(int index, int id)
|
||||
{
|
||||
if (id >= 4)
|
||||
return 0;
|
||||
|
||||
return _state[id];
|
||||
}
|
||||
}
|
||||
|
||||
public class BsnesSuperScopeController : IBsnesController
|
||||
{
|
||||
private readonly short[] _state = new short[6];
|
||||
|
||||
private static readonly ControllerDefinition _definition = new ControllerDefinition
|
||||
{ BoolButtons = { "0Trigger", "0Cursor", "0Turbo", "0Pause" } }
|
||||
.AddLightGun("0Scope {0}");
|
||||
|
||||
public ControllerDefinition Definition => _definition;
|
||||
|
||||
public void UpdateState(IController controller)
|
||||
{
|
||||
_state[0] = (short) controller.AxisValue("0Scope X");
|
||||
_state[1] = (short) controller.AxisValue("0Scope Y");
|
||||
for (int i = 2; i < 6; i++)
|
||||
{
|
||||
_state[i] = (short) (controller.IsPressed(_definition.BoolButtons[i]) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
public short GetState(int index, int id)
|
||||
{
|
||||
if (id >= 6)
|
||||
return 0;
|
||||
|
||||
return _state[id];
|
||||
}
|
||||
}
|
||||
|
||||
public class BsnesJustifierController : IBsnesController
|
||||
{
|
||||
public BsnesJustifierController(bool chained)
|
||||
{
|
||||
Definition = chained
|
||||
? new ControllerDefinition
|
||||
{ BoolButtons = { "0Trigger", "0Start", "1Trigger", "1Start" } }
|
||||
.AddLightGun("0Justifier {0}")
|
||||
.AddLightGun("1Justifier {0}")
|
||||
: new ControllerDefinition
|
||||
{BoolButtons = { "0Trigger", "0Start"} }
|
||||
.AddLightGun("0Justifier {0}");
|
||||
_state = new short[chained ? 8 : 4];
|
||||
_chained = chained;
|
||||
}
|
||||
|
||||
private readonly bool _chained;
|
||||
private readonly short[] _state;
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
public void UpdateState(IController controller)
|
||||
{
|
||||
_state[0] = (short) controller.AxisValue("0Justifier X");
|
||||
_state[1] = (short) controller.AxisValue("0Justifier Y");
|
||||
_state[2] = (short) (controller.IsPressed(Definition.BoolButtons[0]) ? 1 : 0);
|
||||
_state[3] = (short) (controller.IsPressed(Definition.BoolButtons[1]) ? 1 : 0);
|
||||
if (_chained)
|
||||
{
|
||||
_state[4] = (short) controller.AxisValue("1Justifier X");
|
||||
_state[5] = (short) controller.AxisValue("1Justifier Y");
|
||||
_state[6] = (short) (controller.IsPressed(Definition.BoolButtons[2]) ? 1 : 0);
|
||||
_state[7] = (short) (controller.IsPressed(Definition.BoolButtons[3]) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
public short GetState(int index, int id)
|
||||
{
|
||||
if (index >= 2 || id >= 4 || (index == 1 && !_chained))
|
||||
return 0;
|
||||
|
||||
return _state[index * 4 + id];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||
{
|
||||
public partial class BsnesCore : IEmulator
|
||||
{
|
||||
public IEmulatorServiceProvider ServiceProvider { get; }
|
||||
|
||||
public ControllerDefinition ControllerDefinition => _controllers.Definition;
|
||||
|
||||
public bool FrameAdvance(IController controller, bool render, bool renderSound)
|
||||
{
|
||||
_controller = controller;
|
||||
|
||||
/* if the input poll callback is called, it will set this to false
|
||||
* this has to be done before we save the per-frame state in deterministic
|
||||
* mode, because in there, the core actually advances, and might advance
|
||||
* through the point in time where IsLagFrame gets set to false. makes sense?
|
||||
*/
|
||||
IsLagFrame = true;
|
||||
|
||||
bool resetSignal = controller.IsPressed("Reset");
|
||||
if (resetSignal)
|
||||
{
|
||||
Api.core.snes_reset();
|
||||
}
|
||||
|
||||
bool powerSignal = controller.IsPressed("Power");
|
||||
if (powerSignal)
|
||||
{
|
||||
Api.core.snes_power();
|
||||
}
|
||||
|
||||
var enables = new BsnesApi.LayerEnables
|
||||
{
|
||||
BG1_Prio0 = _settings.ShowBG1_0,
|
||||
BG1_Prio1 = _settings.ShowBG1_1,
|
||||
BG2_Prio0 = _settings.ShowBG2_0,
|
||||
BG2_Prio1 = _settings.ShowBG2_1,
|
||||
BG3_Prio0 = _settings.ShowBG3_0,
|
||||
BG3_Prio1 = _settings.ShowBG3_1,
|
||||
BG4_Prio0 = _settings.ShowBG4_0,
|
||||
BG4_Prio1 = _settings.ShowBG4_1,
|
||||
Obj_Prio0 = _settings.ShowOBJ_0,
|
||||
Obj_Prio1 = _settings.ShowOBJ_1,
|
||||
Obj_Prio2 = _settings.ShowOBJ_2,
|
||||
Obj_Prio3 = _settings.ShowOBJ_3
|
||||
};
|
||||
// TODO: I really don't think stuff like this should be set every single frame (only on change)
|
||||
Api.core.snes_set_layer_enables(enables);
|
||||
Api.core.snes_set_trace_enabled(_tracer.Enabled);
|
||||
Api.core.snes_set_video_enabled(render);
|
||||
Api.core.snes_set_audio_enabled(renderSound);
|
||||
|
||||
// run the core for one frame
|
||||
Frame++;
|
||||
Api.core.snes_run();
|
||||
|
||||
if (IsLagFrame)
|
||||
{
|
||||
LagCount++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int Frame { get; private set; }
|
||||
|
||||
public string SystemId { get; }
|
||||
public bool DeterministicEmulation => true;
|
||||
|
||||
public void ResetCounters()
|
||||
{
|
||||
Frame = 0;
|
||||
LagCount = 0;
|
||||
IsLagFrame = false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Api.Dispose();
|
||||
_resampler.Dispose();
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||
{
|
||||
public partial class BsnesCore : IInputPollable
|
||||
{
|
||||
public int LagCount { get; set; }
|
||||
|
||||
public bool IsLagFrame { get; set; }
|
||||
|
||||
// TODO: optimize managed to unmanaged using the ActiveChanged event
|
||||
// ??? no idea what this is
|
||||
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||
{
|
||||
public partial class BsnesCore
|
||||
{
|
||||
private IMemoryDomains _memoryDomains;
|
||||
|
||||
private unsafe void SetMemoryDomains()
|
||||
{
|
||||
List<MemoryDomain> mm = new();
|
||||
foreach (int i in Enum.GetValues(typeof(BsnesApi.SNES_MEMORY)))
|
||||
{
|
||||
void* data = Api.core.snes_get_memory_region(i, out int size, out int wordSize);
|
||||
if (data == null) continue;
|
||||
if (Enum.GetName(typeof(BsnesApi.SNES_MEMORY), i) == BsnesApi.SNES_MEMORY.CARTRIDGE_RAM.ToString())
|
||||
{
|
||||
_saveRam = (byte*) data;
|
||||
_saveRamSize = size;
|
||||
}
|
||||
mm.Add(new MemoryDomainIntPtr(Enum.GetName(typeof(BsnesApi.SNES_MEMORY), i), MemoryDomain.Endian.Little, (IntPtr) data, size, true, wordSize));
|
||||
}
|
||||
|
||||
mm.Add(new MemoryDomainDelegate(
|
||||
"System Bus",
|
||||
0x1000000,
|
||||
MemoryDomain.Endian.Little,
|
||||
address => Api.core.snes_bus_read((uint) address),
|
||||
(address, value) => Api.core.snes_bus_write((uint) address, value), wordSize: 4));
|
||||
mm.Add(Api.exe.GetPagesDomain());
|
||||
|
||||
_memoryDomains = new MemoryDomainList(mm);
|
||||
((BasicServiceProvider) ServiceProvider).Register(_memoryDomains);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||
{
|
||||
public partial class BsnesCore : IRegionable
|
||||
{
|
||||
public DisplayType Region => _region == BsnesApi.SNES_REGION.NTSC
|
||||
? DisplayType.NTSC
|
||||
: DisplayType.PAL;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||
{
|
||||
public unsafe partial class BsnesCore : ISaveRam
|
||||
{
|
||||
private byte* _saveRam;
|
||||
private int _saveRamSize;
|
||||
|
||||
// yeah this is not the best. this will basically always return true as long as the saveRam exists.
|
||||
public bool SaveRamModified => _saveRamSize != 0;
|
||||
|
||||
public byte[] CloneSaveRam()
|
||||
{
|
||||
if (_saveRamSize == 0) return null;
|
||||
|
||||
byte[] saveRamCopy = new byte[_saveRamSize];
|
||||
using (Api.exe.EnterExit())
|
||||
{
|
||||
Marshal.Copy((IntPtr) _saveRam, saveRamCopy, 0, _saveRamSize);
|
||||
}
|
||||
|
||||
return saveRamCopy;
|
||||
}
|
||||
|
||||
public void StoreSaveRam(byte[] data)
|
||||
{
|
||||
if (_saveRamSize == 0) return;
|
||||
|
||||
using (Api.exe.EnterExit())
|
||||
{
|
||||
Marshal.Copy(data, 0, (IntPtr) _saveRam, _saveRamSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||
{
|
||||
public partial class BsnesCore : ISettable<BsnesCore.SnesSettings, BsnesCore.SnesSyncSettings>
|
||||
{
|
||||
public SnesSettings GetSettings()
|
||||
{
|
||||
return _settings.Clone();
|
||||
}
|
||||
|
||||
public SnesSyncSettings GetSyncSettings()
|
||||
{
|
||||
return _syncSettings.Clone();
|
||||
}
|
||||
|
||||
public PutSettingsDirtyBits PutSettings(SnesSettings o)
|
||||
{
|
||||
_settings = o;
|
||||
|
||||
return PutSettingsDirtyBits.None;
|
||||
}
|
||||
|
||||
public PutSettingsDirtyBits PutSyncSettings(SnesSyncSettings o)
|
||||
{
|
||||
bool ret = o.LeftPort != _syncSettings.LeftPort
|
||||
|| o.RightPort != _syncSettings.RightPort
|
||||
|| o.LimitAnalogChangeSensitivity != _syncSettings.LimitAnalogChangeSensitivity
|
||||
|| o.Entropy != _syncSettings.Entropy
|
||||
|| o.Hotfixes != _syncSettings.Hotfixes
|
||||
|| o.FastPPU != _syncSettings.FastPPU;
|
||||
|
||||
_syncSettings = o;
|
||||
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
|
||||
}
|
||||
|
||||
private SnesSettings _settings;
|
||||
private SnesSyncSettings _syncSettings;
|
||||
|
||||
public class SnesSettings
|
||||
{
|
||||
public bool ShowBG1_0 { get; set; } = true;
|
||||
public bool ShowBG2_0 { get; set; } = true;
|
||||
public bool ShowBG3_0 { get; set; } = true;
|
||||
public bool ShowBG4_0 { get; set; } = true;
|
||||
public bool ShowBG1_1 { get; set; } = true;
|
||||
public bool ShowBG2_1 { get; set; } = true;
|
||||
public bool ShowBG3_1 { get; set; } = true;
|
||||
public bool ShowBG4_1 { get; set; } = true;
|
||||
public bool ShowOBJ_0 { get; set; } = true;
|
||||
public bool ShowOBJ_1 { get; set; } = true;
|
||||
public bool ShowOBJ_2 { get; set; } = true;
|
||||
public bool ShowOBJ_3 { get; set; } = true;
|
||||
|
||||
public bool AlwaysDoubleSize { get; set; }
|
||||
public bool CropSGBFrame { get; set; }
|
||||
|
||||
public SnesSettings Clone()
|
||||
{
|
||||
return (SnesSettings) MemberwiseClone();
|
||||
}
|
||||
}
|
||||
|
||||
public class SnesSyncSettings
|
||||
{
|
||||
public BsnesApi.BSNES_INPUT_DEVICE LeftPort { get; set; } = BsnesApi.BSNES_INPUT_DEVICE.Gamepad;
|
||||
|
||||
public BsnesApi.BSNES_INPUT_DEVICE RightPort { get; set; } = BsnesApi.BSNES_INPUT_DEVICE.None;
|
||||
|
||||
public bool LimitAnalogChangeSensitivity { get; set; } = true;
|
||||
|
||||
public BsnesApi.ENTROPY Entropy { get; set; } = BsnesApi.ENTROPY.Low;
|
||||
|
||||
public bool Hotfixes { get; set; } = true;
|
||||
|
||||
public bool FastPPU { get; set; } = true;
|
||||
|
||||
public SnesSyncSettings Clone()
|
||||
{
|
||||
return (SnesSyncSettings) MemberwiseClone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using System.IO;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||
{
|
||||
public partial class BsnesCore : IStatable
|
||||
{
|
||||
public void SaveStateBinary(BinaryWriter writer)
|
||||
{
|
||||
Api.SaveStateBinary(writer);
|
||||
writer.Write(IsLagFrame);
|
||||
writer.Write(LagCount);
|
||||
writer.Write(Frame);
|
||||
}
|
||||
|
||||
public void LoadStateBinary(BinaryReader reader)
|
||||
{
|
||||
Api.LoadStateBinary(reader);
|
||||
IsLagFrame = reader.ReadBoolean();
|
||||
LagCount = reader.ReadInt32();
|
||||
Frame = reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||
{
|
||||
public partial class BsnesCore : IVideoProvider
|
||||
{
|
||||
// TODO: This should probably be different for PAL?
|
||||
public int VirtualWidth => (int) Math.Ceiling((double) BufferHeight * 64 / 49);
|
||||
|
||||
public int VirtualHeight => BufferHeight;
|
||||
|
||||
public int BufferWidth { get; private set; } = 256;
|
||||
|
||||
public int BufferHeight { get; private set; } = 224;
|
||||
|
||||
public int BackgroundColor => 0;
|
||||
|
||||
public int[] GetVideoBuffer() => _videoBuffer;
|
||||
|
||||
public int VsyncNumerator { get; }
|
||||
public int VsyncDenominator { get; }
|
||||
|
||||
private int[] _videoBuffer = new int[256 * 224];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,391 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.IO;
|
||||
|
||||
using BizHawk.Common.BufferExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Components.W65816;
|
||||
|
||||
// http://wiki.superfamicom.org/snes/show/Backgrounds
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||
{
|
||||
[PortedCore(CoreNames.Bsnes115, "bsnes team", "v115+", "https://bsnes.dev", isReleased: false)]
|
||||
[ServiceNotApplicable(new[] { typeof(IDriveLight) })]
|
||||
public unsafe partial class BsnesCore : IEmulator, IVideoProvider, ISaveRam, IStatable, IInputPollable, IRegionable, ISettable<BsnesCore.SnesSettings, BsnesCore.SnesSyncSettings>
|
||||
{
|
||||
private BsnesApi.SNES_REGION _region;
|
||||
|
||||
[CoreConstructor("SGB")]
|
||||
[CoreConstructor("SNES")]
|
||||
public BsnesCore(GameInfo game, byte[] rom, CoreComm comm,
|
||||
SnesSettings settings, SnesSyncSettings syncSettings)
|
||||
:this(game, rom, null, null, comm, settings, syncSettings)
|
||||
{}
|
||||
|
||||
public BsnesCore(GameInfo game, byte[] romData, byte[] xmlData, string baseRomPath, CoreComm comm,
|
||||
SnesSettings settings, SnesSyncSettings syncSettings)
|
||||
{
|
||||
_baseRomPath = baseRomPath;
|
||||
var ser = new BasicServiceProvider(this);
|
||||
ServiceProvider = ser;
|
||||
|
||||
CoreComm = comm;
|
||||
byte[] sgbRomData = null;
|
||||
|
||||
if (game.System == "SGB")
|
||||
{
|
||||
if ((romData[0x143] & 0xc0) == 0xc0)
|
||||
{
|
||||
throw new CGBNotSupportedException();
|
||||
}
|
||||
|
||||
sgbRomData = CoreComm.CoreFileProvider.GetFirmware("SNES", "Rom_SGB", true, "SGB Rom is required for SGB emulation.");
|
||||
game.FirmwareHash = sgbRomData.HashSHA1();
|
||||
}
|
||||
|
||||
_settings = settings ?? new SnesSettings();
|
||||
_syncSettings = syncSettings ?? new SnesSyncSettings();
|
||||
|
||||
BsnesApi.SnesCallbacks callbacks = new()
|
||||
{
|
||||
inputPollCb = snes_input_poll,
|
||||
inputStateCb = snes_input_state,
|
||||
noLagCb = snes_no_lag,
|
||||
videoFrameCb = snes_video_refresh,
|
||||
audioSampleCb = snes_audio_sample,
|
||||
pathRequestCb = snes_path_request,
|
||||
snesTraceCb = snes_trace
|
||||
};
|
||||
|
||||
Api = new BsnesApi(CoreComm.CoreFileProvider.DllPath(), CoreComm, new Delegate[]
|
||||
{
|
||||
callbacks.inputPollCb,
|
||||
callbacks.inputStateCb,
|
||||
callbacks.noLagCb,
|
||||
callbacks.videoFrameCb,
|
||||
callbacks.audioSampleCb,
|
||||
callbacks.pathRequestCb,
|
||||
callbacks.snesTraceCb
|
||||
});
|
||||
|
||||
_controllers = new BsnesControllers(_syncSettings);
|
||||
|
||||
generate_palette();
|
||||
// TODO: massive random hack till waterboxhost gets fixed to support 5+ args
|
||||
ushort mergedBools = (ushort) ((_syncSettings.Hotfixes ? 1 << 8 : 0) | (_syncSettings.FastPPU ? 1 : 0));
|
||||
Api.core.snes_init(_syncSettings.Entropy, _syncSettings.LeftPort, _syncSettings.RightPort, mergedBools);
|
||||
Api.SetCallbacks(callbacks);
|
||||
|
||||
// start up audio resampler
|
||||
InitAudio();
|
||||
ser.Register<ISoundProvider>(_resampler);
|
||||
|
||||
if (game.System == "SGB")
|
||||
{
|
||||
IsSGB = true;
|
||||
SystemId = "SNES";
|
||||
ser.Register<IBoardInfo>(new SGBBoardInfo());
|
||||
|
||||
_currLoadParams = new LoadParams
|
||||
{
|
||||
type = LoadParamType.SuperGameBoy,
|
||||
baseRomPath = baseRomPath,
|
||||
romData = sgbRomData,
|
||||
sgbRomData = romData
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
// we may need to get some information out of the cart, even during the following bootup/load process
|
||||
if (xmlData != null)
|
||||
{
|
||||
_romxml = new XmlDocument();
|
||||
_romxml.Load(new MemoryStream(xmlData));
|
||||
|
||||
// bsnes wont inspect the xml to load the necessary sfc file.
|
||||
// so, we have to do that here and pass it in as the romData :/
|
||||
|
||||
// TODO: uhh i have no idea what the xml is or whether this below code is needed
|
||||
if (_romxml["cartridge"]?["rom"] != null)
|
||||
{
|
||||
romData = File.ReadAllBytes(PathSubfile(_romxml["cartridge"]["rom"].Attributes["name"].Value));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Could not find rom file specification in xml file. Please check the integrity of your xml file");
|
||||
}
|
||||
}
|
||||
|
||||
SystemId = "SNES";
|
||||
_currLoadParams = new LoadParams
|
||||
{
|
||||
type = LoadParamType.Normal,
|
||||
baseRomPath = baseRomPath,
|
||||
romData = romData
|
||||
};
|
||||
}
|
||||
|
||||
LoadCurrent();
|
||||
|
||||
if (_region == BsnesApi.SNES_REGION.NTSC)
|
||||
{
|
||||
// taken from bsnes source
|
||||
VsyncNumerator = 21477272;
|
||||
VsyncDenominator = 357366;
|
||||
}
|
||||
else
|
||||
{
|
||||
// http://forums.nesdev.com/viewtopic.php?t=5367&start=19
|
||||
VsyncNumerator = 21281370;
|
||||
VsyncDenominator = 4 * 341 * 312;
|
||||
}
|
||||
|
||||
SetMemoryDomains();
|
||||
|
||||
_tracer = new TraceBuffer
|
||||
{
|
||||
Header = "65816: PC, mnemonic, operands, registers (A, X, Y, S, D, B, flags (NVMXDIZC), V, H)"
|
||||
};
|
||||
ser.Register<IDisassemblable>(new W65816_DisassemblerService());
|
||||
ser.Register(_tracer);
|
||||
|
||||
Api.Seal();
|
||||
}
|
||||
|
||||
private CoreComm CoreComm { get; }
|
||||
|
||||
private readonly string _baseRomPath;
|
||||
|
||||
private string PathSubfile(string fname) => Path.Combine(_baseRomPath, fname);
|
||||
|
||||
private readonly BsnesControllers _controllers;
|
||||
private readonly ITraceable _tracer;
|
||||
private readonly XmlDocument _romxml;
|
||||
|
||||
private IController _controller;
|
||||
private readonly LoadParams _currLoadParams;
|
||||
private SpeexResampler _resampler;
|
||||
private bool _disposed;
|
||||
|
||||
public bool IsSGB { get; }
|
||||
|
||||
private class SGBBoardInfo : IBoardInfo
|
||||
{
|
||||
public string BoardName => "SGB";
|
||||
}
|
||||
|
||||
private BsnesApi Api { get; }
|
||||
|
||||
private string snes_path_request(int slot, string hint, bool required)
|
||||
{
|
||||
// TODO: this msu1 handling code is outdated and needs to be remade from someone with knowledge.
|
||||
// every rom requests msu1.rom... why? who knows.
|
||||
// also handle msu-1 pcm files here
|
||||
bool isMsu1Rom = hint == "msu1/data.rom";
|
||||
bool isMsu1Pcm = Path.GetExtension(hint).ToLower() == ".pcm";
|
||||
if (isMsu1Rom || isMsu1Pcm)
|
||||
{
|
||||
// well, check if we have an msu-1 xml
|
||||
if (_romxml?["cartridge"]?["msu1"] != null)
|
||||
{
|
||||
var msu1 = _romxml["cartridge"]["msu1"];
|
||||
if (isMsu1Rom && msu1["rom"]?.Attributes["name"] != null)
|
||||
{
|
||||
return PathSubfile(msu1["rom"].Attributes["name"].Value);
|
||||
}
|
||||
|
||||
if (isMsu1Pcm)
|
||||
{
|
||||
// return @"D:\roms\snes\SuperRoadBlaster\SuperRoadBlaster-1.pcm";
|
||||
// return "";
|
||||
int wantsTrackNumber = int.Parse(hint.Replace("track-", "").Replace(".pcm", ""));
|
||||
wantsTrackNumber++;
|
||||
string wantsTrackString = wantsTrackNumber.ToString();
|
||||
foreach (var child in msu1.ChildNodes.Cast<XmlNode>())
|
||||
{
|
||||
if (child.Name == "track" && child.Attributes["number"].Value == wantsTrackString)
|
||||
{
|
||||
return PathSubfile(child.Attributes["name"].Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// not found.. what to do? (every rom will get here when msu1.rom is requested)
|
||||
return "";
|
||||
}
|
||||
|
||||
// not MSU-1. ok.
|
||||
if (hint == "save.ram")
|
||||
{
|
||||
// core asked for saveram, but the interface isn't designed to be able to handle this.
|
||||
// so, we'll just return nothing and the frontend will set the saveram itself later
|
||||
return null;
|
||||
}
|
||||
|
||||
string firmwareId;
|
||||
|
||||
switch (hint)
|
||||
{
|
||||
case "cx4": firmwareId = "CX4"; break;
|
||||
case "dsp1": firmwareId = "DSP1"; break;
|
||||
case "dsp1b": firmwareId = "DSP1b"; break;
|
||||
case "dsp2": firmwareId = "DSP2"; break;
|
||||
case "dsp3": firmwareId = "DSP3"; break;
|
||||
case "dsp4": firmwareId = "DSP4"; break;
|
||||
case "st010": firmwareId = "ST010"; break;
|
||||
case "st011": firmwareId = "ST011"; break;
|
||||
case "st018": firmwareId = "ST018"; break;
|
||||
default:
|
||||
CoreComm.ShowMessage($"Unrecognized SNES firmware request \"{hint}\".");
|
||||
return "";
|
||||
}
|
||||
|
||||
string ret = "";
|
||||
var data = CoreComm.CoreFileProvider.GetFirmware("SNES", firmwareId, required, "Game may function incorrectly without the requested firmware.");
|
||||
if (data != null)
|
||||
{
|
||||
ret = hint;
|
||||
Api.AddReadonlyFile(data, hint);
|
||||
}
|
||||
|
||||
Console.WriteLine("Served bsnescore request for firmware \"{0}\"", hint);
|
||||
|
||||
// return the path we built
|
||||
return ret;
|
||||
}
|
||||
|
||||
private enum LoadParamType
|
||||
{
|
||||
Normal, SuperGameBoy
|
||||
}
|
||||
|
||||
private struct LoadParams
|
||||
{
|
||||
public LoadParamType type;
|
||||
public string baseRomPath;
|
||||
public byte[] romData;
|
||||
public byte[] sgbRomData;
|
||||
}
|
||||
|
||||
private void LoadCurrent()
|
||||
{
|
||||
if (_currLoadParams.type == LoadParamType.Normal)
|
||||
Api.core.snes_load_cartridge_normal(_currLoadParams.baseRomPath, _currLoadParams.romData, _currLoadParams.romData.Length);
|
||||
else
|
||||
Api.core.snes_load_cartridge_super_gameboy(_currLoadParams.baseRomPath, _currLoadParams.romData,
|
||||
_currLoadParams.sgbRomData, (ulong) _currLoadParams.romData.Length << 32 | (uint)_currLoadParams.sgbRomData.Length);
|
||||
|
||||
_region = Api.core.snes_get_region();
|
||||
}
|
||||
|
||||
// poll which updates the controller state
|
||||
private void snes_input_poll()
|
||||
{
|
||||
_controllers.CoreInputPoll(_controller);
|
||||
}
|
||||
|
||||
/// <param name="port">0 or 1, corresponding to L and R physical ports on the snes</param>
|
||||
/// <param name="index">meaningless for most controllers. for multitap, 0-3 for which multitap controller</param>
|
||||
/// <param name="id">button ID enum; in the case of a regular controller, this corresponds to shift register position</param>
|
||||
/// <returns>for regular controllers, one bit D0 of button status. for other controls, varying ranges depending on id</returns>
|
||||
private short snes_input_state(int port, int index, int id)
|
||||
{
|
||||
return _controllers.CoreInputState(port, index, id);
|
||||
}
|
||||
|
||||
private void snes_no_lag()
|
||||
{
|
||||
// gets called whenever there was input polled, aka no lag
|
||||
IsLagFrame = false;
|
||||
}
|
||||
|
||||
private readonly int[] palette = new int[32768];
|
||||
|
||||
private void generate_palette()
|
||||
{
|
||||
for (int color = 0; color < 32768; color++) {
|
||||
int r = (color >> 10) & 31;
|
||||
int g = (color >> 5) & 31;
|
||||
int b = (color >> 0) & 31;
|
||||
|
||||
r = r << 3 | r >> 2; r = r << 8 | r << 0;
|
||||
g = g << 3 | g >> 2; g = g << 8 | g << 0;
|
||||
b = b << 3 | b >> 2; b = b << 8 | b << 0;
|
||||
|
||||
palette[color] = r >> 8 << 16 | g >> 8 << 8 | b >> 8 << 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void snes_video_refresh(ushort* data, int width, int height, int pitch)
|
||||
{
|
||||
int widthMultiplier = 1;
|
||||
int heightMultiplier = 1;
|
||||
if (_settings.CropSGBFrame && IsSGB)
|
||||
{
|
||||
BufferWidth = 160;
|
||||
BufferHeight = 144;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_settings.AlwaysDoubleSize)
|
||||
{
|
||||
if (width == 256) widthMultiplier = 2;
|
||||
if (height == 224) heightMultiplier = 2;
|
||||
}
|
||||
BufferWidth = width * widthMultiplier;
|
||||
BufferHeight = height * heightMultiplier;
|
||||
}
|
||||
|
||||
int size = BufferWidth * BufferHeight;
|
||||
if (_videoBuffer.Length != size)
|
||||
{
|
||||
_videoBuffer = new int[size];
|
||||
}
|
||||
|
||||
int di = 0;
|
||||
if (_settings.CropSGBFrame && IsSGB)
|
||||
{
|
||||
for (int y = 39; y < 39 + 144; y++)
|
||||
{
|
||||
ushort* sp = data + y * pitch + 48;
|
||||
for (int x = 0; x < 160; x++)
|
||||
{
|
||||
_videoBuffer[di++] = palette[*sp++];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (int y = 0; y < height * heightMultiplier; y++)
|
||||
{
|
||||
int si = y / heightMultiplier * pitch;
|
||||
for (int x = 0; x < width * widthMultiplier; x++)
|
||||
{
|
||||
_videoBuffer[di++] = palette[data[si + x / widthMultiplier]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InitAudio()
|
||||
{
|
||||
_resampler = new SpeexResampler(SpeexResampler.Quality.QUALITY_DESKTOP, 64080, 88200, 32040, 44100);
|
||||
}
|
||||
|
||||
private void snes_audio_sample(short left, short right)
|
||||
{
|
||||
_resampler.EnqueueSample(left, right);
|
||||
}
|
||||
|
||||
private void snes_trace(string disassembly, string registerInfo)
|
||||
{
|
||||
_tracer.Put(new TraceInfo
|
||||
{
|
||||
Disassembly = disassembly,
|
||||
RegisterInfo = registerInfo
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ namespace BizHawk.Emulation.Cores
|
|||
public const string A7800Hawk = "A7800Hawk";
|
||||
public const string Atari2600Hawk = "Atari2600Hawk";
|
||||
public const string Bsnes = "BSNES";
|
||||
public const string Bsnes115 = "BSNESv115+";
|
||||
public const string C64Hawk = "C64Hawk";
|
||||
public const string ChannelFHawk = "ChannelFHawk";
|
||||
public const string ColecoHawk = "ColecoHawk";
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
root = false
|
||||
|
||||
[*]
|
||||
# let it auto-detect indent_style for each file
|
||||
# i'm not gonna let my workflow get tampered with
|
||||
indent_style =
|
|
@ -0,0 +1,60 @@
|
|||
NEED_LIBCO := 1
|
||||
|
||||
CXXFLAGS := -std=c++17 \
|
||||
-I../libco -I./bsnes \
|
||||
-Werror=int-to-pointer-cast \
|
||||
-Wno-parentheses -Wno-sign-compare -Wno-unused-variable -Wno-trigraphs -Wno-switch -Wno-reorder -Wno-misleading-indentation \
|
||||
-fno-threadsafe-statics -fno-strict-aliasing -fwrapv
|
||||
|
||||
CCFLAGS := -std=c11 -DGB_INTERNAL -DGB_DISABLE_DEBUGGER -DGB_DISABLE_CHEATS -D_GNU_SOURCE \
|
||||
-Werror \
|
||||
-Wall -Wno-multichar -Wno-int-in-bool-context \
|
||||
-fno-strict-aliasing
|
||||
|
||||
TARGET = bsnes.wbx
|
||||
|
||||
SRCS_PROCESSORS = \
|
||||
$(ROOT_DIR)/bsnes/processor/spc700/spc700.cpp \
|
||||
$(ROOT_DIR)/bsnes/processor/wdc65816/wdc65816.cpp \
|
||||
$(ROOT_DIR)/bsnes/processor/arm7tdmi/arm7tdmi.cpp
|
||||
|
||||
SRCS_EMULATOR = \
|
||||
$(ROOT_DIR)/bsnes/emulator/emulator.cpp
|
||||
|
||||
SRCS_GB = \
|
||||
$(ROOT_DIR)/bsnes/gb/Core/apu.c \
|
||||
$(ROOT_DIR)/bsnes/gb/Core/camera.c \
|
||||
$(ROOT_DIR)/bsnes/gb/Core/rumble.c \
|
||||
$(ROOT_DIR)/bsnes/gb/Core/display.c \
|
||||
$(ROOT_DIR)/bsnes/gb/Core/gb.c \
|
||||
$(ROOT_DIR)/bsnes/gb/Core/joypad.c \
|
||||
$(ROOT_DIR)/bsnes/gb/Core/mbc.c \
|
||||
$(ROOT_DIR)/bsnes/gb/Core/memory.c \
|
||||
$(ROOT_DIR)/bsnes/gb/Core/printer.c \
|
||||
$(ROOT_DIR)/bsnes/gb/Core/random.c \
|
||||
$(ROOT_DIR)/bsnes/gb/Core/rewind.c \
|
||||
$(ROOT_DIR)/bsnes/gb/Core/save_state.c \
|
||||
$(ROOT_DIR)/bsnes/gb/Core/sgb.c \
|
||||
$(ROOT_DIR)/bsnes/gb/Core/sm83_cpu.c \
|
||||
$(ROOT_DIR)/bsnes/gb/Core/symbol_hash.c \
|
||||
$(ROOT_DIR)/bsnes/gb/Core/timing.c
|
||||
|
||||
SRCS_SFC = \
|
||||
$(ROOT_DIR)/bsnes/sfc/interface/interface.cpp \
|
||||
$(ROOT_DIR)/bsnes/sfc/system/system.cpp \
|
||||
$(ROOT_DIR)/bsnes/sfc/controller/controller.cpp \
|
||||
$(ROOT_DIR)/bsnes/sfc/cartridge/cartridge.cpp \
|
||||
$(ROOT_DIR)/bsnes/sfc/memory/memory.cpp \
|
||||
$(ROOT_DIR)/bsnes/sfc/cpu/cpu.cpp \
|
||||
$(ROOT_DIR)/bsnes/sfc/smp/smp.cpp \
|
||||
$(ROOT_DIR)/bsnes/sfc/dsp/dsp.cpp \
|
||||
$(ROOT_DIR)/bsnes/sfc/ppu/ppu.cpp \
|
||||
$(ROOT_DIR)/bsnes/sfc/ppu-fast/ppu.cpp \
|
||||
$(ROOT_DIR)/bsnes/sfc/expansion/expansion.cpp \
|
||||
$(ROOT_DIR)/bsnes/sfc/coprocessor/coprocessor.cpp \
|
||||
$(ROOT_DIR)/bsnes/sfc/slot/slot.cpp \
|
||||
$(ROOT_DIR)/bsnes/target-bsnescore/bsnescore.cpp
|
||||
|
||||
SRCS = $(SRCS_PROCESSORS) $(SRCS_EMULATOR) $(SRCS_GB) $(SRCS_SFC)
|
||||
|
||||
include ../common.mak
|
|
@ -0,0 +1,73 @@
|
|||
namespace Emulator {
|
||||
|
||||
#include "stream.cpp"
|
||||
Audio audio;
|
||||
|
||||
Audio::~Audio() {
|
||||
reset(nullptr);
|
||||
}
|
||||
|
||||
auto Audio::reset(Interface* interface) -> void {
|
||||
_interface = interface;
|
||||
_streams.reset();
|
||||
_channels = 0;
|
||||
}
|
||||
|
||||
auto Audio::setFrequency(double frequency) -> void {
|
||||
_frequency = frequency;
|
||||
for(auto& stream : _streams) {
|
||||
stream->setFrequency(stream->inputFrequency, frequency);
|
||||
}
|
||||
}
|
||||
|
||||
auto Audio::setVolume(double volume) -> void {
|
||||
_volume = volume;
|
||||
}
|
||||
|
||||
auto Audio::setBalance(double balance) -> void {
|
||||
_balance = balance;
|
||||
}
|
||||
|
||||
auto Audio::createStream(uint channels, double frequency) -> shared_pointer<Stream> {
|
||||
_channels = max(_channels, channels);
|
||||
shared_pointer<Stream> stream = new Stream;
|
||||
stream->reset(channels, frequency, _frequency);
|
||||
_streams.append(stream);
|
||||
return stream;
|
||||
}
|
||||
|
||||
auto Audio::process() -> void {
|
||||
while(_streams) {
|
||||
for(auto& stream : _streams) {
|
||||
if(!stream->pending()) return;
|
||||
}
|
||||
|
||||
double samples[_channels];
|
||||
for(auto& sample : samples) sample = 0.0;
|
||||
|
||||
for(auto& stream : _streams) {
|
||||
double buffer[_channels];
|
||||
uint length = stream->read(buffer), offset = 0;
|
||||
|
||||
for(auto& sample : samples) {
|
||||
sample += buffer[offset];
|
||||
if(++offset >= length) offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for(auto c : range(_channels)) {
|
||||
samples[c] = max(-1.0, min(+1.0, samples[c] * _volume));
|
||||
}
|
||||
|
||||
if(_channels == 2) {
|
||||
if(_balance < 0.0) samples[1] *= 1.0 + _balance;
|
||||
if(_balance > 0.0) samples[0] *= 1.0 - _balance;
|
||||
}
|
||||
|
||||
platform->audioFrame(samples, _channels);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#undef double
|
|
@ -0,0 +1,94 @@
|
|||
#pragma once
|
||||
|
||||
#include <nall/dsp/iir/dc-removal.hpp>
|
||||
#include <nall/dsp/iir/one-pole.hpp>
|
||||
#include <nall/dsp/iir/biquad.hpp>
|
||||
#include <nall/dsp/resampler/cubic.hpp>
|
||||
|
||||
namespace Emulator {
|
||||
|
||||
struct Interface;
|
||||
struct Audio;
|
||||
struct Filter;
|
||||
struct Stream;
|
||||
|
||||
struct Audio {
|
||||
~Audio();
|
||||
auto reset(Interface* interface) -> void;
|
||||
|
||||
inline auto channels() const -> uint { return _channels; }
|
||||
inline auto frequency() const -> double { return _frequency; }
|
||||
inline auto volume() const -> double { return _volume; }
|
||||
inline auto balance() const -> double { return _balance; }
|
||||
|
||||
auto setFrequency(double frequency) -> void;
|
||||
auto setVolume(double volume) -> void;
|
||||
auto setBalance(double balance) -> void;
|
||||
|
||||
auto createStream(uint channels, double frequency) -> shared_pointer<Stream>;
|
||||
|
||||
private:
|
||||
auto process() -> void;
|
||||
|
||||
Interface* _interface = nullptr;
|
||||
vector<shared_pointer<Stream>> _streams;
|
||||
|
||||
uint _channels = 0;
|
||||
double _frequency = 48000.0;
|
||||
|
||||
double _volume = 1.0;
|
||||
double _balance = 0.0;
|
||||
|
||||
friend class Stream;
|
||||
};
|
||||
|
||||
struct Filter {
|
||||
enum class Mode : uint { DCRemoval, OnePole, Biquad } mode;
|
||||
enum class Type : uint { None, LowPass, HighPass } type;
|
||||
enum class Order : uint { None, First, Second } order;
|
||||
|
||||
DSP::IIR::DCRemoval dcRemoval;
|
||||
DSP::IIR::OnePole onePole;
|
||||
DSP::IIR::Biquad biquad;
|
||||
};
|
||||
|
||||
struct Stream {
|
||||
auto reset(uint channels, double inputFrequency, double outputFrequency) -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto frequency() const -> double;
|
||||
auto setFrequency(double inputFrequency, maybe<double> outputFrequency = nothing) -> void;
|
||||
|
||||
auto addDCRemovalFilter() -> void;
|
||||
auto addLowPassFilter(double cutoffFrequency, Filter::Order order, uint passes = 1) -> void;
|
||||
auto addHighPassFilter(double cutoffFrequency, Filter::Order order, uint passes = 1) -> void;
|
||||
|
||||
auto pending() const -> uint;
|
||||
auto read(double samples[]) -> uint;
|
||||
auto write(const double samples[]) -> void;
|
||||
|
||||
template<typename... P> auto sample(P&&... p) -> void {
|
||||
double samples[sizeof...(P)] = {forward<P>(p)...};
|
||||
write(samples);
|
||||
}
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
private:
|
||||
struct Channel {
|
||||
vector<Filter> filters;
|
||||
vector<DSP::IIR::Biquad> nyquist;
|
||||
DSP::Resampler::Cubic resampler;
|
||||
};
|
||||
vector<Channel> channels;
|
||||
double inputFrequency;
|
||||
double outputFrequency;
|
||||
|
||||
friend class Audio;
|
||||
};
|
||||
|
||||
extern Audio audio;
|
||||
|
||||
}
|
||||
|
||||
#undef double
|
|
@ -0,0 +1,125 @@
|
|||
auto Stream::reset(uint channelCount, double inputFrequency, double outputFrequency) -> void {
|
||||
channels.reset();
|
||||
channels.resize(channelCount);
|
||||
|
||||
for(auto& channel : channels) {
|
||||
channel.filters.reset();
|
||||
}
|
||||
|
||||
setFrequency(inputFrequency, outputFrequency);
|
||||
}
|
||||
|
||||
auto Stream::reset() -> void {
|
||||
for(auto& channel : channels) {
|
||||
channel.resampler.reset(this->inputFrequency, this->outputFrequency);
|
||||
}
|
||||
}
|
||||
|
||||
auto Stream::frequency() const -> double {
|
||||
return inputFrequency;
|
||||
}
|
||||
|
||||
auto Stream::setFrequency(double inputFrequency, maybe<double> outputFrequency) -> void {
|
||||
this->inputFrequency = inputFrequency;
|
||||
if(outputFrequency) this->outputFrequency = outputFrequency();
|
||||
|
||||
for(auto& channel : channels) {
|
||||
channel.nyquist.reset();
|
||||
channel.resampler.reset(this->inputFrequency, this->outputFrequency);
|
||||
}
|
||||
|
||||
if(this->inputFrequency >= this->outputFrequency * 2) {
|
||||
//add a low-pass filter to prevent aliasing during resampling
|
||||
double cutoffFrequency = min(25000.0, this->outputFrequency / 2.0 - 2000.0);
|
||||
for(auto& channel : channels) {
|
||||
uint passes = 3;
|
||||
for(uint pass : range(passes)) {
|
||||
DSP::IIR::Biquad filter;
|
||||
double q = DSP::IIR::Biquad::butterworth(passes * 2, pass);
|
||||
filter.reset(DSP::IIR::Biquad::Type::LowPass, cutoffFrequency, this->inputFrequency, q);
|
||||
channel.nyquist.append(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Stream::addDCRemovalFilter() -> void {
|
||||
return; //todo: test to ensure this is desirable before enabling
|
||||
for(auto& channel : channels) {
|
||||
Filter filter{Filter::Mode::DCRemoval, Filter::Type::None, Filter::Order::None};
|
||||
channel.filters.append(filter);
|
||||
}
|
||||
}
|
||||
|
||||
auto Stream::addLowPassFilter(double cutoffFrequency, Filter::Order order, uint passes) -> void {
|
||||
for(auto& channel : channels) {
|
||||
for(uint pass : range(passes)) {
|
||||
if(order == Filter::Order::First) {
|
||||
Filter filter{Filter::Mode::OnePole, Filter::Type::LowPass, Filter::Order::First};
|
||||
filter.onePole.reset(DSP::IIR::OnePole::Type::LowPass, cutoffFrequency, inputFrequency);
|
||||
channel.filters.append(filter);
|
||||
}
|
||||
if(order == Filter::Order::Second) {
|
||||
Filter filter{Filter::Mode::Biquad, Filter::Type::LowPass, Filter::Order::Second};
|
||||
double q = DSP::IIR::Biquad::butterworth(passes * 2, pass);
|
||||
filter.biquad.reset(DSP::IIR::Biquad::Type::LowPass, cutoffFrequency, inputFrequency, q);
|
||||
channel.filters.append(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Stream::addHighPassFilter(double cutoffFrequency, Filter::Order order, uint passes) -> void {
|
||||
for(auto& channel : channels) {
|
||||
for(uint pass : range(passes)) {
|
||||
if(order == Filter::Order::First) {
|
||||
Filter filter{Filter::Mode::OnePole, Filter::Type::HighPass, Filter::Order::First};
|
||||
filter.onePole.reset(DSP::IIR::OnePole::Type::HighPass, cutoffFrequency, inputFrequency);
|
||||
channel.filters.append(filter);
|
||||
}
|
||||
if(order == Filter::Order::Second) {
|
||||
Filter filter{Filter::Mode::Biquad, Filter::Type::HighPass, Filter::Order::Second};
|
||||
double q = DSP::IIR::Biquad::butterworth(passes * 2, pass);
|
||||
filter.biquad.reset(DSP::IIR::Biquad::Type::HighPass, cutoffFrequency, inputFrequency, q);
|
||||
channel.filters.append(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Stream::pending() const -> uint {
|
||||
if(!channels) return 0;
|
||||
return channels[0].resampler.pending();
|
||||
}
|
||||
|
||||
auto Stream::read(double samples[]) -> uint {
|
||||
for(uint c : range(channels.size())) samples[c] = channels[c].resampler.read();
|
||||
return channels.size();
|
||||
}
|
||||
|
||||
auto Stream::write(const double samples[]) -> void {
|
||||
for(auto c : range(channels.size())) {
|
||||
double sample = samples[c] + 1e-25; //constant offset used to suppress denormals
|
||||
for(auto& filter : channels[c].filters) {
|
||||
switch(filter.mode) {
|
||||
case Filter::Mode::DCRemoval: sample = filter.dcRemoval.process(sample); break;
|
||||
case Filter::Mode::OnePole: sample = filter.onePole.process(sample); break;
|
||||
case Filter::Mode::Biquad: sample = filter.biquad.process(sample); break;
|
||||
}
|
||||
}
|
||||
for(auto& filter : channels[c].nyquist) {
|
||||
sample = filter.process(sample);
|
||||
}
|
||||
channels[c].resampler.write(sample);
|
||||
}
|
||||
|
||||
audio.process();
|
||||
}
|
||||
|
||||
auto Stream::serialize(serializer& s) -> void {
|
||||
for(auto& channel : channels) {
|
||||
channel.resampler.serialize(s);
|
||||
}
|
||||
s.real(inputFrequency);
|
||||
s.real(outputFrequency);
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
#pragma once
|
||||
|
||||
namespace Emulator {
|
||||
|
||||
struct Cheat {
|
||||
struct Code {
|
||||
auto operator==(const Code& code) const -> bool {
|
||||
if(address != code.address) return false;
|
||||
if(data != code.data) return false;
|
||||
if((bool)compare != (bool)code.compare) return false;
|
||||
if(compare && code.compare && compare() != code.compare()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint address;
|
||||
uint data;
|
||||
maybe<uint> compare;
|
||||
bool enable;
|
||||
uint restore;
|
||||
};
|
||||
|
||||
explicit operator bool() const {
|
||||
return codes.size() > 0;
|
||||
}
|
||||
|
||||
auto reset() -> void {
|
||||
codes.reset();
|
||||
}
|
||||
|
||||
auto append(uint address, uint data, maybe<uint> compare = {}) -> void {
|
||||
codes.append({address, data, compare});
|
||||
}
|
||||
|
||||
auto assign(const vector<string>& list) -> void {
|
||||
reset();
|
||||
for(auto& entry : list) {
|
||||
for(auto code : entry.split("+")) {
|
||||
auto part = code.transform("=?", "//").split("/");
|
||||
if(part.size() == 2) append(part[0].hex(), part[1].hex());
|
||||
if(part.size() == 3) append(part[0].hex(), part[2].hex(), part[1].hex());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto find(uint address, uint compare) -> maybe<uint> {
|
||||
for(auto& code : codes) {
|
||||
if(code.address == address && (!code.compare || code.compare() == compare)) {
|
||||
return code.data;
|
||||
}
|
||||
}
|
||||
return nothing;
|
||||
}
|
||||
|
||||
vector<Code> codes;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include <emulator/emulator.hpp>
|
||||
#include <emulator/audio/audio.cpp>
|
||||
|
||||
namespace Emulator {
|
||||
|
||||
Platform* platform = nullptr;
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
#pragma once
|
||||
|
||||
#include <libco.h>
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/adaptive-array.hpp>
|
||||
#include <nall/any.hpp>
|
||||
#include <nall/chrono.hpp>
|
||||
#include <nall/dl.hpp>
|
||||
#include <nall/endian.hpp>
|
||||
#include <nall/image.hpp>
|
||||
#include <nall/literals.hpp>
|
||||
#include <nall/random.hpp>
|
||||
#include <nall/serializer.hpp>
|
||||
#include <nall/shared-pointer.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/traits.hpp>
|
||||
#include <nall/unique-pointer.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
#include <nall/vfs.hpp>
|
||||
#include <nall/hash/crc32.hpp>
|
||||
#include <nall/hash/sha256.hpp>
|
||||
using namespace nall;
|
||||
|
||||
#include <emulator/types.hpp>
|
||||
#include <emulator/memory/readable.hpp>
|
||||
#include <emulator/memory/writable.hpp>
|
||||
#include <emulator/audio/audio.hpp>
|
||||
|
||||
namespace Emulator {
|
||||
static const string Name = "bsnes";
|
||||
static const string Version = "115";
|
||||
static const string Copyright = "bsnes team";
|
||||
static const string License = "GPLv3 or later";
|
||||
static const string Website = "https://bsnes.dev";
|
||||
|
||||
//incremented only when serialization format changes
|
||||
static const string SerializerVersion = "115";
|
||||
|
||||
namespace Constants {
|
||||
namespace Colorburst {
|
||||
static constexpr double NTSC = 315.0 / 88.0 * 1'000'000.0;
|
||||
static constexpr double PAL = 283.75 * 15'625.0 + 25.0;
|
||||
}
|
||||
}
|
||||
|
||||
//nall/vfs shorthand constants for open(), load()
|
||||
namespace File {
|
||||
static const auto Read = vfs::file::mode::read;
|
||||
static const auto Write = vfs::file::mode::write;
|
||||
static const auto Optional = false;
|
||||
static const auto Required = true;
|
||||
};
|
||||
}
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "interface.hpp"
|
||||
#include "game.hpp"
|
|
@ -0,0 +1,112 @@
|
|||
#pragma once
|
||||
|
||||
namespace Emulator {
|
||||
|
||||
struct Game {
|
||||
struct Memory;
|
||||
struct Oscillator;
|
||||
|
||||
inline auto load(string_view) -> void;
|
||||
inline auto memory(Markup::Node) -> maybe<Memory>;
|
||||
inline auto oscillator(natural = 0) -> maybe<Oscillator>;
|
||||
|
||||
struct Memory {
|
||||
Memory() = default;
|
||||
inline Memory(Markup::Node);
|
||||
explicit operator bool() const { return (bool)type; }
|
||||
inline auto name() const -> string;
|
||||
|
||||
string type;
|
||||
natural size;
|
||||
string content;
|
||||
string manufacturer;
|
||||
string architecture;
|
||||
string identifier;
|
||||
boolean nonVolatile;
|
||||
};
|
||||
|
||||
struct Oscillator {
|
||||
Oscillator() = default;
|
||||
inline Oscillator(Markup::Node);
|
||||
explicit operator bool() const { return frequency; }
|
||||
|
||||
natural frequency;
|
||||
};
|
||||
|
||||
Markup::Node document;
|
||||
string sha256;
|
||||
string label;
|
||||
string name;
|
||||
string title;
|
||||
string region;
|
||||
string revision;
|
||||
string board;
|
||||
vector<Memory> memoryList;
|
||||
vector<Oscillator> oscillatorList;
|
||||
};
|
||||
|
||||
auto Game::load(string_view text) -> void {
|
||||
document = BML::unserialize(text);
|
||||
|
||||
sha256 = document["game/sha256"].text();
|
||||
label = document["game/label"].text();
|
||||
name = document["game/name"].text();
|
||||
title = document["game/title"].text();
|
||||
region = document["game/region"].text();
|
||||
revision = document["game/revision"].text();
|
||||
board = document["game/board"].text();
|
||||
|
||||
for(auto node : document.find("game/board/memory")) {
|
||||
memoryList.append(Memory{node});
|
||||
}
|
||||
|
||||
for(auto node : document.find("game/board/oscillator")) {
|
||||
oscillatorList.append(Oscillator{node});
|
||||
}
|
||||
}
|
||||
|
||||
auto Game::memory(Markup::Node node) -> maybe<Memory> {
|
||||
if(!node) return nothing;
|
||||
for(auto& memory : memoryList) {
|
||||
auto type = node["type"].text();
|
||||
auto size = node["size"].natural();
|
||||
auto content = node["content"].text();
|
||||
auto manufacturer = node["manufacturer"].text();
|
||||
auto architecture = node["architecture"].text();
|
||||
auto identifier = node["identifier"].text();
|
||||
if(type && type != memory.type) continue;
|
||||
if(size && size != memory.size) continue;
|
||||
if(content && content != memory.content) continue;
|
||||
if(manufacturer && manufacturer != memory.manufacturer) continue;
|
||||
if(architecture && architecture != memory.architecture) continue;
|
||||
if(identifier && identifier != memory.identifier) continue;
|
||||
return memory;
|
||||
}
|
||||
return nothing;
|
||||
}
|
||||
|
||||
auto Game::oscillator(natural index) -> maybe<Oscillator> {
|
||||
if(index < oscillatorList.size()) return oscillatorList[index];
|
||||
return nothing;
|
||||
}
|
||||
|
||||
Game::Memory::Memory(Markup::Node node) {
|
||||
type = node["type"].text();
|
||||
size = node["size"].natural();
|
||||
content = node["content"].text();
|
||||
manufacturer = node["manufacturer"].text();
|
||||
architecture = node["architecture"].text();
|
||||
identifier = node["identifier"].text();
|
||||
nonVolatile = !(bool)node["volatile"];
|
||||
}
|
||||
|
||||
auto Game::Memory::name() const -> string {
|
||||
if(architecture) return string{architecture, ".", content, ".", type}.downcase();
|
||||
return string{content, ".", type}.downcase();
|
||||
}
|
||||
|
||||
Game::Oscillator::Oscillator(Markup::Node node) {
|
||||
frequency = node["frequency"].natural();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
#pragma once
|
||||
|
||||
namespace Emulator {
|
||||
|
||||
struct Interface {
|
||||
struct Information {
|
||||
string manufacturer;
|
||||
string name;
|
||||
string extension;
|
||||
bool resettable = false;
|
||||
};
|
||||
|
||||
struct Display {
|
||||
struct Type { enum : uint {
|
||||
CRT,
|
||||
LCD,
|
||||
};};
|
||||
uint id = 0;
|
||||
string name;
|
||||
uint type = 0;
|
||||
uint colors = 0;
|
||||
uint width = 0;
|
||||
uint height = 0;
|
||||
uint internalWidth = 0;
|
||||
uint internalHeight = 0;
|
||||
double aspectCorrection = 0;
|
||||
};
|
||||
|
||||
struct Port {
|
||||
uint id;
|
||||
string name;
|
||||
};
|
||||
|
||||
struct Device {
|
||||
uint id;
|
||||
string name;
|
||||
};
|
||||
|
||||
struct Input {
|
||||
struct Type { enum : uint {
|
||||
Hat,
|
||||
Button,
|
||||
Trigger,
|
||||
Control,
|
||||
Axis,
|
||||
Rumble,
|
||||
};};
|
||||
|
||||
uint type;
|
||||
string name;
|
||||
};
|
||||
|
||||
//information
|
||||
virtual auto information() -> Information { return {}; }
|
||||
|
||||
virtual auto display() -> Display { return {}; }
|
||||
virtual auto color(uint32 color) -> uint64 { return 0; }
|
||||
|
||||
//game interface
|
||||
virtual auto loaded() -> bool { return false; }
|
||||
virtual auto hashes() -> vector<string> { return {}; }
|
||||
virtual auto manifests() -> vector<string> { return {}; }
|
||||
virtual auto titles() -> vector<string> { return {}; }
|
||||
virtual auto title() -> string { return {}; }
|
||||
virtual auto load() -> bool { return false; }
|
||||
virtual auto save() -> void {}
|
||||
virtual auto unload() -> void {}
|
||||
|
||||
//system interface
|
||||
virtual auto ports() -> vector<Port> { return {}; }
|
||||
virtual auto devices(uint port) -> vector<Device> { return {}; }
|
||||
virtual auto inputs(uint device) -> vector<Input> { return {}; }
|
||||
virtual auto connected(uint port) -> uint { return 0; }
|
||||
virtual auto connect(uint port, uint device) -> void {}
|
||||
virtual auto power() -> void {}
|
||||
virtual auto reset() -> void {}
|
||||
virtual auto run() -> void {}
|
||||
|
||||
//time functions
|
||||
virtual auto rtc() -> bool { return false; }
|
||||
virtual auto synchronize(uint64 timestamp = 0) -> void {}
|
||||
|
||||
//state functions
|
||||
virtual auto serialize(bool synchronize = true) -> serializer { return {}; }
|
||||
virtual auto unserialize(serializer&) -> bool { return false; }
|
||||
|
||||
//cheat functions
|
||||
virtual auto read(uint24 address) -> uint8 { return 0; }
|
||||
virtual auto cheats(const vector<string>& = {}) -> void {}
|
||||
|
||||
//configuration
|
||||
virtual auto configuration() -> string { return {}; }
|
||||
virtual auto configuration(string name) -> string { return {}; }
|
||||
virtual auto configure(string configuration = "") -> bool { return false; }
|
||||
virtual auto configure(string name, string value) -> bool { return false; }
|
||||
|
||||
//settings
|
||||
virtual auto cap(const string& name) -> bool { return false; }
|
||||
virtual auto get(const string& name) -> any { return {}; }
|
||||
virtual auto set(const string& name, const any& value) -> bool { return false; }
|
||||
|
||||
virtual auto frameSkip() -> uint { return 0; }
|
||||
virtual auto setFrameSkip(uint frameSkip) -> void {}
|
||||
|
||||
virtual auto runAhead() -> bool { return false; }
|
||||
virtual auto setRunAhead(bool runAhead) -> void {}
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
namespace Emulator::Memory {
|
||||
|
||||
inline auto mirror(uint address, uint size) -> uint {
|
||||
if(size == 0) return 0;
|
||||
uint base = 0;
|
||||
uint mask = 1 << 31;
|
||||
while(address >= size) {
|
||||
while(!(address & mask)) mask >>= 1;
|
||||
address -= mask;
|
||||
if(size > mask) {
|
||||
size -= mask;
|
||||
base += mask;
|
||||
}
|
||||
mask >>= 1;
|
||||
}
|
||||
return base + address;
|
||||
}
|
||||
|
||||
inline auto reduce(uint address, uint mask) -> uint {
|
||||
while(mask) {
|
||||
uint bits = (mask & -mask) - 1;
|
||||
address = address >> 1 & ~bits | address & bits;
|
||||
mask = (mask & mask - 1) >> 1;
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
#pragma once
|
||||
|
||||
#include <emulator/memory/memory.hpp>
|
||||
|
||||
namespace Emulator::Memory {
|
||||
|
||||
template<typename T>
|
||||
struct Readable {
|
||||
~Readable() { reset(); }
|
||||
|
||||
inline auto reset() -> void {
|
||||
delete[] self.data;
|
||||
self.data = nullptr;
|
||||
self.size = 0;
|
||||
self.mask = 0;
|
||||
}
|
||||
|
||||
inline auto allocate(uint size, T fill = ~0ull) -> void {
|
||||
if(!size) return reset();
|
||||
delete[] self.data;
|
||||
self.size = size;
|
||||
self.mask = bit::round(self.size) - 1;
|
||||
self.data = new T[self.mask + 1];
|
||||
memory::fill<T>(self.data, self.mask + 1, fill);
|
||||
}
|
||||
|
||||
inline auto load(shared_pointer<vfs::file> fp) -> void {
|
||||
fp->read(self.data, min(fp->size(), self.size * sizeof(T)));
|
||||
for(uint address = self.size; address <= self.mask; address++) {
|
||||
self.data[address] = self.data[mirror(address, self.size)];
|
||||
}
|
||||
}
|
||||
|
||||
inline auto save(shared_pointer<vfs::file> fp) -> void {
|
||||
fp->write(self.data, self.size * sizeof(T));
|
||||
}
|
||||
|
||||
explicit operator bool() const { return (bool)self.data; }
|
||||
inline auto data() const -> const T* { return self.data; }
|
||||
inline auto size() const -> uint { return self.size; }
|
||||
inline auto mask() const -> uint { return self.mask; }
|
||||
|
||||
inline auto operator[](uint address) const -> T { return self.data[address & self.mask]; }
|
||||
inline auto read(uint address) const -> T { return self.data[address & self.mask]; }
|
||||
inline auto write(uint address, T data) const -> void {}
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
const uint size = self.size;
|
||||
s.integer(self.size);
|
||||
s.integer(self.mask);
|
||||
if(self.size != size) allocate(self.size);
|
||||
s.array(self.data, self.size);
|
||||
}
|
||||
|
||||
private:
|
||||
struct {
|
||||
T* data = nullptr;
|
||||
uint size = 0;
|
||||
uint mask = 0;
|
||||
} self;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
#pragma once
|
||||
|
||||
#include <emulator/memory/memory.hpp>
|
||||
|
||||
namespace Emulator::Memory {
|
||||
|
||||
template<typename T>
|
||||
struct Writable {
|
||||
~Writable() { reset(); }
|
||||
|
||||
inline auto reset() -> void {
|
||||
delete[] self.data;
|
||||
self.data = nullptr;
|
||||
self.size = 0;
|
||||
self.mask = 0;
|
||||
}
|
||||
|
||||
inline auto allocate(uint size, T fill = ~0ull) -> void {
|
||||
if(!size) return reset();
|
||||
delete[] self.data;
|
||||
self.size = size;
|
||||
self.mask = bit::round(self.size) - 1;
|
||||
self.data = new T[self.mask + 1];
|
||||
memory::fill<T>(self.data, self.mask + 1, fill);
|
||||
}
|
||||
|
||||
inline auto load(shared_pointer<vfs::file> fp) -> void {
|
||||
fp->read(self.data, min(fp->size(), self.size * sizeof(T)));
|
||||
for(uint address = self.size; address <= self.mask; address++) {
|
||||
self.data[address] = self.data[mirror(address, self.size)];
|
||||
}
|
||||
}
|
||||
|
||||
inline auto save(shared_pointer<vfs::file> fp) -> void {
|
||||
fp->write(self.data, self.size * sizeof(T));
|
||||
}
|
||||
|
||||
explicit operator bool() const { return (bool)self.data; }
|
||||
inline auto data() -> T* { return self.data; }
|
||||
inline auto data() const -> const T* { return self.data; }
|
||||
inline auto size() const -> uint { return self.size; }
|
||||
inline auto mask() const -> uint { return self.mask; }
|
||||
|
||||
inline auto operator[](uint address) -> T& { return self.data[address & self.mask]; }
|
||||
inline auto operator[](uint address) const -> T { return self.data[address & self.mask]; }
|
||||
inline auto read(uint address) const -> T { return self.data[address & self.mask]; }
|
||||
inline auto write(uint address, T data) -> void { self.data[address & self.mask] = data; }
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
const uint size = self.size;
|
||||
s.integer(self.size);
|
||||
s.integer(self.mask);
|
||||
if(self.size != size) allocate(self.size);
|
||||
s.array(self.data, self.size);
|
||||
}
|
||||
|
||||
private:
|
||||
struct {
|
||||
T* data = nullptr;
|
||||
uint size = 0;
|
||||
uint mask = 0;
|
||||
} self;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
|
||||
namespace Emulator {
|
||||
|
||||
struct Platform {
|
||||
struct Load {
|
||||
Load() = default;
|
||||
Load(uint pathID, string option = "") : valid(true), pathID(pathID), option(option) {}
|
||||
explicit operator bool() const { return valid; }
|
||||
|
||||
bool valid = false;
|
||||
uint pathID = 0;
|
||||
string option;
|
||||
};
|
||||
|
||||
virtual auto path(uint id) -> string { return ""; }
|
||||
virtual auto open(uint id, string name, vfs::file::mode mode, bool required = false) -> shared_pointer<vfs::file> { return {}; }
|
||||
virtual auto load(uint id, string name, string type, vector<string> options = {}) -> Load { return {}; }
|
||||
virtual auto videoFrame(const uint16* data, uint pitch, uint width, uint height, uint scale) -> void {}
|
||||
virtual auto audioFrame(const double* samples, uint channels) -> void {}
|
||||
virtual auto inputPoll(uint port, uint device, uint input) -> int16 { return 0; }
|
||||
virtual auto inputRumble(uint port, uint device, uint input, bool enable) -> void {}
|
||||
virtual auto dipSettings(Markup::Node node) -> uint { return 0; }
|
||||
virtual auto notify(string text) -> void {}
|
||||
// 03-may-2021 manual addition. unused currently but let's hope for the best
|
||||
virtual auto getBackdropColor() -> uint16 { return 0; }
|
||||
|
||||
bool traceEnabled = false;
|
||||
virtual auto cpuTrace(vector<string>) -> void {}
|
||||
};
|
||||
|
||||
extern Platform* platform;
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
#pragma once
|
||||
|
||||
namespace Emulator {
|
||||
|
||||
struct Random {
|
||||
enum class Entropy : uint { None, Low, High };
|
||||
|
||||
auto operator()() -> uint64 {
|
||||
return random();
|
||||
}
|
||||
|
||||
auto entropy(Entropy entropy) -> void {
|
||||
_entropy = entropy;
|
||||
seed();
|
||||
}
|
||||
|
||||
auto seed(maybe<uint32> seed = nothing, maybe<uint32> sequence = nothing) -> void {
|
||||
if(!seed) seed = (uint32)clock();
|
||||
if(!sequence) sequence = 0;
|
||||
|
||||
_state = 0;
|
||||
_increment = sequence() << 1 | 1;
|
||||
step();
|
||||
_state += seed();
|
||||
step();
|
||||
}
|
||||
|
||||
auto random() -> uint64 {
|
||||
if(_entropy == Entropy::None) return 0;
|
||||
return (uint64)step() << 32 | (uint64)step() << 0;
|
||||
}
|
||||
|
||||
auto bias(uint64 bias) -> uint64 {
|
||||
if(_entropy == Entropy::None) return bias;
|
||||
return random();
|
||||
}
|
||||
|
||||
auto bound(uint64 bound) -> uint64 {
|
||||
uint64 threshold = -bound % bound;
|
||||
while(true) {
|
||||
uint64 result = random();
|
||||
if(result >= threshold) return result % bound;
|
||||
}
|
||||
}
|
||||
|
||||
auto array(uint8* data, uint32 size) -> void {
|
||||
if(_entropy == Entropy::None) {
|
||||
memory::fill(data, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if(_entropy == Entropy::High) {
|
||||
for(uint32 address : range(size)) {
|
||||
data[address] = random();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//Entropy::Low
|
||||
uint lobit = random() & 3;
|
||||
uint hibit = (lobit + 8 + (random() & 3)) & 15;
|
||||
uint lovalue = random() & 255;
|
||||
uint hivalue = random() & 255;
|
||||
if((random() & 3) == 0) lovalue = 0;
|
||||
if((random() & 1) == 0) hivalue = ~lovalue;
|
||||
|
||||
for(uint32 address : range(size)) {
|
||||
uint8 value = (address & 1ull << lobit) ? lovalue : hivalue;
|
||||
if((address & 1ull << hibit)) value = ~value;
|
||||
if((random() & 511) == 0) value ^= 1 << (random() & 7);
|
||||
if((random() & 2047) == 0) value ^= 1 << (random() & 7);
|
||||
data[address] = value;
|
||||
}
|
||||
}
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
s.integer((uint&)_entropy);
|
||||
s.integer(_state);
|
||||
s.integer(_increment);
|
||||
}
|
||||
|
||||
private:
|
||||
auto step() -> uint32 {
|
||||
uint64 state = _state;
|
||||
_state = state * 6364136223846793005ull + _increment;
|
||||
uint32 xorshift = (state >> 18 ^ state) >> 27;
|
||||
uint32 rotate = state >> 59;
|
||||
return xorshift >> rotate | xorshift << (-rotate & 31);
|
||||
}
|
||||
|
||||
Entropy _entropy = Entropy::High;
|
||||
uint64 _state;
|
||||
uint64 _increment;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
#pragma once
|
||||
|
||||
using int1 = nall::Integer< 1>;
|
||||
using int2 = nall::Integer< 2>;
|
||||
using int3 = nall::Integer< 3>;
|
||||
using int4 = nall::Integer< 4>;
|
||||
using int5 = nall::Integer< 5>;
|
||||
using int6 = nall::Integer< 6>;
|
||||
using int7 = nall::Integer< 7>;
|
||||
using int8 = int8_t;
|
||||
using int9 = nall::Integer< 9>;
|
||||
using int10 = nall::Integer<10>;
|
||||
using int11 = nall::Integer<11>;
|
||||
using int12 = nall::Integer<12>;
|
||||
using int13 = nall::Integer<13>;
|
||||
using int14 = nall::Integer<14>;
|
||||
using int15 = nall::Integer<15>;
|
||||
using int16 = int16_t;
|
||||
using int17 = nall::Integer<17>;
|
||||
using int18 = nall::Integer<18>;
|
||||
using int19 = nall::Integer<19>;
|
||||
using int20 = nall::Integer<20>;
|
||||
using int21 = nall::Integer<21>;
|
||||
using int22 = nall::Integer<22>;
|
||||
using int23 = nall::Integer<23>;
|
||||
using int24 = nall::Integer<24>;
|
||||
using int25 = nall::Integer<25>;
|
||||
using int26 = nall::Integer<26>;
|
||||
using int27 = nall::Integer<27>;
|
||||
using int28 = nall::Integer<28>;
|
||||
using int29 = nall::Integer<29>;
|
||||
using int30 = nall::Integer<30>;
|
||||
using int31 = nall::Integer<31>;
|
||||
using int32 = int32_t;
|
||||
using int48 = nall::Integer<48>; //Cx4
|
||||
using int64 = int64_t;
|
||||
|
||||
using uint1 = nall::Natural< 1>;
|
||||
using uint2 = nall::Natural< 2>;
|
||||
using uint3 = nall::Natural< 3>;
|
||||
using uint4 = nall::Natural< 4>;
|
||||
using uint5 = nall::Natural< 5>;
|
||||
using uint6 = nall::Natural< 6>;
|
||||
using uint7 = nall::Natural< 7>;
|
||||
using uint8 = uint8_t;
|
||||
using uint9 = nall::Natural< 9>;
|
||||
using uint10 = nall::Natural<10>;
|
||||
using uint11 = nall::Natural<11>;
|
||||
using uint12 = nall::Natural<12>;
|
||||
using uint13 = nall::Natural<13>;
|
||||
using uint14 = nall::Natural<14>;
|
||||
using uint15 = nall::Natural<15>;
|
||||
using uint16 = uint16_t;
|
||||
using uint17 = nall::Natural<17>;
|
||||
using uint18 = nall::Natural<18>;
|
||||
using uint19 = nall::Natural<19>;
|
||||
using uint20 = nall::Natural<20>;
|
||||
using uint21 = nall::Natural<21>;
|
||||
using uint22 = nall::Natural<22>;
|
||||
using uint23 = nall::Natural<23>;
|
||||
using uint24 = nall::Natural<24>;
|
||||
using uint25 = nall::Natural<25>;
|
||||
using uint26 = nall::Natural<26>;
|
||||
using uint27 = nall::Natural<27>;
|
||||
using uint28 = nall::Natural<28>;
|
||||
using uint29 = nall::Natural<29>;
|
||||
using uint30 = nall::Natural<30>;
|
||||
using uint31 = nall::Natural<31>;
|
||||
using uint32 = uint32_t;
|
||||
using uint40 = nall::Natural<40>; //SA1
|
||||
using uint48 = nall::Natural<48>; //Cx4
|
||||
using uint64 = uint64_t;
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,169 @@
|
|||
#ifndef apu_h
|
||||
#define apu_h
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "gb_struct_def.h"
|
||||
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
/* Speed = 1 / Length (in seconds) */
|
||||
#define DAC_DECAY_SPEED 20000
|
||||
#define DAC_ATTACK_SPEED 20000
|
||||
|
||||
|
||||
/* Divides nicely and never overflows with 4 channels and 8 (1-8) volume levels */
|
||||
#ifdef WIIU
|
||||
/* Todo: Remove this hack once https://github.com/libretro/RetroArch/issues/6252 is fixed*/
|
||||
#define MAX_CH_AMP (0xFF0 / 2)
|
||||
#else
|
||||
#define MAX_CH_AMP 0xFF0
|
||||
#endif
|
||||
#define CH_STEP (MAX_CH_AMP/0xF/8)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* APU ticks are 2MHz, triggered by an internal APU clock. */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int16_t left;
|
||||
int16_t right;
|
||||
} GB_sample_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
double left;
|
||||
double right;
|
||||
} GB_double_sample_t;
|
||||
|
||||
enum GB_CHANNELS {
|
||||
GB_SQUARE_1,
|
||||
GB_SQUARE_2,
|
||||
GB_WAVE,
|
||||
GB_NOISE,
|
||||
GB_N_CHANNELS
|
||||
};
|
||||
|
||||
typedef void (*GB_sample_callback_t)(GB_gameboy_t *gb, GB_sample_t *sample);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool global_enable;
|
||||
uint8_t apu_cycles;
|
||||
|
||||
uint8_t samples[GB_N_CHANNELS];
|
||||
bool is_active[GB_N_CHANNELS];
|
||||
|
||||
uint8_t div_divider; // The DIV register ticks the APU at 512Hz, but is then divided
|
||||
// once more to generate 128Hz and 64Hz clocks
|
||||
|
||||
uint8_t lf_div; // The APU runs in 2MHz, but channels 1, 2 and 4 run in 1MHZ so we divide
|
||||
// need to divide the signal.
|
||||
|
||||
uint8_t square_sweep_countdown; // In 128Hz
|
||||
uint8_t square_sweep_calculate_countdown; // In 2 MHz
|
||||
uint16_t new_sweep_sample_length;
|
||||
uint16_t shadow_sweep_sample_length;
|
||||
bool sweep_enabled;
|
||||
bool sweep_decreasing;
|
||||
|
||||
struct {
|
||||
uint16_t pulse_length; // Reloaded from NRX1 (xorred), in 256Hz DIV ticks
|
||||
uint8_t current_volume; // Reloaded from NRX2
|
||||
uint8_t volume_countdown; // Reloaded from NRX2
|
||||
uint8_t current_sample_index; /* For save state compatibility,
|
||||
highest bit is reused (See NR14/NR24's
|
||||
write code)*/
|
||||
|
||||
uint16_t sample_countdown; // in APU ticks (Reloaded from sample_length, xorred $7FF)
|
||||
uint16_t sample_length; // From NRX3, NRX4, in APU ticks
|
||||
bool length_enabled; // NRX4
|
||||
|
||||
} square_channels[2];
|
||||
|
||||
struct {
|
||||
bool enable; // NR30
|
||||
uint16_t pulse_length; // Reloaded from NR31 (xorred), in 256Hz DIV ticks
|
||||
uint8_t shift; // NR32
|
||||
uint16_t sample_length; // NR33, NR34, in APU ticks
|
||||
bool length_enabled; // NR34
|
||||
|
||||
uint16_t sample_countdown; // in APU ticks (Reloaded from sample_length, xorred $7FF)
|
||||
uint8_t current_sample_index;
|
||||
uint8_t current_sample; // Current sample before shifting.
|
||||
|
||||
int8_t wave_form[32];
|
||||
bool wave_form_just_read;
|
||||
} wave_channel;
|
||||
|
||||
struct {
|
||||
uint16_t pulse_length; // Reloaded from NR41 (xorred), in 256Hz DIV ticks
|
||||
uint8_t current_volume; // Reloaded from NR42
|
||||
uint8_t volume_countdown; // Reloaded from NR42
|
||||
uint16_t lfsr;
|
||||
bool narrow;
|
||||
|
||||
uint16_t sample_countdown; // in APU ticks (Reloaded from sample_length)
|
||||
uint16_t sample_length; // From NR43, in APU ticks
|
||||
bool length_enabled; // NR44
|
||||
|
||||
uint8_t alignment; // If (NR43 & 7) != 0, samples are aligned to 512KHz clock instead of
|
||||
// 1MHz. This variable keeps track of the alignment.
|
||||
|
||||
} noise_channel;
|
||||
|
||||
#define GB_SKIP_DIV_EVENT_INACTIVE 0
|
||||
#define GB_SKIP_DIV_EVENT_SKIPPED 1
|
||||
#define GB_SKIP_DIV_EVENT_SKIP 2
|
||||
uint8_t skip_div_event;
|
||||
bool current_lfsr_sample;
|
||||
uint8_t pcm_mask[2]; // For CGB-0 to CGB-C PCM read glitch
|
||||
} GB_apu_t;
|
||||
|
||||
typedef enum {
|
||||
GB_HIGHPASS_OFF, // Do not apply any filter, keep DC offset
|
||||
GB_HIGHPASS_ACCURATE, // Apply a highpass filter similar to the one used on hardware
|
||||
GB_HIGHPASS_REMOVE_DC_OFFSET, // Remove DC Offset without affecting the waveform
|
||||
GB_HIGHPASS_MAX
|
||||
} GB_highpass_mode_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned sample_rate;
|
||||
|
||||
double sample_cycles; // In 8 MHz units
|
||||
double cycles_per_sample;
|
||||
|
||||
// Samples are NOT normalized to MAX_CH_AMP * 4 at this stage!
|
||||
unsigned cycles_since_render;
|
||||
unsigned last_update[GB_N_CHANNELS];
|
||||
GB_sample_t current_sample[GB_N_CHANNELS];
|
||||
GB_sample_t summed_samples[GB_N_CHANNELS];
|
||||
double dac_discharge[GB_N_CHANNELS];
|
||||
|
||||
GB_highpass_mode_t highpass_mode;
|
||||
double highpass_rate;
|
||||
GB_double_sample_t highpass_diff;
|
||||
|
||||
GB_sample_callback_t sample_callback;
|
||||
|
||||
bool rate_set_in_clocks;
|
||||
} GB_apu_output_t;
|
||||
|
||||
void GB_set_sample_rate(GB_gameboy_t *gb, unsigned sample_rate);
|
||||
void GB_set_sample_rate_by_clocks(GB_gameboy_t *gb, double cycles_per_sample); /* Cycles are in 8MHz units */
|
||||
void GB_set_highpass_filter_mode(GB_gameboy_t *gb, GB_highpass_mode_t mode);
|
||||
void GB_apu_set_sample_callback(GB_gameboy_t *gb, GB_sample_callback_t callback);
|
||||
#ifdef GB_INTERNAL
|
||||
bool GB_apu_is_DAC_enabled(GB_gameboy_t *gb, unsigned index);
|
||||
void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value);
|
||||
uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg);
|
||||
void GB_apu_div_event(GB_gameboy_t *gb);
|
||||
void GB_apu_init(GB_gameboy_t *gb);
|
||||
void GB_apu_run(GB_gameboy_t *gb);
|
||||
void GB_apu_update_cycles_per_sample(GB_gameboy_t *gb);
|
||||
void GB_borrow_sgb_border(GB_gameboy_t *gb);
|
||||
#endif
|
||||
|
||||
#endif /* apu_h */
|
|
@ -0,0 +1,149 @@
|
|||
#include "gb.h"
|
||||
|
||||
static signed noise_seed = 0;
|
||||
|
||||
/* This is not a complete emulation of the camera chip. Only the features used by the GameBoy Camera ROMs are supported.
|
||||
We also do not emulate the timing of the real cart, as it might be actually faster than the webcam. */
|
||||
|
||||
static uint8_t generate_noise(uint8_t x, uint8_t y)
|
||||
{
|
||||
signed value = (x + y * 128 + noise_seed);
|
||||
uint8_t *data = (uint8_t *) &value;
|
||||
unsigned hash = 0;
|
||||
|
||||
while ((signed *) data != &value + 1) {
|
||||
hash ^= (*data << 8);
|
||||
if (hash & 0x8000) {
|
||||
hash ^= 0x8a00;
|
||||
hash ^= *data;
|
||||
}
|
||||
data++;
|
||||
hash <<= 1;
|
||||
}
|
||||
return (hash >> 8);
|
||||
}
|
||||
|
||||
static long get_processed_color(GB_gameboy_t *gb, uint8_t x, uint8_t y)
|
||||
{
|
||||
if (x >= 128) {
|
||||
x = 0;
|
||||
}
|
||||
if (y >= 112) {
|
||||
y = 0;
|
||||
}
|
||||
|
||||
long color = gb->camera_get_pixel_callback? gb->camera_get_pixel_callback(gb, x, y) : (generate_noise(x, y));
|
||||
|
||||
static const double gain_values[] =
|
||||
{0.8809390, 0.9149149, 0.9457498, 0.9739758,
|
||||
1.0000000, 1.0241412, 1.0466537, 1.0677433,
|
||||
1.0875793, 1.1240310, 1.1568911, 1.1868043,
|
||||
1.2142561, 1.2396208, 1.2743837, 1.3157323,
|
||||
1.3525190, 1.3856512, 1.4157897, 1.4434309,
|
||||
1.4689574, 1.4926697, 1.5148087, 1.5355703,
|
||||
1.5551159, 1.5735801, 1.5910762, 1.6077008,
|
||||
1.6235366, 1.6386550, 1.6531183, 1.6669808};
|
||||
/* Multiply color by gain value */
|
||||
color *= gain_values[gb->camera_registers[GB_CAMERA_GAIN_AND_EDGE_ENHACEMENT_FLAGS] & 0x1F];
|
||||
|
||||
|
||||
/* Color is multiplied by the exposure register to simulate exposure. */
|
||||
color = color * ((gb->camera_registers[GB_CAMERA_EXPOSURE_HIGH] << 8) + gb->camera_registers[GB_CAMERA_EXPOSURE_LOW]) / 0x1000;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
uint8_t GB_camera_read_image(GB_gameboy_t *gb, uint16_t addr)
|
||||
{
|
||||
if (gb->camera_registers[GB_CAMERA_SHOOT_AND_1D_FLAGS] & 1) {
|
||||
/* Forbid reading the image while the camera is busy. */
|
||||
return 0xFF;
|
||||
}
|
||||
uint8_t tile_x = addr / 0x10 % 0x10;
|
||||
uint8_t tile_y = addr / 0x10 / 0x10;
|
||||
|
||||
uint8_t y = ((addr >> 1) & 0x7) + tile_y * 8;
|
||||
uint8_t bit = addr & 1;
|
||||
|
||||
uint8_t ret = 0;
|
||||
|
||||
for (uint8_t x = tile_x * 8; x < tile_x * 8 + 8; x++) {
|
||||
|
||||
long color = get_processed_color(gb, x, y);
|
||||
|
||||
static const double edge_enhancement_ratios[] = {0.5, 0.75, 1, 1.25, 2, 3, 4, 5};
|
||||
double edge_enhancement_ratio = edge_enhancement_ratios[(gb->camera_registers[GB_CAMERA_EDGE_ENHANCEMENT_INVERT_AND_VOLTAGE] >> 4) & 0x7];
|
||||
if ((gb->camera_registers[GB_CAMERA_GAIN_AND_EDGE_ENHACEMENT_FLAGS] & 0xE0) == 0xE0) {
|
||||
color += (color * 4) * edge_enhancement_ratio;
|
||||
color -= get_processed_color(gb, x - 1, y) * edge_enhancement_ratio;
|
||||
color -= get_processed_color(gb, x + 1, y) * edge_enhancement_ratio;
|
||||
color -= get_processed_color(gb, x, y - 1) * edge_enhancement_ratio;
|
||||
color -= get_processed_color(gb, x, y + 1) * edge_enhancement_ratio;
|
||||
}
|
||||
|
||||
|
||||
/* The camera's registers are used as a threshold pattern, which defines the dithering */
|
||||
uint8_t pattern_base = ((x & 3) + (y & 3) * 4) * 3 + GB_CAMERA_DITHERING_PATTERN_START;
|
||||
|
||||
if (color < gb->camera_registers[pattern_base]) {
|
||||
color = 3;
|
||||
}
|
||||
else if (color < gb->camera_registers[pattern_base + 1]) {
|
||||
color = 2;
|
||||
}
|
||||
else if (color < gb->camera_registers[pattern_base + 2]) {
|
||||
color = 1;
|
||||
}
|
||||
else {
|
||||
color = 0;
|
||||
}
|
||||
|
||||
ret <<= 1;
|
||||
ret |= (color >> bit) & 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GB_set_camera_get_pixel_callback(GB_gameboy_t *gb, GB_camera_get_pixel_callback_t callback)
|
||||
{
|
||||
gb->camera_get_pixel_callback = callback;
|
||||
}
|
||||
|
||||
void GB_set_camera_update_request_callback(GB_gameboy_t *gb, GB_camera_update_request_callback_t callback)
|
||||
{
|
||||
gb->camera_update_request_callback = callback;
|
||||
}
|
||||
|
||||
void GB_camera_updated(GB_gameboy_t *gb)
|
||||
{
|
||||
gb->camera_registers[GB_CAMERA_SHOOT_AND_1D_FLAGS] &= ~1;
|
||||
}
|
||||
|
||||
void GB_camera_write_register(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
{
|
||||
addr &= 0x7F;
|
||||
if (addr == GB_CAMERA_SHOOT_AND_1D_FLAGS) {
|
||||
value &= 0x7;
|
||||
noise_seed = rand();
|
||||
if ((value & 1) && !(gb->camera_registers[GB_CAMERA_SHOOT_AND_1D_FLAGS] & 1) && gb->camera_update_request_callback) {
|
||||
/* If no callback is set, ignore the write as if the camera is instantly done */
|
||||
gb->camera_registers[GB_CAMERA_SHOOT_AND_1D_FLAGS] |= 1;
|
||||
gb->camera_update_request_callback(gb);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (addr >= 0x36) {
|
||||
GB_log(gb, "Wrote invalid camera register %02x: %2x\n", addr, value);
|
||||
return;
|
||||
}
|
||||
gb->camera_registers[addr] = value;
|
||||
}
|
||||
}
|
||||
uint8_t GB_camera_read_register(GB_gameboy_t *gb, uint16_t addr)
|
||||
{
|
||||
if ((addr & 0x7F) == 0) {
|
||||
return gb->camera_registers[GB_CAMERA_SHOOT_AND_1D_FLAGS];
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef camera_h
|
||||
#define camera_h
|
||||
#include <stdint.h>
|
||||
#include "gb_struct_def.h"
|
||||
|
||||
typedef uint8_t (*GB_camera_get_pixel_callback_t)(GB_gameboy_t *gb, uint8_t x, uint8_t y);
|
||||
typedef void (*GB_camera_update_request_callback_t)(GB_gameboy_t *gb);
|
||||
|
||||
enum {
|
||||
GB_CAMERA_SHOOT_AND_1D_FLAGS = 0,
|
||||
GB_CAMERA_GAIN_AND_EDGE_ENHACEMENT_FLAGS = 1,
|
||||
GB_CAMERA_EXPOSURE_HIGH = 2,
|
||||
GB_CAMERA_EXPOSURE_LOW = 3,
|
||||
GB_CAMERA_EDGE_ENHANCEMENT_INVERT_AND_VOLTAGE = 4,
|
||||
GB_CAMERA_DITHERING_PATTERN_START = 6,
|
||||
GB_CAMERA_DITHERING_PATTERN_END = 0x35,
|
||||
};
|
||||
|
||||
uint8_t GB_camera_read_image(GB_gameboy_t *gb, uint16_t addr);
|
||||
|
||||
void GB_set_camera_get_pixel_callback(GB_gameboy_t *gb, GB_camera_get_pixel_callback_t callback);
|
||||
void GB_set_camera_update_request_callback(GB_gameboy_t *gb, GB_camera_update_request_callback_t callback);
|
||||
|
||||
void GB_camera_updated(GB_gameboy_t *gb);
|
||||
|
||||
void GB_camera_write_register(GB_gameboy_t *gb, uint16_t addr, uint8_t value);
|
||||
uint8_t GB_camera_read_register(GB_gameboy_t *gb, uint16_t addr);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,313 @@
|
|||
#include "gb.h"
|
||||
#include "cheats.h"
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
static inline uint8_t hash_addr(uint16_t addr)
|
||||
{
|
||||
return addr;
|
||||
}
|
||||
|
||||
static uint16_t bank_for_addr(GB_gameboy_t *gb, uint16_t addr)
|
||||
{
|
||||
if (addr < 0x4000) {
|
||||
return gb->mbc_rom0_bank;
|
||||
}
|
||||
|
||||
if (addr < 0x8000) {
|
||||
return gb->mbc_rom_bank;
|
||||
}
|
||||
|
||||
if (addr < 0xD000) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (addr < 0xE000) {
|
||||
return gb->cgb_ram_bank;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GB_apply_cheat(GB_gameboy_t *gb, uint16_t address, uint8_t *value)
|
||||
{
|
||||
if (!gb->cheat_enabled) return;
|
||||
if (!gb->boot_rom_finished) return;
|
||||
const GB_cheat_hash_t *hash = gb->cheat_hash[hash_addr(address)];
|
||||
if (hash) {
|
||||
for (unsigned i = 0; i < hash->size; i++) {
|
||||
GB_cheat_t *cheat = hash->cheats[i];
|
||||
if (cheat->address == address && cheat->enabled && (!cheat->use_old_value || cheat->old_value == *value)) {
|
||||
if (cheat->bank == GB_CHEAT_ANY_BANK || cheat->bank == bank_for_addr(gb, address)) {
|
||||
*value = cheat->value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GB_cheats_enabled(GB_gameboy_t *gb)
|
||||
{
|
||||
return gb->cheat_enabled;
|
||||
}
|
||||
|
||||
void GB_set_cheats_enabled(GB_gameboy_t *gb, bool enabled)
|
||||
{
|
||||
gb->cheat_enabled = enabled;
|
||||
}
|
||||
|
||||
void GB_add_cheat(GB_gameboy_t *gb, const char *description, uint16_t address, uint16_t bank, uint8_t value, uint8_t old_value, bool use_old_value, bool enabled)
|
||||
{
|
||||
GB_cheat_t *cheat = malloc(sizeof(*cheat));
|
||||
cheat->address = address;
|
||||
cheat->bank = bank;
|
||||
cheat->value = value;
|
||||
cheat->old_value = old_value;
|
||||
cheat->use_old_value = use_old_value;
|
||||
cheat->enabled = enabled;
|
||||
strncpy(cheat->description, description, sizeof(cheat->description));
|
||||
cheat->description[sizeof(cheat->description) - 1] = 0;
|
||||
gb->cheats = realloc(gb->cheats, (++gb->cheat_count) * sizeof(*cheat));
|
||||
gb->cheats[gb->cheat_count - 1] = cheat;
|
||||
|
||||
GB_cheat_hash_t **hash = &gb->cheat_hash[hash_addr(address)];
|
||||
if (!*hash) {
|
||||
*hash = malloc(sizeof(GB_cheat_hash_t) + sizeof(cheat));
|
||||
(*hash)->size = 1;
|
||||
(*hash)->cheats[0] = cheat;
|
||||
}
|
||||
else {
|
||||
(*hash)->size++;
|
||||
*hash = realloc(*hash, sizeof(GB_cheat_hash_t) + sizeof(cheat) * (*hash)->size);
|
||||
(*hash)->cheats[(*hash)->size - 1] = cheat;
|
||||
}
|
||||
}
|
||||
|
||||
const GB_cheat_t *const *GB_get_cheats(GB_gameboy_t *gb, size_t *size)
|
||||
{
|
||||
*size = gb->cheat_count;
|
||||
return (void *)gb->cheats;
|
||||
}
|
||||
void GB_remove_cheat(GB_gameboy_t *gb, const GB_cheat_t *cheat)
|
||||
{
|
||||
for (unsigned i = 0; i < gb->cheat_count; i++) {
|
||||
if (gb->cheats[i] == cheat) {
|
||||
gb->cheats[i] = gb->cheats[--gb->cheat_count];
|
||||
if (gb->cheat_count == 0) {
|
||||
free(gb->cheats);
|
||||
gb->cheats = NULL;
|
||||
}
|
||||
else {
|
||||
gb->cheats = realloc(gb->cheats, gb->cheat_count * sizeof(*cheat));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GB_cheat_hash_t **hash = &gb->cheat_hash[hash_addr(cheat->address)];
|
||||
for (unsigned i = 0; i < (*hash)->size; i++) {
|
||||
if ((*hash)->cheats[i] == cheat) {
|
||||
(*hash)->cheats[i] = (*hash)->cheats[(*hash)->size--];
|
||||
if ((*hash)->size == 0) {
|
||||
free(*hash);
|
||||
*hash = NULL;
|
||||
}
|
||||
else {
|
||||
*hash = malloc(sizeof(GB_cheat_hash_t) + sizeof(cheat) * (*hash)->size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free((void *)cheat);
|
||||
}
|
||||
|
||||
bool GB_import_cheat(GB_gameboy_t *gb, const char *cheat, const char *description, bool enabled)
|
||||
{
|
||||
uint8_t dummy;
|
||||
/* GameShark */
|
||||
{
|
||||
uint8_t bank;
|
||||
uint8_t value;
|
||||
uint16_t address;
|
||||
if (sscanf(cheat, "%02hhx%02hhx%04hx%c", &bank, &value, &address, &dummy) == 3) {
|
||||
if (bank >= 0x80) {
|
||||
bank &= 0xF;
|
||||
}
|
||||
GB_add_cheat(gb, description, address, bank, value, 0, false, enabled);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* GameGenie */
|
||||
{
|
||||
char stripped_cheat[10] = {0,};
|
||||
for (unsigned i = 0; i < 9 && *cheat; i++) {
|
||||
stripped_cheat[i] = *(cheat++);
|
||||
while (*cheat == '-') {
|
||||
cheat++;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the 7th character;
|
||||
stripped_cheat[7] = stripped_cheat[8];
|
||||
stripped_cheat[8] = 0;
|
||||
|
||||
uint8_t old_value;
|
||||
uint8_t value;
|
||||
uint16_t address;
|
||||
if (sscanf(stripped_cheat, "%02hhx%04hx%02hhx%c", &value, &address, &old_value, &dummy) == 3) {
|
||||
address = (uint16_t)(address >> 4) | (uint16_t)(address << 12);
|
||||
address ^= 0xF000;
|
||||
if (address > 0x7FFF) {
|
||||
return false;
|
||||
}
|
||||
old_value = (uint8_t)(old_value >> 2) | (uint8_t)(old_value << 6);
|
||||
old_value ^= 0xBA;
|
||||
GB_add_cheat(gb, description, address, GB_CHEAT_ANY_BANK, value, old_value, true, enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sscanf(stripped_cheat, "%02hhx%04hx%c", &value, &address, &dummy) == 2) {
|
||||
address = (uint16_t)(address >> 4) | (uint16_t)(address << 12);
|
||||
address ^= 0xF000;
|
||||
if (address > 0x7FFF) {
|
||||
return false;
|
||||
}
|
||||
GB_add_cheat(gb, description, address, GB_CHEAT_ANY_BANK, value, false, true, enabled);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GB_update_cheat(GB_gameboy_t *gb, const GB_cheat_t *_cheat, const char *description, uint16_t address, uint16_t bank, uint8_t value, uint8_t old_value, bool use_old_value, bool enabled)
|
||||
{
|
||||
GB_cheat_t *cheat = NULL;
|
||||
for (unsigned i = 0; i < gb->cheat_count; i++) {
|
||||
if (gb->cheats[i] == _cheat) {
|
||||
cheat = gb->cheats[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(cheat);
|
||||
|
||||
if (cheat->address != address) {
|
||||
/* Remove from old bucket */
|
||||
GB_cheat_hash_t **hash = &gb->cheat_hash[hash_addr(cheat->address)];
|
||||
for (unsigned i = 0; i < (*hash)->size; i++) {
|
||||
if ((*hash)->cheats[i] == cheat) {
|
||||
(*hash)->cheats[i] = (*hash)->cheats[(*hash)->size--];
|
||||
if ((*hash)->size == 0) {
|
||||
free(*hash);
|
||||
*hash = NULL;
|
||||
}
|
||||
else {
|
||||
*hash = malloc(sizeof(GB_cheat_hash_t) + sizeof(cheat) * (*hash)->size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
cheat->address = address;
|
||||
|
||||
/* Add to new bucket */
|
||||
hash = &gb->cheat_hash[hash_addr(address)];
|
||||
if (!*hash) {
|
||||
*hash = malloc(sizeof(GB_cheat_hash_t) + sizeof(cheat));
|
||||
(*hash)->size = 1;
|
||||
(*hash)->cheats[0] = cheat;
|
||||
}
|
||||
else {
|
||||
(*hash)->size++;
|
||||
*hash = malloc(sizeof(GB_cheat_hash_t) + sizeof(cheat) * (*hash)->size);
|
||||
(*hash)->cheats[(*hash)->size - 1] = cheat;
|
||||
}
|
||||
}
|
||||
cheat->bank = bank;
|
||||
cheat->value = value;
|
||||
cheat->old_value = old_value;
|
||||
cheat->use_old_value = use_old_value;
|
||||
cheat->enabled = enabled;
|
||||
if (description != cheat->description) {
|
||||
strncpy(cheat->description, description, sizeof(cheat->description));
|
||||
cheat->description[sizeof(cheat->description) - 1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define CHEAT_MAGIC 'SBCh'
|
||||
|
||||
void GB_load_cheats(GB_gameboy_t *gb, const char *path)
|
||||
{
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (!f) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t magic = 0;
|
||||
uint32_t struct_size = 0;
|
||||
fread(&magic, sizeof(magic), 1, f);
|
||||
fread(&struct_size, sizeof(struct_size), 1, f);
|
||||
if (magic != CHEAT_MAGIC && magic != __builtin_bswap32(CHEAT_MAGIC)) {
|
||||
GB_log(gb, "The file is not a SameBoy cheat database");
|
||||
return;
|
||||
}
|
||||
|
||||
if (struct_size != sizeof(GB_cheat_t)) {
|
||||
GB_log(gb, "This cheat database is not compatible with this version of SameBoy");
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove all cheats first
|
||||
while (gb->cheats) {
|
||||
GB_remove_cheat(gb, gb->cheats[0]);
|
||||
}
|
||||
|
||||
GB_cheat_t cheat;
|
||||
while (fread(&cheat, sizeof(cheat), 1, f)) {
|
||||
if (magic == __builtin_bswap32(CHEAT_MAGIC)) {
|
||||
cheat.address = __builtin_bswap16(cheat.address);
|
||||
cheat.bank = __builtin_bswap16(cheat.bank);
|
||||
}
|
||||
cheat.description[sizeof(cheat.description) - 1] = 0;
|
||||
GB_add_cheat(gb, cheat.description, cheat.address, cheat.bank, cheat.value, cheat.old_value, cheat.use_old_value, cheat.enabled);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int GB_save_cheats(GB_gameboy_t *gb, const char *path)
|
||||
{
|
||||
if (!gb->cheat_count) return 0; // Nothing to save.
|
||||
FILE *f = fopen(path, "wb");
|
||||
if (!f) {
|
||||
GB_log(gb, "Could not dump cheat database: %s.\n", strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
|
||||
uint32_t magic = CHEAT_MAGIC;
|
||||
uint32_t struct_size = sizeof(GB_cheat_t);
|
||||
|
||||
if (fwrite(&magic, sizeof(magic), 1, f) != 1) {
|
||||
fclose(f);
|
||||
return EIO;
|
||||
}
|
||||
|
||||
if (fwrite(&struct_size, sizeof(struct_size), 1, f) != 1) {
|
||||
fclose(f);
|
||||
return EIO;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i <gb->cheat_count; i++) {
|
||||
if (fwrite(gb->cheats[i], sizeof(*gb->cheats[i]), 1, f) != 1) {
|
||||
fclose(f);
|
||||
return EIO;
|
||||
}
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
fclose(f);
|
||||
return errno;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
#ifndef cheats_h
|
||||
#define cheats_h
|
||||
#include "gb_struct_def.h"
|
||||
|
||||
#define GB_CHEAT_ANY_BANK 0xFFFF
|
||||
|
||||
typedef struct GB_cheat_s GB_cheat_t;
|
||||
|
||||
void GB_add_cheat(GB_gameboy_t *gb, const char *description, uint16_t address, uint16_t bank, uint8_t value, uint8_t old_value, bool use_old_value, bool enabled);
|
||||
void GB_update_cheat(GB_gameboy_t *gb, const GB_cheat_t *cheat, const char *description, uint16_t address, uint16_t bank, uint8_t value, uint8_t old_value, bool use_old_value, bool enabled);
|
||||
bool GB_import_cheat(GB_gameboy_t *gb, const char *cheat, const char *description, bool enabled);
|
||||
const GB_cheat_t *const *GB_get_cheats(GB_gameboy_t *gb, size_t *size);
|
||||
void GB_remove_cheat(GB_gameboy_t *gb, const GB_cheat_t *cheat);
|
||||
bool GB_cheats_enabled(GB_gameboy_t *gb);
|
||||
void GB_set_cheats_enabled(GB_gameboy_t *gb, bool enabled);
|
||||
void GB_load_cheats(GB_gameboy_t *gb, const char *path);
|
||||
int GB_save_cheats(GB_gameboy_t *gb, const char *path);
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
#ifdef GB_DISABLE_CHEATS
|
||||
#define GB_apply_cheat(...)
|
||||
#else
|
||||
void GB_apply_cheat(GB_gameboy_t *gb, uint16_t address, uint8_t *value);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
GB_cheat_t *cheats[];
|
||||
} GB_cheat_hash_t;
|
||||
|
||||
struct GB_cheat_s {
|
||||
uint16_t address;
|
||||
uint16_t bank;
|
||||
uint8_t value;
|
||||
uint8_t old_value;
|
||||
bool use_old_value;
|
||||
bool enabled;
|
||||
char description[128];
|
||||
};
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,46 @@
|
|||
#ifndef debugger_h
|
||||
#define debugger_h
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "gb_struct_def.h"
|
||||
#include "symbol_hash.h"
|
||||
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
#ifdef GB_DISABLE_DEBUGGER
|
||||
#define GB_debugger_run(gb) (void)0
|
||||
#define GB_debugger_handle_async_commands(gb) (void)0
|
||||
#define GB_debugger_ret_hook(gb) (void)0
|
||||
#define GB_debugger_call_hook(gb, addr) (void)addr
|
||||
#define GB_debugger_test_write_watchpoint(gb, addr, value) ((void)addr, (void)value)
|
||||
#define GB_debugger_test_read_watchpoint(gb, addr) (void)addr
|
||||
#define GB_debugger_add_symbol(gb, bank, address, symbol) ((void)bank, (void)address, (void)symbol)
|
||||
|
||||
#else
|
||||
void GB_debugger_run(GB_gameboy_t *gb);
|
||||
void GB_debugger_handle_async_commands(GB_gameboy_t *gb);
|
||||
void GB_debugger_call_hook(GB_gameboy_t *gb, uint16_t call_addr);
|
||||
void GB_debugger_ret_hook(GB_gameboy_t *gb);
|
||||
void GB_debugger_test_write_watchpoint(GB_gameboy_t *gb, uint16_t addr, uint8_t value);
|
||||
void GB_debugger_test_read_watchpoint(GB_gameboy_t *gb, uint16_t addr);
|
||||
const GB_bank_symbol_t *GB_debugger_find_symbol(GB_gameboy_t *gb, uint16_t addr);
|
||||
void GB_debugger_add_symbol(GB_gameboy_t *gb, uint16_t bank, uint16_t address, const char *symbol);
|
||||
#endif /* GB_DISABLE_DEBUGGER */
|
||||
#endif
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
bool /* Returns true if debugger waits for more commands. Not relevant for non-GB_INTERNAL */
|
||||
#else
|
||||
void
|
||||
#endif
|
||||
GB_debugger_execute_command(GB_gameboy_t *gb, char *input); /* Destroys input. */
|
||||
char *GB_debugger_complete_substring(GB_gameboy_t *gb, char *input, uintptr_t *context); /* Destroys input, result requires free */
|
||||
|
||||
void GB_debugger_load_symbol_file(GB_gameboy_t *gb, const char *path);
|
||||
const char *GB_debugger_name_for_address(GB_gameboy_t *gb, uint16_t addr);
|
||||
bool GB_debugger_evaluate(GB_gameboy_t *gb, const char *string, uint16_t *result, uint16_t *result_bank); /* result_bank is -1 if unused. */
|
||||
void GB_debugger_break(GB_gameboy_t *gb);
|
||||
bool GB_debugger_is_stopped(GB_gameboy_t *gb);
|
||||
void GB_debugger_set_disabled(GB_gameboy_t *gb, bool disabled);
|
||||
void GB_debugger_clear_symbols(GB_gameboy_t *gb);
|
||||
#endif /* debugger_h */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,62 @@
|
|||
#ifndef display_h
|
||||
#define display_h
|
||||
|
||||
#include "gb.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
void GB_display_run(GB_gameboy_t *gb, uint8_t cycles);
|
||||
void GB_palette_changed(GB_gameboy_t *gb, bool background_palette, uint8_t index);
|
||||
void GB_STAT_update(GB_gameboy_t *gb);
|
||||
void GB_lcd_off(GB_gameboy_t *gb);
|
||||
|
||||
enum {
|
||||
GB_OBJECT_PRIORITY_UNDEFINED, // For save state compatibility
|
||||
GB_OBJECT_PRIORITY_X,
|
||||
GB_OBJECT_PRIORITY_INDEX,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
GB_PALETTE_NONE,
|
||||
GB_PALETTE_BACKGROUND,
|
||||
GB_PALETTE_OAM,
|
||||
GB_PALETTE_AUTO,
|
||||
} GB_palette_type_t;
|
||||
|
||||
typedef enum {
|
||||
GB_MAP_AUTO,
|
||||
GB_MAP_9800,
|
||||
GB_MAP_9C00,
|
||||
} GB_map_type_t;
|
||||
|
||||
typedef enum {
|
||||
GB_TILESET_AUTO,
|
||||
GB_TILESET_8800,
|
||||
GB_TILESET_8000,
|
||||
} GB_tileset_type_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t image[128];
|
||||
uint8_t x, y, tile, flags;
|
||||
uint16_t oam_addr;
|
||||
bool obscured_by_line_limit;
|
||||
} GB_oam_info_t;
|
||||
|
||||
typedef enum {
|
||||
GB_COLOR_CORRECTION_DISABLED,
|
||||
GB_COLOR_CORRECTION_CORRECT_CURVES,
|
||||
GB_COLOR_CORRECTION_EMULATE_HARDWARE,
|
||||
GB_COLOR_CORRECTION_PRESERVE_BRIGHTNESS,
|
||||
GB_COLOR_CORRECTION_REDUCE_CONTRAST,
|
||||
} GB_color_correction_mode_t;
|
||||
|
||||
void GB_draw_tileset(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette_type, uint8_t palette_index);
|
||||
void GB_draw_tilemap(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette_type, uint8_t palette_index, GB_map_type_t map_type, GB_tileset_type_t tileset_type);
|
||||
uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest, uint8_t *sprite_height);
|
||||
uint32_t GB_convert_rgb15(GB_gameboy_t *gb, uint16_t color, bool for_border);
|
||||
void GB_set_color_correction_mode(GB_gameboy_t *gb, GB_color_correction_mode_t mode);
|
||||
bool GB_is_odd_frame(GB_gameboy_t *gb);
|
||||
#endif /* display_h */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,816 @@
|
|||
#ifndef GB_h
|
||||
#define GB_h
|
||||
#define typeof __typeof__
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "gb_struct_def.h"
|
||||
#include "save_state.h"
|
||||
|
||||
#include "apu.h"
|
||||
#include "camera.h"
|
||||
#include "debugger.h"
|
||||
#include "display.h"
|
||||
#include "joypad.h"
|
||||
#include "mbc.h"
|
||||
#include "memory.h"
|
||||
#include "printer.h"
|
||||
#include "timing.h"
|
||||
#include "rewind.h"
|
||||
#include "sm83_cpu.h"
|
||||
#include "symbol_hash.h"
|
||||
#include "sgb.h"
|
||||
#include "cheats.h"
|
||||
#include "rumble.h"
|
||||
#include "workboy.h"
|
||||
|
||||
#define GB_STRUCT_VERSION 13
|
||||
|
||||
#define GB_MODEL_FAMILY_MASK 0xF00
|
||||
#define GB_MODEL_DMG_FAMILY 0x000
|
||||
#define GB_MODEL_MGB_FAMILY 0x100
|
||||
#define GB_MODEL_CGB_FAMILY 0x200
|
||||
#define GB_MODEL_PAL_BIT 0x1000
|
||||
#define GB_MODEL_NO_SFC_BIT 0x2000
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
#if __clang__
|
||||
#define UNROLL _Pragma("unroll")
|
||||
#elif __GNUC__ >= 8
|
||||
#define UNROLL _Pragma("GCC unroll 8")
|
||||
#else
|
||||
#define UNROLL
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#define GB_BIG_ENDIAN
|
||||
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define GB_LITTLE_ENDIAN
|
||||
#else
|
||||
#error Unable to detect endianess
|
||||
#endif
|
||||
|
||||
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)
|
||||
#define __builtin_bswap16(x) ({ typeof(x) _x = (x); _x >> 8 | _x << 8; })
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
uint8_t r, g, b;
|
||||
} colors[5];
|
||||
} GB_palette_t;
|
||||
|
||||
extern const GB_palette_t GB_PALETTE_GREY;
|
||||
extern const GB_palette_t GB_PALETTE_DMG;
|
||||
extern const GB_palette_t GB_PALETTE_MGB;
|
||||
extern const GB_palette_t GB_PALETTE_GBL;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint8_t seconds;
|
||||
uint8_t minutes;
|
||||
uint8_t hours;
|
||||
uint8_t days;
|
||||
uint8_t high;
|
||||
};
|
||||
uint8_t data[5];
|
||||
} GB_rtc_time_t;
|
||||
|
||||
typedef enum {
|
||||
// GB_MODEL_DMG_0 = 0x000,
|
||||
// GB_MODEL_DMG_A = 0x001,
|
||||
GB_MODEL_DMG_B = 0x002,
|
||||
// GB_MODEL_DMG_C = 0x003,
|
||||
GB_MODEL_SGB = 0x004,
|
||||
GB_MODEL_SGB_NTSC = GB_MODEL_SGB,
|
||||
GB_MODEL_SGB_PAL = GB_MODEL_SGB | GB_MODEL_PAL_BIT,
|
||||
GB_MODEL_SGB_NTSC_NO_SFC = GB_MODEL_SGB | GB_MODEL_NO_SFC_BIT,
|
||||
GB_MODEL_SGB_NO_SFC = GB_MODEL_SGB_NTSC_NO_SFC,
|
||||
GB_MODEL_SGB_PAL_NO_SFC = GB_MODEL_SGB | GB_MODEL_NO_SFC_BIT | GB_MODEL_PAL_BIT,
|
||||
// GB_MODEL_MGB = 0x100,
|
||||
GB_MODEL_SGB2 = 0x101,
|
||||
GB_MODEL_SGB2_NO_SFC = GB_MODEL_SGB2 | GB_MODEL_NO_SFC_BIT,
|
||||
// GB_MODEL_CGB_0 = 0x200,
|
||||
// GB_MODEL_CGB_A = 0x201,
|
||||
// GB_MODEL_CGB_B = 0x202,
|
||||
GB_MODEL_CGB_C = 0x203,
|
||||
// GB_MODEL_CGB_D = 0x204,
|
||||
GB_MODEL_CGB_E = 0x205,
|
||||
GB_MODEL_AGB = 0x206,
|
||||
} GB_model_t;
|
||||
|
||||
enum {
|
||||
GB_REGISTER_AF,
|
||||
GB_REGISTER_BC,
|
||||
GB_REGISTER_DE,
|
||||
GB_REGISTER_HL,
|
||||
GB_REGISTER_SP,
|
||||
GB_REGISTERS_16_BIT /* Count */
|
||||
};
|
||||
|
||||
/* Todo: Actually use these! */
|
||||
enum {
|
||||
GB_CARRY_FLAG = 16,
|
||||
GB_HALF_CARRY_FLAG = 32,
|
||||
GB_SUBTRACT_FLAG = 64,
|
||||
GB_ZERO_FLAG = 128,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
GB_BORDER_SGB,
|
||||
GB_BORDER_NEVER,
|
||||
GB_BORDER_ALWAYS,
|
||||
} GB_border_mode_t;
|
||||
|
||||
#define GB_MAX_IR_QUEUE 256
|
||||
|
||||
enum {
|
||||
/* Joypad and Serial */
|
||||
GB_IO_JOYP = 0x00, // Joypad (R/W)
|
||||
GB_IO_SB = 0x01, // Serial transfer data (R/W)
|
||||
GB_IO_SC = 0x02, // Serial Transfer Control (R/W)
|
||||
|
||||
/* Missing */
|
||||
|
||||
/* Timers */
|
||||
GB_IO_DIV = 0x04, // Divider Register (R/W)
|
||||
GB_IO_TIMA = 0x05, // Timer counter (R/W)
|
||||
GB_IO_TMA = 0x06, // Timer Modulo (R/W)
|
||||
GB_IO_TAC = 0x07, // Timer Control (R/W)
|
||||
|
||||
/* Missing */
|
||||
|
||||
GB_IO_IF = 0x0f, // Interrupt Flag (R/W)
|
||||
|
||||
/* Sound */
|
||||
GB_IO_NR10 = 0x10, // Channel 1 Sweep register (R/W)
|
||||
GB_IO_NR11 = 0x11, // Channel 1 Sound length/Wave pattern duty (R/W)
|
||||
GB_IO_NR12 = 0x12, // Channel 1 Volume Envelope (R/W)
|
||||
GB_IO_NR13 = 0x13, // Channel 1 Frequency lo (Write Only)
|
||||
GB_IO_NR14 = 0x14, // Channel 1 Frequency hi (R/W)
|
||||
/* NR20 does not exist */
|
||||
GB_IO_NR21 = 0x16, // Channel 2 Sound Length/Wave Pattern Duty (R/W)
|
||||
GB_IO_NR22 = 0x17, // Channel 2 Volume Envelope (R/W)
|
||||
GB_IO_NR23 = 0x18, // Channel 2 Frequency lo data (W)
|
||||
GB_IO_NR24 = 0x19, // Channel 2 Frequency hi data (R/W)
|
||||
GB_IO_NR30 = 0x1a, // Channel 3 Sound on/off (R/W)
|
||||
GB_IO_NR31 = 0x1b, // Channel 3 Sound Length
|
||||
GB_IO_NR32 = 0x1c, // Channel 3 Select output level (R/W)
|
||||
GB_IO_NR33 = 0x1d, // Channel 3 Frequency's lower data (W)
|
||||
GB_IO_NR34 = 0x1e, // Channel 3 Frequency's higher data (R/W)
|
||||
/* NR40 does not exist */
|
||||
GB_IO_NR41 = 0x20, // Channel 4 Sound Length (R/W)
|
||||
GB_IO_NR42 = 0x21, // Channel 4 Volume Envelope (R/W)
|
||||
GB_IO_NR43 = 0x22, // Channel 4 Polynomial Counter (R/W)
|
||||
GB_IO_NR44 = 0x23, // Channel 4 Counter/consecutive, Inital (R/W)
|
||||
GB_IO_NR50 = 0x24, // Channel control / ON-OFF / Volume (R/W)
|
||||
GB_IO_NR51 = 0x25, // Selection of Sound output terminal (R/W)
|
||||
GB_IO_NR52 = 0x26, // Sound on/off
|
||||
|
||||
/* Missing */
|
||||
|
||||
GB_IO_WAV_START = 0x30, // Wave pattern start
|
||||
GB_IO_WAV_END = 0x3f, // Wave pattern end
|
||||
|
||||
/* Graphics */
|
||||
GB_IO_LCDC = 0x40, // LCD Control (R/W)
|
||||
GB_IO_STAT = 0x41, // LCDC Status (R/W)
|
||||
GB_IO_SCY = 0x42, // Scroll Y (R/W)
|
||||
GB_IO_SCX = 0x43, // Scroll X (R/W)
|
||||
GB_IO_LY = 0x44, // LCDC Y-Coordinate (R)
|
||||
GB_IO_LYC = 0x45, // LY Compare (R/W)
|
||||
GB_IO_DMA = 0x46, // DMA Transfer and Start Address (W)
|
||||
GB_IO_BGP = 0x47, // BG Palette Data (R/W) - Non CGB Mode Only
|
||||
GB_IO_OBP0 = 0x48, // Object Palette 0 Data (R/W) - Non CGB Mode Only
|
||||
GB_IO_OBP1 = 0x49, // Object Palette 1 Data (R/W) - Non CGB Mode Only
|
||||
GB_IO_WY = 0x4a, // Window Y Position (R/W)
|
||||
GB_IO_WX = 0x4b, // Window X Position minus 7 (R/W)
|
||||
// Has some undocumented compatibility flags written at boot.
|
||||
// Unfortunately it is not readable or writable after boot has finished, so research of this
|
||||
// register is quite limited. The value written to this register, however, can be controlled
|
||||
// in some cases.
|
||||
GB_IO_KEY0 = 0x4c,
|
||||
|
||||
/* General CGB features */
|
||||
GB_IO_KEY1 = 0x4d, // CGB Mode Only - Prepare Speed Switch
|
||||
|
||||
/* Missing */
|
||||
|
||||
GB_IO_VBK = 0x4f, // CGB Mode Only - VRAM Bank
|
||||
GB_IO_BANK = 0x50, // Write to disable the BIOS mapping
|
||||
|
||||
/* CGB DMA */
|
||||
GB_IO_HDMA1 = 0x51, // CGB Mode Only - New DMA Source, High
|
||||
GB_IO_HDMA2 = 0x52, // CGB Mode Only - New DMA Source, Low
|
||||
GB_IO_HDMA3 = 0x53, // CGB Mode Only - New DMA Destination, High
|
||||
GB_IO_HDMA4 = 0x54, // CGB Mode Only - New DMA Destination, Low
|
||||
GB_IO_HDMA5 = 0x55, // CGB Mode Only - New DMA Length/Mode/Start
|
||||
|
||||
/* IR */
|
||||
GB_IO_RP = 0x56, // CGB Mode Only - Infrared Communications Port
|
||||
|
||||
/* Missing */
|
||||
|
||||
/* CGB Paletts */
|
||||
GB_IO_BGPI = 0x68, // CGB Mode Only - Background Palette Index
|
||||
GB_IO_BGPD = 0x69, // CGB Mode Only - Background Palette Data
|
||||
GB_IO_OBPI = 0x6a, // CGB Mode Only - Sprite Palette Index
|
||||
GB_IO_OBPD = 0x6b, // CGB Mode Only - Sprite Palette Data
|
||||
GB_IO_OPRI = 0x6c, // Affects object priority (X based or index based)
|
||||
|
||||
/* Missing */
|
||||
|
||||
GB_IO_SVBK = 0x70, // CGB Mode Only - WRAM Bank
|
||||
GB_IO_UNKNOWN2 = 0x72, // (00h) - Bit 0-7 (Read/Write)
|
||||
GB_IO_UNKNOWN3 = 0x73, // (00h) - Bit 0-7 (Read/Write)
|
||||
GB_IO_UNKNOWN4 = 0x74, // (00h) - Bit 0-7 (Read/Write) - CGB Mode Only
|
||||
GB_IO_UNKNOWN5 = 0x75, // (8Fh) - Bit 4-6 (Read/Write)
|
||||
GB_IO_PCM_12 = 0x76, // Channels 1 and 2 amplitudes
|
||||
GB_IO_PCM_34 = 0x77, // Channels 3 and 4 amplitudes
|
||||
GB_IO_UNKNOWN8 = 0x7F, // Unknown, write only
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
GB_LOG_BOLD = 1,
|
||||
GB_LOG_DASHED_UNDERLINE = 2,
|
||||
GB_LOG_UNDERLINE = 4,
|
||||
GB_LOG_UNDERLINE_MASK = GB_LOG_DASHED_UNDERLINE | GB_LOG_UNDERLINE
|
||||
} GB_log_attributes;
|
||||
|
||||
typedef enum {
|
||||
GB_BOOT_ROM_DMG0,
|
||||
GB_BOOT_ROM_DMG,
|
||||
GB_BOOT_ROM_MGB,
|
||||
GB_BOOT_ROM_SGB,
|
||||
GB_BOOT_ROM_SGB2,
|
||||
GB_BOOT_ROM_CGB0,
|
||||
GB_BOOT_ROM_CGB,
|
||||
GB_BOOT_ROM_AGB,
|
||||
} GB_boot_rom_t;
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
#define LCDC_PERIOD 70224
|
||||
#define CPU_FREQUENCY 0x400000
|
||||
#define SGB_NTSC_FREQUENCY (21477272 / 5)
|
||||
#define SGB_PAL_FREQUENCY (21281370 / 5)
|
||||
#define DIV_CYCLES (0x100)
|
||||
#define INTERNAL_DIV_CYCLES (0x40000)
|
||||
|
||||
#if !defined(MIN)
|
||||
#define MIN(A, B) ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __a : __b; })
|
||||
#endif
|
||||
|
||||
#if !defined(MAX)
|
||||
#define MAX(A, B) ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __b : __a; })
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef void (*GB_vblank_callback_t)(GB_gameboy_t *gb);
|
||||
typedef void (*GB_log_callback_t)(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes);
|
||||
typedef char *(*GB_input_callback_t)(GB_gameboy_t *gb);
|
||||
typedef uint32_t (*GB_rgb_encode_callback_t)(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b);
|
||||
typedef void (*GB_infrared_callback_t)(GB_gameboy_t *gb, bool on, uint64_t cycles_since_last_update);
|
||||
typedef void (*GB_rumble_callback_t)(GB_gameboy_t *gb, double rumble_amplitude);
|
||||
typedef void (*GB_serial_transfer_bit_start_callback_t)(GB_gameboy_t *gb, bool bit_to_send);
|
||||
typedef bool (*GB_serial_transfer_bit_end_callback_t)(GB_gameboy_t *gb);
|
||||
typedef void (*GB_update_input_hint_callback_t)(GB_gameboy_t *gb);
|
||||
typedef void (*GB_joyp_write_callback_t)(GB_gameboy_t *gb, uint8_t value);
|
||||
typedef void (*GB_icd_pixel_callback_t)(GB_gameboy_t *gb, uint8_t row);
|
||||
typedef void (*GB_icd_hreset_callback_t)(GB_gameboy_t *gb);
|
||||
typedef void (*GB_icd_vreset_callback_t)(GB_gameboy_t *gb);
|
||||
typedef void (*GB_boot_rom_load_callback_t)(GB_gameboy_t *gb, GB_boot_rom_t type);
|
||||
|
||||
typedef struct {
|
||||
bool state;
|
||||
uint64_t delay;
|
||||
} GB_ir_queue_item_t;
|
||||
|
||||
struct GB_breakpoint_s;
|
||||
struct GB_watchpoint_s;
|
||||
|
||||
typedef struct {
|
||||
uint8_t pixel; // Color, 0-3
|
||||
uint8_t palette; // Palette, 0 - 7 (CGB); 0-1 in DMG (or just 0 for BG)
|
||||
uint8_t priority; // Sprite priority – 0 in DMG, OAM index in CGB
|
||||
bool bg_priority; // For sprite FIFO – the BG priority bit. For the BG FIFO – the CGB attributes priority bit
|
||||
} GB_fifo_item_t;
|
||||
|
||||
#define GB_FIFO_LENGTH 16
|
||||
typedef struct {
|
||||
GB_fifo_item_t fifo[GB_FIFO_LENGTH];
|
||||
uint8_t read_end;
|
||||
uint8_t write_end;
|
||||
} GB_fifo_t;
|
||||
|
||||
/* When state saving, each section is dumped independently of other sections.
|
||||
This allows adding data to the end of the section without worrying about future compatibility.
|
||||
Some other changes might be "safe" as well.
|
||||
This struct is not packed, but dumped sections exclusively use types that have the same alignment in both 32 and 64
|
||||
bit platforms. */
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
struct GB_gameboy_s {
|
||||
#else
|
||||
struct GB_gameboy_internal_s {
|
||||
#endif
|
||||
GB_SECTION(header,
|
||||
/* The magic makes sure a state file is:
|
||||
- Indeed a SameBoy state file.
|
||||
- Has the same endianess has the current platform. */
|
||||
volatile uint32_t magic;
|
||||
/* The version field makes sure we don't load save state files with a completely different structure.
|
||||
This happens when struct fields are removed/resized in an backward incompatible manner. */
|
||||
uint32_t version;
|
||||
);
|
||||
|
||||
GB_SECTION(core_state,
|
||||
/* Registers */
|
||||
uint16_t pc;
|
||||
union {
|
||||
uint16_t registers[GB_REGISTERS_16_BIT];
|
||||
struct {
|
||||
uint16_t af,
|
||||
bc,
|
||||
de,
|
||||
hl,
|
||||
sp;
|
||||
};
|
||||
struct {
|
||||
#ifdef GB_BIG_ENDIAN
|
||||
uint8_t a, f,
|
||||
b, c,
|
||||
d, e,
|
||||
h, l;
|
||||
#else
|
||||
uint8_t f, a,
|
||||
c, b,
|
||||
e, d,
|
||||
l, h;
|
||||
#endif
|
||||
};
|
||||
|
||||
};
|
||||
uint8_t ime;
|
||||
uint8_t interrupt_enable;
|
||||
uint8_t cgb_ram_bank;
|
||||
|
||||
/* CPU and General Hardware Flags*/
|
||||
GB_model_t model;
|
||||
bool cgb_mode;
|
||||
bool cgb_double_speed;
|
||||
bool halted;
|
||||
bool stopped;
|
||||
bool boot_rom_finished;
|
||||
bool ime_toggle; /* ei has delayed a effect.*/
|
||||
bool halt_bug;
|
||||
bool just_halted;
|
||||
|
||||
/* Misc state */
|
||||
bool infrared_input;
|
||||
GB_printer_t printer;
|
||||
uint8_t extra_oam[0xff00 - 0xfea0];
|
||||
uint32_t ram_size; // Different between CGB and DMG
|
||||
GB_workboy_t workboy;
|
||||
);
|
||||
|
||||
/* DMA and HDMA */
|
||||
GB_SECTION(dma,
|
||||
bool hdma_on;
|
||||
bool hdma_on_hblank;
|
||||
uint8_t hdma_steps_left;
|
||||
int16_t hdma_cycles; // in 8MHz units
|
||||
uint16_t hdma_current_src, hdma_current_dest;
|
||||
|
||||
uint8_t dma_steps_left;
|
||||
uint8_t dma_current_dest;
|
||||
uint16_t dma_current_src;
|
||||
int16_t dma_cycles;
|
||||
bool is_dma_restarting;
|
||||
uint8_t last_opcode_read; /* Required to emulte HDMA reads from Exxx */
|
||||
bool hdma_starting;
|
||||
);
|
||||
|
||||
/* MBC */
|
||||
GB_SECTION(mbc,
|
||||
uint16_t mbc_rom_bank;
|
||||
uint8_t mbc_ram_bank;
|
||||
uint32_t mbc_ram_size;
|
||||
bool mbc_ram_enable;
|
||||
union {
|
||||
struct {
|
||||
uint8_t bank_low:5;
|
||||
uint8_t bank_high:2;
|
||||
uint8_t mode:1;
|
||||
} mbc1;
|
||||
|
||||
struct {
|
||||
uint8_t rom_bank:4;
|
||||
} mbc2;
|
||||
|
||||
struct {
|
||||
uint8_t rom_bank:8;
|
||||
uint8_t ram_bank:3;
|
||||
} mbc3;
|
||||
|
||||
struct {
|
||||
uint8_t rom_bank_low;
|
||||
uint8_t rom_bank_high:1;
|
||||
uint8_t ram_bank:4;
|
||||
} mbc5;
|
||||
|
||||
struct {
|
||||
uint8_t bank_low:6;
|
||||
uint8_t bank_high:3;
|
||||
bool mode:1;
|
||||
bool ir_mode:1;
|
||||
} huc1;
|
||||
|
||||
struct {
|
||||
uint8_t rom_bank:7;
|
||||
uint8_t padding:1;
|
||||
uint8_t ram_bank:4;
|
||||
} huc3;
|
||||
};
|
||||
uint16_t mbc_rom0_bank; /* For some MBC1 wirings. */
|
||||
bool camera_registers_mapped;
|
||||
uint8_t camera_registers[0x36];
|
||||
bool rumble_state;
|
||||
bool cart_ir;
|
||||
|
||||
// TODO: move to huc3/mbc3 struct when breaking save compat
|
||||
uint8_t huc3_mode;
|
||||
uint8_t huc3_access_index;
|
||||
uint16_t huc3_minutes, huc3_days;
|
||||
uint16_t huc3_alarm_minutes, huc3_alarm_days;
|
||||
bool huc3_alarm_enabled;
|
||||
uint8_t huc3_read;
|
||||
uint8_t huc3_access_flags;
|
||||
bool mbc3_rtc_mapped;
|
||||
);
|
||||
|
||||
|
||||
/* HRAM and HW Registers */
|
||||
GB_SECTION(hram,
|
||||
uint8_t hram[0xFFFF - 0xFF80];
|
||||
uint8_t io_registers[0x80];
|
||||
);
|
||||
|
||||
/* Timing */
|
||||
GB_SECTION(timing,
|
||||
GB_UNIT(display);
|
||||
GB_UNIT(div);
|
||||
uint16_t div_counter;
|
||||
uint8_t tima_reload_state; /* After TIMA overflows, it becomes 0 for 4 cycles before actually reloading. */
|
||||
uint16_t serial_cycles;
|
||||
uint16_t serial_length;
|
||||
uint8_t double_speed_alignment;
|
||||
uint8_t serial_count;
|
||||
);
|
||||
|
||||
/* APU */
|
||||
GB_SECTION(apu,
|
||||
GB_apu_t apu;
|
||||
);
|
||||
|
||||
/* RTC */
|
||||
GB_SECTION(rtc,
|
||||
GB_rtc_time_t rtc_real, rtc_latched;
|
||||
uint64_t last_rtc_second;
|
||||
bool rtc_latch;
|
||||
);
|
||||
|
||||
/* Video Display */
|
||||
GB_SECTION(video,
|
||||
uint32_t vram_size; // Different between CGB and DMG
|
||||
uint8_t cgb_vram_bank;
|
||||
uint8_t oam[0xA0];
|
||||
uint8_t background_palettes_data[0x40];
|
||||
uint8_t sprite_palettes_data[0x40];
|
||||
uint8_t position_in_line;
|
||||
bool stat_interrupt_line;
|
||||
uint8_t effective_scx;
|
||||
uint8_t window_y;
|
||||
/* The LCDC will skip the first frame it renders after turning it on.
|
||||
On the CGB, a frame is not skipped if the previous frame was skipped as well.
|
||||
See https://www.reddit.com/r/EmuDev/comments/6exyxu/ */
|
||||
|
||||
/* TODO: Drop this and properly emulate the dropped vreset signal*/
|
||||
enum {
|
||||
GB_FRAMESKIP_LCD_TURNED_ON, // On a DMG, the LCD renders a blank screen during this state,
|
||||
// on a CGB, the previous frame is repeated (which might be
|
||||
// blank if the LCD was off for more than a few cycles)
|
||||
GB_FRAMESKIP_FIRST_FRAME_SKIPPED, // This state is 'skipped' when emulating a DMG
|
||||
GB_FRAMESKIP_SECOND_FRAME_RENDERED,
|
||||
} frame_skip_state;
|
||||
bool oam_read_blocked;
|
||||
bool vram_read_blocked;
|
||||
bool oam_write_blocked;
|
||||
bool vram_write_blocked;
|
||||
bool fifo_insertion_glitch;
|
||||
uint8_t current_line;
|
||||
uint16_t ly_for_comparison;
|
||||
GB_fifo_t bg_fifo, oam_fifo;
|
||||
uint8_t fetcher_x;
|
||||
uint8_t fetcher_y;
|
||||
uint16_t cycles_for_line;
|
||||
uint8_t current_tile;
|
||||
uint8_t current_tile_attributes;
|
||||
uint8_t current_tile_data[2];
|
||||
uint8_t fetcher_state;
|
||||
bool window_is_being_fetched;
|
||||
bool wx166_glitch;
|
||||
bool wx_triggered;
|
||||
uint8_t visible_objs[10];
|
||||
uint8_t obj_comparators[10];
|
||||
uint8_t n_visible_objs;
|
||||
uint8_t oam_search_index;
|
||||
uint8_t accessed_oam_row;
|
||||
uint8_t extra_penalty_for_sprite_at_0;
|
||||
uint8_t mode_for_interrupt;
|
||||
bool lyc_interrupt_line;
|
||||
bool cgb_palettes_blocked;
|
||||
uint8_t current_lcd_line; // The LCD can go out of sync since the vsync signal is skipped in some cases.
|
||||
uint32_t cycles_in_stop_mode;
|
||||
uint8_t object_priority;
|
||||
bool oam_ppu_blocked;
|
||||
bool vram_ppu_blocked;
|
||||
bool cgb_palettes_ppu_blocked;
|
||||
bool object_fetch_aborted;
|
||||
bool during_object_fetch;
|
||||
uint16_t object_low_line_address;
|
||||
bool wy_triggered;
|
||||
uint8_t window_tile_x;
|
||||
uint8_t lcd_x; // The LCD can go out of sync since the push signal is skipped in some cases.
|
||||
bool is_odd_frame;
|
||||
uint16_t last_tile_data_address;
|
||||
uint16_t last_tile_index_address;
|
||||
bool cgb_repeated_a_frame;
|
||||
);
|
||||
|
||||
/* Unsaved data. This includes all pointers, as well as everything that shouldn't be on a save state */
|
||||
/* This data is reserved on reset and must come last in the struct */
|
||||
GB_SECTION(unsaved,
|
||||
/* ROM */
|
||||
uint8_t *rom;
|
||||
uint32_t rom_size;
|
||||
const GB_cartridge_t *cartridge_type;
|
||||
enum {
|
||||
GB_STANDARD_MBC1_WIRING,
|
||||
GB_MBC1M_WIRING,
|
||||
} mbc1_wiring;
|
||||
bool is_mbc30;
|
||||
|
||||
unsigned pending_cycles;
|
||||
|
||||
/* Various RAMs */
|
||||
uint8_t *ram;
|
||||
uint8_t *vram;
|
||||
uint8_t *mbc_ram;
|
||||
|
||||
/* I/O */
|
||||
uint32_t *screen;
|
||||
uint32_t background_palettes_rgb[0x20];
|
||||
uint32_t sprite_palettes_rgb[0x20];
|
||||
const GB_palette_t *dmg_palette;
|
||||
GB_color_correction_mode_t color_correction_mode;
|
||||
bool keys[4][GB_KEY_MAX];
|
||||
GB_border_mode_t border_mode;
|
||||
GB_sgb_border_t borrowed_border;
|
||||
bool tried_loading_sgb_border;
|
||||
bool has_sgb_border;
|
||||
|
||||
/* Timing */
|
||||
uint64_t last_sync;
|
||||
uint64_t cycles_since_last_sync; // In 8MHz units
|
||||
|
||||
/* Audio */
|
||||
GB_apu_output_t apu_output;
|
||||
|
||||
/* Callbacks */
|
||||
void *user_data;
|
||||
GB_log_callback_t log_callback;
|
||||
GB_input_callback_t input_callback;
|
||||
GB_input_callback_t async_input_callback;
|
||||
GB_rgb_encode_callback_t rgb_encode_callback;
|
||||
GB_vblank_callback_t vblank_callback;
|
||||
GB_infrared_callback_t infrared_callback;
|
||||
GB_camera_get_pixel_callback_t camera_get_pixel_callback;
|
||||
GB_camera_update_request_callback_t camera_update_request_callback;
|
||||
GB_rumble_callback_t rumble_callback;
|
||||
GB_serial_transfer_bit_start_callback_t serial_transfer_bit_start_callback;
|
||||
GB_serial_transfer_bit_end_callback_t serial_transfer_bit_end_callback;
|
||||
GB_update_input_hint_callback_t update_input_hint_callback;
|
||||
GB_joyp_write_callback_t joyp_write_callback;
|
||||
GB_icd_pixel_callback_t icd_pixel_callback;
|
||||
GB_icd_vreset_callback_t icd_hreset_callback;
|
||||
GB_icd_vreset_callback_t icd_vreset_callback;
|
||||
GB_read_memory_callback_t read_memory_callback;
|
||||
GB_boot_rom_load_callback_t boot_rom_load_callback;
|
||||
GB_print_image_callback_t printer_callback;
|
||||
GB_workboy_set_time_callback workboy_set_time_callback;
|
||||
GB_workboy_get_time_callback workboy_get_time_callback;
|
||||
|
||||
/* IR */
|
||||
uint64_t cycles_since_ir_change; // In 8MHz units
|
||||
uint64_t cycles_since_input_ir_change; // In 8MHz units
|
||||
GB_ir_queue_item_t ir_queue[GB_MAX_IR_QUEUE];
|
||||
size_t ir_queue_length;
|
||||
|
||||
/*** Debugger ***/
|
||||
volatile bool debug_stopped, debug_disable;
|
||||
bool debug_fin_command, debug_next_command;
|
||||
|
||||
/* Breakpoints */
|
||||
uint16_t n_breakpoints;
|
||||
struct GB_breakpoint_s *breakpoints;
|
||||
bool has_jump_to_breakpoints, has_software_breakpoints;
|
||||
void *nontrivial_jump_state;
|
||||
bool non_trivial_jump_breakpoint_occured;
|
||||
|
||||
/* SLD (Todo: merge with backtrace) */
|
||||
bool stack_leak_detection;
|
||||
signed debug_call_depth;
|
||||
uint16_t sp_for_call_depth[0x200]; /* Should be much more than enough */
|
||||
uint16_t addr_for_call_depth[0x200];
|
||||
|
||||
/* Backtrace */
|
||||
unsigned backtrace_size;
|
||||
uint16_t backtrace_sps[0x200];
|
||||
struct {
|
||||
uint16_t bank;
|
||||
uint16_t addr;
|
||||
} backtrace_returns[0x200];
|
||||
|
||||
/* Watchpoints */
|
||||
uint16_t n_watchpoints;
|
||||
struct GB_watchpoint_s *watchpoints;
|
||||
|
||||
/* Symbol tables */
|
||||
GB_symbol_map_t *bank_symbols[0x200];
|
||||
GB_reversed_symbol_map_t reversed_symbol_map;
|
||||
|
||||
/* Ticks command */
|
||||
uint64_t debugger_ticks;
|
||||
|
||||
/* Rewind */
|
||||
#define GB_REWIND_FRAMES_PER_KEY 255
|
||||
size_t rewind_buffer_length;
|
||||
struct {
|
||||
uint8_t *key_state;
|
||||
uint8_t *compressed_states[GB_REWIND_FRAMES_PER_KEY];
|
||||
unsigned pos;
|
||||
} *rewind_sequences; // lasts about 4 seconds
|
||||
size_t rewind_pos;
|
||||
|
||||
/* SGB - saved and allocated optionally */
|
||||
GB_sgb_t *sgb;
|
||||
|
||||
double sgb_intro_jingle_phases[7];
|
||||
double sgb_intro_sweep_phase;
|
||||
double sgb_intro_sweep_previous_sample;
|
||||
|
||||
/* Cheats */
|
||||
bool cheat_enabled;
|
||||
size_t cheat_count;
|
||||
GB_cheat_t **cheats;
|
||||
GB_cheat_hash_t *cheat_hash[256];
|
||||
|
||||
/* Misc */
|
||||
bool turbo;
|
||||
bool turbo_dont_skip;
|
||||
bool disable_rendering;
|
||||
uint8_t boot_rom[0x900];
|
||||
bool vblank_just_occured; // For slow operations involving syscalls; these should only run once per vblank
|
||||
uint8_t cycles_since_run; // How many cycles have passed since the last call to GB_run(), in 8MHz units
|
||||
double clock_multiplier;
|
||||
GB_rumble_mode_t rumble_mode;
|
||||
uint32_t rumble_on_cycles;
|
||||
uint32_t rumble_off_cycles;
|
||||
|
||||
/* Temporary state */
|
||||
bool wx_just_changed;
|
||||
);
|
||||
};
|
||||
|
||||
#ifndef GB_INTERNAL
|
||||
struct GB_gameboy_s {
|
||||
char __internal[sizeof(struct GB_gameboy_internal_s)];
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef __printflike
|
||||
/* Missing from Linux headers. */
|
||||
#define __printflike(fmtarg, firstvararg) \
|
||||
__attribute__((__format__ (__printf__, fmtarg, firstvararg)))
|
||||
#endif
|
||||
|
||||
void GB_init(GB_gameboy_t *gb, GB_model_t model);
|
||||
bool GB_is_inited(GB_gameboy_t *gb);
|
||||
bool GB_is_cgb(GB_gameboy_t *gb);
|
||||
bool GB_is_sgb(GB_gameboy_t *gb); // Returns true if the model is SGB or SGB2
|
||||
bool GB_is_hle_sgb(GB_gameboy_t *gb); // Returns true if the model is SGB or SGB2 and the SFC/SNES side is HLE'd
|
||||
GB_model_t GB_get_model(GB_gameboy_t *gb);
|
||||
void GB_free(GB_gameboy_t *gb);
|
||||
void GB_reset(GB_gameboy_t *gb);
|
||||
void GB_switch_model_and_reset(GB_gameboy_t *gb, GB_model_t model);
|
||||
|
||||
/* Returns the time passed, in 8MHz ticks. */
|
||||
uint8_t GB_run(GB_gameboy_t *gb);
|
||||
/* Returns the time passed since the last frame, in nanoseconds */
|
||||
uint64_t GB_run_frame(GB_gameboy_t *gb);
|
||||
|
||||
typedef enum {
|
||||
GB_DIRECT_ACCESS_ROM,
|
||||
GB_DIRECT_ACCESS_RAM,
|
||||
GB_DIRECT_ACCESS_CART_RAM,
|
||||
GB_DIRECT_ACCESS_VRAM,
|
||||
GB_DIRECT_ACCESS_HRAM,
|
||||
GB_DIRECT_ACCESS_IO, /* Warning: Some registers can only be read/written correctly via GB_memory_read/write. */
|
||||
GB_DIRECT_ACCESS_BOOTROM,
|
||||
GB_DIRECT_ACCESS_OAM,
|
||||
GB_DIRECT_ACCESS_BGP,
|
||||
GB_DIRECT_ACCESS_OBP,
|
||||
GB_DIRECT_ACCESS_IE,
|
||||
} GB_direct_access_t;
|
||||
|
||||
/* Returns a mutable pointer to various hardware memories. If that memory is banked, the current bank
|
||||
is returned at *bank, even if only a portion of the memory is banked. */
|
||||
void *GB_get_direct_access(GB_gameboy_t *gb, GB_direct_access_t access, size_t *size, uint16_t *bank);
|
||||
|
||||
void *GB_get_user_data(GB_gameboy_t *gb);
|
||||
void GB_set_user_data(GB_gameboy_t *gb, void *data);
|
||||
|
||||
|
||||
|
||||
int GB_load_boot_rom(GB_gameboy_t *gb, const char *path);
|
||||
void GB_load_boot_rom_from_buffer(GB_gameboy_t *gb, const unsigned char *buffer, size_t size);
|
||||
int GB_load_rom(GB_gameboy_t *gb, const char *path);
|
||||
void GB_load_rom_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t size);
|
||||
int GB_load_isx(GB_gameboy_t *gb, const char *path);
|
||||
|
||||
int GB_save_battery_size(GB_gameboy_t *gb);
|
||||
int GB_save_battery_to_buffer(GB_gameboy_t *gb, uint8_t *buffer, size_t size);
|
||||
int GB_save_battery(GB_gameboy_t *gb, const char *path);
|
||||
|
||||
void GB_load_battery_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t size);
|
||||
void GB_load_battery(GB_gameboy_t *gb, const char *path);
|
||||
|
||||
void GB_set_turbo_mode(GB_gameboy_t *gb, bool on, bool no_frame_skip);
|
||||
void GB_set_rendering_disabled(GB_gameboy_t *gb, bool disabled);
|
||||
|
||||
void GB_log(GB_gameboy_t *gb, const char *fmt, ...) __printflike(2, 3);
|
||||
void GB_attributed_log(GB_gameboy_t *gb, GB_log_attributes attributes, const char *fmt, ...) __printflike(3, 4);
|
||||
|
||||
void GB_set_pixels_output(GB_gameboy_t *gb, uint32_t *output);
|
||||
void GB_set_border_mode(GB_gameboy_t *gb, GB_border_mode_t border_mode);
|
||||
|
||||
void GB_set_infrared_input(GB_gameboy_t *gb, bool state);
|
||||
void GB_queue_infrared_input(GB_gameboy_t *gb, bool state, uint64_t cycles_after_previous_change); /* In 8MHz units*/
|
||||
|
||||
void GB_set_vblank_callback(GB_gameboy_t *gb, GB_vblank_callback_t callback);
|
||||
void GB_set_log_callback(GB_gameboy_t *gb, GB_log_callback_t callback);
|
||||
void GB_set_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback);
|
||||
void GB_set_async_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback);
|
||||
void GB_set_rgb_encode_callback(GB_gameboy_t *gb, GB_rgb_encode_callback_t callback);
|
||||
void GB_set_infrared_callback(GB_gameboy_t *gb, GB_infrared_callback_t callback);
|
||||
void GB_set_rumble_callback(GB_gameboy_t *gb, GB_rumble_callback_t callback);
|
||||
void GB_set_update_input_hint_callback(GB_gameboy_t *gb, GB_update_input_hint_callback_t callback);
|
||||
/* Called when a new boot ROM is needed. The callback should call GB_load_boot_rom or GB_load_boot_rom_from_buffer */
|
||||
void GB_set_boot_rom_load_callback(GB_gameboy_t *gb, GB_boot_rom_load_callback_t callback);
|
||||
|
||||
void GB_set_palette(GB_gameboy_t *gb, const GB_palette_t *palette);
|
||||
|
||||
/* These APIs are used when using internal clock */
|
||||
void GB_set_serial_transfer_bit_start_callback(GB_gameboy_t *gb, GB_serial_transfer_bit_start_callback_t callback);
|
||||
void GB_set_serial_transfer_bit_end_callback(GB_gameboy_t *gb, GB_serial_transfer_bit_end_callback_t callback);
|
||||
|
||||
/* These APIs are used when using external clock */
|
||||
bool GB_serial_get_data_bit(GB_gameboy_t *gb);
|
||||
void GB_serial_set_data_bit(GB_gameboy_t *gb, bool data);
|
||||
|
||||
void GB_disconnect_serial(GB_gameboy_t *gb);
|
||||
|
||||
/* For cartridges with an alarm clock */
|
||||
unsigned GB_time_to_alarm(GB_gameboy_t *gb); // 0 if no alarm
|
||||
|
||||
/* For integration with SFC/SNES emulators */
|
||||
void GB_set_joyp_write_callback(GB_gameboy_t *gb, GB_joyp_write_callback_t callback);
|
||||
void GB_set_icd_pixel_callback(GB_gameboy_t *gb, GB_icd_pixel_callback_t callback);
|
||||
void GB_set_icd_hreset_callback(GB_gameboy_t *gb, GB_icd_hreset_callback_t callback);
|
||||
void GB_set_icd_vreset_callback(GB_gameboy_t *gb, GB_icd_vreset_callback_t callback);
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
uint32_t GB_get_clock_rate(GB_gameboy_t *gb);
|
||||
#endif
|
||||
void GB_set_clock_multiplier(GB_gameboy_t *gb, double multiplier);
|
||||
|
||||
unsigned GB_get_screen_width(GB_gameboy_t *gb);
|
||||
unsigned GB_get_screen_height(GB_gameboy_t *gb);
|
||||
double GB_get_usual_frame_rate(GB_gameboy_t *gb);
|
||||
unsigned GB_get_player_count(GB_gameboy_t *gb);
|
||||
|
||||
#endif /* GB_h */
|
|
@ -0,0 +1,5 @@
|
|||
#ifndef gb_struct_def_h
|
||||
#define gb_struct_def_h
|
||||
struct GB_gameboy_s;
|
||||
typedef struct GB_gameboy_s GB_gameboy_t;
|
||||
#endif
|
|
@ -0,0 +1,522 @@
|
|||
static const uint16_t palette[] = {
|
||||
0x410A, 0x0421, 0x35AD, 0x4A52, 0x7FFF, 0x2D49, 0x0C42, 0x1484,
|
||||
0x18A5, 0x20C6, 0x6718, 0x5D6E, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
};
|
||||
|
||||
static const uint16_t tilemap[] = {
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0003, 0x0003, 0x0004, 0x0004,
|
||||
0x0004, 0x0004, 0x0004, 0x0004, 0x0005, 0x0005, 0x0005, 0x0005,
|
||||
0x0005, 0x0005, 0x0005, 0x0005, 0x0004, 0x0004, 0x0004, 0x0004,
|
||||
0x0004, 0x0004, 0x0003, 0x0003, 0x0003, 0x4002, 0x4001, 0x0000,
|
||||
0x0000, 0x0006, 0x0007, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
|
||||
0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
|
||||
0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
|
||||
0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x4007, 0x4006, 0x0000,
|
||||
0x0000, 0x0009, 0x0008, 0x0008, 0x0008, 0x000A, 0x000B, 0x000B,
|
||||
0x000B, 0x000B, 0x000B, 0x000B, 0x000B, 0x000B, 0x000B, 0x000B,
|
||||
0x000B, 0x000B, 0x000B, 0x000B, 0x000B, 0x000B, 0x000B, 0x000B,
|
||||
0x000B, 0x000B, 0x400A, 0x0008, 0x0008, 0x0008, 0xC009, 0x0000,
|
||||
0x0000, 0x000C, 0x0008, 0x0008, 0x0008, 0x000D, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC00D, 0x0008, 0x0008, 0x0008, 0x400C, 0x0000,
|
||||
0x0000, 0x000E, 0x0008, 0x0008, 0x0008, 0x000D, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC00D, 0x0008, 0x0008, 0x0008, 0xC00E, 0x0000,
|
||||
0x0000, 0x000F, 0x0008, 0x0008, 0x0008, 0x000D, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC00D, 0x0008, 0x0008, 0x0008, 0x400F, 0x0000,
|
||||
0x0000, 0x0010, 0x0008, 0x0008, 0x0008, 0x000D, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC00D, 0x0008, 0x0008, 0x0008, 0xC010, 0x0000,
|
||||
0x0000, 0x0010, 0x0008, 0x0008, 0x0008, 0x000D, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC00D, 0x0008, 0x0008, 0x0008, 0xC010, 0x0000,
|
||||
0x0000, 0x0011, 0x0008, 0x0008, 0x0008, 0x000D, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC00D, 0x0008, 0x0008, 0x0008, 0xC011, 0x0000,
|
||||
0x0000, 0x0011, 0x0008, 0x0008, 0x0008, 0x000D, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC00D, 0x0008, 0x0008, 0x0008, 0xC011, 0x0000,
|
||||
0x0000, 0x0012, 0x0008, 0x0008, 0x0008, 0x000D, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC00D, 0x0008, 0x0008, 0x0008, 0x4012, 0x0000,
|
||||
0x0000, 0x0013, 0x0008, 0x0008, 0x0008, 0x000D, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC00D, 0x0008, 0x0008, 0x0008, 0xC013, 0x0000,
|
||||
0x0014, 0x0015, 0x0008, 0x0008, 0x0008, 0x000D, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC00D, 0x0008, 0x0008, 0x0008, 0x4015, 0x4014,
|
||||
0x0016, 0x0017, 0x0008, 0x0008, 0x0008, 0x000D, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC00D, 0x0008, 0x0008, 0x0008, 0xC017, 0xC016,
|
||||
0x0016, 0x0017, 0x0008, 0x0008, 0x0008, 0x000D, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC00D, 0x0008, 0x0008, 0x0008, 0xC017, 0xC016,
|
||||
0x0018, 0x0019, 0x0008, 0x0008, 0x0008, 0x000D, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC00D, 0x0008, 0x0008, 0x0008, 0x4019, 0x4018,
|
||||
0x001A, 0x001B, 0x0008, 0x0008, 0x0008, 0x000D, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC00D, 0x0008, 0x0008, 0x0008, 0xC01B, 0xC01A,
|
||||
0x001C, 0x001D, 0x0008, 0x0008, 0x0008, 0x000D, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC00D, 0x0008, 0x0008, 0x0008, 0x401D, 0x401C,
|
||||
0x001E, 0x0008, 0x0008, 0x0008, 0x0008, 0x000D, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC00D, 0x0008, 0x0008, 0x0008, 0x0008, 0xC01E,
|
||||
0x001E, 0x0008, 0x0008, 0x0008, 0x0008, 0x000D, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC00D, 0x0008, 0x0008, 0x0008, 0x0008, 0xC01E,
|
||||
0x001E, 0x0008, 0x0008, 0x0008, 0x0008, 0x000D, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC00D, 0x0008, 0x0008, 0x0008, 0x0008, 0xC01E,
|
||||
0x001F, 0x801D, 0x0008, 0x0008, 0x0008, 0x0020, 0x0021, 0x0022,
|
||||
0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A,
|
||||
0x002B, 0x002C, 0x002D, 0x002D, 0x002D, 0x002D, 0x002D, 0x002D,
|
||||
0x002E, 0x0021, 0x4020, 0x0008, 0x0008, 0x0008, 0xC01D, 0x401F,
|
||||
0x002F, 0x0030, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0031,
|
||||
0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039,
|
||||
0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x0040, 0x0041,
|
||||
0x0042, 0x0043, 0x0008, 0x0008, 0x0008, 0x0008, 0x4030, 0x402F,
|
||||
0x0044, 0x0045, 0x0046, 0x0047, 0x0008, 0x0008, 0x0048, 0x0049,
|
||||
0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, 0x0051,
|
||||
0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059,
|
||||
0x005A, 0x005B, 0x0008, 0x0008, 0x4047, 0x4046, 0x4045, 0x4044,
|
||||
0x0000, 0x0000, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060, 0x0061,
|
||||
0x0061, 0x0062, 0x0063, 0x0063, 0x0063, 0x0063, 0x0063, 0x0063,
|
||||
0x0063, 0x0063, 0x0063, 0x0063, 0x0063, 0x0063, 0x4062, 0x0061,
|
||||
0x0061, 0x4060, 0x405F, 0x405E, 0x405D, 0x405C, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
};
|
||||
|
||||
const uint8_t tiles[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1F, 0x01,
|
||||
0x7F, 0x1F, 0xFF, 0x7E, 0xFF, 0xE1, 0xFF, 0x9F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x1E,
|
||||
0x1F, 0x60, 0x7F, 0x80, 0xFF, 0x00, 0xBF, 0x40,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x03, 0x01, 0x07, 0x03, 0x07, 0x03, 0x07, 0x06,
|
||||
0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06,
|
||||
0x01, 0x02, 0x03, 0x04, 0x03, 0x04, 0x06, 0x01,
|
||||
0x06, 0x01, 0x06, 0x01, 0x06, 0x01, 0x06, 0x01,
|
||||
0xFF, 0xBF, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xBF, 0x40, 0x7F, 0x80, 0x7F, 0x80, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E,
|
||||
0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E,
|
||||
0x0E, 0x01, 0x0E, 0x01, 0x0E, 0x01, 0x0E, 0x01,
|
||||
0x0E, 0x01, 0x0E, 0x01, 0x0E, 0x01, 0x0E, 0x01,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFE, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x0F, 0x0E, 0x0F, 0x0E, 0x1F, 0x1B, 0x1F, 0x1B,
|
||||
0x1F, 0x1B, 0x1F, 0x1B, 0x1F, 0x1B, 0x1F, 0x1B,
|
||||
0x0E, 0x01, 0x0E, 0x01, 0x1B, 0x04, 0x1B, 0x04,
|
||||
0x1B, 0x04, 0x1B, 0x04, 0x1B, 0x04, 0x1B, 0x04,
|
||||
0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE,
|
||||
0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE,
|
||||
0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00,
|
||||
0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00,
|
||||
0x1F, 0x1B, 0x1F, 0x1B, 0x1F, 0x1B, 0x1F, 0x1B,
|
||||
0x1F, 0x1B, 0x1F, 0x1B, 0x1F, 0x1B, 0x1F, 0x1B,
|
||||
0x1B, 0x04, 0x1B, 0x04, 0x1B, 0x04, 0x1B, 0x04,
|
||||
0x1B, 0x04, 0x1B, 0x04, 0x1B, 0x04, 0x1B, 0x04,
|
||||
0x1F, 0x1B, 0x1F, 0x1B, 0x1F, 0x1B, 0x1F, 0x1B,
|
||||
0x1F, 0x1B, 0x3F, 0x37, 0x3F, 0x37, 0x3F, 0x37,
|
||||
0x1B, 0x04, 0x1B, 0x04, 0x1B, 0x04, 0x1B, 0x04,
|
||||
0x1B, 0x04, 0x37, 0x08, 0x37, 0x08, 0x37, 0x08,
|
||||
0x3F, 0x37, 0x3F, 0x37, 0x3F, 0x37, 0x3F, 0x37,
|
||||
0x3F, 0x37, 0x3F, 0x37, 0x3F, 0x37, 0x3F, 0x37,
|
||||
0x37, 0x08, 0x37, 0x08, 0x37, 0x08, 0x37, 0x08,
|
||||
0x37, 0x08, 0x37, 0x08, 0x37, 0x08, 0x37, 0x08,
|
||||
0x7F, 0x6F, 0x7F, 0x6F, 0x7F, 0x6F, 0x7F, 0x6F,
|
||||
0x7F, 0x6F, 0x7F, 0x6F, 0x7F, 0x6F, 0x7F, 0x6F,
|
||||
0x6F, 0x10, 0x6F, 0x10, 0x6F, 0x10, 0x6F, 0x10,
|
||||
0x6F, 0x10, 0x6F, 0x10, 0x6F, 0x10, 0x6F, 0x10,
|
||||
0x7F, 0x6F, 0x7F, 0x6F, 0x7F, 0x6F, 0xFF, 0xDF,
|
||||
0xFF, 0xDF, 0xFF, 0xDF, 0xFF, 0xDF, 0xFF, 0xDF,
|
||||
0x6F, 0x10, 0x6F, 0x10, 0x6F, 0x10, 0xDF, 0x20,
|
||||
0xDF, 0x20, 0xDF, 0x20, 0xDF, 0x20, 0xDF, 0x20,
|
||||
0xFF, 0xDF, 0xFF, 0xDF, 0xFF, 0xDF, 0xFF, 0xDF,
|
||||
0xFF, 0xDF, 0xFF, 0xDF, 0xFF, 0xDF, 0xFF, 0xDF,
|
||||
0xDF, 0x20, 0xDF, 0x20, 0xDF, 0x20, 0xDF, 0x20,
|
||||
0xDF, 0x20, 0xDF, 0x20, 0xDF, 0x20, 0xDF, 0x20,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
|
||||
0xFF, 0xDF, 0xFF, 0xDF, 0xFF, 0xDF, 0xFF, 0xDF,
|
||||
0xFF, 0xDF, 0xFF, 0xDF, 0xFF, 0xBF, 0xFF, 0xBF,
|
||||
0xDF, 0x20, 0xDF, 0x20, 0xDF, 0x20, 0xDF, 0x20,
|
||||
0xDF, 0x20, 0xDF, 0x20, 0xBF, 0x40, 0xBF, 0x40,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
|
||||
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
|
||||
0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
|
||||
0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
|
||||
0xBF, 0x40, 0xBF, 0x40, 0xBF, 0x40, 0xBF, 0x40,
|
||||
0xBF, 0x40, 0xBF, 0x40, 0xBF, 0x40, 0xBF, 0x40,
|
||||
0x01, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x01, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
|
||||
0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
|
||||
0xFF, 0xBF, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F,
|
||||
0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F,
|
||||
0xBF, 0x40, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
|
||||
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
|
||||
0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
|
||||
0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F,
|
||||
0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F,
|
||||
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
|
||||
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06,
|
||||
0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
|
||||
0x06, 0x01, 0x06, 0x01, 0x06, 0x01, 0x06, 0x01,
|
||||
0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06,
|
||||
0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06,
|
||||
0x06, 0x01, 0x06, 0x01, 0x06, 0x01, 0x06, 0x01,
|
||||
0x06, 0x01, 0x06, 0x01, 0x06, 0x01, 0x06, 0x01,
|
||||
0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06,
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x06, 0x01, 0x06, 0x01, 0x06, 0x01, 0x06, 0x01,
|
||||
0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
|
||||
0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFE, 0x01, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xF8, 0xFF, 0xE7, 0xF8, 0xDF, 0xE3,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xF8, 0x00, 0xE4, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x3F, 0xFF, 0xCE, 0x3F, 0xF5, 0x8E,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x3F, 0x00, 0x4E, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x1F, 0xFF, 0xEE, 0x1F, 0xB5, 0x4E,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x1F, 0x00, 0x0E, 0xA0,
|
||||
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x07, 0xFF, 0xFB, 0x07, 0x04, 0x73,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x07, 0x00, 0x03, 0x88,
|
||||
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x80, 0xFF, 0x7F, 0x80, 0x82, 0x39,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x80, 0x00, 0x01, 0x44,
|
||||
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x01, 0xFE,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x83, 0x7C,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x42, 0x01,
|
||||
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFE, 0xFF, 0xBB, 0x7C, 0x4F, 0xB0,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x7C, 0x00, 0xB1, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x07, 0xFF, 0xF9, 0x06, 0xE7, 0xF8,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x06, 0x00, 0x08, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x0E, 0xFF, 0xF5, 0x0E, 0x9B, 0x74,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x0E, 0x00, 0x94, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x1F, 0xFF, 0xF7, 0x0F, 0xBF, 0x47,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x0F, 0x00, 0xA7, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xFF,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x07, 0x07, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01,
|
||||
0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
|
||||
0x03, 0x04, 0x01, 0x02, 0x01, 0x02, 0x00, 0x01,
|
||||
0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F,
|
||||
0xFF, 0x7F, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xDF,
|
||||
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
|
||||
0x7F, 0x80, 0xBF, 0x40, 0xBF, 0x40, 0xDF, 0x20,
|
||||
0xB0, 0xD8, 0xA0, 0xD3, 0x67, 0x84, 0x47, 0xA4,
|
||||
0x61, 0x81, 0xA0, 0xD0, 0xB4, 0xCA, 0x7E, 0x81,
|
||||
0xD7, 0x08, 0xCC, 0x13, 0x98, 0x20, 0x98, 0x00,
|
||||
0x9E, 0x20, 0xCF, 0x00, 0xCD, 0x02, 0x80, 0x01,
|
||||
0x32, 0x2D, 0x13, 0x6D, 0x34, 0x48, 0xFC, 0x02,
|
||||
0x7C, 0x00, 0x78, 0x05, 0x30, 0x49, 0x20, 0x50,
|
||||
0xCD, 0x00, 0xAC, 0x40, 0x49, 0x82, 0x01, 0x02,
|
||||
0x07, 0x80, 0xC2, 0x05, 0x86, 0x41, 0x9F, 0x40,
|
||||
0x15, 0x2E, 0x09, 0x06, 0x09, 0x16, 0x0B, 0xD4,
|
||||
0xC6, 0x49, 0x8E, 0x40, 0xCF, 0xC8, 0x06, 0x01,
|
||||
0xCE, 0x20, 0xE6, 0x10, 0xE6, 0x00, 0x24, 0xD0,
|
||||
0x39, 0x80, 0x38, 0x01, 0x31, 0x00, 0xF8, 0x00,
|
||||
0x0C, 0x8B, 0x85, 0x8A, 0x03, 0x84, 0x27, 0x20,
|
||||
0x22, 0x35, 0x12, 0x34, 0x20, 0x12, 0x10, 0x20,
|
||||
0x73, 0x00, 0x72, 0x08, 0x7C, 0x80, 0xDC, 0x01,
|
||||
0xC8, 0x11, 0xC9, 0x06, 0xCD, 0x22, 0xEF, 0x10,
|
||||
0x83, 0x44, 0x86, 0x01, 0x03, 0x85, 0x26, 0x21,
|
||||
0x46, 0x69, 0x46, 0x68, 0x8E, 0xCA, 0x86, 0x88,
|
||||
0x39, 0x40, 0x78, 0x84, 0x7C, 0x80, 0xD8, 0x01,
|
||||
0x90, 0x29, 0xD1, 0x28, 0x73, 0x00, 0xB3, 0x40,
|
||||
0x00, 0x01, 0x01, 0x00, 0x3F, 0x00, 0x3F, 0x40,
|
||||
0x03, 0x02, 0x01, 0x02, 0x41, 0x7C, 0x7F, 0x00,
|
||||
0xFE, 0x00, 0xFF, 0x00, 0xC0, 0x00, 0x80, 0x40,
|
||||
0xFC, 0x00, 0xFC, 0x00, 0x80, 0x02, 0xC0, 0x00,
|
||||
0xC0, 0x00, 0x80, 0x4C, 0xCC, 0x43, 0x8E, 0x52,
|
||||
0x80, 0x4C, 0x80, 0x00, 0x12, 0x1E, 0x9E, 0x00,
|
||||
0x7F, 0x00, 0x33, 0x0C, 0x32, 0x01, 0x23, 0x50,
|
||||
0x33, 0x4C, 0x7F, 0x00, 0x61, 0x80, 0xF1, 0x00,
|
||||
0x7C, 0x02, 0x30, 0x48, 0x31, 0x40, 0x61, 0x50,
|
||||
0x87, 0xE4, 0xE3, 0x84, 0x23, 0x44, 0x43, 0x44,
|
||||
0x85, 0x42, 0x87, 0x40, 0x8F, 0x50, 0x8C, 0x12,
|
||||
0x78, 0x00, 0x18, 0x20, 0xB8, 0x00, 0x98, 0x24,
|
||||
0x03, 0x04, 0x03, 0xE0, 0xF1, 0x12, 0xF0, 0x09,
|
||||
0xF9, 0x09, 0xF9, 0x08, 0xE1, 0x12, 0xF1, 0x12,
|
||||
0xF8, 0x00, 0x1E, 0xE0, 0x0C, 0x02, 0x07, 0x08,
|
||||
0x07, 0x00, 0x06, 0x00, 0x1C, 0x02, 0x0C, 0x00,
|
||||
0x9F, 0x91, 0x86, 0x88, 0xC4, 0x4C, 0x80, 0x4C,
|
||||
0xE1, 0x20, 0xC1, 0x22, 0x23, 0xD4, 0x22, 0xD5,
|
||||
0x60, 0x00, 0xFB, 0x00, 0x37, 0x00, 0x73, 0x0C,
|
||||
0x1F, 0x00, 0x3C, 0x00, 0xC8, 0x14, 0xC9, 0x14,
|
||||
0x16, 0x2F, 0x76, 0x4F, 0x2D, 0xDE, 0xDD, 0xBE,
|
||||
0xBA, 0x7D, 0x7A, 0xFD, 0x7A, 0xFD, 0xF4, 0xF8,
|
||||
0xCF, 0x00, 0x8F, 0x00, 0x5E, 0x80, 0xBE, 0x00,
|
||||
0x7D, 0x00, 0xFC, 0x00, 0xFC, 0x01, 0xF9, 0x02,
|
||||
0xFF, 0x00, 0xBF, 0x78, 0x86, 0x09, 0x86, 0x89,
|
||||
0x06, 0x25, 0x02, 0x25, 0x42, 0x45, 0x60, 0x11,
|
||||
0x00, 0x00, 0x09, 0x00, 0x70, 0x81, 0x70, 0x09,
|
||||
0xDC, 0x21, 0xD8, 0x01, 0x98, 0x25, 0xCC, 0x13,
|
||||
0xFF, 0x00, 0xF3, 0xF8, 0x02, 0x03, 0x01, 0x30,
|
||||
0x39, 0x09, 0x30, 0x09, 0x31, 0x09, 0x20, 0x19,
|
||||
0x00, 0x00, 0x01, 0x04, 0xFC, 0x00, 0xCF, 0x30,
|
||||
0xE6, 0x00, 0xE6, 0x01, 0xE6, 0x00, 0xF6, 0x08,
|
||||
0xFF, 0x00, 0xFA, 0xC7, 0x18, 0x21, 0x09, 0x10,
|
||||
0x88, 0x99, 0x93, 0x1A, 0x83, 0x11, 0xC2, 0x41,
|
||||
0x00, 0x00, 0x00, 0x20, 0xC6, 0x21, 0xFF, 0x00,
|
||||
0x67, 0x00, 0xE4, 0x08, 0x6F, 0x10, 0x3C, 0x00,
|
||||
0xFD, 0x02, 0xB5, 0x3A, 0xC7, 0x44, 0x03, 0x84,
|
||||
0x83, 0x24, 0x21, 0xB0, 0x21, 0x12, 0x21, 0x02,
|
||||
0x02, 0x00, 0x02, 0x40, 0x3C, 0x00, 0xF8, 0x00,
|
||||
0xD8, 0x24, 0x4C, 0x92, 0xEC, 0x00, 0xCC, 0x12,
|
||||
0xFF, 0x00, 0xFF, 0xF3, 0x1C, 0x14, 0x0C, 0x04,
|
||||
0x00, 0x0C, 0x04, 0x24, 0x00, 0x24, 0x10, 0x30,
|
||||
0x00, 0x00, 0x10, 0x04, 0xE3, 0x00, 0xFB, 0x00,
|
||||
0xF3, 0x08, 0xDB, 0x20, 0xDB, 0x04, 0xCF, 0x00,
|
||||
0xFF, 0x00, 0xEC, 0x3E, 0xC1, 0x01, 0x01, 0x8E,
|
||||
0x8F, 0x10, 0x0F, 0x90, 0x0F, 0x90, 0x0D, 0x09,
|
||||
0x00, 0x00, 0x20, 0x01, 0x7E, 0x00, 0xF1, 0x0E,
|
||||
0xE0, 0x10, 0x60, 0x10, 0x60, 0x10, 0x79, 0x82,
|
||||
0xFF, 0x00, 0x7F, 0xFC, 0x03, 0x82, 0x01, 0x9E,
|
||||
0x13, 0x80, 0x03, 0x80, 0x03, 0x9C, 0x0F, 0x90,
|
||||
0x00, 0x00, 0x02, 0x00, 0x7C, 0x80, 0x60, 0x9C,
|
||||
0x60, 0x9C, 0x7C, 0x80, 0x60, 0x9C, 0x70, 0x80,
|
||||
0xFF, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF,
|
||||
0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xEF, 0xFF, 0xF7, 0x7F, 0x7B, 0x3F, 0x3C,
|
||||
0x1F, 0x1F, 0x0F, 0x0F, 0x03, 0x03, 0x00, 0x00,
|
||||
0xEF, 0x10, 0x77, 0x88, 0x3B, 0x44, 0x1C, 0x23,
|
||||
0x0F, 0x10, 0x03, 0x0C, 0x00, 0x03, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x3F, 0xFF, 0xC3, 0xFF, 0xFC, 0xFF, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x3F, 0xC0, 0xC3, 0x3C, 0xFC, 0x03, 0x3F, 0xC0,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xC1,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x3F, 0xC0, 0xC1, 0x3E,
|
||||
0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xEA, 0x14, 0xC0, 0x00, 0x80, 0x21, 0x7F, 0x92,
|
||||
0x9F, 0xE0, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x27, 0x18, 0x7F, 0x00, 0x1E, 0x61, 0x9A, 0x04,
|
||||
0xE0, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x73, 0x53, 0x47, 0x44, 0x46, 0x25, 0xFD, 0x03,
|
||||
0xF9, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x8C, 0x00, 0xD8, 0x20, 0x1D, 0xA0, 0x03, 0x00,
|
||||
0x07, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xC7, 0xE1, 0xE6, 0x05, 0x42, 0xA5, 0xBF, 0xC0,
|
||||
0x9F, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x18, 0x24, 0x38, 0x01, 0xB8, 0x05, 0xC0, 0x00,
|
||||
0xE0, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x21, 0x11, 0x31, 0x49, 0x33, 0x4A, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xDE, 0x00, 0x87, 0x48, 0x84, 0x48, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xCC, 0x02, 0x8E, 0x4A, 0xCC, 0x42, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x71, 0x08, 0x39, 0x00, 0x31, 0x02, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x3D, 0x40, 0x03, 0x02, 0x03, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xBC, 0x02, 0xFC, 0x00, 0xFE, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x12, 0x82, 0x80, 0x80, 0x01, 0x83, 0xFF, 0x00,
|
||||
0xFE, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x61, 0x1C, 0x7F, 0x00, 0x7C, 0x82, 0x00, 0x00,
|
||||
0x01, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x22, 0x52, 0x30, 0xC0, 0x58, 0xA4, 0x8F, 0x72,
|
||||
0x73, 0xFC, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x8C, 0x11, 0x4F, 0x90, 0xA3, 0x0C, 0x73, 0x00,
|
||||
0xFC, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x23, 0xA4, 0x06, 0x0D, 0x05, 0x1B, 0xBB, 0x07,
|
||||
0xE7, 0x1F, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x98, 0x44, 0xF5, 0x08, 0xEB, 0x00, 0x87, 0x40,
|
||||
0x1F, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x66, 0x85, 0xE2, 0xA5, 0x66, 0x81, 0xBF, 0xC1,
|
||||
0x99, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x99, 0x00, 0xB9, 0x00, 0x9D, 0x20, 0xC1, 0x00,
|
||||
0xE7, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xF6, 0xFA, 0xFC, 0xF2, 0xF7, 0xF8, 0xFB, 0xFC,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xF9, 0x00, 0xF1, 0x02, 0xF8, 0x00, 0xFC, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x52, 0x53, 0x30, 0x23, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x8C, 0x21, 0xCC, 0x13, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0x03, 0x03, 0x06, 0xFE, 0x01, 0xF9, 0x07,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFD, 0x02, 0xFA, 0x04, 0x01, 0x00, 0x07, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x86, 0x05, 0x46, 0xA0, 0x5F, 0xB8, 0xBF, 0xC0,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x38, 0x41, 0x99, 0x26, 0xB8, 0x00, 0xC0, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x30, 0x28, 0x09, 0x09, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xC6, 0x09, 0xE6, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x20, 0x38, 0x38, 0x20, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xD7, 0x08, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x80, 0x41, 0xA1, 0x61, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x3E, 0x40, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x01, 0x82, 0x01, 0x82, 0xFF, 0x00, 0xFC, 0x03,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x7C, 0x82, 0x7C, 0x82, 0x00, 0x00, 0x03, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x3F, 0x3F, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x3C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFE, 0xFF, 0xFF, 0x3F, 0x3F, 0x01, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFE, 0x01, 0x3F, 0xC0, 0x01, 0x3E, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x3F, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x3F, 0xC0, 0xC0, 0x3F, 0xFF, 0x00, 0x3F, 0xC0,
|
||||
0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xC0, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x00, 0x3F, 0xC0, 0xC0, 0x3F, 0xFF, 0x00,
|
||||
0x3F, 0xC0, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFC,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0x00, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x03, 0xFC, 0xFC, 0x03,
|
||||
0xFF, 0x00, 0x03, 0xFC, 0x00, 0x03, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03,
|
||||
0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x03, 0xFC,
|
||||
0xFC, 0x03, 0xFF, 0x00, 0x03, 0xFC, 0x00, 0x03,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF,
|
||||
};
|
|
@ -0,0 +1,446 @@
|
|||
static const uint16_t palette[] = {
|
||||
0x7C1A, 0x0000, 0x0011, 0x3DEF, 0x6318, 0x7FFF, 0x1EBA, 0x19AF,
|
||||
0x1EAF, 0x4648, 0x7FC0, 0x2507, 0x1484, 0x5129, 0x5010, 0x2095,
|
||||
};
|
||||
|
||||
static const uint16_t tilemap[] = {
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003,
|
||||
0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003,
|
||||
0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003,
|
||||
0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x4002, 0x4001, 0x0000,
|
||||
0x0000, 0x0004, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005,
|
||||
0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005,
|
||||
0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005,
|
||||
0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x4004, 0x0000,
|
||||
0x0000, 0x0006, 0x0005, 0x0005, 0x0005, 0x0007, 0x0008, 0x0008,
|
||||
0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
|
||||
0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
|
||||
0x0008, 0x0008, 0x4007, 0x0005, 0x0005, 0x0005, 0xC006, 0x0000,
|
||||
0x0000, 0x0006, 0x0005, 0x0005, 0x0005, 0x0009, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC009, 0x0005, 0x0005, 0x0005, 0xC006, 0x0000,
|
||||
0x0000, 0x0006, 0x0005, 0x0005, 0x0005, 0x0009, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC009, 0x0005, 0x0005, 0x0005, 0xC006, 0x0000,
|
||||
0x0000, 0x0006, 0x0005, 0x0005, 0x0005, 0x0009, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC009, 0x0005, 0x0005, 0x0005, 0xC006, 0x0000,
|
||||
0x0000, 0x0006, 0x0005, 0x0005, 0x0005, 0x0009, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC009, 0x0005, 0x0005, 0x0005, 0xC006, 0x0000,
|
||||
0x0000, 0x0006, 0x0005, 0x0005, 0x0005, 0x0009, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC009, 0x0005, 0x0005, 0x0005, 0xC006, 0x0000,
|
||||
0x0000, 0x0006, 0x000A, 0x000B, 0x400A, 0x0009, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC009, 0x0005, 0x0005, 0x0005, 0xC006, 0x0000,
|
||||
0x0000, 0x0006, 0x800A, 0x000C, 0xC00A, 0x0009, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC009, 0x0005, 0x0005, 0x0005, 0xC006, 0x0000,
|
||||
0x0000, 0x0006, 0x0005, 0x0005, 0x0005, 0x0009, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC009, 0x0005, 0x0005, 0x0005, 0xC006, 0x0000,
|
||||
0x0000, 0x0006, 0x0005, 0x0005, 0x0005, 0x0009, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC009, 0x0005, 0x0005, 0x0005, 0xC006, 0x0000,
|
||||
0x0000, 0x0006, 0x0005, 0x0005, 0x0005, 0x0009, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC009, 0x0005, 0x0005, 0x0005, 0xC006, 0x0000,
|
||||
0x0000, 0x0006, 0x0005, 0x0005, 0x0005, 0x0009, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC009, 0x0005, 0x0005, 0x0005, 0xC006, 0x0000,
|
||||
0x0000, 0x0006, 0x0005, 0x0005, 0x0005, 0x0009, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC009, 0x0005, 0x0005, 0x0005, 0xC006, 0x0000,
|
||||
0x0000, 0x0006, 0x0005, 0x0005, 0x0005, 0x0009, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC009, 0x0005, 0x0005, 0x0005, 0xC006, 0x0000,
|
||||
0x0000, 0x0006, 0x0005, 0x0005, 0x0005, 0x0009, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC009, 0x0005, 0x0005, 0x0005, 0xC006, 0x0000,
|
||||
0x0000, 0x0006, 0x0005, 0x0005, 0x0005, 0x0009, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC009, 0x0005, 0x0005, 0x0005, 0xC006, 0x0000,
|
||||
0x0000, 0x0006, 0x0005, 0x0005, 0x0005, 0x0009, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC009, 0x0005, 0x0005, 0x0005, 0xC006, 0x0000,
|
||||
0x0000, 0x0006, 0x0005, 0x0005, 0x0005, 0x0009, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC009, 0x0005, 0x0005, 0x0005, 0xC006, 0x0000,
|
||||
0x0000, 0x0006, 0x0005, 0x0005, 0x0005, 0x0009, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC009, 0x0005, 0x0005, 0x0005, 0xC006, 0x0000,
|
||||
0x0000, 0x000D, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x000E,
|
||||
0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016,
|
||||
0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E,
|
||||
0x001F, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x400D, 0x0000,
|
||||
0x0000, 0x0020, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0021,
|
||||
0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029,
|
||||
0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030, 0x0031,
|
||||
0x0032, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x4020, 0x0000,
|
||||
0x0000, 0x0033, 0x0034, 0x0035, 0x0036, 0x0005, 0x0005, 0x0037,
|
||||
0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
|
||||
0x0040, 0x0005, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046,
|
||||
0x0047, 0x0005, 0x0005, 0x4036, 0x4035, 0x4034, 0x4033, 0x0000,
|
||||
0x0000, 0x0000, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D,
|
||||
0x004E, 0x004E, 0x004F, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050,
|
||||
0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x404F, 0x004E, 0x004E,
|
||||
0x404D, 0x004C, 0x404B, 0x404A, 0x4049, 0x4048, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
|
||||
};
|
||||
|
||||
const uint8_t tiles[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x08,
|
||||
0x01, 0x11, 0x06, 0x26, 0x04, 0x24, 0x08, 0x48,
|
||||
0x00, 0x00, 0x01, 0x01, 0x07, 0x07, 0x0F, 0x0F,
|
||||
0x1E, 0x1F, 0x39, 0x3F, 0x3B, 0x3F, 0x77, 0x7F,
|
||||
0x00, 0x7F, 0x00, 0x80, 0x00, 0x00, 0x7F, 0x7F,
|
||||
0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xFF,
|
||||
0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x08, 0x48, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x77, 0x7F, 0x6F, 0x7F, 0x6F, 0x7F, 0x6F, 0x7F,
|
||||
0x6F, 0x7F, 0x6F, 0x7F, 0x6F, 0x7F, 0x6F, 0x7F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x6F, 0x7F, 0x6F, 0x7F, 0x6F, 0x7F, 0x6F, 0x7F,
|
||||
0x6F, 0x7F, 0x6F, 0x7F, 0x6F, 0x7F, 0x6F, 0x7F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
|
||||
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
|
||||
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
|
||||
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42,
|
||||
0xBD, 0xBD, 0x7E, 0x66, 0x7E, 0xFF, 0x7E, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBD, 0xFF,
|
||||
0x7E, 0xFF, 0xFF, 0xE7, 0x7E, 0x7E, 0x7E, 0x7E,
|
||||
0x7E, 0xFF, 0x3C, 0xFF, 0x81, 0xFF, 0xC3, 0xFF,
|
||||
0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x7E, 0x7E, 0x3C, 0x3C, 0x00, 0x00, 0x00, 0x81,
|
||||
0x81, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x08, 0x48, 0x08, 0x48, 0x08, 0x48, 0x08, 0x48,
|
||||
0x6F, 0x7F, 0x6F, 0x7F, 0x6F, 0x7F, 0x6F, 0x7F,
|
||||
0x37, 0x7F, 0x37, 0x7F, 0x37, 0x7F, 0x37, 0x7F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFE,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0x3F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x70,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0xDF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x78,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0xC7,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x3C,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xE3,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x80,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x9F,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x60, 0xE1,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xD8,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x27, 0x8F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x70,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0x8F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x70,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0x9F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xC2,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBD, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x10,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x3F,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xE0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x84,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x7F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x08,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF,
|
||||
0x08, 0x48, 0x08, 0x48, 0x08, 0x48, 0x08, 0x48,
|
||||
0x08, 0x48, 0x04, 0x24, 0x04, 0x24, 0x02, 0x12,
|
||||
0x37, 0x7F, 0x37, 0x7F, 0x37, 0x7F, 0x37, 0x7F,
|
||||
0x37, 0x7F, 0x1B, 0x3F, 0x1B, 0x3F, 0x0D, 0x1F,
|
||||
0x0F, 0x08, 0x0E, 0x00, 0x1E, 0x12, 0x1E, 0x12,
|
||||
0x1F, 0x10, 0x0F, 0x08, 0x02, 0x02, 0x00, 0x00,
|
||||
0xF7, 0xF8, 0xFF, 0xF0, 0xED, 0xE3, 0xED, 0xE1,
|
||||
0xEF, 0xE0, 0xF7, 0xF0, 0xFD, 0xFC, 0xFF, 0xFF,
|
||||
0xF0, 0x10, 0x40, 0x00, 0x41, 0x41, 0x00, 0x00,
|
||||
0x83, 0x82, 0xE3, 0x20, 0xC7, 0x04, 0xC7, 0x00,
|
||||
0xEF, 0x1F, 0xFF, 0x1F, 0xBE, 0xFF, 0xFF, 0xFE,
|
||||
0x7D, 0x7E, 0xDF, 0x3C, 0xFB, 0x18, 0xFF, 0x18,
|
||||
0x60, 0x00, 0x70, 0x00, 0xF8, 0x08, 0xB0, 0x00,
|
||||
0xD8, 0x40, 0x3C, 0x24, 0x5C, 0x44, 0xFC, 0x00,
|
||||
0xFF, 0x8F, 0xFF, 0x0F, 0xF7, 0x07, 0xFF, 0x07,
|
||||
0xBF, 0x47, 0xDB, 0x47, 0xBB, 0x03, 0xFF, 0x03,
|
||||
0x3C, 0x04, 0x78, 0x00, 0x78, 0x00, 0xEC, 0x80,
|
||||
0xFE, 0x92, 0xE7, 0x83, 0xE5, 0x80, 0x4F, 0x08,
|
||||
0xFB, 0x83, 0xFF, 0x83, 0xFF, 0x83, 0x7F, 0x83,
|
||||
0x6D, 0x93, 0x7C, 0x10, 0x7F, 0x10, 0xF7, 0x10,
|
||||
0x3C, 0x00, 0x7C, 0x40, 0x78, 0x00, 0xC8, 0x80,
|
||||
0xFC, 0x24, 0xBC, 0x24, 0xFD, 0x65, 0x3D, 0x25,
|
||||
0xFF, 0xC3, 0xBF, 0x83, 0xFF, 0x83, 0x7F, 0x03,
|
||||
0xDB, 0x23, 0xDB, 0x23, 0x9A, 0x67, 0xDA, 0x47,
|
||||
0xFF, 0x80, 0xFF, 0x80, 0xE0, 0x80, 0x40, 0x00,
|
||||
0xFF, 0x01, 0xFF, 0x01, 0xDF, 0x1F, 0xE0, 0x20,
|
||||
0x7F, 0x80, 0x7F, 0x00, 0x7F, 0x1F, 0xFF, 0x1F,
|
||||
0xFE, 0x00, 0xFE, 0x00, 0xE0, 0x01, 0xDF, 0x3F,
|
||||
0xBF, 0xA0, 0xB9, 0xA0, 0x10, 0x00, 0x11, 0x01,
|
||||
0x3B, 0x00, 0x3F, 0x00, 0x7E, 0x4E, 0x78, 0x48,
|
||||
0x5F, 0x40, 0x5F, 0xC0, 0xFF, 0xC7, 0xFE, 0xC7,
|
||||
0xFF, 0xC0, 0xFF, 0xC0, 0xB1, 0xC4, 0xB7, 0x8F,
|
||||
0xE3, 0x22, 0xC7, 0x04, 0xCE, 0x08, 0xE6, 0x20,
|
||||
0xCE, 0x42, 0xDE, 0x52, 0xFE, 0x32, 0xFC, 0x30,
|
||||
0xDD, 0x3E, 0xFB, 0x18, 0xF7, 0x18, 0xDF, 0x31,
|
||||
0xBD, 0x31, 0xAD, 0x23, 0xCD, 0x31, 0xCF, 0x11,
|
||||
0xFE, 0x02, 0x9E, 0x00, 0x86, 0x80, 0x06, 0x00,
|
||||
0x03, 0x00, 0x02, 0x00, 0x07, 0x01, 0x07, 0x01,
|
||||
0xFD, 0x03, 0xFF, 0x01, 0x7F, 0xF0, 0xFF, 0xF8,
|
||||
0xFF, 0xF8, 0xFF, 0xF8, 0xFE, 0xF8, 0xFE, 0xF1,
|
||||
0x38, 0x08, 0x71, 0x41, 0x1F, 0x06, 0x39, 0x20,
|
||||
0x0F, 0x00, 0x0F, 0x01, 0x04, 0x00, 0x0C, 0x00,
|
||||
0xF7, 0x87, 0xBE, 0xC6, 0xF9, 0xC6, 0xDF, 0xE0,
|
||||
0xFF, 0xE0, 0xFE, 0xF1, 0xFF, 0xF1, 0xFF, 0xF1,
|
||||
0x70, 0x10, 0xE0, 0x20, 0x80, 0x00, 0x80, 0x00,
|
||||
0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xEF, 0x1F, 0xDF, 0x1F, 0xFF, 0x3F, 0xFF, 0x7F,
|
||||
0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x3F, 0x3F, 0x7F, 0x7F, 0x78, 0x78, 0xF0, 0xF0,
|
||||
0xF0, 0xF0, 0xE0, 0xE0, 0xE0, 0xE0, 0xF0, 0xF0,
|
||||
0xDF, 0xFF, 0xBD, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF,
|
||||
0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF,
|
||||
0xE7, 0xE0, 0xFF, 0xF0, 0xFE, 0xF0, 0x1C, 0x00,
|
||||
0x3C, 0x20, 0x3C, 0x24, 0x3C, 0x24, 0x3C, 0x20,
|
||||
0xFF, 0xFF, 0xEF, 0xFF, 0x6F, 0xFF, 0xFF, 0xFF,
|
||||
0xDF, 0xFF, 0xDB, 0xFF, 0xDB, 0xFF, 0xDF, 0xFF,
|
||||
0xF8, 0x00, 0xFC, 0xC0, 0x1F, 0x03, 0x1F, 0x13,
|
||||
0x1F, 0x13, 0x1E, 0x02, 0x1E, 0x02, 0x3E, 0x02,
|
||||
0xFF, 0xFF, 0x3F, 0xFF, 0xFC, 0xFF, 0xEC, 0xFF,
|
||||
0xED, 0xFE, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF,
|
||||
0x90, 0x90, 0x00, 0x00, 0x00, 0x00, 0x21, 0x21,
|
||||
0x20, 0x21, 0x00, 0x01, 0x00, 0x01, 0x40, 0x41,
|
||||
0x8F, 0x7F, 0x1F, 0xFF, 0x1F, 0xFF, 0x3F, 0xDE,
|
||||
0x1F, 0xFE, 0x3F, 0xFE, 0x3F, 0xFE, 0x7F, 0xBE,
|
||||
0x40, 0x7F, 0x84, 0xFF, 0x11, 0xF1, 0x20, 0xE0,
|
||||
0x20, 0xE0, 0x01, 0xC1, 0x01, 0xC1, 0x22, 0xE3,
|
||||
0xFF, 0x80, 0xFF, 0x00, 0xFF, 0x0E, 0xFF, 0x1F,
|
||||
0xDF, 0x3F, 0xFE, 0x3F, 0xFF, 0x3E, 0xFD, 0x1E,
|
||||
0x47, 0xC0, 0x27, 0xE0, 0x2F, 0xE8, 0x0F, 0xE9,
|
||||
0x0F, 0xE1, 0x0F, 0xE0, 0x3F, 0xF0, 0x3F, 0xF1,
|
||||
0xF8, 0x3F, 0xF8, 0x1F, 0xF0, 0x1F, 0xF0, 0x1F,
|
||||
0xF0, 0x1F, 0xF0, 0x1F, 0xE0, 0x1F, 0xC0, 0x3F,
|
||||
0xFC, 0x00, 0xFE, 0xE2, 0x1E, 0x12, 0x1E, 0x12,
|
||||
0x3E, 0x22, 0xFC, 0x00, 0xF8, 0x08, 0xF0, 0x10,
|
||||
0x03, 0xFF, 0x01, 0xFF, 0xE1, 0xFF, 0xE1, 0xFF,
|
||||
0xC1, 0xFF, 0x03, 0xFF, 0x07, 0xFF, 0x0F, 0xFF,
|
||||
0x01, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02,
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0E, 0x1F, 0x07, 0x0F, 0x03, 0x07, 0x01, 0x03,
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x80, 0x80, 0x40, 0x40, 0x30, 0x30,
|
||||
0x0C, 0x0C, 0x03, 0xC3, 0x00, 0x30, 0x00, 0x0C,
|
||||
0xFF, 0xFF, 0x7F, 0xFF, 0xBF, 0xFF, 0xCF, 0xFF,
|
||||
0xF3, 0xFF, 0x3C, 0xFF, 0x0F, 0x3F, 0x03, 0x0F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xC0, 0xC0, 0x3C, 0x3C, 0x03, 0x03,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x3F, 0xFF, 0xC3, 0xFF, 0xFC, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE0,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF,
|
||||
0x15, 0x15, 0x3F, 0x20, 0x2F, 0x20, 0x06, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xEA, 0xE6, 0xDF, 0xC0, 0xDF, 0xE0, 0xF9, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xE6, 0x20, 0x9E, 0x12, 0x0C, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xDF, 0x30, 0xED, 0x31, 0xFF, 0x63, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x0E, 0x02, 0x1E, 0x12, 0x0D, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFD, 0x03, 0xED, 0xE1, 0xFE, 0xF1, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x4F, 0x08, 0xE6, 0x20, 0xE7, 0x21, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xF7, 0x18, 0xDF, 0x18, 0xDE, 0x18, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xB9, 0xA1, 0x11, 0x01, 0x10, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x5E, 0x46, 0xFE, 0xC6, 0xFF, 0xC6, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x3F, 0xFF, 0x01, 0xFF, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC0, 0x01, 0xFE, 0x00, 0xFE, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x7E, 0x4E, 0x3F, 0x00, 0x3E, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xB1, 0x8E, 0xFF, 0x80, 0xFF, 0x80, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xEE, 0x20, 0x8F, 0x08, 0x85, 0x84, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xDF, 0x30, 0xF7, 0x38, 0x7B, 0x7C, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xAE, 0xA2, 0xF8, 0x00, 0xE8, 0x08, 0xC0, 0xC0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x5D, 0xE1, 0xFF, 0x03, 0xF7, 0x0F, 0x3F, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x0E, 0x02, 0x1E, 0x12, 0x1E, 0x12, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFD, 0xF1, 0xED, 0xF1, 0xED, 0xE3, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFB, 0xFB, 0x7F, 0x7F, 0x3F, 0x3F, 0x0C, 0x0C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x75, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xDF, 0xC1, 0xDF, 0xD0, 0x8F, 0x88, 0x01, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFE, 0xFF, 0xEF, 0xFF, 0x77, 0xFF, 0xFE, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFA, 0x82, 0xF8, 0x08, 0xE0, 0x00, 0x81, 0x81,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x7E, 0xFD, 0xF4, 0xFF, 0xFC, 0xFF, 0x7E, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x7D, 0x7D, 0x02, 0x02, 0x02, 0x02, 0xFC, 0xFC,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0xFE, 0x01, 0xFF, 0x01, 0xFF, 0x03, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x1C, 0xFF, 0x00, 0xFF, 0x41, 0x7F, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xF7, 0x08, 0xFF, 0x00, 0xFF, 0x80, 0xE7, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x5E, 0xC2, 0x9C, 0x80, 0x1C, 0x04, 0x08, 0x08,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xE1, 0x3F, 0xE3, 0x7F, 0xE3, 0xFF, 0xF7, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xF0, 0x80, 0x78, 0x08, 0x78, 0x48, 0x10, 0x10,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0F, 0xFF, 0x87, 0xFF, 0x87, 0xFF, 0xEF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xC0, 0x00, 0x3C, 0x00, 0x03, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x3F, 0xFF, 0x03, 0x3F, 0x00, 0x03, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x1C, 0x1C, 0x03, 0x03, 0x00, 0xE0, 0x00, 0x1C,
|
||||
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xE3, 0xFF, 0xFC, 0xFF, 0x1F, 0xFF, 0x03, 0x1F,
|
||||
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFC, 0xFC, 0x03, 0x03, 0x00, 0x00,
|
||||
0x00, 0xFC, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0x03, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF,
|
||||
0x03, 0xFF, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0x3F, 0x3F,
|
||||
0x00, 0x00, 0x00, 0xC0, 0x00, 0x3F, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xC0, 0xFF,
|
||||
0xFF, 0xFF, 0x3F, 0xFF, 0x00, 0x3F, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0,
|
||||
0x3F, 0x3F, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x3F,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF,
|
||||
0xC0, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0x00, 0x3F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF
|
||||
};
|
|
@ -0,0 +1,558 @@
|
|||
static const uint16_t palette[] = {
|
||||
0x0000, 0x0011, 0x18C6, 0x001A, 0x318C, 0x39CE, 0x5294, 0x5AD6,
|
||||
0x739C, 0x45A8, 0x4520, 0x18A5, 0x4A32, 0x2033, 0x20EC, 0x0000,
|
||||
};
|
||||
|
||||
static const uint16_t tilemap[] = {
|
||||
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
|
||||
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
|
||||
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
|
||||
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
|
||||
0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002,
|
||||
0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002,
|
||||
0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002,
|
||||
0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002,
|
||||
0x0001, 0x0003, 0x0004, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005,
|
||||
0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005,
|
||||
0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005,
|
||||
0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x4004, 0x4003, 0x0001,
|
||||
0x0001, 0x0006, 0x0007, 0x0007, 0x0007, 0x0008, 0x0009, 0x000A,
|
||||
0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011, 0x0012,
|
||||
0x0013, 0x0014, 0x0015, 0x000E, 0x0016, 0x0017, 0x0018, 0x0019,
|
||||
0x001A, 0x001B, 0x001C, 0x0007, 0x0007, 0x0007, 0x4006, 0x0001,
|
||||
0x0001, 0x001D, 0x001E, 0x001E, 0x001E, 0x001F, 0x0020, 0x0021,
|
||||
0x0022, 0x0023, 0x0024, 0x0025, 0x4024, 0x0026, 0x0025, 0x0025,
|
||||
0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E,
|
||||
0x002F, 0x0030, 0x0031, 0x001E, 0x001E, 0x001E, 0xC01D, 0x0001,
|
||||
0x0001, 0x001D, 0x0032, 0x0032, 0x0032, 0x0033, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC033, 0x0032, 0x0032, 0x0032, 0xC01D, 0x0001,
|
||||
0x0001, 0x001D, 0x0032, 0x0032, 0x0032, 0x0033, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC033, 0x0032, 0x0032, 0x0032, 0xC01D, 0x0001,
|
||||
0x0001, 0x001D, 0x0032, 0x0032, 0x0032, 0x0033, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC033, 0x0032, 0x0032, 0x0032, 0xC01D, 0x0001,
|
||||
0x0001, 0x001D, 0x0032, 0x0032, 0x0032, 0x0033, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC033, 0x0032, 0x0032, 0x0032, 0xC01D, 0x0001,
|
||||
0x0001, 0x001D, 0x0032, 0x0032, 0x0032, 0x0033, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC033, 0x0032, 0x0032, 0x0032, 0xC01D, 0x0001,
|
||||
0x0001, 0x001D, 0x0034, 0x0035, 0x4034, 0x0033, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC033, 0x0032, 0x0032, 0x0032, 0xC01D, 0x0001,
|
||||
0x0001, 0x001D, 0x8034, 0x0036, 0xC034, 0x0033, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC033, 0x0032, 0x0032, 0x0032, 0xC01D, 0x0001,
|
||||
0x0001, 0x001D, 0x0032, 0x0032, 0x0032, 0x0033, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC033, 0x0032, 0x0032, 0x0032, 0xC01D, 0x0001,
|
||||
0x0001, 0x001D, 0x0032, 0x0032, 0x0032, 0x0033, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC033, 0x0032, 0x0032, 0x0032, 0xC01D, 0x0001,
|
||||
0x0001, 0x001D, 0x0032, 0x0032, 0x0032, 0x0033, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC033, 0x0032, 0x0032, 0x0032, 0xC01D, 0x0001,
|
||||
0x0001, 0x001D, 0x0032, 0x0032, 0x0032, 0x0033, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC033, 0x0032, 0x0032, 0x0032, 0xC01D, 0x0001,
|
||||
0x0001, 0x001D, 0x0032, 0x0032, 0x0032, 0x0033, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC033, 0x0032, 0x0032, 0x0032, 0xC01D, 0x0001,
|
||||
0x0001, 0x001D, 0x0032, 0x0032, 0x0032, 0x0033, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC033, 0x0032, 0x0032, 0x0032, 0xC01D, 0x0001,
|
||||
0x0001, 0x001D, 0x0032, 0x0032, 0x0032, 0x0033, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC033, 0x0032, 0x0032, 0x0032, 0xC01D, 0x0001,
|
||||
0x0001, 0x001D, 0x0032, 0x0032, 0x0032, 0x0033, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC033, 0x0032, 0x0032, 0x0032, 0xC01D, 0x0001,
|
||||
0x0001, 0x001D, 0x0032, 0x0032, 0x0032, 0x0033, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC033, 0x0032, 0x0032, 0x0032, 0x0037, 0x0001,
|
||||
0x0001, 0x001D, 0x0032, 0x0032, 0x0032, 0x0033, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC033, 0x0032, 0x0032, 0x0032, 0x0038, 0x0001,
|
||||
0x0001, 0x001D, 0x0032, 0x0032, 0x0032, 0x0033, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0xC033, 0x0032, 0x0032, 0x0039, 0x003A, 0x0001,
|
||||
0x0001, 0x003B, 0x003C, 0x0032, 0x0032, 0xC03C, 0x003D, 0x003D,
|
||||
0x003D, 0x003D, 0x003D, 0x003D, 0x003D, 0x003D, 0x003D, 0x003D,
|
||||
0x003D, 0x003D, 0x003D, 0x003D, 0x003D, 0x003D, 0x003D, 0x003D,
|
||||
0x003D, 0x003D, 0x003E, 0x003F, 0x0040, 0x0041, 0x0001, 0x0001,
|
||||
0x0001, 0x0042, 0x0043, 0x0044, 0x0044, 0x0044, 0x0044, 0x0044,
|
||||
0x0044, 0x0044, 0x0044, 0x0044, 0x0044, 0x0044, 0x0044, 0x0044,
|
||||
0x0044, 0x0044, 0x0044, 0x0044, 0x0044, 0x0044, 0x0044, 0x0044,
|
||||
0x0044, 0x0044, 0x0045, 0x0046, 0x0001, 0x0001, 0x0001, 0x0001,
|
||||
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
|
||||
0x0001, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D,
|
||||
0x004E, 0x004F, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0001,
|
||||
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
|
||||
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
|
||||
0x0001, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x005B,
|
||||
0x005C, 0x005D, 0x005E, 0x005F, 0x0060, 0x0061, 0x0001, 0x0001,
|
||||
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
|
||||
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
|
||||
0x0001, 0x0001, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
|
||||
0x0068, 0x0069, 0x006A, 0x006B, 0x0001, 0x006C, 0x0001, 0x0001,
|
||||
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
|
||||
};
|
||||
|
||||
const uint8_t tiles[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0x01, 0xFE, 0x06, 0xF9, 0x08, 0xF7,
|
||||
0x11, 0xEF, 0x22, 0xDB, 0x20, 0xDB, 0x40, 0xB7,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFE, 0x00, 0xF8, 0x00,
|
||||
0xF1, 0x00, 0xE6, 0x04, 0xE4, 0x00, 0xC8, 0x00,
|
||||
0x7F, 0x80, 0x80, 0x7F, 0x00, 0xFF, 0x7F, 0xFF,
|
||||
0x80, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x80, 0x00, 0x00, 0x00, 0x7F, 0x00,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x40, 0xB7, 0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF,
|
||||
0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF,
|
||||
0xC8, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00,
|
||||
0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x03, 0xFF, 0x02, 0xFF,
|
||||
0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00,
|
||||
0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xC1, 0xDD, 0x00, 0xC9,
|
||||
0x14, 0xFF, 0x14, 0xFF, 0x14, 0xFF, 0x00, 0xC9,
|
||||
0x00, 0x00, 0x00, 0x00, 0xE3, 0x00, 0x36, 0x22,
|
||||
0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x36, 0x22,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xC7, 0xDF, 0x01, 0xCF,
|
||||
0x11, 0xFF, 0x11, 0xFF, 0x11, 0xFF, 0x01, 0xCF,
|
||||
0x00, 0x00, 0x00, 0x00, 0xE7, 0x00, 0x31, 0x20,
|
||||
0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x31, 0x20,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xC2, 0xFF, 0x03, 0xFF,
|
||||
0x02, 0xFE, 0x02, 0xFE, 0x02, 0xFF, 0x02, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0xC2, 0x00, 0x03, 0x00,
|
||||
0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x08, 0xFF, 0x18, 0xFF,
|
||||
0x08, 0x4E, 0x08, 0x4E, 0x09, 0x1F, 0x08, 0x1C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x00,
|
||||
0xB9, 0x10, 0xB9, 0xA1, 0xE9, 0xA0, 0xEB, 0x41,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x4F, 0xFF, 0x02, 0x1F,
|
||||
0x02, 0x4F, 0x02, 0x4F, 0xF2, 0xFF, 0x02, 0xE7,
|
||||
0x00, 0x00, 0x00, 0x00, 0x4F, 0x00, 0xE2, 0xA0,
|
||||
0xB2, 0xA0, 0xB2, 0x10, 0xF2, 0x00, 0x1A, 0x10,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xBC, 0xFD, 0x22, 0xFB,
|
||||
0x22, 0xFB, 0x3C, 0xFD, 0x24, 0xFF, 0x26, 0xF9,
|
||||
0x00, 0x00, 0x00, 0x00, 0xBE, 0x00, 0x26, 0x00,
|
||||
0x26, 0x00, 0x3E, 0x00, 0x24, 0x00, 0x26, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x50, 0xFF, 0x49, 0xEF,
|
||||
0x49, 0xF0, 0x46, 0xFF, 0x49, 0xF0, 0x49, 0xEF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x59, 0x00,
|
||||
0x4F, 0x06, 0x46, 0x00, 0x4F, 0x06, 0x59, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x88, 0xFF, 0x00, 0x72,
|
||||
0x00, 0xF2, 0x05, 0xFF, 0x00, 0xF8, 0x00, 0x78,
|
||||
0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x8D, 0x08,
|
||||
0x0D, 0x05, 0x05, 0x00, 0x07, 0x05, 0x87, 0x02,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x8A, 0xFF, 0x02, 0x27,
|
||||
0x02, 0x27, 0x52, 0xFF, 0x02, 0x8F, 0x02, 0x8F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x8A, 0x00, 0xDA, 0x88,
|
||||
0xDA, 0x50, 0x52, 0x00, 0x72, 0x50, 0x72, 0x20,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xFA, 0xFF, 0x22, 0xFF,
|
||||
0x22, 0xFF, 0x23, 0xFF, 0x22, 0xFF, 0x22, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x22, 0x00,
|
||||
0x22, 0x00, 0x23, 0x00, 0x22, 0x00, 0x22, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x20, 0xFF, 0x20, 0xFF,
|
||||
0x20, 0xFF, 0xE0, 0xFF, 0x20, 0xFF, 0x20, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00,
|
||||
0x20, 0x00, 0xE0, 0x00, 0x20, 0x00, 0x20, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x33, 0x37, 0x00, 0x77,
|
||||
0x80, 0xFF, 0x20, 0x27, 0x08, 0xFF, 0x00, 0x77,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFB, 0x40, 0x88, 0x88,
|
||||
0x80, 0x00, 0xF8, 0x50, 0x08, 0x00, 0x88, 0x88,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xEF, 0xFF, 0x88, 0xFF,
|
||||
0x88, 0xFF, 0x8F, 0xFF, 0x88, 0xFF, 0x88, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0xEF, 0x00, 0x88, 0x00,
|
||||
0x88, 0x00, 0x8F, 0x00, 0x88, 0x00, 0x88, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xF9, 0xFD, 0x80, 0xF9,
|
||||
0x84, 0xFF, 0xF4, 0xFF, 0x84, 0xFF, 0x80, 0xF9,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFB, 0x00, 0x86, 0x02,
|
||||
0x84, 0x00, 0xF4, 0x00, 0x84, 0x00, 0x86, 0x02,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xC0, 0xDF, 0x00, 0xCF,
|
||||
0x10, 0xFF, 0x10, 0xFF, 0x10, 0xFF, 0x00, 0xCF,
|
||||
0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x30, 0x20,
|
||||
0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x30, 0x20,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x30, 0x36, 0x00, 0x74,
|
||||
0x82, 0xFF, 0x22, 0x27, 0x0A, 0xFF, 0x00, 0x74,
|
||||
0x00, 0x00, 0x00, 0x00, 0xF9, 0x40, 0x8B, 0x89,
|
||||
0x82, 0x00, 0xFA, 0x50, 0x0A, 0x00, 0x8B, 0x89,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xE2, 0xEF, 0x02, 0xE7,
|
||||
0x0A, 0xFF, 0x0A, 0xFF, 0x0A, 0xFF, 0x00, 0xE4,
|
||||
0x00, 0x00, 0x00, 0x00, 0xF2, 0x00, 0x1A, 0x10,
|
||||
0x0A, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x1B, 0x12,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x14, 0xFF, 0x16, 0xFF,
|
||||
0x14, 0xFC, 0x15, 0xFE, 0x14, 0xFF, 0x04, 0xCF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x16, 0x00,
|
||||
0x17, 0x01, 0x15, 0x00, 0x14, 0x00, 0x34, 0x10,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x2F, 0xFF, 0x28, 0xFF,
|
||||
0x28, 0xFF, 0xA8, 0x7F, 0x28, 0x3F, 0x68, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x28, 0x00,
|
||||
0x28, 0x00, 0xA8, 0x00, 0xE8, 0x80, 0x68, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x3F,
|
||||
0x40, 0xFF, 0x40, 0xFF, 0x40, 0xFF, 0x00, 0x3F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xC0, 0x80,
|
||||
0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xC0, 0x80,
|
||||
0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF,
|
||||
0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF,
|
||||
0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00,
|
||||
0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0xFF,
|
||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0xC1, 0xDD, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xC1, 0xDF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x02, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x4A, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x0A, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x22, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x82, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x20, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x60, 0x67, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xF8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x8F, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x8F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xA2, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xF9, 0xFD, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xC0, 0xDF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x60, 0x66, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xF9, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xE0, 0xEE, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xF1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xC4, 0xDF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xE4, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x2F, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x00, 0x7F, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x80, 0xFF,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF,
|
||||
0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF,
|
||||
0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
|
||||
0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x3C, 0xFF,
|
||||
0x7E, 0xFF, 0xE7, 0xE7, 0xFF, 0x7E, 0xFF, 0x7E,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E,
|
||||
0x81, 0xC3, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x7E, 0xFF, 0x3C, 0xFF, 0x00, 0x7E, 0x81,
|
||||
0x3C, 0xC3, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0xC3, 0x81,
|
||||
0x7E, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xF7, 0x00, 0xF7, 0x00, 0xF7, 0x00, 0xF7,
|
||||
0x00, 0xF7, 0x00, 0xED, 0x00, 0xED, 0x00, 0xED,
|
||||
0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00,
|
||||
0x09, 0x00, 0x11, 0x02, 0x11, 0x02, 0x11, 0x02,
|
||||
0x00, 0xED, 0x00, 0xDB, 0x00, 0xDB, 0x00, 0xDB,
|
||||
0x00, 0xB7, 0x00, 0xB7, 0x00, 0x6F, 0x00, 0x6F,
|
||||
0x11, 0x02, 0x23, 0x04, 0x23, 0x04, 0x23, 0x04,
|
||||
0x47, 0x08, 0x47, 0x08, 0x8F, 0x10, 0x8F, 0x10,
|
||||
0x00, 0xFE, 0x00, 0xFD, 0x00, 0xFB, 0x00, 0xF7,
|
||||
0x00, 0xEE, 0x00, 0xDD, 0x00, 0xBB, 0x00, 0x77,
|
||||
0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00,
|
||||
0x10, 0x01, 0x21, 0x02, 0x43, 0x04, 0x87, 0x08,
|
||||
0x00, 0xDF, 0x00, 0xBF, 0x00, 0xBF, 0x00, 0x7F,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x1F, 0x20, 0x3F, 0x40, 0x3F, 0x40, 0x7F, 0x80,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF, 0x00, 0xB7,
|
||||
0x00, 0xB7, 0x00, 0xDB, 0x00, 0xDD, 0x00, 0xEE,
|
||||
0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x88, 0x40,
|
||||
0x88, 0x40, 0xC4, 0x20, 0xC2, 0x20, 0xE1, 0x10,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x7F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x7F, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFC,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFC, 0x00, 0xE3, 0x00, 0x1F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x03, 0x00, 0x1C, 0x00, 0xE0, 0x00,
|
||||
0x00, 0xFE, 0x00, 0xFD, 0x00, 0xF3, 0x00, 0xEF,
|
||||
0x00, 0x1C, 0x00, 0xF3, 0x00, 0xEF, 0x00, 0x1F,
|
||||
0x01, 0x00, 0x02, 0x00, 0x0C, 0x00, 0x10, 0x00,
|
||||
0xE0, 0x03, 0x03, 0x0C, 0x0F, 0x10, 0x1F, 0xE0,
|
||||
0x00, 0xEF, 0x00, 0xDF, 0x00, 0xBF, 0x00, 0x7F,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x0F, 0x10, 0x1F, 0x20, 0x3F, 0x40, 0x7F, 0x80,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0xF7, 0x00, 0xF9, 0x00, 0xFE, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xF0, 0x08, 0xF8, 0x06, 0xFE, 0x01, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0x80, 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x80,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x7F, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x7F,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0x03, 0x00, 0xFF, 0x00, 0xFC, 0x00, 0x03,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFC, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0xFC,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0xFC, 0x00, 0xE3, 0x00, 0x1F, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0x03, 0x03, 0x1C, 0x1F, 0xE0, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x21, 0xDE, 0x00, 0x7F,
|
||||
0x0C, 0xF3, 0x19, 0xE0, 0x10, 0xEE, 0x08, 0xF7,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xC0, 0x3F, 0x80, 0xFF,
|
||||
0x00, 0xFF, 0x0E, 0xF7, 0x1F, 0xE1, 0x07, 0xF8,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0x7F, 0x00, 0xBF,
|
||||
0x40, 0xBE, 0x80, 0x3F, 0x02, 0xFD, 0x00, 0xFB,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x80, 0x7F, 0xC0,
|
||||
0x7F, 0x81, 0xFE, 0x41, 0xFC, 0x03, 0xFC, 0x07,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x08, 0xF7, 0x00, 0xFF,
|
||||
0x00, 0xFB, 0x04, 0xFB, 0x24, 0xDB, 0x64, 0x9B,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x87, 0x78, 0x07, 0xF8,
|
||||
0x07, 0xFC, 0x07, 0xF8, 0x03, 0xFC, 0x43, 0xBC,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x01, 0xDE, 0x20, 0xDF,
|
||||
0x20, 0xDF, 0x00, 0xFF, 0x04, 0xFB, 0x04, 0xFB,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xE0, 0x3F, 0xC0, 0x3F,
|
||||
0xC0, 0x3F, 0xC0, 0x3F, 0xC0, 0x3F, 0xC0, 0x3F,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFB, 0x00, 0xFF,
|
||||
0x00, 0x77, 0x00, 0x7F, 0x80, 0x6F, 0x82, 0x7D,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFC, 0x07, 0xF8, 0x07,
|
||||
0xF8, 0x8F, 0xF0, 0x8F, 0x70, 0x9F, 0x60, 0x9F,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFB, 0x24, 0xCB,
|
||||
0x24, 0xDB, 0x20, 0xDF, 0x20, 0xDF, 0x00, 0xDF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x1C, 0xE7, 0x18, 0xF7,
|
||||
0x18, 0xE7, 0x18, 0xE7, 0x38, 0xC7, 0x38, 0xE7,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x02, 0xFC,
|
||||
0x7E, 0x81, 0x80, 0x01, 0x80, 0x7F, 0xF8, 0x03,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x01, 0xFE, 0x01, 0xFF,
|
||||
0x01, 0xFE, 0x7F, 0xFE, 0x7F, 0x80, 0x07, 0xFC,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xBF, 0x40, 0xBF,
|
||||
0x47, 0xB8, 0x08, 0xF0, 0x08, 0xF7, 0x0E, 0xF1,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xC0, 0x7F, 0x80, 0x7F,
|
||||
0x80, 0x7F, 0x87, 0x7F, 0x87, 0x78, 0x80, 0x7F,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x40, 0x9F, 0x00, 0xFF,
|
||||
0x10, 0xEF, 0x90, 0x6F, 0x10, 0xEB, 0x14, 0xEB,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x3F, 0xE0, 0x1F, 0xE0,
|
||||
0x0E, 0xF1, 0x0C, 0xF3, 0x0C, 0xF7, 0x18, 0xE7,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x20, 0x9F, 0x00, 0xFF,
|
||||
0x0C, 0xF3, 0x31, 0xC0, 0x60, 0x9F, 0x40, 0xBF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xC0, 0x7F, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x1E, 0xEF, 0x3F, 0xC0, 0x7F, 0x80,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x80, 0x77, 0x04, 0xDB,
|
||||
0x00, 0xFB, 0x10, 0xEF, 0x00, 0xFD, 0x80, 0x77,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x78, 0x8F, 0x38, 0xE7,
|
||||
0x1C, 0xE7, 0x0C, 0xF3, 0x0E, 0xF3, 0x0E, 0xF9,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x80, 0x7F, 0x00, 0xFF,
|
||||
0x40, 0xB7, 0x00, 0xEF, 0x01, 0xDE, 0x02, 0xFC,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x7C, 0x83, 0x78, 0x87,
|
||||
0x38, 0xCF, 0x30, 0xDF, 0x21, 0xFE, 0x03, 0xFD,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xDF, 0x60, 0x9F,
|
||||
0xC0, 0x3F, 0x80, 0x7F, 0x00, 0x7F, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x3F, 0xE0, 0x3F, 0xC0,
|
||||
0x7F, 0x80, 0xFF, 0x00, 0xFF, 0x80, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFB, 0x01, 0xFC,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFE, 0x01, 0xFC, 0x03, 0xFC, 0x07, 0xFE, 0x03,
|
||||
0x00, 0xFF, 0x40, 0x3F, 0x30, 0x8F, 0x00, 0xF7,
|
||||
0x80, 0x7F, 0x30, 0xCF, 0x01, 0xFE, 0x87, 0x78,
|
||||
0x01, 0xFE, 0x80, 0xFF, 0xE0, 0x5F, 0xF8, 0x0F,
|
||||
0x78, 0x87, 0x00, 0xFF, 0x00, 0xFF, 0x03, 0xFC,
|
||||
0x00, 0xFF, 0x08, 0xF7, 0x80, 0x6F, 0x80, 0x7F,
|
||||
0x80, 0x5F, 0x87, 0x78, 0x04, 0x7B, 0x08, 0x73,
|
||||
0xF8, 0x07, 0xF0, 0x0F, 0x70, 0x9F, 0x60, 0x9F,
|
||||
0x60, 0xBF, 0xC3, 0x3C, 0x87, 0xF8, 0x87, 0xFC,
|
||||
0xA0, 0x1F, 0x80, 0x7D, 0xE2, 0x1D, 0x02, 0xFD,
|
||||
0x02, 0xFD, 0xF0, 0x0F, 0x10, 0xEE, 0x11, 0xEE,
|
||||
0x43, 0xFC, 0xE3, 0x1E, 0x03, 0xFC, 0x01, 0xFE,
|
||||
0x01, 0xFE, 0xE1, 0x1E, 0xE1, 0x1F, 0xE1, 0x1E,
|
||||
0x44, 0xBB, 0x48, 0xB3, 0x48, 0xB7, 0x08, 0xF7,
|
||||
0x0A, 0xF5, 0x02, 0xF5, 0x80, 0x77, 0x90, 0x67,
|
||||
0x84, 0x7B, 0x84, 0x7F, 0x84, 0x7B, 0x84, 0x7B,
|
||||
0x8C, 0x73, 0x8C, 0x7B, 0x0E, 0xF9, 0x0E, 0xF9,
|
||||
0x86, 0x59, 0x06, 0xF9, 0x48, 0xB3, 0x08, 0xF7,
|
||||
0x10, 0xE7, 0x14, 0xEB, 0x24, 0xCB, 0x20, 0xDF,
|
||||
0x60, 0xBF, 0x44, 0xBB, 0x04, 0xFF, 0x0C, 0xF3,
|
||||
0x0C, 0xFB, 0x18, 0xE7, 0x18, 0xF7, 0x38, 0xC7,
|
||||
0x08, 0xD7, 0x48, 0x97, 0x48, 0xB7, 0x41, 0xBE,
|
||||
0x41, 0xBE, 0x01, 0xBE, 0x10, 0xAF, 0x90, 0x2F,
|
||||
0x30, 0xEF, 0x30, 0xEF, 0x30, 0xCF, 0x30, 0xCF,
|
||||
0x70, 0x8F, 0x70, 0xCF, 0x60, 0xDF, 0x60, 0xDF,
|
||||
0x04, 0xFB, 0x04, 0xFB, 0xFC, 0x03, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0xF8, 0x02, 0x05, 0xFA, 0x05, 0xFA,
|
||||
0x03, 0xFC, 0x03, 0xFC, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0x07, 0xFD, 0x02, 0xFD, 0x06, 0xF9,
|
||||
0x80, 0x7F, 0x80, 0x7F, 0x0F, 0xF0, 0x10, 0xE7,
|
||||
0x10, 0xEE, 0x1E, 0xE1, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x0E, 0xF1, 0x0F, 0xF8,
|
||||
0x0F, 0xF1, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x60, 0x8F, 0x00, 0xDF, 0x00, 0xFF, 0x00, 0xEF,
|
||||
0x04, 0xEB, 0x20, 0xCF, 0x22, 0xDD, 0xC1, 0x1E,
|
||||
0x38, 0xD7, 0x38, 0xE7, 0x18, 0xE7, 0x18, 0xF7,
|
||||
0x18, 0xF7, 0x1C, 0xF3, 0x3E, 0xC1, 0x7F, 0xA0,
|
||||
0x80, 0x3F, 0x80, 0x7F, 0x80, 0x7F, 0x01, 0xFE,
|
||||
0x00, 0xBD, 0x18, 0xE7, 0x00, 0xFF, 0x83, 0x7C,
|
||||
0x7F, 0xC0, 0x7F, 0x80, 0x7F, 0x80, 0x7E, 0x81,
|
||||
0x7E, 0xC3, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x81, 0x76, 0x80, 0x77, 0x10, 0xE7, 0x10, 0xEF,
|
||||
0x10, 0xEF, 0x21, 0xCE, 0x41, 0x9E, 0x81, 0x3E,
|
||||
0x0E, 0xF9, 0x0F, 0xF8, 0x0F, 0xF8, 0x0F, 0xF0,
|
||||
0x1F, 0xE0, 0x3E, 0xD1, 0x7E, 0xA1, 0xFE, 0x41,
|
||||
0x04, 0xF9, 0x08, 0xF3, 0x18, 0xE7, 0x10, 0xEF,
|
||||
0x10, 0xEF, 0x10, 0xEF, 0x00, 0xEF, 0x20, 0xCF,
|
||||
0x07, 0xFA, 0x07, 0xFC, 0x0F, 0xF0, 0x0F, 0xF0,
|
||||
0x0F, 0xF0, 0x1F, 0xE0, 0x1F, 0xF0, 0x1F, 0xF0,
|
||||
0x7C, 0x01, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x82, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x78, 0x87, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x0F, 0xF0, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x70, 0x8E, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x01, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xC3, 0x18, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x24, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x8F, 0x70, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xF8, 0x03, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x04, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0x7F, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x80, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x3E, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0xC1, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xE0, 0x1F, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
};
|
|
@ -0,0 +1,563 @@
|
|||
static uint8_t animation_logo[] = {
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x3, 0x3, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x1, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x1, 0x3, 0x3, 0x1, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x1, 0x1, 0x1, 0x1, 0x3, 0x3, 0x1, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x1, 0x3, 0x3, 0x3, 0x3, 0x3, 0x1, 0x1, 0x0, 0x0, 0x0, 0x3, 0x3, 0x3, 0x1, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x3, 0x3, 0x3, 0x3, 0x3, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x3, 0x3, 0x3, 0x1, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4,
|
||||
0x4, 0x4, 0x4, 0x3, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, 0x3, 0x3, 0x1, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xE, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4,
|
||||
0x4, 0x4, 0x4, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, 0x3, 0x3, 0x1, 0x1, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xE, 0xE, 0x1,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x4, 0x4,
|
||||
0x4, 0x4, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, 0x3, 0x3, 0x1, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE, 0xE, 0xE, 0x1,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4,
|
||||
0x4, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x3, 0x3, 0x3, 0x1, 0x1, 0x0, 0x1,
|
||||
0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x7, 0x0, 0x0, 0x1, 0x9, 0x9, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x1, 0xC, 0xC, 0xC, 0xC, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE, 0xE, 0xE, 0xE, 0x1,
|
||||
0x0, 0x0, 0xE, 0xE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4,
|
||||
0x4, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, 0x3, 0x1, 0x1, 0x0, 0x0, 0x5,
|
||||
0x5, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x6, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x7, 0x7, 0x7, 0x9, 0x9, 0x9, 0x9, 0x9, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0x0, 0x0, 0x0, 0x0, 0xE, 0xE, 0xE, 0xE, 0x1,
|
||||
0x1, 0xE, 0xE, 0xE, 0xE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4,
|
||||
0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x3, 0x3, 0x1, 0x0, 0x0, 0x5, 0x5,
|
||||
0x5, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x6, 0x6, 0x6, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1,
|
||||
0x7, 0x7, 0x7, 0x9, 0x1, 0x1, 0x1, 0x9, 0x9, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0xC,
|
||||
0xC, 0xC, 0xC, 0xC, 0x1, 0x1, 0xC, 0xC, 0x0, 0x0, 0x0, 0xE, 0xE, 0xE, 0xE, 0xE,
|
||||
0xE, 0xE, 0xE, 0xE, 0xE, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4,
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x1, 0x1, 0x0, 0x1, 0x5, 0x5,
|
||||
0x5, 0x1, 0x0, 0x0, 0x0, 0x0, 0x6, 0x6, 0x6, 0x6, 0x1, 0x0, 0x0, 0x0, 0x0, 0x7,
|
||||
0x7, 0x7, 0x9, 0x1, 0x1, 0x0, 0x0, 0x9, 0x9, 0x1, 0x0, 0x0, 0x0, 0x0, 0xC, 0xC,
|
||||
0xC, 0xC, 0x1, 0x1, 0x0, 0xC, 0xC, 0xC, 0x1, 0x0, 0x0, 0xE, 0xE, 0xE, 0xE, 0xE,
|
||||
0xE, 0xE, 0xE, 0xE, 0xE, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4,
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x5, 0x5, 0x5,
|
||||
0x5, 0x1, 0x0, 0x0, 0x0, 0x1, 0x6, 0x6, 0x6, 0x1, 0x1, 0x0, 0x0, 0x0, 0x7, 0x7,
|
||||
0x7, 0x7, 0x1, 0x1, 0x0, 0x0, 0x1, 0x9, 0x9, 0x9, 0x0, 0x0, 0x0, 0x1, 0xC, 0xC,
|
||||
0xC, 0x1, 0x1, 0x0, 0x0, 0xC, 0xC, 0xC, 0x1, 0x0, 0x0, 0x1, 0xD, 0x1, 0x1, 0x1,
|
||||
0x1, 0xE, 0xE, 0xE, 0xE, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4,
|
||||
0x4, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x5, 0x5, 0x5,
|
||||
0x1, 0x1, 0x0, 0x0, 0x0, 0x6, 0x6, 0x6, 0x6, 0x1, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7,
|
||||
0x7, 0x1, 0x1, 0x0, 0x0, 0x0, 0x9, 0x9, 0x9, 0x1, 0x0, 0x0, 0x0, 0xC, 0xC, 0xC,
|
||||
0xC, 0x1, 0x0, 0x0, 0xC, 0xC, 0xC, 0xC, 0x1, 0x0, 0x0, 0xD, 0xD, 0x1, 0x0, 0x0,
|
||||
0xE, 0xE, 0xF, 0xF, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4,
|
||||
0x4, 0x4, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x5, 0x5, 0x5,
|
||||
0x1, 0x0, 0x0, 0x0, 0x1, 0x6, 0x6, 0x6, 0x1, 0x1, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7,
|
||||
0x7, 0x1, 0x0, 0x0, 0x0, 0x0, 0x9, 0x9, 0x9, 0x1, 0x0, 0x0, 0xC, 0xC, 0xC, 0xC,
|
||||
0x1, 0x1, 0x0, 0x1, 0xC, 0xC, 0xC, 0x1, 0x1, 0x0, 0x1, 0xD, 0x1, 0x1, 0x0, 0xF,
|
||||
0xF, 0xF, 0xF, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4,
|
||||
0x4, 0x4, 0x4, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x5, 0x5, 0x5, 0x1,
|
||||
0x1, 0x0, 0x0, 0x0, 0x6, 0x6, 0x6, 0x6, 0x1, 0x0, 0x0, 0x0, 0x1, 0x7, 0x7, 0x7,
|
||||
0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x9, 0x9, 0x9, 0x1, 0x0, 0x0, 0xC, 0xC, 0xC, 0xC,
|
||||
0x1, 0x0, 0x1, 0xC, 0xC, 0xC, 0xC, 0x1, 0x0, 0x0, 0xD, 0xD, 0x1, 0x0, 0x1, 0xF,
|
||||
0xF, 0xF, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x4, 0x4, 0x4, 0x4, 0x4, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x6, 0x6, 0x1, 0x1,
|
||||
0x0, 0x0, 0x0, 0x6, 0x6, 0x6, 0x6, 0x1, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x7,
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x9, 0x9, 0x9, 0x9, 0x1, 0x0, 0x1, 0xC, 0xC, 0xB, 0xB,
|
||||
0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0x1, 0x0, 0x0, 0xD, 0xD, 0x1, 0x1, 0x0, 0xF, 0xF,
|
||||
0xF, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x1, 0x4, 0x4, 0x4, 0x4, 0x4, 0x0, 0x0, 0x0, 0x1, 0x6, 0x6, 0x6, 0x1, 0x0,
|
||||
0x0, 0x0, 0x1, 0x6, 0x6, 0x7, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x7, 0x7, 0x7, 0x1,
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x9, 0x9, 0x9, 0x1, 0x1, 0x0, 0xC, 0xC, 0xB, 0xB, 0x1,
|
||||
0xC, 0xC, 0xC, 0xC, 0x1, 0x1, 0x1, 0x0, 0x1, 0xD, 0x1, 0x1, 0x0, 0x1, 0xF, 0xF,
|
||||
0xF, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x4, 0x0, 0x0, 0x6, 0x6, 0x6, 0x1, 0x1, 0x0,
|
||||
0x0, 0x0, 0x6, 0x6, 0x7, 0x7, 0x1, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x8, 0x1,
|
||||
0x0, 0x0, 0x0, 0x0, 0x9, 0x9, 0x9, 0x9, 0x1, 0x0, 0x0, 0xC, 0xB, 0xB, 0xB, 0x1,
|
||||
0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0xD, 0xD, 0x1, 0x0, 0x0, 0xF, 0xF, 0xF,
|
||||
0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0xF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x5, 0x5, 0x5, 0x5, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x1, 0x4, 0x4, 0x4, 0x1, 0x0, 0x6, 0x6, 0x6, 0x1, 0x0, 0x0,
|
||||
0x0, 0x6, 0x6, 0x7, 0x7, 0x1, 0x1, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x8, 0x8, 0x1,
|
||||
0x0, 0x0, 0x0, 0x1, 0x9, 0x9, 0xA, 0x1, 0x1, 0x0, 0xC, 0xB, 0xB, 0xB, 0x1, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xD, 0xD, 0x1, 0x1, 0x0, 0x0, 0xF, 0xF, 0xF,
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0xF, 0xF, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x5, 0x5, 0x5, 0x5, 0x1, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x4, 0x4, 0x1, 0x1, 0x6, 0x6, 0x6, 0x1, 0x0, 0x0,
|
||||
0x1, 0x6, 0x7, 0x7, 0x7, 0x1, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x8, 0x8, 0xA, 0x1,
|
||||
0x0, 0x0, 0x0, 0x9, 0x9, 0xA, 0xA, 0x1, 0x0, 0x1, 0xB, 0xB, 0xB, 0xD, 0x1, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xD, 0xD, 0x1, 0x1, 0x0, 0x0, 0x0, 0xF, 0xF, 0xF,
|
||||
0x1, 0x0, 0x0, 0x0, 0xF, 0xF, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x5, 0x5, 0x5, 0x5, 0x5, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x4, 0x4, 0x1, 0x1, 0x6, 0x6, 0x1, 0x1, 0x0, 0x1,
|
||||
0x6, 0x1, 0x7, 0x7, 0x7, 0x1, 0x0, 0x0, 0x1, 0x7, 0x7, 0x8, 0x8, 0xA, 0xA, 0x1,
|
||||
0x0, 0x0, 0xA, 0xA, 0xA, 0xA, 0x1, 0x1, 0x0, 0xB, 0xB, 0x1, 0xD, 0xD, 0xD, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0xD, 0xD, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0xF, 0xF, 0xF,
|
||||
0x1, 0x0, 0x0, 0x0, 0xF, 0xF, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x5, 0x5, 0x5, 0x5, 0x5,
|
||||
0x5, 0x1, 0x0, 0x0, 0x1, 0x4, 0x4, 0x1, 0x1, 0x0, 0x6, 0x6, 0x1, 0x0, 0x1, 0x6,
|
||||
0x1, 0x1, 0x7, 0x7, 0x7, 0x1, 0x0, 0x1, 0x7, 0x7, 0x8, 0x8, 0x1, 0x1, 0xA, 0xA,
|
||||
0x1, 0xA, 0xA, 0xA, 0xA, 0x1, 0x1, 0xB, 0xB, 0xB, 0x1, 0x1, 0x1, 0xD, 0xD, 0x1,
|
||||
0x0, 0x0, 0x0, 0x1, 0xD, 0xD, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0xF, 0xF, 0xF,
|
||||
0x1, 0x0, 0x1, 0xF, 0xF, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x5, 0x5, 0x5,
|
||||
0x5, 0x5, 0x5, 0x4, 0x4, 0x4, 0x1, 0x1, 0x0, 0x0, 0x6, 0x6, 0x6, 0x6, 0x6, 0x1,
|
||||
0x1, 0x0, 0x1, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x8, 0x8, 0x8, 0x1, 0x0, 0x1, 0xA,
|
||||
0xA, 0xA, 0xA, 0xB, 0xB, 0xB, 0xB, 0xB, 0xB, 0x1, 0x1, 0x0, 0x0, 0xD, 0xD, 0xD,
|
||||
0xD, 0xD, 0xD, 0xD, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xF, 0xF,
|
||||
0xF, 0xF, 0xF, 0xF, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x5,
|
||||
0x5, 0x5, 0x5, 0x5, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x6, 0x1, 0x1, 0x1,
|
||||
0x0, 0x0, 0x0, 0x1, 0x7, 0x7, 0x7, 0x1, 0x8, 0x8, 0x8, 0x1, 0x1, 0x0, 0x0, 0x0,
|
||||
0xB, 0xB, 0xB, 0xB, 0xB, 0xB, 0xB, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0xD,
|
||||
0xD, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
|
||||
0xF, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x8, 0x8, 0x8, 0x1, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x8, 0x8, 0x8, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x8, 0x8, 0x1, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x1, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0,
|
||||
0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x8, 0x8, 0x1, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0,
|
||||
0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x8, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1,
|
||||
0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2,
|
||||
0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2,
|
||||
0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2,
|
||||
0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2,
|
||||
0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x1,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2,
|
||||
0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2,
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1,
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2,
|
||||
0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2,
|
||||
0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2,
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2,
|
||||
0x1, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x1, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2,
|
||||
0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2,
|
||||
0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x2, 0x2,
|
||||
0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2,
|
||||
0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0,
|
||||
0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x2, 0x2, 0x2, 0x1, 0x0, 0x1, 0x2, 0x2,
|
||||
0x2, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
|
||||
0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0,
|
||||
0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2,
|
||||
0x2, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2,
|
||||
0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0,
|
||||
0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1,
|
||||
0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x1, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0,
|
||||
0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x1, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1,
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1,
|
||||
0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2,
|
||||
0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0,
|
||||
0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1,
|
||||
0x1, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1,
|
||||
0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1,
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0,
|
||||
0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1,
|
||||
0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1,
|
||||
0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2,
|
||||
0x2, 0x1, 0x1, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0,
|
||||
0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1,
|
||||
0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0,
|
||||
0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0,
|
||||
0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0,
|
||||
0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0,
|
||||
0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0,
|
||||
0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0,
|
||||
0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
|
||||
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1,
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x0,
|
||||
0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0,
|
||||
0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1,
|
||||
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1,
|
||||
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
|
||||
};
|
||||
static const unsigned animation_logo_height = sizeof(animation_logo) / 160;
|
|
@ -0,0 +1,658 @@
|
|||
static const uint16_t palette[] = {
|
||||
0x0000, 0x0011, 0x18C6, 0x001A, 0x318C, 0x39CE, 0x5294, 0x5AD6,
|
||||
0x739C, 0x45A8, 0x4520, 0x18A5, 0x4631, 0x2033, 0x20EC, 0x18B7
|
||||
};
|
||||
|
||||
static const uint16_t tilemap[] = {
|
||||
0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001,
|
||||
0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001,
|
||||
0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001,
|
||||
0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001,
|
||||
0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002,
|
||||
0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002,
|
||||
0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002,
|
||||
0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002,
|
||||
0x1001, 0x1003, 0x1004, 0x1005, 0x1005, 0x1005, 0x1005, 0x1005,
|
||||
0x1005, 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, 0x1005,
|
||||
0x1005, 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, 0x1005,
|
||||
0x1005, 0x1005, 0x1005, 0x1005, 0x1005, 0x5004, 0x5003, 0x1001,
|
||||
0x1001, 0x1006, 0x1007, 0x1007, 0x1007, 0x1008, 0x1009, 0x100A,
|
||||
0x100B, 0x100C, 0x100D, 0x100E, 0x100F, 0x1010, 0x1011, 0x1012,
|
||||
0x1013, 0x1014, 0x1015, 0x100E, 0x1016, 0x1017, 0x1018, 0x1019,
|
||||
0x101A, 0x101B, 0x101C, 0x1007, 0x1007, 0x1007, 0x5006, 0x1001,
|
||||
0x1001, 0x101D, 0x101E, 0x101E, 0x101E, 0x101F, 0x1020, 0x1021,
|
||||
0x1022, 0x1023, 0x1024, 0x1025, 0x5024, 0x1026, 0x1025, 0x1025,
|
||||
0x1027, 0x1028, 0x1029, 0x102A, 0x102B, 0x102C, 0x102D, 0x102E,
|
||||
0x102F, 0x1030, 0x1031, 0x101E, 0x101E, 0x101E, 0xC01D, 0x1001,
|
||||
0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001,
|
||||
0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001,
|
||||
0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001,
|
||||
0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001,
|
||||
0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001,
|
||||
0x1001, 0x101D, 0x1034, 0x1035, 0x5034, 0x1033, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001,
|
||||
0x1001, 0x101D, 0x8034, 0x1036, 0xC034, 0x1033, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001,
|
||||
0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001,
|
||||
0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001,
|
||||
0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001,
|
||||
0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001,
|
||||
0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001,
|
||||
0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001,
|
||||
0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001,
|
||||
0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001,
|
||||
0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0x1037, 0x1001,
|
||||
0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0x1038, 0x1001,
|
||||
0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
|
||||
0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1039, 0x103A, 0x1001,
|
||||
0x1001, 0x103B, 0x103C, 0x1032, 0x1032, 0xC03C, 0x103D, 0x103D,
|
||||
0x103D, 0x103D, 0x103D, 0x103D, 0x103D, 0x103D, 0x103D, 0x103D,
|
||||
0x103D, 0x103D, 0x103D, 0x103D, 0x103D, 0x103D, 0x103D, 0x103D,
|
||||
0x103D, 0x103D, 0x103E, 0x103F, 0x1040, 0x1041, 0x1001, 0x1001,
|
||||
0x1001, 0x1042, 0x1043, 0x1044, 0x1044, 0x1044, 0x1044, 0x1044,
|
||||
0x1044, 0x1044, 0x1044, 0x1044, 0x1044, 0x1044, 0x1044, 0x1044,
|
||||
0x1044, 0x1044, 0x1044, 0x1044, 0x1044, 0x1044, 0x1044, 0x1044,
|
||||
0x1044, 0x1044, 0x1045, 0x1046, 0x1001, 0x1001, 0x1001, 0x1001,
|
||||
0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1047, 0x1048, 0x1049,
|
||||
0x104A, 0x104B, 0x104C, 0x104D, 0x104E, 0x104F, 0x1050, 0x1051,
|
||||
0x1052, 0x1053, 0x1054, 0x1055, 0x1056, 0x1057, 0x1058, 0x1059,
|
||||
0x105A, 0x105B, 0x105C, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001,
|
||||
0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x105D, 0x105E, 0x105F,
|
||||
0x1060, 0x1061, 0x1062, 0x1063, 0x1064, 0x1065, 0x1066, 0x1067,
|
||||
0x1068, 0x1069, 0x106A, 0x106B, 0x106C, 0x106D, 0x106E, 0x106F,
|
||||
0x1070, 0x1071, 0x1072, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001,
|
||||
0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1073, 0x1074, 0x1075,
|
||||
0x1076, 0x1077, 0x1078, 0x1079, 0x107A, 0x107B, 0x107C, 0x107D,
|
||||
0x107E, 0x107F, 0x1080, 0x1081, 0x1082, 0x1083, 0x507A, 0x1084,
|
||||
0x1001, 0x1085, 0x507A, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001,
|
||||
};
|
||||
|
||||
const uint8_t tiles[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0x01, 0xFE, 0x06, 0xF9, 0x08, 0xF7,
|
||||
0x11, 0xEF, 0x22, 0xDB, 0x20, 0xDB, 0x40, 0xB7,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFE, 0x00, 0xF8, 0x00,
|
||||
0xF1, 0x00, 0xE6, 0x04, 0xE4, 0x00, 0xC8, 0x00,
|
||||
0x7F, 0x80, 0x80, 0x7F, 0x00, 0xFF, 0x7F, 0xFF,
|
||||
0x80, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x80, 0x00, 0x00, 0x00, 0x7F, 0x00,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x40, 0xB7, 0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF,
|
||||
0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF,
|
||||
0xC8, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00,
|
||||
0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x03, 0xFF, 0x02, 0xFF,
|
||||
0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00,
|
||||
0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xC1, 0xDD, 0x00, 0xC9,
|
||||
0x14, 0xFF, 0x14, 0xFF, 0x14, 0xFF, 0x00, 0xC9,
|
||||
0x00, 0x00, 0x00, 0x00, 0xE3, 0x00, 0x36, 0x22,
|
||||
0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x36, 0x22,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xC7, 0xDF, 0x01, 0xCF,
|
||||
0x11, 0xFF, 0x11, 0xFF, 0x11, 0xFF, 0x01, 0xCF,
|
||||
0x00, 0x00, 0x00, 0x00, 0xE7, 0x00, 0x31, 0x20,
|
||||
0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x31, 0x20,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xC2, 0xFF, 0x03, 0xFF,
|
||||
0x02, 0xFE, 0x02, 0xFE, 0x02, 0xFF, 0x02, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0xC2, 0x00, 0x03, 0x00,
|
||||
0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x08, 0xFF, 0x18, 0xFF,
|
||||
0x08, 0x4E, 0x08, 0x4E, 0x09, 0x1F, 0x08, 0x1C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x00,
|
||||
0xB9, 0x10, 0xB9, 0xA1, 0xE9, 0xA0, 0xEB, 0x41,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x4F, 0xFF, 0x02, 0x1F,
|
||||
0x02, 0x4F, 0x02, 0x4F, 0xF2, 0xFF, 0x02, 0xE7,
|
||||
0x00, 0x00, 0x00, 0x00, 0x4F, 0x00, 0xE2, 0xA0,
|
||||
0xB2, 0xA0, 0xB2, 0x10, 0xF2, 0x00, 0x1A, 0x10,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xBC, 0xFD, 0x22, 0xFB,
|
||||
0x22, 0xFB, 0x3C, 0xFD, 0x24, 0xFF, 0x26, 0xF9,
|
||||
0x00, 0x00, 0x00, 0x00, 0xBE, 0x00, 0x26, 0x00,
|
||||
0x26, 0x00, 0x3E, 0x00, 0x24, 0x00, 0x26, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x50, 0xFF, 0x49, 0xEF,
|
||||
0x49, 0xF0, 0x46, 0xFF, 0x49, 0xF0, 0x49, 0xEF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x59, 0x00,
|
||||
0x4F, 0x06, 0x46, 0x00, 0x4F, 0x06, 0x59, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x88, 0xFF, 0x00, 0x72,
|
||||
0x00, 0xF2, 0x05, 0xFF, 0x00, 0xF8, 0x00, 0x78,
|
||||
0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x8D, 0x08,
|
||||
0x0D, 0x05, 0x05, 0x00, 0x07, 0x05, 0x87, 0x02,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x8A, 0xFF, 0x02, 0x27,
|
||||
0x02, 0x27, 0x52, 0xFF, 0x02, 0x8F, 0x02, 0x8F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x8A, 0x00, 0xDA, 0x88,
|
||||
0xDA, 0x50, 0x52, 0x00, 0x72, 0x50, 0x72, 0x20,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xFA, 0xFF, 0x22, 0xFF,
|
||||
0x22, 0xFF, 0x23, 0xFF, 0x22, 0xFF, 0x22, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x22, 0x00,
|
||||
0x22, 0x00, 0x23, 0x00, 0x22, 0x00, 0x22, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x20, 0xFF, 0x20, 0xFF,
|
||||
0x20, 0xFF, 0xE0, 0xFF, 0x20, 0xFF, 0x20, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00,
|
||||
0x20, 0x00, 0xE0, 0x00, 0x20, 0x00, 0x20, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x33, 0x37, 0x00, 0x77,
|
||||
0x80, 0xFF, 0x20, 0x27, 0x08, 0xFF, 0x00, 0x77,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFB, 0x40, 0x88, 0x88,
|
||||
0x80, 0x00, 0xF8, 0x50, 0x08, 0x00, 0x88, 0x88,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xEF, 0xFF, 0x88, 0xFF,
|
||||
0x88, 0xFF, 0x8F, 0xFF, 0x88, 0xFF, 0x88, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0xEF, 0x00, 0x88, 0x00,
|
||||
0x88, 0x00, 0x8F, 0x00, 0x88, 0x00, 0x88, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xF9, 0xFD, 0x80, 0xF9,
|
||||
0x84, 0xFF, 0xF4, 0xFF, 0x84, 0xFF, 0x80, 0xF9,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFB, 0x00, 0x86, 0x02,
|
||||
0x84, 0x00, 0xF4, 0x00, 0x84, 0x00, 0x86, 0x02,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xC0, 0xDF, 0x00, 0xCF,
|
||||
0x10, 0xFF, 0x10, 0xFF, 0x10, 0xFF, 0x00, 0xCF,
|
||||
0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x30, 0x20,
|
||||
0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x30, 0x20,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x30, 0x36, 0x00, 0x74,
|
||||
0x82, 0xFF, 0x22, 0x27, 0x0A, 0xFF, 0x00, 0x74,
|
||||
0x00, 0x00, 0x00, 0x00, 0xF9, 0x40, 0x8B, 0x89,
|
||||
0x82, 0x00, 0xFA, 0x50, 0x0A, 0x00, 0x8B, 0x89,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xE2, 0xEF, 0x02, 0xE7,
|
||||
0x0A, 0xFF, 0x0A, 0xFF, 0x0A, 0xFF, 0x00, 0xE4,
|
||||
0x00, 0x00, 0x00, 0x00, 0xF2, 0x00, 0x1A, 0x10,
|
||||
0x0A, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x1B, 0x12,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x14, 0xFF, 0x16, 0xFF,
|
||||
0x14, 0xFC, 0x15, 0xFE, 0x14, 0xFF, 0x04, 0xCF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x16, 0x00,
|
||||
0x17, 0x01, 0x15, 0x00, 0x14, 0x00, 0x34, 0x10,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x2F, 0xFF, 0x28, 0xFF,
|
||||
0x28, 0xFF, 0xA8, 0x7F, 0x28, 0x3F, 0x68, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x28, 0x00,
|
||||
0x28, 0x00, 0xA8, 0x00, 0xE8, 0x80, 0x68, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x3F,
|
||||
0x40, 0xFF, 0x40, 0xFF, 0x40, 0xFF, 0x00, 0x3F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xC0, 0x80,
|
||||
0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xC0, 0x80,
|
||||
0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF,
|
||||
0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF,
|
||||
0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00,
|
||||
0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0xFF,
|
||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0xC1, 0xDD, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xC1, 0xDF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x02, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x4A, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x0A, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x22, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x82, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x20, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x60, 0x67, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xF8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x8F, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x8F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xA2, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xF9, 0xFD, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xC0, 0xDF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x60, 0x66, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xF9, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xE0, 0xEE, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xF1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xC4, 0xDF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xE4, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x2F, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x00, 0x7F, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x80, 0xFF,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF,
|
||||
0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF,
|
||||
0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
|
||||
0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x3C, 0xFF,
|
||||
0x7E, 0xFF, 0xE7, 0xE7, 0xFF, 0x7E, 0xFF, 0x7E,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E,
|
||||
0x81, 0xC3, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x7E, 0xFF, 0x3C, 0xFF, 0x00, 0x7E, 0x81,
|
||||
0x3C, 0xC3, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0xC3, 0x81,
|
||||
0x7E, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xF7, 0x00, 0xF7, 0x00, 0xF7, 0x00, 0xF7,
|
||||
0x00, 0xF7, 0x00, 0xED, 0x00, 0xED, 0x00, 0xED,
|
||||
0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00,
|
||||
0x09, 0x00, 0x11, 0x02, 0x11, 0x02, 0x11, 0x02,
|
||||
0x00, 0xED, 0x00, 0xDB, 0x00, 0xDB, 0x00, 0xDB,
|
||||
0x00, 0xB7, 0x00, 0xB7, 0x00, 0x6F, 0x00, 0x6F,
|
||||
0x11, 0x02, 0x23, 0x04, 0x23, 0x04, 0x23, 0x04,
|
||||
0x47, 0x08, 0x47, 0x08, 0x8F, 0x10, 0x8F, 0x10,
|
||||
0x00, 0xFE, 0x00, 0xFD, 0x00, 0xFB, 0x00, 0xF7,
|
||||
0x00, 0xEE, 0x00, 0xDD, 0x00, 0xBB, 0x00, 0x77,
|
||||
0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00,
|
||||
0x10, 0x01, 0x21, 0x02, 0x43, 0x04, 0x87, 0x08,
|
||||
0x00, 0xDF, 0x00, 0xBF, 0x00, 0xBF, 0x00, 0x7F,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x1F, 0x20, 0x3F, 0x40, 0x3F, 0x40, 0x7F, 0x80,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF, 0x00, 0xB7,
|
||||
0x00, 0xB7, 0x00, 0xDB, 0x00, 0xDD, 0x00, 0xEE,
|
||||
0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x88, 0x40,
|
||||
0x88, 0x40, 0xC4, 0x20, 0xC2, 0x20, 0xE1, 0x10,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x7F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x7F, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFC,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFC, 0x00, 0xE3, 0x00, 0x1F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x03, 0x00, 0x1C, 0x00, 0xE0, 0x00,
|
||||
0x00, 0xFE, 0x00, 0xFD, 0x00, 0xF3, 0x00, 0xEF,
|
||||
0x00, 0x1C, 0x00, 0xF3, 0x00, 0xEF, 0x00, 0x1F,
|
||||
0x01, 0x00, 0x02, 0x00, 0x0C, 0x00, 0x10, 0x00,
|
||||
0xE0, 0x03, 0x03, 0x0C, 0x0F, 0x10, 0x1F, 0xE0,
|
||||
0x00, 0xEF, 0x00, 0xDF, 0x00, 0xBF, 0x00, 0x7F,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x0F, 0x10, 0x1F, 0x20, 0x3F, 0x40, 0x7F, 0x80,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0xF7, 0x00, 0xF9, 0x00, 0xFE, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xF0, 0x08, 0xF8, 0x06, 0xFE, 0x01, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0x80, 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x80,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x7F, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x7F,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0x03, 0x00, 0xFF, 0x00, 0xFC, 0x00, 0x03,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFC, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0xFC,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0xFC, 0x00, 0xE3, 0x00, 0x1F, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0x03, 0x03, 0x1C, 0x1F, 0xE0, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x01, 0xFF, 0x01, 0xFD, 0x03, 0xFF, 0x03, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x01, 0xFE, 0x02, 0xFE, 0x02, 0xFC, 0x00,
|
||||
0x0E, 0xEE, 0x3F, 0xFF, 0x75, 0x71, 0xFB, 0xE7,
|
||||
0xE3, 0xCB, 0xC7, 0x9F, 0x07, 0x3E, 0x84, 0x7C,
|
||||
0xFB, 0x1B, 0xE6, 0x26, 0x8E, 0x82, 0x3E, 0x22,
|
||||
0x7C, 0x54, 0x7D, 0x25, 0xF9, 0x40, 0xFB, 0x01,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x80, 0xFF, 0x80, 0xFF,
|
||||
0x00, 0x7F, 0x80, 0x4F, 0x31, 0x7F, 0x71, 0xFD,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x80, 0xFF, 0x80,
|
||||
0xFF, 0x00, 0xFF, 0x30, 0xFF, 0xB1, 0xDE, 0x52,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0x7B, 0x87, 0xFF, 0x8E, 0xFE,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x84, 0xFA, 0x82, 0xF9, 0x88,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0xC1, 0xFD, 0xE3, 0x7B,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xC3, 0xBC, 0x24,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x01, 0xFF, 0x03, 0xFF, 0xE3, 0xFB, 0xF7, 0xBF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x01, 0xFE, 0x02, 0x7C, 0x64, 0xFC, 0xB4,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0x7F, 0x80, 0xFF, 0xA0, 0x2F, 0xF0, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x80, 0xFF, 0x80, 0xFF, 0x70, 0x8F, 0x80,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x02, 0xFD, 0x00, 0xF7,
|
||||
0x00, 0xFF, 0x11, 0xEE, 0x11, 0xEE, 0x10, 0xEF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF8, 0x0F,
|
||||
0xF0, 0x0F, 0xE0, 0x1F, 0xE1, 0x1E, 0xE0, 0x1F,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x10, 0xE7, 0x00, 0xFB,
|
||||
0xC4, 0x3B, 0x98, 0x03, 0x00, 0xEF, 0x80, 0x7F,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x0F, 0xF8, 0x07, 0xFC,
|
||||
0x07, 0xF8, 0xEF, 0x74, 0xFF, 0x10, 0x7F, 0x80,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xEF, 0x00, 0xFF, 0x22, 0xDD, 0x06, 0xB9,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xF8, 0x07, 0xF0, 0x0F,
|
||||
0xF0, 0x1F, 0xE0, 0x1F, 0xC0, 0x3F, 0xC4, 0x7B,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x80, 0x7D, 0x02, 0xFD,
|
||||
0x02, 0xBD, 0x40, 0xBF, 0x40, 0xBF, 0x40, 0xBF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x7E, 0x83, 0x7C, 0x83,
|
||||
0x7C, 0xC3, 0x7C, 0x83, 0x3C, 0xC3, 0x3C, 0xC3,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x10, 0xEF, 0x00, 0xFF,
|
||||
0x00, 0xF7, 0x00, 0xF7, 0x48, 0xB6, 0x48, 0xB7,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x0F, 0xF0,
|
||||
0x0F, 0xF8, 0x0F, 0xF8, 0x07, 0xF9, 0x06, 0xF9,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xBF, 0x02, 0xFC,
|
||||
0x02, 0x7D, 0x02, 0xFD, 0x02, 0xFD, 0x20, 0xDD,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xC1, 0x7E, 0x81, 0x7F,
|
||||
0x81, 0xFE, 0x01, 0xFE, 0x03, 0xFC, 0x03, 0xFE,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xBF, 0x40, 0xBF,
|
||||
0x47, 0xB8, 0x08, 0xF0, 0x08, 0xF7, 0x0F, 0xF0,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xC0, 0x7F, 0x80, 0x7F,
|
||||
0x80, 0x7F, 0x87, 0x7F, 0x87, 0x78, 0x80, 0x7F,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFB, 0x24, 0xCB,
|
||||
0xE4, 0x1B, 0x00, 0x1F, 0x00, 0xFF, 0x80, 0x3F,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x1C, 0xE7, 0x18, 0xF7,
|
||||
0x18, 0xE7, 0xF8, 0xE7, 0xF8, 0x07, 0x78, 0xC7,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x04, 0xF9, 0x00, 0xFF,
|
||||
0x71, 0x8E, 0x89, 0x06, 0x81, 0x7E, 0xE1, 0x1E,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x03, 0xFE, 0x01, 0xFE,
|
||||
0x00, 0xFF, 0x70, 0xFF, 0x70, 0x8F, 0x01, 0xFE,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x02, 0xF9, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x03, 0xFC, 0x06, 0xB9, 0x44, 0xBB,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFC, 0x07, 0xF0, 0x0F,
|
||||
0xE0, 0x1F, 0xC1, 0x3E, 0xC3, 0x7C, 0x87, 0x78,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x08, 0xF7, 0x00, 0xFD,
|
||||
0xC0, 0x3F, 0x11, 0x0E, 0x00, 0xFF, 0x08, 0xF7,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x07, 0xF8, 0x03, 0xFE,
|
||||
0x01, 0xFE, 0xE0, 0xFF, 0xF0, 0x0F, 0xF0, 0x0F,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x08, 0x77, 0x40, 0xBF,
|
||||
0x04, 0xBB, 0x00, 0xFE, 0x00, 0xDD, 0x00, 0x7F,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x87, 0xF8, 0x87, 0x78,
|
||||
0xC3, 0x7C, 0xC3, 0x3D, 0xE2, 0x3F, 0xE0, 0x9F,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFD, 0x06, 0xF9,
|
||||
0x0C, 0x73, 0x08, 0xF7, 0x10, 0xE7, 0x20, 0xCF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xC3, 0x3E, 0x83, 0x7C,
|
||||
0x87, 0xF8, 0x0F, 0xF0, 0x1F, 0xE8, 0x3F, 0xD0,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xF7, 0x00, 0xFF,
|
||||
0x01, 0xDE, 0x06, 0xF8, 0x1C, 0xC3, 0x00, 0xF3,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xF8, 0x0F, 0xE0, 0x1F,
|
||||
0xE0, 0x3F, 0xC3, 0x3D, 0xE7, 0x38, 0xFF, 0x0C,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xDF, 0x00, 0xFF,
|
||||
0x00, 0xF7, 0x08, 0x77, 0x08, 0xF7, 0x08, 0xF7,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x3F, 0xE0, 0x0F, 0xF0,
|
||||
0x0F, 0xF8, 0x87, 0xF8, 0x87, 0x78, 0x07, 0xF8,
|
||||
0x03, 0xFF, 0x03, 0xFF, 0x01, 0xFF, 0x00, 0xFE,
|
||||
0x18, 0xDF, 0x1C, 0xFD, 0x0F, 0xEF, 0x07, 0xF7,
|
||||
0xFC, 0x00, 0xFE, 0x02, 0xFF, 0x01, 0xFF, 0x01,
|
||||
0xFF, 0x38, 0xF3, 0x12, 0xF9, 0x19, 0xFC, 0x0C,
|
||||
0x02, 0x79, 0x80, 0xFD, 0xC0, 0xDF, 0xF0, 0xFE,
|
||||
0x79, 0x3F, 0x19, 0xDB, 0x19, 0xFB, 0xF9, 0xF7,
|
||||
0xFF, 0x84, 0xFF, 0x82, 0x7F, 0x60, 0x9F, 0x91,
|
||||
0xEF, 0xA9, 0xF6, 0x34, 0xFE, 0x1C, 0x1F, 0x11,
|
||||
0x63, 0xEF, 0xF3, 0xEB, 0xC6, 0xCE, 0xEF, 0xDE,
|
||||
0x8C, 0x9C, 0xDE, 0xBD, 0x9C, 0x9D, 0xFF, 0xEF,
|
||||
0x9E, 0x02, 0xBC, 0xA4, 0x3D, 0x14, 0x7B, 0x4A,
|
||||
0x73, 0x21, 0xF7, 0x94, 0xF7, 0xF6, 0xFE, 0xEE,
|
||||
0x8D, 0xEC, 0x9E, 0x7D, 0x1C, 0x5B, 0x38, 0xFA,
|
||||
0x79, 0xF7, 0x71, 0x75, 0xF3, 0xF3, 0xEF, 0xCF,
|
||||
0xF3, 0x90, 0xF7, 0x14, 0xEF, 0xA8, 0xEF, 0x2D,
|
||||
0xCF, 0x41, 0x8E, 0x8A, 0x3C, 0x3C, 0x39, 0x19,
|
||||
0x67, 0xFF, 0xEF, 0xFE, 0xEC, 0xDC, 0xCF, 0xCF,
|
||||
0xDD, 0xDC, 0xDC, 0x9F, 0x2C, 0x2F, 0xD7, 0xC7,
|
||||
0xB9, 0x21, 0xBB, 0xAA, 0xB3, 0x81, 0x76, 0x76,
|
||||
0x77, 0x76, 0xE7, 0xA4, 0xD7, 0x44, 0xFB, 0xCB,
|
||||
0xB3, 0x37, 0x73, 0x72, 0xF4, 0xEC, 0xEF, 0xCD,
|
||||
0xCD, 0x09, 0x11, 0xF3, 0x29, 0xA7, 0xF1, 0xCF,
|
||||
0xCD, 0x49, 0xDF, 0xDE, 0xBF, 0xA5, 0x7F, 0x5D,
|
||||
0xF6, 0x32, 0xFE, 0x14, 0xFE, 0x70, 0xFF, 0xC1,
|
||||
0xF0, 0x77, 0xF0, 0x67, 0xE0, 0xCF, 0x80, 0x97,
|
||||
0xC8, 0xBB, 0x98, 0xBB, 0x90, 0xD3, 0xE8, 0xE7,
|
||||
0xDF, 0x58, 0xBF, 0x28, 0x7F, 0x50, 0x7F, 0x28,
|
||||
0xF7, 0x84, 0xFF, 0xDC, 0xEF, 0xA4, 0xDF, 0xC0,
|
||||
0x00, 0xFF, 0x04, 0xF3, 0x03, 0xF8, 0x00, 0xFF,
|
||||
0x08, 0xF7, 0x03, 0xFC, 0x00, 0xBF, 0x18, 0xC7,
|
||||
0xF0, 0x0F, 0xF8, 0x0F, 0xFE, 0x05, 0xFF, 0x00,
|
||||
0xE7, 0x18, 0xC0, 0x3F, 0xC0, 0x7F, 0xE0, 0x3F,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x08, 0xF6, 0x08, 0x77,
|
||||
0x08, 0xF5, 0x08, 0xF7, 0x10, 0xE7, 0x70, 0x87,
|
||||
0x1F, 0xE0, 0x0F, 0xF0, 0x07, 0xF9, 0x86, 0xF9,
|
||||
0x86, 0x7B, 0x0C, 0xF3, 0x08, 0xFF, 0x38, 0xCF,
|
||||
0x0A, 0xF1, 0x88, 0x77, 0x0E, 0xF1, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x7F, 0x80, 0x41, 0xBE, 0x81, 0x3E,
|
||||
0x84, 0x7F, 0x0E, 0xF1, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x3E, 0xC1, 0x7E, 0x81, 0x7E, 0xC1,
|
||||
0x04, 0xFB, 0x04, 0xDB, 0x24, 0xDB, 0x20, 0xDF,
|
||||
0x20, 0xDF, 0x00, 0xFF, 0x08, 0xE7, 0x19, 0xE6,
|
||||
0x38, 0xC7, 0x38, 0xE7, 0x38, 0xC7, 0x18, 0xE7,
|
||||
0x18, 0xE7, 0x18, 0xE7, 0x10, 0xFF, 0x10, 0xEF,
|
||||
0x48, 0xB5, 0x80, 0x3F, 0x84, 0x7B, 0x80, 0x7F,
|
||||
0xA1, 0x5E, 0x21, 0x5E, 0x02, 0x7C, 0x02, 0x7D,
|
||||
0x46, 0xBB, 0x44, 0xFB, 0x40, 0xBF, 0x40, 0xBF,
|
||||
0xC0, 0x3F, 0xC1, 0xBE, 0xE1, 0x9F, 0xE3, 0x9C,
|
||||
0x60, 0x9D, 0x64, 0x99, 0x84, 0x3B, 0x84, 0x7B,
|
||||
0x04, 0x7B, 0x40, 0xBB, 0x41, 0xBA, 0x09, 0xF2,
|
||||
0x03, 0xFE, 0x43, 0xBE, 0x43, 0xFC, 0xC3, 0x3C,
|
||||
0xC7, 0xB8, 0x87, 0x7C, 0x86, 0x7D, 0x86, 0x7D,
|
||||
0x80, 0x7F, 0x80, 0x7F, 0x8F, 0x70, 0x10, 0xEF,
|
||||
0x10, 0xEF, 0x1F, 0xE0, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0,
|
||||
0x0F, 0xF0, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x48, 0xB7, 0x48, 0xB7, 0xC0, 0x3F, 0x01, 0xFE,
|
||||
0x01, 0xFE, 0x81, 0x2E, 0x50, 0xAF, 0x50, 0xAF,
|
||||
0x30, 0xCF, 0x30, 0xCF, 0xF0, 0x0F, 0xF0, 0x0F,
|
||||
0xF0, 0x0F, 0x70, 0xDF, 0x20, 0xDF, 0x60, 0x9F,
|
||||
0x06, 0xF8, 0x00, 0xFD, 0xF0, 0x0F, 0x00, 0x7E,
|
||||
0x00, 0xEE, 0xE2, 0x1C, 0x02, 0xFD, 0x0C, 0xF1,
|
||||
0x03, 0xFD, 0x03, 0xFE, 0xE1, 0x1E, 0xF1, 0x8F,
|
||||
0xF1, 0x1F, 0x01, 0xFF, 0x03, 0xFC, 0x07, 0xFA,
|
||||
0x08, 0xF3, 0x08, 0xF7, 0x08, 0xF7, 0x00, 0xFF,
|
||||
0x40, 0xBB, 0x01, 0xFE, 0x20, 0xDF, 0x18, 0xE7,
|
||||
0x87, 0x7C, 0x87, 0x78, 0x87, 0x78, 0x87, 0x78,
|
||||
0x87, 0x7C, 0xC0, 0x3F, 0xE0, 0x1F, 0xF0, 0x0F,
|
||||
0x08, 0xF7, 0x08, 0xF7, 0x01, 0xFE, 0x11, 0xEE,
|
||||
0x01, 0xDE, 0x82, 0x7C, 0x04, 0xF9, 0x38, 0xC3,
|
||||
0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xE0, 0x1F,
|
||||
0xE1, 0x3E, 0x03, 0xFD, 0x07, 0xFA, 0x0F, 0xF4,
|
||||
0x10, 0x6F, 0x00, 0x7F, 0x01, 0x7E, 0x01, 0xFE,
|
||||
0x01, 0xFE, 0x11, 0xEE, 0x10, 0xEE, 0x12, 0xEC,
|
||||
0xE0, 0x9F, 0xF0, 0x8F, 0xF0, 0x8F, 0xF0, 0x0F,
|
||||
0xF0, 0x0F, 0xE1, 0x1E, 0xE1, 0x1F, 0xE1, 0x1F,
|
||||
0x40, 0x9F, 0x80, 0x3F, 0x80, 0x7F, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x7F, 0xA0, 0x7F, 0xC0, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFB, 0x08, 0xF7, 0x00, 0xFF,
|
||||
0x01, 0xBE, 0x03, 0xFC, 0x00, 0x7F, 0x80, 0x7F,
|
||||
0xFE, 0x01, 0xFC, 0x07, 0xF0, 0x0F, 0xE0, 0x1F,
|
||||
0xC1, 0x7E, 0x80, 0x7F, 0x80, 0xFF, 0x00, 0xFF,
|
||||
0x08, 0xF7, 0x10, 0xE7, 0x60, 0x8F, 0xC0, 0x3F,
|
||||
0x80, 0x7F, 0xE0, 0x0F, 0x00, 0xEF, 0x00, 0xEF,
|
||||
0x0F, 0xF0, 0x1F, 0xE8, 0x3F, 0xD0, 0x7F, 0x80,
|
||||
0xFF, 0x00, 0x1F, 0xF0, 0x1F, 0xF0, 0x1F, 0xF0,
|
||||
0x02, 0xF8, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x04, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xD0, 0xC6, 0x00, 0x1F, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0xC9, 0xFF, 0xE0, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xE7, 0x86, 0x01, 0x39, 0x01, 0xFF, 0x03, 0xFF,
|
||||
0x03, 0xFF, 0x00, 0xFC, 0x00, 0xFE, 0x00, 0xFF,
|
||||
0xFF, 0x9E, 0xFF, 0xC7, 0xFE, 0x00, 0xFE, 0x02,
|
||||
0xFF, 0x03, 0xFF, 0x02, 0xFF, 0x01, 0xFF, 0x00,
|
||||
0xC3, 0xD3, 0xC0, 0xBC, 0x80, 0xBF, 0x00, 0x7F,
|
||||
0x80, 0x7F, 0x00, 0x7F, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x7F, 0x6B, 0x7F, 0x03, 0xFF, 0xC0, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x80, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xC7, 0x1B, 0x00, 0x7C, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x23, 0xFF, 0x83, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xC0, 0x1F, 0x00, 0x7F, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x20, 0xFF, 0x80, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x50, 0x4F, 0x00, 0x9F, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x40, 0xFF, 0x60, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x07, 0xF0, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x08, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xC7, 0x18, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x20, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x80, 0x7F, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xF7, 0x08, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x0C, 0xE1, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x12, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x38, 0x87, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x40, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x8F, 0x30, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x40, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xF0, 0x07, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x08, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x03, 0xF0, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x0C, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x0E, 0xF1, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x7F, 0x80, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00
|
||||
};
|
|
@ -0,0 +1,92 @@
|
|||
#include "gb.h"
|
||||
#include <assert.h>
|
||||
|
||||
void GB_update_joyp(GB_gameboy_t *gb)
|
||||
{
|
||||
if (gb->model & GB_MODEL_NO_SFC_BIT) return;
|
||||
|
||||
uint8_t key_selection = 0;
|
||||
uint8_t previous_state = 0;
|
||||
|
||||
/* Todo: add delay to key selection */
|
||||
previous_state = gb->io_registers[GB_IO_JOYP] & 0xF;
|
||||
key_selection = (gb->io_registers[GB_IO_JOYP] >> 4) & 3;
|
||||
gb->io_registers[GB_IO_JOYP] &= 0xF0;
|
||||
uint8_t current_player = gb->sgb? (gb->sgb->current_player & (gb->sgb->player_count - 1) & 3) : 0;
|
||||
switch (key_selection) {
|
||||
case 3:
|
||||
if (gb->sgb && gb->sgb->player_count > 1) {
|
||||
gb->io_registers[GB_IO_JOYP] |= 0xF - current_player;
|
||||
}
|
||||
else {
|
||||
/* Nothing is wired, all up */
|
||||
gb->io_registers[GB_IO_JOYP] |= 0x0F;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* Direction keys */
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
gb->io_registers[GB_IO_JOYP] |= (!gb->keys[current_player][i]) << i;
|
||||
}
|
||||
/* Forbid pressing two opposing keys, this breaks a lot of games; even if it's somewhat possible. */
|
||||
if (!(gb->io_registers[GB_IO_JOYP] & 1)) {
|
||||
gb->io_registers[GB_IO_JOYP] |= 2;
|
||||
}
|
||||
if (!(gb->io_registers[GB_IO_JOYP] & 4)) {
|
||||
gb->io_registers[GB_IO_JOYP] |= 8;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* Other keys */
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
gb->io_registers[GB_IO_JOYP] |= (!gb->keys[current_player][i + 4]) << i;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0:
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
gb->io_registers[GB_IO_JOYP] |= (!(gb->keys[current_player][i] || gb->keys[current_player][i + 4])) << i;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Todo: This assumes the keys *always* bounce, which is incorrect when emulating an SGB */
|
||||
if (previous_state != (gb->io_registers[GB_IO_JOYP] & 0xF)) {
|
||||
/* The joypad interrupt DOES occur on CGB (Tested on CGB-E), unlike what some documents say. */
|
||||
gb->io_registers[GB_IO_IF] |= 0x10;
|
||||
}
|
||||
|
||||
gb->io_registers[GB_IO_JOYP] |= 0xC0;
|
||||
}
|
||||
|
||||
void GB_icd_set_joyp(GB_gameboy_t *gb, uint8_t value)
|
||||
{
|
||||
uint8_t previous_state = gb->io_registers[GB_IO_JOYP] & 0xF;
|
||||
gb->io_registers[GB_IO_JOYP] &= 0xF0;
|
||||
gb->io_registers[GB_IO_JOYP] |= value & 0xF;
|
||||
|
||||
if (previous_state & ~(gb->io_registers[GB_IO_JOYP] & 0xF)) {
|
||||
gb->io_registers[GB_IO_IF] |= 0x10;
|
||||
}
|
||||
gb->io_registers[GB_IO_JOYP] |= 0xC0;
|
||||
}
|
||||
|
||||
void GB_set_key_state(GB_gameboy_t *gb, GB_key_t index, bool pressed)
|
||||
{
|
||||
assert(index >= 0 && index < GB_KEY_MAX);
|
||||
gb->keys[0][index] = pressed;
|
||||
GB_update_joyp(gb);
|
||||
}
|
||||
|
||||
void GB_set_key_state_for_player(GB_gameboy_t *gb, GB_key_t index, unsigned player, bool pressed)
|
||||
{
|
||||
assert(index >= 0 && index < GB_KEY_MAX);
|
||||
assert(player < 4);
|
||||
gb->keys[player][index] = pressed;
|
||||
GB_update_joyp(gb);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef joypad_h
|
||||
#define joypad_h
|
||||
#include "gb_struct_def.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum {
|
||||
GB_KEY_RIGHT,
|
||||
GB_KEY_LEFT,
|
||||
GB_KEY_UP,
|
||||
GB_KEY_DOWN,
|
||||
GB_KEY_A,
|
||||
GB_KEY_B,
|
||||
GB_KEY_SELECT,
|
||||
GB_KEY_START,
|
||||
GB_KEY_MAX
|
||||
} GB_key_t;
|
||||
|
||||
void GB_set_key_state(GB_gameboy_t *gb, GB_key_t index, bool pressed);
|
||||
void GB_set_key_state_for_player(GB_gameboy_t *gb, GB_key_t index, unsigned player, bool pressed);
|
||||
void GB_icd_set_joyp(GB_gameboy_t *gb, uint8_t value);
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
void GB_update_joyp(GB_gameboy_t *gb);
|
||||
#endif
|
||||
#endif /* joypad_h */
|
|
@ -0,0 +1,167 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "gb.h"
|
||||
|
||||
const GB_cartridge_t GB_cart_defs[256] = {
|
||||
// From http://gbdev.gg8.se/wiki/articles/The_Cartridge_Header#0147_-_Cartridge_Type
|
||||
/* MBC SUBTYPE RAM BAT. RTC RUMB. */
|
||||
{ GB_NO_MBC, GB_STANDARD_MBC, false, false, false, false}, // 00h ROM ONLY
|
||||
{ GB_MBC1 , GB_STANDARD_MBC, false, false, false, false}, // 01h MBC1
|
||||
{ GB_MBC1 , GB_STANDARD_MBC, true , false, false, false}, // 02h MBC1+RAM
|
||||
{ GB_MBC1 , GB_STANDARD_MBC, true , true , false, false}, // 03h MBC1+RAM+BATTERY
|
||||
[5] =
|
||||
{ GB_MBC2 , GB_STANDARD_MBC, true , false, false, false}, // 05h MBC2
|
||||
{ GB_MBC2 , GB_STANDARD_MBC, true , true , false, false}, // 06h MBC2+BATTERY
|
||||
[8] =
|
||||
{ GB_NO_MBC, GB_STANDARD_MBC, true , false, false, false}, // 08h ROM+RAM
|
||||
{ GB_NO_MBC, GB_STANDARD_MBC, true , true , false, false}, // 09h ROM+RAM+BATTERY
|
||||
[0xB] =
|
||||
/* Todo: Not supported yet */
|
||||
{ GB_NO_MBC, GB_STANDARD_MBC, false, false, false, false}, // 0Bh MMM01
|
||||
{ GB_NO_MBC, GB_STANDARD_MBC, false, false, false, false}, // 0Ch MMM01+RAM
|
||||
{ GB_NO_MBC, GB_STANDARD_MBC, false, false, false, false}, // 0Dh MMM01+RAM+BATTERY
|
||||
[0xF] =
|
||||
{ GB_MBC3 , GB_STANDARD_MBC, false, true, true , false}, // 0Fh MBC3+TIMER+BATTERY
|
||||
{ GB_MBC3 , GB_STANDARD_MBC, true , true, true , false}, // 10h MBC3+TIMER+RAM+BATTERY
|
||||
{ GB_MBC3 , GB_STANDARD_MBC, false, false, false, false}, // 11h MBC3
|
||||
{ GB_MBC3 , GB_STANDARD_MBC, true , false, false, false}, // 12h MBC3+RAM
|
||||
{ GB_MBC3 , GB_STANDARD_MBC, true , true , false, false}, // 13h MBC3+RAM+BATTERY
|
||||
[0x19] =
|
||||
{ GB_MBC5 , GB_STANDARD_MBC, false, false, false, false}, // 19h MBC5
|
||||
{ GB_MBC5 , GB_STANDARD_MBC, true , false, false, false}, // 1Ah MBC5+RAM
|
||||
{ GB_MBC5 , GB_STANDARD_MBC, true , true , false, false}, // 1Bh MBC5+RAM+BATTERY
|
||||
{ GB_MBC5 , GB_STANDARD_MBC, false, false, false, true }, // 1Ch MBC5+RUMBLE
|
||||
{ GB_MBC5 , GB_STANDARD_MBC, true , false, false, true }, // 1Dh MBC5+RUMBLE+RAM
|
||||
{ GB_MBC5 , GB_STANDARD_MBC, true , true , false, true }, // 1Eh MBC5+RUMBLE+RAM+BATTERY
|
||||
[0xFC] =
|
||||
{ GB_MBC5 , GB_CAMERA , true , true , false, false}, // FCh POCKET CAMERA
|
||||
{ GB_NO_MBC, GB_STANDARD_MBC, false, false, false, false}, // FDh BANDAI TAMA5 (Todo: Not supported)
|
||||
{ GB_HUC3 , GB_STANDARD_MBC, true , true , true, false}, // FEh HuC3
|
||||
{ GB_HUC1 , GB_STANDARD_MBC, true , true , false, false}, // FFh HuC1+RAM+BATTERY
|
||||
};
|
||||
|
||||
void GB_update_mbc_mappings(GB_gameboy_t *gb)
|
||||
{
|
||||
switch (gb->cartridge_type->mbc_type) {
|
||||
case GB_NO_MBC: return;
|
||||
case GB_MBC1:
|
||||
switch (gb->mbc1_wiring) {
|
||||
case GB_STANDARD_MBC1_WIRING:
|
||||
gb->mbc_rom_bank = gb->mbc1.bank_low | (gb->mbc1.bank_high << 5);
|
||||
if (gb->mbc1.mode == 0) {
|
||||
gb->mbc_ram_bank = 0;
|
||||
gb->mbc_rom0_bank = 0;
|
||||
}
|
||||
else {
|
||||
gb->mbc_ram_bank = gb->mbc1.bank_high;
|
||||
gb->mbc_rom0_bank = gb->mbc1.bank_high << 5;
|
||||
}
|
||||
if ((gb->mbc_rom_bank & 0x1F) == 0) {
|
||||
gb->mbc_rom_bank++;
|
||||
}
|
||||
break;
|
||||
case GB_MBC1M_WIRING:
|
||||
gb->mbc_rom_bank = (gb->mbc1.bank_low & 0xF) | (gb->mbc1.bank_high << 4);
|
||||
if (gb->mbc1.mode == 0) {
|
||||
gb->mbc_ram_bank = 0;
|
||||
gb->mbc_rom0_bank = 0;
|
||||
}
|
||||
else {
|
||||
gb->mbc_rom0_bank = gb->mbc1.bank_high << 4;
|
||||
gb->mbc_ram_bank = 0;
|
||||
}
|
||||
if ((gb->mbc1.bank_low & 0x1F) == 0) {
|
||||
gb->mbc_rom_bank++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GB_MBC2:
|
||||
gb->mbc_rom_bank = gb->mbc2.rom_bank;
|
||||
if ((gb->mbc_rom_bank & 0xF) == 0) {
|
||||
gb->mbc_rom_bank = 1;
|
||||
}
|
||||
break;
|
||||
case GB_MBC3:
|
||||
gb->mbc_rom_bank = gb->mbc3.rom_bank;
|
||||
gb->mbc_ram_bank = gb->mbc3.ram_bank;
|
||||
if (!gb->is_mbc30) {
|
||||
gb->mbc_rom_bank &= 0x7F;
|
||||
}
|
||||
if (gb->mbc_rom_bank == 0) {
|
||||
gb->mbc_rom_bank = 1;
|
||||
}
|
||||
break;
|
||||
case GB_MBC5:
|
||||
gb->mbc_rom_bank = gb->mbc5.rom_bank_low | (gb->mbc5.rom_bank_high << 8);
|
||||
gb->mbc_ram_bank = gb->mbc5.ram_bank;
|
||||
break;
|
||||
case GB_HUC1:
|
||||
if (gb->huc1.mode == 0) {
|
||||
gb->mbc_rom_bank = gb->huc1.bank_low | (gb->mbc1.bank_high << 6);
|
||||
gb->mbc_ram_bank = 0;
|
||||
}
|
||||
else {
|
||||
gb->mbc_rom_bank = gb->huc1.bank_low;
|
||||
gb->mbc_ram_bank = gb->huc1.bank_high;
|
||||
}
|
||||
break;
|
||||
case GB_HUC3:
|
||||
gb->mbc_rom_bank = gb->huc3.rom_bank;
|
||||
gb->mbc_ram_bank = gb->huc3.ram_bank;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GB_configure_cart(GB_gameboy_t *gb)
|
||||
{
|
||||
gb->cartridge_type = &GB_cart_defs[gb->rom[0x147]];
|
||||
|
||||
if (gb->rom[0x147] == 0 && gb->rom_size > 0x8000) {
|
||||
GB_log(gb, "ROM header reports no MBC, but file size is over 32Kb. Assuming cartridge uses MBC3.\n");
|
||||
gb->cartridge_type = &GB_cart_defs[0x11];
|
||||
}
|
||||
else if (gb->rom[0x147] != 0 && memcmp(gb->cartridge_type, &GB_cart_defs[0], sizeof(GB_cart_defs[0])) == 0) {
|
||||
GB_log(gb, "Cartridge type %02x is not yet supported.\n", gb->rom[0x147]);
|
||||
}
|
||||
|
||||
if (gb->cartridge_type->has_ram) {
|
||||
if (gb->cartridge_type->mbc_type == GB_MBC2) {
|
||||
gb->mbc_ram_size = 0x200;
|
||||
}
|
||||
else {
|
||||
static const unsigned ram_sizes[256] = {0, 0x800, 0x2000, 0x8000, 0x20000, 0x10000};
|
||||
gb->mbc_ram_size = ram_sizes[gb->rom[0x149]];
|
||||
}
|
||||
|
||||
if (gb->mbc_ram_size) {
|
||||
gb->mbc_ram = malloc(gb->mbc_ram_size);
|
||||
}
|
||||
|
||||
/* Todo: Some games assume unintialized MBC RAM is 0xFF. It this true for all cartridges types? */
|
||||
memset(gb->mbc_ram, 0xFF, gb->mbc_ram_size);
|
||||
}
|
||||
|
||||
/* MBC1 has at least 3 types of wiring (We currently support two (Standard and 4bit-MBC1M) of these).
|
||||
See http://forums.nesdev.com/viewtopic.php?f=20&t=14099 */
|
||||
|
||||
/* Attempt to "guess" wiring */
|
||||
if (gb->cartridge_type->mbc_type == GB_MBC1) {
|
||||
if (gb->rom_size >= 0x44000 && memcmp(gb->rom + 0x104, gb->rom + 0x40104, 0x30) == 0) {
|
||||
gb->mbc1_wiring = GB_MBC1M_WIRING;
|
||||
}
|
||||
}
|
||||
|
||||
/* Detect MBC30 */
|
||||
if (gb->cartridge_type->mbc_type == GB_MBC3) {
|
||||
if (gb->rom_size > 0x200000 || gb->mbc_ram_size > 0x8000) {
|
||||
gb->is_mbc30 = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set MBC5's bank to 1 correctly */
|
||||
if (gb->cartridge_type->mbc_type == GB_MBC5) {
|
||||
gb->mbc5.rom_bank_low = 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef MBC_h
|
||||
#define MBC_h
|
||||
#include "gb_struct_def.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
enum {
|
||||
GB_NO_MBC,
|
||||
GB_MBC1,
|
||||
GB_MBC2,
|
||||
GB_MBC3,
|
||||
GB_MBC5,
|
||||
GB_HUC1,
|
||||
GB_HUC3,
|
||||
} mbc_type;
|
||||
enum {
|
||||
GB_STANDARD_MBC,
|
||||
GB_CAMERA,
|
||||
} mbc_subtype;
|
||||
bool has_ram;
|
||||
bool has_battery;
|
||||
bool has_rtc;
|
||||
bool has_rumble;
|
||||
} GB_cartridge_t;
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
extern const GB_cartridge_t GB_cart_defs[256];
|
||||
void GB_update_mbc_mappings(GB_gameboy_t *gb);
|
||||
void GB_configure_cart(GB_gameboy_t *gb);
|
||||
#endif
|
||||
|
||||
#endif /* MBC_h */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,18 @@
|
|||
#ifndef memory_h
|
||||
#define memory_h
|
||||
#include "gb_struct_def.h"
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint8_t (*GB_read_memory_callback_t)(GB_gameboy_t *gb, uint16_t addr, uint8_t data);
|
||||
void GB_set_read_memory_callback(GB_gameboy_t *gb, GB_read_memory_callback_t callback);
|
||||
|
||||
uint8_t GB_read_memory(GB_gameboy_t *gb, uint16_t addr);
|
||||
void GB_write_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value);
|
||||
#ifdef GB_INTERNAL
|
||||
void GB_dma_run(GB_gameboy_t *gb);
|
||||
void GB_hdma_run(GB_gameboy_t *gb);
|
||||
void GB_trigger_oam_bug(GB_gameboy_t *gb, uint16_t address);
|
||||
void GB_trigger_oam_bug_read_increase(GB_gameboy_t *gb, uint16_t address);
|
||||
#endif
|
||||
|
||||
#endif /* memory_h */
|
|
@ -0,0 +1,216 @@
|
|||
#include "gb.h"
|
||||
|
||||
/* TODO: Emulation is VERY basic and assumes the ROM correctly uses the printer's interface.
|
||||
Incorrect usage is not correctly emulated, as it's not well documented, nor do I
|
||||
have my own GB Printer to figure it out myself.
|
||||
|
||||
It also does not currently emulate communication timeout, which means that a bug
|
||||
might prevent the printer operation until the GameBoy is restarted.
|
||||
|
||||
Also, field mask values are assumed. */
|
||||
|
||||
static void handle_command(GB_gameboy_t *gb)
|
||||
{
|
||||
|
||||
switch (gb->printer.command_id) {
|
||||
case GB_PRINTER_INIT_COMMAND:
|
||||
gb->printer.status = 0;
|
||||
gb->printer.image_offset = 0;
|
||||
break;
|
||||
|
||||
case GB_PRINTER_START_COMMAND:
|
||||
if (gb->printer.command_length == 4) {
|
||||
gb->printer.status = 6; /* Printing */
|
||||
uint32_t image[gb->printer.image_offset];
|
||||
uint8_t palette = gb->printer.command_data[2];
|
||||
uint32_t colors[4] = {gb->rgb_encode_callback(gb, 0xff, 0xff, 0xff),
|
||||
gb->rgb_encode_callback(gb, 0xaa, 0xaa, 0xaa),
|
||||
gb->rgb_encode_callback(gb, 0x55, 0x55, 0x55),
|
||||
gb->rgb_encode_callback(gb, 0x00, 0x00, 0x00)};
|
||||
for (unsigned i = 0; i < gb->printer.image_offset; i++) {
|
||||
image[i] = colors[(palette >> (gb->printer.image[i] * 2)) & 3];
|
||||
}
|
||||
|
||||
if (gb->printer_callback) {
|
||||
gb->printer_callback(gb, image, gb->printer.image_offset / 160,
|
||||
gb->printer.command_data[1] >> 4, gb->printer.command_data[1] & 7,
|
||||
gb->printer.command_data[3] & 0x7F);
|
||||
}
|
||||
|
||||
gb->printer.image_offset = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case GB_PRINTER_DATA_COMMAND:
|
||||
if (gb->printer.command_length == GB_PRINTER_DATA_SIZE) {
|
||||
gb->printer.image_offset %= sizeof(gb->printer.image);
|
||||
gb->printer.status = 8; /* Received 0x280 bytes */
|
||||
|
||||
uint8_t *byte = gb->printer.command_data;
|
||||
|
||||
for (unsigned row = 2; row--; ) {
|
||||
for (unsigned tile_x = 0; tile_x < 160 / 8; tile_x++) {
|
||||
for (unsigned y = 0; y < 8; y++, byte += 2) {
|
||||
for (unsigned x_pixel = 0; x_pixel < 8; x_pixel++) {
|
||||
gb->printer.image[gb->printer.image_offset + tile_x * 8 + x_pixel + y * 160] =
|
||||
((*byte) >> 7) | (((*(byte + 1)) >> 7) << 1);
|
||||
(*byte) <<= 1;
|
||||
(*(byte + 1)) <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gb->printer.image_offset += 8 * 160;
|
||||
}
|
||||
}
|
||||
|
||||
case GB_PRINTER_NOP_COMMAND:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void byte_reieve_completed(GB_gameboy_t *gb, uint8_t byte_received)
|
||||
{
|
||||
gb->printer.byte_to_send = 0;
|
||||
switch (gb->printer.command_state) {
|
||||
case GB_PRINTER_COMMAND_MAGIC1:
|
||||
if (byte_received != 0x88) {
|
||||
return;
|
||||
}
|
||||
gb->printer.status &= ~1;
|
||||
gb->printer.command_length = 0;
|
||||
gb->printer.checksum = 0;
|
||||
break;
|
||||
|
||||
case GB_PRINTER_COMMAND_MAGIC2:
|
||||
if (byte_received != 0x33) {
|
||||
if (byte_received != 0x88) {
|
||||
gb->printer.command_state = GB_PRINTER_COMMAND_MAGIC1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case GB_PRINTER_COMMAND_ID:
|
||||
gb->printer.command_id = byte_received & 0xF;
|
||||
break;
|
||||
|
||||
case GB_PRINTER_COMMAND_COMPRESSION:
|
||||
gb->printer.compression = byte_received & 1;
|
||||
break;
|
||||
|
||||
case GB_PRINTER_COMMAND_LENGTH_LOW:
|
||||
gb->printer.length_left = byte_received;
|
||||
break;
|
||||
|
||||
case GB_PRINTER_COMMAND_LENGTH_HIGH:
|
||||
gb->printer.length_left |= (byte_received & 3) << 8;
|
||||
break;
|
||||
|
||||
case GB_PRINTER_COMMAND_DATA:
|
||||
if (gb->printer.command_length != GB_PRINTER_MAX_COMMAND_LENGTH) {
|
||||
if (gb->printer.compression) {
|
||||
if (!gb->printer.compression_run_lenth) {
|
||||
gb->printer.compression_run_is_compressed = byte_received & 0x80;
|
||||
gb->printer.compression_run_lenth = (byte_received & 0x7F) + 1 + gb->printer.compression_run_is_compressed;
|
||||
}
|
||||
else if (gb->printer.compression_run_is_compressed) {
|
||||
while (gb->printer.compression_run_lenth) {
|
||||
gb->printer.command_data[gb->printer.command_length++] = byte_received;
|
||||
gb->printer.compression_run_lenth--;
|
||||
if (gb->printer.command_length == GB_PRINTER_MAX_COMMAND_LENGTH) {
|
||||
gb->printer.compression_run_lenth = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
gb->printer.command_data[gb->printer.command_length++] = byte_received;
|
||||
gb->printer.compression_run_lenth--;
|
||||
}
|
||||
}
|
||||
else {
|
||||
gb->printer.command_data[gb->printer.command_length++] = byte_received;
|
||||
}
|
||||
}
|
||||
gb->printer.length_left--;
|
||||
break;
|
||||
|
||||
case GB_PRINTER_COMMAND_CHECKSUM_LOW:
|
||||
gb->printer.checksum ^= byte_received;
|
||||
break;
|
||||
|
||||
case GB_PRINTER_COMMAND_CHECKSUM_HIGH:
|
||||
gb->printer.checksum ^= byte_received << 8;
|
||||
if (gb->printer.checksum) {
|
||||
gb->printer.status |= 1; /* Checksum error*/
|
||||
gb->printer.command_state = GB_PRINTER_COMMAND_MAGIC1;
|
||||
return;
|
||||
}
|
||||
gb->printer.byte_to_send = 0x81;
|
||||
|
||||
break;
|
||||
case GB_PRINTER_COMMAND_ACTIVE:
|
||||
if ((gb->printer.command_id & 0xF) == GB_PRINTER_INIT_COMMAND) {
|
||||
/* Games expect INIT commands to return 0? */
|
||||
gb->printer.byte_to_send = 0;
|
||||
}
|
||||
else {
|
||||
gb->printer.byte_to_send = gb->printer.status;
|
||||
}
|
||||
break;
|
||||
case GB_PRINTER_COMMAND_STATUS:
|
||||
|
||||
/* Printing is done instantly, but let the game recieve a 6 (Printing) status at least once, for compatibility */
|
||||
if (gb->printer.status == 6) {
|
||||
gb->printer.status = 4; /* Done */
|
||||
}
|
||||
|
||||
gb->printer.command_state = GB_PRINTER_COMMAND_MAGIC1;
|
||||
handle_command(gb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gb->printer.command_state >= GB_PRINTER_COMMAND_ID && gb->printer.command_state < GB_PRINTER_COMMAND_CHECKSUM_LOW) {
|
||||
gb->printer.checksum += byte_received;
|
||||
}
|
||||
|
||||
if (gb->printer.command_state != GB_PRINTER_COMMAND_DATA) {
|
||||
gb->printer.command_state++;
|
||||
}
|
||||
|
||||
if (gb->printer.command_state == GB_PRINTER_COMMAND_DATA) {
|
||||
if (gb->printer.length_left == 0) {
|
||||
gb->printer.command_state++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void serial_start(GB_gameboy_t *gb, bool bit_received)
|
||||
{
|
||||
gb->printer.byte_being_received <<= 1;
|
||||
gb->printer.byte_being_received |= bit_received;
|
||||
gb->printer.bits_received++;
|
||||
if (gb->printer.bits_received == 8) {
|
||||
byte_reieve_completed(gb, gb->printer.byte_being_received);
|
||||
gb->printer.bits_received = 0;
|
||||
gb->printer.byte_being_received = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool serial_end(GB_gameboy_t *gb)
|
||||
{
|
||||
bool ret = gb->printer.bit_to_send;
|
||||
gb->printer.bit_to_send = gb->printer.byte_to_send & 0x80;
|
||||
gb->printer.byte_to_send <<= 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GB_connect_printer(GB_gameboy_t *gb, GB_print_image_callback_t callback)
|
||||
{
|
||||
memset(&gb->printer, 0, sizeof(gb->printer));
|
||||
GB_set_serial_transfer_bit_start_callback(gb, serial_start);
|
||||
GB_set_serial_transfer_bit_end_callback(gb, serial_end);
|
||||
gb->printer_callback = callback;
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
#ifndef printer_h
|
||||
#define printer_h
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "gb_struct_def.h"
|
||||
#define GB_PRINTER_MAX_COMMAND_LENGTH 0x280
|
||||
#define GB_PRINTER_DATA_SIZE 0x280
|
||||
|
||||
typedef void (*GB_print_image_callback_t)(GB_gameboy_t *gb,
|
||||
uint32_t *image,
|
||||
uint8_t height,
|
||||
uint8_t top_margin,
|
||||
uint8_t bottom_margin,
|
||||
uint8_t exposure);
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Communication state machine */
|
||||
|
||||
enum {
|
||||
GB_PRINTER_COMMAND_MAGIC1,
|
||||
GB_PRINTER_COMMAND_MAGIC2,
|
||||
GB_PRINTER_COMMAND_ID,
|
||||
GB_PRINTER_COMMAND_COMPRESSION,
|
||||
GB_PRINTER_COMMAND_LENGTH_LOW,
|
||||
GB_PRINTER_COMMAND_LENGTH_HIGH,
|
||||
GB_PRINTER_COMMAND_DATA,
|
||||
GB_PRINTER_COMMAND_CHECKSUM_LOW,
|
||||
GB_PRINTER_COMMAND_CHECKSUM_HIGH,
|
||||
GB_PRINTER_COMMAND_ACTIVE,
|
||||
GB_PRINTER_COMMAND_STATUS,
|
||||
} command_state : 8;
|
||||
enum {
|
||||
GB_PRINTER_INIT_COMMAND = 1,
|
||||
GB_PRINTER_START_COMMAND = 2,
|
||||
GB_PRINTER_DATA_COMMAND = 4,
|
||||
GB_PRINTER_NOP_COMMAND = 0xF,
|
||||
} command_id : 8;
|
||||
bool compression;
|
||||
uint16_t length_left;
|
||||
uint8_t command_data[GB_PRINTER_MAX_COMMAND_LENGTH];
|
||||
uint16_t command_length;
|
||||
uint16_t checksum;
|
||||
uint8_t status;
|
||||
uint8_t byte_to_send;
|
||||
|
||||
uint8_t image[160 * 200];
|
||||
uint16_t image_offset;
|
||||
|
||||
/* TODO: Delete me. */
|
||||
uint64_t padding;
|
||||
|
||||
uint8_t compression_run_lenth;
|
||||
bool compression_run_is_compressed;
|
||||
|
||||
uint8_t bits_received;
|
||||
uint8_t byte_being_received;
|
||||
bool bit_to_send;
|
||||
} GB_printer_t;
|
||||
|
||||
|
||||
void GB_connect_printer(GB_gameboy_t *gb, GB_print_image_callback_t callback);
|
||||
#endif
|
|
@ -0,0 +1,38 @@
|
|||
#include "random.h"
|
||||
#include <time.h>
|
||||
|
||||
static uint64_t seed;
|
||||
static bool enabled = true;
|
||||
|
||||
uint8_t GB_random(void)
|
||||
{
|
||||
if (!enabled) return 0;
|
||||
|
||||
seed *= 0x27BB2EE687B0B0FDL;
|
||||
seed += 0xB504F32D;
|
||||
return seed >> 56;
|
||||
}
|
||||
|
||||
uint32_t GB_random32(void)
|
||||
{
|
||||
GB_random();
|
||||
return seed >> 32;
|
||||
}
|
||||
|
||||
void GB_random_seed(uint64_t new_seed)
|
||||
{
|
||||
seed = new_seed;
|
||||
}
|
||||
|
||||
void GB_random_set_enabled(bool enable)
|
||||
{
|
||||
enabled = enable;
|
||||
}
|
||||
|
||||
static void __attribute__((constructor)) init_seed(void)
|
||||
{
|
||||
seed = time(NULL);
|
||||
for (unsigned i = 64; i--;) {
|
||||
GB_random();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef random_h
|
||||
#define random_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
uint8_t GB_random(void);
|
||||
uint32_t GB_random32(void);
|
||||
void GB_random_seed(uint64_t seed);
|
||||
void GB_random_set_enabled(bool enable);
|
||||
|
||||
#endif /* random_h */
|
|
@ -0,0 +1,208 @@
|
|||
#include "gb.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
static uint8_t *state_compress(const uint8_t *prev, const uint8_t *data, size_t uncompressed_size)
|
||||
{
|
||||
size_t malloc_size = 0x1000;
|
||||
uint8_t *compressed = malloc(malloc_size);
|
||||
size_t counter_pos = 0;
|
||||
size_t data_pos = sizeof(uint16_t);
|
||||
bool prev_mode = true;
|
||||
*(uint16_t *)compressed = 0;
|
||||
#define COUNTER (*(uint16_t *)&compressed[counter_pos])
|
||||
#define DATA (compressed[data_pos])
|
||||
|
||||
while (uncompressed_size) {
|
||||
if (prev_mode) {
|
||||
if (*data == *prev && COUNTER != 0xffff) {
|
||||
COUNTER++;
|
||||
data++;
|
||||
prev++;
|
||||
uncompressed_size--;
|
||||
}
|
||||
else {
|
||||
prev_mode = false;
|
||||
counter_pos += sizeof(uint16_t);
|
||||
data_pos = counter_pos + sizeof(uint16_t);
|
||||
if (data_pos >= malloc_size) {
|
||||
malloc_size *= 2;
|
||||
compressed = realloc(compressed, malloc_size);
|
||||
}
|
||||
COUNTER = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (*data != *prev && COUNTER != 0xffff) {
|
||||
COUNTER++;
|
||||
DATA = *data;
|
||||
data_pos++;
|
||||
data++;
|
||||
prev++;
|
||||
uncompressed_size--;
|
||||
if (data_pos >= malloc_size) {
|
||||
malloc_size *= 2;
|
||||
compressed = realloc(compressed, malloc_size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
prev_mode = true;
|
||||
counter_pos = data_pos;
|
||||
data_pos = counter_pos + sizeof(uint16_t);
|
||||
if (counter_pos >= malloc_size - 1) {
|
||||
malloc_size *= 2;
|
||||
compressed = realloc(compressed, malloc_size);
|
||||
}
|
||||
COUNTER = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return realloc(compressed, data_pos);
|
||||
#undef DATA
|
||||
#undef COUNTER
|
||||
}
|
||||
|
||||
|
||||
static void state_decompress(const uint8_t *prev, uint8_t *data, uint8_t *dest, size_t uncompressed_size)
|
||||
{
|
||||
size_t counter_pos = 0;
|
||||
size_t data_pos = sizeof(uint16_t);
|
||||
bool prev_mode = true;
|
||||
#define COUNTER (*(uint16_t *)&data[counter_pos])
|
||||
#define DATA (data[data_pos])
|
||||
|
||||
while (uncompressed_size) {
|
||||
if (prev_mode) {
|
||||
if (COUNTER) {
|
||||
COUNTER--;
|
||||
*(dest++) = *(prev++);
|
||||
uncompressed_size--;
|
||||
}
|
||||
else {
|
||||
prev_mode = false;
|
||||
counter_pos += sizeof(uint16_t);
|
||||
data_pos = counter_pos + sizeof(uint16_t);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (COUNTER) {
|
||||
COUNTER--;
|
||||
*(dest++) = DATA;
|
||||
data_pos++;
|
||||
prev++;
|
||||
uncompressed_size--;
|
||||
}
|
||||
else {
|
||||
prev_mode = true;
|
||||
counter_pos = data_pos;
|
||||
data_pos += sizeof(uint16_t);
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef DATA
|
||||
#undef COUNTER
|
||||
}
|
||||
|
||||
void GB_rewind_push(GB_gameboy_t *gb)
|
||||
{
|
||||
const size_t save_size = GB_get_save_state_size(gb);
|
||||
if (!gb->rewind_sequences) {
|
||||
if (gb->rewind_buffer_length) {
|
||||
gb->rewind_sequences = malloc(sizeof(*gb->rewind_sequences) * gb->rewind_buffer_length);
|
||||
memset(gb->rewind_sequences, 0, sizeof(*gb->rewind_sequences) * gb->rewind_buffer_length);
|
||||
gb->rewind_pos = 0;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (gb->rewind_sequences[gb->rewind_pos].pos == GB_REWIND_FRAMES_PER_KEY) {
|
||||
gb->rewind_pos++;
|
||||
if (gb->rewind_pos == gb->rewind_buffer_length) {
|
||||
gb->rewind_pos = 0;
|
||||
}
|
||||
if (gb->rewind_sequences[gb->rewind_pos].key_state) {
|
||||
free(gb->rewind_sequences[gb->rewind_pos].key_state);
|
||||
gb->rewind_sequences[gb->rewind_pos].key_state = NULL;
|
||||
}
|
||||
for (unsigned i = 0; i < GB_REWIND_FRAMES_PER_KEY; i++) {
|
||||
if (gb->rewind_sequences[gb->rewind_pos].compressed_states[i]) {
|
||||
free(gb->rewind_sequences[gb->rewind_pos].compressed_states[i]);
|
||||
gb->rewind_sequences[gb->rewind_pos].compressed_states[i] = 0;
|
||||
}
|
||||
}
|
||||
gb->rewind_sequences[gb->rewind_pos].pos = 0;
|
||||
}
|
||||
|
||||
if (!gb->rewind_sequences[gb->rewind_pos].key_state) {
|
||||
gb->rewind_sequences[gb->rewind_pos].key_state = malloc(save_size);
|
||||
GB_save_state_to_buffer(gb, gb->rewind_sequences[gb->rewind_pos].key_state);
|
||||
}
|
||||
else {
|
||||
uint8_t *save_state = malloc(save_size);
|
||||
GB_save_state_to_buffer(gb, save_state);
|
||||
gb->rewind_sequences[gb->rewind_pos].compressed_states[gb->rewind_sequences[gb->rewind_pos].pos++] =
|
||||
state_compress(gb->rewind_sequences[gb->rewind_pos].key_state, save_state, save_size);
|
||||
free(save_state);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool GB_rewind_pop(GB_gameboy_t *gb)
|
||||
{
|
||||
if (!gb->rewind_sequences || !gb->rewind_sequences[gb->rewind_pos].key_state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t save_size = GB_get_save_state_size(gb);
|
||||
if (gb->rewind_sequences[gb->rewind_pos].pos == 0) {
|
||||
GB_load_state_from_buffer(gb, gb->rewind_sequences[gb->rewind_pos].key_state, save_size);
|
||||
free(gb->rewind_sequences[gb->rewind_pos].key_state);
|
||||
gb->rewind_sequences[gb->rewind_pos].key_state = NULL;
|
||||
gb->rewind_pos = gb->rewind_pos == 0? gb->rewind_buffer_length - 1 : gb->rewind_pos - 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t *save_state = malloc(save_size);
|
||||
state_decompress(gb->rewind_sequences[gb->rewind_pos].key_state,
|
||||
gb->rewind_sequences[gb->rewind_pos].compressed_states[--gb->rewind_sequences[gb->rewind_pos].pos],
|
||||
save_state,
|
||||
save_size);
|
||||
free(gb->rewind_sequences[gb->rewind_pos].compressed_states[gb->rewind_sequences[gb->rewind_pos].pos]);
|
||||
gb->rewind_sequences[gb->rewind_pos].compressed_states[gb->rewind_sequences[gb->rewind_pos].pos] = NULL;
|
||||
GB_load_state_from_buffer(gb, save_state, save_size);
|
||||
free(save_state);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GB_rewind_free(GB_gameboy_t *gb)
|
||||
{
|
||||
if (!gb->rewind_sequences) return;
|
||||
for (unsigned i = 0; i < gb->rewind_buffer_length; i++) {
|
||||
if (gb->rewind_sequences[i].key_state) {
|
||||
free(gb->rewind_sequences[i].key_state);
|
||||
}
|
||||
for (unsigned j = 0; j < GB_REWIND_FRAMES_PER_KEY; j++) {
|
||||
if (gb->rewind_sequences[i].compressed_states[j]) {
|
||||
free(gb->rewind_sequences[i].compressed_states[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(gb->rewind_sequences);
|
||||
gb->rewind_sequences = NULL;
|
||||
}
|
||||
|
||||
void GB_set_rewind_length(GB_gameboy_t *gb, double seconds)
|
||||
{
|
||||
GB_rewind_free(gb);
|
||||
if (seconds == 0) {
|
||||
gb->rewind_buffer_length = 0;
|
||||
}
|
||||
else {
|
||||
gb->rewind_buffer_length = (size_t) ceil(seconds * CPU_FREQUENCY / LCDC_PERIOD / GB_REWIND_FRAMES_PER_KEY);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef rewind_h
|
||||
#define rewind_h
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "gb_struct_def.h"
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
void GB_rewind_push(GB_gameboy_t *gb);
|
||||
void GB_rewind_free(GB_gameboy_t *gb);
|
||||
#endif
|
||||
bool GB_rewind_pop(GB_gameboy_t *gb);
|
||||
void GB_set_rewind_length(GB_gameboy_t *gb, double seconds);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,53 @@
|
|||
#include "rumble.h"
|
||||
#include "gb.h"
|
||||
|
||||
void GB_set_rumble_mode(GB_gameboy_t *gb, GB_rumble_mode_t mode)
|
||||
{
|
||||
gb->rumble_mode = mode;
|
||||
if (gb->rumble_callback) {
|
||||
gb->rumble_callback(gb, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void GB_handle_rumble(GB_gameboy_t *gb)
|
||||
{
|
||||
if (gb->rumble_callback) {
|
||||
if (gb->rumble_mode == GB_RUMBLE_DISABLED) {
|
||||
return;
|
||||
}
|
||||
if (gb->cartridge_type->has_rumble) {
|
||||
if (gb->rumble_on_cycles + gb->rumble_off_cycles) {
|
||||
gb->rumble_callback(gb, gb->rumble_on_cycles / (double)(gb->rumble_on_cycles + gb->rumble_off_cycles));
|
||||
gb->rumble_on_cycles = gb->rumble_off_cycles = 0;
|
||||
}
|
||||
}
|
||||
else if (gb->rumble_mode == GB_RUMBLE_ALL_GAMES) {
|
||||
unsigned volume = (gb->io_registers[GB_IO_NR50] & 7) + 1 + ((gb->io_registers[GB_IO_NR50] >> 4) & 7) + 1;
|
||||
unsigned ch4_volume = volume * (!!(gb->io_registers[GB_IO_NR51] & 8) + !!(gb->io_registers[GB_IO_NR51] & 0x80));
|
||||
unsigned ch1_volume = volume * (!!(gb->io_registers[GB_IO_NR51] & 1) + !!(gb->io_registers[GB_IO_NR51] & 0x10));
|
||||
|
||||
double ch4_rumble = (MIN(gb->apu.noise_channel.sample_length * (gb->apu.noise_channel.narrow? 8 : 1) , 4096) * ((signed) gb->apu.noise_channel.current_volume * gb->apu.noise_channel.current_volume * ch4_volume / 32.0 - 50) - 2048) / 2048.0;
|
||||
|
||||
ch4_rumble = MIN(ch4_rumble, 1.0);
|
||||
ch4_rumble = MAX(ch4_rumble, 0.0);
|
||||
|
||||
double ch1_rumble = 0;
|
||||
if (gb->apu.sweep_enabled && ((gb->io_registers[GB_IO_NR10] >> 4) & 7)) {
|
||||
double sweep_speed = (gb->io_registers[GB_IO_NR10] & 7) / (double)((gb->io_registers[GB_IO_NR10] >> 4) & 7);
|
||||
ch1_rumble = gb->apu.square_channels[GB_SQUARE_1].current_volume * ch1_volume / 32.0 * sweep_speed / 8.0 - 0.5;
|
||||
ch1_rumble = MIN(ch1_rumble, 1.0);
|
||||
ch1_rumble = MAX(ch1_rumble, 0.0);
|
||||
}
|
||||
|
||||
if (!gb->apu.is_active[GB_NOISE]) {
|
||||
ch4_rumble = 0;
|
||||
}
|
||||
|
||||
if (!gb->apu.is_active[GB_SQUARE_1]) {
|
||||
ch1_rumble = 0;
|
||||
}
|
||||
|
||||
gb->rumble_callback(gb, MIN(MAX(ch1_rumble / 2 + ch4_rumble, 0.0), 1.0));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef rumble_h
|
||||
#define rumble_h
|
||||
|
||||
#include "gb_struct_def.h"
|
||||
|
||||
typedef enum {
|
||||
GB_RUMBLE_DISABLED,
|
||||
GB_RUMBLE_CARTRIDGE_ONLY,
|
||||
GB_RUMBLE_ALL_GAMES
|
||||
} GB_rumble_mode_t;
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
void GB_handle_rumble(GB_gameboy_t *gb);
|
||||
#endif
|
||||
void GB_set_rumble_mode(GB_gameboy_t *gb, GB_rumble_mode_t mode);
|
||||
|
||||
#endif /* rumble_h */
|
|
@ -0,0 +1,413 @@
|
|||
#include "gb.h"
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
static bool dump_section(FILE *f, const void *src, uint32_t size)
|
||||
{
|
||||
if (fwrite(&size, 1, sizeof(size), f) != sizeof(size)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fwrite(src, 1, size, f) != size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define DUMP_SECTION(gb, f, section) dump_section(f, GB_GET_SECTION(gb, section), GB_SECTION_SIZE(section))
|
||||
|
||||
/* Todo: we need a sane and protable save state format. */
|
||||
int GB_save_state(GB_gameboy_t *gb, const char *path)
|
||||
{
|
||||
FILE *f = fopen(path, "wb");
|
||||
if (!f) {
|
||||
GB_log(gb, "Could not open save state: %s.\n", strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
|
||||
if (fwrite(GB_GET_SECTION(gb, header), 1, GB_SECTION_SIZE(header), f) != GB_SECTION_SIZE(header)) goto error;
|
||||
if (!DUMP_SECTION(gb, f, core_state)) goto error;
|
||||
if (!DUMP_SECTION(gb, f, dma )) goto error;
|
||||
if (!DUMP_SECTION(gb, f, mbc )) goto error;
|
||||
if (!DUMP_SECTION(gb, f, hram )) goto error;
|
||||
if (!DUMP_SECTION(gb, f, timing )) goto error;
|
||||
if (!DUMP_SECTION(gb, f, apu )) goto error;
|
||||
if (!DUMP_SECTION(gb, f, rtc )) goto error;
|
||||
if (!DUMP_SECTION(gb, f, video )) goto error;
|
||||
|
||||
if (GB_is_hle_sgb(gb)) {
|
||||
if (!dump_section(f, gb->sgb, sizeof(*gb->sgb))) goto error;
|
||||
}
|
||||
|
||||
if (fwrite(gb->mbc_ram, 1, gb->mbc_ram_size, f) != gb->mbc_ram_size) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (fwrite(gb->ram, 1, gb->ram_size, f) != gb->ram_size) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (fwrite(gb->vram, 1, gb->vram_size, f) != gb->vram_size) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
|
||||
error:
|
||||
fclose(f);
|
||||
return errno;
|
||||
}
|
||||
|
||||
#undef DUMP_SECTION
|
||||
|
||||
size_t GB_get_save_state_size(GB_gameboy_t *gb)
|
||||
{
|
||||
return GB_SECTION_SIZE(header)
|
||||
+ GB_SECTION_SIZE(core_state) + sizeof(uint32_t)
|
||||
+ GB_SECTION_SIZE(dma ) + sizeof(uint32_t)
|
||||
+ GB_SECTION_SIZE(mbc ) + sizeof(uint32_t)
|
||||
+ GB_SECTION_SIZE(hram ) + sizeof(uint32_t)
|
||||
+ GB_SECTION_SIZE(timing ) + sizeof(uint32_t)
|
||||
+ GB_SECTION_SIZE(apu ) + sizeof(uint32_t)
|
||||
+ GB_SECTION_SIZE(rtc ) + sizeof(uint32_t)
|
||||
+ GB_SECTION_SIZE(video ) + sizeof(uint32_t)
|
||||
+ (GB_is_hle_sgb(gb)? sizeof(*gb->sgb) + sizeof(uint32_t) : 0)
|
||||
+ gb->mbc_ram_size
|
||||
+ gb->ram_size
|
||||
+ gb->vram_size;
|
||||
}
|
||||
|
||||
/* A write-line function for memory copying */
|
||||
static void buffer_write(const void *src, size_t size, uint8_t **dest)
|
||||
{
|
||||
memcpy(*dest, src, size);
|
||||
*dest += size;
|
||||
}
|
||||
|
||||
static void buffer_dump_section(uint8_t **buffer, const void *src, uint32_t size)
|
||||
{
|
||||
buffer_write(&size, sizeof(size), buffer);
|
||||
buffer_write(src, size, buffer);
|
||||
}
|
||||
|
||||
#define DUMP_SECTION(gb, buffer, section) buffer_dump_section(&buffer, GB_GET_SECTION(gb, section), GB_SECTION_SIZE(section))
|
||||
void GB_save_state_to_buffer(GB_gameboy_t *gb, uint8_t *buffer)
|
||||
{
|
||||
buffer_write(GB_GET_SECTION(gb, header), GB_SECTION_SIZE(header), &buffer);
|
||||
DUMP_SECTION(gb, buffer, core_state);
|
||||
DUMP_SECTION(gb, buffer, dma );
|
||||
DUMP_SECTION(gb, buffer, mbc );
|
||||
DUMP_SECTION(gb, buffer, hram );
|
||||
DUMP_SECTION(gb, buffer, timing );
|
||||
DUMP_SECTION(gb, buffer, apu );
|
||||
DUMP_SECTION(gb, buffer, rtc );
|
||||
DUMP_SECTION(gb, buffer, video );
|
||||
|
||||
if (GB_is_hle_sgb(gb)) {
|
||||
buffer_dump_section(&buffer, gb->sgb, sizeof(*gb->sgb));
|
||||
}
|
||||
|
||||
|
||||
buffer_write(gb->mbc_ram, gb->mbc_ram_size, &buffer);
|
||||
buffer_write(gb->ram, gb->ram_size, &buffer);
|
||||
buffer_write(gb->vram, gb->vram_size, &buffer);
|
||||
}
|
||||
|
||||
/* Best-effort read function for maximum future compatibility. */
|
||||
static bool read_section(FILE *f, void *dest, uint32_t size, bool fix_broken_windows_saves)
|
||||
{
|
||||
uint32_t saved_size = 0;
|
||||
if (fread(&saved_size, 1, sizeof(size), f) != sizeof(size)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fix_broken_windows_saves) {
|
||||
if (saved_size < 4) {
|
||||
return false;
|
||||
}
|
||||
saved_size -= 4;
|
||||
fseek(f, 4, SEEK_CUR);
|
||||
}
|
||||
|
||||
if (saved_size <= size) {
|
||||
if (fread(dest, 1, saved_size, f) != saved_size) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (fread(dest, 1, size, f) != size) {
|
||||
return false;
|
||||
}
|
||||
fseek(f, saved_size - size, SEEK_CUR);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#undef DUMP_SECTION
|
||||
|
||||
static bool verify_and_update_state_compatibility(GB_gameboy_t *gb, GB_gameboy_t *save)
|
||||
{
|
||||
if (save->ram_size == 0 && (&save->ram_size)[-1] == gb->ram_size) {
|
||||
/* This is a save state with a bad printer struct from a 32-bit OS */
|
||||
memcpy(save->extra_oam + 4, save->extra_oam, (uintptr_t)&save->ram_size - (uintptr_t)&save->extra_oam);
|
||||
}
|
||||
if (save->ram_size == 0) {
|
||||
/* Save doesn't have ram size specified, it's a pre 0.12 save state with potentially
|
||||
incorrect RAM amount if it's a CGB instance */
|
||||
if (GB_is_cgb(save)) {
|
||||
save->ram_size = 0x2000 * 8; // Incorrect RAM size
|
||||
}
|
||||
else {
|
||||
save->ram_size = gb->ram_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (gb->version != save->version) {
|
||||
GB_log(gb, "The save state is for a different version of SameBoy.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gb->mbc_ram_size < save->mbc_ram_size) {
|
||||
GB_log(gb, "The save state has non-matching MBC RAM size.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gb->vram_size != save->vram_size) {
|
||||
GB_log(gb, "The save state has non-matching VRAM size. Try changing the emulated model.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GB_is_hle_sgb(gb) != GB_is_hle_sgb(save)) {
|
||||
GB_log(gb, "The save state is %sfor a Super Game Boy. Try changing the emulated model.\n", GB_is_hle_sgb(save)? "" : "not ");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gb->ram_size != save->ram_size) {
|
||||
if (gb->ram_size == 0x1000 * 8 && save->ram_size == 0x2000 * 8) {
|
||||
/* A bug in versions prior to 0.12 made CGB instances allocate twice the ammount of RAM.
|
||||
Ignore this issue to retain compatibility with older, 0.11, save states. */
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "The save state has non-matching RAM size. Try changing the emulated model.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void sanitize_state(GB_gameboy_t *gb)
|
||||
{
|
||||
for (unsigned i = 0; i < 32; i++) {
|
||||
GB_palette_changed(gb, false, i * 2);
|
||||
GB_palette_changed(gb, true, i * 2);
|
||||
}
|
||||
|
||||
gb->bg_fifo.read_end &= 0xF;
|
||||
gb->bg_fifo.write_end &= 0xF;
|
||||
gb->oam_fifo.read_end &= 0xF;
|
||||
gb->oam_fifo.write_end &= 0xF;
|
||||
gb->object_low_line_address &= gb->vram_size & ~1;
|
||||
gb->fetcher_x &= 0x1f;
|
||||
if (gb->lcd_x > gb->position_in_line) {
|
||||
gb->lcd_x = gb->position_in_line;
|
||||
}
|
||||
|
||||
if (gb->object_priority == GB_OBJECT_PRIORITY_UNDEFINED) {
|
||||
gb->object_priority = gb->cgb_mode? GB_OBJECT_PRIORITY_INDEX : GB_OBJECT_PRIORITY_X;
|
||||
}
|
||||
}
|
||||
|
||||
#define READ_SECTION(gb, f, section) read_section(f, GB_GET_SECTION(gb, section), GB_SECTION_SIZE(section), fix_broken_windows_saves)
|
||||
|
||||
int GB_load_state(GB_gameboy_t *gb, const char *path)
|
||||
{
|
||||
GB_gameboy_t save;
|
||||
|
||||
/* Every unread value should be kept the same. */
|
||||
memcpy(&save, gb, sizeof(save));
|
||||
/* ...Except ram size, we use it to detect old saves with incorrect ram sizes */
|
||||
save.ram_size = 0;
|
||||
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (!f) {
|
||||
GB_log(gb, "Could not open save state: %s.\n", strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
|
||||
bool fix_broken_windows_saves = false;
|
||||
if (fread(GB_GET_SECTION(&save, header), 1, GB_SECTION_SIZE(header), f) != GB_SECTION_SIZE(header)) goto error;
|
||||
if (save.magic == 0) {
|
||||
/* Potentially legacy, broken Windows save state */
|
||||
fseek(f, 4, SEEK_SET);
|
||||
if (fread(GB_GET_SECTION(&save, header), 1, GB_SECTION_SIZE(header), f) != GB_SECTION_SIZE(header)) goto error;
|
||||
fix_broken_windows_saves = true;
|
||||
}
|
||||
if (gb->magic != save.magic) {
|
||||
GB_log(gb, "The file is not a save state, or is from an incompatible operating system.\n");
|
||||
return false;
|
||||
}
|
||||
if (!READ_SECTION(&save, f, core_state)) goto error;
|
||||
if (!READ_SECTION(&save, f, dma )) goto error;
|
||||
if (!READ_SECTION(&save, f, mbc )) goto error;
|
||||
if (!READ_SECTION(&save, f, hram )) goto error;
|
||||
if (!READ_SECTION(&save, f, timing )) goto error;
|
||||
if (!READ_SECTION(&save, f, apu )) goto error;
|
||||
if (!READ_SECTION(&save, f, rtc )) goto error;
|
||||
if (!READ_SECTION(&save, f, video )) goto error;
|
||||
|
||||
if (!verify_and_update_state_compatibility(gb, &save)) {
|
||||
errno = -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (GB_is_hle_sgb(gb)) {
|
||||
if (!read_section(f, gb->sgb, sizeof(*gb->sgb), false)) goto error;
|
||||
}
|
||||
|
||||
memset(gb->mbc_ram + save.mbc_ram_size, 0xFF, gb->mbc_ram_size - save.mbc_ram_size);
|
||||
if (fread(gb->mbc_ram, 1, save.mbc_ram_size, f) != save.mbc_ram_size) {
|
||||
fclose(f);
|
||||
return EIO;
|
||||
}
|
||||
|
||||
if (fread(gb->ram, 1, gb->ram_size, f) != gb->ram_size) {
|
||||
fclose(f);
|
||||
return EIO;
|
||||
}
|
||||
|
||||
/* Fix for 0.11 save states that allocate twice the amount of RAM in CGB instances */
|
||||
fseek(f, save.ram_size - gb->ram_size, SEEK_CUR);
|
||||
|
||||
if (fread(gb->vram, 1, gb->vram_size, f) != gb->vram_size) {
|
||||
fclose(f);
|
||||
return EIO;
|
||||
}
|
||||
|
||||
size_t orig_ram_size = gb->ram_size;
|
||||
memcpy(gb, &save, sizeof(save));
|
||||
gb->ram_size = orig_ram_size;
|
||||
|
||||
errno = 0;
|
||||
|
||||
sanitize_state(gb);
|
||||
|
||||
error:
|
||||
fclose(f);
|
||||
return errno;
|
||||
}
|
||||
|
||||
#undef READ_SECTION
|
||||
|
||||
/* An read-like function for buffer-copying */
|
||||
static size_t buffer_read(void *dest, size_t length, const uint8_t **buffer, size_t *buffer_length)
|
||||
{
|
||||
if (length > *buffer_length) {
|
||||
length = *buffer_length;
|
||||
}
|
||||
|
||||
memcpy(dest, *buffer, length);
|
||||
*buffer += length;
|
||||
*buffer_length -= length;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static bool buffer_read_section(const uint8_t **buffer, size_t *buffer_length, void *dest, uint32_t size, bool fix_broken_windows_saves)
|
||||
{
|
||||
uint32_t saved_size = 0;
|
||||
if (buffer_read(&saved_size, sizeof(size), buffer, buffer_length) != sizeof(size)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (saved_size > *buffer_length) return false;
|
||||
|
||||
if (fix_broken_windows_saves) {
|
||||
if (saved_size < 4) {
|
||||
return false;
|
||||
}
|
||||
saved_size -= 4;
|
||||
*buffer += 4;
|
||||
}
|
||||
|
||||
if (saved_size <= size) {
|
||||
if (buffer_read(dest, saved_size, buffer, buffer_length) != saved_size) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (buffer_read(dest, size, buffer, buffer_length) != size) {
|
||||
return false;
|
||||
}
|
||||
*buffer += saved_size - size;
|
||||
*buffer_length -= saved_size - size;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define READ_SECTION(gb, buffer, length, section) buffer_read_section(&buffer, &length, GB_GET_SECTION(gb, section), GB_SECTION_SIZE(section), fix_broken_windows_saves)
|
||||
int GB_load_state_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t length)
|
||||
{
|
||||
GB_gameboy_t save;
|
||||
|
||||
/* Every unread value should be kept the same. */
|
||||
memcpy(&save, gb, sizeof(save));
|
||||
bool fix_broken_windows_saves = false;
|
||||
|
||||
if (buffer_read(GB_GET_SECTION(&save, header), GB_SECTION_SIZE(header), &buffer, &length) != GB_SECTION_SIZE(header)) return -1;
|
||||
if (save.magic == 0) {
|
||||
/* Potentially legacy, broken Windows save state*/
|
||||
buffer -= GB_SECTION_SIZE(header) - 4;
|
||||
length += GB_SECTION_SIZE(header) - 4;
|
||||
if (buffer_read(GB_GET_SECTION(&save, header), GB_SECTION_SIZE(header), &buffer, &length) != GB_SECTION_SIZE(header)) return -1;
|
||||
fix_broken_windows_saves = true;
|
||||
}
|
||||
if (gb->magic != save.magic) {
|
||||
GB_log(gb, "The file is not a save state, or is from an incompatible operating system.\n");
|
||||
return false;
|
||||
}
|
||||
if (!READ_SECTION(&save, buffer, length, core_state)) return -1;
|
||||
if (!READ_SECTION(&save, buffer, length, dma )) return -1;
|
||||
if (!READ_SECTION(&save, buffer, length, mbc )) return -1;
|
||||
if (!READ_SECTION(&save, buffer, length, hram )) return -1;
|
||||
if (!READ_SECTION(&save, buffer, length, timing )) return -1;
|
||||
if (!READ_SECTION(&save, buffer, length, apu )) return -1;
|
||||
if (!READ_SECTION(&save, buffer, length, rtc )) return -1;
|
||||
if (!READ_SECTION(&save, buffer, length, video )) return -1;
|
||||
|
||||
|
||||
if (!verify_and_update_state_compatibility(gb, &save)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (GB_is_hle_sgb(gb)) {
|
||||
if (!buffer_read_section(&buffer, &length, gb->sgb, sizeof(*gb->sgb), false)) return -1;
|
||||
}
|
||||
|
||||
memset(gb->mbc_ram + save.mbc_ram_size, 0xFF, gb->mbc_ram_size - save.mbc_ram_size);
|
||||
if (buffer_read(gb->mbc_ram, save.mbc_ram_size, &buffer, &length) != save.mbc_ram_size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (buffer_read(gb->ram, gb->ram_size, &buffer, &length) != gb->ram_size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (buffer_read(gb->vram, gb->vram_size, &buffer, &length) != gb->vram_size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Fix for 0.11 save states that allocate twice the amount of RAM in CGB instances */
|
||||
buffer += save.ram_size - gb->ram_size;
|
||||
length -= save.ram_size - gb->ram_size;
|
||||
|
||||
memcpy(gb, &save, sizeof(save));
|
||||
|
||||
sanitize_state(gb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef READ_SECTION
|
|
@ -0,0 +1,30 @@
|
|||
/* Macros to make the GB_gameboy_t struct more future compatible when state saving */
|
||||
#ifndef save_state_h
|
||||
#define save_state_h
|
||||
#include <stddef.h>
|
||||
|
||||
#define GB_PADDING(type, old_usage) type old_usage##__do_not_use
|
||||
|
||||
#ifdef __cplusplus
|
||||
/* For bsnes integration. C++ code does not need section information, and throws a fit over certain types such
|
||||
as anonymous enums inside unions */
|
||||
#define GB_SECTION(name, ...) __attribute__ ((aligned (8))) __VA_ARGS__
|
||||
#else
|
||||
#define GB_SECTION(name, ...) __attribute__ ((aligned (8))) union {uint8_t name##_section_start; struct {__VA_ARGS__};}; uint8_t name##_section_end[0]
|
||||
#define GB_SECTION_OFFSET(name) (offsetof(GB_gameboy_t, name##_section_start))
|
||||
#define GB_SECTION_SIZE(name) (offsetof(GB_gameboy_t, name##_section_end) - offsetof(GB_gameboy_t, name##_section_start))
|
||||
#define GB_GET_SECTION(gb, name) ((void*)&((gb)->name##_section_start))
|
||||
#endif
|
||||
|
||||
#define GB_aligned_double __attribute__ ((aligned (8))) double
|
||||
|
||||
|
||||
/* Public calls related to save states */
|
||||
int GB_save_state(GB_gameboy_t *gb, const char *path);
|
||||
size_t GB_get_save_state_size(GB_gameboy_t *gb);
|
||||
/* Assumes buffer is big enough to contain the save state. Use with GB_get_save_state_size(). */
|
||||
void GB_save_state_to_buffer(GB_gameboy_t *gb, uint8_t *buffer);
|
||||
|
||||
int GB_load_state(GB_gameboy_t *gb, const char *path);
|
||||
int GB_load_state_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t length);
|
||||
#endif /* save_state_h */
|
|
@ -0,0 +1,913 @@
|
|||
#include "gb.h"
|
||||
#include "random.h"
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#define INTRO_ANIMATION_LENGTH 200
|
||||
|
||||
enum {
|
||||
PAL01 = 0x00,
|
||||
PAL23 = 0x01,
|
||||
PAL03 = 0x02,
|
||||
PAL12 = 0x03,
|
||||
ATTR_BLK = 0x04,
|
||||
ATTR_LIN = 0x05,
|
||||
ATTR_DIV = 0x06,
|
||||
ATTR_CHR = 0x07,
|
||||
PAL_SET = 0x0A,
|
||||
PAL_TRN = 0x0B,
|
||||
DATA_SND = 0x0F,
|
||||
MLT_REQ = 0x11,
|
||||
CHR_TRN = 0x13,
|
||||
PCT_TRN = 0x14,
|
||||
ATTR_TRN = 0x15,
|
||||
ATTR_SET = 0x16,
|
||||
MASK_EN = 0x17,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
MASK_DISABLED,
|
||||
MASK_FREEZE,
|
||||
MASK_BLACK,
|
||||
MASK_COLOR_0,
|
||||
} mask_mode_t;
|
||||
|
||||
typedef enum {
|
||||
TRANSFER_LOW_TILES,
|
||||
TRANSFER_HIGH_TILES,
|
||||
TRANSFER_BORDER_DATA,
|
||||
TRANSFER_PALETTES,
|
||||
TRANSFER_ATTRIBUTES,
|
||||
} transfer_dest_t;
|
||||
|
||||
#define SGB_PACKET_SIZE 16
|
||||
static inline void pal_command(GB_gameboy_t *gb, unsigned first, unsigned second)
|
||||
{
|
||||
gb->sgb->effective_palettes[0] = gb->sgb->effective_palettes[4] =
|
||||
gb->sgb->effective_palettes[8] = gb->sgb->effective_palettes[12] =
|
||||
gb->sgb->command[1] | (gb->sgb->command[2] << 8);
|
||||
|
||||
for (unsigned i = 0; i < 3; i++) {
|
||||
gb->sgb->effective_palettes[first * 4 + i + 1] = gb->sgb->command[3 + i * 2] | (gb->sgb->command[4 + i * 2] << 8);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < 3; i++) {
|
||||
gb->sgb->effective_palettes[second * 4 + i + 1] = gb->sgb->command[9 + i * 2] | (gb->sgb->command[10 + i * 2] << 8);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void load_attribute_file(GB_gameboy_t *gb, unsigned file_index)
|
||||
{
|
||||
if (file_index > 0x2C) return;
|
||||
uint8_t *output = gb->sgb->attribute_map;
|
||||
for (unsigned i = 0; i < 90; i++) {
|
||||
uint8_t byte = gb->sgb->attribute_files[file_index * 90 + i];
|
||||
for (unsigned j = 4; j--;) {
|
||||
*(output++) = byte >> 6;
|
||||
byte <<= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const uint16_t built_in_palettes[] =
|
||||
{
|
||||
0x67BF, 0x265B, 0x10B5, 0x2866,
|
||||
0x637B, 0x3AD9, 0x0956, 0x0000,
|
||||
0x7F1F, 0x2A7D, 0x30F3, 0x4CE7,
|
||||
0x57FF, 0x2618, 0x001F, 0x006A,
|
||||
0x5B7F, 0x3F0F, 0x222D, 0x10EB,
|
||||
0x7FBB, 0x2A3C, 0x0015, 0x0900,
|
||||
0x2800, 0x7680, 0x01EF, 0x2FFF,
|
||||
0x73BF, 0x46FF, 0x0110, 0x0066,
|
||||
0x533E, 0x2638, 0x01E5, 0x0000,
|
||||
0x7FFF, 0x2BBF, 0x00DF, 0x2C0A,
|
||||
0x7F1F, 0x463D, 0x74CF, 0x4CA5,
|
||||
0x53FF, 0x03E0, 0x00DF, 0x2800,
|
||||
0x433F, 0x72D2, 0x3045, 0x0822,
|
||||
0x7FFA, 0x2A5F, 0x0014, 0x0003,
|
||||
0x1EED, 0x215C, 0x42FC, 0x0060,
|
||||
0x7FFF, 0x5EF7, 0x39CE, 0x0000,
|
||||
0x4F5F, 0x630E, 0x159F, 0x3126,
|
||||
0x637B, 0x121C, 0x0140, 0x0840,
|
||||
0x66BC, 0x3FFF, 0x7EE0, 0x2C84,
|
||||
0x5FFE, 0x3EBC, 0x0321, 0x0000,
|
||||
0x63FF, 0x36DC, 0x11F6, 0x392A,
|
||||
0x65EF, 0x7DBF, 0x035F, 0x2108,
|
||||
0x2B6C, 0x7FFF, 0x1CD9, 0x0007,
|
||||
0x53FC, 0x1F2F, 0x0E29, 0x0061,
|
||||
0x36BE, 0x7EAF, 0x681A, 0x3C00,
|
||||
0x7BBE, 0x329D, 0x1DE8, 0x0423,
|
||||
0x739F, 0x6A9B, 0x7293, 0x0001,
|
||||
0x5FFF, 0x6732, 0x3DA9, 0x2481,
|
||||
0x577F, 0x3EBC, 0x456F, 0x1880,
|
||||
0x6B57, 0x6E1B, 0x5010, 0x0007,
|
||||
0x0F96, 0x2C97, 0x0045, 0x3200,
|
||||
0x67FF, 0x2F17, 0x2230, 0x1548,
|
||||
};
|
||||
|
||||
static const struct {
|
||||
char name[16];
|
||||
unsigned palette_index;
|
||||
} palette_assignments[] =
|
||||
{
|
||||
{"ZELDA", 5},
|
||||
{"SUPER MARIOLAND", 6},
|
||||
{"MARIOLAND2", 0x14},
|
||||
{"SUPERMARIOLAND3", 2},
|
||||
{"KIRBY DREAM LAND", 0xB},
|
||||
{"HOSHINOKA-BI", 0xB},
|
||||
{"KIRBY'S PINBALL", 3},
|
||||
{"YOSSY NO TAMAGO", 0xC},
|
||||
{"MARIO & YOSHI", 0xC},
|
||||
{"YOSSY NO COOKIE", 4},
|
||||
{"YOSHI'S COOKIE", 4},
|
||||
{"DR.MARIO", 0x12},
|
||||
{"TETRIS", 0x11},
|
||||
{"YAKUMAN", 0x13},
|
||||
{"METROID2", 0x1F},
|
||||
{"KAERUNOTAMENI", 9},
|
||||
{"GOLF", 0x18},
|
||||
{"ALLEY WAY", 0x16},
|
||||
{"BASEBALL", 0xF},
|
||||
{"TENNIS", 0x17},
|
||||
{"F1RACE", 0x1E},
|
||||
{"KID ICARUS", 0xE},
|
||||
{"QIX", 0x19},
|
||||
{"SOLARSTRIKER", 7},
|
||||
{"X", 0x1C},
|
||||
{"GBWARS", 0x15},
|
||||
};
|
||||
|
||||
static void command_ready(GB_gameboy_t *gb)
|
||||
{
|
||||
/* SGB header commands are used to send the contents of the header to the SNES CPU.
|
||||
A header command looks like this:
|
||||
Command ID: 0b1111xxx1, where xxx is the packet index. (e.g. F1 for [0x104, 0x112), F3 for [0x112, 0x120))
|
||||
Checksum: Simple one byte sum for the following content bytes
|
||||
0xE content bytes. The last command, FB, is padded with zeros, so information past the header is not sent. */
|
||||
|
||||
if ((gb->sgb->command[0] & 0xF1) == 0xF1) {
|
||||
if (gb->boot_rom_finished) return;
|
||||
|
||||
uint8_t checksum = 0;
|
||||
for (unsigned i = 2; i < 0x10; i++) {
|
||||
checksum += gb->sgb->command[i];
|
||||
}
|
||||
if (checksum != gb->sgb->command[1]) {
|
||||
GB_log(gb, "Failed checksum for SGB header command, disabling SGB features\n");
|
||||
gb->sgb->disable_commands = true;
|
||||
return;
|
||||
}
|
||||
unsigned index = (gb->sgb->command[0] >> 1) & 7;
|
||||
if (index > 5) {
|
||||
return;
|
||||
}
|
||||
memcpy(&gb->sgb->received_header[index * 14], &gb->sgb->command[2], 14);
|
||||
if (gb->sgb->command[0] == 0xfb) {
|
||||
if (gb->sgb->received_header[0x42] != 3 || gb->sgb->received_header[0x47] != 0x33) {
|
||||
gb->sgb->disable_commands = true;
|
||||
for (unsigned i = 0; i < sizeof(palette_assignments) / sizeof(palette_assignments[0]); i++) {
|
||||
if (memcmp(palette_assignments[i].name, &gb->sgb->received_header[0x30], sizeof(palette_assignments[i].name)) == 0) {
|
||||
gb->sgb->effective_palettes[0] = built_in_palettes[palette_assignments[i].palette_index * 4 - 4];
|
||||
gb->sgb->effective_palettes[1] = built_in_palettes[palette_assignments[i].palette_index * 4 + 1 - 4];
|
||||
gb->sgb->effective_palettes[2] = built_in_palettes[palette_assignments[i].palette_index * 4 + 2 - 4];
|
||||
gb->sgb->effective_palettes[3] = built_in_palettes[palette_assignments[i].palette_index * 4 + 3 - 4];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ignore malformed commands (0 length)*/
|
||||
if ((gb->sgb->command[0] & 7) == 0) return;
|
||||
|
||||
switch (gb->sgb->command[0] >> 3) {
|
||||
case PAL01:
|
||||
pal_command(gb, 0, 1);
|
||||
break;
|
||||
case PAL23:
|
||||
pal_command(gb, 2, 3);
|
||||
break;
|
||||
case PAL03:
|
||||
pal_command(gb, 0, 3);
|
||||
break;
|
||||
case PAL12:
|
||||
pal_command(gb, 1, 2);
|
||||
break;
|
||||
case ATTR_BLK: {
|
||||
struct {
|
||||
uint8_t count;
|
||||
struct {
|
||||
uint8_t control;
|
||||
uint8_t palettes;
|
||||
uint8_t left, top, right, bottom;
|
||||
} data[];
|
||||
} *command = (void *)(gb->sgb->command + 1);
|
||||
if (command->count > 0x12) return;
|
||||
|
||||
for (unsigned i = 0; i < command->count; i++) {
|
||||
bool inside = command->data[i].control & 1;
|
||||
bool middle = command->data[i].control & 2;
|
||||
bool outside = command->data[i].control & 4;
|
||||
uint8_t inside_palette = command->data[i].palettes & 0x3;
|
||||
uint8_t middle_palette = (command->data[i].palettes >> 2) & 0x3;
|
||||
uint8_t outside_palette = (command->data[i].palettes >> 4) & 0x3;
|
||||
|
||||
if (inside && !middle && !outside) {
|
||||
middle = true;
|
||||
middle_palette = inside_palette;
|
||||
}
|
||||
else if (outside && !middle && !inside) {
|
||||
middle = true;
|
||||
middle_palette = outside_palette;
|
||||
}
|
||||
|
||||
command->data[i].left &= 0x1F;
|
||||
command->data[i].top &= 0x1F;
|
||||
command->data[i].right &= 0x1F;
|
||||
command->data[i].bottom &= 0x1F;
|
||||
|
||||
for (unsigned y = 0; y < 18; y++) {
|
||||
for (unsigned x = 0; x < 20; x++) {
|
||||
if (x < command->data[i].left || x > command->data[i].right ||
|
||||
y < command->data[i].top || y > command->data[i].bottom) {
|
||||
if (outside) {
|
||||
gb->sgb->attribute_map[x + 20 * y] = outside_palette;
|
||||
}
|
||||
}
|
||||
else if (x > command->data[i].left && x < command->data[i].right &&
|
||||
y > command->data[i].top && y < command->data[i].bottom) {
|
||||
if (inside) {
|
||||
gb->sgb->attribute_map[x + 20 * y] = inside_palette;
|
||||
}
|
||||
}
|
||||
else if (middle) {
|
||||
gb->sgb->attribute_map[x + 20 * y] = middle_palette;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ATTR_CHR: {
|
||||
struct __attribute__((packed)) {
|
||||
uint8_t x, y;
|
||||
uint16_t length;
|
||||
uint8_t direction;
|
||||
uint8_t data[];
|
||||
} *command = (void *)(gb->sgb->command + 1);
|
||||
|
||||
uint16_t count = command->length;
|
||||
#ifdef GB_BIG_ENDIAN
|
||||
count = __builtin_bswap16(count);
|
||||
#endif
|
||||
uint8_t x = command->x;
|
||||
uint8_t y = command->y;
|
||||
if (x >= 20 || y >= 18 || (count + 3) / 4 > sizeof(gb->sgb->command) - sizeof(*command) - 1) {
|
||||
/* TODO: Verify with the SFC BIOS */
|
||||
break;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
uint8_t palette = (command->data[i / 4] >> (((~i) & 3) << 1)) & 3;
|
||||
gb->sgb->attribute_map[x + 20 * y] = palette;
|
||||
if (command->direction) {
|
||||
y++;
|
||||
if (y == 18) {
|
||||
x++;
|
||||
y = 0;
|
||||
if (x == 20) {
|
||||
x = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
x++;
|
||||
if (x == 20) {
|
||||
y++;
|
||||
x = 0;
|
||||
if (y == 18) {
|
||||
y = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ATTR_LIN: {
|
||||
struct {
|
||||
uint8_t count;
|
||||
uint8_t data[];
|
||||
} *command = (void *)(gb->sgb->command + 1);
|
||||
if (command->count > sizeof(gb->sgb->command) - 2) return;
|
||||
|
||||
for (unsigned i = 0; i < command->count; i++) {
|
||||
bool horizontal = command->data[i] & 0x80;
|
||||
uint8_t palette = (command->data[i] >> 5) & 0x3;
|
||||
uint8_t line = (command->data[i]) & 0x1F;
|
||||
|
||||
if (horizontal) {
|
||||
if (line > 18) continue;
|
||||
for (unsigned x = 0; x < 20; x++) {
|
||||
gb->sgb->attribute_map[x + 20 * line] = palette;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (line > 20) continue;
|
||||
for (unsigned y = 0; y < 18; y++) {
|
||||
gb->sgb->attribute_map[line + 20 * y] = palette;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ATTR_DIV: {
|
||||
uint8_t high_palette = gb->sgb->command[1] & 3;
|
||||
uint8_t low_palette = (gb->sgb->command[1] >> 2) & 3;
|
||||
uint8_t middle_palette = (gb->sgb->command[1] >> 4) & 3;
|
||||
bool horizontal = gb->sgb->command[1] & 0x40;
|
||||
uint8_t line = gb->sgb->command[2] & 0x1F;
|
||||
|
||||
for (unsigned y = 0; y < 18; y++) {
|
||||
for (unsigned x = 0; x < 20; x++) {
|
||||
if ((horizontal? y : x) < line) {
|
||||
gb->sgb->attribute_map[x + 20 * y] = low_palette;
|
||||
}
|
||||
else if ((horizontal? y : x) == line) {
|
||||
gb->sgb->attribute_map[x + 20 * y] = middle_palette;
|
||||
}
|
||||
else {
|
||||
gb->sgb->attribute_map[x + 20 * y] = high_palette;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PAL_SET:
|
||||
memcpy(&gb->sgb->effective_palettes[0],
|
||||
&gb->sgb->ram_palettes[4 * (gb->sgb->command[1] + (gb->sgb->command[2] & 1) * 0x100)],
|
||||
8);
|
||||
memcpy(&gb->sgb->effective_palettes[4],
|
||||
&gb->sgb->ram_palettes[4 * (gb->sgb->command[3] + (gb->sgb->command[4] & 1) * 0x100)],
|
||||
8);
|
||||
memcpy(&gb->sgb->effective_palettes[8],
|
||||
&gb->sgb->ram_palettes[4 * (gb->sgb->command[5] + (gb->sgb->command[6] & 1) * 0x100)],
|
||||
8);
|
||||
memcpy(&gb->sgb->effective_palettes[12],
|
||||
&gb->sgb->ram_palettes[4 * (gb->sgb->command[7] + (gb->sgb->command[8] & 1) * 0x100)],
|
||||
8);
|
||||
|
||||
gb->sgb->effective_palettes[12] = gb->sgb->effective_palettes[8] =
|
||||
gb->sgb->effective_palettes[4] = gb->sgb->effective_palettes[0];
|
||||
|
||||
if (gb->sgb->command[9] & 0x80) {
|
||||
load_attribute_file(gb, gb->sgb->command[9] & 0x3F);
|
||||
}
|
||||
|
||||
if (gb->sgb->command[9] & 0x40) {
|
||||
gb->sgb->mask_mode = MASK_DISABLED;
|
||||
}
|
||||
break;
|
||||
case PAL_TRN:
|
||||
gb->sgb->vram_transfer_countdown = 2;
|
||||
gb->sgb->transfer_dest = TRANSFER_PALETTES;
|
||||
break;
|
||||
case DATA_SND:
|
||||
// Not supported, but used by almost all SGB games for hot patching, so let's mute the warning for this
|
||||
break;
|
||||
case MLT_REQ:
|
||||
if (gb->sgb->player_count == 1) {
|
||||
gb->sgb->current_player = 0;
|
||||
}
|
||||
gb->sgb->player_count = (gb->sgb->command[1] & 3) + 1; /* Todo: When breaking save state comaptibility,
|
||||
fix this to be 0 based. */
|
||||
if (gb->sgb->player_count == 3) {
|
||||
gb->sgb->current_player++;
|
||||
}
|
||||
gb->sgb->mlt_lock = true;
|
||||
break;
|
||||
case CHR_TRN:
|
||||
gb->sgb->vram_transfer_countdown = 2;
|
||||
gb->sgb->transfer_dest = (gb->sgb->command[1] & 1)? TRANSFER_HIGH_TILES : TRANSFER_LOW_TILES;
|
||||
break;
|
||||
case PCT_TRN:
|
||||
gb->sgb->vram_transfer_countdown = 2;
|
||||
gb->sgb->transfer_dest = TRANSFER_BORDER_DATA;
|
||||
break;
|
||||
case ATTR_TRN:
|
||||
gb->sgb->vram_transfer_countdown = 2;
|
||||
gb->sgb->transfer_dest = TRANSFER_ATTRIBUTES;
|
||||
break;
|
||||
case ATTR_SET:
|
||||
load_attribute_file(gb, gb->sgb->command[0] & 0x3F);
|
||||
|
||||
if (gb->sgb->command[0] & 0x40) {
|
||||
gb->sgb->mask_mode = MASK_DISABLED;
|
||||
}
|
||||
break;
|
||||
case MASK_EN:
|
||||
gb->sgb->mask_mode = gb->sgb->command[1] & 3;
|
||||
break;
|
||||
default:
|
||||
if ((gb->sgb->command[0] >> 3) == 8 &&
|
||||
(gb->sgb->command[1] & ~0x80) == 0 &&
|
||||
(gb->sgb->command[2] & ~0x80) == 0) {
|
||||
/* Mute/dummy sound commands, ignore this command as it's used by many games at startup */
|
||||
break;
|
||||
}
|
||||
GB_log(gb, "Unimplemented SGB command %x: ", gb->sgb->command[0] >> 3);
|
||||
for (unsigned i = 0; i < gb->sgb->command_write_index / 8; i++) {
|
||||
GB_log(gb, "%02x ", gb->sgb->command[i]);
|
||||
}
|
||||
GB_log(gb, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void GB_sgb_write(GB_gameboy_t *gb, uint8_t value)
|
||||
{
|
||||
if (!GB_is_sgb(gb)) return;
|
||||
if (!GB_is_hle_sgb(gb)) {
|
||||
/* Notify via callback */
|
||||
return;
|
||||
}
|
||||
if (gb->sgb->disable_commands) return;
|
||||
if (gb->sgb->command_write_index >= sizeof(gb->sgb->command) * 8) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t command_size = (gb->sgb->command[0] & 7 ?: 1) * SGB_PACKET_SIZE * 8;
|
||||
if ((gb->sgb->command[0] & 0xF1) == 0xF1) {
|
||||
command_size = SGB_PACKET_SIZE * 8;
|
||||
}
|
||||
|
||||
if ((value & 0x20) == 0 && (gb->io_registers[GB_IO_JOYP] & 0x20) != 0) {
|
||||
gb->sgb->mlt_lock ^= true;
|
||||
}
|
||||
|
||||
switch ((value >> 4) & 3) {
|
||||
case 3:
|
||||
gb->sgb->ready_for_pulse = true;
|
||||
if ((gb->sgb->player_count & 1) == 0 && !gb->sgb->mlt_lock) {
|
||||
gb->sgb->current_player++;
|
||||
gb->sgb->current_player &= 3;
|
||||
gb->sgb->mlt_lock = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // Zero
|
||||
if (!gb->sgb->ready_for_pulse || !gb->sgb->ready_for_write) return;
|
||||
if (gb->sgb->ready_for_stop) {
|
||||
if (gb->sgb->command_write_index == command_size) {
|
||||
command_ready(gb);
|
||||
gb->sgb->command_write_index = 0;
|
||||
memset(gb->sgb->command, 0, sizeof(gb->sgb->command));
|
||||
}
|
||||
gb->sgb->ready_for_pulse = false;
|
||||
gb->sgb->ready_for_write = false;
|
||||
gb->sgb->ready_for_stop = false;
|
||||
}
|
||||
else {
|
||||
gb->sgb->command_write_index++;
|
||||
gb->sgb->ready_for_pulse = false;
|
||||
if (((gb->sgb->command_write_index) & (SGB_PACKET_SIZE * 8 - 1)) == 0) {
|
||||
gb->sgb->ready_for_stop = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1: // One
|
||||
if (!gb->sgb->ready_for_pulse || !gb->sgb->ready_for_write) return;
|
||||
if (gb->sgb->ready_for_stop) {
|
||||
GB_log(gb, "Corrupt SGB command.\n");
|
||||
gb->sgb->ready_for_pulse = false;
|
||||
gb->sgb->ready_for_write = false;
|
||||
gb->sgb->command_write_index = 0;
|
||||
memset(gb->sgb->command, 0, sizeof(gb->sgb->command));
|
||||
}
|
||||
else {
|
||||
gb->sgb->command[gb->sgb->command_write_index / 8] |= 1 << (gb->sgb->command_write_index & 7);
|
||||
gb->sgb->command_write_index++;
|
||||
gb->sgb->ready_for_pulse = false;
|
||||
if (((gb->sgb->command_write_index) & (SGB_PACKET_SIZE * 8 - 1)) == 0) {
|
||||
gb->sgb->ready_for_stop = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0:
|
||||
if (!gb->sgb->ready_for_pulse) return;
|
||||
gb->sgb->ready_for_write = true;
|
||||
gb->sgb->ready_for_pulse = false;
|
||||
if (((gb->sgb->command_write_index) & (SGB_PACKET_SIZE * 8 - 1)) != 0 ||
|
||||
gb->sgb->command_write_index == 0 ||
|
||||
gb->sgb->ready_for_stop) {
|
||||
gb->sgb->command_write_index = 0;
|
||||
memset(gb->sgb->command, 0, sizeof(gb->sgb->command));
|
||||
gb->sgb->ready_for_stop = false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t convert_rgb15(GB_gameboy_t *gb, uint16_t color)
|
||||
{
|
||||
return GB_convert_rgb15(gb, color, false);
|
||||
}
|
||||
|
||||
static uint32_t convert_rgb15_with_fade(GB_gameboy_t *gb, uint16_t color, uint8_t fade)
|
||||
{
|
||||
uint8_t r = ((color) & 0x1F) - fade;
|
||||
uint8_t g = ((color >> 5) & 0x1F) - fade;
|
||||
uint8_t b = ((color >> 10) & 0x1F) - fade;
|
||||
|
||||
if (r >= 0x20) r = 0;
|
||||
if (g >= 0x20) g = 0;
|
||||
if (b >= 0x20) b = 0;
|
||||
|
||||
color = r | (g << 5) | (b << 10);
|
||||
|
||||
return GB_convert_rgb15(gb, color, false);
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
static void render_boot_animation (GB_gameboy_t *gb)
|
||||
{
|
||||
#include "graphics/sgb_animation_logo.inc"
|
||||
uint32_t *output = gb->screen;
|
||||
if (gb->border_mode != GB_BORDER_NEVER) {
|
||||
output += 48 + 40 * 256;
|
||||
}
|
||||
uint8_t *input = animation_logo;
|
||||
unsigned fade_blue = 0;
|
||||
unsigned fade_red = 0;
|
||||
if (gb->sgb->intro_animation < 80 - 32) {
|
||||
fade_blue = 32;
|
||||
}
|
||||
else if (gb->sgb->intro_animation < 80) {
|
||||
fade_blue = 80 - gb->sgb->intro_animation;
|
||||
}
|
||||
else if (gb->sgb->intro_animation > INTRO_ANIMATION_LENGTH - 32) {
|
||||
fade_red = fade_blue = gb->sgb->intro_animation - INTRO_ANIMATION_LENGTH + 32;
|
||||
}
|
||||
uint32_t colors[] = {
|
||||
convert_rgb15(gb, 0),
|
||||
convert_rgb15_with_fade(gb, 0x14A5, fade_blue),
|
||||
convert_rgb15_with_fade(gb, 0x54E0, fade_blue),
|
||||
convert_rgb15_with_fade(gb, 0x0019, fade_red),
|
||||
convert_rgb15(gb, 0x0011),
|
||||
convert_rgb15(gb, 0x0009),
|
||||
};
|
||||
unsigned y_min = (144 - animation_logo_height) / 2;
|
||||
unsigned y_max = y_min + animation_logo_height;
|
||||
for (unsigned y = 0; y < 144; y++) {
|
||||
for (unsigned x = 0; x < 160; x++) {
|
||||
if (y < y_min || y >= y_max) {
|
||||
*(output++) = colors[0];
|
||||
}
|
||||
else {
|
||||
uint8_t color = *input;
|
||||
if (color >= 3) {
|
||||
if (color == gb->sgb->intro_animation / 2 - 3) {
|
||||
color = 5;
|
||||
}
|
||||
else if (color == gb->sgb->intro_animation / 2 - 4) {
|
||||
color = 4;
|
||||
}
|
||||
else if (color < gb->sgb->intro_animation / 2 - 4) {
|
||||
color = 3;
|
||||
}
|
||||
else {
|
||||
color = 0;
|
||||
}
|
||||
}
|
||||
*(output++) = colors[color];
|
||||
input++;
|
||||
}
|
||||
}
|
||||
if (gb->border_mode != GB_BORDER_NEVER) {
|
||||
output += 256 - 160;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void render_jingle(GB_gameboy_t *gb, size_t count);
|
||||
void GB_sgb_render(GB_gameboy_t *gb)
|
||||
{
|
||||
if (gb->apu_output.sample_rate) {
|
||||
render_jingle(gb, gb->apu_output.sample_rate / GB_get_usual_frame_rate(gb));
|
||||
}
|
||||
|
||||
if (gb->sgb->intro_animation < INTRO_ANIMATION_LENGTH) gb->sgb->intro_animation++;
|
||||
|
||||
if (gb->sgb->vram_transfer_countdown) {
|
||||
if (--gb->sgb->vram_transfer_countdown == 0) {
|
||||
if (gb->sgb->transfer_dest == TRANSFER_LOW_TILES || gb->sgb->transfer_dest == TRANSFER_HIGH_TILES) {
|
||||
uint8_t *base = &gb->sgb->pending_border.tiles[gb->sgb->transfer_dest == TRANSFER_HIGH_TILES ? 0x80 * 8 * 8 : 0];
|
||||
for (unsigned tile = 0; tile < 0x80; tile++) {
|
||||
unsigned tile_x = (tile % 10) * 16;
|
||||
unsigned tile_y = (tile / 10) * 8;
|
||||
for (unsigned y = 0; y < 0x8; y++) {
|
||||
for (unsigned x = 0; x < 0x8; x++) {
|
||||
base[tile * 8 * 8 + y * 8 + x] = gb->sgb->screen_buffer[(tile_x + x) + (tile_y + y) * 160] +
|
||||
gb->sgb->screen_buffer[(tile_x + x + 8) + (tile_y + y) * 160] * 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
unsigned size = 0;
|
||||
uint16_t *data = NULL;
|
||||
|
||||
switch (gb->sgb->transfer_dest) {
|
||||
case TRANSFER_PALETTES:
|
||||
size = 0x100;
|
||||
data = gb->sgb->ram_palettes;
|
||||
break;
|
||||
case TRANSFER_BORDER_DATA:
|
||||
size = 0x88;
|
||||
data = gb->sgb->pending_border.raw_data;
|
||||
break;
|
||||
case TRANSFER_ATTRIBUTES:
|
||||
size = 0xFE;
|
||||
data = (uint16_t *)gb->sgb->attribute_files;
|
||||
break;
|
||||
default:
|
||||
return; // Corrupt state?
|
||||
}
|
||||
|
||||
for (unsigned tile = 0; tile < size; tile++) {
|
||||
unsigned tile_x = (tile % 20) * 8;
|
||||
unsigned tile_y = (tile / 20) * 8;
|
||||
for (unsigned y = 0; y < 0x8; y++) {
|
||||
static const uint16_t pixel_to_bits[4] = {0x0000, 0x0080, 0x8000, 0x8080};
|
||||
*data = 0;
|
||||
for (unsigned x = 0; x < 8; x++) {
|
||||
*data |= pixel_to_bits[gb->sgb->screen_buffer[(tile_x + x) + (tile_y + y) * 160] & 3] >> x;
|
||||
}
|
||||
#ifdef GB_BIG_ENDIAN
|
||||
if (gb->sgb->transfer_dest == TRANSFER_ATTRIBUTES) {
|
||||
*data = __builtin_bswap16(*data);
|
||||
}
|
||||
#endif
|
||||
data++;
|
||||
}
|
||||
}
|
||||
if (gb->sgb->transfer_dest == TRANSFER_BORDER_DATA) {
|
||||
gb->sgb->border_animation = 64;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!gb->screen || !gb->rgb_encode_callback || gb->disable_rendering) return;
|
||||
|
||||
uint32_t colors[4 * 4];
|
||||
for (unsigned i = 0; i < 4 * 4; i++) {
|
||||
colors[i] = convert_rgb15(gb, gb->sgb->effective_palettes[i]);
|
||||
}
|
||||
|
||||
if (gb->sgb->mask_mode != MASK_FREEZE) {
|
||||
memcpy(gb->sgb->effective_screen_buffer,
|
||||
gb->sgb->screen_buffer,
|
||||
sizeof(gb->sgb->effective_screen_buffer));
|
||||
}
|
||||
|
||||
if (gb->sgb->intro_animation < INTRO_ANIMATION_LENGTH) {
|
||||
render_boot_animation(gb);
|
||||
}
|
||||
else {
|
||||
uint32_t *output = gb->screen;
|
||||
if (gb->border_mode != GB_BORDER_NEVER) {
|
||||
output += 48 + 40 * 256;
|
||||
}
|
||||
uint8_t *input = gb->sgb->effective_screen_buffer;
|
||||
switch ((mask_mode_t) gb->sgb->mask_mode) {
|
||||
case MASK_DISABLED:
|
||||
case MASK_FREEZE: {
|
||||
for (unsigned y = 0; y < 144; y++) {
|
||||
for (unsigned x = 0; x < 160; x++) {
|
||||
uint8_t palette = gb->sgb->attribute_map[x / 8 + y / 8 * 20] & 3;
|
||||
*(output++) = colors[(*(input++) & 3) + palette * 4];
|
||||
}
|
||||
if (gb->border_mode != GB_BORDER_NEVER) {
|
||||
output += 256 - 160;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MASK_BLACK:
|
||||
{
|
||||
uint32_t black = convert_rgb15(gb, 0);
|
||||
for (unsigned y = 0; y < 144; y++) {
|
||||
for (unsigned x = 0; x < 160; x++) {
|
||||
*(output++) = black;
|
||||
}
|
||||
if (gb->border_mode != GB_BORDER_NEVER) {
|
||||
output += 256 - 160;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MASK_COLOR_0:
|
||||
{
|
||||
for (unsigned y = 0; y < 144; y++) {
|
||||
for (unsigned x = 0; x < 160; x++) {
|
||||
*(output++) = colors[0];
|
||||
}
|
||||
if (gb->border_mode != GB_BORDER_NEVER) {
|
||||
output += 256 - 160;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t border_colors[16 * 4];
|
||||
if (gb->sgb->border_animation == 0 || gb->sgb->intro_animation < INTRO_ANIMATION_LENGTH) {
|
||||
for (unsigned i = 0; i < 16 * 4; i++) {
|
||||
border_colors[i] = convert_rgb15(gb, gb->sgb->border.palette[i]);
|
||||
}
|
||||
}
|
||||
else if (gb->sgb->border_animation > 32) {
|
||||
gb->sgb->border_animation--;
|
||||
for (unsigned i = 0; i < 16 * 4; i++) {
|
||||
border_colors[i] = convert_rgb15_with_fade(gb, gb->sgb->border.palette[i], 64 - gb->sgb->border_animation);
|
||||
}
|
||||
}
|
||||
else {
|
||||
gb->sgb->border_animation--;
|
||||
for (unsigned i = 0; i < 16 * 4; i++) {
|
||||
border_colors[i] = convert_rgb15_with_fade(gb, gb->sgb->border.palette[i], gb->sgb->border_animation);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (gb->sgb->border_animation == 32) {
|
||||
memcpy(&gb->sgb->border, &gb->sgb->pending_border, sizeof(gb->sgb->border));
|
||||
}
|
||||
|
||||
for (unsigned tile_y = 0; tile_y < 28; tile_y++) {
|
||||
for (unsigned tile_x = 0; tile_x < 32; tile_x++) {
|
||||
bool gb_area = false;
|
||||
if (tile_x >= 6 && tile_x < 26 && tile_y >= 5 && tile_y < 23) {
|
||||
gb_area = true;
|
||||
}
|
||||
else if (gb->border_mode == GB_BORDER_NEVER) {
|
||||
continue;
|
||||
}
|
||||
uint16_t tile = gb->sgb->border.map[tile_x + tile_y * 32];
|
||||
uint8_t flip_x = (tile & 0x4000)? 0x7 : 0;
|
||||
uint8_t flip_y = (tile & 0x8000)? 0x7 : 0;
|
||||
uint8_t palette = (tile >> 10) & 3;
|
||||
for (unsigned y = 0; y < 8; y++) {
|
||||
for (unsigned x = 0; x < 8; x++) {
|
||||
uint8_t color = gb->sgb->border.tiles[(tile & 0xFF) * 64 + (x ^ flip_x) + (y ^ flip_y) * 8] & 0xF;
|
||||
uint32_t *output = gb->screen;
|
||||
if (gb->border_mode == GB_BORDER_NEVER) {
|
||||
output += (tile_x - 6) * 8 + x + ((tile_y - 5) * 8 + y) * 160;
|
||||
}
|
||||
else {
|
||||
output += tile_x * 8 + x + (tile_y * 8 + y) * 256;
|
||||
}
|
||||
if (color == 0) {
|
||||
if (gb_area) continue;
|
||||
*output = colors[0];
|
||||
}
|
||||
else {
|
||||
*output = border_colors[color + palette * 16];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GB_sgb_load_default_data(GB_gameboy_t *gb)
|
||||
{
|
||||
|
||||
#include "graphics/sgb_border.inc"
|
||||
|
||||
memcpy(gb->sgb->border.map, tilemap, sizeof(tilemap));
|
||||
memcpy(gb->sgb->border.palette, palette, sizeof(palette));
|
||||
|
||||
/* Expand tileset */
|
||||
for (unsigned tile = 0; tile < sizeof(tiles) / 32; tile++) {
|
||||
for (unsigned y = 0; y < 8; y++) {
|
||||
for (unsigned x = 0; x < 8; x++) {
|
||||
gb->sgb->border.tiles[tile * 8 * 8 + y * 8 + x] =
|
||||
(tiles[tile * 32 + y * 2 + 0] & (1 << (7 ^ x)) ? 1 : 0) |
|
||||
(tiles[tile * 32 + y * 2 + 1] & (1 << (7 ^ x)) ? 2 : 0) |
|
||||
(tiles[tile * 32 + y * 2 + 16] & (1 << (7 ^ x)) ? 4 : 0) |
|
||||
(tiles[tile * 32 + y * 2 + 17] & (1 << (7 ^ x)) ? 8 : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gb->model != GB_MODEL_SGB2) {
|
||||
/* Delete the "2" */
|
||||
gb->sgb->border.map[25 * 32 + 25] = gb->sgb->border.map[25 * 32 + 26] =
|
||||
gb->sgb->border.map[26 * 32 + 25] = gb->sgb->border.map[26 * 32 + 26] =
|
||||
gb->sgb->border.map[27 * 32 + 25] = gb->sgb->border.map[27 * 32 + 26] =
|
||||
gb->sgb->border.map[0];
|
||||
|
||||
/* Re-center */
|
||||
memmove(&gb->sgb->border.map[25 * 32 + 1], &gb->sgb->border.map[25 * 32], (32 * 3 - 1) * sizeof(gb->sgb->border.map[0]));
|
||||
}
|
||||
gb->sgb->effective_palettes[0] = built_in_palettes[0];
|
||||
gb->sgb->effective_palettes[1] = built_in_palettes[1];
|
||||
gb->sgb->effective_palettes[2] = built_in_palettes[2];
|
||||
gb->sgb->effective_palettes[3] = built_in_palettes[3];
|
||||
}
|
||||
|
||||
static double fm_synth(double phase)
|
||||
{
|
||||
return (sin(phase * M_PI * 2) +
|
||||
sin(phase * M_PI * 2 + sin(phase * M_PI * 2)) +
|
||||
sin(phase * M_PI * 2 + sin(phase * M_PI * 3)) +
|
||||
sin(phase * M_PI * 2 + sin(phase * M_PI * 4))) / 4;
|
||||
}
|
||||
|
||||
static double fm_sweep(double phase)
|
||||
{
|
||||
double ret = 0;
|
||||
for (unsigned i = 0; i < 8; i++) {
|
||||
ret += sin((phase * M_PI * 2 + sin(phase * M_PI * 8) / 4) * pow(1.25, i)) * (8 - i) / 36;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static double random_double(void)
|
||||
{
|
||||
return ((signed)(GB_random32() % 0x10001) - 0x8000) / (double) 0x8000;
|
||||
}
|
||||
|
||||
static void render_jingle(GB_gameboy_t *gb, size_t count)
|
||||
{
|
||||
const double frequencies[7] = {
|
||||
466.16, // Bb4
|
||||
587.33, // D5
|
||||
698.46, // F5
|
||||
830.61, // Ab5
|
||||
1046.50, // C6
|
||||
1244.51, // Eb6
|
||||
1567.98, // G6
|
||||
};
|
||||
|
||||
assert(gb->apu_output.sample_callback);
|
||||
|
||||
if (gb->sgb->intro_animation < 0) {
|
||||
GB_sample_t sample = {0, 0};
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
gb->apu_output.sample_callback(gb, &sample);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (gb->sgb->intro_animation >= INTRO_ANIMATION_LENGTH) return;
|
||||
|
||||
signed jingle_stage = (gb->sgb->intro_animation - 64) / 3;
|
||||
double sweep_cutoff_ratio = 2000.0 * pow(2, gb->sgb->intro_animation / 20.0) / gb->apu_output.sample_rate;
|
||||
double sweep_phase_shift = 1000.0 * pow(2, gb->sgb->intro_animation / 40.0) / gb->apu_output.sample_rate;
|
||||
if (sweep_cutoff_ratio > 1) {
|
||||
sweep_cutoff_ratio = 1;
|
||||
}
|
||||
|
||||
GB_sample_t stereo;
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
double sample = 0;
|
||||
for (signed f = 0; f < 7 && f < jingle_stage; f++) {
|
||||
sample += fm_synth(gb->sgb_intro_jingle_phases[f]) *
|
||||
(0.75 * pow(0.5, jingle_stage - f) + 0.25) / 5.0;
|
||||
gb->sgb_intro_jingle_phases[f] += frequencies[f] / gb->apu_output.sample_rate;
|
||||
}
|
||||
if (gb->sgb->intro_animation > 100) {
|
||||
sample *= pow((INTRO_ANIMATION_LENGTH - gb->sgb->intro_animation) / (INTRO_ANIMATION_LENGTH - 100.0), 3);
|
||||
}
|
||||
|
||||
if (gb->sgb->intro_animation < 120) {
|
||||
double next = fm_sweep(gb->sgb_intro_sweep_phase) * 0.3 + random_double() * 0.7;
|
||||
gb->sgb_intro_sweep_phase += sweep_phase_shift;
|
||||
|
||||
gb->sgb_intro_sweep_previous_sample = next * (sweep_cutoff_ratio) +
|
||||
gb->sgb_intro_sweep_previous_sample * (1 - sweep_cutoff_ratio);
|
||||
sample += gb->sgb_intro_sweep_previous_sample * pow((120 - gb->sgb->intro_animation) / 120.0, 2) * 0.8;
|
||||
}
|
||||
|
||||
stereo.left = stereo.right = sample * 0x7000;
|
||||
gb->apu_output.sample_callback(gb, &stereo);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
#ifndef sgb_h
|
||||
#define sgb_h
|
||||
#include "gb_struct_def.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct GB_sgb_s GB_sgb_t;
|
||||
typedef struct {
|
||||
uint8_t tiles[0x100 * 8 * 8]; /* High nibble not used*/
|
||||
union {
|
||||
struct {
|
||||
uint16_t map[32 * 32];
|
||||
uint16_t palette[16 * 4];
|
||||
};
|
||||
uint16_t raw_data[0x440];
|
||||
};
|
||||
} GB_sgb_border_t;
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
struct GB_sgb_s {
|
||||
uint8_t command[16 * 7];
|
||||
uint16_t command_write_index;
|
||||
bool ready_for_pulse;
|
||||
bool ready_for_write;
|
||||
bool ready_for_stop;
|
||||
bool disable_commands;
|
||||
|
||||
/* Screen buffer */
|
||||
uint8_t screen_buffer[160 * 144]; // Live image from the Game Boy
|
||||
uint8_t effective_screen_buffer[160 * 144]; // Image actually rendered to the screen
|
||||
|
||||
/* Multiplayer Input */
|
||||
uint8_t player_count, current_player;
|
||||
|
||||
/* Mask */
|
||||
uint8_t mask_mode;
|
||||
|
||||
/* Data Transfer */
|
||||
uint8_t vram_transfer_countdown, transfer_dest;
|
||||
|
||||
/* Border */
|
||||
GB_sgb_border_t border, pending_border;
|
||||
uint8_t border_animation;
|
||||
|
||||
/* Colorization */
|
||||
uint16_t effective_palettes[4 * 4];
|
||||
uint16_t ram_palettes[4 * 512];
|
||||
uint8_t attribute_map[20 * 18];
|
||||
uint8_t attribute_files[0xFE0];
|
||||
|
||||
/* Intro */
|
||||
int16_t intro_animation;
|
||||
|
||||
/* GB Header */
|
||||
uint8_t received_header[0x54];
|
||||
|
||||
/* Multiplayer (cont) */
|
||||
bool mlt_lock;
|
||||
};
|
||||
|
||||
void GB_sgb_write(GB_gameboy_t *gb, uint8_t value);
|
||||
void GB_sgb_render(GB_gameboy_t *gb);
|
||||
void GB_sgb_load_default_data(GB_gameboy_t *gb);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,11 @@
|
|||
#ifndef sm83_cpu_h
|
||||
#define sm83_cpu_h
|
||||
#include "gb_struct_def.h"
|
||||
#include <stdint.h>
|
||||
|
||||
void GB_cpu_disassemble(GB_gameboy_t *gb, uint16_t pc, uint16_t count);
|
||||
#ifdef GB_INTERNAL
|
||||
void GB_cpu_run(GB_gameboy_t *gb);
|
||||
#endif
|
||||
|
||||
#endif /* sm83_cpu_h */
|
|
@ -0,0 +1,789 @@
|
|||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include "gb.h"
|
||||
|
||||
|
||||
typedef void GB_opcode_t(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc);
|
||||
|
||||
static void ill(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, ".BYTE $%02x\n", opcode);
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void nop(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "NOP\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void stop(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint8_t next = GB_read_memory(gb, (*pc)++);
|
||||
if (next) {
|
||||
GB_log(gb, "CORRUPTED STOP (%02x)\n", next);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "STOP\n");
|
||||
}
|
||||
}
|
||||
|
||||
static char *register_names[] = {"af", "bc", "de", "hl", "sp"};
|
||||
|
||||
static void ld_rr_d16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
uint16_t value;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
value = GB_read_memory(gb, (*pc)++);
|
||||
value |= GB_read_memory(gb, (*pc)++) << 8;
|
||||
const char *symbol = GB_debugger_name_for_address(gb, value);
|
||||
if (symbol) {
|
||||
GB_log(gb, "LD %s, %s ; =$%04x\n", register_names[register_id], symbol, value);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "LD %s, $%04x\n", register_names[register_id], value);
|
||||
}
|
||||
}
|
||||
|
||||
static void ld_drr_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
GB_log(gb, "LD [%s], a\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void inc_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
GB_log(gb, "INC %s\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void inc_hr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
(*pc)++;
|
||||
register_id = ((opcode >> 4) + 1) & 0x03;
|
||||
GB_log(gb, "INC %c\n", register_names[register_id][0]);
|
||||
|
||||
}
|
||||
static void dec_hr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
(*pc)++;
|
||||
register_id = ((opcode >> 4) + 1) & 0x03;
|
||||
GB_log(gb, "DEC %c\n", register_names[register_id][0]);
|
||||
}
|
||||
|
||||
static void ld_hr_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
(*pc)++;
|
||||
register_id = ((opcode >> 4) + 1) & 0x03;
|
||||
GB_log(gb, "LD %c, $%02x\n", register_names[register_id][0], GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void rlca(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "RLCA\n");
|
||||
}
|
||||
|
||||
static void rla(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "RLA\n");
|
||||
}
|
||||
|
||||
static void ld_da16_sp(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint16_t addr;
|
||||
(*pc)++;
|
||||
addr = GB_read_memory(gb, (*pc)++);
|
||||
addr |= GB_read_memory(gb, (*pc)++) << 8;
|
||||
const char *symbol = GB_debugger_name_for_address(gb, addr);
|
||||
if (symbol) {
|
||||
GB_log(gb, "LD [%s], sp ; =$%04x\n", symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "LD [$%04x], sp\n", addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void add_hl_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
(*pc)++;
|
||||
register_id = (opcode >> 4) + 1;
|
||||
GB_log(gb, "ADD hl, %s\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void ld_a_drr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
GB_log(gb, "LD a, [%s]\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void dec_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
GB_log(gb, "DEC %s\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void inc_lr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
|
||||
GB_log(gb, "INC %c\n", register_names[register_id][1]);
|
||||
}
|
||||
static void dec_lr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
|
||||
GB_log(gb, "DEC %c\n", register_names[register_id][1]);
|
||||
}
|
||||
|
||||
static void ld_lr_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
|
||||
GB_log(gb, "LD %c, $%02x\n", register_names[register_id][1], GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void rrca(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "RRCA\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void rra(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "RRA\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void jr_r8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint16_t addr = *pc + (int8_t) GB_read_memory(gb, (*pc)) + 1;
|
||||
const char *symbol = GB_debugger_name_for_address(gb, addr);
|
||||
if (symbol) {
|
||||
GB_attributed_log(gb, GB_LOG_UNDERLINE, "JR %s ; =$%04x\n", symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_attributed_log(gb, GB_LOG_UNDERLINE, "JR $%04x\n", addr);
|
||||
}
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static const char *condition_code(uint8_t opcode)
|
||||
{
|
||||
switch ((opcode >> 3) & 0x3) {
|
||||
case 0:
|
||||
return "nz";
|
||||
case 1:
|
||||
return "z";
|
||||
case 2:
|
||||
return "nc";
|
||||
case 3:
|
||||
return "c";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void jr_cc_r8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint16_t addr = *pc + (int8_t) GB_read_memory(gb, (*pc)) + 1;
|
||||
const char *symbol = GB_debugger_name_for_address(gb, addr);
|
||||
if (symbol) {
|
||||
GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JR %s, %s ; =$%04x\n", condition_code(opcode), symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JR %s, $%04x\n", condition_code(opcode), addr);
|
||||
}
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void daa(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "DAA\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void cpl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "CPL\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void scf(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "SCF\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void ccf(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "CCF\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void ld_dhli_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "LD [hli], a\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void ld_dhld_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "LD [hld], a\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void ld_a_dhli(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "LD a, [hli]\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void ld_a_dhld(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "LD a, [hld]\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void inc_dhl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "INC [hl]\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void dec_dhl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "DEC [hl]\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void ld_dhl_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "LD [hl], $%02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static const char *get_src_name(uint8_t opcode)
|
||||
{
|
||||
uint8_t src_register_id;
|
||||
uint8_t src_low;
|
||||
src_register_id = ((opcode >> 1) + 1) & 3;
|
||||
src_low = (opcode & 1);
|
||||
if (src_register_id == GB_REGISTER_AF) {
|
||||
return src_low? "a": "[hl]";
|
||||
}
|
||||
if (src_low) {
|
||||
return register_names[src_register_id] + 1;
|
||||
}
|
||||
static const char *high_register_names[] = {"a", "b", "d", "h"};
|
||||
return high_register_names[src_register_id];
|
||||
}
|
||||
|
||||
static const char *get_dst_name(uint8_t opcode)
|
||||
{
|
||||
uint8_t dst_register_id;
|
||||
uint8_t dst_low;
|
||||
dst_register_id = ((opcode >> 4) + 1) & 3;
|
||||
dst_low = opcode & 8;
|
||||
if (dst_register_id == GB_REGISTER_AF) {
|
||||
return dst_low? "a": "[hl]";
|
||||
}
|
||||
if (dst_low) {
|
||||
return register_names[dst_register_id] + 1;
|
||||
}
|
||||
static const char *high_register_names[] = {"a", "b", "d", "h"};
|
||||
return high_register_names[dst_register_id];
|
||||
}
|
||||
|
||||
static void ld_r_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "LD %s, %s\n", get_dst_name(opcode), get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void add_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "ADD %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void adc_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "ADC %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void sub_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "SUB %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void sbc_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "SBC %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void and_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "AND %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void xor_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "XOR %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void or_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "OR %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void cp_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "CP %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void halt(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "HALT\n");
|
||||
}
|
||||
|
||||
static void ret_cc(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "RET %s\n", condition_code(opcode));
|
||||
}
|
||||
|
||||
static void pop_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
register_id = ((GB_read_memory(gb, (*pc)++) >> 4) + 1) & 3;
|
||||
GB_log(gb, "POP %s\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void jp_cc_a16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8);
|
||||
const char *symbol = GB_debugger_name_for_address(gb, addr);
|
||||
if (symbol) {
|
||||
GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JP %s, %s ; =$%04x\n", condition_code(opcode), symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JP %s, $%04x\n", condition_code(opcode), addr);
|
||||
}
|
||||
(*pc) += 2;
|
||||
}
|
||||
|
||||
static void jp_a16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8);
|
||||
const char *symbol = GB_debugger_name_for_address(gb, addr);
|
||||
if (symbol) {
|
||||
GB_log(gb, "JP %s ; =$%04x\n", symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "JP $%04x\n", addr);
|
||||
}
|
||||
(*pc) += 2;
|
||||
}
|
||||
|
||||
static void call_cc_a16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8);
|
||||
const char *symbol = GB_debugger_name_for_address(gb, addr);
|
||||
if (symbol) {
|
||||
GB_log(gb, "CALL %s, %s ; =$%04x\n", condition_code(opcode), symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "CALL %s, $%04x\n", condition_code(opcode), addr);
|
||||
}
|
||||
(*pc) += 2;
|
||||
}
|
||||
|
||||
static void push_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
register_id = ((GB_read_memory(gb, (*pc)++) >> 4) + 1) & 3;
|
||||
GB_log(gb, "PUSH %s\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void add_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "ADD $%02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void adc_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "ADC $%02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void sub_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "SUB $%02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void sbc_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "SBC $%02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void and_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "AND $%02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void xor_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "XOR $%02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void or_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "OR $%02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void cp_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "CP $%02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void rst(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "RST $%02x\n", opcode ^ 0xC7);
|
||||
|
||||
}
|
||||
|
||||
static void ret(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_attributed_log(gb, GB_LOG_UNDERLINE, "RET\n");
|
||||
}
|
||||
|
||||
static void reti(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_attributed_log(gb, GB_LOG_UNDERLINE, "RETI\n");
|
||||
}
|
||||
|
||||
static void call_a16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8);
|
||||
const char *symbol = GB_debugger_name_for_address(gb, addr);
|
||||
if (symbol) {
|
||||
GB_log(gb, "CALL %s ; =$%04x\n", symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "CALL $%04x\n", addr);
|
||||
}
|
||||
(*pc) += 2;
|
||||
}
|
||||
|
||||
static void ld_da8_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint8_t addr = GB_read_memory(gb, (*pc)++);
|
||||
const char *symbol = GB_debugger_name_for_address(gb, 0xff00 + addr);
|
||||
if (symbol) {
|
||||
GB_log(gb, "LDH [%s & $FF], a ; =$%02x\n", symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "LDH [$%02x], a\n", addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void ld_a_da8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint8_t addr = GB_read_memory(gb, (*pc)++);
|
||||
const char *symbol = GB_debugger_name_for_address(gb, 0xff00 + addr);
|
||||
if (symbol) {
|
||||
GB_log(gb, "LDH a, [%s & $FF] ; =$%02x\n", symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "LDH a, [$%02x]\n", addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void ld_dc_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "LDH [c], a\n");
|
||||
}
|
||||
|
||||
static void ld_a_dc(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "LDH a, [c]\n");
|
||||
}
|
||||
|
||||
static void add_sp_r8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
int8_t temp = GB_read_memory(gb, (*pc)++);
|
||||
GB_log(gb, "ADD SP, %s$%02x\n", temp < 0? "-" : "", temp < 0? -temp : temp);
|
||||
}
|
||||
|
||||
static void jp_hl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "JP hl\n");
|
||||
}
|
||||
|
||||
static void ld_da16_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8);
|
||||
const char *symbol = GB_debugger_name_for_address(gb, addr);
|
||||
if (symbol) {
|
||||
GB_log(gb, "LD [%s], a ; =$%04x\n", symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "LD [$%04x], a\n", addr);
|
||||
}
|
||||
(*pc) += 2;
|
||||
}
|
||||
|
||||
static void ld_a_da16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8);
|
||||
const char *symbol = GB_debugger_name_for_address(gb, addr);
|
||||
if (symbol) {
|
||||
GB_log(gb, "LD a, [%s] ; =$%04x\n", symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "LD a, [$%04x]\n", addr);
|
||||
}
|
||||
(*pc) += 2;
|
||||
}
|
||||
|
||||
static void di(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "DI\n");
|
||||
}
|
||||
|
||||
static void ei(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "EI\n");
|
||||
}
|
||||
|
||||
static void ld_hl_sp_r8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
int8_t temp = GB_read_memory(gb, (*pc)++);
|
||||
GB_log(gb, "LD hl, sp, %s$%02x\n", temp < 0? "-" : "", temp < 0? -temp : temp);
|
||||
}
|
||||
|
||||
static void ld_sp_hl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "LD sp, hl\n");
|
||||
}
|
||||
|
||||
static void rlc_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "RLC %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void rrc_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "RRC %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void rl_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "RL %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void rr_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "RR %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void sla_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "SLA %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void sra_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "SRA %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void srl_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "SRL %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void swap_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "SWAP %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void bit_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t bit;
|
||||
(*pc)++;
|
||||
bit = ((opcode >> 3) & 7);
|
||||
if ((opcode & 0xC0) == 0x40) { /* Bit */
|
||||
GB_log(gb, "BIT %s, %d\n", get_src_name(opcode), bit);
|
||||
}
|
||||
else if ((opcode & 0xC0) == 0x80) { /* res */
|
||||
GB_log(gb, "RES %s, %d\n", get_src_name(opcode), bit);
|
||||
}
|
||||
else if ((opcode & 0xC0) == 0xC0) { /* set */
|
||||
GB_log(gb, "SET %s, %d\n", get_src_name(opcode), bit);
|
||||
}
|
||||
}
|
||||
|
||||
static void cb_prefix(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
opcode = GB_read_memory(gb, ++*pc);
|
||||
switch (opcode >> 3) {
|
||||
case 0:
|
||||
rlc_r(gb, opcode, pc);
|
||||
break;
|
||||
case 1:
|
||||
rrc_r(gb, opcode, pc);
|
||||
break;
|
||||
case 2:
|
||||
rl_r(gb, opcode, pc);
|
||||
break;
|
||||
case 3:
|
||||
rr_r(gb, opcode, pc);
|
||||
break;
|
||||
case 4:
|
||||
sla_r(gb, opcode, pc);
|
||||
break;
|
||||
case 5:
|
||||
sra_r(gb, opcode, pc);
|
||||
break;
|
||||
case 6:
|
||||
swap_r(gb, opcode, pc);
|
||||
break;
|
||||
case 7:
|
||||
srl_r(gb, opcode, pc);
|
||||
break;
|
||||
default:
|
||||
bit_r(gb, opcode, pc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GB_opcode_t *opcodes[256] = {
|
||||
/* X0 X1 X2 X3 X4 X5 X6 X7 */
|
||||
/* X8 X9 Xa Xb Xc Xd Xe Xf */
|
||||
nop, ld_rr_d16, ld_drr_a, inc_rr, inc_hr, dec_hr, ld_hr_d8, rlca, /* 0X */
|
||||
ld_da16_sp, add_hl_rr, ld_a_drr, dec_rr, inc_lr, dec_lr, ld_lr_d8, rrca,
|
||||
stop, ld_rr_d16, ld_drr_a, inc_rr, inc_hr, dec_hr, ld_hr_d8, rla, /* 1X */
|
||||
jr_r8, add_hl_rr, ld_a_drr, dec_rr, inc_lr, dec_lr, ld_lr_d8, rra,
|
||||
jr_cc_r8, ld_rr_d16, ld_dhli_a, inc_rr, inc_hr, dec_hr, ld_hr_d8, daa, /* 2X */
|
||||
jr_cc_r8, add_hl_rr, ld_a_dhli, dec_rr, inc_lr, dec_lr, ld_lr_d8, cpl,
|
||||
jr_cc_r8, ld_rr_d16, ld_dhld_a, inc_rr, inc_dhl, dec_dhl, ld_dhl_d8, scf, /* 3X */
|
||||
jr_cc_r8, add_hl_rr, ld_a_dhld, dec_rr, inc_hr, dec_hr, ld_hr_d8, ccf,
|
||||
ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, /* 4X */
|
||||
ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r,
|
||||
ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, /* 5X */
|
||||
ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r,
|
||||
ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, /* 6X */
|
||||
ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r,
|
||||
ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, halt, ld_r_r, /* 7X */
|
||||
ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r,
|
||||
add_a_r, add_a_r, add_a_r, add_a_r, add_a_r, add_a_r, add_a_r, add_a_r, /* 8X */
|
||||
adc_a_r, adc_a_r, adc_a_r, adc_a_r, adc_a_r, adc_a_r, adc_a_r, adc_a_r,
|
||||
sub_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, /* 9X */
|
||||
sbc_a_r, sbc_a_r, sbc_a_r, sbc_a_r, sbc_a_r, sbc_a_r, sbc_a_r, sbc_a_r,
|
||||
and_a_r, and_a_r, and_a_r, and_a_r, and_a_r, and_a_r, and_a_r, and_a_r, /* aX */
|
||||
xor_a_r, xor_a_r, xor_a_r, xor_a_r, xor_a_r, xor_a_r, xor_a_r, xor_a_r,
|
||||
or_a_r, or_a_r, or_a_r, or_a_r, or_a_r, or_a_r, or_a_r, or_a_r, /* bX */
|
||||
cp_a_r, cp_a_r, cp_a_r, cp_a_r, cp_a_r, cp_a_r, cp_a_r, cp_a_r,
|
||||
ret_cc, pop_rr, jp_cc_a16, jp_a16, call_cc_a16,push_rr, add_a_d8, rst, /* cX */
|
||||
ret_cc, ret, jp_cc_a16, cb_prefix, call_cc_a16,call_a16, adc_a_d8, rst,
|
||||
ret_cc, pop_rr, jp_cc_a16, ill, call_cc_a16,push_rr, sub_a_d8, rst, /* dX */
|
||||
ret_cc, reti, jp_cc_a16, ill, call_cc_a16,ill, sbc_a_d8, rst,
|
||||
ld_da8_a, pop_rr, ld_dc_a, ill, ill, push_rr, and_a_d8, rst, /* eX */
|
||||
add_sp_r8, jp_hl, ld_da16_a, ill, ill, ill, xor_a_d8, rst,
|
||||
ld_a_da8, pop_rr, ld_a_dc, di, ill, push_rr, or_a_d8, rst, /* fX */
|
||||
ld_hl_sp_r8,ld_sp_hl, ld_a_da16, ei, ill, ill, cp_a_d8, rst,
|
||||
};
|
||||
|
||||
|
||||
|
||||
void GB_cpu_disassemble(GB_gameboy_t *gb, uint16_t pc, uint16_t count)
|
||||
{
|
||||
const GB_bank_symbol_t *function_symbol = GB_debugger_find_symbol(gb, pc);
|
||||
|
||||
if (function_symbol && pc - function_symbol->addr > 0x1000) {
|
||||
function_symbol = NULL;
|
||||
}
|
||||
|
||||
if (function_symbol && pc != function_symbol->addr) {
|
||||
GB_log(gb, "%s:\n", function_symbol->name);
|
||||
}
|
||||
|
||||
uint16_t current_function = function_symbol? function_symbol->addr : 0;
|
||||
|
||||
while (count--) {
|
||||
function_symbol = GB_debugger_find_symbol(gb, pc);
|
||||
if (function_symbol && function_symbol->addr == pc) {
|
||||
if (current_function != function_symbol->addr) {
|
||||
GB_log(gb, "\n");
|
||||
}
|
||||
GB_log(gb, "%s:\n", function_symbol->name);
|
||||
}
|
||||
if (function_symbol) {
|
||||
GB_log(gb, "%s%04x <+%03x>: ", pc == gb->pc? " ->": " ", pc, pc - function_symbol->addr);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "%s%04x: ", pc == gb->pc? " ->": " ", pc);
|
||||
}
|
||||
uint8_t opcode = GB_read_memory(gb, pc);
|
||||
opcodes[opcode](gb, opcode, &pc);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
#include "gb.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
static size_t GB_map_find_symbol_index(GB_symbol_map_t *map, uint16_t addr)
|
||||
{
|
||||
if (!map->symbols) {
|
||||
return 0;
|
||||
}
|
||||
ssize_t min = 0;
|
||||
ssize_t max = map->n_symbols;
|
||||
while (min < max) {
|
||||
size_t pivot = (min + max) / 2;
|
||||
if (map->symbols[pivot].addr == addr) return pivot;
|
||||
if (map->symbols[pivot].addr > addr) {
|
||||
max = pivot;
|
||||
}
|
||||
else {
|
||||
min = pivot + 1;
|
||||
}
|
||||
}
|
||||
return (size_t) min;
|
||||
}
|
||||
|
||||
GB_bank_symbol_t *GB_map_add_symbol(GB_symbol_map_t *map, uint16_t addr, const char *name)
|
||||
{
|
||||
size_t index = GB_map_find_symbol_index(map, addr);
|
||||
|
||||
map->symbols = realloc(map->symbols, (map->n_symbols + 1) * sizeof(map->symbols[0]));
|
||||
memmove(&map->symbols[index + 1], &map->symbols[index], (map->n_symbols - index) * sizeof(map->symbols[0]));
|
||||
map->symbols[index].addr = addr;
|
||||
map->symbols[index].name = strdup(name);
|
||||
map->n_symbols++;
|
||||
return &map->symbols[index];
|
||||
}
|
||||
|
||||
const GB_bank_symbol_t *GB_map_find_symbol(GB_symbol_map_t *map, uint16_t addr)
|
||||
{
|
||||
if (!map) return NULL;
|
||||
size_t index = GB_map_find_symbol_index(map, addr);
|
||||
if (index < map->n_symbols && map->symbols[index].addr != addr) {
|
||||
index--;
|
||||
}
|
||||
if (index < map->n_symbols) {
|
||||
return &map->symbols[index];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GB_symbol_map_t *GB_map_alloc(void)
|
||||
{
|
||||
GB_symbol_map_t *map = malloc(sizeof(*map));
|
||||
memset(map, 0, sizeof(*map));
|
||||
return map;
|
||||
}
|
||||
|
||||
void GB_map_free(GB_symbol_map_t *map)
|
||||
{
|
||||
for (unsigned i = 0; i < map->n_symbols; i++) {
|
||||
free(map->symbols[i].name);
|
||||
}
|
||||
|
||||
if (map->symbols) {
|
||||
free(map->symbols);
|
||||
}
|
||||
|
||||
free(map);
|
||||
}
|
||||
|
||||
static unsigned hash_name(const char *name)
|
||||
{
|
||||
unsigned r = 0;
|
||||
while (*name) {
|
||||
r <<= 1;
|
||||
if (r & 0x400) {
|
||||
r ^= 0x401;
|
||||
}
|
||||
r += (unsigned char)*(name++);
|
||||
}
|
||||
|
||||
return r & 0x3FF;
|
||||
}
|
||||
|
||||
void GB_reversed_map_add_symbol(GB_reversed_symbol_map_t *map, uint16_t bank, GB_bank_symbol_t *bank_symbol)
|
||||
{
|
||||
unsigned hash = hash_name(bank_symbol->name);
|
||||
GB_symbol_t *symbol = malloc(sizeof(*symbol));
|
||||
symbol->name = bank_symbol->name;
|
||||
symbol->addr = bank_symbol->addr;
|
||||
symbol->bank = bank;
|
||||
symbol->next = map->buckets[hash];
|
||||
map->buckets[hash] = symbol;
|
||||
}
|
||||
|
||||
const GB_symbol_t *GB_reversed_map_find_symbol(GB_reversed_symbol_map_t *map, const char *name)
|
||||
{
|
||||
unsigned hash = hash_name(name);
|
||||
GB_symbol_t *symbol = map->buckets[hash];
|
||||
|
||||
while (symbol) {
|
||||
if (strcmp(symbol->name, name) == 0) return symbol;
|
||||
symbol = symbol->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
#ifndef symbol_hash_h
|
||||
#define symbol_hash_h
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
uint16_t addr;
|
||||
} GB_bank_symbol_t;
|
||||
|
||||
typedef struct GB_symbol_s {
|
||||
struct GB_symbol_s *next;
|
||||
const char *name;
|
||||
uint16_t bank;
|
||||
uint16_t addr;
|
||||
} GB_symbol_t;
|
||||
|
||||
typedef struct {
|
||||
GB_bank_symbol_t *symbols;
|
||||
size_t n_symbols;
|
||||
} GB_symbol_map_t;
|
||||
|
||||
typedef struct {
|
||||
GB_symbol_t *buckets[0x400];
|
||||
} GB_reversed_symbol_map_t;
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
void GB_reversed_map_add_symbol(GB_reversed_symbol_map_t *map, uint16_t bank, GB_bank_symbol_t *symbol);
|
||||
const GB_symbol_t *GB_reversed_map_find_symbol(GB_reversed_symbol_map_t *map, const char *name);
|
||||
GB_bank_symbol_t *GB_map_add_symbol(GB_symbol_map_t *map, uint16_t addr, const char *name);
|
||||
const GB_bank_symbol_t *GB_map_find_symbol(GB_symbol_map_t *map, uint16_t addr);
|
||||
GB_symbol_map_t *GB_map_alloc(void);
|
||||
void GB_map_free(GB_symbol_map_t *map);
|
||||
#endif
|
||||
|
||||
#endif /* symbol_hash_h */
|
|
@ -0,0 +1,327 @@
|
|||
#include "gb.h"
|
||||
#ifdef _WIN32
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0500
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
static const unsigned GB_TAC_TRIGGER_BITS[] = {512, 8, 32, 128};
|
||||
|
||||
#ifndef GB_DISABLE_TIMEKEEPING
|
||||
static int64_t get_nanoseconds(void)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
return (now.tv_usec) * 1000 + now.tv_sec * 1000000000L;
|
||||
#else
|
||||
FILETIME time;
|
||||
GetSystemTimeAsFileTime(&time);
|
||||
return (((int64_t)time.dwHighDateTime << 32) | time.dwLowDateTime) * 100L;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void nsleep(uint64_t nanoseconds)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
struct timespec sleep = {0, nanoseconds};
|
||||
nanosleep(&sleep, NULL);
|
||||
#else
|
||||
HANDLE timer;
|
||||
LARGE_INTEGER time;
|
||||
timer = CreateWaitableTimer(NULL, true, NULL);
|
||||
time.QuadPart = -(nanoseconds / 100L);
|
||||
SetWaitableTimer(timer, &time, 0, NULL, NULL, false);
|
||||
WaitForSingleObject(timer, INFINITE);
|
||||
CloseHandle(timer);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool GB_timing_sync_turbo(GB_gameboy_t *gb)
|
||||
{
|
||||
if (!gb->turbo_dont_skip) {
|
||||
int64_t nanoseconds = get_nanoseconds();
|
||||
if (nanoseconds <= gb->last_sync + (1000000000LL * LCDC_PERIOD / GB_get_clock_rate(gb))) {
|
||||
return true;
|
||||
}
|
||||
gb->last_sync = nanoseconds;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GB_timing_sync(GB_gameboy_t *gb)
|
||||
{
|
||||
if (gb->turbo) {
|
||||
gb->cycles_since_last_sync = 0;
|
||||
return;
|
||||
}
|
||||
/* Prevent syncing if not enough time has passed.*/
|
||||
if (gb->cycles_since_last_sync < LCDC_PERIOD / 3) return;
|
||||
|
||||
uint64_t target_nanoseconds = gb->cycles_since_last_sync * 1000000000LL / 2 / GB_get_clock_rate(gb); /* / 2 because we use 8MHz units */
|
||||
int64_t nanoseconds = get_nanoseconds();
|
||||
int64_t time_to_sleep = target_nanoseconds + gb->last_sync - nanoseconds;
|
||||
if (time_to_sleep > 0 && time_to_sleep < LCDC_PERIOD * 1000000000LL / GB_get_clock_rate(gb)) {
|
||||
nsleep(time_to_sleep);
|
||||
gb->last_sync += target_nanoseconds;
|
||||
}
|
||||
else {
|
||||
gb->last_sync = nanoseconds;
|
||||
}
|
||||
|
||||
gb->cycles_since_last_sync = 0;
|
||||
if (gb->update_input_hint_callback) {
|
||||
gb->update_input_hint_callback(gb);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
bool GB_timing_sync_turbo(GB_gameboy_t *gb)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void GB_timing_sync(GB_gameboy_t *gb)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
static void GB_ir_run(GB_gameboy_t *gb)
|
||||
{
|
||||
if (gb->ir_queue_length == 0) return;
|
||||
if (gb->cycles_since_input_ir_change >= gb->ir_queue[0].delay) {
|
||||
gb->cycles_since_input_ir_change -= gb->ir_queue[0].delay;
|
||||
gb->infrared_input = gb->ir_queue[0].state;
|
||||
gb->ir_queue_length--;
|
||||
memmove(&gb->ir_queue[0], &gb->ir_queue[1], sizeof(gb->ir_queue[0]) * (gb->ir_queue_length));
|
||||
}
|
||||
}
|
||||
|
||||
static void advance_tima_state_machine(GB_gameboy_t *gb)
|
||||
{
|
||||
if (gb->tima_reload_state == GB_TIMA_RELOADED) {
|
||||
gb->tima_reload_state = GB_TIMA_RUNNING;
|
||||
}
|
||||
else if (gb->tima_reload_state == GB_TIMA_RELOADING) {
|
||||
gb->io_registers[GB_IO_IF] |= 4;
|
||||
gb->tima_reload_state = GB_TIMA_RELOADED;
|
||||
}
|
||||
}
|
||||
|
||||
static void increase_tima(GB_gameboy_t *gb)
|
||||
{
|
||||
gb->io_registers[GB_IO_TIMA]++;
|
||||
if (gb->io_registers[GB_IO_TIMA] == 0) {
|
||||
gb->io_registers[GB_IO_TIMA] = gb->io_registers[GB_IO_TMA];
|
||||
gb->tima_reload_state = GB_TIMA_RELOADING;
|
||||
}
|
||||
}
|
||||
|
||||
static void GB_set_internal_div_counter(GB_gameboy_t *gb, uint32_t value)
|
||||
{
|
||||
/* TIMA increases when a specific high-bit becomes a low-bit. */
|
||||
value &= INTERNAL_DIV_CYCLES - 1;
|
||||
uint32_t triggers = gb->div_counter & ~value;
|
||||
if ((gb->io_registers[GB_IO_TAC] & 4) && (triggers & GB_TAC_TRIGGER_BITS[gb->io_registers[GB_IO_TAC] & 3])) {
|
||||
increase_tima(gb);
|
||||
}
|
||||
|
||||
/* TODO: Can switching to double speed mode trigger an event? */
|
||||
if (triggers & (gb->cgb_double_speed? 0x2000 : 0x1000)) {
|
||||
GB_apu_run(gb);
|
||||
GB_apu_div_event(gb);
|
||||
}
|
||||
gb->div_counter = value;
|
||||
}
|
||||
|
||||
static void GB_timers_run(GB_gameboy_t *gb, uint8_t cycles)
|
||||
{
|
||||
if (gb->stopped) {
|
||||
gb->apu.apu_cycles += 4 << !gb->cgb_double_speed;
|
||||
return;
|
||||
}
|
||||
|
||||
GB_STATE_MACHINE(gb, div, cycles, 1) {
|
||||
GB_STATE(gb, div, 1);
|
||||
GB_STATE(gb, div, 2);
|
||||
GB_STATE(gb, div, 3);
|
||||
}
|
||||
|
||||
GB_set_internal_div_counter(gb, 0);
|
||||
main:
|
||||
GB_SLEEP(gb, div, 1, 3);
|
||||
while (true) {
|
||||
advance_tima_state_machine(gb);
|
||||
GB_set_internal_div_counter(gb, gb->div_counter + 4);
|
||||
gb->apu.apu_cycles += 4 << !gb->cgb_double_speed;
|
||||
GB_SLEEP(gb, div, 2, 4);
|
||||
}
|
||||
|
||||
/* Todo: This is ugly to allow compatibility with 0.11 save states. Fix me when breaking save compatibility */
|
||||
{
|
||||
div3:
|
||||
/* Compensate for lack of prefetch emulation, as well as DIV's internal initial value */
|
||||
GB_set_internal_div_counter(gb, 8);
|
||||
goto main;
|
||||
}
|
||||
}
|
||||
|
||||
static void advance_serial(GB_gameboy_t *gb, uint8_t cycles)
|
||||
{
|
||||
if (gb->serial_length == 0) {
|
||||
gb->serial_cycles += cycles;
|
||||
return;
|
||||
}
|
||||
|
||||
while (cycles > gb->serial_length) {
|
||||
advance_serial(gb, gb->serial_length);
|
||||
cycles -= gb->serial_length;
|
||||
}
|
||||
|
||||
uint16_t previous_serial_cycles = gb->serial_cycles;
|
||||
gb->serial_cycles += cycles;
|
||||
if ((gb->serial_cycles & gb->serial_length) != (previous_serial_cycles & gb->serial_length)) {
|
||||
gb->serial_count++;
|
||||
if (gb->serial_count == 8) {
|
||||
gb->serial_length = 0;
|
||||
gb->serial_count = 0;
|
||||
gb->io_registers[GB_IO_SC] &= ~0x80;
|
||||
gb->io_registers[GB_IO_IF] |= 8;
|
||||
}
|
||||
|
||||
gb->io_registers[GB_IO_SB] <<= 1;
|
||||
|
||||
if (gb->serial_transfer_bit_end_callback) {
|
||||
gb->io_registers[GB_IO_SB] |= gb->serial_transfer_bit_end_callback(gb);
|
||||
}
|
||||
else {
|
||||
gb->io_registers[GB_IO_SB] |= 1;
|
||||
}
|
||||
|
||||
if (gb->serial_length) {
|
||||
/* Still more bits to send */
|
||||
if (gb->serial_transfer_bit_start_callback) {
|
||||
gb->serial_transfer_bit_start_callback(gb, gb->io_registers[GB_IO_SB] & 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles)
|
||||
{
|
||||
gb->apu.pcm_mask[0] = gb->apu.pcm_mask[1] = 0xFF; // Sort of hacky, but too many cross-component interactions to do it right
|
||||
// Affected by speed boost
|
||||
gb->dma_cycles += cycles;
|
||||
|
||||
GB_timers_run(gb, cycles);
|
||||
if (!gb->stopped) {
|
||||
advance_serial(gb, cycles); // TODO: Verify what happens in STOP mode
|
||||
}
|
||||
|
||||
gb->debugger_ticks += cycles;
|
||||
|
||||
if (!gb->cgb_double_speed) {
|
||||
cycles <<= 1;
|
||||
}
|
||||
|
||||
// Not affected by speed boost
|
||||
gb->double_speed_alignment += cycles;
|
||||
gb->hdma_cycles += cycles;
|
||||
gb->apu_output.sample_cycles += cycles;
|
||||
gb->cycles_since_ir_change += cycles;
|
||||
gb->cycles_since_input_ir_change += cycles;
|
||||
gb->cycles_since_last_sync += cycles;
|
||||
gb->cycles_since_run += cycles;
|
||||
|
||||
if (gb->rumble_state) {
|
||||
gb->rumble_on_cycles++;
|
||||
}
|
||||
else {
|
||||
gb->rumble_off_cycles++;
|
||||
}
|
||||
|
||||
if (!gb->stopped) { // TODO: Verify what happens in STOP mode
|
||||
GB_dma_run(gb);
|
||||
GB_hdma_run(gb);
|
||||
}
|
||||
GB_apu_run(gb);
|
||||
GB_display_run(gb, cycles);
|
||||
GB_ir_run(gb);
|
||||
}
|
||||
|
||||
/*
|
||||
This glitch is based on the expected results of mooneye-gb rapid_toggle test.
|
||||
This glitch happens because how TIMA is increased, see GB_set_internal_div_counter.
|
||||
According to GiiBiiAdvance, GBC's behavior is different, but this was not tested or implemented.
|
||||
*/
|
||||
void GB_emulate_timer_glitch(GB_gameboy_t *gb, uint8_t old_tac, uint8_t new_tac)
|
||||
{
|
||||
/* Glitch only happens when old_tac is enabled. */
|
||||
if (!(old_tac & 4)) return;
|
||||
|
||||
unsigned old_clocks = GB_TAC_TRIGGER_BITS[old_tac & 3];
|
||||
unsigned new_clocks = GB_TAC_TRIGGER_BITS[new_tac & 3];
|
||||
|
||||
/* The bit used for overflow testing must have been 1 */
|
||||
if (gb->div_counter & old_clocks) {
|
||||
/* And now either the timer must be disabled, or the new bit used for overflow testing be 0. */
|
||||
if (!(new_tac & 4) || gb->div_counter & new_clocks) {
|
||||
increase_tima(gb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GB_rtc_run(GB_gameboy_t *gb)
|
||||
{
|
||||
if (gb->cartridge_type->mbc_type == GB_HUC3) {
|
||||
time_t current_time = time(NULL);
|
||||
while (gb->last_rtc_second / 60 < current_time / 60) {
|
||||
gb->last_rtc_second += 60;
|
||||
gb->huc3_minutes++;
|
||||
if (gb->huc3_minutes == 60 * 24) {
|
||||
gb->huc3_days++;
|
||||
gb->huc3_minutes = 0;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ((gb->rtc_real.high & 0x40) == 0) { /* is timer running? */
|
||||
time_t current_time = time(NULL);
|
||||
|
||||
while (gb->last_rtc_second + 60 * 60 * 24 < current_time) {
|
||||
gb->last_rtc_second += 60 * 60 * 24;
|
||||
if (++gb->rtc_real.days == 0) {
|
||||
if (gb->rtc_real.high & 1) { /* Bit 8 of days*/
|
||||
gb->rtc_real.high |= 0x80; /* Overflow bit */
|
||||
}
|
||||
gb->rtc_real.high ^= 1;
|
||||
}
|
||||
}
|
||||
|
||||
while (gb->last_rtc_second < current_time) {
|
||||
gb->last_rtc_second++;
|
||||
if (++gb->rtc_real.seconds == 60) {
|
||||
gb->rtc_real.seconds = 0;
|
||||
if (++gb->rtc_real.minutes == 60) {
|
||||
gb->rtc_real.minutes = 0;
|
||||
if (++gb->rtc_real.hours == 24) {
|
||||
gb->rtc_real.hours = 0;
|
||||
if (++gb->rtc_real.days == 0) {
|
||||
if (gb->rtc_real.high & 1) { /* Bit 8 of days*/
|
||||
gb->rtc_real.high |= 0x80; /* Overflow bit */
|
||||
}
|
||||
gb->rtc_real.high ^= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef timing_h
|
||||
#define timing_h
|
||||
#include "gb_struct_def.h"
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles);
|
||||
void GB_rtc_run(GB_gameboy_t *gb);
|
||||
void GB_emulate_timer_glitch(GB_gameboy_t *gb, uint8_t old_tac, uint8_t new_tac);
|
||||
bool GB_timing_sync_turbo(GB_gameboy_t *gb); /* Returns true if should skip frame */
|
||||
void GB_timing_sync(GB_gameboy_t *gb);
|
||||
|
||||
enum {
|
||||
GB_TIMA_RUNNING = 0,
|
||||
GB_TIMA_RELOADING = 1,
|
||||
GB_TIMA_RELOADED = 2
|
||||
};
|
||||
|
||||
|
||||
#define GB_SLEEP(gb, unit, state, cycles) do {\
|
||||
(gb)->unit##_cycles -= (cycles) * __state_machine_divisor; \
|
||||
if ((gb)->unit##_cycles <= 0) {\
|
||||
(gb)->unit##_state = state;\
|
||||
return;\
|
||||
unit##state:; \
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
#define GB_STATE_MACHINE(gb, unit, cycles, divisor) \
|
||||
static const int __state_machine_divisor = divisor;\
|
||||
(gb)->unit##_cycles += cycles; \
|
||||
if ((gb)->unit##_cycles <= 0) {\
|
||||
return;\
|
||||
}\
|
||||
switch ((gb)->unit##_state)
|
||||
#endif
|
||||
|
||||
#define GB_STATE(gb, unit, state) case state: goto unit##state
|
||||
|
||||
#define GB_UNIT(unit) int32_t unit##_cycles, unit##_state
|
||||
|
||||
#endif /* timing_h */
|
|
@ -0,0 +1,169 @@
|
|||
#include "gb.h"
|
||||
#include <time.h>
|
||||
|
||||
static inline uint8_t int_to_bcd(uint8_t i)
|
||||
{
|
||||
return (i % 10) + ((i / 10) << 4);
|
||||
}
|
||||
|
||||
static inline uint8_t bcd_to_int(uint8_t i)
|
||||
{
|
||||
return (i & 0xF) + (i >> 4) * 10;
|
||||
}
|
||||
|
||||
/*
|
||||
Note: This peripheral was never released. This is a hacky software reimplementation of it that allows
|
||||
reaccessing all of the features present in Workboy's ROM. Some of the implementation details are
|
||||
obviously wrong, but without access to the actual hardware, this is the best I can do.
|
||||
*/
|
||||
|
||||
static void serial_start(GB_gameboy_t *gb, bool bit_received)
|
||||
{
|
||||
gb->workboy.byte_being_received <<= 1;
|
||||
gb->workboy.byte_being_received |= bit_received;
|
||||
gb->workboy.bits_received++;
|
||||
if (gb->workboy.bits_received == 8) {
|
||||
gb->workboy.byte_to_send = 0;
|
||||
if (gb->workboy.mode != 'W' && gb->workboy.byte_being_received == 'R') {
|
||||
gb->workboy.byte_to_send = 'D';
|
||||
gb->workboy.key = GB_WORKBOY_NONE;
|
||||
gb->workboy.mode = gb->workboy.byte_being_received;
|
||||
gb->workboy.buffer_index = 1;
|
||||
|
||||
time_t time = gb->workboy_get_time_callback(gb);
|
||||
struct tm tm;
|
||||
tm = *localtime(&time);
|
||||
memset(gb->workboy.buffer, 0, sizeof(gb->workboy.buffer));
|
||||
|
||||
gb->workboy.buffer[0] = 4; // Unknown, unused, but appears to be expected to be 4
|
||||
gb->workboy.buffer[2] = int_to_bcd(tm.tm_sec); // Seconds, BCD
|
||||
gb->workboy.buffer[3] = int_to_bcd(tm.tm_min); // Minutes, BCD
|
||||
gb->workboy.buffer[4] = int_to_bcd(tm.tm_hour); // Hours, BCD
|
||||
gb->workboy.buffer[5] = int_to_bcd(tm.tm_mday); // Days, BCD. Upper most 2 bits are added to Year for some reason
|
||||
gb->workboy.buffer[6] = int_to_bcd(tm.tm_mon + 1); // Months, BCD
|
||||
gb->workboy.buffer[0xF] = tm.tm_year; // Years, plain number, since 1900
|
||||
|
||||
}
|
||||
else if (gb->workboy.mode != 'W' && gb->workboy.byte_being_received == 'W') {
|
||||
gb->workboy.byte_to_send = 'D'; // It is actually unknown what this value should be
|
||||
gb->workboy.key = GB_WORKBOY_NONE;
|
||||
gb->workboy.mode = gb->workboy.byte_being_received;
|
||||
gb->workboy.buffer_index = 0;
|
||||
}
|
||||
else if (gb->workboy.mode != 'W' && (gb->workboy.byte_being_received == 'O' || gb->workboy.mode == 'O')) {
|
||||
gb->workboy.mode = 'O';
|
||||
gb->workboy.byte_to_send = gb->workboy.key;
|
||||
if (gb->workboy.key != GB_WORKBOY_NONE) {
|
||||
if (gb->workboy.key & GB_WORKBOY_REQUIRE_SHIFT) {
|
||||
gb->workboy.key &= ~GB_WORKBOY_REQUIRE_SHIFT;
|
||||
if (gb->workboy.shift_down) {
|
||||
gb->workboy.byte_to_send = gb->workboy.key;
|
||||
gb->workboy.key = GB_WORKBOY_NONE;
|
||||
}
|
||||
else {
|
||||
gb->workboy.byte_to_send = GB_WORKBOY_SHIFT_DOWN;
|
||||
gb->workboy.shift_down = true;
|
||||
}
|
||||
}
|
||||
else if (gb->workboy.key & GB_WORKBOY_FORBID_SHIFT) {
|
||||
gb->workboy.key &= ~GB_WORKBOY_FORBID_SHIFT;
|
||||
if (!gb->workboy.shift_down) {
|
||||
gb->workboy.byte_to_send = gb->workboy.key;
|
||||
gb->workboy.key = GB_WORKBOY_NONE;
|
||||
}
|
||||
else {
|
||||
gb->workboy.byte_to_send = GB_WORKBOY_SHIFT_UP;
|
||||
gb->workboy.shift_down = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (gb->workboy.key == GB_WORKBOY_SHIFT_DOWN) {
|
||||
gb->workboy.shift_down = true;
|
||||
gb->workboy.user_shift_down = true;
|
||||
}
|
||||
else if (gb->workboy.key == GB_WORKBOY_SHIFT_UP) {
|
||||
gb->workboy.shift_down = false;
|
||||
gb->workboy.user_shift_down = false;
|
||||
}
|
||||
gb->workboy.byte_to_send = gb->workboy.key;
|
||||
gb->workboy.key = GB_WORKBOY_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (gb->workboy.mode == 'R') {
|
||||
if (gb->workboy.buffer_index / 2 >= sizeof(gb->workboy.buffer)) {
|
||||
gb->workboy.byte_to_send = 0;
|
||||
}
|
||||
else {
|
||||
if (gb->workboy.buffer_index & 1) {
|
||||
gb->workboy.byte_to_send = "0123456789ABCDEF"[gb->workboy.buffer[gb->workboy.buffer_index / 2] & 0xF];
|
||||
}
|
||||
else {
|
||||
gb->workboy.byte_to_send = "0123456789ABCDEF"[gb->workboy.buffer[gb->workboy.buffer_index / 2] >> 4];
|
||||
}
|
||||
gb->workboy.buffer_index++;
|
||||
}
|
||||
}
|
||||
else if (gb->workboy.mode == 'W') {
|
||||
gb->workboy.byte_to_send = 'D';
|
||||
if (gb->workboy.buffer_index < 2) {
|
||||
gb->workboy.buffer_index++;
|
||||
}
|
||||
else if ((gb->workboy.buffer_index - 2) < sizeof(gb->workboy.buffer)) {
|
||||
gb->workboy.buffer[gb->workboy.buffer_index - 2] = gb->workboy.byte_being_received;
|
||||
gb->workboy.buffer_index++;
|
||||
if (gb->workboy.buffer_index - 2 == sizeof(gb->workboy.buffer)) {
|
||||
struct tm tm = {0,};
|
||||
tm.tm_sec = bcd_to_int(gb->workboy.buffer[7]);
|
||||
tm.tm_min = bcd_to_int(gb->workboy.buffer[8]);
|
||||
tm.tm_hour = bcd_to_int(gb->workboy.buffer[9]);
|
||||
tm.tm_mday = bcd_to_int(gb->workboy.buffer[0xA]);
|
||||
tm.tm_mon = bcd_to_int(gb->workboy.buffer[0xB] & 0x3F) - 1;
|
||||
tm.tm_year = (uint8_t)(gb->workboy.buffer[0x14] + (gb->workboy.buffer[0xA] >> 6)); // What were they thinking?
|
||||
gb->workboy_set_time_callback(gb, mktime(&tm));
|
||||
gb->workboy.mode = 'O';
|
||||
}
|
||||
}
|
||||
}
|
||||
gb->workboy.bits_received = 0;
|
||||
gb->workboy.byte_being_received = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool serial_end(GB_gameboy_t *gb)
|
||||
{
|
||||
bool ret = gb->workboy.bit_to_send;
|
||||
gb->workboy.bit_to_send = gb->workboy.byte_to_send & 0x80;
|
||||
gb->workboy.byte_to_send <<= 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GB_connect_workboy(GB_gameboy_t *gb,
|
||||
GB_workboy_set_time_callback set_time_callback,
|
||||
GB_workboy_get_time_callback get_time_callback)
|
||||
{
|
||||
memset(&gb->workboy, 0, sizeof(gb->workboy));
|
||||
GB_set_serial_transfer_bit_start_callback(gb, serial_start);
|
||||
GB_set_serial_transfer_bit_end_callback(gb, serial_end);
|
||||
gb->workboy_set_time_callback = set_time_callback;
|
||||
gb->workboy_get_time_callback = get_time_callback;
|
||||
}
|
||||
|
||||
bool GB_workboy_is_enabled(GB_gameboy_t *gb)
|
||||
{
|
||||
return gb->workboy.mode;
|
||||
}
|
||||
|
||||
void GB_workboy_set_key(GB_gameboy_t *gb, uint8_t key)
|
||||
{
|
||||
if (gb->workboy.user_shift_down != gb->workboy.shift_down &&
|
||||
(key & (GB_WORKBOY_REQUIRE_SHIFT | GB_WORKBOY_FORBID_SHIFT)) == 0) {
|
||||
if (gb->workboy.user_shift_down) {
|
||||
key |= GB_WORKBOY_REQUIRE_SHIFT;
|
||||
}
|
||||
else {
|
||||
key |= GB_WORKBOY_FORBID_SHIFT;
|
||||
}
|
||||
}
|
||||
gb->workboy.key = key;
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
#ifndef workboy_h
|
||||
#define workboy_h
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
#include "gb_struct_def.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t byte_to_send;
|
||||
bool bit_to_send;
|
||||
uint8_t byte_being_received;
|
||||
uint8_t bits_received;
|
||||
uint8_t mode;
|
||||
uint8_t key;
|
||||
bool shift_down;
|
||||
bool user_shift_down;
|
||||
uint8_t buffer[0x15];
|
||||
uint8_t buffer_index; // In nibbles during read, in bytes during write
|
||||
} GB_workboy_t;
|
||||
|
||||
typedef void (*GB_workboy_set_time_callback)(GB_gameboy_t *gb, time_t time);
|
||||
typedef time_t (*GB_workboy_get_time_callback)(GB_gameboy_t *gb);
|
||||
|
||||
enum {
|
||||
GB_WORKBOY_NONE = 0xFF,
|
||||
GB_WORKBOY_REQUIRE_SHIFT = 0x40,
|
||||
GB_WORKBOY_FORBID_SHIFT = 0x80,
|
||||
|
||||
GB_WORKBOY_CLOCK = 1,
|
||||
GB_WORKBOY_TEMPERATURE = 2,
|
||||
GB_WORKBOY_MONEY = 3,
|
||||
GB_WORKBOY_CALCULATOR = 4,
|
||||
GB_WORKBOY_DATE = 5,
|
||||
GB_WORKBOY_CONVERSION = 6,
|
||||
GB_WORKBOY_RECORD = 7,
|
||||
GB_WORKBOY_WORLD = 8,
|
||||
GB_WORKBOY_PHONE = 9,
|
||||
GB_WORKBOY_ESCAPE = 10,
|
||||
GB_WORKBOY_BACKSPACE = 11,
|
||||
GB_WORKBOY_UNKNOWN = 12,
|
||||
GB_WORKBOY_LEFT = 13,
|
||||
GB_WORKBOY_Q = 17,
|
||||
GB_WORKBOY_1 = 17 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_W = 18,
|
||||
GB_WORKBOY_2 = 18 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_E = 19,
|
||||
GB_WORKBOY_3 = 19 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_R = 20,
|
||||
GB_WORKBOY_T = 21,
|
||||
GB_WORKBOY_Y = 22 ,
|
||||
GB_WORKBOY_U = 23 ,
|
||||
GB_WORKBOY_I = 24,
|
||||
GB_WORKBOY_EXCLAMATION_MARK = 24 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_O = 25,
|
||||
GB_WORKBOY_TILDE = 25 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_P = 26,
|
||||
GB_WORKBOY_ASTERISK = 26 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_DOLLAR = 27 | GB_WORKBOY_FORBID_SHIFT,
|
||||
GB_WORKBOY_HASH = 27 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_A = 28,
|
||||
GB_WORKBOY_4 = 28 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_S = 29,
|
||||
GB_WORKBOY_5 = 29 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_D = 30,
|
||||
GB_WORKBOY_6 = 30 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_F = 31,
|
||||
GB_WORKBOY_PLUS = 31 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_G = 32,
|
||||
GB_WORKBOY_MINUS = 32 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_H = 33,
|
||||
GB_WORKBOY_J = 34,
|
||||
GB_WORKBOY_K = 35,
|
||||
GB_WORKBOY_LEFT_PARENTHESIS = 35 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_L = 36,
|
||||
GB_WORKBOY_RIGHT_PARENTHESIS = 36 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_SEMICOLON = 37 | GB_WORKBOY_FORBID_SHIFT,
|
||||
GB_WORKBOY_COLON = 37,
|
||||
GB_WORKBOY_ENTER = 38,
|
||||
GB_WORKBOY_SHIFT_DOWN = 39,
|
||||
GB_WORKBOY_Z = 40,
|
||||
GB_WORKBOY_7 = 40 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_X = 41,
|
||||
GB_WORKBOY_8 = 41 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_C = 42,
|
||||
GB_WORKBOY_9 = 42 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_V = 43,
|
||||
GB_WORKBOY_DECIMAL_POINT = 43 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_B = 44,
|
||||
GB_WORKBOY_PERCENT = 44 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_N = 45,
|
||||
GB_WORKBOY_EQUAL = 45 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_M = 46,
|
||||
GB_WORKBOY_COMMA = 47 | GB_WORKBOY_FORBID_SHIFT,
|
||||
GB_WORKBOY_LT = 47 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_DOT = 48 | GB_WORKBOY_FORBID_SHIFT,
|
||||
GB_WORKBOY_GT = 48 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_SLASH = 49 | GB_WORKBOY_FORBID_SHIFT,
|
||||
GB_WORKBOY_QUESTION_MARK = 49 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_SHIFT_UP = 50,
|
||||
GB_WORKBOY_0 = 51 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_UMLAUT = 51,
|
||||
GB_WORKBOY_SPACE = 52,
|
||||
GB_WORKBOY_QUOTE = 53 | GB_WORKBOY_FORBID_SHIFT,
|
||||
GB_WORKBOY_AT = 53 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||
GB_WORKBOY_UP = 54,
|
||||
GB_WORKBOY_DOWN = 55,
|
||||
GB_WORKBOY_RIGHT = 56,
|
||||
};
|
||||
|
||||
|
||||
void GB_connect_workboy(GB_gameboy_t *gb,
|
||||
GB_workboy_set_time_callback set_time_callback,
|
||||
GB_workboy_get_time_callback get_time_callback);
|
||||
bool GB_workboy_is_enabled(GB_gameboy_t *gb);
|
||||
void GB_workboy_set_key(GB_gameboy_t *gb, uint8_t key);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,33 @@
|
|||
namespace Heuristics {
|
||||
|
||||
struct BSMemory {
|
||||
BSMemory(vector<uint8_t>& data, string location);
|
||||
explicit operator bool() const;
|
||||
auto manifest() const -> string;
|
||||
|
||||
private:
|
||||
vector<uint8_t>& data;
|
||||
string location;
|
||||
};
|
||||
|
||||
BSMemory::BSMemory(vector<uint8_t>& data, string location) : data(data), location(location) {
|
||||
}
|
||||
|
||||
BSMemory::operator bool() const {
|
||||
return data.size() >= 0x8000;
|
||||
}
|
||||
|
||||
auto BSMemory::manifest() const -> string {
|
||||
if(!operator bool()) return {};
|
||||
|
||||
string output;
|
||||
output.append("game\n");
|
||||
output.append(" sha256: ", Hash::SHA256(data).digest(), "\n");
|
||||
output.append(" label: ", Location::prefix(location), "\n");
|
||||
output.append(" name: ", Location::prefix(location), "\n");
|
||||
output.append(" board\n");
|
||||
output.append(Memory{}.type("Flash").size(data.size()).content("Program").text());
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,298 @@
|
|||
namespace Heuristics {
|
||||
|
||||
struct GameBoy {
|
||||
GameBoy(vector<uint8_t>& data, string location);
|
||||
explicit operator bool() const;
|
||||
auto manifest() const -> string;
|
||||
|
||||
private:
|
||||
auto read(uint offset) const -> uint8_t { return data[headerAddress + offset]; }
|
||||
|
||||
vector<uint8_t>& data;
|
||||
string location;
|
||||
uint headerAddress = 0;
|
||||
};
|
||||
|
||||
GameBoy::GameBoy(vector<uint8_t>& data, string location) : data(data), location(location) {
|
||||
headerAddress = data.size() < 0x8000 ? data.size() : data.size() - 0x8000;
|
||||
if(read(0x0104) == 0xce && read(0x0105) == 0xed && read(0x0106) == 0x66 && read(0x0107) == 0x66
|
||||
&& read(0x0108) == 0xcc && read(0x0109) == 0x0d && read(0x0147) >= 0x0b && read(0x0147) <= 0x0d
|
||||
) { //MMM01 stores header at bottom of data[]
|
||||
} else { //all other mappers store header at top of data[]
|
||||
headerAddress = 0;
|
||||
}
|
||||
}
|
||||
|
||||
GameBoy::operator bool() const {
|
||||
return data.size() >= 0x4000;
|
||||
}
|
||||
|
||||
auto GameBoy::manifest() const -> string {
|
||||
if(!operator bool()) return {};
|
||||
|
||||
bool black = (read(0x0143) & 0xc0) == 0x80; //cartridge works in DMG+CGB mode
|
||||
bool clear = (read(0x0143) & 0xc0) == 0xc0; //cartridge works in CGB mode only
|
||||
|
||||
bool ram = false;
|
||||
bool battery = false;
|
||||
bool eeprom = false;
|
||||
bool flash = false;
|
||||
bool rtc = false;
|
||||
bool accelerometer = false;
|
||||
bool rumble = false;
|
||||
|
||||
uint romSize = 0;
|
||||
uint ramSize = 0;
|
||||
uint eepromSize = 0;
|
||||
uint flashSize = 0;
|
||||
uint rtcSize = 0;
|
||||
|
||||
string mapper = "MBC0";
|
||||
|
||||
switch(read(0x0147)) {
|
||||
|
||||
case 0x00:
|
||||
mapper = "MBC0";
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
mapper = "MBC1";
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
mapper = "MBC1";
|
||||
ram = true;
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
mapper = "MBC1";
|
||||
battery = true;
|
||||
ram = true;
|
||||
break;
|
||||
|
||||
case 0x05:
|
||||
mapper = "MBC2";
|
||||
ram = true;
|
||||
break;
|
||||
|
||||
case 0x06:
|
||||
mapper = "MBC2";
|
||||
battery = true;
|
||||
ram = true;
|
||||
break;
|
||||
|
||||
case 0x08:
|
||||
mapper = "MBC0";
|
||||
ram = true;
|
||||
break;
|
||||
|
||||
case 0x09:
|
||||
mapper = "MBC0";
|
||||
battery = true;
|
||||
ram = true;
|
||||
break;
|
||||
|
||||
case 0x0b:
|
||||
mapper = "MMM01";
|
||||
break;
|
||||
|
||||
case 0x0c:
|
||||
mapper = "MMM01";
|
||||
ram = true;
|
||||
break;
|
||||
|
||||
case 0x0d:
|
||||
mapper = "MMM01";
|
||||
battery = true;
|
||||
ram = true;
|
||||
break;
|
||||
|
||||
case 0x0f:
|
||||
mapper = "MBC3";
|
||||
battery = true;
|
||||
rtc = true;
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
mapper = "MBC3";
|
||||
battery = true;
|
||||
ram = true;
|
||||
rtc = true;
|
||||
break;
|
||||
|
||||
case 0x11:
|
||||
mapper = "MBC3";
|
||||
break;
|
||||
|
||||
case 0x12:
|
||||
mapper = "MBC3";
|
||||
ram = true;
|
||||
break;
|
||||
|
||||
case 0x13:
|
||||
mapper = "MBC3";
|
||||
battery = true;
|
||||
ram = true;
|
||||
break;
|
||||
|
||||
case 0x19:
|
||||
mapper = "MBC5";
|
||||
break;
|
||||
|
||||
case 0x1a:
|
||||
mapper = "MBC5";
|
||||
ram = true;
|
||||
break;
|
||||
|
||||
case 0x1b:
|
||||
mapper = "MBC5";
|
||||
battery = true;
|
||||
ram = true;
|
||||
break;
|
||||
|
||||
case 0x1c:
|
||||
mapper = "MBC5";
|
||||
rumble = true;
|
||||
break;
|
||||
|
||||
case 0x1d:
|
||||
mapper = "MBC5";
|
||||
ram = true;
|
||||
rumble = true;
|
||||
break;
|
||||
|
||||
case 0x1e:
|
||||
mapper = "MBC5";
|
||||
battery = true;
|
||||
ram = true;
|
||||
rumble = true;
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
mapper = "MBC6";
|
||||
flash = true;
|
||||
battery = true;
|
||||
ram = true;
|
||||
break;
|
||||
|
||||
case 0x22:
|
||||
mapper = "MBC7";
|
||||
battery = true;
|
||||
eeprom = true;
|
||||
accelerometer = true;
|
||||
rumble = true;
|
||||
break;
|
||||
|
||||
case 0xfc:
|
||||
mapper = "CAMERA";
|
||||
break;
|
||||
|
||||
case 0xfd:
|
||||
mapper = "TAMA";
|
||||
battery = true;
|
||||
ram = true;
|
||||
rtc = true;
|
||||
break;
|
||||
|
||||
case 0xfe:
|
||||
mapper = "HuC3";
|
||||
break;
|
||||
|
||||
case 0xff:
|
||||
mapper = "HuC1";
|
||||
battery = true;
|
||||
ram = true;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
//Game Boy: title = $0134-0143
|
||||
//Game Boy Color (early games): title = $0134-0142; model = $0143
|
||||
//Game Boy Color (later games): title = $0134-013e; serial = $013f-0142; model = $0143
|
||||
string title;
|
||||
for(uint n : range(black || clear ? 15 : 16)) {
|
||||
char byte = read(0x0134 + n);
|
||||
if(byte < 0x20 || byte > 0x7e) byte = ' ';
|
||||
title.append(byte);
|
||||
}
|
||||
|
||||
string serial = title.slice(-4);
|
||||
if(!black && !clear) serial = "";
|
||||
for(auto& byte : serial) {
|
||||
if(byte >= 'A' && byte <= 'Z') continue;
|
||||
//invalid serial
|
||||
serial = "";
|
||||
break;
|
||||
}
|
||||
title.trimRight(serial, 1L); //remove the serial from the title, if it exists
|
||||
title.strip(); //remove any excess whitespace from the title
|
||||
|
||||
switch(read(0x0148)) { default:
|
||||
case 0x00: romSize = 2 * 16 * 1024; break;
|
||||
case 0x01: romSize = 4 * 16 * 1024; break;
|
||||
case 0x02: romSize = 8 * 16 * 1024; break;
|
||||
case 0x03: romSize = 16 * 16 * 1024; break;
|
||||
case 0x04: romSize = 32 * 16 * 1024; break;
|
||||
case 0x05: romSize = 64 * 16 * 1024; break;
|
||||
case 0x06: romSize = 128 * 16 * 1024; break;
|
||||
case 0x07: romSize = 256 * 16 * 1024; break;
|
||||
case 0x52: romSize = 72 * 16 * 1024; break;
|
||||
case 0x53: romSize = 80 * 16 * 1024; break;
|
||||
case 0x54: romSize = 96 * 16 * 1024; break;
|
||||
}
|
||||
|
||||
switch(read(0x0149)) { default:
|
||||
case 0x00: ramSize = 0 * 1024; break;
|
||||
case 0x01: ramSize = 2 * 1024; break;
|
||||
case 0x02: ramSize = 8 * 1024; break;
|
||||
case 0x03: ramSize = 32 * 1024; break;
|
||||
}
|
||||
|
||||
if(mapper == "MBC2" && ram) ramSize = 256;
|
||||
if(mapper == "MBC6" && ram) ramSize = 32 * 1024;
|
||||
if(mapper == "TAMA" && ram) ramSize = 32;
|
||||
|
||||
if(mapper == "MBC6" && flash) flashSize = 1024 * 1024;
|
||||
|
||||
//Game Boy header does not specify EEPROM size: detect via game title instead
|
||||
//Command Master: EEPROM = 512 bytes
|
||||
//Kirby Tilt 'n' Tumble: EEPROM = 256 bytes
|
||||
//Korokoro Kirby: EEPROM = 256 bytes
|
||||
if(mapper == "MBC7" && eeprom) {
|
||||
eepromSize = 256; //fallback guess; supported values are 128, 256, 512
|
||||
if(title == "CMASTER" && serial == "KCEJ") eepromSize = 512;
|
||||
if(title == "KIRBY TNT" && serial == "KTNE") eepromSize = 256;
|
||||
if(title == "KORO2 KIRBY" && serial == "KKKJ") eepromSize = 256;
|
||||
}
|
||||
|
||||
if(mapper == "MBC3" && rtc) rtcSize = 13;
|
||||
if(mapper == "TAMA" && rtc) rtcSize = 21;
|
||||
|
||||
string output;
|
||||
output.append("game\n");
|
||||
output.append(" sha256: ", Hash::SHA256(data).digest(), "\n");
|
||||
output.append(" label: ", Location::prefix(location), "\n");
|
||||
output.append(" name: ", Location::prefix(location), "\n");
|
||||
output.append(" title: ", title, "\n");
|
||||
if(serial)
|
||||
output.append(" serial: ", serial, "\n");
|
||||
output.append(" board: ", mapper, "\n");
|
||||
output.append(Memory{}.type("ROM").size(data.size()).content("Program").text());
|
||||
if(ram && ramSize && battery)
|
||||
output.append(Memory{}.type("RAM").size(ramSize).content("Save").text());
|
||||
if(ram && ramSize && !battery)
|
||||
output.append(Memory{}.type("RAM").size(ramSize).content("Save").isVolatile().text());
|
||||
if(eeprom && eepromSize)
|
||||
output.append(Memory{}.type("EEPROM").size(eepromSize).content("Save").text());
|
||||
if(flash && flashSize)
|
||||
output.append(Memory{}.type("Flash").size(flashSize).content("Download").text());
|
||||
if(rtc && rtcSize)
|
||||
output.append(Memory{}.type("RTC").size(rtcSize).content("Time").text());
|
||||
if(accelerometer)
|
||||
output.append(" accelerometer\n");
|
||||
if(rumble)
|
||||
output.append(" rumble\n");
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
namespace Heuristics {
|
||||
|
||||
auto Memory::text() const -> string {
|
||||
string output;
|
||||
output.append(" memory\n");
|
||||
output.append(" type: ", _type, "\n");
|
||||
output.append(" size: 0x", hex(_size), "\n");
|
||||
output.append(" content: ", _content, "\n");
|
||||
if(_manufacturer)
|
||||
output.append(" manufacturer: ", _manufacturer, "\n");
|
||||
if(_architecture)
|
||||
output.append(" architecture: ", _architecture, "\n");
|
||||
if(_identifier)
|
||||
output.append(" identifier: ", _identifier, "\n");
|
||||
if(_volatile)
|
||||
output.append(" volatile\n");
|
||||
return output;
|
||||
}
|
||||
|
||||
auto Oscillator::text() const -> string {
|
||||
string output;
|
||||
output.append(" oscillator\n");
|
||||
output.append(" frequency: ", _frequency, "\n");
|
||||
return output;
|
||||
}
|
||||
|
||||
auto Slot::text() const -> string {
|
||||
string output;
|
||||
output.append(" slot\n");
|
||||
output.append(" type: ", _type, "\n");
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
namespace Heuristics {
|
||||
|
||||
struct Memory {
|
||||
auto& type(string type) { _type = type; return *this; }
|
||||
auto& size(natural size) { _size = size; return *this; }
|
||||
auto& content(string content) { _content = content; return *this; }
|
||||
auto& manufacturer(string manufacturer) { _manufacturer = manufacturer; return *this; }
|
||||
auto& architecture(string architecture) { _architecture = architecture; return *this; }
|
||||
auto& identifier(string identifier) { _identifier = identifier; return *this; }
|
||||
auto& isVolatile() { _volatile = true; return *this; }
|
||||
auto text() const -> string;
|
||||
|
||||
string _type;
|
||||
boolean _battery;
|
||||
natural _size;
|
||||
string _content;
|
||||
string _manufacturer;
|
||||
string _architecture;
|
||||
string _identifier;
|
||||
boolean _volatile;
|
||||
};
|
||||
|
||||
struct Oscillator {
|
||||
auto& frequency(natural frequency) { _frequency = frequency; return *this; }
|
||||
auto text() const -> string;
|
||||
|
||||
natural _frequency;
|
||||
};
|
||||
|
||||
struct Slot {
|
||||
auto& type(string type) { _type = type; return *this; }
|
||||
auto text() const -> string;
|
||||
|
||||
string _type;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,605 @@
|
|||
namespace Heuristics {
|
||||
|
||||
struct SuperFamicom {
|
||||
SuperFamicom(vector<uint8_t>& data, string location);
|
||||
explicit operator bool() const;
|
||||
|
||||
auto manifest() const -> string;
|
||||
auto region() const -> string;
|
||||
auto videoRegion() const -> string;
|
||||
auto revision() const -> string;
|
||||
auto board() const -> string;
|
||||
auto title() const -> string;
|
||||
auto serial() const -> string;
|
||||
auto romSize() const -> uint;
|
||||
auto programRomSize() const -> uint;
|
||||
auto dataRomSize() const -> uint;
|
||||
auto expansionRomSize() const -> uint;
|
||||
auto firmwareRomSize() const -> uint;
|
||||
auto ramSize() const -> uint;
|
||||
auto expansionRamSize() const -> uint;
|
||||
auto nonVolatile() const -> bool;
|
||||
|
||||
private:
|
||||
auto size() const -> uint { return data.size(); }
|
||||
auto scoreHeader(uint address) -> uint;
|
||||
auto firmwareARM() const -> string;
|
||||
auto firmwareEXNEC() const -> string;
|
||||
auto firmwareGB() const -> string;
|
||||
auto firmwareHITACHI() const -> string;
|
||||
auto firmwareNEC() const -> string;
|
||||
|
||||
vector<uint8_t>& data;
|
||||
string location;
|
||||
uint headerAddress = 0;
|
||||
};
|
||||
|
||||
SuperFamicom::SuperFamicom(vector<uint8_t>& data, string location) : data(data), location(location) {
|
||||
if((size() & 0x7fff) == 512) {
|
||||
//remove header if present
|
||||
memory::move(&data[0], &data[512], size() - 512);
|
||||
data.resize(size() - 512);
|
||||
}
|
||||
|
||||
if(size() < 0x8000) return; //ignore images too small to be valid
|
||||
|
||||
uint LoROM = scoreHeader( 0x7fb0);
|
||||
uint HiROM = scoreHeader( 0xffb0);
|
||||
uint ExLoROM = scoreHeader(0x407fb0);
|
||||
uint ExHiROM = scoreHeader(0x40ffb0);
|
||||
if(ExLoROM) ExLoROM += 4;
|
||||
if(ExHiROM) ExHiROM += 4;
|
||||
|
||||
if(LoROM >= HiROM && LoROM >= ExLoROM && LoROM >= ExHiROM) headerAddress = 0x7fb0;
|
||||
else if(HiROM >= ExLoROM && HiROM >= ExHiROM) headerAddress = 0xffb0;
|
||||
else if(ExLoROM >= ExHiROM) headerAddress = 0x407fb0;
|
||||
else headerAddress = 0x40ffb0;
|
||||
}
|
||||
|
||||
SuperFamicom::operator bool() const {
|
||||
return headerAddress;
|
||||
}
|
||||
|
||||
auto SuperFamicom::manifest() const -> string {
|
||||
if(!operator bool()) return {};
|
||||
|
||||
string output;
|
||||
output.append("game\n");
|
||||
output.append(" sha256: ", Hash::SHA256(data).digest(), "\n");
|
||||
output.append(" label: ", Location::prefix(location), "\n");
|
||||
output.append(" name: ", Location::prefix(location), "\n");
|
||||
output.append(" title: ", title(), "\n");
|
||||
output.append(" region: ", region(), "\n");
|
||||
output.append(" revision: ", revision(), "\n");
|
||||
output.append(" board: ", board(), "\n");
|
||||
|
||||
auto board = this->board().trimRight("#A", 1L).split("-");
|
||||
|
||||
if(auto size = romSize()) {
|
||||
if(board(0) == "SPC7110" && size > 0x100000) {
|
||||
output.append(Memory{}.type("ROM").size(0x100000).content("Program").text());
|
||||
output.append(Memory{}.type("ROM").size(size - 0x100000).content("Data").text());
|
||||
} else if(board(0) == "EXSPC7110" && size == 0x700000) {
|
||||
//Tengai Maykou Zero (fan translation)
|
||||
output.append(Memory{}.type("ROM").size(0x100000).content("Program").text());
|
||||
output.append(Memory{}.type("ROM").size(0x500000).content("Data").text());
|
||||
output.append(Memory{}.type("ROM").size(0x100000).content("Expansion").text());
|
||||
} else {
|
||||
output.append(Memory{}.type("ROM").size(size).content("Program").text());
|
||||
}
|
||||
}
|
||||
|
||||
if(auto size = ramSize()) {
|
||||
output.append(Memory{}.type("RAM").size(size).content("Save").text());
|
||||
}
|
||||
|
||||
if(auto size = expansionRamSize()) {
|
||||
output.append(Memory{}.type("RAM").size(size).content("Save").text());
|
||||
}
|
||||
|
||||
if(0) {
|
||||
} else if(board(0) == "ARM") {
|
||||
output.append(Memory{}.type("ROM").size(0x20000).content("Program").manufacturer("SETA").architecture("ARM6").identifier(firmwareARM()).text());
|
||||
output.append(Memory{}.type("ROM").size( 0x8000).content("Data" ).manufacturer("SETA").architecture("ARM6").identifier(firmwareARM()).text());
|
||||
output.append(Memory{}.type("RAM").size( 0x4000).content("Data" ).manufacturer("SETA").architecture("ARM6").identifier(firmwareARM()).isVolatile().text());
|
||||
output.append(Oscillator{}.frequency(21'440'000).text());
|
||||
} else if(board(0) == "BS" && board(1) == "MCC") {
|
||||
output.append(Memory{}.type("RAM").size(0x80000).content("Download").text());
|
||||
} else if(board(0) == "EXNEC") {
|
||||
output.append(Memory{}.type("ROM").size(0xc000).content("Program").manufacturer("NEC").architecture("uPD96050").identifier(firmwareEXNEC()).text());
|
||||
output.append(Memory{}.type("ROM").size(0x1000).content("Data" ).manufacturer("NEC").architecture("uPD96050").identifier(firmwareEXNEC()).text());
|
||||
output.append(Memory{}.type("RAM").size(0x1000).content("Data" ).manufacturer("NEC").architecture("uPD96050").identifier(firmwareEXNEC()).text());
|
||||
output.append(Oscillator{}.frequency(firmwareEXNEC() == "ST010" ? 11'000'000 : 15'000'000).text());
|
||||
} else if(board(0) == "GB") {
|
||||
output.append(Memory{}.type("ROM").size(0x100).content("Boot").manufacturer("Nintendo").architecture("LR35902").identifier(firmwareGB()).text());
|
||||
if(firmwareGB() == "SGB2")
|
||||
output.append(Oscillator{}.frequency(20'971'520).text());
|
||||
} else if(board(0) == "GSU") {
|
||||
//todo: MARIO CHIP 1 uses CPU oscillator
|
||||
output.append(Oscillator{}.frequency(21'440'000).text());
|
||||
} else if(board(0) == "HITACHI") {
|
||||
output.append(Memory{}.type("ROM").size(0xc00).content("Data").manufacturer("Hitachi").architecture("HG51BS169").identifier(firmwareHITACHI()).text());
|
||||
output.append(Memory{}.type("RAM").size(0xc00).content("Data").manufacturer("Hitachi").architecture("HG51BS169").identifier(firmwareHITACHI()).isVolatile().text());
|
||||
output.append(Oscillator{}.frequency(20'000'000).text());
|
||||
} else if(board(0) == "NEC") {
|
||||
output.append(Memory{}.type("ROM").size(0x1800).content("Program").manufacturer("NEC").architecture("uPD7725").identifier(firmwareNEC()).text());
|
||||
output.append(Memory{}.type("ROM").size( 0x800).content("Data" ).manufacturer("NEC").architecture("uPD7725").identifier(firmwareNEC()).text());
|
||||
output.append(Memory{}.type("RAM").size( 0x200).content("Data" ).manufacturer("NEC").architecture("uPD7725").identifier(firmwareNEC()).isVolatile().text());
|
||||
output.append(Oscillator{}.frequency(7'600'000).text());
|
||||
} else if(board(0) == "SA1" || board(1) == "SA1") { //SA1-* or BS-SA1-*
|
||||
output.append(Memory{}.type("RAM").size(0x800).content("Internal").isVolatile().text());
|
||||
}
|
||||
|
||||
if(board.right() == "EPSONRTC") {
|
||||
output.append(Memory{}.type("RTC").size(0x10).content("Time").manufacturer("Epson").text());
|
||||
} else if(board.right() == "SHARPRTC") {
|
||||
output.append(Memory{}.type("RTC").size(0x10).content("Time").manufacturer("Sharp").text());
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
auto SuperFamicom::region() const -> string {
|
||||
//Unlicensed software (homebrew, ROM hacks, etc) often change the standard region code,
|
||||
//and then neglect to change the extended header region code. Thanks to that, we can't
|
||||
//decode and display the full game serial + region code.
|
||||
return videoRegion();
|
||||
|
||||
string region;
|
||||
|
||||
char A = data[headerAddress + 0x02]; //game type
|
||||
char B = data[headerAddress + 0x03]; //game code
|
||||
char C = data[headerAddress + 0x04]; //game code
|
||||
char D = data[headerAddress + 0x05]; //region code (new; sometimes ambiguous)
|
||||
auto E = data[headerAddress + 0x29]; //region code (old)
|
||||
|
||||
auto valid = [](char n) { return (n >= '0' && n <= '9') || (n >= 'A' && n <= 'Z'); };
|
||||
if(data[headerAddress + 0x2a] == 0x33 && valid(A) && valid(B) & valid(C) & valid(D)) {
|
||||
string code{A, B, C, D};
|
||||
if(D == 'B') region = {"SNS-", code, "-BRA"};
|
||||
if(D == 'C') region = {"SNSN-", code, "-ROC"};
|
||||
if(D == 'D') region = {"SNSP-", code, "-NOE"};
|
||||
if(D == 'E') region = {"SNS-", code, "-USA"};
|
||||
if(D == 'F') region = {"SNSP-", code, "-FRA"};
|
||||
if(D == 'H') region = {"SNSP-", code, "-HOL"};
|
||||
if(D == 'I') region = {"SNSP-", code, "-ITA"};
|
||||
if(D == 'J') region = {"SHVC-", code, "-JPN"};
|
||||
if(D == 'K') region = {"SNSN-", code, "-KOR"};
|
||||
if(D == 'N') region = {"SNS-", code, "-CAN"};
|
||||
if(D == 'P') region = {"SNSP-", code, "-EUR"};
|
||||
if(D == 'S') region = {"SNSP-", code, "-ESP"};
|
||||
if(D == 'U') region = {"SNSP-", code, "-AUS"};
|
||||
if(D == 'X') region = {"SNSP-", code, "-SCN"};
|
||||
}
|
||||
|
||||
if(!region) {
|
||||
if(E == 0x00) region = {"JPN"};
|
||||
if(E == 0x01) region = {"USA"};
|
||||
if(E == 0x02) region = {"EUR"};
|
||||
if(E == 0x03) region = {"SCN"};
|
||||
if(E == 0x06) region = {"FRA"};
|
||||
if(E == 0x07) region = {"HOL"};
|
||||
if(E == 0x08) region = {"ESP"};
|
||||
if(E == 0x09) region = {"NOE"};
|
||||
if(E == 0x0a) region = {"ITA"};
|
||||
if(E == 0x0b) region = {"ROC"};
|
||||
if(E == 0x0d) region = {"KOR"};
|
||||
if(E == 0x0f) region = {"CAN"};
|
||||
if(E == 0x10) region = {"BRA"};
|
||||
if(E == 0x11) region = {"AUS"};
|
||||
if(E == 0x12) region = {"SCN"};
|
||||
}
|
||||
|
||||
return region ? region : "NTSC";
|
||||
}
|
||||
|
||||
auto SuperFamicom::videoRegion() const -> string {
|
||||
auto region = data[headerAddress + 0x29];
|
||||
if(region == 0x00) return "NTSC"; //JPN
|
||||
if(region == 0x01) return "NTSC"; //USA
|
||||
if(region == 0x0b) return "NTSC"; //ROC
|
||||
if(region == 0x0d) return "NTSC"; //KOR
|
||||
if(region == 0x0f) return "NTSC"; //CAN
|
||||
if(region == 0x10) return "NTSC"; //BRA
|
||||
return "PAL";
|
||||
}
|
||||
|
||||
auto SuperFamicom::revision() const -> string {
|
||||
string revision;
|
||||
|
||||
char A = data[headerAddress + 0x02]; //game type
|
||||
char B = data[headerAddress + 0x03]; //game code
|
||||
char C = data[headerAddress + 0x04]; //game code
|
||||
char D = data[headerAddress + 0x05]; //region code (new; sometimes ambiguous)
|
||||
auto E = data[headerAddress + 0x29]; //region code (old)
|
||||
uint F = data[headerAddress + 0x2b]; //revision code
|
||||
|
||||
auto valid = [](char n) { return (n >= '0' && n <= '9') || (n >= 'A' && n <= 'Z'); };
|
||||
if(data[headerAddress + 0x2a] == 0x33 && valid(A) && valid(B) & valid(C) & valid(D)) {
|
||||
string code{A, B, C, D};
|
||||
if(D == 'B') revision = {"SNS-", code, "-", F};
|
||||
if(D == 'C') revision = {"SNSN-", code, "-", F};
|
||||
if(D == 'D') revision = {"SNSP-", code, "-", F};
|
||||
if(D == 'E') revision = {"SNS-", code, "-", F};
|
||||
if(D == 'F') revision = {"SNSP-", code, "-", F};
|
||||
if(D == 'H') revision = {"SNSP-", code, "-", F};
|
||||
if(D == 'I') revision = {"SNSP-", code, "-", F};
|
||||
if(D == 'J') revision = {"SHVC-", code, "-", F};
|
||||
if(D == 'K') revision = {"SNSN-", code, "-", F};
|
||||
if(D == 'N') revision = {"SNS-", code, "-", F};
|
||||
if(D == 'P') revision = {"SNSP-", code, "-", F};
|
||||
if(D == 'S') revision = {"SNSP-", code, "-", F};
|
||||
if(D == 'U') revision = {"SNSP-", code, "-", F};
|
||||
if(D == 'X') revision = {"SNSP-", code, "-", F};
|
||||
}
|
||||
|
||||
if(!revision) {
|
||||
revision = {"1.", F};
|
||||
}
|
||||
|
||||
return revision ? revision : string{"1.", F};
|
||||
}
|
||||
|
||||
//format: [slot]-[coprocessor]-[mapper]-[ram]-[rtc]
|
||||
auto SuperFamicom::board() const -> string {
|
||||
string board;
|
||||
|
||||
auto mapMode = data[headerAddress + 0x25];
|
||||
auto cartridgeTypeLo = data[headerAddress + 0x26] & 15;
|
||||
auto cartridgeTypeHi = data[headerAddress + 0x26] >> 4;
|
||||
auto cartridgeSubType = data[headerAddress + 0x0f];
|
||||
|
||||
string mode;
|
||||
if(mapMode == 0x20 || mapMode == 0x30) mode = "LOROM-";
|
||||
if(mapMode == 0x21 || mapMode == 0x31) mode = "HIROM-";
|
||||
if(mapMode == 0x22 || mapMode == 0x32) mode = "SDD1-";
|
||||
if(mapMode == 0x23 || mapMode == 0x33) mode = "SA1-";
|
||||
if(mapMode == 0x25 || mapMode == 0x35) mode = "EXHIROM-";
|
||||
if(mapMode == 0x2a || mapMode == 0x3a) mode = "SPC7110-";
|
||||
|
||||
//many games will store an extra title character, overwriting the map mode
|
||||
//further, ExLoROM mode is unofficial, and lacks a mapping mode value
|
||||
if(!mode) {
|
||||
if(headerAddress == 0x7fb0) mode = "LOROM-";
|
||||
if(headerAddress == 0xffb0) mode = "HIROM-";
|
||||
if(headerAddress == 0x407fb0) mode = "EXLOROM-";
|
||||
if(headerAddress == 0x40ffb0) mode = "EXHIROM-";
|
||||
}
|
||||
|
||||
//this game's title ovewrites the map mode with '!' (0x21), but is a LOROM game
|
||||
if(title() == "YUYU NO QUIZ DE GO!GO") mode = "LOROM-";
|
||||
|
||||
if(mode == "LOROM-" && headerAddress == 0x407fb0) mode = "EXLOROM-";
|
||||
|
||||
bool epsonRTC = false;
|
||||
bool sharpRTC = false;
|
||||
|
||||
if(serial() == "A9PJ") {
|
||||
//Sufami Turbo (JPN)
|
||||
board.append("ST-", mode);
|
||||
} else if(serial() == "ZBSJ") {
|
||||
//BS-X: Sore wa Namae o Nusumareta Machi no Monogatari (JPN)
|
||||
board.append("BS-MCC-");
|
||||
} else if(serial() == "042J") {
|
||||
//Super Game Boy 2
|
||||
board.append("GB-", mode);
|
||||
} else if(serial().match("Z??J")) {
|
||||
board.append("BS-", mode);
|
||||
} else if(cartridgeTypeLo >= 0x3) {
|
||||
if(cartridgeTypeHi == 0x0) board.append("NEC-", mode);
|
||||
if(cartridgeTypeHi == 0x1) board.append("GSU-");
|
||||
if(cartridgeTypeHi == 0x2) board.append("OBC1-", mode);
|
||||
if(cartridgeTypeHi == 0x3) board.append("SA1-");
|
||||
if(cartridgeTypeHi == 0x4) board.append("SDD1-");
|
||||
if(cartridgeTypeHi == 0x5) board.append(mode), sharpRTC = true;
|
||||
if(cartridgeTypeHi == 0xe && cartridgeTypeLo == 0x3) board.append("GB-", mode);
|
||||
if(cartridgeTypeHi == 0xf && cartridgeTypeLo == 0x5 && cartridgeSubType == 0x00) board.append("SPC7110-");
|
||||
if(cartridgeTypeHi == 0xf && cartridgeTypeLo == 0x9 && cartridgeSubType == 0x00) board.append("SPC7110-"), epsonRTC = true;
|
||||
if(cartridgeTypeHi == 0xf && cartridgeSubType == 0x01) board.append("EXNEC-", mode);
|
||||
if(cartridgeTypeHi == 0xf && cartridgeSubType == 0x02) board.append("ARM-", mode);
|
||||
if(cartridgeTypeHi == 0xf && cartridgeSubType == 0x10) board.append("HITACHI-", mode);
|
||||
}
|
||||
if(!board) board.append(mode);
|
||||
|
||||
if(ramSize() || expansionRamSize()) board.append("RAM-");
|
||||
if(epsonRTC) board.append("EPSONRTC-");
|
||||
if(sharpRTC) board.append("SHARPRTC-");
|
||||
|
||||
board.trimRight("-", 1L);
|
||||
|
||||
if(board.beginsWith( "LOROM-RAM") && romSize() <= 0x200000) board.append("#A");
|
||||
if(board.beginsWith("NEC-LOROM-RAM") && romSize() <= 0x100000) board.append("#A");
|
||||
|
||||
//Tengai Makyou Zero (fan translation)
|
||||
if(board.beginsWith("SPC7110-") && data.size() == 0x700000) board.prepend("EX");
|
||||
|
||||
return board;
|
||||
}
|
||||
|
||||
auto SuperFamicom::title() const -> string {
|
||||
string label;
|
||||
|
||||
for(uint n = 0; n < 0x15; n++) {
|
||||
auto x = data[headerAddress + 0x10 + n];
|
||||
auto y = n == 0x14 ? 0 : data[headerAddress + 0x11 + n];
|
||||
|
||||
//null terminator (padding)
|
||||
if(x == 0x00 || x == 0xff);
|
||||
|
||||
//ASCII
|
||||
else if(x >= 0x20 && x <= 0x7e) label.append((char)x);
|
||||
|
||||
//Shift-JIS (half-width katakana)
|
||||
else if(x == 0xa1) label.append("。");
|
||||
else if(x == 0xa2) label.append("「");
|
||||
else if(x == 0xa3) label.append("」");
|
||||
else if(x == 0xa4) label.append("、");
|
||||
else if(x == 0xa5) label.append("・");
|
||||
else if(x == 0xa6) label.append("ヲ");
|
||||
else if(x == 0xa7) label.append("ァ");
|
||||
else if(x == 0xa8) label.append("ィ");
|
||||
else if(x == 0xa9) label.append("ゥ");
|
||||
else if(x == 0xaa) label.append("ェ");
|
||||
else if(x == 0xab) label.append("ォ");
|
||||
else if(x == 0xac) label.append("ャ");
|
||||
else if(x == 0xad) label.append("ュ");
|
||||
else if(x == 0xae) label.append("ョ");
|
||||
else if(x == 0xaf) label.append("ッ");
|
||||
else if(x == 0xb0) label.append("ー");
|
||||
|
||||
else if(x == 0xb1) label.append( "ア");
|
||||
else if(x == 0xb2) label.append( "イ");
|
||||
else if(x == 0xb3) label.append(y == 0xde ? "ヴ" : "ウ");
|
||||
else if(x == 0xb4) label.append( "エ");
|
||||
else if(x == 0xb5) label.append( "オ");
|
||||
|
||||
else if(x == 0xb6) label.append(y == 0xde ? "ガ" : "カ");
|
||||
else if(x == 0xb7) label.append(y == 0xde ? "ギ" : "キ");
|
||||
else if(x == 0xb8) label.append(y == 0xde ? "グ" : "ク");
|
||||
else if(x == 0xb9) label.append(y == 0xde ? "ゲ" : "ケ");
|
||||
else if(x == 0xba) label.append(y == 0xde ? "ゴ" : "コ");
|
||||
|
||||
else if(x == 0xbb) label.append(y == 0xde ? "ザ" : "サ");
|
||||
else if(x == 0xbc) label.append(y == 0xde ? "ジ" : "シ");
|
||||
else if(x == 0xbd) label.append(y == 0xde ? "ズ" : "ス");
|
||||
else if(x == 0xbe) label.append(y == 0xde ? "ゼ" : "セ");
|
||||
else if(x == 0xbf) label.append(y == 0xde ? "ゾ" : "ソ");
|
||||
|
||||
else if(x == 0xc0) label.append(y == 0xde ? "ダ" : "タ");
|
||||
else if(x == 0xc1) label.append(y == 0xde ? "ヂ" : "チ");
|
||||
else if(x == 0xc2) label.append(y == 0xde ? "ヅ" : "ツ");
|
||||
else if(x == 0xc3) label.append(y == 0xde ? "デ" : "テ");
|
||||
else if(x == 0xc4) label.append(y == 0xde ? "ド" : "ト");
|
||||
|
||||
else if(x == 0xc5) label.append("ナ");
|
||||
else if(x == 0xc6) label.append("ニ");
|
||||
else if(x == 0xc7) label.append("ヌ");
|
||||
else if(x == 0xc8) label.append("ネ");
|
||||
else if(x == 0xc9) label.append("ノ");
|
||||
|
||||
else if(x == 0xca) label.append(y == 0xdf ? "パ" : y == 0xde ? "バ" : "ハ");
|
||||
else if(x == 0xcb) label.append(y == 0xdf ? "ピ" : y == 0xde ? "ビ" : "ヒ");
|
||||
else if(x == 0xcc) label.append(y == 0xdf ? "プ" : y == 0xde ? "ブ" : "フ");
|
||||
else if(x == 0xcd) label.append(y == 0xdf ? "ペ" : y == 0xde ? "ベ" : "ヘ");
|
||||
else if(x == 0xce) label.append(y == 0xdf ? "ポ" : y == 0xde ? "ボ" : "ホ");
|
||||
|
||||
else if(x == 0xcf) label.append("マ");
|
||||
else if(x == 0xd0) label.append("ミ");
|
||||
else if(x == 0xd1) label.append("ム");
|
||||
else if(x == 0xd2) label.append("メ");
|
||||
else if(x == 0xd3) label.append("モ");
|
||||
|
||||
else if(x == 0xd4) label.append("ヤ");
|
||||
else if(x == 0xd5) label.append("ユ");
|
||||
else if(x == 0xd6) label.append("ヨ");
|
||||
|
||||
else if(x == 0xd7) label.append("ラ");
|
||||
else if(x == 0xd8) label.append("リ");
|
||||
else if(x == 0xd9) label.append("ル");
|
||||
else if(x == 0xda) label.append("レ");
|
||||
else if(x == 0xdb) label.append("ロ");
|
||||
|
||||
else if(x == 0xdc) label.append("ワ");
|
||||
else if(x == 0xdd) label.append("ン");
|
||||
|
||||
else if(x == 0xde) label.append("\xef\xbe\x9e"); //dakuten
|
||||
else if(x == 0xdf) label.append("\xef\xbe\x9f"); //handakuten
|
||||
|
||||
//unknown
|
||||
else label.append("?");
|
||||
|
||||
//(han)dakuten skip
|
||||
if(y == 0xde && x == 0xb3) n++;
|
||||
if(y == 0xde && x >= 0xb6 && x <= 0xc4) n++;
|
||||
if(y == 0xde && x >= 0xca && x <= 0xce) n++;
|
||||
if(y == 0xdf && x >= 0xca && y <= 0xce) n++;
|
||||
}
|
||||
|
||||
return label.strip();
|
||||
}
|
||||
|
||||
auto SuperFamicom::serial() const -> string {
|
||||
char A = data[headerAddress + 0x02]; //game type
|
||||
char B = data[headerAddress + 0x03]; //game code
|
||||
char C = data[headerAddress + 0x04]; //game code
|
||||
char D = data[headerAddress + 0x05]; //region code (new; sometimes ambiguous)
|
||||
|
||||
auto valid = [](char n) { return (n >= '0' && n <= '9') || (n >= 'A' && n <= 'Z'); };
|
||||
if(data[headerAddress + 0x2a] == 0x33 && valid(A) && valid(B) & valid(C) & valid(D)) {
|
||||
return {A, B, C, D};
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
auto SuperFamicom::romSize() const -> uint {
|
||||
return size() - firmwareRomSize();
|
||||
}
|
||||
|
||||
auto SuperFamicom::programRomSize() const -> uint {
|
||||
if(board().beginsWith("SPC7110-")) return 0x100000;
|
||||
if(board().beginsWith("EXSPC7110-")) return 0x100000;
|
||||
return romSize();
|
||||
}
|
||||
|
||||
auto SuperFamicom::dataRomSize() const -> uint {
|
||||
if(board().beginsWith("SPC7110-")) return romSize() - 0x100000;
|
||||
if(board().beginsWith("EXSPC7110-")) return 0x500000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto SuperFamicom::expansionRomSize() const -> uint {
|
||||
if(board().beginsWith("EXSPC7110-")) return 0x100000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//detect if any firmware is appended to the ROM image, and return its size if so
|
||||
auto SuperFamicom::firmwareRomSize() const -> uint {
|
||||
auto cartridgeTypeLo = data[headerAddress + 0x26] & 15;
|
||||
auto cartridgeTypeHi = data[headerAddress + 0x26] >> 4;
|
||||
auto cartridgeSubType = data[headerAddress + 0x0f];
|
||||
|
||||
if(serial() == "042J" || (cartridgeTypeLo == 0x3 && cartridgeTypeHi == 0xe)) {
|
||||
//Game Boy
|
||||
if((size() & 0x7fff) == 0x100) return 0x100;
|
||||
}
|
||||
|
||||
if(cartridgeTypeLo >= 0x3 && cartridgeTypeHi == 0xf && cartridgeSubType == 0x10) {
|
||||
//Hitachi HG51BS169
|
||||
if((size() & 0x7fff) == 0xc00) return 0xc00;
|
||||
}
|
||||
|
||||
if(cartridgeTypeLo >= 0x3 && cartridgeTypeHi == 0x0) {
|
||||
//NEC uPD7725
|
||||
if((size() & 0x7fff) == 0x2000) return 0x2000;
|
||||
}
|
||||
|
||||
if(cartridgeTypeLo >= 0x3 && cartridgeTypeHi == 0xf && cartridgeSubType == 0x01) {
|
||||
//NEC uPD96050
|
||||
if((size() & 0xffff) == 0xd000) return 0xd000;
|
||||
}
|
||||
|
||||
if(cartridgeTypeLo >= 0x3 && cartridgeTypeHi == 0xf && cartridgeSubType == 0x02) {
|
||||
//ARM6
|
||||
if((size() & 0x3ffff) == 0x28000) return 0x28000;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto SuperFamicom::ramSize() const -> uint {
|
||||
auto ramSize = data[headerAddress + 0x28] & 15;
|
||||
if(ramSize > 8) ramSize = 8;
|
||||
if(ramSize > 0) return 1024 << ramSize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto SuperFamicom::expansionRamSize() const -> uint {
|
||||
if(data[headerAddress + 0x2a] == 0x33) {
|
||||
auto ramSize = data[headerAddress + 0x0d] & 15;
|
||||
if(ramSize > 8) ramSize = 8;
|
||||
if(ramSize > 0) return 1024 << ramSize;
|
||||
}
|
||||
if((data[headerAddress + 0x26] >> 4) == 1) {
|
||||
//GSU: Starfox / Starwing lacks an extended header; but still has expansion RAM
|
||||
return 0x8000;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto SuperFamicom::nonVolatile() const -> bool {
|
||||
auto cartridgeTypeLo = data[headerAddress + 0x26] & 15;
|
||||
return cartridgeTypeLo == 0x2 || cartridgeTypeLo == 0x5 || cartridgeTypeLo == 0x6;
|
||||
}
|
||||
|
||||
auto SuperFamicom::scoreHeader(uint address) -> uint {
|
||||
int score = 0;
|
||||
if(size() < address + 0x50) return score;
|
||||
|
||||
uint8_t mapMode = data[address + 0x25] & ~0x10; //ignore FastROM bit
|
||||
uint16_t complement = data[address + 0x2c] << 0 | data[address + 0x2d] << 8;
|
||||
uint16_t checksum = data[address + 0x2e] << 0 | data[address + 0x2f] << 8;
|
||||
uint16_t resetVector = data[address + 0x4c] << 0 | data[address + 0x4d] << 8;
|
||||
if(resetVector < 0x8000) return score; //$00:0000-7fff is never ROM data
|
||||
|
||||
uint8_t opcode = data[(address & ~0x7fff) | (resetVector & 0x7fff)]; //first instruction executed
|
||||
|
||||
//most likely opcodes
|
||||
if(opcode == 0x78 //sei
|
||||
|| opcode == 0x18 //clc (clc; xce)
|
||||
|| opcode == 0x38 //sec (sec; xce)
|
||||
|| opcode == 0x9c //stz $nnnn (stz $4200)
|
||||
|| opcode == 0x4c //jmp $nnnn
|
||||
|| opcode == 0x5c //jml $nnnnnn
|
||||
) score += 8;
|
||||
|
||||
//plausible opcodes
|
||||
if(opcode == 0xc2 //rep #$nn
|
||||
|| opcode == 0xe2 //sep #$nn
|
||||
|| opcode == 0xad //lda $nnnn
|
||||
|| opcode == 0xae //ldx $nnnn
|
||||
|| opcode == 0xac //ldy $nnnn
|
||||
|| opcode == 0xaf //lda $nnnnnn
|
||||
|| opcode == 0xa9 //lda #$nn
|
||||
|| opcode == 0xa2 //ldx #$nn
|
||||
|| opcode == 0xa0 //ldy #$nn
|
||||
|| opcode == 0x20 //jsr $nnnn
|
||||
|| opcode == 0x22 //jsl $nnnnnn
|
||||
) score += 4;
|
||||
|
||||
//implausible opcodes
|
||||
if(opcode == 0x40 //rti
|
||||
|| opcode == 0x60 //rts
|
||||
|| opcode == 0x6b //rtl
|
||||
|| opcode == 0xcd //cmp $nnnn
|
||||
|| opcode == 0xec //cpx $nnnn
|
||||
|| opcode == 0xcc //cpy $nnnn
|
||||
) score -= 4;
|
||||
|
||||
//least likely opcodes
|
||||
if(opcode == 0x00 //brk #$nn
|
||||
|| opcode == 0x02 //cop #$nn
|
||||
|| opcode == 0xdb //stp
|
||||
|| opcode == 0x42 //wdm
|
||||
|| opcode == 0xff //sbc $nnnnnn,x
|
||||
) score -= 8;
|
||||
|
||||
if(checksum + complement == 0xffff) score += 4;
|
||||
|
||||
if(address == 0x7fb0 && mapMode == 0x20) score += 2;
|
||||
if(address == 0xffb0 && mapMode == 0x21) score += 2;
|
||||
|
||||
return max(0, score);
|
||||
}
|
||||
|
||||
auto SuperFamicom::firmwareARM() const -> string {
|
||||
return "ST018";
|
||||
}
|
||||
|
||||
auto SuperFamicom::firmwareEXNEC() const -> string {
|
||||
if(title() == "EXHAUST HEAT2") return "ST010";
|
||||
if(title() == "F1 ROC II") return "ST010";
|
||||
if(title() == "2DAN MORITA SHOUGI") return "ST011";
|
||||
return "ST010";
|
||||
}
|
||||
|
||||
auto SuperFamicom::firmwareGB() const -> string {
|
||||
if(title() == "Super GAMEBOY") return "SGB1";
|
||||
if(title() == "Super GAMEBOY2") return "SGB2";
|
||||
return "SGB1";
|
||||
}
|
||||
|
||||
auto SuperFamicom::firmwareHITACHI() const -> string {
|
||||
return "Cx4";
|
||||
}
|
||||
|
||||
auto SuperFamicom::firmwareNEC() const -> string {
|
||||
if(title() == "PILOTWINGS") return "DSP1";
|
||||
if(title() == "DUNGEON MASTER") return "DSP2";
|
||||
if(title() == "SDガンダムGX") return "DSP3";
|
||||
if(title() == "PLANETS CHAMP TG3000") return "DSP4";
|
||||
if(title() == "TOP GEAR 3000") return "DSP4";
|
||||
return "DSP1B";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
//deprecated
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nall/range.hpp>
|
||||
#include <nall/traits.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
template<typename T, uint Capacity>
|
||||
struct adaptive_array {
|
||||
auto capacity() const -> uint { return Capacity; }
|
||||
auto size() const -> uint { return _size; }
|
||||
|
||||
auto reset() -> void {
|
||||
for(uint n : range(_size)) _pool.t[n].~T();
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
auto operator[](uint index) -> T& {
|
||||
#ifdef DEBUG
|
||||
struct out_of_bounds {};
|
||||
if(index >= Capacity) throw out_of_bounds{};
|
||||
#endif
|
||||
return _pool.t[index];
|
||||
}
|
||||
|
||||
auto operator[](uint index) const -> const T& {
|
||||
#ifdef DEBUG
|
||||
struct out_of_bounds {};
|
||||
if(index >= Capacity) throw out_of_bounds{};
|
||||
#endif
|
||||
return _pool.t[index];
|
||||
}
|
||||
|
||||
auto append() -> T& {
|
||||
new(_pool.t + _size) T;
|
||||
return _pool.t[_size++];
|
||||
}
|
||||
|
||||
auto append(const T& value) -> void {
|
||||
new(_pool.t + _size++) T(value);
|
||||
}
|
||||
|
||||
auto append(T&& value) -> void {
|
||||
new(_pool.t + _size++) T(move(value));
|
||||
}
|
||||
|
||||
auto begin() { return &_pool.t[0]; }
|
||||
auto end() { return &_pool.t[_size]; }
|
||||
|
||||
auto begin() const { return &_pool.t[0]; }
|
||||
auto end() const { return &_pool.t[_size]; }
|
||||
|
||||
private:
|
||||
union U {
|
||||
U() {}
|
||||
~U() {}
|
||||
T t[Capacity];
|
||||
} _pool;
|
||||
uint _size = 0;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <nall/traits.hpp>
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
namespace nall {
|
||||
|
||||
template<typename T, typename U> constexpr auto min(const T& t, const U& u) -> T {
|
||||
return t < u ? t : (T)u;
|
||||
}
|
||||
|
||||
template<typename T, typename U, typename... P> constexpr auto min(const T& t, const U& u, P&&... p) -> T {
|
||||
return t < u ? min(t, forward<P>(p)...) : min(u, forward<P>(p)...);
|
||||
}
|
||||
|
||||
template<typename T, typename U> constexpr auto max(const T& t, const U& u) -> T {
|
||||
return t > u ? t : (T)u;
|
||||
}
|
||||
|
||||
template<typename T, typename U, typename... P> constexpr auto max(const T& t, const U& u, P&&... p) -> T {
|
||||
return t > u ? max(t, forward<P>(p)...) : max(u, forward<P>(p)...);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
#pragma once
|
||||
|
||||
#include <typeinfo>
|
||||
#include <nall/traits.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct any {
|
||||
any() = default;
|
||||
any(const any& source) { operator=(source); }
|
||||
any(any&& source) { operator=(move(source)); }
|
||||
template<typename T> any(const T& value) { operator=(value); }
|
||||
~any() { reset(); }
|
||||
|
||||
explicit operator bool() const { return container; }
|
||||
auto reset() -> void { if(container) { delete container; container = nullptr; } }
|
||||
|
||||
auto type() const -> const std::type_info& {
|
||||
return container ? container->type() : typeid(void);
|
||||
}
|
||||
|
||||
template<typename T> auto is() const -> bool {
|
||||
return type() == typeid(typename remove_reference<T>::type);
|
||||
}
|
||||
|
||||
template<typename T> auto get() -> T& {
|
||||
if(!is<T>()) throw;
|
||||
return static_cast<holder<typename remove_reference<T>::type>*>(container)->value;
|
||||
}
|
||||
|
||||
template<typename T> auto get() const -> const T& {
|
||||
if(!is<T>()) throw;
|
||||
return static_cast<holder<typename remove_reference<T>::type>*>(container)->value;
|
||||
}
|
||||
|
||||
template<typename T> auto get(const T& fallback) const -> const T& {
|
||||
if(!is<T>()) return fallback;
|
||||
return static_cast<holder<typename remove_reference<T>::type>*>(container)->value;
|
||||
}
|
||||
|
||||
template<typename T> auto operator=(const T& value) -> any& {
|
||||
using auto_t = typename conditional<is_array<T>::value, typename remove_extent<typename add_const<T>::type>::type*, T>::type;
|
||||
|
||||
if(type() == typeid(auto_t)) {
|
||||
static_cast<holder<auto_t>*>(container)->value = (auto_t)value;
|
||||
} else {
|
||||
if(container) delete container;
|
||||
container = new holder<auto_t>((auto_t)value);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto operator=(const any& source) -> any& {
|
||||
if(container) { delete container; container = nullptr; }
|
||||
if(source.container) container = source.container->copy();
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto operator=(any&& source) -> any& {
|
||||
if(container) delete container;
|
||||
container = source.container;
|
||||
source.container = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
struct placeholder {
|
||||
virtual ~placeholder() = default;
|
||||
virtual auto type() const -> const std::type_info& = 0;
|
||||
virtual auto copy() const -> placeholder* = 0;
|
||||
};
|
||||
placeholder* container = nullptr;
|
||||
|
||||
template<typename T> struct holder : placeholder {
|
||||
holder(const T& value) : value(value) {}
|
||||
auto type() const -> const std::type_info& { return typeid(T); }
|
||||
auto copy() const -> placeholder* { return new holder(value); }
|
||||
T value;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
#pragma once
|
||||
|
||||
#include <nall/location.hpp>
|
||||
#include <nall/path.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct Arguments {
|
||||
Arguments(int argc, char** argv);
|
||||
Arguments(vector<string> arguments);
|
||||
|
||||
explicit operator bool() const { return (bool)arguments; }
|
||||
auto size() const -> uint { return arguments.size(); }
|
||||
|
||||
auto operator[](uint index) -> string& { return arguments[index]; }
|
||||
auto operator[](uint index) const -> const string& { return arguments[index]; }
|
||||
|
||||
auto programPath() const -> string;
|
||||
auto programName() const -> string;
|
||||
auto programLocation() const -> string;
|
||||
|
||||
auto find(string_view name) const -> bool;
|
||||
auto find(string_view name, bool& argument) const -> bool;
|
||||
auto find(string_view name, string& argument) const -> bool;
|
||||
|
||||
auto begin() const { return arguments.begin(); }
|
||||
auto end() const { return arguments.end(); }
|
||||
|
||||
auto rbegin() const { return arguments.rbegin(); }
|
||||
auto rend() const { return arguments.rend(); }
|
||||
|
||||
auto take() -> string;
|
||||
auto take(string_view name) -> bool;
|
||||
auto take(string_view name, bool& argument) -> bool;
|
||||
auto take(string_view name, string& argument) -> bool;
|
||||
|
||||
auto begin() { return arguments.begin(); }
|
||||
auto end() { return arguments.end(); }
|
||||
|
||||
auto rbegin() { return arguments.rbegin(); }
|
||||
auto rend() { return arguments.rend(); }
|
||||
|
||||
private:
|
||||
auto construct() -> void;
|
||||
|
||||
string programArgument;
|
||||
vector<string> arguments;
|
||||
};
|
||||
|
||||
inline auto Arguments::construct() -> void {
|
||||
if(!arguments) return;
|
||||
|
||||
//extract and pre-process program argument
|
||||
programArgument = arguments.takeFirst();
|
||||
programArgument = {Path::real(programArgument), Location::file(programArgument)};
|
||||
|
||||
//normalize path and file arguments
|
||||
for(auto& argument : arguments) {
|
||||
if(directory::exists(argument)) argument.transform("\\", "/").trimRight("/").append("/");
|
||||
else if(file::exists(argument)) argument.transform("\\", "/").trimRight("/");
|
||||
}
|
||||
}
|
||||
|
||||
inline Arguments::Arguments(int argc, char** argv) {
|
||||
#if defined(PLATFORM_WINDOWS)
|
||||
utf8_arguments(argc, argv);
|
||||
#endif
|
||||
for(uint index : range(argc)) arguments.append(argv[index]);
|
||||
construct();
|
||||
}
|
||||
|
||||
inline Arguments::Arguments(vector<string> arguments) {
|
||||
this->arguments = arguments;
|
||||
construct();
|
||||
}
|
||||
|
||||
inline auto Arguments::programPath() const -> string {
|
||||
return Location::path(programArgument);
|
||||
}
|
||||
|
||||
inline auto Arguments::programName() const -> string {
|
||||
return Location::file(programArgument);
|
||||
}
|
||||
|
||||
inline auto Arguments::programLocation() const -> string {
|
||||
return programArgument;
|
||||
}
|
||||
|
||||
inline auto Arguments::find(string_view name) const -> bool {
|
||||
for(uint index : range(arguments.size())) {
|
||||
if(arguments[index].match(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline auto Arguments::find(string_view name, bool& argument) const -> bool {
|
||||
for(uint index : range(arguments.size())) {
|
||||
if(arguments[index].match(name) && arguments.size() >= index
|
||||
&& (arguments[index + 1] == "true" || arguments[index + 1] == "false")) {
|
||||
argument = arguments[index + 1] == "true";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline auto Arguments::find(string_view name, string& argument) const -> bool {
|
||||
for(uint index : range(arguments.size())) {
|
||||
if(arguments[index].match(name) && arguments.size() >= index) {
|
||||
argument = arguments[index + 1];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline auto Arguments::take() -> string {
|
||||
if(!arguments) return {};
|
||||
return arguments.takeFirst();
|
||||
}
|
||||
|
||||
inline auto Arguments::take(string_view name) -> bool {
|
||||
for(uint index : range(arguments.size())) {
|
||||
if(arguments[index].match(name)) {
|
||||
arguments.remove(index);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline auto Arguments::take(string_view name, bool& argument) -> bool {
|
||||
for(uint index : range(arguments.size())) {
|
||||
if(arguments[index].match(name) && arguments.size() > index + 1
|
||||
&& (arguments[index + 1] == "true" || arguments[index + 1] == "false")) {
|
||||
arguments.remove(index);
|
||||
argument = arguments.take(index) == "true";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline auto Arguments::take(string_view name, string& argument) -> bool {
|
||||
for(uint index : range(arguments.size())) {
|
||||
if(arguments[index].match(name) && arguments.size() > index + 1) {
|
||||
arguments.remove(index);
|
||||
argument = arguments.take(index);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
#pragma once
|
||||
|
||||
//multi-precision arithmetic
|
||||
//warning: each size is quadratically more expensive than the size before it!
|
||||
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/range.hpp>
|
||||
#include <nall/traits.hpp>
|
||||
|
||||
#include <nall/arithmetic/unsigned.hpp>
|
||||
|
||||
namespace nall {
|
||||
template<uint Bits> struct ArithmeticNatural;
|
||||
template<> struct ArithmeticNatural< 8> { using type = uint8_t; };
|
||||
template<> struct ArithmeticNatural< 16> { using type = uint16_t; };
|
||||
template<> struct ArithmeticNatural< 32> { using type = uint32_t; };
|
||||
template<> struct ArithmeticNatural< 64> { using type = uint64_t; };
|
||||
#if INTMAX_BITS >= 128
|
||||
template<> struct ArithmeticNatural<128> { using type = uint128_t; };
|
||||
#endif
|
||||
}
|
||||
|
||||
#if INTMAX_BITS < 128
|
||||
#define PairBits 128
|
||||
#define TypeBits 64
|
||||
#define HalfBits 32
|
||||
#include <nall/arithmetic/natural.hpp>
|
||||
#undef PairBits
|
||||
#undef TypeBits
|
||||
#undef HalfBits
|
||||
#endif
|
||||
|
||||
#define PairBits 256
|
||||
#define TypeBits 128
|
||||
#define HalfBits 64
|
||||
#include <nall/arithmetic/natural.hpp>
|
||||
#undef PairBits
|
||||
#undef TypeBits
|
||||
#undef HalfBits
|
||||
|
||||
#define PairBits 512
|
||||
#define TypeBits 256
|
||||
#define HalfBits 128
|
||||
#include <nall/arithmetic/natural.hpp>
|
||||
#undef PairBits
|
||||
#undef TypeBits
|
||||
#undef HalfBits
|
||||
|
||||
#define PairBits 1024
|
||||
#define TypeBits 512
|
||||
#define HalfBits 256
|
||||
#include <nall/arithmetic/natural.hpp>
|
||||
#undef PairBits
|
||||
#undef TypeBits
|
||||
#undef HalfBits
|
||||
|
||||
#define PairBits 2048
|
||||
#define TypeBits 1024
|
||||
#define HalfBits 512
|
||||
#include <nall/arithmetic/natural.hpp>
|
||||
#undef PairBits
|
||||
#undef TypeBits
|
||||
#undef HalfBits
|
||||
|
||||
#define PairBits 4096
|
||||
#define TypeBits 2048
|
||||
#define HalfBits 1024
|
||||
#include <nall/arithmetic/natural.hpp>
|
||||
#undef PairBits
|
||||
#undef TypeBits
|
||||
#undef HalfBits
|
||||
|
||||
#define PairBits 8192
|
||||
#define TypeBits 4096
|
||||
#define HalfBits 2048
|
||||
#include <nall/arithmetic/natural.hpp>
|
||||
#undef PairBits
|
||||
#undef TypeBits
|
||||
#undef HalfBits
|
||||
|
||||
namespace nall {
|
||||
//TODO: these types are for expressing smaller bit ranges in class interfaces
|
||||
//for instance, XChaCha20 taking a 192-bit nonce
|
||||
//however, they still allow more bits than expressed ...
|
||||
//some sort of wrapper needs to be devised to ensure these sizes are masked and wrap appropriately
|
||||
|
||||
using uint192_t = uint256_t;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
namespace nall {
|
||||
|
||||
template<uint Bits> struct BarrettReduction {
|
||||
using type = typename ArithmeticNatural<1 * Bits>::type;
|
||||
using pair = typename ArithmeticNatural<2 * Bits>::type;
|
||||
|
||||
explicit BarrettReduction(type modulo) : modulo(modulo), factor(pair(1) + -pair(modulo) / modulo) {}
|
||||
|
||||
//return => value % modulo
|
||||
inline auto operator()(pair value) const -> type {
|
||||
pair hi, lo;
|
||||
mul(value, factor, hi, lo);
|
||||
pair remainder = value - hi * modulo;
|
||||
return remainder < modulo ? remainder : remainder - modulo;
|
||||
}
|
||||
|
||||
private:
|
||||
const pair modulo;
|
||||
const pair factor;
|
||||
};
|
||||
|
||||
template<typename T, uint Bits> auto operator%(T value, const BarrettReduction<Bits>& modulo) {
|
||||
return modulo(value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,342 @@
|
|||
#define ConcatenateType(Size) uint##Size##_t
|
||||
#define DeclareType(Size) ConcatenateType(Size)
|
||||
|
||||
#define Pair DeclareType(PairBits)
|
||||
#define Type DeclareType(TypeBits)
|
||||
#define Half DeclareType(HalfBits)
|
||||
|
||||
//pick the larger of two types to prevent unnecessary data clamping
|
||||
#define Cast (typename conditional<sizeof(Pair) >= sizeof(T), Pair, T>::type)
|
||||
|
||||
namespace nall {
|
||||
//namespace Arithmetic {
|
||||
|
||||
struct Pair {
|
||||
Pair() = default;
|
||||
explicit constexpr Pair(const Pair& source) : hi(source.hi), lo(source.lo) {}
|
||||
template<typename Hi, typename Lo> constexpr Pair(const Hi& hi, const Lo& lo) : hi(hi), lo(lo) {}
|
||||
template<typename T> Pair(const T& source) { _set(*this, source); }
|
||||
|
||||
explicit operator bool() const { return hi | lo; }
|
||||
template<typename T> operator T() const { T value; _get(*this, value); return value; }
|
||||
|
||||
auto operator+() const -> Pair { return *this; }
|
||||
auto operator-() const -> Pair { return Pair(0) - *this; }
|
||||
auto operator~() const -> Pair { return {~hi, ~lo}; }
|
||||
auto operator!() const -> bool { return !(hi || lo); }
|
||||
|
||||
auto operator++() -> Pair& { lo++; hi += lo == 0; return *this; }
|
||||
auto operator--() -> Pair& { hi -= lo == 0; lo--; return *this; }
|
||||
|
||||
auto operator++(int) -> Pair { Pair r = *this; lo++; hi += lo == 0; return r; }
|
||||
auto operator--(int) -> Pair { Pair r = *this; hi -= lo == 0; lo--; return r; }
|
||||
|
||||
auto operator* (const Pair& rhs) const -> Pair { return mul(*this, rhs); }
|
||||
auto operator/ (const Pair& rhs) const -> Pair { Pair q, r; div(*this, rhs, q, r); return q; }
|
||||
auto operator% (const Pair& rhs) const -> Pair { Pair q, r; div(*this, rhs, q, r); return r; }
|
||||
auto operator+ (const Pair& rhs) const -> Pair { return {hi + rhs.hi + (lo + rhs.lo < lo), lo + rhs.lo}; }
|
||||
auto operator- (const Pair& rhs) const -> Pair { return {hi - rhs.hi - (lo - rhs.lo > lo), lo - rhs.lo}; }
|
||||
auto operator<<(const Pair& rhs) const -> Pair { return shl(*this, rhs); }
|
||||
auto operator>>(const Pair& rhs) const -> Pair { return shr(*this, rhs); }
|
||||
auto operator& (const Pair& rhs) const -> Pair { return {hi & rhs.hi, lo & rhs.lo}; }
|
||||
auto operator| (const Pair& rhs) const -> Pair { return {hi | rhs.hi, lo | rhs.lo}; }
|
||||
auto operator^ (const Pair& rhs) const -> Pair { return {hi ^ rhs.hi, lo ^ rhs.lo}; }
|
||||
auto operator==(const Pair& rhs) const -> bool { return hi == rhs.hi && lo == rhs.lo; }
|
||||
auto operator!=(const Pair& rhs) const -> bool { return hi != rhs.hi || lo != rhs.lo; }
|
||||
auto operator>=(const Pair& rhs) const -> bool { return hi > rhs.hi || (hi == rhs.hi && lo >= rhs.lo); }
|
||||
auto operator<=(const Pair& rhs) const -> bool { return hi < rhs.hi || (hi == rhs.hi && lo <= rhs.lo); }
|
||||
auto operator> (const Pair& rhs) const -> bool { return hi > rhs.hi || (hi == rhs.hi && lo > rhs.lo); }
|
||||
auto operator< (const Pair& rhs) const -> bool { return hi < rhs.hi || (hi == rhs.hi && lo < rhs.lo); }
|
||||
|
||||
template<typename T> auto& operator*= (const T& rhs) { return *this = *this * Pair(rhs); }
|
||||
template<typename T> auto& operator/= (const T& rhs) { return *this = *this / Pair(rhs); }
|
||||
template<typename T> auto& operator%= (const T& rhs) { return *this = *this % Pair(rhs); }
|
||||
template<typename T> auto& operator+= (const T& rhs) { return *this = *this + Pair(rhs); }
|
||||
template<typename T> auto& operator-= (const T& rhs) { return *this = *this - Pair(rhs); }
|
||||
template<typename T> auto& operator<<=(const T& rhs) { return *this = *this << Pair(rhs); }
|
||||
template<typename T> auto& operator>>=(const T& rhs) { return *this = *this >> Pair(rhs); }
|
||||
template<typename T> auto& operator&= (const T& rhs) { return *this = *this & Pair(rhs); }
|
||||
template<typename T> auto& operator|= (const T& rhs) { return *this = *this | Pair(rhs); }
|
||||
template<typename T> auto& operator^= (const T& rhs) { return *this = *this ^ Pair(rhs); }
|
||||
|
||||
template<typename T> auto operator* (const T& rhs) const { return Cast(*this) * Cast(rhs); }
|
||||
template<typename T> auto operator/ (const T& rhs) const { return Cast(*this) / Cast(rhs); }
|
||||
template<typename T> auto operator% (const T& rhs) const { return Cast(*this) % Cast(rhs); }
|
||||
template<typename T> auto operator+ (const T& rhs) const { return Cast(*this) + Cast(rhs); }
|
||||
template<typename T> auto operator- (const T& rhs) const { return Cast(*this) - Cast(rhs); }
|
||||
template<typename T> auto operator<<(const T& rhs) const { return Cast(*this) << Cast(rhs); }
|
||||
template<typename T> auto operator>>(const T& rhs) const { return Cast(*this) >> Cast(rhs); }
|
||||
template<typename T> auto operator& (const T& rhs) const { return Cast(*this) & Cast(rhs); }
|
||||
template<typename T> auto operator| (const T& rhs) const { return Cast(*this) | Cast(rhs); }
|
||||
template<typename T> auto operator^ (const T& rhs) const { return Cast(*this) ^ Cast(rhs); }
|
||||
|
||||
template<typename T> auto operator==(const T& rhs) const -> bool { return Cast(*this) == Cast(rhs); }
|
||||
template<typename T> auto operator!=(const T& rhs) const -> bool { return Cast(*this) != Cast(rhs); }
|
||||
template<typename T> auto operator>=(const T& rhs) const -> bool { return Cast(*this) >= Cast(rhs); }
|
||||
template<typename T> auto operator<=(const T& rhs) const -> bool { return Cast(*this) <= Cast(rhs); }
|
||||
template<typename T> auto operator> (const T& rhs) const -> bool { return Cast(*this) > Cast(rhs); }
|
||||
template<typename T> auto operator< (const T& rhs) const -> bool { return Cast(*this) < Cast(rhs); }
|
||||
|
||||
private:
|
||||
Type lo;
|
||||
Type hi;
|
||||
|
||||
friend auto upper(const Pair&) -> Type;
|
||||
friend auto lower(const Pair&) -> Type;
|
||||
friend auto bits(Pair) -> uint;
|
||||
friend auto square(const Pair&) -> Pair;
|
||||
friend auto square(const Pair&, Pair&, Pair&) -> void;
|
||||
friend auto mul(const Pair&, const Pair&) -> Pair;
|
||||
friend auto mul(const Pair&, const Pair&, Pair&, Pair&) -> void;
|
||||
friend auto div(const Pair&, const Pair&, Pair&, Pair&) -> void;
|
||||
template<typename T> friend auto shl(const Pair&, const T&) -> Pair;
|
||||
template<typename T> friend auto shr(const Pair&, const T&) -> Pair;
|
||||
};
|
||||
|
||||
template<> struct ArithmeticNatural<PairBits> {
|
||||
using type = Pair;
|
||||
};
|
||||
|
||||
#define ConcatenateUDL(Size) _u##Size
|
||||
#define DeclareUDL(Size) ConcatenateUDL(Size)
|
||||
|
||||
alwaysinline auto operator"" DeclareUDL(PairBits)(const char* s) -> Pair {
|
||||
Pair p = 0;
|
||||
if(s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
|
||||
s += 2;
|
||||
while(*s) {
|
||||
auto c = *s++;
|
||||
if(c == '\'');
|
||||
else if(c >= '0' && c <= '9') p = (p << 4) + (c - '0');
|
||||
else if(c >= 'a' && c <= 'f') p = (p << 4) + (c - 'a' + 10);
|
||||
else if(c >= 'A' && c <= 'F') p = (p << 4) + (c - 'A' + 10);
|
||||
else break;
|
||||
}
|
||||
} else {
|
||||
while(*s) {
|
||||
auto c = *s++;
|
||||
if(c == '\'');
|
||||
else if(c >= '0' && c <= '9') p = (p << 3) + (p << 1) + (c - '0');
|
||||
else break;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
#undef ConcatenateUDL
|
||||
#undef DeclareUDL
|
||||
|
||||
template<typename T> alwaysinline auto _set(Pair& lhs, const T& rhs) -> enable_if_t<(sizeof(Pair) == sizeof(T))> {
|
||||
lhs = rhs;
|
||||
}
|
||||
|
||||
template<typename T> alwaysinline auto _set(Pair& lhs, const T& rhs) -> enable_if_t<(sizeof(Pair) > sizeof(T))> {
|
||||
lhs = {0, rhs};
|
||||
}
|
||||
|
||||
template<typename T> alwaysinline auto _set(Pair& lhs, const T& rhs) -> enable_if_t<(sizeof(Pair) < sizeof(T))> {
|
||||
lhs = {lower(rhs) >> TypeBits, lower(rhs)};
|
||||
}
|
||||
|
||||
template<typename T> alwaysinline auto _get(const Pair& lhs, T& rhs) -> enable_if_t<(sizeof(T) == sizeof(Pair))> {
|
||||
rhs = lhs;
|
||||
}
|
||||
|
||||
template<typename T> alwaysinline auto _get(const Pair& lhs, T& rhs) -> enable_if_t<(sizeof(T) > sizeof(Pair))> {
|
||||
rhs = {0, lhs};
|
||||
}
|
||||
|
||||
template<typename T> alwaysinline auto _get(const Pair& lhs, T& rhs) -> enable_if_t<(sizeof(T) < sizeof(Pair))> {
|
||||
rhs = lower(lhs);
|
||||
}
|
||||
|
||||
alwaysinline auto upper(const Pair& value) -> Type { return value.hi; }
|
||||
alwaysinline auto lower(const Pair& value) -> Type { return value.lo; }
|
||||
|
||||
alwaysinline auto bits(Pair value) -> uint {
|
||||
if(value.hi) {
|
||||
uint bits = TypeBits;
|
||||
while(value.hi) value.hi >>= 1, bits++;
|
||||
return bits;
|
||||
} else {
|
||||
uint bits = 0;
|
||||
while(value.lo) value.lo >>= 1, bits++;
|
||||
return bits;
|
||||
}
|
||||
}
|
||||
|
||||
//Bits * Bits => Bits
|
||||
inline auto square(const Pair& lhs) -> Pair {
|
||||
static const Type Mask = (Type(0) - 1) >> HalfBits;
|
||||
Type a = lhs.hi >> HalfBits, b = lhs.hi & Mask, c = lhs.lo >> HalfBits, d = lhs.lo & Mask;
|
||||
Type dd = square(d), dc = d * c, db = d * b, da = d * a;
|
||||
Type cc = square(c), cb = c * b;
|
||||
|
||||
Pair r0 = Pair(dd);
|
||||
Pair r1 = Pair(dc) + Pair(dc) + Pair(r0 >> HalfBits);
|
||||
Pair r2 = Pair(db) + Pair(cc) + Pair(db) + Pair(r1 >> HalfBits);
|
||||
Pair r3 = Pair(da) + Pair(cb) + Pair(cb) + Pair(da) + Pair(r2 >> HalfBits);
|
||||
|
||||
return {(r3.lo & Mask) << HalfBits | (r2.lo & Mask), (r1.lo & Mask) << HalfBits | (r0.lo & Mask)};
|
||||
}
|
||||
|
||||
//Bits * Bits => 2 * Bits
|
||||
inline auto square(const Pair& lhs, Pair& hi, Pair& lo) -> void {
|
||||
static const Type Mask = (Type(0) - 1) >> HalfBits;
|
||||
Type a = lhs.hi >> HalfBits, b = lhs.hi & Mask, c = lhs.lo >> HalfBits, d = lhs.lo & Mask;
|
||||
Type dd = square(d), dc = d * c, db = d * b, da = d * a;
|
||||
Type cc = square(c), cb = c * b, ca = c * a;
|
||||
Type bb = square(b), ba = b * a;
|
||||
Type aa = square(a);
|
||||
|
||||
Pair r0 = Pair(dd);
|
||||
Pair r1 = Pair(dc) + Pair(dc) + Pair(r0 >> HalfBits);
|
||||
Pair r2 = Pair(db) + Pair(cc) + Pair(db) + Pair(r1 >> HalfBits);
|
||||
Pair r3 = Pair(da) + Pair(cb) + Pair(cb) + Pair(da) + Pair(r2 >> HalfBits);
|
||||
Pair r4 = Pair(ca) + Pair(bb) + Pair(ca) + Pair(r3 >> HalfBits);
|
||||
Pair r5 = Pair(ba) + Pair(ba) + Pair(r4 >> HalfBits);
|
||||
Pair r6 = Pair(aa) + Pair(r5 >> HalfBits);
|
||||
Pair r7 = Pair(r6 >> HalfBits);
|
||||
|
||||
hi = {(r7.lo & Mask) << HalfBits | (r6.lo & Mask), (r5.lo & Mask) << HalfBits | (r4.lo & Mask)};
|
||||
lo = {(r3.lo & Mask) << HalfBits | (r2.lo & Mask), (r1.lo & Mask) << HalfBits | (r0.lo & Mask)};
|
||||
}
|
||||
|
||||
//Bits * Bits => Bits
|
||||
alwaysinline auto mul(const Pair& lhs, const Pair& rhs) -> Pair {
|
||||
static const Type Mask = (Type(0) - 1) >> HalfBits;
|
||||
Type a = lhs.hi >> HalfBits, b = lhs.hi & Mask, c = lhs.lo >> HalfBits, d = lhs.lo & Mask;
|
||||
Type e = rhs.hi >> HalfBits, f = rhs.hi & Mask, g = rhs.lo >> HalfBits, h = rhs.lo & Mask;
|
||||
|
||||
Pair r0 = Pair(d * h);
|
||||
Pair r1 = Pair(c * h) + Pair(d * g) + Pair(r0 >> HalfBits);
|
||||
Pair r2 = Pair(b * h) + Pair(c * g) + Pair(d * f) + Pair(r1 >> HalfBits);
|
||||
Pair r3 = Pair(a * h) + Pair(b * g) + Pair(c * f) + Pair(d * e) + Pair(r2 >> HalfBits);
|
||||
|
||||
return {(r3.lo & Mask) << HalfBits | (r2.lo & Mask), (r1.lo & Mask) << HalfBits | (r0.lo & Mask)};
|
||||
}
|
||||
|
||||
//Bits * Bits => 2 * Bits
|
||||
alwaysinline auto mul(const Pair& lhs, const Pair& rhs, Pair& hi, Pair& lo) -> void {
|
||||
static const Type Mask = (Type(0) - 1) >> HalfBits;
|
||||
Type a = lhs.hi >> HalfBits, b = lhs.hi & Mask, c = lhs.lo >> HalfBits, d = lhs.lo & Mask;
|
||||
Type e = rhs.hi >> HalfBits, f = rhs.hi & Mask, g = rhs.lo >> HalfBits, h = rhs.lo & Mask;
|
||||
|
||||
Pair r0 = Pair(d * h);
|
||||
Pair r1 = Pair(c * h) + Pair(d * g) + Pair(r0 >> HalfBits);
|
||||
Pair r2 = Pair(b * h) + Pair(c * g) + Pair(d * f) + Pair(r1 >> HalfBits);
|
||||
Pair r3 = Pair(a * h) + Pair(b * g) + Pair(c * f) + Pair(d * e) + Pair(r2 >> HalfBits);
|
||||
Pair r4 = Pair(a * g) + Pair(b * f) + Pair(c * e) + Pair(r3 >> HalfBits);
|
||||
Pair r5 = Pair(a * f) + Pair(b * e) + Pair(r4 >> HalfBits);
|
||||
Pair r6 = Pair(a * e) + Pair(r5 >> HalfBits);
|
||||
Pair r7 = Pair(r6 >> HalfBits);
|
||||
|
||||
hi = {(r7.lo & Mask) << HalfBits | (r6.lo & Mask), (r5.lo & Mask) << HalfBits | (r4.lo & Mask)};
|
||||
lo = {(r3.lo & Mask) << HalfBits | (r2.lo & Mask), (r1.lo & Mask) << HalfBits | (r0.lo & Mask)};
|
||||
}
|
||||
|
||||
alwaysinline auto div(const Pair& lhs, const Pair& rhs, Pair& quotient, Pair& remainder) -> void {
|
||||
if(!rhs) throw std::runtime_error("division by zero");
|
||||
quotient = 0, remainder = lhs;
|
||||
if(!lhs || lhs < rhs) return;
|
||||
|
||||
auto count = bits(lhs) - bits(rhs);
|
||||
Pair x = rhs << count;
|
||||
Pair y = Pair(1) << count;
|
||||
if(x > remainder) x >>= 1, y >>= 1;
|
||||
while(remainder >= rhs) {
|
||||
if(remainder >= x) remainder -= x, quotient |= y;
|
||||
x >>= 1, y >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> alwaysinline auto shl(const Pair& lhs, const T& rhs) -> Pair {
|
||||
if(!rhs) return lhs;
|
||||
auto shift = (uint)rhs;
|
||||
if(shift < TypeBits) {
|
||||
return {lhs.hi << shift | lhs.lo >> (TypeBits - shift), lhs.lo << shift};
|
||||
} else {
|
||||
return {lhs.lo << (shift - TypeBits), 0};
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> alwaysinline auto shr(const Pair& lhs, const T& rhs) -> Pair {
|
||||
if(!rhs) return lhs;
|
||||
auto shift = (uint)rhs;
|
||||
if(shift < TypeBits) {
|
||||
return {lhs.hi >> shift, lhs.hi << (TypeBits - shift) | lhs.lo >> shift};
|
||||
} else {
|
||||
return {0, lhs.hi >> (shift - TypeBits)};
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> alwaysinline auto rol(const Pair& lhs, const T& rhs) -> Pair {
|
||||
return lhs << rhs | lhs >> (PairBits - rhs);
|
||||
}
|
||||
|
||||
template<typename T> alwaysinline auto ror(const Pair& lhs, const T& rhs) -> Pair {
|
||||
return lhs >> rhs | lhs << (PairBits - rhs);
|
||||
}
|
||||
|
||||
#define EI enable_if_t<is_integral<T>::value>
|
||||
|
||||
template<typename T, EI> auto& operator*= (T& lhs, const Pair& rhs) { return lhs = lhs * T(rhs); }
|
||||
template<typename T, EI> auto& operator/= (T& lhs, const Pair& rhs) { return lhs = lhs / T(rhs); }
|
||||
template<typename T, EI> auto& operator%= (T& lhs, const Pair& rhs) { return lhs = lhs % T(rhs); }
|
||||
template<typename T, EI> auto& operator+= (T& lhs, const Pair& rhs) { return lhs = lhs + T(rhs); }
|
||||
template<typename T, EI> auto& operator-= (T& lhs, const Pair& rhs) { return lhs = lhs - T(rhs); }
|
||||
template<typename T, EI> auto& operator<<=(T& lhs, const Pair& rhs) { return lhs = lhs << T(rhs); }
|
||||
template<typename T, EI> auto& operator>>=(T& lhs, const Pair& rhs) { return lhs = lhs >> T(rhs); }
|
||||
template<typename T, EI> auto& operator&= (T& lhs, const Pair& rhs) { return lhs = lhs & T(rhs); }
|
||||
template<typename T, EI> auto& operator|= (T& lhs, const Pair& rhs) { return lhs = lhs | T(rhs); }
|
||||
template<typename T, EI> auto& operator^= (T& lhs, const Pair& rhs) { return lhs = lhs ^ T(rhs); }
|
||||
|
||||
template<typename T, EI> auto operator* (const T& lhs, const Pair& rhs) { return Cast(lhs) * Cast(rhs); }
|
||||
template<typename T, EI> auto operator/ (const T& lhs, const Pair& rhs) { return Cast(lhs) / Cast(rhs); }
|
||||
template<typename T, EI> auto operator% (const T& lhs, const Pair& rhs) { return Cast(lhs) % Cast(rhs); }
|
||||
template<typename T, EI> auto operator+ (const T& lhs, const Pair& rhs) { return Cast(lhs) + Cast(rhs); }
|
||||
template<typename T, EI> auto operator- (const T& lhs, const Pair& rhs) { return Cast(lhs) - Cast(rhs); }
|
||||
template<typename T, EI> auto operator<<(const T& lhs, const Pair& rhs) { return Cast(lhs) << Cast(rhs); }
|
||||
template<typename T, EI> auto operator>>(const T& lhs, const Pair& rhs) { return Cast(lhs) >> Cast(rhs); }
|
||||
template<typename T, EI> auto operator& (const T& lhs, const Pair& rhs) { return Cast(lhs) & Cast(rhs); }
|
||||
template<typename T, EI> auto operator| (const T& lhs, const Pair& rhs) { return Cast(lhs) | Cast(rhs); }
|
||||
template<typename T, EI> auto operator^ (const T& lhs, const Pair& rhs) { return Cast(lhs) ^ Cast(rhs); }
|
||||
|
||||
template<typename T, EI> auto operator==(const T& lhs, const Pair& rhs) { return Cast(lhs) == Cast(rhs); }
|
||||
template<typename T, EI> auto operator!=(const T& lhs, const Pair& rhs) { return Cast(lhs) != Cast(rhs); }
|
||||
template<typename T, EI> auto operator>=(const T& lhs, const Pair& rhs) { return Cast(lhs) >= Cast(rhs); }
|
||||
template<typename T, EI> auto operator<=(const T& lhs, const Pair& rhs) { return Cast(lhs) <= Cast(rhs); }
|
||||
template<typename T, EI> auto operator> (const T& lhs, const Pair& rhs) { return Cast(lhs) > Cast(rhs); }
|
||||
template<typename T, EI> auto operator< (const T& lhs, const Pair& rhs) { return Cast(lhs) < Cast(rhs); }
|
||||
|
||||
#undef EI
|
||||
|
||||
template<> struct stringify<Pair> {
|
||||
stringify(Pair source) {
|
||||
char _output[1 + sizeof(Pair) * 3];
|
||||
auto p = (char*)&_output;
|
||||
do {
|
||||
Pair quotient, remainder;
|
||||
div(source, 10, quotient, remainder);
|
||||
*p++ = remainder + '0';
|
||||
source = quotient;
|
||||
} while(source);
|
||||
_size = p - _output;
|
||||
*p = 0;
|
||||
for(int x = _size - 1, y = 0; x >= 0 && y < _size; x--, y++) _data[x] = _output[y];
|
||||
}
|
||||
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> uint { return _size; }
|
||||
char _data[1 + sizeof(Pair) * 3];
|
||||
uint _size;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#undef ConcatenateType
|
||||
#undef DeclareType
|
||||
#undef Pair
|
||||
#undef Type
|
||||
#undef Half
|
||||
#undef Cast
|
|
@ -0,0 +1,61 @@
|
|||
#pragma once
|
||||
|
||||
namespace nall {
|
||||
|
||||
template<typename T, enable_if_t<is_unsigned<T>::value>>
|
||||
inline auto upper(T value) -> T {
|
||||
return value >> sizeof(T) * 4;
|
||||
}
|
||||
|
||||
template<typename T, enable_if_t<is_unsigned<T>::value>>
|
||||
inline auto lower(T value) -> T {
|
||||
static const T Mask = ~T(0) >> sizeof(T) * 4;
|
||||
return value & Mask;
|
||||
}
|
||||
|
||||
template<typename T, typename U, enable_if_t<is_unsigned<T>::value>, enable_if_t<is_unsigned<U>::value>>
|
||||
inline auto mul(T lhs, U rhs) -> uintmax {
|
||||
return lhs * rhs;
|
||||
}
|
||||
|
||||
template<typename T, enable_if_t<is_unsigned<T>::value>>
|
||||
inline auto square(T value) -> uintmax {
|
||||
return value * value;
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
inline auto rol(T lhs, U rhs, enable_if_t<is_unsigned<T>::value>* = 0) -> T {
|
||||
return lhs << rhs | lhs >> sizeof(T) * 8 - rhs;
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
inline auto ror(T lhs, U rhs, enable_if_t<is_unsigned<T>::value>* = 0) -> T {
|
||||
return lhs >> rhs | lhs << sizeof(T) * 8 - rhs;
|
||||
}
|
||||
|
||||
#if INTMAX_BITS >= 128
|
||||
inline auto operator"" _u128(const char* s) -> uint128_t {
|
||||
uint128_t p = 0;
|
||||
if(s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
|
||||
s += 2;
|
||||
while(*s) {
|
||||
auto c = *s++;
|
||||
if(c == '\'');
|
||||
else if(c >= '0' && c <= '9') p = (p << 4) + (c - '0');
|
||||
else if(c >= 'a' && c <= 'f') p = (p << 4) + (c - 'a' + 10);
|
||||
else if(c >= 'A' && c <= 'F') p = (p << 4) + (c - 'A' + 10);
|
||||
else break;
|
||||
}
|
||||
} else {
|
||||
while(*s) {
|
||||
auto c = *s++;
|
||||
if(c == '\'');
|
||||
else if(c >= '0' && c <= '9') p = (p << 3) + (p << 1) + (c - '0');
|
||||
else break;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
#pragma once
|
||||
|
||||
#include <nall/array-view.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
template<typename T> struct array_span : array_view<T> {
|
||||
using type = array_span;
|
||||
using super = array_view<T>;
|
||||
|
||||
inline array_span() {
|
||||
super::_data = nullptr;
|
||||
super::_size = 0;
|
||||
}
|
||||
|
||||
inline array_span(nullptr_t) {
|
||||
super::_data = nullptr;
|
||||
super::_size = 0;
|
||||
}
|
||||
|
||||
inline array_span(void* data, uint64_t size) {
|
||||
super::_data = (T*)data;
|
||||
super::_size = (int)size;
|
||||
}
|
||||
|
||||
inline operator T*() { return (T*)super::operator const T*(); }
|
||||
|
||||
inline auto operator[](uint index) -> T& { return (T&)super::operator[](index); }
|
||||
|
||||
template<typename U = T> inline auto data() -> U* { return (U*)super::_data; }
|
||||
|
||||
inline auto begin() -> iterator<T> { return {(T*)super::_data, (uint)0}; }
|
||||
inline auto end() -> iterator<T> { return {(T*)super::_data, (uint)super::_size}; }
|
||||
|
||||
inline auto rbegin() -> reverse_iterator<T> { return {(T*)super::_data, (uint)super::_size - 1}; }
|
||||
inline auto rend() -> reverse_iterator<T> { return {(T*)super::_data, (uint)-1}; }
|
||||
|
||||
auto write(T value) -> void {
|
||||
operator[](0) = value;
|
||||
super::_data++;
|
||||
super::_size--;
|
||||
}
|
||||
|
||||
auto span(uint offset, uint length) const -> type {
|
||||
#ifdef DEBUG
|
||||
struct out_of_bounds {};
|
||||
if(offset + length >= super::_size) throw out_of_bounds{};
|
||||
#endif
|
||||
return {super::_data + offset, length};
|
||||
}
|
||||
|
||||
//array_span<uint8_t> specializations
|
||||
template<typename U> auto writel(U value, uint size) -> void;
|
||||
template<typename U> auto writem(U value, uint size) -> void;
|
||||
template<typename U> auto writevn(U value, uint size) -> void;
|
||||
template<typename U> auto writevi(U value, uint size) -> void;
|
||||
};
|
||||
|
||||
//array_span<uint8_t>
|
||||
|
||||
template<> inline auto array_span<uint8_t>::write(uint8_t value) -> void {
|
||||
operator[](0) = value;
|
||||
_data++;
|
||||
_size--;
|
||||
}
|
||||
|
||||
template<> template<typename U> inline auto array_span<uint8_t>::writel(U value, uint size) -> void {
|
||||
for(uint byte : range(size)) write(value >> byte * 8);
|
||||
}
|
||||
|
||||
template<> template<typename U> inline auto array_span<uint8_t>::writem(U value, uint size) -> void {
|
||||
for(uint byte : reverse(range(size))) write(value >> byte * 8);
|
||||
}
|
||||
|
||||
template<> template<typename U> inline auto array_span<uint8_t>::writevn(U value, uint size) -> void {
|
||||
while(true) {
|
||||
auto byte = value & 0x7f;
|
||||
value >>= 7;
|
||||
if(value == 0) return write(0x80 | byte);
|
||||
write(byte);
|
||||
value--;
|
||||
}
|
||||
}
|
||||
|
||||
template<> template<typename U> inline auto array_span<uint8_t>::writevi(U value, uint size) -> void {
|
||||
bool negate = value < 0;
|
||||
if(negate) value = ~value;
|
||||
value = value << 1 | negate;
|
||||
writevn(value);
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue