discohawk-add capability for searching for mis-extensioned files (broadens compatibility a bit) and autodetecting audio tracks based on extension where otherwise marked as binary.

This commit is contained in:
zeromus 2012-01-21 21:23:19 +00:00
parent 95a769aa0c
commit 5f66de57ec
14 changed files with 57 additions and 13146 deletions

View File

@ -180,16 +180,6 @@
<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\_.cs" />
<Compile Include="CPUs\HuC6280\Disassembler.cs" />
<Compile Include="CPUs\HuC6280\Execute.cs" />
<Compile Include="CPUs\HuC6280\HuC6280.cs" />

View File

@ -1,60 +0,0 @@
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;
}
}
}

View File

@ -1,506 +0,0 @@
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, "");
if(opcode.Contains("{.fpsize}"))
opcode = opcode.Replace("<{.fpsize}>",".F" + args[argindex++].ToString());
if (opcode.Contains(".fpsize"))
opcode = opcode.Replace("<.fpsize>", ".F" + args[argindex++].ToString());
//---------
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 "sdd":
case "sdn":
case "sdm":
if ((bool)args[argindex++])
item = "s" + args[argindex++].ToString();
else
item = "d" + args[argindex++].ToString();
break;
case "{sdd~sdn, }":
{
bool s = (bool)args[argindex++];
uint rd = (uint)args[argindex++];
uint rx = (uint)args[argindex++];
if (disopt.showExplicitAccumulateRegisters || rd != rx)
item = string.Format("{0}{1}, ", s ? "s" : "d", rd);
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;
}
case "list":
{
bool single = (bool)args[argindex++];
uint d = (uint)args[argindex++];
uint regs = (uint)args[argindex++];
item = "{";
string name = single ? "s" : "d";
bool first=true;
for (uint r = 0; r <= regs - 1; r++)
{
if (!first) item += ",";
first = false;
item += name + (r + d).ToString();
}
item += "}";
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();
}
}
}

View File

@ -1,147 +0,0 @@
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);
}
}
}

View File

@ -1,61 +0,0 @@
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"); }
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -1,962 +0,0 @@
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 Execute_LDR_literal_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 Execute_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 Execute_LDR_literal_T1()
{
//A8.6.59
uint t = Reg8(8);
uint imm8 = instruction & 0xFF;
uint imm32 = imm8 << 2;
const 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_LDR_register_T1();
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_LDR_register_T1()
{
//A8.6.60
if (_CurrentInstrSet() == EInstrSet.THUMBEE) throw new NotSupportedException("Modified operatoin in ThumbEE");
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_LDR_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 Execute_BL_BLX_immediate_T2();
case _.b101:
case _.b111: return Execute_BL_BLX_immediate_T1();
default: throw new InvalidOperationException();
}
}
uint Execute_BL_BLX_immediate_T1()
{
//A8.6.23
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 Execute_BL_BLX_immediate_T2()
{
//A8.6.23
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 Execute_ADR_T1()
{
//A8.6.10
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
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);
}
uint ExecuteThumb_Misc16()
{
uint opcode = (instruction >> 5) & 0x7F;
//ThumbMisc
switch((opcode<<0)) {
//opcode == #0110010
case 50:
Execute_Unhandled("SETEND on page A8-314");
break;
//opcode == #0110011
case 51:
Execute_Unhandled("CPS on page B6-3");
break;
//opcode == #00000xx
case 0: case 1: case 2: case 3:
Execute_ADD_SP_plus_immediate_T2();
break;
//opcode == #00001xx
case 4: case 5: case 6: case 7:
Execute_SUB_SP_minus_immediate_T1();
break;
//opcode == #0001xxx
//opcode == #0011xxx
//opcode == #1001xxx
case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: case 72: case 73: case 74: case 75: case 76: case 77: case 78: case 79:
Execute_Unhandled("CBNZ,CBZ on page A8-66 [v6T2]");
break;
//opcode == #001000x
case 16: case 17:
Execute_Unhandled("SXTH on page A8-444");
break;
//opcode == #001001x
case 18: case 19:
Execute_Unhandled("SXTB on page A8-440");
break;
//opcode == #001010x
case 20: case 21:
Execute_UXTH_T1();
break;
//opcode == #001011x
case 22: case 23:
Execute_UXTB_T1();
break;
//opcode == #010xxxx
case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47:
Execute_PUSH_T1();
break;
//opcode == #101000x
case 80: case 81:
Execute_Unhandled("REV on page A8-272");
break;
//opcode == #101001x
case 82: case 83:
Execute_Unhandled("REV16 on page A8-274");
break;
//opcode == #101011x
case 86: case 87:
Execute_Unhandled("REVSH on page A8-276");
break;
//opcode == #110xxxx
case 96: case 97: case 98: case 99: case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107: case 108: case 109: case 110: case 111:
Execute_POP_T1();
break;
//opcode == #1110xxx
case 112: case 113: case 114: case 115: case 116: case 117: case 118: case 119:
Execute_Unhandled("BKPT on page A8-56");
break;
//opcode == #1111xxx
case 120: case 121: case 122: case 123: case 124: case 125: case 126: case 127:
Execute_Unhandled("If-Then and hints on page A6-12");
break;
default: throw new InvalidOperationException("unhandled case for switch ThumbMisc");
}
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_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");
}
}
}

