diff --git a/BizHawk.Client.Common/RomLoader.cs b/BizHawk.Client.Common/RomLoader.cs
index a5e9c7edbc..f8454a0dc5 100644
--- a/BizHawk.Client.Common/RomLoader.cs
+++ b/BizHawk.Client.Common/RomLoader.cs
@@ -259,8 +259,7 @@ namespace BizHawk.Client.Common
nextEmulator = new PSP(nextComm, file.Name);
break;
case "PSX":
- nextEmulator = new Octoshock(nextComm);
- (nextEmulator as Octoshock).LoadCuePath(file.CanonicalFullPath);
+ nextEmulator = new Octoshock(nextComm, disc);
nextEmulator.CoreComm.RomStatusDetails = "PSX etc.";
break;
case "PCE":
diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
index f706f0fb94..e2f41d8526 100644
--- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
+++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
@@ -533,8 +533,8 @@
-
+
diff --git a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/LibMednahawkDll.cs b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/LibMednahawkDll.cs
deleted file mode 100644
index 9342799021..0000000000
--- a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/LibMednahawkDll.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-public unsafe static class LibMednahawkDll
-{
- public enum eProp : int
- {
- GetPtr_FramebufferPointer,
- GetPtr_FramebufferPitchPixels,
- GetPtr_FramebufferWidth,
- GetPtr_FramebufferHeight,
- SetPtr_FopenCallback,
- SetPtr_FcloseCallback,
- SetPtr_FopCallback
- }
-
- public enum FOP: int
- {
- FOP_fread,
- FOP_fwrite,
- FOP_fflush,
- FOP_fseeko,
- FOP_ftello,
- FOP_ferror,
- FOP_clearerr,
- FOP_size
- };
-
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate IntPtr t_FopenCallback(string fname, string mode);
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int t_FcloseCallback(IntPtr fp);
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate long t_FopCallback(int op, IntPtr ptr, long a, long b, IntPtr fp);
-
- [DllImport("libmednahawk.dll", CallingConvention = CallingConvention.Cdecl)]
- public static extern IntPtr dll_GetPropPtr(eProp prop);
-
- [DllImport("libmednahawk.dll", CallingConvention = CallingConvention.Cdecl)]
- public static extern void dll_SetPropPtr(eProp prop, IntPtr val);
-
- [DllImport("libmednahawk.dll", CallingConvention = CallingConvention.Cdecl)]
- [return: MarshalAs(UnmanagedType.U1)]
- public static extern bool dll_Initialize();
-
- [DllImport("libmednahawk.dll", CallingConvention = CallingConvention.Cdecl)]
- public static extern void psx_FrameAdvance();
-
- [DllImport("libmednahawk.dll", CallingConvention = CallingConvention.Cdecl)]
- [return: MarshalAs(UnmanagedType.U1)]
- public static extern bool psx_LoadCue(string path);
-}
diff --git a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs
index 92a379d76a..403eb0d370 100644
--- a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs
@@ -1,4 +1,19 @@
-using System;
+//TODO hook up newer file ID stuff, think about how to combine it with the disc ID
+//TODO not liking the name ShockFramebufferJob
+//TODO change display manager to not require 0xFF alpha channel set on videoproviders. check gdi+ and opengl! this will get us a speedup in some places
+//TODO Disc.Structure.Sessions[0].length_aba was 0
+
+//looks like we can have (in NTSC) framebuffer dimensions like this:
+//width: 280, 350, 700
+//height: 240, 480
+//mednafen's strategy is to put everything in a 320x240 and scale it up 3x to 960x720 by default (which is adequate to contain the largest PSX framebuffer)
+//heres my strategy.
+//1. we should have a native output mode, for debugging. but most users wont want it (massively distorted resolutions are common in games)
+//2. do the right thing:
+//always double a height of 240, and double a width of 280 or 350. For 280, float content in center screen.
+//but lets not do this til we're on an upgraded mednafen
+
+using System;
using System.Runtime.InteropServices;
using System.IO;
using System.Collections.Generic;
@@ -10,7 +25,7 @@ using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Sony.PSX
{
[CoreAttributes(
- "MednafenPSX",
+ "Octoshock",
"Ryphecha",
isPorted: true,
isReleased: false
@@ -31,41 +46,141 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
public bool StartAsyncSound() { return true; }
public void EndAsyncSound() { }
- public static bool CheckIsPSX(DiscSystem.Disc disc)
- {
- bool ret = false;
-
- byte[] buf = new byte[59];
- disc.ReadLBA_2352_Flat(0x24D8, buf, 0, 59);
- string sig = System.Text.ASCIIEncoding.ASCII.GetString(buf);
-
- //this string is considered highly unlikely to exist anywhere besides a psx disc
- if (sig == " Licensed by Sony Computer Entertainment")
- ret = true;
-
- return ret;
- }
-
//we can only have one active core at a time, due to the lib being so static.
//so we'll track the current one here and detach the previous one whenever a new one is booted up.
static Octoshock CurrOctoshockCore;
+
+ IntPtr psx;
+ DiscSystem.Disc disc;
+ DiscInterface discInterface;
bool disposed = false;
public void Dispose()
{
if (disposed) return;
- disposed = true;
- //BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_audio_sample(null);
+ OctoshockDll.shock_Destroy(psx);
+ psx = IntPtr.Zero;
+
+ disposed = true;
}
- public Octoshock(CoreComm comm)
+ class DiscInterface : IDisposable
+ {
+ public DiscInterface(DiscSystem.Disc disc)
+ {
+ this.Disc = disc;
+ cbReadTOC = ShockDisc_ReadTOC;
+ cbReadLBA = ShockDisc_ReadLBA2448;
+ OctoshockDll.shock_CreateDisc(out OctoshockHandle, IntPtr.Zero, disc.LBACount, cbReadTOC, cbReadLBA, true);
+ }
+
+ OctoshockDll.ShockDisc_ReadTOC cbReadTOC;
+ OctoshockDll.ShockDisc_ReadLBA cbReadLBA;
+
+ public DiscSystem.Disc Disc;
+ public IntPtr OctoshockHandle;
+
+ public void Dispose()
+ {
+ OctoshockDll.shock_DestroyDisc(OctoshockHandle);
+ OctoshockHandle = IntPtr.Zero;
+ }
+
+ int ShockDisc_ReadTOC(IntPtr opaque, OctoshockDll.ShockTOC* read_target, OctoshockDll.ShockTOCTrack* tracks101)
+ {
+ read_target->disc_type = 1; //hardcoded in octoshock
+ read_target->first_track = (byte)Disc.TOCRaw.FirstRecordedTrackNumber; //i _think_ thats what is meant here
+ read_target->last_track = (byte)Disc.TOCRaw.LastRecordedTrackNumber; //i _think_ thats what is meant here
+
+ tracks101[0].lba = tracks101[0].adr = tracks101[0].control = 0;
+
+ for (int i = 1; i < 100; i++)
+ {
+ var item = Disc.TOCRaw.TOCItems[i];
+ tracks101[i].adr = 1; //not sure what this is
+ tracks101[i].lba = (uint)item.LBATimestamp.Sector;
+ tracks101[i].control = (byte)item.Control;
+ }
+
+ ////the lead-out track is to be synthesized
+ tracks101[read_target->last_track + 1].adr = 1;
+ tracks101[read_target->last_track + 1].control = 0;
+ tracks101[read_target->last_track + 1].lba = (uint)Disc.TOCRaw.LeadoutTimestamp.Sector;
+ ////laaaame
+ //tracks101[read_target->last_track + 1].lba =
+ // (uint)(
+ // Disc.Structure.Sessions[0].Tracks[read_target->last_track - 1].Start_ABA //AUGH. see comment in Start_ABA
+ // + Disc.Structure.Sessions[0].Tracks[read_target->last_track - 1].LengthInSectors
+ // - 150
+ // );
+
+ //element 100 is to be copied as the lead-out track
+ tracks101[100] = tracks101[read_target->last_track + 1];
+
+ return OctoshockDll.SHOCK_OK;
+ }
+
+ byte[] SectorBuffer = new byte[2352];
+
+ int ShockDisc_ReadLBA2448(IntPtr opaque, int lba, void* dst)
+ {
+ //lets you check subcode generation by logging it and checking against the CCD subcode
+ bool subcodeLog = false;
+ bool readLog = false;
+
+ if (subcodeLog) Console.Write("{0}|", lba);
+ else if (readLog) Console.WriteLine("Read Sector: " + lba);
+
+ Disc.ReadLBA_2352(lba, SectorBuffer, 0);
+ Marshal.Copy(SectorBuffer, 0, new IntPtr(dst), 2352);
+ Disc.ReadLBA_SectorEntry(lba).SubcodeSector.ReadSubcodeDeinterleaved(SectorBuffer, 0);
+ Marshal.Copy(SectorBuffer, 0, new IntPtr((byte*)dst + 2352), 96);
+
+ if (subcodeLog)
+ {
+ for (int i = 0; i < 24; i++)
+ Console.Write("{0:X2}", *((byte*)dst + 2352 + i));
+ Console.WriteLine();
+ }
+
+
+ return OctoshockDll.SHOCK_OK;
+ }
+ }
+
+
+ public Octoshock(CoreComm comm, DiscSystem.Disc disc)
{
ServiceProvider = new BasicServiceProvider(this);
var domains = new List();
CoreComm = comm;
VirtualWidth = BufferWidth = 256;
BufferHeight = 192;
+
+ Attach();
+
+ this.disc = disc;
+ discInterface = new DiscInterface(disc);
+
+ //determine region of the provided disc
+ OctoshockDll.ShockDiscInfo discInfo;
+ OctoshockDll.shock_AnalyzeDisc(discInterface.OctoshockHandle, out discInfo);
+
+ //try to acquire the appropriate firmware
+ string firmwareRegion = "U";
+ if(discInfo.region == OctoshockDll.eRegion.EU) firmwareRegion = "E";
+ if (discInfo.region == OctoshockDll.eRegion.JP) firmwareRegion = "J";
+ byte[] firmware = comm.CoreFileProvider.GetFirmware("PSX", "U", true, "A PSX `" + firmwareRegion + "` region bios file is required");
+
+ //create the instance
+ fixed (byte* pFirmware = firmware)
+ OctoshockDll.shock_Create(out psx, discInfo.region, pFirmware);
+
+ OctoshockDll.shock_OpenTray(psx);
+ OctoshockDll.shock_SetDisc(psx, discInterface.OctoshockHandle);
+ OctoshockDll.shock_CloseTray(psx);
+ OctoshockDll.shock_PowerOn(psx);
}
public IEmulatorServiceProvider ServiceProvider { get; private set; }
@@ -76,146 +191,21 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
if (CurrOctoshockCore != null)
CurrOctoshockCore.Dispose();
CurrOctoshockCore = this;
+
+ //the psx instance cant be created until the desired region is known, which needs a disc, so we need the dll static attached first
}
- //note to self: try to make mednafen have file IO callbacks into here: open, close, read, write.
- //we'll trick mednafen into using a virtual filesystem and track the fake files internally
-
- public void LoadCuePath(string path)
- {
- Attach();
-
- //note to self:
- //consider loading a fake cue, which is generated by our Disc class, and converting all reads to the fake bin to reads into the disc class.
- //thatd be pretty cool.... (may need to add an absolute byte range read method into the disc class, which can traverse the requisite LBAs)...
- //...but... are there other ideas?
- LibMednahawkDll.psx_LoadCue(path);
- }
+ //public void LoadCuePath(string path)
+ //{
+ // Attach();
+ // DiscSystem.Disc.FromCCDPath
+ //}
static Octoshock()
{
- LibMednahawkDll.dll_Initialize();
-
- FopenCallback = new LibMednahawkDll.t_FopenCallback(FopenCallbackProc);
- FcloseCallback = new LibMednahawkDll.t_FcloseCallback(FcloseCallbackProc);
- FopCallback = new LibMednahawkDll.t_FopCallback(FopCallbackProc);
- LibMednahawkDll.dll_SetPropPtr(LibMednahawkDll.eProp.SetPtr_FopenCallback, Marshal.GetFunctionPointerForDelegate(FopenCallback));
- LibMednahawkDll.dll_SetPropPtr(LibMednahawkDll.eProp.SetPtr_FcloseCallback, Marshal.GetFunctionPointerForDelegate(FcloseCallback));
- LibMednahawkDll.dll_SetPropPtr(LibMednahawkDll.eProp.SetPtr_FopCallback, Marshal.GetFunctionPointerForDelegate(FopCallback));
}
- static LibMednahawkDll.t_FopenCallback FopenCallback;
- static LibMednahawkDll.t_FcloseCallback FcloseCallback;
- static LibMednahawkDll.t_FopCallback FopCallback;
-
- class VirtualFile : IDisposable
- {
- public Stream stream;
- public int id;
- public void Dispose()
- {
- if(stream != null) stream.Dispose();
- stream = null;
- }
- }
-
- static Dictionary VirtualFiles = new Dictionary();
-
- static IntPtr FopenCallbackProc(string fname, string mode)
- {
- throw new NotImplementedException("Antiquated CoreComm.PSX_FirmwaresPath must be replaced by CoreFileProvider");
-
- // TODO - this should be using the CoreComm.CoreFileProvider interfaces
-
- //TODO - probably this should never really fail. but for now, mednafen tries to create a bunch of junk, so just return failure for files which cant be opened
- /*
- if (fname.StartsWith("$psx"))
- {
- string[] parts = fname.Split('/');
- if (parts[0] != "$psx") throw new InvalidOperationException("Octoshock using some weird path we dont handle yet");
- if (parts[1] == "firmware")
- {
- //fname = Path.Combine(CurrOctoshockCore.CoreComm.PSX_FirmwaresPath, parts[2]);
- if (!File.Exists(fname))
- {
- System.Windows.Forms.MessageBox.Show("the Octoshock core is referencing a firmware file which could not be found. Please make sure it's in your configured PSX firmwares folder. The referenced filename is: " + parts[1]);
- }
- }
- }
-
- Stream stream = null;
- if (mode == "rb") { if (File.Exists(fname)) stream = new FileStream(fname, FileMode.Open, FileAccess.Read, FileShare.Read); }
- else if (mode == "wb") stream = new FileStream(fname, FileMode.Create, FileAccess.Write, FileShare.Read);
- else throw new InvalidOperationException("unexpected virtual file mode from libmednahawk");
-
- if (stream == null) return IntPtr.Zero;
-
- //find a free id. dont use 0 because it looks like an error
- int id = 1;
- for (; ; )
- {
- RETRY:
- foreach (var vfid in VirtualFiles.Keys)
- if (vfid == id)
- {
- id++;
- goto RETRY;
- }
- break;
- }
-
- var ret = new VirtualFile();
- ret.id = id;
- ret.stream = stream;
-
- VirtualFiles[ret.id] = ret;
- return new IntPtr(ret.id);
- */
- }
- static int FcloseCallbackProc(IntPtr fp)
- {
- int id = fp.ToInt32();
- VirtualFiles[id].stream.Dispose();
- VirtualFiles.Remove(id);
- return 0;
- }
- static byte[] fiobuf = new byte[10*1024];
- static long FopCallbackProc(int op, IntPtr ptr, long a, long b, IntPtr fp)
- {
- var vf = VirtualFiles[fp.ToInt32()];
- int amt = (int)(a*b);
- switch ((LibMednahawkDll.FOP)op)
- {
- case LibMednahawkDll.FOP.FOP_clearerr: return 0;
- case LibMednahawkDll.FOP.FOP_ferror: return 0;
- case LibMednahawkDll.FOP.FOP_fflush: vf.stream.Flush(); return 0;
- case LibMednahawkDll.FOP.FOP_fread:
- {
- if(fiobuf.Length < amt)
- fiobuf = new byte[amt];
- int read = vf.stream.Read(fiobuf, 0, amt);
- Marshal.Copy(fiobuf, 0, ptr, amt);
- return read / a;
- }
- case LibMednahawkDll.FOP.FOP_fseeko:
- vf.stream.Seek(a, (SeekOrigin)b);
- return vf.stream.Position;
- case LibMednahawkDll.FOP.FOP_ftello:
- return vf.stream.Position;
- case LibMednahawkDll.FOP.FOP_fwrite:
- {
- if (fiobuf.Length < amt)
- fiobuf = new byte[amt];
- Marshal.Copy(fiobuf, 0, ptr, amt);
- vf.stream.Write(fiobuf, 0, amt);
- return (int)b;
- }
- case LibMednahawkDll.FOP.FOP_size: return vf.stream.Length;
- default:
- throw new InvalidOperationException("INESTIMABLE GOPHER");
- }
- }
[FeatureNotImplemented]
public void ResetCounters()
@@ -226,32 +216,33 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
public void FrameAdvance(bool render, bool rendersound)
{
- LibMednahawkDll.psx_FrameAdvance();
-
+ OctoshockDll.shock_Step(psx, OctoshockDll.eShockStep.Frame);
+
+ OctoshockDll.ShockFramebufferJob fb = new OctoshockDll.ShockFramebufferJob();
+ OctoshockDll.shock_GetFramebuffer(psx, ref fb);
+
+ //Console.WriteLine(fb.height);
+
if (render == false) return;
- int w = LibMednahawkDll.dll_GetPropPtr(LibMednahawkDll.eProp.GetPtr_FramebufferWidth).ToInt32();
- int h = LibMednahawkDll.dll_GetPropPtr(LibMednahawkDll.eProp.GetPtr_FramebufferHeight).ToInt32();
- int p = LibMednahawkDll.dll_GetPropPtr(LibMednahawkDll.eProp.GetPtr_FramebufferPitchPixels).ToInt32();
- IntPtr iptr = LibMednahawkDll.dll_GetPropPtr(LibMednahawkDll.eProp.GetPtr_FramebufferPointer);
- void* ptr = iptr.ToPointer();
-
-
- VirtualWidth = BufferWidth = w;
+ int w = fb.width;
+ int h = fb.height;
+ BufferWidth = w;
BufferHeight = h;
int len = w*h;
if (frameBuffer.Length != len)
+ {
+ Console.WriteLine("PSX FB size: {0},{1}", fb.width, fb.height);
frameBuffer = new int[len];
+ }
- //todo - we could do the reformatting in the PSX core
- //better yet, we could send a buffer into the psx core before frame advance to use for outputting video to
-
- for (int y = 0, i = 0; y < h; y++)
- for (int x = 0; x < w; x++, i++)
- {
- frameBuffer[i] = (int)unchecked(((int*)ptr)[y * p + x] | (int)0xFF000000);
- }
+ fixed (int* ptr = frameBuffer)
+ {
+ fb.ptr = ptr;
+ OctoshockDll.shock_GetFramebuffer(psx, ref fb);
+ //alpha channel is added in c++, right now. wish we didnt have to do it at all
+ }
}
[FeatureNotImplemented]
diff --git a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/OctoshockDll.cs b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/OctoshockDll.cs
new file mode 100644
index 0000000000..e65a136617
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/OctoshockDll.cs
@@ -0,0 +1,97 @@
+//API TODO
+//get rid of the 2048 byte reader
+
+using System;
+using System.Runtime.InteropServices;
+
+public unsafe static class OctoshockDll
+{
+ public enum eRegion : int
+ {
+ JP = 0,
+ NA = 1,
+ EU = 2,
+ NONE = 3 //TODO - whats the difference between unset, and region unknown?
+ }
+
+ public enum eShockStep
+ {
+ Frame
+ };
+
+ public const int SHOCK_OK = 0;
+ public const int SHOCK_ERROR = -1;
+ public const int SHOCK_NOCANDO = -2;
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct ShockDiscInfo
+ {
+ public eRegion region;
+ public unsafe fixed sbyte id[5]; //SCEI, SCEA, SCEE, etc. with null terminator
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct ShockTOCTrack
+ {
+ public byte adr;
+ public byte control;
+ public uint lba;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct ShockTOC
+ {
+ public byte first_track;
+ public byte last_track;
+ public byte disc_type;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct ShockFramebufferJob
+ {
+ public int width, height;
+ public void* ptr;
+ };
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate int ShockDisc_ReadTOC(IntPtr opaque, ShockTOC* read_target, ShockTOCTrack* tracks101);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate int ShockDisc_ReadLBA(IntPtr opaque, int lba, void* dst);
+
+ [DllImport("octoshock.dll")]
+ public static extern int shock_CreateDisc(out IntPtr outDisc, IntPtr Opaque, int lbaCount, ShockDisc_ReadTOC ReadTOC, ShockDisc_ReadLBA ReadLBA2448, bool suppliesDeinterleavedSubcode);
+
+ [DllImport("octoshock.dll")]
+ public static extern int shock_DestroyDisc(IntPtr disc);
+
+ [DllImport("octoshock.dll")]
+ public static extern int shock_AnalyzeDisc(IntPtr disc, out ShockDiscInfo info);
+
+ [DllImport("octoshock.dll")]
+ public static extern int shock_Create(out IntPtr psx, eRegion region, void* firmware512k);
+
+ [DllImport("octoshock.dll")]
+ public static extern int shock_Destroy(IntPtr psx);
+
+ [DllImport("octoshock.dll")]
+ public static extern int shock_PowerOn(IntPtr psx);
+
+ [DllImport("octoshock.dll")]
+ public static extern int shock_PowerOff(IntPtr psx);
+
+ [DllImport("octoshock.dll")]
+ public static extern int shock_OpenTray(IntPtr psx);
+
+ [DllImport("octoshock.dll")]
+ public static extern int shock_SetDisc(IntPtr psx, IntPtr disc);
+
+ [DllImport("octoshock.dll")]
+ public static extern int shock_CloseTray(IntPtr psx);
+
+ [DllImport("octoshock.dll")]
+ public static extern int shock_Step(IntPtr psx, eShockStep step);
+
+ [DllImport("octoshock.dll")]
+ public static extern int shock_GetFramebuffer(IntPtr psx, ref ShockFramebufferJob fb);
+}
diff --git a/output/dll/libmednahawk.dll b/output/dll/libmednahawk.dll
deleted file mode 100644
index 7800be9f75..0000000000
Binary files a/output/dll/libmednahawk.dll and /dev/null differ
diff --git a/output/dll/octoshock.dll b/output/dll/octoshock.dll
new file mode 100644
index 0000000000..72c1f18238
Binary files /dev/null and b/output/dll/octoshock.dll differ
diff --git a/psx/octoshock/FileStream.cpp b/psx/octoshock/FileStream.cpp
new file mode 100644
index 0000000000..1e7c1adf75
--- /dev/null
+++ b/psx/octoshock/FileStream.cpp
@@ -0,0 +1,106 @@
+// TODO/WIP
+
+/* Mednafen - Multi-system Emulator
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include
+#include "mednafen.h"
+#include "Stream.h"
+#include "FileStream.h"
+
+#include
+#include
+#include
+
+#ifdef _WIN32
+#include
+#else
+#include
+#endif
+
+#define fseeko fseek
+#define ftello ftell
+
+FileStream::FileStream(const char *path, const int mode): OpenedMode(mode)
+{
+ if(!(fp = fopen(path, (mode == FileStream::MODE_WRITE) ? "wb" : "rb")))
+ {
+ ErrnoHolder ene(errno);
+
+ throw(MDFN_Error(ene.Errno(), _("Error opening file %s"), ene.StrError()));
+ }
+}
+
+FileStream::~FileStream()
+{
+}
+
+uint64 FileStream::attributes(void)
+{
+ uint64 ret = ATTRIBUTE_SEEKABLE;
+
+ switch(OpenedMode)
+ {
+ case FileStream::MODE_READ:
+ ret |= ATTRIBUTE_READABLE;
+ break;
+ case FileStream::MODE_WRITE_SAFE:
+ case FileStream::MODE_WRITE:
+ ret |= ATTRIBUTE_WRITEABLE;
+ break;
+ }
+
+ return ret;
+}
+
+uint64 FileStream::read(void *data, uint64 count, bool error_on_eos)
+{
+ return fread(data, 1, count, fp);
+}
+
+void FileStream::write(const void *data, uint64 count)
+{
+ fwrite(data, 1, count, fp);
+}
+
+void FileStream::seek(int64 offset, int whence)
+{
+ fseeko(fp, offset, whence);
+}
+
+int64 FileStream::tell(void)
+{
+ return ftello(fp);
+}
+
+int64 FileStream::size(void) {
+ struct stat buf;
+
+ fstat(fileno(fp), &buf);
+
+ return(buf.st_size);
+}
+
+void FileStream::close(void)
+{
+ if(!fp)
+ return;
+
+ FILE *tmp = fp;
+ fp = NULL;
+ fclose(tmp);
+}
diff --git a/psx/octoshock/FileStream.h b/psx/octoshock/FileStream.h
new file mode 100644
index 0000000000..97ccd2a747
--- /dev/null
+++ b/psx/octoshock/FileStream.h
@@ -0,0 +1,56 @@
+/* Mednafen - Multi-system Emulator
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+// TODO/WIP
+
+#ifndef __MDFN_FILESTREAM_H
+#define __MDFN_FILESTREAM_H
+
+#include "Stream.h"
+#include "FileWrapper.h"
+
+class FileStream : public Stream
+{
+ public:
+
+ enum
+ {
+ MODE_READ = FileWrapper::MODE_READ,
+ MODE_WRITE = FileWrapper::MODE_WRITE,
+ MODE_WRITE_SAFE = FileWrapper::MODE_WRITE_SAFE,
+ };
+
+ FileStream(const char *path, const int mode);
+ virtual ~FileStream();
+
+ virtual uint64 attributes(void);
+
+ virtual uint64 read(void *data, uint64 count, bool error_on_eos = true);
+ virtual void write(const void *data, uint64 count);
+ virtual void seek(int64 offset, int whence);
+ virtual int64 tell(void);
+ virtual int64 size(void);
+ virtual void close(void);
+
+ private:
+ FILE *fp;
+ const int OpenedMode;
+};
+
+
+
+#endif
diff --git a/psx/octoshock/FileWrapper.cpp b/psx/octoshock/FileWrapper.cpp
new file mode 100644
index 0000000000..8e56645195
--- /dev/null
+++ b/psx/octoshock/FileWrapper.cpp
@@ -0,0 +1,135 @@
+/* Mednafen - Multi-system Emulator
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include
+#include "mednafen.h"
+#include "FileWrapper.h"
+
+#include
+#include
+#include
+
+#ifdef _WIN32
+#include
+#else
+#include
+#endif
+
+// Some really bad preprocessor abuse follows to handle platforms that don't have fseeko and ftello...and of course
+// for largefile support on Windows:
+
+#define fseeko fseek
+#define ftello ftell
+
+// For special uses, IE in classes that take a path or a FileWrapper & in the constructor, and the FileWrapper non-pointer member
+// is in the initialization list for the path constructor but not the constructor with FileWrapper&
+
+FileWrapper::FileWrapper(const char *path, const int mode, const char *purpose) : OpenedMode(mode)
+{
+ if(!(fp = fopen(path, (mode == MODE_WRITE) ? "wb" : "rb")))
+ {
+ ErrnoHolder ene(errno);
+
+ throw(MDFN_Error(ene.Errno(), _("Error opening file %s"), ene.StrError()));
+ }
+}
+
+FileWrapper::~FileWrapper()
+{
+ close();
+}
+
+void FileWrapper::close(void)
+{
+ if(!fp)
+ return;
+
+ FILE *tmp = fp;
+ fp = NULL;
+ fclose(tmp);
+}
+
+uint64 FileWrapper::read(void *data, uint64 count, bool error_on_eof)
+{
+ return fread(data, 1, count, fp);
+}
+
+void FileWrapper::flush(void)
+{
+ fflush(fp);
+}
+
+void FileWrapper::write(const void *data, uint64 count)
+{
+ fwrite(data, 1, count, fp);
+}
+
+int FileWrapper::scanf(const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+
+ ret = trio_vfscanf(fp, format, ap);
+
+ va_end(ap);
+
+ return ret;
+}
+
+void FileWrapper::put_char(int c)
+{
+ fputc(c, fp);
+}
+
+void FileWrapper::put_string(const char *str)
+{
+ write(str, strlen(str));
+}
+
+// We need to decide whether to prohibit NULL characters in output and input strings via std::string.
+// Yes for correctness, no for potential security issues(though unlikely in context all things considered).
+void FileWrapper::put_string(const std::string &str)
+{
+ write(str.data(), str.size());
+}
+
+char *FileWrapper::get_line(char *buf_s, int buf_size)
+{
+ return ::fgets(buf_s, buf_size, fp);
+}
+
+
+void FileWrapper::seek(int64 offset, int whence)
+{
+ fseeko(fp, offset, whence);
+}
+
+int64 FileWrapper::size(void)
+{
+ struct stat buf;
+
+ fstat(fileno(fp), &buf);
+
+ return(buf.st_size);
+}
+
+int64 FileWrapper::tell(void)
+{
+ return ftello(fp);
+}
diff --git a/psx/octoshock/FileWrapper.h b/psx/octoshock/FileWrapper.h
new file mode 100644
index 0000000000..c4d11fd77b
--- /dev/null
+++ b/psx/octoshock/FileWrapper.h
@@ -0,0 +1,57 @@
+#ifndef __MDFN_FILEWRAPPER_H
+#define __MDFN_FILEWRAPPER_H
+
+// A stdio FILE wrapper(with some BSD and POSIXisms, and a little dash of Win32, thrown in for special behaviors)
+class FileWrapper
+{
+ public:
+
+ enum
+ {
+ MODE_READ = 0,
+ MODE_WRITE,
+ MODE_WRITE_SAFE // Will throw an exception instead of overwriting an existing file.
+ };
+
+ FileWrapper(const char *path, const int mode, const char *purpose = NULL);
+ ~FileWrapper();
+
+ uint64 read(void *data, uint64 count, bool error_on_eof = true);
+
+ void write(const void *data, uint64 count);
+
+ int scanf(const char *format, ...) MDFN_FORMATSTR(scanf, 2, 3);
+
+ void put_char(int c);
+
+ void put_string(const char *str);
+ void put_string(const std::string &str);
+
+ char *get_line(char *s, int size); // Same semantics as fgets(), for now
+
+ void seek(int64 offset, int whence);
+
+ int64 tell(void);
+
+ int64 size(void);
+
+ void flush(void);
+
+ void close(void); // Flushes and closes the underlying OS/C lib file. Calling any other method of this class after a call to
+ // this method is illegal(except for the implicit call to the destructor).
+ //
+ // This is necessary since there can be errors when closing a file, and we can't safely throw an
+ // exception from the destructor.
+ //
+ // Manually calling this method isn't strictly necessary, it'll be called from the destructor
+ // automatically, but calling is strongly recommended when the file is opened for writing.
+ private:
+
+ FileWrapper & operator=(const FileWrapper &); // Assignment operator
+ FileWrapper(const FileWrapper &); // Copy constructor
+
+ FILE *fp;
+ const int OpenedMode;
+};
+
+#endif
diff --git a/psx/octoshock/Stream.cpp b/psx/octoshock/Stream.cpp
new file mode 100644
index 0000000000..abe4f2bbd9
--- /dev/null
+++ b/psx/octoshock/Stream.cpp
@@ -0,0 +1,112 @@
+// TODO/WIP
+
+/* Mednafen - Multi-system Emulator
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "octoshock.h"
+#include "Stream.h"
+
+//#include
+
+Stream::Stream()
+{
+
+}
+
+Stream::~Stream()
+{
+
+}
+
+void Stream::put_line(const std::string& str)
+{
+ char l = '\n';
+
+ write(&str[0], str.size());
+ write(&l, sizeof(l));
+}
+
+
+void Stream::print_format(const char *format, ...)
+{
+ //char *str = NULL;
+ //int rc;
+
+ //va_list ap;
+
+ //va_start(ap, format);
+
+ //rc = trio_vasprintf(&str, format, ap);
+
+ //va_end(ap);
+
+ //if(rc < 0)
+ // throw MDFN_Error(0, "Error in trio_vasprintf()");
+ //else
+ //{
+ // try // Bleck
+ // {
+ // write(str, rc);
+ // }
+ // catch(...)
+ // {
+ // free(str);
+ // throw;
+ // }
+ // free(str);
+ //}
+}
+
+int Stream::get_line(std::string &str)
+{
+ uint8 c;
+
+ str.clear(); // or str.resize(0)??
+
+ while(read(&c, sizeof(c), false) > 0)
+ {
+ if(c == '\r' || c == '\n' || c == 0)
+ return(c);
+
+ str.push_back(c);
+ }
+
+ return(str.length() ? 256 : -1);
+}
+
+StreamFilter::StreamFilter()
+{
+ target_stream = NULL;
+}
+
+StreamFilter::StreamFilter(Stream *target_arg)
+{
+ target_stream = target_arg;
+}
+
+StreamFilter::~StreamFilter()
+{
+ if(target_stream)
+ delete target_stream;
+}
+
+Stream* StreamFilter::steal(void)
+{
+ Stream *ret = target_stream;
+ target_stream = NULL;
+ return ret;
+}
diff --git a/psx/octoshock/Stream.h b/psx/octoshock/Stream.h
new file mode 100644
index 0000000000..eecc10eea2
--- /dev/null
+++ b/psx/octoshock/Stream.h
@@ -0,0 +1,206 @@
+#ifndef __MDFN_STREAM_H
+#define __MDFN_STREAM_H
+
+// TODO/WIP
+
+// TODO?: BufferedStream, no virtual functions, yes inline functions, constructor takes a Stream* argument.
+
+#include
+
+#include // For SEEK_* defines, which we will use in Stream out of FORCE OF HABIT.
+#include
+
+#include "octoshock.h"
+
+class Stream
+{
+ public:
+
+ Stream();
+ virtual ~Stream();
+
+ enum
+ {
+ ATTRIBUTE_READABLE = 1U << 0,
+ ATTRIBUTE_WRITEABLE = 1U << 1,
+ ATTRIBUTE_SEEKABLE = 1U << 2,
+ ATTRIBUTE_SLOW_SEEK = 1U << 3,
+ ATTRIBUTE_SLOW_SIZE = 1U << 4
+ };
+ virtual uint64 attributes(void) = 0;
+
+ virtual uint8 *map(void) = 0; // Map the entirety of the stream data into the address space of the process, if possible, and return a pointer.
+ // (the returned pointer must be cached, and returned on any subsequent calls to map() without an unmap()
+ // in-between, to facilitate a sort of "feature-testing", to determine if an alternative like "MemoryStream"
+ // should be used).
+ //
+ // If the mapping fails for whatever reason, return NULL rather than throwing an exception.
+ //
+
+ virtual void unmap(void) = 0; // Unmap the stream data from the address space. (Possibly invalidating the pointer returned from map()).
+ // (must automatically be called, if necessary, from the destructor).
+ //
+ // If the data can't be "unmapped" as such because it was never mmap()'d or similar in the first place(such as with MemoryStream),
+ // then this will be a nop.
+
+ virtual uint64 read(void *data, uint64 count, bool error_on_eos = true) = 0;
+ virtual void write(const void *data, uint64 count) = 0;
+
+ virtual void seek(int64 offset, int whence = SEEK_SET) = 0;
+ inline void rewind(void)
+ {
+ seek(0, SEEK_SET);
+ }
+ virtual int64 tell(void) = 0;
+ virtual int64 size(void) = 0;
+ virtual void close(void) = 0; // Flushes(in the case of writeable streams) and closes the stream.
+ // Necessary since this operation can fail(running out of disk space, for instance),
+ // and throw an exception in the destructor would be a Bad Idea(TM).
+ //
+ // Manually calling this function isn't strictly necessary, but recommended when the
+ // stream is writeable; it will be called automatically from the destructor, with any
+ // exceptions thrown caught and logged.
+
+ //
+ // Utility functions(TODO):
+ //
+ INLINE uint8 get_u8(void)
+ {
+ uint8 ret;
+
+ read(&ret, sizeof(ret));
+
+ return ret;
+ }
+
+ INLINE void put_u8(uint8 c)
+ {
+ write(&c, sizeof(c));
+ }
+
+
+ template
+ INLINE T get_NE(void)
+ {
+ T ret;
+
+ read(&ret, sizeof(ret));
+
+ return ret;
+ }
+
+ template
+ INLINE void put_NE(T c)
+ {
+ write(&c, sizeof(c));
+ }
+
+
+ template
+ INLINE T get_RE(void)
+ {
+ uint8 tmp[sizeof(T)];
+ T ret = 0;
+
+ read(tmp, sizeof(tmp));
+
+ for(unsigned i = 0; i < sizeof(T); i++)
+ ret |= (T)tmp[i] << (i * 8);
+
+ return ret;
+ }
+
+ template
+ INLINE void put_RE(T c)
+ {
+ uint8 tmp[sizeof(T)];
+
+ for(unsigned i = 0; i < sizeof(T); i++)
+ tmp[i] = ((uint8 *)&c)[sizeof(T) - 1 - i];
+
+ write(tmp, sizeof(tmp));
+ }
+
+ template
+ INLINE T get_LE(void)
+ {
+ #ifdef LSB_FIRST
+ return get_NE();
+ #else
+ return get_RE();
+ #endif
+ }
+
+ template
+ INLINE void put_LE(T c)
+ {
+ #ifdef LSB_FIRST
+ return put_NE(c);
+ #else
+ return put_RE(c);
+ #endif
+ }
+
+ template
+ INLINE T get_BE(void)
+ {
+ #ifndef LSB_FIRST
+ return get_NE();
+ #else
+ return get_RE();
+ #endif
+ }
+
+ template
+ INLINE void put_BE(T c)
+ {
+ #ifndef LSB_FIRST
+ return put_NE(c);
+ #else
+ return put_RE(c);
+ #endif
+ }
+
+ // Reads a line into "str", overwriting its contents; returns the line-end char('\n' or '\r' or '\0'), or 256 on EOF and
+ // data has been read into "str", and -1 on EOF when no data has been read into "str".
+ // The line-end char won't be added to "str".
+ // It's up to the caller to handle extraneous empty lines caused by DOS-format text lines(\r\n).
+ // ("str" is passed by reference for the possibility of improved performance by reusing alloced memory for the std::string, though part
+ // of it would be up to the STL implementation).
+ // Implemented as virtual so that a higher-performance version can be implemented if possible(IE with MemoryStream)
+ virtual int get_line(std::string &str);
+
+ virtual void put_line(const std::string& str);
+
+ virtual void print_format(const char *format, ...);
+
+#if 0
+ int scanf(const char *format, ...) MDFN_FORMATSTR(gnu_scanf, 2, 3);
+ void put_string(const char *str);
+ void put_string(const std::string &str);
+#endif
+};
+
+// StreamFilter takes ownership of the Stream pointer passed, and will delete it in its destructor.
+class StreamFilter : public Stream
+{
+ public:
+
+ StreamFilter();
+ StreamFilter(Stream *target_arg);
+ virtual ~StreamFilter();
+
+ virtual uint64 read(void *data, uint64 count, bool error_on_eos = true) = 0;
+ virtual void write(const void *data, uint64 count) = 0;
+ virtual void seek(int64 offset, int whence) = 0;
+ virtual int64 tell(void) = 0;
+ virtual int64 size(void) = 0;
+ virtual void close(void) = 0;
+
+ virtual Stream *steal(void);
+
+ private:
+ Stream *target_stream;
+};
+
+#endif
diff --git a/psx/octoshock/bizhawk/octoshock.sln b/psx/octoshock/bizhawk/octoshock.sln
new file mode 100644
index 0000000000..e19efdc80b
--- /dev/null
+++ b/psx/octoshock/bizhawk/octoshock.sln
@@ -0,0 +1,26 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "octoshock", "octoshock.vcxproj", "{5F35CAFC-6208-4FBE-AD17-0E69BA3F70EC}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniclient", "..\test\miniclient\miniclient.vcxproj", "{5A0DAC84-1170-4B1A-B9A9-F566A1D97790}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {5F35CAFC-6208-4FBE-AD17-0E69BA3F70EC}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5F35CAFC-6208-4FBE-AD17-0E69BA3F70EC}.Debug|Win32.Build.0 = Debug|Win32
+ {5F35CAFC-6208-4FBE-AD17-0E69BA3F70EC}.Release|Win32.ActiveCfg = Release|Win32
+ {5F35CAFC-6208-4FBE-AD17-0E69BA3F70EC}.Release|Win32.Build.0 = Release|Win32
+ {5A0DAC84-1170-4B1A-B9A9-F566A1D97790}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5A0DAC84-1170-4B1A-B9A9-F566A1D97790}.Debug|Win32.Build.0 = Debug|Win32
+ {5A0DAC84-1170-4B1A-B9A9-F566A1D97790}.Release|Win32.ActiveCfg = Release|Win32
+ {5A0DAC84-1170-4B1A-B9A9-F566A1D97790}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/psx/octoshock/bizhawk/octoshock.vcxproj b/psx/octoshock/bizhawk/octoshock.vcxproj
new file mode 100644
index 0000000000..9d226fe27c
--- /dev/null
+++ b/psx/octoshock/bizhawk/octoshock.vcxproj
@@ -0,0 +1,180 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {5F35CAFC-6208-4FBE-AD17-0E69BA3F70EC}
+ Win32Proj
+ octoshock
+
+
+
+ DynamicLibrary
+ true
+ Unicode
+
+
+ DynamicLibrary
+ false
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(ProjectDir)\..\..\..\output\dll\
+
+
+ false
+ $(ProjectDir)\..\..\..\output\dll\
+
+
+
+ NotUsing
+ Level3
+ Disabled
+ EW_EXPORT;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;OCTOSHOCK_EXPORTS;%(PreprocessorDefinitions)
+ ../emuware/msvc;..
+
+
+
+
+ true
+ false
+
+
+ Windows
+ true
+
+
+
+
+ Level3
+ NotUsing
+ MaxSpeed
+ true
+ true
+ _CRT_SECURE_NO_WARNINGS;EW_EXPORT;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
+
+
+
+
+ true
+ ../emuware/msvc;..
+
+
+ Windows
+ true
+ true
+ true
+
+
+
+
+
+
\ No newline at end of file
diff --git a/psx/octoshock/bizhawk/octoshock.vcxproj.filters b/psx/octoshock/bizhawk/octoshock.vcxproj.filters
new file mode 100644
index 0000000000..467cd26a42
--- /dev/null
+++ b/psx/octoshock/bizhawk/octoshock.vcxproj.filters
@@ -0,0 +1,247 @@
+
+
+
+
+ {00f73db4-1182-4bf7-b891-66bf860d3742}
+
+
+ {f69cc8f2-7480-44d6-9a32-9dca789d2bf6}
+
+
+ {57a8e6ec-9225-410d-b38f-ba209abae070}
+
+
+ {76abb796-5411-4d33-b3e0-f1f3873f138e}
+
+
+ {cb700979-4dce-4b10-8521-3ab71a313271}
+
+
+ {d1f71901-17a5-441a-8b4f-f7da34a057c1}
+
+
+
+
+ psx
+
+
+ psx
+
+
+ psx
+
+
+ psx
+
+
+ psx
+
+
+
+ psx
+
+
+
+ psx
+
+
+ psx
+
+
+ psx
+
+
+ psx
+
+
+ psx
+
+
+ psx
+
+
+ psx
+
+
+
+
+ cdrom
+
+
+ cdrom
+
+
+ cdrom
+
+
+ cdrom
+
+
+ psx\input
+
+
+ psx\input
+
+
+ psx\input
+
+
+ psx\input
+
+
+ psx\input
+
+
+ psx\input
+
+
+ psx\input
+
+
+ psx\input
+
+
+ psx\input
+
+
+
+ emuware
+
+
+ video
+
+
+ video
+
+
+ cdrom
+
+
+ cdrom
+
+
+
+
+ psx
+
+
+ psx
+
+
+ emuware
+
+
+ psx
+
+
+ psx
+
+
+
+
+
+ psx
+
+
+
+
+
+ psx
+
+
+
+
+
+ psx
+
+
+ psx
+
+
+ psx
+
+
+ psx
+
+
+ psx
+
+
+ psx
+
+
+ psx
+
+
+ cdrom
+
+
+ cdrom
+
+
+ cdrom
+
+
+ psx\input
+
+
+ psx\input
+
+
+ psx\input
+
+
+ psx\input
+
+
+ psx\input
+
+
+ psx\input
+
+
+ psx\input
+
+
+ psx\input
+
+
+ psx\input
+
+
+ emuware\msvc
+
+
+ emuware\msvc
+
+
+ video
+
+
+ video
+
+
+
+
+ psx
+
+
+ psx
+
+
+ psx
+
+
+ psx
+
+
+ psx
+
+
+ psx
+
+
+ psx
+
+
+
\ No newline at end of file
diff --git a/psx/octoshock/cdrom/CDAccess.cpp b/psx/octoshock/cdrom/CDAccess.cpp
new file mode 100644
index 0000000000..9d932a2491
--- /dev/null
+++ b/psx/octoshock/cdrom/CDAccess.cpp
@@ -0,0 +1,58 @@
+/* Mednafen - Multi-system Emulator
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "../mednafen.h"
+#include "CDAccess.h"
+#include "CDAccess_Image.h"
+#include "CDAccess_CCD.h"
+
+#ifdef HAVE_LIBCDIO
+#include "CDAccess_Physical.h"
+#endif
+
+using namespace CDUtility;
+
+CDAccess::CDAccess()
+{
+
+}
+
+CDAccess::~CDAccess()
+{
+
+}
+
+CDAccess *cdaccess_open_image(const char *path, bool image_memcache)
+{
+ CDAccess *ret = NULL;
+
+ if(strlen(path) >= 4 && !strcasecmp(path + strlen(path) - 4, ".ccd"))
+ ret = new CDAccess_CCD(path, image_memcache);
+ else
+ ret = new CDAccess_Image(path, image_memcache);
+
+ return ret;
+}
+
+CDAccess *cdaccess_open_phys(const char *devicename)
+{
+ #ifdef HAVE_LIBCDIO
+ return new CDAccess_Physical(devicename);
+ #else
+ throw MDFN_Error(0, _("Physical CD access support not compiled in."));
+ #endif
+}
diff --git a/psx/octoshock/cdrom/CDAccess.h b/psx/octoshock/cdrom/CDAccess.h
new file mode 100644
index 0000000000..5fbdda19b8
--- /dev/null
+++ b/psx/octoshock/cdrom/CDAccess.h
@@ -0,0 +1,31 @@
+#ifndef __MDFN_CDROMFILE_H
+#define __MDFN_CDROMFILE_H
+
+#include
+
+#include "CDUtility.h"
+
+class CDAccess
+{
+ public:
+
+ CDAccess();
+ virtual ~CDAccess();
+
+ virtual void Read_Raw_Sector(uint8 *buf, int32 lba) = 0;
+
+ virtual void Read_TOC(CDUtility::TOC *toc) = 0;
+
+ virtual bool Is_Physical(void) throw() = 0;
+
+ virtual void Eject(bool eject_status) = 0; // Eject a disc if it's physical, otherwise NOP. Returns true on success(or NOP), false on error
+
+ private:
+ CDAccess(const CDAccess&); // No copy constructor.
+ CDAccess& operator=(const CDAccess&); // No assignment operator.
+};
+
+CDAccess *cdaccess_open_image(const char *path, bool image_memcache);
+CDAccess *cdaccess_open_phys(const char *devicename);
+
+#endif
diff --git a/psx/octoshock/cdrom/CDUtility.cpp b/psx/octoshock/cdrom/CDUtility.cpp
new file mode 100644
index 0000000000..4a403f542a
--- /dev/null
+++ b/psx/octoshock/cdrom/CDUtility.cpp
@@ -0,0 +1,324 @@
+/* Mednafen - Multi-system Emulator
+ *
+ * Subchannel Q CRC Code: Copyright (C) 1998 Andreas Mueller
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include
+#include
+
+#include "octoshock.h"
+#include "CDUtility.h"
+#include "dvdisaster.h"
+#include "lec.h"
+
+// Kill_LEC_Correct();
+
+
+namespace CDUtility
+{
+
+// lookup table for crc calculation
+static uint16 subq_crctab[256] =
+{
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
+ 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
+ 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
+ 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
+ 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
+ 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
+ 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
+ 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
+ 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
+ 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
+ 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
+ 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
+ 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
+ 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
+ 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
+ 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
+ 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
+ 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
+ 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
+ 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
+ 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
+ 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
+ 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
+ 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
+ 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
+ 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
+ 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
+};
+
+
+static uint8 scramble_table[2352 - 12];
+
+static bool CDUtility_Inited = false;
+
+static void InitScrambleTable(void)
+{
+ unsigned cv = 1;
+
+ for(unsigned i = 12; i < 2352; i++)
+ {
+ unsigned char z = 0;
+
+ for(int b = 0; b < 8; b++)
+ {
+ z |= (cv & 1) << b;
+
+ int feedback = ((cv >> 1) & 1) ^ (cv & 1);
+ cv = (cv >> 1) | (feedback << 14);
+ }
+
+ scramble_table[i - 12] = z;
+ }
+
+ //for(int i = 0; i < 2352 - 12; i++)
+ // printf("0x%02x, ", scramble_table[i]);
+}
+
+void CDUtility_Init(void)
+{
+ if(!CDUtility_Inited)
+ {
+ Init_LEC_Correct();
+
+ InitScrambleTable();
+
+ CDUtility_Inited = true;
+ }
+}
+
+void encode_mode0_sector(uint32 aba, uint8 *sector_data)
+{
+ CDUtility_Init();
+
+ lec_encode_mode0_sector(aba, sector_data);
+}
+
+void encode_mode1_sector(uint32 aba, uint8 *sector_data)
+{
+ CDUtility_Init();
+
+ lec_encode_mode1_sector(aba, sector_data);
+}
+
+void encode_mode2_sector(uint32 aba, uint8 *sector_data)
+{
+ CDUtility_Init();
+
+ lec_encode_mode2_sector(aba, sector_data);
+}
+
+void encode_mode2_form1_sector(uint32 aba, uint8 *sector_data)
+{
+ CDUtility_Init();
+
+ lec_encode_mode2_form1_sector(aba, sector_data);
+}
+
+void encode_mode2_form2_sector(uint32 aba, uint8 *sector_data)
+{
+ CDUtility_Init();
+
+ lec_encode_mode2_form2_sector(aba, sector_data);
+}
+
+bool edc_check(const uint8 *sector_data, bool xa)
+{
+ CDUtility_Init();
+
+ return(CheckEDC(sector_data, xa));
+}
+
+bool edc_lec_check_and_correct(uint8 *sector_data, bool xa)
+{
+ CDUtility_Init();
+
+ return(ValidateRawSector(sector_data, xa));
+}
+
+
+bool subq_check_checksum(const uint8 *SubQBuf)
+{
+ uint16 crc = 0;
+ uint16 stored_crc = 0;
+
+ stored_crc = SubQBuf[0xA] << 8;
+ stored_crc |= SubQBuf[0xB];
+
+ for(int i = 0; i < 0xA; i++)
+ crc = subq_crctab[(crc >> 8) ^ SubQBuf[i]] ^ (crc << 8);
+
+ crc = ~crc;
+
+ return(crc == stored_crc);
+}
+
+void subq_generate_checksum(uint8 *buf)
+{
+ uint16 crc = 0;
+
+ for(int i = 0; i < 0xA; i++)
+ crc = subq_crctab[(crc >> 8) ^ buf[i]] ^ (crc << 8);
+
+ // Checksum
+ buf[0xa] = ~(crc >> 8);
+ buf[0xb] = ~(crc);
+}
+
+void subq_deinterleave(const uint8 *SubPWBuf, uint8 *qbuf)
+{
+ memset(qbuf, 0, 0xC);
+
+ for(int i = 0; i < 96; i++)
+ {
+ 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.
+void subpw_deinterleave(const uint8 *in_buf, uint8 *out_buf)
+{
+ assert(in_buf != out_buf);
+
+ memset(out_buf, 0, 96);
+
+ for(unsigned ch = 0; ch < 8; ch++)
+ {
+ for(unsigned i = 0; i < 96; i++)
+ {
+ 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.
+void subpw_interleave(const uint8 *in_buf, uint8 *out_buf)
+{
+ assert(in_buf != out_buf);
+
+ for(unsigned d = 0; d < 12; d++)
+ {
+ for(unsigned bitpoodle = 0; bitpoodle < 8; bitpoodle++)
+ {
+ uint8 rawb = 0;
+
+ for(unsigned ch = 0; ch < 8; ch++)
+ {
+ rawb |= ((in_buf[ch * 12 + d] >> (7 - bitpoodle)) & 1) << (7 - ch);
+ }
+ out_buf[(d << 3) + bitpoodle] = rawb;
+ }
+ }
+}
+
+// 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
+// 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).
+//
+void subpw_synth_leadout_lba(const TOC& toc, const int32 lba, uint8* SubPWBuf)
+{
+ uint8 buf[0xC];
+ uint32 lba_relative;
+ uint32 ma, sa, fa;
+ uint32 m, s, f;
+
+ lba_relative = lba - toc.tracks[100].lba;
+
+ f = (lba_relative % 75);
+ s = ((lba_relative / 75) % 60);
+ m = (lba_relative / 75 / 60);
+
+ fa = (lba + 150) % 75;
+ sa = ((lba + 150) / 75) % 60;
+ ma = ((lba + 150) / 75 / 60);
+
+ uint8 adr = 0x1; // Q channel data encodes position
+ uint8 control = (toc.tracks[toc.last_track].control & 0x4) | toc.tracks[100].control;
+
+ memset(buf, 0, 0xC);
+ buf[0] = (adr << 0) | (control << 4);
+ buf[1] = 0xAA;
+ buf[2] = 0x01;
+
+ // Track relative MSF address
+ buf[3] = U8_to_BCD(m);
+ buf[4] = U8_to_BCD(s);
+ buf[5] = U8_to_BCD(f);
+
+ buf[6] = 0; // Zerroooo
+
+ // Absolute MSF address
+ buf[7] = U8_to_BCD(ma);
+ buf[8] = U8_to_BCD(sa);
+ buf[9] = U8_to_BCD(fa);
+
+ subq_generate_checksum(buf);
+
+ for(int i = 0; i < 96; i++)
+ SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80;
+}
+
+void synth_leadout_sector_lba(const uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf)
+{
+ memset(out_buf, 0, 2352 + 96);
+ subpw_synth_leadout_lba(toc, lba, out_buf + 2352);
+
+ if((toc.tracks[toc.last_track].control | toc.tracks[100].control) & 0x4)
+ {
+ switch(mode)
+ {
+ default:
+ encode_mode0_sector(LBA_to_ABA(lba), out_buf);
+ break;
+
+ case 0x01:
+ encode_mode1_sector(LBA_to_ABA(lba), out_buf);
+ break;
+
+ case 0x02:
+ out_buf[18] = 0x20;
+ encode_mode2_form2_sector(LBA_to_ABA(lba), out_buf);
+ break;
+ }
+ }
+}
+
+#if 0
+bool subq_extrapolate(const uint8 *subq_input, int32 position_delta, uint8 *subq_output)
+{
+ assert(subq_check_checksum(subq_input));
+
+
+ subq_generate_checksum(subq_output);
+}
+#endif
+
+void scrambleize_data_sector(uint8 *sector_data)
+{
+ for(unsigned i = 12; i < 2352; i++)
+ sector_data[i] ^= scramble_table[i - 12];
+}
+
+}
diff --git a/psx/octoshock/cdrom/CDUtility.h b/psx/octoshock/cdrom/CDUtility.h
new file mode 100644
index 0000000000..896d145459
--- /dev/null
+++ b/psx/octoshock/cdrom/CDUtility.h
@@ -0,0 +1,227 @@
+#ifndef __MDFN_CDROM_CDUTILITY_H
+#define __MDFN_CDROM_CDUTILITY_H
+
+#include
+
+namespace CDUtility
+{
+ // Call once at app startup before creating any threads that could potentially cause re-entrancy to these functions.
+ // It will also be called automatically if needed for the first time a function in this namespace that requires
+ // the initialization function to be called is called, for potential
+ // usage in constructors of statically-declared objects.
+ void CDUtility_Init(void);
+
+ // Quick definitions here:
+ //
+ // ABA - Absolute block address, synonymous to absolute MSF
+ // aba = (m_a * 60 * 75) + (s_a * 75) + f_a
+ //
+ // LBA - Logical block address(related: data CDs are required to have a pregap of 2 seconds, IE 150 frames/sectors)
+ // lba = aba - 150
+
+
+ enum
+ {
+ ADR_NOQINFO = 0x00,
+ ADR_CURPOS = 0x01,
+ ADR_MCN = 0x02,
+ ADR_ISRC = 0x03
+ };
+
+
+ struct TOC_Track
+ {
+ uint8 adr;
+ uint8 control;
+ uint32 lba;
+ };
+
+ // SubQ control field flags.
+ enum
+ {
+ SUBQ_CTRLF_PRE = 0x01, // With 50/15us pre-emphasis.
+ SUBQ_CTRLF_DCP = 0x02, // Digital copy permitted.
+ SUBQ_CTRLF_DATA = 0x04, // Data track.
+ SUBQ_CTRLF_4CH = 0x08, // 4-channel CD-DA.
+ };
+
+ enum
+ {
+ DISC_TYPE_CDDA_OR_M1 = 0x00,
+ DISC_TYPE_CD_I = 0x10,
+ DISC_TYPE_CD_XA = 0x20
+ };
+
+ struct TOC
+ {
+ INLINE TOC()
+ {
+ Clear();
+ }
+
+ INLINE void Clear(void)
+ {
+ first_track = last_track = 0;
+ disc_type = 0;
+
+ memset(tracks, 0, sizeof(tracks)); // FIXME if we change TOC_Track to non-POD type.
+ }
+
+ INLINE int FindTrackByLBA(uint32 LBA)
+ {
+ for(int32 track = first_track; track <= (last_track + 1); track++)
+ {
+ if(track == (last_track + 1))
+ {
+ if(LBA < tracks[100].lba)
+ return(track - 1);
+ }
+ else
+ {
+ if(LBA < tracks[track].lba)
+ return(track - 1);
+ }
+ }
+ return(0);
+ }
+
+ uint8 first_track;
+ uint8 last_track;
+ uint8 disc_type;
+ TOC_Track tracks[100 + 1]; // [0] is unused, [100] is for the leadout track.
+ // Also, for convenience, tracks[last_track + 1] will always refer
+ // to the leadout track(even if last_track < 99, IE the leadout track details are duplicated).
+ };
+
+ //
+ // Address conversion functions.
+ //
+ static INLINE uint32 AMSF_to_ABA(int32 m_a, int32 s_a, int32 f_a)
+ {
+ return(f_a + 75 * s_a + 75 * 60 * m_a);
+ }
+
+ static INLINE void ABA_to_AMSF(uint32 aba, uint8 *m_a, uint8 *s_a, uint8 *f_a)
+ {
+ *m_a = aba / 75 / 60;
+ *s_a = (aba - *m_a * 75 * 60) / 75;
+ *f_a = aba - (*m_a * 75 * 60) - (*s_a * 75);
+ }
+
+ static INLINE int32 ABA_to_LBA(uint32 aba)
+ {
+ return(aba - 150);
+ }
+
+ static INLINE uint32 LBA_to_ABA(int32 lba)
+ {
+ return(lba + 150);
+ }
+
+ static INLINE int32 AMSF_to_LBA(uint8 m_a, uint8 s_a, uint8 f_a)
+ {
+ return(ABA_to_LBA(AMSF_to_ABA(m_a, s_a, f_a)));
+ }
+
+ static INLINE void LBA_to_AMSF(int32 lba, uint8 *m_a, uint8 *s_a, uint8 *f_a)
+ {
+ ABA_to_AMSF(LBA_to_ABA(lba), m_a, s_a, f_a);
+ }
+
+ //
+ // BCD conversion functions
+ //
+ static INLINE bool BCD_is_valid(uint8 bcd_number)
+ {
+ if((bcd_number & 0xF0) >= 0xA0)
+ return(false);
+
+ if((bcd_number & 0x0F) >= 0x0A)
+ return(false);
+
+ return(true);
+ }
+
+ static INLINE uint8 BCD_to_U8(uint8 bcd_number)
+ {
+ return( ((bcd_number >> 4) * 10) + (bcd_number & 0x0F) );
+ }
+
+ static INLINE uint8 U8_to_BCD(uint8 num)
+ {
+ return( ((num / 10) << 4) + (num % 10) );
+ }
+
+ // should always perform the conversion, even if the bcd number is invalid.
+ static INLINE bool BCD_to_U8_check(uint8 bcd_number, uint8 *out_number)
+ {
+ *out_number = BCD_to_U8(bcd_number);
+
+ if(!BCD_is_valid(bcd_number))
+ return(false);
+
+ return(true);
+ }
+
+ //
+ // Sector data encoding functions(to full 2352 bytes raw sector).
+ //
+ // sector_data must be able to contain at least 2352 bytes.
+ void encode_mode0_sector(uint32 aba, uint8 *sector_data);
+ void encode_mode1_sector(uint32 aba, uint8 *sector_data); // 2048 bytes of user data at offset 16
+ void encode_mode2_sector(uint32 aba, uint8 *sector_data); // 2336 bytes of user data at offset 16
+ void encode_mode2_form1_sector(uint32 aba, uint8 *sector_data); // 2048+8 bytes of user data at offset 16
+ void encode_mode2_form2_sector(uint32 aba, uint8 *sector_data); // 2324+8 bytes of user data at offset 16
+
+
+ // out_buf must be able to contain 2352+96 bytes.
+ // "mode" is only used if(toc.tracks[100].control & 0x4)
+ void synth_leadout_sector_lba(const uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf);
+
+ //
+ // User data error detection and correction
+ //
+
+ // Check EDC of a mode 1 or mode 2 form 1 sector.
+ // Returns "true" if checksum is ok(matches).
+ // Returns "false" if checksum mismatch.
+ // sector_data should contain 2352 bytes of raw sector data.
+ bool edc_check(const uint8 *sector_data, bool xa);
+
+ // Check EDC and L-EC data of a mode 1 or mode 2 form 1 sector, and correct bit errors if any exist.
+ // Returns "true" if errors weren't detected, or they were corrected succesfully.
+ // Returns "false" if errors couldn't be corrected.
+ // sector_data should contain 2352 bytes of raw sector data.
+ bool edc_lec_check_and_correct(uint8 *sector_data, bool xa);
+
+ //
+ // Subchannel(Q in particular) functions
+ //
+
+ // Returns false on checksum mismatch, true on match.
+ bool subq_check_checksum(const uint8 *subq_buf);
+
+ // Calculates the checksum of Q subchannel data(not including the checksum bytes of course ;)) from subq_buf, and stores it into the appropriate position
+ // in subq_buf.
+ void subq_generate_checksum(uint8 *subq_buf);
+
+ // Deinterleaves 12 bytes of subchannel Q data from 96 bytes of interleaved subchannel PW data.
+ void subq_deinterleave(const uint8 *subpw_buf, uint8 *subq_buf);
+
+ // 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);
+
+ // 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);
+
+ // Extrapolates Q subchannel current position data from subq_input, with frame/sector delta position_delta, and writes to subq_output.
+ // Only valid for ADR_CURPOS.
+ // subq_input must pass subq_check_checksum().
+ // TODO
+ //void subq_extrapolate(const uint8 *subq_input, int32 position_delta, uint8 *subq_output);
+
+ // (De)Scrambles data sector.
+ void scrambleize_data_sector(uint8 *sector_data);
+}
+
+#endif
diff --git a/psx/octoshock/cdrom/SimpleFIFO.cpp b/psx/octoshock/cdrom/SimpleFIFO.cpp
new file mode 100644
index 0000000000..5232837d15
--- /dev/null
+++ b/psx/octoshock/cdrom/SimpleFIFO.cpp
@@ -0,0 +1,6 @@
+#include "../mednafen.h"
+#include "SimpleFIFO.h"
+
+
+
+
diff --git a/psx/octoshock/cdrom/SimpleFIFO.h b/psx/octoshock/cdrom/SimpleFIFO.h
new file mode 100644
index 0000000000..5ec831d6b5
--- /dev/null
+++ b/psx/octoshock/cdrom/SimpleFIFO.h
@@ -0,0 +1,140 @@
+#ifndef __MDFN_SIMPLEFIFO_H
+#define __MDFN_SIMPLEFIFO_H
+
+#include
+#include
+
+#include "../math_ops.h"
+
+template
+class SimpleFIFO
+{
+ public:
+
+ // Constructor
+ SimpleFIFO(uint32 the_size) // Size should be a power of 2!
+ {
+ data.resize((std::vector::size_type)round_up_pow2(the_size));
+ size = the_size;
+ read_pos = 0;
+ write_pos = 0;
+ in_count = 0;
+ }
+
+ // Destructor
+ INLINE ~SimpleFIFO()
+ {
+
+ }
+
+ INLINE void SaveStatePostLoad(void)
+ {
+ read_pos %= data.size();
+ write_pos %= data.size();
+ in_count %= (data.size() + 1);
+ }
+
+#if 0
+ INLINE int StateAction(StateMem *sm, int load, int data_only, const char* sname)
+ {
+ SFORMAT StateRegs[] =
+ {
+ std::vector data;
+ uint32 size;
+
+ SFVAR(read_pos),
+ SFVAR(write_pos),
+ SFVAR(in_count),
+ SFEND;
+ }
+ int ret = MDFNSS_StateAction(sm, load, data_only, sname);
+
+ if(load)
+ {
+ read_pos %= data.size();
+ write_pos %= data.size();
+ in_count %= (data.size() + 1);
+ }
+
+ return(ret);
+ }
+#endif
+
+ INLINE uint32 CanRead(void)
+ {
+ return(in_count);
+ }
+
+ INLINE uint32 CanWrite(void)
+ {
+ return(size - in_count);
+ }
+
+ INLINE T ReadUnit(bool peek = false)
+ {
+ T ret;
+
+ assert(in_count > 0);
+
+ ret = data[read_pos];
+
+ if(!peek)
+ {
+ read_pos = (read_pos + 1) & (data.size() - 1);
+ in_count--;
+ }
+
+ return(ret);
+ }
+
+ INLINE uint8 ReadByte(bool peek = false)
+ {
+ assert(sizeof(T) == 1);
+
+ return(ReadUnit(peek));
+ }
+
+ INLINE void Write(const T *happy_data, uint32 happy_count)
+ {
+ assert(CanWrite() >= happy_count);
+
+ while(happy_count)
+ {
+ data[write_pos] = *happy_data;
+
+ write_pos = (write_pos + 1) & (data.size() - 1);
+ in_count++;
+ happy_data++;
+ happy_count--;
+ }
+ }
+
+ INLINE void WriteUnit(const T& wr_data)
+ {
+ Write(&wr_data, 1);
+ }
+
+ INLINE void WriteByte(const T& wr_data)
+ {
+ assert(sizeof(T) == 1);
+ Write(&wr_data, 1);
+ }
+
+
+ INLINE void Flush(void)
+ {
+ read_pos = 0;
+ write_pos = 0;
+ in_count = 0;
+ }
+
+ //private:
+ std::vector data;
+ uint32 size;
+ uint32 read_pos; // Read position
+ uint32 write_pos; // Write position
+ uint32 in_count; // Number of units in the FIFO
+};
+
+
+#endif
diff --git a/psx/octoshock/cdrom/cdromif.cpp b/psx/octoshock/cdrom/cdromif.cpp
new file mode 100644
index 0000000000..7fddb300ca
--- /dev/null
+++ b/psx/octoshock/cdrom/cdromif.cpp
@@ -0,0 +1,915 @@
+/* Mednafen - Multi-system Emulator
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "../mednafen.h"
+#include
+#include
+#include
+#include "cdromif.h"
+#include "CDAccess.h"
+#include "../general.h"
+
+#include
+
+using namespace CDUtility;
+
+enum
+{
+ // Status/Error messages
+ CDIF_MSG_DONE = 0, // Read -> emu. args: No args.
+ CDIF_MSG_INFO, // Read -> emu. args: str_message
+ CDIF_MSG_FATAL_ERROR, // Read -> emu. args: *TODO ARGS*
+
+ //
+ // Command messages.
+ //
+ CDIF_MSG_DIEDIEDIE, // Emu -> read
+
+ CDIF_MSG_READ_SECTOR, /* Emu -> read
+ args[0] = lba
+ */
+
+ CDIF_MSG_EJECT, // Emu -> read, args[0]; 0=insert, 1=eject
+};
+
+class CDIF_Message
+{
+ public:
+
+ CDIF_Message();
+ CDIF_Message(unsigned int message_, uint32 arg0 = 0, uint32 arg1 = 0, uint32 arg2 = 0, uint32 arg3 = 0);
+ CDIF_Message(unsigned int message_, const std::string &str);
+ ~CDIF_Message();
+
+ unsigned int message;
+ uint32 args[4];
+ void *parg;
+ std::string str_message;
+};
+
+class CDIF_Queue
+{
+ public:
+
+ CDIF_Queue();
+ ~CDIF_Queue();
+
+ bool Read(CDIF_Message *message, bool blocking = TRUE);
+
+ void Write(const CDIF_Message &message);
+
+ private:
+ std::queue ze_queue;
+ MDFN_Mutex *ze_mutex;
+ MDFN_Cond *ze_cond;
+};
+
+
+typedef struct
+{
+ bool valid;
+ bool error;
+ uint32 lba;
+ uint8 data[2352 + 96];
+} CDIF_Sector_Buffer;
+
+// TODO: prohibit copy constructor
+class CDIF_MT : public CDIF
+{
+ public:
+
+ CDIF_MT(CDAccess *cda);
+ virtual ~CDIF_MT();
+
+ virtual void HintReadSector(uint32 lba);
+ virtual bool ReadRawSector(uint8 *buf, uint32 lba);
+
+ // Return true if operation succeeded or it was a NOP(either due to not being implemented, or the current status matches eject_status).
+ // Returns false on failure(usually drive error of some kind; not completely fatal, can try again).
+ virtual bool Eject(bool eject_status);
+
+ // FIXME: Semi-private:
+ int ReadThreadStart(void);
+
+ private:
+
+ CDAccess *disc_cdaccess;
+
+ MDFN_Thread *CDReadThread;
+
+ // Queue for messages to the read thread.
+ CDIF_Queue ReadThreadQueue;
+
+ // Queue for messages to the emu thread.
+ CDIF_Queue EmuThreadQueue;
+
+
+ enum { SBSize = 256 };
+ CDIF_Sector_Buffer SectorBuffers[SBSize];
+
+ uint32 SBWritePos;
+
+ MDFN_Mutex *SBMutex;
+ MDFN_Cond *SBCond;
+
+
+ //
+ // Read-thread-only:
+ //
+ void RT_EjectDisc(bool eject_status, bool skip_actual_eject = false);
+
+ uint32 ra_lba;
+ int ra_count;
+ uint32 last_read_lba;
+};
+
+
+// TODO: prohibit copy constructor
+class CDIF_ST : public CDIF
+{
+ public:
+
+ CDIF_ST(CDAccess *cda);
+ virtual ~CDIF_ST();
+
+ virtual void HintReadSector(uint32 lba);
+ virtual bool ReadRawSector(uint8 *buf, uint32 lba);
+ virtual bool Eject(bool eject_status);
+
+ private:
+ CDAccess *disc_cdaccess;
+};
+
+CDIF::CDIF() : UnrecoverableError(false), is_phys_cache(false), DiscEjected(false)
+{
+
+}
+
+CDIF::~CDIF()
+{
+
+}
+
+
+CDIF_Message::CDIF_Message()
+{
+ message = 0;
+
+ memset(args, 0, sizeof(args));
+}
+
+CDIF_Message::CDIF_Message(unsigned int message_, uint32 arg0, uint32 arg1, uint32 arg2, uint32 arg3)
+{
+ message = message_;
+ args[0] = arg0;
+ args[1] = arg1;
+ args[2] = arg2;
+ args[3] = arg3;
+}
+
+CDIF_Message::CDIF_Message(unsigned int message_, const std::string &str)
+{
+ message = message_;
+ str_message = str;
+}
+
+CDIF_Message::~CDIF_Message()
+{
+
+}
+
+CDIF_Queue::CDIF_Queue()
+{
+ ze_mutex = MDFND_CreateMutex();
+ ze_cond = MDFND_CreateCond();
+}
+
+CDIF_Queue::~CDIF_Queue()
+{
+ MDFND_DestroyMutex(ze_mutex);
+ MDFND_DestroyCond(ze_cond);
+}
+
+// Returns FALSE if message not read, TRUE if it was read. Will always return TRUE if "blocking" is set.
+// Will throw MDFN_Error if the read message code is CDIF_MSG_FATAL_ERROR
+bool CDIF_Queue::Read(CDIF_Message *message, bool blocking)
+{
+ bool ret = true;
+
+ //
+ //
+ //
+ MDFND_LockMutex(ze_mutex);
+
+ if(blocking)
+ {
+ while(ze_queue.size() == 0) // while, not just if.
+ {
+ MDFND_WaitCond(ze_cond, ze_mutex);
+ }
+ }
+
+ if(ze_queue.size() == 0)
+ ret = false;
+ else
+ {
+ *message = ze_queue.front();
+ ze_queue.pop();
+ }
+
+ MDFND_UnlockMutex(ze_mutex);
+ //
+ //
+ //
+
+ if(ret && message->message == CDIF_MSG_FATAL_ERROR)
+ throw MDFN_Error(0, "%s", message->str_message.c_str());
+
+ return(ret);
+}
+
+void CDIF_Queue::Write(const CDIF_Message &message)
+{
+ MDFND_LockMutex(ze_mutex);
+
+ try
+ {
+ ze_queue.push(message);
+ }
+ catch(...)
+ {
+ fprintf(stderr, "\n\nCDIF_Message queue push failed!!! (We now return you to your regularly unscheduled lockup)\n\n");
+ }
+
+ MDFND_SignalCond(ze_cond); // Signal while the mutex is held to prevent icky race conditions.
+
+ MDFND_UnlockMutex(ze_mutex);
+}
+
+
+void CDIF_MT::RT_EjectDisc(bool eject_status, bool skip_actual_eject)
+{
+ if(eject_status != DiscEjected)
+ {
+ if(!skip_actual_eject)
+ disc_cdaccess->Eject(eject_status);
+
+ // Set after ->Eject(), since it might throw an exception.
+ DiscEjected = -1; // For if TOC reading fails or there's something horribly wrong with the disc.
+
+ if(!eject_status) // Re-read the TOC
+ {
+ disc_cdaccess->Read_TOC(&disc_toc);
+
+ if(disc_toc.first_track < 1 || disc_toc.last_track > 99 || disc_toc.first_track > disc_toc.last_track)
+ {
+ throw(MDFN_Error(0, _("TOC first(%d)/last(%d) track numbers bad."), disc_toc.first_track, disc_toc.last_track));
+ }
+ }
+ DiscEjected = eject_status;
+
+ SBWritePos = 0;
+ ra_lba = 0;
+ ra_count = 0;
+ last_read_lba = ~0U;
+ memset(SectorBuffers, 0, SBSize * sizeof(CDIF_Sector_Buffer));
+ }
+}
+
+struct RTS_Args
+{
+ CDIF_MT *cdif_ptr;
+};
+
+static int ReadThreadStart_C(void *v_arg)
+{
+ RTS_Args *args = (RTS_Args *)v_arg;
+
+ return args->cdif_ptr->ReadThreadStart();
+}
+
+int CDIF_MT::ReadThreadStart()
+{
+ bool Running = TRUE;
+
+ DiscEjected = true;
+ SBWritePos = 0;
+ ra_lba = 0;
+ ra_count = 0;
+ last_read_lba = ~0U;
+
+ try
+ {
+ RT_EjectDisc(false, true);
+ }
+ catch(std::exception &e)
+ {
+ EmuThreadQueue.Write(CDIF_Message(CDIF_MSG_FATAL_ERROR, std::string(e.what())));
+ return(0);
+ }
+
+ is_phys_cache = disc_cdaccess->Is_Physical();
+
+ EmuThreadQueue.Write(CDIF_Message(CDIF_MSG_DONE));
+
+ while(Running)
+ {
+ CDIF_Message msg;
+
+ // Only do a blocking-wait for a message if we don't have any sectors to read-ahead.
+ // MDFN_DispMessage("%d %d %d\n", last_read_lba, ra_lba, ra_count);
+ if(ReadThreadQueue.Read(&msg, ra_count ? FALSE : TRUE))
+ {
+ switch(msg.message)
+ {
+ case CDIF_MSG_DIEDIEDIE:
+ Running = FALSE;
+ break;
+
+ case CDIF_MSG_EJECT:
+ try
+ {
+ RT_EjectDisc(msg.args[0]);
+ EmuThreadQueue.Write(CDIF_Message(CDIF_MSG_DONE));
+ }
+ catch(std::exception &e)
+ {
+ EmuThreadQueue.Write(CDIF_Message(CDIF_MSG_FATAL_ERROR, std::string(e.what())));
+ }
+ break;
+
+ case CDIF_MSG_READ_SECTOR:
+ {
+ static const int max_ra = 16;
+ static const int initial_ra = 1;
+ static const int speedmult_ra = 2;
+ uint32 new_lba = msg.args[0];
+
+ assert((unsigned int)max_ra < (SBSize / 4));
+
+ if(last_read_lba != ~0U && new_lba == (last_read_lba + 1))
+ {
+ int how_far_ahead = ra_lba - new_lba;
+
+ if(how_far_ahead <= max_ra)
+ ra_count = std::min(speedmult_ra, 1 + max_ra - how_far_ahead);
+ else
+ ra_count++;
+ }
+ else if(new_lba != last_read_lba)
+ {
+ ra_lba = new_lba;
+ ra_count = initial_ra;
+ }
+
+ last_read_lba = new_lba;
+ }
+ break;
+ }
+ }
+
+ // Don't read >= the "end" of the disc, silly snake. Slither.
+ if(ra_count && ra_lba == disc_toc.tracks[100].lba)
+ {
+ ra_count = 0;
+ //printf("Ephemeral scarabs: %d!\n", ra_lba);
+ }
+
+ if(ra_count)
+ {
+ uint8 tmpbuf[2352 + 96];
+ bool error_condition = false;
+
+ try
+ {
+ disc_cdaccess->Read_Raw_Sector(tmpbuf, ra_lba);
+ }
+ catch(std::exception &e)
+ {
+ MDFN_PrintError(_("Sector %u read error: %s"), ra_lba, e.what());
+ memset(tmpbuf, 0, sizeof(tmpbuf));
+ error_condition = true;
+ }
+
+ //
+ //
+ MDFND_LockMutex(SBMutex);
+
+ SectorBuffers[SBWritePos].lba = ra_lba;
+ memcpy(SectorBuffers[SBWritePos].data, tmpbuf, 2352 + 96);
+ SectorBuffers[SBWritePos].valid = TRUE;
+ SectorBuffers[SBWritePos].error = error_condition;
+ SBWritePos = (SBWritePos + 1) % SBSize;
+
+ MDFND_SignalCond(SBCond);
+
+ MDFND_UnlockMutex(SBMutex);
+ //
+ //
+
+ ra_lba++;
+ ra_count--;
+ }
+ }
+
+ return(1);
+}
+
+CDIF_MT::CDIF_MT(CDAccess *cda) : disc_cdaccess(cda), CDReadThread(NULL), SBMutex(NULL), SBCond(NULL)
+{
+ try
+ {
+ CDIF_Message msg;
+ RTS_Args s;
+
+ if(!(SBMutex = MDFND_CreateMutex()))
+ throw MDFN_Error(0, _("Error creating CD read thread mutex."));
+
+ if(!(SBCond = MDFND_CreateCond()))
+ throw MDFN_Error(0, _("Error creating CD read thread condition variable."));
+
+ UnrecoverableError = false;
+
+ s.cdif_ptr = this;
+
+ if(!(CDReadThread = MDFND_CreateThread(ReadThreadStart_C, &s)))
+ throw MDFN_Error(0, _("Error creating CD read thread."));
+
+ EmuThreadQueue.Read(&msg);
+ }
+ catch(...)
+ {
+ if(CDReadThread)
+ {
+ MDFND_WaitThread(CDReadThread, NULL);
+ CDReadThread = NULL;
+ }
+
+ if(SBMutex)
+ {
+ MDFND_DestroyMutex(SBMutex);
+ SBMutex = NULL;
+ }
+
+ if(SBCond)
+ {
+ MDFND_DestroyCond(SBCond);
+ SBCond = NULL;
+ }
+
+ if(disc_cdaccess)
+ {
+ delete disc_cdaccess;
+ disc_cdaccess = NULL;
+ }
+
+ throw;
+ }
+}
+
+
+CDIF_MT::~CDIF_MT()
+{
+ bool thread_deaded_failed = false;
+
+ try
+ {
+ ReadThreadQueue.Write(CDIF_Message(CDIF_MSG_DIEDIEDIE));
+ }
+ catch(std::exception &e)
+ {
+ MDFND_PrintError(e.what());
+ thread_deaded_failed = true;
+ }
+
+ if(!thread_deaded_failed)
+ MDFND_WaitThread(CDReadThread, NULL);
+
+ if(SBMutex)
+ {
+ MDFND_DestroyMutex(SBMutex);
+ SBMutex = NULL;
+ }
+
+ if(SBCond)
+ {
+ MDFND_DestroyCond(SBCond);
+ SBCond = NULL;
+ }
+
+ if(disc_cdaccess)
+ {
+ delete disc_cdaccess;
+ disc_cdaccess = NULL;
+ }
+}
+
+bool CDIF::ValidateRawSector(uint8 *buf)
+{
+ int mode = buf[12 + 3];
+
+ if(mode != 0x1 && mode != 0x2)
+ return(false);
+
+ if(!edc_lec_check_and_correct(buf, mode == 2))
+ return(false);
+
+ return(true);
+}
+
+bool CDIF_MT::ReadRawSector(uint8 *buf, uint32 lba)
+{
+ bool found = FALSE;
+ bool error_condition = false;
+
+ if(UnrecoverableError)
+ {
+ memset(buf, 0, 2352 + 96);
+ return(false);
+ }
+
+ // This shouldn't happen, the emulated-system-specific CDROM emulation code should make sure the emulated program doesn't try
+ // to read past the last "real" sector of the disc.
+ if(lba >= disc_toc.tracks[100].lba)
+ {
+ printf("Attempt to read LBA %d, >= LBA %d\n", lba, disc_toc.tracks[100].lba);
+ return(FALSE);
+ }
+
+ ReadThreadQueue.Write(CDIF_Message(CDIF_MSG_READ_SECTOR, lba));
+
+ //
+ //
+ //
+ MDFND_LockMutex(SBMutex);
+
+ do
+ {
+ for(int i = 0; i < SBSize; i++)
+ {
+ if(SectorBuffers[i].valid && SectorBuffers[i].lba == lba)
+ {
+ error_condition = SectorBuffers[i].error;
+ memcpy(buf, SectorBuffers[i].data, 2352 + 96);
+ found = TRUE;
+ }
+ }
+
+ if(!found)
+ {
+ //int32 swt = MDFND_GetTime();
+ MDFND_WaitCond(SBCond, SBMutex);
+ //printf("SB Waited: %d\n", MDFND_GetTime() - swt);
+ }
+ } while(!found);
+
+ MDFND_UnlockMutex(SBMutex);
+ //
+ //
+ //
+
+
+ return(!error_condition);
+}
+
+void CDIF_MT::HintReadSector(uint32 lba)
+{
+ if(UnrecoverableError)
+ return;
+
+ ReadThreadQueue.Write(CDIF_Message(CDIF_MSG_READ_SECTOR, lba));
+}
+
+int CDIF::ReadSector(uint8* pBuf, uint32 lba, uint32 nSectors)
+{
+ int ret = 0;
+
+ if(UnrecoverableError)
+ return(false);
+
+ while(nSectors--)
+ {
+ uint8 tmpbuf[2352 + 96];
+
+ if(!ReadRawSector(tmpbuf, lba))
+ {
+ puts("CDIF Raw Read error");
+ return(FALSE);
+ }
+
+ if(!ValidateRawSector(tmpbuf))
+ {
+ MDFN_DispMessage(_("Uncorrectable data at sector %d"), lba);
+ MDFN_PrintError(_("Uncorrectable data at sector %d"), lba);
+ return(false);
+ }
+
+ const int mode = tmpbuf[12 + 3];
+
+ if(!ret)
+ ret = mode;
+
+ if(mode == 1)
+ {
+ memcpy(pBuf, &tmpbuf[12 + 4], 2048);
+ }
+ else if(mode == 2)
+ {
+ memcpy(pBuf, &tmpbuf[12 + 4 + 8], 2048);
+ }
+ else
+ {
+ printf("CDIF_ReadSector() invalid sector type at LBA=%u\n", (unsigned int)lba);
+ return(false);
+ }
+
+ pBuf += 2048;
+ lba++;
+ }
+
+ return(ret);
+}
+
+bool CDIF_MT::Eject(bool eject_status)
+{
+ if(UnrecoverableError)
+ return(false);
+
+ try
+ {
+ CDIF_Message msg;
+
+ ReadThreadQueue.Write(CDIF_Message(CDIF_MSG_EJECT, eject_status));
+ EmuThreadQueue.Read(&msg);
+ }
+ catch(std::exception &e)
+ {
+ MDFN_PrintError(_("Error on eject/insert attempt: %s"), e.what());
+ return(false);
+ }
+
+ return(true);
+}
+
+//
+//
+// Single-threaded implementation follows.
+//
+//
+
+CDIF_ST::CDIF_ST(CDAccess *cda) : disc_cdaccess(cda)
+{
+ //puts("***WARNING USING SINGLE-THREADED CD READER***");
+
+ is_phys_cache = disc_cdaccess->Is_Physical();
+ UnrecoverableError = false;
+ DiscEjected = false;
+
+ disc_cdaccess->Read_TOC(&disc_toc);
+
+ if(disc_toc.first_track < 1 || disc_toc.last_track > 99 || disc_toc.first_track > disc_toc.last_track)
+ {
+ throw(MDFN_Error(0, _("TOC first(%d)/last(%d) track numbers bad."), disc_toc.first_track, disc_toc.last_track));
+ }
+}
+
+CDIF_ST::~CDIF_ST()
+{
+ if(disc_cdaccess)
+ {
+ delete disc_cdaccess;
+ disc_cdaccess = NULL;
+ }
+}
+
+void CDIF_ST::HintReadSector(uint32 lba)
+{
+ // TODO: disc_cdaccess seek hint? (probably not, would require asynchronousitycamel)
+}
+
+bool CDIF_ST::ReadRawSector(uint8 *buf, uint32 lba)
+{
+ if(UnrecoverableError)
+ {
+ memset(buf, 0, 2352 + 96);
+ return(false);
+ }
+
+ try
+ {
+ disc_cdaccess->Read_Raw_Sector(buf, lba);
+ }
+ catch(std::exception &e)
+ {
+ MDFN_PrintError(_("Sector %u read error: %s"), lba, e.what());
+ memset(buf, 0, 2352 + 96);
+ return(false);
+ }
+
+ return(true);
+}
+
+bool CDIF_ST::Eject(bool eject_status)
+{
+ if(UnrecoverableError)
+ return(false);
+
+ try
+ {
+ if(eject_status != DiscEjected)
+ {
+ disc_cdaccess->Eject(eject_status);
+
+ // Set after ->Eject(), since it might throw an exception.
+ DiscEjected = -1; // For if TOC reading fails or there's something horribly wrong with the disc.
+
+ if(!eject_status) // Re-read the TOC
+ {
+ disc_cdaccess->Read_TOC(&disc_toc);
+
+ if(disc_toc.first_track < 1 || disc_toc.last_track > 99 || disc_toc.first_track > disc_toc.last_track)
+ {
+ throw(MDFN_Error(0, _("TOC first(%d)/last(%d) track numbers bad."), disc_toc.first_track, disc_toc.last_track));
+ }
+ }
+ DiscEjected = eject_status;
+ }
+ }
+ catch(std::exception &e)
+ {
+ MDFN_PrintError("%s", e.what());
+ return(false);
+ }
+
+ return(true);
+}
+
+
+class CDIF_Stream_Thing : public Stream
+{
+ public:
+
+ CDIF_Stream_Thing(CDIF *cdintf_arg, uint32 lba_arg, uint32 sector_count_arg);
+ ~CDIF_Stream_Thing();
+
+ virtual uint64 attributes(void);
+ virtual uint8 *map(void);
+ virtual void unmap(void);
+
+ virtual uint64 read(void *data, uint64 count, bool error_on_eos = true);
+ virtual void write(const void *data, uint64 count);
+
+ virtual void seek(int64 offset, int whence);
+ virtual int64 tell(void);
+ virtual int64 size(void);
+ virtual void close(void);
+
+ private:
+ CDIF *cdintf;
+ const uint32 start_lba;
+ const uint32 sector_count;
+ int64 position;
+};
+
+CDIF_Stream_Thing::CDIF_Stream_Thing(CDIF *cdintf_arg, uint32 start_lba_arg, uint32 sector_count_arg) : cdintf(cdintf_arg), start_lba(start_lba_arg), sector_count(sector_count_arg)
+{
+
+}
+
+CDIF_Stream_Thing::~CDIF_Stream_Thing()
+{
+
+}
+
+uint64 CDIF_Stream_Thing::attributes(void)
+{
+ return(ATTRIBUTE_READABLE | ATTRIBUTE_SEEKABLE);
+}
+
+uint8 *CDIF_Stream_Thing::map(void)
+{
+ return NULL;
+}
+
+void CDIF_Stream_Thing::unmap(void)
+{
+
+}
+
+uint64 CDIF_Stream_Thing::read(void *data, uint64 count, bool error_on_eos)
+{
+ if(count > (((uint64)sector_count * 2048) - position))
+ {
+ if(error_on_eos)
+ {
+ throw MDFN_Error(0, "EOF");
+ }
+
+ count = ((uint64)sector_count * 2048) - position;
+ }
+
+ if(!count)
+ return(0);
+
+ for(uint64 rp = position; rp < (position + count); rp = (rp &~ 2047) + 2048)
+ {
+ uint8 buf[2048];
+
+ if(!cdintf->ReadSector(buf, start_lba + (rp / 2048), 1))
+ {
+ throw MDFN_Error(ErrnoHolder(EIO));
+ }
+
+ //::printf("Meow: %08llx -- %08llx\n", count, (rp - position) + std::min(2048 - (rp & 2047), count - (rp - position)));
+ memcpy((uint8*)data + (rp - position), buf + (rp & 2047), std::min(2048 - (rp & 2047), count - (rp - position)));
+ }
+
+ position += count;
+
+ return count;
+}
+
+void CDIF_Stream_Thing::write(const void *data, uint64 count)
+{
+ throw MDFN_Error(ErrnoHolder(EBADF));
+}
+
+void CDIF_Stream_Thing::seek(int64 offset, int whence)
+{
+ int64 new_position;
+
+ switch(whence)
+ {
+ default:
+ throw MDFN_Error(ErrnoHolder(EINVAL));
+ break;
+
+ case SEEK_SET:
+ new_position = offset;
+ break;
+
+ case SEEK_CUR:
+ new_position = position + offset;
+ break;
+
+ case SEEK_END:
+ new_position = ((int64)sector_count * 2048) + offset;
+ break;
+ }
+
+ if(new_position < 0 || new_position > ((int64)sector_count * 2048))
+ throw MDFN_Error(ErrnoHolder(EINVAL));
+
+ position = new_position;
+}
+
+int64 CDIF_Stream_Thing::tell(void)
+{
+ return position;
+}
+
+int64 CDIF_Stream_Thing::size(void)
+{
+ return(sector_count * 2048);
+}
+
+void CDIF_Stream_Thing::close(void)
+{
+
+}
+
+
+Stream *CDIF::MakeStream(uint32 lba, uint32 sector_count)
+{
+ return new CDIF_Stream_Thing(this, lba, sector_count);
+}
+
+
+CDIF *CDIF_Open(const char *path, const bool is_device, bool image_memcache)
+{
+ if(is_device)
+ return new CDIF_MT(cdaccess_open_phys(path));
+ else
+ {
+ CDAccess *cda = cdaccess_open_image(path, image_memcache);
+
+ if(!image_memcache)
+ return new CDIF_MT(cda);
+ else
+ return new CDIF_ST(cda);
+ }
+}
diff --git a/psx/octoshock/cdrom/cdromif.h b/psx/octoshock/cdrom/cdromif.h
new file mode 100644
index 0000000000..8b0a0bbcd4
--- /dev/null
+++ b/psx/octoshock/cdrom/cdromif.h
@@ -0,0 +1,70 @@
+/* Mednafen - Multi-system Emulator
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __MDFN_CDROM_CDROMIF_H
+#define __MDFN_CDROM_CDROMIF_H
+
+#include "CDUtility.h"
+#include "../Stream.h"
+
+#include
+
+typedef CDUtility::TOC CD_TOC;
+
+class CDIF
+{
+ public:
+
+ CDIF();
+ virtual ~CDIF();
+
+ inline void ReadTOC(CDUtility::TOC *read_target)
+ {
+ *read_target = disc_toc;
+ }
+
+ virtual void HintReadSector(uint32 lba) = 0;
+ virtual bool ReadRawSector(uint8 *buf, uint32 lba) = 0;
+
+ // Call for mode 1 or mode 2 form 1 only.
+ bool ValidateRawSector(uint8 *buf);
+
+ // Utility/Wrapped functions
+ // Reads mode 1 and mode2 form 1 sectors(2048 bytes per sector returned)
+ // Will return the type(1, 2) of the first sector read to the buffer supplied, 0 on error
+ int ReadSector(uint8* pBuf, uint32 lba, uint32 nSectors);
+
+ // Return true if operation succeeded or it was a NOP(either due to not being implemented, or the current status matches eject_status).
+ // Returns false on failure(usually drive error of some kind; not completely fatal, can try again).
+ virtual bool Eject(bool eject_status) = 0;
+
+ inline bool IsPhysical(void) { return(is_phys_cache); }
+
+ // For Mode 1, or Mode 2 Form 1.
+ // No reference counting or whatever is done, so if you destroy the CDIF object before you destroy the returned Stream, things will go BOOM.
+ Stream *MakeStream(uint32 lba, uint32 sector_count);
+
+ protected:
+ bool UnrecoverableError;
+ bool is_phys_cache;
+ CDUtility::TOC disc_toc;
+ int DiscEjected; // 0 = inserted, 1 = ejected, -1 = DRAGONS ATE THE DISC. NOM NOM NOM.
+};
+
+CDIF *CDIF_Open(const char *path, const bool is_device, bool image_memcache);
+
+#endif
diff --git a/psx/octoshock/cdrom/crc32.cpp b/psx/octoshock/cdrom/crc32.cpp
new file mode 100644
index 0000000000..9b3b2c8e6b
--- /dev/null
+++ b/psx/octoshock/cdrom/crc32.cpp
@@ -0,0 +1,130 @@
+/* dvdisaster: Additional error correction for optical media.
+ * Copyright (C) 2004-2007 Carsten Gnoerlich.
+ * Project home page: http://www.dvdisaster.com
+ * Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
+ *
+ * CRC32 code based upon public domain code by Ross Williams (see notes below)
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
+ * or direct your browser at http://www.gnu.org.
+ */
+
+#include "dvdisaster.h"
+
+/***
+ *** EDC checksum used in CDROM sectors
+ ***/
+
+/*****************************************************************/
+/* */
+/* CRC LOOKUP TABLE */
+/* ================ */
+/* The following CRC lookup table was generated automagically */
+/* by the Rocksoft^tm Model CRC Algorithm Table Generation */
+/* Program V1.0 using the following model parameters: */
+/* */
+/* Width : 4 bytes. */
+/* Poly : 0x8001801BL */
+/* Reverse : TRUE. */
+/* */
+/* For more information on the Rocksoft^tm Model CRC Algorithm, */
+/* see the document titled "A Painless Guide to CRC Error */
+/* Detection Algorithms" by Ross Williams */
+/* (ross@guest.adelaide.edu.au.). This document is likely to be */
+/* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */
+/* */
+/*****************************************************************/
+
+unsigned long edctable[256] =
+{
+ 0x00000000L, 0x90910101L, 0x91210201L, 0x01B00300L,
+ 0x92410401L, 0x02D00500L, 0x03600600L, 0x93F10701L,
+ 0x94810801L, 0x04100900L, 0x05A00A00L, 0x95310B01L,
+ 0x06C00C00L, 0x96510D01L, 0x97E10E01L, 0x07700F00L,
+ 0x99011001L, 0x09901100L, 0x08201200L, 0x98B11301L,
+ 0x0B401400L, 0x9BD11501L, 0x9A611601L, 0x0AF01700L,
+ 0x0D801800L, 0x9D111901L, 0x9CA11A01L, 0x0C301B00L,
+ 0x9FC11C01L, 0x0F501D00L, 0x0EE01E00L, 0x9E711F01L,
+ 0x82012001L, 0x12902100L, 0x13202200L, 0x83B12301L,
+ 0x10402400L, 0x80D12501L, 0x81612601L, 0x11F02700L,
+ 0x16802800L, 0x86112901L, 0x87A12A01L, 0x17302B00L,
+ 0x84C12C01L, 0x14502D00L, 0x15E02E00L, 0x85712F01L,
+ 0x1B003000L, 0x8B913101L, 0x8A213201L, 0x1AB03300L,
+ 0x89413401L, 0x19D03500L, 0x18603600L, 0x88F13701L,
+ 0x8F813801L, 0x1F103900L, 0x1EA03A00L, 0x8E313B01L,
+ 0x1DC03C00L, 0x8D513D01L, 0x8CE13E01L, 0x1C703F00L,
+ 0xB4014001L, 0x24904100L, 0x25204200L, 0xB5B14301L,
+ 0x26404400L, 0xB6D14501L, 0xB7614601L, 0x27F04700L,
+ 0x20804800L, 0xB0114901L, 0xB1A14A01L, 0x21304B00L,
+ 0xB2C14C01L, 0x22504D00L, 0x23E04E00L, 0xB3714F01L,
+ 0x2D005000L, 0xBD915101L, 0xBC215201L, 0x2CB05300L,
+ 0xBF415401L, 0x2FD05500L, 0x2E605600L, 0xBEF15701L,
+ 0xB9815801L, 0x29105900L, 0x28A05A00L, 0xB8315B01L,
+ 0x2BC05C00L, 0xBB515D01L, 0xBAE15E01L, 0x2A705F00L,
+ 0x36006000L, 0xA6916101L, 0xA7216201L, 0x37B06300L,
+ 0xA4416401L, 0x34D06500L, 0x35606600L, 0xA5F16701L,
+ 0xA2816801L, 0x32106900L, 0x33A06A00L, 0xA3316B01L,
+ 0x30C06C00L, 0xA0516D01L, 0xA1E16E01L, 0x31706F00L,
+ 0xAF017001L, 0x3F907100L, 0x3E207200L, 0xAEB17301L,
+ 0x3D407400L, 0xADD17501L, 0xAC617601L, 0x3CF07700L,
+ 0x3B807800L, 0xAB117901L, 0xAAA17A01L, 0x3A307B00L,
+ 0xA9C17C01L, 0x39507D00L, 0x38E07E00L, 0xA8717F01L,
+ 0xD8018001L, 0x48908100L, 0x49208200L, 0xD9B18301L,
+ 0x4A408400L, 0xDAD18501L, 0xDB618601L, 0x4BF08700L,
+ 0x4C808800L, 0xDC118901L, 0xDDA18A01L, 0x4D308B00L,
+ 0xDEC18C01L, 0x4E508D00L, 0x4FE08E00L, 0xDF718F01L,
+ 0x41009000L, 0xD1919101L, 0xD0219201L, 0x40B09300L,
+ 0xD3419401L, 0x43D09500L, 0x42609600L, 0xD2F19701L,
+ 0xD5819801L, 0x45109900L, 0x44A09A00L, 0xD4319B01L,
+ 0x47C09C00L, 0xD7519D01L, 0xD6E19E01L, 0x46709F00L,
+ 0x5A00A000L, 0xCA91A101L, 0xCB21A201L, 0x5BB0A300L,
+ 0xC841A401L, 0x58D0A500L, 0x5960A600L, 0xC9F1A701L,
+ 0xCE81A801L, 0x5E10A900L, 0x5FA0AA00L, 0xCF31AB01L,
+ 0x5CC0AC00L, 0xCC51AD01L, 0xCDE1AE01L, 0x5D70AF00L,
+ 0xC301B001L, 0x5390B100L, 0x5220B200L, 0xC2B1B301L,
+ 0x5140B400L, 0xC1D1B501L, 0xC061B601L, 0x50F0B700L,
+ 0x5780B800L, 0xC711B901L, 0xC6A1BA01L, 0x5630BB00L,
+ 0xC5C1BC01L, 0x5550BD00L, 0x54E0BE00L, 0xC471BF01L,
+ 0x6C00C000L, 0xFC91C101L, 0xFD21C201L, 0x6DB0C300L,
+ 0xFE41C401L, 0x6ED0C500L, 0x6F60C600L, 0xFFF1C701L,
+ 0xF881C801L, 0x6810C900L, 0x69A0CA00L, 0xF931CB01L,
+ 0x6AC0CC00L, 0xFA51CD01L, 0xFBE1CE01L, 0x6B70CF00L,
+ 0xF501D001L, 0x6590D100L, 0x6420D200L, 0xF4B1D301L,
+ 0x6740D400L, 0xF7D1D501L, 0xF661D601L, 0x66F0D700L,
+ 0x6180D800L, 0xF111D901L, 0xF0A1DA01L, 0x6030DB00L,
+ 0xF3C1DC01L, 0x6350DD00L, 0x62E0DE00L, 0xF271DF01L,
+ 0xEE01E001L, 0x7E90E100L, 0x7F20E200L, 0xEFB1E301L,
+ 0x7C40E400L, 0xECD1E501L, 0xED61E601L, 0x7DF0E700L,
+ 0x7A80E800L, 0xEA11E901L, 0xEBA1EA01L, 0x7B30EB00L,
+ 0xE8C1EC01L, 0x7850ED00L, 0x79E0EE00L, 0xE971EF01L,
+ 0x7700F000L, 0xE791F101L, 0xE621F201L, 0x76B0F300L,
+ 0xE541F401L, 0x75D0F500L, 0x7460F600L, 0xE4F1F701L,
+ 0xE381F801L, 0x7310F900L, 0x72A0FA00L, 0xE231FB01L,
+ 0x71C0FC00L, 0xE151FD01L, 0xE0E1FE01L, 0x7070FF00L
+};
+
+/*
+ * CDROM EDC calculation
+ */
+
+uint32 EDCCrc32(const unsigned char *data, int len)
+{
+ uint32 crc = 0;
+
+ while(len--)
+ crc = edctable[(crc ^ *data++) & 0xFF] ^ (crc >> 8);
+
+ return crc;
+}
diff --git a/psx/octoshock/cdrom/dvdisaster.h b/psx/octoshock/cdrom/dvdisaster.h
new file mode 100644
index 0000000000..a3e79de6d2
--- /dev/null
+++ b/psx/octoshock/cdrom/dvdisaster.h
@@ -0,0 +1,172 @@
+/* dvdisaster: Additional error correction for optical media.
+ * Copyright (C) 2004-2007 Carsten Gnoerlich.
+ * Project home page: http://www.dvdisaster.com
+ * Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
+ * or direct your browser at http://www.gnu.org.
+ */
+
+#ifndef DVDISASTER_H
+#define DVDISASTER_H
+
+/* "Dare to be gorgeous and unique.
+ * But don't ever be cryptic or otherwise unfathomable.
+ * Make it unforgettably great."
+ *
+ * From "A Final Note on Style",
+ * Amiga Intuition Reference Manual, 1986, p. 231
+ */
+
+/***
+ *** I'm too lazy to mess with #include dependencies.
+ *** Everything #includeable is rolled up herein...
+ */
+
+#include "octoshock.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+/***
+ *** dvdisaster.c
+ ***/
+
+void PrepareDeadSector(void);
+
+void CreateEcc(void);
+void FixEcc(void);
+void Verify(void);
+
+uint32 EDCCrc32(const unsigned char*, int);
+
+/***
+ *** galois.c
+ ***
+ * This is currently the hardcoded GF(2**8).
+ * int32 gives abundant space for the GF.
+ * Squeezing it down to uint8 won't probably gain much,
+ * so we implement this defensively here.
+ *
+ * Note that some performance critical stuff needs to
+ * be #included from galois-inlines.h
+ */
+
+/* Galois field parameters for 8bit symbol Reed-Solomon code */
+
+#define GF_SYMBOLSIZE 8
+#define GF_FIELDSIZE (1<= GF_FIELDMAX)
+ {
+ x -= GF_FIELDMAX;
+ x = (x >> GF_SYMBOLSIZE) + (x & GF_FIELDMAX);
+ }
+
+ return x;
+}
diff --git a/psx/octoshock/cdrom/galois.cpp b/psx/octoshock/cdrom/galois.cpp
new file mode 100644
index 0000000000..2792cfc341
--- /dev/null
+++ b/psx/octoshock/cdrom/galois.cpp
@@ -0,0 +1,156 @@
+/* dvdisaster: Additional error correction for optical media.
+ * Copyright (C) 2004-2007 Carsten Gnoerlich.
+ * Project home page: http://www.dvdisaster.com
+ * Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
+ *
+ * The Reed-Solomon error correction draws a lot of inspiration - and even code -
+ * from Phil Karn's excellent Reed-Solomon library: http://www.ka9q.net/code/fec/
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
+ * or direct your browser at http://www.gnu.org.
+ */
+
+#include "dvdisaster.h"
+
+#include "galois-inlines.h"
+
+/***
+ *** Galois field arithmetic.
+ ***
+ * Calculations are done over the extension field GF(2**n).
+ * Be careful not to overgeneralize these arithmetics;
+ * they only work for the case of GF(p**n) with p being prime.
+ */
+
+/* Initialize the Galois field tables */
+
+
+GaloisTables* CreateGaloisTables(int32 gf_generator)
+{
+ GaloisTables *gt = (GaloisTables *)calloc(1, sizeof(GaloisTables));
+ int32 b,log;
+
+ /* Allocate the tables.
+ The encoder uses a special version of alpha_to which has the mod_fieldmax()
+ folded into the table. */
+
+ gt->gfGenerator = gf_generator;
+
+ gt->indexOf = (int32 *)calloc(GF_FIELDSIZE, sizeof(int32));
+ gt->alphaTo = (int32 *)calloc(GF_FIELDSIZE, sizeof(int32));
+ gt->encAlphaTo = (int32 *)calloc(2*GF_FIELDSIZE, sizeof(int32));
+
+ /* create the log/ilog values */
+
+ for(b=1, log=0; logindexOf[b] = log;
+ gt->alphaTo[log] = b;
+ b = b << 1;
+ if(b & GF_FIELDSIZE)
+ b = b ^ gf_generator;
+ }
+
+ if(b!=1)
+ {
+ printf("Failed to create the Galois field log tables!\n");
+ exit(1);
+ }
+
+ /* we're even closed using infinity (makes things easier) */
+
+ gt->indexOf[0] = GF_ALPHA0; /* log(0) = inf */
+ gt->alphaTo[GF_ALPHA0] = 0; /* and the other way around */
+
+ for(b=0; b<2*GF_FIELDSIZE; b++)
+ gt->encAlphaTo[b] = gt->alphaTo[mod_fieldmax(b)];
+
+ return gt;
+}
+
+void FreeGaloisTables(GaloisTables *gt)
+{
+ if(gt->indexOf) free(gt->indexOf);
+ if(gt->alphaTo) free(gt->alphaTo);
+ if(gt->encAlphaTo) free(gt->encAlphaTo);
+
+ free(gt);
+}
+
+/***
+ *** Create the the Reed-Solomon generator polynomial
+ *** and some auxiliary data structures.
+ */
+
+ReedSolomonTables *CreateReedSolomonTables(GaloisTables *gt,
+ int32 first_consecutive_root,
+ int32 prim_elem,
+ int nroots_in)
+{ ReedSolomonTables *rt = (ReedSolomonTables *)calloc(1, sizeof(ReedSolomonTables));
+ int32 i,j,root;
+
+ rt->gfTables = gt;
+ rt->fcr = first_consecutive_root;
+ rt->primElem = prim_elem;
+ rt->nroots = nroots_in;
+ rt->ndata = GF_FIELDMAX - rt->nroots;
+
+ rt->gpoly = (int32 *)calloc((rt->nroots+1), sizeof(int32));
+
+ /* Create the RS code generator polynomial */
+
+ rt->gpoly[0] = 1;
+
+ for(i=0, root=first_consecutive_root*prim_elem; inroots; i++, root+=prim_elem)
+ { rt->gpoly[i+1] = 1;
+
+ /* Multiply gpoly by alpha**(root+x) */
+
+ for(j=i; j>0; j--)
+ {
+ if(rt->gpoly[j] != 0)
+ rt->gpoly[j] = rt->gpoly[j-1] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[rt->gpoly[j]] + root)];
+ else
+ rt->gpoly[j] = rt->gpoly[j-1];
+ }
+
+ rt->gpoly[0] = gt->alphaTo[mod_fieldmax(gt->indexOf[rt->gpoly[0]] + root)];
+ }
+
+ /* Store the polynomials index for faster encoding */
+
+ for(i=0; i<=rt->nroots; i++)
+ rt->gpoly[i] = gt->indexOf[rt->gpoly[i]];
+
+#if 0
+ /* for the precalculated unrolled loops only */
+
+ for(i=gt->nroots-1; i>0; i--)
+ PrintCLI(
+ " par_idx[((++spk)&%d)] ^= enc_alpha_to[feedback + %3d];\n",
+ nroots-1,gt->gpoly[i]);
+
+ PrintCLI(" par_idx[sp] = enc_alpha_to[feedback + %3d];\n",
+ gt->gpoly[0]);
+#endif
+
+ return rt;
+}
+
+void FreeReedSolomonTables(ReedSolomonTables *rt)
+{
+ if(rt->gpoly) free(rt->gpoly);
+
+ free(rt);
+}
diff --git a/psx/octoshock/cdrom/l-ec.cpp b/psx/octoshock/cdrom/l-ec.cpp
new file mode 100644
index 0000000000..5c035ce4ab
--- /dev/null
+++ b/psx/octoshock/cdrom/l-ec.cpp
@@ -0,0 +1,478 @@
+/* dvdisaster: Additional error correction for optical media.
+ * Copyright (C) 2004-2007 Carsten Gnoerlich.
+ * Project home page: http://www.dvdisaster.com
+ * Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
+ *
+ * The Reed-Solomon error correction draws a lot of inspiration - and even code -
+ * from Phil Karn's excellent Reed-Solomon library: http://www.ka9q.net/code/fec/
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
+ * or direct your browser at http://www.gnu.org.
+ */
+
+#include "dvdisaster.h"
+
+#include "galois-inlines.h"
+
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+/***
+ *** Mapping between cd frame and parity vectors
+ ***/
+
+/*
+ * Mapping of frame bytes to P/Q Vectors
+ */
+
+int PToByteIndex(int p, int i)
+{ return 12 + p + i*86;
+}
+
+void ByteIndexToP(int b, int *p, int *i)
+{ *p = (b-12)%86;
+ *i = (b-12)/86;
+}
+
+int QToByteIndex(int q, int i)
+{ int offset = 12 + (q & 1);
+
+ if(i == 43) return 2248+q;
+ if(i == 44) return 2300+q;
+
+ q&=~1;
+ return offset + (q*43 + i*88) % 2236;
+}
+
+void ByteIndexToQ(int b, int *q, int *i)
+{ int x,y,offset;
+
+ if(b >= 2300)
+ { *i = 44;
+ *q = (b-2300);
+ return;
+ }
+
+ if(b >= 2248)
+ { *i = 43;
+ *q = (b-2248);
+ return;
+ }
+
+ offset = b&1;
+ b = (b-12)/2;
+ x = b/43;
+ y = (b-(x*43))%26;
+ *i = b-(x*43);
+ *q = 2*((x+26-y)%26)+offset;
+}
+
+/*
+ * There are 86 vectors of P-parity, yielding a RS(26,24) code.
+ */
+
+void GetPVector(unsigned char *frame, unsigned char *data, int n)
+{ int i;
+ int w_idx = n+12;
+
+ for(i=0; i<26; i++, w_idx+=86)
+ data[i] = frame[w_idx];
+}
+
+void SetPVector(unsigned char *frame, unsigned char *data, int n)
+{ int i;
+ int w_idx = n+12;
+
+ for(i=0; i<26; i++, w_idx+=86)
+ frame[w_idx] = data[i];
+}
+
+void FillPVector(unsigned char *frame, unsigned char data, int n)
+{ int i;
+ int w_idx = n+12;
+
+ for(i=0; i<26; i++, w_idx+=86)
+ frame[w_idx] = data;
+}
+
+void OrPVector(unsigned char *frame, unsigned char value, int n)
+{ int i;
+ int w_idx = n+12;
+
+ for(i=0; i<26; i++, w_idx+=86)
+ frame[w_idx] |= value;
+}
+
+void AndPVector(unsigned char *frame, unsigned char value, int n)
+{ int i;
+ int w_idx = n+12;
+
+ for(i=0; i<26; i++, w_idx+=86)
+ frame[w_idx] &= value;
+}
+
+/*
+ * There are 52 vectors of Q-parity, yielding a RS(45,43) code.
+ */
+
+void GetQVector(unsigned char *frame, unsigned char *data, int n)
+{ int offset = 12 + (n & 1);
+ int w_idx = (n&~1) * 43;
+ int i;
+
+ for(i=0; i<43; i++, w_idx+=88)
+ data[i] = frame[(w_idx % 2236) + offset];
+
+ data[43] = frame[2248 + n];
+ data[44] = frame[2300 + n];
+}
+
+void SetQVector(unsigned char *frame, unsigned char *data, int n)
+{ int offset = 12 + (n & 1);
+ int w_idx = (n&~1) * 43;
+ int i;
+
+ for(i=0; i<43; i++, w_idx+=88)
+ frame[(w_idx % 2236) + offset] = data[i];
+
+ frame[2248 + n] = data[43];
+ frame[2300 + n] = data[44];
+}
+
+void FillQVector(unsigned char *frame, unsigned char data, int n)
+{ int offset = 12 + (n & 1);
+ int w_idx = (n&~1) * 43;
+ int i;
+
+ for(i=0; i<43; i++, w_idx+=88)
+ frame[(w_idx % 2236) + offset] = data;
+
+ frame[2248 + n] = data;
+ frame[2300 + n] = data;
+}
+
+void OrQVector(unsigned char *frame, unsigned char data, int n)
+{ int offset = 12 + (n & 1);
+ int w_idx = (n&~1) * 43;
+ int i;
+
+ for(i=0; i<43; i++, w_idx+=88)
+ frame[(w_idx % 2236) + offset] |= data;
+
+ frame[2248 + n] |= data;
+ frame[2300 + n] |= data;
+}
+
+void AndQVector(unsigned char *frame, unsigned char data, int n)
+{ int offset = 12 + (n & 1);
+ int w_idx = (n&~1) * 43;
+ int i;
+
+ for(i=0; i<43; i++, w_idx+=88)
+ frame[(w_idx % 2236) + offset] &= data;
+
+ frame[2248 + n] &= data;
+ frame[2300 + n] &= data;
+}
+
+/***
+ *** C2 error counting
+ ***/
+
+int CountC2Errors(unsigned char *frame)
+{ int i,count = 0;
+ frame += 2352;
+
+ for(i=0; i<294; i++, frame++)
+ { if(*frame & 0x01) count++;
+ if(*frame & 0x02) count++;
+ if(*frame & 0x04) count++;
+ if(*frame & 0x08) count++;
+ if(*frame & 0x10) count++;
+ if(*frame & 0x20) count++;
+ if(*frame & 0x40) count++;
+ if(*frame & 0x80) count++;
+ }
+
+ return count;
+}
+
+/***
+ *** L-EC error correction for CD raw data sectors
+ ***/
+
+/*
+ * These could be used from ReedSolomonTables,
+ * but hardcoding them is faster.
+ */
+
+#define NROOTS 2
+#define LEC_FIRST_ROOT 0 //GF_ALPHA0
+#define LEC_PRIM_ELEM 1
+#define LEC_PRIMTH_ROOT 1
+
+/*
+ * Calculate the error syndrome
+ */
+
+int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
+ int *erasure_list, int erasure_count)
+{ GaloisTables *gt = rt->gfTables;
+ int syndrome[NROOTS];
+ int lambda[NROOTS+1];
+ int omega[NROOTS+1];
+ int b[NROOTS+1];
+ int reg[NROOTS+1];
+ int root[NROOTS];
+ int loc[NROOTS];
+ int syn_error;
+ int deg_lambda,lambda_roots;
+ int deg_omega;
+ int shortened_size = GF_FIELDMAX - padding;
+ int corrected = 0;
+ int i,j,k;
+ int r,el;
+
+ /*** Form the syndromes: Evaluate data(x) at roots of g(x) */
+
+ for(i=0; ialphaTo[mod_fieldmax(gt->indexOf[syndrome[i]]
+ + (LEC_FIRST_ROOT+i)*LEC_PRIM_ELEM)];
+
+ /*** Convert syndrome to index form, check for nonzero condition. */
+
+ syn_error = 0;
+ for(i=0; iindexOf[syndrome[i]];
+ }
+
+ /*** If the syndrome is zero, everything is fine. */
+
+ if(!syn_error)
+ return 0;
+
+ /*** Initialize lambda to be the erasure locator polynomial */
+
+ lambda[0] = 1;
+ lambda[1] = lambda[2] = 0;
+
+ erasure_list[0] += padding;
+ erasure_list[1] += padding;
+
+ if(erasure_count > 2) /* sanity check */
+ erasure_count = 0;
+
+ if(erasure_count > 0)
+ { lambda[1] = gt->alphaTo[mod_fieldmax(LEC_PRIM_ELEM*(GF_FIELDMAX-1-erasure_list[0]))];
+
+ for(i=1; i0; j--)
+ { int tmp = gt->indexOf[lambda[j-1]];
+
+ if(tmp != GF_ALPHA0)
+ lambda[j] ^= gt->alphaTo[mod_fieldmax(u + tmp)];
+ }
+ }
+ }
+
+ for(i=0; iindexOf[lambda[i]];
+
+ /*** Berlekamp-Massey algorithm to determine error+erasure locator polynomial */
+
+ r = erasure_count; /* r is the step number */
+ el = erasure_count;
+
+ /* Compute discrepancy at the r-th step in poly-form */
+
+ while(++r <= NROOTS)
+ { int discr_r = 0;
+
+ for(i=0; ialphaTo[mod_fieldmax(gt->indexOf[lambda[i]] + syndrome[r-i-1])];
+
+ discr_r = gt->indexOf[discr_r];
+
+ if(discr_r == GF_ALPHA0)
+ { /* B(x) = x*B(x) */
+ memmove(b+1, b, NROOTS*sizeof(b[0]));
+ b[0] = GF_ALPHA0;
+ }
+ else
+ { int t[NROOTS+1];
+
+ /* T(x) = lambda(x) - discr_r*x*b(x) */
+ t[0] = lambda[0];
+ for(i=0; ialphaTo[mod_fieldmax(discr_r + b[i])];
+ else t[i+1] = lambda[i+1];
+ }
+
+ if(2*el <= r+erasure_count-1)
+ { el = r + erasure_count - el;
+
+ /* B(x) <-- inv(discr_r) * lambda(x) */
+ for(i=0; i<=NROOTS; i++)
+ b[i] = (lambda[i] == 0) ? GF_ALPHA0
+ : mod_fieldmax(gt->indexOf[lambda[i]] - discr_r + GF_FIELDMAX);
+ }
+ else
+ { /* 2 lines below: B(x) <-- x*B(x) */
+ memmove(b+1, b, NROOTS*sizeof(b[0]));
+ b[0] = GF_ALPHA0;
+ }
+
+ memcpy(lambda, t, (NROOTS+1)*sizeof(t[0]));
+ }
+ }
+
+ /*** Convert lambda to index form and compute deg(lambda(x)) */
+
+ deg_lambda = 0;
+ for(i=0; iindexOf[lambda[i]];
+ if(lambda[i] != GF_ALPHA0)
+ deg_lambda = i;
+ }
+
+ /*** Find roots of the error+erasure locator polynomial by Chien search */
+
+ memcpy(reg+1, lambda+1, NROOTS*sizeof(reg[0]));
+ lambda_roots = 0; /* Number of roots of lambda(x) */
+
+ for(i=1, k=LEC_PRIMTH_ROOT-1; i<=GF_FIELDMAX; i++, k=mod_fieldmax(k+LEC_PRIMTH_ROOT))
+ { int q=1; /* lambda[0] is always 0 */
+
+ for(j=deg_lambda; j>0; j--)
+ { if(reg[j] != GF_ALPHA0)
+ { reg[j] = mod_fieldmax(reg[j] + j);
+ q ^= gt->alphaTo[reg[j]];
+ }
+ }
+
+ if(q != 0) continue; /* Not a root */
+
+ /* store root in index-form and the error location number */
+
+ root[lambda_roots] = i;
+ loc[lambda_roots] = k;
+
+ /* If we've already found max possible roots, abort the search to save time */
+
+ if(++lambda_roots == deg_lambda) break;
+ }
+
+ /* deg(lambda) unequal to number of roots => uncorrectable error detected
+ This is not reliable for very small numbers of roots, e.g. nroots = 2 */
+
+ if(deg_lambda != lambda_roots)
+ { return -1;
+ }
+
+ /* Compute err+eras evaluator poly omega(x) = syn(x)*lambda(x)
+ (modulo x**nroots). in index form. Also find deg(omega). */
+
+ deg_omega = deg_lambda-1;
+
+ for(i=0; i<=deg_omega; i++)
+ { int tmp = 0;
+
+ for(j=i; j>=0; j--)
+ { if((syndrome[i - j] != GF_ALPHA0) && (lambda[j] != GF_ALPHA0))
+ tmp ^= gt->alphaTo[mod_fieldmax(syndrome[i - j] + lambda[j])];
+ }
+
+ omega[i] = gt->indexOf[tmp];
+ }
+
+ /* Compute error values in poly-form.
+ num1 = omega(inv(X(l))),
+ num2 = inv(X(l))**(FIRST_ROOT-1) and
+ den = lambda_pr(inv(X(l))) all in poly-form. */
+
+ for(j=lambda_roots-1; j>=0; j--)
+ { int num1 = 0;
+ int num2;
+ int den;
+ int location = loc[j];
+
+ for(i=deg_omega; i>=0; i--)
+ { if(omega[i] != GF_ALPHA0)
+ num1 ^= gt->alphaTo[mod_fieldmax(omega[i] + i * root[j])];
+ }
+
+ num2 = gt->alphaTo[mod_fieldmax(root[j] * (LEC_FIRST_ROOT - 1) + GF_FIELDMAX)];
+ den = 0;
+
+ /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
+
+ for(i=MIN(deg_lambda, NROOTS-1) & ~1; i>=0; i-=2)
+ { if(lambda[i+1] != GF_ALPHA0)
+ den ^= gt->alphaTo[mod_fieldmax(lambda[i+1] + i * root[j])];
+ }
+
+ /* Apply error to data */
+
+ if(num1 != 0 && location >= padding)
+ {
+ corrected++;
+ data[location-padding] ^= gt->alphaTo[mod_fieldmax(gt->indexOf[num1] + gt->indexOf[num2]
+ + GF_FIELDMAX - gt->indexOf[den])];
+
+ /* If no erasures were given, at most one error was corrected.
+ Return its position in erasure_list[0]. */
+
+ if(!erasure_count)
+ erasure_list[0] = location-padding;
+ }
+#if 1
+ else return -3;
+#endif
+ }
+
+ /*** Form the syndromes: Evaluate data(x) at roots of g(x) */
+
+ for(i=0; ialphaTo[mod_fieldmax(gt->indexOf[syndrome[i]]
+ + (LEC_FIRST_ROOT+i)*LEC_PRIM_ELEM)];
+ }
+
+ /*** Convert syndrome to index form, check for nonzero condition. */
+#if 1
+ for(i=0; i
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif
+
+#include
+#include
+
+#include "lec.h"
+
+#define GF8_PRIM_POLY 0x11d /* x^8 + x^4 + x^3 + x^2 + 1 */
+
+#define EDC_POLY 0x8001801b /* (x^16 + x^15 + x^2 + 1) (x^16 + x^2 + x + 1) */
+
+#define LEC_HEADER_OFFSET 12
+#define LEC_DATA_OFFSET 16
+#define LEC_MODE1_DATA_LEN 2048
+#define LEC_MODE1_EDC_OFFSET 2064
+#define LEC_MODE1_INTERMEDIATE_OFFSET 2068
+#define LEC_MODE1_P_PARITY_OFFSET 2076
+#define LEC_MODE1_Q_PARITY_OFFSET 2248
+#define LEC_MODE2_FORM1_DATA_LEN (2048+8)
+#define LEC_MODE2_FORM1_EDC_OFFSET 2072
+#define LEC_MODE2_FORM2_DATA_LEN (2324+8)
+#define LEC_MODE2_FORM2_EDC_OFFSET 2348
+
+
+typedef u_int8_t gf8_t;
+
+static u_int8_t GF8_LOG[256];
+static gf8_t GF8_ILOG[256];
+
+static const class Gf8_Q_Coeffs_Results_01 {
+private:
+ u_int16_t table[43][256];
+public:
+ Gf8_Q_Coeffs_Results_01();
+ ~Gf8_Q_Coeffs_Results_01() {}
+ const u_int16_t *operator[] (int i) const { return &table[i][0]; }
+ operator const u_int16_t *() const { return &table[0][0]; }
+} CF8_Q_COEFFS_RESULTS_01;
+
+static const class CrcTable {
+private:
+ u_int32_t table[256];
+public:
+ CrcTable();
+ ~CrcTable() {}
+ u_int32_t operator[](int i) const { return table[i]; }
+ operator const u_int32_t *() const { return table; }
+} CRCTABLE;
+
+static const class ScrambleTable {
+private:
+ u_int8_t table[2340];
+public:
+ ScrambleTable();
+ ~ScrambleTable() {}
+ u_int8_t operator[](int i) const { return table[i]; }
+ operator const u_int8_t *() const { return table; }
+} SCRAMBLE_TABLE;
+
+/* Creates the logarithm and inverse logarithm table that is required
+ * for performing multiplication in the GF(8) domain.
+ */
+static void gf8_create_log_tables()
+{
+ u_int8_t log;
+ u_int16_t b;
+
+ for (b = 0; b <= 255; b++) {
+ GF8_LOG[b] = 0;
+ GF8_ILOG[b] = 0;
+ }
+
+ b = 1;
+
+ for (log = 0; log < 255; log++) {
+ GF8_LOG[(u_int8_t)b] = log;
+ GF8_ILOG[log] = (u_int8_t)b;
+
+ b <<= 1;
+
+ if ((b & 0x100) != 0)
+ b ^= GF8_PRIM_POLY;
+ }
+}
+
+/* Addition in the GF(8) domain: just the XOR of the values.
+ */
+#define gf8_add(a, b) (a) ^ (b)
+
+
+/* Multiplication in the GF(8) domain: add the logarithms (modulo 255)
+ * and return the inverse logarithm. Not used!
+ */
+#if 0
+static gf8_t gf8_mult(gf8_t a, gf8_t b)
+{
+ int16_t sum;
+
+ if (a == 0 || b == 0)
+ return 0;
+
+ sum = GF8_LOG[a] + GF8_LOG[b];
+
+ if (sum >= 255)
+ sum -= 255;
+
+ return GF8_ILOG[sum];
+}
+#endif
+
+/* Division in the GF(8) domain: Like multiplication but logarithms a
+ * subtracted.
+ */
+static gf8_t gf8_div(gf8_t a, gf8_t b)
+{
+ int16_t sum;
+
+ assert(b != 0);
+
+ if (a == 0)
+ return 0;
+
+ sum = GF8_LOG[a] - GF8_LOG[b];
+
+ if (sum < 0)
+ sum += 255;
+
+ return GF8_ILOG[sum];
+}
+
+Gf8_Q_Coeffs_Results_01::Gf8_Q_Coeffs_Results_01()
+{
+ int i, j;
+ u_int16_t c;
+ gf8_t GF8_COEFFS_HELP[2][45];
+ u_int8_t GF8_Q_COEFFS[2][45];
+
+
+ gf8_create_log_tables();
+
+ /* build matrix H:
+ * 1 1 ... 1 1
+ * a^44 a^43 ... a^1 a^0
+ *
+ *
+ */
+
+ for (j = 0; j < 45; j++) {
+ GF8_COEFFS_HELP[0][j] = 1; /* e0 */
+ GF8_COEFFS_HELP[1][j] = GF8_ILOG[44-j]; /* e1 */
+ }
+
+
+ /* resolve equation system for parity byte 0 and 1 */
+
+ /* e1' = e1 + e0 */
+ for (j = 0; j < 45; j++) {
+ GF8_Q_COEFFS[1][j] = gf8_add(GF8_COEFFS_HELP[1][j],
+ GF8_COEFFS_HELP[0][j]);
+ }
+
+ /* e1'' = e1' / (a^1 + 1) */
+ for (j = 0; j < 45; j++) {
+ GF8_Q_COEFFS[1][j] = gf8_div(GF8_Q_COEFFS[1][j], GF8_Q_COEFFS[1][43]);
+ }
+
+ /* e0' = e0 + e1 / a^1 */
+ for (j = 0; j < 45; j++) {
+ GF8_Q_COEFFS[0][j] = gf8_add(GF8_COEFFS_HELP[0][j],
+ gf8_div(GF8_COEFFS_HELP[1][j],
+ GF8_ILOG[1]));
+ }
+
+ /* e0'' = e0' / (1 + 1 / a^1) */
+ for (j = 0; j < 45; j++) {
+ GF8_Q_COEFFS[0][j] = gf8_div(GF8_Q_COEFFS[0][j], GF8_Q_COEFFS[0][44]);
+ }
+
+ /*
+ * Compute the products of 0..255 with all of the Q coefficients in
+ * advance. When building the scalar product between the data vectors
+ * and the P/Q vectors the individual products can be looked up in
+ * this table
+ *
+ * The P parity coefficients are just a subset of the Q coefficients so
+ * that we do not need to create a separate table for them.
+ */
+
+ for (j = 0; j < 43; j++) {
+
+ table[j][0] = 0;
+
+ for (i = 1; i < 256; i++) {
+ c = GF8_LOG[i] + GF8_LOG[GF8_Q_COEFFS[0][j]];
+ if (c >= 255) c -= 255;
+ table[j][i] = GF8_ILOG[c];
+
+ c = GF8_LOG[i] + GF8_LOG[GF8_Q_COEFFS[1][j]];
+ if (c >= 255) c -= 255;
+ table[j][i] |= GF8_ILOG[c]<<8;
+ }
+ }
+}
+
+/* Reverses the bits in 'd'. 'bits' defines the bit width of 'd'.
+ */
+static u_int32_t mirror_bits(u_int32_t d, int bits)
+{
+ int i;
+ u_int32_t r = 0;
+
+ for (i = 0; i < bits; i++) {
+ r <<= 1;
+
+ if ((d & 0x1) != 0)
+ r |= 0x1;
+
+ d >>= 1;
+ }
+
+ return r;
+}
+
+/* Build the CRC lookup table for EDC_POLY poly. The CRC is 32 bit wide
+ * and reversed (i.e. the bit stream is divided by the EDC_POLY with the
+ * LSB first order).
+ */
+CrcTable::CrcTable ()
+{
+ u_int32_t i, j;
+ u_int32_t r;
+
+ for (i = 0; i < 256; i++) {
+ r = mirror_bits(i, 8);
+
+ r <<= 24;
+
+ for (j = 0; j < 8; j++) {
+ if ((r & 0x80000000) != 0) {
+ r <<= 1;
+ r ^= EDC_POLY;
+ }
+ else {
+ r <<= 1;
+ }
+ }
+
+ r = mirror_bits(r, 32);
+
+ table[i] = r;
+ }
+}
+
+/* Calculates the CRC of given data with given lengths based on the
+ * table lookup algorithm.
+ */
+static u_int32_t calc_edc(u_int8_t *data, int len)
+{
+ u_int32_t crc = 0;
+
+ while (len--) {
+ crc = CRCTABLE[(int)(crc ^ *data++) & 0xff] ^ (crc >> 8);
+ }
+
+ return crc;
+}
+
+/* Build the scramble table as defined in the yellow book. The bytes
+ 12 to 2351 of a sector will be XORed with the data of this table.
+ */
+ScrambleTable::ScrambleTable()
+{
+ u_int16_t i, j;
+ u_int16_t reg = 1;
+ u_int8_t d;
+
+ for (i = 0; i < 2340; i++) {
+ d = 0;
+
+ for (j = 0; j < 8; j++) {
+ d >>= 1;
+
+ if ((reg & 0x1) != 0)
+ d |= 0x80;
+
+ if ((reg & 0x1) != ((reg >> 1) & 0x1)) {
+ reg >>= 1;
+ reg |= 0x4000; /* 15-bit register */
+ }
+ else {
+ reg >>= 1;
+ }
+ }
+
+ table[i] = d;
+ }
+}
+
+/* Calc EDC for a MODE 1 sector
+ */
+static void calc_mode1_edc(u_int8_t *sector)
+{
+ u_int32_t crc = calc_edc(sector, LEC_MODE1_DATA_LEN + 16);
+
+ sector[LEC_MODE1_EDC_OFFSET] = crc & 0xffL;
+ sector[LEC_MODE1_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
+ sector[LEC_MODE1_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
+ sector[LEC_MODE1_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
+}
+
+/* Calc EDC for a XA form 1 sector
+ */
+static void calc_mode2_form1_edc(u_int8_t *sector)
+{
+ u_int32_t crc = calc_edc(sector + LEC_DATA_OFFSET,
+ LEC_MODE2_FORM1_DATA_LEN);
+
+ sector[LEC_MODE2_FORM1_EDC_OFFSET] = crc & 0xffL;
+ sector[LEC_MODE2_FORM1_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
+ sector[LEC_MODE2_FORM1_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
+ sector[LEC_MODE2_FORM1_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
+}
+
+/* Calc EDC for a XA form 2 sector
+ */
+static void calc_mode2_form2_edc(u_int8_t *sector)
+{
+ u_int32_t crc = calc_edc(sector + LEC_DATA_OFFSET,
+ LEC_MODE2_FORM2_DATA_LEN);
+
+ sector[LEC_MODE2_FORM2_EDC_OFFSET] = crc & 0xffL;
+ sector[LEC_MODE2_FORM2_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
+ sector[LEC_MODE2_FORM2_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
+ sector[LEC_MODE2_FORM2_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
+}
+
+/* Writes the sync pattern to the given sector.
+ */
+static void set_sync_pattern(u_int8_t *sector)
+{
+ sector[0] = 0;
+
+ sector[1] = sector[2] = sector[3] = sector[4] = sector[5] =
+ sector[6] = sector[7] = sector[8] = sector[9] = sector[10] = 0xff;
+
+ sector[11] = 0;
+}
+
+
+static u_int8_t bin2bcd(u_int8_t b)
+{
+ return (((b/10) << 4) & 0xf0) | ((b%10) & 0x0f);
+}
+
+/* Builds the sector header.
+ */
+static void set_sector_header(u_int8_t mode, u_int32_t adr, u_int8_t *sector)
+{
+ sector[LEC_HEADER_OFFSET] = bin2bcd(adr / (60*75));
+ sector[LEC_HEADER_OFFSET + 1] = bin2bcd((adr / 75) % 60);
+ sector[LEC_HEADER_OFFSET + 2] = bin2bcd(adr % 75);
+ sector[LEC_HEADER_OFFSET + 3] = mode;
+}
+
+/* Calculate the P parities for the sector.
+ * The 43 P vectors of length 24 are combined with the GF8_P_COEFFS.
+ */
+static void calc_P_parity(u_int8_t *sector)
+{
+ int i, j;
+ u_int16_t p01_msb, p01_lsb;
+ u_int8_t *p_lsb_start;
+ u_int8_t *p_lsb;
+ u_int8_t *p0, *p1;
+ u_int8_t d0,d1;
+
+ p_lsb_start = sector + LEC_HEADER_OFFSET;
+
+ p1 = sector + LEC_MODE1_P_PARITY_OFFSET;
+ p0 = sector + LEC_MODE1_P_PARITY_OFFSET + 2 * 43;
+
+ for (i = 0; i <= 42; i++) {
+ p_lsb = p_lsb_start;
+
+ p01_lsb = p01_msb = 0;
+
+ for (j = 19; j <= 42; j++) {
+ d0 = *p_lsb;
+ d1 = *(p_lsb+1);
+
+ p01_lsb ^= CF8_Q_COEFFS_RESULTS_01[j][d0];
+ p01_msb ^= CF8_Q_COEFFS_RESULTS_01[j][d1];
+
+ p_lsb += 2 * 43;
+ }
+
+ *p0 = p01_lsb;
+ *(p0 + 1) = p01_msb;
+
+ *p1 = p01_lsb>>8;
+ *(p1 + 1) = p01_msb>>8;
+
+ p0 += 2;
+ p1 += 2;
+
+ p_lsb_start += 2;
+ }
+}
+
+/* Calculate the Q parities for the sector.
+ * The 26 Q vectors of length 43 are combined with the GF8_Q_COEFFS.
+ */
+static void calc_Q_parity(u_int8_t *sector)
+{
+ int i, j;
+ u_int16_t q01_lsb, q01_msb;
+ u_int8_t *q_lsb_start;
+ u_int8_t *q_lsb;
+ u_int8_t *q0, *q1, *q_start;
+ u_int8_t d0,d1;
+
+ q_lsb_start = sector + LEC_HEADER_OFFSET;
+
+ q_start = sector + LEC_MODE1_Q_PARITY_OFFSET;
+ q1 = sector + LEC_MODE1_Q_PARITY_OFFSET;
+ q0 = sector + LEC_MODE1_Q_PARITY_OFFSET + 2 * 26;
+
+ for (i = 0; i <= 25; i++) {
+ q_lsb = q_lsb_start;
+
+ q01_lsb = q01_msb = 0;
+
+ for (j = 0; j <= 42; j++) {
+ d0 = *q_lsb;
+ d1 = *(q_lsb+1);
+
+ q01_lsb ^= CF8_Q_COEFFS_RESULTS_01[j][d0];
+ q01_msb ^= CF8_Q_COEFFS_RESULTS_01[j][d1];
+
+ q_lsb += 2 * 44;
+
+ if (q_lsb >= q_start) {
+ q_lsb -= 2 * 1118;
+ }
+ }
+
+ *q0 = q01_lsb;
+ *(q0 + 1) = q01_msb;
+
+ *q1 = q01_lsb>>8;
+ *(q1 + 1) = q01_msb>>8;
+
+ q0 += 2;
+ q1 += 2;
+
+ q_lsb_start += 2 * 43;
+ }
+}
+
+/* Encodes a MODE 0 sector.
+ * 'adr' is the current physical sector address
+ * 'sector' must be 2352 byte wide
+ */
+void lec_encode_mode0_sector(u_int32_t adr, u_int8_t *sector)
+{
+ u_int16_t i;
+
+ set_sync_pattern(sector);
+ set_sector_header(0, adr, sector);
+
+ sector += 16;
+
+ for (i = 0; i < 2336; i++)
+ *sector++ = 0;
+}
+
+/* Encodes a MODE 1 sector.
+ * 'adr' is the current physical sector address
+ * 'sector' must be 2352 byte wide containing 2048 bytes user data at
+ * offset 16
+ */
+void lec_encode_mode1_sector(u_int32_t adr, u_int8_t *sector)
+{
+ set_sync_pattern(sector);
+ set_sector_header(1, adr, sector);
+
+ calc_mode1_edc(sector);
+
+ /* clear the intermediate field */
+ sector[LEC_MODE1_INTERMEDIATE_OFFSET] =
+ sector[LEC_MODE1_INTERMEDIATE_OFFSET + 1] =
+ sector[LEC_MODE1_INTERMEDIATE_OFFSET + 2] =
+ sector[LEC_MODE1_INTERMEDIATE_OFFSET + 3] =
+ sector[LEC_MODE1_INTERMEDIATE_OFFSET + 4] =
+ sector[LEC_MODE1_INTERMEDIATE_OFFSET + 5] =
+ sector[LEC_MODE1_INTERMEDIATE_OFFSET + 6] =
+ sector[LEC_MODE1_INTERMEDIATE_OFFSET + 7] = 0;
+
+ calc_P_parity(sector);
+ calc_Q_parity(sector);
+}
+
+/* Encodes a MODE 2 sector.
+ * 'adr' is the current physical sector address
+ * 'sector' must be 2352 byte wide containing 2336 bytes user data at
+ * offset 16
+ */
+void lec_encode_mode2_sector(u_int32_t adr, u_int8_t *sector)
+{
+ set_sync_pattern(sector);
+ set_sector_header(2, adr, sector);
+}
+
+/* Encodes a XA form 1 sector.
+ * 'adr' is the current physical sector address
+ * 'sector' must be 2352 byte wide containing 2048+8 bytes user data at
+ * offset 16
+ */
+void lec_encode_mode2_form1_sector(u_int32_t adr, u_int8_t *sector)
+{
+ set_sync_pattern(sector);
+
+ calc_mode2_form1_edc(sector);
+
+ /* P/Q partiy must not contain the sector header so clear it */
+ sector[LEC_HEADER_OFFSET] =
+ sector[LEC_HEADER_OFFSET + 1] =
+ sector[LEC_HEADER_OFFSET + 2] =
+ sector[LEC_HEADER_OFFSET + 3] = 0;
+
+ calc_P_parity(sector);
+ calc_Q_parity(sector);
+
+ /* finally add the sector header */
+ set_sector_header(2, adr, sector);
+}
+
+/* Encodes a XA form 2 sector.
+ * 'adr' is the current physical sector address
+ * 'sector' must be 2352 byte wide containing 2324+8 bytes user data at
+ * offset 16
+ */
+void lec_encode_mode2_form2_sector(u_int32_t adr, u_int8_t *sector)
+{
+ set_sync_pattern(sector);
+
+ calc_mode2_form2_edc(sector);
+
+ set_sector_header(2, adr, sector);
+}
+
+/* Scrambles and byte swaps an encoded sector.
+ * 'sector' must be 2352 byte wide.
+ */
+void lec_scramble(u_int8_t *sector)
+{
+ u_int16_t i;
+ const u_int8_t *stable = SCRAMBLE_TABLE;
+ u_int8_t *p = sector;
+ u_int8_t tmp;
+
+
+ for (i = 0; i < 6; i++) {
+ /* just swap bytes of sector sync */
+ tmp = *p;
+ *p = *(p + 1);
+ p++;
+ *p++ = tmp;
+ }
+ for (;i < (2352 / 2); i++) {
+ /* scramble and swap bytes */
+ tmp = *p ^ *stable++;
+ *p = *(p + 1) ^ *stable++;
+ p++;
+ *p++ = tmp;
+ }
+}
+
+#if 0
+#include
+#include
+#include
+#include
+
+int main(int argc, char **argv)
+{
+ char *infile;
+ char *outfile;
+ int fd_in, fd_out;
+ u_int8_t buffer1[2352];
+ u_int8_t buffer2[2352];
+ u_int32_t lba;
+ int i;
+
+#if 0
+ for (i = 0; i < 2048; i++)
+ buffer1[i + 16] = 234;
+
+ lba = 150;
+
+ for (i = 0; i < 100000; i++) {
+ lec_encode_mode1_sector(lba, buffer1);
+ lec_scramble(buffer2);
+ lba++;
+ }
+
+#else
+
+ if (argc != 3)
+ return 1;
+
+ infile = argv[1];
+ outfile = argv[2];
+
+
+ if ((fd_in = open(infile, O_RDONLY)) < 0) {
+ perror("Cannot open input file");
+ return 1;
+ }
+
+ if ((fd_out = open(outfile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) {
+ perror("Cannot open output file");
+ return 1;
+ }
+
+ lba = 150;
+
+ do {
+ if (read(fd_in, buffer1, 2352) != 2352)
+ break;
+
+ switch (*(buffer1 + 12 + 3)) {
+ case 1:
+ memcpy(buffer2 + 16, buffer1 + 16, 2048);
+
+ lec_encode_mode1_sector(lba, buffer2);
+ break;
+
+ case 2:
+ if ((*(buffer1 + 12 + 4 + 2) & 0x20) != 0) {
+ /* form 2 sector */
+ memcpy(buffer2 + 16, buffer1 + 16, 2324 + 8);
+ lec_encode_mode2_form2_sector(lba, buffer2);
+ }
+ else {
+ /* form 1 sector */
+ memcpy(buffer2 + 16, buffer1 + 16, 2048 + 8);
+ lec_encode_mode2_form1_sector(lba, buffer2);
+ }
+ break;
+ }
+
+ if (memcmp(buffer1, buffer2, 2352) != 0) {
+ printf("Verify error at lba %ld\n", lba);
+ }
+
+ lec_scramble(buffer2);
+ write(fd_out, buffer2, 2352);
+
+ lba++;
+ } while (1);
+
+ close(fd_in);
+ close(fd_out);
+
+#endif
+
+ return 0;
+}
+#endif
diff --git a/psx/octoshock/cdrom/lec.h b/psx/octoshock/cdrom/lec.h
new file mode 100644
index 0000000000..c5e874c3f3
--- /dev/null
+++ b/psx/octoshock/cdrom/lec.h
@@ -0,0 +1,77 @@
+/* cdrdao - write audio CD-Rs in disc-at-once mode
+ *
+ * Copyright (C) 1998-2002 Andreas Mueller
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LEC_H__
+#define __LEC_H__
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif
+
+#include
+#include
+
+typedef uint32_t u_int32_t;
+typedef uint16_t u_int16_t;
+typedef uint8_t u_int8_t;
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+/* Encodes a MODE 0 sector.
+ * 'adr' is the current physical sector address
+ * 'sector' must be 2352 byte wide
+ */
+void lec_encode_mode0_sector(u_int32_t adr, u_int8_t *sector);
+
+/* Encodes a MODE 1 sector.
+ * 'adr' is the current physical sector address
+ * 'sector' must be 2352 byte wide containing 2048 bytes user data at
+ * offset 16
+ */
+void lec_encode_mode1_sector(u_int32_t adr, u_int8_t *sector);
+
+/* Encodes a MODE 2 sector.
+ * 'adr' is the current physical sector address
+ * 'sector' must be 2352 byte wide containing 2336 bytes user data at
+ * offset 16
+ */
+void lec_encode_mode2_sector(u_int32_t adr, u_int8_t *sector);
+
+/* Encodes a XA form 1 sector.
+ * 'adr' is the current physical sector address
+ * 'sector' must be 2352 byte wide containing 2048+8 bytes user data at
+ * offset 16
+ */
+void lec_encode_mode2_form1_sector(u_int32_t adr, u_int8_t *sector);
+
+/* Encodes a XA form 2 sector.
+ * 'adr' is the current physical sector address
+ * 'sector' must be 2352 byte wide containing 2324+8 bytes user data at
+ * offset 16
+ */
+void lec_encode_mode2_form2_sector(u_int32_t adr, u_int8_t *sector);
+
+/* Scrambles and byte swaps an encoded sector.
+ * 'sector' must be 2352 byte wide.
+ */
+void lec_scramble(u_int8_t *sector);
+
+#endif
diff --git a/psx/octoshock/cdrom/recover-raw.cpp b/psx/octoshock/cdrom/recover-raw.cpp
new file mode 100644
index 0000000000..78be2e2a54
--- /dev/null
+++ b/psx/octoshock/cdrom/recover-raw.cpp
@@ -0,0 +1,203 @@
+/* dvdisaster: Additional error correction for optical media.
+ * Copyright (C) 2004-2007 Carsten Gnoerlich.
+ * Project home page: http://www.dvdisaster.com
+ * Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
+ * or direct your browser at http://www.gnu.org.
+ */
+
+#include "dvdisaster.h"
+
+static GaloisTables *gt = NULL; /* for L-EC Reed-Solomon */
+static ReedSolomonTables *rt = NULL;
+
+bool Init_LEC_Correct(void)
+{
+ gt = CreateGaloisTables(0x11d);
+ rt = CreateReedSolomonTables(gt, 0, 1, 10);
+
+ return(1);
+}
+
+void Kill_LEC_Correct(void)
+{
+ FreeGaloisTables(gt);
+ FreeReedSolomonTables(rt);
+}
+
+/***
+ *** CD level CRC calculation
+ ***/
+
+/*
+ * Test raw sector against its 32bit CRC.
+ * Returns TRUE if frame is good.
+ */
+
+int CheckEDC(const unsigned char *cd_frame, bool xa_mode)
+{
+ unsigned int expected_crc, real_crc;
+ unsigned int crc_base = xa_mode ? 2072 : 2064;
+
+ expected_crc = cd_frame[crc_base + 0] << 0;
+ expected_crc |= cd_frame[crc_base + 1] << 8;
+ expected_crc |= cd_frame[crc_base + 2] << 16;
+ expected_crc |= cd_frame[crc_base + 3] << 24;
+
+ if(xa_mode)
+ real_crc = EDCCrc32(cd_frame+16, 2056);
+ else
+ real_crc = EDCCrc32(cd_frame, 2064);
+
+ if(expected_crc == real_crc)
+ return(1);
+ else
+ {
+ //printf("Bad EDC CRC: Calculated: %08x, Recorded: %08x\n", real_crc, expected_crc);
+ return(0);
+ }
+}
+
+/***
+ *** A very simple L-EC error correction.
+ ***
+ * Perform just one pass over the Q and P vectors to see if everything
+ * is okay respectively correct minor errors. This is pretty much the
+ * same stuff the drive is supposed to do in the final L-EC stage.
+ */
+
+static int simple_lec(unsigned char *frame)
+{
+ unsigned char byte_state[2352];
+ unsigned char p_vector[P_VECTOR_SIZE];
+ unsigned char q_vector[Q_VECTOR_SIZE];
+ unsigned char p_state[P_VECTOR_SIZE];
+ int erasures[Q_VECTOR_SIZE], erasure_count;
+ int ignore[2];
+ int p_failures, q_failures;
+ int p_corrected, q_corrected;
+ int p,q;
+
+ /* Setup */
+
+ memset(byte_state, 0, 2352);
+
+ p_failures = q_failures = 0;
+ p_corrected = q_corrected = 0;
+
+ /* Perform Q-Parity error correction */
+
+ for(q=0; q 2)
+ { GetPVector(byte_state, p_state, p);
+ erasure_count = 0;
+
+ for(i=0; i 0 && erasure_count <= 2)
+ { GetPVector(frame, p_vector, p);
+ err = DecodePQ(rt, p_vector, P_PADDING, erasures, erasure_count);
+ }
+ }
+
+ /* See what we've got */
+
+ if(err < 0) /* Uncorrectable. */
+ { p_failures++;
+ }
+ else /* Correctable. */
+ { if(err == 1 || err == 2) /* Store back corrected vector */
+ { SetPVector(frame, p_vector, p);
+ p_corrected++;
+ }
+ }
+ }
+
+ /* Sum up */
+
+ if(q_failures || p_failures || q_corrected || p_corrected)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+/***
+ *** Validate CD raw sector
+ ***/
+
+int ValidateRawSector(unsigned char *frame, bool xaMode)
+{
+ int lec_did_sth = FALSE_0;
+
+ /* Do simple L-EC.
+ It seems that drives stop their internal L-EC as soon as the
+ EDC is okay, so we may see uncorrected errors in the parity bytes.
+ Since we are also interested in the user data only and doing the
+ L-EC is expensive, we skip our L-EC as well when the EDC is fine. */
+
+ if(!CheckEDC(frame, xaMode))
+ {
+ lec_did_sth = simple_lec(frame);
+ }
+ /* Test internal sector checksum again */
+
+ if(!CheckEDC(frame, xaMode))
+ {
+ /* EDC failure in RAW sector */
+ return FALSE_0;
+ }
+
+ return TRUE_1;
+}
+
diff --git a/psx/octoshock/emuware/PACKED.h b/psx/octoshock/emuware/PACKED.h
new file mode 100644
index 0000000000..eaef0c7a40
--- /dev/null
+++ b/psx/octoshock/emuware/PACKED.h
@@ -0,0 +1,12 @@
+#ifndef __GNUC__
+#pragma pack(push, 1)
+#pragma warning(disable : 4103)
+#endif
+
+#ifndef __PACKED
+ #ifdef __GNUC__
+ #define __PACKED __attribute__((__packed__))
+ #else
+ #define __PACKED
+ #endif
+#endif
diff --git a/psx/octoshock/emuware/PACKED_END.h b/psx/octoshock/emuware/PACKED_END.h
new file mode 100644
index 0000000000..6eb7bd7c15
--- /dev/null
+++ b/psx/octoshock/emuware/PACKED_END.h
@@ -0,0 +1,3 @@
+#ifndef __GNUC__
+#pragma pack(pop)
+#endif
diff --git a/psx/octoshock/emuware/emuware.cpp b/psx/octoshock/emuware/emuware.cpp
new file mode 100644
index 0000000000..02119e1d59
--- /dev/null
+++ b/psx/octoshock/emuware/emuware.cpp
@@ -0,0 +1,3 @@
+#include "emuware.h"
+
+//this file intentionally empty
\ No newline at end of file
diff --git a/psx/octoshock/emuware/emuware.h b/psx/octoshock/emuware/emuware.h
new file mode 100644
index 0000000000..15481a1f53
--- /dev/null
+++ b/psx/octoshock/emuware/emuware.h
@@ -0,0 +1,73 @@
+#pragma once
+
+#include
+#include
+
+typedef __int64 s64;
+typedef __int32 s32;
+typedef __int16 s16;
+typedef __int8 s8;
+typedef unsigned __int64 u64;
+typedef unsigned __int32 u32;
+typedef unsigned __int16 u16;
+typedef unsigned __int8 u8;
+
+typedef __int64 int64;
+typedef __int32 int32;
+typedef __int16 int16;
+typedef __int8 int8;
+typedef unsigned __int64 uint64;
+typedef unsigned __int32 uint32;
+typedef unsigned __int16 uint16;
+typedef unsigned __int8 uint8;
+
+//#define MDFN_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
+#define MDFN_WARN_UNUSED_RESULT
+
+//#define MDFN_COLD __attribute__((cold))
+#define MDFN_COLD
+
+//#define NO_INLINE __attribute__((noinline))
+#define NO_INLINE
+
+//#define MDFN_UNLIKELY(n) __builtin_expect((n) != 0, 0)
+//#define MDFN_LIKELY(n) __builtin_expect((n) != 0, 1)
+#define MDFN_UNLIKELY(n) (n)
+#define MDFN_LIKELY(n) (n)
+
+//#define MDFN_NOWARN_UNUSED __attribute__((unused))
+#define MDFN_NOWARN_UNUSED
+
+//#define MDFN_FORMATSTR(a,b,c) __attribute__ ((format (a, b, c)))
+#define MDFN_FORMATSTR(a,b,c)
+
+#define INLINE inline
+
+#ifdef _MSC_VER
+ #define snprintf _snprintf
+ #define vsnprintf _vsnprintf
+ #define strcasecmp _stricmp
+ #define strncasecmp _strnicmp
+#endif
+
+#define TRUE_1 1
+#define FALSE_0 0
+
+//------------alignment macros-------------
+//dont apply these to types without further testing. it only works portably here on declarations of variables
+//cant we find a pattern other people use more successfully?
+#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
+#define EW_VAR_ALIGN(X) __declspec(align(X))
+#elif defined(__GNUC__)
+#define EW_VAR_ALIGN(X) __attribute__ ((aligned (X)))
+#else
+#error
+#endif
+//---------------------------------------------
+
+#ifdef EW_EXPORT
+#undef EW_EXPORT
+#define EW_EXPORT extern "C" __declspec(dllexport)
+#else
+#define EW_EXPORT extern "C" __declspec(dllimport)
+#endif
diff --git a/psx/octoshock/emuware/msvc/changelog.txt b/psx/octoshock/emuware/msvc/changelog.txt
new file mode 100644
index 0000000000..cf0539c253
--- /dev/null
+++ b/psx/octoshock/emuware/msvc/changelog.txt
@@ -0,0 +1,138 @@
+------------------------------------------------------------------------
+r26 | 2009-10-02 13:36:47 +0400 | 2 lines
+
+[Issue 5] Change to "stdint.h" to let compiler search for it in local directory.
+
+------------------------------------------------------------------------
+r25 | 2009-09-17 23:46:49 +0400 | 2 lines
+
+[Issue 4] Fix incorrect int8_t behaviour if compiled with /J flag.
+
+------------------------------------------------------------------------
+r24 | 2009-05-13 14:53:48 +0400 | 2 lines
+
+Forgot about #ifdef __cplusplus guard around 'extern "C"', so inclusion to C files has been broken.
+
+------------------------------------------------------------------------
+r23 | 2009-05-12 01:27:45 +0400 | 3 lines
+
+[Issue 2] Always wrap is included.
+
+------------------------------------------------------------------------
+r19 | 2007-07-04 02:14:40 +0400 | 3 lines
+
+Explicitly cast to appropriate type INT8_MIN, INT16_MIN, INT32_MIN and INT64_MIN constants.
+Due to their unusual definition in Visual Studio headers (-_Ix_MAX-1) they are propagated to int and thus do not have expected type, causing VS6 strict compiler to claim about type inconsistency.
+
+------------------------------------------------------------------------
+r18 | 2007-06-26 16:53:23 +0400 | 2 lines
+
+Better handling of (U)INTx_C macros - now they generate constants of exact width.
+
+------------------------------------------------------------------------
+r17 | 2007-03-29 20:16:14 +0400 | 2 lines
+
+Fix typo: Miscrosoft -> Microsoft.
+
+------------------------------------------------------------------------
+r16 | 2007-02-24 17:32:58 +0300 | 4 lines
+
+Remove include, as it is not present in Visual Studio 2005 Epxress Edition and required only for INT_PTR and UINT_PTR types.
+
+'intptr_t' and 'uintptr_t' types now defined explicitly with #ifdef _WIN64.
+
+------------------------------------------------------------------------
+r15 | 2007-02-11 20:53:05 +0300 | 2 lines
+
+More correct fix for compilation under VS6.
+
+------------------------------------------------------------------------
+r14 | 2007-02-11 20:04:32 +0300 | 2 lines
+
+Bugfix: fix compiling under VS6, when stdint.h enclosed in 'extern "C" {}'.
+
+------------------------------------------------------------------------
+r13 | 2006-12-13 16:53:11 +0300 | 2 lines
+
+Make _inline modifier for imaxdiv default option. Use STATIC_IMAXDIV to make it static.
+
+------------------------------------------------------------------------
+r12 | 2006-12-13 16:42:24 +0300 | 2 lines
+
+Error message changed: VC6 supported from now.
+
+------------------------------------------------------------------------
+r11 | 2006-12-13 16:39:33 +0300 | 2 lines
+
+All (U)INT* types changed to (unsigned) __int*. This should make stdint.h compatible with VC6.
+
+------------------------------------------------------------------------
+r10 | 2006-12-13 16:20:57 +0300 | 3 lines
+
+Added INLINE_IMAXDIV define switch.
+If INLINE_IMAXDIV is defined imaxdiv() have static modifier. If not - it is _inline.
+
+------------------------------------------------------------------------
+r9 | 2006-12-13 15:53:52 +0300 | 2 lines
+
+Error message for non-MSC compiler changed.
+
+------------------------------------------------------------------------
+r8 | 2006-12-13 12:47:48 +0300 | 2 lines
+
+Added #ifndef for SIZE_MAX (it is defined in limits.h on MSVSC 8).
+
+------------------------------------------------------------------------
+r7 | 2006-12-13 01:08:02 +0300 | 2 lines
+
+License chaged to BSD-derivative.
+
+------------------------------------------------------------------------
+r6 | 2006-12-13 00:53:20 +0300 | 2 lines
+
+Added include to avoid warnings when it is included after stdint.h.
+
+------------------------------------------------------------------------
+r5 | 2006-12-12 00:58:05 +0300 | 2 lines
+
+BUGFIX: Definitions of INTPTR_MIN, INTPTR_MAX and UINTPTR_MAX for WIN32 and WIN64 was mixed up.
+
+------------------------------------------------------------------------
+r4 | 2006-12-12 00:51:55 +0300 | 2 lines
+
+Rise #error if _MSC_VER is not defined. I.e. compiler other then Microsoft Visual C++ is used.
+
+------------------------------------------------------------------------
+r3 | 2006-12-11 22:54:14 +0300 | 2 lines
+
+Added include to stdint.h.
+
+------------------------------------------------------------------------
+r2 | 2006-12-11 21:39:27 +0300 | 2 lines
+
+Initial check in.
+
+------------------------------------------------------------------------
+r1 | 2006-12-11 21:30:23 +0300 | 1 line
+
+Initial directory structure.
+------------------------------------------------------------------------
diff --git a/psx/octoshock/emuware/msvc/inttypes.h b/psx/octoshock/emuware/msvc/inttypes.h
new file mode 100644
index 0000000000..25542771f5
--- /dev/null
+++ b/psx/octoshock/emuware/msvc/inttypes.h
@@ -0,0 +1,305 @@
+// ISO C9x compliant inttypes.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006 Alexander Chemeris
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. The name of the author may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_INTTYPES_H_ // [
+#define _MSC_INTTYPES_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include "stdint.h"
+
+// 7.8 Format conversion of integer types
+
+typedef struct {
+ intmax_t quot;
+ intmax_t rem;
+} imaxdiv_t;
+
+// 7.8.1 Macros for format specifiers
+
+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
+
+// The fprintf macros for signed integers are:
+#define PRId8 "d"
+#define PRIi8 "i"
+#define PRIdLEAST8 "d"
+#define PRIiLEAST8 "i"
+#define PRIdFAST8 "d"
+#define PRIiFAST8 "i"
+
+#define PRId16 "hd"
+#define PRIi16 "hi"
+#define PRIdLEAST16 "hd"
+#define PRIiLEAST16 "hi"
+#define PRIdFAST16 "hd"
+#define PRIiFAST16 "hi"
+
+#define PRId32 "I32d"
+#define PRIi32 "I32i"
+#define PRIdLEAST32 "I32d"
+#define PRIiLEAST32 "I32i"
+#define PRIdFAST32 "I32d"
+#define PRIiFAST32 "I32i"
+
+#define PRId64 "I64d"
+#define PRIi64 "I64i"
+#define PRIdLEAST64 "I64d"
+#define PRIiLEAST64 "I64i"
+#define PRIdFAST64 "I64d"
+#define PRIiFAST64 "I64i"
+
+#define PRIdMAX "I64d"
+#define PRIiMAX "I64i"
+
+#define PRIdPTR "Id"
+#define PRIiPTR "Ii"
+
+// The fprintf macros for unsigned integers are:
+#define PRIo8 "o"
+#define PRIu8 "u"
+#define PRIx8 "x"
+#define PRIX8 "X"
+#define PRIoLEAST8 "o"
+#define PRIuLEAST8 "u"
+#define PRIxLEAST8 "x"
+#define PRIXLEAST8 "X"
+#define PRIoFAST8 "o"
+#define PRIuFAST8 "u"
+#define PRIxFAST8 "x"
+#define PRIXFAST8 "X"
+
+#define PRIo16 "ho"
+#define PRIu16 "hu"
+#define PRIx16 "hx"
+#define PRIX16 "hX"
+#define PRIoLEAST16 "ho"
+#define PRIuLEAST16 "hu"
+#define PRIxLEAST16 "hx"
+#define PRIXLEAST16 "hX"
+#define PRIoFAST16 "ho"
+#define PRIuFAST16 "hu"
+#define PRIxFAST16 "hx"
+#define PRIXFAST16 "hX"
+
+#define PRIo32 "I32o"
+#define PRIu32 "I32u"
+#define PRIx32 "I32x"
+#define PRIX32 "I32X"
+#define PRIoLEAST32 "I32o"
+#define PRIuLEAST32 "I32u"
+#define PRIxLEAST32 "I32x"
+#define PRIXLEAST32 "I32X"
+#define PRIoFAST32 "I32o"
+#define PRIuFAST32 "I32u"
+#define PRIxFAST32 "I32x"
+#define PRIXFAST32 "I32X"
+
+#define PRIo64 "I64o"
+#define PRIu64 "I64u"
+#define PRIx64 "I64x"
+#define PRIX64 "I64X"
+#define PRIoLEAST64 "I64o"
+#define PRIuLEAST64 "I64u"
+#define PRIxLEAST64 "I64x"
+#define PRIXLEAST64 "I64X"
+#define PRIoFAST64 "I64o"
+#define PRIuFAST64 "I64u"
+#define PRIxFAST64 "I64x"
+#define PRIXFAST64 "I64X"
+
+#define PRIoMAX "I64o"
+#define PRIuMAX "I64u"
+#define PRIxMAX "I64x"
+#define PRIXMAX "I64X"
+
+#define PRIoPTR "Io"
+#define PRIuPTR "Iu"
+#define PRIxPTR "Ix"
+#define PRIXPTR "IX"
+
+// The fscanf macros for signed integers are:
+#define SCNd8 "d"
+#define SCNi8 "i"
+#define SCNdLEAST8 "d"
+#define SCNiLEAST8 "i"
+#define SCNdFAST8 "d"
+#define SCNiFAST8 "i"
+
+#define SCNd16 "hd"
+#define SCNi16 "hi"
+#define SCNdLEAST16 "hd"
+#define SCNiLEAST16 "hi"
+#define SCNdFAST16 "hd"
+#define SCNiFAST16 "hi"
+
+#define SCNd32 "ld"
+#define SCNi32 "li"
+#define SCNdLEAST32 "ld"
+#define SCNiLEAST32 "li"
+#define SCNdFAST32 "ld"
+#define SCNiFAST32 "li"
+
+#define SCNd64 "I64d"
+#define SCNi64 "I64i"
+#define SCNdLEAST64 "I64d"
+#define SCNiLEAST64 "I64i"
+#define SCNdFAST64 "I64d"
+#define SCNiFAST64 "I64i"
+
+#define SCNdMAX "I64d"
+#define SCNiMAX "I64i"
+
+#ifdef _WIN64 // [
+# define SCNdPTR "I64d"
+# define SCNiPTR "I64i"
+#else // _WIN64 ][
+# define SCNdPTR "ld"
+# define SCNiPTR "li"
+#endif // _WIN64 ]
+
+// The fscanf macros for unsigned integers are:
+#define SCNo8 "o"
+#define SCNu8 "u"
+#define SCNx8 "x"
+#define SCNX8 "X"
+#define SCNoLEAST8 "o"
+#define SCNuLEAST8 "u"
+#define SCNxLEAST8 "x"
+#define SCNXLEAST8 "X"
+#define SCNoFAST8 "o"
+#define SCNuFAST8 "u"
+#define SCNxFAST8 "x"
+#define SCNXFAST8 "X"
+
+#define SCNo16 "ho"
+#define SCNu16 "hu"
+#define SCNx16 "hx"
+#define SCNX16 "hX"
+#define SCNoLEAST16 "ho"
+#define SCNuLEAST16 "hu"
+#define SCNxLEAST16 "hx"
+#define SCNXLEAST16 "hX"
+#define SCNoFAST16 "ho"
+#define SCNuFAST16 "hu"
+#define SCNxFAST16 "hx"
+#define SCNXFAST16 "hX"
+
+#define SCNo32 "lo"
+#define SCNu32 "lu"
+#define SCNx32 "lx"
+#define SCNX32 "lX"
+#define SCNoLEAST32 "lo"
+#define SCNuLEAST32 "lu"
+#define SCNxLEAST32 "lx"
+#define SCNXLEAST32 "lX"
+#define SCNoFAST32 "lo"
+#define SCNuFAST32 "lu"
+#define SCNxFAST32 "lx"
+#define SCNXFAST32 "lX"
+
+#define SCNo64 "I64o"
+#define SCNu64 "I64u"
+#define SCNx64 "I64x"
+#define SCNX64 "I64X"
+#define SCNoLEAST64 "I64o"
+#define SCNuLEAST64 "I64u"
+#define SCNxLEAST64 "I64x"
+#define SCNXLEAST64 "I64X"
+#define SCNoFAST64 "I64o"
+#define SCNuFAST64 "I64u"
+#define SCNxFAST64 "I64x"
+#define SCNXFAST64 "I64X"
+
+#define SCNoMAX "I64o"
+#define SCNuMAX "I64u"
+#define SCNxMAX "I64x"
+#define SCNXMAX "I64X"
+
+#ifdef _WIN64 // [
+# define SCNoPTR "I64o"
+# define SCNuPTR "I64u"
+# define SCNxPTR "I64x"
+# define SCNXPTR "I64X"
+#else // _WIN64 ][
+# define SCNoPTR "lo"
+# define SCNuPTR "lu"
+# define SCNxPTR "lx"
+# define SCNXPTR "lX"
+#endif // _WIN64 ]
+
+#endif // __STDC_FORMAT_MACROS ]
+
+// 7.8.2 Functions for greatest-width integer types
+
+// 7.8.2.1 The imaxabs function
+#define imaxabs _abs64
+
+// 7.8.2.2 The imaxdiv function
+
+// This is modified version of div() function from Microsoft's div.c found
+// in %MSVC.NET%\crt\src\div.c
+#ifdef STATIC_IMAXDIV // [
+static
+#else // STATIC_IMAXDIV ][
+_inline
+#endif // STATIC_IMAXDIV ]
+imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
+{
+ imaxdiv_t result;
+
+ result.quot = numer / denom;
+ result.rem = numer % denom;
+
+ if (numer < 0 && result.rem > 0) {
+ // did division wrong; must fix up
+ ++result.quot;
+ result.rem -= denom;
+ }
+
+ return result;
+}
+
+// 7.8.2.3 The strtoimax and strtoumax functions
+#define strtoimax _strtoi64
+#define strtoumax _strtoui64
+
+// 7.8.2.4 The wcstoimax and wcstoumax functions
+#define wcstoimax _wcstoi64
+#define wcstoumax _wcstoui64
+
+
+#endif // _MSC_INTTYPES_H_ ]
diff --git a/psx/octoshock/emuware/msvc/stdint.h b/psx/octoshock/emuware/msvc/stdint.h
new file mode 100644
index 0000000000..59d067302f
--- /dev/null
+++ b/psx/octoshock/emuware/msvc/stdint.h
@@ -0,0 +1,247 @@
+// ISO C9x compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006-2008 Alexander Chemeris
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. The name of the author may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include
+
+// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
+// compiling for ARM we should wrap include with 'extern "C++" {}'
+// or compiler give many errors like this:
+// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#ifdef __cplusplus
+extern "C" {
+#endif
+# include
+#ifdef __cplusplus
+}
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+# define _W64 __w64
+# else
+# define _W64
+# endif
+#endif
+
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+
+// Visual Studio 6 and Embedded Visual C++ 4 doesn't
+// realize that, e.g. char has the same size as __int8
+// so we give up on __intX for them.
+#if (_MSC_VER < 1300)
+ typedef signed char int8_t;
+ typedef signed short int16_t;
+ typedef signed int int32_t;
+ typedef unsigned char uint8_t;
+ typedef unsigned short uint16_t;
+ typedef unsigned int uint32_t;
+#else
+ typedef signed __int8 int8_t;
+ typedef signed __int16 int16_t;
+ typedef signed __int32 int32_t;
+ typedef unsigned __int8 uint8_t;
+ typedef unsigned __int16 uint16_t;
+ typedef unsigned __int32 uint32_t;
+#endif
+typedef signed __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t int_fast8_t;
+typedef int16_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef int64_t int_fast64_t;
+typedef uint8_t uint_fast8_t;
+typedef uint16_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+typedef uint64_t uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+ typedef signed __int64 intptr_t;
+ typedef unsigned __int64 uintptr_t;
+#else // _WIN64 ][
+ typedef _W64 signed int intptr_t;
+ typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN ((int8_t)_I8_MIN)
+#define INT8_MAX _I8_MAX
+#define INT16_MIN ((int16_t)_I16_MIN)
+#define INT16_MAX _I16_MAX
+#define INT32_MIN ((int32_t)_I32_MIN)
+#define INT32_MAX _I32_MAX
+#define INT64_MIN ((int64_t)_I64_MIN)
+#define INT64_MAX _I64_MAX
+#define UINT8_MAX _UI8_MAX
+#define UINT16_MAX _UI16_MAX
+#define UINT32_MAX _UI32_MAX
+#define UINT64_MAX _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST16_MAX INT16_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+# define INTPTR_MIN INT64_MIN
+# define INTPTR_MAX INT64_MAX
+# define UINTPTR_MAX UINT64_MAX
+#else // _WIN64 ][
+# define INTPTR_MIN INT32_MIN
+# define INTPTR_MAX INT32_MAX
+# define UINTPTR_MAX UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+# define PTRDIFF_MIN _I64_MIN
+# define PTRDIFF_MAX _I64_MAX
+#else // _WIN64 ][
+# define PTRDIFF_MIN _I32_MIN
+# define PTRDIFF_MAX _I32_MAX
+#endif // _WIN64 ]
+
+#define SIG_ATOMIC_MIN INT_MIN
+#define SIG_ATOMIC_MAX INT_MAX
+
+#ifndef SIZE_MAX // [
+# ifdef _WIN64 // [
+# define SIZE_MAX _UI64_MAX
+# else // _WIN64 ][
+# define SIZE_MAX _UI32_MAX
+# endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in
+#ifndef WCHAR_MIN // [
+# define WCHAR_MIN 0
+#endif // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+# define WCHAR_MAX _UI16_MAX
+#endif // WCHAR_MAX ]
+
+#define WINT_MIN 0
+#define WINT_MAX _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val) val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val) val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+#define INTMAX_C INT64_C
+#define UINTMAX_C UINT64_C
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+
+#endif // _MSC_STDINT_H_ ]
diff --git a/psx/octoshock/endian.cpp b/psx/octoshock/endian.cpp
new file mode 100644
index 0000000000..f0c7bdfa25
--- /dev/null
+++ b/psx/octoshock/endian.cpp
@@ -0,0 +1,246 @@
+/* Mednafen - Multi-system Emulator
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include
+#include "octoshock.h"
+#include "endian.h"
+
+void Endian_A16_Swap(void *src, uint32 nelements)
+{
+ uint32 i;
+ uint8 *nsrc = (uint8 *)src;
+
+ for(i = 0; i < nelements; i++)
+ {
+ uint8 tmp = nsrc[i * 2];
+
+ nsrc[i * 2] = nsrc[i * 2 + 1];
+ nsrc[i * 2 + 1] = tmp;
+ }
+}
+
+void Endian_A32_Swap(void *src, uint32 nelements)
+{
+ uint32 i;
+ uint8 *nsrc = (uint8 *)src;
+
+ for(i = 0; i < nelements; i++)
+ {
+ uint8 tmp1 = nsrc[i * 4];
+ uint8 tmp2 = nsrc[i * 4 + 1];
+
+ nsrc[i * 4] = nsrc[i * 4 + 3];
+ nsrc[i * 4 + 1] = nsrc[i * 4 + 2];
+
+ nsrc[i * 4 + 2] = tmp2;
+ nsrc[i * 4 + 3] = tmp1;
+ }
+}
+
+void Endian_A64_Swap(void *src, uint32 nelements)
+{
+ uint32 i;
+ uint8 *nsrc = (uint8 *)src;
+
+ for(i = 0; i < nelements; i++)
+ {
+ uint8 *base = &nsrc[i * 8];
+
+ for(int z = 0; z < 4; z++)
+ {
+ uint8 tmp = base[z];
+
+ base[z] = base[7 - z];
+ base[7 - z] = tmp;
+ }
+ }
+}
+
+void Endian_A16_NE_to_LE(void *src, uint32 nelements)
+{
+ #ifdef MSB_FIRST
+ Endian_A16_Swap(src, nelements);
+ #endif
+}
+
+void Endian_A32_NE_to_LE(void *src, uint32 nelements)
+{
+ #ifdef MSB_FIRST
+ Endian_A32_Swap(src, nelements);
+ #endif
+}
+
+void Endian_A64_NE_to_LE(void *src, uint32 nelements)
+{
+ #ifdef MSB_FIRST
+ Endian_A64_Swap(src, nelements);
+ #endif
+}
+
+
+void Endian_A16_LE_to_NE(void *src, uint32 nelements)
+{
+ #ifdef MSB_FIRST
+ uint32 i;
+ uint8 *nsrc = (uint8 *)src;
+
+ for(i = 0; i < nelements; i++)
+ {
+ uint8 tmp = nsrc[i * 2];
+
+ nsrc[i * 2] = nsrc[i * 2 + 1];
+ nsrc[i * 2 + 1] = tmp;
+ }
+ #endif
+}
+
+void Endian_A16_BE_to_NE(void *src, uint32 nelements)
+{
+ #ifdef LSB_FIRST
+ uint32 i;
+ uint8 *nsrc = (uint8 *)src;
+
+ for(i = 0; i < nelements; i++)
+ {
+ uint8 tmp = nsrc[i * 2];
+
+ nsrc[i * 2] = nsrc[i * 2 + 1];
+ nsrc[i * 2 + 1] = tmp;
+ }
+ #endif
+}
+
+
+void Endian_A32_LE_to_NE(void *src, uint32 nelements)
+{
+ #ifdef MSB_FIRST
+ uint32 i;
+ uint8 *nsrc = (uint8 *)src;
+
+ for(i = 0; i < nelements; i++)
+ {
+ uint8 tmp1 = nsrc[i * 4];
+ uint8 tmp2 = nsrc[i * 4 + 1];
+
+ nsrc[i * 4] = nsrc[i * 4 + 3];
+ nsrc[i * 4 + 1] = nsrc[i * 4 + 2];
+
+ nsrc[i * 4 + 2] = tmp2;
+ nsrc[i * 4 + 3] = tmp1;
+ }
+ #endif
+}
+
+void Endian_A64_LE_to_NE(void *src, uint32 nelements)
+{
+ #ifdef MSB_FIRST
+ uint32 i;
+ uint8 *nsrc = (uint8 *)src;
+
+ for(i = 0; i < nelements; i++)
+ {
+ uint8 *base = &nsrc[i * 8];
+
+ for(int z = 0; z < 4; z++)
+ {
+ uint8 tmp = base[z];
+
+ base[z] = base[7 - z];
+ base[7 - z] = tmp;
+ }
+ }
+ #endif
+}
+
+void FlipByteOrder(uint8 *src, uint32 count)
+{
+ uint8 *start=src;
+ uint8 *end=src+count-1;
+
+ if((count&1) || !count) return; /* This shouldn't happen. */
+
+ count >>= 1;
+
+ while(count--)
+ {
+ uint8 tmp;
+
+ tmp=*end;
+ *end=*start;
+ *start=tmp;
+ end--;
+ start++;
+ }
+}
+
+void Endian_V_LE_to_NE(void *src, uint32 bytesize)
+{
+ #ifdef MSB_FIRST
+ FlipByteOrder((uint8 *)src, bytesize);
+ #endif
+}
+
+void Endian_V_NE_to_LE(void *src, uint32 bytesize)
+{
+ #ifdef MSB_FIRST
+ FlipByteOrder((uint8 *)src, bytesize);
+ #endif
+}
+
+int write16le(uint16 b, FILE *fp)
+{
+ uint8 s[2];
+ s[0]=b;
+ s[1]=b>>8;
+ return((fwrite(s,1,2,fp)<2)?0:2);
+}
+
+int write32le(uint32 b, FILE *fp)
+{
+ uint8 s[4];
+ s[0]=b;
+ s[1]=b>>8;
+ s[2]=b>>16;
+ s[3]=b>>24;
+ return((fwrite(s,1,4,fp)<4)?0:4);
+}
+
+int read32le(uint32 *Bufo, FILE *fp)
+{
+ uint32 buf;
+ if(fread(&buf,1,4,fp)<4)
+ return 0;
+ #ifdef LSB_FIRST
+ *(uint32*)Bufo=buf;
+ #else
+ *(uint32*)Bufo=((buf&0xFF)<<24)|((buf&0xFF00)<<8)|((buf&0xFF0000)>>8)|((buf&0xFF000000)>>24);
+ #endif
+ return 1;
+}
+
+int read16le(char *d, FILE *fp)
+{
+ #ifdef LSB_FIRST
+ return((fread(d,1,2,fp)<2)?0:2);
+ #else
+ int ret;
+ ret=fread(d+1,1,1,fp);
+ ret+=fread(d,1,1,fp);
+ return ret<2?0:2;
+ #endif
+}
+
diff --git a/psx/octoshock/endian.h b/psx/octoshock/endian.h
new file mode 100644
index 0000000000..446eec45ec
--- /dev/null
+++ b/psx/octoshock/endian.h
@@ -0,0 +1,209 @@
+#ifndef __MDFN_ENDIAN_H
+#define __MDFN_ENDIAN_H
+
+#include "octoshock.h"
+
+#ifdef MSB_FIRST
+ #ifdef LSB_FIRST
+ #error Only define one of LSB_FIRST and MSB_FIRST
+ #endif
+
+ #ifndef le32toh
+ #define le32toh(l) ((((l)>>24) & 0xff) | (((l)>>8) & 0xff00) \
+ | (((l)<<8) & 0xff0000) | (((l)<<24) & 0xff000000))
+ #endif
+ #ifndef le16toh
+ #define le16toh(l) ((((l)>>8) & 0xff) | (((l)<<8) & 0xff00))
+ #endif
+#else
+ #ifndef le32toh
+ #define le32toh(l) (l)
+ #endif
+ #ifndef le16toh
+ #define le16toh(l) (l)
+ #endif
+#endif
+
+#ifndef htole32
+#define htole32 le32toh
+#endif
+
+#ifndef htole16
+#define htole16 le16toh
+#endif
+
+
+int write16le(uint16 b, FILE *fp);
+int write32le(uint32 b, FILE *fp);
+int read32le(uint32 *Bufo, FILE *fp);
+
+void Endian_A16_Swap(void *src, uint32 nelements);
+void Endian_A32_Swap(void *src, uint32 nelements);
+void Endian_A64_Swap(void *src, uint32 nelements);
+
+void Endian_A16_NE_to_LE(void *src, uint32 nelements);
+void Endian_A32_NE_to_LE(void *src, uint32 nelements);
+void Endian_A64_NE_to_LE(void *src, uint32 nelements);
+
+void Endian_A16_LE_to_NE(void *src, uint32 nelements);
+void Endian_A16_BE_to_NE(void *src, uint32 nelements);
+void Endian_A32_LE_to_NE(void *src, uint32 nelements);
+void Endian_A64_LE_to_NE(void *src, uint32 nelements);
+
+void Endian_V_LE_to_NE(void *src, uint32 bytesize);
+void Endian_V_NE_to_LE(void *src, uint32 bytesize);
+
+void FlipByteOrder(uint8 *src, uint32 count);
+
+// The following functions can encode/decode to unaligned addresses.
+
+static INLINE void MDFN_en16lsb(uint8 *buf, uint16 morp)
+{
+ buf[0]=morp;
+ buf[1]=morp>>8;
+}
+
+static INLINE void MDFN_en24lsb(uint8 *buf, uint32 morp)
+{
+ buf[0]=morp;
+ buf[1]=morp>>8;
+ buf[2]=morp>>16;
+}
+
+
+static INLINE void MDFN_en32lsb(uint8 *buf, uint32 morp)
+{
+ buf[0]=morp;
+ buf[1]=morp>>8;
+ buf[2]=morp>>16;
+ buf[3]=morp>>24;
+}
+
+static INLINE void MDFN_en64lsb(uint8 *buf, uint64 morp)
+{
+ buf[0]=morp >> 0;
+ buf[1]=morp >> 8;
+ buf[2]=morp >> 16;
+ buf[3]=morp >> 24;
+ buf[4]=morp >> 32;
+ buf[5]=morp >> 40;
+ buf[6]=morp >> 48;
+ buf[7]=morp >> 56;
+}
+
+
+static INLINE void MDFN_en16msb(uint8 *buf, uint16 morp)
+{
+ buf[0] = morp >> 8;
+ buf[1] = morp;
+}
+
+static INLINE void MDFN_en24msb(uint8 *buf, uint32 morp)
+{
+ buf[0] = morp >> 16;
+ buf[1] = morp >> 8;
+ buf[2] = morp;
+}
+
+static INLINE void MDFN_en32msb(uint8 *buf, uint32 morp)
+{
+ buf[0] = morp >> 24;
+ buf[1] = morp >> 16;
+ buf[2] = morp >> 8;
+ buf[3] = morp;
+}
+
+static INLINE void MDFN_en64msb(uint8 *buf, uint64 morp)
+{
+ buf[0] = morp >> 56;
+ buf[1] = morp >> 48;
+ buf[2] = morp >> 40;
+ buf[3] = morp >> 32;
+ buf[4] = morp >> 24;
+ buf[5] = morp >> 16;
+ buf[6] = morp >> 8;
+ buf[7] = morp >> 0;
+}
+
+
+// Overloaded functions, yay.
+static INLINE void MDFN_enlsb(uint16 * buf, uint16 value)
+{
+ MDFN_en16lsb((uint8 *)buf, value);
+}
+
+static INLINE void MDFN_enlsb(uint32 * buf, uint32 value)
+{
+ MDFN_en32lsb((uint8 *)buf, value);
+}
+
+static INLINE void MDFN_enlsb(uint64 * buf, uint64 value)
+{
+ MDFN_en64lsb((uint8 *)buf, value);
+}
+
+
+static INLINE uint16 MDFN_de16lsb(const uint8 *morp)
+{
+ return(morp[0] | (morp[1] << 8));
+}
+
+
+static INLINE uint32 MDFN_de24lsb(const uint8 *morp)
+{
+ return(morp[0]|(morp[1]<<8)|(morp[2]<<16));
+}
+
+static INLINE uint32 MDFN_de32lsb(const uint8 *morp)
+{
+ return(morp[0]|(morp[1]<<8)|(morp[2]<<16)|(morp[3]<<24));
+}
+
+static INLINE uint64 MDFN_de64lsb(const uint8 *morp)
+{
+ uint64 ret = 0;
+
+ ret |= (uint64)morp[0];
+ ret |= (uint64)morp[1] << 8;
+ ret |= (uint64)morp[2] << 16;
+ ret |= (uint64)morp[3] << 24;
+ ret |= (uint64)morp[4] << 32;
+ ret |= (uint64)morp[5] << 40;
+ ret |= (uint64)morp[6] << 48;
+ ret |= (uint64)morp[7] << 56;
+
+ return(ret);
+}
+
+static INLINE uint16 MDFN_delsb(const uint16 *buf)
+{
+ return(MDFN_de16lsb((uint8 *)buf));
+}
+
+static INLINE uint32 MDFN_delsb(const uint32 *buf)
+{
+ return(MDFN_de32lsb((uint8 *)buf));
+}
+
+static INLINE uint64 MDFN_delsb(const uint64 *buf)
+{
+ return(MDFN_de64lsb((uint8 *)buf));
+}
+
+static INLINE uint16 MDFN_de16msb(const uint8 *morp)
+{
+ return(morp[1] | (morp[0] << 8));
+}
+
+static INLINE uint32 MDFN_de24msb(const uint8 *morp)
+{
+ return((morp[2]<<0)|(morp[1]<<8)|(morp[0]<<16));
+}
+
+
+static INLINE uint32 MDFN_de32msb(const uint8 *morp)
+{
+ return(morp[3]|(morp[2]<<8)|(morp[1]<<16)|(morp[0]<<24));
+}
+
+#endif
diff --git a/psx/octoshock/error.h b/psx/octoshock/error.h
new file mode 100644
index 0000000000..6b0b7a82b2
--- /dev/null
+++ b/psx/octoshock/error.h
@@ -0,0 +1,75 @@
+#ifndef __MDFN_ERROR_H
+#define __MDFN_ERROR_H
+
+#include
+#include
+#include
+
+#ifdef __cplusplus
+
+class ErrnoHolder;
+class MDFN_Error : public std::exception
+{
+ public:
+
+ MDFN_Error() throw();
+
+ MDFN_Error(int errno_code_new, const char *format, ...) throw() MDFN_FORMATSTR(gnu_printf, 3, 4);
+ MDFN_Error(const ErrnoHolder &enh);
+
+ ~MDFN_Error() throw();
+
+ MDFN_Error(const MDFN_Error &ze_error) throw();
+ MDFN_Error & operator=(const MDFN_Error &ze_error) throw();
+
+ virtual const char *what(void) const throw();
+ int GetErrno(void) const throw();
+
+ private:
+
+ int errno_code;
+ char *error_message;
+};
+
+class ErrnoHolder
+{
+ public:
+
+ ErrnoHolder()
+ {
+ //SetErrno(0);
+ local_errno = 0;
+ local_strerror[0] = 0;
+ }
+
+ ErrnoHolder(int the_errno)
+ {
+ SetErrno(the_errno);
+ }
+
+ inline int Errno(void) const
+ {
+ return(local_errno);
+ }
+
+ const char *StrError(void) const
+ {
+ return(local_strerror);
+ }
+
+ void operator=(int the_errno)
+ {
+ SetErrno(the_errno);
+ }
+
+ private:
+
+ void SetErrno(int the_errno);
+
+ int local_errno;
+ char local_strerror[256];
+};
+
+#endif
+
+#endif
diff --git a/psx/octoshock/file.cpp b/psx/octoshock/file.cpp
new file mode 100644
index 0000000000..f6cf195269
--- /dev/null
+++ b/psx/octoshock/file.cpp
@@ -0,0 +1,562 @@
+///* Mednafen - Multi-system Emulator
+// *
+// * 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
+// * the Free Software Foundation; either version 2 of the License, or
+// * (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// * GNU General Public License for more details.
+// *
+// * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+// */
+//
+//#include
+//#include
+//#include
+//#include
+//#include
+//
+//#include "octoshock.h"
+//#include "FileStream.h"
+//
+//
+//#ifdef HAVE_MMAP
+//#include
+//#include
+//#include
+//#include
+//#endif
+//
+//#include "file.h"
+//
+//static const int64 MaxROMImageSize = (int64)1 << 26; // 2 ^ 26 = 64MiB
+//
+//enum
+//{
+// MDFN_FILETYPE_PLAIN = 0,
+// MDFN_FILETYPE_GZIP = 1,
+// MDFN_FILETYPE_ZIP = 2,
+//};
+//
+//void MDFNFILE::MakeMemWrap(void *tz, int type)
+//{
+// #ifdef HAVE_MMAP
+// is_mmap = FALSE;
+// #endif
+// location = 0;
+//
+// if(type == MDFN_FILETYPE_PLAIN)
+// {
+// ::fseek((FILE *)tz, 0, SEEK_END);
+// f_size = ::ftell((FILE *)tz);
+// ::fseek((FILE *)tz, 0, SEEK_SET);
+//
+//
+// #ifdef HAVE_MMAP
+// if((void *)-1 != (f_data = (uint8 *)mmap(NULL, size, PROT_READ, MAP_SHARED, fileno((FILE *)tz), 0)))
+// {
+// //puts("mmap'ed");
+// is_mmap = TRUE;
+// #ifdef HAVE_MADVISE
+// madvise(f_data, size, MADV_SEQUENTIAL | MADV_WILLNEED);
+// #endif
+// }
+// else
+// #endif
+// {
+// f_data = (uint8 *)MDFN_malloc_T(size, _("file read buffer"));
+//
+// if((int64)::fread(f_data, 1, size, (FILE *)tz) != size)
+// {
+// ErrnoHolder ene(errno);
+//
+// throw MDFN_Error(ene.Errno(), _("Error reading file: %s"), ene.StrError());
+// }
+// }
+// }
+// else if(type == MDFN_FILETYPE_GZIP)
+// {
+// uint32_t cur_size = 0;
+// uint32_t cur_alloced = 65536;
+// int howmany;
+//
+// f_data = (uint8 *)MDFN_malloc_T(cur_alloced, _("file read buffer"));
+//
+// while((howmany = gzread((gzFile)tz, f_data + cur_size, cur_alloced - cur_size)) > 0)
+// {
+// cur_size += howmany;
+// cur_alloced <<= 1;
+//
+// if(cur_size > MaxROMImageSize)
+// throw MDFN_Error(0, _("ROM image is too large; maximum size allowed is %llu bytes."), (unsigned long long)MaxROMImageSize);
+//
+// f_data = (uint8 *)MDFN_realloc_T(f_data, cur_alloced, _("file read buffer"));
+// }
+//
+// f_data = (uint8 *)MDFN_realloc_T(f_data, cur_size, _("file read buffer"));
+// f_size = cur_size;
+//
+// {
+// int gzerrnum = 0;
+// const char *gzerrstring;
+// if((gzerrstring = gzerror((gzFile)tz, &gzerrnum)) && gzerrnum != Z_OK && gzerrnum != Z_STREAM_END)
+// {
+// if(gzerrnum != Z_ERRNO)
+// {
+// throw MDFN_Error(0, _("Error reading file: zlib error: %s"), gzerrstring);
+// }
+// else
+// {
+// ErrnoHolder ene(errno);
+// throw MDFN_Error(ene.Errno(), _("Error reading file: %s"), ene.StrError());
+// }
+// }
+// }
+// }
+// else if(type == MDFN_FILETYPE_ZIP)
+// {
+// unz_file_info ufo;
+// unzGetCurrentFileInfo((unzFile)tz, &ufo, 0, 0, 0, 0, 0, 0);
+//
+// f_size = ufo.uncompressed_size;
+//
+// if(size > MaxROMImageSize)
+// throw MDFN_Error(0, _("ROM image is too large; maximum size allowed is %llu bytes."), (unsigned long long)MaxROMImageSize);
+//
+// f_data = (uint8 *)MDFN_malloc_T(ufo.uncompressed_size, _("file read buffer"));
+// unzReadCurrentFile((unzFile)tz, f_data, ufo.uncompressed_size);
+// }
+//}
+//
+//MDFNFILE::MDFNFILE(const char *path, const FileExtensionSpecStruct *known_ext, const char *purpose) : size(f_size), data((const uint8* const &)f_data), ext((const char * const &)f_ext), fbase((const char * const &)f_fbase)
+//{
+// f_data = NULL;
+// f_size = 0;
+// f_ext = NULL;
+// f_fbase = NULL;
+//
+// location = 0;
+//
+// #ifdef HAVE_MMAP
+// is_mmap = 0;
+// #endif
+//
+// Open(path, known_ext, purpose);
+//}
+//
+//MDFNFILE::~MDFNFILE()
+//{
+// Close();
+//}
+//
+//
+//void MDFNFILE::Open(const char *path, const FileExtensionSpecStruct *known_ext, const char *purpose)
+//{
+// unzFile tz = NULL;
+// FILE *fp = NULL;
+// gzFile gzp = NULL;
+//
+// try
+// {
+// //
+// // Try opening it as a zip file first
+// //
+// if((tz = unzOpen(path)))
+// {
+// char tempu[1024];
+// int errcode;
+//
+// if((errcode = unzGoToFirstFile(tz)) != UNZ_OK)
+// {
+// throw MDFN_Error(0, _("Could not seek to first file in ZIP archive: %s"), unzErrorString(errcode));
+// }
+//
+// if(known_ext)
+// {
+// bool FileFound = FALSE;
+// while(!FileFound)
+// {
+// size_t tempu_strlen;
+// const FileExtensionSpecStruct *ext_search = known_ext;
+//
+// if((errcode = unzGetCurrentFileInfo(tz, 0, tempu, 1024, 0, 0, 0, 0)) != UNZ_OK)
+// {
+// throw MDFN_Error(0, _("Could not get file information in ZIP archive: %s"), unzErrorString(errcode));
+// }
+//
+// tempu[1023] = 0;
+// tempu_strlen = strlen(tempu);
+//
+// while(ext_search->extension && !FileFound)
+// {
+// size_t ttmeow = strlen(ext_search->extension);
+// if(tempu_strlen >= ttmeow)
+// {
+// if(!strcasecmp(tempu + tempu_strlen - ttmeow, ext_search->extension))
+// FileFound = TRUE;
+// }
+// ext_search++;
+// }
+//
+// if(FileFound)
+// break;
+//
+// if((errcode = unzGoToNextFile(tz)) != UNZ_OK)
+// {
+// if(errcode != UNZ_END_OF_LIST_OF_FILE)
+// {
+// throw MDFN_Error(0, _("Error seeking to next file in ZIP archive: %s"), unzErrorString(errcode));
+// }
+//
+// if((errcode = unzGoToFirstFile(tz)) != UNZ_OK)
+// {
+// throw MDFN_Error(0, _("Could not seek to first file in ZIP archive: %s"), unzErrorString(errcode));
+// }
+// break;
+// }
+// } // end to while(!FileFound)
+// } // end to if(ext)
+//
+// if((errcode = unzOpenCurrentFile(tz)) != UNZ_OK)
+// {
+// throw MDFN_Error(0, _("Could not open file in ZIP archive: %s"), unzErrorString(errcode));
+// }
+//
+// MakeMemWrap(tz, MDFN_FILETYPE_ZIP);
+//
+// {
+// char *ld = strrchr(tempu, '.');
+//
+// f_ext = strdup(ld ? ld + 1 : "");
+// f_fbase = strdup(tempu);
+// if(ld)
+// f_fbase[ld - tempu] = 0;
+// }
+// }
+// else // If it's not a zip file, handle it as...another type of file!
+// {
+// if(!(fp = fopen(path, "rb")))
+// {
+// ErrnoHolder ene(errno);
+//
+// throw MDFN_Error(ene.Errno(), _("Error opening \"%s\": %s"), path, ene.StrError());
+// }
+//
+// const char *path_fnp = GetFNComponent(path);
+//
+// uint32 gzmagic;
+//
+// gzmagic = ::fgetc(fp);
+// gzmagic |= ::fgetc(fp) << 8;
+// gzmagic |= ::fgetc(fp) << 16;
+//
+// if(gzmagic != 0x088b1f) /* Not gzip... */
+// {
+// ::fseek(fp, 0, SEEK_SET);
+//
+// MakeMemWrap(fp, MDFN_FILETYPE_PLAIN);
+//
+// {
+// const char *ld = strrchr(path_fnp, '.');
+// f_ext = strdup(ld ? ld + 1 : "");
+// f_fbase = strdup(path_fnp);
+// if(ld)
+// f_fbase[ld - path_fnp] = 0;
+// }
+// }
+// else /* Probably gzip */
+// {
+// fclose(fp);
+// fp = NULL;
+//
+// // Clear errno so we can see if the error occurred within zlib or the C lib
+// errno = 0;
+// if(!(gzp = gzopen(path, "rb")))
+// {
+// if(errno != 0)
+// {
+// ErrnoHolder ene(errno);
+//
+// throw MDFN_Error(ene.Errno(), _("Error opening \"%s\": %s"), path, ene.StrError());
+// }
+// else
+// throw MDFN_Error(0, _("Error opening \"%s\": %s"), path, _("zlib error"));
+// }
+//
+// MakeMemWrap(gzp, MDFN_FILETYPE_GZIP);
+//
+// char *tmp_path = strdup(path_fnp);
+// char *ld = strrchr(tmp_path, '.');
+//
+// if(ld && ld > tmp_path)
+// {
+// char *last_ld = ld;
+// *ld = 0;
+// ld = strrchr(tmp_path, '.');
+// if(!ld) { ld = last_ld; }
+// else *ld = 0;
+// }
+// f_ext = strdup(ld ? ld + 1 : "");
+// f_fbase = tmp_path;
+// } // End gzip handling
+// } // End normal and gzip file handling else to zip
+// }
+// catch(...)
+// {
+// if(tz != NULL)
+// {
+// unzCloseCurrentFile(tz);
+// unzClose(tz);
+// }
+//
+// if(fp != NULL)
+// {
+// fclose(fp);
+// fp = NULL;
+// }
+//
+// if(gzp != NULL)
+// {
+// gzclose(gzp);
+// gzp = NULL;
+// }
+//
+// Close();
+// throw;
+// }
+//
+// if(tz != NULL)
+// {
+// unzCloseCurrentFile(tz);
+// unzClose(tz);
+// }
+//
+// if(fp != NULL)
+// {
+// fclose(fp);
+// fp = NULL;
+// }
+//
+// if(gzp != NULL)
+// {
+// gzclose(gzp);
+// gzp = NULL;
+// }
+//}
+//
+//void MDFNFILE::Close(void) throw()
+//{
+// if(f_ext)
+// {
+// free(f_ext);
+// f_ext = NULL;
+// }
+//
+// if(f_fbase)
+// {
+// free(f_fbase);
+// f_fbase = NULL;
+// }
+//
+// if(f_data)
+// {
+// #if HAVE_MMAP
+// if(is_mmap)
+// munmap(f_data, size);
+// else
+// #endif
+// free(f_data);
+// f_data = NULL;
+// }
+//}
+//
+//uint64 MDFNFILE::fread(void *ptr, size_t element_size, size_t nmemb)
+//{
+// uint32 total = element_size * nmemb;
+//
+// if(location >= f_size)
+// return 0;
+//
+// if((location + total) > f_size)
+// {
+// int64 ak = f_size - location;
+//
+// memcpy((uint8*)ptr, f_data + location, ak);
+//
+// location = f_size;
+//
+// return(ak / element_size);
+// }
+// else
+// {
+// memcpy((uint8*)ptr, f_data + location, total);
+//
+// location += total;
+//
+// return nmemb;
+// }
+//}
+//
+//int MDFNFILE::fseek(int64 offset, int whence)
+//{
+// switch(whence)
+// {
+// case SEEK_SET:if(offset >= f_size)
+// return(-1);
+// location = offset;
+// break;
+//
+// case SEEK_CUR:if((offset + location) > f_size)
+// return(-1);
+//
+// location += offset;
+// break;
+// }
+// return 0;
+//}
+//
+//int MDFNFILE::read16le(uint16 *val)
+//{
+// if((location + 2) > size)
+// return 0;
+//
+// *val = MDFN_de16lsb(data + location);
+//
+// location += 2;
+//
+// return(1);
+//}
+//
+//int MDFNFILE::read32le(uint32 *val)
+//{
+// if((location + 4) > size)
+// return 0;
+//
+// *val = MDFN_de32lsb(data + location);
+//
+// location += 4;
+//
+// return(1);
+//}
+//
+//char *MDFNFILE::fgets(char *s, int buffer_size)
+//{
+// int pos = 0;
+//
+// if(!buffer_size)
+// return(NULL);
+//
+// if(location >= buffer_size)
+// return(NULL);
+//
+// while(pos < (buffer_size - 1) && location < buffer_size)
+// {
+// int v = data[location];
+// s[pos] = v;
+// location++;
+// pos++;
+// if(v == '\n') break;
+// }
+//
+// if(buffer_size)
+// s[pos] = 0;
+//
+// return(s);
+//}
+//
+//static INLINE bool MDFN_DumpToFileReal(const char *filename, int compress, const std::vector &pearpairs)
+//{
+// if(MDFN_GetSettingB("filesys.disablesavegz"))
+// compress = 0;
+//
+// if(compress)
+// {
+// char mode[64];
+// gzFile gp;
+//
+// trio_snprintf(mode, 64, "wb%d", compress);
+//
+// gp = gzopen(filename, mode);
+//
+// if(!gp)
+// {
+// ErrnoHolder ene(errno);
+//
+// MDFN_PrintError(_("Error opening \"%s\": %s"), filename, ene.StrError());
+// return(0);
+// }
+//
+// for(unsigned int i = 0; i < pearpairs.size(); i++)
+// {
+// const void *data = pearpairs[i].GetData();
+// const int64 length = pearpairs[i].GetLength();
+//
+// if(gzwrite(gp, data, length) != length)
+// {
+// int errnum;
+//
+// MDFN_PrintError(_("Error writing to \"%s\": %s"), filename, gzerror(gp, &errnum));
+// gzclose(gp);
+// return(0);
+// }
+// }
+//
+// if(gzclose(gp) != Z_OK) // FIXME: Huhm, how should we handle this?
+// {
+// MDFN_PrintError(_("Error closing \"%s\""), filename);
+// return(0);
+// }
+// }
+// else
+// {
+// FILE *fp = fopen(filename, "wb");
+// if(!fp)
+// {
+// ErrnoHolder ene(errno);
+//
+// MDFN_PrintError(_("Error opening \"%s\": %s"), filename, ene.StrError());
+// return(0);
+// }
+//
+// for(unsigned int i = 0; i < pearpairs.size(); i++)
+// {
+// const void *data = pearpairs[i].GetData();
+// const uint64 length = pearpairs[i].GetLength();
+//
+// if(fwrite(data, 1, length, fp) != length)
+// {
+// ErrnoHolder ene(errno);
+//
+// MDFN_PrintError(_("Error writing to \"%s\": %s"), filename, ene.StrError());
+// fclose(fp);
+// return(0);
+// }
+// }
+//
+// if(fclose(fp) == EOF)
+// {
+// ErrnoHolder ene(errno);
+//
+// MDFN_PrintError(_("Error closing \"%s\": %s"), filename, ene.StrError());
+// return(0);
+// }
+// }
+// return(1);
+//}
+//
+//bool MDFN_DumpToFile(const char *filename, int compress, const std::vector &pearpairs)
+//{
+// return(MDFN_DumpToFileReal(filename, compress, pearpairs));
+//}
+//
+//bool MDFN_DumpToFile(const char *filename, int compress, const void *data, uint64 length)
+//{
+// std::vector tmp_pairs;
+// tmp_pairs.push_back(PtrLengthPair(data, length));
+// return(MDFN_DumpToFileReal(filename, compress, tmp_pairs));
+//}
diff --git a/psx/octoshock/file.h b/psx/octoshock/file.h
new file mode 100644
index 0000000000..847a038de9
--- /dev/null
+++ b/psx/octoshock/file.h
@@ -0,0 +1,122 @@
+#pragma once
+
+#include
+
+class Stream;
+
+#define MDFNFILE_EC_NOTFOUND 1
+#define MDFNFILE_EC_OTHER 2
+
+class MDFNFILE
+{
+ public:
+
+ MDFNFILE(const char *path, const void *known_ext, const char *purpose = NULL);
+ ~MDFNFILE();
+
+ void ApplyIPS(Stream *);
+ void Close(void) throw();
+
+ const int64 &size;
+ const uint8 * const &data;
+ const char * const &ext;
+ const char * const &fbase;
+
+ inline int64 Size(void)
+ {
+ return(f_size);
+ }
+
+ inline const uint8 *Data(void)
+ {
+ return(f_data);
+ }
+
+ uint64 fread(void *ptr, size_t size, size_t nmemb);
+ int fseek(int64 offset, int whence);
+
+ inline uint64 ftell(void)
+ {
+ return(location);
+ }
+
+ inline void rewind(void)
+ {
+ location = 0;
+ }
+
+ int read32le(uint32 *Bufo);
+ int read16le(uint16 *Bufo);
+
+ inline int fgetc(void)
+ {
+ if(location < f_size)
+ return f_data[location++];
+
+ return EOF;
+ }
+
+ inline int fisarchive(void)
+ {
+ return(0);
+ }
+
+ char *fgets(char *s, int size);
+
+ private:
+
+ uint8 *f_data;
+ int64 f_size;
+ char *f_ext;
+ char *f_fbase;
+
+ int64 location;
+
+ #ifdef HAVE_MMAP
+ bool is_mmap;
+ #endif
+
+ void Open(const char *path, const void *known_ext, const char *purpose = NULL);
+ void MakeMemWrap(void *tz, int type);
+};
+
+class PtrLengthPair
+{
+ public:
+
+ inline PtrLengthPair(const void *new_data, const uint64 new_length)
+ {
+ data = new_data;
+ length = new_length;
+ }
+
+ ~PtrLengthPair()
+ {
+
+ }
+
+ INLINE const void *GetData(void) const
+ {
+ return(data);
+ }
+
+ INLINE uint64 GetLength(void) const
+ {
+ return(length);
+ }
+
+ private:
+ const void *data;
+ uint64 length;
+};
+
+#include
+
+// These functions should be used for data like save states and non-volatile backup memory.
+// Until(if, even) we add LoadFromFile functions, for reading the files these functions generate, just use gzopen(), gzread(), etc.
+// "compress" is set to the zlib compression level. 0 disables compression entirely, and dumps the file without a gzip header or footer.
+// (Note: There is a setting that will force compress to 0 in the internal DumpToFile logic, for hackers who don't want to ungzip save files.)
+
+bool MDFN_DumpToFile(const char *filename, int compress, const void *data, const uint64 length);
+bool MDFN_DumpToFile(const char *filename, int compress, const std::vector &pearpairs);
+
diff --git a/psx/octoshock/git.h b/psx/octoshock/git.h
new file mode 100644
index 0000000000..a74cdcbcde
--- /dev/null
+++ b/psx/octoshock/git.h
@@ -0,0 +1,357 @@
+#ifndef _GIT_H
+#define _GIT_H
+
+#include
+
+#include "octoshock.h"
+
+#include "video.h"
+#include "file.h"
+
+class CDIF;
+
+typedef struct
+{
+ const char *extension; // Example ".nes"
+ const char *description; // Example "iNES Format ROM Image"
+} FileExtensionSpecStruct;
+
+#include "file.h"
+
+enum
+{
+ MDFN_ROTATE0 = 0,
+ MDFN_ROTATE90,
+ MDFN_ROTATE180,
+ MDFN_ROTATE270
+};
+
+typedef enum
+{
+ VIDSYS_NONE, // Can be used internally in system emulation code, but it is an error condition to let it continue to be
+ // after the Load() or LoadCD() function returns!
+ VIDSYS_PAL,
+ VIDSYS_PAL_M, // Same timing as NTSC, but uses PAL-style colour encoding
+ VIDSYS_NTSC,
+ VIDSYS_SECAM
+} VideoSystems;
+
+typedef enum
+{
+ GMT_CART, // Self-explanatory!
+ GMT_ARCADE, // VS Unisystem, PC-10...
+ GMT_DISK, // Famicom Disk System, mostly
+ GMT_CDROM, // PC Engine CD, PC-FX
+ GMT_PLAYER // Music player(NSF, HES, GSF)
+} GameMediumTypes;
+
+#include "state.h"
+
+#ifdef WANT_DEBUGGER
+// #ifdef WANT_DEBUGGER
+// typedef struct DebuggerInfoStruct;
+// #else
+#include "debug.h"
+
+#endif
+
+typedef enum
+{
+ IDIT_BUTTON, // 1-bit
+ IDIT_BUTTON_CAN_RAPID, // 1-bit
+
+ IDIT_X_AXIS, // (mouse) 16-bits, signed - in-screen/window range: [0.0, nominal_width)
+ IDIT_Y_AXIS, // (mouse) 16-bits, signed - in-screen/window range: [0.0, nominal_height)
+
+ IDIT_X_AXIS_REL, // (mouse) 32-bits, signed
+ IDIT_Y_AXIS_REL, // (mouse) 32-bits, signed
+
+ IDIT_BYTE_SPECIAL,
+
+ IDIT_BUTTON_ANALOG, // 16-bits, 0 - 32767
+
+ IDIT_RUMBLE, // 16-bits, lower 8 bits are weak rumble(0-255), next 8 bits are strong rumble(0-255), 0=no rumble, 255=max rumble. Somewhat subjective, too...
+ // It's a rather special case of game module->driver code communication.
+} InputDeviceInputType;
+
+
+#define IDIT_BUTTON_ANALOG_FLAG_SQLR 0x00000001 // Denotes analog data that may need to be scaled to ensure a more squareish logical range(for emulated
+ // analog sticks).
+
+typedef struct
+{
+ const char *SettingName; // No spaces, shouldbe all a-z0-9 and _. Definitely no ~!
+ const char *Name;
+ const int ConfigOrder; // Configuration order during in-game config process, -1 for no config.
+ const InputDeviceInputType Type;
+ const char *ExcludeName; // SettingName of a button that can't be pressed at the same time as this button
+ // due to physical limitations.
+
+ const char *RotateName[3]; // 90, 180, 270
+ unsigned Flags;
+} InputDeviceInputInfoStruct;
+
+typedef struct
+{
+ const char *ShortName;
+ const char *FullName;
+ const char *Description;
+
+ //struct InputPortInfoStruct *PortExpanderDeviceInfo;
+ const void *PortExpanderDeviceInfo; // DON'T USE, IT'S NOT IMPLEMENTED PROPERLY CURRENTLY.
+ int NumInputs; // Usually just the number of buttons....OR if PortExpanderDeviceInfo is non-NULL, it's the number of input
+ // ports this port expander device provides.
+ const InputDeviceInputInfoStruct *IDII;
+} InputDeviceInfoStruct;
+
+typedef struct
+{
+ const char *ShortName;
+ const char *FullName;
+ int NumTypes; // Number of unique input devices available for this input port
+ InputDeviceInfoStruct *DeviceInfo;
+ const char *DefaultDevice; // Default device for this port.
+} InputPortInfoStruct;
+
+typedef struct
+{
+ int InputPorts;
+ const InputPortInfoStruct *Types;
+} InputInfoStruct;
+
+struct MemoryPatch;
+
+typedef struct
+{
+ // Pitch(32-bit) must be equal to width and >= the "fb_width" specified in the MDFNGI struct for the emulated system.
+ // Height must be >= to the "fb_height" specified in the MDFNGI struct for the emulated system.
+ // The framebuffer pointed to by surface->pixels is written to by the system emulation code.
+ MDFN_Surface *surface;
+
+ // Will be set to TRUE if the video pixel format has changed since the last call to Emulate(), FALSE otherwise.
+ // Will be set to TRUE on the first call to the Emulate() function/method
+ bool VideoFormatChanged;
+
+ // Set by the system emulation code every frame, to denote the horizontal and vertical offsets of the image, and the size
+ // of the image. If the emulated system sets the elements of LineWidths, then the width(w) of this structure
+ // is ignored while drawing the image.
+ MDFN_Rect DisplayRect;
+
+ // Pointer to an array of int32, number of elements = fb_height, set by the driver code. Individual elements written
+ // to by system emulation code. If the emulated system doesn't support multiple screen widths per frame, or if you handle
+ // such a situation by outputting at a constant width-per-frame that is the least-common-multiple of the screen widths, then
+ // you can ignore this. If you do wish to use this, you must set all elements every frame.
+ int32 *LineWidths;
+
+ // TODO
+ bool *IsFMV;
+
+ // Set(optionally) by emulation code. If InterlaceOn is true, then assume field height is 1/2 DisplayRect.h, and
+ // only every other line in surface (with the start line defined by InterlacedField) has valid data
+ // (it's up to internal Mednafen code to deinterlace it).
+ bool InterlaceOn;
+ bool InterlaceField;
+
+ // Skip rendering this frame if true. Set by the driver code.
+ int skip;
+
+ //
+ // If sound is disabled, the driver code must set SoundRate to false, SoundBuf to NULL, SoundBufMaxSize to 0.
+
+ // Will be set to TRUE if the sound format(only rate for now, at least) has changed since the last call to Emulate(), FALSE otherwise.
+ // Will be set to TRUE on the first call to the Emulate() function/method
+ bool SoundFormatChanged;
+
+ // Sound rate. Set by driver side.
+ double SoundRate;
+
+ // Pointer to sound buffer, set by the driver code, that the emulation code should render sound to.
+ // Guaranteed to be at least 500ms in length, but emulation code really shouldn't exceed 40ms or so. Additionally, if emulation code
+ // generates >= 100ms,
+ // DEPRECATED: Emulation code may set this pointer to a sound buffer internal to the emulation module.
+ int16 *SoundBuf;
+
+ // Maximum size of the sound buffer, in frames. Set by the driver code.
+ int32 SoundBufMaxSize;
+
+ // Number of frames currently in internal sound buffer. Set by the system emulation code, to be read by the driver code.
+ int32 SoundBufSize;
+ int32 SoundBufSizeALMS; // SoundBufSize value at last MidSync(), 0
+ // if mid sync isn't implemented for the emulation module in use.
+
+ // Number of cycles that this frame consumed, using MDFNGI::MasterClock as a time base.
+ // Set by emulation code.
+ int64 MasterCycles;
+ int64 MasterCyclesALMS; // MasterCycles value at last MidSync(), 0
+ // if mid sync isn't implemented for the emulation module in use.
+
+ // Current sound volume(0.000...<=volume<=1.000...). If, after calling Emulate(), it is still != 1, Mednafen will handle it internally.
+ // Emulation modules can handle volume themselves if they like, for speed reasons. If they do, afterwards, they should set its value to 1.
+ double SoundVolume;
+
+ // Current sound speed multiplier. Set by the driver code. If, after calling Emulate(), it is still != 1, Mednafen will handle it internally
+ // by resampling the audio. This means that emulation modules can handle(and set the value to 1 after handling it) it if they want to get the most
+ // performance possible. HOWEVER, emulation modules must make sure the value is in a range(with minimum and maximum) that their code can handle
+ // before they try to handle it.
+ double soundmultiplier;
+
+ // True if we want to rewind one frame. Set by the driver code.
+ bool NeedRewind;
+
+ // Sound reversal during state rewinding is normally done in mednafen.cpp, but
+ // individual system emulation code can also do it if this is set, and clear it after it's done.
+ // (Also, the driver code shouldn't touch this variable)
+ bool NeedSoundReverse;
+
+} EmulateSpecStruct;
+
+
+
+typedef struct
+{
+ /* Private functions to Mednafen. Do not call directly
+ from the driver code, or else bad things shall happen. Maybe. Probably not, but don't
+ do it(yet)!
+ */
+ // Short system name, lowercase a-z, 0-9, and _ are the only allowable characters!
+ const char *shortname;
+
+ // Full system name. Preferably English letters, but can be UTF8
+ const char *fullname;
+
+ // Pointer to an array of FileExtensionSpecStruct, with the last entry being { NULL, NULL } to terminate the list.
+ // This list is used to make best-guess choices, when calling the TestMagic*() functions would be unreasonable, such
+ // as when scanning a ZIP archive for a file to load. The list may also be used in the future for GUI file open windows.
+ const FileExtensionSpecStruct *FileExtensions;
+
+ #ifdef WANT_DEBUGGER
+ DebuggerInfoStruct *Debugger;
+ #else
+ void *Debugger;
+ #endif
+ InputInfoStruct *InputInfo;
+
+ //
+ // Returns 1 on successful load.
+ // throws exception on fatal error.
+ //
+ // DEPRECATED: Return 0 on fatal error.
+ // DEPRECATED: Return -1 on unrecognized format.
+ //
+ // fp's stream position is guaranteed to be 0 when this function is called.
+ //
+ int (*Load)(MDFNFILE *fp);
+
+ //
+ // Return true if the file is a recognized type, false if not.
+ //
+ // fp's stream position is guaranteed to be 0 when this function is called.
+ //
+ bool (*TestMagic)(MDFNFILE *fp);
+
+ //
+ // (*CDInterfaces).size() is guaranteed to be >= 1.
+ void (*LoadCD)(std::vector *CDInterfaces);
+ bool (*TestMagicCD)(std::vector *CDInterfaces);
+
+ void (*CloseGame)(void);
+
+ void (*SetLayerEnableMask)(uint64 mask); // Video
+ const char *LayerNames;
+
+ void (*SetChanEnableMask)(uint64 mask); // Audio(TODO, placeholder)
+ const char *ChanNames;
+
+ //
+ // InstallReadPatch and RemoveReadPatches should be non-NULL(even if only pointing to dummy functions) if the emulator module supports
+ // read-substitution and read-substitution-with-compare style(IE Game Genie-style) cheats.
+ //
+ // See also "SubCheats" global stuff in mempatcher.h.
+ //
+ void (*InstallReadPatch)(uint32 address, uint8 value, int compare); // Compare is >= 0 when utilized.
+ void (*RemoveReadPatches)(void);
+ uint8 (*MemRead)(uint32 addr);
+
+ bool SaveStateAltersState; // true for bsnes and some libco-style emulators, false otherwise.
+ // Main save state routine, called by the save state code in state.cpp.
+ // When saving, load is set to 0. When loading, load is set to the version field of the save state being loaded.
+ // data_only is true when the save state data is temporary, such as being saved into memory for state rewinding.
+ int (*StateAction)(StateMem *sm, int load, int data_only);
+
+ void (*Emulate)(EmulateSpecStruct *espec);
+ void (*SetInput)(int port, const char *type, void *ptr);
+
+ void (*DoSimpleCommand)(int cmd);
+
+ // Time base for EmulateSpecStruct::MasterCycles
+ // MasterClock must be >= MDFN_MASTERCLOCK_FIXED(1.0)
+ // All or part of the fractional component may be ignored in some timekeeping operations in the emulator to prevent integer overflow,
+ // so it is unwise to have a fractional component when the integral component is very small(less than say, 10000).
+ #define MDFN_MASTERCLOCK_FIXED(n) ((int64)((double)(n) * (1LL << 32)))
+ int64 MasterClock;
+
+ // Nominal frames per second * 65536 * 256, truncated.
+ // May be deprecated in the future due to many systems having slight frame rate programmability.
+ uint32 fps;
+
+ // multires is a hint that, if set, indicates that the system has fairly programmable video modes(particularly, the ability
+ // to display multiple horizontal resolutions, such as the PCE, PC-FX, or Genesis). In practice, it will cause the driver
+ // code to set the linear interpolation on by default.
+ //
+ // lcm_width and lcm_height are the least common multiples of all possible
+ // resolutions in the frame buffer as specified by DisplayRect/LineWidths(Ex for PCE: widths of 256, 341.333333, 512,
+ // lcm = 1024)
+ //
+ // nominal_width and nominal_height specify the resolution that Mednafen should display
+ // the framebuffer image in at 1x scaling, scaled from the dimensions of DisplayRect, and optionally the LineWidths array
+ // passed through espec to the Emulate() function.
+ //
+ bool multires;
+
+ int lcm_width;
+ int lcm_height;
+
+ void *dummy_separator; //
+
+ int nominal_width;
+ int nominal_height;
+
+ int fb_width; // Width of the framebuffer(not necessarily width of the image). MDFN_Surface width should be >= this.
+ int fb_height; // Height of the framebuffer passed to the Emulate() function(not necessarily height of the image)
+
+ int soundchan; // Number of output sound channels. Only values of 1 and 2 are currently supported.
+
+
+ int rotated;
+
+ uint8 *name; /* Game name, UTF8 encoding */
+ uint8 MD5[16];
+ uint8 GameSetMD5[16]; /* A unique ID for the game set this CD belongs to, only used in PC-FX emulation. */
+ bool GameSetMD5Valid; /* True if GameSetMD5 is valid. */
+
+ uint8 StateMD5[16]; // ID to use in save state naming and netplay session IDs, if
+ bool StateMD5Valid; // StateMD5Valid is true(useful for systems with multiple BIOS revisions, e.g. PS1).
+
+ int soundrate; /* For Ogg Vorbis expansion sound wacky support. 0 for default. */
+
+ VideoSystems VideoSystem;
+ GameMediumTypes GameType;
+
+ //int DiskLogicalCount; // A single double-sided disk would be 2 here.
+ //const char *DiskNames; // Null-terminated.
+
+ const char *cspecial; /* Special cart expansion: DIP switches, barcode reader, etc. */
+
+ std::vectorDesiredInput; // Desired input device for the input ports, NULL for don't care
+
+ // For mouse relative motion.
+ double mouse_sensitivity;
+
+
+ //
+ // For absolute coordinates(IDIT_X_AXIS and IDIT_Y_AXIS), usually mapped to a mouse(hence the naming).
+ //
+ float mouse_scale_x, mouse_scale_y;
+ float mouse_offs_x, mouse_offs_y;
+} MDFNGI;
+#endif
diff --git a/psx/octoshock/masmem.h b/psx/octoshock/masmem.h
new file mode 100644
index 0000000000..2b6043c434
--- /dev/null
+++ b/psx/octoshock/masmem.h
@@ -0,0 +1,209 @@
+#ifndef __MDFN_PSX_MASMEM_H
+#define __MDFN_PSX_MASMEM_H
+
+// TODO, WIP (big-endian stores and loads not fully supported yet)
+
+#ifdef LSB_FIRST
+ #define MAS_NATIVE_IS_BIGENDIAN 0
+#else
+ #define MAS_NATIVE_IS_BIGENDIAN 1
+#endif
+
+static INLINE uint16 LoadU16_RBO(const uint16 *a)
+{
+ #ifdef ARCH_POWERPC
+ uint16 tmp;
+
+ __asm__ ("lhbrx %0, %y1" : "=r"(tmp) : "Z"(*a));
+
+ return(tmp);
+
+ #else
+ uint16 tmp = *a;
+ return((tmp << 8) | (tmp >> 8));
+ #endif
+}
+
+static INLINE uint32 LoadU32_RBO(const uint32 *a)
+{
+ #ifdef ARCH_POWERPC
+ uint32 tmp;
+
+ __asm__ ("lwbrx %0, %y1" : "=r"(tmp) : "Z"(*a));
+
+ return(tmp);
+ #else
+ uint32 tmp = *a;
+ return((tmp << 24) | ((tmp & 0xFF00) << 8) | ((tmp >> 8) & 0xFF00) | (tmp >> 24));
+ #endif
+}
+
+static INLINE void StoreU16_RBO(uint16 *a, const uint16 v)
+{
+ #ifdef ARCH_POWERPC
+ __asm__ ("sthbrx %0, %y1" : : "r"(v), "Z"(*a));
+ #else
+ uint16 tmp = (v << 8) | (v >> 8);
+ *a = tmp;
+ #endif
+}
+
+static INLINE void StoreU32_RBO(uint32 *a, const uint32 v)
+{
+ #ifdef ARCH_POWERPC
+ __asm__ ("stwbrx %0, %y1" : : "r"(v), "Z"(*a));
+ #else
+ uint32 tmp = (v << 24) | ((v & 0xFF00) << 8) | ((v >> 8) & 0xFF00) | (v >> 24);
+ *a = tmp;
+ #endif
+}
+
+static INLINE uint16 LoadU16_LE(const uint16 *a)
+{
+#ifdef MSB_FIRST
+ return LoadU16_RBO(a);
+#else
+ return *a;
+#endif
+}
+
+static INLINE uint32 LoadU32_LE(const uint32 *a)
+{
+#ifdef MSB_FIRST
+ return LoadU32_RBO(a);
+#else
+ return *a;
+#endif
+}
+
+static INLINE void StoreU16_LE(uint16 *a, const uint16 v)
+{
+#ifdef MSB_FIRST
+ StoreU16_RBO(a, v);
+#else
+ *a = v;
+#endif
+}
+
+static INLINE void StoreU32_LE(uint32 *a, const uint32 v)
+{
+#ifdef MSB_FIRST
+ StoreU32_RBO(a, v);
+#else
+ *a = v;
+#endif
+}
+
+
+// address must not be >= size specified by template parameter, and address must be a multiple of the byte-size of the
+// unit(1,2,4) being read(except for Read/WriteU24, which only needs to be byte-aligned).
+//
+// max_unit_type should be uint16 or uint32
+//
+// pre_padding and post_padding are specified in units of sizeof(max_unit_type).
+//
+template //, unsigned pre_padding_count, unsigned post_padding_count>
+struct MultiAccessSizeMem
+{
+ //max_unit_type pre_padding[pre_padding_count ? pre_padding_count : 1];
+
+ union
+ {
+ uint8 data8[size];
+ uint16 data16[size / sizeof(uint16)];
+ uint32 data32[size / sizeof(uint32)];
+ };
+
+ //max_unit_type post_padding[post_padding_count ? post_padding_count : 1];
+
+ INLINE uint8 ReadU8(uint32 address)
+ {
+ return data8[address];
+ }
+
+ INLINE uint16 ReadU16(uint32 address)
+ {
+ if(MAS_NATIVE_IS_BIGENDIAN == big_endian)
+ return *(uint16*)(((uint8*)data16) + address);
+ else
+ return LoadU16_RBO((uint16*)(((uint8*)data16) + address));
+ }
+
+ INLINE uint32 ReadU32(uint32 address)
+ {
+ if(MAS_NATIVE_IS_BIGENDIAN == big_endian)
+ return *(uint32*)(((uint8*)data32) + address);
+ else
+ return LoadU32_RBO((uint32*)(((uint8*)data32) + address));
+ }
+
+ INLINE uint32 ReadU24(uint32 address)
+ {
+ uint32 ret;
+
+ if(!big_endian)
+ {
+ ret = ReadU8(address) | (ReadU8(address + 1) << 8) | (ReadU8(address + 2) << 16);
+ }
+
+ return(ret);
+ }
+
+
+ INLINE void WriteU8(uint32 address, uint8 value)
+ {
+ data8[address] = value;
+ }
+
+ INLINE void WriteU16(uint32 address, uint16 value)
+ {
+ if(MAS_NATIVE_IS_BIGENDIAN == big_endian)
+ *(uint16*)(((uint8*)data16) + address) = value;
+ else
+ StoreU16_RBO((uint16*)(((uint8*)data16) + address), value);
+ }
+
+ INLINE void WriteU32(uint32 address, uint32 value)
+ {
+ if(MAS_NATIVE_IS_BIGENDIAN == big_endian)
+ *(uint32*)(((uint8*)data32) + address) = value;
+ else
+ StoreU32_RBO((uint32*)(((uint8*)data32) + address), value);
+ }
+
+ INLINE void WriteU24(uint32 address, uint32 value)
+ {
+ if(!big_endian)
+ {
+ WriteU8(address + 0, value >> 0);
+ WriteU8(address + 1, value >> 8);
+ WriteU8(address + 2, value >> 16);
+ }
+ }
+
+ template
+ INLINE T Read(uint32 address)
+ {
+ if(sizeof(T) == 4)
+ return(ReadU32(address));
+ else if(sizeof(T) == 2)
+ return(ReadU16(address));
+ else
+ return(ReadU8(address));
+ }
+
+ template
+ INLINE void Write(uint32 address, T value)
+ {
+ if(sizeof(T) == 4)
+ WriteU32(address, value);
+ else if(sizeof(T) == 2)
+ WriteU16(address, value);
+ else
+ WriteU8(address, value);
+ }
+};
+
+#undef MAS_NATIVE_IS_BIGENDIAN
+
+#endif
diff --git a/psx/octoshock/math_ops.h b/psx/octoshock/math_ops.h
new file mode 100644
index 0000000000..09aa131365
--- /dev/null
+++ b/psx/octoshock/math_ops.h
@@ -0,0 +1,87 @@
+#pragma once
+
+#include "emuware/emuware.h"
+
+// Source: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+// Rounds up to the nearest power of 2.
+static INLINE uint64 round_up_pow2(uint64 v)
+{
+ v--;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ v |= v >> 32;
+ v++;
+
+ v += (v == 0);
+
+ return(v);
+}
+
+static INLINE uint32 uilog2(uint32 v)
+{
+ // http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn
+
+ static const uint32 MultiplyDeBruijnBitPosition[32] =
+ {
+ 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
+ 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
+ };
+
+ v |= v >> 1; // first round down to one less than a power of 2
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+
+ return MultiplyDeBruijnBitPosition[(uint32_t)(v * 0x07C4ACDDU) >> 27];
+}
+
+// Some compilers' optimizers and some platforms might fubar the generated code from these macros,
+// so some tests are run in...tests.cpp
+#define sign_8_to_s16(_value) ((int16)(int8)(_value))
+#define sign_9_to_s16(_value) (((int16)((unsigned int)(_value) << 7)) >> 7)
+#define sign_10_to_s16(_value) (((int16)((uint32)(_value) << 6)) >> 6)
+#define sign_11_to_s16(_value) (((int16)((uint32)(_value) << 5)) >> 5)
+#define sign_12_to_s16(_value) (((int16)((uint32)(_value) << 4)) >> 4)
+#define sign_13_to_s16(_value) (((int16)((uint32)(_value) << 3)) >> 3)
+#define sign_14_to_s16(_value) (((int16)((uint32)(_value) << 2)) >> 2)
+#define sign_15_to_s16(_value) (((int16)((uint32)(_value) << 1)) >> 1)
+
+// This obviously won't convert higher-than-32 bit numbers to signed 32-bit ;)
+// Also, this shouldn't be used for 8-bit and 16-bit signed numbers, since you can
+// convert those faster with typecasts...
+#define sign_x_to_s32(_bits, _value) (((int32)((uint32)(_value) << (32 - _bits))) >> (32 - _bits))
+
+static INLINE int32 clamp_to_u8(int32 i)
+{
+ if(i & 0xFFFFFF00)
+ i = (((~i) >> 30) & 0xFF);
+
+ return(i);
+}
+
+static INLINE int32 clamp_to_u16(int32 i)
+{
+ if(i & 0xFFFF0000)
+ i = (((~i) >> 31) & 0xFFFF);
+
+ return(i);
+}
+
+template static INLINE void clamp(T *val, U minimum, V maximum)
+{
+ if(*val < minimum)
+ {
+ //printf("Warning: clamping to minimum(%d)\n", (int)minimum);
+ *val = minimum;
+ }
+ if(*val > maximum)
+ {
+ //printf("Warning: clamping to maximum(%d)\n", (int)maximum);
+ *val = maximum;
+ }
+}
+
diff --git a/psx/octoshock/octoshock.cpp b/psx/octoshock/octoshock.cpp
new file mode 100644
index 0000000000..c8842921bd
--- /dev/null
+++ b/psx/octoshock/octoshock.cpp
@@ -0,0 +1,3 @@
+#include "octoshock.h"
+
+//this file intentionally empty
\ No newline at end of file
diff --git a/psx/octoshock/octoshock.h b/psx/octoshock/octoshock.h
new file mode 100644
index 0000000000..d71828d296
--- /dev/null
+++ b/psx/octoshock/octoshock.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "emuware/emuware.h"
+
+#define SIZEOF_DOUBLE 8
+
+#define LSB_FIRST
+
+EW_EXPORT int os_test();
+
diff --git a/psx/octoshock/psx/Makefile.am b/psx/octoshock/psx/Makefile.am
new file mode 100644
index 0000000000..c5890eb3cf
--- /dev/null
+++ b/psx/octoshock/psx/Makefile.am
@@ -0,0 +1,12 @@
+AUTOMAKE_OPTIONS = subdir-objects
+DEFS = -DLOCALEDIR=\"$(datadir)/locale\" @DEFS@ @MMX_CFLAGS@ @SSE_CFLAGS@ @SSE2_CFLAGS@ -funroll-loops
+DEFAULT_INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I$(top_srcdir)/intl
+
+noinst_LIBRARIES = libpsx.a
+libpsx_a_SOURCES = psx.cpp irq.cpp timer.cpp dma.cpp frontio.cpp sio.cpp cpu.cpp gte.cpp dis.cpp cdc.cpp spu.cpp gpu.cpp mdec.cpp
+
+libpsx_a_SOURCES += input/gamepad.cpp input/dualanalog.cpp input/dualshock.cpp input/memcard.cpp input/multitap.cpp input/mouse.cpp input/negcon.cpp input/guncon.cpp input/justifier.cpp
+
+if WANT_DEBUGGER
+libpsx_a_SOURCES += debug.cpp
+endif
diff --git a/psx/octoshock/psx/Makefile.in b/psx/octoshock/psx/Makefile.in
new file mode 100644
index 0000000000..d6a71d9c6b
--- /dev/null
+++ b/psx/octoshock/psx/Makefile.in
@@ -0,0 +1,699 @@
+# Makefile.in generated by automake 1.11.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__make_dryrun = \
+ { \
+ am__dry=no; \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
+ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+ *) \
+ for am__flg in $$MAKEFLAGS; do \
+ case $$am__flg in \
+ *=*|--*) ;; \
+ *n*) am__dry=yes; break;; \
+ esac; \
+ done;; \
+ esac; \
+ test $$am__dry = yes; \
+ }
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+@WANT_DEBUGGER_TRUE@am__append_1 = debug.cpp
+subdir = src/psx
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cflags_gcc_option.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/fcntl-o.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/glibc2.m4 \
+ $(top_srcdir)/m4/glibc21.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intdiv0.m4 $(top_srcdir)/m4/intl.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intmax.m4 \
+ $(top_srcdir)/m4/inttypes-pri.m4 \
+ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lcmessage.m4 \
+ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
+ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/lock.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/printf-posix.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/stdint_h.m4 \
+ $(top_srcdir)/m4/threadlib.m4 $(top_srcdir)/m4/uintmax_t.m4 \
+ $(top_srcdir)/m4/visibility.m4 $(top_srcdir)/m4/wchar_t.m4 \
+ $(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/xsize.m4 \
+ $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/include/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo " AR " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+libpsx_a_AR = $(AR) $(ARFLAGS)
+libpsx_a_LIBADD =
+am__libpsx_a_SOURCES_DIST = psx.cpp irq.cpp timer.cpp dma.cpp \
+ frontio.cpp sio.cpp cpu.cpp gte.cpp dis.cpp cdc.cpp spu.cpp \
+ gpu.cpp mdec.cpp input/gamepad.cpp input/dualanalog.cpp \
+ input/dualshock.cpp input/memcard.cpp input/multitap.cpp \
+ input/mouse.cpp input/negcon.cpp input/guncon.cpp \
+ input/justifier.cpp debug.cpp
+am__dirstamp = $(am__leading_dot)dirstamp
+@WANT_DEBUGGER_TRUE@am__objects_1 = debug.$(OBJEXT)
+am_libpsx_a_OBJECTS = psx.$(OBJEXT) irq.$(OBJEXT) timer.$(OBJEXT) \
+ dma.$(OBJEXT) frontio.$(OBJEXT) sio.$(OBJEXT) cpu.$(OBJEXT) \
+ gte.$(OBJEXT) dis.$(OBJEXT) cdc.$(OBJEXT) spu.$(OBJEXT) \
+ gpu.$(OBJEXT) mdec.$(OBJEXT) input/gamepad.$(OBJEXT) \
+ input/dualanalog.$(OBJEXT) input/dualshock.$(OBJEXT) \
+ input/memcard.$(OBJEXT) input/multitap.$(OBJEXT) \
+ input/mouse.$(OBJEXT) input/negcon.$(OBJEXT) \
+ input/guncon.$(OBJEXT) input/justifier.$(OBJEXT) \
+ $(am__objects_1)
+libpsx_a_OBJECTS = $(am_libpsx_a_OBJECTS)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libpsx_a_SOURCES)
+DIST_SOURCES = $(am__libpsx_a_SOURCES_DIST)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AM_CFLAGS = @AM_CFLAGS@
+AM_CXXFLAGS = @AM_CXXFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CFLAG_VISIBILITY = @CFLAG_VISIBILITY@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DEFS = -DLOCALEDIR=\"$(datadir)/locale\" @DEFS@ @MMX_CFLAGS@ @SSE_CFLAGS@ @SSE2_CFLAGS@ -funroll-loops
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GBA_EXTRA_FLAGS = @GBA_EXTRA_FLAGS@
+GENCAT = @GENCAT@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GLIBC2 = @GLIBC2@
+GLIBC21 = @GLIBC21@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+HAVE_ASPRINTF = @HAVE_ASPRINTF@
+HAVE_NEWLOCALE = @HAVE_NEWLOCALE@
+HAVE_POSIX_PRINTF = @HAVE_POSIX_PRINTF@
+HAVE_SNPRINTF = @HAVE_SNPRINTF@
+HAVE_VISIBILITY = @HAVE_VISIBILITY@
+HAVE_WPRINTF = @HAVE_WPRINTF@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLBISON = @INTLBISON@
+INTLLIBS = @INTLLIBS@
+INTLOBJS = @INTLOBJS@
+INTL_DEFAULT_VERBOSITY = @INTL_DEFAULT_VERBOSITY@
+INTL_LIBTOOL_SUFFIX_PREFIX = @INTL_LIBTOOL_SUFFIX_PREFIX@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCDIO_CFLAGS = @LIBCDIO_CFLAGS@
+LIBCDIO_LIBS = @LIBCDIO_LIBS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBMULTITHREAD = @LIBMULTITHREAD@
+LIBOBJS = @LIBOBJS@
+LIBPTH = @LIBPTH@
+LIBPTH_PREFIX = @LIBPTH_PREFIX@
+LIBS = @LIBS@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBC = @LTLIBC@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBMULTITHREAD = @LTLIBMULTITHREAD@
+LTLIBOBJS = @LTLIBOBJS@
+LTLIBPTH = @LTLIBPTH@
+LTLIBTHREAD = @LTLIBTHREAD@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MMX_CFLAGS = @MMX_CFLAGS@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POSUB = @POSUB@
+PRI_MACROS_BROKEN = @PRI_MACROS_BROKEN@
+RANLIB = @RANLIB@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_CONFIG = @SDL_CONFIG@
+SDL_LIBS = @SDL_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+SNES_EXTRA_CXXFLAGS = @SNES_EXTRA_CXXFLAGS@
+SNES_EXTRA_FLAGS = @SNES_EXTRA_FLAGS@
+SSE2_CFLAGS = @SSE2_CFLAGS@
+SSE3_CFLAGS = @SSE3_CFLAGS@
+SSE_CFLAGS = @SSE_CFLAGS@
+STRIP = @STRIP@
+TRIO_CFLAGS = @TRIO_CFLAGS@
+USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WARNING_FLAGS = @WARNING_FLAGS@
+WINDRES = @WINDRES@
+WOE32 = @WOE32@
+WOE32DLL = @WOE32DLL@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AUTOMAKE_OPTIONS = subdir-objects
+DEFAULT_INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I$(top_srcdir)/intl
+noinst_LIBRARIES = libpsx.a
+libpsx_a_SOURCES = psx.cpp irq.cpp timer.cpp dma.cpp frontio.cpp \
+ sio.cpp cpu.cpp gte.cpp dis.cpp cdc.cpp spu.cpp gpu.cpp \
+ mdec.cpp input/gamepad.cpp input/dualanalog.cpp \
+ input/dualshock.cpp input/memcard.cpp input/multitap.cpp \
+ input/mouse.cpp input/negcon.cpp input/guncon.cpp \
+ input/justifier.cpp $(am__append_1)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/psx/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/psx/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+input/$(am__dirstamp):
+ @$(MKDIR_P) input
+ @: > input/$(am__dirstamp)
+input/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) input/$(DEPDIR)
+ @: > input/$(DEPDIR)/$(am__dirstamp)
+input/gamepad.$(OBJEXT): input/$(am__dirstamp) \
+ input/$(DEPDIR)/$(am__dirstamp)
+input/dualanalog.$(OBJEXT): input/$(am__dirstamp) \
+ input/$(DEPDIR)/$(am__dirstamp)
+input/dualshock.$(OBJEXT): input/$(am__dirstamp) \
+ input/$(DEPDIR)/$(am__dirstamp)
+input/memcard.$(OBJEXT): input/$(am__dirstamp) \
+ input/$(DEPDIR)/$(am__dirstamp)
+input/multitap.$(OBJEXT): input/$(am__dirstamp) \
+ input/$(DEPDIR)/$(am__dirstamp)
+input/mouse.$(OBJEXT): input/$(am__dirstamp) \
+ input/$(DEPDIR)/$(am__dirstamp)
+input/negcon.$(OBJEXT): input/$(am__dirstamp) \
+ input/$(DEPDIR)/$(am__dirstamp)
+input/guncon.$(OBJEXT): input/$(am__dirstamp) \
+ input/$(DEPDIR)/$(am__dirstamp)
+input/justifier.$(OBJEXT): input/$(am__dirstamp) \
+ input/$(DEPDIR)/$(am__dirstamp)
+libpsx.a: $(libpsx_a_OBJECTS) $(libpsx_a_DEPENDENCIES) $(EXTRA_libpsx_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libpsx.a
+ $(AM_V_AR)$(libpsx_a_AR) libpsx.a $(libpsx_a_OBJECTS) $(libpsx_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libpsx.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+ -rm -f input/dualanalog.$(OBJEXT)
+ -rm -f input/dualshock.$(OBJEXT)
+ -rm -f input/gamepad.$(OBJEXT)
+ -rm -f input/guncon.$(OBJEXT)
+ -rm -f input/justifier.$(OBJEXT)
+ -rm -f input/memcard.$(OBJEXT)
+ -rm -f input/mouse.$(OBJEXT)
+ -rm -f input/multitap.$(OBJEXT)
+ -rm -f input/negcon.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debug.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dis.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dma.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/frontio.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpu.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gte.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irq.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mdec.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/psx.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sio.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spu.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/dualanalog.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/dualshock.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/gamepad.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/guncon.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/justifier.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/memcard.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/mouse.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/multitap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/negcon.Po@am__quote@
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -rm -f input/$(DEPDIR)/$(am__dirstamp)
+ -rm -f input/$(am__dirstamp)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR) input/$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR) input/$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/psx/octoshock/psx/PSFLoader.cpp b/psx/octoshock/psx/PSFLoader.cpp
new file mode 100644
index 0000000000..452166556b
--- /dev/null
+++ b/psx/octoshock/psx/PSFLoader.cpp
@@ -0,0 +1,336 @@
+/* Mednafen - Multi-system Emulator
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ TODO:
+ Time string parsing convenience functions.
+
+ Character set autodetect heuristics and conversion for when the "utf8" tag is missing.
+*/
+#include "mednafen.h"
+#include "PSFLoader.h"
+#include "endian.h"
+#include "general.h"
+#include "string/trim.h"
+
+#include
+#include
+#include
+//#include
+
+
+PSFTags::PSFTags()
+{
+
+
+}
+
+PSFTags::~PSFTags()
+{
+
+}
+
+void PSFTags::AddTag(char *tag_line)
+{
+ char *eq;
+
+ // Transform 0x01-0x1F -> 0x20
+ for(unsigned int i = 0; i < strlen(tag_line); i++)
+ if((unsigned char)tag_line[i] < 0x20)
+ tag_line[i] = 0x20;
+
+ eq = strchr(tag_line, '=');
+
+ if(eq)
+ {
+ *eq = 0;
+
+ MDFN_trim(tag_line);
+ MDFN_trim(eq + 1);
+
+ for(unsigned int i = 0; i < strlen(tag_line); i++)
+ tag_line[i] = tolower(tag_line[i]);
+
+ if(TagExists(tag_line))
+ tags[tag_line] = tags[std::string(tag_line)] + std::string(1, '\n') + std::string(eq + 1);
+ else
+ tags[tag_line] = std::string(eq + 1);
+ }
+}
+
+#if 0
+static const char *DetectCharset(const uint8 *data, const uint32 data_size)
+{
+ static const char *TestCharsets[] = { "UTF-8", /*"SJIS",*/ "WINDOWS-1252" };
+
+ for(unsigned int i = 0; i < sizeof(TestCharsets) / sizeof(TestCharsets[0]); i++)
+ {
+ iconv_t cd;
+
+ cd = iconv_open("UTF-32", TestCharsets[i]);
+ if(cd != (iconv_t)-1)
+ {
+ size_t in_len = data_size;
+ size_t out_len = data_size * 4 + 4;
+ char *in_ptr = (char *)data;
+ char *const out_ptr_mem = new char[out_len];
+ char *out_ptr = out_ptr_mem;
+
+ if(iconv(cd, (ICONV_CONST char **)&in_ptr, &in_len, &out_ptr, &out_len) != (size_t)-1)
+ {
+ delete[] out_ptr_mem;
+ return(TestCharsets[i]);
+ }
+ delete[] out_ptr_mem;
+ }
+ }
+
+ return(NULL);
+}
+#endif
+
+void PSFTags::LoadTags(const uint8 *data_in, uint32 size)
+{
+ std::vector tags_heap;
+ char *data;
+ char *spos;
+ //const char *detected_charset = DetectCharset(data_in, size);
+
+ tags_heap.resize(size + 1);
+ tags_heap[size] = 0;
+
+ memcpy(&tags_heap[0], data_in, size);
+
+ data = &tags_heap[0];
+ spos = data;
+
+ while(size)
+ {
+ if(*data == 0x0A || *data == 0x00)
+ {
+ *data = 0;
+
+ if(data - spos)
+ {
+ if(*(data - 1) == 0xD) // handle \r
+ *(data - 1) = 0;
+
+ AddTag(spos);
+ }
+
+ spos = data + 1; // Skip \n for next tag
+ }
+
+ size--;
+ data++;
+ }
+
+}
+
+int64 PSFTags::GetTagI(const char *name)
+{
+ std::map::iterator it;
+
+ it = tags.find(name);
+ if(it != tags.end())
+ {
+ long long ret = 0;
+ std::string &tmp = tags[name];
+
+ trio_sscanf(tmp.c_str(), "%lld", &ret);
+
+ return(ret);
+ }
+ return(0); // INT64_MIN
+}
+
+bool PSFTags::TagExists(const char *name)
+{
+ if(tags.find(name) != tags.end())
+ return(true);
+
+ return(false);
+}
+
+
+std::string PSFTags::GetTag(const char *name)
+{
+ std::map::iterator it;
+
+ it = tags.find(name);
+
+ if(it != tags.end())
+ return(it->second);
+
+ return("");
+}
+
+void PSFTags::EraseTag(const char *name)
+{
+ std::map::iterator it;
+
+ it = tags.find(name);
+ if(it != tags.end())
+ tags.erase(it);
+}
+
+PSFLoader::PSFLoader()
+{
+
+
+}
+
+PSFLoader::~PSFLoader()
+{
+
+
+}
+
+bool PSFLoader::TestMagic(uint8 version, MDFNFILE *fp)
+{
+ if(fp->size < (3 + 1 + 4 + 4 + 4))
+ return(false);
+
+ if(memcmp(fp->data, "PSF", 3))
+ return(false);
+
+ if(fp->data[3] != version)
+ return(false);
+
+ return(true);
+}
+
+PSFTags PSFLoader::LoadInternal(uint8 version, uint32 max_exe_size, MDFNFILE *fp, uint32 level, bool force_ignore_pcsp)
+{
+ uint32 reserved_size, compressed_size, compressed_crc32;
+ bool _lib_present = false;
+ PSFTags tags;
+
+ std::vector decompress_buffer;
+ uLongf decompress_len;
+
+ if(!TestMagic(version, fp))
+ throw(MDFN_Error(0, _("Not a PSF(version=0x%02x) file!"), version));
+
+ reserved_size = MDFN_de32lsb(fp->data + 4);
+ compressed_size = MDFN_de32lsb(fp->data + 8);
+ compressed_crc32 = MDFN_de32lsb(fp->data + 12);
+
+ if(fp->size < ((int64)16 + reserved_size + compressed_size))
+ throw MDFN_Error(0, _("PSF is missing at least %lld bytes of data!"), (long long)((int64)16 + reserved_size + compressed_size - fp->size));
+
+ if(crc32(0, fp->data + 16 + reserved_size, compressed_size) != compressed_crc32)
+ throw MDFN_Error(0, _("PSF compressed CRC32 mismatch(data is corrupt)!"));
+
+
+ {
+ const uint8 *tag_section = fp->data + 16 + reserved_size + compressed_size;
+ uint32 tag_section_size = fp->size - 16 - reserved_size - compressed_size;
+
+ if(tag_section_size > 5 && !memcmp(tag_section, "[TAG]", 5))
+ tags.LoadTags(tag_section + 5, tag_section_size - 5);
+ }
+
+ //
+ // Handle minipsf simple _lib
+ //
+
+ if(level < 15)
+ {
+ if(tags.TagExists("_lib"))
+ {
+ std::string tp = tags.GetTag("_lib");
+
+ if(!MDFN_IsFIROPSafe(tp))
+ {
+ throw(MDFN_Error(0, _("Referenced path \"%s\" is potentially unsafe. See \"filesys.untrusted_fip_check\" setting."), tp.c_str()));
+ }
+
+ MDFNFILE subfile(MDFN_MakeFName(MDFNMKF_AUX, 0, tp.c_str()).c_str(), NULL, NULL);
+
+ LoadInternal(version, max_exe_size, &subfile, level + 1);
+
+ _lib_present = true;
+ }
+ }
+
+ //
+ //
+ //
+
+ decompress_buffer.resize(max_exe_size);
+ decompress_len = max_exe_size;
+ switch( uncompress((Bytef *)&decompress_buffer[0], &decompress_len, (const Bytef *)(fp->data + 16 + reserved_size), compressed_size) )
+ {
+ default:
+ throw(MDFN_Error(0, "zlib unknown error"));
+
+ case Z_OK: break;
+
+ case Z_MEM_ERROR:
+ throw(MDFN_Error(0, "zlib Z_MEM_ERROR"));
+
+ case Z_BUF_ERROR:
+ throw(MDFN_Error(0, _("PSF decompressed size exceeds maximum allowed!")));
+
+ case Z_DATA_ERROR:
+ throw(MDFN_Error(0, _("PSF compressed data is bad.")));
+ }
+
+ HandleReserved(fp->data + 16, reserved_size);
+ HandleEXE(&decompress_buffer[0], decompress_len, force_ignore_pcsp | _lib_present);
+ decompress_buffer.resize(0);
+
+ //
+ // handle libN
+ //
+ if(level < 15)
+ {
+ for(unsigned int n = 2; n <= INT_MAX; n++)
+ {
+ char tmpbuf[32];
+
+ trio_snprintf(tmpbuf, 32, "_lib%d", (int)n);
+
+ if(tags.TagExists(tmpbuf))
+ {
+ MDFNFILE subfile(MDFN_MakeFName(MDFNMKF_AUX, 0, tags.GetTag(tmpbuf).c_str()).c_str(), NULL, NULL);
+
+ LoadInternal(version, max_exe_size, &subfile, level + 1, true);
+ }
+ else
+ break;
+ }
+ }
+
+ return(tags);
+}
+
+PSFTags PSFLoader::Load(uint8 version, uint32 max_exe_size, MDFNFILE *fp)
+{
+ return(LoadInternal(version, max_exe_size, fp, 0, false));
+}
+
+void PSFLoader::HandleReserved(const uint8 *data, uint32 len)
+{
+
+}
+
+void PSFLoader::HandleEXE(const uint8 *data, uint32 len, bool ignore_pcsp)
+{
+
+}
+
diff --git a/psx/octoshock/psx/PSFLoader.h b/psx/octoshock/psx/PSFLoader.h
new file mode 100644
index 0000000000..7511ef8b1a
--- /dev/null
+++ b/psx/octoshock/psx/PSFLoader.h
@@ -0,0 +1,49 @@
+#ifndef __MDFN_PSFLOADER_H
+#define __MDFN_PSFLOADER_H
+
+#include