BizHawk/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs

777 lines
25 KiB
C#

//TODO hook up newer file ID stuff, think about how to combine it with the disc ID
//TODO change display manager to not require 0xFF alpha channel set on videoproviders. check gdi+ and opengl! this will get us a speedup in some places
//TODO Disc.Structure.Sessions[0].length_aba was 0
//TODO add sram dump option (bold it if dirty) to file menu
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.IO;
using System.Collections.Generic;
using Newtonsoft.Json;
using BizHawk.Emulation.Common;
using BizHawk.Common;
#pragma warning disable 649 //adelikat: Disable dumb warnings until this file is complete
namespace BizHawk.Emulation.Cores.Sony.PSX
{
[CoreAttributes(
"Octoshock",
"Ryphecha",
isPorted: true,
isReleased: false
)]
public unsafe class Octoshock : IEmulator, IVideoProvider, ISyncSoundProvider, IMemoryDomains, ISaveRam, IStatable, IDriveLight, IInputPollable, ISettable<Octoshock.Settings, Octoshock.SyncSettings>, IDebuggable
{
public string SystemId { get { return "PSX"; } }
public static readonly ControllerDefinition DualShockController = new ControllerDefinition
{
Name = "DualShock Controller",
BoolButtons =
{
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Select", "P1 Start", "P1 Square", "P1 Triangle", "P1 Circle", "P1 Cross", "P1 L1",
"P1 R1", "P1 L2", "P1 R2", "P1 L3", "P1 R3", "P1 MODE",
//"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Select", "P2 Start", "P2 Square", "P2 Triangle", "P2 Circle", "P2 Cross", "P2 L1",
//"P2 R1", "P2 L2", "P2 R2", "P2 L3", "P2 R3", "P2 MODE",
"Eject", "Reset",
},
FloatControls =
{
"P1 LStick X", "P1 LStick Y", "P1 RStick X", "P1 RStick Y",
//"P2 LStick X", "P2 LStick Y", "P2 RStick X", "P2 RStick Y",
//TODO: Fix "Disc Switch",
},
FloatRanges =
{
new[] {0.0f, 128.0f, 255.0f},
new[] {255.0f, 128.0f, 0.0f},
new[] {0.0f, 128.0f, 255.0f},
new[] {255.0f, 128.0f, 0.0f},
}
};
public string BoardName { get { return null; } }
private int[] frameBuffer = new int[0];
private Random rand = new Random();
public CoreComm CoreComm { get; private set; }
public IVideoProvider VideoProvider { get { return this; } }
//we can only have one active core at a time, due to the lib being so static.
//so we'll track the current one here and detach the previous one whenever a new one is booted up.
static Octoshock CurrOctoshockCore;
IntPtr psx;
DiscSystem.Disc disc;
DiscInterface discInterface;
bool disposed = false;
public void Dispose()
{
if (disposed) return;
OctoshockDll.shock_Destroy(psx);
psx = IntPtr.Zero;
disposed = true;
}
/// <summary>
/// Wraps the ShockDiscRef returned from the DLL and acts as a bridge between it and a DiscSystem disc
/// </summary>
class DiscInterface : IDisposable
{
public DiscInterface(DiscSystem.Disc disc, Action cbActivity)
{
this.Disc = disc;
cbReadTOC = ShockDisc_ReadTOC;
cbReadLBA = ShockDisc_ReadLBA2448;
this.cbActivity = cbActivity;
OctoshockDll.shock_CreateDisc(out OctoshockHandle, IntPtr.Zero, disc.LBACount, cbReadTOC, cbReadLBA, true);
}
OctoshockDll.ShockDisc_ReadTOC cbReadTOC;
OctoshockDll.ShockDisc_ReadLBA cbReadLBA;
Action cbActivity;
public DiscSystem.Disc Disc;
public IntPtr OctoshockHandle;
public void Dispose()
{
OctoshockDll.shock_DestroyDisc(OctoshockHandle);
OctoshockHandle = IntPtr.Zero;
}
int ShockDisc_ReadTOC(IntPtr opaque, OctoshockDll.ShockTOC* read_target, OctoshockDll.ShockTOCTrack* tracks101)
{
read_target->disc_type = 1; //hardcoded in octoshock
read_target->first_track = (byte)Disc.TOCRaw.FirstRecordedTrackNumber; //i _think_ thats what is meant here
read_target->last_track = (byte)Disc.TOCRaw.LastRecordedTrackNumber; //i _think_ thats what is meant here
tracks101[0].lba = tracks101[0].adr = tracks101[0].control = 0;
for (int i = 1; i < 100; i++)
{
var item = Disc.TOCRaw.TOCItems[i];
tracks101[i].adr = 1; //not sure what this is
tracks101[i].lba = (uint)item.LBATimestamp.Sector;
tracks101[i].control = (byte)item.Control;
}
////the lead-out track is to be synthesized
tracks101[read_target->last_track + 1].adr = 1;
tracks101[read_target->last_track + 1].control = 0;
tracks101[read_target->last_track + 1].lba = (uint)Disc.TOCRaw.LeadoutTimestamp.Sector;
////laaaame
//tracks101[read_target->last_track + 1].lba =
// (uint)(
// Disc.Structure.Sessions[0].Tracks[read_target->last_track - 1].Start_ABA //AUGH. see comment in Start_ABA
// + Disc.Structure.Sessions[0].Tracks[read_target->last_track - 1].LengthInSectors
// - 150
// );
//element 100 is to be copied as the lead-out track
tracks101[100] = tracks101[read_target->last_track + 1];
return OctoshockDll.SHOCK_OK;
}
byte[] SectorBuffer = new byte[2352];
int ShockDisc_ReadLBA2448(IntPtr opaque, int lba, void* dst)
{
cbActivity();
//lets you check subcode generation by logging it and checking against the CCD subcode
bool subcodeLog = false;
bool readLog = false;
if (subcodeLog) Console.Write("{0}|", lba);
else if (readLog) Console.WriteLine("Read Sector: " + lba);
Disc.ReadLBA_2352(lba, SectorBuffer, 0);
Marshal.Copy(SectorBuffer, 0, new IntPtr(dst), 2352);
Disc.ReadLBA_SectorEntry(lba).SubcodeSector.ReadSubcodeDeinterleaved(SectorBuffer, 0);
Marshal.Copy(SectorBuffer, 0, new IntPtr((byte*)dst + 2352), 96);
if (subcodeLog)
{
for (int i = 0; i < 24; i++)
Console.Write("{0:X2}", *((byte*)dst + 2352 + i));
Console.WriteLine();
}
return OctoshockDll.SHOCK_OK;
}
}
//note: its annoying that we have to have a disc before constructing this.
//might want to change that later. HOWEVER - we need to definitely have a region, at least
public Octoshock(CoreComm comm, List<DiscSystem.Disc> discs, byte[] exe, object settings, object syncSettings)
{
//analyze our first disc from the list by default, because i dont know
DiscSystem.Disc disc = null;
if (discs != null)
disc = discs[0];
ServiceProvider = new BasicServiceProvider(this);
CoreComm = comm;
_Settings = (Settings)settings ?? new Settings();
_SyncSettings = (SyncSettings)syncSettings ?? new SyncSettings();
DriveLightEnabled = true;
Attach();
this.disc = disc;
string firmwareRegion = "U";
OctoshockDll.eRegion region = OctoshockDll.eRegion.NA;
if (disc != null)
{
discInterface = new DiscInterface(disc,
() =>
{
//if current disc this delegate disc, activity is happening
if (disc == this.disc)
DriveLightOn = true;
});
//determine region of the provided disc
OctoshockDll.ShockDiscInfo discInfo;
OctoshockDll.shock_AnalyzeDisc(discInterface.OctoshockHandle, out discInfo);
//try to acquire the appropriate firmware
if (discInfo.region == OctoshockDll.eRegion.EU) firmwareRegion = "E";
if (discInfo.region == OctoshockDll.eRegion.JP) firmwareRegion = "J";
}
else
{
//assume its NA region for test programs, for now. could it be read out of the ps-exe header?
}
byte[] firmware = comm.CoreFileProvider.GetFirmware("PSX", "U", true, "A PSX `" + firmwareRegion + "` region bios file is required");
//create the instance
fixed (byte* pFirmware = firmware)
OctoshockDll.shock_Create(out psx, region, pFirmware);
SetMemoryDomains();
//these should track values in octoshock gpu.cpp FillVideoParams
//if (discInfo.region == OctoshockDll.eRegion.EU)
//{
// VirtualWidth = 377; // " Dunno :( "
// VirtualHeight = 288;
//}
//else
//{
// VirtualWidth = 320; // Dunno :(
// VirtualHeight = 240;
//}
//BUT-for now theyre normalized (NOTE: THIS MESSES UP THE ASPECT RATIOS)
VirtualWidth = 800;
VirtualHeight = 480;
//set a default framebuffer
BufferWidth = VirtualWidth;
BufferHeight = VirtualHeight;
frameBuffer = new int[BufferWidth * BufferHeight];
if (disc != null)
{
OctoshockDll.shock_OpenTray(psx);
OctoshockDll.shock_SetDisc(psx, discInterface.OctoshockHandle);
OctoshockDll.shock_CloseTray(psx);
}
else
{
//must be an exe
fixed (byte* pExeBuffer = exe)
OctoshockDll.shock_MountEXE(psx, pExeBuffer, exe.Length);
}
OctoshockDll.shock_Peripheral_Connect(psx, 0x01, OctoshockDll.ePeripheralType.DualShock);
//do this after framebuffers and peripherals and whatever crap are setup. kind of lame, but thats how it is for now
StudySaveBufferSize();
OctoshockDll.shock_PowerOn(psx);
}
public IEmulatorServiceProvider ServiceProvider { get; private set; }
public IInputCallbackSystem InputCallbacks { get { throw new NotImplementedException(); } }
public bool DriveLightEnabled { get; private set; }
public bool DriveLightOn { get; private set; }
void Attach()
{
//attach this core as the current
if (CurrOctoshockCore != null)
CurrOctoshockCore.Dispose();
CurrOctoshockCore = this;
//the psx instance cant be created until the desired region is known, which needs a disc, so we need the dll static attached first
}
static Octoshock()
{
}
[FeatureNotImplemented]
public void ResetCounters()
{
// FIXME when all this stuff is implemented
Frame = 0;
}
void SetInput()
{
uint buttons = 0;
//dualshock style
if (Controller["Select"]) buttons |= 1;
if (Controller["L3"]) buttons |= 2;
if (Controller["R3"]) buttons |= 4;
if (Controller["Start"]) buttons |= 8;
if (Controller["Up"]) buttons |= 16;
if (Controller["Right"]) buttons |= 32;
if (Controller["Down"]) buttons |= 64;
if (Controller["Left"]) buttons |= 128;
if (Controller["L2"]) buttons |= 256;
if (Controller["R2"]) buttons |= 512;
if (Controller["L1"]) buttons |= 1024;
if (Controller["R1"]) buttons |= 2048;
if (Controller["Triangle"]) buttons |= 4096;
if (Controller["Circle"]) buttons |= 8192;
if (Controller["Cross"]) buttons |= 16384;
if (Controller["Square"]) buttons |= 32768;
if (Controller["MODE"]) buttons |= 65536;
byte left_x = (byte)Controller.GetFloat("LStick X");
byte left_y = (byte)Controller.GetFloat("LStick Y");
byte right_x = (byte)Controller.GetFloat("RStick X");
byte right_y = (byte)Controller.GetFloat("RStick Y");
OctoshockDll.shock_Peripheral_SetPadInput(psx, 0x01, buttons, left_x, left_y, right_x, right_y);
}
public void FrameAdvance(bool render, bool rendersound)
{
Frame++;
DriveLightOn = false;
SetInput();
OctoshockDll.shock_Step(psx, OctoshockDll.eShockStep.Frame);
//what happens to sound in this case?
if (render == false) return;
OctoshockDll.ShockFramebufferInfo fb = new OctoshockDll.ShockFramebufferInfo();
if (_Settings.ResolutionMode == eResolutionMode.PixelPro)
fb.flags = OctoshockDll.eShockFramebufferFlags.Normalize;
OctoshockDll.shock_GetFramebuffer(psx, ref fb);
int w = fb.width;
int h = fb.height;
BufferWidth = w;
BufferHeight = h;
switch (_Settings.ResolutionMode)
{
case eResolutionMode.Debug:
VirtualWidth = w;
VirtualHeight = h;
break;
case eResolutionMode.Mednafen:
VirtualWidth = 320;
VirtualHeight = 240;
break;
case eResolutionMode.PixelPro:
VirtualWidth = 800;
VirtualHeight = 480;
break;
case eResolutionMode.TweakedMednafen:
VirtualWidth = 400;
VirtualHeight = 300;
break;
}
int len = w * h;
if (frameBuffer.Length != len)
{
Console.WriteLine("PSX FB size: {0},{1}", fb.width, fb.height);
frameBuffer = new int[len];
}
fixed (int* ptr = frameBuffer)
{
fb.ptr = ptr;
OctoshockDll.shock_GetFramebuffer(psx, ref fb);
}
fixed (short* samples = sbuff)
{
sbuffcontains = OctoshockDll.shock_GetSamples(psx, null);
if (sbuffcontains * 2 > sbuff.Length) throw new InvalidOperationException("shock_GetSamples returned too many samples: " + sbuffcontains);
OctoshockDll.shock_GetSamples(psx, samples);
}
}
public ControllerDefinition ControllerDefinition { get { return DualShockController; } }
public IController Controller { get; set; }
public int Frame { get; private set; }
public int LagCount { get; set; }
public bool IsLagFrame { get; private set; }
[FeatureNotImplemented]
public bool DeterministicEmulation { get { return true; } }
public int[] GetVideoBuffer() { return frameBuffer; }
public int VirtualWidth { get; private set; }
public int VirtualHeight { get; private set; }
public int BufferWidth { get; private set; }
public int BufferHeight { get; private set; }
public int BackgroundColor { get { return 0; } }
#region Debugging
unsafe void SetMemoryDomains()
{
var mmd = new List<MemoryDomain>();
IntPtr ptr;
int size;
OctoshockDll.shock_GetMemData(psx, out ptr, out size, OctoshockDll.eMemType.MainRAM);
mmd.Add(MemoryDomain.FromIntPtr("MainRAM", size, MemoryDomain.Endian.Little, ptr, true));
OctoshockDll.shock_GetMemData(psx, out ptr, out size, OctoshockDll.eMemType.GPURAM);
mmd.Add(MemoryDomain.FromIntPtr("GPURAM", size, MemoryDomain.Endian.Little, ptr, true));
OctoshockDll.shock_GetMemData(psx, out ptr, out size, OctoshockDll.eMemType.SPURAM);
mmd.Add(MemoryDomain.FromIntPtr("SPURAM", size, MemoryDomain.Endian.Little, ptr, true));
OctoshockDll.shock_GetMemData(psx, out ptr, out size, OctoshockDll.eMemType.BiosROM);
mmd.Add(MemoryDomain.FromIntPtr("BiosROM", size, MemoryDomain.Endian.Little, ptr, true));
OctoshockDll.shock_GetMemData(psx, out ptr, out size, OctoshockDll.eMemType.PIOMem);
mmd.Add(MemoryDomain.FromIntPtr("PIOMem", size, MemoryDomain.Endian.Little, ptr, true));
OctoshockDll.shock_GetMemData(psx, out ptr, out size, OctoshockDll.eMemType.DCache);
mmd.Add(MemoryDomain.FromIntPtr("DCache", size, MemoryDomain.Endian.Little, ptr, true));
MemoryDomains = new MemoryDomainList(mmd, 0);
}
public MemoryDomainList MemoryDomains { get; private set; }
#endregion
#region ISoundProvider
private short[] sbuff = new short[1454 * 2]; //this is the most ive ever seen.. dont know why
private int sbuffcontains = 0;
public ISoundProvider SoundProvider { get { throw new InvalidOperationException(); } }
public ISyncSoundProvider SyncSoundProvider { get { return this; } }
public bool StartAsyncSound() { return false; }
public void EndAsyncSound() { }
public void GetSamples(out short[] samples, out int nsamp)
{
samples = sbuff;
nsamp = sbuffcontains;
}
public void DiscardSamples()
{
sbuffcontains = 0;
}
#endregion
#region ISaveRam
public byte[] CloneSaveRam()
{
var buf = new byte[128 * 1024];
fixed (byte* pbuf = buf)
{
var transaction = new OctoshockDll.ShockMemcardTransaction();
transaction.buffer128k = pbuf;
transaction.transaction = OctoshockDll.eShockMemcardTransaction.Read;
OctoshockDll.shock_Peripheral_MemcardTransact(psx, 0x01, ref transaction);
}
return buf;
}
public void StoreSaveRam(byte[] data)
{
fixed (byte* pbuf = data)
{
var transaction = new OctoshockDll.ShockMemcardTransaction();
transaction.buffer128k = pbuf;
transaction.transaction = OctoshockDll.eShockMemcardTransaction.Write;
OctoshockDll.shock_Peripheral_MemcardTransact(psx, 0x01, ref transaction);
}
}
public bool SaveRamModified
{
get
{
var transaction = new OctoshockDll.ShockMemcardTransaction();
transaction.transaction = OctoshockDll.eShockMemcardTransaction.CheckDirty;
return OctoshockDll.shock_Peripheral_MemcardTransact(psx, 0x01, ref transaction) == OctoshockDll.SHOCK_TRUE;
}
}
#endregion //ISaveRam
#region Savestates
//THIS IS STILL AWFUL
JsonSerializer ser = new JsonSerializer() { Formatting = Formatting.Indented };
class TextStateData
{
public int Frame;
public int LagCount;
public bool IsLagFrame;
}
public void SaveStateText(TextWriter writer)
{
var s = new TextState<TextStateData>();
s.Prepare();
var transaction = new OctoshockDll.ShockStateTransaction()
{
transaction = OctoshockDll.eShockStateTransaction.TextSave,
ff = s.GetFunctionPointersSave()
};
int result = OctoshockDll.shock_StateTransaction(psx, ref transaction);
if (result != OctoshockDll.SHOCK_OK)
throw new InvalidOperationException("eShockStateTransaction.TextSave returned error!");
s.ExtraData.IsLagFrame = IsLagFrame;
s.ExtraData.LagCount = LagCount;
s.ExtraData.Frame = Frame;
ser.Serialize(writer, s);
// TODO write extra copy of stuff we don't use (WHY?)
}
public void LoadStateText(TextReader reader)
{
var s = (TextState<TextStateData>)ser.Deserialize(reader, typeof(TextState<TextStateData>));
s.Prepare();
var transaction = new OctoshockDll.ShockStateTransaction()
{
transaction = OctoshockDll.eShockStateTransaction.TextLoad,
ff = s.GetFunctionPointersLoad()
};
int result = OctoshockDll.shock_StateTransaction(psx, ref transaction);
if (result != OctoshockDll.SHOCK_OK)
throw new InvalidOperationException("eShockStateTransaction.TextLoad returned error!");
IsLagFrame = s.ExtraData.IsLagFrame;
LagCount = s.ExtraData.LagCount;
Frame = s.ExtraData.Frame;
}
byte[] savebuff;
byte[] savebuff2;
void StudySaveBufferSize()
{
var transaction = new OctoshockDll.ShockStateTransaction();
transaction.transaction = OctoshockDll.eShockStateTransaction.BinarySize;
int size = OctoshockDll.shock_StateTransaction(psx, ref transaction);
savebuff = new byte[size];
savebuff2 = new byte[savebuff.Length + 13];
}
public void SaveStateBinary(BinaryWriter writer)
{
fixed (byte* psavebuff = savebuff)
{
var transaction = new OctoshockDll.ShockStateTransaction()
{
transaction = OctoshockDll.eShockStateTransaction.BinarySave,
buffer = psavebuff,
bufferLength = savebuff.Length
};
int result = OctoshockDll.shock_StateTransaction(psx, ref transaction);
if (result != OctoshockDll.SHOCK_OK)
throw new InvalidOperationException("eShockStateTransaction.BinarySave returned error!");
writer.Write(savebuff.Length);
writer.Write(savebuff);
// other variables
writer.Write(IsLagFrame);
writer.Write(LagCount);
writer.Write(Frame);
}
}
public void LoadStateBinary(BinaryReader reader)
{
fixed (byte* psavebuff = savebuff)
{
var transaction = new OctoshockDll.ShockStateTransaction()
{
transaction = OctoshockDll.eShockStateTransaction.BinaryLoad,
buffer = psavebuff,
bufferLength = savebuff.Length
};
int length = reader.ReadInt32();
if (length != savebuff.Length)
throw new InvalidOperationException("Save buffer size mismatch!");
reader.Read(savebuff, 0, length);
int ret = OctoshockDll.shock_StateTransaction(psx, ref transaction);
if (ret != OctoshockDll.SHOCK_OK)
throw new InvalidOperationException("eShockStateTransaction.BinaryLoad returned error!");
// other variables
IsLagFrame = reader.ReadBoolean();
LagCount = reader.ReadInt32();
Frame = reader.ReadInt32();
}
}
public byte[] SaveStateBinary()
{
//this are objectionable shenanigans, but theyre required to get the extra info in the stream. we need a better approach.
var ms = new MemoryStream(savebuff2, true);
var bw = new BinaryWriter(ms);
SaveStateBinary(bw);
bw.Flush();
if (ms.Position != savebuff2.Length)
throw new InvalidOperationException();
ms.Close();
return savebuff2;
}
public bool BinarySaveStatesPreferred
{
get { return true; }
}
#endregion
#region Settings
Settings _Settings = new Settings();
SyncSettings _SyncSettings;
public enum eResolutionMode
{
PixelPro, Debug,
Mednafen, TweakedMednafen
}
public class SyncSettings
{
public SyncSettings Clone()
{
return (SyncSettings)MemberwiseClone();
}
}
public class Settings
{
[DisplayName("Resolution Mode")]
[Description("Stuf")]
[DefaultValue(eResolutionMode.PixelPro)]
public eResolutionMode ResolutionMode { get; set; }
public Settings()
{
SettingsUtil.SetDefaultValues(this);
}
public Settings Clone()
{
return (Settings)MemberwiseClone();
}
}
public Settings GetSettings()
{
return _Settings.Clone();
}
public SyncSettings GetSyncSettings()
{
return _SyncSettings.Clone();
}
public bool PutSettings(Settings o)
{
_Settings = o;
//TODO
//var native = _Settings.GetNativeSettings();
//BizSwan.bizswan_putsettings(Core, ref native);
return false;
}
public bool PutSyncSettings(SyncSettings o)
{
_SyncSettings = o;
return false;
}
#endregion
#region IDebuggable
public IDictionary<string, int> GetCpuFlagsAndRegisters()
{
Dictionary<string, int> ret = new Dictionary<string, int>();
var regs = new OctoshockDll.ShockRegisters_CPU();
OctoshockDll.shock_GetRegisters_CPU(psx, ref regs);
ret["r1"] = (int)regs.GPR[1]; ret["r2"] = (int)regs.GPR[2]; ret["r3"] = (int)regs.GPR[3];
ret["r4"] = (int)regs.GPR[4]; ret["r5"] = (int)regs.GPR[5]; ret["r6"] = (int)regs.GPR[6]; ret["r7"] = (int)regs.GPR[7];
ret["r8"] = (int)regs.GPR[8]; ret["r9"] = (int)regs.GPR[9]; ret["r10"] = (int)regs.GPR[10]; ret["r11"] = (int)regs.GPR[11];
ret["r12"] = (int)regs.GPR[12]; ret["r13"] = (int)regs.GPR[13]; ret["r14"] = (int)regs.GPR[14]; ret["r15"] = (int)regs.GPR[15];
ret["r16"] = (int)regs.GPR[16]; ret["r17"] = (int)regs.GPR[17]; ret["r18"] = (int)regs.GPR[18]; ret["r19"] = (int)regs.GPR[19];
ret["r20"] = (int)regs.GPR[20]; ret["r21"] = (int)regs.GPR[21]; ret["r22"] = (int)regs.GPR[22]; ret["r23"] = (int)regs.GPR[23];
ret["r24"] = (int)regs.GPR[24]; ret["r25"] = (int)regs.GPR[25]; ret["r26"] = (int)regs.GPR[26]; ret["r27"] = (int)regs.GPR[27];
ret["r28"] = (int)regs.GPR[28]; ret["r29"] = (int)regs.GPR[29]; ret["r30"] = (int)regs.GPR[30]; ret["r31"] = (int)regs.GPR[31];
ret["at"] = (int)regs.GPR[1];
ret["v0"] = (int)regs.GPR[2]; ret["v1"] = (int)regs.GPR[3];
ret["a0"] = (int)regs.GPR[4]; ret["a1"] = (int)regs.GPR[5]; ret["a2"] = (int)regs.GPR[6]; ret["a3"] = (int)regs.GPR[7];
ret["t0"] = (int)regs.GPR[8]; ret["t1"] = (int)regs.GPR[9]; ret["t2"] = (int)regs.GPR[10]; ret["t3"] = (int)regs.GPR[11];
ret["t4"] = (int)regs.GPR[12]; ret["t5"] = (int)regs.GPR[13]; ret["t6"] = (int)regs.GPR[14]; ret["t7"] = (int)regs.GPR[15];
ret["s0"] = (int)regs.GPR[16]; ret["s1"] = (int)regs.GPR[17]; ret["s2"] = (int)regs.GPR[18]; ret["s3"] = (int)regs.GPR[19];
ret["s4"] = (int)regs.GPR[20]; ret["s5"] = (int)regs.GPR[21]; ret["s6"] = (int)regs.GPR[22]; ret["s7"] = (int)regs.GPR[23];
ret["t8"] = (int)regs.GPR[24]; ret["t9"] = (int)regs.GPR[25];
ret["k0"] = (int)regs.GPR[26]; ret["k1"] = (int)regs.GPR[27];
ret["gp"] = (int)regs.GPR[28];
ret["sp"] = (int)regs.GPR[29];
ret["fp"] = (int)regs.GPR[30];
ret["ra"] = (int)regs.GPR[31];
return ret;
}
static Dictionary<string, int> CpuRegisterIndices = new Dictionary<string, int>() {
{"r1",1},{"r2",2},{"r3",3},{"r4",4},{"r5",5},{"r6",6},{"r7",7},
{"r8",8},{"r9",9},{"r10",10},{"r11",11},{"r12",12},{"r13",13},{"r14",14},{"r15",15},
{"r16",16},{"r17",17},{"r18",18},{"r19",19},{"r20",20},{"r21",21},{"r22",22},{"r23",23},
{"r24",24},{"r25",25},{"r26",26},{"r27",27},{"r28",28},{"r29",29},{"r30",30},{"r31",31},
{"at",1},{"v0",2},{"v1",3},
{"a0",4},{"a1",5},{"a2",6},{"a3",7},
{"t0",8},{"t1",9},{"t2",10},{"t3",11},
{"t4",12},{"t5",13},{"t6",14},{"t7",15},
{"s0",16},{"s1",17},{"s2",18},{"s3",19},
{"s4",20},{"s5",21},{"s6",22},{"s7",23},
{"t8",24},{"t9",25},
{"k0",26},{"k1",27},
{"gp",28},{"sp",29},{"fp",30},{"ra",31}
};
public void SetCpuRegister(string register, int value)
{
int index = CpuRegisterIndices[register];
OctoshockDll.shock_SetRegister_CPU(psx, index, (uint)value);
}
[FeatureNotImplemented]
public ITracer Tracer { get { throw new NotImplementedException(); } }
[FeatureNotImplemented]
public IMemoryCallbackSystem MemoryCallbacks { get { throw new NotImplementedException(); } }
[FeatureNotImplemented]
public void StepInto() { throw new NotImplementedException(); }
[FeatureNotImplemented]
public void StepOut() { throw new NotImplementedException(); }
[FeatureNotImplemented]
public void StepOver() { throw new NotImplementedException(); }
#endregion //IDebuggable
}
}