Adding Stella as A2600 emulation core (#3911)

* Adding initial version of the core

* Adding base files

* Trying to load waterbox now

* Adding stella

* Adding bk class

* Compiling bk interface to stella core

* Now compiling against Stella + SDL2-based BK backend

* Progress

* More progress

* Frame advancing (no render)

* Calling video update but crashing on zero div

* Now rendering to screen with correct palette

* Now rendering appropriately and with correct palette based on region

* Now reading controls

* Trying to capture audio

* Now adding audio

* Now polling inputs

* Now polling inputs

* Now reporting memory regions

* Added memory regions

* Removing debug prints

* Fixing indent

* Adding stella core

* Updating readme and make all cores

* Recovering ending comma

* Using heap alloc for sound buffer

* Removing unnecessary files

* Update src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.IMemoryDomains.cs

Co-authored-by: James Groom <OSSYoshiRulz+GitHub@gmail.com>

* Update src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.IMemoryDomains.cs

Co-authored-by: James Groom <OSSYoshiRulz+GitHub@gmail.com>

* Fix

* Restoring vscode

* Removing warning

* Update waterbox readme

* Fix Stella's `[Core]` attr

* Increased sound buffer size to 1Mb, as some games need more than 4K

---------

Co-authored-by: James Groom <OSSYoshiRulz+GitHub@gmail.com>
Co-authored-by: Morilli <35152647+Morilli@users.noreply.github.com>
Co-authored-by: YoshiRulz <OSSYoshiRulz+git@gmail.com>
This commit is contained in:
Sergio Martin 2024-09-11 07:18:54 +02:00 committed by GitHub
parent a0800862b3
commit bf8758e61c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
36 changed files with 3203 additions and 2 deletions

View File

@ -60,6 +60,7 @@ jobs:
git submodule update --init gpgx/Genesis-Plus-GX;
git submodule update --init ../submodules/sameboy/libsameboy;
git submodule update --init uae/libretro-uae;
git submodule update --init stella/core;
- name: Download compiled waterbox
uses: actions/download-artifact@v4
with:
@ -100,6 +101,7 @@ jobs:
Assets/dll/turbo.wbx.zst
Assets/dll/uzem.wbx.zst
Assets/dll/vb.wbx.zst
Assets/dll/stella.wbx.zst
Assets/dll/virtualjaguar.wbx.zst
build-mame:

4
.gitmodules vendored
View File

@ -74,6 +74,10 @@
path = waterbox/gpgx/Genesis-Plus-GX
url = https://github.com/TASEmulators/Genesis-Plus-GX.git
branch = tasvideos-2.2
[submodule "waterbox/stella/core"]
path = waterbox/stella/core
url = https://github.com/TASEmulators/stella.git
branch = tasvideos-1
[submodule "waterbox/uae/libretro-uae"]
path = waterbox/uae/libretro-uae
url = https://github.com/TASEmulators/libretro-uae.git

BIN
Assets/dll/stella.wbx.zst Normal file

Binary file not shown.

View File

@ -25,6 +25,8 @@ namespace BizHawk.Client.Common
/// </remarks>
public static readonly IReadOnlyList<(string[] AppliesTo, string[] CoreNames)> CorePickerUIData = new List<(string[], string[])>
{
([ VSystemID.Raw.A26 ],
[ CoreNames.Stella, CoreNames.Atari2600Hawk ]),
([ VSystemID.Raw.Satellaview ],
[ CoreNames.Bsnes115, CoreNames.SubBsnes115 ]),
([ VSystemID.Raw.GB, VSystemID.Raw.GBC ],
@ -49,6 +51,7 @@ namespace BizHawk.Client.Common
[ CoreNames.Snes9X, CoreNames.Bsnes115, CoreNames.SubBsnes115, CoreNames.Faust, CoreNames.Bsnes ]),
([ VSystemID.Raw.TI83 ],
[ CoreNames.Emu83, CoreNames.TI83Hawk ]),
};
public static Dictionary<string, string> GenDefaultCorePreferences()

View File

@ -7,7 +7,8 @@
{
NTSC,
PAL,
Dendy
Dendy,
SECAM
}
/// <summary>

View File

@ -0,0 +1,80 @@
using System.Runtime.InteropServices;
using BizHawk.BizInvoke;
namespace BizHawk.Emulation.Cores.Consoles.Atari.Stella
{
public abstract class CInterface
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int load_archive_cb(string filename, IntPtr buffer, int maxsize);
[StructLayout(LayoutKind.Sequential)]
public class InitSettings
{
public uint dummy;
}
[BizImport(CallingConvention.Cdecl)]
public abstract void stella_get_audio(ref int n, ref IntPtr buffer);
[BizImport(CallingConvention.Cdecl)]
public abstract int stella_get_region();
[BizImport(CallingConvention.Cdecl)]
public abstract bool stella_init(
string fileName,
load_archive_cb feload_archive_cb,
[In]InitSettings settings);
[BizImport(CallingConvention.Cdecl)]
public abstract void stella_frame_advance(int port1, int port2, bool reset, bool power, bool leftDiffToggled, bool rightDiffToggled);
[BizImport(CallingConvention.Cdecl)]
public abstract void stella_get_video(out int w, out int h, out int pitch, ref IntPtr buffer);
[BizImport(CallingConvention.Cdecl)]
public abstract void stella_get_frame_rate(out int fps);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void input_cb();
[BizImport(CallingConvention.Cdecl)]
public abstract void stella_set_input_callback(input_cb cb);
[BizImport(CallingConvention.Cdecl)]
public abstract byte stella_peek_tia(uint addr);
[BizImport(CallingConvention.Cdecl)]
public abstract void stella_poke_tia(uint addr, byte value);
[BizImport(CallingConvention.Cdecl)]
public abstract byte stella_peek_m6532(uint addr);
[BizImport(CallingConvention.Cdecl)]
public abstract void stella_poke_m6532(uint addr, byte value);
[BizImport(CallingConvention.Cdecl)]
public abstract byte stella_peek_systembus(uint addr);
[BizImport(CallingConvention.Cdecl)]
public abstract void stella_poke_systembus(uint addr, byte value);
[BizImport(CallingConvention.Cdecl)]
public abstract uint stella_get_cartram_size();
[BizImport(CallingConvention.Cdecl)]
public abstract byte stella_peek_cartram(uint addr);
[BizImport(CallingConvention.Cdecl)]
public abstract void stella_poke_cartram(uint addr, byte value);
[BizImport(CallingConvention.Cdecl)]
public abstract void stella_get_mainram_ptr(ref IntPtr addr);
[BizImport(CallingConvention.Cdecl)]
public abstract IntPtr stella_get_cart_type();
}
}

View File

