[ARM]
This commit is contained in:
parent
5cd5e799a6
commit
510e52271b
|
@ -162,6 +162,11 @@ namespace BizHawk.Emulation.CPUs.ARM
|
|||
else opcode = opcode.Replace(crepl, CC_strings[_CurrentCond()]);
|
||||
}
|
||||
else opcode = opcode.Replace(crepl, "");
|
||||
|
||||
if(opcode.Contains("{.size}"))
|
||||
{
|
||||
opcode = opcode.Replace("<{.size}>","." + args[argindex++].ToString());
|
||||
}
|
||||
//---------
|
||||
|
||||
string cpcomment = null;
|
||||
|
@ -317,9 +322,26 @@ namespace BizHawk.Emulation.CPUs.ARM
|
|||
{
|
||||
item = "";
|
||||
cpcomment = args[argindex++] as string;
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -377,7 +377,7 @@ namespace BizHawk.Emulation.CPUs.ARM
|
|||
case _.b01000:
|
||||
case _.b01001:
|
||||
if (Rn != _.b1111) return Execute_ADD_immedate_arm_A1();
|
||||
else return Execute_Unhandled("arm adr");
|
||||
else return Execute_ADR_A1();
|
||||
case _.b01010:
|
||||
case _.b01011: return Execute_Unhandled("arm adc imm");
|
||||
case _.b01100:
|
||||
|
@ -413,13 +413,35 @@ namespace BizHawk.Emulation.CPUs.ARM
|
|||
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 == _.b1101) return Execute_SUB_SP_minus_immediate_A1();
|
||||
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_SUB_SP_minus_immediate_A1()
|
||||
{
|
||||
//A8.6.215
|
||||
uint d = Reg16(12);
|
||||
Bit S = _.BIT20(instruction);
|
||||
if (d == _.b1111 && S == 1) throw new NotImplementedException("SEE SUBS PC, LR and related instructions");
|
||||
bool setflags = (S == 1);
|
||||
uint imm12 = instruction & 0xFFF;
|
||||
uint imm32 = _ARMExpandImm(imm12);
|
||||
return ExecuteCore_SUB_SP_minus_immediate(Encoding.A1,d,setflags,imm32);
|
||||
}
|
||||
|
||||
uint Execute_ADR_A1()
|
||||
{
|
||||
//A8.6.10
|
||||
uint d = Reg16(12);
|
||||
uint imm12 = instruction & 0xFFF;
|
||||
uint imm32 = _ARMExpandImm(imm12);
|
||||
const bool add = true;
|
||||
return ExecuteCore_ADR(Encoding.A1, d, imm32, add);
|
||||
}
|
||||
|
||||
uint Execute_ADD_immedate_arm_A1()
|
||||
{
|
||||
Bit S = _.BIT20(instruction);
|
||||
|
@ -690,7 +712,7 @@ namespace BizHawk.Emulation.CPUs.ARM
|
|||
|
||||
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==#0xxxxx && op1!=#000x0x && coproc_special==#1", () => Execute_ExtensionRegister_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)"))
|
||||
|
@ -717,9 +739,85 @@ namespace BizHawk.Emulation.CPUs.ARM
|
|||
return 1;
|
||||
}
|
||||
|
||||
uint Execute_ExtensionRegister_LoadStore()
|
||||
{
|
||||
//A7.6 Extension register load/store instructions
|
||||
uint opcode = (instruction >> 20) & 0x1F;
|
||||
uint n = Reg16(16);
|
||||
bool bit8 = _.BIT8(instruction)==1;
|
||||
switch (opcode)
|
||||
{
|
||||
case _.b00100: case _.b00101: return Execute_Unhandled("64-bit transfers between ARM core and extension registers");
|
||||
case _.b01000: case _.b01100: return Execute_Unhandled("VSTM");
|
||||
case _.b01010: case _.b01110: return Execute_Unhandled("VSTM");
|
||||
case _.b10000: case _.b10100: case _.b11000: case _.b11100: return Execute_Unhandled("VSTR");
|
||||
case _.b10010: case _.b10110:
|
||||
if (n != _.b1101) return Execute_Unhandled("VSTM");
|
||||
else return bit8?Execute_VPUSH_A1():Execute_VPUSH_A2();
|
||||
case _.b01001: case _.b01101: return Execute_Unhandled("VLDM");
|
||||
case _.b01011: case _.b01111:
|
||||
if (n != _.b1101) return Execute_Unhandled("VLDM");
|
||||
else return Execute_Unhandled("VPOP");
|
||||
case _.b10001: case _.b10101: case _.b11001: case _.b11101:
|
||||
return bit8 ? Execute_VLDR_A1() : Execute_VLDR_A2();
|
||||
case _.b10011: case _.b10111: return Execute_Unhandled("VLDM");
|
||||
default: throw new InvalidOperationException("decoder fail");
|
||||
}
|
||||
}
|
||||
|
||||
uint Execute_VLDR_A1()
|
||||
{
|
||||
//A8.6.320
|
||||
throw new NotSupportedException("Execute_VLDR_A1");
|
||||
}
|
||||
|
||||
uint Execute_VLDR_A2()
|
||||
{
|
||||
//A8.6.320
|
||||
const bool single_reg = true;
|
||||
Bit U = _.BIT23(instruction);
|
||||
Bit D = _.BIT22(instruction);
|
||||
bool add = (U == 1);
|
||||
uint imm8 = instruction & 0xFF;
|
||||
uint imm32 = _ZeroExtend_32(imm8 << 2);
|
||||
uint Vd = Reg16(12);
|
||||
uint n = Reg16(0);
|
||||
uint d = (Vd << 1) | D;
|
||||
return ExecuteCore_VLDR(Encoding.A1, single_reg, add, d, n, imm32);
|
||||
}
|
||||
|
||||
uint Execute_VPUSH_A1()
|
||||
{
|
||||
//A8.6.355
|
||||
const bool single_regs = false;
|
||||
Bit D = _.BIT22(instruction);
|
||||
uint d = ((uint)D << 4) | Reg16(12);
|
||||
uint imm8 = instruction & 0xFF;
|
||||
uint imm32 = _ZeroExtend_32(imm8 << 2);
|
||||
uint regs = imm8 / 2;
|
||||
Debug.Assert(!((imm8&1)==1),"see FSTMX");
|
||||
if(regs==0 || regs>16 || (d+regs)>32) _FlagUnpredictable();
|
||||
return ExecuteCore_VPUSH(Encoding.A1, single_regs, d, regs, imm32);
|
||||
|
||||
}
|
||||
|
||||
uint Execute_VPUSH_A2()
|
||||
{
|
||||
//A8.6.355
|
||||
const bool single_regs = true;
|
||||
Bit D = _.BIT22(instruction);
|
||||
uint d = (Reg16(12)<<1)|D;
|
||||
uint imm8 = instruction & 0xFF;
|
||||
uint imm32 = _ZeroExtend_32(imm8 << 2);
|
||||
uint regs = imm8;
|
||||
if (regs == 0 || regs > 16 || (d + regs) > 32) _FlagUnpredictable();
|
||||
return ExecuteCore_VPUSH(Encoding.A2, single_regs, d, regs, imm32);
|
||||
}
|
||||
|
||||
uint Execute_MRC_MRC2_A1()
|
||||
{
|
||||
//ignoring admonition to see "advanced SIMD and VFP" which has been handled by decode earlier
|
||||
//TODO - but i should assert anyway
|
||||
uint t = Reg16(12);
|
||||
uint cp = Reg16(8);
|
||||
uint opc1 = Reg8(21);
|
||||
|
|
|
@ -376,6 +376,34 @@ namespace BizHawk.Emulation.CPUs.ARM
|
|||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.60 LDR (register)
|
||||
uint ExecuteCore_LDR_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("LDR<c>", t, n, m, shift_t, shift_n, index, add, wback);
|
||||
|
||||
_NullCheckIfThumbEE(n);
|
||||
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];
|
||||
uint data = MemU_Read32(address);
|
||||
if (wback) r[n] = offset_addr;
|
||||
if (t == 15)
|
||||
{
|
||||
if ((address & 3) == _.b00) _LoadWritePC(data);
|
||||
else _FlagUnpredictable();
|
||||
}
|
||||
else if (_UnalignedSupport() || (address & 3) == _.b00)
|
||||
r[t] = data;
|
||||
else //can only apply before ARMv7
|
||||
if (_CurrentInstrSet() == EInstrSet.ARM)
|
||||
r[t] = _ROR(data, 8 * ((int)address & 3));
|
||||
else
|
||||
r[t] = (uint)_UNKNOWN(32, _ROR(data, 8 * ((int)address & 3)));
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -979,6 +1007,12 @@ namespace BizHawk.Emulation.CPUs.ARM
|
|||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.320 VLDR
|
||||
uint ExecuteCore_VLDR(Encoding encoding, bool single_reg, bool add, uint d, uint n, uint imm32)
|
||||
{
|
||||
throw new NotImplementedException("TODO");
|
||||
}
|
||||
|
||||
//A8.6.336 VMSR
|
||||
uint ExecuteCore_VMSR(uint t)
|
||||
{
|
||||
|
@ -989,6 +1023,33 @@ namespace BizHawk.Emulation.CPUs.ARM
|
|||
return 1;
|
||||
}
|
||||
|
||||
//A8.6.355 VPUSH
|
||||
uint ExecuteCore_VPUSH(Encoding encoding, bool single_regs, uint d, uint regs, uint imm32)
|
||||
{
|
||||
if (disassemble)
|
||||
return DISNEW("VPUSH<c><{.size}>", "<list>", single_regs ? 32 : 64, single_regs, d, regs);
|
||||
|
||||
_CheckVFPEnabled(true);
|
||||
_NullCheckIfThumbEE(13);
|
||||
|
||||
uint address = SP - imm32;
|
||||
SP = SP - imm32;
|
||||
if (single_regs)
|
||||
for (uint r = 0; r <= regs-1; r++)
|
||||
{
|
||||
MemA_WriteSingle(address, S[d+r]);
|
||||
address += 4;
|
||||
}
|
||||
else
|
||||
for (uint r = 0; r <= regs - 1; r++)
|
||||
{
|
||||
MemA_WriteDouble(address, D[d+r]);
|
||||
address += 8;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//unnecessary opcodes: BKPT, BXJ, CBNZ, CHKA, NOP, CPY, DBG, ENTERX, HB, IT, LDRBT, LDRHT, LDRSBT, LDRSHT, LEAVEX, RBIT, SBFX, SDIV, TBB
|
||||
|
|
|
@ -127,7 +127,7 @@ namespace BizHawk.Emulation.CPUs.ARM
|
|||
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 _.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");
|
||||
|
@ -201,6 +201,19 @@ namespace BizHawk.Emulation.CPUs.ARM
|
|||
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
|
||||
|
|
|
@ -101,6 +101,19 @@ namespace BizHawk.Emulation.CPUs.ARM
|
|||
return true;
|
||||
}
|
||||
|
||||
void MemA_WriteSingle(uint addr, float val)
|
||||
{
|
||||
MemA_Write32(addr,float_downcast(val));
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -181,6 +194,8 @@ namespace BizHawk.Emulation.CPUs.ARM
|
|||
_BranchTo((uint)(address & ~1));
|
||||
}
|
||||
|
||||
bool _BigEndian() { return false; }
|
||||
|
||||
void _BranchTo(uint address)
|
||||
{
|
||||
_R[15] = address;
|
||||
|
|
|
@ -105,12 +105,27 @@ namespace BizHawk.Emulation.CPUs.ARM
|
|||
}
|
||||
}
|
||||
|
||||
//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;
|
||||
|
||||
float[] S = new float[32];
|
||||
double[] D = new double[16];
|
||||
|
||||
unsafe uint float_downcast(float f)
|
||||
{
|
||||
float* fp = &f;
|
||||
return *(uint*)fp;
|
||||
}
|
||||
|
||||
unsafe ulong double_downcast(double f)
|
||||
{
|
||||
double* fp = &f;
|
||||
return *(ulong*)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; } }
|
||||
|
|
Loading…
Reference in New Issue