add 5% of the world's slowest ARM cpu emulator
This commit is contained in:
parent
7eafa54cf7
commit
5cd5e799a6
|
@ -3,7 +3,7 @@
|
|||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.21022</ProductVersion>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{197D4314-8A9F-49BA-977D-54ACEFAEB6BA}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
|
@ -40,6 +40,8 @@
|
|||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\BizHawk.MultiClient\LuaInterface.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.JScript" />
|
||||
<Reference Include="Microsoft.Vsa" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
|
@ -104,6 +106,18 @@
|
|||
<Compile Include="CPUs\68000\Memory.cs" />
|
||||
<Compile Include="CPUs\68000\OpcodeTable.cs" />
|
||||
<Compile Include="CPUs\68000\Tables.cs" />
|
||||
<Compile Include="CPUs\ARM\ARM.CP.cs" />
|
||||
<Compile Include="CPUs\ARM\ARM.cs" />
|
||||
<Compile Include="CPUs\ARM\ARM.Disassembly.cs" />
|
||||
<Compile Include="CPUs\ARM\ARM.Execute.cs" />
|
||||
<Compile Include="CPUs\ARM\ARM.ExecuteArm.cs" />
|
||||
<Compile Include="CPUs\ARM\ARM.ExecuteArm.Unconditional.cs" />
|
||||
<Compile Include="CPUs\ARM\ARM.ExecuteCore.cs" />
|
||||
<Compile Include="CPUs\ARM\ARM.ExecuteThumb.cs" />
|
||||
<Compile Include="CPUs\ARM\ARM.Pseudocode.cs" />
|
||||
<Compile Include="CPUs\ARM\decoder\decoder.cs" />
|
||||
<Compile Include="CPUs\ARM\decoder\scripting.cs" />
|
||||
<Compile Include="CPUs\ARM\_.cs" />
|
||||
<Compile Include="CPUs\HuC6280\Disassembler.cs" />
|
||||
<Compile Include="CPUs\HuC6280\Execute.cs" />
|
||||
<Compile Include="CPUs\HuC6280\HuC6280.cs" />
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.CPUs.ARM
|
||||
{
|
||||
|
||||
partial class ARM
|
||||
{
|
||||
public ARM.CP15 cp15;
|
||||
|
||||
public uint cp15_MRC(uint opc1, uint t, uint crn, uint crm, uint opc2)
|
||||
{
|
||||
if (t == 15) unpredictable = true;
|
||||
switch (crn)
|
||||
{
|
||||
case 13:
|
||||
switch (opc2)
|
||||
{
|
||||
case 0: return cp15.FCSEIDR;
|
||||
case 1: return cp15.CONTEXTIDR;
|
||||
case 2: return cp15.TPIDRURW;
|
||||
case 3: return cp15.TPIDRURO;
|
||||
case 4: return cp15.TPIDRPRW;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//unhandled...
|
||||
unpredictable = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public string cp15_Describe(uint opc1, uint t, uint crn, uint crm, uint opc2)
|
||||
{
|
||||
switch (crn)
|
||||
{
|
||||
case 13:
|
||||
switch (opc2)
|
||||
{
|
||||
case 0: return "CP15.FCSEIDR: FCSE PID";
|
||||
case 1: return "CP15.CONTEXTIDR: Context ID";
|
||||
case 2: return "CP15.TPIDRURW: User RW Thread ID";
|
||||
case 3: return "CP15.TPIDRURW: User RO Thread ID";
|
||||
case 4: return "CP15.TPIDRURW: Priv. Only Thread ID";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
public class CP15
|
||||
{
|
||||
//c13
|
||||
public uint FCSEIDR;
|
||||
public uint CONTEXTIDR;
|
||||
public uint TPIDRURW, TPIDRURO, TPIDRPRW;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,464 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BizHawk.Emulation.CPUs.ARM
|
||||
{
|
||||
partial class ARM
|
||||
{
|
||||
public class DisassemblyOptions
|
||||
{
|
||||
//TODO - refactor these to NumberOptions or somesuch and have several of those
|
||||
//0 = unpadded ; 1,2,4 = numbytes: -1 = no hex
|
||||
public int SVC_hex;
|
||||
public bool SVC_hexPrefix, SVC_literalPrefix, SVC_caps;
|
||||
public bool SVC_showName = true;
|
||||
|
||||
public void SetNstyle()
|
||||
{
|
||||
SVC_hex = 0;
|
||||
SVC_hexPrefix = false;
|
||||
SVC_literalPrefix = false;
|
||||
SVC_caps = true;
|
||||
hideZeroOffset = true;
|
||||
//showExplicitAccumulateRegisters = false;
|
||||
}
|
||||
|
||||
public bool showoptadd = false;
|
||||
|
||||
//fixes retarded debugger label format by adding #0x in front of it
|
||||
public bool fix_nstyle_label = true;
|
||||
|
||||
//TODO - subsume nstyle
|
||||
|
||||
//show all registers when accumulating values, i.e. add r0, r0, #4 (instead of add r0, #4)
|
||||
//TODO - obseleted by rd~rx approach
|
||||
public bool showExplicitAccumulateRegisters = true;
|
||||
|
||||
//hide offsets of #0 (set to true for more terseness with no real loss of information)
|
||||
public bool hideZeroOffset = false;
|
||||
|
||||
//compute PC relative labels for certain operations (like LDR)
|
||||
//public bool computePCLabel = true;
|
||||
|
||||
//consider:
|
||||
//in RVCT many (all?) thumb instructions dont show {S} suffix in thumb mode, because it is sort of redundant (since they always apply in many thumb instructions)
|
||||
//but this is gay. well, consider making it an option
|
||||
}
|
||||
|
||||
public class ProcessorOptions
|
||||
{
|
||||
public void SetNStyle()
|
||||
{
|
||||
Thumb_LSL_immediate_T1_0_is_MOV_register_T2 = false;
|
||||
}
|
||||
|
||||
public bool Thumb_LSL_immediate_T1_0_is_MOV_register_T2 = true;
|
||||
}
|
||||
|
||||
public DisassemblyOptions disopt = new DisassemblyOptions();
|
||||
public ProcessorOptions procopt = new ProcessorOptions();
|
||||
|
||||
bool DIS_Check(object[] args, int argnum, string str, string find)
|
||||
{
|
||||
if (args.Length <= argnum) return false;
|
||||
int index = str.IndexOf(find);
|
||||
if (index == -1) return false;
|
||||
return true;
|
||||
}
|
||||
string disformat_num(object item, bool caps, bool literalprefix, bool hexprefix, int hex)
|
||||
{
|
||||
string hexformat;
|
||||
switch (hex)
|
||||
{
|
||||
case -1: hexformat = "{0}"; break;
|
||||
case 0: hexformat = "{0:x}"; break;
|
||||
case 1: hexformat = "{0:x2}"; break;
|
||||
case 2: hexformat = "{0:x4}"; break;
|
||||
case 4: hexformat = "{0:x8}"; break;
|
||||
default: throw new ArgumentException();
|
||||
}
|
||||
string value = string.Format(hexformat, item);
|
||||
if (caps) value = value.ToUpper();
|
||||
string ret = string.Format("{0}{1}{2}", literalprefix ? "#" : "", hexprefix ? "0x" : "", value);
|
||||
return ret;
|
||||
}
|
||||
uint DIS(string opcode, string format, params object[] args)
|
||||
{
|
||||
//options:
|
||||
//capital reg names
|
||||
//capital mnemonic
|
||||
//tab between mnemonic and arguments (always? sometimes)
|
||||
//0 front-pad hex arguments
|
||||
const bool capMnemonic = true;
|
||||
|
||||
if (DIS_Check(args, 0, opcode, "/s0/")) opcode = opcode.Replace("/s0/", (bool)args[0] ? "s" : "");
|
||||
|
||||
if (_CurrentCond() == 14)
|
||||
opcode = opcode.Replace("/c/", "");
|
||||
else opcode = opcode.Replace("/c/", CC_strings[_CurrentCond()]);
|
||||
|
||||
if (capMnemonic) opcode = opcode.ToUpper();
|
||||
|
||||
string ret = string.Format(opcode + " " + format, args);
|
||||
|
||||
if (DIS_Check(args, 0, ret, "/a0/")) ret = ret.Replace("/a0/", string.Format("{0:x}", args[0])); //address format
|
||||
if (DIS_Check(args, 1, ret, "/a1/")) ret = ret.Replace("/a1/", string.Format("{0:x}", args[1]));
|
||||
if (DIS_Check(args, 0, ret, "/r0/")) ret = ret.Replace("/r0/", Reg_names[(uint)args[0]].ToLower());
|
||||
if (DIS_Check(args, 1, ret, "/r1/")) ret = ret.Replace("/r1/", Reg_names[(uint)args[1]].ToLower());
|
||||
if (DIS_Check(args, 2, ret, "/r2/")) ret = ret.Replace("/r2/", Reg_names[(uint)args[2]].ToLower());
|
||||
if (DIS_Check(args, 0, ret, "/imm8_0/")) ret = ret.Replace("/imm8_0/", string.Format("#{0}", (uint)args[0]));
|
||||
if (DIS_Check(args, 1, ret, "/imm8_1/")) ret = ret.Replace("/imm8_1/", string.Format("#{0}", (uint)args[1]));
|
||||
if (DIS_Check(args, 1, ret, "/uimm32h_1/")) ret = ret.Replace("/uimm32h_1/", string.Format("#0x{0:x}", (uint)args[1]));
|
||||
if (DIS_Check(args, 0, ret, "/label0/")) ret = ret.Replace("/label0/", string.Format("{0:x}", args[0]));
|
||||
if (DIS_Check(args, 1, ret, "/label1/")) ret = ret.Replace("/label1/", string.Format("{0:x}", args[1]));
|
||||
if (DIS_Check(args, 0, ret, "/svc0/")) ret = ret.Replace("/svc0/", disformat_num(args[0], disopt.SVC_caps, disopt.SVC_literalPrefix, disopt.SVC_hexPrefix, disopt.SVC_hex));
|
||||
if (DIS_Check(args, 0, ret, "/const0/")) ret = ret.Replace("/const0/", "#0x" + string.Format("{0:x}", args[0]).ToUpper());
|
||||
if (DIS_Check(args, 1, ret, "/const1/")) ret = ret.Replace("/const1/", "#0x" + string.Format("{0:x}", args[1]).ToUpper());
|
||||
if (DIS_Check(args, 2, ret, "/const2/")) ret = ret.Replace("/const2/", "#0x" + string.Format("{0:x}", args[2]).ToUpper());
|
||||
//TODO - run constN through the disformat scheme
|
||||
ret = DIS_Reglist(ret, args);
|
||||
disassembly = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
string DISNEW_optaddsub(object value)
|
||||
{
|
||||
return (bool)value ? (disopt.showoptadd ? "+" : "") : "-";
|
||||
}
|
||||
|
||||
uint DISNEW(string opcode, string format, params object[] args)
|
||||
{
|
||||
bool hasComment = false;
|
||||
|
||||
const bool capMnemonic = true;
|
||||
|
||||
int index = 0;
|
||||
int tagindex = -1;
|
||||
int argindex = 0;
|
||||
uint regReport = 0;
|
||||
|
||||
//-----
|
||||
//work on opcode
|
||||
if (opcode.IndexOf("<s?>") != -1)
|
||||
{
|
||||
bool s = (bool)args[argindex++];
|
||||
opcode = opcode.Replace("<s?>", s ? "s" : "");
|
||||
}
|
||||
|
||||
//TODO - look for cmaybe and get rid of them.
|
||||
//alternatively, do a good job placing them and just always choose to put them there.
|
||||
//well, we can do that as a separate polish pass later
|
||||
bool cmaybe = (opcode.IndexOf("<c?>") != -1);
|
||||
bool usec = true;
|
||||
if (cmaybe)
|
||||
usec = (bool)args[argindex++];
|
||||
string crepl = cmaybe ? "<c?>" : "<c>";
|
||||
|
||||
if (usec)
|
||||
{
|
||||
if (_CurrentCond() == 14)
|
||||
opcode = opcode.Replace(crepl, "");
|
||||
else opcode = opcode.Replace(crepl, CC_strings[_CurrentCond()]);
|
||||
}
|
||||
else opcode = opcode.Replace(crepl, "");
|
||||
//---------
|
||||
|
||||
string cpcomment = null;
|
||||
while (index < format.Length)
|
||||
{
|
||||
if (tagindex != -1)
|
||||
{
|
||||
if (format[index] == '>')
|
||||
{
|
||||
int len = index - tagindex - 1;
|
||||
string item = format.Substring(tagindex + 1, len).ToLower();
|
||||
|
||||
switch (item)
|
||||
{
|
||||
case "rt":
|
||||
case "rm":
|
||||
case "rn":
|
||||
case "rd":
|
||||
{
|
||||
item = Reg_names[(uint)args[argindex++]].ToLower();
|
||||
break;
|
||||
}
|
||||
|
||||
case "rt!":
|
||||
case "rm!":
|
||||
case "rn!":
|
||||
case "rd!":
|
||||
case "sp!":
|
||||
{
|
||||
uint reg;
|
||||
if (item == "sp!") reg = 13;
|
||||
else reg = (uint)args[argindex++];
|
||||
item = Reg_names[reg].ToLower();
|
||||
regReport |= (uint)(1 << (int)reg);
|
||||
break;
|
||||
}
|
||||
|
||||
case "{rd!~rm, }":
|
||||
case "{rd!~rn, }":
|
||||
{
|
||||
uint rd = (uint)args[argindex++];
|
||||
uint rx = (uint)args[argindex++];
|
||||
if (disopt.showExplicitAccumulateRegisters || rd != rx)
|
||||
item = string.Format("{0}, ", Reg_names[rd].ToLower());
|
||||
else item = "";
|
||||
break;
|
||||
}
|
||||
|
||||
case "fpscr": item = nstyle ? "fpscr" : "FPSCR"; break;
|
||||
|
||||
case "const": item = string.Format("0x{0:x}", args[argindex++]); break;
|
||||
case "imm": item = string.Format("0x{0:x}", args[argindex++]); break;
|
||||
case "imm5": item = string.Format("0x{0:x}", args[argindex++]); break;
|
||||
|
||||
case "{ ,#imm}":
|
||||
{
|
||||
uint temp = (uint)args[argindex++];
|
||||
if (temp == 0) item = "";
|
||||
else item = string.Format(",#0x{0:x}", temp);
|
||||
break;
|
||||
}
|
||||
case "{,+/-#imm}":
|
||||
{
|
||||
uint temp = (uint)args[argindex + 1];
|
||||
if (temp == 0 && disopt.hideZeroOffset) item = "";
|
||||
else item = string.Format(",#{0}0x{1:x}", DISNEW_optaddsub(args[argindex]), temp);
|
||||
argindex++;
|
||||
break;
|
||||
}
|
||||
//case "labelaccess": //same as label but with [] around it
|
||||
case "label":
|
||||
if (disopt.fix_nstyle_label)
|
||||
item = string.Format("#0x{0:x}", args[argindex++]);
|
||||
else
|
||||
item = string.Format("{0:x}", args[argindex++]);
|
||||
break;
|
||||
case "%08x": item = string.Format("0x{0:x8}", args[argindex++]); break;
|
||||
case "optaddsub":
|
||||
case "+/-": item = DISNEW_optaddsub((bool)args[argindex++]); break;
|
||||
|
||||
case "{, shift}":
|
||||
{
|
||||
//TODO - consider whether it is necessary to pass in arguments (can they always be pulled from shift_n and shift_t? i think so
|
||||
SRType sr = (SRType)args[argindex++];
|
||||
int shift_n = (int)args[argindex++];
|
||||
switch (sr)
|
||||
{
|
||||
case SRType.LSL:
|
||||
if (shift_n == 0)
|
||||
{
|
||||
//special case for non-rotated things. theyre usually encoded this way
|
||||
item = "";
|
||||
break;
|
||||
}
|
||||
item = ", LSL " + shift_n.ToString(); break;
|
||||
case SRType.LSR: item = ", LSR " + shift_n.ToString(); break;
|
||||
case SRType.ASR: item = ", ASR " + shift_n.ToString(); break;
|
||||
case SRType.ROR: item = ", ROR " + shift_n.ToString(); break;
|
||||
case SRType.RRX: item = ", RRX"; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "{, rotation}":
|
||||
{
|
||||
uint rotation = (uint)args[argindex++] * 8;
|
||||
if (rotation == 0) item = "";
|
||||
else item = "ROR #" + rotation;
|
||||
break;
|
||||
}
|
||||
|
||||
case "registers":
|
||||
item = DISNEW_Reglist((uint)args[argindex++]);
|
||||
break;
|
||||
case "svc":
|
||||
{
|
||||
uint svc = (uint)args[argindex++];
|
||||
if (nstyle) opcode = opcode.Replace("XXX", "SWI");
|
||||
else opcode = opcode.Replace("XXX", "SVC");
|
||||
item = disformat_num(svc, disopt.SVC_caps, disopt.SVC_literalPrefix, disopt.SVC_hexPrefix, disopt.SVC_hex);
|
||||
if (disopt.SVC_showName) { item += " ; " + sys.svc_name(svc); hasComment = true; }
|
||||
break;
|
||||
}
|
||||
case "{wback!}":
|
||||
if ((bool)args[argindex++])
|
||||
item = "!";
|
||||
else item = "";
|
||||
break;
|
||||
|
||||
case "coproc":
|
||||
item = "cp" + args[argindex++].ToString();
|
||||
break;
|
||||
case "opc1":
|
||||
case "opc2":
|
||||
item = "#" + args[argindex++].ToString();
|
||||
break;
|
||||
case "coproc_rt!":
|
||||
{
|
||||
uint reg = (uint)args[argindex++];
|
||||
if (reg == 15)
|
||||
{
|
||||
item = "APSR_nzcv";
|
||||
}
|
||||
else
|
||||
regReport |= (uint)(1 << (int)reg);
|
||||
item = Reg_names[reg].ToLower();
|
||||
break;
|
||||
}
|
||||
case "crn":
|
||||
case "crm":
|
||||
item = "c" + args[argindex++].ToString();
|
||||
break;
|
||||
case "{ ;cp_comment}":
|
||||
{
|
||||
item = "";
|
||||
cpcomment = args[argindex++] as string;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default: item = "<" + item + ">"; break;
|
||||
}
|
||||
|
||||
format = format.Substring(0, tagindex) + item + format.Substring(tagindex + len + 2);
|
||||
index = tagindex + item.Length - 1;
|
||||
tagindex = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (format[index] == '<')
|
||||
tagindex = index;
|
||||
index++;
|
||||
}
|
||||
|
||||
if (capMnemonic) opcode = opcode.ToUpper();
|
||||
|
||||
disassembly = opcode + " " + format;
|
||||
if (unpredictable)
|
||||
{
|
||||
disassembly = disassembly + " ; UNPREDICTABLE";
|
||||
hasComment = true;
|
||||
}
|
||||
|
||||
//report any relevant registers
|
||||
bool hasRegReport = false;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
uint doit = regReport & 1;
|
||||
regReport >>= 1;
|
||||
if (doit == 1)
|
||||
{
|
||||
if (!hasComment) disassembly += " ; ";
|
||||
if (hasRegReport) disassembly += ", ";
|
||||
hasComment = true;
|
||||
hasRegReport = true;
|
||||
disassembly += string.Format("{0}={1:x8}", Reg_names[i].ToLower(), r[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(cpcomment))
|
||||
{
|
||||
disassembly += " ;" + cpcomment;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
string DIS_Reglist(string str, object[] args)
|
||||
{
|
||||
int index = str.IndexOf("/reglist/");
|
||||
if (index == -1) return str;
|
||||
uint regs = (uint)args[0];
|
||||
StringBuilder sb = new StringBuilder(32);
|
||||
sb.Append("{");
|
||||
//TODO - coalesce these to the range style!!
|
||||
bool first = true;
|
||||
for (int i = 0; i <= 15; i++)
|
||||
{
|
||||
if (_.BITN(i, regs) == 1)
|
||||
{
|
||||
if (!first) sb.Append(",");
|
||||
sb.Append(Reg_names[i].ToLower());
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
sb.Append("}");
|
||||
return str.Replace("/reglist/", sb.ToString());
|
||||
}
|
||||
|
||||
//TODO - unit test this
|
||||
unsafe string DISNEW_Reglist(uint regs)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(32);
|
||||
//TODO - coalesce these to the range style!!
|
||||
const int firstname = 13;
|
||||
bool first = true;
|
||||
int range = -1;
|
||||
int lastrange = -1;
|
||||
int* ra = stackalloc int[8];
|
||||
int* rb = stackalloc int[8];
|
||||
for (int i = 0; i <= 15; i++)
|
||||
{
|
||||
bool bit = _.BITN(i, regs) != 0;
|
||||
if (bit && i < firstname)
|
||||
{
|
||||
if (lastrange == -1)
|
||||
{
|
||||
lastrange = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
if (!bit || i >= firstname)
|
||||
{
|
||||
if (bit && i >= firstname)
|
||||
{
|
||||
range++;
|
||||
ra[range] = i;
|
||||
rb[range] = i;
|
||||
}
|
||||
if (lastrange != -1)
|
||||
{
|
||||
range++;
|
||||
ra[range] = lastrange;
|
||||
rb[range] = i - 1;
|
||||
lastrange = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sb.Append("{");
|
||||
for (int i = 0; i <= range; i++)
|
||||
{
|
||||
int a = ra[i];
|
||||
int b = rb[i];
|
||||
if (!first) sb.Append(",");
|
||||
if (a == b) sb.Append(Reg_names[a].ToLower());
|
||||
else sb.AppendFormat("{0}-{1}", Reg_names[a].ToLower(), Reg_names[b].ToLower());
|
||||
first = false;
|
||||
}
|
||||
sb.Append("}");
|
||||
|
||||
//sb.Append("{");
|
||||
//for (int i = 0; i <= 15; i++)
|
||||
//{
|
||||
// if (_.BITN(i, regs) == 1)
|
||||
// {
|
||||
// if (!first) sb.Append(",");
|
||||
// sb.Append(Reg_names[i].ToLower());
|
||||
// first = false;
|
||||
// }
|
||||
//}
|
||||
//sb.Append("}");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BizHawk.Emulation.CPUs.ARM
|
||||
{
|
||||
|
||||
partial class ARM
|
||||
{
|
||||
public uint Execute()
|
||||
{
|
||||
if (APSR.T == 1) return ExecuteThumb();
|
||||
else return ExecuteArm();
|
||||
}
|
||||
|
||||
enum CC
|
||||
{
|
||||
EQ = 0,
|
||||
NE = 1,
|
||||
CS = 2, HS = 2,
|
||||
CC = 3, LO = 3,
|
||||
MI = 4,
|
||||
PL = 5,
|
||||
VS = 6,
|
||||
VC = 7,
|
||||
HI = 8,
|
||||
LS = 9,
|
||||
GE = 10,
|
||||
LT = 11,
|
||||
GT = 12,
|
||||
LE = 13,
|
||||
AL = 14,
|
||||
}
|
||||
//return (CPSR.N?0x80000000:0)|(CPSR.Z?0x40000000:0)|(CPSR.C?0x20000000:0)|(CPSR.V?0x10000000:0);
|
||||
|
||||
readonly string[] CC_strings = { "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "AL", "XX" };
|
||||
readonly string[] Reg_names = { "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R11", "R12", "SP", "LR", "PC" };
|
||||
|
||||
uint CONDITION(uint i) { return i >> 28; }
|
||||
int SIGNEXTEND_24(uint x) { return (((int)x << 8) >> 8); }
|
||||
|
||||
//an instruction sets this flag when the results are unpredictable but will be executed anyway
|
||||
public bool unpredictable;
|
||||
public uint cycles;
|
||||
uint _currentCondVal;
|
||||
uint _CurrentCond()
|
||||
{
|
||||
//TODO - calculate CurrentCond from from A8.3.1
|
||||
return _currentCondVal;
|
||||
}
|
||||
bool _ConditionPassed()
|
||||
{
|
||||
uint cond = _CurrentCond();
|
||||
bool result = false;
|
||||
switch (cond & _.b1110)
|
||||
{
|
||||
case _.b0000: result = APSR.Z == 1; break;
|
||||
case _.b0010: result = APSR.C == 1; break;
|
||||
case _.b0100: result = APSR.N == 1; break;
|
||||
case _.b0110: result = APSR.V == 1; break;
|
||||
case _.b1000: result = APSR.C == 1 && APSR.Z == 0; break;
|
||||
case _.b1010: result = APSR.N == APSR.V; break;
|
||||
case _.b1100: result = (APSR.N == APSR.V) && APSR.Z == 0; break;
|
||||
case _.b1110: result = true; break;
|
||||
}
|
||||
if ((cond & 1) == 1 && cond != _.b1111)
|
||||
result = !result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool CHK(uint value, int mask, int test)
|
||||
{
|
||||
return (value & mask) == test;
|
||||
}
|
||||
|
||||
uint Reg8(uint pos)
|
||||
{
|
||||
return (uint)((instruction >> (int)pos) & 7);
|
||||
}
|
||||
|
||||
uint Reg16(uint pos)
|
||||
{
|
||||
return (uint)((instruction >> (int)pos) & 0xF);
|
||||
}
|
||||
|
||||
uint Execute_Undefined()
|
||||
{
|
||||
if (disassemble) disassembly = "undefined";
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint Execute_Unhandled(string descr)
|
||||
{
|
||||
if (disassemble) disassembly = descr + " unhandled";
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint Disassembly_Unhandled(string descr)
|
||||
{
|
||||
disassembly = "disasm unhandled: " + descr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint Disassemble_LDR_STR_immediate(string opcode, uint t, uint imm32, uint n, bool index, bool add, bool wback)
|
||||
{
|
||||
bool offset = index == true && wback == false;
|
||||
bool preindexed = index == true && wback == true;
|
||||
bool postindex = index == false && wback == true;
|
||||
|
||||
string rt = "<rt!>";
|
||||
opcode += "<c>";
|
||||
//we may want conditional logic here to control whether various registers are displayed (we used to have it, but i changed my mind)
|
||||
if (offset)
|
||||
return DISNEW(opcode, rt + ", [<Rn!><{,+/-#imm}>]", t, n, add, imm32);
|
||||
else if (preindexed)
|
||||
return DISNEW(opcode, rt + ", [<Rn!>, <+/-><imm>]!", t, n, add, imm32);
|
||||
else if (postindex)
|
||||
return DISNEW(opcode, rt + ", [<Rn!>], <+/-><imm>", t, n, add, imm32);
|
||||
else throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
uint Disassemble_LDR_STR_register(string opcode, uint t, uint n, uint m, SRType shift_t, int shift_n, bool index, bool add, bool wback)
|
||||
{
|
||||
bool offset = index == true && wback == false;
|
||||
bool preindexed = index == true && wback == true;
|
||||
bool postindex = index == false && wback == true;
|
||||
|
||||
string rt = "<rt!>";
|
||||
opcode += "<c>";
|
||||
//we may want conditional logic here to control whether various registers are displayed (we used to have it, but i changed my mind)
|
||||
if (offset)
|
||||
return DISNEW(opcode, rt + ", [<Rn!>, <+/-><rm!><{, shift}>]", t, n, add, m, shift_t, shift_n);
|
||||
else if (preindexed)
|
||||
return DISNEW(opcode, rt + ", [<Rn!>, <+/-><rm!><{, shift}>]!", t, n, add, m, shift_t, shift_n);
|
||||
else if (postindex)
|
||||
return DISNEW(opcode, rt + ", [<Rn!>], <+/-><rm!><{, shift}>", t, n, add, m, shift_t, shift_n);
|
||||
else throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
void UnalignedAccess(uint addr)
|
||||
{
|
||||
Console.WriteLine("Warning! unaligned access at {0:x8}", addr);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
namespace BizHawk.Emulation.CPUs.ARM
|
||||
{
|
||||
partial class ARM
|
||||
{
|
||||
uint ExecuteArm_Unconditional()
|
||||
{
|
||||
//A5.7
|
||||
|
||||
uint op1 = (instruction & 0xFF00000) >> 20;
|
||||
uint op = (instruction & 0x10) >> 4;
|
||||
|
||||
//todo: misc instructions, memory hints, and advanced SIMD instructions on page A5-31
|
||||
if (CHK(op1, _.b10000000, _.b00000000)) return ExecuteArm_Unconditional_Misc();
|
||||
if (CHK(op1, _.b11100101, _.b10000100)) return Execute_SRS_A1(); //v6
|
||||
if (CHK(op1, _.b11100101, _.b10000001)) return Execute_RFE_A1(); //v6
|
||||
if (CHK(op1, _.b11100000, _.b10100000)) return Execute_BL_BLX_immediate_A2(); //v5
|
||||
if (CHK(op1, _.b11111011, _.b11000011)) return ExecuteArm_LDC_LDC2_immediate(); //v5
|
||||
if (CHK(op1, _.b11111001, _.b11000011)) return ExecuteArm_LDC_LDC2_literal(1); //v5
|
||||
if (CHK(op1, _.b11110001, _.b11010001)) return ExecuteArm_LDC_LDC2_literal(2); //v5
|
||||
if (CHK(op1, _.b11111011, _.b11000010)) return ExecuteArm_STC_STC2(1); //v5
|
||||
if (CHK(op1, _.b11111001, _.b11001000)) return ExecuteArm_STC_STC2(2); //v5
|
||||
if (CHK(op1, _.b11110001, _.b11010000)) return ExecuteArm_STC_STC2(3); //v5
|
||||
if (op1 == _.b11000100) return ExecuteArm_MCRR_MCRR2(); //v6
|
||||
if (op1 == _.b11000101) return ExecuteArm_MRRC_MRRC2(); //v6
|
||||
if (CHK(op1, _.b11110000, _.b11100000) && op == 0) return ExecuteArm_CDP_CDP2(); //v5
|
||||
if (CHK(op1, _.b11110001, _.b11100000) && op == 1) return ExecuteArm_MCR_MCR2(); //v5
|
||||
if (CHK(op1, _.b11110001, _.b11100001) && op == 1) return ExecuteArm_MRC_MRC2(); //v5
|
||||
|
||||
return Execute_Unhandled("ExecuteArm_Unconditional");
|
||||
}
|
||||
|
||||
uint ExecuteArm_Unconditional_Misc() { return Execute_Unhandled("ExecuteArm_Unconditional_Misc"); }
|
||||
uint Execute_SRS_A1() { return Execute_Unhandled("ExecuteArm_SRS_A1"); }
|
||||
uint Execute_RFE_A1() { return Execute_Unhandled("ExecuteArm_RFE_A1"); }
|
||||
uint Execute_BL_BLX_immediate_A2()
|
||||
{
|
||||
//A8.6.23
|
||||
uint imm24 = instruction & 0xFFFFFF;
|
||||
uint H = _.BIT24(instruction);
|
||||
int imm32 = SIGNEXTEND_24((imm24 << 2) | (H << 1));
|
||||
return ExecuteCore_BL_BLX_immediate(Encoding.A2, EInstrSet.THUMB, imm32, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint ExecuteArm_LDC_LDC2_immediate()
|
||||
{
|
||||
uint Rn = instruction & 0xF0000;
|
||||
if (Rn == 0xF) { } //special handling for 0xF vs not 0xF
|
||||
return Execute_Unhandled("ExecuteArm_LDC_LDC2_immediate");
|
||||
}
|
||||
uint ExecuteArm_LDC_LDC2_literal(int form) { return Execute_Unhandled("ExecuteArm_LDC_LDC2_literal"); }
|
||||
uint ExecuteArm_STC_STC2(int form) { return Execute_Unhandled("ExecuteArm_STC_STC2"); }
|
||||
uint ExecuteArm_MCRR_MCRR2() { return Execute_Unhandled("ExecuteArm_MCRR_MCRR2"); }
|
||||
uint ExecuteArm_MRRC_MRRC2() { return Execute_Unhandled("ExecuteArm_MRRC_MRRC2"); }
|
||||
uint ExecuteArm_CDP_CDP2() { return Execute_Unhandled("ExecuteArm_CDP_CDP2"); }
|
||||
uint ExecuteArm_MCR_MCR2() { return Execute_Unhandled("ExecuteArm_MCR_MCR2"); }
|
||||
uint ExecuteArm_MRC_MRC2() { return Execute_Unhandled("ExecuteArm_MRC_MRC2"); }
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,785 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BizHawk.Emulation.CPUs.ARM
|
||||
{
|
||||
|
||||
partial class ARM
|
||||
{
|
||||
uint ExecuteArm()
|
||||
{
|
||||
_currentCondVal = CONDITION(instruction);
|
||||
if (_currentCondVal == 0xF) return ExecuteArm_Unconditional();
|
||||
bool pass = _ConditionPassed() || disassemble;
|
||||
if (pass)
|
||||
{
|
||||
uint op1 = (instruction & 0x0E000000) >> 25;
|
||||
uint op = (instruction & 0x10) >> 4;
|
||||
switch (op1)
|
||||
{
|
||||
case _.b000:
|
||||
case _.b001:
|
||||
return ExecuteArm_DataProcessing();
|
||||
case _.b010:
|
||||
return ExecuteArm_LoadStore();
|
||||
case _.b011:
|
||||
if (op == 0) return ExecuteArm_LoadStore();
|
||||
else return ExecuteArm_Media();
|
||||
case _.b100:
|
||||
case _.b101:
|
||||
return ExecuteArm_BranchAndTransfer();
|
||||
case _.b110:
|
||||
case _.b111:
|
||||
return ExecuteArm_SVCAndCP();
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Decoder decoder_ExecuteArm_LoadStore = new Decoder();
|
||||
uint ExecuteArm_LoadStore()
|
||||
{
|
||||
//A5.3
|
||||
//A5-19
|
||||
|
||||
decoder_ExecuteArm_LoadStore.Ensure(() => decoder_ExecuteArm_LoadStore
|
||||
.d("A", 1).d("op1", 5).d("B", 1).d("Rn", 4)
|
||||
.r("A==0 && op1 == #xx0x0 && op1 != #0x010", () => Execute_STR_immediate_A1())
|
||||
.r("A==1 && op1 == #xx0x0 && op1 != #0x010 && B==0", () => Execute_Unhandled("STR (register) on page A8-386"))
|
||||
.r("A==0 && op1 == #0x010", () => Execute_Unhandled("STRT on page A8-416"))
|
||||
.r("A==1 && op1 == #0x010 && B==0", () => Execute_Unhandled("STRT on page A8-416"))
|
||||
.r("A==0 && op1 == #xx0x1 && op1 != #0x011 && Rn != #1111", () => Execute_LDR_immediate_arm_A1())
|
||||
.r("A==0 && op1 == #xx0x1 && op1 != #0x011 && Rn == #1111", () => ExecuteArm_LDR_literal_A1())
|
||||
.r("A==1 && op1 == #xx0x1 && A != #0x011 && B==0", () => Execute_Unhandled("LDR (register) on page A8-124"))
|
||||
.r("A==0 && op1 == #0x011", () => Execute_Unhandled("LDRT on page A8-176"))
|
||||
.r("A==1 && op1 == #0x011 && B==0", () => Execute_Unhandled("LDRT on page A8-176"))
|
||||
.r("A==0 && op1 == #xx1x0 && op1 != #0x110", () => Execute_Unhandled("STRB (immediate, ARM) on page A8-390"))
|
||||
.r("A==1 && op1 == #xx1x0 && op1 != #0x110 && B==0", () => Execute_Unhandled("STRB (register) on page A8-392"))
|
||||
.r("A==0 && op1 == #0x110", () => Execute_Unhandled("STRBT on page A8-394"))
|
||||
.r("A==1 && op1 == #0x110 && B==0", () => Execute_Unhandled("STRBT on page A8-394"))
|
||||
.r("A==0 && op1 == #xx1x1 && op1 != #0x111 && Rn != #1111", () => Execute_Unhandled("LDRB (immediate, ARM) on page A8-128"))
|
||||
.r("A==0 && op1 == #xx1x1 && op1 != #0x111 && Rn == #1111", () => Execute_Unhandled("LDRB (literal) on page A8-130"))
|
||||
.r("A==1 && op1 == #xx1x1 && op1 != #0x111 && B==0", () => Execute_Unhandled("LDRB (register) on page A8-132"))
|
||||
.r("A==0 && op1 == #0x111", () => Execute_Unhandled("LDRBT on page A8-134"))
|
||||
.r("A==1 && op1 == #0x111 && B==0", () => Execute_Unhandled("LDRBT on page A8-134"))
|
||||
);
|
||||
|
||||
uint A = _.BIT25(instruction);
|
||||
uint op1 = (instruction >> 20) & 0x1F;
|
||||
uint B = _.BIT4(instruction);
|
||||
uint Rn = Reg16(16);
|
||||
decoder_ExecuteArm_LoadStore.Evaluate(A, op1, B, Rn);
|
||||
|
||||
return cycles;
|
||||
}
|
||||
|
||||
uint Execute_LDR_immediate_arm_A1()
|
||||
{
|
||||
//A8.6.58 LDR (immediate, ARM)
|
||||
Bit P = _.BIT24(instruction);
|
||||
Bit U = _.BIT23(instruction);
|
||||
Bit W = _.BIT21(instruction);
|
||||
uint n = Reg16(16);
|
||||
uint t = Reg16(12);
|
||||
uint imm12 = instruction & 0xFFF;
|
||||
if (n == _.b1111) throw new NotImplementedException("see LDR (literal");
|
||||
if (P == 0 && W == 1) throw new NotImplementedException("see LDRT");
|
||||
if (n == _.b1101 && P == 0 && U == 1 && W == 0 && imm12 == _.b000000000100)
|
||||
return Execute_POP_A2();
|
||||
uint imm32 = _ZeroExtend_32(imm12);
|
||||
bool index = (P == 1);
|
||||
bool add = (U == 1);
|
||||
bool wback = (P == 0) || (W == 1);
|
||||
if (wback && n == t) unpredictable = true;
|
||||
|
||||
return ExecuteCore_LDR_immediate_arm(Encoding.A1, t, imm32, n, index, add, wback);
|
||||
}
|
||||
|
||||
uint Execute_POP_A2()
|
||||
{
|
||||
//A8.6.122 POP
|
||||
uint t = Reg16(12);
|
||||
uint regs = (uint)(1 << (int)t);
|
||||
if (t == 13) unpredictable = true;
|
||||
const bool UnalignedAllowed = true;
|
||||
return ExecuteCore_POP(Encoding.A2, regs, UnalignedAllowed);
|
||||
}
|
||||
|
||||
uint Execute_STR_immediate_A1()
|
||||
{
|
||||
//A8.6.194
|
||||
Bit P = _.BIT24(instruction);
|
||||
Bit U = _.BIT23(instruction);
|
||||
Bit W = _.BIT21(instruction);
|
||||
uint n = Reg16(16);
|
||||
uint t = Reg16(12);
|
||||
uint imm32 = instruction & 0xFFF;
|
||||
if (P == 0 && W == 1) throw new NotImplementedException("see STRT");
|
||||
if (n == _.b1101 && P == 1 && U == 0 && W == 1 && imm32 == _.b000000000100)
|
||||
return Execute_PUSH_A2();
|
||||
bool index = (P == 1);
|
||||
bool add = (U == 1);
|
||||
bool wback = (P == 0) || (W == 1);
|
||||
if (wback && n == 16 || n == t) unpredictable = true;
|
||||
|
||||
return ExecuteCore_STR_immediate_arm(Encoding.A1, P, U, W, n, t, imm32, index, add, wback);
|
||||
}
|
||||
|
||||
uint Execute_PUSH_A2()
|
||||
{
|
||||
//A8.6.123
|
||||
uint t = Reg8(12);
|
||||
bool UnalignedAllowed = true;
|
||||
uint registers = (uint)(1 << (int)t);
|
||||
if (t == 13) _FlagUnpredictable();
|
||||
return ExecuteCore_PUSH(Encoding.A2, registers, UnalignedAllowed);
|
||||
}
|
||||
|
||||
uint ExecuteArm_LDR_literal_A1()
|
||||
{
|
||||
//A8.6.59
|
||||
//A8-122
|
||||
uint t = Reg16(12);
|
||||
uint imm32 = instruction & 0xFFF;
|
||||
uint U = _.BIT23(instruction);
|
||||
bool add = (U == 1);
|
||||
|
||||
return ExecuteCore_LDR_literal(Encoding.A1, t, imm32, add);
|
||||
}
|
||||
|
||||
|
||||
uint ExecuteArm_DataProcessing()
|
||||
{
|
||||
uint op = _.BIT25(instruction);
|
||||
uint op1 = (instruction >> 20) & 0x1F;
|
||||
uint op2 = (instruction >> 4) & 0xF;
|
||||
switch (op)
|
||||
{
|
||||
case 0:
|
||||
if (!CHK(op1, _.b11001, _.b10000))
|
||||
if (CHK(op2, _.b0001, _.b0000)) return ExecuteArm_DataProcessing_Register();
|
||||
else if (CHK(op2, _.b1001, _.b0001)) return Execute_Unhandled("data-processing (register-shifted register) on page A5-7");
|
||||
if (CHK(op1, _.b11001, _.b10000))
|
||||
if (CHK(op2, _.b1000, _.b0000)) return ExecuteArm_DataProcessing_Misc();
|
||||
else if (CHK(op2, _.b1001, _.b1000)) return Execute_Unhandled("halfword multiply and multiply-accumulate on page A5-13");
|
||||
if (CHK(op1, _.b10000, _.b00000) && op2 == _.b1001) return Execute_Unhandled("multiply and multiply-accumulate on page A5-12");
|
||||
if (CHK(op1, _.b10000, _.b10000) && op2 == _.b1001) return ExecuteArm_SynchronizationPrimitives();
|
||||
if (!CHK(op1, _.b10010, _.b00010))
|
||||
if (op2 == _.b1011) return Execute_Unhandled("extra load/store instructions on page A5-14");
|
||||
else if (CHK(op2, _.b1011, _.b1101)) return Execute_Unhandled("extra load/store instructions on page A5-14");
|
||||
if (CHK(op1, _.b10010, _.b00010))
|
||||
if (op2 == _.b1011) return Execute_Unhandled("extra load/store instructions (unprivileged) on page A5-15");
|
||||
else if (CHK(op2, _.b1011, _.b1101)) return Execute_Unhandled("extra load/store instructions (unprivileged) on page A5-15");
|
||||
throw new InvalidOperationException("unexpected decoder fail");
|
||||
case 1:
|
||||
if (!CHK(op1, _.b11001, _.b10000))
|
||||
return ExecuteArm_DataProcessing_Immediate();
|
||||
if (op1 == _.b10000) return Execute_Unhandled("16-bit immediate load (MOV (immediate on page A8-193) //v6T2");
|
||||
if (op1 == _.b10100) return Execute_Unhandled("high halfword 16-bit immediate load (MOVT on page A8-200) //v6T2");
|
||||
if (CHK(op1, _.b11011, _.b10010)) return Execute_Unhandled("MSR (immediate), and hints on page A5-17");
|
||||
throw new InvalidOperationException("unexpected decoder fail");
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException("totally impossible decoder fail");
|
||||
}
|
||||
}
|
||||
|
||||
uint ExecuteArm_SynchronizationPrimitives()
|
||||
{
|
||||
uint op = (instruction >> 20) & 0xF;
|
||||
switch (op)
|
||||
{
|
||||
case _.b0000:
|
||||
case _.b0100: return Execute_Unhandled("ExecuteArm_SWP_SWPB();");
|
||||
case _.b1000: return Execute_STREX_A1();
|
||||
case _.b1001: return Execute_LDREX_A1();
|
||||
case _.b1010: return Execute_Unhandled("ExecuteArm_STREXD();");
|
||||
case _.b1011: return Execute_Unhandled("ExecuteArm_LDREXD();");
|
||||
case _.b1100: return Execute_Unhandled("ExecuteArm_STREXB();");
|
||||
case _.b1101: return Execute_Unhandled("ExecuteArm_LDREXB();");
|
||||
case _.b1110: return Execute_Unhandled("ExecuteArm_STREXH();");
|
||||
case _.b1111: return Execute_Unhandled("ExecuteArm_LDREXH();");
|
||||
default: throw new InvalidOperationException("decoder fail");
|
||||
}
|
||||
}
|
||||
|
||||
uint Execute_STREX_A1()
|
||||
{
|
||||
//A8.6.202 STREX
|
||||
uint n = Reg16(16);
|
||||
uint d = Reg16(12);
|
||||
uint t = Reg16(0);
|
||||
const uint imm32 = 0;
|
||||
if (d == 15 || t == 15 || n == 15) unpredictable = true;
|
||||
if (d == n || d == t) unpredictable = true;
|
||||
return ExecuteCore_STREX(Encoding.A1, d, n, t, imm32);
|
||||
}
|
||||
|
||||
uint Execute_LDREX_A1()
|
||||
{
|
||||
//A8.6.69 LDREX
|
||||
uint n = Reg16(16);
|
||||
uint t = Reg16(12);
|
||||
uint imm32 = 0;
|
||||
if (t == 15 || n == 15) unpredictable = true;
|
||||
return ExecuteCore_LDREX(Encoding.A1, n, t, imm32);
|
||||
}
|
||||
|
||||
uint ExecuteArm_DataProcessing_Register()
|
||||
{
|
||||
//A5.2.1
|
||||
uint op1 = (instruction >> 20) & 0x1F;
|
||||
uint op2 = (instruction >> 7) & 0x1F;
|
||||
uint op3 = (instruction >> 5) & 3;
|
||||
|
||||
switch (op1)
|
||||
{
|
||||
case _.b00000:
|
||||
case _.b00001: return Execute_Unhandled("arm and reg");
|
||||
case _.b00010:
|
||||
case _.b00011: return Execute_Unhandled("arm eor reg");
|
||||
case _.b00100:
|
||||
case _.b00101: return Execute_Unhandled("arm sub reg");
|
||||
case _.b00110:
|
||||
case _.b00111: return Execute_Unhandled("arm rsb reg");
|
||||
case _.b01000:
|
||||
case _.b01001: return Execute_ADD_register_A1();
|
||||
case _.b01010:
|
||||
case _.b01011: return Execute_Unhandled("arm adc reg");
|
||||
case _.b01100:
|
||||
case _.b01101: return Execute_Unhandled("arm sbc reg");
|
||||
case _.b01110:
|
||||
case _.b01111: return Execute_Unhandled("arm rsc reg");
|
||||
case _.b10001: return Execute_Unhandled("arm tst reg");
|
||||
case _.b10011: return Execute_Unhandled("arm teq reg");
|
||||
case _.b10101: return Execute_CMP_register_A1();
|
||||
case _.b10111: return Execute_Unhandled("arm cmn reg");
|
||||
case _.b11000:
|
||||
case _.b11001: return Execute_Unhandled("arm orr reg");
|
||||
case _.b11010:
|
||||
case _.b11011:
|
||||
if (op2 == _.b00000 && op3 == _.b00) return Execute_MOV_register_A1();
|
||||
if (op2 != _.b00000 && op3 == _.b00) return Execute_LSL_immediate_A1();
|
||||
if (op3 == _.b01) return Execute_LSR_immediate_A1();
|
||||
if (op3 == _.b10) return Execute_Unhandled("arm asr imm");
|
||||
if (op2 == _.b00000 && op3 == _.b11) return Execute_Unhandled("arm rrx");
|
||||
if (op2 != _.b00000 && op3 == _.b11) return Execute_Unhandled("arm ror imm");
|
||||
throw new InvalidOperationException("decode fail");
|
||||
case _.b11100:
|
||||
case _.b11101: return Execute_Unhandled("arm bic reg");
|
||||
case _.b11110:
|
||||
case _.b11111: return Execute_Unhandled("arm mvn reg");
|
||||
default:
|
||||
throw new InvalidOperationException("decode fail");
|
||||
}
|
||||
}
|
||||
|
||||
uint Execute_LSR_immediate_A1()
|
||||
{
|
||||
//A8.6.90
|
||||
uint d = Reg16(12);
|
||||
uint m = Reg16(0);
|
||||
Bit S = _.BIT20(instruction);
|
||||
bool setflags = (S == 1);
|
||||
uint imm5 = (instruction >> 7) & 0x1F;
|
||||
_DecodeImmShift(_.b01, imm5);
|
||||
return ExecuteCore_LSR_immediate(Encoding.A1, d, m, setflags, shift_n);
|
||||
}
|
||||
|
||||
uint Execute_LSL_immediate_A1()
|
||||
{
|
||||
//A8.6.87
|
||||
Bit S = _.BIT20(instruction);
|
||||
uint d = Reg16(12);
|
||||
uint imm5 = (instruction >> 7) & 0x1F;
|
||||
uint m = Reg16(0);
|
||||
Debug.Assert(imm5 != _.b00000); //should have been prevented by decoder
|
||||
bool setflags = (S == 1);
|
||||
_DecodeImmShift(_.b00, imm5);
|
||||
return ExecuteCore_LSL_immediate(Encoding.A1, d, m, setflags, shift_n);
|
||||
}
|
||||
|
||||
uint Execute_MOV_register_A1()
|
||||
{
|
||||
//A8.6.97
|
||||
Bit S = _.BIT20(instruction);
|
||||
uint d = Reg16(12);
|
||||
uint m = Reg16(0);
|
||||
|
||||
if (d == _.b1111 && S == 1) throw new NotSupportedException("SEE SUBS PC, LR and related instructions");
|
||||
bool setflags = (S == 1);
|
||||
return ExecuteCore_MOV_register(Encoding.A1, d, m, setflags);
|
||||
}
|
||||
|
||||
uint Execute_ADD_register_A1()
|
||||
{
|
||||
//A8.6.6 ADD (register)
|
||||
uint m = Reg16(0);
|
||||
uint type = (instruction >> 4) & 3;
|
||||
uint imm5 = (instruction >> 7) & 0x1F;
|
||||
uint d = Reg16(12);
|
||||
uint n = Reg16(16);
|
||||
Bit s = _.BIT20(instruction);
|
||||
bool setflags = (s == 1);
|
||||
if (d == _.b1111 && s == 1) { throw new InvalidOperationException("see SUBS PC, LR and related instructions;"); }
|
||||
if (n == _.b1101) { throw new InvalidOperationException("see ADD (SP plus register);"); }
|
||||
_DecodeImmShift(type, imm5);
|
||||
|
||||
return ExecuteCore_ADD_register(Encoding.A1, m, d, n, setflags, shift_t, shift_n);
|
||||
}
|
||||
|
||||
uint Execute_CMP_register_A1()
|
||||
{
|
||||
//A8.6.36
|
||||
//A8-82
|
||||
uint n = Reg16(16);
|
||||
uint imm5 = (instruction >> 7) & 0x1F;
|
||||
uint m = Reg16(0);
|
||||
uint type = (instruction >> 5) & 3;
|
||||
_DecodeImmShift(type, imm5);
|
||||
|
||||
if (disassemble)
|
||||
return DISNEW("CMP<c>", "<Rn!>,<Rm!><,shift>", n, m, shift_t, shift_n);
|
||||
|
||||
uint shifted = _Shift(r[m], shift_t, shift_n, APSR.C);
|
||||
_AddWithCarry32(r[n], ~shifted, 1);
|
||||
APSR.N = _.BIT31(alu_result_32);
|
||||
APSR.Z = alu_result_32 == 0;
|
||||
APSR.C = alu_carry_out;
|
||||
APSR.V = alu_overflow;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint ExecuteArm_DataProcessing_Immediate()
|
||||
{
|
||||
//A5.2.3
|
||||
uint op = (instruction >> 20) & 0x1F;
|
||||
uint Rn = Reg16(16);
|
||||
switch (op)
|
||||
{
|
||||
case _.b00000:
|
||||
case _.b00001: return Execute_Unhandled("arm and imm");
|
||||
case _.b00010:
|
||||
case _.b00011: return Execute_Unhandled("arm eor imm");
|
||||
case _.b00100:
|
||||
case _.b00101:
|
||||
if (Rn != _.b1111) return Execute_SUB_immediate_arm_A1();
|
||||
else return Execute_Unhandled("arm adr");
|
||||
case _.b00110:
|
||||
case _.b00111: return Execute_Unhandled("arm rsb imm");
|
||||
case _.b01000:
|
||||
case _.b01001:
|
||||
if (Rn != _.b1111) return Execute_ADD_immedate_arm_A1();
|
||||
else return Execute_Unhandled("arm adr");
|
||||
case _.b01010:
|
||||
case _.b01011: return Execute_Unhandled("arm adc imm");
|
||||
case _.b01100:
|
||||
case _.b01101: return Execute_Unhandled("arm sbc imm");
|
||||
case _.b01110:
|
||||
case _.b01111: return Execute_Unhandled("arm rsc imm");
|
||||
case _.b10000:
|
||||
case _.b10010:
|
||||
case _.b10100:
|
||||
case _.b10110: return ExecuteArm_DataProcessing_Misc_Imm();
|
||||
case _.b10001: return Execute_Unhandled("arm tst imm");
|
||||
case _.b10011: return Execute_Unhandled("arm teq imm");
|
||||
case _.b10101: return Execute_CMP_immediate_A1();
|
||||
case _.b10111: return Execute_Unhandled("arm cmn imm");
|
||||
case _.b11000:
|
||||
case _.b11001: return Execute_ORR_immediate_A1();
|
||||
case _.b11010:
|
||||
case _.b11011: return Execute_MOV_immediate_A1();
|
||||
case _.b11100:
|
||||
case _.b11101: return Execute_Unhandled("arm bic imm");
|
||||
case _.b11110:
|
||||
case _.b11111: return Execute_Unhandled("arm mvn imm");
|
||||
default: throw new InvalidOperationException("decoder fail");
|
||||
}
|
||||
}
|
||||
|
||||
uint Execute_SUB_immediate_arm_A1()
|
||||
{
|
||||
//A8.6.212
|
||||
Bit S = _.BIT20(instruction);
|
||||
uint n = Reg16(16);
|
||||
uint d = Reg16(12);
|
||||
uint imm12 = instruction & 0xFFF;
|
||||
|
||||
if (n == _.b1111 && S == 0) throw new NotImplementedException("SEE ADR");
|
||||
if (n == _.b1101) throw new NotImplementedException("SEE SUB (SP minus immediate");
|
||||
if (n == _.b1111 && S == 1) throw new NotImplementedException("SEE SUBS PC, LR and related instructions");
|
||||
bool setflags = (S == 1);
|
||||
uint imm32 = _ARMExpandImm(imm12);
|
||||
return ExecuteCore_SUB_immediate_arm(Encoding.A1, setflags, n, d, imm32);
|
||||
}
|
||||
|
||||
uint Execute_ADD_immedate_arm_A1()
|
||||
{
|
||||
Bit S = _.BIT20(instruction);
|
||||
uint n = Reg16(16);
|
||||
uint d = Reg16(12);
|
||||
uint imm12 = instruction & 0xFFF;
|
||||
|
||||
if (n == _.b1111 && S == 0) { throw new NotImplementedException("SEE ADR"); }
|
||||
if (n == _.b1101) return Execute_ADD_SP_plus_immediate_A1();
|
||||
if (d == _.b1111 && S == 1) throw new NotImplementedException("SEE SUBS PC, LR and related instructions");
|
||||
bool setflags = (S == 1);
|
||||
uint imm32 = _ARMExpandImm(imm12);
|
||||
|
||||
return ExecuteCore_ADD_immediate_arm(Encoding.A1, setflags, n, d, imm32);
|
||||
}
|
||||
|
||||
uint Execute_ADD_SP_plus_immediate_A1()
|
||||
{
|
||||
uint d = Reg16(12);
|
||||
Bit S = _.BIT20(instruction);
|
||||
uint imm12 = instruction & 0xFFF;
|
||||
if (d == _.b1111 && S == 1) throw new NotImplementedException("SEE SUBS PC, LR and related instructions");
|
||||
bool setflags = (S == 1);
|
||||
uint imm32 = _ARMExpandImm(imm12);
|
||||
|
||||
return ExecuteCore_ADD_SP_plus_immedate(Encoding.A1, d, setflags, imm32);
|
||||
}
|
||||
|
||||
uint Execute_CMP_immediate_A1()
|
||||
{
|
||||
//A8.6.35
|
||||
uint Rn = Reg16(16);
|
||||
uint imm12 = instruction & 0xFFF;
|
||||
uint imm32 = _ARMExpandImm(imm12);
|
||||
return ExecuteCore_CMP_immediate(Encoding.A1, Rn, imm32);
|
||||
}
|
||||
|
||||
uint Execute_ORR_immediate_A1()
|
||||
{
|
||||
//A8.6.113
|
||||
Bit S = _.BIT20(instruction);
|
||||
uint n = Reg16(16);
|
||||
uint d = Reg16(12);
|
||||
uint imm12 = instruction & 0xFFF;
|
||||
Debug.Assert(!(d == _.b1111 && S == 1), "SEE SUBS PC, LR and related instructions");
|
||||
bool setflags = (S == 1);
|
||||
uint imm32;
|
||||
Bit carry;
|
||||
_ARMExpandImm_C(imm12, APSR.C, out imm32, out carry);
|
||||
return ExecuteCore_ORR_immediate(Encoding.A1, n, d, setflags, imm32, carry);
|
||||
}
|
||||
|
||||
uint Execute_MOV_immediate_A1()
|
||||
{
|
||||
//A8.6.96
|
||||
uint Rd = Reg16(12);
|
||||
uint S = _.BIT20(instruction);
|
||||
uint imm12 = instruction & 0xFFF;
|
||||
if (Rd == _.b1111 && S == 1)
|
||||
throw new InvalidOperationException("see subs pc, lr and related instructions");
|
||||
bool setflags = (S == 1);
|
||||
uint imm32;
|
||||
Bit carry;
|
||||
_ARMExpandImm_C(imm12, APSR.C, out imm32, out carry);
|
||||
return ExecuteCore_MOV_immediate(Encoding.A1, Rd, setflags, imm32, carry);
|
||||
}
|
||||
|
||||
uint ExecuteArm_DataProcessing_Misc_Imm()
|
||||
{
|
||||
//A5-4
|
||||
//TODO
|
||||
return Execute_Unhandled("ExecuteArm_DataProcessing_Misc_Imm");
|
||||
}
|
||||
|
||||
uint ExecuteArm_DataProcessing_Misc()
|
||||
{
|
||||
//A5.2.12
|
||||
uint op = (instruction >> 21) & 0x3;
|
||||
uint op1 = (instruction >> 16) & 0xF;
|
||||
uint op2 = (instruction >> 4) & 0x7;
|
||||
|
||||
switch (op2)
|
||||
{
|
||||
case _.b000:
|
||||
switch (op)
|
||||
{
|
||||
case _.b00:
|
||||
case _.b10:
|
||||
return Execute_Unhandled("MRS");
|
||||
case _.b01:
|
||||
switch (op1)
|
||||
{
|
||||
case _.b0000:
|
||||
case _.b0100:
|
||||
case _.b1000:
|
||||
case _.b1100: return Execute_Unhandled("MSR (register) application level");
|
||||
case _.b0001:
|
||||
case _.b0101:
|
||||
case _.b1001:
|
||||
case _.b1101:
|
||||
case _.b0010:
|
||||
case _.b0011:
|
||||
case _.b0110:
|
||||
case _.b0111:
|
||||
case _.b1010:
|
||||
case _.b1011:
|
||||
case _.b1110:
|
||||
case _.b1111:
|
||||
return Execute_Unhandled("MSR (register) system level");
|
||||
default:
|
||||
throw new InvalidOperationException("decoder fail");
|
||||
}
|
||||
case _.b11:
|
||||
return Execute_Unhandled("MSR (register) system level");
|
||||
default:
|
||||
throw new InvalidOperationException("decoder fail");
|
||||
}
|
||||
case _.b001:
|
||||
switch (op)
|
||||
{
|
||||
case _.b01: return ExecuteArm_BX_A1();
|
||||
case _.b11: return Execute_Unhandled("ExecuteArm_CLZ");
|
||||
default:
|
||||
return Execute_Undefined();
|
||||
}
|
||||
case _.b010:
|
||||
if (op == _.b01) return Execute_Unhandled("BXJ");
|
||||
else return Execute_Undefined();
|
||||
case _.b011:
|
||||
if (op == _.b01) return Execute_Unhandled("BLX (register) on page A8-60");
|
||||
else return Execute_Undefined();
|
||||
case _.b100: return Execute_Undefined();
|
||||
case _.b101: return Execute_Unhandled("saturating addition and subtraction on page A5-13");
|
||||
case _.b110: return Execute_Undefined();
|
||||
case _.b111:
|
||||
switch (op)
|
||||
{
|
||||
case _.b01: return Execute_Unhandled("BKPT on page A8-56");
|
||||
case _.b11: return Execute_Unhandled("SMC/SMI on page B6-18 //sec.ext");
|
||||
default: return Execute_Undefined();
|
||||
}
|
||||
default:
|
||||
throw new InvalidOperationException("decoder fail");
|
||||
} //switch(op2)
|
||||
}
|
||||
|
||||
uint ExecuteArm_BX_A1()
|
||||
{
|
||||
//A8-62
|
||||
//A8.6.25
|
||||
uint Rm = Reg16(0);
|
||||
if (disassemble)
|
||||
return DIS("BX/c/", "/r0/", Rm);
|
||||
uint m = r[Rm];
|
||||
_BXWritePC(m);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint ExecuteArm_Media() { return Execute_Unhandled("ExecuteArm_Media"); }
|
||||
|
||||
Decoder decoder_ExecuteArm_BranchAndTransfer = new Decoder();
|
||||
uint ExecuteArm_BranchAndTransfer()
|
||||
{
|
||||
decoder_ExecuteArm_BranchAndTransfer.Ensure(() => decoder_ExecuteArm_BranchAndTransfer
|
||||
.d("op", 6).d("R", 1).d("Rn", 4)
|
||||
.r("op == #0000x0", () => Execute_Unhandled("STMDA/STMED on page A8-376"))
|
||||
.r("op == #0000x1", () => Execute_Unhandled("LDMDA/LDMFA on page A8-112"))
|
||||
.r("op == #0010x0", () => Execute_STM_STMIA_STMEA_A1())
|
||||
.r("op == #001001", () => Execute_Unhandled("LDM/LDMIA/LDMFD on page A8-110"))
|
||||
.r("op == #001011 && Rn != #1101", () => Execute_Unhandled("LDM/LDMIA/LDMFD on page A8-110"))
|
||||
.r("op == #001011 && Rn == #1101", () => Execute_POP_A1())
|
||||
.r("op == #010000", () => Execute_Unhandled("STMDB/STMFD on page A8-378"))
|
||||
.r("op == #010010 && Rn != #1101", () => Execute_Unhandled("STMDB/STMFD on page A8-378"))
|
||||
.r("op == #010010 && Rn == #1101", () => Execute_PUSH_A1())
|
||||
.r("op == #0100x1", () => Execute_Unhandled("LDMDB/LDMEA on page A8-114"))
|
||||
.r("op == #0110x0", () => Execute_Unhandled("STMIB/STMFA on page A8-380"))
|
||||
.r("op == #0110x1", () => Execute_Unhandled("LDMIB/LDMED on page A8-116"))
|
||||
.r("op == #0xx1x0", () => Execute_Unhandled("STM (user registers) on page B6-22"))
|
||||
.r("op == #0xx1x1 && R==0", () => Execute_Unhandled("LDM (user registers on page B6-5"))
|
||||
.r("op == #0xx1x1 && R==1", () => Execute_Unhandled("LDM (exception return) on page B6-5"))
|
||||
.r("op == #10xxxx", () => Execute_B_A1())
|
||||
.r("op == #11xxxx", () => Execute_BL_A1())
|
||||
);
|
||||
|
||||
uint op = (instruction >> 20) & 0x3F;
|
||||
uint Rn = Reg16(16);
|
||||
uint R = _.BIT15(instruction);
|
||||
|
||||
decoder_ExecuteArm_BranchAndTransfer.Evaluate(op, R, Rn);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
uint Execute_POP_A1()
|
||||
{
|
||||
uint register_list = instruction & 0xFFFF;
|
||||
if (_.BitCount(register_list) < 2) return Execute_LDM_LDMIA_LDMFD_A1();
|
||||
bool UnalignedAllowed = false;
|
||||
return ExecuteCore_POP(Encoding.A1, register_list, UnalignedAllowed);
|
||||
}
|
||||
|
||||
uint Execute_PUSH_A1()
|
||||
{
|
||||
uint register_list = instruction & 0xFFFF;
|
||||
if (_.BitCount(register_list) < 2) return Execute_STMDB_STMFD_A1();
|
||||
bool UnalignedAllowed = false;
|
||||
return ExecuteCore_PUSH(Encoding.A1, register_list, UnalignedAllowed);
|
||||
}
|
||||
|
||||
uint Execute_LDM_LDMIA_LDMFD_A1()
|
||||
{
|
||||
//A8.6.53 LDM/LDMIA/LDMFD
|
||||
Bit W = _.BIT21(instruction);
|
||||
uint n = Reg16(16);
|
||||
uint register_list = instruction & 0xFFFF;
|
||||
bool wback = (W == 1);
|
||||
if (n == 15 || _.BitCount(register_list) < 1) unpredictable = true;
|
||||
if (wback && _.BITN((int)n, register_list) == 1 && _ArchVersion() >= 7) unpredictable = true;
|
||||
return ExecuteCore_LDM_LDMIA_LDMFD(Encoding.A1, wback, n, register_list);
|
||||
}
|
||||
|
||||
|
||||
uint Execute_STM_STMIA_STMEA_A1()
|
||||
{
|
||||
//A8.6.189 STM/STMIA/STMEA
|
||||
Bit W = _.BIT21(instruction);
|
||||
uint n = Reg16(16);
|
||||
uint register_list = instruction & 0xFFFF;
|
||||
bool wback = W == 1;
|
||||
if (n == 15 || _.BitCount(register_list) < 1) unpredictable = true;
|
||||
return ExecuteCore_STM_STMIA_STMEA(Encoding.A1, wback, n, register_list);
|
||||
}
|
||||
|
||||
uint Execute_STMDB_STMFD_A1()
|
||||
{
|
||||
//A8.6.191 STMDB/STMFD
|
||||
Bit W = _.BIT21(instruction);
|
||||
uint n = Reg16(16);
|
||||
uint register_list = instruction & 0xFFFF;
|
||||
if (W == 1 && n == _.b1101 && _.BitCount(register_list) >= 2) return Execute_PUSH_A1();
|
||||
bool wback = W == 1;
|
||||
if (n == 15 || _.BitCount(register_list) < 1) unpredictable = true;
|
||||
return ExecuteCore_STMDB_STMFD(Encoding.A1, wback, n, register_list);
|
||||
}
|
||||
|
||||
uint Execute_BL_A1()
|
||||
{
|
||||
//A8.6.23
|
||||
//A8-58
|
||||
uint imm24 = instruction & 0xFFFFFF;
|
||||
int imm32 = _SignExtend_32(26, imm24 << 2);
|
||||
return ExecuteCore_BL_BLX_immediate(Encoding.A1, EInstrSet.ARM, imm32, false);
|
||||
}
|
||||
|
||||
uint Execute_B_A1()
|
||||
{
|
||||
uint imm24 = instruction & 0xFFFFFF;
|
||||
int imm32 = _SignExtend_32(26, imm24 << 2);
|
||||
|
||||
return ExecuteCore_B(Encoding.A1, imm32);
|
||||
}
|
||||
|
||||
Decoder Decoder_ExecuteArm_SVCAndCP = new Decoder();
|
||||
uint ExecuteArm_SVCAndCP()
|
||||
{
|
||||
//A5.6 Supervisor Call, and coprocessor instructions
|
||||
|
||||
Decoder_ExecuteArm_SVCAndCP.Ensure(() => Decoder_ExecuteArm_SVCAndCP
|
||||
.d("op1", 6).d("op", 1).d("coproc_special", 1).d("rn_is_15", 1)
|
||||
.r("op1==#0xxxxx && op1!=#000x0x && coproc_special==#1", () => Execute_Unhandled("ExecuteArm_SIMD_VFP_LoadStore"))
|
||||
.r("op1==#0xxxx0 && op1!=#000x0x && coproc_special==#0", () => Execute_Unhandled("STC,STC2"))
|
||||
.r("op1==#0xxxx1 && op1!=#000x0x && coproc_special==#0 && rn_is_15==#0", () => Execute_Unhandled("LDC,LDC2(immediate)"))
|
||||
.r("op1==#0xxxx1 && op1!=#000x0x && coproc_special==#0 && rn_is_15==#1", () => Execute_Unhandled("LDC,LDC2(literal)"))
|
||||
.r("op1==#00000x", () => Execute_Undefined())
|
||||
.r("op1==#00010x && coproc_special==#1", () => Execute_Unhandled("ExecuteArm_SIMD_VFP_64bit_xfer"))
|
||||
.r("op1==#000100 && coproc_special==#0", () => Execute_Unhandled("MCRR,MCRR2"))
|
||||
.r("op1==#000101 && coproc_special==#0", () => Execute_Unhandled("MRRC,MRRC2"))
|
||||
.r("op1==#10xxxx && op==0 && coproc_special==#1", () => Execute_Unhandled("VFP data-processing on page A7-24"))
|
||||
.r("op1==#10xxxx && op==0 && coproc_special==#0", () => Execute_Unhandled("CDP,CDP2 on page A8-68"))
|
||||
.r("op1==#10xxxx && op==1 && coproc_special==#1", () => ExecuteArm_ShortVFPTransfer())
|
||||
.r("op1==#10xxx0 && op==1 && coproc_special==#0", () => Execute_Unhandled("MCR,MCR2 on pageA8-186"))
|
||||
.r("op1==#10xxx1 && op==1 && coproc_special==#0", () => Execute_MRC_MRC2_A1())
|
||||
.r("op1==#110000", () => Execute_SVC_A1())
|
||||
);
|
||||
|
||||
uint op1 = (instruction >> 20) & 0x3F;
|
||||
uint Rn = Reg16(16);
|
||||
uint coproc = (instruction >> 8) & 0xF;
|
||||
uint op = _.BIT4(instruction);
|
||||
uint coproc_special = (coproc == _.b1010 || coproc == _.b1011) ? 1U : 0U;
|
||||
uint rn_is_15 = (Rn == 15) ? 1U : 0U;
|
||||
|
||||
Decoder_ExecuteArm_SVCAndCP.Evaluate(op1, op, coproc_special, rn_is_15);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint Execute_MRC_MRC2_A1()
|
||||
{
|
||||
//ignoring admonition to see "advanced SIMD and VFP" which has been handled by decode earlier
|
||||
uint t = Reg16(12);
|
||||
uint cp = Reg16(8);
|
||||
uint opc1 = Reg8(21);
|
||||
uint crn = Reg16(16);
|
||||
uint opc2 = Reg8(5);
|
||||
uint crm = Reg16(0);
|
||||
if (t == 13 && _CurrentInstrSet() != EInstrSet.ARM) unpredictable = true;
|
||||
return ExecuteCore_MRC_MRC2(Encoding.A1, cp, opc1, t, crn, crm, opc2);
|
||||
}
|
||||
|
||||
Decoder Decoder_ExecuteArm_ShortVFPTransfer = new Decoder();
|
||||
uint ExecuteArm_ShortVFPTransfer()
|
||||
{
|
||||
//A7.8
|
||||
//A7-31
|
||||
|
||||
Decoder_ExecuteArm_ShortVFPTransfer.Ensure(() => Decoder_ExecuteArm_ShortVFPTransfer
|
||||
.d("A", 3).d("L", 1).d("C", 1).d("B", 2)
|
||||
.r("L==0 && C==0 && A==#000", () => Execute_Unhandled("VMOV (between ARM core register and single-precision register) on page A8-648"))
|
||||
.r("L==0 && C==0 && A==#111", () => ExecuteArm_VMSR_A1())
|
||||
.r("L==0 && C==1 && A==#0xx", () => Execute_Unhandled("VMOV (ARM core register to scalar) on page A8-644"))
|
||||
.r("L==0 && C==1 && A==#1xx && B==#0x", () => Execute_Unhandled("VDUP (ARM core register) on page A8-594"))
|
||||
.r("L==1 && C==0 && A==#000", () => Execute_Unhandled("VMOV (between ARM core register and single-precision register) on page A8-648"))
|
||||
.r("L==1 && C==0 && A==#111", () => Execute_Unhandled("VMRS on page A8-658 or page B6-27"))
|
||||
.r("L==1 && C==1", () => Execute_Unhandled("VMOV (scalar to ARM core register) on page A8-646"))
|
||||
);
|
||||
|
||||
uint A = (instruction >> 21) & _.b111;
|
||||
uint L = _.BIT20(instruction);
|
||||
uint C = _.BIT8(instruction);
|
||||
uint B = (instruction >> 5) & _.b11;
|
||||
|
||||
Decoder_ExecuteArm_ShortVFPTransfer.Evaluate(A, L, C, B);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint ExecuteArm_VMSR_A1()
|
||||
{
|
||||
uint t = Reg16(12);
|
||||
if (t == 15 || (t == 13 && _CurrentInstrSet() != EInstrSet.ARM)) return _UNPREDICTABLE();
|
||||
|
||||
if (disassemble)
|
||||
if (nstyle)
|
||||
return DISNEW("FMXR<c>", "<fpscr>,<Rt>", t);
|
||||
else
|
||||
return DISNEW("VMSR<c>", "<fpscr>, <Rt>", t);
|
||||
|
||||
return ExecuteCore_VMSR(t);
|
||||
}
|
||||
|
||||
uint Execute_SVC_A1()
|
||||
{
|
||||
//A8.6.218
|
||||
//A8-430
|
||||
uint imm24 = instruction & 0xFFFFFF;
|
||||
uint imm32 = imm24;
|
||||
|
||||
return ExecuteCore_SVC(Encoding.A1, imm32);
|
||||
}
|
||||
|
||||
|
||||
} //class ARM11
|
||||
}
|
|
@ -0,0 +1,998 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace BizHawk.Emulation.CPUs.ARM
|
||||
{
|
||||
|
||||
partial class ARM
|
||||
{
|
||||
//A8.6.4 ADD
|
||||
uint ExecuteCore_ADD_immediate_thumb(Encoding encoding, uint n, uint d, bool setflags, uint imm32)
|
||||
{
|
||||
if (disassemble)
|
||||
if (disopt.showExplicitAccumulateRegisters || n != d)
|
||||
return DISNEW("ADD<s?><c?>", "<Rd!>, <Rn!>, #<const>", setflags, false, d, n, imm32);
|
||||
else
|
||||
return DISNEW("ADD<s?><c?>", "<Rd!>, #<const>", setflags, false, d, imm32);
|
||||
|
||||
_AddWithCarry32(r[n], imm32, 0);
|
||||
r[d] = alu_result_32;
|
||||
if (setflags)
|
||||
{
|
||||
APSR.N = _.BIT31(alu_result_32);
|
||||
APSR.Z = _IsZeroBit(alu_result_32);
|
||||
APSR.C = alu_carry_out;
|
||||
APSR.V = alu_overflow;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.5 ADD (immediate, ARM)
|
||||
uint ExecuteCore_ADD_immediate_arm(Encoding encoding, bool setflags, uint n, uint d, uint imm32)
|
||||
{
|
||||
if (disassemble)
|
||||
if (disopt.showExplicitAccumulateRegisters || n != d)
|
||||
return DISNEW("ADD<s?><c>", "<rd!>, <rn!>, #<const>", setflags, d, n, imm32);
|
||||
else
|
||||
return DISNEW("ADD<s?><c>", "<rd!>, #<const>", setflags, d, imm32);
|
||||
|
||||
_AddWithCarry32(r[n], imm32, 0);
|
||||
if (d == 15)
|
||||
_ALUWritePC(alu_result_32); //"setflags is always FALSE here"
|
||||
else
|
||||
{
|
||||
r[d] = alu_result_32;
|
||||
if (setflags)
|
||||
{
|
||||
APSR.N = _.BIT31(alu_result_32);
|
||||
APSR.Z = _IsZeroBit(alu_result_32);
|
||||
APSR.C = alu_carry_out;
|
||||
APSR.V = alu_overflow;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.6 ADD (register)
|
||||
uint ExecuteCore_ADD_register(Encoding encoding, uint m, uint d, uint n, bool setflags, SRType shift_t, int shift_n)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("ADD<s?><c>", "<Rd!>, <Rn!>, <Rm!><{, shift}>", setflags, d, n, m, shift_t, shift_n);
|
||||
|
||||
uint shifted = _Shift(r[m], shift_t, shift_n, APSR.C);
|
||||
_AddWithCarry32(r[n], shifted, 0);
|
||||
if (d == 15) _ALUWritePC(alu_result_32);
|
||||
else
|
||||
{
|
||||
r[d] = alu_result_32;
|
||||
if (setflags)
|
||||
{
|
||||
APSR.N = _.BIT31(alu_result_32);
|
||||
APSR.Z = _IsZeroBit(alu_result_32);
|
||||
APSR.C = alu_carry_out;
|
||||
APSR.V = alu_overflow;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//A8.6.8 ADD (SP plus immediate)
|
||||
uint ExecuteCore_ADD_SP_plus_immedate(Encoding encoding, uint d, bool setflags, uint imm32)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("ADD<s?><c>", "<rd!>, <sp!>, #<const>", setflags, d, imm32);
|
||||
|
||||
if (setflags && d == 15) throw new NotImplementedException("see SUBS PC, LR and related instruction on page B6-25");
|
||||
//addendum about !s && d==PC is correctly handled already by writing pseudocode
|
||||
_AddWithCarry32(SP, imm32, 0);
|
||||
if (d == 15)
|
||||
{
|
||||
Debug.Assert(!setflags);
|
||||
_ALUWritePC(alu_result_32); //"can only occur for ARM encoding. setflags is always FALSE here"
|
||||
}
|
||||
else
|
||||
{
|
||||
r[d] = alu_result_32;
|
||||
if (setflags)
|
||||
{
|
||||
APSR.N = _.BIT31(alu_result_32);
|
||||
APSR.Z = _IsZeroBit(alu_result_32);
|
||||
APSR.C = alu_carry_out;
|
||||
APSR.V = alu_overflow;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.10 ADR
|
||||
uint ExecuteCore_ADR(Encoding encoding, uint d, uint imm32, bool add)
|
||||
{
|
||||
uint result;
|
||||
if (add)
|
||||
result = _Align(PC, 4) + imm32;
|
||||
else result = _Align(PC, 4) - imm32;
|
||||
|
||||
if (disassemble)
|
||||
if (nstyle)
|
||||
return DIS("ADD", "/r0/,pc,/imm8_1/ ; maybe MOV rX,pc", d, imm32);
|
||||
else return DIS("ADR", "/r0/, /label1/ ; maybe MOV rX,pc", d, result);
|
||||
|
||||
if (d == 15)
|
||||
_ALUWritePC(result);
|
||||
else r[d] = result;
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.14 ASR (immediate)
|
||||
uint ExecuteCore_ASR_immediate(Encoding encoding, uint d, uint m, bool setflags, int shift_n)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("ASR<s?><c>", "<{rd!~rm, }><rm!>, #<imm>", setflags, d, m, m, shift_n);
|
||||
|
||||
uint result;
|
||||
Bit carry;
|
||||
_Shift_C(r[m], SRType.ASR, shift_n, APSR.C, out result, out carry);
|
||||
if (d == 15)
|
||||
_ALUWritePC(result);
|
||||
else
|
||||
{
|
||||
r[d] = result;
|
||||
if (setflags)
|
||||
{
|
||||
APSR.N = _.BIT31(result);
|
||||
APSR.Z = _IsZeroBit(result);
|
||||
APSR.C = carry;
|
||||
//APSR.V unchanged
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//A8.6.16 B
|
||||
uint ExecuteCore_B(Encoding encoding, int imm32)
|
||||
{
|
||||
uint label = (uint)((int)PC + imm32);
|
||||
|
||||
if (disassemble)
|
||||
return DISNEW("B<c>", "<label>", label);
|
||||
|
||||
//make sure to check conditions here since this can get called from thumb
|
||||
if (_ConditionPassed())
|
||||
_BranchWritePC(label);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.23 BL, BLX (immediate)
|
||||
uint ExecuteCore_BL_BLX_immediate(Encoding encoding, EInstrSet targetInstrSet, int imm32, bool blx)
|
||||
{
|
||||
uint targetAddress;
|
||||
if (targetInstrSet == EInstrSet.ARM)
|
||||
targetAddress = (uint)((int)_Align(PC, 4) + imm32);
|
||||
else
|
||||
targetAddress = (uint)((int)PC + imm32);
|
||||
|
||||
if (disassemble)
|
||||
return DISNEW(blx ? "blx<c?>" : "bl<c?>", "<label>", (encoding == Encoding.A1), targetAddress);
|
||||
|
||||
if (_CurrentInstrSet() == EInstrSet.ARM)
|
||||
LR = PC - 4;
|
||||
else LR = (uint)((PC & ~1) | 1);
|
||||
|
||||
_SelectInstrSet(targetInstrSet);
|
||||
_BranchWritePC(targetAddress);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.24 BLX (register)
|
||||
uint ExecuteCore_BLX_register(Encoding encoding, uint m)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("BLX<c>", "<rm!>", m);
|
||||
|
||||
//NEXT_INSTR_ADDR not to be confused with other variables in our core emulator
|
||||
uint target = r[m];
|
||||
if (_CurrentInstrSet() == EInstrSet.ARM)
|
||||
{
|
||||
uint NEXT_INSTR_ADDR = PC - 4;
|
||||
LR = NEXT_INSTR_ADDR;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint NEXT_INSTR_ADDR = PC - 2;
|
||||
LR = (NEXT_INSTR_ADDR & 0xFFFFFFFE) | 1;
|
||||
}
|
||||
_BXWritePC(target);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.35 CMP (immediate)
|
||||
uint ExecuteCore_CMP_immediate(Encoding encoding, uint n, uint imm32)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("CMP<c>", "<Rn!>, #<const>", n, imm32);
|
||||
|
||||
_AddWithCarry32(r[n], ~imm32, 1);
|
||||
APSR.N = _.BIT31(alu_result_32);
|
||||
APSR.Z = _IsZeroBit(alu_result_32);
|
||||
APSR.C = alu_carry_out;
|
||||
APSR.V = alu_overflow;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//A8.6.36 CMP (register)
|
||||
uint ExecuteCore_CMP_register(Encoding encoding, uint n, uint m, SRType shift_t, int shift_n)
|
||||
{
|
||||
Debug.Assert(!(EncodingT(encoding) && n == 15)); //?? not in pseudocode but sort of suggested by addenda
|
||||
|
||||
if (disassemble)
|
||||
return DISNEW("CMP<c>", "<rn!>, <rm!><{, shift}>", n, m, shift_t, shift_n);
|
||||
|
||||
uint shifted = _Shift(r[m], shift_t, shift_n, APSR.C);
|
||||
_AddWithCarry32(r[n], ~shifted, 1);
|
||||
APSR.N = _.BIT31(alu_result_32);
|
||||
APSR.Z = _IsZeroBit(alu_result_32);
|
||||
APSR.C = alu_carry_out;
|
||||
APSR.V = alu_overflow;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.39 CPY
|
||||
uint ExecuteCore_CPY()
|
||||
{
|
||||
//(this space intentionally blank. instruction is obsoleted)
|
||||
return 0;
|
||||
}
|
||||
|
||||
//A8.6.45 EOR (register)
|
||||
uint ExecuteCore_EOR_register(Encoding encoding, uint m, uint d, uint n, bool setflags, SRType shift_t, int shift_n)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("EOR<s?><c>", "<{rd!~rn, }><rn!>, <rm!><{, shift}>", setflags, d, n, n, m, shift_t, shift_n);
|
||||
|
||||
uint shifted;
|
||||
Bit carry;
|
||||
_Shift_C(r[m], shift_t, shift_n, APSR.C, out shifted, out carry);
|
||||
uint result = r[n] ^ shifted;
|
||||
if (d == 15)
|
||||
_ALUWritePC(result);
|
||||
else
|
||||
{
|
||||
r[d] = result;
|
||||
if (setflags)
|
||||
{
|
||||
APSR.N = _.BIT31(result);
|
||||
APSR.Z = _IsZeroBit(result);
|
||||
APSR.C = carry;
|
||||
//APSR.V unchanged
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.53 LDM/LDMIA/LDMFD
|
||||
uint ExecuteCore_LDM_LDMIA_LDMFD(Encoding encoding, bool wback, uint n, uint registers)
|
||||
{
|
||||
//many ways to write this...
|
||||
//I chose LDMIA to match rvct
|
||||
if (disassemble)
|
||||
return DISNEW("LDMIA<c>", "<Rn!><{wback!}>, <registers>", n, wback, registers);
|
||||
|
||||
_NullCheckIfThumbEE(n);
|
||||
uint bitcount = _.BitCount(registers);
|
||||
uint address = r[n];
|
||||
for (int i = 0; i <= 14; i++)
|
||||
if (_.BITN(i, registers) == 1)
|
||||
{
|
||||
r[i] = MemA_Read32(address);
|
||||
address += 4;
|
||||
}
|
||||
if (_.BIT15(registers) == 1)
|
||||
_LoadWritePC(MemA_Read32(address));
|
||||
if (wback && _.BITN((int)n, registers) == 0) r[n] = r[n] + 4 * bitcount;
|
||||
if (wback && _.BITN((int)n, registers) == 1) r[n] = (uint)_UNKNOWN(32, r[n] + 4 * bitcount);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//A8.6.57 LDR (immediate, thumb)
|
||||
uint ExecuteCore_LDR_immediate_thumb(Encoding encoding, uint t, uint imm32, uint n, bool index, bool add, bool wback)
|
||||
{
|
||||
if (disassemble)
|
||||
return Disassemble_LDR_STR_immediate("LDR", t, imm32, n, index, add, wback);
|
||||
|
||||
_NullCheckIfThumbEE(n);
|
||||
uint offset_addr, address;
|
||||
if (add) offset_addr = r[n] + imm32; else offset_addr = r[n] - imm32;
|
||||
if (index) address = offset_addr; else address = r[n];
|
||||
uint data = MemU_Read32(address);
|
||||
if (wback) r[n] = offset_addr;
|
||||
if (t == 15)
|
||||
{
|
||||
if ((address & 3) == 0) _LoadWritePC(data); else _UNPREDICTABLE();
|
||||
}
|
||||
else if (_UnalignedSupport() || (address & 3) == 0)
|
||||
r[t] = data;
|
||||
else r[t] = (uint)_UNKNOWN(32, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//A8.6.58 LDR (immediate, arm)
|
||||
uint ExecuteCore_LDR_immediate_arm(Encoding encoding, uint t, uint imm32, uint n, bool index, bool add, bool wback)
|
||||
{
|
||||
if (disassemble)
|
||||
return Disassemble_LDR_STR_immediate("LDR", t, imm32, n, index, add, wback);
|
||||
|
||||
uint offset_addr, address;
|
||||
if (add) offset_addr = r[n] + imm32;
|
||||
else offset_addr = r[n] - imm32;
|
||||
if (index) address = offset_addr;
|
||||
else address = r[n];
|
||||
uint data = MemU_Read32(address);
|
||||
if (wback) r[n] = offset_addr;
|
||||
if (t == 15)
|
||||
{
|
||||
if ((address & 3) == _.b00) _LoadWritePC(data); else unpredictable = true;
|
||||
}
|
||||
else if (_UnalignedSupport() || ((address & 3) == _.b00))
|
||||
r[t] = data;
|
||||
else //can only apply before ARMv7
|
||||
r[t] = _ROR(data, 8 * ((int)address & 3));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//A8.6.59 LDR (literal)
|
||||
uint ExecuteCore_LDR_literal(Encoding encoding, uint t, uint imm32, bool add)
|
||||
{
|
||||
uint @base = _Align(PC, 4);
|
||||
uint address = add ? (@base + imm32) : (@base - imm32);
|
||||
|
||||
if (disassemble)
|
||||
return DISNEW("LDR<c>", "<Rt>,[PC,#<optaddsub><imm>] ; @<label>=<%08X>", t, add, imm32, address, bus.Read32(AT.PEEK, address));
|
||||
|
||||
uint data = _MemU(address, 4);
|
||||
|
||||
if (t == 15)
|
||||
if ((address & 3) == 0) _LoadWritePC(data); else _UNPREDICTABLE();
|
||||
else if (_UnalignedSupport() || ((address & 3) == 0))
|
||||
r[t] = data;
|
||||
else
|
||||
//can only apply before armv7
|
||||
if (_CurrentInstrSet() == EInstrSet.ARM)
|
||||
r[t] = _ROR(data, (int)(address & 3));
|
||||
else
|
||||
{ r[t] = (uint)_UNKNOWN(32, data); }
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.61 LDRB (immediate, thumb)
|
||||
uint ExecuteCore_LDRB_immediate_thumb(Encoding encoding, uint t, uint n, uint imm32, bool index, bool add, bool wback)
|
||||
{
|
||||
if (disassemble)
|
||||
return Disassemble_LDR_STR_immediate("LDRB<c>", t, imm32, n, index, add, wback);
|
||||
|
||||
uint offset_addr = add ? (r[n] + imm32) : (r[n] - imm32);
|
||||
uint address = index ? offset_addr : r[n];
|
||||
r[t] = _ZeroExtend_32(MemU_Read08(address));
|
||||
if (wback) r[n] = offset_addr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.64 LDRB (register)
|
||||
uint ExecuteCore_LDRB_register(Encoding encoding, uint t, uint n, uint m, SRType shift_t, int shift_n, bool index, bool add, bool wback)
|
||||
{
|
||||
if (disassemble)
|
||||
return Disassemble_LDR_STR_register("LDRB<c>", t, n, m, shift_t, shift_n, index, add, wback);
|
||||
|
||||
uint offset = _Shift(r[m], shift_t, shift_n, APSR.C);
|
||||
uint offset_addr = add ? (r[n] + offset) : (r[n] - offset);
|
||||
uint address = index ? offset_addr : r[n];
|
||||
r[t] = _ZeroExtend_32(_MemU(address, 1));
|
||||
if (wback) r[n] = offset_addr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.69 LDREX
|
||||
uint ExecuteCore_LDREX(Encoding encoding, uint n, uint t, uint imm32)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("LDREX<c>", "<rt!>, [<rn!><{ ,#imm}>]", t, n, imm32);
|
||||
_NullCheckIfThumbEE(n);
|
||||
uint address = r[n] + imm32;
|
||||
_SetExclusiveMonitors(address, 4);
|
||||
r[t] = MemA_Read32(address);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.73 LDRH (immediate, thumb)
|
||||
uint ExecuteCore_LDRH_immediate_thumb(Encoding encoding, uint t, uint n, uint imm32, bool index, bool add, bool wback)
|
||||
{
|
||||
if (disassemble)
|
||||
return Disassemble_LDR_STR_immediate("LDRH", t, imm32, n, index, add, wback);
|
||||
_NullCheckIfThumbEE(n);
|
||||
uint offset_addr = add ? (r[n] + imm32) : (r[n] - imm32);
|
||||
uint address = index ? offset_addr : r[n];
|
||||
ushort data = MemU_Read16(address);
|
||||
if (wback) r[n] = offset_addr;
|
||||
if (_UnalignedSupport() || _.BIT0(address) == 0)
|
||||
r[t] = _ZeroExtend_32((uint)data);
|
||||
else r[t] = (uint)_UNKNOWN(32, (ulong)_ZeroExtend_32((uint)data));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.88 LSL (immediate)
|
||||
uint ExecuteCore_LSL_immediate(Encoding encoding, uint d, uint m, bool setflags, int shift_n)
|
||||
{
|
||||
//sometimes (in arm) this shows up as MOV. i sort of like that syntax better...
|
||||
if (disassemble)
|
||||
return DISNEW("LSL<s?><c>", "<{rd!~rm, }><rm!>, #<imm5>", setflags, d, m, m, shift_n);
|
||||
|
||||
uint result;
|
||||
Bit carry;
|
||||
_Shift_C(r[m], SRType.LSL, shift_n, APSR.C, out result, out carry);
|
||||
if (d == 15)
|
||||
_ALUWritePC(result);
|
||||
else
|
||||
{
|
||||
r[d] = result;
|
||||
if (setflags)
|
||||
{
|
||||
APSR.N = _.BIT31(result);
|
||||
APSR.Z = _IsZeroBit(result);
|
||||
APSR.C = carry;
|
||||
//APSR.V unchanged
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//A8.6.90 LSR (immediate)
|
||||
uint ExecuteCore_LSR_immediate(Encoding encoding, uint d, uint m, bool setflags, int shift_n)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("LSR<s?><c>", "<{rd!~rm, }><rm!>, #<imm5>", setflags, d, m, m, shift_n);
|
||||
|
||||
uint result;
|
||||
Bit carry;
|
||||
_Shift_C(r[m], SRType.LSR, shift_n, APSR.C, out result, out carry);
|
||||
if (d == 15)
|
||||
_ALUWritePC(result);
|
||||
else
|
||||
{
|
||||
r[d] = result;
|
||||
if (setflags)
|
||||
{
|
||||
APSR.N = _.BIT31(result);
|
||||
APSR.Z = _IsZeroBit(result);
|
||||
APSR.C = carry;
|
||||
//APSR.V unchanged
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.97 MOV (register)
|
||||
uint ExecuteCore_MOV_register(Encoding encoding, uint d, uint m, bool setflags)
|
||||
{
|
||||
//there are many caveats and addenda in the manual. check it carefully.
|
||||
|
||||
if (disassemble)
|
||||
return DISNEW("MOV<s?><c?>", "<Rd!>,<Rm!>", setflags, EncodingA(encoding), d, m);
|
||||
|
||||
uint result = r[m];
|
||||
if (d == 15)
|
||||
_ALUWritePC(result);
|
||||
else
|
||||
{
|
||||
r[d] = result;
|
||||
if (setflags)
|
||||
{
|
||||
APSR.N = _.BIT31(result);
|
||||
APSR.Z = _IsZeroBit(result);
|
||||
//C and V are unchanged
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.96 MOV (immedate)
|
||||
uint ExecuteCore_MOV_immediate(Encoding encoding, uint d, bool setflags, uint imm32, uint carry)
|
||||
{
|
||||
if (disassemble)
|
||||
return DIS("MOV/s0//c/", "/r1/,/const2/", setflags, d, imm32);
|
||||
uint result = imm32;
|
||||
if (d == 15)
|
||||
_ALUWritePC(result);
|
||||
else
|
||||
{
|
||||
r[d] = result;
|
||||
if (setflags)
|
||||
{
|
||||
APSR.N = _.BIT31(result);
|
||||
APSR.Z = (result == 0) ? 1U : 0U;
|
||||
APSR.C = carry;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.100 MRC, MRC2
|
||||
uint ExecuteCore_MRC_MRC2(Encoding encoding, uint cp, uint opc1, uint t, uint crn, uint crm, uint opc2)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("MRC<c>" + ((encoding == Encoding.A2 || encoding == Encoding.T2) ? "2" : ""), "<coproc>, <opc1>, <coproc_rt!>, <crn>, <crm>, <opc2><{ ;cp_comment}>", cp, opc1, t, crn, crm, opc2, "TBD");
|
||||
|
||||
uint value = sys.coprocessors.MRC(cp, opc1, t, crn, crm, opc2);
|
||||
if (t != 15)
|
||||
r[t] = value;
|
||||
else
|
||||
{
|
||||
APSR.N = _.BIT31(value);
|
||||
APSR.Z = _.BIT30(value);
|
||||
APSR.C = _.BIT29(value);
|
||||
APSR.V = _.BIT28(value);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.109 NEG [BLANK]
|
||||
uint ExecuteCore_NEG()
|
||||
{
|
||||
//(this space intentionally blank. NEG was removed from the spec and replaced with RSB (immediate)
|
||||
return 0;
|
||||
}
|
||||
|
||||
//A8.6.113 ORR (immediate)
|
||||
uint ExecuteCore_ORR_immediate(Encoding encoding, uint n, uint d, bool setflags, uint imm32, Bit carry)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("ORR<s?><c>", "<{rd!~rn, }><rn!>, #<const>", setflags, d, n, n, imm32);
|
||||
|
||||
uint result = r[n] | imm32;
|
||||
if (d == 15)
|
||||
_ALUWritePC(result);
|
||||
else
|
||||
{
|
||||
r[d] = result;
|
||||
if (setflags)
|
||||
{
|
||||
APSR.N = result;
|
||||
APSR.Z = _IsZeroBit(result);
|
||||
APSR.C = carry;
|
||||
//APSR.V unchanged
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.114 ORR (reg)
|
||||
uint ExecuteCore_ORR_register(Encoding encoding, uint m, uint d, uint n, bool setflags, SRType shift_t, int shift_n)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("ORR<s?><c>", "<Rd!>, <Rn!>, <Rm!><{, shift}>", setflags, d, n, m, shift_t, shift_n);
|
||||
|
||||
uint shifted;
|
||||
Bit carry;
|
||||
_Shift_C(r[m], shift_t, shift_n, APSR.C, out shifted, out carry);
|
||||
uint result = r[n] | shifted;
|
||||
if (d == 15)
|
||||
_ALUWritePC(result);
|
||||
else
|
||||
{
|
||||
r[d] = result;
|
||||
if (setflags)
|
||||
{
|
||||
APSR.N = _.BIT31(result);
|
||||
APSR.Z = _IsZeroBit(result);
|
||||
APSR.C = carry;
|
||||
//APSR.V unchanged
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.122 POP
|
||||
uint ExecuteCore_POP(Encoding encoding, uint registers, bool UnalignedAllowed)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("pop<c>", "<registers> ; maybe LDMIA sp!,{..}", registers);
|
||||
|
||||
//in armv7, if SP is in the list then the instruction is UNKNOWN
|
||||
uint address = SP;
|
||||
|
||||
uint bitcount = 0;
|
||||
for (int i = 0; i <= 14; i++)
|
||||
{
|
||||
if (_.BITN(i, registers) == 1)
|
||||
{
|
||||
bitcount++;
|
||||
r[i] = UnalignedAllowed ? _MemU(address, 4) : _MemA(address, 4);
|
||||
address = address + 4;
|
||||
}
|
||||
}
|
||||
if (_.BIT15(registers) == 1)
|
||||
{
|
||||
bitcount++;
|
||||
if (UnalignedAllowed)
|
||||
_LoadWritePC(_MemU(address, 4));
|
||||
else
|
||||
_LoadWritePC(_MemA(address, 4));
|
||||
}
|
||||
if (_.BIT13(registers) == 0) SP = SP + 4 * bitcount;
|
||||
else SP = (uint)_UNKNOWN(32, SP + 4 * bitcount);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.123 PUSH
|
||||
uint ExecuteCore_PUSH(Encoding encoding, uint registers, bool UnalignedAllowed)
|
||||
{
|
||||
uint bitcount = _.BitCount(registers);
|
||||
|
||||
if (disassemble)
|
||||
if (bitcount == 1)
|
||||
return DISNEW("push<c>", "<registers> ; maybe STR rx,[SP,#-0x4]", registers);
|
||||
else
|
||||
return DISNEW("push<c>", "<registers> ; maybe STMDB sp!,{..}", registers);
|
||||
|
||||
_NullCheckIfThumbEE(13);
|
||||
uint address = SP - 4 * bitcount;
|
||||
for (int i = 0; i <= 14; i++)
|
||||
{
|
||||
if (_.BITN(i, registers) == 1)
|
||||
{
|
||||
//TODO - work on this
|
||||
if (i == 13 && i != _LowestSetBit(registers, 16))
|
||||
MemA_Write32(address, (uint)_UNKNOWN(32, r[i]));
|
||||
else if (UnalignedAllowed)
|
||||
MemU_Write32(address, r[i]);
|
||||
else
|
||||
MemA_Write32(address, r[i]);
|
||||
address += 4;
|
||||
}
|
||||
}
|
||||
if (_.BIT15(registers) == 1)
|
||||
{
|
||||
if (UnalignedAllowed)
|
||||
MemU_Write32(address, _PCStoreValue());
|
||||
else
|
||||
MemA_Write32(address, _PCStoreValue());
|
||||
}
|
||||
|
||||
SP = SP - 4 * bitcount;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.142 RSB (immediate)
|
||||
uint ExecuteCore_RSB_immediate(Encoding encoding, uint d, uint n, bool setflags, uint imm32)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("RSB<s?><c>", "<{rd!~rn, }><rn!>, #<const>" + (imm32 == 0 ? " ;maybe NEG" : ""), setflags, d, n, n, imm32);
|
||||
_AddWithCarry32(~r[n], imm32, 1);
|
||||
if (d == 15)
|
||||
_ALUWritePC(alu_result_32);
|
||||
else
|
||||
{
|
||||
r[d] = alu_result_32;
|
||||
APSR.N = _.BIT31(alu_result_32);
|
||||
APSR.Z = _IsZeroBit(alu_result_32);
|
||||
APSR.C = alu_carry_out;
|
||||
APSR.V = alu_overflow;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.189 STM/STMIA/STMEA
|
||||
uint ExecuteCore_STM_STMIA_STMEA(Encoding encoding, bool wback, uint n, uint registers)
|
||||
{
|
||||
//we could write this as STM<c>, STM<c>IA or STMIA<c> or STMEA<c> or STM<c>EA but how to choose?? who cares. christ.
|
||||
//I chose STMIA to match rvct
|
||||
if (disassemble)
|
||||
return DISNEW("STMIA<c>", "<Rn!><{wback!}>, <registers>", n, wback, registers);
|
||||
|
||||
uint bitcount = _.BitCount(registers);
|
||||
uint address = r[n];
|
||||
for (int i = 0; i <= 14; i++)
|
||||
{
|
||||
if (_.BITN(i, registers) == 1)
|
||||
{
|
||||
if (i == n && wback && i != _LowestSetBit(registers, 16))
|
||||
MemA_Write32(address, (uint)_UNKNOWN(32, r[i])); //"only possible for encodings T1 and A1"
|
||||
else MemA_Write32(address, r[i]);
|
||||
address += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (_.BIT15(registers) == 1) //"only possible for encoding A1"
|
||||
MemA_Write32(address, _PCStoreValue());
|
||||
if (wback) r[n] = r[n] + 4 * bitcount;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.191 STMDB/STMFD
|
||||
uint ExecuteCore_STMDB_STMFD(Encoding encoding, bool wback, uint n, uint registers)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("STMDB<c>", "<Rn!><{wback!}>, <registers>", n, wback, registers);
|
||||
|
||||
uint bitcount = _.BitCount(registers);
|
||||
uint address = r[n] - 4 * bitcount;
|
||||
for (int i = 0; i <= 14; i++)
|
||||
{
|
||||
if (_.BITN(i, registers) == 1)
|
||||
{
|
||||
if (i == n && wback && i != _LowestSetBit(registers, 16))
|
||||
MemA_Write32(address, (uint)_UNKNOWN(32, r[i])); //"only possible for encoding A1"
|
||||
else
|
||||
MemA_Write32(address, r[i]);
|
||||
address += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (_.BIT15(registers) == 1) //"only possible for encoding A1"
|
||||
MemA_Write32(address, _PCStoreValue());
|
||||
|
||||
if (wback) r[n] = r[n] - 4 * bitcount;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//A8.6.193 STR (immediate, thumb)
|
||||
uint ExecuteCore_STR_immediate_thumb(Encoding encoding, uint t, uint imm32, uint n, bool index, bool add, bool wback)
|
||||
{
|
||||
if (disassemble)
|
||||
return Disassemble_LDR_STR_immediate("STR", t, imm32, n, index, add, wback);
|
||||
|
||||
uint offset_addr;
|
||||
if (add) offset_addr = r[n] + imm32; else offset_addr = r[n] - imm32;
|
||||
uint address;
|
||||
if (index) address = offset_addr; else address = r[n];
|
||||
if (_UnalignedSupport() || ((address & 3) == 0))
|
||||
MemU_Write32(address, r[t]);
|
||||
else
|
||||
UnalignedAccess(address);
|
||||
if (wback) r[n] = offset_addr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.194 STR (immediate, arm)
|
||||
uint ExecuteCore_STR_immediate_arm(Encoding encoding, bool P, bool U, bool W, uint n, uint t, uint imm32, bool index, bool add, bool wback)
|
||||
{
|
||||
if (disassemble)
|
||||
return Disassemble_LDR_STR_immediate("STR", t, imm32, n, index, add, wback);
|
||||
|
||||
uint offset_addr = add ? (r[n] + imm32) : (r[n] - imm32);
|
||||
uint address = index ? offset_addr : r[n];
|
||||
MemU_Write32(address, t == 15 ? _PCStoreValue() : r[t]);
|
||||
if (wback) r[n] = offset_addr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.196 STRB (immediate, thumb)
|
||||
uint ExecuteCore_STRB_immediate_thumb(Encoding encoding, uint t, uint n, uint imm32, bool index, bool add, bool wback)
|
||||
{
|
||||
if (disassemble)
|
||||
return Disassemble_LDR_STR_immediate("STRB", t, imm32, n, index, add, wback);
|
||||
|
||||
uint offset_addr = add ? (r[n] + imm32) : (r[n] - imm32);
|
||||
uint address = index ? offset_addr : r[n];
|
||||
MemU_Write08(address, r[t] & 0xFF);
|
||||
if (wback) r[n] = offset_addr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.198 STRB (register)
|
||||
uint ExecuteCore_STRB_register(Encoding encoding, uint t, uint n, uint m, SRType shift_t, int shift_n, bool index, bool add, bool wback)
|
||||
{
|
||||
if (disassemble)
|
||||
return Disassemble_LDR_STR_register("STRB<c>", t, n, m, shift_t, shift_n, index, add, wback);
|
||||
|
||||
uint offset = _Shift(r[m], shift_t, shift_n, APSR.C);
|
||||
uint offset_addr = add ? (r[n] + offset) : (r[n] - offset);
|
||||
uint address = index ? offset_addr : r[n];
|
||||
MemU_Write08(address, r[t] & 0xFF);
|
||||
if (wback) r[n] = offset_addr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.202 STREX
|
||||
uint ExecuteCore_STREX(Encoding encoding, uint d, uint n, uint t, uint imm32)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("STREX<c>", "<rd!>, <rt!>, [<rn!><{ ,#imm}>]", d, t, n, imm32);
|
||||
_NullCheckIfThumbEE(n);
|
||||
uint address = r[n] + imm32;
|
||||
if (_ExclusiveMonitorsPass(address, 4))
|
||||
{
|
||||
MemA_Write32(address, r[t]);
|
||||
r[d] = 0;
|
||||
}
|
||||
else r[d] = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.206 STRH (immediate, thumb)
|
||||
uint ExecuteCore_STRH_immediate_thumb(Encoding encoding, uint t, uint n, uint imm32, bool index, bool add, bool wback)
|
||||
{
|
||||
if (disassemble)
|
||||
return Disassemble_LDR_STR_immediate("STRH", t, imm32, n, index, add, wback);
|
||||
_NullCheckIfThumbEE(n);
|
||||
uint offset_addr = add ? (r[n] + imm32) : (r[n] - imm32);
|
||||
uint address = index ? offset_addr : r[n];
|
||||
if (_UnalignedSupport() || _.BIT0(address) == 0)
|
||||
MemU_Write16(address, r[t] & 0xFFFF);
|
||||
else
|
||||
MemU_Write16(address, (uint)_UNKNOWN(16, r[t] & 0xFFFF));
|
||||
if (wback) r[n] = offset_addr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.211 SUB (immediate, thumb)
|
||||
uint ExecuteCore_SUB_immediate_thumb(Encoding encoding, uint n, uint d, bool setflags, uint imm32)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("SUB<s?><c>", "<{rd!~rn, }><rn!>, #<const>", setflags, d, n, n, imm32);
|
||||
|
||||
_AddWithCarry32(r[n], ~imm32, 1);
|
||||
r[d] = alu_result_32;
|
||||
if (setflags)
|
||||
{
|
||||
APSR.N = _.BIT31(alu_result_32);
|
||||
APSR.Z = _IsZeroBit(alu_result_32);
|
||||
APSR.C = alu_carry_out;
|
||||
APSR.V = alu_overflow;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.212 SUB (immediate, arm)
|
||||
uint ExecuteCore_SUB_immediate_arm(Encoding encoding, bool setflags, uint n, uint d, uint imm32)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("SUB<s?><c>", "<{rd!~rn, }><rn!>, #<const>", setflags, d, n, n, imm32);
|
||||
|
||||
_AddWithCarry32(r[n], ~imm32, 1);
|
||||
if (d == 15)
|
||||
_ALUWritePC(alu_result_32); //setflags is always FALSE here
|
||||
else
|
||||
{
|
||||
r[d] = alu_result_32;
|
||||
if (setflags)
|
||||
{
|
||||
APSR.N = _.BIT31(alu_result_32);
|
||||
APSR.Z = _IsZeroBit(alu_result_32);
|
||||
APSR.C = alu_carry_out;
|
||||
APSR.V = alu_overflow;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.213 SUB (register)
|
||||
uint ExecuteCore_SUB_register(Encoding encoding, bool setflags, uint m, uint n, uint d, SRType shift_t, int shift_n)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("SUB<s?><c>", "<{rd!~rn, }><rn!>, <rm!><{, shift}>", setflags, d, n, n, m, shift_t, shift_n);
|
||||
|
||||
uint shifted = _Shift(r[m], shift_t, shift_n, APSR.C);
|
||||
_AddWithCarry32(r[n], ~shifted, 1);
|
||||
if (d == 15)
|
||||
_ALUWritePC(alu_result_32);
|
||||
else
|
||||
{
|
||||
r[d] = alu_result_32;
|
||||
if (setflags)
|
||||
{
|
||||
APSR.N = _.BIT31(alu_result_32);
|
||||
APSR.Z = _IsZeroBit(alu_result_32);
|
||||
APSR.C = alu_carry_out;
|
||||
APSR.V = alu_overflow;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.215 SUB (SP minus immediate)
|
||||
uint ExecuteCore_SUB_SP_minus_immediate(Encoding encoding, uint d, bool setflags, uint imm32)
|
||||
{
|
||||
uint n = 13;
|
||||
if (disassemble)
|
||||
return DISNEW("SUB<s?><c>", "<{rd!~rn, }><rn!>, #<const>", setflags, d, n, n, imm32);
|
||||
|
||||
_AddWithCarry32(SP, ~imm32, 1);
|
||||
if (d == 15)
|
||||
_ALUWritePC(alu_result_32);
|
||||
else
|
||||
{
|
||||
r[d] = alu_result_32;
|
||||
if (setflags)
|
||||
{
|
||||
APSR.N = _.BIT31(alu_result_32);
|
||||
APSR.Z = _IsZeroBit(alu_result_32);
|
||||
APSR.C = alu_carry_out;
|
||||
APSR.V = alu_overflow;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.218 SVC (previously SWI)
|
||||
uint ExecuteCore_SVC(Encoding encoding, uint imm32)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("XXX", "<svc>", imm32);
|
||||
return sys.svc(imm32);
|
||||
}
|
||||
|
||||
//A8.6.263 UXTB
|
||||
uint ExecuteCore_UXTB(Encoding encoding, uint d, uint m, uint rotation)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("UXTB<c>", "<rd!>, <rm!><{, rotation}>", d, m, rotation);
|
||||
|
||||
rotation *= 8;
|
||||
uint rotated = _ROR(r[m], (int)rotation);
|
||||
r[d] = _ZeroExtend_32(rotated & 0xFF);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.265 UXTH
|
||||
uint ExecuteCore_UXTH(Encoding encoding, uint d, uint m, uint rotation)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("UXTH<c>", "<rd!>, <rm!><{, rotation}>", d, m, rotation);
|
||||
|
||||
rotation *= 8;
|
||||
uint rotated = _ROR(r[m], (int)rotation);
|
||||
r[d] = _ZeroExtend_32(rotated & 0xFFFF);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.336 VMSR
|
||||
uint ExecuteCore_VMSR(uint t)
|
||||
{
|
||||
_CheckVFPEnabled(true);
|
||||
_SerializeVFP();
|
||||
_VFPExcBarrier();
|
||||
FPSCR = r[t];
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//unnecessary opcodes: BKPT, BXJ, CBNZ, CHKA, NOP, CPY, DBG, ENTERX, HB, IT, LDRBT, LDRHT, LDRSBT, LDRSHT, LEAVEX, RBIT, SBFX, SDIV, TBB
|
||||
//likely unnecessary: CDP, SETEND, SEV
|
||||
//etc..
|
||||
|
||||
}
|
|
@ -0,0 +1,905 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace BizHawk.Emulation.CPUs.ARM
|
||||
{
|
||||
|
||||
partial class ARM
|
||||
{
|
||||
|
||||
uint ExecuteThumb()
|
||||
{
|
||||
uint opcode = instruction >> 10;
|
||||
_currentCondVal = 14;
|
||||
|
||||
//TODO - this one could really be turned into a table
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case _.b000000:
|
||||
case _.b000001:
|
||||
case _.b000010:
|
||||
case _.b000011:
|
||||
case _.b000100:
|
||||
case _.b000101:
|
||||
case _.b000110:
|
||||
case _.b000111:
|
||||
case _.b001000:
|
||||
case _.b001001:
|
||||
case _.b001010:
|
||||
case _.b001011:
|
||||
case _.b001100:
|
||||
case _.b001101:
|
||||
case _.b001110:
|
||||
case _.b001111:
|
||||
return ExecuteThumb_AluMisc();
|
||||
|
||||
case _.b010000: return ExecuteThumb_DataProcessing();
|
||||
case _.b010001: return ExecuteThumb_SpecialBX();
|
||||
|
||||
case _.b010010:
|
||||
case _.b010011:
|
||||
return ExecuteThumb_LdrLiteral_T1();
|
||||
|
||||
case _.b010100:
|
||||
case _.b010101:
|
||||
case _.b010110:
|
||||
case _.b010111:
|
||||
case _.b011000:
|
||||
case _.b011001:
|
||||
case _.b011010:
|
||||
case _.b011011:
|
||||
case _.b011100:
|
||||
case _.b011101:
|
||||
case _.b011110:
|
||||
case _.b011111:
|
||||
case _.b100000:
|
||||
case _.b100001:
|
||||
case _.b100010:
|
||||
case _.b100011:
|
||||
case _.b100100:
|
||||
case _.b100101:
|
||||
case _.b100110:
|
||||
case _.b100111:
|
||||
return ExecuteThumb_LoadStore();
|
||||
|
||||
case _.b101000:
|
||||
case _.b101001: return ExecuteThumb_ADR_T1();
|
||||
case _.b101010:
|
||||
case _.b101011: return Execute_ADD_SP_plus_immediate_T1();
|
||||
|
||||
case _.b101100:
|
||||
case _.b101101:
|
||||
case _.b101110:
|
||||
case _.b101111:
|
||||
return ExecuteThumb_Misc16();
|
||||
|
||||
case _.b110000:
|
||||
case _.b110001: return Execute_STM_STMIA_STMEA_T1();
|
||||
case _.b110010:
|
||||
case _.b110011: return Execute_LDM_LDMIA_LDMFD_T1();
|
||||
|
||||
case _.b110100:
|
||||
case _.b110101:
|
||||
case _.b110110:
|
||||
case _.b110111:
|
||||
return ExecuteThumb_CondBr_And_SVC();
|
||||
|
||||
case _.b111000:
|
||||
case _.b111001: return Execute_B_T2();
|
||||
|
||||
case _.b111010:
|
||||
case _.b111011:
|
||||
case _.b111100:
|
||||
case _.b111101:
|
||||
case _.b111110:
|
||||
case _.b111111:
|
||||
return ExecuteThumb_32();
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException("unhandled case in ExecuteThumb");
|
||||
}
|
||||
}
|
||||
|
||||
uint ExecuteThumb_LdrLiteral_T1()
|
||||
{
|
||||
//A8.6.59
|
||||
//A8-122
|
||||
uint t = Reg8(8);
|
||||
uint imm8 = instruction & 0xFF;
|
||||
uint imm32 = imm8 << 2;
|
||||
bool add = true;
|
||||
|
||||
return ExecuteCore_LDR_literal(Encoding.T1, t, imm32, add);
|
||||
}
|
||||
|
||||
uint ExecuteThumb_LoadStore()
|
||||
{
|
||||
//A6.2.4
|
||||
uint opA = (instruction >> 12) & 0xF;
|
||||
uint opB = (instruction >> 9) & 0x7;
|
||||
switch (opA)
|
||||
{
|
||||
case _.b0101:
|
||||
switch (opB)
|
||||
{
|
||||
case _.b000: return Execute_Unhandled("STR (register) on page A8-386");
|
||||
case _.b001: return Execute_Unhandled("STRH (register) on page A8-412");
|
||||
case _.b010: return Execute_STRB_register_T1();
|
||||
case _.b011: return Execute_Unhandled("LDRSB (register) on page A8-164");
|
||||
case _.b100: return Execute_Unhandled("LDR (register) on page A8-124");
|
||||
case _.b101: return Execute_Unhandled("LDRH (register)");
|
||||
case _.b110: return Execute_LDRB_register_T1();
|
||||
case _.b111: return Execute_Unhandled("LDRSH (register) on page A8-172");
|
||||
default: throw new InvalidOperationException("decoder fail");
|
||||
}
|
||||
case _.b0110:
|
||||
switch (opB)
|
||||
{
|
||||
case _.b000:
|
||||
case _.b001:
|
||||
case _.b010:
|
||||
case _.b011: return Execute_STR_immediate_thumb_T1();
|
||||
case _.b100:
|
||||
case _.b101:
|
||||
case _.b110:
|
||||
case _.b111: return Execute_LDR_immediate_thumb_T1();
|
||||
default: throw new InvalidOperationException("decoder fail");
|
||||
}
|
||||
case _.b0111:
|
||||
switch (opB)
|
||||
{
|
||||
case _.b000:
|
||||
case _.b001:
|
||||
case _.b010:
|
||||
case _.b011: return Execute_STRB_immediate_thumb_T1();
|
||||
case _.b100:
|
||||
case _.b101:
|
||||
case _.b110:
|
||||
case _.b111: return Execute_LDRB_immediate_thumb_T1();
|
||||
default: throw new InvalidOperationException("decoder fail");
|
||||
}
|
||||
case _.b1000:
|
||||
switch (opB)
|
||||
{
|
||||
case _.b000:
|
||||
case _.b001:
|
||||
case _.b010:
|
||||
case _.b011: return Execute_STRH_immediate_thumb_T1();
|
||||
case _.b100:
|
||||
case _.b101:
|
||||
case _.b110:
|
||||
case _.b111: return Execute_LDRH_immediate_thumb_T1();
|
||||
default: throw new InvalidOperationException("decoder fail");
|
||||
}
|
||||
case _.b1001:
|
||||
switch (opB)
|
||||
{
|
||||
case _.b000:
|
||||
case _.b001:
|
||||
case _.b010:
|
||||
case _.b011: return Execute_STR_immediate_thumb_T2();
|
||||
case _.b100:
|
||||
case _.b101:
|
||||
case _.b110:
|
||||
case _.b111: return Execute_LDR_immediate_thumb_T2();
|
||||
default: throw new InvalidOperationException("decoder fail");
|
||||
}
|
||||
default: throw new InvalidOperationException("decoder fail");
|
||||
} //switch(opA)
|
||||
}
|
||||
|
||||
uint Execute_STRB_register_T1()
|
||||
{
|
||||
//A8.6.198
|
||||
uint t = Reg8(0);
|
||||
uint n = Reg8(3);
|
||||
uint m = Reg8(6);
|
||||
const bool index = true; const bool add = true; const bool wback = false;
|
||||
const SRType shift_t = SRType.LSL;
|
||||
const int shift_n = 0;
|
||||
return ExecuteCore_STRB_register(Encoding.T1, t, n, m, shift_t, shift_n, index, add, wback);
|
||||
}
|
||||
|
||||
uint Execute_LDRB_register_T1()
|
||||
{
|
||||
//A8.6.64
|
||||
uint t = Reg8(0);
|
||||
uint n = Reg8(3);
|
||||
uint m = Reg8(6);
|
||||
const bool index = true; const bool add = true; const bool wback = false;
|
||||
const SRType shift_t = SRType.LSL;
|
||||
const int shift_n = 0;
|
||||
return ExecuteCore_LDRB_register(Encoding.T1, t, n, m, shift_t, shift_n, index, add, wback);
|
||||
}
|
||||
|
||||
uint Execute_LDRB_immediate_thumb_T1()
|
||||
{
|
||||
//A8.6.61
|
||||
uint t = Reg8(0);
|
||||
uint n = Reg8(3);
|
||||
uint imm5 = (instruction >> 6) & 0x1F;
|
||||
uint imm32 = _ZeroExtend_32(imm5);
|
||||
const bool index = true; const bool add = true; const bool wback = false;
|
||||
return ExecuteCore_LDRB_immediate_thumb(Encoding.T1, t, n, imm32, index, add, wback);
|
||||
}
|
||||
|
||||
uint Execute_STRB_immediate_thumb_T1()
|
||||
{
|
||||
//A8.6.196
|
||||
uint t = Reg8(0);
|
||||
uint n = Reg8(3);
|
||||
uint imm5 = (instruction >> 6) & 0x1F;
|
||||
uint imm32 = _ZeroExtend_32(imm5);
|
||||
const bool index = true; const bool add = true; const bool wback = false;
|
||||
return ExecuteCore_STRB_immediate_thumb(Encoding.T1, t, n, imm32, index, add, wback);
|
||||
}
|
||||
|
||||
uint Execute_LDRH_immediate_thumb_T1()
|
||||
{
|
||||
//A8.6.73
|
||||
uint t = Reg8(0);
|
||||
uint n = Reg8(3);
|
||||
uint imm5 = (instruction >> 6) & 0x1F;
|
||||
uint imm32 = _ZeroExtend_32(imm5 << 1);
|
||||
const bool index = true; const bool add = true; const bool wback = false;
|
||||
return ExecuteCore_LDRH_immediate_thumb(Encoding.T1, t, n, imm32, index, add, wback);
|
||||
}
|
||||
|
||||
uint Execute_STRH_immediate_thumb_T1()
|
||||
{
|
||||
//A8.6.206 STRH
|
||||
uint t = Reg8(0);
|
||||
uint n = Reg8(3);
|
||||
uint imm5 = (instruction >> 6) & 0x1F;
|
||||
uint imm32 = _ZeroExtend_32(imm5 << 1);
|
||||
const bool index = true; const bool add = true; const bool wback = false;
|
||||
return ExecuteCore_STRH_immediate_thumb(Encoding.T1, t, n, imm32, index, add, wback);
|
||||
}
|
||||
|
||||
uint Execute_LDR_immediate_thumb_T1()
|
||||
{
|
||||
//A8.6.57 LDR (immediate,thumb)
|
||||
uint t = Reg8(0);
|
||||
uint n = Reg8(3);
|
||||
uint imm5 = (instruction >> 6) & 0x1F;
|
||||
uint imm32 = _ZeroExtend_32(imm5 << 2);
|
||||
bool index = true; bool add = true; bool wback = false;
|
||||
return ExecuteCore_LDR_immediate_thumb(Encoding.T1, t, imm32, n, index, add, wback);
|
||||
}
|
||||
|
||||
uint Execute_STR_immediate_thumb_T1()
|
||||
{
|
||||
//A8.6.193 STR (immediate,thumb)
|
||||
uint t = Reg8(0);
|
||||
uint n = Reg8(3);
|
||||
uint imm5 = (instruction >> 6) & 0x1F;
|
||||
uint imm32 = _ZeroExtend_32(imm5 << 2);
|
||||
bool index = true; bool add = true; bool wback = false;
|
||||
return ExecuteCore_STR_immediate_thumb(Encoding.T1, t, imm32, n, index, add, wback);
|
||||
}
|
||||
|
||||
uint Execute_LDR_immediate_thumb_T2()
|
||||
{
|
||||
//A8.6.57 LDR (immediate, thumb)
|
||||
uint t = Reg8(8);
|
||||
uint imm8 = instruction & 0xFF;
|
||||
const uint n = 13;
|
||||
uint imm32 = _ZeroExtend_32(imm8 << 2);
|
||||
const bool index = true; const bool add = true; const bool wback = false;
|
||||
return ExecuteCore_LDR_immediate_thumb(Encoding.T2, t, imm32, n, index, add, wback);
|
||||
}
|
||||
|
||||
uint Execute_STR_immediate_thumb_T2()
|
||||
{
|
||||
//A8.6.193 STR (immediate,thumb)
|
||||
uint Rt = Reg8(8);
|
||||
uint imm8 = instruction & 0xFF;
|
||||
const uint n = 13;
|
||||
uint imm32 = _ZeroExtend_32(imm8 << 2);
|
||||
const bool index = true; const bool add = true; const bool wback = false;
|
||||
return ExecuteCore_STR_immediate_thumb(Encoding.T2, Rt, imm32, n, index, add, wback);
|
||||
}
|
||||
|
||||
uint ExecuteThumb_32()
|
||||
{
|
||||
uint op1 = (instruction >> 11) & 3;
|
||||
uint op2 = (instruction >> 4) & 0x7F;
|
||||
ThumbFetchExtra();
|
||||
uint op = _.BIT15(thumb_32bit_extra);
|
||||
switch (op1)
|
||||
{
|
||||
case _.b00: throw new InvalidOperationException("decode error");
|
||||
case _.b01: return Execute_Unhandled("thumb-32bit");
|
||||
case _.b10:
|
||||
if (op == 0) return Execute_Unhandled("thumb-32bit");
|
||||
else return ExecuteThumb_32_BranchAndMiscControl(op2);
|
||||
case _.b11:
|
||||
return Execute_Unhandled("thumb-32bit");
|
||||
default: throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
uint ExecuteThumb_32_BranchAndMiscControl(uint op)
|
||||
{
|
||||
uint op1 = (thumb_32bit_extra >> 12) & 7;
|
||||
switch (op1)
|
||||
{
|
||||
case _.b000:
|
||||
case _.b010:
|
||||
return Execute_Unhandled("thumb-32bit");
|
||||
case _.b001:
|
||||
case _.b011: return Execute_Unhandled("thumb-32bit 6T2 branch");
|
||||
case _.b100:
|
||||
case _.b110: return ExecuteThumb_BL_BLX_immediate_T2();
|
||||
case _.b101:
|
||||
case _.b111: return ExecuteThumb_BL_BLX_immediate_T1();
|
||||
default: throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
uint ExecuteThumb_BL_BLX_immediate_T1()
|
||||
{
|
||||
//A8.6.23
|
||||
//A8-58
|
||||
//(BL)
|
||||
uint S = _.BIT10(instruction);
|
||||
uint J1 = _.BIT13(thumb_32bit_extra);
|
||||
uint J2 = _.BIT11(thumb_32bit_extra);
|
||||
uint imm11 = thumb_32bit_extra & _.b11111111111;
|
||||
uint imm10 = instruction & _.b1111111111;
|
||||
uint I1 = (~(J1 ^ S)) & 1;
|
||||
uint I2 = (~(J2 ^ S)) & 1;
|
||||
int imm32 = _SignExtend_32(25, (imm11 << 1) | (imm10 << 12) | (I2 << 22) | (I1 << 23) | (S << 24));
|
||||
if (_InITBlock() && !_LastInITBlock()) _UNPREDICTABLE();
|
||||
return ExecuteCore_BL_BLX_immediate(Encoding.T1, _CurrentInstrSet(), imm32, false);
|
||||
}
|
||||
|
||||
uint ExecuteThumb_BL_BLX_immediate_T2()
|
||||
{
|
||||
//A8.6.23
|
||||
//A8-58
|
||||
//(BLX)
|
||||
uint S = _.BIT10(instruction);
|
||||
uint J1 = _.BIT13(thumb_32bit_extra);
|
||||
uint J2 = _.BIT11(thumb_32bit_extra);
|
||||
uint H = _.BIT0(thumb_32bit_extra);
|
||||
uint imm10L = (thumb_32bit_extra >> 1) & 0x3FF;
|
||||
uint imm10H = instruction & 0x3FF;
|
||||
uint I1 = (~(J1 ^ S)) & 1;
|
||||
uint I2 = (~(J2 ^ S)) & 1;
|
||||
int imm32 = _SignExtend_32(25, (imm10L << 2) | (imm10H << 12) | (I2 << 22) | (I1 << 23) | (S << 24));
|
||||
return ExecuteCore_BL_BLX_immediate(Encoding.T2, EInstrSet.ARM, imm32, true);
|
||||
}
|
||||
|
||||
uint ExecuteThumb_AluMisc()
|
||||
{
|
||||
//A6.2.1
|
||||
uint opcode = (instruction >> 9) & 0x1F;
|
||||
switch (opcode)
|
||||
{
|
||||
case _.b00000:
|
||||
case _.b00001:
|
||||
case _.b00010:
|
||||
case _.b00011:
|
||||
return Execute_LSL_immediate_T1();
|
||||
case _.b00100:
|
||||
case _.b00101:
|
||||
case _.b00110:
|
||||
case _.b00111:
|
||||
return Execute_LSR_immediate_T1();
|
||||
case _.b01000:
|
||||
case _.b01001:
|
||||
case _.b01010:
|
||||
case _.b01011:
|
||||
return Execute_ASR_immediate_T1();
|
||||
case _.b01100: return Execute_ADD_Register_T1();
|
||||
case _.b01101: return Execute_SUB_Register_T1();
|
||||
case _.b01110: return Execute_ADD_immediate_thumb_T1();
|
||||
case _.b01111: return Execute_SUB_immediate_thumb_T1();
|
||||
case _.b10000:
|
||||
case _.b10001:
|
||||
case _.b10010:
|
||||
case _.b10011:
|
||||
return Execute_MOV_immediate_T1();
|
||||
case _.b10100:
|
||||
case _.b10101:
|
||||
case _.b10110:
|
||||
case _.b10111:
|
||||
return Execute_CMP_immediate_T1();
|
||||
case _.b11000:
|
||||
case _.b11001:
|
||||
case _.b11010:
|
||||
case _.b11011:
|
||||
return Execute_ADD_immediate_thumb_T2();
|
||||
case _.b11100:
|
||||
case _.b11101:
|
||||
case _.b11110:
|
||||
case _.b11111:
|
||||
return Execute_SUB_immediate_thumb_T2();
|
||||
}
|
||||
return Execute_Unhandled("ExecuteThumb_AluMisc");
|
||||
}
|
||||
|
||||
uint Execute_CMP_immediate_T1()
|
||||
{
|
||||
//A8.6.35 CMP immediate
|
||||
//A8-80
|
||||
uint n = Reg8(8);
|
||||
uint imm8 = instruction & 0xFF;
|
||||
uint imm32 = _ZeroExtend_32(imm8);
|
||||
return ExecuteCore_CMP_immediate(Encoding.T1, n, imm32);
|
||||
}
|
||||
|
||||
uint Execute_MOV_immediate_T1()
|
||||
{
|
||||
//A8.6.96 MOV immediate
|
||||
uint d = Reg8(8);
|
||||
uint imm8 = instruction & 0xFF;
|
||||
bool setflags = !_InITBlock();
|
||||
uint imm32 = _ZeroExtend_32(imm8);
|
||||
Bit carry = APSR.C;
|
||||
return ExecuteCore_MOV_immediate(Encoding.T1, d, setflags, imm32, carry);
|
||||
}
|
||||
|
||||
uint Execute_SUB_Register_T1()
|
||||
{
|
||||
//A8.6.213 SUB (register)
|
||||
uint d = Reg8(0);
|
||||
uint n = Reg8(3);
|
||||
uint m = Reg8(6);
|
||||
bool setflags = !_InITBlock();
|
||||
const SRType shift_t = SRType.LSL;
|
||||
const int shift_n = 0;
|
||||
return ExecuteCore_SUB_register(Encoding.T1, setflags, m, n, d, shift_t, shift_n);
|
||||
}
|
||||
|
||||
uint Execute_ADD_Register_T1()
|
||||
{
|
||||
//A8.6.6 ADD (register)
|
||||
uint d = Reg8(0);
|
||||
uint n = Reg8(3);
|
||||
uint m = Reg8(6);
|
||||
bool setflags = !_InITBlock();
|
||||
const SRType shift_t = SRType.LSL;
|
||||
const int shift_n = 0;
|
||||
return ExecuteCore_ADD_register(Encoding.T1, m, d, n, setflags, shift_t, shift_n);
|
||||
}
|
||||
|
||||
uint Execute_ADD_register_T2()
|
||||
{
|
||||
//A8.6.6 ADD (register)
|
||||
Bit DN = _.BIT7(instruction);
|
||||
uint rdn = Reg8(0);
|
||||
uint m = Reg16(3);
|
||||
Debug.Assert(!(DN == 1 && rdn == _.b101 || m == _.b1101), "see ADD (SP plus register)");
|
||||
uint d = rdn;
|
||||
uint n = rdn;
|
||||
bool setflags = false;
|
||||
const SRType shift_t = SRType.LSL;
|
||||
const int shift_n = 0;
|
||||
if (n == 15 && m == 15) _FlagUnpredictable();
|
||||
if (d == 15 && _InITBlock() && !_LastInITBlock()) _FlagUnpredictable();
|
||||
return ExecuteCore_ADD_register(Encoding.T2, m, d, n, setflags, shift_t, shift_n);
|
||||
}
|
||||
|
||||
uint Execute_SUB_immediate_thumb_T1()
|
||||
{
|
||||
//A7.6.211
|
||||
uint d = Reg8(0);
|
||||
uint n = Reg8(3);
|
||||
uint imm3 = (instruction >> 6) & 7;
|
||||
bool setflags = !_InITBlock();
|
||||
uint imm32 = _ZeroExtend_32(imm3);
|
||||
return ExecuteCore_SUB_immediate_thumb(Encoding.T1, n, d, setflags, imm32);
|
||||
}
|
||||
|
||||
uint Execute_ADD_immediate_thumb_T1()
|
||||
{
|
||||
uint d = Reg8(0);
|
||||
uint n = Reg8(3);
|
||||
uint imm3 = (instruction >> 6) & 7;
|
||||
bool setflags = !_InITBlock();
|
||||
uint imm32 = _ZeroExtend_32(imm3);
|
||||
return ExecuteCore_ADD_immediate_thumb(Encoding.T1, n, d, setflags, imm32);
|
||||
}
|
||||
|
||||
uint Execute_SUB_immediate_thumb_T2()
|
||||
{
|
||||
//A8.6.211
|
||||
uint d = Reg8(8);
|
||||
uint n = d;
|
||||
bool setflags = !_InITBlock();
|
||||
uint imm8 = (instruction & 0xFF);
|
||||
uint imm32 = _ZeroExtend_32(imm8);
|
||||
return ExecuteCore_SUB_immediate_thumb(Encoding.T2, n, d, setflags, imm32);
|
||||
}
|
||||
|
||||
uint Execute_ADD_immediate_thumb_T2()
|
||||
{
|
||||
uint Rdn = Reg8(8);
|
||||
uint imm8 = instruction & _.b11111111;
|
||||
uint d = Rdn;
|
||||
uint n = Rdn;
|
||||
bool setflags = !_InITBlock();
|
||||
uint imm32 = imm8;
|
||||
return ExecuteCore_ADD_immediate_thumb(Encoding.T2, n, d, setflags, imm32);
|
||||
}
|
||||
|
||||
uint Execute_LSL_immediate_T1()
|
||||
{
|
||||
//A8.6.14
|
||||
uint imm5 = (instruction >> 6) & 0x1F;
|
||||
if (imm5 == 0 && procopt.Thumb_LSL_immediate_T1_0_is_MOV_register_T2) return Execute_MOV_register_T2();
|
||||
|
||||
uint d = Reg8(0);
|
||||
uint m = Reg8(3);
|
||||
bool setflags = !_InITBlock();
|
||||
_DecodeImmShift(0, imm5);
|
||||
|
||||
return ExecuteCore_LSL_immediate(Encoding.T1, d, m, setflags, shift_n);
|
||||
}
|
||||
|
||||
uint Execute_ASR_immediate_T1()
|
||||
{
|
||||
//A8.6.14 ASR (immediate)
|
||||
uint d = Reg8(0);
|
||||
uint m = Reg8(3);
|
||||
uint imm5 = (instruction >> 6) & 0x1F;
|
||||
bool setflags = !_InITBlock();
|
||||
_DecodeImmShift(_.b10, imm5);
|
||||
|
||||
return ExecuteCore_ASR_immediate(Encoding.T1, d, m, setflags, shift_n);
|
||||
}
|
||||
|
||||
uint Execute_LSR_immediate_T1()
|
||||
{
|
||||
uint imm5 = (instruction >> 6) & 0x1F;
|
||||
uint m = Reg8(3);
|
||||
uint d = Reg8(0);
|
||||
bool setflags = !_InITBlock();
|
||||
_DecodeImmShift(_.b01, imm5);
|
||||
return ExecuteCore_LSR_immediate(Encoding.T1, d, m, setflags, shift_n);
|
||||
}
|
||||
|
||||
uint Execute_MOV_register_T1()
|
||||
{
|
||||
//A8.6.97 MOV (register)
|
||||
uint D = _.BIT7(instruction);
|
||||
uint d = Reg8(0) + 8 * D;
|
||||
uint m = Reg16(3);
|
||||
bool setflags = false;
|
||||
if (d == 15 && _InITBlock() && !_LastInITBlock()) unpredictable = true;
|
||||
|
||||
//my own sanity check:
|
||||
if (m >= 8 && _ArchVersion() < 6) throw new InvalidOperationException("thumb mov register invalid for your architecture version. need to think about this.");
|
||||
|
||||
return ExecuteCore_MOV_register(Encoding.T1, d, m, setflags);
|
||||
}
|
||||
|
||||
uint Execute_MOV_register_T2()
|
||||
{
|
||||
uint D = _.BIT7(instruction);
|
||||
uint d = Reg8(0);
|
||||
uint m = Reg8(3);
|
||||
bool setflags = true;
|
||||
|
||||
if (_InITBlock()) unpredictable = true;
|
||||
|
||||
return ExecuteCore_MOV_register(Encoding.T2, d, m, setflags);
|
||||
}
|
||||
|
||||
uint ExecuteThumb_DataProcessing()
|
||||
{
|
||||
//A6.2.2
|
||||
uint opcode = (instruction >> 6) & 0xF;
|
||||
switch (opcode)
|
||||
{
|
||||
case _.b0000: return Execute_Unhandled("thumb AND reg");
|
||||
case _.b0001: return Execute_EOR_register_T1();
|
||||
case _.b0010: return Execute_Unhandled("thumb LSL reg");
|
||||
case _.b0011: return Execute_Unhandled("thumb LSR reg");
|
||||
case _.b0100: return Execute_Unhandled("thumb ASR reg");
|
||||
case _.b0101: return Execute_Unhandled("thumb ADC reg");
|
||||
case _.b0110: return Execute_Unhandled("thumb SBC reg");
|
||||
case _.b0111: return Execute_Unhandled("thumb ROR reg");
|
||||
case _.b1000: return Execute_Unhandled("thumb TST reg");
|
||||
case _.b1001: return Execute_RSB_immediate_T1();
|
||||
case _.b1010: return Execute_CMP_register_T1();
|
||||
case _.b1011: return Execute_Unhandled("thumb CMN reg");
|
||||
case _.b1100: return Execute_ORR_register_T1();
|
||||
case _.b1101: return Execute_Unhandled("thumb MUL");
|
||||
case _.b1110: return Execute_Unhandled("thumb BIC reg");
|
||||
case _.b1111: return Execute_Unhandled("thumb MVN reg");
|
||||
default: throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
uint Execute_RSB_immediate_T1()
|
||||
{
|
||||
//A8.6.142
|
||||
uint d = Reg8(0);
|
||||
uint n = Reg8(3);
|
||||
bool setflags = !_InITBlock();
|
||||
uint imm32 = 0;
|
||||
return ExecuteCore_RSB_immediate(Encoding.T1, d, n, setflags, imm32);
|
||||
}
|
||||
|
||||
uint Execute_EOR_register_T1()
|
||||
{
|
||||
//A8.6.45
|
||||
uint d = Reg8(0);
|
||||
uint n = d;
|
||||
uint m = Reg8(3);
|
||||
bool setflags = !_InITBlock();
|
||||
const SRType shift_t = SRType.LSL;
|
||||
const int shift_n = 0;
|
||||
return ExecuteCore_EOR_register(Encoding.T1, m, d, n, setflags, shift_t, shift_n);
|
||||
}
|
||||
|
||||
uint Execute_ORR_register_T1()
|
||||
{
|
||||
//A7.6.114
|
||||
uint d = Reg8(0);
|
||||
uint n = d;
|
||||
uint m = Reg8(3);
|
||||
bool setflags = !_InITBlock();
|
||||
const SRType shift_t = SRType.LSL;
|
||||
const int shift_n = 0;
|
||||
return ExecuteCore_ORR_register(Encoding.T1, m, d, n, setflags, shift_t, shift_n);
|
||||
}
|
||||
|
||||
uint Execute_CMP_register_T1()
|
||||
{
|
||||
//A8.6.36
|
||||
uint n = Reg8(0);
|
||||
uint m = Reg8(3);
|
||||
SRType shift_t = SRType.LSL;
|
||||
int shift_n = 0;
|
||||
return ExecuteCore_CMP_register(Encoding.T1, n, m, shift_t, shift_n);
|
||||
}
|
||||
|
||||
uint ExecuteThumb_SpecialBX()
|
||||
{
|
||||
uint opcode = (instruction >> 6) & _.b1111;
|
||||
switch (opcode)
|
||||
{
|
||||
case _.b0000:
|
||||
return Execute_Unhandled("ADD (low register) on page A8-24 [v6T2*] *unpredictable in earlier variants");
|
||||
case _.b0001:
|
||||
case _.b0010:
|
||||
case _.b0011:
|
||||
return Execute_ADD_register_T2();
|
||||
case _.b0100:
|
||||
return _UNPREDICTABLE();
|
||||
case _.b0101:
|
||||
case _.b0110:
|
||||
case _.b0111:
|
||||
return Execute_Unhandled("CMP (high register) on page A8-82 [v4t]");
|
||||
case _.b1000:
|
||||
return Execute_MOV_register_T1();
|
||||
case _.b1001:
|
||||
case _.b1010:
|
||||
case _.b1011:
|
||||
return Execute_MOV_register_T1();
|
||||
case _.b1100:
|
||||
case _.b1101:
|
||||
return Execute_BX_T1();
|
||||
case _.b1110:
|
||||
case _.b1111:
|
||||
return Execute_BLX_register_T1();
|
||||
default: throw new InvalidOperationException("decode fail");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
uint Execute_BLX_register_T1()
|
||||
{
|
||||
//A8.6.24
|
||||
uint m = Reg16(3);
|
||||
if (m == 15) _FlagUnpredictable();
|
||||
if (_InITBlock() && !_LastInITBlock()) _FlagUnpredictable();
|
||||
return ExecuteCore_BLX_register(Encoding.T1, m);
|
||||
}
|
||||
|
||||
uint Execute_BX_T1()
|
||||
{
|
||||
//A8.6.25
|
||||
uint m = Reg16(3);
|
||||
if (_InITBlock() && !_LastInITBlock()) return _UNPREDICTABLE();
|
||||
if (disassemble)
|
||||
return DISNEW("BX", "<Rm!>", m);
|
||||
_BXWritePC(r[m]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint ExecuteThumb_ADR_T1()
|
||||
{
|
||||
//A8.6.10 ADR
|
||||
uint d = Reg8(8);
|
||||
uint imm8 = instruction & 0xFF;
|
||||
uint imm32 = _ZeroExtend_32(imm8 << 2);
|
||||
const bool add = true;
|
||||
return ExecuteCore_ADR(Encoding.T1, d, imm32, add);
|
||||
}
|
||||
|
||||
uint Execute_ADD_SP_plus_immediate_T2()
|
||||
{
|
||||
//A8.6.8 ADD SP plus immediate
|
||||
uint d = 13;
|
||||
uint imm7 = (instruction & 0xFF);
|
||||
bool setflags = false;
|
||||
uint imm32 = _ZeroExtend_32(imm7 << 2);
|
||||
return ExecuteCore_ADD_SP_plus_immedate(Encoding.T2, d, setflags, imm32);
|
||||
}
|
||||
|
||||
uint Execute_ADD_SP_plus_immediate_T1()
|
||||
{
|
||||
//A8.6.8 ADD SP plus immediate
|
||||
//A8-28
|
||||
uint d = Reg8(8);
|
||||
uint imm8 = (instruction & 0xFF);
|
||||
bool setflags = false;
|
||||
uint imm32 = _ZeroExtend_32(imm8 << 2);
|
||||
return ExecuteCore_ADD_SP_plus_immedate(Encoding.T1, d, setflags, imm32);
|
||||
}
|
||||
|
||||
Decoder decoder_ExecuteThumb_Misc16 = new Decoder();
|
||||
uint ExecuteThumb_Misc16()
|
||||
{
|
||||
decoder_ExecuteThumb_Misc16.Ensure(() => decoder_ExecuteThumb_Misc16
|
||||
.d("opcode", 7)
|
||||
.r("opcode == #0110010", () => Execute_Unhandled("SETEND on page A8-314"))
|
||||
.r("opcode == #0110011", () => Execute_Unhandled("CPS on page B6-3"))
|
||||
.r("opcode == #00000xx", () => Execute_ADD_SP_plus_immediate_T2())
|
||||
.r("opcode == #00001xx", () => Execute_SUB_SP_minus_immediate_T1())
|
||||
.r("opcode == #0001xxx", () => Execute_Unhandled("CBNZ,CBZ on page A8-66 [v6T2]"))
|
||||
.r("opcode == #001000x", () => Execute_Unhandled("SXTH on page A8-444"))
|
||||
.r("opcode == #001001x", () => Execute_Unhandled("SXTB on page A8-440"))
|
||||
.r("opcode == #001010x", () => Execute_UXTH_T1())
|
||||
.r("opcode == #001011x", () => Execute_UXTB_T1())
|
||||
.r("opcode == #0011xxx", () => Execute_Unhandled("CBNZ,CBZ on page A8-66 [v6T2]"))
|
||||
.r("opcode == #010xxxx", () => Execute_PUSH_T1())
|
||||
.r("opcode == #1001xxx", () => Execute_Unhandled("CBNZ,CBZ on page A8-66 [v6T2]"))
|
||||
.r("opcode == #101000x", () => Execute_Unhandled("REV on page A8-272"))
|
||||
.r("opcode == #101001x", () => Execute_Unhandled("REV16 on page A8-274"))
|
||||
.r("opcode == #101011x", () => Execute_Unhandled("REVSH on page A8-276"))
|
||||
.r("opcode == #110xxxx", () => Execute_POP_T1())
|
||||
.r("opcode == #1110xxx", () => Execute_Unhandled("BKPT on page A8-56"))
|
||||
.r("opcode == #1111xxx", () => Execute_Unhandled("If-Then and hints on page A6-12"))
|
||||
);
|
||||
|
||||
uint opcode = (instruction >> 5) & 0x7F;
|
||||
decoder_ExecuteThumb_Misc16.Evaluate(opcode);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint Execute_POP_T1()
|
||||
{
|
||||
//A8.6.122
|
||||
uint P = _.BIT8(instruction);
|
||||
uint registers = (P << 15) | (instruction & 0xFF);
|
||||
bool UnalignedAllowed = false;
|
||||
if (registers == 0) { _UNPREDICTABLE(); return 1; }
|
||||
if (P == 1 && _InITBlock() && !_LastInITBlock()) { _UNPREDICTABLE(); return 1; }
|
||||
if (disassemble)
|
||||
return DISNEW("pop<c>", "<registers>", registers);
|
||||
return ExecuteCore_POP(Encoding.T1, registers, UnalignedAllowed);
|
||||
}
|
||||
|
||||
uint Execute_SUB_SP_minus_immediate_T1()
|
||||
{
|
||||
//A8.6.215 SUB (SP minus immediate)
|
||||
const uint d = 13;
|
||||
uint imm7 = instruction & 0x7F;
|
||||
bool setflags = false;
|
||||
uint imm32 = _ZeroExtend_32(imm7 << 2);
|
||||
return ExecuteCore_SUB_SP_minus_immediate(Encoding.T1, d, setflags, imm32);
|
||||
}
|
||||
|
||||
uint Execute_UXTH_T1()
|
||||
{
|
||||
//A8.6.265
|
||||
uint d = Reg8(0);
|
||||
uint m = Reg8(3);
|
||||
const uint rotation = 0;
|
||||
return ExecuteCore_UXTH(Encoding.T1, d, m, rotation);
|
||||
}
|
||||
|
||||
uint Execute_UXTB_T1()
|
||||
{
|
||||
//A8.6.263
|
||||
uint d = Reg8(0);
|
||||
uint m = Reg8(3);
|
||||
const uint rotation = 0;
|
||||
return ExecuteCore_UXTB(Encoding.T1, d, m, rotation);
|
||||
}
|
||||
|
||||
uint Execute_PUSH_T1()
|
||||
{
|
||||
//A8.6.123
|
||||
uint M = _.BIT8(instruction);
|
||||
uint regs = (M << 14) | (instruction & 0xFF);
|
||||
if (_.BitCount(regs) < 1) unpredictable = true;
|
||||
|
||||
return ExecuteCore_PUSH(Encoding.T1, regs, false);
|
||||
}
|
||||
|
||||
uint Execute_LDM_LDMIA_LDMFD_T1()
|
||||
{
|
||||
//A8.6.53 LDM/LDMIA/LDMFD
|
||||
if (_CurrentInstrSet() == EInstrSet.THUMBEE) throw new NotImplementedException();
|
||||
uint n = Reg8(8);
|
||||
uint registers = instruction & 0xFF;
|
||||
bool wback = (_.BITN((int)n, registers) == 0);
|
||||
if (registers == 0) _FlagUnpredictable();
|
||||
return ExecuteCore_LDM_LDMIA_LDMFD(Encoding.T1, wback, n, registers);
|
||||
}
|
||||
|
||||
uint Execute_STM_STMIA_STMEA_T1()
|
||||
{
|
||||
//A8.6.189 STM/STMIA/STMEA
|
||||
if (_CurrentInstrSet() == EInstrSet.THUMBEE) throw new NotImplementedException();
|
||||
uint n = Reg8(8);
|
||||
uint registers = instruction & 0xFF;
|
||||
bool wback = true;
|
||||
if (registers == 0) unpredictable = true;
|
||||
return ExecuteCore_STM_STMIA_STMEA(Encoding.T1, wback, n, registers);
|
||||
}
|
||||
|
||||
uint ExecuteThumb_LDM() { return Execute_Unhandled("ExecuteThumb_LDM"); }
|
||||
uint ExecuteThumb_CondBr_And_SVC()
|
||||
{
|
||||
uint opcode = (instruction >> 8) & 0xF;
|
||||
switch (opcode)
|
||||
{
|
||||
case _.b0000:
|
||||
case _.b0001:
|
||||
case _.b0010:
|
||||
case _.b0011:
|
||||
case _.b0100:
|
||||
case _.b0101:
|
||||
case _.b0110:
|
||||
case _.b0111:
|
||||
case _.b1000:
|
||||
case _.b1001:
|
||||
case _.b1010:
|
||||
case _.b1011:
|
||||
case _.b1100:
|
||||
case _.b1101:
|
||||
return Execute_B_T1();
|
||||
|
||||
case _.b1110: return _PERMANENTLY_UNDEFINED();
|
||||
case _.b1111: return Execute_SVC_T1();
|
||||
|
||||
default: throw new InvalidOperationException("decode fail");
|
||||
}
|
||||
}
|
||||
uint ExecuteThumb_UnCondBr() { return Execute_Unhandled("ExecuteThumb_UnCondBr"); }
|
||||
|
||||
uint Execute_B_T2()
|
||||
{
|
||||
//A8.6.16 B
|
||||
uint imm11 = instruction & 0x7FF;
|
||||
int imm32 = _SignExtend_32(11, imm11 << 1);
|
||||
if (_InITBlock() && !_LastInITBlock()) unpredictable = true;
|
||||
return ExecuteCore_B(Encoding.T2, imm32);
|
||||
}
|
||||
|
||||
uint Execute_B_T1()
|
||||
{
|
||||
//A8.6.16 B
|
||||
uint imm8 = (instruction & 0xFF);
|
||||
int imm32 = _SignExtend_32(9, imm8 << 1);
|
||||
_currentCondVal = (instruction >> 8) & 0xF;
|
||||
if (_InITBlock()) return _UNPREDICTABLE();
|
||||
return ExecuteCore_B(Encoding.T1, imm32);
|
||||
}
|
||||
|
||||
uint Execute_SVC_T1()
|
||||
{
|
||||
return Execute_Unhandled("Execute_SVC_T1");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,460 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BizHawk.Emulation.CPUs.ARM
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// this file contains functions transcribed as closely as possible from arm's docs. theyre all _Prefixed
|
||||
/// </summary>
|
||||
partial class ARM
|
||||
{
|
||||
uint _ArchVersion() { return 6; }
|
||||
|
||||
enum EInstrSet
|
||||
{
|
||||
ARM, THUMB, THUMBEE
|
||||
}
|
||||
EInstrSet _CurrentInstrSet() { return APSR.T == 1 ? EInstrSet.THUMB : EInstrSet.ARM; }
|
||||
void _SelectInstrSet(EInstrSet newset)
|
||||
{
|
||||
//TODO - copy from manual
|
||||
APSR.T = (newset == EInstrSet.THUMB) ? 1U : 0U;
|
||||
}
|
||||
|
||||
uint _Align(uint value, int level)
|
||||
{
|
||||
return (uint)(value & ~(level - 1));
|
||||
}
|
||||
|
||||
bool _InITBlock() { return false; }
|
||||
bool _LastInITBlock()
|
||||
{
|
||||
//how the hell are we going to implement this?
|
||||
return false;
|
||||
}
|
||||
|
||||
int _LowestSetBit(uint val, int size)
|
||||
{
|
||||
for (int i = 0; i < size; i++)
|
||||
if (_.BITN(i, val) == 1) return i;
|
||||
return size;
|
||||
}
|
||||
|
||||
void _FlagUnpredictable()
|
||||
{
|
||||
unpredictable = true;
|
||||
}
|
||||
|
||||
uint _UNPREDICTABLE()
|
||||
{
|
||||
_FlagUnpredictable();
|
||||
Console.WriteLine("UNPREDICTABLE!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool _CheckVFPEnabled(bool arg)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void _SerializeVFP() { }
|
||||
void _VFPExcBarrier() { }
|
||||
|
||||
uint _PERMANENTLY_UNDEFINED()
|
||||
{
|
||||
Console.WriteLine("PERMANENTLY UNDEFINED! this space will not be allocated in future. (why not?)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ulong _UNKNOWN(int bits, ulong data)
|
||||
{
|
||||
Console.WriteLine("UNKNOWN {0} BITS! (using {0:x16} anyway)", bits, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
uint _PCStoreValue()
|
||||
{
|
||||
// This function returns the PC value. On architecture versions before ARMv7, it
|
||||
// is permitted to instead return PC+4, provided it does so consistently. It is
|
||||
// used only to describe ARM instructions, so it returns the address of the current
|
||||
// instruction plus 8 (normally) or 12 (when the alternative is permitted).
|
||||
return PC;
|
||||
}
|
||||
|
||||
uint MemA_Read32(uint addr)
|
||||
{
|
||||
addr = _Align(addr, 4);
|
||||
return bus.Read32(AT.READ, addr);
|
||||
}
|
||||
|
||||
void _SetExclusiveMonitors(uint address, int size)
|
||||
{
|
||||
//TODO!!! boring!!
|
||||
|
||||
}
|
||||
|
||||
bool _ExclusiveMonitorsPass(uint address, int size)
|
||||
{
|
||||
//TODO!!! boring!!
|
||||
return true;
|
||||
}
|
||||
|
||||
void MemA_Write32(uint addr, uint val)
|
||||
{
|
||||
addr = _Align(addr, 4);
|
||||
bus.Write32(AT.WRITE, addr, val);
|
||||
}
|
||||
|
||||
void MemU_Write08(uint addr, uint val)
|
||||
{
|
||||
bus.Write08(AT.WRITE, addr, (byte)val);
|
||||
}
|
||||
|
||||
byte MemU_Read08(uint addr)
|
||||
{
|
||||
return bus.Read08(AT.READ, addr);
|
||||
}
|
||||
|
||||
ushort MemU_Read16(uint addr)
|
||||
{
|
||||
return bus.Read08(AT.READ, addr);
|
||||
}
|
||||
|
||||
void MemU_Write16(uint addr, uint val)
|
||||
{
|
||||
bus.Write16(AT.WRITE, addr, (ushort)val);
|
||||
}
|
||||
|
||||
void MemU_Write32(uint addr, uint val)
|
||||
{
|
||||
bus.Write32(AT.WRITE, addr, val);
|
||||
}
|
||||
|
||||
uint MemU_Read32(uint addr)
|
||||
{
|
||||
return bus.Read32(AT.READ, addr);
|
||||
}
|
||||
|
||||
uint _MemU(uint addr, uint size)
|
||||
{
|
||||
//TODO - differentiate from MemA
|
||||
switch (size)
|
||||
{
|
||||
case 4: return bus.Read32(AT.READ, addr);
|
||||
case 2: return bus.Read16(AT.READ, addr);
|
||||
case 1: return bus.Read08(AT.READ, addr);
|
||||
default: throw new ArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
uint _MemA(uint addr, uint size)
|
||||
{
|
||||
//TODO - differentiate from MemU
|
||||
switch (size)
|
||||
{
|
||||
case 4: return bus.Read32(AT.READ, addr);
|
||||
case 2: return bus.Read16(AT.READ, addr);
|
||||
case 1: return bus.Read08(AT.READ, addr);
|
||||
default: throw new ArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _ALUWritePC(uint address)
|
||||
{
|
||||
if (_ArchVersion() >= 7 && _CurrentInstrSet() == EInstrSet.ARM)
|
||||
_BXWritePC(address);
|
||||
else
|
||||
_BranchWritePC(address);
|
||||
}
|
||||
|
||||
void _BranchWritePC(uint address)
|
||||
{
|
||||
if (_CurrentInstrSet() == EInstrSet.ARM)
|
||||
{
|
||||
if (_ArchVersion() < 6 && ((address & 0x3) != 0)) { _UNPREDICTABLE(); }
|
||||
_BranchTo((uint)(address & ~3));
|
||||
}
|
||||
else
|
||||
_BranchTo((uint)(address & ~1));
|
||||
}
|
||||
|
||||
void _BranchTo(uint address)
|
||||
{
|
||||
_R[15] = address;
|
||||
next_instruct_adr = address;
|
||||
}
|
||||
|
||||
uint _LoadWritePC(uint address)
|
||||
{
|
||||
if (_ArchVersion() >= 5)
|
||||
_BXWritePC(address);
|
||||
else
|
||||
_BranchWritePC(address);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void _BXWritePC(uint address)
|
||||
{
|
||||
if (_CurrentInstrSet() == EInstrSet.THUMBEE)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_.BIT0(address) == 1)
|
||||
{
|
||||
_SelectInstrSet(EInstrSet.THUMB);
|
||||
_BranchTo((uint)(address & ~1));
|
||||
}
|
||||
else if (_.BIT1(address) == 0)
|
||||
{
|
||||
_SelectInstrSet(EInstrSet.ARM);
|
||||
_BranchTo(address);
|
||||
}
|
||||
else
|
||||
{
|
||||
_UNPREDICTABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum SRType
|
||||
{
|
||||
LSL = 0, LSR = 1, ASR = 2, ROR = 3, RRX = 4
|
||||
}
|
||||
|
||||
uint _ZeroExtend_32(uint val)
|
||||
{
|
||||
//TODO - any tricky behaviour from doc?
|
||||
return val;
|
||||
}
|
||||
|
||||
int _SignExtend_32(int bits_present, uint val)
|
||||
{
|
||||
int temp = (int)val;
|
||||
int shift = 32 - bits_present;
|
||||
temp <<= (shift);
|
||||
return temp >> shift;
|
||||
}
|
||||
|
||||
SRType shift_t;
|
||||
int shift_n;
|
||||
/// <summary>
|
||||
/// decodes shifter arguments to shift_t and shift_n
|
||||
/// </summary>
|
||||
void _DecodeImmShift(uint arg, uint imm5)
|
||||
{
|
||||
switch (arg)
|
||||
{
|
||||
case _.b00:
|
||||
shift_t = SRType.LSL;
|
||||
shift_n = (int)imm5;
|
||||
break;
|
||||
case _.b01:
|
||||
shift_t = SRType.LSR;
|
||||
if (imm5 == 0) shift_n = 32;
|
||||
else shift_n = (int)imm5;
|
||||
break;
|
||||
case _.b10:
|
||||
shift_t = SRType.LSR;
|
||||
if (imm5 == 0) shift_n = 32;
|
||||
else shift_n = (int)imm5;
|
||||
break;
|
||||
case _.b11:
|
||||
if (imm5 == 0)
|
||||
{
|
||||
shift_t = SRType.RRX;
|
||||
shift_n = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
shift_t = SRType.ROR;
|
||||
shift_n = (int)imm5;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool _UnalignedSupport() { return false; /*TODO*/ }
|
||||
|
||||
|
||||
|
||||
bool _NullCheckIfThumbEE(uint num) { return false; }
|
||||
|
||||
bool _IsZeroBit(uint value) { return value == 0; }
|
||||
|
||||
uint _Shift(uint value, SRType type, int amount, Bit carry_in)
|
||||
{
|
||||
uint result; Bit carry_out;
|
||||
_Shift_C(value, type, amount, carry_in, out result, out carry_out);
|
||||
return result;
|
||||
}
|
||||
|
||||
void _Shift_C(uint value, SRType type, int amount, Bit carry_in, out uint result, out Bit carry_out)
|
||||
{
|
||||
if (type == SRType.RRX && amount == 1) throw new InvalidOperationException("bogus shift");
|
||||
if (amount == 0)
|
||||
{
|
||||
result = value;
|
||||
carry_out = carry_in;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case SRType.LSL: _LSL_C(value, amount, out result, out carry_out); break;
|
||||
case SRType.LSR: _LSR_C(value, amount, out result, out carry_out); break;
|
||||
case SRType.ASR: _ASR_C(value, amount, out result, out carry_out); break;
|
||||
case SRType.ROR: _ROR_C(value, amount, out result, out carry_out); break;
|
||||
case SRType.RRX: _RRX_C(value, carry_in, out result, out carry_out); break;
|
||||
default: throw new ArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _Assert(bool condition)
|
||||
{
|
||||
#if DEBUG
|
||||
System.Diagnostics.Debug.Assert(condition);
|
||||
#endif
|
||||
}
|
||||
|
||||
void _LSL_C(uint x, int shift, out uint result, out Bit carry_out)
|
||||
{
|
||||
//A2-5
|
||||
_Assert(shift > 0);
|
||||
ulong extended_x = (ulong)x << shift;
|
||||
result = (uint)extended_x;
|
||||
carry_out = _.BIT32(extended_x);
|
||||
}
|
||||
|
||||
uint _LSL(uint x, int shift)
|
||||
{
|
||||
//A2-5
|
||||
_Assert(shift >= 0);
|
||||
if (shift == 0) return x;
|
||||
else
|
||||
{
|
||||
uint result;
|
||||
Bit carry_out;
|
||||
_LSL_C(x, shift, out result, out carry_out);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void _LSR_C(uint x, int shift, out uint result, out Bit carry_out)
|
||||
{
|
||||
//A2-6 but coded my own way
|
||||
_Assert(shift > 0);
|
||||
result = x >> shift;
|
||||
carry_out = ((x >> (shift - 1)) & 1);
|
||||
}
|
||||
|
||||
uint _LSR(uint x, int shift)
|
||||
{
|
||||
//A2-6
|
||||
_Assert(shift >= 0);
|
||||
if (shift == 0) return x;
|
||||
else
|
||||
{
|
||||
uint result;
|
||||
Bit carry_out;
|
||||
_LSR_C(x, shift, out result, out carry_out);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void _ASR_C(uint x, int shift, out uint result, out Bit carry_out)
|
||||
{
|
||||
//A2-6 but coded my own way
|
||||
_Assert(shift > 0);
|
||||
int temp = (int)x;
|
||||
temp >>= shift;
|
||||
result = (uint)temp;
|
||||
carry_out = ((x >> (shift - 1)) & 1);
|
||||
}
|
||||
|
||||
uint _ASR(uint x, int shift)
|
||||
{
|
||||
//A2-6
|
||||
_Assert(shift >= 0);
|
||||
if (shift == 0) return x;
|
||||
else
|
||||
{
|
||||
uint result;
|
||||
Bit carry_out;
|
||||
_ASR_C(x, shift, out result, out carry_out);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void _ROR_C(uint x, int shift, out uint result, out Bit carry_out)
|
||||
{
|
||||
//A2-6
|
||||
_Assert(shift != 0);
|
||||
int m = shift & 31;
|
||||
result = _LSR(x, m) | _LSL(x, 32 - m);
|
||||
carry_out = _.BIT31(result);
|
||||
}
|
||||
|
||||
uint _ROR(uint x, int shift)
|
||||
{
|
||||
//A5-7 //TODO - there is an error in this pseudocode. report it to ARM! (if(n==0) should be if(shift==0)
|
||||
if (shift == 0) return x;
|
||||
else
|
||||
{
|
||||
uint result;
|
||||
Bit carry_out;
|
||||
_ROR_C(x, shift, out result, out carry_out);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void _RRX_C(uint x, Bit carry_in, out uint result, out Bit carry_out)
|
||||
{
|
||||
//A2-7
|
||||
result = ((carry_in) ? (uint)0x80000000 : (uint)0) | (x >> 1);
|
||||
carry_out = _.BIT0(x);
|
||||
}
|
||||
|
||||
uint _RRX(uint x, Bit carry_in)
|
||||
{
|
||||
uint result;
|
||||
Bit carry_out;
|
||||
_RRX_C(x, carry_in, out result, out carry_out);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint _ARMExpandImm(uint imm12)
|
||||
{
|
||||
//A5-10
|
||||
uint imm32;
|
||||
Bit trash;
|
||||
_ARMExpandImm_C(imm12, 0, out imm32, out trash); //DEVIATION: docs say to pass in APSR.C even though it doesnt matter.
|
||||
return imm32;
|
||||
}
|
||||
|
||||
void _ARMExpandImm_C(uint imm12, Bit carry_in, out uint imm32, out Bit carry_out)
|
||||
{
|
||||
//A5-10
|
||||
uint unrotated_value = imm12 & 0xFF;
|
||||
_Shift_C(unrotated_value, SRType.ROR, 2 * (int)((imm12 >> 8) & 0xF), carry_in, out imm32, out carry_out);
|
||||
}
|
||||
|
||||
uint alu_result_32;
|
||||
Bit alu_carry_out;
|
||||
Bit alu_overflow;
|
||||
void _AddWithCarry32(uint x, uint y, Bit carry_in)
|
||||
{
|
||||
ulong unsigned_sum = (ulong)x + (ulong)y + (uint)carry_in;
|
||||
long signed_sum = (long)(int)x + (long)(int)y + (uint)carry_in;
|
||||
alu_result_32 = (uint)(unsigned_sum & 0xFFFFFFFF);
|
||||
alu_carry_out = (alu_result_32 == unsigned_sum) ? 0 : 1;
|
||||
alu_overflow = ((long)(int)alu_result_32 == signed_sum) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BizHawk.Emulation.CPUs.ARM
|
||||
{
|
||||
//reference: ARM manual DDI0406B
|
||||
|
||||
public enum AT
|
||||
{
|
||||
PEEK, POKE, READ, WRITE, FETCH
|
||||
}
|
||||
|
||||
//this may need to be rearchitectured to pass the entire instruction, as specified in the docs...
|
||||
public interface ICoprocessorSet
|
||||
{
|
||||
//read
|
||||
uint MRC(uint cp, uint opc1, uint t, uint crn, uint crm, uint opc2);
|
||||
string Describe(uint cp, uint opc1, uint t, uint crn, uint crm, uint opc2);
|
||||
}
|
||||
|
||||
public interface ARM_SYS
|
||||
{
|
||||
uint svc(uint num);
|
||||
string svc_name(uint num);
|
||||
ICoprocessorSet coprocessors { get; }
|
||||
}
|
||||
|
||||
public interface ARM_BUS
|
||||
{
|
||||
byte Read08(AT at, uint addr);
|
||||
ushort Read16(AT at, uint addr);
|
||||
uint Read32(AT at, uint addr);
|
||||
void Write08(AT at, uint addr, byte val);
|
||||
void Write16(AT at, uint addr, ushort val);
|
||||
void Write32(AT at, uint addr, uint val);
|
||||
void Write64(AT at, uint addr, ulong val);
|
||||
}
|
||||
|
||||
public unsafe partial class ARM
|
||||
{
|
||||
public ARM_SYS sys;
|
||||
public ARM_BUS bus;
|
||||
|
||||
public enum Mode
|
||||
{
|
||||
USR = 0x10,
|
||||
FIQ = 0x11,
|
||||
IRQ = 0x12,
|
||||
SVC = 0x13,
|
||||
ABT = 0x17,
|
||||
UND = 0x1B,
|
||||
SYS = 0x1F
|
||||
}
|
||||
|
||||
public struct Status_Reg
|
||||
{
|
||||
//public uint val;
|
||||
//public uint mode { get { return val & 0x1F; } set { val = (uint)((val & ~0x1F) | (value & 0x1F)); } }
|
||||
//public uint T { get { return val & 0x20; } set { val = (uint)((val & ~0x20) | (value & 0x20)); } }
|
||||
//public uint F { get { return val & 0x40; } set { val = (uint)((val & ~0x40) | (value & 0x40)); } }
|
||||
//public uint I { get { return val & 0x80; } set { val = (uint)((val & ~0x80) | (value & 0x80)); } }
|
||||
//public uint N { get { return val & 0x80000000; } set { val = (uint)((val & ~0x80000000) | (value & 0x80000000)); } }
|
||||
|
||||
public Mode mode;
|
||||
public Bit T, F, I, Q, V, C, Z, N;
|
||||
//todo - consider combining the condition flags together for various speedups
|
||||
}
|
||||
|
||||
public uint next_instruct_adr;
|
||||
public uint instruct_adr;
|
||||
public uint instruction;
|
||||
uint thumb_32bit_extra;
|
||||
bool thumb_32bit;
|
||||
|
||||
public class Registers
|
||||
{
|
||||
ARM cpu;
|
||||
public Registers(ARM cpu) { this.cpu = cpu; }
|
||||
public uint this[int n] { get { return this[(uint)n]; } set { this[(uint)n] = value; } }
|
||||
public uint this[uint n]
|
||||
{
|
||||
//this is a bit different than the docs, in the interest of performance
|
||||
get
|
||||
{
|
||||
if (n == 15)
|
||||
{
|
||||
uint offset = (cpu._CurrentInstrSet() == EInstrSet.ARM ? 8U : 4U);
|
||||
return cpu._R[15] + offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO - junk about security and monitor mode and FIQ and whatnot
|
||||
return cpu._R[n];
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
Debug.Assert(n >= 0 && n <= 14);
|
||||
//TODO - junk about security and monitor mode and FIQ and whatnot
|
||||
if (n == 13 && (value & 3) != 0 && cpu._CurrentInstrSet() != EInstrSet.ARM) cpu._FlagUnpredictable();
|
||||
cpu._R[n] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//todo: make R[] indexer which is defined as in manual with an assert when R[15] is written to
|
||||
public Registers r;
|
||||
uint[] _R = new uint[16];
|
||||
public Status_Reg APSR;
|
||||
public Status_Reg SPSR;
|
||||
|
||||
public uint SP { get { return r[13]; } set { r[13] = value; } }
|
||||
public uint LR { get { return r[14]; } set { r[14] = value; } }
|
||||
public uint PC { get { return r[15]; } set { r[15] = value; } }
|
||||
|
||||
uint R13_usr, R14_usr;
|
||||
uint R13_svc, R14_svc;
|
||||
uint R13_abt, R14_abt;
|
||||
uint R13_und, R14_und;
|
||||
uint R13_irq, R14_irq;
|
||||
uint R8_fiq, R9_fiq, R10_fiq, R11_fiq, R12_fiq, R13_fiq, R14_fiq;
|
||||
Status_Reg SPSR_svc, SPSR_abt, SPSR_und, SPSR_irq, SPSR_fiq;
|
||||
|
||||
|
||||
uint FPSCR;
|
||||
|
||||
public ARM(ARM_SYS sys, ARM_BUS bus)
|
||||
{
|
||||
this.sys = sys;
|
||||
this.bus = bus;
|
||||
r = new Registers(this);
|
||||
}
|
||||
|
||||
//disassembly state
|
||||
public bool disassemble;
|
||||
public bool nstyle;
|
||||
public string disassembly;
|
||||
|
||||
enum Encoding
|
||||
{
|
||||
T1, T2, T3, T4,
|
||||
A1, A2, A3, A4
|
||||
}
|
||||
bool EncodingT(Encoding e)
|
||||
{
|
||||
return e == Encoding.T1 || e == Encoding.T2 || e == Encoding.T3 || e == Encoding.T4;
|
||||
}
|
||||
bool EncodingA(Encoding e)
|
||||
{
|
||||
return e == Encoding.A1 || e == Encoding.A2 || e == Encoding.A3 || e == Encoding.A4;
|
||||
}
|
||||
|
||||
public enum TraceType
|
||||
{
|
||||
Full, Short
|
||||
}
|
||||
ulong tracetr = 0;
|
||||
public string Trace(TraceType tt)
|
||||
{
|
||||
disassemble = true;
|
||||
Execute();
|
||||
StringBuilder sb = new StringBuilder(256);
|
||||
sb.AppendFormat("{0}:{1}:{2:X8} ", tracetr, _CurrentInstrSet() == EInstrSet.ARM ? 'A' : 'T', instruct_adr);
|
||||
tracetr++;
|
||||
if(thumb_32bit)
|
||||
sb.AppendFormat("{0:X4}{1:X4} ", instruction,thumb_32bit_extra);
|
||||
else
|
||||
sb.AppendFormat("{0:X8} ",instruction);
|
||||
sb.Append(disassembly.PadRight(30,' '));
|
||||
if(tt == TraceType.Full)
|
||||
for(int i=0;i<16;i++)
|
||||
sb.AppendFormat(" {0:X8}", r[i]);
|
||||
disassemble = false;
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public uint Fetch()
|
||||
{
|
||||
thumb_32bit = false;
|
||||
instruct_adr = next_instruct_adr;
|
||||
if (APSR.T)
|
||||
{
|
||||
//THUMB:
|
||||
Debug.Assert((instruct_adr & 1) == 0);
|
||||
_R[15] = instruct_adr;
|
||||
next_instruct_adr += 2;
|
||||
instruction = bus.Read16(AT.FETCH, instruct_adr);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert((instruct_adr & 3) == 0);
|
||||
_R[15] = instruct_adr;
|
||||
next_instruct_adr += 4;
|
||||
instruction = bus.Read32(AT.FETCH, instruct_adr);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ThumbFetchExtra()
|
||||
{
|
||||
thumb_32bit = true;
|
||||
thumb_32bit_extra = bus.Read16(AT.FETCH, next_instruct_adr);
|
||||
next_instruct_adr = instruct_adr + 2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,179 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class BS
|
||||
{
|
||||
public BS(string str)
|
||||
{
|
||||
ca = str.ToCharArray();
|
||||
Array.Reverse(ca);
|
||||
}
|
||||
char[] ca;
|
||||
public static bool operator ==(uint lhs, BS rhs) { return rhs == lhs; }
|
||||
public static bool operator !=(uint lhs, BS rhs) { return rhs != lhs; }
|
||||
public static bool operator ==(int lhs, BS rhs) { return rhs == (uint)lhs; }
|
||||
public static bool operator !=(int lhs, BS rhs) { return rhs != (uint)lhs; }
|
||||
public static bool operator ==(BS lhs, int rhs) { return (uint)rhs == lhs; }
|
||||
public static bool operator !=(BS lhs, int rhs) { return (uint)rhs != lhs; }
|
||||
public static bool operator ==(BS lhs, uint rhs)
|
||||
{
|
||||
foreach (char c in lhs.ca)
|
||||
{
|
||||
uint bit = rhs & 1;
|
||||
switch (c)
|
||||
{
|
||||
case '0': if (bit != 0) return false; break;
|
||||
case '1': if (bit != 1) return false; break;
|
||||
}
|
||||
rhs >>= 1;
|
||||
}
|
||||
if(rhs != 0) return false;
|
||||
return true;
|
||||
}
|
||||
public static bool operator !=(BS lhs, uint rhs) { return !(lhs == rhs); }
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is uint) return this == (uint)obj;
|
||||
if (obj is int) return this == (int)obj;
|
||||
if (obj is BS) throw new InvalidOperationException();
|
||||
return false;
|
||||
}
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return ca.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
class Decoder
|
||||
{
|
||||
bool constructed = false;
|
||||
public void Ensure(Action constructor)
|
||||
{
|
||||
if (constructed) return;
|
||||
constructed = true;
|
||||
constructor();
|
||||
Compile();
|
||||
}
|
||||
|
||||
//public Decoder(params object[] args)
|
||||
//{
|
||||
// if(args.Length %2 != 0) throw new ArgumentException("need odd params to Decoder");
|
||||
|
||||
// for(int i=0;i<args.Length/2;i++)
|
||||
// {
|
||||
// string str = (string)args[i * 2];
|
||||
// object o = args[i * 2 + 1];
|
||||
// if (o is int)
|
||||
// Declare(str, (int)o);
|
||||
// else AddRule(str, (Action)o);
|
||||
// }
|
||||
//}
|
||||
|
||||
class Rule
|
||||
{
|
||||
public Rule(string program,Action action)
|
||||
{
|
||||
this.program = program;
|
||||
this.action = action;
|
||||
}
|
||||
public string program;
|
||||
public Action action;
|
||||
}
|
||||
public void AddRule(string rule, Action action)
|
||||
{
|
||||
rules.Add(new Rule(rule,action));
|
||||
}
|
||||
public Decoder r(string rule, Action action)
|
||||
{
|
||||
AddRule(rule, action);
|
||||
return this;
|
||||
}
|
||||
|
||||
List<Rule> rules = new List<Rule>();
|
||||
|
||||
class Variable
|
||||
{
|
||||
public Variable(string name, int bits)
|
||||
{
|
||||
this.name = name;
|
||||
this.bits = bits;
|
||||
}
|
||||
public string name;
|
||||
public int bits;
|
||||
}
|
||||
List<Variable> variables = new List<Variable>();
|
||||
|
||||
public void Declare(string name, int bits)
|
||||
{
|
||||
variables.Add(new Variable(name, bits));
|
||||
}
|
||||
public Decoder d(string name, int bits)
|
||||
{
|
||||
Declare(name, bits);
|
||||
return this;
|
||||
}
|
||||
|
||||
static Regex rxBits = new Regex(@"(\#([01xX]*))", RegexOptions.Compiled);
|
||||
bool compiled = false;
|
||||
|
||||
public void Compile()
|
||||
{
|
||||
if (compiled) return;
|
||||
compiled = true;
|
||||
int numbits = 0;
|
||||
ScriptEngine se = new ScriptEngine();
|
||||
foreach (Variable v in variables) numbits += v.bits;
|
||||
int cases = 1 << numbits;
|
||||
for (uint i = 0; i < cases; i++)
|
||||
{
|
||||
//split apart key
|
||||
uint itemp = i;
|
||||
for (int j = 0; j < variables.Count; j++)
|
||||
{
|
||||
Variable v = variables[j];
|
||||
uint x = (uint)(itemp & ((1 << v.bits)-1));
|
||||
itemp >>= v.bits;
|
||||
se.variables[v.name] = x;
|
||||
}
|
||||
|
||||
//default table value is an exception
|
||||
table[i] = () => { throw new InvalidOperationException("auto-decoder fail (missing case)"); };
|
||||
|
||||
foreach (Rule rule in rules)
|
||||
{
|
||||
string program = rule.program;
|
||||
foreach (Match m in rxBits.Matches(program))
|
||||
program = program.Replace(m.Value, "new BS(\"" + m.Groups[2].Value + "\")");
|
||||
object o = se.Eval(program);
|
||||
bool? b = o as bool?;
|
||||
if(!b.HasValue) throw new InvalidOperationException();
|
||||
if (b.Value)
|
||||
{
|
||||
table[i] = rule.action;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
se.Dispose();
|
||||
}
|
||||
|
||||
//TODO - make overloads for different param number (array create overhead will be high)
|
||||
public void Evaluate(params uint[] args)
|
||||
{
|
||||
Compile();
|
||||
uint key = 0;
|
||||
for (int i = variables.Count-1; i >= 0; i--)
|
||||
{
|
||||
Variable v = variables[i];
|
||||
key <<= v.bits;
|
||||
if (args[i] > (1 << v.bits))
|
||||
throw new ArgumentException();
|
||||
key |= args[i];
|
||||
}
|
||||
table[key]();
|
||||
}
|
||||
|
||||
Dictionary<uint, Action> table = new Dictionary<uint, Action>();
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Microsoft.JScript;
|
||||
using Microsoft.JScript.Vsa;
|
||||
using Microsoft.Vsa;
|
||||
|
||||
#pragma warning disable 0618
|
||||
|
||||
class ScriptEngine : IDisposable
|
||||
{
|
||||
string[] commonNamespaces =
|
||||
{
|
||||
"System"
|
||||
};
|
||||
|
||||
string[] commonAssemblies =
|
||||
{
|
||||
"mscorlib.dll",
|
||||
"System.dll",
|
||||
System.Reflection.Assembly.GetExecutingAssembly().Location
|
||||
};
|
||||
|
||||
|
||||
VsaEngine engine;
|
||||
//Microsoft.JScript.GlobalScope jscriptGlobalScope = null;
|
||||
|
||||
public Dictionary<string, object> variables = new Dictionary<string, object>();
|
||||
|
||||
class MySite : Microsoft.Vsa.BaseVsaSite
|
||||
{
|
||||
ScriptEngine se;
|
||||
public MySite(ScriptEngine se)
|
||||
{
|
||||
this.se = se;
|
||||
}
|
||||
public override object GetGlobalInstance(string name)
|
||||
{
|
||||
return se.variables[name];
|
||||
}
|
||||
}
|
||||
|
||||
public ScriptEngine()
|
||||
{
|
||||
InitializeJScriptDotNetEngine();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
UninitializeJScriptDotNetEngine();
|
||||
}
|
||||
|
||||
bool hasVariables = false;
|
||||
public object Eval(string script)
|
||||
{
|
||||
if (!hasVariables)
|
||||
{
|
||||
hasVariables = true;
|
||||
foreach (KeyValuePair<string, object> kvp in variables)
|
||||
{
|
||||
IVsaGlobalItem globItem = (IVsaGlobalItem)engine.Items.CreateItem(kvp.Key, VsaItemType.AppGlobal, VsaItemFlag.None);
|
||||
globItem.TypeString = kvp.Value.GetType().FullName;
|
||||
}
|
||||
engine.CompileEmpty();
|
||||
engine.RunEmpty();
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
foreach (KeyValuePair<string, object> kvp in variables)
|
||||
sb.AppendFormat("{0} = {1};\n",kvp.Key,kvp.Value);
|
||||
sb.AppendLine(script);
|
||||
|
||||
object o = Microsoft.JScript.Eval.JScriptEvaluate(sb.ToString(), engine);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
private void UninitializeJScriptDotNetEngine()
|
||||
{
|
||||
|
||||
//if (jscriptGlobalScope != null)
|
||||
|
||||
// jscriptGlobalScope.engine.Close();
|
||||
|
||||
//jscriptGlobalScope = null;
|
||||
if(engine != null)
|
||||
engine.Close();
|
||||
engine = null;
|
||||
}
|
||||
|
||||
private void InitializeJScriptDotNetEngine()
|
||||
{
|
||||
|
||||
if (engine == null)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
engine = new VsaEngine();
|
||||
engine.InitVsaEngine("blah://x",new MySite(this));
|
||||
foreach (string str in commonAssemblies)
|
||||
{
|
||||
IVsaReferenceItem reference = (IVsaReferenceItem)engine.Items.CreateItem(str, VsaItemType.Reference, VsaItemFlag.None);
|
||||
reference.AssemblyName = str;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
catch { }
|
||||
|
||||
foreach (string ns in commonNamespaces)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
if ((ns != null) && (ns != String.Empty))
|
||||
|
||||
Microsoft.JScript.Import.JScriptImport(ns, engine);
|
||||
|
||||
}
|
||||
|
||||
catch { }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue