Revamp waterbox build environment and runtime. (#2027)

Create an all new waterbox build environment:
WSL2 + Ubuntu 20.04 LTS (Other linuxes may work)
Musl libc with waterbox customizations
LLVM's libclang-rt, libunwind, libcxxabi, libcxx
Static linking to elf files

Compared with the old system, this is easier to set up a dev env for and easier to update in the future. The executables are larger but produce smaller savestates due to static linking. The modern toolchain means advanced library features and language features that sometimes appear in some upstream cores will be reusable.
This commit is contained in:
nattthebear 2020-05-20 15:34:24 -04:00 committed by GitHub
parent acf7926629
commit 21cdf5120b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
84 changed files with 9790 additions and 10226 deletions

3
.gitmodules vendored
View File

@ -19,3 +19,6 @@
path = melonds path = melonds
url = https://github.com/TASVideos/melonDS.git url = https://github.com/TASVideos/melonDS.git
branch = SuuperW_DSHawk branch = SuuperW_DSHawk
[submodule "waterbox/musl"]
path = waterbox/musl
url = https://github.com/nattthebear/musl.git

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -18,11 +18,8 @@ namespace BizHawk.Emulation.Common
/// If unavailable these options will not be exposed /// If unavailable these options will not be exposed
/// Additionally many tools depend on savestates such as TAStudio, these will only be available if this service is implemented /// Additionally many tools depend on savestates such as TAStudio, these will only be available if this service is implemented
/// </summary> /// </summary>
public interface IStatable : IEmulatorService public interface IStatable : IBinaryStateable, IEmulatorService
{ {
void SaveStateBinary(BinaryWriter writer);
void LoadStateBinary(BinaryReader reader);
/// <summary> /// <summary>
/// save state binary to a byte buffer /// save state binary to a byte buffer
/// </summary> /// </summary>

View File

@ -5,10 +5,10 @@
<TargetFrameworks>netstandard2.0;netcoreapp3.1</TargetFrameworks> <TargetFrameworks>netstandard2.0;netcoreapp3.1</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ELFSharp" Version="2.10.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.7.0" PrivateAssets="All" /> <PackageReference Include="System.ComponentModel.Annotations" Version="4.7.0" PrivateAssets="All" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" PrivateAssets="All" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" PrivateAssets="All" />
<PackageReference Include="OpenTK" Version="3.0.1" PrivateAssets="All" /> <PackageReference Include="OpenTK" Version="3.0.1" PrivateAssets="All" />
<Reference Include="PeNet" HintPath="$(ProjectDir)../../References/PeNet.dll" Private="true" />
<Reference Include="Virtu" HintPath="$(ProjectDir)../../References/Virtu.dll" Private="true" /> <Reference Include="Virtu" HintPath="$(ProjectDir)../../References/Virtu.dll" Private="true" />
<ProjectReference Include="$(ProjectDir)../BizHawk.BizInvoke/BizHawk.BizInvoke.csproj" /> <ProjectReference Include="$(ProjectDir)../BizHawk.BizInvoke/BizHawk.BizInvoke.csproj" />
<ProjectReference Include="$(ProjectDir)../BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj" /> <ProjectReference Include="$(ProjectDir)../BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj" />

View File

@ -24,7 +24,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Belogic
DefaultFpsDenominator = 476840 DefaultFpsDenominator = 476840
}) })
{ {
_uze = PreInit<LibUzem>(new PeRunnerOptions _uze = PreInit<LibUzem>(new WaterboxOptions
{ {
Filename = "uzem.wbx", Filename = "uzem.wbx",
SbrkHeapSizeKB = 20, SbrkHeapSizeKB = 20,

View File

@ -62,7 +62,7 @@ namespace BizHawk.Emulation.Cores.Consoles.NEC.PCFX
_syncSettings = syncSettings ?? new SyncSettings(); _syncSettings = syncSettings ?? new SyncSettings();
BufferHeight = _settings.ScanlineEnd - _settings.ScanlineStart + 1; BufferHeight = _settings.ScanlineEnd - _settings.ScanlineStart + 1;
_core = PreInit<LibTst>(new PeRunnerOptions _core = PreInit<LibTst>(new WaterboxOptions
{ {
Filename = "pcfx.wbx", Filename = "pcfx.wbx",
SbrkHeapSizeKB = 512, SbrkHeapSizeKB = 512,

View File

@ -58,7 +58,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
SystemId = sgb ? "SGB" : "GB" SystemId = sgb ? "SGB" : "GB"
}) })
{ {
_core = PreInit<LibSameboy>(new PeRunnerOptions _core = PreInit<LibSameboy>(new WaterboxOptions
{ {
Filename = "sameboy.wbx", Filename = "sameboy.wbx",
SbrkHeapSizeKB = 192, SbrkHeapSizeKB = 192,

View File

@ -34,7 +34,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
} }
} }
private PeRunner _exe; private WaterboxHost _exe;
private CoreImpl _core; private CoreImpl _core;
private bool _disposed; private bool _disposed;
private CommStruct* _comm; private CommStruct* _comm;
@ -61,7 +61,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
public LibsnesApi(string dllPath, CoreComm comm) public LibsnesApi(string dllPath, CoreComm comm)
{ {
_exe = new PeRunner(new PeRunnerOptions _exe = new WaterboxHost(new WaterboxOptions
{ {
Filename = "libsnes.wbx", Filename = "libsnes.wbx",
Path = dllPath, Path = dllPath,

View File

@ -32,7 +32,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES9X
settings ??= new Settings(); settings ??= new Settings();
syncSettings ??= new SyncSettings(); syncSettings ??= new SyncSettings();
_core = PreInit<LibSnes9x>(new PeRunnerOptions _core = PreInit<LibSnes9x>(new WaterboxOptions
{ {
Filename = "snes9x.wbx", Filename = "snes9x.wbx",
SbrkHeapSizeKB = 1024, SbrkHeapSizeKB = 1024,

View File

@ -33,7 +33,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
_settings = settings ?? new Settings(); _settings = settings ?? new Settings();
_syncSettings = syncSettings ?? new SyncSettings(); _syncSettings = syncSettings ?? new SyncSettings();
_boyee = PreInit<LibVirtualBoyee>(new PeRunnerOptions _boyee = PreInit<LibVirtualBoyee>(new WaterboxOptions
{ {
Filename = "vb.wbx", Filename = "vb.wbx",
SbrkHeapSizeKB = 256, SbrkHeapSizeKB = 256,

View File

@ -28,9 +28,10 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK
[CoreConstructor("DNGP")] [CoreConstructor("DNGP")]
public DualNeoGeoPort(CoreComm comm, byte[] rom, bool deterministic) public DualNeoGeoPort(CoreComm comm, byte[] rom, bool deterministic)
{ {
// this will throw on construct: we need to compile two different copies of ngp at different starts
CoreComm = comm; CoreComm = comm;
_left = new NeoGeoPort(comm, rom, new NeoGeoPort.SyncSettings { Language = LibNeoGeoPort.Language.English }, deterministic, PeRunner.CanonicalStart); _left = new NeoGeoPort(comm, rom, new NeoGeoPort.SyncSettings { Language = LibNeoGeoPort.Language.English }, deterministic, WaterboxHost.CanonicalStart);
_right = new NeoGeoPort(comm, rom, new NeoGeoPort.SyncSettings { Language = LibNeoGeoPort.Language.English }, deterministic, PeRunner.AlternateStart); _right = new NeoGeoPort(comm, rom, new NeoGeoPort.SyncSettings { Language = LibNeoGeoPort.Language.English }, deterministic, WaterboxHost.CanonicalStart);
_linkCable = new LinkCable(); _linkCable = new LinkCable();
_leftEnd = new LinkInterop(_left, _linkCable.LeftIn, _linkCable.LeftOut); _leftEnd = new LinkInterop(_left, _linkCable.LeftIn, _linkCable.LeftOut);
_rightEnd = new LinkInterop(_right, _linkCable.RightIn, _linkCable.RightOut); _rightEnd = new LinkInterop(_right, _linkCable.RightIn, _linkCable.RightOut);

View File

@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK
[CoreConstructor("NGP")] [CoreConstructor("NGP")]
public NeoGeoPort(CoreComm comm, byte[] rom, SyncSettings syncSettings, bool deterministic) public NeoGeoPort(CoreComm comm, byte[] rom, SyncSettings syncSettings, bool deterministic)
: this(comm, rom, syncSettings, deterministic, PeRunner.CanonicalStart) : this(comm, rom, syncSettings, deterministic, WaterboxHost.CanonicalStart)
{ {
} }
@ -41,7 +41,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK
_syncSettings = syncSettings ?? new SyncSettings(); _syncSettings = syncSettings ?? new SyncSettings();
_neopop = PreInit<LibNeoGeoPort>(new PeRunnerOptions _neopop = PreInit<LibNeoGeoPort>(new WaterboxOptions
{ {
Filename = "ngp.wbx", Filename = "ngp.wbx",
SbrkHeapSizeKB = 256, SbrkHeapSizeKB = 256,

View File

@ -45,7 +45,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive
_syncSettings = syncSettings ?? new SyncSettings(); _syncSettings = syncSettings ?? new SyncSettings();
_core = PreInit<LibPicoDrive>(new PeRunnerOptions _core = PreInit<LibPicoDrive>(new WaterboxOptions
{ {
Filename = "picodrive.wbx", Filename = "picodrive.wbx",
SbrkHeapSizeKB = 64, SbrkHeapSizeKB = 64,

View File

@ -9,7 +9,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
{ {
// some of the internal code uses wizardry by which certain pointers in ss.wbx[.text] // some of the internal code uses wizardry by which certain pointers in ss.wbx[.text]
// must be greater than or equal to this address, but less than 4GB bigger than it // must be greater than or equal to this address, but less than 4GB bigger than it
public const ulong StartAddress = 0x36d00000000; public const ulong StartAddress = WaterboxHost.CanonicalStart;
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public class TOC public class TOC

View File

@ -85,7 +85,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
throw new InvalidOperationException("Some disks are not valid"); throw new InvalidOperationException("Some disks are not valid");
InitCallbacks(); InitCallbacks();
_core = PreInit<LibSaturnus>(new PeRunnerOptions _core = PreInit<LibSaturnus>(new WaterboxOptions
{ {
Filename = "ss.wbx", Filename = "ss.wbx",
SbrkHeapSizeKB = 128, SbrkHeapSizeKB = 128,

View File

@ -43,7 +43,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
throw new InvalidOperationException("ROM too big! Did you try to load a CD as a ROM?"); throw new InvalidOperationException("ROM too big! Did you try to load a CD as a ROM?");
} }
_elf = new PeRunner(new PeRunnerOptions _elf = new WaterboxHost(new WaterboxOptions
{ {
Path = comm.CoreFileProvider.DllPath(), Path = comm.CoreFileProvider.DllPath(),
Filename = "gpgx.wbx", Filename = "gpgx.wbx",
@ -166,7 +166,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
} }
private LibGPGX Core; private LibGPGX Core;
private PeRunner _elf; private WaterboxHost _elf;
private Disc[] _cds; private Disc[] _cds;
private int _discIndex; private int _discIndex;

View File

@ -179,9 +179,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
{ {
Console.WriteLine("Genesis Controller report:"); Console.WriteLine("Genesis Controller report:");
foreach (var e in input.system) foreach (var e in input.system)
Console.WriteLine("S:{0}", e); Console.WriteLine(" S:{0}", e);
foreach (var e in input.dev) foreach (var e in input.dev)
Console.WriteLine("D:{0}", e); Console.WriteLine(" D:{0}", e);
int player = 1; int player = 1;

View File

@ -0,0 +1,360 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using BizHawk.BizInvoke;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using ELFSharp.ELF;
using ELFSharp.ELF.Sections;
using ELFSharp.ELF.Segments;
namespace BizHawk.Emulation.Cores.Waterbox
{
public class ElfLoader : IImportResolver, IDisposable, IBinaryStateable
{
private readonly ELF<ulong> _elf;
private readonly byte[] _elfHash;
private readonly List<SymbolEntry<ulong>> _allSymbols;
private readonly Dictionary<string, SymbolEntry<ulong>> _visibleSymbols;
private readonly Dictionary<string, Section<ulong>> _sectionsByName;
private readonly List<SymbolEntry<ulong>> _importSymbols;
private readonly Section<ulong> _imports;
private readonly Section<ulong> _sealed;
private readonly Section<ulong> _invisible;
private readonly List<Section<ulong>> _savedSections;
private readonly bool _skipCoreConsistencyCheck;
private readonly bool _skipMemoryConsistencyCheck;
private bool _everythingSealed;
public MemoryBlockBase Memory { get; private set; }
public string ModuleName { get; }
public ElfLoader(string moduleName, byte[] fileData, ulong assumedStart, bool skipCoreConsistencyCheck, bool skipMemoryConsistencyCheck)
{
ModuleName = moduleName;
_skipCoreConsistencyCheck = skipCoreConsistencyCheck;
_skipMemoryConsistencyCheck = skipMemoryConsistencyCheck;
_elfHash = WaterboxUtils.Hash(fileData);
_elf = ELFReader.Load<ulong>(new MemoryStream(fileData, false), true);
var loadsegs = _elf.Segments.Where(s => s.Type == SegmentType.Load);
var start = loadsegs.Min(s => s.Address);
start = WaterboxUtils.AlignDown(start);
var end = loadsegs.Max(s => s.Address + s.Size);
end = WaterboxUtils.AlignUp(end);
var size = end - start;
if (start != assumedStart)
throw new InvalidOperationException($"{nameof(assumedStart)} did not match actual origin in elf file");
if (_elf.Sections.Any(s => s.Name.StartsWith(".rel")))
throw new InvalidOperationException("Elf has relocations!");
_allSymbols = ((ISymbolTable)_elf.GetSection(".symtab"))
.Entries
.Cast<SymbolEntry<ulong>>()
.ToList();
_sectionsByName = _elf.Sections
.ToDictionary(s => s.Name);
_sectionsByName.TryGetValue(".wbxsyscall", out _imports);
if (_imports == null)
{
// Likely cause: This is a valid elf file, but it was not compiled by our toolchain at all
throw new InvalidOperationException("Missing .wbxsyscall section!");
}
_sectionsByName.TryGetValue(".sealed", out _sealed);
_sectionsByName.TryGetValue(".invis", out _invisible);
_savedSections = _elf.Sections
.Where(s => (s.Flags & SectionFlags.Allocatable) != 0 && (s.Flags & SectionFlags.Writable) != 0)
.Where(s => !IsSpecialReadonlySection(s) && s != _invisible)
.OrderBy(s => s.LoadAddress)
.ToList();
_visibleSymbols = _allSymbols
.Where(s => s.Binding == SymbolBinding.Global && s.Visibility == SymbolVisibility.Default)
.ToDictionary(s => s.Name);
_importSymbols = _allSymbols
// TODO: No matter what attributes I provide, I seem to end up with Local and/or Hidden symbols in
// .wbxsyscall a lot of the time on heavily optimized release builds.
// Fortunately, there's nothing else in .wbxsyscall so we can just not filter at all.
.Where(s => s.PointedSection == _imports)
.ToList();
Memory = MemoryBlock.CallPlatformCtor(start, size);
Memory.Activate();
Memory.Protect(Memory.Start, Memory.Size, MemoryBlockBase.Protection.RW);
foreach (var seg in loadsegs)
{
var data = seg.GetFileContents();
Marshal.Copy(data, 0, Z.US(seg.Address), Math.Min((int)seg.Size, (int)seg.FileSize));
}
PrintSections();
PrintGdbData();
PrintTopSavableSymbols();
Protect();
}
private void PrintGdbData()
{
Console.WriteLine("GDB Symbol Load:");
Console.WriteLine($" add-sym {ModuleName}");
}
private void PrintSections()
{
Console.WriteLine($"Mounted `{ModuleName}` @{Memory.Start:x16}");
foreach (var s in _elf.Sections.OrderBy(s => s.LoadAddress))
{
Console.WriteLine(" @{0:x16} {1}{2}{3}{4} `{5}` {6} bytes",
s.LoadAddress,
(s.Flags & SectionFlags.Allocatable) != 0 ? "R" : " ",
(s.Flags & SectionFlags.Writable) != 0 ? "W" : " ",
(s.Flags & SectionFlags.Executable) != 0 ? "X" : " ",
_savedSections.Contains(s) ? "V" : " ",
s.Name,
s.Size);
}
}
private void PrintTopSavableSymbols()
{
var tops = _allSymbols
.Where(s => _savedSections.Contains(s.PointedSection))
.OrderByDescending(s => s.Size)
.Where(s => s.Size >= 20 * 1024)
.Take(30)
.Select(s => $" {s.Name} {s.Size / 1024}kiB")
.ToList();
if (tops.Count > 0)
{
Console.WriteLine("Top savestate symbols:");
foreach (var text in tops)
{
Console.WriteLine(text);
}
}
}
/// <summary>
/// Returns true if section is readonly after init
/// </summary>
private bool IsSpecialReadonlySection(Section<ulong> sec)
{
return sec.Name.Contains(".rel.ro")
|| sec.Name.StartsWith(".got")
|| sec.Name == ".init_array"
|| sec.Name == ".fini_array"
|| sec == _imports
|| sec == _sealed;
}
/// <summary>
/// Set normal (post-seal) memory protections
/// </summary>
private void Protect()
{
Memory.Protect(Memory.Start, Memory.Size, MemoryBlockBase.Protection.R);
foreach (var sec in _elf.Sections.Where(s => (s.Flags & SectionFlags.Allocatable) != 0))
{
if (_everythingSealed && IsSpecialReadonlySection(sec))
continue;
if ((sec.Flags & SectionFlags.Executable) != 0)
Memory.Protect(sec.LoadAddress, sec.Size, MemoryBlockBase.Protection.RX);
else if ((sec.Flags & SectionFlags.Writable) != 0)
Memory.Protect(sec.LoadAddress, sec.Size, MemoryBlockBase.Protection.RW);
}
}
// connect all of the .wbxsyscall stuff
public void ConnectSyscalls(IImportResolver syscalls)
{
Memory.Protect(Memory.Start, Memory.Size, MemoryBlockBase.Protection.RW);
var tmp = new IntPtr[1];
var ptrSize = (ulong)IntPtr.Size;
foreach (var s in _importSymbols)
{
if (s.Size == ptrSize)
{
var p = syscalls.GetProcAddrOrThrow(s.Name);
tmp[0] = p;
Marshal.Copy(tmp, 0, Z.US(s.Value), 1);
}
else
{
if (s.Size % ptrSize != 0)
{
// They're supposed to be arrays of pointers, so uhhh yeah?
throw new InvalidOperationException($"Symbol {s.Name} has unexpected size");
}
var count = (int)(s.Size / ptrSize);
for (var i = 0; i < count; i++)
{
var p = syscalls.GetProcAddrOrThrow($"{s.Name}[{i}]");
tmp[0] = p;
Marshal.Copy(tmp, 0, Z.US(s.Value + ((ulong)i * ptrSize)), 1);
}
}
}
Protect();
}
public void RunNativeInit()
{
CallingConventionAdapters.Waterbox.GetDelegateForFunctionPointer<Action>(Z.US(_elf.EntryPoint))();
}
public void SealImportsAndTakeXorSnapshot()
{
if (_everythingSealed)
throw new InvalidOperationException($"{nameof(ElfLoader)} already sealed!");
// save import values, then zero them all (for hash purposes), then take our snapshot, then load them again,
// then set the .wbxsyscall area to read only
byte[] impData = null;
impData = new byte[_imports.Size];
Marshal.Copy(Z.US(_imports.LoadAddress), impData, 0, (int)_imports.Size);
WaterboxUtils.ZeroMemory(Z.US(_imports.LoadAddress), (long)_imports.Size);
byte[] invData = null;
if (_invisible != null)
{
invData = new byte[_invisible.Size];
Marshal.Copy(Z.US(_invisible.LoadAddress), invData, 0, (int)_invisible.Size);
WaterboxUtils.ZeroMemory(Z.US(_invisible.LoadAddress), (long)_invisible.Size);
}
Memory.SaveXorSnapshot();
Marshal.Copy(impData, 0, Z.US(_imports.LoadAddress), (int)_imports.Size);
if (_invisible != null)
{
Marshal.Copy(invData, 0, Z.US(_invisible.LoadAddress), (int)_invisible.Size);
}
_everythingSealed = true;
Protect();
}
private bool _disposed = false;
public void Dispose()
{
if (!_disposed)
{
Memory.Dispose();
Memory = null;
_disposed = true;
}
}
public IntPtr GetProcAddrOrZero(string entryPoint)
{
if (_visibleSymbols.TryGetValue(entryPoint, out var sym))
{
return Z.US(sym.Value);
}
else
{
return IntPtr.Zero;
}
}
public IntPtr GetProcAddrOrThrow(string entryPoint)
{
if (_visibleSymbols.TryGetValue(entryPoint, out var sym))
{
return Z.US(sym.Value);
}
else
{
throw new InvalidOperationException($"Couldn't find {nameof(entryPoint)} {entryPoint} in {ModuleName}");
}
}
const ulong MAGIC = 0x6018ab7df99310ca;
public void SaveStateBinary(BinaryWriter bw)
{
if (!_everythingSealed)
throw new InvalidOperationException(".wbxsyscall section must be closed before saving state");
bw.Write(MAGIC);
bw.Write(_elfHash);
bw.Write(Memory.XorHash);
foreach (var s in _savedSections)
{
var ms = Memory.GetXorStream(s.LoadAddress, s.Size, false);
bw.Write(s.Size);
ms.CopyTo(bw.BaseStream);
}
}
public void LoadStateBinary(BinaryReader br)
{
if (!_everythingSealed)
// operations happening in the wrong order. probable cause: internal logic error. make sure frontend calls Seal
throw new InvalidOperationException(".wbxsyscall section must be closed before loading state");
if (br.ReadUInt64() != MAGIC)
// file id is missing. probable cause: garbage savestate
throw new InvalidOperationException("Savestate corrupted!");
var elfHash = br.ReadBytes(_elfHash.Length);
if (_skipCoreConsistencyCheck)
{
throw new InvalidOperationException("We decided that the core consistency check should always run");
}
else
{
if (!elfHash.SequenceEqual(_elfHash))
// the .dll file that is loaded now has a different hash than the .dll that created the savestate
throw new InvalidOperationException("Core consistency check failed. Is this a savestate from a different version?");
}
var xorHash = br.ReadBytes(Memory.XorHash.Length);
if (!_skipMemoryConsistencyCheck)
{
if (!xorHash.SequenceEqual(Memory.XorHash))
// the post-Seal memory state is different. probable cause: different rom or different version of rom,
// different syncsettings
throw new InvalidOperationException("Memory consistency check failed. Is this savestate from different SyncSettings?");
}
Memory.Protect(Memory.Start, Memory.Size, MemoryBlockBase.Protection.RW);
foreach (var s in _savedSections)
{
if (br.ReadUInt64() != s.Size)
throw new InvalidOperationException("Unexpected section size for " + s.Name);
var ms = Memory.GetXorStream(s.LoadAddress, s.Size, true);
WaterboxUtils.CopySome(br.BaseStream, ms, (long)s.Size);
}
Protect();
}
}
}

View File

@ -0,0 +1,43 @@
using System;
using System.Runtime.InteropServices;
using BizHawk.BizInvoke;
namespace BizHawk.Emulation.Cores.Waterbox
{
/// <summary>
/// implementation for special functions defined in emulibc.h
/// </summary>
internal class EmuLibc
{
private readonly WaterboxHost _parent;
public EmuLibc(WaterboxHost parent)
{
_parent = parent;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__walloc_sealed")]
public IntPtr AllocSealed(UIntPtr size)
{
return Z.US(_parent._sealedheap.Allocate((ulong)size, 16));
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__walloc_invisible")]
public IntPtr AllocInvisible(UIntPtr size)
{
return Z.US(_parent._invisibleheap.Allocate((ulong)size, 16));
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__walloc_plain")]
public IntPtr AllocPlain(UIntPtr size)
{
return Z.US(_parent._plainheap.Allocate((ulong)size, 16));
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__w_debug_puts")]
public void DebugPuts(IntPtr s)
{
// TODO: Should be PtrToStringUtf8
Console.WriteLine(Marshal.PtrToStringAnsi(s));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,461 +0,0 @@
using BizHawk.Common;
using BizHawk.BizInvoke;
using BizHawk.Emulation.Common;
using PeNet;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace BizHawk.Emulation.Cores.Waterbox
{
/// <summary>
/// represents one PE file. used in PeRunner
/// </summary>
internal class PeWrapper : IImportResolver, IBinaryStateable, IDisposable
{
public Dictionary<int, IntPtr> ExportsByOrdinal { get; } = new Dictionary<int, IntPtr>();
/// <summary>
/// ordinal only exports will not show up in this list!
/// </summary>
public Dictionary<string, IntPtr> ExportsByName { get; } = new Dictionary<string, IntPtr>();
public Dictionary<string, Dictionary<string, IntPtr>> ImportsByModule { get; } =
new Dictionary<string, Dictionary<string, IntPtr>>();
private class Section
{
public string Name { get; set; }
public ulong Start { get; set; }
public ulong Size { get; set; }
public ulong SavedSize { get; set; }
public bool W { get; set; }
public bool R { get; set; }
public bool X { get; set; }
public MemoryBlockBase.Protection Prot { get; set; }
public ulong DiskStart { get; set; }
public ulong DiskSize { get; set; }
}
private readonly Dictionary<string, Section> _sectionsByName = new Dictionary<string, Section>();
private readonly List<Section> _sections = new List<Section>();
private Section _imports;
private Section _sealed;
private Section _invisible;
public string ModuleName { get; }
private readonly PeFile _pe;
private readonly byte[] _fileHash;
private bool _skipCoreConsistencyCheck;
private bool _skipMemoryConsistencyCheck;
public ulong Size { get; }
public ulong Start { get; }
public long LoadOffset { get; }
public MemoryBlockBase Memory { get; private set; }
public IntPtr EntryPoint { get; }
/// <summary>
/// for midipix-built PEs, pointer to the constructors to run during init
/// </summary>
public IntPtr CtorList { get; }
/// <summary>
/// for midipix-build PEs, pointer to the destructors to run during fini
/// </summary>
public IntPtr DtorList { get; }
// true if the seal process has completed, including .idata and .sealed set to readonly,
// xorstate taken
private bool _everythingSealed = false;
/*[UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate bool DllEntry(IntPtr instance, int reason, IntPtr reserved);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate void ExeEntry();*/
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void GlobalCtor();
/*public bool RunDllEntry()
{
var entryThunk = (DllEntry)CallingConventionAdapters.Waterbox.GetDelegateForFunctionPointer(EntryPoint, typeof(DllEntry));
return entryThunk(Z.US(Start), 1, IntPtr.Zero); // DLL_PROCESS_ATTACH
}
public void RunExeEntry()
{
var entryThunk = (ExeEntry)CallingConventionAdapters.Waterbox.GetDelegateForFunctionPointer(EntryPoint, typeof(ExeEntry));
entryThunk();
}*/
public unsafe void RunGlobalCtors()
{
int did = 0;
if (CtorList != IntPtr.Zero)
{
IntPtr* p = (IntPtr*)CtorList;
IntPtr f;
while ((f = *++p) != IntPtr.Zero) // skip 0th dummy pointer
{
var ctorThunk = (GlobalCtor)CallingConventionAdapters.Waterbox.GetDelegateForFunctionPointer(f, typeof(GlobalCtor));
//Console.WriteLine(f);
//System.Diagnostics.Debugger.Break();
ctorThunk();
did++;
}
}
if (did > 0)
{
Console.WriteLine($"Did {did} global ctors for {ModuleName}");
}
else
{
Console.WriteLine($"Warn: no global ctors for {ModuleName}; possibly no C++?");
}
}
public PeWrapper(string moduleName, byte[] fileData, ulong destAddress, bool skipCoreConsistencyCheck, bool skipMemoryConsistencyCheck)
{
ModuleName = moduleName;
_pe = new PeFile(fileData);
Size = _pe.ImageNtHeaders.OptionalHeader.SizeOfImage;
Start = destAddress;
this._skipCoreConsistencyCheck = skipCoreConsistencyCheck;
this._skipMemoryConsistencyCheck = skipMemoryConsistencyCheck;
if (Size < _pe.ImageSectionHeaders.Max(s => (ulong)s.VirtualSize + s.VirtualAddress))
{
throw new InvalidOperationException("Image not Big Enough");
}
_fileHash = WaterboxUtils.Hash(fileData);
foreach (var s in _pe.ImageSectionHeaders)
{
ulong start = Start + s.VirtualAddress;
ulong length = s.VirtualSize;
MemoryBlockBase.Protection prot;
var r = (s.Characteristics & (uint)Constants.SectionFlags.IMAGE_SCN_MEM_READ) != 0;
var w = (s.Characteristics & (uint)Constants.SectionFlags.IMAGE_SCN_MEM_WRITE) != 0;
var x = (s.Characteristics & (uint)Constants.SectionFlags.IMAGE_SCN_MEM_EXECUTE) != 0;
if (w && x)
{
throw new InvalidOperationException("Write and Execute not allowed");
}
prot = x ? MemoryBlockBase.Protection.RX : w ? MemoryBlockBase.Protection.RW : MemoryBlockBase.Protection.R;
var section = new Section
{
// chop off possible null padding from name
Name = Encoding.ASCII.GetString(s.Name, 0,
(s.Name.Select((v, i) => new { v, i }).FirstOrDefault(a => a.v == 0) ?? new { v = (byte)0, i = s.Name.Length }).i),
Start = start,
Size = length,
SavedSize = WaterboxUtils.AlignUp(length),
R = r,
W = w,
X = x,
Prot = prot,
DiskStart = s.PointerToRawData,
DiskSize = s.SizeOfRawData
};
_sections.Add(section);
_sectionsByName.Add(section.Name, section);
}
_sectionsByName.TryGetValue(".idata", out _imports);
_sectionsByName.TryGetValue(".sealed", out _sealed);
_sectionsByName.TryGetValue(".invis", out _invisible);
// OK, NOW MOUNT
LoadOffset = (long)Start - (long)_pe.ImageNtHeaders.OptionalHeader.ImageBase;
Memory = MemoryBlockBase.CallPlatformCtor(Start, Size);
Memory.Activate();
Memory.Protect(Start, Size, MemoryBlockBase.Protection.RW);
// copy headers
Marshal.Copy(fileData, 0, Z.US(Start), (int)_pe.ImageNtHeaders.OptionalHeader.SizeOfHeaders);
// copy sections
foreach (var s in _sections)
{
ulong datalength = Math.Min(s.Size, s.DiskSize);
Marshal.Copy(fileData, (int)s.DiskStart, Z.US(s.Start), (int)datalength);
WaterboxUtils.ZeroMemory(Z.US(s.Start + datalength), (long)(s.SavedSize - datalength));
}
// apply relocations
var n32 = 0;
var n64 = 0;
foreach (var rel in _pe.ImageRelocationDirectory)
{
foreach (var to in rel.TypeOffsets)
{
ulong address = Start + rel.VirtualAddress + to.Offset;
switch (to.Type)
{
// there are many other types of relocation specified,
// but the only that are used is 0 (does nothing), 3 (32 bit standard), 10 (64 bit standard)
case 3: // IMAGE_REL_BASED_HIGHLOW
{
byte[] tmp = new byte[4];
Marshal.Copy(Z.US(address), tmp, 0, 4);
uint val = BitConverter.ToUInt32(tmp, 0);
tmp = BitConverter.GetBytes((uint)(val + LoadOffset));
Marshal.Copy(tmp, 0, Z.US(address), 4);
n32++;
break;
}
case 10: // IMAGE_REL_BASED_DIR64
{
byte[] tmp = new byte[8];
Marshal.Copy(Z.US(address), tmp, 0, 8);
long val = BitConverter.ToInt64(tmp, 0);
tmp = BitConverter.GetBytes(val + LoadOffset);
Marshal.Copy(tmp, 0, Z.US(address), 8);
n64++;
break;
}
}
}
}
if (IntPtr.Size == 8 && n32 > 0)
{
// check mcmodel, etc
throw new InvalidOperationException("32 bit relocations found in 64 bit dll! This will fail.");
}
Console.WriteLine($"Processed {n32} 32 bit and {n64} 64 bit relocations");
ProtectMemory();
// publish exports
EntryPoint = Z.US(Start + _pe.ImageNtHeaders.OptionalHeader.AddressOfEntryPoint);
foreach (var export in _pe.ExportedFunctions)
{
if (export.Name != null)
ExportsByName.Add(export.Name, Z.US(Start + export.Address));
ExportsByOrdinal.Add(export.Ordinal, Z.US(Start + export.Address));
}
// collect information about imports
// NB: Hints are not the same as Ordinals
foreach (var import in _pe.ImportedFunctions)
{
if (!ImportsByModule.TryGetValue(import.DLL, out var module))
{
module = new Dictionary<string, IntPtr>();
ImportsByModule.Add(import.DLL, module);
}
var dest = Start + import.Thunk;
if (_imports == null || dest >= _imports.Start + _imports.Size || dest < _imports.Start)
throw new InvalidOperationException("Import record outside of .idata!");
module.Add(import.Name, Z.US(dest));
}
if (_sectionsByName.TryGetValue(".midipix", out Section midipix))
{
var dataOffset = midipix.DiskStart;
CtorList = Z.SS(BitConverter.ToInt64(fileData, (int)(dataOffset + 0x30)) + LoadOffset);
DtorList = Z.SS(BitConverter.ToInt64(fileData, (int)(dataOffset + 0x38)) + LoadOffset);
}
Console.WriteLine($"Mounted `{ModuleName}` @{Start:x16}");
foreach (var s in _sections.OrderBy(s => s.Start))
{
Console.WriteLine(" @{0:x16} {1}{2}{3} `{4}` {5} bytes",
s.Start,
s.R ? "R" : " ",
s.W ? "W" : " ",
s.X ? "X" : " ",
s.Name,
s.Size);
}
Console.WriteLine("GDB Symbol Load:");
var symload = $"add-sym {ModuleName} {_sectionsByName[".text"].Start}";
if (_sectionsByName.ContainsKey(".data"))
symload += $" -s .data {_sectionsByName[".data"].Start}";
if (_sectionsByName.ContainsKey(".bss"))
symload += $" -s .bss {_sectionsByName[".bss"].Start}";
Console.WriteLine(symload);
}
/// <summary>
/// set memory protections.
/// </summary>
private void ProtectMemory()
{
Memory.Protect(Memory.Start, Memory.Size, MemoryBlockBase.Protection.R);
foreach (var s in _sections)
{
Memory.Protect(s.Start, s.Size, s.Prot);
}
}
public IntPtr GetProcAddrOrZero(string entryPoint) => ExportsByName.TryGetValue(entryPoint, out var ret) ? ret : IntPtr.Zero;
public IntPtr GetProcAddrOrThrow(string entryPoint) => ExportsByName.TryGetValue(entryPoint, out var ret) ? ret : throw new InvalidOperationException($"could not find {entryPoint} in exports");
public void ConnectImports(string moduleName, IImportResolver module)
{
// this is called once internally when bootstrapping, and externally
// when we need to restore a savestate from another run. so imports might or might not be sealed
if (_everythingSealed && _imports != null)
Memory.Protect(_imports.Start, _imports.Size, MemoryBlockBase.Protection.RW);
if (ImportsByModule.TryGetValue(moduleName, out var imports))
{
foreach (var kvp in imports)
{
var valueArray = new IntPtr[] { module.GetProcAddrOrThrow(kvp.Key) };
Marshal.Copy(valueArray, 0, kvp.Value, 1);
}
}
if (_everythingSealed && _imports != null)
Memory.Protect(_imports.Start, _imports.Size, _imports.Prot);
}
public void SealImportsAndTakeXorSnapshot()
{
if (_everythingSealed)
throw new InvalidOperationException($"{nameof(PeWrapper)} already sealed!");
// save import values, then zero them all (for hash purposes), then take our snapshot, then load them again,
// then set the .idata area to read only
byte[] impData = null;
if (_imports != null)
{
impData = new byte[_imports.Size];
Marshal.Copy(Z.US(_imports.Start), impData, 0, (int)_imports.Size);
WaterboxUtils.ZeroMemory(Z.US(_imports.Start), (long)_imports.Size);
}
byte[] invData = null;
if (_invisible != null)
{
invData = new byte[_invisible.Size];
Marshal.Copy(Z.US(_invisible.Start), invData, 0, (int)_invisible.Size);
WaterboxUtils.ZeroMemory(Z.US(_invisible.Start), (long)_invisible.Size);
}
Memory.SaveXorSnapshot();
if (_imports != null)
{
Marshal.Copy(impData, 0, Z.US(_imports.Start), (int)_imports.Size);
_imports.W = false;
Memory.Protect(_imports.Start, _imports.Size, _imports.Prot);
}
if (_invisible != null)
{
Marshal.Copy(invData, 0, Z.US(_invisible.Start), (int)_invisible.Size);
}
if (_sealed != null)
{
_sealed.W = false;
Memory.Protect(_sealed.Start, _sealed.Size, _sealed.Prot);
}
_everythingSealed = true;
}
private bool _disposed = false;
public void Dispose()
{
if (!_disposed)
{
Memory.Dispose();
Memory = null;
_disposed = true;
}
}
const ulong MAGIC = 0x420cccb1a2e17420;
public void SaveStateBinary(BinaryWriter bw)
{
if (!_everythingSealed)
throw new InvalidOperationException(".idata sections must be closed before saving state");
bw.Write(MAGIC);
bw.Write(_fileHash);
bw.Write(Memory.XorHash);
bw.Write(Start);
foreach (var s in _sections)
{
if (!s.W || s == _invisible)
continue;
var ms = Memory.GetXorStream(s.Start, s.SavedSize, false);
bw.Write(s.SavedSize);
ms.CopyTo(bw.BaseStream);
}
}
public void LoadStateBinary(BinaryReader br)
{
if (!_everythingSealed)
// operations happening in the wrong order. probable cause: internal logic error. make sure frontend calls Seal
throw new InvalidOperationException(".idata sections must be closed before loading state");
if (br.ReadUInt64() != MAGIC)
// file id is missing. probable cause: garbage savestate
throw new InvalidOperationException("Savestate corrupted!");
var fileHash = br.ReadBytes(_fileHash.Length);
if (_skipCoreConsistencyCheck)
{
throw new InvalidOperationException("We decided that the core consistency check should always run");
}
else
{
if (!fileHash.SequenceEqual(_fileHash))
// the .dll file that is loaded now has a different hash than the .dll that created the savestate
throw new InvalidOperationException("Core consistency check failed. Is this a savestate from a different version?");
}
var xorHash = br.ReadBytes(Memory.XorHash.Length);
if (!_skipMemoryConsistencyCheck)
{
if (!xorHash.SequenceEqual(Memory.XorHash))
// the post-Seal memory state is different. probable cause: different rom or different version of rom,
// different syncsettings
throw new InvalidOperationException("Memory consistency check failed. Is this savestate from different SyncSettings?");
}
if (br.ReadUInt64() != Start)
// dll loaded somewhere else. probable cause: internal logic error.
// unlikely to get this far if the previous checks pssed
throw new InvalidOperationException("Trickys elves moved on you!");
Memory.Protect(Memory.Start, Memory.Size, MemoryBlockBase.Protection.RW);
foreach (var s in _sections)
{
if (!s.W || s == _invisible)
continue;
if (br.ReadUInt64() != s.SavedSize)
throw new InvalidOperationException("Unexpected section size for " + s.Name);
var ms = Memory.GetXorStream(s.Start, s.SavedSize, true);
WaterboxUtils.CopySome(br.BaseStream, ms, (long)s.SavedSize);
}
ProtectMemory();
}
}
}

View File

@ -0,0 +1,590 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using BizHawk.BizInvoke;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Waterbox
{
/// <summary>
/// syscall emulation layer
/// </summary>
internal class Syscalls : IBinaryStateable
{
public interface IFileObject : IBinaryStateable
{
bool Open(FileAccess access);
bool Close();
Stream Stream { get; }
string Name { get; }
}
private class SpecialFile : IFileObject
{
// stdin, stdout, stderr
public string Name { get; }
public Stream Stream { get; }
public bool Close() => false;
public bool Open(FileAccess access) => false;
public void SaveStateBinary(BinaryWriter writer) { }
public void LoadStateBinary(BinaryReader reader) { }
public SpecialFile(Stream stream, string name)
{
Stream = stream;
Name = name;
}
}
private class ReadonlyFirmware : IFileObject
{
private readonly byte[] _data;
private readonly byte[] _hash;
public string Name { get; }
public Stream Stream { get; private set; }
public bool Close()
{
if (Stream == null)
return false;
Stream = null;
return true;
}
public bool Open(FileAccess access)
{
if (Stream != null || access != FileAccess.Read)
return false;
Stream = new MemoryStream(_data, false);
return true;
}
public void LoadStateBinary(BinaryReader br)
{
if (!br.ReadBytes(_hash.Length).SequenceEqual(_hash))
throw new InvalidOperationException("Savestate internal firmware mismatch");
var pos = br.ReadInt64();
if (pos == -1)
{
Stream = null;
}
else
{
if (Stream == null)
Open(FileAccess.Read);
Stream.Position = pos;
}
}
public void SaveStateBinary(BinaryWriter bw)
{
bw.Write(_hash);
bw.Write(Stream != null ? Stream.Position : -1);
}
public ReadonlyFirmware(byte[] data, string name)
{
_data = data;
_hash = WaterboxUtils.Hash(data);
Name = name;
}
}
private class TransientFile : IFileObject
{
private bool _inUse = false;
public string Name { get; }
public Stream Stream { get; }
public bool Close()
{
if (_inUse)
{
_inUse = false;
return true;
}
else
{
return false;
}
}
public bool Open(FileAccess access)
{
if (_inUse)
{
return false;
}
else
{
// TODO: if access != RW, the resultant handle lets you do those all anyway
_inUse = true;
Stream.Position = 0;
return true;
}
}
public void LoadStateBinary(BinaryReader br)
{
throw new InvalidOperationException("Internal savestate error!");
}
public void SaveStateBinary(BinaryWriter bw)
{
throw new InvalidOperationException("Transient files cannot be savestated!");
}
public TransientFile(byte[] data, string name)
{
Stream = new MemoryStream();
Name = name;
if (data != null)
{
Stream.Write(data, 0, data.Length);
Stream.Position = 0;
}
}
public byte[] GetContents()
{
if (_inUse)
throw new InvalidOperationException();
return ((MemoryStream)Stream).ToArray();
}
}
private readonly List<IFileObject> _openFiles = new List<IFileObject>();
private readonly Dictionary<string, IFileObject> _availableFiles = new Dictionary<string, IFileObject>();
private readonly WaterboxHost _parent;
public Syscalls(WaterboxHost parent)
{
_parent = parent;
var stdin = new SpecialFile(Stream.Null, "___stdin");
var stdout = new SpecialFile(Console.OpenStandardOutput(), "___stdout");
var stderr = new SpecialFile(Console.OpenStandardError(), "___stderr");
_openFiles = new List<IFileObject>
{
stdin,
stdout,
stderr
};
_availableFiles = new Dictionary<string, IFileObject>
{
[stdin.Name] = stdin,
[stdout.Name] = stdout,
[stderr.Name] = stderr
};
}
private Stream StreamForFd(int fd)
{
if (fd >= 0 && fd < _openFiles.Count)
return _openFiles[fd].Stream;
else
return null;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[12]")]
public UIntPtr Brk(UIntPtr _p)
{
var heap = _parent._heap;
var start = heap.Memory.Start;
var currentEnd = start + heap.Used;
var maxEnd = heap.Memory.EndExclusive;
var p = (ulong)_p;
if (p < start || p > maxEnd)
{
// failure: return current break
return Z.UU(currentEnd);
}
else if (p > currentEnd)
{
// increase size of heap
heap.Allocate(p - currentEnd, 1);
return Z.UU(p);
}
else if (p < currentEnd)
{
throw new InvalidOperationException("We don't support shrinking heaps");
}
else
{
// no change
return Z.UU(currentEnd);
}
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[16]")]
public int IoCtl(int fd, ulong req)
{
return 0; // sure it worked, honest
}
public struct Iovec
{
public IntPtr Base;
public ulong Length;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[0]")]
public long Read(int fd, IntPtr buff, ulong count)
{
var s = StreamForFd(fd);
if (s == null || !s.CanRead)
return -1;
var tmp = new byte[count];
var ret = s.Read(tmp, 0, (int)count);
Marshal.Copy(tmp, 0, buff, ret);
return ret;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[1]")]
public long Write(int fd, IntPtr buff, ulong count)
{
var s = StreamForFd(fd);
if (s == null || !s.CanWrite)
return -1;
var tmp = new byte[count];
Marshal.Copy(buff, tmp, 0, (int)count);
s.Write(tmp, 0, tmp.Length);
return (long)count;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[19]")]
public unsafe long Readv(int fd, Iovec* iov, int iovcnt)
{
long ret = 0;
for (int i = 0; i < iovcnt; i++)
{
var len = Read(fd, iov[i].Base, iov[i].Length);
if (len < 0)
return len;
ret += len;
if (len != (long)iov[i].Length)
break;
}
return ret;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[20]")]
public unsafe long Writev(int fd, Iovec* iov, int iovcnt)
{
long ret = 0;
for (int i = 0; i < iovcnt; i++)
{
if (iov[i].Base != IntPtr.Zero)
ret += Write(fd, iov[i].Base, iov[i].Length);
}
return ret;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[2]")]
public int Open(string path, int flags, int mode)
{
if (!_availableFiles.TryGetValue(path, out var o))
return -1;
if (_openFiles.Contains(o))
return -1;
FileAccess access;
switch (flags & 3)
{
case 0:
access = FileAccess.Read;
break;
case 1:
access = FileAccess.Write;
break;
case 2:
access = FileAccess.ReadWrite;
break;
default:
return -1;
}
if (!o.Open(access))
return -1;
int fd;
for (fd = 0; fd < _openFiles.Count; fd++)
if (_openFiles[fd] == null)
break;
if (fd == _openFiles.Count)
_openFiles.Add(o);
else
_openFiles[fd] = o;
return fd;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[3]")]
public int Close(int fd)
{
if (fd < 0 || fd >= _openFiles.Count)
return -1;
var o = _openFiles[fd];
if (o == null || !o.Close())
return -1;
_openFiles[fd] = null;
return 0;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[8]")]
public long Seek(int fd, long offset, int type)
{
var s = StreamForFd(fd);
if (s == null || !s.CanSeek)
return -1;
SeekOrigin o;
switch (type)
{
case 0:
o = SeekOrigin.Begin;
break;
case 1:
o = SeekOrigin.Current;
break;
case 2:
o = SeekOrigin.End;
break;
default:
return -1;
}
return s.Seek(offset, o);
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[4]")]
public int Stat(string path, IntPtr statbuf)
{
return -1;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[5]")]
public int Fstat(int fd, IntPtr statbuf)
{
return -1;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[205]")]
public long SetThreadArea(IntPtr uinfo)
{
return 38; // ENOSYS
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[218]")]
public long SetTidAddress(IntPtr address)
{
return 8675309; // arbitrary thread id
}
[StructLayout(LayoutKind.Sequential)]
public class TimeSpec
{
public long Seconds;
public long NanoSeconds;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[228]")]
public int SysClockGetTime(int which, [In, Out] TimeSpec time)
{
time.Seconds = 1495889068;
time.NanoSeconds = 0;
return 0;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[9]")]
public IntPtr MMap(IntPtr address, UIntPtr size, int prot, int flags, int fd, IntPtr offs)
{
if (address != IntPtr.Zero)
return Z.SS(-1);
MemoryBlockBase.Protection mprot;
switch (prot)
{
case 0: mprot = MemoryBlockBase.Protection.None; break;
default:
case 6: // W^X
case 7: // W^X
case 4: // exec only????
case 2: return Z.SS(-1); // write only????
case 3: mprot = MemoryBlockBase.Protection.RW; break;
case 1: mprot = MemoryBlockBase.Protection.R; break;
case 5: mprot = MemoryBlockBase.Protection.RX; break;
}
if ((flags & 0x20) == 0)
{
// MAP_ANONYMOUS is required
return Z.SS(-1);
}
if ((flags & 0xf00) != 0)
{
// various unsupported flags
return Z.SS(-1);
}
var ret = _parent._mmapheap.Map((ulong)size, mprot);
return ret == 0 ? Z.SS(-1) : Z.US(ret);
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[25]")]
public IntPtr MRemap(UIntPtr oldAddress, UIntPtr oldSize,
UIntPtr newSize, int flags)
{
if ((flags & 2) != 0)
{
// don't support MREMAP_FIXED
return Z.SS(-1);
}
var ret = _parent._mmapheap.Remap((ulong)oldAddress, (ulong)oldSize, (ulong)newSize,
(flags & 1) != 0);
return ret == 0 ? Z.SS(-1) : Z.US(ret);
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[11]")]
public int MUnmap(UIntPtr address, UIntPtr size)
{
return _parent._mmapheap.Unmap((ulong)address, (ulong)size) ? 0 : -1;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[10]")]
public int MProtect(UIntPtr address, UIntPtr size, int prot)
{
MemoryBlockBase.Protection mprot;
switch (prot)
{
case 0: mprot = MemoryBlockBase.Protection.None; break;
default:
case 6: // W^X
case 7: // W^X
case 4: // exec only????
case 2: return -1; // write only????
case 3: mprot = MemoryBlockBase.Protection.RW; break;
case 1: mprot = MemoryBlockBase.Protection.R; break;
case 5: mprot = MemoryBlockBase.Protection.RX; break;
}
return _parent._mmapheap.Protect((ulong)address, (ulong)size, mprot) ? 0 : -1;
}
public void SaveStateBinary(BinaryWriter bw)
{
bw.Write(_availableFiles.Count);
foreach (var f in _availableFiles.Values.OrderBy(f => f.Name))
{
bw.Write(f.Name);
f.SaveStateBinary(bw);
}
bw.Write(_openFiles.Count);
foreach (var f in _openFiles)
{
bw.Write(f != null);
if (f != null)
bw.Write(f.Name);
}
}
public void LoadStateBinary(BinaryReader br)
{
if (_availableFiles.Count != br.ReadInt32())
throw new InvalidOperationException("Internal savestate error: Filelist change");
foreach (var f in _availableFiles.Values.OrderBy(f => f.Name))
{
if (br.ReadString() != f.Name)
throw new InvalidOperationException("Internal savestate error: Filelist change");
f.LoadStateBinary(br);
}
var c = br.ReadInt32();
_openFiles.Clear();
for (int i = 0; i < c; i++)
{
_openFiles.Add(br.ReadBoolean() ? _availableFiles[br.ReadString()] : null);
}
}
private T RemoveFileInternal<T>(string name)
where T : IFileObject
{
if (!_availableFiles.TryGetValue(name, out var o))
throw new InvalidOperationException("File was never registered!");
if (o.GetType() != typeof(T))
throw new InvalidOperationException("Object was not a the right kind of file");
if (_openFiles.Contains(o))
throw new InvalidOperationException("Core never closed the file!");
_availableFiles.Remove(name);
return (T)o;
}
public void AddReadonlyFile(byte[] data, string name)
{
_availableFiles.Add(name, new ReadonlyFirmware(data, name));
}
public void RemoveReadonlyFile(string name)
{
RemoveFileInternal<ReadonlyFirmware>(name);
}
public void AddTransientFile(byte[] data, string name)
{
_availableFiles.Add(name, new TransientFile(data, name));
}
public byte[] RemoveTransientFile(string name)
{
return RemoveFileInternal<TransientFile>(name).GetContents();
}
}
/// <summary>
/// Provides useful traps for any syscalls that are not implemented by libc
/// </summary>
internal class NotImplementedSyscalls : IImportResolver
{
private class Trap
{
private readonly int _index;
private readonly IImportResolver _resolver;
public Trap(int index)
{
_index = index;
_resolver = BizExvoker.GetExvoker(this, CallingConventionAdapters.Waterbox);
}
[BizExport(CallingConvention.Cdecl, EntryPoint="@@")]
public void RunTrap()
{
var s = $"Trapped on unimplemented syscall {_index}";
Console.WriteLine(s);
throw new InvalidOperationException(s);
}
public IntPtr FunctionPointer => _resolver.GetProcAddrOrThrow("@@");
}
private readonly List<Trap> _traps;
private NotImplementedSyscalls()
{
_traps = Enumerable.Range(0, 512)
.Select(i => new Trap(i))
.ToList();
}
private static readonly Regex ExportRegex = new Regex("__wsyscalltab\\[(\\d+)\\]");
public IntPtr GetProcAddrOrZero(string entryPoint)
{
var m = ExportRegex.Match(entryPoint);
if (m.Success)
{
return _traps[int.Parse(m.Groups[1].Value)].FunctionPointer;
}
return IntPtr.Zero;
}
public IntPtr GetProcAddrOrThrow(string entryPoint)
{
var m = ExportRegex.Match(entryPoint);
if (m.Success)
{
return _traps[int.Parse(m.Groups[1].Value)].FunctionPointer;
}
throw new InvalidOperationException($"{entryPoint} was not of the format __wsyscalltab[#]");
}
public static NotImplementedSyscalls Instance { get; } = new NotImplementedSyscalls();
}
}

View File

@ -12,7 +12,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
IInputPollable, ISaveRam IInputPollable, ISaveRam
{ {
private LibWaterboxCore _core; private LibWaterboxCore _core;
protected PeRunner _exe; protected WaterboxHost _exe;
protected LibWaterboxCore.MemoryArea[] _memoryAreas; protected LibWaterboxCore.MemoryArea[] _memoryAreas;
private LibWaterboxCore.EmptyCallback _inputCallback; private LibWaterboxCore.EmptyCallback _inputCallback;
protected CoreComm CoreComm { get; } protected CoreComm CoreComm { get; }
@ -43,11 +43,11 @@ namespace BizHawk.Emulation.Cores.Waterbox
_inputCallback = InputCallbacks.Call; _inputCallback = InputCallbacks.Call;
} }
protected T PreInit<T>(PeRunnerOptions options) protected T PreInit<T>(WaterboxOptions options)
where T : LibWaterboxCore where T : LibWaterboxCore
{ {
options.Path ??= CoreComm.CoreFileProvider.DllPath(); options.Path ??= CoreComm.CoreFileProvider.DllPath();
_exe = new PeRunner(options); _exe = new WaterboxHost(options);
using (_exe.EnterExit()) using (_exe.EnterExit())
{ {
var ret = BizInvoker.GetInvoker<T>(_exe, _exe, CallingConventionAdapters.Waterbox); var ret = BizInvoker.GetInvoker<T>(_exe, _exe, CallingConventionAdapters.Waterbox);

View File

@ -0,0 +1,405 @@
using BizHawk.Common;
using BizHawk.BizInvoke;
using BizHawk.Emulation.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
namespace BizHawk.Emulation.Cores.Waterbox
{
public class WaterboxOptions
{
// string directory, string filename, ulong heapsize, ulong sealedheapsize, ulong invisibleheapsize
/// <summary>
/// path which the main executable and all associated libraries should be found
/// </summary>
public string Path { get; set; }
/// <summary>
/// filename of the main executable; expected to be in Path
/// </summary>
public string Filename { get; set; }
/// <summary>
/// how large the normal heap should be. it services sbrk calls
/// can be 0, but sbrk calls will crash.
/// </summary>
public uint SbrkHeapSizeKB { get; set; }
/// <summary>
/// how large the sealed heap should be. it services special allocations that become readonly after init
/// Must be > 0 and at least large enough to store argv and envp, and any alloc_sealed() calls
/// </summary>
public uint SealedHeapSizeKB { get; set; }
/// <summary>
/// how large the invisible heap should be. it services special allocations which are not savestated
/// Must be > 0 and at least large enough for the internal vtables, and any alloc_invisible() calls
/// </summary>
public uint InvisibleHeapSizeKB { get; set; }
/// <summary>
/// how large the "plain" heap should be. it is savestated, and contains
/// Must be > 0 and at least large enough for the internal pthread structure, and any alloc_plain() calls
/// </summary>
public uint PlainHeapSizeKB { get; set; }
/// <summary>
/// how large the mmap heap should be. it is savestated.
/// can be 0, but mmap calls will crash.
/// </summary>
public uint MmapHeapSizeKB { get; set; }
/// <summary>
/// start address in memory
/// </summary>
public ulong StartAddress { get; set; } = WaterboxHost.CanonicalStart;
/// <summary>
/// Skips the check that the wbx file and other associated dlls match from state save to state load.
/// DO NOT SET THIS TO TRUE. A different executable most likely means different meanings for memory locations,
/// and nothing will make sense.
/// </summary>
public bool SkipCoreConsistencyCheck { get; set; } = false;
/// <summary>
/// Skips the check that the initial memory state (after init, but before any running) matches from state save to state load.
/// DO NOT SET THIS TO TRUE. The initial memory state must be the same for the XORed memory contents in the savestate to make sense.
/// </summary>
public bool SkipMemoryConsistencyCheck { get; set; } = false;
}
public class WaterboxHost : Swappable, IImportResolver, IBinaryStateable
{
/// <summary>
/// usual starting point for the executable
/// </summary>
public const ulong CanonicalStart = 0x0000036f00000000;
/// <summary>
/// the next place where we can put a module or heap
/// </summary>
private ulong _nextStart = CanonicalStart;
/// <summary>
/// increment _nextStart after adding a module
/// </summary>
private void ComputeNextStart(ulong size)
{
_nextStart += size;
// align to 1MB, then increment 16MB
_nextStart = ((_nextStart - 1) | 0xfffff) + 0x1000001;
}
/// <summary>
/// standard malloc() heap
/// </summary>
internal Heap _heap;
/// <summary>
/// sealed heap (writable only during init)
/// </summary>
internal Heap _sealedheap;
/// <summary>
/// invisible heap (not savestated, use with care)
/// </summary>
internal Heap _invisibleheap;
/// <summary>
/// extra savestated heap
/// </summary>
internal Heap _plainheap;
/// <summary>
/// memory map emulation
/// </summary>
internal MapHeap _mmapheap;
/// <summary>
/// the loaded elf file
/// </summary>
private ElfLoader _module;
/// <summary>
/// all loaded heaps
/// </summary>
private readonly List<Heap> _heaps = new List<Heap>();
/// <summary>
/// anything at all that needs to be disposed on finish
/// </summary>
private readonly List<IDisposable> _disposeList = new List<IDisposable>();
/// <summary>
/// anything at all that needs its state saved and loaded
/// </summary>
private readonly List<IBinaryStateable> _savestateComponents = new List<IBinaryStateable>();
private readonly EmuLibc _emu;
private readonly Syscalls _syscalls;
/// <summary>
/// the set of functions made available for the elf module
/// </summary>
private readonly IImportResolver _imports;
/// <summary>
/// timestamp of creation acts as a sort of "object id" in the savestate
/// </summary>
private readonly long _createstamp = WaterboxUtils.Timestamp();
private Heap CreateHeapHelper(uint sizeKB, string name, bool saveStated)
{
if (sizeKB != 0)
{
var heap = new Heap(_nextStart, sizeKB * 1024, name);
heap.Memory.Activate();
ComputeNextStart(sizeKB * 1024);
AddMemoryBlock(heap.Memory, name);
if (saveStated)
_savestateComponents.Add(heap);
_disposeList.Add(heap);
_heaps.Add(heap);
return heap;
}
else
{
return null;
}
}
public WaterboxHost(WaterboxOptions opt)
{
_nextStart = opt.StartAddress;
Initialize(_nextStart);
using (this.EnterExit())
{
_emu = new EmuLibc(this);
_syscalls = new Syscalls(this);
_imports = new PatchImportResolver(
NotImplementedSyscalls.Instance,
BizExvoker.GetExvoker(_emu, CallingConventionAdapters.Waterbox),
BizExvoker.GetExvoker(_syscalls, CallingConventionAdapters.Waterbox)
);
if (true)
{
var moduleName = opt.Filename;
var path = Path.Combine(opt.Path, moduleName);
var gzpath = path + ".gz";
byte[] data;
if (File.Exists(gzpath))
{
using var fs = new FileStream(gzpath, FileMode.Open, FileAccess.Read);
data = Util.DecompressGzipFile(fs);
}
else
{
data = File.ReadAllBytes(path);
}
_module = new ElfLoader(moduleName, data, _nextStart, opt.SkipCoreConsistencyCheck, opt.SkipMemoryConsistencyCheck);
ComputeNextStart(_module.Memory.Size);
AddMemoryBlock(_module.Memory, moduleName);
_savestateComponents.Add(_module);
_disposeList.Add(_module);
}
ConnectAllImports();
// load all heaps
_heap = CreateHeapHelper(opt.SbrkHeapSizeKB, "brk-heap", true);
_sealedheap = CreateHeapHelper(opt.SealedHeapSizeKB, "sealed-heap", true);
_invisibleheap = CreateHeapHelper(opt.InvisibleHeapSizeKB, "invisible-heap", false);
_plainheap = CreateHeapHelper(opt.PlainHeapSizeKB, "plain-heap", true);
if (opt.MmapHeapSizeKB != 0)
{
_mmapheap = new MapHeap(_nextStart, opt.MmapHeapSizeKB * 1024, "mmap-heap");
_mmapheap.Memory.Activate();
ComputeNextStart(opt.MmapHeapSizeKB * 1024);
AddMemoryBlock(_mmapheap.Memory, "mmap-heap");
_savestateComponents.Add(_mmapheap);
_disposeList.Add(_mmapheap);
}
Console.WriteLine("About to enter unmanaged code");
if (!OSTailoredCode.IsUnixHost && !System.Diagnostics.Debugger.IsAttached && Win32Imports.IsDebuggerPresent())
{
// this means that GDB or another unconventional debugger is attached.
// if that's the case, and it's observing this core, it probably wants a break
System.Diagnostics.Debugger.Break();
}
_module.RunNativeInit();
}
}
public IntPtr GetProcAddrOrZero(string entryPoint)
{
var addr = _module.GetProcAddrOrZero(entryPoint);
if (addr != IntPtr.Zero)
{
var exclude = _imports.GetProcAddrOrZero(entryPoint);
if (exclude != IntPtr.Zero)
{
// don't reexport anything that's part of waterbox internals
return IntPtr.Zero;
}
}
return addr;
}
public IntPtr GetProcAddrOrThrow(string entryPoint)
{
var addr = _module.GetProcAddrOrZero(entryPoint);
if (addr != IntPtr.Zero)
{
var exclude = _imports.GetProcAddrOrZero(entryPoint);
if (exclude != IntPtr.Zero)
{
// don't reexport anything that's part of waterbox internals
throw new InvalidOperationException($"Tried to resolve {entryPoint}, but it should not be exported");
}
else
{
return addr;
}
}
else
{
throw new InvalidOperationException($"{entryPoint} was not exported from elf");
}
}
public void Seal()
{
using (this.EnterExit())
{
// if libco is used, the jmp_buf for the main cothread can have stack stuff in it.
// this isn't a problem, since we only savestate when the core is not running, and
// the next time it's run, that buf will be overridden again.
// but it breaks xor state verification, so when we seal, nuke it.
// this could be the responsibility of something else other than the PeRunner; I am not sure yet...
// TODO: MAKE SURE THIS STILL WORKS
IntPtr co_clean;
if ((co_clean = _module.GetProcAddrOrZero("co_clean")) != IntPtr.Zero)
{
Console.WriteLine("Calling co_clean()...");
CallingConventionAdapters.Waterbox.GetDelegateForFunctionPointer<Action>(co_clean)();
}
_sealedheap.Seal();
foreach (var h in _heaps)
{
if (h != _invisibleheap && h != _sealedheap) // TODO: if we have more non-savestated heaps, refine this hack
h.Memory.SaveXorSnapshot();
}
_module.SealImportsAndTakeXorSnapshot();
_mmapheap?.Memory.SaveXorSnapshot();
}
}
private void ConnectAllImports()
{
_module.ConnectSyscalls(_imports);
}
/// <summary>
/// Adds a file that will appear to the waterbox core's libc. the file will be read only.
/// All savestates must have the same file list, so either leave it up forever or remove it during init!
/// </summary>
/// <param name="name">the filename that the unmanaged core will access the file by</param>
public void AddReadonlyFile(byte[] data, string name)
{
_syscalls.AddReadonlyFile((byte[])data.Clone(), name);
}
/// <summary>
/// Remove a file previously added by AddReadonlyFile. Frees the internal copy of the filedata, saving memory.
/// All savestates must have the same file list, so either leave it up forever or remove it during init!
/// </summary>
public void RemoveReadonlyFile(string name)
{
_syscalls.RemoveReadonlyFile(name);
}
/// <summary>
/// Add a transient file that will appear to the waterbox core's libc. The file will be readable
/// and writable. Any attempt to save state while the file is loaded will fail.
/// </summary>
public void AddTransientFile(byte[] data, string name)
{
_syscalls.AddTransientFile(data, name); // don't need to clone data, as it's used at init only
}
/// <summary>
/// Remove a file previously added by AddTransientFile
/// </summary>
/// <returns>The state of the file when it was removed</returns>
public byte[] RemoveTransientFile(string name)
{
return _syscalls.RemoveTransientFile(name);
}
public void SaveStateBinary(BinaryWriter bw)
{
bw.Write(_createstamp);
bw.Write(_savestateComponents.Count);
using (this.EnterExit())
{
foreach (var c in _savestateComponents)
{
c.SaveStateBinary(bw);
}
}
}
public void LoadStateBinary(BinaryReader br)
{
var differentCore = br.ReadInt64() != _createstamp; // true if a different core instance created the state
if (br.ReadInt32() != _savestateComponents.Count)
throw new InvalidOperationException("Internal savestate error");
using (this.EnterExit())
{
foreach (var c in _savestateComponents)
{
c.LoadStateBinary(br);
}
if (differentCore)
{
// if a different runtime instance than this one saved the state,
// Exvoker imports need to be reconnected
Console.WriteLine($"Restoring {nameof(WaterboxHost)} state from a different core...");
ConnectAllImports();
}
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
foreach (var d in _disposeList)
d.Dispose();
_disposeList.Clear();
PurgeMemoryBlocks();
_module = null;
_heap = null;
_sealedheap = null;
_invisibleheap = null;
_plainheap = null;
_mmapheap = null;
}
}
}
}

1
waterbox/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/sysroot

104
waterbox/common.mak Normal file
View File

@ -0,0 +1,104 @@
# common parts of all waterbox cores
WATERBOX_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
ROOT_DIR := $(shell dirname $(realpath $(lastword $(filter-out $(lastword $(MAKEFILE_LIST)), $(MAKEFILE_LIST)))))
OUTPUTDLL_DIR := $(realpath $(WATERBOX_DIR)/../output/dll)
OBJ_DIR := $(ROOT_DIR)/obj/release
DOBJ_DIR := $(ROOT_DIR)/obj/debug
EMULIBC_OBJS := $(WATERBOX_DIR)/emulibc/obj/release/emulibc.c.o
EMULIBC_DOBJS := $(WATERBOX_DIR)/emulibc/obj/debug/emulibc.c.o
SYSROOT := $(WATERBOX_DIR)/sysroot
ifdef NEED_LIBCO
EMULIBC_OBJS := $(EMULIBC_OBJS) $(shell find $(WATERBOX_DIR)/libco/obj/release -type f -name '*.o')
EMULIBC_DOBJS := $(EMULIBC_DOBJS) $(shell find $(WATERBOX_DIR)/libco/obj/debug -type f -name '*.o')
endif
print-%: ;
@echo $* = $($*)
#LD_PLUGIN := $(shell gcc --print-file-name=liblto_plugin.so)
CC := $(SYSROOT)/bin/musl-gcc
CCFLAGS := $(CCFLAGS) -mabi=ms -fvisibility=hidden -I$(WATERBOX_DIR)/emulibc -Wall -mcmodel=large \
-mstack-protector-guard=global
LDFLAGS := $(LDFLAGS) -fuse-ld=gold -static -Wl,-Ttext,0x0000036f00000000 #-Wl,--plugin,$(LD_PLUGIN)
CCFLAGS_DEBUG := -O0 -g
CCFLAGS_RELEASE := -O3 -flto
LDFLAGS_DEBUG :=
LDFLAGS_RELEASE :=
CXXFLAGS := $(CXXFLAGS) -I$(SYSROOT)/include/c++/v1 -fno-use-cxa-atexit
CXXFLAGS_DEBUG :=
CXXFLAGS_RELEASE :=
EXTRA_LIBS := -L $(SYSROOT)/lib/linux -lclang_rt.builtins-x86_64
ifneq ($(filter %.cpp, $(SRCS)), )
EXTRA_LIBS := -lc++ -lc++abi -lunwind $(EXTRA_LIBS)
endif
_OBJS := $(addsuffix .o, $(realpath $(SRCS)))
OBJS := $(patsubst $(ROOT_DIR)%, $(OBJ_DIR)%, $(_OBJS))
DOBJS := $(patsubst $(ROOT_DIR)%, $(DOBJ_DIR)%, $(_OBJS))
$(OBJ_DIR)/%.c.o: %.c
@echo cc $<
@mkdir -p $(@D)
@$(CC) -c -o $@ $< $(CCFLAGS) $(CCFLAGS_RELEASE)
$(OBJ_DIR)/%.cpp.o: %.cpp
@echo cxx $<
@mkdir -p $(@D)
@$(CC) -c -o $@ $< $(CCFLAGS) $(CXXFLAGS) $(CCFLAGS_RELEASE)
$(DOBJ_DIR)/%.c.o: %.c
@echo cc $<
@mkdir -p $(@D)
@$(CC) -c -o $@ $< $(CCFLAGS) $(CCFLAGS_DEBUG)
$(DOBJ_DIR)/%.cpp.o: %.cpp
@echo cxx $<
@mkdir -p $(@D)
@$(CC) -c -o $@ $< $(CCFLAGS) $(CXXFLAGS) $(CCFLAGS_DEBUG) $(CXXFLAGS_DEBUG)
ifndef NO_WBX_TARGETS
.DEFAULT_GOAL := release
TARGET_RELEASE := $(OBJ_DIR)/$(TARGET)
TARGET_DEBUG := $(DOBJ_DIR)/$(TARGET)
.PHONY: release debug install install-debug
release: $(TARGET_RELEASE)
debug: $(TARGET_DEBUG)
$(TARGET_RELEASE): $(OBJS) $(EMULIBC_OBJS)
@echo ld $@
@$(CC) -o $@ $(LDFLAGS) $(LDFLAGS_RELEASE) $(CCFLAGS) $(CCFLAGS_RELEASE) $(OBJS) $(EMULIBC_OBJS) $(EXTRA_LIBS)
$(TARGET_DEBUG): $(DOBJS) $(EMULIBC_DOBJS)
@echo ld $@
@$(CC) -o $@ $(LDFLAGS) $(LDFLAGS_DEBUG) $(CCFLAGS) $(CCFLAGS_DEBUG) $(DOBJS) $(EMULIBC_DOBJS) $(EXTRA_LIBS)
install: $(TARGET_RELEASE)
@cp -f $< $(OUTPUTDLL_DIR)
@gzip --stdout --best $< > $(OUTPUTDLL_DIR)/$(TARGET).gz
@echo Release build of $(TARGET) installed.
install-debug: $(TARGET_DEBUG)
@cp -f $< $(OUTPUTDLL_DIR)
@gzip --stdout --best $< > $(OUTPUTDLL_DIR)/$(TARGET).gz
@echo Debug build of $(TARGET) installed.
else
.DEFAULT_GOAL = all
.PHONY: all
all: $(OBJS) $(DOBJS)
endif
.PHONY: clean clean-release clean-debug
clean:
rm -rf $(ROOT_DIR)/obj
clean-release:
rm -rf $(ROOT_DIR)/obj/release
clean-debug:
rm -rf $(ROOT_DIR)/obj/debug

View File

@ -1,32 +1,4 @@
CC = x86_64-nt64-midipix-gcc NO_WBX_TARGETS := 1
CCFLAGS := -Wall
CCFLAGS:= -Wall -O2# -mcmodel=large SRCS = $(shell find $(ROOT_DIR) -type f -name '*.c')
include ../common.mak
TARGET = libemuhost.so
LDFLAGS = -shared
ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
SRCS:=$(shell find $(ROOT_DIR) -type f -name '*.c')
OBJ_DIR:=$(ROOT_DIR)/obj
_OBJS:=$(SRCS:.c=.o)
OBJS:=$(patsubst $(ROOT_DIR)%,$(OBJ_DIR)%,$(_OBJS))
$(OBJ_DIR)/%.o: %.c
@mkdir -p $(@D)
@$(CC) -c -o $@ $< $(CCFLAGS)
all: $(TARGET)
.PHONY: clean all
$(TARGET) : $(OBJS)
@$(CC) -o $@ $(LDFLAGS) $(CCFLAGS) $(OBJS)
clean:
rm -rf $(OBJ_DIR)
rm -f $(TARGET)
#install:
# $(CP) $(TARGET) $(DEST_$(ARCH))

View File

@ -1,7 +1,27 @@
#include "emulibc.h" #include "emulibc.h"
// this is just used to build a dummy .so file that isn't used #define __WBXSYSCALL __attribute__((section(".wbxsyscall"))) __attribute__((visibility("default")))
void *alloc_sealed(size_t size) { return NULL; }
void *alloc_invisible(size_t size) { return NULL; } __WBXSYSCALL void *(*__walloc_sealed)(size_t);
void *alloc_plain(size_t size) { return NULL; } void *alloc_sealed(size_t size)
void _debug_puts(const char *s) { } {
return __walloc_sealed(size);
}
__WBXSYSCALL void *(*__walloc_invisible)(size_t);
void *alloc_invisible(size_t size)
{
return __walloc_invisible(size);
}
__WBXSYSCALL void *(*__walloc_plain)(size_t);
void *alloc_plain(size_t size)
{
return __walloc_plain(size);
}
__WBXSYSCALL void (*__w_debug_puts)(const char *);
void _debug_puts(const char *s)
{
__w_debug_puts(s);
}

View File

@ -1,48 +1,48 @@
#ifndef _EMULIBC_H #ifndef _EMULIBC_H
#define _EMULIBC_H #define _EMULIBC_H
#include <stddef.h> #include <stddef.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
// mark an entry point or callback pointer // mark an entry point or callback pointer
#define ECL_ENTRY #define ECL_ENTRY
// mark a visible symbol // mark a visible symbol
#ifdef __cplusplus #ifdef __cplusplus
#define ECL_EXPORT extern "C" __attribute__((visibility("default"))) #define ECL_EXPORT extern "C" __attribute__((visibility("default"))) __attribute__((used))
#else #else
#define ECL_EXPORT __attribute__((visibility("default"))) #define ECL_EXPORT __attribute__((visibility("default"))) __attribute__((used))
#endif #endif
// allocate memory from the "sealed" pool. this memory can never be freed, // allocate memory from the "sealed" pool. this memory can never be freed,
// and can only be allocated or written to during the init phase. after that, the host // and can only be allocated or written to during the init phase. after that, the host
// seals the pool, making it read only and all of its contents frozen. good for LUTs and // seals the pool, making it read only and all of its contents frozen. good for LUTs and
// ROMs // ROMs
void *alloc_sealed(size_t size); void *alloc_sealed(size_t size);
// allocate memory from the "invisible" pool. this memory can never be freed. // allocate memory from the "invisible" pool. this memory can never be freed.
// this memory is not savestated! this should only be used for a large buffer whose contents // this memory is not savestated! this should only be used for a large buffer whose contents
// you are absolutely sure will not harm savestates // you are absolutely sure will not harm savestates
void *alloc_invisible(size_t size); void *alloc_invisible(size_t size);
// allocate memory from the "plain" pool. this memory can never be freed. // allocate memory from the "plain" pool. this memory can never be freed.
// this memory is savestated normally. // this memory is savestated normally.
// useful to avoid malloc() overhead for things that will never be freed // useful to avoid malloc() overhead for things that will never be freed
void *alloc_plain(size_t size); void *alloc_plain(size_t size);
// send a debug string somewhere, bypassing stdio // send a debug string somewhere, bypassing stdio
void _debug_puts(const char *); void _debug_puts(const char *);
// put data in a section that will have similar behavior characteristics to alloc_sealed // put data in a section that will have similar behavior characteristics to alloc_sealed
#define ECL_SEALED __attribute__((section(".sealed"))) #define ECL_SEALED __attribute__((section(".sealed")))
// put data in a section that will have similar behavior characteristics to alloc_invisible // put data in a section that will have similar behavior characteristics to alloc_invisible
#define ECL_INVISIBLE __attribute__((section(".invis"))) #define ECL_INVISIBLE __attribute__((section(".invis")))
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif #endif

Binary file not shown.

View File

@ -1,42 +1,13 @@
CC = x86_64-nt64-midipix-gcc CCFLAGS := -Icore -Iutil -Icore/m68k -Icore/z80 -Icore/input_hw \
-Icore/cart_hw -Icore/cart_hw/svp -Icore/sound -Icore/ntsc -Icore/cd_hw \
CCFLAGS:=-Icore -Iutil -Icore/m68k -Icore/z80 -Icore/input_hw \ -Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=implicit-function-declaration \
-Icore/cart_hw -Icore/cart_hw/svp -Icore/sound -Icore/ntsc -Icore/cd_hw \ -std=c99 -fomit-frame-pointer \
-I../emulibc \ -DLSB_FIRST -DUSE_32BPP_RENDERING -DINLINE=static\ __inline__
-Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=implicit-function-declaration \
-std=c99 -fomit-frame-pointer -fvisibility=hidden \ LDFLAGS :=
-DLSB_FIRST -DUSE_32BPP_RENDERING -DINLINE=static\ __inline__ \
-O3 -flto TARGET := gpgx.wbx
TARGET = gpgx.wbx SRCS = $(shell find $(ROOT_DIR) -type f -name '*.c')
LDFLAGS = -Wl,--dynamicbase,--export-all-symbols include ../common.mak
ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
SRCS:=$(shell find $(ROOT_DIR) -type f -name '*.c')
OBJ_DIR:=$(ROOT_DIR)/obj
_OBJS:=$(SRCS:.c=.o)
OBJS:=$(patsubst $(ROOT_DIR)%,$(OBJ_DIR)%,$(_OBJS))
$(OBJ_DIR)/%.o: %.c
@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
clean:
rm -rf $(OBJ_DIR)
rm -f $(TARGET).in
rm -f $(TARGET)
#install:
# $(CP) $(TARGET) $(DEST_$(ARCH))

View File

@ -42,21 +42,17 @@ extern uint8 border;
int cinterface_force_sram = 0; int cinterface_force_sram = 0;
#ifdef _MSC_VER #define GPGX_EX ECL_EXPORT
#define GPGX_EX __declspec(dllexport)
#else
#define GPGX_EX __attribute__((visibility("default"))) ECL_ENTRY
#endif
static int vwidth; static int vwidth;
static int vheight; static int vheight;
static uint8_t brm_format[0x40] = static uint8_t brm_format[0x40] =
{ {
0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x00,0x00,0x00,0x00,0x40, 0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x00,0x00,0x00,0x00,0x40,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x53,0x45,0x47,0x41,0x5f,0x43,0x44,0x5f,0x52,0x4f,0x4d,0x00,0x01,0x00,0x00,0x00, 0x53,0x45,0x47,0x41,0x5f,0x43,0x44,0x5f,0x52,0x4f,0x4d,0x00,0x01,0x00,0x00,0x00,
0x52,0x41,0x4d,0x5f,0x43,0x41,0x52,0x54,0x52,0x49,0x44,0x47,0x45,0x5f,0x5f,0x5f 0x52,0x41,0x4d,0x5f,0x43,0x41,0x52,0x54,0x52,0x49,0x44,0x47,0x45,0x5f,0x5f,0x5f
}; };
ECL_ENTRY void (*biz_execcb)(unsigned addr); ECL_ENTRY void (*biz_execcb)(unsigned addr);
@ -69,21 +65,21 @@ uint8 *tempsram;
static void update_viewport(void) static void update_viewport(void)
{ {
vwidth = bitmap.viewport.w + (bitmap.viewport.x * 2); vwidth = bitmap.viewport.w + (bitmap.viewport.x * 2);
vheight = bitmap.viewport.h + (bitmap.viewport.y * 2); vheight = bitmap.viewport.h + (bitmap.viewport.y * 2);
if (config.ntsc) if (config.ntsc)
{ {
if (reg[12] & 1) if (reg[12] & 1)
vwidth = MD_NTSC_OUT_WIDTH(vwidth); vwidth = MD_NTSC_OUT_WIDTH(vwidth);
else else
vwidth = SMS_NTSC_OUT_WIDTH(vwidth); vwidth = SMS_NTSC_OUT_WIDTH(vwidth);
} }
if (config.render && interlaced) if (config.render && interlaced)
{ {
vheight = vheight * 2; vheight = vheight * 2;
} }
} }
GPGX_EX void gpgx_get_video(int *w, int *h, int *pitch, void **buffer) GPGX_EX void gpgx_get_video(int *w, int *h, int *pitch, void **buffer)
@ -144,7 +140,7 @@ GPGX_EX void gpgx_set_input_callback(ECL_ENTRY void (*fecb)(void))
GPGX_EX void gpgx_set_cdd_callback(ECL_ENTRY void (*cddcb)(int lba, void *dest, int audio)) GPGX_EX void gpgx_set_cdd_callback(ECL_ENTRY void (*cddcb)(int lba, void *dest, int audio))
{ {
cdd_readcallback = cddcb; cdd_readcallback = cddcb;
} }
ECL_ENTRY int (*load_archive_cb)(const char *filename, unsigned char *buffer, int maxsize); ECL_ENTRY int (*load_archive_cb)(const char *filename, unsigned char *buffer, int maxsize);
@ -283,7 +279,7 @@ GPGX_EX void* gpgx_get_sram(int *size)
} }
else if (cdd.loaded && scd.cartridge.id) else if (cdd.loaded && scd.cartridge.id)
{ {
int sz = scd.cartridge.mask + 1; int sz = scd.cartridge.mask + 1;
memcpy(tempsram, scd.cartridge.area, sz); memcpy(tempsram, scd.cartridge.area, sz);
memcpy(tempsram + sz, scd.bram, 0x2000); memcpy(tempsram + sz, scd.bram, 0x2000);
*size = sz + 0x2000; *size = sz + 0x2000;
@ -295,14 +291,14 @@ GPGX_EX void* gpgx_get_sram(int *size)
return scd.bram; return scd.bram;
} }
else if (scd.cartridge.id) else if (scd.cartridge.id)
{ {
*size = scd.cartridge.mask + 1; *size = scd.cartridge.mask + 1;
return scd.cartridge.area; return scd.cartridge.area;
} }
else else
{ {
*size = 0; *size = 0;
return NULL; return NULL;
} }
} }
@ -310,40 +306,40 @@ GPGX_EX int gpgx_put_sram(const uint8 *data, int size)
{ {
if (sram.on) if (sram.on)
{ {
if (size != saveramsize()) if (size != saveramsize())
return 0; return 0;
memcpy(sram.sram, data, size); memcpy(sram.sram, data, size);
return 1; return 1;
} }
else if (cdd.loaded && scd.cartridge.id) else if (cdd.loaded && scd.cartridge.id)
{ {
int sz = scd.cartridge.mask + 1; int sz = scd.cartridge.mask + 1;
if (size != sz + 0x2000) if (size != sz + 0x2000)
return 0; return 0;
memcpy(scd.cartridge.area, data, sz); memcpy(scd.cartridge.area, data, sz);
memcpy(scd.bram, data + sz, 0x2000); memcpy(scd.bram, data + sz, 0x2000);
return 1; return 1;
} }
else if (cdd.loaded) else if (cdd.loaded)
{ {
if (size != 0x2000) if (size != 0x2000)
return 0; return 0;
memcpy(scd.bram, data, size); memcpy(scd.bram, data, size);
return 1; return 1;
} }
else if (scd.cartridge.id) else if (scd.cartridge.id)
{ {
int sz = scd.cartridge.mask + 1; int sz = scd.cartridge.mask + 1;
if (size != sz) if (size != sz)
return 0; return 0;
memcpy(scd.cartridge.area, data, size); memcpy(scd.cartridge.area, data, size);
return 1; return 1;
} }
else else
{ {
if (size != 0) if (size != 0)
return 0; return 0;
return 1; // "successful"? return 1; // "successful"?
} }
} }
@ -510,7 +506,7 @@ GPGX_EX int gpgx_init(
int sixbutton, char system_a, char system_b, int region, int forcesram, int sixbutton, char system_a, char system_b, int region, int forcesram,
struct InitSettings *settings) struct InitSettings *settings)
{ {
_debug_puts("Initializing GPGX native..."); _debug_puts("Initializing GPGX native...");
cinterface_force_sram = forcesram; cinterface_force_sram = forcesram;
@ -530,12 +526,12 @@ GPGX_EX int gpgx_init(
ext.md_cart.rom = alloc_sealed(32 * 1024 * 1024); ext.md_cart.rom = alloc_sealed(32 * 1024 * 1024);
SZHVC_add = alloc_sealed(131072); SZHVC_add = alloc_sealed(131072);
SZHVC_sub = alloc_sealed(131072); SZHVC_sub = alloc_sealed(131072);
ym2612_lfo_pm_table = alloc_sealed(131072); ym2612_lfo_pm_table = alloc_sealed(131072);
vdp_bp_lut = alloc_sealed(262144); vdp_bp_lut = alloc_sealed(262144);
vdp_lut = alloc_sealed(6 * sizeof(*vdp_lut)); vdp_lut = alloc_sealed(6 * sizeof(*vdp_lut));
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
vdp_lut[i] = alloc_sealed(65536); vdp_lut[i] = alloc_sealed(65536);
/* sound options */ /* sound options */
config.psg_preamp = 150; config.psg_preamp = 150;
@ -638,7 +634,7 @@ GPGX_EX void gpgx_set_draw_mask(int mask)
GPGX_EX void gpgx_invalidate_pattern_cache(void) GPGX_EX void gpgx_invalidate_pattern_cache(void)
{ {
vdp_invalidate_full_cache(); vdp_invalidate_full_cache();
} }
typedef struct typedef struct

View File

@ -67,57 +67,6 @@ static const uint16 lut_BCD_16[100] =
0x0900, 0x0901, 0x0902, 0x0903, 0x0904, 0x0905, 0x0906, 0x0907, 0x0908, 0x0909, 0x0900, 0x0901, 0x0902, 0x0903, 0x0904, 0x0905, 0x0906, 0x0907, 0x0908, 0x0909,
}; };
/* pre-build TOC */
static const uint16 toc_snatcher[21] =
{
56014, 495, 10120, 20555, 1580, 5417, 12502, 16090, 6553, 9681,
8148, 20228, 8622, 6142, 5858, 1287, 7424, 3535, 31697, 2485,
31380
};
static const uint16 toc_lunar[52] =
{
5422, 1057, 7932, 5401, 6380, 6592, 5862, 5937, 5478, 5870,
6673, 6613, 6429, 4996, 4977, 5657, 3720, 5892, 3140, 3263,
6351, 5187, 3249, 1464, 1596, 1750, 1751, 6599, 4578, 5205,
1550, 1827, 2328, 1346, 1569, 1613, 7199, 4928, 1656, 2549,
1875, 3901, 1850, 2399, 2028, 1724, 4889, 14551, 1184, 2132,
685, 3167
};
static const uint32 toc_shadow[15] =
{
10226, 70054, 11100, 12532, 12444, 11923, 10059, 10167, 10138, 13792,
11637, 2547, 2521, 3856, 900
};
static const uint32 toc_dungeon[13] =
{
2250, 22950, 16350, 24900, 13875, 19950, 13800, 15375, 17400, 17100,
3325, 6825, 25275
};
static const uint32 toc_ffight[26] =
{
11994, 9742, 10136, 9685, 9553, 14588, 9430, 8721, 9975, 9764,
9704, 12796, 585, 754, 951, 624, 9047, 1068, 817, 9191, 1024,
14562, 10320, 8627, 3795, 3047
};
static const uint32 toc_ffightj[29] =
{
11994, 9752, 10119, 9690, 9567, 14575, 9431, 8731, 9965, 9763,
9716, 12791, 579, 751, 958, 630, 9050, 1052, 825, 9193, 1026,
14553, 9834, 10542, 1699, 1792, 1781, 3783, 3052
};
/* supported WAVE file header (16-bit stereo samples @44.1kHz) */
static const unsigned char waveHeader[32] =
{
0x57,0x41,0x56,0x45,0x66,0x6d,0x74,0x20,0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,
0x44,0xac,0x00,0x00,0x10,0xb1,0x02,0x00,0x04,0x00,0x10,0x00,0x64,0x61,0x74,0x61
};
static blip_t* blip[2]; static blip_t* blip[2];
typedef struct typedef struct

View File

@ -28,6 +28,7 @@ to do:
/** EkeEke (2011): removed multiple chips support, cleaned code & added FM board interface for Genesis Plus GX **/ /** EkeEke (2011): removed multiple chips support, cleaned code & added FM board interface for Genesis Plus GX **/
#include "shared.h" #include "shared.h"
#include <emulibc.h>
#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ #define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
#define EG_SH 16 /* 16.16 fixed point (EG timing) */ #define EG_SH 16 /* 16.16 fixed point (EG timing) */
@ -341,7 +342,7 @@ static const UINT8 mul_tab[16]= {
* TL_RES_LEN - sinus resolution (X axis) * TL_RES_LEN - sinus resolution (X axis)
*/ */
#define TL_TAB_LEN (11*2*TL_RES_LEN) #define TL_TAB_LEN (11*2*TL_RES_LEN)
static signed int tl_tab[TL_TAB_LEN]; ECL_SEALED static signed int tl_tab[TL_TAB_LEN];
#define ENV_QUIET (TL_TAB_LEN>>5) #define ENV_QUIET (TL_TAB_LEN>>5)

View File

@ -129,6 +129,7 @@
/************************************************************************/ /************************************************************************/
#include "shared.h" #include "shared.h"
#include <emulibc.h>
/* envelope generator */ /* envelope generator */
#define ENV_BITS 10 #define ENV_BITS 10
@ -164,7 +165,7 @@
* TL_RES_LEN - sinus resolution (X axis) * TL_RES_LEN - sinus resolution (X axis)
*/ */
#define TL_TAB_LEN (13*2*TL_RES_LEN) #define TL_TAB_LEN (13*2*TL_RES_LEN)
static signed int tl_tab[TL_TAB_LEN]; ECL_SEALED static signed int tl_tab[TL_TAB_LEN];
#define ENV_QUIET (TL_TAB_LEN>>3) #define ENV_QUIET (TL_TAB_LEN>>3)

View File

@ -1,45 +1,16 @@
CC = x86_64-nt64-midipix-gcc NO_WBX_TARGETS := 1
AS = nasm CCFLAGS := -std=c99
SRCS := amd64.c coswap.s
CCFLAGS:= -Wall -O3 -std=c99 AS := nasm
ASFLAGS:= -f elf64 ASFLAGS := -f elf64 -Wall
TARGET = libco.so include ../common.mak
LDFLAGS = -shared $(OBJ_DIR)/%.s.o: %.s
@echo as $<
ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) @mkdir -p $(@D)
SRCS:=$(shell find $(ROOT_DIR) -type f -name '*.c') @$(AS) $(ASFLAGS) -o $@ $<
ASRCS:=$(shell find $(ROOT_DIR) -type f -name '*.s') $(DOBJ_DIR)/%.s.o: %.s
@echo as $<
OBJ_DIR:=$(ROOT_DIR)/obj @mkdir -p $(@D)
@$(AS) $(ASFLAGS) -o $@ $<
_OBJS:=$(SRCS:.c=.c.o)
OBJS:=$(patsubst $(ROOT_DIR)%,$(OBJ_DIR)%,$(_OBJS))
_AOBJS:=$(ASRCS:.s=.s.o)
AOBJS:=$(patsubst $(ROOT_DIR)%,$(OBJ_DIR)%,$(_AOBJS))
$(OBJ_DIR)/%.c.o: %.c
@mkdir -p $(@D)
@$(CC) -c -o $@ $< $(CCFLAGS)
$(OBJ_DIR)/%.s.o: %.s
@mkdir -p $(@D)
@$(AS) $(ASFLAGS) -o $@ $<
all: $(TARGET)
.PHONY: clean all
$(TARGET): $(OBJS) $(AOBJS)
@$(CC) -o $@ $(LDFLAGS) $(CCFLAGS) $(OBJS) $(AOBJS)
@mv $(TARGET) $(TARGET).in
@strip $(TARGET).in -o $(TARGET) -R /4 -R /14 -R /29 -R /41 -R /55 -R /67 -R /78 -R /89 -R /104
clean:
@rm -rf $(OBJ_DIR)
@rm -f $(TARGET).in
@rm -f $(TARGET)
#install:
# $(CP) $(TARGET) $(DEST_$(ARCH))

View File

@ -1,100 +1,101 @@
/* /*
libco.amd64 (2016-09-14) libco.amd64 (2016-09-14)
author: byuu author: byuu
license: public domain license: public domain
*/ */
#define LIBCO_C #define LIBCO_C
#include "libco.h" #include "libco.h"
#include <stdint.h> #include <stdint.h>
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <emulibc.h>
static long long co_active_buffer[64];
static cothread_t co_active_handle = 0; static long long co_active_buffer[64];
static cothread_t co_active_handle = 0;
// allocations are 16k larger than asked for,
// and include guard space between the stack and the storage // allocations are 16k larger than asked for,
// and include guard space between the stack and the storage
static void* alloc_thread(size_t* size)
{ static void* alloc_thread(size_t* size)
// align up to 4k {
*size = (*size + 16384 + 4095) & ~4095; // align up to 4k
*size = (*size + 16384 + 4095) & ~4095;
uint64_t* ptr = mmap(NULL, *size,
PROT_READ | PROT_WRITE, MAP_ANONYMOUS, -1, 0); uint64_t* ptr = mmap(NULL, *size,
if (ptr == (uint64_t*)(-1)) PROT_READ | PROT_WRITE, MAP_ANONYMOUS, -1, 0);
return NULL; if (ptr == (uint64_t*)(-1))
return NULL;
ptr[512] = *size;
for (int i = 513; i < 2048; i++) ptr[512] = *size;
ptr[i] = 0xdeadbeefdeadbeef; for (int i = 513; i < 2048; i++)
ptr[i] = 0xdeadbeefdeadbeef;
if (mprotect(ptr + 512, 512 * 3 * sizeof(uint64_t), PROT_NONE) != 0)
abort(); if (mprotect(ptr + 512, 512 * 3 * sizeof(uint64_t), PROT_NONE) != 0)
abort();
return ptr;
} return ptr;
}
static void free_thread(void* p)
{ static void free_thread(void* p)
uint64_t* ptr = (uint64_t*)p; {
if (mprotect(ptr + 512, 512 * 3 * sizeof(uint64_t), PROT_READ | PROT_WRITE) != 0) uint64_t* ptr = (uint64_t*)p;
abort(); if (mprotect(ptr + 512, 512 * 3 * sizeof(uint64_t), PROT_READ | PROT_WRITE) != 0)
uint64_t size = ptr[512]; abort();
memset(p, 0, size); uint64_t size = ptr[512];
if (munmap(ptr, size) != 0) memset(p, 0, size);
abort(); if (munmap(ptr, size) != 0)
} abort();
}
extern void co_swap(cothread_t, cothread_t);
extern void co_swap(cothread_t, cothread_t);
static void crash()
{ static void crash()
assert(0); /* called only if cothread_t entrypoint returns */ {
} assert(0); /* called only if cothread_t entrypoint returns */
}
void co_clean()
{ ECL_EXPORT void co_clean()
memset(co_active_buffer, 0, sizeof(co_active_buffer)); {
} memset(co_active_buffer, 0, sizeof(co_active_buffer));
}
cothread_t co_active()
{ cothread_t co_active()
if (!co_active_handle) {
co_active_handle = &co_active_buffer; if (!co_active_handle)
return co_active_handle; co_active_handle = &co_active_buffer;
} return co_active_handle;
}
cothread_t co_create(unsigned int sz, void (*entrypoint)(void))
{ cothread_t co_create(unsigned int sz, void (*entrypoint)(void))
cothread_t handle; {
if (!co_active_handle) cothread_t handle;
co_active_handle = &co_active_buffer; if (!co_active_handle)
co_active_handle = &co_active_buffer;
uint64_t size = sz;
uint64_t size = sz;
if (handle = (cothread_t)alloc_thread(&size))
{ if (handle = (cothread_t)alloc_thread(&size))
uint64_t* p = (uint64_t*)((char*)handle + size); // seek to top of stack {
*--p = (uint64_t)crash; /* crash if entrypoint returns */ uint64_t* p = (uint64_t*)((char*)handle + size); // seek to top of stack
*--p = (uint64_t)entrypoint; /* start of function */ *--p = (uint64_t)crash; /* crash if entrypoint returns */
*(uint64_t*)handle = (uint64_t)p; /* stack pointer */ *--p = (uint64_t)entrypoint; /* start of function */
} *(uint64_t*)handle = (uint64_t)p; /* stack pointer */
}
return handle;
} return handle;
}
void co_delete(cothread_t handle)
{ void co_delete(cothread_t handle)
free_thread(handle); {
} free_thread(handle);
}
void co_switch(cothread_t handle)
{ void co_switch(cothread_t handle)
register cothread_t co_previous_handle = co_active_handle; {
co_swap(co_active_handle = handle, co_previous_handle); register cothread_t co_previous_handle = co_active_handle;
} co_swap(co_active_handle = handle, co_previous_handle);
}

Binary file not shown.

4
waterbox/libcxx/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/build-
/build0
/build1
/build2

View File

@ -0,0 +1,28 @@
#!/bin/sh
MYPATH="`dirname \"$0\"`"
SYSROOT="`realpath \"$MYPATH/../sysroot\"`"
LLVMDIR="`realpath \"$MYPATH/../../../llvm-project\"`"
#To uselibclang-rt (and libunwind), we need to evict the gcc libs, but musl automatically puts that in the specs file
#and has no setting to remove it. Fix that here.
sed -i -e '13c\' -e '' "$SYSROOT/lib/musl-gcc.specs"
rm -rf build-
mkdir build-
cd build-
export CFLAGS="-mabi=ms -mcmodel=large -mstack-protector-guard=global"
export CXXFLAGS="-mabi=ms -mcmodel=large -mstack-protector-guard=global"
cmake \
-DCMAKE_C_COMPILER="$SYSROOT/bin/musl-gcc" \
-DCMAKE_CXX_COMPILER="$SYSROOT/bin/musl-gcc" \
-DCOMPILER_RT_BUILD_CRT=OFF \
-DCOMPILER_RT_BUILD_SANITIZERS=OFF \
-DCOMPILER_RT_BUILD_XRAY=OFF \
-DCOMPILER_RT_BUILD_LIBFUZZER=OFF \
-DCOMPILER_RT_BUILD_PROFILE=OFF \
-DCOMPILER_RT_CAN_EXECUTE_TESTS=OFF \
-DCOMPILER_RT_USE_BUILTINS_LIBRARY=ON \
-DCMAKE_INSTALL_PREFIX="$SYSROOT" \
-DCMAKE_AR="/usr/bin/gcc-ar" \
-DCMAKE_RANLIB="/usr/bin/gcc-ranlib" \
../../../../llvm-project/compiler-rt

View File

@ -0,0 +1,19 @@
#!/bin/sh
MYPATH="`dirname \"$0\"`"
SYSROOT="`realpath \"$MYPATH/../sysroot\"`"
LLVMDIR="`realpath \"$MYPATH/../../../llvm-project\"`"
rm -rf build0
mkdir build0
cd build0
export CFLAGS="-mabi=ms -mcmodel=large -mstack-protector-guard=global -fno-use-cxa-atexit"
export CXXFLAGS="-mabi=ms -mcmodel=large -mstack-protector-guard=global -fno-use-cxa-atexit"
cmake \
-DCMAKE_C_COMPILER="$SYSROOT/bin/musl-gcc" \
-DCMAKE_CXX_COMPILER="$SYSROOT/bin/musl-gcc" \
-DLIBUNWIND_ENABLE_SHARED=OFF \
-DLIBUNWIND_ENABLE_THREADS=OFF \
-DLIBUNWIND_USE_COMPILER_RT=ON \
-DCMAKE_INSTALL_PREFIX="$SYSROOT" \
-DCMAKE_AR="/usr/bin/gcc-ar" \
-DCMAKE_RANLIB="/usr/bin/gcc-ranlib" \
../../../../llvm-project/libunwind

View File

@ -0,0 +1,27 @@
#!/bin/sh
MYPATH="`dirname \"$0\"`"
SYSROOT="`realpath \"$MYPATH/../sysroot\"`"
LLVMDIR="`realpath \"$MYPATH/../../../llvm-project\"`"
rm -rf build1
mkdir build1
cd build1
export CFLAGS="-mabi=ms -mcmodel=large -mstack-protector-guard=global -fno-use-cxa-atexit"
export CXXFLAGS="-mabi=ms -mcmodel=large -mstack-protector-guard=global -fno-use-cxa-atexit"
cmake \
-DCMAKE_C_COMPILER="$SYSROOT/bin/musl-gcc" \
-DCMAKE_CXX_COMPILER="$SYSROOT/bin/musl-gcc" \
-DLIBCXXABI_ENABLE_EXCEPTIONS=ON \
-DLIBCXXABI_ENABLE_PIC=OFF \
-DLIBCXXABI_ENABLE_THREADS=OFF \
-DLIBCXXABI_ENABLE_SHARED=OFF \
-DLIBCXXABI_BAREMETAL=ON \
-DLIBCXXABI_SILENT_TERMINATE=ON \
-DLIBCXXABI_USE_LLVM_UNWINDER=ON \
-DLIBCXXABI_USE_COMPILER_RT=ON \
-DLIBCXXABI_INCLUDE_TESTS=OFF \
-DLIBCXXABI_LINK_TESTS_WITH_SHARED_LIBCXXABI=OFF \
-DLIBCXXABI_LIBCXX_INCLUDES="$LLVMDIR/libcxx/include" \
-DCMAKE_INSTALL_PREFIX="$SYSROOT" \
-DCMAKE_AR="/usr/bin/gcc-ar" \
-DCMAKE_RANLIB="/usr/bin/gcc-ranlib" \
../../../../llvm-project/libcxxabi

View File

@ -0,0 +1,34 @@
#!/bin/sh
MYPATH="`dirname \"$0\"`"
SYSROOT="`realpath \"$MYPATH/../sysroot\"`"
LLVMDIR="`realpath \"$MYPATH/../../../llvm-project\"`"
#libcxx needs this one trivial file to autodetect sendfile(2), which musl does support
mkdir -p "$SYSROOT/include/linux"
cp -n "/usr/include/linux/version.h" "$SYSROOT/include/linux"
rm -rf build2
mkdir build2
cd build2
export CFLAGS="-mabi=ms -mcmodel=large -mstack-protector-guard=global -fno-use-cxa-atexit"
export CXXFLAGS="-mabi=ms -mcmodel=large -mstack-protector-guard=global -fno-use-cxa-atexit"
cmake \
-DCMAKE_C_COMPILER="$SYSROOT/bin/musl-gcc" \
-DCMAKE_CXX_COMPILER="$SYSROOT/bin/musl-gcc" \
-DLIBCXX_ENABLE_SHARED=OFF \
-DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=OFF \
-DLIBCXX_CXX_ABI="libcxxabi" \
-DLIBCXX_CXX_ABI_INCLUDE_PATHS="$LLVMDIR/libcxxabi/include" \
-DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON \
-DLIBCXX_ENABLE_EXCEPTIONS=ON \
-DLIBCXX_ENABLE_RTTI=ON \
-DLIBCXX_ENABLE_THREADS=OFF \
-DLIBCXX_HAS_MUSL_LIBC=ON \
-DLIBCXX_USE_COMPILER_RT=ON \
-DLIBCXX_INCLUDE_TESTS=OFF \
-DLIBCXX_INCLUDE_BENCHMARKS=OFF \
-DLIBCXX_STATICALLY_LINK_ABI_IN_STATIC_LIBRARY=OFF \
-DCMAKE_INSTALL_PREFIX="$SYSROOT" \
-DCMAKE_AR="/usr/bin/gcc-ar" \
-DCMAKE_RANLIB="/usr/bin/gcc-ranlib" \
../../../../llvm-project/libcxx

View File

@ -0,0 +1,25 @@
#!/bin/sh
./configure-for-waterbox-phase--
cd build-
make
make install
cd ..
./configure-for-waterbox-phase-0
cd build0
make
make install
cd ..
./configure-for-waterbox-phase-1
cd build1
make
make install
cd ..
./configure-for-waterbox-phase-2
cd build2
make
make install
cd ..

View File

@ -0,0 +1,8 @@
Building and installing libcxx:
1. Clone llvm-project into $BIZHAWKGITROOT/../llvm-project
* I used eaae6dfc545000e335e6f89abb9c78818383d7ad, which was the tip of origin/release/10.x at the time
2. Come to this folder
3. Run ./do-everything.sh
* This isn't resumable at all, so if it crashes or you're curious about the process,
read its source and execute the commands individually.

View File

@ -1,100 +1,62 @@
CC = x86_64-nt64-midipix-g++ NEED_LIBCO := 1
# -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast #-DPROFILE_PERFORMANCE
#-std=c99 -fomit-frame-pointer -fvisibility=hidden CCFLAGS := -DHOOKS -DBIZHAWK -DPROFILE_COMPATIBILITY -DGAMEBOY \
#-DPROFILE_PERFORMANCE -D_GNU_SOURCE \
#-fno-exceptions -fno-rtti -Werror=int-to-pointer-cast \
CCFLAGS:= -DHOOKS -DBIZHAWK -DPROFILE_COMPATIBILITY -DGAMEBOY \ -I../libco -I./bsnes \
-D_GNU_SOURCE \ -Wno-parentheses -Wno-sign-compare \
-Werror=pointer-to-int-cast -Werror=int-to-pointer-cast \ -Wno-unused-variable -Wno-unused-function \
-I../emulibc -I../libco -I./bsnes \ -fno-threadsafe-statics \
-Wall -Werror=implicit-function-declaration \ -std=c++0x
-Wno-parentheses -Wno-sign-compare \
-Wno-unused-variable -Wno-unused-function \ TARGET = libsnes.wbx
-fvisibility=hidden \
-fno-threadsafe-statics \ SRCS_PERF = \
-std=c++0x \ $(ROOT_DIR)/bsnes/snes/alt/cpu/cpu.cpp \
-O3 -flto $(ROOT_DIR)/bsnes/snes/alt/ppu-performance/ppu.cpp \
$(ROOT_DIR)/bsnes/snes/alt/smp/smp.cpp
TARGET = libsnes.wbx SRCS_COMPAT = \
$(ROOT_DIR)/bsnes/snes/alt/ppu-compatibility/ppu.cpp \
LDFLAGS = -Wl,--dynamicbase,--export-all-symbols $(ROOT_DIR)/bsnes/snes/cpu/cpu.cpp \
$(ROOT_DIR)/bsnes/snes/smp/smp.cpp
ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) SRCS_ALL = \
$(ROOT_DIR)/bsnes/base/base.cpp \
SRCS_PERF:= \ $(ROOT_DIR)/bsnes/gameboy/apu/apu.cpp \
$(ROOT_DIR)/bsnes/snes/alt/cpu/cpu.cpp \ $(ROOT_DIR)/bsnes/gameboy/cartridge/cartridge.cpp \
$(ROOT_DIR)/bsnes/snes/alt/ppu-performance/ppu.cpp \ $(ROOT_DIR)/bsnes/gameboy/cpu/cpu.cpp \
$(ROOT_DIR)/bsnes/snes/alt/smp/smp.cpp $(ROOT_DIR)/bsnes/snes/alt/dsp/dsp.cpp \
SRCS_COMPAT:= \ $(ROOT_DIR)/bsnes/gameboy/interface/interface.cpp \
$(ROOT_DIR)/bsnes/snes/alt/ppu-compatibility/ppu.cpp \ $(ROOT_DIR)/bsnes/gameboy/lcd/lcd.cpp \
$(ROOT_DIR)/bsnes/snes/cpu/cpu.cpp \ $(ROOT_DIR)/bsnes/gameboy/memory/memory.cpp \
$(ROOT_DIR)/bsnes/snes/smp/smp.cpp $(ROOT_DIR)/bsnes/gameboy/scheduler/scheduler.cpp \
SRCS_ALL:= \ $(ROOT_DIR)/bsnes/gameboy/system/system.cpp \
$(ROOT_DIR)/bsnes/base/base.cpp \ $(ROOT_DIR)/bsnes/gameboy/video/video.cpp \
$(ROOT_DIR)/bsnes/gameboy/apu/apu.cpp \ $(ROOT_DIR)/bsnes/snes/cartridge/cartridge.cpp \
$(ROOT_DIR)/bsnes/gameboy/cartridge/cartridge.cpp \ $(ROOT_DIR)/bsnes/snes/chip/armdsp/armdsp.cpp \
$(ROOT_DIR)/bsnes/gameboy/cpu/cpu.cpp \ $(ROOT_DIR)/bsnes/snes/chip/bsx/bsx.cpp \
$(ROOT_DIR)/bsnes/snes/alt/dsp/dsp.cpp \ $(ROOT_DIR)/bsnes/snes/chip/hitachidsp/hitachidsp.cpp \
$(ROOT_DIR)/bsnes/gameboy/interface/interface.cpp \ $(ROOT_DIR)/bsnes/snes/chip/icd2/icd2.cpp \
$(ROOT_DIR)/bsnes/gameboy/lcd/lcd.cpp \ $(ROOT_DIR)/bsnes/snes/chip/link/link.cpp \
$(ROOT_DIR)/bsnes/gameboy/memory/memory.cpp \ $(ROOT_DIR)/bsnes/snes/chip/msu1/msu1.cpp \
$(ROOT_DIR)/bsnes/gameboy/scheduler/scheduler.cpp \ $(ROOT_DIR)/bsnes/snes/chip/necdsp/necdsp.cpp \
$(ROOT_DIR)/bsnes/gameboy/system/system.cpp \ $(ROOT_DIR)/bsnes/snes/chip/nss/nss.cpp \
$(ROOT_DIR)/bsnes/gameboy/video/video.cpp \ $(ROOT_DIR)/bsnes/snes/chip/obc1/obc1.cpp \
$(ROOT_DIR)/bsnes/snes/cartridge/cartridge.cpp \ $(ROOT_DIR)/bsnes/snes/chip/sa1/sa1.cpp \
$(ROOT_DIR)/bsnes/snes/chip/armdsp/armdsp.cpp \ $(ROOT_DIR)/bsnes/snes/chip/sdd1/sdd1.cpp \
$(ROOT_DIR)/bsnes/snes/chip/bsx/bsx.cpp \ $(ROOT_DIR)/bsnes/snes/chip/spc7110/spc7110.cpp \
$(ROOT_DIR)/bsnes/snes/chip/hitachidsp/hitachidsp.cpp \ $(ROOT_DIR)/bsnes/snes/chip/srtc/srtc.cpp \
$(ROOT_DIR)/bsnes/snes/chip/icd2/icd2.cpp \ $(ROOT_DIR)/bsnes/snes/chip/sufamiturbo/sufamiturbo.cpp \
$(ROOT_DIR)/bsnes/snes/chip/link/link.cpp \ $(ROOT_DIR)/bsnes/snes/chip/superfx/superfx.cpp \
$(ROOT_DIR)/bsnes/snes/chip/msu1/msu1.cpp \ $(ROOT_DIR)/bsnes/snes/config/config.cpp \
$(ROOT_DIR)/bsnes/snes/chip/necdsp/necdsp.cpp \ $(ROOT_DIR)/bsnes/snes/controller/controller.cpp \
$(ROOT_DIR)/bsnes/snes/chip/nss/nss.cpp \ $(ROOT_DIR)/bsnes/snes/cpu/core/core.cpp \
$(ROOT_DIR)/bsnes/snes/chip/obc1/obc1.cpp \ $(ROOT_DIR)/bsnes/snes/interface/interface.cpp \
$(ROOT_DIR)/bsnes/snes/chip/sa1/sa1.cpp \ $(ROOT_DIR)/bsnes/snes/memory/memory.cpp \
$(ROOT_DIR)/bsnes/snes/chip/sdd1/sdd1.cpp \ $(ROOT_DIR)/bsnes/snes/smp/core/core.cpp \
$(ROOT_DIR)/bsnes/snes/chip/spc7110/spc7110.cpp \ $(ROOT_DIR)/bsnes/snes/system/system.cpp \
$(ROOT_DIR)/bsnes/snes/chip/srtc/srtc.cpp \ $(ROOT_DIR)/bsnes/target-libsnes/libsnes.cpp \
$(ROOT_DIR)/bsnes/snes/chip/sufamiturbo/sufamiturbo.cpp \ $(ROOT_DIR)/bsnes/target-libsnes/libsnes_pwrap.cpp
$(ROOT_DIR)/bsnes/snes/chip/superfx/superfx.cpp \ SRCS = $(SRCS_ALL) $(SRCS_COMPAT)
$(ROOT_DIR)/bsnes/snes/config/config.cpp \
$(ROOT_DIR)/bsnes/snes/controller/controller.cpp \ include ../common.mak
$(ROOT_DIR)/bsnes/snes/cpu/core/core.cpp \
$(ROOT_DIR)/bsnes/snes/interface/interface.cpp \
$(ROOT_DIR)/bsnes/snes/memory/memory.cpp \
$(ROOT_DIR)/bsnes/snes/smp/core/core.cpp \
$(ROOT_DIR)/bsnes/snes/system/system.cpp \
$(ROOT_DIR)/bsnes/target-libsnes/libsnes.cpp \
$(ROOT_DIR)/bsnes/target-libsnes/libsnes_pwrap.cpp
SRCS:=$(SRCS_ALL) $(SRCS_COMPAT)
OBJ_DIR:=$(ROOT_DIR)/obj
_OBJS:=$(SRCS:.cpp=.o)
OBJS:=$(patsubst $(ROOT_DIR)%,$(OBJ_DIR)%,$(_OBJS))
$(OBJ_DIR)/%.o: $(ROOT_DIR)/%.cpp
@mkdir -p $(@D)
@$(CC) -c -o $@ $< $(CCFLAGS)
all: $(TARGET)
.PHONY: clean all
$(TARGET).in: $(OBJS)
@$(CC) -o $@ $(LDFLAGS) $(CCFLAGS) $(OBJS) ../emulibc/libemuhost.so ../libco/libco.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))

View File

@ -1,154 +1,155 @@
#ifndef NALL_PLATFORM_HPP #ifndef NALL_PLATFORM_HPP
#define NALL_PLATFORM_HPP #define NALL_PLATFORM_HPP
#if defined(_WIN32) #if defined(_WIN32)
//minimum version needed for _wstat64, etc //minimum version needed for _wstat64, etc
#undef __MSVCRT_VERSION__ #undef __MSVCRT_VERSION__
#define __MSVCRT_VERSION__ 0x0601 #define __MSVCRT_VERSION__ 0x0601
#include <nall/windows/utf8.hpp> #include <nall/windows/utf8.hpp>
#endif #endif
#ifdef _MSC_VER #ifdef _MSC_VER
#define _USE_MATH_DEFINES 1 #define _USE_MATH_DEFINES 1
#endif #endif
//========================= //=========================
//standard platform headers //standard platform headers
//========================= //=========================
#include <limits> #include <limits>
#include <assert.h> #include <assert.h>
#include <limits.h> #include <limits.h>
#include <math.h> #include <math.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <limits.h> #include <limits.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#if defined(_WIN32) #include <string>
#include <io.h> #include <vector>
#include <direct.h>
//#include <shlobj.h> //bizhawk chokes? #if defined(_WIN32)
#include <wchar.h> #include <io.h>
#undef interface #include <direct.h>
#define dllexport __declspec(dllexport) //#include <shlobj.h> //bizhawk chokes?
//bad things happen without these here #include <wchar.h>
#include <string> #undef interface
#include <vector> #define dllexport __declspec(dllexport)
#else //bad things happen without these here
#include <unistd.h> #else
#include <pwd.h> #include <unistd.h>
#define dllexport #include <pwd.h>
#endif #define dllexport
#endif
//==================
//warning supression //==================
//================== //warning supression
//==================
//Visual C++
#if defined(_MSC_VER) //Visual C++
//disable libc "deprecation" warnings #if defined(_MSC_VER)
#pragma warning(disable:4996) //disable libc "deprecation" warnings
#endif #pragma warning(disable:4996)
#endif
//================
//POSIX compliance //================
//================ //POSIX compliance
//================
#if defined(_MSC_VER)
#define PATH_MAX _MAX_PATH #if defined(_MSC_VER)
#define va_copy(dest, src) ((dest) = (src)) #define PATH_MAX _MAX_PATH
#endif #define va_copy(dest, src) ((dest) = (src))
#endif
#if defined(_WIN32)
#define getcwd _getcwd #if defined(_WIN32)
#define ftruncate _chsize #define getcwd _getcwd
#define mkdir(n, m) _wmkdir(nall::utf16_t(n)) #define ftruncate _chsize
#define putenv _putenv #define mkdir(n, m) _wmkdir(nall::utf16_t(n))
#define rmdir _rmdir #define putenv _putenv
#define vsnprintf _vsnprintf #define rmdir _rmdir
inline void usleep(unsigned milliseconds) { Sleep(milliseconds / 1000); } #define vsnprintf _vsnprintf
#endif inline void usleep(unsigned milliseconds) { Sleep(milliseconds / 1000); }
#endif
//================
//inline expansion //================
//================ //inline expansion
//================
#if defined(__GNUC__)
#define noinline __attribute__((noinline)) #if defined(__GNUC__)
#define inline inline #define noinline __attribute__((noinline))
#define alwaysinline inline __attribute__((always_inline)) #define inline inline
#elif defined(_MSC_VER) #define alwaysinline inline __attribute__((always_inline))
#define noinline __declspec(noinline) #elif defined(_MSC_VER)
#define inline inline #define noinline __declspec(noinline)
#define alwaysinline inline __forceinline #define inline inline
#else #define alwaysinline inline __forceinline
#define noinline #else
#define inline inline #define noinline
#define alwaysinline inline #define inline inline
#endif #define alwaysinline inline
#endif
//=========================
//file system functionality //=========================
//========================= //file system functionality
//=========================
#if defined(_WIN32)
inline char* realpath(const char *filename, char *resolvedname) { #if defined(_WIN32)
wchar_t fn[_MAX_PATH] = L""; inline char* realpath(const char *filename, char *resolvedname) {
_wfullpath(fn, nall::utf16_t(filename), _MAX_PATH); wchar_t fn[_MAX_PATH] = L"";
strcpy(resolvedname, nall::utf8_t(fn)); _wfullpath(fn, nall::utf16_t(filename), _MAX_PATH);
for(unsigned n = 0; resolvedname[n]; n++) if(resolvedname[n] == '\\') resolvedname[n] = '/'; strcpy(resolvedname, nall::utf8_t(fn));
return resolvedname; for(unsigned n = 0; resolvedname[n]; n++) if(resolvedname[n] == '\\') resolvedname[n] = '/';
} return resolvedname;
}
inline char* userpath(char *path) {
//TODO BIZHAWK inline char* userpath(char *path) {
return nullptr; //TODO BIZHAWK
//wchar_t fp[_MAX_PATH] = L""; return nullptr;
//SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, fp); //wchar_t fp[_MAX_PATH] = L"";
//strcpy(path, nall::utf8_t(fp)); //SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, fp);
//for(unsigned n = 0; path[n]; n++) if(path[n] == '\\') path[n] = '/'; //strcpy(path, nall::utf8_t(fp));
//unsigned length = strlen(path); //for(unsigned n = 0; path[n]; n++) if(path[n] == '\\') path[n] = '/';
//if(path[length] != '/') strcpy(path + length, "/"); //unsigned length = strlen(path);
//return path; //if(path[length] != '/') strcpy(path + length, "/");
} //return path;
}
inline char* getcwd(char *path) {
//TODO BIZHAWK inline char* getcwd(char *path) {
return nullptr; //TODO BIZHAWK
//wchar_t fp[_MAX_PATH] = L""; return nullptr;
//_wgetcwd(fp, _MAX_PATH); //wchar_t fp[_MAX_PATH] = L"";
//strcpy(path, nall::utf8_t(fp)); //_wgetcwd(fp, _MAX_PATH);
//for(unsigned n = 0; path[n]; n++) if(path[n] == '\\') path[n] = '/'; //strcpy(path, nall::utf8_t(fp));
//unsigned length = strlen(path); //for(unsigned n = 0; path[n]; n++) if(path[n] == '\\') path[n] = '/';
//if(path[length] != '/') strcpy(path + length, "/"); //unsigned length = strlen(path);
//return path; //if(path[length] != '/') strcpy(path + length, "/");
} //return path;
#else }
//realpath() already exists #else
//realpath() already exists
inline char* userpath(char *path) {
*path = 0; inline char* userpath(char *path) {
struct passwd *userinfo = getpwuid(getuid()); *path = 0;
if(userinfo) strcpy(path, userinfo->pw_dir); struct passwd *userinfo = getpwuid(getuid());
unsigned length = strlen(path); if(userinfo) strcpy(path, userinfo->pw_dir);
if(path[length] != '/') strcpy(path + length, "/"); unsigned length = strlen(path);
return path; if(path[length] != '/') strcpy(path + length, "/");
} return path;
}
inline char *getcwd(char *path) {
auto unused = getcwd(path, PATH_MAX); inline char *getcwd(char *path) {
unsigned length = strlen(path); auto unused = getcwd(path, PATH_MAX);
if(path[length] != '/') strcpy(path + length, "/"); unsigned length = strlen(path);
return path; if(path[length] != '/') strcpy(path + length, "/");
} return path;
#endif }
#endif
#endif
#endif

View File

@ -1 +0,0 @@
make -j && gzip -c libsnes.wbx > ../../output/dll/libsnes.wbx.gz

1
waterbox/musl Submodule

@ -0,0 +1 @@
Subproject commit 8e064437203731ae3d9f17b953a31e885a71f879

View File

@ -1,44 +1,10 @@
CC = x86_64-nt64-midipix-g++ CCFLAGS:= -I. \
-Wall -Werror=int-to-pointer-cast \
CCFLAGS:= -I. -I../emulibc \ -std=c++0x -fomit-frame-pointer -fno-exceptions -fno-rtti \
-Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=implicit-function-declaration \ -DLSB_FIRST
-std=c++0x -fomit-frame-pointer -fvisibility=hidden -fno-exceptions -fno-rtti \
-DLSB_FIRST \ TARGET = ngp.wbx
-O3 -flto
SRCS = $(shell find $(ROOT_DIR) -type f -name '*.cpp')
TARGET = ngp.wbx
include ../common.mak
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))

View File

@ -24,6 +24,7 @@
#include "flash.h" #include "flash.h"
#include <algorithm> #include <algorithm>
#include <time.h>
namespace MDFN_IEN_NGP namespace MDFN_IEN_NGP
{ {

View File

@ -1,44 +1,10 @@
CC = x86_64-nt64-midipix-g++ CCFLAGS:= \
-Wall -Werror=int-to-pointer-cast \
CCFLAGS:= -I. -I../emulibc \ -std=c++0x -fomit-frame-pointer -fno-exceptions -fno-rtti \
-Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=implicit-function-declaration \ -DLSB_FIRST
-std=c++0x -fomit-frame-pointer -fvisibility=hidden -fno-exceptions -fno-rtti \
-DLSB_FIRST \ TARGET = pcfx.wbx
-O3 -flto
SRCS = $(shell find $(ROOT_DIR) -type f -name '*.cpp')
TARGET = pcfx.wbx
include ../common.mak
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))

View File

@ -1,430 +1,430 @@
/* Mednafen - Multi-system Emulator /* Mednafen - Multi-system Emulator
* *
* Subchannel Q CRC Code: Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.de> * Subchannel Q CRC Code: Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.de>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include "defs.h" #include "../defs.h"
#include "CDUtility.h" #include "CDUtility.h"
#include "dvdisaster.h" #include "dvdisaster.h"
#include "lec.h" #include "lec.h"
#include <assert.h> #include <assert.h>
namespace CDUtility namespace CDUtility
{ {
// lookup table for crc calculation // lookup table for crc calculation
static uint16 subq_crctab[256] = static uint16 subq_crctab[256] =
{ {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
}; };
static uint8 scramble_table[2352 - 12]; static uint8 scramble_table[2352 - 12];
static bool CDUtility_Inited = false; static bool CDUtility_Inited = false;
static void InitScrambleTable(void) static void InitScrambleTable(void)
{ {
unsigned cv = 1; unsigned cv = 1;
for(unsigned i = 12; i < 2352; i++) for(unsigned i = 12; i < 2352; i++)
{ {
unsigned char z = 0; unsigned char z = 0;
for(int b = 0; b < 8; b++) for(int b = 0; b < 8; b++)
{ {
z |= (cv & 1) << b; z |= (cv & 1) << b;
int feedback = ((cv >> 1) & 1) ^ (cv & 1); int feedback = ((cv >> 1) & 1) ^ (cv & 1);
cv = (cv >> 1) | (feedback << 14); cv = (cv >> 1) | (feedback << 14);
} }
scramble_table[i - 12] = z; scramble_table[i - 12] = z;
} }
//for(int i = 0; i < 2352 - 12; i++) //for(int i = 0; i < 2352 - 12; i++)
// printf("0x%02x, ", scramble_table[i]); // printf("0x%02x, ", scramble_table[i]);
} }
void CDUtility_Init(void) void CDUtility_Init(void)
{ {
if(!CDUtility_Inited) if(!CDUtility_Inited)
{ {
//Init_LEC_Correct(); //Init_LEC_Correct();
InitScrambleTable(); InitScrambleTable();
CDUtility_Inited = true; CDUtility_Inited = true;
} }
} }
void encode_mode0_sector(uint32 aba, uint8 *sector_data) void encode_mode0_sector(uint32 aba, uint8 *sector_data)
{ {
CDUtility_Init(); CDUtility_Init();
lec_encode_mode0_sector(aba, sector_data); lec_encode_mode0_sector(aba, sector_data);
} }
void encode_mode1_sector(uint32 aba, uint8 *sector_data) void encode_mode1_sector(uint32 aba, uint8 *sector_data)
{ {
CDUtility_Init(); CDUtility_Init();
lec_encode_mode1_sector(aba, sector_data); lec_encode_mode1_sector(aba, sector_data);
} }
void encode_mode2_sector(uint32 aba, uint8 *sector_data) void encode_mode2_sector(uint32 aba, uint8 *sector_data)
{ {
CDUtility_Init(); CDUtility_Init();
lec_encode_mode2_sector(aba, sector_data); lec_encode_mode2_sector(aba, sector_data);
} }
void encode_mode2_form1_sector(uint32 aba, uint8 *sector_data) void encode_mode2_form1_sector(uint32 aba, uint8 *sector_data)
{ {
CDUtility_Init(); CDUtility_Init();
lec_encode_mode2_form1_sector(aba, sector_data); lec_encode_mode2_form1_sector(aba, sector_data);
} }
void encode_mode2_form2_sector(uint32 aba, uint8 *sector_data) void encode_mode2_form2_sector(uint32 aba, uint8 *sector_data)
{ {
CDUtility_Init(); CDUtility_Init();
lec_encode_mode2_form2_sector(aba, sector_data); lec_encode_mode2_form2_sector(aba, sector_data);
} }
bool edc_check(const uint8 *sector_data, bool xa) bool edc_check(const uint8 *sector_data, bool xa)
{ {
CDUtility_Init(); CDUtility_Init();
return(CheckEDC(sector_data, xa)); return(CheckEDC(sector_data, xa));
} }
bool edc_lec_check_and_correct(uint8 *sector_data, bool xa) bool edc_lec_check_and_correct(uint8 *sector_data, bool xa)
{ {
CDUtility_Init(); CDUtility_Init();
return(ValidateRawSector(sector_data, xa)); return(ValidateRawSector(sector_data, xa));
} }
bool subq_check_checksum(const uint8 *SubQBuf) bool subq_check_checksum(const uint8 *SubQBuf)
{ {
uint16 crc = 0; uint16 crc = 0;
uint16 stored_crc = 0; uint16 stored_crc = 0;
stored_crc = SubQBuf[0xA] << 8; stored_crc = SubQBuf[0xA] << 8;
stored_crc |= SubQBuf[0xB]; stored_crc |= SubQBuf[0xB];
for(int i = 0; i < 0xA; i++) for(int i = 0; i < 0xA; i++)
crc = subq_crctab[(crc >> 8) ^ SubQBuf[i]] ^ (crc << 8); crc = subq_crctab[(crc >> 8) ^ SubQBuf[i]] ^ (crc << 8);
crc = ~crc; crc = ~crc;
return(crc == stored_crc); return(crc == stored_crc);
} }
void subq_generate_checksum(uint8 *buf) void subq_generate_checksum(uint8 *buf)
{ {
uint16 crc = 0; uint16 crc = 0;
for(int i = 0; i < 0xA; i++) for(int i = 0; i < 0xA; i++)
crc = subq_crctab[(crc >> 8) ^ buf[i]] ^ (crc << 8); crc = subq_crctab[(crc >> 8) ^ buf[i]] ^ (crc << 8);
// Checksum // Checksum
buf[0xa] = ~(crc >> 8); buf[0xa] = ~(crc >> 8);
buf[0xb] = ~(crc); buf[0xb] = ~(crc);
} }
void subq_deinterleave(const uint8 *SubPWBuf, uint8 *qbuf) void subq_deinterleave(const uint8 *SubPWBuf, uint8 *qbuf)
{ {
memset(qbuf, 0, 0xC); memset(qbuf, 0, 0xC);
for(int i = 0; i < 96; i++) for(int i = 0; i < 96; i++)
{ {
qbuf[i >> 3] |= ((SubPWBuf[i] >> 6) & 0x1) << (7 - (i & 0x7)); qbuf[i >> 3] |= ((SubPWBuf[i] >> 6) & 0x1) << (7 - (i & 0x7));
} }
} }
// Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data. // Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.
void subpw_deinterleave(const uint8 *in_buf, uint8 *out_buf) void subpw_deinterleave(const uint8 *in_buf, uint8 *out_buf)
{ {
assert(in_buf != out_buf); assert(in_buf != out_buf);
memset(out_buf, 0, 96); memset(out_buf, 0, 96);
for(unsigned ch = 0; ch < 8; ch++) for(unsigned ch = 0; ch < 8; ch++)
{ {
for(unsigned i = 0; i < 96; i++) for(unsigned i = 0; i < 96; i++)
{ {
out_buf[(ch * 12) + (i >> 3)] |= ((in_buf[i] >> (7 - ch)) & 0x1) << (7 - (i & 0x7)); out_buf[(ch * 12) + (i >> 3)] |= ((in_buf[i] >> (7 - ch)) & 0x1) << (7 - (i & 0x7));
} }
} }
} }
// Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data. // Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.
void subpw_interleave(const uint8 *in_buf, uint8 *out_buf) void subpw_interleave(const uint8 *in_buf, uint8 *out_buf)
{ {
assert(in_buf != out_buf); assert(in_buf != out_buf);
for(unsigned d = 0; d < 12; d++) for(unsigned d = 0; d < 12; d++)
{ {
for(unsigned bitpoodle = 0; bitpoodle < 8; bitpoodle++) for(unsigned bitpoodle = 0; bitpoodle < 8; bitpoodle++)
{ {
uint8 rawb = 0; uint8 rawb = 0;
for(unsigned ch = 0; ch < 8; ch++) for(unsigned ch = 0; ch < 8; ch++)
{ {
rawb |= ((in_buf[ch * 12 + d] >> (7 - bitpoodle)) & 1) << (7 - ch); rawb |= ((in_buf[ch * 12 + d] >> (7 - bitpoodle)) & 1) << (7 - ch);
} }
out_buf[(d << 3) + bitpoodle] = rawb; out_buf[(d << 3) + bitpoodle] = rawb;
} }
} }
} }
// NOTES ON LEADOUT AREA SYNTHESIS // NOTES ON LEADOUT AREA SYNTHESIS
// //
// I'm not trusting that the "control" field for the TOC leadout entry will always be set properly, so | the control fields for the last track entry // I'm not trusting that the "control" field for the TOC leadout entry will always be set properly, so | the control fields for the last track entry
// and the leadout entry together before extracting the D2 bit. Audio track->data leadout is fairly benign though maybe noisy(especially if we ever implement // and the leadout entry together before extracting the D2 bit. Audio track->data leadout is fairly benign though maybe noisy(especially if we ever implement
// data scrambling properly), but data track->audio leadout could break things in an insidious manner for the more accurate drive emulation code). // data scrambling properly), but data track->audio leadout could break things in an insidious manner for the more accurate drive emulation code).
// //
void subpw_synth_leadout_lba(const TOC& toc, const int32 lba, uint8* SubPWBuf) void subpw_synth_leadout_lba(const TOC& toc, const int32 lba, uint8* SubPWBuf)
{ {
uint8 buf[0xC]; uint8 buf[0xC];
uint32 lba_relative; uint32 lba_relative;
uint32 ma, sa, fa; uint32 ma, sa, fa;
uint32 m, s, f; uint32 m, s, f;
lba_relative = lba - toc.tracks[100].lba; lba_relative = lba - toc.tracks[100].lba;
f = (lba_relative % 75); f = (lba_relative % 75);
s = ((lba_relative / 75) % 60); s = ((lba_relative / 75) % 60);
m = (lba_relative / 75 / 60); m = (lba_relative / 75 / 60);
fa = (lba + 150) % 75; fa = (lba + 150) % 75;
sa = ((lba + 150) / 75) % 60; sa = ((lba + 150) / 75) % 60;
ma = ((lba + 150) / 75 / 60); ma = ((lba + 150) / 75 / 60);
uint8 adr = 0x1; // Q channel data encodes position uint8 adr = 0x1; // Q channel data encodes position
uint8 control = toc.tracks[100].control; uint8 control = toc.tracks[100].control;
if(toc.tracks[toc.last_track].valid) if(toc.tracks[toc.last_track].valid)
control |= toc.tracks[toc.last_track].control & 0x4; control |= toc.tracks[toc.last_track].control & 0x4;
else if(toc.disc_type == DISC_TYPE_CD_I) else if(toc.disc_type == DISC_TYPE_CD_I)
control |= 0x4; control |= 0x4;
memset(buf, 0, 0xC); memset(buf, 0, 0xC);
buf[0] = (adr << 0) | (control << 4); buf[0] = (adr << 0) | (control << 4);
buf[1] = 0xAA; buf[1] = 0xAA;
buf[2] = 0x01; buf[2] = 0x01;
// Track relative MSF address // Track relative MSF address
buf[3] = U8_to_BCD(m); buf[3] = U8_to_BCD(m);
buf[4] = U8_to_BCD(s); buf[4] = U8_to_BCD(s);
buf[5] = U8_to_BCD(f); buf[5] = U8_to_BCD(f);
buf[6] = 0; // Zerroooo buf[6] = 0; // Zerroooo
// Absolute MSF address // Absolute MSF address
buf[7] = U8_to_BCD(ma); buf[7] = U8_to_BCD(ma);
buf[8] = U8_to_BCD(sa); buf[8] = U8_to_BCD(sa);
buf[9] = U8_to_BCD(fa); buf[9] = U8_to_BCD(fa);
subq_generate_checksum(buf); subq_generate_checksum(buf);
for(int i = 0; i < 96; i++) for(int i = 0; i < 96; i++)
SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80; SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80;
} }
void synth_leadout_sector_lba(uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf) void synth_leadout_sector_lba(uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf)
{ {
memset(out_buf, 0, 2352 + 96); memset(out_buf, 0, 2352 + 96);
subpw_synth_leadout_lba(toc, lba, out_buf + 2352); subpw_synth_leadout_lba(toc, lba, out_buf + 2352);
if(out_buf[2352 + 1] & 0x40) if(out_buf[2352 + 1] & 0x40)
{ {
if(mode == 0xFF) if(mode == 0xFF)
{ {
if(toc.disc_type == DISC_TYPE_CD_XA || toc.disc_type == DISC_TYPE_CD_I) if(toc.disc_type == DISC_TYPE_CD_XA || toc.disc_type == DISC_TYPE_CD_I)
mode = 0x02; mode = 0x02;
else else
mode = 0x01; mode = 0x01;
} }
switch(mode) switch(mode)
{ {
default: default:
encode_mode0_sector(LBA_to_ABA(lba), out_buf); encode_mode0_sector(LBA_to_ABA(lba), out_buf);
break; break;
case 0x01: case 0x01:
encode_mode1_sector(LBA_to_ABA(lba), out_buf); encode_mode1_sector(LBA_to_ABA(lba), out_buf);
break; break;
case 0x02: case 0x02:
out_buf[12 + 6] = 0x20; out_buf[12 + 6] = 0x20;
out_buf[12 + 10] = 0x20; out_buf[12 + 10] = 0x20;
encode_mode2_form2_sector(LBA_to_ABA(lba), out_buf); encode_mode2_form2_sector(LBA_to_ABA(lba), out_buf);
break; break;
} }
} }
} }
// ISO/IEC 10149:1995 (E): 20.2 // ISO/IEC 10149:1995 (E): 20.2
// //
void subpw_synth_udapp_lba(const TOC& toc, const int32 lba, const int32 lba_subq_relative_offs, uint8* SubPWBuf) void subpw_synth_udapp_lba(const TOC& toc, const int32 lba, const int32 lba_subq_relative_offs, uint8* SubPWBuf)
{ {
uint8 buf[0xC]; uint8 buf[0xC];
uint32 lba_relative; uint32 lba_relative;
uint32 ma, sa, fa; uint32 ma, sa, fa;
uint32 m, s, f; uint32 m, s, f;
if(lba < -150 || lba >= 0) if(lba < -150 || lba >= 0)
printf("[BUG] subpw_synth_udapp_lba() lba out of range --- %d\n", lba); printf("[BUG] subpw_synth_udapp_lba() lba out of range --- %d\n", lba);
{ {
int32 lba_tmp = lba + lba_subq_relative_offs; int32 lba_tmp = lba + lba_subq_relative_offs;
if(lba_tmp < 0) if(lba_tmp < 0)
lba_relative = 0 - 1 - lba_tmp; lba_relative = 0 - 1 - lba_tmp;
else else
lba_relative = lba_tmp - 0; lba_relative = lba_tmp - 0;
} }
f = (lba_relative % 75); f = (lba_relative % 75);
s = ((lba_relative / 75) % 60); s = ((lba_relative / 75) % 60);
m = (lba_relative / 75 / 60); m = (lba_relative / 75 / 60);
fa = (lba + 150) % 75; fa = (lba + 150) % 75;
sa = ((lba + 150) / 75) % 60; sa = ((lba + 150) / 75) % 60;
ma = ((lba + 150) / 75 / 60); ma = ((lba + 150) / 75 / 60);
uint8 adr = 0x1; // Q channel data encodes position uint8 adr = 0x1; // Q channel data encodes position
uint8 control; uint8 control;
if(toc.disc_type == DISC_TYPE_CD_I && toc.first_track > 1) if(toc.disc_type == DISC_TYPE_CD_I && toc.first_track > 1)
control = 0x4; control = 0x4;
else if(toc.tracks[toc.first_track].valid) else if(toc.tracks[toc.first_track].valid)
control = toc.tracks[toc.first_track].control; control = toc.tracks[toc.first_track].control;
else else
control = 0x0; control = 0x0;
memset(buf, 0, 0xC); memset(buf, 0, 0xC);
buf[0] = (adr << 0) | (control << 4); buf[0] = (adr << 0) | (control << 4);
buf[1] = U8_to_BCD(toc.first_track); buf[1] = U8_to_BCD(toc.first_track);
buf[2] = U8_to_BCD(0x00); buf[2] = U8_to_BCD(0x00);
// Track relative MSF address // Track relative MSF address
buf[3] = U8_to_BCD(m); buf[3] = U8_to_BCD(m);
buf[4] = U8_to_BCD(s); buf[4] = U8_to_BCD(s);
buf[5] = U8_to_BCD(f); buf[5] = U8_to_BCD(f);
buf[6] = 0; // Zerroooo buf[6] = 0; // Zerroooo
// Absolute MSF address // Absolute MSF address
buf[7] = U8_to_BCD(ma); buf[7] = U8_to_BCD(ma);
buf[8] = U8_to_BCD(sa); buf[8] = U8_to_BCD(sa);
buf[9] = U8_to_BCD(fa); buf[9] = U8_to_BCD(fa);
subq_generate_checksum(buf); subq_generate_checksum(buf);
for(int i = 0; i < 96; i++) for(int i = 0; i < 96; i++)
SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80; SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80;
} }
void synth_udapp_sector_lba(uint8 mode, const TOC& toc, const int32 lba, int32 lba_subq_relative_offs, uint8* out_buf) void synth_udapp_sector_lba(uint8 mode, const TOC& toc, const int32 lba, int32 lba_subq_relative_offs, uint8* out_buf)
{ {
memset(out_buf, 0, 2352 + 96); memset(out_buf, 0, 2352 + 96);
subpw_synth_udapp_lba(toc, lba, lba_subq_relative_offs, out_buf + 2352); subpw_synth_udapp_lba(toc, lba, lba_subq_relative_offs, out_buf + 2352);
if(out_buf[2352 + 1] & 0x40) if(out_buf[2352 + 1] & 0x40)
{ {
if(mode == 0xFF) if(mode == 0xFF)
{ {
if(toc.disc_type == DISC_TYPE_CD_XA || toc.disc_type == DISC_TYPE_CD_I) if(toc.disc_type == DISC_TYPE_CD_XA || toc.disc_type == DISC_TYPE_CD_I)
mode = 0x02; mode = 0x02;
else else
mode = 0x01; mode = 0x01;
} }
switch(mode) switch(mode)
{ {
default: default:
encode_mode0_sector(LBA_to_ABA(lba), out_buf); encode_mode0_sector(LBA_to_ABA(lba), out_buf);
break; break;
case 0x01: case 0x01:
encode_mode1_sector(LBA_to_ABA(lba), out_buf); encode_mode1_sector(LBA_to_ABA(lba), out_buf);
break; break;
case 0x02: case 0x02:
out_buf[12 + 6] = 0x20; out_buf[12 + 6] = 0x20;
out_buf[12 + 10] = 0x20; out_buf[12 + 10] = 0x20;
encode_mode2_form2_sector(LBA_to_ABA(lba), out_buf); encode_mode2_form2_sector(LBA_to_ABA(lba), out_buf);
break; break;
} }
} }
} }
#if 0 #if 0
bool subq_extrapolate(const uint8 *subq_input, int32 position_delta, uint8 *subq_output) bool subq_extrapolate(const uint8 *subq_input, int32 position_delta, uint8 *subq_output)
{ {
assert(subq_check_checksum(subq_input)); assert(subq_check_checksum(subq_input));
subq_generate_checksum(subq_output); subq_generate_checksum(subq_output);
} }
#endif #endif
void scrambleize_data_sector(uint8 *sector_data) void scrambleize_data_sector(uint8 *sector_data)
{ {
for(unsigned i = 12; i < 2352; i++) for(unsigned i = 12; i < 2352; i++)
sector_data[i] ^= scramble_table[i - 12]; sector_data[i] ^= scramble_table[i - 12];
} }
} }

View File

@ -6,6 +6,7 @@
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#include <cstdlib> #include <cstdlib>
#include <cstdio>
#include <memory> #include <memory>
typedef uint8_t uint8; typedef uint8_t uint8;

View File

@ -1,43 +1,9 @@
CC = x86_64-nt64-midipix-gcc CCFLAGS := -I. \
CCFLAGS:=-I. \
-I../emulibc \
-Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=implicit-function-declaration \ -Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=implicit-function-declaration \
-std=c99 -fomit-frame-pointer -fvisibility=hidden \ -std=c99 -fomit-frame-pointer \
-falign-functions=16 \ -falign-functions=16 \
-DLSB_FIRST -DNDEBUG -DEMU_F68K -D_USE_CZ80 \ -DLSB_FIRST -DNDEBUG -DEMU_F68K -D_USE_CZ80
-O3 -flto
TARGET = picodrive.wbx TARGET := picodrive.wbx
SRCS = $(shell find $(ROOT_DIR) -type f -name '*.c')
LDFLAGS = -Wl,--dynamicbase,--export-all-symbols include ../common.mak
ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
SRCS:=$(shell find $(ROOT_DIR) -type f -name '*.c')
OBJ_DIR:=$(ROOT_DIR)/obj
_OBJS:=$(SRCS:.c=.o)
OBJS:=$(patsubst $(ROOT_DIR)%,$(OBJ_DIR)%,$(_OBJS))
$(OBJ_DIR)/%.o: %.c
@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)
#install:
# $(CP) $(TARGET) $(DEST_$(ARCH))

View File

@ -1,12 +1,24 @@
This is the experimental "waterbox" project for bizhawk. This is the native side of the experimental "waterbox" project for bizhawk.
It consists of a modified musl libc, and build scripts to tie it all together.
libc.so, libgcc_s.so, libstdc++.so.6, and the waterbox executables are built with a modified verion of the midipix project.
The makefiles for the cores only support the cross compilation setup (build from whatever linux box you built midipix How to use:
from).
1. Get a full Bizhawk checkout.
The mmglue portion of the midipix project is modified; get the correct version from <ssh://git@github.com/nattthebear/mmglue.git>. * This needs to be in an NTFS path which is then foreign mounted in WSL2
2. Get WSL2 + Ubuntu 20.4LTS
gpgx: This is a modified version of our gpgx core * Other combinations may work. Shrug.
snes9x: Based off of snes9x 1.54. 3. Start running commands:
cd musl
./configure-for-waterbox
make
make install
cd ../emulibc
make
cd ../libco
make
cd ../libcxx
./do-everything.sh
cd ../<insert your favourite core here>
make
make install

View File

@ -1,54 +1,17 @@
CC = x86_64-nt64-midipix-gcc FLAGS := -Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=implicit-function-declaration \
CPP = x86_64-nt64-midipix-g++
FLAGS:=-Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=implicit-function-declaration \
-Wno-multichar \ -Wno-multichar \
-fomit-frame-pointer \ -fomit-frame-pointer
-O3 -flto
CCFLAGS:=$(FLAGS) \ CCFLAGS := $(FLAGS) \
-std=gnu99 \ -std=gnu99 \
-DLSB_FIRST -D_GNU_SOURCE -DGB_INTERNAL -DLSB_FIRST -D_GNU_SOURCE -DGB_INTERNAL
CPPFLAGS:=$(FLAGS) -DSPC_NO_COPY_STATE_FUNCS -std=c++0x -D_GNU_SOURCE -DGB_INTERNAL CPPFLAGS := $(FLAGS) -DSPC_NO_COPY_STATE_FUNCS -std=c++0x -D_GNU_SOURCE -DGB_INTERNAL
TARGET = sameboy.wbx TARGET := sameboy.wbx
LDFLAGS = -Wl,--dynamicbase,--export-all-symbols C_SRCS = $(shell find $(ROOT_DIR) -type f -name '*.c')
CPP_SRCS = $(shell find $(ROOT_DIR) -type f -name '*.cpp')
SRCS = $(C_SRCS) $(CPP_SRCS)
ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) include ../common.mak
C_SRCS:=$(shell find $(ROOT_DIR) -type f -name '*.c')
CPP_SRCS:=$(shell find $(ROOT_DIR) -type f -name '*.cpp')
SRCS:=$(C_SRCS) $(CPP_SRCS)
OBJ_DIR:=$(ROOT_DIR)/obj
__OBJS:=$(SRCS:.c=.o)
_OBJS:=$(__OBJS:.cpp=.opp)
OBJS:=$(patsubst $(ROOT_DIR)%,$(OBJ_DIR)%,$(_OBJS))
$(OBJ_DIR)/%.o: %.c
@mkdir -p $(@D)
@$(CC) -c -o $@ $< $(CCFLAGS)
$(OBJ_DIR)/%.opp: %.cpp
@mkdir -p $(@D)
@$(CPP) -c -o $@ $< $(CPPFLAGS)
all: $(TARGET)
.PHONY: clean all
$(TARGET).in: $(OBJS)
@$(CPP) -o $@ $(LDFLAGS) $(FLAGS) $(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)
#install:
# $(CP) $(TARGET) $(DEST_$(ARCH))

@ -1 +1 @@
Subproject commit 6d1d6dc591cb1cbb183760d2783dd37f0d8bf773 Subproject commit a261d2a22b2fefb4b7eab633a2d5fd7d691ce890

View File

@ -1,44 +1,10 @@
CC = x86_64-nt64-midipix-g++ CCFLAGS:= \
-Wall -Werror=int-to-pointer-cast \
CCFLAGS:= -I. -I../emulibc \ -std=c++0x -fomit-frame-pointer -fno-exceptions -fno-rtti \
-Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=implicit-function-declaration \ -DLSB_FIRST
-std=c++0x -fomit-frame-pointer -fvisibility=hidden -fno-exceptions -fno-rtti \
-DLSB_FIRST \ TARGET = ss.wbx
-O3 -flto
SRCS = $(shell find $(ROOT_DIR) -type f -name '*.cpp')
TARGET = ss.wbx
include ../common.mak
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))

View File

@ -1,430 +1,430 @@
/* Mednafen - Multi-system Emulator /* Mednafen - Multi-system Emulator
* *
* Subchannel Q CRC Code: Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.de> * Subchannel Q CRC Code: Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.de>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include "defs.h" #include "../defs.h"
#include "CDUtility.h" #include "CDUtility.h"
#include "dvdisaster.h" #include "dvdisaster.h"
#include "lec.h" #include "lec.h"
#include <assert.h> #include <assert.h>
namespace CDUtility namespace CDUtility
{ {
// lookup table for crc calculation // lookup table for crc calculation
static uint16 subq_crctab[256] = static uint16 subq_crctab[256] =
{ {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
}; };
static uint8 scramble_table[2352 - 12]; static uint8 scramble_table[2352 - 12];
static bool CDUtility_Inited = false; static bool CDUtility_Inited = false;
static void InitScrambleTable(void) static void InitScrambleTable(void)
{ {
unsigned cv = 1; unsigned cv = 1;
for(unsigned i = 12; i < 2352; i++) for(unsigned i = 12; i < 2352; i++)
{ {
unsigned char z = 0; unsigned char z = 0;
for(int b = 0; b < 8; b++) for(int b = 0; b < 8; b++)
{ {
z |= (cv & 1) << b; z |= (cv & 1) << b;
int feedback = ((cv >> 1) & 1) ^ (cv & 1); int feedback = ((cv >> 1) & 1) ^ (cv & 1);
cv = (cv >> 1) | (feedback << 14); cv = (cv >> 1) | (feedback << 14);
} }
scramble_table[i - 12] = z; scramble_table[i - 12] = z;
} }
//for(int i = 0; i < 2352 - 12; i++) //for(int i = 0; i < 2352 - 12; i++)
// printf("0x%02x, ", scramble_table[i]); // printf("0x%02x, ", scramble_table[i]);
} }
void CDUtility_Init(void) void CDUtility_Init(void)
{ {
if(!CDUtility_Inited) if(!CDUtility_Inited)
{ {
//Init_LEC_Correct(); //Init_LEC_Correct();
InitScrambleTable(); InitScrambleTable();
CDUtility_Inited = true; CDUtility_Inited = true;
} }
} }
void encode_mode0_sector(uint32 aba, uint8 *sector_data) void encode_mode0_sector(uint32 aba, uint8 *sector_data)
{ {
CDUtility_Init(); CDUtility_Init();
lec_encode_mode0_sector(aba, sector_data); lec_encode_mode0_sector(aba, sector_data);
} }
void encode_mode1_sector(uint32 aba, uint8 *sector_data) void encode_mode1_sector(uint32 aba, uint8 *sector_data)
{ {
CDUtility_Init(); CDUtility_Init();
lec_encode_mode1_sector(aba, sector_data); lec_encode_mode1_sector(aba, sector_data);
} }
void encode_mode2_sector(uint32 aba, uint8 *sector_data) void encode_mode2_sector(uint32 aba, uint8 *sector_data)
{ {
CDUtility_Init(); CDUtility_Init();
lec_encode_mode2_sector(aba, sector_data); lec_encode_mode2_sector(aba, sector_data);
} }
void encode_mode2_form1_sector(uint32 aba, uint8 *sector_data) void encode_mode2_form1_sector(uint32 aba, uint8 *sector_data)
{ {
CDUtility_Init(); CDUtility_Init();
lec_encode_mode2_form1_sector(aba, sector_data); lec_encode_mode2_form1_sector(aba, sector_data);
} }
void encode_mode2_form2_sector(uint32 aba, uint8 *sector_data) void encode_mode2_form2_sector(uint32 aba, uint8 *sector_data)
{ {
CDUtility_Init(); CDUtility_Init();
lec_encode_mode2_form2_sector(aba, sector_data); lec_encode_mode2_form2_sector(aba, sector_data);
} }
bool edc_check(const uint8 *sector_data, bool xa) bool edc_check(const uint8 *sector_data, bool xa)
{ {
CDUtility_Init(); CDUtility_Init();
return(CheckEDC(sector_data, xa)); return(CheckEDC(sector_data, xa));
} }
bool edc_lec_check_and_correct(uint8 *sector_data, bool xa) bool edc_lec_check_and_correct(uint8 *sector_data, bool xa)
{ {
CDUtility_Init(); CDUtility_Init();
return(ValidateRawSector(sector_data, xa)); return(ValidateRawSector(sector_data, xa));
} }
bool subq_check_checksum(const uint8 *SubQBuf) bool subq_check_checksum(const uint8 *SubQBuf)
{ {
uint16 crc = 0; uint16 crc = 0;
uint16 stored_crc = 0; uint16 stored_crc = 0;
stored_crc = SubQBuf[0xA] << 8; stored_crc = SubQBuf[0xA] << 8;
stored_crc |= SubQBuf[0xB]; stored_crc |= SubQBuf[0xB];
for(int i = 0; i < 0xA; i++) for(int i = 0; i < 0xA; i++)
crc = subq_crctab[(crc >> 8) ^ SubQBuf[i]] ^ (crc << 8); crc = subq_crctab[(crc >> 8) ^ SubQBuf[i]] ^ (crc << 8);
crc = ~crc; crc = ~crc;
return(crc == stored_crc); return(crc == stored_crc);
} }
void subq_generate_checksum(uint8 *buf) void subq_generate_checksum(uint8 *buf)
{ {
uint16 crc = 0; uint16 crc = 0;
for(int i = 0; i < 0xA; i++) for(int i = 0; i < 0xA; i++)
crc = subq_crctab[(crc >> 8) ^ buf[i]] ^ (crc << 8); crc = subq_crctab[(crc >> 8) ^ buf[i]] ^ (crc << 8);
// Checksum // Checksum
buf[0xa] = ~(crc >> 8); buf[0xa] = ~(crc >> 8);
buf[0xb] = ~(crc); buf[0xb] = ~(crc);
} }
void subq_deinterleave(const uint8 *SubPWBuf, uint8 *qbuf) void subq_deinterleave(const uint8 *SubPWBuf, uint8 *qbuf)
{ {
memset(qbuf, 0, 0xC); memset(qbuf, 0, 0xC);
for(int i = 0; i < 96; i++) for(int i = 0; i < 96; i++)
{ {
qbuf[i >> 3] |= ((SubPWBuf[i] >> 6) & 0x1) << (7 - (i & 0x7)); qbuf[i >> 3] |= ((SubPWBuf[i] >> 6) & 0x1) << (7 - (i & 0x7));
} }
} }
// Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data. // Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.
void subpw_deinterleave(const uint8 *in_buf, uint8 *out_buf) void subpw_deinterleave(const uint8 *in_buf, uint8 *out_buf)
{ {
assert(in_buf != out_buf); assert(in_buf != out_buf);
memset(out_buf, 0, 96); memset(out_buf, 0, 96);
for(unsigned ch = 0; ch < 8; ch++) for(unsigned ch = 0; ch < 8; ch++)
{ {
for(unsigned i = 0; i < 96; i++) for(unsigned i = 0; i < 96; i++)
{ {
out_buf[(ch * 12) + (i >> 3)] |= ((in_buf[i] >> (7 - ch)) & 0x1) << (7 - (i & 0x7)); out_buf[(ch * 12) + (i >> 3)] |= ((in_buf[i] >> (7 - ch)) & 0x1) << (7 - (i & 0x7));
} }
} }
} }
// Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data. // Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.
void subpw_interleave(const uint8 *in_buf, uint8 *out_buf) void subpw_interleave(const uint8 *in_buf, uint8 *out_buf)
{ {
assert(in_buf != out_buf); assert(in_buf != out_buf);
for(unsigned d = 0; d < 12; d++) for(unsigned d = 0; d < 12; d++)
{ {
for(unsigned bitpoodle = 0; bitpoodle < 8; bitpoodle++) for(unsigned bitpoodle = 0; bitpoodle < 8; bitpoodle++)
{ {
uint8 rawb = 0; uint8 rawb = 0;
for(unsigned ch = 0; ch < 8; ch++) for(unsigned ch = 0; ch < 8; ch++)
{ {
rawb |= ((in_buf[ch * 12 + d] >> (7 - bitpoodle)) & 1) << (7 - ch); rawb |= ((in_buf[ch * 12 + d] >> (7 - bitpoodle)) & 1) << (7 - ch);
} }
out_buf[(d << 3) + bitpoodle] = rawb; out_buf[(d << 3) + bitpoodle] = rawb;
} }
} }
} }
// NOTES ON LEADOUT AREA SYNTHESIS // NOTES ON LEADOUT AREA SYNTHESIS
// //
// I'm not trusting that the "control" field for the TOC leadout entry will always be set properly, so | the control fields for the last track entry // I'm not trusting that the "control" field for the TOC leadout entry will always be set properly, so | the control fields for the last track entry
// and the leadout entry together before extracting the D2 bit. Audio track->data leadout is fairly benign though maybe noisy(especially if we ever implement // and the leadout entry together before extracting the D2 bit. Audio track->data leadout is fairly benign though maybe noisy(especially if we ever implement
// data scrambling properly), but data track->audio leadout could break things in an insidious manner for the more accurate drive emulation code). // data scrambling properly), but data track->audio leadout could break things in an insidious manner for the more accurate drive emulation code).
// //
void subpw_synth_leadout_lba(const TOC& toc, const int32 lba, uint8* SubPWBuf) void subpw_synth_leadout_lba(const TOC& toc, const int32 lba, uint8* SubPWBuf)
{ {
uint8 buf[0xC]; uint8 buf[0xC];
uint32 lba_relative; uint32 lba_relative;
uint32 ma, sa, fa; uint32 ma, sa, fa;
uint32 m, s, f; uint32 m, s, f;
lba_relative = lba - toc.tracks[100].lba; lba_relative = lba - toc.tracks[100].lba;
f = (lba_relative % 75); f = (lba_relative % 75);
s = ((lba_relative / 75) % 60); s = ((lba_relative / 75) % 60);
m = (lba_relative / 75 / 60); m = (lba_relative / 75 / 60);
fa = (lba + 150) % 75; fa = (lba + 150) % 75;
sa = ((lba + 150) / 75) % 60; sa = ((lba + 150) / 75) % 60;
ma = ((lba + 150) / 75 / 60); ma = ((lba + 150) / 75 / 60);
uint8 adr = 0x1; // Q channel data encodes position uint8 adr = 0x1; // Q channel data encodes position
uint8 control = toc.tracks[100].control; uint8 control = toc.tracks[100].control;
if(toc.tracks[toc.last_track].valid) if(toc.tracks[toc.last_track].valid)
control |= toc.tracks[toc.last_track].control & 0x4; control |= toc.tracks[toc.last_track].control & 0x4;
else if(toc.disc_type == DISC_TYPE_CD_I) else if(toc.disc_type == DISC_TYPE_CD_I)
control |= 0x4; control |= 0x4;
memset(buf, 0, 0xC); memset(buf, 0, 0xC);
buf[0] = (adr << 0) | (control << 4); buf[0] = (adr << 0) | (control << 4);
buf[1] = 0xAA; buf[1] = 0xAA;
buf[2] = 0x01; buf[2] = 0x01;
// Track relative MSF address // Track relative MSF address
buf[3] = U8_to_BCD(m); buf[3] = U8_to_BCD(m);
buf[4] = U8_to_BCD(s); buf[4] = U8_to_BCD(s);
buf[5] = U8_to_BCD(f); buf[5] = U8_to_BCD(f);
buf[6] = 0; // Zerroooo buf[6] = 0; // Zerroooo
// Absolute MSF address // Absolute MSF address
buf[7] = U8_to_BCD(ma); buf[7] = U8_to_BCD(ma);
buf[8] = U8_to_BCD(sa); buf[8] = U8_to_BCD(sa);
buf[9] = U8_to_BCD(fa); buf[9] = U8_to_BCD(fa);
subq_generate_checksum(buf); subq_generate_checksum(buf);
for(int i = 0; i < 96; i++) for(int i = 0; i < 96; i++)
SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80; SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80;
} }
void synth_leadout_sector_lba(uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf) void synth_leadout_sector_lba(uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf)
{ {
memset(out_buf, 0, 2352 + 96); memset(out_buf, 0, 2352 + 96);
subpw_synth_leadout_lba(toc, lba, out_buf + 2352); subpw_synth_leadout_lba(toc, lba, out_buf + 2352);
if(out_buf[2352 + 1] & 0x40) if(out_buf[2352 + 1] & 0x40)
{ {
if(mode == 0xFF) if(mode == 0xFF)
{ {
if(toc.disc_type == DISC_TYPE_CD_XA || toc.disc_type == DISC_TYPE_CD_I) if(toc.disc_type == DISC_TYPE_CD_XA || toc.disc_type == DISC_TYPE_CD_I)
mode = 0x02; mode = 0x02;
else else
mode = 0x01; mode = 0x01;
} }
switch(mode) switch(mode)
{ {
default: default:
encode_mode0_sector(LBA_to_ABA(lba), out_buf); encode_mode0_sector(LBA_to_ABA(lba), out_buf);
break; break;
case 0x01: case 0x01:
encode_mode1_sector(LBA_to_ABA(lba), out_buf); encode_mode1_sector(LBA_to_ABA(lba), out_buf);
break; break;
case 0x02: case 0x02:
out_buf[12 + 6] = 0x20; out_buf[12 + 6] = 0x20;
out_buf[12 + 10] = 0x20; out_buf[12 + 10] = 0x20;
encode_mode2_form2_sector(LBA_to_ABA(lba), out_buf); encode_mode2_form2_sector(LBA_to_ABA(lba), out_buf);
break; break;
} }
} }
} }
// ISO/IEC 10149:1995 (E): 20.2 // ISO/IEC 10149:1995 (E): 20.2
// //
void subpw_synth_udapp_lba(const TOC& toc, const int32 lba, const int32 lba_subq_relative_offs, uint8* SubPWBuf) void subpw_synth_udapp_lba(const TOC& toc, const int32 lba, const int32 lba_subq_relative_offs, uint8* SubPWBuf)
{ {
uint8 buf[0xC]; uint8 buf[0xC];
uint32 lba_relative; uint32 lba_relative;
uint32 ma, sa, fa; uint32 ma, sa, fa;
uint32 m, s, f; uint32 m, s, f;
if(lba < -150 || lba >= 0) if(lba < -150 || lba >= 0)
printf("[BUG] subpw_synth_udapp_lba() lba out of range --- %d\n", lba); printf("[BUG] subpw_synth_udapp_lba() lba out of range --- %d\n", lba);
{ {
int32 lba_tmp = lba + lba_subq_relative_offs; int32 lba_tmp = lba + lba_subq_relative_offs;
if(lba_tmp < 0) if(lba_tmp < 0)
lba_relative = 0 - 1 - lba_tmp; lba_relative = 0 - 1 - lba_tmp;
else else
lba_relative = lba_tmp - 0; lba_relative = lba_tmp - 0;
} }
f = (lba_relative % 75); f = (lba_relative % 75);
s = ((lba_relative / 75) % 60); s = ((lba_relative / 75) % 60);
m = (lba_relative / 75 / 60); m = (lba_relative / 75 / 60);
fa = (lba + 150) % 75; fa = (lba + 150) % 75;
sa = ((lba + 150) / 75) % 60; sa = ((lba + 150) / 75) % 60;
ma = ((lba + 150) / 75 / 60); ma = ((lba + 150) / 75 / 60);
uint8 adr = 0x1; // Q channel data encodes position uint8 adr = 0x1; // Q channel data encodes position
uint8 control; uint8 control;
if(toc.disc_type == DISC_TYPE_CD_I && toc.first_track > 1) if(toc.disc_type == DISC_TYPE_CD_I && toc.first_track > 1)
control = 0x4; control = 0x4;
else if(toc.tracks[toc.first_track].valid) else if(toc.tracks[toc.first_track].valid)
control = toc.tracks[toc.first_track].control; control = toc.tracks[toc.first_track].control;
else else
control = 0x0; control = 0x0;
memset(buf, 0, 0xC); memset(buf, 0, 0xC);
buf[0] = (adr << 0) | (control << 4); buf[0] = (adr << 0) | (control << 4);
buf[1] = U8_to_BCD(toc.first_track); buf[1] = U8_to_BCD(toc.first_track);
buf[2] = U8_to_BCD(0x00); buf[2] = U8_to_BCD(0x00);
// Track relative MSF address // Track relative MSF address
buf[3] = U8_to_BCD(m); buf[3] = U8_to_BCD(m);
buf[4] = U8_to_BCD(s); buf[4] = U8_to_BCD(s);
buf[5] = U8_to_BCD(f); buf[5] = U8_to_BCD(f);
buf[6] = 0; // Zerroooo buf[6] = 0; // Zerroooo
// Absolute MSF address // Absolute MSF address
buf[7] = U8_to_BCD(ma); buf[7] = U8_to_BCD(ma);
buf[8] = U8_to_BCD(sa); buf[8] = U8_to_BCD(sa);
buf[9] = U8_to_BCD(fa); buf[9] = U8_to_BCD(fa);
subq_generate_checksum(buf); subq_generate_checksum(buf);
for(int i = 0; i < 96; i++) for(int i = 0; i < 96; i++)
SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80; SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80;
} }
void synth_udapp_sector_lba(uint8 mode, const TOC& toc, const int32 lba, int32 lba_subq_relative_offs, uint8* out_buf) void synth_udapp_sector_lba(uint8 mode, const TOC& toc, const int32 lba, int32 lba_subq_relative_offs, uint8* out_buf)
{ {
memset(out_buf, 0, 2352 + 96); memset(out_buf, 0, 2352 + 96);
subpw_synth_udapp_lba(toc, lba, lba_subq_relative_offs, out_buf + 2352); subpw_synth_udapp_lba(toc, lba, lba_subq_relative_offs, out_buf + 2352);
if(out_buf[2352 + 1] & 0x40) if(out_buf[2352 + 1] & 0x40)
{ {
if(mode == 0xFF) if(mode == 0xFF)
{ {
if(toc.disc_type == DISC_TYPE_CD_XA || toc.disc_type == DISC_TYPE_CD_I) if(toc.disc_type == DISC_TYPE_CD_XA || toc.disc_type == DISC_TYPE_CD_I)
mode = 0x02; mode = 0x02;
else else
mode = 0x01; mode = 0x01;
} }
switch(mode) switch(mode)
{ {
default: default:
encode_mode0_sector(LBA_to_ABA(lba), out_buf); encode_mode0_sector(LBA_to_ABA(lba), out_buf);
break; break;
case 0x01: case 0x01:
encode_mode1_sector(LBA_to_ABA(lba), out_buf); encode_mode1_sector(LBA_to_ABA(lba), out_buf);
break; break;
case 0x02: case 0x02:
out_buf[12 + 6] = 0x20; out_buf[12 + 6] = 0x20;
out_buf[12 + 10] = 0x20; out_buf[12 + 10] = 0x20;
encode_mode2_form2_sector(LBA_to_ABA(lba), out_buf); encode_mode2_form2_sector(LBA_to_ABA(lba), out_buf);
break; break;
} }
} }
} }
#if 0 #if 0
bool subq_extrapolate(const uint8 *subq_input, int32 position_delta, uint8 *subq_output) bool subq_extrapolate(const uint8 *subq_input, int32 position_delta, uint8 *subq_output)
{ {
assert(subq_check_checksum(subq_input)); assert(subq_check_checksum(subq_input));
subq_generate_checksum(subq_output); subq_generate_checksum(subq_output);
} }
#endif #endif
void scrambleize_data_sector(uint8 *sector_data) void scrambleize_data_sector(uint8 *sector_data)
{ {
for(unsigned i = 12; i < 2352; i++) for(unsigned i = 12; i < 2352; i++)
sector_data[i] ^= scramble_table[i - 12]; sector_data[i] ^= scramble_table[i - 12];
} }
} }

View File

@ -1,131 +1,131 @@
/* Mednafen - Multi-system Emulator /* Mednafen - Multi-system Emulator
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include "ss.h" #include "../ss.h"
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include "cdromif.h" #include "cdromif.h"
//#include "CDAccess.h" //#include "CDAccess.h"
//#include "../general.h" //#include "../general.h"
#include <algorithm> #include <algorithm>
using namespace CDUtility; using namespace CDUtility;
enum enum
{ {
// Status/Error messages // Status/Error messages
CDIF_MSG_DONE = 0, // Read -> emu. args: No args. CDIF_MSG_DONE = 0, // Read -> emu. args: No args.
CDIF_MSG_INFO, // Read -> emu. args: str_message CDIF_MSG_INFO, // Read -> emu. args: str_message
CDIF_MSG_FATAL_ERROR, // Read -> emu. args: *TODO ARGS* CDIF_MSG_FATAL_ERROR, // Read -> emu. args: *TODO ARGS*
// //
// Command messages. // Command messages.
// //
CDIF_MSG_DIEDIEDIE, // Emu -> read CDIF_MSG_DIEDIEDIE, // Emu -> read
CDIF_MSG_READ_SECTOR, /* Emu -> read CDIF_MSG_READ_SECTOR, /* Emu -> read
args[0] = lba args[0] = lba
*/ */
}; };
typedef struct typedef struct
{ {
bool valid; bool valid;
bool error; bool error;
int32 lba; int32 lba;
uint8 data[2352 + 96]; uint8 data[2352 + 96];
} CDIF_Sector_Buffer; } CDIF_Sector_Buffer;
CDIF::CDIF() : UnrecoverableError(false) CDIF::CDIF() : UnrecoverableError(false)
{ {
} }
CDIF::~CDIF() CDIF::~CDIF()
{ {
} }
bool CDIF::ValidateRawSector(uint8 *buf) bool CDIF::ValidateRawSector(uint8 *buf)
{ {
int mode = buf[12 + 3]; int mode = buf[12 + 3];
if(mode != 0x1 && mode != 0x2) if(mode != 0x1 && mode != 0x2)
return(false); return(false);
if(!edc_lec_check_and_correct(buf, mode == 2)) if(!edc_lec_check_and_correct(buf, mode == 2))
return(false); return(false);
return(true); return(true);
} }
int CDIF::ReadSector(uint8* buf, int32 lba, uint32 sector_count, bool suppress_uncorrectable_message) int CDIF::ReadSector(uint8* buf, int32 lba, uint32 sector_count, bool suppress_uncorrectable_message)
{ {
int ret = 0; int ret = 0;
if(UnrecoverableError) if(UnrecoverableError)
return(false); return(false);
while(sector_count--) while(sector_count--)
{ {
uint8 tmpbuf[2352 + 96]; uint8 tmpbuf[2352 + 96];
if(!ReadRawSector(tmpbuf, lba)) if(!ReadRawSector(tmpbuf, lba))
{ {
puts("CDIF Raw Read error"); puts("CDIF Raw Read error");
return(FALSE); return(FALSE);
} }
if(!ValidateRawSector(tmpbuf)) if(!ValidateRawSector(tmpbuf))
{ {
/*if(!suppress_uncorrectable_message) /*if(!suppress_uncorrectable_message)
{ {
MDFN_DispMessage(_("Uncorrectable data at sector %d"), lba); MDFN_DispMessage(_("Uncorrectable data at sector %d"), lba);
MDFN_PrintError(_("Uncorrectable data at sector %d"), lba); MDFN_PrintError(_("Uncorrectable data at sector %d"), lba);
}*/ }*/
return(false); return(false);
} }
const int mode = tmpbuf[12 + 3]; const int mode = tmpbuf[12 + 3];
if(!ret) if(!ret)
ret = mode; ret = mode;
if(mode == 1) if(mode == 1)
{ {
memcpy(buf, &tmpbuf[12 + 4], 2048); memcpy(buf, &tmpbuf[12 + 4], 2048);
} }
else if(mode == 2) else if(mode == 2)
{ {
memcpy(buf, &tmpbuf[12 + 4 + 8], 2048); memcpy(buf, &tmpbuf[12 + 4 + 8], 2048);
} }
else else
{ {
printf("CDIF_ReadSector() invalid sector type at LBA=%u\n", (unsigned int)lba); printf("CDIF_ReadSector() invalid sector type at LBA=%u\n", (unsigned int)lba);
return(false); return(false);
} }
buf += 2048; buf += 2048;
lba++; lba++;
} }
return(ret); return(ret);
} }

View File

@ -1,171 +1,171 @@
/* dvdisaster: Additional error correction for optical media. /* dvdisaster: Additional error correction for optical media.
* Copyright (C) 2004-2007 Carsten Gnoerlich. * Copyright (C) 2004-2007 Carsten Gnoerlich.
* Project home page: http://www.dvdisaster.com * Project home page: http://www.dvdisaster.com
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org * Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA, * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
* or direct your browser at http://www.gnu.org. * or direct your browser at http://www.gnu.org.
*/ */
#ifndef DVDISASTER_H #ifndef DVDISASTER_H
#define DVDISASTER_H #define DVDISASTER_H
/* "Dare to be gorgeous and unique. /* "Dare to be gorgeous and unique.
* But don't ever be cryptic or otherwise unfathomable. * But don't ever be cryptic or otherwise unfathomable.
* Make it unforgettably great." * Make it unforgettably great."
* *
* From "A Final Note on Style", * From "A Final Note on Style",
* Amiga Intuition Reference Manual, 1986, p. 231 * Amiga Intuition Reference Manual, 1986, p. 231
*/ */
/*** /***
*** I'm too lazy to mess with #include dependencies. *** I'm too lazy to mess with #include dependencies.
*** Everything #includeable is rolled up herein... *** Everything #includeable is rolled up herein...
*/ */
#include "ss.h" #include "../ss.h"
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <math.h> #include <math.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <stdarg.h> #include <stdarg.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
/*** /***
*** dvdisaster.c *** dvdisaster.c
***/ ***/
void PrepareDeadSector(void); void PrepareDeadSector(void);
void CreateEcc(void); void CreateEcc(void);
void FixEcc(void); void FixEcc(void);
void Verify(void); void Verify(void);
uint32 EDCCrc32(const unsigned char*, int); uint32 EDCCrc32(const unsigned char*, int);
/*** /***
*** galois.c *** galois.c
*** ***
* This is currently the hardcoded GF(2**8). * This is currently the hardcoded GF(2**8).
* int32 gives abundant space for the GF. * int32 gives abundant space for the GF.
* Squeezing it down to uint8 won't probably gain much, * Squeezing it down to uint8 won't probably gain much,
* so we implement this defensively here. * so we implement this defensively here.
* *
* Note that some performance critical stuff needs to * Note that some performance critical stuff needs to
* be #included from galois-inlines.h * be #included from galois-inlines.h
*/ */
/* Galois field parameters for 8bit symbol Reed-Solomon code */ /* Galois field parameters for 8bit symbol Reed-Solomon code */
#define GF_SYMBOLSIZE 8 #define GF_SYMBOLSIZE 8
#define GF_FIELDSIZE (1<<GF_SYMBOLSIZE) #define GF_FIELDSIZE (1<<GF_SYMBOLSIZE)
#define GF_FIELDMAX (GF_FIELDSIZE-1) #define GF_FIELDMAX (GF_FIELDSIZE-1)
#define GF_ALPHA0 GF_FIELDMAX #define GF_ALPHA0 GF_FIELDMAX
/* Lookup tables for Galois field arithmetic */ /* Lookup tables for Galois field arithmetic */
typedef struct _GaloisTables typedef struct _GaloisTables
{ int32 gfGenerator; /* GF generator polynomial */ { int32 gfGenerator; /* GF generator polynomial */
int32 *indexOf; /* log */ int32 *indexOf; /* log */
int32 *alphaTo; /* inverse log */ int32 *alphaTo; /* inverse log */
int32 *encAlphaTo; /* inverse log optimized for encoder */ int32 *encAlphaTo; /* inverse log optimized for encoder */
} GaloisTables; } GaloisTables;
/* Lookup and working tables for the ReedSolomon codecs */ /* Lookup and working tables for the ReedSolomon codecs */
typedef struct _ReedSolomonTables typedef struct _ReedSolomonTables
{ GaloisTables *gfTables;/* from above */ { GaloisTables *gfTables;/* from above */
int32 *gpoly; /* RS code generator polynomial */ int32 *gpoly; /* RS code generator polynomial */
int32 fcr; /* first consecutive root of RS generator polynomial */ int32 fcr; /* first consecutive root of RS generator polynomial */
int32 primElem; /* primitive field element */ int32 primElem; /* primitive field element */
int32 nroots; /* degree of RS generator polynomial */ int32 nroots; /* degree of RS generator polynomial */
int32 ndata; /* data bytes per ecc block */ int32 ndata; /* data bytes per ecc block */
} ReedSolomonTables; } ReedSolomonTables;
GaloisTables* CreateGaloisTables(int32); GaloisTables* CreateGaloisTables(int32);
void FreeGaloisTables(GaloisTables*); void FreeGaloisTables(GaloisTables*);
ReedSolomonTables *CreateReedSolomonTables(GaloisTables*, int32, int32, int); ReedSolomonTables *CreateReedSolomonTables(GaloisTables*, int32, int32, int);
void FreeReedSolomonTables(ReedSolomonTables*); void FreeReedSolomonTables(ReedSolomonTables*);
/*** /***
*** l-ec.c *** l-ec.c
***/ ***/
#define N_P_VECTORS 86 /* 43 16bit p vectors */ #define N_P_VECTORS 86 /* 43 16bit p vectors */
#define P_VECTOR_SIZE 26 /* using RS(26,24) ECC */ #define P_VECTOR_SIZE 26 /* using RS(26,24) ECC */
#define N_Q_VECTORS 52 /* 26 16bit q vectors */ #define N_Q_VECTORS 52 /* 26 16bit q vectors */
#define Q_VECTOR_SIZE 45 /* using RS(45,43) ECC */ #define Q_VECTOR_SIZE 45 /* using RS(45,43) ECC */
#define P_PADDING 229 /* padding values for */ #define P_PADDING 229 /* padding values for */
#define Q_PADDING 210 /* shortened RS code */ #define Q_PADDING 210 /* shortened RS code */
int PToByteIndex(int, int); int PToByteIndex(int, int);
int QToByteIndex(int, int); int QToByteIndex(int, int);
void ByteIndexToP(int, int*, int*); void ByteIndexToP(int, int*, int*);
void ByteIndexToQ(int, int*, int*); void ByteIndexToQ(int, int*, int*);
void GetPVector(unsigned char*, unsigned char*, int); void GetPVector(unsigned char*, unsigned char*, int);
void SetPVector(unsigned char*, unsigned char*, int); void SetPVector(unsigned char*, unsigned char*, int);
void FillPVector(unsigned char*, unsigned char, int); void FillPVector(unsigned char*, unsigned char, int);
void AndPVector(unsigned char*, unsigned char, int); void AndPVector(unsigned char*, unsigned char, int);
void OrPVector(unsigned char*, unsigned char, int); void OrPVector(unsigned char*, unsigned char, int);
void GetQVector(unsigned char*, unsigned char*, int); void GetQVector(unsigned char*, unsigned char*, int);
void SetQVector(unsigned char*, unsigned char*, int); void SetQVector(unsigned char*, unsigned char*, int);
void FillQVector(unsigned char*, unsigned char, int); void FillQVector(unsigned char*, unsigned char, int);
void AndQVector(unsigned char*, unsigned char, int); void AndQVector(unsigned char*, unsigned char, int);
void OrQVector(unsigned char*, unsigned char, int); void OrQVector(unsigned char*, unsigned char, int);
int DecodePQ(ReedSolomonTables*, unsigned char*, int, int*, int); int DecodePQ(ReedSolomonTables*, unsigned char*, int, int*, int);
int CountC2Errors(unsigned char*); int CountC2Errors(unsigned char*);
/*** /***
*** misc.c *** misc.c
***/ ***/
char* sgettext(char*); char* sgettext(char*);
char* sgettext_utf8(char*); char* sgettext_utf8(char*);
int64 uchar_to_int64(unsigned char*); int64 uchar_to_int64(unsigned char*);
void int64_to_uchar(unsigned char*, int64); void int64_to_uchar(unsigned char*, int64);
void CalcSectors(int64, int64*, int*); void CalcSectors(int64, int64*, int*);
/*** /***
*** recover-raw.c *** recover-raw.c
***/ ***/
#define CD_RAW_SECTOR_SIZE 2352 #define CD_RAW_SECTOR_SIZE 2352
#define CD_RAW_C2_SECTOR_SIZE (2352+294) /* main channel plus C2 vector */ #define CD_RAW_C2_SECTOR_SIZE (2352+294) /* main channel plus C2 vector */
int CheckEDC(const unsigned char*, bool); int CheckEDC(const unsigned char*, bool);
int CheckMSF(unsigned char*, int); int CheckMSF(unsigned char*, int);
int ValidateRawSector(unsigned char *frame, bool xaMode); int ValidateRawSector(unsigned char *frame, bool xaMode);
bool Init_LEC_Correct(void); bool Init_LEC_Correct(void);
#endif /* DVDISASTER_H */ #endif /* DVDISASTER_H */

View File

@ -6,6 +6,7 @@
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#include <cstdlib> #include <cstdlib>
#include <cstdio>
#include <memory> #include <memory>
typedef uint8_t uint8; typedef uint8_t uint8;

File diff suppressed because it is too large Load Diff

View File

@ -1,492 +1,492 @@
/******************************************************************************/ /******************************************************************************/
/* Mednafen - Multi-system Emulator */ /* Mednafen - Multi-system Emulator */
/******************************************************************************/ /******************************************************************************/
/* m68k.h - Motorola 68000 CPU Emulator /* m68k.h - Motorola 68000 CPU Emulator
** Copyright (C) 2015-2016 Mednafen Team ** Copyright (C) 2015-2016 Mednafen Team
** **
** This program is free software; you can redistribute it and/or ** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License ** modify it under the terms of the GNU General Public License
** as published by the Free Software Foundation; either version 2 ** as published by the Free Software Foundation; either version 2
** of the License, or (at your option) any later version. ** of the License, or (at your option) any later version.
** **
** This program is distributed in the hope that it will be useful, ** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of ** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details. ** GNU General Public License for more details.
** **
** You should have received a copy of the GNU General Public License ** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software Foundation, Inc., ** along with this program; if not, write to the Free Software Foundation, Inc.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
#ifndef __MDFN_M68K_H #ifndef __MDFN_M68K_H
#define __MDFN_M68K_H #define __MDFN_M68K_H
#include "ss.h" #include "../ss.h"
class M68K class M68K
{ {
public: public:
M68K(const bool rev_e = false) MDFN_COLD; M68K(const bool rev_e = false) MDFN_COLD;
~M68K() MDFN_COLD; ~M68K() MDFN_COLD;
void Run(int32 run_until_time); void Run(int32 run_until_time);
void Step(void); void Step(void);
void Reset(bool powering_up) MDFN_COLD; void Reset(bool powering_up) MDFN_COLD;
void SetIPL(uint8 ipl_new); void SetIPL(uint8 ipl_new);
void SetExtHalted(bool state); void SetExtHalted(bool state);
// //
// //
// //
// //
// //
// //
// //
// //
union union
{ {
uint32 DA[16]; uint32 DA[16];
struct struct
{ {
uint32 D[8]; uint32 D[8];
uint32 A[8]; uint32 A[8];
}; };
}; };
int32 timestamp; int32 timestamp;
uint32 PC; uint32 PC;
uint8 SRHB; uint8 SRHB;
uint8 IPL; uint8 IPL;
bool Flag_Z, Flag_N; bool Flag_Z, Flag_N;
bool Flag_X, Flag_C, Flag_V; bool Flag_X, Flag_C, Flag_V;
uint32 SP_Inactive; uint32 SP_Inactive;
uint32 XPending; uint32 XPending;
enum enum
{ {
XPENDING_MASK_INT = 0x0001, XPENDING_MASK_INT = 0x0001,
XPENDING_MASK_NMI = 0x0002, XPENDING_MASK_NMI = 0x0002,
XPENDING_MASK_RESET = 0x0010, XPENDING_MASK_RESET = 0x0010,
XPENDING_MASK_STOPPED = 0x0100, // via STOP instruction XPENDING_MASK_STOPPED = 0x0100, // via STOP instruction
XPENDING_MASK_EXTHALTED= 0x1000 XPENDING_MASK_EXTHALTED= 0x1000
}; };
const bool Revision_E; const bool Revision_E;
//private: //private:
void RecalcInt(void); void RecalcInt(void);
template<typename T> template<typename T>
T Read(uint32 addr); T Read(uint32 addr);
uint16 ReadOp(void); uint16 ReadOp(void);
template<typename T, bool long_dec = false> template<typename T, bool long_dec = false>
void Write(uint32 addr, const T val); void Write(uint32 addr, const T val);
template<typename T> template<typename T>
void Push(const T value); void Push(const T value);
template<typename T> template<typename T>
T Pull(void); T Pull(void);
enum AddressMode enum AddressMode
{ {
DATA_REG_DIR, DATA_REG_DIR,
ADDR_REG_DIR, ADDR_REG_DIR,
ADDR_REG_INDIR, ADDR_REG_INDIR,
ADDR_REG_INDIR_POST, ADDR_REG_INDIR_POST,
ADDR_REG_INDIR_PRE, ADDR_REG_INDIR_PRE,
ADDR_REG_INDIR_DISP, ADDR_REG_INDIR_DISP,
ADDR_REG_INDIR_INDX, ADDR_REG_INDIR_INDX,
ABS_SHORT, ABS_SHORT,
ABS_LONG, ABS_LONG,
PC_DISP, PC_DISP,
PC_INDEX, PC_INDEX,
IMMEDIATE IMMEDIATE
}; };
// //
// MOVE byte and word: instructions, 2 cycle penalty for source predecrement only // MOVE byte and word: instructions, 2 cycle penalty for source predecrement only
// 2 cycle penalty for (d8, An, Xn) for both source and dest ams // 2 cycle penalty for (d8, An, Xn) for both source and dest ams
// 2 cycle penalty for (d8, PC, Xn) for dest am // 2 cycle penalty for (d8, PC, Xn) for dest am
// //
// //
// Careful on declaration order of HAM objects(needs to be source then dest). // Careful on declaration order of HAM objects(needs to be source then dest).
// //
template<typename T, M68K::AddressMode am> template<typename T, M68K::AddressMode am>
struct HAM; struct HAM;
void SetC(bool val); void SetC(bool val);
void SetV(bool val); void SetV(bool val);
void SetZ(bool val); void SetZ(bool val);
void SetN(bool val); void SetN(bool val);
void SetX(bool val); void SetX(bool val);
bool GetC(void); bool GetC(void);
bool GetV(void); bool GetV(void);
bool GetZ(void); bool GetZ(void);
bool GetN(void); bool GetN(void);
bool GetX(void); bool GetX(void);
void SetCX(bool val); void SetCX(bool val);
template<typename T, bool Z_OnlyClear = false> template<typename T, bool Z_OnlyClear = false>
void CalcZN(const T val); void CalcZN(const T val);
template<typename T> template<typename T>
void CalcCX(const uint64& val); void CalcCX(const uint64& val);
uint8 GetCCR(void); uint8 GetCCR(void);
void SetCCR(uint8 val); void SetCCR(uint8 val);
uint16 GetSR(void); uint16 GetSR(void);
void SetSR(uint16 val); void SetSR(uint16 val);
uint8 GetIMask(void); uint8 GetIMask(void);
void SetIMask(uint8 val); void SetIMask(uint8 val);
bool GetSVisor(void); bool GetSVisor(void);
void SetSVisor(bool value); void SetSVisor(bool value);
bool GetTrace(void); bool GetTrace(void);
void SetTrace(bool value); void SetTrace(bool value);
// //
// //
// //
enum enum
{ {
VECNUM_RESET_SSP = 0, VECNUM_RESET_SSP = 0,
VECNUM_RESET_PC = 1, VECNUM_RESET_PC = 1,
VECNUM_BUS_ERROR = 2, VECNUM_BUS_ERROR = 2,
VECNUM_ADDRESS_ERROR = 3, VECNUM_ADDRESS_ERROR = 3,
VECNUM_ILLEGAL = 4, VECNUM_ILLEGAL = 4,
VECNUM_ZERO_DIVIDE = 5, VECNUM_ZERO_DIVIDE = 5,
VECNUM_CHK = 6, VECNUM_CHK = 6,
VECNUM_TRAPV = 7, VECNUM_TRAPV = 7,
VECNUM_PRIVILEGE = 8, VECNUM_PRIVILEGE = 8,
VECNUM_TRACE = 9, VECNUM_TRACE = 9,
VECNUM_LINEA = 10, VECNUM_LINEA = 10,
VECNUM_LINEF = 11, VECNUM_LINEF = 11,
VECNUM_UNINI_INT = 15, VECNUM_UNINI_INT = 15,
VECNUM_SPURIOUS_INT = 24, VECNUM_SPURIOUS_INT = 24,
VECNUM_INT_BASE = 24, VECNUM_INT_BASE = 24,
VECNUM_TRAP_BASE = 32 VECNUM_TRAP_BASE = 32
}; };
enum enum
{ {
EXCEPTION_RESET = 0, EXCEPTION_RESET = 0,
EXCEPTION_BUS_ERROR, EXCEPTION_BUS_ERROR,
EXCEPTION_ADDRESS_ERROR, EXCEPTION_ADDRESS_ERROR,
EXCEPTION_ILLEGAL, EXCEPTION_ILLEGAL,
EXCEPTION_ZERO_DIVIDE, EXCEPTION_ZERO_DIVIDE,
EXCEPTION_CHK, EXCEPTION_CHK,
EXCEPTION_TRAPV, EXCEPTION_TRAPV,
EXCEPTION_PRIVILEGE, EXCEPTION_PRIVILEGE,
EXCEPTION_TRACE, EXCEPTION_TRACE,
EXCEPTION_INT, EXCEPTION_INT,
EXCEPTION_TRAP EXCEPTION_TRAP
}; };
void NO_INLINE Exception(unsigned which, unsigned vecnum); void NO_INLINE Exception(unsigned which, unsigned vecnum);
template<typename T, typename DT, M68K::AddressMode SAM, M68K::AddressMode DAM> template<typename T, typename DT, M68K::AddressMode SAM, M68K::AddressMode DAM>
void ADD(HAM<T, SAM> &src, HAM<DT, DAM> &dst); void ADD(HAM<T, SAM> &src, HAM<DT, DAM> &dst);
template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM> template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
void ADDX(HAM<T, SAM> &src, HAM<T, DAM> &dst); void ADDX(HAM<T, SAM> &src, HAM<T, DAM> &dst);
template<bool X_form, typename T, typename DT, M68K::AddressMode SAM, M68K::AddressMode DAM> template<bool X_form, typename T, typename DT, M68K::AddressMode SAM, M68K::AddressMode DAM>
DT Subtract(HAM<T, SAM> &src, HAM<DT, DAM> &dst); DT Subtract(HAM<T, SAM> &src, HAM<DT, DAM> &dst);
template<typename T, typename DT, M68K::AddressMode SAM, M68K::AddressMode DAM> template<typename T, typename DT, M68K::AddressMode SAM, M68K::AddressMode DAM>
void SUB(HAM<T, SAM> &src, HAM<DT, DAM> &dst); void SUB(HAM<T, SAM> &src, HAM<DT, DAM> &dst);
template<typename T, typename DT, M68K::AddressMode SAM, M68K::AddressMode DAM> template<typename T, typename DT, M68K::AddressMode SAM, M68K::AddressMode DAM>
void SUBX(HAM<T, SAM> &src, HAM<DT, DAM> &dst); void SUBX(HAM<T, SAM> &src, HAM<DT, DAM> &dst);
template<typename DT, M68K::AddressMode DAM> template<typename DT, M68K::AddressMode DAM>
void NEG(HAM<DT, DAM> &dst); void NEG(HAM<DT, DAM> &dst);
template<typename DT, M68K::AddressMode DAM> template<typename DT, M68K::AddressMode DAM>
void NEGX(HAM<DT, DAM> &dst); void NEGX(HAM<DT, DAM> &dst);
template<typename T, typename DT, M68K::AddressMode SAM, M68K::AddressMode DAM> template<typename T, typename DT, M68K::AddressMode SAM, M68K::AddressMode DAM>
void CMP(HAM<T, SAM> &src, HAM<DT, DAM> &dst); void CMP(HAM<T, SAM> &src, HAM<DT, DAM> &dst);
template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM> template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
void CHK(HAM<T, SAM> &src, HAM<T, DAM> &dst); void CHK(HAM<T, SAM> &src, HAM<T, DAM> &dst);
template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM> template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
void OR(HAM<T, SAM> &src, HAM<T, DAM> &dst); void OR(HAM<T, SAM> &src, HAM<T, DAM> &dst);
template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM> template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
void EOR(HAM<T, SAM> &src, HAM<T, DAM> &dst); void EOR(HAM<T, SAM> &src, HAM<T, DAM> &dst);
template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM> template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
void AND(HAM<T, SAM> &src, HAM<T, DAM> &dst); void AND(HAM<T, SAM> &src, HAM<T, DAM> &dst);
void ORI_CCR(void); void ORI_CCR(void);
void ORI_SR(void); void ORI_SR(void);
void ANDI_CCR(void); void ANDI_CCR(void);
void ANDI_SR(void); void ANDI_SR(void);
void EORI_CCR(void); void EORI_CCR(void);
void EORI_SR(void); void EORI_SR(void);
template<typename T, M68K::AddressMode SAM> template<typename T, M68K::AddressMode SAM>
void MULU(HAM<T, SAM> &src, const unsigned dr); void MULU(HAM<T, SAM> &src, const unsigned dr);
template<typename T, M68K::AddressMode SAM> template<typename T, M68K::AddressMode SAM>
void MULS(HAM<T, SAM> &src, const unsigned dr); void MULS(HAM<T, SAM> &src, const unsigned dr);
template<bool sdiv> template<bool sdiv>
void Divide(uint16 divisor, const unsigned dr); void Divide(uint16 divisor, const unsigned dr);
template<typename T, M68K::AddressMode SAM> template<typename T, M68K::AddressMode SAM>
void DIVU(HAM<T, SAM> &src, const unsigned dr); void DIVU(HAM<T, SAM> &src, const unsigned dr);
template<typename T, M68K::AddressMode SAM> template<typename T, M68K::AddressMode SAM>
void DIVS(HAM<T, SAM> &src, const unsigned dr); void DIVS(HAM<T, SAM> &src, const unsigned dr);
template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM> template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
void ABCD(HAM<T, SAM> &src, HAM<T, DAM> &dst); void ABCD(HAM<T, SAM> &src, HAM<T, DAM> &dst);
uint8 DecimalSubtractX(const uint8 src_data, const uint8 dst_data); uint8 DecimalSubtractX(const uint8 src_data, const uint8 dst_data);
template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM> template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
void SBCD(HAM<T, SAM> &src, HAM<T, DAM> &dst); void SBCD(HAM<T, SAM> &src, HAM<T, DAM> &dst);
template<typename T, M68K::AddressMode DAM> template<typename T, M68K::AddressMode DAM>
void NBCD(HAM<T, DAM> &dst); void NBCD(HAM<T, DAM> &dst);
template<typename T, bool reg_to_mem> template<typename T, bool reg_to_mem>
void MOVEP(const unsigned ar, const unsigned dr); void MOVEP(const unsigned ar, const unsigned dr);
template<typename T, M68K::AddressMode TAM> template<typename T, M68K::AddressMode TAM>
void BTST(HAM<T, TAM> &targ, unsigned wb); void BTST(HAM<T, TAM> &targ, unsigned wb);
template<typename T, M68K::AddressMode TAM> template<typename T, M68K::AddressMode TAM>
void BCHG(HAM<T, TAM> &targ, unsigned wb); void BCHG(HAM<T, TAM> &targ, unsigned wb);
template<typename T, M68K::AddressMode TAM> template<typename T, M68K::AddressMode TAM>
void BCLR(HAM<T, TAM> &targ, unsigned wb); void BCLR(HAM<T, TAM> &targ, unsigned wb);
template<typename T, M68K::AddressMode TAM> template<typename T, M68K::AddressMode TAM>
void BSET(HAM<T, TAM> &targ, unsigned wb); void BSET(HAM<T, TAM> &targ, unsigned wb);
template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM> template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
void MOVE(HAM<T, SAM> &src, HAM<T, DAM> &dst); void MOVE(HAM<T, SAM> &src, HAM<T, DAM> &dst);
template<typename T, M68K::AddressMode SAM> template<typename T, M68K::AddressMode SAM>
void MOVEA(HAM<T, SAM> &src, const unsigned ar); void MOVEA(HAM<T, SAM> &src, const unsigned ar);
template<bool pseudo_predec, typename T, M68K::AddressMode DAM> template<bool pseudo_predec, typename T, M68K::AddressMode DAM>
void MOVEM_to_MEM(const uint16 reglist, HAM<T, DAM> &dst); void MOVEM_to_MEM(const uint16 reglist, HAM<T, DAM> &dst);
template<bool pseudo_postinc, typename T, M68K::AddressMode SAM> template<bool pseudo_postinc, typename T, M68K::AddressMode SAM>
void MOVEM_to_REGS(HAM<T, SAM> &src, const uint16 reglist); void MOVEM_to_REGS(HAM<T, SAM> &src, const uint16 reglist);
template<typename T, M68K::AddressMode TAM, bool Arithmetic, bool ShiftLeft> template<typename T, M68K::AddressMode TAM, bool Arithmetic, bool ShiftLeft>
void ShiftBase(HAM<T, TAM> &targ, unsigned count); void ShiftBase(HAM<T, TAM> &targ, unsigned count);
template<typename T, M68K::AddressMode TAM> template<typename T, M68K::AddressMode TAM>
void ASL(HAM<T, TAM> &targ, unsigned count); void ASL(HAM<T, TAM> &targ, unsigned count);
template<typename T, M68K::AddressMode TAM> template<typename T, M68K::AddressMode TAM>
void ASR(HAM<T, TAM> &targ, unsigned count); void ASR(HAM<T, TAM> &targ, unsigned count);
template<typename T, M68K::AddressMode TAM> template<typename T, M68K::AddressMode TAM>
void LSL(HAM<T, TAM> &targ, unsigned count); void LSL(HAM<T, TAM> &targ, unsigned count);
template<typename T, M68K::AddressMode TAM> template<typename T, M68K::AddressMode TAM>
void LSR(HAM<T, TAM> &targ, unsigned count); void LSR(HAM<T, TAM> &targ, unsigned count);
template<typename T, M68K::AddressMode TAM, bool X_Form, bool ShiftLeft> template<typename T, M68K::AddressMode TAM, bool X_Form, bool ShiftLeft>
void RotateBase(HAM<T, TAM> &targ, unsigned count); void RotateBase(HAM<T, TAM> &targ, unsigned count);
template<typename T, M68K::AddressMode TAM> template<typename T, M68K::AddressMode TAM>
void ROL(HAM<T, TAM> &targ, unsigned count); void ROL(HAM<T, TAM> &targ, unsigned count);
template<typename T, M68K::AddressMode TAM> template<typename T, M68K::AddressMode TAM>
void ROR(HAM<T, TAM> &targ, unsigned count); void ROR(HAM<T, TAM> &targ, unsigned count);
template<typename T, M68K::AddressMode TAM> template<typename T, M68K::AddressMode TAM>
void ROXL(HAM<T, TAM> &targ, unsigned count); void ROXL(HAM<T, TAM> &targ, unsigned count);
template<typename T, M68K::AddressMode TAM> template<typename T, M68K::AddressMode TAM>
void ROXR(HAM<T, TAM> &targ, unsigned count); void ROXR(HAM<T, TAM> &targ, unsigned count);
#if 0 #if 0
static uint8 TAS_Callback(uint8 data) static uint8 TAS_Callback(uint8 data)
{ {
CalcZN<uint8>(data); CalcZN<uint8>(data);
SetC(false); SetC(false);
SetV(false); SetV(false);
data |= 0x80; data |= 0x80;
return data; return data;
} }
#endif #endif
template<typename T, M68K::AddressMode DAM> template<typename T, M68K::AddressMode DAM>
void TAS(HAM<T, DAM> &dst); void TAS(HAM<T, DAM> &dst);
template<typename T, M68K::AddressMode DAM> template<typename T, M68K::AddressMode DAM>
void TST(HAM<T, DAM> &dst); void TST(HAM<T, DAM> &dst);
template<typename T, M68K::AddressMode DAM> template<typename T, M68K::AddressMode DAM>
void CLR(HAM<T, DAM> &dst); void CLR(HAM<T, DAM> &dst);
template<typename T, M68K::AddressMode DAM> template<typename T, M68K::AddressMode DAM>
void NOT(HAM<T, DAM> &dst); void NOT(HAM<T, DAM> &dst);
template<typename T, M68K::AddressMode DAM> template<typename T, M68K::AddressMode DAM>
void EXT(HAM<T, DAM> &dst); void EXT(HAM<T, DAM> &dst);
void SWAP(const unsigned dr); void SWAP(const unsigned dr);
void EXG(uint32* a, uint32* b); void EXG(uint32* a, uint32* b);
template<unsigned cc> template<unsigned cc>
bool TestCond(void); bool TestCond(void);
template<unsigned cc> template<unsigned cc>
void Bxx(uint32 disp); void Bxx(uint32 disp);
template<unsigned cc> template<unsigned cc>
void DBcc(const unsigned dr); void DBcc(const unsigned dr);
template<unsigned cc, typename T, M68K::AddressMode DAM> template<unsigned cc, typename T, M68K::AddressMode DAM>
void Scc(HAM<T, DAM> &dst); void Scc(HAM<T, DAM> &dst);
template<typename T, M68K::AddressMode TAM> template<typename T, M68K::AddressMode TAM>
void JSR(HAM<T, TAM> &targ); void JSR(HAM<T, TAM> &targ);
template<typename T, M68K::AddressMode TAM> template<typename T, M68K::AddressMode TAM>
void JMP(HAM<T, TAM> &targ); void JMP(HAM<T, TAM> &targ);
template <typename T, M68K::AddressMode DAM> template <typename T, M68K::AddressMode DAM>
void MOVE_from_SR(HAM<T, DAM> &dst); void MOVE_from_SR(HAM<T, DAM> &dst);
template<typename T, M68K::AddressMode SAM> template<typename T, M68K::AddressMode SAM>
void MOVE_to_CCR(HAM<T, SAM> &src); void MOVE_to_CCR(HAM<T, SAM> &src);
template<typename T, M68K::AddressMode SAM> template<typename T, M68K::AddressMode SAM>
void MOVE_to_SR(HAM<T, SAM> &src); void MOVE_to_SR(HAM<T, SAM> &src);
template<bool direction> template<bool direction>
void MOVE_USP(const unsigned ar); void MOVE_USP(const unsigned ar);
template<typename T, M68K::AddressMode SAM> template<typename T, M68K::AddressMode SAM>
void LEA(HAM<T, SAM> &src, const unsigned ar); void LEA(HAM<T, SAM> &src, const unsigned ar);
template<typename T, M68K::AddressMode SAM> template<typename T, M68K::AddressMode SAM>
void PEA(HAM<T, SAM> &src); void PEA(HAM<T, SAM> &src);
void UNLK(const unsigned ar); void UNLK(const unsigned ar);
void LINK(const unsigned ar); void LINK(const unsigned ar);
void RTE(void); void RTE(void);
void RTR(void); void RTR(void);
void RTS(void); void RTS(void);
void TRAP(const unsigned vf); void TRAP(const unsigned vf);
void TRAPV(void); void TRAPV(void);
void ILLEGAL(const uint16 instr); void ILLEGAL(const uint16 instr);
void LINEA(void); void LINEA(void);
void LINEF(void); void LINEF(void);
void NOP(void); void NOP(void);
void RESET(void); void RESET(void);
void STOP(void); void STOP(void);
bool CheckPrivilege(void); bool CheckPrivilege(void);
void InternalStep(void); void InternalStep(void);
// //
// //
// //
// //
// //
// These externally-provided functions should add >= 4 to M68K::timestamp per call: // These externally-provided functions should add >= 4 to M68K::timestamp per call:
enum { BUS_INT_ACK_AUTO = -1 }; enum { BUS_INT_ACK_AUTO = -1 };
uint16 (MDFN_FASTCALL *BusReadInstr)(uint32 A); uint16 (MDFN_FASTCALL *BusReadInstr)(uint32 A);
uint8 (MDFN_FASTCALL *BusRead8)(uint32 A); uint8 (MDFN_FASTCALL *BusRead8)(uint32 A);
uint16 (MDFN_FASTCALL *BusRead16)(uint32 A); uint16 (MDFN_FASTCALL *BusRead16)(uint32 A);
void (MDFN_FASTCALL *BusWrite8)(uint32 A, uint8 V); void (MDFN_FASTCALL *BusWrite8)(uint32 A, uint8 V);
void (MDFN_FASTCALL *BusWrite16)(uint32 A, uint16 V); void (MDFN_FASTCALL *BusWrite16)(uint32 A, uint16 V);
// //
// //
void (MDFN_FASTCALL *BusRMW)(uint32 A, uint8 (MDFN_FASTCALL *cb)(M68K*, uint8)); void (MDFN_FASTCALL *BusRMW)(uint32 A, uint8 (MDFN_FASTCALL *cb)(M68K*, uint8));
unsigned (MDFN_FASTCALL *BusIntAck)(uint8 level); unsigned (MDFN_FASTCALL *BusIntAck)(uint8 level);
void (MDFN_FASTCALL *BusRESET)(bool state); // Optional; Calling Reset(false) from this callback *is* permitted. void (MDFN_FASTCALL *BusRESET)(bool state); // Optional; Calling Reset(false) from this callback *is* permitted.
// //
// //
// //
void (*DBG_Warning)(const char* format, ...) noexcept MDFN_FORMATSTR(gnu_printf, 1, 2); void (*DBG_Warning)(const char* format, ...) noexcept MDFN_FORMATSTR(gnu_printf, 1, 2);
void (*DBG_Verbose)(const char* format, ...) noexcept MDFN_FORMATSTR(gnu_printf, 1, 2); void (*DBG_Verbose)(const char* format, ...) noexcept MDFN_FORMATSTR(gnu_printf, 1, 2);
// //
// //
// //
public: public:
enum enum
{ {
GSREG_D0 = 0, GSREG_D0 = 0,
GSREG_D1, GSREG_D1,
GSREG_D2, GSREG_D2,
GSREG_D3, GSREG_D3,
GSREG_D4, GSREG_D4,
GSREG_D5, GSREG_D5,
GSREG_D6, GSREG_D6,
GSREG_D7, GSREG_D7,
GSREG_A0 = 8, GSREG_A0 = 8,
GSREG_A1, GSREG_A1,
GSREG_A2, GSREG_A2,
GSREG_A3, GSREG_A3,
GSREG_A4, GSREG_A4,
GSREG_A5, GSREG_A5,
GSREG_A6, GSREG_A6,
GSREG_A7, GSREG_A7,
GSREG_PC = 16, GSREG_PC = 16,
GSREG_SR, GSREG_SR,
GSREG_SSP, GSREG_SSP,
GSREG_USP GSREG_USP
}; };
uint32 GetRegister(unsigned which, char* special = nullptr, const uint32 special_len = 0); uint32 GetRegister(unsigned which, char* special = nullptr, const uint32 special_len = 0);
void SetRegister(unsigned which, uint32 value); void SetRegister(unsigned which, uint32 value);
INLINE void DupeState(const M68K* const src) INLINE void DupeState(const M68K* const src)
{ {
memcpy(DA, src->DA, 16 * sizeof(uint32)); memcpy(DA, src->DA, 16 * sizeof(uint32));
timestamp = src->timestamp; timestamp = src->timestamp;
PC = src->PC; PC = src->PC;
SRHB = src->SRHB; SRHB = src->SRHB;
IPL = src->IPL; IPL = src->IPL;
Flag_Z = src->Flag_Z; Flag_Z = src->Flag_Z;
Flag_N = src->Flag_N; Flag_N = src->Flag_N;
Flag_X = src->Flag_X; Flag_X = src->Flag_X;
Flag_C = src->Flag_C; Flag_C = src->Flag_C;
Flag_V = src->Flag_V; Flag_V = src->Flag_V;
SP_Inactive = src->SP_Inactive; SP_Inactive = src->SP_Inactive;
XPending = src->XPending; XPending = src->XPending;
} }
}; };
#endif #endif

View File

@ -1,235 +1,236 @@
/******************************************************************************/ /******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */ /* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/ /******************************************************************************/
/* scu_dsp_common.inc: /* scu_dsp_common.inc:
** Copyright (C) 2015-2016 Mednafen Team ** Copyright (C) 2015-2016 Mednafen Team
** **
** This program is free software; you can redistribute it and/or ** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License ** modify it under the terms of the GNU General Public License
** as published by the Free Software Foundation; either version 2 ** as published by the Free Software Foundation; either version 2
** of the License, or (at your option) any later version. ** of the License, or (at your option) any later version.
** **
** This program is distributed in the hope that it will be useful, ** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of ** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details. ** GNU General Public License for more details.
** **
** You should have received a copy of the GNU General Public License ** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software Foundation, Inc., ** along with this program; if not, write to the Free Software Foundation, Inc.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
// base ptr must match the waterbox base load location! // base ptr must match the waterbox base load location!
#if (defined(__x86_64__) && defined(__code_model_small__) && !defined(__PIC__) && !defined(__pic__)) || SIZEOF_VOID_P <= 4 // TODO: Since we're not relocating, can't we use DSP_Init?
#define DSP_INSTR_BASE_UIPT 0x36d00000000ul #if (defined(__x86_64__) && defined(__code_model_small__) && !defined(__PIC__) && !defined(__pic__)) || SIZEOF_VOID_P <= 4
#define DSP_INSTR_RECOVER_TCAST uint32 #define DSP_INSTR_BASE_UIPT 0x36f00000000ul
#else #define DSP_INSTR_RECOVER_TCAST uint32
#define DSP_INSTR_BASE_UIPT ((uintptr_t)DSP_Init) #else
#define DSP_INSTR_RECOVER_TCAST int32 #define DSP_INSTR_BASE_UIPT ((uintptr_t)DSP_Init)
#endif #define DSP_INSTR_RECOVER_TCAST int32
#endif
// See loop in "SCU_UpdateDSP()" in scu.inc, and END/ENDI handling in scu_dsp_misc.cpp
enum { DSP_EndCCSubVal = 1000000 }; // See loop in "SCU_UpdateDSP()" in scu.inc, and END/ENDI handling in scu_dsp_misc.cpp
enum { DSP_EndCCSubVal = 1000000 };
void DSP_Init(void);
void DSP_Init(void);
struct DSP_ITS;
struct DSP_ITS;
union DSPR48
{ union DSPR48
#ifdef MSB_FIRST {
struct #ifdef MSB_FIRST
{ struct
uint16 dummy; {
uint16 H; uint16 dummy;
uint32 L; uint16 H;
}; uint32 L;
#else };
struct #else
{ struct
uint32 L; {
uint16 H; uint32 L;
uint16 dummy; uint16 H;
}; uint16 dummy;
#endif };
uint64 T; // Upper 16 bits may be non-zero "garbage", so don't assume they're zero in code that reads from this variable. #endif
}; uint64 T; // Upper 16 bits may be non-zero "garbage", so don't assume they're zero in code that reads from this variable.
};
struct DSPS
{ struct DSPS
sscpu_timestamp_t LastTS; {
int32 CycleCounter; sscpu_timestamp_t LastTS;
int32 T0_Until; int32 CycleCounter;
// int32 T0_Until;
enum //
{ enum
// No execute = 0x00000000 <= 0 {
// Paused + No execute = 0x80000000 <= 0 // No execute = 0x00000000 <= 0
// Paused + Execute = 0x80000001 <= 0 // Paused + No execute = 0x80000000 <= 0
// Execute = 0x00000001 > 0 // Paused + Execute = 0x80000001 <= 0
STATE_MASK_PAUSE = 0x80000000, // Execute = 0x00000001 > 0
STATE_MASK_EXECUTE = 0x00000001, STATE_MASK_PAUSE = 0x80000000,
}; STATE_MASK_EXECUTE = 0x00000001,
int32 State; };
int32 State;
INLINE bool IsRunning(void) // returns true if not stopped and not paused.
{ INLINE bool IsRunning(void) // returns true if not stopped and not paused.
return State > 0; {
} return State > 0;
}
uint64 NextInstr;
uint64 NextInstr;
uint8 PC;
uint8 RA; uint8 PC;
uint8 RA;
bool FlagZ;
bool FlagS; bool FlagZ;
bool FlagV; bool FlagS;
bool FlagC; bool FlagV;
bool FlagC;
bool FlagEnd;
bool FlagEnd;
uint8 TOP;
uint16 LOP; // 12 bits uint8 TOP;
uint16 LOP; // 12 bits
DSPR48 AC;
DSPR48 P; DSPR48 AC;
DSPR48 P;
union
{ union
uint8 CT[4]; // 6 bits(each) {
uint32 CT32; uint8 CT[4]; // 6 bits(each)
}; uint32 CT32;
};
uint32 RX;
uint32 RY; uint32 RX;
uint32 RY;
uint32 RAO;
uint32 WAO; uint32 RAO;
uint32 WAO;
uint32 DataRAM[4][64];
uint32 DataRAM[4][64];
uint64 ProgRAM[256]; // Upper 32 bits = actual raw instruction, lower 32 bits = horrible emulator handler pointer madness
}; uint64 ProgRAM[256]; // Upper 32 bits = actual raw instruction, lower 32 bits = horrible emulator handler pointer madness
};
// ALU Op: bits 26-29 - *16
// X Op: bits 23-25 - * 8 // ALU Op: bits 26-29 - *16
// Y Op: bits 17-19 - * 8 // X Op: bits 23-25 - * 8
// D1 Op: bits 12-13 - * 4 // Y Op: bits 17-19 - * 8
extern void (*const DSP_GenFuncTable[2][16][8][8][4])(void); // D1 Op: bits 12-13 - * 4
extern void (*const DSP_GenFuncTable[2][16][8][8][4])(void);
// Hold/Format/Direction: bits 12-14
// Hold: bit 14 // Hold/Format/Direction: bits 12-14
// Format: bit 13 // Hold: bit 14
// Direction: bit 12 // Format: bit 13
// RAM: bits 8-10 // Direction: bit 12
// // RAM: bits 8-10
extern void (*const DSP_DMAFuncTable[2][8][8])(void); //
extern void (*const DSP_DMAFuncTable[2][8][8])(void);
//
// Dest: bits 26-29 //
// Condition: bits 19-25 // Dest: bits 26-29
// // Condition: bits 19-25
extern void (*const DSP_MVIFuncTable[2][16][128])(void); //
extern void (*const DSP_MVIFuncTable[2][16][128])(void);
//
// Condition: bits 19-25 //
// // Condition: bits 19-25
extern void (*const DSP_JMPFuncTable[2][128])(void); //
extern void (*const DSP_JMPFuncTable[2][128])(void);
//
// LPS, BTM, END, ENDI(bits 29-31 = 0x7) //
// bits 27-28 // LPS, BTM, END, ENDI(bits 29-31 = 0x7)
// // bits 27-28
extern void (*const DSP_MiscFuncTable[2][4])(void); //
extern void (*const DSP_MiscFuncTable[2][4])(void);
extern DSPS DSP;
extern DSPS DSP;
template<bool looped = false>
static INLINE uint64 DSP_DecodeInstruction(const uint32 instr) template<bool looped = false>
{ static INLINE uint64 DSP_DecodeInstruction(const uint32 instr)
void (*aal)(void); {
void (*aal)(void);
switch((instr >> 28) & 0xF)
{ switch((instr >> 28) & 0xF)
default: {
aal = DSP_GenFuncTable[looped][0][0][0][0]; default:
break; aal = DSP_GenFuncTable[looped][0][0][0][0];
break;
case 0x0:
case 0x1: case 0x0:
case 0x2: case 0x1:
case 0x3: case 0x2:
aal = DSP_GenFuncTable[looped][(instr >> 26) & 0xF][(instr >> 23) & 0x7][(instr >> 17) & 0x7][(instr >> 12) & 0x3]; case 0x3:
break; aal = DSP_GenFuncTable[looped][(instr >> 26) & 0xF][(instr >> 23) & 0x7][(instr >> 17) & 0x7][(instr >> 12) & 0x3];
break;
case 0x8:
case 0x9: case 0x8:
case 0xA: case 0x9:
case 0xB: case 0xA:
aal = DSP_MVIFuncTable[looped][(instr >> 26) & 0xF][(instr >> 19) & 0x7F]; case 0xB:
break; aal = DSP_MVIFuncTable[looped][(instr >> 26) & 0xF][(instr >> 19) & 0x7F];
break;
case 0xC:
aal = DSP_DMAFuncTable[looped][(instr >> 12) & 0x7][(instr >> 8) & 0x7]; case 0xC:
break; aal = DSP_DMAFuncTable[looped][(instr >> 12) & 0x7][(instr >> 8) & 0x7];
break;
case 0xD:
aal = DSP_JMPFuncTable[looped][(instr >> 19) & 0x7F]; case 0xD:
break; aal = DSP_JMPFuncTable[looped][(instr >> 19) & 0x7F];
break;
case 0xE:
case 0xF: case 0xE:
aal = DSP_MiscFuncTable[looped][(instr >> 27) & 0x3]; case 0xF:
break; aal = DSP_MiscFuncTable[looped][(instr >> 27) & 0x3];
} break;
}
return ((uint64)instr << 32) | (uint32)((uintptr_t)aal - DSP_INSTR_BASE_UIPT);
} return ((uint64)instr << 32) | (uint32)((uintptr_t)aal - DSP_INSTR_BASE_UIPT);
}
template<bool looped>
static INLINE uint32 DSP_InstrPre(void) template<bool looped>
{ static INLINE uint32 DSP_InstrPre(void)
const uint32 instr = DSP.NextInstr >> 32; {
const uint32 instr = DSP.NextInstr >> 32;
if(!looped || !DSP.LOP)
{ if(!looped || !DSP.LOP)
DSP.NextInstr = DSP.ProgRAM[DSP.PC]; {
DSP.PC++; DSP.NextInstr = DSP.ProgRAM[DSP.PC];
} DSP.PC++;
}
if(looped)
DSP.LOP -= (bool)DSP.LOP; if(looped)
DSP.LOP -= (bool)DSP.LOP;
return instr;
} return instr;
}
template<unsigned cond>
static INLINE bool DSP_TestCond(void) template<unsigned cond>
{ static INLINE bool DSP_TestCond(void)
if(!(cond & 0x40)) {
return true; if(!(cond & 0x40))
// return true;
// //
// //
bool ret = false; //
bool ret = false;
if(cond & 0x1)
ret |= DSP.FlagZ; if(cond & 0x1)
ret |= DSP.FlagZ;
if(cond & 0x2)
ret |= DSP.FlagS; if(cond & 0x2)
ret |= DSP.FlagS;
if(cond & 0x4)
ret |= DSP.FlagC; if(cond & 0x4)
ret |= DSP.FlagC;
if(cond & 0x8)
ret |= (DSP.T0_Until < DSP.CycleCounter); if(cond & 0x8)
ret |= (DSP.T0_Until < DSP.CycleCounter);
//if(cond & 0x10) // ?
//if(cond & 0x10) // ?
return ret == (bool)(cond & 0x20);
} return ret == (bool)(cond & 0x20);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,45 +1,11 @@
CC = x86_64-nt64-midipix-g++ CCFLAGS := \
-Wall -Werror=int-to-pointer-cast \
CCFLAGS:= -I. -I../emulibc \
-Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=implicit-function-declaration \
-Wno-reorder \ -Wno-reorder \
-std=c++0x -fomit-frame-pointer -fvisibility=hidden -fno-exceptions -fno-rtti \ -std=c++0x -fomit-frame-pointer \
-DNOGDB \ -DNOGDB
-O3 -flto
TARGET = uzem.wbx TARGET := uzem.wbx
LDFLAGS = -Wl,--dynamicbase,--export-all-symbols SRCS = $(shell find $(ROOT_DIR) -type f -name '*.cpp')
ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) include ../common.mak
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))

View File

@ -453,8 +453,8 @@ struct avr8
memset(io, 0, sizeof(io)); memset(io, 0, sizeof(io));
memset(sram, 0, sizeof(sram)); memset(sram, 0, sizeof(sram));
memset(eeprom, 0, sizeof(eeprom)); memset(eeprom, 0, sizeof(eeprom));
memset(progmem, 0, progSize / 2); memset(progmem, 0, progSize / 2 * sizeof(*progmem));
memset(progmemDecoded, 0, progSize / 2); memset(progmemDecoded, 0, progSize / 2 * sizeof(*progmemDecoded));
} }
/*Core*/ /*Core*/

View File

@ -1,44 +1,10 @@
CC = x86_64-nt64-midipix-g++ CCFLAGS:= -I. \
-Wall -Werror=int-to-pointer-cast \
CCFLAGS:= -I. -I../emulibc \ -std=c++0x -fomit-frame-pointer -fno-exceptions -fno-rtti \
-Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=implicit-function-declaration \ -DLSB_FIRST
-std=c++0x -fomit-frame-pointer -fvisibility=hidden -fno-exceptions -fno-rtti \
-DLSB_FIRST \ TARGET = vb.wbx
-O3 -flto
SRCS = $(shell find $(ROOT_DIR) -type f -name '*.cpp')
TARGET = vb.wbx
include ../common.mak
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))