New! With more games than the 32X! And better sounding ones too!
This commit is contained in:
parent
41fdb3a140
commit
bd57871171
|
@ -1,226 +1,227 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
/// <summary>
|
||||
/// This class holds a converter for BizHawk SystemId (which is a simple <see cref="string"/>
|
||||
/// It allows you to convert it to a <see cref="CoreSystem"/> value and vice versa
|
||||
/// </summary>
|
||||
/// <remarks>I made it this way just in case one day we need it for WPF (DependencyProperty binding). Just uncomment :IValueConverter implementation
|
||||
/// I didn't implemented it because of mono compatibility
|
||||
/// </remarks>
|
||||
public sealed class BizHawkSystemIdToEnumConverter //:IValueConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Convert BizHawk SystemId <see cref="string"/> to <see cref="CoreSystem"/> value
|
||||
/// </summary>
|
||||
/// <param name="value"><see cref="string"/> you want to convert</param>
|
||||
/// <param name="targetType">The type of the binding target property</param>
|
||||
/// <param name="parameter">The converter parameter to use; null in our case</param>
|
||||
/// <param name="cultureInfo">The culture to use in the converter</param>
|
||||
/// <returns>A <see cref="CoreSystem"/> that is equivalent to BizHawk SystemId <see cref="string"/></returns>
|
||||
/// <exception cref="IndexOutOfRangeException">Thrown when SystemId hasn't been found</exception>
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo cultureInfo)
|
||||
{
|
||||
switch ((string)value)
|
||||
{
|
||||
case "AppleII":
|
||||
return CoreSystem.AppleII;
|
||||
|
||||
case "A26":
|
||||
return CoreSystem.Atari2600;
|
||||
|
||||
case "A78":
|
||||
return CoreSystem.Atari2600;
|
||||
|
||||
case "A7800":
|
||||
return CoreSystem.Atari7800;
|
||||
|
||||
case "Coleco":
|
||||
return CoreSystem.ColecoVision;
|
||||
|
||||
case "C64":
|
||||
return CoreSystem.Commodore64;
|
||||
|
||||
case "DGB":
|
||||
return CoreSystem.DualGameBoy;
|
||||
|
||||
case "GB":
|
||||
return CoreSystem.GameBoy;
|
||||
|
||||
case "GBA":
|
||||
return CoreSystem.GameBoyAdvance;
|
||||
|
||||
case "GEN":
|
||||
return CoreSystem.Genesis;
|
||||
|
||||
case "INTV":
|
||||
return CoreSystem.Intellivision;
|
||||
|
||||
case "Libretro":
|
||||
return CoreSystem.Libretro;
|
||||
|
||||
case "Lynx":
|
||||
return CoreSystem.Lynx;
|
||||
|
||||
case "SMS":
|
||||
return CoreSystem.MasterSystem;
|
||||
|
||||
case "NES":
|
||||
return CoreSystem.NES;
|
||||
|
||||
case "N64":
|
||||
return CoreSystem.Nintendo64;
|
||||
|
||||
case "NULL":
|
||||
return CoreSystem.Null;
|
||||
|
||||
case "PCE":
|
||||
case "PCECD":
|
||||
case "SGX":
|
||||
return CoreSystem.PCEngine;
|
||||
|
||||
case "PSX":
|
||||
return CoreSystem.Playstation;
|
||||
|
||||
case "PSP":
|
||||
return CoreSystem.PSP;
|
||||
|
||||
case "SAT":
|
||||
return CoreSystem.Saturn;
|
||||
|
||||
case "SNES":
|
||||
return CoreSystem.SNES;
|
||||
|
||||
case "TI83":
|
||||
return CoreSystem.TI83;
|
||||
|
||||
case "WSWAN":
|
||||
return CoreSystem.WonderSwan;
|
||||
|
||||
case "VB":
|
||||
case "NGP":
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
/// <summary>
|
||||
/// This class holds a converter for BizHawk SystemId (which is a simple <see cref="string"/>
|
||||
/// It allows you to convert it to a <see cref="CoreSystem"/> value and vice versa
|
||||
/// </summary>
|
||||
/// <remarks>I made it this way just in case one day we need it for WPF (DependencyProperty binding). Just uncomment :IValueConverter implementation
|
||||
/// I didn't implemented it because of mono compatibility
|
||||
/// </remarks>
|
||||
public sealed class BizHawkSystemIdToEnumConverter //:IValueConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Convert BizHawk SystemId <see cref="string"/> to <see cref="CoreSystem"/> value
|
||||
/// </summary>
|
||||
/// <param name="value"><see cref="string"/> you want to convert</param>
|
||||
/// <param name="targetType">The type of the binding target property</param>
|
||||
/// <param name="parameter">The converter parameter to use; null in our case</param>
|
||||
/// <param name="cultureInfo">The culture to use in the converter</param>
|
||||
/// <returns>A <see cref="CoreSystem"/> that is equivalent to BizHawk SystemId <see cref="string"/></returns>
|
||||
/// <exception cref="IndexOutOfRangeException">Thrown when SystemId hasn't been found</exception>
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo cultureInfo)
|
||||
{
|
||||
switch ((string)value)
|
||||
{
|
||||
case "AppleII":
|
||||
return CoreSystem.AppleII;
|
||||
|
||||
case "A26":
|
||||
return CoreSystem.Atari2600;
|
||||
|
||||
case "A78":
|
||||
return CoreSystem.Atari2600;
|
||||
|
||||
case "A7800":
|
||||
return CoreSystem.Atari7800;
|
||||
|
||||
case "Coleco":
|
||||
return CoreSystem.ColecoVision;
|
||||
|
||||
case "C64":
|
||||
return CoreSystem.Commodore64;
|
||||
|
||||
case "DGB":
|
||||
return CoreSystem.DualGameBoy;
|
||||
|
||||
case "GB":
|
||||
return CoreSystem.GameBoy;
|
||||
|
||||
case "GBA":
|
||||
return CoreSystem.GameBoyAdvance;
|
||||
|
||||
case "GEN":
|
||||
return CoreSystem.Genesis;
|
||||
|
||||
case "INTV":
|
||||
return CoreSystem.Intellivision;
|
||||
|
||||
case "Libretro":
|
||||
return CoreSystem.Libretro;
|
||||
|
||||
case "Lynx":
|
||||
return CoreSystem.Lynx;
|
||||
|
||||
case "SMS":
|
||||
return CoreSystem.MasterSystem;
|
||||
|
||||
case "NES":
|
||||
return CoreSystem.NES;
|
||||
|
||||
case "N64":
|
||||
return CoreSystem.Nintendo64;
|
||||
|
||||
case "NULL":
|
||||
return CoreSystem.Null;
|
||||
|
||||
case "PCE":
|
||||
case "PCECD":
|
||||
case "SGX":
|
||||
return CoreSystem.PCEngine;
|
||||
|
||||
case "PSX":
|
||||
return CoreSystem.Playstation;
|
||||
|
||||
case "PSP":
|
||||
return CoreSystem.PSP;
|
||||
|
||||
case "SAT":
|
||||
return CoreSystem.Saturn;
|
||||
|
||||
case "SNES":
|
||||
return CoreSystem.SNES;
|
||||
|
||||
case "TI83":
|
||||
return CoreSystem.TI83;
|
||||
|
||||
case "WSWAN":
|
||||
return CoreSystem.WonderSwan;
|
||||
|
||||
case "VB":
|
||||
case "NGP":
|
||||
case "DNGP":
|
||||
case "O2":
|
||||
case "SGB":
|
||||
return 0; // like I give a shit
|
||||
|
||||
default:
|
||||
throw new IndexOutOfRangeException(string.Format("{0} is missing in convert list", value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Convert BizHawk SystemId <see cref="string"/> to <see cref="CoreSystem"/> value
|
||||
/// </summary>
|
||||
/// <param name="value"><see cref="string"/> you want to convert</param>
|
||||
/// <returns>A <see cref="CoreSystem"/> that is equivalent to BizHawk SystemId <see cref="string"/></returns>
|
||||
/// <exception cref="IndexOutOfRangeException">Thrown when SystemId hasn't been found</exception>
|
||||
public CoreSystem Convert(string value)
|
||||
{
|
||||
return (CoreSystem)Convert(value, null, null, CultureInfo.CurrentCulture);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Convert a <see cref="CoreSystem"/> value to BizHawk SystemId <see cref="string"/>
|
||||
/// </summary>
|
||||
/// <param name="value"><see cref="CoreSystem"/> you want to convert</param>
|
||||
/// <param name="targetType">The type of the binding target property</param>
|
||||
/// <param name="parameter">The converter parameter to use; null in our case</param>
|
||||
/// <param name="cultureInfo">The culture to use in the converter</param>
|
||||
/// <returns>A <see cref="string"/> that is used by BizHawk SystemId</returns>
|
||||
/// <exception cref="IndexOutOfRangeException">Thrown when <see cref="CoreSystem"/> hasn't been found</exception>
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo cultureInfo)
|
||||
{
|
||||
switch ((CoreSystem)value)
|
||||
{
|
||||
case CoreSystem.AppleII:
|
||||
return "AppleII";
|
||||
|
||||
case CoreSystem.Atari2600:
|
||||
return "A26";
|
||||
|
||||
case CoreSystem.Atari7800:
|
||||
return "A78";
|
||||
|
||||
case CoreSystem.ColecoVision:
|
||||
return "Coleco";
|
||||
|
||||
case CoreSystem.Commodore64:
|
||||
return "C64";
|
||||
|
||||
case CoreSystem.DualGameBoy:
|
||||
return "DGB";
|
||||
|
||||
case CoreSystem.GameBoy:
|
||||
return "GB";
|
||||
|
||||
case CoreSystem.GameBoyAdvance:
|
||||
return "GBA";
|
||||
|
||||
case CoreSystem.Genesis:
|
||||
return "GEN";
|
||||
|
||||
case CoreSystem.Intellivision:
|
||||
return "INTV";
|
||||
|
||||
case CoreSystem.Libretro:
|
||||
return "Libretro";
|
||||
|
||||
case CoreSystem.Lynx:
|
||||
return "Lynx";
|
||||
|
||||
case CoreSystem.MasterSystem:
|
||||
return "SMS";
|
||||
|
||||
case CoreSystem.NES:
|
||||
return "NES";
|
||||
|
||||
case CoreSystem.Nintendo64:
|
||||
return "N64";
|
||||
|
||||
case CoreSystem.Null:
|
||||
return "NULL";
|
||||
|
||||
case CoreSystem.PCEngine:
|
||||
return "PCE";
|
||||
|
||||
case CoreSystem.Playstation:
|
||||
return "PSX";
|
||||
|
||||
case CoreSystem.PSP:
|
||||
return "PSP";
|
||||
|
||||
case CoreSystem.Saturn:
|
||||
return "SAT";
|
||||
|
||||
case CoreSystem.SNES:
|
||||
return "SNES";
|
||||
|
||||
case CoreSystem.TI83:
|
||||
return "TI83";
|
||||
|
||||
case CoreSystem.WonderSwan:
|
||||
return "WSWAN";
|
||||
|
||||
default:
|
||||
throw new IndexOutOfRangeException(string.Format("{0} is missing in convert list", value.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Convert a <see cref="CoreSystem"/> value to BizHawk SystemId <see cref="string"/>
|
||||
/// </summary>
|
||||
/// <param name="value"><see cref="CoreSystem"/> you want to convert</param>
|
||||
/// <returns>A <see cref="string"/> that is used by BizHawk SystemId</returns>
|
||||
/// <exception cref="IndexOutOfRangeException">Thrown when <see cref="CoreSystem"/> hasn't been found</exception>
|
||||
public string ConvertBack(CoreSystem value)
|
||||
{
|
||||
return (string)ConvertBack(value, null, null, CultureInfo.CurrentCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
case "SGB":
|
||||
case "UZE":
|
||||
return 0; // like I give a shit
|
||||
|
||||
default:
|
||||
throw new IndexOutOfRangeException(string.Format("{0} is missing in convert list", value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Convert BizHawk SystemId <see cref="string"/> to <see cref="CoreSystem"/> value
|
||||
/// </summary>
|
||||
/// <param name="value"><see cref="string"/> you want to convert</param>
|
||||
/// <returns>A <see cref="CoreSystem"/> that is equivalent to BizHawk SystemId <see cref="string"/></returns>
|
||||
/// <exception cref="IndexOutOfRangeException">Thrown when SystemId hasn't been found</exception>
|
||||
public CoreSystem Convert(string value)
|
||||
{
|
||||
return (CoreSystem)Convert(value, null, null, CultureInfo.CurrentCulture);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Convert a <see cref="CoreSystem"/> value to BizHawk SystemId <see cref="string"/>
|
||||
/// </summary>
|
||||
/// <param name="value"><see cref="CoreSystem"/> you want to convert</param>
|
||||
/// <param name="targetType">The type of the binding target property</param>
|
||||
/// <param name="parameter">The converter parameter to use; null in our case</param>
|
||||
/// <param name="cultureInfo">The culture to use in the converter</param>
|
||||
/// <returns>A <see cref="string"/> that is used by BizHawk SystemId</returns>
|
||||
/// <exception cref="IndexOutOfRangeException">Thrown when <see cref="CoreSystem"/> hasn't been found</exception>
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo cultureInfo)
|
||||
{
|
||||
switch ((CoreSystem)value)
|
||||
{
|
||||
case CoreSystem.AppleII:
|
||||
return "AppleII";
|
||||
|
||||
case CoreSystem.Atari2600:
|
||||
return "A26";
|
||||
|
||||
case CoreSystem.Atari7800:
|
||||
return "A78";
|
||||
|
||||
case CoreSystem.ColecoVision:
|
||||
return "Coleco";
|
||||
|
||||
case CoreSystem.Commodore64:
|
||||
return "C64";
|
||||
|
||||
case CoreSystem.DualGameBoy:
|
||||
return "DGB";
|
||||
|
||||
case CoreSystem.GameBoy:
|
||||
return "GB";
|
||||
|
||||
case CoreSystem.GameBoyAdvance:
|
||||
return "GBA";
|
||||
|
||||
case CoreSystem.Genesis:
|
||||
return "GEN";
|
||||
|
||||
case CoreSystem.Intellivision:
|
||||
return "INTV";
|
||||
|
||||
case CoreSystem.Libretro:
|
||||
return "Libretro";
|
||||
|
||||
case CoreSystem.Lynx:
|
||||
return "Lynx";
|
||||
|
||||
case CoreSystem.MasterSystem:
|
||||
return "SMS";
|
||||
|
||||
case CoreSystem.NES:
|
||||
return "NES";
|
||||
|
||||
case CoreSystem.Nintendo64:
|
||||
return "N64";
|
||||
|
||||
case CoreSystem.Null:
|
||||
return "NULL";
|
||||
|
||||
case CoreSystem.PCEngine:
|
||||
return "PCE";
|
||||
|
||||
case CoreSystem.Playstation:
|
||||
return "PSX";
|
||||
|
||||
case CoreSystem.PSP:
|
||||
return "PSP";
|
||||
|
||||
case CoreSystem.Saturn:
|
||||
return "SAT";
|
||||
|
||||
case CoreSystem.SNES:
|
||||
return "SNES";
|
||||
|
||||
case CoreSystem.TI83:
|
||||
return "TI83";
|
||||
|
||||
case CoreSystem.WonderSwan:
|
||||
return "WSWAN";
|
||||
|
||||
default:
|
||||
throw new IndexOutOfRangeException(string.Format("{0} is missing in convert list", value.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Convert a <see cref="CoreSystem"/> value to BizHawk SystemId <see cref="string"/>
|
||||
/// </summary>
|
||||
/// <param name="value"><see cref="CoreSystem"/> you want to convert</param>
|
||||
/// <returns>A <see cref="string"/> that is used by BizHawk SystemId</returns>
|
||||
/// <exception cref="IndexOutOfRangeException">Thrown when <see cref="CoreSystem"/> hasn't been found</exception>
|
||||
public string ConvertBack(CoreSystem value)
|
||||
{
|
||||
return (string)ConvertBack(value, null, null, CultureInfo.CurrentCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -344,6 +344,10 @@ namespace BizHawk.Emulation.Common
|
|||
case ".O2":
|
||||
game.System = "O2";
|
||||
break;
|
||||
|
||||
case ".UZE":
|
||||
game.System = "UZE";
|
||||
break;
|
||||
}
|
||||
|
||||
game.Name = Path.GetFileNameWithoutExtension(fileName)?.Replace('_', ' ');
|
||||
|
|
|
@ -407,6 +407,8 @@
|
|||
<Compile Include="Consoles\Atari\lynx\Lynx.IVideoProvider.cs">
|
||||
<DependentUpon>Lynx.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Belogic\LibUzem.cs" />
|
||||
<Compile Include="Consoles\Belogic\Uzem.cs" />
|
||||
<Compile Include="Consoles\Coleco\ColecoVision.cs" />
|
||||
<Compile Include="Consoles\Coleco\ColecoVision.IDebuggable.cs">
|
||||
<DependentUpon>ColecoVision.cs</DependentUpon>
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
using BizHawk.Common.BizInvoke;
|
||||
using BizHawk.Emulation.Cores.Waterbox;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Belogic
|
||||
{
|
||||
public abstract class LibUzem : LibWaterboxCore
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public new class FrameInfo : LibWaterboxCore.FrameInfo
|
||||
{
|
||||
public int ButtonsP1;
|
||||
public int ButtonsP2;
|
||||
public int ButtonsConsole;
|
||||
}
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract bool Init();
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract bool MouseEnabled();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Waterbox;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Belogic
|
||||
{
|
||||
[CoreAttributes("uzem", "David Etherton", true, false, "", "", false)]
|
||||
public class Uzem : WaterboxCore
|
||||
{
|
||||
private LibUzem _uze;
|
||||
private bool _mouseEnabled;
|
||||
|
||||
[CoreConstructor("UZE")]
|
||||
public Uzem(CoreComm comm, byte[] rom)
|
||||
:base(comm, new Configuration
|
||||
{
|
||||
DefaultWidth = 720,
|
||||
DefaultHeight = 224,
|
||||
MaxWidth = 720,
|
||||
MaxHeight = 224,
|
||||
MaxSamples = 4096,
|
||||
SystemId = "UZE",
|
||||
DefaultFpsNumerator = 28618182,
|
||||
DefaultFpsDenominator = 476840
|
||||
})
|
||||
{
|
||||
_uze = PreInit<LibUzem>(new PeRunnerOptions
|
||||
{
|
||||
Filename = "uzem.wbx",
|
||||
SbrkHeapSizeKB = 4,
|
||||
SealedHeapSizeKB = 4,
|
||||
InvisibleHeapSizeKB = 4,
|
||||
MmapHeapSizeKB = 4,
|
||||
PlainHeapSizeKB = 4,
|
||||
});
|
||||
|
||||
_exe.AddReadonlyFile(rom, "romfile");
|
||||
if (!_uze.Init())
|
||||
throw new InvalidOperationException("Core rejected the rom!");
|
||||
_mouseEnabled = _uze.MouseEnabled();
|
||||
_exe.RemoveReadonlyFile("romfile");
|
||||
|
||||
PostInit();
|
||||
}
|
||||
|
||||
private static readonly ControllerDefinition TwoPads = new ControllerDefinition
|
||||
{
|
||||
Name = "SNES Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
"P1 Up", "P1 Left", "P1 Right", "P1 Down", "P1 Select", "P1 Start", "P1 X", "P1 A", "P1 B", "P1 Y", "P1 R", "P1 L",
|
||||
"P2 Up", "P2 Left", "P2 Right", "P2 Down", "P2 Select", "P2 Start", "P2 X", "P2 A", "P2 B", "P2 Y", "P2 R", "P2 L",
|
||||
"Power"
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition Mouse = new ControllerDefinition
|
||||
{
|
||||
Name = "SNES Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
"P1 Mouse Left", "P1 Mouse Right", "Power"
|
||||
},
|
||||
FloatControls =
|
||||
{
|
||||
"P1 Mouse X", "P1 Mouse Y"
|
||||
},
|
||||
FloatRanges =
|
||||
{
|
||||
new[] { -127f, 0f, 127f },
|
||||
new[] { -127f, 0f, 127f }
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly string[] PadBits =
|
||||
{
|
||||
"B", "Y", "Select", "Start", "Up", "Down", "Left", "Right", "A", "X", "L", "R"
|
||||
};
|
||||
|
||||
private static int EncodePad(IController c, int p)
|
||||
{
|
||||
int ret = 0;
|
||||
int val = 1;
|
||||
int idx = 0;
|
||||
foreach (var s in PadBits)
|
||||
{
|
||||
if (c.IsPressed("P" + p + " " + PadBits[idx++]))
|
||||
ret |= val;
|
||||
val <<= 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static int EncodeDelta(float value)
|
||||
{
|
||||
int v = (int)value;
|
||||
if (v > 127)
|
||||
v = 127;
|
||||
if (v < -127)
|
||||
v = -127;
|
||||
|
||||
int ret = 0;
|
||||
if (v < 0)
|
||||
{
|
||||
ret |= 1;
|
||||
v = -v;
|
||||
}
|
||||
|
||||
int mask = 64;
|
||||
int bit = 2;
|
||||
while (mask != 0)
|
||||
{
|
||||
if ((v & mask) != 0)
|
||||
ret |= bit;
|
||||
mask >>= 1;
|
||||
bit <<= 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override ControllerDefinition ControllerDefinition => _mouseEnabled ? Mouse : TwoPads;
|
||||
|
||||
protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound)
|
||||
{
|
||||
var ret = new LibUzem.FrameInfo();
|
||||
if (_mouseEnabled)
|
||||
{
|
||||
ret.ButtonsP1 = EncodeDelta(controller.GetFloat("P1 X"))
|
||||
| EncodeDelta(controller.GetFloat("P1 Y"))
|
||||
| 0x8000;
|
||||
if (controller.IsPressed("P1 Mouse Left"))
|
||||
ret.ButtonsP1 |= 0x200;
|
||||
if (controller.IsPressed("P1 Mouse Right"))
|
||||
ret.ButtonsP1 |= 0x100;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.ButtonsP1 = EncodePad(controller, 1);
|
||||
ret.ButtonsP2 = EncodePad(controller, 2);
|
||||
}
|
||||
if (controller.IsPressed("Power"))
|
||||
ret.ButtonsConsole = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override int VirtualHeight => 448; // TODO: It's not quite this, NTSC and such
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"files.associations": {
|
||||
"ios": "cpp",
|
||||
"xiosbase": "cpp",
|
||||
"queue": "cpp"
|
||||
},
|
||||
"editor.tabSize": 4,
|
||||
"editor.insertSpaces": false,
|
||||
"editor.detectIndentation": false
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
CC = x86_64-nt64-midipix-g++
|
||||
|
||||
CCFLAGS:= -I. -I../emulibc \
|
||||
-Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=implicit-function-declaration \
|
||||
-Wno-reorder \
|
||||
-std=c++0x -fomit-frame-pointer -fvisibility=hidden -fno-exceptions -fno-rtti \
|
||||
-DNOGDB \
|
||||
-O3 -flto
|
||||
|
||||
TARGET = uzem.wbx
|
||||
|
||||
LDFLAGS = -Wl,--dynamicbase,--export-all-symbols
|
||||
|
||||
ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||
SRCS:=$(shell find $(ROOT_DIR) -type f -name '*.cpp')
|
||||
OBJ_DIR:=$(ROOT_DIR)/obj
|
||||
|
||||
_OBJS:=$(SRCS:.cpp=.o)
|
||||
OBJS:=$(patsubst $(ROOT_DIR)%,$(OBJ_DIR)%,$(_OBJS))
|
||||
|
||||
$(OBJ_DIR)/%.o: %.cpp
|
||||
@mkdir -p $(@D)
|
||||
@$(CC) -c -o $@ $< $(CCFLAGS)
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
.PHONY: clean all
|
||||
|
||||
$(TARGET).in: $(OBJS)
|
||||
@$(CC) -o $@ $(LDFLAGS) $(CCFLAGS) $(OBJS) ../emulibc/libemuhost.so
|
||||
|
||||
$(TARGET): $(TARGET).in
|
||||
strip $< -o $@ -R /4 -R /14 -R /29 -R /41 -R /55 -R /67 -R /78 -R /89 -R /104
|
||||
# cp $< $@
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJ_DIR)
|
||||
rm -f $(TARGET).in
|
||||
rm -f $(TARGET)
|
||||
|
||||
print-%:
|
||||
@echo $* = $($*)
|
||||
|
||||
#install:
|
||||
# $(CP) $(TARGET) $(DEST_$(ARCH))
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,697 @@
|
|||
/*
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2008-2016 by
|
||||
David Etherton, Eric Anderton, Alec Bourque (Uze), Filipe Rinaldi,
|
||||
Sandor Zsuga (Jubatian), Matt Pandina (Artcfox)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include <queue>
|
||||
#include <cstring>
|
||||
|
||||
// Video: Offset of display on the emulator's surface
|
||||
// Syncronized with the kernel, this value now results in the image
|
||||
// being perfectly centered in both the emulator and a real TV
|
||||
#define VIDEO_LEFT_EDGE 168U
|
||||
// Video: Display width; the width of the emulator's output (before any
|
||||
// scaling applied) and video capturing
|
||||
#define VIDEO_DISP_WIDTH 720U
|
||||
|
||||
//Uzebox keyboard defines
|
||||
#define KB_STOP 0
|
||||
#define KB_TX_START 1
|
||||
#define KB_TX_READY 2
|
||||
|
||||
#define KB_SEND_KEY 0x00
|
||||
#define KB_SEND_END 0x01
|
||||
#define KB_SEND_DEVICE_ID 0x02
|
||||
#define KB_SEND_FIRMWARE_REV 0x03
|
||||
#define KB_RESET 0x7f
|
||||
|
||||
// Joysticks
|
||||
#define MAX_JOYSTICKS 2
|
||||
#define NUM_JOYSTICK_BUTTONS 8
|
||||
#define MAX_JOYSTICK_AXES 8
|
||||
#define MAX_JOYSTICK_HATS 8
|
||||
|
||||
#define JOY_SNES_X 0
|
||||
#define JOY_SNES_A 1
|
||||
#define JOY_SNES_B 2
|
||||
#define JOY_SNES_Y 3
|
||||
#define JOY_SNES_LSH 6
|
||||
#define JOY_SNES_RSH 7
|
||||
#define JOY_SNES_SELECT 8
|
||||
#define JOY_SNES_START 9
|
||||
|
||||
#define JOY_DIR_UP 1
|
||||
#define JOY_DIR_RIGHT 2
|
||||
#define JOY_DIR_DOWN 4
|
||||
#define JOY_DIR_LEFT 8
|
||||
#define JOY_DIR_COUNT 4
|
||||
#define JOY_AXIS_UNUSED -1
|
||||
|
||||
#define JOY_MASK_UP 0x11111111
|
||||
#define JOY_MASK_RIGHT 0x22222222
|
||||
#define JOY_MASK_DOWN 0x44444444
|
||||
#define JOY_MASK_LEFT 0x88888888
|
||||
|
||||
#ifndef JOY_ANALOG_DEADZONE
|
||||
#define JOY_ANALOG_DEADZONE 4096
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
// don't whine about sprintf and fopen.
|
||||
// could switch to sprintf_s but that's not standard.
|
||||
#pragma warning(disable : 4996)
|
||||
#endif
|
||||
|
||||
// 644 Overview: http://www.atmel.com/dyn/resources/prod_documents/doc2593.pdf
|
||||
// AVR8 insn set: http://www.atmel.com/dyn/resources/prod_documents/doc0856.pdf
|
||||
|
||||
enum
|
||||
{
|
||||
NES_A,
|
||||
NES_B,
|
||||
PAD_SELECT,
|
||||
PAD_START,
|
||||
PAD_UP,
|
||||
PAD_DOWN,
|
||||
PAD_LEFT,
|
||||
PAD_RIGHT
|
||||
};
|
||||
enum
|
||||
{
|
||||
SNES_B,
|
||||
SNES_Y,
|
||||
SNES_A = 8,
|
||||
SNES_X,
|
||||
SNES_LSH,
|
||||
SNES_RSH
|
||||
};
|
||||
|
||||
#if 1 // 644P
|
||||
const unsigned eepromSize = 2048;
|
||||
const unsigned sramSize = 4096;
|
||||
const unsigned progSize = 65536;
|
||||
#else // 1284P
|
||||
const unsigned eepromSize = 4096;
|
||||
const unsigned sramSize = 16384;
|
||||
const unsigned progSize = 131072;
|
||||
#endif
|
||||
|
||||
#define IOBASE 32
|
||||
#define SRAMBASE 256
|
||||
|
||||
namespace ports
|
||||
{
|
||||
enum
|
||||
{
|
||||
PINA,
|
||||
DDRA,
|
||||
PORTA,
|
||||
PINB,
|
||||
DDRB,
|
||||
PORTB,
|
||||
PINC,
|
||||
DDRC,
|
||||
PORTC,
|
||||
PIND,
|
||||
DDRD,
|
||||
PORTD,
|
||||
res2C,
|
||||
res2D,
|
||||
res2E,
|
||||
res2F,
|
||||
res30,
|
||||
res31,
|
||||
res32,
|
||||
res33,
|
||||
res34,
|
||||
TIFR0,
|
||||
TIFR1,
|
||||
TIFR2,
|
||||
res38,
|
||||
res39,
|
||||
res3A,
|
||||
PCIFR,
|
||||
EIFR,
|
||||
EIMSK,
|
||||
GPIOR0,
|
||||
EECR,
|
||||
EEDR,
|
||||
EEARL,
|
||||
EEARH,
|
||||
GTCCR,
|
||||
TCCR0A,
|
||||
TCCR0B,
|
||||
TCNT0,
|
||||
OCR0A,
|
||||
OCR0B,
|
||||
res49,
|
||||
GPIOR1,
|
||||
GPIOR2,
|
||||
SPCR,
|
||||
SPSR,
|
||||
SPDR,
|
||||
res4f,
|
||||
ACSR,
|
||||
OCDR,
|
||||
res52,
|
||||
SMCR,
|
||||
MCUSR,
|
||||
MCUCR,
|
||||
res56,
|
||||
SPMCSR,
|
||||
res58,
|
||||
res59,
|
||||
res5A,
|
||||
res5B,
|
||||
res5C,
|
||||
SPL,
|
||||
SPH,
|
||||
SREG,
|
||||
WDTCSR,
|
||||
CLKPR,
|
||||
res62,
|
||||
res63,
|
||||
PRR,
|
||||
res65,
|
||||
OSCCAL,
|
||||
res67,
|
||||
PCICR,
|
||||
EICRA,
|
||||
res6a,
|
||||
PCMSK0,
|
||||
PCMSK1,
|
||||
PCMSK2,
|
||||
TIMSK0,
|
||||
TIMSK1,
|
||||
TIMSK2,
|
||||
res71,
|
||||
res72,
|
||||
PCMSK3,
|
||||
res74,
|
||||
res75,
|
||||
res76,
|
||||
res77,
|
||||
ADCL,
|
||||
ADCH,
|
||||
ADCSRA,
|
||||
ADCSRB,
|
||||
ADMUX,
|
||||
res7d,
|
||||
DIDR0,
|
||||
DIDR1,
|
||||
TCCR1A,
|
||||
TCCR1B,
|
||||
TCCR1C,
|
||||
res83,
|
||||
TCNT1L,
|
||||
TCNT1H,
|
||||
ICR1L,
|
||||
ICR1H,
|
||||
OCR1AL,
|
||||
OCR1AH,
|
||||
OCR1BL,
|
||||
OCR1BH,
|
||||
res8c,
|
||||
res8d,
|
||||
res8e,
|
||||
res8f,
|
||||
res90,
|
||||
res91,
|
||||
res92,
|
||||
res93,
|
||||
res94,
|
||||
res95,
|
||||
res96,
|
||||
res97,
|
||||
res98,
|
||||
res99,
|
||||
res9a,
|
||||
res9b,
|
||||
res9c,
|
||||
res9d,
|
||||
res9e,
|
||||
res9f,
|
||||
resa0,
|
||||
resa1,
|
||||
resa2,
|
||||
resa3,
|
||||
resa4,
|
||||
resa5,
|
||||
resa6,
|
||||
resa7,
|
||||
resa8,
|
||||
resa9,
|
||||
resaa,
|
||||
resab,
|
||||
resac,
|
||||
resad,
|
||||
resae,
|
||||
resaf,
|
||||
TCCR2A,
|
||||
TCCR2B,
|
||||
TCNT2,
|
||||
OCR2A,
|
||||
OCR2B,
|
||||
resb5,
|
||||
ASSR,
|
||||
resb7,
|
||||
TWBR,
|
||||
TWSR,
|
||||
TWAR,
|
||||
TWDR,
|
||||
TWCR,
|
||||
TWAMR,
|
||||
resbe,
|
||||
resbf,
|
||||
UCSR0A,
|
||||
UCSR0B,
|
||||
UCSR0C,
|
||||
resc3,
|
||||
UBRR0L,
|
||||
UBRR0H,
|
||||
UDR0,
|
||||
resc7,
|
||||
resc8,
|
||||
resc9,
|
||||
resca,
|
||||
rescb,
|
||||
rescc,
|
||||
rescd,
|
||||
resce,
|
||||
rescf,
|
||||
resd0,
|
||||
resd1,
|
||||
resd2,
|
||||
resd3,
|
||||
resd4,
|
||||
resd5,
|
||||
resd6,
|
||||
resd7,
|
||||
resd8,
|
||||
resd9,
|
||||
resda,
|
||||
resdb,
|
||||
resdc,
|
||||
resdd,
|
||||
resde,
|
||||
resdf,
|
||||
rese0,
|
||||
rese1,
|
||||
rese2,
|
||||
rese3,
|
||||
rese4,
|
||||
rese5,
|
||||
rese6,
|
||||
rese7,
|
||||
rese8,
|
||||
rese9,
|
||||
resea,
|
||||
reseb,
|
||||
resec,
|
||||
resed,
|
||||
resee,
|
||||
resef,
|
||||
resf0,
|
||||
resf1,
|
||||
resf2,
|
||||
resf3,
|
||||
resf4,
|
||||
resf5,
|
||||
resf6,
|
||||
resf7,
|
||||
resf8,
|
||||
resf9,
|
||||
resfa,
|
||||
resfb,
|
||||
resfc,
|
||||
resfd,
|
||||
resfe,
|
||||
resff
|
||||
};
|
||||
}
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef int8_t s8;
|
||||
typedef uint16_t u16;
|
||||
typedef int16_t s16;
|
||||
typedef uint32_t u32;
|
||||
typedef int32_t s32;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
s16 arg2;
|
||||
u8 arg1;
|
||||
u8 opNum;
|
||||
} __attribute__((packed)) instructionDecode_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 opNum;
|
||||
char opName[32];
|
||||
u8 arg1Type;
|
||||
u8 arg1Mul;
|
||||
u8 arg1Offset;
|
||||
u8 arg1Neg;
|
||||
u8 arg2Type;
|
||||
u8 arg2Mul;
|
||||
u8 arg2Offset;
|
||||
u8 arg2Neg;
|
||||
u8 words;
|
||||
u8 clocks;
|
||||
u16 mask;
|
||||
u16 arg1Mask;
|
||||
u16 arg2Mask;
|
||||
} instructionList_t;
|
||||
|
||||
using namespace std;
|
||||
|
||||
//SPI state machine states
|
||||
enum
|
||||
{
|
||||
SPI_IDLE_STATE,
|
||||
SPI_ARG_X_LO,
|
||||
SPI_ARG_X_HI,
|
||||
SPI_ARG_Y_LO,
|
||||
SPI_ARG_Y_HI,
|
||||
SPI_ARG_CRC,
|
||||
SPI_RESPOND_SINGLE,
|
||||
SPI_RESPOND_MULTI,
|
||||
SPI_READ_SINGLE_BLOCK,
|
||||
SPI_READ_MULTIPLE_BLOCK,
|
||||
SPI_WRITE_SINGLE,
|
||||
SPI_WRITE_SINGLE_BLOCK,
|
||||
SPI_RESPOND_R1,
|
||||
SPI_RESPOND_R1B,
|
||||
SPI_RESPOND_R2,
|
||||
SPI_RESPOND_R3,
|
||||
SPI_RESPOND_R7,
|
||||
};
|
||||
|
||||
struct SDPartitionEntry
|
||||
{
|
||||
u8 state;
|
||||
u8 startHead;
|
||||
u16 startCylinder;
|
||||
u8 type;
|
||||
u8 endHead;
|
||||
u16 endCylinder;
|
||||
u32 sectorOffset;
|
||||
u32 sectorCount;
|
||||
};
|
||||
|
||||
struct avr8
|
||||
{
|
||||
avr8() : /*Core*/
|
||||
pc(0),
|
||||
watchdogTimer(0), prevPortB(0), prevWDR(0),
|
||||
dly_out(0), itd_TIFR1(0), elapsedCyclesSleep(0),
|
||||
timer1_next(0), timer1_base(0), TCNT1(0),
|
||||
//to align with AVR Simulator 2 since it has a bug that the first JMP
|
||||
//at the reset vector takes only 2 cycles
|
||||
cycleCounter(-1),
|
||||
|
||||
/*Video*/
|
||||
video_buffer(nullptr),
|
||||
|
||||
/*Audio*/
|
||||
enableSound(true),
|
||||
|
||||
/*Joystick*/
|
||||
new_input_mode(false), lagged(false),
|
||||
|
||||
/*Uzekeyboard*/
|
||||
uzeKbState(0), uzeKbEnabled(false),
|
||||
|
||||
/*SPI Emulation*/
|
||||
spiByte(0), spiClock(0), spiTransfer(0), spiState(SPI_IDLE_STATE), spiResponsePtr(0), spiResponseEnd(0)
|
||||
{
|
||||
memset(r, 0, sizeof(r));
|
||||
memset(io, 0, sizeof(io));
|
||||
memset(sram, 0, sizeof(sram));
|
||||
memset(eeprom, 0, sizeof(eeprom));
|
||||
memset(progmem, 0, progSize / 2);
|
||||
memset(progmemDecoded, 0, progSize / 2);
|
||||
}
|
||||
|
||||
/*Core*/
|
||||
u16 progmem[progSize / 2];
|
||||
instructionDecode_t progmemDecoded[progSize / 2];
|
||||
u16 pc, currentPc;
|
||||
|
||||
private:
|
||||
unsigned int cycleCounter;
|
||||
unsigned int elapsedCycles, prevCyclesCounter, elapsedCyclesSleep, lastCyclesSleep;
|
||||
unsigned int prevPortB, prevWDR;
|
||||
unsigned int watchdogTimer;
|
||||
unsigned int cycle_ctr_ins; // Used in update_hardware_ins to track elapsed cycles between calls
|
||||
// u8 eeClock; TODO: Only set at one location, never used. Maybe a never completed EEPROM timing code.
|
||||
unsigned int T16_latch; // Latch for 16-bit timers (16 bits used)
|
||||
unsigned int TCNT1; // Timer 1 counter (used instead of TCNT1H:TCNT1L)
|
||||
unsigned int timer1_next; // Cycles remaining until next timer1 event
|
||||
unsigned int timer1_base; // Where the between-events timer started (to reproduce TCNT1)
|
||||
unsigned int itd_TIFR1; // Interrupt delaying for TIFR1 (8 bits used)
|
||||
unsigned int dly_out; // Delayed output flags
|
||||
unsigned int dly_TCCR1B; // Delayed Timer1 controls
|
||||
unsigned int dly_TCNT1L; // Delayed Timer1 count (low)
|
||||
unsigned int dly_TCNT1H; // Delayed Timer1 count (high)
|
||||
public:
|
||||
int randomSeed;
|
||||
u16 decodeArg(u16 flash, u16 argMask, u8 argNeg);
|
||||
void instructionDecode(u16 address);
|
||||
void decodeFlash(void);
|
||||
void decodeFlash(u16 address);
|
||||
|
||||
struct
|
||||
{
|
||||
union {
|
||||
u8 r[32]; // Register file
|
||||
struct
|
||||
{
|
||||
u8 r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15;
|
||||
u8 r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, XL, XH, YL, YH, ZL, ZH;
|
||||
};
|
||||
};
|
||||
union {
|
||||
u8 io[256]; // Direct-mapped I/O space
|
||||
struct
|
||||
{
|
||||
u8 PINA, DDRA, PORTA, PINB, DDRB, PORTB, PINC, DDRC;
|
||||
u8 PORTC, PIND, DDRD, PORTD, res2C, res2D, res2E, res2F;
|
||||
u8 res30, res31, res32, res33, res34, TIFR0, TIFR1, TIFR2;
|
||||
u8 res38, res39, res3A, PCIFR, EIFR, EIMSK, GPIOR0, EECR;
|
||||
u8 EEDR, EEARL, EEARH, GTCCR, TCCR0A, TCCR0B, TCNT0, OCR0A;
|
||||
u8 OCR0B, res49, GPIOR1, GPIOR2, SPCR, SPSR, SPDR, res4f;
|
||||
u8 ACSR, OCDR, res52, SMCR, MCUSR, MCUCR, res56, SPMCSR;
|
||||
u8 res58, res59, res5A, res5B, res5C, SPL, SPH, SREG;
|
||||
u8 WDTCSR, CLKPR, res62, res63, PRR, res65, OSCCAL, res67;
|
||||
u8 PCICR, EICRA, res6a, PCMSK0, PCMSK1, PCMSK2, TIMSK0, TIMSK1;
|
||||
u8 TIMSK2, res71, res72, PCMSK3, res74, res75, res76, res77;
|
||||
u8 ADCL, ADCH, ADCSRA, ADCSRB, ADMUX, res7d, DIDR0, DIDR1;
|
||||
u8 TCCR1A, TCCR1B, TCCR1C, res83, TCNT1L, TCNT1H, ICR1L, ICR1H;
|
||||
u8 OCR1AL, OCR1AH, OCR1BL, OCR1BH, res8c, res8d, res8e, res8f;
|
||||
u8 res90, res91, res92, res93, res94, res95, res96, res97;
|
||||
u8 res98, res99, res9a, res9b, res9c, res9d, res9e, res9f;
|
||||
u8 resa0, resa1, resa2, resa3, resa4, resa5, resa6, resa7;
|
||||
u8 resa8, resa9, resaa, resab, resac, resad, resae, resaf;
|
||||
u8 TCCR2A, TCCR2B, TCNT2, OCR2A, OCR2B, resb5, ASSR, resb7;
|
||||
u8 TWBR, TWSR, TWAR, TWDR, TWCR, TWAMR, resbe, resbf;
|
||||
u8 UCSR0A, UCSR0B, UCSR0C, resc3, UBRR0L, UBRR0H, UDR0, resc7;
|
||||
u8 resc8, resc9, resca, rescb, rescc, rescd, resce, rescf;
|
||||
u8 resd0, resd1, resd2, resd3, resd4, resd5, resd6, resd7;
|
||||
u8 resd8, resd9, resda, resdb, resdc, resdd, resde, resdf;
|
||||
u8 rese0, rese1, rese2, rese3, rese4, rese5, rese6, rese7;
|
||||
u8 rese8, rese9, resea, reseb, resec, resed, resee, resef;
|
||||
u8 resf0, resf1, resf2, resf3, resf4, resf5, resf6, resf7;
|
||||
u8 resf8, resf9, resfa, resfb, resfc, resfd, resfe, resff;
|
||||
};
|
||||
};
|
||||
u8 sram[sramSize];
|
||||
};
|
||||
u8 eeprom[eepromSize];
|
||||
|
||||
int scanline_count;
|
||||
unsigned int left_edge_cycle;
|
||||
int scanline_top;
|
||||
unsigned int left_edge;
|
||||
u32 inset;
|
||||
u32 palette[256];
|
||||
u8 scanline_buf[2048]; // For collecting pixels from a single scanline
|
||||
u8 pixel_raw; // Raw (8 bit) input pixel
|
||||
|
||||
u32 *video_buffer;
|
||||
|
||||
/*Audio*/
|
||||
bool enableSound;
|
||||
|
||||
/*Joystick*/
|
||||
// SNES bit order: 0 = B, Y, Select, Start, Up, Down, Left, Right, A, X, L, 11 = R
|
||||
// NES bit order: 0 = A, B, Select, Start, Up, Down, Left, 7 = Right
|
||||
u32 buttons[2], latched_buttons[2];
|
||||
bool new_input_mode;
|
||||
bool lagged;
|
||||
|
||||
/*Uzebox Keyboard*/
|
||||
u8 uzeKbState;
|
||||
u8 uzeKbDataOut;
|
||||
bool uzeKbEnabled;
|
||||
queue<u8> uzeKbScanCodeQueue;
|
||||
u8 uzeKbDataIn;
|
||||
u8 uzeKbClock;
|
||||
|
||||
/*SPI Emulation*/
|
||||
u8 spiByte;
|
||||
u8 spiTransfer;
|
||||
u16 spiClock;
|
||||
u16 spiCycleWait;
|
||||
u8 spiState;
|
||||
u8 spiCommand;
|
||||
u8 spiCommandDelay;
|
||||
union {
|
||||
u32 spiArg;
|
||||
union {
|
||||
struct
|
||||
{
|
||||
u16 spiArgY;
|
||||
u16 spiArgX;
|
||||
};
|
||||
struct
|
||||
{
|
||||
u8 spiArgYlo;
|
||||
u8 spiArgYhi;
|
||||
u8 spiArgXlo;
|
||||
u8 spiArgXhi;
|
||||
};
|
||||
};
|
||||
};
|
||||
u32 spiByteCount;
|
||||
u8 spiResponseBuffer[12];
|
||||
u8 *spiResponsePtr;
|
||||
u8 *spiResponseEnd;
|
||||
|
||||
private:
|
||||
void write_io(u8 addr, u8 value);
|
||||
u8 read_io(u8 addr);
|
||||
// Should not be called directly (see write_io)
|
||||
void write_io_x(u8 addr, u8 value);
|
||||
|
||||
inline u8 read_progmem(u16 addr)
|
||||
{
|
||||
u16 word = progmem[addr >> 1];
|
||||
return (addr & 1) ? word >> 8 : word;
|
||||
}
|
||||
|
||||
inline void write_sram(u16 addr, u8 value)
|
||||
{
|
||||
sram[(addr - SRAMBASE) & (sramSize - 1U)] = value;
|
||||
}
|
||||
|
||||
void write_sram_io(u16 addr, u8 value)
|
||||
{
|
||||
if (addr >= SRAMBASE)
|
||||
{
|
||||
sram[(addr - SRAMBASE) & (sramSize - 1)] = value;
|
||||
}
|
||||
else if (addr >= IOBASE)
|
||||
{
|
||||
write_io(addr - IOBASE, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
r[addr] = value; // Write a register
|
||||
}
|
||||
}
|
||||
|
||||
inline u8 read_sram(u16 addr)
|
||||
{
|
||||
return sram[(addr - SRAMBASE) & (sramSize - 1U)];
|
||||
}
|
||||
|
||||
u8 read_sram_io(u16 addr)
|
||||
{
|
||||
|
||||
if (addr >= SRAMBASE)
|
||||
{
|
||||
return sram[(addr - SRAMBASE) & (sramSize - 1)];
|
||||
}
|
||||
else if (addr >= IOBASE)
|
||||
{
|
||||
return read_io(addr - IOBASE);
|
||||
}
|
||||
else
|
||||
{
|
||||
return r[addr]; // Read a register
|
||||
}
|
||||
}
|
||||
|
||||
inline static unsigned int get_insn_size(unsigned int insn)
|
||||
{
|
||||
/* 41 LDS Rd,k (next word is rest of address)
|
||||
82 STS k,Rr (next word is rest of address)
|
||||
30 JMP k (next word is rest of address)
|
||||
14 CALL k (next word is rest of address) */
|
||||
// This code is simplified by assuming upper k bits are zero on 644
|
||||
|
||||
if (insn == 14 || insn == 30 || insn == 41 || insn == 82)
|
||||
{
|
||||
return 2U;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1U;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
bool init_gui();
|
||||
void draw_memorymap();
|
||||
void trigger_interrupt(unsigned int location);
|
||||
unsigned int exec();
|
||||
void spi_calculateClock();
|
||||
void update_hardware();
|
||||
void update_hardware_fast();
|
||||
void update_hardware_ins();
|
||||
void update_spi();
|
||||
u8 SDReadByte();
|
||||
void SDWriteByte(u8 value);
|
||||
void SDCommit();
|
||||
void LoadEEPROMFile(const char *filename);
|
||||
void shutdown(int errcode);
|
||||
void idle(void);
|
||||
};
|
||||
|
||||
// undefine the following to disable SPI debug messages
|
||||
#ifdef USE_SPI_DEBUG
|
||||
#define SPI_DEBUG(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define SPI_DEBUG(...)
|
||||
#endif
|
||||
|
||||
#ifdef USE_EEPROM_DEBUG
|
||||
#define EEPROM_DEBUG(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define EEPROM_DEBUG(...)
|
||||
#endif
|
|
@ -0,0 +1,92 @@
|
|||
0000 0000 0000 0000 NOP
|
||||
0000 0001 dddd rrrr MOVW Rd+1:Rd,Rr+1:R
|
||||
0000 0010 dddd rrrr MULS Rd,Rr
|
||||
0000 0011 0ddd 0rrr MULSU Rd,Rr (registers are in 16-23 range)
|
||||
0000 0011 0ddd 1rrr FMUL Rd,Rr (registers are in 16-23 range)
|
||||
0000 0011 1ddd 0rrr FMULS Rd,Rr
|
||||
0000 0011 1ddd 1rrr FMULSU Rd,Rr
|
||||
0000 01rd dddd rrrr CPC Rd,Rr
|
||||
0000 10rd dddd rrrr SBC Rd,Rr
|
||||
0000 11rd dddd rrrr ADD Rd,Rr (LSL is ADD Rd,Rd)
|
||||
0001 00rd dddd rrrr CPSE Rd,Rr
|
||||
0001 01rd dddd rrrr CP Rd,Rr
|
||||
0001 10rd dddd rrrr SUB Rd,Rr
|
||||
0001 11rd dddd rrrr ADC Rd,Rr (ROL is ADC Rd,Rd)
|
||||
0010 00rd dddd rrrr AND Rd,Rr (TST is AND Rd,Rd)
|
||||
0010 01rd dddd rrrr EOR Rd,Rr (CLR is EOR Rd,Rd)
|
||||
0010 10rd dddd rrrr OR Rd,Rr
|
||||
0010 11rd dddd rrrr MOV Rd,Rr
|
||||
0011 KKKK dddd KKKK CPI Rd,K
|
||||
0100 KKKK dddd KKKK SBCI Rd,K
|
||||
0101 KKKK dddd KKKK SUBI Rd,K
|
||||
0110 KKKK dddd KKKK ORI Rd,K (same as SBR insn)
|
||||
0111 KKKK dddd KKKK ANDI Rd,K (CBR is ANDI with K complemented)
|
||||
10q0 qq0d dddd 0qqq LD Rd,Z+q
|
||||
10q0 qq0d dddd 1qqq LD Rd,Y+q
|
||||
10q0 qq1d dddd 0qqq ST Z+q,Rd
|
||||
10q0 qq1d dddd 1qqq ST Y+q,Rd
|
||||
1001 000d dddd 0000 LDS Rd,k (next word is rest of address)
|
||||
1001 000d dddd 0001 LD Rd,Z+
|
||||
1001 000d dddd 0010 LD Rd,-Z
|
||||
1001 000d dddd 0100 LPM Rd,Z
|
||||
1001 000d dddd 0101 LPM Rd,Z+
|
||||
1001 000d dddd 0110 ELPM Rd,Z
|
||||
1001 000d dddd 0111 ELPM Rd,Z+
|
||||
1001 000d dddd 1001 LD Rd,Y+
|
||||
1001 000d dddd 1010 LD Rd,-Y
|
||||
1001 000d dddd 1100 LD rd,X
|
||||
1001 000d dddd 1101 LD rd,X+
|
||||
1001 000d dddd 1110 LD rd,-X
|
||||
1001 000d dddd 1111 POP Rd
|
||||
1001 001d dddd 0000 STS k,Rr (next word is rest of address)
|
||||
1001 001r rrrr 0001 ST Z+,Rr
|
||||
1001 001r rrrr 0010 ST -Z,Rr
|
||||
1001 001r rrrr 1001 ST Y+,Rr
|
||||
1001 001r rrrr 1010 ST -Y,Rr
|
||||
1001 001r rrrr 1100 ST X,Rr
|
||||
1001 001r rrrr 1101 ST X+,Rr
|
||||
1001 001r rrrr 1110 ST -X,Rr
|
||||
1001 001d dddd 1111 PUSH Rd
|
||||
1001 010d dddd 0000 COM Rd
|
||||
1001 010d dddd 0001 NEG Rd
|
||||
1001 010d dddd 0010 SWAP Rd
|
||||
1001 010d dddd 0011 INC Rd
|
||||
1001 010d dddd 0101 ASR Rd
|
||||
1001 010d dddd 0110 LSR Rd
|
||||
1001 010d dddd 0111 ROR Rd
|
||||
1001 010d dddd 1010 DEC Rd
|
||||
1001 010k kkkk 110k JMP k (next word is rest of address)
|
||||
1001 010k kkkk 111k CALL k (next word is rest of address)
|
||||
1001 0100 0sss 1000 BSET s (SEC, etc are aliases with sss implicit)
|
||||
1001 0100 1sss 1000 BCLR s (CLC, etc are aliases with sss implicit)
|
||||
1001 0100 0000 1001 IJMP (jump thru Z register)
|
||||
1001 0101 0000 1000 RET
|
||||
1001 0101 0000 1001 ICALL (call thru Z register)
|
||||
1001 0101 0001 1000 RETI
|
||||
1001 0101 1000 1000 SLEEP
|
||||
1001 0101 1001 1000 BREAK
|
||||
1001 0101 1010 1000 WDR
|
||||
1001 0101 1100 1000 LPM (r0 implied, why is this special?)
|
||||
1001 0101 1110 1000 SPM Z (writes R1:R0)
|
||||
1001 0110 KKdd KKKK ADIW Rd+1:Rd,K (16-bit add to upper four register pairs)
|
||||
1001 0111 KKdd KKKK SBIW Rd+1:Rd,K
|
||||
1001 1000 AAAA Abbb CBI A,b
|
||||
1001 1001 AAAA Abbb SBIC A,b
|
||||
1001 1010 AAAA Abbb SBI A,b
|
||||
1001 1011 AAAA Abbb SBIS A,b
|
||||
1001 11rd dddd rrrr MUL Rd,Rr
|
||||
1011 0AAd dddd AAAA IN Rd,A
|
||||
1011 1AAd dddd AAAA OUT A,Rd
|
||||
1100 kkkk kkkk kkkk RJMP k
|
||||
1101 kkkk kkkk kkkk RCALL k
|
||||
1110 KKKK dddd KKKK LDI Rd,K (SER is just LDI Rd,255)
|
||||
1111 00kk kkkk ksss BRBS s,k (same here)
|
||||
1111 01kk kkkk ksss BRBC s,k (BRCC, etc are aliases for this with sss implicit)
|
||||
1111 100d dddd 0bbb BLD Rd,b
|
||||
1111 101d dddd 0bbb BST Rd,b
|
||||
1111 110r rrrr 0bbb SBRC Rr,b
|
||||
1111 111r rrrr 0bbb SBRS Rr,b
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,344 @@
|
|||
/* blip_buf 1.1.0. http://www.slack.net/~ant/ */
|
||||
|
||||
#include "blip_buf.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Library Copyright (C) 2003-2009 Shay Green. This library is free software;
|
||||
you can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#if defined (BLARGG_TEST) && BLARGG_TEST
|
||||
#include "blargg_test.h"
|
||||
#endif
|
||||
|
||||
/* Equivalent to ULONG_MAX >= 0xFFFFFFFF00000000.
|
||||
Avoids constants that don't fit in 32 bits. */
|
||||
#if ULONG_MAX/0xFFFFFFFF > 0xFFFFFFFF
|
||||
typedef unsigned long fixed_t;
|
||||
enum { pre_shift = 32 };
|
||||
|
||||
#elif defined(ULLONG_MAX)
|
||||
typedef unsigned long long fixed_t;
|
||||
enum { pre_shift = 32 };
|
||||
|
||||
#else
|
||||
typedef unsigned fixed_t;
|
||||
enum { pre_shift = 0 };
|
||||
|
||||
#endif
|
||||
|
||||
enum { time_bits = pre_shift + 20 };
|
||||
|
||||
static fixed_t const time_unit = (fixed_t) 1 << time_bits;
|
||||
|
||||
enum { bass_shift = 9 }; /* affects high-pass filter breakpoint frequency */
|
||||
enum { end_frame_extra = 2 }; /* allows deltas slightly after frame length */
|
||||
|
||||
enum { half_width = 8 };
|
||||
enum { buf_extra = half_width*2 + end_frame_extra };
|
||||
enum { phase_bits = 5 };
|
||||
enum { phase_count = 1 << phase_bits };
|
||||
enum { delta_bits = 15 };
|
||||
enum { delta_unit = 1 << delta_bits };
|
||||
enum { frac_bits = time_bits - pre_shift };
|
||||
|
||||
/* We could eliminate avail and encode whole samples in offset, but that would
|
||||
limit the total buffered samples to blip_max_frame. That could only be
|
||||
increased by decreasing time_bits, which would reduce resample ratio accuracy.
|
||||
*/
|
||||
|
||||
/** Sample buffer that resamples to output rate and accumulates samples
|
||||
until they're read out */
|
||||
struct blip_t
|
||||
{
|
||||
fixed_t factor;
|
||||
fixed_t offset;
|
||||
int avail;
|
||||
int size;
|
||||
int integrator;
|
||||
};
|
||||
|
||||
typedef int buf_t;
|
||||
|
||||
/* probably not totally portable */
|
||||
#define SAMPLES( buf ) ((buf_t*) ((buf) + 1))
|
||||
|
||||
/* Arithmetic (sign-preserving) right shift */
|
||||
#define ARITH_SHIFT( n, shift ) \
|
||||
((n) >> (shift))
|
||||
|
||||
enum { max_sample = +32767 };
|
||||
enum { min_sample = -32768 };
|
||||
|
||||
#define CLAMP( n ) \
|
||||
{\
|
||||
if ( (short) n != n )\
|
||||
n = ARITH_SHIFT( n, 16 ) ^ max_sample;\
|
||||
}
|
||||
|
||||
static void check_assumptions( void )
|
||||
{
|
||||
int n;
|
||||
|
||||
#if INT_MAX < 0x7FFFFFFF || UINT_MAX < 0xFFFFFFFF
|
||||
#error "int must be at least 32 bits"
|
||||
#endif
|
||||
|
||||
assert( (-3 >> 1) == -2 ); /* right shift must preserve sign */
|
||||
|
||||
n = max_sample * 2;
|
||||
CLAMP( n );
|
||||
assert( n == max_sample );
|
||||
|
||||
n = min_sample * 2;
|
||||
CLAMP( n );
|
||||
assert( n == min_sample );
|
||||
|
||||
assert( blip_max_ratio <= time_unit );
|
||||
assert( blip_max_frame <= (fixed_t) -1 >> time_bits );
|
||||
}
|
||||
|
||||
blip_t* blip_new( int size )
|
||||
{
|
||||
blip_t* m;
|
||||
assert( size >= 0 );
|
||||
|
||||
m = (blip_t*) malloc( sizeof *m + (size + buf_extra) * sizeof (buf_t) );
|
||||
if ( m )
|
||||
{
|
||||
m->factor = time_unit / blip_max_ratio;
|
||||
m->size = size;
|
||||
blip_clear( m );
|
||||
check_assumptions();
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
void blip_delete( blip_t* m )
|
||||
{
|
||||
if ( m != NULL )
|
||||
{
|
||||
/* Clear fields in case user tries to use after freeing */
|
||||
memset( m, 0, sizeof *m );
|
||||
free( m );
|
||||
}
|
||||
}
|
||||
|
||||
void blip_set_rates( blip_t* m, double clock_rate, double sample_rate )
|
||||
{
|
||||
double factor = time_unit * sample_rate / clock_rate;
|
||||
m->factor = (fixed_t) factor;
|
||||
|
||||
/* Fails if clock_rate exceeds maximum, relative to sample_rate */
|
||||
assert( 0 <= factor - m->factor && factor - m->factor < 1 );
|
||||
|
||||
/* Avoid requiring math.h. Equivalent to
|
||||
m->factor = (int) ceil( factor ) */
|
||||
if ( m->factor < factor )
|
||||
m->factor++;
|
||||
|
||||
/* At this point, factor is most likely rounded up, but could still
|
||||
have been rounded down in the floating-point calculation. */
|
||||
}
|
||||
|
||||
void blip_clear( blip_t* m )
|
||||
{
|
||||
/* We could set offset to 0, factor/2, or factor-1. 0 is suitable if
|
||||
factor is rounded up. factor-1 is suitable if factor is rounded down.
|
||||
Since we don't know rounding direction, factor/2 accommodates either,
|
||||
with the slight loss of showing an error in half the time. Since for
|
||||
a 64-bit factor this is years, the halving isn't a problem. */
|
||||
|
||||
m->offset = m->factor / 2;
|
||||
m->avail = 0;
|
||||
m->integrator = 0;
|
||||
memset( SAMPLES( m ), 0, (m->size + buf_extra) * sizeof (buf_t) );
|
||||
}
|
||||
|
||||
int blip_clocks_needed( const blip_t* m, int samples )
|
||||
{
|
||||
fixed_t needed;
|
||||
|
||||
/* Fails if buffer can't hold that many more samples */
|
||||
assert( samples >= 0 && m->avail + samples <= m->size );
|
||||
|
||||
needed = (fixed_t) samples * time_unit;
|
||||
if ( needed < m->offset )
|
||||
return 0;
|
||||
|
||||
return (needed - m->offset + m->factor - 1) / m->factor;
|
||||
}
|
||||
|
||||
void blip_end_frame( blip_t* m, unsigned t )
|
||||
{
|
||||
fixed_t off = t * m->factor + m->offset;
|
||||
m->avail += off >> time_bits;
|
||||
m->offset = off & (time_unit - 1);
|
||||
|
||||
/* Fails if buffer size was exceeded */
|
||||
assert( m->avail <= m->size );
|
||||
}
|
||||
|
||||
int blip_samples_avail( const blip_t* m )
|
||||
{
|
||||
return m->avail;
|
||||
}
|
||||
|
||||
static void remove_samples( blip_t* m, int count )
|
||||
{
|
||||
buf_t* buf = SAMPLES( m );
|
||||
int remain = m->avail + buf_extra - count;
|
||||
m->avail -= count;
|
||||
|
||||
memmove( &buf [0], &buf [count], remain * sizeof buf [0] );
|
||||
memset( &buf [remain], 0, count * sizeof buf [0] );
|
||||
}
|
||||
|
||||
int blip_read_samples( blip_t* m, short out [], int count, int stereo )
|
||||
{
|
||||
assert( count >= 0 );
|
||||
|
||||
if ( count > m->avail )
|
||||
count = m->avail;
|
||||
|
||||
if ( count )
|
||||
{
|
||||
int const step = stereo ? 2 : 1;
|
||||
buf_t const* in = SAMPLES( m );
|
||||
buf_t const* end = in + count;
|
||||
int sum = m->integrator;
|
||||
do
|
||||
{
|
||||
/* Eliminate fraction */
|
||||
int s = ARITH_SHIFT( sum, delta_bits );
|
||||
|
||||
sum += *in++;
|
||||
|
||||
CLAMP( s );
|
||||
|
||||
*out = s;
|
||||
out += step;
|
||||
|
||||
/* High-pass filter */
|
||||
sum -= s << (delta_bits - bass_shift);
|
||||
}
|
||||
while ( in != end );
|
||||
m->integrator = sum;
|
||||
|
||||
remove_samples( m, count );
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Things that didn't help performance on x86:
|
||||
__attribute__((aligned(128)))
|
||||
#define short int
|
||||
restrict
|
||||
*/
|
||||
|
||||
/* Sinc_Generator( 0.9, 0.55, 4.5 ) */
|
||||
static short const bl_step [phase_count + 1] [half_width] =
|
||||
{
|
||||
{ 43, -115, 350, -488, 1136, -914, 5861,21022},
|
||||
{ 44, -118, 348, -473, 1076, -799, 5274,21001},
|
||||
{ 45, -121, 344, -454, 1011, -677, 4706,20936},
|
||||
{ 46, -122, 336, -431, 942, -549, 4156,20829},
|
||||
{ 47, -123, 327, -404, 868, -418, 3629,20679},
|
||||
{ 47, -122, 316, -375, 792, -285, 3124,20488},
|
||||
{ 47, -120, 303, -344, 714, -151, 2644,20256},
|
||||
{ 46, -117, 289, -310, 634, -17, 2188,19985},
|
||||
{ 46, -114, 273, -275, 553, 117, 1758,19675},
|
||||
{ 44, -108, 255, -237, 471, 247, 1356,19327},
|
||||
{ 43, -103, 237, -199, 390, 373, 981,18944},
|
||||
{ 42, -98, 218, -160, 310, 495, 633,18527},
|
||||
{ 40, -91, 198, -121, 231, 611, 314,18078},
|
||||
{ 38, -84, 178, -81, 153, 722, 22,17599},
|
||||
{ 36, -76, 157, -43, 80, 824, -241,17092},
|
||||
{ 34, -68, 135, -3, 8, 919, -476,16558},
|
||||
{ 32, -61, 115, 34, -60, 1006, -683,16001},
|
||||
{ 29, -52, 94, 70, -123, 1083, -862,15422},
|
||||
{ 27, -44, 73, 106, -184, 1152,-1015,14824},
|
||||
{ 25, -36, 53, 139, -239, 1211,-1142,14210},
|
||||
{ 22, -27, 34, 170, -290, 1261,-1244,13582},
|
||||
{ 20, -20, 16, 199, -335, 1301,-1322,12942},
|
||||
{ 18, -12, -3, 226, -375, 1331,-1376,12293},
|
||||
{ 15, -4, -19, 250, -410, 1351,-1408,11638},
|
||||
{ 13, 3, -35, 272, -439, 1361,-1419,10979},
|
||||
{ 11, 9, -49, 292, -464, 1362,-1410,10319},
|
||||
{ 9, 16, -63, 309, -483, 1354,-1383, 9660},
|
||||
{ 7, 22, -75, 322, -496, 1337,-1339, 9005},
|
||||
{ 6, 26, -85, 333, -504, 1312,-1280, 8355},
|
||||
{ 4, 31, -94, 341, -507, 1278,-1205, 7713},
|
||||
{ 3, 35, -102, 347, -506, 1238,-1119, 7082},
|
||||
{ 1, 40, -110, 350, -499, 1190,-1021, 6464},
|
||||
{ 0, 43, -115, 350, -488, 1136, -914, 5861}
|
||||
};
|
||||
|
||||
/* Shifting by pre_shift allows calculation using unsigned int rather than
|
||||
possibly-wider fixed_t. On 32-bit platforms, this is likely more efficient.
|
||||
And by having pre_shift 32, a 32-bit platform can easily do the shift by
|
||||
simply ignoring the low half. */
|
||||
|
||||
void blip_add_delta( blip_t* m, unsigned time, int delta )
|
||||
{
|
||||
unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
|
||||
buf_t* out = SAMPLES( m ) + m->avail + (fixed >> frac_bits);
|
||||
|
||||
int const phase_shift = frac_bits - phase_bits;
|
||||
int phase = fixed >> phase_shift & (phase_count - 1);
|
||||
short const* in = bl_step [phase];
|
||||
short const* rev = bl_step [phase_count - phase];
|
||||
|
||||
int interp = fixed >> (phase_shift - delta_bits) & (delta_unit - 1);
|
||||
int delta2 = (delta * interp) >> delta_bits;
|
||||
delta -= delta2;
|
||||
|
||||
/* Fails if buffer size was exceeded */
|
||||
assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] );
|
||||
|
||||
out [0] += in[0]*delta + in[half_width+0]*delta2;
|
||||
out [1] += in[1]*delta + in[half_width+1]*delta2;
|
||||
out [2] += in[2]*delta + in[half_width+2]*delta2;
|
||||
out [3] += in[3]*delta + in[half_width+3]*delta2;
|
||||
out [4] += in[4]*delta + in[half_width+4]*delta2;
|
||||
out [5] += in[5]*delta + in[half_width+5]*delta2;
|
||||
out [6] += in[6]*delta + in[half_width+6]*delta2;
|
||||
out [7] += in[7]*delta + in[half_width+7]*delta2;
|
||||
|
||||
in = rev;
|
||||
out [ 8] += in[7]*delta + in[7-half_width]*delta2;
|
||||
out [ 9] += in[6]*delta + in[6-half_width]*delta2;
|
||||
out [10] += in[5]*delta + in[5-half_width]*delta2;
|
||||
out [11] += in[4]*delta + in[4-half_width]*delta2;
|
||||
out [12] += in[3]*delta + in[3-half_width]*delta2;
|
||||
out [13] += in[2]*delta + in[2-half_width]*delta2;
|
||||
out [14] += in[1]*delta + in[1-half_width]*delta2;
|
||||
out [15] += in[0]*delta + in[0-half_width]*delta2;
|
||||
}
|
||||
|
||||
void blip_add_delta_fast( blip_t* m, unsigned time, int delta )
|
||||
{
|
||||
unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
|
||||
buf_t* out = SAMPLES( m ) + m->avail + (fixed >> frac_bits);
|
||||
|
||||
int interp = fixed >> (frac_bits - delta_bits) & (delta_unit - 1);
|
||||
int delta2 = delta * interp;
|
||||
|
||||
/* Fails if buffer size was exceeded */
|
||||
assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] );
|
||||
|
||||
out [7] += delta * delta_unit - delta2;
|
||||
out [8] += delta2;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/** \file
|
||||
Sample buffer that resamples from input clock rate to output sample rate */
|
||||
|
||||
/* blip_buf 1.1.0 */
|
||||
#ifndef BLIP_BUF_H
|
||||
#define BLIP_BUF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** First parameter of most functions is blip_t*, or const blip_t* if nothing
|
||||
is changed. */
|
||||
typedef struct blip_t blip_t;
|
||||
|
||||
/** Creates new buffer that can hold at most sample_count samples. Sets rates
|
||||
so that there are blip_max_ratio clocks per sample. Returns pointer to new
|
||||
buffer, or NULL if insufficient memory. */
|
||||
blip_t* blip_new( int sample_count );
|
||||
|
||||
/** Sets approximate input clock rate and output sample rate. For every
|
||||
clock_rate input clocks, approximately sample_rate samples are generated. */
|
||||
void blip_set_rates( blip_t*, double clock_rate, double sample_rate );
|
||||
|
||||
enum { /** Maximum clock_rate/sample_rate ratio. For a given sample_rate,
|
||||
clock_rate must not be greater than sample_rate*blip_max_ratio. */
|
||||
blip_max_ratio = 1 << 20 };
|
||||
|
||||
/** Clears entire buffer. Afterwards, blip_samples_avail() == 0. */
|
||||
void blip_clear( blip_t* );
|
||||
|
||||
/** Adds positive/negative delta into buffer at specified clock time. */
|
||||
void blip_add_delta( blip_t*, unsigned int clock_time, int delta );
|
||||
|
||||
/** Same as blip_add_delta(), but uses faster, lower-quality synthesis. */
|
||||
void blip_add_delta_fast( blip_t*, unsigned int clock_time, int delta );
|
||||
|
||||
/** Length of time frame, in clocks, needed to make sample_count additional
|
||||
samples available. */
|
||||
int blip_clocks_needed( const blip_t*, int sample_count );
|
||||
|
||||
enum { /** Maximum number of samples that can be generated from one time frame. */
|
||||
blip_max_frame = 4000 };
|
||||
|
||||
/** Makes input clocks before clock_duration available for reading as output
|
||||
samples. Also begins new time frame at clock_duration, so that clock time 0 in
|
||||
the new time frame specifies the same clock as clock_duration in the old time
|
||||
frame specified. Deltas can have been added slightly past clock_duration (up to
|
||||
however many clocks there are in two output samples). */
|
||||
void blip_end_frame( blip_t*, unsigned int clock_duration );
|
||||
|
||||
/** Number of buffered samples available for reading. */
|
||||
int blip_samples_avail( const blip_t* );
|
||||
|
||||
/** Reads and removes at most 'count' samples and writes them to 'out'. If
|
||||
'stereo' is true, writes output to every other element of 'out', allowing easy
|
||||
interleaving of two buffers into a stereo sample stream. Outputs 16-bit signed
|
||||
samples. Returns number of samples actually read. */
|
||||
int blip_read_samples( blip_t*, short out [], int count, int stereo );
|
||||
|
||||
/** Frees buffer. No effect if NULL is passed. */
|
||||
void blip_delete( blip_t* );
|
||||
|
||||
|
||||
/* Deprecated */
|
||||
typedef blip_t blip_buffer_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
Copyright (c) 2009 Eric Anderton
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct SDPartitionEntry{
|
||||
BYTE state;
|
||||
BYTE startHead;
|
||||
WORD startCylinder;
|
||||
BYTE type;
|
||||
BYTE endHead;
|
||||
WORD endCylinder;
|
||||
DWORD sectorOffset;
|
||||
DWORD sectorCount;
|
||||
};
|
||||
|
||||
// Partition 1 example
|
||||
/*
|
||||
entry.state = 0x00;
|
||||
entry.startHead = 0x03;
|
||||
entry.startCylinder = 0x003D;
|
||||
entry.type = 0x06;
|
||||
entry.endHead = 0x0D;
|
||||
entry.endCylinder = 0xDBED;
|
||||
entry.sectorOffset = 0x000000F9;
|
||||
entry.sectorCount = 0x001E5F07;
|
||||
*/
|
||||
|
||||
//Code mostly borrowed from: http://support.microsoft.com/kb/138434
|
||||
|
||||
#define SECTORS_PER_WRITE 4096
|
||||
|
||||
char drivePath[] = "\\\\.\\X:";
|
||||
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
HANDLE hCD, hFile;
|
||||
DWORD dwNotUsed;
|
||||
|
||||
if (argc<3){
|
||||
printf("Disk Image dumper - creates binary images of disks, suitable for SD media.\n");
|
||||
printf("(c) 2009 Eric Anderton\n");
|
||||
printf("\nUsage: dump DRIVELETTER FILENAME\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(strlen(argv[1]) > 1){
|
||||
printf("Invalid drive letter.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// set the drive letter in the path specification
|
||||
drivePath[4] = argv[1][0];
|
||||
|
||||
hFile = CreateFile (argv[2],GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
hCD = CreateFile (drivePath, GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);
|
||||
|
||||
if (hCD != INVALID_HANDLE_VALUE){
|
||||
DISK_GEOMETRY disk;
|
||||
PARTITION_INFORMATION partition;
|
||||
PARTITION_INFORMATION_MBR mbr;
|
||||
|
||||
// Get sector size of compact disc
|
||||
if (DeviceIoControl (hCD, IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
||||
NULL, 0, &disk, sizeof(disk),
|
||||
&dwNotUsed, NULL))
|
||||
{
|
||||
LPBYTE lpSector;
|
||||
DWORD dwSize = disk.BytesPerSector; // 2 sectors
|
||||
DWORD dwReadSize = dwSize*SECTORS_PER_WRITE;
|
||||
__int64 cylinders = *((__int64*)&disk);
|
||||
__int64 sectors = cylinders * disk.TracksPerCylinder * disk.SectorsPerTrack;
|
||||
__int64 totalSize = sectors*dwSize;
|
||||
__int64 i;
|
||||
|
||||
printf("Cylinders %lld\nTracks Per Cylinder: %d\nSectors Per Track %d\nSector Size: %d\n",cylinders,disk.TracksPerCylinder,disk.SectorsPerTrack,dwSize);
|
||||
printf("Total Sectors: %lld\n",sectors);
|
||||
printf("Media Size: %lld\n",totalSize);
|
||||
|
||||
// Allocate buffer to hold sectors from compact disc. Note that
|
||||
// the buffer will be allocated on a sector boundary because the
|
||||
// allocation granularity is larger than the size of a sector on a
|
||||
// compact disk.
|
||||
lpSector = (LPBYTE)VirtualAlloc (NULL, dwReadSize,MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
|
||||
|
||||
SDPartitionEntry entry;
|
||||
// query system about partition and fill out the partition structure
|
||||
if(DeviceIoControl(hCD, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &partition, sizeof(PARTITION_INFORMATION), &dwNotUsed, NULL)){
|
||||
entry.state = 0x00;
|
||||
entry.startCylinder = 0;//(*(__int64*)(&partition.StartingOffset))/dwSize;
|
||||
|
||||
entry.startHead = 0x00; //TODO
|
||||
entry.startCylinder = 0x0000; //TODO
|
||||
entry.type = partition.PartitionType;
|
||||
entry.endHead = 0x00; //TODO
|
||||
entry.endCylinder = 0x0000; //TODO
|
||||
entry.sectorOffset = partition.HiddenSectors;
|
||||
entry.sectorCount = (*(__int64*)(&partition.PartitionLength))/dwSize;
|
||||
printf("----------\n");
|
||||
printf("state: %0.4X\n",entry.state);
|
||||
// printf("startHead: %0.4X\n",entry.startHead);
|
||||
// printf("startCylinder: %0.4X\n",entry.startCylinder);
|
||||
printf("type: %0.2X\n",entry.type);
|
||||
// printf("endHead: %0.4X\n",entry.endHead);
|
||||
// printf("endCylinder: %0.4X\n",entry.endCylinder);
|
||||
printf("sectorCount: %0.8X\n",entry.sectorCount);
|
||||
printf("sectorOffset: %0.8X\n",entry.sectorOffset);
|
||||
}
|
||||
else{
|
||||
printf("Error reading parition info.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// build a replica of the MBR for a single-partition image (common for SD media)
|
||||
memset(lpSector,0,dwSize);
|
||||
memcpy(lpSector + 0x1BE,&entry,sizeof(SDPartitionEntry));
|
||||
|
||||
// Executable Marker
|
||||
lpSector[0x1FE] = 0x55;
|
||||
lpSector[0x1FF] = 0xAA;
|
||||
|
||||
WriteFile (hFile, lpSector, dwSize, &dwNotUsed, NULL);
|
||||
|
||||
// write out hidden sectors (empty)
|
||||
memset(lpSector,0,dwSize);
|
||||
for(i = 1; i < entry.sectorOffset; i++){
|
||||
WriteFile (hFile, lpSector, dwSize, &dwNotUsed, NULL);
|
||||
}
|
||||
|
||||
// iteratively read all the sectors for the disk image
|
||||
printf("Writing...");
|
||||
for(i = 0; i < sectors/SECTORS_PER_WRITE; i++){
|
||||
// Read sectors from the disc and write them to a file.
|
||||
ReadFile (hCD, lpSector, dwReadSize, &dwNotUsed, NULL);
|
||||
WriteFile (hFile, lpSector, dwReadSize, &dwNotUsed, NULL);
|
||||
}
|
||||
DWORD leftovers = sectors-i;
|
||||
if(leftovers > 0){
|
||||
dwReadSize = leftovers*dwSize;
|
||||
ReadFile (hCD, lpSector, dwReadSize, &dwNotUsed, NULL);
|
||||
WriteFile (hFile, lpSector, dwReadSize, &dwNotUsed, NULL);
|
||||
}
|
||||
VirtualFree (lpSector, 0, MEM_RELEASE);
|
||||
}
|
||||
CloseHandle (hCD);
|
||||
CloseHandle (hFile);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2008-2016 by
|
||||
David Etherton, Eric Anderton, Alec Bourque (Uze), Filipe Rinaldi,
|
||||
Sandor Zsuga (Jubatian), Matt Pandina (Artcfox)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
#include "uzem.h"
|
||||
#include "avr8.h"
|
||||
#include "uzerom.h"
|
||||
#include "blip_buf.h"
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../emulibc/emulibc.h"
|
||||
#include "../emulibc/waterboxcore.h"
|
||||
|
||||
#define EXPORT extern "C" ECL_EXPORT
|
||||
|
||||
// header for use with UzeRom files
|
||||
static RomHeader uzeRomHeader;
|
||||
static avr8 uzebox;
|
||||
static blip_t* blip;
|
||||
|
||||
void avr8::shutdown(int errcode)
|
||||
{
|
||||
printf("Oh no, that's bad!\n");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT bool MouseEnabled()
|
||||
{
|
||||
return uzeRomHeader.mouse;
|
||||
}
|
||||
|
||||
EXPORT bool Init()
|
||||
{
|
||||
const char *heximage = "romfile";
|
||||
|
||||
unsigned char *buffer = (unsigned char *)(uzebox.progmem);
|
||||
|
||||
if (isUzeromFile(heximage))
|
||||
{
|
||||
printf("-- Loading UzeROM Image --\n");
|
||||
if (!loadUzeImage(heximage, &uzeRomHeader, buffer))
|
||||
{
|
||||
printf("Error: cannot load UzeRom file '%s'.\n\n", heximage);
|
||||
return false;
|
||||
}
|
||||
// enable mouse support if required
|
||||
if (uzeRomHeader.mouse)
|
||||
{
|
||||
printf("Mouse support enabled\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Error: Doesn't seem to be an UzeROM image\n");
|
||||
return false;
|
||||
/*printf("Loading Hex Image...\n");
|
||||
if (!loadHex(heximage, buffer))
|
||||
{
|
||||
printf("Error: cannot load HEX image '%s'.\n\n", heximage);
|
||||
return false;
|
||||
}*/
|
||||
}
|
||||
|
||||
uzebox.decodeFlash();
|
||||
if (!uzebox.init_gui())
|
||||
return false;
|
||||
|
||||
uzebox.randomSeed = time(NULL);
|
||||
srand(uzebox.randomSeed); //used for the watchdog timer entropy
|
||||
|
||||
blip = blip_new(2048);
|
||||
blip_set_rates(blip, 28618182, 44100);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
EXPORT void GetMemoryAreas(MemoryArea *m)
|
||||
{
|
||||
m[0].Data = uzebox.sram;
|
||||
m[0].Name = "SRAM";
|
||||
m[0].Size = sramSize;
|
||||
m[0].Flags = MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_PRIMARY;
|
||||
|
||||
m[1].Data = uzebox.eeprom;
|
||||
m[1].Name = "EEPROM";
|
||||
m[1].Size = eepromSize;
|
||||
m[1].Flags = MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_SAVERAMMABLE;
|
||||
|
||||
m[2].Data = uzebox.progmem;
|
||||
m[2].Name = "ROM";
|
||||
m[2].Size = progSize;
|
||||
m[2].Flags = MEMORYAREA_FLAGS_WORDSIZE2;
|
||||
}
|
||||
|
||||
struct MyFrameInfo : public FrameInfo
|
||||
{
|
||||
uint32_t Buttons[3];
|
||||
};
|
||||
|
||||
static int cycles;
|
||||
|
||||
static int audio_value;
|
||||
void SampleCallback(uint8_t val)
|
||||
{
|
||||
int v = (val - 128) * 100;
|
||||
int delta = v - audio_value;
|
||||
if (delta)
|
||||
blip_add_delta(blip, cycles, delta);
|
||||
audio_value = v;
|
||||
}
|
||||
|
||||
EXPORT void FrameAdvance(MyFrameInfo* f)
|
||||
{
|
||||
cycles = 0;
|
||||
uzebox.video_buffer = f->VideoBuffer;
|
||||
uzebox.lagged = true;
|
||||
uzebox.buttons[0] = ~f->Buttons[0];
|
||||
uzebox.buttons[1] = ~f->Buttons[1];
|
||||
if (f->Buttons[2] & 1) // power pressed
|
||||
{
|
||||
uzebox.PIND = uzebox.PIND & ~0b00001100;
|
||||
}
|
||||
else
|
||||
{
|
||||
uzebox.PIND |= 0b00001100;
|
||||
}
|
||||
|
||||
while (uzebox.scanline_count == -999 && cycles < 700000)
|
||||
{
|
||||
cycles += uzebox.exec();
|
||||
}
|
||||
while (uzebox.scanline_count != -999 && cycles < 700000)
|
||||
{
|
||||
cycles += uzebox.exec();
|
||||
}
|
||||
uzebox.video_buffer = nullptr;
|
||||
f->Cycles = cycles;
|
||||
f->Width = VIDEO_DISP_WIDTH;
|
||||
f->Height = 224;
|
||||
blip_end_frame(blip, cycles);
|
||||
f->Samples = blip_read_samples(blip, f->SoundBuffer, 2048, true);
|
||||
for (int i = 0; i < f->Samples; i++)
|
||||
f->SoundBuffer[i * 2 + 1] = f->SoundBuffer[i * 2];
|
||||
f->Lagged = uzebox.lagged;
|
||||
}
|
||||
|
||||
void (*InputCallback)();
|
||||
|
||||
EXPORT void SetInputCallback(void (*callback)())
|
||||
{
|
||||
InputCallback = callback;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2008-2016 by
|
||||
David Etherton, Eric Anderton, Alec Bourque (Uze), Filipe Rinaldi,
|
||||
Sandor Zsuga (Jubatian), Matt Pandina (Artcfox)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
#ifndef UZEM_H
|
||||
#define UZEM_H
|
||||
|
||||
#define VERSION "v2.0"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2008-2016 by
|
||||
David Etherton, Eric Anderton, Alec Bourque (Uze), Filipe Rinaldi,
|
||||
Sandor Zsuga (Jubatian), Matt Pandina (Artcfox)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "uzerom.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef signed char s8;
|
||||
typedef unsigned short u16;
|
||||
typedef signed short s16;
|
||||
typedef unsigned long u32;
|
||||
|
||||
#define MAGIC_SIZE 6
|
||||
|
||||
const unsigned char magic[7] = "UZEBOX";
|
||||
|
||||
bool isUzeromFile(const char *in_filename)
|
||||
{
|
||||
unsigned char test[MAGIC_SIZE];
|
||||
FILE *f = fopen(in_filename, "rb");
|
||||
if (f)
|
||||
{
|
||||
if (fread(test, 1, MAGIC_SIZE, f) != MAGIC_SIZE)
|
||||
{
|
||||
printf("Error: failed to read the file %s.\n", in_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAGIC_SIZE; i++)
|
||||
{
|
||||
if (test[i] != magic[i])
|
||||
return false;
|
||||
}
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool loadUzeImage(const char *in_filename, RomHeader *header, u8 *buffer)
|
||||
{
|
||||
FILE *f = fopen(in_filename, "rb");
|
||||
size_t ret;
|
||||
if (f)
|
||||
{
|
||||
ret = fread(header, 1, 512, f);
|
||||
if (ret != 512)
|
||||
{
|
||||
printf("Error: failed to read the file %s.\n", in_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header->version != HEADER_VERSION)
|
||||
{
|
||||
printf("Error: cannot parse version %d UzeROM files.\n", header->version);
|
||||
}
|
||||
printf("%s\n", header->name);
|
||||
printf("%s\n", header->author);
|
||||
printf("%d\n", header->year);
|
||||
|
||||
if (header->target == 0)
|
||||
{
|
||||
printf("Uzebox 1.0 - ATmega644\n");
|
||||
}
|
||||
else if (header->target == 1)
|
||||
{
|
||||
printf("Uzebox 2.0 - XTmega128\n");
|
||||
printf("Error: Uzebox 2.0 ROM images are not supported.\n");
|
||||
return false;
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if (fread(buffer, 1, header->progSize, f) != header->progSize)
|
||||
{
|
||||
printf("Erro: failed to read the file %s.\n", in_filename);
|
||||
return false;
|
||||
}
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int parse_hex_nibble(char s)
|
||||
{
|
||||
if (s >= '0' && s <= '9')
|
||||
return s - '0';
|
||||
else if (s >= 'A' && s <= 'F')
|
||||
return s - 'A' + 10;
|
||||
else if (s >= 'a' && s <= 'a')
|
||||
return s - 'a' + 10;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int parse_hex_byte(const char *s)
|
||||
{
|
||||
return (parse_hex_nibble(s[0]) << 4) | parse_hex_nibble(s[1]);
|
||||
}
|
||||
|
||||
static int parse_hex_word(const char *s)
|
||||
{
|
||||
return (parse_hex_nibble(s[0]) << 12) | (parse_hex_nibble(s[1]) << 8) |
|
||||
(parse_hex_nibble(s[2]) << 4) | parse_hex_nibble(s[3]);
|
||||
}
|
||||
|
||||
bool loadHex(const char *in_filename, unsigned char *buffer, unsigned int *bytesRead)
|
||||
{
|
||||
(void)bytesRead;
|
||||
//http://en.wikipedia.org/wiki/.hex
|
||||
|
||||
//(I've added the spaces for clarity, they don't exist in the real files)
|
||||
//:10 65B0 00 661F771F881F991F1A9469F760957095 59
|
||||
//:10 65C0 00 809590959B01AC01BD01CF010895F894 91
|
||||
//:02 65D0 00 FFCF FB
|
||||
//:02 65D2 00 0100 C6
|
||||
//:00 0000 01 FF [EOF marker]
|
||||
|
||||
//First field is the byte count. Second field is the 16-bit address. Third field is the record type;
|
||||
//00 is data, 01 is EOF. For record type zero, next "wide" field is the actual data, followed by a
|
||||
//checksum.
|
||||
u16 progmemLast = 0;
|
||||
char line[128];
|
||||
int lineNumber = 1;
|
||||
|
||||
FILE *in_file = fopen(in_filename, "rb");
|
||||
if (!in_file)
|
||||
return false;
|
||||
|
||||
while (fgets(line, sizeof(line), in_file) && line[0]==':')
|
||||
{
|
||||
int bytes = parse_hex_byte(line + 1);
|
||||
int addr = parse_hex_word(line + 3);
|
||||
int recordType = parse_hex_byte(line + 7);
|
||||
if (recordType == 0)
|
||||
{
|
||||
char *lp = line + 9;
|
||||
while (bytes > 0)
|
||||
{
|
||||
unsigned char value = parse_hex_byte(lp);
|
||||
buffer[addr] = value;
|
||||
addr++;
|
||||
if (addr > progmemLast)
|
||||
{
|
||||
progmemLast = addr;
|
||||
}
|
||||
lp += 2;
|
||||
bytes -= 1;
|
||||
}
|
||||
}
|
||||
else if (recordType == 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "ignoring unknown record type %d in line %d of %s\n", recordType, lineNumber, in_filename);
|
||||
|
||||
++lineNumber;
|
||||
}
|
||||
/*
|
||||
if(bytesRead != 0){
|
||||
*bytesRead=progmemLast;
|
||||
}
|
||||
*/
|
||||
fclose(in_file);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2008-2016 by
|
||||
David Etherton, Eric Anderton, Alec Bourque (Uze), Filipe Rinaldi,
|
||||
Sandor Zsuga (Jubatian), Matt Pandina (Artcfox)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef UZEROM_H
|
||||
|
||||
#define HEADER_VERSION 1
|
||||
#define VERSION_MAJOR 1
|
||||
#define VERSION_MINOR 0
|
||||
#define MAX_PROG_SIZE 61440 //65536-4096
|
||||
#define HEADER_SIZE 512
|
||||
|
||||
#pragma pack( 1 )
|
||||
struct RomHeader{
|
||||
//Header fields (512 bytes)
|
||||
uint8_t marker[6]; //'UZEBOX'
|
||||
uint8_t version; //header version
|
||||
uint8_t target; //AVR target (ATmega644=0, ATmega1284=1)
|
||||
uint32_t progSize; //program memory size in bytes
|
||||
uint16_t year;
|
||||
uint8_t name[32];
|
||||
uint8_t author[32];
|
||||
uint8_t icon[16*16];
|
||||
uint32_t crc32;
|
||||
uint8_t mouse;
|
||||
uint8_t description[64];
|
||||
uint8_t reserved[114];
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
|
||||
/*
|
||||
isUzeromFile - returns true if the file is indeed an .uze file
|
||||
*/
|
||||
bool isUzeromFile(const char* in_filename);
|
||||
|
||||
/*
|
||||
readUzeImage - reads an .uze file into the header and buffer structures provided.
|
||||
*/
|
||||
bool loadUzeImage(const char* in_filename,RomHeader *header,unsigned char *buffer);
|
||||
|
||||
/*
|
||||
load_hex - loads a hex image into the buffer provided, and provides the number of bytes read.
|
||||
*/
|
||||
bool loadHex(const char *in_filename,unsigned char *buffer,unsigned int *bytesRead = 0);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue