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 +#include +#include +#include + +class PSFTags +{ + public: + + PSFTags(); + ~PSFTags(); + + int64 GetTagI(const char *name); + std::string GetTag(const char *name); + bool TagExists(const char *name); + + void LoadTags(const uint8 *data, uint32 size); + void EraseTag(const char *name); + + + private: + + void AddTag(char *tag_line); + std::map tags; +}; + +class PSFLoader +{ + public: + PSFLoader(); + ~PSFLoader(); + + static bool TestMagic(uint8 version, MDFNFILE *fp); + + PSFTags Load(uint8 version, uint32 max_exe_size, MDFNFILE *fp); + + virtual void HandleReserved(const uint8 *data, uint32 len); + virtual void HandleEXE(const uint8 *data, uint32 len, bool ignore_pcsp = false); + + private: + + PSFTags LoadInternal(uint8 version, uint32 max_exe_size, MDFNFILE *fp, uint32 level, bool force_ignore_pcsp = false); +}; + + +#endif diff --git a/psx/octoshock/psx/cdc.cpp b/psx/octoshock/psx/cdc.cpp new file mode 100644 index 0000000000..56514c1523 --- /dev/null +++ b/psx/octoshock/psx/cdc.cpp @@ -0,0 +1,2403 @@ +/* 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: async command counter and async command phase? +/* + + TODO: + Implement missing commands. + + SPU CD-DA and CD-XA streaming semantics. +*/ + +/* + After eject(doesn't appear to occur when drive is in STOP state): + * Does not appear to occur in STOP state. + * Does not appear to occur in PAUSE state. + * DOES appear to occur in STANDBY state. (TODO: retest) + +% Result 0: 16 +% Result 1: 08 +% IRQ Result: e5 +% 19 e0 + + Command abortion tests(NOP tested): + Does not appear to occur when in STOP or PAUSE states(STOP or PAUSE command just executed). + + DOES occur after a ReadTOC completes, if ReadTOC is not followed by a STOP or PAUSE. Odd. +*/ + +#include "psx.h" +#include "cdc.h" +#include "spu.h" +#include "cdrom/CDUtility.h" +#include "cdrom/cdromif.h" +#include "endian.h" + +using namespace CDUtility; + +namespace MDFN_IEN_PSX +{ + +PS_CDC::PS_CDC() : DMABuffer(4096) +{ + IsPSXDisc = false; + Cur_disc = NULL; + + DriveStatus = DS_STOPPED; + PendingCommandPhase = 0; +} + +PS_CDC::~PS_CDC() +{ + +} + +void PS_CDC::SetDisc(bool tray_open, ShockDiscRef *disc, const char *disc_id) +{ + if(tray_open) + disc = NULL; + + Cur_disc = disc; + IsPSXDisc = false; + memset(DiscID, 0, sizeof(DiscID)); + + if(!Cur_disc) + { + PSRCounter = 0; + + if((DriveStatus != DS_PAUSED && DriveStatus != DS_STOPPED) || PendingCommandPhase >= 2) + { + PendingCommand = 0x00; + PendingCommandCounter = 0; + PendingCommandPhase = 0; + } + + HeaderBufValid = false; + DriveStatus = DS_STOPPED; + ClearAIP(); + SectorPipe_Pos = SectorPipe_In = 0; + } + else + { + HeaderBufValid = false; + DiscStartupDelay = (int64)1000 * 33868800 / 1000; + DiscChanged = true; + + Cur_disc->ReadTOC((ShockTOC*)&toc,(ShockTOCTrack*)toc.tracks); + + if(disc_id) + { + strncpy((char *)DiscID, disc_id, 4); + IsPSXDisc = true; + } + } +} + +int32 PS_CDC::CalcNextEvent(void) +{ + int32 next_event = SPUCounter; + + if(PSRCounter > 0 && next_event > PSRCounter) + next_event = PSRCounter; + + if(PendingCommandCounter > 0 && next_event > PendingCommandCounter) + next_event = PendingCommandCounter; + + if(!IRQBuffer) + { + if(CDCReadyReceiveCounter > 0 && next_event > CDCReadyReceiveCounter) + next_event = CDCReadyReceiveCounter; + } + + if(DiscStartupDelay > 0 && next_event > DiscStartupDelay) + next_event = DiscStartupDelay; + + //fprintf(stderr, "%d %d %d %d --- %d\n", PSRCounter, PendingCommandCounter, CDCReadyReceiveCounter, DiscStartupDelay, next_event); + + return(next_event); +} + +void PS_CDC::SoftReset(void) +{ + ClearAudioBuffers(); + + // Not sure about initial volume state + Pending_DecodeVolume[0][0] = 0x80; + Pending_DecodeVolume[0][1] = 0x00; + Pending_DecodeVolume[1][0] = 0x00; + Pending_DecodeVolume[1][1] = 0x80; + memcpy(DecodeVolume, Pending_DecodeVolume, sizeof(DecodeVolume)); + + RegSelector = 0; + memset(ArgsBuf, 0, sizeof(ArgsBuf)); + ArgsWP = ArgsRP = 0; + + memset(ResultsBuffer, 0, sizeof(ResultsBuffer)); + ResultsWP = 0; + ResultsRP = 0; + ResultsIn = 0; + + CDCReadyReceiveCounter = 0; + + IRQBuffer = 0; + IRQOutTestMask = 0; + RecalcIRQ(); + + DMABuffer.Flush(); + SB_In = 0; + SectorPipe_Pos = SectorPipe_In = 0; + + memset(SubQBuf, 0, sizeof(SubQBuf)); + memset(SubQBuf_Safe, 0, sizeof(SubQBuf_Safe)); + SubQChecksumOK = false; + + memset(HeaderBuf, 0, sizeof(HeaderBuf)); + + + FilterFile = 0; + FilterChan = 0; + + PendingCommand = 0; + PendingCommandPhase = 0; + PendingCommandCounter = 0; + + Mode = 0; + + HeaderBufValid = false; + DriveStatus = DS_STOPPED; + ClearAIP(); + StatusAfterSeek = DS_STOPPED; + + Forward = false; + Backward = false; + Muted = false; + + PlayTrackMatch = 0; + + PSRCounter = 0; + + CurSector = 0; + + ClearAIP(); + + SeekTarget = 0; + + CommandLoc = 0; + CommandLoc_Dirty = true; + + DiscChanged = true; +} + +void PS_CDC::Power(void) +{ + SPU->Power(); + + SoftReset(); + + DiscStartupDelay = 0; + + SPUCounter = SPU->UpdateFromCDC(0); + lastts = 0; +} + +int PS_CDC::StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFVAR(DiscChanged), + SFVAR(DiscStartupDelay), + + SFARRAY16(&AudioBuffer.Samples[0][0], sizeof(AudioBuffer.Samples) / sizeof(AudioBuffer.Samples[0][0])), + SFVAR(AudioBuffer.Size), + SFVAR(AudioBuffer.Freq), + SFVAR(AudioBuffer.ReadPos), + + SFARRAY(&Pending_DecodeVolume[0][0], 2 * 2), + SFARRAY(&DecodeVolume[0][0], 2 * 2), + + SFARRAY16(&ADPCM_ResampBuf[0][0], sizeof(ADPCM_ResampBuf) / sizeof(ADPCM_ResampBuf[0][0])), + SFVAR(ADPCM_ResampCurPhase), + SFVAR(ADPCM_ResampCurPos), + + + + SFVAR(RegSelector), + SFARRAY(ArgsBuf, 16), + SFVAR(ArgsWP), + SFVAR(ArgsRP), + + SFVAR(ArgsReceiveLatch), + SFARRAY(ArgsReceiveBuf, 32), + SFVAR(ArgsReceiveIn), + + SFARRAY(ResultsBuffer, 16), + SFVAR(ResultsIn), + SFVAR(ResultsWP), + SFVAR(ResultsRP), + + // + // + // + SFARRAY(&DMABuffer.data[0], DMABuffer.data.size()), + SFVAR(DMABuffer.read_pos), + SFVAR(DMABuffer.write_pos), + SFVAR(DMABuffer.in_count), + // + // + // + + SFARRAY(SB, sizeof(SB) / sizeof(SB[0])), + SFVAR(SB_In), + + SFARRAY(&SectorPipe[0][0], sizeof(SectorPipe) / sizeof(SectorPipe[0][0])), + SFVAR(SectorPipe_Pos), + SFVAR(SectorPipe_In), + + SFARRAY(SubQBuf, sizeof(SubQBuf) / sizeof(SubQBuf[0])), + SFARRAY(SubQBuf_Safe, sizeof(SubQBuf_Safe) / sizeof(SubQBuf_Safe[0])), + + SFVAR(SubQChecksumOK), + + SFVAR(HeaderBufValid), + SFARRAY(HeaderBuf, sizeof(HeaderBuf) / sizeof(HeaderBuf[0])), + + SFVAR(IRQBuffer), + SFVAR(IRQOutTestMask), + SFVAR(CDCReadyReceiveCounter), + + + SFVAR(FilterFile), + SFVAR(FilterChan), + + SFVAR(PendingCommand), + SFVAR(PendingCommandPhase), + SFVAR(PendingCommandCounter), + + SFVAR(SPUCounter), + + SFVAR(Mode), + SFVAR(DriveStatus), + SFVAR(StatusAfterSeek), + SFVAR(Forward), + SFVAR(Backward), + SFVAR(Muted), + + SFVAR(PlayTrackMatch), + + SFVAR(PSRCounter), + + SFVAR(CurSector), + + SFVAR(AsyncIRQPending), + SFARRAY(AsyncResultsPending, sizeof(AsyncResultsPending) / sizeof(AsyncResultsPending[0])), + SFVAR(AsyncResultsPendingCount), + + SFVAR(SeekTarget), + + // FIXME: Save TOC stuff? +#if 0 + CDUtility::TOC toc; + bool IsPSXDisc; + uint8 DiscID[4]; +#endif + + SFVAR(CommandLoc), + SFVAR(CommandLoc_Dirty), + SFARRAY16(&xa_previous[0][0], sizeof(xa_previous) / sizeof(xa_previous[0][0])), + + SFVAR(xa_cur_set), + SFVAR(xa_cur_file), + SFVAR(xa_cur_chan), + + SFVAR(ReportLastF), + + SFEND + }; + + int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "CDC"); + + if(load) + { + DMABuffer.SaveStatePostLoad(); + SectorPipe_Pos %= SectorPipe_Count; + } + return(ret); +} + +void PS_CDC::ResetTS(void) +{ + lastts = 0; +} + +void PS_CDC::RecalcIRQ(void) +{ + IRQ_Assert(IRQ_CD, (bool)(IRQBuffer & (IRQOutTestMask & 0x1F))); +} +//static int32 doom_ts; +void PS_CDC::WriteIRQ(uint8 V) +{ + assert(CDCReadyReceiveCounter <= 0); + assert(!IRQBuffer); + + //PSX_WARNING("[CDC] ***IRQTHINGY: 0x%02x -- %u", V, doom_ts); + + CDCReadyReceiveCounter = 2000; //1024; + + IRQBuffer = V; + RecalcIRQ(); +} + +void PS_CDC::BeginResults(void) +{ + //if(ResultsIn) + // { + // printf("Cleared %d results. IRQBuffer=0x%02x\n", ResultsIn, IRQBuffer); + //} + + // TODO: test semantics on real thing. + ResultsIn = 0; + ResultsWP = 0; + ResultsRP = 0; +} + +void PS_CDC::WriteResult(uint8 V) +{ + ResultsBuffer[ResultsWP] = V; + ResultsWP = (ResultsWP + 1) & 0xF; + ResultsIn = (ResultsIn + 1) & 0x1F; + + if(!ResultsIn) + PSX_WARNING("[CDC] Results buffer overflow!"); +} + +uint8 PS_CDC::ReadResult(void) +{ + uint8 ret = ResultsBuffer[ResultsRP]; + + ResultsRP = (ResultsRP + 1) & 0xF; + ResultsIn = (ResultsIn - 1) & 0x1F; + + return ret; +} + +uint8 PS_CDC::MakeStatus(bool cmd_error) +{ + uint8 ret = 0; + + // Are these bit positions right? + + if(DriveStatus == DS_PLAYING) + ret |= 0x80; + + if(DriveStatus == DS_SEEKING || DriveStatus == DS_SEEKING_LOGICAL) + ret |= 0x40; + + if(DriveStatus == DS_READING) + ret |= 0x20; + + // TODO: shell open and seek error + if(!Cur_disc || DiscChanged) + ret |= 0x10; + + if(DriveStatus != DS_STOPPED) + ret |= 0x02; + + if(cmd_error) + ret |= 0x01; + + DiscChanged = false; + + return(ret); +} + +bool PS_CDC::DecodeSubQ(uint8 *subpw) +{ + uint8 tmp_q[0xC]; + + memset(tmp_q, 0, 0xC); + + for(int i = 0; i < 96; i++) + tmp_q[i >> 3] |= ((subpw[i] & 0x40) >> 6) << (7 - (i & 7)); + + if((tmp_q[0] & 0xF) == 1) + { + memcpy(SubQBuf, tmp_q, 0xC); + SubQChecksumOK = subq_check_checksum(tmp_q); + + if(SubQChecksumOK) + { + memcpy(SubQBuf_Safe, tmp_q, 0xC); + return(true); + } + } + + return(false); +} + +static const int16 CDADPCMImpulse[7][25] = +{ + { 0, -5, 17, -35, 70, -23, -68, 347, -839, 2062, -4681, 15367, 21472, -5882, 2810, -1352, 635, -235, 26, 43, -35, 16, -8, 2, 0, }, /* 0 */ + { 0, -2, 10, -34, 65, -84, 52, 9, -266, 1024, -2680, 9036, 26516, -6016, 3021, -1571, 848, -365, 107, 10, -16, 17, -8, 3, -1, }, /* 1 */ + { -2, 0, 3, -19, 60, -75, 162, -227, 306, -67, -615, 3229, 29883, -4532, 2488, -1471, 882, -424, 166, -27, 5, 6, -8, 3, -1, }, /* 2 */ + { -1, 3, -2, -5, 31, -74, 179, -402, 689, -926, 1272, -1446, 31033, -1446, 1272, -926, 689, -402, 179, -74, 31, -5, -2, 3, -1, }, /* 3 */ + { -1, 3, -8, 6, 5, -27, 166, -424, 882, -1471, 2488, -4532, 29883, 3229, -615, -67, 306, -227, 162, -75, 60, -19, 3, 0, -2, }, /* 4 */ + { -1, 3, -8, 17, -16, 10, 107, -365, 848, -1571, 3021, -6016, 26516, 9036, -2680, 1024, -266, 9, 52, -84, 65, -34, 10, -2, 0, }, /* 5 */ + { 0, 2, -8, 16, -35, 43, 26, -235, 635, -1352, 2810, -5882, 21472, 15367, -4681, 2062, -839, 347, -68, -23, 70, -35, 17, -5, 0, }, /* 6 */ +}; + +void PS_CDC::ReadAudioBuffer(int32 samples[2]) +{ + samples[0] = AudioBuffer.Samples[0][AudioBuffer.ReadPos]; + samples[1] = AudioBuffer.Samples[1][AudioBuffer.ReadPos]; + + AudioBuffer.ReadPos++; +} + +INLINE void PS_CDC::ApplyVolume(int32 samples[2]) +{ + // + // Take care not to alter samples[] before we're done calculating the new output samples! + // + int32 left_out = ((samples[0] * DecodeVolume[0][0]) >> 7) + ((samples[1] * DecodeVolume[1][0]) >> 7); + int32 right_out = ((samples[0] * DecodeVolume[0][1]) >> 7) + ((samples[1] * DecodeVolume[1][1]) >> 7); + + clamp(&left_out, -32768, 32767); + clamp(&right_out, -32768, 32767); + + if(Muted) + { + left_out = 0; + right_out = 0; + } + + samples[0] = left_out; + samples[1] = right_out; +} + +// +// This function must always set samples[0] and samples[1], even if just to 0; range of samples[n] shall be restricted to -32768 through 32767. +// +void PS_CDC::GetCDAudio(int32 samples[2]) +{ + const unsigned freq = (AudioBuffer.ReadPos < AudioBuffer.Size) ? AudioBuffer.Freq : 0; + + samples[0] = 0; + samples[1] = 0; + + if(!freq) + return; + + if(freq == 7 || freq == 14) + { + ReadAudioBuffer(samples); + if(freq == 14) + ReadAudioBuffer(samples); + } + else + { + int32 out_tmp[2] = { 0, 0 }; + + for(unsigned i = 0; i < 2; i++) + { + const int16* imp = CDADPCMImpulse[ADPCM_ResampCurPhase]; + int16* wf = &ADPCM_ResampBuf[i][(ADPCM_ResampCurPos + 32 - 25) & 0x1F]; + + for(unsigned s = 0; s < 25; s++) + { + out_tmp[i] += imp[s] * wf[s]; + } + + out_tmp[i] >>= 15; + clamp(&out_tmp[i], -32768, 32767); + samples[i] = out_tmp[i]; + } + + ADPCM_ResampCurPhase += freq; + + if(ADPCM_ResampCurPhase >= 7) + { + int32 raw[2] = { 0, 0 }; + + ADPCM_ResampCurPhase -= 7; + ReadAudioBuffer(raw); + + for(unsigned i = 0; i < 2; i++) + { + ADPCM_ResampBuf[i][ADPCM_ResampCurPos + 0] = + ADPCM_ResampBuf[i][ADPCM_ResampCurPos + 32] = raw[i]; + } + ADPCM_ResampCurPos = (ADPCM_ResampCurPos + 1) & 0x1F; + } + } + + // + // Algorithmically, volume is applied after resampling for CD-XA ADPCM playback, per PS1 tests(though when "mute" is applied wasn't tested). + // + ApplyVolume(samples); +} + +#include "emuware/PACKED.h" +struct XA_Subheader +{ + uint8 file; + uint8 channel; + uint8 submode; + uint8 coding; + + uint8 file_dup; + uint8 channel_dup; + uint8 submode_dup; + uint8 coding_dup; +}; +#include "emuware/PACKED_END.h" + +#include "emuware/PACKED.h" +struct XA_SoundGroup +{ + uint8 params[16]; + uint8 samples[112]; +}; +#include "emuware/PACKED_END.h" + +#define XA_SUBMODE_EOF 0x80 +#define XA_SUBMODE_REALTIME 0x40 +#define XA_SUBMODE_FORM 0x20 +#define XA_SUBMODE_TRIGGER 0x10 +#define XA_SUBMODE_DATA 0x08 +#define XA_SUBMODE_AUDIO 0x04 +#define XA_SUBMODE_VIDEO 0x02 +#define XA_SUBMODE_EOR 0x01 + +#define XA_CODING_EMPHASIS 0x40 + +//#define XA_CODING_BPS_MASK 0x30 +//#define XA_CODING_BPS_4BIT 0x00 +//#define XA_CODING_BPS_8BIT 0x10 +//#define XA_CODING_SR_MASK 0x0C +//#define XA_CODING_SR_378 0x00 +//#define XA_CODING_SR_ + +#define XA_CODING_8BIT 0x10 +#define XA_CODING_189 0x04 +#define XA_CODING_STEREO 0x01 + +// Special regression prevention test cases: +// Um Jammer Lammy (start doing poorly) +// Yarudora Series Vol.1 - Double Cast (non-FMV speech) + +bool PS_CDC::XA_Test(const uint8 *sdata) +{ + const XA_Subheader *sh = (const XA_Subheader *)&sdata[12 + 4]; + + if(!(Mode & MODE_STRSND)) + return false; + + if(!(sh->submode & XA_SUBMODE_AUDIO)) + return false; + + //printf("Test File: 0x%02x 0x%02x - Channel: 0x%02x 0x%02x - Submode: 0x%02x 0x%02x - Coding: 0x%02x 0x%02x - \n", sh->file, sh->file_dup, sh->channel, sh->channel_dup, sh->submode, sh->submode_dup, sh->coding, sh->coding_dup); + + if((Mode & MODE_SF) && (sh->file != FilterFile || sh->channel != FilterChan)) + return false; + + if(!xa_cur_set || (Mode & MODE_SF)) + { + xa_cur_set = true; + xa_cur_file = sh->file; + xa_cur_chan = sh->channel; + } + else if(sh->file != xa_cur_file || sh->channel != xa_cur_chan) + return false; + + if(sh->submode & XA_SUBMODE_EOF) + { + //puts("YAY"); + xa_cur_set = false; + xa_cur_file = 0; + xa_cur_chan = 0; + } + + return true; +} + +void PS_CDC::ClearAudioBuffers(void) +{ + memset(&AudioBuffer, 0, sizeof(AudioBuffer)); + memset(xa_previous, 0, sizeof(xa_previous)); + + xa_cur_set = false; + xa_cur_file = 0; + xa_cur_chan = 0; + + memset(ADPCM_ResampBuf, 0, sizeof(ADPCM_ResampBuf)); + ADPCM_ResampCurPhase = 0; + ADPCM_ResampCurPos = 0; +} + +// +// output should be readable at -2 and -1 +static void DecodeXAADPCM(const uint8 *input, int16 *output, const unsigned shift, const unsigned weight) +{ + // Weights copied over from SPU channel ADPCM playback code, may not be entirely the same for CD-XA ADPCM, we need to run tests. + static const int32 Weights[16][2] = + { + // s-1 s-2 + { 0, 0 }, + { 60, 0 }, + { 115, -52 }, + { 98, -55 }, + { 122, -60 }, + }; + + for(int i = 0; i < 28; i++) + { + int32 sample; + + sample = (int16)(input[i] << 8); + sample >>= shift; + + sample += ((output[i - 1] * Weights[weight][0]) >> 6) + ((output[i - 2] * Weights[weight][1]) >> 6); + + if(sample < -32768) + sample = -32768; + + if(sample > 32767) + sample = 32767; + + output[i] = sample; + } +} + +void PS_CDC::XA_ProcessSector(const uint8 *sdata, CD_Audio_Buffer *ab) +{ + const XA_Subheader *sh = (const XA_Subheader *)&sdata[12 + 4]; + const unsigned unit_index_shift = (sh->coding & XA_CODING_8BIT) ? 0 : 1; + + //printf("File: 0x%02x 0x%02x - Channel: 0x%02x 0x%02x - Submode: 0x%02x 0x%02x - Coding: 0x%02x 0x%02x - \n", sh->file, sh->file_dup, sh->channel, sh->channel_dup, sh->submode, sh->submode_dup, sh->coding, sh->coding_dup); + ab->ReadPos = 0; + ab->Size = 18 * (4 << unit_index_shift) * 28; + + if(sh->coding & XA_CODING_STEREO) + ab->Size >>= 1; + + ab->Freq = (sh->coding & XA_CODING_189) ? 3 : 6; + + //fprintf(stderr, "Coding: %02x %02x\n", sh->coding, sh->coding_dup); + + for(unsigned group = 0; group < 18; group++) + { + const XA_SoundGroup *sg = (const XA_SoundGroup *)&sdata[12 + 4 + 8 + group * 128]; + + for(unsigned unit = 0; unit < (4U << unit_index_shift); unit++) + { + const uint8 param = sg->params[(unit & 3) | ((unit & 4) << 1)]; + const uint8 param_copy = sg->params[4 | (unit & 3) | ((unit & 4) << 1)]; + uint8 ibuffer[28]; + int16 obuffer[2 + 28]; + + if(param != param_copy) + { + PSX_WARNING("[CDC] CD-XA param != param_copy --- %d %02x %02x\n", unit, param, param_copy); + } + + for(unsigned i = 0; i < 28; i++) + { + uint8 tmp = sg->samples[i * 4 + (unit >> unit_index_shift)]; + + if(unit_index_shift) + { + tmp <<= (unit & 1) ? 0 : 4; + tmp &= 0xf0; + } + + ibuffer[i] = tmp; + } + + const bool ocn = (bool)(unit & 1) && (sh->coding & XA_CODING_STEREO); + + obuffer[0] = xa_previous[ocn][0]; + obuffer[1] = xa_previous[ocn][1]; + + DecodeXAADPCM(ibuffer, &obuffer[2], param & 0x0F, param >> 4); + + xa_previous[ocn][0] = obuffer[28]; + xa_previous[ocn][1] = obuffer[29]; + + if(param != param_copy) + memset(obuffer, 0, sizeof(obuffer)); + + if(sh->coding & XA_CODING_STEREO) + { + for(unsigned s = 0; s < 28; s++) + { + ab->Samples[ocn][group * (2 << unit_index_shift) * 28 + (unit >> 1) * 28 + s] = obuffer[2 + s]; + } + } + else + { + for(unsigned s = 0; s < 28; s++) + { + ab->Samples[0][group * (4 << unit_index_shift) * 28 + unit * 28 + s] = obuffer[2 + s]; + ab->Samples[1][group * (4 << unit_index_shift) * 28 + unit * 28 + s] = obuffer[2 + s]; + } + } + } + } + +#if 0 + // Test + for(unsigned i = 0; i < ab->Size; i++) + { + static unsigned counter = 0; + + ab->Samples[0][i] = (counter & 2) ? -0x6000 : 0x6000; + ab->Samples[1][i] = rand(); + counter++; + } +#endif +} + +void PS_CDC::ClearAIP(void) +{ + AsyncResultsPendingCount = 0; + AsyncIRQPending = 0; +} + +void PS_CDC::CheckAIP(void) +{ + if(AsyncIRQPending && CDCReadyReceiveCounter <= 0) + { + BeginResults(); + + for(unsigned i = 0; i < AsyncResultsPendingCount; i++) + WriteResult(AsyncResultsPending[i]); + + WriteIRQ(AsyncIRQPending); + + ClearAIP(); + } +} + +void PS_CDC::SetAIP(unsigned irq, unsigned result_count, uint8 *r) +{ + if(AsyncIRQPending) + { + PSX_WARNING("***WARNING*** Previous notification skipped: CurSector=%d, old_notification=0x%02x", CurSector, AsyncIRQPending); + } + ClearAIP(); + + AsyncResultsPendingCount = result_count; + + for(unsigned i = 0; i < result_count; i++) + AsyncResultsPending[i] = r[i]; + + AsyncIRQPending = irq; + + CheckAIP(); +} + +void PS_CDC::SetAIP(unsigned irq, uint8 result0) +{ + uint8 tr[1] = { result0 }; + SetAIP(irq, 1, tr); +} + +void PS_CDC::SetAIP(unsigned irq, uint8 result0, uint8 result1) +{ + uint8 tr[2] = { result0, result1 }; + SetAIP(irq, 2, tr); +} + + +void PS_CDC::EnbufferizeCDDASector(const uint8 *buf) +{ + CD_Audio_Buffer *ab = &AudioBuffer; + + ab->Freq = 7 * ((Mode & MODE_SPEED) ? 2 : 1); + ab->Size = 588; + + if(SubQBuf_Safe[0] & 0x40) + { + for(int i = 0; i < 588; i++) + { + ab->Samples[0][i] = 0; + ab->Samples[1][i] = 0; + } + } + else + { + for(int i = 0; i < 588; i++) + { + ab->Samples[0][i] = (int16)MDFN_de16lsb(&buf[i * sizeof(int16) * 2 + 0]); + ab->Samples[1][i] = (int16)MDFN_de16lsb(&buf[i * sizeof(int16) * 2 + 2]); + } + } + + ab->ReadPos = 0; +} + +// SetAIP(CDCIRQ_DISC_ERROR, MakeStatus() | 0x04, 0x04); +void PS_CDC::HandlePlayRead(void) +{ + uint8 read_buf[2352 + 96]; + + //PSX_WARNING("Read sector: %d", CurSector); + + if(CurSector >= ((int32)toc.tracks[100].lba + 300) && CurSector >= (75 * 60 * 75 - 150)) + { + PSX_WARNING("[CDC] Read/Play position waaay too far out(%u), forcing STOP", CurSector); + DriveStatus = DS_STOPPED; + SectorPipe_Pos = SectorPipe_In = 0; + return; + } + + if(CurSector >= (int32)toc.tracks[100].lba) + { + PSX_WARNING("[CDC] In leadout area: %u", CurSector); + + // + // Synthesis is a bit of a kludge... :/ + // + synth_leadout_sector_lba(0x02, toc, CurSector, read_buf); + DecodeSubQ(read_buf + 2352); + } + else + { + Cur_disc->ReadLBA2448(CurSector,read_buf); // FIXME: error out on error. + DecodeSubQ(read_buf + 2352); + } + + + if(SubQBuf_Safe[1] == 0xAA && (DriveStatus == DS_PLAYING || (!(SubQBuf_Safe[0] & 0x40) && (Mode & MODE_CDDA)))) + { + HeaderBufValid = false; + + PSX_WARNING("[CDC] CD-DA leadout reached: %u", CurSector); + + // Status in this end-of-disc context here should be generated after we're in the pause state. + DriveStatus = DS_PAUSED; + SectorPipe_Pos = SectorPipe_In = 0; + SetAIP(CDCIRQ_DATA_END, MakeStatus()); + + return; + } + + if(DriveStatus == DS_PLAYING) + { + // Note: Some game(s) start playing in the pregap of a track(so don't replace this with a simple subq index == 0 check for autopause). + if(PlayTrackMatch == -1 && SubQChecksumOK) + PlayTrackMatch = SubQBuf_Safe[0x1]; + + if((Mode & MODE_AUTOPAUSE) && PlayTrackMatch != -1 && SubQBuf_Safe[0x1] != PlayTrackMatch) + { + // Status needs to be taken before we're paused(IE it should still report playing). + SetAIP(CDCIRQ_DATA_END, MakeStatus()); + + DriveStatus = DS_PAUSED; + SectorPipe_Pos = SectorPipe_In = 0; + PSRCounter = 0; + return; + } + + if((Mode & MODE_REPORT) && (((SubQBuf_Safe[0x9] >> 4) != ReportLastF) || Forward || Backward) && SubQChecksumOK) + { + uint8 tr[8]; +#if 0 + uint16 abs_lev_max = 0; + bool abs_lev_chselect = SubQBuf_Safe[0x8] & 0x01; + + for(int i = 0; i < 588; i++) + abs_lev_max = std::max(abs_lev_max, std::min(abs((int16)MDFN_de16lsb(&read_buf[i * 4 + (abs_lev_chselect * 2)])), 32767)); + abs_lev_max |= abs_lev_chselect << 15; +#endif + + ReportLastF = SubQBuf_Safe[0x9] >> 4; + + tr[0] = MakeStatus(); + tr[1] = SubQBuf_Safe[0x1]; // Track + tr[2] = SubQBuf_Safe[0x2]; // Index + + if(SubQBuf_Safe[0x9] & 0x10) + { + tr[3] = SubQBuf_Safe[0x3]; // R M + tr[4] = SubQBuf_Safe[0x4] | 0x80; // R S + tr[5] = SubQBuf_Safe[0x5]; // R F + } + else + { + tr[3] = SubQBuf_Safe[0x7]; // A M + tr[4] = SubQBuf_Safe[0x8]; // A S + tr[5] = SubQBuf_Safe[0x9]; // A F + } + + tr[6] = 0; //abs_lev_max >> 0; + tr[7] = 0; //abs_lev_max >> 8; + + SetAIP(CDCIRQ_DATA_READY, 8, tr); + } + } + + if(SectorPipe_In >= SectorPipe_Count) + { + uint8* buf = SectorPipe[SectorPipe_Pos]; + SectorPipe_In--; + + if(DriveStatus == DS_READING) + { + if(SubQBuf_Safe[0] & 0x40) //) || !(Mode & MODE_CDDA)) + { + memcpy(HeaderBuf, buf + 12, 12); + HeaderBufValid = true; + + if((Mode & MODE_STRSND) && (buf[12 + 3] == 0x2) && ((buf[12 + 6] & 0x64) == 0x64)) + { + if(XA_Test(buf)) + { + if(AudioBuffer.ReadPos < AudioBuffer.Size) + { + PSX_WARNING("[CDC] CD-XA ADPCM sector skipped - readpos=0x%04x, size=0x%04x", AudioBuffer.ReadPos, AudioBuffer.Size); + } + else + { + XA_ProcessSector(buf, &AudioBuffer); + } + } + } + else + { + // maybe if(!(Mode & 0x30)) too? + if(!(buf[12 + 6] & 0x20)) + { + if(!edc_lec_check_and_correct(buf, true)) + { + printf("Bad sector? - %d", CurSector); + } + } + + if(!(Mode & 0x30) && (buf[12 + 6] & 0x20)) + PSX_WARNING("[CDC] BORK: %d", CurSector); + + int32 offs = (Mode & 0x20) ? 0 : 12; + int32 size = (Mode & 0x20) ? 2340 : 2048; + + if(Mode & 0x10) + { + offs = 12; + size = 2328; + } + + memcpy(SB, buf + 12 + offs, size); + SB_In = size; + SetAIP(CDCIRQ_DATA_READY, MakeStatus()); + } + } + } + + if(!(SubQBuf_Safe[0] & 0x40) && ((Mode & MODE_CDDA) || DriveStatus == DS_PLAYING)) + { + if(AudioBuffer.ReadPos < AudioBuffer.Size) + { + PSX_WARNING("[CDC] BUG CDDA buffer full"); + } + else + { + EnbufferizeCDDASector(buf); + } + } + } + + memcpy(SectorPipe[SectorPipe_Pos], read_buf, 2352); + SectorPipe_Pos = (SectorPipe_Pos + 1) % SectorPipe_Count; + SectorPipe_In++; + + PSRCounter += 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1)); + + if(DriveStatus == DS_PLAYING) + { + // FIXME: What's the real fast-forward and backward speed? + if(Forward) + CurSector += 12; + else if(Backward) + { + CurSector -= 12; + + if(CurSector < 0) // FIXME: How does a real PS handle this condition? + CurSector = 0; + } + else + CurSector++; + } + else + CurSector++; + +} + +pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp) +{ + int32 clocks = timestamp - lastts; + + //doom_ts = timestamp; + + while(clocks > 0) + { + int32 chunk_clocks = clocks; + + if(PSRCounter > 0 && chunk_clocks > PSRCounter) + chunk_clocks = PSRCounter; + + if(PendingCommandCounter > 0 && chunk_clocks > PendingCommandCounter) + chunk_clocks = PendingCommandCounter; + + if(chunk_clocks > SPUCounter) + chunk_clocks = SPUCounter; + + if(DiscStartupDelay > 0) + { + if(chunk_clocks > DiscStartupDelay) + chunk_clocks = DiscStartupDelay; + + DiscStartupDelay -= chunk_clocks; + + if(DiscStartupDelay <= 0) + { + DriveStatus = DS_PAUSED; // or is it supposed to be DS_STANDBY? + } + } + + //MDFN_DispMessage("%02x %d -- %d %d -- %02x", IRQBuffer, CDCReadyReceiveCounter, PSRCounter, PendingCommandCounter, PendingCommand); + + if(!IRQBuffer) + { + if(CDCReadyReceiveCounter > 0 && chunk_clocks > CDCReadyReceiveCounter) + chunk_clocks = CDCReadyReceiveCounter; + + if(CDCReadyReceiveCounter > 0) + CDCReadyReceiveCounter -= chunk_clocks; + } + + CheckAIP(); + + if(PSRCounter > 0) + { + uint8 buf[2352 + 96]; + + PSRCounter -= chunk_clocks; + + if(PSRCounter <= 0) + { + if(DriveStatus == DS_RESETTING) + { + SetAIP(CDCIRQ_COMPLETE, MakeStatus()); + + Muted = false; // Does it get reset here? + ClearAudioBuffers(); + + SB_In = 0; + SectorPipe_Pos = SectorPipe_In = 0; + + Mode = 0; + CurSector = 0; + CommandLoc = 0; + + DriveStatus = DS_PAUSED; // or DS_STANDBY? + ClearAIP(); + } + else if(DriveStatus == DS_SEEKING) + { + CurSector = SeekTarget; + Cur_disc->ReadLBA2448(CurSector,buf); + DecodeSubQ(buf + 2352); + + DriveStatus = StatusAfterSeek; + + if(DriveStatus != DS_PAUSED && DriveStatus != DS_STANDBY) + { + PSRCounter = 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1)); + } + } + else if(DriveStatus == DS_SEEKING_LOGICAL) + { + CurSector = SeekTarget; + Cur_disc->ReadLBA2448(CurSector, buf); + DecodeSubQ(buf + 2352); + memcpy(HeaderBuf, buf + 12, 12); + + DriveStatus = StatusAfterSeek; + + if(DriveStatus != DS_PAUSED && DriveStatus != DS_STANDBY) + { + // TODO: SetAIP(CDCIRQ_DISC_ERROR, MakeStatus() | 0x04, 0x04); when !(Mode & MODE_CDDA) and the sector isn't a data sector. + PSRCounter = 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1)); + } + } + else if(DriveStatus == DS_READING || DriveStatus == DS_PLAYING) + { + HandlePlayRead(); + } + } + } + + if(PendingCommandCounter > 0) + { + PendingCommandCounter -= chunk_clocks; + + if(PendingCommandCounter <= 0 && CDCReadyReceiveCounter > 0) + { + PendingCommandCounter = CDCReadyReceiveCounter; //256; + } + //else if(PendingCommandCounter <= 0 && PSRCounter > 0 && PSRCounter < 2000) + //{ + // PendingCommandCounter = PSRCounter + 1; + //} + else if(PendingCommandCounter <= 0) + { + int32 next_time = 0; + + if(PendingCommandPhase == -1) + { + if(ArgsRP != ArgsWP) + { + ArgsReceiveLatch = ArgsBuf[ArgsRP & 0x0F]; + ArgsRP = (ArgsRP + 1) & 0x1F; + PendingCommandPhase += 1; + next_time = 1815; + } + else + { + PendingCommandPhase += 2; + next_time = 8500; + } + } + else if(PendingCommandPhase == 0) // Command phase 0 + { + if(ArgsReceiveIn < 32) + ArgsReceiveBuf[ArgsReceiveIn++] = ArgsReceiveLatch; + + if(ArgsRP != ArgsWP) + { + ArgsReceiveLatch = ArgsBuf[ArgsRP & 0x0F]; + ArgsRP = (ArgsRP + 1) & 0x1F; + next_time = 1815; + } + else + { + PendingCommandPhase++; + next_time = 8500; + } + } + else if(PendingCommandPhase >= 2) // Command phase 2+ + { + BeginResults(); + + const CDC_CTEntry *command = &Commands[PendingCommand]; + + next_time = (this->*(command->func2))(); + } + else // Command phase 1 + { + if(PendingCommand >= 0x20 || !Commands[PendingCommand].func) + { + BeginResults(); + + PSX_WARNING("[CDC] Unknown command: 0x%02x", PendingCommand); + + WriteResult(MakeStatus(true)); + WriteResult(ERRCODE_BAD_COMMAND); + WriteIRQ(CDCIRQ_DISC_ERROR); + } + else if(ArgsReceiveIn < Commands[PendingCommand].args_min || ArgsReceiveIn > Commands[PendingCommand].args_max) + { + BeginResults(); + + PSX_DBG(PSX_DBG_WARNING, "[CDC] Bad number(%d) of args(first check) for command 0x%02x", ArgsReceiveIn, PendingCommand); + for(unsigned int i = 0; i < ArgsReceiveIn; i++) + PSX_DBG(PSX_DBG_WARNING, " 0x%02x", ArgsReceiveBuf[i]); + PSX_DBG(PSX_DBG_WARNING, "\n"); + + WriteResult(MakeStatus(true)); + WriteResult(ERRCODE_BAD_NUMARGS); + WriteIRQ(CDCIRQ_DISC_ERROR); + } + else + { + BeginResults(); + + const CDC_CTEntry *command = &Commands[PendingCommand]; + + PSX_DBG(PSX_DBG_SPARSE, "[CDC] Command: %s --- ", command->name); + for(unsigned int i = 0; i < ArgsReceiveIn; i++) + PSX_DBG(PSX_DBG_SPARSE, " 0x%02x", ArgsReceiveBuf[i]); + PSX_DBG(PSX_DBG_SPARSE, "\n"); + + next_time = (this->*(command->func))(ArgsReceiveIn, ArgsReceiveBuf); + PendingCommandPhase = 2; + } + ArgsReceiveIn = 0; + } // end command phase 1 + + if(!next_time) + PendingCommandCounter = 0; + else + PendingCommandCounter += next_time; + } + } + + SPUCounter = SPU->UpdateFromCDC(chunk_clocks); + + clocks -= chunk_clocks; + } // end while(clocks > 0) + + lastts = timestamp; + + return(timestamp + CalcNextEvent()); +} + +void PS_CDC::Write(const pscpu_timestamp_t timestamp, uint32 A, uint8 V) +{ + A &= 0x3; + + //printf("Write: %08x %02x\n", A, V); + + if(A == 0x00) + { + RegSelector = V & 0x3; + } + else + { + const unsigned reg_index = ((RegSelector & 0x3) * 3) + (A - 1); + + Update(timestamp); + //PSX_WARNING("[CDC] Write to register 0x%02x: 0x%02x @ %d --- 0x%02x 0x%02x\n", reg_index, V, timestamp, DMABuffer.CanRead(), IRQBuffer); + + switch(reg_index) + { + default: + PSX_WARNING("[CDC] Unknown write to register 0x%02x: 0x%02x\n", reg_index, V); + break; + + case 0x00: + if(PendingCommandCounter > 0) + { + PSX_WARNING("[CDC] WARNING: Interrupting command 0x%02x, phase=%d, timeleft=%d with command=0x%02x", PendingCommand, PendingCommandPhase, + PendingCommandCounter, V); + } + + if(IRQBuffer) + { + PSX_WARNING("[CDC] Attempting to start command(0x%02x) while IRQBuffer(0x%02x) is not clear.", V, IRQBuffer); + } + + if(ResultsIn > 0) + { + PSX_WARNING("[CDC] Attempting to start command(0x%02x) while command results(count=%d) still in buffer.", V, ResultsIn); + } + + PendingCommandCounter = 10500 + PSX_GetRandU32(0, 3000) + 1815; + PendingCommand = V; + PendingCommandPhase = -1; + ArgsReceiveIn = 0; + break; + + case 0x01: + ArgsBuf[ArgsWP & 0xF] = V; + ArgsWP = (ArgsWP + 1) & 0x1F; + + if(!((ArgsWP - ArgsRP) & 0x0F)) + { + PSX_WARNING("[CDC] Argument buffer overflow"); + } + break; + + case 0x02: + if(V & 0x80) + { + if(!DMABuffer.CanRead()) + { + if(!SB_In) + { + PSX_WARNING("[CDC] Data read begin when no data to read!"); + + DMABuffer.Write(SB, 2340); + + while(DMABuffer.CanWrite()) + DMABuffer.WriteByte(0x00); + } + else + { + DMABuffer.Write(SB, SB_In); + SB_In = 0; + } + } + else + { + //PSX_WARNING("[CDC] Attempt to start data transfer via 0x80->1803 when %d bytes still in buffer", DMABuffer.CanRead()); + } + } + else if(V & 0x40) // Something CD-DA related(along with & 0x20 ???)? + { + for(unsigned i = 0; i < 4 && DMABuffer.CanRead(); i++) + DMABuffer.ReadByte(); + } + else + { + DMABuffer.Flush(); + } + + if(V & 0x20) + { + PSX_WARNING("[CDC] Mystery IRQ trigger bit set."); + IRQBuffer |= 0x10; + } + break; + + case 0x04: + IRQOutTestMask = V; + RecalcIRQ(); + break; + + case 0x05: + if((IRQBuffer &~ V) != IRQBuffer && ResultsIn) + { + // To debug icky race-condition related problems in "Psychic Detective", and to see if any games suffer from the same potential issue + // (to know what to test when we emulate CPU more accurately in regards to pipeline stalls and timing, which could throw off our kludge + // for this issue) + PSX_WARNING("[CDC] Acknowledged IRQ(wrote 0x%02x, before_IRQBuffer=0x%02x) while %u bytes in results buffer.", V, IRQBuffer, ResultsIn); + } + + IRQBuffer &= ~V; + RecalcIRQ(); + + if(V & 0x80) // Forced CD hardware reset of some kind(interface, controller, and drive?) Seems to take a while(relatively speaking) to complete. + { + PSX_WARNING("[CDC] Soft Reset"); + SoftReset(); + } + + if(V & 0x40) // Does it clear more than arguments buffer? Doesn't appear to clear results buffer. + { + ArgsWP = ArgsRP = 0; + } + break; + + case 0x07: + Pending_DecodeVolume[0][0] = V; + break; + + case 0x08: + Pending_DecodeVolume[0][1] = V; + break; + + case 0x09: + Pending_DecodeVolume[1][1] = V; + break; + + case 0x0A: + Pending_DecodeVolume[1][0] = V; + break; + + case 0x0B: + if(V & 0x20) + { + memcpy(DecodeVolume, Pending_DecodeVolume, sizeof(DecodeVolume)); + + for(int i = 0; i < 2; i++) + { + for(int o = 0; o < 2; o++) + { + //fprintf(stderr, "Input Channel %d, Output Channel %d -- Volume=%d\n", i, o, DecodeVolume[i][o]); + } + } + } + break; + } + PSX_SetEventNT(PSX_EVENT_CDC, timestamp + CalcNextEvent()); + } +} + +uint8 PS_CDC::Read(const pscpu_timestamp_t timestamp, uint32 A) +{ + uint8 ret = 0; + + A &= 0x03; + + //printf("Read %08x\n", A); + + if(A == 0x00) + { + ret = RegSelector & 0x3; + + if(ArgsWP == ArgsRP) + ret |= 0x08; // Args FIFO empty. + + if(!((ArgsWP - ArgsRP) & 0x10)) + ret |= 0x10; // Args FIFO has room. + + if(ResultsIn) + ret |= 0x20; + + if(DMABuffer.CanRead()) + ret |= 0x40; + + if(PendingCommandCounter > 0 && PendingCommandPhase <= 1) + ret |= 0x80; + } + else + { + switch(A & 0x3) + { + case 0x01: + ret = ReadResult(); + break; + + case 0x02: + //PSX_WARNING("[CDC] DMA Buffer manual read"); + if(DMABuffer.CanRead()) + ret = DMABuffer.ReadByte(); + else + { + PSX_WARNING("[CDC] CD data transfer port read, but no data present!"); + } + break; + + case 0x03: + if(RegSelector & 0x1) + { + ret = 0xE0 | IRQBuffer; + } + else + { + ret = 0xFF; + } + break; + } + } + + return(ret); +} + + +bool PS_CDC::DMACanRead(void) +{ + return(DMABuffer.CanRead()); +} + +uint32 PS_CDC::DMARead(void) +{ + uint32 data = 0; + + for(int i = 0; i < 4; i++) + { + if(DMABuffer.CanRead()) + data |= DMABuffer.ReadByte() << (i * 8); + else + { + //assert(0); + } + } + + return(data); +} + +bool PS_CDC::CommandCheckDiscPresent(void) +{ + if(!Cur_disc || DiscStartupDelay > 0) + { + WriteResult(MakeStatus(true)); + WriteResult(ERRCODE_NOT_READY); + + WriteIRQ(CDCIRQ_DISC_ERROR); + + return(false); + } + + return(true); +} + +int32 PS_CDC::Command_Sync(const int arg_count, const uint8 *args) +{ + PSX_WARNING("[CDC] Unimplemented command: 0x%02x", PendingCommand); + return(0); +} + +int32 PS_CDC::Command_Nop(const int arg_count, const uint8 *args) +{ + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + return(0); +} + +int32 PS_CDC::Command_Setloc(const int arg_count, const uint8 *args) +{ + uint8 m, s, f; + + m = BCD_to_U8(args[0] & 0x7F); + s = BCD_to_U8(args[1]); + f = BCD_to_U8(args[2]); + + CommandLoc = f + 75 * s + 75 * 60 * m - 150; + CommandLoc_Dirty = true; + + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + return(0); +} + +int32 PS_CDC::CalcSeekTime(int32 initial, int32 target, bool motor_on, bool paused) +{ + int32 ret = 0; + + if(!motor_on) + { + initial = 0; + ret += 33868800; + } + + ret += std::max((int64)abs(initial - target) * 33868800 * 1000 / (72 * 60 * 75) / 1000, 20000); + + if(abs(initial - target) >= 2250) + ret += (int64)33868800 * 300 / 1000; + else if(paused) + { + // The delay to restart from a Pause state is...very....WEIRD. The time it takes is related to the amount of time that has passed since the pause, and + // where on the disc the laser head is, with generally more time passed = longer to resume, except that there's a window of time where it takes a + // ridiculous amount of time when not much time has passed. + // + // What we have here will be EXTREMELY simplified. + + // + // + + //if(time_passed >= 67737) + //{ + //} + //else + { + // Take twice as long for 1x mode. + ret += 1237952 * ((Mode & MODE_SPEED) ? 1 : 2); + } + } + + ret += PSX_GetRandU32(0, 25000); + + PSX_DBG(PSX_DBG_SPARSE, "[CDC] CalcSeekTime() = %d\n", ret); + + return(ret); +} + +#if 0 +void PS_CDC::BeginSeek(uint32 target, int after_seek) +{ + SeekTarget = target; + StatusAfterSeek = after_seek; + + PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED); +} +#endif + +// Remove this function when we have better seek emulation; it's here because the Rockman complete works games(at least 2 and 4) apparently have finicky fubared CD +// access code. +void PS_CDC::PreSeekHack(bool logical, uint32 target) +{ + uint8 buf[2352 + 96]; + int max_try = 32; + bool NeedHBuf = logical; + + CurSector = target; // If removing/changing this, take into account how it will affect ReadN/ReadS/Play/etc command calls that interrupt a seek. + + // If removing this SubQ reading bit, think about how it will interact with a Read command of data(or audio :b) sectors when Mode bit0 is 1. + if(target < toc.tracks[100].lba) + { + do + { + Cur_disc->ReadLBA2448(target++, buf); + + // GetLocL related kludge, for Gran Turismo 1 music, perhaps others? + if(NeedHBuf) + { + NeedHBuf = false; + memcpy(HeaderBuf, buf + 12, 12); + HeaderBufValid = true; + } + } while(!DecodeSubQ(buf + 2352) && --max_try > 0 && target < toc.tracks[100].lba); + } +} + +int32 PS_CDC::Command_Play(const int arg_count, const uint8 *args) +{ + if(!CommandCheckDiscPresent()) + return(0); + + ClearAIP(); + + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + Forward = Backward = false; + + if(arg_count && args[0]) + { + int track = BCD_to_U8(args[0]); + + if(track < toc.first_track) + { + PSX_WARNING("[CDC] Attempt to play track before first track."); + track = toc.first_track; + } + else if(track > toc.last_track) + { + PSX_WARNING("[CDC] Attempt to play track before first track."); + track = toc.last_track; + } + + ClearAudioBuffers(); + SectorPipe_Pos = SectorPipe_In = 0; + + PlayTrackMatch = track; + + PSX_WARNING("[CDC] Play track: %d", track); + + SeekTarget = toc.tracks[track].lba; + PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED); + HeaderBufValid = false; + PreSeekHack(false, SeekTarget); + + ReportLastF = 0xFF; + + DriveStatus = DS_SEEKING; + StatusAfterSeek = DS_PLAYING; + } + else if(CommandLoc_Dirty || DriveStatus != DS_PLAYING) + { + ClearAudioBuffers(); + SectorPipe_Pos = SectorPipe_In = 0; + + if(CommandLoc_Dirty) + SeekTarget = CommandLoc; + else + SeekTarget = CurSector; + + PlayTrackMatch = -1; + + PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED); + HeaderBufValid = false; + PreSeekHack(false, SeekTarget); + + ReportLastF = 0xFF; + + DriveStatus = DS_SEEKING; + StatusAfterSeek = DS_PLAYING; + } + + CommandLoc_Dirty = false; + return(0); +} + +int32 PS_CDC::Command_Forward(const int arg_count, const uint8 *args) +{ + if(!CommandCheckDiscPresent()) + return(0); + + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + Backward = false; + Forward = true; + + return(0); +} + +int32 PS_CDC::Command_Backward(const int arg_count, const uint8 *args) +{ + if(!CommandCheckDiscPresent()) + return(0); + + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + Backward = true; + Forward = false; + + return(0); +} + + +void PS_CDC::ReadBase(void) +{ + if(!CommandCheckDiscPresent()) + return; + + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + if(DriveStatus == DS_SEEKING_LOGICAL && SeekTarget == CommandLoc && StatusAfterSeek == DS_READING) + { + CommandLoc_Dirty = false; + return; + } + + if(CommandLoc_Dirty || DriveStatus != DS_READING) + { + // Don't flush the DMABuffer here; see CTR course selection screen. + ClearAIP(); + ClearAudioBuffers(); + SB_In = 0; + SectorPipe_Pos = SectorPipe_In = 0; + + // TODO: separate motor start from seek phase? + + if(CommandLoc_Dirty) + SeekTarget = CommandLoc; + else + SeekTarget = CurSector; + + PSRCounter = /*903168 * 1.5 +*/ CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED); + HeaderBufValid = false; + PreSeekHack(true, SeekTarget); + + DriveStatus = DS_SEEKING_LOGICAL; + StatusAfterSeek = DS_READING; + } + + CommandLoc_Dirty = false; +} + +int32 PS_CDC::Command_ReadN(const int arg_count, const uint8 *args) +{ + ReadBase(); + return 0; +} + +int32 PS_CDC::Command_ReadS(const int arg_count, const uint8 *args) +{ + ReadBase(); + return 0; +} + +int32 PS_CDC::Command_Stop(const int arg_count, const uint8 *args) +{ + if(!CommandCheckDiscPresent()) + return(0); + + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + if(DriveStatus == DS_STOPPED) + { + return(5000); + } + else + { + ClearAudioBuffers(); + ClearAIP(); + SectorPipe_Pos = SectorPipe_In = 0; + + DriveStatus = DS_STOPPED; + HeaderBufValid = false; + + return(33868); // FIXME, should be much higher. + } +} + +int32 PS_CDC::Command_Stop_Part2(void) +{ + PSRCounter = 0; + + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_COMPLETE); + + return(0); +} + +int32 PS_CDC::Command_Standby(const int arg_count, const uint8 *args) +{ + if(!CommandCheckDiscPresent()) + return(0); + + if(DriveStatus != DS_STOPPED) + { + WriteResult(MakeStatus(true)); + WriteResult(0x20); + WriteIRQ(CDCIRQ_DISC_ERROR); + return(0); + } + + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + ClearAudioBuffers(); + ClearAIP(); + SectorPipe_Pos = SectorPipe_In = 0; + + DriveStatus = DS_STANDBY; + + return((int64)33868800 * 100 / 1000); // No idea, FIXME. +} + +int32 PS_CDC::Command_Standby_Part2(void) +{ + PSRCounter = 0; + + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_COMPLETE); + + return(0); +} + +int32 PS_CDC::Command_Pause(const int arg_count, const uint8 *args) +{ + if(!CommandCheckDiscPresent()) + return(0); + + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + if(DriveStatus == DS_PAUSED || DriveStatus == DS_STOPPED) + { + return(5000); + } + else + { + // "Viewpoint" flips out and crashes if reading isn't stopped (almost?) immediately. + //ClearAudioBuffers(); + SectorPipe_Pos = SectorPipe_In = 0; + ClearAIP(); + DriveStatus = DS_PAUSED; + + // An approximation. + return((1124584 + ((int64)CurSector * 42596 / (75 * 60))) * ((Mode & MODE_SPEED) ? 1 : 2)); + } +} + +int32 PS_CDC::Command_Pause_Part2(void) +{ + PSRCounter = 0; + + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_COMPLETE); + + return(0); +} + +int32 PS_CDC::Command_Reset(const int arg_count, const uint8 *args) +{ + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + if(DriveStatus != DS_RESETTING) + { + HeaderBufValid = false; + DriveStatus = DS_RESETTING; + PSRCounter = 1136000; + } + + return(0); +} + +int32 PS_CDC::Command_Mute(const int arg_count, const uint8 *args) +{ + Muted = true; + + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + return(0); +} + +int32 PS_CDC::Command_Demute(const int arg_count, const uint8 *args) +{ + Muted = false; + + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + return(0); +} + +int32 PS_CDC::Command_Setfilter(const int arg_count, const uint8 *args) +{ + FilterFile = args[0]; + FilterChan = args[1]; + + //PSX_WARNING("[CDC] Setfilter: %02x %02x", args[0], args[1]); + + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + return(0); +} + +int32 PS_CDC::Command_Setmode(const int arg_count, const uint8 *args) +{ + Mode = args[0]; + + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + return(0); +} + +int32 PS_CDC::Command_Getparam(const int arg_count, const uint8 *args) +{ + WriteResult(MakeStatus()); + WriteResult(Mode); + WriteResult(0x00); + WriteResult(FilterFile); + WriteResult(FilterChan); + + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + + return(0); +} + +int32 PS_CDC::Command_GetlocL(const int arg_count, const uint8 *args) +{ + if(!CommandCheckDiscPresent()) + return(0); + + if(!HeaderBufValid) + { + WriteResult(MakeStatus(true)); + WriteResult(0x80); + WriteIRQ(CDCIRQ_DISC_ERROR); + return(0); + } + + for(unsigned i = 0; i < 8; i++) + { + //printf("%d %d: %02x\n", DriveStatus, i, HeaderBuf[i]); + WriteResult(HeaderBuf[i]); + } + + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + return(0); +} + +int32 PS_CDC::Command_GetlocP(const int arg_count, const uint8 *args) +{ + if(!CommandCheckDiscPresent()) + return(0); + + //printf("%2x:%2x %2x:%2x:%2x %2x:%2x:%2x\n", SubQBuf_Safe[0x1], SubQBuf_Safe[0x2], SubQBuf_Safe[0x3], SubQBuf_Safe[0x4], SubQBuf_Safe[0x5], SubQBuf_Safe[0x7], SubQBuf_Safe[0x8], SubQBuf_Safe[0x9]); + + WriteResult(SubQBuf_Safe[0x1]); // Track + WriteResult(SubQBuf_Safe[0x2]); // Index + WriteResult(SubQBuf_Safe[0x3]); // R M + WriteResult(SubQBuf_Safe[0x4]); // R S + WriteResult(SubQBuf_Safe[0x5]); // R F + WriteResult(SubQBuf_Safe[0x7]); // A M + WriteResult(SubQBuf_Safe[0x8]); // A S + WriteResult(SubQBuf_Safe[0x9]); // A F + + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + return(0); +} + +int32 PS_CDC::Command_ReadT(const int arg_count, const uint8 *args) +{ + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + return(44100 * 768 / 1000); +} + +int32 PS_CDC::Command_ReadT_Part2(void) +{ + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_COMPLETE); + + return(0); +} + +int32 PS_CDC::Command_GetTN(const int arg_count, const uint8 *args) +{ + if(!CommandCheckDiscPresent()) + return(0); + + WriteResult(MakeStatus()); + WriteResult(U8_to_BCD(toc.first_track)); + WriteResult(U8_to_BCD(toc.last_track)); + + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + return(0); +} + +int32 PS_CDC::Command_GetTD(const int arg_count, const uint8 *args) +{ + if(!CommandCheckDiscPresent()) + return(0); + + int track; + uint8 m, s, f; + + if(!args[0] || args[0] == 0xAA) + track = 100; + else + { + track= BCD_to_U8(args[0]); + + if(track < toc.first_track || track > toc.last_track) // Error + { + WriteResult(MakeStatus(true)); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + return(0); + } + } + + LBA_to_AMSF(toc.tracks[track].lba, &m, &s, &f); + + WriteResult(MakeStatus()); + WriteResult(U8_to_BCD(m)); + WriteResult(U8_to_BCD(s)); + //WriteResult(U8_to_BCD(f)); + + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + return(0); +} + +int32 PS_CDC::Command_SeekL(const int arg_count, const uint8 *args) +{ + if(!CommandCheckDiscPresent()) + return(0); + + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + SeekTarget = CommandLoc; + + PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED); + HeaderBufValid = false; + PreSeekHack(true, SeekTarget); + DriveStatus = DS_SEEKING_LOGICAL; + StatusAfterSeek = DS_STANDBY; + ClearAIP(); + + return(PSRCounter); +} + +int32 PS_CDC::Command_SeekP(const int arg_count, const uint8 *args) +{ + if(!CommandCheckDiscPresent()) + return(0); + + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + SeekTarget = CommandLoc; + + PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED); + HeaderBufValid = false; + PreSeekHack(false, SeekTarget); + DriveStatus = DS_SEEKING; + StatusAfterSeek = DS_STANDBY; + ClearAIP(); + + return(PSRCounter); +} + +int32 PS_CDC::Command_Seek_PartN(void) +{ + if(DriveStatus == DS_STANDBY) + { + BeginResults(); + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_COMPLETE); + + return(0); + } + else + { + return(std::max(PSRCounter, 256)); + } +} + +int32 PS_CDC::Command_Test(const int arg_count, const uint8 *args) +{ + //PSX_WARNING("[CDC] Test command sub-operation: 0x%02x", args[0]); + + switch(args[0]) + { + default: + PSX_WARNING("[CDC] Unknown Test command sub-operation: 0x%02x", args[0]); + WriteResult(MakeStatus(true)); + WriteResult(0x10); + WriteIRQ(CDCIRQ_DISC_ERROR); + break; + + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + PSX_WARNING("[CDC] Unknown Test command sub-operation: 0x%02x", args[0]); + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + break; + +#if 0 + case 0x50: // *Need to retest this test command, it takes additional arguments??? Or in any case, it generates a different error code(0x20) than most other Test + // sub-commands that generate an error code(0x10). + break; + + // Same with 0x60, 0x71-0x76 + +#endif + + case 0x51: // *Need to retest this test command + PSX_WARNING("[CDC] Unknown Test command sub-operation: 0x%02x", args[0]); + WriteResult(0x01); + WriteResult(0x00); + WriteResult(0x00); + break; + + case 0x75: // *Need to retest this test command + PSX_WARNING("[CDC] Unknown Test command sub-operation: 0x%02x", args[0]); + WriteResult(0x00); + WriteResult(0xC0); + WriteResult(0x00); + WriteResult(0x00); + break; + + // + // SCEx counters not reset by command 0x0A. + // + + case 0x04: // Reset SCEx counters + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + break; + + case 0x05: // Read SCEx counters + WriteResult(0x00); // Number of TOC/leadin reads? (apparently increases by 1 or 2 per ReadTOC, even on non-PSX music CD) + WriteResult(0x00); // Number of SCEx strings received? (Stays at zero on music CD) + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + break; + + case 0x20: + { + WriteResult(0x97); + WriteResult(0x01); + WriteResult(0x10); + WriteResult(0xC2); + + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + } + break; + + case 0x21: // *Need to retest this test command. + { + WriteResult(0x01); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + } + break; + + case 0x22: + { + static const uint8 td[7] = { 0x66, 0x6f, 0x72, 0x20, 0x55, 0x2f, 0x43 }; + + for(unsigned i = 0; i < 7; i++) + WriteResult(td[i]); + + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + } + break; + + case 0x23: + case 0x24: + { + static const uint8 td[8] = { 0x43, 0x58, 0x44, 0x32, 0x35, 0x34, 0x35, 0x51 }; + + for(unsigned i = 0; i < 8; i++) + WriteResult(td[i]); + + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + } + break; + + case 0x25: + { + static const uint8 td[8] = { 0x43, 0x58, 0x44, 0x31, 0x38, 0x31, 0x35, 0x51 }; + + for(unsigned i = 0; i < 8; i++) + WriteResult(td[i]); + + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + } + break; + } + return(0); +} + +int32 PS_CDC::Command_ID(const int arg_count, const uint8 *args) +{ + if(!CommandCheckDiscPresent()) + return(0); + + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + return(33868); +} + +int32 PS_CDC::Command_ID_Part2(void) +{ + if(IsPSXDisc) + { + WriteResult(MakeStatus()); + WriteResult(0x00); + WriteResult(0x20); + WriteResult(0x00); + } + else + { + WriteResult(MakeStatus() | 0x08); + WriteResult(0x90); + WriteResult(toc.disc_type); + WriteResult(0x00); + } + + if(IsPSXDisc) + { + WriteResult(DiscID[0]); + WriteResult(DiscID[1]); + WriteResult(DiscID[2]); + WriteResult(DiscID[3]); + } + else + { + WriteResult(0xff); + WriteResult(0); + WriteResult(0); + WriteResult(0); + } + + if(IsPSXDisc) + WriteIRQ(CDCIRQ_COMPLETE); + else + WriteIRQ(CDCIRQ_DISC_ERROR); + + return(0); +} + +int32 PS_CDC::Command_Init(const int arg_count, const uint8 *args) +{ + return(0); +} + +int32 PS_CDC::Command_ReadTOC(const int arg_count, const uint8 *args) +{ + int32 ret_time; + + HeaderBufValid = false; + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + + // ReadTOC doesn't error out if the tray is open, and it completes rather quickly in that case. + // + if(!CommandCheckDiscPresent()) + return(26000); + + + + // A gross approximation. + // The penalty for the drive being stopped seems to be rather high(higher than what CalcSeekTime() currently introduces), although + // that should be investigated further. + // + // ...and not to mention the time taken varies from disc to disc even! + ret_time = 30000000 + CalcSeekTime(CurSector, 0, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED); + + DriveStatus = DS_PAUSED; // Ends up in a pause state when the command is finished. Maybe we should add DS_READTOC or something... + ClearAIP(); + + return ret_time; +} + +int32 PS_CDC::Command_ReadTOC_Part2(void) +{ + //if(!CommandCheckDiscPresent()) + // DriveStatus = DS_PAUSED; + + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_COMPLETE); + + return(0); +} + +int32 PS_CDC::Command_0x1d(const int arg_count, const uint8 *args) +{ + WriteResult(MakeStatus()); + WriteIRQ(CDCIRQ_ACKNOWLEDGE); + return(0); +} + +PS_CDC::CDC_CTEntry PS_CDC::Commands[0x20] = +{ + { /* 0x00, */ 0, 0, "Sync", &PS_CDC::Command_Sync, NULL }, + { /* 0x01, */ 0, 0, "Nop", &PS_CDC::Command_Nop, NULL }, + { /* 0x02, */ 3, 3, "Setloc", &PS_CDC::Command_Setloc, NULL }, + { /* 0x03, */ 0, 1, "Play", &PS_CDC::Command_Play, NULL }, + { /* 0x04, */ 0, 0, "Forward", &PS_CDC::Command_Forward, NULL }, + { /* 0x05, */ 0, 0, "Backward", &PS_CDC::Command_Backward, NULL }, + { /* 0x06, */ 0, 0, "ReadN", &PS_CDC::Command_ReadN, NULL }, + { /* 0x07, */ 0, 0, "Standby", &PS_CDC::Command_Standby, &PS_CDC::Command_Standby_Part2 }, + { /* 0x08, */ 0, 0, "Stop", &PS_CDC::Command_Stop, &PS_CDC::Command_Stop_Part2 }, + { /* 0x09, */ 0, 0, "Pause", &PS_CDC::Command_Pause, &PS_CDC::Command_Pause_Part2 }, + { /* 0x0A, */ 0, 0, "Reset", &PS_CDC::Command_Reset, NULL }, + { /* 0x0B, */ 0, 0, "Mute", &PS_CDC::Command_Mute, NULL }, + { /* 0x0C, */ 0, 0, "Demute", &PS_CDC::Command_Demute, NULL }, + { /* 0x0D, */ 2, 2, "Setfilter", &PS_CDC::Command_Setfilter, NULL }, + { /* 0x0E, */ 1, 1, "Setmode", &PS_CDC::Command_Setmode, NULL }, + { /* 0x0F, */ 0, 0, "Getparam", &PS_CDC::Command_Getparam, NULL }, + { /* 0x10, */ 0, 0, "GetlocL", &PS_CDC::Command_GetlocL, NULL }, + { /* 0x11, */ 0, 0, "GetlocP", &PS_CDC::Command_GetlocP, NULL }, + { /* 0x12, */ 1, 1, "ReadT", &PS_CDC::Command_ReadT, &PS_CDC::Command_ReadT_Part2 }, + { /* 0x13, */ 0, 0, "GetTN", &PS_CDC::Command_GetTN, NULL }, + { /* 0x14, */ 1, 1, "GetTD", &PS_CDC::Command_GetTD, NULL }, + { /* 0x15, */ 0, 0, "SeekL", &PS_CDC::Command_SeekL, &PS_CDC::Command_Seek_PartN }, + { /* 0x16, */ 0, 0, "SeekP", &PS_CDC::Command_SeekP, &PS_CDC::Command_Seek_PartN }, + + { /* 0x17, */ 0, 0, NULL, NULL, NULL }, + { /* 0x18, */ 0, 0, NULL, NULL, NULL }, + + { /* 0x19, */ 1, 1/* ??? */, "Test", &PS_CDC::Command_Test, NULL }, + { /* 0x1A, */ 0, 0, "ID", &PS_CDC::Command_ID, &PS_CDC::Command_ID_Part2 }, + { /* 0x1B, */ 0, 0, "ReadS", &PS_CDC::Command_ReadS, NULL }, + { /* 0x1C, */ 0, 0, "Init", &PS_CDC::Command_Init, NULL }, + { /* 0x1D, */ 2, 2, "Unknown 0x1D", &PS_CDC::Command_0x1d, NULL }, + { /* 0x1E, */ 0, 0, "ReadTOC", &PS_CDC::Command_ReadTOC, &PS_CDC::Command_ReadTOC_Part2 }, + { /* 0x1F, */ 0, 0, NULL, NULL, NULL }, +}; + + +} diff --git a/psx/octoshock/psx/cdc.h b/psx/octoshock/psx/cdc.h new file mode 100644 index 0000000000..33edf5fc2a --- /dev/null +++ b/psx/octoshock/psx/cdc.h @@ -0,0 +1,280 @@ +#ifndef __MDFN_PSX_CDC_H +#define __MDFN_PSX_CDC_H + +#include "cdrom/CDUtility.h" + +class ShockDiscRef; + + +namespace MDFN_IEN_PSX +{ + +struct CD_Audio_Buffer +{ + int16 Samples[2][0x1000]; // [0][...] = l, [1][...] = r + int32 Size; + uint32 Freq; + int32 ReadPos; +}; + + +class PS_CDC +{ + public: + + PS_CDC(); + ~PS_CDC(); + + void SetDisc(bool tray_open, ShockDiscRef *disc, const char disc_id[4]); + + void Power(void); + int StateAction(StateMem *sm, int load, int data_only); + void ResetTS(void); + + int32 CalcNextEvent(void); // Returns in master cycles to next event. + + pscpu_timestamp_t Update(const pscpu_timestamp_t timestamp); + + void Write(const pscpu_timestamp_t timestamp, uint32 A, uint8 V); + uint8 Read(const pscpu_timestamp_t timestamp, uint32 A); + + bool DMACanRead(void); + uint32 DMARead(void); + void SoftReset(void); + + void GetCDAudio(int32 samples[2]); + + private: + CDIF *Cur_CDIF; + ShockDiscRef* Cur_disc; + bool DiscChanged; + int32 DiscStartupDelay; + + CD_Audio_Buffer AudioBuffer; + + uint8 Pending_DecodeVolume[2][2], DecodeVolume[2][2]; // [data_source][output_port] + + int16 ADPCM_ResampBuf[2][32 * 2]; + uint8 ADPCM_ResampCurPos; + uint8 ADPCM_ResampCurPhase; + + void ApplyVolume(int32 samples[2]); + void ReadAudioBuffer(int32 samples[2]); + + void ClearAudioBuffers(void); + + + // + // + // + + + uint8 RegSelector; + uint8 ArgsBuf[16]; + uint8 ArgsWP; // 5-bit(0 ... 31) + uint8 ArgsRP; // 5-bit(0 ... 31) + + uint8 ArgsReceiveLatch; + uint8 ArgsReceiveBuf[32]; + uint8 ArgsReceiveIn; + + uint8 ResultsBuffer[16]; + uint8 ResultsIn; // 5-bit(0 ... 31) + uint8 ResultsWP; // Write position, 4 bit(0 ... 15). + uint8 ResultsRP; // Read position, 4 bit(0 ... 15). + + SimpleFIFO DMABuffer; + uint8 SB[2340]; + uint32 SB_In; + + enum { SectorPipe_Count = 2 }; + uint8 SectorPipe[SectorPipe_Count][2352]; + uint8 SectorPipe_Pos; + uint8 SectorPipe_In; + + uint8 SubQBuf[0xC]; + uint8 SubQBuf_Safe[0xC]; + bool SubQChecksumOK; + + bool HeaderBufValid; + uint8 HeaderBuf[12]; + + void RecalcIRQ(void); + enum + { + CDCIRQ_NONE = 0, + CDCIRQ_DATA_READY = 1, + CDCIRQ_COMPLETE = 2, + CDCIRQ_ACKNOWLEDGE = 3, + CDCIRQ_DATA_END = 4, + CDCIRQ_DISC_ERROR = 5 + }; + + // Names are just guessed for these based on what conditions cause them: + enum + { + ERRCODE_BAD_ARGVAL = 0x10, + ERRCODE_BAD_NUMARGS = 0x20, + ERRCODE_BAD_COMMAND = 0x40, + ERRCODE_NOT_READY = 0x80, // 0x80 (happens with getlocl when drive isn't reading, pause when tray is open, and MAYBE when trying to run an async + // command while another async command is currently in its asynch phase being executed[pause when in readtoc, todo test more]) + }; + + uint8 IRQBuffer; + uint8 IRQOutTestMask; + int32 CDCReadyReceiveCounter; // IRQBuffer being non-zero prevents new results and new IRQ from coming in and erasing the current results, + // but apparently at least one CONFOUNDED game is clearing the IRQ state BEFORE reading the results, so we need to have a delay + // between IRQBuffer being cleared to when we allow new results to come in. (The real thing should be like this too, + // but the mechanism is probably more nuanced and complex and ugly and I like anchovy pizza) + + void BeginResults(void); + void WriteIRQ(uint8); + void WriteResult(uint8); + uint8 ReadResult(void); + + uint8 FilterFile; + uint8 FilterChan; + + + uint8 PendingCommand; + int PendingCommandPhase; + int32 PendingCommandCounter; + + int32 SPUCounter; + + enum { MODE_SPEED = 0x80 }; + enum { MODE_STRSND = 0x40 }; + enum { MODE_SIZE = 0x20 }; + enum { MODE_SIZE2 = 0x10 }; + enum { MODE_SF = 0x08 }; + enum { MODE_REPORT = 0x04 }; + enum { MODE_AUTOPAUSE = 0x02 }; + enum { MODE_CDDA = 0x01 }; + uint8 Mode; + + enum + { + DS_STANDBY = -2, + DS_PAUSED = -1, + DS_STOPPED = 0, + DS_SEEKING, + DS_SEEKING_LOGICAL, + DS_PLAY_SEEKING, + DS_PLAYING, + DS_READING, + DS_RESETTING + }; + int DriveStatus; + int StatusAfterSeek; + bool Forward; + bool Backward; + bool Muted; + + int32 PlayTrackMatch; + + int32 PSRCounter; + + int32 CurSector; + + unsigned AsyncIRQPending; + uint8 AsyncResultsPending[16]; + uint8 AsyncResultsPendingCount; + + int32 CalcSeekTime(int32 initial, int32 target, bool motor_on, bool paused); + + void ClearAIP(void); + void CheckAIP(void); + void SetAIP(unsigned irq, unsigned result_count, uint8 *r); + void SetAIP(unsigned irq, uint8 result0); + void SetAIP(unsigned irq, uint8 result0, uint8 result1); + + int32 SeekTarget; + + pscpu_timestamp_t lastts; + + CDUtility::TOC toc; + bool IsPSXDisc; + uint8 DiscID[4]; + + int32 CommandLoc; + bool CommandLoc_Dirty; + + uint8 MakeStatus(bool cmd_error = false); + bool DecodeSubQ(uint8 *subpw); + bool CommandCheckDiscPresent(void); + + void EnbufferizeCDDASector(const uint8 *buf); + bool XA_Test(const uint8 *sdata); + void XA_ProcessSector(const uint8 *sdata, CD_Audio_Buffer *ab); + int16 xa_previous[2][2]; + bool xa_cur_set; + uint8 xa_cur_file; + uint8 xa_cur_chan; + + uint8 ReportLastF; + + void HandlePlayRead(void); + + struct CDC_CTEntry + { + uint8 args_min; + uint8 args_max; + const char *name; + int32 (PS_CDC::*func)(const int arg_count, const uint8 *args); + int32 (PS_CDC::*func2)(void); + }; + + void BeginSeek(uint32 target); + void PreSeekHack(bool logical, uint32 target); + void ReadBase(void); + + static CDC_CTEntry Commands[0x20]; + + int32 Command_Sync(const int arg_count, const uint8 *args); + int32 Command_Nop(const int arg_count, const uint8 *args); + int32 Command_Setloc(const int arg_count, const uint8 *args); + int32 Command_Play(const int arg_count, const uint8 *args); + int32 Command_Forward(const int arg_count, const uint8 *args); + int32 Command_Backward(const int arg_count, const uint8 *args); + int32 Command_ReadN(const int arg_count, const uint8 *args); + int32 Command_Standby(const int arg_count, const uint8 *args); + int32 Command_Standby_Part2(void); + int32 Command_Stop(const int arg_count, const uint8 *args); + int32 Command_Stop_Part2(void); + int32 Command_Pause(const int arg_count, const uint8 *args); + int32 Command_Pause_Part2(void); + int32 Command_Reset(const int arg_count, const uint8 *args); + int32 Command_Mute(const int arg_count, const uint8 *args); + int32 Command_Demute(const int arg_count, const uint8 *args); + int32 Command_Setfilter(const int arg_count, const uint8 *args); + int32 Command_Setmode(const int arg_count, const uint8 *args); + int32 Command_Getparam(const int arg_count, const uint8 *args); + int32 Command_GetlocL(const int arg_count, const uint8 *args); + int32 Command_GetlocP(const int arg_count, const uint8 *args); + + int32 Command_ReadT(const int arg_count, const uint8 *args); + int32 Command_ReadT_Part2(void); + + int32 Command_GetTN(const int arg_count, const uint8 *args); + int32 Command_GetTD(const int arg_count, const uint8 *args); + int32 Command_SeekL(const int arg_count, const uint8 *args); + int32 Command_SeekP(const int arg_count, const uint8 *args); + int32 Command_Seek_PartN(void); + + int32 Command_Test(const int arg_count, const uint8 *args); + + int32 Command_ID(const int arg_count, const uint8 *args); + int32 Command_ID_Part2(void); + + int32 Command_ReadS(const int arg_count, const uint8 *args); + int32 Command_Init(const int arg_count, const uint8 *args); + + int32 Command_ReadTOC(const int arg_count, const uint8 *args); + int32 Command_ReadTOC_Part2(void); + + int32 Command_0x1d(const int arg_count, const uint8 *args); +}; + +} + +#endif diff --git a/psx/octoshock/psx/cpu.cpp b/psx/octoshock/psx/cpu.cpp new file mode 100644 index 0000000000..42c53c909e --- /dev/null +++ b/psx/octoshock/psx/cpu.cpp @@ -0,0 +1,954 @@ +/* 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 "psx.h" +#include "cpu.h" + +/* TODO + Make sure load delays are correct. + + Consider preventing IRQs being taken while in a branch delay slot, to prevent potential problems with games that like to be too clever and perform + un-restartable sequences of instructions. +*/ + +#define BIU_ENABLE_ICACHE_S1 0x00000800 // Enable I-cache, set 1 +#define BIU_ENABLE_DCACHE 0x00000080 // Enable D-cache +#define BIU_TAG_TEST_MODE 0x00000004 // Enable TAG test mode(IsC must be set to 1 as well presumably?) +#define BIU_INVALIDATE_MODE 0x00000002 // Enable Invalidate mode(IsC must be set to 1 as well presumably?) +#define BIU_LOCK 0x00000001 // Enable Lock mode(IsC must be set to 1 as well presumably?) + // Does lock mode prevent the actual data payload from being modified, while allowing tags to be modified/updated??? + +namespace MDFN_IEN_PSX +{ + + +PS_CPU::PS_CPU() +{ + Halted = false; + + memset(FastMap, 0, sizeof(FastMap)); + memset(DummyPage, 0xFF, sizeof(DummyPage)); // 0xFF to trigger an illegal instruction exception, so we'll know what's up when debugging. + + for(uint64 a = 0x00000000; a < (1ULL << 32); a += FAST_MAP_PSIZE) + SetFastMap(DummyPage, a, FAST_MAP_PSIZE); + + CPUHook = NULL; + ADDBT = NULL; +} + +PS_CPU::~PS_CPU() +{ + + +} + +void PS_CPU::SetFastMap(void *region_mem, uint32_t region_address, uint32_t region_size) +{ + uint64_t A; + // FAST_MAP_SHIFT + // FAST_MAP_PSIZE + + for(A = region_address; A < (uint64)region_address + region_size; A += FAST_MAP_PSIZE) + FastMap[A >> FAST_MAP_SHIFT] = ((uint8_t *)region_mem - region_address); +} + +INLINE void PS_CPU::RecalcIPCache(void) +{ + IPCache = 0; + + if(((CP0.SR & CP0.CAUSE & 0xFF00) && (CP0.SR & 1)) || Halted) + IPCache = 0x80; +} + +void PS_CPU::SetHalt(bool status) +{ + Halted = status; + RecalcIPCache(); +} + +void PS_CPU::Power(void) +{ + unsigned i; + + assert(sizeof(ICache) == sizeof(ICache_Bulk)); + + memset(GPR, 0, sizeof(GPR)); + memset(&CP0, 0, sizeof(CP0)); + LO = 0; + HI = 0; + + gte_ts_done = 0; + muldiv_ts_done = 0; + + BACKED_PC = 0xBFC00000; + BACKED_new_PC = 4; + BACKED_new_PC_mask = ~0U; + + BACKED_LDWhich = 0x20; + BACKED_LDValue = 0; + LDAbsorb = 0; + memset(ReadAbsorb, 0, sizeof(ReadAbsorb)); + ReadAbsorbWhich = 0; + ReadFudge = 0; + + //WriteAbsorb = 0; + //WriteAbsorbCount = 0; + //WriteAbsorbMonkey = 0; + + CP0.SR |= (1 << 22); // BEV + CP0.SR |= (1 << 21); // TS + + CP0.PRID = 0x2; + + RecalcIPCache(); + + + BIU = 0; + + memset(ScratchRAM.data8, 0, 1024); + + // Not quite sure about these poweron/reset values: + for(i = 0; i < 1024; i++) + { + ICache[i].TV = 0x2 | ((BIU & 0x800) ? 0x0 : 0x1); + ICache[i].Data = 0; + } + + GTE_Power(); +} + +int PS_CPU::StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFARRAY32(GPR, 32), + SFVAR(LO), + SFVAR(HI), + SFVAR(BACKED_PC), + SFVAR(BACKED_new_PC), + SFVAR(BACKED_new_PC_mask), + + SFVAR(IPCache), + SFVAR(Halted), + + SFVAR(BACKED_LDWhich), + SFVAR(BACKED_LDValue), + SFVAR(LDAbsorb), + + SFVAR(next_event_ts), + SFVAR(gte_ts_done), + SFVAR(muldiv_ts_done), + + SFVAR(BIU), + SFARRAY32(ICache_Bulk, 2048), + + SFARRAY32(CP0.Regs, 32), + + SFARRAY(ReadAbsorb, 0x20), + SFVAR(ReadAbsorbDummy), + SFVAR(ReadAbsorbWhich), + SFVAR(ReadFudge), + + SFARRAY(ScratchRAM.data8, 1024), + + SFEND + }; + int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "CPU"); + + ret &= GTE_StateAction(sm, load, data_only); + + if(load) + { + + } + + return(ret); +} + +void PS_CPU::AssertIRQ(int which, bool asserted) +{ + assert(which >= 0 && which <= 5); + + CP0.CAUSE &= ~(1 << (10 + which)); + + if(asserted) + CP0.CAUSE |= 1 << (10 + which); + + RecalcIPCache(); +} + +void PS_CPU::SetBIU(uint32_t val) +{ + unsigned i; + const uint32_t old_BIU = BIU; + + BIU = val & ~(0x440); + + if((BIU ^ old_BIU) & 0x800) + { + if(BIU & 0x800) // ICache enabled + { + for(i = 0; i < 1024; i++) + ICache[i].TV &= ~0x1; + } + else // ICache disabled + { + for(i = 0; i < 1024; i++) + ICache[i].TV |= 0x1; + } + } + + PSX_DBG(PSX_DBG_SPARSE, "[CPU] Set BIU=0x%08x\n", BIU); +} + +uint32_t PS_CPU::GetBIU(void) +{ + return BIU; +} + +static const uint32_t addr_mask[8] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x7FFFFFFF, 0x1FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + +template +INLINE T PS_CPU::PeekMemory(uint32_t address) +{ + T ret; + address &= addr_mask[address >> 29]; + + if(address >= 0x1F800000 && address <= 0x1F8003FF) + return ScratchRAM.Read(address & 0x3FF); + + //assert(!(CP0.SR & 0x10000)); + + if(sizeof(T) == 1) + ret = PSX_MemPeek8(address); + else if(sizeof(T) == 2) + ret = PSX_MemPeek16(address); + else + ret = PSX_MemPeek32(address); + + return(ret); +} + +template +INLINE T PS_CPU::ReadMemory(pscpu_timestamp_t ×tamp, uint32_t address, bool DS24, bool LWC_timing) +{ + T ret; + + //WriteAbsorb >>= WriteAbsorbMonkey * 8; + //WriteAbsorbCount -= WriteAbsorbMonkey; + //WriteAbsorbMonkey = WriteAbsorbCount; + + ReadAbsorb[ReadAbsorbWhich] = 0; + ReadAbsorbWhich = 0; + + address &= addr_mask[address >> 29]; + + if(address >= 0x1F800000 && address <= 0x1F8003FF) + { + LDAbsorb = 0; + + if(DS24) + return ScratchRAM.ReadU24(address & 0x3FF); + else + return ScratchRAM.Read(address & 0x3FF); + } + + timestamp += (ReadFudge >> 4) & 2; + + //assert(!(CP0.SR & 0x10000)); + + pscpu_timestamp_t lts = timestamp; + + if(sizeof(T) == 1) + ret = PSX_MemRead8(lts, address); + else if(sizeof(T) == 2) + ret = PSX_MemRead16(lts, address); + else + { + if(DS24) + ret = PSX_MemRead24(lts, address) & 0xFFFFFF; + else + ret = PSX_MemRead32(lts, address); + } + + if(LWC_timing) + lts += 1; + else + lts += 2; + + LDAbsorb = (lts - timestamp); + timestamp = lts; + + return(ret); +} + +template +INLINE void PS_CPU::WriteMemory(pscpu_timestamp_t ×tamp, uint32_t address, uint32_t value, bool DS24) +{ + if(MDFN_LIKELY(!(CP0.SR & 0x10000))) + { + address &= addr_mask[address >> 29]; + + if(address >= 0x1F800000 && address <= 0x1F8003FF) + { + if(DS24) + ScratchRAM.WriteU24(address & 0x3FF, value); + else + ScratchRAM.Write(address & 0x3FF, value); + + return; + } + + //if(WriteAbsorbCount == 4) + //{ + // WriteAbsorb >>= 8; + // WriteAbsorbCount--; + // + // if(WriteAbsorbMonkey) + // WriteAbsorbMonkey--; + //} + //timestamp += 3; + //WriteAbsorb |= (3U << (WriteAbsorbCount * 8)); + //WriteAbsorbCount++; + + if(sizeof(T) == 1) + PSX_MemWrite8(timestamp, address, value); + else if(sizeof(T) == 2) + PSX_MemWrite16(timestamp, address, value); + else + { + if(DS24) + PSX_MemWrite24(timestamp, address, value); + else + PSX_MemWrite32(timestamp, address, value); + } + } + else + { + if(BIU & 0x800) // Instruction cache is enabled/active + { + if(BIU & 0x4) // TAG test mode. + { + // TODO: Respect written value. + __ICache *ICI = &ICache[((address & 0xFF0) >> 2)]; + const uint8_t valid_bits = 0x00; + + ICI[0].TV = ((valid_bits & 0x01) ? 0x00 : 0x02) | ((BIU & 0x800) ? 0x0 : 0x1); + ICI[1].TV = ((valid_bits & 0x02) ? 0x00 : 0x02) | ((BIU & 0x800) ? 0x0 : 0x1); + ICI[2].TV = ((valid_bits & 0x04) ? 0x00 : 0x02) | ((BIU & 0x800) ? 0x0 : 0x1); + ICI[3].TV = ((valid_bits & 0x08) ? 0x00 : 0x02) | ((BIU & 0x800) ? 0x0 : 0x1); + } + else if(!(BIU & 0x1)) + { + ICache[(address & 0xFFC) >> 2].Data = value << ((address & 0x3) * 8); + } + } + + if((BIU & 0x081) == 0x080) // Writes to the scratchpad(TODO test) + { + if(DS24) + ScratchRAM.WriteU24(address & 0x3FF, value); + else + ScratchRAM.Write(address & 0x3FF, value); + } + //printf("IsC WRITE%d 0x%08x 0x%08x -- CP0.SR=0x%08x\n", (int)sizeof(T), address, value, CP0.SR); + } +} + +uint32_t PS_CPU::Exception(uint32_t code, uint32_t PC, const uint32_t NPM) +{ + const bool InBDSlot = !(NPM & 0x3); + uint32_t handler = 0x80000080; + + assert(code < 16); + + if(code != EXCEPTION_INT && code != EXCEPTION_BP && code != EXCEPTION_SYSCALL) + { + PSX_DBG(PSX_DBG_WARNING, "Exception: %08x @ PC=0x%08x(IBDS=%d) -- IPCache=0x%02x -- IPEND=0x%02x -- SR=0x%08x ; IRQC_Status=0x%04x -- IRQC_Mask=0x%04x\n", code, PC, InBDSlot, IPCache, (CP0.CAUSE >> 8) & 0xFF, CP0.SR, + IRQ_GetRegister(IRQ_GSREG_STATUS, NULL, 0), IRQ_GetRegister(IRQ_GSREG_MASK, NULL, 0)); + } + + if(CP0.SR & (1 << 22)) // BEV + handler = 0xBFC00180; + + CP0.EPC = PC; + if(InBDSlot) + CP0.EPC -= 4; + + if(ADDBT) + ADDBT(PC, handler, true); + + // "Push" IEc and KUc(so that the new IEc and KUc are 0) + CP0.SR = (CP0.SR & ~0x3F) | ((CP0.SR << 2) & 0x3F); + + // Setup cause register + CP0.CAUSE &= 0x0000FF00; + CP0.CAUSE |= code << 2; + + // If EPC was adjusted -= 4 because we were in a branch delay slot, set the bit. + if(InBDSlot) + CP0.CAUSE |= 0x80000000; + + RecalcIPCache(); + + return(handler); +} + +#define BACKING_TO_ACTIVE \ + PC = BACKED_PC; \ + new_PC = BACKED_new_PC; \ + new_PC_mask = BACKED_new_PC_mask; \ + LDWhich = BACKED_LDWhich; \ + LDValue = BACKED_LDValue; + +#define ACTIVE_TO_BACKING \ + BACKED_PC = PC; \ + BACKED_new_PC = new_PC; \ + BACKED_new_PC_mask = new_PC_mask; \ + BACKED_LDWhich = LDWhich; \ + BACKED_LDValue = LDValue; + +#define GPR_DEPRES_BEGIN { uint8_t back = ReadAbsorb[0]; +#define GPR_DEP(n) { unsigned tn = (n); ReadAbsorb[tn] = 0; } +#define GPR_RES(n) { unsigned tn = (n); ReadAbsorb[tn] = 0; } +#define GPR_DEPRES_END ReadAbsorb[0] = back; } + +template +pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in) +{ + register pscpu_timestamp_t timestamp = timestamp_in; + + register uint32_t PC; + register uint32_t new_PC; + register uint32_t new_PC_mask; + register uint32_t LDWhich; + register uint32_t LDValue; + + //printf("%d %d\n", gte_ts_done, muldiv_ts_done); + + gte_ts_done += timestamp; + muldiv_ts_done += timestamp; + + BACKING_TO_ACTIVE; + + do + { + //printf("Running: %d %d\n", timestamp, next_event_ts); + while(MDFN_LIKELY(timestamp < next_event_ts)) + { + uint32_t instr; + uint32_t opf; + + // Zero must be zero...until the Master Plan is enacted. + GPR[0] = 0; + + if(DebugMode && CPUHook) + { + ACTIVE_TO_BACKING; + + // For save states in step mode. + gte_ts_done -= timestamp; + muldiv_ts_done -= timestamp; + + CPUHook(timestamp, PC); + + // For save states in step mode. + gte_ts_done += timestamp; + muldiv_ts_done += timestamp; + + BACKING_TO_ACTIVE; + } + + if(!ILHMode) + { + if(PC == 0xB0) + { + if(MDFN_UNLIKELY(GPR[9] == 0x3D)) + { + PSX_DBG(PSX_DBG_BIOS_PRINT, "%c", GPR[4]); + } + } + } + + instr = ICache[(PC & 0xFFC) >> 2].Data; + + if(ICache[(PC & 0xFFC) >> 2].TV != PC) + { + //WriteAbsorb = 0; + //WriteAbsorbCount = 0; + //WriteAbsorbMonkey = 0; + ReadAbsorb[ReadAbsorbWhich] = 0; + ReadAbsorbWhich = 0; + + // FIXME: Handle executing out of scratchpad. + if(PC >= 0xA0000000 || !(BIU & 0x800)) + { + instr = LoadU32_LE((uint32_t *)&FastMap[PC >> FAST_MAP_SHIFT][PC]); + timestamp += 4; // Approximate best-case cache-disabled time, per PS1 tests(executing out of 0xA0000000+); it can be 5 in *some* sequences of code(like a lot of sequential "nop"s, probably other simple instructions too). + } + else + { + __ICache *ICI = &ICache[((PC & 0xFF0) >> 2)]; + const uint32_t *FMP = (uint32_t *)&FastMap[(PC &~ 0xF) >> FAST_MAP_SHIFT][PC &~ 0xF]; + + // | 0x2 to simulate (in)validity bits. + ICI[0x00].TV = (PC &~ 0xF) | 0x00 | 0x2; + ICI[0x01].TV = (PC &~ 0xF) | 0x04 | 0x2; + ICI[0x02].TV = (PC &~ 0xF) | 0x08 | 0x2; + ICI[0x03].TV = (PC &~ 0xF) | 0x0C | 0x2; + + timestamp += 3; + + switch(PC & 0xC) + { + case 0x0: + timestamp++; + ICI[0x00].TV &= ~0x2; + ICI[0x00].Data = LoadU32_LE(&FMP[0]); + case 0x4: + timestamp++; + ICI[0x01].TV &= ~0x2; + ICI[0x01].Data = LoadU32_LE(&FMP[1]); + case 0x8: + timestamp++; + ICI[0x02].TV &= ~0x2; + ICI[0x02].Data = LoadU32_LE(&FMP[2]); + case 0xC: + timestamp++; + ICI[0x03].TV &= ~0x2; + ICI[0x03].Data = LoadU32_LE(&FMP[3]); + break; + } + instr = ICache[(PC & 0xFFC) >> 2].Data; + } + } + + //printf("PC=%08x, SP=%08x - op=0x%02x - funct=0x%02x - instr=0x%08x\n", PC, GPR[29], instr >> 26, instr & 0x3F, instr); + //for(int i = 0; i < 32; i++) + // printf("%02x : %08x\n", i, GPR[i]); + //printf("\n"); + + opf = instr & 0x3F; + + if(instr & (0x3F << 26)) + opf = 0x40 | (instr >> 26); + + opf |= IPCache; + +#if 0 + { + uint32_t tmp = (ReadAbsorb[ReadAbsorbWhich] + 0x7FFFFFFF) >> 31; + ReadAbsorb[ReadAbsorbWhich] -= tmp; + timestamp = timestamp + 1 - tmp; + } +#else + if(ReadAbsorb[ReadAbsorbWhich]) + ReadAbsorb[ReadAbsorbWhich]--; + //else if((uint8)WriteAbsorb) + //{ + // WriteAbsorb--; + // if(!WriteAbsorb) + // { + // WriteAbsorbCount--; + // if(WriteAbsorbMonkey) + // WriteAbsorbMonkey--; + // WriteAbsorb >>= 8; + // } + //} + else + timestamp++; +#endif + +#define DO_LDS() { GPR[LDWhich] = LDValue; ReadAbsorb[LDWhich] = LDAbsorb; ReadFudge = LDWhich; ReadAbsorbWhich |= LDWhich & 0x1F; LDWhich = 0x20; } +#define BEGIN_OPF(name, arg_op, arg_funct) { op_##name: /*assert( ((arg_op) ? (0x40 | (arg_op)) : (arg_funct)) == opf); */ +#define END_OPF goto OpDone; } + +#define DO_BRANCH(offset, mask) \ + { \ + if(ILHMode) \ + { \ + uint32_t old_PC = PC; \ + PC = (PC & new_PC_mask) + new_PC; \ + if(old_PC == ((PC & (mask)) + (offset))) \ + { \ + if(*(uint32_t *)&FastMap[PC >> FAST_MAP_SHIFT][PC] == 0) \ + { \ + if(next_event_ts > timestamp) /* Necessary since next_event_ts might be set to something like "0" to force a call to the event handler. */ \ + { \ + timestamp = next_event_ts; \ + } \ + } \ + } \ + } \ + else \ + PC = (PC & new_PC_mask) + new_PC; \ + new_PC = (offset); \ + new_PC_mask = (mask) & ~3; \ + /* Lower bits of new_PC_mask being clear signifies being in a branch delay slot. (overloaded behavior for performance) */ \ + \ + if(DebugMode && ADDBT) \ + { \ + ADDBT(PC, (PC & new_PC_mask) + new_PC, false); \ + } \ + goto SkipNPCStuff; \ + } + +#define ITYPE uint32_t rs MDFN_NOWARN_UNUSED = (instr >> 21) & 0x1F; uint32_t rt MDFN_NOWARN_UNUSED = (instr >> 16) & 0x1F; int32_t immediate = (int16)(instr & 0xFFFF); /*printf(" rs=%02x(%08x), rt=%02x(%08x), immediate=(%08x) ", rs, GPR[rs], rt, GPR[rt], immediate);*/ +#define ITYPE_ZE uint32_t rs MDFN_NOWARN_UNUSED = (instr >> 21) & 0x1F; uint32_t rt MDFN_NOWARN_UNUSED = (instr >> 16) & 0x1F; uint32_t immediate = instr & 0xFFFF; /*printf(" rs=%02x(%08x), rt=%02x(%08x), immediate=(%08x) ", rs, GPR[rs], rt, GPR[rt], immediate);*/ +#define JTYPE uint32_t target = instr & ((1 << 26) - 1); /*printf(" target=(%08x) ", target);*/ +#define RTYPE uint32_t rs MDFN_NOWARN_UNUSED = (instr >> 21) & 0x1F; uint32_t rt MDFN_NOWARN_UNUSED = (instr >> 16) & 0x1F; uint32_t rd MDFN_NOWARN_UNUSED = (instr >> 11) & 0x1F; uint32_t shamt MDFN_NOWARN_UNUSED = (instr >> 6) & 0x1F; /*printf(" rs=%02x(%08x), rt=%02x(%08x), rd=%02x(%08x) ", rs, GPR[rs], rt, GPR[rt], rd, GPR[rd]);*/ + +#if 1 +#include "cpu_bigswitch.c" +#else +#include "cpu_coputedgoto.c" +#endif + +OpDone: ; + + PC = (PC & new_PC_mask) + new_PC; + new_PC_mask = ~0U; + new_PC = 4; + +SkipNPCStuff: ; + + //printf("\n"); + } + } while(MDFN_LIKELY(PSX_EventHandler(timestamp))); + + if(gte_ts_done > 0) + gte_ts_done -= timestamp; + + if(muldiv_ts_done > 0) + muldiv_ts_done -= timestamp; + + ACTIVE_TO_BACKING; + + return(timestamp); +} + +pscpu_timestamp_t PS_CPU::Run(pscpu_timestamp_t timestamp_in, const bool ILHMode) +{ + if(CPUHook || ADDBT) + return(RunReal(timestamp_in)); + if (ILHMode) + return(RunReal(timestamp_in)); + return(RunReal(timestamp_in)); +} + +void PS_CPU::SetCPUHook(void (*cpuh)(const pscpu_timestamp_t timestamp, uint32_t pc), void (*addbt)(uint32_t from, uint32_t to, bool exception)) +{ + ADDBT = addbt; + CPUHook = cpuh; +} + +uint32_t PS_CPU::GetRegister(unsigned int which, char *special, const uint32_t special_len) +{ + uint32_t ret = 0; + + if(which >= GSREG_GPR && which < (GSREG_GPR + 32)) + return GPR[which]; + + switch(which) + { + case GSREG_PC: + ret = BACKED_PC; + break; + + case GSREG_PC_NEXT: + ret = BACKED_new_PC; + break; + + case GSREG_IN_BD_SLOT: + ret = !(BACKED_new_PC_mask & 3); + break; + + case GSREG_LO: + ret = LO; + break; + + case GSREG_HI: + ret = HI; + break; + + case GSREG_SR: + ret = CP0.SR; + break; + + case GSREG_CAUSE: + ret = CP0.CAUSE; + break; + + case GSREG_EPC: + ret = CP0.EPC; + break; + + } + + return ret; +} + +void PS_CPU::SetRegister(unsigned int which, uint32_t value) +{ + if(which >= GSREG_GPR && which < (GSREG_GPR + 32)) + { + if(which != (GSREG_GPR + 0)) + GPR[which] = value; + } + else switch(which) + { + case GSREG_PC: + BACKED_PC = value & ~0x3; // Remove masking if we ever add proper misaligned PC exception + break; + + case GSREG_LO: + LO = value; + break; + + case GSREG_HI: + HI = value; + break; + + case GSREG_SR: + CP0.SR = value; // TODO: mask + break; + + case GSREG_CAUSE: + CP0.CAUSE = value; + break; + + case GSREG_EPC: + CP0.EPC = value & ~0x3U; + break; + } +} + +bool PS_CPU::PeekCheckICache(uint32_t PC, uint32_t *iw) +{ + if(ICache[(PC & 0xFFC) >> 2].TV == PC) + { + *iw = ICache[(PC & 0xFFC) >> 2].Data; + return(true); + } + + return(false); +} + + +uint8_t PS_CPU::PeekMem8(uint32_t A) +{ + return PeekMemory(A); +} + +uint16_t PS_CPU::PeekMem16(uint32_t A) +{ + return PeekMemory(A); +} + +uint32_t PS_CPU::PeekMem32(uint32_t A) +{ + return PeekMemory(A); +} + + +#undef BEGIN_OPF +#undef END_OPF +#undef MK_OPF + +#define MK_OPF(op, funct) ((op) ? (0x40 | (op)) : (funct)) +#define BEGIN_OPF(op, funct) case MK_OPF(op, funct): { +#define END_OPF } break; + +// FIXME: should we breakpoint on an illegal address? And with LWC2/SWC2 if CP2 isn't enabled? +void PS_CPU::CheckBreakpoints(void (*callback)(bool write, uint32_t address, unsigned int len), uint32_t instr) +{ + uint32_t opf; + + opf = instr & 0x3F; + + if(instr & (0x3F << 26)) + opf = 0x40 | (instr >> 26); + + + switch(opf) + { + default: + break; + + // + // LB - Load Byte + // + BEGIN_OPF(0x20, 0); + ITYPE; + uint32_t address = GPR[rs] + immediate; + + callback(false, address, 1); + END_OPF; + + // + // LBU - Load Byte Unsigned + // + BEGIN_OPF(0x24, 0); + ITYPE; + uint32_t address = GPR[rs] + immediate; + + callback(false, address, 1); + END_OPF; + + // + // LH - Load Halfword + // + BEGIN_OPF(0x21, 0); + ITYPE; + uint32_t address = GPR[rs] + immediate; + + callback(false, address, 2); + END_OPF; + + // + // LHU - Load Halfword Unsigned + // + BEGIN_OPF(0x25, 0); + ITYPE; + uint32_t address = GPR[rs] + immediate; + + callback(false, address, 2); + END_OPF; + + + // + // LW - Load Word + // + BEGIN_OPF(0x23, 0); + ITYPE; + uint32_t address = GPR[rs] + immediate; + + callback(false, address, 4); + END_OPF; + + // + // SB - Store Byte + // + BEGIN_OPF(0x28, 0); + ITYPE; + uint32_t address = GPR[rs] + immediate; + + callback(true, address, 1); + END_OPF; + + // + // SH - Store Halfword + // + BEGIN_OPF(0x29, 0); + ITYPE; + uint32_t address = GPR[rs] + immediate; + + callback(true, address, 2); + END_OPF; + + // + // SW - Store Word + // + BEGIN_OPF(0x2B, 0); + ITYPE; + uint32_t address = GPR[rs] + immediate; + + callback(true, address, 4); + END_OPF; + + // + // LWL - Load Word Left + // + BEGIN_OPF(0x22, 0); + ITYPE; + uint32_t address = GPR[rs] + immediate; + + do + { + callback(false, address, 1); + } while((address--) & 0x3); + + END_OPF; + + // + // SWL - Store Word Left + // + BEGIN_OPF(0x2A, 0); + ITYPE; + uint32_t address = GPR[rs] + immediate; + + do + { + callback(true, address, 1); + } while((address--) & 0x3); + + END_OPF; + + // + // LWR - Load Word Right + // + BEGIN_OPF(0x26, 0); + ITYPE; + uint32_t address = GPR[rs] + immediate; + + do + { + callback(false, address, 1); + } while((++address) & 0x3); + + END_OPF; + + // + // SWR - Store Word Right + // + BEGIN_OPF(0x2E, 0); + ITYPE; + uint32_t address = GPR[rs] + immediate; + + do + { + callback(true, address, 1); + } while((++address) & 0x3); + + END_OPF; + + // + // LWC2 + // + BEGIN_OPF(0x32, 0); + ITYPE; + uint32_t address = GPR[rs] + immediate; + + callback(false, address, 4); + END_OPF; + + // + // SWC2 + // + BEGIN_OPF(0x3A, 0); + ITYPE; + uint32_t address = GPR[rs] + immediate; + + callback(true, address, 4); + END_OPF; + + } +} + + +} diff --git a/psx/octoshock/psx/cpu.h b/psx/octoshock/psx/cpu.h new file mode 100644 index 0000000000..7734001686 --- /dev/null +++ b/psx/octoshock/psx/cpu.h @@ -0,0 +1,260 @@ +#ifndef __MDFN_PSX_CPU_H +#define __MDFN_PSX_CPU_H + +/* + Load delay notes: + + // Takes 1 less + ".set noreorder\n\t" + ".set nomacro\n\t" + "lw %0, 0(%2)\n\t" + "nop\n\t" + "nop\n\t" + "or %0, %1, %1\n\t" + + // cycle than this: + ".set noreorder\n\t" + ".set nomacro\n\t" + "lw %0, 0(%2)\n\t" + "nop\n\t" + "or %0, %1, %1\n\t" + "nop\n\t" + + + // Both of these + ".set noreorder\n\t" + ".set nomacro\n\t" + "lw %0, 0(%2)\n\t" + "nop\n\t" + "nop\n\t" + "or %1, %0, %0\n\t" + + // take same...(which is kind of odd). + ".set noreorder\n\t" + ".set nomacro\n\t" + "lw %0, 0(%2)\n\t" + "nop\n\t" + "or %1, %0, %0\n\t" + "nop\n\t" +*/ + +#include "gte.h" + +namespace MDFN_IEN_PSX +{ + +#define PS_CPU_EMULATE_ICACHE 1 + +class PS_CPU +{ + public: + + PS_CPU(); + ~PS_CPU(); + + // FAST_MAP_* enums are in BYTES(8-bit), not in 32-bit units("words" in MIPS context), but the sizes + // will always be multiples of 4. + enum { FAST_MAP_SHIFT = 16 }; + enum { FAST_MAP_PSIZE = 1 << FAST_MAP_SHIFT }; + + void SetFastMap(void *region_mem, uint32_t region_address, uint32_t region_size); + + INLINE void SetEventNT(const pscpu_timestamp_t next_event_ts_arg) + { + next_event_ts = next_event_ts_arg; + } + + pscpu_timestamp_t Run(pscpu_timestamp_t timestamp_in, const bool ILHMode); + + void Power(void); + + // which ranges 0-5, inclusive + void AssertIRQ(int which, bool asserted); + + void SetHalt(bool status); + + // TODO eventually: factor BIU address decoding directly in the CPU core somehow without hurting speed. + void SetBIU(uint32_t val); + uint32_t GetBIU(void); + + int StateAction(StateMem *sm, int load, int data_only); + + private: + + struct + { + uint32_t GPR[32]; + uint32_t GPR_dummy; // Used in load delay simulation(indexing past the end of GPR) + }; + uint32_t LO; + uint32_t HI; + + + uint32_t BACKED_PC; + uint32_t BACKED_new_PC; + uint32_t BACKED_new_PC_mask; + + uint32_t IPCache; + void RecalcIPCache(void); + bool Halted; + + uint32_t BACKED_LDWhich; + uint32_t BACKED_LDValue; + uint32_t LDAbsorb; + + pscpu_timestamp_t next_event_ts; + pscpu_timestamp_t gte_ts_done; + pscpu_timestamp_t muldiv_ts_done; + + uint32_t BIU; + + struct __ICache + { + uint32_t TV; + uint32_t Data; + }; + + union + { + __ICache ICache[1024]; + uint32 ICache_Bulk[2048]; + }; + + enum + { + CP0REG_BPC = 3, // PC breakpoint address. + CP0REG_BDA = 5, // Data load/store breakpoint address. + CP0REG_TAR = 6, // Target address(???) + CP0REG_DCIC = 7, // Cache control + CP0REG_BDAM = 9, // Data load/store address mask. + CP0REG_BPCM = 11, // PC breakpoint address mask. + CP0REG_SR = 12, + CP0REG_CAUSE = 13, + CP0REG_EPC = 14, + CP0REG_PRID = 15, // Product ID + CP0REG_ERREG = 16 + }; + + struct + { + union + { + uint32_t Regs[32]; + struct + { + uint32_t Unused00; + uint32_t Unused01; + uint32_t Unused02; + uint32_t BPC; // RW + uint32_t Unused04; + uint32_t BDA; // RW + uint32_t TAR; + uint32_t DCIC; // RW + uint32_t Unused08; + uint32_t BDAM; // R/W + uint32_t Unused0A; + uint32_t BPCM; // R/W + uint32_t SR; // R/W + uint32_t CAUSE; // R/W(partial) + uint32_t EPC; // R + uint32_t PRID; // R + uint32_t ERREG; // ?(may not exist, test) + }; + }; + } CP0; + +#if 1 + //uint32_t WrAbsorb; + //uint8_t WrAbsorbShift; + + // On read: + //WrAbsorb = 0; + //WrAbsorbShift = 0; + + // On write: + //WrAbsorb >>= (WrAbsorbShift >> 2) & 8; + //WrAbsorbShift -= (WrAbsorbShift >> 2) & 8; + + //WrAbsorb |= (timestamp - pre_write_timestamp) << WrAbsorbShift; + //WrAbsorbShift += 8; +#endif + + struct + { + uint8_t ReadAbsorb[0x20]; + uint8_t ReadAbsorbDummy; + }; + uint8_t ReadAbsorbWhich; + uint8_t ReadFudge; + + //uint32_t WriteAbsorb; + //uint8_t WriteAbsorbCount; + //uint8_t WriteAbsorbMonkey; + + MultiAccessSizeMem<1024, uint32, false> ScratchRAM; + + //PS_GTE GTE; + + uint8_t *FastMap[1 << (32 - FAST_MAP_SHIFT)]; + uint8_t DummyPage[FAST_MAP_PSIZE]; + + enum + { + EXCEPTION_INT = 0, + EXCEPTION_MOD = 1, + EXCEPTION_TLBL = 2, + EXCEPTION_TLBS = 3, + EXCEPTION_ADEL = 4, // Address error on load + EXCEPTION_ADES = 5, // Address error on store + EXCEPTION_IBE = 6, // Instruction bus error + EXCEPTION_DBE = 7, // Data bus error + EXCEPTION_SYSCALL = 8, // System call + EXCEPTION_BP = 9, // Breakpoint + EXCEPTION_RI = 10, // Reserved instruction + EXCEPTION_COPU = 11, // Coprocessor unusable + EXCEPTION_OV = 12 // Arithmetic overflow + }; + + uint32_t Exception(uint32_t code, uint32_t PC, const uint32_t NPM) MDFN_WARN_UNUSED_RESULT; + + template pscpu_timestamp_t RunReal(pscpu_timestamp_t timestamp_in); + + template T PeekMemory(uint32_t address) MDFN_COLD; + template T ReadMemory(pscpu_timestamp_t ×tamp, uint32_t address, bool DS24 = false, bool LWC_timing = false); + template void WriteMemory(pscpu_timestamp_t ×tamp, uint32_t address, uint32_t value, bool DS24 = false); + + + // + // Mednafen debugger stuff follows: + // + public: + void SetCPUHook(void (*cpuh)(const pscpu_timestamp_t timestamp, uint32_t pc), void (*addbt)(uint32_t from, uint32_t to, bool exception)); + void CheckBreakpoints(void (*callback)(bool write, uint32_t address, unsigned int len), uint32_t instr); + + enum + { + GSREG_GPR = 0, + GSREG_PC = 32, + GSREG_PC_NEXT, + GSREG_IN_BD_SLOT, + GSREG_LO, + GSREG_HI, + GSREG_SR, + GSREG_CAUSE, + GSREG_EPC, + }; + + uint32_t GetRegister(unsigned int which, char *special, const uint32_t special_len); + void SetRegister(unsigned int which, uint32_t value); + bool PeekCheckICache(uint32_t PC, uint32_t *iw); + uint8_t PeekMem8(uint32_t A); + uint16_t PeekMem16(uint32_t A); + uint32_t PeekMem32(uint32_t A); + private: + void (*CPUHook)(const pscpu_timestamp_t timestamp, uint32_t pc); + void (*ADDBT)(uint32_t from, uint32_t to, bool exception); +}; + +} + +#endif diff --git a/psx/octoshock/psx/cpu_bigswitch.c b/psx/octoshock/psx/cpu_bigswitch.c new file mode 100644 index 0000000000..1f78922380 --- /dev/null +++ b/psx/octoshock/psx/cpu_bigswitch.c @@ -0,0 +1,1954 @@ + switch(opf) + { + case 0: /* SLL */ + { + // + // SLL - Shift Word Left Logical + // + BEGIN_OPF(SLL, 0, 0x00); // SLL + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rt] << shamt; + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + } + break; + case 1: /* ILL */ + case 5: + case 10: + case 11: + case 14: + case 15: + case 20: + case 21: + case 22: + case 23: + case 28: + case 29: + case 30: + case 31: + case 40: + case 41: + case 44: + case 45: + case 46: + case 47: + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + case 58: + case 59: + case 60: + case 61: + case 62: + case 63: + case 84: + case 85: + case 86: + case 87: + case 88: + case 89: + case 90: + case 91: + case 92: + case 93: + case 94: + case 95: + case 103: + case 108: + case 109: + case 111: + case 116: + case 117: + case 118: + case 119: + case 124: + case 125: + case 126: + case 127: + { + BEGIN_OPF(ILL, 0, 0); + PSX_WARNING("[CPU] Unknown instruction @%08x = %08x, op=%02x, funct=%02x", PC, instr, instr >> 26, (instr & 0x3F)); + DO_LDS(); + new_PC = Exception(EXCEPTION_RI, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + } + break; + case 2: /* SRL */ + { + // + // SRL - Shift Word Right Logical + // + BEGIN_OPF(SRL, 0, 0x02); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rt] >> shamt; + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + } + break; + case 3: /* SRA */ + { + // + // SRA - Shift Word Right Arithmetic + // + BEGIN_OPF(SRA, 0, 0x03); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = ((int32)GPR[rt]) >> shamt; + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + } + break; + case 4: /* SLLV */ + { + // + // SLLV - Shift Word Left Logical Variable + // + BEGIN_OPF(SLLV, 0, 0x04); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rt] << (GPR[rs] & 0x1F); + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + } + break; + case 6: /* SRLV */ + { + // + // SRLV - Shift Word Right Logical Variable + // + BEGIN_OPF(SRLV, 0, 0x06); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rt] >> (GPR[rs] & 0x1F); + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + } + break; + case 7: /* SRAV */ + { + // + // SRAV - Shift Word Right Arithmetic Variable + // + BEGIN_OPF(SRAV, 0, 0x07); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = ((int32)GPR[rt]) >> (GPR[rs] & 0x1F); + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + } + break; + case 8: /* JR */ + { + // + // JR - Jump Register + // + BEGIN_OPF(JR, 0, 0x08); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t bt = GPR[rs]; + + DO_LDS(); + + DO_BRANCH(bt, 0); + + END_OPF; + } + break; + case 9: /* JALR */ + { + // + // JALR - Jump and Link Register + // + BEGIN_OPF(JALR, 0, 0x09); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t tmp = GPR[rs]; + + DO_LDS(); + + GPR[rd] = PC + 8; + + DO_BRANCH(tmp, 0); + + END_OPF; + } + case 12: /* SYSCALL */ + { + // + // SYSCALL + // + BEGIN_OPF(SYSCALL, 0, 0x0C); + DO_LDS(); + + new_PC = Exception(EXCEPTION_SYSCALL, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + } + break; + case 13: /* BREAK */ + { + // + // BREAK - Breakpoint + // + BEGIN_OPF(BREAK, 0, 0x0D); + PSX_WARNING("[CPU] BREAK BREAK BREAK BREAK DAAANCE -- PC=0x%08x", PC); + + DO_LDS(); + new_PC = Exception(EXCEPTION_BP, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + } + break; + case 16: + { + // + // MFHI - Move from HI + // + BEGIN_OPF(MFHI, 0, 0x10); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_RES(rd); + GPR_DEPRES_END + + DO_LDS(); + + if(timestamp < muldiv_ts_done) + { + if(timestamp == muldiv_ts_done - 1) + muldiv_ts_done--; + else + { + do + { + if(ReadAbsorb[ReadAbsorbWhich]) + ReadAbsorb[ReadAbsorbWhich]--; + timestamp++; + } while(timestamp < muldiv_ts_done); + } + } + + GPR[rd] = HI; + + END_OPF; + + } + break; + case 17: + { + // + // MTHI - Move to HI + // + BEGIN_OPF(MTHI, 0, 0x11); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEPRES_END + + HI = GPR[rs]; + + DO_LDS(); + + END_OPF; + } + break; + case 18: + { + // + // MFLO - Move from LO + // + BEGIN_OPF(MFLO, 0, 0x12); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_RES(rd); + GPR_DEPRES_END + + DO_LDS(); + + if(timestamp < muldiv_ts_done) + { + if(timestamp == muldiv_ts_done - 1) + muldiv_ts_done--; + else + { + do + { + if(ReadAbsorb[ReadAbsorbWhich]) + ReadAbsorb[ReadAbsorbWhich]--; + timestamp++; + } while(timestamp < muldiv_ts_done); + } + } + + GPR[rd] = LO; + + END_OPF; + } + break; + case 19: + { + // + // MTLO - Move to LO + // + BEGIN_OPF(MTLO, 0, 0x13); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEPRES_END + + LO = GPR[rs]; + + DO_LDS(); + + END_OPF; + } + break; + case 24: /* MULT */ + { + // + // MULT - Multiply Word + // + BEGIN_OPF(MULT, 0, 0x18); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + uint64 result; + + result = (int64)(int32)GPR[rs] * (int32)GPR[rt]; + muldiv_ts_done = timestamp + 7; + + DO_LDS(); + + LO = result; + HI = result >> 32; + + END_OPF; + } + break; + case 25: /* MULTU */ + { + // + // MULTU - Multiply Unsigned Word + // + BEGIN_OPF(MULTU, 0, 0x19); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + uint64 result; + + result = (uint64)GPR[rs] * GPR[rt]; + muldiv_ts_done = timestamp + 7; + + DO_LDS(); + + LO = result; + HI = result >> 32; + + END_OPF; + } + break; + case 26: /* DIV */ + { + // + // DIV - Divide Word + // + BEGIN_OPF(DIV, 0, 0x1A); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + if(!GPR[rt]) + { + if(GPR[rs] & 0x80000000) + LO = 1; + else + LO = 0xFFFFFFFF; + + HI = GPR[rs]; + } + else if(GPR[rs] == 0x80000000 && GPR[rt] == 0xFFFFFFFF) + { + LO = 0x80000000; + HI = 0; + } + else + { + LO = (int32)GPR[rs] / (int32)GPR[rt]; + HI = (int32)GPR[rs] % (int32)GPR[rt]; + } + muldiv_ts_done = timestamp + 37; + + DO_LDS(); + + END_OPF; + } + break; + case 27: /* DIVU */ + { + // + // DIVU - Divide Unsigned Word + // + BEGIN_OPF(DIVU, 0, 0x1B); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + if(!GPR[rt]) + { + LO = 0xFFFFFFFF; + HI = GPR[rs]; + } + else + { + LO = GPR[rs] / GPR[rt]; + HI = GPR[rs] % GPR[rt]; + } + muldiv_ts_done = timestamp + 37; + + DO_LDS(); + END_OPF; + } + break; + case 32: /* ADD */ + { + // + // ADD - Add Word + // + BEGIN_OPF(ADD, 0, 0x20); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rs] + GPR[rt]; + bool ep = ((~(GPR[rs] ^ GPR[rt])) & (GPR[rs] ^ result)) & 0x80000000; + + DO_LDS(); + + if(MDFN_UNLIKELY(ep)) + { + new_PC = Exception(EXCEPTION_OV, PC, new_PC_mask); + new_PC_mask = 0; + } + else + GPR[rd] = result; + + END_OPF; + } + break; + case 33: /* ADDU */ + { + // + // ADDU - Add Unsigned Word + // + BEGIN_OPF(ADDU, 0, 0x21); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rs] + GPR[rt]; + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + } + break; + case 34: /* SUB */ + { + // + // SUB - Subtract Word + // + BEGIN_OPF(SUB, 0, 0x22); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rs] - GPR[rt]; + bool ep = (((GPR[rs] ^ GPR[rt])) & (GPR[rs] ^ result)) & 0x80000000; + + DO_LDS(); + + if(MDFN_UNLIKELY(ep)) + { + new_PC = Exception(EXCEPTION_OV, PC, new_PC_mask); + new_PC_mask = 0; + } + else + GPR[rd] = result; + + END_OPF; + } + break; + case 35: /* SUBU */ + { + // + // SUBU - Subtract Unsigned Word + // + BEGIN_OPF(SUBU, 0, 0x23); // SUBU + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rs] - GPR[rt]; + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + } + break; + case 36: /* AND */ + { + // + // AND - And + // + BEGIN_OPF(AND, 0, 0x24); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rs] & GPR[rt]; + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + } + break; + + case 37: /* OR */ + { + // + // OR - OR + // + BEGIN_OPF(OR, 0, 0x25); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rs] | GPR[rt]; + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + } + break; + case 38: /* XOR */ + { + // + // XOR + // + BEGIN_OPF(XOR, 0, 0x26); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rs] ^ GPR[rt]; + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + } + break; + case 39: /* NOR */ + { + // + // NOR - NOR + // + BEGIN_OPF(NOR, 0, 0x27); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = ~(GPR[rs] | GPR[rt]); + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + } + break; + case 42: /* SLT */ + { + // + // SLT - Set on Less Than + // + BEGIN_OPF(SLT, 0, 0x2A); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = (bool)((int32)GPR[rs] < (int32)GPR[rt]); + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + } + break; + case 43: /* SLTU */ + { + // + // SLTU - Set on Less Than, Unsigned + // + BEGIN_OPF(SLTU, 0, 0x2B); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = (bool)(GPR[rs] < GPR[rt]); + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + } + break; + case 65: /* BCOND */ + { + // Bah, why does MIPS encoding have to be funky like this. :( + // Handles BGEZ, BGEZAL, BLTZ, BLTZAL + BEGIN_OPF(BCOND, 0x01, 0); + const uint32_t tv = GPR[(instr >> 21) & 0x1F]; + uint32_t riv = (instr >> 16) & 0x1F; + int32_t immediate = (int16)(instr & 0xFFFF); + bool result = (int32)(tv ^ (riv << 31)) < 0; + + GPR_DEPRES_BEGIN + GPR_DEP((instr >> 21) & 0x1F); + + if(riv & 0x10) + GPR_RES(31); + + GPR_DEPRES_END + + + DO_LDS(); + + if(riv & 0x10) // Unconditional link reg setting. + GPR[31] = PC + 8; + + if(result) + { + DO_BRANCH((immediate << 2), ~0U); + } + + END_OPF; + } + break; + case 66: /* JUMP */ + { + // + // J - Jump + // + BEGIN_OPF(J, 0x02, 0); + JTYPE; + + DO_LDS(); + + DO_BRANCH(target << 2, 0xF0000000); + END_OPF; + } + break; + case 67: /* JAL */ + { + // + // JAL - Jump and Link + // + BEGIN_OPF(JAL, 0x03, 0); + JTYPE; + + //GPR_DEPRES_BEGIN + GPR_RES(31); + //GPR_DEPRES_END + + DO_LDS(); + + GPR[31] = PC + 8; + + DO_BRANCH(target << 2, 0xF0000000); + END_OPF; + } + break; + case 68: /* BEQ */ + { + // + // BEQ - Branch on Equal + // + BEGIN_OPF(BEQ, 0x04, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + bool result = (GPR[rs] == GPR[rt]); + + DO_LDS(); + + if(result) + { + DO_BRANCH((immediate << 2), ~0U); + } + END_OPF; + } + break; + case 69: /* BNE */ + { + // + // BNE - Branch on Not Equal + // + BEGIN_OPF(BNE, 0x05, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + bool result = GPR[rs] != GPR[rt]; + + DO_LDS(); + + if(result) + { + DO_BRANCH((immediate << 2), ~0U); + } + + END_OPF; + } + break; + case 70: /* BLEZ */ + { + // + // BLEZ - Branch on Less Than or Equal to Zero + // + BEGIN_OPF(BLEZ, 0x06, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEPRES_END + + bool result = (int32)GPR[rs] <= 0; + + DO_LDS(); + + if(result) + { + DO_BRANCH((immediate << 2), ~0U); + } + + END_OPF; + } + break; + case 71: /* BGTZ */ + { + // + // BGTZ - Branch on Greater than Zero + // + BEGIN_OPF(BGTZ, 0x07, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEPRES_END + + bool result = (int32)GPR[rs] > 0; + + DO_LDS(); + + if(result) + { + DO_BRANCH((immediate << 2), ~0U); + } + END_OPF; + } + break; + case 72: /* ADDI */ + { + // + // ADDI - Add Immediate Word + // + BEGIN_OPF(ADDI, 0x08, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_RES(rt); + GPR_DEPRES_END + + uint32_t result = GPR[rs] + immediate; + bool ep = ((~(GPR[rs] ^ immediate)) & (GPR[rs] ^ result)) & 0x80000000; + + DO_LDS(); + + if(MDFN_UNLIKELY(ep)) + { + new_PC = Exception(EXCEPTION_OV, PC, new_PC_mask); + new_PC_mask = 0; + } + else + GPR[rt] = result; + + END_OPF; + } + break; + case 73: /* ADDIU */ + { + // + // ADDIU - Add Immediate Unsigned Word + // + BEGIN_OPF(ADDIU, 0x09, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_RES(rt); + GPR_DEPRES_END + + uint32_t result = GPR[rs] + immediate; + + DO_LDS(); + + GPR[rt] = result; + + END_OPF; + } + break; + case 74: /* SLTI */ + { + // + // SLTI - Set on Less Than Immediate + // + BEGIN_OPF(SLTI, 0x0A, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_RES(rt); + GPR_DEPRES_END + + uint32_t result = (bool)((int32)GPR[rs] < immediate); + + DO_LDS(); + + GPR[rt] = result; + + END_OPF; + } + break; + case 75: /* SLTIU */ + { + // + // SLTIU - Set on Less Than Immediate, Unsigned + // + BEGIN_OPF(SLTIU, 0x0B, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_RES(rt); + GPR_DEPRES_END + + uint32_t result = (bool)(GPR[rs] < (uint32)immediate); + + DO_LDS(); + + GPR[rt] = result; + + END_OPF; + } + break; + case 76: /* ANDI */ + { + // + // ANDI - And Immediate + // + BEGIN_OPF(ANDI, 0x0C, 0); + ITYPE_ZE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_RES(rt); + GPR_DEPRES_END + + uint32_t result = GPR[rs] & immediate; + + DO_LDS(); + + GPR[rt] = result; + + END_OPF; + } + break; + case 77: /* ORI */ + { + // + // ORI - OR Immediate + // + BEGIN_OPF(ORI, 0x0D, 0); + ITYPE_ZE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_RES(rt); + GPR_DEPRES_END + + uint32_t result = GPR[rs] | immediate; + + DO_LDS(); + + GPR[rt] = result; + + END_OPF; + } + break; + case 78: /* XORI */ + { + // + // XORI - Exclusive OR Immediate + // + BEGIN_OPF(XORI, 0x0E, 0); + ITYPE_ZE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_RES(rt); + GPR_DEPRES_END + + uint32_t result = GPR[rs] ^ immediate; + + DO_LDS(); + + GPR[rt] = result; + END_OPF; + } + break; + case 79: /* LUI */ + { + // + // LUI - Load Upper Immediate + // + BEGIN_OPF(LUI, 0x0F, 0); + ITYPE_ZE; // Actually, probably would be sign-extending...if we were emulating a 64-bit MIPS chip :b + + GPR_DEPRES_BEGIN + GPR_RES(rt); + GPR_DEPRES_END + + DO_LDS(); + + GPR[rt] = immediate << 16; + + END_OPF; + } + break; + case 80: /* COP0 */ + { + // Cop "instructions": CFCz(no CP0), COPz, CTCz(no CP0), LWCz(no CP0), MFCz, MTCz, SWCz(no CP0) + // + // COP0 instructions + BEGIN_OPF(COP0, 0x10, 0); + uint32_t sub_op = (instr >> 21) & 0x1F; + + if(sub_op & 0x10) + sub_op = 0x10 + (instr & 0x3F); + + //printf("COP0 thing: %02x\n", sub_op); + switch(sub_op) + { + default: + DO_LDS(); + break; + + case 0x00: // MFC0 - Move from Coprocessor + { + uint32_t rt = (instr >> 16) & 0x1F; + uint32_t rd = (instr >> 11) & 0x1F; + + //printf("MFC0: rt=%d <- rd=%d(%08x)\n", rt, rd, CP0.Regs[rd]); + DO_LDS(); + + LDAbsorb = 0; + LDWhich = rt; + LDValue = CP0.Regs[rd]; + } + break; + + case 0x04: // MTC0 - Move to Coprocessor + { + uint32_t rt = (instr >> 16) & 0x1F; + uint32_t rd = (instr >> 11) & 0x1F; + uint32_t val = GPR[rt]; + + if(rd != CP0REG_PRID && rd != CP0REG_CAUSE && rd != CP0REG_SR && val) + { + PSX_WARNING("[CPU] Unimplemented MTC0: rt=%d(%08x) -> rd=%d", rt, GPR[rt], rd); + } + + switch(rd) + { + case CP0REG_BPC: + CP0.BPC = val; + break; + + case CP0REG_BDA: + CP0.BDA = val; + break; + + case CP0REG_TAR: + CP0.TAR = val; + break; + + case CP0REG_DCIC: + CP0.DCIC = val & 0xFF80003F; + break; + + case CP0REG_BDAM: + CP0.BDAM = val; + break; + + case CP0REG_BPCM: + CP0.BPCM = val; + break; + + case CP0REG_CAUSE: + CP0.CAUSE &= ~(0x3 << 8); + CP0.CAUSE |= val & (0x3 << 8); + RecalcIPCache(); + break; + + case CP0REG_SR: + if((CP0.SR ^ val) & 0x10000) + PSX_DBG(PSX_DBG_SPARSE, "[CPU] IsC %u->%u\n", (bool)(CP0.SR & (1U << 16)), (bool)(val & (1U << 16))); + + CP0.SR = val & ~( (0x3 << 26) | (0x3 << 23) | (0x3 << 6)); + RecalcIPCache(); + break; + } + } + DO_LDS(); + break; + + case (0x10 + 0x10): // RFE + // "Pop" + DO_LDS(); + CP0.SR = (CP0.SR & ~0x0F) | ((CP0.SR >> 2) & 0x0F); + RecalcIPCache(); + break; + } + END_OPF; + } + break; + case 81: /* COP1 */ + { + // + // COP1 + // + BEGIN_OPF(COP1, 0x11, 0); + DO_LDS(); + new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + } + break; + case 82: /* COP2 */ + case 210: + { + // + // COP2 + // + BEGIN_OPF(COP2, 0x12, 0); + uint32_t sub_op = (instr >> 21) & 0x1F; + + switch(sub_op) + { + default: + DO_LDS(); + break; + + case 0x00: // MFC2 - Move from Coprocessor + { + uint32_t rt = (instr >> 16) & 0x1F; + uint32_t rd = (instr >> 11) & 0x1F; + + DO_LDS(); + + if(timestamp < gte_ts_done) + { + LDAbsorb = gte_ts_done - timestamp; + timestamp = gte_ts_done; + } + else + LDAbsorb = 0; + + LDWhich = rt; + LDValue = GTE_ReadDR(rd); + } + break; + + case 0x04: // MTC2 - Move to Coprocessor + { + uint32_t rt = (instr >> 16) & 0x1F; + uint32_t rd = (instr >> 11) & 0x1F; + uint32_t val = GPR[rt]; + + if(timestamp < gte_ts_done) + timestamp = gte_ts_done; + + //printf("GTE WriteDR: %d %d\n", rd, val); + GTE_WriteDR(rd, val); + DO_LDS(); + } + break; + + case 0x02: // CFC2 + { + uint32_t rt = (instr >> 16) & 0x1F; + uint32_t rd = (instr >> 11) & 0x1F; + + DO_LDS(); + + if(timestamp < gte_ts_done) + { + LDAbsorb = gte_ts_done - timestamp; + timestamp = gte_ts_done; + } + else + LDAbsorb = 0; + + LDWhich = rt; + LDValue = GTE_ReadCR(rd); + + //printf("GTE ReadCR: %d %d\n", rd, GPR[rt]); + } + break; + + case 0x06: // CTC2 + { + uint32_t rt = (instr >> 16) & 0x1F; + uint32_t rd = (instr >> 11) & 0x1F; + uint32_t val = GPR[rt]; + + //printf("GTE WriteCR: %d %d\n", rd, val); + + if(timestamp < gte_ts_done) + timestamp = gte_ts_done; + + GTE_WriteCR(rd, val); + DO_LDS(); + } + break; + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F: + //printf("%08x\n", PC); + if(timestamp < gte_ts_done) + timestamp = gte_ts_done; + gte_ts_done = timestamp + GTE_Instruction(instr); + DO_LDS(); + break; + } + END_OPF; + } + break; + case 83: /* COP3 */ + { + // + // COP3 + // + BEGIN_OPF(COP3, 0x13, 0); + DO_LDS(); + new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + } + break; + case 96: /* LB */ + { + // + // LB - Load Byte + // + BEGIN_OPF(LB, 0x20, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + + DO_LDS(); + + LDWhich = rt; + LDValue = (int32)ReadMemory(timestamp, address); + END_OPF; + } + break; + case 97: /* LH */ + { + // + // LH - Load Halfword + // + BEGIN_OPF(LH, 0x21, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + + DO_LDS(); + + if(MDFN_UNLIKELY(address & 1)) + { + new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask); + new_PC_mask = 0; + } + else + { + LDWhich = rt; + LDValue = (int32)ReadMemory(timestamp, address); + } + END_OPF; + } + break; + case 98: /* LWL */ + { + // LWL and LWR load delay slot tomfoolery appears to apply even to MFC0! (and probably MFCn and CFCn as well, though they weren't explicitly tested) + + // + // LWL - Load Word Left + // + BEGIN_OPF(LWL, 0x22, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + //GPR_DEP(rt); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + uint32_t v = GPR[rt]; + + if(LDWhich == rt) + { + v = LDValue; + ReadFudge = 0; + } + else + { + DO_LDS(); + } + + LDWhich = rt; + switch(address & 0x3) + { + case 0: LDValue = (v & ~(0xFF << 24)) | (ReadMemory(timestamp, address & ~3) << 24); + break; + + case 1: LDValue = (v & ~(0xFFFF << 16)) | (ReadMemory(timestamp, address & ~3) << 16); + break; + + case 2: LDValue = (v & ~(0xFFFFFF << 8)) | (ReadMemory(timestamp, address & ~3, true) << 8); + break; + + case 3: LDValue = (v & ~(0xFFFFFFFF << 0)) | (ReadMemory(timestamp, address & ~3) << 0); + break; + } + END_OPF; + } + break; + case 99: /* LW */ + { + // + // LW - Load Word + // + BEGIN_OPF(LW, 0x23, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + + DO_LDS(); + + if(MDFN_UNLIKELY(address & 3)) + { + new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask); + new_PC_mask = 0; + } + else + { + LDWhich = rt; + LDValue = ReadMemory(timestamp, address); + } + END_OPF; + } + break; + case 100: /* LBU */ + { + // + // LBU - Load Byte Unsigned + // + BEGIN_OPF(LBU, 0x24, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + + DO_LDS(); + + LDWhich = rt; + LDValue = ReadMemory(timestamp, address); + END_OPF; + } + break; + case 101: /* LHU */ + { + // + // LHU - Load Halfword Unsigned + // + BEGIN_OPF(LHU, 0x25, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + + DO_LDS(); + + if(MDFN_UNLIKELY(address & 1)) + { + new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask); + new_PC_mask = 0; + } + else + { + LDWhich = rt; + LDValue = ReadMemory(timestamp, address); + } + END_OPF; + } + break; + case 102: /* LWR */ + { + // + // LWR - Load Word Right + // + BEGIN_OPF(LWR, 0x26, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + //GPR_DEP(rt); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + uint32_t v = GPR[rt]; + + if(LDWhich == rt) + { + v = LDValue; + ReadFudge = 0; + } + else + { + DO_LDS(); + } + + LDWhich = rt; + switch(address & 0x3) + { + case 0: + LDValue = (v & ~(0xFFFFFFFF)) | ReadMemory(timestamp, address); + break; + case 1: + LDValue = (v & ~(0xFFFFFF)) | ReadMemory(timestamp, address, true); + break; + case 2: + LDValue = (v & ~(0xFFFF)) | ReadMemory(timestamp, address); + break; + + case 3: + LDValue = (v & ~(0xFF)) | ReadMemory(timestamp, address); + break; + } + END_OPF; + } + break; + case 104: /* SB */ + { + // + // SB - Store Byte + // + BEGIN_OPF(SB, 0x28, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + + WriteMemory(timestamp, address, GPR[rt]); + + DO_LDS(); + END_OPF; + } + break; + case 105: /* SH */ + { + // + // SH - Store Halfword + // + BEGIN_OPF(SH, 0x29, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + + if(MDFN_UNLIKELY(address & 0x1)) + { + new_PC = Exception(EXCEPTION_ADES, PC, new_PC_mask); + new_PC_mask = 0; + } + else + WriteMemory(timestamp, address, GPR[rt]); + + DO_LDS(); + END_OPF; + } + break; + case 106: /* SWL */ + { + // + // SWL - Store Word Left + // + BEGIN_OPF(SWL, 0x2A, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + + switch(address & 0x3) + { + case 0: WriteMemory(timestamp, address & ~3, GPR[rt] >> 24); + break; + + case 1: WriteMemory(timestamp, address & ~3, GPR[rt] >> 16); + break; + + case 2: WriteMemory(timestamp, address & ~3, GPR[rt] >> 8, true); + break; + + case 3: WriteMemory(timestamp, address & ~3, GPR[rt] >> 0); + break; + } + DO_LDS(); + + END_OPF; + } + break; + case 107: /* SW */ + { + // + // SW - Store Word + // + BEGIN_OPF(SW, 0x2B, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + + if(MDFN_UNLIKELY(address & 0x3)) + { + new_PC = Exception(EXCEPTION_ADES, PC, new_PC_mask); + new_PC_mask = 0; + } + else + WriteMemory(timestamp, address, GPR[rt]); + + DO_LDS(); + END_OPF; + } + break; + case 110: /* SWR */ + { + // + // SWR - Store Word Right + // + BEGIN_OPF(SWR, 0x2E, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + + switch(address & 0x3) + { + case 0: + WriteMemory(timestamp, address, GPR[rt]); + break; + + case 1: + WriteMemory(timestamp, address, GPR[rt], true); + break; + + case 2: + WriteMemory(timestamp, address, GPR[rt]); + break; + + case 3: + WriteMemory(timestamp, address, GPR[rt]); + break; + } + + DO_LDS(); + + END_OPF; + } + break; + case 112: /* LWC0 */ + { + // + // LWC0 + // + BEGIN_OPF(LWC0, 0x30, 0); + DO_LDS(); + new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + } + break; + case 113: /* LWC1 */ + { + // + // LWC1 + // + BEGIN_OPF(LWC1, 0x31, 0); + DO_LDS(); + new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + } + break; + case 114: /* LWC2 */ + { + // + // LWC2 + // + BEGIN_OPF(LWC2, 0x32, 0); + ITYPE; + uint32_t address = GPR[rs] + immediate; + + DO_LDS(); + + if(MDFN_UNLIKELY(address & 3)) + { + new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask); + new_PC_mask = 0; + } + else + { + if(timestamp < gte_ts_done) + timestamp = gte_ts_done; + + GTE_WriteDR(rt, ReadMemory(timestamp, address, false, true)); + } + // GTE stuff here + END_OPF; + } + break; + case 115: /* LWC3 */ + { + // + // LWC3 + // + BEGIN_OPF(LWC3, 0x33, 0); + DO_LDS(); + new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + } + break; + case 120: /* SWC0 */ + { + // + // SWC0 + // + BEGIN_OPF(SWC0, 0x38, 0); + DO_LDS(); + new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + } + break; + case 121: /* SWC1 */ + { + // + // SWC1 + // + BEGIN_OPF(SWC1, 0x39, 0); + DO_LDS(); + new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + } + break; + case 122: /* SWC2 */ + { + // + // SWC2 + // + BEGIN_OPF(SWC2, 0x3A, 0); + ITYPE; + uint32_t address = GPR[rs] + immediate; + + if(MDFN_UNLIKELY(address & 0x3)) + { + new_PC = Exception(EXCEPTION_ADES, PC, new_PC_mask); + new_PC_mask = 0; + } + else + { + if(timestamp < gte_ts_done) + timestamp = gte_ts_done; + + WriteMemory(timestamp, address, GTE_ReadDR(rt)); + } + DO_LDS(); + END_OPF; + } + break; + case 123: /* SWC3 */ + { + // + // SWC3 + /// + BEGIN_OPF(SWC3, 0x3B, 0); + DO_LDS(); + new_PC = Exception(EXCEPTION_RI, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + } + break; + case 128: + case 129: + case 130: + case 131: + case 132: + case 133: + case 134: + case 135: + case 136: + case 137: + case 138: + case 139: + case 140: + case 141: + case 142: + case 143: + case 144: + case 145: + case 146: + case 147: + case 148: + case 149: + case 150: + case 151: + case 152: + case 153: + case 154: + case 155: + case 156: + case 157: + case 158: + case 159: + case 160: + case 161: + case 162: + case 163: + case 164: + case 165: + case 166: + case 167: + case 168: + case 169: + case 170: + case 171: + case 172: + case 173: + case 174: + case 175: + case 176: + case 177: + case 178: + case 179: + case 180: + case 181: + case 182: + case 183: + case 184: + case 185: + case 186: + case 187: + case 188: + case 189: + case 190: + case 191: /* INTERRUPT */ + case 193: + case 194: + case 195: + case 196: + case 197: + case 198: + case 199: + case 200: + case 201: + case 202: + case 203: + case 204: + case 205: + case 206: + case 207: + case 208: + case 209: + case 211: + case 212: + case 213: + case 214: + case 215: + case 216: + case 217: + case 218: + case 219: + case 220: + case 221: + case 222: + case 223: + case 224: + case 225: + case 226: + case 227: + case 228: + case 229: + case 230: + case 231: + case 232: + case 233: + case 234: + case 235: + case 236: + case 237: + case 238: + case 239: + case 240: + case 241: + case 242: + case 243: + case 244: + case 245: + case 246: + case 247: + case 248: + case 249: + case 250: + case 251: + case 252: + case 253: + case 254: + case 256: + { + // + // Mednafen special instruction + // + BEGIN_OPF(INTERRUPT, 0x3F, 0); + if(Halted) + { + goto SkipNPCStuff; + } + else + { + DO_LDS(); + + new_PC = Exception(EXCEPTION_INT, PC, new_PC_mask); + new_PC_mask = 0; + } + END_OPF; + } + break; + default: + break; + } + diff --git a/psx/octoshock/psx/cpu_computedgoto.c b/psx/octoshock/psx/cpu_computedgoto.c new file mode 100644 index 0000000000..24d2122edf --- /dev/null +++ b/psx/octoshock/psx/cpu_computedgoto.c @@ -0,0 +1,1624 @@ + static const void *const op_goto_table[256] = + { + &&op_SLL, &&op_ILL, &&op_SRL, &&op_SRA, &&op_SLLV, &&op_ILL, &&op_SRLV, &&op_SRAV, + &&op_JR, &&op_JALR, &&op_ILL, &&op_ILL, &&op_SYSCALL, &&op_BREAK, &&op_ILL, &&op_ILL, + &&op_MFHI, &&op_MTHI, &&op_MFLO, &&op_MTLO, &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, + &&op_MULT, &&op_MULTU, &&op_DIV, &&op_DIVU, &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, + &&op_ADD, &&op_ADDU, &&op_SUB, &&op_SUBU, &&op_AND, &&op_OR, &&op_XOR, &&op_NOR, + &&op_ILL, &&op_ILL, &&op_SLT, &&op_SLTU, &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, + &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, + &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, + + NULL, &&op_BCOND, &&op_J, &&op_JAL, &&op_BEQ, &&op_BNE, &&op_BLEZ, &&op_BGTZ, + &&op_ADDI, &&op_ADDIU, &&op_SLTI, &&op_SLTIU, &&op_ANDI, &&op_ORI, &&op_XORI, &&op_LUI, + &&op_COP0, &&op_COP1, &&op_COP2, &&op_COP3, &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, + &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, + &&op_LB, &&op_LH, &&op_LWL, &&op_LW, &&op_LBU, &&op_LHU, &&op_LWR, &&op_ILL, + &&op_SB, &&op_SH, &&op_SWL, &&op_SW, &&op_ILL, &&op_ILL, &&op_SWR, &&op_ILL, + &&op_LWC0, &&op_LWC1, &&op_LWC2, &&op_LWC3, &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, + &&op_SWC0, &&op_SWC1, &&op_SWC2, &&op_SWC3, &&op_ILL, &&op_ILL, &&op_ILL, &&op_ILL, + + // Interrupt portion of this table is constructed so that an interrupt won't be taken when the PC is pointing to a GTE instruction, + // to avoid problems caused by pipeline vs coprocessor nuances that aren't emulated. + &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, + &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, + &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, + &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, + &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, + &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, + &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, + &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, + + NULL, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, + &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, + &&op_INTERRUPT, &&op_INTERRUPT, &&op_COP2, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, + &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, + &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, + &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, + &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, + &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, &&op_INTERRUPT, + }; + + goto *op_goto_table[opf]; + + { + BEGIN_OPF(ILL, 0, 0); + PSX_WARNING("[CPU] Unknown instruction @%08x = %08x, op=%02x, funct=%02x", PC, instr, instr >> 26, (instr & 0x3F)); + DO_LDS(); + new_PC = Exception(EXCEPTION_RI, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + + // + // ADD - Add Word + // + BEGIN_OPF(ADD, 0, 0x20); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rs] + GPR[rt]; + bool ep = ((~(GPR[rs] ^ GPR[rt])) & (GPR[rs] ^ result)) & 0x80000000; + + DO_LDS(); + + if(MDFN_UNLIKELY(ep)) + { + new_PC = Exception(EXCEPTION_OV, PC, new_PC_mask); + new_PC_mask = 0; + } + else + GPR[rd] = result; + + END_OPF; + + // + // ADDI - Add Immediate Word + // + BEGIN_OPF(ADDI, 0x08, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_RES(rt); + GPR_DEPRES_END + + uint32_t result = GPR[rs] + immediate; + bool ep = ((~(GPR[rs] ^ immediate)) & (GPR[rs] ^ result)) & 0x80000000; + + DO_LDS(); + + if(MDFN_UNLIKELY(ep)) + { + new_PC = Exception(EXCEPTION_OV, PC, new_PC_mask); + new_PC_mask = 0; + } + else + GPR[rt] = result; + + END_OPF; + + // + // ADDIU - Add Immediate Unsigned Word + // + BEGIN_OPF(ADDIU, 0x09, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_RES(rt); + GPR_DEPRES_END + + uint32_t result = GPR[rs] + immediate; + + DO_LDS(); + + GPR[rt] = result; + + END_OPF; + + // + // ADDU - Add Unsigned Word + // + BEGIN_OPF(ADDU, 0, 0x21); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rs] + GPR[rt]; + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + + // + // AND - And + // + BEGIN_OPF(AND, 0, 0x24); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rs] & GPR[rt]; + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + + // + // ANDI - And Immediate + // + BEGIN_OPF(ANDI, 0x0C, 0); + ITYPE_ZE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_RES(rt); + GPR_DEPRES_END + + uint32_t result = GPR[rs] & immediate; + + DO_LDS(); + + GPR[rt] = result; + + END_OPF; + + // + // BEQ - Branch on Equal + // + BEGIN_OPF(BEQ, 0x04, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + bool result = (GPR[rs] == GPR[rt]); + + DO_LDS(); + + if(result) + { + DO_BRANCH((immediate << 2), ~0U); + } + END_OPF; + + // Bah, why does MIPS encoding have to be funky like this. :( + // Handles BGEZ, BGEZAL, BLTZ, BLTZAL + BEGIN_OPF(BCOND, 0x01, 0); + const uint32_t tv = GPR[(instr >> 21) & 0x1F]; + uint32_t riv = (instr >> 16) & 0x1F; + int32_t immediate = (int16)(instr & 0xFFFF); + bool result = (int32)(tv ^ (riv << 31)) < 0; + + GPR_DEPRES_BEGIN + GPR_DEP((instr >> 21) & 0x1F); + + if(riv & 0x10) + GPR_RES(31); + + GPR_DEPRES_END + + + DO_LDS(); + + if(riv & 0x10) // Unconditional link reg setting. + GPR[31] = PC + 8; + + if(result) + { + DO_BRANCH((immediate << 2), ~0U); + } + + END_OPF; + + + // + // BGTZ - Branch on Greater than Zero + // + BEGIN_OPF(BGTZ, 0x07, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEPRES_END + + bool result = (int32)GPR[rs] > 0; + + DO_LDS(); + + if(result) + { + DO_BRANCH((immediate << 2), ~0U); + } + END_OPF; + + // + // BLEZ - Branch on Less Than or Equal to Zero + // + BEGIN_OPF(BLEZ, 0x06, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEPRES_END + + bool result = (int32)GPR[rs] <= 0; + + DO_LDS(); + + if(result) + { + DO_BRANCH((immediate << 2), ~0U); + } + + END_OPF; + + // + // BNE - Branch on Not Equal + // + BEGIN_OPF(BNE, 0x05, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + bool result = GPR[rs] != GPR[rt]; + + DO_LDS(); + + if(result) + { + DO_BRANCH((immediate << 2), ~0U); + } + + END_OPF; + + // + // BREAK - Breakpoint + // + BEGIN_OPF(BREAK, 0, 0x0D); + PSX_WARNING("[CPU] BREAK BREAK BREAK BREAK DAAANCE -- PC=0x%08x", PC); + + DO_LDS(); + new_PC = Exception(EXCEPTION_BP, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + + // Cop "instructions": CFCz(no CP0), COPz, CTCz(no CP0), LWCz(no CP0), MFCz, MTCz, SWCz(no CP0) + // + // COP0 instructions + BEGIN_OPF(COP0, 0x10, 0); + uint32_t sub_op = (instr >> 21) & 0x1F; + + if(sub_op & 0x10) + sub_op = 0x10 + (instr & 0x3F); + + //printf("COP0 thing: %02x\n", sub_op); + switch(sub_op) + { + default: + DO_LDS(); + break; + + case 0x00: // MFC0 - Move from Coprocessor + { + uint32_t rt = (instr >> 16) & 0x1F; + uint32_t rd = (instr >> 11) & 0x1F; + + //printf("MFC0: rt=%d <- rd=%d(%08x)\n", rt, rd, CP0.Regs[rd]); + DO_LDS(); + + LDAbsorb = 0; + LDWhich = rt; + LDValue = CP0.Regs[rd]; + } + break; + + case 0x04: // MTC0 - Move to Coprocessor + { + uint32_t rt = (instr >> 16) & 0x1F; + uint32_t rd = (instr >> 11) & 0x1F; + uint32_t val = GPR[rt]; + + if(rd != CP0REG_PRID && rd != CP0REG_CAUSE && rd != CP0REG_SR && val) + { + PSX_WARNING("[CPU] Unimplemented MTC0: rt=%d(%08x) -> rd=%d", rt, GPR[rt], rd); + } + + switch(rd) + { + case CP0REG_BPC: + CP0.BPC = val; + break; + + case CP0REG_BDA: + CP0.BDA = val; + break; + + case CP0REG_TAR: + CP0.TAR = val; + break; + + case CP0REG_DCIC: + CP0.DCIC = val & 0xFF80003F; + break; + + case CP0REG_BDAM: + CP0.BDAM = val; + break; + + case CP0REG_BPCM: + CP0.BPCM = val; + break; + + case CP0REG_CAUSE: + CP0.CAUSE &= ~(0x3 << 8); + CP0.CAUSE |= val & (0x3 << 8); + RecalcIPCache(); + break; + + case CP0REG_SR: + if((CP0.SR ^ val) & 0x10000) + PSX_DBG(PSX_DBG_SPARSE, "[CPU] IsC %u->%u\n", (bool)(CP0.SR & (1U << 16)), (bool)(val & (1U << 16))); + + CP0.SR = val & ~( (0x3 << 26) | (0x3 << 23) | (0x3 << 6)); + RecalcIPCache(); + break; + } + } + DO_LDS(); + break; + + case (0x10 + 0x10): // RFE + // "Pop" + DO_LDS(); + CP0.SR = (CP0.SR & ~0x0F) | ((CP0.SR >> 2) & 0x0F); + RecalcIPCache(); + break; + } + END_OPF; + + // + // COP1 + // + BEGIN_OPF(COP1, 0x11, 0); + DO_LDS(); + new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + + // + // COP2 + // + BEGIN_OPF(COP2, 0x12, 0); + uint32_t sub_op = (instr >> 21) & 0x1F; + + switch(sub_op) + { + default: + DO_LDS(); + break; + + case 0x00: // MFC2 - Move from Coprocessor + { + uint32_t rt = (instr >> 16) & 0x1F; + uint32_t rd = (instr >> 11) & 0x1F; + + DO_LDS(); + + if(timestamp < gte_ts_done) + { + LDAbsorb = gte_ts_done - timestamp; + timestamp = gte_ts_done; + } + else + LDAbsorb = 0; + + LDWhich = rt; + LDValue = GTE_ReadDR(rd); + } + break; + + case 0x04: // MTC2 - Move to Coprocessor + { + uint32_t rt = (instr >> 16) & 0x1F; + uint32_t rd = (instr >> 11) & 0x1F; + uint32_t val = GPR[rt]; + + if(timestamp < gte_ts_done) + timestamp = gte_ts_done; + + //printf("GTE WriteDR: %d %d\n", rd, val); + GTE_WriteDR(rd, val); + DO_LDS(); + } + break; + + case 0x02: // CFC2 + { + uint32_t rt = (instr >> 16) & 0x1F; + uint32_t rd = (instr >> 11) & 0x1F; + + DO_LDS(); + + if(timestamp < gte_ts_done) + { + LDAbsorb = gte_ts_done - timestamp; + timestamp = gte_ts_done; + } + else + LDAbsorb = 0; + + LDWhich = rt; + LDValue = GTE_ReadCR(rd); + + //printf("GTE ReadCR: %d %d\n", rd, GPR[rt]); + } + break; + + case 0x06: // CTC2 + { + uint32_t rt = (instr >> 16) & 0x1F; + uint32_t rd = (instr >> 11) & 0x1F; + uint32_t val = GPR[rt]; + + //printf("GTE WriteCR: %d %d\n", rd, val); + + if(timestamp < gte_ts_done) + timestamp = gte_ts_done; + + GTE_WriteCR(rd, val); + DO_LDS(); + } + break; + + case 0x10 ... 0x1F: + //printf("%08x\n", PC); + if(timestamp < gte_ts_done) + timestamp = gte_ts_done; + gte_ts_done = timestamp + GTE_Instruction(instr); + DO_LDS(); + break; + } + END_OPF; + + // + // COP3 + // + BEGIN_OPF(COP3, 0x13, 0); + DO_LDS(); + new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + + // + // LWC0 + // + BEGIN_OPF(LWC0, 0x30, 0); + DO_LDS(); + new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + + // + // LWC1 + // + BEGIN_OPF(LWC1, 0x31, 0); + DO_LDS(); + new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + + // + // LWC2 + // + BEGIN_OPF(LWC2, 0x32, 0); + ITYPE; + uint32_t address = GPR[rs] + immediate; + + DO_LDS(); + + if(MDFN_UNLIKELY(address & 3)) + { + new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask); + new_PC_mask = 0; + } + else + { + if(timestamp < gte_ts_done) + timestamp = gte_ts_done; + + GTE_WriteDR(rt, ReadMemory(timestamp, address, false, true)); + } + // GTE stuff here + END_OPF; + + // + // LWC3 + // + BEGIN_OPF(LWC3, 0x33, 0); + DO_LDS(); + new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + + + // + // SWC0 + // + BEGIN_OPF(SWC0, 0x38, 0); + DO_LDS(); + new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + + // + // SWC1 + // + BEGIN_OPF(SWC1, 0x39, 0); + DO_LDS(); + new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + + // + // SWC2 + // + BEGIN_OPF(SWC2, 0x3A, 0); + ITYPE; + uint32_t address = GPR[rs] + immediate; + + if(MDFN_UNLIKELY(address & 0x3)) + { + new_PC = Exception(EXCEPTION_ADES, PC, new_PC_mask); + new_PC_mask = 0; + } + else + { + if(timestamp < gte_ts_done) + timestamp = gte_ts_done; + + WriteMemory(timestamp, address, GTE_ReadDR(rt)); + } + DO_LDS(); + END_OPF; + + // + // SWC3 + /// + BEGIN_OPF(SWC3, 0x3B, 0); + DO_LDS(); + new_PC = Exception(EXCEPTION_RI, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + + + // + // DIV - Divide Word + // + BEGIN_OPF(DIV, 0, 0x1A); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + if(!GPR[rt]) + { + if(GPR[rs] & 0x80000000) + LO = 1; + else + LO = 0xFFFFFFFF; + + HI = GPR[rs]; + } + else if(GPR[rs] == 0x80000000 && GPR[rt] == 0xFFFFFFFF) + { + LO = 0x80000000; + HI = 0; + } + else + { + LO = (int32)GPR[rs] / (int32)GPR[rt]; + HI = (int32)GPR[rs] % (int32)GPR[rt]; + } + muldiv_ts_done = timestamp + 37; + + DO_LDS(); + + END_OPF; + + + // + // DIVU - Divide Unsigned Word + // + BEGIN_OPF(DIVU, 0, 0x1B); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + if(!GPR[rt]) + { + LO = 0xFFFFFFFF; + HI = GPR[rs]; + } + else + { + LO = GPR[rs] / GPR[rt]; + HI = GPR[rs] % GPR[rt]; + } + muldiv_ts_done = timestamp + 37; + + DO_LDS(); + END_OPF; + + // + // J - Jump + // + BEGIN_OPF(J, 0x02, 0); + JTYPE; + + DO_LDS(); + + DO_BRANCH(target << 2, 0xF0000000); + END_OPF; + + // + // JAL - Jump and Link + // + BEGIN_OPF(JAL, 0x03, 0); + JTYPE; + + //GPR_DEPRES_BEGIN + GPR_RES(31); + //GPR_DEPRES_END + + DO_LDS(); + + GPR[31] = PC + 8; + + DO_BRANCH(target << 2, 0xF0000000); + END_OPF; + + // + // JALR - Jump and Link Register + // + BEGIN_OPF(JALR, 0, 0x09); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t tmp = GPR[rs]; + + DO_LDS(); + + GPR[rd] = PC + 8; + + DO_BRANCH(tmp, 0); + + END_OPF; + + // + // JR - Jump Register + // + BEGIN_OPF(JR, 0, 0x08); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t bt = GPR[rs]; + + DO_LDS(); + + DO_BRANCH(bt, 0); + + END_OPF; + + // + // LUI - Load Upper Immediate + // + BEGIN_OPF(LUI, 0x0F, 0); + ITYPE_ZE; // Actually, probably would be sign-extending...if we were emulating a 64-bit MIPS chip :b + + GPR_DEPRES_BEGIN + GPR_RES(rt); + GPR_DEPRES_END + + DO_LDS(); + + GPR[rt] = immediate << 16; + + END_OPF; + + // + // MFHI - Move from HI + // + BEGIN_OPF(MFHI, 0, 0x10); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_RES(rd); + GPR_DEPRES_END + + DO_LDS(); + + if(timestamp < muldiv_ts_done) + { + if(timestamp == muldiv_ts_done - 1) + muldiv_ts_done--; + else + { + do + { + if(ReadAbsorb[ReadAbsorbWhich]) + ReadAbsorb[ReadAbsorbWhich]--; + timestamp++; + } while(timestamp < muldiv_ts_done); + } + } + + GPR[rd] = HI; + + END_OPF; + + + // + // MFLO - Move from LO + // + BEGIN_OPF(MFLO, 0, 0x12); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_RES(rd); + GPR_DEPRES_END + + DO_LDS(); + + if(timestamp < muldiv_ts_done) + { + if(timestamp == muldiv_ts_done - 1) + muldiv_ts_done--; + else + { + do + { + if(ReadAbsorb[ReadAbsorbWhich]) + ReadAbsorb[ReadAbsorbWhich]--; + timestamp++; + } while(timestamp < muldiv_ts_done); + } + } + + GPR[rd] = LO; + + END_OPF; + + + // + // MTHI - Move to HI + // + BEGIN_OPF(MTHI, 0, 0x11); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEPRES_END + + HI = GPR[rs]; + + DO_LDS(); + + END_OPF; + + // + // MTLO - Move to LO + // + BEGIN_OPF(MTLO, 0, 0x13); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEPRES_END + + LO = GPR[rs]; + + DO_LDS(); + + END_OPF; + + + // + // MULT - Multiply Word + // + BEGIN_OPF(MULT, 0, 0x18); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + uint64 result; + + result = (int64)(int32)GPR[rs] * (int32)GPR[rt]; + muldiv_ts_done = timestamp + 7; + + DO_LDS(); + + LO = result; + HI = result >> 32; + + END_OPF; + + // + // MULTU - Multiply Unsigned Word + // + BEGIN_OPF(MULTU, 0, 0x19); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + uint64 result; + + result = (uint64)GPR[rs] * GPR[rt]; + muldiv_ts_done = timestamp + 7; + + DO_LDS(); + + LO = result; + HI = result >> 32; + + END_OPF; + + + // + // NOR - NOR + // + BEGIN_OPF(NOR, 0, 0x27); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = ~(GPR[rs] | GPR[rt]); + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + + // + // OR - OR + // + BEGIN_OPF(OR, 0, 0x25); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rs] | GPR[rt]; + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + + + // + // ORI - OR Immediate + // + BEGIN_OPF(ORI, 0x0D, 0); + ITYPE_ZE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_RES(rt); + GPR_DEPRES_END + + uint32_t result = GPR[rs] | immediate; + + DO_LDS(); + + GPR[rt] = result; + + END_OPF; + + + // + // SLL - Shift Word Left Logical + // + BEGIN_OPF(SLL, 0, 0x00); // SLL + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rt] << shamt; + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + + + // + // SLLV - Shift Word Left Logical Variable + // + BEGIN_OPF(SLLV, 0, 0x04); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rt] << (GPR[rs] & 0x1F); + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + + // + // SLT - Set on Less Than + // + BEGIN_OPF(SLT, 0, 0x2A); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = (bool)((int32)GPR[rs] < (int32)GPR[rt]); + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + + + // + // SLTI - Set on Less Than Immediate + // + BEGIN_OPF(SLTI, 0x0A, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_RES(rt); + GPR_DEPRES_END + + uint32_t result = (bool)((int32)GPR[rs] < immediate); + + DO_LDS(); + + GPR[rt] = result; + + END_OPF; + + + // + // SLTIU - Set on Less Than Immediate, Unsigned + // + BEGIN_OPF(SLTIU, 0x0B, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_RES(rt); + GPR_DEPRES_END + + uint32_t result = (bool)(GPR[rs] < (uint32)immediate); + + DO_LDS(); + + GPR[rt] = result; + + END_OPF; + + + // + // SLTU - Set on Less Than, Unsigned + // + BEGIN_OPF(SLTU, 0, 0x2B); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = (bool)(GPR[rs] < GPR[rt]); + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + + + // + // SRA - Shift Word Right Arithmetic + // + BEGIN_OPF(SRA, 0, 0x03); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = ((int32)GPR[rt]) >> shamt; + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + + + // + // SRAV - Shift Word Right Arithmetic Variable + // + BEGIN_OPF(SRAV, 0, 0x07); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = ((int32)GPR[rt]) >> (GPR[rs] & 0x1F); + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + + + // + // SRL - Shift Word Right Logical + // + BEGIN_OPF(SRL, 0, 0x02); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rt] >> shamt; + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + + // + // SRLV - Shift Word Right Logical Variable + // + BEGIN_OPF(SRLV, 0, 0x06); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rt] >> (GPR[rs] & 0x1F); + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + + + // + // SUB - Subtract Word + // + BEGIN_OPF(SUB, 0, 0x22); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rs] - GPR[rt]; + bool ep = (((GPR[rs] ^ GPR[rt])) & (GPR[rs] ^ result)) & 0x80000000; + + DO_LDS(); + + if(MDFN_UNLIKELY(ep)) + { + new_PC = Exception(EXCEPTION_OV, PC, new_PC_mask); + new_PC_mask = 0; + } + else + GPR[rd] = result; + + END_OPF; + + + // + // SUBU - Subtract Unsigned Word + // + BEGIN_OPF(SUBU, 0, 0x23); // SUBU + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rs] - GPR[rt]; + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + + + // + // SYSCALL + // + BEGIN_OPF(SYSCALL, 0, 0x0C); + DO_LDS(); + + new_PC = Exception(EXCEPTION_SYSCALL, PC, new_PC_mask); + new_PC_mask = 0; + END_OPF; + + + // + // XOR + // + BEGIN_OPF(XOR, 0, 0x26); + RTYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_RES(rd); + GPR_DEPRES_END + + uint32_t result = GPR[rs] ^ GPR[rt]; + + DO_LDS(); + + GPR[rd] = result; + + END_OPF; + + // + // XORI - Exclusive OR Immediate + // + BEGIN_OPF(XORI, 0x0E, 0); + ITYPE_ZE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_RES(rt); + GPR_DEPRES_END + + uint32_t result = GPR[rs] ^ immediate; + + DO_LDS(); + + GPR[rt] = result; + END_OPF; + + // + // Memory access instructions(besides the coprocessor ones) follow: + // + + // + // LB - Load Byte + // + BEGIN_OPF(LB, 0x20, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + + DO_LDS(); + + LDWhich = rt; + LDValue = (int32)ReadMemory(timestamp, address); + END_OPF; + + // + // LBU - Load Byte Unsigned + // + BEGIN_OPF(LBU, 0x24, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + + DO_LDS(); + + LDWhich = rt; + LDValue = ReadMemory(timestamp, address); + END_OPF; + + // + // LH - Load Halfword + // + BEGIN_OPF(LH, 0x21, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + + DO_LDS(); + + if(MDFN_UNLIKELY(address & 1)) + { + new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask); + new_PC_mask = 0; + } + else + { + LDWhich = rt; + LDValue = (int32)ReadMemory(timestamp, address); + } + END_OPF; + + // + // LHU - Load Halfword Unsigned + // + BEGIN_OPF(LHU, 0x25, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + + DO_LDS(); + + if(MDFN_UNLIKELY(address & 1)) + { + new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask); + new_PC_mask = 0; + } + else + { + LDWhich = rt; + LDValue = ReadMemory(timestamp, address); + } + END_OPF; + + + // + // LW - Load Word + // + BEGIN_OPF(LW, 0x23, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + + DO_LDS(); + + if(MDFN_UNLIKELY(address & 3)) + { + new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask); + new_PC_mask = 0; + } + else + { + LDWhich = rt; + LDValue = ReadMemory(timestamp, address); + } + END_OPF; + + // + // SB - Store Byte + // + BEGIN_OPF(SB, 0x28, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + + WriteMemory(timestamp, address, GPR[rt]); + + DO_LDS(); + END_OPF; + + // + // SH - Store Halfword + // + BEGIN_OPF(SH, 0x29, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + + if(MDFN_UNLIKELY(address & 0x1)) + { + new_PC = Exception(EXCEPTION_ADES, PC, new_PC_mask); + new_PC_mask = 0; + } + else + WriteMemory(timestamp, address, GPR[rt]); + + DO_LDS(); + END_OPF; + + // + // SW - Store Word + // + BEGIN_OPF(SW, 0x2B, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + + if(MDFN_UNLIKELY(address & 0x3)) + { + new_PC = Exception(EXCEPTION_ADES, PC, new_PC_mask); + new_PC_mask = 0; + } + else + WriteMemory(timestamp, address, GPR[rt]); + + DO_LDS(); + END_OPF; + + // LWL and LWR load delay slot tomfoolery appears to apply even to MFC0! (and probably MFCn and CFCn as well, though they weren't explicitly tested) + + // + // LWL - Load Word Left + // + BEGIN_OPF(LWL, 0x22, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + //GPR_DEP(rt); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + uint32_t v = GPR[rt]; + + if(LDWhich == rt) + { + v = LDValue; + ReadFudge = 0; + } + else + { + DO_LDS(); + } + + LDWhich = rt; + switch(address & 0x3) + { + case 0: LDValue = (v & ~(0xFF << 24)) | (ReadMemory(timestamp, address & ~3) << 24); + break; + + case 1: LDValue = (v & ~(0xFFFF << 16)) | (ReadMemory(timestamp, address & ~3) << 16); + break; + + case 2: LDValue = (v & ~(0xFFFFFF << 8)) | (ReadMemory(timestamp, address & ~3, true) << 8); + break; + + case 3: LDValue = (v & ~(0xFFFFFFFF << 0)) | (ReadMemory(timestamp, address & ~3) << 0); + break; + } + END_OPF; + + // + // SWL - Store Word Left + // + BEGIN_OPF(SWL, 0x2A, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + + switch(address & 0x3) + { + case 0: WriteMemory(timestamp, address & ~3, GPR[rt] >> 24); + break; + + case 1: WriteMemory(timestamp, address & ~3, GPR[rt] >> 16); + break; + + case 2: WriteMemory(timestamp, address & ~3, GPR[rt] >> 8, true); + break; + + case 3: WriteMemory(timestamp, address & ~3, GPR[rt] >> 0); + break; + } + DO_LDS(); + + END_OPF; + + // + // LWR - Load Word Right + // + BEGIN_OPF(LWR, 0x26, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + //GPR_DEP(rt); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + uint32_t v = GPR[rt]; + + if(LDWhich == rt) + { + v = LDValue; + ReadFudge = 0; + } + else + { + DO_LDS(); + } + + LDWhich = rt; + switch(address & 0x3) + { + case 0: + LDValue = (v & ~(0xFFFFFFFF)) | ReadMemory(timestamp, address); + break; + case 1: + LDValue = (v & ~(0xFFFFFF)) | ReadMemory(timestamp, address, true); + break; + case 2: + LDValue = (v & ~(0xFFFF)) | ReadMemory(timestamp, address); + break; + + case 3: + LDValue = (v & ~(0xFF)) | ReadMemory(timestamp, address); + break; + } + END_OPF; + + // + // SWR - Store Word Right + // + BEGIN_OPF(SWR, 0x2E, 0); + ITYPE; + + GPR_DEPRES_BEGIN + GPR_DEP(rs); + GPR_DEP(rt); + GPR_DEPRES_END + + uint32_t address = GPR[rs] + immediate; + + switch(address & 0x3) + { + case 0: + WriteMemory(timestamp, address, GPR[rt]); + break; + + case 1: + WriteMemory(timestamp, address, GPR[rt], true); + break; + + case 2: + WriteMemory(timestamp, address, GPR[rt]); + break; + + case 3: + WriteMemory(timestamp, address, GPR[rt]); + break; + } + + DO_LDS(); + + END_OPF; + + // + // Mednafen special instruction + // + BEGIN_OPF(INTERRUPT, 0x3F, 0); + if(Halted) + { + goto SkipNPCStuff; + } + else + { + DO_LDS(); + + new_PC = Exception(EXCEPTION_INT, PC, new_PC_mask); + new_PC_mask = 0; + } + END_OPF; + } diff --git a/psx/octoshock/psx/debug.cpp b/psx/octoshock/psx/debug.cpp new file mode 100644 index 0000000000..4af853f3a4 --- /dev/null +++ b/psx/octoshock/psx/debug.cpp @@ -0,0 +1,679 @@ +/* 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 "psx.h" +#include "timer.h" +#include "cdc.h" +#include "spu.h" + +namespace MDFN_IEN_PSX +{ + +extern PS_GPU *GPU; +extern PS_SPU *SPU; + +static void RedoCPUHook(void); + +static void (*CPUHook)(uint32, bool) = NULL; +static bool CPUHookContinuous = false; + +struct PSX_BPOINT +{ + uint32 A[2]; + int type; +}; + +static std::vector BreakPointsPC, BreakPointsRead, BreakPointsWrite; +static bool FoundBPoint; + +static bool BTEnabled; +static int BTIndex; + +struct BTEntry +{ + uint32 from; + uint32 to; + uint32 branch_count; + bool exception; + bool valid; +}; + +#define NUMBT 24 +static BTEntry BTEntries[NUMBT]; + +void DBG_Break(void) +{ + FoundBPoint = true; +} + +static void AddBranchTrace(uint32 from, uint32 to, bool exception) +{ + BTEntry *prevbt = &BTEntries[(BTIndex + NUMBT - 1) % NUMBT]; + + //if(BTEntries[(BTIndex - 1) & 0xF] == PC) return; + + if(prevbt->from == from && prevbt->to == to && prevbt->exception == exception && prevbt->branch_count < 0xFFFFFFFF && prevbt->valid) + prevbt->branch_count++; + else + { + BTEntries[BTIndex].from = from; + BTEntries[BTIndex].to = to; + BTEntries[BTIndex].exception = exception; + BTEntries[BTIndex].branch_count = 1; + BTEntries[BTIndex].valid = true; + + BTIndex = (BTIndex + 1) % NUMBT; + } +} + +static void EnableBranchTrace(bool enable) +{ + BTEnabled = enable; + if(!enable) + { + BTIndex = 0; + memset(BTEntries, 0, sizeof(BTEntries)); + } + RedoCPUHook(); +} + +static std::vector GetBranchTrace(void) +{ + BranchTraceResult tmp; + std::vector ret; + + for(int x = 0; x < NUMBT; x++) + { + const BTEntry *bt = &BTEntries[(x + BTIndex) % NUMBT]; + + tmp.count = bt->branch_count; + trio_snprintf(tmp.from, sizeof(tmp.from), "%08x", bt->from); + trio_snprintf(tmp.to, sizeof(tmp.to), "%08x", bt->to); + trio_snprintf(tmp.code, sizeof(tmp.code), "%s", bt->exception ? "e" : ""); + + ret.push_back(tmp); + } + return(ret); +} + +void CheckCPUBPCallB(bool write, uint32 address, unsigned int len) +{ + std::vector::iterator bpit; + std::vector::iterator bpit_end; + + if(write) + { + bpit = BreakPointsWrite.begin(); + bpit_end = BreakPointsWrite.end(); + } + else + { + bpit = BreakPointsRead.begin(); + bpit_end = BreakPointsRead.end(); + } + + while(bpit != bpit_end) + { + if(address >= bpit->A[0] && address <= bpit->A[1]) + { + FoundBPoint = true; + break; + } + bpit++; + } +} + +static void CPUHandler(const pscpu_timestamp_t timestamp, uint32 PC) +{ + std::vector::iterator bpit; + + for(bpit = BreakPointsPC.begin(); bpit != BreakPointsPC.end(); bpit++) + { + if(PC >= bpit->A[0] && PC <= bpit->A[1]) + { + FoundBPoint = true; + break; + } + } + + CPU->CheckBreakpoints(CheckCPUBPCallB, CPU->PeekMem32(PC)); + + CPUHookContinuous |= FoundBPoint; + + if(CPUHookContinuous && CPUHook) + { + ForceEventUpdates(timestamp); + CPUHook(PC, FoundBPoint); + } + + FoundBPoint = false; +} + + +static void RedoCPUHook(void) +{ + const bool HappyTest = CPUHook || BreakPointsPC.size() || BreakPointsRead.size() || BreakPointsWrite.size(); + + CPU->SetCPUHook(HappyTest ? CPUHandler : NULL, BTEnabled ? AddBranchTrace : NULL); +} + +static void FlushBreakPoints(int type) +{ + if(type == BPOINT_READ) + BreakPointsRead.clear(); + else if(type == BPOINT_WRITE) + BreakPointsWrite.clear(); + else if(type == BPOINT_PC) + BreakPointsPC.clear(); + + RedoCPUHook(); +} + +static void AddBreakPoint(int type, unsigned int A1, unsigned int A2, bool logical) +{ + PSX_BPOINT tmp; + + tmp.A[0] = A1; + tmp.A[1] = A2; + tmp.type = type; + + if(type == BPOINT_READ) + BreakPointsRead.push_back(tmp); + else if(type == BPOINT_WRITE) + BreakPointsWrite.push_back(tmp); + else if(type == BPOINT_PC) + BreakPointsPC.push_back(tmp); + + RedoCPUHook(); +} + +static void SetCPUCallback(void (*callb)(uint32 PC, bool bpoint), bool continuous) +{ + CPUHook = callb; + CPUHookContinuous = continuous; + RedoCPUHook(); +} + +static void GetAddressSpaceBytes(const char *name, uint32 Address, uint32 Length, uint8 *Buffer) +{ + if(!strcmp(name, "cpu")) + { + while(Length--) + { + Address &= 0xFFFFFFFF; + *Buffer = CPU->PeekMem8(Address); + Address++; + Buffer++; + } + } + else if(!strcmp(name, "ram")) + { + while(Length--) + { + Address &= 0x1FFFFF; + *Buffer = CPU->PeekMem8(Address); + Address++; + Buffer++; + } + } + else if(!strcmp(name, "spu")) + { + while(Length--) + { + Address &= 0x7FFFF; + *Buffer = SPU->PeekSPURAM(Address >> 1) >> ((Address & 1) * 8); + Address++; + Buffer++; + } + } + else if(!strcmp(name, "gpu")) + { + while(Length--) + { + Address &= 0xFFFFF; + *Buffer = GPU->PeekRAM(Address >> 1) >> ((Address & 1) * 8); + Address++; + Buffer++; + } + } +} + + +static void PutAddressSpaceBytes(const char *name, uint32 Address, uint32 Length, uint32 Granularity, bool hl, const uint8 *Buffer) +{ + if(!strcmp(name, "cpu")) + { + while(Length--) + { + pscpu_timestamp_t dummy = 0; + Address &= 0xFFFFFFFF; + + // TODO + PSX_MemWrite8(dummy, Address, *Buffer); + + Address++; + Buffer++; + } + } + else if(!strcmp(name, "gpu")) + { + while(Length--) + { + Address &= 0xFFFFF; + + uint16 peeko = GPU->PeekRAM(Address >> 1); + + GPU->PokeRAM(Address >> 1, (*Buffer << ((Address & 1) * 8)) | (peeko & (0xFF00 >> ((Address & 1) * 8))) ); + Address++; + Buffer++; + } + } + else if(!strcmp(name, "spu")) + { + while(Length--) + { + Address &= 0x7FFFF; + + uint16 peeko = SPU->PeekSPURAM(Address >> 1); + + SPU->PokeSPURAM(Address >> 1, (*Buffer << ((Address & 1) * 8)) | (peeko & (0xFF00 >> ((Address & 1) * 8))) ); + Address++; + Buffer++; + } + } + +} + +static uint32 MemPeek(uint32 A, unsigned int bsize, bool hl, bool logical) +{ + uint32 ret = 0; + + for(unsigned int i = 0; i < bsize; i++) + ret |= CPU->PeekMem8(A + i) << (i * 8); + + return(ret); +} + +static void Disassemble(uint32 &A, uint32 SpecialA, char *TextBuf) +{ + assert(!(A & 0x3)); + + uint32 instr = CPU->PeekMem32(A); + + CPU->PeekCheckICache(A, &instr); + + strncpy(TextBuf, DisassembleMIPS(A, instr).c_str(), 256); + TextBuf[255] = 0; + +// trio_snprintf(TextBuf, 256, "0x%08x", instr); + + A += 4; +} + +static MDFN_Surface *GfxDecode_Buf = NULL; +static int GfxDecode_Line = -1; +static int GfxDecode_Layer = 0; +static int GfxDecode_Scroll = 0; +static int GfxDecode_PBN = 0; + +static void DoGfxDecode(void) +{ + unsigned tp_w, tp_h; + + tp_w = 256; + tp_h = 256; + + if(GfxDecode_Buf) + { + for(int sy = 0; sy < GfxDecode_Buf->h; sy++) + { + for(int sx = 0; sx < GfxDecode_Buf->w; sx++) + { + unsigned fb_x = ((sx % GfxDecode_Buf->w) + ((sy + GfxDecode_Scroll) / GfxDecode_Buf->w * GfxDecode_Buf->w)) & 1023; + unsigned fb_y = (((sy + GfxDecode_Scroll) % GfxDecode_Buf->w) + ((((sx % GfxDecode_Buf->w) + ((sy + GfxDecode_Scroll) / GfxDecode_Buf->w * GfxDecode_Buf->w)) / 1024) * 256)) & 511; + + uint16 pixel = GPU->PeekRAM(fb_y * 1024 + fb_x); + + GfxDecode_Buf->pixels[(sy * GfxDecode_Buf->w * 3) + sx] = GfxDecode_Buf->MakeColor(((pixel >> 0) & 0x1F) * 255 / 31, + ((pixel >> 5) & 0x1F) * 255 / 31, + ((pixel >> 10) & 0x1F) * 255 / 31, 0xFF); + } + } + } +} + + +void DBG_GPUScanlineHook(unsigned scanline) +{ + if((int)scanline == GfxDecode_Line) + { + DoGfxDecode(); + } +} + + +static void SetGraphicsDecode(MDFN_Surface *surface, int line, int which, int xscroll, int yscroll, int pbn) +{ + GfxDecode_Buf = surface; + GfxDecode_Line = line; + GfxDecode_Layer = which; + GfxDecode_Scroll = yscroll; + GfxDecode_PBN = pbn; + + if(GfxDecode_Buf && GfxDecode_Line == -1) + DoGfxDecode(); +} + +DebuggerInfoStruct PSX_DBGInfo = +{ + "shift_jis", + 4, // Max instruction byte size + 4, // Instruction alignment(bytes) + 32, // Logical address bits + 32, // Physical address bits + 0x00000000, // Default watch addr + ~0U, // ZP addr + + MemPeek, + Disassemble, + NULL, + NULL, //ForceIRQ, + NULL, //NESDBG_GetVector, + FlushBreakPoints, + AddBreakPoint, + SetCPUCallback, + EnableBranchTrace, + GetBranchTrace, + SetGraphicsDecode, + NULL, //PCFXDBG_SetLogFunc, +}; + +static RegType Regs_Misc[] = +{ + { TIMER_GSREG_COUNTER0, "COUNT0", "Counter 0", 2 }, + { TIMER_GSREG_MODE0, "MODE0", "Mode 0", 2 }, + { TIMER_GSREG_TARGET0, "TARGET0", "Target 0", 2 }, + + { 0, "------", "", 0xFFFF }, + + + { TIMER_GSREG_COUNTER1, "COUNT1", "Counter 1", 2 }, + { TIMER_GSREG_MODE1, "MODE1", "Mode 1", 2 }, + { TIMER_GSREG_TARGET1, "TARGET1", "Target 1", 2 }, + + { 0, "------", "", 0xFFFF }, + + { TIMER_GSREG_COUNTER2, "COUNT2", "Counter 2", 2 }, + { TIMER_GSREG_MODE2, "MODE2", "Mode 2", 2 }, + { TIMER_GSREG_TARGET2, "TARGET2", "Target 2", 2 }, + + { 0, "------", "", 0xFFFF }, + { 0, "------", "", 0xFFFF }, + + { 0x10000 | IRQ_GSREG_ASSERTED, "ASSERTD", "IRQ Asserted", 2 }, + { 0x10000 | IRQ_GSREG_STATUS, "STATUS", "IRQ Status", 2 }, + { 0x10000 | IRQ_GSREG_MASK, "MASK", "IRQ Mask", 2 }, + + { 0, "", "", 0 } +}; + + +static uint32 GetRegister_Misc(const unsigned int id, char *special, const uint32 special_len) +{ + if(id & 0x10000) + return(IRQ_GetRegister(id & 0xFFFF, special, special_len)); + else + return(TIMER_GetRegister(id & 0xFFFF, special, special_len)); +} + +static void SetRegister_Misc(const unsigned int id, uint32 value) +{ + if(id & 0x10000) + IRQ_SetRegister(id & 0xFFFF, value); + else + TIMER_SetRegister(id & 0xFFFF, value); +} + +static RegGroupType MiscRegsGroup = +{ + NULL, + Regs_Misc, + GetRegister_Misc, + SetRegister_Misc +}; + +static RegType Regs_SPU[] = +{ + { PS_SPU::GSREG_SPUCONTROL, "SPUCTRL", "SPU Control", 2 }, + + { PS_SPU::GSREG_FM_ON, "FMOn", "FM Enable", 3 }, + { PS_SPU::GSREG_NOISE_ON, "NoiseOn", "Noise Enable", 3 }, + { PS_SPU::GSREG_REVERB_ON, "ReverbOn", "Reverb Enable", 3 }, + + { PS_SPU::GSREG_CDVOL_L, "CDVolL", "CD Volume Left", 2 }, + { PS_SPU::GSREG_CDVOL_R, "CDVolR", "CD Volume Right", 2 }, + + { PS_SPU::GSREG_DRYVOL_CTRL_L, "DryVolCL", "Dry Volume Control Left", 2 }, + { PS_SPU::GSREG_DRYVOL_CTRL_R, "DryVolCR", "Dry Volume Control Right", 2 }, + + { PS_SPU::GSREG_DRYVOL_L, "DryVolL", "Dry Volume Left", 2 }, + { PS_SPU::GSREG_DRYVOL_R, "DryVolR", "Dry Volume Right", 2 }, + + { PS_SPU::GSREG_WETVOL_L, "WetVolL", "Wet Volume Left", 2 }, + { PS_SPU::GSREG_WETVOL_R, "WetVolR", "Wet Volume Right", 2 }, + + { PS_SPU::GSREG_RWADDR, "RWAddr", "SPURAM Read/Write Address", 3 }, + + { PS_SPU::GSREG_IRQADDR, "IRQAddr", "IRQ Compare Address", 3 }, + + { PS_SPU::GSREG_REVERBWA, "ReverbWA", "Reverb Work Area(Raw)", 2 }, + + { PS_SPU::GSREG_VOICEON, "VoiceOn", "Voice On", 3 }, + { PS_SPU::GSREG_VOICEOFF, "VoiceOff", "Voice Off", 3 }, + { PS_SPU::GSREG_BLOCKEND, "BlockEnd", "Block End", 3 }, + + + { 0, "------", "", 0xFFFF }, + + { PS_SPU::GSREG_FB_SRC_A, "FB_SRC_A", "", 2 }, + { PS_SPU::GSREG_FB_SRC_B, "FB_SRC_B", "", 2 }, + { PS_SPU::GSREG_IIR_ALPHA, "IIR_ALPHA", "", 2 }, + { PS_SPU::GSREG_ACC_COEF_A, "ACC_COEF_A", "", 2 }, + { PS_SPU::GSREG_ACC_COEF_B, "ACC_COEF_B", "", 2 }, + { PS_SPU::GSREG_ACC_COEF_C, "ACC_COEF_C", "", 2 }, + { PS_SPU::GSREG_ACC_COEF_D, "ACC_COEF_D", "", 2 }, + { PS_SPU::GSREG_IIR_COEF, "IIR_COEF", "", 2 }, + { PS_SPU::GSREG_FB_ALPHA, "FB_ALPHA", "", 2 }, + { PS_SPU::GSREG_FB_X, "FB_X", "", 2 }, + { PS_SPU::GSREG_IIR_DEST_A0, "IIR_DST_A0", "", 2 }, + { PS_SPU::GSREG_IIR_DEST_A1, "IIR_DST_A1", "", 2 }, + { PS_SPU::GSREG_ACC_SRC_A0, "ACC_SRC_A0", "", 2 }, + { PS_SPU::GSREG_ACC_SRC_A1, "ACC_SRC_A1", "", 2 }, + { PS_SPU::GSREG_ACC_SRC_B0, "ACC_SRC_B0", "", 2 }, + { PS_SPU::GSREG_ACC_SRC_B1, "ACC_SRC_B1", "", 2 }, + { PS_SPU::GSREG_IIR_SRC_A0, "IIR_SRC_A0", "", 2 }, + { PS_SPU::GSREG_IIR_SRC_A1, "IIR_SRC_A1", "", 2 }, + { PS_SPU::GSREG_IIR_DEST_B0, "IIR_DST_B0", "", 2 }, + { PS_SPU::GSREG_IIR_DEST_B1, "IIR_DST_B1", "", 2 }, + { PS_SPU::GSREG_ACC_SRC_C0, "ACC_SRC_C0", "", 2 }, + { PS_SPU::GSREG_ACC_SRC_C1, "ACC_SRC_C1", "", 2 }, + { PS_SPU::GSREG_ACC_SRC_D0, "ACC_SRC_D0", "", 2 }, + { PS_SPU::GSREG_ACC_SRC_D1, "ACC_SRC_D1", "", 2 }, + { PS_SPU::GSREG_IIR_SRC_B1, "IIR_SRC_B1", "", 2 }, + { PS_SPU::GSREG_IIR_SRC_B0, "IIR_SRC_B0", "", 2 }, + { PS_SPU::GSREG_MIX_DEST_A0, "MIX_DST_A0", "", 2 }, + { PS_SPU::GSREG_MIX_DEST_A1, "MIX_DST_A1", "", 2 }, + { PS_SPU::GSREG_MIX_DEST_B0, "MIX_DST_B0", "", 2 }, + { PS_SPU::GSREG_MIX_DEST_B1, "MIX_DST_B1", "", 2 }, + { PS_SPU::GSREG_IN_COEF_L, "IN_COEF_L", "", 2 }, + { PS_SPU::GSREG_IN_COEF_R, "IN_COEF_R", "", 2 }, + + { 0, "", "", 0 }, +}; + +#define VOICE_HELPER(v) \ + { 0, "--V"#v"--", "", 0xFFFF }, \ + { PS_SPU:: GSREG_V0_VOL_CTRL_L + v * 256, "VolCL", "Volume Control Left", 2 }, \ + { PS_SPU:: GSREG_V0_VOL_CTRL_R + v * 256, "VolCR", "Volume Control Right", 2 }, \ + { PS_SPU:: GSREG_V0_VOL_L + v * 256, "VolL", "Volume Left", 2 }, \ + { PS_SPU:: GSREG_V0_VOL_R + v * 256, "VolR", "Volume Right", 2 }, \ + { PS_SPU:: GSREG_V0_PITCH + v * 256, "Pitch", "Pitch", 2 }, \ + { PS_SPU:: GSREG_V0_STARTADDR + v * 256, "SAddr", "Start Address", 3 }, \ + { PS_SPU:: GSREG_V0_ADSR_CTRL + v * 256, "ADSRCTRL", "ADSR Control", 4 }, \ + { PS_SPU:: GSREG_V0_ADSR_LEVEL + v * 256, "ADSRLev", "ADSR Level", 2 }, \ + { PS_SPU:: GSREG_V0_LOOP_ADDR + v * 256, "LAddr", "Loop Address", 3 }, \ + { PS_SPU:: GSREG_V0_READ_ADDR + v * 256, "RAddr", "Read Address", 3 } + + +static RegType Regs_SPU_Voices[] = +{ +#if 1 + VOICE_HELPER(0), + VOICE_HELPER(1), + VOICE_HELPER(2), + VOICE_HELPER(3), +#else + VOICE_HELPER(9), + VOICE_HELPER(12), + VOICE_HELPER(17), + VOICE_HELPER(22), + + //VOICE_HELPER(20), + //VOICE_HELPER(21), + //VOICE_HELPER(22), + //VOICE_HELPER(23), +#endif + { 0, "", "", 0 }, +}; + + +static uint32 GetRegister_SPU(const unsigned int id, char *special, const uint32 special_len) +{ + return(SPU->GetRegister(id, special, special_len)); +} + +static void SetRegister_SPU(const unsigned int id, uint32 value) +{ + SPU->SetRegister(id, value); +} + +static RegGroupType SPURegsGroup = +{ + NULL, + Regs_SPU, + GetRegister_SPU, + SetRegister_SPU +}; + + +static RegGroupType SPUVoicesRegsGroup = +{ + NULL, + Regs_SPU_Voices, + GetRegister_SPU, + SetRegister_SPU +}; + +static RegType Regs_CPU[] = +{ + { PS_CPU::GSREG_PC, "PC", "PC", 4 }, + { PS_CPU::GSREG_PC_NEXT, "NPC", "Next PC", 4 }, + { PS_CPU::GSREG_IN_BD_SLOT, "INBD", "In Branch Delay Slot", 1 }, + { 0, "------", "", 0xFFFF }, + { PS_CPU::GSREG_GPR + 1, "at", "Assembler Temporary", 4 }, + { PS_CPU::GSREG_GPR + 2, "v0", "Return Value 0", 4 }, + { PS_CPU::GSREG_GPR + 3, "v1", "Return Value 1", 4 }, + { PS_CPU::GSREG_GPR + 4, "a0", "Argument 0", 4 }, + { PS_CPU::GSREG_GPR + 5, "a1", "Argument 1", 4 }, + { PS_CPU::GSREG_GPR + 6, "a2", "Argument 2", 4 }, + { PS_CPU::GSREG_GPR + 7, "a3", "Argument 3", 4 }, + { PS_CPU::GSREG_GPR + 8, "t0", "Temporary 0", 4 }, + { PS_CPU::GSREG_GPR + 9, "t1", "Temporary 1", 4 }, + { PS_CPU::GSREG_GPR + 10, "t2", "Temporary 2", 4 }, + { PS_CPU::GSREG_GPR + 11, "t3", "Temporary 3", 4 }, + { PS_CPU::GSREG_GPR + 12, "t4", "Temporary 4", 4 }, + { PS_CPU::GSREG_GPR + 13, "t5", "Temporary 5", 4 }, + { PS_CPU::GSREG_GPR + 14, "t6", "Temporary 6", 4 }, + { PS_CPU::GSREG_GPR + 15, "t7", "Temporary 7", 4 }, + { PS_CPU::GSREG_GPR + 16, "s0", "Subroutine Reg Var 0", 4 }, + { PS_CPU::GSREG_GPR + 17, "s1", "Subroutine Reg Var 1", 4 }, + { PS_CPU::GSREG_GPR + 18, "s2", "Subroutine Reg Var 2", 4 }, + { PS_CPU::GSREG_GPR + 19, "s3", "Subroutine Reg Var 3", 4 }, + { PS_CPU::GSREG_GPR + 20, "s4", "Subroutine Reg Var 4", 4 }, + { PS_CPU::GSREG_GPR + 21, "s5", "Subroutine Reg Var 5", 4 }, + { PS_CPU::GSREG_GPR + 22, "s6", "Subroutine Reg Var 6", 4 }, + { PS_CPU::GSREG_GPR + 23, "s7", "Subroutine Reg Var 7", 4 }, + { PS_CPU::GSREG_GPR + 24, "t8", "Temporary 8", 4 }, + { PS_CPU::GSREG_GPR + 25, "t9", "Temporary 9", 4 }, + { PS_CPU::GSREG_GPR + 26, "k0", "Interrupt/Trap Handler Reg 0", 4 }, + { PS_CPU::GSREG_GPR + 27, "k1", "Interrupt/Trap Handler Reg 1", 4 }, + { PS_CPU::GSREG_GPR + 28, "gp", "Global Pointer", 4 }, + { PS_CPU::GSREG_GPR + 29, "sp", "Stack Pointer", 4 }, + { PS_CPU::GSREG_GPR + 30, "s8", "Subroutine Reg Var 8/Frame Pointer", 4 }, + { PS_CPU::GSREG_GPR + 31, "ra", "Return Address", 4 }, + { 0, "------", "", 0xFFFF }, + + { PS_CPU::GSREG_SR, "SR", "Status Register", 4 }, + { PS_CPU::GSREG_CAUSE, "CAU","Cause Register", 4 }, + { PS_CPU::GSREG_EPC, "EPC", "EPC Register", 4 }, + { 0, "", "", 0 } +}; + +static uint32 GetRegister_CPU(const unsigned int id, char *special, const uint32 special_len) +{ + return(CPU->GetRegister(id, special, special_len)); +} + +static void SetRegister_CPU(const unsigned int id, uint32 value) +{ + CPU->SetRegister(id, value); +} + +static RegGroupType CPURegsGroup = +{ + NULL, + Regs_CPU, + GetRegister_CPU, + SetRegister_CPU +}; + + +bool DBG_Init(void) +{ + CPUHook = NULL; + CPUHookContinuous = false; + FoundBPoint = false; + + BTEnabled = false; + BTIndex = false; + memset(BTEntries, 0, sizeof(BTEntries)); + + MDFNDBG_AddRegGroup(&CPURegsGroup); + MDFNDBG_AddRegGroup(&MiscRegsGroup); + MDFNDBG_AddRegGroup(&SPURegsGroup); + MDFNDBG_AddRegGroup(&SPUVoicesRegsGroup); + ASpace_Add(GetAddressSpaceBytes, PutAddressSpaceBytes, "cpu", "CPU Physical", 32); + ASpace_Add(GetAddressSpaceBytes, PutAddressSpaceBytes, "ram", "CPU Main Ram", 21); + ASpace_Add(GetAddressSpaceBytes, PutAddressSpaceBytes, "spu", "SPU RAM", 19); + ASpace_Add(GetAddressSpaceBytes, PutAddressSpaceBytes, "gpu", "GPU RAM", 20); + return(true); +} + + + +} + diff --git a/psx/octoshock/psx/debug.h b/psx/octoshock/psx/debug.h new file mode 100644 index 0000000000..18035d66b9 --- /dev/null +++ b/psx/octoshock/psx/debug.h @@ -0,0 +1,21 @@ +#ifndef __MDFN_PSX_DEBUG_H +#define __MDFN_PSX_DEBUG_H + +#ifdef WANT_DEBUGGER + +namespace MDFN_IEN_PSX +{ + +extern DebuggerInfoStruct PSX_DBGInfo; + +bool DBG_Init(void); + +void DBG_Break(void); + +void DBG_GPUScanlineHook(unsigned scanline); + +} + +#endif + +#endif diff --git a/psx/octoshock/psx/dis.cpp b/psx/octoshock/psx/dis.cpp new file mode 100644 index 0000000000..cc2f89df7a --- /dev/null +++ b/psx/octoshock/psx/dis.cpp @@ -0,0 +1,416 @@ +/* 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 "psx.h" + +#define trio_snprintf snprintf + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif + +namespace MDFN_IEN_PSX +{ + +struct OpEntry +{ + uint32 mask; + uint32 value; + const char *mnemonic; + const char *format; +}; + +#define MASK_OP (0x3FU << 26) +#define MASK_FUNC (0x3FU) +#define MASK_RS (0x1FU << 21) +#define MASK_RT (0x1FU << 16) +#define MASK_RD (0x1FU << 11) +#define MASK_SA (0x1FU << 6) + +#define MK_OP(mnemonic, format, op, func, extra_mask) { MASK_OP | (op ? 0 : MASK_FUNC) | extra_mask, ((unsigned)op << 26) | func, mnemonic, format } + +#define MK_OP_REGIMM(mnemonic, regop) { MASK_OP | MASK_RT, (0x01U << 26) | (regop << 16), mnemonic, "s, p" } + + +#define MK_COPZ(z) { MASK_OP | (0x1U << 25), (0x1U << 25) | ((0x10U | z) << 26), "cop" #z, "F" } +#define MK_COP0_FUNC(mnemonic, func) { MASK_OP | (0x1U << 25) | MASK_FUNC, (0x10U << 26) | (0x1U << 25) | func, mnemonic, "" } + +#define MK_COPZ_XFER(z, mnemonic, format, xf) { MASK_OP | (0x1FU << 21), ((0x10U | z) << 26) | (xf << 21), mnemonic, format } + +#define MK_GTE(mnemonic, format, func) { MASK_OP | (0x1U << 25) | MASK_FUNC, (0x1U << 25) | (0x12U << 26) | func, mnemonic, format } + +static OpEntry ops[] = +{ + MK_OP("nop", "", 0, 0, MASK_RT | MASK_RD | MASK_SA), + + // + // + // + MK_OP("sll", "d, t, a", 0, 0, 0), + MK_OP("srl", "d, t, a", 0, 2, 0), + MK_OP("sra", "d, t, a", 0, 3, 0), + + MK_OP("sllv", "d, t, s", 0, 4, 0), + MK_OP("srlv", "d, t, s", 0, 6, 0), + MK_OP("srav", "d, t, s", 0, 7, 0), + + MK_OP("jr", "s", 0, 8, 0), + MK_OP("jalr", "d, s", 0, 9, 0), + + MK_OP("syscall", "", 0, 12, 0), // TODO + MK_OP("break", "", 0, 13, 0), // TODO + + MK_OP("mfhi", "d", 0, 16, 0), + MK_OP("mthi", "s", 0, 17, 0), + MK_OP("mflo", "d", 0, 18, 0), + MK_OP("mtlo", "s", 0, 19, 0), + + MK_OP("mult", "s, t", 0, 24, 0), + MK_OP("multu", "s, t", 0, 25, 0), + MK_OP("div", "s, t", 0, 26, 0), + MK_OP("divu", "s, t", 0, 27, 0), + + MK_OP("add", "d, s, t", 0, 32, 0), + MK_OP("addu", "d, s, t", 0, 33, 0), + MK_OP("sub", "d, s, t", 0, 34, 0), + MK_OP("subu", "d, s, t", 0, 35, 0), + MK_OP("and", "d, s, t", 0, 36, 0), + MK_OP("or", "d, s, t", 0, 37, 0), + MK_OP("xor", "d, s, t", 0, 38, 0), + MK_OP("nor", "d, s, t", 0, 39, 0), + MK_OP("slt", "d, s, t", 0, 42, 0), + MK_OP("sltu", "d, s, t", 0, 43, 0), + + MK_OP_REGIMM("bgez", 0x01), + MK_OP_REGIMM("bgezal", 0x11), + MK_OP_REGIMM("bltz", 0x00), + MK_OP_REGIMM("bltzal", 0x10), + + + MK_OP("j", "P", 2, 0, 0), + MK_OP("jal", "P", 3, 0, 0), + + MK_OP("beq", "s, t, p", 4, 0, 0), + MK_OP("bne", "s, t, p", 5, 0, 0), + MK_OP("blez", "s, p", 6, 0, 0), + MK_OP("bgtz", "s, p", 7, 0, 0), + + MK_OP("addi", "t, s, i", 8, 0, 0), + MK_OP("addiu", "t, s, i", 9, 0, 0), + MK_OP("slti", "t, s, i", 10, 0, 0), + MK_OP("sltiu", "t, s, i", 11, 0, 0), + + MK_OP("andi", "t, s, z", 12, 0, 0), + + MK_OP("ori", "t, s, z", 13, 0, 0), + MK_OP("xori", "t, s, z", 14, 0, 0), + MK_OP("lui", "t, z", 15, 0, 0), + + MK_COPZ_XFER(0, "mfc0", "t, 0", 0x00), + MK_COPZ_XFER(1, "mfc1", "t, ?", 0x00), + MK_COPZ_XFER(2, "mfc2", "t, g", 0x00), + MK_COPZ_XFER(3, "mfc3", "t, ?", 0x00), + + MK_COPZ_XFER(0, "mtc0", "t, 0", 0x04), + MK_COPZ_XFER(1, "mtc1", "t, ?", 0x04), + MK_COPZ_XFER(2, "mtc2", "t, g", 0x04), + MK_COPZ_XFER(3, "mtc3", "t, ?", 0x04), + + MK_COPZ_XFER(0, "cfc0", "t, ?", 0x02), + MK_COPZ_XFER(1, "cfc1", "t, ?", 0x02), + MK_COPZ_XFER(2, "cfc2", "t, G", 0x02), + MK_COPZ_XFER(3, "cfc3", "t, ?", 0x02), + + MK_COPZ_XFER(0, "ctc0", "t, ?", 0x06), + MK_COPZ_XFER(1, "ctc1", "t, ?", 0x06), + MK_COPZ_XFER(2, "ctc2", "t, G", 0x06), + MK_COPZ_XFER(3, "ctc3", "t, ?", 0x06), + + // COP0 stuff here + MK_COP0_FUNC("rfe", 0x10), + + MK_OP("lwc0", "?, i(s)", 0x30, 0, 0), + MK_OP("lwc1", "?, i(s)", 0x31, 0, 0), + MK_OP("lwc2", "h, i(s)", 0x32, 0, 0), + MK_OP("lwc3", "?, i(s)", 0x33, 0, 0), + + MK_OP("swc0", "?, i(s)", 0x38, 0, 0), + MK_OP("swc1", "?, i(s)", 0x39, 0, 0), + MK_OP("swc2", "h, i(s)", 0x3A, 0, 0), + MK_OP("swc3", "?, i(s)", 0x3B, 0, 0), + + MK_OP("lb", "t, i(s)", 0x20, 0, 0), + MK_OP("lh", "t, i(s)", 0x21, 0, 0), + MK_OP("lwl", "t, i(s)", 0x22, 0, 0), + MK_OP("lw", "t, i(s)", 0x23, 0, 0), + MK_OP("lbu", "t, i(s)", 0x24, 0, 0), + MK_OP("lhu", "t, i(s)", 0x25, 0, 0), + MK_OP("lwr", "t, i(s)", 0x26, 0, 0), + + MK_OP("sb", "t, i(s)", 0x28, 0, 0), + MK_OP("sh", "t, i(s)", 0x29, 0, 0), + MK_OP("swl", "t, i(s)", 0x2A, 0, 0), + MK_OP("sw", "t, i(s)", 0x2B, 0, 0), + MK_OP("swr", "t, i(s)", 0x2E, 0, 0), + + // + // GTE specific instructions + // + // sf mx v cv lm + // + MK_GTE("rtps", "#sf# #lm#", 0x00), + MK_GTE("rtps", "#sf# #lm#", 0x01), + MK_GTE("nclip", "", 0x06), + MK_GTE("op", "#sf# #lm#", 0x0C), + + MK_GTE("dpcs", "#sf# #lm#", 0x10), + MK_GTE("intpl", "#sf# #lm#", 0x11), + MK_GTE("mvmva", "#sf# #mx# #v# #cv# #lm#", 0x12), + MK_GTE("ncds", "#sf# #lm#", 0x13), + MK_GTE("cdp", "#sf# #lm#", 0x14), + MK_GTE("ncdt", "#sf# #lm#", 0x16), + MK_GTE("dcpl", "#sf# #lm#", 0x1A), + MK_GTE("nccs", "#sf# #lm#", 0x1B), + MK_GTE("cc", "#sf# #lm#", 0x1C), + MK_GTE("ncs", "#sf# #lm#", 0x1E), + MK_GTE("nct", "#sf# #lm#", 0x20), + MK_GTE("sqr", "#sf# #lm#", 0x28), + MK_GTE("dcpl", "#sf# #lm#", 0x29), + MK_GTE("dpct", "#sf# #lm#", 0x2A), + MK_GTE("avsz3", "", 0x2D), + MK_GTE("avsz4", "", 0x2E), + MK_GTE("rtpt", "#sf# #lm#", 0x30), + MK_GTE("gpf", "#sf# #lm#", 0x3D), + MK_GTE("gpl", "#sf# #lm#", 0x3E), + MK_GTE("ncct", "#sf# #lm#", 0x3F), + + + // + // + // + MK_COPZ(0), + MK_COPZ(1), + MK_COPZ(2), + MK_COPZ(3), + + { 0, 0, NULL, NULL } +}; + +std::string DisassembleMIPS(uint32 PC, uint32 instr) +{ + std::string ret = "UNKNOWN"; + unsigned int rs = (instr >> 21) & 0x1F; + unsigned int rt = (instr >> 16) & 0x1F; + unsigned int rd = (instr >> 11) & 0x1F; + unsigned int shamt = (instr >> 6) & 0x1F; + unsigned int immediate = (int32)(int16)(instr & 0xFFFF); + unsigned int immediate_ze = (instr & 0xFFFF); + unsigned int jt = instr & ((1 << 26) - 1); + + static const char *gpr_names[32] = + { + "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" + }; + + static const char *cop0_names[32] = + { + "CPR0", "CPR1", "CPR2", "BPC", "CPR4", "BDA", "TAR", "DCIC", "CPR8", "BDAM", "CPR10", "BPCM", "SR", "CAUSE", "EPC", "PRID", + "ERREG", "CPR17", "CPR18", "CPR19", "CPR20", "CPR21", "CPR22", "CPR23", "CPR24", "CPR25", "CPR26", "CPR27", "CPR28", "CPR29", "CPR30", "CPR31" + }; + + static const char *gte_cr_names[32] = + { + "R11R12", "R13R21", "R22R23", "R31R32", "R33", "TRX", "TRY", "TRZ", "L11L12", "L13L21", "L22L23", "L31L32", "L33", "RBK", "GBK", "BBK", + "LR1LR2", "LR3LG1", "LG2LG3", "LB1LB2", "LB3", "RFC", "GFC", "BFC", "OFX", "OFY", "H", "DQA", "DQB", "ZSF3", "ZSF4", "FLAG" + }; + + static const char *gte_dr_names[32] = + { + "VXY0", "VZ0", "VXY1", "VZ1", "VXY2", "VZ2", "RGB", "OTZ", "IR0", "IR1", "IR2", "IR3", "SXY0", "SXY1", "SXY2", "SXYP", + "SZ0", "SZ1", "SZ2", "SZ3", "RGB0", "RGB1", "RGB2", "RES1", "MAC0", "MAC1", "MAC2", "MAC3", "IRGB", "ORGB", "LZCS", "LZCR" + }; + + OpEntry *op = ops; + + while(op->mnemonic) + { + if((instr & op->mask) == op->value) + { + // a = shift amount + // s = rs + // t = rt + // d = rd + // i = immediate + // z = immediate, zero-extended + // p = PC + 4 + immediate + // P = ((PC + 4) & 0xF0000000) | (26bitval << 2) + // + // 0 = rd(cop0 registers) + // c = rd(copz data registers) + // C = rd(copz control registers) + // g = rd(GTE data registers) + // G = rd(GTE control registers) + // h = rt(GTE data registers) + + char s_a[16]; + char s_i[16]; + char s_z[16]; + char s_p[16]; + char s_P[16]; + char s_c[16]; + char s_C[16]; + + trio_snprintf(s_a, sizeof(s_a), "%d", shamt); + + if(immediate < 0) + trio_snprintf(s_i, sizeof(s_i), "%d", immediate); + else + trio_snprintf(s_i, sizeof(s_i), "0x%04x", (uint32)immediate); + + trio_snprintf(s_z, sizeof(s_z), "0x%04x", immediate_ze); + + trio_snprintf(s_p, sizeof(s_p), "0x%08x", PC + 4 + (immediate << 2)); + + trio_snprintf(s_P, sizeof(s_P), "0x%08x", ((PC + 4) & 0xF0000000) | (jt << 2)); + + trio_snprintf(s_c, sizeof(s_c), "CPR%d", rd); + trio_snprintf(s_C, sizeof(s_C), "CCR%d", rd); + + ret = std::string(op->mnemonic); + ret.append(10 - ret.size(), ' '); + + for(unsigned int i = 0; i < strlen(op->format); i++) + { + switch(op->format[i]) + { + case '#': + // sf mx v cv lm + { + char as[16]; + + as[0] = 0; + if(!strncmp(&op->format[i], "#sf#", 4)) + { + i += 3; + trio_snprintf(as, 16, "sf=%d", (int)(bool)(instr & (1 << 19))); + } + else if(!strncmp(&op->format[i], "#mx#", 4)) + { + i += 3; + trio_snprintf(as, 16, "mx=%d", (instr >> 17) & 0x3); + } + else if(!strncmp(&op->format[i], "#v#", 3)) + { + i += 2; + trio_snprintf(as, 16, "v=%d", (instr >> 15) & 0x3); + } + else if(!strncmp(&op->format[i], "#cv#", 4)) + { + i += 3; + trio_snprintf(as, 16, "cv=%d", (instr >> 13) & 0x3); + } + else if(!strncmp(&op->format[i], "#lm#", 4)) + { + i += 3; + trio_snprintf(as, 16, "lm=%d", (int)(bool)(instr & (1 << 10))); + } + ret.append(as); + } + break; + case 'F': + { + char s_F[16]; + + trio_snprintf(s_F, 16, "0x%07x", instr & 0x1FFFFFF); + ret.append(s_F); + } + break; + + case 'h': + ret.append(gte_dr_names[rt]); + break; + + case 'g': + ret.append(gte_dr_names[rd]); + break; + + case 'G': + ret.append(gte_cr_names[rd]); + break; + + case '0': + ret.append(cop0_names[rd]); + break; + + case 'c': + ret.append(s_c); + break; + + case 'C': + ret.append(s_C); + break; + + case 'a': + ret.append(s_a); + break; + + case 'i': + ret.append(s_i); + break; + + case 'z': + ret.append(s_z); + break; + + case 'p': + ret.append(s_p); + break; + + case 'P': + ret.append(s_P); + break; + + case 's': + ret.append(gpr_names[rs]); + break; + + case 't': + ret.append(gpr_names[rt]); + break; + + case 'd': + ret.append(gpr_names[rd]); + break; + + default: + ret.append(1, op->format[i]); + break; + } + } + break; + } + op++; + } + + return(ret); +} + +} + diff --git a/psx/octoshock/psx/dis.h b/psx/octoshock/psx/dis.h new file mode 100644 index 0000000000..46609e10dc --- /dev/null +++ b/psx/octoshock/psx/dis.h @@ -0,0 +1,11 @@ +#pragma once + +#include "emuware/emuware.h" +#include + +namespace MDFN_IEN_PSX +{ + +std::string DisassembleMIPS(uint32 PC, uint32 instr); + +} diff --git a/psx/octoshock/psx/dma.cpp b/psx/octoshock/psx/dma.cpp new file mode 100644 index 0000000000..270f84de93 --- /dev/null +++ b/psx/octoshock/psx/dma.cpp @@ -0,0 +1,821 @@ +/* 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 "psx.h" +#include "mdec.h" +#include "cdc.h" +#include "spu.h" + +//#include + +// Notes: DMA tested to abort when + +/* Notes: + + Channel 4(SPU): + Write: + Doesn't seem to work properly with CHCR=0x01000001 + Hung when CHCR=0x11000601 + + Channel 6: + DMA hangs if D28 of CHCR is 0? + D1 did not have an apparent effect. + +*/ + +enum +{ + CH_MDEC_IN = 0, + CH_MDEC_OUT = 1, + CH_GPU = 2, + CH_CDC = 3, + CH_SPU = 4, + CH_FIVE = 5, + CH_OT = 6, +}; + + +// RunChannels(128 - whatevercounter); +// +// GPU next event, std::max<128, wait_time>, or something similar, for handling FIFO. + +namespace MDFN_IEN_PSX +{ + +static int32 DMACycleCounter; + +static uint32 DMAControl; +static uint32 DMAIntControl; +static uint8 DMAIntStatus; +static bool IRQOut; + +struct Channel +{ + uint32 BaseAddr; + uint32 BlockControl; + uint32 ChanControl; + + // + // + // + uint32 CurAddr; + uint16 WordCounter; + + // + // + int32 ClockCounter; +}; + +static Channel DMACH[7]; +static pscpu_timestamp_t lastts; + + +static const char *PrettyChannelNames[7] = { "MDEC IN", "MDEC OUT", "GPU", "CDC", "SPU", "PIO", "OTC" }; + +void DMA_Init(void) +{ + +} + +void DMA_Kill(void) +{ + +} + +static INLINE void RecalcIRQOut(void) +{ + bool irqo; + + irqo = (bool)(DMAIntStatus & ((DMAIntControl >> 16) & 0x7F)); + irqo &= (DMAIntControl >> 23) & 1; + + // I think it's logical OR, not XOR/invert. Still kind of weird, maybe it actually does something more complicated? + //irqo ^= (DMAIntControl >> 15) & 1; + irqo |= (DMAIntControl >> 15) & 1; + + IRQOut = irqo; + IRQ_Assert(IRQ_DMA, irqo); +} + +void DMA_ResetTS(void) +{ + lastts = 0; +} + +void DMA_Power(void) +{ + lastts = 0; + + memset(DMACH, 0, sizeof(DMACH)); + + DMACycleCounter = 128; + + DMAControl = 0; + DMAIntControl = 0; + DMAIntStatus = 0; + RecalcIRQOut(); +} + +void PSX_SetDMASuckSuck(unsigned); + +static INLINE bool ChCan(const unsigned ch, const uint32 CRModeCache) +{ + switch(ch) + { + default: + abort(); + + case CH_MDEC_IN: + return(MDEC_DMACanWrite()); + + case CH_MDEC_OUT: + return(MDEC_DMACanRead()); + + case CH_GPU: + if(CRModeCache & 0x1) + return(GPU->DMACanWrite()); + else + return(true); + + case CH_CDC: + return(true); + + case CH_SPU: + return(true); + + case CH_FIVE: + return(false); + + case CH_OT: + return((bool)(DMACH[ch].ChanControl & (1U << 28))); + } +} + +static void RecalcHalt(void) +{ + bool Halt = false; + unsigned ch = 0; + + for(ch = 0; ch < 7; ch++) + { + if(DMACH[ch].ChanControl & (1U << 24)) + { + if(!(DMACH[ch].ChanControl & (7U << 8))) + { + if(DMACH[ch].WordCounter > 0) + { + Halt = true; + break; + } + } + +#if 0 + if(DMACH[ch].ChanControl & 0x100) // DMA doesn't hog the bus when this bit is set, though the DMA takes longer. + continue; + + if(ch == 4 || ch == 5) // Not sure if these channels will typically hog the bus or not...investigate. + continue; + + if(!(DMACH[ch].ChanControl & (1U << 10))) // Not sure about HOGGERYNESS with linked-list mode, and it likely wouldn't work well either in regards + // to GPU commands due to the rather large DMA update granularity. + { + if((DMACH[ch].WordCounter > 0) || ChCan(ch, DMACH[ch].ChanControl & 0x1)) + { + Halt = true; + break; + } + } +#endif + } + } + +#if 0 + if((DMACH[0].WordCounter || (DMACH[0].ChanControl & (1 << 24))) && (DMACH[0].ChanControl & 0x200) /*&& MDEC_DMACanWrite()*/) + Halt = true; + + if((DMACH[1].WordCounter || (DMACH[1].ChanControl & (1 << 24))) && (DMACH[1].ChanControl & 0x200) && (DMACH[1].WordCounter || MDEC_DMACanRead())) + Halt = true; + + if((DMACH[2].WordCounter || (DMACH[2].ChanControl & (1 << 24))) && (DMACH[2].ChanControl & 0x200) && ((DMACH[2].ChanControl & 0x1) && (DMACH[2].WordCounter || GPU->DMACanWrite()))) + Halt = true; + + if((DMACH[3].WordCounter || (DMACH[3].ChanControl & (1 << 24))) && !(DMACH[3].ChanControl & 0x100)) + Halt = true; + + if(DMACH[6].WordCounter || (DMACH[6].ChanControl & (1 << 24))) + Halt = true; +#endif + + //printf("Halt: %d\n", Halt); + + if(!Halt && (DMACH[2].ChanControl & (1U << 24)) && ((DMACH[2].ChanControl & 0x700) == 0x200) && ChCan(2, DMACH[2].ChanControl)) + { + unsigned tmp = DMACH[2].BlockControl & 0xFFFF; + + if(tmp > 0) + tmp--; + + if(tmp > 200) // Due to 8-bit limitations in the CPU core. + tmp = 200; + + PSX_SetDMASuckSuck(tmp); + } + else + PSX_SetDMASuckSuck(0); + + CPU->SetHalt(Halt); +} + + +static INLINE void ChRW(const unsigned ch, const uint32 CRModeCache, uint32 *V, int32 *offset) +{ + unsigned extra_cyc_overhead = 0; + + switch(ch) + { + default: + abort(); + break; + + case CH_MDEC_IN: + if(CRModeCache & 0x1) + MDEC_DMAWrite(*V); + else + *V = 0; + break; + + case CH_MDEC_OUT: + if(CRModeCache & 0x1) + { + } + else + *V = MDEC_DMARead(offset); + break; + + case CH_GPU: + if(CRModeCache & 0x1) + GPU->WriteDMA(*V); + else + *V = GPU->ReadDMA(); + break; + + case CH_CDC: + // 0x1f801018 affects CDC DMA timing. +#if 0 + if(CRModeCache & 0x100) // For CDC DMA(at least): When this bit is set, DMA controller doesn't appear to hog the (RAM?) bus. + { + if(CRModeCache & 0x00400000) // For CDC DMA(at least): When this bit is set, DMA controller appears to get even less bus time(or has a lower priority??) + { + DMACH[ch].ClockCounter -= 44 * 20 / 12; + } + else + { + DMACH[ch].ClockCounter -= 29 * 20 / 12; + } + } + else + { + DMACH[ch].ClockCounter -= 23 * 20 / 12; // (23 + 1) = 24. (Though closer to 24.5 or 24.4 on average per tests on a PS1) + } +#endif + if(CRModeCache & 0x1) + { + } + else + { + extra_cyc_overhead = 8; // FIXME: Test. + *V = CDC->DMARead(); // Note: Legend of Mana's opening movie is sensitive to DMA timing, including CDC. + } + break; + + case CH_SPU: + // 0x1f801014 affects SPU DMA timing. + // Wild conjecture about 0x1f801014: + // + // & 0x0000000F + // & 0x000001E0 --- Used if (& 0x20000000) == 0? + // & 0x00001000 --- Double total bus cycle time if value == 0? + // & 0x0f000000 --- (value << 1) 33MHz cycles, bus cycle extension(added to 4?)? + // & 0x20000000 --- + // + // + // TODO?: SPU DMA will "complete" much faster if there's a mismatch between the CHCR read/write mode bit and the SPU control register DMA mode. + // + // + // Investigate: SPU DMA doesn't seem to work right if the value written to 0x1F801DAA doesn't have the upper bit set to 1(0x8000) on a PS1. + + extra_cyc_overhead = 47; // Should be closer to 69, average, but actual timing is...complicated. + + if(CRModeCache & 0x1) + SPU->WriteDMA(*V); + else + *V = SPU->ReadDMA(); + break; + + case CH_FIVE: + if(CRModeCache & 0x1) + { + } + else + { + *V = 0; + } + break; + + case CH_OT: + if(DMACH[ch].WordCounter == 1) + *V = 0xFFFFFF; + else + *V = (DMACH[ch].CurAddr - 4) & 0x1FFFFF; + break; + } + + // GROSS APPROXIMATION, shoehorning multiple effects together, TODO separate(especially SPU and CDC) + DMACH[ch].ClockCounter -= std::max(extra_cyc_overhead, (CRModeCache & 0x100) ? 7 : 0); +} + +// +// Remember to handle an end condition on the same iteration of the while(DMACH[ch].ClockCounter > 0) loop that caused it, +// otherwise RecalcHalt() might take the CPU out of a halted state before the end-of-DMA is signaled(especially a problem considering our largeish +// DMA update timing granularity). +// +static INLINE void RunChannelI(const unsigned ch, const uint32 CRModeCache, int32 clocks) +{ + //const uint32 dc = (DMAControl >> (ch * 4)) & 0xF; + + DMACH[ch].ClockCounter += clocks; + + while(MDFN_LIKELY(DMACH[ch].ClockCounter > 0)) + { + if(DMACH[ch].WordCounter == 0) // Begin WordCounter reload. + { + if(!(DMACH[ch].ChanControl & (1 << 24))) // Needed for the forced-DMA-stop kludge(see DMA_Write()). + break; + + if(!ChCan(ch, CRModeCache)) + break; + + DMACH[ch].CurAddr = DMACH[ch].BaseAddr; + + if(CRModeCache & (1U << 10)) + { + uint32 header; + + if(MDFN_UNLIKELY(DMACH[ch].CurAddr & 0x800000)) + { + DMACH[ch].ChanControl &= ~(0x11 << 24); + DMAIntControl |= 0x8000; + RecalcIRQOut(); + break; + } + + header = MainRAM.ReadU32(DMACH[ch].CurAddr & 0x1FFFFC); + DMACH[ch].CurAddr = (DMACH[ch].CurAddr + 4) & 0xFFFFFF; + + DMACH[ch].WordCounter = header >> 24; + DMACH[ch].BaseAddr = header & 0xFFFFFF; + + // printf to debug Soul Reaver ;) + //if(DMACH[ch].WordCounter > 0x10) + // printf("What the lala? 0x%02x @ 0x%08x\n", DMACH[ch].WordCounter, DMACH[ch].CurAddr - 4); + + if(DMACH[ch].WordCounter) + DMACH[ch].ClockCounter -= 15; + else + DMACH[ch].ClockCounter -= 10; + + goto SkipPayloadStuff; // 3 cheers for gluten-free spaghetticode(necessary because the newly-loaded WordCounter might be 0, and we actually + // want 0 to mean 0 and not 65536 in this context)! + } + else + { + DMACH[ch].WordCounter = DMACH[ch].BlockControl & 0xFFFF; + + if(CRModeCache & (1U << 9)) + { + if(ch == 2) // Technically should apply to all channels, but since we don't implement CPU read penalties for channels other than 2 yet, it's like this to avoid making DMA longer than what games can handle. + DMACH[ch].ClockCounter -= 7; + + DMACH[ch].BlockControl = (DMACH[ch].BlockControl & 0xFFFF) | ((DMACH[ch].BlockControl - (1U << 16)) & 0xFFFF0000); + } + } + } // End WordCounter reload. + else if(CRModeCache & 0x100) // BLARGH BLARGH FISHWHALE + { + //printf("LoadWC: %u(oldWC=%u)\n", DMACH[ch].BlockControl & 0xFFFF, DMACH[ch].WordCounter); + //MDFN_DispMessage("SPOOOON\n"); + DMACH[ch].CurAddr = DMACH[ch].BaseAddr; + DMACH[ch].WordCounter = DMACH[ch].BlockControl & 0xFFFF; + } + + // + // Do the payload read/write + // + { + uint32 vtmp; + int32 voffs = 0; + + if(MDFN_UNLIKELY(DMACH[ch].CurAddr & 0x800000)) + { + DMACH[ch].ChanControl &= ~(0x11 << 24); + DMAIntControl |= 0x8000; + RecalcIRQOut(); + break; + } + + if(CRModeCache & 0x1) + vtmp = MainRAM.ReadU32(DMACH[ch].CurAddr & 0x1FFFFC); + + ChRW(ch, CRModeCache, &vtmp, &voffs); + + if(!(CRModeCache & 0x1)) + MainRAM.WriteU32((DMACH[ch].CurAddr + (voffs << 2)) & 0x1FFFFC, vtmp); + } + + if(CRModeCache & 0x2) + DMACH[ch].CurAddr = (DMACH[ch].CurAddr - 4) & 0xFFFFFF; + else + DMACH[ch].CurAddr = (DMACH[ch].CurAddr + 4) & 0xFFFFFF; + + DMACH[ch].WordCounter--; + DMACH[ch].ClockCounter--; + + SkipPayloadStuff: ; + + if(CRModeCache & 0x100) // BLARGH BLARGH WHALEFISH + { + DMACH[ch].BaseAddr = DMACH[ch].CurAddr; + DMACH[ch].BlockControl = (DMACH[ch].BlockControl & 0xFFFF0000) | DMACH[ch].WordCounter; + //printf("SaveWC: %u\n", DMACH[ch].WordCounter); + } + + // + // Handle channel end condition: + // + if(DMACH[ch].WordCounter == 0) + { + bool ChannelEndTC = false; + + if(!(DMACH[ch].ChanControl & (1 << 24))) // Needed for the forced-DMA-stop kludge(see DMA_Write()). + break; + + switch((CRModeCache >> 9) & 0x3) + { + case 0x0: + ChannelEndTC = true; + break; + + case 0x1: + DMACH[ch].BaseAddr = DMACH[ch].CurAddr; + if((DMACH[ch].BlockControl >> 16) == 0) + ChannelEndTC = true; + break; + + case 0x2: + case 0x3: // Not sure about 0x3. + if(DMACH[ch].BaseAddr == 0xFFFFFF) + ChannelEndTC = true; + break; + } + + if(ChannelEndTC) + { + DMACH[ch].ChanControl &= ~(0x11 << 24); + if(DMAIntControl & (1U << (16 + ch))) + { + DMAIntStatus |= 1U << ch; + RecalcIRQOut(); + } + break; + } + } + } + + if(DMACH[ch].ClockCounter > 0) + DMACH[ch].ClockCounter = 0; +} + +static INLINE void RunChannel(pscpu_timestamp_t timestamp, int32 clocks, int ch) +{ + // Mask out the bits that the DMA controller will modify during the course of operation. + const uint32 CRModeCache = DMACH[ch].ChanControl &~(0x11 << 24); + + switch(ch) + { + default: abort(); + + case 0: + if(MDFN_LIKELY(CRModeCache == 0x00000201)) + RunChannelI(0, 0x00000201, clocks); + else + RunChannelI(0, CRModeCache, clocks); + break; + + case 1: + if(MDFN_LIKELY(CRModeCache == 0x00000200)) + RunChannelI(1, 0x00000200, clocks); + else + RunChannelI(1, CRModeCache, clocks); + break; + + case 2: + if(MDFN_LIKELY(CRModeCache == 0x00000401)) + RunChannelI(2, 0x00000401, clocks); + else if(MDFN_LIKELY(CRModeCache == 0x00000201)) + RunChannelI(2, 0x00000201, clocks); + else if(MDFN_LIKELY(CRModeCache == 0x00000200)) + RunChannelI(2, 0x00000200, clocks); + else + RunChannelI(2, CRModeCache, clocks); + break; + + case 3: + if(MDFN_LIKELY(CRModeCache == 0x00000000)) + RunChannelI(3, 0x00000000, clocks); + else if(MDFN_LIKELY(CRModeCache == 0x00000100)) + RunChannelI(3, 0x00000100, clocks); + else + RunChannelI(3, CRModeCache, clocks); + break; + + case 4: + if(MDFN_LIKELY(CRModeCache == 0x00000201)) + RunChannelI(4, 0x00000201, clocks); + else if(MDFN_LIKELY(CRModeCache == 0x00000200)) + RunChannelI(4, 0x00000200, clocks); + else + RunChannelI(4, CRModeCache, clocks); + break; + + case 5: + RunChannelI(5, CRModeCache, clocks); + break; + + case 6: + if(MDFN_LIKELY(CRModeCache == 0x00000002)) + RunChannelI(6, 0x00000002, clocks); + else + RunChannelI(6, CRModeCache, clocks); + break; + } +} + +static INLINE int32 CalcNextEvent(int32 next_event) +{ + if(DMACycleCounter < next_event) + next_event = DMACycleCounter; + + return(next_event); +} + +pscpu_timestamp_t DMA_Update(const pscpu_timestamp_t timestamp) +{ +// uint32 dc = (DMAControl >> (ch * 4)) & 0xF; + int32 clocks = timestamp - lastts; + lastts = timestamp; + + GPU->Update(timestamp); + MDEC_Run(clocks); + + RunChannel(timestamp, clocks, 0); + RunChannel(timestamp, clocks, 1); + RunChannel(timestamp, clocks, 2); + RunChannel(timestamp, clocks, 3); + RunChannel(timestamp, clocks, 4); + RunChannel(timestamp, clocks, 6); + + DMACycleCounter -= clocks; + while(DMACycleCounter <= 0) + DMACycleCounter += 128; + + RecalcHalt(); + + return(timestamp + CalcNextEvent(0x10000000)); +} + +#if 0 +static void CheckLinkedList(uint32 addr) +{ + std::map zoom; + + do + { + if(zoom[addr]) + { + printf("Bad linked list: 0x%08x\n", addr); + break; + } + zoom[addr] = 1; + + uint32 header = MainRAM.ReadU32(addr & 0x1FFFFC); + + addr = header & 0xFFFFFF; + + } while(addr != 0xFFFFFF && !(addr & 0x800000)); +} +#endif + +void DMA_Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V) +{ + int ch = (A & 0x7F) >> 4; + + //if(ch == 2 || ch == 7) + //PSX_WARNING("[DMA] Write: %08x %08x, DMAIntStatus=%08x", A, V, DMAIntStatus); + + // FIXME if we ever have "accurate" bus emulation + V <<= (A & 3) * 8; + + DMA_Update(timestamp); + + if(ch == 7) + { + switch(A & 0xC) + { + case 0x0: //fprintf(stderr, "Global DMA control: 0x%08x\n", V); + DMAControl = V; + RecalcHalt(); + break; + + case 0x4: + //for(int x = 0; x < 7; x++) + //{ + // if(DMACH[x].WordCounter || (DMACH[x].ChanControl & (1 << 24))) + // { + // fprintf(stderr, "Write DMAIntControl while channel %d active: 0x%08x\n", x, V); + // } + //} + DMAIntControl = V & 0x00ff803f; + DMAIntStatus &= ~(V >> 24); + + //if(DMAIntStatus ^ (DMAIntStatus & (V >> 16))) + // fprintf(stderr, "DMAINT Fudge: %02x\n", DMAIntStatus ^ (DMAIntStatus & (V >> 16))); + DMAIntStatus &= (V >> 16); // THIS IS ALMOST CERTAINLY WRONG AND A HACK. Remove when CDC emulation is better. + RecalcIRQOut(); + break; + + default: PSX_WARNING("[DMA] Unknown write: %08x %08x", A, V); + break; + } + return; + } + switch(A & 0xC) + { + case 0x0: DMACH[ch].BaseAddr = V & 0xFFFFFF; + break; + + case 0x4: DMACH[ch].BlockControl = V; + break; + + case 0xC: + case 0x8: + { + uint32 OldCC = DMACH[ch].ChanControl; + + //printf("CHCR: %u, %08x --- 0x%08x\n", ch, V, DMACH[ch].BlockControl); + // + // Kludge for DMA timing granularity and other issues. Needs to occur before setting all bits of ChanControl to the new value, to accommodate the + // case of a game cancelling DMA and changing the type of DMA(read/write, etc.) at the same time. + // + if((DMACH[ch].ChanControl & (1 << 24)) && !(V & (1 << 24))) + { + DMACH[ch].ChanControl &= ~(1 << 24); // Clear bit before RunChannel(), so it will only finish the block it's on at most. + RunChannel(timestamp, 128 * 16, ch); + DMACH[ch].WordCounter = 0; + +#if 0 // TODO(maybe, need to work out worst-case performance for abnormally/brokenly large block sizes) + DMACH[ch].ClockCounter = (1 << 30); + RunChannel(timestamp, 1, ch); + DMACH[ch].ClockCounter = 0; +#endif + PSX_WARNING("[DMA] Forced stop for channel %d -- scanline=%d", ch, GPU->GetScanlineNum()); + //MDFN_DispMessage("[DMA] Forced stop for channel %d", ch); + } + + if(ch == 6) + DMACH[ch].ChanControl = (V & 0x51000000) | 0x2; + else + DMACH[ch].ChanControl = V & 0x71770703; + + if(!(OldCC & (1 << 24)) && (V & (1 << 24))) + { + //if(ch == 0 || ch == 1) + // PSX_WARNING("[DMA] Started DMA for channel=%d --- CHCR=0x%08x --- BCR=0x%08x --- scanline=%d", ch, DMACH[ch].ChanControl, DMACH[ch].BlockControl, GPU->GetScanlineNum()); + + DMACH[ch].WordCounter = 0; + DMACH[ch].ClockCounter = 0; + + // + // Viewpoint starts a short MEM->GPU LL DMA and apparently has race conditions that can cause a crash if it doesn't finish almost immediately( + // or at least very quickly, which the current DMA granularity has issues with, so run the channel ahead a bit to take of this issue and potentially + // games with similar issues). + // + // Though, Viewpoint isn't exactly a good game, so maybe we shouldn't bother? ;) + // + // Also, it's needed for RecalcHalt() to work with some semblance of workiness. + // + RunChannel(timestamp, 64, ch); //std::max(128 - DMACycleCounter, 1)); //64); //1); //128 - DMACycleCounter); + } + + RecalcHalt(); + } + break; + } + PSX_SetEventNT(PSX_EVENT_DMA, timestamp + CalcNextEvent(0x10000000)); +} + +uint32 DMA_Read(const pscpu_timestamp_t timestamp, uint32 A) +{ + int ch = (A & 0x7F) >> 4; + uint32 ret = 0; + + if(ch == 7) + { + switch(A & 0xC) + { + default: PSX_WARNING("[DMA] Unknown read: %08x", A); + break; + + case 0x0: ret = DMAControl; + break; + + case 0x4: ret = DMAIntControl | (DMAIntStatus << 24) | (IRQOut << 31); + break; + } + } + else switch(A & 0xC) + { + case 0x0: ret = DMACH[ch].BaseAddr; + break; + + case 0x4: ret = DMACH[ch].BlockControl; + break; + + case 0xC: + case 0x8: ret = DMACH[ch].ChanControl; + break; + + } + + ret >>= (A & 3) * 8; + + //PSX_WARNING("[DMA] Read: %08x %08x", A, ret); + + return(ret); +} + + +int DMA_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFVAR(DMACycleCounter), + SFVAR(DMAControl), + SFVAR(DMAIntControl), + SFVAR(DMAIntStatus), + SFVAR(IRQOut), + +#define SFDMACH(n) SFVARN(DMACH[n].BaseAddr, #n "BaseAddr"), \ + SFVARN(DMACH[n].BlockControl, #n "BlockControl"), \ + SFVARN(DMACH[n].ChanControl, #n "ChanControl"), \ + SFVARN(DMACH[n].CurAddr, #n "CurAddr"), \ + SFVARN(DMACH[n].WordCounter, #n "WordCounter"), \ + SFVARN(DMACH[n].ClockCounter, #n "ClockCounter") + + SFDMACH(0), + SFDMACH(1), + SFDMACH(2), + SFDMACH(3), + SFDMACH(4), + SFDMACH(5), + SFDMACH(6), + +#undef SFDMACH + + SFEND + }; + int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "DMA"); + + if(load) + { + + } + + return(ret); +} + + +} diff --git a/psx/octoshock/psx/dma.h b/psx/octoshock/psx/dma.h new file mode 100644 index 0000000000..abfeeb4194 --- /dev/null +++ b/psx/octoshock/psx/dma.h @@ -0,0 +1,24 @@ +#ifndef __MDFN_PSX_DMA_H +#define __MDFN_PSX_DMA_H + +namespace MDFN_IEN_PSX +{ + +bool DMA_GPUWriteActive(void); + +pscpu_timestamp_t DMA_Update(const pscpu_timestamp_t timestamp); +void DMA_Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V); +uint32 DMA_Read(const pscpu_timestamp_t timestamp, uint32 A); + +void DMA_ResetTS(void); + +void DMA_Power(void); + +void DMA_Init(void); +void DMA_Kill(void); + +int DMA_StateAction(StateMem *sm, int load, int data_only); + +} + +#endif diff --git a/psx/octoshock/psx/frontio.cpp b/psx/octoshock/psx/frontio.cpp new file mode 100644 index 0000000000..aa3e69d36e --- /dev/null +++ b/psx/octoshock/psx/frontio.cpp @@ -0,0 +1,1073 @@ +/* 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 "psx.h" +#include "frontio.h" + +#include "input/gamepad.h" +#include "input/dualanalog.h" +#include "input/dualshock.h" +#include "input/mouse.h" +#include "input/negcon.h" +#include "input/guncon.h" +#include "input/justifier.h" + +#include "input/memcard.h" + +#include "input/multitap.h" + +#define PSX_FIODBGINFO(format, ...) { /* printf(format " -- timestamp=%d -- PAD temp\n", ## __VA_ARGS__, timestamp); */ } + +namespace MDFN_IEN_PSX +{ + +InputDevice::InputDevice() : chair_r(0), chair_g(0), chair_b(0), draw_chair(0), chair_x(-1000), chair_y(-1000) +{ +} + +InputDevice::~InputDevice() +{ +} + +void InputDevice::Power(void) +{ +} + +int InputDevice::StateAction(StateMem* sm, int load, int data_only, const char* section_name) +{ + return(1); +} + + +void InputDevice::Update(const pscpu_timestamp_t timestamp) +{ + +} + +void InputDevice::ResetTS(void) +{ + +} + +void InputDevice::SetCrosshairsColor(uint32 color) +{ + chair_r = (color >> 16) & 0xFF; + chair_g = (color >> 8) & 0xFF; + chair_b = (color >> 0) & 0xFF; + + draw_chair = (color != (1 << 24)); +} + +INLINE void InputDevice::DrawCrosshairs(uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock) +{ + if(draw_chair && chair_y >= -8 && chair_y <= 8) + { + int32 ic; + int32 x_start, x_bound; + + if(chair_y == 0) + ic = pix_clock / 762925; + else + ic = 0; + + x_start = std::max(0, chair_x - ic); + x_bound = std::min(width, chair_x + ic + 1); + + for(int32 x = x_start; x < x_bound; x++) + { + int r, g, b, a; + int nr, ng, nb; + + format->DecodeColor(pixels[x], r, g, b, a); + + nr = (r + chair_r * 3) >> 2; + ng = (g + chair_g * 3) >> 2; + nb = (b + chair_b * 3) >> 2; + + if((int)((abs(r - nr) - 0x40) & (abs(g - ng) - 0x40) & (abs(b - nb) - 0x40)) < 0) + { + if((nr | ng | nb) & 0x80) + { + nr >>= 1; + ng >>= 1; + nb >>= 1; + } + else + { + nr ^= 0x80; + ng ^= 0x80; + nb ^= 0x80; + } + } + + pixels[x] = format->MakeColor(nr, ng, nb, a); + } + } +} + +bool InputDevice::RequireNoFrameskip(void) +{ + return(false); +} + +pscpu_timestamp_t InputDevice::GPULineHook(const pscpu_timestamp_t timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider) +{ + return(PSX_EVENT_MAXTS); +} + + +void InputDevice::UpdateInput(const void *data) +{ +} + + +void InputDevice::SetDTR(bool new_dtr) +{ + +} + +bool InputDevice::GetDSR(void) +{ + return(0); +} + +bool InputDevice::Clock(bool TxD, int32 &dsr_pulse_delay) +{ + dsr_pulse_delay = 0; + + return(1); +} + +uint32 InputDevice::GetNVSize(void) +{ + return(0); +} + +void InputDevice::ReadNV(uint8 *buffer, uint32 offset, uint32 count) +{ + +} + +void InputDevice::WriteNV(const uint8 *buffer, uint32 offset, uint32 count) +{ + +} + +uint64 InputDevice::GetNVDirtyCount(void) +{ + return(0); +} + +void InputDevice::ResetNVDirtyCount(void) +{ + +} + +static unsigned EP_to_MP(bool emulate_multitap[2], unsigned ep) +{ + if(!emulate_multitap[0] && emulate_multitap[1]) + { + if(ep == 0 || ep >= 5) + return(0); + else + return(1); + } + else + return(ep >= 4); +} + +static INLINE unsigned EP_to_SP(bool emulate_multitap[2], unsigned ep) +{ + if(!emulate_multitap[0] && emulate_multitap[1]) + { + if(ep == 0) + return(0); + else if(ep < 5) + return(ep - 1); + else + return(ep - 4); + } + else + return(ep & 0x3); +} + +void FrontIO::MapDevicesToPorts(void) +{ + if(emulate_multitap[0] && emulate_multitap[1]) + { + for(unsigned i = 0; i < 2; i++) + { + Ports[i] = DevicesTap[i]; + MCPorts[i] = DummyDevice; + } + } + else if(!emulate_multitap[0] && emulate_multitap[1]) + { + Ports[0] = Devices[0]; + MCPorts[0] = emulate_memcards[0] ? DevicesMC[0] : DummyDevice; + + Ports[1] = DevicesTap[1]; + MCPorts[1] = DummyDevice; + } + else if(emulate_multitap[0] && !emulate_multitap[1]) + { + Ports[0] = DevicesTap[0]; + MCPorts[0] = DummyDevice; + + Ports[1] = Devices[4]; + MCPorts[1] = emulate_memcards[4] ? DevicesMC[4] : DummyDevice; + } + else + { + for(unsigned i = 0; i < 2; i++) + { + Ports[i] = Devices[i]; + MCPorts[i] = emulate_memcards[i] ? DevicesMC[i] : DummyDevice; + } + } + + //printf("\n"); + for(unsigned i = 0; i < 8; i++) + { + unsigned mp = EP_to_MP(emulate_multitap, i); + + if(emulate_multitap[mp]) + DevicesTap[mp]->SetSubDevice(EP_to_SP(emulate_multitap, i), Devices[i], emulate_memcards[i] ? DevicesMC[i] : DummyDevice); + else + DevicesTap[mp]->SetSubDevice(EP_to_SP(emulate_multitap, i), DummyDevice, DummyDevice); + + //printf("%d-> multitap: %d, sub-port: %d\n", i, mp, EP_to_SP(emulate_multitap, i)); + } +} + +FrontIO::FrontIO(bool emulate_memcards_[8], bool emulate_multitap_[2]) +{ + memcpy(emulate_memcards, emulate_memcards_, sizeof(emulate_memcards)); + memcpy(emulate_multitap, emulate_multitap_, sizeof(emulate_multitap)); + + DummyDevice = new InputDevice(); + + for(unsigned i = 0; i < 8; i++) + { + DeviceData[i] = NULL; + Devices[i] = new InputDevice(); + DevicesMC[i] = Device_Memcard_Create(); + chair_colors[i] = 1 << 24; + Devices[i]->SetCrosshairsColor(chair_colors[i]); + } + + for(unsigned i = 0; i < 2; i++) + { + DevicesTap[i] = new InputDevice_Multitap(); + } + + MapDevicesToPorts(); +} + + +void FrontIO::SetCrosshairsColor(unsigned port, uint32 color) +{ + assert(port >= 0 && port < 8); + + chair_colors[port] = color; + Devices[port]->SetCrosshairsColor(color); +} + +FrontIO::~FrontIO() +{ + for(int i = 0; i < 8; i++) + { + if(Devices[i]) + { + delete Devices[i]; + Devices[i] = NULL; + } + if(DevicesMC[i]) + { + delete DevicesMC[i]; + DevicesMC[i] = NULL; + } + } + + for(unsigned i = 0; i < 2; i++) + { + if(DevicesTap[i]) + { + delete DevicesTap[i]; + DevicesTap[i] = NULL; + } + } + + if(DummyDevice) + { + delete DummyDevice; + DummyDevice = NULL; + } +} + +pscpu_timestamp_t FrontIO::CalcNextEventTS(pscpu_timestamp_t timestamp, int32 next_event) +{ + pscpu_timestamp_t ret; + + if(ClockDivider > 0 && ClockDivider < next_event) + next_event = ClockDivider; + + for(int i = 0; i < 4; i++) + if(dsr_pulse_delay[i] > 0 && next_event > dsr_pulse_delay[i]) + next_event = dsr_pulse_delay[i]; + + ret = timestamp + next_event; + + if(irq10_pulse_ts[0] < ret) + ret = irq10_pulse_ts[0]; + + if(irq10_pulse_ts[1] < ret) + ret = irq10_pulse_ts[1]; + + return(ret); +} + +static const uint8 ScaleShift[4] = { 0, 0, 4, 6 }; + +void FrontIO::CheckStartStopPending(pscpu_timestamp_t timestamp, bool skip_event_set) +{ + //const bool prior_ReceiveInProgress = ReceiveInProgress; + //const bool prior_TransmitInProgress = TransmitInProgress; + bool trigger_condition = false; + + trigger_condition = (ReceivePending && (Control & 0x4)) || (TransmitPending && (Control & 0x1)); + + if(trigger_condition) + { + if(ReceivePending) + { + ReceivePending = false; + ReceiveInProgress = true; + ReceiveBufferAvail = false; + ReceiveBuffer = 0; + ReceiveBitCounter = 0; + } + + if(TransmitPending) + { + TransmitPending = false; + TransmitInProgress = true; + TransmitBitCounter = 0; + } + + ClockDivider = std::max(0x20, (Baudrate << ScaleShift[Mode & 0x3]) & ~1); // Minimum of 0x20 is an emulation sanity check to prevent severe performance degradation. + //printf("CD: 0x%02x\n", ClockDivider); + } + + if(!(Control & 0x5)) + { + ReceiveInProgress = false; + TransmitInProgress = false; + } + + if(!ReceiveInProgress && !TransmitInProgress) + ClockDivider = 0; + + if(!(skip_event_set)) + PSX_SetEventNT(PSX_EVENT_FIO, CalcNextEventTS(timestamp, 0x10000000)); +} + +// DSR IRQ bit setting appears(from indirect tests on real PS1) to be level-sensitive, not edge-sensitive +INLINE void FrontIO::DoDSRIRQ(void) +{ + if(Control & 0x1000) + { + PSX_FIODBGINFO("[DSR] IRQ"); + istatus = true; + IRQ_Assert(IRQ_SIO, true); + } +} + + +void FrontIO::Write(pscpu_timestamp_t timestamp, uint32 A, uint32 V) +{ + assert(!(A & 0x1)); + + PSX_FIODBGINFO("[FIO] Write: %08x %08x", A, V); + + Update(timestamp); + + switch(A & 0xF) + { + case 0x0: + TransmitBuffer = V; + TransmitPending = true; + TransmitInProgress = false; + break; + + case 0x8: + Mode = V & 0x013F; + break; + + case 0xa: + if(ClockDivider > 0 && ((V & 0x2000) != (Control & 0x2000)) && ((Control & 0x2) == (V & 0x2)) ) + PSX_DBG(PSX_DBG_WARNING, "FIO device selection changed during comm %04x->%04x\n", Control, V); + + //printf("Control: %d, %04x\n", timestamp, V); + Control = V & 0x3F2F; + + if(V & 0x10) + { + istatus = false; + IRQ_Assert(IRQ_SIO, false); + } + + if(V & 0x40) // Reset + { + istatus = false; + IRQ_Assert(IRQ_SIO, false); + + ClockDivider = 0; + ReceivePending = false; + TransmitPending = false; + + ReceiveInProgress = false; + TransmitInProgress = false; + + ReceiveBufferAvail = false; + + TransmitBuffer = 0; + ReceiveBuffer = 0; + + ReceiveBitCounter = 0; + TransmitBitCounter = 0; + + Mode = 0; + Control = 0; + Baudrate = 0; + } + + Ports[0]->SetDTR((Control & 0x2) && !(Control & 0x2000)); + MCPorts[0]->SetDTR((Control & 0x2) && !(Control & 0x2000)); + Ports[1]->SetDTR((Control & 0x2) && (Control & 0x2000)); + MCPorts[1]->SetDTR((Control & 0x2) && (Control & 0x2000)); + +#if 1 +if(!((Control & 0x2) && !(Control & 0x2000))) +{ + dsr_pulse_delay[0] = 0; + dsr_pulse_delay[2] = 0; + dsr_active_until_ts[0] = -1; + dsr_active_until_ts[2] = -1; +} + +if(!((Control & 0x2) && (Control & 0x2000))) +{ + dsr_pulse_delay[1] = 0; + dsr_pulse_delay[3] = 0; + dsr_active_until_ts[1] = -1; + dsr_active_until_ts[3] = -1; +} + +#endif + // TODO: Uncomment out in the future once our CPU emulation is a bit more accurate with timing, to prevent causing problems with games + // that may clear the IRQ in an unsafe pattern that only works because its execution was slow enough to allow DSR to go inactive. (Whether or not + // such games even exist though is unknown!) + //if(timestamp < dsr_active_until_ts[0] || timestamp < dsr_active_until_ts[1] || timestamp < dsr_active_until_ts[2] || timestamp < dsr_active_until_ts[3]) + // DoDSRIRQ(); + + break; + + case 0xe: + Baudrate = V; + //printf("%02x\n", V); + //MDFN_DispMessage("%02x\n", V); + break; + } + + CheckStartStopPending(timestamp, false); +} + + +uint32 FrontIO::Read(pscpu_timestamp_t timestamp, uint32 A) +{ + uint32 ret = 0; + + assert(!(A & 0x1)); + + Update(timestamp); + + switch(A & 0xF) + { + case 0x0: + //printf("FIO Read: 0x%02x\n", ReceiveBuffer); + ret = ReceiveBuffer | (ReceiveBuffer << 8) | (ReceiveBuffer << 16) | (ReceiveBuffer << 24); + ReceiveBufferAvail = false; + ReceivePending = true; + ReceiveInProgress = false; + CheckStartStopPending(timestamp, false); + break; + + case 0x4: + ret = 0; + + if(!TransmitPending && !TransmitInProgress) + ret |= 0x1; + + if(ReceiveBufferAvail) + ret |= 0x2; + + if(timestamp < dsr_active_until_ts[0] || timestamp < dsr_active_until_ts[1] || timestamp < dsr_active_until_ts[2] || timestamp < dsr_active_until_ts[3]) + ret |= 0x80; + + if(istatus) + ret |= 0x200; + + break; + + case 0x8: + ret = Mode; + break; + + case 0xa: + ret = Control; + break; + + case 0xe: + ret = Baudrate; + break; + } + + if((A & 0xF) != 0x4) + PSX_FIODBGINFO("[FIO] Read: %08x %08x", A, ret); + + return(ret); +} + +pscpu_timestamp_t FrontIO::Update(pscpu_timestamp_t timestamp) +{ + int32 clocks = timestamp - lastts; + bool need_start_stop_check = false; + + for(int i = 0; i < 4; i++) + if(dsr_pulse_delay[i] > 0) + { + dsr_pulse_delay[i] -= clocks; + if(dsr_pulse_delay[i] <= 0) + { + dsr_active_until_ts[i] = timestamp + 32 + dsr_pulse_delay[i]; + DoDSRIRQ(); + } + } + + for(int i = 0; i < 2; i++) + { + if(timestamp >= irq10_pulse_ts[i]) + { + //printf("Yay: %d %u\n", i, timestamp); + irq10_pulse_ts[i] = PSX_EVENT_MAXTS; + IRQ_Assert(IRQ_PIO, true); + IRQ_Assert(IRQ_PIO, false); + } + } + + if(ClockDivider > 0) + { + ClockDivider -= clocks; + + while(ClockDivider <= 0) + { + if(ReceiveInProgress || TransmitInProgress) + { + bool rxd = 0, txd = 0; + const uint32 BCMask = 0x07; + + if(TransmitInProgress) + { + txd = (TransmitBuffer >> TransmitBitCounter) & 1; + TransmitBitCounter = (TransmitBitCounter + 1) & BCMask; + if(!TransmitBitCounter) + { + need_start_stop_check = true; + PSX_FIODBGINFO("[FIO] Data transmitted: %08x", TransmitBuffer); + TransmitInProgress = false; + + if(Control & 0x400) + { + istatus = true; + IRQ_Assert(IRQ_SIO, true); + } + } + } + + rxd = Ports[0]->Clock(txd, dsr_pulse_delay[0]) & Ports[1]->Clock(txd, dsr_pulse_delay[1]) & + MCPorts[0]->Clock(txd, dsr_pulse_delay[2]) & MCPorts[1]->Clock(txd, dsr_pulse_delay[3]); + + if(ReceiveInProgress) + { + ReceiveBuffer &= ~(1 << ReceiveBitCounter); + ReceiveBuffer |= rxd << ReceiveBitCounter; + + ReceiveBitCounter = (ReceiveBitCounter + 1) & BCMask; + + if(!ReceiveBitCounter) + { + need_start_stop_check = true; + PSX_FIODBGINFO("[FIO] Data received: %08x", ReceiveBuffer); + + ReceiveInProgress = false; + ReceiveBufferAvail = true; + + if(Control & 0x800) + { + istatus = true; + IRQ_Assert(IRQ_SIO, true); + } + } + } + ClockDivider += std::max(0x20, (Baudrate << ScaleShift[Mode & 0x3]) & ~1); // Minimum of 0x20 is an emulation sanity check to prevent severe performance degradation. + } + else + break; + } + } + + + lastts = timestamp; + + + if(need_start_stop_check) + { + CheckStartStopPending(timestamp, true); + } + + return(CalcNextEventTS(timestamp, 0x10000000)); +} + +void FrontIO::ResetTS(void) +{ + for(int i = 0; i < 8; i++) + { + Devices[i]->Update(lastts); // Maybe eventually call Update() from FrontIO::Update() and remove this(but would hurt speed)? + Devices[i]->ResetTS(); + + DevicesMC[i]->Update(lastts); // Maybe eventually call Update() from FrontIO::Update() and remove this(but would hurt speed)? + DevicesMC[i]->ResetTS(); + } + + for(int i = 0; i < 2; i++) + { + DevicesTap[i]->Update(lastts); + DevicesTap[i]->ResetTS(); + } + + for(int i = 0; i < 2; i++) + { + if(irq10_pulse_ts[i] != PSX_EVENT_MAXTS) + irq10_pulse_ts[i] -= lastts; + } + + for(int i = 0; i < 4; i++) + { + if(dsr_active_until_ts[i] >= 0) + { + dsr_active_until_ts[i] -= lastts; + //printf("SPOOONY: %d %d\n", i, dsr_active_until_ts[i]); + } + } + lastts = 0; +} + + +void FrontIO::Power(void) +{ + for(int i = 0; i < 4; i++) + { + dsr_pulse_delay[i] = 0; + dsr_active_until_ts[i] = -1; + } + + for(int i = 0; i < 2; i++) + { + irq10_pulse_ts[i] = PSX_EVENT_MAXTS; + } + + lastts = 0; + + // + // + + ClockDivider = 0; + + ReceivePending = false; + TransmitPending = false; + + ReceiveInProgress = false; + TransmitInProgress = false; + + ReceiveBufferAvail = false; + + TransmitBuffer = 0; + ReceiveBuffer = 0; + + ReceiveBitCounter = 0; + TransmitBitCounter = 0; + + Mode = 0; + Control = 0; + Baudrate = 0; + + for(int i = 0; i < 8; i++) + { + Devices[i]->Power(); + DevicesMC[i]->Power(); + } + + istatus = false; +} + +void FrontIO::UpdateInput(void) +{ + for(int i = 0; i < 8; i++) + Devices[i]->UpdateInput(DeviceData[i]); +} + +void FrontIO::SetInput(unsigned int port, const char *type, void *ptr) +{ + delete Devices[port]; + Devices[port] = NULL; + + if(port < 2) + irq10_pulse_ts[port] = PSX_EVENT_MAXTS; + + //DAW + //if(!strcmp(type, "gamepad") || !strcmp(type, "dancepad")) + Devices[port] = Device_Gamepad_Create(); + //else if(!strcmp(type, "dualanalog")) + // Devices[port] = Device_DualAnalog_Create(false); + //else if(!strcmp(type, "analogjoy")) + // Devices[port] = Device_DualAnalog_Create(true); + //else if(!strcmp(type, "dualshock")) + //{ + // char name[256]; + // trio_snprintf(name, 256, _("DualShock on port %u"), port + 1); + // Devices[port] = Device_DualShock_Create(std::string(name)); + //} + //else if(!strcmp(type, "mouse")) + // Devices[port] = Device_Mouse_Create(); + //else if(!strcmp(type, "negcon")) + // Devices[port] = Device_neGcon_Create(); + //else if(!strcmp(type, "guncon")) + // Devices[port] = Device_GunCon_Create(); + //else if(!strcmp(type, "justifier")) + // Devices[port] = Device_Justifier_Create(); + //else + // Devices[port] = new InputDevice(); + + //Devices[port]->SetCrosshairsColor(chair_colors[port]); + DeviceData[port] = ptr; + + MapDevicesToPorts(); +} + +uint64 FrontIO::GetMemcardDirtyCount(unsigned int which) +{ + assert(which < 8); + + return(DevicesMC[which]->GetNVDirtyCount()); +} + +void FrontIO::LoadMemcard(unsigned int which, const char *path) +{ + //assert(which < 8); + + //try + //{ + // if(DevicesMC[which]->GetNVSize()) + // { + // FileStream mf(path, FileStream::MODE_READ); + // std::vector tmpbuf; + + // tmpbuf.resize(DevicesMC[which]->GetNVSize()); + + // if(mf.size() != (int64)tmpbuf.size()) + // throw(MDFN_Error(0, _("Memory card file \"%s\" is an incorrect size(%d bytes). The correct size is %d bytes."), path, (int)mf.size(), (int)tmpbuf.size())); + + // mf.read(&tmpbuf[0], tmpbuf.size()); + + // DevicesMC[which]->WriteNV(&tmpbuf[0], 0, tmpbuf.size()); + // DevicesMC[which]->ResetNVDirtyCount(); // There's no need to rewrite the file if it's the same data. + // } + //} + //catch(MDFN_Error &e) + //{ + // if(e.GetErrno() != ENOENT) + // throw(e); + //} +} + +void FrontIO::SaveMemcard(unsigned int which, const char *path) +{ + //assert(which < 8); + + //if(DevicesMC[which]->GetNVSize() && DevicesMC[which]->GetNVDirtyCount()) + //{ + // FileStream mf(path, FileStream::MODE_WRITE); // TODO: MODE_WRITE_ATOMIC_OVERWRITE + // std::vector tmpbuf; + + // tmpbuf.resize(DevicesMC[which]->GetNVSize()); + + // DevicesMC[which]->ReadNV(&tmpbuf[0], 0, tmpbuf.size()); + // mf.write(&tmpbuf[0], tmpbuf.size()); + + // mf.close(); // Call before resetting the NV dirty count! + + // DevicesMC[which]->ResetNVDirtyCount(); + //} +} + +int FrontIO::StateAction(StateMem* sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFVAR(ClockDivider), + + SFVAR(ReceivePending), + SFVAR(TransmitPending), + + SFVAR(ReceiveInProgress), + SFVAR(TransmitInProgress), + + SFVAR(ReceiveBufferAvail), + + SFVAR(ReceiveBuffer), + SFVAR(TransmitBuffer), + + SFVAR(ReceiveBitCounter), + SFVAR(TransmitBitCounter), + + SFVAR(Mode), + SFVAR(Control), + SFVAR(Baudrate), + + SFVAR(istatus), + + // FIXME: Step mode save states. + SFARRAY32(irq10_pulse_ts, sizeof(irq10_pulse_ts) / sizeof(irq10_pulse_ts[0])), + SFARRAY32(dsr_pulse_delay, sizeof(dsr_pulse_delay) / sizeof(dsr_pulse_delay[0])), + SFARRAY32(dsr_active_until_ts, sizeof(dsr_active_until_ts) / sizeof(dsr_active_until_ts[0])), + + SFEND + }; + + int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "FIO"); + + for(unsigned i = 0; i < 8; i++) + { + static const char* labels[] = { + "FIODEV0","FIODEV1","FIODEV2","FIODEV3","FIODEV4","FIODEV5","FIODEV6","FIODEV7" + }; + + ret &= Devices[i]->StateAction(sm, load, data_only, labels[i]); + } + + for(unsigned i = 0; i < 8; i++) + { + static const char* labels[] = { + "FIOMC0","FIOMC1","FIOMC2","FIOMC3","FIOMC4","FIOMC5","FIOMC6","FIOMC7" + }; + + + ret &= DevicesMC[i]->StateAction(sm, load, data_only, labels[i]); + } + + for(unsigned i = 0; i < 2; i++) + { + static const char* labels[] = { + "FIOTAP0","FIOTAP1", + }; + + ret &= DevicesTap[i]->StateAction(sm, load, data_only, labels[i]); + } + + if(load) + { + IRQ_Assert(IRQ_SIO, istatus); + } + + return(ret); +} + +bool FrontIO::RequireNoFrameskip(void) +{ + for(unsigned i = 0; i < 8; i++) + if(Devices[i]->RequireNoFrameskip()) + return(true); + + return(false); +} + +void FrontIO::GPULineHook(const pscpu_timestamp_t timestamp, const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider) +{ + Update(timestamp); + + for(unsigned i = 0; i < 8; i++) + { + pscpu_timestamp_t plts = Devices[i]->GPULineHook(line_timestamp, vsync, pixels, format, width, pix_clock_offset, pix_clock, pix_clock_divider); + + if(i < 2) + { + irq10_pulse_ts[i] = plts; + + if(irq10_pulse_ts[i] <= timestamp) + { + irq10_pulse_ts[i] = PSX_EVENT_MAXTS; + IRQ_Assert(IRQ_PIO, true); + IRQ_Assert(IRQ_PIO, false); + } + } + } + + // + // Draw crosshairs in a separate pass so the crosshairs won't mess up the color evaluation of later lightun GPULineHook()s. + // + if(pixels && pix_clock) + { + for(unsigned i = 0; i < 8; i++) + { + Devices[i]->DrawCrosshairs(pixels, format, width, pix_clock); + } + } + + PSX_SetEventNT(PSX_EVENT_FIO, CalcNextEventTS(timestamp, 0x10000000)); +} + +static InputDeviceInfoStruct InputDeviceInfoPSXPort[] = +{ + // None + { + "none", + "none", + NULL, + NULL, + 0, + NULL + }, + + // Gamepad(SCPH-1080) + { + "gamepad", + "Digital Gamepad", + "PlayStation digital gamepad; SCPH-1080.", + NULL, + sizeof(Device_Gamepad_IDII) / sizeof(InputDeviceInputInfoStruct), + Device_Gamepad_IDII, + }, + + // Dual Shock Gamepad(SCPH-1200) + { + "dualshock", + "DualShock", + "DualShock gamepad; SCPH-1200. Emulation in Mednafen includes the analog mode toggle button. Rumble is emulated, but currently only supported on Linux, and MS Windows via the XInput API and XInput-compatible gamepads/joysticks. If you're having trouble getting rumble to work on Linux, see if Mednafen is printing out error messages during startup regarding /dev/input/event*, and resolve the issue(s) as necessary.", + NULL, + sizeof(Device_DualShock_IDII) / sizeof(InputDeviceInputInfoStruct), + Device_DualShock_IDII, + }, + + // Dual Analog Gamepad(SCPH-1180), forced to analog mode. + { + "dualanalog", + "Dual Analog", + "Dual Analog gamepad; SCPH-1180. It is the predecessor/prototype to the more advanced DualShock. Emulated in Mednafen as forced to analog mode, and without rumble.", + NULL, + sizeof(Device_DualAnalog_IDII) / sizeof(InputDeviceInputInfoStruct), + Device_DualAnalog_IDII, + }, + + + // Analog joystick(SCPH-1110), forced to analog mode - emulated through a tweak to dual analog gamepad emulation. + { + "analogjoy", + "Analog Joystick", + "Flight-game-oriented dual-joystick controller; SCPH-1110. Emulated in Mednafen as forced to analog mode.", + NULL, + sizeof(Device_AnalogJoy_IDII) / sizeof(InputDeviceInputInfoStruct), + Device_AnalogJoy_IDII, + }, + + { + "mouse", + "Mouse", + NULL, + NULL, + sizeof(Device_Mouse_IDII) / sizeof(InputDeviceInputInfoStruct), + Device_Mouse_IDII, + }, + + { + "negcon", + "neGcon", + "Namco's unconventional twisty racing-game-oriented gamepad; NPC-101.", + NULL, + sizeof(Device_neGcon_IDII) / sizeof(InputDeviceInputInfoStruct), + Device_neGcon_IDII, + }, + + { + "guncon", + "GunCon", + "Namco's light gun; NPC-103.", + NULL, + sizeof(Device_GunCon_IDII) / sizeof(InputDeviceInputInfoStruct), + Device_GunCon_IDII, + }, + + { + "justifier", + "Konami Justifier", + "Konami's light gun; SLUH-00017. Rumored to be wrought of the coagulated rage of all who tried to shoot The Dog. If the game you want to play supports the \"GunCon\", you should use that instead. NOTE: Currently does not work properly when on any of ports 1B-1D and 2B-2D.", + NULL, + sizeof(Device_Justifier_IDII) / sizeof(InputDeviceInputInfoStruct), + Device_Justifier_IDII, + }, + + { + "dancepad", + "Dance Pad", + "Dingo Dingo Rodeo!", + NULL, + sizeof(Device_Dancepad_IDII) / sizeof(InputDeviceInputInfoStruct), + Device_Dancepad_IDII, + }, + +}; + +static const InputPortInfoStruct PortInfo[] = +{ + { "port1", "Virtual Port 1", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" }, + { "port2", "Virtual Port 2", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" }, + { "port3", "Virtual Port 3", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" }, + { "port4", "Virtual Port 4", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" }, + { "port5", "Virtual Port 5", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" }, + { "port6", "Virtual Port 6", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" }, + { "port7", "Virtual Port 7", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" }, + { "port8", "Virtual Port 8", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" }, +}; + +InputInfoStruct FIO_InputInfo = +{ + sizeof(PortInfo) / sizeof(InputPortInfoStruct), + PortInfo +}; + + +} diff --git a/psx/octoshock/psx/frontio.h b/psx/octoshock/psx/frontio.h new file mode 100644 index 0000000000..c02ecbd3f8 --- /dev/null +++ b/psx/octoshock/psx/frontio.h @@ -0,0 +1,151 @@ +#ifndef __MDFN_PSX_FRONTIO_H +#define __MDFN_PSX_FRONTIO_H + +namespace MDFN_IEN_PSX +{ + +class InputDevice_Multitap; + +class InputDevice +{ + public: + + InputDevice(); + virtual ~InputDevice(); + + virtual void Power(void); + virtual void UpdateInput(const void *data); + virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name); + + virtual bool RequireNoFrameskip(void); + + // Divide mouse X coordinate by pix_clock_divider in the lightgun code to get the coordinate in pixel(clocks). + virtual pscpu_timestamp_t GPULineHook(const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider); + + virtual void Update(const pscpu_timestamp_t timestamp); // Partially-implemented, don't rely on for timing any more fine-grained than a video frame for now. + virtual void ResetTS(void); + + void DrawCrosshairs(uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock); + // + // + // + virtual void SetCrosshairsColor(uint32 color); + + // + // + // + virtual void SetDTR(bool new_dtr); + virtual bool GetDSR(void); // Currently unused. + + virtual bool Clock(bool TxD, int32 &dsr_pulse_delay); + + // + // + virtual uint32 GetNVSize(void); + virtual void ReadNV(uint8 *buffer, uint32 offset, uint32 count); + virtual void WriteNV(const uint8 *buffer, uint32 offset, uint32 count); + + // + // Dirty count should be incremented on each call to a method this class that causes at least 1 write to occur to the + // nonvolatile memory(IE Clock() in the correct command phase, and WriteNV()). + // + virtual uint64 GetNVDirtyCount(void); + virtual void ResetNVDirtyCount(void); + + private: + unsigned chair_r, chair_g, chair_b; + bool draw_chair; + protected: + int32 chair_x, chair_y; +}; + +class FrontIO +{ + public: + + FrontIO(bool emulate_memcards_[8], bool emulate_multitap_[2]); + ~FrontIO(); + + void Power(void); + void Write(pscpu_timestamp_t timestamp, uint32 A, uint32 V); + uint32 Read(pscpu_timestamp_t timestamp, uint32 A); + pscpu_timestamp_t CalcNextEventTS(pscpu_timestamp_t timestamp, int32 next_event); + pscpu_timestamp_t Update(pscpu_timestamp_t timestamp); + void ResetTS(void); + + bool RequireNoFrameskip(void); + void GPULineHook(const pscpu_timestamp_t timestamp, const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider); + + void UpdateInput(void); + void SetInput(unsigned int port, const char *type, void *ptr); + void SetCrosshairsColor(unsigned port, uint32 color); + + uint64 GetMemcardDirtyCount(unsigned int which); + void LoadMemcard(unsigned int which, const char *path); + void SaveMemcard(unsigned int which, const char *path); //, bool force_save = false); + + int StateAction(StateMem* sm, int load, int data_only); + + private: + + void DoDSRIRQ(void); + void CheckStartStopPending(pscpu_timestamp_t timestamp, bool skip_event_set = false); + + void MapDevicesToPorts(void); + + bool emulate_memcards[8]; + bool emulate_multitap[2]; + + InputDevice *Ports[2]; + InputDevice *MCPorts[2]; + + InputDevice *DummyDevice; + InputDevice_Multitap *DevicesTap[2]; + + InputDevice *Devices[8]; + void *DeviceData[8]; + + InputDevice *DevicesMC[8]; + + // + // + // + + int32 ClockDivider; + + bool ReceivePending; + bool TransmitPending; + + bool ReceiveInProgress; + bool TransmitInProgress; + + bool ReceiveBufferAvail; + + uint8 ReceiveBuffer; + uint8 TransmitBuffer; + + int32 ReceiveBitCounter; + int32 TransmitBitCounter; + + uint16 Mode; + uint16 Control; + uint16 Baudrate; + + + bool istatus; + // + // + pscpu_timestamp_t irq10_pulse_ts[2]; + + int32 dsr_pulse_delay[4]; + int32 dsr_active_until_ts[4]; + int32 lastts; + // + // + uint32 chair_colors[8]; +}; + +extern InputInfoStruct FIO_InputInfo; + +} +#endif diff --git a/psx/octoshock/psx/gpu.cpp b/psx/octoshock/psx/gpu.cpp new file mode 100644 index 0000000000..f5d0eb68fb --- /dev/null +++ b/psx/octoshock/psx/gpu.cpp @@ -0,0 +1,1691 @@ +/* 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 "psx.h" +#include "timer.h" + +/* + TODO: + Test and clean up line, particularly polyline, drawing. + + "abe" transparency testing might be not correct, the transparency in regards to mask bit setting and evaluation may not be correct. + + Not everything is returned in the status port read yet(double check). + + "dfe" bit of drawing mode is probably not implemented 100% correctly. + + Initialize more stuff in the Power() function. + + Fix triangle span rendering order(it's bottom-to-up sometimes on the real thing, to avoid negative x step/increment values). +*/ + +/* + GPU display timing master clock is nominally 53.693182 MHz for NTSC PlayStations, and 53.203425 MHz for PAL PlayStations. + + Non-interlaced NTSC mode line timing notes(real-world times calculated via PS1 timer and math with nominal CPU clock value): + + 263 lines per frame + + ~16714.85 us per frame, average. + ~63.55456 us per line, average. + + Multiplying the results of counter 0 in pixel clock mode by the clock divider of the current dot clock mode/width gives a result that's slightly less + than expected; the dot clock divider is probably being reset each scanline. + + Non-interlaced PAL mode(but with an NTSC source clock in an NTSC PS1; calculated same way as NTSC values): + + 314 lines per frame + + ~19912.27 us per frame, average. + ~63.41486 us per line, average. + + FB X and Y display positions can be changed during active display; and Y display position appears to be treated as an offset to the current Y readout + position that gets reset around vblank time. + +*/ + +/* + Known problematic games to do regression testing on: + + Dukes of Hazzard: Racing For Home + Sensitive about the GPU busy status flag being set long enough; double-check if we ever make CPU emulation more timing-accurate( + the fix will likely just involve reducing the timing granularity for DMA and GPU updates). + + Final Fantasy 7 + WHERE DO I BEGIN?! (Currently broken as of Jan. 1, 2012) + + Pro Pinball (series) + Sensitive to correct interlace and draw line skipping emulation. + + Valkyrie Profile + Battle scenes will go all kaka with no graphics updates if GPU LL DMA completes too soon. + +*/ + +/* + November 29, 2012 notes: + + PAL mode can be turned on, and then off again, mid-frame(creates a neat effect). + + Pixel clock can be changed mid-frame with effect(the effect is either instantaneous, or cached at some point in the scanline, not tested to see which); + interestingly, alignment is off on a PS1 when going 5MHz->10MHz>5MHz with a grid image. + + Vertical start and end can be changed during active display, with effect(though it needs to be vs0->ve0->vs1->ve1->..., vs0->vs1->ve0 doesn't apparently do anything + different from vs0->ve0. +*/ + +namespace MDFN_IEN_PSX +{ +//FILE *fp; + +static const int32 dither_table[4][4] = +{ + { -4, 0, -3, 1 }, + { 2, -2, 3, -1 }, + { -3, 1, -4, 0 }, + { 3, -1, 2, -2 }, +}; + +PS_GPU::PS_GPU(bool pal_clock_and_tv, int sls, int sle) : BlitterFIFO(0x20) // 0x10 on actual PS1 GPU, 0x20 here(see comment at top of gpu.h) // 0x10) +{ + HardwarePALType = pal_clock_and_tv; + + for(int y = 0; y < 4; y++) + for(int x = 0; x < 4; x++) + for(int v = 0; v < 512; v++) + { + int value = v + dither_table[y][x]; + + value >>= 3; + + if(value < 0) + value = 0; + + if(value > 0x1F) + value = 0x1F; + + DitherLUT[y][x][v] = value; + } + + if(HardwarePALType == false) // NTSC clock + { + GPUClockRatio = 103896; // 65536 * 53693181.818 / (44100 * 768) + } + else // PAL clock + { + GPUClockRatio = 102948; // 65536 * 53203425 / (44100 * 768) + } + + memset(RGB8SAT_Under, 0, sizeof(RGB8SAT_Under)); + + for(int i = 0; i < 256; i++) + RGB8SAT[i] = i; + + memset(RGB8SAT_Over, 0xFF, sizeof(RGB8SAT_Over)); + + LineVisFirst = sls; + LineVisLast = sle; +} + +PS_GPU::~PS_GPU() +{ + +} + +void PS_GPU::FillVideoParams(MDFNGI* gi) +{ + if(HardwarePALType) + { + gi->lcm_width = 2800; + gi->lcm_height = (LineVisLast + 1 - LineVisFirst) * 2; //576; + + gi->nominal_width = 377; // Dunno. :( + gi->nominal_height = LineVisLast + 1 - LineVisFirst; //288; + + gi->fb_width = 768; + gi->fb_height = 576; + + gi->fps = 836203078; + + gi->VideoSystem = VIDSYS_PAL; + } + else + { + gi->lcm_width = 2800; + gi->lcm_height = (LineVisLast + 1 - LineVisFirst) * 2; //480; + + gi->nominal_width = 320; + gi->nominal_height = LineVisLast + 1 - LineVisFirst; //240; + + gi->fb_width = 768; + gi->fb_height = 480; + + gi->fps = 1005643085; + + gi->VideoSystem = VIDSYS_NTSC; + } + + + // + // For Justifier and Guncon. + // + gi->mouse_scale_x = (float)gi->lcm_width / gi->nominal_width; + gi->mouse_offs_x = 0; + + gi->mouse_scale_y = 1.0; + gi->mouse_offs_y = LineVisFirst; +} + +void PS_GPU::SoftReset(void) // Control command 0x00 +{ + IRQPending = false; + IRQ_Assert(IRQ_GPU, IRQPending); + + DMAControl = 0; + + if(DrawTimeAvail < 0) + DrawTimeAvail = 0; + + BlitterFIFO.Flush(); + InCmd = INCMD_NONE; + + DisplayOff = 1; + DisplayFB_XStart = 0; + DisplayFB_YStart = 0; + + if(HardwarePALType) + { + DisplayMode = 0x08; + + // FIXME, timing values(I need a PAL PS1 to derive them); for now, just copy the NTSC ones. + HorizStart = 0x200; + HorizEnd = 0xC00; + + VertStart = 0x10; + VertEnd = 0x100; + } + else + { + DisplayMode = 0; + + HorizStart = 0x200; + HorizEnd = 0xC00; + + VertStart = 0x10; + VertEnd = 0x100; + } + + // + TexPageX = 0; + TexPageY = 0; + + SpriteFlip = 0; + + abr = 0; + TexMode = 0; + + dtd = 0; + dfe = 0; + + // + tww = 0; + twh = 0; + twx = 0; + twy = 0; + + RecalcTexWindowLUT(); + + // + ClipX0 = 0; + ClipY0 = 0; + + // + ClipX1 = 0; + ClipY1 = 0; + + // + OffsX = 0; + OffsY = 0; + + // + MaskSetOR = 0; + MaskEvalAND = 0; +} + +void PS_GPU::Power(void) +{ + memset(GPURAM, 0, sizeof(GPURAM)); + + DMAControl = 0; + + ClipX0 = 0; + ClipY0 = 0; + ClipX1 = 1023; + ClipY1 = 1023; + + OffsX = 0; + OffsY = 0; + + dtd = false; + dfe = false; + + MaskSetOR = 0; + MaskEvalAND = 0; + + tww = 0; + twh = 0; + twx = 0; + twy = 0; + + RecalcTexWindowLUT(); + + TexPageX = 0; + TexPageY = 0; + SpriteFlip = 0; + + abr = 0; + TexMode = 0; + + BlitterFIFO.Flush(); + + InCmd = INCMD_NONE; + FBRW_X = 0; + FBRW_Y = 0; + FBRW_W = 0; + FBRW_H = 0; + FBRW_CurY = 0; + FBRW_CurX = 0; + + DisplayMode = 0; + DisplayOff = 1; + DisplayFB_XStart = 0; + DisplayFB_YStart = 0; + + HorizStart = 0; + HorizEnd = 0; + + VertStart = 0; + VertEnd = 0; + + // + // + // + DisplayFB_CurYOffset = 0; + DisplayFB_CurLineYReadout = 0; + InVBlank = true; + + // TODO: factor out in a separate function. + LinesPerField = 263; + + // + // + // + scanline = 0; + field = 0; + field_ram_readout = 0; + PhaseChange = 0; + + // + // + // + DotClockCounter = 0; + GPUClockCounter = 0; + LineClockCounter = 3412 - 200; + LinePhase = 0; + + DrawTimeAvail = 0; + + lastts = 0; + + SoftReset(); + + IRQ_Assert(IRQ_VBLANK, InVBlank); + TIMER_SetVBlank(InVBlank); +} + +void PS_GPU::ResetTS(void) +{ + lastts = 0; +} + +template +INLINE void PS_GPU::PlotPixel(int32 x, int32 y, uint16 fore_pix) +{ + y &= 511; // More Y precision bits than GPU RAM installed in (non-arcade, at least) Playstation hardware. + + if(BlendMode >= 0 && (fore_pix & 0x8000)) + { + uint16 bg_pix = GPURAM[y][x]; // Don't use bg_pix for mask evaluation, it's modified in blending code paths. + uint16 pix; // = fore_pix & 0x8000; + +/* + static const int32 tab[4][2] = + { + { 2, 2 }, + { 4, 4 }, + { 4, -4 }, + { 4, 1 } + }; +*/ + // Efficient 15bpp pixel math algorithms from blargg + switch(BlendMode) + { + case 0: + bg_pix |= 0x8000; + pix = ((fore_pix + bg_pix) - ((fore_pix ^ bg_pix) & 0x0421)) >> 1; + break; + + case 1: + { + bg_pix &= ~0x8000; + + uint32 sum = fore_pix + bg_pix; + uint32 carry = (sum - ((fore_pix ^ bg_pix) & 0x8421)) & 0x8420; + + pix = (sum - carry) | (carry - (carry >> 5)); + } + break; + + case 2: + { + bg_pix |= 0x8000; + fore_pix &= ~0x8000; + + uint32 diff = bg_pix - fore_pix + 0x108420; + uint32 borrow = (diff - ((bg_pix ^ fore_pix) & 0x108420)) & 0x108420; + + pix = (diff - borrow) & (borrow - (borrow >> 5)); + } + break; + + case 3: + { + bg_pix &= ~0x8000; + fore_pix = ((fore_pix >> 2) & 0x1CE7) | 0x8000; + + uint32 sum = fore_pix + bg_pix; + uint32 carry = (sum - ((fore_pix ^ bg_pix) & 0x8421)) & 0x8420; + + pix = (sum - carry) | (carry - (carry >> 5)); + } + break; + } + + if(!MaskEval_TA || !(GPURAM[y][x] & 0x8000)) + GPURAM[y][x] = (textured ? pix : (pix & 0x7FFF)) | MaskSetOR; + } + else + { + if(!MaskEval_TA || !(GPURAM[y][x] & 0x8000)) + GPURAM[y][x] = (textured ? fore_pix : (fore_pix & 0x7FFF)) | MaskSetOR; + } +} + +INLINE uint16 PS_GPU::ModTexel(uint16 texel, int32 r, int32 g, int32 b, const int32 dither_x, const int32 dither_y) +{ + uint16 ret = texel & 0x8000; + + ret |= DitherLUT[dither_y][dither_x][(((texel & 0x1F) * r) >> (5 - 1))] << 0; + ret |= DitherLUT[dither_y][dither_x][(((texel & 0x3E0) * g) >> (10 - 1))] << 5; + ret |= DitherLUT[dither_y][dither_x][(((texel & 0x7C00) * b) >> (15 - 1))] << 10; + + return(ret); +} + +template +INLINE uint16 PS_GPU::GetTexel(const uint32 clut_offset, int32 u_arg, int32 v_arg) +{ + uint32 u = TexWindowXLUT[u_arg]; + uint32 v = TexWindowYLUT[v_arg]; + uint32 fbtex_x = TexPageX + (u >> (2 - TexMode_TA)); + uint32 fbtex_y = TexPageY + v; + uint16 fbw = GPURAM[fbtex_y][fbtex_x & 1023]; + + if(TexMode_TA != 2) + { + if(TexMode_TA == 0) + fbw = (fbw >> ((u & 3) * 4)) & 0xF; + else + fbw = (fbw >> ((u & 1) * 8)) & 0xFF; + + fbw = GPURAM[(clut_offset >> 10) & 511][(clut_offset + fbw) & 1023]; + } + + return(fbw); +} + +INLINE bool PS_GPU::LineSkipTest(unsigned y) +{ + //DisplayFB_XStart >= OffsX && DisplayFB_YStart >= OffsY && + // ((y & 1) == (DisplayFB_CurLineYReadout & 1)) + + if((DisplayMode & 0x24) != 0x24) + return false; + + if(!dfe && ((y & 1) == ((DisplayFB_YStart + field_ram_readout) & 1))/* && !DisplayOff*/) //&& (y >> 1) >= DisplayFB_YStart && (y >> 1) < (DisplayFB_YStart + (VertEnd - VertStart))) + return true; + + return false; +} + +#include "gpu_polygon.inc" +#include "gpu_sprite.inc" +#include "gpu_line.inc" + +// Special RAM write mode(16 pixels at a time), does *not* appear to use mask drawing environment settings. +INLINE void PS_GPU::Command_FBFill(const uint32 *cb) +{ + int32 r = cb[0] & 0xFF; + int32 g = (cb[0] >> 8) & 0xFF; + int32 b = (cb[0] >> 16) & 0xFF; + const uint16 fill_value = ((r >> 3) << 0) | ((g >> 3) << 5) | ((b >> 3) << 10); + + int32 destX = (cb[1] >> 0) & 0x3F0; + int32 destY = (cb[1] >> 16) & 0x3FF; + + int32 width = (((cb[2] >> 0) & 0x3FF) + 0xF) & ~0xF; + int32 height = (cb[2] >> 16) & 0x1FF; + + //printf("[GPU] FB Fill %d:%d w=%d, h=%d\n", destX, destY, width, height); + DrawTimeAvail -= 46; // Approximate + DrawTimeAvail -= ((width * height) >> 3) + (height * 9); + + for(int32 y = 0; y < height; y++) + { + const int32 d_y = (y + destY) & 511; + + if(LineSkipTest(d_y)) + continue; + + for(int32 x = 0; x < width; x++) + { + const int32 d_x = (x + destX) & 1023; + + GPURAM[d_y][d_x] = fill_value; + } + } + +} + +INLINE void PS_GPU::Command_FBCopy(const uint32 *cb) +{ + int32 sourceX = (cb[1] >> 0) & 0x3FF; + int32 sourceY = (cb[1] >> 16) & 0x3FF; + int32 destX = (cb[2] >> 0) & 0x3FF; + int32 destY = (cb[2] >> 16) & 0x3FF; + + int32 width = (cb[3] >> 0) & 0x3FF; + int32 height = (cb[3] >> 16) & 0x1FF; + + if(!width) + width = 0x400; + + if(!height) + height = 0x200; + + //printf("FB Copy: %d %d %d %d %d %d\n", sourceX, sourceY, destX, destY, width, height); + + DrawTimeAvail -= (width * height) * 2; + + for(int32 y = 0; y < height; y++) + { + for(int32 x = 0; x < width; x += 128) + { + const int32 chunk_x_max = std::min(width - x, 128); + uint16 tmpbuf[128]; // TODO: Check and see if the GPU is actually (ab)using the CLUT or texture cache. + + for(int32 chunk_x = 0; chunk_x < chunk_x_max; chunk_x++) + { + int32 s_y = (y + sourceY) & 511; + int32 s_x = (x + chunk_x + sourceX) & 1023; + + tmpbuf[chunk_x] = GPURAM[s_y][s_x]; + } + + for(int32 chunk_x = 0; chunk_x < chunk_x_max; chunk_x++) + { + int32 d_y = (y + destY) & 511; + int32 d_x = (x + chunk_x + destX) & 1023; + + if(!(GPURAM[d_y][d_x] & MaskEvalAND)) + GPURAM[d_y][d_x] = tmpbuf[chunk_x] | MaskSetOR; + } + } + } + +} + +INLINE void PS_GPU::Command_FBWrite(const uint32 *cb) +{ + assert(InCmd == INCMD_NONE); + + FBRW_X = (cb[1] >> 0) & 0x3FF; + FBRW_Y = (cb[1] >> 16) & 0x3FF; + + FBRW_W = (cb[2] >> 0) & 0x7FF; + FBRW_H = (cb[2] >> 16) & 0x3FF; + + if(FBRW_W > 0x400) + FBRW_W &= 0x3FF; + + if(FBRW_H > 0x200) + FBRW_H &= 0x1FF; + + FBRW_CurX = FBRW_X; + FBRW_CurY = FBRW_Y; + + if(FBRW_W != 0 && FBRW_H != 0) + InCmd = INCMD_FBWRITE; +} + +INLINE void PS_GPU::Command_FBRead(const uint32 *cb) +{ + assert(InCmd == INCMD_NONE); + + FBRW_X = (cb[1] >> 0) & 0x3FF; + FBRW_Y = (cb[1] >> 16) & 0x3FF; + + FBRW_W = (cb[2] >> 0) & 0x7FF; + FBRW_H = (cb[2] >> 16) & 0x3FF; + + if(FBRW_W > 0x400) + FBRW_W &= 0x3FF; + + if(FBRW_H > 0x200) + FBRW_H &= 0x1FF; + + FBRW_CurX = FBRW_X; + FBRW_CurY = FBRW_Y; + + if(FBRW_W != 0 && FBRW_H != 0) + InCmd = INCMD_FBREAD; +} + + +INLINE void PS_GPU::RecalcTexWindowLUT(void) +{ + const unsigned TexWindowX_AND = ~(tww << 3); + const unsigned TexWindowX_OR = (twx & tww) << 3; + + const unsigned TexWindowY_AND = ~(twh << 3); + const unsigned TexWindowY_OR = (twy & twh) << 3; + +// printf("TWX: 0x%02x, TWW: 0x%02x\n", twx, tww); +// printf("TWY: 0x%02x, TWH: 0x%02x\n", twy, twh); + + for(unsigned x = 0; x < 256; x++) + { + TexWindowXLUT[x] = (x & TexWindowX_AND) | TexWindowX_OR; + } + + for(unsigned y = 0; y < 256; y++) + { + TexWindowYLUT[y] = (y & TexWindowY_AND) | TexWindowY_OR; + } + + memset(TexWindowXLUT_Pre, TexWindowXLUT[0], sizeof(TexWindowXLUT_Pre)); + memset(TexWindowXLUT_Post, TexWindowXLUT[255], sizeof(TexWindowXLUT_Post)); + + memset(TexWindowYLUT_Pre, TexWindowYLUT[0], sizeof(TexWindowYLUT_Pre)); + memset(TexWindowYLUT_Post, TexWindowYLUT[255], sizeof(TexWindowYLUT_Post)); +} + +INLINE void PS_GPU::Command_DrawMode(const uint32 *cb) +{ + TexPageX = (*cb & 0xF) * 64; + TexPageY = (*cb & 0x10) * 16; + + SpriteFlip = *cb & 0x3000; + + abr = (*cb >> 5) & 0x3; + TexMode = (*cb >> 7) & 0x3; + + dtd = (*cb >> 9) & 1; + dfe = (*cb >> 10) & 1; + //printf("*******************DFE: %d -- scanline=%d\n", dfe, scanline); +} + +INLINE void PS_GPU::Command_TexWindow(const uint32 *cb) +{ + tww = (*cb & 0x1F); + twh = ((*cb >> 5) & 0x1F); + twx = ((*cb >> 10) & 0x1F); + twy = ((*cb >> 15) & 0x1F); + + RecalcTexWindowLUT(); +} + +INLINE void PS_GPU::Command_Clip0(const uint32 *cb) +{ + ClipX0 = *cb & 1023; + ClipY0 = (*cb >> 10) & 1023; +} + +INLINE void PS_GPU::Command_Clip1(const uint32 *cb) +{ + ClipX1 = *cb & 1023; + ClipY1 = (*cb >> 10) & 1023; +} + +INLINE void PS_GPU::Command_DrawingOffset(const uint32 *cb) +{ + OffsX = sign_x_to_s32(11, (*cb & 2047)); + OffsY = sign_x_to_s32(11, ((*cb >> 11) & 2047)); + + //fprintf(stderr, "[GPU] Drawing offset: %d(raw=%d) %d(raw=%d) -- %d\n", OffsX, *cb, OffsY, *cb >> 11, scanline); +} + +INLINE void PS_GPU::Command_MaskSetting(const uint32 *cb) +{ + //printf("Mask setting: %08x\n", *cb); + MaskSetOR = (*cb & 1) ? 0x8000 : 0x0000; + MaskEvalAND = (*cb & 2) ? 0x8000 : 0x0000; +} + +INLINE void PS_GPU::Command_ClearCache(const uint32 *cb) +{ + +} + +INLINE void PS_GPU::Command_IRQ(const uint32 *cb) +{ + IRQPending = true; + IRQ_Assert(IRQ_GPU, IRQPending); +} + +// +// C-style function wrappers so our command table isn't so ginormous(in memory usage). +// +template +static void G_Command_DrawPolygon(PS_GPU* g, const uint32 *cb) +{ + g->Command_DrawPolygon(cb); +} + +template +static void G_Command_DrawSprite(PS_GPU* g, const uint32 *cb) +{ + g->Command_DrawSprite(cb); +} + +template +static void G_Command_DrawLine(PS_GPU* g, const uint32 *cb) +{ + g->Command_DrawLine(cb); +} + +static void G_Command_ClearCache(PS_GPU* g, const uint32 *cb) +{ + g->Command_ClearCache(cb); +} + +static void G_Command_IRQ(PS_GPU* g, const uint32 *cb) +{ + g->Command_IRQ(cb); +} + +static void G_Command_FBFill(PS_GPU* g, const uint32 *cb) +{ + g->Command_FBFill(cb); +} + +static void G_Command_FBCopy(PS_GPU* g, const uint32 *cb) +{ + g->Command_FBCopy(cb); +} + +static void G_Command_FBWrite(PS_GPU* g, const uint32 *cb) +{ + g->Command_FBWrite(cb); +} + +static void G_Command_FBRead(PS_GPU* g, const uint32 *cb) +{ + g->Command_FBRead(cb); +} + +static void G_Command_DrawMode(PS_GPU* g, const uint32 *cb) +{ + g->Command_DrawMode(cb); +} + +static void G_Command_TexWindow(PS_GPU* g, const uint32 *cb) +{ + g->Command_TexWindow(cb); +} + +static void G_Command_Clip0(PS_GPU* g, const uint32 *cb) +{ + g->Command_Clip0(cb); +} + +static void G_Command_Clip1(PS_GPU* g, const uint32 *cb) +{ + g->Command_Clip1(cb); +} + +static void G_Command_DrawingOffset(PS_GPU* g, const uint32 *cb) +{ + g->Command_DrawingOffset(cb); +} + +static void G_Command_MaskSetting(PS_GPU* g, const uint32 *cb) +{ + g->Command_MaskSetting(cb); +} + + +CTEntry PS_GPU::Commands[256] = +{ + #include "gpu_command_table.inc" +}; + +void PS_GPU::ProcessFIFO(void) +{ + if(!BlitterFIFO.CanRead()) + return; + + switch(InCmd) + { + default: + abort(); + break; + + case INCMD_NONE: + break; + + case INCMD_FBREAD: + puts("BOGUS SALAMANDERS, CAPTAIN!"); + return; + + case INCMD_FBWRITE: + { + uint32 InData = BlitterFIFO.ReadUnit(); + + for(int i = 0; i < 2; i++) + { + if(!(GPURAM[FBRW_CurY & 511][FBRW_CurX & 1023] & MaskEvalAND)) + GPURAM[FBRW_CurY & 511][FBRW_CurX & 1023] = InData | MaskSetOR; + + FBRW_CurX++; + if(FBRW_CurX == (FBRW_X + FBRW_W)) + { + FBRW_CurX = FBRW_X; + FBRW_CurY++; + if(FBRW_CurY == (FBRW_Y + FBRW_H)) + { + InCmd = INCMD_NONE; + break; // Break out of the for() loop. + } + } + InData >>= 16; + } + return; + } + break; + + case INCMD_QUAD: + { + if(DrawTimeAvail < 0) + return; + + const uint32 cc = InCmd_CC; + const CTEntry *command = &Commands[cc]; + unsigned vl = 1 + (bool)(cc & 0x4) + (bool)(cc & 0x10); + uint32 CB[3]; + + if(BlitterFIFO.CanRead() >= vl) + { + for(unsigned i = 0; i < vl; i++) + { + CB[i] = BlitterFIFO.ReadUnit(); + } + + command->func[abr][TexMode | (MaskEvalAND ? 0x4 : 0x0)](this, CB); + } + return; + } + break; + + case INCMD_PLINE: + { + if(DrawTimeAvail < 0) + return; + + const uint32 cc = InCmd_CC; + const CTEntry *command = &Commands[cc]; + unsigned vl = 1 + (bool)(InCmd_CC & 0x10); + uint32 CB[2]; + + if((BlitterFIFO.ReadUnit(true) & 0xF000F000) == 0x50005000) + { + BlitterFIFO.ReadUnit(); + InCmd = INCMD_NONE; + return; + } + + if(BlitterFIFO.CanRead() >= vl) + { + for(unsigned i = 0; i < vl; i++) + { + CB[i] = BlitterFIFO.ReadUnit(); + } + + command->func[abr][TexMode | (MaskEvalAND ? 0x4 : 0x0)](this, CB); + } + return; + } + break; + } + + const uint32 cc = BlitterFIFO.ReadUnit(true) >> 24; + const CTEntry *command = &Commands[cc]; + + if(DrawTimeAvail < 0 && !command->ss_cmd) + return; + + if(BlitterFIFO.CanRead() >= command->len) + { + uint32 CB[0x10]; + + for(unsigned i = 0; i < command->len; i++) + CB[i] = BlitterFIFO.ReadUnit(); + + if(!command->ss_cmd) + DrawTimeAvail -= 2; + +#if 0 + PSX_WARNING("[GPU] Command: %08x %s %d %d %d", CB[0], command->name, command->len, scanline, DrawTimeAvail); + if(1) + { + printf("[GPU] "); + for(unsigned i = 0; i < command->len; i++) + printf("0x%08x ", CB[i]); + printf("\n"); + } +#endif + // A very very ugly kludge to support texture mode specialization. fixme/cleanup/SOMETHING in the future. + if(cc >= 0x20 && cc <= 0x3F && (cc & 0x4)) + { + uint32 tpage; + + tpage = CB[4 + ((cc >> 4) & 0x1)] >> 16; + + TexPageX = (tpage & 0xF) * 64; + TexPageY = (tpage & 0x10) * 16; + + SpriteFlip = tpage & 0x3000; + + abr = (tpage >> 5) & 0x3; + TexMode = (tpage >> 7) & 0x3; + } + + if(!command->func[abr][TexMode]) + { + if(CB[0]) + PSX_WARNING("[GPU] Unknown command: %08x, %d", CB[0], scanline); + } + else + { + command->func[abr][TexMode | (MaskEvalAND ? 0x4 : 0x0)](this, CB); + } + } +} + +INLINE void PS_GPU::WriteCB(uint32 InData) +{ + if(BlitterFIFO.CanRead() >= 0x10 && (InCmd != INCMD_NONE || (BlitterFIFO.CanRead() - 0x10) >= Commands[BlitterFIFO.ReadUnit(true) >> 24].fifo_fb_len)) + { + PSX_DBG(PSX_DBG_WARNING, "GPU FIFO overflow!!!\n"); + return; + } + + BlitterFIFO.WriteUnit(InData); + ProcessFIFO(); +} + +void PS_GPU::Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V) +{ + V <<= (A & 3) * 8; + + if(A & 4) // GP1 ("Control") + { + uint32 command = V >> 24; + + V &= 0x00FFFFFF; + + //PSX_WARNING("[GPU] Control command: %02x %06x %d", command, V, scanline); + + switch(command) + { + /* + 0x40-0xFF do NOT appear to be mirrors, at least not on my PS1's GPU. + */ + default: PSX_WARNING("[GPU] Unknown control command %02x - %06x", command, V); + break; + + case 0x00: // Reset GPU + //printf("\n\n************ Soft Reset %u ********* \n\n", scanline); + SoftReset(); + break; + + case 0x01: // Reset command buffer + if(DrawTimeAvail < 0) + DrawTimeAvail = 0; + BlitterFIFO.Flush(); + InCmd = INCMD_NONE; + break; + + case 0x02: // Acknowledge IRQ + IRQPending = false; + IRQ_Assert(IRQ_GPU, IRQPending); + break; + + case 0x03: // Display enable + DisplayOff = V & 1; + break; + + case 0x04: // DMA Setup + DMAControl = V & 0x3; + break; + + case 0x05: // Start of display area in framebuffer + DisplayFB_XStart = V & 0x3FE; // Lower bit is apparently ignored. + DisplayFB_YStart = (V >> 10) & 0x1FF; + break; + + case 0x06: // Horizontal display range + HorizStart = V & 0xFFF; + HorizEnd = (V >> 12) & 0xFFF; + break; + + case 0x07: + VertStart = V & 0x3FF; + VertEnd = (V >> 10) & 0x3FF; + break; + + case 0x08: + //printf("\n\nDISPLAYMODE SET: 0x%02x, %u *************************\n\n\n", V & 0xFF, scanline); + DisplayMode = V & 0xFF; + break; + + case 0x10: // GPU info(?) + switch(V & 0xF) + { + // DataReadBuffer must remain unchanged for any unhandled GPU info index. + default: break; + + case 0x2: DataReadBuffer = (tww << 0) | (twh << 5) | (twx << 10) | (twy << 15); + break; + + case 0x3: DataReadBuffer = (ClipY0 << 10) | ClipX0; + break; + + case 0x4: DataReadBuffer = (ClipY1 << 10) | ClipX1; + break; + + case 0x5: DataReadBuffer = (OffsX & 2047) | ((OffsY & 2047) << 11); + break; + + case 0x7: DataReadBuffer = 2; + break; + + case 0x8: DataReadBuffer = 0; + break; + } + break; + + } + } + else // GP0 ("Data") + { + //uint32 command = V >> 24; + //printf("Meow command: %02x\n", command); + //assert(!(DMAControl & 2)); + WriteCB(V); + } +} + + +void PS_GPU::WriteDMA(uint32 V) +{ + WriteCB(V); +} + +INLINE uint32 PS_GPU::ReadData(void) +{ + if(InCmd == INCMD_FBREAD) + { + DataReadBuffer = 0; + for(int i = 0; i < 2; i++) + { + DataReadBuffer |= GPURAM[FBRW_CurY & 511][FBRW_CurX & 1023] << (i * 16); + + FBRW_CurX++; + if(FBRW_CurX == (FBRW_X + FBRW_W)) + { + FBRW_CurX = FBRW_X; + FBRW_CurY++; + if(FBRW_CurY == (FBRW_Y + FBRW_H)) + { + InCmd = INCMD_NONE; + break; + } + } + } + } + + return DataReadBuffer; +} + +uint32 PS_GPU::ReadDMA(void) +{ + return ReadData(); +} + +uint32 PS_GPU::Read(const pscpu_timestamp_t timestamp, uint32 A) +{ + uint32 ret = 0; + + if(A & 4) // Status + { + ret = (((DisplayMode << 1) & 0x7F) | ((DisplayMode >> 6) & 1)) << 16; + + ret |= DMAControl << 29; + + ret |= (DisplayFB_CurLineYReadout & 1) << 31; + + ret |= (!field) << 13; + + if(DMAControl & 0x02) + ret |= 1 << 25; + + ret |= IRQPending << 24; + + ret |= DisplayOff << 23; + + if(InCmd == INCMD_NONE && DrawTimeAvail >= 0 && BlitterFIFO.CanRead() == 0x00) // GPU idle bit. + ret |= 1 << 26; + + if(InCmd == INCMD_FBREAD) // Might want to more accurately emulate this in the future? + ret |= (1 << 27); + + ret |= CalcFIFOReadyBit() << 28; // FIFO has room bit? (kinda). + + // + // + ret |= TexPageX >> 6; + ret |= TexPageY >> 4; + ret |= abr << 5; + ret |= TexMode << 7; + + ret |= dtd << 9; + ret |= dfe << 10; + + if(MaskSetOR) + ret |= 1 << 11; + + if(MaskEvalAND) + ret |= 1 << 12; + } + else // "Data" + ret = ReadData(); + + if(DMAControl & 2) + { + //PSX_WARNING("[GPU READ WHEN (DMACONTROL&2)] 0x%08x - ret=0x%08x, scanline=%d", A, ret, scanline); + } + + return(ret >> ((A & 3) * 8)); +} + +/* +static INLINE uint32 ShiftHelper(uint32 val, int shamt, uint32 mask) +{ + if(shamt < 0) + return((val >> (-shamt)) & mask); + else + return((val << shamt) & mask); +} +*/ +INLINE void PS_GPU::ReorderRGB_Var(uint32 out_Rshift, uint32 out_Gshift, uint32 out_Bshift, bool bpp24, const uint16 *src, uint32 *dest, const int32 dx_start, const int32 dx_end, int32 fb_x) +{ + if(bpp24) // 24bpp + { + for(int32 x = dx_start; x < dx_end; x++) + { + uint32 srcpix; + + srcpix = src[(fb_x >> 1) + 0] | (src[((fb_x >> 1) + 1) & 0x7FF] << 16); + srcpix >>= (fb_x & 1) * 8; + + dest[x] = (((srcpix >> 0) << out_Rshift) & (0xFF << out_Rshift)) | (((srcpix >> 8) << out_Gshift) & (0xFF << out_Gshift)) | + (((srcpix >> 16) << out_Bshift) & (0xFF << out_Bshift)); + + fb_x = (fb_x + 3) & 0x7FF; + } + } // 15bpp + else + { + for(int32 x = dx_start; x < dx_end; x++) + { + uint32 srcpix = src[fb_x >> 1]; + + dest[x] = OutputLUT[srcpix & 0x7FFF]; + //dest[x] = ShiftHelper(srcpix, out_Rshift + 3 - 0, (0xF8 << out_Rshift)) | +// ShiftHelper(srcpix, out_Gshift + 3 - 5, (0xF8 << out_Gshift)) | +// ShiftHelper(srcpix, out_Bshift + 3 - 10, (0xF8 << out_Bshift)); + + fb_x = (fb_x + 2) & 0x7FF; + } + } + +} + + +template +void PS_GPU::ReorderRGB(bool bpp24, const uint16 *src, uint32 *dest, const int32 dx_start, const int32 dx_end, int32 fb_x) +{ + ReorderRGB_Var(out_Rshift, out_Gshift, out_Bshift, bpp24, src, dest, dx_start, dx_end, fb_x); +} + +pscpu_timestamp_t PS_GPU::Update(const pscpu_timestamp_t sys_timestamp) +{ + static const uint32 DotClockRatios[5] = { 10, 8, 5, 4, 7 }; + const uint32 dmc = (DisplayMode & 0x40) ? 4 : (DisplayMode & 0x3); + const uint32 dmw = 2800 / DotClockRatios[dmc]; // Must be <= 768 + + int32 sys_clocks = sys_timestamp - lastts; + int32 gpu_clocks; + + //printf("GPUISH: %d\n", sys_timestamp - lastts); + + if(!sys_clocks) + goto TheEnd; + + DrawTimeAvail += sys_clocks << 1; + + if(DrawTimeAvail > 256) + DrawTimeAvail = 256; + + ProcessFIFO(); + + //puts("GPU Update Start"); + + GPUClockCounter += (uint64)sys_clocks * GPUClockRatio; + + gpu_clocks = GPUClockCounter >> 16; + GPUClockCounter -= gpu_clocks << 16; + + while(gpu_clocks > 0) + { + int32 chunk_clocks = gpu_clocks; + int32 dot_clocks; + + if(chunk_clocks > LineClockCounter) + { + //printf("Chunk: %u, LCC: %u\n", chunk_clocks, LineClockCounter); + chunk_clocks = LineClockCounter; + } + + gpu_clocks -= chunk_clocks; + LineClockCounter -= chunk_clocks; + + DotClockCounter += chunk_clocks; + dot_clocks = DotClockCounter / DotClockRatios[DisplayMode & 0x3]; + DotClockCounter -= dot_clocks * DotClockRatios[DisplayMode & 0x3]; + + TIMER_AddDotClocks(dot_clocks); + + + if(!LineClockCounter) + { + PSX_SetEventNT(PSX_EVENT_TIMER, TIMER_Update(sys_timestamp)); // We could just call this at the top of GPU_Update(), but do it here for slightly less CPU usage(presumably). + + LinePhase = (LinePhase + 1) & 1; + + if(LinePhase) + { + TIMER_SetHRetrace(true); + LineClockCounter = 200; + TIMER_ClockHRetrace(); + } + else + { + const unsigned int FirstVisibleLine = LineVisFirst + (HardwarePALType ? 20 : 16); + const unsigned int VisibleLineCount = LineVisLast + 1 - LineVisFirst; //HardwarePALType ? 288 : 240; + + TIMER_SetHRetrace(false); + + if(DisplayMode & 0x08) + LineClockCounter = 3405 - 200; + else + LineClockCounter = 3412 + PhaseChange - 200; + + scanline = (scanline + 1) % LinesPerField; + PhaseChange = !PhaseChange; + +#ifdef WANT_DEBUGGER + DBG_GPUScanlineHook(scanline); +#endif + + // + // + // + if(scanline == (HardwarePALType ? 308 : 256)) // Will need to be redone if we ever allow for visible vertical overscan with NTSC. + { + if(sl_zero_reached) + { + //printf("Req Exit(visible fallthrough case): %u\n", scanline); + PSX_RequestMLExit(); + } + } + + if(scanline == (LinesPerField - 1)) + { + if(sl_zero_reached) + { + //printf("Req Exit(final fallthrough case): %u\n", scanline); + PSX_RequestMLExit(); + } + + if(DisplayMode & 0x20) + field = !field; + else + field = 0; + } + + if(scanline == 0) + { + assert(sl_zero_reached == false); + sl_zero_reached = true; + + if(DisplayMode & 0x20) + { + skip = false; + + if(DisplayMode & 0x08) // PAL + LinesPerField = 313 - field; + else // NTSC + LinesPerField = 263 - field; + } + else + { + field = 0; // May not be the correct place for this? + + if(DisplayMode & 0x08) // PAL + LinesPerField = 314; + else // NTSC + LinesPerField = 263; + } + + if(espec) + { + if((bool)(DisplayMode & 0x08) != HardwarePALType) + { + const uint32 black = surface->MakeColor(0, 0, 0); + + DisplayRect->x = 0; + DisplayRect->y = 0; + DisplayRect->w = 384; + DisplayRect->h = VisibleLineCount; + + for(int32 y = 0; y < DisplayRect->h; y++) + { + uint32 *dest = surface->pixels + y * surface->pitch32; + + LineWidths[y] = 384; + + for(int32 x = 0; x < 384; x++) + { + dest[x] = black; + } + } + char buffer[256]; + + // trio_snprintf(buffer, sizeof(buffer), _("VIDEO STANDARD MISMATCH")); + // DrawTextTrans(surface->pixels + ((DisplayRect->h / 2) - (13 / 2)) * surface->pitch32, surface->pitch32 << 2, DisplayRect->w, (UTF8*)buffer, + //surface->MakeColor(0x00, 0xFF, 0x00), true, MDFN_FONT_6x13_12x13); + } + else + { + const uint32 black = surface->MakeColor(0, 0, 0); + + espec->InterlaceOn = (bool)(DisplayMode & 0x20); + espec->InterlaceField = (bool)(DisplayMode & 0x20) && field; + + DisplayRect->x = 0; + DisplayRect->y = 0; + DisplayRect->w = 0; + DisplayRect->h = VisibleLineCount << (bool)(DisplayMode & 0x20); + + // Clear ~0 state. + LineWidths[0] = 0; + + for(int i = 0; i < (DisplayRect->y + DisplayRect->h); i++) + { + surface->pixels[i * surface->pitch32 + 0] = + surface->pixels[i * surface->pitch32 + 1] = black; + LineWidths[i] = 2; + } + } + } + } + + // + // Don't mess with the order of evaluation of these scanline == VertXXX && (InVblankwhatever) if statements and the following IRQ/timer vblank stuff + // unless you know what you're doing!!! (IE you've run further tests to refine the behavior) + // + if(scanline == VertEnd && !InVBlank) + { + if(sl_zero_reached) + { + // Gameplay in Descent(NTSC) has vblank at scanline 236 + if(scanline >= (FirstVisibleLine + VisibleLineCount) || (scanline >= (HardwarePALType ? 260 : 232))) + { + //printf("Req Exit(vblank case): %u\n", scanline); + PSX_RequestMLExit(); + } + else + { + //printf("VBlank too early, chickening out early exit!\n"); + } + } + + //printf("VBLANK: %u\n", scanline); + InVBlank = true; + + DisplayFB_CurYOffset = 0; + + if((DisplayMode & 0x24) == 0x24) + field_ram_readout = !field; + else + field_ram_readout = 0; + } + + if(scanline == VertStart && InVBlank) + { + InVBlank = false; + + // Note to self: X-Men Mutant Academy relies on this being set on the proper scanline in 480i mode(otherwise it locks up on startup). + //if(HeightMode) + // DisplayFB_CurYOffset = field; + } + + IRQ_Assert(IRQ_VBLANK, InVBlank); + TIMER_SetVBlank(InVBlank); + // + // + // + + // Needs to occur even in vblank. + // Not particularly confident about the timing of this in regards to vblank and the upper bit(ODE) of the GPU status port, though the test that + // showed an oddity was pathological in that VertEnd < VertStart in it. + if((DisplayMode & 0x24) == 0x24) + DisplayFB_CurLineYReadout = (DisplayFB_YStart + (DisplayFB_CurYOffset << 1) + (InVBlank ? 0 : field_ram_readout)) & 0x1FF; + else + DisplayFB_CurLineYReadout = (DisplayFB_YStart + DisplayFB_CurYOffset) & 0x1FF; + + if((bool)(DisplayMode & 0x08) == HardwarePALType && scanline >= FirstVisibleLine && scanline < (FirstVisibleLine + VisibleLineCount) && !skip && espec) + { + uint32 *dest; // = surface->pixels + (scanline - VisibleStartLine) * surface->pitch32; + int32 dest_line; + int32 fb_x = DisplayFB_XStart * 2; + int32 dx_start = HorizStart, dx_end = HorizEnd; + + dest_line = ((scanline - FirstVisibleLine) << espec->InterlaceOn) + espec->InterlaceField; + dest = surface->pixels + dest_line * surface->pitch32; + + if(dx_end < dx_start) + dx_end = dx_start; + + dx_start = dx_start / DotClockRatios[dmc]; + dx_end = dx_end / DotClockRatios[dmc]; + + dx_start -= 488 / DotClockRatios[dmc]; + dx_end -= 488 / DotClockRatios[dmc]; + + if(dx_start < 0) + { + fb_x -= dx_start * ((DisplayMode & 0x10) ? 3 : 2); + fb_x &= 0x7FF; //0x3FF; + dx_start = 0; + } + + if((uint32)dx_end > dmw) + dx_end = dmw; + + if(InVBlank || DisplayOff) + dx_start = dx_end = 0; + + // TODO, but there are problems with this, as not all blitter busy cycles(crudely abstracted with DrawTimeAvail) are GPU RAM access cycles. + // Also, it shouldn't be here per-se, since this code won't be all if we're frameskipping or there's a video standard mismatch + //DrawTimeAvail -= (dx_end - dx_start) + ((DisplayMode & 0x10) ? ((dx_end - dx_start + 1) >> 1) : 0); + + LineWidths[dest_line] = dmw; + + { + const uint16 *src = GPURAM[DisplayFB_CurLineYReadout]; + const uint32 black = surface->MakeColor(0, 0, 0); + + for(int32 x = 0; x < dx_start; x++) + dest[x] = black; + + //printf("%d %d %d - %d %d\n", scanline, dx_start, dx_end, HorizStart, HorizEnd); + if(surface->format.Rshift == 0 && surface->format.Gshift == 8 && surface->format.Bshift == 16) + ReorderRGB<0, 8, 16>(DisplayMode & 0x10, src, dest, dx_start, dx_end, fb_x); + else if(surface->format.Rshift == 8 && surface->format.Gshift == 16 && surface->format.Bshift == 24) + ReorderRGB<8, 16, 24>(DisplayMode & 0x10, src, dest, dx_start, dx_end, fb_x); + else if(surface->format.Rshift == 16 && surface->format.Gshift == 8 && surface->format.Bshift == 0) + ReorderRGB<16, 8, 0>(DisplayMode & 0x10, src, dest, dx_start, dx_end, fb_x); + else if(surface->format.Rshift == 24 && surface->format.Gshift == 16 && surface->format.Bshift == 8) + ReorderRGB<24, 16, 8>(DisplayMode & 0x10, src, dest, dx_start, dx_end, fb_x); + else + ReorderRGB_Var(surface->format.Rshift, surface->format.Gshift, surface->format.Bshift, DisplayMode & 0x10, src, dest, dx_start, dx_end, fb_x); + + for(uint32 x = dx_end; x < dmw; x++) + dest[x] = black; + } + + //if(scanline == 64) + // printf("%u\n", sys_timestamp - ((uint64)gpu_clocks * 65536) / GPUClockRatio); + + PSX_GPULineHook(sys_timestamp, sys_timestamp - ((uint64)gpu_clocks * 65536) / GPUClockRatio, scanline == 0, dest, &surface->format, dmw, (488 - 146) / DotClockRatios[dmc], (HardwarePALType ? 53203425 : 53693182) / DotClockRatios[dmc], DotClockRatios[dmc]); + } + else + { + PSX_GPULineHook(sys_timestamp, sys_timestamp - ((uint64)gpu_clocks * 65536) / GPUClockRatio, scanline == 0, NULL, &surface->format, 0, 0, 0, 0); + } + + if(!InVBlank) + { + DisplayFB_CurYOffset = (DisplayFB_CurYOffset + 1) & 0x1FF; + } + } + } + } + + //puts("GPU Update End"); + + TheEnd: + lastts = sys_timestamp; + + { + int32 next_dt = LineClockCounter; + + next_dt = (((int64)next_dt << 16) - GPUClockCounter + GPUClockRatio - 1) / GPUClockRatio; + + next_dt = std::max(1, next_dt); + next_dt = std::min(128, next_dt); + + //printf("%d\n", next_dt); + + return(sys_timestamp + next_dt); + } +} + +void PS_GPU::StartFrame(EmulateSpecStruct *espec_arg) +{ + sl_zero_reached = false; + + if(!espec_arg) + { + espec = NULL; + surface = NULL; + DisplayRect = NULL; + LineWidths = NULL; + skip = true; + return; + } + + espec = espec_arg; + + surface = espec->surface; + DisplayRect = &espec->DisplayRect; + LineWidths = espec->LineWidths; + skip = espec->skip; + + if(espec->VideoFormatChanged) + { + for(int rc = 0; rc < 0x8000; rc++) + { + uint32 r, g, b; + + r = ((rc >> 0) & 0x1F) << 3; + g = ((rc >> 5) & 0x1F) << 3; + b = ((rc >> 10) & 0x1F) << 3; + OutputLUT[rc] = espec->surface->format.MakeColor(r, g, b, 0); + } + } +} + +int PS_GPU::StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFARRAY16(&GPURAM[0][0], sizeof(GPURAM) / sizeof(GPURAM[0][0])), + + SFVAR(DMAControl), + + SFVAR(ClipX0), + SFVAR(ClipY0), + SFVAR(ClipX1), + SFVAR(ClipY1), + + SFVAR(OffsX), + SFVAR(OffsY), + + SFVAR(dtd), + SFVAR(dfe), + + SFVAR(MaskSetOR), + SFVAR(MaskEvalAND), + + SFVAR(tww), + SFVAR(twh), + SFVAR(twx), + SFVAR(twy), + + SFVAR(TexPageX), + SFVAR(TexPageY), + + SFVAR(SpriteFlip), + + SFVAR(abr), + SFVAR(TexMode), + + SFARRAY32(&BlitterFIFO.data[0], BlitterFIFO.data.size()), + SFVAR(BlitterFIFO.read_pos), + SFVAR(BlitterFIFO.write_pos), + SFVAR(BlitterFIFO.in_count), + + SFVAR(DataReadBuffer), + + SFVAR(IRQPending), + + SFVAR(InCmd), + SFVAR(InCmd_CC), + +#define TVHELPER(n) SFVAR(n.x), SFVAR(n.y), SFVAR(n.u), SFVAR(n.v), SFVAR(n.r), SFVAR(n.g), SFVAR(n.b) + TVHELPER(InQuad_F3Vertices[0]), + TVHELPER(InQuad_F3Vertices[1]), + TVHELPER(InQuad_F3Vertices[2]), +#undef TVHELPER + SFVAR(InQuad_clut), + + SFVAR(InPLine_PrevPoint.x), + SFVAR(InPLine_PrevPoint.y), + SFVAR(InPLine_PrevPoint.r), + SFVAR(InPLine_PrevPoint.g), + SFVAR(InPLine_PrevPoint.b), + + SFVAR(FBRW_X), + SFVAR(FBRW_Y), + SFVAR(FBRW_W), + SFVAR(FBRW_H), + SFVAR(FBRW_CurY), + SFVAR(FBRW_CurX), + + SFVAR(DisplayMode), + SFVAR(DisplayOff), + SFVAR(DisplayFB_XStart), + SFVAR(DisplayFB_YStart), + + SFVAR(HorizStart), + SFVAR(HorizEnd), + + SFVAR(VertStart), + SFVAR(VertEnd), + + SFVAR(DisplayFB_CurYOffset), + SFVAR(DisplayFB_CurLineYReadout), + + SFVAR(InVBlank), + + SFVAR(LinesPerField), + SFVAR(scanline), + SFVAR(field), + SFVAR(field_ram_readout), + SFVAR(PhaseChange), + + SFVAR(DotClockCounter), + + SFVAR(GPUClockCounter), + SFVAR(LineClockCounter), + SFVAR(LinePhase), + + SFVAR(DrawTimeAvail), + + SFEND + }; + int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "GPU"); + + if(load) + { + RecalcTexWindowLUT(); + BlitterFIFO.SaveStatePostLoad(); + + HorizStart &= 0xFFF; + HorizEnd &= 0xFFF; + + IRQ_Assert(IRQ_GPU, IRQPending); + } + + return(ret); +} + +} diff --git a/psx/octoshock/psx/gpu.h b/psx/octoshock/psx/gpu.h new file mode 100644 index 0000000000..06f4085025 --- /dev/null +++ b/psx/octoshock/psx/gpu.h @@ -0,0 +1,317 @@ +// WARNING WARNING WARNING: ONLY use CanRead() method of BlitterFIFO, and NOT CanWrite(), since the FIFO is larger than the actual PS1 GPU FIFO to accommodate +// our lack of fancy superscalarish command sequencer. + +#pragma once + +#include "cdrom/SimpleFIFO.h" +#include "git.h" + +namespace MDFN_IEN_PSX +{ + +class PS_GPU; + +struct CTEntry +{ + void (*func[4][8])(PS_GPU* g, const uint32 *cb); + uint8 len; + uint8 fifo_fb_len; + bool ss_cmd; +}; + +struct tri_vertex +{ + int32 x, y; + int32 u, v; + int32 r, g, b; +}; + +struct i_group; +struct i_deltas; + +struct line_point +{ + int32 x, y; + uint8 r, g, b; +}; + +class PS_GPU +{ + public: + + PS_GPU(bool pal_clock_and_tv, int sls, int sle) MDFN_COLD; + ~PS_GPU() MDFN_COLD; + + void FillVideoParams(MDFNGI* gi) MDFN_COLD; + + void Power(void) MDFN_COLD; + + int StateAction(StateMem *sm, int load, int data_only); + + void ResetTS(void); + + void StartFrame(EmulateSpecStruct *espec); + + pscpu_timestamp_t Update(const pscpu_timestamp_t timestamp); + + void Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V); + + INLINE bool CalcFIFOReadyBit(void) + { + if(InCmd & (INCMD_PLINE | INCMD_QUAD)) + return(false); + + if(BlitterFIFO.CanRead() == 0) + return(true); + + if(InCmd & (INCMD_FBREAD | INCMD_FBWRITE)) + return(false); + + if(BlitterFIFO.CanRead() >= Commands[BlitterFIFO.ReadUnit(true) >> 24].fifo_fb_len) + return(false); + + return(true); + } + + INLINE bool DMACanWrite(void) + { + return CalcFIFOReadyBit(); + } + + void WriteDMA(uint32 V); + uint32 ReadDMA(void); + + uint32 Read(const pscpu_timestamp_t timestamp, uint32 A); + + inline int32 GetScanlineNum(void) + { + return(scanline); + } + + INLINE uint16 PeekRAM(uint32 A) + { + return(GPURAM[(A >> 10) & 0x1FF][A & 0x3FF]); + } + + INLINE void PokeRAM(uint32 A, uint16 V) + { + GPURAM[(A >> 10) & 0x1FF][A & 0x3FF] = V; + } + + private: + + void ProcessFIFO(void); + void WriteCB(uint32 data); + uint32 ReadData(void); + void SoftReset(void); + + // Y, X + uint16 GPURAM[512][1024]; + + uint32 DMAControl; + + // + // Drawing stuff + // + //int32 TexPageX; // 0, 64, 128, 192, etc up to 960 + //int32 TexPageY; // 0 or 256 + //uint32 abr; // Semi-transparency mode(0~3) + //bool dtd; // Dithering enable + + int32 ClipX0; + int32 ClipY0; + int32 ClipX1; + int32 ClipY1; + + int32 OffsX; + int32 OffsY; + + bool dtd; + bool dfe; + + uint32 MaskSetOR; + uint32 MaskEvalAND; + + uint8 tww, twh, twx, twy; + struct + { + uint8 TexWindowXLUT_Pre[16]; + uint8 TexWindowXLUT[256]; + uint8 TexWindowXLUT_Post[16]; + }; + + struct + { + uint8 TexWindowYLUT_Pre[16]; + uint8 TexWindowYLUT[256]; + uint8 TexWindowYLUT_Post[16]; + }; + void RecalcTexWindowLUT(void); + + int32 TexPageX; + int32 TexPageY; + + uint32 SpriteFlip; + + uint32 abr; + uint32 TexMode; + + struct + { + uint8 RGB8SAT_Under[256]; + uint8 RGB8SAT[256]; + uint8 RGB8SAT_Over[256]; + }; + + uint8 DitherLUT[4][4][512]; // Y, X, 8-bit source value(256 extra for saturation) + + bool LineSkipTest(unsigned y); + + template + void PlotPixel(int32 x, int32 y, uint16 pix); + + template + uint16 GetTexel(uint32 clut_offset, int32 u, int32 v); + + uint16 ModTexel(uint16 texel, int32 r, int32 g, int32 b, const int32 dither_x, const int32 dither_y); + + template + void DrawSpan(int y, uint32 clut_offset, const int32 x_start, const int32 x_bound, i_group ig, const i_deltas &idl); + + template + void DrawTriangle(tri_vertex *vertices, uint32 clut); + + template + void DrawSprite(int32 x_arg, int32 y_arg, int32 w, int32 h, uint8 u_arg, uint8 v_arg, uint32 color, uint32 clut_offset); + + template + void DrawLine(line_point *vertices); + + + public: + template + void Command_DrawPolygon(const uint32 *cb); + + template + void Command_DrawSprite(const uint32 *cb); + + template + void Command_DrawLine(const uint32 *cb); + + void Command_ClearCache(const uint32 *cb); + void Command_IRQ(const uint32 *cb); + + void Command_FBFill(const uint32 *cb); + void Command_FBCopy(const uint32 *cb); + void Command_FBWrite(const uint32 *cb); + void Command_FBRead(const uint32 *cb); + + void Command_DrawMode(const uint32 *cb); + void Command_TexWindow(const uint32 *cb); + void Command_Clip0(const uint32 *cb); + void Command_Clip1(const uint32 *cb); + void Command_DrawingOffset(const uint32 *cb); + void Command_MaskSetting(const uint32 *cb); + + private: + static CTEntry Commands[256]; + + SimpleFIFO BlitterFIFO; + + uint32 DataReadBuffer; + + bool IRQPending; + // + // + // + // Powers of 2 for faster multiple equality testing(just for multi-testing; InCmd itself will only contain 0, or a power of 2). + enum + { + INCMD_NONE = 0, + INCMD_PLINE = (1 << 0), + INCMD_QUAD = (1 << 1), + INCMD_FBWRITE = (1 << 2), + INCMD_FBREAD = (1 << 3) + }; + uint8 InCmd; + uint8 InCmd_CC; + + tri_vertex InQuad_F3Vertices[3]; + uint32 InQuad_clut; + + line_point InPLine_PrevPoint; + + uint32 FBRW_X; + uint32 FBRW_Y; + uint32 FBRW_W; + uint32 FBRW_H; + uint32 FBRW_CurY; + uint32 FBRW_CurX; + + // + // Display Parameters + // + uint32 DisplayMode; + + bool DisplayOff; + uint32 DisplayFB_XStart; + uint32 DisplayFB_YStart; + + uint32 HorizStart; + uint32 HorizEnd; + + uint32 VertStart; + uint32 VertEnd; + + // + // Display work vars + // + uint32 DisplayFB_CurYOffset; + uint32 DisplayFB_CurLineYReadout; + + bool InVBlank; + + // + // + // + uint32 LinesPerField; + uint32 scanline; + bool field; + bool field_ram_readout; + bool PhaseChange; + + uint32 DotClockCounter; + + uint64 GPUClockCounter; + uint32 GPUClockRatio; + int32 LineClockCounter; + int32 LinePhase; + + int32 DrawTimeAvail; + + pscpu_timestamp_t lastts; + + // + // + // + + bool sl_zero_reached; + // + // + + EmulateSpecStruct *espec; + MDFN_Surface *surface; + MDFN_Rect *DisplayRect; + int32 *LineWidths; + bool skip; + bool HardwarePALType; + int LineVisFirst, LineVisLast; + + uint32 OutputLUT[32768]; + void ReorderRGB_Var(uint32 out_Rshift, uint32 out_Gshift, uint32 out_Bshift, bool bpp24, const uint16 *src, uint32 *dest, const int32 dx_start, const int32 dx_end, int32 fb_x); + + template + void ReorderRGB(bool bpp24, const uint16 *src, uint32 *dest, const int32 dx_start, const int32 dx_end, int32 fb_x) NO_INLINE; +}; + +} diff --git a/psx/octoshock/psx/gpu_command_table.inc b/psx/octoshock/psx/gpu_command_table.inc new file mode 100644 index 0000000000..5c3f7cbe0d --- /dev/null +++ b/psx/octoshock/psx/gpu_command_table.inc @@ -0,0 +1,232 @@ +//#define BM_HELPER(fg) { fg(0), fg(1), fg(2), fg(3) } + +#define POLY_HELPER_SUB(bm, cv, tm, mam) \ + G_Command_DrawPolygon<3 + ((cv & 0x8) >> 3), ((cv & 0x10) >> 4), ((cv & 0x4) >> 2), ((cv & 0x2) >> 1) ? bm : -1, ((cv & 1) ^ 1) & ((cv & 0x4) >> 2), tm, mam > + +#define POLY_HELPER_FG(bm, cv) \ + { \ + POLY_HELPER_SUB(bm, cv, ((cv & 0x4) ? 0 : 0), 0), \ + POLY_HELPER_SUB(bm, cv, ((cv & 0x4) ? 1 : 0), 0), \ + POLY_HELPER_SUB(bm, cv, ((cv & 0x4) ? 2 : 0), 0), \ + POLY_HELPER_SUB(bm, cv, ((cv & 0x4) ? 2 : 0), 0), \ + POLY_HELPER_SUB(bm, cv, ((cv & 0x4) ? 0 : 0), 1), \ + POLY_HELPER_SUB(bm, cv, ((cv & 0x4) ? 1 : 0), 1), \ + POLY_HELPER_SUB(bm, cv, ((cv & 0x4) ? 2 : 0), 1), \ + POLY_HELPER_SUB(bm, cv, ((cv & 0x4) ? 2 : 0), 1), \ + } + +#define POLY_HELPER(cv) \ + { \ + { POLY_HELPER_FG(0, cv), POLY_HELPER_FG(1, cv), POLY_HELPER_FG(2, cv), POLY_HELPER_FG(3, cv) }, \ + 1 + (3 /*+ ((cv & 0x8) >> 3)*/) * ( 1 + ((cv & 0x4) >> 2) + ((cv & 0x10) >> 4) ) - ((cv & 0x10) >> 4), \ + 1, \ + false \ + } + +// +// + +#define SPR_HELPER_SUB(bm, cv, tm, mam) G_Command_DrawSprite<(cv >> 3) & 0x3, ((cv & 0x4) >> 2), ((cv & 0x2) >> 1) ? bm : -1, ((cv & 1) ^ 1) & ((cv & 0x4) >> 2), tm, mam> + +#define SPR_HELPER_FG(bm, cv) \ + { \ + SPR_HELPER_SUB(bm, cv, ((cv & 0x4) ? 0 : 0), 0), \ + SPR_HELPER_SUB(bm, cv, ((cv & 0x4) ? 1 : 0), 0), \ + SPR_HELPER_SUB(bm, cv, ((cv & 0x4) ? 2 : 0), 0), \ + SPR_HELPER_SUB(bm, cv, ((cv & 0x4) ? 2 : 0), 0), \ + SPR_HELPER_SUB(bm, cv, ((cv & 0x4) ? 0 : 0), 1), \ + SPR_HELPER_SUB(bm, cv, ((cv & 0x4) ? 1 : 0), 1), \ + SPR_HELPER_SUB(bm, cv, ((cv & 0x4) ? 2 : 0), 1), \ + SPR_HELPER_SUB(bm, cv, ((cv & 0x4) ? 2 : 0), 1), \ + } + + +#define SPR_HELPER(cv) \ + { \ + { SPR_HELPER_FG(0, cv), SPR_HELPER_FG(1, cv), SPR_HELPER_FG(2, cv), SPR_HELPER_FG(3, cv) }, \ + 2 + ((cv & 0x4) >> 2) + ((cv & 0x18) ? 0 : 1), \ + 2 | ((cv & 0x4) >> 2) | ((cv & 0x18) ? 0 : 1), /* |, not +, for this */ \ + false \ + } + +// +// + +#define LINE_HELPER_SUB(bm, cv, mam) G_Command_DrawLine<((cv & 0x08) >> 3), ((cv & 0x10) >> 4), ((cv & 0x2) >> 1) ? bm : -1, mam> + +#define LINE_HELPER_FG(bm, cv) \ + { \ + LINE_HELPER_SUB(bm, cv, 0), \ + LINE_HELPER_SUB(bm, cv, 0), \ + LINE_HELPER_SUB(bm, cv, 0), \ + LINE_HELPER_SUB(bm, cv, 0), \ + LINE_HELPER_SUB(bm, cv, 1), \ + LINE_HELPER_SUB(bm, cv, 1), \ + LINE_HELPER_SUB(bm, cv, 1), \ + LINE_HELPER_SUB(bm, cv, 1) \ + } + +#define LINE_HELPER(cv) \ + { \ + { LINE_HELPER_FG(0, cv), LINE_HELPER_FG(1, cv), LINE_HELPER_FG(2, cv), LINE_HELPER_FG(3, cv) }, \ + 3 + ((cv & 0x10) >> 4), \ + 1, \ + false \ + } + +// +// + + +#define OTHER_HELPER_FG(bm, arg_ptr) { arg_ptr, arg_ptr, arg_ptr, arg_ptr, arg_ptr, arg_ptr, arg_ptr, arg_ptr } +#define OTHER_HELPER(arg_cs, arg_fbcs, arg_ss, arg_ptr) { { OTHER_HELPER_FG(0, arg_ptr), OTHER_HELPER_FG(1, arg_ptr), OTHER_HELPER_FG(2, arg_ptr), OTHER_HELPER_FG(3, arg_ptr) }, arg_cs, arg_fbcs, arg_ss } +#define OTHER_HELPER_X2(arg_cs, arg_fbcs, arg_ss, arg_ptr) OTHER_HELPER(arg_cs, arg_fbcs, arg_ss, arg_ptr), OTHER_HELPER(arg_cs, arg_fbcs, arg_ss, arg_ptr) +#define OTHER_HELPER_X4(arg_cs, arg_fbcs, arg_ss, arg_ptr) OTHER_HELPER_X2(arg_cs, arg_fbcs, arg_ss, arg_ptr), OTHER_HELPER_X2(arg_cs, arg_fbcs, arg_ss, arg_ptr) +#define OTHER_HELPER_X8(arg_cs, arg_fbcs, arg_ss, arg_ptr) OTHER_HELPER_X4(arg_cs, arg_fbcs, arg_ss, arg_ptr), OTHER_HELPER_X4(arg_cs, arg_fbcs, arg_ss, arg_ptr) +#define OTHER_HELPER_X16(arg_cs, arg_fbcs, arg_ss, arg_ptr) OTHER_HELPER_X8(arg_cs, arg_fbcs, arg_ss, arg_ptr), OTHER_HELPER_X8(arg_cs, arg_fbcs, arg_ss, arg_ptr) +#define OTHER_HELPER_X32(arg_cs, arg_fbcs, arg_ss, arg_ptr) OTHER_HELPER_X16(arg_cs, arg_fbcs, arg_ss, arg_ptr), OTHER_HELPER_X16(arg_cs, arg_fbcs, arg_ss, arg_ptr) + +#define NULLCMD_FG(bm) { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } +#define NULLCMD() { { NULLCMD_FG(0), NULLCMD_FG(1), NULLCMD_FG(2), NULLCMD_FG(3) }, 1, 1, true } + + + /* 0x00 */ + NULLCMD(), + OTHER_HELPER(1, 2, false, G_Command_ClearCache), + OTHER_HELPER(3, 3, false, G_Command_FBFill), + + NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), + NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), + + /* 0x10 */ + NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), + NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), + + OTHER_HELPER(1, 1, false, G_Command_IRQ), + + /* 0x20 */ + POLY_HELPER(0x20), + POLY_HELPER(0x21), + POLY_HELPER(0x22), + POLY_HELPER(0x23), + POLY_HELPER(0x24), + POLY_HELPER(0x25), + POLY_HELPER(0x26), + POLY_HELPER(0x27), + POLY_HELPER(0x28), + POLY_HELPER(0x29), + POLY_HELPER(0x2a), + POLY_HELPER(0x2b), + POLY_HELPER(0x2c), + POLY_HELPER(0x2d), + POLY_HELPER(0x2e), + POLY_HELPER(0x2f), + POLY_HELPER(0x30), + POLY_HELPER(0x31), + POLY_HELPER(0x32), + POLY_HELPER(0x33), + POLY_HELPER(0x34), + POLY_HELPER(0x35), + POLY_HELPER(0x36), + POLY_HELPER(0x37), + POLY_HELPER(0x38), + POLY_HELPER(0x39), + POLY_HELPER(0x3a), + POLY_HELPER(0x3b), + POLY_HELPER(0x3c), + POLY_HELPER(0x3d), + POLY_HELPER(0x3e), + POLY_HELPER(0x3f), + + LINE_HELPER(0x40), + LINE_HELPER(0x41), + LINE_HELPER(0x42), + LINE_HELPER(0x43), + LINE_HELPER(0x44), + LINE_HELPER(0x45), + LINE_HELPER(0x46), + LINE_HELPER(0x47), + LINE_HELPER(0x48), + LINE_HELPER(0x49), + LINE_HELPER(0x4a), + LINE_HELPER(0x4b), + LINE_HELPER(0x4c), + LINE_HELPER(0x4d), + LINE_HELPER(0x4e), + LINE_HELPER(0x4f), + LINE_HELPER(0x50), + LINE_HELPER(0x51), + LINE_HELPER(0x52), + LINE_HELPER(0x53), + LINE_HELPER(0x54), + LINE_HELPER(0x55), + LINE_HELPER(0x56), + LINE_HELPER(0x57), + LINE_HELPER(0x58), + LINE_HELPER(0x59), + LINE_HELPER(0x5a), + LINE_HELPER(0x5b), + LINE_HELPER(0x5c), + LINE_HELPER(0x5d), + LINE_HELPER(0x5e), + LINE_HELPER(0x5f), + + SPR_HELPER(0x60), + SPR_HELPER(0x61), + SPR_HELPER(0x62), + SPR_HELPER(0x63), + SPR_HELPER(0x64), + SPR_HELPER(0x65), + SPR_HELPER(0x66), + SPR_HELPER(0x67), + SPR_HELPER(0x68), + SPR_HELPER(0x69), + SPR_HELPER(0x6a), + SPR_HELPER(0x6b), + SPR_HELPER(0x6c), + SPR_HELPER(0x6d), + SPR_HELPER(0x6e), + SPR_HELPER(0x6f), + SPR_HELPER(0x70), + SPR_HELPER(0x71), + SPR_HELPER(0x72), + SPR_HELPER(0x73), + SPR_HELPER(0x74), + SPR_HELPER(0x75), + SPR_HELPER(0x76), + SPR_HELPER(0x77), + SPR_HELPER(0x78), + SPR_HELPER(0x79), + SPR_HELPER(0x7a), + SPR_HELPER(0x7b), + SPR_HELPER(0x7c), + SPR_HELPER(0x7d), + SPR_HELPER(0x7e), + SPR_HELPER(0x7f), + + /* 0x80 ... 0x9F */ + OTHER_HELPER_X32(4, 2, false, G_Command_FBCopy), + + /* 0xA0 ... 0xBF */ + OTHER_HELPER_X32(3, 2, false, G_Command_FBWrite), + + /* 0xC0 ... 0xDF */ + OTHER_HELPER_X32(3, 2, false, G_Command_FBRead), + + /* 0xE0 */ + + NULLCMD(), + OTHER_HELPER(1, 2, false, G_Command_DrawMode), + OTHER_HELPER(1, 2, false, G_Command_TexWindow), + OTHER_HELPER(1, 1, true, G_Command_Clip0), + OTHER_HELPER(1, 1, true, G_Command_Clip1), + OTHER_HELPER(1, 1, true, G_Command_DrawingOffset), + OTHER_HELPER(1, 2, false, G_Command_MaskSetting), + + NULLCMD(), + NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), + + /* 0xF0 */ + NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), + NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), + diff --git a/psx/octoshock/psx/gpu_line.inc b/psx/octoshock/psx/gpu_line.inc new file mode 100644 index 0000000000..3b8b88451a --- /dev/null +++ b/psx/octoshock/psx/gpu_line.inc @@ -0,0 +1,238 @@ +struct line_fxp_coord +{ + int64 x, y; + int32 r, g, b; +}; + +struct line_fxp_step +{ + int64 dx_dk, dy_dk; + int32 dr_dk, dg_dk, db_dk; +}; + +enum { Line_XY_FractBits = 32 }; +enum { Line_RGB_FractBits = 12 }; + +template +static INLINE void LinePointToFXPCoord(const line_point &point, const line_fxp_step &step, line_fxp_coord &coord) +{ + coord.x = ((int64)point.x << Line_XY_FractBits) | (1LL << (Line_XY_FractBits - 1)); + coord.y = ((int64)point.y << Line_XY_FractBits) | (1LL << (Line_XY_FractBits - 1)); + + coord.x -= 1024; + + if(step.dy_dk < 0) + coord.y -= 1024; + + if(goraud) + { + coord.r = (point.r << Line_RGB_FractBits) | (1 << (Line_RGB_FractBits - 1)); + coord.g = (point.g << Line_RGB_FractBits) | (1 << (Line_RGB_FractBits - 1)); + coord.b = (point.b << Line_RGB_FractBits) | (1 << (Line_RGB_FractBits - 1)); + } +} + +template +static INLINE T LineDivide(T delta, int32 dk) +{ + delta <<= bits; + + if(delta < 0) + delta -= dk - 1; + if(delta > 0) + delta += dk - 1; + + return(delta / dk); +} + +template +static INLINE void LinePointsToFXPStep(const line_point &point0, const line_point &point1, const int32 dk, line_fxp_step &step) +{ + if(!dk) + { + step.dx_dk = 0; + step.dy_dk = 0; + + if(goraud) + { + step.dr_dk = 0; + step.dg_dk = 0; + step.db_dk = 0; + } + return; + } + + step.dx_dk = LineDivide(point1.x - point0.x, dk); + step.dy_dk = LineDivide(point1.y - point0.y, dk); + + if(goraud) + { + step.dr_dk = ((point1.r - point0.r) << Line_RGB_FractBits) / dk; + step.dg_dk = ((point1.g - point0.g) << Line_RGB_FractBits) / dk; + step.db_dk = ((point1.b - point0.b) << Line_RGB_FractBits) / dk; + } +} + +template +static INLINE void AddLineStep(line_fxp_coord &point, const line_fxp_step &step, int32 count = 1) +{ + point.x += step.dx_dk * count; + point.y += step.dy_dk * count; + + if(goraud) + { + point.r += step.dr_dk * count; + point.g += step.dg_dk * count; + point.b += step.db_dk * count; + } +} + +template +void PS_GPU::DrawLine(line_point *points) +{ + int32 i_dx; + int32 i_dy; + int32 k; + line_fxp_coord cur_point; + line_fxp_step step; + + i_dx = abs(points[1].x - points[0].x); + i_dy = abs(points[1].y - points[0].y); + k = (i_dx > i_dy) ? i_dx : i_dy; + + if(i_dx >= 1024) + { + PSX_DBG(PSX_DBG_WARNING, "[GPU] Line too long: i_dx=%d\n", i_dx); + return; + } + + if(i_dy >= 512) + { + PSX_DBG(PSX_DBG_WARNING, "[GPU] Line too long: i_dy=%d\n", i_dy); + return; + } + + // May not be correct(do tests for the case of k == i_dy on real thing. + if(points[0].x > points[1].x) + { + line_point tmp = points[1]; + + points[1] = points[0]; + points[0] = tmp; + } + + DrawTimeAvail -= k * ((BlendMode >= 0) ? 2 : 1); + + // + // + // + + LinePointsToFXPStep(points[0], points[1], k, step); + LinePointToFXPCoord(points[0], step, cur_point); + + // + // + // + for(int32 i = 0; i <= k; i++) // <= is not a typo. + { + // Sign extension is not necessary here for x and y, due to the maximum values that ClipX1 and ClipY1 can contain. + const int32 x = (cur_point.x >> Line_XY_FractBits) & 2047; + const int32 y = (cur_point.y >> Line_XY_FractBits) & 2047; + uint16 pix = 0x8000; + + if(!LineSkipTest(y)) + { + uint8 r, g, b; + + if(goraud) + { + r = cur_point.r >> Line_RGB_FractBits; + g = cur_point.g >> Line_RGB_FractBits; + b = cur_point.b >> Line_RGB_FractBits; + } + else + { + r = points[0].r; + g = points[0].g; + b = points[0].b; + } + + if(goraud && dtd) + { + pix |= DitherLUT[y & 3][x & 3][r] << 0; + pix |= DitherLUT[y & 3][x & 3][g] << 5; + pix |= DitherLUT[y & 3][x & 3][b] << 10; + } + else + { + pix |= (r >> 3) << 0; + pix |= (g >> 3) << 5; + pix |= (b >> 3) << 10; + } + + // FIXME: There has to be a faster way than checking for being inside the drawing area for each pixel. + if(x >= ClipX0 && x <= ClipX1 && y >= ClipY0 && y <= ClipY1) + PlotPixel(x, y, pix); + } + + AddLineStep(cur_point, step); + } +} + +template +INLINE void PS_GPU::Command_DrawLine(const uint32 *cb) +{ + const uint8 cc = cb[0] >> 24; // For pline handling later. + line_point points[2]; + + DrawTimeAvail -= 16; // FIXME, correct time. + + if(polyline && InCmd == INCMD_PLINE) + { + //printf("PLINE N\n"); + points[0] = InPLine_PrevPoint; + } + else + { + points[0].r = (*cb >> 0) & 0xFF; + points[0].g = (*cb >> 8) & 0xFF; + points[0].b = (*cb >> 16) & 0xFF; + cb++; + + points[0].x = sign_x_to_s32(11, ((*cb >> 0) & 0xFFFF)) + OffsX; + points[0].y = sign_x_to_s32(11, ((*cb >> 16) & 0xFFFF)) + OffsY; + cb++; + } + + if(goraud) + { + points[1].r = (*cb >> 0) & 0xFF; + points[1].g = (*cb >> 8) & 0xFF; + points[1].b = (*cb >> 16) & 0xFF; + cb++; + } + else + { + points[1].r = points[0].r; + points[1].g = points[0].g; + points[1].b = points[0].b; + } + + points[1].x = sign_x_to_s32(11, ((*cb >> 0) & 0xFFFF)) + OffsX; + points[1].y = sign_x_to_s32(11, ((*cb >> 16) & 0xFFFF)) + OffsY; + cb++; + + if(polyline) + { + InPLine_PrevPoint = points[1]; + + if(InCmd != INCMD_PLINE) + { + InCmd = INCMD_PLINE; + InCmd_CC = cc; + } + } + + DrawLine(points); +} + diff --git a/psx/octoshock/psx/gpu_polygon.inc b/psx/octoshock/psx/gpu_polygon.inc new file mode 100644 index 0000000000..4f8dd28b62 --- /dev/null +++ b/psx/octoshock/psx/gpu_polygon.inc @@ -0,0 +1,514 @@ +#define COORD_FBS 12 +#define COORD_MF_INT(n) ((n) << COORD_FBS) + +/* + Store and do most math with interpolant coordinates and deltas as unsigned to avoid violating strict overflow(due to biasing), + but when actually grabbing the coordinates, treat them as signed(with signed right shift) so we can do saturation properly. +*/ +static INLINE int32 COORD_GET_INT(int32 n) +{ + return(n >> COORD_FBS); +} + +struct i_group +{ + uint32 u, v; + uint32 r, g, b; + uint32 dummy0[3]; +}; + +struct i_deltas +{ + uint32 du_dx, dv_dx; + uint32 dr_dx, dg_dx, db_dx; + uint32 dummy0[3]; + + uint32 du_dy, dv_dy; + uint32 dr_dy, dg_dy, db_dy; + uint32 dummy1[3]; +}; + +static INLINE int64 MakePolyXFP(int32 x) +{ + return ((int64)x << 32) + ((1LL << 32) - (1 << 11)); +} + +static INLINE int64 MakePolyXFPStep(int32 dx, int32 dy) +{ + int64 ret; + int64 dx_ex = (int64)dx << 32; + + if(dx_ex < 0) + dx_ex -= dy - 1; + + if(dx_ex > 0) + dx_ex += dy - 1; + + ret = dx_ex / dy; + + return(ret); +} + +static INLINE int32 GetPolyXFP_Int(int64 xfp) +{ + return(xfp >> 32); +} + +//#define CALCIS(x,y) ( A.x * (B.y - C.y) + B.x * (C.y - A.y) + C.x * (A.y - B.y) ) +#define CALCIS(x,y) (((B.x - A.x) * (C.y - B.y)) - ((C.x - B.x) * (B.y - A.y))) +static INLINE bool CalcIDeltas(i_deltas &idl, const tri_vertex &A, const tri_vertex &B, const tri_vertex &C) +{ + const unsigned sa = 32; + int64 num = ((int64)COORD_MF_INT(1)) << sa; + int64 denom = CALCIS(x, y); + int64 one_div; + + if(!denom) + return(false); + + one_div = num / denom; + + idl.dr_dx = ((one_div * CALCIS(r, y)) + 0x00000000) >> sa; + idl.dr_dy = ((one_div * CALCIS(x, r)) + 0x00000000) >> sa; + + idl.dg_dx = ((one_div * CALCIS(g, y)) + 0x00000000) >> sa; + idl.dg_dy = ((one_div * CALCIS(x, g)) + 0x00000000) >> sa; + + idl.db_dx = ((one_div * CALCIS(b, y)) + 0x00000000) >> sa; + idl.db_dy = ((one_div * CALCIS(x, b)) + 0x00000000) >> sa; + + idl.du_dx = ((one_div * CALCIS(u, y)) + 0x00000000) >> sa; + idl.du_dy = ((one_div * CALCIS(x, u)) + 0x00000000) >> sa; + + idl.dv_dx = ((one_div * CALCIS(v, y)) + 0x00000000) >> sa; + idl.dv_dy = ((one_div * CALCIS(x, v)) + 0x00000000) >> sa; + + // idl.du_dx = ((int64)CALCIS(u, y) << COORD_FBS) / denom; + // idl.du_dy = ((int64)CALCIS(x, u) << COORD_FBS) / denom; + + // idl.dv_dx = ((int64)CALCIS(v, y) << COORD_FBS) / denom; + // idl.dv_dy = ((int64)CALCIS(x, v) << COORD_FBS) / denom; + + //printf("Denom=%lld - CIS_UY=%d, CIS_XU=%d, CIS_VY=%d, CIS_XV=%d\n", denom, CALCIS(u, y), CALCIS(x, u), CALCIS(v, y), CALCIS(x, v)); + //printf(" du_dx=0x%08x, du_dy=0x%08x --- dv_dx=0x%08x, dv_dy=0x%08x\n", idl.du_dx, idl.du_dy, idl.dv_dx, idl.dv_dy); + + return(true); +} +#undef CALCIS + +template +static INLINE void AddIDeltas_DX(i_group &ig, const i_deltas &idl, uint32 count = 1) +{ + if(textured) + { + ig.u += idl.du_dx * count; + ig.v += idl.dv_dx * count; + } + + if(goraud) + { + ig.r += idl.dr_dx * count; + ig.g += idl.dg_dx * count; + ig.b += idl.db_dx * count; + } +} + +template +static INLINE void AddIDeltas_DY(i_group &ig, const i_deltas &idl, uint32 count = 1) +{ + if(textured) + { + ig.u += idl.du_dy * count; + ig.v += idl.dv_dy * count; + } + + if(goraud) + { + ig.r += idl.dr_dy * count; + ig.g += idl.dg_dy * count; + ig.b += idl.db_dy * count; + } +} + +template +INLINE void PS_GPU::DrawSpan(int y, uint32 clut_offset, const int32 x_start, const int32 x_bound, i_group ig, const i_deltas &idl) +{ + int32 xs = x_start, xb = x_bound; + + if(LineSkipTest(y)) + return; + + if(xs < xb) // (xs != xb) + { + if(xs < ClipX0) + xs = ClipX0; + + if(xb > (ClipX1 + 1)) + xb = ClipX1 + 1; + + if(xs < xb) + { + DrawTimeAvail -= (xb - xs); + + if(goraud || textured) + { + DrawTimeAvail -= (xb - xs); + } + else if((BlendMode >= 0) || MaskEval_TA) + { + DrawTimeAvail -= (((xb + 1) & ~1) - (xs & ~1)) >> 1; + } + } + + if(textured) + { + ig.u += (xs * idl.du_dx) + (y * idl.du_dy); + ig.v += (xs * idl.dv_dx) + (y * idl.dv_dy); + } + + if(goraud) + { + ig.r += (xs * idl.dr_dx) + (y * idl.dr_dy); + ig.g += (xs * idl.dg_dx) + (y * idl.dg_dy); + ig.b += (xs * idl.db_dx) + (y * idl.db_dy); + } + + for(int32 x = xs; MDFN_LIKELY(x < xb); x++) + { + uint32 r, g, b; + + if(goraud) + { + r = RGB8SAT[COORD_GET_INT(ig.r)]; + g = RGB8SAT[COORD_GET_INT(ig.g)]; + b = RGB8SAT[COORD_GET_INT(ig.b)]; + } + else + { + r = COORD_GET_INT(ig.r); + g = COORD_GET_INT(ig.g); + b = COORD_GET_INT(ig.b); + } + + if(textured) + { + uint16 fbw = GetTexel(clut_offset, COORD_GET_INT(ig.u), COORD_GET_INT(ig.v)); + + if(fbw) + { + if(TexMult) + { + if(dtd) + fbw = ModTexel(fbw, r, g, b, x & 3, y & 3); + else + fbw = ModTexel(fbw, r, g, b, 3, 2); //x & 3, y & 3); + } + PlotPixel(x, y, fbw); + } + } + else + { + uint16 pix = 0x8000; + + if(goraud && dtd) + { + pix |= DitherLUT[y & 3][x & 3][r] << 0; + pix |= DitherLUT[y & 3][x & 3][g] << 5; + pix |= DitherLUT[y & 3][x & 3][b] << 10; + } + else + { + pix |= (r >> 3) << 0; + pix |= (g >> 3) << 5; + pix |= (b >> 3) << 10; + } + + PlotPixel(x, y, pix); + } + + AddIDeltas_DX(ig, idl); + //AddStep(perp_coord, perp_step); + } + } +} + +template +void PS_GPU::DrawTriangle(tri_vertex *vertices, uint32 clut) +{ + i_deltas idl; + + // + // Sort vertices by y. + // + if(vertices[2].y < vertices[1].y) + { + tri_vertex tmp = vertices[1]; + vertices[1] = vertices[2]; + vertices[2] = tmp; + } + + if(vertices[1].y < vertices[0].y) + { + tri_vertex tmp = vertices[0]; + vertices[0] = vertices[1]; + vertices[1] = tmp; + } + + if(vertices[2].y < vertices[1].y) + { + tri_vertex tmp = vertices[1]; + vertices[1] = vertices[2]; + vertices[2] = tmp; + } + + if(vertices[0].y == vertices[2].y) + return; + + if((vertices[2].y - vertices[0].y) >= 512) + { + //PSX_WARNING("[GPU] Triangle height too large: %d", (vertices[2].y - vertices[0].y)); + return; + } + + if(abs(vertices[2].x - vertices[0].x) >= 1024 || + abs(vertices[2].x - vertices[1].x) >= 1024 || + abs(vertices[1].x - vertices[0].x) >= 1024) + { + //PSX_WARNING("[GPU] Triangle width too large: %d %d %d", abs(vertices[2].x - vertices[0].x), abs(vertices[2].x - vertices[1].x), abs(vertices[1].x - vertices[0].x)); + return; + } + + if(!CalcIDeltas(idl, vertices[0], vertices[1], vertices[2])) + return; + + // [0] should be top vertex, [2] should be bottom vertex, [1] should be off to the side vertex. + // + // + int32 y_start = vertices[0].y; + int32 y_middle = vertices[1].y; + int32 y_bound = vertices[2].y; + + int64 base_coord; + int64 base_step; + + int64 bound_coord_ul; + int64 bound_coord_us; + + int64 bound_coord_ll; + int64 bound_coord_ls; + + bool right_facing; + //bool bottom_up; + i_group ig; + + // + // Find vertex with lowest X coordinate, and use as the base for calculating interpolants from. + // + { + unsigned iggvi = 0; + + // + // <=, not < + // + if(vertices[1].x <= vertices[iggvi].x) + iggvi = 1; + + if(vertices[2].x <= vertices[iggvi].x) + iggvi = 2; + + ig.u = COORD_MF_INT(vertices[iggvi].u) + (1 << (COORD_FBS - 1)); + ig.v = COORD_MF_INT(vertices[iggvi].v) + (1 << (COORD_FBS - 1)); + ig.r = COORD_MF_INT(vertices[iggvi].r); + ig.g = COORD_MF_INT(vertices[iggvi].g); + ig.b = COORD_MF_INT(vertices[iggvi].b); + + AddIDeltas_DX(ig, idl, -vertices[iggvi].x); + AddIDeltas_DY(ig, idl, -vertices[iggvi].y); + } + + base_coord = MakePolyXFP(vertices[0].x); + base_step = MakePolyXFPStep((vertices[2].x - vertices[0].x), (vertices[2].y - vertices[0].y)); + + bound_coord_ul = MakePolyXFP(vertices[0].x); + bound_coord_ll = MakePolyXFP(vertices[1].x); + + // + // + // + + + if(vertices[1].y == vertices[0].y) + { + bound_coord_us = 0; + right_facing = (bool)(vertices[1].x > vertices[0].x); + } + else + { + bound_coord_us = MakePolyXFPStep((vertices[1].x - vertices[0].x), (vertices[1].y - vertices[0].y)); + right_facing = (bool)(bound_coord_us > base_step); + } + + if(vertices[2].y == vertices[1].y) + bound_coord_ls = 0; + else + bound_coord_ls = MakePolyXFPStep((vertices[2].x - vertices[1].x), (vertices[2].y - vertices[1].y)); + + if(y_start < ClipY0) + { + int32 count = ClipY0 - y_start; + + y_start = ClipY0; + base_coord += base_step * count; + bound_coord_ul += bound_coord_us * count; + + if(y_middle < ClipY0) + { + int32 count_ls = ClipY0 - y_middle; + + y_middle = ClipY0; + bound_coord_ll += bound_coord_ls * count_ls; + } + } + + if(y_bound > (ClipY1 + 1)) + { + y_bound = ClipY1 + 1; + + if(y_middle > y_bound) + y_middle = y_bound; + } + + if(right_facing) + { + for(int32 y = y_start; y < y_middle; y++) + { + DrawSpan(y, clut, GetPolyXFP_Int(base_coord), GetPolyXFP_Int(bound_coord_ul), ig, idl); + base_coord += base_step; + bound_coord_ul += bound_coord_us; + } + + for(int32 y = y_middle; y < y_bound; y++) + { + DrawSpan(y, clut, GetPolyXFP_Int(base_coord), GetPolyXFP_Int(bound_coord_ll), ig, idl); + base_coord += base_step; + bound_coord_ll += bound_coord_ls; + } + } + else + { + for(int32 y = y_start; y < y_middle; y++) + { + DrawSpan(y, clut, GetPolyXFP_Int(bound_coord_ul), GetPolyXFP_Int(base_coord), ig, idl); + base_coord += base_step; + bound_coord_ul += bound_coord_us; + } + + for(int32 y = y_middle; y < y_bound; y++) + { + DrawSpan(y, clut, GetPolyXFP_Int(bound_coord_ll), GetPolyXFP_Int(base_coord), ig, idl); + base_coord += base_step; + bound_coord_ll += bound_coord_ls; + } + } + +#if 0 + printf("[GPU] Vertices: %d:%d(r=%d, g=%d, b=%d) -> %d:%d(r=%d, g=%d, b=%d) -> %d:%d(r=%d, g=%d, b=%d)\n\n\n", vertices[0].x, vertices[0].y, + vertices[0].r, vertices[0].g, vertices[0].b, + vertices[1].x, vertices[1].y, + vertices[1].r, vertices[1].g, vertices[1].b, + vertices[2].x, vertices[2].y, + vertices[2].r, vertices[2].g, vertices[2].b); +#endif +} + +template +INLINE void PS_GPU::Command_DrawPolygon(const uint32 *cb) +{ + const unsigned cb0 = cb[0]; + tri_vertex vertices[3]; + uint32 clut = 0; + unsigned sv = 0; + //uint32 tpage = 0; + + // Base timing is approximate, and could be improved. + if(numvertices == 4 && InCmd == INCMD_QUAD) + DrawTimeAvail -= (28 + 18); + else + DrawTimeAvail -= (64 + 18); + + if(goraud && textured) + DrawTimeAvail -= 150 * 3; + else if(goraud) + DrawTimeAvail -= 96 * 3; + else if(textured) + DrawTimeAvail -= 60 * 3; + + if(numvertices == 4) + { + if(InCmd == INCMD_QUAD) + { + memcpy(&vertices[0], &InQuad_F3Vertices[1], 2 * sizeof(tri_vertex)); + clut = InQuad_clut; + sv = 2; + } + } + //else + // memset(vertices, 0, sizeof(vertices)); + + for(unsigned v = sv; v < 3; v++) + { + if(v == 0 || goraud) + { + uint32 raw_color = (*cb & 0xFFFFFF); + + vertices[v].r = raw_color & 0xFF; + vertices[v].g = (raw_color >> 8) & 0xFF; + vertices[v].b = (raw_color >> 16) & 0xFF; + + cb++; + } + else + { + vertices[v].r = vertices[0].r; + vertices[v].g = vertices[0].g; + vertices[v].b = vertices[0].b; + } + + vertices[v].x = sign_x_to_s32(11, ((int16)(*cb & 0xFFFF))) + OffsX; + vertices[v].y = sign_x_to_s32(11, ((int16)(*cb >> 16))) + OffsY; + cb++; + + if(textured) + { + vertices[v].u = (*cb & 0xFF); + vertices[v].v = (*cb >> 8) & 0xFF; + + if(v == 0) + { + clut = ((*cb >> 16) & 0xFFFF) << 4; + } + + cb++; + } + } + + if(numvertices == 4) + { + if(InCmd == INCMD_QUAD) + { + InCmd = INCMD_NONE; + } + else + { + InCmd = INCMD_QUAD; + InCmd_CC = cb0 >> 24; + memcpy(&InQuad_F3Vertices[0], &vertices[0], sizeof(tri_vertex) * 3); + InQuad_clut = clut; + } + } + + DrawTriangle(vertices, clut); +} + +#undef COORD_FBS +#undef COORD_MF_INT diff --git a/psx/octoshock/psx/gpu_sprite.inc b/psx/octoshock/psx/gpu_sprite.inc new file mode 100644 index 0000000000..38e16ebe4c --- /dev/null +++ b/psx/octoshock/psx/gpu_sprite.inc @@ -0,0 +1,235 @@ +template +void PS_GPU::DrawSprite(int32 x_arg, int32 y_arg, int32 w, int32 h, uint8 u_arg, uint8 v_arg, uint32 color, uint32 clut_offset) +{ + const int32 r = color & 0xFF; + const int32 g = (color >> 8) & 0xFF; + const int32 b = (color >> 16) & 0xFF; + const uint16 fill_color = 0x8000 | ((r >> 3) << 0) | ((g >> 3) << 5) | ((b >> 3) << 10); + + int32 x_start, x_bound; + int32 y_start, y_bound; + uint8 u, v; + int v_inc = 1, u_inc = 1; + + //printf("[GPU] Sprite: x=%d, y=%d, w=%d, h=%d\n", x_arg, y_arg, w, h); + + x_start = x_arg; + x_bound = x_arg + w; + + y_start = y_arg; + y_bound = y_arg + h; + + if(textured) + { + u = u_arg; + v = v_arg; + + //if(FlipX || FlipY || (u & 1) || (v & 1) || ((TexMode_TA == 0) && ((u & 3) || (v & 3)))) + // fprintf(stderr, "Flippy: %d %d 0x%02x 0x%02x\n", FlipX, FlipY, u, v); + + if(FlipX) + { + u_inc = -1; + u |= 1; + } + // FIXME: Something weird happens when lower bit of u is set and we're not doing horizontal flip, but I'm not sure what it is exactly(needs testing) + // It may only happen to the first pixel, so look for that case too during testing. + //else + // u = (u + 1) & ~1; + + if(FlipY) + { + v_inc = -1; + } + } + + if(x_start < ClipX0) + { + if(textured) + u += (ClipX0 - x_start) * u_inc; + + x_start = ClipX0; + } + + if(y_start < ClipY0) + { + if(textured) + v += (ClipY0 - y_start) * v_inc; + + y_start = ClipY0; + } + + if(x_bound > (ClipX1 + 1)) + x_bound = ClipX1 + 1; + + if(y_bound > (ClipY1 + 1)) + y_bound = ClipY1 + 1; + + if(y_bound > y_start && x_bound > x_start) + { + // + // Note(TODO): From tests on a PS1, even a 0-width sprite takes up time to "draw" proportional to its height. + // + int32 suck_time = (x_bound - x_start) * (y_bound - y_start); + + // Disabled until we can get it to take into account texture windowing, which can cause large sprites to be drawn entirely from cache(and not suffer from a texturing + // penalty); and disabled until we find a game that needs more accurate sprite draw timing. :b +#if 0 + if(textured) + { + // Empirically-observed approximations of time(66MHz cycles) taken to draw large textured sprites in the various texture depths, when the texture data and CLUT data + // was zero(non-zero takes longer to draw, TODO test that more): + // 4bpp - area * 2 + // 8bpp - area * 3 + // 15/16bpp - area * 5 + // (other factors come into more importance for smaller sprites) + static const int cw[4] = { 64, 32, 32, 32 }; + static const int ch[4] = { 64, 64, 32, 32 }; + static const int mm[4] = { 2 - 1, 3 - 1, 5 - 1, 5 - 1 }; + + // Parts of the first few(up to texture cache height) horizontal lines can be in cache, so assume they are. + suck_time += mm[TexMode_TA] * std::max(0, (x_bound - x_start) - cw[TexMode_TA]) * std::min(ch[TexMode_TA], y_bound - y_start); + + // The rest of the horizontal lines should not possibly have parts in the cache now. + suck_time += mm[TexMode_TA] * (x_bound - x_start) * std::max(0, (y_bound - y_start) - ch[TexMode_TA]); + } + else +#endif + + if((BlendMode >= 0) || MaskEval_TA) + { + suck_time += ((((x_bound + 1) & ~1) - (x_start & ~1)) * (y_bound - y_start)) >> 1; + } + + DrawTimeAvail -= suck_time; + } + + + //HeightMode && !dfe && ((y & 1) == ((DisplayFB_YStart + !field_atvs) & 1)) && !DisplayOff + //printf("%d:%d, %d, %d ---- heightmode=%d displayfb_ystart=%d field_atvs=%d displayoff=%d\n", w, h, scanline, dfe, HeightMode, DisplayFB_YStart, field_atvs, DisplayOff); + + for(int32 y = y_start; MDFN_LIKELY(y < y_bound); y++) + { + uint8 u_r; + + if(textured) + u_r = u; + + if(!LineSkipTest(y)) + { + for(int32 x = x_start; MDFN_LIKELY(x < x_bound); x++) + { + if(textured) + { + uint16 fbw = GetTexel(clut_offset, u_r, v); + + if(fbw) + { + if(TexMult) + { + fbw = ModTexel(fbw, r, g, b, 3, 2); + } + PlotPixel(x, y, fbw); + } + } + else + PlotPixel(x, y, fill_color); + + if(textured) + u_r += u_inc; + } + } + if(textured) + v += v_inc; + } +} + +template +INLINE void PS_GPU::Command_DrawSprite(const uint32 *cb) +{ + int32 x, y; + int32 w, h; + uint8 u = 0, v = 0; + uint32 color = 0; + uint32 clut = 0; + + DrawTimeAvail -= 16; // FIXME, correct time. + + color = *cb & 0x00FFFFFF; + cb++; + + x = sign_x_to_s32(11, (*cb & 0xFFFF)); + y = sign_x_to_s32(11, (*cb >> 16)); + cb++; + + if(textured) + { + u = *cb & 0xFF; + v = (*cb >> 8) & 0xFF; + clut = ((*cb >> 16) & 0xFFFF) << 4; + cb++; + } + + switch(raw_size) + { + default: + case 0: + w = (*cb & 0x3FF); + h = (*cb >> 16) & 0x1FF; + cb++; + break; + + case 1: + w = 1; + h = 1; + break; + + case 2: + w = 8; + h = 8; + break; + + case 3: + w = 16; + h = 16; + break; + } + + //printf("SPRITE: %d %d %d -- %d %d\n", raw_size, x, y, w, h); + + x = sign_x_to_s32(11, x + OffsX); + y = sign_x_to_s32(11, y + OffsY); + + switch(SpriteFlip & 0x3000) + { + case 0x0000: + if(!TexMult || color == 0x808080) + DrawSprite(x, y, w, h, u, v, color, clut); + else + DrawSprite(x, y, w, h, u, v, color, clut); + break; + + case 0x1000: + if(!TexMult || color == 0x808080) + DrawSprite(x, y, w, h, u, v, color, clut); + else + DrawSprite(x, y, w, h, u, v, color, clut); + break; + + case 0x2000: + if(!TexMult || color == 0x808080) + DrawSprite(x, y, w, h, u, v, color, clut); + else + DrawSprite(x, y, w, h, u, v, color, clut); + break; + + case 0x3000: + if(!TexMult || color == 0x808080) + DrawSprite(x, y, w, h, u, v, color, clut); + else + DrawSprite(x, y, w, h, u, v, color, clut); + break; + } +} + + diff --git a/psx/octoshock/psx/gte.cpp b/psx/octoshock/psx/gte.cpp new file mode 100644 index 0000000000..e83b907de7 --- /dev/null +++ b/psx/octoshock/psx/gte.cpp @@ -0,0 +1,1736 @@ +/* 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 "psx.h" +#include "gte.h" + +static uint32 ReciprocalTable[0x8000] = +{ + #include "gte_divrecip.inc" +}; + +/* Notes: + + AVSZ3/AVSZ4: + OTZ is MAC0 >> 12 + OTZ overflow/underflow flag is set in an overflow condition even if MAC0 == 0. + sf field bit has no effect? + + FLAG register: + Bits present mask: 0xfffff000 + + Checksum bit can't be directly set, it's apparently calculated like (bool)(FLAGS & 0x7f87e000) + + Instructions effectively clear it 0 at start. (todo: test "invalid" instructions) + + X/Y FIFO [3] register write pushes a copy down to [2] + +*/ + +#ifndef PSXDEV_GTE_TESTING +namespace MDFN_IEN_PSX +{ +#endif + +#include "emuware/PACKED.h" +struct gtematrix +{ + int16 MX[3][3]; + int16 dummy; +}; +#include "emuware/PACKED_END.h" + +typedef struct +{ + union + { + struct + { + uint8 R; + uint8 G; + uint8 B; + uint8 CD; + }; + uint8 Raw8[4]; + }; +} gtergb; + +typedef struct +{ + int16 X; + int16 Y; +} gtexy; + +int16 Lm_B(unsigned int which, int32 value, int lm); +uint8 Lm_C(unsigned int which, int32 value); + + + +int32 Lm_G(unsigned int which, int32 value); +int32 Lm_H(int32 value); + +void MAC_to_RGB_FIFO(void); +void MAC_to_IR(int lm); + +void MultiplyMatrixByVector(const gtematrix *matrix, const int16 *v, const int32 *crv, uint32 sf, int lm); + +static uint32 CR[32]; +static uint32 FLAGS; // Temporary for instruction execution, copied into CR[31] at end of instruction execution. + +typedef union +{ + gtematrix All[4]; + int32 Raw[4][5]; // Don't read from this(Raw[][]), only write(and when writing, if running on a big-endian platform, swap the upper 16-bits with the lower 16-bits) + int16 Raw16[4][10]; + + struct + { + gtematrix Rot; + gtematrix Light; + gtematrix Color; + gtematrix AbbyNormal; + }; +} Matrices_t; + +static Matrices_t Matrices; + +static union +{ + int32 All[4][4]; // Really only [4][3], but [4] to ease address calculation. + + struct + { + int32 T[4]; + int32 B[4]; + int32 FC[4]; + int32 Null[4]; + }; +} CRVectors; + +static int32 OFX; +static int32 OFY; +static uint16 H; +static int16 DQA; +static int32 DQB; + +static int16 ZSF3; +static int16 ZSF4; + + +// Begin DR +static int16 Vectors[3][4]; +static gtergb RGB; +static uint16 OTZ; + +static int16 IR[4]; + +#define IR0 IR[0] +#define IR1 IR[1] +#define IR2 IR[2] +#define IR3 IR[3] + +static gtexy XY_FIFO[4]; +static uint16 Z_FIFO[4]; +static gtergb RGB_FIFO[3]; +static int32 MAC[4]; +static uint32 LZCS; +static uint32 LZCR; + +static uint32 Reg23; +// end DR + +int32 RTPS(uint32 instr); +int32 RTPT(uint32 instr); + +int32 NCLIP(uint32 instr); + +void NormColor(uint32 sf, int lm, uint32 v); +int32 NCS(uint32 instr); +int32 NCT(uint32 instr); + + +void NormColorColor(uint32 v, uint32 sf, int lm); +int32 NCCS(uint32 instr); +int32 NCCT(uint32 instr); + +void NormColorDepthCue(uint32 v, uint32 sf, int lm); +int32 NCDS(uint32 instr); +int32 NCDT(uint32 instr); + +int32 AVSZ3(uint32 instr); +int32 AVSZ4(uint32 instr); + +int32 OP(uint32 instr); + +int32 GPF(uint32 instr); +int32 GPL(uint32 instr); + +void DepthCue(int mult_IR123, int RGB_from_FIFO, uint32 sf, int lm); +int32 DCPL(uint32 instr); +int32 DPCS(uint32 instr); +int32 DPCT(uint32 instr); +int32 INTPL(uint32 instr); + +int32 SQR(uint32 instr); +int32 MVMVA(uint32 instr); + +static INLINE uint8 Sat5(int16 cc) +{ + if(cc < 0) + cc = 0; + if(cc > 0x1F) + cc = 0x1F; + return(cc); +} + + + +void GTE_Power(void) +{ + memset(CR, 0, sizeof(CR)); + //memset(DR, 0, sizeof(DR)); + + memset(Matrices.All, 0, sizeof(Matrices.All)); + memset(CRVectors.All, 0, sizeof(CRVectors.All)); + OFX = 0; + OFY = 0; + H = 0; + DQA = 0; + DQB = 0; + ZSF3 = 0; + ZSF4 = 0; + + + memset(Vectors, 0, sizeof(Vectors)); + memset(&RGB, 0, sizeof(RGB)); + OTZ = 0; + IR0 = 0; + IR1 = 0; + IR2 = 0; + IR3 = 0; + + memset(XY_FIFO, 0, sizeof(XY_FIFO)); + memset(Z_FIFO, 0, sizeof(Z_FIFO)); + memset(RGB_FIFO, 0, sizeof(RGB_FIFO)); + memset(MAC, 0, sizeof(MAC)); + LZCS = 0; + LZCR = 0; + + Reg23 = 0; +} + +// TODO: Don't save redundant state, regarding CR cache variables +int GTE_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFARRAY32(CR, 32), + SFVAR(FLAGS), + + SFARRAY16(&Matrices.Raw16[0][0], 4 * 10), + + SFARRAY32(&CRVectors.All[0][0], 4 * 4), + + SFVAR(OFX), + SFVAR(OFY), + SFVAR(H), + SFVAR(DQA), + SFVAR(DQB), + + SFVAR(ZSF3), + SFVAR(ZSF4), + SFARRAY16(&Vectors[0][0], 3 * 4), + + SFARRAY(RGB.Raw8, 4), + SFVAR(OTZ), + SFARRAY16(IR, 4), + + SFVAR(XY_FIFO[0].X), + SFVAR(XY_FIFO[0].Y), + SFVAR(XY_FIFO[1].X), + SFVAR(XY_FIFO[1].Y), + SFVAR(XY_FIFO[2].X), + SFVAR(XY_FIFO[2].Y), + SFVAR(XY_FIFO[3].X), + SFVAR(XY_FIFO[3].Y), + + SFARRAY16(Z_FIFO, 4), + + SFARRAY(RGB_FIFO[0].Raw8, 4), + SFARRAY(RGB_FIFO[1].Raw8, 4), + SFARRAY(RGB_FIFO[2].Raw8, 4), + + SFARRAY32(MAC, 4), + + SFVAR(LZCS), + SFVAR(LZCR), + SFVAR(Reg23), + + SFEND + }; + int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "GTE"); + + if(load) + { + + } + + return(ret); +} + + +void GTE_WriteCR(unsigned int which, uint32 value) +{ + static const uint32 mask_table[32] = { + /* 0x00 */ + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + + /* 0x08 */ + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + + /* 0x10 */ + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + + /* 0x18 */ + 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF, 0x0000FFFF, 0xFFFFFFFF, 0x0000FFFF, 0x0000FFFF, 0xFFFFFFFF + }; + + //PSX_WARNING("[GTE] Write CR %d, 0x%08x", which, value); + + value &= mask_table[which]; + + CR[which] = value | (CR[which] & ~mask_table[which]); + + if(which < 24) + { + int we = which >> 3; + which &= 0x7; + + if(which >= 5) + CRVectors.All[we][which - 5] = value; + else + { + #ifdef MSB_FIRST + Matrices.Raw[we][which] = (value << 16) | (value >> 16); + #else + Matrices.Raw[we][which] = value; + #endif + } + return; + } + + switch(which) + { + case 24: + OFX = value; + break; + + case 25: + OFY = value; + break; + + case 26: + H = value; + break; + + case 27: + DQA = value; + break; + + case 28: + DQB = value; + break; + + case 29: + ZSF3 = value; + break; + + case 30: + ZSF4 = value; + break; + + case 31: + CR[31] = (value & 0x7ffff000) | ((value & 0x7f87e000) ? (1 << 31) : 0); + break; + } +} + +uint32 GTE_ReadCR(unsigned int which) +{ + uint32 ret = 0; + + switch(which) + { + default: + ret = CR[which]; + if(which == 4 || which == 12 || which == 20) + ret = (int16)ret; + break; + + case 24: + ret = OFX; + break; + + case 25: + ret = OFY; + break; + + case 26: + ret = (int16)H; + break; + + case 27: + ret = (int16)DQA; + break; + + case 28: + ret = DQB; + break; + + case 29: + ret = (int16)ZSF3; + break; + + case 30: + ret = (int16)ZSF4; + break; + + case 31: + ret = CR[31]; + break; + } + + return(ret); +} + +void GTE_WriteDR(unsigned int which, uint32 value) +{ + switch(which & 0x1F) + { + case 0: + Vectors[0][0] = value; + Vectors[0][1] = value >> 16; + break; + + case 1: + Vectors[0][2] = value; + break; + + case 2: + Vectors[1][0] = value; + Vectors[1][1] = value >> 16; + break; + + case 3: + Vectors[1][2] = value; + break; + + case 4: + Vectors[2][0] = value; + Vectors[2][1] = value >> 16; + break; + + case 5: + Vectors[2][2] = value; + break; + + case 6: + RGB.R = value >> 0; + RGB.G = value >> 8; + RGB.B = value >> 16; + RGB.CD = value >> 24; + break; + + case 7: + OTZ = value; + break; + + case 8: + IR0 = value; + break; + + case 9: + IR1 = value; + break; + + case 10: + IR2 = value; + break; + + case 11: + IR3 = value; + break; + + case 12: + XY_FIFO[0].X = value; + XY_FIFO[0].Y = value >> 16; + break; + + case 13: + XY_FIFO[1].X = value; + XY_FIFO[1].Y = value >> 16; + break; + + case 14: + XY_FIFO[2].X = value; + XY_FIFO[2].Y = value >> 16; + XY_FIFO[3].X = value; + XY_FIFO[3].Y = value >> 16; + break; + + case 15: + XY_FIFO[3].X = value; + XY_FIFO[3].Y = value >> 16; + + XY_FIFO[0] = XY_FIFO[1]; + XY_FIFO[1] = XY_FIFO[2]; + XY_FIFO[2] = XY_FIFO[3]; + break; + + case 16: + Z_FIFO[0] = value; + break; + + case 17: + Z_FIFO[1] = value; + break; + + case 18: + Z_FIFO[2] = value; + break; + + case 19: + Z_FIFO[3] = value; + break; + + case 20: + RGB_FIFO[0].R = value; + RGB_FIFO[0].G = value >> 8; + RGB_FIFO[0].B = value >> 16; + RGB_FIFO[0].CD = value >> 24; + break; + + case 21: + RGB_FIFO[1].R = value; + RGB_FIFO[1].G = value >> 8; + RGB_FIFO[1].B = value >> 16; + RGB_FIFO[1].CD = value >> 24; + break; + + case 22: + RGB_FIFO[2].R = value; + RGB_FIFO[2].G = value >> 8; + RGB_FIFO[2].B = value >> 16; + RGB_FIFO[2].CD = value >> 24; + break; + + case 23: + Reg23 = value; + break; + + case 24: + MAC[0] = value; + break; + + case 25: + MAC[1] = value; + break; + + case 26: + MAC[2] = value; + break; + + case 27: + MAC[3] = value; + break; + + case 28: + IR1 = ((value >> 0) & 0x1F) << 7; + IR2 = ((value >> 5) & 0x1F) << 7; + IR3 = ((value >> 10) & 0x1F) << 7; + break; + + case 29: // Read-only + break; + + case 30: + LZCS = value; + { + uint32 test = value & 0x80000000; + LZCR = 0; + + while((value & 0x80000000) == test && LZCR < 32) + { + LZCR++; + value <<= 1; + } + } + break; + + case 31: // Read-only + break; + } +} + +uint32 GTE_ReadDR(unsigned int which) +{ + uint32 ret = 0; + + switch(which & 0x1F) + { + case 0: + ret = (uint16)Vectors[0][0] | ((uint16)Vectors[0][1] << 16); + break; + + case 1: + ret = (int16)Vectors[0][2]; + break; + + case 2: + ret = (uint16)Vectors[1][0] | ((uint16)Vectors[1][1] << 16); + break; + + case 3: + ret = (int16)Vectors[1][2]; + break; + + case 4: + ret = (uint16)Vectors[2][0] | ((uint16)Vectors[2][1] << 16); + break; + + case 5: + ret = (int16)Vectors[2][2]; + break; + + case 6: + ret = RGB.R | (RGB.G << 8) | (RGB.B << 16) | (RGB.CD << 24); + break; + + case 7: + ret = (uint16)OTZ; + break; + + case 8: + ret = (int16)IR0; + break; + + case 9: + ret = (int16)IR1; + break; + + case 10: + ret = (int16)IR2; + break; + + case 11: + ret = (int16)IR3; + break; + + case 12: + ret = (uint16)XY_FIFO[0].X | ((uint16)XY_FIFO[0].Y << 16); + break; + + case 13: + ret = (uint16)XY_FIFO[1].X | ((uint16)XY_FIFO[1].Y << 16); + break; + + case 14: + ret = (uint16)XY_FIFO[2].X | ((uint16)XY_FIFO[2].Y << 16); + break; + + case 15: + ret = (uint16)XY_FIFO[3].X | ((uint16)XY_FIFO[3].Y << 16); + break; + + case 16: + ret = (uint16)Z_FIFO[0]; + break; + + case 17: + ret = (uint16)Z_FIFO[1]; + break; + + case 18: + ret = (uint16)Z_FIFO[2]; + break; + + case 19: + ret = (uint16)Z_FIFO[3]; + break; + + case 20: + ret = RGB_FIFO[0].R | (RGB_FIFO[0].G << 8) | (RGB_FIFO[0].B << 16) | (RGB_FIFO[0].CD << 24); + break; + + case 21: + ret = RGB_FIFO[1].R | (RGB_FIFO[1].G << 8) | (RGB_FIFO[1].B << 16) | (RGB_FIFO[1].CD << 24); + break; + + case 22: + ret = RGB_FIFO[2].R | (RGB_FIFO[2].G << 8) | (RGB_FIFO[2].B << 16) | (RGB_FIFO[2].CD << 24); + break; + + case 23: + ret = Reg23; + break; + + case 24: + ret = MAC[0]; + break; + + case 25: + ret = MAC[1]; + break; + + case 26: + ret = MAC[2]; + break; + + case 27: + ret = MAC[3]; + break; + + case 28: + case 29: + ret = Sat5(IR1 >> 7) | (Sat5(IR2 >> 7) << 5) | (Sat5(IR3 >> 7) << 10); + break; + + case 30: + ret = LZCS; + break; + + case 31: + ret = LZCR; + break; + } + return(ret); +} + +#define sign_x_to_s64(_bits, _value) (((int64)((uint64)(_value) << (64 - _bits))) >> (64 - _bits)) +INLINE int64 A_MV(unsigned which, int64 value) +{ + if(value >= (1LL << 43)) + FLAGS |= 1 << (30 - which); + + if(value < -(1LL << 43)) + FLAGS |= 1 << (27 - which); + + return sign_x_to_s64(44, value); +} + +INLINE int64 F(int64 value) +{ + if(value < -2147483648LL) + { + // flag set here + FLAGS |= 1 << 15; + } + + if(value > 2147483647LL) + { + // flag set here + FLAGS |= 1 << 16; + } + return(value); +} + + +INLINE int16 Lm_B(unsigned int which, int32 value, int lm) +{ + int32 tmp = lm << 15; + + if(value < (-32768 + tmp)) + { + // set flag here + FLAGS |= 1 << (24 - which); + value = -32768 + tmp; + } + + if(value > 32767) + { + // Set flag here + FLAGS |= 1 << (24 - which); + value = 32767; + } + + return(value); +} + + +INLINE int16 Lm_B_PTZ(unsigned int which, int32 value, int32 ftv_value, int lm) +{ + int32 tmp = lm << 15; + + if(ftv_value < -32768) + { + FLAGS |= 1 << (24 - which); + } + + if(ftv_value > 32767) + { + FLAGS |= 1 << (24 - which); + } + + if(value < (-32768 + tmp)) + { + value = -32768 + tmp; + } + + if(value > 32767) + { + value = 32767; + } + + return(value); +} + +INLINE uint8 Lm_C(unsigned int which, int32 value) +{ + if(value & ~0xFF) + { + // Set flag here + FLAGS |= 1 << (21 - which); // Tested with GPF + + if(value < 0) + value = 0; + + if(value > 255) + value = 255; + } + + return(value); +} + +INLINE int32 Lm_D(int32 value, int unchained) +{ + // Not sure if we should have it as int64, or just chain on to and special case when the F flags are set. + if(!unchained) + { + if(FLAGS & (1 << 15)) + { + FLAGS |= 1 << 18; + return(0); + } + + if(FLAGS & (1 << 16)) + { + FLAGS |= 1 << 18; + return(0xFFFF); + } + } + + if(value < 0) + { + // Set flag here + value = 0; + FLAGS |= 1 << 18; // Tested with AVSZ3 + } + else if(value > 65535) + { + // Set flag here. + value = 65535; + FLAGS |= 1 << 18; // Tested with AVSZ3 + } + + return(value); +} + +INLINE int32 Lm_G(unsigned int which, int32 value) +{ + if(value < -1024) + { + // Set flag here + value = -1024; + FLAGS |= 1 << (14 - which); + } + + if(value > 1023) + { + // Set flag here. + value = 1023; + FLAGS |= 1 << (14 - which); + } + + return(value); +} + +// limit to 4096, not 4095 +INLINE int32 Lm_H(int32 value) +{ +#if 0 + if(FLAGS & (1 << 15)) + { + value = 0; + FLAGS |= 1 << 12; + return value; + } + + if(FLAGS & (1 << 16)) + { + value = 4096; + FLAGS |= 1 << 12; + return value; + } +#endif + + if(value < 0) + { + value = 0; + FLAGS |= 1 << 12; + } + + if(value > 4096) + { + value = 4096; + FLAGS |= 1 << 12; + } + + return(value); +} + +INLINE void MAC_to_RGB_FIFO(void) +{ + RGB_FIFO[0] = RGB_FIFO[1]; + RGB_FIFO[1] = RGB_FIFO[2]; + RGB_FIFO[2].R = Lm_C(0, MAC[1] >> 4); + RGB_FIFO[2].G = Lm_C(1, MAC[2] >> 4); + RGB_FIFO[2].B = Lm_C(2, MAC[3] >> 4); + RGB_FIFO[2].CD = RGB.CD; +} + + +INLINE void MAC_to_IR(int lm) +{ + IR1 = Lm_B(0, MAC[1], lm); + IR2 = Lm_B(1, MAC[2], lm); + IR3 = Lm_B(2, MAC[3], lm); +} + +INLINE void MultiplyMatrixByVector(const gtematrix *matrix, const int16 *v, const int32 *crv, uint32 sf, int lm) +{ + unsigned i; + + for(i = 0; i < 3; i++) + { + int64 tmp; + int32 mulr[3]; + + tmp = (int64)crv[i] << 12; + + if(matrix == &Matrices.AbbyNormal) + { + if(i == 0) + { + mulr[0] = -((RGB.R << 4) * v[0]); + mulr[1] = (RGB.R << 4) * v[1]; + mulr[2] = IR0 * v[2]; + } + else + { + mulr[0] = (int16)CR[i] * v[0]; + mulr[1] = (int16)CR[i] * v[1]; + mulr[2] = (int16)CR[i] * v[2]; + } + } + else + { + mulr[0] = matrix->MX[i][0] * v[0]; + mulr[1] = matrix->MX[i][1] * v[1]; + mulr[2] = matrix->MX[i][2] * v[2]; + } + + tmp = A_MV(i, tmp + mulr[0]); + if(crv == CRVectors.FC) + { + Lm_B(i, tmp >> sf, FALSE_0); + tmp = 0; + } + + tmp = A_MV(i, tmp + mulr[1]); + tmp = A_MV(i, tmp + mulr[2]); + + MAC[1 + i] = tmp >> sf; + } + + + MAC_to_IR(lm); +} + + +INLINE void MultiplyMatrixByVector_PT(const gtematrix *matrix, const int16 *v, const int32 *crv, uint32 sf, int lm) +{ + int64 tmp[3]; + unsigned i; + + for(i = 0; i < 3; i++) + { + int32 mulr[3]; + + tmp[i] = (int64)crv[i] << 12; + + mulr[0] = matrix->MX[i][0] * v[0]; + mulr[1] = matrix->MX[i][1] * v[1]; + mulr[2] = matrix->MX[i][2] * v[2]; + + tmp[i] = A_MV(i, tmp[i] + mulr[0]); + tmp[i] = A_MV(i, tmp[i] + mulr[1]); + tmp[i] = A_MV(i, tmp[i] + mulr[2]); + + MAC[1 + i] = tmp[i] >> sf; + } + + IR1 = Lm_B(0, MAC[1], lm); + IR2 = Lm_B(1, MAC[2], lm); + //printf("FTV: %08x %08x\n", crv[2], (uint32)(tmp[2] >> 12)); + IR3 = Lm_B_PTZ(2, MAC[3], tmp[2] >> 12, lm); + + Z_FIFO[0] = Z_FIFO[1]; + Z_FIFO[1] = Z_FIFO[2]; + Z_FIFO[2] = Z_FIFO[3]; + Z_FIFO[3] = Lm_D(tmp[2] >> 12, TRUE_1); +} + + +#define DECODE_FIELDS \ + const uint32 sf MDFN_NOWARN_UNUSED = (instr & (1 << 19)) ? 12 : 0; \ + const uint32 mx MDFN_NOWARN_UNUSED = (instr >> 17) & 0x3; \ + const uint32 v_i = (instr >> 15) & 0x3; \ + const int32* cv MDFN_NOWARN_UNUSED = CRVectors.All[(instr >> 13) & 0x3]; \ + const int lm MDFN_NOWARN_UNUSED = (instr >> 10) & 1; \ + int16 v[3] MDFN_NOWARN_UNUSED; \ + if(v_i == 3) \ + { \ + v[0] = IR1; \ + v[1] = IR2; \ + v[2] = IR3; \ + } \ + else \ + { \ + v[0] = Vectors[v_i][0]; \ + v[1] = Vectors[v_i][1]; \ + v[2] = Vectors[v_i][2]; \ + } + + +int32 SQR(uint32 instr) +{ + DECODE_FIELDS; + + MAC[1] = ((IR1 * IR1) >> sf); + MAC[2] = ((IR2 * IR2) >> sf); + MAC[3] = ((IR3 * IR3) >> sf); + + MAC_to_IR(lm); + + return(5); +} + + +int32 MVMVA(uint32 instr) +{ + DECODE_FIELDS; + + MultiplyMatrixByVector(&Matrices.All[mx], v, cv, sf, lm); + + return(8); +} + +static INLINE unsigned CountLeadingZeroU16(uint16 val) +{ + unsigned ret = 0; + + while(!(val & 0x8000) && ret < 16) + { + val <<= 1; + ret++; + } + + return ret; +} + +static INLINE uint32 Divide(uint32 dividend, uint32 divisor) +{ + //if((Z_FIFO[3] * 2) > H) + if((divisor * 2) > dividend) + { + unsigned shift_bias = CountLeadingZeroU16(divisor); + + dividend <<= shift_bias; + divisor <<= shift_bias; + + return ((int64)dividend * ReciprocalTable[divisor & 0x7FFF] + 32768) >> 16; + } + else + { + FLAGS |= 1 << 17; + return 0x1FFFF; + } +} + +static INLINE void TransformXY(int64 h_div_sz) +{ + MAC[0] = F((int64)OFX + IR1 * h_div_sz) >> 16; + XY_FIFO[3].X = Lm_G(0, MAC[0]); + + MAC[0] = F((int64)OFY + IR2 * h_div_sz) >> 16; + XY_FIFO[3].Y = Lm_G(1, MAC[0]); + + XY_FIFO[0] = XY_FIFO[1]; + XY_FIFO[1] = XY_FIFO[2]; + XY_FIFO[2] = XY_FIFO[3]; +} + +static INLINE void TransformDQ(int64 h_div_sz) +{ + MAC[0] = F((int64)DQB + DQA * h_div_sz); + IR0 = Lm_H(((int64)DQB + DQA * h_div_sz) >> 12); +} + +int32 RTPS(uint32 instr) +{ + DECODE_FIELDS; + int64 h_div_sz; + + MultiplyMatrixByVector_PT(&Matrices.Rot, Vectors[0], CRVectors.T, sf, lm); + h_div_sz = Divide(H, Z_FIFO[3]); + + TransformXY(h_div_sz); + TransformDQ(h_div_sz); + + return(15); +} + +int32 RTPT(uint32 instr) +{ + DECODE_FIELDS; + int i; + + for(i = 0; i < 3; i++) + { + int64 h_div_sz; + + MultiplyMatrixByVector_PT(&Matrices.Rot, Vectors[i], CRVectors.T, sf, lm); + h_div_sz = Divide(H, Z_FIFO[3]); + + TransformXY(h_div_sz); + + if(i == 2) + TransformDQ(h_div_sz); + } + + return(23); +} + +INLINE void NormColor(uint32 sf, int lm, uint32 v) +{ + int16 tmp_vector[3]; + + MultiplyMatrixByVector(&Matrices.Light, Vectors[v], CRVectors.Null, sf, lm); + + tmp_vector[0] = IR1; tmp_vector[1] = IR2; tmp_vector[2] = IR3; + MultiplyMatrixByVector(&Matrices.Color, tmp_vector, CRVectors.B, sf, lm); + + MAC_to_RGB_FIFO(); +} + +int32 NCS(uint32 instr) +{ + DECODE_FIELDS; + + NormColor(sf, lm, 0); + + return(14); +} + +int32 NCT(uint32 instr) +{ + DECODE_FIELDS; + int i; + + for(i = 0; i < 3; i++) + NormColor(sf, lm, i); + + return(30); +} + +INLINE void NormColorColor(uint32 v, uint32 sf, int lm) +{ + int16 tmp_vector[3]; + + MultiplyMatrixByVector(&Matrices.Light, Vectors[v], CRVectors.Null, sf, lm); + + tmp_vector[0] = IR1; tmp_vector[1] = IR2; tmp_vector[2] = IR3; + MultiplyMatrixByVector(&Matrices.Color, tmp_vector, CRVectors.B, sf, lm); + + MAC[1] = ((RGB.R << 4) * IR1) >> sf; + MAC[2] = ((RGB.G << 4) * IR2) >> sf; + MAC[3] = ((RGB.B << 4) * IR3) >> sf; + + MAC_to_IR(lm); + + MAC_to_RGB_FIFO(); +} + +int32 NCCS(uint32 instr) +{ + DECODE_FIELDS; + + NormColorColor(0, sf, lm); + return(17); +} + + +int32 NCCT(uint32 instr) +{ + int i; + DECODE_FIELDS; + + for(i = 0; i < 3; i++) + NormColorColor(i, sf, lm); + + return(39); +} + +INLINE void DepthCue(int mult_IR123, int RGB_from_FIFO, uint32 sf, int lm) +{ + int32 RGB_temp[3]; + int32 IR_temp[3] = { IR1, IR2, IR3 }; + int i; + + //assert(sf); + + if(RGB_from_FIFO) + { + RGB_temp[0] = RGB_FIFO[0].R << 4; + RGB_temp[1] = RGB_FIFO[0].G << 4; + RGB_temp[2] = RGB_FIFO[0].B << 4; + } + else + { + RGB_temp[0] = RGB.R << 4; + RGB_temp[1] = RGB.G << 4; + RGB_temp[2] = RGB.B << 4; + } + + if(mult_IR123) + { + for(i = 0; i < 3; i++) + { + MAC[1 + i] = A_MV(i, (((int64)CRVectors.FC[i] << 12) - RGB_temp[i] * IR_temp[i])) >> sf; + MAC[1 + i] = A_MV(i, (RGB_temp[i] * IR_temp[i] + IR0 * Lm_B(i, MAC[1 + i], FALSE_0))) >> sf; + } + } + else + { + for(i = 0; i < 3; i++) + { + MAC[1 + i] = A_MV(i, (((int64)CRVectors.FC[i] << 12) - (RGB_temp[i] << 12))) >> sf; + MAC[1 + i] = A_MV(i, (((int64)RGB_temp[i] << 12) + IR0 * Lm_B(i, MAC[1 + i], FALSE_0))) >> sf; + } + } + + MAC_to_IR(lm); + + MAC_to_RGB_FIFO(); +} + + +int32 DCPL(uint32 instr) +{ + DECODE_FIELDS; + + DepthCue(TRUE_1, FALSE_0, sf, lm); + + return(8); +} + + +int32 DPCS(uint32 instr) +{ + DECODE_FIELDS; + + DepthCue(FALSE_0, FALSE_0, sf, lm); + + return(8); +} + +int32 DPCT(uint32 instr) +{ + int i; + DECODE_FIELDS; + + for(i = 0; i < 3; i++) + { + DepthCue(FALSE_0, TRUE_1, sf, lm); + } + + return(17); +} + +int32 INTPL(uint32 instr) +{ + DECODE_FIELDS; + + MAC[1] = A_MV(0, (((int64)CRVectors.FC[0] << 12) - (IR1 << 12))) >> sf; + MAC[2] = A_MV(1, (((int64)CRVectors.FC[1] << 12) - (IR2 << 12))) >> sf; + MAC[3] = A_MV(2, (((int64)CRVectors.FC[2] << 12) - (IR3 << 12))) >> sf; + + MAC[1] = A_MV(0, (((int64)IR1 << 12) + IR0 * Lm_B(0, MAC[1], FALSE_0)) >> sf); + MAC[2] = A_MV(1, (((int64)IR2 << 12) + IR0 * Lm_B(1, MAC[2], FALSE_0)) >> sf); + MAC[3] = A_MV(2, (((int64)IR3 << 12) + IR0 * Lm_B(2, MAC[3], FALSE_0)) >> sf); + + MAC_to_IR(lm); + + MAC_to_RGB_FIFO(); + + return(8); +} + + +INLINE void NormColorDepthCue(uint32 v, uint32 sf, int lm) +{ + int16 tmp_vector[3]; + + MultiplyMatrixByVector(&Matrices.Light, Vectors[v], CRVectors.Null, sf, lm); + + tmp_vector[0] = IR1; tmp_vector[1] = IR2; tmp_vector[2] = IR3; + MultiplyMatrixByVector(&Matrices.Color, tmp_vector, CRVectors.B, sf, lm); + + DepthCue(TRUE_1, FALSE_0, sf, lm); +} + +int32 NCDS(uint32 instr) +{ + DECODE_FIELDS; + + NormColorDepthCue(0, sf, lm); + + return(19); +} + +int32 NCDT(uint32 instr) +{ + int i; + DECODE_FIELDS; + + for(i = 0; i < 3; i++) + { + NormColorDepthCue(i, sf, lm); + } + + return(44); +} + +int32 CC(uint32 instr) +{ + DECODE_FIELDS; + int16 tmp_vector[3]; + + tmp_vector[0] = IR1; tmp_vector[1] = IR2; tmp_vector[2] = IR3; + MultiplyMatrixByVector(&Matrices.Color, tmp_vector, CRVectors.B, sf, lm); + + MAC[1] = ((RGB.R << 4) * IR1) >> sf; + MAC[2] = ((RGB.G << 4) * IR2) >> sf; + MAC[3] = ((RGB.B << 4) * IR3) >> sf; + + MAC_to_IR(lm); + + MAC_to_RGB_FIFO(); + + return(11); +} + +int32 CDP(uint32 instr) +{ + DECODE_FIELDS; + int16 tmp_vector[3]; + + tmp_vector[0] = IR1; tmp_vector[1] = IR2; tmp_vector[2] = IR3; + MultiplyMatrixByVector(&Matrices.Color, tmp_vector, CRVectors.B, sf, lm); + + DepthCue(TRUE_1, FALSE_0, sf, lm); + + return(13); +} + +int32 NCLIP(uint32 instr) +{ + DECODE_FIELDS; + + MAC[0] = F( (int64)(XY_FIFO[0].X * (XY_FIFO[1].Y - XY_FIFO[2].Y)) + (XY_FIFO[1].X * (XY_FIFO[2].Y - XY_FIFO[0].Y)) + (XY_FIFO[2].X * (XY_FIFO[0].Y - XY_FIFO[1].Y)) + ); + + return(8); +} + +int32 AVSZ3(uint32 instr) +{ + DECODE_FIELDS; + + MAC[0] = F(((int64)ZSF3 * (Z_FIFO[1] + Z_FIFO[2] + Z_FIFO[3]))); + + OTZ = Lm_D(MAC[0] >> 12, FALSE_0); + + return(5); +} + +int32 AVSZ4(uint32 instr) +{ + DECODE_FIELDS; + + MAC[0] = F(((int64)ZSF4 * (Z_FIFO[0] + Z_FIFO[1] + Z_FIFO[2] + Z_FIFO[3]))); + + OTZ = Lm_D(MAC[0] >> 12, FALSE_0); + + return(5); +} + + +// -32768 * -32768 - 32767 * -32768 = 2147450880 +// (2 ^ 31) - 1 = 2147483647 +int32 OP(uint32 instr) +{ + DECODE_FIELDS; + + MAC[1] = ((Matrices.Rot.MX[1][1] * IR3) - (Matrices.Rot.MX[2][2] * IR2)) >> sf; + MAC[2] = ((Matrices.Rot.MX[2][2] * IR1) - (Matrices.Rot.MX[0][0] * IR3)) >> sf; + MAC[3] = ((Matrices.Rot.MX[0][0] * IR2) - (Matrices.Rot.MX[1][1] * IR1)) >> sf; + + MAC_to_IR(lm); + + return(6); +} + +int32 GPF(uint32 instr) +{ + DECODE_FIELDS; + + MAC[1] = (IR0 * IR1) >> sf; + MAC[2] = (IR0 * IR2) >> sf; + MAC[3] = (IR0 * IR3) >> sf; + + MAC_to_IR(lm); + + MAC_to_RGB_FIFO(); + + return(5); +} + +int32 GPL(uint32 instr) +{ + DECODE_FIELDS; + + MAC[1] = A_MV(0, ((int64)MAC[1] << sf) + (IR0 * IR1)) >> sf; + MAC[2] = A_MV(1, ((int64)MAC[2] << sf) + (IR0 * IR2)) >> sf; + MAC[3] = A_MV(2, ((int64)MAC[3] << sf) + (IR0 * IR3)) >> sf; + + MAC_to_IR(lm); + + MAC_to_RGB_FIFO(); + + return(5); +} + +/* + +--------------------------------------------------------------------------------------------- +| 24 23 22 21 20 | 19 | 18 17 | 16 15 | 14 13 | 12 11 | 10 | 9 8 7 6 | 5 4 3 2 1 0 | +|-------------------------------------------------------------------------------------------| +| (unused) | sf | mx | v | cv |(unused)| lm | (unused) | opcode | +--------------------------------------------------------------------------------------------- + (unused) = unused, ignored + + sf = shift 12 + + mx = matrix selection + + v = source vector + + cv = add vector(translation/back/far color(bugged)/none) + + (unused) = unused, ignored + + lm = limit negative results to 0 + + (unused) = unused, ignored + + opcode = operation code +*/ + +int32 GTE_Instruction(uint32 instr) +{ + const unsigned code = instr & 0x3F; + int32 ret = 1; + + FLAGS = 0; + + switch(code) + { + default: +#ifndef PSXDEV_GTE_TESTING + PSX_WARNING("[GTE] Unknown instruction code: 0x%02x", code); +#endif + break; + + case 0x00: // alternate? + case 0x01: + ret = RTPS(instr); + break; + +/* + case 0x02: // UNSTABLE? + break; + + case 0x03: // UNSTABLE? + break; + + case 0x04: // Probably simple with v,cv,sf,mx,lm ignored. Same calculation as 0x3B? + break; + + case 0x05: // UNSTABLE? + break; +*/ + + case 0x06: + ret = NCLIP(instr); + break; + +/* + case 0x07: // UNSTABLE? + break; + + case 0x08: // UNSTABLE? + break; + + case 0x09: // UNSTABLE? + break; + + case 0x0A: // UNSTABLE? + break; + + case 0x0B: // UNSTABLE? + break; + +*/ + + case 0x0C: + ret = OP(instr); + break; + +/* + case 0x0D: // UNSTABLE? + break; + + case 0x0E: // UNSTABLE? + break; + + case 0x0F: // UNSTABLE? + break; +*/ + + case 0x10: + ret = DPCS(instr); + break; + + case 0x11: + ret = INTPL(instr); + break; + + case 0x12: + ret = MVMVA(instr); + break; + + case 0x13: + ret = NCDS(instr); + break; + + case 0x14: + ret = CDP(instr); + break; + + +/* + case 0x15: // does one push on RGB FIFO, what else... + break; +*/ + + case 0x16: + ret = NCDT(instr); + break; + +/* + case 0x17: // PARTIALLY UNSTABLE(depending on sf or v or cv or mx or lm???), similar behavior under some conditions to 0x16? + break; + + case 0x18: + break; + + case 0x19: + break; +*/ + + case 0x1A: // Alternate for 0x29? + ret = DCPL(instr); + break; + + case 0x1B: + ret = NCCS(instr); + break; + + case 0x1C: + ret = CC(instr); + break; + +/* + case 0x1D: + break; +*/ + + case 0x1E: + ret = NCS(instr); + break; + +/* + case 0x1F: + break; +*/ + + case 0x20: + ret = NCT(instr); + break; +/* + case 0x21: + break; + + case 0x22: // UNSTABLE? + break; + + case 0x23: + break; + + case 0x24: + break; + + case 0x25: + break; + + case 0x26: + break; + + case 0x27: + break; +*/ + + case 0x28: + ret = SQR(instr); + break; + + case 0x29: + ret = DCPL(instr); + break; + + case 0x2A: + ret = DPCT(instr); + break; + +/* + case 0x2B: + break; + + case 0x2C: + break; +*/ + + case 0x2D: + ret = AVSZ3(instr); + break; + + case 0x2E: + ret = AVSZ4(instr); + break; + +/* + case 0x2F: // UNSTABLE? + break; +*/ + + case 0x30: + ret = RTPT(instr); + break; + +/* + case 0x31: // UNSTABLE? + break; + + case 0x32: // UNSTABLE? + break; + + case 0x33: // UNSTABLE? + break; + + case 0x34: // UNSTABLE? + break; + + case 0x35: // UNSTABLE? + break; + + case 0x36: // UNSTABLE? + break; + + case 0x37: // UNSTABLE? + break; + + case 0x38: + break; + + case 0x39: // Probably simple with v,cv,sf,mx,lm ignored. + break; + + case 0x3A: // Probably simple with v,cv,sf,mx,lm ignored. + break; + + case 0x3B: // Probably simple with v,cv,sf,mx,lm ignored. Same calculation as 0x04? + break; + + case 0x3C: // UNSTABLE? + break; +*/ + + case 0x3D: + ret = GPF(instr); + break; + + case 0x3E: + ret = GPL(instr); + break; + + case 0x3F: + ret = NCCT(instr); + break; + } + + if(FLAGS & 0x7f87e000) + FLAGS |= 1 << 31; + + CR[31] = FLAGS; + + return(ret - 1); +} + +#ifndef PSXDEV_GTE_TESTING +} +#endif diff --git a/psx/octoshock/psx/gte.h b/psx/octoshock/psx/gte.h new file mode 100644 index 0000000000..7e5aa0869b --- /dev/null +++ b/psx/octoshock/psx/gte.h @@ -0,0 +1,21 @@ +#pragma once + +#include "state.h" + +namespace MDFN_IEN_PSX +{ + +void GTE_Power(void); +int GTE_StateAction(StateMem *sm, int load, int data_only); + +int32 GTE_Instruction(uint32 instr); + +void GTE_WriteCR(unsigned int which, uint32 value); +void GTE_WriteDR(unsigned int which, uint32 value); + +uint32 GTE_ReadCR(unsigned int which); +uint32 GTE_ReadDR(unsigned int which); + + +} + diff --git a/psx/octoshock/psx/gte_divrecip.inc b/psx/octoshock/psx/gte_divrecip.inc new file mode 100644 index 0000000000..25e7b1e774 --- /dev/null +++ b/psx/octoshock/psx/gte_divrecip.inc @@ -0,0 +1,32768 @@ +0x00020000, +0x0001fffc, +0x0001fff8, +0x0001fff4, +0x0001fff0, +0x0001ffec, +0x0001ffe8, +0x0001ffe4, +0x0001ffe0, +0x0001ffdc, +0x0001ffd8, +0x0001ffd4, +0x0001ffd0, +0x0001ffcc, +0x0001ffc8, +0x0001ffc4, +0x0001ffc0, +0x0001ffbc, +0x0001ffb8, +0x0001ffb4, +0x0001ffb0, +0x0001ffac, +0x0001ffa8, +0x0001ffa4, +0x0001ffa0, +0x0001ff9c, +0x0001ff98, +0x0001ff94, +0x0001ff90, +0x0001ff8c, +0x0001ff88, +0x0001ff84, +0x0001ff80, +0x0001ff7c, +0x0001ff78, +0x0001ff74, +0x0001ff70, +0x0001ff6c, +0x0001ff68, +0x0001ff64, +0x0001ff60, +0x0001ff5c, +0x0001ff58, +0x0001ff54, +0x0001ff50, +0x0001ff4c, +0x0001ff48, +0x0001ff44, +0x0001ff40, +0x0001ff3c, +0x0001ff38, +0x0001ff34, +0x0001ff30, +0x0001ff2c, +0x0001ff28, +0x0001ff24, +0x0001ff20, +0x0001ff1c, +0x0001ff18, +0x0001ff14, +0x0001ff10, +0x0001ff0c, +0x0001ff08, +0x0001ff04, +0x0001ff01, +0x0001fefd, +0x0001fef9, +0x0001fef5, +0x0001fef1, +0x0001feed, +0x0001fee9, +0x0001fee5, +0x0001fee1, +0x0001fedd, +0x0001fed9, +0x0001fed5, +0x0001fed1, +0x0001fecd, +0x0001fec9, +0x0001fec5, +0x0001fec1, +0x0001febd, +0x0001feb9, +0x0001feb5, +0x0001feb1, +0x0001fead, +0x0001fea9, +0x0001fea5, +0x0001fea1, +0x0001fe9d, +0x0001fe99, +0x0001fe95, +0x0001fe91, +0x0001fe8d, +0x0001fe89, +0x0001fe85, +0x0001fe81, +0x0001fe7e, +0x0001fe7a, +0x0001fe76, +0x0001fe72, +0x0001fe6e, +0x0001fe6a, +0x0001fe66, +0x0001fe62, +0x0001fe5e, +0x0001fe5a, +0x0001fe56, +0x0001fe52, +0x0001fe4e, +0x0001fe4a, +0x0001fe46, +0x0001fe42, +0x0001fe3e, +0x0001fe3a, +0x0001fe36, +0x0001fe32, +0x0001fe2e, +0x0001fe2a, +0x0001fe26, +0x0001fe22, +0x0001fe1e, +0x0001fe1a, +0x0001fe16, +0x0001fe12, +0x0001fe0e, +0x0001fe0a, +0x0001fe06, +0x0001fe02, +0x0001fdfe, +0x0001fdfa, +0x0001fdf6, +0x0001fdf2, +0x0001fdee, +0x0001fdea, +0x0001fde6, +0x0001fde2, +0x0001fdde, +0x0001fdda, +0x0001fdd6, +0x0001fdd2, +0x0001fdce, +0x0001fdca, +0x0001fdc6, +0x0001fdc2, +0x0001fdbe, +0x0001fdba, +0x0001fdb6, +0x0001fdb2, +0x0001fdae, +0x0001fdaa, +0x0001fda6, +0x0001fda2, +0x0001fd9e, +0x0001fd9a, +0x0001fd96, +0x0001fd92, +0x0001fd8e, +0x0001fd8a, +0x0001fd86, +0x0001fd82, +0x0001fd7f, +0x0001fd7b, +0x0001fd77, +0x0001fd73, +0x0001fd6f, +0x0001fd6b, +0x0001fd67, +0x0001fd63, +0x0001fd5f, +0x0001fd5b, +0x0001fd57, +0x0001fd53, +0x0001fd4f, +0x0001fd4b, +0x0001fd47, +0x0001fd43, +0x0001fd3f, +0x0001fd3b, +0x0001fd37, +0x0001fd33, +0x0001fd2f, +0x0001fd2b, +0x0001fd27, +0x0001fd23, +0x0001fd1f, +0x0001fd1b, +0x0001fd17, +0x0001fd13, +0x0001fd0f, +0x0001fd0b, +0x0001fd07, +0x0001fd04, +0x0001fd00, +0x0001fcfc, +0x0001fcf8, +0x0001fcf4, +0x0001fcf0, +0x0001fcec, +0x0001fce8, +0x0001fce4, +0x0001fce0, +0x0001fcdc, +0x0001fcd8, +0x0001fcd4, +0x0001fcd0, +0x0001fccc, +0x0001fcc8, +0x0001fcc4, +0x0001fcc0, +0x0001fcbd, +0x0001fcb9, +0x0001fcb5, +0x0001fcb1, +0x0001fcad, +0x0001fca9, +0x0001fca5, +0x0001fca1, +0x0001fc9d, +0x0001fc99, +0x0001fc95, +0x0001fc91, +0x0001fc8d, +0x0001fc89, +0x0001fc87, +0x0001fc83, +0x0001fc7f, +0x0001fc7b, +0x0001fc77, +0x0001fc73, +0x0001fc6f, +0x0001fc6b, +0x0001fc67, +0x0001fc63, +0x0001fc5f, +0x0001fc5b, +0x0001fc57, +0x0001fc53, +0x0001fc4f, +0x0001fc4b, +0x0001fc47, +0x0001fc43, +0x0001fc40, +0x0001fc3c, +0x0001fc38, +0x0001fc34, +0x0001fc30, +0x0001fc2c, +0x0001fc28, +0x0001fc24, +0x0001fc20, +0x0001fc1c, +0x0001fc18, +0x0001fc14, +0x0001fc10, +0x0001fc0c, +0x0001fc08, +0x0001fc04, +0x0001fc00, +0x0001fbfc, +0x0001fbf8, +0x0001fbf4, +0x0001fbf0, +0x0001fbec, +0x0001fbe8, +0x0001fbe4, +0x0001fbe0, +0x0001fbdc, +0x0001fbd8, +0x0001fbd4, +0x0001fbd0, +0x0001fbcc, +0x0001fbc8, +0x0001fbc4, +0x0001fbc1, +0x0001fbbd, +0x0001fbb9, +0x0001fbb5, +0x0001fbb1, +0x0001fbad, +0x0001fba9, +0x0001fba5, +0x0001fba1, +0x0001fb9d, +0x0001fb99, +0x0001fb95, +0x0001fb91, +0x0001fb8d, +0x0001fb8b, +0x0001fb87, +0x0001fb83, +0x0001fb7f, +0x0001fb7b, +0x0001fb77, +0x0001fb73, +0x0001fb6f, +0x0001fb6b, +0x0001fb67, +0x0001fb63, +0x0001fb5f, +0x0001fb5b, +0x0001fb57, +0x0001fb53, +0x0001fb4f, +0x0001fb4b, +0x0001fb47, +0x0001fb43, +0x0001fb40, +0x0001fb3c, +0x0001fb38, +0x0001fb34, +0x0001fb30, +0x0001fb2c, +0x0001fb28, +0x0001fb24, +0x0001fb20, +0x0001fb1c, +0x0001fb18, +0x0001fb14, +0x0001fb10, +0x0001fb0d, +0x0001fb09, +0x0001fb05, +0x0001fb01, +0x0001fafd, +0x0001faf9, +0x0001faf5, +0x0001faf1, +0x0001faed, +0x0001fae9, +0x0001fae5, +0x0001fae1, +0x0001fadd, +0x0001fad9, +0x0001fad5, +0x0001fad2, +0x0001face, +0x0001faca, +0x0001fac6, +0x0001fac2, +0x0001fabe, +0x0001faba, +0x0001fab6, +0x0001fab2, +0x0001faae, +0x0001faaa, +0x0001faa6, +0x0001faa2, +0x0001fa9e, +0x0001fa9a, +0x0001fa96, +0x0001fa92, +0x0001fa8e, +0x0001fa8a, +0x0001fa86, +0x0001fa82, +0x0001fa7f, +0x0001fa7b, +0x0001fa77, +0x0001fa73, +0x0001fa6f, +0x0001fa6b, +0x0001fa67, +0x0001fa65, +0x0001fa61, +0x0001fa5d, +0x0001fa59, +0x0001fa55, +0x0001fa51, +0x0001fa4d, +0x0001fa49, +0x0001fa45, +0x0001fa41, +0x0001fa3d, +0x0001fa39, +0x0001fa35, +0x0001fa31, +0x0001fa2d, +0x0001fa2a, +0x0001fa26, +0x0001fa22, +0x0001fa1e, +0x0001fa1a, +0x0001fa16, +0x0001fa12, +0x0001fa0e, +0x0001fa0a, +0x0001fa06, +0x0001fa02, +0x0001f9fe, +0x0001f9fa, +0x0001f9f6, +0x0001f9f2, +0x0001f9ee, +0x0001f9ea, +0x0001f9e6, +0x0001f9e2, +0x0001f9de, +0x0001f9da, +0x0001f9d6, +0x0001f9d3, +0x0001f9cf, +0x0001f9cb, +0x0001f9c7, +0x0001f9c3, +0x0001f9bf, +0x0001f9bd, +0x0001f9b9, +0x0001f9b5, +0x0001f9b1, +0x0001f9ad, +0x0001f9a9, +0x0001f9a5, +0x0001f9a1, +0x0001f99d, +0x0001f999, +0x0001f995, +0x0001f991, +0x0001f98d, +0x0001f989, +0x0001f985, +0x0001f982, +0x0001f97e, +0x0001f97a, +0x0001f976, +0x0001f972, +0x0001f96e, +0x0001f96a, +0x0001f966, +0x0001f962, +0x0001f95e, +0x0001f95a, +0x0001f956, +0x0001f952, +0x0001f94e, +0x0001f94a, +0x0001f946, +0x0001f942, +0x0001f93e, +0x0001f93a, +0x0001f936, +0x0001f932, +0x0001f92e, +0x0001f92b, +0x0001f927, +0x0001f923, +0x0001f91f, +0x0001f91b, +0x0001f918, +0x0001f914, +0x0001f910, +0x0001f90c, +0x0001f908, +0x0001f904, +0x0001f900, +0x0001f8fc, +0x0001f8f8, +0x0001f8f4, +0x0001f8f0, +0x0001f8ec, +0x0001f8e8, +0x0001f8e4, +0x0001f8e0, +0x0001f8dd, +0x0001f8db, +0x0001f8d7, +0x0001f8d3, +0x0001f8cf, +0x0001f8cb, +0x0001f8c7, +0x0001f8c3, +0x0001f8bf, +0x0001f8bb, +0x0001f8b7, +0x0001f8b3, +0x0001f8af, +0x0001f8ab, +0x0001f8a7, +0x0001f8a3, +0x0001f89f, +0x0001f89c, +0x0001f898, +0x0001f894, +0x0001f890, +0x0001f88c, +0x0001f888, +0x0001f884, +0x0001f880, +0x0001f87c, +0x0001f878, +0x0001f874, +0x0001f870, +0x0001f86c, +0x0001f868, +0x0001f864, +0x0001f860, +0x0001f85f, +0x0001f85b, +0x0001f857, +0x0001f853, +0x0001f84f, +0x0001f84b, +0x0001f847, +0x0001f843, +0x0001f83f, +0x0001f83b, +0x0001f837, +0x0001f833, +0x0001f82f, +0x0001f82b, +0x0001f827, +0x0001f823, +0x0001f820, +0x0001f81c, +0x0001f818, +0x0001f814, +0x0001f810, +0x0001f80c, +0x0001f808, +0x0001f804, +0x0001f800, +0x0001f7fc, +0x0001f7f8, +0x0001f7f4, +0x0001f7f0, +0x0001f7ec, +0x0001f7e8, +0x0001f7e4, +0x0001f7e2, +0x0001f7df, +0x0001f7db, +0x0001f7d7, +0x0001f7d3, +0x0001f7cf, +0x0001f7cb, +0x0001f7c7, +0x0001f7c3, +0x0001f7bf, +0x0001f7bb, +0x0001f7b7, +0x0001f7b3, +0x0001f7af, +0x0001f7ab, +0x0001f7a7, +0x0001f7a3, +0x0001f7a0, +0x0001f79c, +0x0001f798, +0x0001f794, +0x0001f790, +0x0001f78c, +0x0001f788, +0x0001f784, +0x0001f780, +0x0001f77c, +0x0001f778, +0x0001f774, +0x0001f770, +0x0001f76c, +0x0001f768, +0x0001f766, +0x0001f763, +0x0001f75f, +0x0001f75b, +0x0001f757, +0x0001f753, +0x0001f74f, +0x0001f74b, +0x0001f747, +0x0001f743, +0x0001f73f, +0x0001f73b, +0x0001f737, +0x0001f733, +0x0001f72f, +0x0001f72b, +0x0001f728, +0x0001f724, +0x0001f720, +0x0001f71c, +0x0001f718, +0x0001f714, +0x0001f711, +0x0001f70d, +0x0001f709, +0x0001f705, +0x0001f701, +0x0001f6fd, +0x0001f6f9, +0x0001f6f5, +0x0001f6f1, +0x0001f6ed, +0x0001f6e9, +0x0001f6e5, +0x0001f6e2, +0x0001f6de, +0x0001f6da, +0x0001f6d6, +0x0001f6d2, +0x0001f6ce, +0x0001f6ca, +0x0001f6c6, +0x0001f6c4, +0x0001f6c0, +0x0001f6bc, +0x0001f6b8, +0x0001f6b4, +0x0001f6b0, +0x0001f6ad, +0x0001f6a9, +0x0001f6a5, +0x0001f6a1, +0x0001f69d, +0x0001f699, +0x0001f695, +0x0001f691, +0x0001f68d, +0x0001f689, +0x0001f685, +0x0001f681, +0x0001f67e, +0x0001f67a, +0x0001f676, +0x0001f672, +0x0001f66e, +0x0001f66a, +0x0001f666, +0x0001f662, +0x0001f660, +0x0001f65c, +0x0001f658, +0x0001f654, +0x0001f650, +0x0001f64c, +0x0001f649, +0x0001f645, +0x0001f641, +0x0001f63d, +0x0001f639, +0x0001f635, +0x0001f631, +0x0001f62d, +0x0001f629, +0x0001f625, +0x0001f621, +0x0001f61d, +0x0001f619, +0x0001f616, +0x0001f612, +0x0001f60e, +0x0001f60a, +0x0001f606, +0x0001f602, +0x0001f600, +0x0001f5fc, +0x0001f5f8, +0x0001f5f4, +0x0001f5f0, +0x0001f5ec, +0x0001f5e8, +0x0001f5e5, +0x0001f5e1, +0x0001f5dd, +0x0001f5d9, +0x0001f5d5, +0x0001f5d1, +0x0001f5cd, +0x0001f5c9, +0x0001f5c5, +0x0001f5c1, +0x0001f5bd, +0x0001f5b9, +0x0001f5b5, +0x0001f5b2, +0x0001f5ae, +0x0001f5aa, +0x0001f5a6, +0x0001f5a2, +0x0001f59e, +0x0001f59c, +0x0001f598, +0x0001f594, +0x0001f590, +0x0001f58c, +0x0001f588, +0x0001f584, +0x0001f581, +0x0001f57d, +0x0001f579, +0x0001f575, +0x0001f571, +0x0001f56d, +0x0001f569, +0x0001f565, +0x0001f561, +0x0001f55d, +0x0001f559, +0x0001f555, +0x0001f551, +0x0001f54e, +0x0001f54a, +0x0001f546, +0x0001f542, +0x0001f53e, +0x0001f53a, +0x0001f537, +0x0001f533, +0x0001f52f, +0x0001f52b, +0x0001f527, +0x0001f523, +0x0001f51f, +0x0001f51b, +0x0001f517, +0x0001f513, +0x0001f511, +0x0001f50e, +0x0001f50a, +0x0001f506, +0x0001f502, +0x0001f4fe, +0x0001f4fa, +0x0001f4f6, +0x0001f4f2, +0x0001f4ee, +0x0001f4ea, +0x0001f4e6, +0x0001f4e3, +0x0001f4df, +0x0001f4db, +0x0001f4d7, +0x0001f4d3, +0x0001f4cf, +0x0001f4cb, +0x0001f4c7, +0x0001f4c3, +0x0001f4c1, +0x0001f4bd, +0x0001f4ba, +0x0001f4b6, +0x0001f4b2, +0x0001f4ae, +0x0001f4aa, +0x0001f4a6, +0x0001f4a2, +0x0001f49e, +0x0001f49a, +0x0001f496, +0x0001f492, +0x0001f48f, +0x0001f48b, +0x0001f487, +0x0001f483, +0x0001f47f, +0x0001f47b, +0x0001f477, +0x0001f473, +0x0001f46f, +0x0001f46d, +0x0001f469, +0x0001f466, +0x0001f462, +0x0001f45e, +0x0001f45a, +0x0001f456, +0x0001f452, +0x0001f44e, +0x0001f44a, +0x0001f446, +0x0001f442, +0x0001f43f, +0x0001f43b, +0x0001f437, +0x0001f433, +0x0001f42f, +0x0001f42b, +0x0001f427, +0x0001f423, +0x0001f41f, +0x0001f41d, +0x0001f419, +0x0001f415, +0x0001f412, +0x0001f40e, +0x0001f40a, +0x0001f406, +0x0001f402, +0x0001f3fe, +0x0001f3fa, +0x0001f3f6, +0x0001f3f2, +0x0001f3ee, +0x0001f3eb, +0x0001f3e7, +0x0001f3e3, +0x0001f3df, +0x0001f3db, +0x0001f3d7, +0x0001f3d3, +0x0001f3cf, +0x0001f3cd, +0x0001f3c9, +0x0001f3c5, +0x0001f3c2, +0x0001f3be, +0x0001f3ba, +0x0001f3b6, +0x0001f3b2, +0x0001f3ae, +0x0001f3aa, +0x0001f3a6, +0x0001f3a2, +0x0001f39e, +0x0001f39a, +0x0001f397, +0x0001f393, +0x0001f38f, +0x0001f38b, +0x0001f387, +0x0001f383, +0x0001f37f, +0x0001f37b, +0x0001f379, +0x0001f375, +0x0001f371, +0x0001f36e, +0x0001f36a, +0x0001f366, +0x0001f362, +0x0001f35e, +0x0001f35a, +0x0001f356, +0x0001f352, +0x0001f34f, +0x0001f34b, +0x0001f347, +0x0001f343, +0x0001f33f, +0x0001f33b, +0x0001f337, +0x0001f333, +0x0001f32f, +0x0001f32c, +0x0001f328, +0x0001f324, +0x0001f320, +0x0001f31c, +0x0001f318, +0x0001f314, +0x0001f310, +0x0001f30c, +0x0001f30b, +0x0001f307, +0x0001f303, +0x0001f2ff, +0x0001f2fb, +0x0001f2f7, +0x0001f2f3, +0x0001f2ef, +0x0001f2eb, +0x0001f2e7, +0x0001f2e4, +0x0001f2e0, +0x0001f2dc, +0x0001f2d8, +0x0001f2d4, +0x0001f2d0, +0x0001f2cc, +0x0001f2c8, +0x0001f2c6, +0x0001f2c3, +0x0001f2bf, +0x0001f2bb, +0x0001f2b7, +0x0001f2b3, +0x0001f2af, +0x0001f2ab, +0x0001f2a7, +0x0001f2a3, +0x0001f2a0, +0x0001f29c, +0x0001f298, +0x0001f294, +0x0001f290, +0x0001f28c, +0x0001f288, +0x0001f284, +0x0001f282, +0x0001f27e, +0x0001f27b, +0x0001f277, +0x0001f273, +0x0001f26f, +0x0001f26b, +0x0001f267, +0x0001f263, +0x0001f25f, +0x0001f25b, +0x0001f258, +0x0001f254, +0x0001f250, +0x0001f24c, +0x0001f248, +0x0001f244, +0x0001f240, +0x0001f23c, +0x0001f23a, +0x0001f236, +0x0001f233, +0x0001f22f, +0x0001f22b, +0x0001f227, +0x0001f223, +0x0001f21f, +0x0001f21b, +0x0001f217, +0x0001f213, +0x0001f210, +0x0001f20c, +0x0001f208, +0x0001f204, +0x0001f200, +0x0001f1fc, +0x0001f1f8, +0x0001f1f6, +0x0001f1f2, +0x0001f1ee, +0x0001f1eb, +0x0001f1e7, +0x0001f1e3, +0x0001f1df, +0x0001f1db, +0x0001f1d7, +0x0001f1d3, +0x0001f1cf, +0x0001f1cb, +0x0001f1c8, +0x0001f1c4, +0x0001f1c0, +0x0001f1bc, +0x0001f1b8, +0x0001f1b4, +0x0001f1b2, +0x0001f1ae, +0x0001f1aa, +0x0001f1a7, +0x0001f1a3, +0x0001f19f, +0x0001f19b, +0x0001f197, +0x0001f193, +0x0001f18f, +0x0001f18b, +0x0001f187, +0x0001f184, +0x0001f180, +0x0001f17c, +0x0001f178, +0x0001f174, +0x0001f170, +0x0001f16c, +0x0001f168, +0x0001f165, +0x0001f161, +0x0001f15d, +0x0001f159, +0x0001f155, +0x0001f151, +0x0001f14f, +0x0001f14b, +0x0001f147, +0x0001f144, +0x0001f140, +0x0001f13c, +0x0001f138, +0x0001f134, +0x0001f130, +0x0001f12c, +0x0001f128, +0x0001f125, +0x0001f121, +0x0001f11d, +0x0001f119, +0x0001f115, +0x0001f113, +0x0001f10f, +0x0001f10b, +0x0001f108, +0x0001f104, +0x0001f100, +0x0001f0fc, +0x0001f0f8, +0x0001f0f4, +0x0001f0f0, +0x0001f0ec, +0x0001f0e9, +0x0001f0e5, +0x0001f0e1, +0x0001f0dd, +0x0001f0d9, +0x0001f0d7, +0x0001f0d3, +0x0001f0cf, +0x0001f0cb, +0x0001f0c8, +0x0001f0c4, +0x0001f0c0, +0x0001f0bc, +0x0001f0b8, +0x0001f0b4, +0x0001f0b0, +0x0001f0ac, +0x0001f0a9, +0x0001f0a5, +0x0001f0a1, +0x0001f09d, +0x0001f09b, +0x0001f097, +0x0001f093, +0x0001f08f, +0x0001f08c, +0x0001f088, +0x0001f084, +0x0001f080, +0x0001f07c, +0x0001f078, +0x0001f074, +0x0001f070, +0x0001f06d, +0x0001f069, +0x0001f065, +0x0001f061, +0x0001f05f, +0x0001f05b, +0x0001f057, +0x0001f053, +0x0001f04f, +0x0001f04c, +0x0001f048, +0x0001f044, +0x0001f040, +0x0001f03c, +0x0001f038, +0x0001f034, +0x0001f030, +0x0001f02d, +0x0001f029, +0x0001f025, +0x0001f023, +0x0001f01f, +0x0001f01b, +0x0001f017, +0x0001f013, +0x0001f010, +0x0001f00c, +0x0001f008, +0x0001f004, +0x0001f000, +0x0001effc, +0x0001eff8, +0x0001eff4, +0x0001eff1, +0x0001efed, +0x0001efe9, +0x0001efe7, +0x0001efe3, +0x0001efdf, +0x0001efdb, +0x0001efd7, +0x0001efd3, +0x0001efd0, +0x0001efcc, +0x0001efc8, +0x0001efc4, +0x0001efc0, +0x0001efbc, +0x0001efb8, +0x0001efb4, +0x0001efb1, +0x0001efad, +0x0001efab, +0x0001efa7, +0x0001efa3, +0x0001ef9f, +0x0001ef9b, +0x0001ef97, +0x0001ef94, +0x0001ef90, +0x0001ef8b, +0x0001ef87, +0x0001ef83, +0x0001ef80, +0x0001ef7e, +0x0001ef7a, +0x0001ef76, +0x0001ef72, +0x0001ef6e, +0x0001ef6a, +0x0001ef66, +0x0001ef63, +0x0001ef5f, +0x0001ef5b, +0x0001ef57, +0x0001ef53, +0x0001ef4f, +0x0001ef4b, +0x0001ef48, +0x0001ef46, +0x0001ef42, +0x0001ef3e, +0x0001ef3a, +0x0001ef36, +0x0001ef32, +0x0001ef2e, +0x0001ef2b, +0x0001ef27, +0x0001ef23, +0x0001ef1f, +0x0001ef1b, +0x0001ef17, +0x0001ef13, +0x0001ef0f, +0x0001ef0e, +0x0001ef0a, +0x0001ef06, +0x0001ef02, +0x0001eefe, +0x0001eefa, +0x0001eef6, +0x0001eef2, +0x0001eeef, +0x0001eeeb, +0x0001eee7, +0x0001eee3, +0x0001eedf, +0x0001eedb, +0x0001eed7, +0x0001eed5, +0x0001eed2, +0x0001eece, +0x0001eeca, +0x0001eec6, +0x0001eec2, +0x0001eebe, +0x0001eeba, +0x0001eeb7, +0x0001eeb3, +0x0001eeaf, +0x0001eeab, +0x0001eea7, +0x0001eea3, +0x0001ee9f, +0x0001ee9d, +0x0001ee9a, +0x0001ee96, +0x0001ee92, +0x0001ee8e, +0x0001ee8a, +0x0001ee86, +0x0001ee82, +0x0001ee7e, +0x0001ee7b, +0x0001ee77, +0x0001ee73, +0x0001ee6f, +0x0001ee6b, +0x0001ee67, +0x0001ee63, +0x0001ee61, +0x0001ee5e, +0x0001ee5a, +0x0001ee56, +0x0001ee52, +0x0001ee4e, +0x0001ee4a, +0x0001ee46, +0x0001ee43, +0x0001ee3f, +0x0001ee3b, +0x0001ee37, +0x0001ee33, +0x0001ee2f, +0x0001ee2b, +0x0001ee29, +0x0001ee26, +0x0001ee22, +0x0001ee1e, +0x0001ee1a, +0x0001ee16, +0x0001ee12, +0x0001ee0e, +0x0001ee0a, +0x0001ee07, +0x0001ee03, +0x0001edff, +0x0001edfb, +0x0001edf7, +0x0001edf3, +0x0001edf1, +0x0001eded, +0x0001edea, +0x0001ede6, +0x0001ede2, +0x0001edde, +0x0001edda, +0x0001edd6, +0x0001edd2, +0x0001edce, +0x0001edcb, +0x0001edc7, +0x0001edc3, +0x0001edbf, +0x0001edbb, +0x0001edb9, +0x0001edb5, +0x0001edb1, +0x0001edad, +0x0001eda9, +0x0001eda6, +0x0001eda2, +0x0001eda0, +0x0001ed9c, +0x0001ed98, +0x0001ed94, +0x0001ed90, +0x0001ed8d, +0x0001ed89, +0x0001ed85, +0x0001ed81, +0x0001ed7d, +0x0001ed79, +0x0001ed75, +0x0001ed72, +0x0001ed70, +0x0001ed6c, +0x0001ed68, +0x0001ed64, +0x0001ed60, +0x0001ed5c, +0x0001ed59, +0x0001ed55, +0x0001ed51, +0x0001ed4d, +0x0001ed49, +0x0001ed45, +0x0001ed41, +0x0001ed3e, +0x0001ed3c, +0x0001ed38, +0x0001ed34, +0x0001ed30, +0x0001ed2c, +0x0001ed28, +0x0001ed25, +0x0001ed21, +0x0001ed1d, +0x0001ed19, +0x0001ed15, +0x0001ed11, +0x0001ed0d, +0x0001ed0c, +0x0001ed08, +0x0001ed04, +0x0001ed00, +0x0001ecfc, +0x0001ecf8, +0x0001ecf4, +0x0001ecf1, +0x0001eced, +0x0001ece9, +0x0001ece5, +0x0001ece1, +0x0001ecdd, +0x0001ecd9, +0x0001ecd8, +0x0001ecd4, +0x0001ecd0, +0x0001eccc, +0x0001ecc8, +0x0001ecc4, +0x0001ecc0, +0x0001ecbd, +0x0001ecb9, +0x0001ecb5, +0x0001ecb1, +0x0001ecad, +0x0001eca9, +0x0001eca7, +0x0001eca4, +0x0001eca0, +0x0001ec9c, +0x0001ec98, +0x0001ec94, +0x0001ec90, +0x0001ec8c, +0x0001ec89, +0x0001ec85, +0x0001ec81, +0x0001ec7d, +0x0001ec79, +0x0001ec75, +0x0001ec73, +0x0001ec70, +0x0001ec6c, +0x0001ec68, +0x0001ec64, +0x0001ec60, +0x0001ec5c, +0x0001ec58, +0x0001ec55, +0x0001ec51, +0x0001ec4d, +0x0001ec49, +0x0001ec45, +0x0001ec43, +0x0001ec3f, +0x0001ec3c, +0x0001ec38, +0x0001ec34, +0x0001ec30, +0x0001ec2c, +0x0001ec28, +0x0001ec24, +0x0001ec21, +0x0001ec1d, +0x0001ec19, +0x0001ec15, +0x0001ec11, +0x0001ec0f, +0x0001ec0b, +0x0001ec08, +0x0001ec04, +0x0001ec00, +0x0001ebfc, +0x0001ebf8, +0x0001ebf4, +0x0001ebf0, +0x0001ebed, +0x0001ebe9, +0x0001ebe5, +0x0001ebe1, +0x0001ebdf, +0x0001ebdb, +0x0001ebd7, +0x0001ebd3, +0x0001ebcf, +0x0001ebcb, +0x0001ebc7, +0x0001ebc6, +0x0001ebc2, +0x0001ebbe, +0x0001ebba, +0x0001ebb6, +0x0001ebb2, +0x0001ebaf, +0x0001ebab, +0x0001eba7, +0x0001eba3, +0x0001eb9f, +0x0001eb9b, +0x0001eb99, +0x0001eb96, +0x0001eb92, +0x0001eb8e, +0x0001eb8a, +0x0001eb86, +0x0001eb82, +0x0001eb7f, +0x0001eb7b, +0x0001eb77, +0x0001eb73, +0x0001eb6f, +0x0001eb6d, +0x0001eb69, +0x0001eb66, +0x0001eb62, +0x0001eb5e, +0x0001eb5a, +0x0001eb56, +0x0001eb52, +0x0001eb4f, +0x0001eb4b, +0x0001eb47, +0x0001eb43, +0x0001eb41, +0x0001eb3d, +0x0001eb3a, +0x0001eb36, +0x0001eb32, +0x0001eb2e, +0x0001eb2a, +0x0001eb26, +0x0001eb23, +0x0001eb1f, +0x0001eb1b, +0x0001eb17, +0x0001eb15, +0x0001eb11, +0x0001eb0d, +0x0001eb0a, +0x0001eb06, +0x0001eb02, +0x0001eafe, +0x0001eafa, +0x0001eaf6, +0x0001eaf3, +0x0001eaef, +0x0001eaeb, +0x0001eae9, +0x0001eae5, +0x0001eae1, +0x0001eadd, +0x0001eada, +0x0001ead6, +0x0001ead2, +0x0001eace, +0x0001eaca, +0x0001eac6, +0x0001eac3, +0x0001eabf, +0x0001eabb, +0x0001eab9, +0x0001eab5, +0x0001eab1, +0x0001eaae, +0x0001eaaa, +0x0001eaa6, +0x0001eaa2, +0x0001ea9e, +0x0001ea9a, +0x0001ea97, +0x0001ea93, +0x0001ea8f, +0x0001ea8d, +0x0001ea89, +0x0001ea85, +0x0001ea81, +0x0001ea7e, +0x0001ea7a, +0x0001ea76, +0x0001ea72, +0x0001ea6e, +0x0001ea6a, +0x0001ea67, +0x0001ea63, +0x0001ea61, +0x0001ea5d, +0x0001ea59, +0x0001ea55, +0x0001ea51, +0x0001ea4e, +0x0001ea4a, +0x0001ea46, +0x0001ea42, +0x0001ea3e, +0x0001ea3a, +0x0001ea37, +0x0001ea35, +0x0001ea31, +0x0001ea2d, +0x0001ea29, +0x0001ea25, +0x0001ea22, +0x0001ea1e, +0x0001ea1a, +0x0001ea16, +0x0001ea12, +0x0001ea0e, +0x0001ea0b, +0x0001ea09, +0x0001ea05, +0x0001ea01, +0x0001e9fc, +0x0001e9f8, +0x0001e9f5, +0x0001e9f3, +0x0001e9ef, +0x0001e9eb, +0x0001e9e7, +0x0001e9e3, +0x0001e9df, +0x0001e9dc, +0x0001e9d8, +0x0001e9d4, +0x0001e9d0, +0x0001e9cc, +0x0001e9ca, +0x0001e9c7, +0x0001e9c3, +0x0001e9bf, +0x0001e9bb, +0x0001e9b7, +0x0001e9b4, +0x0001e9b0, +0x0001e9ac, +0x0001e9a8, +0x0001e9a4, +0x0001e9a0, +0x0001e99f, +0x0001e99b, +0x0001e997, +0x0001e993, +0x0001e98f, +0x0001e98b, +0x0001e988, +0x0001e984, +0x0001e980, +0x0001e97c, +0x0001e978, +0x0001e976, +0x0001e973, +0x0001e96f, +0x0001e96b, +0x0001e967, +0x0001e963, +0x0001e960, +0x0001e95c, +0x0001e958, +0x0001e954, +0x0001e950, +0x0001e94e, +0x0001e94a, +0x0001e947, +0x0001e943, +0x0001e93f, +0x0001e93b, +0x0001e937, +0x0001e934, +0x0001e930, +0x0001e92c, +0x0001e928, +0x0001e926, +0x0001e922, +0x0001e91f, +0x0001e91b, +0x0001e917, +0x0001e913, +0x0001e90f, +0x0001e90b, +0x0001e908, +0x0001e904, +0x0001e900, +0x0001e8fe, +0x0001e8fa, +0x0001e8f6, +0x0001e8f3, +0x0001e8ef, +0x0001e8eb, +0x0001e8e7, +0x0001e8e3, +0x0001e8e0, +0x0001e8dc, +0x0001e8d8, +0x0001e8d6, +0x0001e8d2, +0x0001e8ce, +0x0001e8cb, +0x0001e8c7, +0x0001e8c3, +0x0001e8bf, +0x0001e8bb, +0x0001e8b7, +0x0001e8b4, +0x0001e8b0, +0x0001e8ae, +0x0001e8aa, +0x0001e8a6, +0x0001e8a2, +0x0001e89f, +0x0001e89b, +0x0001e897, +0x0001e893, +0x0001e88f, +0x0001e88b, +0x0001e888, +0x0001e886, +0x0001e882, +0x0001e87e, +0x0001e87a, +0x0001e876, +0x0001e873, +0x0001e86f, +0x0001e86b, +0x0001e867, +0x0001e863, +0x0001e860, +0x0001e85c, +0x0001e85a, +0x0001e856, +0x0001e852, +0x0001e84e, +0x0001e84b, +0x0001e847, +0x0001e843, +0x0001e83f, +0x0001e83b, +0x0001e837, +0x0001e834, +0x0001e832, +0x0001e82e, +0x0001e829, +0x0001e825, +0x0001e821, +0x0001e81f, +0x0001e81b, +0x0001e818, +0x0001e814, +0x0001e810, +0x0001e80c, +0x0001e808, +0x0001e805, +0x0001e801, +0x0001e7fd, +0x0001e7fb, +0x0001e7f7, +0x0001e7f4, +0x0001e7f0, +0x0001e7ec, +0x0001e7e8, +0x0001e7e4, +0x0001e7e0, +0x0001e7dd, +0x0001e7d9, +0x0001e7d5, +0x0001e7d3, +0x0001e7cf, +0x0001e7cc, +0x0001e7c8, +0x0001e7c4, +0x0001e7c0, +0x0001e7bc, +0x0001e7b9, +0x0001e7b5, +0x0001e7b1, +0x0001e7af, +0x0001e7ab, +0x0001e7a7, +0x0001e7a4, +0x0001e7a0, +0x0001e79c, +0x0001e798, +0x0001e794, +0x0001e791, +0x0001e78d, +0x0001e78b, +0x0001e787, +0x0001e783, +0x0001e77f, +0x0001e77c, +0x0001e778, +0x0001e774, +0x0001e770, +0x0001e76c, +0x0001e769, +0x0001e767, +0x0001e763, +0x0001e75f, +0x0001e75b, +0x0001e758, +0x0001e754, +0x0001e750, +0x0001e74c, +0x0001e748, +0x0001e744, +0x0001e743, +0x0001e73f, +0x0001e73b, +0x0001e737, +0x0001e733, +0x0001e730, +0x0001e72c, +0x0001e728, +0x0001e724, +0x0001e720, +0x0001e71d, +0x0001e71b, +0x0001e717, +0x0001e713, +0x0001e70f, +0x0001e70b, +0x0001e708, +0x0001e704, +0x0001e700, +0x0001e6fc, +0x0001e6f8, +0x0001e6f6, +0x0001e6f3, +0x0001e6ef, +0x0001e6eb, +0x0001e6e7, +0x0001e6e3, +0x0001e6e0, +0x0001e6dc, +0x0001e6d8, +0x0001e6d4, +0x0001e6d2, +0x0001e6cf, +0x0001e6cb, +0x0001e6c7, +0x0001e6c3, +0x0001e6bf, +0x0001e6bc, +0x0001e6b8, +0x0001e6b4, +0x0001e6b0, +0x0001e6ae, +0x0001e6aa, +0x0001e6a7, +0x0001e6a3, +0x0001e69f, +0x0001e69b, +0x0001e697, +0x0001e694, +0x0001e690, +0x0001e68c, +0x0001e688, +0x0001e686, +0x0001e682, +0x0001e67f, +0x0001e67b, +0x0001e677, +0x0001e673, +0x0001e66f, +0x0001e66c, +0x0001e668, +0x0001e664, +0x0001e662, +0x0001e65e, +0x0001e659, +0x0001e655, +0x0001e651, +0x0001e64f, +0x0001e64c, +0x0001e648, +0x0001e644, +0x0001e640, +0x0001e63c, +0x0001e639, +0x0001e635, +0x0001e631, +0x0001e62f, +0x0001e62b, +0x0001e628, +0x0001e624, +0x0001e620, +0x0001e61c, +0x0001e618, +0x0001e615, +0x0001e611, +0x0001e60d, +0x0001e60b, +0x0001e607, +0x0001e604, +0x0001e600, +0x0001e5fc, +0x0001e5f8, +0x0001e5f4, +0x0001e5f1, +0x0001e5ed, +0x0001e5eb, +0x0001e5e7, +0x0001e5e3, +0x0001e5e0, +0x0001e5dc, +0x0001e5d8, +0x0001e5d4, +0x0001e5d0, +0x0001e5cd, +0x0001e5c9, +0x0001e5c7, +0x0001e5c3, +0x0001e5bf, +0x0001e5bc, +0x0001e5b8, +0x0001e5b4, +0x0001e5b0, +0x0001e5ac, +0x0001e5a9, +0x0001e5a7, +0x0001e5a3, +0x0001e59f, +0x0001e59b, +0x0001e598, +0x0001e594, +0x0001e590, +0x0001e58c, +0x0001e588, +0x0001e585, +0x0001e583, +0x0001e57f, +0x0001e57b, +0x0001e577, +0x0001e574, +0x0001e570, +0x0001e56c, +0x0001e568, +0x0001e564, +0x0001e563, +0x0001e55f, +0x0001e55b, +0x0001e557, +0x0001e553, +0x0001e550, +0x0001e54c, +0x0001e548, +0x0001e544, +0x0001e540, +0x0001e53f, +0x0001e53b, +0x0001e537, +0x0001e533, +0x0001e52f, +0x0001e52c, +0x0001e528, +0x0001e524, +0x0001e520, +0x0001e51e, +0x0001e51b, +0x0001e517, +0x0001e513, +0x0001e50f, +0x0001e50b, +0x0001e508, +0x0001e504, +0x0001e500, +0x0001e4fc, +0x0001e4fa, +0x0001e4f7, +0x0001e4f3, +0x0001e4ef, +0x0001e4eb, +0x0001e4e7, +0x0001e4e4, +0x0001e4e0, +0x0001e4dc, +0x0001e4da, +0x0001e4d6, +0x0001e4d3, +0x0001e4cf, +0x0001e4cb, +0x0001e4c7, +0x0001e4c3, +0x0001e4c0, +0x0001e4bc, +0x0001e4b8, +0x0001e4b6, +0x0001e4b2, +0x0001e4af, +0x0001e4ab, +0x0001e4a7, +0x0001e4a3, +0x0001e49f, +0x0001e49c, +0x0001e498, +0x0001e496, +0x0001e492, +0x0001e48e, +0x0001e48a, +0x0001e486, +0x0001e482, +0x0001e47f, +0x0001e47d, +0x0001e479, +0x0001e475, +0x0001e471, +0x0001e46e, +0x0001e46a, +0x0001e466, +0x0001e462, +0x0001e45f, +0x0001e45d, +0x0001e459, +0x0001e455, +0x0001e451, +0x0001e44e, +0x0001e44a, +0x0001e446, +0x0001e442, +0x0001e43e, +0x0001e43d, +0x0001e439, +0x0001e435, +0x0001e431, +0x0001e42d, +0x0001e42a, +0x0001e426, +0x0001e422, +0x0001e41e, +0x0001e41c, +0x0001e419, +0x0001e415, +0x0001e411, +0x0001e40d, +0x0001e409, +0x0001e406, +0x0001e402, +0x0001e3fe, +0x0001e3fa, +0x0001e3f8, +0x0001e3f5, +0x0001e3f1, +0x0001e3ed, +0x0001e3e9, +0x0001e3e6, +0x0001e3e2, +0x0001e3de, +0x0001e3da, +0x0001e3d8, +0x0001e3d5, +0x0001e3d1, +0x0001e3cd, +0x0001e3c9, +0x0001e3c5, +0x0001e3c2, +0x0001e3be, +0x0001e3ba, +0x0001e3b8, +0x0001e3b4, +0x0001e3b1, +0x0001e3ad, +0x0001e3a9, +0x0001e3a5, +0x0001e3a1, +0x0001e39e, +0x0001e39a, +0x0001e398, +0x0001e394, +0x0001e390, +0x0001e38d, +0x0001e389, +0x0001e385, +0x0001e381, +0x0001e37e, +0x0001e37a, +0x0001e378, +0x0001e374, +0x0001e370, +0x0001e36d, +0x0001e369, +0x0001e365, +0x0001e361, +0x0001e35d, +0x0001e35a, +0x0001e358, +0x0001e354, +0x0001e350, +0x0001e34c, +0x0001e349, +0x0001e345, +0x0001e341, +0x0001e33d, +0x0001e339, +0x0001e338, +0x0001e334, +0x0001e330, +0x0001e32c, +0x0001e328, +0x0001e325, +0x0001e321, +0x0001e31d, +0x0001e319, +0x0001e316, +0x0001e314, +0x0001e310, +0x0001e30c, +0x0001e308, +0x0001e305, +0x0001e301, +0x0001e2fd, +0x0001e2f9, +0x0001e2f5, +0x0001e2f4, +0x0001e2f0, +0x0001e2ec, +0x0001e2e8, +0x0001e2e4, +0x0001e2e1, +0x0001e2dd, +0x0001e2d9, +0x0001e2d5, +0x0001e2d3, +0x0001e2d0, +0x0001e2cc, +0x0001e2c8, +0x0001e2c6, +0x0001e2c2, +0x0001e2be, +0x0001e2ba, +0x0001e2b7, +0x0001e2b3, +0x0001e2af, +0x0001e2ab, +0x0001e2a8, +0x0001e2a6, +0x0001e2a2, +0x0001e29e, +0x0001e29a, +0x0001e297, +0x0001e293, +0x0001e28f, +0x0001e28b, +0x0001e288, +0x0001e286, +0x0001e282, +0x0001e27e, +0x0001e27a, +0x0001e277, +0x0001e273, +0x0001e26f, +0x0001e26b, +0x0001e269, +0x0001e266, +0x0001e262, +0x0001e25e, +0x0001e25a, +0x0001e257, +0x0001e253, +0x0001e24f, +0x0001e24b, +0x0001e249, +0x0001e246, +0x0001e242, +0x0001e23e, +0x0001e23a, +0x0001e237, +0x0001e233, +0x0001e22f, +0x0001e22d, +0x0001e229, +0x0001e226, +0x0001e222, +0x0001e21e, +0x0001e21a, +0x0001e217, +0x0001e213, +0x0001e20f, +0x0001e20d, +0x0001e209, +0x0001e206, +0x0001e202, +0x0001e1fe, +0x0001e1fa, +0x0001e1f7, +0x0001e1f3, +0x0001e1f1, +0x0001e1ed, +0x0001e1e9, +0x0001e1e6, +0x0001e1e2, +0x0001e1de, +0x0001e1da, +0x0001e1d7, +0x0001e1d3, +0x0001e1d1, +0x0001e1cd, +0x0001e1c9, +0x0001e1c6, +0x0001e1c2, +0x0001e1be, +0x0001e1ba, +0x0001e1b7, +0x0001e1b5, +0x0001e1b1, +0x0001e1ad, +0x0001e1a9, +0x0001e1a6, +0x0001e1a2, +0x0001e19e, +0x0001e19a, +0x0001e197, +0x0001e195, +0x0001e191, +0x0001e18d, +0x0001e189, +0x0001e186, +0x0001e182, +0x0001e17e, +0x0001e17a, +0x0001e178, +0x0001e175, +0x0001e171, +0x0001e16d, +0x0001e169, +0x0001e166, +0x0001e162, +0x0001e15e, +0x0001e15a, +0x0001e158, +0x0001e155, +0x0001e151, +0x0001e14d, +0x0001e149, +0x0001e146, +0x0001e142, +0x0001e13e, +0x0001e13c, +0x0001e138, +0x0001e135, +0x0001e131, +0x0001e12d, +0x0001e129, +0x0001e126, +0x0001e122, +0x0001e11e, +0x0001e11c, +0x0001e118, +0x0001e115, +0x0001e111, +0x0001e10d, +0x0001e109, +0x0001e106, +0x0001e102, +0x0001e0ff, +0x0001e0fb, +0x0001e0f8, +0x0001e0f4, +0x0001e0f2, +0x0001e0ee, +0x0001e0ea, +0x0001e0e7, +0x0001e0e3, +0x0001e0df, +0x0001e0db, +0x0001e0d8, +0x0001e0d6, +0x0001e0d2, +0x0001e0ce, +0x0001e0cb, +0x0001e0c7, +0x0001e0c3, +0x0001e0bf, +0x0001e0bc, +0x0001e0ba, +0x0001e0b6, +0x0001e0b2, +0x0001e0ae, +0x0001e0ab, +0x0001e0a7, +0x0001e0a3, +0x0001e09f, +0x0001e09e, +0x0001e09a, +0x0001e096, +0x0001e092, +0x0001e08f, +0x0001e08b, +0x0001e087, +0x0001e083, +0x0001e081, +0x0001e07e, +0x0001e07a, +0x0001e076, +0x0001e072, +0x0001e06f, +0x0001e06b, +0x0001e067, +0x0001e065, +0x0001e062, +0x0001e05e, +0x0001e05a, +0x0001e056, +0x0001e053, +0x0001e04f, +0x0001e04b, +0x0001e049, +0x0001e045, +0x0001e042, +0x0001e03e, +0x0001e03a, +0x0001e036, +0x0001e033, +0x0001e02f, +0x0001e02d, +0x0001e029, +0x0001e026, +0x0001e022, +0x0001e01e, +0x0001e01a, +0x0001e017, +0x0001e013, +0x0001e011, +0x0001e00d, +0x0001e009, +0x0001e006, +0x0001e002, +0x0001dffe, +0x0001dffa, +0x0001dff7, +0x0001dff5, +0x0001dff1, +0x0001dfed, +0x0001dfea, +0x0001dfe6, +0x0001dfe2, +0x0001dfde, +0x0001dfdb, +0x0001dfd9, +0x0001dfd5, +0x0001dfd1, +0x0001dfcd, +0x0001dfca, +0x0001dfc6, +0x0001dfc2, +0x0001dfbe, +0x0001dfbd, +0x0001dfb9, +0x0001dfb5, +0x0001dfb1, +0x0001dfae, +0x0001dfaa, +0x0001dfa6, +0x0001dfa2, +0x0001dfa0, +0x0001df9d, +0x0001df99, +0x0001df95, +0x0001df91, +0x0001df8e, +0x0001df8a, +0x0001df86, +0x0001df84, +0x0001df81, +0x0001df7d, +0x0001df79, +0x0001df75, +0x0001df72, +0x0001df6e, +0x0001df6a, +0x0001df68, +0x0001df64, +0x0001df61, +0x0001df5d, +0x0001df59, +0x0001df55, +0x0001df52, +0x0001df4e, +0x0001df4c, +0x0001df48, +0x0001df45, +0x0001df41, +0x0001df3d, +0x0001df3a, +0x0001df36, +0x0001df32, +0x0001df2e, +0x0001df2b, +0x0001df27, +0x0001df23, +0x0001df21, +0x0001df1e, +0x0001df1a, +0x0001df16, +0x0001df12, +0x0001df0f, +0x0001df0b, +0x0001df07, +0x0001df05, +0x0001df02, +0x0001defe, +0x0001defa, +0x0001def6, +0x0001def3, +0x0001deef, +0x0001deed, +0x0001dee9, +0x0001dee6, +0x0001dee2, +0x0001dede, +0x0001deda, +0x0001ded7, +0x0001ded3, +0x0001ded1, +0x0001decd, +0x0001deca, +0x0001dec6, +0x0001dec2, +0x0001debe, +0x0001debb, +0x0001deb9, +0x0001deb5, +0x0001deb1, +0x0001deae, +0x0001deaa, +0x0001dea6, +0x0001dea2, +0x0001de9f, +0x0001de9d, +0x0001de99, +0x0001de95, +0x0001de92, +0x0001de8e, +0x0001de8a, +0x0001de86, +0x0001de85, +0x0001de81, +0x0001de7d, +0x0001de79, +0x0001de76, +0x0001de72, +0x0001de6e, +0x0001de6a, +0x0001de69, +0x0001de65, +0x0001de61, +0x0001de5d, +0x0001de5a, +0x0001de56, +0x0001de52, +0x0001de50, +0x0001de4d, +0x0001de49, +0x0001de45, +0x0001de41, +0x0001de3e, +0x0001de3a, +0x0001de36, +0x0001de34, +0x0001de31, +0x0001de2d, +0x0001de29, +0x0001de25, +0x0001de22, +0x0001de1e, +0x0001de1c, +0x0001de18, +0x0001de15, +0x0001de11, +0x0001de0d, +0x0001de09, +0x0001de06, +0x0001de02, +0x0001de00, +0x0001ddfc, +0x0001ddf9, +0x0001ddf5, +0x0001ddf1, +0x0001dded, +0x0001ddea, +0x0001dde8, +0x0001dde4, +0x0001dde0, +0x0001dddd, +0x0001ddd9, +0x0001ddd5, +0x0001ddd1, +0x0001ddce, +0x0001ddcc, +0x0001ddc8, +0x0001ddc4, +0x0001ddc1, +0x0001ddbd, +0x0001ddb9, +0x0001ddb5, +0x0001ddb3, +0x0001ddb0, +0x0001ddac, +0x0001dda8, +0x0001dda5, +0x0001dda1, +0x0001dd9d, +0x0001dd99, +0x0001dd97, +0x0001dd94, +0x0001dd90, +0x0001dd8c, +0x0001dd89, +0x0001dd85, +0x0001dd81, +0x0001dd7f, +0x0001dd7b, +0x0001dd77, +0x0001dd74, +0x0001dd70, +0x0001dd6c, +0x0001dd6a, +0x0001dd66, +0x0001dd63, +0x0001dd5f, +0x0001dd5b, +0x0001dd58, +0x0001dd54, +0x0001dd52, +0x0001dd4e, +0x0001dd4b, +0x0001dd47, +0x0001dd43, +0x0001dd3f, +0x0001dd3c, +0x0001dd38, +0x0001dd36, +0x0001dd32, +0x0001dd2f, +0x0001dd2b, +0x0001dd27, +0x0001dd23, +0x0001dd20, +0x0001dd1e, +0x0001dd1a, +0x0001dd16, +0x0001dd13, +0x0001dd0f, +0x0001dd0b, +0x0001dd07, +0x0001dd06, +0x0001dd02, +0x0001dcfe, +0x0001dcfa, +0x0001dcf7, +0x0001dcf3, +0x0001dcef, +0x0001dcec, +0x0001dcea, +0x0001dce6, +0x0001dce2, +0x0001dcde, +0x0001dcdb, +0x0001dcd7, +0x0001dcd3, +0x0001dcd1, +0x0001dcce, +0x0001dcca, +0x0001dcc6, +0x0001dcc3, +0x0001dcbf, +0x0001dcbb, +0x0001dcb9, +0x0001dcb5, +0x0001dcb2, +0x0001dcae, +0x0001dcaa, +0x0001dca7, +0x0001dca3, +0x0001dca1, +0x0001dc9d, +0x0001dc9a, +0x0001dc96, +0x0001dc92, +0x0001dc8e, +0x0001dc8b, +0x0001dc87, +0x0001dc85, +0x0001dc81, +0x0001dc7e, +0x0001dc7a, +0x0001dc76, +0x0001dc72, +0x0001dc6f, +0x0001dc6d, +0x0001dc69, +0x0001dc65, +0x0001dc62, +0x0001dc5e, +0x0001dc5a, +0x0001dc56, +0x0001dc55, +0x0001dc51, +0x0001dc4d, +0x0001dc49, +0x0001dc46, +0x0001dc42, +0x0001dc3e, +0x0001dc3a, +0x0001dc39, +0x0001dc35, +0x0001dc31, +0x0001dc2d, +0x0001dc2a, +0x0001dc26, +0x0001dc22, +0x0001dc20, +0x0001dc1d, +0x0001dc19, +0x0001dc15, +0x0001dc12, +0x0001dc0e, +0x0001dc0a, +0x0001dc08, +0x0001dc04, +0x0001dc01, +0x0001dbfd, +0x0001dbf9, +0x0001dbf6, +0x0001dbf2, +0x0001dbee, +0x0001dbec, +0x0001dbe9, +0x0001dbe5, +0x0001dbe1, +0x0001dbdd, +0x0001dbda, +0x0001dbd6, +0x0001dbd4, +0x0001dbd0, +0x0001dbcd, +0x0001dbc9, +0x0001dbc5, +0x0001dbc3, +0x0001dbbf, +0x0001dbbb, +0x0001dbb8, +0x0001dbb4, +0x0001dbb0, +0x0001dbae, +0x0001dbab, +0x0001dba7, +0x0001dba3, +0x0001dba0, +0x0001db9c, +0x0001db98, +0x0001db96, +0x0001db93, +0x0001db8f, +0x0001db8b, +0x0001db87, +0x0001db84, +0x0001db80, +0x0001db7e, +0x0001db7a, +0x0001db77, +0x0001db73, +0x0001db6f, +0x0001db6c, +0x0001db6a, +0x0001db66, +0x0001db62, +0x0001db5f, +0x0001db5b, +0x0001db57, +0x0001db53, +0x0001db52, +0x0001db4e, +0x0001db4a, +0x0001db47, +0x0001db43, +0x0001db3f, +0x0001db3b, +0x0001db3a, +0x0001db36, +0x0001db32, +0x0001db2e, +0x0001db2b, +0x0001db27, +0x0001db23, +0x0001db21, +0x0001db1e, +0x0001db1a, +0x0001db16, +0x0001db13, +0x0001db0f, +0x0001db0b, +0x0001db09, +0x0001db06, +0x0001db02, +0x0001dafe, +0x0001dafa, +0x0001daf7, +0x0001daf3, +0x0001daf1, +0x0001daed, +0x0001daea, +0x0001dae6, +0x0001dae2, +0x0001dadf, +0x0001dadb, +0x0001dad9, +0x0001dad5, +0x0001dad2, +0x0001dace, +0x0001daca, +0x0001dac6, +0x0001dac3, +0x0001dac1, +0x0001dabd, +0x0001dab9, +0x0001dab6, +0x0001dab2, +0x0001daae, +0x0001daab, +0x0001daa9, +0x0001daa5, +0x0001daa1, +0x0001da9e, +0x0001da9a, +0x0001da96, +0x0001da93, +0x0001da91, +0x0001da8d, +0x0001da89, +0x0001da86, +0x0001da82, +0x0001da7e, +0x0001da7a, +0x0001da79, +0x0001da75, +0x0001da71, +0x0001da6d, +0x0001da6a, +0x0001da66, +0x0001da62, +0x0001da60, +0x0001da5d, +0x0001da59, +0x0001da55, +0x0001da52, +0x0001da4e, +0x0001da4c, +0x0001da48, +0x0001da45, +0x0001da41, +0x0001da3d, +0x0001da39, +0x0001da36, +0x0001da34, +0x0001da30, +0x0001da2c, +0x0001da29, +0x0001da25, +0x0001da21, +0x0001da1e, +0x0001da1c, +0x0001da18, +0x0001da14, +0x0001da11, +0x0001da0d, +0x0001da0a, +0x0001da06, +0x0001da03, +0x0001d9ff, +0x0001d9fb, +0x0001d9f9, +0x0001d9f6, +0x0001d9f2, +0x0001d9ee, +0x0001d9eb, +0x0001d9e7, +0x0001d9e3, +0x0001d9e1, +0x0001d9de, +0x0001d9da, +0x0001d9d6, +0x0001d9d3, +0x0001d9cf, +0x0001d9cb, +0x0001d9c9, +0x0001d9c6, +0x0001d9c2, +0x0001d9be, +0x0001d9bb, +0x0001d9b7, +0x0001d9b5, +0x0001d9b1, +0x0001d9ae, +0x0001d9aa, +0x0001d9a6, +0x0001d9a3, +0x0001d99f, +0x0001d99d, +0x0001d999, +0x0001d996, +0x0001d992, +0x0001d98e, +0x0001d98b, +0x0001d989, +0x0001d985, +0x0001d981, +0x0001d97e, +0x0001d97a, +0x0001d976, +0x0001d973, +0x0001d971, +0x0001d96d, +0x0001d969, +0x0001d966, +0x0001d962, +0x0001d95e, +0x0001d95c, +0x0001d959, +0x0001d955, +0x0001d951, +0x0001d94e, +0x0001d94a, +0x0001d946, +0x0001d944, +0x0001d941, +0x0001d93d, +0x0001d939, +0x0001d936, +0x0001d932, +0x0001d930, +0x0001d92c, +0x0001d929, +0x0001d925, +0x0001d921, +0x0001d91e, +0x0001d91a, +0x0001d918, +0x0001d914, +0x0001d911, +0x0001d90d, +0x0001d909, +0x0001d906, +0x0001d902, +0x0001d900, +0x0001d8fc, +0x0001d8f9, +0x0001d8f5, +0x0001d8f1, +0x0001d8ee, +0x0001d8ec, +0x0001d8e8, +0x0001d8e4, +0x0001d8e1, +0x0001d8dd, +0x0001d8d9, +0x0001d8d6, +0x0001d8d4, +0x0001d8d0, +0x0001d8cc, +0x0001d8c9, +0x0001d8c5, +0x0001d8c1, +0x0001d8bf, +0x0001d8bc, +0x0001d8b8, +0x0001d8b4, +0x0001d8b1, +0x0001d8ad, +0x0001d8a9, +0x0001d8a7, +0x0001d8a4, +0x0001d8a0, +0x0001d89c, +0x0001d899, +0x0001d895, +0x0001d893, +0x0001d88f, +0x0001d88c, +0x0001d888, +0x0001d884, +0x0001d881, +0x0001d87d, +0x0001d87b, +0x0001d877, +0x0001d874, +0x0001d870, +0x0001d86c, +0x0001d868, +0x0001d865, +0x0001d863, +0x0001d85f, +0x0001d85c, +0x0001d858, +0x0001d854, +0x0001d851, +0x0001d84d, +0x0001d849, +0x0001d846, +0x0001d844, +0x0001d840, +0x0001d83c, +0x0001d839, +0x0001d835, +0x0001d831, +0x0001d830, +0x0001d82c, +0x0001d828, +0x0001d825, +0x0001d821, +0x0001d81d, +0x0001d819, +0x0001d818, +0x0001d814, +0x0001d810, +0x0001d80d, +0x0001d809, +0x0001d805, +0x0001d803, +0x0001d800, +0x0001d7fc, +0x0001d7f8, +0x0001d7f5, +0x0001d7f1, +0x0001d7ef, +0x0001d7ec, +0x0001d7e8, +0x0001d7e4, +0x0001d7e0, +0x0001d7dd, +0x0001d7db, +0x0001d7d7, +0x0001d7d4, +0x0001d7d0, +0x0001d7cc, +0x0001d7c9, +0x0001d7c5, +0x0001d7c3, +0x0001d7bf, +0x0001d7bc, +0x0001d7b8, +0x0001d7b4, +0x0001d7b1, +0x0001d7af, +0x0001d7ab, +0x0001d7a7, +0x0001d7a4, +0x0001d7a0, +0x0001d79c, +0x0001d79b, +0x0001d797, +0x0001d793, +0x0001d790, +0x0001d78c, +0x0001d788, +0x0001d786, +0x0001d783, +0x0001d77f, +0x0001d77b, +0x0001d778, +0x0001d774, +0x0001d770, +0x0001d76e, +0x0001d76b, +0x0001d767, +0x0001d763, +0x0001d760, +0x0001d75c, +0x0001d75a, +0x0001d756, +0x0001d753, +0x0001d74f, +0x0001d74b, +0x0001d748, +0x0001d746, +0x0001d742, +0x0001d73f, +0x0001d73b, +0x0001d737, +0x0001d734, +0x0001d732, +0x0001d72e, +0x0001d72a, +0x0001d727, +0x0001d723, +0x0001d71f, +0x0001d71c, +0x0001d71a, +0x0001d716, +0x0001d712, +0x0001d70f, +0x0001d70b, +0x0001d707, +0x0001d706, +0x0001d702, +0x0001d6fe, +0x0001d6fa, +0x0001d6f7, +0x0001d6f3, +0x0001d6f1, +0x0001d6ee, +0x0001d6ea, +0x0001d6e6, +0x0001d6e3, +0x0001d6df, +0x0001d6dd, +0x0001d6d9, +0x0001d6d6, +0x0001d6d2, +0x0001d6ce, +0x0001d6cb, +0x0001d6c7, +0x0001d6c5, +0x0001d6c1, +0x0001d6be, +0x0001d6ba, +0x0001d6b6, +0x0001d6b3, +0x0001d6b1, +0x0001d6ad, +0x0001d6aa, +0x0001d6a6, +0x0001d6a3, +0x0001d6a0, +0x0001d69c, +0x0001d698, +0x0001d695, +0x0001d691, +0x0001d68d, +0x0001d68c, +0x0001d688, +0x0001d684, +0x0001d681, +0x0001d67d, +0x0001d679, +0x0001d677, +0x0001d674, +0x0001d670, +0x0001d66c, +0x0001d669, +0x0001d665, +0x0001d663, +0x0001d65f, +0x0001d65c, +0x0001d658, +0x0001d654, +0x0001d651, +0x0001d64f, +0x0001d64b, +0x0001d648, +0x0001d644, +0x0001d640, +0x0001d63d, +0x0001d63b, +0x0001d637, +0x0001d633, +0x0001d630, +0x0001d62c, +0x0001d628, +0x0001d627, +0x0001d623, +0x0001d61f, +0x0001d61c, +0x0001d618, +0x0001d614, +0x0001d612, +0x0001d60f, +0x0001d60b, +0x0001d607, +0x0001d604, +0x0001d600, +0x0001d5fe, +0x0001d5fa, +0x0001d5f7, +0x0001d5f3, +0x0001d5ef, +0x0001d5ec, +0x0001d5ea, +0x0001d5e6, +0x0001d5e3, +0x0001d5df, +0x0001d5db, +0x0001d5d8, +0x0001d5d6, +0x0001d5d2, +0x0001d5ce, +0x0001d5cb, +0x0001d5c7, +0x0001d5c3, +0x0001d5c0, +0x0001d5be, +0x0001d5ba, +0x0001d5b7, +0x0001d5b3, +0x0001d5af, +0x0001d5ac, +0x0001d5aa, +0x0001d5a6, +0x0001d5a2, +0x0001d59f, +0x0001d59b, +0x0001d597, +0x0001d596, +0x0001d592, +0x0001d58e, +0x0001d58b, +0x0001d587, +0x0001d583, +0x0001d581, +0x0001d57e, +0x0001d57a, +0x0001d576, +0x0001d573, +0x0001d56f, +0x0001d56d, +0x0001d569, +0x0001d566, +0x0001d562, +0x0001d55e, +0x0001d55b, +0x0001d559, +0x0001d555, +0x0001d552, +0x0001d54e, +0x0001d54a, +0x0001d547, +0x0001d545, +0x0001d541, +0x0001d53d, +0x0001d53a, +0x0001d536, +0x0001d532, +0x0001d531, +0x0001d52d, +0x0001d529, +0x0001d526, +0x0001d522, +0x0001d51e, +0x0001d51c, +0x0001d519, +0x0001d515, +0x0001d511, +0x0001d50e, +0x0001d50a, +0x0001d508, +0x0001d504, +0x0001d501, +0x0001d4fd, +0x0001d4f9, +0x0001d4f6, +0x0001d4f3, +0x0001d4ef, +0x0001d4ec, +0x0001d4ea, +0x0001d4e6, +0x0001d4e3, +0x0001d4df, +0x0001d4db, +0x0001d4d8, +0x0001d4d6, +0x0001d4d2, +0x0001d4cf, +0x0001d4cb, +0x0001d4c7, +0x0001d4c4, +0x0001d4c2, +0x0001d4be, +0x0001d4ba, +0x0001d4b7, +0x0001d4b3, +0x0001d4b0, +0x0001d4ae, +0x0001d4aa, +0x0001d4a6, +0x0001d4a3, +0x0001d49f, +0x0001d49b, +0x0001d49a, +0x0001d496, +0x0001d492, +0x0001d48f, +0x0001d48b, +0x0001d489, +0x0001d485, +0x0001d482, +0x0001d47e, +0x0001d47a, +0x0001d477, +0x0001d475, +0x0001d471, +0x0001d46e, +0x0001d46a, +0x0001d466, +0x0001d463, +0x0001d461, +0x0001d45d, +0x0001d45a, +0x0001d456, +0x0001d452, +0x0001d44f, +0x0001d44d, +0x0001d449, +0x0001d445, +0x0001d442, +0x0001d43e, +0x0001d43b, +0x0001d439, +0x0001d435, +0x0001d431, +0x0001d42e, +0x0001d42a, +0x0001d426, +0x0001d425, +0x0001d421, +0x0001d41d, +0x0001d41a, +0x0001d416, +0x0001d414, +0x0001d410, +0x0001d40d, +0x0001d409, +0x0001d405, +0x0001d402, +0x0001d400, +0x0001d3fc, +0x0001d3f9, +0x0001d3f5, +0x0001d3f1, +0x0001d3ee, +0x0001d3ec, +0x0001d3e8, +0x0001d3e5, +0x0001d3e1, +0x0001d3dd, +0x0001d3da, +0x0001d3d8, +0x0001d3d4, +0x0001d3d0, +0x0001d3cd, +0x0001d3c9, +0x0001d3c6, +0x0001d3c4, +0x0001d3c0, +0x0001d3bc, +0x0001d3b9, +0x0001d3b5, +0x0001d3b3, +0x0001d3b0, +0x0001d3ac, +0x0001d3a8, +0x0001d3a5, +0x0001d3a1, +0x0001d39f, +0x0001d39b, +0x0001d398, +0x0001d394, +0x0001d390, +0x0001d38d, +0x0001d38b, +0x0001d387, +0x0001d384, +0x0001d380, +0x0001d37c, +0x0001d379, +0x0001d377, +0x0001d373, +0x0001d370, +0x0001d36c, +0x0001d368, +0x0001d365, +0x0001d363, +0x0001d35f, +0x0001d35b, +0x0001d358, +0x0001d354, +0x0001d351, +0x0001d34f, +0x0001d34b, +0x0001d348, +0x0001d344, +0x0001d340, +0x0001d33d, +0x0001d339, +0x0001d335, +0x0001d334, +0x0001d330, +0x0001d32c, +0x0001d329, +0x0001d325, +0x0001d321, +0x0001d320, +0x0001d31c, +0x0001d318, +0x0001d315, +0x0001d311, +0x0001d30f, +0x0001d30c, +0x0001d308, +0x0001d304, +0x0001d301, +0x0001d2fd, +0x0001d2fb, +0x0001d2f8, +0x0001d2f4, +0x0001d2f0, +0x0001d2ed, +0x0001d2eb, +0x0001d2e7, +0x0001d2e4, +0x0001d2e0, +0x0001d2dc, +0x0001d2d9, +0x0001d2d7, +0x0001d2d3, +0x0001d2d0, +0x0001d2cc, +0x0001d2c8, +0x0001d2c6, +0x0001d2c3, +0x0001d2bf, +0x0001d2bb, +0x0001d2b8, +0x0001d2b4, +0x0001d2b2, +0x0001d2af, +0x0001d2ab, +0x0001d2a7, +0x0001d2a4, +0x0001d2a0, +0x0001d29e, +0x0001d29b, +0x0001d297, +0x0001d293, +0x0001d290, +0x0001d28e, +0x0001d28a, +0x0001d287, +0x0001d283, +0x0001d27f, +0x0001d27c, +0x0001d27a, +0x0001d276, +0x0001d273, +0x0001d26f, +0x0001d26b, +0x0001d26a, +0x0001d266, +0x0001d262, +0x0001d25f, +0x0001d25b, +0x0001d257, +0x0001d256, +0x0001d252, +0x0001d24e, +0x0001d24b, +0x0001d247, +0x0001d245, +0x0001d242, +0x0001d23e, +0x0001d23a, +0x0001d237, +0x0001d233, +0x0001d231, +0x0001d22e, +0x0001d22a, +0x0001d226, +0x0001d223, +0x0001d21f, +0x0001d21d, +0x0001d219, +0x0001d216, +0x0001d212, +0x0001d20f, +0x0001d20d, +0x0001d209, +0x0001d205, +0x0001d202, +0x0001d1fe, +0x0001d1fb, +0x0001d1f9, +0x0001d1f5, +0x0001d1f1, +0x0001d1ee, +0x0001d1ea, +0x0001d1e8, +0x0001d1e5, +0x0001d1e1, +0x0001d1dd, +0x0001d1da, +0x0001d1d6, +0x0001d1d4, +0x0001d1d1, +0x0001d1cd, +0x0001d1c9, +0x0001d1c6, +0x0001d1c4, +0x0001d1c0, +0x0001d1bd, +0x0001d1b9, +0x0001d1b5, +0x0001d1b2, +0x0001d1b0, +0x0001d1ac, +0x0001d1a9, +0x0001d1a5, +0x0001d1a1, +0x0001d19e, +0x0001d19a, +0x0001d199, +0x0001d195, +0x0001d191, +0x0001d18e, +0x0001d18a, +0x0001d188, +0x0001d185, +0x0001d181, +0x0001d17d, +0x0001d17a, +0x0001d176, +0x0001d174, +0x0001d171, +0x0001d16d, +0x0001d169, +0x0001d166, +0x0001d164, +0x0001d160, +0x0001d15d, +0x0001d159, +0x0001d155, +0x0001d152, +0x0001d150, +0x0001d14c, +0x0001d149, +0x0001d145, +0x0001d141, +0x0001d140, +0x0001d13c, +0x0001d138, +0x0001d135, +0x0001d131, +0x0001d12d, +0x0001d12c, +0x0001d128, +0x0001d124, +0x0001d121, +0x0001d11d, +0x0001d11b, +0x0001d118, +0x0001d114, +0x0001d110, +0x0001d10d, +0x0001d10b, +0x0001d107, +0x0001d104, +0x0001d100, +0x0001d0fc, +0x0001d0f9, +0x0001d0f7, +0x0001d0f3, +0x0001d0f0, +0x0001d0ec, +0x0001d0e8, +0x0001d0e7, +0x0001d0e3, +0x0001d0df, +0x0001d0dc, +0x0001d0d8, +0x0001d0d4, +0x0001d0d3, +0x0001d0cf, +0x0001d0cb, +0x0001d0c8, +0x0001d0c4, +0x0001d0c2, +0x0001d0bf, +0x0001d0bb, +0x0001d0b7, +0x0001d0b4, +0x0001d0b0, +0x0001d0ae, +0x0001d0ab, +0x0001d0a7, +0x0001d0a3, +0x0001d0a0, +0x0001d09e, +0x0001d09a, +0x0001d097, +0x0001d093, +0x0001d08f, +0x0001d08c, +0x0001d08a, +0x0001d086, +0x0001d083, +0x0001d07f, +0x0001d07b, +0x0001d07a, +0x0001d076, +0x0001d072, +0x0001d06f, +0x0001d06b, +0x0001d069, +0x0001d066, +0x0001d062, +0x0001d05e, +0x0001d05b, +0x0001d057, +0x0001d055, +0x0001d052, +0x0001d04e, +0x0001d04a, +0x0001d047, +0x0001d045, +0x0001d041, +0x0001d03e, +0x0001d03a, +0x0001d036, +0x0001d033, +0x0001d031, +0x0001d02d, +0x0001d02a, +0x0001d026, +0x0001d022, +0x0001d021, +0x0001d01d, +0x0001d019, +0x0001d016, +0x0001d012, +0x0001d00e, +0x0001d00d, +0x0001d009, +0x0001d005, +0x0001d002, +0x0001cffe, +0x0001cffc, +0x0001cff8, +0x0001cff4, +0x0001cff2, +0x0001cfef, +0x0001cfeb, +0x0001cfe8, +0x0001cfe4, +0x0001cfe2, +0x0001cfde, +0x0001cfdb, +0x0001cfd7, +0x0001cfd4, +0x0001cfd2, +0x0001cfce, +0x0001cfcb, +0x0001cfc7, +0x0001cfc3, +0x0001cfc2, +0x0001cfbe, +0x0001cfba, +0x0001cfb7, +0x0001cfb3, +0x0001cfaf, +0x0001cfae, +0x0001cfaa, +0x0001cfa6, +0x0001cfa3, +0x0001cf9f, +0x0001cf9d, +0x0001cf9a, +0x0001cf96, +0x0001cf92, +0x0001cf8f, +0x0001cf8d, +0x0001cf89, +0x0001cf86, +0x0001cf82, +0x0001cf7f, +0x0001cf7d, +0x0001cf79, +0x0001cf76, +0x0001cf72, +0x0001cf6e, +0x0001cf6b, +0x0001cf69, +0x0001cf65, +0x0001cf62, +0x0001cf5e, +0x0001cf5a, +0x0001cf59, +0x0001cf55, +0x0001cf51, +0x0001cf4e, +0x0001cf4a, +0x0001cf48, +0x0001cf45, +0x0001cf41, +0x0001cf3d, +0x0001cf3a, +0x0001cf38, +0x0001cf34, +0x0001cf31, +0x0001cf2d, +0x0001cf2a, +0x0001cf28, +0x0001cf24, +0x0001cf21, +0x0001cf1d, +0x0001cf19, +0x0001cf16, +0x0001cf14, +0x0001cf10, +0x0001cf0d, +0x0001cf09, +0x0001cf05, +0x0001cf04, +0x0001cf00, +0x0001cefc, +0x0001cef9, +0x0001cef5, +0x0001cef3, +0x0001cef0, +0x0001ceec, +0x0001cee8, +0x0001cee5, +0x0001cee3, +0x0001cedf, +0x0001cedc, +0x0001ced8, +0x0001ced5, +0x0001ced1, +0x0001cecf, +0x0001cecc, +0x0001cec8, +0x0001cec4, +0x0001cec1, +0x0001cebf, +0x0001cebb, +0x0001ceb8, +0x0001ceb4, +0x0001ceb0, +0x0001ceaf, +0x0001ceab, +0x0001cea7, +0x0001cea4, +0x0001cea0, +0x0001ce9e, +0x0001ce9b, +0x0001ce97, +0x0001ce93, +0x0001ce90, +0x0001ce8c, +0x0001ce8a, +0x0001ce87, +0x0001ce83, +0x0001ce80, +0x0001ce7c, +0x0001ce7a, +0x0001ce77, +0x0001ce73, +0x0001ce6f, +0x0001ce6c, +0x0001ce6a, +0x0001ce66, +0x0001ce63, +0x0001ce5f, +0x0001ce5b, +0x0001ce5a, +0x0001ce57, +0x0001ce53, +0x0001ce4f, +0x0001ce4c, +0x0001ce48, +0x0001ce45, +0x0001ce43, +0x0001ce3f, +0x0001ce3c, +0x0001ce38, +0x0001ce34, +0x0001ce33, +0x0001ce2f, +0x0001ce2b, +0x0001ce28, +0x0001ce24, +0x0001ce22, +0x0001ce1f, +0x0001ce1b, +0x0001ce17, +0x0001ce14, +0x0001ce12, +0x0001ce0e, +0x0001ce0b, +0x0001ce07, +0x0001ce04, +0x0001ce02, +0x0001cdfe, +0x0001cdfb, +0x0001cdf7, +0x0001cdf3, +0x0001cdf2, +0x0001cdee, +0x0001cdea, +0x0001cde7, +0x0001cde3, +0x0001cde1, +0x0001cdde, +0x0001cdda, +0x0001cdd6, +0x0001cdd3, +0x0001cdd1, +0x0001cdcd, +0x0001cdca, +0x0001cdc6, +0x0001cdc3, +0x0001cdbf, +0x0001cdbd, +0x0001cdba, +0x0001cdb6, +0x0001cdb2, +0x0001cdaf, +0x0001cdad, +0x0001cda9, +0x0001cda6, +0x0001cda2, +0x0001cd9f, +0x0001cd9d, +0x0001cd99, +0x0001cd96, +0x0001cd92, +0x0001cd8e, +0x0001cd8d, +0x0001cd89, +0x0001cd85, +0x0001cd82, +0x0001cd7e, +0x0001cd7c, +0x0001cd79, +0x0001cd75, +0x0001cd71, +0x0001cd6e, +0x0001cd6c, +0x0001cd68, +0x0001cd65, +0x0001cd61, +0x0001cd5e, +0x0001cd5c, +0x0001cd58, +0x0001cd55, +0x0001cd51, +0x0001cd4d, +0x0001cd4c, +0x0001cd48, +0x0001cd44, +0x0001cd41, +0x0001cd3d, +0x0001cd39, +0x0001cd38, +0x0001cd34, +0x0001cd30, +0x0001cd2d, +0x0001cd29, +0x0001cd27, +0x0001cd24, +0x0001cd20, +0x0001cd1d, +0x0001cd19, +0x0001cd17, +0x0001cd14, +0x0001cd10, +0x0001cd0c, +0x0001cd09, +0x0001cd07, +0x0001cd03, +0x0001cd00, +0x0001ccfc, +0x0001ccf9, +0x0001ccf7, +0x0001ccf3, +0x0001ccef, +0x0001ccec, +0x0001cce8, +0x0001cce6, +0x0001cce3, +0x0001ccdf, +0x0001ccdc, +0x0001ccd8, +0x0001ccd6, +0x0001ccd3, +0x0001cccf, +0x0001cccb, +0x0001ccc8, +0x0001ccc6, +0x0001ccc2, +0x0001ccbf, +0x0001ccbb, +0x0001ccb8, +0x0001ccb5, +0x0001ccb2, +0x0001ccae, +0x0001ccad, +0x0001cca9, +0x0001cca5, +0x0001cca2, +0x0001cc9e, +0x0001cc9c, +0x0001cc99, +0x0001cc95, +0x0001cc92, +0x0001cc8e, +0x0001cc8c, +0x0001cc89, +0x0001cc85, +0x0001cc81, +0x0001cc7e, +0x0001cc7c, +0x0001cc78, +0x0001cc75, +0x0001cc71, +0x0001cc6e, +0x0001cc6c, +0x0001cc68, +0x0001cc65, +0x0001cc61, +0x0001cc5d, +0x0001cc5c, +0x0001cc58, +0x0001cc54, +0x0001cc51, +0x0001cc4f, +0x0001cc4b, +0x0001cc48, +0x0001cc44, +0x0001cc41, +0x0001cc3f, +0x0001cc3b, +0x0001cc38, +0x0001cc34, +0x0001cc31, +0x0001cc2f, +0x0001cc2b, +0x0001cc28, +0x0001cc24, +0x0001cc20, +0x0001cc1f, +0x0001cc1b, +0x0001cc17, +0x0001cc14, +0x0001cc10, +0x0001cc0e, +0x0001cc0b, +0x0001cc07, +0x0001cc04, +0x0001cc00, +0x0001cbfe, +0x0001cbfb, +0x0001cbf7, +0x0001cbf3, +0x0001cbf0, +0x0001cbee, +0x0001cbea, +0x0001cbe7, +0x0001cbe3, +0x0001cbe0, +0x0001cbde, +0x0001cbda, +0x0001cbd7, +0x0001cbd3, +0x0001cbcf, +0x0001cbce, +0x0001cbca, +0x0001cbc7, +0x0001cbc3, +0x0001cbbf, +0x0001cbbe, +0x0001cbba, +0x0001cbb6, +0x0001cbb3, +0x0001cbaf, +0x0001cbad, +0x0001cbaa, +0x0001cba6, +0x0001cba3, +0x0001cb9f, +0x0001cb9d, +0x0001cb9a, +0x0001cb96, +0x0001cb92, +0x0001cb8f, +0x0001cb8d, +0x0001cb89, +0x0001cb86, +0x0001cb82, +0x0001cb80, +0x0001cb7d, +0x0001cb79, +0x0001cb76, +0x0001cb72, +0x0001cb70, +0x0001cb6d, +0x0001cb69, +0x0001cb65, +0x0001cb62, +0x0001cb60, +0x0001cb5c, +0x0001cb59, +0x0001cb55, +0x0001cb52, +0x0001cb50, +0x0001cb4c, +0x0001cb49, +0x0001cb45, +0x0001cb42, +0x0001cb40, +0x0001cb3c, +0x0001cb39, +0x0001cb35, +0x0001cb31, +0x0001cb30, +0x0001cb2c, +0x0001cb28, +0x0001cb25, +0x0001cb21, +0x0001cb1f, +0x0001cb1c, +0x0001cb19, +0x0001cb15, +0x0001cb12, +0x0001cb0e, +0x0001cb0b, +0x0001cb09, +0x0001cb05, +0x0001cb02, +0x0001cafe, +0x0001cafa, +0x0001caf9, +0x0001caf5, +0x0001caf2, +0x0001caee, +0x0001caea, +0x0001cae9, +0x0001cae5, +0x0001cae1, +0x0001cade, +0x0001cadc, +0x0001cad8, +0x0001cad5, +0x0001cad1, +0x0001cace, +0x0001cacc, +0x0001cac8, +0x0001cac5, +0x0001cac1, +0x0001cabe, +0x0001cabc, +0x0001cab8, +0x0001cab5, +0x0001cab1, +0x0001caae, +0x0001caac, +0x0001caa8, +0x0001caa5, +0x0001caa1, +0x0001ca9f, +0x0001ca9c, +0x0001ca98, +0x0001ca94, +0x0001ca91, +0x0001ca8f, +0x0001ca8c, +0x0001ca88, +0x0001ca84, +0x0001ca81, +0x0001ca7f, +0x0001ca7b, +0x0001ca78, +0x0001ca74, +0x0001ca71, +0x0001ca6f, +0x0001ca6b, +0x0001ca68, +0x0001ca64, +0x0001ca62, +0x0001ca5f, +0x0001ca5b, +0x0001ca58, +0x0001ca54, +0x0001ca52, +0x0001ca4f, +0x0001ca4b, +0x0001ca48, +0x0001ca44, +0x0001ca42, +0x0001ca3f, +0x0001ca3b, +0x0001ca37, +0x0001ca34, +0x0001ca32, +0x0001ca2f, +0x0001ca2b, +0x0001ca27, +0x0001ca26, +0x0001ca22, +0x0001ca1e, +0x0001ca1b, +0x0001ca17, +0x0001ca15, +0x0001ca12, +0x0001ca0e, +0x0001ca0b, +0x0001ca07, +0x0001ca05, +0x0001ca02, +0x0001c9fe, +0x0001c9fb, +0x0001c9f7, +0x0001c9f5, +0x0001c9f2, +0x0001c9ee, +0x0001c9eb, +0x0001c9e9, +0x0001c9e5, +0x0001c9e2, +0x0001c9de, +0x0001c9da, +0x0001c9d9, +0x0001c9d5, +0x0001c9d1, +0x0001c9ce, +0x0001c9ca, +0x0001c9c9, +0x0001c9c5, +0x0001c9c1, +0x0001c9be, +0x0001c9ba, +0x0001c9b8, +0x0001c9b5, +0x0001c9b1, +0x0001c9ae, +0x0001c9ac, +0x0001c9a8, +0x0001c9a5, +0x0001c9a1, +0x0001c99e, +0x0001c99c, +0x0001c998, +0x0001c995, +0x0001c991, +0x0001c98e, +0x0001c98c, +0x0001c988, +0x0001c985, +0x0001c981, +0x0001c97f, +0x0001c97b, +0x0001c978, +0x0001c974, +0x0001c972, +0x0001c96f, +0x0001c96b, +0x0001c968, +0x0001c964, +0x0001c962, +0x0001c95f, +0x0001c95b, +0x0001c957, +0x0001c956, +0x0001c952, +0x0001c94f, +0x0001c94b, +0x0001c947, +0x0001c946, +0x0001c942, +0x0001c93e, +0x0001c93b, +0x0001c937, +0x0001c936, +0x0001c932, +0x0001c92e, +0x0001c92b, +0x0001c929, +0x0001c925, +0x0001c922, +0x0001c91e, +0x0001c91b, +0x0001c919, +0x0001c915, +0x0001c912, +0x0001c90e, +0x0001c90b, +0x0001c909, +0x0001c905, +0x0001c902, +0x0001c8fe, +0x0001c8fc, +0x0001c8f9, +0x0001c8f5, +0x0001c8f2, +0x0001c8ee, +0x0001c8ec, +0x0001c8e9, +0x0001c8e5, +0x0001c8e2, +0x0001c8de, +0x0001c8dc, +0x0001c8d9, +0x0001c8d5, +0x0001c8d2, +0x0001c8d0, +0x0001c8cc, +0x0001c8c9, +0x0001c8c5, +0x0001c8c2, +0x0001c8c0, +0x0001c8bc, +0x0001c8b9, +0x0001c8b5, +0x0001c8b3, +0x0001c8b0, +0x0001c8ac, +0x0001c8a9, +0x0001c8a5, +0x0001c8a3, +0x0001c8a0, +0x0001c89c, +0x0001c898, +0x0001c895, +0x0001c893, +0x0001c890, +0x0001c88c, +0x0001c888, +0x0001c887, +0x0001c883, +0x0001c87f, +0x0001c87c, +0x0001c878, +0x0001c877, +0x0001c873, +0x0001c86f, +0x0001c86c, +0x0001c868, +0x0001c866, +0x0001c863, +0x0001c85f, +0x0001c85c, +0x0001c85a, +0x0001c856, +0x0001c853, +0x0001c84f, +0x0001c84c, +0x0001c84a, +0x0001c846, +0x0001c843, +0x0001c83f, +0x0001c83c, +0x0001c83a, +0x0001c836, +0x0001c833, +0x0001c82f, +0x0001c82d, +0x0001c82a, +0x0001c826, +0x0001c823, +0x0001c81f, +0x0001c81d, +0x0001c81a, +0x0001c816, +0x0001c813, +0x0001c80f, +0x0001c80d, +0x0001c80a, +0x0001c806, +0x0001c803, +0x0001c801, +0x0001c7fd, +0x0001c7fa, +0x0001c7f6, +0x0001c7f2, +0x0001c7f1, +0x0001c7ed, +0x0001c7ea, +0x0001c7e7, +0x0001c7e4, +0x0001c7e0, +0x0001c7dc, +0x0001c7db, +0x0001c7d7, +0x0001c7d4, +0x0001c7d0, +0x0001c7ce, +0x0001c7cb, +0x0001c7c7, +0x0001c7c4, +0x0001c7c0, +0x0001c7be, +0x0001c7bb, +0x0001c7b7, +0x0001c7b4, +0x0001c7b2, +0x0001c7ae, +0x0001c7ab, +0x0001c7a7, +0x0001c7a4, +0x0001c7a2, +0x0001c79e, +0x0001c79b, +0x0001c797, +0x0001c795, +0x0001c792, +0x0001c78e, +0x0001c78b, +0x0001c787, +0x0001c785, +0x0001c782, +0x0001c77e, +0x0001c77b, +0x0001c779, +0x0001c775, +0x0001c772, +0x0001c76e, +0x0001c76b, +0x0001c769, +0x0001c765, +0x0001c762, +0x0001c75e, +0x0001c75c, +0x0001c759, +0x0001c755, +0x0001c752, +0x0001c74e, +0x0001c74c, +0x0001c749, +0x0001c745, +0x0001c742, +0x0001c740, +0x0001c73c, +0x0001c739, +0x0001c735, +0x0001c732, +0x0001c730, +0x0001c72c, +0x0001c729, +0x0001c725, +0x0001c724, +0x0001c720, +0x0001c71c, +0x0001c719, +0x0001c715, +0x0001c714, +0x0001c710, +0x0001c70c, +0x0001c709, +0x0001c707, +0x0001c704, +0x0001c700, +0x0001c6fc, +0x0001c6f9, +0x0001c6f7, +0x0001c6f4, +0x0001c6f0, +0x0001c6ec, +0x0001c6eb, +0x0001c6e7, +0x0001c6e4, +0x0001c6e0, +0x0001c6dc, +0x0001c6db, +0x0001c6d7, +0x0001c6d4, +0x0001c6d0, +0x0001c6ce, +0x0001c6cb, +0x0001c6c7, +0x0001c6c4, +0x0001c6c0, +0x0001c6be, +0x0001c6bb, +0x0001c6b7, +0x0001c6b4, +0x0001c6b2, +0x0001c6ae, +0x0001c6ab, +0x0001c6a7, +0x0001c6a4, +0x0001c6a2, +0x0001c69e, +0x0001c69b, +0x0001c697, +0x0001c695, +0x0001c692, +0x0001c68e, +0x0001c68b, +0x0001c687, +0x0001c685, +0x0001c682, +0x0001c67e, +0x0001c67b, +0x0001c679, +0x0001c675, +0x0001c672, +0x0001c66e, +0x0001c66b, +0x0001c669, +0x0001c665, +0x0001c662, +0x0001c65e, +0x0001c65c, +0x0001c659, +0x0001c655, +0x0001c653, +0x0001c650, +0x0001c64c, +0x0001c649, +0x0001c645, +0x0001c643, +0x0001c640, +0x0001c63c, +0x0001c639, +0x0001c637, +0x0001c633, +0x0001c630, +0x0001c62c, +0x0001c629, +0x0001c627, +0x0001c623, +0x0001c620, +0x0001c61c, +0x0001c61b, +0x0001c617, +0x0001c614, +0x0001c610, +0x0001c60c, +0x0001c60b, +0x0001c607, +0x0001c604, +0x0001c600, +0x0001c5fe, +0x0001c5fb, +0x0001c5f7, +0x0001c5f4, +0x0001c5f2, +0x0001c5ee, +0x0001c5eb, +0x0001c5e7, +0x0001c5e4, +0x0001c5e2, +0x0001c5de, +0x0001c5db, +0x0001c5d7, +0x0001c5d5, +0x0001c5d2, +0x0001c5ce, +0x0001c5cb, +0x0001c5c7, +0x0001c5c5, +0x0001c5c2, +0x0001c5be, +0x0001c5bb, +0x0001c5b9, +0x0001c5b6, +0x0001c5b2, +0x0001c5ae, +0x0001c5ad, +0x0001c5a9, +0x0001c5a6, +0x0001c5a2, +0x0001c59e, +0x0001c59d, +0x0001c599, +0x0001c596, +0x0001c592, +0x0001c590, +0x0001c58d, +0x0001c589, +0x0001c586, +0x0001c582, +0x0001c580, +0x0001c57d, +0x0001c579, +0x0001c576, +0x0001c574, +0x0001c570, +0x0001c56d, +0x0001c569, +0x0001c566, +0x0001c564, +0x0001c560, +0x0001c55d, +0x0001c559, +0x0001c558, +0x0001c554, +0x0001c550, +0x0001c54d, +0x0001c54b, +0x0001c548, +0x0001c544, +0x0001c540, +0x0001c53d, +0x0001c53b, +0x0001c538, +0x0001c534, +0x0001c531, +0x0001c52f, +0x0001c52b, +0x0001c528, +0x0001c524, +0x0001c521, +0x0001c51f, +0x0001c51b, +0x0001c518, +0x0001c514, +0x0001c512, +0x0001c50f, +0x0001c50b, +0x0001c508, +0x0001c506, +0x0001c502, +0x0001c4ff, +0x0001c4fb, +0x0001c4f8, +0x0001c4f6, +0x0001c4f2, +0x0001c4ef, +0x0001c4eb, +0x0001c4ea, +0x0001c4e6, +0x0001c4e2, +0x0001c4df, +0x0001c4db, +0x0001c4da, +0x0001c4d6, +0x0001c4d3, +0x0001c4cf, +0x0001c4cd, +0x0001c4ca, +0x0001c4c6, +0x0001c4c3, +0x0001c4c0, +0x0001c4bd, +0x0001c4b9, +0x0001c4b8, +0x0001c4b4, +0x0001c4b1, +0x0001c4ad, +0x0001c4ab, +0x0001c4a8, +0x0001c4a4, +0x0001c4a1, +0x0001c49f, +0x0001c49b, +0x0001c498, +0x0001c494, +0x0001c493, +0x0001c48f, +0x0001c48b, +0x0001c488, +0x0001c484, +0x0001c483, +0x0001c47f, +0x0001c47c, +0x0001c478, +0x0001c476, +0x0001c473, +0x0001c46f, +0x0001c46c, +0x0001c46a, +0x0001c466, +0x0001c463, +0x0001c45f, +0x0001c45e, +0x0001c45a, +0x0001c457, +0x0001c453, +0x0001c44f, +0x0001c44e, +0x0001c44a, +0x0001c447, +0x0001c443, +0x0001c441, +0x0001c43e, +0x0001c43a, +0x0001c437, +0x0001c435, +0x0001c431, +0x0001c42e, +0x0001c42a, +0x0001c427, +0x0001c425, +0x0001c422, +0x0001c41e, +0x0001c41a, +0x0001c419, +0x0001c415, +0x0001c412, +0x0001c40e, +0x0001c40c, +0x0001c409, +0x0001c405, +0x0001c402, +0x0001c400, +0x0001c3fc, +0x0001c3f9, +0x0001c3f5, +0x0001c3f2, +0x0001c3f0, +0x0001c3ed, +0x0001c3e9, +0x0001c3e6, +0x0001c3e4, +0x0001c3e0, +0x0001c3dd, +0x0001c3d9, +0x0001c3d7, +0x0001c3d4, +0x0001c3d0, +0x0001c3cd, +0x0001c3cb, +0x0001c3c8, +0x0001c3c4, +0x0001c3c0, +0x0001c3bd, +0x0001c3bb, +0x0001c3b8, +0x0001c3b4, +0x0001c3b1, +0x0001c3af, +0x0001c3ab, +0x0001c3a8, +0x0001c3a4, +0x0001c3a2, +0x0001c39f, +0x0001c39b, +0x0001c398, +0x0001c396, +0x0001c393, +0x0001c38f, +0x0001c38b, +0x0001c388, +0x0001c386, +0x0001c383, +0x0001c37f, +0x0001c37c, +0x0001c37a, +0x0001c376, +0x0001c373, +0x0001c36f, +0x0001c36d, +0x0001c36a, +0x0001c366, +0x0001c363, +0x0001c35f, +0x0001c35e, +0x0001c35a, +0x0001c357, +0x0001c353, +0x0001c351, +0x0001c34e, +0x0001c34a, +0x0001c347, +0x0001c345, +0x0001c341, +0x0001c33e, +0x0001c33a, +0x0001c338, +0x0001c335, +0x0001c332, +0x0001c32e, +0x0001c32b, +0x0001c327, +0x0001c324, +0x0001c322, +0x0001c31f, +0x0001c31b, +0x0001c317, +0x0001c316, +0x0001c312, +0x0001c30f, +0x0001c30b, +0x0001c309, +0x0001c306, +0x0001c302, +0x0001c2ff, +0x0001c2fd, +0x0001c2fa, +0x0001c2f6, +0x0001c2f3, +0x0001c2f1, +0x0001c2ed, +0x0001c2ea, +0x0001c2e6, +0x0001c2e5, +0x0001c2e1, +0x0001c2dd, +0x0001c2da, +0x0001c2d8, +0x0001c2d5, +0x0001c2d1, +0x0001c2ce, +0x0001c2ca, +0x0001c2c8, +0x0001c2c5, +0x0001c2c1, +0x0001c2be, +0x0001c2bc, +0x0001c2b9, +0x0001c2b5, +0x0001c2b2, +0x0001c2b0, +0x0001c2ac, +0x0001c2a9, +0x0001c2a5, +0x0001c2a3, +0x0001c2a0, +0x0001c29c, +0x0001c299, +0x0001c297, +0x0001c294, +0x0001c290, +0x0001c28d, +0x0001c28b, +0x0001c287, +0x0001c284, +0x0001c280, +0x0001c27f, +0x0001c27b, +0x0001c278, +0x0001c274, +0x0001c272, +0x0001c26f, +0x0001c26b, +0x0001c268, +0x0001c264, +0x0001c262, +0x0001c25f, +0x0001c25b, +0x0001c258, +0x0001c256, +0x0001c253, +0x0001c24f, +0x0001c24c, +0x0001c24a, +0x0001c246, +0x0001c243, +0x0001c23f, +0x0001c23e, +0x0001c23a, +0x0001c236, +0x0001c233, +0x0001c231, +0x0001c22e, +0x0001c22a, +0x0001c227, +0x0001c225, +0x0001c221, +0x0001c21e, +0x0001c21a, +0x0001c219, +0x0001c215, +0x0001c212, +0x0001c20e, +0x0001c20c, +0x0001c209, +0x0001c205, +0x0001c202, +0x0001c1fe, +0x0001c1fc, +0x0001c1f9, +0x0001c1f5, +0x0001c1f2, +0x0001c1f0, +0x0001c1ed, +0x0001c1e9, +0x0001c1e6, +0x0001c1e4, +0x0001c1e0, +0x0001c1dd, +0x0001c1d9, +0x0001c1d8, +0x0001c1d4, +0x0001c1d1, +0x0001c1cd, +0x0001c1cb, +0x0001c1c8, +0x0001c1c4, +0x0001c1c1, +0x0001c1bf, +0x0001c1bb, +0x0001c1b8, +0x0001c1b4, +0x0001c1b3, +0x0001c1af, +0x0001c1ac, +0x0001c1a8, +0x0001c1a5, +0x0001c1a1, +0x0001c1a0, +0x0001c19c, +0x0001c199, +0x0001c195, +0x0001c193, +0x0001c190, +0x0001c18c, +0x0001c189, +0x0001c187, +0x0001c184, +0x0001c180, +0x0001c17d, +0x0001c17b, +0x0001c177, +0x0001c174, +0x0001c170, +0x0001c16e, +0x0001c16b, +0x0001c167, +0x0001c164, +0x0001c162, +0x0001c15f, +0x0001c15b, +0x0001c158, +0x0001c156, +0x0001c152, +0x0001c14f, +0x0001c14b, +0x0001c14a, +0x0001c146, +0x0001c143, +0x0001c13f, +0x0001c13d, +0x0001c13a, +0x0001c136, +0x0001c133, +0x0001c131, +0x0001c12e, +0x0001c12a, +0x0001c127, +0x0001c125, +0x0001c121, +0x0001c11e, +0x0001c11a, +0x0001c119, +0x0001c115, +0x0001c112, +0x0001c10e, +0x0001c10c, +0x0001c109, +0x0001c105, +0x0001c102, +0x0001c100, +0x0001c0fc, +0x0001c0f9, +0x0001c0f5, +0x0001c0f4, +0x0001c0f0, +0x0001c0ed, +0x0001c0e9, +0x0001c0e7, +0x0001c0e4, +0x0001c0e0, +0x0001c0dd, +0x0001c0d9, +0x0001c0d8, +0x0001c0d4, +0x0001c0d1, +0x0001c0cd, +0x0001c0cb, +0x0001c0c8, +0x0001c0c4, +0x0001c0c1, +0x0001c0bf, +0x0001c0bc, +0x0001c0b8, +0x0001c0b5, +0x0001c0b3, +0x0001c0af, +0x0001c0ac, +0x0001c0a8, +0x0001c0a7, +0x0001c0a3, +0x0001c0a0, +0x0001c09c, +0x0001c09a, +0x0001c097, +0x0001c093, +0x0001c090, +0x0001c08e, +0x0001c08a, +0x0001c087, +0x0001c083, +0x0001c082, +0x0001c07e, +0x0001c07b, +0x0001c077, +0x0001c075, +0x0001c072, +0x0001c06e, +0x0001c06b, +0x0001c069, +0x0001c066, +0x0001c062, +0x0001c05f, +0x0001c05d, +0x0001c059, +0x0001c056, +0x0001c052, +0x0001c051, +0x0001c04d, +0x0001c04a, +0x0001c046, +0x0001c044, +0x0001c041, +0x0001c03d, +0x0001c03a, +0x0001c038, +0x0001c035, +0x0001c031, +0x0001c02e, +0x0001c02c, +0x0001c028, +0x0001c025, +0x0001c021, +0x0001c020, +0x0001c01b, +0x0001c019, +0x0001c016, +0x0001c012, +0x0001c00f, +0x0001c00d, +0x0001c009, +0x0001c006, +0x0001c002, +0x0001c001, +0x0001bffd, +0x0001bffa, +0x0001bff6, +0x0001bff4, +0x0001bff1, +0x0001bfed, +0x0001bfea, +0x0001bfe8, +0x0001bfe5, +0x0001bfe1, +0x0001bfde, +0x0001bfdc, +0x0001bfd9, +0x0001bfd5, +0x0001bfd2, +0x0001bfd0, +0x0001bfcc, +0x0001bfc9, +0x0001bfc5, +0x0001bfc4, +0x0001bfc0, +0x0001bfbd, +0x0001bfb9, +0x0001bfb7, +0x0001bfb4, +0x0001bfb0, +0x0001bfad, +0x0001bfab, +0x0001bfa8, +0x0001bfa4, +0x0001bfa1, +0x0001bf9f, +0x0001bf9b, +0x0001bf98, +0x0001bf94, +0x0001bf93, +0x0001bf8f, +0x0001bf8c, +0x0001bf88, +0x0001bf86, +0x0001bf83, +0x0001bf7f, +0x0001bf7c, +0x0001bf7a, +0x0001bf77, +0x0001bf73, +0x0001bf70, +0x0001bf6e, +0x0001bf6b, +0x0001bf67, +0x0001bf64, +0x0001bf62, +0x0001bf5e, +0x0001bf5b, +0x0001bf59, +0x0001bf56, +0x0001bf52, +0x0001bf4f, +0x0001bf4d, +0x0001bf49, +0x0001bf46, +0x0001bf42, +0x0001bf41, +0x0001bf3d, +0x0001bf3a, +0x0001bf36, +0x0001bf34, +0x0001bf31, +0x0001bf2d, +0x0001bf2a, +0x0001bf28, +0x0001bf25, +0x0001bf21, +0x0001bf1e, +0x0001bf1c, +0x0001bf18, +0x0001bf15, +0x0001bf11, +0x0001bf10, +0x0001bf0c, +0x0001bf09, +0x0001bf05, +0x0001bf03, +0x0001bf00, +0x0001befd, +0x0001bef9, +0x0001bef7, +0x0001bef4, +0x0001bef0, +0x0001beed, +0x0001beeb, +0x0001bee8, +0x0001bee4, +0x0001bee1, +0x0001bedf, +0x0001bedb, +0x0001bed8, +0x0001bed4, +0x0001bed3, +0x0001becf, +0x0001becc, +0x0001bec8, +0x0001bec6, +0x0001bec3, +0x0001bebf, +0x0001bebc, +0x0001beba, +0x0001beb7, +0x0001beb3, +0x0001beb0, +0x0001beae, +0x0001beaa, +0x0001bea7, +0x0001bea3, +0x0001bea2, +0x0001be9e, +0x0001be9b, +0x0001be97, +0x0001be96, +0x0001be92, +0x0001be8f, +0x0001be8b, +0x0001be8a, +0x0001be86, +0x0001be83, +0x0001be7f, +0x0001be7d, +0x0001be7a, +0x0001be76, +0x0001be73, +0x0001be71, +0x0001be6e, +0x0001be6a, +0x0001be67, +0x0001be65, +0x0001be62, +0x0001be5e, +0x0001be5b, +0x0001be59, +0x0001be55, +0x0001be52, +0x0001be4e, +0x0001be4d, +0x0001be49, +0x0001be46, +0x0001be42, +0x0001be40, +0x0001be3d, +0x0001be39, +0x0001be36, +0x0001be34, +0x0001be31, +0x0001be2d, +0x0001be2c, +0x0001be28, +0x0001be25, +0x0001be21, +0x0001be1f, +0x0001be1c, +0x0001be18, +0x0001be15, +0x0001be13, +0x0001be10, +0x0001be0c, +0x0001be09, +0x0001be07, +0x0001be03, +0x0001be00, +0x0001bdfd, +0x0001bdfb, +0x0001bdf7, +0x0001bdf4, +0x0001bdf0, +0x0001bdef, +0x0001bdeb, +0x0001bde8, +0x0001bde4, +0x0001bde2, +0x0001bddf, +0x0001bddb, +0x0001bdd8, +0x0001bdd6, +0x0001bdd3, +0x0001bdcf, +0x0001bdcd, +0x0001bdca, +0x0001bdc7, +0x0001bdc3, +0x0001bdc1, +0x0001bdbe, +0x0001bdba, +0x0001bdb7, +0x0001bdb5, +0x0001bdb2, +0x0001bdae, +0x0001bdab, +0x0001bda9, +0x0001bda5, +0x0001bda2, +0x0001bd9e, +0x0001bd9d, +0x0001bd99, +0x0001bd96, +0x0001bd92, +0x0001bd91, +0x0001bd8d, +0x0001bd8a, +0x0001bd86, +0x0001bd84, +0x0001bd81, +0x0001bd7d, +0x0001bd7a, +0x0001bd78, +0x0001bd75, +0x0001bd71, +0x0001bd6f, +0x0001bd6c, +0x0001bd68, +0x0001bd65, +0x0001bd63, +0x0001bd60, +0x0001bd5c, +0x0001bd59, +0x0001bd57, +0x0001bd54, +0x0001bd50, +0x0001bd4d, +0x0001bd4b, +0x0001bd47, +0x0001bd44, +0x0001bd40, +0x0001bd3f, +0x0001bd3b, +0x0001bd38, +0x0001bd34, +0x0001bd32, +0x0001bd2f, +0x0001bd2b, +0x0001bd28, +0x0001bd26, +0x0001bd23, +0x0001bd1f, +0x0001bd1c, +0x0001bd1a, +0x0001bd17, +0x0001bd13, +0x0001bd10, +0x0001bd0d, +0x0001bd0b, +0x0001bd08, +0x0001bd04, +0x0001bd01, +0x0001bcff, +0x0001bcfb, +0x0001bcf8, +0x0001bcf5, +0x0001bcf3, +0x0001bcef, +0x0001bcec, +0x0001bce8, +0x0001bce7, +0x0001bce3, +0x0001bce0, +0x0001bcde, +0x0001bcdb, +0x0001bcd7, +0x0001bcd4, +0x0001bcd2, +0x0001bcce, +0x0001bccb, +0x0001bcc7, +0x0001bcc6, +0x0001bcc2, +0x0001bcbf, +0x0001bcbb, +0x0001bcba, +0x0001bcb6, +0x0001bcb3, +0x0001bcb1, +0x0001bcad, +0x0001bcaa, +0x0001bca7, +0x0001bca5, +0x0001bca1, +0x0001bc9e, +0x0001bc9a, +0x0001bc99, +0x0001bc95, +0x0001bc92, +0x0001bc8e, +0x0001bc8c, +0x0001bc89, +0x0001bc86, +0x0001bc82, +0x0001bc80, +0x0001bc7d, +0x0001bc79, +0x0001bc78, +0x0001bc74, +0x0001bc71, +0x0001bc6d, +0x0001bc6c, +0x0001bc68, +0x0001bc65, +0x0001bc61, +0x0001bc5f, +0x0001bc5c, +0x0001bc58, +0x0001bc55, +0x0001bc53, +0x0001bc50, +0x0001bc4c, +0x0001bc4b, +0x0001bc47, +0x0001bc44, +0x0001bc40, +0x0001bc3e, +0x0001bc3b, +0x0001bc38, +0x0001bc34, +0x0001bc32, +0x0001bc2f, +0x0001bc2b, +0x0001bc28, +0x0001bc26, +0x0001bc23, +0x0001bc1f, +0x0001bc1d, +0x0001bc1a, +0x0001bc17, +0x0001bc13, +0x0001bc11, +0x0001bc0e, +0x0001bc0a, +0x0001bc07, +0x0001bc05, +0x0001bc02, +0x0001bbfe, +0x0001bbfb, +0x0001bbf9, +0x0001bbf6, +0x0001bbf2, +0x0001bbf0, +0x0001bbed, +0x0001bbe9, +0x0001bbe6, +0x0001bbe4, +0x0001bbe1, +0x0001bbdd, +0x0001bbda, +0x0001bbd8, +0x0001bbd5, +0x0001bbd1, +0x0001bbce, +0x0001bbcc, +0x0001bbc9, +0x0001bbc5, +0x0001bbc2, +0x0001bbc0, +0x0001bbbc, +0x0001bbb9, +0x0001bbb7, +0x0001bbb4, +0x0001bbb0, +0x0001bbad, +0x0001bbab, +0x0001bba8, +0x0001bba4, +0x0001bba1, +0x0001bb9f, +0x0001bb9b, +0x0001bb98, +0x0001bb94, +0x0001bb93, +0x0001bb90, +0x0001bb8c, +0x0001bb89, +0x0001bb87, +0x0001bb84, +0x0001bb80, +0x0001bb7d, +0x0001bb7b, +0x0001bb77, +0x0001bb74, +0x0001bb70, +0x0001bb6f, +0x0001bb6b, +0x0001bb68, +0x0001bb66, +0x0001bb63, +0x0001bb5f, +0x0001bb5c, +0x0001bb5a, +0x0001bb57, +0x0001bb53, +0x0001bb50, +0x0001bb4e, +0x0001bb4a, +0x0001bb47, +0x0001bb43, +0x0001bb42, +0x0001bb3e, +0x0001bb3b, +0x0001bb39, +0x0001bb36, +0x0001bb32, +0x0001bb2f, +0x0001bb2d, +0x0001bb2a, +0x0001bb26, +0x0001bb23, +0x0001bb21, +0x0001bb1d, +0x0001bb1a, +0x0001bb18, +0x0001bb15, +0x0001bb11, +0x0001bb0e, +0x0001bb0c, +0x0001bb09, +0x0001bb05, +0x0001bb02, +0x0001bb00, +0x0001bafd, +0x0001baf9, +0x0001baf6, +0x0001baf4, +0x0001baf0, +0x0001baed, +0x0001baeb, +0x0001bae8, +0x0001bae4, +0x0001bae1, +0x0001badf, +0x0001badc, +0x0001bad8, +0x0001bad5, +0x0001bad3, +0x0001bad0, +0x0001bacc, +0x0001baca, +0x0001bac7, +0x0001bac3, +0x0001bac0, +0x0001babe, +0x0001babb, +0x0001bab7, +0x0001bab4, +0x0001bab2, +0x0001baaf, +0x0001baab, +0x0001baa9, +0x0001baa6, +0x0001baa3, +0x0001ba9f, +0x0001ba9d, +0x0001ba9a, +0x0001ba96, +0x0001ba93, +0x0001ba91, +0x0001ba8e, +0x0001ba8a, +0x0001ba87, +0x0001ba85, +0x0001ba82, +0x0001ba7e, +0x0001ba7c, +0x0001ba79, +0x0001ba76, +0x0001ba72, +0x0001ba70, +0x0001ba6d, +0x0001ba69, +0x0001ba66, +0x0001ba64, +0x0001ba61, +0x0001ba5d, +0x0001ba5c, +0x0001ba58, +0x0001ba55, +0x0001ba51, +0x0001ba4f, +0x0001ba4c, +0x0001ba49, +0x0001ba45, +0x0001ba43, +0x0001ba40, +0x0001ba3c, +0x0001ba39, +0x0001ba37, +0x0001ba34, +0x0001ba30, +0x0001ba2f, +0x0001ba2b, +0x0001ba28, +0x0001ba24, +0x0001ba23, +0x0001ba1f, +0x0001ba1c, +0x0001ba18, +0x0001ba16, +0x0001ba13, +0x0001ba10, +0x0001ba0d, +0x0001ba09, +0x0001ba08, +0x0001ba04, +0x0001ba01, +0x0001b9fd, +0x0001b9fc, +0x0001b9f8, +0x0001b9f5, +0x0001b9f3, +0x0001b9ef, +0x0001b9ec, +0x0001b9e9, +0x0001b9e7, +0x0001b9e3, +0x0001b9e0, +0x0001b9dd, +0x0001b9db, +0x0001b9d7, +0x0001b9d4, +0x0001b9d2, +0x0001b9cf, +0x0001b9cb, +0x0001b9c8, +0x0001b9c6, +0x0001b9c3, +0x0001b9bf, +0x0001b9bd, +0x0001b9ba, +0x0001b9b7, +0x0001b9b3, +0x0001b9b1, +0x0001b9ae, +0x0001b9ab, +0x0001b9a7, +0x0001b9a5, +0x0001b9a2, +0x0001b99e, +0x0001b99d, +0x0001b999, +0x0001b996, +0x0001b992, +0x0001b991, +0x0001b98d, +0x0001b98a, +0x0001b988, +0x0001b985, +0x0001b981, +0x0001b97e, +0x0001b97c, +0x0001b979, +0x0001b975, +0x0001b972, +0x0001b970, +0x0001b96d, +0x0001b969, +0x0001b967, +0x0001b964, +0x0001b960, +0x0001b95d, +0x0001b95b, +0x0001b958, +0x0001b954, +0x0001b953, +0x0001b94f, +0x0001b94c, +0x0001b948, +0x0001b947, +0x0001b943, +0x0001b940, +0x0001b93c, +0x0001b93b, +0x0001b937, +0x0001b934, +0x0001b932, +0x0001b92f, +0x0001b92b, +0x0001b928, +0x0001b926, +0x0001b922, +0x0001b91f, +0x0001b91c, +0x0001b91a, +0x0001b916, +0x0001b913, +0x0001b911, +0x0001b90e, +0x0001b90a, +0x0001b907, +0x0001b905, +0x0001b902, +0x0001b8fe, +0x0001b8fd, +0x0001b8f9, +0x0001b8f6, +0x0001b8f2, +0x0001b8f0, +0x0001b8ed, +0x0001b8ea, +0x0001b8e6, +0x0001b8e4, +0x0001b8e1, +0x0001b8de, +0x0001b8dc, +0x0001b8d8, +0x0001b8d5, +0x0001b8d1, +0x0001b8d0, +0x0001b8cc, +0x0001b8c9, +0x0001b8c7, +0x0001b8c4, +0x0001b8c0, +0x0001b8bd, +0x0001b8bb, +0x0001b8b8, +0x0001b8b4, +0x0001b8b1, +0x0001b8af, +0x0001b8ac, +0x0001b8a8, +0x0001b8a6, +0x0001b8a3, +0x0001b8a0, +0x0001b89c, +0x0001b89a, +0x0001b897, +0x0001b894, +0x0001b890, +0x0001b88f, +0x0001b88b, +0x0001b888, +0x0001b884, +0x0001b883, +0x0001b87f, +0x0001b87c, +0x0001b87a, +0x0001b877, +0x0001b873, +0x0001b870, +0x0001b86e, +0x0001b86b, +0x0001b867, +0x0001b865, +0x0001b862, +0x0001b85f, +0x0001b85b, +0x0001b859, +0x0001b856, +0x0001b853, +0x0001b84f, +0x0001b84d, +0x0001b84a, +0x0001b846, +0x0001b845, +0x0001b841, +0x0001b83e, +0x0001b83a, +0x0001b839, +0x0001b835, +0x0001b832, +0x0001b830, +0x0001b82d, +0x0001b829, +0x0001b826, +0x0001b824, +0x0001b821, +0x0001b81d, +0x0001b81c, +0x0001b818, +0x0001b815, +0x0001b811, +0x0001b80f, +0x0001b80c, +0x0001b809, +0x0001b807, +0x0001b803, +0x0001b800, +0x0001b7fd, +0x0001b7fb, +0x0001b7f7, +0x0001b7f4, +0x0001b7f1, +0x0001b7ef, +0x0001b7eb, +0x0001b7e8, +0x0001b7e6, +0x0001b7e3, +0x0001b7df, +0x0001b7dc, +0x0001b7da, +0x0001b7d7, +0x0001b7d3, +0x0001b7d2, +0x0001b7ce, +0x0001b7cb, +0x0001b7c7, +0x0001b7c6, +0x0001b7c2, +0x0001b7bf, +0x0001b7bd, +0x0001b7ba, +0x0001b7b6, +0x0001b7b3, +0x0001b7b1, +0x0001b7ae, +0x0001b7aa, +0x0001b7a8, +0x0001b7a5, +0x0001b7a1, +0x0001b79e, +0x0001b79c, +0x0001b799, +0x0001b795, +0x0001b792, +0x0001b790, +0x0001b78d, +0x0001b789, +0x0001b788, +0x0001b784, +0x0001b781, +0x0001b77d, +0x0001b77c, +0x0001b778, +0x0001b775, +0x0001b773, +0x0001b770, +0x0001b76c, +0x0001b769, +0x0001b767, +0x0001b764, +0x0001b760, +0x0001b75e, +0x0001b75b, +0x0001b758, +0x0001b754, +0x0001b752, +0x0001b74f, +0x0001b74c, +0x0001b74a, +0x0001b746, +0x0001b743, +0x0001b740, +0x0001b73e, +0x0001b73a, +0x0001b737, +0x0001b733, +0x0001b732, +0x0001b72e, +0x0001b72b, +0x0001b729, +0x0001b726, +0x0001b722, +0x0001b71f, +0x0001b71d, +0x0001b71a, +0x0001b717, +0x0001b713, +0x0001b710, +0x0001b70e, +0x0001b70b, +0x0001b707, +0x0001b706, +0x0001b702, +0x0001b6ff, +0x0001b6fc, +0x0001b6fa, +0x0001b6f6, +0x0001b6f3, +0x0001b6f1, +0x0001b6ee, +0x0001b6ea, +0x0001b6e7, +0x0001b6e5, +0x0001b6e2, +0x0001b6de, +0x0001b6dd, +0x0001b6d9, +0x0001b6d6, +0x0001b6d2, +0x0001b6d1, +0x0001b6cd, +0x0001b6ca, +0x0001b6c8, +0x0001b6c5, +0x0001b6c1, +0x0001b6be, +0x0001b6bc, +0x0001b6b9, +0x0001b6b5, +0x0001b6b4, +0x0001b6b0, +0x0001b6ad, +0x0001b6a9, +0x0001b6a8, +0x0001b6a4, +0x0001b6a1, +0x0001b69f, +0x0001b69c, +0x0001b698, +0x0001b697, +0x0001b693, +0x0001b690, +0x0001b68c, +0x0001b68b, +0x0001b687, +0x0001b684, +0x0001b682, +0x0001b67f, +0x0001b67b, +0x0001b678, +0x0001b676, +0x0001b673, +0x0001b66f, +0x0001b66e, +0x0001b66a, +0x0001b667, +0x0001b663, +0x0001b662, +0x0001b65e, +0x0001b65b, +0x0001b659, +0x0001b656, +0x0001b652, +0x0001b64f, +0x0001b64d, +0x0001b64a, +0x0001b646, +0x0001b644, +0x0001b641, +0x0001b63e, +0x0001b63a, +0x0001b638, +0x0001b635, +0x0001b632, +0x0001b630, +0x0001b62c, +0x0001b629, +0x0001b626, +0x0001b624, +0x0001b621, +0x0001b61d, +0x0001b61b, +0x0001b618, +0x0001b615, +0x0001b613, +0x0001b60f, +0x0001b60c, +0x0001b609, +0x0001b607, +0x0001b603, +0x0001b600, +0x0001b5fe, +0x0001b5fb, +0x0001b5f7, +0x0001b5f4, +0x0001b5f2, +0x0001b5ef, +0x0001b5eb, +0x0001b5ea, +0x0001b5e6, +0x0001b5e3, +0x0001b5df, +0x0001b5de, +0x0001b5da, +0x0001b5d7, +0x0001b5d5, +0x0001b5d2, +0x0001b5ce, +0x0001b5cb, +0x0001b5c9, +0x0001b5c6, +0x0001b5c2, +0x0001b5c1, +0x0001b5bd, +0x0001b5ba, +0x0001b5b6, +0x0001b5b5, +0x0001b5b1, +0x0001b5ae, +0x0001b5ac, +0x0001b5a9, +0x0001b5a5, +0x0001b5a2, +0x0001b5a0, +0x0001b59d, +0x0001b59a, +0x0001b596, +0x0001b595, +0x0001b591, +0x0001b58e, +0x0001b58c, +0x0001b589, +0x0001b585, +0x0001b582, +0x0001b580, +0x0001b57d, +0x0001b579, +0x0001b577, +0x0001b574, +0x0001b571, +0x0001b56f, +0x0001b56c, +0x0001b568, +0x0001b565, +0x0001b563, +0x0001b560, +0x0001b55c, +0x0001b55a, +0x0001b557, +0x0001b554, +0x0001b550, +0x0001b54f, +0x0001b54b, +0x0001b548, +0x0001b546, +0x0001b543, +0x0001b53f, +0x0001b53d, +0x0001b53a, +0x0001b537, +0x0001b533, +0x0001b532, +0x0001b52e, +0x0001b52b, +0x0001b529, +0x0001b526, +0x0001b522, +0x0001b51f, +0x0001b51d, +0x0001b51a, +0x0001b516, +0x0001b514, +0x0001b511, +0x0001b50e, +0x0001b50a, +0x0001b509, +0x0001b505, +0x0001b502, +0x0001b500, +0x0001b4fd, +0x0001b4f9, +0x0001b4f7, +0x0001b4f4, +0x0001b4f1, +0x0001b4ed, +0x0001b4ec, +0x0001b4e8, +0x0001b4e5, +0x0001b4e3, +0x0001b4e0, +0x0001b4dc, +0x0001b4d9, +0x0001b4d7, +0x0001b4d4, +0x0001b4d0, +0x0001b4ce, +0x0001b4cb, +0x0001b4c8, +0x0001b4c6, +0x0001b4c3, +0x0001b4bf, +0x0001b4bc, +0x0001b4ba, +0x0001b4b7, +0x0001b4b3, +0x0001b4b1, +0x0001b4ae, +0x0001b4ab, +0x0001b4a7, +0x0001b4a6, +0x0001b4a2, +0x0001b49f, +0x0001b49d, +0x0001b49a, +0x0001b496, +0x0001b493, +0x0001b491, +0x0001b48e, +0x0001b48a, +0x0001b489, +0x0001b485, +0x0001b482, +0x0001b480, +0x0001b47d, +0x0001b479, +0x0001b476, +0x0001b474, +0x0001b471, +0x0001b46d, +0x0001b46b, +0x0001b468, +0x0001b465, +0x0001b461, +0x0001b460, +0x0001b45c, +0x0001b459, +0x0001b457, +0x0001b454, +0x0001b450, +0x0001b44e, +0x0001b44b, +0x0001b448, +0x0001b444, +0x0001b443, +0x0001b43f, +0x0001b43c, +0x0001b43a, +0x0001b437, +0x0001b433, +0x0001b430, +0x0001b42d, +0x0001b42b, +0x0001b428, +0x0001b424, +0x0001b421, +0x0001b41f, +0x0001b41c, +0x0001b418, +0x0001b417, +0x0001b413, +0x0001b410, +0x0001b40e, +0x0001b40b, +0x0001b407, +0x0001b404, +0x0001b402, +0x0001b3ff, +0x0001b3fb, +0x0001b3fa, +0x0001b3f6, +0x0001b3f3, +0x0001b3f1, +0x0001b3ee, +0x0001b3ea, +0x0001b3e7, +0x0001b3e5, +0x0001b3e2, +0x0001b3df, +0x0001b3dd, +0x0001b3da, +0x0001b3d6, +0x0001b3d4, +0x0001b3d1, +0x0001b3ce, +0x0001b3ca, +0x0001b3c9, +0x0001b3c5, +0x0001b3c2, +0x0001b3c0, +0x0001b3bd, +0x0001b3b9, +0x0001b3b8, +0x0001b3b4, +0x0001b3b1, +0x0001b3ad, +0x0001b3ac, +0x0001b3a8, +0x0001b3a5, +0x0001b3a3, +0x0001b3a0, +0x0001b39c, +0x0001b39b, +0x0001b397, +0x0001b394, +0x0001b390, +0x0001b38f, +0x0001b38b, +0x0001b388, +0x0001b386, +0x0001b383, +0x0001b37f, +0x0001b37e, +0x0001b37a, +0x0001b377, +0x0001b375, +0x0001b372, +0x0001b36e, +0x0001b36b, +0x0001b369, +0x0001b366, +0x0001b363, +0x0001b361, +0x0001b35d, +0x0001b35a, +0x0001b358, +0x0001b355, +0x0001b352, +0x0001b34e, +0x0001b34c, +0x0001b349, +0x0001b346, +0x0001b344, +0x0001b341, +0x0001b33d, +0x0001b33b, +0x0001b338, +0x0001b335, +0x0001b331, +0x0001b330, +0x0001b32c, +0x0001b329, +0x0001b327, +0x0001b324, +0x0001b320, +0x0001b31f, +0x0001b31b, +0x0001b318, +0x0001b314, +0x0001b313, +0x0001b30f, +0x0001b30c, +0x0001b30a, +0x0001b307, +0x0001b303, +0x0001b302, +0x0001b2fe, +0x0001b2fb, +0x0001b2f8, +0x0001b2f6, +0x0001b2f2, +0x0001b2ef, +0x0001b2ed, +0x0001b2ea, +0x0001b2e7, +0x0001b2e5, +0x0001b2e1, +0x0001b2de, +0x0001b2db, +0x0001b2d9, +0x0001b2d6, +0x0001b2d2, +0x0001b2d0, +0x0001b2cd, +0x0001b2ca, +0x0001b2c8, +0x0001b2c5, +0x0001b2c1, +0x0001b2be, +0x0001b2bc, +0x0001b2b9, +0x0001b2b5, +0x0001b2b2, +0x0001b2b0, +0x0001b2ad, +0x0001b2aa, +0x0001b2a8, +0x0001b2a4, +0x0001b2a1, +0x0001b29f, +0x0001b29c, +0x0001b299, +0x0001b295, +0x0001b293, +0x0001b290, +0x0001b28d, +0x0001b28b, +0x0001b288, +0x0001b284, +0x0001b283, +0x0001b27f, +0x0001b27c, +0x0001b27a, +0x0001b277, +0x0001b273, +0x0001b270, +0x0001b26e, +0x0001b26b, +0x0001b267, +0x0001b266, +0x0001b262, +0x0001b25f, +0x0001b25d, +0x0001b25a, +0x0001b256, +0x0001b253, +0x0001b251, +0x0001b24e, +0x0001b24b, +0x0001b249, +0x0001b246, +0x0001b242, +0x0001b240, +0x0001b23d, +0x0001b23a, +0x0001b238, +0x0001b235, +0x0001b231, +0x0001b22e, +0x0001b22c, +0x0001b229, +0x0001b225, +0x0001b224, +0x0001b220, +0x0001b21d, +0x0001b21b, +0x0001b218, +0x0001b214, +0x0001b211, +0x0001b20f, +0x0001b20c, +0x0001b208, +0x0001b207, +0x0001b203, +0x0001b200, +0x0001b1fe, +0x0001b1fb, +0x0001b1f8, +0x0001b1f6, +0x0001b1f2, +0x0001b1ef, +0x0001b1ec, +0x0001b1ea, +0x0001b1e7, +0x0001b1e3, +0x0001b1e1, +0x0001b1de, +0x0001b1db, +0x0001b1d9, +0x0001b1d6, +0x0001b1d2, +0x0001b1cf, +0x0001b1cd, +0x0001b1ca, +0x0001b1c6, +0x0001b1c5, +0x0001b1c1, +0x0001b1be, +0x0001b1bc, +0x0001b1b9, +0x0001b1b5, +0x0001b1b4, +0x0001b1b0, +0x0001b1ad, +0x0001b1aa, +0x0001b1a8, +0x0001b1a4, +0x0001b1a1, +0x0001b19f, +0x0001b19c, +0x0001b199, +0x0001b197, +0x0001b194, +0x0001b190, +0x0001b18d, +0x0001b18b, +0x0001b188, +0x0001b184, +0x0001b183, +0x0001b17f, +0x0001b17c, +0x0001b17a, +0x0001b177, +0x0001b173, +0x0001b172, +0x0001b16e, +0x0001b16b, +0x0001b167, +0x0001b166, +0x0001b162, +0x0001b15f, +0x0001b15d, +0x0001b15a, +0x0001b156, +0x0001b155, +0x0001b151, +0x0001b14e, +0x0001b14c, +0x0001b149, +0x0001b145, +0x0001b144, +0x0001b140, +0x0001b13d, +0x0001b13b, +0x0001b138, +0x0001b134, +0x0001b133, +0x0001b12f, +0x0001b12c, +0x0001b129, +0x0001b127, +0x0001b124, +0x0001b120, +0x0001b11e, +0x0001b11b, +0x0001b118, +0x0001b116, +0x0001b113, +0x0001b10f, +0x0001b10e, +0x0001b10a, +0x0001b107, +0x0001b103, +0x0001b102, +0x0001b0fe, +0x0001b0fb, +0x0001b0f9, +0x0001b0f6, +0x0001b0f2, +0x0001b0f1, +0x0001b0ed, +0x0001b0ea, +0x0001b0e8, +0x0001b0e5, +0x0001b0e2, +0x0001b0de, +0x0001b0dc, +0x0001b0d9, +0x0001b0d6, +0x0001b0d4, +0x0001b0d1, +0x0001b0cd, +0x0001b0cc, +0x0001b0c8, +0x0001b0c5, +0x0001b0c3, +0x0001b0c0, +0x0001b0bc, +0x0001b0b9, +0x0001b0b7, +0x0001b0b4, +0x0001b0b1, +0x0001b0af, +0x0001b0ab, +0x0001b0a8, +0x0001b0a6, +0x0001b0a3, +0x0001b0a0, +0x0001b09e, +0x0001b09b, +0x0001b097, +0x0001b095, +0x0001b092, +0x0001b08f, +0x0001b08b, +0x0001b08a, +0x0001b086, +0x0001b083, +0x0001b081, +0x0001b07e, +0x0001b07a, +0x0001b079, +0x0001b075, +0x0001b072, +0x0001b070, +0x0001b06d, +0x0001b069, +0x0001b066, +0x0001b064, +0x0001b061, +0x0001b05e, +0x0001b05c, +0x0001b059, +0x0001b055, +0x0001b053, +0x0001b050, +0x0001b04d, +0x0001b04b, +0x0001b048, +0x0001b044, +0x0001b041, +0x0001b03f, +0x0001b03c, +0x0001b038, +0x0001b037, +0x0001b033, +0x0001b030, +0x0001b02e, +0x0001b02b, +0x0001b028, +0x0001b026, +0x0001b022, +0x0001b01f, +0x0001b01c, +0x0001b01a, +0x0001b017, +0x0001b013, +0x0001b012, +0x0001b00e, +0x0001b00b, +0x0001b009, +0x0001b006, +0x0001b002, +0x0001b001, +0x0001affd, +0x0001affa, +0x0001aff6, +0x0001aff5, +0x0001aff1, +0x0001afee, +0x0001afec, +0x0001afe9, +0x0001afe6, +0x0001afe4, +0x0001afe0, +0x0001afde, +0x0001afdb, +0x0001afd8, +0x0001afd6, +0x0001afd2, +0x0001afcf, +0x0001afcd, +0x0001afca, +0x0001afc7, +0x0001afc5, +0x0001afc2, +0x0001afbe, +0x0001afbd, +0x0001afb9, +0x0001afb6, +0x0001afb2, +0x0001afb1, +0x0001afad, +0x0001afaa, +0x0001afa8, +0x0001afa5, +0x0001afa2, +0x0001afa0, +0x0001af9d, +0x0001af99, +0x0001af98, +0x0001af94, +0x0001af91, +0x0001af8f, +0x0001af8c, +0x0001af88, +0x0001af87, +0x0001af83, +0x0001af80, +0x0001af7e, +0x0001af7b, +0x0001af78, +0x0001af74, +0x0001af72, +0x0001af6f, +0x0001af6c, +0x0001af6a, +0x0001af67, +0x0001af63, +0x0001af62, +0x0001af5e, +0x0001af5b, +0x0001af59, +0x0001af56, +0x0001af52, +0x0001af51, +0x0001af4d, +0x0001af4a, +0x0001af48, +0x0001af45, +0x0001af42, +0x0001af3e, +0x0001af3d, +0x0001af39, +0x0001af36, +0x0001af34, +0x0001af31, +0x0001af2d, +0x0001af2c, +0x0001af28, +0x0001af25, +0x0001af23, +0x0001af20, +0x0001af1d, +0x0001af1b, +0x0001af18, +0x0001af14, +0x0001af13, +0x0001af0f, +0x0001af0c, +0x0001af08, +0x0001af07, +0x0001af03, +0x0001af00, +0x0001aefe, +0x0001aefb, +0x0001aef8, +0x0001aef6, +0x0001aef3, +0x0001aeef, +0x0001aeed, +0x0001aeea, +0x0001aee7, +0x0001aee5, +0x0001aee2, +0x0001aede, +0x0001aedd, +0x0001aed9, +0x0001aed6, +0x0001aed3, +0x0001aed1, +0x0001aecd, +0x0001aeca, +0x0001aec8, +0x0001aec5, +0x0001aec2, +0x0001aec0, +0x0001aebd, +0x0001aeb9, +0x0001aeb8, +0x0001aeb4, +0x0001aeb1, +0x0001aeaf, +0x0001aeac, +0x0001aea8, +0x0001aea7, +0x0001aea3, +0x0001aea0, +0x0001ae9e, +0x0001ae9b, +0x0001ae98, +0x0001ae94, +0x0001ae93, +0x0001ae8f, +0x0001ae8c, +0x0001ae8a, +0x0001ae87, +0x0001ae83, +0x0001ae82, +0x0001ae7e, +0x0001ae7b, +0x0001ae79, +0x0001ae76, +0x0001ae74, +0x0001ae71, +0x0001ae6d, +0x0001ae6a, +0x0001ae68, +0x0001ae65, +0x0001ae61, +0x0001ae60, +0x0001ae5c, +0x0001ae59, +0x0001ae57, +0x0001ae54, +0x0001ae51, +0x0001ae4f, +0x0001ae4c, +0x0001ae48, +0x0001ae47, +0x0001ae43, +0x0001ae40, +0x0001ae3e, +0x0001ae3b, +0x0001ae37, +0x0001ae36, +0x0001ae32, +0x0001ae2f, +0x0001ae2d, +0x0001ae2a, +0x0001ae27, +0x0001ae23, +0x0001ae22, +0x0001ae1e, +0x0001ae1b, +0x0001ae19, +0x0001ae16, +0x0001ae12, +0x0001ae11, +0x0001ae0d, +0x0001ae0a, +0x0001ae08, +0x0001ae05, +0x0001ae02, +0x0001ae00, +0x0001adfd, +0x0001adf9, +0x0001adf8, +0x0001adf4, +0x0001adf1, +0x0001adef, +0x0001adec, +0x0001ade8, +0x0001ade7, +0x0001ade3, +0x0001ade0, +0x0001addd, +0x0001addb, +0x0001add8, +0x0001add4, +0x0001add3, +0x0001adcf, +0x0001adcc, +0x0001adca, +0x0001adc7, +0x0001adc4, +0x0001adc2, +0x0001adbe, +0x0001adbb, +0x0001adb9, +0x0001adb6, +0x0001adb3, +0x0001adb1, +0x0001adae, +0x0001adaa, +0x0001ada9, +0x0001ada5, +0x0001ada2, +0x0001ada0, +0x0001ad9d, +0x0001ad9a, +0x0001ad96, +0x0001ad95, +0x0001ad91, +0x0001ad8e, +0x0001ad8c, +0x0001ad89, +0x0001ad85, +0x0001ad84, +0x0001ad80, +0x0001ad7d, +0x0001ad7b, +0x0001ad78, +0x0001ad75, +0x0001ad73, +0x0001ad70, +0x0001ad6c, +0x0001ad6b, +0x0001ad67, +0x0001ad64, +0x0001ad62, +0x0001ad5f, +0x0001ad5b, +0x0001ad5a, +0x0001ad56, +0x0001ad53, +0x0001ad50, +0x0001ad4e, +0x0001ad4b, +0x0001ad47, +0x0001ad46, +0x0001ad42, +0x0001ad3f, +0x0001ad3d, +0x0001ad3a, +0x0001ad36, +0x0001ad35, +0x0001ad31, +0x0001ad2e, +0x0001ad2c, +0x0001ad29, +0x0001ad26, +0x0001ad24, +0x0001ad21, +0x0001ad1d, +0x0001ad1c, +0x0001ad18, +0x0001ad15, +0x0001ad13, +0x0001ad10, +0x0001ad0c, +0x0001ad0a, +0x0001ad06, +0x0001ad05, +0x0001ad01, +0x0001acfe, +0x0001acfc, +0x0001acf9, +0x0001acf6, +0x0001acf4, +0x0001acf1, +0x0001aced, +0x0001acec, +0x0001ace8, +0x0001ace5, +0x0001ace3, +0x0001ace0, +0x0001acdd, +0x0001acdb, +0x0001acd8, +0x0001acd4, +0x0001acd3, +0x0001accf, +0x0001accc, +0x0001acca, +0x0001acc7, +0x0001acc4, +0x0001acc2, +0x0001acbf, +0x0001acbb, +0x0001acba, +0x0001acb6, +0x0001acb3, +0x0001acb1, +0x0001acae, +0x0001acab, +0x0001aca7, +0x0001aca6, +0x0001aca2, +0x0001ac9f, +0x0001ac9d, +0x0001ac9a, +0x0001ac96, +0x0001ac95, +0x0001ac91, +0x0001ac8e, +0x0001ac8c, +0x0001ac89, +0x0001ac86, +0x0001ac84, +0x0001ac81, +0x0001ac7d, +0x0001ac7c, +0x0001ac78, +0x0001ac75, +0x0001ac73, +0x0001ac70, +0x0001ac6d, +0x0001ac6b, +0x0001ac68, +0x0001ac64, +0x0001ac63, +0x0001ac5f, +0x0001ac5c, +0x0001ac5a, +0x0001ac57, +0x0001ac54, +0x0001ac52, +0x0001ac4f, +0x0001ac4b, +0x0001ac4a, +0x0001ac46, +0x0001ac43, +0x0001ac41, +0x0001ac3e, +0x0001ac3b, +0x0001ac39, +0x0001ac36, +0x0001ac32, +0x0001ac30, +0x0001ac2d, +0x0001ac2a, +0x0001ac28, +0x0001ac25, +0x0001ac21, +0x0001ac20, +0x0001ac1c, +0x0001ac19, +0x0001ac17, +0x0001ac14, +0x0001ac11, +0x0001ac0f, +0x0001ac0c, +0x0001ac08, +0x0001ac07, +0x0001ac03, +0x0001ac00, +0x0001abfe, +0x0001abfb, +0x0001abf8, +0x0001abf4, +0x0001abf3, +0x0001abef, +0x0001abec, +0x0001abea, +0x0001abe7, +0x0001abe4, +0x0001abe2, +0x0001abdf, +0x0001abdb, +0x0001abda, +0x0001abd6, +0x0001abd3, +0x0001abd1, +0x0001abce, +0x0001abcb, +0x0001abc9, +0x0001abc5, +0x0001abc2, +0x0001abc0, +0x0001abbd, +0x0001abba, +0x0001abb8, +0x0001abb5, +0x0001abb1, +0x0001abb0, +0x0001abac, +0x0001aba9, +0x0001aba7, +0x0001aba3, +0x0001aba2, +0x0001ab9e, +0x0001ab9b, +0x0001ab99, +0x0001ab96, +0x0001ab93, +0x0001ab91, +0x0001ab8e, +0x0001ab8a, +0x0001ab89, +0x0001ab85, +0x0001ab82, +0x0001ab80, +0x0001ab7d, +0x0001ab7a, +0x0001ab78, +0x0001ab75, +0x0001ab71, +0x0001ab70, +0x0001ab6c, +0x0001ab69, +0x0001ab67, +0x0001ab64, +0x0001ab61, +0x0001ab5f, +0x0001ab5c, +0x0001ab58, +0x0001ab57, +0x0001ab53, +0x0001ab50, +0x0001ab4e, +0x0001ab4b, +0x0001ab48, +0x0001ab46, +0x0001ab43, +0x0001ab3f, +0x0001ab3e, +0x0001ab3a, +0x0001ab37, +0x0001ab35, +0x0001ab32, +0x0001ab2f, +0x0001ab2d, +0x0001ab2a, +0x0001ab26, +0x0001ab25, +0x0001ab21, +0x0001ab1e, +0x0001ab1c, +0x0001ab19, +0x0001ab16, +0x0001ab14, +0x0001ab11, +0x0001ab0d, +0x0001ab0c, +0x0001ab08, +0x0001ab05, +0x0001ab03, +0x0001ab00, +0x0001aafd, +0x0001aafb, +0x0001aaf8, +0x0001aaf4, +0x0001aaf3, +0x0001aaef, +0x0001aaec, +0x0001aae9, +0x0001aae7, +0x0001aae4, +0x0001aae0, +0x0001aadf, +0x0001aadb, +0x0001aad8, +0x0001aad6, +0x0001aad3, +0x0001aad0, +0x0001aace, +0x0001aacb, +0x0001aac7, +0x0001aac6, +0x0001aac2, +0x0001aabf, +0x0001aabd, +0x0001aaba, +0x0001aab7, +0x0001aab5, +0x0001aab2, +0x0001aaae, +0x0001aaad, +0x0001aaa9, +0x0001aaa6, +0x0001aaa4, +0x0001aaa1, +0x0001aa9e, +0x0001aa9c, +0x0001aa99, +0x0001aa95, +0x0001aa94, +0x0001aa90, +0x0001aa8d, +0x0001aa8b, +0x0001aa88, +0x0001aa85, +0x0001aa83, +0x0001aa80, +0x0001aa7c, +0x0001aa7b, +0x0001aa77, +0x0001aa74, +0x0001aa72, +0x0001aa6f, +0x0001aa6c, +0x0001aa6a, +0x0001aa67, +0x0001aa63, +0x0001aa62, +0x0001aa5e, +0x0001aa5b, +0x0001aa59, +0x0001aa56, +0x0001aa53, +0x0001aa51, +0x0001aa4e, +0x0001aa4a, +0x0001aa49, +0x0001aa45, +0x0001aa42, +0x0001aa41, +0x0001aa3e, +0x0001aa3a, +0x0001aa39, +0x0001aa35, +0x0001aa32, +0x0001aa30, +0x0001aa2d, +0x0001aa2a, +0x0001aa28, +0x0001aa25, +0x0001aa21, +0x0001aa20, +0x0001aa1c, +0x0001aa19, +0x0001aa17, +0x0001aa14, +0x0001aa11, +0x0001aa0f, +0x0001aa0c, +0x0001aa08, +0x0001aa07, +0x0001aa03, +0x0001aa00, +0x0001a9fe, +0x0001a9fb, +0x0001a9f8, +0x0001a9f6, +0x0001a9f3, +0x0001a9ef, +0x0001a9ee, +0x0001a9ea, +0x0001a9e7, +0x0001a9e5, +0x0001a9e2, +0x0001a9df, +0x0001a9dd, +0x0001a9da, +0x0001a9d6, +0x0001a9d5, +0x0001a9d1, +0x0001a9ce, +0x0001a9cc, +0x0001a9c9, +0x0001a9c6, +0x0001a9c4, +0x0001a9c1, +0x0001a9bd, +0x0001a9bc, +0x0001a9b8, +0x0001a9b5, +0x0001a9b3, +0x0001a9b0, +0x0001a9ad, +0x0001a9ab, +0x0001a9a8, +0x0001a9a4, +0x0001a9a3, +0x0001a99f, +0x0001a99c, +0x0001a99a, +0x0001a997, +0x0001a994, +0x0001a992, +0x0001a98f, +0x0001a98c, +0x0001a98a, +0x0001a987, +0x0001a983, +0x0001a982, +0x0001a97e, +0x0001a97b, +0x0001a979, +0x0001a976, +0x0001a973, +0x0001a971, +0x0001a96e, +0x0001a96a, +0x0001a969, +0x0001a965, +0x0001a962, +0x0001a960, +0x0001a95d, +0x0001a95a, +0x0001a958, +0x0001a955, +0x0001a951, +0x0001a950, +0x0001a94c, +0x0001a949, +0x0001a947, +0x0001a944, +0x0001a941, +0x0001a93f, +0x0001a93c, +0x0001a938, +0x0001a937, +0x0001a933, +0x0001a930, +0x0001a92e, +0x0001a92b, +0x0001a928, +0x0001a926, +0x0001a923, +0x0001a91f, +0x0001a91e, +0x0001a91a, +0x0001a917, +0x0001a915, +0x0001a912, +0x0001a90f, +0x0001a90d, +0x0001a90a, +0x0001a906, +0x0001a905, +0x0001a901, +0x0001a8fe, +0x0001a8fc, +0x0001a8f9, +0x0001a8f6, +0x0001a8f4, +0x0001a8f1, +0x0001a8ed, +0x0001a8ec, +0x0001a8e8, +0x0001a8e5, +0x0001a8e3, +0x0001a8e0, +0x0001a8de, +0x0001a8db, +0x0001a8d9, +0x0001a8d6, +0x0001a8d2, +0x0001a8d1, +0x0001a8cd, +0x0001a8ca, +0x0001a8c8, +0x0001a8c5, +0x0001a8c2, +0x0001a8c0, +0x0001a8bd, +0x0001a8ba, +0x0001a8b8, +0x0001a8b5, +0x0001a8b3, +0x0001a8b0, +0x0001a8ac, +0x0001a8ab, +0x0001a8a7, +0x0001a8a4, +0x0001a8a2, +0x0001a89f, +0x0001a89c, +0x0001a89a, +0x0001a897, +0x0001a893, +0x0001a892, +0x0001a88e, +0x0001a88b, +0x0001a889, +0x0001a886, +0x0001a883, +0x0001a881, +0x0001a87e, +0x0001a87b, +0x0001a879, +0x0001a876, +0x0001a872, +0x0001a871, +0x0001a86d, +0x0001a86a, +0x0001a868, +0x0001a865, +0x0001a862, +0x0001a860, +0x0001a85d, +0x0001a85b, +0x0001a858, +0x0001a854, +0x0001a853, +0x0001a850, +0x0001a84c, +0x0001a84b, +0x0001a847, +0x0001a844, +0x0001a842, +0x0001a83f, +0x0001a83c, +0x0001a83a, +0x0001a837, +0x0001a833, +0x0001a832, +0x0001a82e, +0x0001a82b, +0x0001a829, +0x0001a826, +0x0001a823, +0x0001a821, +0x0001a81e, +0x0001a81b, +0x0001a819, +0x0001a816, +0x0001a812, +0x0001a811, +0x0001a80d, +0x0001a80a, +0x0001a808, +0x0001a805, +0x0001a803, +0x0001a800, +0x0001a7fd, +0x0001a7fb, +0x0001a7f8, +0x0001a7f4, +0x0001a7f3, +0x0001a7ef, +0x0001a7ec, +0x0001a7ea, +0x0001a7e7, +0x0001a7e4, +0x0001a7e2, +0x0001a7df, +0x0001a7dc, +0x0001a7da, +0x0001a7d7, +0x0001a7d3, +0x0001a7d2, +0x0001a7ce, +0x0001a7cb, +0x0001a7c9, +0x0001a7c6, +0x0001a7c3, +0x0001a7c1, +0x0001a7be, +0x0001a7ba, +0x0001a7b9, +0x0001a7b5, +0x0001a7b2, +0x0001a7b1, +0x0001a7ad, +0x0001a7ac, +0x0001a7a8, +0x0001a7a5, +0x0001a7a3, +0x0001a7a0, +0x0001a79d, +0x0001a79b, +0x0001a798, +0x0001a794, +0x0001a793, +0x0001a78f, +0x0001a78c, +0x0001a78a, +0x0001a787, +0x0001a784, +0x0001a782, +0x0001a77f, +0x0001a77c, +0x0001a779, +0x0001a777, +0x0001a774, +0x0001a770, +0x0001a76f, +0x0001a76b, +0x0001a76a, +0x0001a766, +0x0001a763, +0x0001a761, +0x0001a75e, +0x0001a75b, +0x0001a759, +0x0001a756, +0x0001a753, +0x0001a751, +0x0001a74e, +0x0001a74a, +0x0001a749, +0x0001a745, +0x0001a742, +0x0001a740, +0x0001a73d, +0x0001a73a, +0x0001a738, +0x0001a735, +0x0001a732, +0x0001a730, +0x0001a72d, +0x0001a72b, +0x0001a728, +0x0001a724, +0x0001a723, +0x0001a71f, +0x0001a71c, +0x0001a71a, +0x0001a717, +0x0001a714, +0x0001a712, +0x0001a70f, +0x0001a70c, +0x0001a70a, +0x0001a707, +0x0001a703, +0x0001a702, +0x0001a6fe, +0x0001a6fb, +0x0001a6f9, +0x0001a6f6, +0x0001a6f3, +0x0001a6f1, +0x0001a6ee, +0x0001a6ec, +0x0001a6e9, +0x0001a6e6, +0x0001a6e4, +0x0001a6e1, +0x0001a6dd, +0x0001a6dc, +0x0001a6d8, +0x0001a6d5, +0x0001a6d3, +0x0001a6d0, +0x0001a6cd, +0x0001a6cb, +0x0001a6c8, +0x0001a6c5, +0x0001a6c3, +0x0001a6c0, +0x0001a6bc, +0x0001a6bb, +0x0001a6b7, +0x0001a6b4, +0x0001a6b2, +0x0001a6af, +0x0001a6ad, +0x0001a6aa, +0x0001a6a7, +0x0001a6a5, +0x0001a6a2, +0x0001a69f, +0x0001a69d, +0x0001a69a, +0x0001a696, +0x0001a695, +0x0001a691, +0x0001a68e, +0x0001a68c, +0x0001a689, +0x0001a686, +0x0001a684, +0x0001a681, +0x0001a67d, +0x0001a67c, +0x0001a679, +0x0001a675, +0x0001a674, +0x0001a670, +0x0001a66f, +0x0001a66b, +0x0001a668, +0x0001a666, +0x0001a663, +0x0001a660, +0x0001a65e, +0x0001a65b, +0x0001a657, +0x0001a656, +0x0001a653, +0x0001a64f, +0x0001a64e, +0x0001a64a, +0x0001a647, +0x0001a645, +0x0001a642, +0x0001a63f, +0x0001a63d, +0x0001a63a, +0x0001a636, +0x0001a635, +0x0001a631, +0x0001a630, +0x0001a62d, +0x0001a629, +0x0001a628, +0x0001a624, +0x0001a621, +0x0001a61e, +0x0001a61b, +0x0001a619, +0x0001a616, +0x0001a614, +0x0001a611, +0x0001a60e, +0x0001a60c, +0x0001a609, +0x0001a605, +0x0001a604, +0x0001a601, +0x0001a5fd, +0x0001a5fc, +0x0001a5f8, +0x0001a5f5, +0x0001a5f3, +0x0001a5f0, +0x0001a5ee, +0x0001a5eb, +0x0001a5e8, +0x0001a5e6, +0x0001a5e3, +0x0001a5e0, +0x0001a5de, +0x0001a5db, +0x0001a5d7, +0x0001a5d6, +0x0001a5d3, +0x0001a5cf, +0x0001a5ce, +0x0001a5ca, +0x0001a5c7, +0x0001a5c5, +0x0001a5c2, +0x0001a5c0, +0x0001a5bd, +0x0001a5ba, +0x0001a5b8, +0x0001a5b5, +0x0001a5b2, +0x0001a5b0, +0x0001a5ad, +0x0001a5a9, +0x0001a5a8, +0x0001a5a4, +0x0001a5a1, +0x0001a5a0, +0x0001a59c, +0x0001a59b, +0x0001a597, +0x0001a594, +0x0001a592, +0x0001a58f, +0x0001a58c, +0x0001a58a, +0x0001a587, +0x0001a584, +0x0001a582, +0x0001a57f, +0x0001a57b, +0x0001a57a, +0x0001a576, +0x0001a575, +0x0001a571, +0x0001a56e, +0x0001a56d, +0x0001a569, +0x0001a566, +0x0001a564, +0x0001a561, +0x0001a55e, +0x0001a55c, +0x0001a559, +0x0001a556, +0x0001a554, +0x0001a551, +0x0001a54d, +0x0001a54c, +0x0001a548, +0x0001a547, +0x0001a543, +0x0001a540, +0x0001a53e, +0x0001a53b, +0x0001a538, +0x0001a536, +0x0001a533, +0x0001a530, +0x0001a52e, +0x0001a52b, +0x0001a527, +0x0001a526, +0x0001a523, +0x0001a521, +0x0001a51e, +0x0001a51a, +0x0001a519, +0x0001a515, +0x0001a512, +0x0001a510, +0x0001a50d, +0x0001a50a, +0x0001a508, +0x0001a505, +0x0001a502, +0x0001a500, +0x0001a4fd, +0x0001a4f9, +0x0001a4f8, +0x0001a4f4, +0x0001a4f3, +0x0001a4f0, +0x0001a4ec, +0x0001a4eb, +0x0001a4e7, +0x0001a4e4, +0x0001a4e2, +0x0001a4df, +0x0001a4dc, +0x0001a4da, +0x0001a4d7, +0x0001a4d4, +0x0001a4d2, +0x0001a4cf, +0x0001a4cd, +0x0001a4ca, +0x0001a4c7, +0x0001a4c3, +0x0001a4c2, +0x0001a4be, +0x0001a4bb, +0x0001a4b9, +0x0001a4b6, +0x0001a4b4, +0x0001a4b1, +0x0001a4ae, +0x0001a4ac, +0x0001a4a9, +0x0001a4a6, +0x0001a4a4, +0x0001a4a1, +0x0001a49e, +0x0001a49c, +0x0001a499, +0x0001a495, +0x0001a494, +0x0001a490, +0x0001a48f, +0x0001a48b, +0x0001a488, +0x0001a487, +0x0001a483, +0x0001a480, +0x0001a47e, +0x0001a47b, +0x0001a478, +0x0001a476, +0x0001a473, +0x0001a471, +0x0001a46e, +0x0001a46b, +0x0001a469, +0x0001a466, +0x0001a462, +0x0001a461, +0x0001a45e, +0x0001a45a, +0x0001a459, +0x0001a455, +0x0001a452, +0x0001a450, +0x0001a44d, +0x0001a44b, +0x0001a448, +0x0001a445, +0x0001a443, +0x0001a440, +0x0001a43d, +0x0001a43b, +0x0001a438, +0x0001a435, +0x0001a433, +0x0001a430, +0x0001a42c, +0x0001a42b, +0x0001a427, +0x0001a426, +0x0001a422, +0x0001a41f, +0x0001a41e, +0x0001a41a, +0x0001a417, +0x0001a415, +0x0001a412, +0x0001a40f, +0x0001a40d, +0x0001a40a, +0x0001a408, +0x0001a405, +0x0001a402, +0x0001a400, +0x0001a3fd, +0x0001a3f9, +0x0001a3f8, +0x0001a3f5, +0x0001a3f1, +0x0001a3f0, +0x0001a3ec, +0x0001a3e9, +0x0001a3e7, +0x0001a3e4, +0x0001a3e2, +0x0001a3df, +0x0001a3dc, +0x0001a3da, +0x0001a3d7, +0x0001a3d4, +0x0001a3d2, +0x0001a3cf, +0x0001a3cc, +0x0001a3ca, +0x0001a3c7, +0x0001a3c5, +0x0001a3c2, +0x0001a3be, +0x0001a3bd, +0x0001a3b9, +0x0001a3b6, +0x0001a3b5, +0x0001a3b1, +0x0001a3ae, +0x0001a3ac, +0x0001a3a9, +0x0001a3a6, +0x0001a3a4, +0x0001a3a1, +0x0001a39f, +0x0001a39c, +0x0001a399, +0x0001a397, +0x0001a394, +0x0001a390, +0x0001a38f, +0x0001a38c, +0x0001a388, +0x0001a387, +0x0001a383, +0x0001a380, +0x0001a37e, +0x0001a37b, +0x0001a379, +0x0001a376, +0x0001a373, +0x0001a371, +0x0001a36e, +0x0001a36c, +0x0001a369, +0x0001a365, +0x0001a364, +0x0001a361, +0x0001a35d, +0x0001a35c, +0x0001a358, +0x0001a357, +0x0001a353, +0x0001a350, +0x0001a34f, +0x0001a34b, +0x0001a348, +0x0001a346, +0x0001a343, +0x0001a340, +0x0001a33e, +0x0001a33b, +0x0001a339, +0x0001a336, +0x0001a333, +0x0001a331, +0x0001a32e, +0x0001a32b, +0x0001a329, +0x0001a326, +0x0001a322, +0x0001a321, +0x0001a31d, +0x0001a31c, +0x0001a319, +0x0001a315, +0x0001a314, +0x0001a310, +0x0001a30d, +0x0001a30b, +0x0001a308, +0x0001a305, +0x0001a303, +0x0001a300, +0x0001a2fe, +0x0001a2fb, +0x0001a2f8, +0x0001a2f6, +0x0001a2f3, +0x0001a2f0, +0x0001a2ee, +0x0001a2eb, +0x0001a2e7, +0x0001a2e6, +0x0001a2e3, +0x0001a2e1, +0x0001a2de, +0x0001a2da, +0x0001a2d9, +0x0001a2d5, +0x0001a2d2, +0x0001a2d1, +0x0001a2cd, +0x0001a2ca, +0x0001a2c8, +0x0001a2c5, +0x0001a2c3, +0x0001a2c0, +0x0001a2bd, +0x0001a2bb, +0x0001a2b8, +0x0001a2b5, +0x0001a2b3, +0x0001a2b0, +0x0001a2ad, +0x0001a2ab, +0x0001a2a8, +0x0001a2a4, +0x0001a2a3, +0x0001a29f, +0x0001a29e, +0x0001a29b, +0x0001a297, +0x0001a296, +0x0001a292, +0x0001a28f, +0x0001a28d, +0x0001a28a, +0x0001a287, +0x0001a285, +0x0001a282, +0x0001a280, +0x0001a27d, +0x0001a27a, +0x0001a278, +0x0001a275, +0x0001a272, +0x0001a270, +0x0001a26d, +0x0001a269, +0x0001a268, +0x0001a265, +0x0001a263, +0x0001a260, +0x0001a25c, +0x0001a25b, +0x0001a257, +0x0001a254, +0x0001a253, +0x0001a24f, +0x0001a24c, +0x0001a24a, +0x0001a247, +0x0001a245, +0x0001a242, +0x0001a23f, +0x0001a23d, +0x0001a23a, +0x0001a237, +0x0001a235, +0x0001a232, +0x0001a22f, +0x0001a22d, +0x0001a22a, +0x0001a228, +0x0001a225, +0x0001a221, +0x0001a220, +0x0001a21c, +0x0001a219, +0x0001a217, +0x0001a215, +0x0001a212, +0x0001a20e, +0x0001a20d, +0x0001a20a, +0x0001a206, +0x0001a205, +0x0001a201, +0x0001a200, +0x0001a1fc, +0x0001a1f9, +0x0001a1f8, +0x0001a1f4, +0x0001a1f1, +0x0001a1ef, +0x0001a1ec, +0x0001a1eb, +0x0001a1e7, +0x0001a1e4, +0x0001a1e2, +0x0001a1df, +0x0001a1dc, +0x0001a1da, +0x0001a1d7, +0x0001a1d5, +0x0001a1d2, +0x0001a1cf, +0x0001a1cd, +0x0001a1ca, +0x0001a1c7, +0x0001a1c5, +0x0001a1c2, +0x0001a1bf, +0x0001a1bd, +0x0001a1ba, +0x0001a1b8, +0x0001a1b5, +0x0001a1b2, +0x0001a1b0, +0x0001a1ad, +0x0001a1a9, +0x0001a1a8, +0x0001a1a5, +0x0001a1a3, +0x0001a1a0, +0x0001a19c, +0x0001a19b, +0x0001a197, +0x0001a194, +0x0001a193, +0x0001a18f, +0x0001a18e, +0x0001a18a, +0x0001a187, +0x0001a186, +0x0001a182, +0x0001a17f, +0x0001a17d, +0x0001a17a, +0x0001a179, +0x0001a175, +0x0001a172, +0x0001a170, +0x0001a16d, +0x0001a16a, +0x0001a168, +0x0001a165, +0x0001a162, +0x0001a160, +0x0001a15d, +0x0001a15b, +0x0001a158, +0x0001a155, +0x0001a153, +0x0001a150, +0x0001a14d, +0x0001a14b, +0x0001a148, +0x0001a146, +0x0001a143, +0x0001a140, +0x0001a13e, +0x0001a13b, +0x0001a137, +0x0001a136, +0x0001a132, +0x0001a131, +0x0001a12e, +0x0001a12a, +0x0001a129, +0x0001a125, +0x0001a122, +0x0001a121, +0x0001a11d, +0x0001a11c, +0x0001a118, +0x0001a115, +0x0001a114, +0x0001a110, +0x0001a10d, +0x0001a10b, +0x0001a108, +0x0001a105, +0x0001a103, +0x0001a100, +0x0001a0fe, +0x0001a0fb, +0x0001a0f8, +0x0001a0f6, +0x0001a0f3, +0x0001a0f0, +0x0001a0ee, +0x0001a0eb, +0x0001a0e9, +0x0001a0e6, +0x0001a0e3, +0x0001a0e1, +0x0001a0de, +0x0001a0db, +0x0001a0d9, +0x0001a0d6, +0x0001a0d4, +0x0001a0d1, +0x0001a0ce, +0x0001a0cc, +0x0001a0c9, +0x0001a0c5, +0x0001a0c3, +0x0001a0c0, +0x0001a0be, +0x0001a0bb, +0x0001a0b9, +0x0001a0b6, +0x0001a0b3, +0x0001a0b1, +0x0001a0ae, +0x0001a0ab, +0x0001a0a9, +0x0001a0a6, +0x0001a0a4, +0x0001a0a1, +0x0001a09e, +0x0001a09c, +0x0001a099, +0x0001a096, +0x0001a094, +0x0001a091, +0x0001a08f, +0x0001a08c, +0x0001a089, +0x0001a087, +0x0001a084, +0x0001a080, +0x0001a07f, +0x0001a07c, +0x0001a07a, +0x0001a077, +0x0001a073, +0x0001a072, +0x0001a06f, +0x0001a06b, +0x0001a06a, +0x0001a066, +0x0001a065, +0x0001a062, +0x0001a05e, +0x0001a05d, +0x0001a059, +0x0001a056, +0x0001a055, +0x0001a051, +0x0001a050, +0x0001a04c, +0x0001a049, +0x0001a048, +0x0001a044, +0x0001a041, +0x0001a03f, +0x0001a03c, +0x0001a03b, +0x0001a037, +0x0001a034, +0x0001a032, +0x0001a02f, +0x0001a02c, +0x0001a02a, +0x0001a027, +0x0001a025, +0x0001a022, +0x0001a01f, +0x0001a01d, +0x0001a01a, +0x0001a017, +0x0001a015, +0x0001a012, +0x0001a010, +0x0001a00d, +0x0001a00a, +0x0001a008, +0x0001a005, +0x0001a002, +0x0001a000, +0x00019ffd, +0x00019ffb, +0x00019ff8, +0x00019ff5, +0x00019ff3, +0x00019ff0, +0x00019fed, +0x00019feb, +0x00019fe8, +0x00019fe6, +0x00019fe3, +0x00019fe0, +0x00019fde, +0x00019fdb, +0x00019fd7, +0x00019fd6, +0x00019fd3, +0x00019fd1, +0x00019fce, +0x00019fca, +0x00019fc9, +0x00019fc6, +0x00019fc2, +0x00019fc1, +0x00019fbd, +0x00019fbc, +0x00019fb9, +0x00019fb5, +0x00019fb4, +0x00019fb0, +0x00019fad, +0x00019fac, +0x00019fa8, +0x00019fa7, +0x00019fa3, +0x00019fa0, +0x00019f9f, +0x00019f9b, +0x00019f98, +0x00019f96, +0x00019f93, +0x00019f92, +0x00019f8e, +0x00019f8b, +0x00019f89, +0x00019f86, +0x00019f83, +0x00019f81, +0x00019f7e, +0x00019f7c, +0x00019f79, +0x00019f76, +0x00019f74, +0x00019f71, +0x00019f6e, +0x00019f6d, +0x00019f69, +0x00019f66, +0x00019f65, +0x00019f61, +0x00019f5e, +0x00019f5c, +0x00019f59, +0x00019f58, +0x00019f54, +0x00019f51, +0x00019f4f, +0x00019f4c, +0x00019f49, +0x00019f47, +0x00019f44, +0x00019f42, +0x00019f3f, +0x00019f3c, +0x00019f3a, +0x00019f37, +0x00019f34, +0x00019f32, +0x00019f2f, +0x00019f2d, +0x00019f2a, +0x00019f27, +0x00019f25, +0x00019f22, +0x00019f1f, +0x00019f1d, +0x00019f1a, +0x00019f18, +0x00019f15, +0x00019f12, +0x00019f10, +0x00019f0d, +0x00019f0b, +0x00019f08, +0x00019f05, +0x00019f03, +0x00019f00, +0x00019efd, +0x00019efb, +0x00019ef8, +0x00019ef6, +0x00019ef3, +0x00019ef0, +0x00019eee, +0x00019eeb, +0x00019ee8, +0x00019ee6, +0x00019ee3, +0x00019ee1, +0x00019ede, +0x00019edb, +0x00019ed9, +0x00019ed6, +0x00019ed3, +0x00019ed1, +0x00019ece, +0x00019ecc, +0x00019ec9, +0x00019ec6, +0x00019ec4, +0x00019ec1, +0x00019ebf, +0x00019ebc, +0x00019eb9, +0x00019eb7, +0x00019eb4, +0x00019eb1, +0x00019eaf, +0x00019eac, +0x00019eaa, +0x00019ea7, +0x00019ea4, +0x00019ea2, +0x00019e9f, +0x00019e9b, +0x00019e9a, +0x00019e97, +0x00019e95, +0x00019e92, +0x00019e8f, +0x00019e8d, +0x00019e8a, +0x00019e86, +0x00019e85, +0x00019e82, +0x00019e80, +0x00019e7d, +0x00019e79, +0x00019e78, +0x00019e75, +0x00019e73, +0x00019e70, +0x00019e6c, +0x00019e6b, +0x00019e68, +0x00019e64, +0x00019e63, +0x00019e60, +0x00019e5e, +0x00019e5b, +0x00019e57, +0x00019e56, +0x00019e53, +0x00019e4f, +0x00019e4e, +0x00019e4a, +0x00019e49, +0x00019e46, +0x00019e42, +0x00019e41, +0x00019e3d, +0x00019e3a, +0x00019e39, +0x00019e35, +0x00019e34, +0x00019e31, +0x00019e2d, +0x00019e2c, +0x00019e28, +0x00019e25, +0x00019e24, +0x00019e21, +0x00019e1e, +0x00019e1c, +0x00019e19, +0x00019e15, +0x00019e14, +0x00019e11, +0x00019e0d, +0x00019e0c, +0x00019e09, +0x00019e07, +0x00019e04, +0x00019e01, +0x00019dff, +0x00019dfc, +0x00019dfa, +0x00019df7, +0x00019df4, +0x00019df2, +0x00019def, +0x00019dec, +0x00019dea, +0x00019de7, +0x00019de5, +0x00019de2, +0x00019ddf, +0x00019ddd, +0x00019dda, +0x00019dd8, +0x00019dd5, +0x00019dd2, +0x00019dd0, +0x00019dcd, +0x00019dcb, +0x00019dc8, +0x00019dc5, +0x00019dc3, +0x00019dc0, +0x00019dbd, +0x00019dbb, +0x00019db8, +0x00019db6, +0x00019db3, +0x00019db0, +0x00019dae, +0x00019dab, +0x00019da9, +0x00019da6, +0x00019da3, +0x00019da1, +0x00019d9e, +0x00019d9b, +0x00019d99, +0x00019d96, +0x00019d94, +0x00019d91, +0x00019d8e, +0x00019d8c, +0x00019d89, +0x00019d88, +0x00019d84, +0x00019d81, +0x00019d7f, +0x00019d7c, +0x00019d7b, +0x00019d77, +0x00019d74, +0x00019d73, +0x00019d6f, +0x00019d6c, +0x00019d6a, +0x00019d67, +0x00019d66, +0x00019d62, +0x00019d5f, +0x00019d5e, +0x00019d5a, +0x00019d59, +0x00019d56, +0x00019d52, +0x00019d51, +0x00019d4d, +0x00019d4a, +0x00019d49, +0x00019d45, +0x00019d44, +0x00019d41, +0x00019d3d, +0x00019d3c, +0x00019d38, +0x00019d37, +0x00019d34, +0x00019d30, +0x00019d2f, +0x00019d2c, +0x00019d28, +0x00019d27, +0x00019d23, +0x00019d22, +0x00019d1f, +0x00019d1b, +0x00019d1a, +0x00019d17, +0x00019d15, +0x00019d12, +0x00019d0f, +0x00019d0d, +0x00019d0a, +0x00019d08, +0x00019d05, +0x00019d02, +0x00019d00, +0x00019cfd, +0x00019cfa, +0x00019cf8, +0x00019cf5, +0x00019cf3, +0x00019cf0, +0x00019ced, +0x00019ceb, +0x00019ce8, +0x00019ce6, +0x00019ce3, +0x00019ce0, +0x00019cde, +0x00019cdb, +0x00019cd8, +0x00019cd6, +0x00019cd3, +0x00019cd0, +0x00019cce, +0x00019ccb, +0x00019cc9, +0x00019cc6, +0x00019cc3, +0x00019cc1, +0x00019cbe, +0x00019cbc, +0x00019cb9, +0x00019cb6, +0x00019cb4, +0x00019cb1, +0x00019cae, +0x00019cac, +0x00019ca9, +0x00019ca7, +0x00019ca4, +0x00019ca1, +0x00019c9f, +0x00019c9c, +0x00019c9b, +0x00019c97, +0x00019c94, +0x00019c92, +0x00019c8f, +0x00019c8e, +0x00019c8a, +0x00019c87, +0x00019c86, +0x00019c82, +0x00019c81, +0x00019c7e, +0x00019c7a, +0x00019c79, +0x00019c75, +0x00019c72, +0x00019c71, +0x00019c6d, +0x00019c6c, +0x00019c69, +0x00019c65, +0x00019c64, +0x00019c61, +0x00019c5f, +0x00019c5c, +0x00019c59, +0x00019c57, +0x00019c54, +0x00019c52, +0x00019c4f, +0x00019c4c, +0x00019c4a, +0x00019c47, +0x00019c44, +0x00019c42, +0x00019c3f, +0x00019c3d, +0x00019c3a, +0x00019c37, +0x00019c35, +0x00019c32, +0x00019c30, +0x00019c2d, +0x00019c2a, +0x00019c28, +0x00019c25, +0x00019c23, +0x00019c20, +0x00019c1d, +0x00019c1b, +0x00019c18, +0x00019c17, +0x00019c13, +0x00019c10, +0x00019c0e, +0x00019c0b, +0x00019c08, +0x00019c06, +0x00019c03, +0x00019c02, +0x00019bfe, +0x00019bfb, +0x00019bfa, +0x00019bf6, +0x00019bf5, +0x00019bf2, +0x00019bee, +0x00019bed, +0x00019be9, +0x00019be8, +0x00019be5, +0x00019be1, +0x00019be0, +0x00019bdd, +0x00019bdb, +0x00019bd8, +0x00019bd5, +0x00019bd3, +0x00019bd0, +0x00019bcd, +0x00019bcb, +0x00019bc8, +0x00019bc6, +0x00019bc3, +0x00019bc0, +0x00019bbe, +0x00019bbb, +0x00019bb9, +0x00019bb6, +0x00019bb3, +0x00019bb1, +0x00019bae, +0x00019bac, +0x00019ba9, +0x00019ba6, +0x00019ba4, +0x00019ba1, +0x00019b9e, +0x00019b9c, +0x00019b99, +0x00019b97, +0x00019b94, +0x00019b91, +0x00019b8f, +0x00019b8c, +0x00019b8b, +0x00019b87, +0x00019b85, +0x00019b82, +0x00019b7f, +0x00019b7d, +0x00019b7a, +0x00019b78, +0x00019b75, +0x00019b72, +0x00019b70, +0x00019b6d, +0x00019b6c, +0x00019b68, +0x00019b65, +0x00019b64, +0x00019b60, +0x00019b5f, +0x00019b5c, +0x00019b58, +0x00019b57, +0x00019b53, +0x00019b52, +0x00019b4f, +0x00019b4b, +0x00019b4a, +0x00019b47, +0x00019b45, +0x00019b42, +0x00019b3f, +0x00019b3d, +0x00019b3a, +0x00019b37, +0x00019b35, +0x00019b32, +0x00019b30, +0x00019b2d, +0x00019b2a, +0x00019b28, +0x00019b25, +0x00019b23, +0x00019b20, +0x00019b1d, +0x00019b1b, +0x00019b18, +0x00019b16, +0x00019b13, +0x00019b10, +0x00019b0e, +0x00019b0b, +0x00019b0a, +0x00019b06, +0x00019b03, +0x00019b02, +0x00019afe, +0x00019afd, +0x00019afa, +0x00019af6, +0x00019af5, +0x00019af2, +0x00019af0, +0x00019aed, +0x00019aea, +0x00019ae8, +0x00019ae5, +0x00019ae3, +0x00019ae0, +0x00019add, +0x00019adb, +0x00019ad8, +0x00019ad5, +0x00019ad3, +0x00019ad0, +0x00019ace, +0x00019acb, +0x00019ac8, +0x00019ac6, +0x00019ac3, +0x00019ac1, +0x00019abe, +0x00019abb, +0x00019ab9, +0x00019ab6, +0x00019ab5, +0x00019ab1, +0x00019aae, +0x00019aad, +0x00019aa9, +0x00019aa8, +0x00019aa4, +0x00019aa1, +0x00019aa0, +0x00019a9c, +0x00019a9b, +0x00019a98, +0x00019a94, +0x00019a93, +0x00019a90, +0x00019a8e, +0x00019a8b, +0x00019a88, +0x00019a86, +0x00019a83, +0x00019a80, +0x00019a7e, +0x00019a7b, +0x00019a79, +0x00019a76, +0x00019a73, +0x00019a71, +0x00019a6e, +0x00019a6c, +0x00019a69, +0x00019a66, +0x00019a64, +0x00019a61, +0x00019a5f, +0x00019a5c, +0x00019a59, +0x00019a57, +0x00019a54, +0x00019a53, +0x00019a4f, +0x00019a4c, +0x00019a4b, +0x00019a47, +0x00019a46, +0x00019a43, +0x00019a3f, +0x00019a3e, +0x00019a3b, +0x00019a38, +0x00019a36, +0x00019a33, +0x00019a30, +0x00019a2e, +0x00019a2b, +0x00019a2a, +0x00019a26, +0x00019a23, +0x00019a22, +0x00019a1e, +0x00019a1d, +0x00019a1a, +0x00019a16, +0x00019a15, +0x00019a12, +0x00019a10, +0x00019a0d, +0x00019a0a, +0x00019a08, +0x00019a05, +0x00019a03, +0x00019a00, +0x000199fd, +0x000199fb, +0x000199f8, +0x000199f6, +0x000199f3, +0x000199f0, +0x000199ee, +0x000199eb, +0x000199ea, +0x000199e6, +0x000199e3, +0x000199e2, +0x000199de, +0x000199dd, +0x000199da, +0x000199d6, +0x000199d5, +0x000199d2, +0x000199d0, +0x000199cd, +0x000199ca, +0x000199c8, +0x000199c5, +0x000199c3, +0x000199c0, +0x000199bd, +0x000199bb, +0x000199b8, +0x000199b6, +0x000199b3, +0x000199b0, +0x000199ae, +0x000199ab, +0x000199aa, +0x000199a6, +0x000199a3, +0x000199a2, +0x0001999e, +0x0001999d, +0x0001999a, +0x00019996, +0x00019995, +0x00019991, +0x00019990, +0x0001998d, +0x00019989, +0x00019988, +0x00019985, +0x00019983, +0x00019980, +0x0001997d, +0x0001997b, +0x00019978, +0x00019976, +0x00019973, +0x00019970, +0x0001996e, +0x0001996b, +0x00019969, +0x00019966, +0x00019963, +0x00019961, +0x0001995e, +0x0001995d, +0x00019959, +0x00019956, +0x00019955, +0x00019951, +0x00019950, +0x0001994d, +0x00019949, +0x00019948, +0x00019945, +0x00019943, +0x00019940, +0x0001993d, +0x0001993b, +0x00019938, +0x00019936, +0x00019933, +0x00019930, +0x0001992e, +0x0001992b, +0x00019929, +0x00019926, +0x00019923, +0x00019921, +0x0001991e, +0x0001991d, +0x00019919, +0x00019916, +0x00019915, +0x00019911, +0x00019910, +0x0001990d, +0x00019909, +0x00019908, +0x00019905, +0x00019903, +0x00019900, +0x000198fd, +0x000198fb, +0x000198f8, +0x000198f5, +0x000198f2, +0x000198f1, +0x000198ed, +0x000198ec, +0x000198e9, +0x000198e6, +0x000198e4, +0x000198e1, +0x000198df, +0x000198dc, +0x000198d9, +0x000198d7, +0x000198d4, +0x000198d2, +0x000198cf, +0x000198ce, +0x000198ca, +0x000198c7, +0x000198c6, +0x000198c2, +0x000198c1, +0x000198be, +0x000198ba, +0x000198b9, +0x000198b6, +0x000198b4, +0x000198b1, +0x000198ae, +0x000198ac, +0x000198a9, +0x000198a7, +0x000198a4, +0x000198a1, +0x0001989f, +0x0001989c, +0x0001989b, +0x00019897, +0x00019894, +0x00019893, +0x0001988f, +0x0001988e, +0x0001988b, +0x00019887, +0x00019886, +0x00019883, +0x00019881, +0x0001987e, +0x0001987c, +0x00019879, +0x00019876, +0x00019874, +0x00019871, +0x00019870, +0x0001986c, +0x00019869, +0x00019868, +0x00019864, +0x00019863, +0x00019860, +0x0001985c, +0x0001985b, +0x00019858, +0x00019856, +0x00019853, +0x00019850, +0x0001984e, +0x0001984b, +0x00019849, +0x00019846, +0x00019843, +0x00019841, +0x0001983e, +0x0001983d, +0x00019839, +0x00019836, +0x00019835, +0x00019831, +0x00019830, +0x0001982d, +0x0001982b, +0x00019828, +0x00019825, +0x00019823, +0x00019820, +0x0001981e, +0x0001981b, +0x00019818, +0x00019816, +0x00019813, +0x00019812, +0x0001980e, +0x0001980b, +0x0001980a, +0x00019806, +0x00019805, +0x00019802, +0x000197fe, +0x000197fd, +0x000197fa, +0x000197f8, +0x000197f5, +0x000197f2, +0x000197f0, +0x000197ed, +0x000197eb, +0x000197e8, +0x000197e5, +0x000197e3, +0x000197e0, +0x000197df, +0x000197db, +0x000197da, +0x000197d7, +0x000197d3, +0x000197d2, +0x000197cf, +0x000197cd, +0x000197ca, +0x000197c7, +0x000197c5, +0x000197c2, +0x000197c0, +0x000197bd, +0x000197ba, +0x000197b8, +0x000197b5, +0x000197b4, +0x000197b0, +0x000197ad, +0x000197ac, +0x000197a9, +0x000197a5, +0x000197a4, +0x000197a1, +0x0001979f, +0x0001979c, +0x00019799, +0x00019797, +0x00019794, +0x00019792, +0x0001978f, +0x0001978c, +0x0001978a, +0x00019787, +0x00019786, +0x00019782, +0x00019781, +0x0001977e, +0x0001977a, +0x00019779, +0x00019776, +0x00019774, +0x00019771, +0x0001976e, +0x0001976c, +0x00019769, +0x00019767, +0x00019764, +0x00019761, +0x0001975f, +0x0001975c, +0x0001975b, +0x00019757, +0x00019756, +0x00019753, +0x0001974f, +0x0001974e, +0x0001974b, +0x00019749, +0x00019746, +0x00019743, +0x00019741, +0x0001973e, +0x0001973c, +0x00019739, +0x00019736, +0x00019734, +0x00019731, +0x00019730, +0x0001972d, +0x00019729, +0x00019728, +0x00019725, +0x00019723, +0x00019720, +0x0001971e, +0x0001971b, +0x00019718, +0x00019716, +0x00019713, +0x00019711, +0x0001970e, +0x0001970b, +0x0001970a, +0x00019706, +0x00019705, +0x00019702, +0x000196fe, +0x000196fd, +0x000196fa, +0x000196f8, +0x000196f5, +0x000196f3, +0x000196f0, +0x000196ed, +0x000196eb, +0x000196e8, +0x000196e7, +0x000196e3, +0x000196e0, +0x000196df, +0x000196db, +0x000196da, +0x000196d7, +0x000196d3, +0x000196d2, +0x000196cf, +0x000196cd, +0x000196ca, +0x000196c7, +0x000196c5, +0x000196c2, +0x000196c0, +0x000196bd, +0x000196bc, +0x000196b8, +0x000196b5, +0x000196b4, +0x000196b1, +0x000196af, +0x000196ac, +0x000196a9, +0x000196a7, +0x000196a4, +0x000196a2, +0x0001969f, +0x0001969c, +0x0001969a, +0x00019697, +0x00019695, +0x00019692, +0x00019691, +0x0001968e, +0x0001968a, +0x00019689, +0x00019686, +0x00019684, +0x00019681, +0x0001967e, +0x0001967c, +0x00019679, +0x00019677, +0x00019674, +0x00019671, +0x0001966f, +0x0001966d, +0x0001966a, +0x00019667, +0x00019666, +0x00019662, +0x00019661, +0x0001965e, +0x0001965a, +0x00019659, +0x00019656, +0x00019654, +0x00019651, +0x0001964e, +0x0001964c, +0x00019649, +0x00019647, +0x00019644, +0x00019643, +0x0001963f, +0x0001963c, +0x0001963b, +0x00019638, +0x00019636, +0x00019633, +0x00019630, +0x0001962e, +0x0001962b, +0x00019629, +0x00019626, +0x00019624, +0x00019621, +0x0001961e, +0x0001961d, +0x00019619, +0x00019618, +0x00019615, +0x00019611, +0x00019610, +0x0001960d, +0x0001960b, +0x00019608, +0x00019605, +0x00019603, +0x00019600, +0x000195fe, +0x000195fb, +0x000195fa, +0x000195f6, +0x000195f3, +0x000195f2, +0x000195ef, +0x000195ed, +0x000195ea, +0x000195e7, +0x000195e5, +0x000195e2, +0x000195e0, +0x000195dd, +0x000195dc, +0x000195d8, +0x000195d5, +0x000195d4, +0x000195d0, +0x000195cf, +0x000195cc, +0x000195c8, +0x000195c7, +0x000195c4, +0x000195c2, +0x000195bf, +0x000195bc, +0x000195ba, +0x000195b7, +0x000195b5, +0x000195b2, +0x000195b1, +0x000195ae, +0x000195aa, +0x000195a9, +0x000195a6, +0x000195a4, +0x000195a1, +0x0001959e, +0x0001959c, +0x00019599, +0x00019597, +0x00019594, +0x00019593, +0x0001958f, +0x0001958c, +0x0001958b, +0x00019587, +0x00019586, +0x00019583, +0x00019580, +0x0001957e, +0x0001957b, +0x00019579, +0x00019576, +0x00019573, +0x00019571, +0x0001956e, +0x0001956d, +0x00019569, +0x00019568, +0x00019565, +0x00019561, +0x00019560, +0x0001955d, +0x0001955b, +0x00019558, +0x00019555, +0x00019553, +0x00019550, +0x0001954e, +0x0001954b, +0x0001954a, +0x00019546, +0x00019543, +0x00019542, +0x0001953f, +0x0001953d, +0x0001953a, +0x00019537, +0x00019535, +0x00019532, +0x00019530, +0x0001952d, +0x0001952b, +0x00019529, +0x00019526, +0x00019524, +0x00019521, +0x0001951e, +0x0001951c, +0x00019519, +0x00019518, +0x00019515, +0x00019511, +0x00019510, +0x0001950d, +0x0001950b, +0x00019508, +0x00019506, +0x00019503, +0x00019500, +0x000194fe, +0x000194fb, +0x000194fa, +0x000194f7, +0x000194f3, +0x000194f2, +0x000194ef, +0x000194ed, +0x000194ea, +0x000194e8, +0x000194e5, +0x000194e2, +0x000194e0, +0x000194dd, +0x000194dc, +0x000194d8, +0x000194d5, +0x000194d4, +0x000194d1, +0x000194cf, +0x000194cc, +0x000194ca, +0x000194c7, +0x000194c4, +0x000194c2, +0x000194bf, +0x000194be, +0x000194ba, +0x000194b7, +0x000194b6, +0x000194b2, +0x000194b1, +0x000194ae, +0x000194ac, +0x000194a9, +0x000194a6, +0x000194a4, +0x000194a1, +0x0001949f, +0x0001949c, +0x00019499, +0x00019498, +0x00019494, +0x00019493, +0x00019490, +0x0001948e, +0x0001948b, +0x00019488, +0x00019486, +0x00019483, +0x00019481, +0x0001947e, +0x0001947d, +0x0001947a, +0x00019476, +0x00019475, +0x00019472, +0x00019470, +0x0001946d, +0x0001946a, +0x00019468, +0x00019465, +0x00019463, +0x00019460, +0x0001945f, +0x0001945b, +0x00019458, +0x00019457, +0x00019454, +0x00019452, +0x0001944f, +0x0001944c, +0x0001944a, +0x00019447, +0x00019445, +0x00019442, +0x00019441, +0x0001943d, +0x0001943a, +0x00019439, +0x00019436, +0x00019434, +0x00019431, +0x0001942e, +0x0001942c, +0x00019429, +0x00019427, +0x00019424, +0x00019423, +0x0001941f, +0x0001941c, +0x0001941b, +0x00019417, +0x00019416, +0x00019413, +0x00019410, +0x0001940e, +0x0001940b, +0x00019409, +0x00019406, +0x00019404, +0x00019401, +0x000193fe, +0x000193fd, +0x000193f9, +0x000193f8, +0x000193f5, +0x000193f1, +0x000193f0, +0x000193ed, +0x000193eb, +0x000193e9, +0x000193e6, +0x000193e4, +0x000193e1, +0x000193de, +0x000193dc, +0x000193d9, +0x000193d8, +0x000193d5, +0x000193d3, +0x000193d0, +0x000193cd, +0x000193cb, +0x000193c8, +0x000193c6, +0x000193c3, +0x000193c0, +0x000193be, +0x000193bb, +0x000193ba, +0x000193b7, +0x000193b5, +0x000193b2, +0x000193af, +0x000193ad, +0x000193aa, +0x000193a8, +0x000193a5, +0x000193a4, +0x000193a1, +0x0001939d, +0x0001939c, +0x00019399, +0x00019397, +0x00019394, +0x00019392, +0x0001938f, +0x0001938c, +0x0001938b, +0x00019387, +0x00019386, +0x00019383, +0x00019381, +0x0001937e, +0x0001937b, +0x00019379, +0x00019376, +0x00019374, +0x00019371, +0x00019370, +0x0001936d, +0x00019369, +0x00019368, +0x00019365, +0x00019363, +0x00019360, +0x0001935e, +0x0001935b, +0x00019358, +0x00019357, +0x00019353, +0x00019352, +0x0001934f, +0x0001934d, +0x0001934a, +0x00019347, +0x00019345, +0x00019342, +0x00019341, +0x0001933d, +0x0001933a, +0x00019339, +0x00019336, +0x00019334, +0x00019331, +0x0001932f, +0x0001932c, +0x00019329, +0x00019327, +0x00019324, +0x00019323, +0x0001931f, +0x0001931e, +0x0001931b, +0x00019318, +0x00019316, +0x00019313, +0x00019311, +0x0001930e, +0x0001930d, +0x00019309, +0x00019306, +0x00019305, +0x00019302, +0x00019300, +0x000192fd, +0x000192fb, +0x000192f8, +0x000192f5, +0x000192f3, +0x000192f0, +0x000192ef, +0x000192ec, +0x000192ea, +0x000192e7, +0x000192e4, +0x000192e2, +0x000192df, +0x000192dd, +0x000192da, +0x000192d9, +0x000192d5, +0x000192d2, +0x000192d1, +0x000192ce, +0x000192cc, +0x000192c9, +0x000192c6, +0x000192c4, +0x000192c1, +0x000192bf, +0x000192bc, +0x000192bb, +0x000192b8, +0x000192b4, +0x000192b3, +0x000192b0, +0x000192ae, +0x000192ab, +0x000192a8, +0x000192a6, +0x000192a3, +0x000192a2, +0x0001929f, +0x0001929d, +0x0001929a, +0x00019297, +0x00019295, +0x00019292, +0x00019290, +0x0001928d, +0x0001928c, +0x00019289, +0x00019285, +0x00019284, +0x00019281, +0x0001927f, +0x0001927c, +0x0001927a, +0x00019277, +0x00019274, +0x00019273, +0x0001926f, +0x0001926e, +0x0001926b, +0x00019269, +0x00019266, +0x00019263, +0x00019261, +0x0001925e, +0x0001925d, +0x0001925a, +0x00019258, +0x00019255, +0x00019252, +0x00019250, +0x0001924d, +0x0001924b, +0x00019248, +0x00019247, +0x00019244, +0x00019240, +0x0001923f, +0x0001923c, +0x0001923a, +0x00019237, +0x00019235, +0x00019232, +0x0001922f, +0x0001922e, +0x0001922a, +0x00019229, +0x00019226, +0x00019224, +0x00019221, +0x0001921e, +0x0001921c, +0x00019219, +0x00019218, +0x00019214, +0x00019213, +0x00019210, +0x0001920d, +0x0001920b, +0x00019208, +0x00019206, +0x00019203, +0x00019202, +0x000191fe, +0x000191fb, +0x000191fa, +0x000191f7, +0x000191f5, +0x000191f2, +0x000191f0, +0x000191ed, +0x000191ea, +0x000191e8, +0x000191e5, +0x000191e4, +0x000191e1, +0x000191df, +0x000191dc, +0x000191d9, +0x000191d7, +0x000191d4, +0x000191d2, +0x000191cf, +0x000191ce, +0x000191cb, +0x000191c7, +0x000191c6, +0x000191c3, +0x000191c1, +0x000191be, +0x000191bc, +0x000191b9, +0x000191b6, +0x000191b5, +0x000191b1, +0x000191b0, +0x000191ad, +0x000191ab, +0x000191a8, +0x000191a5, +0x000191a3, +0x000191a0, +0x0001919f, +0x0001919c, +0x0001919a, +0x00019197, +0x00019194, +0x00019192, +0x0001918f, +0x0001918d, +0x0001918a, +0x00019189, +0x00019186, +0x00019182, +0x00019181, +0x0001917e, +0x0001917c, +0x00019179, +0x00019177, +0x00019174, +0x00019172, +0x0001916f, +0x0001916e, +0x0001916b, +0x00019167, +0x00019166, +0x00019163, +0x00019161, +0x0001915e, +0x0001915c, +0x00019159, +0x00019158, +0x00019155, +0x00019151, +0x00019150, +0x0001914d, +0x0001914b, +0x00019148, +0x00019146, +0x00019143, +0x00019140, +0x0001913f, +0x0001913c, +0x0001913a, +0x00019137, +0x00019135, +0x00019132, +0x0001912f, +0x0001912d, +0x0001912a, +0x00019129, +0x00019126, +0x00019124, +0x00019121, +0x0001911e, +0x0001911c, +0x00019119, +0x00019117, +0x00019114, +0x00019113, +0x00019110, +0x0001910e, +0x0001910b, +0x00019108, +0x00019106, +0x00019103, +0x00019102, +0x000190fe, +0x000190fd, +0x000190fa, +0x000190f7, +0x000190f5, +0x000190f2, +0x000190f0, +0x000190ed, +0x000190ec, +0x000190e9, +0x000190e5, +0x000190e4, +0x000190e1, +0x000190df, +0x000190dc, +0x000190da, +0x000190d7, +0x000190d6, +0x000190d3, +0x000190cf, +0x000190ce, +0x000190cb, +0x000190c9, +0x000190c6, +0x000190c4, +0x000190c1, +0x000190be, +0x000190bd, +0x000190ba, +0x000190b8, +0x000190b5, +0x000190b3, +0x000190b0, +0x000190ad, +0x000190ab, +0x000190a8, +0x000190a7, +0x000190a4, +0x000190a2, +0x0001909f, +0x0001909c, +0x0001909a, +0x00019097, +0x00019095, +0x00019092, +0x00019091, +0x0001908e, +0x0001908c, +0x00019089, +0x00019086, +0x00019084, +0x00019081, +0x00019080, +0x0001907c, +0x0001907b, +0x00019078, +0x00019075, +0x00019073, +0x00019070, +0x0001906e, +0x0001906b, +0x0001906a, +0x00019066, +0x00019063, +0x00019062, +0x0001905f, +0x0001905d, +0x0001905a, +0x00019058, +0x00019055, +0x00019052, +0x00019051, +0x0001904d, +0x0001904c, +0x00019049, +0x00019047, +0x00019044, +0x00019042, +0x0001903f, +0x0001903c, +0x0001903b, +0x00019038, +0x00019035, +0x00019034, +0x00019030, +0x0001902f, +0x0001902c, +0x0001902a, +0x00019027, +0x00019026, +0x00019022, +0x0001901f, +0x0001901e, +0x0001901b, +0x00019019, +0x00019016, +0x00019014, +0x00019011, +0x0001900e, +0x0001900d, +0x00019009, +0x00019008, +0x00019005, +0x00019003, +0x00019000, +0x00018ffe, +0x00018ffb, +0x00018ff8, +0x00018ff7, +0x00018ff4, +0x00018ff2, +0x00018fef, +0x00018fed, +0x00018fea, +0x00018fe7, +0x00018fe5, +0x00018fe2, +0x00018fe1, +0x00018fde, +0x00018fdc, +0x00018fd9, +0x00018fd7, +0x00018fd4, +0x00018fd1, +0x00018fd0, +0x00018fcc, +0x00018fcb, +0x00018fc8, +0x00018fc6, +0x00018fc3, +0x00018fc0, +0x00018fbe, +0x00018fbb, +0x00018fba, +0x00018fb7, +0x00018fb5, +0x00018fb2, +0x00018fb0, +0x00018fad, +0x00018faa, +0x00018fa9, +0x00018fa5, +0x00018fa4, +0x00018fa1, +0x00018f9f, +0x00018f9c, +0x00018f99, +0x00018f97, +0x00018f94, +0x00018f93, +0x00018f90, +0x00018f8e, +0x00018f8b, +0x00018f89, +0x00018f86, +0x00018f83, +0x00018f81, +0x00018f7e, +0x00018f7d, +0x00018f7a, +0x00018f78, +0x00018f75, +0x00018f72, +0x00018f70, +0x00018f6d, +0x00018f6c, +0x00018f68, +0x00018f67, +0x00018f64, +0x00018f62, +0x00018f5f, +0x00018f5c, +0x00018f5a, +0x00018f57, +0x00018f56, +0x00018f53, +0x00018f51, +0x00018f4e, +0x00018f4b, +0x00018f49, +0x00018f46, +0x00018f45, +0x00018f41, +0x00018f40, +0x00018f3d, +0x00018f3b, +0x00018f38, +0x00018f35, +0x00018f33, +0x00018f30, +0x00018f2f, +0x00018f2c, +0x00018f2a, +0x00018f27, +0x00018f24, +0x00018f22, +0x00018f1f, +0x00018f1d, +0x00018f1a, +0x00018f19, +0x00018f16, +0x00018f14, +0x00018f11, +0x00018f0e, +0x00018f0c, +0x00018f09, +0x00018f08, +0x00018f04, +0x00018f03, +0x00018f01, +0x00018efd, +0x00018efa, +0x00018ef9, +0x00018ef6, +0x00018ef4, +0x00018ef1, +0x00018eef, +0x00018eec, +0x00018eeb, +0x00018ee8, +0x00018ee5, +0x00018ee3, +0x00018ee0, +0x00018ede, +0x00018edb, +0x00018eda, +0x00018ed7, +0x00018ed5, +0x00018ed2, +0x00018ecf, +0x00018ecd, +0x00018eca, +0x00018ec9, +0x00018ec5, +0x00018ec4, +0x00018ec1, +0x00018ebf, +0x00018ebc, +0x00018eb9, +0x00018eb7, +0x00018eb4, +0x00018eb3, +0x00018eb0, +0x00018eae, +0x00018eab, +0x00018ea9, +0x00018ea6, +0x00018ea3, +0x00018ea2, +0x00018e9f, +0x00018e9d, +0x00018e9a, +0x00018e98, +0x00018e95, +0x00018e94, +0x00018e91, +0x00018e8d, +0x00018e8c, +0x00018e89, +0x00018e87, +0x00018e84, +0x00018e83, +0x00018e7f, +0x00018e7e, +0x00018e7b, +0x00018e78, +0x00018e76, +0x00018e73, +0x00018e71, +0x00018e6e, +0x00018e6d, +0x00018e6a, +0x00018e68, +0x00018e65, +0x00018e62, +0x00018e60, +0x00018e5d, +0x00018e5c, +0x00018e59, +0x00018e57, +0x00018e54, +0x00018e52, +0x00018e4f, +0x00018e4c, +0x00018e4b, +0x00018e48, +0x00018e46, +0x00018e43, +0x00018e41, +0x00018e3e, +0x00018e3d, +0x00018e3a, +0x00018e36, +0x00018e35, +0x00018e32, +0x00018e30, +0x00018e2d, +0x00018e2c, +0x00018e28, +0x00018e27, +0x00018e24, +0x00018e21, +0x00018e1f, +0x00018e1c, +0x00018e1a, +0x00018e17, +0x00018e16, +0x00018e13, +0x00018e11, +0x00018e0e, +0x00018e0b, +0x00018e09, +0x00018e06, +0x00018e05, +0x00018e02, +0x00018e00, +0x00018dfd, +0x00018dfb, +0x00018df8, +0x00018df5, +0x00018df4, +0x00018df0, +0x00018def, +0x00018dec, +0x00018dea, +0x00018de7, +0x00018de6, +0x00018de2, +0x00018ddf, +0x00018dde, +0x00018ddb, +0x00018dd9, +0x00018dd6, +0x00018dd4, +0x00018dd1, +0x00018dd0, +0x00018dcd, +0x00018dca, +0x00018dc8, +0x00018dc5, +0x00018dc3, +0x00018dc0, +0x00018dbd, +0x00018dbc, +0x00018db9, +0x00018db7, +0x00018db4, +0x00018db2, +0x00018daf, +0x00018dae, +0x00018dab, +0x00018da9, +0x00018da6, +0x00018da3, +0x00018da1, +0x00018d9e, +0x00018d9d, +0x00018d9a, +0x00018d98, +0x00018d95, +0x00018d93, +0x00018d90, +0x00018d8d, +0x00018d8c, +0x00018d88, +0x00018d87, +0x00018d84, +0x00018d82, +0x00018d7f, +0x00018d7e, +0x00018d7b, +0x00018d79, +0x00018d76, +0x00018d73, +0x00018d71, +0x00018d6e, +0x00018d6d, +0x00018d69, +0x00018d68, +0x00018d65, +0x00018d63, +0x00018d60, +0x00018d5d, +0x00018d5b, +0x00018d58, +0x00018d57, +0x00018d54, +0x00018d52, +0x00018d4f, +0x00018d4e, +0x00018d4a, +0x00018d49, +0x00018d46, +0x00018d43, +0x00018d41, +0x00018d3e, +0x00018d3c, +0x00018d39, +0x00018d38, +0x00018d35, +0x00018d33, +0x00018d30, +0x00018d2d, +0x00018d2b, +0x00018d28, +0x00018d27, +0x00018d24, +0x00018d22, +0x00018d1f, +0x00018d1d, +0x00018d1a, +0x00018d17, +0x00018d16, +0x00018d13, +0x00018d11, +0x00018d0e, +0x00018d0c, +0x00018d09, +0x00018d08, +0x00018d05, +0x00018d03, +0x00018d00, +0x00018cfd, +0x00018cfb, +0x00018cf8, +0x00018cf7, +0x00018cf4, +0x00018cf2, +0x00018cef, +0x00018ced, +0x00018cea, +0x00018ce7, +0x00018ce6, +0x00018ce3, +0x00018ce1, +0x00018cde, +0x00018cdc, +0x00018cd9, +0x00018cd8, +0x00018cd5, +0x00018cd3, +0x00018cd0, +0x00018ccd, +0x00018ccb, +0x00018cc8, +0x00018cc7, +0x00018cc4, +0x00018cc2, +0x00018cbf, +0x00018cbd, +0x00018cba, +0x00018cb7, +0x00018cb6, +0x00018cb2, +0x00018cb1, +0x00018cae, +0x00018cac, +0x00018ca9, +0x00018ca8, +0x00018ca5, +0x00018ca3, +0x00018ca0, +0x00018c9d, +0x00018c9b, +0x00018c98, +0x00018c96, +0x00018c93, +0x00018c91, +0x00018c8e, +0x00018c8d, +0x00018c8a, +0x00018c88, +0x00018c85, +0x00018c83, +0x00018c80, +0x00018c7f, +0x00018c7c, +0x00018c79, +0x00018c77, +0x00018c74, +0x00018c72, +0x00018c6f, +0x00018c6e, +0x00018c6b, +0x00018c69, +0x00018c66, +0x00018c65, +0x00018c61, +0x00018c5e, +0x00018c5d, +0x00018c5a, +0x00018c58, +0x00018c55, +0x00018c54, +0x00018c50, +0x00018c4f, +0x00018c4c, +0x00018c4a, +0x00018c47, +0x00018c44, +0x00018c43, +0x00018c3f, +0x00018c3e, +0x00018c3b, +0x00018c39, +0x00018c36, +0x00018c35, +0x00018c32, +0x00018c2e, +0x00018c2d, +0x00018c2a, +0x00018c28, +0x00018c25, +0x00018c24, +0x00018c20, +0x00018c1f, +0x00018c1c, +0x00018c1a, +0x00018c17, +0x00018c14, +0x00018c13, +0x00018c0f, +0x00018c0e, +0x00018c0b, +0x00018c09, +0x00018c06, +0x00018c05, +0x00018c02, +0x00018c00, +0x00018bfd, +0x00018bfa, +0x00018bf8, +0x00018bf5, +0x00018bf4, +0x00018bf1, +0x00018bef, +0x00018bec, +0x00018bea, +0x00018be7, +0x00018be6, +0x00018be3, +0x00018be0, +0x00018bde, +0x00018bdb, +0x00018bd9, +0x00018bd6, +0x00018bd5, +0x00018bd2, +0x00018bd0, +0x00018bcd, +0x00018bcb, +0x00018bc8, +0x00018bc5, +0x00018bc4, +0x00018bc1, +0x00018bbf, +0x00018bbc, +0x00018bba, +0x00018bb7, +0x00018bb6, +0x00018bb3, +0x00018bb1, +0x00018bae, +0x00018bab, +0x00018ba9, +0x00018ba6, +0x00018ba5, +0x00018ba2, +0x00018ba0, +0x00018b9d, +0x00018b9b, +0x00018b98, +0x00018b95, +0x00018b94, +0x00018b91, +0x00018b8f, +0x00018b8c, +0x00018b8a, +0x00018b87, +0x00018b86, +0x00018b83, +0x00018b81, +0x00018b7e, +0x00018b7b, +0x00018b79, +0x00018b76, +0x00018b75, +0x00018b72, +0x00018b70, +0x00018b6d, +0x00018b6c, +0x00018b68, +0x00018b67, +0x00018b64, +0x00018b61, +0x00018b60, +0x00018b5d, +0x00018b5b, +0x00018b58, +0x00018b55, +0x00018b53, +0x00018b50, +0x00018b4f, +0x00018b4c, +0x00018b4a, +0x00018b47, +0x00018b45, +0x00018b42, +0x00018b41, +0x00018b3e, +0x00018b3c, +0x00018b39, +0x00018b36, +0x00018b34, +0x00018b31, +0x00018b30, +0x00018b2d, +0x00018b2b, +0x00018b28, +0x00018b27, +0x00018b23, +0x00018b22, +0x00018b1f, +0x00018b1c, +0x00018b1a, +0x00018b17, +0x00018b16, +0x00018b13, +0x00018b11, +0x00018b0e, +0x00018b0c, +0x00018b09, +0x00018b08, +0x00018b05, +0x00018b02, +0x00018b00, +0x00018afd, +0x00018afb, +0x00018af8, +0x00018af7, +0x00018af4, +0x00018af2, +0x00018aef, +0x00018aed, +0x00018aea, +0x00018ae9, +0x00018ae6, +0x00018ae3, +0x00018ae1, +0x00018ade, +0x00018add, +0x00018ad9, +0x00018ad8, +0x00018ad5, +0x00018ad3, +0x00018ad0, +0x00018acf, +0x00018acc, +0x00018ac8, +0x00018ac7, +0x00018ac4, +0x00018ac2, +0x00018abf, +0x00018abe, +0x00018abb, +0x00018ab9, +0x00018ab6, +0x00018ab4, +0x00018ab1, +0x00018aae, +0x00018aad, +0x00018aaa, +0x00018aa8, +0x00018aa5, +0x00018aa3, +0x00018aa0, +0x00018a9f, +0x00018a9c, +0x00018a9a, +0x00018a97, +0x00018a96, +0x00018a92, +0x00018a8f, +0x00018a8e, +0x00018a8b, +0x00018a89, +0x00018a86, +0x00018a85, +0x00018a81, +0x00018a80, +0x00018a7d, +0x00018a7b, +0x00018a78, +0x00018a75, +0x00018a74, +0x00018a71, +0x00018a6f, +0x00018a6c, +0x00018a6a, +0x00018a67, +0x00018a66, +0x00018a63, +0x00018a61, +0x00018a5e, +0x00018a5b, +0x00018a59, +0x00018a56, +0x00018a55, +0x00018a52, +0x00018a50, +0x00018a4d, +0x00018a4b, +0x00018a48, +0x00018a47, +0x00018a44, +0x00018a42, +0x00018a3f, +0x00018a3c, +0x00018a3b, +0x00018a37, +0x00018a36, +0x00018a34, +0x00018a31, +0x00018a2e, +0x00018a2d, +0x00018a2a, +0x00018a28, +0x00018a25, +0x00018a23, +0x00018a20, +0x00018a1f, +0x00018a1c, +0x00018a1a, +0x00018a17, +0x00018a14, +0x00018a12, +0x00018a0f, +0x00018a0e, +0x00018a0b, +0x00018a09, +0x00018a06, +0x00018a05, +0x00018a02, +0x00018a00, +0x000189fd, +0x000189fb, +0x000189f8, +0x000189f5, +0x000189f4, +0x000189f1, +0x000189ef, +0x000189ec, +0x000189ea, +0x000189e7, +0x000189e6, +0x000189e3, +0x000189e1, +0x000189de, +0x000189dd, +0x000189da, +0x000189d6, +0x000189d5, +0x000189d2, +0x000189d0, +0x000189cd, +0x000189cc, +0x000189c9, +0x000189c7, +0x000189c4, +0x000189c2, +0x000189bf, +0x000189be, +0x000189bb, +0x000189b8, +0x000189b6, +0x000189b3, +0x000189b2, +0x000189ae, +0x000189ad, +0x000189aa, +0x000189a8, +0x000189a5, +0x000189a4, +0x000189a1, +0x0001899f, +0x0001899c, +0x00018999, +0x00018997, +0x00018994, +0x00018993, +0x00018990, +0x0001898e, +0x0001898b, +0x00018989, +0x00018986, +0x00018985, +0x00018982, +0x00018980, +0x0001897d, +0x0001897a, +0x00018979, +0x00018975, +0x00018974, +0x00018971, +0x0001896f, +0x0001896c, +0x0001896b, +0x00018968, +0x00018966, +0x00018963, +0x00018961, +0x0001895e, +0x0001895b, +0x0001895a, +0x00018957, +0x00018955, +0x00018952, +0x00018951, +0x0001894d, +0x0001894c, +0x00018949, +0x00018947, +0x00018944, +0x00018943, +0x00018940, +0x0001893d, +0x0001893b, +0x00018938, +0x00018936, +0x00018933, +0x00018932, +0x0001892f, +0x0001892d, +0x0001892a, +0x00018929, +0x00018925, +0x00018924, +0x00018921, +0x0001891e, +0x0001891c, +0x00018919, +0x00018918, +0x00018915, +0x00018913, +0x00018910, +0x0001890e, +0x0001890b, +0x0001890a, +0x00018907, +0x00018904, +0x00018901, +0x00018900, +0x000188fd, +0x000188fb, +0x000188f8, +0x000188f7, +0x000188f3, +0x000188f2, +0x000188ef, +0x000188ed, +0x000188ea, +0x000188e9, +0x000188e6, +0x000188e4, +0x000188e1, +0x000188e0, +0x000188dd, +0x000188d9, +0x000188d8, +0x000188d5, +0x000188d3, +0x000188d0, +0x000188cf, +0x000188cc, +0x000188ca, +0x000188c7, +0x000188c6, +0x000188c2, +0x000188c1, +0x000188be, +0x000188bc, +0x000188b9, +0x000188b6, +0x000188b5, +0x000188b2, +0x000188b0, +0x000188ad, +0x000188ac, +0x000188a8, +0x000188a7, +0x000188a4, +0x000188a2, +0x0001889f, +0x0001889e, +0x0001889b, +0x00018899, +0x00018896, +0x00018895, +0x00018891, +0x0001888e, +0x0001888d, +0x0001888a, +0x00018888, +0x00018885, +0x00018884, +0x00018881, +0x0001887f, +0x0001887c, +0x0001887b, +0x00018877, +0x00018876, +0x00018873, +0x00018871, +0x0001886e, +0x0001886b, +0x0001886a, +0x00018867, +0x00018865, +0x00018862, +0x00018860, +0x0001885d, +0x0001885c, +0x00018859, +0x00018857, +0x00018854, +0x00018853, +0x00018850, +0x0001884e, +0x0001884b, +0x0001884a, +0x00018846, +0x00018843, +0x00018842, +0x0001883f, +0x0001883d, +0x0001883a, +0x00018839, +0x00018836, +0x00018834, +0x00018831, +0x0001882f, +0x0001882c, +0x0001882b, +0x00018828, +0x00018826, +0x00018823, +0x00018820, +0x0001881f, +0x0001881c, +0x0001881a, +0x00018817, +0x00018815, +0x00018812, +0x00018811, +0x0001880e, +0x0001880c, +0x00018809, +0x00018808, +0x00018805, +0x00018803, +0x00018800, +0x000187fe, +0x000187fb, +0x000187f8, +0x000187f7, +0x000187f4, +0x000187f2, +0x000187ef, +0x000187ee, +0x000187eb, +0x000187e9, +0x000187e6, +0x000187e4, +0x000187e1, +0x000187e0, +0x000187dd, +0x000187db, +0x000187d7, +0x000187d6, +0x000187d3, +0x000187d1, +0x000187ce, +0x000187cd, +0x000187ca, +0x000187c8, +0x000187c5, +0x000187c4, +0x000187c0, +0x000187bd, +0x000187bc, +0x000187b9, +0x000187b7, +0x000187b4, +0x000187b3, +0x000187b0, +0x000187ae, +0x000187ab, +0x000187aa, +0x000187a6, +0x000187a5, +0x000187a2, +0x000187a0, +0x0001879d, +0x0001879c, +0x00018799, +0x00018796, +0x00018794, +0x00018791, +0x00018790, +0x0001878d, +0x0001878b, +0x00018788, +0x00018786, +0x00018783, +0x00018782, +0x0001877f, +0x0001877d, +0x0001877a, +0x00018779, +0x00018776, +0x00018774, +0x00018771, +0x0001876f, +0x0001876c, +0x00018769, +0x00018768, +0x00018765, +0x00018763, +0x00018760, +0x0001875f, +0x0001875c, +0x0001875a, +0x00018757, +0x00018756, +0x00018752, +0x00018751, +0x0001874e, +0x0001874c, +0x00018749, +0x00018748, +0x00018745, +0x00018743, +0x00018740, +0x0001873d, +0x0001873c, +0x00018739, +0x00018737, +0x00018734, +0x00018732, +0x0001872f, +0x0001872e, +0x0001872b, +0x00018729, +0x00018726, +0x00018725, +0x00018722, +0x00018720, +0x0001871d, +0x0001871b, +0x00018718, +0x00018715, +0x00018714, +0x00018711, +0x0001870f, +0x0001870c, +0x0001870b, +0x00018708, +0x00018706, +0x00018703, +0x00018702, +0x000186fe, +0x000186fd, +0x000186fa, +0x000186f8, +0x000186f5, +0x000186f4, +0x000186f1, +0x000186ef, +0x000186ec, +0x000186e9, +0x000186e8, +0x000186e5, +0x000186e3, +0x000186e0, +0x000186de, +0x000186db, +0x000186da, +0x000186d7, +0x000186d5, +0x000186d2, +0x000186d1, +0x000186ce, +0x000186cc, +0x000186c9, +0x000186c7, +0x000186c4, +0x000186c1, +0x000186c0, +0x000186bd, +0x000186bb, +0x000186b8, +0x000186b7, +0x000186b4, +0x000186b2, +0x000186af, +0x000186ae, +0x000186ab, +0x000186a8, +0x000186a6, +0x000186a3, +0x000186a1, +0x0001869e, +0x0001869d, +0x0001869a, +0x00018698, +0x00018695, +0x00018694, +0x00018691, +0x0001868f, +0x0001868c, +0x0001868b, +0x00018688, +0x00018686, +0x00018683, +0x00018681, +0x0001867e, +0x0001867d, +0x0001867a, +0x00018677, +0x00018675, +0x00018672, +0x00018671, +0x0001866e, +0x0001866c, +0x00018669, +0x00018668, +0x00018665, +0x00018663, +0x00018660, +0x0001865e, +0x0001865b, +0x0001865a, +0x00018657, +0x00018655, +0x00018652, +0x00018651, +0x0001864e, +0x0001864c, +0x00018649, +0x00018646, +0x00018645, +0x00018642, +0x00018640, +0x0001863d, +0x0001863b, +0x00018638, +0x00018637, +0x00018634, +0x00018632, +0x0001862f, +0x0001862e, +0x0001862b, +0x00018629, +0x00018626, +0x00018625, +0x00018622, +0x00018620, +0x0001861d, +0x0001861b, +0x00018618, +0x00018615, +0x00018614, +0x00018611, +0x0001860f, +0x0001860c, +0x0001860b, +0x00018608, +0x00018606, +0x00018603, +0x00018602, +0x000185fe, +0x000185fd, +0x000185fa, +0x000185f8, +0x000185f5, +0x000185f4, +0x000185f1, +0x000185ef, +0x000185ec, +0x000185eb, +0x000185e8, +0x000185e5, +0x000185e3, +0x000185e0, +0x000185de, +0x000185db, +0x000185da, +0x000185d7, +0x000185d5, +0x000185d2, +0x000185d1, +0x000185ce, +0x000185cc, +0x000185c9, +0x000185c8, +0x000185c5, +0x000185c3, +0x000185c0, +0x000185be, +0x000185bb, +0x000185ba, +0x000185b7, +0x000185b4, +0x000185b2, +0x000185af, +0x000185ae, +0x000185ab, +0x000185a9, +0x000185a6, +0x000185a5, +0x000185a2, +0x000185a0, +0x0001859d, +0x0001859b, +0x00018598, +0x00018597, +0x00018594, +0x00018592, +0x0001858f, +0x0001858e, +0x0001858b, +0x00018589, +0x00018586, +0x00018584, +0x00018581, +0x00018580, +0x0001857d, +0x0001857b, +0x00018578, +0x00018577, +0x00018573, +0x00018572, +0x0001856f, +0x0001856d, +0x0001856a, +0x00018569, +0x00018566, +0x00018563, +0x00018561, +0x0001855e, +0x0001855d, +0x0001855a, +0x00018558, +0x00018555, +0x00018554, +0x00018551, +0x0001854f, +0x0001854c, +0x0001854a, +0x00018547, +0x00018546, +0x00018543, +0x00018541, +0x0001853e, +0x0001853d, +0x0001853a, +0x00018538, +0x00018535, +0x00018534, +0x00018531, +0x0001852f, +0x0001852c, +0x00018529, +0x00018528, +0x00018524, +0x00018523, +0x00018520, +0x0001851e, +0x0001851b, +0x0001851a, +0x00018517, +0x00018515, +0x00018512, +0x00018511, +0x0001850e, +0x0001850c, +0x00018509, +0x00018508, +0x00018505, +0x00018503, +0x00018500, +0x000184fe, +0x000184fb, +0x000184fa, +0x000184f7, +0x000184f5, +0x000184f2, +0x000184f1, +0x000184ee, +0x000184eb, +0x000184e9, +0x000184e6, +0x000184e5, +0x000184e2, +0x000184e0, +0x000184dd, +0x000184dc, +0x000184d8, +0x000184d7, +0x000184d4, +0x000184d2, +0x000184cf, +0x000184ce, +0x000184cb, +0x000184c9, +0x000184c6, +0x000184c5, +0x000184c2, +0x000184c0, +0x000184bd, +0x000184bc, +0x000184b9, +0x000184b7, +0x000184b4, +0x000184b1, +0x000184af, +0x000184ac, +0x000184ab, +0x000184a8, +0x000184a6, +0x000184a3, +0x000184a2, +0x0001849f, +0x0001849d, +0x0001849a, +0x00018499, +0x00018496, +0x00018494, +0x00018491, +0x00018490, +0x0001848d, +0x0001848b, +0x00018488, +0x00018486, +0x00018483, +0x00018482, +0x0001847f, +0x0001847d, +0x0001847a, +0x00018477, +0x00018476, +0x00018473, +0x00018471, +0x0001846e, +0x0001846d, +0x0001846a, +0x00018468, +0x00018465, +0x00018463, +0x00018460, +0x0001845f, +0x0001845c, +0x00018459, +0x00018458, +0x00018455, +0x00018453, +0x00018450, +0x0001844f, +0x0001844c, +0x0001844a, +0x00018447, +0x00018446, +0x00018443, +0x00018441, +0x0001843e, +0x0001843d, +0x0001843a, +0x00018438, +0x00018435, +0x00018434, +0x00018431, +0x0001842f, +0x0001842c, +0x0001842a, +0x00018427, +0x00018426, +0x00018423, +0x00018421, +0x0001841e, +0x0001841d, +0x0001841a, +0x00018418, +0x00018415, +0x00018414, +0x00018411, +0x0001840e, +0x0001840c, +0x00018409, +0x00018408, +0x00018405, +0x00018403, +0x00018400, +0x000183fe, +0x000183fb, +0x000183fa, +0x000183f7, +0x000183f5, +0x000183f2, +0x000183f1, +0x000183ee, +0x000183ec, +0x000183e9, +0x000183e8, +0x000183e5, +0x000183e3, +0x000183e0, +0x000183df, +0x000183dc, +0x000183da, +0x000183d7, +0x000183d6, +0x000183d3, +0x000183d1, +0x000183ce, +0x000183cc, +0x000183c9, +0x000183c6, +0x000183c5, +0x000183c2, +0x000183c0, +0x000183bd, +0x000183bc, +0x000183b9, +0x000183b7, +0x000183b4, +0x000183b3, +0x000183b0, +0x000183ae, +0x000183ab, +0x000183aa, +0x000183a7, +0x000183a5, +0x000183a2, +0x000183a1, +0x0001839d, +0x0001839c, +0x00018399, +0x00018397, +0x00018394, +0x00018393, +0x00018390, +0x0001838e, +0x0001838b, +0x0001838a, +0x00018387, +0x00018385, +0x00018382, +0x00018381, +0x0001837e, +0x0001837b, +0x00018379, +0x00018376, +0x00018375, +0x00018372, +0x00018370, +0x0001836d, +0x0001836b, +0x00018368, +0x00018367, +0x00018364, +0x00018362, +0x0001835f, +0x0001835e, +0x0001835b, +0x00018359, +0x00018356, +0x00018355, +0x00018352, +0x00018350, +0x0001834d, +0x0001834c, +0x00018349, +0x00018347, +0x00018344, +0x00018343, +0x00018340, +0x0001833e, +0x0001833b, +0x00018339, +0x00018336, +0x00018335, +0x00018332, +0x00018330, +0x0001832d, +0x0001832c, +0x00018329, +0x00018327, +0x00018324, +0x00018323, +0x00018320, +0x0001831e, +0x0001831b, +0x0001831a, +0x00018317, +0x00018315, +0x00018312, +0x00018311, +0x0001830e, +0x0001830c, +0x00018309, +0x00018308, +0x00018305, +0x00018302, +0x00018300, +0x000182fd, +0x000182fb, +0x000182f8, +0x000182f7, +0x000182f4, +0x000182f2, +0x000182ef, +0x000182ee, +0x000182eb, +0x000182e9, +0x000182e6, +0x000182e5, +0x000182e2, +0x000182e0, +0x000182dd, +0x000182dc, +0x000182d9, +0x000182d7, +0x000182d4, +0x000182d3, +0x000182d0, +0x000182ce, +0x000182cb, +0x000182ca, +0x000182c7, +0x000182c5, +0x000182c2, +0x000182c1, +0x000182bd, +0x000182bc, +0x000182b9, +0x000182b7, +0x000182b4, +0x000182b3, +0x000182b0, +0x000182ae, +0x000182ab, +0x000182aa, +0x000182a7, +0x000182a5, +0x000182a2, +0x0001829f, +0x0001829e, +0x0001829b, +0x00018299, +0x00018296, +0x00018295, +0x00018292, +0x00018290, +0x0001828d, +0x0001828c, +0x00018289, +0x00018287, +0x00018284, +0x00018283, +0x00018280, +0x0001827e, +0x0001827b, +0x00018279, +0x00018276, +0x00018275, +0x00018272, +0x00018270, +0x0001826d, +0x0001826c, +0x00018269, +0x00018267, +0x00018264, +0x00018263, +0x00018260, +0x0001825e, +0x0001825b, +0x0001825a, +0x00018257, +0x00018255, +0x00018252, +0x00018251, +0x0001824e, +0x0001824c, +0x00018249, +0x00018248, +0x00018245, +0x00018242, +0x00018240, +0x0001823d, +0x0001823b, +0x00018238, +0x00018237, +0x00018234, +0x00018232, +0x0001822f, +0x0001822e, +0x0001822b, +0x00018229, +0x00018226, +0x00018225, +0x00018222, +0x00018220, +0x0001821d, +0x0001821c, +0x00018219, +0x00018217, +0x00018214, +0x00018214, +0x00018211, +0x0001820e, +0x0001820c, +0x00018209, +0x00018208, +0x00018205, +0x00018203, +0x00018200, +0x000181fe, +0x000181fb, +0x000181fa, +0x000181f7, +0x000181f5, +0x000181f2, +0x000181f1, +0x000181ee, +0x000181ec, +0x000181e9, +0x000181e8, +0x000181e5, +0x000181e3, +0x000181e0, +0x000181df, +0x000181dc, +0x000181da, +0x000181d7, +0x000181d6, +0x000181d3, +0x000181d1, +0x000181ce, +0x000181cd, +0x000181ca, +0x000181c8, +0x000181c5, +0x000181c4, +0x000181c1, +0x000181bf, +0x000181bc, +0x000181bb, +0x000181b8, +0x000181b6, +0x000181b3, +0x000181b2, +0x000181af, +0x000181ad, +0x000181aa, +0x000181a9, +0x000181a6, +0x000181a4, +0x000181a1, +0x000181a0, +0x0001819c, +0x0001819b, +0x00018198, +0x00018196, +0x00018193, +0x00018192, +0x0001818f, +0x0001818d, +0x0001818a, +0x00018189, +0x00018186, +0x00018184, +0x00018181, +0x0001817e, +0x0001817d, +0x0001817a, +0x00018178, +0x00018175, +0x00018174, +0x00018171, +0x0001816f, +0x0001816c, +0x0001816b, +0x00018168, +0x00018166, +0x00018163, +0x00018162, +0x0001815f, +0x0001815d, +0x0001815a, +0x00018159, +0x00018156, +0x00018154, +0x00018151, +0x00018150, +0x0001814d, +0x0001814b, +0x00018148, +0x00018147, +0x00018144, +0x00018142, +0x0001813f, +0x0001813d, +0x0001813a, +0x00018139, +0x00018136, +0x00018134, +0x00018131, +0x00018130, +0x0001812d, +0x0001812b, +0x00018128, +0x00018127, +0x00018124, +0x00018122, +0x0001811f, +0x0001811e, +0x0001811b, +0x00018119, +0x00018116, +0x00018115, +0x00018112, +0x00018110, +0x0001810d, +0x0001810c, +0x00018109, +0x00018107, +0x00018104, +0x00018103, +0x00018100, +0x000180fe, +0x000180fb, +0x000180fa, +0x000180f7, +0x000180f5, +0x000180f2, +0x000180f0, +0x000180ef, +0x000180ec, +0x000180ea, +0x000180e7, +0x000180e6, +0x000180e3, +0x000180e1, +0x000180de, +0x000180dd, +0x000180da, +0x000180d8, +0x000180d5, +0x000180d4, +0x000180d1, +0x000180cf, +0x000180cc, +0x000180cb, +0x000180c8, +0x000180c6, +0x000180c3, +0x000180c2, +0x000180bf, +0x000180bd, +0x000180ba, +0x000180b9, +0x000180b6, +0x000180b4, +0x000180b1, +0x000180b0, +0x000180ad, +0x000180ab, +0x000180a8, +0x000180a7, +0x000180a4, +0x000180a2, +0x0001809f, +0x0001809e, +0x0001809b, +0x00018099, +0x00018096, +0x00018095, +0x00018092, +0x00018090, +0x0001808d, +0x0001808c, +0x00018089, +0x00018087, +0x00018084, +0x00018083, +0x00018080, +0x0001807e, +0x0001807b, +0x0001807a, +0x00018077, +0x00018075, +0x00018072, +0x00018071, +0x0001806e, +0x0001806c, +0x00018069, +0x00018068, +0x00018065, +0x00018063, +0x00018060, +0x0001805f, +0x0001805c, +0x0001805a, +0x00018057, +0x00018056, +0x00018053, +0x00018051, +0x0001804e, +0x0001804d, +0x0001804a, +0x00018048, +0x00018045, +0x00018044, +0x00018041, +0x0001803f, +0x0001803c, +0x0001803b, +0x00018038, +0x00018036, +0x00018033, +0x00018032, +0x0001802f, +0x0001802d, +0x0001802a, +0x00018029, +0x00018026, +0x00018024, +0x00018021, +0x00018020, +0x0001801d, +0x0001801b, +0x00018018, +0x00018017, +0x00018014, +0x00018012, +0x0001800f, +0x0001800e, +0x0001800b, +0x00018009, +0x00018006, +0x00018005, +0x00018002, +0x00018000, +0x00017ffd, +0x00017ffc, +0x00017ff9, +0x00017ff7, +0x00017ff4, +0x00017ff3, +0x00017ff0, +0x00017fee, +0x00017feb, +0x00017fea, +0x00017fe7, +0x00017fe5, +0x00017fe2, +0x00017fe1, +0x00017fde, +0x00017fdc, +0x00017fd9, +0x00017fd8, +0x00017fd5, +0x00017fd3, +0x00017fd0, +0x00017fcd, +0x00017fcb, +0x00017fc8, +0x00017fc7, +0x00017fc4, +0x00017fc2, +0x00017fc0, +0x00017fbe, +0x00017fbb, +0x00017fba, +0x00017fb7, +0x00017fb5, +0x00017fb2, +0x00017fb1, +0x00017fae, +0x00017fac, +0x00017fa9, +0x00017fa8, +0x00017fa5, +0x00017fa3, +0x00017fa0, +0x00017f9f, +0x00017f9c, +0x00017f9a, +0x00017f97, +0x00017f96, +0x00017f93, +0x00017f91, +0x00017f8e, +0x00017f8d, +0x00017f8a, +0x00017f88, +0x00017f85, +0x00017f84, +0x00017f81, +0x00017f7f, +0x00017f7c, +0x00017f7b, +0x00017f78, +0x00017f76, +0x00017f73, +0x00017f72, +0x00017f6f, +0x00017f6d, +0x00017f6a, +0x00017f69, +0x00017f66, +0x00017f64, +0x00017f61, +0x00017f60, +0x00017f5d, +0x00017f5b, +0x00017f58, +0x00017f57, +0x00017f54, +0x00017f52, +0x00017f4f, +0x00017f4e, +0x00017f4b, +0x00017f49, +0x00017f46, +0x00017f45, +0x00017f42, +0x00017f40, +0x00017f3f, +0x00017f3c, +0x00017f3a, +0x00017f37, +0x00017f36, +0x00017f33, +0x00017f31, +0x00017f2e, +0x00017f2d, +0x00017f2a, +0x00017f28, +0x00017f25, +0x00017f24, +0x00017f21, +0x00017f1f, +0x00017f1c, +0x00017f1b, +0x00017f18, +0x00017f16, +0x00017f13, +0x00017f12, +0x00017f0f, +0x00017f0d, +0x00017f0a, +0x00017f09, +0x00017f06, +0x00017f04, +0x00017f01, +0x00017f00, +0x00017efd, +0x00017efc, +0x00017ef9, +0x00017ef7, +0x00017ef4, +0x00017ef3, +0x00017ef0, +0x00017eee, +0x00017eeb, +0x00017eea, +0x00017ee7, +0x00017ee5, +0x00017ee2, +0x00017ee1, +0x00017ede, +0x00017edc, +0x00017ed9, +0x00017ed8, +0x00017ed5, +0x00017ed3, +0x00017ed0, +0x00017ecf, +0x00017ecc, +0x00017eca, +0x00017ec7, +0x00017ec6, +0x00017ec3, +0x00017ec1, +0x00017ebe, +0x00017ebd, +0x00017eba, +0x00017eb8, +0x00017eb5, +0x00017eb4, +0x00017eb2, +0x00017eaf, +0x00017ead, +0x00017eaa, +0x00017ea9, +0x00017ea6, +0x00017ea4, +0x00017ea1, +0x00017ea0, +0x00017e9d, +0x00017e9b, +0x00017e98, +0x00017e97, +0x00017e94, +0x00017e92, +0x00017e8f, +0x00017e8e, +0x00017e8b, +0x00017e89, +0x00017e86, +0x00017e85, +0x00017e82, +0x00017e80, +0x00017e7d, +0x00017e7c, +0x00017e79, +0x00017e77, +0x00017e74, +0x00017e73, +0x00017e70, +0x00017e6e, +0x00017e6b, +0x00017e6a, +0x00017e67, +0x00017e65, +0x00017e62, +0x00017e61, +0x00017e5e, +0x00017e5d, +0x00017e5a, +0x00017e58, +0x00017e55, +0x00017e54, +0x00017e51, +0x00017e4f, +0x00017e4c, +0x00017e4b, +0x00017e48, +0x00017e46, +0x00017e43, +0x00017e42, +0x00017e3f, +0x00017e3d, +0x00017e3a, +0x00017e39, +0x00017e36, +0x00017e34, +0x00017e31, +0x00017e30, +0x00017e2d, +0x00017e2b, +0x00017e28, +0x00017e27, +0x00017e24, +0x00017e22, +0x00017e21, +0x00017e1e, +0x00017e1c, +0x00017e19, +0x00017e18, +0x00017e15, +0x00017e13, +0x00017e10, +0x00017e0f, +0x00017e0c, +0x00017e0a, +0x00017e07, +0x00017e06, +0x00017e03, +0x00017e01, +0x00017dff, +0x00017dfd, +0x00017dfa, +0x00017df9, +0x00017df6, +0x00017df4, +0x00017df1, +0x00017df0, +0x00017ded, +0x00017deb, +0x00017de8, +0x00017de7, +0x00017de4, +0x00017de2, +0x00017ddf, +0x00017dde, +0x00017ddb, +0x00017dd9, +0x00017dd6, +0x00017dd5, +0x00017dd2, +0x00017dd0, +0x00017dcd, +0x00017dcc, +0x00017dc9, +0x00017dc7, +0x00017dc4, +0x00017dc3, +0x00017dc0, +0x00017dbe, +0x00017dbb, +0x00017dba, +0x00017db7, +0x00017db5, +0x00017db2, +0x00017db1, +0x00017dae, +0x00017dac, +0x00017da9, +0x00017da8, +0x00017da5, +0x00017da3, +0x00017da1, +0x00017d9f, +0x00017d9c, +0x00017d9b, +0x00017d98, +0x00017d96, +0x00017d93, +0x00017d92, +0x00017d8f, +0x00017d8d, +0x00017d8a, +0x00017d89, +0x00017d86, +0x00017d84, +0x00017d81, +0x00017d80, +0x00017d7d, +0x00017d7c, +0x00017d79, +0x00017d77, +0x00017d74, +0x00017d73, +0x00017d70, +0x00017d6e, +0x00017d6b, +0x00017d6a, +0x00017d67, +0x00017d65, +0x00017d64, +0x00017d61, +0x00017d5f, +0x00017d5c, +0x00017d5b, +0x00017d58, +0x00017d56, +0x00017d53, +0x00017d52, +0x00017d4f, +0x00017d4d, +0x00017d4a, +0x00017d49, +0x00017d46, +0x00017d44, +0x00017d41, +0x00017d40, +0x00017d3d, +0x00017d3c, +0x00017d39, +0x00017d37, +0x00017d34, +0x00017d33, +0x00017d30, +0x00017d2e, +0x00017d2b, +0x00017d2a, +0x00017d27, +0x00017d25, +0x00017d22, +0x00017d21, +0x00017d1e, +0x00017d1c, +0x00017d19, +0x00017d18, +0x00017d15, +0x00017d13, +0x00017d10, +0x00017d0f, +0x00017d0c, +0x00017d0a, +0x00017d07, +0x00017d06, +0x00017d04, +0x00017d01, +0x00017d00, +0x00017cfd, +0x00017cfc, +0x00017cf9, +0x00017cf7, +0x00017cf4, +0x00017cf3, +0x00017cf0, +0x00017cee, +0x00017ceb, +0x00017cea, +0x00017ce7, +0x00017ce5, +0x00017ce2, +0x00017ce1, +0x00017cde, +0x00017cdc, +0x00017cd9, +0x00017cd8, +0x00017cd5, +0x00017cd3, +0x00017cd0, +0x00017ccf, +0x00017ccc, +0x00017cca, +0x00017cc7, +0x00017cc6, +0x00017cc3, +0x00017cc1, +0x00017cbf, +0x00017cbd, +0x00017cba, +0x00017cb9, +0x00017cb6, +0x00017cb4, +0x00017cb1, +0x00017cb0, +0x00017cad, +0x00017cab, +0x00017ca8, +0x00017ca7, +0x00017ca5, +0x00017ca2, +0x00017ca1, +0x00017c9e, +0x00017c9c, +0x00017c99, +0x00017c98, +0x00017c95, +0x00017c93, +0x00017c90, +0x00017c8f, +0x00017c8c, +0x00017c8a, +0x00017c87, +0x00017c86, +0x00017c83, +0x00017c81, +0x00017c7f, +0x00017c7d, +0x00017c7a, +0x00017c78, +0x00017c77, +0x00017c74, +0x00017c72, +0x00017c6f, +0x00017c6e, +0x00017c6b, +0x00017c69, +0x00017c66, +0x00017c65, +0x00017c62, +0x00017c60, +0x00017c5e, +0x00017c5c, +0x00017c59, +0x00017c58, +0x00017c55, +0x00017c53, +0x00017c50, +0x00017c4f, +0x00017c4c, +0x00017c4a, +0x00017c47, +0x00017c46, +0x00017c43, +0x00017c41, +0x00017c3e, +0x00017c3d, +0x00017c3a, +0x00017c38, +0x00017c35, +0x00017c34, +0x00017c32, +0x00017c30, +0x00017c2e, +0x00017c2b, +0x00017c2a, +0x00017c27, +0x00017c25, +0x00017c22, +0x00017c21, +0x00017c1e, +0x00017c1c, +0x00017c19, +0x00017c18, +0x00017c15, +0x00017c13, +0x00017c10, +0x00017c0f, +0x00017c0c, +0x00017c0a, +0x00017c07, +0x00017c06, +0x00017c03, +0x00017c01, +0x00017bff, +0x00017bfd, +0x00017bfa, +0x00017bf9, +0x00017bf6, +0x00017bf4, +0x00017bf1, +0x00017bf0, +0x00017bed, +0x00017beb, +0x00017bea, +0x00017be7, +0x00017be5, +0x00017be2, +0x00017be1, +0x00017bde, +0x00017bdc, +0x00017bd9, +0x00017bd8, +0x00017bd5, +0x00017bd3, +0x00017bd1, +0x00017bcf, +0x00017bcc, +0x00017bcb, +0x00017bc8, +0x00017bc6, +0x00017bc3, +0x00017bc2, +0x00017bbf, +0x00017bbd, +0x00017bba, +0x00017bb9, +0x00017bb6, +0x00017bb4, +0x00017bb1, +0x00017bb0, +0x00017bad, +0x00017bab, +0x00017ba8, +0x00017ba7, +0x00017ba5, +0x00017ba2, +0x00017ba1, +0x00017b9e, +0x00017b9d, +0x00017b9a, +0x00017b98, +0x00017b95, +0x00017b94, +0x00017b91, +0x00017b8f, +0x00017b8c, +0x00017b8b, +0x00017b88, +0x00017b86, +0x00017b83, +0x00017b82, +0x00017b7f, +0x00017b7d, +0x00017b7a, +0x00017b79, +0x00017b76, +0x00017b74, +0x00017b72, +0x00017b70, +0x00017b6d, +0x00017b6c, +0x00017b69, +0x00017b67, +0x00017b64, +0x00017b63, +0x00017b60, +0x00017b5f, +0x00017b5c, +0x00017b5a, +0x00017b57, +0x00017b56, +0x00017b53, +0x00017b51, +0x00017b4e, +0x00017b4d, +0x00017b4a, +0x00017b49, +0x00017b46, +0x00017b44, +0x00017b43, +0x00017b40, +0x00017b3e, +0x00017b3b, +0x00017b3a, +0x00017b37, +0x00017b35, +0x00017b32, +0x00017b31, +0x00017b2e, +0x00017b2c, +0x00017b29, +0x00017b28, +0x00017b25, +0x00017b24, +0x00017b21, +0x00017b1f, +0x00017b1c, +0x00017b1b, +0x00017b18, +0x00017b16, +0x00017b13, +0x00017b12, +0x00017b0f, +0x00017b0d, +0x00017b0a, +0x00017b09, +0x00017b07, +0x00017b04, +0x00017b03, +0x00017b00, +0x00017aff, +0x00017afc, +0x00017afa, +0x00017af7, +0x00017af6, +0x00017af3, +0x00017af1, +0x00017aee, +0x00017aed, +0x00017aea, +0x00017ae8, +0x00017ae5, +0x00017ae4, +0x00017ae1, +0x00017adf, +0x00017adc, +0x00017adb, +0x00017ad8, +0x00017ad7, +0x00017ad4, +0x00017ad2, +0x00017ad1, +0x00017ace, +0x00017acc, +0x00017ac9, +0x00017ac8, +0x00017ac5, +0x00017ac3, +0x00017ac0, +0x00017abf, +0x00017abc, +0x00017aba, +0x00017ab7, +0x00017ab6, +0x00017ab3, +0x00017ab2, +0x00017aaf, +0x00017aad, +0x00017aaa, +0x00017aa9, +0x00017aa6, +0x00017aa4, +0x00017aa1, +0x00017aa0, +0x00017a9d, +0x00017a9b, +0x00017a9a, +0x00017a97, +0x00017a95, +0x00017a92, +0x00017a91, +0x00017a8e, +0x00017a8d, +0x00017a8a, +0x00017a88, +0x00017a85, +0x00017a84, +0x00017a81, +0x00017a7f, +0x00017a7c, +0x00017a7b, +0x00017a78, +0x00017a76, +0x00017a73, +0x00017a72, +0x00017a6f, +0x00017a6d, +0x00017a6a, +0x00017a69, +0x00017a66, +0x00017a65, +0x00017a62, +0x00017a60, +0x00017a5f, +0x00017a5c, +0x00017a5a, +0x00017a57, +0x00017a56, +0x00017a53, +0x00017a51, +0x00017a4e, +0x00017a4d, +0x00017a4a, +0x00017a48, +0x00017a47, +0x00017a44, +0x00017a42, +0x00017a3f, +0x00017a3e, +0x00017a3b, +0x00017a3a, +0x00017a37, +0x00017a35, +0x00017a32, +0x00017a31, +0x00017a2e, +0x00017a2c, +0x00017a29, +0x00017a28, +0x00017a25, +0x00017a23, +0x00017a20, +0x00017a1f, +0x00017a1c, +0x00017a1b, +0x00017a18, +0x00017a16, +0x00017a15, +0x00017a12, +0x00017a10, +0x00017a0d, +0x00017a0c, +0x00017a09, +0x00017a07, +0x00017a04, +0x00017a03, +0x00017a00, +0x000179ff, +0x000179fc, +0x000179fa, +0x000179f7, +0x000179f6, +0x000179f3, +0x000179f1, +0x000179ee, +0x000179ed, +0x000179ea, +0x000179e8, +0x000179e7, +0x000179e4, +0x000179e2, +0x000179e0, +0x000179de, +0x000179db, +0x000179da, +0x000179d7, +0x000179d5, +0x000179d2, +0x000179d1, +0x000179ce, +0x000179cc, +0x000179c9, +0x000179c8, +0x000179c5, +0x000179c3, +0x000179c1, +0x000179bf, +0x000179bc, +0x000179bb, +0x000179b9, +0x000179b6, +0x000179b5, +0x000179b2, +0x000179b0, +0x000179ad, +0x000179ac, +0x000179a9, +0x000179a7, +0x000179a4, +0x000179a3, +0x000179a0, +0x0001799f, +0x0001799c, +0x0001799a, +0x00017997, +0x00017996, +0x00017993, +0x00017991, +0x0001798e, +0x0001798d, +0x0001798b, +0x00017988, +0x00017987, +0x00017984, +0x00017982, +0x00017980, +0x0001797e, +0x0001797b, +0x0001797a, +0x00017977, +0x00017975, +0x00017972, +0x00017971, +0x0001796e, +0x0001796c, +0x00017969, +0x00017968, +0x00017965, +0x00017963, +0x00017961, +0x0001795f, +0x0001795e, +0x0001795b, +0x00017959, +0x00017956, +0x00017955, +0x00017952, +0x00017950, +0x0001794d, +0x0001794c, +0x00017949, +0x00017947, +0x00017944, +0x00017943, +0x00017940, +0x0001793f, +0x0001793c, +0x0001793a, +0x00017937, +0x00017936, +0x00017933, +0x00017931, +0x0001792f, +0x0001792e, +0x0001792b, +0x00017929, +0x00017926, +0x00017925, +0x00017922, +0x00017920, +0x0001791d, +0x0001791c, +0x0001791b, +0x00017918, +0x00017916, +0x00017913, +0x00017912, +0x0001790f, +0x0001790d, +0x0001790a, +0x00017909, +0x00017906, +0x00017904, +0x00017901, +0x00017900, +0x000178fd, +0x000178fc, +0x000178f9, +0x000178f7, +0x000178f4, +0x000178f3, +0x000178f1, +0x000178ee, +0x000178ed, +0x000178ea, +0x000178e8, +0x000178e5, +0x000178e4, +0x000178e1, +0x000178e0, +0x000178dd, +0x000178db, +0x000178d8, +0x000178d7, +0x000178d4, +0x000178d2, +0x000178cf, +0x000178ce, +0x000178cc, +0x000178ca, +0x000178c8, +0x000178c5, +0x000178c4, +0x000178c1, +0x000178bf, +0x000178bc, +0x000178bb, +0x000178b8, +0x000178b6, +0x000178b3, +0x000178b2, +0x000178af, +0x000178ae, +0x000178ab, +0x000178a9, +0x000178a6, +0x000178a5, +0x000178a3, +0x000178a0, +0x0001789f, +0x0001789c, +0x0001789a, +0x00017897, +0x00017896, +0x00017893, +0x00017892, +0x0001788f, +0x0001788d, +0x0001788a, +0x00017889, +0x00017886, +0x00017884, +0x00017881, +0x00017880, +0x0001787d, +0x0001787b, +0x0001787a, +0x00017877, +0x00017876, +0x00017873, +0x00017871, +0x0001786e, +0x0001786d, +0x0001786a, +0x00017868, +0x00017865, +0x00017864, +0x00017861, +0x0001785f, +0x0001785d, +0x0001785b, +0x00017858, +0x00017857, +0x00017855, +0x00017852, +0x00017851, +0x0001784e, +0x0001784c, +0x00017849, +0x00017848, +0x00017845, +0x00017844, +0x00017841, +0x0001783f, +0x0001783c, +0x0001783b, +0x00017838, +0x00017836, +0x00017833, +0x00017832, +0x0001782f, +0x0001782d, +0x0001782c, +0x00017829, +0x00017828, +0x00017825, +0x00017823, +0x00017820, +0x0001781f, +0x0001781c, +0x0001781a, +0x00017819, +0x00017816, +0x00017815, +0x00017812, +0x00017810, +0x0001780d, +0x0001780c, +0x00017809, +0x00017807, +0x00017804, +0x00017803, +0x00017800, +0x000177ff, +0x000177fc, +0x000177fa, +0x000177f9, +0x000177f6, +0x000177f4, +0x000177f1, +0x000177f0, +0x000177ed, +0x000177eb, +0x000177e9, +0x000177e7, +0x000177e4, +0x000177e3, +0x000177e0, +0x000177de, +0x000177db, +0x000177da, +0x000177d7, +0x000177d5, +0x000177d4, +0x000177d1, +0x000177d0, +0x000177cd, +0x000177cb, +0x000177c8, +0x000177c7, +0x000177c4, +0x000177c2, +0x000177bf, +0x000177be, +0x000177bb, +0x000177ba, +0x000177b7, +0x000177b5, +0x000177b4, +0x000177b1, +0x000177af, +0x000177ac, +0x000177ab, +0x000177a8, +0x000177a6, +0x000177a3, +0x000177a2, +0x0001779f, +0x0001779e, +0x0001779b, +0x00017799, +0x00017796, +0x00017795, +0x00017792, +0x00017790, +0x0001778f, +0x0001778c, +0x0001778b, +0x00017788, +0x00017786, +0x00017783, +0x00017782, +0x0001777f, +0x0001777d, +0x0001777a, +0x00017779, +0x00017776, +0x00017774, +0x00017772, +0x00017770, +0x0001776f, +0x0001776c, +0x0001776a, +0x00017767, +0x00017766, +0x00017763, +0x00017761, +0x0001775e, +0x0001775d, +0x0001775a, +0x00017759, +0x00017756, +0x00017754, +0x00017751, +0x00017750, +0x0001774d, +0x0001774b, +0x0001774a, +0x00017747, +0x00017745, +0x00017743, +0x00017741, +0x0001773e, +0x0001773d, +0x0001773a, +0x00017738, +0x00017735, +0x00017734, +0x00017731, +0x0001772f, +0x0001772d, +0x0001772b, +0x0001772a, +0x00017727, +0x00017725, +0x00017722, +0x00017721, +0x0001771e, +0x0001771c, +0x00017719, +0x00017718, +0x00017715, +0x00017714, +0x00017711, +0x0001770f, +0x0001770c, +0x0001770b, +0x00017708, +0x00017707, +0x00017704, +0x00017703, +0x00017700, +0x000176fe, +0x000176fb, +0x000176fa, +0x000176f7, +0x000176f5, +0x000176f3, +0x000176f1, +0x000176ee, +0x000176ed, +0x000176eb, +0x000176e8, +0x000176e7, +0x000176e4, +0x000176e2, +0x000176e0, +0x000176de, +0x000176db, +0x000176da, +0x000176d7, +0x000176d5, +0x000176d2, +0x000176d1, +0x000176cf, +0x000176cd, +0x000176cb, +0x000176c8, +0x000176c7, +0x000176c4, +0x000176c2, +0x000176bf, +0x000176be, +0x000176bb, +0x000176ba, +0x000176b7, +0x000176b5, +0x000176b4, +0x000176b1, +0x000176af, +0x000176ac, +0x000176ab, +0x000176a8, +0x000176a7, +0x000176a4, +0x000176a2, +0x0001769f, +0x0001769e, +0x0001769b, +0x00017699, +0x00017698, +0x00017695, +0x00017694, +0x00017691, +0x0001768f, +0x0001768c, +0x0001768b, +0x00017688, +0x00017686, +0x00017683, +0x00017682, +0x0001767f, +0x0001767e, +0x0001767c, +0x00017679, +0x00017678, +0x00017675, +0x00017673, +0x00017670, +0x0001766f, +0x0001766c, +0x0001766b, +0x00017668, +0x00017666, +0x00017663, +0x00017662, +0x00017660, +0x0001765e, +0x0001765c, +0x00017659, +0x00017658, +0x00017655, +0x00017653, +0x00017650, +0x0001764f, +0x0001764c, +0x0001764b, +0x00017648, +0x00017646, +0x00017645, +0x00017642, +0x00017640, +0x0001763d, +0x0001763c, +0x00017639, +0x00017638, +0x00017635, +0x00017633, +0x00017630, +0x0001762f, +0x0001762c, +0x0001762a, +0x00017629, +0x00017626, +0x00017625, +0x00017622, +0x00017620, +0x0001761d, +0x0001761c, +0x00017619, +0x00017617, +0x00017614, +0x00017613, +0x00017610, +0x0001760f, +0x0001760d, +0x0001760a, +0x00017609, +0x00017606, +0x00017604, +0x00017601, +0x00017600, +0x000175fd, +0x000175fc, +0x000175f9, +0x000175f7, +0x000175f5, +0x000175f2, +0x000175f0, +0x000175ed, +0x000175ec, +0x000175e9, +0x000175e8, +0x000175e6, +0x000175e3, +0x000175e2, +0x000175df, +0x000175dd, +0x000175db, +0x000175d9, +0x000175d6, +0x000175d5, +0x000175d2, +0x000175d0, +0x000175cf, +0x000175cc, +0x000175cb, +0x000175c8, +0x000175c6, +0x000175c3, +0x000175c2, +0x000175bf, +0x000175bd, +0x000175bb, +0x000175b9, +0x000175b6, +0x000175b5, +0x000175b3, +0x000175b0, +0x000175af, +0x000175ac, +0x000175aa, +0x000175a8, +0x000175a6, +0x000175a3, +0x000175a2, +0x0001759f, +0x0001759d, +0x0001759c, +0x00017599, +0x00017598, +0x00017595, +0x00017593, +0x00017590, +0x0001758f, +0x0001758c, +0x0001758a, +0x00017588, +0x00017586, +0x00017585, +0x00017582, +0x00017580, +0x0001757d, +0x0001757c, +0x00017579, +0x00017577, +0x00017575, +0x00017573, +0x00017570, +0x0001756f, +0x0001756d, +0x0001756a, +0x00017569, +0x00017566, +0x00017565, +0x00017562, +0x00017560, +0x0001755d, +0x0001755c, +0x00017559, +0x00017557, +0x00017555, +0x00017553, +0x00017552, +0x0001754f, +0x0001754d, +0x0001754a, +0x00017549, +0x00017546, +0x00017544, +0x00017542, +0x00017540, +0x0001753d, +0x0001753c, +0x0001753a, +0x00017537, +0x00017536, +0x00017533, +0x00017532, +0x0001752f, +0x0001752d, +0x0001752a, +0x00017529, +0x00017526, +0x00017524, +0x00017523, +0x00017520, +0x0001751f, +0x0001751c, +0x0001751a, +0x00017517, +0x00017516, +0x00017513, +0x00017511, +0x0001750f, +0x0001750d, +0x0001750a, +0x00017509, +0x00017507, +0x00017504, +0x00017503, +0x00017500, +0x000174ff, +0x000174fc, +0x000174fa, +0x000174f7, +0x000174f6, +0x000174f3, +0x000174f1, +0x000174f0, +0x000174ed, +0x000174ec, +0x000174e9, +0x000174e7, +0x000174e4, +0x000174e3, +0x000174e0, +0x000174de, +0x000174db, +0x000174da, +0x000174d7, +0x000174d6, +0x000174d3, +0x000174d1, +0x000174ce, +0x000174cd, +0x000174cb, +0x000174c9, +0x000174c7, +0x000174c4, +0x000174c3, +0x000174c0, +0x000174be, +0x000174bb, +0x000174ba, +0x000174b7, +0x000174b6, +0x000174b4, +0x000174b1, +0x000174b0, +0x000174ad, +0x000174ab, +0x000174a9, +0x000174a7, +0x000174a4, +0x000174a3, +0x000174a1, +0x0001749e, +0x0001749d, +0x0001749a, +0x00017499, +0x00017496, +0x00017494, +0x00017491, +0x00017490, +0x0001748d, +0x0001748c, +0x0001748a, +0x00017487, +0x00017486, +0x00017483, +0x00017481, +0x0001747e, +0x0001747d, +0x0001747a, +0x00017479, +0x00017476, +0x00017474, +0x00017473, +0x00017470, +0x0001746e, +0x0001746c, +0x0001746a, +0x00017467, +0x00017466, +0x00017463, +0x00017461, +0x0001745e, +0x0001745d, +0x0001745c, +0x00017459, +0x00017457, +0x00017454, +0x00017453, +0x00017450, +0x0001744e, +0x0001744c, +0x0001744a, +0x00017447, +0x00017446, +0x00017444, +0x00017441, +0x00017440, +0x0001743d, +0x0001743c, +0x00017439, +0x00017437, +0x00017434, +0x00017433, +0x00017430, +0x0001742f, +0x0001742d, +0x0001742a, +0x00017429, +0x00017426, +0x00017424, +0x00017421, +0x00017420, +0x0001741d, +0x0001741c, +0x0001741a, +0x00017417, +0x00017416, +0x00017413, +0x00017411, +0x0001740f, +0x0001740d, +0x0001740a, +0x00017409, +0x00017406, +0x00017404, +0x00017403, +0x00017400, +0x000173ff, +0x000173fc, +0x000173fa, +0x000173f7, +0x000173f6, +0x000173f3, +0x000173f1, +0x000173ef, +0x000173ed, +0x000173ec, +0x000173e9, +0x000173e7, +0x000173e4, +0x000173e3, +0x000173e0, +0x000173df, +0x000173dc, +0x000173da, +0x000173d7, +0x000173d5, +0x000173d4, +0x000173d1, +0x000173cf, +0x000173cc, +0x000173cb, +0x000173c9, +0x000173c7, +0x000173c5, +0x000173c2, +0x000173c1, +0x000173be, +0x000173bc, +0x000173ba, +0x000173b8, +0x000173b7, +0x000173b4, +0x000173b2, +0x000173af, +0x000173ae, +0x000173ab, +0x000173aa, +0x000173a7, +0x000173a5, +0x000173a2, +0x000173a1, +0x0001739f, +0x0001739d, +0x0001739b, +0x00017398, +0x00017397, +0x00017394, +0x00017392, +0x0001738f, +0x0001738e, +0x0001738d, +0x0001738a, +0x00017388, +0x00017385, +0x00017384, +0x00017381, +0x00017380, +0x0001737d, +0x0001737b, +0x00017378, +0x00017377, +0x00017375, +0x00017372, +0x00017371, +0x0001736e, +0x0001736d, +0x0001736a, +0x00017368, +0x00017365, +0x00017364, +0x00017363, +0x00017360, +0x0001735e, +0x0001735b, +0x0001735a, +0x00017357, +0x00017356, +0x00017353, +0x00017351, +0x00017350, +0x0001734d, +0x0001734b, +0x00017348, +0x00017347, +0x00017344, +0x00017343, +0x00017340, +0x0001733e, +0x0001733b, +0x0001733a, +0x00017339, +0x00017336, +0x00017334, +0x00017331, +0x00017330, +0x0001732d, +0x0001732b, +0x00017329, +0x00017327, +0x00017326, +0x00017323, +0x00017321, +0x0001731e, +0x0001731d, +0x0001731a, +0x00017319, +0x00017316, +0x00017314, +0x00017311, +0x00017310, +0x0001730e, +0x0001730c, +0x0001730a, +0x00017307, +0x00017306, +0x00017303, +0x00017301, +0x000172ff, +0x000172fd, +0x000172fc, +0x000172f9, +0x000172f7, +0x000172f4, +0x000172f3, +0x000172f0, +0x000172ef, +0x000172ec, +0x000172ea, +0x000172e7, +0x000172e6, +0x000172e4, +0x000172e2, +0x000172e0, +0x000172dd, +0x000172dc, +0x000172d9, +0x000172d7, +0x000172d5, +0x000172d3, +0x000172d2, +0x000172cf, +0x000172cd, +0x000172ca, +0x000172c9, +0x000172c6, +0x000172c5, +0x000172c2, +0x000172c0, +0x000172bd, +0x000172bc, +0x000172b9, +0x000172b8, +0x000172b5, +0x000172b3, +0x000172b2, +0x000172af, +0x000172ad, +0x000172ab, +0x000172a9, +0x000172a6, +0x000172a5, +0x000172a2, +0x000172a0, +0x0001729f, +0x0001729c, +0x0001729b, +0x00017298, +0x00017296, +0x00017293, +0x00017292, +0x0001728f, +0x0001728e, +0x0001728c, +0x00017289, +0x00017288, +0x00017285, +0x00017284, +0x00017281, +0x0001727f, +0x0001727c, +0x0001727b, +0x00017279, +0x00017277, +0x00017275, +0x00017272, +0x00017271, +0x0001726e, +0x0001726c, +0x0001726a, +0x00017268, +0x00017267, +0x00017264, +0x00017262, +0x0001725f, +0x0001725e, +0x0001725b, +0x0001725a, +0x00017257, +0x00017255, +0x00017254, +0x00017251, +0x0001724f, +0x0001724d, +0x0001724b, +0x00017248, +0x00017247, +0x00017244, +0x00017242, +0x00017241, +0x0001723e, +0x0001723d, +0x0001723a, +0x00017238, +0x00017235, +0x00017234, +0x00017231, +0x00017230, +0x0001722e, +0x0001722b, +0x0001722a, +0x00017227, +0x00017226, +0x00017223, +0x00017221, +0x0001721e, +0x0001721d, +0x0001721b, +0x00017219, +0x00017217, +0x00017214, +0x00017213, +0x00017210, +0x0001720e, +0x0001720c, +0x0001720a, +0x00017209, +0x00017206, +0x00017204, +0x00017201, +0x00017200, +0x000171fd, +0x000171fc, +0x000171f9, +0x000171f7, +0x000171f6, +0x000171f3, +0x000171f2, +0x000171ef, +0x000171ed, +0x000171ea, +0x000171e9, +0x000171e6, +0x000171e5, +0x000171e3, +0x000171e0, +0x000171df, +0x000171dc, +0x000171da, +0x000171d8, +0x000171d6, +0x000171d3, +0x000171d2, +0x000171d0, +0x000171cd, +0x000171cc, +0x000171c9, +0x000171c8, +0x000171c5, +0x000171c3, +0x000171c0, +0x000171bf, +0x000171bd, +0x000171ba, +0x000171b9, +0x000171b6, +0x000171b4, +0x000171b3, +0x000171b0, +0x000171ae, +0x000171ac, +0x000171aa, +0x000171a7, +0x000171a6, +0x000171a3, +0x000171a1, +0x000171a0, +0x0001719d, +0x0001719c, +0x00017199, +0x00017197, +0x00017194, +0x00017193, +0x00017190, +0x0001718f, +0x0001718d, +0x0001718a, +0x00017189, +0x00017186, +0x00017185, +0x00017182, +0x00017180, +0x0001717f, +0x0001717c, +0x0001717b, +0x00017178, +0x00017176, +0x00017173, +0x00017172, +0x0001716f, +0x0001716e, +0x0001716c, +0x00017169, +0x00017168, +0x00017165, +0x00017163, +0x00017161, +0x0001715f, +0x0001715c, +0x0001715b, +0x00017159, +0x00017156, +0x00017155, +0x00017152, +0x00017151, +0x0001714e, +0x0001714c, +0x0001714a, +0x00017148, +0x00017147, +0x00017144, +0x00017142, +0x0001713f, +0x0001713e, +0x0001713b, +0x0001713a, +0x00017138, +0x00017135, +0x00017134, +0x00017131, +0x00017130, +0x0001712d, +0x0001712b, +0x00017128, +0x00017127, +0x00017125, +0x00017123, +0x00017121, +0x0001711e, +0x0001711d, +0x0001711a, +0x00017119, +0x00017116, +0x00017114, +0x00017113, +0x00017110, +0x0001710e, +0x0001710c, +0x0001710a, +0x00017107, +0x00017106, +0x00017103, +0x00017101, +0x00017100, +0x000170fd, +0x000170fc, +0x000170f9, +0x000170f7, +0x000170f4, +0x000170f3, +0x000170f0, +0x000170ef, +0x000170ed, +0x000170ea, +0x000170e9, +0x000170e6, +0x000170e5, +0x000170e2, +0x000170e0, +0x000170df, +0x000170dc, +0x000170db, +0x000170d8, +0x000170d6, +0x000170d3, +0x000170d2, +0x000170cf, +0x000170ce, +0x000170cc, +0x000170c9, +0x000170c8, +0x000170c5, +0x000170c3, +0x000170c1, +0x000170bf, +0x000170bc, +0x000170bb, +0x000170b9, +0x000170b6, +0x000170b5, +0x000170b2, +0x000170b1, +0x000170ae, +0x000170ad, +0x000170aa, +0x000170a8, +0x000170a5, +0x000170a4, +0x000170a2, +0x000170a0, +0x0001709e, +0x0001709b, +0x0001709a, +0x00017097, +0x00017096, +0x00017093, +0x00017091, +0x00017090, +0x0001708d, +0x0001708b, +0x00017089, +0x00017087, +0x00017084, +0x00017083, +0x00017081, +0x0001707f, +0x0001707d, +0x0001707a, +0x00017079, +0x00017076, +0x00017074, +0x00017072, +0x00017070, +0x0001706f, +0x0001706c, +0x0001706a, +0x00017068, +0x00017066, +0x00017063, +0x00017062, +0x00017060, +0x0001705d, +0x0001705c, +0x00017059, +0x00017058, +0x00017055, +0x00017053, +0x00017051, +0x0001704f, +0x0001704e, +0x0001704b, +0x00017049, +0x00017046, +0x00017045, +0x00017042, +0x00017041, +0x0001703f, +0x0001703c, +0x0001703b, +0x00017038, +0x00017037, +0x00017034, +0x00017032, +0x0001702f, +0x0001702e, +0x0001702d, +0x0001702a, +0x00017028, +0x00017025, +0x00017024, +0x00017021, +0x00017020, +0x0001701e, +0x0001701b, +0x0001701a, +0x00017017, +0x00017016, +0x00017013, +0x00017011, +0x0001700e, +0x0001700d, +0x0001700c, +0x00017009, +0x00017007, +0x00017004, +0x00017003, +0x00017000, +0x00016fff, +0x00016ffd, +0x00016ffa, +0x00016ff9, +0x00016ff6, +0x00016ff5, +0x00016ff2, +0x00016ff0, +0x00016fed, +0x00016fec, +0x00016fea, +0x00016fe8, +0x00016fe6, +0x00016fe3, +0x00016fe2, +0x00016fdf, +0x00016fde, +0x00016fdc, +0x00016fd9, +0x00016fd8, +0x00016fd5, +0x00016fd3, +0x00016fd1, +0x00016fcf, +0x00016fcc, +0x00016fcb, +0x00016fc9, +0x00016fc7, +0x00016fc5, +0x00016fc2, +0x00016fc1, +0x00016fbe, +0x00016fbc, +0x00016fbb, +0x00016fb8, +0x00016fb7, +0x00016fb4, +0x00016fb2, +0x00016fb0, +0x00016fae, +0x00016fab, +0x00016fa9, +0x00016fa8, +0x00016fa5, +0x00016fa3, +0x00016fa2, +0x00016f9f, +0x00016f9e, +0x00016f9b, +0x00016f99, +0x00016f97, +0x00016f95, +0x00016f92, +0x00016f91, +0x00016f8f, +0x00016f8c, +0x00016f8b, +0x00016f88, +0x00016f87, +0x00016f84, +0x00016f82, +0x00016f81, +0x00016f7e, +0x00016f7d, +0x00016f7a, +0x00016f78, +0x00016f76, +0x00016f74, +0x00016f73, +0x00016f70, +0x00016f6e, +0x00016f6c, +0x00016f6a, +0x00016f67, +0x00016f66, +0x00016f64, +0x00016f61, +0x00016f60, +0x00016f5d, +0x00016f5c, +0x00016f59, +0x00016f57, +0x00016f55, +0x00016f53, +0x00016f52, +0x00016f4f, +0x00016f4d, +0x00016f4b, +0x00016f49, +0x00016f46, +0x00016f45, +0x00016f43, +0x00016f41, +0x00016f3f, +0x00016f3c, +0x00016f3b, +0x00016f38, +0x00016f36, +0x00016f35, +0x00016f32, +0x00016f31, +0x00016f2e, +0x00016f2c, +0x00016f2a, +0x00016f28, +0x00016f27, +0x00016f24, +0x00016f22, +0x00016f20, +0x00016f1e, +0x00016f1b, +0x00016f1a, +0x00016f17, +0x00016f16, +0x00016f14, +0x00016f11, +0x00016f10, +0x00016f0d, +0x00016f0b, +0x00016f09, +0x00016f07, +0x00016f06, +0x00016f03, +0x00016f01, +0x00016eff, +0x00016efd, +0x00016efa, +0x00016ef9, +0x00016ef7, +0x00016ef5, +0x00016ef3, +0x00016ef0, +0x00016eef, +0x00016eec, +0x00016eea, +0x00016ee8, +0x00016ee6, +0x00016ee5, +0x00016ee2, +0x00016ee0, +0x00016ede, +0x00016edc, +0x00016ed9, +0x00016ed8, +0x00016ed6, +0x00016ed4, +0x00016ed2, +0x00016ecf, +0x00016ece, +0x00016ecb, +0x00016eca, +0x00016ec8, +0x00016ec5, +0x00016ec4, +0x00016ec1, +0x00016ebf, +0x00016ebd, +0x00016ebb, +0x00016eba, +0x00016eb7, +0x00016eb5, +0x00016eb3, +0x00016eb1, +0x00016eae, +0x00016ead, +0x00016eaa, +0x00016ea9, +0x00016ea7, +0x00016ea4, +0x00016ea3, +0x00016ea0, +0x00016e9f, +0x00016e9c, +0x00016e9a, +0x00016e98, +0x00016e96, +0x00016e93, +0x00016e92, +0x00016e90, +0x00016e8e, +0x00016e8c, +0x00016e89, +0x00016e88, +0x00016e85, +0x00016e84, +0x00016e82, +0x00016e7f, +0x00016e7e, +0x00016e7b, +0x00016e7a, +0x00016e77, +0x00016e75, +0x00016e74, +0x00016e71, +0x00016e70, +0x00016e6d, +0x00016e6b, +0x00016e68, +0x00016e67, +0x00016e66, +0x00016e63, +0x00016e61, +0x00016e5e, +0x00016e5d, +0x00016e5a, +0x00016e59, +0x00016e57, +0x00016e54, +0x00016e53, +0x00016e50, +0x00016e4f, +0x00016e4c, +0x00016e4a, +0x00016e49, +0x00016e46, +0x00016e45, +0x00016e42, +0x00016e40, +0x00016e3d, +0x00016e3c, +0x00016e3b, +0x00016e38, +0x00016e36, +0x00016e33, +0x00016e32, +0x00016e2f, +0x00016e2e, +0x00016e2c, +0x00016e29, +0x00016e28, +0x00016e25, +0x00016e24, +0x00016e21, +0x00016e1f, +0x00016e1e, +0x00016e1b, +0x00016e1a, +0x00016e17, +0x00016e15, +0x00016e13, +0x00016e11, +0x00016e10, +0x00016e0d, +0x00016e0b, +0x00016e09, +0x00016e07, +0x00016e04, +0x00016e03, +0x00016e01, +0x00016dff, +0x00016dfd, +0x00016dfa, +0x00016df9, +0x00016df6, +0x00016df5, +0x00016df3, +0x00016df0, +0x00016def, +0x00016dec, +0x00016deb, +0x00016de8, +0x00016de6, +0x00016de5, +0x00016de2, +0x00016de1, +0x00016dde, +0x00016ddc, +0x00016dd9, +0x00016dd8, +0x00016dd7, +0x00016dd4, +0x00016dd2, +0x00016dcf, +0x00016dce, +0x00016dcb, +0x00016dca, +0x00016dc8, +0x00016dc5, +0x00016dc4, +0x00016dc1, +0x00016dc0, +0x00016dbd, +0x00016dbb, +0x00016dba, +0x00016db7, +0x00016db6, +0x00016db3, +0x00016db1, +0x00016daf, +0x00016dad, +0x00016dac, +0x00016da9, +0x00016da7, +0x00016da5, +0x00016da3, +0x00016da0, +0x00016d9f, +0x00016d9d, +0x00016d9a, +0x00016d99, +0x00016d96, +0x00016d94, +0x00016d93, +0x00016d90, +0x00016d8f, +0x00016d8c, +0x00016d8a, +0x00016d87, +0x00016d86, +0x00016d85, +0x00016d82, +0x00016d80, +0x00016d7d, +0x00016d7c, +0x00016d7b, +0x00016d78, +0x00016d76, +0x00016d73, +0x00016d72, +0x00016d6f, +0x00016d6e, +0x00016d6c, +0x00016d6a, +0x00016d68, +0x00016d65, +0x00016d64, +0x00016d61, +0x00016d60, +0x00016d5e, +0x00016d5b, +0x00016d5a, +0x00016d57, +0x00016d56, +0x00016d53, +0x00016d51, +0x00016d50, +0x00016d4d, +0x00016d4c, +0x00016d49, +0x00016d47, +0x00016d44, +0x00016d43, +0x00016d42, +0x00016d3f, +0x00016d3d, +0x00016d3a, +0x00016d39, +0x00016d36, +0x00016d35, +0x00016d33, +0x00016d30, +0x00016d2f, +0x00016d2c, +0x00016d2b, +0x00016d28, +0x00016d26, +0x00016d25, +0x00016d22, +0x00016d21, +0x00016d1e, +0x00016d1d, +0x00016d1b, +0x00016d18, +0x00016d17, +0x00016d14, +0x00016d13, +0x00016d10, +0x00016d0e, +0x00016d0d, +0x00016d0a, +0x00016d09, +0x00016d06, +0x00016d04, +0x00016d01, +0x00016d00, +0x00016cff, +0x00016cfc, +0x00016cfa, +0x00016cf7, +0x00016cf6, +0x00016cf3, +0x00016cf2, +0x00016cf0, +0x00016ced, +0x00016cec, +0x00016ce9, +0x00016ce8, +0x00016ce5, +0x00016ce3, +0x00016ce2, +0x00016cdf, +0x00016cde, +0x00016cdb, +0x00016cda, +0x00016cd7, +0x00016cd5, +0x00016cd4, +0x00016cd1, +0x00016cd0, +0x00016ccd, +0x00016ccb, +0x00016cc8, +0x00016cc7, +0x00016cc6, +0x00016cc3, +0x00016cc1, +0x00016cbe, +0x00016cbd, +0x00016cba, +0x00016cb9, +0x00016cb7, +0x00016cb4, +0x00016cb3, +0x00016cb0, +0x00016caf, +0x00016cad, +0x00016caa, +0x00016ca9, +0x00016ca6, +0x00016ca5, +0x00016ca2, +0x00016ca0, +0x00016c9f, +0x00016c9c, +0x00016c9b, +0x00016c98, +0x00016c97, +0x00016c94, +0x00016c92, +0x00016c90, +0x00016c8e, +0x00016c8b, +0x00016c8a, +0x00016c89, +0x00016c86, +0x00016c84, +0x00016c81, +0x00016c80, +0x00016c7f, +0x00016c7c, +0x00016c7a, +0x00016c77, +0x00016c76, +0x00016c73, +0x00016c72, +0x00016c70, +0x00016c6d, +0x00016c6c, +0x00016c69, +0x00016c68, +0x00016c65, +0x00016c64, +0x00016c62, +0x00016c5f, +0x00016c5e, +0x00016c5b, +0x00016c5a, +0x00016c58, +0x00016c55, +0x00016c54, +0x00016c51, +0x00016c50, +0x00016c4d, +0x00016c4b, +0x00016c4a, +0x00016c47, +0x00016c46, +0x00016c43, +0x00016c41, +0x00016c3f, +0x00016c3d, +0x00016c3c, +0x00016c39, +0x00016c37, +0x00016c35, +0x00016c33, +0x00016c30, +0x00016c2f, +0x00016c2e, +0x00016c2b, +0x00016c29, +0x00016c26, +0x00016c25, +0x00016c24, +0x00016c21, +0x00016c1f, +0x00016c1c, +0x00016c1b, +0x00016c18, +0x00016c17, +0x00016c15, +0x00016c12, +0x00016c11, +0x00016c0e, +0x00016c0d, +0x00016c0a, +0x00016c09, +0x00016c07, +0x00016c04, +0x00016c03, +0x00016c00, +0x00016bff, +0x00016bfd, +0x00016bfa, +0x00016bf9, +0x00016bf6, +0x00016bf5, +0x00016bf2, +0x00016bf0, +0x00016bef, +0x00016bec, +0x00016beb, +0x00016be8, +0x00016be6, +0x00016be4, +0x00016be2, +0x00016be1, +0x00016bde, +0x00016bdc, +0x00016bda, +0x00016bd8, +0x00016bd7, +0x00016bd4, +0x00016bd3, +0x00016bd0, +0x00016bce, +0x00016bcb, +0x00016bca, +0x00016bc9, +0x00016bc6, +0x00016bc4, +0x00016bc1, +0x00016bc0, +0x00016bbd, +0x00016bbc, +0x00016bba, +0x00016bb7, +0x00016bb6, +0x00016bb3, +0x00016bb2, +0x00016baf, +0x00016bae, +0x00016bac, +0x00016ba9, +0x00016ba8, +0x00016ba5, +0x00016ba4, +0x00016ba2, +0x00016b9f, +0x00016b9e, +0x00016b9b, +0x00016b9a, +0x00016b97, +0x00016b95, +0x00016b93, +0x00016b91, +0x00016b8f, +0x00016b8e, +0x00016b8b, +0x00016b8a, +0x00016b87, +0x00016b85, +0x00016b82, +0x00016b81, +0x00016b80, +0x00016b7d, +0x00016b7b, +0x00016b79, +0x00016b77, +0x00016b76, +0x00016b73, +0x00016b71, +0x00016b6f, +0x00016b6d, +0x00016b6a, +0x00016b69, +0x00016b68, +0x00016b65, +0x00016b63, +0x00016b60, +0x00016b5f, +0x00016b5e, +0x00016b5b, +0x00016b59, +0x00016b56, +0x00016b55, +0x00016b52, +0x00016b51, +0x00016b4f, +0x00016b4d, +0x00016b4b, +0x00016b48, +0x00016b47, +0x00016b45, +0x00016b43, +0x00016b41, +0x00016b3e, +0x00016b3d, +0x00016b3a, +0x00016b39, +0x00016b37, +0x00016b34, +0x00016b33, +0x00016b30, +0x00016b2f, +0x00016b2d, +0x00016b2b, +0x00016b29, +0x00016b26, +0x00016b25, +0x00016b22, +0x00016b21, +0x00016b1f, +0x00016b1c, +0x00016b1b, +0x00016b18, +0x00016b17, +0x00016b15, +0x00016b12, +0x00016b11, +0x00016b0e, +0x00016b0d, +0x00016b0a, +0x00016b09, +0x00016b07, +0x00016b04, +0x00016b03, +0x00016b00, +0x00016aff, +0x00016afc, +0x00016afa, +0x00016af9, +0x00016af6, +0x00016af5, +0x00016af2, +0x00016af0, +0x00016aef, +0x00016aec, +0x00016aeb, +0x00016ae8, +0x00016ae6, +0x00016ae4, +0x00016ae2, +0x00016ae1, +0x00016ade, +0x00016add, +0x00016ada, +0x00016ad8, +0x00016ad7, +0x00016ad4, +0x00016ad3, +0x00016ad0, +0x00016ace, +0x00016acc, +0x00016aca, +0x00016ac9, +0x00016ac6, +0x00016ac4, +0x00016ac2, +0x00016ac0, +0x00016abf, +0x00016abc, +0x00016abb, +0x00016ab8, +0x00016ab6, +0x00016ab3, +0x00016ab2, +0x00016ab1, +0x00016aae, +0x00016aac, +0x00016aaa, +0x00016aa8, +0x00016aa7, +0x00016aa4, +0x00016aa2, +0x00016aa0, +0x00016a9e, +0x00016a9b, +0x00016a9a, +0x00016a98, +0x00016a96, +0x00016a94, +0x00016a92, +0x00016a90, +0x00016a8d, +0x00016a8c, +0x00016a89, +0x00016a88, +0x00016a86, +0x00016a84, +0x00016a82, +0x00016a7f, +0x00016a7e, +0x00016a7c, +0x00016a7a, +0x00016a78, +0x00016a75, +0x00016a74, +0x00016a71, +0x00016a70, +0x00016a6e, +0x00016a6b, +0x00016a6a, +0x00016a67, +0x00016a66, +0x00016a64, +0x00016a62, +0x00016a60, +0x00016a5d, +0x00016a5c, +0x00016a59, +0x00016a58, +0x00016a56, +0x00016a53, +0x00016a52, +0x00016a4f, +0x00016a4e, +0x00016a4c, +0x00016a4a, +0x00016a48, +0x00016a45, +0x00016a44, +0x00016a42, +0x00016a40, +0x00016a3e, +0x00016a3b, +0x00016a3a, +0x00016a37, +0x00016a36, +0x00016a34, +0x00016a31, +0x00016a30, +0x00016a2d, +0x00016a2c, +0x00016a2a, +0x00016a28, +0x00016a26, +0x00016a23, +0x00016a22, +0x00016a1f, +0x00016a1e, +0x00016a1c, +0x00016a19, +0x00016a18, +0x00016a15, +0x00016a14, +0x00016a12, +0x00016a10, +0x00016a0e, +0x00016a0b, +0x00016a0a, +0x00016a08, +0x00016a06, +0x00016a04, +0x00016a01, +0x00016a00, +0x000169fd, +0x000169fc, +0x000169fa, +0x000169f8, +0x000169f6, +0x000169f3, +0x000169f2, +0x000169f0, +0x000169ee, +0x000169ec, +0x000169e9, +0x000169e8, +0x000169e5, +0x000169e4, +0x000169e2, +0x000169df, +0x000169de, +0x000169db, +0x000169da, +0x000169d8, +0x000169d6, +0x000169d4, +0x000169d1, +0x000169d0, +0x000169cf, +0x000169cc, +0x000169ca, +0x000169c7, +0x000169c6, +0x000169c3, +0x000169c2, +0x000169c0, +0x000169be, +0x000169bc, +0x000169b9, +0x000169b8, +0x000169b6, +0x000169b4, +0x000169b2, +0x000169af, +0x000169ae, +0x000169ab, +0x000169aa, +0x000169a8, +0x000169a6, +0x000169a4, +0x000169a1, +0x000169a0, +0x0001699e, +0x0001699c, +0x0001699a, +0x00016997, +0x00016996, +0x00016994, +0x00016991, +0x00016990, +0x0001698e, +0x0001698c, +0x0001698a, +0x00016987, +0x00016986, +0x00016983, +0x00016982, +0x00016980, +0x0001697e, +0x0001697c, +0x00016979, +0x00016978, +0x00016976, +0x00016974, +0x00016972, +0x0001696f, +0x0001696e, +0x0001696d, +0x0001696a, +0x00016968, +0x00016966, +0x00016964, +0x00016961, +0x00016960, +0x0001695e, +0x0001695c, +0x0001695a, +0x00016957, +0x00016956, +0x00016955, +0x00016952, +0x00016950, +0x0001694e, +0x0001694c, +0x0001694b, +0x00016948, +0x00016947, +0x00016944, +0x00016942, +0x00016941, +0x0001693e, +0x0001693d, +0x0001693a, +0x00016938, +0x00016936, +0x00016934, +0x00016933, +0x00016930, +0x0001692f, +0x0001692c, +0x0001692a, +0x00016929, +0x00016926, +0x00016925, +0x00016922, +0x00016920, +0x0001691f, +0x0001691c, +0x0001691b, +0x00016918, +0x00016917, +0x00016915, +0x00016912, +0x00016911, +0x0001690e, +0x0001690d, +0x0001690a, +0x00016908, +0x00016907, +0x00016904, +0x00016903, +0x00016900, +0x000168ff, +0x000168fd, +0x000168fa, +0x000168f9, +0x000168f6, +0x000168f5, +0x000168f3, +0x000168f0, +0x000168ef, +0x000168ec, +0x000168eb, +0x000168e8, +0x000168e7, +0x000168e5, +0x000168e2, +0x000168e1, +0x000168de, +0x000168dd, +0x000168db, +0x000168d9, +0x000168d7, +0x000168d4, +0x000168d3, +0x000168d1, +0x000168cf, +0x000168cd, +0x000168ca, +0x000168c9, +0x000168c8, +0x000168c5, +0x000168c3, +0x000168c1, +0x000168bf, +0x000168bc, +0x000168bb, +0x000168b9, +0x000168b7, +0x000168b5, +0x000168b2, +0x000168b1, +0x000168b0, +0x000168ad, +0x000168ab, +0x000168a9, +0x000168a7, +0x000168a6, +0x000168a3, +0x000168a2, +0x0001689f, +0x0001689d, +0x0001689a, +0x00016899, +0x00016898, +0x00016895, +0x00016894, +0x00016891, +0x0001688f, +0x0001688d, +0x0001688b, +0x0001688a, +0x00016887, +0x00016886, +0x00016883, +0x00016881, +0x00016880, +0x0001687d, +0x0001687c, +0x00016879, +0x00016878, +0x00016876, +0x00016873, +0x00016872, +0x0001686f, +0x0001686e, +0x0001686b, +0x00016869, +0x00016868, +0x00016865, +0x00016864, +0x00016861, +0x00016860, +0x0001685e, +0x0001685b, +0x0001685a, +0x00016857, +0x00016856, +0x00016854, +0x00016852, +0x00016850, +0x0001684d, +0x0001684c, +0x0001684b, +0x00016848, +0x00016846, +0x00016844, +0x00016842, +0x00016841, +0x0001683e, +0x0001683c, +0x0001683a, +0x00016838, +0x00016837, +0x00016834, +0x00016833, +0x00016830, +0x0001682e, +0x0001682c, +0x0001682a, +0x00016829, +0x00016826, +0x00016825, +0x00016822, +0x00016820, +0x0001681f, +0x0001681c, +0x0001681b, +0x00016818, +0x00016817, +0x00016815, +0x00016812, +0x00016811, +0x0001680e, +0x0001680d, +0x0001680b, +0x00016808, +0x00016807, +0x00016804, +0x00016803, +0x00016801, +0x000167ff, +0x000167fd, +0x000167fa, +0x000167f9, +0x000167f8, +0x000167f5, +0x000167f3, +0x000167f1, +0x000167ef, +0x000167ec, +0x000167eb, +0x000167ea, +0x000167e7, +0x000167e5, +0x000167e2, +0x000167e1, +0x000167e0, +0x000167dd, +0x000167db, +0x000167d9, +0x000167d7, +0x000167d6, +0x000167d3, +0x000167d2, +0x000167cf, +0x000167cd, +0x000167cc, +0x000167c9, +0x000167c8, +0x000167c5, +0x000167c4, +0x000167c2, +0x000167bf, +0x000167be, +0x000167bb, +0x000167ba, +0x000167b8, +0x000167b5, +0x000167b4, +0x000167b1, +0x000167b0, +0x000167ad, +0x000167ac, +0x000167aa, +0x000167a7, +0x000167a6, +0x000167a3, +0x000167a2, +0x000167a0, +0x0001679e, +0x0001679c, +0x00016799, +0x00016797, +0x00016796, +0x00016793, +0x00016792, +0x00016790, +0x0001678e, +0x0001678c, +0x00016789, +0x00016788, +0x00016787, +0x00016784, +0x00016782, +0x00016780, +0x0001677e, +0x0001677d, +0x0001677a, +0x00016779, +0x00016776, +0x00016774, +0x00016773, +0x00016770, +0x0001676f, +0x0001676c, +0x0001676b, +0x00016769, +0x00016766, +0x00016765, +0x00016762, +0x00016761, +0x0001675f, +0x0001675d, +0x0001675b, +0x00016758, +0x00016757, +0x00016756, +0x00016753, +0x00016751, +0x0001674f, +0x0001674d, +0x0001674c, +0x00016749, +0x00016748, +0x00016745, +0x00016743, +0x00016742, +0x0001673f, +0x0001673e, +0x0001673b, +0x00016739, +0x00016738, +0x00016735, +0x00016734, +0x00016731, +0x00016730, +0x0001672e, +0x0001672b, +0x0001672a, +0x00016727, +0x00016726, +0x00016724, +0x00016722, +0x00016720, +0x0001671d, +0x0001671c, +0x0001671b, +0x00016718, +0x00016716, +0x00016714, +0x00016712, +0x0001670f, +0x0001670e, +0x0001670d, +0x0001670a, +0x00016708, +0x00016706, +0x00016704, +0x00016703, +0x00016700, +0x000166ff, +0x000166fc, +0x000166fa, +0x000166f9, +0x000166f6, +0x000166f5, +0x000166f2, +0x000166f1, +0x000166ef, +0x000166ec, +0x000166eb, +0x000166e8, +0x000166e7, +0x000166e5, +0x000166e3, +0x000166e1, +0x000166de, +0x000166dd, +0x000166dc, +0x000166d9, +0x000166d7, +0x000166d5, +0x000166d3, +0x000166d2, +0x000166cf, +0x000166ce, +0x000166cb, +0x000166c9, +0x000166c8, +0x000166c5, +0x000166c4, +0x000166c1, +0x000166bf, +0x000166be, +0x000166bb, +0x000166ba, +0x000166b7, +0x000166b6, +0x000166b4, +0x000166b1, +0x000166b0, +0x000166ad, +0x000166ac, +0x000166aa, +0x000166a8, +0x000166a6, +0x000166a3, +0x000166a2, +0x000166a1, +0x0001669e, +0x0001669d, +0x0001669a, +0x00016698, +0x00016696, +0x00016694, +0x00016693, +0x00016690, +0x0001668f, +0x0001668c, +0x0001668a, +0x00016689, +0x00016686, +0x00016685, +0x00016682, +0x00016681, +0x0001667f, +0x0001667c, +0x0001667b, +0x00016678, +0x00016677, +0x00016675, +0x00016673, +0x00016671, +0x0001666e, +0x0001666d, +0x0001666c, +0x00016669, +0x00016667, +0x00016665, +0x00016663, +0x00016662, +0x0001665f, +0x0001665e, +0x0001665b, +0x0001665a, +0x00016658, +0x00016655, +0x00016654, +0x00016651, +0x00016650, +0x0001664e, +0x0001664c, +0x0001664a, +0x00016647, +0x00016646, +0x00016645, +0x00016642, +0x00016640, +0x0001663e, +0x0001663c, +0x0001663b, +0x00016638, +0x00016637, +0x00016634, +0x00016632, +0x00016631, +0x0001662e, +0x0001662d, +0x0001662a, +0x00016629, +0x00016627, +0x00016624, +0x00016623, +0x00016620, +0x0001661f, +0x0001661d, +0x0001661b, +0x00016619, +0x00016616, +0x00016615, +0x00016614, +0x00016611, +0x0001660f, +0x0001660d, +0x0001660b, +0x0001660a, +0x00016607, +0x00016606, +0x00016603, +0x00016601, +0x00016600, +0x000165fd, +0x000165fc, +0x000165f9, +0x000165f8, +0x000165f6, +0x000165f3, +0x000165f2, +0x000165ef, +0x000165ee, +0x000165ec, +0x000165ea, +0x000165e8, +0x000165e5, +0x000165e4, +0x000165e3, +0x000165e0, +0x000165de, +0x000165dc, +0x000165da, +0x000165d9, +0x000165d6, +0x000165d5, +0x000165d2, +0x000165d0, +0x000165cf, +0x000165cc, +0x000165cb, +0x000165c8, +0x000165c7, +0x000165c5, +0x000165c2, +0x000165c1, +0x000165be, +0x000165bd, +0x000165bb, +0x000165b9, +0x000165b7, +0x000165b4, +0x000165b3, +0x000165b2, +0x000165af, +0x000165ad, +0x000165ab, +0x000165a9, +0x000165a8, +0x000165a5, +0x000165a4, +0x000165a2, +0x0001659f, +0x0001659e, +0x0001659c, +0x00016599, +0x00016598, +0x00016595, +0x00016594, +0x00016592, +0x00016590, +0x0001658e, +0x0001658b, +0x0001658a, +0x00016589, +0x00016586, +0x00016584, +0x00016582, +0x00016580, +0x0001657f, +0x0001657c, +0x0001657b, +0x00016578, +0x00016577, +0x00016575, +0x00016572, +0x00016571, +0x0001656e, +0x0001656d, +0x0001656b, +0x00016569, +0x00016567, +0x00016566, +0x00016563, +0x00016562, +0x0001655f, +0x0001655d, +0x0001655c, +0x00016559, +0x00016558, +0x00016555, +0x00016554, +0x00016552, +0x0001654f, +0x0001654e, +0x0001654b, +0x0001654a, +0x00016549, +0x00016546, +0x00016544, +0x00016542, +0x00016540, +0x0001653f, +0x0001653c, +0x0001653b, +0x00016538, +0x00016536, +0x00016535, +0x00016532, +0x00016531, +0x0001652e, +0x0001652d, +0x0001652b, +0x00016528, +0x00016527, +0x00016526, +0x00016523, +0x00016521, +0x0001651f, +0x0001651d, +0x0001651c, +0x00016519, +0x00016518, +0x00016515, +0x00016514, +0x00016512, +0x0001650f, +0x0001650e, +0x0001650b, +0x0001650a, +0x00016508, +0x00016506, +0x00016504, +0x00016501, +0x00016500, +0x000164ff, +0x000164fc, +0x000164fa, +0x000164f8, +0x000164f6, +0x000164f5, +0x000164f2, +0x000164f1, +0x000164ee, +0x000164ec, +0x000164eb, +0x000164e8, +0x000164e7, +0x000164e4, +0x000164e3, +0x000164e1, +0x000164df, +0x000164dd, +0x000164dc, +0x000164d9, +0x000164d8, +0x000164d5, +0x000164d3, +0x000164d2, +0x000164cf, +0x000164ce, +0x000164cb, +0x000164ca, +0x000164c8, +0x000164c5, +0x000164c4, +0x000164c1, +0x000164c0, +0x000164be, +0x000164bc, +0x000164ba, +0x000164b7, +0x000164b6, +0x000164b5, +0x000164b2, +0x000164b1, +0x000164ae, +0x000164ac, +0x000164ab, +0x000164a8, +0x000164a7, +0x000164a4, +0x000164a3, +0x000164a0, +0x0001649f, +0x0001649d, +0x0001649a, +0x00016499, +0x00016496, +0x00016495, +0x00016493, +0x00016491, +0x0001648f, +0x0001648e, +0x0001648b, +0x0001648a, +0x00016487, +0x00016486, +0x00016484, +0x00016481, +0x00016480, +0x0001647d, +0x0001647c, +0x0001647a, +0x00016478, +0x00016476, +0x00016473, +0x00016472, +0x00016471, +0x0001646e, +0x0001646c, +0x0001646b, +0x00016468, +0x00016467, +0x00016464, +0x00016463, +0x00016461, +0x0001645f, +0x0001645d, +0x0001645a, +0x00016459, +0x00016458, +0x00016455, +0x00016453, +0x00016451, +0x0001644f, +0x0001644e, +0x0001644b, +0x0001644a, +0x00016447, +0x00016446, +0x00016444, +0x00016441, +0x00016440, +0x0001643f, +0x0001643c, +0x0001643a, +0x00016438, +0x00016436, +0x00016435, +0x00016432, +0x00016431, +0x0001642e, +0x0001642d, +0x0001642b, +0x00016428, +0x00016427, +0x00016424, +0x00016423, +0x00016421, +0x0001641f, +0x0001641d, +0x0001641a, +0x00016419, +0x00016418, +0x00016415, +0x00016413, +0x00016412, +0x0001640f, +0x0001640e, +0x0001640b, +0x0001640a, +0x00016408, +0x00016406, +0x00016404, +0x00016401, +0x00016400, +0x000163ff, +0x000163fc, +0x000163fa, +0x000163f8, +0x000163f6, +0x000163f5, +0x000163f2, +0x000163f1, +0x000163ef, +0x000163ed, +0x000163eb, +0x000163e8, +0x000163e7, +0x000163e6, +0x000163e3, +0x000163e1, +0x000163df, +0x000163dd, +0x000163dc, +0x000163d9, +0x000163d8, +0x000163d5, +0x000163d4, +0x000163d2, +0x000163cf, +0x000163ce, +0x000163cb, +0x000163ca, +0x000163c8, +0x000163c6, +0x000163c4, +0x000163c3, +0x000163c0, +0x000163bf, +0x000163bc, +0x000163ba, +0x000163b9, +0x000163b6, +0x000163b5, +0x000163b2, +0x000163b0, +0x000163af, +0x000163ac, +0x000163ab, +0x000163a9, +0x000163a6, +0x000163a5, +0x000163a4, +0x000163a1, +0x0001639f, +0x0001639d, +0x0001639b, +0x0001639a, +0x00016397, +0x00016396, +0x00016393, +0x00016392, +0x00016390, +0x0001638d, +0x0001638c, +0x0001638b, +0x00016388, +0x00016387, +0x00016384, +0x00016382, +0x00016381, +0x0001637e, +0x0001637d, +0x0001637a, +0x00016379, +0x00016377, +0x00016374, +0x00016373, +0x00016370, +0x0001636f, +0x0001636e, +0x0001636b, +0x00016369, +0x00016368, +0x00016365, +0x00016364, +0x00016361, +0x00016360, +0x0001635e, +0x0001635c, +0x0001635a, +0x00016357, +0x00016356, +0x00016355, +0x00016352, +0x00016350, +0x0001634f, +0x0001634c, +0x0001634b, +0x00016348, +0x00016347, +0x00016345, +0x00016343, +0x00016341, +0x0001633e, +0x0001633d, +0x0001633c, +0x00016339, +0x00016337, +0x00016336, +0x00016333, +0x00016332, +0x0001632f, +0x0001632e, +0x0001632c, +0x0001632a, +0x00016328, +0x00016325, +0x00016324, +0x00016323, +0x00016320, +0x0001631f, +0x0001631c, +0x0001631a, +0x00016319, +0x00016316, +0x00016315, +0x00016313, +0x00016311, +0x0001630f, +0x0001630c, +0x0001630b, +0x0001630a, +0x00016307, +0x00016306, +0x00016303, +0x00016301, +0x00016300, +0x000162fd, +0x000162fc, +0x000162fa, +0x000162f8, +0x000162f6, +0x000162f4, +0x000162f2, +0x000162f1, +0x000162ee, +0x000162ed, +0x000162ea, +0x000162e8, +0x000162e7, +0x000162e4, +0x000162e3, +0x000162e0, +0x000162df, +0x000162dd, +0x000162db, +0x000162d9, +0x000162d8, +0x000162d5, +0x000162d4, +0x000162d1, +0x000162cf, +0x000162ce, +0x000162cb, +0x000162ca, +0x000162c7, +0x000162c6, +0x000162c4, +0x000162c2, +0x000162c0, +0x000162bf, +0x000162bc, +0x000162bb, +0x000162b8, +0x000162b7, +0x000162b4, +0x000162b2, +0x000162b1, +0x000162ae, +0x000162ad, +0x000162aa, +0x000162a9, +0x000162a7, +0x000162a5, +0x000162a3, +0x000162a2, +0x0001629f, +0x0001629e, +0x0001629b, +0x00016299, +0x00016298, +0x00016295, +0x00016294, +0x00016291, +0x00016290, +0x0001628e, +0x0001628c, +0x0001628a, +0x00016289, +0x00016286, +0x00016285, +0x00016282, +0x00016281, +0x0001627f, +0x0001627c, +0x0001627b, +0x00016278, +0x00016277, +0x00016276, +0x00016273, +0x00016271, +0x00016270, +0x0001626d, +0x0001626c, +0x00016269, +0x00016268, +0x00016266, +0x00016264, +0x00016262, +0x00016261, +0x0001625e, +0x0001625d, +0x0001625a, +0x00016259, +0x00016257, +0x00016254, +0x00016253, +0x00016250, +0x0001624f, +0x0001624d, +0x0001624b, +0x00016249, +0x00016248, +0x00016245, +0x00016244, +0x00016241, +0x00016240, +0x0001623e, +0x0001623b, +0x0001623a, +0x00016237, +0x00016236, +0x00016235, +0x00016232, +0x00016230, +0x0001622f, +0x0001622c, +0x0001622b, +0x00016228, +0x00016227, +0x00016225, +0x00016223, +0x00016221, +0x0001621e, +0x0001621d, +0x0001621c, +0x00016219, +0x00016218, +0x00016216, +0x00016213, +0x00016212, +0x0001620f, +0x0001620e, +0x0001620c, +0x0001620a, +0x00016208, +0x00016207, +0x00016204, +0x00016203, +0x00016200, +0x000161ff, +0x000161fd, +0x000161fa, +0x000161f9, +0x000161f6, +0x000161f5, +0x000161f4, +0x000161f1, +0x000161ef, +0x000161ee, +0x000161eb, +0x000161ea, +0x000161e7, +0x000161e6, +0x000161e4, +0x000161e2, +0x000161e0, +0x000161dd, +0x000161dc, +0x000161db, +0x000161d8, +0x000161d7, +0x000161d5, +0x000161d2, +0x000161d1, +0x000161ce, +0x000161cd, +0x000161cb, +0x000161c9, +0x000161c7, +0x000161c5, +0x000161c2, +0x000161c1, +0x000161c0, +0x000161bd, +0x000161bc, +0x000161b9, +0x000161b7, +0x000161b6, +0x000161b3, +0x000161b2, +0x000161b1, +0x000161ae, +0x000161ac, +0x000161aa, +0x000161a8, +0x000161a7, +0x000161a4, +0x000161a3, +0x000161a1, +0x0001619f, +0x0001619d, +0x0001619a, +0x00016199, +0x00016198, +0x00016195, +0x00016194, +0x00016192, +0x0001618f, +0x0001618e, +0x0001618b, +0x0001618a, +0x00016189, +0x00016186, +0x00016184, +0x00016182, +0x00016180, +0x0001617f, +0x0001617c, +0x0001617b, +0x00016179, +0x00016177, +0x00016175, +0x00016172, +0x00016171, +0x00016170, +0x0001616d, +0x0001616c, +0x0001616a, +0x00016167, +0x00016166, +0x00016163, +0x00016162, +0x00016161, +0x0001615e, +0x0001615c, +0x0001615b, +0x00016158, +0x00016157, +0x00016154, +0x00016153, +0x00016151, +0x0001614f, +0x0001614d, +0x0001614c, +0x00016149, +0x00016148, +0x00016145, +0x00016144, +0x00016142, +0x0001613f, +0x0001613e, +0x0001613b, +0x0001613a, +0x00016139, +0x00016136, +0x00016134, +0x00016133, +0x00016130, +0x0001612f, +0x0001612c, +0x0001612b, +0x00016129, +0x00016127, +0x00016125, +0x00016124, +0x00016121, +0x00016120, +0x0001611d, +0x0001611c, +0x0001611a, +0x00016117, +0x00016116, +0x00016115, +0x00016112, +0x00016111, +0x0001610e, +0x0001610c, +0x0001610b, +0x00016108, +0x00016107, +0x00016104, +0x00016103, +0x00016101, +0x000160ff, +0x000160fd, +0x000160fc, +0x000160f9, +0x000160f8, +0x000160f5, +0x000160f4, +0x000160f2, +0x000160ef, +0x000160ee, +0x000160ed, +0x000160ea, +0x000160e9, +0x000160e6, +0x000160e4, +0x000160e3, +0x000160e0, +0x000160df, +0x000160de, +0x000160db, +0x000160d9, +0x000160d7, +0x000160d5, +0x000160d4, +0x000160d1, +0x000160d0, +0x000160cd, +0x000160cc, +0x000160ca, +0x000160c7, +0x000160c6, +0x000160c3, +0x000160c2, +0x000160c1, +0x000160be, +0x000160bc, +0x000160bb, +0x000160b8, +0x000160b7, +0x000160b4, +0x000160b3, +0x000160b1, +0x000160af, +0x000160ad, +0x000160ac, +0x000160a9, +0x000160a8, +0x000160a5, +0x000160a4, +0x000160a2, +0x000160a0, +0x0001609e, +0x0001609d, +0x0001609a, +0x00016099, +0x00016096, +0x00016095, +0x00016093, +0x00016090, +0x0001608f, +0x0001608e, +0x0001608b, +0x0001608a, +0x00016087, +0x00016085, +0x00016084, +0x00016081, +0x00016080, +0x0001607f, +0x0001607c, +0x0001607a, +0x00016078, +0x00016076, +0x00016075, +0x00016072, +0x00016071, +0x0001606f, +0x0001606d, +0x0001606b, +0x00016069, +0x00016067, +0x00016066, +0x00016063, +0x00016062, +0x00016060, +0x0001605e, +0x0001605c, +0x00016059, +0x00016058, +0x00016057, +0x00016054, +0x00016053, +0x00016051, +0x0001604e, +0x0001604d, +0x0001604a, +0x00016049, +0x00016048, +0x00016045, +0x00016043, +0x00016042, +0x0001603f, +0x0001603e, +0x0001603b, +0x0001603a, +0x00016038, +0x00016036, +0x00016034, +0x00016033, +0x00016030, +0x0001602f, +0x0001602c, +0x0001602b, +0x00016029, +0x00016027, +0x00016025, +0x00016024, +0x00016021, +0x00016020, +0x0001601d, +0x0001601c, +0x0001601a, +0x00016017, +0x00016016, +0x00016015, +0x00016012, +0x00016011, +0x0001600e, +0x0001600c, +0x0001600b, +0x00016008, +0x00016007, +0x00016006, +0x00016003, +0x00016001, +0x00015fff, +0x00015ffd, +0x00015ffc, +0x00015ff9, +0x00015ff8, +0x00015ff6, +0x00015ff4, +0x00015ff2, +0x00015ff0, +0x00015fee, +0x00015fed, +0x00015fea, +0x00015fe9, +0x00015fe7, +0x00015fe5, +0x00015fe3, +0x00015fe0, +0x00015fde, +0x00015fdd, +0x00015fdb, +0x00015fd9, +0x00015fd7, +0x00015fd5, +0x00015fd3, +0x00015fd2, +0x00015fcf, +0x00015fce, +0x00015fcc, +0x00015fca, +0x00015fc8, +0x00015fc5, +0x00015fc4, +0x00015fc3, +0x00015fc0, +0x00015fbf, +0x00015fbd, +0x00015fba, +0x00015fb9, +0x00015fb6, +0x00015fb5, +0x00015fb4, +0x00015fb1, +0x00015fb0, +0x00015fae, +0x00015fab, +0x00015faa, +0x00015fa7, +0x00015fa6, +0x00015fa5, +0x00015fa2, +0x00015fa0, +0x00015f9f, +0x00015f9c, +0x00015f9b, +0x00015f9a, +0x00015f97, +0x00015f95, +0x00015f93, +0x00015f91, +0x00015f90, +0x00015f8d, +0x00015f8c, +0x00015f8a, +0x00015f88, +0x00015f86, +0x00015f84, +0x00015f82, +0x00015f81, +0x00015f7e, +0x00015f7d, +0x00015f7b, +0x00015f79, +0x00015f77, +0x00015f75, +0x00015f73, +0x00015f72, +0x00015f6f, +0x00015f6e, +0x00015f6c, +0x00015f6a, +0x00015f68, +0x00015f67, +0x00015f64, +0x00015f63, +0x00015f60, +0x00015f5f, +0x00015f5d, +0x00015f5a, +0x00015f59, +0x00015f58, +0x00015f55, +0x00015f54, +0x00015f51, +0x00015f50, +0x00015f4e, +0x00015f4b, +0x00015f4a, +0x00015f49, +0x00015f46, +0x00015f45, +0x00015f42, +0x00015f40, +0x00015f3f, +0x00015f3c, +0x00015f3b, +0x00015f3a, +0x00015f37, +0x00015f35, +0x00015f33, +0x00015f31, +0x00015f30, +0x00015f2d, +0x00015f2c, +0x00015f2b, +0x00015f28, +0x00015f26, +0x00015f25, +0x00015f22, +0x00015f21, +0x00015f1e, +0x00015f1d, +0x00015f1b, +0x00015f19, +0x00015f17, +0x00015f16, +0x00015f13, +0x00015f12, +0x00015f0f, +0x00015f0e, +0x00015f0c, +0x00015f0a, +0x00015f08, +0x00015f07, +0x00015f04, +0x00015f03, +0x00015f00, +0x00015eff, +0x00015efd, +0x00015efb, +0x00015ef9, +0x00015ef8, +0x00015ef5, +0x00015ef4, +0x00015ef1, +0x00015ef0, +0x00015eee, +0x00015eeb, +0x00015eea, +0x00015ee7, +0x00015ee6, +0x00015ee4, +0x00015ee2, +0x00015ee0, +0x00015edf, +0x00015edc, +0x00015edb, +0x00015ed8, +0x00015ed7, +0x00015ed5, +0x00015ed3, +0x00015ed1, +0x00015ed0, +0x00015ecd, +0x00015ecc, +0x00015eca, +0x00015ec8, +0x00015ec6, +0x00015ec4, +0x00015ec2, +0x00015ec1, +0x00015ebe, +0x00015ebd, +0x00015ebb, +0x00015eb9, +0x00015eb7, +0x00015eb4, +0x00015eb3, +0x00015eb2, +0x00015eaf, +0x00015eae, +0x00015eac, +0x00015eaa, +0x00015ea8, +0x00015ea7, +0x00015ea4, +0x00015ea3, +0x00015ea0, +0x00015e9f, +0x00015e9d, +0x00015e9a, +0x00015e99, +0x00015e98, +0x00015e95, +0x00015e94, +0x00015e92, +0x00015e90, +0x00015e8e, +0x00015e8b, +0x00015e8a, +0x00015e89, +0x00015e86, +0x00015e85, +0x00015e83, +0x00015e81, +0x00015e7f, +0x00015e7c, +0x00015e7b, +0x00015e7a, +0x00015e77, +0x00015e76, +0x00015e74, +0x00015e71, +0x00015e70, +0x00015e6f, +0x00015e6c, +0x00015e6b, +0x00015e68, +0x00015e67, +0x00015e65, +0x00015e62, +0x00015e61, +0x00015e60, +0x00015e5d, +0x00015e5c, +0x00015e59, +0x00015e58, +0x00015e56, +0x00015e53, +0x00015e52, +0x00015e51, +0x00015e4e, +0x00015e4d, +0x00015e4b, +0x00015e48, +0x00015e47, +0x00015e44, +0x00015e43, +0x00015e42, +0x00015e3f, +0x00015e3e, +0x00015e3c, +0x00015e39, +0x00015e38, +0x00015e37, +0x00015e34, +0x00015e33, +0x00015e30, +0x00015e2e, +0x00015e2d, +0x00015e2a, +0x00015e29, +0x00015e28, +0x00015e25, +0x00015e24, +0x00015e21, +0x00015e1f, +0x00015e1e, +0x00015e1b, +0x00015e1a, +0x00015e19, +0x00015e16, +0x00015e15, +0x00015e13, +0x00015e10, +0x00015e0f, +0x00015e0c, +0x00015e0b, +0x00015e0a, +0x00015e07, +0x00015e05, +0x00015e04, +0x00015e01, +0x00015e00, +0x00015dff, +0x00015dfc, +0x00015dfb, +0x00015df8, +0x00015df6, +0x00015df5, +0x00015df2, +0x00015df1, +0x00015df0, +0x00015ded, +0x00015deb, +0x00015de9, +0x00015de7, +0x00015de6, +0x00015de3, +0x00015de2, +0x00015de1, +0x00015dde, +0x00015ddc, +0x00015ddb, +0x00015dd8, +0x00015dd7, +0x00015dd4, +0x00015dd3, +0x00015dd2, +0x00015dcf, +0x00015dcd, +0x00015dcc, +0x00015dc9, +0x00015dc8, +0x00015dc5, +0x00015dc4, +0x00015dc2, +0x00015dc0, +0x00015dbe, +0x00015dbd, +0x00015dba, +0x00015db9, +0x00015db8, +0x00015db5, +0x00015db3, +0x00015db1, +0x00015daf, +0x00015dae, +0x00015dab, +0x00015daa, +0x00015da9, +0x00015da6, +0x00015da4, +0x00015da3, +0x00015da0, +0x00015d9f, +0x00015d9c, +0x00015d9b, +0x00015d99, +0x00015d97, +0x00015d95, +0x00015d94, +0x00015d91, +0x00015d90, +0x00015d8d, +0x00015d8c, +0x00015d8a, +0x00015d88, +0x00015d86, +0x00015d85, +0x00015d82, +0x00015d81, +0x00015d7f, +0x00015d7d, +0x00015d7b, +0x00015d79, +0x00015d77, +0x00015d76, +0x00015d73, +0x00015d72, +0x00015d70, +0x00015d6e, +0x00015d6c, +0x00015d6a, +0x00015d68, +0x00015d67, +0x00015d64, +0x00015d63, +0x00015d61, +0x00015d5f, +0x00015d5d, +0x00015d5c, +0x00015d59, +0x00015d58, +0x00015d55, +0x00015d54, +0x00015d52, +0x00015d50, +0x00015d4e, +0x00015d4d, +0x00015d4a, +0x00015d49, +0x00015d47, +0x00015d45, +0x00015d43, +0x00015d41, +0x00015d3f, +0x00015d3e, +0x00015d3b, +0x00015d3a, +0x00015d38, +0x00015d36, +0x00015d34, +0x00015d32, +0x00015d30, +0x00015d2f, +0x00015d2c, +0x00015d2b, +0x00015d29, +0x00015d27, +0x00015d25, +0x00015d24, +0x00015d21, +0x00015d20, +0x00015d1d, +0x00015d1c, +0x00015d1a, +0x00015d18, +0x00015d16, +0x00015d15, +0x00015d12, +0x00015d11, +0x00015d0f, +0x00015d0e, +0x00015d0c, +0x00015d0a, +0x00015d08, +0x00015d05, +0x00015d04, +0x00015d03, +0x00015d00, +0x00015cff, +0x00015cfd, +0x00015cfb, +0x00015cf9, +0x00015cf8, +0x00015cf5, +0x00015cf4, +0x00015cf1, +0x00015cf0, +0x00015cee, +0x00015cec, +0x00015cea, +0x00015ce9, +0x00015ce6, +0x00015ce5, +0x00015ce3, +0x00015ce1, +0x00015cdf, +0x00015cdd, +0x00015cdb, +0x00015cda, +0x00015cd7, +0x00015cd6, +0x00015cd4, +0x00015cd2, +0x00015cd0, +0x00015ccf, +0x00015ccc, +0x00015ccb, +0x00015cc8, +0x00015cc7, +0x00015cc5, +0x00015cc3, +0x00015cc1, +0x00015cc0, +0x00015cbd, +0x00015cbc, +0x00015cba, +0x00015cb8, +0x00015cb6, +0x00015cb4, +0x00015cb2, +0x00015cb1, +0x00015cae, +0x00015cad, +0x00015cab, +0x00015ca9, +0x00015ca7, +0x00015ca6, +0x00015ca3, +0x00015ca2, +0x00015c9f, +0x00015c9e, +0x00015c9c, +0x00015c9a, +0x00015c98, +0x00015c97, +0x00015c94, +0x00015c93, +0x00015c92, +0x00015c8f, +0x00015c8d, +0x00015c8b, +0x00015c89, +0x00015c88, +0x00015c85, +0x00015c84, +0x00015c83, +0x00015c80, +0x00015c7e, +0x00015c7d, +0x00015c7a, +0x00015c79, +0x00015c76, +0x00015c75, +0x00015c74, +0x00015c71, +0x00015c6f, +0x00015c6e, +0x00015c6b, +0x00015c6a, +0x00015c69, +0x00015c66, +0x00015c65, +0x00015c62, +0x00015c60, +0x00015c5f, +0x00015c5c, +0x00015c5b, +0x00015c5a, +0x00015c57, +0x00015c56, +0x00015c54, +0x00015c52, +0x00015c50, +0x00015c4d, +0x00015c4c, +0x00015c4b, +0x00015c48, +0x00015c47, +0x00015c45, +0x00015c43, +0x00015c41, +0x00015c40, +0x00015c3d, +0x00015c3c, +0x00015c39, +0x00015c38, +0x00015c36, +0x00015c34, +0x00015c32, +0x00015c31, +0x00015c2e, +0x00015c2d, +0x00015c2b, +0x00015c29, +0x00015c27, +0x00015c25, +0x00015c23, +0x00015c22, +0x00015c21, +0x00015c1e, +0x00015c1d, +0x00015c1b, +0x00015c18, +0x00015c17, +0x00015c14, +0x00015c13, +0x00015c12, +0x00015c0f, +0x00015c0e, +0x00015c0c, +0x00015c0a, +0x00015c08, +0x00015c07, +0x00015c04, +0x00015c03, +0x00015c01, +0x00015bff, +0x00015bfd, +0x00015bfb, +0x00015bf9, +0x00015bf8, +0x00015bf5, +0x00015bf4, +0x00015bf2, +0x00015bf0, +0x00015bee, +0x00015bed, +0x00015bea, +0x00015be9, +0x00015be8, +0x00015be5, +0x00015be3, +0x00015be1, +0x00015bdf, +0x00015bde, +0x00015bdb, +0x00015bda, +0x00015bd9, +0x00015bd6, +0x00015bd5, +0x00015bd3, +0x00015bd0, +0x00015bcf, +0x00015bcc, +0x00015bcb, +0x00015bca, +0x00015bc7, +0x00015bc6, +0x00015bc4, +0x00015bc1, +0x00015bc0, +0x00015bbf, +0x00015bbc, +0x00015bbb, +0x00015bb9, +0x00015bb7, +0x00015bb5, +0x00015bb3, +0x00015bb1, +0x00015bb0, +0x00015bad, +0x00015bac, +0x00015baa, +0x00015ba8, +0x00015ba6, +0x00015ba5, +0x00015ba2, +0x00015ba1, +0x00015b9e, +0x00015b9d, +0x00015b9b, +0x00015b99, +0x00015b97, +0x00015b96, +0x00015b93, +0x00015b92, +0x00015b91, +0x00015b8e, +0x00015b8c, +0x00015b8b, +0x00015b88, +0x00015b87, +0x00015b84, +0x00015b83, +0x00015b82, +0x00015b7f, +0x00015b7e, +0x00015b7c, +0x00015b79, +0x00015b78, +0x00015b77, +0x00015b74, +0x00015b73, +0x00015b71, +0x00015b6f, +0x00015b6d, +0x00015b6a, +0x00015b69, +0x00015b68, +0x00015b65, +0x00015b64, +0x00015b62, +0x00015b60, +0x00015b5e, +0x00015b5d, +0x00015b5a, +0x00015b59, +0x00015b56, +0x00015b55, +0x00015b53, +0x00015b51, +0x00015b4f, +0x00015b4e, +0x00015b4b, +0x00015b4a, +0x00015b48, +0x00015b46, +0x00015b44, +0x00015b43, +0x00015b40, +0x00015b3f, +0x00015b3c, +0x00015b3b, +0x00015b3a, +0x00015b37, +0x00015b36, +0x00015b34, +0x00015b32, +0x00015b31, +0x00015b2e, +0x00015b2d, +0x00015b2b, +0x00015b29, +0x00015b27, +0x00015b26, +0x00015b23, +0x00015b22, +0x00015b1f, +0x00015b1e, +0x00015b1c, +0x00015b1a, +0x00015b18, +0x00015b17, +0x00015b14, +0x00015b13, +0x00015b12, +0x00015b0f, +0x00015b0e, +0x00015b0c, +0x00015b09, +0x00015b08, +0x00015b07, +0x00015b04, +0x00015b03, +0x00015b00, +0x00015aff, +0x00015afd, +0x00015afb, +0x00015af9, +0x00015af8, +0x00015af5, +0x00015af4, +0x00015af2, +0x00015af0, +0x00015aee, +0x00015aed, +0x00015aea, +0x00015ae9, +0x00015ae6, +0x00015ae5, +0x00015ae4, +0x00015ae1, +0x00015adf, +0x00015ade, +0x00015adb, +0x00015ada, +0x00015ad9, +0x00015ad6, +0x00015ad5, +0x00015ad3, +0x00015ad1, +0x00015acf, +0x00015acc, +0x00015acb, +0x00015aca, +0x00015ac7, +0x00015ac6, +0x00015ac4, +0x00015ac2, +0x00015ac0, +0x00015abf, +0x00015abc, +0x00015abb, +0x00015aba, +0x00015ab7, +0x00015ab5, +0x00015ab4, +0x00015ab1, +0x00015ab0, +0x00015aad, +0x00015aac, +0x00015aab, +0x00015aa8, +0x00015aa7, +0x00015aa5, +0x00015aa2, +0x00015aa1, +0x00015aa0, +0x00015a9d, +0x00015a9c, +0x00015a9a, +0x00015a98, +0x00015a96, +0x00015a94, +0x00015a92, +0x00015a91, +0x00015a8e, +0x00015a8d, +0x00015a8b, +0x00015a89, +0x00015a87, +0x00015a86, +0x00015a83, +0x00015a82, +0x00015a81, +0x00015a7e, +0x00015a7d, +0x00015a7a, +0x00015a78, +0x00015a77, +0x00015a74, +0x00015a73, +0x00015a72, +0x00015a6f, +0x00015a6e, +0x00015a6c, +0x00015a6a, +0x00015a68, +0x00015a67, +0x00015a64, +0x00015a63, +0x00015a61, +0x00015a5f, +0x00015a5d, +0x00015a5b, +0x00015a59, +0x00015a58, +0x00015a55, +0x00015a54, +0x00015a53, +0x00015a50, +0x00015a4e, +0x00015a4d, +0x00015a4c, +0x00015a49, +0x00015a48, +0x00015a45, +0x00015a44, +0x00015a42, +0x00015a40, +0x00015a3e, +0x00015a3d, +0x00015a3a, +0x00015a39, +0x00015a37, +0x00015a35, +0x00015a33, +0x00015a32, +0x00015a2f, +0x00015a2e, +0x00015a2d, +0x00015a2a, +0x00015a29, +0x00015a26, +0x00015a24, +0x00015a23, +0x00015a20, +0x00015a1f, +0x00015a1e, +0x00015a1b, +0x00015a1a, +0x00015a18, +0x00015a16, +0x00015a14, +0x00015a13, +0x00015a10, +0x00015a0f, +0x00015a0e, +0x00015a0b, +0x00015a09, +0x00015a07, +0x00015a05, +0x00015a04, +0x00015a01, +0x00015a00, +0x000159ff, +0x000159fc, +0x000159fb, +0x000159f9, +0x000159f7, +0x000159f5, +0x000159f4, +0x000159f1, +0x000159f0, +0x000159ee, +0x000159ec, +0x000159ea, +0x000159e9, +0x000159e6, +0x000159e5, +0x000159e2, +0x000159e1, +0x000159e0, +0x000159dd, +0x000159dc, +0x000159da, +0x000159d7, +0x000159d6, +0x000159d5, +0x000159d2, +0x000159d1, +0x000159cf, +0x000159cd, +0x000159cb, +0x000159ca, +0x000159c7, +0x000159c6, +0x000159c3, +0x000159c2, +0x000159c0, +0x000159be, +0x000159bc, +0x000159bb, +0x000159b8, +0x000159b7, +0x000159b6, +0x000159b3, +0x000159b2, +0x000159b0, +0x000159ae, +0x000159ac, +0x000159ab, +0x000159a8, +0x000159a7, +0x000159a5, +0x000159a3, +0x000159a1, +0x0001599f, +0x0001599d, +0x0001599c, +0x00015999, +0x00015998, +0x00015997, +0x00015994, +0x00015993, +0x00015991, +0x0001598e, +0x0001598d, +0x0001598c, +0x00015989, +0x00015988, +0x00015986, +0x00015984, +0x00015982, +0x00015980, +0x0001597e, +0x0001597d, +0x0001597a, +0x00015979, +0x00015977, +0x00015975, +0x00015973, +0x00015972, +0x0001596f, +0x0001596e, +0x0001596d, +0x0001596a, +0x00015969, +0x00015967, +0x00015965, +0x00015963, +0x00015961, +0x00015960, +0x0001595e, +0x0001595c, +0x0001595a, +0x00015959, +0x00015956, +0x00015955, +0x00015952, +0x00015951, +0x00015950, +0x0001594d, +0x0001594b, +0x0001594a, +0x00015947, +0x00015946, +0x00015945, +0x00015942, +0x00015941, +0x0001593f, +0x0001593d, +0x0001593b, +0x0001593a, +0x00015937, +0x00015936, +0x00015935, +0x00015932, +0x00015931, +0x0001592f, +0x0001592c, +0x0001592b, +0x00015928, +0x00015927, +0x00015926, +0x00015923, +0x00015922, +0x00015920, +0x0001591e, +0x0001591c, +0x0001591b, +0x00015918, +0x00015917, +0x00015916, +0x00015913, +0x00015912, +0x00015910, +0x0001590d, +0x0001590c, +0x0001590b, +0x00015908, +0x00015907, +0x00015905, +0x00015903, +0x00015901, +0x000158ff, +0x000158fd, +0x000158fc, +0x000158f9, +0x000158f8, +0x000158f7, +0x000158f4, +0x000158f3, +0x000158f1, +0x000158ee, +0x000158ed, +0x000158ec, +0x000158e9, +0x000158e8, +0x000158e6, +0x000158e4, +0x000158e2, +0x000158e1, +0x000158de, +0x000158dd, +0x000158dc, +0x000158d9, +0x000158d8, +0x000158d5, +0x000158d4, +0x000158d2, +0x000158cf, +0x000158ce, +0x000158cd, +0x000158ca, +0x000158c9, +0x000158c7, +0x000158c5, +0x000158c3, +0x000158c2, +0x000158bf, +0x000158be, +0x000158bd, +0x000158ba, +0x000158b9, +0x000158b7, +0x000158b5, +0x000158b3, +0x000158b2, +0x000158af, +0x000158ae, +0x000158ab, +0x000158aa, +0x000158a8, +0x000158a6, +0x000158a4, +0x000158a3, +0x000158a0, +0x0001589f, +0x0001589e, +0x0001589b, +0x0001589a, +0x00015898, +0x00015896, +0x00015894, +0x00015893, +0x00015890, +0x0001588f, +0x0001588d, +0x0001588b, +0x00015889, +0x00015888, +0x00015885, +0x00015884, +0x00015881, +0x00015880, +0x0001587f, +0x0001587c, +0x0001587b, +0x00015879, +0x00015878, +0x00015875, +0x00015874, +0x00015872, +0x00015870, +0x0001586e, +0x0001586d, +0x0001586a, +0x00015869, +0x00015867, +0x00015865, +0x00015863, +0x00015862, +0x0001585f, +0x0001585e, +0x0001585d, +0x0001585a, +0x00015859, +0x00015856, +0x00015855, +0x00015853, +0x00015851, +0x0001584f, +0x0001584e, +0x0001584b, +0x0001584a, +0x00015849, +0x00015846, +0x00015845, +0x00015843, +0x00015841, +0x0001583f, +0x0001583e, +0x0001583b, +0x0001583a, +0x00015838, +0x00015836, +0x00015834, +0x00015833, +0x00015830, +0x0001582f, +0x0001582e, +0x0001582b, +0x0001582a, +0x00015828, +0x00015826, +0x00015824, +0x00015823, +0x00015820, +0x0001581f, +0x0001581c, +0x0001581b, +0x0001581a, +0x00015817, +0x00015816, +0x00015814, +0x00015811, +0x00015810, +0x0001580f, +0x0001580c, +0x0001580b, +0x00015809, +0x00015807, +0x00015805, +0x00015804, +0x00015801, +0x00015800, +0x000157ff, +0x000157fc, +0x000157fb, +0x000157f9, +0x000157f7, +0x000157f5, +0x000157f4, +0x000157f1, +0x000157f0, +0x000157ef, +0x000157ec, +0x000157eb, +0x000157e9, +0x000157e6, +0x000157e5, +0x000157e2, +0x000157e1, +0x000157e0, +0x000157dd, +0x000157dc, +0x000157da, +0x000157d8, +0x000157d6, +0x000157d5, +0x000157d2, +0x000157d1, +0x000157d0, +0x000157cd, +0x000157cc, +0x000157ca, +0x000157c8, +0x000157c6, +0x000157c5, +0x000157c2, +0x000157c1, +0x000157c0, +0x000157bd, +0x000157bb, +0x000157ba, +0x000157b7, +0x000157b6, +0x000157b5, +0x000157b2, +0x000157b1, +0x000157af, +0x000157ad, +0x000157ab, +0x000157a9, +0x000157a7, +0x000157a6, +0x000157a3, +0x000157a2, +0x000157a1, +0x0001579e, +0x0001579d, +0x0001579b, +0x00015799, +0x00015797, +0x00015796, +0x00015793, +0x00015792, +0x0001578f, +0x0001578e, +0x0001578d, +0x0001578a, +0x00015789, +0x00015787, +0x00015785, +0x00015783, +0x00015782, +0x0001577f, +0x0001577e, +0x0001577d, +0x0001577a, +0x00015779, +0x00015777, +0x00015775, +0x00015773, +0x00015772, +0x0001576f, +0x0001576e, +0x0001576d, +0x0001576a, +0x00015769, +0x00015767, +0x00015764, +0x00015763, +0x00015762, +0x0001575f, +0x0001575e, +0x0001575c, +0x0001575a, +0x00015758, +0x00015757, +0x00015754, +0x00015753, +0x00015752, +0x0001574f, +0x0001574e, +0x0001574b, +0x0001574a, +0x00015748, +0x00015746, +0x00015744, +0x00015743, +0x00015740, +0x0001573f, +0x0001573e, +0x0001573b, +0x0001573a, +0x00015738, +0x00015736, +0x00015734, +0x00015733, +0x00015730, +0x0001572f, +0x0001572e, +0x0001572b, +0x0001572a, +0x00015728, +0x00015726, +0x00015724, +0x00015723, +0x00015720, +0x0001571f, +0x0001571d, +0x0001571b, +0x00015719, +0x00015718, +0x00015715, +0x00015714, +0x00015713, +0x00015710, +0x0001570f, +0x0001570d, +0x0001570b, +0x00015709, +0x00015708, +0x00015705, +0x00015704, +0x00015703, +0x00015700, +0x000156ff, +0x000156fd, +0x000156fb, +0x000156f9, +0x000156f8, +0x000156f5, +0x000156f4, +0x000156f3, +0x000156f0, +0x000156ef, +0x000156ec, +0x000156eb, +0x000156e9, +0x000156e7, +0x000156e5, +0x000156e4, +0x000156e1, +0x000156e0, +0x000156df, +0x000156dc, +0x000156da, +0x000156d9, +0x000156d6, +0x000156d5, +0x000156d4, +0x000156d1, +0x000156d0, +0x000156ce, +0x000156cc, +0x000156ca, +0x000156c9, +0x000156c6, +0x000156c5, +0x000156c4, +0x000156c1, +0x000156c0, +0x000156be, +0x000156bc, +0x000156ba, +0x000156b9, +0x000156b6, +0x000156b5, +0x000156b4, +0x000156b1, +0x000156b0, +0x000156ae, +0x000156ac, +0x000156aa, +0x000156a8, +0x000156a6, +0x000156a4, +0x000156a3, +0x000156a0, +0x0001569f, +0x0001569e, +0x0001569b, +0x0001569a, +0x00015698, +0x00015696, +0x00015694, +0x00015693, +0x00015690, +0x0001568f, +0x0001568e, +0x0001568b, +0x0001568a, +0x00015688, +0x00015686, +0x00015684, +0x00015683, +0x00015680, +0x0001567f, +0x0001567e, +0x0001567b, +0x0001567a, +0x00015678, +0x00015676, +0x00015674, +0x00015673, +0x00015670, +0x0001566f, +0x0001566e, +0x0001566b, +0x0001566a, +0x00015668, +0x00015666, +0x00015664, +0x00015663, +0x00015660, +0x0001565f, +0x0001565e, +0x0001565b, +0x0001565a, +0x00015658, +0x00015656, +0x00015654, +0x00015653, +0x00015650, +0x0001564f, +0x0001564d, +0x0001564b, +0x00015649, +0x00015648, +0x00015645, +0x00015644, +0x00015643, +0x00015640, +0x0001563f, +0x0001563d, +0x0001563b, +0x00015639, +0x00015638, +0x00015635, +0x00015634, +0x00015633, +0x00015630, +0x0001562f, +0x0001562d, +0x0001562b, +0x00015629, +0x00015628, +0x00015625, +0x00015624, +0x00015623, +0x00015620, +0x0001561f, +0x0001561d, +0x0001561b, +0x00015619, +0x00015618, +0x00015615, +0x00015614, +0x00015613, +0x00015610, +0x0001560f, +0x0001560d, +0x0001560b, +0x00015609, +0x00015608, +0x00015605, +0x00015604, +0x00015603, +0x00015600, +0x000155ff, +0x000155fd, +0x000155fb, +0x000155f9, +0x000155f8, +0x000155f5, +0x000155f4, +0x000155f3, +0x000155f0, +0x000155ef, +0x000155ed, +0x000155eb, +0x000155e9, +0x000155e8, +0x000155e5, +0x000155e4, +0x000155e3, +0x000155e0, +0x000155df, +0x000155dd, +0x000155db, +0x000155d9, +0x000155d8, +0x000155d5, +0x000155d4, +0x000155d3, +0x000155d0, +0x000155cf, +0x000155cd, +0x000155cb, +0x000155c9, +0x000155c6, +0x000155c5, +0x000155c4, +0x000155c1, +0x000155c0, +0x000155be, +0x000155bc, +0x000155ba, +0x000155b9, +0x000155b6, +0x000155b5, +0x000155b4, +0x000155b1, +0x000155b0, +0x000155ae, +0x000155ac, +0x000155ab, +0x000155a9, +0x000155a7, +0x000155a5, +0x000155a4, +0x000155a1, +0x000155a0, +0x0001559f, +0x0001559c, +0x0001559b, +0x00015599, +0x00015597, +0x00015595, +0x00015594, +0x00015591, +0x00015590, +0x0001558f, +0x0001558c, +0x0001558b, +0x00015589, +0x00015587, +0x00015585, +0x00015584, +0x00015581, +0x00015580, +0x0001557f, +0x0001557c, +0x0001557b, +0x00015579, +0x00015577, +0x00015575, +0x00015574, +0x00015571, +0x00015570, +0x0001556f, +0x0001556c, +0x0001556b, +0x00015569, +0x00015567, +0x00015565, +0x00015564, +0x00015561, +0x00015560, +0x0001555f, +0x0001555c, +0x0001555b, +0x00015559, +0x00015557, +0x00015555, +0x00015554, +0x00015551, +0x00015550, +0x0001554f, +0x0001554c, +0x0001554b, +0x00015549, +0x00015547, +0x00015545, +0x00015544, +0x00015541, +0x00015540, +0x0001553f, +0x0001553c, +0x0001553b, +0x00015539, +0x00015537, +0x00015535, +0x00015534, +0x00015531, +0x00015530, +0x0001552f, +0x0001552c, +0x0001552b, +0x00015529, +0x00015527, +0x00015525, +0x00015524, +0x00015521, +0x00015520, +0x0001551f, +0x0001551c, +0x0001551b, +0x00015519, +0x00015517, +0x00015515, +0x00015514, +0x00015511, +0x00015510, +0x0001550f, +0x0001550c, +0x0001550b, +0x00015509, +0x00015507, +0x00015505, +0x00015504, +0x00015501, +0x00015500, +0x000154ff, +0x000154fc, +0x000154fb, +0x000154f9, +0x000154f7, +0x000154f5, +0x000154f4, +0x000154f1, +0x000154f0, +0x000154ef, +0x000154ec, +0x000154eb, +0x000154e9, +0x000154e7, +0x000154e5, +0x000154e3, +0x000154e2, +0x000154df, +0x000154de, +0x000154dc, +0x000154da, +0x000154d8, +0x000154d7, +0x000154d5, +0x000154d3, +0x000154d2, +0x000154cf, +0x000154ce, +0x000154cd, +0x000154ca, +0x000154c9, +0x000154c7, +0x000154c5, +0x000154c3, +0x000154c2, +0x000154bf, +0x000154be, +0x000154bd, +0x000154ba, +0x000154b9, +0x000154b7, +0x000154b5, +0x000154b3, +0x000154b2, +0x000154af, +0x000154ae, +0x000154ad, +0x000154ab, +0x000154a9, +0x000154a7, +0x000154a6, +0x000154a3, +0x000154a2, +0x000154a1, +0x0001549e, +0x0001549d, +0x0001549b, +0x00015499, +0x00015497, +0x00015496, +0x00015493, +0x00015492, +0x00015491, +0x0001548e, +0x0001548d, +0x0001548b, +0x00015489, +0x00015487, +0x00015486, +0x00015483, +0x00015482, +0x00015481, +0x0001547e, +0x0001547d, +0x0001547c, +0x00015479, +0x00015478, +0x00015476, +0x00015474, +0x00015472, +0x00015471, +0x0001546e, +0x0001546d, +0x0001546c, +0x00015469, +0x00015468, +0x00015466, +0x00015464, +0x00015462, +0x00015461, +0x0001545e, +0x0001545d, +0x0001545c, +0x00015459, +0x00015458, +0x00015456, +0x00015454, +0x00015452, +0x00015451, +0x0001544e, +0x0001544d, +0x0001544c, +0x00015449, +0x00015448, +0x00015446, +0x00015444, +0x00015442, +0x00015441, +0x0001543e, +0x0001543d, +0x0001543c, +0x0001543a, +0x00015438, +0x00015436, +0x00015435, +0x00015432, +0x00015431, +0x00015430, +0x0001542d, +0x0001542c, +0x0001542b, +0x00015428, +0x00015427, +0x00015425, +0x00015423, +0x00015421, +0x00015420, +0x0001541d, +0x0001541c, +0x0001541b, +0x00015418, +0x00015417, +0x00015415, +0x00015413, +0x00015411, +0x00015410, +0x0001540d, +0x0001540c, +0x0001540b, +0x00015408, +0x00015407, +0x00015405, +0x00015403, +0x00015401, +0x00015400, +0x000153fd, +0x000153fc, +0x000153fb, +0x000153f8, +0x000153f7, +0x000153f5, +0x000153f3, +0x000153f1, +0x000153f0, +0x000153ed, +0x000153ec, +0x000153eb, +0x000153e8, +0x000153e7, +0x000153e5, +0x000153e3, +0x000153e1, +0x000153e0, +0x000153dd, +0x000153dc, +0x000153db, +0x000153d8, +0x000153d7, +0x000153d6, +0x000153d3, +0x000153d2, +0x000153d0, +0x000153ce, +0x000153cc, +0x000153cb, +0x000153ca, +0x000153c7, +0x000153c6, +0x000153c4, +0x000153c2, +0x000153c0, +0x000153bf, +0x000153bc, +0x000153bb, +0x000153ba, +0x000153b7, +0x000153b6, +0x000153b4, +0x000153b2, +0x000153b0, +0x000153af, +0x000153ac, +0x000153ab, +0x000153aa, +0x000153a7, +0x000153a6, +0x000153a4, +0x000153a2, +0x000153a0, +0x0001539f, +0x0001539c, +0x0001539b, +0x0001539a, +0x00015397, +0x00015396, +0x00015394, +0x00015392, +0x00015390, +0x0001538f, +0x0001538c, +0x0001538b, +0x0001538a, +0x00015387, +0x00015386, +0x00015384, +0x00015382, +0x00015381, +0x0001537f, +0x0001537d, +0x0001537b, +0x0001537a, +0x00015377, +0x00015376, +0x00015375, +0x00015372, +0x00015371, +0x0001536f, +0x0001536d, +0x0001536b, +0x0001536a, +0x00015367, +0x00015366, +0x00015365, +0x00015362, +0x00015361, +0x0001535f, +0x0001535d, +0x0001535b, +0x0001535a, +0x00015359, +0x00015356, +0x00015355, +0x00015353, +0x00015351, +0x0001534f, +0x0001534e, +0x0001534b, +0x0001534a, +0x00015349, +0x00015346, +0x00015345, +0x00015343, +0x00015341, +0x0001533f, +0x0001533e, +0x0001533b, +0x0001533a, +0x00015339, +0x00015336, +0x00015335, +0x00015333, +0x00015331, +0x0001532f, +0x0001532e, +0x0001532c, +0x0001532a, +0x00015329, +0x00015326, +0x00015325, +0x00015324, +0x00015321, +0x00015320, +0x0001531e, +0x0001531d, +0x0001531a, +0x00015319, +0x00015318, +0x00015315, +0x00015314, +0x00015313, +0x00015310, +0x0001530f, +0x0001530d, +0x0001530b, +0x00015309, +0x00015308, +0x00015305, +0x00015304, +0x00015303, +0x00015300, +0x000152ff, +0x000152fd, +0x000152fb, +0x000152f9, +0x000152f8, +0x000152f5, +0x000152f4, +0x000152f3, +0x000152f0, +0x000152ef, +0x000152ed, +0x000152ec, +0x000152e9, +0x000152e8, +0x000152e7, +0x000152e4, +0x000152e3, +0x000152e2, +0x000152df, +0x000152de, +0x000152dc, +0x000152da, +0x000152d8, +0x000152d7, +0x000152d4, +0x000152d3, +0x000152d2, +0x000152cf, +0x000152ce, +0x000152cc, +0x000152ca, +0x000152c8, +0x000152c7, +0x000152c4, +0x000152c3, +0x000152c2, +0x000152bf, +0x000152be, +0x000152bc, +0x000152ba, +0x000152b8, +0x000152b7, +0x000152b5, +0x000152b3, +0x000152b2, +0x000152b1, +0x000152ae, +0x000152ad, +0x000152ab, +0x000152a9, +0x000152a7, +0x000152a6, +0x000152a3, +0x000152a2, +0x000152a1, +0x0001529e, +0x0001529d, +0x0001529b, +0x00015299, +0x00015297, +0x00015296, +0x00015293, +0x00015292, +0x00015291, +0x0001528e, +0x0001528d, +0x0001528b, +0x00015289, +0x00015287, +0x00015286, +0x00015284, +0x00015282, +0x00015281, +0x0001527e, +0x0001527d, +0x0001527c, +0x00015279, +0x00015278, +0x00015276, +0x00015274, +0x00015272, +0x00015271, +0x00015270, +0x0001526d, +0x0001526c, +0x0001526a, +0x00015268, +0x00015266, +0x00015265, +0x00015262, +0x00015261, +0x00015260, +0x0001525d, +0x0001525c, +0x0001525a, +0x00015258, +0x00015257, +0x00015255, +0x00015253, +0x00015251, +0x00015250, +0x0001524d, +0x0001524c, +0x0001524b, +0x00015248, +0x00015247, +0x00015245, +0x00015243, +0x00015241, +0x00015241, +0x0001523e, +0x0001523d, +0x0001523b, +0x00015239, +0x00015237, +0x00015236, +0x00015233, +0x00015232, +0x00015231, +0x0001522e, +0x0001522d, +0x0001522c, +0x00015229, +0x00015228, +0x00015226, +0x00015224, +0x00015222, +0x00015221, +0x0001521e, +0x0001521d, +0x0001521c, +0x00015219, +0x00015218, +0x00015216, +0x00015214, +0x00015212, +0x00015211, +0x00015210, +0x0001520d, +0x0001520c, +0x0001520b, +0x00015208, +0x00015207, +0x00015205, +0x00015203, +0x00015201, +0x00015200, +0x000151fd, +0x000151fc, +0x000151fb, +0x000151f8, +0x000151f7, +0x000151f5, +0x000151f3, +0x000151f1, +0x000151f0, +0x000151ee, +0x000151ec, +0x000151eb, +0x000151e8, +0x000151e7, +0x000151e6, +0x000151e4, +0x000151e2, +0x000151e0, +0x000151df, +0x000151dc, +0x000151db, +0x000151da, +0x000151d7, +0x000151d6, +0x000151d4, +0x000151d2, +0x000151d0, +0x000151cf, +0x000151cd, +0x000151cb, +0x000151ca, +0x000151c7, +0x000151c6, +0x000151c5, +0x000151c2, +0x000151c1, +0x000151bf, +0x000151bd, +0x000151bb, +0x000151ba, +0x000151b9, +0x000151b6, +0x000151b5, +0x000151b3, +0x000151b1, +0x000151af, +0x000151ae, +0x000151ac, +0x000151aa, +0x000151a9, +0x000151a6, +0x000151a5, +0x000151a4, +0x000151a1, +0x000151a0, +0x0001519e, +0x0001519c, +0x0001519a, +0x00015199, +0x00015196, +0x00015195, +0x00015194, +0x00015191, +0x00015190, +0x0001518e, +0x0001518d, +0x0001518a, +0x00015189, +0x00015188, +0x00015185, +0x00015184, +0x00015183, +0x00015180, +0x0001517f, +0x0001517d, +0x0001517b, +0x00015179, +0x00015178, +0x00015175, +0x00015174, +0x00015173, +0x00015170, +0x0001516f, +0x0001516d, +0x0001516b, +0x00015169, +0x00015168, +0x00015166, +0x00015164, +0x00015163, +0x00015161, +0x0001515f, +0x0001515d, +0x0001515c, +0x0001515a, +0x00015158, +0x00015157, +0x00015156, +0x00015153, +0x00015152, +0x00015150, +0x0001514e, +0x0001514c, +0x0001514b, +0x00015148, +0x00015147, +0x00015146, +0x00015143, +0x00015142, +0x00015141, +0x0001513e, +0x0001513d, +0x0001513b, +0x00015139, +0x00015137, +0x00015136, +0x00015135, +0x00015132, +0x00015131, +0x0001512f, +0x0001512d, +0x0001512b, +0x0001512a, +0x00015127, +0x00015126, +0x00015125, +0x00015122, +0x00015121, +0x00015120, +0x0001511d, +0x0001511c, +0x0001511a, +0x00015118, +0x00015116, +0x00015115, +0x00015114, +0x00015111, +0x00015110, +0x0001510e, +0x0001510c, +0x0001510b, +0x00015109, +0x00015107, +0x00015105, +0x00015104, +0x00015101, +0x00015100, +0x000150ff, +0x000150fc, +0x000150fb, +0x000150f9, +0x000150f7, +0x000150f5, +0x000150f4, +0x000150f3, +0x000150f0, +0x000150ef, +0x000150ee, +0x000150eb, +0x000150ea, +0x000150e8, +0x000150e6, +0x000150e4, +0x000150e3, +0x000150e0, +0x000150df, +0x000150de, +0x000150db, +0x000150da, +0x000150d9, +0x000150d6, +0x000150d5, +0x000150d3, +0x000150d1, +0x000150cf, +0x000150ce, +0x000150cd, +0x000150ca, +0x000150c9, +0x000150c7, +0x000150c5, +0x000150c3, +0x000150c2, +0x000150bf, +0x000150be, +0x000150bd, +0x000150ba, +0x000150b9, +0x000150b8, +0x000150b5, +0x000150b4, +0x000150b2, +0x000150b0, +0x000150ae, +0x000150ad, +0x000150ac, +0x000150a9, +0x000150a8, +0x000150a6, +0x000150a4, +0x000150a3, +0x000150a1, +0x0001509f, +0x0001509d, +0x0001509c, +0x00015099, +0x00015098, +0x00015097, +0x00015094, +0x00015093, +0x00015091, +0x0001508f, +0x0001508d, +0x0001508c, +0x0001508b, +0x00015088, +0x00015087, +0x00015086, +0x00015083, +0x00015082, +0x0001507f, +0x0001507e, +0x0001507d, +0x0001507a, +0x00015079, +0x00015077, +0x00015076, +0x00015074, +0x00015072, +0x00015071, +0x0001506e, +0x0001506d, +0x0001506c, +0x00015069, +0x00015068, +0x00015066, +0x00015064, +0x00015062, +0x00015061, +0x0001505f, +0x0001505d, +0x0001505c, +0x0001505b, +0x00015058, +0x00015057, +0x00015055, +0x00015053, +0x00015051, +0x00015050, +0x0001504d, +0x0001504c, +0x0001504b, +0x00015048, +0x00015047, +0x00015046, +0x00015043, +0x00015042, +0x00015040, +0x0001503f, +0x0001503c, +0x0001503b, +0x0001503a, +0x00015037, +0x00015036, +0x00015035, +0x00015032, +0x00015031, +0x0001502f, +0x0001502d, +0x0001502b, +0x0001502a, +0x00015027, +0x00015026, +0x00015025, +0x00015023, +0x00015021, +0x00015020, +0x0001501e, +0x0001501c, +0x0001501a, +0x00015019, +0x00015016, +0x00015015, +0x00015014, +0x00015011, +0x00015010, +0x0001500e, +0x0001500c, +0x0001500b, +0x00015009, +0x00015008, +0x00015005, +0x00015004, +0x00015003, +0x00015000, +0x00014fff, +0x00014ffd, +0x00014ffb, +0x00014ff9, +0x00014ff8, +0x00014ff6, +0x00014ff4, +0x00014ff3, +0x00014ff0, +0x00014fef, +0x00014fee, +0x00014fec, +0x00014fea, +0x00014fe8, +0x00014fe7, +0x00014fe4, +0x00014fe3, +0x00014fe2, +0x00014fdf, +0x00014fde, +0x00014fdd, +0x00014fda, +0x00014fd9, +0x00014fd7, +0x00014fd5, +0x00014fd3, +0x00014fd2, +0x00014fd1, +0x00014fce, +0x00014fcd, +0x00014fcc, +0x00014fc9, +0x00014fc8, +0x00014fc6, +0x00014fc4, +0x00014fc2, +0x00014fc1, +0x00014fbe, +0x00014fbd, +0x00014fbc, +0x00014fb9, +0x00014fb8, +0x00014fb7, +0x00014fb5, +0x00014fb3, +0x00014fb1, +0x00014fb0, +0x00014fad, +0x00014fac, +0x00014fab, +0x00014fa8, +0x00014fa6, +0x00014fa5, +0x00014fa4, +0x00014fa1, +0x00014fa0, +0x00014f9e, +0x00014f9c, +0x00014f9a, +0x00014f99, +0x00014f96, +0x00014f95, +0x00014f94, +0x00014f93, +0x00014f90, +0x00014f8f, +0x00014f8d, +0x00014f8b, +0x00014f89, +0x00014f88, +0x00014f85, +0x00014f84, +0x00014f83, +0x00014f80, +0x00014f7f, +0x00014f7e, +0x00014f7c, +0x00014f7a, +0x00014f78, +0x00014f77, +0x00014f74, +0x00014f73, +0x00014f72, +0x00014f6f, +0x00014f6e, +0x00014f6d, +0x00014f6a, +0x00014f69, +0x00014f67, +0x00014f66, +0x00014f63, +0x00014f62, +0x00014f61, +0x00014f5e, +0x00014f5d, +0x00014f5c, +0x00014f59, +0x00014f58, +0x00014f56, +0x00014f54, +0x00014f52, +0x00014f51, +0x00014f50, +0x00014f4d, +0x00014f4c, +0x00014f4b, +0x00014f48, +0x00014f47, +0x00014f45, +0x00014f43, +0x00014f41, +0x00014f40, +0x00014f3e, +0x00014f3c, +0x00014f3b, +0x00014f3a, +0x00014f37, +0x00014f36, +0x00014f34, +0x00014f32, +0x00014f30, +0x00014f2f, +0x00014f2c, +0x00014f2b, +0x00014f2a, +0x00014f27, +0x00014f26, +0x00014f25, +0x00014f22, +0x00014f21, +0x00014f1f, +0x00014f1e, +0x00014f1b, +0x00014f1a, +0x00014f19, +0x00014f16, +0x00014f15, +0x00014f14, +0x00014f11, +0x00014f10, +0x00014f0e, +0x00014f0c, +0x00014f0a, +0x00014f09, +0x00014f08, +0x00014f05, +0x00014f04, +0x00014f03, +0x00014f00, +0x00014eff, +0x00014efd, +0x00014efb, +0x00014ef9, +0x00014ef8, +0x00014ef6, +0x00014ef4, +0x00014ef3, +0x00014ef2, +0x00014eef, +0x00014eee, +0x00014eec, +0x00014eea, +0x00014ee8, +0x00014ee7, +0x00014ee5, +0x00014ee3, +0x00014ee2, +0x00014edf, +0x00014ede, +0x00014edd, +0x00014edb, +0x00014ed9, +0x00014ed7, +0x00014ed6, +0x00014ed4, +0x00014ed2, +0x00014ed1, +0x00014ece, +0x00014ecd, +0x00014ecc, +0x00014ec9, +0x00014ec8, +0x00014ec6, +0x00014ec4, +0x00014ec2, +0x00014ec1, +0x00014ebe, +0x00014ebd, +0x00014ebc, +0x00014eb9, +0x00014eb8, +0x00014eb7, +0x00014eb5, +0x00014eb3, +0x00014eb1, +0x00014eb0, +0x00014eae, +0x00014eac, +0x00014eab, +0x00014ea8, +0x00014ea7, +0x00014ea6, +0x00014ea3, +0x00014ea2, +0x00014ea0, +0x00014e9f, +0x00014e9d, +0x00014e9b, +0x00014e9a, +0x00014e97, +0x00014e96, +0x00014e95, +0x00014e92, +0x00014e91, +0x00014e90, +0x00014e8e, +0x00014e8c, +0x00014e8a, +0x00014e89, +0x00014e86, +0x00014e85, +0x00014e84, +0x00014e81, +0x00014e80, +0x00014e7f, +0x00014e7c, +0x00014e7b, +0x00014e79, +0x00014e78, +0x00014e75, +0x00014e74, +0x00014e73, +0x00014e70, +0x00014e6f, +0x00014e6e, +0x00014e6b, +0x00014e6a, +0x00014e68, +0x00014e67, +0x00014e64, +0x00014e63, +0x00014e62, +0x00014e5f, +0x00014e5e, +0x00014e5d, +0x00014e5a, +0x00014e59, +0x00014e57, +0x00014e55, +0x00014e54, +0x00014e52, +0x00014e51, +0x00014e4e, +0x00014e4d, +0x00014e4c, +0x00014e49, +0x00014e48, +0x00014e46, +0x00014e44, +0x00014e43, +0x00014e41, +0x00014e40, +0x00014e3d, +0x00014e3c, +0x00014e3b, +0x00014e38, +0x00014e37, +0x00014e35, +0x00014e33, +0x00014e32, +0x00014e30, +0x00014e2e, +0x00014e2c, +0x00014e2b, +0x00014e2a, +0x00014e27, +0x00014e26, +0x00014e25, +0x00014e22, +0x00014e21, +0x00014e1f, +0x00014e1d, +0x00014e1b, +0x00014e1a, +0x00014e19, +0x00014e16, +0x00014e15, +0x00014e14, +0x00014e11, +0x00014e10, +0x00014e0e, +0x00014e0c, +0x00014e0a, +0x00014e09, +0x00014e07, +0x00014e05, +0x00014e04, +0x00014e03, +0x00014e00, +0x00014dff, +0x00014dfd, +0x00014dfb, +0x00014df9, +0x00014df8, +0x00014df6, +0x00014df4, +0x00014df3, +0x00014df2, +0x00014def, +0x00014dee, +0x00014dec, +0x00014dea, +0x00014de9, +0x00014de7, +0x00014de5, +0x00014de3, +0x00014de2, +0x00014ddf, +0x00014dde, +0x00014ddd, +0x00014ddb, +0x00014dd9, +0x00014dd8, +0x00014dd6, +0x00014dd4, +0x00014dd2, +0x00014dd1, +0x00014dce, +0x00014dcd, +0x00014dcc, +0x00014dc9, +0x00014dc8, +0x00014dc7, +0x00014dc5, +0x00014dc3, +0x00014dc1, +0x00014dc0, +0x00014dbd, +0x00014dbc, +0x00014dbb, +0x00014db8, +0x00014db7, +0x00014db6, +0x00014db4, +0x00014db2, +0x00014db0, +0x00014daf, +0x00014dad, +0x00014dab, +0x00014daa, +0x00014da7, +0x00014da6, +0x00014da5, +0x00014da2, +0x00014da1, +0x00014d9f, +0x00014d9e, +0x00014d9c, +0x00014d9a, +0x00014d99, +0x00014d96, +0x00014d95, +0x00014d94, +0x00014d91, +0x00014d90, +0x00014d8e, +0x00014d8d, +0x00014d8b, +0x00014d89, +0x00014d88, +0x00014d85, +0x00014d84, +0x00014d83, +0x00014d80, +0x00014d7f, +0x00014d7e, +0x00014d7b, +0x00014d7a, +0x00014d78, +0x00014d77, +0x00014d74, +0x00014d73, +0x00014d72, +0x00014d6f, +0x00014d6e, +0x00014d6d, +0x00014d6a, +0x00014d69, +0x00014d67, +0x00014d66, +0x00014d63, +0x00014d62, +0x00014d61, +0x00014d5e, +0x00014d5d, +0x00014d5c, +0x00014d59, +0x00014d58, +0x00014d56, +0x00014d54, +0x00014d52, +0x00014d51, +0x00014d50, +0x00014d4d, +0x00014d4c, +0x00014d4b, +0x00014d48, +0x00014d47, +0x00014d45, +0x00014d43, +0x00014d42, +0x00014d40, +0x00014d3f, +0x00014d3c, +0x00014d3b, +0x00014d3a, +0x00014d37, +0x00014d36, +0x00014d34, +0x00014d32, +0x00014d31, +0x00014d2f, +0x00014d2d, +0x00014d2b, +0x00014d2a, +0x00014d29, +0x00014d26, +0x00014d25, +0x00014d24, +0x00014d21, +0x00014d20, +0x00014d1e, +0x00014d1c, +0x00014d1a, +0x00014d19, +0x00014d17, +0x00014d16, +0x00014d15, +0x00014d12, +0x00014d11, +0x00014d10, +0x00014d0d, +0x00014d0c, +0x00014d0a, +0x00014d09, +0x00014d07, +0x00014d05, +0x00014d04, +0x00014d01, +0x00014d00, +0x00014cff, +0x00014cfc, +0x00014cfb, +0x00014cf9, +0x00014cf8, +0x00014cf6, +0x00014cf4, +0x00014cf3, +0x00014cf0, +0x00014cef, +0x00014cee, +0x00014ceb, +0x00014cea, +0x00014ce9, +0x00014ce7, +0x00014ce5, +0x00014ce3, +0x00014ce2, +0x00014cdf, +0x00014cde, +0x00014cdd, +0x00014cda, +0x00014cd9, +0x00014cd8, +0x00014cd6, +0x00014cd4, +0x00014cd2, +0x00014cd1, +0x00014ccf, +0x00014ccd, +0x00014ccc, +0x00014cc9, +0x00014cc8, +0x00014cc7, +0x00014cc5, +0x00014cc3, +0x00014cc2, +0x00014cc0, +0x00014cbe, +0x00014cbc, +0x00014cbb, +0x00014cb8, +0x00014cb7, +0x00014cb6, +0x00014cb5, +0x00014cb2, +0x00014cb1, +0x00014caf, +0x00014cad, +0x00014cab, +0x00014caa, +0x00014ca8, +0x00014ca6, +0x00014ca5, +0x00014ca2, +0x00014ca1, +0x00014ca0, +0x00014c9e, +0x00014c9c, +0x00014c9b, +0x00014c99, +0x00014c97, +0x00014c95, +0x00014c94, +0x00014c91, +0x00014c90, +0x00014c8f, +0x00014c8e, +0x00014c8b, +0x00014c8a, +0x00014c88, +0x00014c86, +0x00014c84, +0x00014c83, +0x00014c81, +0x00014c7f, +0x00014c7e, +0x00014c7d, +0x00014c7a, +0x00014c79, +0x00014c77, +0x00014c75, +0x00014c74, +0x00014c72, +0x00014c70, +0x00014c6e, +0x00014c6d, +0x00014c6c, +0x00014c69, +0x00014c68, +0x00014c67, +0x00014c64, +0x00014c63, +0x00014c61, +0x00014c5f, +0x00014c5d, +0x00014c5c, +0x00014c5b, +0x00014c58, +0x00014c57, +0x00014c56, +0x00014c53, +0x00014c52, +0x00014c50, +0x00014c4e, +0x00014c4c, +0x00014c4b, +0x00014c4a, +0x00014c47, +0x00014c46, +0x00014c45, +0x00014c42, +0x00014c41, +0x00014c40, +0x00014c3e, +0x00014c3c, +0x00014c3a, +0x00014c39, +0x00014c38, +0x00014c35, +0x00014c34, +0x00014c33, +0x00014c30, +0x00014c2f, +0x00014c2d, +0x00014c2b, +0x00014c2a, +0x00014c28, +0x00014c27, +0x00014c24, +0x00014c23, +0x00014c22, +0x00014c1f, +0x00014c1e, +0x00014c1d, +0x00014c1a, +0x00014c19, +0x00014c17, +0x00014c16, +0x00014c13, +0x00014c12, +0x00014c11, +0x00014c0e, +0x00014c0d, +0x00014c0c, +0x00014c0a, +0x00014c08, +0x00014c06, +0x00014c05, +0x00014c03, +0x00014c01, +0x00014c00, +0x00014bfd, +0x00014bfc, +0x00014bfb, +0x00014bfa, +0x00014bf7, +0x00014bf6, +0x00014bf4, +0x00014bf2, +0x00014bf0, +0x00014bef, +0x00014bed, +0x00014beb, +0x00014bea, +0x00014be9, +0x00014be6, +0x00014be5, +0x00014be3, +0x00014be1, +0x00014be0, +0x00014bde, +0x00014bdc, +0x00014bda, +0x00014bd9, +0x00014bd8, +0x00014bd5, +0x00014bd4, +0x00014bd3, +0x00014bd0, +0x00014bcf, +0x00014bcd, +0x00014bcc, +0x00014bca, +0x00014bc8, +0x00014bc7, +0x00014bc4, +0x00014bc3, +0x00014bc2, +0x00014bbf, +0x00014bbe, +0x00014bbd, +0x00014bbb, +0x00014bb9, +0x00014bb7, +0x00014bb6, +0x00014bb3, +0x00014bb2, +0x00014bb1, +0x00014bae, +0x00014bad, +0x00014bac, +0x00014baa, +0x00014ba8, +0x00014ba7, +0x00014ba5, +0x00014ba3, +0x00014ba1, +0x00014ba0, +0x00014b9f, +0x00014b9c, +0x00014b9b, +0x00014b9a, +0x00014b97, +0x00014b96, +0x00014b94, +0x00014b92, +0x00014b90, +0x00014b8f, +0x00014b8e, +0x00014b8b, +0x00014b8a, +0x00014b89, +0x00014b86, +0x00014b85, +0x00014b84, +0x00014b81, +0x00014b80, +0x00014b7e, +0x00014b7d, +0x00014b7a, +0x00014b79, +0x00014b78, +0x00014b75, +0x00014b74, +0x00014b73, +0x00014b70, +0x00014b6f, +0x00014b6d, +0x00014b6c, +0x00014b6a, +0x00014b69, +0x00014b66, +0x00014b65, +0x00014b64, +0x00014b62, +0x00014b60, +0x00014b5e, +0x00014b5d, +0x00014b5b, +0x00014b59, +0x00014b58, +0x00014b57, +0x00014b54, +0x00014b53, +0x00014b51, +0x00014b4f, +0x00014b4e, +0x00014b4c, +0x00014b4a, +0x00014b48, +0x00014b47, +0x00014b46, +0x00014b43, +0x00014b42, +0x00014b41, +0x00014b3e, +0x00014b3d, +0x00014b3b, +0x00014b3a, +0x00014b38, +0x00014b36, +0x00014b35, +0x00014b32, +0x00014b31, +0x00014b30, +0x00014b2d, +0x00014b2c, +0x00014b2b, +0x00014b29, +0x00014b27, +0x00014b25, +0x00014b24, +0x00014b22, +0x00014b20, +0x00014b1f, +0x00014b1e, +0x00014b1b, +0x00014b1a, +0x00014b19, +0x00014b16, +0x00014b15, +0x00014b13, +0x00014b12, +0x00014b10, +0x00014b0e, +0x00014b0d, +0x00014b0a, +0x00014b09, +0x00014b08, +0x00014b05, +0x00014b04, +0x00014b03, +0x00014b01, +0x00014aff, +0x00014afd, +0x00014afc, +0x00014afa, +0x00014af8, +0x00014af7, +0x00014af6, +0x00014af3, +0x00014af2, +0x00014af0, +0x00014aee, +0x00014aed, +0x00014aeb, +0x00014ae9, +0x00014ae7, +0x00014ae6, +0x00014ae5, +0x00014ae2, +0x00014ae1, +0x00014ae0, +0x00014add, +0x00014adc, +0x00014adb, +0x00014ad9, +0x00014ad7, +0x00014ad5, +0x00014ad4, +0x00014ad1, +0x00014ad0, +0x00014acf, +0x00014ace, +0x00014acb, +0x00014aca, +0x00014ac8, +0x00014ac6, +0x00014ac5, +0x00014ac3, +0x00014ac1, +0x00014abf, +0x00014abe, +0x00014abd, +0x00014aba, +0x00014ab9, +0x00014ab8, +0x00014ab5, +0x00014ab4, +0x00014ab2, +0x00014ab1, +0x00014aaf, +0x00014aad, +0x00014aac, +0x00014aa9, +0x00014aa8, +0x00014aa7, +0x00014aa4, +0x00014aa3, +0x00014aa2, +0x00014aa0, +0x00014a9e, +0x00014a9c, +0x00014a9b, +0x00014a99, +0x00014a97, +0x00014a96, +0x00014a95, +0x00014a93, +0x00014a90, +0x00014a8f, +0x00014a8e, +0x00014a8b, +0x00014a8a, +0x00014a89, +0x00014a86, +0x00014a85, +0x00014a83, +0x00014a82, +0x00014a80, +0x00014a7e, +0x00014a7d, +0x00014a7a, +0x00014a79, +0x00014a78, +0x00014a77, +0x00014a74, +0x00014a73, +0x00014a71, +0x00014a6f, +0x00014a6e, +0x00014a6c, +0x00014a6b, +0x00014a68, +0x00014a67, +0x00014a66, +0x00014a63, +0x00014a62, +0x00014a61, +0x00014a5f, +0x00014a5d, +0x00014a5c, +0x00014a5a, +0x00014a58, +0x00014a56, +0x00014a55, +0x00014a54, +0x00014a51, +0x00014a50, +0x00014a4f, +0x00014a4c, +0x00014a4b, +0x00014a49, +0x00014a47, +0x00014a46, +0x00014a44, +0x00014a43, +0x00014a40, +0x00014a3f, +0x00014a3e, +0x00014a3b, +0x00014a3a, +0x00014a39, +0x00014a37, +0x00014a35, +0x00014a34, +0x00014a32, +0x00014a30, +0x00014a2e, +0x00014a2d, +0x00014a2c, +0x00014a29, +0x00014a28, +0x00014a27, +0x00014a24, +0x00014a23, +0x00014a22, +0x00014a20, +0x00014a1e, +0x00014a1c, +0x00014a1b, +0x00014a18, +0x00014a17, +0x00014a16, +0x00014a15, +0x00014a12, +0x00014a11, +0x00014a0f, +0x00014a0d, +0x00014a0c, +0x00014a0a, +0x00014a09, +0x00014a06, +0x00014a05, +0x00014a04, +0x00014a01, +0x00014a00, +0x000149ff, +0x000149fc, +0x000149fb, +0x000149fa, +0x000149f8, +0x000149f6, +0x000149f4, +0x000149f3, +0x000149f1, +0x000149ef, +0x000149ee, +0x000149ed, +0x000149ea, +0x000149e9, +0x000149e8, +0x000149e5, +0x000149e4, +0x000149e2, +0x000149e1, +0x000149de, +0x000149dd, +0x000149dc, +0x000149d9, +0x000149d8, +0x000149d7, +0x000149d5, +0x000149d3, +0x000149d2, +0x000149d0, +0x000149ce, +0x000149cc, +0x000149cb, +0x000149ca, +0x000149c7, +0x000149c6, +0x000149c5, +0x000149c2, +0x000149c1, +0x000149c0, +0x000149bd, +0x000149bc, +0x000149ba, +0x000149b8, +0x000149b6, +0x000149b5, +0x000149b4, +0x000149b1, +0x000149b0, +0x000149af, +0x000149ac, +0x000149ab, +0x000149aa, +0x000149a8, +0x000149a6, +0x000149a5, +0x000149a3, +0x000149a1, +0x0001499f, +0x0001499e, +0x0001499d, +0x0001499a, +0x00014999, +0x00014998, +0x00014995, +0x00014994, +0x00014993, +0x00014991, +0x0001498f, +0x0001498d, +0x0001498c, +0x0001498a, +0x00014988, +0x00014987, +0x00014986, +0x00014983, +0x00014982, +0x00014981, +0x0001497e, +0x0001497d, +0x0001497b, +0x0001497a, +0x00014978, +0x00014976, +0x00014975, +0x00014972, +0x00014971, +0x00014970, +0x0001496f, +0x0001496c, +0x0001496b, +0x00014969, +0x00014967, +0x00014966, +0x00014964, +0x00014963, +0x00014960, +0x0001495f, +0x0001495e, +0x0001495b, +0x0001495a, +0x00014959, +0x00014957, +0x00014955, +0x00014954, +0x00014952, +0x00014950, +0x0001494e, +0x0001494d, +0x0001494c, +0x00014949, +0x00014948, +0x00014947, +0x00014944, +0x00014943, +0x00014942, +0x00014940, +0x0001493e, +0x0001493c, +0x0001493b, +0x00014939, +0x00014937, +0x00014936, +0x00014935, +0x00014932, +0x00014931, +0x00014930, +0x0001492d, +0x0001492c, +0x0001492a, +0x00014929, +0x00014927, +0x00014925, +0x00014924, +0x00014921, +0x00014920, +0x0001491f, +0x0001491e, +0x0001491b, +0x0001491a, +0x00014918, +0x00014916, +0x00014915, +0x00014913, +0x00014912, +0x0001490f, +0x0001490e, +0x0001490d, +0x0001490a, +0x00014909, +0x00014908, +0x00014906, +0x00014904, +0x00014903, +0x00014901, +0x000148ff, +0x000148fd, +0x000148fc, +0x000148fb, +0x000148f8, +0x000148f7, +0x000148f6, +0x000148f3, +0x000148f2, +0x000148f1, +0x000148ef, +0x000148ed, +0x000148eb, +0x000148ea, +0x000148e8, +0x000148e6, +0x000148e5, +0x000148e4, +0x000148e1, +0x000148e0, +0x000148df, +0x000148dc, +0x000148db, +0x000148d9, +0x000148d8, +0x000148d6, +0x000148d4, +0x000148d3, +0x000148d0, +0x000148cf, +0x000148ce, +0x000148cd, +0x000148ca, +0x000148c9, +0x000148c7, +0x000148c5, +0x000148c4, +0x000148c2, +0x000148c1, +0x000148be, +0x000148bd, +0x000148bc, +0x000148b9, +0x000148b8, +0x000148b7, +0x000148b5, +0x000148b3, +0x000148b2, +0x000148b0, +0x000148ae, +0x000148ac, +0x000148ab, +0x000148aa, +0x000148a7, +0x000148a6, +0x000148a5, +0x000148a2, +0x000148a1, +0x000148a0, +0x0001489e, +0x0001489c, +0x0001489a, +0x00014899, +0x00014897, +0x00014895, +0x00014894, +0x00014893, +0x00014890, +0x0001488f, +0x0001488e, +0x0001488b, +0x0001488a, +0x00014888, +0x00014887, +0x00014885, +0x00014883, +0x00014882, +0x00014881, +0x0001487e, +0x0001487d, +0x0001487c, +0x00014879, +0x00014878, +0x00014876, +0x00014875, +0x00014873, +0x00014871, +0x00014870, +0x0001486d, +0x0001486c, +0x0001486b, +0x0001486a, +0x00014867, +0x00014866, +0x00014864, +0x00014862, +0x00014861, +0x0001485f, +0x0001485e, +0x0001485c, +0x0001485a, +0x00014859, +0x00014856, +0x00014855, +0x00014854, +0x00014853, +0x00014850, +0x0001484f, +0x0001484d, +0x0001484b, +0x0001484a, +0x00014848, +0x00014847, +0x00014844, +0x00014843, +0x00014842, +0x0001483f, +0x0001483e, +0x0001483d, +0x0001483b, +0x00014839, +0x00014838, +0x00014836, +0x00014834, +0x00014832, +0x00014831, +0x00014830, +0x0001482d, +0x0001482c, +0x0001482b, +0x00014828, +0x00014827, +0x00014826, +0x00014824, +0x00014822, +0x00014820, +0x0001481f, +0x0001481d, +0x0001481b, +0x0001481a, +0x00014819, +0x00014817, +0x00014816, +0x00014813, +0x00014812, +0x00014811, +0x0001480f, +0x0001480d, +0x0001480c, +0x0001480a, +0x00014808, +0x00014806, +0x00014805, +0x00014804, +0x00014801, +0x00014800, +0x000147ff, +0x000147fd, +0x000147fb, +0x000147fa, +0x000147f8, +0x000147f6, +0x000147f4, +0x000147f3, +0x000147f2, +0x000147ef, +0x000147ee, +0x000147ed, +0x000147ea, +0x000147e9, +0x000147e8, +0x000147e6, +0x000147e4, +0x000147e3, +0x000147e1, +0x000147df, +0x000147dd, +0x000147dc, +0x000147db, +0x000147d8, +0x000147d7, +0x000147d6, +0x000147d3, +0x000147d2, +0x000147d1, +0x000147cf, +0x000147cd, +0x000147cb, +0x000147ca, +0x000147c9, +0x000147c6, +0x000147c5, +0x000147c4, +0x000147c1, +0x000147c0, +0x000147bf, +0x000147bd, +0x000147bb, +0x000147ba, +0x000147b8, +0x000147b6, +0x000147b4, +0x000147b3, +0x000147b2, +0x000147af, +0x000147ae, +0x000147ad, +0x000147aa, +0x000147a9, +0x000147a8, +0x000147a6, +0x000147a4, +0x000147a2, +0x000147a1, +0x0001479f, +0x0001479d, +0x0001479c, +0x0001479b, +0x00014798, +0x00014797, +0x00014796, +0x00014794, +0x00014792, +0x00014791, +0x0001478f, +0x0001478d, +0x0001478b, +0x0001478a, +0x00014789, +0x00014786, +0x00014785, +0x00014784, +0x00014781, +0x00014780, +0x0001477f, +0x0001477d, +0x0001477b, +0x00014779, +0x00014778, +0x00014776, +0x00014774, +0x00014773, +0x00014772, +0x0001476f, +0x0001476e, +0x0001476d, +0x0001476a, +0x00014769, +0x00014768, +0x00014766, +0x00014764, +0x00014762, +0x00014761, +0x00014760, +0x0001475d, +0x0001475c, +0x0001475b, +0x00014758, +0x00014757, +0x00014756, +0x00014754, +0x00014752, +0x00014750, +0x0001474f, +0x0001474d, +0x0001474b, +0x0001474a, +0x00014749, +0x00014746, +0x00014745, +0x00014744, +0x00014742, +0x00014740, +0x0001473f, +0x0001473d, +0x0001473c, +0x00014739, +0x00014738, +0x00014737, +0x00014734, +0x00014733, +0x00014732, +0x00014731, +0x0001472e, +0x0001472d, +0x0001472b, +0x0001472a, +0x00014728, +0x00014726, +0x00014725, +0x00014722, +0x00014721, +0x00014720, +0x0001471f, +0x0001471c, +0x0001471b, +0x0001471a, +0x00014717, +0x00014716, +0x00014714, +0x00014713, +0x00014711, +0x0001470f, +0x0001470e, +0x0001470d, +0x0001470a, +0x00014709, +0x00014708, +0x00014705, +0x00014704, +0x00014703, +0x00014701, +0x000146ff, +0x000146fd, +0x000146fc, +0x000146fa, +0x000146f8, +0x000146f7, +0x000146f6, +0x000146f3, +0x000146f2, +0x000146f1, +0x000146ef, +0x000146ed, +0x000146ec, +0x000146ea, +0x000146e8, +0x000146e6, +0x000146e5, +0x000146e4, +0x000146e1, +0x000146e0, +0x000146df, +0x000146de, +0x000146db, +0x000146da, +0x000146d8, +0x000146d6, +0x000146d5, +0x000146d3, +0x000146d2, +0x000146cf, +0x000146ce, +0x000146cd, +0x000146ca, +0x000146c9, +0x000146c8, +0x000146c7, +0x000146c4, +0x000146c3, +0x000146c1, +0x000146c0, +0x000146be, +0x000146bc, +0x000146bb, +0x000146b8, +0x000146b7, +0x000146b6, +0x000146b5, +0x000146b2, +0x000146b1, +0x000146b0, +0x000146ad, +0x000146ac, +0x000146aa, +0x000146a9, +0x000146a7, +0x000146a5, +0x000146a4, +0x000146a3, +0x000146a0, +0x0001469f, +0x0001469e, +0x0001469b, +0x0001469a, +0x00014699, +0x00014697, +0x00014695, +0x00014693, +0x00014692, +0x00014690, +0x0001468e, +0x0001468d, +0x0001468c, +0x00014689, +0x00014688, +0x00014687, +0x00014685, +0x00014683, +0x00014682, +0x00014680, +0x0001467e, +0x0001467c, +0x0001467b, +0x0001467a, +0x00014677, +0x00014676, +0x00014675, +0x00014673, +0x00014671, +0x00014670, +0x0001466e, +0x0001466c, +0x0001466b, +0x0001466a, +0x00014667, +0x00014666, +0x00014665, +0x00014662, +0x00014661, +0x00014660, +0x0001465e, +0x0001465c, +0x0001465a, +0x00014659, +0x00014658, +0x00014655, +0x00014654, +0x00014653, +0x00014650, +0x0001464f, +0x0001464e, +0x0001464c, +0x0001464a, +0x00014649, +0x00014647, +0x00014646, +0x00014643, +0x00014642, +0x00014641, +0x0001463e, +0x0001463d, +0x0001463c, +0x0001463b, +0x00014638, +0x00014637, +0x00014635, +0x00014634, +0x00014632, +0x00014630, +0x0001462f, +0x0001462d, +0x0001462b, +0x0001462a, +0x00014629, +0x00014626, +0x00014625, +0x00014624, +0x00014622, +0x00014620, +0x0001461f, +0x0001461d, +0x0001461b, +0x00014619, +0x00014618, +0x00014617, +0x00014614, +0x00014613, +0x00014612, +0x00014611, +0x0001460e, +0x0001460d, +0x0001460b, +0x00014609, +0x00014608, +0x00014606, +0x00014605, +0x00014603, +0x00014601, +0x00014600, +0x000145ff, +0x000145fc, +0x000145fb, +0x000145fa, +0x000145f7, +0x000145f6, +0x000145f5, +0x000145f3, +0x000145f1, +0x000145ef, +0x000145ee, +0x000145ed, +0x000145ea, +0x000145e9, +0x000145e8, +0x000145e5, +0x000145e4, +0x000145e3, +0x000145e1, +0x000145df, +0x000145de, +0x000145dc, +0x000145db, +0x000145d9, +0x000145d7, +0x000145d6, +0x000145d3, +0x000145d2, +0x000145d1, +0x000145d0, +0x000145cd, +0x000145cc, +0x000145cb, +0x000145c9, +0x000145c7, +0x000145c5, +0x000145c4, +0x000145c2, +0x000145c0, +0x000145bf, +0x000145be, +0x000145bb, +0x000145ba, +0x000145b9, +0x000145b7, +0x000145b5, +0x000145b4, +0x000145b2, +0x000145b0, +0x000145af, +0x000145ad, +0x000145ac, +0x000145a9, +0x000145a8, +0x000145a7, +0x000145a5, +0x000145a3, +0x000145a1, +0x000145a0, +0x0001459f, +0x0001459c, +0x0001459b, +0x0001459a, +0x00014598, +0x00014596, +0x00014595, +0x00014593, +0x00014592, +0x0001458f, +0x0001458e, +0x0001458d, +0x0001458a, +0x00014589, +0x00014588, +0x00014587, +0x00014584, +0x00014583, +0x00014581, +0x00014580, +0x0001457e, +0x0001457c, +0x0001457b, +0x00014579, +0x00014577, +0x00014576, +0x00014575, +0x00014572, +0x00014571, +0x00014570, +0x0001456e, +0x0001456c, +0x0001456b, +0x00014569, +0x00014568, +0x00014566, +0x00014564, +0x00014563, +0x00014560, +0x0001455f, +0x0001455e, +0x0001455d, +0x0001455a, +0x00014559, +0x00014558, +0x00014556, +0x00014554, +0x00014553, +0x00014551, +0x0001454f, +0x0001454d, +0x0001454c, +0x0001454b, +0x00014548, +0x00014547, +0x00014546, +0x00014545, +0x00014542, +0x00014541, +0x0001453f, +0x0001453e, +0x0001453c, +0x0001453a, +0x00014539, +0x00014537, +0x00014535, +0x00014534, +0x00014533, +0x00014530, +0x0001452f, +0x0001452e, +0x0001452c, +0x0001452a, +0x00014529, +0x00014527, +0x00014525, +0x00014524, +0x00014522, +0x00014521, +0x0001451e, +0x0001451d, +0x0001451c, +0x0001451b, +0x00014518, +0x00014517, +0x00014516, +0x00014513, +0x00014512, +0x00014511, +0x0001450f, +0x0001450d, +0x0001450b, +0x0001450a, +0x00014509, +0x00014506, +0x00014505, +0x00014504, +0x00014503, +0x00014500, +0x000144ff, +0x000144fd, +0x000144fb, +0x000144fa, +0x000144f8, +0x000144f7, +0x000144f5, +0x000144f3, +0x000144f2, +0x000144f1, +0x000144ee, +0x000144ed, +0x000144ec, +0x000144e9, +0x000144e8, +0x000144e7, +0x000144e5, +0x000144e3, +0x000144e2, +0x000144e0, +0x000144df, +0x000144dc, +0x000144db, +0x000144da, +0x000144d9, +0x000144d6, +0x000144d5, +0x000144d2, +0x000144d1, +0x000144d0, +0x000144ce, +0x000144cc, +0x000144cb, +0x000144c9, +0x000144c8, +0x000144c5, +0x000144c4, +0x000144c3, +0x000144c2, +0x000144bf, +0x000144be, +0x000144bd, +0x000144ba, +0x000144b9, +0x000144b8, +0x000144b6, +0x000144b4, +0x000144b2, +0x000144b1, +0x000144b0, +0x000144ad, +0x000144ac, +0x000144ab, +0x000144aa, +0x000144a7, +0x000144a6, +0x000144a5, +0x000144a3, +0x000144a1, +0x0001449f, +0x0001449e, +0x0001449c, +0x0001449a, +0x00014499, +0x00014498, +0x00014495, +0x00014494, +0x00014493, +0x00014492, +0x0001448f, +0x0001448e, +0x0001448c, +0x0001448b, +0x00014489, +0x00014487, +0x00014486, +0x00014484, +0x00014482, +0x00014481, +0x00014480, +0x0001447d, +0x0001447c, +0x0001447b, +0x0001447a, +0x00014477, +0x00014476, +0x00014474, +0x00014473, +0x00014471, +0x0001446f, +0x0001446e, +0x0001446c, +0x0001446a, +0x00014469, +0x00014468, +0x00014465, +0x00014464, +0x00014463, +0x00014461, +0x0001445f, +0x0001445e, +0x0001445c, +0x0001445b, +0x00014459, +0x00014457, +0x00014456, +0x00014454, +0x00014452, +0x00014451, +0x00014450, +0x0001444d, +0x0001444c, +0x0001444b, +0x00014449, +0x00014447, +0x00014446, +0x00014444, +0x00014443, +0x00014441, +0x0001443f, +0x0001443e, +0x0001443d, +0x0001443a, +0x00014439, +0x00014438, +0x00014435, +0x00014434, +0x00014433, +0x00014431, +0x0001442f, +0x0001442e, +0x0001442c, +0x0001442b, +0x00014429, +0x00014427, +0x00014426, +0x00014425, +0x00014422, +0x00014421, +0x00014420, +0x0001441d, +0x0001441c, +0x0001441b, +0x00014419, +0x00014417, +0x00014416, +0x00014414, +0x00014413, +0x00014410, +0x0001440f, +0x0001440e, +0x0001440d, +0x0001440a, +0x00014409, +0x00014408, +0x00014405, +0x00014404, +0x00014403, +0x00014401, +0x000143ff, +0x000143fd, +0x000143fc, +0x000143fb, +0x000143f8, +0x000143f7, +0x000143f6, +0x000143f5, +0x000143f2, +0x000143f1, +0x000143f0, +0x000143ed, +0x000143ec, +0x000143ea, +0x000143e9, +0x000143e7, +0x000143e5, +0x000143e4, +0x000143e3, +0x000143e0, +0x000143df, +0x000143de, +0x000143dd, +0x000143da, +0x000143d9, +0x000143d8, +0x000143d6, +0x000143d4, +0x000143d2, +0x000143d1, +0x000143cf, +0x000143cd, +0x000143cc, +0x000143cb, +0x000143c8, +0x000143c7, +0x000143c6, +0x000143c5, +0x000143c2, +0x000143c1, +0x000143bf, +0x000143be, +0x000143bc, +0x000143ba, +0x000143b9, +0x000143b7, +0x000143b5, +0x000143b4, +0x000143b3, +0x000143b0, +0x000143af, +0x000143ae, +0x000143ac, +0x000143aa, +0x000143a9, +0x000143a7, +0x000143a6, +0x000143a4, +0x000143a2, +0x000143a1, +0x0001439f, +0x0001439d, +0x0001439c, +0x0001439b, +0x00014398, +0x00014397, +0x00014396, +0x00014394, +0x00014392, +0x00014391, +0x0001438f, +0x0001438e, +0x0001438c, +0x0001438a, +0x00014389, +0x00014387, +0x00014385, +0x00014384, +0x00014383, +0x00014380, +0x0001437f, +0x0001437e, +0x0001437c, +0x0001437a, +0x00014379, +0x00014377, +0x00014376, +0x00014374, +0x00014372, +0x00014371, +0x00014370, +0x0001436d, +0x0001436c, +0x0001436b, +0x00014368, +0x00014367, +0x00014366, +0x00014364, +0x00014362, +0x00014361, +0x0001435f, +0x0001435e, +0x0001435b, +0x0001435a, +0x00014359, +0x00014358, +0x00014355, +0x00014354, +0x00014353, +0x00014350, +0x0001434f, +0x0001434e, +0x0001434c, +0x0001434a, +0x00014348, +0x00014347, +0x00014346, +0x00014343, +0x00014342, +0x00014341, +0x00014340, +0x0001433d, +0x0001433d, +0x0001433a, +0x00014339, +0x00014338, +0x00014336, +0x00014334, +0x00014332, +0x00014331, +0x00014330, +0x0001432d, +0x0001432c, +0x0001432b, +0x0001432a, +0x00014327, +0x00014326, +0x00014325, +0x00014323, +0x00014321, +0x00014320, +0x0001431e, +0x0001431d, +0x0001431a, +0x00014319, +0x00014318, +0x00014315, +0x00014314, +0x00014313, +0x00014312, +0x0001430f, +0x0001430e, +0x0001430d, +0x0001430b, +0x00014309, +0x00014308, +0x00014306, +0x00014305, +0x00014303, +0x00014301, +0x00014300, +0x000142ff, +0x000142fc, +0x000142fb, +0x000142fa, +0x000142f7, +0x000142f6, +0x000142f5, +0x000142f3, +0x000142f1, +0x000142f0, +0x000142ee, +0x000142ed, +0x000142eb, +0x000142e9, +0x000142e8, +0x000142e7, +0x000142e4, +0x000142e3, +0x000142e2, +0x000142e0, +0x000142de, +0x000142dd, +0x000142db, +0x000142da, +0x000142d8, +0x000142d6, +0x000142d5, +0x000142d3, +0x000142d1, +0x000142d0, +0x000142cf, +0x000142cc, +0x000142cb, +0x000142ca, +0x000142c8, +0x000142c6, +0x000142c5, +0x000142c3, +0x000142c2, +0x000142c0, +0x000142be, +0x000142bd, +0x000142bc, +0x000142b9, +0x000142b8, +0x000142b7, +0x000142b6, +0x000142b3, +0x000142b2, +0x000142b1, +0x000142ae, +0x000142ad, +0x000142ab, +0x000142aa, +0x000142a8, +0x000142a6, +0x000142a5, +0x000142a4, +0x000142a1, +0x000142a0, +0x0001429f, +0x0001429e, +0x0001429b, +0x0001429a, +0x00014299, +0x00014297, +0x00014295, +0x00014293, +0x00014292, +0x00014290, +0x0001428e, +0x0001428d, +0x0001428c, +0x00014289, +0x00014288, +0x00014287, +0x00014286, +0x00014283, +0x00014282, +0x00014281, +0x0001427f, +0x0001427d, +0x0001427c, +0x0001427a, +0x00014279, +0x00014276, +0x00014275, +0x00014274, +0x00014273, +0x00014271, +0x0001426f, +0x0001426d, +0x0001426c, +0x0001426a, +0x00014268, +0x00014267, +0x00014266, +0x00014263, +0x00014262, +0x00014261, +0x00014260, +0x0001425d, +0x0001425c, +0x0001425b, +0x00014259, +0x00014257, +0x00014256, +0x00014254, +0x00014253, +0x00014251, +0x0001424f, +0x0001424e, +0x0001424d, +0x0001424a, +0x00014249, +0x00014248, +0x00014246, +0x00014244, +0x00014243, +0x00014241, +0x00014240, +0x0001423e, +0x0001423c, +0x0001423b, +0x00014239, +0x00014237, +0x00014236, +0x00014235, +0x00014232, +0x00014231, +0x00014230, +0x0001422f, +0x0001422c, +0x0001422b, +0x0001422a, +0x00014228, +0x00014226, +0x00014224, +0x00014223, +0x00014222, +0x0001421f, +0x0001421e, +0x0001421d, +0x0001421c, +0x00014219, +0x00014218, +0x00014217, +0x00014215, +0x00014213, +0x00014212, +0x00014210, +0x0001420f, +0x0001420d, +0x0001420b, +0x0001420a, +0x00014208, +0x00014206, +0x00014205, +0x00014204, +0x00014201, +0x00014200, +0x000141ff, +0x000141fd, +0x000141fb, +0x000141fa, +0x000141f8, +0x000141f7, +0x000141f5, +0x000141f3, +0x000141f2, +0x000141f1, +0x000141ee, +0x000141ed, +0x000141ec, +0x000141eb, +0x000141e8, +0x000141e7, +0x000141e6, +0x000141e4, +0x000141e2, +0x000141e1, +0x000141df, +0x000141de, +0x000141dc, +0x000141da, +0x000141d9, +0x000141d6, +0x000141d5, +0x000141d4, +0x000141d3, +0x000141d0, +0x000141cf, +0x000141ce, +0x000141cc, +0x000141ca, +0x000141c9, +0x000141c7, +0x000141c6, +0x000141c4, +0x000141c2, +0x000141c1, +0x000141c0, +0x000141bd, +0x000141bc, +0x000141bb, +0x000141ba, +0x000141b7, +0x000141b6, +0x000141b5, +0x000141b3, +0x000141b1, +0x000141b0, +0x000141ae, +0x000141ad, +0x000141aa, +0x000141a9, +0x000141a8, +0x000141a6, +0x000141a4, +0x000141a3, +0x000141a1, +0x0001419f, +0x0001419e, +0x0001419d, +0x0001419a, +0x00014199, +0x00014198, +0x00014196, +0x00014194, +0x00014193, +0x00014191, +0x00014190, +0x0001418e, +0x0001418c, +0x0001418b, +0x0001418a, +0x00014187, +0x00014186, +0x00014185, +0x00014184, +0x00014181, +0x00014180, +0x0001417f, +0x0001417d, +0x0001417b, +0x0001417a, +0x00014178, +0x00014177, +0x00014175, +0x00014173, +0x00014172, +0x00014171, +0x0001416e, +0x0001416d, +0x0001416c, +0x0001416b, +0x00014168, +0x00014167, +0x00014166, +0x00014164, +0x00014162, +0x00014161, +0x0001415f, +0x0001415e, +0x0001415c, +0x0001415a, +0x00014159, +0x00014158, +0x00014155, +0x00014154, +0x00014153, +0x00014152, +0x0001414f, +0x0001414e, +0x0001414c, +0x0001414b, +0x00014149, +0x00014147, +0x00014146, +0x00014145, +0x00014142, +0x00014141, +0x00014140, +0x0001413d, +0x0001413c, +0x0001413b, +0x0001413a, +0x00014137, +0x00014136, +0x00014135, +0x00014133, +0x00014131, +0x00014130, +0x0001412e, +0x0001412d, +0x0001412b, +0x00014129, +0x00014128, +0x00014127, +0x00014124, +0x00014123, +0x00014122, +0x00014121, +0x0001411e, +0x0001411d, +0x0001411c, +0x0001411a, +0x00014118, +0x00014117, +0x00014115, +0x00014114, +0x00014112, +0x00014110, +0x0001410f, +0x0001410e, +0x0001410b, +0x0001410a, +0x00014109, +0x00014108, +0x00014105, +0x00014104, +0x00014103, +0x00014101, +0x000140ff, +0x000140fd, +0x000140fc, +0x000140fb, +0x000140f8, +0x000140f7, +0x000140f6, +0x000140f5, +0x000140f2, +0x000140f1, +0x000140f0, +0x000140ee, +0x000140ec, +0x000140eb, +0x000140e9, +0x000140e8, +0x000140e6, +0x000140e4, +0x000140e3, +0x000140e2, +0x000140df, +0x000140de, +0x000140dc, +0x000140db, +0x000140da, +0x000140d7, +0x000140d6, +0x000140d5, +0x000140d3, +0x000140d1, +0x000140d0, +0x000140ce, +0x000140cd, +0x000140cb, +0x000140c9, +0x000140c8, +0x000140c7, +0x000140c4, +0x000140c3, +0x000140c2, +0x000140c1, +0x000140be, +0x000140bd, +0x000140bc, +0x000140ba, +0x000140b8, +0x000140b7, +0x000140b5, +0x000140b4, +0x000140b2, +0x000140b0, +0x000140af, +0x000140ae, +0x000140ab, +0x000140aa, +0x000140a9, +0x000140a8, +0x000140a5, +0x000140a4, +0x000140a3, +0x000140a1, +0x0001409f, +0x0001409e, +0x0001409c, +0x0001409b, +0x00014099, +0x00014097, +0x00014096, +0x00014095, +0x00014092, +0x00014091, +0x00014090, +0x0001408f, +0x0001408c, +0x0001408b, +0x0001408a, +0x00014088, +0x00014086, +0x00014085, +0x00014083, +0x00014082, +0x00014080, +0x0001407e, +0x0001407d, +0x0001407c, +0x00014079, +0x00014078, +0x00014077, +0x00014076, +0x00014073, +0x00014072, +0x00014071, +0x0001406f, +0x0001406d, +0x0001406c, +0x0001406a, +0x00014069, +0x00014067, +0x00014065, +0x00014064, +0x00014063, +0x00014060, +0x0001405f, +0x0001405e, +0x0001405d, +0x0001405a, +0x00014059, +0x00014058, +0x00014056, +0x00014054, +0x00014053, +0x00014051, +0x00014050, +0x0001404e, +0x0001404c, +0x0001404b, +0x0001404a, +0x00014047, +0x00014046, +0x00014045, +0x00014044, +0x00014041, +0x00014040, +0x0001403f, +0x0001403d, +0x0001403b, +0x0001403a, +0x00014038, +0x00014037, +0x00014035, +0x00014033, +0x00014032, +0x00014031, +0x0001402e, +0x0001402d, +0x0001402c, +0x0001402b, +0x00014028, +0x00014027, +0x00014026, +0x00014024, +0x00014022, +0x00014021, +0x0001401f, +0x0001401e, +0x0001401c, +0x0001401a, +0x00014019, +0x00014018, +0x00014015, +0x00014014, +0x00014013, +0x00014012, +0x0001400f, +0x0001400e, +0x0001400d, +0x0001400b, +0x00014009, +0x00014008, +0x00014006, +0x00014005, +0x00014003, +0x00014001, +0x00014000, +0x00013fff, +0x00013ffc, +0x00013ffb, +0x00013ffa, +0x00013ff9, +0x00013ff6, +0x00013ff5, +0x00013ff4, +0x00013ff2, +0x00013ff0, +0x00013fef, +0x00013fed, +0x00013fec, +0x00013fea, +0x00013fe8, +0x00013fe7, +0x00013fe6, +0x00013fe3, +0x00013fe2, +0x00013fe1, +0x00013fe0, +0x00013fdd, +0x00013fdc, +0x00013fdb, +0x00013fd9, +0x00013fd7, +0x00013fd6, +0x00013fd4, +0x00013fd3, +0x00013fd1, +0x00013fcf, +0x00013fce, +0x00013fcd, +0x00013fca, +0x00013fc9, +0x00013fc8, +0x00013fc7, +0x00013fc4, +0x00013fc3, +0x00013fc2, +0x00013fc0, +0x00013fbe, +0x00013fbd, +0x00013fbb, +0x00013fba, +0x00013fb8, +0x00013fb6, +0x00013fb5, +0x00013fb4, +0x00013fb1, +0x00013fb0, +0x00013faf, +0x00013fae, +0x00013fab, +0x00013faa, +0x00013fa9, +0x00013fa7, +0x00013fa5, +0x00013fa4, +0x00013fa2, +0x00013fa1, +0x00013f9f, +0x00013f9d, +0x00013f9c, +0x00013f9b, +0x00013f98, +0x00013f97, +0x00013f96, +0x00013f95, +0x00013f92, +0x00013f91, +0x00013f90, +0x00013f8e, +0x00013f8c, +0x00013f8b, +0x00013f89, +0x00013f88, +0x00013f86, +0x00013f84, +0x00013f83, +0x00013f82, +0x00013f7f, +0x00013f7e, +0x00013f7d, +0x00013f7c, +0x00013f79, +0x00013f78, +0x00013f77, +0x00013f75, +0x00013f73, +0x00013f72, +0x00013f70, +0x00013f6f, +0x00013f6d, +0x00013f6b, +0x00013f6a, +0x00013f69, +0x00013f66, +0x00013f65, +0x00013f64, +0x00013f63, +0x00013f60, +0x00013f5f, +0x00013f5e, +0x00013f5c, +0x00013f5a, +0x00013f59, +0x00013f57, +0x00013f56, +0x00013f54, +0x00013f52, +0x00013f51, +0x00013f50, +0x00013f4d, +0x00013f4c, +0x00013f4b, +0x00013f4a, +0x00013f48, +0x00013f46, +0x00013f45, +0x00013f43, +0x00013f42, +0x00013f40, +0x00013f3e, +0x00013f3d, +0x00013f3c, +0x00013f39, +0x00013f38, +0x00013f37, +0x00013f36, +0x00013f33, +0x00013f32, +0x00013f31, +0x00013f2f, +0x00013f2d, +0x00013f2c, +0x00013f2a, +0x00013f29, +0x00013f27, +0x00013f25, +0x00013f24, +0x00013f23, +0x00013f20, +0x00013f1f, +0x00013f1e, +0x00013f1d, +0x00013f1a, +0x00013f19, +0x00013f18, +0x00013f16, +0x00013f14, +0x00013f13, +0x00013f11, +0x00013f10, +0x00013f0e, +0x00013f0c, +0x00013f0b, +0x00013f0a, +0x00013f07, +0x00013f06, +0x00013f05, +0x00013f04, +0x00013f01, +0x00013f00, +0x00013eff, +0x00013efe, +0x00013efb, +0x00013efa, +0x00013ef9, +0x00013ef7, +0x00013ef5, +0x00013ef4, +0x00013ef2, +0x00013ef1, +0x00013eef, +0x00013eed, +0x00013eec, +0x00013eeb, +0x00013eea, +0x00013ee7, +0x00013ee6, +0x00013ee5, +0x00013ee3, +0x00013ee1, +0x00013ee0, +0x00013ede, +0x00013edd, +0x00013edb, +0x00013ed9, +0x00013ed8, +0x00013ed7, +0x00013ed4, +0x00013ed3, +0x00013ed2, +0x00013ed1, +0x00013ece, +0x00013ecd, +0x00013ecc, +0x00013eca, +0x00013ec8, +0x00013ec7, +0x00013ec5, +0x00013ec4, +0x00013ec2, +0x00013ec0, +0x00013ebf, +0x00013ebe, +0x00013ebb, +0x00013eba, +0x00013eb9, +0x00013eb8, +0x00013eb5, +0x00013eb4, +0x00013eb3, +0x00013eb1, +0x00013eaf, +0x00013eae, +0x00013ead, +0x00013eab, +0x00013ea9, +0x00013ea8, +0x00013ea6, +0x00013ea5, +0x00013ea3, +0x00013ea1, +0x00013ea0, +0x00013e9f, +0x00013e9c, +0x00013e9b, +0x00013e9a, +0x00013e99, +0x00013e96, +0x00013e95, +0x00013e94, +0x00013e92, +0x00013e90, +0x00013e8f, +0x00013e8d, +0x00013e8c, +0x00013e8a, +0x00013e88, +0x00013e87, +0x00013e86, +0x00013e84, +0x00013e82, +0x00013e81, +0x00013e80, +0x00013e7d, +0x00013e7c, +0x00013e7b, +0x00013e7a, +0x00013e77, +0x00013e76, +0x00013e75, +0x00013e74, +0x00013e71, +0x00013e70, +0x00013e6f, +0x00013e6d, +0x00013e6b, +0x00013e6a, +0x00013e68, +0x00013e67, +0x00013e65, +0x00013e63, +0x00013e62, +0x00013e61, +0x00013e5e, +0x00013e5d, +0x00013e5c, +0x00013e5b, +0x00013e58, +0x00013e57, +0x00013e56, +0x00013e54, +0x00013e53, +0x00013e51, +0x00013e50, +0x00013e4e, +0x00013e4d, +0x00013e4b, +0x00013e49, +0x00013e48, +0x00013e47, +0x00013e44, +0x00013e43, +0x00013e42, +0x00013e41, +0x00013e3e, +0x00013e3d, +0x00013e3c, +0x00013e3a, +0x00013e38, +0x00013e37, +0x00013e35, +0x00013e34, +0x00013e32, +0x00013e30, +0x00013e2f, +0x00013e2e, +0x00013e2b, +0x00013e2a, +0x00013e29, +0x00013e28, +0x00013e25, +0x00013e24, +0x00013e23, +0x00013e22, +0x00013e20, +0x00013e1e, +0x00013e1d, +0x00013e1b, +0x00013e1a, +0x00013e18, +0x00013e16, +0x00013e15, +0x00013e14, +0x00013e11, +0x00013e10, +0x00013e0f, +0x00013e0e, +0x00013e0b, +0x00013e0a, +0x00013e09, +0x00013e07, +0x00013e05, +0x00013e04, +0x00013e02, +0x00013e01, +0x00013dff, +0x00013dfe, +0x00013dfc, +0x00013dfb, +0x00013df9, +0x00013df7, +0x00013df6, +0x00013df5, +0x00013df2, +0x00013df1, +0x00013df0, +0x00013def, +0x00013ded, +0x00013deb, +0x00013dea, +0x00013de8, +0x00013de7, +0x00013de5, +0x00013de3, +0x00013de2, +0x00013de1, +0x00013dde, +0x00013ddd, +0x00013ddc, +0x00013ddb, +0x00013dd8, +0x00013dd7, +0x00013dd6, +0x00013dd5, +0x00013dd2, +0x00013dd1, +0x00013dd0, +0x00013dce, +0x00013dcc, +0x00013dcb, +0x00013dc9, +0x00013dc8, +0x00013dc6, +0x00013dc4, +0x00013dc3, +0x00013dc2, +0x00013dc0, +0x00013dbf, +0x00013dbc, +0x00013dbb, +0x00013dba, +0x00013db9, +0x00013db6, +0x00013db5, +0x00013db4, +0x00013db2, +0x00013db0, +0x00013daf, +0x00013dad, +0x00013dac, +0x00013daa, +0x00013da8, +0x00013da7, +0x00013da6, +0x00013da3, +0x00013da2, +0x00013da1, +0x00013da0, +0x00013d9f, +0x00013d9c, +0x00013d9b, +0x00013d9a, +0x00013d98, +0x00013d96, +0x00013d95, +0x00013d93, +0x00013d92, +0x00013d90, +0x00013d8e, +0x00013d8d, +0x00013d8c, +0x00013d89, +0x00013d88, +0x00013d87, +0x00013d86, +0x00013d83, +0x00013d82, +0x00013d81, +0x00013d80, +0x00013d7e, +0x00013d7c, +0x00013d7b, +0x00013d79, +0x00013d78, +0x00013d76, +0x00013d74, +0x00013d73, +0x00013d72, +0x00013d6f, +0x00013d6e, +0x00013d6d, +0x00013d6c, +0x00013d69, +0x00013d68, +0x00013d67, +0x00013d66, +0x00013d63, +0x00013d62, +0x00013d61, +0x00013d5f, +0x00013d5e, +0x00013d5c, +0x00013d5a, +0x00013d59, +0x00013d58, +0x00013d55, +0x00013d54, +0x00013d53, +0x00013d52, +0x00013d4f, +0x00013d4e, +0x00013d4d, +0x00013d4c, +0x00013d49, +0x00013d48, +0x00013d47, +0x00013d45, +0x00013d43, +0x00013d42, +0x00013d40, +0x00013d3f, +0x00013d3d, +0x00013d3b, +0x00013d3a, +0x00013d39, +0x00013d38, +0x00013d35, +0x00013d34, +0x00013d33, +0x00013d32, +0x00013d2f, +0x00013d2e, +0x00013d2d, +0x00013d2b, +0x00013d29, +0x00013d28, +0x00013d26, +0x00013d25, +0x00013d23, +0x00013d21, +0x00013d20, +0x00013d1f, +0x00013d1c, +0x00013d1b, +0x00013d1a, +0x00013d19, +0x00013d18, +0x00013d15, +0x00013d14, +0x00013d13, +0x00013d11, +0x00013d0f, +0x00013d0e, +0x00013d0c, +0x00013d0b, +0x00013d09, +0x00013d07, +0x00013d06, +0x00013d05, +0x00013d02, +0x00013d01, +0x00013d00, +0x00013cff, +0x00013cfc, +0x00013cfb, +0x00013cfa, +0x00013cf9, +0x00013cf7, +0x00013cf5, +0x00013cf4, +0x00013cf2, +0x00013cf1, +0x00013cef, +0x00013ced, +0x00013cec, +0x00013ceb, +0x00013ce8, +0x00013ce7, +0x00013ce6, +0x00013ce5, +0x00013ce2, +0x00013ce1, +0x00013ce0, +0x00013cdf, +0x00013cdc, +0x00013cdb, +0x00013cda, +0x00013cd8, +0x00013cd7, +0x00013cd5, +0x00013cd3, +0x00013cd2, +0x00013cd1, +0x00013cce, +0x00013ccd, +0x00013ccc, +0x00013ccb, +0x00013cc8, +0x00013cc7, +0x00013cc6, +0x00013cc5, +0x00013cc2, +0x00013cc1, +0x00013cc0, +0x00013cbe, +0x00013cbc, +0x00013cbb, +0x00013cb9, +0x00013cb8, +0x00013cb7, +0x00013cb4, +0x00013cb3, +0x00013cb2, +0x00013cb1, +0x00013cae, +0x00013cad, +0x00013cac, +0x00013cab, +0x00013ca8, +0x00013ca7, +0x00013ca6, +0x00013ca4, +0x00013ca2, +0x00013ca1, +0x00013c9f, +0x00013c9e, +0x00013c9c, +0x00013c9a, +0x00013c99, +0x00013c98, +0x00013c97, +0x00013c94, +0x00013c93, +0x00013c92, +0x00013c91, +0x00013c8e, +0x00013c8d, +0x00013c8c, +0x00013c8a, +0x00013c88, +0x00013c87, +0x00013c85, +0x00013c84, +0x00013c82, +0x00013c80, +0x00013c7f, +0x00013c7e, +0x00013c7c, +0x00013c7a, +0x00013c79, +0x00013c78, +0x00013c77, +0x00013c74, +0x00013c73, +0x00013c72, +0x00013c70, +0x00013c6e, +0x00013c6d, +0x00013c6b, +0x00013c6a, +0x00013c68, +0x00013c66, +0x00013c65, +0x00013c64, +0x00013c62, +0x00013c60, +0x00013c5f, +0x00013c5e, +0x00013c5b, +0x00013c5a, +0x00013c59, +0x00013c58, +0x00013c56, +0x00013c54, +0x00013c53, +0x00013c51, +0x00013c50, +0x00013c4e, +0x00013c4c, +0x00013c4b, +0x00013c4a, +0x00013c47, +0x00013c46, +0x00013c45, +0x00013c44, +0x00013c41, +0x00013c40, +0x00013c3f, +0x00013c3e, +0x00013c3b, +0x00013c3a, +0x00013c39, +0x00013c38, +0x00013c36, +0x00013c35, +0x00013c33, +0x00013c31, +0x00013c30, +0x00013c2f, +0x00013c2c, +0x00013c2b, +0x00013c2a, +0x00013c29, +0x00013c26, +0x00013c25, +0x00013c24, +0x00013c23, +0x00013c20, +0x00013c1f, +0x00013c1e, +0x00013c1c, +0x00013c1b, +0x00013c19, +0x00013c17, +0x00013c16, +0x00013c15, +0x00013c13, +0x00013c11, +0x00013c10, +0x00013c0f, +0x00013c0c, +0x00013c0b, +0x00013c0a, +0x00013c09, +0x00013c07, +0x00013c05, +0x00013c04, +0x00013c02, +0x00013c01, +0x00013bff, +0x00013bfe, +0x00013bfc, +0x00013bfb, +0x00013bf9, +0x00013bf7, +0x00013bf6, +0x00013bf5, +0x00013bf2, +0x00013bf1, +0x00013bf0, +0x00013bef, +0x00013bed, +0x00013beb, +0x00013bea, +0x00013be9, +0x00013be7, +0x00013be5, +0x00013be4, +0x00013be2, +0x00013be1, +0x00013bdf, +0x00013bdd, +0x00013bdc, +0x00013bdb, +0x00013bd9, +0x00013bd7, +0x00013bd6, +0x00013bd5, +0x00013bd4, +0x00013bd1, +0x00013bd0, +0x00013bcf, +0x00013bcd, +0x00013bcb, +0x00013bca, +0x00013bc8, +0x00013bc7, +0x00013bc5, +0x00013bc4, +0x00013bc2, +0x00013bc1, +0x00013bbf, +0x00013bbd, +0x00013bbc, +0x00013bbb, +0x00013bba, +0x00013bb7, +0x00013bb6, +0x00013bb5, +0x00013bb3, +0x00013bb1, +0x00013bb0, +0x00013baf, +0x00013bad, +0x00013bab, +0x00013baa, +0x00013ba8, +0x00013ba7, +0x00013ba6, +0x00013ba3, +0x00013ba2, +0x00013ba1, +0x00013ba0, +0x00013b9d, +0x00013b9c, +0x00013b9b, +0x00013b9a, +0x00013b97, +0x00013b96, +0x00013b95, +0x00013b93, +0x00013b91, +0x00013b90, +0x00013b8e, +0x00013b8d, +0x00013b8c, +0x00013b8a, +0x00013b88, +0x00013b87, +0x00013b86, +0x00013b83, +0x00013b82, +0x00013b81, +0x00013b80, +0x00013b7d, +0x00013b7c, +0x00013b7b, +0x00013b79, +0x00013b77, +0x00013b76, +0x00013b75, +0x00013b74, +0x00013b71, +0x00013b70, +0x00013b6f, +0x00013b6e, +0x00013b6b, +0x00013b6a, +0x00013b69, +0x00013b67, +0x00013b65, +0x00013b64, +0x00013b62, +0x00013b61, +0x00013b60, +0x00013b5e, +0x00013b5c, +0x00013b5b, +0x00013b5a, +0x00013b57, +0x00013b56, +0x00013b55, +0x00013b54, +0x00013b51, +0x00013b50, +0x00013b4f, +0x00013b4e, +0x00013b4c, +0x00013b4a, +0x00013b49, +0x00013b47, +0x00013b46, +0x00013b44, +0x00013b42, +0x00013b41, +0x00013b40, +0x00013b3e, +0x00013b3c, +0x00013b3b, +0x00013b3a, +0x00013b39, +0x00013b36, +0x00013b35, +0x00013b34, +0x00013b32, +0x00013b30, +0x00013b2f, +0x00013b2e, +0x00013b2c, +0x00013b2a, +0x00013b29, +0x00013b27, +0x00013b26, +0x00013b25, +0x00013b22, +0x00013b21, +0x00013b20, +0x00013b1f, +0x00013b1c, +0x00013b1b, +0x00013b1a, +0x00013b19, +0x00013b16, +0x00013b15, +0x00013b14, +0x00013b12, +0x00013b11, +0x00013b0f, +0x00013b0e, +0x00013b0c, +0x00013b0b, +0x00013b09, +0x00013b07, +0x00013b06, +0x00013b05, +0x00013b02, +0x00013b01, +0x00013b00, +0x00013aff, +0x00013afe, +0x00013afb, +0x00013afa, +0x00013af9, +0x00013af7, +0x00013af5, +0x00013af4, +0x00013af2, +0x00013af1, +0x00013aef, +0x00013aee, +0x00013aec, +0x00013aeb, +0x00013aea, +0x00013ae7, +0x00013ae6, +0x00013ae5, +0x00013ae4, +0x00013ae1, +0x00013ae0, +0x00013adf, +0x00013ade, +0x00013adb, +0x00013ada, +0x00013ad9, +0x00013ad7, +0x00013ad6, +0x00013ad4, +0x00013ad2, +0x00013ad1, +0x00013ad0, +0x00013ace, +0x00013acc, +0x00013acb, +0x00013aca, +0x00013ac7, +0x00013ac6, +0x00013ac5, +0x00013ac4, +0x00013ac2, +0x00013ac0, +0x00013abf, +0x00013abe, +0x00013abc, +0x00013aba, +0x00013ab9, +0x00013ab7, +0x00013ab6, +0x00013ab4, +0x00013ab3, +0x00013ab1, +0x00013aaf, +0x00013aae, +0x00013aad, +0x00013aaa, +0x00013aa9, +0x00013aa8, +0x00013aa7, +0x00013aa4, +0x00013aa3, +0x00013aa2, +0x00013aa1, +0x00013a9f, +0x00013a9d, +0x00013a9c, +0x00013a9b, +0x00013a99, +0x00013a97, +0x00013a96, +0x00013a94, +0x00013a93, +0x00013a92, +0x00013a90, +0x00013a8e, +0x00013a8d, +0x00013a8c, +0x00013a89, +0x00013a88, +0x00013a87, +0x00013a86, +0x00013a83, +0x00013a82, +0x00013a81, +0x00013a80, +0x00013a7e, +0x00013a7c, +0x00013a7b, +0x00013a79, +0x00013a78, +0x00013a76, +0x00013a75, +0x00013a73, +0x00013a72, +0x00013a71, +0x00013a6e, +0x00013a6d, +0x00013a6c, +0x00013a6b, +0x00013a68, +0x00013a67, +0x00013a66, +0x00013a65, +0x00013a62, +0x00013a61, +0x00013a60, +0x00013a5e, +0x00013a5d, +0x00013a5b, +0x00013a5a, +0x00013a58, +0x00013a57, +0x00013a55, +0x00013a53, +0x00013a52, +0x00013a51, +0x00013a50, +0x00013a4d, +0x00013a4c, +0x00013a4b, +0x00013a4a, +0x00013a47, +0x00013a46, +0x00013a45, +0x00013a43, +0x00013a42, +0x00013a40, +0x00013a3f, +0x00013a3d, +0x00013a3c, +0x00013a3a, +0x00013a38, +0x00013a37, +0x00013a36, +0x00013a34, +0x00013a32, +0x00013a31, +0x00013a30, +0x00013a2f, +0x00013a2c, +0x00013a2b, +0x00013a2a, +0x00013a28, +0x00013a26, +0x00013a25, +0x00013a24, +0x00013a22, +0x00013a21, +0x00013a1f, +0x00013a1d, +0x00013a1c, +0x00013a1b, +0x00013a19, +0x00013a17, +0x00013a16, +0x00013a15, +0x00013a12, +0x00013a11, +0x00013a10, +0x00013a0f, +0x00013a0d, +0x00013a0b, +0x00013a0a, +0x00013a09, +0x00013a07, +0x00013a05, +0x00013a04, +0x00013a02, +0x00013a01, +0x00013a00, +0x000139fe, +0x000139fc, +0x000139fb, +0x000139fa, +0x000139f7, +0x000139f6, +0x000139f5, +0x000139f4, +0x000139f3, +0x000139f0, +0x000139ef, +0x000139ee, +0x000139ec, +0x000139ea, +0x000139e9, +0x000139e7, +0x000139e6, +0x000139e4, +0x000139e3, +0x000139e1, +0x000139e0, +0x000139df, +0x000139dc, +0x000139db, +0x000139da, +0x000139d9, +0x000139d6, +0x000139d5, +0x000139d4, +0x000139d3, +0x000139d1, +0x000139cf, +0x000139ce, +0x000139cc, +0x000139cb, +0x000139c9, +0x000139c8, +0x000139c6, +0x000139c5, +0x000139c3, +0x000139c1, +0x000139c0, +0x000139bf, +0x000139be, +0x000139bb, +0x000139ba, +0x000139b9, +0x000139b8, +0x000139b5, +0x000139b4, +0x000139b3, +0x000139b2, +0x000139b0, +0x000139ae, +0x000139ad, +0x000139ab, +0x000139aa, +0x000139a8, +0x000139a6, +0x000139a5, +0x000139a4, +0x000139a2, +0x000139a0, +0x0001399f, +0x0001399e, +0x0001399d, +0x0001399a, +0x00013999, +0x00013998, +0x00013997, +0x00013994, +0x00013993, +0x00013992, +0x00013990, +0x0001398f, +0x0001398d, +0x0001398b, +0x0001398a, +0x00013989, +0x00013987, +0x00013985, +0x00013984, +0x00013983, +0x00013982, +0x0001397f, +0x0001397e, +0x0001397d, +0x0001397c, +0x00013979, +0x00013978, +0x00013977, +0x00013975, +0x00013973, +0x00013972, +0x00013970, +0x0001396f, +0x0001396e, +0x0001396c, +0x0001396a, +0x00013969, +0x00013968, +0x00013965, +0x00013964, +0x00013963, +0x00013962, +0x00013961, +0x0001395e, +0x0001395d, +0x0001395c, +0x0001395a, +0x00013958, +0x00013957, +0x00013956, +0x00013954, +0x00013952, +0x00013951, +0x0001394f, +0x0001394e, +0x0001394d, +0x0001394a, +0x00013949, +0x00013948, +0x00013947, +0x00013944, +0x00013943, +0x00013942, +0x00013941, +0x0001393f, +0x0001393d, +0x0001393c, +0x0001393b, +0x00013939, +0x00013937, +0x00013936, +0x00013934, +0x00013933, +0x00013932, +0x00013931, +0x0001392e, +0x0001392d, +0x0001392c, +0x0001392b, +0x00013928, +0x00013927, +0x00013926, +0x00013925, +0x00013923, +0x00013921, +0x00013920, +0x0001391f, +0x0001391d, +0x0001391b, +0x0001391a, +0x00013918, +0x00013917, +0x00013916, +0x00013914, +0x00013912, +0x00013911, +0x00013910, +0x0001390d, +0x0001390c, +0x0001390b, +0x0001390a, +0x00013909, +0x00013906, +0x00013905, +0x00013904, +0x00013902, +0x00013900, +0x000138ff, +0x000138fe, +0x000138fc, +0x000138fb, +0x000138f9, +0x000138f7, +0x000138f6, +0x000138f5, +0x000138f3, +0x000138f1, +0x000138f0, +0x000138ef, +0x000138ee, +0x000138eb, +0x000138ea, +0x000138e9, +0x000138e8, +0x000138e5, +0x000138e4, +0x000138e3, +0x000138e1, +0x000138e0, +0x000138de, +0x000138dd, +0x000138db, +0x000138da, +0x000138d8, +0x000138d6, +0x000138d5, +0x000138d4, +0x000138d3, +0x000138d0, +0x000138cf, +0x000138ce, +0x000138cd, +0x000138ca, +0x000138c9, +0x000138c8, +0x000138c7, +0x000138c4, +0x000138c3, +0x000138c2, +0x000138c0, +0x000138bf, +0x000138bd, +0x000138bc, +0x000138ba, +0x000138b9, +0x000138b7, +0x000138b5, +0x000138b4, +0x000138b3, +0x000138b2, +0x000138af, +0x000138ae, +0x000138ad, +0x000138ac, +0x000138a9, +0x000138a8, +0x000138a7, +0x000138a6, +0x000138a4, +0x000138a2, +0x000138a1, +0x0001389f, +0x0001389e, +0x0001389c, +0x0001389b, +0x00013899, +0x00013898, +0x00013897, +0x00013894, +0x00013893, +0x00013892, +0x00013891, +0x0001388e, +0x0001388d, +0x0001388c, +0x0001388b, +0x00013889, +0x00013887, +0x00013886, +0x00013885, +0x00013883, +0x00013881, +0x00013880, +0x0001387e, +0x0001387d, +0x0001387c, +0x0001387a, +0x00013878, +0x00013877, +0x00013876, +0x00013873, +0x00013873, +0x00013871, +0x00013870, +0x0001386e, +0x0001386c, +0x0001386b, +0x0001386a, +0x00013868, +0x00013866, +0x00013865, +0x00013864, +0x00013863, +0x00013860, +0x0001385f, +0x0001385e, +0x0001385d, +0x0001385b, +0x00013859, +0x00013858, +0x00013857, +0x00013855, +0x00013853, +0x00013852, +0x00013850, +0x0001384f, +0x0001384e, +0x0001384c, +0x0001384a, +0x00013849, +0x00013848, +0x00013845, +0x00013844, +0x00013843, +0x00013842, +0x00013841, +0x0001383e, +0x0001383d, +0x0001383c, +0x0001383b, +0x00013838, +0x00013837, +0x00013836, +0x00013834, +0x00013833, +0x00013831, +0x00013830, +0x0001382e, +0x0001382d, +0x0001382c, +0x00013829, +0x00013828, +0x00013827, +0x00013826, +0x00013823, +0x00013822, +0x00013821, +0x00013820, +0x0001381e, +0x0001381c, +0x0001381b, +0x0001381a, +0x00013818, +0x00013816, +0x00013815, +0x00013814, +0x00013812, +0x00013811, +0x0001380f, +0x0001380d, +0x0001380c, +0x0001380b, +0x00013809, +0x00013807, +0x00013806, +0x00013805, +0x00013804, +0x00013801, +0x00013800, +0x000137ff, +0x000137fe, +0x000137fc, +0x000137fa, +0x000137f9, +0x000137f7, +0x000137f6, +0x000137f4, +0x000137f3, +0x000137f1, +0x000137f0, +0x000137ef, +0x000137ed, +0x000137eb, +0x000137ea, +0x000137e9, +0x000137e6, +0x000137e5, +0x000137e4, +0x000137e3, +0x000137e2, +0x000137df, +0x000137de, +0x000137dd, +0x000137db, +0x000137d9, +0x000137d8, +0x000137d7, +0x000137d5, +0x000137d4, +0x000137d2, +0x000137d0, +0x000137cf, +0x000137ce, +0x000137cd, +0x000137ca, +0x000137c9, +0x000137c8, +0x000137c7, +0x000137c4, +0x000137c3, +0x000137c2, +0x000137c1, +0x000137bf, +0x000137bd, +0x000137bc, +0x000137bb, +0x000137b9, +0x000137b7, +0x000137b6, +0x000137b4, +0x000137b3, +0x000137b1, +0x000137b0, +0x000137ae, +0x000137ad, +0x000137ab, +0x000137aa, +0x000137a9, +0x000137a6, +0x000137a5, +0x000137a4, +0x000137a3, +0x000137a0, +0x0001379f, +0x0001379e, +0x0001379d, +0x0001379c, +0x00013799, +0x00013798, +0x00013797, +0x00013795, +0x00013794, +0x00013792, +0x00013791, +0x0001378f, +0x0001378e, +0x0001378c, +0x0001378a, +0x00013789, +0x00013788, +0x00013787, +0x00013784, +0x00013783, +0x00013782, +0x00013781, +0x00013780, +0x0001377d, +0x0001377c, +0x0001377b, +0x00013779, +0x00013777, +0x00013776, +0x00013775, +0x00013773, +0x00013772, +0x00013770, +0x0001376f, +0x0001376d, +0x0001376c, +0x0001376b, +0x00013768, +0x00013767, +0x00013766, +0x00013765, +0x00013762, +0x00013761, +0x00013760, +0x0001375f, +0x0001375e, +0x0001375b, +0x0001375a, +0x00013759, +0x00013757, +0x00013756, +0x00013754, +0x00013753, +0x00013751, +0x00013750, +0x0001374e, +0x0001374d, +0x0001374b, +0x0001374a, +0x00013749, +0x00013746, +0x00013745, +0x00013744, +0x00013743, +0x00013740, +0x0001373f, +0x0001373e, +0x0001373d, +0x0001373c, +0x00013739, +0x00013738, +0x00013737, +0x00013735, +0x00013734, +0x00013732, +0x00013731, +0x0001372f, +0x0001372e, +0x0001372c, +0x0001372b, +0x00013729, +0x00013728, +0x00013727, +0x00013724, +0x00013723, +0x00013722, +0x00013721, +0x00013720, +0x0001371d, +0x0001371c, +0x0001371b, +0x0001371a, +0x00013717, +0x00013716, +0x00013715, +0x00013713, +0x00013712, +0x00013710, +0x0001370f, +0x0001370d, +0x0001370c, +0x0001370b, +0x00013709, +0x00013707, +0x00013706, +0x00013705, +0x00013702, +0x00013701, +0x00013700, +0x000136ff, +0x000136fe, +0x000136fb, +0x000136fa, +0x000136f9, +0x000136f7, +0x000136f6, +0x000136f4, +0x000136f3, +0x000136f1, +0x000136f0, +0x000136ee, +0x000136ed, +0x000136eb, +0x000136ea, +0x000136e9, +0x000136e6, +0x000136e5, +0x000136e4, +0x000136e3, +0x000136e2, +0x000136df, +0x000136de, +0x000136dd, +0x000136dc, +0x000136d9, +0x000136d8, +0x000136d7, +0x000136d5, +0x000136d4, +0x000136d2, +0x000136d1, +0x000136cf, +0x000136ce, +0x000136cd, +0x000136cb, +0x000136c9, +0x000136c8, +0x000136c7, +0x000136c4, +0x000136c3, +0x000136c2, +0x000136c1, +0x000136c0, +0x000136bd, +0x000136bc, +0x000136bb, +0x000136ba, +0x000136b8, +0x000136b6, +0x000136b5, +0x000136b3, +0x000136b2, +0x000136b0, +0x000136af, +0x000136ad, +0x000136ac, +0x000136ab, +0x000136a9, +0x000136a7, +0x000136a6, +0x000136a5, +0x000136a4, +0x000136a1, +0x000136a0, +0x0001369f, +0x0001369e, +0x0001369b, +0x0001369a, +0x00013699, +0x00013698, +0x00013696, +0x00013694, +0x00013693, +0x00013691, +0x00013690, +0x0001368e, +0x0001368d, +0x0001368b, +0x0001368a, +0x00013689, +0x00013687, +0x00013685, +0x00013684, +0x00013683, +0x00013682, +0x0001367f, +0x0001367e, +0x0001367d, +0x0001367c, +0x00013679, +0x00013678, +0x00013677, +0x00013676, +0x00013674, +0x00013672, +0x00013671, +0x0001366f, +0x0001366e, +0x0001366d, +0x0001366b, +0x00013669, +0x00013668, +0x00013667, +0x00013665, +0x00013663, +0x00013662, +0x00013661, +0x00013660, +0x0001365d, +0x0001365c, +0x0001365b, +0x0001365a, +0x00013658, +0x00013656, +0x00013655, +0x00013653, +0x00013652, +0x00013650, +0x0001364f, +0x0001364d, +0x0001364c, +0x0001364b, +0x00013649, +0x00013647, +0x00013646, +0x00013645, +0x00013644, +0x00013641, +0x00013640, +0x0001363f, +0x0001363e, +0x0001363b, +0x0001363b, +0x00013639, +0x00013638, +0x00013636, +0x00013635, +0x00013633, +0x00013632, +0x00013630, +0x0001362f, +0x0001362e, +0x0001362c, +0x0001362a, +0x00013629, +0x00013628, +0x00013627, +0x00013624, +0x00013623, +0x00013622, +0x00013621, +0x0001361e, +0x0001361d, +0x0001361c, +0x0001361b, +0x00013619, +0x00013617, +0x00013616, +0x00013615, +0x00013613, +0x00013612, +0x00013610, +0x0001360f, +0x0001360d, +0x0001360c, +0x0001360b, +0x00013608, +0x00013607, +0x00013606, +0x00013605, +0x00013602, +0x00013601, +0x00013600, +0x000135ff, +0x000135fe, +0x000135fb, +0x000135fa, +0x000135f9, +0x000135f8, +0x000135f6, +0x000135f4, +0x000135f3, +0x000135f1, +0x000135f0, +0x000135ef, +0x000135ed, +0x000135eb, +0x000135ea, +0x000135e9, +0x000135e7, +0x000135e5, +0x000135e4, +0x000135e3, +0x000135e2, +0x000135df, +0x000135de, +0x000135dd, +0x000135dc, +0x000135da, +0x000135d8, +0x000135d7, +0x000135d6, +0x000135d4, +0x000135d3, +0x000135d1, +0x000135d0, +0x000135ce, +0x000135cd, +0x000135cb, +0x000135ca, +0x000135c8, +0x000135c7, +0x000135c6, +0x000135c3, +0x000135c2, +0x000135c1, +0x000135c0, +0x000135bf, +0x000135bc, +0x000135bb, +0x000135ba, +0x000135b9, +0x000135b7, +0x000135b5, +0x000135b4, +0x000135b3, +0x000135b1, +0x000135af, +0x000135ae, +0x000135ac, +0x000135ab, +0x000135aa, +0x000135a8, +0x000135a6, +0x000135a5, +0x000135a4, +0x000135a3, +0x000135a0, +0x0001359f, +0x0001359e, +0x0001359d, +0x0001359b, +0x00013599, +0x00013598, +0x00013597, +0x00013595, +0x00013593, +0x00013592, +0x00013591, +0x0001358f, +0x0001358e, +0x0001358c, +0x0001358b, +0x00013589, +0x00013588, +0x00013587, +0x00013584, +0x00013583, +0x00013582, +0x00013581, +0x0001357f, +0x0001357e, +0x0001357c, +0x0001357b, +0x00013579, +0x00013577, +0x00013576, +0x00013575, +0x00013574, +0x00013571, +0x00013570, +0x0001356f, +0x0001356e, +0x0001356d, +0x0001356a, +0x00013569, +0x00013568, +0x00013567, +0x00013565, +0x00013563, +0x00013562, +0x00013561, +0x0001355f, +0x0001355d, +0x0001355c, +0x0001355b, +0x00013559, +0x00013558, +0x00013556, +0x00013554, +0x00013553, +0x00013552, +0x00013551, +0x0001354e, +0x0001354d, +0x0001354c, +0x0001354b, +0x0001354a, +0x00013547, +0x00013546, +0x00013545, +0x00013544, +0x00013542, +0x00013540, +0x0001353f, +0x0001353e, +0x0001353c, +0x0001353b, +0x00013539, +0x00013538, +0x00013536, +0x00013535, +0x00013533, +0x00013531, +0x00013530, +0x0001352f, +0x0001352e, +0x0001352b, +0x0001352a, +0x00013529, +0x00013528, +0x00013527, +0x00013524, +0x00013523, +0x00013522, +0x00013521, +0x0001351f, +0x0001351d, +0x0001351c, +0x0001351b, +0x00013519, +0x00013518, +0x00013516, +0x00013515, +0x00013513, +0x00013512, +0x00013511, +0x0001350e, +0x0001350d, +0x0001350c, +0x0001350b, +0x00013508, +0x00013507, +0x00013506, +0x00013505, +0x00013504, +0x00013501, +0x00013500, +0x000134ff, +0x000134fe, +0x000134fc, +0x000134fa, +0x000134f9, +0x000134f8, +0x000134f6, +0x000134f5, +0x000134f3, +0x000134f2, +0x000134f0, +0x000134ef, +0x000134ee, +0x000134eb, +0x000134ea, +0x000134e9, +0x000134e8, +0x000134e7, +0x000134e4, +0x000134e3, +0x000134e2, +0x000134e1, +0x000134de, +0x000134dd, +0x000134dc, +0x000134db, +0x000134d9, +0x000134d7, +0x000134d6, +0x000134d5, +0x000134d3, +0x000134d2, +0x000134d0, +0x000134cf, +0x000134cd, +0x000134cc, +0x000134cb, +0x000134c8, +0x000134c7, +0x000134c6, +0x000134c4, +0x000134c3, +0x000134c2, +0x000134bf, +0x000134be, +0x000134bd, +0x000134bc, +0x000134ba, +0x000134b8, +0x000134b7, +0x000134b6, +0x000134b4, +0x000134b3, +0x000134b1, +0x000134b0, +0x000134ae, +0x000134ad, +0x000134ac, +0x000134aa, +0x000134a8, +0x000134a7, +0x000134a6, +0x000134a5, +0x000134a2, +0x000134a1, +0x000134a0, +0x0001349f, +0x0001349e, +0x0001349b, +0x0001349a, +0x00013499, +0x00013498, +0x00013496, +0x00013494, +0x00013493, +0x00013492, +0x00013490, +0x0001348e, +0x0001348d, +0x0001348c, +0x0001348a, +0x00013489, +0x00013487, +0x00013486, +0x00013484, +0x00013483, +0x00013482, +0x00013480, +0x0001347e, +0x0001347d, +0x0001347c, +0x0001347b, +0x00013478, +0x00013477, +0x00013476, +0x00013475, +0x00013474, +0x00013471, +0x00013470, +0x0001346f, +0x0001346d, +0x0001346c, +0x0001346a, +0x00013469, +0x00013467, +0x00013466, +0x00013465, +0x00013463, +0x00013461, +0x00013460, +0x0001345f, +0x0001345e, +0x0001345b, +0x0001345a, +0x00013459, +0x00013458, +0x00013457, +0x00013454, +0x00013453, +0x00013452, +0x00013451, +0x0001344f, +0x0001344d, +0x0001344c, +0x0001344b, +0x00013449, +0x00013448, +0x00013446, +0x00013445, +0x00013443, +0x00013442, +0x00013441, +0x0001343f, +0x0001343d, +0x0001343c, +0x0001343b, +0x0001343a, +0x00013437, +0x00013436, +0x00013435, +0x00013434, +0x00013431, +0x00013430, +0x0001342f, +0x0001342e, +0x0001342d, +0x0001342a, +0x00013429, +0x00013428, +0x00013427, +0x00013425, +0x00013423, +0x00013422, +0x00013420, +0x0001341f, +0x0001341e, +0x0001341c, +0x0001341a, +0x00013419, +0x00013418, +0x00013417, +0x00013414, +0x00013413, +0x00013412, +0x00013411, +0x00013410, +0x0001340d, +0x0001340c, +0x0001340b, +0x0001340a, +0x00013408, +0x00013406, +0x00013405, +0x00013404, +0x00013402, +0x00013401, +0x000133ff, +0x000133fe, +0x000133fc, +0x000133fb, +0x000133fa, +0x000133f8, +0x000133f6, +0x000133f5, +0x000133f4, +0x000133f3, +0x000133f0, +0x000133ef, +0x000133ee, +0x000133ed, +0x000133ec, +0x000133e9, +0x000133e8, +0x000133e7, +0x000133e6, +0x000133e4, +0x000133e2, +0x000133e1, +0x000133e0, +0x000133de, +0x000133dd, +0x000133db, +0x000133da, +0x000133d8, +0x000133d7, +0x000133d5, +0x000133d3, +0x000133d2, +0x000133d1, +0x000133d0, +0x000133cd, +0x000133cc, +0x000133cb, +0x000133ca, +0x000133c9, +0x000133c6, +0x000133c5, +0x000133c4, +0x000133c3, +0x000133c1, +0x000133bf, +0x000133be, +0x000133bd, +0x000133bb, +0x000133ba, +0x000133b8, +0x000133b7, +0x000133b5, +0x000133b4, +0x000133b3, +0x000133b1, +0x000133af, +0x000133ae, +0x000133ad, +0x000133ac, +0x000133a9, +0x000133a8, +0x000133a7, +0x000133a6, +0x000133a5, +0x000133a2, +0x000133a1, +0x000133a0, +0x0001339f, +0x0001339d, +0x0001339b, +0x0001339a, +0x00013399, +0x00013397, +0x00013396, +0x00013394, +0x00013393, +0x00013391, +0x00013390, +0x0001338f, +0x0001338d, +0x0001338b, +0x0001338a, +0x00013389, +0x00013388, +0x00013385, +0x00013384, +0x00013383, +0x00013382, +0x00013380, +0x0001337e, +0x0001337d, +0x0001337c, +0x0001337a, +0x00013378, +0x00013377, +0x00013376, +0x00013374, +0x00013373, +0x00013371, +0x00013370, +0x0001336e, +0x0001336d, +0x0001336c, +0x0001336a, +0x00013368, +0x00013367, +0x00013366, +0x00013365, +0x00013362, +0x00013361, +0x00013360, +0x0001335f, +0x0001335e, +0x0001335b, +0x0001335a, +0x00013359, +0x00013358, +0x00013356, +0x00013354, +0x00013353, +0x00013352, +0x00013350, +0x0001334f, +0x0001334e, +0x0001334c, +0x0001334a, +0x00013349, +0x00013348, +0x00013347, +0x00013344, +0x00013343, +0x00013342, +0x00013341, +0x00013340, +0x0001333d, +0x0001333c, +0x0001333b, +0x0001333a, +0x00013338, +0x00013336, +0x00013335, +0x00013334, +0x00013332, +0x00013331, +0x0001332f, +0x0001332e, +0x0001332c, +0x0001332b, +0x0001332a, +0x00013328, +0x00013326, +0x00013325, +0x00013324, +0x00013323, +0x00013320, +0x0001331f, +0x0001331e, +0x0001331d, +0x0001331c, +0x00013319, +0x00013318, +0x00013317, +0x00013316, +0x00013314, +0x00013312, +0x00013311, +0x00013310, +0x0001330e, +0x0001330d, +0x0001330b, +0x0001330a, +0x00013308, +0x00013307, +0x00013306, +0x00013304, +0x00013302, +0x00013301, +0x00013300, +0x000132ff, +0x000132fc, +0x000132fb, +0x000132fa, +0x000132f9, +0x000132f8, +0x000132f6, +0x000132f4, +0x000132f3, +0x000132f2, +0x000132f0, +0x000132ef, +0x000132ed, +0x000132ec, +0x000132ea, +0x000132e9, +0x000132e8, +0x000132e6, +0x000132e4, +0x000132e3, +0x000132e2, +0x000132e1, +0x000132de, +0x000132dd, +0x000132dc, +0x000132db, +0x000132da, +0x000132d7, +0x000132d6, +0x000132d5, +0x000132d4, +0x000132d2, +0x000132d0, +0x000132cf, +0x000132ce, +0x000132cc, +0x000132cb, +0x000132c9, +0x000132c8, +0x000132c6, +0x000132c5, +0x000132c4, +0x000132c2, +0x000132c0, +0x000132bf, +0x000132be, +0x000132bd, +0x000132ba, +0x000132b9, +0x000132b8, +0x000132b7, +0x000132b6, +0x000132b3, +0x000132b2, +0x000132b1, +0x000132b0, +0x000132ae, +0x000132ac, +0x000132ab, +0x000132aa, +0x000132a8, +0x000132a7, +0x000132a5, +0x000132a4, +0x000132a2, +0x000132a1, +0x000132a0, +0x0001329e, +0x0001329c, +0x0001329b, +0x0001329a, +0x00013298, +0x00013297, +0x00013295, +0x00013294, +0x00013293, +0x00013291, +0x0001328f, +0x0001328e, +0x0001328d, +0x0001328c, +0x00013289, +0x00013288, +0x00013287, +0x00013286, +0x00013285, +0x00013282, +0x00013281, +0x00013280, +0x0001327f, +0x0001327e, +0x0001327b, +0x0001327a, +0x00013279, +0x00013278, +0x00013276, +0x00013274, +0x00013273, +0x00013272, +0x00013270, +0x0001326f, +0x0001326d, +0x0001326c, +0x0001326a, +0x00013269, +0x00013268, +0x00013266, +0x00013264, +0x00013263, +0x00013262, +0x00013261, +0x0001325e, +0x0001325d, +0x0001325c, +0x0001325b, +0x0001325a, +0x00013258, +0x00013256, +0x00013255, +0x00013254, +0x00013252, +0x00013251, +0x0001324f, +0x0001324e, +0x0001324d, +0x0001324b, +0x0001324a, +0x00013248, +0x00013247, +0x00013245, +0x00013244, +0x00013243, +0x00013241, +0x0001323f, +0x0001323e, +0x0001323d, +0x0001323c, +0x00013239, +0x00013238, +0x00013237, +0x00013236, +0x00013235, +0x00013232, +0x00013231, +0x00013230, +0x0001322f, +0x0001322d, +0x0001322b, +0x0001322a, +0x00013229, +0x00013227, +0x00013226, +0x00013224, +0x00013223, +0x00013221, +0x00013220, +0x0001321f, +0x0001321e, +0x0001321b, +0x0001321a, +0x00013219, +0x00013218, +0x00013217, +0x00013214, +0x00013213, +0x00013212, +0x00013211, +0x00013210, +0x0001320d, +0x0001320c, +0x0001320b, +0x0001320a, +0x00013208, +0x00013206, +0x00013205, +0x00013204, +0x00013202, +0x00013201, +0x000131ff, +0x000131fe, +0x000131fc, +0x000131fb, +0x000131fa, +0x000131f8, +0x000131f6, +0x000131f5, +0x000131f4, +0x000131f3, +0x000131f0, +0x000131ef, +0x000131ee, +0x000131ed, +0x000131ec, +0x000131e9, +0x000131e8, +0x000131e7, +0x000131e6, +0x000131e5, +0x000131e3, +0x000131e1, +0x000131e0, +0x000131df, +0x000131dd, +0x000131dc, +0x000131da, +0x000131d9, +0x000131d7, +0x000131d6, +0x000131d5, +0x000131d3, +0x000131d1, +0x000131d0, +0x000131cf, +0x000131ce, +0x000131cb, +0x000131ca, +0x000131c9, +0x000131c8, +0x000131c7, +0x000131c4, +0x000131c3, +0x000131c2, +0x000131c1, +0x000131bf, +0x000131bd, +0x000131bc, +0x000131bb, +0x000131b9, +0x000131b8, +0x000131b6, +0x000131b5, +0x000131b4, +0x000131b2, +0x000131b1, +0x000131af, +0x000131ae, +0x000131ac, +0x000131ab, +0x000131aa, +0x000131a8, +0x000131a6, +0x000131a5, +0x000131a4, +0x000131a3, +0x000131a2, +0x0001319f, +0x0001319e, +0x0001319d, +0x0001319c, +0x0001319a, +0x00013198, +0x00013197, +0x00013196, +0x00013194, +0x00013193, +0x00013191, +0x00013190, +0x0001318e, +0x0001318d, +0x0001318c, +0x0001318a, +0x00013188, +0x00013187, +0x00013186, +0x00013185, +0x00013182, +0x00013181, +0x00013180, +0x0001317f, +0x0001317e, +0x0001317b, +0x0001317a, +0x00013179, +0x00013178, +0x00013177, +0x00013174, +0x00013173, +0x00013172, +0x00013171, +0x0001316f, +0x0001316d, +0x0001316c, +0x0001316b, +0x00013169, +0x00013168, +0x00013167, +0x00013165, +0x00013163, +0x00013162, +0x00013161, +0x00013160, +0x0001315d, +0x0001315c, +0x0001315b, +0x0001315a, +0x00013159, +0x00013156, +0x00013155, +0x00013154, +0x00013153, +0x00013151, +0x0001314f, +0x0001314e, +0x0001314d, +0x0001314c, +0x0001314a, +0x00013148, +0x00013147, +0x00013146, +0x00013144, +0x00013143, +0x00013141, +0x00013140, +0x0001313e, +0x0001313d, +0x0001313c, +0x0001313a, +0x00013138, +0x00013137, +0x00013136, +0x00013135, +0x00013132, +0x00013131, +0x00013130, +0x0001312f, +0x0001312e, +0x0001312c, +0x0001312b, +0x0001312a, +0x00013129, +0x00013126, +0x00013125, +0x00013124, +0x00013123, +0x00013121, +0x00013120, +0x0001311e, +0x0001311d, +0x0001311b, +0x0001311a, +0x00013119, +0x00013117, +0x00013115, +0x00013114, +0x00013113, +0x00013112, +0x0001310f, +0x0001310e, +0x0001310d, +0x0001310c, +0x0001310b, +0x00013108, +0x00013107, +0x00013106, +0x00013105, +0x00013104, +0x00013102, +0x00013100, +0x000130ff, +0x000130fe, +0x000130fc, +0x000130fb, +0x000130f9, +0x000130f8, +0x000130f6, +0x000130f5, +0x000130f4, +0x000130f2, +0x000130f1, +0x000130ef, +0x000130ee, +0x000130ed, +0x000130eb, +0x000130e9, +0x000130e8, +0x000130e7, +0x000130e6, +0x000130e3, +0x000130e2, +0x000130e1, +0x000130e0, +0x000130df, +0x000130dd, +0x000130db, +0x000130da, +0x000130d9, +0x000130d7, +0x000130d6, +0x000130d4, +0x000130d3, +0x000130d2, +0x000130d0, +0x000130cf, +0x000130cd, +0x000130cc, +0x000130ca, +0x000130c9, +0x000130c8, +0x000130c6, +0x000130c4, +0x000130c3, +0x000130c2, +0x000130c1, +0x000130c0, +0x000130bd, +0x000130bc, +0x000130bb, +0x000130ba, +0x000130b9, +0x000130b6, +0x000130b5, +0x000130b4, +0x000130b3, +0x000130b1, +0x000130af, +0x000130ae, +0x000130ad, +0x000130ab, +0x000130aa, +0x000130a8, +0x000130a7, +0x000130a5, +0x000130a4, +0x000130a3, +0x000130a1, +0x0001309f, +0x0001309e, +0x0001309d, +0x0001309c, +0x0001309b, +0x00013098, +0x00013097, +0x00013096, +0x00013095, +0x00013094, +0x00013091, +0x00013090, +0x0001308f, +0x0001308e, +0x0001308c, +0x0001308a, +0x00013089, +0x00013088, +0x00013086, +0x00013085, +0x00013083, +0x00013082, +0x00013081, +0x0001307f, +0x0001307e, +0x0001307d, +0x0001307b, +0x00013079, +0x00013078, +0x00013077, +0x00013076, +0x00013074, +0x00013072, +0x00013071, +0x00013070, +0x0001306e, +0x0001306d, +0x0001306c, +0x0001306a, +0x00013069, +0x00013067, +0x00013066, +0x00013065, +0x00013063, +0x00013061, +0x00013060, +0x0001305f, +0x0001305e, +0x0001305b, +0x0001305a, +0x00013059, +0x00013058, +0x00013057, +0x00013056, +0x00013053, +0x00013052, +0x00013051, +0x00013050, +0x0001304e, +0x0001304c, +0x0001304b, +0x0001304a, +0x00013048, +0x00013047, +0x00013045, +0x00013044, +0x00013043, +0x00013041, +0x00013040, +0x0001303f, +0x0001303d, +0x0001303b, +0x0001303a, +0x00013039, +0x00013038, +0x00013035, +0x00013034, +0x00013033, +0x00013032, +0x00013031, +0x0001302e, +0x0001302d, +0x0001302c, +0x0001302b, +0x0001302a, +0x00013028, +0x00013026, +0x00013025, +0x00013024, +0x00013022, +0x00013021, +0x0001301f, +0x0001301e, +0x0001301d, +0x0001301b, +0x0001301a, +0x00013018, +0x00013017, +0x00013015, +0x00013014, +0x00013013, +0x00013012, +0x0001300f, +0x0001300e, +0x0001300d, +0x0001300c, +0x0001300b, +0x00013008, +0x00013007, +0x00013006, +0x00013005, +0x00013004, +0x00013001, +0x00013000, +0x00012fff, +0x00012ffe, +0x00012ffc, +0x00012ffb, +0x00012ff9, +0x00012ff8, +0x00012ff7, +0x00012ff5, +0x00012ff4, +0x00012ff2, +0x00012ff1, +0x00012fef, +0x00012fee, +0x00012fed, +0x00012feb, +0x00012fe9, +0x00012fe8, +0x00012fe7, +0x00012fe6, +0x00012fe5, +0x00012fe2, +0x00012fe1, +0x00012fe0, +0x00012fdf, +0x00012fde, +0x00012fdb, +0x00012fda, +0x00012fd9, +0x00012fd8, +0x00012fd6, +0x00012fd4, +0x00012fd3, +0x00012fd2, +0x00012fd1, +0x00012fcf, +0x00012fce, +0x00012fcc, +0x00012fcb, +0x00012fc9, +0x00012fc8, +0x00012fc7, +0x00012fc5, +0x00012fc3, +0x00012fc2, +0x00012fc1, +0x00012fbf, +0x00012fbd, +0x00012fbc, +0x00012fbb, +0x00012fba, +0x00012fb7, +0x00012fb6, +0x00012fb5, +0x00012fb4, +0x00012fb3, +0x00012fb2, +0x00012faf, +0x00012fae, +0x00012fad, +0x00012fac, +0x00012faa, +0x00012fa8, +0x00012fa7, +0x00012fa6, +0x00012fa5, +0x00012fa3, +0x00012fa2, +0x00012fa0, +0x00012f9f, +0x00012f9d, +0x00012f9c, +0x00012f9b, +0x00012f99, +0x00012f98, +0x00012f96, +0x00012f95, +0x00012f94, +0x00012f93, +0x00012f90, +0x00012f8f, +0x00012f8e, +0x00012f8d, +0x00012f8c, +0x00012f89, +0x00012f88, +0x00012f87, +0x00012f86, +0x00012f85, +0x00012f82, +0x00012f81, +0x00012f80, +0x00012f7f, +0x00012f7d, +0x00012f7c, +0x00012f7a, +0x00012f79, +0x00012f78, +0x00012f76, +0x00012f75, +0x00012f73, +0x00012f72, +0x00012f70, +0x00012f6f, +0x00012f6e, +0x00012f6d, +0x00012f6b, +0x00012f69, +0x00012f68, +0x00012f67, +0x00012f66, +0x00012f63, +0x00012f62, +0x00012f61, +0x00012f60, +0x00012f5f, +0x00012f5e, +0x00012f5b, +0x00012f5a, +0x00012f59, +0x00012f58, +0x00012f56, +0x00012f54, +0x00012f53, +0x00012f52, +0x00012f50, +0x00012f4f, +0x00012f4e, +0x00012f4c, +0x00012f4b, +0x00012f49, +0x00012f48, +0x00012f47, +0x00012f45, +0x00012f43, +0x00012f42, +0x00012f41, +0x00012f40, +0x00012f3e, +0x00012f3c, +0x00012f3b, +0x00012f3a, +0x00012f39, +0x00012f38, +0x00012f35, +0x00012f34, +0x00012f33, +0x00012f32, +0x00012f31, +0x00012f2e, +0x00012f2d, +0x00012f2c, +0x00012f2b, +0x00012f29, +0x00012f28, +0x00012f26, +0x00012f25, +0x00012f24, +0x00012f22, +0x00012f21, +0x00012f1f, +0x00012f1e, +0x00012f1c, +0x00012f1b, +0x00012f1a, +0x00012f19, +0x00012f16, +0x00012f15, +0x00012f14, +0x00012f13, +0x00012f12, +0x00012f0f, +0x00012f0e, +0x00012f0d, +0x00012f0c, +0x00012f0b, +0x00012f09, +0x00012f07, +0x00012f06, +0x00012f05, +0x00012f04, +0x00012f02, +0x00012f00, +0x00012eff, +0x00012efe, +0x00012efc, +0x00012efb, +0x00012ef9, +0x00012ef8, +0x00012ef7, +0x00012ef5, +0x00012ef4, +0x00012ef3, +0x00012ef1, +0x00012eef, +0x00012eee, +0x00012eed, +0x00012eec, +0x00012eea, +0x00012ee8, +0x00012ee7, +0x00012ee6, +0x00012ee5, +0x00012ee4, +0x00012ee1, +0x00012ee0, +0x00012edf, +0x00012ede, +0x00012edc, +0x00012eda, +0x00012ed9, +0x00012ed8, +0x00012ed7, +0x00012ed5, +0x00012ed4, +0x00012ed2, +0x00012ed1, +0x00012ecf, +0x00012ece, +0x00012ecd, +0x00012ecb, +0x00012eca, +0x00012ec8, +0x00012ec7, +0x00012ec6, +0x00012ec5, +0x00012ec2, +0x00012ec1, +0x00012ec0, +0x00012ebf, +0x00012ebe, +0x00012ebb, +0x00012eba, +0x00012eb9, +0x00012eb8, +0x00012eb7, +0x00012eb5, +0x00012eb3, +0x00012eb2, +0x00012eb1, +0x00012eb0, +0x00012eae, +0x00012eac, +0x00012eab, +0x00012eaa, +0x00012ea8, +0x00012ea7, +0x00012ea5, +0x00012ea4, +0x00012ea2, +0x00012ea1, +0x00012ea0, +0x00012e9f, +0x00012e9d, +0x00012e9b, +0x00012e9a, +0x00012e99, +0x00012e98, +0x00012e95, +0x00012e94, +0x00012e93, +0x00012e92, +0x00012e91, +0x00012e90, +0x00012e8d, +0x00012e8c, +0x00012e8b, +0x00012e8a, +0x00012e88, +0x00012e86, +0x00012e85, +0x00012e84, +0x00012e83, +0x00012e81, +0x00012e80, +0x00012e7e, +0x00012e7d, +0x00012e7b, +0x00012e7a, +0x00012e79, +0x00012e77, +0x00012e76, +0x00012e74, +0x00012e73, +0x00012e72, +0x00012e71, +0x00012e6e, +0x00012e6d, +0x00012e6c, +0x00012e6b, +0x00012e6a, +0x00012e67, +0x00012e66, +0x00012e65, +0x00012e64, +0x00012e63, +0x00012e60, +0x00012e5f, +0x00012e5e, +0x00012e5d, +0x00012e5c, +0x00012e5a, +0x00012e58, +0x00012e57, +0x00012e56, +0x00012e55, +0x00012e53, +0x00012e51, +0x00012e50, +0x00012e4f, +0x00012e4e, +0x00012e4d, +0x00012e4a, +0x00012e49, +0x00012e48, +0x00012e47, +0x00012e46, +0x00012e43, +0x00012e42, +0x00012e41, +0x00012e40, +0x00012e3f, +0x00012e3d, +0x00012e3b, +0x00012e3a, +0x00012e39, +0x00012e37, +0x00012e36, +0x00012e34, +0x00012e33, +0x00012e32, +0x00012e30, +0x00012e2f, +0x00012e2e, +0x00012e2c, +0x00012e2a, +0x00012e29, +0x00012e28, +0x00012e27, +0x00012e25, +0x00012e23, +0x00012e22, +0x00012e21, +0x00012e20, +0x00012e1f, +0x00012e1c, +0x00012e1b, +0x00012e1a, +0x00012e19, +0x00012e18, +0x00012e16, +0x00012e14, +0x00012e13, +0x00012e12, +0x00012e11, +0x00012e0f, +0x00012e0d, +0x00012e0c, +0x00012e0b, +0x00012e09, +0x00012e08, +0x00012e07, +0x00012e05, +0x00012e04, +0x00012e02, +0x00012e01, +0x00012e00, +0x00012dfe, +0x00012dfc, +0x00012dfb, +0x00012dfa, +0x00012df9, +0x00012df8, +0x00012df5, +0x00012df4, +0x00012df3, +0x00012df2, +0x00012df1, +0x00012dee, +0x00012ded, +0x00012dec, +0x00012deb, +0x00012dea, +0x00012de8, +0x00012de6, +0x00012de5, +0x00012de4, +0x00012de3, +0x00012de1, +0x00012de0, +0x00012dde, +0x00012ddd, +0x00012ddb, +0x00012dda, +0x00012dd9, +0x00012dd7, +0x00012dd6, +0x00012dd4, +0x00012dd3, +0x00012dd2, +0x00012dd1, +0x00012dce, +0x00012dcd, +0x00012dcc, +0x00012dcb, +0x00012dca, +0x00012dc7, +0x00012dc6, +0x00012dc5, +0x00012dc4, +0x00012dc3, +0x00012dc1, +0x00012dbf, +0x00012dbe, +0x00012dbd, +0x00012dbc, +0x00012dba, +0x00012db8, +0x00012db7, +0x00012db6, +0x00012db5, +0x00012db3, +0x00012db2, +0x00012db0, +0x00012daf, +0x00012dad, +0x00012dac, +0x00012dab, +0x00012da9, +0x00012da8, +0x00012da6, +0x00012da5, +0x00012da3, +0x00012da2, +0x00012da1, +0x00012da0, +0x00012d9e, +0x00012d9c, +0x00012d9b, +0x00012d9a, +0x00012d99, +0x00012d97, +0x00012d95, +0x00012d94, +0x00012d93, +0x00012d92, +0x00012d91, +0x00012d8e, +0x00012d8d, +0x00012d8c, +0x00012d8b, +0x00012d8a, +0x00012d88, +0x00012d86, +0x00012d85, +0x00012d84, +0x00012d83, +0x00012d81, +0x00012d7f, +0x00012d7e, +0x00012d7d, +0x00012d7b, +0x00012d7a, +0x00012d79, +0x00012d77, +0x00012d76, +0x00012d74, +0x00012d73, +0x00012d72, +0x00012d71, +0x00012d6f, +0x00012d6d, +0x00012d6c, +0x00012d6b, +0x00012d6a, +0x00012d67, +0x00012d66, +0x00012d65, +0x00012d64, +0x00012d63, +0x00012d62, +0x00012d5f, +0x00012d5e, +0x00012d5d, +0x00012d5c, +0x00012d5b, +0x00012d59, +0x00012d57, +0x00012d56, +0x00012d55, +0x00012d53, +0x00012d52, +0x00012d51, +0x00012d4f, +0x00012d4e, +0x00012d4c, +0x00012d4b, +0x00012d4a, +0x00012d48, +0x00012d47, +0x00012d45, +0x00012d44, +0x00012d43, +0x00012d42, +0x00012d3f, +0x00012d3e, +0x00012d3d, +0x00012d3c, +0x00012d3b, +0x00012d3a, +0x00012d37, +0x00012d36, +0x00012d35, +0x00012d34, +0x00012d33, +0x00012d30, +0x00012d2f, +0x00012d2e, +0x00012d2d, +0x00012d2c, +0x00012d2a, +0x00012d28, +0x00012d27, +0x00012d26, +0x00012d24, +0x00012d23, +0x00012d22, +0x00012d20, +0x00012d1f, +0x00012d1d, +0x00012d1c, +0x00012d1b, +0x00012d19, +0x00012d18, +0x00012d16, +0x00012d15, +0x00012d14, +0x00012d13, +0x00012d10, +0x00012d0f, +0x00012d0e, +0x00012d0d, +0x00012d0c, +0x00012d0b, +0x00012d08, +0x00012d07, +0x00012d06, +0x00012d05, +0x00012d04, +0x00012d01, +0x00012d00, +0x00012cff, +0x00012cfe, +0x00012cfc, +0x00012cfb, +0x00012cf9, +0x00012cf8, +0x00012cf7, +0x00012cf5, +0x00012cf4, +0x00012cf3, +0x00012cf1, +0x00012cf0, +0x00012cee, +0x00012ced, +0x00012cec, +0x00012cea, +0x00012ce8, +0x00012ce7, +0x00012ce6, +0x00012ce5, +0x00012ce4, +0x00012ce1, +0x00012ce0, +0x00012cdf, +0x00012cde, +0x00012cdd, +0x00012cdc, +0x00012cd9, +0x00012cd8, +0x00012cd7, +0x00012cd6, +0x00012cd4, +0x00012cd3, +0x00012cd1, +0x00012cd0, +0x00012ccf, +0x00012ccd, +0x00012ccc, +0x00012cca, +0x00012cc9, +0x00012cc8, +0x00012cc6, +0x00012cc5, +0x00012cc4, +0x00012cc2, +0x00012cc1, +0x00012cbf, +0x00012cbe, +0x00012cbd, +0x00012cbc, +0x00012cb9, +0x00012cb8, +0x00012cb7, +0x00012cb6, +0x00012cb5, +0x00012cb2, +0x00012cb1, +0x00012cb0, +0x00012caf, +0x00012cae, +0x00012cad, +0x00012caa, +0x00012ca9, +0x00012ca8, +0x00012ca7, +0x00012ca5, +0x00012ca4, +0x00012ca2, +0x00012ca1, +0x00012ca0, +0x00012c9e, +0x00012c9d, +0x00012c9b, +0x00012c9a, +0x00012c99, +0x00012c97, +0x00012c96, +0x00012c95, +0x00012c93, +0x00012c91, +0x00012c90, +0x00012c8f, +0x00012c8e, +0x00012c8d, +0x00012c8a, +0x00012c89, +0x00012c88, +0x00012c87, +0x00012c86, +0x00012c83, +0x00012c82, +0x00012c81, +0x00012c80, +0x00012c7f, +0x00012c7d, +0x00012c7b, +0x00012c7a, +0x00012c79, +0x00012c78, +0x00012c76, +0x00012c75, +0x00012c73, +0x00012c72, +0x00012c71, +0x00012c6f, +0x00012c6e, +0x00012c6c, +0x00012c6b, +0x00012c6a, +0x00012c68, +0x00012c67, +0x00012c66, +0x00012c64, +0x00012c62, +0x00012c61, +0x00012c60, +0x00012c5f, +0x00012c5e, +0x00012c5b, +0x00012c5a, +0x00012c59, +0x00012c58, +0x00012c57, +0x00012c56, +0x00012c53, +0x00012c52, +0x00012c51, +0x00012c50, +0x00012c4e, +0x00012c4c, +0x00012c4b, +0x00012c4a, +0x00012c49, +0x00012c47, +0x00012c46, +0x00012c45, +0x00012c43, +0x00012c42, +0x00012c40, +0x00012c3f, +0x00012c3e, +0x00012c3d, +0x00012c3b, +0x00012c39, +0x00012c38, +0x00012c37, +0x00012c36, +0x00012c35, +0x00012c32, +0x00012c31, +0x00012c30, +0x00012c2f, +0x00012c2e, +0x00012c2d, +0x00012c2a, +0x00012c29, +0x00012c28, +0x00012c27, +0x00012c26, +0x00012c24, +0x00012c22, +0x00012c21, +0x00012c20, +0x00012c1e, +0x00012c1d, +0x00012c1c, +0x00012c1a, +0x00012c19, +0x00012c17, +0x00012c16, +0x00012c15, +0x00012c13, +0x00012c12, +0x00012c10, +0x00012c0f, +0x00012c0e, +0x00012c0d, +0x00012c0b, +0x00012c09, +0x00012c08, +0x00012c07, +0x00012c06, +0x00012c05, +0x00012c02, +0x00012c01, +0x00012c00, +0x00012bff, +0x00012bfe, +0x00012bfc, +0x00012bfa, +0x00012bf9, +0x00012bf8, +0x00012bf7, +0x00012bf5, +0x00012bf4, +0x00012bf2, +0x00012bf1, +0x00012bf0, +0x00012bee, +0x00012bed, +0x00012beb, +0x00012bea, +0x00012be9, +0x00012be7, +0x00012be6, +0x00012be5, +0x00012be3, +0x00012be2, +0x00012be0, +0x00012bdf, +0x00012bde, +0x00012bdd, +0x00012bdb, +0x00012bd9, +0x00012bd8, +0x00012bd7, +0x00012bd6, +0x00012bd5, +0x00012bd2, +0x00012bd1, +0x00012bd0, +0x00012bcf, +0x00012bce, +0x00012bcc, +0x00012bca, +0x00012bc9, +0x00012bc8, +0x00012bc7, +0x00012bc5, +0x00012bc4, +0x00012bc2, +0x00012bc1, +0x00012bc0, +0x00012bbe, +0x00012bbd, +0x00012bbb, +0x00012bba, +0x00012bb9, +0x00012bb7, +0x00012bb6, +0x00012bb5, +0x00012bb3, +0x00012bb1, +0x00012bb0, +0x00012baf, +0x00012bae, +0x00012bad, +0x00012baa, +0x00012ba9, +0x00012ba8, +0x00012ba7, +0x00012ba6, +0x00012ba5, +0x00012ba2, +0x00012ba1, +0x00012ba0, +0x00012b9f, +0x00012b9e, +0x00012b9c, +0x00012b9a, +0x00012b99, +0x00012b98, +0x00012b97, +0x00012b94, +0x00012b93, +0x00012b92, +0x00012b91, +0x00012b90, +0x00012b8e, +0x00012b8c, +0x00012b8b, +0x00012b8a, +0x00012b89, +0x00012b87, +0x00012b86, +0x00012b84, +0x00012b83, +0x00012b82, +0x00012b80, +0x00012b7f, +0x00012b7e, +0x00012b7c, +0x00012b7b, +0x00012b79, +0x00012b78, +0x00012b77, +0x00012b76, +0x00012b74, +0x00012b72, +0x00012b71, +0x00012b70, +0x00012b6f, +0x00012b6e, +0x00012b6b, +0x00012b6a, +0x00012b69, +0x00012b68, +0x00012b67, +0x00012b66, +0x00012b63, +0x00012b62, +0x00012b61, +0x00012b60, +0x00012b5f, +0x00012b5d, +0x00012b5b, +0x00012b5a, +0x00012b59, +0x00012b58, +0x00012b56, +0x00012b55, +0x00012b53, +0x00012b52, +0x00012b51, +0x00012b4f, +0x00012b4e, +0x00012b4d, +0x00012b4b, +0x00012b4a, +0x00012b48, +0x00012b47, +0x00012b46, +0x00012b45, +0x00012b43, +0x00012b41, +0x00012b40, +0x00012b3f, +0x00012b3e, +0x00012b3c, +0x00012b3a, +0x00012b39, +0x00012b38, +0x00012b37, +0x00012b36, +0x00012b33, +0x00012b32, +0x00012b31, +0x00012b30, +0x00012b2f, +0x00012b2e, +0x00012b2b, +0x00012b2a, +0x00012b29, +0x00012b28, +0x00012b27, +0x00012b25, +0x00012b23, +0x00012b22, +0x00012b21, +0x00012b20, +0x00012b1e, +0x00012b1d, +0x00012b1b, +0x00012b1a, +0x00012b19, +0x00012b17, +0x00012b16, +0x00012b15, +0x00012b13, +0x00012b12, +0x00012b10, +0x00012b0f, +0x00012b0e, +0x00012b0d, +0x00012b0b, +0x00012b09, +0x00012b08, +0x00012b07, +0x00012b06, +0x00012b05, +0x00012b02, +0x00012b01, +0x00012b00, +0x00012aff, +0x00012afe, +0x00012afc, +0x00012afa, +0x00012af9, +0x00012af8, +0x00012af7, +0x00012af5, +0x00012af4, +0x00012af2, +0x00012af1, +0x00012af0, +0x00012aee, +0x00012aed, +0x00012aec, +0x00012aea, +0x00012ae9, +0x00012ae7, +0x00012ae6, +0x00012ae5, +0x00012ae4, +0x00012ae2, +0x00012ae0, +0x00012adf, +0x00012ade, +0x00012add, +0x00012adc, +0x00012ad9, +0x00012ad8, +0x00012ad7, +0x00012ad6, +0x00012ad5, +0x00012ad4, +0x00012ad1, +0x00012ad0, +0x00012acf, +0x00012ace, +0x00012acd, +0x00012acb, +0x00012ac9, +0x00012ac8, +0x00012ac7, +0x00012ac6, +0x00012ac4, +0x00012ac3, +0x00012ac1, +0x00012ac0, +0x00012abf, +0x00012abd, +0x00012abc, +0x00012abb, +0x00012ab9, +0x00012ab8, +0x00012ab6, +0x00012ab5, +0x00012ab4, +0x00012ab3, +0x00012ab1, +0x00012aaf, +0x00012aae, +0x00012aad, +0x00012aac, +0x00012aab, +0x00012aa8, +0x00012aa7, +0x00012aa6, +0x00012aa5, +0x00012aa4, +0x00012aa3, +0x00012aa0, +0x00012a9f, +0x00012a9e, +0x00012a9d, +0x00012a9c, +0x00012a9a, +0x00012a98, +0x00012a97, +0x00012a96, +0x00012a95, +0x00012a93, +0x00012a92, +0x00012a90, +0x00012a8f, +0x00012a8e, +0x00012a8c, +0x00012a8b, +0x00012a89, +0x00012a88, +0x00012a87, +0x00012a85, +0x00012a84, +0x00012a83, +0x00012a81, +0x00012a80, +0x00012a7e, +0x00012a7d, +0x00012a7c, +0x00012a7b, +0x00012a79, +0x00012a77, +0x00012a76, +0x00012a75, +0x00012a74, +0x00012a73, +0x00012a70, +0x00012a6f, +0x00012a6e, +0x00012a6d, +0x00012a6c, +0x00012a6b, +0x00012a68, +0x00012a67, +0x00012a66, +0x00012a65, +0x00012a63, +0x00012a62, +0x00012a60, +0x00012a5f, +0x00012a5e, +0x00012a5c, +0x00012a5b, +0x00012a5a, +0x00012a58, +0x00012a57, +0x00012a55, +0x00012a54, +0x00012a53, +0x00012a52, +0x00012a50, +0x00012a4e, +0x00012a4d, +0x00012a4c, +0x00012a4b, +0x00012a4a, +0x00012a47, +0x00012a46, +0x00012a45, +0x00012a44, +0x00012a43, +0x00012a42, +0x00012a3f, +0x00012a3e, +0x00012a3d, +0x00012a3c, +0x00012a3b, +0x00012a39, +0x00012a38, +0x00012a37, +0x00012a36, +0x00012a34, +0x00012a33, +0x00012a31, +0x00012a30, +0x00012a2f, +0x00012a2d, +0x00012a2c, +0x00012a2b, +0x00012a29, +0x00012a28, +0x00012a26, +0x00012a25, +0x00012a24, +0x00012a23, +0x00012a21, +0x00012a1f, +0x00012a1e, +0x00012a1d, +0x00012a1c, +0x00012a1b, +0x00012a18, +0x00012a17, +0x00012a16, +0x00012a15, +0x00012a14, +0x00012a13, +0x00012a10, +0x00012a0f, +0x00012a0e, +0x00012a0d, +0x00012a0c, +0x00012a0a, +0x00012a08, +0x00012a07, +0x00012a06, +0x00012a05, +0x00012a03, +0x00012a02, +0x00012a00, +0x000129ff, +0x000129fe, +0x000129fd, +0x000129fb, +0x000129fa, +0x000129f8, +0x000129f7, +0x000129f6, +0x000129f4, +0x000129f3, +0x000129f2, +0x000129f0, +0x000129ef, +0x000129ed, +0x000129ec, +0x000129eb, +0x000129ea, +0x000129e8, +0x000129e6, +0x000129e5, +0x000129e4, +0x000129e3, +0x000129e2, +0x000129e1, +0x000129de, +0x000129dd, +0x000129dc, +0x000129db, +0x000129da, +0x000129d8, +0x000129d6, +0x000129d5, +0x000129d4, +0x000129d3, +0x000129d1, +0x000129d0, +0x000129ce, +0x000129cd, +0x000129cc, +0x000129ca, +0x000129c9, +0x000129c8, +0x000129c6, +0x000129c5, +0x000129c3, +0x000129c2, +0x000129c1, +0x000129c0, +0x000129be, +0x000129bc, +0x000129bb, +0x000129ba, +0x000129b9, +0x000129b8, +0x000129b6, +0x000129b4, +0x000129b3, +0x000129b2, +0x000129b1, +0x000129b0, +0x000129ad, +0x000129ac, +0x000129ab, +0x000129aa, +0x000129a9, +0x000129a8, +0x000129a5, +0x000129a4, +0x000129a3, +0x000129a2, +0x000129a1, +0x0001299f, +0x0001299d, +0x0001299c, +0x0001299b, +0x0001299a, +0x00012998, +0x00012997, +0x00012995, +0x00012994, +0x00012993, +0x00012991, +0x00012990, +0x0001298f, +0x0001298e, +0x0001298c, +0x0001298a, +0x00012989, +0x00012988, +0x00012987, +0x00012985, +0x00012984, +0x00012982, +0x00012981, +0x00012980, +0x0001297e, +0x0001297d, +0x0001297c, +0x0001297b, +0x00012979, +0x00012977, +0x00012976, +0x00012975, +0x00012974, +0x00012973, +0x00012971, +0x0001296f, +0x0001296e, +0x0001296d, +0x0001296c, +0x0001296b, +0x00012968, +0x00012967, +0x00012966, +0x00012965, +0x00012964, +0x00012963, +0x00012960, +0x0001295f, +0x0001295e, +0x0001295d, +0x0001295c, +0x0001295a, +0x00012959, +0x00012957, +0x00012956, +0x00012955, +0x00012954, +0x00012952, +0x00012951, +0x0001294f, +0x0001294e, +0x0001294d, +0x0001294b, +0x0001294a, +0x00012949, +0x00012947, +0x00012946, +0x00012944, +0x00012943, +0x00012942, +0x00012941, +0x0001293f, +0x0001293d, +0x0001293c, +0x0001293b, +0x0001293a, +0x00012939, +0x00012938, +0x00012935, +0x00012934, +0x00012933, +0x00012932, +0x00012931, +0x00012930, +0x0001292d, +0x0001292c, +0x0001292b, +0x0001292a, +0x00012929, +0x00012927, +0x00012925, +0x00012924, +0x00012923, +0x00012922, +0x00012920, +0x0001291f, +0x0001291d, +0x0001291c, +0x0001291b, +0x0001291a, +0x00012918, +0x00012917, +0x00012915, +0x00012914, +0x00012913, +0x00012911, +0x00012910, +0x0001290f, +0x0001290e, +0x0001290c, +0x0001290a, +0x00012909, +0x00012908, +0x00012907, +0x00012906, +0x00012903, +0x00012902, +0x00012901, +0x00012900, +0x000128ff, +0x000128fe, +0x000128fb, +0x000128fa, +0x000128f9, +0x000128f8, +0x000128f7, +0x000128f6, +0x000128f3, +0x000128f2, +0x000128f1, +0x000128f0, +0x000128ef, +0x000128ed, +0x000128ec, +0x000128ea, +0x000128e9, +0x000128e8, +0x000128e6, +0x000128e5, +0x000128e4, +0x000128e2, +0x000128e1, +0x000128e0, +0x000128de, +0x000128dd, +0x000128dc, +0x000128da, +0x000128d9, +0x000128d7, +0x000128d6, +0x000128d5, +0x000128d4, +0x000128d2, +0x000128d0, +0x000128cf, +0x000128ce, +0x000128cd, +0x000128cc, +0x000128cb, +0x000128c8, +0x000128c7, +0x000128c6, +0x000128c5, +0x000128c4, +0x000128c3, +0x000128c0, +0x000128bf, +0x000128be, +0x000128bd, +0x000128bc, +0x000128ba, +0x000128b8, +0x000128b7, +0x000128b6, +0x000128b5, +0x000128b3, +0x000128b2, +0x000128b0, +0x000128af, +0x000128ae, +0x000128ac, +0x000128ab, +0x000128aa, +0x000128a9, +0x000128a7, +0x000128a6, +0x000128a4, +0x000128a3, +0x000128a2, +0x000128a1, +0x0001289f, +0x0001289d, +0x0001289c, +0x0001289b, +0x0001289a, +0x00012899, +0x00012896, +0x00012895, +0x00012894, +0x00012893, +0x00012892, +0x00012891, +0x0001288e, +0x0001288d, +0x0001288c, +0x0001288b, +0x0001288a, +0x00012889, +0x00012887, +0x00012885, +0x00012884, +0x00012883, +0x00012882, +0x00012880, +0x0001287f, +0x0001287d, +0x0001287c, +0x0001287b, +0x00012879, +0x00012878, +0x00012877, +0x00012875, +0x00012874, +0x00012872, +0x00012871, +0x00012870, +0x0001286f, +0x0001286d, +0x0001286c, +0x0001286a, +0x00012869, +0x00012868, +0x00012867, +0x00012866, +0x00012863, +0x00012862, +0x00012861, +0x00012860, +0x0001285f, +0x0001285e, +0x0001285b, +0x0001285a, +0x00012859, +0x00012858, +0x00012857, +0x00012855, +0x00012853, +0x00012852, +0x00012851, +0x00012850, +0x0001284e, +0x0001284d, +0x0001284b, +0x0001284a, +0x00012849, +0x00012848, +0x00012846, +0x00012845, +0x00012844, +0x00012842, +0x00012841, +0x0001283f, +0x0001283e, +0x0001283d, +0x0001283c, +0x0001283a, +0x00012838, +0x00012837, +0x00012836, +0x00012835, +0x00012834, +0x00012833, +0x00012832, +0x0001282f, +0x0001282e, +0x0001282d, +0x0001282c, +0x0001282b, +0x0001282a, +0x00012827, +0x00012826, +0x00012825, +0x00012824, +0x00012823, +0x00012822, +0x00012820, +0x0001281e, +0x0001281d, +0x0001281c, +0x0001281b, +0x00012819, +0x00012818, +0x00012816, +0x00012815, +0x00012814, +0x00012813, +0x00012811, +0x00012810, +0x0001280e, +0x0001280d, +0x0001280c, +0x0001280a, +0x00012809, +0x00012808, +0x00012807, +0x00012805, +0x00012803, +0x00012802, +0x00012801, +0x00012800, +0x000127ff, +0x000127fd, +0x000127fb, +0x000127fa, +0x000127f9, +0x000127f8, +0x000127f7, +0x000127f6, +0x000127f3, +0x000127f2, +0x000127f1, +0x000127f0, +0x000127ef, +0x000127ee, +0x000127eb, +0x000127ea, +0x000127e9, +0x000127e8, +0x000127e7, +0x000127e5, +0x000127e3, +0x000127e2, +0x000127e1, +0x000127e0, +0x000127de, +0x000127dd, +0x000127dc, +0x000127da, +0x000127d9, +0x000127d8, +0x000127d6, +0x000127d5, +0x000127d4, +0x000127d2, +0x000127d1, +0x000127cf, +0x000127ce, +0x000127cd, +0x000127cc, +0x000127cb, +0x000127c9, +0x000127c7, +0x000127c6, +0x000127c5, +0x000127c4, +0x000127c3, +0x000127c0, +0x000127bf, +0x000127be, +0x000127bd, +0x000127bc, +0x000127bb, +0x000127b8, +0x000127b7, +0x000127b6, +0x000127b5, +0x000127b4, +0x000127b3, +0x000127b1, +0x000127af, +0x000127ae, +0x000127ad, +0x000127ac, +0x000127aa, +0x000127a9, +0x000127a7, +0x000127a6, +0x000127a5, +0x000127a4, +0x000127a2, +0x000127a1, +0x000127a0, +0x0001279e, +0x0001279d, +0x0001279b, +0x0001279a, +0x00012799, +0x00012798, +0x00012796, +0x00012794, +0x00012793, +0x00012792, +0x00012791, +0x00012790, +0x0001278e, +0x0001278c, +0x0001278b, +0x0001278a, +0x00012789, +0x00012787, +0x00012786, +0x00012785, +0x00012783, +0x00012782, +0x00012781, +0x00012780, +0x0001277e, +0x0001277c, +0x0001277b, +0x0001277a, +0x00012779, +0x00012778, +0x00012776, +0x00012774, +0x00012773, +0x00012772, +0x00012771, +0x00012770, +0x0001276f, +0x0001276c, +0x0001276b, +0x0001276a, +0x00012769, +0x00012768, +0x00012767, +0x00012764, +0x00012763, +0x00012762, +0x00012761, +0x00012760, +0x0001275e, +0x0001275d, +0x0001275b, +0x0001275a, +0x00012759, +0x00012758, +0x00012756, +0x00012755, +0x00012754, +0x00012752, +0x00012751, +0x00012750, +0x0001274e, +0x0001274d, +0x0001274c, +0x0001274a, +0x00012749, +0x00012747, +0x00012746, +0x00012745, +0x00012744, +0x00012743, +0x00012741, +0x0001273f, +0x0001273e, +0x0001273d, +0x0001273c, +0x0001273b, +0x00012738, +0x00012737, +0x00012736, +0x00012735, +0x00012734, +0x00012733, +0x00012732, +0x0001272f, +0x0001272e, +0x0001272d, +0x0001272c, +0x0001272b, +0x00012729, +0x00012727, +0x00012726, +0x00012725, +0x00012724, +0x00012723, +0x00012721, +0x00012720, +0x0001271e, +0x0001271d, +0x0001271c, +0x0001271b, +0x00012719, +0x00012718, +0x00012716, +0x00012715, +0x00012714, +0x00012712, +0x00012711, +0x00012710, +0x0001270f, +0x0001270d, +0x0001270c, +0x0001270a, +0x00012709, +0x00012708, +0x00012707, +0x00012706, +0x00012703, +0x00012702, +0x00012701, +0x00012700, +0x000126ff, +0x000126fe, +0x000126fb, +0x000126fa, +0x000126f9, +0x000126f8, +0x000126f7, +0x000126f6, +0x000126f4, +0x000126f2, +0x000126f1, +0x000126f0, +0x000126ef, +0x000126ee, +0x000126ec, +0x000126ea, +0x000126e9, +0x000126e8, +0x000126e7, +0x000126e5, +0x000126e4, +0x000126e3, +0x000126e1, +0x000126e0, +0x000126df, +0x000126dd, +0x000126dc, +0x000126db, +0x000126d9, +0x000126d8, +0x000126d7, +0x000126d5, +0x000126d4, +0x000126d3, +0x000126d2, +0x000126d0, +0x000126ce, +0x000126cd, +0x000126cc, +0x000126cb, +0x000126ca, +0x000126c9, +0x000126c6, +0x000126c5, +0x000126c4, +0x000126c3, +0x000126c2, +0x000126c1, +0x000126be, +0x000126bd, +0x000126bc, +0x000126bb, +0x000126ba, +0x000126b9, +0x000126b7, +0x000126b5, +0x000126b4, +0x000126b3, +0x000126b2, +0x000126b0, +0x000126af, +0x000126ad, +0x000126ac, +0x000126ab, +0x000126aa, +0x000126a8, +0x000126a7, +0x000126a6, +0x000126a4, +0x000126a3, +0x000126a2, +0x000126a0, +0x0001269f, +0x0001269e, +0x0001269c, +0x0001269b, +0x00012699, +0x00012698, +0x00012697, +0x00012696, +0x00012695, +0x00012693, +0x00012691, +0x00012690, +0x0001268f, +0x0001268e, +0x0001268d, +0x0001268c, +0x00012689, +0x00012688, +0x00012687, +0x00012686, +0x00012685, +0x00012684, +0x00012681, +0x00012680, +0x0001267f, +0x0001267e, +0x0001267d, +0x0001267b, +0x0001267a, +0x00012678, +0x00012677, +0x00012676, +0x00012675, +0x00012673, +0x00012672, +0x00012670, +0x0001266f, +0x0001266e, +0x0001266d, +0x0001266b, +0x0001266a, +0x00012669, +0x00012667, +0x00012666, +0x00012664, +0x00012663, +0x00012662, +0x00012661, +0x0001265f, +0x0001265e, +0x0001265c, +0x0001265b, +0x0001265a, +0x00012659, +0x00012658, +0x00012655, +0x00012654, +0x00012653, +0x00012652, +0x00012651, +0x00012650, +0x0001264d, +0x0001264c, +0x0001264b, +0x0001264a, +0x00012649, +0x00012648, +0x00012646, +0x00012644, +0x00012643, +0x00012642, +0x00012641, +0x00012640, +0x0001263e, +0x0001263d, +0x0001263b, +0x0001263a, +0x00012639, +0x00012637, +0x00012637, +0x00012635, +0x00012634, +0x00012633, +0x00012631, +0x00012630, +0x0001262f, +0x0001262d, +0x0001262c, +0x0001262a, +0x00012629, +0x00012628, +0x00012627, +0x00012626, +0x00012624, +0x00012622, +0x00012621, +0x00012620, +0x0001261f, +0x0001261e, +0x0001261d, +0x0001261a, +0x00012619, +0x00012618, +0x00012617, +0x00012616, +0x00012615, +0x00012612, +0x00012611, +0x00012610, +0x0001260f, +0x0001260e, +0x0001260d, +0x0001260b, +0x00012609, +0x00012608, +0x00012607, +0x00012606, +0x00012605, +0x00012603, +0x00012602, +0x00012600, +0x000125ff, +0x000125fe, +0x000125fd, +0x000125fb, +0x000125fa, +0x000125f9, +0x000125f7, +0x000125f6, +0x000125f5, +0x000125f3, +0x000125f2, +0x000125f1, +0x000125ef, +0x000125ee, +0x000125ec, +0x000125eb, +0x000125ea, +0x000125e9, +0x000125e8, +0x000125e6, +0x000125e4, +0x000125e3, +0x000125e2, +0x000125e1, +0x000125e0, +0x000125df, +0x000125dc, +0x000125db, +0x000125da, +0x000125d9, +0x000125d8, +0x000125d7, +0x000125d6, +0x000125d3, +0x000125d2, +0x000125d1, +0x000125d0, +0x000125cf, +0x000125cd, +0x000125cb, +0x000125ca, +0x000125c9, +0x000125c8, +0x000125c7, +0x000125c5, +0x000125c4, +0x000125c2, +0x000125c1, +0x000125c0, +0x000125bf, +0x000125bd, +0x000125bc, +0x000125bb, +0x000125b9, +0x000125b8, +0x000125b7, +0x000125b5, +0x000125b4, +0x000125b3, +0x000125b2, +0x000125b0, +0x000125ae, +0x000125ad, +0x000125ac, +0x000125ab, +0x000125aa, +0x000125a8, +0x000125a6, +0x000125a5, +0x000125a4, +0x000125a3, +0x000125a2, +0x000125a1, +0x0001259e, +0x0001259d, +0x0001259c, +0x0001259b, +0x0001259a, +0x00012599, +0x00012597, +0x00012595, +0x00012594, +0x00012593, +0x00012592, +0x00012591, +0x0001258f, +0x0001258e, +0x0001258d, +0x0001258a, +0x00012589, +0x00012588, +0x00012587, +0x00012586, +0x00012585, +0x00012584, +0x00012581, +0x00012580, +0x0001257f, +0x0001257e, +0x0001257d, +0x0001257c, +0x0001257a, +0x00012578, +0x00012577, +0x00012576, +0x00012575, +0x00012574, +0x00012572, +0x00012571, +0x0001256f, +0x0001256e, +0x0001256d, +0x0001256c, +0x0001256a, +0x00012569, +0x00012568, +0x00012566, +0x00012565, +0x00012564, +0x00012562, +0x00012561, +0x00012560, +0x0001255f, +0x0001255d, +0x0001255c, +0x0001255a, +0x00012559, +0x00012558, +0x00012557, +0x00012556, +0x00012554, +0x00012552, +0x00012551, +0x00012550, +0x0001254f, +0x0001254e, +0x0001254d, +0x0001254a, +0x00012549, +0x00012548, +0x00012547, +0x00012546, +0x00012545, +0x00012544, +0x00012541, +0x00012540, +0x0001253f, +0x0001253e, +0x0001253d, +0x0001253c, +0x0001253a, +0x00012538, +0x00012537, +0x00012536, +0x00012535, +0x00012534, +0x00012532, +0x00012530, +0x0001252f, +0x0001252e, +0x0001252d, +0x0001252b, +0x0001252a, +0x00012529, +0x00012527, +0x00012526, +0x00012525, +0x00012523, +0x00012522, +0x00012521, +0x00012520, +0x0001251e, +0x0001251d, +0x0001251b, +0x0001251a, +0x00012519, +0x00012518, +0x00012517, +0x00012515, +0x00012513, +0x00012512, +0x00012511, +0x00012510, +0x0001250f, +0x0001250e, +0x0001250b, +0x0001250a, +0x00012509, +0x00012508, +0x00012507, +0x00012506, +0x00012505, +0x00012502, +0x00012501, +0x00012500, +0x000124ff, +0x000124fe, +0x000124fd, +0x000124fb, +0x000124f9, +0x000124f8, +0x000124f7, +0x000124f6, +0x000124f5, +0x000124f3, +0x000124f2, +0x000124f0, +0x000124ef, +0x000124ee, +0x000124ed, +0x000124eb, +0x000124ea, +0x000124e9, +0x000124e7, +0x000124e6, +0x000124e5, +0x000124e3, +0x000124e2, +0x000124e1, +0x000124e0, +0x000124de, +0x000124dd, +0x000124db, +0x000124da, +0x000124d9, +0x000124d8, +0x000124d7, +0x000124d5, +0x000124d3, +0x000124d2, +0x000124d1, +0x000124d0, +0x000124cf, +0x000124ce, +0x000124cb, +0x000124ca, +0x000124c9, +0x000124c8, +0x000124c7, +0x000124c6, +0x000124c3, +0x000124c2, +0x000124c1, +0x000124c0, +0x000124bf, +0x000124be, +0x000124bc, +0x000124ba, +0x000124b9, +0x000124b8, +0x000124b7, +0x000124b6, +0x000124b4, +0x000124b3, +0x000124b1, +0x000124b0, +0x000124af, +0x000124ae, +0x000124ac, +0x000124ab, +0x000124aa, +0x000124a8, +0x000124a7, +0x000124a6, +0x000124a4, +0x000124a3, +0x000124a2, +0x000124a1, +0x0001249f, +0x0001249e, +0x0001249c, +0x0001249b, +0x0001249a, +0x00012499, +0x00012498, +0x00012496, +0x00012494, +0x00012493, +0x00012492, +0x00012491, +0x00012490, +0x0001248f, +0x0001248c, +0x0001248b, +0x0001248a, +0x00012489, +0x00012488, +0x00012487, +0x00012486, +0x00012483, +0x00012482, +0x00012481, +0x00012480, +0x0001247f, +0x0001247e, +0x0001247c, +0x0001247a, +0x00012479, +0x00012478, +0x00012477, +0x00012476, +0x00012474, +0x00012473, +0x00012471, +0x00012470, +0x0001246f, +0x0001246e, +0x0001246c, +0x0001246b, +0x0001246a, +0x00012468, +0x00012467, +0x00012465, +0x00012464, +0x00012463, +0x00012462, +0x00012461, +0x0001245f, +0x0001245d, +0x0001245c, +0x0001245b, +0x0001245a, +0x00012459, +0x00012457, +0x00012455, +0x00012454, +0x00012453, +0x00012452, +0x00012451, +0x00012450, +0x0001244d, +0x0001244c, +0x0001244b, +0x0001244a, +0x00012449, +0x00012448, +0x00012447, +0x00012444, +0x00012443, +0x00012442, +0x00012441, +0x00012440, +0x0001243f, +0x0001243e, +0x0001243c, +0x0001243b, +0x00012439, +0x00012438, +0x00012437, +0x00012436, +0x00012434, +0x00012433, +0x00012432, +0x00012430, +0x0001242f, +0x0001242e, +0x0001242c, +0x0001242b, +0x0001242a, +0x00012429, +0x00012427, +0x00012426, +0x00012425, +0x00012423, +0x00012422, +0x00012421, +0x00012420, +0x0001241e, +0x0001241d, +0x0001241b, +0x0001241a, +0x00012419, +0x00012418, +0x00012417, +0x00012416, +0x00012413, +0x00012412, +0x00012411, +0x00012410, +0x0001240f, +0x0001240e, +0x0001240d, +0x0001240a, +0x00012409, +0x00012408, +0x00012407, +0x00012406, +0x00012405, +0x00012403, +0x00012401, +0x00012400, +0x000123ff, +0x000123fe, +0x000123fd, +0x000123fb, +0x000123fa, +0x000123f8, +0x000123f7, +0x000123f6, +0x000123f5, +0x000123f3, +0x000123f2, +0x000123f1, +0x000123ef, +0x000123ee, +0x000123ed, +0x000123eb, +0x000123ea, +0x000123e9, +0x000123e8, +0x000123e6, +0x000123e5, +0x000123e3, +0x000123e2, +0x000123e1, +0x000123e0, +0x000123df, +0x000123dd, +0x000123dc, +0x000123da, +0x000123d9, +0x000123d8, +0x000123d7, +0x000123d6, +0x000123d4, +0x000123d2, +0x000123d1, +0x000123d0, +0x000123cf, +0x000123ce, +0x000123cd, +0x000123ca, +0x000123c9, +0x000123c8, +0x000123c7, +0x000123c6, +0x000123c5, +0x000123c4, +0x000123c2, +0x000123c0, +0x000123bf, +0x000123be, +0x000123bd, +0x000123bc, +0x000123ba, +0x000123b9, +0x000123b7, +0x000123b6, +0x000123b5, +0x000123b4, +0x000123b2, +0x000123b1, +0x000123b0, +0x000123ae, +0x000123ad, +0x000123ac, +0x000123aa, +0x000123a9, +0x000123a8, +0x000123a7, +0x000123a5, +0x000123a4, +0x000123a2, +0x000123a1, +0x000123a0, +0x0001239f, +0x0001239e, +0x0001239c, +0x0001239a, +0x00012399, +0x00012398, +0x00012397, +0x00012395, +0x00012394, +0x00012393, +0x00012392, +0x00012390, +0x0001238f, +0x0001238e, +0x0001238d, +0x0001238b, +0x0001238a, +0x00012388, +0x00012387, +0x00012386, +0x00012385, +0x00012384, +0x00012382, +0x00012380, +0x0001237f, +0x0001237e, +0x0001237d, +0x0001237c, +0x0001237b, +0x00012378, +0x00012377, +0x00012376, +0x00012375, +0x00012374, +0x00012373, +0x00012372, +0x00012371, +0x0001236e, +0x0001236d, +0x0001236c, +0x0001236b, +0x0001236a, +0x00012369, +0x00012367, +0x00012365, +0x00012364, +0x00012363, +0x00012362, +0x00012361, +0x0001235f, +0x0001235e, +0x0001235c, +0x0001235b, +0x0001235a, +0x00012359, +0x00012358, +0x00012356, +0x00012355, +0x00012354, +0x00012352, +0x00012351, +0x00012350, +0x0001234e, +0x0001234d, +0x0001234c, +0x0001234b, +0x00012349, +0x00012348, +0x00012346, +0x00012345, +0x00012344, +0x00012343, +0x00012342, +0x00012340, +0x0001233f, +0x0001233d, +0x0001233c, +0x0001233b, +0x0001233a, +0x00012339, +0x00012337, +0x00012335, +0x00012334, +0x00012333, +0x00012332, +0x00012331, +0x00012330, +0x0001232f, +0x0001232c, +0x0001232b, +0x0001232a, +0x00012329, +0x00012328, +0x00012327, +0x00012326, +0x00012323, +0x00012322, +0x00012321, +0x00012320, +0x0001231f, +0x0001231e, +0x0001231c, +0x0001231a, +0x00012319, +0x00012318, +0x00012317, +0x00012316, +0x00012314, +0x00012313, +0x00012312, +0x00012310, +0x0001230f, +0x0001230e, +0x0001230d, +0x0001230b, +0x0001230a, +0x00012309, +0x00012307, +0x00012306, +0x00012305, +0x00012303, +0x00012302, +0x00012301, +0x00012300, +0x000122fe, +0x000122fd, +0x000122fb, +0x000122fa, +0x000122f9, +0x000122f8, +0x000122f7, +0x000122f6, +0x000122f3, +0x000122f2, +0x000122f1, +0x000122f0, +0x000122ef, +0x000122ee, +0x000122ed, +0x000122ea, +0x000122e9, +0x000122e8, +0x000122e7, +0x000122e6, +0x000122e5, +0x000122e4, +0x000122e1, +0x000122e0, +0x000122df, +0x000122de, +0x000122dd, +0x000122dc, +0x000122da, +0x000122d9, +0x000122d7, +0x000122d6, +0x000122d5, +0x000122d4, +0x000122d3, +0x000122d1, +0x000122d0, +0x000122ce, +0x000122cd, +0x000122cc, +0x000122cb, +0x000122c9, +0x000122c8, +0x000122c7, +0x000122c5, +0x000122c4, +0x000122c3, +0x000122c1, +0x000122c0, +0x000122bf, +0x000122be, +0x000122bd, +0x000122bb, +0x000122ba, +0x000122b8, +0x000122b7, +0x000122b6, +0x000122b5, +0x000122b4, +0x000122b2, +0x000122b0, +0x000122af, +0x000122ae, +0x000122ad, +0x000122ac, +0x000122ab, +0x000122a8, +0x000122a7, +0x000122a6, +0x000122a5, +0x000122a4, +0x000122a3, +0x000122a2, +0x000122a1, +0x0001229e, +0x0001229d, +0x0001229c, +0x0001229b, +0x0001229a, +0x00012299, +0x00012297, +0x00012295, +0x00012294, +0x00012293, +0x00012292, +0x00012291, +0x0001228f, +0x0001228e, +0x0001228c, +0x0001228b, +0x0001228a, +0x00012289, +0x00012288, +0x00012286, +0x00012285, +0x00012283, +0x00012282, +0x00012281, +0x00012280, +0x0001227e, +0x0001227d, +0x0001227c, +0x0001227b, +0x00012279, +0x00012278, +0x00012276, +0x00012275, +0x00012274, +0x00012273, +0x00012272, +0x00012270, +0x0001226f, +0x0001226d, +0x0001226c, +0x0001226b, +0x0001226a, +0x00012269, +0x00012267, +0x00012265, +0x00012264, +0x00012263, +0x00012262, +0x00012261, +0x00012260, +0x0001225f, +0x0001225c, +0x0001225b, +0x0001225a, +0x00012259, +0x00012258, +0x00012257, +0x00012255, +0x00012253, +0x00012252, +0x00012251, +0x00012250, +0x0001224f, +0x0001224e, +0x0001224c, +0x0001224b, +0x0001224a, +0x00012249, +0x00012247, +0x00012246, +0x00012245, +0x00012243, +0x00012242, +0x00012241, +0x0001223f, +0x0001223e, +0x0001223d, +0x0001223c, +0x0001223b, +0x00012239, +0x00012238, +0x00012236, +0x00012235, +0x00012234, +0x00012233, +0x00012232, +0x00012230, +0x0001222e, +0x0001222d, +0x0001222c, +0x0001222b, +0x0001222a, +0x00012229, +0x00012228, +0x00012225, +0x00012224, +0x00012223, +0x00012222, +0x00012221, +0x00012220, +0x0001221f, +0x0001221c, +0x0001221b, +0x0001221a, +0x00012219, +0x00012218, +0x00012217, +0x00012216, +0x00012214, +0x00012212, +0x00012211, +0x00012210, +0x0001220f, +0x0001220e, +0x0001220c, +0x0001220b, +0x00012209, +0x00012208, +0x00012207, +0x00012206, +0x00012205, +0x00012203, +0x00012202, +0x00012201, +0x000121ff, +0x000121fe, +0x000121fd, +0x000121fb, +0x000121fa, +0x000121f9, +0x000121f8, +0x000121f6, +0x000121f5, +0x000121f4, +0x000121f2, +0x000121f1, +0x000121f0, +0x000121ef, +0x000121ee, +0x000121ec, +0x000121ea, +0x000121e9, +0x000121e8, +0x000121e7, +0x000121e6, +0x000121e5, +0x000121e3, +0x000121e1, +0x000121e0, +0x000121df, +0x000121de, +0x000121dd, +0x000121dc, +0x000121db, +0x000121d8, +0x000121d7, +0x000121d6, +0x000121d5, +0x000121d4, +0x000121d3, +0x000121d2, +0x000121cf, +0x000121ce, +0x000121cd, +0x000121cc, +0x000121cb, +0x000121ca, +0x000121c8, +0x000121c7, +0x000121c5, +0x000121c4, +0x000121c3, +0x000121c2, +0x000121c1, +0x000121bf, +0x000121be, +0x000121bc, +0x000121bb, +0x000121ba, +0x000121b9, +0x000121b8, +0x000121b6, +0x000121b5, +0x000121b4, +0x000121b2, +0x000121b1, +0x000121b0, +0x000121ae, +0x000121ad, +0x000121ac, +0x000121ab, +0x000121a9, +0x000121a8, +0x000121a6, +0x000121a5, +0x000121a4, +0x000121a3, +0x000121a1, +0x000121a0, +0x0001219f, +0x0001219e, +0x0001219c, +0x0001219b, +0x0001219a, +0x00012198, +0x00012197, +0x00012196, +0x00012195, +0x00012194, +0x00012192, +0x00012191, +0x0001218f, +0x0001218e, +0x0001218d, +0x0001218c, +0x0001218b, +0x0001218a, +0x00012187, +0x00012186, +0x00012185, +0x00012184, +0x00012183, +0x00012182, +0x00012181, +0x0001217e, +0x0001217d, +0x0001217c, +0x0001217b, +0x0001217a, +0x00012179, +0x00012178, +0x00012177, +0x00012174, +0x00012173, +0x00012172, +0x00012171, +0x00012170, +0x0001216f, +0x0001216e, +0x0001216c, +0x0001216a, +0x00012169, +0x00012168, +0x00012167, +0x00012166, +0x00012164, +0x00012163, +0x00012162, +0x00012160, +0x0001215f, +0x0001215e, +0x0001215d, +0x0001215b, +0x0001215a, +0x00012159, +0x00012158, +0x00012156, +0x00012155, +0x00012154, +0x00012152, +0x00012151, +0x00012150, +0x0001214f, +0x0001214d, +0x0001214c, +0x0001214b, +0x00012149, +0x00012148, +0x00012147, +0x00012146, +0x00012145, +0x00012143, +0x00012141, +0x00012140, +0x0001213f, +0x0001213e, +0x0001213d, +0x0001213c, +0x0001213b, +0x00012138, +0x00012137, +0x00012136, +0x00012135, +0x00012134, +0x00012133, +0x00012132, +0x00012131, +0x0001212e, +0x0001212d, +0x0001212c, +0x0001212b, +0x0001212a, +0x00012129, +0x00012128, +0x00012125, +0x00012124, +0x00012123, +0x00012122, +0x00012121, +0x00012120, +0x0001211e, +0x0001211d, +0x0001211b, +0x0001211a, +0x00012119, +0x00012118, +0x00012117, +0x00012115, +0x00012114, +0x00012113, +0x00012111, +0x00012110, +0x0001210f, +0x0001210e, +0x0001210c, +0x0001210b, +0x0001210a, +0x00012109, +0x00012107, +0x00012106, +0x00012105, +0x00012103, +0x00012102, +0x00012101, +0x00012100, +0x000120fe, +0x000120fd, +0x000120fb, +0x000120fa, +0x000120f9, +0x000120f8, +0x000120f7, +0x000120f6, +0x000120f4, +0x000120f2, +0x000120f1, +0x000120f0, +0x000120ef, +0x000120ee, +0x000120ed, +0x000120ec, +0x000120e9, +0x000120e8, +0x000120e7, +0x000120e6, +0x000120e5, +0x000120e4, +0x000120e3, +0x000120e2, +0x000120df, +0x000120de, +0x000120dd, +0x000120dc, +0x000120db, +0x000120da, +0x000120d8, +0x000120d6, +0x000120d5, +0x000120d4, +0x000120d3, +0x000120d2, +0x000120d1, +0x000120cf, +0x000120ce, +0x000120cc, +0x000120cb, +0x000120ca, +0x000120c9, +0x000120c8, +0x000120c6, +0x000120c5, +0x000120c4, +0x000120c2, +0x000120c1, +0x000120c0, +0x000120bf, +0x000120bd, +0x000120bc, +0x000120bb, +0x000120ba, +0x000120b8, +0x000120b7, +0x000120b5, +0x000120b4, +0x000120b3, +0x000120b2, +0x000120b1, +0x000120af, +0x000120ae, +0x000120ac, +0x000120ab, +0x000120aa, +0x000120a9, +0x000120a8, +0x000120a7, +0x000120a5, +0x000120a3, +0x000120a2, +0x000120a1, +0x000120a0, +0x0001209f, +0x0001209e, +0x0001209d, +0x0001209a, +0x00012099, +0x00012098, +0x00012097, +0x00012096, +0x00012095, +0x00012094, +0x00012092, +0x00012090, +0x0001208f, +0x0001208e, +0x0001208d, +0x0001208c, +0x0001208b, +0x00012089, +0x00012087, +0x00012086, +0x00012085, +0x00012084, +0x00012083, +0x00012082, +0x00012080, +0x0001207f, +0x0001207d, +0x0001207c, +0x0001207b, +0x0001207a, +0x00012079, +0x00012077, +0x00012076, +0x00012075, +0x00012073, +0x00012072, +0x00012071, +0x00012070, +0x0001206e, +0x0001206d, +0x0001206c, +0x0001206b, +0x00012069, +0x00012068, +0x00012066, +0x00012065, +0x00012064, +0x00012063, +0x00012062, +0x00012061, +0x00012060, +0x0001205f, +0x0001205c, +0x0001205b, +0x0001205a, +0x00012059, +0x00012058, +0x00012057, +0x00012056, +0x00012054, +0x00012052, +0x00012051, +0x00012050, +0x0001204f, +0x0001204e, +0x0001204d, +0x0001204b, +0x0001204a, +0x00012048, +0x00012047, +0x00012046, +0x00012045, +0x00012044, +0x00012042, +0x00012041, +0x00012040, +0x0001203e, +0x0001203d, +0x0001203c, +0x0001203b, +0x00012039, +0x00012038, +0x00012037, +0x00012036, +0x00012034, +0x00012033, +0x00012032, +0x00012030, +0x0001202f, +0x0001202e, +0x0001202d, +0x0001202c, +0x0001202a, +0x00012029, +0x00012027, +0x00012026, +0x00012025, +0x00012024, +0x00012023, +0x00012022, +0x00012020, +0x0001201e, +0x0001201d, +0x0001201c, +0x0001201b, +0x0001201a, +0x00012019, +0x00012018, +0x00012015, +0x00012014, +0x00012013, +0x00012012, +0x00012011, +0x00012010, +0x0001200f, +0x0001200e, +0x0001200b, +0x0001200a, +0x00012009, +0x00012008, +0x00012007, +0x00012006, +0x00012005, +0x00012003, +0x00012001, +0x00012000, +0x00011fff, +0x00011ffe, +0x00011ffd, +0x00011ffc, +0x00011ffa, +0x00011ff9, +0x00011ff7, +0x00011ff6, +0x00011ff5, +0x00011ff4, +0x00011ff3, +0x00011ff1, +0x00011ff0, +0x00011fef, +0x00011fed, +0x00011fec, +0x00011feb, +0x00011fea, +0x00011fe8, +0x00011fe7, +0x00011fe6, +0x00011fe5, +0x00011fe3, +0x00011fe2, +0x00011fe1, +0x00011fdf, +0x00011fde, +0x00011fdd, +0x00011fdc, +0x00011fdb, +0x00011fd9, +0x00011fd8, +0x00011fd6, +0x00011fd5, +0x00011fd4, +0x00011fd3, +0x00011fd2, +0x00011fd1, +0x00011fcf, +0x00011fcd, +0x00011fcc, +0x00011fcb, +0x00011fca, +0x00011fc9, +0x00011fc8, +0x00011fc7, +0x00011fc4, +0x00011fc3, +0x00011fc2, +0x00011fc1, +0x00011fc0, +0x00011fbf, +0x00011fbc, +0x00011fbb, +0x00011fba, +0x00011fb9, +0x00011fb8, +0x00011fb7, +0x00011fb6, +0x00011fb4, +0x00011fb2, +0x00011fb1, +0x00011fb0, +0x00011faf, +0x00011fae, +0x00011fad, +0x00011fac, +0x00011faa, +0x00011fa8, +0x00011fa7, +0x00011fa6, +0x00011fa5, +0x00011fa4, +0x00011fa3, +0x00011fa1, +0x00011fa0, +0x00011f9e, +0x00011f9d, +0x00011f9c, +0x00011f9b, +0x00011f9a, +0x00011f98, +0x00011f97, +0x00011f96, +0x00011f95, +0x00011f93, +0x00011f92, +0x00011f91, +0x00011f90, +0x00011f8e, +0x00011f8d, +0x00011f8c, +0x00011f8b, +0x00011f89, +0x00011f88, +0x00011f87, +0x00011f85, +0x00011f84, +0x00011f83, +0x00011f82, +0x00011f81, +0x00011f7f, +0x00011f7e, +0x00011f7c, +0x00011f7b, +0x00011f7a, +0x00011f79, +0x00011f78, +0x00011f77, +0x00011f75, +0x00011f73, +0x00011f72, +0x00011f71, +0x00011f70, +0x00011f6f, +0x00011f6e, +0x00011f6d, +0x00011f6c, +0x00011f69, +0x00011f68, +0x00011f67, +0x00011f66, +0x00011f65, +0x00011f64, +0x00011f63, +0x00011f62, +0x00011f5f, +0x00011f5e, +0x00011f5d, +0x00011f5c, +0x00011f5b, +0x00011f5a, +0x00011f59, +0x00011f57, +0x00011f55, +0x00011f54, +0x00011f53, +0x00011f52, +0x00011f51, +0x00011f50, +0x00011f4e, +0x00011f4d, +0x00011f4b, +0x00011f4a, +0x00011f49, +0x00011f48, +0x00011f47, +0x00011f46, +0x00011f44, +0x00011f43, +0x00011f42, +0x00011f40, +0x00011f3f, +0x00011f3e, +0x00011f3d, +0x00011f3b, +0x00011f3a, +0x00011f39, +0x00011f38, +0x00011f36, +0x00011f35, +0x00011f34, +0x00011f32, +0x00011f31, +0x00011f30, +0x00011f2f, +0x00011f2e, +0x00011f2c, +0x00011f2b, +0x00011f29, +0x00011f28, +0x00011f27, +0x00011f26, +0x00011f25, +0x00011f24, +0x00011f22, +0x00011f21, +0x00011f1f, +0x00011f1e, +0x00011f1d, +0x00011f1c, +0x00011f1b, +0x00011f1a, +0x00011f19, +0x00011f16, +0x00011f15, +0x00011f14, +0x00011f13, +0x00011f12, +0x00011f11, +0x00011f10, +0x00011f0f, +0x00011f0c, +0x00011f0b, +0x00011f0a, +0x00011f09, +0x00011f08, +0x00011f07, +0x00011f06, +0x00011f04, +0x00011f02, +0x00011f01, +0x00011f00, +0x00011eff, +0x00011efe, +0x00011efd, +0x00011efc, +0x00011efa, +0x00011ef8, +0x00011ef7, +0x00011ef6, +0x00011ef5, +0x00011ef4, +0x00011ef3, +0x00011ef1, +0x00011ef0, +0x00011eef, +0x00011eed, +0x00011eec, +0x00011eeb, +0x00011eea, +0x00011ee8, +0x00011ee7, +0x00011ee6, +0x00011ee5, +0x00011ee3, +0x00011ee2, +0x00011ee1, +0x00011edf, +0x00011ede, +0x00011edd, +0x00011edc, +0x00011edb, +0x00011ed9, +0x00011ed8, +0x00011ed7, +0x00011ed5, +0x00011ed4, +0x00011ed3, +0x00011ed2, +0x00011ed1, +0x00011ed0, +0x00011ece, +0x00011ecc, +0x00011ecb, +0x00011eca, +0x00011ec9, +0x00011ec8, +0x00011ec7, +0x00011ec6, +0x00011ec3, +0x00011ec2, +0x00011ec1, +0x00011ec0, +0x00011ebf, +0x00011ebe, +0x00011ebd, +0x00011ebc, +0x00011eb9, +0x00011eb8, +0x00011eb7, +0x00011eb6, +0x00011eb5, +0x00011eb4, +0x00011eb3, +0x00011eb2, +0x00011eaf, +0x00011eae, +0x00011ead, +0x00011eac, +0x00011eab, +0x00011eaa, +0x00011ea9, +0x00011ea7, +0x00011ea6, +0x00011ea4, +0x00011ea3, +0x00011ea2, +0x00011ea1, +0x00011ea0, +0x00011e9e, +0x00011e9d, +0x00011e9c, +0x00011e9a, +0x00011e99, +0x00011e98, +0x00011e97, +0x00011e95, +0x00011e94, +0x00011e93, +0x00011e92, +0x00011e90, +0x00011e8f, +0x00011e8e, +0x00011e8d, +0x00011e8b, +0x00011e8a, +0x00011e89, +0x00011e88, +0x00011e86, +0x00011e85, +0x00011e84, +0x00011e82, +0x00011e81, +0x00011e80, +0x00011e7f, +0x00011e7d, +0x00011e7c, +0x00011e7b, +0x00011e7a, +0x00011e79, +0x00011e78, +0x00011e76, +0x00011e75, +0x00011e73, +0x00011e72, +0x00011e71, +0x00011e70, +0x00011e6f, +0x00011e6d, +0x00011e6c, +0x00011e6b, +0x00011e6a, +0x00011e68, +0x00011e67, +0x00011e66, +0x00011e65, +0x00011e63, +0x00011e62, +0x00011e61, +0x00011e60, +0x00011e5e, +0x00011e5d, +0x00011e5c, +0x00011e5a, +0x00011e59, +0x00011e58, +0x00011e57, +0x00011e56, +0x00011e55, +0x00011e53, +0x00011e52, +0x00011e50, +0x00011e4f, +0x00011e4e, +0x00011e4d, +0x00011e4c, +0x00011e4b, +0x00011e49, +0x00011e48, +0x00011e46, +0x00011e45, +0x00011e44, +0x00011e43, +0x00011e42, +0x00011e41, +0x00011e40, +0x00011e3d, +0x00011e3c, +0x00011e3b, +0x00011e3a, +0x00011e39, +0x00011e38, +0x00011e37, +0x00011e36, +0x00011e33, +0x00011e32, +0x00011e31, +0x00011e30, +0x00011e2f, +0x00011e2e, +0x00011e2d, +0x00011e2c, +0x00011e2a, +0x00011e28, +0x00011e27, +0x00011e26, +0x00011e25, +0x00011e24, +0x00011e23, +0x00011e22, +0x00011e20, +0x00011e1e, +0x00011e1d, +0x00011e1c, +0x00011e1b, +0x00011e1a, +0x00011e19, +0x00011e17, +0x00011e16, +0x00011e15, +0x00011e13, +0x00011e12, +0x00011e11, +0x00011e10, +0x00011e0f, +0x00011e0d, +0x00011e0c, +0x00011e0b, +0x00011e09, +0x00011e08, +0x00011e07, +0x00011e06, +0x00011e04, +0x00011e03, +0x00011e02, +0x00011e01, +0x00011e00, +0x00011dfe, +0x00011dfd, +0x00011dfc, +0x00011dfa, +0x00011df9, +0x00011df8, +0x00011df7, +0x00011df6, +0x00011df4, +0x00011df3, +0x00011df1, +0x00011df0, +0x00011def, +0x00011dee, +0x00011ded, +0x00011dec, +0x00011deb, +0x00011de9, +0x00011de7, +0x00011de6, +0x00011de5, +0x00011de4, +0x00011de3, +0x00011de2, +0x00011de1, +0x00011de0, +0x00011ddd, +0x00011ddc, +0x00011ddb, +0x00011dda, +0x00011dd9, +0x00011dd8, +0x00011dd7, +0x00011dd6, +0x00011dd3, +0x00011dd2, +0x00011dd1, +0x00011dd0, +0x00011dcf, +0x00011dce, +0x00011dcd, +0x00011dcb, +0x00011dca, +0x00011dc8, +0x00011dc7, +0x00011dc6, +0x00011dc5, +0x00011dc4, +0x00011dc3, +0x00011dc1, +0x00011dc0, +0x00011dbe, +0x00011dbd, +0x00011dbc, +0x00011dbb, +0x00011dba, +0x00011db9, +0x00011db7, +0x00011db6, +0x00011db5, +0x00011db3, +0x00011db2, +0x00011db1, +0x00011db0, +0x00011dae, +0x00011dad, +0x00011dac, +0x00011dab, +0x00011da9, +0x00011da8, +0x00011da7, +0x00011da6, +0x00011da4, +0x00011da3, +0x00011da2, +0x00011da1, +0x00011da0, +0x00011d9e, +0x00011d9d, +0x00011d9b, +0x00011d9a, +0x00011d99, +0x00011d98, +0x00011d97, +0x00011d96, +0x00011d94, +0x00011d93, +0x00011d91, +0x00011d90, +0x00011d8f, +0x00011d8e, +0x00011d8d, +0x00011d8c, +0x00011d8b, +0x00011d88, +0x00011d87, +0x00011d86, +0x00011d85, +0x00011d84, +0x00011d83, +0x00011d82, +0x00011d81, +0x00011d7e, +0x00011d7d, +0x00011d7c, +0x00011d7b, +0x00011d7a, +0x00011d79, +0x00011d78, +0x00011d77, +0x00011d75, +0x00011d73, +0x00011d72, +0x00011d71, +0x00011d70, +0x00011d6f, +0x00011d6e, +0x00011d6d, +0x00011d6b, +0x00011d69, +0x00011d68, +0x00011d67, +0x00011d66, +0x00011d65, +0x00011d64, +0x00011d62, +0x00011d61, +0x00011d60, +0x00011d5e, +0x00011d5d, +0x00011d5c, +0x00011d5b, +0x00011d5a, +0x00011d58, +0x00011d57, +0x00011d56, +0x00011d54, +0x00011d53, +0x00011d52, +0x00011d51, +0x00011d4f, +0x00011d4e, +0x00011d4d, +0x00011d4c, +0x00011d4b, +0x00011d49, +0x00011d48, +0x00011d47, +0x00011d45, +0x00011d44, +0x00011d43, +0x00011d42, +0x00011d41, +0x00011d3f, +0x00011d3e, +0x00011d3d, +0x00011d3c, +0x00011d3b, +0x00011d3a, +0x00011d39, +0x00011d37, +0x00011d35, +0x00011d34, +0x00011d33, +0x00011d32, +0x00011d31, +0x00011d30, +0x00011d2f, +0x00011d2e, +0x00011d2b, +0x00011d2a, +0x00011d29, +0x00011d28, +0x00011d27, +0x00011d26, +0x00011d25, +0x00011d24, +0x00011d23, +0x00011d20, +0x00011d1f, +0x00011d1e, +0x00011d1d, +0x00011d1c, +0x00011d1b, +0x00011d1a, +0x00011d18, +0x00011d17, +0x00011d15, +0x00011d14, +0x00011d13, +0x00011d12, +0x00011d11, +0x00011d10, +0x00011d0e, +0x00011d0d, +0x00011d0b, +0x00011d0a, +0x00011d09, +0x00011d08, +0x00011d07, +0x00011d06, +0x00011d04, +0x00011d03, +0x00011d02, +0x00011d00, +0x00011cff, +0x00011cfe, +0x00011cfd, +0x00011cfc, +0x00011cfa, +0x00011cf9, +0x00011cf8, +0x00011cf7, +0x00011cf5, +0x00011cf4, +0x00011cf3, +0x00011cf2, +0x00011cf0, +0x00011cef, +0x00011cee, +0x00011ced, +0x00011cec, +0x00011cea, +0x00011ce9, +0x00011ce8, +0x00011ce6, +0x00011ce5, +0x00011ce4, +0x00011ce3, +0x00011ce2, +0x00011ce1, +0x00011cdf, +0x00011cdd, +0x00011cdc, +0x00011cdb, +0x00011cda, +0x00011cd9, +0x00011cd8, +0x00011cd7, +0x00011cd6, +0x00011cd3, +0x00011cd2, +0x00011cd1, +0x00011cd0, +0x00011ccf, +0x00011cce, +0x00011ccd, +0x00011ccc, +0x00011cc9, +0x00011cc8, +0x00011cc7, +0x00011cc6, +0x00011cc5, +0x00011cc4, +0x00011cc3, +0x00011cc2, +0x00011cc1, +0x00011cbe, +0x00011cbd, +0x00011cbc, +0x00011cbb, +0x00011cba, +0x00011cb9, +0x00011cb8, +0x00011cb7, +0x00011cb5, +0x00011cb3, +0x00011cb2, +0x00011cb1, +0x00011cb0, +0x00011caf, +0x00011cae, +0x00011cad, +0x00011cab, +0x00011caa, +0x00011ca8, +0x00011ca7, +0x00011ca6, +0x00011ca5, +0x00011ca4, +0x00011ca2, +0x00011ca1, +0x00011ca0, +0x00011c9f, +0x00011c9e, +0x00011c9c, +0x00011c9a, +0x00011c99, +0x00011c98, +0x00011c97, +0x00011c96, +0x00011c95, +0x00011c94, +0x00011c92, +0x00011c91, +0x00011c8f, +0x00011c8e, +0x00011c8d, +0x00011c8c, +0x00011c8b, +0x00011c8a, +0x00011c88, +0x00011c87, +0x00011c86, +0x00011c84, +0x00011c83, +0x00011c82, +0x00011c81, +0x00011c80, +0x00011c7e, +0x00011c7d, +0x00011c7c, +0x00011c7b, +0x00011c7a, +0x00011c78, +0x00011c77, +0x00011c76, +0x00011c74, +0x00011c73, +0x00011c72, +0x00011c71, +0x00011c70, +0x00011c6f, +0x00011c6d, +0x00011c6c, +0x00011c6b, +0x00011c69, +0x00011c68, +0x00011c67, +0x00011c66, +0x00011c65, +0x00011c64, +0x00011c62, +0x00011c61, +0x00011c5f, +0x00011c5e, +0x00011c5d, +0x00011c5c, +0x00011c5b, +0x00011c5a, +0x00011c59, +0x00011c57, +0x00011c55, +0x00011c54, +0x00011c53, +0x00011c52, +0x00011c51, +0x00011c50, +0x00011c4f, +0x00011c4e, +0x00011c4b, +0x00011c4a, +0x00011c49, +0x00011c48, +0x00011c47, +0x00011c46, +0x00011c45, +0x00011c44, +0x00011c43, +0x00011c40, +0x00011c3f, +0x00011c3e, +0x00011c3d, +0x00011c3c, +0x00011c3b, +0x00011c3a, +0x00011c39, +0x00011c37, +0x00011c35, +0x00011c34, +0x00011c33, +0x00011c32, +0x00011c31, +0x00011c30, +0x00011c2f, +0x00011c2d, +0x00011c2c, +0x00011c2b, +0x00011c29, +0x00011c28, +0x00011c27, +0x00011c26, +0x00011c25, +0x00011c24, +0x00011c22, +0x00011c21, +0x00011c20, +0x00011c1e, +0x00011c1d, +0x00011c1c, +0x00011c1b, +0x00011c1a, +0x00011c18, +0x00011c17, +0x00011c16, +0x00011c15, +0x00011c13, +0x00011c12, +0x00011c11, +0x00011c10, +0x00011c0e, +0x00011c0d, +0x00011c0c, +0x00011c0b, +0x00011c0a, +0x00011c08, +0x00011c07, +0x00011c06, +0x00011c04, +0x00011c03, +0x00011c02, +0x00011c01, +0x00011c00, +0x00011bff, +0x00011bfd, +0x00011bfc, +0x00011bfa, +0x00011bf9, +0x00011bf8, +0x00011bf7, +0x00011bf6, +0x00011bf5, +0x00011bf4, +0x00011bf2, +0x00011bf0, +0x00011bef, +0x00011bee, +0x00011bed, +0x00011bec, +0x00011beb, +0x00011bea, +0x00011be9, +0x00011be6, +0x00011be5, +0x00011be4, +0x00011be3, +0x00011be2, +0x00011be1, +0x00011be0, +0x00011bdf, +0x00011bde, +0x00011bdd, +0x00011bda, +0x00011bd9, +0x00011bd8, +0x00011bd7, +0x00011bd6, +0x00011bd5, +0x00011bd4, +0x00011bd3, +0x00011bd1, +0x00011bcf, +0x00011bce, +0x00011bcd, +0x00011bcc, +0x00011bcb, +0x00011bca, +0x00011bc9, +0x00011bc7, +0x00011bc6, +0x00011bc4, +0x00011bc3, +0x00011bc2, +0x00011bc1, +0x00011bc0, +0x00011bbf, +0x00011bbd, +0x00011bbc, +0x00011bbb, +0x00011bb9, +0x00011bb8, +0x00011bb7, +0x00011bb6, +0x00011bb5, +0x00011bb3, +0x00011bb2, +0x00011bb1, +0x00011bb0, +0x00011bae, +0x00011bad, +0x00011bac, +0x00011bab, +0x00011ba9, +0x00011ba8, +0x00011ba7, +0x00011ba6, +0x00011ba5, +0x00011ba3, +0x00011ba2, +0x00011ba1, +0x00011b9f, +0x00011b9e, +0x00011b9d, +0x00011b9c, +0x00011b9b, +0x00011b9a, +0x00011b98, +0x00011b97, +0x00011b96, +0x00011b94, +0x00011b93, +0x00011b92, +0x00011b91, +0x00011b90, +0x00011b8f, +0x00011b8e, +0x00011b8c, +0x00011b8a, +0x00011b89, +0x00011b88, +0x00011b87, +0x00011b86, +0x00011b85, +0x00011b84, +0x00011b83, +0x00011b80, +0x00011b7f, +0x00011b7e, +0x00011b7d, +0x00011b7c, +0x00011b7b, +0x00011b7a, +0x00011b79, +0x00011b78, +0x00011b75, +0x00011b74, +0x00011b73, +0x00011b72, +0x00011b71, +0x00011b70, +0x00011b6f, +0x00011b6e, +0x00011b6c, +0x00011b6a, +0x00011b69, +0x00011b68, +0x00011b67, +0x00011b66, +0x00011b65, +0x00011b63, +0x00011b62, +0x00011b61, +0x00011b60, +0x00011b5f, +0x00011b5e, +0x00011b5c, +0x00011b5b, +0x00011b5a, +0x00011b58, +0x00011b57, +0x00011b56, +0x00011b55, +0x00011b54, +0x00011b53, +0x00011b51, +0x00011b50, +0x00011b4e, +0x00011b4d, +0x00011b4c, +0x00011b4b, +0x00011b4a, +0x00011b49, +0x00011b48, +0x00011b47, +0x00011b45, +0x00011b43, +0x00011b42, +0x00011b41, +0x00011b40, +0x00011b3f, +0x00011b3e, +0x00011b3d, +0x00011b3c, +0x00011b39, +0x00011b38, +0x00011b37, +0x00011b36, +0x00011b35, +0x00011b34, +0x00011b33, +0x00011b32, +0x00011b31, +0x00011b30, +0x00011b2d, +0x00011b2c, +0x00011b2b, +0x00011b2a, +0x00011b29, +0x00011b28, +0x00011b27, +0x00011b26, +0x00011b24, +0x00011b22, +0x00011b21, +0x00011b20, +0x00011b1f, +0x00011b1e, +0x00011b1d, +0x00011b1c, +0x00011b1b, +0x00011b19, +0x00011b18, +0x00011b16, +0x00011b15, +0x00011b14, +0x00011b13, +0x00011b12, +0x00011b11, +0x00011b0f, +0x00011b0e, +0x00011b0d, +0x00011b0b, +0x00011b0a, +0x00011b09, +0x00011b08, +0x00011b07, +0x00011b06, +0x00011b04, +0x00011b03, +0x00011b02, +0x00011b00, +0x00011aff, +0x00011afe, +0x00011afd, +0x00011afc, +0x00011afa, +0x00011af9, +0x00011af8, +0x00011af7, +0x00011af6, +0x00011af4, +0x00011af3, +0x00011af2, +0x00011af1, +0x00011aef, +0x00011aee, +0x00011aed, +0x00011aec, +0x00011aeb, +0x00011ae9, +0x00011ae8, +0x00011ae7, +0x00011ae5, +0x00011ae4, +0x00011ae3, +0x00011ae2, +0x00011ae1, +0x00011ae0, +0x00011adf, +0x00011add, +0x00011adc, +0x00011ada, +0x00011ad9, +0x00011ad8, +0x00011ad7, +0x00011ad6, +0x00011ad5, +0x00011ad4, +0x00011ad2, +0x00011ad0, +0x00011acf, +0x00011ace, +0x00011acd, +0x00011acc, +0x00011acb, +0x00011aca, +0x00011ac7, +0x00011ac6, +0x00011ac5, +0x00011ac4, +0x00011ac3, +0x00011ac2, +0x00011ac1, +0x00011ac0, +0x00011abf, +0x00011abc, +0x00011abb, +0x00011aba, +0x00011ab9, +0x00011ab8, +0x00011ab7, +0x00011ab6, +0x00011ab5, +0x00011ab4, +0x00011ab2, +0x00011ab0, +0x00011aaf, +0x00011aae, +0x00011aad, +0x00011aac, +0x00011aab, +0x00011aaa, +0x00011aa9, +0x00011aa7, +0x00011aa6, +0x00011aa4, +0x00011aa3, +0x00011aa2, +0x00011aa1, +0x00011aa0, +0x00011a9f, +0x00011a9e, +0x00011a9c, +0x00011a9b, +0x00011a9a, +0x00011a98, +0x00011a97, +0x00011a96, +0x00011a95, +0x00011a94, +0x00011a93, +0x00011a91, +0x00011a90, +0x00011a8f, +0x00011a8e, +0x00011a8c, +0x00011a8b, +0x00011a8a, +0x00011a89, +0x00011a87, +0x00011a86, +0x00011a85, +0x00011a84, +0x00011a83, +0x00011a82, +0x00011a80, +0x00011a7f, +0x00011a7e, +0x00011a7c, +0x00011a7b, +0x00011a7a, +0x00011a79, +0x00011a78, +0x00011a77, +0x00011a75, +0x00011a74, +0x00011a73, +0x00011a71, +0x00011a70, +0x00011a6f, +0x00011a6e, +0x00011a6d, +0x00011a6c, +0x00011a6b, +0x00011a69, +0x00011a68, +0x00011a66, +0x00011a65, +0x00011a64, +0x00011a63, +0x00011a62, +0x00011a61, +0x00011a60, +0x00011a5f, +0x00011a5d, +0x00011a5b, +0x00011a5a, +0x00011a59, +0x00011a58, +0x00011a57, +0x00011a56, +0x00011a55, +0x00011a54, +0x00011a53, +0x00011a50, +0x00011a4f, +0x00011a4e, +0x00011a4d, +0x00011a4c, +0x00011a4b, +0x00011a4a, +0x00011a49, +0x00011a48, +0x00011a47, +0x00011a44, +0x00011a43, +0x00011a42, +0x00011a41, +0x00011a40, +0x00011a3f, +0x00011a3e, +0x00011a3d, +0x00011a3b, +0x00011a3a, +0x00011a38, +0x00011a37, +0x00011a36, +0x00011a35, +0x00011a34, +0x00011a33, +0x00011a32, +0x00011a30, +0x00011a2f, +0x00011a2e, +0x00011a2c, +0x00011a2b, +0x00011a2a, +0x00011a29, +0x00011a28, +0x00011a27, +0x00011a25, +0x00011a24, +0x00011a23, +0x00011a21, +0x00011a20, +0x00011a1f, +0x00011a1e, +0x00011a1d, +0x00011a1c, +0x00011a1a, +0x00011a19, +0x00011a18, +0x00011a17, +0x00011a15, +0x00011a14, +0x00011a13, +0x00011a12, +0x00011a11, +0x00011a0f, +0x00011a0e, +0x00011a0d, +0x00011a0c, +0x00011a0b, +0x00011a09, +0x00011a08, +0x00011a07, +0x00011a06, +0x00011a04, +0x00011a03, +0x00011a02, +0x00011a01, +0x00011a00, +0x000119ff, +0x000119fd, +0x000119fc, +0x000119fa, +0x000119f9, +0x000119f8, +0x000119f7, +0x000119f6, +0x000119f5, +0x000119f4, +0x000119f3, +0x000119f1, +0x000119ef, +0x000119ee, +0x000119ed, +0x000119ec, +0x000119eb, +0x000119ea, +0x000119e9, +0x000119e8, +0x000119e7, +0x000119e4, +0x000119e3, +0x000119e2, +0x000119e1, +0x000119e0, +0x000119df, +0x000119de, +0x000119dd, +0x000119dc, +0x000119d9, +0x000119d8, +0x000119d7, +0x000119d6, +0x000119d5, +0x000119d4, +0x000119d3, +0x000119d2, +0x000119d1, +0x000119d0, +0x000119cd, +0x000119cc, +0x000119cb, +0x000119ca, +0x000119c9, +0x000119c8, +0x000119c7, +0x000119c6, +0x000119c5, +0x000119c3, +0x000119c1, +0x000119c0, +0x000119bf, +0x000119be, +0x000119bd, +0x000119bc, +0x000119bb, +0x000119ba, +0x000119b8, +0x000119b7, +0x000119b5, +0x000119b4, +0x000119b3, +0x000119b2, +0x000119b1, +0x000119b0, +0x000119ae, +0x000119ad, +0x000119ac, +0x000119ab, +0x000119a9, +0x000119a8, +0x000119a7, +0x000119a6, +0x000119a5, +0x000119a3, +0x000119a2, +0x000119a1, +0x000119a0, +0x0001199f, +0x0001199d, +0x0001199c, +0x0001199b, +0x0001199a, +0x00011998, +0x00011997, +0x00011996, +0x00011995, +0x00011994, +0x00011992, +0x00011991, +0x00011990, +0x0001198f, +0x0001198e, +0x0001198d, +0x0001198b, +0x0001198a, +0x00011988, +0x00011987, +0x00011986, +0x00011985, +0x00011984, +0x00011983, +0x00011982, +0x00011980, +0x0001197f, +0x0001197e, +0x0001197c, +0x0001197b, +0x0001197a, +0x00011979, +0x00011978, +0x00011977, +0x00011975, +0x00011974, +0x00011973, +0x00011972, +0x00011971, +0x0001196f, +0x0001196e, +0x0001196d, +0x0001196c, +0x0001196a, +0x00011969, +0x00011968, +0x00011967, +0x00011966, +0x00011965, +0x00011963, +0x00011962, +0x00011961, +0x0001195f, +0x0001195e, +0x0001195d, +0x0001195c, +0x0001195b, +0x0001195a, +0x00011959, +0x00011957, +0x00011956, +0x00011955, +0x00011953, +0x00011952, +0x00011951, +0x00011950, +0x0001194f, +0x0001194e, +0x0001194d, +0x0001194b, +0x0001194a, +0x00011948, +0x00011947, +0x00011946, +0x00011945, +0x00011944, +0x00011943, +0x00011942, +0x00011941, +0x00011940, +0x0001193d, +0x0001193c, +0x0001193b, +0x0001193a, +0x00011939, +0x00011938, +0x00011937, +0x00011936, +0x00011935, +0x00011934, +0x00011931, +0x00011930, +0x0001192f, +0x0001192e, +0x0001192d, +0x0001192c, +0x0001192b, +0x0001192a, +0x00011929, +0x00011928, +0x00011925, +0x00011924, +0x00011923, +0x00011922, +0x00011921, +0x00011920, +0x0001191f, +0x0001191e, +0x0001191d, +0x0001191b, +0x00011919, +0x00011918, +0x00011917, +0x00011916, +0x00011915, +0x00011914, +0x00011913, +0x00011912, +0x00011910, +0x0001190f, +0x0001190e, +0x0001190c, +0x0001190b, +0x0001190a, +0x00011909, +0x00011908, +0x00011907, +0x00011905, +0x00011904, +0x00011903, +0x00011902, +0x00011900, +0x000118ff, +0x000118fe, +0x000118fd, +0x000118fc, +0x000118fb, +0x000118f9, +0x000118f8, +0x000118f7, +0x000118f6, +0x000118f4, +0x000118f3, +0x000118f2, +0x000118f1, +0x000118f0, +0x000118ee, +0x000118ed, +0x000118ec, +0x000118eb, +0x000118ea, +0x000118e8, +0x000118e7, +0x000118e6, +0x000118e5, +0x000118e3, +0x000118e2, +0x000118e1, +0x000118e0, +0x000118df, +0x000118de, +0x000118dd, +0x000118db, +0x000118da, +0x000118d8, +0x000118d7, +0x000118d6, +0x000118d5, +0x000118d4, +0x000118d3, +0x000118d2, +0x000118d1, +0x000118cf, +0x000118ce, +0x000118cc, +0x000118cb, +0x000118ca, +0x000118c9, +0x000118c8, +0x000118c7, +0x000118c6, +0x000118c5, +0x000118c3, +0x000118c1, +0x000118c0, +0x000118bf, +0x000118be, +0x000118bd, +0x000118bc, +0x000118bb, +0x000118ba, +0x000118b9, +0x000118b6, +0x000118b5, +0x000118b4, +0x000118b3, +0x000118b2, +0x000118b1, +0x000118b0, +0x000118af, +0x000118ae, +0x000118ad, +0x000118ab, +0x000118a9, +0x000118a8, +0x000118a7, +0x000118a6, +0x000118a5, +0x000118a4, +0x000118a3, +0x000118a2, +0x000118a1, +0x0001189f, +0x0001189d, +0x0001189c, +0x0001189b, +0x0001189a, +0x00011899, +0x00011898, +0x00011897, +0x00011896, +0x00011894, +0x00011893, +0x00011891, +0x00011890, +0x0001188f, +0x0001188e, +0x0001188d, +0x0001188c, +0x0001188b, +0x00011889, +0x00011888, +0x00011887, +0x00011885, +0x00011884, +0x00011883, +0x00011882, +0x00011881, +0x00011880, +0x0001187e, +0x0001187d, +0x0001187c, +0x0001187b, +0x00011879, +0x00011878, +0x00011877, +0x00011876, +0x00011875, +0x00011874, +0x00011872, +0x00011871, +0x00011870, +0x0001186f, +0x0001186e, +0x0001186c, +0x0001186b, +0x0001186a, +0x00011869, +0x00011867, +0x00011866, +0x00011865, +0x00011864, +0x00011863, +0x00011862, +0x00011860, +0x0001185f, +0x0001185e, +0x0001185d, +0x0001185c, +0x0001185b, +0x0001185a, +0x00011859, +0x00011856, +0x00011855, +0x00011854, +0x00011853, +0x00011852, +0x00011851, +0x00011850, +0x0001184f, +0x0001184e, +0x0001184d, +0x0001184b, +0x00011849, +0x00011848, +0x00011847, +0x00011846, +0x00011845, +0x00011844, +0x00011843, +0x00011842, +0x00011841, +0x0001183f, +0x0001183d, +0x0001183c, +0x0001183b, +0x0001183a, +0x00011839, +0x00011838, +0x00011837, +0x00011836, +0x00011835, +0x00011833, +0x00011832, +0x00011830, +0x0001182f, +0x0001182e, +0x0001182d, +0x0001182c, +0x0001182b, +0x0001182a, +0x00011828, +0x00011827, +0x00011826, +0x00011825, +0x00011823, +0x00011822, +0x00011821, +0x00011820, +0x0001181f, +0x0001181e, +0x0001181c, +0x0001181b, +0x0001181a, +0x00011819, +0x00011817, +0x00011816, +0x00011815, +0x00011814, +0x00011813, +0x00011812, +0x00011810, +0x0001180f, +0x0001180e, +0x0001180d, +0x0001180c, +0x0001180a, +0x00011809, +0x00011808, +0x00011807, +0x00011805, +0x00011804, +0x00011803, +0x00011802, +0x00011801, +0x00011800, +0x000117ff, +0x000117fd, +0x000117fc, +0x000117fb, +0x000117f9, +0x000117f8, +0x000117f7, +0x000117f6, +0x000117f5, +0x000117f4, +0x000117f3, +0x000117f1, +0x000117f0, +0x000117ef, +0x000117ed, +0x000117ec, +0x000117eb, +0x000117ea, +0x000117e9, +0x000117e8, +0x000117e7, +0x000117e6, +0x000117e4, +0x000117e2, +0x000117e1, +0x000117e0, +0x000117df, +0x000117de, +0x000117dd, +0x000117dc, +0x000117db, +0x000117da, +0x000117d9, +0x000117d6, +0x000117d5, +0x000117d4, +0x000117d3, +0x000117d2, +0x000117d1, +0x000117d0, +0x000117cf, +0x000117ce, +0x000117cd, +0x000117ca, +0x000117c9, +0x000117c8, +0x000117c7, +0x000117c6, +0x000117c4, +0x000117c3, +0x000117c2, +0x000117c1, +0x000117c0, +0x000117bf, +0x000117be, +0x000117bd, +0x000117bb, +0x000117b9, +0x000117b8, +0x000117b7, +0x000117b6, +0x000117b5, +0x000117b4, +0x000117b3, +0x000117b2, +0x000117b1, +0x000117af, +0x000117ae, +0x000117ac, +0x000117ab, +0x000117aa, +0x000117a9, +0x000117a8, +0x000117a7, +0x000117a6, +0x000117a5, +0x000117a3, +0x000117a2, +0x000117a1, +0x0001179f, +0x0001179e, +0x0001179d, +0x0001179c, +0x0001179b, +0x0001179a, +0x00011799, +0x00011797, +0x00011796, +0x00011795, +0x00011794, +0x00011792, +0x00011791, +0x00011790, +0x0001178f, +0x0001178e, +0x0001178d, +0x0001178c, +0x0001178a, +0x00011789, +0x00011788, +0x00011787, +0x00011785, +0x00011784, +0x00011783, +0x00011782, +0x00011781, +0x00011780, +0x0001177e, +0x0001177d, +0x0001177c, +0x0001177b, +0x0001177a, +0x00011779, +0x00011777, +0x00011776, +0x00011775, +0x00011774, +0x00011772, +0x00011771, +0x00011770, +0x0001176f, +0x0001176e, +0x0001176d, +0x0001176c, +0x0001176a, +0x00011769, +0x00011768, +0x00011766, +0x00011765, +0x00011764, +0x00011763, +0x00011762, +0x00011761, +0x00011760, +0x0001175f, +0x0001175d, +0x0001175c, +0x0001175a, +0x00011759, +0x00011758, +0x00011757, +0x00011756, +0x00011755, +0x00011754, +0x00011753, +0x00011752, +0x00011750, +0x0001174e, +0x0001174d, +0x0001174c, +0x0001174b, +0x0001174a, +0x00011749, +0x00011748, +0x00011747, +0x00011746, +0x00011745, +0x00011742, +0x00011741, +0x00011740, +0x0001173f, +0x0001173e, +0x0001173d, +0x0001173c, +0x0001173b, +0x0001173a, +0x00011739, +0x00011738, +0x00011735, +0x00011734, +0x00011733, +0x00011732, +0x00011731, +0x00011730, +0x0001172f, +0x0001172e, +0x0001172d, +0x0001172c, +0x0001172b, +0x00011728, +0x00011727, +0x00011726, +0x00011725, +0x00011724, +0x00011723, +0x00011722, +0x00011721, +0x00011720, +0x0001171f, +0x0001171d, +0x0001171b, +0x0001171a, +0x00011719, +0x00011718, +0x00011717, +0x00011716, +0x00011715, +0x00011714, +0x00011713, +0x00011711, +0x00011710, +0x0001170f, +0x0001170d, +0x0001170c, +0x0001170b, +0x0001170a, +0x00011709, +0x00011708, +0x00011707, +0x00011705, +0x00011704, +0x00011703, +0x00011702, +0x00011700, +0x000116ff, +0x000116fe, +0x000116fd, +0x000116fc, +0x000116fb, +0x000116f9, +0x000116f8, +0x000116f7, +0x000116f6, +0x000116f5, +0x000116f3, +0x000116f2, +0x000116f1, +0x000116f0, +0x000116ef, +0x000116ed, +0x000116ec, +0x000116eb, +0x000116ea, +0x000116e9, +0x000116e8, +0x000116e6, +0x000116e5, +0x000116e4, +0x000116e3, +0x000116e1, +0x000116e0, +0x000116df, +0x000116de, +0x000116dd, +0x000116dc, +0x000116db, +0x000116d9, +0x000116d8, +0x000116d7, +0x000116d5, +0x000116d4, +0x000116d3, +0x000116d2, +0x000116d1, +0x000116d0, +0x000116cf, +0x000116ce, +0x000116cc, +0x000116cb, +0x000116ca, +0x000116c8, +0x000116c7, +0x000116c6, +0x000116c5, +0x000116c4, +0x000116c3, +0x000116c2, +0x000116c1, +0x000116bf, +0x000116be, +0x000116bc, +0x000116bb, +0x000116ba, +0x000116b9, +0x000116b8, +0x000116b7, +0x000116b6, +0x000116b5, +0x000116b4, +0x000116b2, +0x000116b0, +0x000116af, +0x000116ae, +0x000116ad, +0x000116ac, +0x000116ab, +0x000116aa, +0x000116a9, +0x000116a8, +0x000116a7, +0x000116a6, +0x000116a3, +0x000116a2, +0x000116a1, +0x000116a0, +0x0001169f, +0x0001169e, +0x0001169d, +0x0001169c, +0x0001169b, +0x0001169a, +0x00011698, +0x00011696, +0x00011695, +0x00011695, +0x00011693, +0x00011692, +0x00011690, +0x0001168f, +0x0001168e, +0x0001168d, +0x0001168c, +0x0001168b, +0x0001168a, +0x00011689, +0x00011688, +0x00011686, +0x00011684, +0x00011683, +0x00011682, +0x00011681, +0x00011680, +0x0001167f, +0x0001167e, +0x0001167d, +0x0001167c, +0x0001167b, +0x0001167a, +0x00011677, +0x00011676, +0x00011675, +0x00011674, +0x00011673, +0x00011672, +0x00011671, +0x00011670, +0x0001166f, +0x0001166e, +0x0001166d, +0x0001166a, +0x00011669, +0x00011668, +0x00011667, +0x00011666, +0x00011665, +0x00011664, +0x00011663, +0x00011662, +0x00011661, +0x00011660, +0x0001165e, +0x0001165c, +0x0001165b, +0x0001165a, +0x00011659, +0x00011658, +0x00011657, +0x00011656, +0x00011655, +0x00011654, +0x00011653, +0x00011651, +0x00011650, +0x0001164e, +0x0001164d, +0x0001164c, +0x0001164b, +0x0001164a, +0x00011649, +0x00011648, +0x00011647, +0x00011646, +0x00011644, +0x00011643, +0x00011641, +0x00011640, +0x0001163f, +0x0001163e, +0x0001163d, +0x0001163c, +0x0001163b, +0x0001163a, +0x00011638, +0x00011637, +0x00011636, +0x00011635, +0x00011633, +0x00011632, +0x00011631, +0x00011630, +0x0001162f, +0x0001162e, +0x0001162d, +0x0001162b, +0x0001162a, +0x00011629, +0x00011628, +0x00011627, +0x00011625, +0x00011624, +0x00011623, +0x00011622, +0x00011621, +0x0001161f, +0x0001161e, +0x0001161d, +0x0001161c, +0x0001161b, +0x0001161a, +0x00011618, +0x00011617, +0x00011616, +0x00011615, +0x00011614, +0x00011612, +0x00011611, +0x00011610, +0x0001160f, +0x0001160e, +0x0001160d, +0x0001160c, +0x0001160a, +0x00011609, +0x00011608, +0x00011607, +0x00011605, +0x00011604, +0x00011603, +0x00011602, +0x00011601, +0x00011600, +0x000115ff, +0x000115fe, +0x000115fc, +0x000115fb, +0x000115f9, +0x000115f8, +0x000115f7, +0x000115f6, +0x000115f5, +0x000115f4, +0x000115f3, +0x000115f2, +0x000115f1, +0x000115ef, +0x000115ee, +0x000115ec, +0x000115eb, +0x000115ea, +0x000115e9, +0x000115e8, +0x000115e7, +0x000115e6, +0x000115e5, +0x000115e4, +0x000115e3, +0x000115e1, +0x000115df, +0x000115de, +0x000115dd, +0x000115dc, +0x000115db, +0x000115da, +0x000115d9, +0x000115d8, +0x000115d7, +0x000115d6, +0x000115d3, +0x000115d2, +0x000115d1, +0x000115d0, +0x000115cf, +0x000115ce, +0x000115cd, +0x000115cc, +0x000115cb, +0x000115ca, +0x000115c9, +0x000115c8, +0x000115c5, +0x000115c4, +0x000115c3, +0x000115c2, +0x000115c1, +0x000115c0, +0x000115bf, +0x000115be, +0x000115bd, +0x000115bc, +0x000115bb, +0x000115b9, +0x000115b7, +0x000115b6, +0x000115b5, +0x000115b4, +0x000115b3, +0x000115b2, +0x000115b1, +0x000115b0, +0x000115af, +0x000115ad, +0x000115ac, +0x000115aa, +0x000115a9, +0x000115a8, +0x000115a7, +0x000115a6, +0x000115a5, +0x000115a4, +0x000115a3, +0x000115a2, +0x000115a0, +0x0001159f, +0x0001159e, +0x0001159c, +0x0001159b, +0x0001159a, +0x00011599, +0x00011598, +0x00011597, +0x00011596, +0x00011594, +0x00011593, +0x00011592, +0x00011591, +0x00011590, +0x0001158e, +0x0001158d, +0x0001158c, +0x0001158b, +0x0001158a, +0x00011589, +0x00011587, +0x00011586, +0x00011585, +0x00011584, +0x00011583, +0x00011581, +0x00011580, +0x0001157f, +0x0001157e, +0x0001157d, +0x0001157c, +0x0001157a, +0x00011579, +0x00011578, +0x00011577, +0x00011576, +0x00011575, +0x00011573, +0x00011572, +0x00011571, +0x00011570, +0x0001156e, +0x0001156d, +0x0001156c, +0x0001156b, +0x0001156a, +0x00011569, +0x00011568, +0x00011567, +0x00011566, +0x00011565, +0x00011564, +0x00011561, +0x00011560, +0x0001155f, +0x0001155e, +0x0001155d, +0x0001155c, +0x0001155b, +0x0001155a, +0x00011559, +0x00011558, +0x00011557, +0x00011555, +0x00011553, +0x00011552, +0x00011551, +0x00011550, +0x0001154f, +0x0001154e, +0x0001154d, +0x0001154c, +0x0001154b, +0x0001154a, +0x00011548, +0x00011547, +0x00011545, +0x00011544, +0x00011543, +0x00011542, +0x00011541, +0x00011540, +0x0001153f, +0x0001153e, +0x0001153d, +0x0001153c, +0x0001153a, +0x00011539, +0x00011537, +0x00011536, +0x00011535, +0x00011534, +0x00011533, +0x00011532, +0x00011531, +0x00011530, +0x0001152f, +0x0001152d, +0x0001152c, +0x0001152b, +0x00011529, +0x00011528, +0x00011527, +0x00011526, +0x00011525, +0x00011524, +0x00011523, +0x00011522, +0x00011520, +0x0001151f, +0x0001151e, +0x0001151d, +0x0001151c, +0x0001151a, +0x00011519, +0x00011518, +0x00011517, +0x00011516, +0x00011515, +0x00011513, +0x00011512, +0x00011511, +0x00011510, +0x0001150f, +0x0001150e, +0x0001150c, +0x0001150b, +0x0001150a, +0x00011509, +0x00011508, +0x00011506, +0x00011505, +0x00011504, +0x00011503, +0x00011502, +0x00011501, +0x00011500, +0x000114fe, +0x000114fd, +0x000114fc, +0x000114fb, +0x000114fa, +0x000114f8, +0x000114f7, +0x000114f6, +0x000114f5, +0x000114f4, +0x000114f3, +0x000114f2, +0x000114f0, +0x000114ef, +0x000114ee, +0x000114ed, +0x000114eb, +0x000114ea, +0x000114e9, +0x000114e8, +0x000114e7, +0x000114e6, +0x000114e5, +0x000114e4, +0x000114e2, +0x000114e1, +0x000114e0, +0x000114de, +0x000114dd, +0x000114dc, +0x000114db, +0x000114da, +0x000114d9, +0x000114d8, +0x000114d7, +0x000114d6, +0x000114d4, +0x000114d3, +0x000114d1, +0x000114d0, +0x000114cf, +0x000114ce, +0x000114cd, +0x000114cc, +0x000114cb, +0x000114ca, +0x000114c9, +0x000114c8, +0x000114c7, +0x000114c4, +0x000114c3, +0x000114c2, +0x000114c1, +0x000114c0, +0x000114bf, +0x000114be, +0x000114bd, +0x000114bc, +0x000114bb, +0x000114ba, +0x000114b9, +0x000114b6, +0x000114b5, +0x000114b4, +0x000114b3, +0x000114b2, +0x000114b1, +0x000114b0, +0x000114af, +0x000114ae, +0x000114ad, +0x000114ac, +0x000114ab, +0x000114a8, +0x000114a7, +0x000114a6, +0x000114a5, +0x000114a4, +0x000114a3, +0x000114a2, +0x000114a1, +0x000114a0, +0x0001149f, +0x0001149e, +0x0001149c, +0x0001149a, +0x00011499, +0x00011498, +0x00011497, +0x00011496, +0x00011495, +0x00011494, +0x00011493, +0x00011492, +0x00011491, +0x0001148f, +0x0001148e, +0x0001148c, +0x0001148b, +0x0001148a, +0x00011489, +0x00011488, +0x00011487, +0x00011486, +0x00011485, +0x00011484, +0x00011482, +0x00011481, +0x00011480, +0x0001147f, +0x0001147d, +0x0001147c, +0x0001147b, +0x0001147a, +0x00011479, +0x00011478, +0x00011477, +0x00011476, +0x00011474, +0x00011473, +0x00011472, +0x00011471, +0x0001146f, +0x0001146e, +0x0001146d, +0x0001146c, +0x0001146b, +0x0001146a, +0x00011469, +0x00011467, +0x00011466, +0x00011465, +0x00011464, +0x00011463, +0x00011461, +0x00011460, +0x0001145f, +0x0001145e, +0x0001145d, +0x0001145c, +0x0001145a, +0x00011459, +0x00011458, +0x00011457, +0x00011456, +0x00011455, +0x00011453, +0x00011452, +0x00011451, +0x00011450, +0x0001144f, +0x0001144d, +0x0001144c, +0x0001144b, +0x0001144a, +0x00011449, +0x00011448, +0x00011447, +0x00011445, +0x00011444, +0x00011443, +0x00011442, +0x00011440, +0x0001143f, +0x0001143e, +0x0001143d, +0x0001143c, +0x0001143b, +0x0001143a, +0x00011439, +0x00011438, +0x00011437, +0x00011436, +0x00011435, +0x00011433, +0x00011432, +0x00011431, +0x0001142f, +0x0001142e, +0x0001142d, +0x0001142c, +0x0001142b, +0x0001142a, +0x00011429, +0x00011428, +0x00011427, +0x00011426, +0x00011424, +0x00011423, +0x00011421, +0x00011420, +0x0001141f, +0x0001141e, +0x0001141d, +0x0001141c, +0x0001141b, +0x0001141a, +0x00011419, +0x00011418, +0x00011417, +0x00011414, +0x00011413, +0x00011412, +0x00011411, +0x00011410, +0x0001140f, +0x0001140e, +0x0001140d, +0x0001140c, +0x0001140b, +0x0001140a, +0x00011409, +0x00011406, +0x00011405, +0x00011404, +0x00011403, +0x00011402, +0x00011401, +0x00011400, +0x000113ff, +0x000113fe, +0x000113fd, +0x000113fc, +0x000113fb, +0x000113fa, +0x000113f7, +0x000113f6, +0x000113f5, +0x000113f4, +0x000113f3, +0x000113f2, +0x000113f1, +0x000113f0, +0x000113ef, +0x000113ee, +0x000113ed, +0x000113ec, +0x000113ea, +0x000113e8, +0x000113e7, +0x000113e6, +0x000113e5, +0x000113e4, +0x000113e3, +0x000113e2, +0x000113e1, +0x000113e0, +0x000113df, +0x000113de, +0x000113dc, +0x000113db, +0x000113d9, +0x000113d8, +0x000113d7, +0x000113d6, +0x000113d5, +0x000113d4, +0x000113d3, +0x000113d2, +0x000113d1, +0x000113cf, +0x000113ce, +0x000113cd, +0x000113cc, +0x000113ca, +0x000113c9, +0x000113c8, +0x000113c7, +0x000113c6, +0x000113c5, +0x000113c4, +0x000113c3, +0x000113c1, +0x000113c0, +0x000113bf, +0x000113be, +0x000113bc, +0x000113bb, +0x000113ba, +0x000113b9, +0x000113b8, +0x000113b7, +0x000113b6, +0x000113b5, +0x000113b3, +0x000113b2, +0x000113b1, +0x000113b0, +0x000113af, +0x000113ad, +0x000113ac, +0x000113ab, +0x000113aa, +0x000113a9, +0x000113a8, +0x000113a7, +0x000113a5, +0x000113a4, +0x000113a3, +0x000113a1, +0x000113a0, +0x0001139f, +0x0001139e, +0x0001139d, +0x0001139c, +0x0001139b, +0x0001139a, +0x00011399, +0x00011397, +0x00011396, +0x00011395, +0x00011394, +0x00011392, +0x00011391, +0x00011390, +0x0001138f, +0x0001138e, +0x0001138d, +0x0001138c, +0x0001138b, +0x0001138a, +0x00011388, +0x00011387, +0x00011386, +0x00011385, +0x00011384, +0x00011382, +0x00011381, +0x00011380, +0x0001137f, +0x0001137e, +0x0001137d, +0x0001137c, +0x0001137a, +0x00011379, +0x00011378, +0x00011377, +0x00011376, +0x00011375, +0x00011373, +0x00011372, +0x00011371, +0x00011370, +0x0001136f, +0x0001136e, +0x0001136c, +0x0001136b, +0x0001136a, +0x00011369, +0x00011368, +0x00011367, +0x00011366, +0x00011365, +0x00011363, +0x00011362, +0x00011361, +0x00011360, +0x0001135f, +0x0001135d, +0x0001135c, +0x0001135b, +0x0001135a, +0x00011359, +0x00011358, +0x00011357, +0x00011356, +0x00011354, +0x00011353, +0x00011352, +0x00011351, +0x0001134f, +0x0001134e, +0x0001134d, +0x0001134c, +0x0001134b, +0x0001134a, +0x00011349, +0x00011348, +0x00011347, +0x00011346, +0x00011344, +0x00011343, +0x00011342, +0x00011340, +0x0001133f, +0x0001133e, +0x0001133d, +0x0001133c, +0x0001133b, +0x0001133a, +0x00011339, +0x00011338, +0x00011337, +0x00011335, +0x00011334, +0x00011332, +0x00011331, +0x00011330, +0x0001132f, +0x0001132e, +0x0001132d, +0x0001132c, +0x0001132b, +0x0001132a, +0x00011329, +0x00011328, +0x00011327, +0x00011325, +0x00011323, +0x00011322, +0x00011321, +0x00011320, +0x0001131f, +0x0001131e, +0x0001131d, +0x0001131c, +0x0001131b, +0x0001131a, +0x00011319, +0x00011318, +0x00011315, +0x00011314, +0x00011313, +0x00011312, +0x00011311, +0x00011310, +0x0001130f, +0x0001130e, +0x0001130d, +0x0001130c, +0x0001130b, +0x0001130a, +0x00011309, +0x00011308, +0x00011305, +0x00011304, +0x00011303, +0x00011302, +0x00011301, +0x00011300, +0x000112ff, +0x000112fe, +0x000112fd, +0x000112fc, +0x000112fb, +0x000112fa, +0x000112f8, +0x000112f6, +0x000112f5, +0x000112f4, +0x000112f3, +0x000112f2, +0x000112f1, +0x000112f0, +0x000112ef, +0x000112ee, +0x000112ed, +0x000112ec, +0x000112eb, +0x000112e9, +0x000112e8, +0x000112e6, +0x000112e5, +0x000112e4, +0x000112e3, +0x000112e2, +0x000112e1, +0x000112e0, +0x000112df, +0x000112de, +0x000112dd, +0x000112db, +0x000112da, +0x000112d9, +0x000112d7, +0x000112d6, +0x000112d5, +0x000112d4, +0x000112d3, +0x000112d2, +0x000112d1, +0x000112d0, +0x000112cf, +0x000112ce, +0x000112cc, +0x000112cb, +0x000112ca, +0x000112c9, +0x000112c7, +0x000112c6, +0x000112c5, +0x000112c4, +0x000112c3, +0x000112c2, +0x000112c1, +0x000112c0, +0x000112be, +0x000112bd, +0x000112bc, +0x000112bb, +0x000112ba, +0x000112b8, +0x000112b7, +0x000112b6, +0x000112b5, +0x000112b4, +0x000112b3, +0x000112b2, +0x000112b1, +0x000112af, +0x000112ae, +0x000112ad, +0x000112ac, +0x000112ab, +0x000112a9, +0x000112a8, +0x000112a7, +0x000112a6, +0x000112a5, +0x000112a4, +0x000112a3, +0x000112a1, +0x000112a0, +0x0001129f, +0x0001129e, +0x0001129d, +0x0001129c, +0x0001129b, +0x00011299, +0x00011298, +0x00011297, +0x00011296, +0x00011295, +0x00011294, +0x00011292, +0x00011291, +0x00011290, +0x0001128f, +0x0001128e, +0x0001128d, +0x0001128c, +0x0001128a, +0x00011289, +0x00011288, +0x00011287, +0x00011286, +0x00011284, +0x00011283, +0x00011282, +0x00011281, +0x00011280, +0x0001127f, +0x0001127d, +0x0001127c, +0x0001127b, +0x0001127a, +0x00011279, +0x00011278, +0x00011277, +0x00011276, +0x00011275, +0x00011274, +0x00011273, +0x00011271, +0x00011270, +0x0001126f, +0x0001126d, +0x0001126c, +0x0001126b, +0x0001126a, +0x00011269, +0x00011268, +0x00011267, +0x00011266, +0x00011265, +0x00011264, +0x00011262, +0x00011261, +0x00011260, +0x0001125f, +0x0001125d, +0x0001125c, +0x0001125b, +0x0001125a, +0x00011259, +0x00011258, +0x00011257, +0x00011256, +0x00011255, +0x00011253, +0x00011252, +0x00011251, +0x00011250, +0x0001124f, +0x0001124d, +0x0001124c, +0x0001124b, +0x0001124a, +0x00011249, +0x00011248, +0x00011247, +0x00011246, +0x00011245, +0x00011243, +0x00011242, +0x00011241, +0x00011240, +0x0001123f, +0x0001123d, +0x0001123c, +0x0001123b, +0x0001123a, +0x00011239, +0x00011238, +0x00011237, +0x00011236, +0x00011234, +0x00011233, +0x00011232, +0x00011231, +0x00011230, +0x0001122f, +0x0001122e, +0x0001122c, +0x0001122b, +0x0001122a, +0x00011229, +0x00011228, +0x00011227, +0x00011225, +0x00011224, +0x00011223, +0x00011222, +0x00011221, +0x00011220, +0x0001121f, +0x0001121e, +0x0001121c, +0x0001121b, +0x0001121a, +0x00011219, +0x00011218, +0x00011216, +0x00011215, +0x00011214, +0x00011213, +0x00011212, +0x00011211, +0x00011210, +0x0001120f, +0x0001120e, +0x0001120c, +0x0001120b, +0x0001120a, +0x00011209, +0x00011207, +0x00011206, +0x00011205, +0x00011204, +0x00011203, +0x00011202, +0x00011201, +0x00011200, +0x000111ff, +0x000111fe, +0x000111fc, +0x000111fb, +0x000111fa, +0x000111f9, +0x000111f7, +0x000111f6, +0x000111f5, +0x000111f4, +0x000111f3, +0x000111f2, +0x000111f1, +0x000111f0, +0x000111ef, +0x000111ee, +0x000111ed, +0x000111eb, +0x000111ea, +0x000111e8, +0x000111e7, +0x000111e6, +0x000111e5, +0x000111e4, +0x000111e3, +0x000111e2, +0x000111e1, +0x000111e0, +0x000111df, +0x000111de, +0x000111dd, +0x000111db, +0x000111d9, +0x000111d8, +0x000111d7, +0x000111d6, +0x000111d5, +0x000111d4, +0x000111d3, +0x000111d2, +0x000111d1, +0x000111d0, +0x000111cf, +0x000111ce, +0x000111cd, +0x000111ca, +0x000111c9, +0x000111c8, +0x000111c7, +0x000111c6, +0x000111c5, +0x000111c4, +0x000111c3, +0x000111c2, +0x000111c1, +0x000111c0, +0x000111bf, +0x000111be, +0x000111bd, +0x000111ba, +0x000111b9, +0x000111b8, +0x000111b7, +0x000111b6, +0x000111b5, +0x000111b4, +0x000111b3, +0x000111b2, +0x000111b1, +0x000111b0, +0x000111af, +0x000111ae, +0x000111ad, +0x000111aa, +0x000111a9, +0x000111a8, +0x000111a7, +0x000111a6, +0x000111a5, +0x000111a4, +0x000111a3, +0x000111a2, +0x000111a1, +0x000111a0, +0x0001119f, +0x0001119e, +0x0001119c, +0x0001119b, +0x00011199, +0x00011198, +0x00011197, +0x00011196, +0x00011195, +0x00011194, +0x00011193, +0x00011192, +0x00011191, +0x00011190, +0x0001118f, +0x0001118d, +0x0001118c, +0x0001118b, +0x00011189, +0x00011188, +0x00011187, +0x00011186, +0x00011185, +0x00011184, +0x00011183, +0x00011182, +0x00011181, +0x00011180, +0x0001117e, +0x0001117d, +0x0001117c, +0x0001117b, +0x00011179, +0x00011178, +0x00011177, +0x00011176, +0x00011175, +0x00011174, +0x00011173, +0x00011172, +0x00011171, +0x00011170, +0x0001116e, +0x0001116d, +0x0001116c, +0x0001116b, +0x00011169, +0x00011168, +0x00011167, +0x00011166, +0x00011165, +0x00011164, +0x00011163, +0x00011162, +0x00011161, +0x0001115f, +0x0001115e, +0x0001115d, +0x0001115c, +0x0001115b, +0x0001115a, +0x00011159, +0x00011157, +0x00011156, +0x00011155, +0x00011154, +0x00011153, +0x00011152, +0x00011151, +0x00011150, +0x0001114f, +0x0001114e, +0x0001114c, +0x0001114b, +0x0001114a, +0x00011149, +0x00011147, +0x00011146, +0x00011145, +0x00011144, +0x00011143, +0x00011142, +0x00011141, +0x00011140, +0x0001113f, +0x0001113e, +0x0001113d, +0x0001113b, +0x0001113a, +0x00011139, +0x00011137, +0x00011136, +0x00011135, +0x00011134, +0x00011133, +0x00011132, +0x00011131, +0x00011130, +0x0001112f, +0x0001112e, +0x0001112d, +0x0001112c, +0x0001112a, +0x00011129, +0x00011127, +0x00011126, +0x00011125, +0x00011124, +0x00011123, +0x00011122, +0x00011121, +0x00011120, +0x0001111f, +0x0001111e, +0x0001111d, +0x0001111c, +0x0001111b, +0x00011119, +0x00011117, +0x00011116, +0x00011115, +0x00011114, +0x00011113, +0x00011112, +0x00011111, +0x00011110, +0x0001110f, +0x0001110e, +0x0001110d, +0x0001110c, +0x0001110b, +0x0001110a, +0x00011107, +0x00011106, +0x00011105, +0x00011104, +0x00011103, +0x00011102, +0x00011101, +0x00011100, +0x000110ff, +0x000110fe, +0x000110fd, +0x000110fc, +0x000110fb, +0x000110fa, +0x000110f9, +0x000110f6, +0x000110f5, +0x000110f4, +0x000110f3, +0x000110f2, +0x000110f1, +0x000110f0, +0x000110ef, +0x000110ee, +0x000110ed, +0x000110ec, +0x000110eb, +0x000110ea, +0x000110e9, +0x000110e7, +0x000110e5, +0x000110e4, +0x000110e3, +0x000110e2, +0x000110e1, +0x000110e0, +0x000110df, +0x000110de, +0x000110dd, +0x000110dc, +0x000110db, +0x000110da, +0x000110d9, +0x000110d7, +0x000110d6, +0x000110d4, +0x000110d3, +0x000110d2, +0x000110d1, +0x000110d0, +0x000110cf, +0x000110ce, +0x000110cd, +0x000110cc, +0x000110cb, +0x000110ca, +0x000110c8, +0x000110c7, +0x000110c6, +0x000110c5, +0x000110c4, +0x000110c2, +0x000110c1, +0x000110c0, +0x000110bf, +0x000110bd, +0x000110bc, +0x000110bb, +0x000110ba, +0x000110b9, +0x000110b8, +0x000110b7, +0x000110b6, +0x000110b5, +0x000110b4, +0x000110b3, +0x000110b1, +0x000110b0, +0x000110af, +0x000110ae, +0x000110ad, +0x000110ab, +0x000110aa, +0x000110a9, +0x000110a8, +0x000110a7, +0x000110a6, +0x000110a5, +0x000110a4, +0x000110a3, +0x000110a2, +0x000110a0, +0x0001109f, +0x0001109e, +0x0001109d, +0x0001109c, +0x0001109b, +0x00011099, +0x00011098, +0x00011097, +0x00011096, +0x00011095, +0x00011094, +0x00011093, +0x00011092, +0x00011091, +0x0001108f, +0x0001108e, +0x0001108d, +0x0001108c, +0x0001108b, +0x0001108a, +0x00011089, +0x00011087, +0x00011086, +0x00011085, +0x00011084, +0x00011083, +0x00011082, +0x00011081, +0x00011080, +0x0001107e, +0x0001107d, +0x0001107c, +0x0001107b, +0x0001107a, +0x00011079, +0x00011078, +0x00011077, +0x00011075, +0x00011074, +0x00011073, +0x00011072, +0x00011071, +0x00011070, +0x0001106f, +0x0001106d, +0x0001106c, +0x0001106b, +0x0001106a, +0x00011069, +0x00011068, +0x00011067, +0x00011066, +0x00011065, +0x00011063, +0x00011062, +0x00011061, +0x00011060, +0x0001105f, +0x0001105e, +0x0001105c, +0x0001105b, +0x0001105a, +0x00011059, +0x00011058, +0x00011057, +0x00011056, +0x00011055, +0x00011054, +0x00011053, +0x00011051, +0x00011050, +0x0001104f, +0x0001104e, +0x0001104d, +0x0001104b, +0x0001104a, +0x00011049, +0x00011048, +0x00011047, +0x00011046, +0x00011045, +0x00011044, +0x00011043, +0x00011042, +0x00011041, +0x0001103f, +0x0001103e, +0x0001103d, +0x0001103c, +0x0001103a, +0x00011039, +0x00011038, +0x00011037, +0x00011036, +0x00011035, +0x00011034, +0x00011033, +0x00011032, +0x00011031, +0x00011030, +0x0001102f, +0x0001102d, +0x0001102c, +0x0001102b, +0x00011029, +0x00011028, +0x00011027, +0x00011026, +0x00011025, +0x00011024, +0x00011023, +0x00011022, +0x00011021, +0x00011020, +0x0001101f, +0x0001101e, +0x0001101d, +0x0001101b, +0x0001101a, +0x00011018, +0x00011017, +0x00011016, +0x00011015, +0x00011014, +0x00011013, +0x00011012, +0x00011011, +0x00011010, +0x0001100f, +0x0001100e, +0x0001100d, +0x0001100c, +0x0001100b, +0x00011009, +0x00011007, +0x00011006, +0x00011005, +0x00011004, +0x00011003, +0x00011002, +0x00011001, +0x00011000, +0x00010fff, +0x00010ffe, +0x00010ffd, +0x00010ffc, +0x00010ffb, +0x00010ffa, +0x00010ff9, +0x00010ff6, +0x00010ff5, +0x00010ff4, +0x00010ff3, +0x00010ff2, +0x00010ff1, +0x00010ff0, +0x00010fef, +0x00010fee, +0x00010fed, +0x00010fec, +0x00010feb, +0x00010fea, +0x00010fe9, +0x00010fe8, +0x00010fe7, +0x00010fe4, +0x00010fe3, +0x00010fe2, +0x00010fe1, +0x00010fe0, +0x00010fdf, +0x00010fde, +0x00010fdd, +0x00010fdc, +0x00010fdb, +0x00010fda, +0x00010fd9, +0x00010fd8, +0x00010fd7, +0x00010fd6, +0x00010fd4, +0x00010fd2, +0x00010fd1, +0x00010fd0, +0x00010fcf, +0x00010fce, +0x00010fcd, +0x00010fcc, +0x00010fcb, +0x00010fca, +0x00010fc9, +0x00010fc8, +0x00010fc7, +0x00010fc6, +0x00010fc5, +0x00010fc3, +0x00010fc2, +0x00010fc0, +0x00010fbf, +0x00010fbe, +0x00010fbd, +0x00010fbc, +0x00010fbb, +0x00010fba, +0x00010fb9, +0x00010fb8, +0x00010fb7, +0x00010fb6, +0x00010fb5, +0x00010fb4, +0x00010fb2, +0x00010fb1, +0x00010fb0, +0x00010fae, +0x00010fad, +0x00010fac, +0x00010fab, +0x00010faa, +0x00010fa9, +0x00010fa8, +0x00010fa6, +0x00010fa5, +0x00010fa4, +0x00010fa3, +0x00010fa2, +0x00010fa1, +0x00010fa0, +0x00010f9f, +0x00010f9e, +0x00010f9d, +0x00010f9c, +0x00010f9b, +0x00010f99, +0x00010f97, +0x00010f96, +0x00010f95, +0x00010f94, +0x00010f93, +0x00010f92, +0x00010f91, +0x00010f90, +0x00010f8f, +0x00010f8e, +0x00010f8d, +0x00010f8c, +0x00010f8b, +0x00010f8a, +0x00010f89, +0x00010f88, +0x00010f86, +0x00010f84, +0x00010f83, +0x00010f82, +0x00010f81, +0x00010f80, +0x00010f7f, +0x00010f7e, +0x00010f7d, +0x00010f7c, +0x00010f7b, +0x00010f7a, +0x00010f79, +0x00010f78, +0x00010f77, +0x00010f76, +0x00010f74, +0x00010f73, +0x00010f71, +0x00010f70, +0x00010f6f, +0x00010f6e, +0x00010f6d, +0x00010f6c, +0x00010f6b, +0x00010f6a, +0x00010f69, +0x00010f68, +0x00010f67, +0x00010f66, +0x00010f65, +0x00010f64, +0x00010f62, +0x00010f61, +0x00010f60, +0x00010f5f, +0x00010f5d, +0x00010f5c, +0x00010f5b, +0x00010f5a, +0x00010f59, +0x00010f58, +0x00010f57, +0x00010f56, +0x00010f55, +0x00010f54, +0x00010f53, +0x00010f52, +0x00010f50, +0x00010f4f, +0x00010f4e, +0x00010f4d, +0x00010f4c, +0x00010f4a, +0x00010f49, +0x00010f48, +0x00010f47, +0x00010f46, +0x00010f45, +0x00010f44, +0x00010f43, +0x00010f42, +0x00010f41, +0x00010f40, +0x00010f3e, +0x00010f3d, +0x00010f3c, +0x00010f3b, +0x00010f3a, +0x00010f39, +0x00010f37, +0x00010f36, +0x00010f35, +0x00010f34, +0x00010f33, +0x00010f32, +0x00010f31, +0x00010f30, +0x00010f2f, +0x00010f2e, +0x00010f2c, +0x00010f2b, +0x00010f2a, +0x00010f29, +0x00010f28, +0x00010f27, +0x00010f26, +0x00010f24, +0x00010f23, +0x00010f22, +0x00010f21, +0x00010f20, +0x00010f1f, +0x00010f1e, +0x00010f1d, +0x00010f1c, +0x00010f1a, +0x00010f19, +0x00010f18, +0x00010f17, +0x00010f16, +0x00010f15, +0x00010f14, +0x00010f13, +0x00010f11, +0x00010f10, +0x00010f0f, +0x00010f0e, +0x00010f0d, +0x00010f0c, +0x00010f0b, +0x00010f0a, +0x00010f08, +0x00010f07, +0x00010f06, +0x00010f05, +0x00010f04, +0x00010f03, +0x00010f02, +0x00010f01, +0x00010f00, +0x00010efe, +0x00010efd, +0x00010efc, +0x00010efb, +0x00010efa, +0x00010ef9, +0x00010ef8, +0x00010ef6, +0x00010ef5, +0x00010ef4, +0x00010ef3, +0x00010ef2, +0x00010ef1, +0x00010ef0, +0x00010eef, +0x00010eee, +0x00010eed, +0x00010eeb, +0x00010eea, +0x00010ee9, +0x00010ee8, +0x00010ee7, +0x00010ee6, +0x00010ee4, +0x00010ee3, +0x00010ee2, +0x00010ee1, +0x00010ee0, +0x00010edf, +0x00010ede, +0x00010edd, +0x00010edc, +0x00010edb, +0x00010eda, +0x00010ed8, +0x00010ed7, +0x00010ed6, +0x00010ed5, +0x00010ed4, +0x00010ed2, +0x00010ed1, +0x00010ed0, +0x00010ecf, +0x00010ece, +0x00010ecd, +0x00010ecc, +0x00010ecb, +0x00010eca, +0x00010ec9, +0x00010ec8, +0x00010ec7, +0x00010ec5, +0x00010ec4, +0x00010ec3, +0x00010ec2, +0x00010ec0, +0x00010ebf, +0x00010ebe, +0x00010ebd, +0x00010ebc, +0x00010ebb, +0x00010eba, +0x00010eb9, +0x00010eb8, +0x00010eb7, +0x00010eb6, +0x00010eb5, +0x00010eb4, +0x00010eb2, +0x00010eb1, +0x00010eb0, +0x00010eae, +0x00010ead, +0x00010eac, +0x00010eab, +0x00010eaa, +0x00010ea9, +0x00010ea8, +0x00010ea7, +0x00010ea6, +0x00010ea5, +0x00010ea4, +0x00010ea3, +0x00010ea2, +0x00010ea1, +0x00010e9f, +0x00010e9e, +0x00010e9c, +0x00010e9b, +0x00010e9a, +0x00010e99, +0x00010e98, +0x00010e97, +0x00010e96, +0x00010e95, +0x00010e94, +0x00010e93, +0x00010e92, +0x00010e91, +0x00010e90, +0x00010e8f, +0x00010e8e, +0x00010e8c, +0x00010e8a, +0x00010e89, +0x00010e88, +0x00010e88, +0x00010e86, +0x00010e85, +0x00010e84, +0x00010e83, +0x00010e82, +0x00010e81, +0x00010e80, +0x00010e7f, +0x00010e7e, +0x00010e7c, +0x00010e7b, +0x00010e7a, +0x00010e79, +0x00010e78, +0x00010e77, +0x00010e76, +0x00010e75, +0x00010e74, +0x00010e72, +0x00010e71, +0x00010e70, +0x00010e6f, +0x00010e6e, +0x00010e6d, +0x00010e6c, +0x00010e6b, +0x00010e69, +0x00010e68, +0x00010e67, +0x00010e66, +0x00010e65, +0x00010e64, +0x00010e63, +0x00010e62, +0x00010e61, +0x00010e60, +0x00010e5e, +0x00010e5d, +0x00010e5c, +0x00010e5b, +0x00010e5a, +0x00010e59, +0x00010e58, +0x00010e56, +0x00010e55, +0x00010e54, +0x00010e53, +0x00010e52, +0x00010e51, +0x00010e50, +0x00010e4f, +0x00010e4e, +0x00010e4d, +0x00010e4c, +0x00010e4a, +0x00010e49, +0x00010e48, +0x00010e47, +0x00010e46, +0x00010e45, +0x00010e44, +0x00010e42, +0x00010e41, +0x00010e40, +0x00010e3f, +0x00010e3e, +0x00010e3d, +0x00010e3c, +0x00010e3b, +0x00010e3a, +0x00010e39, +0x00010e38, +0x00010e37, +0x00010e35, +0x00010e34, +0x00010e33, +0x00010e32, +0x00010e31, +0x00010e2f, +0x00010e2e, +0x00010e2d, +0x00010e2c, +0x00010e2b, +0x00010e2a, +0x00010e29, +0x00010e28, +0x00010e27, +0x00010e26, +0x00010e25, +0x00010e24, +0x00010e23, +0x00010e21, +0x00010e20, +0x00010e1f, +0x00010e1e, +0x00010e1c, +0x00010e1b, +0x00010e1a, +0x00010e19, +0x00010e18, +0x00010e17, +0x00010e16, +0x00010e15, +0x00010e14, +0x00010e13, +0x00010e12, +0x00010e11, +0x00010e10, +0x00010e0f, +0x00010e0d, +0x00010e0c, +0x00010e0b, +0x00010e09, +0x00010e08, +0x00010e07, +0x00010e06, +0x00010e05, +0x00010e04, +0x00010e03, +0x00010e02, +0x00010e01, +0x00010e00, +0x00010dff, +0x00010dfe, +0x00010dfd, +0x00010dfc, +0x00010dfb, +0x00010dfa, +0x00010df8, +0x00010df7, +0x00010df5, +0x00010df4, +0x00010df3, +0x00010df2, +0x00010df1, +0x00010df0, +0x00010def, +0x00010dee, +0x00010ded, +0x00010dec, +0x00010deb, +0x00010dea, +0x00010de9, +0x00010de8, +0x00010de7, +0x00010de6, +0x00010de4, +0x00010de2, +0x00010de1, +0x00010de0, +0x00010ddf, +0x00010dde, +0x00010ddd, +0x00010ddc, +0x00010ddb, +0x00010dda, +0x00010dd9, +0x00010dd8, +0x00010dd7, +0x00010dd6, +0x00010dd5, +0x00010dd4, +0x00010dd3, +0x00010dd2, +0x00010dcf, +0x00010dce, +0x00010dcd, +0x00010dcc, +0x00010dcb, +0x00010dca, +0x00010dc9, +0x00010dc8, +0x00010dc7, +0x00010dc6, +0x00010dc5, +0x00010dc4, +0x00010dc3, +0x00010dc2, +0x00010dc1, +0x00010dc0, +0x00010dbf, +0x00010dbe, +0x00010dbb, +0x00010dba, +0x00010db9, +0x00010db8, +0x00010db7, +0x00010db6, +0x00010db5, +0x00010db4, +0x00010db3, +0x00010db2, +0x00010db1, +0x00010db0, +0x00010daf, +0x00010dae, +0x00010dad, +0x00010dac, +0x00010dab, +0x00010daa, +0x00010da8, +0x00010da6, +0x00010da5, +0x00010da4, +0x00010da3, +0x00010da2, +0x00010da1, +0x00010da0, +0x00010d9f, +0x00010d9e, +0x00010d9d, +0x00010d9c, +0x00010d9b, +0x00010d9a, +0x00010d99, +0x00010d98, +0x00010d97, +0x00010d95, +0x00010d94, +0x00010d92, +0x00010d91, +0x00010d90, +0x00010d8f, +0x00010d8e, +0x00010d8d, +0x00010d8c, +0x00010d8b, +0x00010d8a, +0x00010d89, +0x00010d88, +0x00010d87, +0x00010d86, +0x00010d85, +0x00010d84, +0x00010d82, +0x00010d81, +0x00010d80, +0x00010d7e, +0x00010d7d, +0x00010d7c, +0x00010d7b, +0x00010d7a, +0x00010d79, +0x00010d78, +0x00010d77, +0x00010d76, +0x00010d75, +0x00010d74, +0x00010d73, +0x00010d72, +0x00010d71, +0x00010d70, +0x00010d6e, +0x00010d6d, +0x00010d6c, +0x00010d6b, +0x00010d6a, +0x00010d69, +0x00010d68, +0x00010d67, +0x00010d65, +0x00010d64, +0x00010d63, +0x00010d62, +0x00010d61, +0x00010d60, +0x00010d5f, +0x00010d5e, +0x00010d5c, +0x00010d5b, +0x00010d5a, +0x00010d59, +0x00010d58, +0x00010d57, +0x00010d56, +0x00010d55, +0x00010d54, +0x00010d53, +0x00010d52, +0x00010d51, +0x00010d4f, +0x00010d4e, +0x00010d4d, +0x00010d4c, +0x00010d4b, +0x00010d4a, +0x00010d49, +0x00010d47, +0x00010d46, +0x00010d45, +0x00010d44, +0x00010d43, +0x00010d42, +0x00010d41, +0x00010d40, +0x00010d3f, +0x00010d3e, +0x00010d3d, +0x00010d3c, +0x00010d3b, +0x00010d39, +0x00010d38, +0x00010d37, +0x00010d36, +0x00010d35, +0x00010d33, +0x00010d32, +0x00010d31, +0x00010d30, +0x00010d2f, +0x00010d2e, +0x00010d2d, +0x00010d2c, +0x00010d2b, +0x00010d2a, +0x00010d29, +0x00010d28, +0x00010d27, +0x00010d26, +0x00010d25, +0x00010d23, +0x00010d22, +0x00010d21, +0x00010d20, +0x00010d1e, +0x00010d1d, +0x00010d1c, +0x00010d1b, +0x00010d1a, +0x00010d19, +0x00010d18, +0x00010d17, +0x00010d16, +0x00010d15, +0x00010d14, +0x00010d13, +0x00010d12, +0x00010d11, +0x00010d10, +0x00010d0e, +0x00010d0d, +0x00010d0c, +0x00010d0b, +0x00010d09, +0x00010d08, +0x00010d07, +0x00010d06, +0x00010d05, +0x00010d04, +0x00010d03, +0x00010d02, +0x00010d01, +0x00010d00, +0x00010cff, +0x00010cfe, +0x00010cfd, +0x00010cfc, +0x00010cfb, +0x00010cfa, +0x00010cf8, +0x00010cf7, +0x00010cf5, +0x00010cf4, +0x00010cf3, +0x00010cf2, +0x00010cf1, +0x00010cf0, +0x00010cef, +0x00010cee, +0x00010ced, +0x00010cec, +0x00010ceb, +0x00010cea, +0x00010ce9, +0x00010ce8, +0x00010ce7, +0x00010ce6, +0x00010ce5, +0x00010ce4, +0x00010ce2, +0x00010ce0, +0x00010cdf, +0x00010cde, +0x00010cdd, +0x00010cdc, +0x00010cdb, +0x00010cda, +0x00010cd9, +0x00010cd8, +0x00010cd7, +0x00010cd6, +0x00010cd5, +0x00010cd4, +0x00010cd3, +0x00010cd2, +0x00010cd1, +0x00010cd0, +0x00010ccf, +0x00010ccd, +0x00010ccb, +0x00010cca, +0x00010cc9, +0x00010cc8, +0x00010cc7, +0x00010cc6, +0x00010cc5, +0x00010cc4, +0x00010cc3, +0x00010cc2, +0x00010cc1, +0x00010cc0, +0x00010cbf, +0x00010cbe, +0x00010cbd, +0x00010cbc, +0x00010cbb, +0x00010cba, +0x00010cb9, +0x00010cb6, +0x00010cb5, +0x00010cb4, +0x00010cb3, +0x00010cb2, +0x00010cb1, +0x00010cb0, +0x00010caf, +0x00010cae, +0x00010cad, +0x00010cac, +0x00010cab, +0x00010caa, +0x00010ca9, +0x00010ca8, +0x00010ca7, +0x00010ca6, +0x00010ca5, +0x00010ca4, +0x00010ca2, +0x00010ca0, +0x00010c9f, +0x00010c9e, +0x00010c9d, +0x00010c9c, +0x00010c9b, +0x00010c9a, +0x00010c99, +0x00010c98, +0x00010c97, +0x00010c96, +0x00010c95, +0x00010c94, +0x00010c93, +0x00010c92, +0x00010c91, +0x00010c90, +0x00010c8f, +0x00010c8d, +0x00010c8b, +0x00010c8a, +0x00010c89, +0x00010c88, +0x00010c87, +0x00010c86, +0x00010c85, +0x00010c84, +0x00010c83, +0x00010c82, +0x00010c81, +0x00010c80, +0x00010c7f, +0x00010c7e, +0x00010c7d, +0x00010c7c, +0x00010c7b, +0x00010c7a, +0x00010c78, +0x00010c77, +0x00010c75, +0x00010c74, +0x00010c73, +0x00010c72, +0x00010c71, +0x00010c70, +0x00010c6f, +0x00010c6e, +0x00010c6d, +0x00010c6c, +0x00010c6b, +0x00010c6a, +0x00010c69, +0x00010c68, +0x00010c67, +0x00010c66, +0x00010c64, +0x00010c63, +0x00010c62, +0x00010c61, +0x00010c5f, +0x00010c5e, +0x00010c5d, +0x00010c5c, +0x00010c5b, +0x00010c5a, +0x00010c59, +0x00010c58, +0x00010c57, +0x00010c56, +0x00010c55, +0x00010c54, +0x00010c53, +0x00010c52, +0x00010c51, +0x00010c50, +0x00010c4f, +0x00010c4d, +0x00010c4c, +0x00010c4b, +0x00010c4a, +0x00010c49, +0x00010c48, +0x00010c47, +0x00010c46, +0x00010c44, +0x00010c43, +0x00010c42, +0x00010c41, +0x00010c40, +0x00010c3f, +0x00010c3e, +0x00010c3d, +0x00010c3c, +0x00010c3b, +0x00010c3a, +0x00010c39, +0x00010c37, +0x00010c36, +0x00010c35, +0x00010c34, +0x00010c33, +0x00010c32, +0x00010c31, +0x00010c30, +0x00010c2f, +0x00010c2e, +0x00010c2c, +0x00010c2b, +0x00010c2a, +0x00010c29, +0x00010c28, +0x00010c27, +0x00010c26, +0x00010c25, +0x00010c24, +0x00010c23, +0x00010c22, +0x00010c20, +0x00010c1f, +0x00010c1e, +0x00010c1d, +0x00010c1c, +0x00010c1b, +0x00010c1a, +0x00010c19, +0x00010c18, +0x00010c17, +0x00010c15, +0x00010c14, +0x00010c13, +0x00010c12, +0x00010c11, +0x00010c10, +0x00010c0f, +0x00010c0e, +0x00010c0d, +0x00010c0c, +0x00010c0a, +0x00010c09, +0x00010c08, +0x00010c07, +0x00010c06, +0x00010c05, +0x00010c04, +0x00010c03, +0x00010c02, +0x00010c01, +0x00010c00, +0x00010bfe, +0x00010bfd, +0x00010bfc, +0x00010bfb, +0x00010bfa, +0x00010bf9, +0x00010bf8, +0x00010bf7, +0x00010bf6, +0x00010bf4, +0x00010bf3, +0x00010bf2, +0x00010bf1, +0x00010bf0, +0x00010bef, +0x00010bee, +0x00010bed, +0x00010bec, +0x00010beb, +0x00010bea, +0x00010be9, +0x00010be8, +0x00010be6, +0x00010be5, +0x00010be4, +0x00010be3, +0x00010be2, +0x00010be1, +0x00010be0, +0x00010bdf, +0x00010bdd, +0x00010bdc, +0x00010bdb, +0x00010bda, +0x00010bd9, +0x00010bd8, +0x00010bd7, +0x00010bd6, +0x00010bd5, +0x00010bd4, +0x00010bd3, +0x00010bd2, +0x00010bd1, +0x00010bcf, +0x00010bce, +0x00010bcd, +0x00010bcc, +0x00010bcb, +0x00010bca, +0x00010bc9, +0x00010bc7, +0x00010bc6, +0x00010bc5, +0x00010bc4, +0x00010bc3, +0x00010bc2, +0x00010bc1, +0x00010bc0, +0x00010bbf, +0x00010bbd, +0x00010bbc, +0x00010bbb, +0x00010bba, +0x00010bb9, +0x00010bb8, +0x00010bb7, +0x00010bb5, +0x00010bb4, +0x00010bb3, +0x00010bb2, +0x00010bb1, +0x00010bb0, +0x00010baf, +0x00010bae, +0x00010bad, +0x00010bac, +0x00010bab, +0x00010baa, +0x00010ba9, +0x00010ba8, +0x00010ba7, +0x00010ba6, +0x00010ba5, +0x00010ba3, +0x00010ba2, +0x00010ba1, +0x00010ba0, +0x00010b9f, +0x00010b9d, +0x00010b9c, +0x00010b9b, +0x00010b9a, +0x00010b99, +0x00010b98, +0x00010b97, +0x00010b96, +0x00010b95, +0x00010b94, +0x00010b93, +0x00010b92, +0x00010b91, +0x00010b90, +0x00010b8f, +0x00010b8e, +0x00010b8d, +0x00010b8c, +0x00010b8a, +0x00010b89, +0x00010b88, +0x00010b87, +0x00010b86, +0x00010b84, +0x00010b83, +0x00010b82, +0x00010b81, +0x00010b80, +0x00010b7f, +0x00010b7e, +0x00010b7d, +0x00010b7c, +0x00010b7b, +0x00010b7a, +0x00010b79, +0x00010b78, +0x00010b77, +0x00010b76, +0x00010b75, +0x00010b74, +0x00010b73, +0x00010b71, +0x00010b70, +0x00010b6f, +0x00010b6e, +0x00010b6c, +0x00010b6b, +0x00010b6a, +0x00010b69, +0x00010b68, +0x00010b67, +0x00010b66, +0x00010b65, +0x00010b64, +0x00010b63, +0x00010b62, +0x00010b61, +0x00010b60, +0x00010b5f, +0x00010b5e, +0x00010b5d, +0x00010b5c, +0x00010b5b, +0x00010b5a, +0x00010b58, +0x00010b57, +0x00010b56, +0x00010b54, +0x00010b53, +0x00010b52, +0x00010b51, +0x00010b50, +0x00010b4f, +0x00010b4e, +0x00010b4d, +0x00010b4c, +0x00010b4b, +0x00010b4a, +0x00010b49, +0x00010b48, +0x00010b47, +0x00010b46, +0x00010b45, +0x00010b44, +0x00010b43, +0x00010b42, +0x00010b41, +0x00010b40, +0x00010b3e, +0x00010b3c, +0x00010b3b, +0x00010b3a, +0x00010b39, +0x00010b38, +0x00010b37, +0x00010b36, +0x00010b35, +0x00010b34, +0x00010b33, +0x00010b32, +0x00010b31, +0x00010b30, +0x00010b2f, +0x00010b2e, +0x00010b2d, +0x00010b2c, +0x00010b2b, +0x00010b2a, +0x00010b29, +0x00010b28, +0x00010b27, +0x00010b25, +0x00010b23, +0x00010b22, +0x00010b21, +0x00010b20, +0x00010b1f, +0x00010b1e, +0x00010b1d, +0x00010b1c, +0x00010b1b, +0x00010b1a, +0x00010b19, +0x00010b18, +0x00010b17, +0x00010b16, +0x00010b15, +0x00010b14, +0x00010b13, +0x00010b12, +0x00010b11, +0x00010b10, +0x00010b0f, +0x00010b0e, +0x00010b0b, +0x00010b0a, +0x00010b09, +0x00010b08, +0x00010b07, +0x00010b06, +0x00010b05, +0x00010b04, +0x00010b03, +0x00010b02, +0x00010b01, +0x00010b00, +0x00010aff, +0x00010afe, +0x00010afd, +0x00010afc, +0x00010afb, +0x00010afa, +0x00010af9, +0x00010af8, +0x00010af7, +0x00010af6, +0x00010af5, +0x00010af3, +0x00010af1, +0x00010af0, +0x00010aef, +0x00010aee, +0x00010aed, +0x00010aec, +0x00010aeb, +0x00010aea, +0x00010ae9, +0x00010ae8, +0x00010ae7, +0x00010ae6, +0x00010ae5, +0x00010ae4, +0x00010ae3, +0x00010ae2, +0x00010ae1, +0x00010ae0, +0x00010adf, +0x00010ade, +0x00010add, +0x00010adb, +0x00010ada, +0x00010ad8, +0x00010ad7, +0x00010ad6, +0x00010ad5, +0x00010ad4, +0x00010ad3, +0x00010ad2, +0x00010ad1, +0x00010ad0, +0x00010acf, +0x00010ace, +0x00010acd, +0x00010acc, +0x00010acb, +0x00010aca, +0x00010ac9, +0x00010ac8, +0x00010ac7, +0x00010ac6, +0x00010ac5, +0x00010ac4, +0x00010ac2, +0x00010ac1, +0x00010abf, +0x00010abe, +0x00010abd, +0x00010abc, +0x00010abb, +0x00010aba, +0x00010ab9, +0x00010ab8, +0x00010ab7, +0x00010ab6, +0x00010ab5, +0x00010ab4, +0x00010ab3, +0x00010ab2, +0x00010ab1, +0x00010ab0, +0x00010aaf, +0x00010aae, +0x00010aab, +0x00010aaa, +0x00010aa9, +0x00010aa8, +0x00010aa7, +0x00010aa6, +0x00010aa5, +0x00010aa4, +0x00010aa3, +0x00010aa2, +0x00010aa1, +0x00010aa0, +0x00010a9f, +0x00010a9e, +0x00010a9d, +0x00010a9c, +0x00010a9b, +0x00010a9a, +0x00010a99, +0x00010a98, +0x00010a97, +0x00010a96, +0x00010a95, +0x00010a94, +0x00010a93, +0x00010a90, +0x00010a8f, +0x00010a8e, +0x00010a8d, +0x00010a8c, +0x00010a8b, +0x00010a8a, +0x00010a89, +0x00010a88, +0x00010a87, +0x00010a86, +0x00010a85, +0x00010a84, +0x00010a83, +0x00010a82, +0x00010a81, +0x00010a80, +0x00010a7f, +0x00010a7e, +0x00010a7d, +0x00010a7c, +0x00010a7b, +0x00010a7a, +0x00010a79, +0x00010a77, +0x00010a76, +0x00010a74, +0x00010a73, +0x00010a72, +0x00010a71, +0x00010a70, +0x00010a6f, +0x00010a6e, +0x00010a6d, +0x00010a6c, +0x00010a6b, +0x00010a6a, +0x00010a69, +0x00010a68, +0x00010a67, +0x00010a66, +0x00010a65, +0x00010a64, +0x00010a63, +0x00010a62, +0x00010a61, +0x00010a60, +0x00010a5f, +0x00010a5e, +0x00010a5c, +0x00010a5b, +0x00010a59, +0x00010a58, +0x00010a57, +0x00010a56, +0x00010a55, +0x00010a54, +0x00010a53, +0x00010a52, +0x00010a51, +0x00010a50, +0x00010a4f, +0x00010a4e, +0x00010a4d, +0x00010a4c, +0x00010a4b, +0x00010a4a, +0x00010a49, +0x00010a48, +0x00010a47, +0x00010a46, +0x00010a45, +0x00010a44, +0x00010a43, +0x00010a41, +0x00010a40, +0x00010a3f, +0x00010a3d, +0x00010a3c, +0x00010a3b, +0x00010a3a, +0x00010a39, +0x00010a38, +0x00010a37, +0x00010a36, +0x00010a35, +0x00010a34, +0x00010a33, +0x00010a32, +0x00010a31, +0x00010a30, +0x00010a2f, +0x00010a2e, +0x00010a2d, +0x00010a2c, +0x00010a2b, +0x00010a2a, +0x00010a29, +0x00010a27, +0x00010a26, +0x00010a25, +0x00010a24, +0x00010a23, +0x00010a21, +0x00010a20, +0x00010a1f, +0x00010a1e, +0x00010a1d, +0x00010a1c, +0x00010a1b, +0x00010a1a, +0x00010a19, +0x00010a18, +0x00010a17, +0x00010a16, +0x00010a15, +0x00010a14, +0x00010a13, +0x00010a12, +0x00010a11, +0x00010a10, +0x00010a0f, +0x00010a0e, +0x00010a0c, +0x00010a0b, +0x00010a0a, +0x00010a09, +0x00010a08, +0x00010a06, +0x00010a05, +0x00010a04, +0x00010a03, +0x00010a02, +0x00010a01, +0x00010a00, +0x000109ff, +0x000109fe, +0x000109fd, +0x000109fc, +0x000109fb, +0x000109fa, +0x000109f9, +0x000109f8, +0x000109f7, +0x000109f6, +0x000109f5, +0x000109f4, +0x000109f2, +0x000109f1, +0x000109f0, +0x000109ef, +0x000109ee, +0x000109ed, +0x000109ec, +0x000109ea, +0x000109e9, +0x000109e8, +0x000109e7, +0x000109e6, +0x000109e5, +0x000109e4, +0x000109e3, +0x000109e2, +0x000109e1, +0x000109e0, +0x000109df, +0x000109de, +0x000109dd, +0x000109dc, +0x000109db, +0x000109da, +0x000109d9, +0x000109d7, +0x000109d6, +0x000109d5, +0x000109d4, +0x000109d3, +0x000109d2, +0x000109d1, +0x000109cf, +0x000109ce, +0x000109cd, +0x000109cc, +0x000109cb, +0x000109ca, +0x000109c9, +0x000109c8, +0x000109c7, +0x000109c6, +0x000109c5, +0x000109c4, +0x000109c3, +0x000109c2, +0x000109c1, +0x000109c0, +0x000109bf, +0x000109be, +0x000109bc, +0x000109bb, +0x000109ba, +0x000109b9, +0x000109b8, +0x000109b7, +0x000109b6, +0x000109b5, +0x000109b3, +0x000109b2, +0x000109b1, +0x000109b0, +0x000109af, +0x000109ae, +0x000109ad, +0x000109ac, +0x000109ab, +0x000109aa, +0x000109a9, +0x000109a8, +0x000109a7, +0x000109a6, +0x000109a5, +0x000109a4, +0x000109a2, +0x000109a1, +0x000109a0, +0x0001099f, +0x0001099e, +0x0001099d, +0x0001099c, +0x0001099b, +0x0001099a, +0x00010998, +0x00010997, +0x00010996, +0x00010995, +0x00010994, +0x00010993, +0x00010992, +0x00010991, +0x00010990, +0x0001098f, +0x0001098e, +0x0001098d, +0x0001098c, +0x0001098b, +0x0001098a, +0x00010989, +0x00010988, +0x00010987, +0x00010986, +0x00010985, +0x00010983, +0x00010982, +0x00010980, +0x0001097f, +0x0001097e, +0x0001097d, +0x0001097c, +0x0001097b, +0x0001097a, +0x00010979, +0x00010978, +0x00010977, +0x00010976, +0x00010975, +0x00010974, +0x00010973, +0x00010972, +0x00010971, +0x00010970, +0x0001096f, +0x0001096e, +0x0001096d, +0x0001096c, +0x0001096b, +0x0001096a, +0x00010969, +0x00010968, +0x00010966, +0x00010965, +0x00010964, +0x00010962, +0x00010961, +0x00010960, +0x0001095f, +0x0001095e, +0x0001095d, +0x0001095c, +0x0001095b, +0x0001095a, +0x00010959, +0x00010958, +0x00010957, +0x00010956, +0x00010955, +0x00010954, +0x00010953, +0x00010952, +0x00010951, +0x00010950, +0x0001094f, +0x0001094e, +0x0001094d, +0x0001094c, +0x0001094b, +0x00010949, +0x00010948, +0x00010947, +0x00010946, +0x00010945, +0x00010943, +0x00010942, +0x00010941, +0x00010940, +0x0001093f, +0x0001093e, +0x0001093d, +0x0001093c, +0x0001093b, +0x0001093a, +0x00010939, +0x00010938, +0x00010937, +0x00010936, +0x00010935, +0x00010934, +0x00010933, +0x00010932, +0x00010931, +0x00010930, +0x0001092f, +0x0001092e, +0x0001092d, +0x0001092b, +0x0001092a, +0x00010929, +0x00010928, +0x00010927, +0x00010925, +0x00010924, +0x00010923, +0x00010922, +0x00010921, +0x00010920, +0x0001091f, +0x0001091e, +0x0001091d, +0x0001091c, +0x0001091b, +0x0001091a, +0x00010919, +0x00010918, +0x00010917, +0x00010916, +0x00010915, +0x00010914, +0x00010913, +0x00010912, +0x00010911, +0x00010910, +0x0001090e, +0x0001090d, +0x0001090c, +0x0001090b, +0x0001090a, +0x00010909, +0x00010908, +0x00010906, +0x00010905, +0x00010904, +0x00010903, +0x00010902, +0x00010901, +0x00010900, +0x000108ff, +0x000108fe, +0x000108fd, +0x000108fc, +0x000108fb, +0x000108fa, +0x000108f9, +0x000108f8, +0x000108f7, +0x000108f6, +0x000108f5, +0x000108f4, +0x000108f3, +0x000108f2, +0x000108f0, +0x000108ef, +0x000108ee, +0x000108ed, +0x000108ec, +0x000108eb, +0x000108ea, +0x000108e8, +0x000108e7, +0x000108e6, +0x000108e5, +0x000108e4, +0x000108e3, +0x000108e2, +0x000108e1, +0x000108e0, +0x000108df, +0x000108de, +0x000108dd, +0x000108dc, +0x000108db, +0x000108da, +0x000108d9, +0x000108d8, +0x000108d7, +0x000108d6, +0x000108d5, +0x000108d3, +0x000108d2, +0x000108d1, +0x000108d0, +0x000108cf, +0x000108ce, +0x000108cd, +0x000108cc, +0x000108cb, +0x000108c9, +0x000108c8, +0x000108c7, +0x000108c6, +0x000108c5, +0x000108c4, +0x000108c3, +0x000108c2, +0x000108c1, +0x000108c0, +0x000108bf, +0x000108be, +0x000108bd, +0x000108bc, +0x000108bb, +0x000108ba, +0x000108b9, +0x000108b8, +0x000108b7, +0x000108b5, +0x000108b4, +0x000108b3, +0x000108b2, +0x000108b1, +0x000108b0, +0x000108af, +0x000108ae, +0x000108ad, +0x000108ab, +0x000108aa, +0x000108a9, +0x000108a8, +0x000108a7, +0x000108a6, +0x000108a5, +0x000108a4, +0x000108a3, +0x000108a2, +0x000108a1, +0x000108a0, +0x0001089f, +0x0001089e, +0x0001089d, +0x0001089c, +0x0001089b, +0x0001089a, +0x00010898, +0x00010897, +0x00010896, +0x00010895, +0x00010894, +0x00010893, +0x00010892, +0x00010891, +0x00010890, +0x0001088f, +0x0001088d, +0x0001088c, +0x0001088b, +0x0001088a, +0x00010889, +0x00010888, +0x00010887, +0x00010886, +0x00010885, +0x00010884, +0x00010883, +0x00010882, +0x00010881, +0x00010880, +0x0001087f, +0x0001087e, +0x0001087d, +0x0001087c, +0x0001087b, +0x0001087a, +0x00010879, +0x00010878, +0x00010877, +0x00010876, +0x00010874, +0x00010872, +0x00010871, +0x00010870, +0x0001086f, +0x0001086e, +0x0001086d, +0x0001086c, +0x0001086b, +0x0001086a, +0x00010869, +0x00010868, +0x00010867, +0x00010866, +0x00010865, +0x00010864, +0x00010863, +0x00010862, +0x00010861, +0x00010860, +0x0001085f, +0x0001085e, +0x0001085d, +0x0001085c, +0x0001085b, +0x0001085a, +0x00010859, +0x00010858, +0x00010857, +0x00010856, +0x00010855, +0x00010854, +0x00010851, +0x00010850, +0x0001084f, +0x0001084e, +0x0001084d, +0x0001084c, +0x0001084b, +0x0001084a, +0x00010849, +0x00010848, +0x00010847, +0x00010846, +0x00010845, +0x00010844, +0x00010843, +0x00010842, +0x00010841, +0x00010840, +0x0001083f, +0x0001083e, +0x0001083d, +0x0001083c, +0x0001083b, +0x0001083a, +0x00010839, +0x00010838, +0x00010837, +0x00010836, +0x00010835, +0x00010834, +0x00010833, +0x00010832, +0x0001082f, +0x0001082e, +0x0001082d, +0x0001082c, +0x0001082b, +0x0001082a, +0x00010829, +0x00010828, +0x00010827, +0x00010826, +0x00010825, +0x00010824, +0x00010823, +0x00010822, +0x00010821, +0x00010820, +0x0001081f, +0x0001081e, +0x0001081d, +0x0001081c, +0x0001081b, +0x0001081a, +0x00010819, +0x00010818, +0x00010817, +0x00010816, +0x00010815, +0x00010814, +0x00010813, +0x00010812, +0x00010811, +0x0001080f, +0x0001080d, +0x0001080c, +0x0001080b, +0x0001080a, +0x00010809, +0x00010808, +0x00010807, +0x00010806, +0x00010805, +0x00010804, +0x00010803, +0x00010802, +0x00010801, +0x00010800, +0x000107ff, +0x000107fe, +0x000107fd, +0x000107fc, +0x000107fb, +0x000107fa, +0x000107f9, +0x000107f8, +0x000107f7, +0x000107f6, +0x000107f5, +0x000107f4, +0x000107f3, +0x000107f2, +0x000107f1, +0x000107f0, +0x000107ee, +0x000107ed, +0x000107eb, +0x000107ea, +0x000107e9, +0x000107e8, +0x000107e7, +0x000107e6, +0x000107e5, +0x000107e4, +0x000107e3, +0x000107e2, +0x000107e1, +0x000107e0, +0x000107df, +0x000107de, +0x000107dd, +0x000107dc, +0x000107db, +0x000107da, +0x000107d9, +0x000107d8, +0x000107d7, +0x000107d6, +0x000107d5, +0x000107d4, +0x000107d3, +0x000107d2, +0x000107d1, +0x000107d0, +0x000107cf, +0x000107cd, +0x000107cc, +0x000107cb, +0x000107c9, +0x000107c8, +0x000107c7, +0x000107c6, +0x000107c5, +0x000107c4, +0x000107c3, +0x000107c2, +0x000107c1, +0x000107c0, +0x000107bf, +0x000107be, +0x000107bd, +0x000107bc, +0x000107bb, +0x000107ba, +0x000107b9, +0x000107b8, +0x000107b7, +0x000107b6, +0x000107b5, +0x000107b4, +0x000107b3, +0x000107b2, +0x000107b1, +0x000107b0, +0x000107af, +0x000107ae, +0x000107ac, +0x000107ab, +0x000107aa, +0x000107a9, +0x000107a7, +0x000107a6, +0x000107a5, +0x000107a4, +0x000107a3, +0x000107a2, +0x000107a1, +0x000107a0, +0x0001079f, +0x0001079e, +0x0001079d, +0x0001079c, +0x0001079b, +0x0001079a, +0x00010799, +0x00010798, +0x00010797, +0x00010796, +0x00010795, +0x00010794, +0x00010793, +0x00010792, +0x00010791, +0x00010790, +0x0001078f, +0x0001078e, +0x0001078d, +0x0001078b, +0x0001078a, +0x00010789, +0x00010788, +0x00010787, +0x00010785, +0x00010784, +0x00010783, +0x00010782, +0x00010781, +0x00010780, +0x0001077f, +0x0001077e, +0x0001077d, +0x0001077c, +0x0001077b, +0x0001077a, +0x00010779, +0x00010778, +0x00010777, +0x00010776, +0x00010775, +0x00010774, +0x00010773, +0x00010772, +0x00010771, +0x00010770, +0x0001076f, +0x0001076e, +0x0001076d, +0x0001076b, +0x0001076a, +0x00010769, +0x00010768, +0x00010767, +0x00010766, +0x00010765, +0x00010764, +0x00010763, +0x00010762, +0x00010761, +0x00010760, +0x0001075f, +0x0001075d, +0x0001075c, +0x0001075b, +0x0001075a, +0x00010759, +0x00010758, +0x00010757, +0x00010756, +0x00010755, +0x00010754, +0x00010753, +0x00010752, +0x00010751, +0x00010750, +0x0001074f, +0x0001074e, +0x0001074d, +0x0001074c, +0x0001074b, +0x0001074a, +0x00010749, +0x00010748, +0x00010747, +0x00010745, +0x00010744, +0x00010743, +0x00010742, +0x00010741, +0x00010740, +0x0001073f, +0x0001073e, +0x0001073d, +0x0001073c, +0x0001073b, +0x0001073a, +0x00010739, +0x00010737, +0x00010736, +0x00010735, +0x00010734, +0x00010733, +0x00010732, +0x00010731, +0x00010730, +0x0001072f, +0x0001072e, +0x0001072d, +0x0001072c, +0x0001072b, +0x0001072a, +0x00010729, +0x00010728, +0x00010727, +0x00010726, +0x00010725, +0x00010724, +0x00010723, +0x00010722, +0x00010721, +0x00010720, +0x0001071e, +0x0001071d, +0x0001071c, +0x0001071b, +0x0001071a, +0x00010719, +0x00010718, +0x00010717, +0x00010716, +0x00010715, +0x00010714, +0x00010712, +0x00010711, +0x00010710, +0x0001070f, +0x0001070e, +0x0001070d, +0x0001070c, +0x0001070b, +0x0001070a, +0x00010709, +0x00010708, +0x00010707, +0x00010706, +0x00010705, +0x00010704, +0x00010703, +0x00010702, +0x00010701, +0x00010700, +0x000106ff, +0x000106fe, +0x000106fd, +0x000106fc, +0x000106fb, +0x000106fa, +0x000106f8, +0x000106f7, +0x000106f6, +0x000106f5, +0x000106f4, +0x000106f3, +0x000106f2, +0x000106f1, +0x000106f0, +0x000106ef, +0x000106ee, +0x000106ec, +0x000106eb, +0x000106ea, +0x000106e9, +0x000106e8, +0x000106e7, +0x000106e6, +0x000106e5, +0x000106e4, +0x000106e3, +0x000106e2, +0x000106e1, +0x000106e0, +0x000106df, +0x000106de, +0x000106dd, +0x000106dc, +0x000106db, +0x000106da, +0x000106d9, +0x000106d8, +0x000106d7, +0x000106d6, +0x000106d5, +0x000106d4, +0x000106d3, +0x000106d1, +0x000106d0, +0x000106cf, +0x000106ce, +0x000106cd, +0x000106cc, +0x000106cb, +0x000106ca, +0x000106c9, +0x000106c7, +0x000106c6, +0x000106c5, +0x000106c4, +0x000106c3, +0x000106c2, +0x000106c1, +0x000106c0, +0x000106bf, +0x000106be, +0x000106bd, +0x000106bc, +0x000106bb, +0x000106ba, +0x000106b9, +0x000106b8, +0x000106b7, +0x000106b6, +0x000106b5, +0x000106b4, +0x000106b3, +0x000106b2, +0x000106b1, +0x000106b0, +0x000106af, +0x000106ae, +0x000106ad, +0x000106ac, +0x000106aa, +0x000106a9, +0x000106a8, +0x000106a7, +0x000106a6, +0x000106a5, +0x000106a4, +0x000106a3, +0x000106a1, +0x000106a0, +0x0001069f, +0x0001069e, +0x0001069d, +0x0001069c, +0x0001069b, +0x0001069a, +0x00010699, +0x00010698, +0x00010697, +0x00010696, +0x00010695, +0x00010694, +0x00010693, +0x00010692, +0x00010691, +0x00010690, +0x0001068f, +0x0001068e, +0x0001068d, +0x0001068c, +0x0001068b, +0x0001068a, +0x00010689, +0x00010688, +0x00010687, +0x00010686, +0x00010684, +0x00010683, +0x00010682, +0x00010681, +0x00010680, +0x0001067f, +0x0001067e, +0x0001067d, +0x0001067b, +0x0001067a, +0x00010679, +0x00010678, +0x00010677, +0x00010676, +0x00010675, +0x00010674, +0x00010673, +0x00010672, +0x00010671, +0x00010670, +0x0001066f, +0x0001066e, +0x0001066d, +0x0001066c, +0x0001066b, +0x0001066a, +0x00010669, +0x00010668, +0x00010666, +0x00010665, +0x00010664, +0x00010663, +0x00010662, +0x00010661, +0x00010660, +0x0001065f, +0x0001065e, +0x0001065d, +0x0001065c, +0x0001065b, +0x0001065a, +0x00010659, +0x00010658, +0x00010657, +0x00010656, +0x00010655, +0x00010654, +0x00010653, +0x00010652, +0x00010651, +0x00010650, +0x0001064f, +0x0001064e, +0x0001064d, +0x0001064c, +0x0001064b, +0x0001064a, +0x00010649, +0x00010648, +0x00010647, +0x00010646, +0x00010645, +0x00010644, +0x00010643, +0x00010642, +0x00010640, +0x0001063f, +0x0001063e, +0x0001063d, +0x0001063c, +0x0001063a, +0x00010639, +0x00010638, +0x00010637, +0x00010636, +0x00010635, +0x00010634, +0x00010633, +0x00010632, +0x00010631, +0x00010630, +0x0001062f, +0x0001062e, +0x0001062d, +0x0001062c, +0x0001062b, +0x0001062a, +0x00010629, +0x00010628, +0x00010627, +0x00010626, +0x00010625, +0x00010624, +0x00010623, +0x00010622, +0x00010621, +0x00010620, +0x0001061f, +0x0001061e, +0x0001061d, +0x0001061c, +0x0001061b, +0x0001061a, +0x00010619, +0x00010618, +0x00010617, +0x00010615, +0x00010614, +0x00010613, +0x00010612, +0x00010611, +0x00010610, +0x0001060f, +0x0001060d, +0x0001060c, +0x0001060b, +0x0001060a, +0x00010609, +0x00010608, +0x00010607, +0x00010606, +0x00010605, +0x00010604, +0x00010603, +0x00010602, +0x00010601, +0x00010600, +0x000105ff, +0x000105fe, +0x000105fd, +0x000105fc, +0x000105fb, +0x000105fa, +0x000105f9, +0x000105f8, +0x000105f7, +0x000105f6, +0x000105f5, +0x000105f4, +0x000105f3, +0x000105f2, +0x000105f1, +0x000105f0, +0x000105ef, +0x000105ee, +0x000105ed, +0x000105ec, +0x000105eb, +0x000105e9, +0x000105e8, +0x000105e7, +0x000105e6, +0x000105e5, +0x000105e4, +0x000105e3, +0x000105e2, +0x000105e0, +0x000105df, +0x000105de, +0x000105dd, +0x000105dc, +0x000105db, +0x000105da, +0x000105d9, +0x000105d8, +0x000105d7, +0x000105d6, +0x000105d5, +0x000105d4, +0x000105d3, +0x000105d2, +0x000105d1, +0x000105d0, +0x000105cf, +0x000105ce, +0x000105cd, +0x000105cc, +0x000105cb, +0x000105ca, +0x000105c9, +0x000105c8, +0x000105c7, +0x000105c6, +0x000105c5, +0x000105c4, +0x000105c3, +0x000105c2, +0x000105c1, +0x000105c0, +0x000105bf, +0x000105bd, +0x000105bc, +0x000105bb, +0x000105ba, +0x000105b9, +0x000105b8, +0x000105b7, +0x000105b6, +0x000105b4, +0x000105b3, +0x000105b2, +0x000105b1, +0x000105b0, +0x000105af, +0x000105ae, +0x000105ad, +0x000105ac, +0x000105ab, +0x000105aa, +0x000105a9, +0x000105a8, +0x000105a7, +0x000105a6, +0x000105a5, +0x000105a4, +0x000105a3, +0x000105a2, +0x000105a1, +0x000105a0, +0x0001059f, +0x0001059e, +0x0001059d, +0x0001059c, +0x0001059b, +0x0001059a, +0x00010599, +0x00010598, +0x00010597, +0x00010596, +0x00010595, +0x00010594, +0x00010592, +0x00010591, +0x00010590, +0x0001058f, +0x0001058e, +0x0001058d, +0x0001058c, +0x0001058b, +0x0001058a, +0x00010589, +0x00010587, +0x00010586, +0x00010585, +0x00010584, +0x00010583, +0x00010582, +0x00010581, +0x00010580, +0x0001057f, +0x0001057e, +0x0001057d, +0x0001057c, +0x0001057b, +0x0001057a, +0x00010579, +0x00010578, +0x00010577, +0x00010576, +0x00010575, +0x00010574, +0x00010573, +0x00010572, +0x00010571, +0x00010570, +0x0001056f, +0x0001056e, +0x0001056d, +0x0001056c, +0x0001056b, +0x0001056a, +0x00010569, +0x00010568, +0x00010566, +0x00010565, +0x00010564, +0x00010563, +0x00010562, +0x00010561, +0x00010560, +0x0001055f, +0x0001055e, +0x0001055d, +0x0001055c, +0x0001055b, +0x0001055a, +0x00010559, +0x00010558, +0x00010557, +0x00010556, +0x00010555, +0x00010554, +0x00010553, +0x00010552, +0x00010551, +0x00010550, +0x0001054f, +0x0001054d, +0x0001054c, +0x0001054b, +0x0001054a, +0x00010549, +0x00010548, +0x00010547, +0x00010546, +0x00010545, +0x00010544, +0x00010543, +0x00010542, +0x00010541, +0x00010540, +0x0001053f, +0x0001053e, +0x0001053d, +0x0001053c, +0x0001053b, +0x0001053a, +0x00010539, +0x00010538, +0x00010537, +0x00010536, +0x00010535, +0x00010533, +0x00010532, +0x00010531, +0x00010530, +0x0001052f, +0x0001052e, +0x0001052d, +0x0001052c, +0x0001052b, +0x0001052a, +0x00010529, +0x00010528, +0x00010527, +0x00010526, +0x00010525, +0x00010524, +0x00010523, +0x00010522, +0x00010521, +0x00010520, +0x0001051f, +0x0001051e, +0x0001051d, +0x0001051c, +0x0001051b, +0x00010519, +0x00010518, +0x00010517, +0x00010516, +0x00010515, +0x00010514, +0x00010513, +0x00010512, +0x00010511, +0x00010510, +0x0001050f, +0x0001050e, +0x0001050d, +0x0001050c, +0x0001050b, +0x0001050a, +0x00010509, +0x00010508, +0x00010507, +0x00010506, +0x00010505, +0x00010504, +0x00010503, +0x00010502, +0x00010501, +0x00010500, +0x000104fe, +0x000104fd, +0x000104fc, +0x000104fb, +0x000104fa, +0x000104f9, +0x000104f8, +0x000104f7, +0x000104f6, +0x000104f5, +0x000104f4, +0x000104f3, +0x000104f2, +0x000104f1, +0x000104f0, +0x000104ef, +0x000104ee, +0x000104ed, +0x000104ec, +0x000104eb, +0x000104ea, +0x000104e9, +0x000104e8, +0x000104e7, +0x000104e5, +0x000104e4, +0x000104e3, +0x000104e2, +0x000104e1, +0x000104e0, +0x000104df, +0x000104de, +0x000104dd, +0x000104dc, +0x000104db, +0x000104da, +0x000104d9, +0x000104d8, +0x000104d7, +0x000104d6, +0x000104d5, +0x000104d4, +0x000104d3, +0x000104d2, +0x000104d1, +0x000104d0, +0x000104cf, +0x000104ce, +0x000104cd, +0x000104cc, +0x000104cb, +0x000104c9, +0x000104c8, +0x000104c7, +0x000104c6, +0x000104c5, +0x000104c4, +0x000104c3, +0x000104c2, +0x000104c1, +0x000104c0, +0x000104bf, +0x000104be, +0x000104bd, +0x000104bc, +0x000104bb, +0x000104ba, +0x000104b9, +0x000104b8, +0x000104b7, +0x000104b6, +0x000104b5, +0x000104b4, +0x000104b3, +0x000104b1, +0x000104b0, +0x000104af, +0x000104ae, +0x000104ad, +0x000104ac, +0x000104ab, +0x000104aa, +0x000104a9, +0x000104a8, +0x000104a7, +0x000104a6, +0x000104a5, +0x000104a4, +0x000104a3, +0x000104a2, +0x000104a1, +0x000104a0, +0x0001049f, +0x0001049e, +0x0001049d, +0x0001049c, +0x0001049b, +0x0001049a, +0x00010499, +0x00010498, +0x00010497, +0x00010496, +0x00010495, +0x00010493, +0x00010492, +0x00010491, +0x00010490, +0x0001048f, +0x0001048e, +0x0001048d, +0x0001048c, +0x0001048b, +0x0001048a, +0x00010489, +0x00010488, +0x00010487, +0x00010486, +0x00010485, +0x00010484, +0x00010483, +0x00010482, +0x00010481, +0x00010480, +0x0001047f, +0x0001047e, +0x0001047c, +0x0001047b, +0x0001047a, +0x00010479, +0x00010478, +0x00010477, +0x00010476, +0x00010475, +0x00010474, +0x00010473, +0x00010472, +0x00010471, +0x00010470, +0x0001046f, +0x0001046e, +0x0001046d, +0x0001046c, +0x0001046b, +0x0001046a, +0x00010469, +0x00010468, +0x00010467, +0x00010466, +0x00010465, +0x00010464, +0x00010463, +0x00010462, +0x00010461, +0x00010460, +0x0001045e, +0x0001045d, +0x0001045c, +0x0001045b, +0x0001045a, +0x00010459, +0x00010458, +0x00010457, +0x00010456, +0x00010455, +0x00010454, +0x00010453, +0x00010452, +0x00010451, +0x00010450, +0x0001044f, +0x0001044e, +0x0001044d, +0x0001044c, +0x0001044b, +0x0001044a, +0x00010449, +0x00010448, +0x00010447, +0x00010446, +0x00010445, +0x00010444, +0x00010443, +0x00010442, +0x00010441, +0x00010440, +0x0001043f, +0x0001043e, +0x0001043d, +0x0001043c, +0x0001043b, +0x0001043a, +0x00010439, +0x00010438, +0x00010437, +0x00010436, +0x00010435, +0x00010434, +0x00010433, +0x00010432, +0x00010430, +0x0001042f, +0x0001042e, +0x0001042d, +0x0001042c, +0x0001042b, +0x0001042a, +0x00010429, +0x00010428, +0x00010427, +0x00010426, +0x00010425, +0x00010424, +0x00010423, +0x00010422, +0x00010421, +0x0001041f, +0x0001041e, +0x0001041d, +0x0001041c, +0x0001041b, +0x0001041a, +0x00010419, +0x00010418, +0x00010417, +0x00010416, +0x00010415, +0x00010414, +0x00010413, +0x00010412, +0x00010411, +0x00010410, +0x0001040f, +0x0001040e, +0x0001040d, +0x0001040c, +0x0001040b, +0x0001040a, +0x00010409, +0x00010408, +0x00010407, +0x00010406, +0x00010405, +0x00010404, +0x00010403, +0x00010402, +0x00010401, +0x00010400, +0x000103ff, +0x000103fe, +0x000103fd, +0x000103fc, +0x000103fb, +0x000103fa, +0x000103f9, +0x000103f8, +0x000103f7, +0x000103f6, +0x000103f5, +0x000103f4, +0x000103f3, +0x000103f2, +0x000103f1, +0x000103f0, +0x000103ee, +0x000103ed, +0x000103ec, +0x000103eb, +0x000103ea, +0x000103e9, +0x000103e8, +0x000103e7, +0x000103e6, +0x000103e5, +0x000103e4, +0x000103e3, +0x000103e2, +0x000103e1, +0x000103e0, +0x000103de, +0x000103dd, +0x000103dc, +0x000103db, +0x000103da, +0x000103d9, +0x000103d8, +0x000103d7, +0x000103d6, +0x000103d5, +0x000103d4, +0x000103d3, +0x000103d2, +0x000103d1, +0x000103d0, +0x000103cf, +0x000103ce, +0x000103cd, +0x000103cc, +0x000103cb, +0x000103ca, +0x000103c9, +0x000103c8, +0x000103c7, +0x000103c6, +0x000103c5, +0x000103c4, +0x000103c3, +0x000103c2, +0x000103c1, +0x000103c0, +0x000103bf, +0x000103be, +0x000103bd, +0x000103bc, +0x000103bb, +0x000103ba, +0x000103b9, +0x000103b8, +0x000103b7, +0x000103b6, +0x000103b5, +0x000103b4, +0x000103b3, +0x000103b2, +0x000103b1, +0x000103b0, +0x000103af, +0x000103ae, +0x000103ac, +0x000103ab, +0x000103aa, +0x000103a9, +0x000103a8, +0x000103a7, +0x000103a6, +0x000103a5, +0x000103a4, +0x000103a3, +0x000103a2, +0x000103a1, +0x000103a0, +0x0001039f, +0x0001039d, +0x0001039c, +0x0001039b, +0x0001039a, +0x00010399, +0x00010398, +0x00010397, +0x00010396, +0x00010395, +0x00010394, +0x00010393, +0x00010392, +0x00010391, +0x00010390, +0x0001038f, +0x0001038e, +0x0001038d, +0x0001038c, +0x0001038b, +0x0001038a, +0x00010389, +0x00010388, +0x00010387, +0x00010386, +0x00010385, +0x00010384, +0x00010383, +0x00010382, +0x00010381, +0x00010380, +0x0001037f, +0x0001037e, +0x0001037d, +0x0001037c, +0x0001037b, +0x0001037a, +0x00010379, +0x00010378, +0x00010377, +0x00010376, +0x00010375, +0x00010374, +0x00010373, +0x00010372, +0x00010371, +0x00010370, +0x0001036f, +0x0001036e, +0x0001036d, +0x0001036c, +0x0001036a, +0x00010369, +0x00010368, +0x00010367, +0x00010366, +0x00010365, +0x00010364, +0x00010363, +0x00010362, +0x00010361, +0x00010360, +0x0001035f, +0x0001035e, +0x0001035c, +0x0001035b, +0x0001035a, +0x00010359, +0x00010358, +0x00010357, +0x00010356, +0x00010355, +0x00010354, +0x00010353, +0x00010352, +0x00010351, +0x00010350, +0x0001034f, +0x0001034e, +0x0001034d, +0x0001034c, +0x0001034b, +0x0001034b, +0x0001034a, +0x00010349, +0x00010348, +0x00010347, +0x00010346, +0x00010345, +0x00010344, +0x00010343, +0x00010342, +0x00010341, +0x00010340, +0x0001033f, +0x0001033e, +0x0001033d, +0x0001033c, +0x0001033b, +0x0001033a, +0x00010339, +0x00010338, +0x00010337, +0x00010336, +0x00010334, +0x00010333, +0x00010332, +0x00010331, +0x00010330, +0x0001032f, +0x0001032e, +0x0001032d, +0x0001032c, +0x0001032a, +0x00010329, +0x00010328, +0x00010327, +0x00010326, +0x00010325, +0x00010324, +0x00010323, +0x00010322, +0x00010321, +0x00010320, +0x0001031f, +0x0001031e, +0x0001031d, +0x0001031c, +0x0001031b, +0x0001031a, +0x00010319, +0x00010318, +0x00010317, +0x00010316, +0x00010315, +0x00010314, +0x00010313, +0x00010312, +0x00010311, +0x00010310, +0x0001030f, +0x0001030e, +0x0001030d, +0x0001030c, +0x0001030b, +0x0001030a, +0x00010309, +0x00010308, +0x00010307, +0x00010306, +0x00010305, +0x00010304, +0x00010303, +0x00010302, +0x00010301, +0x00010300, +0x000102ff, +0x000102fe, +0x000102fd, +0x000102fc, +0x000102fb, +0x000102fa, +0x000102f9, +0x000102f8, +0x000102f7, +0x000102f6, +0x000102f5, +0x000102f4, +0x000102f3, +0x000102f2, +0x000102f1, +0x000102f0, +0x000102ef, +0x000102ee, +0x000102ed, +0x000102ec, +0x000102eb, +0x000102ea, +0x000102e9, +0x000102e8, +0x000102e7, +0x000102e6, +0x000102e5, +0x000102e4, +0x000102e3, +0x000102e2, +0x000102e1, +0x000102e0, +0x000102df, +0x000102dd, +0x000102dc, +0x000102db, +0x000102da, +0x000102d9, +0x000102d8, +0x000102d7, +0x000102d6, +0x000102d4, +0x000102d3, +0x000102d2, +0x000102d1, +0x000102d0, +0x000102cf, +0x000102ce, +0x000102cd, +0x000102cc, +0x000102cb, +0x000102ca, +0x000102c9, +0x000102c8, +0x000102c7, +0x000102c6, +0x000102c5, +0x000102c4, +0x000102c3, +0x000102c2, +0x000102c1, +0x000102c0, +0x000102bf, +0x000102be, +0x000102bd, +0x000102bc, +0x000102bb, +0x000102ba, +0x000102b9, +0x000102b8, +0x000102b7, +0x000102b6, +0x000102b5, +0x000102b4, +0x000102b3, +0x000102b2, +0x000102b1, +0x000102b0, +0x000102af, +0x000102ae, +0x000102ad, +0x000102ac, +0x000102ab, +0x000102aa, +0x000102a9, +0x000102a8, +0x000102a7, +0x000102a6, +0x000102a5, +0x000102a4, +0x000102a3, +0x000102a2, +0x000102a1, +0x000102a0, +0x0001029f, +0x0001029e, +0x0001029d, +0x0001029c, +0x0001029b, +0x0001029a, +0x00010299, +0x00010298, +0x00010297, +0x00010296, +0x00010295, +0x00010294, +0x00010293, +0x00010292, +0x00010291, +0x00010290, +0x0001028f, +0x0001028e, +0x0001028d, +0x0001028c, +0x0001028b, +0x0001028a, +0x00010289, +0x00010288, +0x00010287, +0x00010285, +0x00010284, +0x00010283, +0x00010282, +0x00010281, +0x00010280, +0x0001027f, +0x0001027d, +0x0001027c, +0x0001027b, +0x0001027a, +0x00010279, +0x00010278, +0x00010277, +0x00010276, +0x00010275, +0x00010274, +0x00010273, +0x00010272, +0x00010271, +0x00010270, +0x0001026f, +0x0001026e, +0x0001026d, +0x0001026c, +0x0001026b, +0x0001026a, +0x00010269, +0x00010268, +0x00010267, +0x00010266, +0x00010265, +0x00010264, +0x00010263, +0x00010262, +0x00010261, +0x00010260, +0x0001025f, +0x0001025e, +0x0001025d, +0x0001025c, +0x0001025b, +0x0001025a, +0x00010259, +0x00010258, +0x00010257, +0x00010256, +0x00010255, +0x00010254, +0x00010253, +0x00010252, +0x00010251, +0x00010250, +0x0001024f, +0x0001024e, +0x0001024d, +0x0001024c, +0x0001024b, +0x0001024a, +0x00010249, +0x00010248, +0x00010247, +0x00010246, +0x00010246, +0x00010244, +0x00010243, +0x00010242, +0x00010241, +0x0001023f, +0x0001023e, +0x0001023d, +0x0001023c, +0x0001023b, +0x0001023a, +0x00010239, +0x00010238, +0x00010237, +0x00010236, +0x00010235, +0x00010234, +0x00010233, +0x00010232, +0x00010231, +0x00010230, +0x0001022f, +0x0001022e, +0x0001022d, +0x0001022c, +0x0001022b, +0x0001022a, +0x00010229, +0x00010228, +0x00010227, +0x00010226, +0x00010225, +0x00010224, +0x00010223, +0x00010222, +0x00010221, +0x00010220, +0x0001021f, +0x0001021e, +0x0001021d, +0x0001021c, +0x0001021b, +0x0001021a, +0x00010219, +0x00010218, +0x00010217, +0x00010216, +0x00010215, +0x00010214, +0x00010213, +0x00010212, +0x00010211, +0x00010210, +0x0001020f, +0x0001020e, +0x0001020d, +0x0001020c, +0x0001020b, +0x0001020a, +0x00010209, +0x00010208, +0x00010207, +0x00010206, +0x00010205, +0x00010204, +0x00010203, +0x00010202, +0x00010201, +0x00010200, +0x000101ff, +0x000101fe, +0x000101fd, +0x000101fc, +0x000101fb, +0x000101fa, +0x000101f9, +0x000101f8, +0x000101f7, +0x000101f6, +0x000101f5, +0x000101f4, +0x000101f3, +0x000101f2, +0x000101f1, +0x000101f0, +0x000101ef, +0x000101ee, +0x000101ed, +0x000101ec, +0x000101eb, +0x000101ea, +0x000101e9, +0x000101e8, +0x000101e7, +0x000101e6, +0x000101e5, +0x000101e4, +0x000101e3, +0x000101e2, +0x000101e1, +0x000101e0, +0x000101df, +0x000101de, +0x000101dd, +0x000101dc, +0x000101db, +0x000101da, +0x000101d9, +0x000101d8, +0x000101d7, +0x000101d6, +0x000101d5, +0x000101d4, +0x000101d3, +0x000101d2, +0x000101d1, +0x000101d0, +0x000101cf, +0x000101ce, +0x000101cd, +0x000101cc, +0x000101cb, +0x000101ca, +0x000101c9, +0x000101c8, +0x000101c7, +0x000101c6, +0x000101c5, +0x000101c4, +0x000101c2, +0x000101c1, +0x000101c0, +0x000101be, +0x000101bd, +0x000101bc, +0x000101bb, +0x000101ba, +0x000101b9, +0x000101b8, +0x000101b7, +0x000101b6, +0x000101b5, +0x000101b4, +0x000101b3, +0x000101b2, +0x000101b1, +0x000101b0, +0x000101af, +0x000101ae, +0x000101ad, +0x000101ac, +0x000101ab, +0x000101aa, +0x000101a9, +0x000101a8, +0x000101a7, +0x000101a6, +0x000101a5, +0x000101a4, +0x000101a3, +0x000101a2, +0x000101a1, +0x000101a0, +0x0001019f, +0x0001019e, +0x0001019d, +0x0001019c, +0x0001019b, +0x0001019a, +0x00010199, +0x00010198, +0x00010197, +0x00010196, +0x00010195, +0x00010194, +0x00010193, +0x00010192, +0x00010191, +0x00010190, +0x0001018f, +0x0001018e, +0x0001018d, +0x0001018c, +0x0001018b, +0x0001018a, +0x00010189, +0x00010188, +0x00010187, +0x00010186, +0x00010185, +0x00010184, +0x00010183, +0x00010182, +0x00010181, +0x00010180, +0x0001017f, +0x0001017e, +0x0001017d, +0x0001017c, +0x0001017b, +0x0001017a, +0x00010179, +0x00010178, +0x00010177, +0x00010176, +0x00010175, +0x00010174, +0x00010173, +0x00010172, +0x00010171, +0x00010170, +0x0001016f, +0x0001016e, +0x0001016d, +0x0001016c, +0x0001016b, +0x0001016a, +0x00010169, +0x00010168, +0x00010167, +0x00010166, +0x00010165, +0x00010164, +0x00010163, +0x00010162, +0x00010161, +0x00010160, +0x0001015f, +0x0001015e, +0x0001015d, +0x0001015c, +0x0001015b, +0x0001015a, +0x00010159, +0x00010158, +0x00010157, +0x00010156, +0x00010155, +0x00010154, +0x00010153, +0x00010152, +0x00010151, +0x00010150, +0x0001014f, +0x0001014e, +0x0001014d, +0x0001014c, +0x0001014b, +0x0001014a, +0x00010149, +0x00010148, +0x00010147, +0x00010146, +0x00010145, +0x00010144, +0x00010143, +0x00010141, +0x00010140, +0x0001013f, +0x0001013e, +0x0001013d, +0x0001013c, +0x0001013b, +0x0001013a, +0x00010139, +0x00010138, +0x00010137, +0x00010136, +0x00010135, +0x00010134, +0x00010133, +0x00010132, +0x00010131, +0x00010130, +0x0001012f, +0x0001012e, +0x0001012d, +0x0001012c, +0x0001012b, +0x0001012a, +0x00010129, +0x00010128, +0x00010127, +0x00010126, +0x00010125, +0x00010124, +0x00010123, +0x00010122, +0x00010121, +0x00010120, +0x0001011f, +0x0001011e, +0x0001011d, +0x0001011c, +0x0001011b, +0x0001011a, +0x00010119, +0x00010118, +0x00010117, +0x00010116, +0x00010115, +0x00010114, +0x00010113, +0x00010112, +0x00010111, +0x00010110, +0x0001010f, +0x0001010e, +0x0001010d, +0x0001010c, +0x0001010b, +0x0001010a, +0x00010109, +0x00010108, +0x00010107, +0x00010106, +0x00010105, +0x00010104, +0x00010103, +0x00010102, +0x00010101, +0x00010100, +0x000100ff, +0x000100fe, +0x000100fd, +0x000100fc, +0x000100fb, +0x000100fa, +0x000100f9, +0x000100f8, +0x000100f7, +0x000100f6, +0x000100f5, +0x000100f4, +0x000100f3, +0x000100f2, +0x000100f1, +0x000100f0, +0x000100ef, +0x000100ee, +0x000100ed, +0x000100ec, +0x000100eb, +0x000100ea, +0x000100e9, +0x000100e8, +0x000100e7, +0x000100e6, +0x000100e5, +0x000100e4, +0x000100e3, +0x000100e2, +0x000100e1, +0x000100e0, +0x000100df, +0x000100de, +0x000100dd, +0x000100dc, +0x000100db, +0x000100da, +0x000100d9, +0x000100d8, +0x000100d7, +0x000100d6, +0x000100d5, +0x000100d4, +0x000100d3, +0x000100d2, +0x000100d1, +0x000100d0, +0x000100cf, +0x000100ce, +0x000100cd, +0x000100cc, +0x000100cb, +0x000100ca, +0x000100c9, +0x000100c8, +0x000100c7, +0x000100c6, +0x000100c5, +0x000100c4, +0x000100c3, +0x000100c2, +0x000100c1, +0x000100c0, +0x000100bf, +0x000100be, +0x000100bd, +0x000100bc, +0x000100bb, +0x000100ba, +0x000100b9, +0x000100b8, +0x000100b7, +0x000100b6, +0x000100b5, +0x000100b4, +0x000100b3, +0x000100b2, +0x000100b1, +0x000100b0, +0x000100af, +0x000100ae, +0x000100ad, +0x000100ac, +0x000100ab, +0x000100aa, +0x000100a9, +0x000100a8, +0x000100a7, +0x000100a6, +0x000100a5, +0x000100a4, +0x000100a3, +0x000100a2, +0x000100a1, +0x000100a0, +0x0001009f, +0x0001009e, +0x0001009d, +0x0001009c, +0x0001009b, +0x0001009a, +0x00010099, +0x00010098, +0x00010097, +0x00010096, +0x00010095, +0x00010094, +0x00010093, +0x00010092, +0x00010091, +0x00010090, +0x0001008f, +0x0001008e, +0x0001008d, +0x0001008c, +0x0001008b, +0x0001008a, +0x00010089, +0x00010088, +0x00010087, +0x00010086, +0x00010085, +0x00010084, +0x00010083, +0x00010082, +0x00010081, +0x0001007e, +0x0001007d, +0x0001007c, +0x0001007b, +0x0001007a, +0x00010079, +0x00010078, +0x00010077, +0x00010076, +0x00010075, +0x00010074, +0x00010073, +0x00010072, +0x00010071, +0x00010070, +0x0001006f, +0x0001006e, +0x0001006d, +0x0001006c, +0x0001006b, +0x0001006a, +0x00010069, +0x00010068, +0x00010067, +0x00010066, +0x00010065, +0x00010064, +0x00010063, +0x00010062, +0x00010061, +0x00010060, +0x0001005f, +0x0001005e, +0x0001005d, +0x0001005c, +0x0001005b, +0x0001005a, +0x00010059, +0x00010058, +0x00010057, +0x00010056, +0x00010055, +0x00010054, +0x00010053, +0x00010052, +0x00010051, +0x00010050, +0x0001004f, +0x0001004e, +0x0001004d, +0x0001004c, +0x0001004b, +0x0001004a, +0x00010049, +0x00010048, +0x00010047, +0x00010046, +0x00010045, +0x00010044, +0x00010043, +0x00010042, +0x00010041, +0x00010040, +0x0001003f, +0x0001003e, +0x0001003d, +0x0001003c, +0x0001003b, +0x0001003a, +0x00010039, +0x00010038, +0x00010037, +0x00010036, +0x00010035, +0x00010034, +0x00010033, +0x00010032, +0x00010031, +0x00010030, +0x0001002f, +0x0001002e, +0x0001002d, +0x0001002c, +0x0001002b, +0x0001002a, +0x00010029, +0x00010028, +0x00010027, +0x00010026, +0x00010025, +0x00010024, +0x00010023, +0x00010022, +0x00010021, +0x00010020, +0x0001001f, +0x0001001e, +0x0001001d, +0x0001001c, +0x0001001b, +0x0001001a, +0x00010019, +0x00010018, +0x00010017, +0x00010016, +0x00010015, +0x00010014, +0x00010013, +0x00010012, +0x00010011, +0x00010010, +0x0001000f, +0x0001000e, +0x0001000d, +0x0001000c, +0x0001000b, +0x0001000a, +0x00010009, +0x00010008, +0x00010007, +0x00010006, +0x00010005, +0x00010004, +0x00010003, +0x00010002, +0x00010001, +0x00010000, diff --git a/psx/octoshock/psx/input/dualanalog.cpp b/psx/octoshock/psx/input/dualanalog.cpp new file mode 100644 index 0000000000..45cdbb0013 --- /dev/null +++ b/psx/octoshock/psx/input/dualanalog.cpp @@ -0,0 +1,322 @@ +#include "../psx.h" +#include "../frontio.h" +#include "dualanalog.h" + +namespace MDFN_IEN_PSX +{ + +class InputDevice_DualAnalog : public InputDevice +{ + public: + + InputDevice_DualAnalog(bool joystick_mode_); + virtual ~InputDevice_DualAnalog(); + + virtual void Power(void); + virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name); + virtual void UpdateInput(const void *data); + + // + // + // + virtual void SetDTR(bool new_dtr); + virtual bool GetDSR(void); + virtual bool Clock(bool TxD, int32 &dsr_pulse_delay); + + private: + + bool joystick_mode; + bool dtr; + + uint8 buttons[2]; + uint8 axes[2][2]; + + int32 command_phase; + uint32 bitpos; + uint8 receive_buffer; + + uint8 command; + + uint8 transmit_buffer[8]; + uint32 transmit_pos; + uint32 transmit_count; +}; + +InputDevice_DualAnalog::InputDevice_DualAnalog(bool joystick_mode_) : joystick_mode(joystick_mode_) +{ + Power(); +} + +InputDevice_DualAnalog::~InputDevice_DualAnalog() +{ + +} + +void InputDevice_DualAnalog::Power(void) +{ + dtr = 0; + + buttons[0] = buttons[1] = 0; + + command_phase = 0; + + bitpos = 0; + + receive_buffer = 0; + + command = 0; + + memset(transmit_buffer, 0, sizeof(transmit_buffer)); + + transmit_pos = 0; + transmit_count = 0; +} + +int InputDevice_DualAnalog::StateAction(StateMem* sm, int load, int data_only, const char* section_name) +{ + SFORMAT StateRegs[] = + { + SFVAR(dtr), + + SFARRAY(buttons, sizeof(buttons)), + SFARRAY(&axes[0][0], sizeof(axes)), + + SFVAR(command_phase), + SFVAR(bitpos), + SFVAR(receive_buffer), + + SFVAR(command), + + SFARRAY(transmit_buffer, sizeof(transmit_buffer)), + SFVAR(transmit_pos), + SFVAR(transmit_count), + + SFEND + }; + int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name); + + if(load) + { + if((transmit_pos + transmit_count) > sizeof(transmit_buffer)) + { + transmit_pos = 0; + transmit_count = 0; + } + } + + return(ret); +} + + +void InputDevice_DualAnalog::UpdateInput(const void *data) +{ + uint8 *d8 = (uint8 *)data; + + buttons[0] = d8[0]; + buttons[1] = d8[1]; + + for(int stick = 0; stick < 2; stick++) + { + for(int axis = 0; axis < 2; axis++) + { + const uint8* aba = &d8[2] + stick * 8 + axis * 4; + int32 tmp; + + tmp = 32768 + MDFN_de16lsb(&aba[0]) - ((int32)MDFN_de16lsb(&aba[2]) * 32768 / 32767); + tmp >>= 8; + + axes[stick][axis] = tmp; + } + } + + //printf("%d %d %d %d\n", axes[0][0], axes[0][1], axes[1][0], axes[1][1]); +} + + +void InputDevice_DualAnalog::SetDTR(bool new_dtr) +{ + if(!dtr && new_dtr) + { + command_phase = 0; + bitpos = 0; + transmit_pos = 0; + transmit_count = 0; + } + else if(dtr && !new_dtr) + { + //if(bitpos || transmit_count) + // printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + } + + dtr = new_dtr; +} + +bool InputDevice_DualAnalog::GetDSR(void) +{ + if(!dtr) + return(0); + + if(!bitpos && transmit_count) + return(1); + + return(0); +} + +bool InputDevice_DualAnalog::Clock(bool TxD, int32 &dsr_pulse_delay) +{ + bool ret = 1; + + dsr_pulse_delay = 0; + + if(!dtr) + return(1); + + if(transmit_count) + ret = (transmit_buffer[transmit_pos] >> bitpos) & 1; + + receive_buffer &= ~(1 << bitpos); + receive_buffer |= TxD << bitpos; + bitpos = (bitpos + 1) & 0x7; + + if(!bitpos) + { + //printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase); + + if(transmit_count) + { + transmit_pos++; + transmit_count--; + } + + + switch(command_phase) + { + case 0: + if(receive_buffer != 0x01) + command_phase = -1; + else + { + transmit_buffer[0] = joystick_mode ? 0x53 : 0x73; + transmit_pos = 0; + transmit_count = 1; + command_phase++; + } + break; + + case 1: + command = receive_buffer; + command_phase++; + + transmit_buffer[0] = 0x5A; + + //if(command != 0x42) + // fprintf(stderr, "Gamepad unhandled command: 0x%02x\n", command); + + if(command == 0x42) + { + transmit_buffer[1] = 0xFF ^ buttons[0]; + transmit_buffer[2] = 0xFF ^ buttons[1]; + transmit_buffer[3] = axes[0][0]; + transmit_buffer[4] = axes[0][1]; + transmit_buffer[5] = axes[1][0]; + transmit_buffer[6] = axes[1][1]; + transmit_pos = 0; + transmit_count = 7; + } + else + { + command_phase = -1; + transmit_buffer[1] = 0; + transmit_buffer[2] = 0; + transmit_pos = 0; + transmit_count = 0; + } + break; + case 2: + //if(receive_buffer) + // printf("%d: %02x\n", 7 - transmit_count, receive_buffer); + break; + } + } + + if(!bitpos && transmit_count) + dsr_pulse_delay = 0x40; //0x100; + + return(ret); +} + +InputDevice *Device_DualAnalog_Create(bool joystick_mode) +{ + return new InputDevice_DualAnalog(joystick_mode); +} + + +InputDeviceInputInfoStruct Device_DualAnalog_IDII[24] = +{ + { "select", "SELECT", 4, IDIT_BUTTON, NULL }, + { "l3", "Left Stick, Button(L3)", 18, IDIT_BUTTON, NULL }, + { "r3", "Right stick, Button(R3)", 23, IDIT_BUTTON, NULL }, + { "start", "START", 5, IDIT_BUTTON, NULL }, + { "up", "D-Pad UP ↑", 0, IDIT_BUTTON, "down" }, + { "right", "D-Pad RIGHT →", 3, IDIT_BUTTON, "left" }, + { "down", "D-Pad DOWN ↓", 1, IDIT_BUTTON, "up" }, + { "left", "D-Pad LEFT ←", 2, IDIT_BUTTON, "right" }, + + { "l2", "L2 (rear left shoulder)", 11, IDIT_BUTTON, NULL }, + { "r2", "R2 (rear right shoulder)", 13, IDIT_BUTTON, NULL }, + { "l1", "L1 (front left shoulder)", 10, IDIT_BUTTON, NULL }, + { "r1", "R1 (front right shoulder)", 12, IDIT_BUTTON, NULL }, + + { "triangle", "△ (upper)", 6, IDIT_BUTTON_CAN_RAPID, NULL }, + { "circle", "○ (right)", 9, IDIT_BUTTON_CAN_RAPID, NULL }, + { "cross", "x (lower)", 7, IDIT_BUTTON_CAN_RAPID, NULL }, + { "square", "□ (left)", 8, IDIT_BUTTON_CAN_RAPID, NULL }, + + { "rstick_right", "Right Stick RIGHT →", 22, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + { "rstick_left", "Right Stick LEFT ←", 21, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + { "rstick_down", "Right Stick DOWN ↓", 20, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + { "rstick_up", "Right Stick UP ↑", 19, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + + { "lstick_right", "Left Stick RIGHT →", 17, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + { "lstick_left", "Left Stick LEFT ←", 16, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + { "lstick_down", "Left Stick DOWN ↓", 15, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + { "lstick_up", "Left Stick UP ↑", 14, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + +}; + +// Not sure if all these buttons are named correctly! +InputDeviceInputInfoStruct Device_AnalogJoy_IDII[24] = +{ + { "select", "SELECT", 8, IDIT_BUTTON, NULL }, + { NULL, "empty", 0, IDIT_BUTTON }, + { NULL, "empty", 0, IDIT_BUTTON }, + { "start", "START", 9, IDIT_BUTTON, NULL }, + { "up", "Thumbstick UP ↑", 14, IDIT_BUTTON, "down" }, + { "right", "Thumbstick RIGHT →", 17, IDIT_BUTTON, "left" }, + { "down", "Thumbstick DOWN ↓", 15, IDIT_BUTTON, "up" }, + { "left", "Thumbstick LEFT ←", 16, IDIT_BUTTON, "right" }, + + { "l2", "Left stick, Trigger", 2, IDIT_BUTTON, NULL }, + { "r2", "Left stick, Pinky", 3, IDIT_BUTTON, NULL }, + { "l1", "Left stick, L-thumb", 0, IDIT_BUTTON, NULL }, + { "r1", "Left stick, R-thumb", 1, IDIT_BUTTON, NULL }, + + { "triangle", "Right stick, Pinky", 13, IDIT_BUTTON, NULL }, + { "circle", "Right stick, R-thumb", 11, IDIT_BUTTON, NULL }, + { "cross", "Right stick, L-thumb", 10, IDIT_BUTTON, NULL }, + { "square", "Right stick, Trigger", 12, IDIT_BUTTON, NULL }, + + { "rstick_right", "Right Stick, RIGHT →", 21, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + { "rstick_left", "Right Stick, LEFT ←", 20, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + { "rstick_down", "Right Stick, BACK ↓", 19, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + { "rstick_up", "Right Stick, FORE ↑", 18, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + + { "lstick_right", "Left Stick, RIGHT →", 7, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + { "lstick_left", "Left Stick, LEFT ←", 6, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + { "lstick_down", "Left Stick, BACK ↓", 5, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + { "lstick_up", "Left Stick, FORE ↑", 4, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + +}; + + +} diff --git a/psx/octoshock/psx/input/dualanalog.h b/psx/octoshock/psx/input/dualanalog.h new file mode 100644 index 0000000000..71bd6e7d62 --- /dev/null +++ b/psx/octoshock/psx/input/dualanalog.h @@ -0,0 +1,11 @@ +#ifndef __MDFN_PSX_INPUT_DUALANALOG_H +#define __MDFN_PSX_INPUT_DUALANALOG_H + +namespace MDFN_IEN_PSX +{ + +InputDevice *Device_DualAnalog_Create(bool joystick_mode); +extern InputDeviceInputInfoStruct Device_DualAnalog_IDII[24]; +extern InputDeviceInputInfoStruct Device_AnalogJoy_IDII[24]; +} +#endif diff --git a/psx/octoshock/psx/input/dualshock.cpp b/psx/octoshock/psx/input/dualshock.cpp new file mode 100644 index 0000000000..994227533e --- /dev/null +++ b/psx/octoshock/psx/input/dualshock.cpp @@ -0,0 +1,1102 @@ +/* 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 "../psx.h" +#include "../frontio.h" +#include "dualshock.h" + +/* + TODO: + If we ever call Update() more than once per video frame(IE 50/60Hz), we'll need to add debounce logic to the analog mode button evaluation code. +*/ + +/* Notes: + + Both DA and DS style rumblings work in both analog and digital modes. + + Regarding getting Dual Shock style rumble working, Sony is evil and/or mean. The owl tells me to burn Sony with boiling oil. + + To enable Dual Shock-style rumble, the game has to at least enter MAD MUNCHKINS MODE with command 0x43, and send the appropriate data(not the actual rumble type data per-se) + with command 0x4D. + + DualAnalog-style rumble support seems to be borked until power loss if MAD MUNCHKINS MODE is even entered once...investigate further. + + Command 0x44 in MAD MUNCHKINS MODE can turn on/off analog mode(and the light with it). + + Command 0x42 in MAD MUNCHKINS MODE will return the analog mode style gamepad data, even when analog mode is off. In combination with command 0x44, this could hypothetically + be used for using the light in the gamepad as some kind of game mechanic). + + Dual Analog-style rumble notes(some of which may apply to DS too): + Rumble appears to stop if you hold DTR active(TODO: for how long? instant?). (TODO: investigate if it's still stopped even if a memory card device number is sent. It may be, since rumble may + cause excessive current draw in combination with memory card access) + + Rumble will work even if you interrupt the communication process after you've sent the rumble data(via command 0x42). + Though if you interrupt it when you've only sent partial rumble data, dragons will eat you and I don't know(seems to have timing-dependent or random effects or something; + based on VERY ROUGH testing). +*/ + +namespace MDFN_IEN_PSX +{ + +class InputDevice_DualShock : public InputDevice +{ + public: + + InputDevice_DualShock(const std::string &arg_name); + virtual ~InputDevice_DualShock(); + + virtual void Power(void); + virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name); + + virtual void Update(const pscpu_timestamp_t timestamp); + virtual void ResetTS(void); + virtual void UpdateInput(const void *data); + + // + // + // + virtual void SetDTR(bool new_dtr); + virtual bool GetDSR(void); + virtual bool Clock(bool TxD, int32 &dsr_pulse_delay); + + private: + + void CheckManualAnaModeChange(void); + + // + // + bool cur_ana_button_state; + bool prev_ana_button_state; + int64 combo_anatoggle_counter; + // + + bool da_rumble_compat; + + bool analog_mode; + bool analog_mode_locked; + + bool mad_munchkins; + uint8 rumble_magic[6]; + + uint8 rumble_param[2]; + + bool dtr; + + uint8 buttons[2]; + uint8 axes[2][2]; + + int32 command_phase; + uint32 bitpos; + uint8 receive_buffer; + + uint8 command; + + uint8 transmit_buffer[8]; + uint32 transmit_pos; + uint32 transmit_count; + + // + // + // + bool am_prev_info; + bool aml_prev_info; + std::string gp_name; + pscpu_timestamp_t lastts; + + // + // + bool amct_enabled; +}; + +InputDevice_DualShock::InputDevice_DualShock(const std::string &name) +{ + gp_name = name; + Power(); + am_prev_info = analog_mode; + aml_prev_info = analog_mode_locked; + amct_enabled = false; +} + +InputDevice_DualShock::~InputDevice_DualShock() +{ + +} + +void InputDevice_DualShock::Update(const pscpu_timestamp_t timestamp) +{ + lastts = timestamp; +} + +void InputDevice_DualShock::ResetTS(void) +{ + //printf("%lld\n", combo_anatoggle_counter); + if(combo_anatoggle_counter >= 0) + combo_anatoggle_counter += lastts; + lastts = 0; +} + +// +// This simulates the behavior of the actual DualShock(analog toggle button evaluation is suspended while DTR is active). +// Call in Update(), and whenever dtr goes inactive in the port access code. +void InputDevice_DualShock::CheckManualAnaModeChange(void) +{ + if(!dtr) + { + bool need_mode_toggle = false; + + if(amct_enabled) + { + if(buttons[0] == 0x09 && buttons[1] == 0x0f) + { + if(combo_anatoggle_counter == -1) + combo_anatoggle_counter = 0; + else if(combo_anatoggle_counter >= (44100 * 768)) + { + need_mode_toggle = true; + combo_anatoggle_counter = -2; + } + } + else + combo_anatoggle_counter = -1; + } + else + { + combo_anatoggle_counter = -1; + if(cur_ana_button_state && (cur_ana_button_state != prev_ana_button_state)) + { + need_mode_toggle = true; + } + } + + if(need_mode_toggle) + { + if(analog_mode_locked) + { + //MDFN_DispMessage(_("%s: Analog mode is locked %s."), gp_name.c_str(), analog_mode ? _("on") : _("off")); + } + else + analog_mode = !analog_mode; + } + + prev_ana_button_state = cur_ana_button_state; // Don't move this outside of the if(!dtr) block! + } +} + +void InputDevice_DualShock::Power(void) +{ + combo_anatoggle_counter = -2; + lastts = 0; + // + // + + dtr = 0; + + buttons[0] = buttons[1] = 0; + + command_phase = 0; + + bitpos = 0; + + receive_buffer = 0; + + command = 0; + + memset(transmit_buffer, 0, sizeof(transmit_buffer)); + + transmit_pos = 0; + transmit_count = 0; + + analog_mode = false; + analog_mode_locked = false; + + mad_munchkins = false; + memset(rumble_magic, 0xFF, sizeof(rumble_magic)); + memset(rumble_param, 0, sizeof(rumble_param)); + + da_rumble_compat = true; + + prev_ana_button_state = false; +} + +int InputDevice_DualShock::StateAction(StateMem* sm, int load, int data_only, const char* section_name) +{ + SFORMAT StateRegs[] = + { + SFVAR(cur_ana_button_state), + SFVAR(prev_ana_button_state), + SFVAR(combo_anatoggle_counter), + + SFVAR(da_rumble_compat), + + SFVAR(analog_mode), + SFVAR(analog_mode_locked), + + SFVAR(mad_munchkins), + SFARRAY(rumble_magic, sizeof(rumble_magic)), + + SFARRAY(rumble_param, sizeof(rumble_param)), + + SFVAR(dtr), + + SFARRAY(buttons, sizeof(buttons)), + SFARRAY(&axes[0][0], sizeof(axes)), + + SFVAR(command_phase), + SFVAR(bitpos), + SFVAR(receive_buffer), + + SFVAR(command), + + SFARRAY(transmit_buffer, sizeof(transmit_buffer)), + SFVAR(transmit_pos), + SFVAR(transmit_count), + + SFEND + }; + int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name); + + if(load) + { + if((transmit_pos + transmit_count) > sizeof(transmit_buffer)) + { + transmit_pos = 0; + transmit_count = 0; + } + } + + return(ret); +} + + +void InputDevice_DualShock::UpdateInput(const void *data) +{ + uint8 *d8 = (uint8 *)data; + uint8* const rumb_dp = &d8[3 + 16]; + + buttons[0] = d8[0]; + buttons[1] = d8[1]; + cur_ana_button_state = d8[2] & 0x01; + + for(int stick = 0; stick < 2; stick++) + { + for(int axis = 0; axis < 2; axis++) + { + const uint8* aba = &d8[3] + stick * 8 + axis * 4; + int32 tmp; + + tmp = 32767 + MDFN_de16lsb(&aba[0]) - MDFN_de16lsb(&aba[2]); + tmp = (tmp * 0x100) / 0xFFFF; + + axes[stick][axis] = tmp; + } + } + + //printf("%3d:%3d, %3d:%3d\n", axes[0][0], axes[0][1], axes[1][0], axes[1][1]); + + //printf("RUMBLE: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", rumble_magic[0], rumble_magic[1], rumble_magic[2], rumble_magic[3], rumble_magic[4], rumble_magic[5]); + //printf("%d, 0x%02x 0x%02x\n", da_rumble_compat, rumble_param[0], rumble_param[1]); + + if(da_rumble_compat == false) + { + uint8 sneaky_weaky = 0; + + if(rumble_param[0] == 0x01) + sneaky_weaky = 0xFF; + + MDFN_en16lsb(rumb_dp, (sneaky_weaky << 0) | (rumble_param[1] << 8)); + } + else + { + uint8 sneaky_weaky = 0; + + if(((rumble_param[0] & 0xC0) == 0x40) && ((rumble_param[1] & 0x01) == 0x01)) + sneaky_weaky = 0xFF; + + MDFN_en16lsb(rumb_dp, sneaky_weaky << 0); + } + + //printf("%d %d %d %d\n", axes[0][0], axes[0][1], axes[1][0], axes[1][1]); + + // + // + // + CheckManualAnaModeChange(); + + if(am_prev_info != analog_mode || aml_prev_info != analog_mode_locked) + { + //MDFN_DispMessage(_("%s: Analog mode is %s(%s)."), gp_name.c_str(), analog_mode ? _("on") : _("off"), analog_mode_locked ? _("locked") : _("unlocked")); + } + aml_prev_info = analog_mode_locked; + am_prev_info = analog_mode; +} + + +void InputDevice_DualShock::SetDTR(bool new_dtr) +{ + const bool old_dtr = dtr; + dtr = new_dtr; // Set it to new state before we call CheckManualAnaModeChange(). + + if(!old_dtr && dtr) + { + command_phase = 0; + bitpos = 0; + transmit_pos = 0; + transmit_count = 0; + } + else if(old_dtr && !dtr) + { + CheckManualAnaModeChange(); + //if(bitpos || transmit_count) + // printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + } +} + +bool InputDevice_DualShock::GetDSR(void) +{ + if(!dtr) + return(0); + + if(!bitpos && transmit_count) + return(1); + + return(0); +} + +bool InputDevice_DualShock::Clock(bool TxD, int32 &dsr_pulse_delay) +{ + bool ret = 1; + + dsr_pulse_delay = 0; + + if(!dtr) + return(1); + + if(transmit_count) + ret = (transmit_buffer[transmit_pos] >> bitpos) & 1; + + receive_buffer &= ~(1 << bitpos); + receive_buffer |= TxD << bitpos; + bitpos = (bitpos + 1) & 0x7; + + if(!bitpos) + { + //if(command == 0x44) + //if(command == 0x4D) //mad_munchkins) // || command == 0x43) + // fprintf(stderr, "[PAD] Receive: %02x -- command=%02x, command_phase=%d, transmit_pos=%d\n", receive_buffer, command, command_phase, transmit_pos); + + if(transmit_count) + { + transmit_pos++; + transmit_count--; + } + + switch(command_phase) + { + case 0: + if(receive_buffer != 0x01) + command_phase = -1; + else + { + if(mad_munchkins) + { + transmit_buffer[0] = 0xF3; + transmit_pos = 0; + transmit_count = 1; + command_phase = 101; + } + else + { + transmit_buffer[0] = analog_mode ? 0x73 : 0x41; + transmit_pos = 0; + transmit_count = 1; + command_phase++; + } + } + break; + + case 1: + command = receive_buffer; + command_phase++; + + transmit_buffer[0] = 0x5A; + + //fprintf(stderr, "Gamepad command: 0x%02x\n", command); + //if(command != 0x42 && command != 0x43) + // fprintf(stderr, "Gamepad unhandled command: 0x%02x\n", command); + + if(command == 0x42) + { + transmit_buffer[0] = 0x5A; + transmit_pos = 0; + transmit_count = 1; + command_phase = (command << 8) | 0x00; + } + else if(command == 0x43) + { + transmit_pos = 0; + if(analog_mode) + { + transmit_buffer[1] = 0xFF ^ buttons[0]; + transmit_buffer[2] = 0xFF ^ buttons[1]; + transmit_buffer[3] = axes[0][0]; + transmit_buffer[4] = axes[0][1]; + transmit_buffer[5] = axes[1][0]; + transmit_buffer[6] = axes[1][1]; + transmit_count = 7; + } + else + { + transmit_buffer[1] = 0xFF ^ buttons[0]; + transmit_buffer[2] = 0xFF ^ buttons[1]; + transmit_count = 3; + } + } + else + { + command_phase = -1; + transmit_buffer[1] = 0; + transmit_buffer[2] = 0; + transmit_pos = 0; + transmit_count = 0; + } + break; + + case 2: + { + if(command == 0x43 && transmit_pos == 2 && (receive_buffer == 0x01)) + { + //fprintf(stderr, "Mad Munchkins mode entered!\n"); + mad_munchkins = true; + + if(da_rumble_compat) + { + rumble_param[0] = 0; + rumble_param[1] = 0; + da_rumble_compat = false; + } + command_phase = -1; + } + } + break; + + case 101: + command = receive_buffer; + + //fprintf(stderr, "Mad Munchkins DualShock command: 0x%02x\n", command); + + if(command >= 0x40 && command <= 0x4F) + { + transmit_buffer[0] = 0x5A; + transmit_pos = 0; + transmit_count = 1; + command_phase = (command << 8) | 0x00; + } + else + { + transmit_count = 0; + command_phase = -1; + } + break; + + /************************/ + /* MMMode 1, Command 0x40 */ + /************************/ + case 0x4000: + if(receive_buffer == 0x00) + { + transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/ + command_phase++; + } + else + command_phase = -1; + break; + + case 0x4001: + transmit_buffer[0] = 0x00; + transmit_buffer[1] = 0x00; + transmit_buffer[2] = 0x00; + transmit_buffer[3] = 0x00; + transmit_buffer[4] = 0x00; + transmit_pos = 0; + transmit_count = 5; + command_phase = -1; + break; + + + /************************/ + /* MMMode 1, Command 0x41 */ + /************************/ + case 0x4100: + if(receive_buffer == 0x00) + { + transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/ + command_phase++; + } + else + command_phase = -1; + break; + + case 0x4101: + transmit_buffer[0] = 0x00; + transmit_buffer[1] = 0x00; + transmit_buffer[2] = 0x00; + transmit_buffer[3] = 0x00; + transmit_buffer[4] = 0x00; + transmit_pos = 0; + transmit_count = 5; + command_phase = -1; + break; + + /**************************/ + /* MMMode 0&1, Command 0x42 */ + /**************************/ + case 0x4200: + transmit_pos = 0; + if(analog_mode || mad_munchkins) + { + transmit_buffer[0] = 0xFF ^ buttons[0]; + transmit_buffer[1] = 0xFF ^ buttons[1]; + transmit_buffer[2] = axes[0][0]; + transmit_buffer[3] = axes[0][1]; + transmit_buffer[4] = axes[1][0]; + transmit_buffer[5] = axes[1][1]; + transmit_count = 6; + } + else + { + transmit_buffer[0] = 0xFF ^ buttons[0]; + transmit_buffer[1] = 0xFF ^ buttons[1]; + transmit_count = 2; + + if(!(rumble_magic[2] & 0xFE)) + { + transmit_buffer[transmit_count++] = 0x00; + transmit_buffer[transmit_count++] = 0x00; + } + } + command_phase++; + break; + + case 0x4201: // Weak(in DS mode) + if(da_rumble_compat) + rumble_param[0] = receive_buffer; + // Dualshock weak + else if(rumble_magic[0] == 0x00 && rumble_magic[2] != 0x00 && rumble_magic[3] != 0x00 && rumble_magic[4] != 0x00 && rumble_magic[5] != 0x00) + rumble_param[0] = receive_buffer; + command_phase++; + break; + + case 0x4202: + if(da_rumble_compat) + rumble_param[1] = receive_buffer; + else if(rumble_magic[1] == 0x01) // DualShock strong + rumble_param[1] = receive_buffer; + else if(rumble_magic[1] == 0x00 && rumble_magic[2] != 0x00 && rumble_magic[3] != 0x00 && rumble_magic[4] != 0x00 && rumble_magic[5] != 0x00) // DualShock weak + rumble_param[0] = receive_buffer; + + command_phase++; + break; + + case 0x4203: + if(da_rumble_compat) + { + + } + else if(rumble_magic[1] == 0x00 && rumble_magic[2] == 0x01) + rumble_param[1] = receive_buffer; // DualShock strong. + command_phase++; // Nowhere here we come! + break; + + /************************/ + /* MMMode 1, Command 0x43 */ + /************************/ + case 0x4300: + if(receive_buffer == 0x00) + { + transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/ + command_phase++; + } + else + command_phase = -1; + break; + + case 0x4301: + if(receive_buffer == 0x00) + { + //fprintf(stderr, "Mad Munchkins mode left!\n"); + mad_munchkins = false; + } + transmit_buffer[0] = 0x00; + transmit_buffer[1] = 0x00; + transmit_buffer[2] = 0x00; + transmit_buffer[3] = 0x00; + transmit_buffer[4] = 0x00; + transmit_pos = 0; + transmit_count = 5; + command_phase = -1; + break; + + /************************/ + /* MMMode 1, Command 0x44 */ + /************************/ + case 0x4400: + if(receive_buffer == 0x00) + { + transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/ + command_phase++; + } + else + command_phase = -1; + break; + + case 0x4401: + transmit_buffer[0] = 0x00; + transmit_buffer[1] = 0x00; + transmit_buffer[2] = 0x00; + transmit_buffer[3] = 0x00; + transmit_buffer[4] = 0x00; + transmit_pos = 0; + transmit_count = 5; + command_phase++; + + // Ignores locking state. + switch(receive_buffer) + { + case 0x00: + analog_mode = false; + //fprintf(stderr, "Analog mode disabled\n"); + break; + + case 0x01: + analog_mode = true; + //fprintf(stderr, "Analog mode enabled\n"); + break; + } + break; + + case 0x4402: + switch(receive_buffer) + { + case 0x02: + analog_mode_locked = false; + break; + + case 0x03: + analog_mode_locked = true; + break; + } + command_phase = -1; + break; + + /************************/ + /* MMMode 1, Command 0x45 */ + /************************/ + case 0x4500: + if(receive_buffer == 0x00) + { + transmit_buffer[0] = 0x01; /**/ transmit_pos = 0; transmit_count = 1; /**/ + command_phase++; + } + else + command_phase = -1; + break; + + case 0x4501: + transmit_buffer[0] = 0x02; + transmit_buffer[1] = analog_mode ? 0x01 : 0x00; + transmit_buffer[2] = 0x02; + transmit_buffer[3] = 0x01; + transmit_buffer[4] = 0x00; + transmit_pos = 0; + transmit_count = 5; + command_phase = -1; + break; + + + /************************/ + /* MMMode 1, Command 0x46 */ + /************************/ + case 0x4600: + if(receive_buffer == 0x00) + { + transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/ + command_phase++; + } + else + command_phase = -1; + break; + + case 0x4601: + if(receive_buffer == 0x00) + { + transmit_buffer[0] = 0x00; + transmit_buffer[1] = 0x01; + transmit_buffer[2] = 0x02; + transmit_buffer[3] = 0x00; + transmit_buffer[4] = 0x0A; + } + else if(receive_buffer == 0x01) + { + transmit_buffer[0] = 0x00; + transmit_buffer[1] = 0x01; + transmit_buffer[2] = 0x01; + transmit_buffer[3] = 0x01; + transmit_buffer[4] = 0x14; + } + else + { + transmit_buffer[0] = 0x00; + transmit_buffer[1] = 0x00; + transmit_buffer[2] = 0x00; + transmit_buffer[3] = 0x00; + transmit_buffer[4] = 0x00; + } + transmit_pos = 0; + transmit_count = 5; + command_phase = -1; + break; + + /************************/ + /* MMMode 1, Command 0x47 */ + /************************/ + case 0x4700: + if(receive_buffer == 0x00) + { + transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/ + command_phase++; + } + else + command_phase = -1; + break; + + case 0x4701: + if(receive_buffer == 0x00) + { + transmit_buffer[0] = 0x00; + transmit_buffer[1] = 0x02; + transmit_buffer[2] = 0x00; + transmit_buffer[3] = 0x01; + transmit_buffer[4] = 0x00; + } + else + { + transmit_buffer[0] = 0x00; + transmit_buffer[1] = 0x00; + transmit_buffer[2] = 0x00; + transmit_buffer[3] = 0x00; + transmit_buffer[4] = 0x00; + } + transmit_pos = 0; + transmit_count = 5; + command_phase = -1; + break; + + /************************/ + /* MMMode 1, Command 0x48 */ + /************************/ + case 0x4800: + if(receive_buffer == 0x00) + { + transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/ + command_phase++; + } + else + command_phase = -1; + break; + + case 0x4801: + if(receive_buffer == 0x00) + { + transmit_buffer[0] = 0x00; + transmit_buffer[1] = 0x00; + transmit_buffer[2] = 0x00; + transmit_buffer[3] = 0x01; + transmit_buffer[4] = rumble_param[0]; + } + else if(receive_buffer == 0x01) + { + transmit_buffer[0] = 0x00; + transmit_buffer[1] = 0x00; + transmit_buffer[2] = 0x00; + transmit_buffer[3] = 0x01; + transmit_buffer[4] = rumble_param[1]; + } + else + { + transmit_buffer[0] = 0x00; + transmit_buffer[1] = 0x00; + transmit_buffer[2] = 0x00; + transmit_buffer[3] = 0x00; + transmit_buffer[4] = 0x00; + } + transmit_pos = 0; + transmit_count = 5; + command_phase = -1; + break; + + /************************/ + /* MMMode 1, Command 0x49 */ + /************************/ + case 0x4900: + if(receive_buffer == 0x00) + { + transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/ + command_phase++; + } + else + command_phase = -1; + break; + + case 0x4901: + transmit_buffer[0] = 0x00; + transmit_buffer[1] = 0x00; + transmit_buffer[2] = 0x00; + transmit_buffer[3] = 0x00; + transmit_buffer[4] = 0x00; + transmit_pos = 0; + transmit_count = 5; + command_phase = -1; + break; + + /************************/ + /* MMMode 1, Command 0x4A */ + /************************/ + case 0x4A00: + if(receive_buffer == 0x00) + { + transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/ + command_phase++; + } + else + command_phase = -1; + break; + + case 0x4A01: + transmit_buffer[0] = 0x00; + transmit_buffer[1] = 0x00; + transmit_buffer[2] = 0x00; + transmit_buffer[3] = 0x00; + transmit_buffer[4] = 0x00; + transmit_pos = 0; + transmit_count = 5; + command_phase = -1; + break; + + /************************/ + /* MMMode 1, Command 0x4B */ + /************************/ + case 0x4B00: + if(receive_buffer == 0x00) + { + transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/ + command_phase++; + } + else + command_phase = -1; + break; + + case 0x4B01: + transmit_buffer[0] = 0x00; + transmit_buffer[1] = 0x00; + transmit_buffer[2] = 0x00; + transmit_buffer[3] = 0x00; + transmit_buffer[4] = 0x00; + transmit_pos = 0; + transmit_count = 5; + command_phase = -1; + break; + + /************************/ + /* MMMode 1, Command 0x4C */ + /************************/ + case 0x4C00: + if(receive_buffer == 0x00) + { + transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/ + command_phase++; + } + else + command_phase = -1; + break; + + case 0x4C01: + if(receive_buffer == 0x00) + { + transmit_buffer[0] = 0x00; + transmit_buffer[1] = 0x00; + transmit_buffer[2] = 0x04; + transmit_buffer[3] = 0x00; + transmit_buffer[4] = 0x00; + } + else if(receive_buffer == 0x01) + { + transmit_buffer[0] = 0x00; + transmit_buffer[1] = 0x00; + transmit_buffer[2] = 0x07; + transmit_buffer[3] = 0x00; + transmit_buffer[4] = 0x00; + } + else + { + transmit_buffer[0] = 0x00; + transmit_buffer[1] = 0x00; + transmit_buffer[2] = 0x00; + transmit_buffer[3] = 0x00; + transmit_buffer[4] = 0x00; + } + + transmit_pos = 0; + transmit_count = 5; + command_phase = -1; + break; + + /************************/ + /* MMMode 1, Command 0x4D */ + /************************/ + case 0x4D00: + if(receive_buffer == 0x00) + { + transmit_buffer[0] = rumble_magic[0]; /**/ transmit_pos = 0; transmit_count = 1; /**/ + command_phase++; + } + else + command_phase = -1; + break; + + case 0x4D01: + case 0x4D02: + case 0x4D03: + case 0x4D04: + case 0x4D05: + case 0x4D06: + { + unsigned index = command_phase - 0x4D01; + + if(index < 5) + { + transmit_buffer[0] = rumble_magic[1 + index]; + transmit_pos = 0; + transmit_count = 1; + command_phase++; + } + else + command_phase = -1; + + rumble_magic[index] = receive_buffer; + } + break; + + /************************/ + /* MMMode 1, Command 0x4E */ + /************************/ + case 0x4E00: + if(receive_buffer == 0x00) + { + transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/ + command_phase++; + } + else + command_phase = -1; + break; + + case 0x4E01: + transmit_buffer[0] = 0x00; + transmit_buffer[1] = 0x00; + transmit_buffer[2] = 0x00; + transmit_buffer[3] = 0x00; + transmit_buffer[4] = 0x00; + transmit_pos = 0; + transmit_count = 5; + command_phase = -1; + break; + + + /************************/ + /* MMMode 1, Command 0x4F */ + /************************/ + case 0x4F00: + if(receive_buffer == 0x00) + { + transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/ + command_phase++; + } + else + command_phase = -1; + break; + + case 0x4F01: + transmit_buffer[0] = 0x00; + transmit_buffer[1] = 0x00; + transmit_buffer[2] = 0x00; + transmit_buffer[3] = 0x00; + transmit_buffer[4] = 0x00; + transmit_pos = 0; + transmit_count = 5; + command_phase = -1; + break; + } + } + + if(!bitpos && transmit_count) + dsr_pulse_delay = 0x40; //0x100; + + return(ret); +} + +InputDevice *Device_DualShock_Create(const std::string &name) +{ + return new InputDevice_DualShock(name); +} + + +InputDeviceInputInfoStruct Device_DualShock_IDII[26] = +{ + { "select", "SELECT", 4, IDIT_BUTTON, NULL }, + { "l3", "Left Stick, Button(L3)", 18, IDIT_BUTTON, NULL }, + { "r3", "Right stick, Button(R3)", 23, IDIT_BUTTON, NULL }, + { "start", "START", 5, IDIT_BUTTON, NULL }, + { "up", "D-Pad UP ↑", 0, IDIT_BUTTON, "down" }, + { "right", "D-Pad RIGHT →", 3, IDIT_BUTTON, "left" }, + { "down", "D-Pad DOWN ↓", 1, IDIT_BUTTON, "up" }, + { "left", "D-Pad LEFT ←", 2, IDIT_BUTTON, "right" }, + + { "l2", "L2 (rear left shoulder)", 11, IDIT_BUTTON, NULL }, + { "r2", "R2 (rear right shoulder)", 13, IDIT_BUTTON, NULL }, + { "l1", "L1 (front left shoulder)", 10, IDIT_BUTTON, NULL }, + { "r1", "R1 (front right shoulder)", 12, IDIT_BUTTON, NULL }, + + { "triangle", "△ (upper)", 6, IDIT_BUTTON_CAN_RAPID, NULL }, + { "circle", "○ (right)", 9, IDIT_BUTTON_CAN_RAPID, NULL }, + { "cross", "x (lower)", 7, IDIT_BUTTON_CAN_RAPID, NULL }, + { "square", "□ (left)", 8, IDIT_BUTTON_CAN_RAPID, NULL }, + + { "analog", "Analog(mode toggle)", 24, IDIT_BUTTON, NULL }, + + { "rstick_right", "Right Stick RIGHT →", 22, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + { "rstick_left", "Right Stick LEFT ←", 21, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + { "rstick_down", "Right Stick DOWN ↓", 20, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + { "rstick_up", "Right Stick UP ↑", 19, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + + { "lstick_right", "Left Stick RIGHT →", 17, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + { "lstick_left", "Left Stick LEFT ←", 16, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + { "lstick_down", "Left Stick DOWN ↓", 15, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + { "lstick_up", "Left Stick UP ↑", 14, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR }, + + { "rumble", "RUMBLE MONSTER RUMBA", 100, IDIT_RUMBLE }, +}; + +} diff --git a/psx/octoshock/psx/input/dualshock.h b/psx/octoshock/psx/input/dualshock.h new file mode 100644 index 0000000000..758f10bf3a --- /dev/null +++ b/psx/octoshock/psx/input/dualshock.h @@ -0,0 +1,11 @@ +#ifndef __MDFN_PSX_INPUT_DUALSHOCK_H +#define __MDFN_PSX_INPUT_DUALSHOCK_H + +#include + +namespace MDFN_IEN_PSX +{ +InputDevice *Device_DualShock_Create(const std::string &name); +extern InputDeviceInputInfoStruct Device_DualShock_IDII[26]; +} +#endif diff --git a/psx/octoshock/psx/input/gamepad.cpp b/psx/octoshock/psx/input/gamepad.cpp new file mode 100644 index 0000000000..b3045253bc --- /dev/null +++ b/psx/octoshock/psx/input/gamepad.cpp @@ -0,0 +1,276 @@ +#include "../psx.h" +#include "../frontio.h" +#include "gamepad.h" + +namespace MDFN_IEN_PSX +{ + +class InputDevice_Gamepad : public InputDevice +{ + public: + + InputDevice_Gamepad(); + virtual ~InputDevice_Gamepad(); + + virtual void Power(void); + virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name); + virtual void UpdateInput(const void *data); + + // + // + // + virtual void SetDTR(bool new_dtr); + virtual bool GetDSR(void); + virtual bool Clock(bool TxD, int32 &dsr_pulse_delay); + + private: + + bool dtr; + + uint8 buttons[2]; + + int32 command_phase; + uint32 bitpos; + uint8 receive_buffer; + + uint8 command; + + uint8 transmit_buffer[3]; + uint32 transmit_pos; + uint32 transmit_count; +}; + +InputDevice_Gamepad::InputDevice_Gamepad() +{ + Power(); +} + +InputDevice_Gamepad::~InputDevice_Gamepad() +{ + +} + +void InputDevice_Gamepad::Power(void) +{ + dtr = 0; + + buttons[0] = buttons[1] = 0; + + command_phase = 0; + + bitpos = 0; + + receive_buffer = 0; + + command = 0; + + memset(transmit_buffer, 0, sizeof(transmit_buffer)); + + transmit_pos = 0; + transmit_count = 0; +} + +int InputDevice_Gamepad::StateAction(StateMem* sm, int load, int data_only, const char* section_name) +{ + SFORMAT StateRegs[] = + { + SFVAR(dtr), + + SFARRAY(buttons, sizeof(buttons)), + + SFVAR(command_phase), + SFVAR(bitpos), + SFVAR(receive_buffer), + + SFVAR(command), + + SFARRAY(transmit_buffer, sizeof(transmit_buffer)), + SFVAR(transmit_pos), + SFVAR(transmit_count), + + SFEND + }; + int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name); + + if(load) + { + if((transmit_pos + transmit_count) > sizeof(transmit_buffer)) + { + transmit_pos = 0; + transmit_count = 0; + } + } + + return(ret); +} + + +void InputDevice_Gamepad::UpdateInput(const void *data) +{ + uint8 *d8 = (uint8 *)data; + + buttons[0] = d8[0]; + buttons[1] = d8[1]; +} + + +void InputDevice_Gamepad::SetDTR(bool new_dtr) +{ + if(!dtr && new_dtr) + { + command_phase = 0; + bitpos = 0; + transmit_pos = 0; + transmit_count = 0; + } + else if(dtr && !new_dtr) + { + //if(bitpos || transmit_count) + // printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + } + + dtr = new_dtr; +} + +bool InputDevice_Gamepad::GetDSR(void) +{ + if(!dtr) + return(0); + + if(!bitpos && transmit_count) + return(1); + + return(0); +} + +bool InputDevice_Gamepad::Clock(bool TxD, int32 &dsr_pulse_delay) +{ + bool ret = 1; + + dsr_pulse_delay = 0; + + if(!dtr) + return(1); + + if(transmit_count) + ret = (transmit_buffer[transmit_pos] >> bitpos) & 1; + + receive_buffer &= ~(1 << bitpos); + receive_buffer |= TxD << bitpos; + bitpos = (bitpos + 1) & 0x7; + + if(!bitpos) + { + //printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase); + + if(transmit_count) + { + transmit_pos++; + transmit_count--; + } + + + switch(command_phase) + { + case 0: + if(receive_buffer != 0x01) + command_phase = -1; + else + { + transmit_buffer[0] = 0x41; + transmit_pos = 0; + transmit_count = 1; + command_phase++; + } + break; + + case 1: + command = receive_buffer; + command_phase++; + + transmit_buffer[0] = 0x5A; + + //if(command != 0x42) + // fprintf(stderr, "Gamepad unhandled command: 0x%02x\n", command); + //assert(command == 0x42); + if(command == 0x42) + { + //printf("PAD COmmand 0x42, sl=%u\n", GPU->GetScanlineNum()); + + transmit_buffer[1] = 0xFF ^ buttons[0]; + transmit_buffer[2] = 0xFF ^ buttons[1]; + transmit_pos = 0; + transmit_count = 3; + } + else + { + command_phase = -1; + transmit_buffer[1] = 0; + transmit_buffer[2] = 0; + transmit_pos = 0; + transmit_count = 0; + } + break; + + } + } + + if(!bitpos && transmit_count) + dsr_pulse_delay = 0x40; //0x100; + + return(ret); +} + +InputDevice *Device_Gamepad_Create(void) +{ + return new InputDevice_Gamepad(); +} + + +InputDeviceInputInfoStruct Device_Gamepad_IDII[16] = +{ + { "select", "SELECT", 4, IDIT_BUTTON, NULL }, + { NULL, "empty", 0, IDIT_BUTTON }, + { NULL, "empty", 0, IDIT_BUTTON }, + { "start", "START", 5, IDIT_BUTTON, NULL }, + { "up", "UP ↑", 0, IDIT_BUTTON, "down" }, + { "right", "RIGHT →", 3, IDIT_BUTTON, "left" }, + { "down", "DOWN ↓", 1, IDIT_BUTTON, "up" }, + { "left", "LEFT ←", 2, IDIT_BUTTON, "right" }, + + { "l2", "L2 (rear left shoulder)", 11, IDIT_BUTTON, NULL }, + { "r2", "R2 (rear right shoulder)", 13, IDIT_BUTTON, NULL }, + { "l1", "L1 (front left shoulder)", 10, IDIT_BUTTON, NULL }, + { "r1", "R1 (front right shoulder)", 12, IDIT_BUTTON, NULL }, + + { "triangle", "△ (upper)", 6, IDIT_BUTTON_CAN_RAPID, NULL }, + { "circle", "○ (right)", 9, IDIT_BUTTON_CAN_RAPID, NULL }, + { "cross", "x (lower)", 7, IDIT_BUTTON_CAN_RAPID, NULL }, + { "square", "□ (left)", 8, IDIT_BUTTON_CAN_RAPID, NULL }, +}; + +InputDeviceInputInfoStruct Device_Dancepad_IDII[16] = +{ + { "select", "SELECT", 0, IDIT_BUTTON, NULL }, + { NULL, "empty", 0, IDIT_BUTTON }, + { NULL, "empty", 0, IDIT_BUTTON }, + { "start", "START", 1, IDIT_BUTTON, NULL }, + + { "up", "UP ↑", 3, IDIT_BUTTON, NULL }, + { "right", "RIGHT →", 6, IDIT_BUTTON, NULL }, + { "down", "DOWN ↓", 8, IDIT_BUTTON, NULL }, + { "left", "LEFT ←", 5, IDIT_BUTTON, NULL }, + + { NULL, "empty", 0, IDIT_BUTTON, NULL }, + { NULL, "empty", 0, IDIT_BUTTON, NULL }, + { NULL, "empty", 0, IDIT_BUTTON, NULL }, + { NULL, "empty", 0, IDIT_BUTTON, NULL }, + + { "triangle", "△ (lower left)", 7, IDIT_BUTTON, NULL }, + { "circle", "○ (upper right)", 4, IDIT_BUTTON, NULL }, + { "cross", "x (upper left)", 2, IDIT_BUTTON, NULL }, + { "square", "□ (lower right)", 9, IDIT_BUTTON, NULL }, +}; + + +} diff --git a/psx/octoshock/psx/input/gamepad.h b/psx/octoshock/psx/input/gamepad.h new file mode 100644 index 0000000000..5c652b1551 --- /dev/null +++ b/psx/octoshock/psx/input/gamepad.h @@ -0,0 +1,12 @@ +#ifndef __MDFN_PSX_INPUT_GAMEPAD_H +#define __MDFN_PSX_INPUT_GAMEPAD_H + +namespace MDFN_IEN_PSX +{ + +InputDevice *Device_Gamepad_Create(void); +extern InputDeviceInputInfoStruct Device_Gamepad_IDII[16]; +extern InputDeviceInputInfoStruct Device_Dancepad_IDII[16]; + +} +#endif diff --git a/psx/octoshock/psx/input/guncon.cpp b/psx/octoshock/psx/input/guncon.cpp new file mode 100644 index 0000000000..b9ae7501c5 --- /dev/null +++ b/psx/octoshock/psx/input/guncon.cpp @@ -0,0 +1,383 @@ +/* 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 "../psx.h" +#include "../frontio.h" +#include "guncon.h" + +namespace MDFN_IEN_PSX +{ + +class InputDevice_GunCon : public InputDevice +{ + public: + + InputDevice_GunCon(void); + virtual ~InputDevice_GunCon(); + + virtual void Power(void); + virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name); + virtual void UpdateInput(const void *data); + virtual bool RequireNoFrameskip(void); + virtual pscpu_timestamp_t GPULineHook(const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider); + + // + // + // + virtual void SetDTR(bool new_dtr); + virtual bool GetDSR(void); + virtual bool Clock(bool TxD, int32 &dsr_pulse_delay); + + private: + + bool dtr; + + uint8 buttons; + bool trigger_eff; + bool trigger_noclear; + uint16 hit_x, hit_y; + + int16 nom_x, nom_y; + int32 os_shot_counter; + bool prev_oss; + + int32 command_phase; + uint32 bitpos; + uint8 receive_buffer; + + uint8 command; + + uint8 transmit_buffer[16]; + uint32 transmit_pos; + uint32 transmit_count; + + // + // Video timing stuff + bool prev_vsync; + int line_counter; +}; + +InputDevice_GunCon::InputDevice_GunCon(void) +{ + Power(); +} + +InputDevice_GunCon::~InputDevice_GunCon() +{ + +} + +void InputDevice_GunCon::Power(void) +{ + dtr = 0; + + buttons = 0; + trigger_eff = 0; + trigger_noclear = 0; + hit_x = 0; + hit_y = 0; + + nom_x = 0; + nom_y = 0; + + os_shot_counter = 0; + prev_oss = 0; + + command_phase = 0; + + bitpos = 0; + + receive_buffer = 0; + + command = 0; + + memset(transmit_buffer, 0, sizeof(transmit_buffer)); + + transmit_pos = 0; + transmit_count = 0; + + prev_vsync = 0; + line_counter = 0; +} + +int InputDevice_GunCon::StateAction(StateMem* sm, int load, int data_only, const char* section_name) +{ + SFORMAT StateRegs[] = + { + SFVAR(dtr), + + SFVAR(buttons), + SFVAR(trigger_eff), + SFVAR(trigger_noclear), + SFVAR(hit_x), + SFVAR(hit_y), + + SFVAR(nom_x), + SFVAR(nom_y), + SFVAR(os_shot_counter), + SFVAR(prev_oss), + + SFVAR(command_phase), + SFVAR(bitpos), + SFVAR(receive_buffer), + + SFVAR(command), + + SFARRAY(transmit_buffer, sizeof(transmit_buffer)), + SFVAR(transmit_pos), + SFVAR(transmit_count), + + SFVAR(prev_vsync), + SFVAR(line_counter), + + SFEND + }; + int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name); + + if(load) + { + if((transmit_pos + transmit_count) > sizeof(transmit_buffer)) + { + transmit_pos = 0; + transmit_count = 0; + } + } + + return(ret); +} + + +void InputDevice_GunCon::UpdateInput(const void *data) +{ + uint8 *d8 = (uint8 *)data; + + nom_x = (int16)MDFN_de16lsb(&d8[0]); + nom_y = (int16)MDFN_de16lsb(&d8[2]); + + trigger_noclear = (bool)(d8[4] & 0x1); + trigger_eff |= trigger_noclear; + + buttons = d8[4] >> 1; + + if(os_shot_counter > 0) // FIXME if UpdateInput() is ever called more than once per video frame(at ~50 or ~60Hz). + os_shot_counter--; + + if((d8[4] & 0x8) && !prev_oss && os_shot_counter == 0) + os_shot_counter = 4; + prev_oss = d8[4] & 0x8; + + //MDFN_DispMessage("%08x %08x", nom_x, nom_y); +} + +bool InputDevice_GunCon::RequireNoFrameskip(void) +{ + return(true); +} + +pscpu_timestamp_t InputDevice_GunCon::GPULineHook(const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, + const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider) +{ + if(vsync && !prev_vsync) + line_counter = 0; + + if(pixels && pix_clock) + { + const int avs = 16; // Not 16 for PAL, fixme. + int32 gx; + int32 gy; + + gx = (nom_x * 2 + pix_clock_divider) / (pix_clock_divider * 2); + gy = nom_y; + + for(int32 ix = gx; ix < (gx + (int32)(pix_clock / 762925)); ix++) + { + if(ix >= 0 && ix < (int)width && line_counter >= (avs + gy) && line_counter < (avs + gy + 8)) + { + int r, g, b, a; + + format->DecodeColor(pixels[ix], r, g, b, a); + + if((r + g + b) >= 0x40) // Wrong, but not COMPLETELY ABSOLUTELY wrong, at least. ;) + { + hit_x = (int64)(ix + pix_clock_offset) * 8000000 / pix_clock; // GunCon has what appears to be an 8.00MHz ceramic resonator in it. + hit_y = line_counter; + } + } + } + + chair_x = gx; + chair_y = (avs + gy) - line_counter; + } + + line_counter++; + + return(PSX_EVENT_MAXTS); +} + +void InputDevice_GunCon::SetDTR(bool new_dtr) +{ + if(!dtr && new_dtr) + { + command_phase = 0; + bitpos = 0; + transmit_pos = 0; + transmit_count = 0; + } + else if(dtr && !new_dtr) + { + //if(bitpos || transmit_count) + // printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + } + + dtr = new_dtr; +} + +bool InputDevice_GunCon::GetDSR(void) +{ + if(!dtr) + return(0); + + if(!bitpos && transmit_count) + return(1); + + return(0); +} + +bool InputDevice_GunCon::Clock(bool TxD, int32 &dsr_pulse_delay) +{ + bool ret = 1; + + dsr_pulse_delay = 0; + + if(!dtr) + return(1); + + if(transmit_count) + ret = (transmit_buffer[transmit_pos] >> bitpos) & 1; + + receive_buffer &= ~(1 << bitpos); + receive_buffer |= TxD << bitpos; + bitpos = (bitpos + 1) & 0x7; + + if(!bitpos) + { + //printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase); + + if(transmit_count) + { + transmit_pos++; + transmit_count--; + } + + + switch(command_phase) + { + case 0: + if(receive_buffer != 0x01) + command_phase = -1; + else + { + transmit_buffer[0] = 0x63; + transmit_pos = 0; + transmit_count = 1; + command_phase++; + } + break; + + case 2: + //if(receive_buffer) + // printf("%02x\n", receive_buffer); + break; + + case 1: + command = receive_buffer; + command_phase++; + + transmit_buffer[0] = 0x5A; + + //puts("MOO"); + //if(command != 0x42) + // fprintf(stderr, "GunCon unhandled command: 0x%02x\n", command); + //assert(command == 0x42); + if(command == 0x42) + { + transmit_buffer[1] = 0xFF ^ ((buttons & 0x01) << 3); + transmit_buffer[2] = 0xFF ^ (trigger_eff << 5) ^ ((buttons & 0x02) << 5); + + if(os_shot_counter > 0) + { + hit_x = 0x01; + hit_y = 0x0A; + transmit_buffer[2] |= (1 << 5); + if(os_shot_counter == 2 || os_shot_counter == 3) + { + transmit_buffer[2] &= ~(1 << 5); + } + } + + MDFN_en16lsb(&transmit_buffer[3], hit_x); + MDFN_en16lsb(&transmit_buffer[5], hit_y); + + hit_x = 0x01; + hit_y = 0x0A; + + transmit_pos = 0; + transmit_count = 7; + + trigger_eff = trigger_noclear; + } + else + { + command_phase = -1; + transmit_buffer[1] = 0; + transmit_buffer[2] = 0; + transmit_pos = 0; + transmit_count = 0; + } + break; + + } + } + + if(!bitpos && transmit_count) + dsr_pulse_delay = 100; //0x80; //0x40; + + return(ret); +} + +InputDevice *Device_GunCon_Create(void) +{ + return new InputDevice_GunCon(); +} + + +InputDeviceInputInfoStruct Device_GunCon_IDII[6] = +{ + { "x_axis", "X Axis", -1, IDIT_X_AXIS }, + { "y_axis", "Y Axis", -1, IDIT_Y_AXIS }, + + { "trigger", "Trigger", 0, IDIT_BUTTON, NULL }, + + { "a", "A", 1, IDIT_BUTTON, NULL }, + { "b", "B", 2, IDIT_BUTTON, NULL }, + + { "offscreen_shot", "Offscreen Shot(Simulated)", 3, IDIT_BUTTON, NULL }, // Useful for "Judge Dredd", and probably not much else. +}; + + + +} diff --git a/psx/octoshock/psx/input/guncon.h b/psx/octoshock/psx/input/guncon.h new file mode 100644 index 0000000000..7641cc2d9f --- /dev/null +++ b/psx/octoshock/psx/input/guncon.h @@ -0,0 +1,11 @@ +#ifndef __MDFN_PSX_INPUT_GUNCON_H +#define __MDFN_PSX_INPUT_GUNCON_H + +namespace MDFN_IEN_PSX +{ + +InputDevice *Device_GunCon_Create(void); +extern InputDeviceInputInfoStruct Device_GunCon_IDII[6]; + +} +#endif diff --git a/psx/octoshock/psx/input/justifier.cpp b/psx/octoshock/psx/input/justifier.cpp new file mode 100644 index 0000000000..e19bfb9b7b --- /dev/null +++ b/psx/octoshock/psx/input/justifier.cpp @@ -0,0 +1,381 @@ +/* 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 "../psx.h" +#include "../frontio.h" +#include "justifier.h" + +namespace MDFN_IEN_PSX +{ + +class InputDevice_Justifier : public InputDevice +{ + public: + + InputDevice_Justifier(void); + virtual ~InputDevice_Justifier(); + + virtual void Power(void); + virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name); + virtual void UpdateInput(const void *data); + virtual bool RequireNoFrameskip(void); + virtual pscpu_timestamp_t GPULineHook(const pscpu_timestamp_t timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider); + + // + // + // + virtual void SetDTR(bool new_dtr); + virtual bool GetDSR(void); + virtual bool Clock(bool TxD, int32 &dsr_pulse_delay); + + private: + + bool dtr; + + uint8 buttons; + bool trigger_eff; + bool trigger_noclear; + + bool need_hit_detect; + + int16 nom_x, nom_y; + int32 os_shot_counter; + bool prev_oss; + + int32 command_phase; + uint32 bitpos; + uint8 receive_buffer; + + uint8 command; + + uint8 transmit_buffer[16]; + uint32 transmit_pos; + uint32 transmit_count; + + // + // Video timing stuff + bool prev_vsync; + int line_counter; +}; + +InputDevice_Justifier::InputDevice_Justifier(void) +{ + Power(); +} + +InputDevice_Justifier::~InputDevice_Justifier() +{ + +} + +void InputDevice_Justifier::Power(void) +{ + dtr = 0; + + buttons = 0; + trigger_eff = 0; + trigger_noclear = 0; + + need_hit_detect = false; + + nom_x = 0; + nom_y = 0; + + os_shot_counter = 0; + prev_oss = 0; + + command_phase = 0; + + bitpos = 0; + + receive_buffer = 0; + + command = 0; + + memset(transmit_buffer, 0, sizeof(transmit_buffer)); + + transmit_pos = 0; + transmit_count = 0; + + prev_vsync = 0; + line_counter = 0; +} + +void InputDevice_Justifier::UpdateInput(const void *data) +{ + uint8 *d8 = (uint8 *)data; + + nom_x = (int16)MDFN_de16lsb(&d8[0]); + nom_y = (int16)MDFN_de16lsb(&d8[2]); + + trigger_noclear = (bool)(d8[4] & 0x1); + trigger_eff |= trigger_noclear; + + buttons = (d8[4] >> 1) & 0x3; + + if(os_shot_counter > 0) // FIXME if UpdateInput() is ever called more than once per video frame(at ~50 or ~60Hz). + os_shot_counter--; + + if((d8[4] & 0x8) && !prev_oss && os_shot_counter == 0) + os_shot_counter = 10; + prev_oss = d8[4] & 0x8; +} + +int InputDevice_Justifier::StateAction(StateMem* sm, int load, int data_only, const char* section_name) +{ + SFORMAT StateRegs[] = + { + SFVAR(dtr), + + SFVAR(buttons), + SFVAR(trigger_eff), + SFVAR(trigger_noclear), + + SFVAR(need_hit_detect), + + SFVAR(nom_x), + SFVAR(nom_y), + SFVAR(os_shot_counter), + SFVAR(prev_oss), + + SFVAR(command_phase), + SFVAR(bitpos), + SFVAR(receive_buffer), + + SFVAR(command), + + SFARRAY(transmit_buffer, sizeof(transmit_buffer)), + SFVAR(transmit_pos), + SFVAR(transmit_count), + + SFVAR(prev_vsync), + SFVAR(line_counter), + + SFEND + }; + int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name); + + if(load) + { + if((transmit_pos + transmit_count) > sizeof(transmit_buffer)) + { + transmit_pos = 0; + transmit_count = 0; + } + } + + return(ret); +} + + +bool InputDevice_Justifier::RequireNoFrameskip(void) +{ + return(true); +} + +pscpu_timestamp_t InputDevice_Justifier::GPULineHook(const pscpu_timestamp_t timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, + const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider) +{ + pscpu_timestamp_t ret = PSX_EVENT_MAXTS; + + if(vsync && !prev_vsync) + line_counter = 0; + + if(pixels && pix_clock) + { + const int avs = 16; // Not 16 for PAL, fixme. + int32 gx; + int32 gy; + int32 gxa; + + gx = (nom_x * 2 + pix_clock_divider) / (pix_clock_divider * 2); + gy = nom_y; + gxa = gx; // - (pix_clock / 400000); + //if(gxa < 0 && gx >= 0) + // gxa = 0; + + if(!os_shot_counter && need_hit_detect && gxa >= 0 && gxa < (int)width && line_counter >= (avs + gy - 1) && line_counter <= (avs + gy + 1)) + { + int r, g, b, a; + + format->DecodeColor(pixels[gxa], r, g, b, a); + + if((r + g + b) >= 0x40) // Wrong, but not COMPLETELY ABSOLUTELY wrong, at least. ;) + { + ret = timestamp + (int64)(gxa + pix_clock_offset) * (44100 * 768) / pix_clock - 177; + } + } + + chair_x = gx; + chair_y = (avs + gy) - line_counter; + } + + line_counter++; + + return(ret); +} + +void InputDevice_Justifier::SetDTR(bool new_dtr) +{ + if(!dtr && new_dtr) + { + command_phase = 0; + bitpos = 0; + transmit_pos = 0; + transmit_count = 0; + } + else if(dtr && !new_dtr) + { + //if(bitpos || transmit_count) + // printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + } + + dtr = new_dtr; +} + +bool InputDevice_Justifier::GetDSR(void) +{ + if(!dtr) + return(0); + + if(!bitpos && transmit_count) + return(1); + + return(0); +} + +bool InputDevice_Justifier::Clock(bool TxD, int32 &dsr_pulse_delay) +{ + bool ret = 1; + + dsr_pulse_delay = 0; + + if(!dtr) + return(1); + + if(transmit_count) + ret = (transmit_buffer[transmit_pos] >> bitpos) & 1; + + receive_buffer &= ~(1 << bitpos); + receive_buffer |= TxD << bitpos; + bitpos = (bitpos + 1) & 0x7; + + if(!bitpos) + { + //printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase); + + if(transmit_count) + { + transmit_pos++; + transmit_count--; + } + + + switch(command_phase) + { + case 0: + if(receive_buffer != 0x01) + command_phase = -1; + else + { + transmit_buffer[0] = 0x31; + transmit_pos = 0; + transmit_count = 1; + command_phase++; + } + break; + + case 2: + //if(receive_buffer) + // printf("%02x\n", receive_buffer); + command_phase++; + break; + + case 3: + need_hit_detect = receive_buffer & 0x10; // TODO, see if it's (val&0x10) == 0x10, or some other mask value. + command_phase++; + break; + + case 1: + command = receive_buffer; + command_phase++; + + transmit_buffer[0] = 0x5A; + + //if(command != 0x42) + // fprintf(stderr, "Justifier unhandled command: 0x%02x\n", command); + //assert(command == 0x42); + if(command == 0x42) + { + transmit_buffer[1] = 0xFF ^ ((buttons & 2) << 2); + transmit_buffer[2] = 0xFF ^ (trigger_eff << 7) ^ ((buttons & 1) << 6); + + if(os_shot_counter > 0) + { + transmit_buffer[2] |= (1 << 7); + if(os_shot_counter == 6 || os_shot_counter == 5) + { + transmit_buffer[2] &= ~(1 << 7); + } + } + + transmit_pos = 0; + transmit_count = 3; + + trigger_eff = trigger_noclear; + } + else + { + command_phase = -1; + transmit_buffer[1] = 0; + transmit_buffer[2] = 0; + transmit_pos = 0; + transmit_count = 0; + } + break; + + } + } + + if(!bitpos && transmit_count) + dsr_pulse_delay = 200; + + return(ret); +} + +InputDevice *Device_Justifier_Create(void) +{ + return new InputDevice_Justifier(); +} + + +InputDeviceInputInfoStruct Device_Justifier_IDII[6] = +{ + { "x_axis", "X Axis", -1, IDIT_X_AXIS }, + { "y_axis", "Y Axis", -1, IDIT_Y_AXIS }, + + { "trigger", "Trigger", 0, IDIT_BUTTON, NULL }, + + { "o", "O", 1, IDIT_BUTTON, NULL }, + { "start", "Start", 2, IDIT_BUTTON, NULL }, + + { "offscreen_shot", "Offscreen Shot(Simulated)", 3, IDIT_BUTTON, NULL }, +}; + + + +} diff --git a/psx/octoshock/psx/input/justifier.h b/psx/octoshock/psx/input/justifier.h new file mode 100644 index 0000000000..b9c95982a6 --- /dev/null +++ b/psx/octoshock/psx/input/justifier.h @@ -0,0 +1,11 @@ +#ifndef __MDFN_PSX_INPUT_JUSTIFIER_H +#define __MDFN_PSX_INPUT_JUSTIFIER_H + +namespace MDFN_IEN_PSX +{ + +InputDevice *Device_Justifier_Create(void); +extern InputDeviceInputInfoStruct Device_Justifier_IDII[6]; + +} +#endif diff --git a/psx/octoshock/psx/input/memcard.cpp b/psx/octoshock/psx/input/memcard.cpp new file mode 100644 index 0000000000..db872a7bec --- /dev/null +++ b/psx/octoshock/psx/input/memcard.cpp @@ -0,0 +1,546 @@ +/* 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 + */ + +// I could find no other commands than 'R', 'W', and 'S' (not sure what 'S' is for, however) + +#include "../psx.h" +#include "../frontio.h" +#include "memcard.h" + +#define BIGCASE2(X) case X+0: case X+1: +#define BIGCASE4(X) BIGCASE2(X+0) BIGCASE2(X+2) +#define BIGCASE8(X) BIGCASE4(X+0) BIGCASE4(X+4) +#define BIGCASE16(X) BIGCASE8(X+0) BIGCASE8(X+8) +#define BIGCASE32(X) BIGCASE16(X+0) BIGCASE16(X+16) +#define BIGCASE64(X) BIGCASE32(X+0) BIGCASE32(X+32) +#define BIGCASE128(X) BIGCASE64(X+0) BIGCASE64(X+64) + +namespace MDFN_IEN_PSX +{ + +class InputDevice_Memcard : public InputDevice +{ + public: + + InputDevice_Memcard(); + virtual ~InputDevice_Memcard(); + + virtual void Power(void); + virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name); + + // + // + // + virtual void SetDTR(bool new_dtr); + virtual bool GetDSR(void); + virtual bool Clock(bool TxD, int32 &dsr_pulse_delay); + + // + // + virtual uint32 GetNVSize(void); + virtual void ReadNV(uint8 *buffer, uint32 offset, uint32 size); + virtual void WriteNV(const uint8 *buffer, uint32 offset, uint32 size); + + virtual uint64 GetNVDirtyCount(void); + virtual void ResetNVDirtyCount(void); + + private: + + void Format(void); + + bool presence_new; + + uint8 card_data[1 << 17]; + uint8 rw_buffer[128]; + uint8 write_xor; + + // + // Used to avoid saving unused memory cards' card data in save states. + // Set to false on object initialization, set to true when data is written to card_data that differs + // from existing data(either from loading a memory card saved to disk, or from a game writing to the memory card). + // + // Save and load its state to/from save states. + // + bool data_used; + + // + // Do not save dirty_count in save states! + // + uint64 dirty_count; + + bool dtr; + int32 command_phase; + uint32 bitpos; + uint8 receive_buffer; + + uint8 command; + uint16 addr; + uint8 calced_xor; + + uint8 transmit_buffer; + uint32 transmit_count; +}; + +void InputDevice_Memcard::Format(void) +{ + memset(card_data, 0x00, sizeof(card_data)); + + card_data[0x00] = 0x4D; + card_data[0x01] = 0x43; + card_data[0x7F] = 0x0E; + + for(unsigned int A = 0x80; A < 0x800; A += 0x80) + { + card_data[A + 0x00] = 0xA0; + card_data[A + 0x08] = 0xFF; + card_data[A + 0x09] = 0xFF; + card_data[A + 0x7F] = 0xA0; + } + + for(unsigned int A = 0x0800; A < 0x1200; A += 0x80) + { + card_data[A + 0x00] = 0xFF; + card_data[A + 0x01] = 0xFF; + card_data[A + 0x02] = 0xFF; + card_data[A + 0x03] = 0xFF; + card_data[A + 0x08] = 0xFF; + card_data[A + 0x09] = 0xFF; + } +} + +InputDevice_Memcard::InputDevice_Memcard() +{ + Power(); + + data_used = false; + dirty_count = 0; + + // Init memcard as formatted. + assert(sizeof(card_data) == (1 << 17)); + Format(); +} + +InputDevice_Memcard::~InputDevice_Memcard() +{ + +} + +void InputDevice_Memcard::Power(void) +{ + dtr = 0; + + //buttons[0] = buttons[1] = 0; + + command_phase = 0; + + bitpos = 0; + + receive_buffer = 0; + + command = 0; + + transmit_buffer = 0; + + transmit_count = 0; + + addr = 0; + + presence_new = true; +} + +int InputDevice_Memcard::StateAction(StateMem* sm, int load, int data_only, const char* section_name) +{ + // Don't save dirty_count. + SFORMAT StateRegs[] = + { + SFVAR(presence_new), + + SFARRAY(rw_buffer, sizeof(rw_buffer)), + SFVAR(write_xor), + + SFVAR(dtr), + SFVAR(command_phase), + SFVAR(bitpos), + SFVAR(receive_buffer), + + SFVAR(command), + SFVAR(addr), + SFVAR(calced_xor), + + SFVAR(transmit_buffer), + SFVAR(transmit_count), + + SFVAR(data_used), + + SFEND + }; + + SFORMAT CD_StateRegs[] = + { + SFARRAY(card_data, sizeof(card_data)), + SFEND + }; + int ret = 1; + + if(MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name) != 0) + { + //printf("%s data_used=%d\n", section_name, data_used); + if(data_used) + { + std::string tmp_name = std::string(section_name) + "_DT"; + + ret &= MDFNSS_StateAction(sm, load, data_only, CD_StateRegs, tmp_name.c_str()); + } + + if(load) + { + if(data_used) + dirty_count++; + else + { + //printf("Format: %s\n", section_name); + Format(); + } + } + } + else + ret = 0; + + return(ret); +} + + +void InputDevice_Memcard::SetDTR(bool new_dtr) +{ + if(!dtr && new_dtr) + { + command_phase = 0; + bitpos = 0; + transmit_count = 0; + } + else if(dtr && !new_dtr) + { + if(command_phase > 0) + PSX_WARNING("[MCR] Communication aborted???"); + } + dtr = new_dtr; +} + +bool InputDevice_Memcard::GetDSR(void) +{ + if(!dtr) + return(0); + + if(!bitpos && transmit_count) + return(1); + + return(0); +} + +bool InputDevice_Memcard::Clock(bool TxD, int32 &dsr_pulse_delay) +{ + bool ret = 1; + + dsr_pulse_delay = 0; + + if(!dtr) + return(1); + + if(transmit_count) + ret = (transmit_buffer >> bitpos) & 1; + + receive_buffer &= ~(1 << bitpos); + receive_buffer |= TxD << bitpos; + bitpos = (bitpos + 1) & 0x7; + + if(!bitpos) + { + //if(command_phase > 0 || transmit_count) + // printf("[MCRDATA] Received_data=0x%02x, Sent_data=0x%02x\n", receive_buffer, transmit_buffer); + + if(transmit_count) + { + transmit_count--; + } + + + switch(command_phase) + { + case 0: + if(receive_buffer != 0x81) + command_phase = -1; + else + { + //printf("[MCR] Device selected\n"); + transmit_buffer = presence_new ? 0x08 : 0x00; + transmit_count = 1; + command_phase++; + } + break; + + case 1: + command = receive_buffer; + //printf("[MCR] Command received: %c\n", command); + if(command == 'R' || command == 'W') + { + command_phase++; + transmit_buffer = 0x5A; + transmit_count = 1; + } + else + { + if(command == 'S') + { + PSX_WARNING("[MCR] Memcard S command unsupported."); + } + + command_phase = -1; + transmit_buffer = 0; + transmit_count = 0; + } + break; + + case 2: + transmit_buffer = 0x5D; + transmit_count = 1; + command_phase++; + break; + + case 3: + transmit_buffer = 0x00; + transmit_count = 1; + if(command == 'R') + command_phase = 1000; + else if(command == 'W') + command_phase = 2000; + break; + + // + // Read + // + case 1000: + addr = receive_buffer << 8; + transmit_buffer = receive_buffer; + transmit_count = 1; + command_phase++; + break; + + case 1001: + addr |= receive_buffer & 0xFF; + transmit_buffer = '\\'; + transmit_count = 1; + command_phase++; + break; + + case 1002: + //printf("[MCR] READ ADDR=0x%04x\n", addr); + if(addr >= (sizeof(card_data) >> 7)) + addr = 0xFFFF; + + calced_xor = 0; + transmit_buffer = ']'; + transmit_count = 1; + command_phase++; + + // TODO: enable this code(or something like it) when CPU instruction timing is a bit better. + // + //dsr_pulse_delay = 32000; + //goto SkipDPD; + // + + break; + + case 1003: + transmit_buffer = addr >> 8; + calced_xor ^= transmit_buffer; + transmit_count = 1; + command_phase++; + break; + + case 1004: + transmit_buffer = addr & 0xFF; + calced_xor ^= transmit_buffer; + + if(addr == 0xFFFF) + { + transmit_count = 1; + command_phase = -1; + } + else + { + transmit_count = 1; + command_phase = 1024; + } + break; + + // Transmit actual 128 bytes data + //case (1024 + 0) ... (1024 + 128 - 1): + BIGCASE128(1024) + transmit_buffer = card_data[(addr << 7) + (command_phase - 1024)]; + calced_xor ^= transmit_buffer; + transmit_count = 1; + command_phase++; + break; + + // XOR + case (1024 + 128): + transmit_buffer = calced_xor; + transmit_count = 1; + command_phase++; + break; + + // End flag + case (1024 + 129): + transmit_buffer = 'G'; + transmit_count = 1; + command_phase = -1; + break; + + // + // Write + // + case 2000: + calced_xor = receive_buffer; + addr = receive_buffer << 8; + transmit_buffer = receive_buffer; + transmit_count = 1; + command_phase++; + break; + + case 2001: + calced_xor ^= receive_buffer; + addr |= receive_buffer & 0xFF; + //printf("[MCR] WRITE ADDR=0x%04x\n", addr); + transmit_buffer = receive_buffer; + transmit_count = 1; + command_phase = 2048; + break; + + //case (2048 + 0) ... (2048 + 128 - 1): + BIGCASE128(2048) + calced_xor ^= receive_buffer; + rw_buffer[command_phase - 2048] = receive_buffer; + + transmit_buffer = receive_buffer; + transmit_count = 1; + command_phase++; + break; + + case (2048 + 128): // XOR + write_xor = receive_buffer; + transmit_buffer = '\\'; + transmit_count = 1; + command_phase++; + break; + + case (2048 + 129): + transmit_buffer = ']'; + transmit_count = 1; + command_phase++; + break; + + case (2048 + 130): // End flag + //MDFN_DispMessage("%02x %02x", calced_xor, write_xor); + //printf("[MCR] Write End. Actual_XOR=0x%02x, CW_XOR=0x%02x\n", calced_xor, write_xor); + + if(calced_xor != write_xor) + transmit_buffer = 'N'; + else if(addr >= (sizeof(card_data) >> 7)) + transmit_buffer = 0xFF; + else + { + transmit_buffer = 'G'; + presence_new = false; + + // If the current data is different from the data to be written, increment the dirty count. + // memcpy()'ing over to card_data is also conditionalized here for a slight optimization. + if(memcmp(&card_data[addr << 7], rw_buffer, 128)) + { + memcpy(&card_data[addr << 7], rw_buffer, 128); + dirty_count++; + data_used = true; + } + } + + transmit_count = 1; + command_phase = -1; + break; + + } + + //if(command_phase != -1 || transmit_count) + // printf("[MCR] Receive: 0x%02x, Send: 0x%02x -- %d\n", receive_buffer, transmit_buffer, command_phase); + } + + if(!bitpos && transmit_count) + dsr_pulse_delay = 0x100; + + //SkipDPD: ; + + return(ret); +} + +uint32 InputDevice_Memcard::GetNVSize(void) +{ + return(sizeof(card_data)); +} + +void InputDevice_Memcard::ReadNV(uint8 *buffer, uint32 offset, uint32 size) +{ + while(size--) + { + *buffer = card_data[offset & (sizeof(card_data) - 1)]; + buffer++; + offset++; + } +} + +void InputDevice_Memcard::WriteNV(const uint8 *buffer, uint32 offset, uint32 size) +{ + if(size) + { + dirty_count++; + } + + while(size--) + { + if(card_data[offset & (sizeof(card_data) - 1)] != *buffer) + data_used = true; + + card_data[offset & (sizeof(card_data) - 1)] = *buffer; + buffer++; + offset++; + } +} + +uint64 InputDevice_Memcard::GetNVDirtyCount(void) +{ + return(dirty_count); +} + +void InputDevice_Memcard::ResetNVDirtyCount(void) +{ + dirty_count = 0; +} + + +InputDevice *Device_Memcard_Create(void) +{ + return new InputDevice_Memcard(); +} + +} diff --git a/psx/octoshock/psx/input/memcard.h b/psx/octoshock/psx/input/memcard.h new file mode 100644 index 0000000000..05627661c4 --- /dev/null +++ b/psx/octoshock/psx/input/memcard.h @@ -0,0 +1,11 @@ +#ifndef __MDFN_PSX_INPUT_MEMCARD_H +#define __MDFN_PSX_INPUT_MEMCARD_H + +namespace MDFN_IEN_PSX +{ + +InputDevice *Device_Memcard_Create(void); + +} + +#endif diff --git a/psx/octoshock/psx/input/mouse.cpp b/psx/octoshock/psx/input/mouse.cpp new file mode 100644 index 0000000000..530ff638ad --- /dev/null +++ b/psx/octoshock/psx/input/mouse.cpp @@ -0,0 +1,293 @@ +#include "../psx.h" +#include "../frontio.h" +#include "mouse.h" + +namespace MDFN_IEN_PSX +{ + +class InputDevice_Mouse : public InputDevice +{ + public: + + InputDevice_Mouse(); + virtual ~InputDevice_Mouse(); + + virtual void Power(void); + virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name); + virtual void UpdateInput(const void *data); + + virtual void Update(const pscpu_timestamp_t timestamp); + virtual void ResetTS(void); + + // + // + // + virtual void SetDTR(bool new_dtr); + virtual bool Clock(bool TxD, int32 &dsr_pulse_delay); + + private: + + int32 lastts; + int32 clear_timeout; + + bool dtr; + + uint8 button; + uint8 button_post_mask; + int32 accum_xdelta; + int32 accum_ydelta; + + int32 command_phase; + uint32 bitpos; + uint8 receive_buffer; + + uint8 command; + + uint8 transmit_buffer[5]; + uint32 transmit_pos; + uint32 transmit_count; +}; + +InputDevice_Mouse::InputDevice_Mouse() +{ + Power(); +} + +InputDevice_Mouse::~InputDevice_Mouse() +{ + +} + +void InputDevice_Mouse::Update(const pscpu_timestamp_t timestamp) +{ + int32 cycles = timestamp - lastts; + + clear_timeout += cycles; + if(clear_timeout >= (33868800 / 4)) + { + //puts("Mouse timeout\n"); + clear_timeout = 0; + accum_xdelta = 0; + accum_ydelta = 0; + button &= button_post_mask; + } + + lastts = timestamp; +} + +void InputDevice_Mouse::ResetTS(void) +{ + lastts = 0; +} + +void InputDevice_Mouse::Power(void) +{ + lastts = 0; + clear_timeout = 0; + + dtr = 0; + + button = 0; + button_post_mask = 0; + accum_xdelta = 0; + accum_ydelta = 0; + + command_phase = 0; + + bitpos = 0; + + receive_buffer = 0; + + command = 0; + + memset(transmit_buffer, 0, sizeof(transmit_buffer)); + + transmit_pos = 0; + transmit_count = 0; +} + +int InputDevice_Mouse::StateAction(StateMem* sm, int load, int data_only, const char* section_name) +{ + SFORMAT StateRegs[] = + { + SFVAR(clear_timeout), + + SFVAR(dtr), + + SFVAR(button), + SFVAR(button_post_mask), + SFVAR(accum_xdelta), + SFVAR(accum_ydelta), + + SFVAR(command_phase), + SFVAR(bitpos), + SFVAR(receive_buffer), + + SFVAR(command), + + SFARRAY(transmit_buffer, sizeof(transmit_buffer)), + SFVAR(transmit_pos), + SFVAR(transmit_count), + + SFEND + }; + int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name); + + if(load) + { + if((transmit_pos + transmit_count) > sizeof(transmit_buffer)) + { + transmit_pos = 0; + transmit_count = 0; + } + } + + return(ret); +} + + +void InputDevice_Mouse::UpdateInput(const void *data) +{ + accum_xdelta += (int32)MDFN_de32lsb((uint8*)data + 0); + accum_ydelta += (int32)MDFN_de32lsb((uint8*)data + 4); + + if(accum_xdelta > 30 * 127) accum_xdelta = 30 * 127; + if(accum_xdelta < 30 * -128) accum_xdelta = 30 * -128; + + if(accum_ydelta > 30 * 127) accum_ydelta = 30 * 127; + if(accum_ydelta < 30 * -128) accum_ydelta = 30 * -128; + + button |= *((uint8 *)data + 8); + button_post_mask = *((uint8 *)data + 8); + + //if(button) + // MDFN_DispMessage("Button\n"); + //printf("%d %d\n", accum_xdelta, accum_ydelta); +} + + +void InputDevice_Mouse::SetDTR(bool new_dtr) +{ + if(!dtr && new_dtr) + { + command_phase = 0; + bitpos = 0; + transmit_pos = 0; + transmit_count = 0; + } + else if(dtr && !new_dtr) + { + //if(bitpos || transmit_count) + // printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + } + + dtr = new_dtr; +} + +bool InputDevice_Mouse::Clock(bool TxD, int32 &dsr_pulse_delay) +{ + bool ret = 1; + + dsr_pulse_delay = 0; + + if(!dtr) + return(1); + + if(transmit_count) + ret = (transmit_buffer[transmit_pos] >> bitpos) & 1; + + receive_buffer &= ~(1 << bitpos); + receive_buffer |= TxD << bitpos; + bitpos = (bitpos + 1) & 0x7; + + if(!bitpos) + { + //printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase); + + if(transmit_count) + { + transmit_pos++; + transmit_count--; + } + + + switch(command_phase) + { + case 0: + if(receive_buffer != 0x01) + command_phase = -1; + else + { + transmit_buffer[0] = 0x12; + transmit_pos = 0; + transmit_count = 1; + command_phase++; + } + break; + + case 1: + command = receive_buffer; + command_phase++; + + transmit_buffer[0] = 0x5A; + + if(command == 0x42) + { + int32 xdelta = accum_xdelta; + int32 ydelta = accum_ydelta; + + if(xdelta < -128) xdelta = -128; + if(xdelta > 127) xdelta = 127; + + if(ydelta < -128) ydelta = -128; + if(ydelta > 127) ydelta = 127; + + transmit_buffer[1] = 0xFF; + transmit_buffer[2] = 0xFC ^ (button << 2); + transmit_buffer[3] = xdelta; + transmit_buffer[4] = ydelta; + + accum_xdelta -= xdelta; + accum_ydelta -= ydelta; + + button &= button_post_mask; + + transmit_pos = 0; + transmit_count = 5; + + clear_timeout = 0; + } + else + { + command_phase = -1; + transmit_pos = 0; + transmit_count = 0; + } + break; + + } + } + + if(!bitpos && transmit_count) + dsr_pulse_delay = 0x40; //0x100; + + return(ret); +} + +InputDevice *Device_Mouse_Create(void) +{ + return new InputDevice_Mouse(); +} + + +InputDeviceInputInfoStruct Device_Mouse_IDII[4] = +{ + { "x_axis", "X Axis", -1, IDIT_X_AXIS_REL }, + { "y_axis", "Y Axis", -1, IDIT_Y_AXIS_REL }, + { "right", "Right Button", 1, IDIT_BUTTON, NULL }, + { "left", "Left Button", 0, IDIT_BUTTON, NULL }, +}; + + + +} diff --git a/psx/octoshock/psx/input/mouse.h b/psx/octoshock/psx/input/mouse.h new file mode 100644 index 0000000000..2597a75f31 --- /dev/null +++ b/psx/octoshock/psx/input/mouse.h @@ -0,0 +1,11 @@ +#ifndef __MDFN_PSX_INPUT_MOUSE_H +#define __MDFN_PSX_INPUT_MOUSE_H + +namespace MDFN_IEN_PSX +{ + +InputDevice *Device_Mouse_Create(void); +extern InputDeviceInputInfoStruct Device_Mouse_IDII[4]; + +} +#endif diff --git a/psx/octoshock/psx/input/multitap.cpp b/psx/octoshock/psx/input/multitap.cpp new file mode 100644 index 0000000000..4ec530b64e --- /dev/null +++ b/psx/octoshock/psx/input/multitap.cpp @@ -0,0 +1,434 @@ +/* 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 "../psx.h" +#include "../frontio.h" +#include "multitap.h" + +/* + TODO: PS1 multitap appears to have some internal knowledge of controller IDs, so it won't get "stuck" waiting for data from a controller that'll never + come. We currently sort of "cheat" due to how the dsr_pulse_delay stuff works, but in the future we should try to emulate this multitap functionality. + + Also, full-mode read startup and subport controller ID read timing isn't quite right, so we should fix that too. +*/ + +/* + Notes from tests on real thing(not necessarily emulated the same way here): + + Manual port selection read mode: + Write 0x01-0x04 instead of 0x01 as first byte, selects port(1=A,2=B,3=C,4=D) to access. + + Ports that don't exist(0x00, 0x05-0xFF) or don't have a device plugged in will not respond(no DSR pulse). + + Full read mode: + Bit0 of third byte(from-zero-index=0x02) should be set to 1 to enter full read mode, on subsequent reads. + + Appears to require a controller to be plugged into the port specified by the first byte as per manual port selection read mode, + to write the byte necessary to enter full-read mode; but once the third byte with the bit set has been written, no controller in + that port is required for doing full reads(and the manual port selection is ignored when doing a full read). + + However, if there are no controllers plugged in, the returned data will be short: + % 0: 0xff + % 1: 0x80 + % 2: 0x5a + + Example full-read bytestream(with controllers plugged into port A, port B, and port C, with port D empty): + % 0: 0xff + % 1: 0x80 + % 2: 0x5a + + % 3: 0x73 (Port A controller data start) + % 4: 0x5a + % 5: 0xff + % 6: 0xff + % 7: 0x80 + % 8: 0x8c + % 9: 0x79 + % 10: 0x8f + + % 11: 0x53 (Port B controller data start) + % 12: 0x5a + % 13: 0xff + % 14: 0xff + % 15: 0x80 + % 16: 0x80 + % 17: 0x75 + % 18: 0x8e + + % 19: 0x41 (Port C controller data start) + % 20: 0x5a + % 21: 0xff + % 22: 0xff + % 23: 0xff + % 24: 0xff + % 25: 0xff + % 26: 0xff + + % 27: 0xff (Port D controller data start) + % 28: 0xff + % 29: 0xff + % 30: 0xff + % 31: 0xff + % 32: 0xff + % 33: 0xff + % 34: 0xff + +*/ + +namespace MDFN_IEN_PSX +{ + +InputDevice_Multitap::InputDevice_Multitap() +{ + for(int i = 0; i < 4; i++) + { + pad_devices[i] = NULL; + mc_devices[i] = NULL; + } + Power(); +} + +InputDevice_Multitap::~InputDevice_Multitap() +{ +} + +void InputDevice_Multitap::SetSubDevice(unsigned int sub_index, InputDevice *device, InputDevice *mc_device) +{ + assert(sub_index < 4); + + //printf("%d\n", sub_index); + + pad_devices[sub_index] = device; + mc_devices[sub_index] = mc_device; +} + + +void InputDevice_Multitap::Power(void) +{ + selected_device = -1; + bit_counter = 0; + receive_buffer = 0; + byte_counter = 0; + + mc_mode = false; + full_mode = false; + full_mode_setting = false; + + fm_dp = 0; + memset(fm_buffer, 0, sizeof(fm_buffer)); + fm_deferred_error_temp = false; + fm_deferred_error = false; + fm_command_error = false; + + for(int i = 0; i < 4; i++) + { + if(pad_devices[i]) + pad_devices[i]->Power(); + + if(mc_devices[i]) + mc_devices[i]->Power(); + } +} + +int InputDevice_Multitap::StateAction(StateMem* sm, int load, int data_only, const char* section_name) +{ + SFORMAT StateRegs[] = + { + SFVAR(dtr), + + SFVAR(selected_device), + SFVAR(full_mode_setting), + + SFVAR(full_mode), + SFVAR(mc_mode), + + SFVAR(fm_dp), + SFARRAY(&fm_buffer[0][0], sizeof(fm_buffer) / sizeof(fm_buffer[0][0])), + + SFVAR(fm_deferred_error_temp), + SFVAR(fm_deferred_error), + SFVAR(fm_command_error), + + SFVAR(command), + SFVAR(receive_buffer), + SFVAR(bit_counter), + SFVAR(byte_counter), + + SFEND + }; + int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name); + + if(load) + { + + } + + return(ret); +} + + +void InputDevice_Multitap::SetDTR(bool new_dtr) +{ + bool old_dtr = dtr; + dtr = new_dtr; + + if(!dtr) + { + if(old_dtr) + { + //printf("Multitap stop.\n"); + } + + bit_counter = 0; + receive_buffer = 0; + selected_device = -1; + mc_mode = false; + full_mode = false; + } + + if(!old_dtr && dtr) + { + full_mode = full_mode_setting; + + byte_counter = 0; + + //if(full_mode) + // printf("Multitap start: %d\n", full_mode); + } + + for(int i = 0; i < 4; i++) + { + pad_devices[i]->SetDTR(dtr); + mc_devices[i]->SetDTR(dtr); + } +} + +bool InputDevice_Multitap::GetDSR(void) +{ + return(0); +} + +bool InputDevice_Multitap::Clock(bool TxD, int32 &dsr_pulse_delay) +{ + if(!dtr) + return(1); + + bool ret = 1; + int32 tmp_pulse_delay[2][4] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }; + + //printf("Receive bit: %d\n", TxD); + //printf("TxD %d\n", TxD); + + receive_buffer &= ~ (1 << bit_counter); + receive_buffer |= TxD << bit_counter; + + if(1) + { + if(byte_counter == 0) + { + bool mangled_txd = TxD; + + if(bit_counter < 4) + mangled_txd = (0x01 >> bit_counter) & 1; + + for(unsigned i = 0; i < 4; i++) + { + pad_devices[i]->Clock(mangled_txd, tmp_pulse_delay[0][i]); + mc_devices[i]->Clock(mangled_txd, tmp_pulse_delay[1][i]); + } + } + else + { + if(full_mode) + { + if(byte_counter == 1) + { + ret = (0x80 >> bit_counter) & 1; + + for(unsigned i = 0; i < 4; i++) + { + fm_buffer[i][0] &= (pad_devices[i]->Clock(TxD, tmp_pulse_delay[0][i]) << bit_counter) | (~(1U << bit_counter)); + } + } + else if(byte_counter == 2) + { + ret = (0x5A >> bit_counter) & 1; + } + // || byte_counter == (0x03 + 0x08 * 1) || byte_counter == (0x03 + 0x08 * 2) || byte_counter == (0x03 + 0x08 * 3)) + else if(byte_counter >= 0x03 && byte_counter < 0x03 + 0x08 * 4) + { + if(!fm_command_error && byte_counter >= (0x03 + 1) && byte_counter < (0x03 + 0x08)) + { + for(unsigned i = 0; i < 4; i++) + { + fm_buffer[i][byte_counter - 0x03] &= (pad_devices[i]->Clock(0, tmp_pulse_delay[0][i]) << bit_counter) | (~(1U << bit_counter)); + } + } + ret &= ((&fm_buffer[0][0])[byte_counter - 0x03] >> bit_counter) & 1; + } + } + else // to if(full_mode) + { + if((unsigned)selected_device < 4) + { + ret &= pad_devices[selected_device]->Clock(TxD, tmp_pulse_delay[0][selected_device]); + ret &= mc_devices[selected_device]->Clock(TxD, tmp_pulse_delay[1][selected_device]); + } + } + } // end else to if(byte_counter == 0) + } + + // + // + // + + bit_counter = (bit_counter + 1) & 0x7; + if(bit_counter == 0) + { + //printf("Receive: 0x%02x\n", receive_buffer); + if(byte_counter == 0) + { + mc_mode = (bool)(receive_buffer & 0xF0); + if(mc_mode) + full_mode = false; + + //printf("Zoomba: 0x%02x\n", receive_buffer); + //printf("Full mode: %d %d %d\n", full_mode, bit_counter, byte_counter); + + if(full_mode) + { + memset(fm_buffer, 0xFF, sizeof(fm_buffer)); + selected_device = 0; + } + else + { + //printf("Device select: %02x\n", receive_buffer); + fm_deferred_error = false; + selected_device = ((receive_buffer & 0xF) - 1) & 0xFF; + } + } + + if(byte_counter == 1) + { + command = receive_buffer; + + //printf("Multitap sub-command: %02x\n", command); + + if(full_mode) + { + if(command != 0x42) + fm_command_error = true; + else + fm_command_error = fm_deferred_error; + } + else + { + fm_command_error = false; + } + fm_deferred_error = false; + } + + if((!mc_mode || full_mode) && byte_counter == 2) + { + //printf("Full mode setting: %02x\n", receive_buffer); + full_mode_setting = receive_buffer & 0x01; + } + + if(full_mode) + { + if(byte_counter == (3 + 8 * 0) || byte_counter == (3 + 8 * 1) || byte_counter == (3 + 8 * 2) || byte_counter == (3 + 8 * 3)) + { + unsigned index = (byte_counter - 3) >> 3; + assert(index < 4); + + if(index == 0) + fm_deferred_error_temp = false; + + if((fm_dp & (1U << index)) && receive_buffer != 0x42) + { + //printf("Multitap command check failed: %u, 0x%02x\n", byte_counter, receive_buffer); + fm_deferred_error_temp = true; + } + } + + if(byte_counter == 33) + fm_deferred_error = fm_deferred_error_temp; + } + + // Handle DSR stuff + if(full_mode) + { + if(byte_counter == 0) // Next byte: 0x80 + { + dsr_pulse_delay = 1000; + + fm_dp = 0; + for(unsigned i = 0; i < 4; i++) + fm_dp |= (((bool)(tmp_pulse_delay[0][i])) << i); + } + else if(byte_counter == 1) // Next byte: 0x5A + dsr_pulse_delay = 0x40; + else if(byte_counter == 2) // Next byte(typically, controller-dependent): 0x41 + { + if(fm_dp) + dsr_pulse_delay = 0x40; + else + dsr_pulse_delay = 0; + } + else if(byte_counter >= 3 && byte_counter < 34) // Next byte when byte_counter==3 (typically, controller-dependent): 0x5A + { + if(byte_counter < 10) + { + int d = 0x40; + + for(unsigned i = 0; i < 4; i++) + if(tmp_pulse_delay[0][i] > d) + d = tmp_pulse_delay[0][i]; + + dsr_pulse_delay = d; + } + else + dsr_pulse_delay = 0x20; + + if(byte_counter == 3 && fm_command_error) + dsr_pulse_delay = 0; + } + } // end if(full_mode) + else + { + if((unsigned)selected_device < 4) + { + dsr_pulse_delay = std::max(tmp_pulse_delay[0][selected_device], tmp_pulse_delay[1][selected_device]); + } + } + + + // + // + // + + //printf("Byte Counter Increment\n"); + if(byte_counter < 255) + byte_counter++; + } + + + + return(ret); +} + +} diff --git a/psx/octoshock/psx/input/multitap.h b/psx/octoshock/psx/input/multitap.h new file mode 100644 index 0000000000..4736d1b269 --- /dev/null +++ b/psx/octoshock/psx/input/multitap.h @@ -0,0 +1,53 @@ +#ifndef __MDFN_PSX_INPUT_MULTITAP_H +#define __MDFN_PSX_INPUT_MULTITAP_H + +namespace MDFN_IEN_PSX +{ + +class InputDevice_Multitap : public InputDevice +{ + public: + + InputDevice_Multitap(); + virtual ~InputDevice_Multitap(); + virtual void Power(void); + virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name); + + void SetSubDevice(unsigned int sub_index, InputDevice *device, InputDevice *mc_device); + + // + // + // + virtual void SetDTR(bool new_dtr); + virtual bool GetDSR(void); + virtual bool Clock(bool TxD, int32 &dsr_pulse_delay); + + private: + + InputDevice *pad_devices[4]; + InputDevice *mc_devices[4]; + + bool dtr; + + int selected_device; + bool full_mode_setting; + + bool full_mode; + bool mc_mode; + + uint8 fm_dp; // Device-present. + uint8 fm_buffer[4][8]; + + bool fm_deferred_error_temp; + bool fm_deferred_error; + bool fm_command_error; + + uint8 command; + uint8 receive_buffer; + uint8 bit_counter; + uint8 byte_counter; +}; + +} + +#endif diff --git a/psx/octoshock/psx/input/negcon.cpp b/psx/octoshock/psx/input/negcon.cpp new file mode 100644 index 0000000000..fc6f2633ae --- /dev/null +++ b/psx/octoshock/psx/input/negcon.cpp @@ -0,0 +1,297 @@ +/* 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 "../psx.h" +#include "../frontio.h" +#include "negcon.h" + +namespace MDFN_IEN_PSX +{ + +class InputDevice_neGcon : public InputDevice +{ + public: + + InputDevice_neGcon(void); + virtual ~InputDevice_neGcon(); + + virtual void Power(void); + virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name); + virtual void UpdateInput(const void *data); + + // + // + // + virtual void SetDTR(bool new_dtr); + virtual bool GetDSR(void); + virtual bool Clock(bool TxD, int32 &dsr_pulse_delay); + + private: + + bool dtr; + + uint8 buttons[2]; + uint8 twist; + uint8 anabuttons[3]; + + int32 command_phase; + uint32 bitpos; + uint8 receive_buffer; + + uint8 command; + + uint8 transmit_buffer[8]; + uint32 transmit_pos; + uint32 transmit_count; +}; + +InputDevice_neGcon::InputDevice_neGcon(void) +{ + Power(); +} + +InputDevice_neGcon::~InputDevice_neGcon() +{ + +} + +void InputDevice_neGcon::Power(void) +{ + dtr = 0; + + buttons[0] = buttons[1] = 0; + twist = 0; + anabuttons[0] = 0; + anabuttons[1] = 0; + anabuttons[2] = 0; + + command_phase = 0; + + bitpos = 0; + + receive_buffer = 0; + + command = 0; + + memset(transmit_buffer, 0, sizeof(transmit_buffer)); + + transmit_pos = 0; + transmit_count = 0; +} + +int InputDevice_neGcon::StateAction(StateMem* sm, int load, int data_only, const char* section_name) +{ + SFORMAT StateRegs[] = + { + SFVAR(dtr), + + SFARRAY(buttons, sizeof(buttons)), + SFVAR(twist), + SFARRAY(anabuttons, sizeof(anabuttons)), + + SFVAR(command_phase), + SFVAR(bitpos), + SFVAR(receive_buffer), + + SFVAR(command), + + SFARRAY(transmit_buffer, sizeof(transmit_buffer)), + SFVAR(transmit_pos), + SFVAR(transmit_count), + + SFEND + }; + int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name); + + if(load) + { + if((transmit_pos + transmit_count) > sizeof(transmit_buffer)) + { + transmit_pos = 0; + transmit_count = 0; + } + } + + return(ret); +} + + +void InputDevice_neGcon::UpdateInput(const void *data) +{ + uint8 *d8 = (uint8 *)data; + + buttons[0] = d8[0]; + buttons[1] = d8[1]; + + twist = ((32768 + MDFN_de16lsb((const uint8 *)data + 2) - (((int32)MDFN_de16lsb((const uint8 *)data + 4) * 32768 + 16383) / 32767)) * 255 + 32767) / 65535; + + anabuttons[0] = (MDFN_de16lsb((const uint8 *)data + 6) * 255 + 16383) / 32767; + anabuttons[1] = (MDFN_de16lsb((const uint8 *)data + 8) * 255 + 16383) / 32767; + anabuttons[2] = (MDFN_de16lsb((const uint8 *)data + 10) * 255 + 16383) / 32767; + + //printf("%02x %02x %02x %02x\n", twist, anabuttons[0], anabuttons[1], anabuttons[2]); +} + + +void InputDevice_neGcon::SetDTR(bool new_dtr) +{ + if(!dtr && new_dtr) + { + command_phase = 0; + bitpos = 0; + transmit_pos = 0; + transmit_count = 0; + } + else if(dtr && !new_dtr) + { + //if(bitpos || transmit_count) + // printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + } + + dtr = new_dtr; +} + +bool InputDevice_neGcon::GetDSR(void) +{ + if(!dtr) + return(0); + + if(!bitpos && transmit_count) + return(1); + + return(0); +} + +bool InputDevice_neGcon::Clock(bool TxD, int32 &dsr_pulse_delay) +{ + bool ret = 1; + + dsr_pulse_delay = 0; + + if(!dtr) + return(1); + + if(transmit_count) + ret = (transmit_buffer[transmit_pos] >> bitpos) & 1; + + receive_buffer &= ~(1 << bitpos); + receive_buffer |= TxD << bitpos; + bitpos = (bitpos + 1) & 0x7; + + if(!bitpos) + { + //printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase); + + if(transmit_count) + { + transmit_pos++; + transmit_count--; + } + + + switch(command_phase) + { + case 0: + if(receive_buffer != 0x01) + command_phase = -1; + else + { + transmit_buffer[0] = 0x23; + transmit_pos = 0; + transmit_count = 1; + command_phase++; + dsr_pulse_delay = 256; + } + break; + + case 1: + command = receive_buffer; + command_phase++; + + transmit_buffer[0] = 0x5A; + + //if(command != 0x42) + // fprintf(stderr, "Gamepad unhandled command: 0x%02x\n", command); + + if(command == 0x42) + { + transmit_buffer[1] = 0xFF ^ buttons[0]; + transmit_buffer[2] = 0xFF ^ buttons[1]; + transmit_buffer[3] = twist; // Twist, 0x00 through 0xFF, 0x80 center. + transmit_buffer[4] = anabuttons[0]; // Analog button I, 0x00 through 0xFF, 0x00 = no pressing, 0xFF = max. + transmit_buffer[5] = anabuttons[1]; // Analog button II, "" + transmit_buffer[6] = anabuttons[2]; // Left shoulder analog button, "" + transmit_pos = 0; + transmit_count = 7; + dsr_pulse_delay = 256; + } + else + { + command_phase = -1; + transmit_buffer[1] = 0; + transmit_buffer[2] = 0; + transmit_pos = 0; + transmit_count = 0; + } + break; + + case 2: + if(transmit_count > 0) + dsr_pulse_delay = 128; + break; + } + } + + return(ret); +} + +InputDevice *Device_neGcon_Create(void) +{ + return new InputDevice_neGcon(); +} + + +InputDeviceInputInfoStruct Device_neGcon_IDII[21] = +{ + { NULL, "empty", -1, IDIT_BUTTON, NULL }, + { NULL, "empty", -1, IDIT_BUTTON, NULL }, + { NULL, "empty", -1, IDIT_BUTTON, NULL }, + { "start", "START", 4, IDIT_BUTTON, NULL }, + { "up", "D-Pad UP ↑", 0, IDIT_BUTTON, "down" }, + { "right", "D-Pad RIGHT →", 3, IDIT_BUTTON, "left" }, + { "down", "D-Pad DOWN ↓", 1, IDIT_BUTTON, "up" }, + { "left", "D-Pad LEFT ←", 2, IDIT_BUTTON, "right" }, + + { NULL, "empty", -1, IDIT_BUTTON, NULL }, + { NULL, "empty", -1, IDIT_BUTTON, NULL }, + { NULL, "empty", -1, IDIT_BUTTON, NULL }, + { "r", "Right Shoulder", 12, IDIT_BUTTON }, + + { "b", "B", 9, IDIT_BUTTON, NULL }, + { "a", "A", 10, IDIT_BUTTON, NULL }, + { NULL, "empty", -1, IDIT_BUTTON, NULL }, + { NULL, "empty", -1, IDIT_BUTTON, NULL }, + + { "twist_cwise", "Twist ↓|↑ (Analog, Turn Right)", 6, IDIT_BUTTON_ANALOG }, + { "twist_ccwise", "Twist ↑|↓ (Analog, Turn Left)", 5, IDIT_BUTTON_ANALOG }, + { "i", "I (Analog)", 8, IDIT_BUTTON_ANALOG }, + { "ii", "II (Analog)", 7, IDIT_BUTTON_ANALOG }, + + { "l", "Left Shoulder (Analog)", 11, IDIT_BUTTON_ANALOG }, +}; + +} diff --git a/psx/octoshock/psx/input/negcon.h b/psx/octoshock/psx/input/negcon.h new file mode 100644 index 0000000000..0091fec476 --- /dev/null +++ b/psx/octoshock/psx/input/negcon.h @@ -0,0 +1,9 @@ +#ifndef __MDFN_PSX_INPUT_NEGCON_H +#define __MDFN_PSX_INPUT_NEGCON_H + +namespace MDFN_IEN_PSX +{ + InputDevice *Device_neGcon_Create(void); + extern InputDeviceInputInfoStruct Device_neGcon_IDII[21]; +} +#endif diff --git a/psx/octoshock/psx/irq.cpp b/psx/octoshock/psx/irq.cpp new file mode 100644 index 0000000000..20a36c7a13 --- /dev/null +++ b/psx/octoshock/psx/irq.cpp @@ -0,0 +1,174 @@ +/* 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 "psx.h" + +namespace MDFN_IEN_PSX +{ + +static uint16 Asserted; +static uint16 Mask; +static uint16 Status; + +static INLINE void Recalc(void) +{ + CPU->AssertIRQ(0, (bool)(Status & Mask)); +} + +void IRQ_Power(void) +{ + Asserted = 0; + Status = 0; + Mask = 0; + + Recalc(); +} + +int IRQ_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFVAR(Asserted), + SFVAR(Mask), + SFVAR(Status), + SFEND + }; + int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "IRQ"); + + if(load) + { + Recalc(); + } + + return(ret); +} + + +void IRQ_Assert(int which, bool status) +{ + uint32 old_Asserted = Asserted; + //PSX_WARNING("[IRQ] Assert: %d %d", which, status); + + //if(which == IRQ_SPU && status && (Asserted & (1 << which))) + // MDFN_DispMessage("SPU IRQ glitch??"); + + Asserted &= ~(1 << which); + + if(status) + { + Asserted |= 1 << which; + //Status |= 1 << which; + Status |= (old_Asserted ^ Asserted) & Asserted; + } + + Recalc(); +} + + +void IRQ_Write(uint32 A, uint32 V) +{ + // FIXME if we ever have "accurate" bus emulation + V <<= (A & 3) * 8; + + //printf("[IRQ] Write: 0x%08x 0x%08x --- PAD TEMP\n", A, V); + + if(A & 4) + Mask = V; + else + { + Status &= V; + //Status |= Asserted; + } + + Recalc(); +} + + +uint32 IRQ_Read(uint32 A) +{ + uint32 ret = 0; + + if(A & 4) + ret = Mask; + else + ret = Status; + + // FIXME: Might want to move this out to psx.cpp eventually. + ret |= 0x1F800000; + ret >>= (A & 3) * 8; + + + //printf("[IRQ] Read: 0x%08x 0x%08x --- PAD TEMP\n", A, ret); + + return(ret); +} + + +void IRQ_Reset(void) +{ + Asserted = 0; + Status = 0; + Mask = 0; + + Recalc(); +} + + +uint32 IRQ_GetRegister(unsigned int which, char *special, const uint32 special_len) +{ + uint32 ret = 0; + + switch(which) + { + case IRQ_GSREG_ASSERTED: + ret = Asserted; + break; + + case IRQ_GSREG_STATUS: + ret = Status; + break; + + case IRQ_GSREG_MASK: + ret = Mask; + break; + } + return(ret); +} + +void IRQ_SetRegister(unsigned int which, uint32 value) +{ + switch(which) + { + case IRQ_GSREG_ASSERTED: + Asserted = value; + Recalc(); + break; + + case IRQ_GSREG_STATUS: + Status = value; + Recalc(); + break; + + case IRQ_GSREG_MASK: + Mask = value; + Recalc(); + break; + } +} + + +} diff --git a/psx/octoshock/psx/irq.h b/psx/octoshock/psx/irq.h new file mode 100644 index 0000000000..f716a40b9d --- /dev/null +++ b/psx/octoshock/psx/irq.h @@ -0,0 +1,43 @@ +#ifndef __MDFN_PSX_IRQ_H +#define __MDFN_PSX_IRQ_H + +namespace MDFN_IEN_PSX +{ + + +enum +{ + IRQ_VBLANK = 0, + IRQ_GPU = 1, + IRQ_CD = 2, + IRQ_DMA = 3, // Probably + IRQ_TIMER_0 = 4, + IRQ_TIMER_1 = 5, + IRQ_TIMER_2 = 6, + IRQ_SIO = 7, + IRQ_SPU = 9, + IRQ_PIO = 10, // Probably +}; + +void IRQ_Power(void); +void IRQ_Assert(int which, bool asserted); + +void IRQ_Write(uint32 A, uint32 V); +uint32 IRQ_Read(uint32 A); + + +enum +{ + IRQ_GSREG_ASSERTED = 0, + IRQ_GSREG_STATUS = 1, + IRQ_GSREG_MASK = 2 +}; + +uint32 IRQ_GetRegister(unsigned int which, char *special, const uint32 special_len); +void IRQ_SetRegister(unsigned int which, uint32 value); + +int IRQ_StateAction(StateMem *sm, int load, int data_only); +}; + + +#endif diff --git a/psx/octoshock/psx/mdec.cpp b/psx/octoshock/psx/mdec.cpp new file mode 100644 index 0000000000..3e3f366027 --- /dev/null +++ b/psx/octoshock/psx/mdec.cpp @@ -0,0 +1,820 @@ +/* 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 + */ + +/* + MDEC_READ_FIFO(tfr) vs InCounter vs MDEC_DMACanRead() is a bit fragile right now. Actually, the entire horrible state machine monstrosity is fragile. + + TODO: OutFIFOReady, so <16bpp works right. + + TODO CODE: + + bool InFIFOReady; + + if(InFIFO.CanWrite()) + { + InFIFO.WriteUnit(V); + + if(InCommand) + { + if(InCounter != 0xFFFF) + { + InCounter--; + + // This condition when InFIFO.CanWrite() != 0 is a bit buggy on real hardware, decoding loop *seems* to be reading too + // much and pulling garbage from the FIFO. + if(InCounter == 0xFFFF) + InFIFOReady = true; + } + + if(InFIFO.CanWrite() == 0) + InFIFOReady = true; + } + } +*/ + +// Good test-case games: +// Dragon Knight 4(bad disc?) +// Final Fantasy 7 intro movie. +// GameShark Version 4.0 intro movie; (clever) abuse of DMA channel 0. +// SimCity 2000 startup. + + +#include + +#include "psx.h" +#include "mdec.h" + +#include "masmem.h" +#include "cdrom/SimpleFIFO.h" + +#if defined(__SSE2__) +#include +#include +#endif + +#if defined(ARCH_POWERPC_ALTIVEC) && defined(HAVE_ALTIVEC_H) + #include +#endif + +namespace MDFN_IEN_PSX +{ + +static int32 ClockCounter; +static unsigned MDRPhase; +static SimpleFIFO InFIFO(0x20); +static SimpleFIFO OutFIFO(0x20); + +static int8 block_y[8][8]; +static int8 block_cb[8][8]; // [y >> 1][x >> 1] +static int8 block_cr[8][8]; // [y >> 1][x >> 1] + +static uint32 Control; +static uint32 Command; +static bool InCommand; + +static uint8 QMatrix[2][64]; +static uint32 QMIndex; + +static EW_VAR_ALIGN(16) int16 IDCTMatrix[64]; +static uint32 IDCTMIndex; + +static uint8 QScale; + +static EW_VAR_ALIGN(16) int16 Coeff[64]; +static uint32 CoeffIndex; +static uint32 DecodeWB; + +static union +{ + uint32 pix32[48]; + uint16 pix16[96]; + uint8 pix8[192]; +} PixelBuffer; +static uint32 PixelBufferReadOffset; +static uint32 PixelBufferCount32; + +static uint16 InCounter; + +static uint8 RAMOffsetY; +static uint8 RAMOffsetCounter; +static uint8 RAMOffsetWWS; + +static const uint8 ZigZag[64] = +{ + 0x00, 0x08, 0x01, 0x02, 0x09, 0x10, 0x18, 0x11, + 0x0a, 0x03, 0x04, 0x0b, 0x12, 0x19, 0x20, 0x28, + 0x21, 0x1a, 0x13, 0x0c, 0x05, 0x06, 0x0d, 0x14, + 0x1b, 0x22, 0x29, 0x30, 0x38, 0x31, 0x2a, 0x23, + 0x1c, 0x15, 0x0e, 0x07, 0x0f, 0x16, 0x1d, 0x24, + 0x2b, 0x32, 0x39, 0x3a, 0x33, 0x2c, 0x25, 0x1e, + 0x17, 0x1f, 0x26, 0x2d, 0x34, 0x3b, 0x3c, 0x35, + 0x2e, 0x27, 0x2f, 0x36, 0x3d, 0x3e, 0x37, 0x3f, +}; + +void MDEC_Power(void) +{ + ClockCounter = 0; + MDRPhase = 0; + + InFIFO.Flush(); + OutFIFO.Flush(); + + memset(block_y, 0, sizeof(block_y)); + memset(block_cb, 0, sizeof(block_cb)); + memset(block_cr, 0, sizeof(block_cr)); + + Control = 0; + Command = 0; + InCommand = false; + + memset(QMatrix, 0, sizeof(QMatrix)); + QMIndex = 0; + + memset(IDCTMatrix, 0, sizeof(IDCTMatrix)); + IDCTMIndex = 0; + + QScale = 0; + + memset(Coeff, 0, sizeof(Coeff)); + CoeffIndex = 0; + DecodeWB = 0; + + memset(PixelBuffer.pix32, 0, sizeof(PixelBuffer.pix32)); + PixelBufferReadOffset = 0; + PixelBufferCount32 = 0; + + InCounter = 0; + + RAMOffsetY = 0; + RAMOffsetCounter = 0; + RAMOffsetWWS = 0; +} + +int MDEC_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFVAR(ClockCounter), + SFVAR(MDRPhase), + +#define SFFIFO32(fifoobj) SFARRAY32(&fifoobj.data[0], fifoobj.data.size()), \ + SFVAR(fifoobj.read_pos), \ + SFVAR(fifoobj.write_pos), \ + SFVAR(fifoobj.in_count) + + SFFIFO32(InFIFO), + SFFIFO32(OutFIFO), +#undef SFFIFO + + SFARRAY(&block_y[0][0], sizeof(block_y) / sizeof(block_y[0][0])), + SFARRAY(&block_cb[0][0], sizeof(block_cb) / sizeof(block_cb[0][0])), + SFARRAY(&block_cr[0][0], sizeof(block_cr) / sizeof(block_cr[0][0])), + + SFVAR(Control), + SFVAR(Command), + SFVAR(InCommand), + + SFARRAY(&QMatrix[0][0], sizeof(QMatrix) / sizeof(QMatrix[0][0])), + SFVAR(QMIndex), + + SFARRAY16(&IDCTMatrix[0], sizeof(IDCTMatrix) / sizeof(IDCTMatrix[0])), + SFVAR(IDCTMIndex), + + SFVAR(QScale), + + SFARRAY16(&Coeff[0], sizeof(Coeff) / sizeof(Coeff[0])), + SFVAR(CoeffIndex), + SFVAR(DecodeWB), + + SFARRAY32(&PixelBuffer.pix32[0], sizeof(PixelBuffer.pix32) / sizeof(PixelBuffer.pix32[0])), + SFVAR(PixelBufferReadOffset), + SFVAR(PixelBufferCount32), + + SFVAR(InCounter), + + SFVAR(RAMOffsetY), + SFVAR(RAMOffsetCounter), + SFVAR(RAMOffsetWWS), + + SFEND + }; + + int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "MDEC"); + + if(load) + { + InFIFO.SaveStatePostLoad(); + OutFIFO.SaveStatePostLoad(); + } + + return(ret); +} + +static INLINE int8 Mask9ClampS8(int32 v) +{ + v = sign_x_to_s32(9, v); + + if(v < -128) + v = -128; + + if(v > 127) + v = 127; + + return v; +} + +template +static void IDCT_1D_Multi(int16 *in_coeff, T *out_coeff) +{ +#if defined(__SSE2__) +{ + for(unsigned col = 0; col < 8; col++) + { + __m128i c = _mm_load_si128((__m128i *)&in_coeff[(col * 8)]); + + for(unsigned x = 0; x < 8; x++) + { + __m128i sum; + __m128i m; + int32 tmp[4] MDFN_ALIGN(16); + + m = _mm_load_si128((__m128i *)&IDCTMatrix[(x * 8)]); + sum = _mm_madd_epi16(m, c); + sum = _mm_add_epi32(sum, _mm_shuffle_epi32(sum, (3 << 0) | (2 << 2) | (1 << 4) | (0 << 6))); + sum = _mm_add_epi32(sum, _mm_shuffle_epi32(sum, (1 << 0) | (0 << 2))); + + //_mm_store_ss((float *)&tmp[0], (__m128)sum); + _mm_store_si128((__m128i*)tmp, sum); + + if(sizeof(T) == 1) + out_coeff[(col * 8) + x] = Mask9ClampS8((tmp[0] + 0x4000) >> 15); + else + out_coeff[(x * 8) + col] = (tmp[0] + 0x4000) >> 15; + } + } +} +#else + for(unsigned col = 0; col < 8; col++) + { + for(unsigned x = 0; x < 8; x++) + { + int32 sum = 0; + + for(unsigned u = 0; u < 8; u++) + { + sum += (in_coeff[(col * 8) + u] * IDCTMatrix[(x * 8) + u]); + } + + if(sizeof(T) == 1) + out_coeff[(col * 8) + x] = Mask9ClampS8((sum + 0x4000) >> 15); + else + out_coeff[(x * 8) + col] = (sum + 0x4000) >> 15; + } + } +#endif +} + +static void IDCT(int16 *in_coeff, int8 *out_coeff) NO_INLINE; +static void IDCT(int16 *in_coeff, int8 *out_coeff) +{ + EW_VAR_ALIGN(16) int16 tmpbuf[64]; + + IDCT_1D_Multi(in_coeff, tmpbuf); + IDCT_1D_Multi(tmpbuf, out_coeff); +} + +static INLINE void YCbCr_to_RGB(const int8 y, const int8 cb, const int8 cr, int &r, int &g, int &b) +{ + // + // The formula for green is still a bit off(precision/rounding issues when both cb and cr are non-zero). + // + + r = Mask9ClampS8(y + (((359 * cr) + 0x80) >> 8)); + //g = Mask9ClampS8(y + (((-88 * cb) + (-183 * cr) + 0x80) >> 8)); + g = Mask9ClampS8(y + ((((-88 * cb) &~ 0x1F) + ((-183 * cr) &~ 0x07) + 0x80) >> 8)); + b = Mask9ClampS8(y + (((454 * cb) + 0x80) >> 8)); + + r ^= 0x80; + g ^= 0x80; + b ^= 0x80; +} + +static INLINE uint16 RGB_to_RGB555(uint8 r, uint8 g, uint8 b) +{ + r = (r + 4) >> 3; + g = (g + 4) >> 3; + b = (b + 4) >> 3; + + if(r > 0x1F) + r = 0x1F; + + if(g > 0x1F) + g = 0x1F; + + if(b > 0x1F) + b = 0x1F; + + return((r << 0) | (g << 5) | (b << 10)); +} + +static void EncodeImage(const unsigned ybn) +{ + //printf("ENCODE, %d\n", (Command & 0x08000000) ? 256 : 384); + + PixelBufferCount32 = 0; + + switch((Command >> 27) & 0x3) + { + case 0: // 4bpp + { + const uint8 us_xor = (Command & (1U << 26)) ? 0x00 : 0x88; + uint8* pix_out = PixelBuffer.pix8; + + for(int y = 0; y < 8; y++) + { + for(int x = 0; x < 8; x += 2) + { + uint8 p0 = std::min(127, block_y[y][x + 0] + 8); + uint8 p1 = std::min(127, block_y[y][x + 1] + 8); + + *pix_out = ((p0 >> 4) | (p1 & 0xF0)) ^ us_xor; + pix_out++; + } + } + PixelBufferCount32 = 8; + } + break; + + + case 1: // 8bpp + { + const uint8 us_xor = (Command & (1U << 26)) ? 0x00 : 0x80; + uint8* pix_out = PixelBuffer.pix8; + + for(int y = 0; y < 8; y++) + { + for(int x = 0; x < 8; x++) + { + *pix_out = (uint8)block_y[y][x] ^ us_xor; + pix_out++; + } + } + PixelBufferCount32 = 16; + } + break; + + case 2: // 24bpp + { + const uint8 rgb_xor = (Command & (1U << 26)) ? 0x80 : 0x00; + uint8* pix_out = PixelBuffer.pix8; + + for(int y = 0; y < 8; y++) + { + const int8* by = &block_y[y][0]; + const int8* cb = &block_cb[(y >> 1) | ((ybn & 2) << 1)][(ybn & 1) << 2]; + const int8* cr = &block_cr[(y >> 1) | ((ybn & 2) << 1)][(ybn & 1) << 2]; + + for(int x = 0; x < 8; x++) + { + int r, g, b; + + YCbCr_to_RGB(by[x], cb[x >> 1], cr[x >> 1], r, g, b); + + pix_out[0] = r ^ rgb_xor; + pix_out[1] = g ^ rgb_xor; + pix_out[2] = b ^ rgb_xor; + pix_out += 3; + } + } + PixelBufferCount32 = 48; + } + break; + + case 3: // 16bpp + { + uint16 pixel_xor = ((Command & 0x02000000) ? 0x8000 : 0x0000) | ((Command & (1U << 26)) ? 0x4210 : 0x0000); + uint16* pix_out = PixelBuffer.pix16; + + for(int y = 0; y < 8; y++) + { + const int8* by = &block_y[y][0]; + const int8* cb = &block_cb[(y >> 1) | ((ybn & 2) << 1)][(ybn & 1) << 2]; + const int8* cr = &block_cr[(y >> 1) | ((ybn & 2) << 1)][(ybn & 1) << 2]; + + for(int x = 0; x < 8; x++) + { + int r, g, b; + + YCbCr_to_RGB(by[x], cb[x >> 1], cr[x >> 1], r, g, b); + + StoreU16_LE(pix_out, pixel_xor ^ RGB_to_RGB555(r, g, b)); + pix_out++; + } + } + PixelBufferCount32 = 32; + } + break; + + } +} + +static INLINE void WriteImageData(uint16 V, int32* eat_cycles) +{ + const uint32 qmw = (bool)(DecodeWB < 2); + + //printf("MDEC DMA SubWrite: %04x, %d\n", V, CoeffIndex); + + if(!CoeffIndex) + { + if(V == 0xFE00) + { + //printf("FE00 @ %u\n", DecodeWB); + return; + } + + QScale = V >> 10; + + { + int q = QMatrix[qmw][0]; // No QScale here! + int ci = sign_10_to_s16(V & 0x3FF); + int tmp; + + if(q != 0) + tmp = ((ci * q) << 4) + (ci ? ((ci < 0) ? 8 : -8) : 0); + else + tmp = (ci * 2) << 4; + + // Not sure if it should be 0x3FFF or 0x3FF0 or maybe 0x3FF8? + Coeff[ZigZag[0]] = std::min(0x3FFF, std::max(-0x4000, tmp)); + CoeffIndex++; + } + } + else + { + if(V == 0xFE00) + { + while(CoeffIndex < 64) + Coeff[ZigZag[CoeffIndex++]] = 0; + } + else + { + uint32 rlcount = V >> 10; + + for(uint32 i = 0; i < rlcount && CoeffIndex < 64; i++) + { + Coeff[ZigZag[CoeffIndex]] = 0; + CoeffIndex++; + } + + if(CoeffIndex < 64) + { + int q = QScale * QMatrix[qmw][CoeffIndex]; + int ci = sign_10_to_s16(V & 0x3FF); + int tmp; + + if(q != 0) + tmp = (((ci * q) >> 3) << 4) + (ci ? ((ci < 0) ? 8 : -8) : 0); + else + tmp = (ci * 2) << 4; + + // Not sure if it should be 0x3FFF or 0x3FF0 or maybe 0x3FF8? + Coeff[ZigZag[CoeffIndex]] = std::min(0x3FFF, std::max(-0x4000, tmp)); + CoeffIndex++; + } + } + } + + if(CoeffIndex == 64) + { + CoeffIndex = 0; + + //printf("Block %d finished\n", DecodeWB); + + switch(DecodeWB) + { + case 0: IDCT(Coeff, &block_cr[0][0]); break; + case 1: IDCT(Coeff, &block_cb[0][0]); break; + case 2: IDCT(Coeff, &block_y[0][0]); break; + case 3: IDCT(Coeff, &block_y[0][0]); break; + case 4: IDCT(Coeff, &block_y[0][0]); break; + case 5: IDCT(Coeff, &block_y[0][0]); break; + } + + // + // Approximate, actual timing seems to be a bit complex. + // + *eat_cycles += 341; + + if(DecodeWB >= 2) + { + EncodeImage((DecodeWB + 4) % 6); + } + + DecodeWB++; + if(DecodeWB == (((Command >> 27) & 2) ? 6 : 3)) + { + DecodeWB = ((Command >> 27) & 2) ? 0 : 2; + } + } +} + +#if 1 + +// +// +// +#define MDEC_WAIT_COND(n) { case __COUNTER__: if(!(n)) { MDRPhase = __COUNTER__ - MDRPhaseBias - 1; return; } } + +#define MDEC_WRITE_FIFO(n) { MDEC_WAIT_COND(OutFIFO.CanWrite()); OutFIFO.WriteUnit(n); } +#define MDEC_READ_FIFO(n) { MDEC_WAIT_COND(InFIFO.CanRead()); n = InFIFO.ReadUnit(); } +#define MDEC_EAT_CLOCKS(n) { ClockCounter -= (n); MDEC_WAIT_COND(ClockCounter > 0); } + +void MDEC_Run(int32 clocks) +{ + static const unsigned MDRPhaseBias = __COUNTER__ + 1; + + //MDFN_DispMessage("%u", OutFIFO.CanRead()); + + ClockCounter += clocks; + + if(ClockCounter > 128) + { + //if(MDRPhase != 0) + // printf("SNORT: %d\n", ClockCounter); + ClockCounter = 128; + } + + switch(MDRPhase + MDRPhaseBias) + { + for(;;) + { + InCommand = false; + MDEC_READ_FIFO(Command); // This must be the first MDEC_* macro used! + InCommand = true; + MDEC_EAT_CLOCKS(1); + + //printf("****************** Command: %08x, %02x\n", Command, Command >> 29); + + // + // + // + if(((Command >> 29) & 0x7) == 1) + { + InCounter = Command & 0xFFFF; + OutFIFO.Flush(); + //OutBuffer.Flush(); + + PixelBufferCount32 = 0; + CoeffIndex = 0; + + if((Command >> 27) & 2) + DecodeWB = 0; + else + DecodeWB = 2; + + switch((Command >> 27) & 0x3) + { + case 0: + case 1: RAMOffsetWWS = 0; break; + case 2: RAMOffsetWWS = 6; break; + case 3: RAMOffsetWWS = 4; break; + } + RAMOffsetY = 0; + RAMOffsetCounter = RAMOffsetWWS; + + InCounter--; + do + { + uint32 tfr; + int32 need_eat; // = 0; + + MDEC_READ_FIFO(tfr); + InCounter--; + +// printf("KA: %04x %08x\n", InCounter, tfr); + + need_eat = 0; + PixelBufferCount32 = 0; + WriteImageData(tfr, &need_eat); + WriteImageData(tfr >> 16, &need_eat); + + MDEC_EAT_CLOCKS(need_eat); + + PixelBufferReadOffset = 0; + while(PixelBufferReadOffset != PixelBufferCount32) + { + MDEC_WRITE_FIFO(LoadU32_LE(&PixelBuffer.pix32[PixelBufferReadOffset++])); + } + } while(InCounter != 0xFFFF); + } + // + // + // + else if(((Command >> 29) & 0x7) == 2) + { + QMIndex = 0; + InCounter = 0x10 + ((Command & 0x1) ? 0x10 : 0x00); + + InCounter--; + do + { + uint32 tfr; + + MDEC_READ_FIFO(tfr); + InCounter--; + + //printf("KA: %04x %08x\n", InCounter, tfr); + + for(int i = 0; i < 4; i++) + { + QMatrix[QMIndex >> 6][QMIndex & 0x3F] = (uint8)tfr; + QMIndex = (QMIndex + 1) & 0x7F; + tfr >>= 8; + } + } while(InCounter != 0xFFFF); + } + // + // + // + else if(((Command >> 29) & 0x7) == 3) + { + IDCTMIndex = 0; + InCounter = 0x20; + + InCounter--; + do + { + uint32 tfr; + + MDEC_READ_FIFO(tfr); + InCounter--; + + for(unsigned i = 0; i < 2; i++) + { + IDCTMatrix[((IDCTMIndex & 0x7) << 3) | ((IDCTMIndex >> 3) & 0x7)] = (int16)(tfr & 0xFFFF) >> 3; + IDCTMIndex = (IDCTMIndex + 1) & 0x3F; + + tfr >>= 16; + } + } while(InCounter != 0xFFFF); + } + else + { + InCounter = Command & 0xFFFF; + } + } // end for(;;) + } +} +#endif + +void MDEC_DMAWrite(uint32 V) +{ + if(InFIFO.CanWrite()) + { + InFIFO.WriteUnit(V); + MDEC_Run(0); + } + else + { + PSX_DBG(PSX_DBG_WARNING, "Input FIFO DMA write overflow?!\n"); + } +} + +uint32 MDEC_DMARead(int32* offs) +{ + uint32 V = 0; + + *offs = 0; + + if(MDFN_LIKELY(OutFIFO.CanRead())) + { + V = OutFIFO.ReadUnit(); + + *offs = (RAMOffsetY & 0x7) * RAMOffsetWWS; + + if(RAMOffsetY & 0x08) + { + *offs = (*offs - RAMOffsetWWS*7); + } + + RAMOffsetCounter--; + if(!RAMOffsetCounter) + { + RAMOffsetCounter = RAMOffsetWWS; + RAMOffsetY++; + } + } + else + { + PSX_DBG(PSX_DBG_WARNING, "[MDEC] BONUS GNOMES\n"); + V = rand(); + } + + return(V); +} + +bool MDEC_DMACanWrite(void) +{ + return((InFIFO.CanWrite() >= 0x20) && (Control & (1U << 30)) && InCommand && InCounter != 0xFFFF); +} + +bool MDEC_DMACanRead(void) +{ + return((OutFIFO.CanRead() >= 0x20) && (Control & (1U << 29))); +} + +void MDEC_Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V) +{ + //PSX_WARNING("[MDEC] Write: 0x%08x 0x%08x, %d --- %u %u", A, V, timestamp, InFIFO.CanRead(), OutFIFO.CanRead()); + if(A & 4) + { + if(V & 0x80000000) // Reset? + { + MDRPhase = 0; + InCounter = 0; + Command = 0; + InCommand = false; + + PixelBufferCount32 = 0; + ClockCounter = 0; + QMIndex = 0; + IDCTMIndex = 0; + + QScale = 0; + + memset(Coeff, 0, sizeof(Coeff)); + CoeffIndex = 0; + DecodeWB = 0; + + InFIFO.Flush(); + OutFIFO.Flush(); + } + Control = V & 0x7FFFFFFF; + } + else + { + if(InFIFO.CanWrite()) + { + InFIFO.WriteUnit(V); + + if(!InCommand) + { + if(ClockCounter < 1) + ClockCounter = 1; + } + MDEC_Run(0); + } + else + { + PSX_DBG(PSX_DBG_WARNING, "MDEC manual write FIFO overflow?!\n"); + } + } +} + +uint32 MDEC_Read(const pscpu_timestamp_t timestamp, uint32 A) +{ + uint32 ret = 0; + + if(A & 4) + { + ret = 0; + + ret |= (OutFIFO.CanRead() == 0) << 31; + ret |= (InFIFO.CanWrite() == 0) << 30; + ret |= InCommand << 29; + + ret |= MDEC_DMACanWrite() << 28; + ret |= MDEC_DMACanRead() << 27; + + ret |= ((Command >> 25) & 0xF) << 23; + + // Needs refactoring elsewhere to work right: ret |= ((DecodeWB + 4) % 6) << 16; + + ret |= InCounter & 0xFFFF; + } + else + { + if(OutFIFO.CanRead()) + ret = OutFIFO.ReadUnit(); + } + + //PSX_WARNING("[MDEC] Read: 0x%08x 0x%08x -- %d %d", A, ret, InputBuffer.CanRead(), InCounter); + + return(ret); +} + +} diff --git a/psx/octoshock/psx/mdec.h b/psx/octoshock/psx/mdec.h new file mode 100644 index 0000000000..a9ff800720 --- /dev/null +++ b/psx/octoshock/psx/mdec.h @@ -0,0 +1,24 @@ +#ifndef __MDFN_PSX_MDEC_H +#define __MDFN_PSX_MDEC_H + +namespace MDFN_IEN_PSX +{ + +void MDEC_DMAWrite(uint32 V); + +uint32 MDEC_DMARead(int32* offs); + +void MDEC_Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V); +uint32 MDEC_Read(const pscpu_timestamp_t timestamp, uint32 A); + + +void MDEC_Power(void); + +bool MDEC_DMACanWrite(void); +bool MDEC_DMACanRead(void); +void MDEC_Run(int32 clocks); + +int MDEC_StateAction(StateMem *sm, int load, int data_only); +} + +#endif diff --git a/psx/octoshock/psx/psx.cpp b/psx/octoshock/psx/psx.cpp new file mode 100644 index 0000000000..71f38c59b0 --- /dev/null +++ b/psx/octoshock/psx/psx.cpp @@ -0,0 +1,2929 @@ +/* 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 "psx.h" +#include "mdec.h" +#include "frontio.h" +#include "timer.h" +#include "sio.h" +#include "cdc.h" +#include "spu.h" +#include "cdrom/cdromif.h" +#include "error.h" +#include "endian.h" + +//DAW +//#include +//#include + +#ifdef WANT_PSF +#include +#endif + + +#include +#include + +//extern MDFNGI EmulatedPSX; + +namespace MDFN_IEN_PSX +{ + +#if PSX_DBGPRINT_ENABLE +static unsigned psx_dbg_level = 0; + +void PSX_DBG(unsigned level, const char *format, ...) throw() +{ + if(psx_dbg_level >= level) + { + va_list ap; + + va_start(ap, format); + + trio_vprintf(format, ap); + + va_end(ap); + } +} +#endif + + +struct MDFN_PseudoRNG // Based off(but not the same as) public-domain "JKISS" PRNG. +{ + MDFN_PseudoRNG() + { + ResetState(); + } + + u32 RandU32(void) + { + u64 t; + + x = 314527869 * x + 1234567; + y ^= y << 5; y ^= y >> 7; y ^= y << 22; + t = 4294584393ULL * z + c; c = t >> 32; z = t; + lcgo = (19073486328125ULL * lcgo) + 1; + + return (x + y + z) ^ (lcgo >> 16); + } + + uint32 RandU32(uint32 mina, uint32 maxa) + { + const uint32 range_m1 = maxa - mina; + uint32 range_mask; + uint32 tmp; + + range_mask = range_m1; + range_mask |= range_mask >> 1; + range_mask |= range_mask >> 2; + range_mask |= range_mask >> 4; + range_mask |= range_mask >> 8; + range_mask |= range_mask >> 16; + + do + { + tmp = RandU32() & range_mask; + } while(tmp > range_m1); + + return(mina + tmp); + } + + void ResetState(void) // Must always reset to the same state. + { + x = 123456789; + y = 987654321; + z = 43219876; + c = 6543217; + lcgo = 0xDEADBEEFCAFEBABEULL; + } + + uint32 x,y,z,c; + uint64 lcgo; +}; + +static MDFN_PseudoRNG PSX_PRNG; + +uint32 PSX_GetRandU32(uint32 mina, uint32 maxa) +{ + return PSX_PRNG.RandU32(mina, maxa); +} + + +#ifdef WANT_PSF +class PSF1Loader : public PSFLoader +{ + public: + + PSF1Loader(MDFNFILE *fp); + virtual ~PSF1Loader(); + + virtual void HandleEXE(const uint8 *data, uint32 len, bool ignore_pcsp = false); + + PSFTags tags; +}; +#else +class PSF1Loader {}; +#endif + + +static PSF1Loader *psf_loader = NULL; +static std::vector *cdifs = NULL; +static std::vector cdifs_scex_ids; +static bool CD_TrayOpen; +static int CD_SelectedDisc; // -1 for no disc + +static uint64 Memcard_PrevDC[8]; +static int64 Memcard_SaveDelay[8]; + +PS_CPU *CPU = NULL; +PS_SPU *SPU = NULL; +PS_GPU *GPU = NULL; +PS_CDC *CDC = NULL; +FrontIO *FIO = NULL; + +static MultiAccessSizeMem<512 * 1024, uint32, false> *BIOSROM = NULL; +static MultiAccessSizeMem<65536, uint32, false> *PIOMem = NULL; + +MultiAccessSizeMem<2048 * 1024, uint32, false> MainRAM; + +static uint32 TextMem_Start; +static std::vector TextMem; + +static const uint32 SysControl_Mask[9] = { 0x00ffffff, 0x00ffffff, 0xffffffff, 0x2f1fffff, + 0xffffffff, 0x2f1fffff, 0x2f1fffff, 0xffffffff, + 0x0003ffff }; + +static const uint32 SysControl_OR[9] = { 0x1f000000, 0x1f000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000 }; + +static struct +{ + union + { + struct + { + uint32 PIO_Base; // 0x1f801000 // BIOS Init: 0x1f000000, Writeable bits: 0x00ffffff(assumed, verify), FixedOR = 0x1f000000 + uint32 Unknown0; // 0x1f801004 // BIOS Init: 0x1f802000, Writeable bits: 0x00ffffff, FixedOR = 0x1f000000 + uint32 Unknown1; // 0x1f801008 // BIOS Init: 0x0013243f, ???? + uint32 Unknown2; // 0x1f80100c // BIOS Init: 0x00003022, Writeable bits: 0x2f1fffff, FixedOR = 0x00000000 + + uint32 BIOS_Mapping; // 0x1f801010 // BIOS Init: 0x0013243f, ???? + uint32 SPU_Delay; // 0x1f801014 // BIOS Init: 0x200931e1, Writeable bits: 0x2f1fffff, FixedOR = 0x00000000 - Affects bus timing on access to SPU + uint32 CDC_Delay; // 0x1f801018 // BIOS Init: 0x00020843, Writeable bits: 0x2f1fffff, FixedOR = 0x00000000 + uint32 Unknown4; // 0x1f80101c // BIOS Init: 0x00070777, ???? + uint32 Unknown5; // 0x1f801020 // BIOS Init: 0x00031125(but rewritten with other values often), Writeable bits: 0x0003ffff, FixedOR = 0x00000000 -- Possibly CDC related + }; + uint32 Regs[9]; + }; +} SysControl; + + +// +// Event stuff +// + +static pscpu_timestamp_t Running; // Set to -1 when not desiring exit, and 0 when we are. + +struct event_list_entry +{ + uint32 which; + pscpu_timestamp_t event_time; + event_list_entry *prev; + event_list_entry *next; +}; + +static event_list_entry events[PSX_EVENT__COUNT]; + +static void EventReset(void) +{ + for(unsigned i = 0; i < PSX_EVENT__COUNT; i++) + { + events[i].which = i; + + if(i == PSX_EVENT__SYNFIRST) + events[i].event_time = 0; + else if(i == PSX_EVENT__SYNLAST) + events[i].event_time = 0x7FFFFFFF; + else + events[i].event_time = PSX_EVENT_MAXTS; + + events[i].prev = (i > 0) ? &events[i - 1] : NULL; + events[i].next = (i < (PSX_EVENT__COUNT - 1)) ? &events[i + 1] : NULL; + } +} + +//static void RemoveEvent(event_list_entry *e) +//{ +// e->prev->next = e->next; +// e->next->prev = e->prev; +//} + +static void RebaseTS(const pscpu_timestamp_t timestamp) +{ + for(unsigned i = 0; i < PSX_EVENT__COUNT; i++) + { + if(i == PSX_EVENT__SYNFIRST || i == PSX_EVENT__SYNLAST) + continue; + + assert(events[i].event_time > timestamp); + events[i].event_time -= timestamp; + } + + CPU->SetEventNT(events[PSX_EVENT__SYNFIRST].next->event_time); +} + +void PSX_SetEventNT(const int type, const pscpu_timestamp_t next_timestamp) +{ + assert(type > PSX_EVENT__SYNFIRST && type < PSX_EVENT__SYNLAST); + event_list_entry *e = &events[type]; + + if(next_timestamp < e->event_time) + { + event_list_entry *fe = e; + + do + { + fe = fe->prev; + } + while(next_timestamp < fe->event_time); + + // Remove this event from the list, temporarily of course. + e->prev->next = e->next; + e->next->prev = e->prev; + + // Insert into the list, just after "fe". + e->prev = fe; + e->next = fe->next; + fe->next->prev = e; + fe->next = e; + + e->event_time = next_timestamp; + } + else if(next_timestamp > e->event_time) + { + event_list_entry *fe = e; + + do + { + fe = fe->next; + } while(next_timestamp > fe->event_time); + + // Remove this event from the list, temporarily of course + e->prev->next = e->next; + e->next->prev = e->prev; + + // Insert into the list, just BEFORE "fe". + e->prev = fe->prev; + e->next = fe; + fe->prev->next = e; + fe->prev = e; + + e->event_time = next_timestamp; + } + + CPU->SetEventNT(events[PSX_EVENT__SYNFIRST].next->event_time & Running); +} + +// Called from debug.cpp too. +void ForceEventUpdates(const pscpu_timestamp_t timestamp) +{ + PSX_SetEventNT(PSX_EVENT_GPU, GPU->Update(timestamp)); + PSX_SetEventNT(PSX_EVENT_CDC, CDC->Update(timestamp)); + + PSX_SetEventNT(PSX_EVENT_TIMER, TIMER_Update(timestamp)); + + PSX_SetEventNT(PSX_EVENT_DMA, DMA_Update(timestamp)); + + PSX_SetEventNT(PSX_EVENT_FIO, FIO->Update(timestamp)); + + CPU->SetEventNT(events[PSX_EVENT__SYNFIRST].next->event_time); +} + +bool PSX_EventHandler(const pscpu_timestamp_t timestamp) +{ + event_list_entry *e = events[PSX_EVENT__SYNFIRST].next; +#if PSX_EVENT_SYSTEM_CHECKS + pscpu_timestamp_t prev_event_time = 0; +#endif +#if 0 + { + printf("EventHandler - timestamp=%8d\n", timestamp); + event_list_entry *moo = &events[PSX_EVENT__SYNFIRST]; + while(moo) + { + printf("%u: %8d\n", moo->which, moo->event_time); + moo = moo->next; + } + } +#endif + +#if PSX_EVENT_SYSTEM_CHECKS + assert(Running == 0 || timestamp >= e->event_time); // If Running == 0, our EventHandler +#endif + + while(timestamp >= e->event_time) // If Running = 0, PSX_EventHandler() may be called even if there isn't an event per-se, so while() instead of do { ... } while + { + event_list_entry *prev = e->prev; + pscpu_timestamp_t nt; + +#if PSX_EVENT_SYSTEM_CHECKS + // Sanity test to make sure events are being evaluated in temporal order. + if(e->event_time < prev_event_time) + abort(); + prev_event_time = e->event_time; +#endif + + //printf("Event: %u %8d\n", e->which, e->event_time); +#if PSX_EVENT_SYSTEM_CHECKS + if((timestamp - e->event_time) > 50) + printf("Late: %u %d --- %8d\n", e->which, timestamp - e->event_time, timestamp); +#endif + + switch(e->which) + { + default: abort(); + + case PSX_EVENT_GPU: + nt = GPU->Update(e->event_time); + break; + + case PSX_EVENT_CDC: + nt = CDC->Update(e->event_time); + break; + + case PSX_EVENT_TIMER: + nt = TIMER_Update(e->event_time); + break; + + case PSX_EVENT_DMA: + nt = DMA_Update(e->event_time); + break; + + case PSX_EVENT_FIO: + nt = FIO->Update(e->event_time); + break; + } +#if PSX_EVENT_SYSTEM_CHECKS + assert(nt > e->event_time); +#endif + + PSX_SetEventNT(e->which, nt); + + // Order of events can change due to calling PSX_SetEventNT(), this prev business ensures we don't miss an event due to reordering. + e = prev->next; + } + +#if PSX_EVENT_SYSTEM_CHECKS + for(int i = PSX_EVENT__SYNFIRST + 1; i < PSX_EVENT__SYNLAST; i++) + { + if(timestamp >= events[i].event_time) + { + printf("BUG: %u\n", i); + + event_list_entry *moo = &events[PSX_EVENT__SYNFIRST]; + + while(moo) + { + printf("%u: %8d\n", moo->which, moo->event_time); + moo = moo->next; + } + + abort(); + } + } +#endif + + return(Running); +} + + +void PSX_RequestMLExit(void) +{ + Running = 0; + CPU->SetEventNT(0); +} + + +// +// End event stuff +// + +void DMA_CheckReadDebug(uint32 A); + +static unsigned sucksuck = 0; +void PSX_SetDMASuckSuck(unsigned suckage) +{ + sucksuck = suckage; +} + + +// Remember to update MemPeek<>() when we change address decoding in MemRW() +template static INLINE void MemRW(pscpu_timestamp_t ×tamp, uint32 A, uint32 &V) +{ + #if 0 + if(IsWrite) + printf("Write%d: %08x(orig=%08x), %08x\n", (int)(sizeof(T) * 8), A & mask[A >> 29], A, V); + else + printf("Read%d: %08x(orig=%08x)\n", (int)(sizeof(T) * 8), A & mask[A >> 29], A); + #endif + + if(!IsWrite) + timestamp += sucksuck; + + //if(A == 0xa0 && IsWrite) + // DBG_Break(); + + if(A < 0x00800000) + //if(A <= 0x1FFFFF) + { + if(IsWrite) + { + //timestamp++; // Best-case timing. + } + else + { + timestamp += 3; + } + + //DMA_CheckReadDebug(A); + //assert(A <= 0x1FFFFF); + if(Access24) + { + if(IsWrite) + MainRAM.WriteU24(A & 0x1FFFFF, V); + else + V = MainRAM.ReadU24(A & 0x1FFFFF); + } + else + { + if(IsWrite) + MainRAM.Write(A & 0x1FFFFF, V); + else + V = MainRAM.Read(A & 0x1FFFFF); + } + + return; + } + + if(A >= 0x1FC00000 && A <= 0x1FC7FFFF) + { + if(!IsWrite) + { + if(Access24) + V = BIOSROM->ReadU24(A & 0x7FFFF); + else + V = BIOSROM->Read(A & 0x7FFFF); + } + + return; + } + + if(timestamp >= events[PSX_EVENT__SYNFIRST].next->event_time) + PSX_EventHandler(timestamp); + + if(A >= 0x1F801000 && A <= 0x1F802FFF) + { + //if(IsWrite) + // printf("HW Write%d: %08x %08x\n", (unsigned int)(sizeof(T)*8), (unsigned int)A, (unsigned int)V); + //else + // printf("HW Read%d: %08x\n", (unsigned int)(sizeof(T)*8), (unsigned int)A); + + if(A >= 0x1F801C00 && A <= 0x1F801FFF) // SPU + { + if(sizeof(T) == 4 && !Access24) + { + if(IsWrite) + { + //timestamp += 15; + + //if(timestamp >= events[PSX_EVENT__SYNFIRST].next->event_time) + // PSX_EventHandler(timestamp); + + SPU->Write(timestamp, A | 0, V); + SPU->Write(timestamp, A | 2, V >> 16); + } + else + { + timestamp += 36; + + if(timestamp >= events[PSX_EVENT__SYNFIRST].next->event_time) + PSX_EventHandler(timestamp); + + V = SPU->Read(timestamp, A) | (SPU->Read(timestamp, A | 2) << 16); + } + } + else + { + if(IsWrite) + { + //timestamp += 8; + + //if(timestamp >= events[PSX_EVENT__SYNFIRST].next->event_time) + // PSX_EventHandler(timestamp); + + SPU->Write(timestamp, A & ~1, V); + } + else + { + timestamp += 16; // Just a guess, need to test. + + if(timestamp >= events[PSX_EVENT__SYNFIRST].next->event_time) + PSX_EventHandler(timestamp); + + V = SPU->Read(timestamp, A & ~1); + } + } + return; + } // End SPU + + + // CDC: TODO - 8-bit access. + if(A >= 0x1f801800 && A <= 0x1f80180F) + { + if(!IsWrite) + { + timestamp += 6 * sizeof(T); //24; + } + + if(IsWrite) + CDC->Write(timestamp, A & 0x3, V); + else + V = CDC->Read(timestamp, A & 0x3); + + return; + } + + if(A >= 0x1F801810 && A <= 0x1F801817) + { + if(!IsWrite) + timestamp++; + + if(IsWrite) + GPU->Write(timestamp, A, V); + else + V = GPU->Read(timestamp, A); + + return; + } + + if(A >= 0x1F801820 && A <= 0x1F801827) + { + if(!IsWrite) + timestamp++; + + if(IsWrite) + MDEC_Write(timestamp, A, V); + else + V = MDEC_Read(timestamp, A); + + return; + } + + if(A >= 0x1F801000 && A <= 0x1F801023) + { + unsigned index = (A & 0x1F) >> 2; + + if(!IsWrite) + timestamp++; + + //if(A == 0x1F801014 && IsWrite) + // fprintf(stderr, "%08x %08x\n",A,V); + + if(IsWrite) + { + V <<= (A & 3) * 8; + SysControl.Regs[index] = V & SysControl_Mask[index]; + } + else + { + V = SysControl.Regs[index] | SysControl_OR[index]; + V >>= (A & 3) * 8; + } + return; + } + + if(A >= 0x1F801040 && A <= 0x1F80104F) + { + if(!IsWrite) + timestamp++; + + if(IsWrite) + FIO->Write(timestamp, A, V); + else + V = FIO->Read(timestamp, A); + return; + } + + if(A >= 0x1F801050 && A <= 0x1F80105F) + { + if(!IsWrite) + timestamp++; + +#if 0 + if(IsWrite) + { + PSX_WARNING("[SIO] Write: 0x%08x 0x%08x %u", A, V, (unsigned)sizeof(T)); + } + else + { + PSX_WARNING("[SIO] Read: 0x%08x", A); + } +#endif + + if(IsWrite) + SIO_Write(timestamp, A, V); + else + V = SIO_Read(timestamp, A); + return; + } + +#if 0 + if(A >= 0x1F801060 && A <= 0x1F801063) + { + if(IsWrite) + { + + } + else + { + + } + + return; + } +#endif + + if(A >= 0x1F801070 && A <= 0x1F801077) // IRQ + { + if(!IsWrite) + timestamp++; + + if(IsWrite) + IRQ_Write(A, V); + else + V = IRQ_Read(A); + return; + } + + if(A >= 0x1F801080 && A <= 0x1F8010FF) // DMA + { + if(!IsWrite) + timestamp++; + + if(IsWrite) + DMA_Write(timestamp, A, V); + else + V = DMA_Read(timestamp, A); + + return; + } + + if(A >= 0x1F801100 && A <= 0x1F80113F) // Root counters + { + if(!IsWrite) + timestamp++; + + if(IsWrite) + TIMER_Write(timestamp, A, V); + else + V = TIMER_Read(timestamp, A); + + return; + } + } + + + if(A >= 0x1F000000 && A <= 0x1F7FFFFF) + { + if(!IsWrite) + { + //if((A & 0x7FFFFF) <= 0x84) + //PSX_WARNING("[PIO] Read%d from 0x%08x at time %d", (int)(sizeof(T) * 8), A, timestamp); + + V = ~0U; // A game this affects: Tetris with Cardcaptor Sakura + + if(PIOMem) + { + if((A & 0x7FFFFF) < 65536) + { + if(Access24) + V = PIOMem->ReadU24(A & 0x7FFFFF); + else + V = PIOMem->Read(A & 0x7FFFFF); + } + else if((A & 0x7FFFFF) < (65536 + TextMem.size())) + { + if(Access24) + V = MDFN_de24lsb(&TextMem[(A & 0x7FFFFF) - 65536]); + else switch(sizeof(T)) + { + case 1: V = TextMem[(A & 0x7FFFFF) - 65536]; break; + case 2: V = MDFN_de16lsb(&TextMem[(A & 0x7FFFFF) - 65536]); break; + case 4: V = MDFN_de32lsb(&TextMem[(A & 0x7FFFFF) - 65536]); break; + } + } + } + } + return; + } + + if(A == 0xFFFE0130) // Per tests on PS1, ignores the access(sort of, on reads the value is forced to 0 if not aligned) if not aligned to 4-bytes. + { + if(!IsWrite) + V = CPU->GetBIU(); + else + CPU->SetBIU(V); + + return; + } + + if(IsWrite) + { + PSX_WARNING("[MEM] Unknown write%d to %08x at time %d, =%08x(%d)", (int)(sizeof(T) * 8), A, timestamp, V, V); + } + else + { + V = 0; + PSX_WARNING("[MEM] Unknown read%d from %08x at time %d", (int)(sizeof(T) * 8), A, timestamp); + } +} + +void PSX_MemWrite8(pscpu_timestamp_t timestamp, uint32 A, uint32 V) +{ + MemRW(timestamp, A, V); +} + +void PSX_MemWrite16(pscpu_timestamp_t timestamp, uint32 A, uint32 V) +{ + MemRW(timestamp, A, V); +} + +void PSX_MemWrite24(pscpu_timestamp_t timestamp, uint32 A, uint32 V) +{ + //assert(0); + MemRW(timestamp, A, V); +} + +void PSX_MemWrite32(pscpu_timestamp_t timestamp, uint32 A, uint32 V) +{ + MemRW(timestamp, A, V); +} + +uint8 PSX_MemRead8(pscpu_timestamp_t ×tamp, uint32 A) +{ + uint32 V; + + MemRW(timestamp, A, V); + + return(V); +} + +uint16 PSX_MemRead16(pscpu_timestamp_t ×tamp, uint32 A) +{ + uint32 V; + + MemRW(timestamp, A, V); + + return(V); +} + +uint32 PSX_MemRead24(pscpu_timestamp_t ×tamp, uint32 A) +{ + uint32 V; + + MemRW(timestamp, A, V); + + return(V); +} + +uint32 PSX_MemRead32(pscpu_timestamp_t ×tamp, uint32 A) +{ + uint32 V; + + MemRW(timestamp, A, V); + + return(V); +} + +template static INLINE uint32 MemPeek(pscpu_timestamp_t timestamp, uint32 A) +{ + if(A < 0x00800000) + { + if(Access24) + return(MainRAM.ReadU24(A & 0x1FFFFF)); + else + return(MainRAM.Read(A & 0x1FFFFF)); + } + + if(A >= 0x1FC00000 && A <= 0x1FC7FFFF) + { + if(Access24) + return(BIOSROM->ReadU24(A & 0x7FFFF)); + else + return(BIOSROM->Read(A & 0x7FFFF)); + } + + if(A >= 0x1F801000 && A <= 0x1F802FFF) + { + if(A >= 0x1F801C00 && A <= 0x1F801FFF) // SPU + { + // TODO + + } // End SPU + + + // CDC: TODO - 8-bit access. + if(A >= 0x1f801800 && A <= 0x1f80180F) + { + // TODO + + } + + if(A >= 0x1F801810 && A <= 0x1F801817) + { + // TODO + + } + + if(A >= 0x1F801820 && A <= 0x1F801827) + { + // TODO + + } + + if(A >= 0x1F801000 && A <= 0x1F801023) + { + unsigned index = (A & 0x1F) >> 2; + return((SysControl.Regs[index] | SysControl_OR[index]) >> ((A & 3) * 8)); + } + + if(A >= 0x1F801040 && A <= 0x1F80104F) + { + // TODO + + } + + if(A >= 0x1F801050 && A <= 0x1F80105F) + { + // TODO + + } + + + if(A >= 0x1F801070 && A <= 0x1F801077) // IRQ + { + // TODO + + } + + if(A >= 0x1F801080 && A <= 0x1F8010FF) // DMA + { + // TODO + + } + + if(A >= 0x1F801100 && A <= 0x1F80113F) // Root counters + { + // TODO + + } + } + + + if(A >= 0x1F000000 && A <= 0x1F7FFFFF) + { + if(PIOMem) + { + if((A & 0x7FFFFF) < 65536) + { + if(Access24) + return(PIOMem->ReadU24(A & 0x7FFFFF)); + else + return(PIOMem->Read(A & 0x7FFFFF)); + } + else if((A & 0x7FFFFF) < (65536 + TextMem.size())) + { + if(Access24) + return(MDFN_de24lsb(&TextMem[(A & 0x7FFFFF) - 65536])); + else switch(sizeof(T)) + { + case 1: return(TextMem[(A & 0x7FFFFF) - 65536]); break; + case 2: return(MDFN_de16lsb(&TextMem[(A & 0x7FFFFF) - 65536])); break; + case 4: return(MDFN_de32lsb(&TextMem[(A & 0x7FFFFF) - 65536])); break; + } + } + } + return(~0U); + } + + if(A == 0xFFFE0130) + return CPU->GetBIU(); + + return(0); +} + +uint8 PSX_MemPeek8(uint32 A) +{ + return MemPeek(0, A); +} + +uint16 PSX_MemPeek16(uint32 A) +{ + return MemPeek(0, A); +} + +uint32 PSX_MemPeek32(uint32 A) +{ + return MemPeek(0, A); +} + +// FIXME: Add PSX_Reset() and FrontIO::Reset() so that emulated input devices don't get power-reset on reset-button reset. +static void PSX_Power(void) +{ + PSX_PRNG.ResetState(); // Should occur first! + +#if 0 + const uint32 counterer = 262144; + uint64 averageizer = 0; + uint32 maximizer = 0; + uint32 minimizer = ~0U; + for(int i = 0; i < counterer; i++) + { + uint32 tmp = PSX_GetRandU32(0, 20000); + if(tmp < minimizer) + minimizer = tmp; + + if(tmp > maximizer) + maximizer = tmp; + + averageizer += tmp; + printf("%8u\n", tmp); + } + printf("Average: %f\nMinimum: %u\nMaximum: %u\n", (double)averageizer / counterer, minimizer, maximizer); + exit(1); +#endif + + memset(MainRAM.data32, 0, 2048 * 1024); + + for(unsigned i = 0; i < 9; i++) + SysControl.Regs[i] = 0; + + CPU->Power(); + + EventReset(); + + TIMER_Power(); + + DMA_Power(); + + FIO->Power(); + SIO_Power(); + + MDEC_Power(); + CDC->Power(); + GPU->Power(); + //SPU->Power(); // Called from CDC->Power() + IRQ_Power(); + + ForceEventUpdates(0); +} + + +void PSX_GPULineHook(const pscpu_timestamp_t timestamp, const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider) +{ + FIO->GPULineHook(timestamp, line_timestamp, vsync, pixels, format, width, pix_clock_offset, pix_clock, pix_clock_divider); +} + +} + +using namespace MDFN_IEN_PSX; + + +static void Emulate(EmulateSpecStruct *espec) +{ + pscpu_timestamp_t timestamp = 0; + + if(FIO->RequireNoFrameskip()) + { + //puts("MEOW"); + espec->skip = false; //TODO: Save here, and restore at end of Emulate() ? + } + + //DAW + //MDFNGameInfo->mouse_sensitivity = MDFN_GetSettingF("psx.input.mouse_sensitivity"); + + //MDFNMP_ApplyPeriodicCheats(); + + + espec->MasterCycles = 0; + espec->SoundBufSize = 0; + + FIO->UpdateInput(); + GPU->StartFrame(psf_loader ? NULL : espec); + SPU->StartFrame(espec->SoundRate, 0); + + Running = -1; + timestamp = CPU->Run(timestamp, psf_loader != NULL); + + assert(timestamp); + + ForceEventUpdates(timestamp); + if(GPU->GetScanlineNum() < 100) + PSX_DBG(PSX_DBG_ERROR, "[BUUUUUUUG] Frame timing end glitch; scanline=%u, st=%u\n", GPU->GetScanlineNum(), timestamp); + + //printf("scanline=%u, st=%u\n", GPU->GetScanlineNum(), timestamp); + + espec->SoundBufSize = SPU->EndFrame(espec->SoundBuf); + + CDC->ResetTS(); + TIMER_ResetTS(); + DMA_ResetTS(); + GPU->ResetTS(); + FIO->ResetTS(); + + RebaseTS(timestamp); + + espec->MasterCycles = timestamp; + + if(psf_loader) + { + if(!espec->skip) + { + espec->LineWidths[0] = ~0; + //Player_Draw(espec->surface, &espec->DisplayRect, 0, espec->SoundBuf, espec->SoundBufSize); + } + } + + //DAW!! + // Save memcards if dirty. + //for(int i = 0; i < 8; i++) + //{ + // uint64 new_dc = FIO->GetMemcardDirtyCount(i); + + // if(new_dc > Memcard_PrevDC[i]) + // { + // Memcard_PrevDC[i] = new_dc; + // Memcard_SaveDelay[i] = 0; + // } + + // if(Memcard_SaveDelay[i] >= 0) + // { + // Memcard_SaveDelay[i] += timestamp; + // if(Memcard_SaveDelay[i] >= (33868800 * 2)) // Wait until about 2 seconds of no new writes. + // { + // PSX_DBG(PSX_DBG_SPARSE, "Saving memcard %d...\n", i); + // try + // { + // char ext[64]; + // trio_snprintf(ext, sizeof(ext), "%d.mcr", i); + // FIO->SaveMemcard(i, MDFN_MakeFName(MDFNMKF_SAV, 0, ext).c_str()); + // Memcard_SaveDelay[i] = -1; + // Memcard_PrevDC[i] = 0; + // } + // catch(std::exception &e) + // { + // MDFN_PrintError("Memcard %d save error: %s", i, e.what()); + // MDFN_DispMessage("Memcard %d save error: %s", i, e.what()); + // } + // //MDFN_DispMessage("Memcard %d saved.", i); + // } + // } + //} +} +// +//static bool TestMagic(MDFNFILE *fp) +//{ +//#ifdef WANT_PSF +// if(PSFLoader::TestMagic(0x01, fp)) +// return(true); +//#endif +// +// if(fp->size < 0x800) +// return(false); +// +// if(memcmp(fp->data, "PS-X EXE", 8)) +// return(false); +// +// return(true); +//} +// +//static bool TestMagicCD(std::vector *CDInterfaces) +//{ +// uint8 buf[2048]; +// CDUtility::TOC toc; +// int dt; +// +// (*CDInterfaces)[0]->ReadTOC(&toc); +// +// dt = toc.FindTrackByLBA(4); +// if(dt > 0 && !(toc.tracks[dt].control & 0x4)) +// return(false); +// +// if((*CDInterfaces)[0]->ReadSector(buf, 4, 1) != 0x2) +// return(false); +// +// if(strncmp((char *)buf + 10, "Licensed by", strlen("Licensed by"))) +// return(false); +// +// //if(strncmp((char *)buf + 32, "Sony", 4)) +// // return(false); +// +// //for(int i = 0; i < 2048; i++) +// // printf("%d, %02x %c\n", i, buf[i], buf[i]); +// //exit(1); +// +//#if 0 +// { +// uint8 buf[2048 * 7]; +// +// if((*cdifs)[0]->ReadSector(buf, 5, 7) == 0x2) +// { +// printf("CRC32: 0x%08x\n", (uint32)crc32(0, &buf[0], 0x3278)); +// } +// } +//#endif +// +// return(true); +//} + +// +// +//static const char *CalcDiscSCEx_BySYSTEMCNF(CDIF *c, unsigned *rr) +//{ +// const char *ret = NULL; +// Stream *fp = NULL; +// CDUtility::TOC toc; +// +// //(*CDInterfaces)[disc]->ReadTOC(&toc); +// +// //if(toc.first_track > 1 || toc. +// +// try +// { +// uint8 pvd[2048]; +// unsigned pvd_search_count = 0; +// +// fp = c->MakeStream(0, ~0U); +// fp->seek(0x8000, SEEK_SET); +// +// do +// { +// if((pvd_search_count++) == 32) +// throw MDFN_Error(0, "PVD search count limit met."); +// +// fp->read(pvd, 2048); +// +// if(memcmp(&pvd[1], "CD001", 5)) +// throw MDFN_Error(0, "Not ISO-9660"); +// +// if(pvd[0] == 0xFF) +// throw MDFN_Error(0, "Missing Primary Volume Descriptor"); +// } while(pvd[0] != 0x01); +// //[156 ... 189], 34 bytes +// uint32 rdel = MDFN_de32lsb(&pvd[0x9E]); +// uint32 rdel_len = MDFN_de32lsb(&pvd[0xA6]); +// +// if(rdel_len >= (1024 * 1024 * 10)) // Arbitrary sanity check. +// throw MDFN_Error(0, "Root directory table too large"); +// +// fp->seek((int64)rdel * 2048, SEEK_SET); +// //printf("%08x, %08x\n", rdel * 2048, rdel_len); +// while(fp->tell() < (((int64)rdel * 2048) + rdel_len)) +// { +// uint8 len_dr = fp->get_u8(); +// uint8 dr[256 + 1]; +// +// memset(dr, 0xFF, sizeof(dr)); +// +// if(!len_dr) +// break; +// +// memset(dr, 0, sizeof(dr)); +// dr[0] = len_dr; +// fp->read(dr + 1, len_dr - 1); +// +// uint8 len_fi = dr[0x20]; +// +// if(len_fi == 12 && !memcmp(&dr[0x21], "SYSTEM.CNF;1", 12)) +// { +// uint32 file_lba = MDFN_de32lsb(&dr[0x02]); +// //uint32 file_len = MDFN_de32lsb(&dr[0x0A]); +// uint8 fb[2048 + 1]; +// char *bootpos; +// +// memset(fb, 0, sizeof(fb)); +// fp->seek(file_lba * 2048, SEEK_SET); +// fp->read(fb, 2048); +// +// bootpos = strstr((char*)fb, "BOOT") + 4; +// while(*bootpos == ' ' || *bootpos == '\t') bootpos++; +// if(*bootpos == '=') +// { +// bootpos++; +// while(*bootpos == ' ' || *bootpos == '\t') bootpos++; +// if(!strncasecmp(bootpos, "cdrom:\\", 7)) +// { +// bootpos += 7; +// char *tmp; +// +// if((tmp = strchr(bootpos, '_'))) *tmp = 0; +// if((tmp = strchr(bootpos, '.'))) *tmp = 0; +// if((tmp = strchr(bootpos, ';'))) *tmp = 0; +// //puts(bootpos); +// +// if(strlen(bootpos) == 4 && bootpos[0] == 'S' && (bootpos[1] == 'C' || bootpos[1] == 'L' || bootpos[1] == 'I')) +// { +// switch(bootpos[2]) +// { +// case 'E': if(rr) +// *rr = REGION_EU; +// ret = "SCEE"; +// goto Breakout; +// +// case 'U': if(rr) +// *rr = REGION_NA; +// ret = "SCEA"; +// goto Breakout; +// +// case 'K': // Korea? +// case 'B': +// case 'P': if(rr) +// *rr = REGION_JP; +// ret = "SCEI"; +// goto Breakout; +// } +// } +// } +// } +// +// //puts((char*)fb); +// //puts("ASOFKOASDFKO"); +// } +// } +// } +// catch(std::exception &e) +// { +// //puts(e.what()); +// } +// catch(...) +// { +// +// } +// +// Breakout: +// if(fp != NULL) +// { +// delete fp; +// fp = NULL; +// } +// +// return(ret); +//} + +struct ShockConfig +{ + // 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. (TRUE for psx) + // 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. + int lcm_width; + int lcm_height; + 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) +} s_ShockConfig; + + +struct ShockState +{ + bool power; +} s_ShockState; + +static void MountCPUAddressSpace() +{ + for(uint32 ma = 0x00000000; ma < 0x00800000; ma += 2048 * 1024) + { + CPU->SetFastMap(MainRAM.data32, 0x00000000 + ma, 2048 * 1024); + CPU->SetFastMap(MainRAM.data32, 0x80000000 + ma, 2048 * 1024); + CPU->SetFastMap(MainRAM.data32, 0xA0000000 + ma, 2048 * 1024); + } + + CPU->SetFastMap(BIOSROM->data32, 0x1FC00000, 512 * 1024); + CPU->SetFastMap(BIOSROM->data32, 0x9FC00000, 512 * 1024); + CPU->SetFastMap(BIOSROM->data32, 0xBFC00000, 512 * 1024); + + if(PIOMem) + { + CPU->SetFastMap(PIOMem->data32, 0x1F000000, 65536); + CPU->SetFastMap(PIOMem->data32, 0x9F000000, 65536); + CPU->SetFastMap(PIOMem->data32, 0xBF000000, 65536); + } +} + +static MDFN_Surface *VTBuffer[2] = { NULL, NULL }; +static int *VTLineWidths[2] = { NULL, NULL }; + +EW_EXPORT s32 shock_Create(void** psx, eRegion region, void* firmware512k) +{ + //NEW + *psx = NULL; + + //PIO Mem: why wouldn't we want this? + static const bool WantPIOMem = true; + + BIOSROM = new MultiAccessSizeMem<512 * 1024, uint32, false>(); + memcpy(BIOSROM->data8, firmware512k, 512 * 1024); + + if(WantPIOMem) PIOMem = new MultiAccessSizeMem<65536, uint32, false>(); + else PIOMem = NULL; + + CPU = new PS_CPU(); + SPU = new PS_SPU(); + CDC = new PS_CDC(); + DMA_Init(); + + //analyze region to determine display area (visible scanline regions and such) + //currently this can't be changed by the user + //[0,239] for NTSC; [0,287] for PAL + int sls, sle; + if(region == REGION_EU) + { + sls = 0; + sle = 287; + s_ShockConfig.nominal_width = 367; // Dunno. :( + s_ShockConfig.nominal_height = 288; + + s_ShockConfig.fb_width = 768; + s_ShockConfig.fb_height = 576; + } + else + { + sls = 0; + sle = 239; + s_ShockConfig.lcm_width = 2720; + s_ShockConfig.lcm_height = 480; + + s_ShockConfig.nominal_width = 310; + s_ShockConfig.nominal_height = 240; + + s_ShockConfig.fb_width = 768; + s_ShockConfig.fb_height = 480; + } + + //setup gpu output surfaces + MDFN_PixelFormat nf(MDFN_COLORSPACE_RGB, 16, 8, 0, 24); + VTBuffer[0] = new MDFN_Surface(NULL, s_ShockConfig.fb_width, s_ShockConfig.fb_height, s_ShockConfig.fb_width, nf); + VTLineWidths[0] = (int *)calloc(s_ShockConfig.fb_height, sizeof(int)); + + //these steps can't be done without more information + GPU = new PS_GPU(region == REGION_EU, sls, sle); + + //TODO - configuration + static bool emulate_memcard[8] = {0}; + static bool emulate_multitap[2] = {0}; + FIO = new FrontIO(emulate_memcard, emulate_multitap); + + MountCPUAddressSpace(); + + s_ShockState.power = false; + + //TODO - disc tray / cdc stuff? + CD_TrayOpen = true; + CD_SelectedDisc = -1; + + return SHOCK_OK; +} + +EW_EXPORT s32 shock_Destroy(void* psx) +{ + //TODO + return SHOCK_OK; +} + +//Sets the power to ON. It is an error to turn an already-on console ON again +EW_EXPORT s32 shock_PowerOn(void* psx) +{ + if(s_ShockState.power) return SHOCK_NOCANDO; + + PSX_Power(); + + return SHOCK_OK; +} + +//Sets the power to OFF. It is an error to turn an already-off console OFF again +EW_EXPORT s32 shock_PowerOff(void* psx) +{ + if(!s_ShockState.power) return SHOCK_NOCANDO; + + //not supported yet + return SHOCK_ERROR; +} + + +int16 soundbuf[1024*1024]; //how big? big enough. +int VTBackBuffer = 0; +static MDFN_Rect VTDisplayRects[2]; +#include "video/Deinterlacer.h" +static bool PrevInterlaced; +static Deinterlacer deint; +static EmulateSpecStruct espec; +EW_EXPORT s32 shock_Step(void* psx, eShockStep step) +{ + //only eShockStep_Frame is supported + + pscpu_timestamp_t timestamp = 0; + + //MDFNMP_ApplyPeriodicCheats(); //TODO + + memset(&espec, 0, sizeof(EmulateSpecStruct)); + + espec.VideoFormatChanged = true; //shouldnt do this every frame.. + espec.surface = (MDFN_Surface *)VTBuffer[VTBackBuffer]; + espec.LineWidths = (int *)VTLineWidths[VTBackBuffer]; + espec.skip = false; + espec.soundmultiplier = 1.0; + espec.NeedRewind = false; + + espec.SoundBufMaxSize = 1024*1024; + espec.SoundRate = 44100; + espec.SoundBuf = soundbuf; + espec.SoundVolume = 1.0; + + //------------------------- + + FIO->UpdateInput(); + //GPU->StartFrame(psf_loader ? NULL : espec); + GPU->StartFrame(&espec); + static const int ResampleQuality = 5; + SPU->StartFrame(espec.SoundRate, ResampleQuality); + + Running = -1; + timestamp = CPU->Run(timestamp, psf_loader != NULL); + assert(timestamp); + + ForceEventUpdates(timestamp); + if(GPU->GetScanlineNum() < 100) + printf("[BUUUUUUUG] Frame timing end glitch; scanline=%u, st=%u\n", GPU->GetScanlineNum(), timestamp); + + espec.SoundBufSize = SPU->EndFrame(espec.SoundBuf); + + CDC->ResetTS(); + TIMER_ResetTS(); + DMA_ResetTS(); + GPU->ResetTS(); + FIO->ResetTS(); + + RebaseTS(timestamp); + + espec.MasterCycles = timestamp; + + //(memcard saving happened here) + + //---------------------- + + VTDisplayRects[VTBackBuffer] = espec.DisplayRect; + + //if interlacing is active, do that processing now + if(espec.InterlaceOn) + { + if(!PrevInterlaced) + deint.ClearState(); + + deint.Process(espec.surface, espec.DisplayRect, espec.LineWidths, espec.InterlaceField); + + PrevInterlaced = true; + + espec.InterlaceOn = false; + espec.InterlaceField = 0; + } + + //pixel-double some dimensions as needed (TBD) + + return SHOCK_OK; +} + +EW_EXPORT s32 shock_GetFramebuffer(void* psx, ShockFramebufferJob* fb) +{ + //always fetch description + int width = VTLineWidths[0][0]; //presently, except for contrived test programs, it is safe to assume this is the same for the entire frame (no known use by games) + int height = espec.DisplayRect.h; + fb->width = width; + fb->height = height; + + //is that all we needed? + if(fb->ptr == NULL) + { + return SHOCK_OK; + } + + //maybe we need to output the framebuffer + //do a raster loop and copy it to the target + uint32* src = VTBuffer[0]->pixels + (s_ShockConfig.fb_width*espec.DisplayRect.y) + espec.DisplayRect.x; + uint32* dst = (u32*)fb->ptr; + int tocopy = width*4; + for(int y=0;y *CDInterfaces, const bool EmulateMemcards = true, const bool WantPIOMem = false) +{ + //OLD + unsigned region; + bool emulate_memcard[8]; + bool emulate_multitap[2]; + int sls, sle; + +#if PSX_DBGPRINT_ENABLE + psx_dbg_level = MDFN_GetSettingUI("psx.dbg_level"); +#endif + + //DAW + /*for(unsigned i = 0; i < 8; i++) + { + char buf[64]; + trio_snprintf(buf, sizeof(buf), "psx.input.port%u.memcard", i + 1); + emulate_memcard[i] = EmulateMemcards && MDFN_GetSettingB(buf); + } + + for(unsigned i = 0; i < 2; i++) + { + char buf[64]; + trio_snprintf(buf, sizeof(buf), "psx.input.pport%u.multitap", i + 1); + emulate_multitap[i] = MDFN_GetSettingB(buf); + }*/ + + + //cdifs = CDInterfaces; + //region = CalcDiscSCEx(); + + if(shock_GetSetting(REGION_AUTODETECT)==0) + region = shock_GetSetting(REGION_DEFAULT); + + sls = shock_GetSetting((region == REGION_EU) ? SLSTARTP : SLSTART); + sle = shock_GetSetting((region == REGION_EU) ? SLENDP : SLEND); + + if(sls > sle) + { + int tmp = sls; + sls = sle; + sle = tmp; + } + + CPU = new PS_CPU(); + SPU = new PS_SPU(); + GPU = new PS_GPU(region == REGION_EU, sls, sle); + CDC = new PS_CDC(); + FIO = new FrontIO(emulate_memcard, emulate_multitap); + + //dont think we want the crosshair drawing to be done here + //FIO->SetCrosshairsColor(i, MDFN_GetSettingUI(buf)); + + DMA_Init(); + + //DAW + //GPU->FillVideoParams(&EmulatedPSX); + + if(cdifs) + { + CD_TrayOpen = false; + CD_SelectedDisc = 0; + } + else + { + CD_TrayOpen = true; + CD_SelectedDisc = -1; + } + + //CDC->SetDisc(true, NULL, NULL); + //CDC->SetDisc(CD_TrayOpen, (CD_SelectedDisc >= 0 && !CD_TrayOpen) ? (*cdifs)[CD_SelectedDisc] : NULL, + //(CD_SelectedDisc >= 0 && !CD_TrayOpen) ? cdifs_scex_ids[CD_SelectedDisc] : NULL); + + + BIOSROM = new MultiAccessSizeMem<512 * 1024, uint32, false>(); + + if(WantPIOMem) + PIOMem = new MultiAccessSizeMem<65536, uint32, false>(); + else + PIOMem = NULL; + + for(uint32 ma = 0x00000000; ma < 0x00800000; ma += 2048 * 1024) + { + CPU->SetFastMap(MainRAM.data32, 0x00000000 + ma, 2048 * 1024); + CPU->SetFastMap(MainRAM.data32, 0x80000000 + ma, 2048 * 1024); + CPU->SetFastMap(MainRAM.data32, 0xA0000000 + ma, 2048 * 1024); + } + + CPU->SetFastMap(BIOSROM->data32, 0x1FC00000, 512 * 1024); + CPU->SetFastMap(BIOSROM->data32, 0x9FC00000, 512 * 1024); + CPU->SetFastMap(BIOSROM->data32, 0xBFC00000, 512 * 1024); + + if(PIOMem) + { + CPU->SetFastMap(PIOMem->data32, 0x1F000000, 65536); + CPU->SetFastMap(PIOMem->data32, 0x9F000000, 65536); + CPU->SetFastMap(PIOMem->data32, 0xBF000000, 65536); + } + + + //MDFNMP_Init(1024, ((uint64)1 << 29) / 1024); + //MDFNMP_AddRAM(2048 * 1024, 0x00000000, MainRAM.data8); + + //DAW- + //TODO - load bios + // + // + // + //const char *biospath_sname; + + //if(region == REGION_JP) + // biospath_sname = "psx.bios_jp"; + //else if(region == REGION_EU) + // biospath_sname = "psx.bios_eu"; + //else if(region == REGION_NA) + // biospath_sname = "psx.bios_na"; + //else + // abort(); + + //{ + // std::string biospath = MDFN_MakeFName(MDFNMKF_FIRMWARE, 0, MDFN_GetSettingS(biospath_sname).c_str()); + // FileStream BIOSFile(biospath.c_str(), FileStream::MODE_READ); + + // BIOSFile.read(BIOSROM->data8, 512 * 1024); + //} + + //todo - load memcard + //DAW + //for(int i = 0; i < 8; i++) + //{ + // char ext[64]; + // trio_snprintf(ext, sizeof(ext), "%d.mcr", i); + // FIO->LoadMemcard(i, MDFN_MakeFName(MDFNMKF_SAV, 0, ext).c_str()); + //} + + for(int i = 0; i < 8; i++) + { + Memcard_PrevDC[i] = FIO->GetMemcardDirtyCount(i); + Memcard_SaveDelay[i] = -1; + } + + + #ifdef WANT_DEBUGGER + DBG_Init(); + #endif + + PSX_Power(); +} + +static void LoadEXE(const uint8 *data, const uint32 size, bool ignore_pcsp = false) +{ +// uint32 PC; +// uint32 SP; +// uint32 TextStart; +// uint32 TextSize; +// +// if(size < 0x800) +// throw(MDFN_Error(0, "PS-EXE is too small.")); +// +// PC = MDFN_de32lsb(&data[0x10]); +// SP = MDFN_de32lsb(&data[0x30]); +// TextStart = MDFN_de32lsb(&data[0x18]); +// TextSize = MDFN_de32lsb(&data[0x1C]); +// +// if(ignore_pcsp) +// printf("TextStart=0x%08x\nTextSize=0x%08x\n", TextStart, TextSize); +// else +// printf("PC=0x%08x\nSP=0x%08x\nTextStart=0x%08x\nTextSize=0x%08x\n", PC, SP, TextStart, TextSize); +// +// TextStart &= 0x1FFFFF; +// +// if(TextSize > 2048 * 1024) +// { +// throw(MDFN_Error(0, "Text section too large")); +// } +// +// if(TextSize > (size - 0x800)) +// throw(MDFN_Error(0, "Text section recorded size is larger than data available in file. Header=0x%08x, Available=0x%08x", TextSize, size - 0x800)); +// +// if(TextSize < (size - 0x800)) +// throw(MDFN_Error(0, "Text section recorded size is smaller than data available in file. Header=0x%08x, Available=0x%08x", TextSize, size - 0x800)); +// +// if(!TextMem.size()) +// { +// TextMem_Start = TextStart; +// TextMem.resize(TextSize); +// } +// +// if(TextStart < TextMem_Start) +// { +// uint32 old_size = TextMem.size(); +// +// //printf("RESIZE: 0x%08x\n", TextMem_Start - TextStart); +// +// TextMem.resize(old_size + TextMem_Start - TextStart); +// memmove(&TextMem[TextMem_Start - TextStart], &TextMem[0], old_size); +// +// TextMem_Start = TextStart; +// } +// +// if(TextMem.size() < (TextStart - TextMem_Start + TextSize)) +// TextMem.resize(TextStart - TextMem_Start + TextSize); +// +// memcpy(&TextMem[TextStart - TextMem_Start], data + 0x800, TextSize); +// +// +// // +// // +// // +// +// // BIOS patch +// BIOSROM->WriteU32(0x6990, (3 << 26) | ((0xBF001000 >> 2) & ((1 << 26) - 1))); +//// BIOSROM->WriteU32(0x691C, (3 << 26) | ((0xBF001000 >> 2) & ((1 << 26) - 1))); +// +//// printf("INSN: 0x%08x\n", BIOSROM->ReadU32(0x6990)); +//// exit(1); +// uint8 *po; +// +// po = &PIOMem->data8[0x0800]; +// +// MDFN_en32lsb(po, (0x0 << 26) | (31 << 21) | (0x8 << 0)); // JR +// po += 4; +// MDFN_en32lsb(po, 0); // NOP(kinda) +// po += 4; +// +// po = &PIOMem->data8[0x1000]; +// +// // Load cacheable-region target PC into r2 +// MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (0x9F001010 >> 16)); // LUI +// po += 4; +// MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (2 << 16) | (0x9F001010 & 0xFFFF)); // ORI +// po += 4; +// +// // Jump to r2 +// MDFN_en32lsb(po, (0x0 << 26) | (2 << 21) | (0x8 << 0)); // JR +// po += 4; +// MDFN_en32lsb(po, 0); // NOP(kinda) +// po += 4; +// +// // +// // 0x9F001010: +// // +// +// // Load source address into r8 +// uint32 sa = 0x9F000000 + 65536; +// MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (sa >> 16)); // LUI +// po += 4; +// MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (8 << 16) | (sa & 0xFFFF)); // ORI +// po += 4; +// +// // Load dest address into r9 +// MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (TextMem_Start >> 16)); // LUI +// po += 4; +// MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (9 << 16) | (TextMem_Start & 0xFFFF)); // ORI +// po += 4; +// +// // Load size into r10 +// MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (TextMem.size() >> 16)); // LUI +// po += 4; +// MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (10 << 16) | (TextMem.size() & 0xFFFF)); // ORI +// po += 4; +// +// // +// // Loop begin +// // +// +// MDFN_en32lsb(po, (0x24 << 26) | (8 << 21) | (1 << 16)); // LBU to r1 +// po += 4; +// +// MDFN_en32lsb(po, (0x08 << 26) | (10 << 21) | (10 << 16) | 0xFFFF); // Decrement size +// po += 4; +// +// MDFN_en32lsb(po, (0x28 << 26) | (9 << 21) | (1 << 16)); // SB from r1 +// po += 4; +// +// MDFN_en32lsb(po, (0x08 << 26) | (8 << 21) | (8 << 16) | 0x0001); // Increment source addr +// po += 4; +// +// MDFN_en32lsb(po, (0x05 << 26) | (0 << 21) | (10 << 16) | (-5 & 0xFFFF)); +// po += 4; +// MDFN_en32lsb(po, (0x08 << 26) | (9 << 21) | (9 << 16) | 0x0001); // Increment dest addr +// po += 4; +// +// // +// // Loop end +// // +// +// // Load SP into r29 +// if(ignore_pcsp) +// { +// po += 16; +// } +// else +// { +// MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (SP >> 16)); // LUI +// po += 4; +// MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (29 << 16) | (SP & 0xFFFF)); // ORI +// po += 4; +// +// // Load PC into r2 +// MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | ((PC >> 16) | 0x8000)); // LUI +// po += 4; +// MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (2 << 16) | (PC & 0xFFFF)); // ORI +// po += 4; +// } +// +// // Half-assed instruction cache flush. ;) +// for(unsigned i = 0; i < 1024; i++) +// { +// MDFN_en32lsb(po, 0); +// po += 4; +// } +// +// +// +// // Jump to r2 +// MDFN_en32lsb(po, (0x0 << 26) | (2 << 21) | (0x8 << 0)); // JR +// po += 4; +// MDFN_en32lsb(po, 0); // NOP(kinda) +// po += 4; +} + +#ifdef WANT_PSF +PSF1Loader::PSF1Loader(MDFNFILE *fp) +{ + tags = Load(0x01, 2033664, fp); +} + + +PSF1Loader::~PSF1Loader() +{ + +} + + +void PSF1Loader::HandleEXE(const uint8 *data, uint32 size, bool ignore_pcsp) +{ + LoadEXE(data, size, ignore_pcsp); +} +#endif + +//static void Cleanup(void); +//static int Load(MDFNFILE *fp) +//{ +// try +// { +// const bool IsPSF = PSFLoader::TestMagic(0x01, fp); +// +// if(!TestMagic(fp)) +// throw MDFN_Error(0, _("File format is unknown to module \"%s\"."), MDFNGameInfo->shortname); +// +//// For testing. +//#if 0 +// #warning "GREMLINS GREMLINS EVERYWHEREE IYEEEEEE" +// #warning "Seriously, GREMLINS! Or peanut butter. Or maybe...DINOSAURS." +// +// static std::vector CDInterfaces; +// +// //CDInterfaces.push_back(CDIF_Open("/home/sarah-projects/psxdev/tests/cd/adpcm.cue", false, false)); +// //CDInterfaces.push_back(CDIF_Open("/extra/games/PSX/Tony Hawk's Pro Skater 2 (USA)/Tony Hawk's Pro Skater 2 (USA).cue", false, false)); +// //CDInterfaces.push_back(CDIF_Open("/extra/games/PSX/Jumping Flash! (USA)/Jumping Flash! (USA).cue", false, false)); +// //CDInterfaces.push_back(CDIF_Open("/extra/games/PC-FX/Blue Breaker.cue", false, false)); +// CDInterfaces.push_back(CDIF_Open("/dev/cdrom2", true, false)); +// InitCommon(&CDInterfaces, !IsPSF, true); +//#else +// InitCommon(NULL, !IsPSF, true); +//#endif +// +// TextMem.resize(0); +// +// if(IsPSF) +// { +// psf_loader = new PSF1Loader(fp); +// +// std::vector SongNames; +// +// SongNames.push_back(psf_loader->tags.GetTag("title")); +// +// Player_Init(1, psf_loader->tags.GetTag("game"), psf_loader->tags.GetTag("artist"), psf_loader->tags.GetTag("copyright"), SongNames); +// } +// else +// LoadEXE(fp->data, fp->size); +// } +// catch(std::exception &e) +// { +// Cleanup(); +// throw; +// } +// +// return(1); +//} + +//static void LoadCD(std::vector *CDInterfaces) +//{ +// try +// { +// InitCommon(CDInterfaces); +// +// MDFNGameInfo->GameType = GMT_CDROM; +// } +// catch(std::exception &e) +// { +// Cleanup(); +// throw; +// } +//} + +static void Cleanup(void) +{ + TextMem.resize(0); + + if(psf_loader) + { + delete psf_loader; + psf_loader = NULL; + } + + if(CDC) + { + delete CDC; + CDC = NULL; + } + + if(SPU) + { + delete SPU; + SPU = NULL; + } + + if(GPU) + { + delete GPU; + GPU = NULL; + } + + if(CPU) + { + delete CPU; + CPU = NULL; + } + + if(FIO) + { + delete FIO; + FIO = NULL; + } + + DMA_Kill(); + + if(BIOSROM) + { + delete BIOSROM; + BIOSROM = NULL; + } + + if(PIOMem) + { + delete PIOMem; + PIOMem = NULL; + } + + cdifs = NULL; +} + +static void CloseGame(void) +{ + if(!psf_loader) + { + for(int i = 0; i < 8; i++) + { + //DAW + //FIO->SaveMemcard(i, MDFN_MakeFName(MDFNMKF_SAV, 0, ext).c_str()); + } + + } + + Cleanup(); +} + + +static void SetInput(int port, const char *type, void *ptr) +{ + if(psf_loader) + FIO->SetInput(port, "none", NULL); + else + FIO->SetInput(port, type, ptr); +} + +static int StateAction(StateMem *sm, int load, int data_only) +{ + + SFORMAT StateRegs[] = + { + SFVAR(CD_TrayOpen), + SFVAR(CD_SelectedDisc), + SFARRAY(MainRAM.data8, 1024 * 2048), + SFARRAY32(SysControl.Regs, 9), + + SFVAR(PSX_PRNG.lcgo), + SFVAR(PSX_PRNG.x), + SFVAR(PSX_PRNG.y), + SFVAR(PSX_PRNG.z), + SFVAR(PSX_PRNG.c), + + SFEND + }; + + int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "MAIN"); + + // Call SetDisc() BEFORE we load CDC state, since SetDisc() has emulation side effects. We might want to clean this up in the future. + if(load) + { + if(CD_SelectedDisc >= (int)cdifs->size()) + CD_SelectedDisc = -1; + + //DAW???????????? + // CDC->SetDisc(CD_TrayOpen, (CD_SelectedDisc >= 0 && !CD_TrayOpen) ? (*cdifs)[CD_SelectedDisc] : NULL, + //(CD_SelectedDisc >= 0 && !CD_TrayOpen) ? cdifs_scex_ids[CD_SelectedDisc] : NULL); + } + + // TODO: Remember to increment dirty count in memory card state loading routine. + + ret &= CPU->StateAction(sm, load, data_only); + ret &= DMA_StateAction(sm, load, data_only); + ret &= TIMER_StateAction(sm, load, data_only); + ret &= SIO_StateAction(sm, load, data_only); + + ret &= CDC->StateAction(sm, load, data_only); + ret &= MDEC_StateAction(sm, load, data_only); + ret &= GPU->StateAction(sm, load, data_only); + ret &= SPU->StateAction(sm, load, data_only); + + ret &= FIO->StateAction(sm, load, data_only); + + ret &= IRQ_StateAction(sm, load, data_only); // Do it last. + + if(load) + { + ForceEventUpdates(0); // FIXME to work with debugger step mode. + } + + return(ret); +} + +static void CDInsertEject(void) +{ + CD_TrayOpen = !CD_TrayOpen; + + for(unsigned disc = 0; disc < cdifs->size(); disc++) + { + if(!(*cdifs)[disc]->Eject(CD_TrayOpen)) + { + + CD_TrayOpen = !CD_TrayOpen; + } + } + + +//DAWWWWW + //CDC->SetDisc(CD_TrayOpen, (CD_SelectedDisc >= 0 && !CD_TrayOpen) ? (*cdifs)[CD_SelectedDisc] : NULL, + //(CD_SelectedDisc >= 0 && !CD_TrayOpen) ? cdifs_scex_ids[CD_SelectedDisc] : NULL); +} + +static void CDEject(void) +{ + if(!CD_TrayOpen) + CDInsertEject(); +} + +static void CDSelect(void) +{ + if(cdifs && CD_TrayOpen) + { + CD_SelectedDisc = (CD_SelectedDisc + 1) % (cdifs->size() + 1); + + if((unsigned)CD_SelectedDisc == cdifs->size()) + CD_SelectedDisc = -1; + + + } +} + + +static void DoSimpleCommand(int cmd) +{ + switch(cmd) + { + case MDFN_MSC_RESET: PSX_Power(); break; + case MDFN_MSC_POWER: PSX_Power(); break; + + case MDFN_MSC_INSERT_DISK: + CDInsertEject(); + break; + + case MDFN_MSC_SELECT_DISK: + CDSelect(); + break; + + case MDFN_MSC_EJECT_DISK: + CDEject(); + break; + } +} +// +//static void GSCondCode(MemoryPatch* patch, const char* cc, const unsigned len, const uint32 addr, const uint16 val) +//{ +// char tmp[256]; +// +// if(patch->conditions.size() > 0) +// patch->conditions.append(", "); +// +// if(len == 2) +// trio_snprintf(tmp, 256, "%u L 0x%08x %s 0x%04x", len, addr, cc, val & 0xFFFFU); +// else +// trio_snprintf(tmp, 256, "%u L 0x%08x %s 0x%02x", len, addr, cc, val & 0xFFU); +// +// patch->conditions.append(tmp); +//} +// +//static bool DecodeGS(const std::string& cheat_string, MemoryPatch* patch) +//{ +// uint64 code = 0; +// unsigned nybble_count = 0; +// +// for(unsigned i = 0; i < cheat_string.size(); i++) +// { +// if(cheat_string[i] == ' ' || cheat_string[i] == '-' || cheat_string[i] == ':') +// continue; +// +// nybble_count++; +// code <<= 4; +// +// if(cheat_string[i] >= '0' && cheat_string[i] <= '9') +// code |= cheat_string[i] - '0'; +// else if(cheat_string[i] >= 'a' && cheat_string[i] <= 'f') +// code |= cheat_string[i] - 'a' + 0xA; +// else if(cheat_string[i] >= 'A' && cheat_string[i] <= 'F') +// code |= cheat_string[i] - 'A' + 0xA; +// else +// { +// if(cheat_string[i] & 0x80) +// throw MDFN_Error(0, _("Invalid character in GameShark code.")); +// else +// throw MDFN_Error(0, _("Invalid character in GameShark code: %c"), cheat_string[i]); +// } +// } +// +// if(nybble_count != 12) +// throw MDFN_Error(0, _("GameShark code is of an incorrect length.")); +// +// const uint8 code_type = code >> 40; +// const uint64 cl = code & 0xFFFFFFFFFFULL; +// +// patch->bigendian = false; +// patch->compare = 0; +// +// if(patch->type == 'T') +// { +// if(code_type != 0x80) +// throw MDFN_Error(0, _("Unrecognized GameShark code type for second part to copy bytes code.")); +// +// patch->addr = cl >> 16; +// return(false); +// } +// +// switch(code_type) +// { +// default: +// throw MDFN_Error(0, _("GameShark code type 0x%02X is currently not supported."), code_type); +// +// return(false); +// +// // +// // +// // TODO: +// case 0x10: // 16-bit increment +// patch->length = 2; +// patch->type = 'A'; +// patch->addr = cl >> 16; +// patch->val = cl & 0xFFFF; +// return(false); +// +// case 0x11: // 16-bit decrement +// patch->length = 2; +// patch->type = 'A'; +// patch->addr = cl >> 16; +// patch->val = (0 - cl) & 0xFFFF; +// return(false); +// +// case 0x20: // 8-bit increment +// patch->length = 1; +// patch->type = 'A'; +// patch->addr = cl >> 16; +// patch->val = cl & 0xFF; +// return(false); +// +// case 0x21: // 8-bit decrement +// patch->length = 1; +// patch->type = 'A'; +// patch->addr = cl >> 16; +// patch->val = (0 - cl) & 0xFF; +// return(false); +// // +// // +// // +// +// case 0x30: // 8-bit constant +// patch->length = 1; +// patch->type = 'R'; +// patch->addr = cl >> 16; +// patch->val = cl & 0xFF; +// return(false); +// +// case 0x80: // 16-bit constant +// patch->length = 2; +// patch->type = 'R'; +// patch->addr = cl >> 16; +// patch->val = cl & 0xFFFF; +// return(false); +// +// case 0x50: // Repeat thingy +// { +// const uint8 wcount = (cl >> 24) & 0xFF; +// const uint8 addr_inc = (cl >> 16) & 0xFF; +// const uint8 val_inc = (cl >> 0) & 0xFF; +// +// patch->mltpl_count = wcount; +// patch->mltpl_addr_inc = addr_inc; +// patch->mltpl_val_inc = val_inc; +// } +// return(true); +// +// case 0xC2: // Copy +// { +// const uint16 ccount = cl & 0xFFFF; +// +// patch->type = 'T'; +// patch->val = 0; +// patch->length = 1; +// +// patch->copy_src_addr = cl >> 16; +// patch->copy_src_addr_inc = 1; +// +// patch->mltpl_count = ccount; +// patch->mltpl_addr_inc = 1; +// patch->mltpl_val_inc = 0; +// } +// return(true); +// +// case 0xD0: // 16-bit == condition +// GSCondCode(patch, "==", 2, cl >> 16, cl); +// return(true); +// +// case 0xD1: // 16-bit != condition +// GSCondCode(patch, "!=", 2, cl >> 16, cl); +// return(true); +// +// case 0xD2: // 16-bit < condition +// GSCondCode(patch, "<", 2, cl >> 16, cl); +// return(true); +// +// case 0xD3: // 16-bit > condition +// GSCondCode(patch, ">", 2, cl >> 16, cl); +// return(true); +// +// +// +// case 0xE0: // 8-bit == condition +// GSCondCode(patch, "==", 1, cl >> 16, cl); +// return(true); +// +// case 0xE1: // 8-bit != condition +// GSCondCode(patch, "!=", 1, cl >> 16, cl); +// return(true); +// +// case 0xE2: // 8-bit < condition +// GSCondCode(patch, "<", 1, cl >> 16, cl); +// return(true); +// +// case 0xE3: // 8-bit > condition +// GSCondCode(patch, ">", 1, cl >> 16, cl); +// return(true); +// +// } +//} +// +//static CheatFormatStruct CheatFormats[] = +//{ +// { "GameShark", gettext_noop("Sharks with lamprey eels for eyes."), DecodeGS }, +//}; +// +//static CheatFormatInfoStruct CheatFormatInfo = +//{ +// 1, +// CheatFormats +//}; +// +//static const FileExtensionSpecStruct KnownExtensions[] = +//{ +// { ".psf", gettext_noop("PSF1 Rip") }, +// { ".minipsf", gettext_noop("MiniPSF1 Rip") }, +// { ".psx", gettext_noop("PS-X Executable") }, +// { ".exe", gettext_noop("PS-X Executable") }, +// { NULL, NULL } +//}; +// +//static const MDFNSetting_EnumList Region_List[] = +//{ +// { "jp", REGION_JP, gettext_noop("Japan") }, +// { "na", REGION_NA, gettext_noop("North America") }, +// { "eu", REGION_EU, gettext_noop("Europe") }, +// { NULL, 0 }, +//}; +// +//#if 0 +//static const MDFNSetting_EnumList MultiTap_List[] = +//{ +// { "0", 0, gettext_noop("Disabled") }, +// { "1", 1, gettext_noop("Enabled") }, +// { "auto", 0, gettext_noop("Automatically-enable multitap."), gettext_noop("NOT IMPLEMENTED YET(currently equivalent to 0)") }, +// { NULL, 0 }, +//}; +//#endif +// +//static MDFNSetting PSXSettings[] = +//{ +// { "psx.input.mouse_sensitivity", MDFNSF_NOFLAGS, gettext_noop("Emulated mouse sensitivity."), NULL, MDFNST_FLOAT, "1.00", NULL, NULL }, +// +// { "psx.input.analog_mode_ct", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Enable analog mode combo-button alternate toggle."), gettext_noop("When enabled, instead of the configured Analog mode toggle button for the emulated DualShock, use a combination of buttons to toggle it instead. When Select, Start, and all four shoulder buttons are held down for about 1 second, the mode will toggle."), MDFNST_BOOL, "0", NULL, NULL }, +// +// { "psx.input.pport1.multitap", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Enable multitap on PSX port 1."), gettext_noop("Makes 3 more virtual ports available.\n\nNOTE: Enabling multitap in games that don't fully support it may cause deleterious effects."), MDFNST_BOOL, "0", NULL, NULL }, //MDFNST_ENUM, "auto", NULL, NULL, NULL, NULL, MultiTap_List }, +// { "psx.input.pport2.multitap", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Enable multitap on PSX port 2."), gettext_noop("Makes 3 more virtual ports available.\n\nNOTE: Enabling multitap in games that don't fully support it may cause deleterious effects."), MDFNST_BOOL, "0", NULL, NULL }, +// +// { "psx.input.port1.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Emulate memcard on virtual port 1."), NULL, MDFNST_BOOL, "1", NULL, NULL, }, +// { "psx.input.port2.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Emulate memcard on virtual port 2."), NULL, MDFNST_BOOL, "1", NULL, NULL, }, +// { "psx.input.port3.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Emulate memcard on virtual port 3."), NULL, MDFNST_BOOL, "1", NULL, NULL, }, +// { "psx.input.port4.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Emulate memcard on virtual port 4."), NULL, MDFNST_BOOL, "1", NULL, NULL, }, +// { "psx.input.port5.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Emulate memcard on virtual port 5."), NULL, MDFNST_BOOL, "1", NULL, NULL, }, +// { "psx.input.port6.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Emulate memcard on virtual port 6."), NULL, MDFNST_BOOL, "1", NULL, NULL, }, +// { "psx.input.port7.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Emulate memcard on virtual port 7."), NULL, MDFNST_BOOL, "1", NULL, NULL, }, +// { "psx.input.port8.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Emulate memcard on virtual port 8."), NULL, MDFNST_BOOL, "1", NULL, NULL, }, +// +// +// { "psx.input.port1.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on virtual port 1."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0xFF0000", "0x000000", "0x1000000" }, +// { "psx.input.port2.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on virtual port 2."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0x00FF00", "0x000000", "0x1000000" }, +// { "psx.input.port3.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on virtual port 3."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0xFF00FF", "0x000000", "0x1000000" }, +// { "psx.input.port4.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on virtual port 4."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0xFF8000", "0x000000", "0x1000000" }, +// { "psx.input.port5.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on virtual port 5."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0xFFFF00", "0x000000", "0x1000000" }, +// { "psx.input.port6.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on virtual port 6."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0x00FFFF", "0x000000", "0x1000000" }, +// { "psx.input.port7.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on virtual port 7."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0x0080FF", "0x000000", "0x1000000" }, +// { "psx.input.port8.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on virtual port 8."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0x8000FF", "0x000000", "0x1000000" }, +// +// { "psx.region_autodetect", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Attempt to auto-detect region of game."), NULL, MDFNST_BOOL, "1" }, +// { "psx.region_default", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Default region to use."), gettext_noop("Used if region autodetection fails or is disabled."), MDFNST_ENUM, "jp", NULL, NULL, NULL, NULL, Region_List }, +// +// { "psx.bios_jp", MDFNSF_EMU_STATE, gettext_noop("Path to the Japan SCPH-5500 ROM BIOS"), NULL, MDFNST_STRING, "scph5500.bin" }, +// { "psx.bios_na", MDFNSF_EMU_STATE, gettext_noop("Path to the North America SCPH-5501 ROM BIOS"), gettext_noop("SHA1 0555c6fae8906f3f09baf5988f00e55f88e9f30b"), MDFNST_STRING, "scph5501.bin" }, +// { "psx.bios_eu", MDFNSF_EMU_STATE, gettext_noop("Path to the Europe SCPH-5502 ROM BIOS"), NULL, MDFNST_STRING, "scph5502.bin" }, +// +// { "psx.spu.resamp_quality", MDFNSF_NOFLAGS, gettext_noop("SPU output resampler quality."), +// gettext_noop("0 is lowest quality and CPU usage, 10 is highest quality and CPU usage. The resampler that this setting refers to is used for converting from 44.1KHz to the sampling rate of the host audio device Mednafen is using. Changing Mednafen's output rate, via the \"sound.rate\" setting, to \"44100\" may bypass the resampler, which can decrease CPU usage by Mednafen, and can increase or decrease audio quality, depending on various operating system and hardware factors."), MDFNST_UINT, "5", "0", "10" }, +// +// +// { "psx.slstart", MDFNSF_NOFLAGS, gettext_noop("First displayed scanline in NTSC mode."), NULL, MDFNST_INT, "0", "0", "239" }, +// { "psx.slend", MDFNSF_NOFLAGS, gettext_noop("Last displayed scanline in NTSC mode."), NULL, MDFNST_INT, "239", "0", "239" }, +// +// { "psx.slstartp", MDFNSF_NOFLAGS, gettext_noop("First displayed scanline in PAL mode."), NULL, MDFNST_INT, "0", "0", "287" }, +// { "psx.slendp", MDFNSF_NOFLAGS, gettext_noop("Last displayed scanline in PAL mode."), NULL, MDFNST_INT, "287", "0", "287" }, +// +//#if PSX_DBGPRINT_ENABLE +// { "psx.dbg_level", MDFNSF_NOFLAGS, gettext_noop("Debug printf verbosity level."), NULL, MDFNST_UINT, "0", "0", "4" }, +//#endif +// +// { "psx.clobbers_lament", MDFNSF_NOFLAGS, gettext_noop("Enable experimental save state functionality."), gettext_noop("Save states will destroy your saved game/memory card data if you're careless, and that will make clobber sad. Poor clobber."), MDFNST_BOOL, "0" }, +// +// { NULL }, +//}; + + +EW_EXPORT s32 shock_CreateDisc(ShockDiscRef** outDisc, void *Opaque, s32 lbaCount, ShockDisc_ReadTOC ReadTOC, ShockDisc_ReadLBA ReadLBA2448, bool suppliesDeinterleavedSubcode) +{ + *outDisc = new ShockDiscRef(Opaque, lbaCount, ReadTOC, ReadLBA2448, suppliesDeinterleavedSubcode); + return SHOCK_OK; +} + +ShockDiscRef* s_CurrDisc = NULL; +ShockDiscInfo s_CurrDiscInfo; + +//Sets the disc in the tray. Returns SHOCK_NOCANDO if it's closed. You can pass NULL to remove a disc from the tray +EW_EXPORT s32 shock_SetDisc(void* psx, ShockDiscRef* disc) +{ + //TODO - non-psx disc is legal here. should pass null ID to CDC setdisc + + //analyze disc so we dont have to annoyingly manage it from client + ShockDiscInfo info; + s32 ret = shock_AnalyzeDisc(disc,&info); + if(ret != SHOCK_OK) return ret; + + s_CurrDiscInfo = info; + s_CurrDisc = disc; + CDC->SetDisc(true,s_CurrDisc,s_CurrDiscInfo.id); + + return SHOCK_OK; +} + +EW_EXPORT s32 shock_OpenTray(void* psx) +{ + CDC->SetDisc(true,s_CurrDisc,s_CurrDiscInfo.id); + return SHOCK_OK; +} + +EW_EXPORT s32 shock_CloseTray(void* psx) +{ + CDC->SetDisc(false,s_CurrDisc,s_CurrDiscInfo.id); + return SHOCK_OK; +} + + +EW_EXPORT s32 shock_DestroyDisc(ShockDiscRef* disc) +{ + delete disc; + return SHOCK_OK; +} + + +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; +}; + +//THIS CODE SHOULD BE REMOVED WHEN A MORE ROBUST ISO PARSER IS ADDED. +class ShockDiscRef_Stream_Thing : public Stream +{ + public: + + ShockDiscRef_Stream_Thing(ShockDiscRef *cdintf_arg, uint32 lba_arg, uint32 sector_count_arg); + ~ShockDiscRef_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: + ShockDiscRef *cdintf; + const uint32 start_lba; + const uint32 sector_count; + int64 position; +}; + +ShockDiscRef_Stream_Thing::ShockDiscRef_Stream_Thing(ShockDiscRef *cdintf_arg, uint32 start_lba_arg, uint32 sector_count_arg) + : cdintf(cdintf_arg) + , start_lba(start_lba_arg) + , sector_count(sector_count_arg) +{ + +} + +ShockDiscRef_Stream_Thing::~ShockDiscRef_Stream_Thing() +{ + +} + +uint64 ShockDiscRef_Stream_Thing::attributes(void) +{ + return(ATTRIBUTE_READABLE | ATTRIBUTE_SEEKABLE); +} + +uint8 *ShockDiscRef_Stream_Thing::map(void) +{ + return NULL; +} + +void ShockDiscRef_Stream_Thing::unmap(void) +{ + +} + +uint64 ShockDiscRef_Stream_Thing::read(void *data, uint64 count, bool error_on_eos) +{ + if(count > (((uint64)sector_count * 2048) - position)) + { + //if(error_on_eos) + //{ + // throw "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->ReadLBA2048(start_lba + (rp / 2048), buf)) + { + //throw MDFN_Error(ErrnoHolder(EIO)); + return 0; //??????????? + } + + //::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 ShockDiscRef_Stream_Thing::write(const void *data, uint64 count) +{ + +} + +void ShockDiscRef_Stream_Thing::seek(int64 offset, int whence) +{ + int64 new_position; + + switch(whence) + { + default: + + 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 ShockDiscRef_Stream_Thing::tell(void) +{ + return position; +} + +int64 ShockDiscRef_Stream_Thing::size(void) +{ + return(sector_count * 2048); +} + +void ShockDiscRef_Stream_Thing::close(void) +{ + +} + +//Analyzes the disc by inspecting other things, in case the system.cnf determination failed +static s32 AnalyzeDiscEx(ShockDiscRef* disc, ShockDiscInfo* info) +{ + const char *id = NULL; + uint8 buf[2048]; + uint8 fbuf[2048 + 1]; + unsigned ipos, opos; + int i; + + //clear it out in case of error + info->region = REGION_NONE; + info->id[0] = 0; + + memset(fbuf, 0, sizeof(fbuf)); + + //if it wasnt mode 2, we failed + s32 readed = disc->ReadLBA2048(4, buf); + if(readed != 0x02) + return SHOCK_ERROR; + + //lowercase strings for searching + for(ipos = 0, opos = 0; ipos < 0x48; ipos++) + { + if(buf[ipos] > 0x20 && buf[ipos] < 0x80) + { + fbuf[opos++] = tolower(buf[ipos]); + } + } + + fbuf[opos++] = 0; + + PSX_DBG(PSX_DBG_SPARSE, "License string: %s", (char *)fbuf); + + if(strstr((char *)fbuf, "licensedby") != NULL) + { + if(strstr((char *)fbuf, "america") != NULL) + { + strcpy(info->id,"SCEA"); + info->region = REGION_NA; + return SHOCK_OK; + } + else if(strstr((char *)fbuf, "europe") != NULL) + { + strcpy(info->id,"SCEE"); + info->region = REGION_EU; + return SHOCK_OK; + } + else if(strstr((char *)fbuf, "japan") != NULL) + { + strcpy(info->id,"SCEI"); + info->region = REGION_JP; + return SHOCK_OK; + } + else if(strstr((char *)fbuf, "sonycomputerentertainmentinc.") != NULL) + { + strcpy(info->id,"SCEI"); + info->region = REGION_JP; + return SHOCK_OK; + } + } + + return SHOCK_ERROR; +} + +//this is kind of lame. cant we get a proper iso fs parser here? +EW_EXPORT s32 shock_AnalyzeDisc(ShockDiscRef* disc, ShockDiscInfo* info) +{ + const char *ret = NULL; + Stream *fp = NULL; + CDUtility::TOC toc; + + //(*CDInterfaces)[disc]->ReadTOC(&toc); + + //if(toc.first_track > 1 || toc. + + try + { + uint8 pvd[2048]; + unsigned pvd_search_count = 0; + + fp = new ShockDiscRef_Stream_Thing(disc, 0, ~0); + fp->seek(0x8000, SEEK_SET); + + do + { + if((pvd_search_count++) == 32) + throw "PVD search count limit met."; + + fp->read(pvd, 2048); + + if(memcmp(&pvd[1], "CD001", 5)) + throw "Not ISO-9660"; + + if(pvd[0] == 0xFF) + throw "Missing Primary Volume Descriptor"; + } while(pvd[0] != 0x01); + //[156 ... 189], 34 bytes + uint32 rdel = MDFN_de32lsb(&pvd[0x9E]); + uint32 rdel_len = MDFN_de32lsb(&pvd[0xA6]); + + if(rdel_len >= (1024 * 1024 * 10)) // Arbitrary sanity check. + throw "Root directory table too large"; + + fp->seek((int64)rdel * 2048, SEEK_SET); + //printf("%08x, %08x\n", rdel * 2048, rdel_len); + + //I think this loop is scanning directory entries until it finds system.cnf and if it never finishes we'll jsut fall out + while(fp->tell() < (((int64)rdel * 2048) + rdel_len)) + { + uint8 len_dr = fp->get_u8(); + uint8 dr[256 + 1]; + + memset(dr, 0xFF, sizeof(dr)); + + if(!len_dr) + break; + + memset(dr, 0, sizeof(dr)); + dr[0] = len_dr; + fp->read(dr + 1, len_dr - 1); + + uint8 len_fi = dr[0x20]; + + if(len_fi == 12 && !memcmp(&dr[0x21], "SYSTEM.CNF;1", 12)) + { + uint32 file_lba = MDFN_de32lsb(&dr[0x02]); + //uint32 file_len = MDFN_de32lsb(&dr[0x0A]); + uint8 fb[2048 + 1]; + char *bootpos; + + memset(fb, 0, sizeof(fb)); + fp->seek(file_lba * 2048, SEEK_SET); + fp->read(fb, 2048); + + bootpos = strstr((char*)fb, "BOOT") + 4; + while(*bootpos == ' ' || *bootpos == '\t') bootpos++; + if(*bootpos == '=') + { + bootpos++; + while(*bootpos == ' ' || *bootpos == '\t') bootpos++; + if(!strncasecmp(bootpos, "cdrom:\\", 7)) + { + bootpos += 7; + char *tmp; + + if((tmp = strchr(bootpos, '_'))) *tmp = 0; + if((tmp = strchr(bootpos, '.'))) *tmp = 0; + if((tmp = strchr(bootpos, ';'))) *tmp = 0; + //puts(bootpos); + + if(strlen(bootpos) == 4 && bootpos[0] == 'S' && (bootpos[1] == 'C' || bootpos[1] == 'L' || bootpos[1] == 'I')) + { + switch(bootpos[2]) + { + case 'E': + info->region = REGION_EU; + strcpy(info->id,"SCEE"); + goto Breakout; + + case 'U': + info->region = REGION_NA; + strcpy(info->id,"SCEA"); + goto Breakout; + + case 'K': // Korea? + case 'B': + case 'P': + info->region = REGION_JP; + strcpy(info->id,"SCEI"); + goto Breakout; + } + } + } + } + + //puts((char*)fb); + //puts("ASOFKOASDFKO"); + } + } + } + catch(const char* str) + { + //puts(e.what()); + int zzz=9; + } + catch(...) + { + int zzz=9; + } + + //uhmm couldnt find system.cnf. try another way + return AnalyzeDiscEx(disc,info); + +Breakout: + + return SHOCK_OK; +} + +s32 ShockDiscRef::ReadLBA2448(s32 lba, void* dst2448) +{ + return InternalReadLBA2448(lba, dst2448, true); +} + +s32 ShockDiscRef::InternalReadLBA2448(s32 lba, void* dst2448, bool needSubcode) +{ + int ret = mcbReadLBA2448(mOpaque, lba, dst2448); + if(ret != SHOCK_OK) + return ret; + + if(needSubcode && mSuppliesDeinterleavedSubcode) + { + u8 tmp[96]; + CDUtility::subpw_interleave((u8*)dst2448+2352,tmp); + memcpy((u8*)dst2448+2352,tmp,96); + } + + return SHOCK_OK; +} + +//adapts the ReadLBA2448 results to a 2048 byte sector and returns the mode, as required +s32 ShockDiscRef::ReadLBA2048(s32 lba, void* dst2048) +{ + union Sector { + struct { + u8 sync[12]; + u8 adr[3]; + u8 mode; + union { + struct { + u8 data2048[2048]; + u8 ecc[4]; + u8 reserved[8]; + u8 ecm[276]; + }; + u8 data2336[2336]; + }; + }; + u8 buf[2352]; + }; + + union XASector { + struct { + u8 sync[12]; + u8 adr[3]; + u8 mode; + u8 subheader[8]; + union { + u8 data2048[2048]; + u8 ecc[4]; + u8 ecm[276]; + } form1; + union { + u8 data2334[2334]; + u8 ecc[4]; + } form2; + }; + u8 buf[2352]; + }; + + static union { + struct { + union { + XASector xasector; + Sector sector; + }; + u8 subcode[96]; + }; + u8 buf2448[2448]; + }; + + s32 ret = InternalReadLBA2448(lba,buf2448,false); + if(ret != SHOCK_OK) + return ret; + + if(sector.mode == 1) + memcpy(dst2048,sector.data2048,2048); + else + memcpy(dst2048,xasector.form1.data2048,2048); + + return sector.mode; +} \ No newline at end of file diff --git a/psx/octoshock/psx/psx.h b/psx/octoshock/psx/psx.h new file mode 100644 index 0000000000..36ba924e8b --- /dev/null +++ b/psx/octoshock/psx/psx.h @@ -0,0 +1,253 @@ +#pragma once + +#include "emuware/emuware.h" +#include "cdrom/cdromif.h" +#include "video/surface.h" +#include "masmem.h" +#include "endian.h" + + +// +// Comment out these 2 defines for extra speeeeed. +// +#define PSX_DBGPRINT_ENABLE 1 +#define PSX_EVENT_SYSTEM_CHECKS 1 + +// +// It's highly unlikely the user will want these if they're intentionally compiling without the debugger. +#ifndef WANT_DEBUGGER + #undef PSX_DBGPRINT_ENABLE + #undef PSX_EVENT_SYSTEM_CHECKS +#endif +// +// +// + +namespace MDFN_IEN_PSX +{ + #define PSX_DBG_ERROR 0 // Emulator-level error. + #define PSX_DBG_WARNING 1 // Warning about game doing questionable things/hitting stuff that might not be emulated correctly. + #define PSX_DBG_BIOS_PRINT 2 // BIOS printf/putchar output. + #define PSX_DBG_SPARSE 3 // Sparse(relatively) information debug messages(CDC commands). + #define PSX_DBG_FLOOD 4 // Heavy informational debug messages(GPU commands; TODO). + +#if PSX_DBGPRINT_ENABLE + void PSX_DBG(unsigned level, const char *format, ...) throw() MDFN_COLD MDFN_FORMATSTR(gnu_printf, 2, 3); + + #define PSX_WARNING(format, ...) { PSX_DBG(PSX_DBG_WARNING, format "\n", ## __VA_ARGS__); } + #define PSX_DBGINFO(format, ...) { } +#else + static INLINE void PSX_DBG(unsigned level, const char* format, ...) { } + static INLINE void PSX_WARNING(const char* format, ...) { } + static INLINE void PSX_DBGINFO(const char* format, ...) { } +#endif + + typedef int32 pscpu_timestamp_t; + + bool PSX_EventHandler(const pscpu_timestamp_t timestamp); + + void PSX_MemWrite8(pscpu_timestamp_t timestamp, uint32 A, uint32 V); + void PSX_MemWrite16(pscpu_timestamp_t timestamp, uint32 A, uint32 V); + void PSX_MemWrite24(pscpu_timestamp_t timestamp, uint32 A, uint32 V); + void PSX_MemWrite32(pscpu_timestamp_t timestamp, uint32 A, uint32 V); + + uint8 PSX_MemRead8(pscpu_timestamp_t ×tamp, uint32 A); + uint16 PSX_MemRead16(pscpu_timestamp_t ×tamp, uint32 A); + uint32 PSX_MemRead24(pscpu_timestamp_t ×tamp, uint32 A); + uint32 PSX_MemRead32(pscpu_timestamp_t ×tamp, uint32 A); + + uint8 PSX_MemPeek8(uint32 A); + uint16 PSX_MemPeek16(uint32 A); + uint32 PSX_MemPeek32(uint32 A); + + // Should write to WO-locations if possible + #if 0 + void PSX_MemPoke8(uint32 A, uint8 V); + void PSX_MemPoke16(uint32 A, uint16 V); + void PSX_MemPoke32(uint32 A, uint32 V); + #endif + + void PSX_RequestMLExit(void); + void ForceEventUpdates(const pscpu_timestamp_t timestamp); + + enum + { + PSX_EVENT__SYNFIRST = 0, + PSX_EVENT_GPU, + PSX_EVENT_CDC, + //PSX_EVENT_SPU, + PSX_EVENT_TIMER, + PSX_EVENT_DMA, + PSX_EVENT_FIO, + PSX_EVENT__SYNLAST, + PSX_EVENT__COUNT, + }; + + #define PSX_EVENT_MAXTS 0x20000000 + void PSX_SetEventNT(const int type, const pscpu_timestamp_t next_timestamp); + + void PSX_GPULineHook(const pscpu_timestamp_t timestamp, const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider); + + uint32 PSX_GetRandU32(uint32 mina, uint32 maxa); +}; + + +#include "dis.h" +#include "cpu.h" +#include "irq.h" +#include "gpu.h" +#include "dma.h" +//#include "sio.h" +#include "debug.h" + +namespace MDFN_IEN_PSX +{ + class PS_CDC; + class PS_SPU; + + extern PS_CPU *CPU; + extern PS_GPU *GPU; + extern PS_CDC *CDC; + extern PS_SPU *SPU; + extern MultiAccessSizeMem<2048 * 1024, uint32, false> MainRAM; +}; + +enum eRegion +{ + REGION_JP = 0, + REGION_NA = 1, + REGION_EU = 2, + REGION_NONE = 3 +}; + +enum eShockStep +{ + eShockStep_Frame +}; + + +enum eShockSetting +{ + REGION_AUTODETECT = 0, + REGION_DEFAULT = 1, + SLSTART = 2, + SLEND = 3, + SLSTARTP = 4, + SLENDP = 5 +}; + +int shock_GetSetting(eShockSetting setting); + +#define MDFN_MSC_RESET 0 +#define MDFN_MSC_POWER 1 +#define MDFN_MSC_INSERT_DISK 2 +#define MDFN_MSC_SELECT_DISK 3 +#define MDFN_MSC_EJECT_DISK 4 + +#define SHOCK_OK 0 +#define SHOCK_ERROR -1 +#define SHOCK_NOCANDO -2 + +struct ShockTOCTrack +{ + u8 adr; + u8 control; + u32 lba; +}; + +struct ShockTOC +{ + u8 first_track; + u8 last_track; + u8 disc_type; +}; + +// [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). +typedef s32 (*ShockDisc_ReadTOC)(void* opaque, ShockTOC *read_target, ShockTOCTrack tracks[100 + 1]); +typedef s32 (*ShockDisc_ReadLBA)(void* opaque, s32 lba, void* dst); + +class ShockDiscRef +{ +public: + ShockDiscRef(void *opaque, s32 lbaCount, ShockDisc_ReadTOC cbReadTOC, ShockDisc_ReadLBA cbReadLBA2448, bool suppliesDeinterleavedSubcode) + : mOpaque(opaque) + , mLbaCount(lbaCount) + , mcbReadTOC(cbReadTOC) + , mcbReadLBA2448(cbReadLBA2448) + , mSuppliesDeinterleavedSubcode(suppliesDeinterleavedSubcode) + { + } + + s32 ReadTOC( ShockTOC *read_target, ShockTOCTrack tracks[100 + 1]) + { + return mcbReadTOC(mOpaque, read_target, tracks); + } + + s32 ReadLBA2448(s32 lba, void* dst2448); + s32 ReadLBA2048(s32 lba, void* dst2048); + +private: + s32 InternalReadLBA2448(s32 lba, void* dst2448, bool needSubcode); + void *mOpaque; + s32 mLbaCount; + ShockDisc_ReadTOC mcbReadTOC; + ShockDisc_ReadLBA mcbReadLBA2448; + bool mSuppliesDeinterleavedSubcode; +}; + +struct ShockDiscInfo +{ + s32 region; + char id[5]; //SCEI, SCEA, SCEE, etc. with null terminator +}; + +struct ShockFramebufferJob +{ + int width, height; + void* ptr; +}; + +//Creates a ShockDiscRef (representing a disc) with the given properties. Returns it in the specified output pointer. +//The ReadLBA2048 function should return 0x01 or 0x02 depending on which mode was there. +//Others should return SHOCK_OK +EW_EXPORT s32 shock_CreateDisc(ShockDiscRef** outDisc, void *Opaque, s32 lbaCount, ShockDisc_ReadTOC ReadTOC, ShockDisc_ReadLBA ReadLBA2448, bool suppliesDeinterleavedSubcode); + +//Destroys a ShockDiscRef created with shock_CreateDisc. Make sure you havent left it in the playstation before destroying it! +EW_EXPORT s32 shock_DestroyDisc(ShockDiscRef* disc); + +//Inspects a disc by looking for the system.cnf and retrieves some necessary information about it. +//Useful for determining the region of a disc +EW_EXPORT s32 shock_AnalyzeDisc(ShockDiscRef* disc, ShockDiscInfo* info); + +//Creates the psx instance as a console of the specified region. +//Additionally mounts the firmware from the provided buffer (the contents are copied) +//TODO - receive a model number parameter instead +EW_EXPORT s32 shock_Create(void** psx, eRegion region, void* firmware512k); + +//Frees the psx instance created with shock_Create +EW_EXPORT s32 shock_Destroy(void* psx); + +//Sets the power to ON. Returns SHOCK_NOCANDO if already on. +EW_EXPORT s32 shock_PowerOn(void* psx); + +//Sets the power to OFF. Returns SHOCK_NOCANDO if already off. +EW_EXPORT s32 shock_PowerOff(void* psx); + +//Opens the disc tray. Returns SHOCK_NOCANDO if already open. +EW_EXPORT s32 shock_OpenTray(void* psx); + +//Sets the disc in the tray. Returns SHOCK_NOCANDO if it's closed. You can pass NULL to remove a disc from the tray +EW_EXPORT s32 shock_SetDisc(void* psx, ShockDiscRef* disc); + +//Closes the disc tray. Returns SHOCK_NOCANDO if already closed. +EW_EXPORT s32 shock_CloseTray(void* psx); + +//Steps emulation by the specified interval +EW_EXPORT s32 shock_Step(void* psx, eShockStep step); + +//Fetches the framebuffer. Can retrieve parameters (set the job ptr to NULL) or fill the provided job ptr with the framebuffer (make sure its big enough). +//This helps us copy fewer times. +//TODO - support pitch and color format conversion if needed +EW_EXPORT s32 shock_GetFramebuffer(void* psx, ShockFramebufferJob* fb); \ No newline at end of file diff --git a/psx/octoshock/psx/sio.cpp b/psx/octoshock/psx/sio.cpp new file mode 100644 index 0000000000..a2b02c0937 --- /dev/null +++ b/psx/octoshock/psx/sio.cpp @@ -0,0 +1,128 @@ +/* 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 "psx.h" +#include "sio.h" + +namespace MDFN_IEN_PSX +{ + +// Dummy implementation. + +static uint16 Status; +static uint16 Mode; +static uint16 Control; +static uint16 BaudRate; +static uint32 DataBuffer; + +void SIO_Power(void) +{ + Status = 0; + Mode = 0; + Control = 0; + BaudRate = 0; + DataBuffer = 0; +} + +uint32 SIO_Read(pscpu_timestamp_t timestamp, uint32 A) +{ + uint32 ret = 0; + + switch(A & 0xE) + { + default: + PSX_WARNING("[SIO] Unknown read: 0x%08x -- %d\n", A, timestamp); + break; + + case 0x0: + //case 0x2: + ret = DataBuffer >> ((A & 2) * 8); + break; + + case 0x4: + ret = Status; + break; + + case 0x8: + ret = Mode; + break; + + case 0xA: + ret = Control; + break; + + case 0xE: + ret = BaudRate; + break; + } + + return(ret >> ((A & 1) * 8)); +} + +void SIO_Write(pscpu_timestamp_t timestamp, uint32 A, uint32 V) +{ + V <<= (A & 1) * 8; + + switch(A & 0xE) + { + default: + PSX_WARNING("[SIO] Unknown write: 0x%08x 0x%08x -- %d\n", A, V, timestamp); + break; + + case 0x0: + //case 0x2: + V <<= (A & 2) * 8; + DataBuffer = V; + break; + + case 0x8: + Mode = V; + break; + + case 0xA: + Control = V; + break; + + case 0xE: + BaudRate = V; + break; + } +} + +int SIO_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { + SFVAR(Status), + SFVAR(Mode), + SFVAR(Control), + SFVAR(BaudRate), + SFVAR(DataBuffer), + + SFEND + }; + int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "SIO"); + + if(load) + { + + } + + return(ret); +} + +} diff --git a/psx/octoshock/psx/sio.h b/psx/octoshock/psx/sio.h new file mode 100644 index 0000000000..eccd5d0ab7 --- /dev/null +++ b/psx/octoshock/psx/sio.h @@ -0,0 +1,15 @@ +#ifndef __MDFN_PSX_SIO_H +#define __MDFN_PSX_SIO_H + +namespace MDFN_IEN_PSX +{ + +void SIO_Write(pscpu_timestamp_t timestamp, uint32 A, uint32 V); +uint32 SIO_Read(pscpu_timestamp_t timestamp, uint32 A); +void SIO_Power(void); + +int SIO_StateAction(StateMem *sm, int load, int data_only); + +} + +#endif diff --git a/psx/octoshock/psx/spu.cpp b/psx/octoshock/psx/spu.cpp new file mode 100644 index 0000000000..4caad3b07a --- /dev/null +++ b/psx/octoshock/psx/spu.cpp @@ -0,0 +1,1569 @@ +/* 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: + Note to self: Emulating the SPU at more timing accuracy than sample, and emulating the whole SPU RAM write port FIFO thing and hypothetical periodic FIFO commit to + SPU RAM(maybe every 32 CPU cycles, with exceptions?) will likely necessitate a much more timing-accurate CPU core, and emulation of the SPU delay register(or at least the + effects of the standard value written to it), to avoid game glitches. Probably more trouble than it's worth.... + + SPU IRQ emulation isn't totally correct, behavior is kind of complex; run more tests on PS1. + + Test reverb upsampler on the real thing. + + Alter reverb algorithm to process in the pattern of L,R,L,R,L,R on each input sample, instead of doing both L and R on every 2 input samples(make + sure the real thing does it this way too, I think it at least runs the downsampler this way); and while we're at it, implement the correct buffer + offset(probably either -39 or -40, the latter is what we have now). + + Alter reverb algorithm to perform saturation more often, as occurs on the real thing. + + See if sample flag & 0x8 does anything weird, like suppressing the program-readable block end flag setting. + + Determine the actual purpose of global register 0x2C(is it REALLY an address multiplier? And if so, does it affect the reverb offsets too?) + + For ADSR and volume sweep, should the divider be reset to 0 on &0x8000 == true, or should the upper bit be cleared? + + Should shift occur on all stages of ADPCM sample decoding, or only at the end? + + On the real thing, there's some kind of weirdness with ADSR when you voice on when attack_rate(raw) = 0x7F; the envelope level register is repeatedly + reset to 0, which you can see by manual writes to the envelope level register. Normally in the attack phase when attack_rate = 0x7F, enveloping is effectively stuck/paused such that the value you write is sticky and won't be replaced or reset. Note that after you voice on, you can write a new attack_rate < 0x7F, and enveloping will work "normally" again shortly afterwards. You can even write an attack_rate of 0x7F at that point to pause enveloping clocking. I doubt any games rely on this, but it's something to keep in mind if we ever need greater insight as to how the SPU functions at a low-level in order to emulate it at cycle granularity rather than sample granularity, and it may not be a bad idea to investigate this oddity further and emulate it in the future regardless. + + Voice 1 and 3 waveform output writes to SPURAM might not be correct(noted due to problems reading this area of SPU RAM on the real thing + based on my expectations of how this should work). +*/ + +/* + Notes: + The last half of the noise freq table was confirmed on a real PSX(more or less, number of changes * 0x8000 / samples), but the first half hasn't been yet with sufficient precision. + + All addresses(for 16-bit access, at least) within the SPU address space appear to be fully read/write as if they were RAM, though + values at some addresses(like the envelope current value) will be "overwritten" by the sound processing at certain times. + + 32-bit and 8-bit reads act as if it were RAM(not tested with all addresses, but a few, assuming the rest are the same), but 8-bit writes + to odd addresses appear to be ignored, and 8-bit writes to even addresses are treated as 16-bit writes(most likely, but, need to code custom assembly to + fully test the upper 8 bits). NOTE: the preceding information doesn't necessarily cover accesses with side effects, they still need to be tested; and it + of course covers reads/writes from the point of view of software running on the CPU. + + It doesn't appear to be possible to enable FM on the first channel/voice(channel/voice 0). + + Lower bit of channel start address appears to be masked out to 0(such that ADPCM block decoding is always 8 16-bit units, 16 bytes, aligned), as far as + block-decoding and flag-set program-readable loop address go. +*/ + +/* + Update() isn't called on Read and Writes for performance reasons, it's called with sufficient granularity from the event + system, though this will obviously need to change if we ever emulate the SPU with better precision than per-sample(pair). +*/ + +#define SPUIRQ_DBG(format, ...) { printf("[SPUIRQDBG] " format " -- Voice 22 CA=0x%06x,LA=0x%06x\n", ## __VA_ARGS__, Voices[22].CurAddr, Voices[22].LoopAddr); } + +#include "psx.h" +#include "cdc.h" +#include "spu.h" + +namespace MDFN_IEN_PSX +{ + +static const int16 FIR_Table[256][4] = +{ + #include "spu_fir_table.inc" +}; + +static const uint32 NoiseFreqTable[64] = +{ + #include "spu_nft.inc" +}; + +PS_SPU::PS_SPU() +{ + last_rate = -1; + last_quality = ~0U; + + IntermediateBufferPos = 0; + memset(IntermediateBuffer, 0, sizeof(IntermediateBuffer)); + + for(int16 a = 32760; a >= 0; a++); +} + +PS_SPU::~PS_SPU() +{ +} + +void PS_SPU::Power(void) +{ + clock_divider = 768; + + memset(SPURAM, 0, sizeof(SPURAM)); + + for(int i = 0; i < 24; i++) + { + memset(Voices[i].DecodeBuffer, 0, sizeof(Voices[i].DecodeBuffer)); + Voices[i].DecodeM2 = 0; + Voices[i].DecodeM1 = 0; + + Voices[i].DecodePlayDelay = 0; + Voices[i].DecodeWritePos = 0; + Voices[i].DecodeReadPos = 0; + Voices[i].DecodeAvail = 0; + + Voices[i].DecodeShift = 0; + Voices[i].DecodeWeight = 0; + Voices[i].DecodeFlags = 0; + + Voices[i].IgnoreSampLA = false; + + Voices[i].Sweep[0].Power(); + Voices[i].Sweep[1].Power(); + + Voices[i].Pitch = 0; + Voices[i].CurPhase = 0; + + Voices[i].StartAddr = 0; + + Voices[i].CurAddr = 0; + + Voices[i].ADSRControl = 0; + + Voices[i].LoopAddr = 0; + + Voices[i].PreLRSample = 0; + + memset(&Voices[i].ADSR, 0, sizeof(SPU_ADSR)); + } + + GlobalSweep[0].Power(); + GlobalSweep[1].Power(); + + NoiseCounter = 0; + LFSR = 0; + + FM_Mode = 0; + Noise_Mode = 0; + Reverb_Mode = 0; + ReverbWA = 0; + + ReverbVol[0] = ReverbVol[1] = 0; + + CDVol[0] = CDVol[1] = 0; + + ExternVol[0] = ExternVol[1] = 0; + + IRQAddr = 0; + + RWAddr = 0; + + SPUControl = 0; + + VoiceOn = 0; + VoiceOff = 0; + + BlockEnd = 0; + + CWA = 0; + + memset(Regs, 0, sizeof(Regs)); + + memset(RDSB, 0, sizeof(RDSB)); + RDSB_WP = 0; + + memset(RUSB, 0, sizeof(RUSB)); + RUSB_WP = 0; + + ReverbCur = ReverbWA; + + IRQAsserted = false; +} + +static INLINE void CalcVCDelta(const uint8 zs, uint8 speed, bool log_mode, bool dec_mode, bool inv_increment, int16 Current, int &increment, int &divinco) +{ + increment = (7 - (speed & 0x3)); + + if(inv_increment) + increment = ~increment; + + divinco = 32768; + + if(speed < 0x2C) + increment <<= (0x2F - speed) >> 2; + + if(speed >= 0x30) + divinco >>= (speed - 0x2C) >> 2; + + if(log_mode) + { + if(dec_mode) // Log decrement mode + increment = (Current * increment) >> 15; + else // Log increment mode + { + if((Current & 0x7FFF) >= 0x6000) + { + if(speed < 0x28) + increment >>= 2; + else if(speed >= 0x2C) + divinco >>= 2; + else // 0x28 ... 0x2B + { + increment >>= 1; + divinco >>= 1; + } + } + } + } // end if(log_mode) + + if(divinco == 0 && speed < zs) //0x7F) + divinco = 1; +} + + +INLINE void SPU_Sweep::Power(void) +{ + Control = 0; + Current = 0; + Divider = 0; +} + +INLINE void SPU_Sweep::WriteControl(uint16 value) +{ + Control = value; +} + +INLINE int16 SPU_Sweep::ReadVolume(void) +{ + return((int16)Current); +} + +void SPU_Sweep::Clock(void) +{ + if(!(Control & 0x8000)) + { + Current = (Control & 0x7FFF) << 1; + return; + } + + if(Control & 0x8000) // Sweep enabled + { + const bool log_mode = (bool)(Control & 0x4000); + const bool dec_mode = (bool)(Control & 0x2000); + const bool inv_mode = (bool)(Control & 0x1000); + const bool inv_increment = (dec_mode ^ inv_mode) | (dec_mode & log_mode); + const uint16 vc_cv_xor = (inv_mode & !(dec_mode & log_mode)) ? 0xFFFF : 0x0000; + const uint16 TestInvert = inv_mode ? 0xFFFF : 0x0000; + int increment; + int divinco; + + CalcVCDelta(0x7F, Control & 0x7F, log_mode, dec_mode, inv_increment, (int16)(Current ^ vc_cv_xor), increment, divinco); + //printf("%d %d\n", divinco, increment); + + if((dec_mode & !(inv_mode & log_mode)) && ((Current & 0x8000) == (inv_mode ? 0x0000 : 0x8000) || (Current == 0))) + { + // + // Not sure if this condition should stop the Divider adding or force the increment value to 0. + // + Current = 0; + } + else + { + Divider += divinco; + + if(Divider & 0x8000) + { + Divider = 0; + + if(dec_mode || ((Current ^ TestInvert) != 0x7FFF)) + { + uint16 PrevCurrent = Current; + Current = Current + increment; + + //printf("%04x %04x\n", PrevCurrent, Current); + + if(!dec_mode && ((Current ^ PrevCurrent) & 0x8000) && ((Current ^ TestInvert) & 0x8000)) + Current = 0x7FFF ^ TestInvert; + } + } + } + } +} + +INLINE void SPU_Sweep::WriteVolume(int16 value) +{ + Current = value; +} + + +// +// Take care not to trigger SPU IRQ for the next block before its decoding start. +// +void PS_SPU::RunDecoder(SPU_Voice *voice) +{ + // 5 through 0xF appear to be 0 on the real thing. + static const int32 Weights[16][2] = + { + // s-1 s-2 + { 0, 0 }, + { 60, 0 }, + { 115, -52 }, + { 98, -55 }, + { 122, -60 }, + }; + + if(voice->DecodeAvail >= 11) + { + if(SPUControl & 0x40) + { + unsigned test_addr = (voice->CurAddr - 1) & 0x3FFFF; + if(IRQAddr == test_addr || IRQAddr == (test_addr & 0x3FFF8)) + { + //SPUIRQ_DBG("SPU IRQ (VDA): 0x%06x", addr); + IRQAsserted = true; + IRQ_Assert(IRQ_SPU, IRQAsserted); + } + } + return; + } + + if((voice->CurAddr & 0x7) == 0) + { + // Handle delayed flags from the previously-decoded block. + if(voice->DecodeFlags & 0x1) + { + voice->CurAddr = voice->LoopAddr & ~0x7; + + BlockEnd |= 1 << (voice - Voices); + + if(!(voice->DecodeFlags & 0x2)) // Force enveloping to 0 if not "looping". TODO: Should we reset the ADSR divider counter too? + { + if(!(Noise_Mode & (1 << (voice - Voices)))) + { + voice->ADSR.Phase = ADSR_RELEASE; + voice->ADSR.EnvLevel = 0; + } + } + } + } + + //for(int z = 0; z < 4; z++) + { + const uint16 CV = SPURAM[voice->CurAddr]; + + if(SPUControl & 0x40) + { + unsigned test_addr = voice->CurAddr & 0x3FFFF; + if(IRQAddr == test_addr || IRQAddr == (test_addr & 0x3FFF8)) + { + //SPUIRQ_DBG("SPU IRQ: 0x%06x", addr); + IRQAsserted = true; + IRQ_Assert(IRQ_SPU, IRQAsserted); + } + } + + if((voice->CurAddr & 0x7) == 0) + { + voice->DecodeShift = CV & 0xF; + voice->DecodeWeight = (CV >> 4) & 0xF; + voice->DecodeFlags = (CV >> 8) & 0xFF; + + if(voice->DecodeFlags & 0x4) + { + if(!voice->IgnoreSampLA) + { + voice->LoopAddr = voice->CurAddr; + } + else + { + if(voice->LoopAddr != voice->CurAddr) + { + PSX_DBG(PSX_DBG_FLOOD, "[SPU] Ignore: LoopAddr=0x%08x, SampLA=0x%08x\n", voice->LoopAddr, voice->CurAddr); + } + } + } + } + else + { + const unsigned shift = voice->DecodeShift; + const int32 weight_m1 = Weights[voice->DecodeWeight][0]; + const int32 weight_m2 = Weights[voice->DecodeWeight][1]; + uint32 coded = (uint32)CV << 12; + int16 *tb = &voice->DecodeBuffer[voice->DecodeWritePos]; + + for(int i = 0; i < 4; i++) + { + int32 sample = (int16)(coded & 0xF000) >> shift; + + sample += ((voice->DecodeM2 * weight_m2) >> 6); + sample += ((voice->DecodeM1 * weight_m1) >> 6); + + clamp(&sample, -32768, 32767); + + tb[i] = sample; + voice->DecodeM2 = voice->DecodeM1; + voice->DecodeM1 = sample; + coded >>= 4; + } + voice->DecodeWritePos = (voice->DecodeWritePos + 4) & 0x1F; + voice->DecodeAvail += 4; + } + voice->CurAddr = (voice->CurAddr + 1) & 0x3FFFF; + } +} + +void PS_SPU::CacheEnvelope(SPU_Voice *voice) +{ + uint32 raw = voice->ADSRControl; + SPU_ADSR *ADSR = &voice->ADSR; + int32 Sl, Dr, Ar, Rr, Sr; + + Sl = (raw >> 0) & 0x0F; + Dr = (raw >> 4) & 0x0F; + Ar = (raw >> 8) & 0x7F; + + Rr = (raw >> 16) & 0x1F; + Sr = (raw >> 22) & 0x7F; + + + ADSR->AttackExp = (bool)(raw & (1 << 15)); + ADSR->ReleaseExp = (bool)(raw & (1 << 21)); + ADSR->SustainExp = (bool)(raw & (1 << 31)); + ADSR->SustainDec = (bool)(raw & (1 << 30)); + + ADSR->AttackRate = Ar; + ADSR->DecayRate = Dr << 2; + ADSR->SustainRate = Sr; + ADSR->ReleaseRate = Rr << 2; + + ADSR->SustainLevel = (Sl + 1) << 11; +} + +void PS_SPU::ResetEnvelope(SPU_Voice *voice) +{ + SPU_ADSR *ADSR = &voice->ADSR; + + ADSR->EnvLevel = 0; + ADSR->Divider = 0; + ADSR->Phase = ADSR_ATTACK; +} + +void PS_SPU::ReleaseEnvelope(SPU_Voice *voice) +{ + SPU_ADSR *ADSR = &voice->ADSR; + + ADSR->Divider = 0; + ADSR->Phase = ADSR_RELEASE; +} + + +void PS_SPU::RunEnvelope(SPU_Voice *voice) +{ + SPU_ADSR *ADSR = &voice->ADSR; + int increment; + int divinco; + int16 uoflow_reset; + + if(ADSR->Phase == ADSR_ATTACK && ADSR->EnvLevel == 0x7FFF) + ADSR->Phase++; + + //static INLINE void CalcVCDelta(const uint8 zs, uint8 speed, bool log_mode, bool decrement, bool inv_increment, int16 Current, int &increment, int &divinco) + switch(ADSR->Phase) + { + default: assert(0); + break; + + case ADSR_ATTACK: + CalcVCDelta(0x7F, ADSR->AttackRate, ADSR->AttackExp, false, false, (int16)ADSR->EnvLevel, increment, divinco); + uoflow_reset = 0x7FFF; + break; + + case ADSR_DECAY: + CalcVCDelta(0x1F << 2, ADSR->DecayRate, true, true, true, (int16)ADSR->EnvLevel, increment, divinco); + uoflow_reset = 0; + break; + + case ADSR_SUSTAIN: + CalcVCDelta(0x7F, ADSR->SustainRate, ADSR->SustainExp, ADSR->SustainDec, ADSR->SustainDec, (int16)ADSR->EnvLevel, increment, divinco); + uoflow_reset = ADSR->SustainDec ? 0 : 0x7FFF; + break; + + case ADSR_RELEASE: + CalcVCDelta(0x1F << 2, ADSR->ReleaseRate, ADSR->ReleaseExp, true, true, (int16)ADSR->EnvLevel, increment, divinco); + uoflow_reset = 0; + break; + } + + ADSR->Divider += divinco; + if(ADSR->Divider & 0x8000) + { + const uint16 prev_level = ADSR->EnvLevel; + + ADSR->Divider = 0; + ADSR->EnvLevel += increment; + + if(ADSR->Phase == ADSR_ATTACK) + { + // If previous the upper bit was 0, but now it's 1, handle overflow. + if(((prev_level ^ ADSR->EnvLevel) & ADSR->EnvLevel) & 0x8000) + ADSR->EnvLevel = uoflow_reset; + } + else + { + if(ADSR->EnvLevel & 0x8000) + ADSR->EnvLevel = uoflow_reset; + } + if(ADSR->Phase == ADSR_DECAY && (uint16)ADSR->EnvLevel < ADSR->SustainLevel) + ADSR->Phase++; + } +} + +INLINE void PS_SPU::CheckIRQAddr(uint32 addr) +{ + if(SPUControl & 0x40) + { + if(IRQAddr == addr) + { + //SPUIRQ_DBG("SPU IRQ (ALT): 0x%06x", addr); + IRQAsserted = true; + IRQ_Assert(IRQ_SPU, IRQAsserted); + } + } +} + +INLINE void PS_SPU::WriteSPURAM(uint32 addr, uint16 value) +{ + CheckIRQAddr(addr); + + SPURAM[addr] = value; +} + +INLINE uint16 PS_SPU::ReadSPURAM(uint32 addr) +{ + CheckIRQAddr(addr); + return(SPURAM[addr]); +} + +#include "spu_reverb.inc" + +int32 PS_SPU::UpdateFromCDC(int32 clocks) +//pscpu_timestamp_t PS_SPU::Update(const pscpu_timestamp_t timestamp) +{ + //int32 clocks = timestamp - lastts; + int32 sample_clocks = 0; + //lastts = timestamp; + + clock_divider -= clocks; + + while(clock_divider <= 0) + { + clock_divider += 768; + sample_clocks++; + } + + while(sample_clocks > 0) + { + // Accumulated normal sound output. + int32 accum_l = 0; + int32 accum_r = 0; + + // Accumulated sound output for reverb input + int32 accum_fv_l = 0; + int32 accum_fv_r = 0; + + // Output of reverb processing. + int32 reverb_l = 0; + int32 reverb_r = 0; + + // Final output. + int32 output_l = 0; + int32 output_r = 0; + + const uint32 PhaseModCache = FM_Mode & ~ 1; +/* +** +** 0x1F801DAE Notes and Conjecture: +** ------------------------------------------------------------------------------------- +** | 15 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 4 3 2 1 0 | +** | ? | *13| ? | ba | *10 | wrr|rdr| df | is | c | +** ------------------------------------------------------------------------------------- +** +** c - Appears to be delayed copy of lower 6 bits from 0x1F801DAA. +** +** is - Interrupt asserted out status. (apparently not instantaneous status though...) +** +** df - Related to (c & 0x30) == 0x20 or (c & 0x30) == 0x30, at least. +** 0 = DMA busy(FIFO not empty when in DMA write mode?)? +** 1 = DMA ready? Something to do with the FIFO? +** +** rdr - Read(DMA read?) Ready? +** +** wrr - Write(DMA write?) Ready? +** +** *10 - Unknown. Some sort of (FIFO?) busy status?(BIOS tests for this bit in places) +** +** ba - Alternates between 0 and 1, even when SPUControl bit15 is 0; might be related to CD audio and voice 1 and 3 writing to SPU RAM. +** +** *13 - Unknown, was set to 1 when testing with an SPU delay system reg value of 0x200921E1(test result might not be reliable, re-run). +*/ + SPUStatus = SPUControl & 0x3F; + SPUStatus |= IRQAsserted ? 0x40 : 0x00; + + if(Regs[0xD6] == 0x4) // TODO: Investigate more(case 0x2C in global regs r/w handler) + SPUStatus |= (CWA & 0x100) ? 0x800 : 0x000; + + for(int voice_num = 0; voice_num < 24; voice_num++) + { + SPU_Voice *voice = &Voices[voice_num]; + int32 voice_pvs; + + voice->PreLRSample = 0; + + //PSX_WARNING("[SPU] Voice %d CurPhase=%08x, pitch=%04x, CurAddr=%08x", voice_num, voice->CurPhase, voice->Pitch, voice->CurAddr); + + // + // Decode new samples if necessary. + // + RunDecoder(voice); + + + // + // + // + int l, r; + + if(Noise_Mode & (1 << voice_num)) + voice_pvs = (int16)LFSR; + else + { + const int si = voice->DecodeReadPos; + const int pi = ((voice->CurPhase & 0xFFF) >> 4); + + voice_pvs = ((voice->DecodeBuffer[(si + 0) & 0x1F] * FIR_Table[pi][0]) + + (voice->DecodeBuffer[(si + 1) & 0x1F] * FIR_Table[pi][1]) + + (voice->DecodeBuffer[(si + 2) & 0x1F] * FIR_Table[pi][2]) + + (voice->DecodeBuffer[(si + 3) & 0x1F] * FIR_Table[pi][3])) >> 15; + } + + voice_pvs = (voice_pvs * (int16)voice->ADSR.EnvLevel) >> 15; + voice->PreLRSample = voice_pvs; + + if(voice_num == 1 || voice_num == 3) + { + int index = voice_num >> 1; + + WriteSPURAM(0x400 | (index * 0x200) | CWA, voice_pvs); + } + + + l = (voice_pvs * voice->Sweep[0].ReadVolume()) >> 15; + r = (voice_pvs * voice->Sweep[1].ReadVolume()) >> 15; + + accum_l += l; + accum_r += r; + + if(Reverb_Mode & (1 << voice_num)) + { + accum_fv_l += l; + accum_fv_r += r; + } + + // Run sweep + for(int lr = 0; lr < 2; lr++) + voice->Sweep[lr].Clock(); + + // Increment stuff + if(!voice->DecodePlayDelay) + { + unsigned phase_inc; + + // Run enveloping + RunEnvelope(voice); + + if(PhaseModCache & (1 << voice_num)) + { + // This old formula: phase_inc = (voice->Pitch * ((voice - 1)->PreLRSample + 0x8000)) >> 15; + // is incorrect, as it does not handle carrier pitches >= 0x8000 properly. + phase_inc = voice->Pitch + (((int16)voice->Pitch * ((voice - 1)->PreLRSample)) >> 15); + } + else + phase_inc = voice->Pitch; + + if(phase_inc > 0x3FFF) + phase_inc = 0x3FFF; + + { + const uint32 tmp_phase = voice->CurPhase + phase_inc; + const unsigned used = tmp_phase >> 12; + + voice->CurPhase = tmp_phase & 0xFFF; + voice->DecodeAvail -= used; + voice->DecodeReadPos = (voice->DecodeReadPos + used) & 0x1F; + } + } + else + voice->DecodePlayDelay--; + + if(VoiceOff & (1U << voice_num)) + { + if(voice->ADSR.Phase != ADSR_RELEASE) + { + ReleaseEnvelope(voice); + } + } + + if(VoiceOn & (1U << voice_num)) + { + //printf("Voice On: %u\n", voice_num); + + ResetEnvelope(voice); + + voice->DecodeFlags = 0; + voice->DecodeWritePos = 0; + voice->DecodeReadPos = 0; + voice->DecodeAvail = 0; + voice->DecodePlayDelay = 4; + + BlockEnd &= ~(1 << voice_num); + + // + // Weight/filter previous value initialization: + // + voice->DecodeM2 = 0; + voice->DecodeM1 = 0; + + voice->CurPhase = 0; + voice->CurAddr = voice->StartAddr & ~0x7; + voice->IgnoreSampLA = false; + } + + if(!(SPUControl & 0x8000)) + { + voice->ADSR.Phase = ADSR_RELEASE; + voice->ADSR.EnvLevel = 0; + } + } + + VoiceOff = 0; + VoiceOn = 0; + + // "Mute" control doesn't seem to affect CD audio(though CD audio reverb wasn't tested...) + // TODO: If we add sub-sample timing accuracy, see if it's checked for every channel at different times, or just once. + if(!(SPUControl & 0x4000)) + { + accum_l = 0; + accum_r = 0; + accum_fv_l = 0; + accum_fv_r = 0; + } + + // Get CD-DA + { + int32 cda_raw[2]; + int32 cdav[2]; + + CDC->GetCDAudio(cda_raw); // PS_CDC::GetCDAudio() guarantees the variables passed by reference will be set to 0, + // and that their range shall be -32768 through 32767. + + WriteSPURAM(CWA | 0x000, cda_raw[0]); + WriteSPURAM(CWA | 0x200, cda_raw[1]); + + for(unsigned i = 0; i < 2; i++) + cdav[i] = (cda_raw[i] * CDVol[i]) >> 15; + + if(SPUControl & 0x0001) + { + accum_l += cdav[0]; + accum_r += cdav[1]; + + if(SPUControl & 0x0004) // TODO: Test this bit(and see if it is really dependent on bit0) + { + accum_fv_l += cdav[0]; + accum_fv_r += cdav[1]; + } + } + } + + CWA = (CWA + 1) & 0x1FF; + + NoiseCounter += NoiseFreqTable[(SPUControl >> 8) & 0x3F]; + if(NoiseCounter >= 0x8000) + { + NoiseCounter -= 0x8000; + LFSR = (LFSR << 1) | (((LFSR >> 15) ^ (LFSR >> 12) ^ (LFSR >> 11) ^ (LFSR >> 10) ^ 1) & 1); + } + + clamp(&accum_l, -32768, 32767); + clamp(&accum_r, -32768, 32767); + clamp(&accum_fv_l, -32768, 32767); + clamp(&accum_fv_r, -32768, 32767); + +#if 0 + accum_l = 0; + accum_r = 0; + //accum_fv_l = (short)(rand()); + //accum_fv_r = (short)(rand()); +#endif + + RunReverb(accum_fv_l, accum_fv_r, reverb_l, reverb_r); + + //MDFN_DispMessage("%d %d\n", MainVol[0], MainVol[1], ReverbVol[0], ReverbVol[1]); + + // FIXME: Dry volume versus everything else + output_l = (((accum_l * GlobalSweep[0].ReadVolume()) >> 16) + ((reverb_l * ReverbVol[0]) >> 15)); + output_r = (((accum_r * GlobalSweep[1].ReadVolume()) >> 16) + ((reverb_r * ReverbVol[1]) >> 15)); + + //output_l = reverb_l; + //output_r = reverb_r; + + clamp(&output_l, -32768, 32767); + clamp(&output_r, -32768, 32767); + + if(IntermediateBufferPos < 4096) // Overflow might occur in some debugger use cases. + { + IntermediateBuffer[IntermediateBufferPos][0] = output_l; + IntermediateBuffer[IntermediateBufferPos][1] = output_r; + IntermediateBufferPos++; + } + + sample_clocks--; + + // Clock global sweep + for(int lr = 0; lr < 2; lr++) + GlobalSweep[lr].Clock(); + } + + //assert(clock_divider < 768); + + return clock_divider; +} + +void PS_SPU::WriteDMA(uint32 V) +{ + //SPUIRQ_DBG("DMA Write, RWAddr after=0x%06x", RWAddr); + WriteSPURAM(RWAddr, V); + RWAddr = (RWAddr + 1) & 0x3FFFF; + + WriteSPURAM(RWAddr, V >> 16); + RWAddr = (RWAddr + 1) & 0x3FFFF; + + + CheckIRQAddr(RWAddr); +} + +uint32 PS_SPU::ReadDMA(void) +{ + uint32 ret; + + ret = (uint16)ReadSPURAM(RWAddr); + RWAddr = (RWAddr + 1) & 0x3FFFF; + + ret |= (uint32)(uint16)ReadSPURAM(RWAddr) << 16; + RWAddr = (RWAddr + 1) & 0x3FFFF; + + CheckIRQAddr(RWAddr); + + //SPUIRQ_DBG("DMA Read, RWAddr after=0x%06x", RWAddr); + + return(ret); +} + +void PS_SPU::Write(pscpu_timestamp_t timestamp, uint32 A, uint16 V) +{ + //if((A & 0x3FF) < 0x180) + // PSX_WARNING("[SPU] Write: %08x %04x", A, V); + + A &= 0x3FF; + + if(A >= 0x200) + { + //printf("Write: %08x %04x\n", A, V); + if(A < 0x260) + { + SPU_Voice *voice = &Voices[(A - 0x200) >> 2]; + voice->Sweep[(A & 2) >> 1].WriteVolume(V); + } + else if(A < 0x280) + AuxRegs[(A & 0x1F) >> 1] = V; + + return; + } + + if(A < 0x180) + { + SPU_Voice *voice = &Voices[A >> 4]; + + switch(A & 0xF) + { + case 0x00: + case 0x02: + voice->Sweep[(A & 2) >> 1].WriteControl(V); + break; + + case 0x04: voice->Pitch = V; + break; + + case 0x06: voice->StartAddr = (V << 2) & 0x3FFFF; + break; + + case 0x08: voice->ADSRControl &= 0xFFFF0000; + voice->ADSRControl |= V; + CacheEnvelope(voice); + break; + + case 0x0A: voice->ADSRControl &= 0x0000FFFF; + voice->ADSRControl |= V << 16; + CacheEnvelope(voice); + break; + + case 0x0C: voice->ADSR.EnvLevel = V; + break; + + case 0x0E: voice->LoopAddr = (V << 2) & 0x3FFFF; + voice->IgnoreSampLA = true; + //if((voice - Voices) == 22) + //{ + // SPUIRQ_DBG("Manual loop address setting for voice %d: %04x", (int)(voice - Voices), V); + //} + break; + } + } + else + { + switch(A & 0x7F) + { + case 0x00: + case 0x02: GlobalSweep[(A & 2) >> 1].WriteControl(V); + break; + + case 0x04: ReverbVol[0] = (int16)V; + break; + + case 0x06: ReverbVol[1] = (int16)V; + break; + + // Voice ON: + case 0x08: VoiceOn &= 0xFFFF0000; + VoiceOn |= V << 0; + break; + + case 0x0a: VoiceOn &= 0x0000FFFF; + VoiceOn |= (V & 0xFF) << 16; + break; + + // Voice OFF: + case 0x0c: VoiceOff &= 0xFFFF0000; + VoiceOff |= V << 0; + break; + + case 0x0e: VoiceOff &= 0x0000FFFF; + VoiceOff |= (V & 0xFF) << 16; + break; + + case 0x10: FM_Mode &= 0xFFFF0000; + FM_Mode |= V << 0; + break; + + case 0x12: FM_Mode &= 0x0000FFFF; + FM_Mode |= (V & 0xFF) << 16; + break; + + case 0x14: Noise_Mode &= 0xFFFF0000; + Noise_Mode |= V << 0; + break; + + case 0x16: Noise_Mode &= 0x0000FFFF; + Noise_Mode |= (V & 0xFF) << 16; + break; + + case 0x18: Reverb_Mode &= 0xFFFF0000; + Reverb_Mode |= V << 0; + break; + + case 0x1A: Reverb_Mode &= 0x0000FFFF; + Reverb_Mode |= (V & 0xFF) << 16; + break; + + case 0x1C: BlockEnd &= 0xFFFF0000; + BlockEnd |= V << 0; + break; + + case 0x1E: BlockEnd &= 0x0000FFFF; + BlockEnd |= V << 16; + break; + + case 0x22: ReverbWA = (V << 2) & 0x3FFFF; + ReverbCur = ReverbWA; + //PSX_WARNING("[SPU] Reverb WA set: 0x%04x", V); + break; + + case 0x24: IRQAddr = (V << 2) & 0x3FFFF; + CheckIRQAddr(RWAddr); + //SPUIRQ_DBG("Set IRQAddr=0x%06x", IRQAddr); + break; + + case 0x26: RWAddr = (V << 2) & 0x3FFFF; + CheckIRQAddr(RWAddr); + //SPUIRQ_DBG("Set RWAddr=0x%06x", RWAddr); + break; + + case 0x28: WriteSPURAM(RWAddr, V); + RWAddr = (RWAddr + 1) & 0x3FFFF; + CheckIRQAddr(RWAddr); + break; + + case 0x2A: //if((SPUControl & 0x80) && !(V & 0x80)) + // printf("\n\n\n\n ************** REVERB PROCESSING DISABLED\n\n\n\n"); + + SPUControl = V; + //SPUIRQ_DBG("Set SPUControl=0x%04x -- IRQA=%06x, RWA=%06x", V, IRQAddr, RWAddr); + //printf("SPU control write: %04x\n", V); + if(!(V & 0x40)) + { + IRQAsserted = false; + IRQ_Assert(IRQ_SPU, IRQAsserted); + } + CheckIRQAddr(RWAddr); + break; + + case 0x2C: PSX_WARNING("[SPU] Global reg 0x2c set: 0x%04x", V); + break; + + case 0x30: CDVol[0] = V; + break; + + case 0x32: CDVol[1] = V; + break; + + case 0x34: ExternVol[0] = V; + break; + + case 0x36: ExternVol[1] = V; + break; + + case 0x38: + case 0x3A: GlobalSweep[(A & 2) >> 1].WriteVolume(V); + break; + } + } + + Regs[(A & 0x1FF) >> 1] = V; +} + +uint16 PS_SPU::Read(pscpu_timestamp_t timestamp, uint32 A) +{ + A &= 0x3FF; + + PSX_DBGINFO("[SPU] Read: %08x", A); + + if(A >= 0x200) + { + if(A < 0x260) + { + SPU_Voice *voice = &Voices[(A - 0x200) >> 2]; + + //printf("Read: %08x %04x\n", A, voice->Sweep[(A & 2) >> 1].ReadVolume()); + + return voice->Sweep[(A & 2) >> 1].ReadVolume(); + } + else if(A < 0x280) + return(AuxRegs[(A & 0x1F) >> 1]); + + return(0xFFFF); + } + + + if(A < 0x180) + { + SPU_Voice *voice = &Voices[A >> 4]; + + switch(A & 0xF) + { + case 0x0C: return(voice->ADSR.EnvLevel); + case 0x0E: return(voice->LoopAddr >> 2); + } + } + else + { + switch(A & 0x7F) + { + case 0x1C: return(BlockEnd); + case 0x1E: return(BlockEnd >> 16); + + case 0x26: //PSX_WARNING("[SPU] RWADDR Read"); + break; + + case 0x28: PSX_WARNING("[SPU] SPURAM Read port(?) Read"); + + { + uint16 ret = ReadSPURAM(RWAddr); + + RWAddr = (RWAddr + 1) & 0x3FFFF; + CheckIRQAddr(RWAddr); + + return(ret); + } + + case 0x2a: + return(SPUControl); + +/* FIXME: What is this used for? */ + case 0x3C: + //PSX_WARNING("[SPU] Read Unknown: %08x", A); + return(0); + + case 0x38: + case 0x3A: return(GlobalSweep[(A & 2) >> 1].ReadVolume()); + } + } + + return(Regs[(A & 0x1FF) >> 1]); +} + + +void PS_SPU::StartFrame(double rate, uint32 quality) +{ + if((int)rate != last_rate || quality != last_quality) + { + int err = 0; + + last_rate = (int)rate; + last_quality = quality; + } + +} + +int32 PS_SPU::EndFrame(int16 *SoundBuf) +{ + //lastts = 0; + + if(last_rate == 44100) + { + int32 ret = IntermediateBufferPos; + + memcpy(SoundBuf, IntermediateBuffer, IntermediateBufferPos * 2 * sizeof(int16)); + IntermediateBufferPos = 0; + + return(ret); + } + else + { + IntermediateBufferPos = 0; + return 0; + } +} + +int PS_SPU::StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { +#define SFSWEEP(r) SFVAR((r).Control), \ + SFVAR((r).Current), \ + SFVAR((r).Divider) + +#define SFVOICE(n) SFARRAY16(&Voices[n].DecodeBuffer[0], sizeof(Voices[n].DecodeBuffer) / sizeof(Voices[n].DecodeBuffer[0])), \ + SFVAR(Voices[n].DecodeM2), \ + SFVAR(Voices[n].DecodeM1), \ + SFVAR(Voices[n].DecodePlayDelay), \ + SFVAR(Voices[n].DecodeWritePos), \ + SFVAR(Voices[n].DecodeReadPos), \ + SFVAR(Voices[n].DecodeAvail), \ + SFVAR(Voices[n].DecodeShift), \ + SFVAR(Voices[n].DecodeWeight), \ + SFVAR(Voices[n].DecodeFlags), \ + SFVAR(Voices[n].IgnoreSampLA), \ + \ + SFSWEEP(Voices[n].Sweep[0]), \ + SFSWEEP(Voices[n].Sweep[1]), \ + \ + SFVAR(Voices[n].Pitch), \ + SFVAR(Voices[n].CurPhase), \ + \ + SFVAR(Voices[n].StartAddr), \ + SFVAR(Voices[n].CurAddr), \ + SFVAR(Voices[n].ADSRControl), \ + SFVAR(Voices[n].LoopAddr), \ + SFVAR(Voices[n].PreLRSample), \ + \ + SFVAR(Voices[n].ADSR.EnvLevel), \ + SFVAR(Voices[n].ADSR.Divider), \ + SFVAR(Voices[n].ADSR.Phase), \ + \ + SFVAR(Voices[n].ADSR.AttackExp), \ + SFVAR(Voices[n].ADSR.SustainExp), \ + SFVAR(Voices[n].ADSR.SustainDec), \ + SFVAR(Voices[n].ADSR.ReleaseExp), \ + \ + SFVAR(Voices[n].ADSR.AttackRate), \ + SFVAR(Voices[n].ADSR.DecayRate), \ + SFVAR(Voices[n].ADSR.SustainRate), \ + SFVAR(Voices[n].ADSR.ReleaseRate), \ + \ + SFVAR(Voices[n].ADSR.SustainLevel) + + SFVOICE(0), + SFVOICE(1), + SFVOICE(2), + SFVOICE(3), + SFVOICE(4), + SFVOICE(5), + SFVOICE(6), + SFVOICE(7), + SFVOICE(8), + SFVOICE(9), + SFVOICE(10), + SFVOICE(11), + SFVOICE(12), + SFVOICE(13), + SFVOICE(14), + SFVOICE(15), + SFVOICE(16), + SFVOICE(17), + SFVOICE(18), + SFVOICE(19), + SFVOICE(20), + SFVOICE(21), + SFVOICE(22), + SFVOICE(23), +#undef SFVOICE + + SFVAR(NoiseCounter), + SFVAR(LFSR), + + SFVAR(FM_Mode), + SFVAR(Noise_Mode), + SFVAR(Reverb_Mode), + + SFVAR(ReverbWA), + + SFSWEEP(GlobalSweep[0]), + SFSWEEP(GlobalSweep[1]), + + SFARRAY32(ReverbVol, sizeof(ReverbVol) / sizeof(ReverbVol[0])), + + SFARRAY32(CDVol, sizeof(CDVol) / sizeof(CDVol[0])), + SFARRAY32(ExternVol, sizeof(ExternVol) / sizeof(ExternVol[0])), + + SFVAR(IRQAddr), + + SFVAR(RWAddr), + + SFVAR(SPUControl), + + SFVAR(VoiceOn), + SFVAR(VoiceOff), + + SFVAR(BlockEnd), + + SFVAR(CWA), + + SFARRAY16(Regs, sizeof(Regs) / sizeof(Regs[0])), + SFARRAY16(AuxRegs, sizeof(AuxRegs) / sizeof(AuxRegs[0])), + + SFARRAY16(&RDSB[0][0], sizeof(RDSB) / sizeof(RDSB[0][0])), + SFVAR(RDSB_WP), + + SFARRAY16(&RUSB[0][0], sizeof(RUSB) / sizeof(RUSB[0][0])), + SFVAR(RUSB_WP), + + SFVAR(ReverbCur), + SFVAR(IRQAsserted), + + SFVAR(clock_divider), + + SFARRAY16(SPURAM, 524288 / sizeof(uint16)), + SFEND + }; +#undef SFSWEEP + int ret = 1; + + ret &= MDFNSS_StateAction(sm, load, data_only, StateRegs, "SPU"); + + if(load) + { + for(unsigned i = 0; i < 24; i++) + { + Voices[i].DecodeReadPos &= 0x1F; + Voices[i].DecodeWritePos &= 0x1F; + } + + RDSB_WP &= 0x3F; + RUSB_WP &= 0x3F; + + IRQ_Assert(IRQ_SPU, IRQAsserted); + } + + return(ret); +} + +uint16 PS_SPU::PeekSPURAM(uint32 address) +{ + return(SPURAM[address & 0x3FFFF]); +} + +void PS_SPU::PokeSPURAM(uint32 address, uint16 value) +{ + SPURAM[address & 0x3FFFF] = value; +} + +uint32 PS_SPU::GetRegister(unsigned int which, char *special, const uint32 special_len) +{ + uint32 ret = 0xDEADBEEF; + + if(which >= 0x8000) + { + unsigned int v = (which - 0x8000) >> 8; + + switch((which & 0xFF) | 0x8000) + { + case GSREG_V0_VOL_CTRL_L: + ret = Regs[v * 8 + 0x0]; + break; + + case GSREG_V0_VOL_CTRL_R: + ret = Regs[v * 8 + 0x1]; + break; + + case GSREG_V0_VOL_L: + ret = Voices[v].Sweep[0].ReadVolume() & 0xFFFF; + break; + + case GSREG_V0_VOL_R: + ret = Voices[v].Sweep[1].ReadVolume() & 0xFFFF; + break; + + case GSREG_V0_PITCH: + ret = Voices[v].Pitch; + break; + + case GSREG_V0_STARTADDR: + ret = Voices[v].StartAddr; + break; + + case GSREG_V0_ADSR_CTRL: + ret = Voices[v].ADSRControl; + break; + + case GSREG_V0_ADSR_LEVEL: + ret = Voices[v].ADSR.EnvLevel; + break; + + case GSREG_V0_LOOP_ADDR: + ret = Voices[v].LoopAddr; + break; + + case GSREG_V0_READ_ADDR: + ret = Voices[v].CurAddr; + break; + } + } + else switch(which) + { + case GSREG_SPUCONTROL: + ret = SPUControl; + break; + + case GSREG_FM_ON: + ret = FM_Mode; + break; + + case GSREG_NOISE_ON: + ret = Noise_Mode; + break; + + case GSREG_REVERB_ON: + ret = Reverb_Mode; + break; + + case GSREG_CDVOL_L: + ret = (uint16)CDVol[0]; + break; + + case GSREG_CDVOL_R: + ret = (uint16)CDVol[1]; + break; + + case GSREG_DRYVOL_CTRL_L: + ret = Regs[0xC0]; + break; + + case GSREG_DRYVOL_CTRL_R: + ret = Regs[0xC1]; + break; + + case GSREG_DRYVOL_L: + ret = GlobalSweep[0].ReadVolume() & 0xFFFF; + break; + + case GSREG_DRYVOL_R: + ret = GlobalSweep[1].ReadVolume() & 0xFFFF; + break; + + case GSREG_WETVOL_L: + ret = (uint16)ReverbVol[0]; + break; + + case GSREG_WETVOL_R: + ret = (uint16)ReverbVol[1]; + break; + + case GSREG_RWADDR: + ret = RWAddr; + break; + + case GSREG_IRQADDR: + ret = IRQAddr; + break; + + case GSREG_REVERBWA: + ret = ReverbWA >> 2; + break; + + case GSREG_VOICEON: + ret = VoiceOn; + break; + + case GSREG_VOICEOFF: + ret = VoiceOff; + break; + + case GSREG_BLOCKEND: + ret = BlockEnd; + break; + + + //case GSREG_FB_SRC_A ... GSREG_IN_COEF_R: + case GSREG_FB_SRC_A: + case GSREG_FB_SRC_B: + case GSREG_IIR_ALPHA: + case GSREG_ACC_COEF_A: + case GSREG_ACC_COEF_B: + case GSREG_ACC_COEF_C: + case GSREG_ACC_COEF_D: + case GSREG_IIR_COEF: + case GSREG_FB_ALPHA: + case GSREG_FB_X: + case GSREG_IIR_DEST_A0: + case GSREG_IIR_DEST_A1: + case GSREG_ACC_SRC_A0: + case GSREG_ACC_SRC_A1: + case GSREG_ACC_SRC_B0: + case GSREG_ACC_SRC_B1: + case GSREG_IIR_SRC_A0: + case GSREG_IIR_SRC_A1: + case GSREG_IIR_DEST_B0: + case GSREG_IIR_DEST_B1: + case GSREG_ACC_SRC_C0: + case GSREG_ACC_SRC_C1: + case GSREG_ACC_SRC_D0: + case GSREG_ACC_SRC_D1: + case GSREG_IIR_SRC_B1: + case GSREG_IIR_SRC_B0: + case GSREG_MIX_DEST_A0: + case GSREG_MIX_DEST_A1: + case GSREG_MIX_DEST_B0: + case GSREG_MIX_DEST_B1: + case GSREG_IN_COEF_L: + case GSREG_IN_COEF_R: + ret = ReverbRegs[which - GSREG_FB_SRC_A] & 0xFFFF; + break; + } + + return(ret); +} + +void PS_SPU::SetRegister(unsigned int which, uint32 value) +{ + + switch(which) + { + case GSREG_SPUCONTROL: + SPUControl = value; + break; + + case GSREG_FM_ON: + FM_Mode = value & 0xFFFFFF; + break; + + case GSREG_NOISE_ON: + Noise_Mode = value & 0xFFFFFF; + break; + + case GSREG_REVERB_ON: + Reverb_Mode = value & 0xFFFFFF; + break; + + case GSREG_CDVOL_L: + CDVol[0] = (int16)value; + break; + + case GSREG_CDVOL_R: + CDVol[1] = (int16)value; + break; + + case GSREG_DRYVOL_CTRL_L: + Regs[0xC0] = value; + GlobalSweep[0].WriteControl(value); + //GlobalSweep[0].Control = value; + break; + + case GSREG_DRYVOL_CTRL_R: + Regs[0xC1] = value; + GlobalSweep[1].WriteControl(value); + //GlobalSweep[1].Control = value; + break; + + case GSREG_DRYVOL_L: + GlobalSweep[0].WriteVolume(value); + break; + + case GSREG_DRYVOL_R: + GlobalSweep[1].WriteVolume(value); + break; + + case GSREG_WETVOL_L: + ReverbVol[0] = (int16)value; + break; + + case GSREG_WETVOL_R: + ReverbVol[1] = (int16)value; + break; + + case GSREG_RWADDR: + RWAddr = value & 0x3FFFF; + break; + + case GSREG_IRQADDR: + IRQAddr = value & 0x3FFFC; + break; + + // + // REVERB_WA + // + + case GSREG_VOICEON: + VoiceOn = value & 0xFFFFFF; + break; + + case GSREG_VOICEOFF: + VoiceOff = value & 0xFFFFFF; + break; + + case GSREG_BLOCKEND: + BlockEnd = value & 0xFFFFFF; + break; + + + } +} + + + +} diff --git a/psx/octoshock/psx/spu.h b/psx/octoshock/psx/spu.h new file mode 100644 index 0000000000..52b075ce9c --- /dev/null +++ b/psx/octoshock/psx/spu.h @@ -0,0 +1,342 @@ +#ifndef __MDFN_PSX_SPU_H +#define __MDFN_PSX_SPU_H + +namespace MDFN_IEN_PSX +{ + +enum +{ + ADSR_ATTACK = 0, + ADSR_DECAY = 1, + ADSR_SUSTAIN = 2, + ADSR_RELEASE = 3 +}; + +struct SPU_ADSR +{ + uint16 EnvLevel; // We typecast it to (int16) in several places, but keep it here as (uint16) to prevent signed overflow/underflow, which compilers + // may not treat consistently. + uint32 Divider; + uint32 Phase; + + bool AttackExp; + bool SustainExp; + bool SustainDec; + bool ReleaseExp; + + int32 AttackRate; // Ar + int32 DecayRate; // Dr * 4 + int32 SustainRate; // Sr + int32 ReleaseRate; // Rr * 4 + + int32 SustainLevel; // (Sl + 1) << 11 +}; + +class PS_SPU; +class SPU_Sweep +{ + friend class PS_SPU; // For save states - FIXME(remove in future?) + + public: + SPU_Sweep() { } + ~SPU_Sweep() { } + + void Power(void); + + void WriteControl(uint16 value); + int16 ReadVolume(void); + + void WriteVolume(int16 value); + + void Clock(void); + + private: + uint16 Control; + uint16 Current; // We typecast it to (int16) in several places, but keep it here as (uint16) to prevent signed overflow/underflow, which compilers + // may not treat consistently. + uint32 Divider; +}; + +struct SPU_Voice +{ + int16 DecodeBuffer[0x20]; + int16 DecodeM2; + int16 DecodeM1; + + uint32 DecodePlayDelay; + uint32 DecodeWritePos; + uint32 DecodeReadPos; + uint32 DecodeAvail; + + uint8 DecodeShift; + uint8 DecodeWeight; + uint8 DecodeFlags; + + bool IgnoreSampLA; + + SPU_Sweep Sweep[2]; + + uint16 Pitch; + uint32 CurPhase; + + uint32 StartAddr; + + uint32 CurAddr; + + uint32 ADSRControl; + + uint32 LoopAddr; + + int32 PreLRSample; // After enveloping, but before L/R volume. Range of -32768 to 32767 + + SPU_ADSR ADSR; +}; + +class PS_SPU +{ + public: + + PS_SPU(); + ~PS_SPU(); + + int StateAction(StateMem *sm, int load, int data_only); + + void Power(void); + void Write(pscpu_timestamp_t timestamp, uint32 A, uint16 V); + uint16 Read(pscpu_timestamp_t timestamp, uint32 A); + + void WriteDMA(uint32 V); + uint32 ReadDMA(void); + + void StartFrame(double rate, uint32 quality); + int32 EndFrame(int16 *SoundBuf); + + int32 UpdateFromCDC(int32 clocks); + //pscpu_timestamp_t Update(pscpu_timestamp_t timestamp); + + private: + + void CheckIRQAddr(uint32 addr); + void WriteSPURAM(uint32 addr, uint16 value); + uint16 ReadSPURAM(uint32 addr); + + void RunDecoder(SPU_Voice *voice); + + void CacheEnvelope(SPU_Voice *voice); + void ResetEnvelope(SPU_Voice *voice); + void ReleaseEnvelope(SPU_Voice *voice); + void RunEnvelope(SPU_Voice *voice); + + + void RunReverb(int32 in_l, int32 in_r, int32 &out_l, int32 &out_r); + bool GetCDAudio(int32 &l, int32 &r); + + SPU_Voice Voices[24]; + + uint32 NoiseCounter; + uint16 LFSR; + + uint32 FM_Mode; + uint32 Noise_Mode; + uint32 Reverb_Mode; + + int32 ReverbWA; + + SPU_Sweep GlobalSweep[2]; // Doesn't affect reverb volume! + + int32 ReverbVol[2]; + + int32 CDVol[2]; + int32 ExternVol[2]; + + uint32 IRQAddr; + + uint32 RWAddr; + + uint16 SPUControl; + + uint32 VoiceOn; + uint32 VoiceOff; + + uint32 BlockEnd; + + uint32 CWA; + + union + { + uint16 Regs[0x100]; + struct + { + uint16 VoiceRegs[0xC0]; + union + { + uint16 GlobalRegs[0x20]; + struct + { + uint16 _Global0[0x17]; + uint16 SPUStatus; + uint16 _Global1[0x08]; + }; + }; + union + { + int16 ReverbRegs[0x20]; + + struct + { + int16 FB_SRC_A; + int16 FB_SRC_B; + int16 IIR_ALPHA; + int16 ACC_COEF_A; + int16 ACC_COEF_B; + int16 ACC_COEF_C; + int16 ACC_COEF_D; + int16 IIR_COEF; + int16 FB_ALPHA; + int16 FB_X; + int16 IIR_DEST_A0; + int16 IIR_DEST_A1; + int16 ACC_SRC_A0; + int16 ACC_SRC_A1; + int16 ACC_SRC_B0; + int16 ACC_SRC_B1; + int16 IIR_SRC_A0; + int16 IIR_SRC_A1; + int16 IIR_DEST_B0; + int16 IIR_DEST_B1; + int16 ACC_SRC_C0; + int16 ACC_SRC_C1; + int16 ACC_SRC_D0; + int16 ACC_SRC_D1; + int16 IIR_SRC_B1; + int16 IIR_SRC_B0; + int16 MIX_DEST_A0; + int16 MIX_DEST_A1; + int16 MIX_DEST_B0; + int16 MIX_DEST_B1; + int16 IN_COEF_L; + int16 IN_COEF_R; + }; + }; + }; + }; + + uint16 AuxRegs[0x10]; + + int16 RDSB[2][128]; // [40] + int32 RDSB_WP; + + int16 RUSB[2][128]; + int32 RUSB_WP; + + int32 ReverbCur; + + int32 Get_Reverb_Offset(int32 offset); + int32 RD_RVB(int16 raw_offs); + void WR_RVB(int16 raw_offs, int32 sample, int32 extra_offs = 0); + + bool IRQAsserted; + + //pscpu_timestamp_t lastts; + int32 clock_divider; + + uint16 SPURAM[524288 / sizeof(uint16)]; + + int last_rate; + uint32 last_quality; + + // Buffers 44.1KHz samples, should have enough for two(worst-case scenario) video frames(2* ~735 frames NTSC, 2* ~882 PAL) plus jitter plus enough for the resampler leftovers. + // We'll just go with 4096 because powers of 2 are AWESOME and such. + uint32 IntermediateBufferPos; + int16 IntermediateBuffer[4096][2]; + + public: + enum + { + GSREG_SPUCONTROL = 0, + + GSREG_FM_ON, + GSREG_NOISE_ON, + GSREG_REVERB_ON, + + GSREG_CDVOL_L, + GSREG_CDVOL_R, + + GSREG_DRYVOL_CTRL_L, + GSREG_DRYVOL_CTRL_R, + + GSREG_DRYVOL_L, + GSREG_DRYVOL_R, + + GSREG_WETVOL_L, + GSREG_WETVOL_R, + + GSREG_RWADDR, + + GSREG_IRQADDR, + + GSREG_REVERBWA, + + GSREG_VOICEON, + GSREG_VOICEOFF, + GSREG_BLOCKEND, + + // Note: the order of these should match the reverb reg array + GSREG_FB_SRC_A, + GSREG_FB_SRC_B, + GSREG_IIR_ALPHA, + GSREG_ACC_COEF_A, + GSREG_ACC_COEF_B, + GSREG_ACC_COEF_C, + GSREG_ACC_COEF_D, + GSREG_IIR_COEF, + GSREG_FB_ALPHA, + GSREG_FB_X, + GSREG_IIR_DEST_A0, + GSREG_IIR_DEST_A1, + GSREG_ACC_SRC_A0, + GSREG_ACC_SRC_A1, + GSREG_ACC_SRC_B0, + GSREG_ACC_SRC_B1, + GSREG_IIR_SRC_A0, + GSREG_IIR_SRC_A1, + GSREG_IIR_DEST_B0, + GSREG_IIR_DEST_B1, + GSREG_ACC_SRC_C0, + GSREG_ACC_SRC_C1, + GSREG_ACC_SRC_D0, + GSREG_ACC_SRC_D1, + GSREG_IIR_SRC_B1, + GSREG_IIR_SRC_B0, + GSREG_MIX_DEST_A0, + GSREG_MIX_DEST_A1, + GSREG_MIX_DEST_B0, + GSREG_MIX_DEST_B1, + GSREG_IN_COEF_L, + GSREG_IN_COEF_R, + + + // Multiply v * 256 for each extra voice + GSREG_V0_VOL_CTRL_L = 0x8000, + GSREG_V0_VOL_CTRL_R, + GSREG_V0_VOL_L, + GSREG_V0_VOL_R, + GSREG_V0_PITCH, + GSREG_V0_STARTADDR, + GSREG_V0_ADSR_CTRL, + GSREG_V0_ADSR_LEVEL, + GSREG_V0_LOOP_ADDR, + GSREG_V0_READ_ADDR + }; + + uint32 GetRegister(unsigned int which, char *special, const uint32 special_len); + void SetRegister(unsigned int which, uint32 value); + + uint16 PeekSPURAM(uint32 address); + void PokeSPURAM(uint32 address, uint16 value); +}; + + +} + +#endif diff --git a/psx/octoshock/psx/spu_fir_table.inc b/psx/octoshock/psx/spu_fir_table.inc new file mode 100644 index 0000000000..dabee3cb18 --- /dev/null +++ b/psx/octoshock/psx/spu_fir_table.inc @@ -0,0 +1,256 @@ + { (int16)0x12c7, (int16)0x59b3, (int16)0x1307, (int16)0xffff }, + { (int16)0x1288, (int16)0x59b2, (int16)0x1347, (int16)0xffff }, + { (int16)0x1249, (int16)0x59b0, (int16)0x1388, (int16)0xffff }, + { (int16)0x120b, (int16)0x59ad, (int16)0x13c9, (int16)0xffff }, + { (int16)0x11cd, (int16)0x59a9, (int16)0x140b, (int16)0xffff }, + { (int16)0x118f, (int16)0x59a4, (int16)0x144d, (int16)0xffff }, + { (int16)0x1153, (int16)0x599e, (int16)0x1490, (int16)0xffff }, + { (int16)0x1116, (int16)0x5997, (int16)0x14d4, (int16)0xffff }, + { (int16)0x10db, (int16)0x598f, (int16)0x1517, (int16)0xffff }, + { (int16)0x109f, (int16)0x5986, (int16)0x155c, (int16)0xffff }, + { (int16)0x1065, (int16)0x597c, (int16)0x15a0, (int16)0xffff }, + { (int16)0x102a, (int16)0x5971, (int16)0x15e6, (int16)0xffff }, + { (int16)0x0ff1, (int16)0x5965, (int16)0x162c, (int16)0xffff }, + { (int16)0x0fb7, (int16)0x5958, (int16)0x1672, (int16)0xffff }, + { (int16)0x0f7f, (int16)0x5949, (int16)0x16b9, (int16)0xffff }, + { (int16)0x0f46, (int16)0x593a, (int16)0x1700, (int16)0xffff }, + { (int16)0x0f0f, (int16)0x592a, (int16)0x1747, (int16)0x0000 }, + { (int16)0x0ed7, (int16)0x5919, (int16)0x1790, (int16)0x0000 }, + { (int16)0x0ea1, (int16)0x5907, (int16)0x17d8, (int16)0x0000 }, + { (int16)0x0e6b, (int16)0x58f4, (int16)0x1821, (int16)0x0000 }, + { (int16)0x0e35, (int16)0x58e0, (int16)0x186b, (int16)0x0000 }, + { (int16)0x0e00, (int16)0x58cb, (int16)0x18b5, (int16)0x0000 }, + { (int16)0x0dcb, (int16)0x58b5, (int16)0x1900, (int16)0x0000 }, + { (int16)0x0d97, (int16)0x589e, (int16)0x194b, (int16)0x0001 }, + { (int16)0x0d63, (int16)0x5886, (int16)0x1996, (int16)0x0001 }, + { (int16)0x0d30, (int16)0x586d, (int16)0x19e2, (int16)0x0001 }, + { (int16)0x0cfd, (int16)0x5853, (int16)0x1a2e, (int16)0x0001 }, + { (int16)0x0ccb, (int16)0x5838, (int16)0x1a7b, (int16)0x0002 }, + { (int16)0x0c99, (int16)0x581c, (int16)0x1ac8, (int16)0x0002 }, + { (int16)0x0c68, (int16)0x57ff, (int16)0x1b16, (int16)0x0002 }, + { (int16)0x0c38, (int16)0x57e2, (int16)0x1b64, (int16)0x0003 }, + { (int16)0x0c07, (int16)0x57c3, (int16)0x1bb3, (int16)0x0003 }, + { (int16)0x0bd8, (int16)0x57a3, (int16)0x1c02, (int16)0x0003 }, + { (int16)0x0ba9, (int16)0x5782, (int16)0x1c51, (int16)0x0004 }, + { (int16)0x0b7a, (int16)0x5761, (int16)0x1ca1, (int16)0x0004 }, + { (int16)0x0b4c, (int16)0x573e, (int16)0x1cf1, (int16)0x0005 }, + { (int16)0x0b1e, (int16)0x571b, (int16)0x1d42, (int16)0x0005 }, + { (int16)0x0af1, (int16)0x56f6, (int16)0x1d93, (int16)0x0006 }, + { (int16)0x0ac4, (int16)0x56d1, (int16)0x1de5, (int16)0x0007 }, + { (int16)0x0a98, (int16)0x56ab, (int16)0x1e37, (int16)0x0007 }, + { (int16)0x0a6c, (int16)0x5684, (int16)0x1e89, (int16)0x0008 }, + { (int16)0x0a40, (int16)0x565b, (int16)0x1edc, (int16)0x0009 }, + { (int16)0x0a16, (int16)0x5632, (int16)0x1f2f, (int16)0x0009 }, + { (int16)0x09eb, (int16)0x5609, (int16)0x1f82, (int16)0x000a }, + { (int16)0x09c1, (int16)0x55de, (int16)0x1fd6, (int16)0x000b }, + { (int16)0x0998, (int16)0x55b2, (int16)0x202a, (int16)0x000c }, + { (int16)0x096f, (int16)0x5585, (int16)0x207f, (int16)0x000d }, + { (int16)0x0946, (int16)0x5558, (int16)0x20d4, (int16)0x000e }, + { (int16)0x091e, (int16)0x5529, (int16)0x2129, (int16)0x000f }, + { (int16)0x08f7, (int16)0x54fa, (int16)0x217f, (int16)0x0010 }, + { (int16)0x08d0, (int16)0x54ca, (int16)0x21d5, (int16)0x0011 }, + { (int16)0x08a9, (int16)0x5499, (int16)0x222c, (int16)0x0012 }, + { (int16)0x0883, (int16)0x5467, (int16)0x2282, (int16)0x0013 }, + { (int16)0x085d, (int16)0x5434, (int16)0x22da, (int16)0x0015 }, + { (int16)0x0838, (int16)0x5401, (int16)0x2331, (int16)0x0016 }, + { (int16)0x0813, (int16)0x53cc, (int16)0x2389, (int16)0x0018 }, + { (int16)0x07ef, (int16)0x5397, (int16)0x23e1, (int16)0x0019 }, + { (int16)0x07cb, (int16)0x5361, (int16)0x2439, (int16)0x001b }, + { (int16)0x07a7, (int16)0x532a, (int16)0x2492, (int16)0x001c }, + { (int16)0x0784, (int16)0x52f3, (int16)0x24eb, (int16)0x001e }, + { (int16)0x0762, (int16)0x52ba, (int16)0x2545, (int16)0x0020 }, + { (int16)0x0740, (int16)0x5281, (int16)0x259e, (int16)0x0021 }, + { (int16)0x071e, (int16)0x5247, (int16)0x25f8, (int16)0x0023 }, + { (int16)0x06fd, (int16)0x520c, (int16)0x2653, (int16)0x0025 }, + { (int16)0x06dc, (int16)0x51d0, (int16)0x26ad, (int16)0x0027 }, + { (int16)0x06bb, (int16)0x5194, (int16)0x2708, (int16)0x0029 }, + { (int16)0x069b, (int16)0x5156, (int16)0x2763, (int16)0x002c }, + { (int16)0x067c, (int16)0x5118, (int16)0x27be, (int16)0x002e }, + { (int16)0x065c, (int16)0x50da, (int16)0x281a, (int16)0x0030 }, + { (int16)0x063e, (int16)0x509a, (int16)0x2876, (int16)0x0033 }, + { (int16)0x061f, (int16)0x505a, (int16)0x28d2, (int16)0x0035 }, + { (int16)0x0601, (int16)0x5019, (int16)0x292e, (int16)0x0038 }, + { (int16)0x05e4, (int16)0x4fd7, (int16)0x298b, (int16)0x003a }, + { (int16)0x05c7, (int16)0x4f95, (int16)0x29e7, (int16)0x003d }, + { (int16)0x05aa, (int16)0x4f52, (int16)0x2a44, (int16)0x0040 }, + { (int16)0x058e, (int16)0x4f0e, (int16)0x2aa1, (int16)0x0043 }, + { (int16)0x0572, (int16)0x4ec9, (int16)0x2aff, (int16)0x0046 }, + { (int16)0x0556, (int16)0x4e84, (int16)0x2b5c, (int16)0x0049 }, + { (int16)0x053b, (int16)0x4e3e, (int16)0x2bba, (int16)0x004d }, + { (int16)0x0520, (int16)0x4df7, (int16)0x2c18, (int16)0x0050 }, + { (int16)0x0506, (int16)0x4db0, (int16)0x2c76, (int16)0x0054 }, + { (int16)0x04ec, (int16)0x4d68, (int16)0x2cd4, (int16)0x0057 }, + { (int16)0x04d2, (int16)0x4d20, (int16)0x2d33, (int16)0x005b }, + { (int16)0x04b9, (int16)0x4cd7, (int16)0x2d91, (int16)0x005f }, + { (int16)0x04a0, (int16)0x4c8d, (int16)0x2df0, (int16)0x0063 }, + { (int16)0x0488, (int16)0x4c42, (int16)0x2e4f, (int16)0x0067 }, + { (int16)0x0470, (int16)0x4bf7, (int16)0x2eae, (int16)0x006b }, + { (int16)0x0458, (int16)0x4bac, (int16)0x2f0d, (int16)0x006f }, + { (int16)0x0441, (int16)0x4b5f, (int16)0x2f6c, (int16)0x0074 }, + { (int16)0x042a, (int16)0x4b13, (int16)0x2fcc, (int16)0x0078 }, + { (int16)0x0413, (int16)0x4ac5, (int16)0x302b, (int16)0x007d }, + { (int16)0x03fc, (int16)0x4a77, (int16)0x308b, (int16)0x0082 }, + { (int16)0x03e7, (int16)0x4a29, (int16)0x30ea, (int16)0x0087 }, + { (int16)0x03d1, (int16)0x49d9, (int16)0x314a, (int16)0x008c }, + { (int16)0x03bc, (int16)0x498a, (int16)0x31aa, (int16)0x0091 }, + { (int16)0x03a7, (int16)0x493a, (int16)0x3209, (int16)0x0096 }, + { (int16)0x0392, (int16)0x48e9, (int16)0x3269, (int16)0x009c }, + { (int16)0x037e, (int16)0x4898, (int16)0x32c9, (int16)0x00a1 }, + { (int16)0x036a, (int16)0x4846, (int16)0x3329, (int16)0x00a7 }, + { (int16)0x0356, (int16)0x47f4, (int16)0x3389, (int16)0x00ad }, + { (int16)0x0343, (int16)0x47a1, (int16)0x33e9, (int16)0x00b3 }, + { (int16)0x0330, (int16)0x474e, (int16)0x3449, (int16)0x00ba }, + { (int16)0x031d, (int16)0x46fa, (int16)0x34a9, (int16)0x00c0 }, + { (int16)0x030b, (int16)0x46a6, (int16)0x3509, (int16)0x00c7 }, + { (int16)0x02f9, (int16)0x4651, (int16)0x3569, (int16)0x00cd }, + { (int16)0x02e7, (int16)0x45fc, (int16)0x35c9, (int16)0x00d4 }, + { (int16)0x02d6, (int16)0x45a6, (int16)0x3629, (int16)0x00db }, + { (int16)0x02c4, (int16)0x4550, (int16)0x3689, (int16)0x00e3 }, + { (int16)0x02b4, (int16)0x44fa, (int16)0x36e8, (int16)0x00ea }, + { (int16)0x02a3, (int16)0x44a3, (int16)0x3748, (int16)0x00f2 }, + { (int16)0x0293, (int16)0x444c, (int16)0x37a8, (int16)0x00fa }, + { (int16)0x0283, (int16)0x43f4, (int16)0x3807, (int16)0x0101 }, + { (int16)0x0273, (int16)0x439c, (int16)0x3867, (int16)0x010a }, + { (int16)0x0264, (int16)0x4344, (int16)0x38c6, (int16)0x0112 }, + { (int16)0x0255, (int16)0x42eb, (int16)0x3926, (int16)0x011b }, + { (int16)0x0246, (int16)0x4292, (int16)0x3985, (int16)0x0123 }, + { (int16)0x0237, (int16)0x4239, (int16)0x39e4, (int16)0x012c }, + { (int16)0x0229, (int16)0x41df, (int16)0x3a43, (int16)0x0135 }, + { (int16)0x021b, (int16)0x4185, (int16)0x3aa2, (int16)0x013f }, + { (int16)0x020d, (int16)0x412a, (int16)0x3b00, (int16)0x0148 }, + { (int16)0x0200, (int16)0x40d0, (int16)0x3b5f, (int16)0x0152 }, + { (int16)0x01f2, (int16)0x4074, (int16)0x3bbd, (int16)0x015c }, + { (int16)0x01e5, (int16)0x4019, (int16)0x3c1b, (int16)0x0166 }, + { (int16)0x01d9, (int16)0x3fbd, (int16)0x3c79, (int16)0x0171 }, + { (int16)0x01cc, (int16)0x3f62, (int16)0x3cd7, (int16)0x017b }, + { (int16)0x01c0, (int16)0x3f05, (int16)0x3d35, (int16)0x0186 }, + { (int16)0x01b4, (int16)0x3ea9, (int16)0x3d92, (int16)0x0191 }, + { (int16)0x01a8, (int16)0x3e4c, (int16)0x3def, (int16)0x019c }, + { (int16)0x019c, (int16)0x3def, (int16)0x3e4c, (int16)0x01a8 }, + { (int16)0x0191, (int16)0x3d92, (int16)0x3ea9, (int16)0x01b4 }, + { (int16)0x0186, (int16)0x3d35, (int16)0x3f05, (int16)0x01c0 }, + { (int16)0x017b, (int16)0x3cd7, (int16)0x3f62, (int16)0x01cc }, + { (int16)0x0171, (int16)0x3c79, (int16)0x3fbd, (int16)0x01d9 }, + { (int16)0x0166, (int16)0x3c1b, (int16)0x4019, (int16)0x01e5 }, + { (int16)0x015c, (int16)0x3bbd, (int16)0x4074, (int16)0x01f2 }, + { (int16)0x0152, (int16)0x3b5f, (int16)0x40d0, (int16)0x0200 }, + { (int16)0x0148, (int16)0x3b00, (int16)0x412a, (int16)0x020d }, + { (int16)0x013f, (int16)0x3aa2, (int16)0x4185, (int16)0x021b }, + { (int16)0x0135, (int16)0x3a43, (int16)0x41df, (int16)0x0229 }, + { (int16)0x012c, (int16)0x39e4, (int16)0x4239, (int16)0x0237 }, + { (int16)0x0123, (int16)0x3985, (int16)0x4292, (int16)0x0246 }, + { (int16)0x011b, (int16)0x3926, (int16)0x42eb, (int16)0x0255 }, + { (int16)0x0112, (int16)0x38c6, (int16)0x4344, (int16)0x0264 }, + { (int16)0x010a, (int16)0x3867, (int16)0x439c, (int16)0x0273 }, + { (int16)0x0101, (int16)0x3807, (int16)0x43f4, (int16)0x0283 }, + { (int16)0x00fa, (int16)0x37a8, (int16)0x444c, (int16)0x0293 }, + { (int16)0x00f2, (int16)0x3748, (int16)0x44a3, (int16)0x02a3 }, + { (int16)0x00ea, (int16)0x36e8, (int16)0x44fa, (int16)0x02b4 }, + { (int16)0x00e3, (int16)0x3689, (int16)0x4550, (int16)0x02c4 }, + { (int16)0x00db, (int16)0x3629, (int16)0x45a6, (int16)0x02d6 }, + { (int16)0x00d4, (int16)0x35c9, (int16)0x45fc, (int16)0x02e7 }, + { (int16)0x00cd, (int16)0x3569, (int16)0x4651, (int16)0x02f9 }, + { (int16)0x00c7, (int16)0x3509, (int16)0x46a6, (int16)0x030b }, + { (int16)0x00c0, (int16)0x34a9, (int16)0x46fa, (int16)0x031d }, + { (int16)0x00ba, (int16)0x3449, (int16)0x474e, (int16)0x0330 }, + { (int16)0x00b3, (int16)0x33e9, (int16)0x47a1, (int16)0x0343 }, + { (int16)0x00ad, (int16)0x3389, (int16)0x47f4, (int16)0x0356 }, + { (int16)0x00a7, (int16)0x3329, (int16)0x4846, (int16)0x036a }, + { (int16)0x00a1, (int16)0x32c9, (int16)0x4898, (int16)0x037e }, + { (int16)0x009c, (int16)0x3269, (int16)0x48e9, (int16)0x0392 }, + { (int16)0x0096, (int16)0x3209, (int16)0x493a, (int16)0x03a7 }, + { (int16)0x0091, (int16)0x31aa, (int16)0x498a, (int16)0x03bc }, + { (int16)0x008c, (int16)0x314a, (int16)0x49d9, (int16)0x03d1 }, + { (int16)0x0087, (int16)0x30ea, (int16)0x4a29, (int16)0x03e7 }, + { (int16)0x0082, (int16)0x308b, (int16)0x4a77, (int16)0x03fc }, + { (int16)0x007d, (int16)0x302b, (int16)0x4ac5, (int16)0x0413 }, + { (int16)0x0078, (int16)0x2fcc, (int16)0x4b13, (int16)0x042a }, + { (int16)0x0074, (int16)0x2f6c, (int16)0x4b5f, (int16)0x0441 }, + { (int16)0x006f, (int16)0x2f0d, (int16)0x4bac, (int16)0x0458 }, + { (int16)0x006b, (int16)0x2eae, (int16)0x4bf7, (int16)0x0470 }, + { (int16)0x0067, (int16)0x2e4f, (int16)0x4c42, (int16)0x0488 }, + { (int16)0x0063, (int16)0x2df0, (int16)0x4c8d, (int16)0x04a0 }, + { (int16)0x005f, (int16)0x2d91, (int16)0x4cd7, (int16)0x04b9 }, + { (int16)0x005b, (int16)0x2d33, (int16)0x4d20, (int16)0x04d2 }, + { (int16)0x0057, (int16)0x2cd4, (int16)0x4d68, (int16)0x04ec }, + { (int16)0x0054, (int16)0x2c76, (int16)0x4db0, (int16)0x0506 }, + { (int16)0x0050, (int16)0x2c18, (int16)0x4df7, (int16)0x0520 }, + { (int16)0x004d, (int16)0x2bba, (int16)0x4e3e, (int16)0x053b }, + { (int16)0x0049, (int16)0x2b5c, (int16)0x4e84, (int16)0x0556 }, + { (int16)0x0046, (int16)0x2aff, (int16)0x4ec9, (int16)0x0572 }, + { (int16)0x0043, (int16)0x2aa1, (int16)0x4f0e, (int16)0x058e }, + { (int16)0x0040, (int16)0x2a44, (int16)0x4f52, (int16)0x05aa }, + { (int16)0x003d, (int16)0x29e7, (int16)0x4f95, (int16)0x05c7 }, + { (int16)0x003a, (int16)0x298b, (int16)0x4fd7, (int16)0x05e4 }, + { (int16)0x0038, (int16)0x292e, (int16)0x5019, (int16)0x0601 }, + { (int16)0x0035, (int16)0x28d2, (int16)0x505a, (int16)0x061f }, + { (int16)0x0033, (int16)0x2876, (int16)0x509a, (int16)0x063e }, + { (int16)0x0030, (int16)0x281a, (int16)0x50da, (int16)0x065c }, + { (int16)0x002e, (int16)0x27be, (int16)0x5118, (int16)0x067c }, + { (int16)0x002c, (int16)0x2763, (int16)0x5156, (int16)0x069b }, + { (int16)0x0029, (int16)0x2708, (int16)0x5194, (int16)0x06bb }, + { (int16)0x0027, (int16)0x26ad, (int16)0x51d0, (int16)0x06dc }, + { (int16)0x0025, (int16)0x2653, (int16)0x520c, (int16)0x06fd }, + { (int16)0x0023, (int16)0x25f8, (int16)0x5247, (int16)0x071e }, + { (int16)0x0021, (int16)0x259e, (int16)0x5281, (int16)0x0740 }, + { (int16)0x0020, (int16)0x2545, (int16)0x52ba, (int16)0x0762 }, + { (int16)0x001e, (int16)0x24eb, (int16)0x52f3, (int16)0x0784 }, + { (int16)0x001c, (int16)0x2492, (int16)0x532a, (int16)0x07a7 }, + { (int16)0x001b, (int16)0x2439, (int16)0x5361, (int16)0x07cb }, + { (int16)0x0019, (int16)0x23e1, (int16)0x5397, (int16)0x07ef }, + { (int16)0x0018, (int16)0x2389, (int16)0x53cc, (int16)0x0813 }, + { (int16)0x0016, (int16)0x2331, (int16)0x5401, (int16)0x0838 }, + { (int16)0x0015, (int16)0x22da, (int16)0x5434, (int16)0x085d }, + { (int16)0x0013, (int16)0x2282, (int16)0x5467, (int16)0x0883 }, + { (int16)0x0012, (int16)0x222c, (int16)0x5499, (int16)0x08a9 }, + { (int16)0x0011, (int16)0x21d5, (int16)0x54ca, (int16)0x08d0 }, + { (int16)0x0010, (int16)0x217f, (int16)0x54fa, (int16)0x08f7 }, + { (int16)0x000f, (int16)0x2129, (int16)0x5529, (int16)0x091e }, + { (int16)0x000e, (int16)0x20d4, (int16)0x5558, (int16)0x0946 }, + { (int16)0x000d, (int16)0x207f, (int16)0x5585, (int16)0x096f }, + { (int16)0x000c, (int16)0x202a, (int16)0x55b2, (int16)0x0998 }, + { (int16)0x000b, (int16)0x1fd6, (int16)0x55de, (int16)0x09c1 }, + { (int16)0x000a, (int16)0x1f82, (int16)0x5609, (int16)0x09eb }, + { (int16)0x0009, (int16)0x1f2f, (int16)0x5632, (int16)0x0a16 }, + { (int16)0x0009, (int16)0x1edc, (int16)0x565b, (int16)0x0a40 }, + { (int16)0x0008, (int16)0x1e89, (int16)0x5684, (int16)0x0a6c }, + { (int16)0x0007, (int16)0x1e37, (int16)0x56ab, (int16)0x0a98 }, + { (int16)0x0007, (int16)0x1de5, (int16)0x56d1, (int16)0x0ac4 }, + { (int16)0x0006, (int16)0x1d93, (int16)0x56f6, (int16)0x0af1 }, + { (int16)0x0005, (int16)0x1d42, (int16)0x571b, (int16)0x0b1e }, + { (int16)0x0005, (int16)0x1cf1, (int16)0x573e, (int16)0x0b4c }, + { (int16)0x0004, (int16)0x1ca1, (int16)0x5761, (int16)0x0b7a }, + { (int16)0x0004, (int16)0x1c51, (int16)0x5782, (int16)0x0ba9 }, + { (int16)0x0003, (int16)0x1c02, (int16)0x57a3, (int16)0x0bd8 }, + { (int16)0x0003, (int16)0x1bb3, (int16)0x57c3, (int16)0x0c07 }, + { (int16)0x0003, (int16)0x1b64, (int16)0x57e2, (int16)0x0c38 }, + { (int16)0x0002, (int16)0x1b16, (int16)0x57ff, (int16)0x0c68 }, + { (int16)0x0002, (int16)0x1ac8, (int16)0x581c, (int16)0x0c99 }, + { (int16)0x0002, (int16)0x1a7b, (int16)0x5838, (int16)0x0ccb }, + { (int16)0x0001, (int16)0x1a2e, (int16)0x5853, (int16)0x0cfd }, + { (int16)0x0001, (int16)0x19e2, (int16)0x586d, (int16)0x0d30 }, + { (int16)0x0001, (int16)0x1996, (int16)0x5886, (int16)0x0d63 }, + { (int16)0x0001, (int16)0x194b, (int16)0x589e, (int16)0x0d97 }, + { (int16)0x0000, (int16)0x1900, (int16)0x58b5, (int16)0x0dcb }, + { (int16)0x0000, (int16)0x18b5, (int16)0x58cb, (int16)0x0e00 }, + { (int16)0x0000, (int16)0x186b, (int16)0x58e0, (int16)0x0e35 }, + { (int16)0x0000, (int16)0x1821, (int16)0x58f4, (int16)0x0e6b }, + { (int16)0x0000, (int16)0x17d8, (int16)0x5907, (int16)0x0ea1 }, + { (int16)0x0000, (int16)0x1790, (int16)0x5919, (int16)0x0ed7 }, + { (int16)0x0000, (int16)0x1747, (int16)0x592a, (int16)0x0f0f }, + { (int16)0xffff, (int16)0x1700, (int16)0x593a, (int16)0x0f46 }, + { (int16)0xffff, (int16)0x16b9, (int16)0x5949, (int16)0x0f7f }, + { (int16)0xffff, (int16)0x1672, (int16)0x5958, (int16)0x0fb7 }, + { (int16)0xffff, (int16)0x162c, (int16)0x5965, (int16)0x0ff1 }, + { (int16)0xffff, (int16)0x15e6, (int16)0x5971, (int16)0x102a }, + { (int16)0xffff, (int16)0x15a0, (int16)0x597c, (int16)0x1065 }, + { (int16)0xffff, (int16)0x155c, (int16)0x5986, (int16)0x109f }, + { (int16)0xffff, (int16)0x1517, (int16)0x598f, (int16)0x10db }, + { (int16)0xffff, (int16)0x14d4, (int16)0x5997, (int16)0x1116 }, + { (int16)0xffff, (int16)0x1490, (int16)0x599e, (int16)0x1153 }, + { (int16)0xffff, (int16)0x144d, (int16)0x59a4, (int16)0x118f }, + { (int16)0xffff, (int16)0x140b, (int16)0x59a9, (int16)0x11cd }, + { (int16)0xffff, (int16)0x13c9, (int16)0x59ad, (int16)0x120b }, + { (int16)0xffff, (int16)0x1388, (int16)0x59b0, (int16)0x1249 }, + { (int16)0xffff, (int16)0x1347, (int16)0x59b2, (int16)0x1288 }, + { (int16)0xffff, (int16)0x1307, (int16)0x59b3, (int16)0x12c7 }, diff --git a/psx/octoshock/psx/spu_nft.inc b/psx/octoshock/psx/spu_nft.inc new file mode 100644 index 0000000000..95b8f49c11 --- /dev/null +++ b/psx/octoshock/psx/spu_nft.inc @@ -0,0 +1,64 @@ +0x00000001, +0x00000001, +0x00000001, +0x00000001, +0x00000002, +0x00000002, +0x00000002, +0x00000002, +0x00000004, +0x00000005, +0x00000006, +0x00000007, +0x00000008, +0x0000000a, +0x0000000c, +0x0000000e, +0x00000010, +0x00000014, +0x00000018, +0x0000001c, +0x00000020, +0x00000028, +0x00000030, +0x00000038, +0x00000040, +0x00000050, +0x00000060, +0x00000070, +0x00000080, +0x000000a0, +0x000000c0, +0x000000e0, +0x00000100, +0x00000140, +0x00000180, +0x000001c0, +0x00000200, +0x00000280, +0x00000300, +0x00000380, +0x00000400, +0x00000500, +0x00000600, +0x00000700, +0x00000800, +0x00000a00, +0x00000c00, +0x00000e00, +0x00001000, +0x00001400, +0x00001800, +0x00001c00, +0x00002000, +0x00002800, +0x00003000, +0x00003800, +0x00004000, +0x00005000, +0x00006000, +0x00007000, +0x00008000, +0x00008000, +0x00008000, +0x00008000, diff --git a/psx/octoshock/psx/spu_reverb.inc b/psx/octoshock/psx/spu_reverb.inc new file mode 100644 index 0000000000..8192fd9c9f --- /dev/null +++ b/psx/octoshock/psx/spu_reverb.inc @@ -0,0 +1,237 @@ +static int16 ReverbSat(int32 samp) MDFN_WARN_UNUSED_RESULT; +static INLINE int16 ReverbSat(int32 samp) +{ + if(samp > 32767) + samp = 32767; + + if(samp < -32768) + samp = -32768; + + return(samp); +} + + +INLINE int32 PS_SPU::Get_Reverb_Offset(int32 in_offset) +{ + int32 offset = in_offset & 0x3FFFF; + int32 wa_size = 0x40000 - ReverbWA; + + if(offset & 0x20000) + { + offset -= ReverbWA; + + if(offset < 0) + { + offset = 0; + //PSX_WARNING("[SPU] A reverb offset is broken(-)."); + } + } + else + { + if(offset >= wa_size) + { + offset = wa_size - 1; + //PSX_WARNING("[SPU] A reverb offset is broken(+): WASize=0x%04x, 0x%04x.", wa_size >> 2, in_offset >> 2); + } + } + + offset += ReverbCur; + + if(offset >= 0x40000) + offset = (offset & 0x3FFFF) + ReverbWA; + + assert(offset >= ReverbWA && offset < 0x40000); + + return(offset); +} + +int32 PS_SPU::RD_RVB(int16 raw_offs) +{ + //raw_offs = rand() & 0xFFFF; + + return((int16)SPURAM[Get_Reverb_Offset(raw_offs << 2)]); +} + +void PS_SPU::WR_RVB(int16 raw_offs, int32 sample, int32 extra_offs) +{ + //raw_offs = rand() & 0xFFFF; + + SPURAM[Get_Reverb_Offset((raw_offs << 2) + extra_offs)] = ReverbSat(sample); +} + +static INLINE int32 Reverb4422(const int16 *src) +{ + static const int16 ResampTable[40] = + { + (int16)0xffff, + (int16)0x0000, + (int16)0x0002, + (int16)0x0000, + (int16)0xfff6, + (int16)0x0000, + (int16)0x0023, + (int16)0x0000, + (int16)0xff99, + (int16)0x0000, + (int16)0x010a, + (int16)0x0000, + (int16)0xfd98, + (int16)0x0000, + (int16)0x0534, + (int16)0x0000, + (int16)0xf470, + (int16)0x0000, + (int16)0x2806, + (int16)0x4000, + (int16)0x2806, + (int16)0x0000, + (int16)0xf470, + (int16)0x0000, + (int16)0x0534, + (int16)0x0000, + (int16)0xfd98, + (int16)0x0000, + (int16)0x010a, + (int16)0x0000, + (int16)0xff99, + (int16)0x0000, + (int16)0x0023, + (int16)0x0000, + (int16)0xfff6, + (int16)0x0000, + (int16)0x0002, + (int16)0x0000, + (int16)0xffff, + (int16)0x0000, + }; + int32 out = 0; // 32-bits is adequate(it won't overflow) + + for(int i = 0; i < 40; i += 2) + out += ResampTable[i] * src[i]; + + // Middle non-zero + out += 0x4000 * src[19]; + + out >>= 15; + + if(out < -32768) + out = -32768; + + if(out > 32767) + out = 32767; + + return(out); +} + +void PS_SPU::RunReverb(int32 in_l, int32 in_r, int32 &out_l, int32 &out_r) +{ + int32 upsampled[2] = { 0, 0 }; + + RDSB[0][RDSB_WP] = in_l; + RDSB[1][RDSB_WP] = in_r; + RDSB[0][RDSB_WP | 0x40] = in_l; // So we don't have to &/bounds check in our MAC loop + RDSB[1][RDSB_WP | 0x40] = in_r; + + RDSB_WP = (RDSB_WP + 1) & 0x3F; + + if(!(RDSB_WP & 1)) + { + int32 downsampled[2]; + + for(int lr = 0; lr < 2; lr++) + downsampled[lr] = Reverb4422(&RDSB[lr][(RDSB_WP - 40) & 0x3F]); + + // + // Run algorithm + /// + if(SPUControl & 0x80) + { + int32 IIR_INPUT_A0; + int32 IIR_INPUT_A1; + int32 IIR_INPUT_B0; + int32 IIR_INPUT_B1; + int32 IIR_A0, IIR_A1, IIR_B0, IIR_B1; + int32 ACC0, ACC1; + int32 FB_A0, FB_A1, FB_B0, FB_B1; + + IIR_INPUT_A0 = ((RD_RVB(IIR_SRC_A0) * IIR_COEF) >> 15) + ((downsampled[0] * IN_COEF_L) >> 15); + IIR_INPUT_A1 = ((RD_RVB(IIR_SRC_A1) * IIR_COEF) >> 15) + ((downsampled[1] * IN_COEF_R) >> 15); + IIR_INPUT_B0 = ((RD_RVB(IIR_SRC_B0) * IIR_COEF) >> 15) + ((downsampled[0] * IN_COEF_L) >> 15); + IIR_INPUT_B1 = ((RD_RVB(IIR_SRC_B1) * IIR_COEF) >> 15) + ((downsampled[1] * IN_COEF_R) >> 15); + + + IIR_A0 = (((int64)IIR_INPUT_A0 * IIR_ALPHA) >> 15) + ((RD_RVB(IIR_DEST_A0) * (32768 - IIR_ALPHA)) >> 15); + IIR_A1 = (((int64)IIR_INPUT_A1 * IIR_ALPHA) >> 15) + ((RD_RVB(IIR_DEST_A1) * (32768 - IIR_ALPHA)) >> 15); + IIR_B0 = (((int64)IIR_INPUT_B0 * IIR_ALPHA) >> 15) + ((RD_RVB(IIR_DEST_B0) * (32768 - IIR_ALPHA)) >> 15); + IIR_B1 = (((int64)IIR_INPUT_B1 * IIR_ALPHA) >> 15) + ((RD_RVB(IIR_DEST_B1) * (32768 - IIR_ALPHA)) >> 15); + + WR_RVB(IIR_DEST_A0, IIR_A0, 1); + WR_RVB(IIR_DEST_A1, IIR_A1, 1); + WR_RVB(IIR_DEST_B0, IIR_B0, 1); + WR_RVB(IIR_DEST_B1, IIR_B1, 1); + +#if 0 + ACC0 = ((RD_RVB(ACC_SRC_A0) * ACC_COEF_A) >> 15) + + ((RD_RVB(ACC_SRC_B0) * ACC_COEF_B) >> 15) + + ((RD_RVB(ACC_SRC_C0) * ACC_COEF_C) >> 15) + + ((RD_RVB(ACC_SRC_D0) * ACC_COEF_D) >> 15); + + ACC1 = ((RD_RVB(ACC_SRC_A1) * ACC_COEF_A) >> 15) + + ((RD_RVB(ACC_SRC_B1) * ACC_COEF_B) >> 15) + + ((RD_RVB(ACC_SRC_C1) * ACC_COEF_C) >> 15) + + ((RD_RVB(ACC_SRC_D1) * ACC_COEF_D) >> 15); +#endif + + ACC0 = ((int64)(RD_RVB(ACC_SRC_A0) * ACC_COEF_A) + + (RD_RVB(ACC_SRC_B0) * ACC_COEF_B) + + (RD_RVB(ACC_SRC_C0) * ACC_COEF_C) + + (RD_RVB(ACC_SRC_D0) * ACC_COEF_D)) >> 15; + + + ACC1 = ((int64)(RD_RVB(ACC_SRC_A1) * ACC_COEF_A) + + (RD_RVB(ACC_SRC_B1) * ACC_COEF_B) + + (RD_RVB(ACC_SRC_C1) * ACC_COEF_C) + + (RD_RVB(ACC_SRC_D1) * ACC_COEF_D)) >> 15; + + + FB_A0 = RD_RVB(MIX_DEST_A0 - FB_SRC_A); + FB_A1 = RD_RVB(MIX_DEST_A1 - FB_SRC_A); + FB_B0 = RD_RVB(MIX_DEST_B0 - FB_SRC_B); + FB_B1 = RD_RVB(MIX_DEST_B1 - FB_SRC_B); + + WR_RVB(MIX_DEST_A0, ACC0 - ((FB_A0 * FB_ALPHA) >> 15)); + WR_RVB(MIX_DEST_A1, ACC1 - ((FB_A1 * FB_ALPHA) >> 15)); + + WR_RVB(MIX_DEST_B0, (((int64)FB_ALPHA * ACC0) >> 15) - ((FB_A0 * (int16)(0x8000 ^ FB_ALPHA)) >> 15) - ((FB_B0 * FB_X) >> 15)); + WR_RVB(MIX_DEST_B1, (((int64)FB_ALPHA * ACC1) >> 15) - ((FB_A1 * (int16)(0x8000 ^ FB_ALPHA)) >> 15) - ((FB_B1 * FB_X) >> 15)); + } + + // + // Get output samples + // +// RUSB[0][RUSB_WP | 0x40] = RUSB[0][RUSB_WP] = (short)rand(); +// RUSB[1][RUSB_WP | 0x40] = RUSB[1][RUSB_WP] = (short)rand(); + RUSB[0][RUSB_WP | 0x40] = RUSB[0][RUSB_WP] = (RD_RVB(MIX_DEST_A0) + RD_RVB(MIX_DEST_B0)) >> 1; + RUSB[1][RUSB_WP | 0x40] = RUSB[1][RUSB_WP] = (RD_RVB(MIX_DEST_A1) + RD_RVB(MIX_DEST_B1)) >> 1; + + RUSB_WP = (RUSB_WP + 1) & 0x3F; + + ReverbCur = (ReverbCur + 1) & 0x3FFFF; + if(!ReverbCur) + ReverbCur = ReverbWA; + } + else + { + RUSB[0][RUSB_WP | 0x40] = RUSB[0][RUSB_WP] = 0; + RUSB[1][RUSB_WP | 0x40] = RUSB[1][RUSB_WP] = 0; + + RUSB_WP = (RUSB_WP + 1) & 0x3F; + } + + for(int lr = 0; lr < 2; lr++) + upsampled[lr] = Reverb4422(&RUSB[lr][(RUSB_WP - 40) & 0x3F]); + + out_l = upsampled[0]; + out_r = upsampled[1]; +} + diff --git a/psx/octoshock/psx/timer.cpp b/psx/octoshock/psx/timer.cpp new file mode 100644 index 0000000000..8cb918e19c --- /dev/null +++ b/psx/octoshock/psx/timer.cpp @@ -0,0 +1,524 @@ +/* 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 "psx.h" +#include "timer.h" + +/* + Notes(some of it may be incomplete or wrong in subtle ways) + + Control bits: + Lower 3 bits of mode, for timer1(when mode is | 0x100): + 0x1 = don't count while in vblank(except that the first count while in vblank does go through) + 0x3 = vblank going inactive triggers timer reset, then some interesting behavior where counting again is delayed... + 0x5 = vblank going inactive triggers timer reset, and only count within vblank. + 0x7 = Wait until vblank goes active then inactive, then start counting? + For timer2: + 0x1 = timer stopped(TODO: confirm on real system) + + Target mode enabled 0x008 + IRQ enable 0x010 + --?Affects 0x400 status flag?-- 0x020 + IRQ evaluation auto-reset 0x040 + --unknown-- 0x080 + Clock selection 0x100 + Divide by 8(timer 2 only?) 0x200 + + Counter: + Reset to 0 on writes to the mode/status register. + + Status flags: + Unknown flag 0x0400 + Compare flag 0x0800 + Cleared on mode/status read. + Set when: //ever Counter == 0(proooobably, need to investigate lower 3 bits in relation to this). + + + Overflow/Carry flag 0x1000 + Cleared on mode/status read. + Set when counter overflows from 0xFFFF->0. + + Hidden flags: + IRQ done + Cleared on writes to the mode/status register, on writes to the count register, and apparently automatically when the counter + increments if (Mode & 0x40) [Note: If target mode is enabled, and target is 0, IRQ done flag won't be automatically reset] + + There seems to be a brief period(edge condition?) where, if count to target is enabled, you can (sometimes?) read the target value in the count + register before it's reset to 0. I doubt any games rely on this, but who knows. Maybe a PSX equivalent of the PC Engine "Battle Royale"? ;) + + When the counter == 0, the compare flag is set. An IRQ will be generated if (Mode & 0x10), and the hidden IRQ done flag will be set. +*/ + +/* + Dec. 26, 2011 Note + Due to problems I've had with my GPU timing test program, timer2 appears to be unreliable(clocks are skipped?) when target mode is enabled and the full + 33MHz clock is used(rather than 33MHz / 8). TODO: Investigate further and confirm(or not). + + Jan. 15, 2013 Note: + Counters using GPU clock sources(hretrace,dot clock) reportedly will with a low probability return wrong count values on an actual PS1, so keep this in mind + when writing test programs(IE keep reading the count value until two consecutive reads return the same value). +*/ + +/* + FIXME: Clock appropriately(and update events) when using SetRegister() via the debugger. + + TODO: If we ever return randomish values to "simulate" open bus, remember to change the return type and such of the TIMER_Read() function to full 32-bit too. +*/ + +namespace MDFN_IEN_PSX +{ + +struct Timer +{ + uint32 Mode; + int32 Counter; // Only 16-bit, but 32-bit here for detecting counting past target. + int32 Target; + + int32 Div8Counter; + + bool IRQDone; + int32 DoZeCounting; +}; + +static bool vblank; +static bool hretrace; +static Timer Timers[3]; +static pscpu_timestamp_t lastts; + +static int32 CalcNextEvent(int32 next_event) +{ + for(int i = 0; i < 3; i++) + { + int32 target; + int32 count_delta; + + if((i == 0 || i == 1) && (Timers[i].Mode & 0x100)) // If clocked by GPU, abort for this timer(will result in poor granularity for pixel-clock-derived timer IRQs, but whatever). + continue; + + if(!(Timers[i].Mode & 0x10)) // If IRQ is disabled, abort for this timer. + continue; + + if((Timers[i].Mode & 0x8) && (Timers[i].Counter == 0) && (Timers[i].Target == 0) && !Timers[i].IRQDone) + { + next_event = 1; + continue; + } + + target = ((Timers[i].Mode & 0x8) && (Timers[i].Counter < Timers[i].Target)) ? Timers[i].Target : 0x10000; + + count_delta = target - Timers[i].Counter; + if(count_delta <= 0) + { + PSX_DBG(PSX_DBG_ERROR, "timer %d count_delta <= 0!!! %d %d\n", i, target, Timers[i].Counter); + continue; + } + + { + int32 tmp_clocks; + + if(Timers[i].DoZeCounting <= 0) + continue; + + if((i == 0x2) && (Timers[i].Mode & 0x1)) + continue; + + if((i == 0x2) && (Timers[i].Mode & 0x200)) + { + assert(Timers[i].Div8Counter >= 0 && Timers[i].Div8Counter < 8); + tmp_clocks = ((count_delta - 1) * 8) + (8 - Timers[i].Div8Counter); + } + else + tmp_clocks = count_delta; + + assert(tmp_clocks > 0); + + if(next_event > tmp_clocks) + next_event = tmp_clocks; + } + } + + return(next_event); +} + +static void ClockTimer(int i, uint32 clocks) +{ + int32 before = Timers[i].Counter; + int32 target = 0x10000; + bool zero_tm = false; + + if(Timers[i].DoZeCounting <= 0) + clocks = 0; + + if(i == 0x2) + { + uint32 d8_clocks; + + Timers[i].Div8Counter += clocks; + d8_clocks = Timers[i].Div8Counter >> 3; + Timers[i].Div8Counter -= d8_clocks << 3; + + if(Timers[i].Mode & 0x200) // Divide by 8, at least for timer 0x2 + clocks = d8_clocks; + + if(Timers[i].Mode & 1) + clocks = 0; + } + + if(Timers[i].Mode & 0x008) + target = Timers[i].Target; + + if(target == 0 && Timers[i].Counter == 0) + zero_tm = true; + else + Timers[i].Counter += clocks; + + if(clocks && (Timers[i].Mode & 0x40)) + Timers[i].IRQDone = false; + + if((before < target && Timers[i].Counter >= target) || zero_tm || Timers[i].Counter > 0xFFFF) + { +#if 1 + if(Timers[i].Mode & 0x10) + { + if((Timers[i].Counter - target) > 3) + PSX_WARNING("Timer %d IRQ trigger error: %d", i, Timers[i].Counter - target); + } + +#endif + + + Timers[i].Mode |= 0x0800; + + if(Timers[i].Counter > 0xFFFF) + { + Timers[i].Counter -= 0x10000; + + if(target == 0x10000) + Timers[i].Mode |= 0x1000; + + if(!target) + Timers[i].Counter = 0; + } + + if(target) + Timers[i].Counter -= (Timers[i].Counter / target) * target; + + if((Timers[i].Mode & 0x10) && !Timers[i].IRQDone) + { + Timers[i].IRQDone = true; + + IRQ_Assert(IRQ_TIMER_0 + i, true); + IRQ_Assert(IRQ_TIMER_0 + i, false); + } + + if(Timers[i].Counter && (Timers[i].Mode & 0x40)) + Timers[i].IRQDone = false; + } + +} + +void TIMER_SetVBlank(bool status) +{ + switch(Timers[1].Mode & 0x7) + { + case 0x1: + Timers[1].DoZeCounting = !status; + break; + + case 0x3: + if(vblank && !status) + Timers[1].Counter = 0; + break; + + case 0x5: + Timers[1].DoZeCounting = status; + if(vblank && !status) + Timers[1].Counter = 0; + break; + + case 0x7: + if(Timers[1].DoZeCounting == -1) + { + if(!vblank && status) + Timers[1].DoZeCounting = 0; + } + else if(Timers[1].DoZeCounting == 0) + { + if(vblank && !status) + Timers[1].DoZeCounting = 1; + } + break; + } + vblank = status; +} + +void TIMER_SetHRetrace(bool status) +{ + if(hretrace && !status) + { + if((Timers[0].Mode & 0x7) == 0x3) + Timers[0].Counter = 0; + } + + hretrace = status; +} + +void TIMER_AddDotClocks(uint32 count) +{ + if(Timers[0].Mode & 0x100) + ClockTimer(0, count); +} + +void TIMER_ClockHRetrace(void) +{ + if(Timers[1].Mode & 0x100) + ClockTimer(1, 1); +} + +pscpu_timestamp_t TIMER_Update(const pscpu_timestamp_t timestamp) +{ + int32 cpu_clocks = timestamp - lastts; + + for(int i = 0; i < 3; i++) + { + uint32 timer_clocks = cpu_clocks; + + if(Timers[i].Mode & 0x100) + continue; + + ClockTimer(i, timer_clocks); + } + + lastts = timestamp; + + return(timestamp + CalcNextEvent(1024)); +} + +static void CalcCountingStart(unsigned which) +{ + Timers[which].DoZeCounting = true; + + switch(which) + { + case 1: + switch(Timers[which].Mode & 0x07) + { + case 0x1: + Timers[which].DoZeCounting = !vblank; + break; + + case 0x5: + Timers[which].DoZeCounting = vblank; + break; + + case 0x7: + Timers[which].DoZeCounting = -1; + break; + } + break; + + + } +} + +void TIMER_Write(const pscpu_timestamp_t timestamp, uint32 A, uint16 V) +{ + TIMER_Update(timestamp); + + int which = (A >> 4) & 0x3; + + V <<= (A & 3) * 8; + + PSX_DBGINFO("[TIMER] Write: %08x %04x\n", A, V); + + if(which >= 3) + return; + + // TODO: See if the "Timers[which].Counter" part of the IRQ if() statements below is what a real PSX does. + switch(A & 0xC) + { + case 0x0: Timers[which].IRQDone = false; +#if 1 + if(Timers[which].Counter && (V & 0xFFFF) == 0) + { + Timers[which].Mode |= 0x0800; + if((Timers[which].Mode & 0x10) && !Timers[which].IRQDone) + { + Timers[which].IRQDone = true; + IRQ_Assert(IRQ_TIMER_0 + which, true); + IRQ_Assert(IRQ_TIMER_0 + which, false); + } + } +#endif + Timers[which].Counter = V & 0xFFFF; + break; + + case 0x4: Timers[which].Mode = (V & 0x3FF) | (Timers[which].Mode & 0x1C00); + Timers[which].IRQDone = false; +#if 1 + if(Timers[which].Counter) + { + Timers[which].Mode |= 0x0800; + if((Timers[which].Mode & 0x10) && !Timers[which].IRQDone) + { + Timers[which].IRQDone = true; + IRQ_Assert(IRQ_TIMER_0 + which, true); + IRQ_Assert(IRQ_TIMER_0 + which, false); + } + } + Timers[which].Counter = 0; +#endif + CalcCountingStart(which); // Call after setting .Mode + break; + + case 0x8: Timers[which].Target = V & 0xFFFF; + break; + + case 0xC: // Open bus + break; + } + + // TIMER_Update(timestamp); + + PSX_SetEventNT(PSX_EVENT_TIMER, timestamp + CalcNextEvent(1024)); +} + +uint16 TIMER_Read(const pscpu_timestamp_t timestamp, uint32 A) +{ + uint16 ret = 0; + int which = (A >> 4) & 0x3; + + if(which >= 3) + { + PSX_WARNING("[TIMER] Open Bus Read: 0x%08x", A); + + return(ret >> ((A & 3) * 8)); + } + + TIMER_Update(timestamp); + + switch(A & 0xC) + { + case 0x0: ret = Timers[which].Counter; + break; + + case 0x4: ret = Timers[which].Mode; + Timers[which].Mode &= ~0x1800; + break; + + case 0x8: ret = Timers[which].Target; + break; + + case 0xC: PSX_WARNING("[TIMER] Open Bus Read: 0x%08x", A); + break; + } + + return(ret >> ((A & 3) * 8)); +} + + +void TIMER_ResetTS(void) +{ + lastts = 0; +} + + +void TIMER_Power(void) +{ + lastts = 0; + + hretrace = false; + vblank = false; + memset(Timers, 0, sizeof(Timers)); +} + +int TIMER_StateAction(StateMem *sm, int load, int data_only) +{ + SFORMAT StateRegs[] = + { +#define SFTIMER(n) SFVARN(Timers[n].Mode, #n "Mode"), \ + SFVARN(Timers[n].Counter, #n "Counter"), \ + SFVARN(Timers[n].Target, #n "Target"), \ + SFVARN(Timers[n].Div8Counter, #n "Div8Counter"), \ + SFVARN(Timers[n].IRQDone, #n "IRQDone"), \ + SFVARN(Timers[n].DoZeCounting, #n "DoZeCounting") + SFTIMER(0), + SFTIMER(1), + SFTIMER(2), +#undef SFTIMER + + SFVAR(vblank), + SFVAR(hretrace), + + SFEND + }; + int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "TIMER"); + + if(load) + { + + } + + return(ret); +} + +uint32 TIMER_GetRegister(unsigned int which, char *special, const uint32 special_len) +{ + int tw = (which >> 4) & 0x3; + uint32 ret = 0; + + switch(which & 0xF) + { + case TIMER_GSREG_COUNTER0: + ret = Timers[tw].Counter; + break; + + case TIMER_GSREG_MODE0: + ret = Timers[tw].Mode; + break; + + case TIMER_GSREG_TARGET0: + ret = Timers[tw].Target; + break; + } + + return(ret); +} + +void TIMER_SetRegister(unsigned int which, uint32 value) +{ + int tw = (which >> 4) & 0x3; + + switch(which & 0xF) + { + case TIMER_GSREG_COUNTER0: + Timers[tw].Counter = value & 0xFFFF; + break; + + case TIMER_GSREG_MODE0: + Timers[tw].Mode = value & 0xFFFF; + break; + + case TIMER_GSREG_TARGET0: + Timers[tw].Target = value & 0xFFFF; + break; + } + +} + + +} diff --git a/psx/octoshock/psx/timer.h b/psx/octoshock/psx/timer.h new file mode 100644 index 0000000000..a816ad0591 --- /dev/null +++ b/psx/octoshock/psx/timer.h @@ -0,0 +1,42 @@ +#ifndef __MDFN_PSX_TIMER_H +#define __MDFN_PSX_TIMER_H + +namespace MDFN_IEN_PSX +{ + +enum +{ + TIMER_GSREG_COUNTER0 = 0x00, + TIMER_GSREG_MODE0, + TIMER_GSREG_TARGET0, + + TIMER_GSREG_COUNTER1 = 0x10, + TIMER_GSREG_MODE1, + TIMER_GSREG_TARGET1, + + TIMER_GSREG_COUNTER2 = 0x20, + TIMER_GSREG_MODE2, + TIMER_GSREG_TARGET2, +}; + +uint32 TIMER_GetRegister(unsigned int which, char *special, const uint32 special_len); +void TIMER_SetRegister(unsigned int which, uint32 value); + + +void TIMER_Write(const pscpu_timestamp_t timestamp, uint32 A, uint16 V); +uint16 TIMER_Read(const pscpu_timestamp_t timestamp, uint32 A); + +void TIMER_AddDotClocks(uint32 count); +void TIMER_ClockHRetrace(void); +void TIMER_SetHRetrace(bool status); +void TIMER_SetVBlank(bool status); + +pscpu_timestamp_t TIMER_Update(const pscpu_timestamp_t); +void TIMER_ResetTS(void); + +void TIMER_Power(void); +int TIMER_StateAction(StateMem *sm, int load, int data_only); + +} + +#endif diff --git a/psx/octoshock/state.cpp b/psx/octoshock/state.cpp new file mode 100644 index 0000000000..5df459221b --- /dev/null +++ b/psx/octoshock/state.cpp @@ -0,0 +1,897 @@ +/* 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 + +#include "octoshock.h" + +#include "state.h" +#include "video.h" +//#include "video/resize.h" +#include "endian.h" + +static int SaveStateStatus[10]; + +#define RLSB MDFNSTATE_RLSB //0x80000000 + +int32 smem_read(StateMem *st, void *buffer, uint32 len) +{ + if((len + st->loc) > st->len) + return(0); + + memcpy(buffer, st->data + st->loc, len); + st->loc += len; + + return(len); +} + +int32 smem_write(StateMem *st, void *buffer, uint32 len) +{ + if((len + st->loc) > st->malloced) + { + uint32 newsize = (st->malloced >= 32768) ? st->malloced : (st->initial_malloc ? st->initial_malloc : 32768); + + while(newsize < (len + st->loc)) + newsize *= 2; + st->data = (uint8 *)realloc(st->data, newsize); + st->malloced = newsize; + } + memcpy(st->data + st->loc, buffer, len); + st->loc += len; + + if(st->loc > st->len) st->len = st->loc; + + return(len); +} + +int32 smem_putc(StateMem *st, int value) +{ + uint8 tmpval = value; + if(smem_write(st, &tmpval, 1) != 1) + return(-1); + return(1); +} + +int32 smem_tell(StateMem *st) +{ + return(st->loc); +} + +int32 smem_seek(StateMem *st, uint32 offset, int whence) +{ + switch(whence) + { + case SEEK_SET: st->loc = offset; break; + case SEEK_END: st->loc = st->len - offset; break; + case SEEK_CUR: st->loc += offset; break; + } + + if(st->loc > st->len) + { + st->loc = st->len; + return(-1); + } + + if(st->loc < 0) + { + st->loc = 0; + return(-1); + } + + return(0); +} + +int smem_write32le(StateMem *st, uint32 b) +{ + uint8 s[4]; + s[0]=b; + s[1]=b>>8; + s[2]=b>>16; + s[3]=b>>24; + return((smem_write(st, s, 4)<4)?0:4); +} + +int smem_read32le(StateMem *st, uint32 *b) +{ + uint8 s[4]; + + if(smem_read(st, s, 4) < 4) + return(0); + + *b = s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24); + + return(4); +} + + +static bool ValidateSFStructure(SFORMAT *sf) +{ + SFORMAT *saved_sf = sf; + + while(sf->size || sf->name) + { + SFORMAT *sub_sf = saved_sf; + while(sub_sf->size || sub_sf->name) + { + if(sf != sub_sf) + { + if(!strncmp(sf->name, sub_sf->name, 32)) + { + printf("Duplicate state variable name: %.32s\n", sf->name); + } + } + sub_sf++; + } + + sf++; + } + return(1); +} + + +static bool SubWrite(StateMem *st, SFORMAT *sf, int data_only, const char *name_prefix = NULL) +{ + // FIXME? It's kind of slow, and we definitely don't want it on with state rewinding... + if(!data_only) + ValidateSFStructure(sf); + + while(sf->size || sf->name) // Size can sometimes be zero, so also check for the text name. These two should both be zero only at the end of a struct. + { + if(!sf->size || !sf->v) + { + sf++; + continue; + } + + if(sf->size == (uint32)~0) /* Link to another struct. */ + { + if(!SubWrite(st, (SFORMAT *)sf->v, data_only, name_prefix)) + return(0); + + sf++; + continue; + } + + int32 bytesize = sf->size; + + // If we're only saving the raw data, and we come across a bool type, we save it as it is in memory, rather than converting it to + // 1-byte. In the SFORMAT structure, the size member for bool entries is the number of bool elements, not the total in-memory size, + // so we adjust it here. + if(data_only && (sf->flags & MDFNSTATE_BOOL)) + { + bytesize *= sizeof(bool); + } + + if(!data_only) + { + char nameo[1 + 256]; + int slen; + + slen = snprintf(nameo + 1, 256, "%s%s", name_prefix ? name_prefix : "", sf->name); + nameo[0] = slen; + + if(slen >= 255) + { + printf("Warning: state variable name possibly too long: %s %s %s %d\n", sf->name, name_prefix, nameo, slen); + slen = 255; + } + + smem_write(st, nameo, 1 + nameo[0]); + smem_write32le(st, bytesize); + + /* Flip the byte order... */ + if(sf->flags & MDFNSTATE_BOOL) + { + + } + else if(sf->flags & MDFNSTATE_RLSB64) + Endian_A64_NE_to_LE(sf->v, bytesize / sizeof(uint64)); + else if(sf->flags & MDFNSTATE_RLSB32) + Endian_A32_NE_to_LE(sf->v, bytesize / sizeof(uint32)); + else if(sf->flags & MDFNSTATE_RLSB16) + Endian_A16_NE_to_LE(sf->v, bytesize / sizeof(uint16)); + else if(sf->flags & RLSB) + Endian_V_NE_to_LE(sf->v, bytesize); + } + + // Special case for the evil bool type, to convert bool to 1-byte elements. + // Don't do it if we're only saving the raw data. + if((sf->flags & MDFNSTATE_BOOL) && !data_only) + { + for(int32 bool_monster = 0; bool_monster < bytesize; bool_monster++) + { + uint8 tmp_bool = ((bool *)sf->v)[bool_monster]; + //printf("Bool write: %.31s\n", sf->name); + smem_write(st, &tmp_bool, 1); + } + } + else + smem_write(st, (uint8 *)sf->v, bytesize); + + if(!data_only) + { + /* Now restore the original byte order. */ + if(sf->flags & MDFNSTATE_BOOL) + { + + } + else if(sf->flags & MDFNSTATE_RLSB64) + Endian_A64_LE_to_NE(sf->v, bytesize / sizeof(uint64)); + else if(sf->flags & MDFNSTATE_RLSB32) + Endian_A32_LE_to_NE(sf->v, bytesize / sizeof(uint32)); + else if(sf->flags & MDFNSTATE_RLSB16) + Endian_A16_LE_to_NE(sf->v, bytesize / sizeof(uint16)); + else if(sf->flags & RLSB) + Endian_V_LE_to_NE(sf->v, bytesize); + } + sf++; + } + + return TRUE_1; +} + +static int WriteStateChunk(StateMem *st, const char *sname, SFORMAT *sf, int data_only) +{ + int32 data_start_pos; + int32 end_pos; + + if(!data_only) + { + uint8 sname_tmp[32]; + + memset(sname_tmp, 0, sizeof(sname_tmp)); + strncpy((char *)sname_tmp, sname, 32); + + if(strlen(sname) > 32) + printf("Warning: section name is too long: %s\n", sname); + + smem_write(st, sname_tmp, 32); + + smem_write32le(st, 0); // We'll come back and write this later. + } + + data_start_pos = smem_tell(st); + + if(!SubWrite(st, sf, data_only)) + return(0); + + end_pos = smem_tell(st); + + if(!data_only) + { + smem_seek(st, data_start_pos - 4, SEEK_SET); + smem_write32le(st, end_pos - data_start_pos); + smem_seek(st, end_pos, SEEK_SET); + } + + return(end_pos - data_start_pos); +} + +struct compare_cstr +{ + bool operator()(const char *s1, const char *s2) const + { + return(strcmp(s1, s2) < 0); + } +}; + +typedef std::map SFMap_t; + +static void MakeSFMap(SFORMAT *sf, SFMap_t &sfmap) +{ + while(sf->size || sf->name) // Size can sometimes be zero, so also check for the text name. These two should both be zero only at the end of a struct. + { + if(!sf->size || !sf->v) + { + sf++; + continue; + } + + if(sf->size == (uint32)~0) /* Link to another SFORMAT structure. */ + MakeSFMap((SFORMAT *)sf->v, sfmap); + else + { + assert(sf->name); + + if(sfmap.find(sf->name) != sfmap.end()) + printf("Duplicate save state variable in internal emulator structures(CLUB THE PROGRAMMERS WITH BREADSTICKS): %s\n", sf->name); + + sfmap[sf->name] = sf; + } + + sf++; + } +} + +// Fast raw chunk reader +static void DOReadChunk(StateMem *st, SFORMAT *sf) +{ + while(sf->size || sf->name) // Size can sometimes be zero, so also check for the text name. + // These two should both be zero only at the end of a struct. + { + if(!sf->size || !sf->v) + { + sf++; + continue; + } + + if(sf->size == (uint32) ~0) // Link to another SFORMAT struct + { + DOReadChunk(st, (SFORMAT *)sf->v); + sf++; + continue; + } + + int32 bytesize = sf->size; + + // Loading raw data, bool types are stored as they appear in memory, not as single bytes in the full state format. + // In the SFORMAT structure, the size member for bool entries is the number of bool elements, not the total in-memory size, + // so we adjust it here. + if(sf->flags & MDFNSTATE_BOOL) + bytesize *= sizeof(bool); + + smem_read(st, (uint8 *)sf->v, bytesize); + sf++; + } +} + +static int ReadStateChunk(StateMem *st, SFORMAT *sf, int size, int data_only) +{ + int temp; + + if(data_only) + { + DOReadChunk(st, sf); + } + else + { + SFMap_t sfmap; + SFMap_t sfmap_found; // Used for identifying variables that are missing in the save state. + + MakeSFMap(sf, sfmap); + + temp = smem_tell(st); + while(smem_tell(st) < (temp + size)) + { + uint32 recorded_size; // In bytes + uint8 toa[1 + 256]; // Don't change to char unless cast toa[0] to unsigned to smem_read() and other places. + + if(smem_read(st, toa, 1) != 1) + { + puts("Unexpected EOF"); + return(0); + } + + if(smem_read(st, toa + 1, toa[0]) != toa[0]) + { + puts("Unexpected EOF?"); + return 0; + } + + toa[1 + toa[0]] = 0; + + smem_read32le(st, &recorded_size); + + SFMap_t::iterator sfmit; + + sfmit = sfmap.find((char *)toa + 1); + + if(sfmit != sfmap.end()) + { + SFORMAT *tmp = sfmit->second; + uint32 expected_size = tmp->size; // In bytes + + if(recorded_size != expected_size) + { + printf("Variable in save state wrong size: %s. Need: %u, got: %u\n", toa + 1, expected_size, recorded_size); + if(smem_seek(st, recorded_size, SEEK_CUR) < 0) + { + puts("Seek error"); + return(0); + } + } + else + { + sfmap_found[tmp->name] = tmp; + + smem_read(st, (uint8 *)tmp->v, expected_size); + + if(tmp->flags & MDFNSTATE_BOOL) + { + // Converting downwards is necessary for the case of sizeof(bool) > 1 + for(int32 bool_monster = expected_size - 1; bool_monster >= 0; bool_monster--) + { + ((bool *)tmp->v)[bool_monster] = ((uint8 *)tmp->v)[bool_monster]; + } + } + if(tmp->flags & MDFNSTATE_RLSB64) + Endian_A64_LE_to_NE(tmp->v, expected_size / sizeof(uint64)); + else if(tmp->flags & MDFNSTATE_RLSB32) + Endian_A32_LE_to_NE(tmp->v, expected_size / sizeof(uint32)); + else if(tmp->flags & MDFNSTATE_RLSB16) + Endian_A16_LE_to_NE(tmp->v, expected_size / sizeof(uint16)); + else if(tmp->flags & RLSB) + Endian_V_LE_to_NE(tmp->v, expected_size); + } + } + else + { + printf("Unknown variable in save state: %s\n", toa + 1); + if(smem_seek(st, recorded_size, SEEK_CUR) < 0) + { + puts("Seek error"); + return(0); + } + } + } // while(...) + + for(SFMap_t::const_iterator it = sfmap.begin(); it != sfmap.end(); it++) + { + if(sfmap_found.find(it->second->name) == sfmap_found.end()) + { + printf("Variable missing from save state: %s\n", it->second->name); + } + } + + assert(smem_tell(st) == (temp + size)); + } + return 1; +} + +static int CurrentState = 0; +static int RecentlySavedState = -1; + +/* This function is called by the game driver(NES, GB, GBA) to save a state. */ +int MDFNSS_StateAction(StateMem *st, int load, int data_only, std::vector §ions) +{ + std::vector::iterator section; + + if(load) + { + if(data_only) + { + for(section = sections.begin(); section != sections.end(); section++) + { + ReadStateChunk(st, section->sf, ~0, 1); + } + } + else + { + char sname[32]; + + for(section = sections.begin(); section != sections.end(); section++) + { + int found = 0; + uint32 tmp_size; + uint32 total = 0; + + while(smem_read(st, (uint8 *)sname, 32) == 32) + { + if(smem_read32le(st, &tmp_size) != 4) + return(0); + + total += tmp_size + 32 + 4; + + // Yay, we found the section + if(!strncmp(sname, section->name, 32)) + { + if(!ReadStateChunk(st, section->sf, tmp_size, 0)) + { + printf("Error reading chunk: %s\n", section->name); + return(0); + } + found = 1; + break; + } + else + { + // puts("SEEK"); + if(smem_seek(st, tmp_size, SEEK_CUR) < 0) + { + puts("Chunk seek failure"); + return(0); + } + } + } + if(smem_seek(st, -total, SEEK_CUR) < 0) + { + puts("Reverse seek error"); + return(0); + } + if(!found && !section->optional) // Not found. We are sad! + { + printf("Section missing: %.32s\n", section->name); + return(0); + } + } + } + } + else + { + for(section = sections.begin(); section != sections.end(); section++) + { + if(!WriteStateChunk(st, section->name, section->sf, data_only)) + return(0); + } + } + + return(1); +} + +int MDFNSS_StateAction(StateMem *st, int load, int data_only, SFORMAT *sf, const char *name, bool optional) +{ + std::vector love; + + love.push_back(SSDescriptor(sf, name, optional)); + return(MDFNSS_StateAction(st, load, data_only, love)); +} + +//int MDFNSS_SaveSM(StateMem *st, int wantpreview_and_ts, int data_only, const MDFN_Surface *surface, const MDFN_Rect *DisplayRect, const int32 *LineWidths) +//{ +// static const char *header_magic = "MDFNSVST"; +// uint8 header[32]; +// int neowidth = 0, neoheight = 0; +// +// memset(header, 0, sizeof(header)); +// +// if(wantpreview_and_ts) +// { +// bool is_multires = false; +// +// // We'll want to use the nominal width if the source rectangle is > 25% off on either axis, or the source image has +// // multiple horizontal resolutions. +// neowidth = MDFNGameInfo->nominal_width; +// neoheight = MDFNGameInfo->nominal_height; +// +// if(LineWidths[0] != ~0) +// { +// uint32 first_w = LineWidths[DisplayRect->y]; +// +// for(int y = 0; y < DisplayRect->h; y++) +// if(LineWidths[DisplayRect->y + y] != first_w) +// { +// puts("Multires!"); +// is_multires = TRUE; +// } +// } +// +// if(!is_multires) +// { +// if(((double)DisplayRect->w / MDFNGameInfo->nominal_width) > 0.75 && ((double)DisplayRect->w / MDFNGameInfo->nominal_width) < 1.25) +// neowidth = DisplayRect->w; +// +// if(((double)DisplayRect->h / MDFNGameInfo->nominal_height) > 0.75 && ((double)DisplayRect->h / MDFNGameInfo->nominal_height) < 1.25) +// neoheight = DisplayRect->h; +// } +// } +// +// if(!data_only) +// { +// memcpy(header, header_magic, 8); +// +// if(wantpreview_and_ts) +// MDFN_en64lsb(header + 8, time(NULL)); +// +// MDFN_en32lsb(header + 16, MEDNAFEN_VERSION_NUMERIC); +// MDFN_en32lsb(header + 24, neowidth); +// MDFN_en32lsb(header + 28, neoheight); +// smem_write(st, header, 32); +// } +// +// if(wantpreview_and_ts) +// { +// uint8 *previewbuffer = (uint8 *)malloc(4 * neowidth * neoheight); +// MDFN_Surface *dest_surface = new MDFN_Surface((uint32 *)previewbuffer, neowidth, neoheight, neowidth, surface->format); +// MDFN_Rect dest_rect; +// +// dest_rect.x = 0; +// dest_rect.y = 0; +// dest_rect.w = neowidth; +// dest_rect.h = neoheight; +// +// MDFN_ResizeSurface(surface, DisplayRect, LineWidths, dest_surface, &dest_rect); +// +// { +// uint32 a, b = 0; +// for(a = 0; a < neowidth * neoheight * 4; a+=4) +// { +// uint32 c = *(uint32 *)&previewbuffer[a]; +// int nr, ng, nb; +// +// surface->DecodeColor(c, nr, ng, nb); +// +// previewbuffer[b + 0] = nr; +// previewbuffer[b + 1] = ng; +// previewbuffer[b + 2] = nb; +// b += 3; +// } +// } +// +// smem_write(st, previewbuffer, 3 * neowidth * neoheight); +// +// free(previewbuffer); +// delete dest_surface; +// } +// +// // State rewinding code path hack, FIXME +// if(data_only) +// { +// if(!MDFN_RawInputStateAction(st, 0, data_only)) +// return(0); +// } +// +// if(!MDFNGameInfo->StateAction(st, 0, data_only)) +// return(0); +// +// if(!data_only) +// { +// uint32 sizy = smem_tell(st); +// smem_seek(st, 16 + 4, SEEK_SET); +// smem_write32le(st, sizy); +// } +// return(1); +//} + +int MDFNSS_Save(const char *fname, const char *suffix, const MDFN_Surface *surface, const MDFN_Rect *DisplayRect, const int32 *LineWidths) +{ + StateMem st; + + memset(&st, 0, sizeof(StateMem)); + + + //if(!MDFNGameInfo->StateAction) + //{ + // MDFN_DispMessage(_("Module \"%s\" doesn't support save states."), MDFNGameInfo->shortname); + // return(0); + //} + + //if(!MDFNSS_SaveSM(&st, (DisplayRect && LineWidths), 0, surface, DisplayRect, LineWidths)) + //{ + // if(st.data) + // free(st.data); + // if(!fname && !suffix) + // MDFN_DispMessage(_("State %d save error."), CurrentState); + // return(0); + //} + + /*if(!MDFN_DumpToFile(fname ? fname : MDFN_MakeFName(MDFNMKF_STATE,CurrentState,suffix).c_str(), 6, st.data, st.len)) + { + SaveStateStatus[CurrentState] = 0; + free(st.data); + + if(!fname && !suffix) + MDFN_DispMessage(_("State %d save error."),CurrentState); + + return(0); + }*/ + + //free(st.data); + + //if(!fname && !suffix) + // MDFN_DispMessage(_("State %d saved."),CurrentState); + + return(1); +} +// +// +//int MDFNSS_LoadSM(StateMem *st, int haspreview, int data_only) +//{ +// uint8 header[32]; +// uint32 stateversion; +// +// if(data_only) +// { +// stateversion = MEDNAFEN_VERSION_NUMERIC; +// } +// else +// { +// smem_read(st, header, 32); +// +// if(memcmp(header, "MEDNAFENSVESTATE", 16) && memcmp(header, "MDFNSVST", 8)) +// return(0); +// +// stateversion = MDFN_de32lsb(header + 16); +// +// if((int)stateversion < 0x900) // Ensuring that (int)stateversion is > 0 is the most important part. +// return(0); +// +// if(haspreview) +// { +// uint32 width = MDFN_de32lsb(header + 24); +// uint32 height = MDFN_de32lsb(header + 28); +// uint32 psize; +// +// psize = width * height * 3; +// smem_seek(st, psize, SEEK_CUR); // Skip preview +// } +// } +// +// // State rewinding code path hack, FIXME +// if(data_only) +// { +// if(!MDFN_RawInputStateAction(st, stateversion, data_only)) +// return(0); +// } +// +// return(MDFNGameInfo->StateAction(st, stateversion, data_only)); +//} +// +//int MDFNSS_LoadFP(gzFile fp) +//{ +// uint8 header[32]; +// StateMem st; +// +// memset(&st, 0, sizeof(StateMem)); +// +// if(gzread(fp, header, 32) != 32) +// { +// return(0); +// } +// st.len = MDFN_de32lsb(header + 16 + 4); +// +// if(st.len < 32) +// return(0); +// +// if(!(st.data = (uint8 *)malloc(st.len))) +// return(0); +// +// memcpy(st.data, header, 32); +// if(gzread(fp, st.data + 32, st.len - 32) != ((int32)st.len - 32)) +// { +// free(st.data); +// return(0); +// } +// if(!MDFNSS_LoadSM(&st, 1, 0)) +// { +// free(st.data); +// return(0); +// } +// free(st.data); +// return(1); +//} + +int MDFNSS_Load(const char *fname, const char *suffix) +{ + //gzFile st; + + // if(!MDFNGameInfo->StateAction) + // { + // MDFN_DispMessage(_("Module \"%s\" doesn't support save states."), MDFNGameInfo->shortname); + // return(0); + // } + + // if(fname) + // st=gzopen(fname, "rb"); + // else + // { + // st=gzopen(MDFN_MakeFName(MDFNMKF_STATE,CurrentState,suffix).c_str(),"rb"); + //} + + //if(st == NULL) + //{ + // if(!fname && !suffix) + // { + // MDFN_DispMessage(_("State %d load error."),CurrentState); + // SaveStateStatus[CurrentState]=0; + // } + // return(0); + //} + + //if(MDFNSS_LoadFP(st)) + //{ + // if(!fname && !suffix) + // { + // SaveStateStatus[CurrentState]=1; + // MDFN_DispMessage(_("State %d loaded."),CurrentState); + // SaveStateStatus[CurrentState]=1; + // } + // gzclose(st); + // return(1); + // } + // else + // { + // SaveStateStatus[CurrentState]=1; + // MDFN_DispMessage(_("State %d read error!"),CurrentState); + // gzclose(st); + // return(0); + // } + + return 0; +} +// +//void MDFNSS_GetStateInfo(const char *filename, StateStatusStruct *status) +//{ +// gzFile fp; +// uint32 StateShowPBWidth; +// uint32 StateShowPBHeight; +// uint8 *previewbuffer = NULL; +// +// fp = gzopen(filename, "rb"); +// if(fp) +// { +// uint8 header[32]; +// +// gzread(fp, header, 32); +// uint32 width = MDFN_de32lsb(header + 24); +// uint32 height = MDFN_de32lsb(header + 28); +// +// if(width > 1024) width = 1024; +// if(height > 1024) height = 1024; +// +// if(!(previewbuffer = (uint8 *)MDFN_malloc(3 * width * height, _("Save state preview buffer")))) +// { +// StateShowPBWidth = 0; +// StateShowPBHeight = 0; +// } +// else +// { +// gzread(fp, previewbuffer, 3 * width * height); +// +// StateShowPBWidth = width; +// StateShowPBHeight = height; +// } +// gzclose(fp); +// } +// else +// { +// StateShowPBWidth = MDFNGameInfo->nominal_width; +// StateShowPBHeight = MDFNGameInfo->nominal_height; +// } +// +// status->gfx = previewbuffer; +// status->w = StateShowPBWidth; +// status->h = StateShowPBHeight; +//} + + +void MDFNI_SaveState(const char *fname, const char *suffix, const MDFN_Surface *surface, const MDFN_Rect *DisplayRect, const int32 *LineWidths) +{ + //if(!MDFNGameInfo->StateAction) + // return; + + //if(MDFNnetplay && (MDFNGameInfo->SaveStateAltersState == true)) + //{ + // char sb[256]; + // trio_snprintf(sb, sizeof(sb), _("Module %s is not compatible with manual state saving during netplay."), MDFNGameInfo->shortname); + // MDFND_NetplayText((const uint8*)sb, false); + // return; + //} + + MDFNSS_Save(fname, suffix, surface, DisplayRect, LineWidths); +} + +void MDFNI_LoadState(const char *fname, const char *suffix) +{ + //if(!MDFNGameInfo->StateAction) + // return; + + /* For network play and movies, be load the state locally, and then save the state to a temporary buffer, + and send or record that. This ensures that if an older state is loaded that is missing some + information expected in newer save states, desynchronization won't occur(at least not + from this ;)). + */ + if(MDFNSS_Load(fname, suffix)) + { + + } +} + diff --git a/psx/octoshock/state.h b/psx/octoshock/state.h new file mode 100644 index 0000000000..1dd1cd5864 --- /dev/null +++ b/psx/octoshock/state.h @@ -0,0 +1,145 @@ +#pragma once + +#include "octoshock.h" +#include "video/surface.h" +//#include "state-common.h" +#include + +//void MDFNSS_GetStateInfo(const char *filename, StateStatusStruct *status); + +int MDFNSS_Save(const char *, const char *suffix, const MDFN_Surface *surface = (MDFN_Surface *)NULL, const MDFN_Rect *DisplayRect = (MDFN_Rect*)NULL, const int32 *LineWidths = (int32*)NULL); +int MDFNSS_Load(const char *, const char *suffix); +int MDFNSS_SaveFP(FILE* fp, const MDFN_Surface *surface = (MDFN_Surface *)NULL, const MDFN_Rect *DisplayRect = (MDFN_Rect*)NULL, const int32 *LineWidths = (int32*)NULL); +int MDFNSS_LoadFP(FILE fp); + +typedef struct +{ + uint8 *data; + uint32 loc; + uint32 len; + + uint32 malloced; + + uint32 initial_malloc; // A setting! +} StateMem; + +// Eh, we abuse the smem_* in-memory stream code +// in a few other places. :) +int32 smem_read(StateMem *st, void *buffer, uint32 len); +int32 smem_write(StateMem *st, void *buffer, uint32 len); +int32 smem_putc(StateMem *st, int value); +int32 smem_tell(StateMem *st); +int32 smem_seek(StateMem *st, uint32 offset, int whence); +int smem_write32le(StateMem *st, uint32 b); +int smem_read32le(StateMem *st, uint32 *b); + +int MDFNSS_SaveSM(StateMem *st, int wantpreview_and_ts, int data_only, const MDFN_Surface *surface = (MDFN_Surface *)NULL, const MDFN_Rect *DisplayRect = (MDFN_Rect*)NULL, const int32 *LineWidths = (int32*)NULL); +int MDFNSS_LoadSM(StateMem *st, int haspreview, int data_only); + +void MDFNSS_CheckStates(void); + +// Flag for a single, >= 1 byte native-endian variable +#define MDFNSTATE_RLSB 0x80000000 + +// 32-bit native-endian elements +#define MDFNSTATE_RLSB32 0x40000000 + +// 16-bit native-endian elements +#define MDFNSTATE_RLSB16 0x20000000 + +// 64-bit native-endian elements +#define MDFNSTATE_RLSB64 0x10000000 + +#define MDFNSTATE_BOOL 0x08000000 + + +//// Array of structures +//#define MDFNSTATE_ARRAYOFS 0x04000000 + +typedef struct { + void *v; // Pointer to the variable/array + uint32 size; // Length, in bytes, of the data to be saved EXCEPT: + // In the case of MDFNSTATE_BOOL, it is the number of bool elements to save(bool is not always 1-byte). + // If 0, the subchunk isn't saved. + uint32 flags; // Flags + const char *name; // Name + //uint32 struct_size; // Only used for MDFNSTATE_ARRAYOFS, sizeof(struct) that members of the linked SFORMAT struct are in. +} SFORMAT; + +INLINE bool SF_IS_BOOL(bool *) { return(1); } +INLINE bool SF_IS_BOOL(void *) { return(0); } + +INLINE uint32 SF_FORCE_AB(bool *) { return(0); } + +INLINE uint32 SF_FORCE_A8(int8 *) { return(0); } +INLINE uint32 SF_FORCE_A8(uint8 *) { return(0); } + +INLINE uint32 SF_FORCE_A16(int16 *) { return(0); } +INLINE uint32 SF_FORCE_A16(uint16 *) { return(0); } + +INLINE uint32 SF_FORCE_A32(int32 *) { return(0); } +INLINE uint32 SF_FORCE_A32(uint32 *) { return(0); } + +INLINE uint32 SF_FORCE_A64(int64 *) { return(0); } +INLINE uint32 SF_FORCE_A64(uint64 *) { return(0); } + +INLINE uint32 SF_FORCE_D(double *) { return(0); } + +#define SFVARN(x, n) { &(x), SF_IS_BOOL(&(x)) ? 1U : (uint32)sizeof(x), MDFNSTATE_RLSB | (SF_IS_BOOL(&(x)) ? MDFNSTATE_BOOL : 0), n } +#define SFVAR(x) SFVARN((x), #x) + +#define SFARRAYN(x, l, n) { (x), (uint32)(l), 0 | SF_FORCE_A8(x), n } +#define SFARRAY(x, l) SFARRAYN((x), (l), #x) + +#define SFARRAYBN(x, l, n) { (x), (uint32)(l), MDFNSTATE_BOOL | SF_FORCE_AB(x), n } +#define SFARRAYB(x, l) SFARRAYBN((x), (l), #x) + +#define SFARRAY16N(x, l, n) { (x), (uint32)((l) * sizeof(uint16)), MDFNSTATE_RLSB16 | SF_FORCE_A16(x), n } +#define SFARRAY16(x, l) SFARRAY16N((x), (l), #x) + +#define SFARRAY32N(x, l, n) { (x), (uint32)((l) * sizeof(uint32)), MDFNSTATE_RLSB32 | SF_FORCE_A32(x), n } +#define SFARRAY32(x, l) SFARRAY32N((x), (l), #x) + +#define SFARRAY64N(x, l, n) { (x), (uint32)((l) * sizeof(uint64)), MDFNSTATE_RLSB64 | SF_FORCE_A64(x), n } +#define SFARRAY64(x, l) SFARRAY64N((x), (l), #x) + +#if SIZEOF_DOUBLE != 8 +#error "sizeof(double) != 8" +#endif + +#define SFARRAYDN(x, l, n) { (x), (uint32)((l) * 8), MDFNSTATE_RLSB64 | SF_FORCE_D(x), n } +#define SFARRAYD(x, l) SFARRAYDN((x), (l), #x) + +#define SFEND { 0, 0, 0, 0 } + +#include + +// State-Section Descriptor +class SSDescriptor +{ + public: + SSDescriptor(SFORMAT *n_sf, const char *n_name, bool n_optional = 0) + { + sf = n_sf; + name = n_name; + optional = n_optional; + } + ~SSDescriptor(void) + { + + } + + SFORMAT *sf; + const char *name; + bool optional; +}; + +int MDFNSS_StateAction(StateMem *st, int load, int data_only, std::vector §ions); +int MDFNSS_StateAction(StateMem *st, int load, int data_only, SFORMAT *sf, const char *name, bool optional = 0); + +void MDFN_StateEvilFlushMovieLove(void); +bool MDFN_StateEvilIsRunning(void); +void MDFN_StateEvilBegin(void); +void MDFN_StateEvilEnd(void); +int MDFN_StateEvil(int); + diff --git a/psx/octoshock/test/miniclient/miniclient.cpp b/psx/octoshock/test/miniclient/miniclient.cpp new file mode 100644 index 0000000000..f4c33ef4c4 --- /dev/null +++ b/psx/octoshock/test/miniclient/miniclient.cpp @@ -0,0 +1,330 @@ +#include + +#include "octoshock.h" +#include "psx/psx.h" + +// 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 +}; + +#ifndef __PACKED + #ifdef __GNUC__ + #define __PACKED __attribute__((__packed__)) + #else + #define __PACKED + #endif +#endif + +#ifndef __GNUC__ +#pragma pack(push, 1) +#pragma warning(disable : 4103) +#endif +struct bmpimgheader_struct +{ + u32 size; + s32 width; + s32 height; + u16 planes; + u16 bpp; + u32 cmptype; + u32 imgsize; + s32 hppm; + s32 vppm; + u32 numcol; + u32 numimpcol; +} ; +struct bmpfileheader_struct +{ + u16 id __PACKED; + u32 size __PACKED; + u16 reserved1 __PACKED; + u16 reserved2 __PACKED; + u32 imgoffset __PACKED; +}; +#ifndef __GNUC__ +#pragma pack(pop) +#endif + +int WriteBMP32(int width, int height, const void* buf, const char *filename) +{ + bmpfileheader_struct fileheader; + bmpimgheader_struct imageheader; + FILE *file; + size_t elems_written = 0; + memset(&fileheader, 0, sizeof(fileheader)); + fileheader.size = sizeof(fileheader); + fileheader.id = 'B' | ('M' << 8); + fileheader.imgoffset = sizeof(fileheader)+sizeof(imageheader); + + memset(&imageheader, 0, sizeof(imageheader)); + imageheader.size = sizeof(imageheader); + imageheader.width = width; + imageheader.height = height; + imageheader.planes = 1; + imageheader.bpp = 32; + imageheader.cmptype = 0; // None + imageheader.imgsize = imageheader.width * imageheader.height * 4; + + if ((file = fopen(filename,"wb")) == NULL) + return 0; + + elems_written += fwrite(&fileheader, 1, sizeof(fileheader), file); + elems_written += fwrite(&imageheader, 1, sizeof(imageheader), file); + + for(int i=0;iReadTOC(read_target, tracks); } + static s32 s_ReadLBA2448(void* opaque, s32 lba, void* dst) { return ((BinReader2352*)opaque)->ReadLBA2448(lba,dst); } + + ~BinReader2352() + { + fclose(inf); + shock_DestroyDisc(disc); + } + +private: + int lbaCount; + FILE* inf; + + + union Sector { + struct { + u8 sync[12]; + u8 adr[3]; + u8 mode; + union { + struct { + u8 data2048[2048]; + u8 ecc[4]; + u8 reserved[8]; + u8 ecm[276]; + }; + u8 data2336[2336]; + }; + }; + u8 buf[2352]; + }; + + union XASector { + struct { + u8 sync[12]; + u8 adr[3]; + u8 mode; + u8 subheader[8]; + union { + u8 data2048[2048]; + u8 ecc[4]; + u8 ecm[276]; + } form1; + union { + u8 data2334[2334]; + u8 ecc[4]; + } form2; + }; + u8 buf[2352]; + }; + + union { + XASector xasector; + Sector sector; + }; + + + s32 ReadTOC( ShockTOC *read_target, ShockTOCTrack tracks[100 + 1]) + { + memset(read_target,0,sizeof(*read_target)); + read_target->disc_type = 0; + read_target->first_track = 1; + read_target->last_track = 1; + tracks[1].adr = 1; + tracks[1].lba = 0; + tracks[1].control = 4; + tracks[2].adr = 1; + tracks[2].lba = lbaCount; + tracks[2].control = 0; + tracks[100].adr = 1; + tracks[100].lba = lbaCount; + tracks[100].control = 0; + return SHOCK_OK; + } + + s32 ReadLBA2448(s32 lba, void* dst) + { + fseek(inf,lba*2352,SEEK_SET); + fread(dst,1,2352,inf); + //do something for subcode I guess + memset((u8*)dst+2352,0,96); + hacky_MakeSubPQ(lba,(u8*)dst+2352,1,0); + + //not the right thing to do + //return ((Sector*)dst)->mode; + + return SHOCK_OK; + } + + uint8 U8_to_BCD(uint8 num) + { + return( ((num / 10) << 4) + (num % 10) ); + } + + 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 hacky_MakeSubPQ(int lba, u8* SubPWBuf, int track, int track_start) + { + uint8 buf[0xC]; + uint32 lba_relative; + uint32 ma, sa, fa; + uint32 m, s, f; + uint8 pause_or = 0x00; + + lba_relative = abs((int32)lba - track_start); + + 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 + + memset(buf, 0, 0xC); + buf[0] = (adr << 0) | (0x04 << 4); + buf[1] = U8_to_BCD(track); + + buf[2] = U8_to_BCD(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) | pause_or; + } + + +}; + +int main(int argc, char **argv) +{ + FILE* inf; + + //load up the firmware + char firmware[512*1024]; + inf = fopen("myfirmware.bin","rb"); + fread(firmware,1,512*1024,inf); + fclose(inf); + + BinReader2352 bin("mybin.bin"); + ShockDiscInfo info; + shock_AnalyzeDisc(bin.disc, &info); + printf("disc id: %s\n",info.id); + + //placeholder for instance + void* psx = NULL; + + shock_Create(&psx, REGION_NA, firmware); + shock_OpenTray(psx); + shock_SetDisc(psx,bin.disc); + shock_CloseTray(psx); + shock_PowerOn(psx); + + int framectr = 0; + for(;;) + { + printf("frame %d\n",framectr); + shock_Step(psx,eShockStep_Frame); + if(framectr%60==0) + { + //dump a screen grab + ShockFramebufferJob fbinfo; + static u32 buf[1024*1024]; + fbinfo.ptr = buf; + shock_GetFramebuffer(psx,&fbinfo); + char fname[128]; + sprintf(fname,"c:\\dump\\test%03d.bmp",framectr/60); + WriteBMP32(fbinfo.width,fbinfo.height,buf,fname); //rgb is backwards + } + + framectr++; + } +} \ No newline at end of file diff --git a/psx/octoshock/test/miniclient/miniclient.vcxproj b/psx/octoshock/test/miniclient/miniclient.vcxproj new file mode 100644 index 0000000000..68f488b82c --- /dev/null +++ b/psx/octoshock/test/miniclient/miniclient.vcxproj @@ -0,0 +1,91 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {5A0DAC84-1170-4B1A-B9A9-F566A1D97790} + Win32Proj + miniclient + + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + true + $(ProjectDir)\..\..\..\..\output\dll\ + + + false + $(ProjectDir)\..\..\..\..\output\dll\ + + + + + + Level3 + Disabled + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ..\..;..\..\emuware\msvc + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ..\..;..\..\emuware\msvc + + + Console + true + true + true + + + + + + + + {5f35cafc-6208-4fbe-ad17-0e69ba3f70ec} + + + + + + \ No newline at end of file diff --git a/psx/octoshock/test/miniclient/miniclient.vcxproj.filters b/psx/octoshock/test/miniclient/miniclient.vcxproj.filters new file mode 100644 index 0000000000..a5d3d63429 --- /dev/null +++ b/psx/octoshock/test/miniclient/miniclient.vcxproj.filters @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/psx/octoshock/video.h b/psx/octoshock/video.h new file mode 100644 index 0000000000..ed3f5def39 --- /dev/null +++ b/psx/octoshock/video.h @@ -0,0 +1,18 @@ +#ifndef __MDFN_VIDEO_H +#define __MDFN_VIDEO_H + +#include "video/surface.h" +//#include "video/primitives.h" +//#include "video/text.h" + +#include + +void MDFN_ResetMessages(void); +void MDFN_InitFontData(void); +void MDFN_DispMessage(const char *format, ...); + +int MDFN_InitVirtualVideo(void); +void MDFN_KillVirtualVideo(void); + + +#endif diff --git a/psx/octoshock/video/Deinterlacer.cpp b/psx/octoshock/video/Deinterlacer.cpp new file mode 100644 index 0000000000..13816ef07d --- /dev/null +++ b/psx/octoshock/video/Deinterlacer.cpp @@ -0,0 +1,211 @@ +/* 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 "video.h" + +#include "Deinterlacer.h" + +Deinterlacer::Deinterlacer() : FieldBuffer(NULL), StateValid(false), DeintType(DEINT_WEAVE) +{ + PrevDRect.x = 0; + PrevDRect.y = 0; + + PrevDRect.w = 0; + PrevDRect.h = 0; +} + +Deinterlacer::~Deinterlacer() +{ + if(FieldBuffer) + { + delete FieldBuffer; + FieldBuffer = NULL; + } +} + +void Deinterlacer::SetType(unsigned dt) +{ + if(DeintType != dt) + { + DeintType = dt; + + LWBuffer.resize(0); + if(FieldBuffer) + { + delete FieldBuffer; + FieldBuffer = NULL; + } + StateValid = false; + } +} + +template +void Deinterlacer::InternalProcess(MDFN_Surface *surface, MDFN_Rect &DisplayRect, int32 *LineWidths, const bool field) +{ + // + // We need to output with LineWidths as always being valid to handle the case of horizontal resolution change between fields + // while in interlace mode, so clear the first LineWidths entry if it's == ~0, and + // [...] + const bool LineWidths_In_Valid = (LineWidths[0] != ~0); + const bool WeaveGood = (StateValid && PrevDRect.h == DisplayRect.h && DeintType == DEINT_WEAVE); + // + // XReposition stuff is to prevent exceeding the dimensions of the video surface under certain conditions(weave deinterlacer, previous field has higher + // horizontal resolution than current field, and current field's rectangle has an x offset that's too large when taking into consideration the previous field's + // width; for simplicity, we don't check widths, but just assume that the previous field's maximum width is >= than the current field's maximum width). + // + const int32 XReposition = ((WeaveGood && DisplayRect.x > PrevDRect.x) ? DisplayRect.x : 0); + + //printf("%2d %2d, %d\n", DisplayRect.x, PrevDRect.x, XReposition); + + if(XReposition) + DisplayRect.x = 0; + + if(surface->h && !LineWidths_In_Valid) + { + LineWidths[0] = 0; + } + + for(int y = 0; y < DisplayRect.h / 2; y++) + { + // [...] + // set all relevant source line widths to the contents of DisplayRect(also simplifies the src_lw and related pointer calculation code + // farther below. + if(!LineWidths_In_Valid) + LineWidths[(y * 2) + field + DisplayRect.y] = DisplayRect.w; + + if(XReposition) + { + memmove(surface->pix() + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix, + surface->pix() + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix + XReposition, + LineWidths[(y * 2) + field + DisplayRect.y] * sizeof(T)); + } + + if(WeaveGood) + { + const T* src = FieldBuffer->pix() + y * FieldBuffer->pitchinpix; + T* dest = surface->pix() + ((y * 2) + (field ^ 1) + DisplayRect.y) * surface->pitchinpix + DisplayRect.x; + int32 *dest_lw = &LineWidths[(y * 2) + (field ^ 1) + DisplayRect.y]; + + *dest_lw = LWBuffer[y]; + + memcpy(dest, src, LWBuffer[y] * sizeof(T)); + } + else if(DeintType == DEINT_BOB) + { + const T* src = surface->pix() + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix + DisplayRect.x; + T* dest = surface->pix() + ((y * 2) + (field ^ 1) + DisplayRect.y) * surface->pitchinpix + DisplayRect.x; + const int32 *src_lw = &LineWidths[(y * 2) + field + DisplayRect.y]; + int32 *dest_lw = &LineWidths[(y * 2) + (field ^ 1) + DisplayRect.y]; + + *dest_lw = *src_lw; + + memcpy(dest, src, *src_lw * sizeof(T)); + } + else + { + const int32 *src_lw = &LineWidths[(y * 2) + field + DisplayRect.y]; + const T* src = surface->pix() + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix + DisplayRect.x; + const int32 dly = ((y * 2) + (field + 1) + DisplayRect.y); + T* dest = surface->pix() + dly * surface->pitchinpix + DisplayRect.x; + + if(y == 0 && field) + { + T black = surface->MakeColor(0, 0, 0); + T* dm2 = surface->pix() + (dly - 2) * surface->pitchinpix; + + LineWidths[dly - 2] = *src_lw; + + for(int x = 0; x < *src_lw; x++) + dm2[x] = black; + } + + if(dly < (DisplayRect.y + DisplayRect.h)) + { + LineWidths[dly] = *src_lw; + memcpy(dest, src, *src_lw * sizeof(T)); + } + } + + // + // + // + // + // + // + if(DeintType == DEINT_WEAVE) + { + const int32 *src_lw = &LineWidths[(y * 2) + field + DisplayRect.y]; + const T* src = surface->pix() + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix + DisplayRect.x; + T* dest = FieldBuffer->pix() + y * FieldBuffer->pitchinpix; + + memcpy(dest, src, *src_lw * sizeof(uint32)); + LWBuffer[y] = *src_lw; + + StateValid = true; + } + } +} + +void Deinterlacer::Process(MDFN_Surface *surface, MDFN_Rect &DisplayRect, int32 *LineWidths, const bool field) +{ + const MDFN_Rect DisplayRect_Original = DisplayRect; + + if(DeintType == DEINT_WEAVE) + { + if(!FieldBuffer || FieldBuffer->w < surface->w || FieldBuffer->h < (surface->h / 2)) + { + if(FieldBuffer) + delete FieldBuffer; + + FieldBuffer = new MDFN_Surface(NULL, surface->w, surface->h / 2, surface->w, surface->format); + LWBuffer.resize(FieldBuffer->h); + } + else if(memcmp(&surface->format, &FieldBuffer->format, sizeof(MDFN_PixelFormat))) + { + FieldBuffer->SetFormat(surface->format, StateValid && PrevDRect.h == DisplayRect.h); + } + } + + switch(surface->format.bpp) + { + case 8: + InternalProcess(surface, DisplayRect, LineWidths, field); + break; + + case 16: + InternalProcess(surface, DisplayRect, LineWidths, field); + break; + + case 32: + InternalProcess(surface, DisplayRect, LineWidths, field); + break; + } + + PrevDRect = DisplayRect_Original; +} + +void Deinterlacer::ClearState(void) +{ + StateValid = false; + + PrevDRect.x = 0; + PrevDRect.y = 0; + + PrevDRect.w = 0; + PrevDRect.h = 0; +} diff --git a/psx/octoshock/video/Deinterlacer.h b/psx/octoshock/video/Deinterlacer.h new file mode 100644 index 0000000000..7f7c6704c7 --- /dev/null +++ b/psx/octoshock/video/Deinterlacer.h @@ -0,0 +1,59 @@ +/* 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_DEINTERLACER_H +#define __MDFN_DEINTERLACER_H + +#include + +class Deinterlacer +{ + public: + + Deinterlacer(); + ~Deinterlacer(); + + enum + { + DEINT_BOB_OFFSET = 0, // Code will fall-through to this case under certain conditions, too. + DEINT_BOB, + DEINT_WEAVE, + }; + + void SetType(unsigned t); + inline unsigned GetType(void) + { + return(DeintType); + } + + void Process(MDFN_Surface *surface, MDFN_Rect &DisplayRect, int32 *LineWidths, const bool field); + + void ClearState(void); + + private: + + template + void InternalProcess(MDFN_Surface *surface, MDFN_Rect &DisplayRect, int32 *LineWidths, const bool field); + + MDFN_Surface *FieldBuffer; + std::vector LWBuffer; + bool StateValid; + MDFN_Rect PrevDRect; + unsigned DeintType; +}; + +#endif diff --git a/psx/octoshock/video/surface.cpp b/psx/octoshock/video/surface.cpp new file mode 100644 index 0000000000..8b2b247ccf --- /dev/null +++ b/psx/octoshock/video/surface.cpp @@ -0,0 +1,428 @@ +/* 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 "surface.h" + +MDFN_PixelFormat::MDFN_PixelFormat() +{ + bpp = 0; + colorspace = 0; + + Rshift = 0; + Gshift = 0; + Bshift = 0; + Ashift = 0; + + Rprec = 0; + Gprec = 0; + Bprec = 0; + Aprec = 0; +} + +MDFN_PixelFormat::MDFN_PixelFormat(const unsigned int p_colorspace, const uint8 p_rs, const uint8 p_gs, const uint8 p_bs, const uint8 p_as) +{ + bpp = 32; + colorspace = p_colorspace; + + Rshift = p_rs; + Gshift = p_gs; + Bshift = p_bs; + Ashift = p_as; + + Rprec = 8; + Gprec = 8; + Bprec = 8; + Aprec = 8; +} + +MDFN_Surface::MDFN_Surface() +{ + memset(&format, 0, sizeof(format)); + + pixels = NULL; + pixels8 = NULL; + pixels16 = NULL; + palette = NULL; + pixels_is_external = false; + pitchinpix = 0; + w = 0; + h = 0; +} + +MDFN_Surface::MDFN_Surface(void *const p_pixels, const uint32 p_width, const uint32 p_height, const uint32 p_pitchinpix, const MDFN_PixelFormat &nf, const bool alloc_init_pixels) +{ + Init(p_pixels, p_width, p_height, p_pitchinpix, nf, alloc_init_pixels); +} + +#if 0 +void MDFN_Surface::Resize(const uint32 p_width, const uint32 p_height, const uint32 p_pitchinpix) +{ + void *ptr = (format.bpp == 16) ? pixels16 : pixels; + uint64 old_asize = ((uint64)pitchinpix * (format.bpp >> 3)) * h; + uint64 new_asize = ((uint64)p_pitchinpix * (format.bpp >> 3)) * p_height; + + if(!(ptr = realloc(ptr, new_asize))) + throw MDFN_Error(ErrnoHolder(errno)); + + if(new_asize > old_asize) + memset((uint8*)ptr + old_asize, 0x00, new_asize - old_asize); + + if(format.bpp == 16) + pixels16 = (uint16*)ptr; + else + pixels = (uint32*)ptr; + + pitchinpix = p_pitchinpix; + w = p_width; + h = p_height; +} +#endif + +void MDFN_Surface::Init(void *const p_pixels, const uint32 p_width, const uint32 p_height, const uint32 p_pitchinpix, const MDFN_PixelFormat &nf, const bool alloc_init_pixels) +{ + void *rpix = NULL; + assert(nf.bpp == 8 || nf.bpp == 16 || nf.bpp == 32); + + format = nf; + + if(nf.bpp == 8) + { + //assert(!nf.Rshift && !nf.Gshift && !nf.Bshift && !nf.Ashift); + //assert(!nf.Rprec && !nf.Gprec && !nf.Bprec && !nf.Aprec); + } + else if(nf.bpp == 16) + { + assert(nf.Rprec && nf.Gprec && nf.Bprec && nf.Aprec); + } + else + { + assert((nf.Rshift + nf.Gshift + nf.Bshift + nf.Ashift) == 48); + assert(!((nf.Rshift | nf.Gshift | nf.Bshift | nf.Ashift) & 0x7)); + + format.Rprec = 8; + format.Gprec = 8; + format.Bprec = 8; + format.Aprec = 8; + } + + pixels16 = NULL; + pixels8 = NULL; + pixels = NULL; + palette = NULL; + + pixels_is_external = false; + + if(p_pixels) + { + rpix = p_pixels; + pixels_is_external = true; + } + else + { + if(alloc_init_pixels) + rpix = calloc(1, p_pitchinpix * p_height * (nf.bpp / 8)); + else + rpix = malloc(p_pitchinpix * p_height * (nf.bpp / 8)); + + if(!rpix) + { + //ErrnoHolder ene(errno); + + throw "OLD ERROR"; + //throw(MDFN_Error(ene.Errno(), "%s", ene.StrError())); + } + } + + if(nf.bpp == 8) + { + if(!(palette = (MDFN_PaletteEntry*) calloc(sizeof(MDFN_PaletteEntry), 256))) + { + //ErrnoHolder ene(errno); + + if(!pixels_is_external) + free(rpix); + + throw "OLD ERROR"; + //throw(MDFN_Error(ene.Errno(), "%s", ene.StrError())); + } + } + + if(nf.bpp == 16) + pixels16 = (uint16 *)rpix; + else if(nf.bpp == 8) + pixels8 = (uint8 *)rpix; + else + pixels = (uint32 *)rpix; + + w = p_width; + h = p_height; + + pitchinpix = p_pitchinpix; +} + +// When we're converting, only convert the w*h area(AKA leave the last part of the line, pitch32 - w, alone), +// for places where we store auxillary information there(graphics viewer in the debugger), and it'll be faster +// to boot. +void MDFN_Surface::SetFormat(const MDFN_PixelFormat &nf, bool convert) +{ + if(format.bpp != 32 || nf.bpp != 32) + printf("%u->%u\n",format.bpp, nf.bpp); + + assert(format.bpp == 8 || format.bpp == 16 || format.bpp == 32); + assert((nf.bpp == 8 && !convert) || nf.bpp == 16 || nf.bpp == 32); + + if(nf.bpp == 8) + { + + } + else if(nf.bpp == 16) + { + + } + else + { + assert((nf.Rshift + nf.Gshift + nf.Bshift + nf.Ashift) == 48); + assert(!((nf.Rshift | nf.Gshift | nf.Bshift | nf.Ashift) & 0x7)); + } + + if(nf.bpp != format.bpp) + { + void *rpix = calloc(1, pitchinpix * h * (nf.bpp / 8)); + void *oldpix; + + if(nf.bpp == 8) + { + assert(!convert); + + pixels8 = (uint8 *)rpix; + palette = (MDFN_PaletteEntry*)calloc(sizeof(MDFN_PaletteEntry), 256); + } + else if(nf.bpp == 16) // 32bpp or 8bpp to 16bpp + { + pixels16 = (uint16 *)rpix; + + if(convert) + { + if(format.bpp == 8) + { + puts("8bpp to 16bpp convert"); + for(int y = 0; y < h; y++) + { + uint8 *srow = &pixels8[y * pitchinpix]; + uint16 *drow = &pixels16[y * pitchinpix]; + + for(int x = 0; x < w; x++) + { + const MDFN_PaletteEntry &p = palette[srow[x]]; + + drow[x] = nf.MakeColor(p.r, p.g, p.b, 0); + } + } + } + else + { + puts("32bpp to 16bpp convert"); + for(int y = 0; y < h; y++) + { + uint32 *srow = &pixels[y * pitchinpix]; + uint16 *drow = &pixels16[y * pitchinpix]; + + for(int x = 0; x < w; x++) + { + uint32 c = srow[x]; + int r, g, b, a; + + DecodeColor(c, r, g, b, a); + drow[x] = nf.MakeColor(r, g, b, a); + } + } + } + } + } + else // 16bpp or 8bpp to 32bpp + { + pixels = (uint32 *)rpix; + + if(convert) + { + if(format.bpp == 8) + { + puts("8bpp to 32bpp convert"); + for(int y = 0; y < h; y++) + { + uint8 *srow = &pixels8[y * pitchinpix]; + uint32 *drow = &pixels[y * pitchinpix]; + + for(int x = 0; x < w; x++) + { + const MDFN_PaletteEntry &p = palette[srow[x]]; + + drow[x] = nf.MakeColor(p.r, p.g, p.b, 0); + } + } + } + else + { + puts("16bpp to 32bpp convert"); + for(int y = 0; y < h; y++) + { + uint16 *srow = &pixels16[y * pitchinpix]; + uint32 *drow = &pixels[y * pitchinpix]; + + for(int x = 0; x < w; x++) + { + uint32 c = srow[x]; + int r, g, b, a; + + DecodeColor(c, r, g, b, a); + drow[x] = nf.MakeColor(r, g, b, a); + } + } + } + } + } + + switch(format.bpp) + { + default: + + case 32: oldpix = pixels; + pixels = NULL; + break; + + case 16: oldpix = pixels16; + pixels16 = NULL; + break; + + case 8: oldpix = pixels8; + pixels8 = NULL; + if(palette) + { + free(palette); + palette = NULL; + } + break; + } + + if(oldpix && !pixels_is_external) + free(oldpix); + + pixels_is_external = false; + + // We already handled surface conversion above. + convert = false; + } + + if(convert) + { + if(format.bpp == 16) + { + // We should assert that surface->pixels is non-NULL even if we don't need to convert the surface, to catch more insidious bugs. + assert(pixels16); + + if(memcmp(&format, &nf, sizeof(MDFN_PixelFormat))) + { + //puts("Converting"); + for(int y = 0; y < h; y++) + { + uint16 *row = &pixels16[y * pitchinpix]; + + for(int x = 0; x < w; x++) + { + uint32 c = row[x]; + int r, g, b, a; + + DecodeColor(c, r, g, b, a); + row[x] = nf.MakeColor(r, g, b, a); + } + } + } + } + else + { + // We should assert that surface->pixels is non-NULL even if we don't need to convert the surface, to catch more insidious bugs. + assert(pixels); + + if(memcmp(&format, &nf, sizeof(MDFN_PixelFormat))) + { + //puts("Converting"); + for(int y = 0; y < h; y++) + { + uint32 *row = &pixels[y * pitchinpix]; + + for(int x = 0; x < w; x++) + { + uint32 c = row[x]; + int r, g, b, a; + + DecodeColor(c, r, g, b, a); + row[x] = nf.MakeColor(r, g, b, a); + } + } + } + } + } + format = nf; +} + +void MDFN_Surface::Fill(uint8 r, uint8 g, uint8 b, uint8 a) +{ + uint32 color = MakeColor(r, g, b, a); + + if(format.bpp == 8) + { + assert(pixels8); + + for(int32 i = 0; i < pitchinpix * h; i++) + pixels8[i] = color; + } + else if(format.bpp == 16) + { + assert(pixels16); + + for(int32 i = 0; i < pitchinpix * h; i++) + pixels16[i] = color; + } + else + { + assert(pixels); + + for(int32 i = 0; i < pitchinpix * h; i++) + pixels[i] = color; + } +} + +MDFN_Surface::~MDFN_Surface() +{ + if(!pixels_is_external) + { + if(pixels) + free(pixels); + if(pixels16) + free(pixels16); + if(pixels8) + free(pixels8); + if(palette) + free(palette); + } +} diff --git a/psx/octoshock/video/surface.h b/psx/octoshock/video/surface.h new file mode 100644 index 0000000000..e6fbe0e149 --- /dev/null +++ b/psx/octoshock/video/surface.h @@ -0,0 +1,227 @@ +#ifndef __MDFN_SURFACE_H +#define __MDFN_SURFACE_H + +struct MDFN_Rect +{ + int32 x, y, w, h; +}; + +enum +{ + MDFN_COLORSPACE_RGB = 0, + MDFN_COLORSPACE_YCbCr = 1, + //MDFN_COLORSPACE_YUV = 2, // TODO, maybe. +}; + +class MDFN_PixelFormat +{ + public: + + MDFN_PixelFormat(); + MDFN_PixelFormat(const unsigned int p_colorspace, const uint8 p_rs, const uint8 p_gs, const uint8 p_bs, const uint8 p_as); + + unsigned int bpp; // 32 only for now(16 and 8 wip) + unsigned int colorspace; + + union + { + uint8 Rshift; // Bit position of the lowest bit of the red component + uint8 Yshift; + }; + + union + { + uint8 Gshift; // [...] green component + uint8 Ushift; + uint8 Cbshift; + }; + + union + { + uint8 Bshift; // [...] blue component + uint8 Vshift; + uint8 Crshift; + }; + + uint8 Ashift; // [...] alpha component. + + // For 16bpp, WIP + uint8 Rprec; + uint8 Gprec; + uint8 Bprec; + uint8 Aprec; + + // Creates a color value for the surface corresponding to the 8-bit R/G/B/A color passed. + INLINE uint32 MakeColor(uint8 r, uint8 g, uint8 b, uint8 a = 0) const + { + if(colorspace == MDFN_COLORSPACE_YCbCr) + { + uint32 y, u, v; + + y = 16 + ((r * 16842 + g * 33030 + b * 6422) >> 16); + u = 128 + ((r * -9699 + g * -19071 + b * 28770) >> 16); + v = 128 + ((r * 28770 + g * -24117 + b * -4653) >> 16); + + return((y << Yshift) | (u << Ushift) | (v << Vshift) | (a << Ashift)); + } + else + { + if(bpp == 16) + { + uint32 ret = 0; +/* + ret |= std::min(((r * ((1 << Rprec) - 1) + 127) / 255), 255) << Rshift; + ret |= std::min(((g * ((1 << Gprec) - 1) + 127) / 255), 255) << Gshift; + ret |= std::min(((b * ((1 << Bprec) - 1) + 127) / 255), 255) << Bshift; + ret |= std::min(((a * ((1 << Aprec) - 1) + 127) / 255), 255) << Ashift; +*/ + ret |= ((r * ((1 << Rprec) - 1) + 127) / 255) << Rshift; + ret |= ((g * ((1 << Gprec) - 1) + 127) / 255) << Gshift; + ret |= ((b * ((1 << Bprec) - 1) + 127) / 255) << Bshift; + ret |= ((a * ((1 << Aprec) - 1) + 127) / 255) << Ashift; + return(ret); + } + else + return((r << Rshift) | (g << Gshift) | (b << Bshift) | (a << Ashift)); + } + } + + // Gets the R/G/B/A values for the passed 32-bit surface pixel value + INLINE void DecodeColor(uint32 value, int &r, int &g, int &b, int &a) const + { + if(colorspace == MDFN_COLORSPACE_YCbCr) + { + int32 y = (value >> Yshift) & 0xFF; + int32 cb = (value >> Cbshift) & 0xFF; + int32 cr = (value >> Crshift) & 0xFF; + + int32 r_tmp, g_tmp, b_tmp; + + r_tmp = g_tmp = b_tmp = 76284 * (y - 16); + + r_tmp = r_tmp + 104595 * (cr - 128); + g_tmp = g_tmp - 53281 * (cr - 128) - 25690 * (cb - 128); + b_tmp = b_tmp + 132186 * (cb - 128); + + r_tmp >>= 16; + g_tmp >>= 16; + b_tmp >>= 16; + + if(r_tmp < 0) r_tmp = 0; + if(r_tmp > 255) r_tmp = 255; + + if(g_tmp < 0) g_tmp = 0; + if(g_tmp > 255) g_tmp = 255; + + if(b_tmp < 0) b_tmp = 0; + if(b_tmp > 255) b_tmp = 255; + + r = r_tmp; + g = g_tmp; + b = b_tmp; + + a = (value >> Ashift) & 0xFF; + } + else + { + if(bpp == 16) + { + r = ((value >> Rshift) & ((1 << Rprec) - 1)) * 255 / ((1 << Rprec) - 1); + g = ((value >> Gshift) & ((1 << Gprec) - 1)) * 255 / ((1 << Gprec) - 1); + b = ((value >> Bshift) & ((1 << Bprec) - 1)) * 255 / ((1 << Bprec) - 1); + a = ((value >> Ashift) & ((1 << Aprec) - 1)) * 255 / ((1 << Aprec) - 1); + } + else + { + r = (value >> Rshift) & 0xFF; + g = (value >> Gshift) & 0xFF; + b = (value >> Bshift) & 0xFF; + a = (value >> Ashift) & 0xFF; + } + } + } + + INLINE void DecodeColor(uint32 value, int &r, int &g, int &b) const + { + int dummy_a; + + DecodeColor(value, r, g, b, dummy_a); + } +}; // MDFN_PixelFormat; + +struct MDFN_PaletteEntry +{ + uint8 r, g, b; +}; + +// Supports 32-bit RGBA +// 16-bit is WIP +// 8-bit is even WIPier. +class MDFN_Surface //typedef struct +{ + public: + + MDFN_Surface(); + MDFN_Surface(void *const p_pixels, const uint32 p_width, const uint32 p_height, const uint32 p_pitchinpix, const MDFN_PixelFormat &nf, const bool alloc_init_pixels = true); + + ~MDFN_Surface(); + + uint8 *pixels8; + uint16 *pixels16; + uint32 *pixels; + + template + T* pix(void) + { + if(sizeof(T) == 1) + return (T*)pixels8; + else if(sizeof(T) == 2) + return (T*)pixels16; + else if(sizeof(T) == 4) + return (T*)pixels; + else + return NULL; + } + + MDFN_PaletteEntry *palette; + + bool pixels_is_external; + + // w, h, and pitch32 should always be > 0 + int32 w; + int32 h; + + union + { + int32 pitch32; // In pixels, not in bytes. + int32 pitchinpix; // New name, new code should use this. + }; + + MDFN_PixelFormat format; + + void Fill(uint8 r, uint8 g, uint8 b, uint8 a); + void SetFormat(const MDFN_PixelFormat &new_format, bool convert); + + // Creates a 32-bit value for the surface corresponding to the R/G/B/A color passed. + INLINE uint32 MakeColor(uint8 r, uint8 g, uint8 b, uint8 a = 0) const + { + return(format.MakeColor(r, g, b, a)); + } + + // Gets the R/G/B/A values for the passed 32-bit surface pixel value + INLINE void DecodeColor(uint32 value, int &r, int &g, int &b, int &a) const + { + format.DecodeColor(value, r, g, b, a); + } + + INLINE void DecodeColor(uint32 value, int &r, int &g, int &b) const + { + int dummy_a; + + DecodeColor(value, r, g, b, dummy_a); + } + private: + void Init(void *const p_pixels, const uint32 p_width, const uint32 p_height, const uint32 p_pitchinpix, const MDFN_PixelFormat &nf, const bool alloc_init_pixels); +}; + +#endif diff --git a/psx/octoshock/video/video-common.h b/psx/octoshock/video/video-common.h new file mode 100644 index 0000000000..e69de29bb2