switch snes core back to external process. more refined this time. support use of performance core.
This commit is contained in:
parent
259364bb33
commit
8a69a4ebe0
|
@ -339,6 +339,7 @@
|
|||
<Compile Include="Consoles\Nintendo\NES\PPU.regs.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\PPU.run.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Unif.cs" />
|
||||
<Compile Include="Consoles\Nintendo\SNES\LibsnesApi.cs" />
|
||||
<Compile Include="Consoles\Nintendo\SNES\LibsnesCore.cs" />
|
||||
<Compile Include="Consoles\Nintendo\SNES\SnesColors.cs" />
|
||||
<Compile Include="Consoles\Nintendo\SNES\SNESGraphicsDecoder.cs" />
|
||||
|
|
|
@ -0,0 +1,722 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Pipes;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO.MemoryMappedFiles;
|
||||
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
||||
{
|
||||
public unsafe class LibsnesApi : IDisposable
|
||||
{
|
||||
//this wouldve been the ideal situation to learn protocol buffers, but since the number of messages here is so limited, it took less time to roll it by hand.
|
||||
//todo - could optimize a lot of the apis once we decide to commit to this. will we? then we wont be able to debug bsnes as well
|
||||
// well, we could refactor it a lot and let the debuggable static dll version be the one that does annoying workarounds
|
||||
//todo - more intelligent use of buffers to avoid so many copies (especially framebuffer from bsnes? supply framebuffer to-be-used to libsnes? same for audiobuffer)
|
||||
//todo - refactor to use a smarter set of pipe reader and pipe writer classes
|
||||
//todo - combine messages / tracecallbacks into one system with a channel number enum additionally
|
||||
//todo - consider refactoring bsnes to allocate memory blocks through the interface, and set ours up to allocate from a large arena of shared memory.
|
||||
// this is a lot of work, but it will be some decent speedups. who wouldve ever thought to make an emulator this way? I will, from now on...
|
||||
//todo - use a reader/writer ring buffer for communication instead of pipe
|
||||
//todo - when exe wrapper is fully baked, put it into mingw so we can just have libsneshawk.exe without a separate dll. it hardly needs any debugging presently, it should be easy to maintain.
|
||||
|
||||
//speedups to deploy later:
|
||||
//todo - convey rom data faster than pipe blob (use shared memory) (WARNING: right now our general purpose shared memory is only 1MB. maybe wait until ring buffer IPC)
|
||||
//todo - collapse input messages to one IPC operation. right now theresl ike 30 of them
|
||||
//todo - collect all memory block names whenever a memory block is alloc/dealloced. that way we avoid the overhead when using them for gui stuff (gfx debugger, hex editor)
|
||||
|
||||
string InstanceName;
|
||||
Process process;
|
||||
NamedPipeServerStream pipe;
|
||||
BinaryWriter bwPipe;
|
||||
BinaryReader brPipe;
|
||||
MemoryMappedFile mmf;
|
||||
MemoryMappedViewAccessor mmva;
|
||||
byte* mmvaPtr;
|
||||
|
||||
public enum eMessage : int
|
||||
{
|
||||
eMessage_Complete,
|
||||
|
||||
eMessage_snes_library_id,
|
||||
eMessage_snes_library_revision_major,
|
||||
eMessage_snes_library_revision_minor,
|
||||
|
||||
eMessage_snes_init,
|
||||
eMessage_snes_power,
|
||||
eMessage_snes_reset,
|
||||
eMessage_snes_run,
|
||||
eMessage_snes_term,
|
||||
eMessage_snes_unload_cartridge,
|
||||
|
||||
//snes_set_cartridge_basename, //not used
|
||||
|
||||
eMessage_snes_load_cartridge_normal,
|
||||
eMessage_snes_load_cartridge_super_game_boy,
|
||||
|
||||
//incoming from bsnes
|
||||
eMessage_snes_cb_video_refresh,
|
||||
eMessage_snes_cb_input_poll,
|
||||
eMessage_snes_cb_input_state,
|
||||
eMessage_snes_cb_input_notify,
|
||||
eMessage_snes_cb_audio_sample,
|
||||
eMessage_snes_cb_scanlineStart,
|
||||
eMessage_snes_cb_path_request,
|
||||
eMessage_snes_cb_trace_callback,
|
||||
|
||||
eMessage_snes_get_region,
|
||||
|
||||
eMessage_snes_get_memory_size,
|
||||
eMessage_snes_get_memory_data,
|
||||
eMessage_peek,
|
||||
eMessage_poke,
|
||||
|
||||
eMessage_snes_serialize_size,
|
||||
|
||||
eMessage_snes_serialize,
|
||||
eMessage_snes_unserialize,
|
||||
|
||||
eMessage_snes_poll_message,
|
||||
eMessage_snes_dequeue_message,
|
||||
|
||||
eMessage_snes_set_color_lut,
|
||||
|
||||
eMessage_snes_enable_trace,
|
||||
eMessage_snes_enable_scanline,
|
||||
eMessage_snes_enable_audio,
|
||||
eMessage_snes_set_layer_enable,
|
||||
eMessage_snes_set_backdropColor,
|
||||
eMessage_snes_peek_logical_register,
|
||||
|
||||
eMessage_snes_allocSharedMemory,
|
||||
eMessage_snes_freeSharedMemory,
|
||||
eMessage_GetMemoryIdName,
|
||||
};
|
||||
|
||||
static bool DryRun(string exePath)
|
||||
{
|
||||
ProcessStartInfo oInfo = new ProcessStartInfo(exePath, "Bongizong");
|
||||
oInfo.WorkingDirectory = Path.GetDirectoryName(exePath);
|
||||
oInfo.UseShellExecute = false;
|
||||
oInfo.CreateNoWindow = true;
|
||||
oInfo.RedirectStandardOutput = true;
|
||||
oInfo.RedirectStandardError = true;
|
||||
|
||||
Process proc = System.Diagnostics.Process.Start(oInfo);
|
||||
string result = proc.StandardError.ReadToEnd();
|
||||
proc.WaitForExit();
|
||||
|
||||
//yongou chonganong nongo tong rongeadong
|
||||
//pongigong chong hongi nonge songe
|
||||
if (result == "Honga Wongkong" && proc.ExitCode == 0x16817)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static HashSet<string> okExes = new HashSet<string>();
|
||||
public LibsnesApi(string exePath)
|
||||
{
|
||||
//make sure we've checked this exe for OKness.. the dry run should keep us from freezing up or crashing weirdly if the external process isnt correct
|
||||
if (!okExes.Contains(exePath))
|
||||
{
|
||||
bool ok = DryRun(exePath);
|
||||
if (!ok)
|
||||
throw new InvalidOperationException(string.Format("Couldn't launch {0} to run SNES core. Not sure why this would have happened. Try redownloading BizHawk first.", Path.GetFileName(exePath)));
|
||||
okExes.Add(exePath);
|
||||
}
|
||||
|
||||
InstanceName = "libsneshawk_" + Guid.NewGuid().ToString();
|
||||
|
||||
//use this to get a debug console with libsnes output
|
||||
//InstanceName = "console-" + InstanceName;
|
||||
|
||||
var pipeName = InstanceName;
|
||||
|
||||
mmf = MemoryMappedFile.CreateNew(pipeName, 1024 * 1024);
|
||||
mmva = mmf.CreateViewAccessor();
|
||||
mmva.SafeMemoryMappedViewHandle.AcquirePointer(ref mmvaPtr);
|
||||
|
||||
pipe = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.None, 1024 * 1024, 1024);
|
||||
|
||||
process = new Process();
|
||||
process.StartInfo.WorkingDirectory = Path.GetDirectoryName(exePath);
|
||||
process.StartInfo.FileName = exePath;
|
||||
process.StartInfo.Arguments = pipeName;
|
||||
process.StartInfo.ErrorDialog = true;
|
||||
process.Start();
|
||||
|
||||
//TODO - start a thread to wait for process to exit and gracefully handle errors? how about the pipe?
|
||||
|
||||
pipe.WaitForConnection();
|
||||
bwPipe = new BinaryWriter(pipe);
|
||||
brPipe = new BinaryReader(pipe);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
process.Kill();
|
||||
process.Dispose();
|
||||
process = null;
|
||||
pipe.Dispose();
|
||||
mmva.Dispose();
|
||||
mmf.Dispose();
|
||||
}
|
||||
|
||||
void WritePipeString(string str)
|
||||
{
|
||||
WritePipeBlob(System.Text.Encoding.ASCII.GetBytes(str));
|
||||
}
|
||||
|
||||
byte[] ReadPipeBlob()
|
||||
{
|
||||
int len = brPipe.ReadInt32();
|
||||
var ret = new byte[len];
|
||||
brPipe.Read(ret, 0, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void WritePipeBlob(byte[] blob)
|
||||
{
|
||||
bwPipe.Write(blob.Length);
|
||||
bwPipe.Write(blob);
|
||||
}
|
||||
|
||||
public int MessageCounter;
|
||||
|
||||
void WritePipeMessage(eMessage msg)
|
||||
{
|
||||
MessageCounter++;
|
||||
bwPipe.Write((int)msg);
|
||||
}
|
||||
|
||||
eMessage ReadPipeMessage()
|
||||
{
|
||||
return (eMessage)brPipe.ReadInt32();
|
||||
}
|
||||
|
||||
string ReadPipeString()
|
||||
{
|
||||
int len = brPipe.ReadInt32();
|
||||
var bytes = brPipe.ReadBytes(len);
|
||||
return System.Text.ASCIIEncoding.ASCII.GetString(bytes);
|
||||
}
|
||||
|
||||
public string snes_library_id()
|
||||
{
|
||||
WritePipeMessage(eMessage.eMessage_snes_library_id);
|
||||
return ReadPipeString();
|
||||
}
|
||||
|
||||
|
||||
public uint snes_library_revision_major()
|
||||
{
|
||||
WritePipeMessage(eMessage.eMessage_snes_library_revision_major);
|
||||
return brPipe.ReadUInt32();
|
||||
}
|
||||
|
||||
public uint snes_library_revision_minor()
|
||||
{
|
||||
WritePipeMessage(eMessage.eMessage_snes_library_revision_minor);
|
||||
return brPipe.ReadUInt32();
|
||||
}
|
||||
|
||||
public void snes_init()
|
||||
{
|
||||
WritePipeMessage(eMessage.eMessage_snes_init);
|
||||
WaitForCompletion();
|
||||
}
|
||||
public void snes_power() { WritePipeMessage(eMessage.eMessage_snes_power); }
|
||||
public void snes_reset() { WritePipeMessage(eMessage.eMessage_snes_reset); }
|
||||
public void snes_run()
|
||||
{
|
||||
WritePipeMessage(eMessage.eMessage_snes_run);
|
||||
WaitForCompletion();
|
||||
}
|
||||
public void snes_term() { WritePipeMessage(eMessage.eMessage_snes_term); }
|
||||
public void snes_unload_cartridge() { WritePipeMessage(eMessage.eMessage_snes_unload_cartridge); }
|
||||
|
||||
public bool snes_load_cartridge_super_game_boy(string rom_xml, byte[] rom_data, uint rom_size, string dmg_xml, byte[] dmg_data, uint dmg_size)
|
||||
{
|
||||
WritePipeMessage(eMessage.eMessage_snes_load_cartridge_super_game_boy);
|
||||
WritePipeString(rom_xml ?? "");
|
||||
WritePipeBlob(rom_data);
|
||||
WritePipeString(rom_xml ?? "");
|
||||
WritePipeBlob(dmg_data);
|
||||
//not a very obvious order.. because we do tons of work immediately after the last param goes down and need to answer messages
|
||||
WaitForCompletion();
|
||||
bool ret = brPipe.ReadBoolean();
|
||||
return ret;
|
||||
}
|
||||
|
||||
public bool snes_load_cartridge_normal(string rom_xml, byte[] rom_data)
|
||||
{
|
||||
WritePipeMessage(eMessage.eMessage_snes_load_cartridge_normal);
|
||||
WritePipeString(rom_xml ?? "");
|
||||
WritePipeBlob(rom_data);
|
||||
//not a very obvious order.. because we do tons of work immediately after the last param goes down and need to answer messages
|
||||
WaitForCompletion();
|
||||
bool ret = brPipe.ReadBoolean();
|
||||
return ret;
|
||||
}
|
||||
|
||||
public SNES_REGION snes_get_region()
|
||||
{
|
||||
WritePipeMessage(eMessage.eMessage_snes_get_region);
|
||||
return (SNES_REGION)brPipe.ReadByte();
|
||||
}
|
||||
|
||||
public int snes_get_memory_size(SNES_MEMORY id)
|
||||
{
|
||||
WritePipeMessage(eMessage.eMessage_snes_get_memory_size);
|
||||
bwPipe.Write((int)id);
|
||||
return brPipe.ReadInt32();
|
||||
}
|
||||
|
||||
string MemoryNameForId(SNES_MEMORY id)
|
||||
{
|
||||
WritePipeMessage(eMessage.eMessage_GetMemoryIdName);
|
||||
bwPipe.Write((uint)id);
|
||||
return ReadPipeString();
|
||||
}
|
||||
|
||||
public byte* snes_get_memory_data(SNES_MEMORY id)
|
||||
{
|
||||
string name = MemoryNameForId(id);
|
||||
var smb = SharedMemoryBlocks[name];
|
||||
return (byte*)smb.Ptr;
|
||||
}
|
||||
|
||||
public byte peek(SNES_MEMORY id, uint addr)
|
||||
{
|
||||
WritePipeMessage(eMessage.eMessage_peek);
|
||||
bwPipe.Write((uint)id);
|
||||
bwPipe.Write(addr);
|
||||
return brPipe.ReadByte();
|
||||
}
|
||||
public void poke(SNES_MEMORY id, uint addr, byte val)
|
||||
{
|
||||
WritePipeMessage(eMessage.eMessage_poke);
|
||||
bwPipe.Write((uint)id);
|
||||
bwPipe.Write(addr);
|
||||
bwPipe.Write(val);
|
||||
}
|
||||
|
||||
public int snes_serialize_size()
|
||||
{
|
||||
WritePipeMessage(eMessage.eMessage_snes_serialize_size);
|
||||
return brPipe.ReadInt32();
|
||||
}
|
||||
|
||||
[DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
|
||||
public static unsafe extern void* CopyMemory(void* dest, void* src, ulong count);
|
||||
|
||||
|
||||
|
||||
public bool snes_serialize(IntPtr data, int size)
|
||||
{
|
||||
WritePipeMessage(eMessage.eMessage_snes_serialize);
|
||||
bwPipe.Write(size);
|
||||
bwPipe.Write(0); //mapped memory location to serialize to
|
||||
WaitForCompletion(); //serialize/unserialize can cause traces to get called (because serialize can cause execution?)
|
||||
bool ret = brPipe.ReadBoolean();
|
||||
if (ret)
|
||||
{
|
||||
CopyMemory(data.ToPointer(), mmvaPtr, (ulong)size);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public bool snes_unserialize(IntPtr data, int size)
|
||||
{
|
||||
WritePipeMessage(eMessage.eMessage_snes_unserialize);
|
||||
CopyMemory(mmvaPtr, data.ToPointer(), (ulong)size);
|
||||
bwPipe.Write(size);
|
||||
bwPipe.Write(0); //mapped memory location to serialize from
|
||||
WaitForCompletion(); //serialize/unserialize can cause traces to get called (because serialize can cause execution?)
|
||||
bool ret = brPipe.ReadBoolean();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int snes_poll_message()
|
||||
{
|
||||
WritePipeMessage(eMessage.eMessage_snes_poll_message);
|
||||
return brPipe.ReadInt32();
|
||||
}
|
||||
|
||||
public bool HasMessage { get { return snes_poll_message() != -1; } }
|
||||
|
||||
|
||||
public string DequeueMessage()
|
||||
{
|
||||
WritePipeMessage(eMessage.eMessage_snes_dequeue_message);
|
||||
return ReadPipeString();
|
||||
}
|
||||
|
||||
public void snes_set_color_lut(IntPtr colors)
|
||||
{
|
||||
int len = 4 * 16 * 32768;
|
||||
byte[] buf = new byte[len];
|
||||
Marshal.Copy(colors, buf, 0, len);
|
||||
|
||||
WritePipeMessage(eMessage.eMessage_snes_set_color_lut);
|
||||
WritePipeBlob(buf);
|
||||
}
|
||||
|
||||
public void snes_set_layer_enable(int layer, int priority, bool enable)
|
||||
{
|
||||
WritePipeMessage(eMessage.eMessage_snes_set_layer_enable);
|
||||
bwPipe.Write(layer);
|
||||
bwPipe.Write(priority);
|
||||
bwPipe.Write(enable);
|
||||
}
|
||||
|
||||
public void snes_set_backdropColor(int backdropColor)
|
||||
{
|
||||
WritePipeMessage(eMessage.eMessage_snes_set_backdropColor);
|
||||
bwPipe.Write(backdropColor);
|
||||
}
|
||||
|
||||
public int snes_peek_logical_register(SNES_REG reg)
|
||||
{
|
||||
WritePipeMessage(eMessage.eMessage_snes_peek_logical_register);
|
||||
bwPipe.Write((int)reg);
|
||||
return brPipe.ReadInt32();
|
||||
}
|
||||
|
||||
void WaitForCompletion()
|
||||
{
|
||||
for (; ; )
|
||||
{
|
||||
var msg = ReadPipeMessage();
|
||||
MessageCounter++;
|
||||
//Console.WriteLine(msg);
|
||||
switch (msg)
|
||||
{
|
||||
case eMessage.eMessage_Complete:
|
||||
return;
|
||||
|
||||
case eMessage.eMessage_snes_cb_video_refresh:
|
||||
{
|
||||
int width = brPipe.ReadInt32();
|
||||
int height = brPipe.ReadInt32();
|
||||
bwPipe.Write(0); //offset in mapped memory buffer
|
||||
brPipe.ReadBoolean(); //dummy synchronization
|
||||
if (video_refresh != null)
|
||||
{
|
||||
video_refresh((int*)mmvaPtr, width, height);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case eMessage.eMessage_snes_cb_input_poll:
|
||||
break;
|
||||
case eMessage.eMessage_snes_cb_input_state:
|
||||
{
|
||||
int port = brPipe.ReadInt32();
|
||||
int device = brPipe.ReadInt32();
|
||||
int index = brPipe.ReadInt32();
|
||||
int id = brPipe.ReadInt32();
|
||||
ushort ret = 0;
|
||||
if (input_state != null)
|
||||
ret = input_state(port, device, index, id);
|
||||
bwPipe.Write(ret);
|
||||
break;
|
||||
}
|
||||
case eMessage.eMessage_snes_cb_input_notify:
|
||||
{
|
||||
int index = brPipe.ReadInt32();
|
||||
if (input_notify != null)
|
||||
input_notify(index);
|
||||
break;
|
||||
}
|
||||
case eMessage.eMessage_snes_cb_audio_sample:
|
||||
{
|
||||
int nsamples = brPipe.ReadInt32();
|
||||
bwPipe.Write(0); //location to store audio buffer in
|
||||
brPipe.ReadInt32(); //dummy synchronization
|
||||
|
||||
if (audio_sample != null)
|
||||
{
|
||||
ushort* audiobuffer = ((ushort*)mmvaPtr);
|
||||
for (int i = 0; i < nsamples; )
|
||||
{
|
||||
ushort left = audiobuffer[i++];
|
||||
ushort right = audiobuffer[i++];
|
||||
audio_sample(left, right);
|
||||
}
|
||||
}
|
||||
|
||||
bwPipe.Write(0); //dummy synchronization
|
||||
brPipe.ReadInt32(); //dummy synchronization
|
||||
break;
|
||||
}
|
||||
case eMessage.eMessage_snes_cb_scanlineStart:
|
||||
{
|
||||
int line = brPipe.ReadInt32();
|
||||
if (scanlineStart != null)
|
||||
scanlineStart(line);
|
||||
|
||||
//we have to notify the unmanaged process that we're done peeking thruogh its memory and whatnot so it can proceed with emulation
|
||||
WritePipeMessage(eMessage.eMessage_Complete);
|
||||
break;
|
||||
}
|
||||
case eMessage.eMessage_snes_cb_path_request:
|
||||
{
|
||||
int slot = brPipe.ReadInt32();
|
||||
string hint = ReadPipeString();
|
||||
string ret = hint;
|
||||
if (pathRequest != null)
|
||||
hint = pathRequest(slot, hint);
|
||||
WritePipeString(hint);
|
||||
break;
|
||||
}
|
||||
case eMessage.eMessage_snes_cb_trace_callback:
|
||||
{
|
||||
var trace = ReadPipeString();
|
||||
if (traceCallback != null)
|
||||
traceCallback(trace);
|
||||
break;
|
||||
}
|
||||
case eMessage.eMessage_snes_allocSharedMemory:
|
||||
{
|
||||
var smb = new SharedMemoryBlock();
|
||||
smb.Name = ReadPipeString();
|
||||
smb.Size = brPipe.ReadInt32();
|
||||
smb.BlockName = InstanceName + smb.Name;
|
||||
smb.Allocate();
|
||||
if (SharedMemoryBlocks.ContainsKey(smb.Name))
|
||||
{
|
||||
throw new InvalidOperationException("Re-defined a shared memory block. Check bsnes init/shutdown code. Block name: " + smb.Name);
|
||||
}
|
||||
|
||||
SharedMemoryBlocks[smb.Name] = smb;
|
||||
WritePipeString(smb.BlockName);
|
||||
break;
|
||||
}
|
||||
case eMessage.eMessage_snes_freeSharedMemory:
|
||||
{
|
||||
string name = ReadPipeString();
|
||||
var smb = SharedMemoryBlocks[name];
|
||||
smb.Dispose();
|
||||
SharedMemoryBlocks.Remove(name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SharedMemoryBlock : IDisposable
|
||||
{
|
||||
public string Name;
|
||||
public string BlockName;
|
||||
public int Size;
|
||||
public MemoryMappedFile mmf;
|
||||
public MemoryMappedViewAccessor mmva;
|
||||
public byte* Ptr;
|
||||
|
||||
public void Allocate()
|
||||
{
|
||||
mmf = MemoryMappedFile.CreateNew(BlockName, Size);
|
||||
mmva = mmf.CreateViewAccessor();
|
||||
mmva.SafeMemoryMappedViewHandle.AcquirePointer(ref Ptr);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (mmf == null) return;
|
||||
mmva.Dispose();
|
||||
mmf.Dispose();
|
||||
mmf = null;
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<string, SharedMemoryBlock> SharedMemoryBlocks = new Dictionary<string, SharedMemoryBlock>();
|
||||
|
||||
snes_video_refresh_t video_refresh;
|
||||
snes_input_poll_t input_poll;
|
||||
snes_input_state_t input_state;
|
||||
snes_input_notify_t input_notify;
|
||||
snes_audio_sample_t audio_sample;
|
||||
snes_scanlineStart_t scanlineStart;
|
||||
snes_path_request_t pathRequest;
|
||||
snes_trace_t traceCallback;
|
||||
|
||||
public void snes_set_video_refresh(snes_video_refresh_t video_refresh) { this.video_refresh = video_refresh; }
|
||||
public void snes_set_input_poll(snes_input_poll_t input_poll) { this.input_poll = input_poll; }
|
||||
public void snes_set_input_state(snes_input_state_t input_state) { this.input_state = input_state; }
|
||||
public void snes_set_input_notify(snes_input_notify_t input_notify) { this.input_notify = input_notify; }
|
||||
public void snes_set_audio_sample(snes_audio_sample_t audio_sample)
|
||||
{
|
||||
this.audio_sample = audio_sample;
|
||||
WritePipeMessage(eMessage.eMessage_snes_enable_audio);
|
||||
bwPipe.Write(audio_sample != null);
|
||||
}
|
||||
public void snes_set_path_request(snes_path_request_t pathRequest) { this.pathRequest = pathRequest; }
|
||||
public void snes_set_scanlineStart(snes_scanlineStart_t scanlineStart)
|
||||
{
|
||||
this.scanlineStart = scanlineStart;
|
||||
WritePipeMessage(eMessage.eMessage_snes_enable_scanline);
|
||||
bwPipe.Write(scanlineStart != null);
|
||||
}
|
||||
public void snes_set_trace_callback(snes_trace_t callback)
|
||||
{
|
||||
this.traceCallback = callback;
|
||||
WritePipeMessage(eMessage.eMessage_snes_enable_trace);
|
||||
bwPipe.Write(callback != null);
|
||||
}
|
||||
|
||||
public delegate void snes_video_refresh_t(int* data, int width, int height);
|
||||
public delegate void snes_input_poll_t();
|
||||
public delegate ushort snes_input_state_t(int port, int device, int index, int id);
|
||||
public delegate void snes_input_notify_t(int index);
|
||||
public delegate void snes_audio_sample_t(ushort left, ushort right);
|
||||
public delegate void snes_scanlineStart_t(int line);
|
||||
public delegate string snes_path_request_t(int slot, string hint);
|
||||
public delegate void snes_trace_t(string msg);
|
||||
|
||||
public enum SNES_REG : int
|
||||
{
|
||||
//$2105
|
||||
BG_MODE = 0,
|
||||
BG3_PRIORITY = 1,
|
||||
BG1_TILESIZE = 2,
|
||||
BG2_TILESIZE = 3,
|
||||
BG3_TILESIZE = 4,
|
||||
BG4_TILESIZE = 5,
|
||||
//$2107
|
||||
BG1_SCADDR = 10,
|
||||
BG1_SCSIZE = 11,
|
||||
//$2108
|
||||
BG2_SCADDR = 12,
|
||||
BG2_SCSIZE = 13,
|
||||
//$2109
|
||||
BG3_SCADDR = 14,
|
||||
BG3_SCSIZE = 15,
|
||||
//$210A
|
||||
BG4_SCADDR = 16,
|
||||
BG4_SCSIZE = 17,
|
||||
//$210B
|
||||
BG1_TDADDR = 20,
|
||||
BG2_TDADDR = 21,
|
||||
//$210C
|
||||
BG3_TDADDR = 22,
|
||||
BG4_TDADDR = 23,
|
||||
//$2133 SETINI
|
||||
SETINI_MODE7_EXTBG = 30,
|
||||
SETINI_HIRES = 31,
|
||||
SETINI_OVERSCAN = 32,
|
||||
SETINI_OBJ_INTERLACE = 33,
|
||||
SETINI_SCREEN_INTERLACE = 34,
|
||||
//$2130 CGWSEL
|
||||
CGWSEL_COLORMASK = 40,
|
||||
CGWSEL_COLORSUBMASK = 41,
|
||||
CGWSEL_ADDSUBMODE = 42,
|
||||
CGWSEL_DIRECTCOLOR = 43,
|
||||
//$2101 OBSEL
|
||||
OBSEL_NAMEBASE = 50,
|
||||
OBSEL_NAMESEL = 51,
|
||||
OBSEL_SIZE = 52,
|
||||
//$2131 CGADSUB
|
||||
CGADSUB_MODE = 60,
|
||||
CGADSUB_HALF = 61,
|
||||
CGADSUB_BG4 = 62,
|
||||
CGADSUB_BG3 = 63,
|
||||
CGADSUB_BG2 = 64,
|
||||
CGADSUB_BG1 = 65,
|
||||
CGADSUB_OBJ = 66,
|
||||
CGADSUB_BACKDROP = 67,
|
||||
//$212C TM
|
||||
TM_BG1 = 70,
|
||||
TM_BG2 = 71,
|
||||
TM_BG3 = 72,
|
||||
TM_BG4 = 73,
|
||||
TM_OBJ = 74,
|
||||
//$212D TM
|
||||
TS_BG1 = 80,
|
||||
TS_BG2 = 81,
|
||||
TS_BG3 = 82,
|
||||
TS_BG4 = 83,
|
||||
TS_OBJ = 84,
|
||||
//Mode7 regs
|
||||
M7SEL_REPEAT = 90,
|
||||
M7SEL_HFLIP = 91,
|
||||
M7SEL_VFLIP = 92,
|
||||
M7A = 93,
|
||||
M7B = 94,
|
||||
M7C = 95,
|
||||
M7D = 96,
|
||||
M7X = 97,
|
||||
M7Y = 98,
|
||||
//BG scroll regs
|
||||
BG1HOFS = 100,
|
||||
BG1VOFS = 101,
|
||||
BG2HOFS = 102,
|
||||
BG2VOFS = 103,
|
||||
BG3HOFS = 104,
|
||||
BG3VOFS = 105,
|
||||
BG4HOFS = 106,
|
||||
BG4VOFS = 107,
|
||||
M7HOFS = 108,
|
||||
M7VOFS = 109,
|
||||
}
|
||||
|
||||
public enum SNES_MEMORY : uint
|
||||
{
|
||||
CARTRIDGE_RAM = 0,
|
||||
CARTRIDGE_RTC = 1,
|
||||
BSX_RAM = 2,
|
||||
BSX_PRAM = 3,
|
||||
SUFAMI_TURBO_A_RAM = 4,
|
||||
SUFAMI_TURBO_B_RAM = 5,
|
||||
GAME_BOY_RAM = 6,
|
||||
GAME_BOY_RTC = 7,
|
||||
|
||||
WRAM = 100,
|
||||
APURAM = 101,
|
||||
VRAM = 102,
|
||||
OAM = 103,
|
||||
CGRAM = 104,
|
||||
|
||||
SYSBUS = 200,
|
||||
LOGICAL_REGS = 201
|
||||
}
|
||||
|
||||
public enum SNES_REGION : byte
|
||||
{
|
||||
NTSC = 0,
|
||||
PAL = 1,
|
||||
}
|
||||
|
||||
public enum SNES_DEVICE : uint
|
||||
{
|
||||
NONE = 0,
|
||||
JOYPAD = 1,
|
||||
MULTITAP = 2,
|
||||
MOUSE = 3,
|
||||
SUPER_SCOPE = 4,
|
||||
JUSTIFIER = 5,
|
||||
JUSTIFIERS = 6,
|
||||
SERIAL_CABLE = 7
|
||||
}
|
||||
|
||||
public enum SNES_DEVICE_ID : uint
|
||||
{
|
||||
JOYPAD_B = 0,
|
||||
JOYPAD_Y = 1,
|
||||
JOYPAD_SELECT = 2,
|
||||
JOYPAD_START = 3,
|
||||
JOYPAD_UP = 4,
|
||||
JOYPAD_DOWN = 5,
|
||||
JOYPAD_LEFT = 6,
|
||||
JOYPAD_RIGHT = 7,
|
||||
JOYPAD_A = 8,
|
||||
JOYPAD_X = 9,
|
||||
JOYPAD_L = 10,
|
||||
JOYPAD_R = 11
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
|
@ -17,290 +16,6 @@ using System.Runtime.InteropServices;
|
|||
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
||||
{
|
||||
public unsafe static class LibsnesDll
|
||||
{
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern string snes_library_id();
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int snes_library_revision_major();
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int snes_library_revision_minor();
|
||||
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void snes_init();
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void snes_power();
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void snes_reset();
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void snes_run();
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void snes_term();
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void snes_unload_cartridge();
|
||||
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void snes_set_cartridge_basename(string basename);
|
||||
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
public static extern bool snes_load_cartridge_normal(
|
||||
[MarshalAs(UnmanagedType.LPStr)]
|
||||
string rom_xml,
|
||||
[MarshalAs(UnmanagedType.LPArray)]
|
||||
byte[] rom_data,
|
||||
uint rom_size);
|
||||
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
public static extern bool snes_load_cartridge_super_game_boy(
|
||||
[MarshalAs(UnmanagedType.LPStr)]
|
||||
string rom_xml,
|
||||
[MarshalAs(UnmanagedType.LPArray)]
|
||||
byte[] rom_data,
|
||||
uint rom_size,
|
||||
[MarshalAs(UnmanagedType.LPStr)]
|
||||
string dmg_xml,
|
||||
[MarshalAs(UnmanagedType.LPArray)]
|
||||
byte[] dmg_data,
|
||||
uint dmg_size);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void snes_video_refresh_t(int* data, int width, int height);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void snes_input_poll_t();
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate ushort snes_input_state_t(int port, int device, int index, int id);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void snes_input_notify_t(int index);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void snes_audio_sample_t(ushort left, ushort right);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void snes_scanlineStart_t(int line);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate string snes_path_request_t(int slot, string hint);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void snes_trace_t(string msg);
|
||||
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void snes_set_video_refresh(snes_video_refresh_t video_refresh);
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void snes_set_input_poll(snes_input_poll_t input_poll);
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void snes_set_input_state(snes_input_state_t input_state);
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void snes_set_input_notify(snes_input_notify_t input_notify);
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void snes_set_audio_sample(snes_audio_sample_t audio_sample);
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void snes_set_scanlineStart(snes_scanlineStart_t scanlineStart);
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void snes_set_path_request(snes_path_request_t scanlineStart);
|
||||
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
public static extern bool snes_check_cartridge(
|
||||
[MarshalAs(UnmanagedType.LPArray)] byte[] rom_data,
|
||||
int rom_size);
|
||||
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
public static extern SNES_REGION snes_get_region();
|
||||
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int snes_get_memory_size(SNES_MEMORY id);
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr snes_get_memory_data(SNES_MEMORY id);
|
||||
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern byte bus_read(uint addr);
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void bus_write(uint addr, byte val);
|
||||
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int snes_serialize_size();
|
||||
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool snes_serialize(IntPtr data, int size);
|
||||
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool snes_unserialize(IntPtr data, int size);
|
||||
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int snes_poll_message();
|
||||
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void snes_dequeue_message(IntPtr strBuffer);
|
||||
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void snes_set_trace_callback(snes_trace_t callback);
|
||||
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void snes_set_color_lut(IntPtr colors);
|
||||
|
||||
public static bool HasMessage { get { return snes_poll_message() != -1; } }
|
||||
|
||||
public static string DequeueMessage()
|
||||
{
|
||||
int len = snes_poll_message();
|
||||
sbyte* temp = stackalloc sbyte[len + 1];
|
||||
temp[len] = 0;
|
||||
snes_dequeue_message(new IntPtr(temp));
|
||||
return new string(temp);
|
||||
}
|
||||
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void snes_set_layer_enable(int layer, int priority,
|
||||
[MarshalAs(UnmanagedType.U1)]
|
||||
bool enable
|
||||
);
|
||||
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void snes_set_backdropColor(int backdropColor);
|
||||
|
||||
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int snes_peek_logical_register(SNES_REG reg);
|
||||
|
||||
public enum SNES_REG : int
|
||||
{
|
||||
//$2105
|
||||
BG_MODE = 0,
|
||||
BG3_PRIORITY = 1,
|
||||
BG1_TILESIZE = 2,
|
||||
BG2_TILESIZE = 3,
|
||||
BG3_TILESIZE = 4,
|
||||
BG4_TILESIZE = 5,
|
||||
//$2107
|
||||
BG1_SCADDR = 10,
|
||||
BG1_SCSIZE = 11,
|
||||
//$2108
|
||||
BG2_SCADDR = 12,
|
||||
BG2_SCSIZE = 13,
|
||||
//$2109
|
||||
BG3_SCADDR = 14,
|
||||
BG3_SCSIZE = 15,
|
||||
//$210A
|
||||
BG4_SCADDR = 16,
|
||||
BG4_SCSIZE = 17,
|
||||
//$210B
|
||||
BG1_TDADDR = 20,
|
||||
BG2_TDADDR = 21,
|
||||
//$210C
|
||||
BG3_TDADDR = 22,
|
||||
BG4_TDADDR = 23,
|
||||
//$2133 SETINI
|
||||
SETINI_MODE7_EXTBG = 30,
|
||||
SETINI_HIRES = 31,
|
||||
SETINI_OVERSCAN = 32,
|
||||
SETINI_OBJ_INTERLACE = 33,
|
||||
SETINI_SCREEN_INTERLACE = 34,
|
||||
//$2130 CGWSEL
|
||||
CGWSEL_COLORMASK = 40,
|
||||
CGWSEL_COLORSUBMASK = 41,
|
||||
CGWSEL_ADDSUBMODE = 42,
|
||||
CGWSEL_DIRECTCOLOR = 43,
|
||||
//$2101 OBSEL
|
||||
OBSEL_NAMEBASE = 50,
|
||||
OBSEL_NAMESEL = 51,
|
||||
OBSEL_SIZE = 52,
|
||||
//$2131 CGADSUB
|
||||
CGADSUB_MODE = 60,
|
||||
CGADSUB_HALF = 61,
|
||||
CGADSUB_BG4 = 62,
|
||||
CGADSUB_BG3 = 63,
|
||||
CGADSUB_BG2 = 64,
|
||||
CGADSUB_BG1 = 65,
|
||||
CGADSUB_OBJ = 66,
|
||||
CGADSUB_BACKDROP = 67,
|
||||
//$212C TM
|
||||
TM_BG1 = 70,
|
||||
TM_BG2 = 71,
|
||||
TM_BG3 = 72,
|
||||
TM_BG4 = 73,
|
||||
TM_OBJ = 74,
|
||||
//$212D TM
|
||||
TS_BG1 = 80,
|
||||
TS_BG2 = 81,
|
||||
TS_BG3 = 82,
|
||||
TS_BG4 = 83,
|
||||
TS_OBJ = 84,
|
||||
//Mode7 regs
|
||||
M7SEL_REPEAT = 90,
|
||||
M7SEL_HFLIP = 91,
|
||||
M7SEL_VFLIP = 92,
|
||||
M7A = 93,
|
||||
M7B = 94,
|
||||
M7C = 95,
|
||||
M7D = 96,
|
||||
M7X = 97,
|
||||
M7Y = 98,
|
||||
//BG scroll regs
|
||||
BG1HOFS = 100,
|
||||
BG1VOFS = 101,
|
||||
BG2HOFS = 102,
|
||||
BG2VOFS = 103,
|
||||
BG3HOFS = 104,
|
||||
BG3VOFS = 105,
|
||||
BG4HOFS = 106,
|
||||
BG4VOFS = 107,
|
||||
M7HOFS = 108,
|
||||
M7VOFS = 109,
|
||||
}
|
||||
|
||||
public enum SNES_MEMORY : uint
|
||||
{
|
||||
CARTRIDGE_RAM = 0,
|
||||
CARTRIDGE_RTC = 1,
|
||||
BSX_RAM = 2,
|
||||
BSX_PRAM = 3,
|
||||
SUFAMI_TURBO_A_RAM = 4,
|
||||
SUFAMI_TURBO_B_RAM = 5,
|
||||
GAME_BOY_RAM = 6,
|
||||
GAME_BOY_RTC = 7,
|
||||
|
||||
WRAM = 100,
|
||||
APURAM = 101,
|
||||
VRAM = 102,
|
||||
OAM = 103,
|
||||
CGRAM = 104,
|
||||
}
|
||||
|
||||
public enum SNES_REGION : byte
|
||||
{
|
||||
NTSC = 0,
|
||||
PAL = 1,
|
||||
}
|
||||
|
||||
public enum SNES_DEVICE : uint
|
||||
{
|
||||
NONE = 0,
|
||||
JOYPAD = 1,
|
||||
MULTITAP = 2,
|
||||
MOUSE = 3,
|
||||
SUPER_SCOPE = 4,
|
||||
JUSTIFIER = 5,
|
||||
JUSTIFIERS = 6,
|
||||
SERIAL_CABLE = 7
|
||||
}
|
||||
|
||||
public enum SNES_DEVICE_ID : uint
|
||||
{
|
||||
JOYPAD_B = 0,
|
||||
JOYPAD_Y = 1,
|
||||
JOYPAD_SELECT = 2,
|
||||
JOYPAD_START = 3,
|
||||
JOYPAD_UP = 4,
|
||||
JOYPAD_DOWN = 5,
|
||||
JOYPAD_LEFT = 6,
|
||||
JOYPAD_RIGHT = 7,
|
||||
JOYPAD_A = 8,
|
||||
JOYPAD_X = 9,
|
||||
JOYPAD_L = 10,
|
||||
JOYPAD_R = 11
|
||||
}
|
||||
}
|
||||
|
||||
public class ScanlineHookManager
|
||||
{
|
||||
|
@ -352,26 +67,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
if (disposed) return;
|
||||
disposed = true;
|
||||
|
||||
disposedSaveRam = ReadSaveRam();
|
||||
|
||||
BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_video_refresh(null);
|
||||
BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_input_poll(null);
|
||||
BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_input_state(null);
|
||||
BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_audio_sample(null);
|
||||
BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_scanlineStart(null);
|
||||
|
||||
LibsnesDll.snes_unload_cartridge();
|
||||
LibsnesDll.snes_term();
|
||||
api.snes_unload_cartridge();
|
||||
api.snes_term();
|
||||
|
||||
resampler.Dispose();
|
||||
api.Dispose();
|
||||
}
|
||||
//save the save memory before disposing the core, so we can pull from it in the future after the core is terminated
|
||||
//that will be necessary to get it saving to disk
|
||||
byte[] disposedSaveRam;
|
||||
|
||||
//we can only have one active snes core at a time, due to libsnes being so static.
|
||||
//so we'll track the current one here and detach the previous one whenever a new one is booted up.
|
||||
static LibsnesCore CurrLibsnesCore;
|
||||
|
||||
public class MyScanlineHookManager : ScanlineHookManager
|
||||
{
|
||||
|
@ -390,8 +91,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
void OnScanlineHooksChanged()
|
||||
{
|
||||
if (disposed) return;
|
||||
if (ScanlineHookManager.HookCount == 0) LibsnesDll.snes_set_scanlineStart(null);
|
||||
else LibsnesDll.snes_set_scanlineStart(scanlineStart_cb);
|
||||
if (ScanlineHookManager.HookCount == 0) api.snes_set_scanlineStart(null);
|
||||
else api.snes_set_scanlineStart(scanlineStart_cb);
|
||||
}
|
||||
|
||||
void snes_scanlineStart(int line)
|
||||
|
@ -432,48 +133,39 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
CurrPalette = pal;
|
||||
int[] tmp = SnesColors.GetLUT(pal);
|
||||
fixed (int* p = &tmp[0])
|
||||
BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_color_lut((IntPtr)p);
|
||||
api.snes_set_color_lut((IntPtr)p);
|
||||
}
|
||||
|
||||
public LibsnesApi api;
|
||||
|
||||
public LibsnesCore(CoreComm comm)
|
||||
{
|
||||
CoreComm = comm;
|
||||
api = new LibsnesApi(CoreComm.SNES_ExePath);
|
||||
api.snes_init();
|
||||
}
|
||||
|
||||
LibsnesApi.snes_scanlineStart_t scanlineStart_cb;
|
||||
LibsnesApi.snes_trace_t tracecb;
|
||||
LibsnesApi.snes_audio_sample_t soundcb;
|
||||
|
||||
public void Load(GameInfo game, byte[] romData, byte[] sgbRomData, bool DeterministicEmulation)
|
||||
{
|
||||
//attach this core as the current
|
||||
if (CurrLibsnesCore != null)
|
||||
CurrLibsnesCore.Dispose();
|
||||
CurrLibsnesCore = this;
|
||||
|
||||
ScanlineHookManager = new MyScanlineHookManager(this);
|
||||
|
||||
LibsnesDll.snes_init();
|
||||
api.snes_init();
|
||||
|
||||
//LibsnesDll.snes_set_cartridge_basename(@);
|
||||
api.snes_set_video_refresh(snes_video_refresh);
|
||||
api.snes_set_input_poll(snes_input_poll);
|
||||
api.snes_set_input_state(snes_input_state);
|
||||
api.snes_set_input_notify(snes_input_notify);
|
||||
api.snes_set_path_request(snes_path_request);
|
||||
|
||||
scanlineStart_cb = new LibsnesApi.snes_scanlineStart_t(snes_scanlineStart);
|
||||
tracecb = new LibsnesApi.snes_trace_t(snes_trace);
|
||||
|
||||
vidcb = new LibsnesDll.snes_video_refresh_t(snes_video_refresh);
|
||||
BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_video_refresh(vidcb);
|
||||
|
||||
pollcb = new LibsnesDll.snes_input_poll_t(snes_input_poll);
|
||||
BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_input_poll(pollcb);
|
||||
|
||||
inputcb = new LibsnesDll.snes_input_state_t(snes_input_state);
|
||||
BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_input_state(inputcb);
|
||||
|
||||
notifycb = new LibsnesDll.snes_input_notify_t(snes_input_notify);
|
||||
BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_input_notify(notifycb);
|
||||
|
||||
soundcb = new LibsnesDll.snes_audio_sample_t(snes_audio_sample);
|
||||
BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_audio_sample(soundcb);
|
||||
|
||||
pathRequest_cb = new LibsnesDll.snes_path_request_t(snes_path_request);
|
||||
BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_path_request(pathRequest_cb);
|
||||
|
||||
scanlineStart_cb = new LibsnesDll.snes_scanlineStart_t(snes_scanlineStart);
|
||||
|
||||
tracecb = new LibsnesDll.snes_trace_t(snes_trace);
|
||||
soundcb = new LibsnesApi.snes_audio_sample_t(snes_audio_sample);
|
||||
api.snes_set_audio_sample(soundcb);
|
||||
|
||||
// set default palette. Should be overridden by frontend probably
|
||||
SetPalette(SnesColors.ColorType.BizHawk);
|
||||
|
@ -494,17 +186,17 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
{
|
||||
IsSGB = true;
|
||||
SystemId = "SNES";
|
||||
if (!LibsnesDll.snes_load_cartridge_super_game_boy(null, sgbRomData, (uint)sgbRomData.Length, null, romData, (uint)romData.Length))
|
||||
if (!api.snes_load_cartridge_super_game_boy(null, sgbRomData, (uint)sgbRomData.Length, null, romData, (uint)romData.Length))
|
||||
throw new Exception("snes_load_cartridge_super_game_boy() failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
SystemId = "SNES";
|
||||
if (!LibsnesDll.snes_load_cartridge_normal(null, romData, (uint)romData.Length))
|
||||
if (!api.snes_load_cartridge_normal(null, romData))
|
||||
throw new Exception("snes_load_cartridge_normal() failed");
|
||||
}
|
||||
|
||||
if (LibsnesDll.snes_get_region() == LibsnesDll.SNES_REGION.NTSC)
|
||||
if (api.snes_get_region() == LibsnesApi.SNES_REGION.NTSC)
|
||||
{
|
||||
//similar to what aviout reports from snes9x and seems logical from bsnes first principles. bsnes uses that numerator (ntsc master clockrate) for sure.
|
||||
CoreComm.VsyncNum = 21477272;
|
||||
|
@ -516,9 +208,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
CoreComm.VsyncDen = 1;
|
||||
}
|
||||
|
||||
CoreComm.CpuTraceAvailable = false;
|
||||
CoreComm.CpuTraceAvailable = true;
|
||||
|
||||
LibsnesDll.snes_power();
|
||||
api.snes_power();
|
||||
|
||||
SetupMemoryDomains(romData);
|
||||
|
||||
|
@ -536,38 +228,28 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
}
|
||||
}
|
||||
|
||||
//must keep references to these so that they wont get garbage collected
|
||||
LibsnesDll.snes_video_refresh_t vidcb;
|
||||
LibsnesDll.snes_input_poll_t pollcb;
|
||||
LibsnesDll.snes_input_state_t inputcb;
|
||||
LibsnesDll.snes_input_notify_t notifycb;
|
||||
LibsnesDll.snes_audio_sample_t soundcb;
|
||||
LibsnesDll.snes_scanlineStart_t scanlineStart_cb;
|
||||
LibsnesDll.snes_path_request_t pathRequest_cb;
|
||||
LibsnesDll.snes_trace_t tracecb;
|
||||
|
||||
ushort snes_input_state(int port, int device, int index, int id)
|
||||
{
|
||||
if (!nocallbacks && CoreComm.InputCallback != null) CoreComm.InputCallback();
|
||||
//Console.WriteLine("{0} {1} {2} {3}", port, device, index, id);
|
||||
|
||||
string key = "P" + (1 + port) + " ";
|
||||
if ((LibsnesDll.SNES_DEVICE)device == LibsnesDll.SNES_DEVICE.JOYPAD)
|
||||
if ((LibsnesApi.SNES_DEVICE)device == LibsnesApi.SNES_DEVICE.JOYPAD)
|
||||
{
|
||||
switch ((LibsnesDll.SNES_DEVICE_ID)id)
|
||||
switch ((LibsnesApi.SNES_DEVICE_ID)id)
|
||||
{
|
||||
case LibsnesDll.SNES_DEVICE_ID.JOYPAD_A: key += "A"; break;
|
||||
case LibsnesDll.SNES_DEVICE_ID.JOYPAD_B: key += "B"; break;
|
||||
case LibsnesDll.SNES_DEVICE_ID.JOYPAD_X: key += "X"; break;
|
||||
case LibsnesDll.SNES_DEVICE_ID.JOYPAD_Y: key += "Y"; break;
|
||||
case LibsnesDll.SNES_DEVICE_ID.JOYPAD_UP: key += "Up"; break;
|
||||
case LibsnesDll.SNES_DEVICE_ID.JOYPAD_DOWN: key += "Down"; break;
|
||||
case LibsnesDll.SNES_DEVICE_ID.JOYPAD_LEFT: key += "Left"; break;
|
||||
case LibsnesDll.SNES_DEVICE_ID.JOYPAD_RIGHT: key += "Right"; break;
|
||||
case LibsnesDll.SNES_DEVICE_ID.JOYPAD_L: key += "L"; break;
|
||||
case LibsnesDll.SNES_DEVICE_ID.JOYPAD_R: key += "R"; break;
|
||||
case LibsnesDll.SNES_DEVICE_ID.JOYPAD_SELECT: key += "Select"; break;
|
||||
case LibsnesDll.SNES_DEVICE_ID.JOYPAD_START: key += "Start"; break;
|
||||
case LibsnesApi.SNES_DEVICE_ID.JOYPAD_A: key += "A"; break;
|
||||
case LibsnesApi.SNES_DEVICE_ID.JOYPAD_B: key += "B"; break;
|
||||
case LibsnesApi.SNES_DEVICE_ID.JOYPAD_X: key += "X"; break;
|
||||
case LibsnesApi.SNES_DEVICE_ID.JOYPAD_Y: key += "Y"; break;
|
||||
case LibsnesApi.SNES_DEVICE_ID.JOYPAD_UP: key += "Up"; break;
|
||||
case LibsnesApi.SNES_DEVICE_ID.JOYPAD_DOWN: key += "Down"; break;
|
||||
case LibsnesApi.SNES_DEVICE_ID.JOYPAD_LEFT: key += "Left"; break;
|
||||
case LibsnesApi.SNES_DEVICE_ID.JOYPAD_RIGHT: key += "Right"; break;
|
||||
case LibsnesApi.SNES_DEVICE_ID.JOYPAD_L: key += "L"; break;
|
||||
case LibsnesApi.SNES_DEVICE_ID.JOYPAD_R: key += "R"; break;
|
||||
case LibsnesApi.SNES_DEVICE_ID.JOYPAD_SELECT: key += "Select"; break;
|
||||
case LibsnesApi.SNES_DEVICE_ID.JOYPAD_START: key += "Start"; break;
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
|
@ -649,6 +331,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
|
||||
public void FrameAdvance(bool render, bool rendersound)
|
||||
{
|
||||
api.MessageCounter = 0;
|
||||
|
||||
// for deterministic emulation, save the state we're going to use before frame advance
|
||||
// don't do this during nocallbacks though, since it's already been done
|
||||
if (!nocallbacks && DeterministicEmulation)
|
||||
|
@ -665,55 +349,58 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
}
|
||||
|
||||
if (!nocallbacks && CoreComm.Tracer.Enabled)
|
||||
LibsnesDll.snes_set_trace_callback(tracecb);
|
||||
api.snes_set_trace_callback(tracecb);
|
||||
else
|
||||
LibsnesDll.snes_set_trace_callback(null);
|
||||
api.snes_set_trace_callback(null);
|
||||
|
||||
// speedup when sound rendering is not needed
|
||||
if (!rendersound)
|
||||
LibsnesDll.snes_set_audio_sample(null);
|
||||
api.snes_set_audio_sample(null);
|
||||
else
|
||||
LibsnesDll.snes_set_audio_sample(soundcb);
|
||||
api.snes_set_audio_sample(soundcb);
|
||||
|
||||
bool resetSignal = Controller["Reset"];
|
||||
if (resetSignal) LibsnesDll.snes_reset();
|
||||
if (resetSignal) api.snes_reset();
|
||||
|
||||
bool powerSignal = Controller["Power"];
|
||||
if (powerSignal) LibsnesDll.snes_power();
|
||||
if (powerSignal) api.snes_power();
|
||||
|
||||
LibsnesDll.snes_set_layer_enable(0, 0, CoreComm.SNES_ShowBG1_0);
|
||||
LibsnesDll.snes_set_layer_enable(0, 1, CoreComm.SNES_ShowBG1_1);
|
||||
LibsnesDll.snes_set_layer_enable(1, 0, CoreComm.SNES_ShowBG2_0);
|
||||
LibsnesDll.snes_set_layer_enable(1, 1, CoreComm.SNES_ShowBG2_1);
|
||||
LibsnesDll.snes_set_layer_enable(2, 0, CoreComm.SNES_ShowBG3_0);
|
||||
LibsnesDll.snes_set_layer_enable(2, 1, CoreComm.SNES_ShowBG3_1);
|
||||
LibsnesDll.snes_set_layer_enable(3, 0, CoreComm.SNES_ShowBG4_0);
|
||||
LibsnesDll.snes_set_layer_enable(3, 1, CoreComm.SNES_ShowBG4_1);
|
||||
LibsnesDll.snes_set_layer_enable(4, 0, CoreComm.SNES_ShowOBJ_0);
|
||||
LibsnesDll.snes_set_layer_enable(4, 1, CoreComm.SNES_ShowOBJ_1);
|
||||
LibsnesDll.snes_set_layer_enable(4, 2, CoreComm.SNES_ShowOBJ_2);
|
||||
LibsnesDll.snes_set_layer_enable(4, 3, CoreComm.SNES_ShowOBJ_3);
|
||||
//too many messages
|
||||
api.snes_set_layer_enable(0, 0, CoreComm.SNES_ShowBG1_0);
|
||||
api.snes_set_layer_enable(0, 1, CoreComm.SNES_ShowBG1_1);
|
||||
api.snes_set_layer_enable(1, 0, CoreComm.SNES_ShowBG2_0);
|
||||
api.snes_set_layer_enable(1, 1, CoreComm.SNES_ShowBG2_1);
|
||||
api.snes_set_layer_enable(2, 0, CoreComm.SNES_ShowBG3_0);
|
||||
api.snes_set_layer_enable(2, 1, CoreComm.SNES_ShowBG3_1);
|
||||
api.snes_set_layer_enable(3, 0, CoreComm.SNES_ShowBG4_0);
|
||||
api.snes_set_layer_enable(3, 1, CoreComm.SNES_ShowBG4_1);
|
||||
api.snes_set_layer_enable(4, 0, CoreComm.SNES_ShowOBJ_0);
|
||||
api.snes_set_layer_enable(4, 1, CoreComm.SNES_ShowOBJ_1);
|
||||
api.snes_set_layer_enable(4, 2, CoreComm.SNES_ShowOBJ_2);
|
||||
api.snes_set_layer_enable(4, 3, CoreComm.SNES_ShowOBJ_3);
|
||||
|
||||
// if the input poll callback is called, it will set this to false
|
||||
IsLagFrame = true;
|
||||
|
||||
//apparently this is one frame?
|
||||
timeFrameCounter++;
|
||||
LibsnesDll.snes_run();
|
||||
api.snes_run();
|
||||
|
||||
while (LibsnesDll.HasMessage)
|
||||
Console.WriteLine(LibsnesDll.DequeueMessage());
|
||||
while (api.HasMessage)
|
||||
Console.WriteLine(api.DequeueMessage());
|
||||
|
||||
if (IsLagFrame)
|
||||
LagCount++;
|
||||
|
||||
//diagnostics for IPC traffic
|
||||
//Console.WriteLine(api.MessageCounter);
|
||||
}
|
||||
|
||||
public DisplayType DisplayType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (LibsnesDll.snes_get_region() == LibsnesDll.SNES_REGION.NTSC)
|
||||
if (api.snes_get_region() == LibsnesApi.SNES_REGION.NTSC)
|
||||
return BizHawk.DisplayType.NTSC;
|
||||
else
|
||||
return BizHawk.DisplayType.PAL;
|
||||
|
@ -770,37 +457,39 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
set { }
|
||||
get
|
||||
{
|
||||
return LibsnesDll.snes_get_memory_size(LibsnesDll.SNES_MEMORY.CARTRIDGE_RAM) != 0;
|
||||
return api.snes_get_memory_size(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] ReadSaveRam()
|
||||
{
|
||||
if (disposedSaveRam != null) return disposedSaveRam;
|
||||
return snes_get_memory_data_read(LibsnesDll.SNES_MEMORY.CARTRIDGE_RAM);
|
||||
}
|
||||
|
||||
public static byte[] snes_get_memory_data_read(LibsnesDll.SNES_MEMORY id)
|
||||
{
|
||||
var size = (int)LibsnesDll.snes_get_memory_size(id);
|
||||
if (size == 0) return new byte[0];
|
||||
var data = LibsnesDll.snes_get_memory_data(id);
|
||||
byte* buf = api.snes_get_memory_data(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM);
|
||||
var size = api.snes_get_memory_size(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM);
|
||||
var ret = new byte[size];
|
||||
Marshal.Copy(data, ret, 0, size);
|
||||
Marshal.Copy((IntPtr)buf, ret, 0, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//public byte[] snes_get_memory_data_read(LibsnesApi.SNES_MEMORY id)
|
||||
//{
|
||||
// var size = (int)api.snes_get_memory_size(id);
|
||||
// if (size == 0) return new byte[0];
|
||||
// var ret = api.snes_get_memory_data(id);
|
||||
// return ret;
|
||||
//}
|
||||
|
||||
public void StoreSaveRam(byte[] data)
|
||||
{
|
||||
var size = (int)LibsnesDll.snes_get_memory_size(LibsnesDll.SNES_MEMORY.CARTRIDGE_RAM);
|
||||
var size = api.snes_get_memory_size(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM);
|
||||
if (size == 0) return;
|
||||
var emudata = LibsnesDll.snes_get_memory_data(LibsnesDll.SNES_MEMORY.CARTRIDGE_RAM);
|
||||
Marshal.Copy(data, 0, emudata, size);
|
||||
if (size != data.Length) throw new InvalidOperationException("Somehow, we got a mismatch between saveram size and what bsnes says the saveram size is");
|
||||
byte* buf = api.snes_get_memory_data(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM);
|
||||
Marshal.Copy(data, 0, (IntPtr)buf, size);
|
||||
}
|
||||
|
||||
public void ClearSaveRam()
|
||||
{
|
||||
byte[] cleardata = new byte[(int)LibsnesDll.snes_get_memory_size(LibsnesDll.SNES_MEMORY.CARTRIDGE_RAM)];
|
||||
byte[] cleardata = new byte[(int)api.snes_get_memory_size(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM)];
|
||||
StoreSaveRam(cleardata);
|
||||
}
|
||||
|
||||
|
@ -914,6 +603,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
temp.SaveAsHex(writer);
|
||||
// write extra copy of stuff we don't use
|
||||
writer.WriteLine("Frame {0}", Frame);
|
||||
writer.WriteLine("Profile {0}", CoreComm.SNES_Profile);
|
||||
}
|
||||
public void LoadStateText(TextReader reader)
|
||||
{
|
||||
|
@ -921,6 +611,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
byte[] state = new byte[hex.Length / 2];
|
||||
state.ReadFromHex(hex);
|
||||
LoadStateBinary(new BinaryReader(new MemoryStream(state)));
|
||||
reader.ReadLine();
|
||||
var profile = reader.ReadLine().Split(' ')[1];
|
||||
ValidateLoadstateProfile(profile);
|
||||
}
|
||||
|
||||
public void SaveStateBinary(BinaryWriter writer)
|
||||
|
@ -934,12 +627,13 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
writer.Write(IsLagFrame);
|
||||
writer.Write(LagCount);
|
||||
writer.Write(Frame);
|
||||
writer.Write(CoreComm.SNES_Profile);
|
||||
|
||||
writer.Flush();
|
||||
}
|
||||
public void LoadStateBinary(BinaryReader reader)
|
||||
{
|
||||
int size = LibsnesDll.snes_serialize_size();
|
||||
int size = api.snes_serialize_size();
|
||||
byte[] buf = reader.ReadBytes(size);
|
||||
CoreLoadState(buf);
|
||||
|
||||
|
@ -975,7 +669,18 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
IsLagFrame = reader.ReadBoolean();
|
||||
LagCount = reader.ReadInt32();
|
||||
Frame = reader.ReadInt32();
|
||||
var profile = reader.ReadString();
|
||||
ValidateLoadstateProfile(profile);
|
||||
}
|
||||
|
||||
void ValidateLoadstateProfile(string profile)
|
||||
{
|
||||
if (profile != CoreComm.SNES_Profile)
|
||||
{
|
||||
throw new InvalidOperationException("You've attempted to load a savestate made using a different SNES profile than your current configuration. We COULD automatically switch for you, but we havent done that yet. This error is to make sure you know that this isnt going to work right now.");
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] SaveStateBinary()
|
||||
{
|
||||
MemoryStream ms = new MemoryStream();
|
||||
|
@ -990,22 +695,22 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
/// </summary>
|
||||
void CoreLoadState(byte[] data)
|
||||
{
|
||||
int size = LibsnesDll.snes_serialize_size();
|
||||
int size = api.snes_serialize_size();
|
||||
if (data.Length != size)
|
||||
throw new Exception("Libsnes internal savestate size mismatch!");
|
||||
LibsnesDll.snes_init();
|
||||
api.snes_init();
|
||||
fixed (byte* pbuf = &data[0])
|
||||
LibsnesDll.snes_unserialize(new IntPtr(pbuf), size);
|
||||
api.snes_unserialize(new IntPtr(pbuf), size);
|
||||
}
|
||||
/// <summary>
|
||||
/// handle the unmanaged part of savestating
|
||||
/// </summary>
|
||||
byte[] CoreSaveState()
|
||||
{
|
||||
int size = LibsnesDll.snes_serialize_size();
|
||||
int size = api.snes_serialize_size();
|
||||
byte[] buf = new byte[size];
|
||||
fixed (byte* pbuf = &buf[0])
|
||||
LibsnesDll.snes_serialize(new IntPtr(pbuf), size);
|
||||
api.snes_serialize(new IntPtr(pbuf), size);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
@ -1019,38 +724,52 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
public CoreComm CoreComm { get; private set; }
|
||||
|
||||
// ----- Client Debugging API stuff -----
|
||||
unsafe MemoryDomain MakeMemoryDomain(string name, LibsnesDll.SNES_MEMORY id, Endian endian)
|
||||
unsafe MemoryDomain MakeMemoryDomain(string name, LibsnesApi.SNES_MEMORY id, Endian endian)
|
||||
{
|
||||
IntPtr block = LibsnesDll.snes_get_memory_data(id);
|
||||
int size = LibsnesDll.snes_get_memory_size(id);
|
||||
int size = api.snes_get_memory_size(id);
|
||||
int mask = size - 1;
|
||||
byte* blockptr = (byte*)block.ToPointer();
|
||||
MemoryDomain md;
|
||||
|
||||
//have to bitmask these somehow because it's unmanaged memory and we would hate to clobber things or make them nondeterministic
|
||||
////have to bitmask these somehow because it's unmanaged memory and we would hate to clobber things or make them nondeterministic
|
||||
//if (Util.IsPowerOfTwo(size))
|
||||
//{
|
||||
// //can &mask for speed
|
||||
// md = new MemoryDomain(name, size, endian,
|
||||
// (addr) => blockptr[addr & mask],
|
||||
// (addr, value) => blockptr[addr & mask] = value);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// //have to use % (only OAM needs this, it seems)
|
||||
// //(OAM is actually two differently sized banks of memory which arent truly considered adjacent. maybe a better way to visualize it would be with an empty bus and adjacent banks)
|
||||
// md = new MemoryDomain(name, size, endian,
|
||||
// (addr) => blockptr[addr % size],
|
||||
// (addr, value) => blockptr[addr % size] = value);
|
||||
//}
|
||||
|
||||
//EXTERNAL PROCESS CONVERSION: MUST MAKE THIS SAFE
|
||||
//speed it up later
|
||||
if (Util.IsPowerOfTwo(size))
|
||||
{
|
||||
//can &mask for speed
|
||||
md = new MemoryDomain(name, size, endian,
|
||||
(addr) => blockptr[addr & mask],
|
||||
(addr, value) => blockptr[addr & mask] = value);
|
||||
(addr) => api.peek(id, (uint)(addr & mask)),
|
||||
(addr, value) => api.poke(id, (uint)(addr & mask), value));
|
||||
}
|
||||
else
|
||||
{
|
||||
//have to use % (only OAM needs this, it seems)
|
||||
//(OAM is actually two differently sized banks of memory which arent truly considered adjacent. maybe a better way to visualize it would be with an empty bus and adjacent banks)
|
||||
md = new MemoryDomain(name, size, endian,
|
||||
(addr) => blockptr[addr % size],
|
||||
(addr, value) => blockptr[addr % size] = value);
|
||||
(addr) => api.peek(id, (uint)(addr % size)),
|
||||
(addr, value) => api.poke(id, (uint)(addr % size), value));
|
||||
}
|
||||
|
||||
MemoryDomains.Add(md);
|
||||
|
||||
return md;
|
||||
|
||||
//doesnt cache the addresses. safer. slower. necessary? don't know
|
||||
//return new MemoryDomain(name, size, endian,
|
||||
// (addr) => Peek(LibsnesDll.SNES_MEMORY.WRAM, addr & mask),
|
||||
// (addr, value) => Poke(LibsnesDll.SNES_MEMORY.WRAM, addr & mask, value));
|
||||
|
||||
}
|
||||
|
||||
void SetupMemoryDomains(byte[] romData)
|
||||
|
@ -1061,18 +780,18 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
(addr) => romData[addr],
|
||||
(addr, value) => romData[addr] = value);
|
||||
|
||||
MainMemory = MakeMemoryDomain("WRAM", LibsnesDll.SNES_MEMORY.WRAM, Endian.Little);
|
||||
MainMemory = MakeMemoryDomain("WRAM", LibsnesApi.SNES_MEMORY.WRAM, Endian.Little);
|
||||
MemoryDomains.Add(romDomain);
|
||||
MakeMemoryDomain("CARTRAM", LibsnesDll.SNES_MEMORY.CARTRIDGE_RAM, Endian.Little);
|
||||
MakeMemoryDomain("VRAM", LibsnesDll.SNES_MEMORY.VRAM, Endian.Little);
|
||||
MakeMemoryDomain("OAM", LibsnesDll.SNES_MEMORY.OAM, Endian.Little);
|
||||
MakeMemoryDomain("CGRAM", LibsnesDll.SNES_MEMORY.CGRAM, Endian.Little);
|
||||
MakeMemoryDomain("APURAM", LibsnesDll.SNES_MEMORY.APURAM, Endian.Little);
|
||||
MakeMemoryDomain("CARTRAM", LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM, Endian.Little);
|
||||
MakeMemoryDomain("VRAM", LibsnesApi.SNES_MEMORY.VRAM, Endian.Little);
|
||||
MakeMemoryDomain("OAM", LibsnesApi.SNES_MEMORY.OAM, Endian.Little);
|
||||
MakeMemoryDomain("CGRAM", LibsnesApi.SNES_MEMORY.CGRAM, Endian.Little);
|
||||
MakeMemoryDomain("APURAM", LibsnesApi.SNES_MEMORY.APURAM, Endian.Little);
|
||||
|
||||
if (!DeterministicEmulation)
|
||||
MemoryDomains.Add(new MemoryDomain("BUS", 0x1000000, Endian.Little,
|
||||
(addr) => LibsnesDll.bus_read((uint)addr),
|
||||
(addr, val) => LibsnesDll.bus_write((uint)addr, val)));
|
||||
(addr) => api.peek(LibsnesApi.SNES_MEMORY.SYSBUS, (uint)addr),
|
||||
(addr, val) => api.poke(LibsnesApi.SNES_MEMORY.SYSBUS, (uint)addr, val)));
|
||||
}
|
||||
public IList<MemoryDomain> MemoryDomains { get; private set; }
|
||||
public MemoryDomain MainMemory { get; private set; }
|
||||
|
|
|
@ -10,14 +10,14 @@ using System.Linq;
|
|||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
||||
{
|
||||
|
||||
public unsafe class SNESGraphicsDecoder
|
||||
public unsafe class SNESGraphicsDecoder : IDisposable
|
||||
{
|
||||
|
||||
public class PaletteSelection
|
||||
{
|
||||
public PaletteSelection() { }
|
||||
|
@ -332,15 +332,15 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
public bool M7SEL_HFLIP { private set; get; }
|
||||
public bool M7SEL_VFLIP { private set; get; }
|
||||
|
||||
public static ScreenInfo GetScreenInfo()
|
||||
public static ScreenInfo GetScreenInfo(LibsnesApi api)
|
||||
{
|
||||
var si = new ScreenInfo();
|
||||
|
||||
si.Mode1_BG3_Priority = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_PRIORITY) == 1;
|
||||
si.Mode1_BG3_Priority = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG3_PRIORITY) == 1;
|
||||
|
||||
si.OBSEL_Size = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.OBSEL_SIZE);
|
||||
si.OBSEL_NameSel = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.OBSEL_NAMESEL);
|
||||
si.OBSEL_NameBase = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.OBSEL_NAMEBASE);
|
||||
si.OBSEL_Size = api.snes_peek_logical_register(LibsnesApi.SNES_REG.OBSEL_SIZE);
|
||||
si.OBSEL_NameSel = api.snes_peek_logical_register(LibsnesApi.SNES_REG.OBSEL_NAMESEL);
|
||||
si.OBSEL_NameBase = api.snes_peek_logical_register(LibsnesApi.SNES_REG.OBSEL_NAMEBASE);
|
||||
|
||||
si.ObjSizeBounds = ObjSizes[si.OBSEL_Size,1];
|
||||
int square = Math.Max(si.ObjSizeBounds.Width, si.ObjSizeBounds.Height);
|
||||
|
@ -350,26 +350,26 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
si.OBJTable0Addr = si.OBSEL_NameBase << 14;
|
||||
si.OBJTable1Addr = (si.OBJTable0Addr + ((si.OBSEL_NameSel + 1) << 13)) & 0xFFFF;
|
||||
|
||||
si.SETINI_Mode7ExtBG = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.SETINI_MODE7_EXTBG) == 1;
|
||||
si.SETINI_HiRes = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.SETINI_HIRES) == 1;
|
||||
si.SETINI_Overscan = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.SETINI_OVERSCAN) == 1;
|
||||
si.SETINI_ObjInterlace = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.SETINI_OBJ_INTERLACE) == 1;
|
||||
si.SETINI_ScreenInterlace = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.SETINI_SCREEN_INTERLACE) == 1;
|
||||
si.SETINI_Mode7ExtBG = api.snes_peek_logical_register(LibsnesApi.SNES_REG.SETINI_MODE7_EXTBG) == 1;
|
||||
si.SETINI_HiRes = api.snes_peek_logical_register(LibsnesApi.SNES_REG.SETINI_HIRES) == 1;
|
||||
si.SETINI_Overscan = api.snes_peek_logical_register(LibsnesApi.SNES_REG.SETINI_OVERSCAN) == 1;
|
||||
si.SETINI_ObjInterlace = api.snes_peek_logical_register(LibsnesApi.SNES_REG.SETINI_OBJ_INTERLACE) == 1;
|
||||
si.SETINI_ScreenInterlace = api.snes_peek_logical_register(LibsnesApi.SNES_REG.SETINI_SCREEN_INTERLACE) == 1;
|
||||
|
||||
si.CGWSEL_ColorMask = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGWSEL_COLORMASK);
|
||||
si.CGWSEL_ColorSubMask = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGWSEL_COLORSUBMASK);
|
||||
si.CGWSEL_AddSubMode = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGWSEL_ADDSUBMODE);
|
||||
si.CGWSEL_DirectColor = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGWSEL_DIRECTCOLOR) == 1;
|
||||
si.CGWSEL_ColorMask = api.snes_peek_logical_register(LibsnesApi.SNES_REG.CGWSEL_COLORMASK);
|
||||
si.CGWSEL_ColorSubMask = api.snes_peek_logical_register(LibsnesApi.SNES_REG.CGWSEL_COLORSUBMASK);
|
||||
si.CGWSEL_AddSubMode = api.snes_peek_logical_register(LibsnesApi.SNES_REG.CGWSEL_ADDSUBMODE);
|
||||
si.CGWSEL_DirectColor = api.snes_peek_logical_register(LibsnesApi.SNES_REG.CGWSEL_DIRECTCOLOR) == 1;
|
||||
|
||||
si.CGADSUB_AddSub = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_MODE);
|
||||
si.CGADSUB_Half = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_HALF) == 1;
|
||||
si.CGADSUB_AddSub = api.snes_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_MODE);
|
||||
si.CGADSUB_Half = api.snes_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_HALF) == 1;
|
||||
|
||||
si.OBJ_MainEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.TM_OBJ) == 1;
|
||||
si.OBJ_SubEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.TS_OBJ) == 1;
|
||||
si.OBJ_MathEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_OBJ) == 1;
|
||||
si.BK_MathEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_BACKDROP) == 1;
|
||||
si.OBJ_MainEnabled = api.snes_peek_logical_register(LibsnesApi.SNES_REG.TM_OBJ) == 1;
|
||||
si.OBJ_SubEnabled = api.snes_peek_logical_register(LibsnesApi.SNES_REG.TS_OBJ) == 1;
|
||||
si.OBJ_MathEnabled = api.snes_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_OBJ) == 1;
|
||||
si.BK_MathEnabled = api.snes_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_BACKDROP) == 1;
|
||||
|
||||
si.Mode.MODE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG_MODE);
|
||||
si.Mode.MODE = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG_MODE);
|
||||
si.BG.BG1.Bpp = ModeBpps[si.Mode.MODE, 0];
|
||||
si.BG.BG2.Bpp = ModeBpps[si.Mode.MODE, 1];
|
||||
si.BG.BG3.Bpp = ModeBpps[si.Mode.MODE, 2];
|
||||
|
@ -379,58 +379,58 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
for(int i=1;i<=4;i++)
|
||||
si.BG[i].BGMode = si.BG[i].Bpp == 0 ? BGMode.Unavailable : BGMode.Text;
|
||||
|
||||
si.BG.BG1.TILESIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1_TILESIZE);
|
||||
si.BG.BG2.TILESIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2_TILESIZE);
|
||||
si.BG.BG3.TILESIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_TILESIZE);
|
||||
si.BG.BG4.TILESIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4_TILESIZE);
|
||||
si.BG.BG1.TILESIZE = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG1_TILESIZE);
|
||||
si.BG.BG2.TILESIZE = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG2_TILESIZE);
|
||||
si.BG.BG3.TILESIZE = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG3_TILESIZE);
|
||||
si.BG.BG4.TILESIZE = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG4_TILESIZE);
|
||||
|
||||
si.BG.BG1.SCSIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1_SCSIZE);
|
||||
si.BG.BG2.SCSIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2_SCSIZE);
|
||||
si.BG.BG3.SCSIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_SCSIZE);
|
||||
si.BG.BG4.SCSIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4_SCSIZE);
|
||||
si.BG.BG1.SCADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1_SCADDR);
|
||||
si.BG.BG2.SCADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2_SCADDR);
|
||||
si.BG.BG3.SCADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_SCADDR);
|
||||
si.BG.BG4.SCADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4_SCADDR);
|
||||
si.BG.BG1.TDADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1_TDADDR);
|
||||
si.BG.BG2.TDADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2_TDADDR);
|
||||
si.BG.BG3.TDADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_TDADDR);
|
||||
si.BG.BG4.TDADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4_TDADDR);
|
||||
si.BG.BG1.SCSIZE = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG1_SCSIZE);
|
||||
si.BG.BG2.SCSIZE = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG2_SCSIZE);
|
||||
si.BG.BG3.SCSIZE = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG3_SCSIZE);
|
||||
si.BG.BG4.SCSIZE = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG4_SCSIZE);
|
||||
si.BG.BG1.SCADDR = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG1_SCADDR);
|
||||
si.BG.BG2.SCADDR = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG2_SCADDR);
|
||||
si.BG.BG3.SCADDR = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG3_SCADDR);
|
||||
si.BG.BG4.SCADDR = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG4_SCADDR);
|
||||
si.BG.BG1.TDADDR = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG1_TDADDR);
|
||||
si.BG.BG2.TDADDR = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG2_TDADDR);
|
||||
si.BG.BG3.TDADDR = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG3_TDADDR);
|
||||
si.BG.BG4.TDADDR = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG4_TDADDR);
|
||||
|
||||
si.BG.BG1.MainEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.TM_BG1) == 1;
|
||||
si.BG.BG2.MainEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.TM_BG2) == 1;
|
||||
si.BG.BG3.MainEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.TM_BG3) == 1;
|
||||
si.BG.BG4.MainEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.TM_BG4) == 1;
|
||||
si.BG.BG1.SubEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.TS_BG1) == 1;
|
||||
si.BG.BG2.SubEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.TS_BG2) == 1;
|
||||
si.BG.BG3.SubEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.TS_BG3) == 1;
|
||||
si.BG.BG4.SubEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.TS_BG4) == 1;
|
||||
si.BG.BG1.MathEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_BG1) == 1;
|
||||
si.BG.BG2.MathEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_BG2) == 1;
|
||||
si.BG.BG3.MathEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_BG3) == 1;
|
||||
si.BG.BG4.MathEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_BG4) == 1;
|
||||
si.BG.BG1.MainEnabled = api.snes_peek_logical_register(LibsnesApi.SNES_REG.TM_BG1) == 1;
|
||||
si.BG.BG2.MainEnabled = api.snes_peek_logical_register(LibsnesApi.SNES_REG.TM_BG2) == 1;
|
||||
si.BG.BG3.MainEnabled = api.snes_peek_logical_register(LibsnesApi.SNES_REG.TM_BG3) == 1;
|
||||
si.BG.BG4.MainEnabled = api.snes_peek_logical_register(LibsnesApi.SNES_REG.TM_BG4) == 1;
|
||||
si.BG.BG1.SubEnabled = api.snes_peek_logical_register(LibsnesApi.SNES_REG.TS_BG1) == 1;
|
||||
si.BG.BG2.SubEnabled = api.snes_peek_logical_register(LibsnesApi.SNES_REG.TS_BG2) == 1;
|
||||
si.BG.BG3.SubEnabled = api.snes_peek_logical_register(LibsnesApi.SNES_REG.TS_BG3) == 1;
|
||||
si.BG.BG4.SubEnabled = api.snes_peek_logical_register(LibsnesApi.SNES_REG.TS_BG4) == 1;
|
||||
si.BG.BG1.MathEnabled = api.snes_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_BG1) == 1;
|
||||
si.BG.BG2.MathEnabled = api.snes_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_BG2) == 1;
|
||||
si.BG.BG3.MathEnabled = api.snes_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_BG3) == 1;
|
||||
si.BG.BG4.MathEnabled = api.snes_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_BG4) == 1;
|
||||
|
||||
si.BG.BG1.HOFS = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1HOFS);
|
||||
si.BG.BG1.VOFS = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1VOFS);
|
||||
si.BG.BG2.HOFS = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2HOFS);
|
||||
si.BG.BG2.VOFS = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2VOFS);
|
||||
si.BG.BG3.HOFS = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3HOFS);
|
||||
si.BG.BG3.VOFS = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3VOFS);
|
||||
si.BG.BG4.HOFS = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4HOFS);
|
||||
si.BG.BG4.VOFS = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4VOFS);
|
||||
si.BG.BG1.HOFS = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG1HOFS);
|
||||
si.BG.BG1.VOFS = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG1VOFS);
|
||||
si.BG.BG2.HOFS = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG2HOFS);
|
||||
si.BG.BG2.VOFS = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG2VOFS);
|
||||
si.BG.BG3.HOFS = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG3HOFS);
|
||||
si.BG.BG3.VOFS = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG3VOFS);
|
||||
si.BG.BG4.HOFS = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG4HOFS);
|
||||
si.BG.BG4.VOFS = api.snes_peek_logical_register(LibsnesApi.SNES_REG.BG4VOFS);
|
||||
|
||||
si.M7HOFS = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7HOFS);
|
||||
si.M7VOFS = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7VOFS);
|
||||
si.M7A = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7A);
|
||||
si.M7B = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7B);
|
||||
si.M7C = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7C);
|
||||
si.M7D = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7D);
|
||||
si.M7X = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7X);
|
||||
si.M7Y = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7Y);
|
||||
si.M7Y = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7Y);
|
||||
si.M7SEL_REPEAT = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7SEL_REPEAT);
|
||||
si.M7SEL_HFLIP = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7SEL_HFLIP)!=0;
|
||||
si.M7SEL_VFLIP = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7SEL_VFLIP)!=0;
|
||||
si.M7HOFS = api.snes_peek_logical_register(LibsnesApi.SNES_REG.M7HOFS);
|
||||
si.M7VOFS = api.snes_peek_logical_register(LibsnesApi.SNES_REG.M7VOFS);
|
||||
si.M7A = api.snes_peek_logical_register(LibsnesApi.SNES_REG.M7A);
|
||||
si.M7B = api.snes_peek_logical_register(LibsnesApi.SNES_REG.M7B);
|
||||
si.M7C = api.snes_peek_logical_register(LibsnesApi.SNES_REG.M7C);
|
||||
si.M7D = api.snes_peek_logical_register(LibsnesApi.SNES_REG.M7D);
|
||||
si.M7X = api.snes_peek_logical_register(LibsnesApi.SNES_REG.M7X);
|
||||
si.M7Y = api.snes_peek_logical_register(LibsnesApi.SNES_REG.M7Y);
|
||||
si.M7Y = api.snes_peek_logical_register(LibsnesApi.SNES_REG.M7Y);
|
||||
si.M7SEL_REPEAT = api.snes_peek_logical_register(LibsnesApi.SNES_REG.M7SEL_REPEAT);
|
||||
si.M7SEL_HFLIP = api.snes_peek_logical_register(LibsnesApi.SNES_REG.M7SEL_HFLIP)!=0;
|
||||
si.M7SEL_VFLIP = api.snes_peek_logical_register(LibsnesApi.SNES_REG.M7SEL_VFLIP)!=0;
|
||||
|
||||
for (int i = 1; i <= 4; i++)
|
||||
{
|
||||
|
@ -534,7 +534,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
|
||||
public ScreenInfo ScanScreenInfo()
|
||||
{
|
||||
return ScreenInfo.GetScreenInfo();
|
||||
return ScreenInfo.GetScreenInfo(api);
|
||||
}
|
||||
|
||||
//the same basic color table that libsnes uses to convert from snes 555 to rgba32
|
||||
|
@ -558,18 +558,27 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
int[] colortable;
|
||||
public byte* vram, oam;
|
||||
public ushort* cgram, vram16;
|
||||
public SNESGraphicsDecoder(SnesColors.ColorType pal)
|
||||
|
||||
LibsnesApi api;
|
||||
|
||||
public SNESGraphicsDecoder(LibsnesApi api, SnesColors.ColorType pal)
|
||||
{
|
||||
this.api = api;
|
||||
colortable = SnesColors.GetLUT(pal);
|
||||
IntPtr block = LibsnesDll.snes_get_memory_data(LibsnesDll.SNES_MEMORY.VRAM);
|
||||
IntPtr block = (IntPtr)api.snes_get_memory_data(LibsnesApi.SNES_MEMORY.VRAM);
|
||||
vram = (byte*)block;
|
||||
vram16 = (ushort*)block;
|
||||
block = LibsnesDll.snes_get_memory_data(LibsnesDll.SNES_MEMORY.CGRAM);
|
||||
block = (IntPtr)api.snes_get_memory_data(LibsnesApi.SNES_MEMORY.CGRAM);
|
||||
cgram = (ushort*)block;
|
||||
block = LibsnesDll.snes_get_memory_data(LibsnesDll.SNES_MEMORY.OAM);
|
||||
block = (IntPtr)api.snes_get_memory_data(LibsnesApi.SNES_MEMORY.OAM);
|
||||
oam = (byte*)block;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
//todo - unhook from api?
|
||||
}
|
||||
|
||||
public struct TileEntry
|
||||
{
|
||||
public ushort tilenum;
|
||||
|
@ -783,7 +792,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
|||
public void CacheTiles()
|
||||
{
|
||||
//generate 2bpp tiles
|
||||
int numtiles = 8192;
|
||||
int numtiles = 65536/8/2;
|
||||
int[] tiles = new int[8 * 8 * numtiles];
|
||||
_tileCache[2] = tiles;
|
||||
for (int i = 0; i < numtiles; i++)
|
||||
|
|
|
@ -15,6 +15,9 @@ namespace BizHawk
|
|||
public string SNES_FirmwaresPath;
|
||||
public string C64_FirmwaresPath;
|
||||
|
||||
public string SNES_ExePath;
|
||||
public string SNES_Profile;
|
||||
|
||||
public bool SNES_ShowBG1_0, SNES_ShowBG2_0, SNES_ShowBG3_0, SNES_ShowBG4_0;
|
||||
public bool SNES_ShowBG1_1, SNES_ShowBG2_1, SNES_ShowBG3_1, SNES_ShowBG4_1;
|
||||
public bool SNES_ShowOBJ_0, SNES_ShowOBJ_1, SNES_ShowOBJ_2, SNES_ShowOBJ_3;
|
||||
|
|
|
@ -12,6 +12,14 @@ namespace BizHawk
|
|||
{
|
||||
public static class Extensions
|
||||
{
|
||||
public static string GetDirectory(this Assembly asm)
|
||||
{
|
||||
string codeBase = asm.CodeBase;
|
||||
UriBuilder uri = new UriBuilder(codeBase);
|
||||
string path = Uri.UnescapeDataString(uri.Path);
|
||||
return Path.GetDirectoryName(path);
|
||||
}
|
||||
|
||||
public static int LowerBoundBinarySearch<T, TKey>(this IList<T> list, Func<T, TKey> keySelector, TKey key) where TKey : IComparable<TKey>
|
||||
{
|
||||
int min = 0;
|
||||
|
@ -491,6 +499,18 @@ namespace BizHawk
|
|||
return System.Text.Encoding.UTF8.GetString(read);
|
||||
}
|
||||
|
||||
public static string ReadStringAsciiZ(this BinaryReader r)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(;;)
|
||||
{
|
||||
int b = r.ReadByte();
|
||||
if(b <= 0) break;
|
||||
sb.Append((char)b);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// conerts bytes to an uppercase string of hex numbers in upper case without any spacing or anything
|
||||
/// //could be extension method
|
||||
|
|
|
@ -395,6 +395,12 @@
|
|||
<Compile Include="SNESTools\SNESGraphicsViewer.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="SNESTools\SNESOptions.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="SNESTools\SNESOptions.Designer.cs">
|
||||
<DependentUpon>SNESOptions.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="tools\HexColor.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
@ -561,6 +567,9 @@
|
|||
<EmbeddedResource Include="SNESTools\SNESGraphicsDebugger.resx">
|
||||
<DependentUpon>SNESGraphicsDebugger.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="SNESTools\SNESOptions.resx">
|
||||
<DependentUpon>SNESOptions.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="tools\HexColor.resx">
|
||||
<DependentUpon>HexColor.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
|
|
@ -743,6 +743,7 @@ namespace BizHawk.MultiClient
|
|||
public SNESControllerTemplate[] SNESController = new SNESControllerTemplate[4];
|
||||
public SNESControllerTemplate[] SNESAutoController = new SNESControllerTemplate[4];
|
||||
public NESConsoleButtonTemplate SNESConsoleButtons = new NESConsoleButtonTemplate();
|
||||
public string SNESProfile = "Compatibility";
|
||||
|
||||
//TI 83 settings
|
||||
public TI83ControllerTemplate[] TI83Controller = new TI83ControllerTemplate[1];
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1811,6 +1811,18 @@ namespace BizHawk.MultiClient
|
|||
LoadSNESGraphicsDebugger();
|
||||
}
|
||||
|
||||
private void miSnesOptions_Click(object sender, EventArgs e)
|
||||
{
|
||||
var so = new SNESOptions();
|
||||
so.Profile = Global.Config.SNESProfile;
|
||||
if (so.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
||||
{
|
||||
bool reboot = Global.Config.SNESProfile != so.Profile;
|
||||
Global.Config.SNESProfile = so.Profile;
|
||||
if (reboot) FlagNeedsReboot();
|
||||
}
|
||||
}
|
||||
|
||||
private void SNES_ToggleBG1()
|
||||
{
|
||||
if (Global.Emulator is LibsnesCore)
|
||||
|
|
|
@ -5,6 +5,7 @@ using System.Drawing;
|
|||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using System.Diagnostics;
|
||||
using BizHawk.Core;
|
||||
using BizHawk.DiscSystem;
|
||||
using BizHawk.Emulation.Consoles.Sega;
|
||||
|
@ -26,7 +27,7 @@ namespace BizHawk.MultiClient
|
|||
|
||||
public partial class MainForm : Form
|
||||
{
|
||||
public bool INTERIM = true;
|
||||
public static bool INTERIM = true;
|
||||
public const string EMUVERSION = "Version " + VersionInfo.MAINVERSION;
|
||||
public const string RELEASEDATE = "December 23, 2012";
|
||||
private Control renderTarget;
|
||||
|
@ -359,6 +360,33 @@ namespace BizHawk.MultiClient
|
|||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//contains a mapping: profilename->exepath ; or null if the exe wasnt available
|
||||
Dictionary<string, string> SNES_prepared = new Dictionary<string, string>();
|
||||
string SNES_Prepare(string profile)
|
||||
{
|
||||
SNES_Check(profile);
|
||||
if (SNES_prepared[profile] == null)
|
||||
{
|
||||
throw new InvalidOperationException("Couldn't locate the executable for SNES emulation for profile: " + profile + ". Please make sure you're using a fresh dearchive of a BizHawk distribution.");
|
||||
}
|
||||
return SNES_prepared[profile];
|
||||
}
|
||||
void SNES_Check(string profile)
|
||||
{
|
||||
if (SNES_prepared.ContainsKey(profile)) return;
|
||||
string exename = "libsneshawk-" + profile.ToLower() + ".exe";
|
||||
|
||||
string thisDir = PathManager.GetExeDirectoryAbsolute();
|
||||
string exePath = Path.Combine(thisDir, exename);
|
||||
if (!File.Exists(exePath))
|
||||
exePath = Path.Combine(Path.Combine(thisDir, "dll"), exename);
|
||||
|
||||
if (!File.Exists(exePath))
|
||||
exePath = null;
|
||||
|
||||
SNES_prepared[profile] = exePath;
|
||||
}
|
||||
|
||||
public void SyncCoreCommInputSignals(CoreComm target)
|
||||
{
|
||||
target.NES_BackdropColor = Global.Config.NESBackgroundColor;
|
||||
|
@ -390,6 +418,8 @@ namespace BizHawk.MultiClient
|
|||
target.SNES_ShowOBJ_2 = Global.Config.SNES_ShowOBJ3;
|
||||
target.SNES_ShowOBJ_3 = Global.Config.SNES_ShowOBJ4;
|
||||
|
||||
target.SNES_Profile = Global.Config.SNESProfile;
|
||||
|
||||
target.GG_HighlightActiveDisplayRegion = Global.Config.GGHighlightActiveDisplayRegion;
|
||||
target.GG_ShowClippedRegions = Global.Config.GGShowClippedRegions;
|
||||
|
||||
|
@ -1843,6 +1873,7 @@ namespace BizHawk.MultiClient
|
|||
case "SNES":
|
||||
{
|
||||
game.System = "SNES";
|
||||
nextComm.SNES_ExePath = SNES_Prepare(Global.Config.SNESProfile);
|
||||
var snes = new LibsnesCore(nextComm);
|
||||
nextEmulator = snes;
|
||||
snes.Load(game, rom.FileData, null, deterministicemulation);
|
||||
|
@ -1968,6 +1999,7 @@ namespace BizHawk.MultiClient
|
|||
{
|
||||
game.System = "SNES";
|
||||
game.AddOption("SGB");
|
||||
nextComm.SNES_ExePath = SNES_Prepare(Global.Config.SNESProfile);
|
||||
var snes = new LibsnesCore(nextComm);
|
||||
nextEmulator = snes;
|
||||
game.FirmwareHash = Util.BytesToHexString(System.Security.Cryptography.SHA1.Create().ComputeHash(sgbrom));
|
||||
|
@ -4933,5 +4965,7 @@ namespace BizHawk.MultiClient
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ namespace BizHawk.MultiClient
|
|||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
|
||||
// catch morons who mix versions
|
||||
// zero 25-dec-2012 - only do for public builds. its annoying during development
|
||||
if(!MainForm.INTERIM)
|
||||
{
|
||||
var thisversion = typeof(Program).Assembly.GetName().Version;
|
||||
var utilversion = typeof(InputValidate).Assembly.GetName().Version;
|
||||
|
|
|
@ -191,7 +191,7 @@ namespace BizHawk.MultiClient
|
|||
}
|
||||
}
|
||||
|
||||
SNESGraphicsDecoder gd = new SNESGraphicsDecoder(SnesColors.ColorType.BizHawk);
|
||||
SNESGraphicsDecoder gd;
|
||||
SNESGraphicsDecoder.ScreenInfo si;
|
||||
SNESGraphicsDecoder.TileEntry[] map;
|
||||
byte[,] spriteMap = new byte[256, 224];
|
||||
|
@ -199,6 +199,7 @@ namespace BizHawk.MultiClient
|
|||
|
||||
void RegenerateData()
|
||||
{
|
||||
if (gd != null) gd.Dispose();
|
||||
gd = null;
|
||||
if (currentSnesCore == null) return;
|
||||
gd = NewDecoder();
|
||||
|
@ -663,14 +664,15 @@ namespace BizHawk.MultiClient
|
|||
|
||||
SNESGraphicsDecoder NewDecoder()
|
||||
{
|
||||
//wtf to do? now we need an api all the time
|
||||
if (currentSnesCore != null)
|
||||
return new SNESGraphicsDecoder(currentSnesCore.CurrPalette);
|
||||
else return new SNESGraphicsDecoder(SnesColors.ColorType.BizHawk);
|
||||
return new SNESGraphicsDecoder(currentSnesCore.api, currentSnesCore.CurrPalette);
|
||||
else return new SNESGraphicsDecoder(currentSnesCore.api, SnesColors.ColorType.BizHawk);
|
||||
}
|
||||
|
||||
void RenderPalette()
|
||||
{
|
||||
var gd = NewDecoder();
|
||||
//var gd = NewDecoder(); //??
|
||||
lastPalette = gd.GetPalette();
|
||||
|
||||
int pixsize = paletteCellSize * 16 + paletteCellSpacing * 17;
|
||||
|
@ -792,7 +794,7 @@ namespace BizHawk.MultiClient
|
|||
if (lastPalette == null) return;
|
||||
|
||||
int rgb555 = lastPalette[lastColorNum];
|
||||
var gd = NewDecoder();
|
||||
//var gd = NewDecoder(); //??
|
||||
int color = gd.Colorize(rgb555);
|
||||
pnDetailsPaletteColor.BackColor = Color.FromArgb(color);
|
||||
|
||||
|
@ -1239,15 +1241,16 @@ namespace BizHawk.MultiClient
|
|||
|
||||
void SyncBackdropColor()
|
||||
{
|
||||
if (checkBackdropColor.Checked)
|
||||
{
|
||||
int col = DecodeWinformsColorToSNES(pnBackdropColor.BackColor);
|
||||
LibsnesDll.snes_set_backdropColor(col);
|
||||
}
|
||||
else
|
||||
{
|
||||
LibsnesDll.snes_set_backdropColor(-1);
|
||||
}
|
||||
//TODO
|
||||
//if (checkBackdropColor.Checked)
|
||||
//{
|
||||
// int col = DecodeWinformsColorToSNES(pnBackdropColor.BackColor);
|
||||
// LibsnesDll.snes_set_backdropColor(col);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// LibsnesDll.snes_set_backdropColor(-1);
|
||||
//}
|
||||
}
|
||||
|
||||
private void checkBackdropColor_CheckedChanged(object sender, EventArgs e)
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
namespace BizHawk.MultiClient
|
||||
{
|
||||
partial class SNESOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.btnOk = new System.Windows.Forms.Button();
|
||||
this.btnCancel = new System.Windows.Forms.Button();
|
||||
this.rbCompatibility = new System.Windows.Forms.RadioButton();
|
||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
this.rbPerformance = new System.Windows.Forms.RadioButton();
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// btnOk
|
||||
//
|
||||
this.btnOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnOk.Location = new System.Drawing.Point(141, 102);
|
||||
this.btnOk.Name = "btnOk";
|
||||
this.btnOk.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnOk.TabIndex = 0;
|
||||
this.btnOk.Text = "OK";
|
||||
this.btnOk.UseVisualStyleBackColor = true;
|
||||
this.btnOk.Click += new System.EventHandler(this.btnOk_Click);
|
||||
//
|
||||
// btnCancel
|
||||
//
|
||||
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.btnCancel.Location = new System.Drawing.Point(222, 102);
|
||||
this.btnCancel.Name = "btnCancel";
|
||||
this.btnCancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnCancel.TabIndex = 1;
|
||||
this.btnCancel.Text = "Cancel";
|
||||
this.btnCancel.UseVisualStyleBackColor = true;
|
||||
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
|
||||
//
|
||||
// rbCompatibility
|
||||
//
|
||||
this.rbCompatibility.AutoSize = true;
|
||||
this.rbCompatibility.Location = new System.Drawing.Point(6, 19);
|
||||
this.rbCompatibility.Name = "rbCompatibility";
|
||||
this.rbCompatibility.Size = new System.Drawing.Size(83, 17);
|
||||
this.rbCompatibility.TabIndex = 2;
|
||||
this.rbCompatibility.TabStop = true;
|
||||
this.rbCompatibility.Text = "Compatibility";
|
||||
this.rbCompatibility.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// groupBox1
|
||||
//
|
||||
this.groupBox1.Controls.Add(this.rbPerformance);
|
||||
this.groupBox1.Controls.Add(this.rbCompatibility);
|
||||
this.groupBox1.Location = new System.Drawing.Point(12, 12);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(277, 70);
|
||||
this.groupBox1.TabIndex = 3;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "Core Selection";
|
||||
//
|
||||
// rbPerformance
|
||||
//
|
||||
this.rbPerformance.AutoSize = true;
|
||||
this.rbPerformance.Location = new System.Drawing.Point(6, 42);
|
||||
this.rbPerformance.Name = "rbPerformance";
|
||||
this.rbPerformance.Size = new System.Drawing.Size(202, 17);
|
||||
this.rbPerformance.TabIndex = 3;
|
||||
this.rbPerformance.TabStop = true;
|
||||
this.rbPerformance.Text = "Performance (only for casual gaming!)";
|
||||
this.rbPerformance.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// SNESOptions
|
||||
//
|
||||
this.AcceptButton = this.btnOk;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.btnCancel;
|
||||
this.ClientSize = new System.Drawing.Size(300, 128);
|
||||
this.Controls.Add(this.groupBox1);
|
||||
this.Controls.Add(this.btnCancel);
|
||||
this.Controls.Add(this.btnOk);
|
||||
this.Name = "SNESOptions";
|
||||
this.Text = "SNESOptions";
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
this.groupBox1.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button btnOk;
|
||||
private System.Windows.Forms.Button btnCancel;
|
||||
private System.Windows.Forms.RadioButton rbCompatibility;
|
||||
private System.Windows.Forms.GroupBox groupBox1;
|
||||
private System.Windows.Forms.RadioButton rbPerformance;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BizHawk.MultiClient
|
||||
{
|
||||
public partial class SNESOptions : Form
|
||||
{
|
||||
public SNESOptions()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public string Profile
|
||||
{
|
||||
get { return rbCompatibility.Checked ? "Compatibility" : "Performance"; }
|
||||
set
|
||||
{
|
||||
rbCompatibility.Checked = (value == "Compatibility");
|
||||
rbPerformance.Checked = (value == "Performance");
|
||||
}
|
||||
}
|
||||
|
||||
private void btnOk_Click(object sender, EventArgs e)
|
||||
{
|
||||
DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void btnCancel_Click(object sender, EventArgs e)
|
||||
{
|
||||
DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
|
@ -151,7 +151,7 @@ namespace BizHawk.MultiClient
|
|||
|
||||
SetTabByPlatform();
|
||||
|
||||
if (!Global.MainForm.INTERIM)
|
||||
if (!MainForm.INTERIM)
|
||||
{
|
||||
PlatformTabControl.Controls.Remove(tabPageC64);
|
||||
PlatformTabControl.Controls.Remove(tabPageGBA);
|
||||
|
|
|
@ -176,7 +176,7 @@ namespace BizHawk.MultiClient
|
|||
|
||||
SetTabByPlatform();
|
||||
|
||||
if (!Global.MainForm.INTERIM)
|
||||
if (!MainForm.INTERIM)
|
||||
{
|
||||
tabControl1.Controls.Remove(tabPageIntellivision);
|
||||
tabControl1.Controls.Remove(tabPageC64);
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace BizHawk.MultiClient
|
|||
UpdateSoundDialog();
|
||||
|
||||
// to be removed
|
||||
//if (Global.MainForm.INTERIM)
|
||||
//if (MainForm.INTERIM)
|
||||
//{
|
||||
// ThrottlecheckBox.Visible = true;
|
||||
//}
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -103,10 +103,10 @@ namespace BizHawk.MultiClient
|
|||
}
|
||||
}
|
||||
|
||||
newStripButton1.Visible = Global.MainForm.INTERIM;
|
||||
newScriptToolStripMenuItem.Visible = Global.MainForm.INTERIM;
|
||||
newStripButton1.Enabled = Global.MainForm.INTERIM;
|
||||
newScriptToolStripMenuItem.Enabled = Global.MainForm.INTERIM;
|
||||
newStripButton1.Visible = MainForm.INTERIM;
|
||||
newScriptToolStripMenuItem.Visible = MainForm.INTERIM;
|
||||
newStripButton1.Enabled = MainForm.INTERIM;
|
||||
newScriptToolStripMenuItem.Enabled = MainForm.INTERIM;
|
||||
}
|
||||
|
||||
private void StopScript(int x)
|
||||
|
@ -708,7 +708,7 @@ namespace BizHawk.MultiClient
|
|||
|
||||
private void EditToolstripButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (Global.MainForm.INTERIM)
|
||||
if (MainForm.INTERIM)
|
||||
{
|
||||
DoLuaWriter();
|
||||
}
|
||||
|
|
|
@ -185,7 +185,7 @@ namespace BizHawk.MultiClient
|
|||
|
||||
private void TAStudio_Load(object sender, EventArgs e)
|
||||
{
|
||||
if (!Global.MainForm.INTERIM)
|
||||
if (!MainForm.INTERIM)
|
||||
{
|
||||
newProjectToolStripMenuItem.Enabled = false;
|
||||
openProjectToolStripMenuItem.Enabled = false;
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
cd bsnes
|
||||
mkdir obj
|
||||
mkdir out
|
||||
export BIZWINCFLAGS="-I. -O3 -masm=intel -DLIBCO_IMPORT -DLIBCO_MSVC -static-libgcc -static-libstdc++"
|
||||
#for gdb debugging
|
||||
#export BIZWINCFLAGS="-I. -O0 -g -masm=intel -DLIBCO_IMPORT -DLIBCO_MSVC -static-libgcc -static-libstdc++"
|
||||
export TARGET_LIBSNES_LIBDEPS="-L ../libco_msvc_win32/release/ -llibco_msvc_win32 -static-libgcc -static-libstdc++"
|
||||
profile=compatibility platform=win target=libsnes make -e -j 4
|
||||
cd ..
|
||||
cp bsnes/out/snes.dll ../BizHawk.MultiClient/output/dll/libsneshawk.dll
|
||||
#!/bin/sh
|
||||
|
||||
./bizwinmakeone.sh compatibility
|
|
@ -0,0 +1,11 @@
|
|||
#this is for using the dll libco, and so the threads implementation can be used, for easier debugging
|
||||
cd bsnes
|
||||
mkdir obj
|
||||
mkdir out
|
||||
export BIZWINCFLAGS="-I. -O3 -masm=intel -DLIBCO_IMPORT -DLIBCO_MSVC -static-libgcc -static-libstdc++"
|
||||
#for gdb debugging
|
||||
#export BIZWINCFLAGS="-I. -O0 -g -masm=intel -DLIBCO_IMPORT -DLIBCO_MSVC -static-libgcc -static-libstdc++"
|
||||
export TARGET_LIBSNES_LIBDEPS="-L ../libco_msvc_win32/release/ -llibco_msvc_win32 -static-libgcc -static-libstdc++"
|
||||
profile=compatibility platform=win target=libsnes make -e -j 4
|
||||
cd ..
|
||||
cp bsnes/out/snes.dll ../BizHawk.MultiClient/output/dll/libsneshawk.dll
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/sh
|
||||
|
||||
#makes all bsnes binaries for distribution
|
||||
#TODO - 64bit
|
||||
|
||||
./bizwinclean.sh
|
||||
./bizwinmakeone.sh performance compress
|
||||
./bizwinclean.sh
|
||||
./bizwinmakeone.sh compatibility compress
|
||||
|
||||
#leave compatibility built as objs because thats more useful to us while devving
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#!/bin/sh -x
|
||||
|
||||
#this is for using the fast libco, hand-coded by byuu. the dll isnt used, and so the threads implementation wont be useful, so it cant be debugged easily
|
||||
cd bsnes
|
||||
mkdir obj
|
||||
mkdir out
|
||||
|
||||
#debug:
|
||||
#export BIZWINCFLAGS="-I. -O0 -g -masm=intel -DLIBCO_IMPORT -DLIBCO_MSVC -static-libgcc -static-libstdc++"
|
||||
|
||||
#not debug
|
||||
export BIZWINCFLAGS="-I. -O3 -masm=intel -static-libgcc -static-libstdc++"
|
||||
|
||||
export TARGET_LIBSNES_LIBDEPS="-L ../libco_msvc_win32/release/ -llibco_msvc_win32 -static-libgcc -static-libstdc++ -Wl,--subsystem,windows"
|
||||
export profile=$1
|
||||
|
||||
platform=win target=libsnes make -e -j 4
|
||||
cd ..
|
||||
|
||||
filename=libsneshawk-${profile}.exe
|
||||
targetdir=../BizHawk.MultiClient/output/dll
|
||||
targetpath=${targetdir}/${filename}
|
||||
cp bsnes/out/${filename} ${targetdir}
|
||||
if [ "$2" == "compress" ]; then
|
||||
upx -9 ${targetpath} ;
|
||||
fi
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
./bizwinmakeone.sh performance
|
|
@ -60,7 +60,7 @@ void Cartridge::load(System::Revision revision, const string &markup, const uint
|
|||
case Mapper::HuC3: mapper = &huc3; break;
|
||||
}
|
||||
|
||||
ramdata = new uint8_t[ramsize = info.ramsize]();
|
||||
ramdata = (uint8_t*)interface->allocSharedMemory("GAME_BOY_RAM",ramsize = info.ramsize);
|
||||
system.load(revision);
|
||||
|
||||
loaded = true;
|
||||
|
@ -71,7 +71,7 @@ void Cartridge::unload() {
|
|||
if(loaded == false) return;
|
||||
|
||||
if(romdata) { delete[] romdata; romdata = 0; }
|
||||
if(ramdata) { delete[] ramdata; ramdata = 0; }
|
||||
if(ramdata) { interface->freeSharedMemory(ramdata); }
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,9 @@ struct Interface {
|
|||
virtual bool inputPoll(unsigned id);
|
||||
|
||||
virtual void message(const string &text);
|
||||
|
||||
virtual void* allocSharedMemory(const char* memtype, size_t amt, int initialByte = -1) = 0;
|
||||
virtual void freeSharedMemory(void* ptr) = 0;
|
||||
};
|
||||
|
||||
extern Interface *interface;
|
||||
|
|
|
@ -74,6 +74,10 @@ namespace nall {
|
|||
}
|
||||
}
|
||||
|
||||
template<typename T> void array(T *array, int size) {
|
||||
for(unsigned n = 0; n < size; n++) integer(array[n]);
|
||||
}
|
||||
|
||||
template<typename T> void array(T &array) {
|
||||
enum { size = sizeof(T) / sizeof(typename std::remove_extent<T>::type) };
|
||||
for(unsigned n = 0; n < size; n++) integer(array[n]);
|
||||
|
|
|
@ -171,11 +171,20 @@ void CPU::reset() {
|
|||
dma_reset();
|
||||
}
|
||||
|
||||
CPU::CPU() : queue(512, { &CPU::queue_event, this }) {
|
||||
CPU::CPU()
|
||||
: queue(512, { &CPU::queue_event, this })
|
||||
, wram(nullptr)
|
||||
{
|
||||
PPUcounter::scanline = { &CPU::scanline, this };
|
||||
}
|
||||
|
||||
CPU::~CPU() {
|
||||
interface()->freeSharedMemory(wram);
|
||||
}
|
||||
|
||||
void CPU::initialize()
|
||||
{
|
||||
wram = (uint8*)interface()->allocSharedMemory("WRAM", 128 * 1024);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class CPU : public Processor, public CPUcore, public PPUcounter {
|
||||
public:
|
||||
uint8 wram[128 * 1024];
|
||||
uint8* wram; //[128 * 1024];
|
||||
|
||||
enum : bool { Threaded = true };
|
||||
array<Processor*> coprocessors;
|
||||
|
@ -30,6 +30,7 @@ public:
|
|||
void serialize(serializer&);
|
||||
CPU();
|
||||
~CPU();
|
||||
void initialize();
|
||||
|
||||
private:
|
||||
//cpu
|
||||
|
|
|
@ -5,7 +5,7 @@ void CPU::serialize(serializer &s) {
|
|||
CPUcore::core_serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
s.array(wram);
|
||||
s.array(wram, 128 * 1024);
|
||||
|
||||
queue.serialize(s);
|
||||
s.array(port_data);
|
||||
|
|
|
@ -19,7 +19,7 @@ void PPU::synchronize_cpu() {
|
|||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All)
|
||||
co_switch(cpu.thread);
|
||||
else if(clock >= 0 && scheduler.sync == Scheduler::SynchronizeMode::All)
|
||||
interface->message("PPU had to advance nondeterministically!");
|
||||
interface()->message("PPU had to advance nondeterministically!");
|
||||
} else {
|
||||
while(clock >= 0) cpu.enter();
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ void PPU::scanline() {
|
|||
regs.range_over = false;
|
||||
}
|
||||
|
||||
interface->scanlineStart(line);
|
||||
interface()->scanlineStart(line);
|
||||
|
||||
if(line == 1) {
|
||||
//mosaic reset
|
||||
|
@ -154,9 +154,9 @@ void PPU::power() {
|
|||
ppu1_version = config.ppu1.version;
|
||||
ppu2_version = config.ppu2.version;
|
||||
|
||||
for(auto &n : vram) n = 0x00;
|
||||
for(auto &n : oam) n = 0x00;
|
||||
for(auto &n : cgram) n = 0x00;
|
||||
for(int i=0;i<128*1024;i++) vram[i] = 0;
|
||||
for(int i=0;i<544;i++) oam[i] = 0;
|
||||
for(int i=0;i<512;i++) cgram[i] = 0;
|
||||
flush_tiledata_cache();
|
||||
|
||||
region = (system.region() == System::Region::NTSC ? 0 : 1); //0 = NTSC, 1 = PAL
|
||||
|
@ -431,7 +431,20 @@ void PPU::set_frameskip(unsigned frameskip_) {
|
|||
framecounter = 0;
|
||||
}
|
||||
|
||||
PPU::PPU() {
|
||||
PPU::PPU()
|
||||
: vram(nullptr)
|
||||
, oam(nullptr)
|
||||
, cgram(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PPU::initialize()
|
||||
{
|
||||
vram = (uint8*)interface()->allocSharedMemory("VRAM",128 * 1024);
|
||||
oam = (uint8*)interface()->allocSharedMemory("OAM",544);
|
||||
cgram = (uint8*)interface()->allocSharedMemory("CGRAM",512);
|
||||
|
||||
surface = new uint32[512 * 512];
|
||||
output = surface + 16 * 512;
|
||||
|
||||
|
@ -462,6 +475,9 @@ PPU::PPU() {
|
|||
PPU::~PPU() {
|
||||
delete[] surface;
|
||||
free_tiledata_cache();
|
||||
interface()->freeSharedMemory(vram);
|
||||
interface()->freeSharedMemory(oam);
|
||||
interface()->freeSharedMemory(cgram);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
class PPU : public Processor, public PPUcounter {
|
||||
public:
|
||||
uint8 vram[128 * 1024];
|
||||
uint8 oam[544];
|
||||
uint8 cgram[512];
|
||||
uint8* vram; //[128 * 1024]
|
||||
uint8* oam; //[544]
|
||||
uint8* cgram; //[512]
|
||||
|
||||
enum : bool { Threaded = true };
|
||||
alwaysinline void step(unsigned clocks);
|
||||
|
@ -76,6 +76,7 @@ public:
|
|||
void set_frameskip(unsigned frameskip);
|
||||
|
||||
void serialize(serializer&);
|
||||
void initialize();
|
||||
PPU();
|
||||
~PPU();
|
||||
};
|
||||
|
|
|
@ -104,7 +104,7 @@ void PPU::flush_pixel_cache() {
|
|||
|
||||
uint16 main;
|
||||
|
||||
int backdropColor = interface->getBackdropColor();
|
||||
int backdropColor = interface()->getBackdropColor();
|
||||
if(backdropColor == -1)
|
||||
main = get_palette(0);
|
||||
else main = backdropColor;
|
||||
|
|
|
@ -16,9 +16,9 @@ void PPU::serialize(serializer &s) {
|
|||
Processor::serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
s.array(vram);
|
||||
s.array(oam);
|
||||
s.array(cgram);
|
||||
s.array(vram,128 * 1024);
|
||||
s.array(oam,544);
|
||||
s.array(cgram,512);
|
||||
|
||||
s.integer(ppu1_version);
|
||||
s.integer(ppu2_version);
|
||||
|
@ -156,6 +156,7 @@ void PPU::serialize(serializer &s) {
|
|||
s.integer(pixel_cache[n].pri_sub);
|
||||
}
|
||||
|
||||
//zero TODO - only on load
|
||||
//better to just take a small speed hit than store all of bg_tiledata[3][] ...
|
||||
flush_tiledata_cache();
|
||||
|
||||
|
|
|
@ -90,9 +90,9 @@ void PPU::enable() {
|
|||
}
|
||||
|
||||
void PPU::power() {
|
||||
for(auto &n : vram) n = 0;
|
||||
for(auto &n : oam) n = 0;
|
||||
for(auto &n : cgram) n = 0;
|
||||
for(int i=0;i<128*1024;i++) vram[i] = 0;
|
||||
for(int i=0;i<544;i++) oam[i] = 0;
|
||||
for(int i=0;i<512;i++) cgram[i] = 0;
|
||||
reset();
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,11 @@ bg2(*this, Background::ID::BG2),
|
|||
bg3(*this, Background::ID::BG3),
|
||||
bg4(*this, Background::ID::BG4),
|
||||
sprite(*this),
|
||||
screen(*this) {
|
||||
screen(*this),
|
||||
vram(nullptr),
|
||||
oam(nullptr),
|
||||
cgram(nullptr)
|
||||
{
|
||||
surface = new uint32[512 * 512];
|
||||
output = surface + 16 * 512;
|
||||
display.width = 256;
|
||||
|
@ -145,6 +149,16 @@ screen(*this) {
|
|||
|
||||
PPU::~PPU() {
|
||||
delete[] surface;
|
||||
interface()->freeSharedMemory(vram);
|
||||
interface()->freeSharedMemory(oam);
|
||||
interface()->freeSharedMemory(cgram);
|
||||
}
|
||||
|
||||
void PPU::initialize()
|
||||
{
|
||||
vram = (uint8*)interface()->allocSharedMemory("VRAM",128 * 1024);
|
||||
oam = (uint8*)interface()->allocSharedMemory("OAM",544);
|
||||
cgram = (uint8*)interface()->allocSharedMemory("CGRAM",512);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
class PPU : public Processor, public PPUcounter {
|
||||
public:
|
||||
uint8 vram[64 * 1024];
|
||||
uint8 oam[544];
|
||||
uint8 cgram[512];
|
||||
uint8 *vram; //[64 * 1024];
|
||||
uint8 *oam; //[544];
|
||||
uint8 *cgram; //[512];
|
||||
|
||||
enum : bool { Threaded = true };
|
||||
alwaysinline void step(unsigned clocks);
|
||||
|
@ -26,6 +26,7 @@ public:
|
|||
void serialize(serializer&);
|
||||
PPU();
|
||||
~PPU();
|
||||
void initialize();
|
||||
|
||||
private:
|
||||
uint32 *surface;
|
||||
|
|
|
@ -138,11 +138,21 @@ void SMP::serialize(serializer &s) {
|
|||
s.integer(timer2.stage3_ticks);
|
||||
}
|
||||
|
||||
SMP::SMP() {
|
||||
apuram = new uint8[64 * 1024];
|
||||
SMP::SMP() :
|
||||
apuram(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SMP::~SMP() {
|
||||
interface()->freeSharedMemory(apuram);
|
||||
}
|
||||
|
||||
void SMP::initialize()
|
||||
{
|
||||
apuram = (uint8*)interface()->allocSharedMemory("APURAM", 64 * 1024);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ public:
|
|||
void serialize(serializer&);
|
||||
SMP();
|
||||
~SMP();
|
||||
void initialize();
|
||||
|
||||
void disassemble_opcode(char *output, uint16 addr);
|
||||
|
||||
|
|
|
@ -37,7 +37,8 @@ void Cartridge::load(Mode cartridge_mode, const char *markup) {
|
|||
//print(markup, "\n\n");
|
||||
|
||||
if(ram_size > 0) {
|
||||
ram.map(allocate<uint8>(ram_size, 0xff), ram_size);
|
||||
uint8* buf = (uint8*)interface()->allocSharedMemory("CARTRIDGE_RAM",ram_size,0xff);
|
||||
ram.map(buf, ram_size);
|
||||
nvram.append({ "program.ram", ram.data(), ram.size() });
|
||||
}
|
||||
|
||||
|
@ -80,7 +81,10 @@ void Cartridge::unload() {
|
|||
loaded = false;
|
||||
}
|
||||
|
||||
Cartridge::Cartridge() {
|
||||
Cartridge::Cartridge()
|
||||
: rom()
|
||||
, ram("CARTRIDGE_RAM")
|
||||
{
|
||||
loaded = false;
|
||||
unload();
|
||||
}
|
||||
|
|
|
@ -223,16 +223,16 @@ void Cartridge::parse_markup_necdsp(XML::Node &root) {
|
|||
string firmware = root["firmware"].data;
|
||||
string sha256 = root["sha256"].data;
|
||||
|
||||
string path = interface->path(Slot::Base, firmware);
|
||||
string path = interface()->path(Slot::Base, firmware);
|
||||
unsigned promsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 2048 : 16384);
|
||||
unsigned dromsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 1024 : 2048);
|
||||
unsigned filesize = promsize * 3 + dromsize * 2;
|
||||
|
||||
file fp;
|
||||
if(fp.open(path, file::mode::read) == false) {
|
||||
interface->message({ "Warning: NEC DSP firmware ", firmware, " is missing." });
|
||||
interface()->message({ "Warning: NEC DSP firmware ", firmware, " is missing." });
|
||||
} else if(fp.size() != filesize) {
|
||||
interface->message({ "Warning: NEC DSP firmware ", firmware, " is of the wrong file size." });
|
||||
interface()->message({ "Warning: NEC DSP firmware ", firmware, " is of the wrong file size." });
|
||||
fp.close();
|
||||
} else {
|
||||
for(unsigned n = 0; n < promsize; n++) necdsp.programROM[n] = fp.readl(3);
|
||||
|
@ -245,7 +245,7 @@ void Cartridge::parse_markup_necdsp(XML::Node &root) {
|
|||
fp.read(data, filesize);
|
||||
|
||||
if(sha256 != nall::sha256(data, filesize)) {
|
||||
interface->message({ "Warning: NEC DSP firmware ", firmware, " SHA256 sum is incorrect." });
|
||||
interface()->message({ "Warning: NEC DSP firmware ", firmware, " SHA256 sum is incorrect." });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -288,12 +288,12 @@ void Cartridge::parse_markup_hitachidsp(XML::Node &root) {
|
|||
string firmware = root["firmware"].data;
|
||||
string sha256 = root["sha256"].data;
|
||||
|
||||
string path = interface->path(Slot::Base, firmware);
|
||||
string path = interface()->path(Slot::Base, firmware);
|
||||
file fp;
|
||||
if(fp.open(path, file::mode::read) == false) {
|
||||
interface->message({ "Warning: Hitachi DSP firmware ", firmware, " is missing." });
|
||||
interface()->message({ "Warning: Hitachi DSP firmware ", firmware, " is missing." });
|
||||
} else if(fp.size() != 1024 * 3) {
|
||||
interface->message({ "Warning: Hitachi DSP firmware ", firmware, " is of the wrong file size." });
|
||||
interface()->message({ "Warning: Hitachi DSP firmware ", firmware, " is of the wrong file size." });
|
||||
fp.close();
|
||||
} else {
|
||||
for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = fp.readl(3);
|
||||
|
@ -305,7 +305,7 @@ void Cartridge::parse_markup_hitachidsp(XML::Node &root) {
|
|||
fp.read(data, 3072);
|
||||
|
||||
if(sha256 != nall::sha256(data, 3072)) {
|
||||
interface->message({ "Warning: Hitachi DSP firmware ", firmware, " SHA256 sum is incorrect." });
|
||||
interface()->message({ "Warning: Hitachi DSP firmware ", firmware, " SHA256 sum is incorrect." });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,19 +338,19 @@ void Cartridge::parse_markup_armdsp(XML::Node &root) {
|
|||
string firmware = root["firmware"].data;
|
||||
string sha256 = root["sha256"].data;
|
||||
|
||||
string path = interface->path(Slot::Base, firmware);
|
||||
string path = interface()->path(Slot::Base, firmware);
|
||||
file fp;
|
||||
if(fp.open(path, file::mode::read) == false) {
|
||||
interface->message({ "Warning: ARM DSP firmware ", firmware, " is missing." });
|
||||
interface()->message({ "Warning: ARM DSP firmware ", firmware, " is missing." });
|
||||
} else if(fp.size() != 160 * 1024) {
|
||||
interface->message({ "Warning: ARM DSP firmware ", firmware, " is of the wrong file size." });
|
||||
interface()->message({ "Warning: ARM DSP firmware ", firmware, " is of the wrong file size." });
|
||||
fp.close();
|
||||
} else {
|
||||
fp.read(armdsp.firmware, fp.size());
|
||||
|
||||
if(!sha256.empty()) {
|
||||
if(sha256 != nall::sha256(armdsp.firmware, fp.size())) {
|
||||
interface->message({ "Warning: ARM DSP firmware ", firmware, " SHA256 sum is incorrect." });
|
||||
interface()->message({ "Warning: ARM DSP firmware ", firmware, " SHA256 sum is incorrect." });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -520,7 +520,7 @@ void Cartridge::parse_markup_obc1(XML::Node &root) {
|
|||
|
||||
void Cartridge::parse_markup_msu1(XML::Node &root) {
|
||||
if(root.exists() == false) {
|
||||
has_msu1 = file::exists(interface->path(Cartridge::Slot::Base, "msu1.rom"));
|
||||
has_msu1 = file::exists(interface()->path(Cartridge::Slot::Base, "msu1.rom"));
|
||||
if(has_msu1) {
|
||||
Mapping m({ &MSU1::mmio_read, &msu1 }, { &MSU1::mmio_write, &msu1 });
|
||||
m.banklo = 0x00, m.bankhi = 0x3f, m.addrlo = 0x2000, m.addrhi = 0x2007;
|
||||
|
|
|
@ -2,6 +2,12 @@
|
|||
|
||||
BSXCartridge bsxcartridge;
|
||||
|
||||
BSXCartridge::BSXCartridge()
|
||||
: sram("BSX_RAM")
|
||||
, psram("BSX_PRAM")
|
||||
{
|
||||
}
|
||||
|
||||
void BSXCartridge::init() {
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ public:
|
|||
void mmio_write(unsigned addr, uint8 data);
|
||||
void mmio_commit();
|
||||
|
||||
BSXCartridge();
|
||||
|
||||
private:
|
||||
uint8 r[16];
|
||||
bool r00, r01, r02, r03;
|
||||
|
|
|
@ -38,7 +38,7 @@ uint8 BSXSatellaview::mmio_read(unsigned addr) {
|
|||
|
||||
if(counter == 0) {
|
||||
time_t rawtime;
|
||||
rawtime = SNES::interface->currentTime();
|
||||
rawtime = SNES::interface()->currentTime();
|
||||
tm *t = localtime(&rawtime);
|
||||
|
||||
regs.r2192_hour = t->tm_hour;
|
||||
|
|
|
@ -69,11 +69,15 @@ void ICD2::reset() {
|
|||
joyp14lock = 0;
|
||||
pulselock = true;
|
||||
|
||||
GameBoy::interface = this;
|
||||
GameBoy::system.init();
|
||||
GameBoy::system.power();
|
||||
}
|
||||
|
||||
ICD2::ICD2()
|
||||
{
|
||||
GameBoy::interface = this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,6 +16,8 @@ public:
|
|||
|
||||
void serialize(serializer&);
|
||||
|
||||
ICD2();
|
||||
|
||||
private:
|
||||
#include "interface/interface.hpp"
|
||||
#include "mmio/mmio.hpp"
|
||||
|
|
|
@ -112,4 +112,7 @@ bool ICD2::inputPoll(unsigned id) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void* ICD2::allocSharedMemory(const char* memtype, size_t amt, int initialByte) { SNES::interface()->allocSharedMemory(memtype, amt, initialByte); }
|
||||
void ICD2::freeSharedMemory(void* ptr) { SNES::interface()->freeSharedMemory(ptr); }
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,6 +4,9 @@ void videoRefresh(const uint16_t *data);
|
|||
void audioSample(int16_t center, int16_t left, int16_t right);
|
||||
bool inputPoll(unsigned id);
|
||||
|
||||
void* allocSharedMemory(const char* memtype, size_t amt, int initialByte = -1);
|
||||
void freeSharedMemory(void* ptr);
|
||||
|
||||
struct Packet {
|
||||
uint8 data[16];
|
||||
uint8& operator[](unsigned addr) { return data[addr & 15]; }
|
||||
|
|
|
@ -22,7 +22,7 @@ void Link::init() {
|
|||
|
||||
void Link::load() {
|
||||
if(opened()) close();
|
||||
string basename = interface->path(Cartridge::Slot::Base, "");
|
||||
string basename = interface()->path(Cartridge::Slot::Base, "");
|
||||
string name = program != "" ? program : notdir(basename);
|
||||
string path = dir(basename);
|
||||
if(open(name, path)) {
|
||||
|
|
|
@ -52,7 +52,7 @@ void MSU1::init() {
|
|||
|
||||
void MSU1::load() {
|
||||
if(datafile.open()) datafile.close();
|
||||
datafile.open(interface->path(Cartridge::Slot::Base, "msu1.rom"), file::mode::read);
|
||||
datafile.open(interface()->path(Cartridge::Slot::Base, "msu1.rom"), file::mode::read);
|
||||
}
|
||||
|
||||
void MSU1::unload() {
|
||||
|
@ -112,7 +112,7 @@ void MSU1::mmio_write(unsigned addr, uint8 data) {
|
|||
case 4: mmio.audio_track = (mmio.audio_track & 0xff00) | (data << 0);
|
||||
case 5: mmio.audio_track = (mmio.audio_track & 0x00ff) | (data << 8);
|
||||
if(audiofile.open()) audiofile.close();
|
||||
if(audiofile.open(interface->path(Cartridge::Slot::Base, { "track-", (unsigned)mmio.audio_track, ".pcm" }), file::mode::read)) {
|
||||
if(audiofile.open(interface()->path(Cartridge::Slot::Base, { "track-", (unsigned)mmio.audio_track, ".pcm" }), file::mode::read)) {
|
||||
uint32 header = audiofile.readm(4);
|
||||
if(header != 0x4d535531) { //verify 'MSU1' header
|
||||
audiofile.close();
|
||||
|
|
|
@ -16,12 +16,12 @@ void MSU1::serialize(serializer &s) {
|
|||
s.integer(mmio.audio_play);
|
||||
|
||||
if(datafile.open()) datafile.close();
|
||||
if(datafile.open(interface->path(Cartridge::Slot::Base, "msu1.rom"), file::mode::read)) {
|
||||
if(datafile.open(interface()->path(Cartridge::Slot::Base, "msu1.rom"), file::mode::read)) {
|
||||
datafile.seek(mmio.data_offset);
|
||||
}
|
||||
|
||||
if(audiofile.open()) audiofile.close();
|
||||
if(audiofile.open(interface->path(Cartridge::Slot::Base, { "track-", (unsigned)mmio.audio_track, ".pcm" }), file::mode::read)) {
|
||||
if(audiofile.open(interface()->path(Cartridge::Slot::Base, { "track-", (unsigned)mmio.audio_track, ".pcm" }), file::mode::read)) {
|
||||
audiofile.seek(mmio.audio_offset);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ void SPC7110::serialize(serializer &s) {
|
|||
s.integer(r4841);
|
||||
s.integer(r4842);
|
||||
|
||||
s.array(rtc);
|
||||
s.array(rtc,20);
|
||||
s.integer(rtc_state);
|
||||
s.integer(rtc_mode);
|
||||
s.integer(rtc_index);
|
||||
|
|
|
@ -101,7 +101,7 @@ void SPC7110::set_data_adjust(unsigned addr) { r4814 = addr; r4815 = addr >> 8;
|
|||
|
||||
void SPC7110::update_time(int offset) {
|
||||
time_t rtc_time = (rtc[16] << 0) | (rtc[17] << 8) | (rtc[18] << 16) | (rtc[19] << 24);
|
||||
time_t current_time = SNES::interface->currentTime() - offset;
|
||||
time_t current_time = SNES::interface()->currentTime() - offset;
|
||||
|
||||
//sizeof(time_t) is platform-dependent; though rtc[] needs to be platform-agnostic.
|
||||
//yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by
|
||||
|
@ -631,9 +631,21 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
SPC7110::SPC7110() {
|
||||
SPC7110::SPC7110() :
|
||||
rtc(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SPC7110::~SPC7110()
|
||||
{
|
||||
interface()->freeSharedMemory(rtc);
|
||||
}
|
||||
|
||||
void SPC7110::initialize()
|
||||
{
|
||||
rtc = (uint8*)interface()->allocSharedMemory("SPC7110_RTC", 20);
|
||||
}
|
||||
//============
|
||||
//SPC7110::MCU
|
||||
//============
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
class SPC7110 {
|
||||
public:
|
||||
uint8 rtc[20];
|
||||
uint8* rtc; //[20];
|
||||
unsigned data_rom_offset;
|
||||
|
||||
void init();
|
||||
|
@ -41,6 +41,8 @@ public:
|
|||
|
||||
void serialize(serializer&);
|
||||
SPC7110();
|
||||
~SPC7110();
|
||||
void initialize();
|
||||
|
||||
private:
|
||||
//==================
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifdef SRTC_CPP
|
||||
|
||||
void SRTC::serialize(serializer &s) {
|
||||
s.array(rtc);
|
||||
s.array(rtc,20);
|
||||
s.integer(rtc_mode);
|
||||
s.integer(rtc_index);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,21 @@ SRTC srtc;
|
|||
|
||||
const unsigned SRTC::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
|
||||
SRTC::SRTC()
|
||||
: rtc(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
SRTC::~SRTC()
|
||||
{
|
||||
interface()->freeSharedMemory(rtc);
|
||||
}
|
||||
|
||||
void SRTC::initialize()
|
||||
{
|
||||
rtc = (uint8*)interface()->allocSharedMemory("RTC",20);
|
||||
}
|
||||
|
||||
void SRTC::init() {
|
||||
}
|
||||
|
||||
|
@ -31,7 +46,7 @@ void SRTC::reset() {
|
|||
|
||||
void SRTC::update_time() {
|
||||
time_t rtc_time = (rtc[16] << 0) | (rtc[17] << 8) | (rtc[18] << 16) | (rtc[19] << 24);
|
||||
time_t current_time = SNES::interface->currentTime();
|
||||
time_t current_time = SNES::interface()->currentTime();
|
||||
|
||||
//sizeof(time_t) is platform-dependent; though rtc[] needs to be platform-agnostic.
|
||||
//yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by
|
||||
|
@ -225,7 +240,4 @@ void SRTC::write(unsigned addr, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
SRTC::SRTC() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class SRTC {
|
||||
public:
|
||||
uint8 rtc[20];
|
||||
uint8* rtc; //[20];
|
||||
|
||||
void init();
|
||||
void load();
|
||||
|
@ -12,7 +12,9 @@ public:
|
|||
void write(unsigned addr, uint8 data);
|
||||
|
||||
void serialize(serializer&);
|
||||
void initialize();
|
||||
SRTC();
|
||||
~SRTC();
|
||||
|
||||
private:
|
||||
static const unsigned months[12];
|
||||
|
|
|
@ -6,6 +6,12 @@ namespace SNES {
|
|||
#include "serialization.cpp"
|
||||
SufamiTurbo sufamiturbo;
|
||||
|
||||
SufamiTurbo::SufamiTurbo()
|
||||
{
|
||||
slotA.ram.setName("SUFAMI_TURBO_A_RAM");
|
||||
slotB.ram.setName("SUFAMI_TURBO_B_RAM");
|
||||
}
|
||||
|
||||
void SufamiTurbo::load() {
|
||||
slotA.ram.map(allocate<uint8>(128 * 1024, 0xff), 128 * 1024);
|
||||
slotB.ram.map(allocate<uint8>(128 * 1024, 0xff), 128 * 1024);
|
||||
|
|
|
@ -8,6 +8,8 @@ public:
|
|||
void load();
|
||||
void unload();
|
||||
void serialize(serializer&);
|
||||
|
||||
SufamiTurbo();
|
||||
};
|
||||
|
||||
extern SufamiTurbo sufamiturbo;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
uint2 Gamepad::data() {
|
||||
if(counter >= 16) return 1;
|
||||
uint2 result = interface->inputPoll(port, Input::Device::Joypad, 0, counter);
|
||||
uint2 result = interface()->inputPoll(port, Input::Device::Joypad, 0, counter);
|
||||
if(latched == 0) counter++;
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@ void Justifier::enter() {
|
|||
}
|
||||
|
||||
if(next < prev) {
|
||||
int nx1 = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::X);
|
||||
int ny1 = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Y);
|
||||
int nx1 = interface()->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::X);
|
||||
int ny1 = interface()->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Y);
|
||||
nx1 += player1.x;
|
||||
ny1 += player1.y;
|
||||
player1.x = max(-16, min(256 + 16, nx1));
|
||||
|
@ -27,8 +27,8 @@ void Justifier::enter() {
|
|||
}
|
||||
|
||||
if(next < prev && chained) {
|
||||
int nx2 = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::X);
|
||||
int ny2 = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Y);
|
||||
int nx2 = interface()->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::X);
|
||||
int ny2 = interface()->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Y);
|
||||
nx2 += player2.x;
|
||||
ny2 += player2.y;
|
||||
player2.x = max(-16, min(256 + 16, nx2));
|
||||
|
@ -44,13 +44,13 @@ uint2 Justifier::data() {
|
|||
if(counter >= 32) return 1;
|
||||
|
||||
if(counter == 0) {
|
||||
player1.trigger = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Trigger);
|
||||
player1.start = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Start);
|
||||
player1.trigger = interface()->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Trigger);
|
||||
player1.start = interface()->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Start);
|
||||
}
|
||||
|
||||
if(counter == 0 && chained) {
|
||||
player2.trigger = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Trigger);
|
||||
player2.start = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Start);
|
||||
player2.trigger = interface()->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Trigger);
|
||||
player2.start = interface()->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Start);
|
||||
}
|
||||
|
||||
switch(counter++) {
|
||||
|
|
|
@ -4,8 +4,8 @@ uint2 Mouse::data() {
|
|||
if(counter >= 32) return 1;
|
||||
|
||||
if(counter == 0) {
|
||||
position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right
|
||||
position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down
|
||||
position_x = interface()->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right
|
||||
position_y = interface()->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down
|
||||
}
|
||||
|
||||
bool direction_x = position_x < 0; //0 = right, 1 = left
|
||||
|
@ -27,8 +27,8 @@ uint2 Mouse::data() {
|
|||
case 6: return 0;
|
||||
case 7: return 0;
|
||||
|
||||
case 8: return interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Right);
|
||||
case 9: return interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Left);
|
||||
case 8: return interface()->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Right);
|
||||
case 9: return interface()->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Left);
|
||||
case 10: return 0; //speed (0 = slow, 1 = normal, 2 = fast, 3 = unused)
|
||||
case 11: return 0; // ||
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@ uint2 Multitap::data() {
|
|||
port2 = 3; //controller 4
|
||||
}
|
||||
|
||||
bool data1 = interface->inputPoll(port, Input::Device::Multitap, port1, index);
|
||||
bool data2 = interface->inputPoll(port, Input::Device::Multitap, port2, index);
|
||||
bool data1 = interface()->inputPoll(port, Input::Device::Multitap, port1, index);
|
||||
bool data2 = interface()->inputPoll(port, Input::Device::Multitap, port2, index);
|
||||
return (data2 << 1) | (data1 << 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,8 +28,8 @@ void SuperScope::enter() {
|
|||
|
||||
if(next < prev) {
|
||||
//Vcounter wrapped back to zero; update cursor coordinates for start of new frame
|
||||
int nx = interface->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::X);
|
||||
int ny = interface->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Y);
|
||||
int nx = interface()->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::X);
|
||||
int ny = interface()->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Y);
|
||||
nx += x;
|
||||
ny += y;
|
||||
x = max(-16, min(256 + 16, nx));
|
||||
|
@ -47,7 +47,7 @@ uint2 SuperScope::data() {
|
|||
|
||||
if(counter == 0) {
|
||||
//turbo is a switch; toggle is edge sensitive
|
||||
bool newturbo = interface->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Turbo);
|
||||
bool newturbo = interface()->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Turbo);
|
||||
if(newturbo && !turbo) {
|
||||
turbo = !turbo; //toggle state
|
||||
turbolock = true;
|
||||
|
@ -58,7 +58,7 @@ uint2 SuperScope::data() {
|
|||
//trigger is a button
|
||||
//if turbo is active, trigger is level sensitive; otherwise, it is edge sensitive
|
||||
trigger = false;
|
||||
bool newtrigger = interface->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Trigger);
|
||||
bool newtrigger = interface()->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Trigger);
|
||||
if(newtrigger && (turbo || !triggerlock)) {
|
||||
trigger = true;
|
||||
triggerlock = true;
|
||||
|
@ -67,11 +67,11 @@ uint2 SuperScope::data() {
|
|||
}
|
||||
|
||||
//cursor is a button; it is always level sensitive
|
||||
cursor = interface->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Cursor);
|
||||
cursor = interface()->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Cursor);
|
||||
|
||||
//pause is a button; it is always edge sensitive
|
||||
pause = false;
|
||||
bool newpause = interface->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Pause);
|
||||
bool newpause = interface()->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Pause);
|
||||
if(newpause && !pauselock) {
|
||||
pause = true;
|
||||
pauselock = true;
|
||||
|
|
|
@ -88,7 +88,7 @@ USART::USART(bool port) : Controller(port) {
|
|||
txlength = 0;
|
||||
txdata = 0;
|
||||
|
||||
string filename = interface->path(Cartridge::Slot::Base, "usart.so");
|
||||
string filename = interface()->path(Cartridge::Slot::Base, "usart.so");
|
||||
if(open_absolute(filename)) {
|
||||
init = sym("usart_init");
|
||||
main = sym("usart_main");
|
||||
|
|
|
@ -91,12 +91,12 @@ void CPU::enter() {
|
|||
void CPU::op_step() {
|
||||
debugger.op_exec(regs.pc.d);
|
||||
|
||||
if (interface->wanttrace)
|
||||
if (interface()->wanttrace)
|
||||
{
|
||||
char tmp[512];
|
||||
disassemble_opcode(tmp, regs.pc.d);
|
||||
tmp[511] = 0;
|
||||
interface->cpuTrace(tmp);
|
||||
interface()->cpuTrace(tmp);
|
||||
}
|
||||
|
||||
(this->*opcode_table[op_readpc()])();
|
||||
|
@ -128,7 +128,7 @@ void CPU::enable() {
|
|||
|
||||
void CPU::power() {
|
||||
cpu_version = config.cpu.version;
|
||||
for(auto &n : wram) n = random(config.cpu.wram_init_value);
|
||||
for(int i=0;i<128*1024;i++) wram[i] = random(config.cpu.wram_init_value);
|
||||
|
||||
regs.a = regs.x = regs.y = 0x0000;
|
||||
regs.s = 0x01ff;
|
||||
|
@ -166,11 +166,19 @@ void CPU::reset() {
|
|||
timing_reset();
|
||||
}
|
||||
|
||||
CPU::CPU() {
|
||||
CPU::CPU()
|
||||
: wram(nullptr)
|
||||
{
|
||||
PPUcounter::scanline = { &CPU::scanline, this };
|
||||
}
|
||||
|
||||
CPU::~CPU() {
|
||||
interface()->freeSharedMemory(wram);
|
||||
}
|
||||
|
||||
void CPU::initialize()
|
||||
{
|
||||
wram = (uint8*)interface()->allocSharedMemory("WRAM",128 * 1024);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
struct CPU : public Processor, public CPUcore, public PPUcounter {
|
||||
uint8 wram[128 * 1024];
|
||||
uint8 *wram; //[128 * 1024];
|
||||
|
||||
enum : bool { Threaded = true };
|
||||
array<Processor*> coprocessors;
|
||||
|
@ -24,6 +24,7 @@ struct CPU : public Processor, public CPUcore, public PPUcounter {
|
|||
void serialize(serializer&);
|
||||
CPU();
|
||||
~CPU();
|
||||
void initialize();
|
||||
|
||||
privileged:
|
||||
#include "dma/dma.hpp"
|
||||
|
|
|
@ -43,7 +43,7 @@ void CPU::mmio_w4016(uint8 data) {
|
|||
uint8 CPU::mmio_r4016() {
|
||||
uint8 r = regs.mdr & 0xfc;
|
||||
r |= input.port1->data();
|
||||
if (!status.auto_joypad_poll) interface->inputNotify(0x4016);
|
||||
if (!status.auto_joypad_poll) interface()->inputNotify(0x4016);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ uint8 CPU::mmio_r4016() {
|
|||
uint8 CPU::mmio_r4017() {
|
||||
uint8 r = (regs.mdr & 0xe0) | 0x1c;
|
||||
r |= input.port2->data();
|
||||
if (!status.auto_joypad_poll) interface->inputNotify(0x4017);
|
||||
if (!status.auto_joypad_poll) interface()->inputNotify(0x4017);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -183,7 +183,7 @@ uint8 CPU::mmio_r4212() {
|
|||
|
||||
//RDIO
|
||||
uint8 CPU::mmio_r4213() {
|
||||
// interface->inputNotify(0x4213); // if there are lag counter issues with super scope, uncomment this
|
||||
// interface()->inputNotify(0x4213); // if there are lag counter issues with super scope, uncomment this
|
||||
return status.pio;
|
||||
}
|
||||
|
||||
|
@ -207,14 +207,14 @@ uint8 CPU::mmio_r4217() {
|
|||
return status.rdmpy >> 8;
|
||||
}
|
||||
|
||||
uint8 CPU::mmio_r4218() { interface->inputNotify(0x4218); return status.joy1 >> 0; } //JOY1L
|
||||
uint8 CPU::mmio_r4219() { interface->inputNotify(0x4219); return status.joy1 >> 8; } //JOY1H
|
||||
uint8 CPU::mmio_r421a() { interface->inputNotify(0x421a); return status.joy2 >> 0; } //JOY2L
|
||||
uint8 CPU::mmio_r421b() { interface->inputNotify(0x421b); return status.joy2 >> 8; } //JOY2H
|
||||
uint8 CPU::mmio_r421c() { interface->inputNotify(0x421c); return status.joy3 >> 0; } //JOY3L
|
||||
uint8 CPU::mmio_r421d() { interface->inputNotify(0x421d); return status.joy3 >> 8; } //JOY3H
|
||||
uint8 CPU::mmio_r421e() { interface->inputNotify(0x421e); return status.joy4 >> 0; } //JOY4L
|
||||
uint8 CPU::mmio_r421f() { interface->inputNotify(0x421f); return status.joy4 >> 8; } //JOY4H
|
||||
uint8 CPU::mmio_r4218() { interface()->inputNotify(0x4218); return status.joy1 >> 0; } //JOY1L
|
||||
uint8 CPU::mmio_r4219() { interface()->inputNotify(0x4219); return status.joy1 >> 8; } //JOY1H
|
||||
uint8 CPU::mmio_r421a() { interface()->inputNotify(0x421a); return status.joy2 >> 0; } //JOY2L
|
||||
uint8 CPU::mmio_r421b() { interface()->inputNotify(0x421b); return status.joy2 >> 8; } //JOY2H
|
||||
uint8 CPU::mmio_r421c() { interface()->inputNotify(0x421c); return status.joy3 >> 0; } //JOY3L
|
||||
uint8 CPU::mmio_r421d() { interface()->inputNotify(0x421d); return status.joy3 >> 8; } //JOY3H
|
||||
uint8 CPU::mmio_r421e() { interface()->inputNotify(0x421e); return status.joy4 >> 0; } //JOY4L
|
||||
uint8 CPU::mmio_r421f() { interface()->inputNotify(0x421f); return status.joy4 >> 8; } //JOY4H
|
||||
|
||||
//DMAPx
|
||||
uint8 CPU::mmio_r43x0(uint8 i) {
|
||||
|
|
|
@ -5,7 +5,7 @@ void CPU::serialize(serializer &s) {
|
|||
CPUcore::core_serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
s.array(wram);
|
||||
s.array(wram,128 * 1024);
|
||||
|
||||
s.integer(cpu_version);
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace SNES {
|
||||
|
||||
Interface *interface = nullptr;
|
||||
|
||||
Interface::Interface()
|
||||
: wanttrace(false)
|
||||
{
|
||||
|
|
|
@ -19,6 +19,10 @@ struct Interface {
|
|||
|
||||
bool wanttrace;
|
||||
virtual void cpuTrace(const char *msg);
|
||||
|
||||
//zero 23-dec-2012
|
||||
virtual void* allocSharedMemory(const char* memtype, size_t amt, int initialByte = -1) = 0;
|
||||
virtual void freeSharedMemory(void* ptr) = 0;
|
||||
};
|
||||
|
||||
extern Interface *interface;
|
||||
Interface *interface();
|
||||
|
|
|
@ -19,7 +19,8 @@ StaticRAM::~StaticRAM() { delete[] data_; }
|
|||
|
||||
void MappedRAM::reset() {
|
||||
if(data_) {
|
||||
delete[] data_;
|
||||
if(name_) interface()->freeSharedMemory(data_);
|
||||
else free(data_);
|
||||
data_ = 0;
|
||||
}
|
||||
size_ = 0;
|
||||
|
@ -35,7 +36,8 @@ void MappedRAM::map(uint8 *source, unsigned length) {
|
|||
void MappedRAM::copy(const uint8 *data, unsigned size) {
|
||||
if(!data_) {
|
||||
size_ = (size & ~255) + ((bool)(size & 255) << 8);
|
||||
data_ = new uint8[size_]();
|
||||
if(name_) data_ = (uint8*)interface()->allocSharedMemory(name_, size_);
|
||||
else data_ = new uint8[size_]();
|
||||
}
|
||||
memcpy(data_, data, min(size_, size));
|
||||
}
|
||||
|
@ -47,7 +49,7 @@ unsigned MappedRAM::size() const { return size_; }
|
|||
uint8 MappedRAM::read(unsigned addr) { return data_[addr]; }
|
||||
void MappedRAM::write(unsigned addr, uint8 n) { if(!write_protect_) data_[addr] = n; }
|
||||
const uint8& MappedRAM::operator[](unsigned addr) const { return data_[addr]; }
|
||||
MappedRAM::MappedRAM() : data_(0), size_(0), write_protect_(false) {}
|
||||
MappedRAM::MappedRAM(const char* name) : data_(0), size_(0), write_protect_(false), name_(name) {}
|
||||
|
||||
//Bus
|
||||
|
||||
|
|
|
@ -33,12 +33,15 @@ struct MappedRAM : Memory {
|
|||
inline uint8 read(unsigned addr);
|
||||
inline void write(unsigned addr, uint8 n);
|
||||
inline const uint8& operator[](unsigned addr) const;
|
||||
inline MappedRAM();
|
||||
inline MappedRAM(const char* name = NULL);
|
||||
|
||||
inline void setName(const char* name) { name_ = name; }
|
||||
|
||||
private:
|
||||
uint8 *data_;
|
||||
unsigned size_;
|
||||
bool write_protect_;
|
||||
const char* name_;
|
||||
};
|
||||
|
||||
struct Bus {
|
||||
|
|
|
@ -4,7 +4,7 @@ void SMP::serialize(serializer &s) {
|
|||
Processor::serialize(s);
|
||||
SMPcore::core_serialize(s);
|
||||
|
||||
s.array(apuram);
|
||||
s.array(apuram, 64 * 1024);
|
||||
|
||||
s.integer(status.clock_counter);
|
||||
s.integer(status.dsp_counter);
|
||||
|
|
|
@ -28,7 +28,7 @@ void SMP::synchronize_cpu_force() {
|
|||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All)
|
||||
co_switch(cpu.thread);
|
||||
else if(clock >= 0 && scheduler.sync == Scheduler::SynchronizeMode::All)
|
||||
interface->message("SMP had to advance nondeterministically!");
|
||||
interface()->message("SMP had to advance nondeterministically!");
|
||||
} else {
|
||||
while(clock >= 0) cpu.enter();
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ void SMP::reset() {
|
|||
regs.s = 0xef;
|
||||
regs.p = 0x02;
|
||||
|
||||
for(auto &n : apuram) n = random(0x00);
|
||||
for(int i=0;i<64*1024;i++) apuram[i] = random(0x00);
|
||||
apuram[0x00f4] = 0x00;
|
||||
apuram[0x00f5] = 0x00;
|
||||
apuram[0x00f6] = 0x00;
|
||||
|
@ -140,11 +140,18 @@ void SMP::reset() {
|
|||
timer2.enable = false;
|
||||
}
|
||||
|
||||
SMP::SMP() {
|
||||
|
||||
SMP::SMP()
|
||||
: apuram(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
SMP::~SMP() {
|
||||
interface()->freeSharedMemory(apuram);
|
||||
}
|
||||
|
||||
void SMP::initialize()
|
||||
{
|
||||
apuram = (uint8*)interface()->allocSharedMemory("APURAM",64 * 1024);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
struct SMP : public Processor, public SMPcore {
|
||||
static const uint8 iplrom[64];
|
||||
uint8 apuram[64 * 1024];
|
||||
uint8* apuram; //[64 * 1024];
|
||||
|
||||
enum : bool { Threaded = true };
|
||||
alwaysinline void step(unsigned clocks);
|
||||
|
@ -18,6 +18,7 @@ struct SMP : public Processor, public SMPcore {
|
|||
void serialize(serializer&);
|
||||
SMP();
|
||||
~SMP();
|
||||
void initialize();
|
||||
|
||||
privileged:
|
||||
#include "memory/memory.hpp"
|
||||
|
|
|
@ -18,7 +18,7 @@ void Audio::coprocessor_frequency(double input_frequency) {
|
|||
}
|
||||
|
||||
void Audio::sample(int16 lsample, int16 rsample) {
|
||||
if(coprocessor == false) return interface->audioSample(lsample, rsample);
|
||||
if(coprocessor == false) return interface()->audioSample(lsample, rsample);
|
||||
|
||||
dsp_buffer[dsp_wroffset] = ((uint16)lsample << 0) + ((uint16)rsample << 16);
|
||||
dsp_wroffset = (dsp_wroffset + 1) & buffer_mask;
|
||||
|
@ -59,7 +59,7 @@ void Audio::flush() {
|
|||
signed cop_left = (int16)(cop_sample >> 0);
|
||||
signed cop_right = (int16)(cop_sample >> 16);
|
||||
|
||||
interface->audioSample(
|
||||
interface()->audioSample(
|
||||
sclamp<16>((dsp_left + cop_left ) / 2),
|
||||
sclamp<16>((dsp_right + cop_right) / 2)
|
||||
);
|
||||
|
|
|
@ -151,7 +151,7 @@ void System::unload() {
|
|||
}
|
||||
|
||||
void System::power() {
|
||||
random.seed((unsigned)interface->randomSeed());
|
||||
random.seed((unsigned)interface()->randomSeed());
|
||||
|
||||
region = config.region;
|
||||
expansion = config.expansion_port;
|
||||
|
|
|
@ -129,7 +129,7 @@ void Video::update() {
|
|||
}
|
||||
}
|
||||
|
||||
interface->videoRefresh(ppu.surface, hires, ppu.interlace(), ppu.overscan());
|
||||
interface()->videoRefresh(ppu.surface, hires, ppu.interlace(), ppu.overscan());
|
||||
|
||||
hires = false;
|
||||
}
|
||||
|
|
|
@ -10,10 +10,11 @@ else ifeq ($(platform),win)
|
|||
endif
|
||||
|
||||
#rules
|
||||
objects := $(objects) libsnes
|
||||
objects := $(objects) libsnes libsnes_pwrap
|
||||
objects := $(patsubst %,obj/%.o,$(objects))
|
||||
|
||||
obj/libsnes.o: $(ui)/libsnes.cpp $(ui)/*
|
||||
obj/libsnes_pwrap.o: $(ui)/libsnes_pwrap.cpp $(ui)/*
|
||||
|
||||
#targets
|
||||
build: $(objects)
|
||||
|
@ -24,7 +25,7 @@ else ifeq ($(platform),osx)
|
|||
ar rcs out/libsnes.a $(objects)
|
||||
$(cpp) -o out/libsnes.dylib -install_name @executable_path/../Libraries/libsnes.dylib -shared -dynamiclib $(objects)
|
||||
else ifeq ($(platform),win)
|
||||
$(cpp) -o out/snes.dll -shared -Wl,--out-implib,libsnes.a $(objects) $(TARGET_LIBSNES_LIBDEPS)
|
||||
$(cpp) -o out/libsneshawk-$(profile).exe -Wl $(objects) $(TARGET_LIBSNES_LIBDEPS)
|
||||
endif
|
||||
|
||||
install:
|
||||
|
|
|
@ -6,15 +6,21 @@
|
|||
|
||||
#include <queue>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
using namespace nall;
|
||||
|
||||
struct Interface : public SNES::Interface {
|
||||
typedef SNES::Interface BaseType;
|
||||
|
||||
snes_video_refresh_t pvideo_refresh;
|
||||
snes_audio_sample_t paudio_sample;
|
||||
snes_input_poll_t pinput_poll;
|
||||
snes_input_state_t pinput_state;
|
||||
snes_input_notify_t pinput_notify;
|
||||
snes_path_request_t ppath_request;
|
||||
snes_allocSharedMemory_t pallocSharedMemory;
|
||||
snes_freeSharedMemory_t pfreeSharedMemory;
|
||||
snes_trace_t ptrace;
|
||||
string basename;
|
||||
uint32_t *buffer;
|
||||
|
@ -89,9 +95,27 @@ struct Interface : public SNES::Interface {
|
|||
return path;
|
||||
}
|
||||
return { basename, hint };
|
||||
|
||||
}
|
||||
|
||||
|
||||
//zero 23-dec-2012
|
||||
void* allocSharedMemory(const char* memtype, size_t amt, int initialByte = -1)
|
||||
{
|
||||
void* ret;
|
||||
//if pallocSharedMemory isnt set up yet, we're going to have serious problems
|
||||
ret = pallocSharedMemory(memtype,amt);
|
||||
if(initialByte != -1)
|
||||
{
|
||||
for(unsigned i = 0; i < amt; i++) ((uint8*)ret)[i] = (uint8)initialByte;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
void freeSharedMemory(void* ptr)
|
||||
{
|
||||
if(!pfreeSharedMemory) return; //??
|
||||
pfreeSharedMemory(ptr);
|
||||
}
|
||||
|
||||
Interface() :
|
||||
pvideo_refresh(0),
|
||||
paudio_sample(0),
|
||||
|
@ -99,12 +123,14 @@ struct Interface : public SNES::Interface {
|
|||
pinput_state(0),
|
||||
pinput_notify(0),
|
||||
ppath_request(0),
|
||||
pScanlineStart(0),
|
||||
pallocSharedMemory(0),
|
||||
pfreeSharedMemory(0),
|
||||
backdropColor(-1),
|
||||
ptrace(0)
|
||||
{
|
||||
buffer = new uint32_t[512 * 480];
|
||||
palette = new uint32_t[16 * 32768];
|
||||
|
||||
}
|
||||
|
||||
~Interface() {
|
||||
|
@ -113,7 +139,17 @@ struct Interface : public SNES::Interface {
|
|||
}
|
||||
};
|
||||
|
||||
static Interface interface;
|
||||
void pwrap_init();
|
||||
static Interface *iface = nullptr;
|
||||
namespace SNES {
|
||||
SNES::Interface *interface()
|
||||
{
|
||||
if(iface != nullptr) return iface;
|
||||
iface = new ::Interface();
|
||||
pwrap_init();
|
||||
return iface;
|
||||
}
|
||||
}
|
||||
|
||||
const char* snes_library_id(void) {
|
||||
static string version = {"bsnes v", Version};
|
||||
|
@ -128,34 +164,43 @@ unsigned snes_library_revision_minor(void) {
|
|||
return 3;
|
||||
}
|
||||
|
||||
void snes_set_allocSharedMemory(snes_allocSharedMemory_t cb)
|
||||
{
|
||||
iface->pallocSharedMemory = cb;
|
||||
}
|
||||
void snes_set_freeSharedMemory(snes_freeSharedMemory_t cb)
|
||||
{
|
||||
iface->pfreeSharedMemory = cb;
|
||||
}
|
||||
|
||||
void snes_set_video_refresh(snes_video_refresh_t video_refresh) {
|
||||
interface.pvideo_refresh = video_refresh;
|
||||
iface->pvideo_refresh = video_refresh;
|
||||
}
|
||||
|
||||
void snes_set_color_lut(uint32_t * colors) {
|
||||
for (int i = 0; i < 16 * 32768; i++)
|
||||
interface.palette[i] = colors[i];
|
||||
iface->palette[i] = colors[i];
|
||||
}
|
||||
|
||||
void snes_set_audio_sample(snes_audio_sample_t audio_sample) {
|
||||
interface.paudio_sample = audio_sample;
|
||||
iface->paudio_sample = audio_sample;
|
||||
}
|
||||
|
||||
void snes_set_input_poll(snes_input_poll_t input_poll) {
|
||||
interface.pinput_poll = input_poll;
|
||||
iface->pinput_poll = input_poll;
|
||||
}
|
||||
|
||||
void snes_set_input_state(snes_input_state_t input_state) {
|
||||
interface.pinput_state = input_state;
|
||||
iface->pinput_state = input_state;
|
||||
}
|
||||
|
||||
void snes_set_input_notify(snes_input_notify_t input_notify) {
|
||||
interface.pinput_notify = input_notify;
|
||||
iface->pinput_notify = input_notify;
|
||||
}
|
||||
|
||||
void snes_set_path_request(snes_path_request_t path_request)
|
||||
{
|
||||
interface.ppath_request = path_request;
|
||||
iface->ppath_request = path_request;
|
||||
}
|
||||
|
||||
void snes_set_controller_port_device(bool port, unsigned device) {
|
||||
|
@ -163,7 +208,7 @@ void snes_set_controller_port_device(bool port, unsigned device) {
|
|||
}
|
||||
|
||||
void snes_set_cartridge_basename(const char *basename) {
|
||||
interface.basename = basename;
|
||||
iface->basename = basename;
|
||||
}
|
||||
|
||||
template<typename T> inline void reconstruct(T* t) {
|
||||
|
@ -173,7 +218,9 @@ template<typename T> inline void reconstruct(T* t) {
|
|||
}
|
||||
|
||||
void snes_init(void) {
|
||||
SNES::interface = &interface;
|
||||
|
||||
//force everything to get initialized, even thuogh it probably already is
|
||||
SNES::interface();
|
||||
|
||||
//zero 01-dec-2012 - due to systematic variable initialization fails in bsnes components, these reconstructions are necessary,
|
||||
//and the previous comment here which called this paranoid has been removed.
|
||||
|
@ -187,9 +234,9 @@ void snes_init(void) {
|
|||
reconstruct(&SNES::bsxsatellaview);
|
||||
reconstruct(&SNES::bsxcartridge);
|
||||
reconstruct(&SNES::bsxflash);
|
||||
reconstruct(&SNES::srtc);
|
||||
reconstruct(&SNES::srtc); SNES::srtc.initialize();
|
||||
reconstruct(&SNES::sdd1);
|
||||
reconstruct(&SNES::spc7110);
|
||||
reconstruct(&SNES::spc7110); SNES::spc7110.initialize();
|
||||
reconstruct(&SNES::obc1);
|
||||
reconstruct(&SNES::msu1);
|
||||
reconstruct(&SNES::link);
|
||||
|
@ -199,11 +246,11 @@ void snes_init(void) {
|
|||
//zero 01-dec-2012 - forgot to do all these. massive desync chaos!
|
||||
//remove these to make it easier to find initialization fails in the component power-ons / constructors / etc.
|
||||
//or just forget about it. this snes_init gets called paranoidly frequently by bizhawk, so things should stay zeroed correctly
|
||||
reconstruct(&SNES::cpu);
|
||||
reconstruct(&SNES::smp);
|
||||
reconstruct(&SNES::cpu); SNES::cpu.initialize();
|
||||
reconstruct(&SNES::smp); SNES::smp.initialize();
|
||||
reconstruct(&SNES::dsp);
|
||||
reconstruct(&SNES::ppu);
|
||||
|
||||
SNES::ppu.initialize();
|
||||
SNES::system.init();
|
||||
SNES::input.connect(SNES::Controller::Port1, SNES::Input::Device::Joypad);
|
||||
SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::Joypad);
|
||||
|
@ -299,7 +346,7 @@ void snes_cheat_set(unsigned index, bool enable, const char *code) {
|
|||
//zero 21-sep-2012
|
||||
void snes_set_scanlineStart(snes_scanlineStart_t cb)
|
||||
{
|
||||
interface.pScanlineStart = cb;
|
||||
iface->pScanlineStart = cb;
|
||||
}
|
||||
|
||||
//zero 03-sep-2012
|
||||
|
@ -316,6 +363,7 @@ int snes_peek_logical_register(int reg)
|
|||
switch(reg)
|
||||
{
|
||||
//$2105
|
||||
#if !defined(PROFILE_PERFORMANCE)
|
||||
case SNES_REG_BG_MODE: return SNES::ppu.regs.bg_mode;
|
||||
case SNES_REG_BG3_PRIORITY: return SNES::ppu.regs.bg3_priority;
|
||||
case SNES_REG_BG1_TILESIZE: return SNES::ppu.regs.bg_tilesize[SNES::PPU::BG1];
|
||||
|
@ -399,7 +447,7 @@ int snes_peek_logical_register(int reg)
|
|||
case SNES_REG_BG4VOFS: return SNES::ppu.regs.bg_vofs[3] & 0x3FF;
|
||||
case SNES_REG_M7HOFS: return SNES::ppu.regs.m7_hofs & 0x1FFF; //rememebr to make these signed with <<19>>19
|
||||
case SNES_REG_M7VOFS: return SNES::ppu.regs.m7_vofs & 0x1FFF; //rememebr to make these signed with <<19>>19
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
return 0;
|
||||
|
@ -533,6 +581,53 @@ uint8_t* snes_get_memory_data(unsigned id) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
const char* snes_get_memory_id_name(unsigned id) {
|
||||
if(SNES::cartridge.loaded() == false) return nullptr;
|
||||
|
||||
switch(id) {
|
||||
case SNES_MEMORY_CARTRIDGE_RAM:
|
||||
return "CARTRIDGE_RAM";
|
||||
case SNES_MEMORY_CARTRIDGE_RTC:
|
||||
if(SNES::cartridge.has_srtc()) return "RTC";
|
||||
if(SNES::cartridge.has_spc7110rtc()) return "SPC7110_RTC";
|
||||
return nullptr;
|
||||
case SNES_MEMORY_BSX_RAM:
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break;
|
||||
return "BSX_SRAM";
|
||||
case SNES_MEMORY_BSX_PRAM:
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break;
|
||||
return "BSX_PSRAM";
|
||||
case SNES_MEMORY_SUFAMI_TURBO_A_RAM:
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break;
|
||||
return "SUFAMI_SLOTARAM";
|
||||
case SNES_MEMORY_SUFAMI_TURBO_B_RAM:
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break;
|
||||
return "SUFAMI_SLOTBRAM";
|
||||
case SNES_MEMORY_GAME_BOY_RAM:
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break;
|
||||
//return GameBoy::cartridge.ramdata;
|
||||
return "SGB_CARTRAM";
|
||||
//case SNES_MEMORY_GAME_BOY_RTC:
|
||||
// if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break;
|
||||
// return GameBoy::cartridge.rtcdata;
|
||||
|
||||
case SNES_MEMORY_WRAM:
|
||||
//return SNES::cpu.wram;
|
||||
return "WRAM";
|
||||
case SNES_MEMORY_APURAM:
|
||||
//return SNES::smp.apuram;
|
||||
return "APURAM";
|
||||
case SNES_MEMORY_VRAM:
|
||||
return "VRAM";
|
||||
case SNES_MEMORY_OAM:
|
||||
return "OAM";
|
||||
case SNES_MEMORY_CGRAM:
|
||||
return "CGRAM";
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned snes_get_memory_size(unsigned id) {
|
||||
if(SNES::cartridge.loaded() == false) return 0;
|
||||
unsigned size = 0;
|
||||
|
@ -599,31 +694,31 @@ void bus_write(unsigned addr, uint8_t val) {
|
|||
|
||||
int snes_poll_message()
|
||||
{
|
||||
if(interface.messages.size() == 0) return -1;
|
||||
return interface.messages.front().length();
|
||||
if(iface->messages.empty()) return -1;
|
||||
return iface->messages.front().length();
|
||||
}
|
||||
void snes_dequeue_message(char* buffer)
|
||||
{
|
||||
int len = interface.messages.front().length();
|
||||
memcpy(buffer,(const char*)interface.messages.front(),len);
|
||||
interface.messages.pop();
|
||||
int len = iface->messages.front().length();
|
||||
memcpy(buffer,(const char*)iface->messages.front(),len);
|
||||
iface->messages.pop();
|
||||
}
|
||||
|
||||
void snes_set_backdropColor(int color)
|
||||
{
|
||||
interface.backdropColor = color;
|
||||
iface->backdropColor = color;
|
||||
}
|
||||
|
||||
void snes_set_trace_callback(snes_trace_t callback)
|
||||
{
|
||||
if (callback)
|
||||
{
|
||||
interface.wanttrace = true;
|
||||
interface.ptrace = callback;
|
||||
iface->wanttrace = true;
|
||||
iface->ptrace = callback;
|
||||
}
|
||||
else
|
||||
{
|
||||
interface.wanttrace = false;
|
||||
interface.ptrace = 0;
|
||||
iface->wanttrace = false;
|
||||
iface->ptrace = 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,15 @@
|
|||
#define LIBSNES_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(LIBSNES_IMPORT)
|
||||
#define LIBSNES_IMPORTDECL __declspec(dllimport)
|
||||
#elif defined(LIBSNES_EXPORT)
|
||||
#define LIBSNES_IMPORTDECL __declspec(dllexport)
|
||||
#else
|
||||
#define LIBSNES_IMPORTDECL
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -67,12 +76,17 @@ extern "C" {
|
|||
#define SNES_MEMORY_OAM 103
|
||||
#define SNES_MEMORY_CGRAM 104
|
||||
|
||||
#define SNES_MEMORY_SYSBUS 200
|
||||
#define SNES_MEMORY_LOGICAL_REGS 201
|
||||
|
||||
typedef void (*snes_video_refresh_t)(const uint32_t *data, unsigned width, unsigned height);
|
||||
typedef void (*snes_audio_sample_t)(uint16_t left, uint16_t right);
|
||||
typedef void (*snes_input_poll_t)(void);
|
||||
typedef int16_t (*snes_input_state_t)(unsigned port, unsigned device, unsigned index, unsigned id);
|
||||
typedef void (*snes_input_notify_t)(int index);
|
||||
typedef void (*snes_trace_t)(const char *msg);
|
||||
typedef void* (*snes_allocSharedMemory_t)(const char* memtype, size_t amt);
|
||||
typedef void (*snes_freeSharedMemory_t)(void* ptr);
|
||||
|
||||
const char* snes_library_id(void);
|
||||
unsigned snes_library_revision_major(void);
|
||||
|
@ -84,6 +98,9 @@ void snes_set_input_poll(snes_input_poll_t);
|
|||
void snes_set_input_state(snes_input_state_t);
|
||||
void snes_set_input_notify(snes_input_notify_t);
|
||||
|
||||
void snes_set_allocSharedMemory(snes_allocSharedMemory_t);
|
||||
void snes_set_freeSharedMemory(snes_freeSharedMemory_t);
|
||||
|
||||
void snes_set_controller_port_device(bool port, unsigned device);
|
||||
void snes_set_cartridge_basename(const char *basename);
|
||||
|
||||
|
@ -129,6 +146,7 @@ void snes_unload_cartridge(void);
|
|||
|
||||
bool snes_get_region(void);
|
||||
uint8_t* snes_get_memory_data(unsigned id);
|
||||
const char* snes_get_memory_id_name(unsigned id);
|
||||
unsigned snes_get_memory_size(unsigned id);
|
||||
|
||||
//zeromus additions
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
#include <Windows.h>
|
||||
|
||||
#define LIBSNES_IMPORT
|
||||
#include "snes/snes.hpp"
|
||||
#include "libsnes.hpp"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define LIBSNES_IMPORT
|
||||
#include "../bsnes/target-libsnes/libsnes.hpp"
|
||||
|
||||
|
||||
HANDLE hPipe, hMapFile;
|
||||
void* hMapFilePtr;
|
||||
static bool running = false;
|
||||
|
||||
enum eMessage : int
|
||||
{
|
||||
|
@ -29,20 +35,21 @@ enum eMessage : int
|
|||
|
||||
//snes_set_cartridge_basename, //not used
|
||||
|
||||
eMessage_snes_load_cartridge_normal, //10
|
||||
eMessage_snes_load_cartridge_normal,
|
||||
eMessage_snes_load_cartridge_super_game_boy,
|
||||
|
||||
eMessage_snes_cb_video_refresh,
|
||||
eMessage_snes_cb_input_poll,
|
||||
eMessage_snes_cb_input_state,
|
||||
eMessage_snes_cb_input_notify,
|
||||
eMessage_snes_cb_audio_sample,
|
||||
eMessage_snes_cb_scanlineStart, //16
|
||||
eMessage_snes_cb_scanlineStart,
|
||||
eMessage_snes_cb_path_request,
|
||||
eMessage_snes_cb_trace_callback,
|
||||
|
||||
eMessage_snes_get_region,
|
||||
|
||||
eMessage_snes_get_memory_size, //20
|
||||
eMessage_snes_get_memory_size,
|
||||
eMessage_snes_get_memory_data,
|
||||
eMessage_peek,
|
||||
eMessage_poke,
|
||||
|
@ -62,7 +69,11 @@ enum eMessage : int
|
|||
eMessage_snes_enable_audio,
|
||||
eMessage_snes_set_layer_enable,
|
||||
eMessage_snes_set_backdropColor,
|
||||
eMessage_snes_peek_logical_register
|
||||
eMessage_snes_peek_logical_register,
|
||||
|
||||
eMessage_snes_allocSharedMemory,
|
||||
eMessage_snes_freeSharedMemory,
|
||||
eMessage_GetMemoryIdName
|
||||
};
|
||||
|
||||
void ReadPipeBuffer(void* buf, int len)
|
||||
|
@ -90,10 +101,10 @@ template<> bool ReadPipe<bool>()
|
|||
return !!ReadPipe<char>();
|
||||
}
|
||||
|
||||
FILE* outf = NULL;
|
||||
|
||||
void WritePipeBuffer(const void* buf, int len)
|
||||
{
|
||||
//static FILE* outf = NULL;
|
||||
//if(!outf) outf = fopen("c:\\trace.bin","wb"); fwrite(buf,1,len,outf); fflush(outf);
|
||||
DWORD bytesWritten;
|
||||
BOOL result = WriteFile(hPipe, buf, len, &bytesWritten, NULL);
|
||||
|
@ -108,9 +119,9 @@ template<typename T> void WritePipe(const T& val)
|
|||
|
||||
void WritePipeString(const char* str)
|
||||
{
|
||||
//TODO - write string length
|
||||
int len = strlen(str);
|
||||
WritePipeBuffer(str,len+1);
|
||||
WritePipe(len);
|
||||
WritePipeBuffer(str,len);
|
||||
}
|
||||
|
||||
std::string ReadPipeString()
|
||||
|
@ -164,13 +175,15 @@ void FlushAudio()
|
|||
|
||||
WritePipe(eMessage_snes_cb_audio_sample);
|
||||
|
||||
int nsamples = audiobuffer_idx/2;
|
||||
int nsamples = audiobuffer_idx;
|
||||
WritePipe(nsamples);
|
||||
int destOfs = ReadPipe<int>();
|
||||
char* buf = (char*)hMapFilePtr + destOfs;
|
||||
memcpy(buf,audiobuffer,nsamples*4);
|
||||
char* buf = ReadPipeSharedPtr();
|
||||
memcpy(buf,audiobuffer,nsamples*2);
|
||||
//extra just in case we had to unexpectedly flush audio and then carry on with some other process... yeah, its rickety.
|
||||
WritePipe(0); //dummy synchronization
|
||||
|
||||
//wait for frontend to consume data
|
||||
|
||||
ReadPipe<int>(); //dummy synchronization
|
||||
WritePipe(0); //dummy synchronization
|
||||
audiobuffer_idx = 0;
|
||||
|
@ -222,10 +235,62 @@ const char* snes_path_request(int slot, const char* hint)
|
|||
strcpy(ret,str.c_str());
|
||||
return ret;
|
||||
}
|
||||
|
||||
void RunMessageLoop();
|
||||
void snes_scanlineStart(int line)
|
||||
{
|
||||
WritePipe(eMessage_snes_cb_scanlineStart);
|
||||
WritePipe(line);
|
||||
|
||||
//we've got to wait for the frontend to finish processing.
|
||||
//in theory we could let emulation proceed after snagging the vram and registers, and do decoding and stuff on another thread...
|
||||
//but its too hard for now.
|
||||
RunMessageLoop();
|
||||
}
|
||||
|
||||
class SharedMemoryBlock
|
||||
{
|
||||
public:
|
||||
std::string memtype;
|
||||
HANDLE handle;
|
||||
};
|
||||
|
||||
static std::map<void*,SharedMemoryBlock*> memHandleTable;
|
||||
|
||||
void* snes_allocSharedMemory(const char* memtype, size_t amt)
|
||||
{
|
||||
if(!running) return NULL;
|
||||
WritePipe(eMessage_snes_allocSharedMemory);
|
||||
WritePipeString(memtype);
|
||||
WritePipe(amt);
|
||||
|
||||
std::string blockname = ReadPipeString();
|
||||
|
||||
auto mapfile = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, blockname.c_str());
|
||||
|
||||
if(mapfile == INVALID_HANDLE_VALUE)
|
||||
return NULL;
|
||||
|
||||
auto ptr = MapViewOfFile(mapfile, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
|
||||
|
||||
auto smb = new SharedMemoryBlock();
|
||||
smb->memtype = memtype;
|
||||
smb->handle = mapfile;
|
||||
|
||||
memHandleTable[ptr] = smb;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void snes_freeSharedMemory(void* ptr)
|
||||
{
|
||||
if(!running) return;
|
||||
if(!ptr) return;
|
||||
auto smb = memHandleTable.find(ptr)->second;
|
||||
UnmapViewOfFile(ptr);
|
||||
CloseHandle(smb->handle);
|
||||
WritePipe(eMessage_snes_freeSharedMemory);
|
||||
WritePipeString(smb->memtype.c_str());
|
||||
}
|
||||
|
||||
void InitBsnes()
|
||||
|
@ -237,49 +302,30 @@ void InitBsnes()
|
|||
snes_set_input_state(snes_input_state);
|
||||
snes_set_input_notify(snes_input_notify);
|
||||
snes_set_path_request(snes_path_request);
|
||||
|
||||
snes_set_allocSharedMemory(snes_allocSharedMemory);
|
||||
snes_set_freeSharedMemory(snes_freeSharedMemory);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
void RunMessageLoop()
|
||||
{
|
||||
if(argc != 2)
|
||||
{
|
||||
printf("This program is run from the libsneshawk emulator core. It is useless to you directly.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(!strcmp(argv[1],"Bongizong"))
|
||||
{
|
||||
fprintf(stderr,"Honga Wongkong");
|
||||
exit(0x16817);
|
||||
}
|
||||
|
||||
InitBsnes();
|
||||
|
||||
char pipename[256];
|
||||
sprintf(pipename, "\\\\.\\Pipe\\%s",argv[1]);
|
||||
|
||||
hPipe = CreateFile(pipename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
|
||||
if(hPipe == INVALID_HANDLE_VALUE)
|
||||
return 1;
|
||||
|
||||
hMapFile = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, argv[1]);
|
||||
if(hMapFile == INVALID_HANDLE_VALUE)
|
||||
return 1;
|
||||
|
||||
hMapFilePtr = MapViewOfFile(hMapFile, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
//printf("Reading message from pipe...\n");
|
||||
auto msg = ReadPipe<eMessage>();
|
||||
//printf("slam %08X\n",msg);
|
||||
switch(msg)
|
||||
{
|
||||
case eMessage_Complete:
|
||||
return;
|
||||
|
||||
case eMessage_snes_library_id: WritePipeString(snes_library_id()); break;
|
||||
case eMessage_snes_library_revision_major: WritePipe(snes_library_revision_major()); break;
|
||||
case eMessage_snes_library_revision_minor: WritePipe(snes_library_revision_minor()); break;
|
||||
|
||||
case eMessage_snes_init:
|
||||
snes_init();
|
||||
WritePipe(eMessage_Complete);
|
||||
break;
|
||||
case eMessage_snes_power: snes_power(); break;
|
||||
case eMessage_snes_reset: snes_reset(); break;
|
||||
|
@ -304,6 +350,28 @@ int main(int argc, char** argv)
|
|||
break;
|
||||
}
|
||||
|
||||
case eMessage_snes_load_cartridge_super_game_boy:
|
||||
{
|
||||
std::string rom_xml = ReadPipeString();
|
||||
const char* rom_xmlptr = NULL;
|
||||
if(rom_xml != "") rom_xmlptr = rom_xml.c_str();
|
||||
Blob rom_data = ReadPipeBlob();
|
||||
uint32 rom_length = rom_data.size();
|
||||
|
||||
std::string dmg_xml = ReadPipeString();
|
||||
const char* dmg_xmlptr = NULL;
|
||||
if(dmg_xml != "") dmg_xmlptr = dmg_xml.c_str();
|
||||
Blob dmg_data = ReadPipeBlob();
|
||||
uint32 dmg_length = dmg_data.size();
|
||||
|
||||
bool ret = snes_load_cartridge_super_game_boy(rom_xmlptr,(uint8*)&rom_data[0],rom_length, dmg_xmlptr,(uint8*)&dmg_data[0], dmg_length);
|
||||
|
||||
WritePipe(eMessage_Complete);
|
||||
WritePipe((char)(ret?1:0));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case eMessage_snes_get_region:
|
||||
WritePipe((char)snes_get_region());
|
||||
break;
|
||||
|
@ -421,9 +489,68 @@ int main(int argc, char** argv)
|
|||
WritePipe(snes_peek_logical_register(ReadPipe<int>()));
|
||||
break;
|
||||
|
||||
case eMessage_GetMemoryIdName:
|
||||
{
|
||||
uint32 id = ReadPipe<uint32>();
|
||||
const char* ret = snes_get_memory_id_name(id);
|
||||
if(!ret) ret = "";
|
||||
WritePipeString(ret);
|
||||
break;
|
||||
}
|
||||
|
||||
} //switch(msg)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OpenConsole()
|
||||
{
|
||||
AllocConsole();
|
||||
freopen("CONOUT$", "w", stdout);
|
||||
freopen("CONOUT$", "w", stderr);
|
||||
freopen("CONIN$", "r", stdin);
|
||||
}
|
||||
|
||||
int xmain(int argc, char** argv)
|
||||
{
|
||||
if(argc != 2)
|
||||
{
|
||||
printf("This program is run from the libsneshawk emulator core. It is useless to you directly.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(!strcmp(argv[1],"Bongizong"))
|
||||
{
|
||||
fprintf(stderr,"Honga Wongkong");
|
||||
exit(0x16817);
|
||||
}
|
||||
|
||||
char pipename[256];
|
||||
sprintf(pipename, "\\\\.\\Pipe\\%s",argv[1]);
|
||||
|
||||
if(!strncmp(argv[1],"console",7))
|
||||
{
|
||||
OpenConsole();
|
||||
}
|
||||
|
||||
printf("pipe: %s\n",pipename);
|
||||
|
||||
hPipe = CreateFile(pipename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
|
||||
if(hPipe == INVALID_HANDLE_VALUE)
|
||||
return 1;
|
||||
|
||||
hMapFile = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, argv[1]);
|
||||
if(hMapFile == INVALID_HANDLE_VALUE)
|
||||
return 1;
|
||||
|
||||
hMapFilePtr = MapViewOfFile(hMapFile, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
|
||||
|
||||
running = true;
|
||||
printf("running\n");
|
||||
|
||||
RunMessageLoop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -434,12 +561,17 @@ int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine
|
|||
|
||||
if(argc != 2)
|
||||
{
|
||||
if(IDCANCEL == MessageBox(0,"This program is run from the libsneshawk emulator core. It is useless to you directly. But if you're really, that curious, click cancel.","Whatfor my daddy-o",MB_OKCANCEL))
|
||||
if(IDOK == MessageBox(0,"This program is run from the libsneshawk emulator core. It is useless to you directly. But if you're really, that curious, click OK.","Whatfor my daddy-o",MB_OKCANCEL))
|
||||
{
|
||||
ShellExecute(0,"open","http://www.youtube.com/watch?v=boanuwUMNNQ#t=98s",NULL,NULL,SW_SHOWNORMAL);
|
||||
}
|
||||
exit(1);
|
||||
|
||||
}
|
||||
main(argc,argv);
|
||||
xmain(argc,argv);
|
||||
}
|
||||
|
||||
void pwrap_init()
|
||||
{
|
||||
InitBsnes();
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
gcc libco_win32threads.c -o libco.dll -Wall -shared -O0 -g
|
||||
mv libco.dll ../../BizHawk.MultiClient/output/dll/libco_msvc_win32.dll
|
|
@ -1,92 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{8D864AC0-4BC2-48EA-8957-53C704F4BC57}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>libsnes_pwrap</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>..\..\Bizhawk.MultiClient\output\dll</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>..\..\Bizhawk.MultiClient\output\dll</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>libsneshawk.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>lib /machine:i386 /def:..\bsnes\libsneshawk.def</Command>
|
||||
</PreBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>libsneshawk.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>lib /machine:i386 /def:..\bsnes\libsneshawk.def</Command>
|
||||
</PreBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="libsnes_pwrap.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="libsnes_pwrap.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
Binary file not shown.
Loading…
Reference in New Issue