View File

@ -1,564 +0,0 @@
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);
}
ulong MemA_Read64(uint addr)
{
ulong ret = MemA_Read32(addr);
ret |= (((ulong)MemA_Read32(addr + 4)) << 32);
return ret;
}
void _SetExclusiveMonitors(uint address, int size)
{
//TODO!!! boring!!
}
bool _ExclusiveMonitorsPass(uint address, int size)
{
//TODO!!! boring!!
return true;
}
void MemA_WriteSingle(uint addr, float val)
{
MemA_Write32(addr,float_downcast(val));
}
float MemA_ReadSingle(uint addr)
{
return float_upcast(MemA_Read32(addr));
}
double MemA_ReadDouble(uint addr)
{
return double_upcast(MemA_Read64(addr));
}
void MemA_WriteDouble(uint addr, double val)
{
ulong uval = double_downcast(val);
//TODO endian
MemA_Write32(addr,(uint)uval);
MemA_Write32(addr+4,(uint)(uval>>32));
}
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));
}
bool _BigEndian() { return false; }
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;
}
float _FPAdd(float op1, float op2, bool fpscr_controlled)
{
//TODO
return op1 + op2;
}
double _FPAdd(double op1, double op2, bool fpscr_controlled)
{
//TODO
return op1 + op2;
}
bool _CheckAdvSIMDOrVFPEnabled(bool x, bool y)
{
//TODO
return true;
}
static uint[] __VFPExpandImm32_table;
static uint __VFPExpandImm32_calc(uint imm8)
{
uint a = _.BIT7(imm8);
uint B = _.BIT6(imm8)^1;
uint b = _.BIT6(imm8);
b |= (b << 1); //replicated to 2 bits
b |= (b << 2); //replicated to 4 bits
b |= (b << 1); //replicated to 5 bits
uint cdefgh = imm8 & 0x3F;
return (a<<31)|(B<<30)|(b<<29)|(cdefgh<<24);
}
static ulong[] __VFPExpandImm64_table;
static ulong __VFPExpandImm64_calc(uint imm8)
{
uint a = _.BIT7(imm8);
uint B = _.BIT6(imm8) ^ 1;
uint b = _.BIT6(imm8);
b |= (b << 1); //replicated to 2 bits
b |= (b << 2); //replicated to 4 bits
b |= (b << 4); //replicated to 8 bits
uint cdefgh = imm8 & 0x3F;
uint uintret = (a << 31) | (B << 30) | (b << 29) | (cdefgh << 20);
ulong ulongret = uintret << 32;
return ulongret;
}
uint _VFPExpandImm32(uint imm8)
{
if(__VFPExpandImm32_table == null)
{
__VFPExpandImm32_table = new uint[256];
for(uint i=0;i<256;i++)
__VFPExpandImm32_table[i] = __VFPExpandImm32_calc(i);
}
return __VFPExpandImm32_table[imm8];
}
ulong _VFPExpandImm64(uint imm8)
{
if (__VFPExpandImm64_table == null)
{
__VFPExpandImm64_table = new ulong[256];
for (uint i = 0; i < 256; i++)
__VFPExpandImm64_table[i] = __VFPExpandImm64_calc(i);
}
return __VFPExpandImm64_table[imm8];
}
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;
}
}
}

View File

@ -1,239 +0,0 @@
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;
}
}
}
public Registers r;
uint[] _R = new uint[16];
public Status_Reg APSR;
public Status_Reg SPSR;
float[] S = new float[32];
double[] D = new double[16];
unsafe static uint float_downcast(float f)
{
float* fp = &f;
return *(uint*)fp;
}
unsafe static float float_upcast(uint f)
{
uint* fp = &f;
return *(float*)fp;
}
unsafe static ulong double_downcast(double f)
{
double* fp = &f;
return *(ulong*)fp;
}
unsafe static double double_upcast(ulong f)
{
ulong* fp = &f;
return *(double*)fp;
}
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;
uint _FPSCR_LEN() { return 0; }
uint _FPSCR_STRIDE() { return 0; }
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