@ -0,0 +1,99 @@
using BizHawk.Emulation.Cores.Components.M6502;
using System.Runtime.CompilerServices;
namespace BizHawk.Emulation.Cores.Atari.Stella
{
public partial class Stella
{
internal struct CpuLink : IMOS6502XLink
{
public byte DummyReadMemory(ushort address) { return 0; }
public void OnExecFetch(ushort address) { }
public byte PeekMemory(ushort address) { return 0; }
public byte ReadMemory(ushort address) { return 0; }
public void WriteMemory(ushort address, byte value) { }
}
internal byte BaseReadMemory(ushort addr)
{
return 0;
}
internal byte BasePeekMemory(ushort addr)
{
return 0;
}
internal void BaseWriteMemory(ushort addr, byte value)
{
}
internal void BasePokeMemory(ushort addr, byte value)
{
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private byte ReadMemory(ushort addr)
{
return 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void WriteMemory(ushort addr, byte value)
{
}
internal void PokeMemory(ushort addr, byte value)
{
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ExecFetch(ushort addr)
{
}
private void RebootCore()
{
}
private void HardReset()
{
}
private void Cycle()
{
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal byte ReadControls1(bool peek)
{
return 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal byte ReadControls2(bool peek)
{
return 0;
}
internal int ReadPot1(int pot)
{
return 0;
}
internal int ReadPot2(int pot)
{
return 0;
}
internal byte ReadConsoleSwitches(bool peek)
{
return 0;
}
}
}

View File

@ -0,0 +1,65 @@
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Atari.Stella
{
public partial class Stella : IEmulator
{
public IEmulatorServiceProvider ServiceProvider { get; }
public ControllerDefinition ControllerDefinition => _controllerDeck.Definition;
private bool _leftDifficultyToggled = false;
private bool _rightDifficultyToggled = false;
public bool FrameAdvance(IController controller, bool render, bool renderSound)
{
int port1 = _controllerDeck.ReadPort1(controller);
int port2 = _controllerDeck.ReadPort2(controller);
// Handle all the console controls here
bool powerPressed = false;
bool resetPressed = false;
if (controller.IsPressed("Power")) powerPressed = true;
if (controller.IsPressed("Reset")) resetPressed = true;
if (controller.IsPressed("Toggle Left Difficulty")) _leftDifficultyToggled = !_leftDifficultyToggled;
if (controller.IsPressed("Toggle Right Difficulty")) _rightDifficultyToggled = !_rightDifficultyToggled;
IsLagFrame = true;
Core.stella_frame_advance(port1, port2, resetPressed, powerPressed, _leftDifficultyToggled, _rightDifficultyToggled);
if (IsLagFrame)
LagCount++;
if (render)
UpdateVideo();
if (renderSound)
update_audio();
_frame++;
return true;
}
public int _frame;
public int Frame => _frame;
public string SystemId => VSystemID.Raw.A26;
public bool DeterministicEmulation => true;
public void ResetCounters()
{
_frame = 0;
LagCount = 0;
IsLagFrame = false;
}
public void Dispose()
{
}
}
}

View File

@ -0,0 +1,24 @@
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Consoles.Atari.Stella;
namespace BizHawk.Emulation.Cores.Atari.Stella
{
public partial class Stella : IInputPollable
{
public int LagCount { get; set; }
public bool IsLagFrame { get; set; }
public IInputCallbackSystem InputCallbacks => _inputCallbacks;
private readonly CInterface.input_cb _inputCallback;
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
private void input_callback()
{
InputCallbacks.Call();
IsLagFrame = false;
}
}
}

View File

@ -0,0 +1,64 @@
using System.Collections.Generic;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Atari.Stella
{
public partial class Stella
{
internal IMemoryDomains MemoryDomains;
private uint _cartMemSize;
private void SetupMemoryDomains()
{
_cartMemSize = Core.stella_get_cartram_size();
var mainRamAddress = IntPtr.Zero;
var cartDPCRamAddress = IntPtr.Zero;
Core.stella_get_mainram_ptr(ref mainRamAddress);
var domains = new List<MemoryDomain>
{
new MemoryDomainDelegate(
"TIA",
16,
MemoryDomain.Endian.Little,
addr => Core.stella_peek_tia((uint)addr),
(addr, value) => Core.stella_poke_tia((uint)addr, value),
1),
new MemoryDomainDelegate(
"PIA",
1024,
MemoryDomain.Endian.Little,
addr => Core.stella_peek_m6532((uint)addr),
(addr, value) => Core.stella_poke_m6532((uint)addr, value),
1),
new MemoryDomainDelegate(
"System Bus",
65536,
MemoryDomain.Endian.Little,
addr => Core.stella_peek_systembus((uint) addr),
(addr, value) => Core.stella_poke_systembus((uint) addr, value),
1)
};
if (_cartMemSize > 0)
{
domains.Add(new MemoryDomainDelegate(
"Cart Ram",
_cartMemSize,
MemoryDomain.Endian.Little,
addr => Core.stella_peek_cartram((uint)addr),
(addr, value) => Core.stella_poke_cartram((uint)addr, value),
1));
}
MemoryDomainIntPtrMonitor mainRAM = new("Main RAM", MemoryDomain.Endian.Little, mainRamAddress, 128, true, 1, _elf);
domains.Add(mainRAM);
MemoryDomains = new MemoryDomainList(domains) { MainMemory = mainRAM };
((BasicServiceProvider)ServiceProvider).Register(MemoryDomains);
}
}
}

View File

@ -0,0 +1,206 @@
using System.ComponentModel;
using System.Drawing;
using Newtonsoft.Json;
using BizHawk.Emulation.Common;
using BizHawk.Common;
using BizHawk.Emulation.Cores.Consoles.Atari.Stella;
namespace BizHawk.Emulation.Cores.Atari.Stella
{
public partial class Stella : ISettable<Stella.A2600Settings, Stella.A2600SyncSettings>
{
public A2600Settings GetSettings()
{
return Settings.Clone();
}
public A2600SyncSettings GetSyncSettings()
{
return SyncSettings.Clone();
}
public PutSettingsDirtyBits PutSettings(A2600Settings o)
{
Settings = o;
return PutSettingsDirtyBits.None;
}
public PutSettingsDirtyBits PutSyncSettings(A2600SyncSettings o)
{
bool ret = A2600SyncSettings.NeedsReboot(SyncSettings, o);
SyncSettings = o;
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
}
internal A2600Settings Settings { get; private set; }
internal A2600SyncSettings SyncSettings { get; private set; }
[CoreSettings]
public class A2600Settings
{
[JsonIgnore]
private int _ntscTopLine;
[JsonIgnore]
private int _ntscBottomLine;
[JsonIgnore]
private int _palTopLine;
[JsonIgnore]
private int _palBottomLine;
[DisplayName("Show Background")]
[Description("Sets whether or not the Background layer will be displayed")]
[DefaultValue(true)]
public bool ShowBG { get; set; }
[DisplayName("Show Player 1")]
[Description("Sets whether or not the Player 1 layer will be displayed")]
[DefaultValue(true)]
public bool ShowPlayer1 { get; set; }
[DisplayName("Show Player 2")]
[Description("Sets whether or not the Player 2 layer will be displayed")]
[DefaultValue(true)]
public bool ShowPlayer2 { get; set; }
[DisplayName("Show Missle 1")]
[Description("Sets whether or not the Missle 1 layer will be displayed")]
[DefaultValue(true)]
public bool ShowMissle1 { get; set; }
[DisplayName("Show Missle 2")]
[Description("Sets whether or not the Missle 2 layer will be displayed")]
[DefaultValue(true)]
public bool ShowMissle2 { get; set; }
[DisplayName("Show Ball")]
[Description("Sets whether or not the Ball layer will be displayed")]
[DefaultValue(true)]
public bool ShowBall { get; set; }
[DisplayName("Show Playfield")]
[Description("Sets whether or not the Playfield layer will be displayed")]
[DefaultValue(true)]
public bool ShowPlayfield { get; set; }
[DisplayName("SECAM Colors")]
[Description("If true, PAL mode will show with SECAM (French) colors.")]
[DefaultValue(false)]
public bool SECAMColors { get; set; }
[DisplayName("NTSC Top Line")]
[Description("First line of the video image to display in NTSC mode.")]
[DefaultValue(24)]
public int NTSCTopLine
{
get => _ntscTopLine;
set => _ntscTopLine = Math.Min(64, Math.Max(value, 0));
}
[DisplayName("NTSC Bottom Line")]
[Description("Last line of the video image to display in NTSC mode.")]
[DefaultValue(248)]
public int NTSCBottomLine
{
get => _ntscBottomLine;
set => _ntscBottomLine = Math.Min(260, Math.Max(value, 192));
}
[DisplayName("PAL Top Line")]
[Description("First line of the video image to display in PAL mode.")]
[DefaultValue(24)]
public int PALTopLine
{
get => _palTopLine;
set => _palTopLine = Math.Min(64, Math.Max(value, 0));
}
[DisplayName("PAL Bottom Line")]
[Description("Last line of the video image to display in PAL mode.")]
[DefaultValue(296)]
public int PALBottomLine
{
get => _palBottomLine;
set => _palBottomLine = Math.Min(310, Math.Max(value, 192));
}
[DisplayName("Background Color")]
[DefaultValue(typeof(Color), "Black")]
public Color BackgroundColor { get; set; }
public A2600Settings Clone()
{
return (A2600Settings)MemberwiseClone();
}
public A2600Settings()
{
SettingsUtil.SetDefaultValues(this);
}
}
[CoreSettings]
public class A2600SyncSettings
{
[DefaultValue(Atari2600ControllerTypes.Joystick)]
[DisplayName("Port 1 Device")]
[Description("The type of controller plugged into the first controller port")]
[TypeConverter(typeof(DescribableEnumConverter))]
public Atari2600ControllerTypes Port1 { get; set; } = Atari2600ControllerTypes.Joystick;
[DefaultValue(Atari2600ControllerTypes.Joystick)]
[DisplayName("Port 2 Device")]
[Description("The type of controller plugged into the second controller port")]
[TypeConverter(typeof(DescribableEnumConverter))]
public Atari2600ControllerTypes Port2 { get; set; } = Atari2600ControllerTypes.Joystick;
[DisplayName("Black and White Mode")]
[Description("Set the TV Type switch on the console to B&W or Color. This only affects the displayed image if the game supports it.")]
[DefaultValue(false)]
public bool BW { get; set; }
[DisplayName("Left Difficulty")]
[Description("Set the Left Difficulty switch on the console")]
[DefaultValue(true)]
public bool LeftDifficulty { get; set; }
[DisplayName("Right Difficulty")]
[Description("Set the Right Difficulty switch on the console")]
[DefaultValue(true)]
public bool RightDifficulty { get; set; }
[DisplayName("Super Charger BIOS Skip")]
[Description("On Super Charger carts, this will skip the BIOS intro")]
[DefaultValue(false)]
public bool FastScBios { get; set; }
public CInterface.InitSettings GetNativeSettings(GameInfo game)
{
return new CInterface.InitSettings
{
dummy = 1
};
}
public A2600SyncSettings Clone()
{
return (A2600SyncSettings)MemberwiseClone();
}
public A2600SyncSettings()
{
SettingsUtil.SetDefaultValues(this);
}
public static bool NeedsReboot(A2600SyncSettings x, A2600SyncSettings y)
{
return !DeepEquality.DeepEquals(x, y);
}
}
}
}

View File

@ -0,0 +1,53 @@
using BizHawk.Emulation.Common;
using System.Runtime.InteropServices;
using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Atari.Stella
{
public partial class Stella : ISoundProvider
{
private readonly short[] _samples = new short[4096];
private int _nsamp;
public bool CanProvideAsync => false;
public void GetSamplesSync(out short[] samples, out int nsamp)
{
nsamp = _nsamp;
samples = _samples;
_nsamp = 0;
}
public void DiscardSamples()
{
_nsamp = 0;
}
public void SetSyncMode(SyncSoundMode mode)
{
if (mode == SyncSoundMode.Async)
{
throw new NotSupportedException("Async mode is not supported.");
}
}
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
public void GetSamplesAsync(short[] samples)
{
throw new InvalidOperationException("Async mode is not supported.");
}
private void update_audio()
{
IntPtr src = IntPtr.Zero;
Core.stella_get_audio(ref _nsamp, ref src);
if (src != IntPtr.Zero)
{
using (_elf.EnterExit())
Marshal.Copy(src, _samples, 0, _nsamp * 2);
}
}
}
}

View File

@ -0,0 +1,31 @@
using System.IO;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Atari.Stella
{
public partial class Stella : IStatable
{
public bool AvoidRewind => false;
public void LoadStateBinary(BinaryReader reader)
{
_elf.LoadStateBinary(reader);
// other variables
_frame = reader.ReadInt32();
LagCount = reader.ReadInt32();
IsLagFrame = reader.ReadBoolean();
// any managed pointers that we sent to the core need to be resent now!
Core.stella_set_input_callback(_inputCallback);
UpdateVideo();
}
public void SaveStateBinary(BinaryWriter writer)
{
_elf.SaveStateBinary(writer);
// other variables
writer.Write(Frame);
writer.Write(LagCount);
writer.Write(IsLagFrame);
}
}
}

View File

@ -0,0 +1,81 @@
using BizHawk.Emulation.Common;
using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Atari.Stella
{
public partial class Stella : IVideoProvider
{
public int[] GetVideoBuffer() => _vidBuff;
public int VirtualWidth => 160;
public int VirtualHeight => 192;
public int BufferWidth => _vwidth;
public int BufferHeight => _vheight;
public int BackgroundColor => unchecked((int)0xff000000);
public int VsyncNumerator { get; }
public int VsyncDenominator { get; }
private int[] _vidBuff = new int[0];
private int _vwidth;
private int _vheight;
private void UpdateVideoInitial()
{
// hack: you should call update_video() here, but that gives you 256x192 on frame 0
// and we know that we only use GPGX to emulate genesis games that will always be 320x224 immediately afterwards
// so instead, just assume a 320x224 size now; if that happens to be wrong, it'll be fixed soon enough.
_vwidth = 320;
_vheight = 224;
_vidBuff = new int[_vwidth * _vheight];
for (int i = 0; i < _vidBuff.Length; i++)
{
_vidBuff[i] = unchecked((int)0xff000000);
}
}
private readonly byte[] TwoBitToEightBitTable = new byte[] { 0, 85, 171, 255 };
private readonly byte[] ThreeBitToEightBitTable = new byte[] { 0, 36, 73, 109, 146, 182, 219, 255 };
private unsafe void UpdateVideo()
{
if (Frame == 0)
{
UpdateVideoInitial();
return;
}
using (_elf.EnterExit())
{
IntPtr src = IntPtr.Zero;
Core.stella_get_video(out var width, out var height, out var pitch, ref src);
_vwidth = width;
_vheight = height;
byte* buffer = (byte*)src.ToPointer();
if (_vidBuff.Length < _vwidth * _vheight)
_vidBuff = new int[_vwidth * _vheight];
if (Region == DisplayType.NTSC)
for (int i = 0; i < _vidBuff.Length; i++) _vidBuff[i] = NTSCPalette[buffer[i]];
if (Region == DisplayType.PAL)
for (int i = 0; i < _vidBuff.Length; i++) _vidBuff[i] = PALPalette[buffer[i]];
if (Region == DisplayType.SECAM)
for (int i = 0; i < _vidBuff.Length; i++) _vidBuff[i] = SecamPalette[buffer[i]];
}
}
}
}

View File

@ -0,0 +1,207 @@
namespace BizHawk.Emulation.Cores.Atari.Stella
{
public partial class Stella
{
private static readonly int[] PALPalette =
{
0x000000, 0x000000, 0x2b2b2b, 0x2b2b2b,
0x525252, 0x525252, 0x767676, 0x767676,
0x979797, 0x979797, 0xb6b6b6, 0xb6b6b6,
0xd2d2d2, 0xd2d2d2, 0xececec, 0xececec,
0x000000, 0x000000, 0x2b2b2b, 0x2b2b2b,
0x525252, 0x525252, 0x767676, 0x767676,
0x979797, 0x979797, 0xb6b6b6, 0xb6b6b6,
0xd2d2d2, 0xd2d2d2, 0xececec, 0xececec,
0x805800, 0x000000, 0x96711a, 0x2b2b2b,
0xab8732, 0x525252, 0xbe9c48, 0x767676,
0xcfaf5c, 0x979797, 0xdfc06f, 0xb6b6b6,
0xeed180, 0xd2d2d2, 0xfce090, 0xececec,
0x445c00, 0x000000, 0x5e791a, 0x2b2b2b,
0x769332, 0x525252, 0x8cac48, 0x767676,
0xa0c25c, 0x979797, 0xb3d76f, 0xb6b6b6,
0xc4ea80, 0xd2d2d2, 0xd4fc90, 0xececec,
0x703400, 0x000000, 0x89511a, 0x2b2b2b,
0xa06b32, 0x525252, 0xb68448, 0x767676,
0xc99a5c, 0x979797, 0xdcaf6f, 0xb6b6b6,
0xecc280, 0xd2d2d2, 0xfcd490, 0xececec,
0x006414, 0x000000, 0x1a8035, 0x2b2b2b,
0x329852, 0x525252, 0x48b06e, 0x767676,
0x5cc587, 0x979797, 0x6fd99e, 0xb6b6b6,
0x80ebb4, 0xd2d2d2, 0x90fcc8, 0xececec,
0x700014, 0x000000, 0x891a35, 0x2b2b2b,
0xa03252, 0x525252, 0xb6486e, 0x767676,
0xc95c87, 0x979797, 0xdc6f9e, 0xb6b6b6,
0xec80b4, 0xd2d2d2, 0xfc90c8, 0xececec,
0x005c5c, 0x000000, 0x1a7676, 0x2b2b2b,
0x328e8e, 0x525252, 0x48a4a4, 0x767676,
0x5cb8b8, 0x979797, 0x6fcbcb, 0xb6b6b6,
0x80dcdc, 0xd2d2d2, 0x90ecec, 0xececec,
0x70005c, 0x000000, 0x841a74, 0x2b2b2b,
0x963289, 0x525252, 0xa8489e, 0x767676,
0xb75cb0, 0x979797, 0xc66fc1, 0xb6b6b6,
0xd380d1, 0xd2d2d2, 0xe090e0, 0xececec,
0x003c70, 0x000000, 0x195a89, 0x2b2b2b,
0x2f75a0, 0x525252, 0x448eb6, 0x767676,
0x57a5c9, 0x979797, 0x68badc, 0xb6b6b6,
0x79ceec, 0xd2d2d2, 0x88e0fc, 0xececec,
0x580070, 0x000000, 0x6e1a89, 0x2b2b2b,
0x8332a0, 0x525252, 0x9648b6, 0x767676,
0xa75cc9, 0x979797, 0xb76fdc, 0xb6b6b6,
0xc680ec, 0xd2d2d2, 0xd490fc, 0xececec,
0x002070, 0x000000, 0x193f89, 0x2b2b2b,
0x2f5aa0, 0x525252, 0x4474b6, 0x767676,
0x578bc9, 0x979797, 0x68a1dc, 0xb6b6b6,
0x79b5ec, 0xd2d2d2, 0x88c8fc, 0xececec,
0x340080, 0x000000, 0x4a1a96, 0x2b2b2b,
0x5f32ab, 0x525252, 0x7248be, 0x767676,
0x835ccf, 0x979797, 0x936fdf, 0xb6b6b6,
0xa280ee, 0xd2d2d2, 0xb090fc, 0xececec,
0x000088, 0x000000, 0x1a1a9d, 0x2b2b2b,
0x3232b0, 0x525252, 0x4848c2, 0x767676,
0x5c5cd2, 0x979797, 0x6f6fe1, 0xb6b6b6,
0x8080ef, 0xd2d2d2, 0x9090fc, 0xececec,
0x000000, 0x000000, 0x2b2b2b, 0x2b2b2b,
0x525252, 0x525252, 0x767676, 0x767676,
0x979797, 0x979797, 0xb6b6b6, 0xb6b6b6,
0xd2d2d2, 0xd2d2d2, 0xececec, 0xececec,
0x000000, 0x000000, 0x2b2b2b, 0x2b2b2b,
0x525252, 0x525252, 0x767676, 0x767676,
0x979797, 0x979797, 0xb6b6b6, 0xb6b6b6,
0xd2d2d2, 0xd2d2d2, 0xececec, 0xececec
};
private static readonly int[] NTSCPalette =
{
0x000000, 0, 0x4a4a4a, 0, 0x6f6f6f, 0, 0x8e8e8e, 0,
0xaaaaaa, 0, 0xc0c0c0, 0, 0xd6d6d6, 0, 0xececec, 0,
0x484800, 0, 0x69690f, 0, 0x86861d, 0, 0xa2a22a, 0,
0xbbbb35, 0, 0xd2d240, 0, 0xe8e84a, 0, 0xfcfc54, 0,
0x7c2c00, 0, 0x904811, 0, 0xa26221, 0, 0xb47a30, 0,
0xc3903d, 0, 0xd2a44a, 0, 0xdfb755, 0, 0xecc860, 0,
0x901c00, 0, 0xa33915, 0, 0xb55328, 0, 0xc66c3a, 0,
0xd5824a, 0, 0xe39759, 0, 0xf0aa67, 0, 0xfcbc74, 0,
0x940000, 0, 0xa71a1a, 0, 0xb83232, 0, 0xc84848, 0,
0xd65c5c, 0, 0xe46f6f, 0, 0xf08080, 0, 0xfc9090, 0,
0x840064, 0, 0x97197a, 0, 0xa8308f, 0, 0xb846a2, 0,
0xc659b3, 0, 0xd46cc3, 0, 0xe07cd2, 0, 0xec8ce0, 0,
0x500084, 0, 0x68199a, 0, 0x7d30ad, 0, 0x9246c0, 0,
0xa459d0, 0, 0xb56ce0, 0, 0xc57cee, 0, 0xd48cfc, 0,
0x140090, 0, 0x331aa3, 0, 0x4e32b5, 0, 0x6848c6, 0,
0x7f5cd5, 0, 0x956fe3, 0, 0xa980f0, 0, 0xbc90fc, 0,
0x000094, 0, 0x181aa7, 0, 0x2d32b8, 0, 0x4248c8, 0,
0x545cd6, 0, 0x656fe4, 0, 0x7580f0, 0, 0x8490fc, 0,
0x001c88, 0, 0x183b9d, 0, 0x2d57b0, 0, 0x4272c2, 0,
0x548ad2, 0, 0x65a0e1, 0, 0x75b5ef, 0, 0x84c8fc, 0,
0x003064, 0, 0x185080, 0, 0x2d6d98, 0, 0x4288b0, 0,
0x54a0c5, 0, 0x65b7d9, 0, 0x75cceb, 0, 0x84e0fc, 0,
0x004030, 0, 0x18624e, 0, 0x2d8169, 0, 0x429e82, 0,
0x54b899, 0, 0x65d1ae, 0, 0x75e7c2, 0, 0x84fcd4, 0,
0x004400, 0, 0x1a661a, 0, 0x328432, 0, 0x48a048, 0,
0x5cba5c, 0, 0x6fd26f, 0, 0x80e880, 0, 0x90fc90, 0,
0x143c00, 0, 0x355f18, 0, 0x527e2d, 0, 0x6e9c42, 0,
0x87b754, 0, 0x9ed065, 0, 0xb4e775, 0, 0xc8fc84, 0,
0x303800, 0, 0x505916, 0, 0x6d762b, 0, 0x88923e, 0,
0xa0ab4f, 0, 0xb7c25f, 0, 0xccd86e, 0, 0xe0ec7c, 0,
0x482c00, 0, 0x694d14, 0, 0x866a26, 0, 0xa28638, 0,
0xbb9f47, 0, 0xd2b656, 0, 0xe8cc63, 0, 0xfce070, 0
};
private static readonly int[] SecamPalette =
{
0x000000, 0x000000, 0x2121FF, 0x2121FF,
0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF,
0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF,
0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff,
0x000000, 0x000000, 0x2121FF, 0x2121FF,
0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF,
0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF,
0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff,
0x000000, 0x000000, 0x2121FF, 0x2121FF,
0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF,
0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF,
0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff,
0x000000, 0x000000, 0x2121FF, 0x2121FF,
0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF,
0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF,
0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff,
0x000000, 0x000000, 0x2121FF, 0x2121FF,
0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF,
0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF,
0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff,
0x000000, 0x000000, 0x2121FF, 0x2121FF,
0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF,
0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF,
0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff,
0x000000, 0x000000, 0x2121FF, 0x2121FF,
0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF,
0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF,
0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff,
0x000000, 0x000000, 0x2121FF, 0x2121FF,
0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF,
0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF,
0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff,
0x000000, 0x000000, 0x2121FF, 0x2121FF,
0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF,
0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF,
0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff,
0x000000, 0x000000, 0x2121FF, 0x2121FF,
0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF,
0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF,
0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff,
0x000000, 0x000000, 0x2121FF, 0x2121FF,
0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF,
0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF,
0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff,
0x000000, 0x000000, 0x2121FF, 0x2121FF,
0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF,
0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF,
0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff,
0x000000, 0x000000, 0x2121FF, 0x2121FF,
0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF,
0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF,
0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff,
0x000000, 0x000000, 0x2121FF, 0x2121FF,
0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF,
0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF,
0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff,
0x000000, 0x000000, 0x2121FF, 0x2121FF,
0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF,
0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF,
0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff,
0x000000, 0x000000, 0x2121FF, 0x2121FF,
0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF,
0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF,
0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff
};
}
}

View File

@ -0,0 +1,185 @@
using System.Linq;
using System.Runtime.InteropServices;
using BizHawk.BizInvoke;
using BizHawk.Common;
using BizHawk.Common.PathExtensions;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Consoles.Atari.Stella;
using BizHawk.Emulation.Cores.Waterbox;
namespace BizHawk.Emulation.Cores.Atari.Stella
{
[PortedCore(
name: CoreNames.Stella,
author: "The Stella Team",
// portedVersion: "", //TODO
portedUrl: "https://stella-emu.github.io")]
[ServiceNotApplicable(new[] { typeof(IDriveLight), typeof(ISaveRam) })]
public partial class Stella : IEmulator, IVideoProvider, IInputPollable, IRomInfo, IRegionable,
ICreateGameDBEntries, ISettable<Stella.A2600Settings, Stella.A2600SyncSettings>
{
internal static class RomChecksums
{
public const string CongoBongo = "SHA1:3A77DB43B6583E8689435F0F14AA04B9E57BDDED";
public const string KangarooNotInGameDB = "SHA1:982B8016B393A9AA7DD110295A53C4612ECF2141";
public const string Tapper = "SHA1:E986E1818E747BEB9B33CE4DFF1CDC6B55BDB620";
}
[CoreConstructor(VSystemID.Raw.A26)]
public Stella(CoreLoadParameters<Stella.A2600Settings, Stella.A2600SyncSettings> lp)
{
var ser = new BasicServiceProvider(this);
ServiceProvider = ser;
SyncSettings = lp.SyncSettings ?? new A2600SyncSettings();
Settings = lp.Settings ?? new A2600Settings();
_controllerDeck = new Atari2600ControllerDeck(SyncSettings.Port1, SyncSettings.Port2);
_elf = new WaterboxHost(new WaterboxOptions
{
Path = PathUtils.DllDirectoryPath,
Filename = "stella.wbx",
SbrkHeapSizeKB = 4 * 1024,
SealedHeapSizeKB = 4 * 1024,
InvisibleHeapSizeKB = 4 * 1024,
PlainHeapSizeKB = 4 * 1024,
MmapHeapSizeKB = 4 * 1024,
SkipCoreConsistencyCheck = lp.Comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck),
SkipMemoryConsistencyCheck = lp.Comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck),
});
LoadCallback = load_archive;
_inputCallback = input_callback;
var callingConventionAdapter = CallingConventionAdapters.MakeWaterbox(new Delegate[]
{
LoadCallback, _inputCallback
}, _elf);
using (_elf.EnterExit())
{
Core = BizInvoker.GetInvoker<CInterface>(_elf, _elf, callingConventionAdapter);
SyncSettings = lp.SyncSettings ?? new A2600SyncSettings();
Settings = lp.Settings ?? new A2600Settings();
CoreComm = lp.Comm;
_romfile = lp.Roms.FirstOrDefault()?.RomData;
string romPath = lp.Roms.FirstOrDefault()?.RomPath;
var initResult = Core.stella_init(romPath, LoadCallback, SyncSettings.GetNativeSettings(lp.Game));
if (!initResult) throw new Exception($"{nameof(Core.stella_init)}() failed");
Core.stella_get_frame_rate(out int fps);
int regionId = Core.stella_get_region();
if (regionId == 0) _region = DisplayType.NTSC;
if (regionId == 1) _region = DisplayType.PAL;
if (regionId == 2) _region = DisplayType.SECAM;
VsyncNumerator = fps;
VsyncDenominator = 1;
Core.stella_set_input_callback(_inputCallback);
// Getting cartridge type
var ptr = Core.stella_get_cart_type();
string _cartType = Marshal.PtrToStringAnsi(ptr);
Console.WriteLine("[Stella] Cart type loaded: {0} (string size: {1}, ptr: {2})", _cartType, _cartType.Length, ptr);
_elf.Seal();
}
// pull the default video size from the core
UpdateVideo();
// Registering memory domains
SetupMemoryDomains();
}
// IRegionable
public DisplayType Region => _region;
private DisplayType _region;
private CInterface.load_archive_cb LoadCallback;
private readonly byte[] _romfile;
private readonly CInterface Core;
private readonly WaterboxHost _elf;
private string _cartType { get; }
private CoreComm CoreComm { get; }
public string RomDetails { get; private set; }
private readonly Atari2600ControllerDeck _controllerDeck;
private ITraceable Tracer { get; }
// ICreateGameDBEntries
public CompactGameInfo GenerateGameDbEntry()
{
return new CompactGameInfo
{
};
}
// IBoardInfo
private static bool DetectPal(GameInfo game, byte[] rom)
{
return true;
}
/// <summary>
/// core callback for file loading
/// </summary>
/// <param name="filename">string identifying file to be loaded</param>
/// <param name="buffer">buffer to load file to</param>
/// <param name="maxsize">maximum length buffer can hold</param>
/// <returns>actual size loaded, or 0 on failure</returns>
private int load_archive(string filename, IntPtr buffer, int maxsize)
{
byte[] srcdata = null;
if (buffer == IntPtr.Zero)
{
Console.WriteLine("Couldn't satisfy firmware request {0} because buffer == NULL", filename);
return 0;
}
if (filename == "PRIMARY_ROM")
{
if (_romfile == null)
{
Console.WriteLine("Couldn't satisfy firmware request PRIMARY_ROM because none was provided.");
return 0;
}
srcdata = _romfile;
}
if (srcdata != null)
{
if (srcdata.Length > maxsize)
{
Console.WriteLine("Couldn't satisfy firmware request {0} because {1} > {2}", filename, srcdata.Length, maxsize);
return 0;
}
else
{
Console.WriteLine("Copying Data from " + srcdata + " to " + buffer + " Size: " + srcdata.Length);
Marshal.Copy(srcdata, 0, buffer, srcdata.Length);
Console.WriteLine("Firmware request {0} satisfied at size {1}", filename, srcdata.Length);
return srcdata.Length;
}
}
else
{
throw new InvalidOperationException("Unknown error processing firmware");
}
}
}
}

View File

@ -0,0 +1,83 @@
using System.Collections.Generic;
using System.Linq;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Atari.Stella
{
public class Atari2600ControllerDeck
{
public Atari2600ControllerDeck(Atari2600ControllerTypes controller1, Atari2600ControllerTypes controller2)
{
Port1 = ControllerCtors[controller1](1);
Port2 = ControllerCtors[controller2](2);
Definition = new("Atari 2600 Basic Controller")
{
BoolButtons = Port1.Definition.BoolButtons
.Concat(Port2.Definition.BoolButtons)
.Concat(new[]
{
"Reset", "Select", "Power", "Toggle Left Difficulty", "Toggle Right Difficulty"
})
.ToList()
};
foreach (var kvp in Port1.Definition.Axes) Definition.Axes.Add(kvp);
foreach (var kvp in Port2.Definition.Axes) Definition.Axes.Add(kvp);
Definition.MakeImmutable();
}
public byte ReadPort1(IController c)
{
return Port1.Read(c);
}
public byte ReadPort2(IController c)
{
return Port2.Read(c);
}
public int ReadPot1(IController c, int pot)
{
return Port1.Read_Pot(c, pot);
}
public int ReadPot2(IController c, int pot)
{
return Port2.Read_Pot(c, pot);
}
public ControllerDefinition Definition { get; }
public void SyncState(Serializer ser)
{
ser.BeginSection(nameof(Port1));
Port1.SyncState(ser);
ser.EndSection();
ser.BeginSection(nameof(Port2));
Port2.SyncState(ser);
ser.EndSection();
}
private readonly IPort Port1;
private readonly IPort Port2;
private static IReadOnlyDictionary<Atari2600ControllerTypes, Func<int, IPort>> _controllerCtors;
public static IReadOnlyDictionary<Atari2600ControllerTypes, Func<int, IPort>> ControllerCtors => _controllerCtors
??= new Dictionary<Atari2600ControllerTypes, Func<int, IPort>>
{
[Atari2600ControllerTypes.Unplugged] = portNum => new UnpluggedController(portNum),
[Atari2600ControllerTypes.Joystick] = portNum => new StandardController(portNum),
[Atari2600ControllerTypes.Paddle] = portNum => new PaddleController(portNum),
[Atari2600ControllerTypes.BoostGrip] = portNum => new BoostGripController(portNum),
[Atari2600ControllerTypes.Driving] = portNum => new DrivingController(portNum),
[Atari2600ControllerTypes.Keyboard] = portNum => new KeyboardController(portNum)
};
}
}

View File

@ -0,0 +1,375 @@
using System.Linq;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Atari.Stella
{
public enum Atari2600ControllerTypes
{
Unplugged,
Joystick,
Paddle,
BoostGrip,
Driving,
Keyboard
}
/// <summary>
/// Represents a controller plugged into a controller port on the 2600
/// </summary>
public interface IPort
{
byte Read(IController c);
int Read_Pot(IController c, int pot);
ControllerDefinition Definition { get; }
void SyncState(Serializer ser);
int PortNum { get; }
}
public class UnpluggedController : IPort
{
public UnpluggedController(int portNum)
{
PortNum = portNum;
Definition = new("(Atari 2600 Basic Controller fragment)");
}
public byte Read(IController c)
{
return 0xFF;
}
public int Read_Pot(IController c, int pot)
{
return -1; // indicates not applicable
}
public ControllerDefinition Definition { get; }
public void SyncState(Serializer ser)
{
// Do nothing
}
public int PortNum { get; }
}
public class StandardController : IPort
{
public StandardController(int portNum)
{
PortNum = portNum;
Definition = new("(Atari 2600 Basic Controller fragment)")
{
BoolButtons = BaseDefinition
.Select(b => $"P{PortNum} " + b)
.ToList()
};
}
public ControllerDefinition Definition { get; }
public void SyncState(Serializer ser)
{
// Nothing todo, I think
}
public int PortNum { get; }
public byte Read(IController c)
{
byte result = 0xFF;
if (c.IsPressed($"P{PortNum} Up")) { result &= 0xEF; }
if (c.IsPressed($"P{PortNum} Down")) { result &= 0xDF; }
if (c.IsPressed($"P{PortNum} Left")) { result &= 0xBF; }
if (c.IsPressed($"P{PortNum} Right")) { result &= 0x7F; }
if (c.IsPressed($"P{PortNum} Button")) { result &= 0xF7; }
return result;
}
public int Read_Pot(IController c, int pot)
{
return -1; // indicates not applicable
}
private static readonly string[] BaseDefinition =
{
"Up", "Down", "Left", "Right", "Button"
};
}
public class PaddleController : IPort
{
public PaddleController(int portNum)
{
PortNum = portNum;
Definition = new ControllerDefinition("(Atari 2600 Basic Controller fragment)")
{
BoolButtons = BaseDefinition
.Select(b => $"P{PortNum} " + b)
.ToList()
}.AddAxis($"P{PortNum} Paddle X 1", (-127).RangeTo(127), 0)
.AddAxis($"P{PortNum} Paddle X 2", (-127).RangeTo(127), 0)
.MakeImmutable();
}
public int PortNum { get; }
public void SyncState(Serializer ser)
{
// Nothing todo, I think
}
public ControllerDefinition Definition { get; }
private static readonly string[] BaseDefinition =
{
"Button 1",
"Button 2"
};
public byte Read(IController c)
{
byte result = 0xF0;
if (c.IsPressed($"P{PortNum} Button 1")) { result &= 0x70; }
if (c.IsPressed($"P{PortNum} Button 2")) { result &= 0xB0; }
return result;
}
public int Read_Pot(IController c, int pot)
{
int x = c.AxisValue(Definition.Axes[pot]);
x = -x;
x += 127;
x = x * 64 + 10;
return x;
}
}
public class BoostGripController : IPort
{
public BoostGripController(int portNum)
{
PortNum = portNum;
Definition = new("(Atari 2600 Basic Controller fragment)")
{
BoolButtons = BaseDefinition
.Select(b => $"P{PortNum} " + b)
.ToList()
};
}
public int PortNum { get; }
public void SyncState(Serializer ser)
{
// Nothing todo, I think
}
public ControllerDefinition Definition { get; }
private static readonly string[] BaseDefinition =
{
"Up", "Down", "Left", "Right", "Button",
"Button 1",
"Button 2"
};
public byte Read(IController c)
{
byte result = 0xFF;
if (c.IsPressed($"P{PortNum} Up")) { result &= 0xEF; }
if (c.IsPressed($"P{PortNum} Down")) { result &= 0xDF; }
if (c.IsPressed($"P{PortNum} Left")) { result &= 0xBF; }
if (c.IsPressed($"P{PortNum} Right")) { result &= 0x7F; }
if (c.IsPressed($"P{PortNum} Button")) { result &= 0xF7; }
return result;
}
public int Read_Pot(IController c, int pot)
{
bool is_pressed = false;
if (pot == 0)
{
is_pressed = c.IsPressed($"P{PortNum} Button 1");
}
else
{
is_pressed = c.IsPressed($"P{PortNum} Button 2");
}
if (is_pressed)
{
return 10;
}
return 65535;
}
}
public class DrivingController : IPort
{
public DrivingController(int portNum)
{
PortNum = portNum;
Definition = new ControllerDefinition("(Atari 2600 Basic Controller fragment)")
{
BoolButtons = BaseDefinition
.Select(b => $"P{PortNum} " + b)
.ToList()
}.AddAxis($"P{PortNum} Wheel X 1", (-127).RangeTo(127), 0)
.AddAxis($"P{PortNum} Wheel X 2", (-127).RangeTo(127), 0)
.MakeImmutable();
}
public int PortNum { get; }
public void SyncState(Serializer ser)
{
// Nothing todo, I think
}
public ControllerDefinition Definition { get; }
private static readonly string[] BaseDefinition =
{
"Button"
};
public byte Read(IController c)
{
byte result = 0xFF;
if (c.IsPressed($"P{PortNum} Button")) { result &= 0xF7; }
float x = c.AxisValue(Definition.Axes[0]);
float y = c.AxisValue(Definition.Axes[1]);
float angle = CalcDirection(x, y);
byte temp2 = 0;
int temp1 = (int)Math.Floor(angle / 45);
temp1 %= 4;
if (temp1 == 0)
{
temp2 = 0xEF;
}
if (temp1 == 1)
{
temp2 = 0xCF;
}
if (temp1 == 2)
{
temp2 = 0xDF;
}
if (temp1 == 3)
{
temp2 = 0xFF;
}
result &= temp2;
return result;
}
public int Read_Pot(IController c, int pot)
{
return -1; // indicates not applicable
}
private static float CalcDirection(float x, float y)
{
y = -y; // vflip to match the arrangement of FloatControllerButtons
// the wheel is arranged in a grey coded configuration of sensitivity ~2.5 degrees
// for each signal
// so overall the value returned changes every 1.25 degrees
float angle = (float)(Math.Atan2(y, x) * 180.0 / Math.PI);
if (angle < 0)
{
angle = 360 + angle;
}
return angle;
}
}
public class KeyboardController : IPort
{
public KeyboardController(int portNum)
{
PortNum = portNum;
Definition = new("(Atari 2600 Basic Controller fragment)")
{
BoolButtons = BaseDefinition
.Select(b => $"P{PortNum} " + b)
.ToList()
};
}
public ControllerDefinition Definition { get; }
public void SyncState(Serializer ser)
{
// Nothing todo, I think
}
public int PortNum { get; }
public byte Read(IController c)
{
byte result = 0xFF;
if (c.IsPressed($"P{PortNum} 0")) { result = 0x00; }
if (c.IsPressed($"P{PortNum} 1")) { result = 0x01; }
if (c.IsPressed($"P{PortNum} 2")) { result = 0x02; }
if (c.IsPressed($"P{PortNum} 3")) { result = 0x03; }
if (c.IsPressed($"P{PortNum} 4")) { result = 0x04; }
if (c.IsPressed($"P{PortNum} 5")) { result = 0x05; }
if (c.IsPressed($"P{PortNum} 6")) { result = 0x06; }
if (c.IsPressed($"P{PortNum} 7")) { result = 0x07; }
if (c.IsPressed($"P{PortNum} 8")) { result = 0x08; }
if (c.IsPressed($"P{PortNum} 9")) { result = 0x09; }
if (c.IsPressed($"P{PortNum} *")) { result = 0x0A; }
if (c.IsPressed($"P{PortNum} #")) { result = 0x0B; }
return result;
}
public int Read_Pot(IController c, int pot)
{
return -2; // indicates keyboard
}
private static readonly string[] BaseDefinition =
{
"1", "2", "3",
"4", "5", "6",
"7", "8", "9",
"*", "0", "#"
};
}
}

View File

@ -52,6 +52,7 @@ namespace BizHawk.Emulation.Cores
public const string Saturnus = "Saturnus";
public const string SMSHawk = "SMSHawk";
public const string Snes9X = "Snes9x";
public const string Stella = "Stella";
public const string SubBsnes115 = "SubBSNESv115+";
public const string SubGbHawk = "SubGBHawk";
public const string SubNesHawk = "SubNESHawk";

View File

@ -46,8 +46,14 @@ CXXFLAGS_RELEASE := -O3 -flto -DNDEBUG
CXXFLAGS_RELEASE_ASONLY := -O3
EXTRA_LIBS := -L $(SYSROOT)/lib/linux -lclang_rt.builtins-x86_64 $(EXTRA_LIBS)
CPP_EXTRA_LIBS := -lc++ -lc++abi -lunwind $(EXTRA_LIBS)
ifneq ($(filter %.cpp,$(SRCS)),)
EXTRA_LIBS := -lc++ -lc++abi -lunwind $(EXTRA_LIBS)
EXTRA_LIBS += $(CPP_EXTRA_LIBS)
endif
ifneq ($(filter %.cxx,$(SRCS)),)
EXTRA_LIBS += $(CPP_EXTRA_LIBS)
endif
_OBJS := $(addsuffix .o,$(abspath $(SRCS)))
@ -62,6 +68,10 @@ $(OBJ_DIR)/%.cpp.o: %.cpp
@echo cxx $<
@mkdir -p $(@D)
@$(CC) -c -o $@ $< $(CXXFLAGS) $(CXXFLAGS_RELEASE) $(PER_FILE_FLAGS_$<)
$(OBJ_DIR)/%.cxx.o: %.cxx
@echo cxx $<
@mkdir -p $(@D)
@$(CC) -c -o $@ $< $(CXXFLAGS) $(CXXFLAGS_RELEASE) $(PER_FILE_FLAGS_$<)
$(DOBJ_DIR)/%.c.o: %.c
@echo cc $<
@mkdir -p $(@D)
@ -70,6 +80,10 @@ $(DOBJ_DIR)/%.cpp.o: %.cpp
@echo cxx $<
@mkdir -p $(@D)
@$(CC) -c -o $@ $< $(CXXFLAGS) $(CXXFLAGS_DEBUG) $(PER_FILE_FLAGS_$<)
$(DOBJ_DIR)/%.cxx.o: %.cxx
@echo cxx $<
@mkdir -p $(@D)
@$(CC) -c -o $@ $< $(CXXFLAGS) $(CXXFLAGS_DEBUG) $(PER_FILE_FLAGS_$<)
$(OBJ_DIR)/%.c.s: %.c
@echo cc -S $<
@mkdir -p $(@D)
@ -78,6 +92,10 @@ $(OBJ_DIR)/%.cpp.s: %.cpp
@echo cxx -S $<
@mkdir -p $(@D)
@$(CC) -c -S -o $@ $< $(CXXFLAGS) $(CXXFLAGS_RELEASE_ASONLY) $(PER_FILE_FLAGS_$<)
$(OBJ_DIR)/%.cxx.s: %.cxx
@echo cxx -S $<
@mkdir -p $(@D)
@$(CC) -c -S -o $@ $< $(CXXFLAGS) $(CXXFLAGS_RELEASE_ASONLY) $(PER_FILE_FLAGS_$<)
ifndef NO_WBX_TARGETS

View File

@ -9,6 +9,7 @@ cd gpgx && make -f Makefile $1 -j && cd -
cd libsnes && make -f Makefile $1 -j && cd -
cd melon && make -f Makefile $1 -j && cd -
cd picodrive && make -f Makefile $1 -j && cd -
cd stella && make -f Makefile $1 -j && cd -
cd snes9x && make -f Makefile $1 -j && cd -
cd tic80 && make -f Makefile $1 -j && cd -
cd uae && make -f Makefile $1 -j && cd -

View File

@ -37,6 +37,7 @@ It consists of a modified musl libc, and build scripts to tie it all together.
* waterbox/snes9x (required for Snes9x)
* waterbox/gpgx/Genesis-Plus-GX (required for gpgx)
* waterbox/uae/libretro-uae (required for puae)
* waterbox/stella/core (required for stella)
* none of these submodules need to be cloned recursively
3. Consider whether it is time to update your build environment (i.e. sudo apt-get upgrade). Build environment tools are generally best kept at the latest version, to ensure top performance for our users.
@ -76,6 +77,7 @@ It consists of a modified musl libc, and build scripts to tie it all together.
cd nyma && make -f shock.mak install
cd nyma && make -f vb.mak install
cd picodrive && make install
cd stella && make install
cd snes9x && make install
cd tic80 && make install
cd uae && make install

View File

@ -0,0 +1,224 @@
#include <cstdio>
#include <cstdint>
#include "Cart.hxx"
#include "BizhawkInterface.hxx"
#include "OSystem.hxx"
#include "Settings.hxx"
#include "MediaFactory.hxx"
#include "Serializer.hxx"
#include "StateManager.hxx"
#include "Console.hxx"
#include "Control.hxx"
#include "Switches.hxx"
#include "M6532.hxx"
#include "TIA.hxx"
#define SOUND_BUFFER_SIZE 1024*1024
uint16_t* soundbuffer;
int nsamples;
struct InitSettings
{
uint32_t dummy;
};
std::unique_ptr<OSystem> _a2600;
void printRAM()
{
printf("[] Ram Pointer: %p\n", _a2600->console().riot().getRAM());
printf("[] Memory Contents:\n");
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 16; j++)
{
printf("%02X ", _a2600->console().riot().getRAM()[i*16 + j]);
}
printf("\n");
}
}
enum regionType
{
ntsc = 0,
pal = 1,
secam = 2
};
ECL_EXPORT int stella_get_region()
{
const auto regionString = _a2600->console().getFormatString();
if (regionString == "NTSC" || regionString == "NTSC50") return regionType::ntsc;
if (regionString == "PAL" || regionString == "PAL60") return regionType::pal;
if (regionString == "SECAM" || regionString == "SECAM60") return regionType::secam;
return -1;
}
ECL_EXPORT void stella_get_frame_rate(int& fps)
{
fps = _a2600->console().gameRefreshRate();
}
void printFrameBuffer()
{
auto frameBuffer = _a2600->console().tia().frameBuffer();
auto height = _a2600->console().tia().height();
auto width = _a2600->console().tia().width();
printf("[] Frame Buffer Pointer: %p\n", frameBuffer);
// printf("[] Frame Buffer Contents:\n");
uint64_t checkSum = 0;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
// printf("%02X ", frameBuffer[i*height + j]);
checkSum += frameBuffer[i*height + j];
}
// printf("\n");
}
printf("[] Frame Buffer Checksum: 0x%lX\n", checkSum);
}
ECL_EXPORT const char* stella_get_cart_type()
{
return _a2600->console().cartridge().detectedType().c_str();
}
ECL_EXPORT uint8_t stella_peek_tia(uint32_t address)
{
return _a2600->console().tia().peek(address);
}
ECL_EXPORT void stella_poke_tia(uint32_t address, uint8_t value)
{
_a2600->console().tia().poke(address, value);
}
ECL_EXPORT uint8_t stella_peek_m6532(uint32_t address)
{
return _a2600->console().riot().peek(address);
}
ECL_EXPORT void stella_poke_m6532(uint32_t address, uint8_t value)
{
_a2600->console().riot().poke(address, value);
}
ECL_EXPORT uint8_t stella_peek_systembus(uint32_t address)
{
return _a2600->console().system().peek(address);
}
ECL_EXPORT void stella_poke_systembus(uint32_t address, uint8_t value)
{
_a2600->console().system().poke(address, value);
}
ECL_EXPORT uint32_t stella_get_cartram_size()
{
return _a2600->console().cartridge().internalRamSize();
}
ECL_EXPORT uint8_t stella_peek_cartram(uint32_t address)
{
return _a2600->console().cartridge().peek(address);
}
ECL_EXPORT void stella_poke_cartram(uint32_t address, uint8_t value)
{
_a2600->console().cartridge().poke(address, value);
}
ECL_EXPORT void stella_get_mainram_ptr(void** ptr)
{
*ptr = (void*) _a2600->console().riot().getRAM();
}
ECL_EXPORT void stella_get_audio(int *n, void **buffer)
{
if (n)
*n = nsamples;
if (buffer)
*buffer = soundbuffer;
}
ECL_EXPORT void stella_get_video(int& w, int& h, int& pitch, uint8_t*& buffer)
{
w = _a2600->console().tia().width();
h = _a2600->console().tia().height();
buffer = _a2600->console().tia().frameBuffer();
pitch = _a2600->console().tia().width();
}
ECL_EXPORT void stella_frame_advance(uint8_t port1, uint8_t port2, bool reset, bool power, bool leftDiffToggled, bool rightDiffToggled)
{
_a2600->console().switches().setLeftDifficultyA(leftDiffToggled);
_a2600->console().switches().setRightDifficultyA(rightDiffToggled);
_a2600->console().switches().setReset(!reset);
if (power) _a2600->console().system().reset(true);
_a2600->console().leftController().write(::Controller::DigitalPin::One, port1 & 0b00010000); // Up
_a2600->console().leftController().write(::Controller::DigitalPin::Two, port1 & 0b00100000); // Down
_a2600->console().leftController().write(::Controller::DigitalPin::Three, port1 & 0b01000000); // Left
_a2600->console().leftController().write(::Controller::DigitalPin::Four, port1 & 0b10000000); // Right
_a2600->console().leftController().write(::Controller::DigitalPin::Six, port1 & 0b00001000); // Button
_a2600->console().rightController().write(::Controller::DigitalPin::One, port2 & 0b00010000); // Up
_a2600->console().rightController().write(::Controller::DigitalPin::Two, port2 & 0b00100000); // Down
_a2600->console().rightController().write(::Controller::DigitalPin::Three, port2 & 0b01000000); // Left
_a2600->console().rightController().write(::Controller::DigitalPin::Four, port2 & 0b10000000); // Right
_a2600->console().rightController().write(::Controller::DigitalPin::Six, port2 & 0b00001000); // Button
nsamples = 0;
_a2600->dispatchEmulation();
// printRAM();
// printFrameBuffer();
}
ECL_ENTRY void (*input_callback_cb)(void);
void real_input_callback(void)
{
if (input_callback_cb)
input_callback_cb();
}
ECL_EXPORT void stella_set_input_callback(ECL_ENTRY void (*fecb)(void))
{
input_callback_cb = fecb;
}
ECL_EXPORT int stella_init(
const char* romFileName,
ECL_ENTRY int (*feload_archive_cb)(const char *filename, unsigned char *buffer, int maxsize),
struct InitSettings *settings)
{
fprintf(stderr, "Initializing Stella core...\n");
// Allocating sound buffer
soundbuffer = (uint16_t*) alloc_invisible(SOUND_BUFFER_SIZE);
Settings::Options opts;
_a2600 = MediaFactory::createOSystem();
if(!_a2600->initialize(opts)) { fprintf(stderr, "ERROR: Couldn't create A2600 System\n"); return 0; }
uint8_t* buf = (uint8_t*) calloc(1, BUFFER_SIZE);
int size = feload_archive_cb("PRIMARY_ROM", buf, BUFFER_SIZE);
const FSNode romnode(romFileName, buf, size);
auto error = _a2600->createConsole(romnode);
if (error != "") { fprintf(stderr, "ERROR: Couldn't create A2600 Console. Reason: '%s'\n", error.c_str()); return 0; }
printf("A2600 console created successfully\n");
return 1;
}

