unmanaged core experiment

This commit is contained in:
zeromus 2011-07-24 06:45:05 +00:00
parent c30529685d
commit 8a1e0c2b09
21 changed files with 1730 additions and 57 deletions

View File

@ -190,6 +190,9 @@
<Compile Include="Disc\FFmpeg.cs" />
<Compile Include="Disc\Subcode.cs" />
<Compile Include="Disc\TOC_format.cs" />
<Compile Include="ExternalCores\EmuFile.cs" />
<Compile Include="ExternalCores\ExternalCore.cs" />
<Compile Include="ExternalCores\PsxCore.cs" />
<Compile Include="Interfaces\Base Implementations\Game.cs" />
<Compile Include="Interfaces\Base Implementations\IPS.cs" />
<Compile Include="Interfaces\Base Implementations\Movies.cs" />
@ -241,6 +244,7 @@
<Content Include="Consoles\Nintendo\Docs\test_status.txt" />
<Content Include="Consoles\PC Engine\Compat.txt" />
<Content Include="Consoles\Sega\SMS\Compat.txt" />
<Content Include="ExternalCores\Snippets.txt" />
<Content Include="Notes.txt" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />

View File

@ -0,0 +1,110 @@
using System;
using System.Security;
using System.Runtime.InteropServices;
using System.Linq;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Reflection.Emit;
using System.Threading;
namespace BizHawk
{
public class EmuFile : ExternalCore
{
public EmuFile(IExternalCoreAccessor accessor)
: base(accessor)
{
UnmanagedOpaque = QueryCoreCall<Func<IntPtr, IntPtr>>("EmuFile.Construct")(ManagedOpaque);
QueryCoreCall<Action<string, IntPtr>>("EmuFile.Set_fp")("fgetc", ExportDelegate(new fgetcDelegate(fgetc)));
QueryCoreCall<Action<string, IntPtr>>("EmuFile.Set_fp")("fread", ExportDelegate(new freadDelegate(fread)));
QueryCoreCall<Action<string, IntPtr>>("EmuFile.Set_fp")("fwrite", ExportDelegate(new fwriteDelegate(fwrite)));
QueryCoreCall<Action<string, IntPtr>>("EmuFile.Set_fp")("fseek", ExportDelegate(new fseekDelegate(fseek)));
QueryCoreCall<Action<string, IntPtr>>("EmuFile.Set_fp")("ftell", ExportDelegate(new ftellDelegate(ftell)));
QueryCoreCall<Action<string, IntPtr>>("EmuFile.Set_fp")("size", ExportDelegate(new sizeDelegate(size)));
QueryCoreCall<Action<string, IntPtr>>("EmuFile.Set_fp")("size", ExportDelegate(new sizeDelegate(size)));
}
public Stream BaseStream { get; set; }
//do we want to have a finalizer? not sure.
bool disposed = false;
public override void Dispose()
{
if (disposed) return;
disposed = true;
//we will call Delete in the c++ side, which will delete the object, and cause Dispose() to get called.
//but, Dispose() can never be called again due to setting the flag above
QueryCoreCall<Action>("EmuFile.Delete")();
//do we always want to do this? not sure. but usually.
BaseStream.Dispose();
base.Dispose();
}
int fgetc()
{
return BaseStream.ReadByte();
}
IntPtr fread(
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
byte[] ptr,
IntPtr bytes)
{
long len = bytes.ToInt64();
if (len >= int.MaxValue || len < 0) throw new ArgumentException();
int ret = BaseStream.Read(ptr, 0, (int)len);
return new IntPtr(ret);
}
IntPtr fseek(IntPtr offset, IntPtr origin)
{
SeekOrigin so = (SeekOrigin)origin.ToInt32();
long loffset = offset.ToInt64();
return new IntPtr(BaseStream.Seek(loffset, so));
}
IntPtr ftell() { return new IntPtr(BaseStream.Position); }
IntPtr size() { return new IntPtr(BaseStream.Length); }
void fwrite(
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
byte[] ptr,
IntPtr bytes)
{
long len = bytes.ToInt64();
if (len >= int.MaxValue || len < 0) throw new ArgumentException();
BaseStream.Write(ptr, 0, (int)len);
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int fgetcDelegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void disposeDelegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate IntPtr freadDelegate(
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
byte[] ptr,
IntPtr bytes);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void fwriteDelegate(
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
byte[] ptr,
IntPtr bytes);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate IntPtr fseekDelegate(IntPtr offset, IntPtr origin);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate IntPtr ftellDelegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate IntPtr sizeDelegate();
}
}

View File

@ -0,0 +1,237 @@
using System;
using System.Security;
using System.Threading;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using System.Linq;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Collections.Generic;
namespace BizHawk
{
/// <summary>
/// universal interface to a shared library
/// </summary>
public interface ILibAccessor : IDisposable
{
IntPtr GetProcAddress(string name);
bool IsOpen { get; }
}
/// <summary>
/// universal access to an external emulator core
/// </summary>
public interface IExternalCoreAccessor : IDisposable
{
IntPtr Signal(string type, IntPtr obj, string param, IntPtr value);
bool IsOpen { get; }
void RegisterCore(ExternalCore core, bool register);
}
public class CoreAccessor : IExternalCoreAccessor
{
ILibAccessor mLibAccessor;
public CoreAccessor(ILibAccessor accessor)
{
mLibAccessor = accessor;
if (accessor.IsOpen)
{
mSignal = (SignalCallbackDelegate)Marshal.GetDelegateForFunctionPointer(accessor.GetProcAddress("Core_signal"), typeof(SignalCallbackDelegate));
IsOpen = true;
}
}
public void RegisterCore(ExternalCore core, bool register)
{
if (core is StaticCoreCommon) return;
//defer initialization until the core is needed, to avoid pointless costs for cores the user isnt using
if (!IsInitialized)
{
IsInitialized = true;
scc = new StaticCoreCommon(this);
scc.RegisterClientSignal(new SignalCallbackDelegate(ClientSignal));
scc.Initialize();
}
if (register)
{
}
else
{
//delete
}
}
StaticCoreCommon scc;
public void Dispose()
{
if (mLibAccessor == null) return;
scc.Dispose();
mLibAccessor.Dispose();
mLibAccessor = null;
IsOpen = false;
}
public bool IsOpen { get; private set; }
bool IsInitialized;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate IntPtr SignalCallbackDelegate(string type, IntPtr obj, string param, IntPtr value);
SignalCallbackDelegate mSignal;
//external cores call into the client from here
public IntPtr ClientSignal(string type, IntPtr obj, string param, IntPtr value)
{
//static calls
if (obj == IntPtr.Zero)
{
return scc.ClientSignal(type, obj, param, value);
}
else return IntPtr.Zero;
}
public IntPtr Signal(string type, IntPtr obj, string param, IntPtr value)
{
if (!IsOpen) throw new InvalidOperationException("core accessor is open");
return mSignal(type, obj, param, value);
}
}
//todo - make abstract
public class ExternalCore : IDisposable
{
//rename to managed and unmanaged
public IntPtr ManagedOpaque;
public IntPtr UnmanagedOpaque;
static int _ManagedOpaque_Counter = 1;
protected IExternalCoreAccessor mAccessor;
public ExternalCore(IExternalCoreAccessor accessor)
{
mAccessor = accessor;
mAccessor.RegisterCore(this,true);
lock (this)
{
ManagedOpaque = new IntPtr(_ManagedOpaque_Counter);
_ManagedOpaque_Counter++;
}
}
public virtual void Dispose()
{
mAccessor.RegisterCore(this, false);
//universal delete mechanism?
//probably not.
}
/// <summary>
/// cores call into the client from here. this system is not fully baked yet, though
/// </summary>
virtual public IntPtr ClientSignal(string type, IntPtr obj, string param, IntPtr value)
{
return IntPtr.Zero;
}
/// <summary>
/// merely emits an integer of the current system int size to an ILGenerator
/// </summary>
static void EmitIntPtr(ILGenerator gen, IntPtr val)
{
if (IntPtr.Size == 4) gen.Emit(OpCodes.Ldc_I4, val.ToInt32());
else gen.Emit(OpCodes.Ldc_I8, val.ToInt64());
}
/// <summary>
/// retrieves a function pointer from the core and returns it as the specified delegate type
/// </summary>
protected void QueryCoreCall<T>(out T del, string name)
{
del = QueryCoreCall<T>(name);
}
/// <summary>
/// retrieves a function pointer from the core and returns it as the specified delegate type
/// </summary>
protected T QueryCoreCall<T>(string name)
{
MethodInfo mi = typeof(T).GetMethod("Invoke");
ParameterInfo[] pis = mi.GetParameters();
Type[] unmanagedParamTypes = new Type[pis.Length + 1];
Type[] managedParamTypes = new Type[pis.Length];
unmanagedParamTypes[0] = typeof(int);
for (int i = 0; i < pis.Length; i++)
{
unmanagedParamTypes[i + 1] = pis[i].ParameterType;
managedParamTypes[i] = pis[i].ParameterType;
}
IntPtr fptr = mAccessor.Signal("QUERY_FUNCTION", IntPtr.Zero, name, IntPtr.Zero);
if (fptr == IntPtr.Zero)
throw new InvalidOperationException("external core was missing requested function: " + name);
DynamicMethod dm = new DynamicMethod("", mi.ReturnType, managedParamTypes, GetType().Module);
ILGenerator gen = dm.GetILGenerator();
EmitIntPtr(gen, UnmanagedOpaque);
for (int i = 0; i < pis.Length; i++) gen.Emit(OpCodes.Ldarg, i);
EmitIntPtr(gen, fptr);
gen.EmitCalli(OpCodes.Calli, CallingConvention.ThisCall, mi.ReturnType, unmanagedParamTypes);
gen.Emit(OpCodes.Ret);
Delegate d = dm.CreateDelegate(typeof(T));
return (T)(object)d;
}
/// <summary>
/// exports a delegate as an IntPtr for use in unmanaged code and manages its life cycle to keep it from getting freed
/// </summary>
protected IntPtr ExportDelegate(Delegate d)
{
IntPtr retPtr = Marshal.GetFunctionPointerForDelegate(d);
listLiveDelegates.Add(d);
return retPtr;
}
//need to hold on to these callbacks to make sure they dont get GCed while unmanaged code has a pointer to them
List<Delegate> listLiveDelegates = new List<Delegate>();
}
public class StaticCoreCommon : ExternalCore
{
//keep in mind that we may need to make the console thread safe if we ever do any zany multithreaded things
public StaticCoreCommon(IExternalCoreAccessor accessor)
: base(accessor)
{
}
EmuFile Console;
public void Initialize()
{
Console = new EmuFile(mAccessor);
if (Log.HACK_LOG_STREAM != null)
Console.BaseStream = Log.HACK_LOG_STREAM;
else
Console.BaseStream = System.Console.OpenStandardOutput();
mAccessor.Signal("SET_CONSOLE", IntPtr.Zero, null, Console.UnmanagedOpaque);
}
public void RegisterClientSignal(CoreAccessor.SignalCallbackDelegate ClientSignal)
{
mAccessor.Signal("SET_CLIENT_SIGNAL", IntPtr.Zero, null, ExportDelegate(ClientSignal));
}
}
}

View File

@ -0,0 +1,80 @@
using System;
using System.Runtime.InteropServices;
using System.Linq;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Collections.Generic;
namespace BizHawk
{
public class PsxCore : ExternalCore, IEmulator, IVideoProvider, ISoundProvider
{
public PsxCore(IExternalCoreAccessor accessor)
: base(accessor)
{
var domains = new List<MemoryDomain>(1);
memoryDomains = domains.AsReadOnly();
CoreOutputComm = new CoreOutputComm();
CoreInputComm = new CoreInputComm();
UnmanagedOpaque = QueryCoreCall<Func<IntPtr,IntPtr>>("PsxCore.Construct")(ManagedOpaque);
QueryCoreCall(out cGetResolution, "PsxCore.GetResolution");
QueryCoreCall(out cUpdateVideoBuffer, "PsxCore.UpdateVideoBuffer");
QueryCoreCall(out cFrameAdvance, "PsxCore.FrameAdvance");
}
Func<System.Drawing.Size> cGetResolution;
Action cFrameAdvance;
Action<IntPtr> cUpdateVideoBuffer;
//video provider
int[] videoBuffer = new int[256 * 256];
public int[] GetVideoBuffer() { return videoBuffer; }
public int BufferWidth { get { return 256; } }
public int BufferHeight { get { return 192; } }
public int BackgroundColor { get { return 0; } }
public string SystemId { get { return "PSX"; } }
public static readonly ControllerDefinition NullController = new ControllerDefinition { Name = "Null Controller" };
private Random rand = new Random();
public CoreInputComm CoreInputComm { get; set; }
public CoreOutputComm CoreOutputComm { get; private set; }
public IVideoProvider VideoProvider { get { return this; } }
public ISoundProvider SoundProvider { get { return this; } }
public void LoadGame(IGame game) { }
public unsafe void FrameAdvance(bool render)
{
//if (render == false) return;
cFrameAdvance();
fixed (int* vidbuf = &videoBuffer[0])
cUpdateVideoBuffer(new IntPtr(vidbuf));
}
public ControllerDefinition ControllerDefinition { get { return NullController; } }
public IController Controller { get; set; }
public int Frame { get; set; }
public int LagCount { get { return 0; } set { return; } }
public bool IsLagFrame { get { return false; } }
public byte[] SaveRam { get { return new byte[0]; } }
public bool DeterministicEmulation { get; set; }
public bool SaveRamModified { get; set; }
public void SaveStateText(TextWriter writer) { }
public void LoadStateText(TextReader reader) { }
public void SaveStateBinary(BinaryWriter writer) { }
public void LoadStateBinary(BinaryReader reader) { }
public byte[] SaveStateBinary() { return new byte[1]; }
public void GetSamples(short[] samples) { }
public void DiscardSamples() { }
private IList<MemoryDomain> memoryDomains;
public IList<MemoryDomain> MemoryDomains { get { return memoryDomains; } }
public MemoryDomain MainMemory { get { return memoryDomains[0]; } }
public void Dispose() { }
}
}

View File

@ -0,0 +1,103 @@
////////////////////////////
//we can't use these because we need more clever control over the delegate type (marshalling attributes, for one thing)
Delegate MyMakeDelegate(string methodName)
{
MethodInfo mi = GetType().GetMethod(methodName,BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
var parameters = mi.GetParameters()
.Select(p => p.ParameterType)
.ToArray();
Type t = DelegateCreator.MakeNewCustomDelegate(mi.ReturnType, parameters);
return Delegate.CreateDelegate(t, this, mi);
}
static class DelegateCreator
{
public static Type MakeNewCustomDelegate(Type ret_type, Type[] argtypes)
{
var _DelegateCtorSignature = new Type[] { typeof(object), typeof(IntPtr) };
Type returnType = ret_type;
Type[] parameterTypes = argtypes;
TypeBuilder builder = DefineDelegateType("Delegate" + argtypes.Length);
builder.DefineConstructor(MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public, CallingConventions.Standard, _DelegateCtorSignature).SetImplementationFlags(MethodImplAttributes.CodeTypeMask);
builder.DefineMethod("Invoke", MethodAttributes.VtableLayoutMask | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Public, returnType, parameterTypes).SetImplementationFlags(MethodImplAttributes.CodeTypeMask);
//[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
//builder.SetCustomAttribute(new CustomAttributeBuilder(new ConstructorInfo(
ConstructorInfo ci = typeof(UnmanagedFunctionPointerAttribute).GetConstructor(new[] { typeof(CallingConvention) });
CustomAttributeBuilder cab = new CustomAttributeBuilder(ci, new object[] { CallingConvention.ThisCall });
builder.SetCustomAttribute(cab);
return builder.CreateType();
}
internal static TypeBuilder DefineDelegateType(string name)
{
return DefineType(name, typeof(MulticastDelegate), TypeAttributes.AutoClass | TypeAttributes.Sealed | TypeAttributes.Public);
}
static int _index;
private static TypeBuilder DefineType(string name, Type parent, TypeAttributes attr)
{
StringBuilder builder = new StringBuilder(name);
int num = Interlocked.Increment(ref _index);
builder.Append("$");
builder.Append(num);
builder.Replace('+', '_').Replace('[', '_').Replace(']', '_').Replace('*', '_').Replace('&', '_').Replace(',', '_').Replace('\\', '_');
name = builder.ToString();
return _myModule.DefineType(name, attr, parent);
}
static AssemblyBuilder _myAssembly;
static ModuleBuilder _myModule;
static void InitializeAssemblyGen()
{
AssemblyName name = new AssemblyName("Snippets");
CustomAttributeBuilder[] assemblyAttributes = new CustomAttributeBuilder[] { new CustomAttributeBuilder(typeof(SecurityTransparentAttribute).GetConstructor(Type.EmptyTypes), new object[0]) };
_myAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run, assemblyAttributes);
_myModule = _myAssembly.DefineDynamicModule(name.Name, false);
_myAssembly.DefineVersionInfoResource();
}
static DelegateCreator()
{
InitializeAssemblyGen();
}
}
////////////////
these are members of external core. theyre deprecated.
public IntPtr Signal(string param, IntPtr value)
{
return mAccessor.Signal(null, IntPtr.Zero, param, value);
}
public IntPtr Signal(string param)
{
return mAccessor.Signal(null, IntPtr.Zero, param, IntPtr.Zero);
}
public IntPtr Signal(string type, IntPtr obj, string param, Delegate value)
{
liveDelegates[value.Target ?? ostatic][param] = value;
return mAccessor.Signal(type, obj, param, Marshal.GetFunctionPointerForDelegate(value));
}
public IntPtr Signal(string param, Delegate value)
{
return Signal(null, IntPtr.Zero, param, value);
}
public IntPtr Signal(string param, int value)
{
return mAccessor.Signal(null, IntPtr.Zero, param, new IntPtr(value));
}
public IntPtr Signal(string type, IntPtr obj, string param, IntPtr value)
{
return mAccessor.Signal(type, obj, param, value);
}

View File

@ -128,6 +128,7 @@
<Compile Include="config\SoundConfig.Designer.cs">
<DependentUpon>SoundConfig.cs</DependentUpon>
</Compile>
<Compile Include="ExternalCoreSupport.cs" />
<Compile Include="Gameboy\Debugger.cs">
<SubType>Form</SubType>
</Compile>
@ -667,4 +668,8 @@
<Target Name="AfterBuild">
</Target>
-->
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@ -56,5 +56,8 @@ namespace BizHawk.MultiClient
//TODO - wtf is this being used for
public static bool MovieMode;
public static CoreAccessor PsxCoreLibrary = new CoreAccessor(new Win32LibAccessor("PsxHawk.Core.dll"));
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Text;
using System.Threading;
using System.Drawing;
using System.Drawing.Imaging;
@ -74,6 +75,7 @@ namespace BizHawk.MultiClient
}
UpdateStatusSlots();
//in order to allow late construction of this database, we hook up a delegate here to dearchive the data and provide it on demand
//we could background thread this later instead if we wanted to be real clever
NES.BootGodDB.GetDatabaseBytes = () =>
@ -819,70 +821,83 @@ namespace BizHawk.MultiClient
else return false;
}
var game = new RomGame(file);
IEmulator nextEmulator = null;
RomGame game = null;
switch (game.System)
if (Path.GetExtension(path).ToLower() == ".iso")
{
case "SG":
case "SMS":
nextEmulator = new SMS();
if (Global.Config.SmsEnableFM) game.AddOptions("UseFM");
if (Global.Config.SmsAllowOverlock) game.AddOptions("AllowOverclock");
if (Global.Config.SmsForceStereoSeparation) game.AddOptions("ForceStereo");
break;
case "GG":
nextEmulator = new SMS { IsGameGear = true };
if (Global.Config.SmsAllowOverlock) game.AddOptions("AllowOverclock");
break;
case "PCE":
nextEmulator = new PCEngine(NecSystemType.TurboGrafx);
break;
case "SGX":
nextEmulator = new PCEngine(NecSystemType.SuperGrafx);
break;
case "GEN":
nextEmulator = new Genesis(true);//TODO
break;
case "TI83":
nextEmulator = new TI83();
if (Global.Config.TI83autoloadKeyPad)
LoadTI83KeyPad();
break;
case "NES":
{
NES nes = new NES();
nextEmulator = nes;
if (Global.Config.NESAutoLoadPalette && Global.Config.NESPaletteFile.Length > 0 && HawkFile.ExistsAt(Global.Config.NESPaletteFile))
if (Global.PsxCoreLibrary.IsOpen)
{
nextEmulator = new PsxCore(Global.PsxCoreLibrary);
game = new RomGame();
}
}
else
{
game = new RomGame(file);
switch (game.System)
{
case "SG":
case "SMS":
nextEmulator = new SMS();
if (Global.Config.SmsEnableFM) game.AddOptions("UseFM");
if (Global.Config.SmsAllowOverlock) game.AddOptions("AllowOverclock");
if (Global.Config.SmsForceStereoSeparation) game.AddOptions("ForceStereo");
break;
case "GG":
nextEmulator = new SMS { IsGameGear = true };
if (Global.Config.SmsAllowOverlock) game.AddOptions("AllowOverclock");
break;
case "PCE":
nextEmulator = new PCEngine(NecSystemType.TurboGrafx);
break;
case "SGX":
nextEmulator = new PCEngine(NecSystemType.SuperGrafx);
break;
case "GEN":
nextEmulator = new Genesis(true);//TODO
break;
case "TI83":
nextEmulator = new TI83();
if (Global.Config.TI83autoloadKeyPad)
LoadTI83KeyPad();
break;
case "NES":
{
nes.SetPalette(NES.Palettes.Load_FCEUX_Palette(HawkFile.ReadAllBytes(Global.Config.NESPaletteFile)));
NES nes = new NES();
nextEmulator = nes;
if (Global.Config.NESAutoLoadPalette && Global.Config.NESPaletteFile.Length > 0 && HawkFile.ExistsAt(Global.Config.NESPaletteFile))
{
nes.SetPalette(NES.Palettes.Load_FCEUX_Palette(HawkFile.ReadAllBytes(Global.Config.NESPaletteFile)));
}
}
}
break;
case "GB":
nextEmulator = new Gameboy();
break;
break;
case "GB":
nextEmulator = new Gameboy();
break;
}
if (nextEmulator == null) throw new Exception();
try
{
nextEmulator.CoreInputComm = Global.CoreInputComm;
//this is a bit hacky, but many cores do not take responsibility for setting this, so we need to set it for them.
nextEmulator.CoreOutputComm.RomStatus = game.Status;
nextEmulator.LoadGame(game);
}
catch (Exception ex)
{
MessageBox.Show("Exception during loadgame:\n\n" + ex.ToString());
return false;
}
}
if (nextEmulator == null)
{
throw new Exception();
}
if (nextEmulator == null) throw new Exception();
try
{
nextEmulator.CoreInputComm = Global.CoreInputComm;
//this is a bit hacky, but many cores do not take responsibility for setting this, so we need to set it for them.
nextEmulator.CoreOutputComm.RomStatus = game.Status;
nextEmulator.LoadGame(game);
}
catch (Exception ex)
{
MessageBox.Show("Exception during loadgame:\n\n" + ex.ToString());
return false;
}
CloseGame();
Global.Emulator.Dispose();
@ -1916,11 +1931,38 @@ namespace BizHawk.MultiClient
typeof(ToolStrip).InvokeMember("ProcessMnemonicInternal", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Instance, null, menuStrip1, new object[] { c });
}
string FormatFilter(params string[] args)
{
var sb = new StringBuilder();
if (args.Length % 2 != 0) throw new ArgumentException();
int num = args.Length / 2;
for (int i = 0; i < num; i++)
{
sb.AppendFormat("{0} ({1})|{1}", args[i * 2], args[i * 2 + 1]);
if (i != num - 1) sb.Append('|');
}
string str = sb.ToString().Replace("%ARCH%", "*.zip;*.rar;*.7z");
str = str.Replace(";", "; ");
return str;
}
private void OpenROM()
{
var ofd = new OpenFileDialog();
ofd.InitialDirectory = PathManager.GetRomsPath(Global.Emulator.SystemId);
ofd.Filter = "Rom Files|*.NES;*.SMS;*.GG;*.SG;*.PCE;*.SGX;*.GB;*.BIN;*.SMD;*.ROM;*.ZIP;*.7z|NES|*.NES|Master System|*.SMS;*.GG;*.SG;*.ZIP;*.7z|PC Engine|*.PCE;*.SGX;*.ZIP;*.7z|Gameboy|*.GB;*.ZIP;*.7z|TI-83|*.rom|Archive Files|*.zip;*.7z|Savestate|*.state|All Files|*.*";
//"Rom Files|*.NES;*.SMS;*.GG;*.SG;*.PCE;*.SGX;*.GB;*.BIN;*.SMD;*.ROM;*.ZIP;*.7z|NES (*.NES)|*.NES|Master System|*.SMS;*.GG;*.SG;*.ZIP;*.7z|PC Engine|*.PCE;*.SGX;*.ZIP;*.7z|Gameboy|*.GB;*.ZIP;*.7z|TI-83|*.rom|Archive Files|*.zip;*.7z|Savestate|*.state|All Files|*.*";
ofd.Filter = FormatFilter(
"Rom Files", "*.nes;*.sms;*.gg;*.sg;*.pce;*.sgx;*.gb;*.bin;*.smd;*.rom;*.iso;%ARCH%",
"Disc Images", "*.iso",
"NES", "*.nes;%ARCH%",
"Master System", "*.sms;*.gg;*.sg;%ARCH%",
"PC Engine", "*.pce;*.sgx;%ARCH%",
"Gameboy", "*.gb;%ARCH%",
"TI-83", "*.rom;%ARCH%",
"Archive Files", "%ARCH%",
"Savestate", "*.state",
"All Files", "*.*");
ofd.RestoreDirectory = false;
Global.Sound.StopSound();

View File

@ -17,6 +17,8 @@ namespace BizHawk.MultiClient
private List<string> options;
private const int BankSize = 4096;
public RomGame() { }
public RomGame(HawkFile file) : this(file, null) { }
public RomGame(HawkFile file, string patch)

View File

@ -0,0 +1,177 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="BizHawk.UnmanagedCore"
ProjectGUID="{1CE74E20-B345-4126-AACB-A21FA23149DE}"
RootNamespace="BizHawkUnmanagedCore"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath=".\core.cpp"
>
</File>
<File
RelativePath=".\core.h"
>
</File>
<File
RelativePath=".\emufile.cpp"
>
</File>
<File
RelativePath=".\emufile.h"
>
</File>
<File
RelativePath=".\emufile_hawk.cpp"
>
</File>
<File
RelativePath=".\emufile_hawk.h"
>
</File>
<File
RelativePath=".\types.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,91 @@
#include <string>
#include "core.h"
#include "emufile.h"
#include "emufile_hawk.h"
//TODO
class DISC_INTERFACE
{
};
//TODO - setup a null file to use as the default console, so we dont have to check whether its set to null everywhere
class EMUFILE_HAWK;
EMUFILE_HAWK* con = NULL;
static void* (*ClientSignal_cb)(const char*,void*,const char*,void*);
void* ClientSignal(const char* type, void* obj, const char* _param, void* value)
{
return ClientSignal_cb(type,obj,_param,value);
}
//core objects function pointers get registered here
class FunctionRegistry
{
private:
typedef std::map<std::string, void*> TFunctionMap;
TFunctionMap map;
public:
static FunctionRegistry& Instance() {
static FunctionRegistry inst;
return inst;
}
void Register(const char* _name, void* _funcptr)
{
map[_name] = _funcptr;
}
void* Lookup(const char* name)
{
TFunctionMap::iterator it(map.find(name));
if(it == map.end()) return NULL;
else return it->second;
}
private:
FunctionRegistry() {}
};
void _registerFunction(const char* _name, void* _funcptr)
{
FunctionRegistry::Instance().Register(_name,_funcptr);
}
//maybe youll need this some day... but probably not.
//#pragma comment(linker, "/include:_Core_signal")
extern "C" __declspec(dllexport) void* Core_signal(const char* type, void* obj, const char* param, void* value)
{
//use this to log signals
if(con) con->fprintf("core signal: %s : %s\n",type?type:"n/a",param?param:"n/a");
if(!strcmp(type,"SET_CLIENT_SIGNAL"))
{
ClientSignal_cb = (void *(*)(const char*,void*,const char*,void*))value;
return 0;
}
if(!strcmp(type,"SET_CONSOLE"))
{
con = (EMUFILE_HAWK*)value;
return 0;
}
//query a function pointer for later blazing fast reuse
if(!strcmp(type,"QUERY_FUNCTION"))
return FunctionRegistry::Instance().Lookup(param);
//TODO - custom core static operations?
//force a reference to our core types. a bit annoying but if its this easy i guess i dont mind
if(!strcmp(type,"IMPOSSIBLE"))
{
return new EMUFILE_HAWK(0);
}
return 0;
}

View File

@ -0,0 +1,72 @@
#ifndef _CORE_H_
#define _CORE_H_
#include <map>
#include <string>
#ifndef CTASSERT
#define CTASSERT(x) typedef char __assert ## y[(x) ? 1 : -1];
#endif
//use this to send a signal to the client.
//it may not be completely fully-baked yet though
void* ClientSignal(const char* type, void* obj, const char* _param, void* value);
class EMUFILE_HAWK;
//use this to print output to the client
extern EMUFILE_HAWK* con;
//this is supposedly illegal. but i say its perfectly legal, as long as im not using virtual functions. so stuff it.
//well, since we're doing it illegally, we need to resist the urge to generalize the function pointer system (to emufile and disc)
//since we may need to change all these later to work un-generalized
//but seriously. before doing that, i would rather return sizeof(functionpointer) bytes as a token to the managed code and pass that back in
//(MP stands for MEMBER POINTER)
template<typename T> void* MP(const T& a)
{
union U{
void* vp;
T t;
} u;
u.t = a;
return u.vp;
CTASSERT(sizeof(U)==4||(sizeof(U)==8&&sizeof(void*)==8));
}
//this is a function pointer which can be assigned without having to type the function protoype again to cast it.
template<typename T> class FP
{
private:
template<typename T> T MPX(void* a)
{
union U{
void* vp;
T t;
} u;
u.vp = a;
return u.t;
CTASSERT(sizeof(U)==4||(sizeof(U)==8&&sizeof(void*)==8));
}
public:
T func;
void set(void* val) { func = MPX<T>(val); }
};
//nothing important
void _registerFunction(const char* _name, void* _funcptr);
struct FunctionRecord
{
FunctionRecord(const char* _name, void* _funcptr)
{
_registerFunction(_name,_funcptr);
}
};
//register a core object member function. put it in a global static array
template<typename T> FunctionRecord FUNC(const char* name, const T& a)
{
return FunctionRecord(name,MP(a));
}
#endif //_CORE_H_

View File

@ -0,0 +1,28 @@
#include "types.h"
#include "emufile.h"
#include <vector>
bool EMUFILE::readAllBytes(std::vector<u8>* dstbuf, const std::string& fname)
{
EMUFILE_FILE file(fname.c_str(),"rb");
if(file.fail()) return false;
int size = file.size();
dstbuf->resize(size);
file.fread(&dstbuf->at(0),size);
return true;
}
EMUFILE* EMUFILE::memwrap(EMUFILE* fp)
{
EMUFILE_FILE* file;
EMUFILE_MEMORY* mem;
file = dynamic_cast<EMUFILE_FILE*>(fp);
mem = dynamic_cast<EMUFILE_MEMORY*>(fp);
if(mem) return mem;
mem = new EMUFILE_MEMORY(file->size());
if(file->size()==0) return mem;
file->fread(mem->buf(),file->size());
delete file;
return mem;
}

View File

@ -0,0 +1,299 @@
/* Copyright (C) 2009 DeSmuME team
*
* This file is part of DeSmuME
*
* DeSmuME 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.
*
* DeSmuME 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 DeSmuME; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef EMUFILE_H
#define EMUFILE_H
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <algorithm>
#include <string>
#include <stdarg.h>
//should be changed to #ifdef FCEUX but too much work
#ifndef DESMUME
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef char s8;
typedef short s16;
typedef int s32;
#endif
#ifdef _XBOX
#undef min;
#undef max;
#endif
class EMUFILE {
protected:
bool failbit;
public:
EMUFILE()
: failbit(false)
{}
//takes control of the provided EMUFILE and returns a new EMUFILE which is guranteed to be in memory
static EMUFILE* memwrap(EMUFILE* fp);
virtual ~EMUFILE() {}
static bool readAllBytes(std::vector<u8>* buf, const std::string& fname);
bool fail() { return failbit; }
bool eof() { return size()==ftell(); }
size_t fread(const void *ptr, size_t bytes){
return _fread(ptr,bytes);
}
void unget() { fseek(-1,SEEK_CUR); }
//virtuals
public:
virtual FILE *get_fp() = 0;
virtual int fprintf(const char *format, ...) = 0;
virtual int fgetc() = 0;
virtual int fputc(int c) = 0;
virtual size_t _fread(const void *ptr, size_t bytes) = 0;
//removing these return values for now so we can find any code that might be using them and make sure
//they handle the return values correctly
virtual void fwrite(const void *ptr, size_t bytes) = 0;
virtual int fseek(int offset, int origin) = 0;
virtual int ftell() = 0;
virtual int size() = 0;
};
//todo - handle read-only specially?
class EMUFILE_MEMORY : public EMUFILE {
protected:
std::vector<u8> *vec;
bool ownvec;
s32 pos, len;
void reserve(u32 amt) {
if(vec->size() < amt)
vec->resize(amt);
}
public:
EMUFILE_MEMORY(std::vector<u8> *underlying) : vec(underlying), ownvec(false), pos(0), len(underlying->size()) { }
EMUFILE_MEMORY(u32 preallocate) : vec(new std::vector<u8>()), ownvec(true), pos(0), len(0) {
vec->resize(preallocate);
len = preallocate;
}
EMUFILE_MEMORY() : vec(new std::vector<u8>()), ownvec(true), pos(0), len(0) { vec->reserve(1024); }
EMUFILE_MEMORY(void* buf, s32 size) : vec(new std::vector<u8>()), ownvec(true), pos(0), len(size) {
vec->resize(size);
if(size != 0)
memcpy(&vec[0],buf,size);
}
~EMUFILE_MEMORY() {
if(ownvec) delete vec;
}
u8* buf() { return &(*vec)[0]; }
std::vector<u8>* get_vec() { return vec; };
virtual FILE *get_fp() { return NULL; }
virtual int fprintf(const char *format, ...) {
va_list argptr;
va_start(argptr, format);
//we dont generate straight into the buffer because it will null terminate (one more byte than we want)
int amt = vsnprintf(0,0,format,argptr);
char* tempbuf = new char[amt+1];
vsprintf(tempbuf,format,argptr);
fwrite(tempbuf,amt);
delete[] tempbuf;
va_end(argptr);
return amt;
};
virtual int fgetc() {
u8 temp;
//need an optimized codepath
//if(_fread(&temp,1) != 1)
// return EOF;
//else return temp;
u32 remain = len-pos;
if(remain<1) {
failbit = true;
return -1;
}
temp = buf()[pos];
pos++;
return temp;
}
virtual int fputc(int c) {
u8 temp = (u8)c;
//TODO
//if(fwrite(&temp,1)!=1) return EOF;
fwrite(&temp,1);
return 0;
}
virtual size_t _fread(const void *ptr, size_t bytes){
u32 remain = len-pos;
u32 todo = std::min<u32>(remain,(u32)bytes);
memcpy((void*)ptr,buf()+pos,todo);
pos += todo;
if(todo<bytes)
failbit = true;
return todo;
}
//removing these return values for now so we can find any code that might be using them and make sure
//they handle the return values correctly
virtual void fwrite(const void *ptr, size_t bytes){
reserve(pos+bytes);
memcpy(buf()+pos,ptr,bytes);
pos += bytes;
len = std::max(pos,len);
}
virtual int fseek(int offset, int origin){
//work differently for read-only...?
switch(origin) {
case SEEK_SET:
pos = offset;
break;
case SEEK_CUR:
pos += offset;
break;
case SEEK_END:
pos = size()+offset;
break;
default:
assert(false);
}
reserve(pos);
return 0;
}
virtual int ftell() {
return pos;
}
void trim()
{
vec->resize(len);
}
virtual int size() { return (int)len; }
};
class EMUFILE_FILE : public EMUFILE {
protected:
FILE* fp;
private:
void open(const char* fname, const char* mode)
{
fp = fopen(fname,mode);
if(!fp)
failbit = true;
}
public:
EMUFILE_FILE(const std::string& fname, const char* mode) { open(fname.c_str(),mode); }
EMUFILE_FILE(const char* fname, const char* mode) { open(fname,mode); }
virtual ~EMUFILE_FILE() {
if(NULL != fp)
fclose(fp);
}
virtual FILE *get_fp() {
return fp;
}
bool is_open() { return fp != NULL; }
virtual int fprintf(const char *format, ...) {
va_list argptr;
va_start(argptr, format);
int ret = ::vfprintf(fp, format, argptr);
va_end(argptr);
return ret;
};
virtual int fgetc() {
return ::fgetc(fp);
}
virtual int fputc(int c) {
return ::fputc(c, fp);
}
virtual size_t _fread(const void *ptr, size_t bytes){
size_t ret = ::fread((void*)ptr, 1, bytes, fp);
if(ret < bytes)
failbit = true;
return ret;
}
//removing these return values for now so we can find any code that might be using them and make sure
//they handle the return values correctly
virtual void fwrite(const void *ptr, size_t bytes){
size_t ret = ::fwrite((void*)ptr, 1, bytes, fp);
if(ret < bytes)
failbit = true;
}
virtual int fseek(int offset, int origin){
return ::fseek(fp, offset, origin);
}
virtual int ftell() {
return (u32)::ftell(fp);
}
virtual int size() {
int oldpos = ftell();
fseek(0,SEEK_END);
int len = ftell();
fseek(oldpos,SEEK_SET);
return len;
}
};
#endif

View File

@ -0,0 +1,32 @@
#include "emufile_hawk.h"
#include "core.h"
static FunctionRecord records[] = {
FUNC("EmuFile.Construct", &EMUFILE_HAWK::Construct),
FUNC("EmuFile.Set_fp", &EMUFILE_HAWK::Set_fp),
FUNC("EmuFile.Delete", &EMUFILE_HAWK::Delete),
};
int EMUFILE_HAWK::fprintf(const char *format, ...)
{
va_list argptr;
va_start(argptr, format);
//could use a small static buf here optionally for quickness's sake but we may regret it if we multithread later
int amt = vsnprintf(0,0,format,argptr);
char* tempbuf = new char[amt+1];
vsprintf(tempbuf,format,argptr);
fwrite(tempbuf,amt);
delete[] tempbuf;
va_end(argptr);
return amt;
}
void* EMUFILE_HAWK::Construct(void* ManagedOpaque)
{
return new EMUFILE_HAWK(ManagedOpaque);
}

View File

@ -0,0 +1,65 @@
#ifndef _EMUFILE_HAWK_H_
#define _EMUFILE_HAWK_H_
#include "emufile.h"
#include "core.h"
class EMUFILE_HAWK : public EMUFILE
{
void* ManagedOpaque;
struct {
FP<int(*)()> fgetc;
FP<size_t(*)(const void* ptr, size_t bytes)> fread;
FP<void(*)(const void* ptr, size_t bytes)> fwrite;
FP<int(*)(int offset, int origin)> fseek;
FP<int(*)()> ftell;
FP<int(*)()> size;
FP<void(*)()> dispose;
} _;
public:
~EMUFILE_HAWK()
{
_.dispose.func();
}
EMUFILE_HAWK(void* _ManagedOpaque)
: ManagedOpaque(_ManagedOpaque)
{
}
void* Construct(void* ManagedOpaque);
void Delete()
{
delete this;
}
void Set_fp(const char* param, void* value)
{
if(!strcmp(param,"fgetc")) _.fgetc.set(value);
if(!strcmp(param,"fread")) _.fread.set(value);
if(!strcmp(param,"fwrite")) _.fwrite.set(value);
if(!strcmp(param,"fseek")) _.fseek.set(value);
if(!strcmp(param,"ftell")) _.ftell.set(value);
if(!strcmp(param,"size")) _.size.set(value);
if(!strcmp(param,"dispose")) _.dispose.set(value);
}
virtual int fgetc() { return _.fgetc.func(); }
virtual FILE *get_fp() { return NULL; }
virtual int fputc(int c) { return -1; }
virtual int fprintf(const char *format, ...);
virtual size_t _fread(const void *ptr, size_t bytes) { return _.fread.func(ptr,bytes); }
virtual void fwrite(const void *ptr, size_t bytes) { return _.fwrite.func(ptr,bytes); }
virtual int fseek(int offset, int origin) { return _.fseek.func(offset,origin); }
virtual int ftell() { return _.ftell.func(); }
virtual int size() { return _.size.func(); }
void* signal(const char* _param, void* value);
};
#endif //_EMUFILE_HAWK_H_

View File

@ -0,0 +1,8 @@
typedef unsigned char u8;
typedef char s8;
typedef unsigned short u16;
typedef short s16;
typedef unsigned int u32;
typedef int s32;
typedef unsigned __int64 u64;
typedef __int64 s64;

View File

@ -6,31 +6,89 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizHawk.Util", "BizHawk.Util\BizHawk.Util.csproj", "{EE135301-08B3-4EFC-A61C-1C53E1C65CB9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizHawk.MultiClient", "BizHawk.MultiClient\BizHawk.MultiClient.csproj", "{DD448B37-BA3F-4544-9754-5406E8094723}"
ProjectSection(ProjectDependencies) = postProject
{7B67D95B-29E0-4F9D-9767-42C35CEC3F25} = {7B67D95B-29E0-4F9D-9767-42C35CEC3F25}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiscoHawk", "DiscoHawk\DiscoHawk.csproj", "{C4366030-6D03-424B-AE53-F4F43BB217C3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PsxHawk.Core", "PsxHawk.Core\PsxHawk.Core.vcproj", "{7B67D95B-29E0-4F9D-9767-42C35CEC3F25}"
ProjectSection(ProjectDependencies) = postProject
{1CE74E20-B345-4126-AACB-A21FA23149DE} = {1CE74E20-B345-4126-AACB-A21FA23149DE}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BizHawk.UnmanagedCore", "BizHawk.UnmanagedCore\BizHawk.UnmanagedCore.vcproj", "{1CE74E20-B345-4126-AACB-A21FA23149DE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|Mixed Platforms = Debug|Mixed Platforms
Debug|Win32 = Debug|Win32
Release|Any CPU = Release|Any CPU
Release|Mixed Platforms = Release|Mixed Platforms
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Debug|Win32.ActiveCfg = Debug|Any CPU
{197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Release|Any CPU.Build.0 = Release|Any CPU
{197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Release|Win32.ActiveCfg = Release|Any CPU
{EE135301-08B3-4EFC-A61C-1C53E1C65CB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EE135301-08B3-4EFC-A61C-1C53E1C65CB9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EE135301-08B3-4EFC-A61C-1C53E1C65CB9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{EE135301-08B3-4EFC-A61C-1C53E1C65CB9}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{EE135301-08B3-4EFC-A61C-1C53E1C65CB9}.Debug|Win32.ActiveCfg = Debug|Any CPU
{EE135301-08B3-4EFC-A61C-1C53E1C65CB9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EE135301-08B3-4EFC-A61C-1C53E1C65CB9}.Release|Any CPU.Build.0 = Release|Any CPU
{EE135301-08B3-4EFC-A61C-1C53E1C65CB9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{EE135301-08B3-4EFC-A61C-1C53E1C65CB9}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{EE135301-08B3-4EFC-A61C-1C53E1C65CB9}.Release|Win32.ActiveCfg = Release|Any CPU
{DD448B37-BA3F-4544-9754-5406E8094723}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DD448B37-BA3F-4544-9754-5406E8094723}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DD448B37-BA3F-4544-9754-5406E8094723}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{DD448B37-BA3F-4544-9754-5406E8094723}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{DD448B37-BA3F-4544-9754-5406E8094723}.Debug|Win32.ActiveCfg = Debug|Any CPU
{DD448B37-BA3F-4544-9754-5406E8094723}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DD448B37-BA3F-4544-9754-5406E8094723}.Release|Any CPU.Build.0 = Release|Any CPU
{DD448B37-BA3F-4544-9754-5406E8094723}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{DD448B37-BA3F-4544-9754-5406E8094723}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{DD448B37-BA3F-4544-9754-5406E8094723}.Release|Win32.ActiveCfg = Release|Any CPU
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Win32.ActiveCfg = Debug|Any CPU
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Any CPU.Build.0 = Release|Any CPU
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Win32.ActiveCfg = Release|Any CPU
{7B67D95B-29E0-4F9D-9767-42C35CEC3F25}.Debug|Any CPU.ActiveCfg = Debug|Win32
{7B67D95B-29E0-4F9D-9767-42C35CEC3F25}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{7B67D95B-29E0-4F9D-9767-42C35CEC3F25}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{7B67D95B-29E0-4F9D-9767-42C35CEC3F25}.Debug|Win32.ActiveCfg = Debug|Win32
{7B67D95B-29E0-4F9D-9767-42C35CEC3F25}.Debug|Win32.Build.0 = Debug|Win32
{7B67D95B-29E0-4F9D-9767-42C35CEC3F25}.Release|Any CPU.ActiveCfg = Release|Win32
{7B67D95B-29E0-4F9D-9767-42C35CEC3F25}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{7B67D95B-29E0-4F9D-9767-42C35CEC3F25}.Release|Mixed Platforms.Build.0 = Release|Win32
{7B67D95B-29E0-4F9D-9767-42C35CEC3F25}.Release|Win32.ActiveCfg = Release|Win32
{7B67D95B-29E0-4F9D-9767-42C35CEC3F25}.Release|Win32.Build.0 = Release|Win32
{1CE74E20-B345-4126-AACB-A21FA23149DE}.Debug|Any CPU.ActiveCfg = Debug|Win32
{1CE74E20-B345-4126-AACB-A21FA23149DE}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{1CE74E20-B345-4126-AACB-A21FA23149DE}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{1CE74E20-B345-4126-AACB-A21FA23149DE}.Debug|Win32.ActiveCfg = Debug|Win32
{1CE74E20-B345-4126-AACB-A21FA23149DE}.Debug|Win32.Build.0 = Debug|Win32
{1CE74E20-B345-4126-AACB-A21FA23149DE}.Release|Any CPU.ActiveCfg = Release|Win32
{1CE74E20-B345-4126-AACB-A21FA23149DE}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{1CE74E20-B345-4126-AACB-A21FA23149DE}.Release|Mixed Platforms.Build.0 = Release|Win32
{1CE74E20-B345-4126-AACB-A21FA23149DE}.Release|Win32.ActiveCfg = Release|Win32
{1CE74E20-B345-4126-AACB-A21FA23149DE}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

40
PsxHawk.Core/PsxCore.cpp Normal file
View File

@ -0,0 +1,40 @@
#include "PsxCore.h"
#include "core.h"
#include <string.h>
#include <stdlib.h>
#include "emufile_hawk.h"
static FunctionRecord records[] = {
FUNC("PsxCore.Construct", &PsxCore::Construct),
FUNC("PsxCore.GetResolution", &PsxCore::GetResolution),
FUNC("PsxCore.FrameAdvance", &PsxCore::FrameAdvance),
FUNC("PsxCore.UpdateVideoBuffer", &PsxCore::UpdateVideoBuffer)
};
PsxCore::Size PsxCore::GetResolution()
{
con->fprintf("in PsxCore::GetResolution\n");
Size size = {256,256};
return size;
}
int videoBuffer[256*256];
void PsxCore::FrameAdvance()
{
for(int i=0;i<256*256;i++)
{
videoBuffer[i] = rand() | (rand()<<15) | 0xFF000000;
}
}
void PsxCore::UpdateVideoBuffer(void* target)
{
int* dest = (int*)target;
int* src = (int*)videoBuffer;
for(int i=0;i<256*256;i++)
*dest++ = *src++;
}

33
PsxHawk.Core/PsxCore.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef _PSXCORE_H_
#define _PSXCORE_H_
#include <stdio.h>
class PsxCore
{
public:
PsxCore(void* _opaque)
: opaque(_opaque)
{
}
private:
void* opaque;
public:
void* Construct(void* ManagedOpaque)
{
return new PsxCore(ManagedOpaque);
}
struct Size
{
int width,height;
};
Size GetResolution();
void FrameAdvance();
void UpdateVideoBuffer(void* target);
};
#endif //_PSXCORE_H_

View File

@ -0,0 +1,184 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="PsxHawk.Core"
ProjectGUID="{7B67D95B-29E0-4F9D-9767-42C35CEC3F25}"
RootNamespace="PsxHawkCore"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\BizHawk.UnmanagedCore"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;PSXHAWKCORE_EXPORTS;_CRT_SECURE_NO_WARNINGS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
GenerateMapFile="true"
SubSystem="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy $(TargetPath) $(SolutionDir)\BizHawk.MultiClient\output"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="..\BizHawk.UnmanagedCore"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;PSXHAWKCORE_EXPORTS;_CRT_SECURE_NO_WARNINGS"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy $(TargetPath) $(SolutionDir)\BizHawk.MultiClient\output"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath=".\PsxCore.cpp"
>
</File>
<File
RelativePath=".\PsxCore.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>