View File

@ -10,7 +10,28 @@ namespace BizHawk.DiscSystem
{
partial class Disc
{
void FromCuePathInternal(string cuePath)
/// <summary>
/// finds a file in the same directory with an extension alternate to the supplied one.
/// If two are found, an exception is thrown (later, we may have heuristics to try to acquire the desired content)
/// </summary>
string FindAlternateExtensionFile(string path, bool caseSensitive)
{
string targetFragment = Path.GetFileNameWithoutExtension(path);
var di = new FileInfo(path).Directory;
var results = new List<FileInfo>();
foreach (var fi in di.GetFiles())
{
string fragment = Path.GetFileNameWithoutExtension(fi.FullName);
int cmp = string.Compare(fragment, targetFragment, !caseSensitive);
if (cmp == 0)
results.Add(fi);
}
if(results.Count == 0) throw new DiscReferenceException(path, "Cannot find the specified file");
if (results.Count > 1) throw new DiscReferenceException(path, "Cannot choose between multiple options");
return results[0].FullName;
}
void FromCuePathInternal(string cuePath, CueBinPrefs prefs)
{
string cueDir = Path.GetDirectoryName(cuePath);
var cue = new Cue();
@ -34,7 +55,23 @@ namespace BizHawk.DiscSystem
int blob_length_aba, blob_leftover;
IBlob cue_blob = null;
if (cue_file.FileType == Cue.CueFileType.Binary)
//try any way we can to acquire a file
if (!File.Exists(blobPath) && prefs.ExtensionAware)
{
blobPath = FindAlternateExtensionFile(blobPath, prefs.CaseSensitive);
}
if (!File.Exists(blobPath))
throw new DiscReferenceException(blobPath,"");
//some simple rules to mutate the file type if we received something fishy
string blobPathExt = Path.GetExtension(blobPath).ToLower();
if (blobPathExt == ".ape") cue_file.FileType = Cue.CueFileType.Wave;
if (blobPathExt == ".mp3") cue_file.FileType = Cue.CueFileType.Wave;
if (blobPathExt == ".mpc") cue_file.FileType = Cue.CueFileType.Wave;
if (blobPathExt == ".flac") cue_file.FileType = Cue.CueFileType.Wave;
if (cue_file.FileType == Cue.CueFileType.Binary || cue_file.FileType == Cue.CueFileType.Unspecified)
{
//make a blob for the file
Blob_RawFile blob = new Blob_RawFile();
@ -89,10 +126,9 @@ namespace BizHawk.DiscSystem
blob_leftover = (int)(blob.Length - blob_length_aba * blob_sectorsize);
cue_blob = blob;
}
else throw new DiscReferenceException(blobPath, new InvalidOperationException("unknown cue file type: " + cue_file.StrFileType));
else throw new Exception("Internal error - Unhandled cue blob type");
//TODO - make CueTimestamp better, and also make it a struct, and also just make it DiscTimestamp
//TODO - mp3 decode
//start timekeeping for the blob. every time we hit an index, this will advance
int blob_timestamp = 0;

View File

@ -11,6 +11,10 @@ namespace BizHawk.DiscSystem
: base(string.Format("A disc attempted to reference a file which could not be accessed or loaded: {0}", fname),inner)
{
}
public DiscReferenceException(string fname, string extrainfo)
: base(string.Format("A disc attempted to reference a file which could not be accessed or loaded:\n\n{0}\n\n{1}", fname, extrainfo))
{
}
}
public class ProgressReport

View File

@ -452,10 +452,10 @@ namespace BizHawk.DiscSystem
}
}
public static Disc FromCuePath(string cuePath)
public static Disc FromCuePath(string cuePath, CueBinPrefs prefs)
{
var ret = new Disc();
ret.FromCuePathInternal(cuePath);
ret.FromCuePathInternal(cuePath, prefs);
ret.TOC.GeneratePoints();
ret.PopulateQSubchannel();
return ret;
@ -670,7 +670,17 @@ namespace BizHawk.DiscSystem
/// </summary>
public bool SingleSession;
//THIS IS WRONG-HEADED. track 1 index 0 must never equal index 1! apparently.
/// <summary>
/// enables various extension-aware behaviours.
/// enables auto-search for files with the same name but differing extension.
/// enables auto-detection of situations where cue blobfiles are indicating the wrong type in the cuefile
/// </summary>
public bool ExtensionAware = false;
/// <summary>
/// whenever we have a choice, use case sensitivity in searching for files
/// </summary>
public bool CaseSensitive = false;
/// <summary>
/// DO NOT CHANGE THIS! All sectors will be written with ECM data. It's a waste of space, but it is exact. (not completely supported yet)