View File

@ -0,0 +1,8 @@
#pragma once
#include <emulibc.h>
#include <vector>
#include <cstdint>
extern uint16_t* soundbuffer;
extern int nsamples;

200
waterbox/stella/Makefile Normal file
View File

@ -0,0 +1,200 @@
STELLA_DIR := core
CCFLAGS := \
-ISDL/include \
-ISDL/src
CXXFLAGS := \
-I. \
-Iport \
-Icore/src/emucore \
-Icore/src/common \
-Icore/src/common/tv_filters \
-Icore/src/emucore/tia \
-Icore/src/emucore/tia/frame-manager \
-Icore/src/lib/json \
-Icore/src/common/repository/sqlite \
-Icore/src/os/unix \
-Icore/src/gui \
-Icore/src/lib/httplib \
-Icore/src/lib/sqlite \
-ISDL/include/SDL2 \
-ISDL/include \
-ISDL/src \
-DUNIX \
-DSOUND_SUPPORT \
-DSDL_ENABLE_OLD_NAMES \
-D_REENTRANT \
-D__USE_BIZHAWK \
-std=gnu++17 \
-Wno-multichar \
LDFLAGS :=
TARGET := stella.wbx
SRCS = \
BizhawkInterface.cxx \
port/EventHandlerBizhawk.cxx \
port/FBBackendBizhawk.cxx \
port/FBSurfaceBizhawk.cxx \
port/OSystemBizhawk.cxx \
port/SoundBizhawk.cxx \
core/src/emucore/OSystem.cxx \
core/src/emucore/Switches.cxx \
core/src/emucore/FrameBuffer.cxx \
core/src/emucore/Console.cxx \
core/src/common/Logger.cxx \
core/src/common/tv_filters/NTSCFilter.cxx \
core/src/common/tv_filters/AtariNTSC.cxx \
core/src/common/AudioSettings.cxx \
core/src/common/VideoModeHandler.cxx \
core/src/common/PhysicalJoystick.cxx \
core/src/common/ThreadDebugging.cxx \
core/src/common/TimerManager.cxx \
core/src/common/PKeyboardHandler.cxx \
core/src/common/PhosphorHandler.cxx \
core/src/common/JoyMap.cxx \
core/src/common/ZipHandler.cxx \
core/src/common/MouseControl.cxx \
core/src/common/PJoystickHandler.cxx \
core/src/common/JPGLibrary.cxx \
core/src/common/AudioQueue.cxx \
core/src/common/StateManager.cxx \
core/src/common/DevSettingsHandler.cxx \
core/src/common/FpsMeter.cxx \
core/src/common/audio/ConvolutionBuffer.cxx \
core/src/common/audio/HighPass.cxx \
core/src/common/audio/SimpleResampler.cxx \
core/src/common/audio/LanczosResampler.cxx \
core/src/common/StaggeredLogger.cxx \
core/src/common/Base.cxx \
core/src/common/FSNodeZIP.cxx \
core/src/common/KeyMap.cxx \
core/src/common/repository/KeyValueRepositoryJsonFile.cxx \
core/src/common/repository/CompositeKVRJsonAdapter.cxx \
core/src/common/repository/sqlite/SqliteDatabase.cxx \
core/src/common/repository/sqlite/SqliteStatement.cxx \
core/src/common/repository/sqlite/SqliteTransaction.cxx \
core/src/common/repository/sqlite/AbstractKeyValueRepositorySqlite.cxx \
core/src/common/repository/sqlite/KeyValueRepositorySqlite.cxx \
core/src/common/repository/sqlite/StellaDb.cxx \
core/src/common/repository/sqlite/CompositeKeyValueRepositorySqlite.cxx \
core/src/common/repository/KeyValueRepositoryPropertyFile.cxx \
core/src/common/repository/CompositeKeyValueRepository.cxx \
core/src/common/repository/KeyValueRepositoryConfigfile.cxx \
core/src/common/Bezel.cxx \
core/src/common/PNGLibrary.cxx \
core/src/common/PaletteHandler.cxx \
core/src/common/RewindManager.cxx \
core/src/emucore/Genesis.cxx \
core/src/emucore/Bankswitch.cxx \
core/src/emucore/Cart03E0.cxx \
core/src/emucore/CartF0.cxx \
core/src/emucore/Cart4K.cxx \
core/src/emucore/CartWD.cxx \
core/src/emucore/Cart4A50.cxx \
core/src/emucore/CartBF.cxx \
core/src/emucore/EmulationWorker.cxx \
core/src/emucore/CartF6.cxx \
core/src/emucore/Cart.cxx \
core/src/emucore/CartF4SC.cxx \
core/src/emucore/CartCTY.cxx \
core/src/emucore/CartF8SC.cxx \
core/src/emucore/CartDetector.cxx \
core/src/emucore/CartDFSC.cxx \
core/src/emucore/Serializer.cxx \
core/src/emucore/Cart0840.cxx \
core/src/emucore/CartFA.cxx \
core/src/emucore/CartX07.cxx \
core/src/emucore/Cart2K.cxx \
core/src/emucore/Cart3EX.cxx \
core/src/emucore/CartDPCPlus.cxx \
core/src/emucore/CartBFSC.cxx \
core/src/emucore/CartCM.cxx \
core/src/emucore/CartEF.cxx \
core/src/emucore/CartSB.cxx \
core/src/emucore/MD5.cxx \
core/src/emucore/Settings.cxx \
core/src/emucore/CartBUS.cxx \
core/src/emucore/SaveKey.cxx \
core/src/emucore/CartDPC.cxx \
core/src/emucore/CompuMate.cxx \
core/src/emucore/TIASurface.cxx \
core/src/emucore/Paddles.cxx \
core/src/emucore/CartEFSC.cxx \
core/src/emucore/Joystick.cxx \
core/src/emucore/Lightgun.cxx \
core/src/emucore/KidVid.cxx \
core/src/emucore/CartAR.cxx \
core/src/emucore/CartFC.cxx \
core/src/emucore/Cart3F.cxx \
core/src/emucore/FBSurface.cxx \
core/src/emucore/Cart3E.cxx \
core/src/emucore/GlobalKeyHandler.cxx \
core/src/emucore/PointingDevice.cxx \
core/src/emucore/CartTVBoy.cxx \
core/src/emucore/CartCreator.cxx \
core/src/emucore/CartF6SC.cxx \
core/src/emucore/Cart4KSC.cxx \
core/src/emucore/Props.cxx \
core/src/emucore/Thumbulator.cxx \
core/src/emucore/DispatchResult.cxx \
core/src/emucore/EmulationTiming.cxx \
core/src/emucore/PlusROM.cxx \
core/src/emucore/CartGL.cxx \
core/src/emucore/Cart0FA0.cxx \
core/src/emucore/CartMVC.cxx \
core/src/emucore/Keyboard.cxx \
core/src/emucore/CartFA2.cxx \
core/src/emucore/QuadTari.cxx \
core/src/emucore/CartFE.cxx \
core/src/emucore/CartMDM.cxx \
core/src/emucore/CartF4.cxx \
core/src/emucore/CartF8.cxx \
core/src/emucore/CartCV.cxx \
core/src/emucore/EventHandler.cxx \
core/src/emucore/Driving.cxx \
core/src/emucore/M6532.cxx \
core/src/emucore/System.cxx \
core/src/emucore/M6502.cxx \
core/src/emucore/Joy2BPlus.cxx \
core/src/emucore/CartE7.cxx \
core/src/emucore/OSystemStandalone.cxx \
core/src/emucore/tia/Player.cxx \
core/src/emucore/tia/LatchedInput.cxx \
core/src/emucore/tia/Missile.cxx \
core/src/emucore/tia/frame-manager/FrameLayoutDetector.cxx \
core/src/emucore/tia/frame-manager/AbstractFrameManager.cxx \
core/src/emucore/tia/frame-manager/FrameManager.cxx \
core/src/emucore/tia/frame-manager/JitterEmulation.cxx \
core/src/emucore/tia/AnalogReadout.cxx \
core/src/emucore/tia/Background.cxx \
core/src/emucore/tia/DrawCounterDecodes.cxx \
core/src/emucore/tia/TIA.cxx \
core/src/emucore/tia/Playfield.cxx \
core/src/emucore/tia/Audio.cxx \
core/src/emucore/tia/AudioChannel.cxx \
core/src/emucore/tia/Ball.cxx \
core/src/emucore/CartARM.cxx \
core/src/emucore/PropsSet.cxx \
core/src/emucore/ProfilingRunner.cxx \
core/src/emucore/CartUA.cxx \
core/src/emucore/CartE0.cxx \
core/src/emucore/Booster.cxx \
core/src/emucore/CartEnhanced.cxx \
core/src/emucore/FSNode.cxx \
core/src/emucore/CartCDF.cxx \
core/src/emucore/ControllerDetector.cxx \
core/src/emucore/MindLink.cxx \
core/src/emucore/Cart3EPlus.cxx \
core/src/emucore/MT24LC256.cxx \
core/src/emucore/CartDF.cxx \
core/src/emucore/Control.cxx \
core/src/emucore/AtariVox.cxx \
core/src/os/unix/SerialPortUNIX.cxx \
core/src/lib/tinyexif/tinyexif.cxx \
core/src/lib/sqlite/sqlite3.c \
core/src/lib/nanojpeg/nanojpeg.c \
include ../common.mak

1
waterbox/stella/core Submodule

@ -0,0 +1 @@
Subproject commit 48734d5c38c12e3988959ebcb6efee4a570268e3

View File

@ -0,0 +1,43 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include "Logger.hxx"
#include "OSystem.hxx"
#include "EventHandlerBizhawk.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventHandlerBizhawk::EventHandlerBizhawk(OSystem& osystem)
: EventHandler{osystem}
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventHandlerBizhawk::~EventHandlerBizhawk()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandlerBizhawk::enableTextEvents(bool enable)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandlerBizhawk::pollEvent()
{
}

View File

@ -0,0 +1,57 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#pragma once
#include "EventHandler.hxx"
/**
This class handles event collection from the point of view of the specific
backend toolkit (Bizhawk). It converts from Bizhawk-specific events into events
that the Stella core can understand.
@author Stephen Anthony
*/
class EventHandlerBizhawk : public EventHandler
{
public:
/**
Create a new Bizhawk event handler object
*/
explicit EventHandlerBizhawk(OSystem& osystem);
~EventHandlerBizhawk() override;
private:
/**
Enable/disable text events (distinct from single-key events).
*/
void enableTextEvents(bool enable) override;
/**
Collects and dispatches any pending Bizhawk events.
*/
void pollEvent() override;
private:
// Following constructors and assignment operators not supported
EventHandlerBizhawk() = delete;
EventHandlerBizhawk(const EventHandlerBizhawk&) = delete;
EventHandlerBizhawk(EventHandlerBizhawk&&) = delete;
EventHandlerBizhawk& operator=(const EventHandlerBizhawk&) = delete;
EventHandlerBizhawk& operator=(EventHandlerBizhawk&&) = delete;
};

View File

@ -0,0 +1,171 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include <cmath>
#include "bspf.hxx"
#include "Logger.hxx"
#include "Console.hxx"
#include "OSystem.hxx"
#include "Settings.hxx"
#include "ThreadDebugging.hxx"
#include "FBSurfaceBizhawk.hxx"
#include "FBBackendBizhawk.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBBackendBIZHAWK::FBBackendBIZHAWK(OSystem& osystem)
: myOSystem{osystem}
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBBackendBIZHAWK::~FBBackendBIZHAWK()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendBIZHAWK::queryHardware(vector<Common::Size>& fullscreenRes,
vector<Common::Size>& windowedRes,
VariantList& renderers)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FBBackendBIZHAWK::isCurrentWindowPositioned() const
{
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Common::Point FBBackendBIZHAWK::getCurrentWindowPos() const
{
Common::Point pos;
return pos;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 FBBackendBIZHAWK::getCurrentDisplayIndex() const
{
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FBBackendBIZHAWK::setVideoMode(const VideoModeHandler::Mode& mode,
int winIdx, const Common::Point& winPos)
{
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FBBackendBIZHAWK::createRenderer(const VideoModeHandler::Mode& mode)
{
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendBIZHAWK::setTitle(string_view title)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string FBBackendBIZHAWK::about() const
{
return "";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendBIZHAWK::showCursor(bool show)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendBIZHAWK::grabMouse(bool grab)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FBBackendBIZHAWK::fullScreen() const
{
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int FBBackendBIZHAWK::refreshRate() const
{
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendBIZHAWK::renderToScreen()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendBIZHAWK::setWindowIcon()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unique_ptr<FBSurface> FBBackendBIZHAWK::createSurface(
uInt32 w,
uInt32 h,
ScalingInterpolation inter,
const uInt32* data
) const
{
return make_unique<FBSurfaceBIZHAWK>
(const_cast<FBBackendBIZHAWK&>(*this), w, h, inter, data);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendBIZHAWK::readPixels(uInt8* buffer, size_t pitch,
const Common::Rect& rect) const
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendBIZHAWK::clear()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendBIZHAWK::detectFeatures()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FBBackendBIZHAWK::detectRenderTargetSupport()
{
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendBIZHAWK::determineDimensions()
{
}

View File

@ -0,0 +1,273 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef FB_BACKEND_BIZHAWK_HXX
#define FB_BACKEND_BIZHAWK_HXX
class OSystem;
class FBSurfaceBIZHAWK;
#include "bspf.hxx"
#include "FBBackend.hxx"
/**
This class implements a standard BIZHAWK 2D, hardware accelerated framebuffer
backend. Behind the scenes, it may be using Direct3D, OpenGL(ES), etc.
@author Stephen Anthony
*/
class FBBackendBIZHAWK : public FBBackend
{
public:
/**
Creates a new BIZHAWK framebuffer
*/
explicit FBBackendBIZHAWK(OSystem& osystem);
~FBBackendBIZHAWK() override;
public:
/**
Is the renderer initialized?
*/
bool isInitialized() const { return true; }
/**
Does the renderer support render targets?
*/
bool hasRenderTargetSupport() const { return true;; }
/**
Transform from window to renderer coordinates, x direction
*/
int scaleX(int x) const override { return 1; }
/**
Transform from window to renderer coordinates, y direction
*/
int scaleY(int y) const override { return 1; }
protected:
/**
Updates window title.
@param title The title of the application / window
*/
void setTitle(string_view title) override;
/**
Shows or hides the cursor based on the given boolean value.
*/
void showCursor(bool show) override;
/**
Answers if the display is currently in fullscreen mode.
*/
bool fullScreen() const override;
/**
This method is called to retrieve the R/G/B data from the given pixel.
@param pixel The pixel containing R/G/B data
@param r The red component of the color
@param g The green component of the color
@param b The blue component of the color
*/
FORCE_INLINE void getRGB(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b) const override
{ }
/**
This method is called to retrieve the R/G/B/A data from the given pixel.
@param pixel The pixel containing R/G/B data
@param r The red component of the color
@param g The green component of the color
@param b The blue component of the color
@param a The alpha component of the color.
*/
FORCE_INLINE void getRGBA(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b, uInt8* a) const override
{ }
/**
This method is called to map a given R/G/B triple to the screen palette.
@param r The red component of the color.
@param g The green component of the color.
@param b The blue component of the color.
*/
inline uInt32 mapRGB(uInt8 r, uInt8 g, uInt8 b) const override
{ return 0; }
/**
This method is called to map a given R/G/B/A triple to the screen palette.
@param r The red component of the color.
@param g The green component of the color.
@param b The blue component of the color.
@param a The alpha component of the color.
*/
inline uInt32 mapRGBA(uInt8 r, uInt8 g, uInt8 b, uInt8 a) const override
{ return 0; }
/**
This method is called to get a copy of the specified ARGB data from the
viewable FrameBuffer area. Note that this isn't the same as any
internal surfaces that may be in use; it should return the actual data
as it is currently seen onscreen.
@param buffer A copy of the pixel data in ARGB8888 format
@param pitch The pitch (in bytes) for the pixel data
@param rect The bounding rectangle for the buffer
*/
void readPixels(uInt8* buffer, size_t pitch,
const Common::Rect& rect) const override;
/**
This method is called to query if the current window is not centered
or fullscreen.
@return True, if the current window is positioned
*/
bool isCurrentWindowPositioned() const override;
/**
This method is called to query the video hardware for position of
the current window
@return The position of the currently displayed window
*/
Common::Point getCurrentWindowPos() const override;
/**
This method is called to query the video hardware for the index
of the display the current window is displayed on
@return the current display index or a negative value if no
window is displayed
*/
Int32 getCurrentDisplayIndex() const override;
/**
Clear the frame buffer.
*/
void clear() override;
/**
This method is called to query and initialize the video hardware
for desktop and fullscreen resolution information. Since several
monitors may be attached, we need the resolution for all of them.
@param fullscreenRes Maximum resolution supported in fullscreen mode
@param windowedRes Maximum resolution supported in windowed mode
@param renderers List of renderer names (internal name -> end-user name)
*/
void queryHardware(vector<Common::Size>& fullscreenRes,
vector<Common::Size>& windowedRes,
VariantList& renderers) override;
/**
This method is called to change to the given video mode.
@param mode The video mode to use
@param winIdx The display/monitor that the window last opened on
@param winPos The position that the window last opened at
@return False on any errors, else true
*/
bool setVideoMode(const VideoModeHandler::Mode& mode,
int winIdx, const Common::Point& winPos) override;
/**
This method is called to create a surface with the given attributes.
@param w The requested width of the new surface.
@param h The requested height of the new surface.
@param inter Interpolation mode
@param data If non-null, use the given data values as a static surface
*/
unique_ptr<FBSurface>
createSurface(
uInt32 w,
uInt32 h,
ScalingInterpolation inter,
const uInt32* data
) const override;
/**
Grabs or ungrabs the mouse based on the given boolean value.
*/
void grabMouse(bool grab) override;
/**
This method is called to provide information about the backend.
*/
string about() const override;
/**
Create a new renderer if required.
@return False on any errors, else true
*/
bool createRenderer(const VideoModeHandler::Mode& mode);
/**
This method must be called after all drawing is done, and indicates
that the buffers should be pushed to the physical screen.
*/
void renderToScreen() override;
/**
Retrieve the current display's refresh rate, or 0 if no window.
*/
int refreshRate() const override;
/**
After the renderer has been created, detect the features it supports.
*/
void detectFeatures();
/**
Detect render target support.
*/
bool detectRenderTargetSupport();
/**
Determine window and renderer dimensions.
*/
void determineDimensions();
/**
Set the icon for the main SDL window.
*/
void setWindowIcon();
private:
OSystem& myOSystem;
// Center setting of current window
bool myCenter{false};
private:
// Following constructors and assignment operators not supported
FBBackendBIZHAWK() = delete;
FBBackendBIZHAWK(const FBBackendBIZHAWK&) = delete;
FBBackendBIZHAWK(FBBackendBIZHAWK&&) = delete;
FBBackendBIZHAWK& operator=(const FBBackendBIZHAWK&) = delete;
FBBackendBIZHAWK& operator=(FBBackendBIZHAWK&&) = delete;
};
#endif

View File

@ -0,0 +1,152 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include "FBSurfaceBizhawk.hxx"
#include "Logger.hxx"
#include "ThreadDebugging.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBSurfaceBIZHAWK::FBSurfaceBIZHAWK(FBBackendBIZHAWK& backend,
uInt32 width, uInt32 height,
ScalingInterpolation inter,
const uInt32* staticData)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBSurfaceBIZHAWK::~FBSurfaceBIZHAWK()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceBIZHAWK::fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, ColorId color)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 FBSurfaceBIZHAWK::width() const
{
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 FBSurfaceBIZHAWK::height() const
{
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const Common::Rect& FBSurfaceBIZHAWK::srcRect() const
{
Common::Rect a;
return a;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const Common::Rect& FBSurfaceBIZHAWK::dstRect() const
{
Common::Rect a;
return a;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceBIZHAWK::setSrcPos(uInt32 x, uInt32 y)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceBIZHAWK::setSrcSize(uInt32 w, uInt32 h)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceBIZHAWK::setSrcRect(const Common::Rect& r)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceBIZHAWK::setDstPos(uInt32 x, uInt32 y)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceBIZHAWK::setDstSize(uInt32 w, uInt32 h)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceBIZHAWK::setDstRect(const Common::Rect& r)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceBIZHAWK::setVisible(bool visible)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceBIZHAWK::translateCoords(Int32& x, Int32& y) const
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FBSurfaceBIZHAWK::render()
{
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceBIZHAWK::invalidate()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceBIZHAWK::invalidateRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceBIZHAWK::reload()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceBIZHAWK::resize(uInt32 width, uInt32 height)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceBIZHAWK::createSurface(uInt32 width, uInt32 height,
const uInt32* data)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceBIZHAWK::reinitializeBlitter(bool force)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceBIZHAWK::applyAttributes()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceBIZHAWK::setScalingInterpolation(ScalingInterpolation interpolation)
{
}

View File

@ -0,0 +1,89 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef FBSURFACE_BIZHAWK_HXX
#define FBSURFACE_BIZHAWK_HXX
#include "bspf.hxx"
#include "FBSurface.hxx"
#include "FBBackendBizhawk.hxx"
/**
An FBSurface suitable for the BIZHAWK Render2D API, making use of hardware
acceleration behind the scenes.
@author Stephen Anthony
*/
class FBSurfaceBIZHAWK : public FBSurface
{
public:
FBSurfaceBIZHAWK(FBBackendBIZHAWK& backend, uInt32 width, uInt32 height,
ScalingInterpolation inter, const uInt32* staticData);
~FBSurfaceBIZHAWK() override;
// Most of the surface drawing primitives are implemented in FBSurface;
// the ones implemented here use SDL-specific code for extra performance
//
void fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, ColorId color) override;
uInt32 width() const override;
uInt32 height() const override;
const Common::Rect& srcRect() const override;
const Common::Rect& dstRect() const override;
void setSrcPos(uInt32 x, uInt32 y) override;
void setSrcSize(uInt32 w, uInt32 h) override;
void setSrcRect(const Common::Rect& r) override;
void setDstPos(uInt32 x, uInt32 y) override;
void setDstSize(uInt32 w, uInt32 h) override;
void setDstRect(const Common::Rect& r) override;
void setVisible(bool visible) override;
void translateCoords(Int32& x, Int32& y) const override;
bool render() override;
void invalidate() override;
void invalidateRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) override;
void reload() override;
void resize(uInt32 width, uInt32 height) override;
void setScalingInterpolation(ScalingInterpolation) override;
protected:
void applyAttributes() override;
void createSurface(uInt32 width, uInt32 height, const uInt32* data);
void reinitializeBlitter(bool force = false);
// Following constructors and assignment operators not supported
FBSurfaceBIZHAWK() = delete;
FBSurfaceBIZHAWK(const FBSurfaceBIZHAWK&) = delete;
FBSurfaceBIZHAWK(FBSurfaceBIZHAWK&&) = delete;
FBSurfaceBIZHAWK& operator=(const FBSurfaceBIZHAWK&) = delete;
FBSurfaceBIZHAWK& operator=(FBSurfaceBIZHAWK&&) = delete;
private:
bool myIsVisible{true};
bool myIsStatic{false};
Common::Rect mySrcGUIR, myDstGUIR;
};
#endif

View File

@ -0,0 +1,31 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include <cstdlib>
#include "FSNode.hxx"
#include "OSystemBizhawk.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void OSystemBIZHAWK::getBaseDirectories(string& basedir, string& homedir,
bool useappdir, string_view usedir)
{
}
void OSystemBIZHAWK::initPersistence(FSNode& basedir) {}
string OSystemBIZHAWK::describePresistence() { return ""; };

View File

@ -0,0 +1,62 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#pragma once
#include "OSystemStandalone.hxx"
/**
This class defines an OSystem object for UNIX-like OS's (Linux).
It is responsible for completely implementing getBaseDirectories(),
to set the base directory and various other save/load locations.
@author Stephen Anthony
*/
class OSystemBIZHAWK : public OSystemStandalone
{
public:
OSystemBIZHAWK() = default;
~OSystemBIZHAWK() override = default;
/**
Determine the base directory and home directory from the derived
class. It can also use hints, as described below.
@param basedir The base directory for all configuration files
@param homedir The default directory to store various other files
@param useappdir A hint that the base dir should be set to the
app directory; not all ports can do this, so
they are free to ignore it
@param usedir A hint that the base dir should be set to this
parameter; not all ports can do this, so
they are free to ignore it
*/
void getBaseDirectories(string& basedir, string& homedir,
bool useappdir, string_view usedir) override;
void initPersistence(FSNode& basedir) override;
string describePresistence() override;
private:
// Following constructors and assignment operators not supported
OSystemBIZHAWK(const OSystemBIZHAWK&) = delete;
OSystemBIZHAWK(OSystemBIZHAWK&&) = delete;
OSystemBIZHAWK& operator=(const OSystemBIZHAWK&) = delete;
OSystemBIZHAWK& operator=(OSystemBIZHAWK&&) = delete;
};

View File

@ -0,0 +1,131 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifdef SOUND_SUPPORT
#include <cmath>
#include "Logger.hxx"
#include "FrameBuffer.hxx"
#include "OSystem.hxx"
#include "Console.hxx"
#include "AudioQueue.hxx"
#include "EmulationTiming.hxx"
#include "AudioSettings.hxx"
#include "audio/SimpleResampler.hxx"
#include "audio/LanczosResampler.hxx"
#include "ThreadDebugging.hxx"
#include "SoundBizhawk.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SoundBizhawk::SoundBizhawk(OSystem& osystem, AudioSettings& audioSettings)
: Sound{osystem},
myAudioSettings{audioSettings}
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SoundBizhawk::~SoundBizhawk()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundBizhawk::queryHardware(VariantList& devices)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SoundBizhawk::openDevice()
{
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundBizhawk::setEnabled(bool enable)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundBizhawk::open(shared_ptr<AudioQueue> audioQueue,
EmulationTiming* emulationTiming)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundBizhawk::mute(bool enable)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundBizhawk::toggleMute()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SoundBizhawk::pause(bool enable)
{
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundBizhawk::setVolume(uInt32 volume)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundBizhawk::adjustVolume(int direction)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string SoundBizhawk::about() const
{
ostringstream buf;
return buf.str();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundBizhawk::initResampler()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundBizhawk::callback(void* object, uInt8* stream, int len)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SoundBizhawk::playWav(const string& fileName, const uInt32 position,
const uInt32 length)
{
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundBizhawk::stopWav()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 SoundBizhawk::wavSize() const
{
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#endif // SOUND_SUPPORT

View File

@ -0,0 +1,174 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifdef SOUND_SUPPORT
#ifndef SOUND_SDL2_HXX
#define SOUND_SDL2_HXX
class OSystem;
class AudioQueue;
class EmulationTiming;
class AudioSettings;
class Resampler;
#include "bspf.hxx"
#include "Sound.hxx"
/**
This class implements the sound API for SDL.
@author Stephen Anthony and Christian Speckner (DirtyHairy)
*/
class SoundBizhawk : public Sound
{
public:
/**
Create a new sound object. The init method must be invoked before
using the object.
*/
SoundBizhawk(OSystem& osystem, AudioSettings& audioSettings);
/**
Destructor
*/
~SoundBizhawk() override;
public:
/**
Enables/disables the sound subsystem.
@param enable Either true or false, to enable or disable the sound system
*/
void setEnabled(bool enable) override;
/**
Initializes the sound device. This must be called before any
calls are made to derived methods.
*/
void open(shared_ptr<AudioQueue> audioQueue,
EmulationTiming* emulationTiming) override;
/**
Sets the sound mute state; sound processing continues. When enabled,
sound volume is 0; when disabled, sound volume returns to previously
set level.
@param enable Mutes sound if true, unmute if false
*/
void mute(bool enable) override;
/**
Toggles the sound mute state; sound processing continues.
Switches between mute(true) and mute(false).
*/
void toggleMute() override;
/**
Set the pause state of the sound object. While paused, sound is
neither played nor processed (ie, the sound subsystem is temporarily
disabled).
@param enable Pause sound if true, unpause if false
@return The previous (old) pause state
*/
bool pause(bool enable) override;
/**
Sets the volume of the sound device to the specified level. The
volume is given as a range from 0 to 100 (0 indicates mute). Values
outside this range indicate that the volume shouldn't be changed at all.
@param volume The new volume level for the sound device
*/
void setVolume(uInt32 volume) override;
/**
Adjusts the volume of the sound device based on the given direction.
@param direction +1 indicates increase, -1 indicates decrease.
*/
void adjustVolume(int direction = 1) override;
/**
This method is called to provide information about the sound device.
*/
string about() const override;
/**
Play a WAV file.
@param fileName The name of the WAV file
@param position The position to start playing
@param length The played length
@return True if the WAV file can be played, else false
*/
bool playWav(const string& fileName, const uInt32 position = 0,
const uInt32 length = 0) override;
/**
Stop any currently playing WAV file.
*/
void stopWav() override;
/**
Get the size of the WAV file which remains to be played.
@return The remaining number of bytes
*/
uInt32 wavSize() const override;
private:
/**
This method is called to query the audio devices.
@param devices List of device names
*/
void queryHardware(VariantList& devices) override;
/**
The actual sound device is opened only when absolutely necessary.
Typically this will only happen once per program run, but it can also
happen dynamically when changing sample rate and/or fragment size.
*/
bool openDevice();
void initResampler();
private:
AudioSettings& myAudioSettings;
// Audio specification structure
static float myVolumeFactor; // Current volume level (0 - 100)
private:
// Callback functions invoked by the SDL Audio library when it needs data
static void callback(void* object, uInt8* stream, int len);
// Following constructors and assignment operators not supported
SoundBizhawk() = delete;
SoundBizhawk(const SoundBizhawk&) = delete;
SoundBizhawk(SoundBizhawk&&) = delete;
SoundBizhawk& operator=(const SoundBizhawk&) = delete;
SoundBizhawk& operator=(SoundBizhawk&&) = delete;
};
#endif
#endif // SOUND_SUPPORT