|
|
@@ -37,296 +37,18 @@ unsigned VFPInit(ARMul_State* state)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-unsigned VFPMRC(ARMul_State* state, unsigned type, u32 instr, u32* value)
|
|
|
-{
|
|
|
- /* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
|
|
|
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
|
|
|
- int OPC_1 = BITS(instr, 21, 23);
|
|
|
- int Rt = BITS(instr, 12, 15);
|
|
|
- int CRn = BITS(instr, 16, 19);
|
|
|
- int CRm = BITS(instr, 0, 3);
|
|
|
- int OPC_2 = BITS(instr, 5, 7);
|
|
|
-
|
|
|
- /* TODO check access permission */
|
|
|
-
|
|
|
- /* CRn/opc1 CRm/opc2 */
|
|
|
-
|
|
|
- if (CoProc == 10 || CoProc == 11)
|
|
|
- {
|
|
|
- if (OPC_1 == 0x0 && CRm == 0 && (OPC_2 & 0x3) == 0)
|
|
|
- {
|
|
|
- /* VMOV r to s */
|
|
|
- /* Transfering Rt is not mandatory, as the value of interest is pointed by value */
|
|
|
- VMOVBRS(state, BIT(instr, 20), Rt, BIT(instr, 7)|CRn<<1, value);
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
-
|
|
|
- if (OPC_1 == 0x7 && CRm == 0 && OPC_2 == 0)
|
|
|
- {
|
|
|
- VMRS(state, CRn, Rt, value);
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- }
|
|
|
- LOG_WARNING(Core_ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
|
|
|
- instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
|
|
|
-
|
|
|
- return ARMul_CANT;
|
|
|
-}
|
|
|
-
|
|
|
-unsigned VFPMCR(ARMul_State* state, unsigned type, u32 instr, u32 value)
|
|
|
-{
|
|
|
- /* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
|
|
|
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
|
|
|
- int OPC_1 = BITS(instr, 21, 23);
|
|
|
- int Rt = BITS(instr, 12, 15);
|
|
|
- int CRn = BITS(instr, 16, 19);
|
|
|
- int CRm = BITS(instr, 0, 3);
|
|
|
- int OPC_2 = BITS(instr, 5, 7);
|
|
|
-
|
|
|
- /* TODO check access permission */
|
|
|
-
|
|
|
- /* CRn/opc1 CRm/opc2 */
|
|
|
- if (CoProc == 10 || CoProc == 11)
|
|
|
- {
|
|
|
- if (OPC_1 == 0x0 && CRm == 0 && (OPC_2 & 0x3) == 0)
|
|
|
- {
|
|
|
- /* VMOV s to r */
|
|
|
- /* Transfering Rt is not mandatory, as the value of interest is pointed by value */
|
|
|
- VMOVBRS(state, BIT(instr, 20), Rt, BIT(instr, 7)|CRn<<1, &value);
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
-
|
|
|
- if (OPC_1 == 0x7 && CRm == 0 && OPC_2 == 0)
|
|
|
- {
|
|
|
- VMSR(state, CRn, Rt);
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
-
|
|
|
- if ((OPC_1 & 0x4) == 0 && CoProc == 11 && CRm == 0)
|
|
|
- {
|
|
|
- VFP_DEBUG_UNIMPLEMENTED(VMOVBRC);
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
-
|
|
|
- if (CoProc == 11 && CRm == 0)
|
|
|
- {
|
|
|
- VFP_DEBUG_UNIMPLEMENTED(VMOVBCR);
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- }
|
|
|
- LOG_WARNING(Core_ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
|
|
|
- instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
|
|
|
-
|
|
|
- return ARMul_CANT;
|
|
|
-}
|
|
|
-
|
|
|
-unsigned VFPMRRC(ARMul_State* state, unsigned type, u32 instr, u32* value1, u32* value2)
|
|
|
-{
|
|
|
- /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
|
|
|
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
|
|
|
- int OPC_1 = BITS(instr, 4, 7);
|
|
|
- int Rt = BITS(instr, 12, 15);
|
|
|
- int Rt2 = BITS(instr, 16, 19);
|
|
|
- int CRm = BITS(instr, 0, 3);
|
|
|
-
|
|
|
- if (CoProc == 10 || CoProc == 11)
|
|
|
- {
|
|
|
- if (CoProc == 10 && (OPC_1 & 0xD) == 1)
|
|
|
- {
|
|
|
- VMOVBRRSS(state, BIT(instr, 20), Rt, Rt2, BIT(instr, 5)<<4|CRm, value1, value2);
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
-
|
|
|
- if (CoProc == 11 && (OPC_1 & 0xD) == 1)
|
|
|
- {
|
|
|
- /* Transfering Rt and Rt2 is not mandatory, as the value of interest is pointed by value1 and value2 */
|
|
|
- VMOVBRRD(state, BIT(instr, 20), Rt, Rt2, BIT(instr, 5)<<4|CRm, value1, value2);
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- }
|
|
|
- LOG_WARNING(Core_ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
|
|
|
- instr, CoProc, OPC_1, Rt, Rt2, CRm);
|
|
|
-
|
|
|
- return ARMul_CANT;
|
|
|
-}
|
|
|
-
|
|
|
-unsigned VFPMCRR(ARMul_State* state, unsigned type, u32 instr, u32 value1, u32 value2)
|
|
|
-{
|
|
|
- /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
|
|
|
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
|
|
|
- int OPC_1 = BITS(instr, 4, 7);
|
|
|
- int Rt = BITS(instr, 12, 15);
|
|
|
- int Rt2 = BITS(instr, 16, 19);
|
|
|
- int CRm = BITS(instr, 0, 3);
|
|
|
-
|
|
|
- /* TODO check access permission */
|
|
|
-
|
|
|
- /* CRn/opc1 CRm/opc2 */
|
|
|
-
|
|
|
- if (CoProc == 11 || CoProc == 10)
|
|
|
- {
|
|
|
- if (CoProc == 10 && (OPC_1 & 0xD) == 1)
|
|
|
- {
|
|
|
- VMOVBRRSS(state, BIT(instr, 20), Rt, Rt2, BIT(instr, 5)<<4|CRm, &value1, &value2);
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
-
|
|
|
- if (CoProc == 11 && (OPC_1 & 0xD) == 1)
|
|
|
- {
|
|
|
- /* Transfering Rt and Rt2 is not mandatory, as the value of interest is pointed by value1 and value2 */
|
|
|
- VMOVBRRD(state, BIT(instr, 20), Rt, Rt2, BIT(instr, 5)<<4|CRm, &value1, &value2);
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- }
|
|
|
- LOG_WARNING(Core_ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
|
|
|
- instr, CoProc, OPC_1, Rt, Rt2, CRm);
|
|
|
-
|
|
|
- return ARMul_CANT;
|
|
|
-}
|
|
|
-
|
|
|
-unsigned VFPSTC(ARMul_State* state, unsigned type, u32 instr, u32 * value)
|
|
|
-{
|
|
|
- /* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */
|
|
|
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
|
|
|
- int CRd = BITS(instr, 12, 15);
|
|
|
- int Rn = BITS(instr, 16, 19);
|
|
|
- int imm8 = BITS(instr, 0, 7);
|
|
|
- int P = BIT(instr, 24);
|
|
|
- int U = BIT(instr, 23);
|
|
|
- int D = BIT(instr, 22);
|
|
|
- int W = BIT(instr, 21);
|
|
|
-
|
|
|
- /* TODO check access permission */
|
|
|
-
|
|
|
- /* VSTM */
|
|
|
- if ( (P|U|D|W) == 0 ) {
|
|
|
- LOG_ERROR(Core_ARM11, "In %s, UNDEFINED\n", __FUNCTION__);
|
|
|
- exit(-1);
|
|
|
- }
|
|
|
- if (CoProc == 10 || CoProc == 11) {
|
|
|
-#if 1
|
|
|
- if (P == 0 && U == 0 && W == 0) {
|
|
|
- LOG_ERROR(Core_ARM11, "VSTM Related encodings\n");
|
|
|
- exit(-1);
|
|
|
- }
|
|
|
- if (P == U && W == 1) {
|
|
|
- LOG_ERROR(Core_ARM11, "UNDEFINED\n");
|
|
|
- exit(-1);
|
|
|
- }
|
|
|
-#endif
|
|
|
-
|
|
|
- if (P == 1 && W == 0)
|
|
|
- {
|
|
|
- return VSTR(state, type, instr, value);
|
|
|
- }
|
|
|
-
|
|
|
- if (P == 1 && U == 0 && W == 1 && Rn == 0xD)
|
|
|
- {
|
|
|
- return VPUSH(state, type, instr, value);
|
|
|
- }
|
|
|
-
|
|
|
- return VSTM(state, type, instr, value);
|
|
|
- }
|
|
|
- LOG_WARNING(Core_ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
|
|
|
- instr, CoProc, CRd, Rn, imm8, P, U, D, W);
|
|
|
-
|
|
|
- return ARMul_CANT;
|
|
|
-}
|
|
|
-
|
|
|
-unsigned VFPLDC(ARMul_State* state, unsigned type, u32 instr, u32 value)
|
|
|
+void VMSR(ARMul_State* state, ARMword reg, ARMword Rt)
|
|
|
{
|
|
|
- /* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */
|
|
|
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
|
|
|
- int CRd = BITS(instr, 12, 15);
|
|
|
- int Rn = BITS(instr, 16, 19);
|
|
|
- int imm8 = BITS(instr, 0, 7);
|
|
|
- int P = BIT(instr, 24);
|
|
|
- int U = BIT(instr, 23);
|
|
|
- int D = BIT(instr, 22);
|
|
|
- int W = BIT(instr, 21);
|
|
|
-
|
|
|
- /* TODO check access permission */
|
|
|
-
|
|
|
- if ( (P|U|D|W) == 0 ) {
|
|
|
- LOG_ERROR(Core_ARM11, "In %s, UNDEFINED\n", __FUNCTION__);
|
|
|
- exit(-1);
|
|
|
- }
|
|
|
- if (CoProc == 10 || CoProc == 11)
|
|
|
+ if (reg == 1)
|
|
|
{
|
|
|
- if (P == 1 && W == 0)
|
|
|
- {
|
|
|
- return VLDR(state, type, instr, value);
|
|
|
- }
|
|
|
-
|
|
|
- if (P == 0 && U == 1 && W == 1 && Rn == 0xD)
|
|
|
- {
|
|
|
- return VPOP(state, type, instr, value);
|
|
|
- }
|
|
|
-
|
|
|
- return VLDM(state, type, instr, value);
|
|
|
+ state->VFP[VFP_FPSCR] = state->Reg[Rt];
|
|
|
}
|
|
|
- LOG_WARNING(Core_ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
|
|
|
- instr, CoProc, CRd, Rn, imm8, P, U, D, W);
|
|
|
-
|
|
|
- return ARMul_CANT;
|
|
|
-}
|
|
|
-
|
|
|
-unsigned VFPCDP(ARMul_State* state, unsigned type, u32 instr)
|
|
|
-{
|
|
|
- /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */
|
|
|
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
|
|
|
- int OPC_1 = BITS(instr, 20, 23);
|
|
|
- int CRd = BITS(instr, 12, 15);
|
|
|
- int CRn = BITS(instr, 16, 19);
|
|
|
- int CRm = BITS(instr, 0, 3);
|
|
|
- int OPC_2 = BITS(instr, 5, 7);
|
|
|
-
|
|
|
- /* TODO check access permission */
|
|
|
-
|
|
|
- /* CRn/opc1 CRm/opc2 */
|
|
|
-
|
|
|
- if (CoProc == 10 || CoProc == 11)
|
|
|
+ else if (reg == 8)
|
|
|
{
|
|
|
- if ((OPC_1 & 0xB) == 0xB && BITS(instr, 4, 7) == 0)
|
|
|
- {
|
|
|
- unsigned int single = BIT(instr, 8) == 0;
|
|
|
- unsigned int d = (single ? BITS(instr, 12,15)<<1 | BIT(instr, 22) : BITS(instr, 12,15) | BIT(instr, 22)<<4);
|
|
|
- unsigned int imm;
|
|
|
- instr = BITS(instr, 16, 19) << 4 | BITS(instr, 0, 3); // FIXME dirty workaround to get a correct imm
|
|
|
-
|
|
|
- if (single)
|
|
|
- imm = BIT(instr, 7)<<31 | (BIT(instr, 6)==0)<<30 | (BIT(instr, 6) ? 0x1f : 0)<<25 | BITS(instr, 0, 5)<<19;
|
|
|
- else
|
|
|
- imm = BIT(instr, 7)<<31 | (BIT(instr, 6)==0)<<30 | (BIT(instr, 6) ? 0xff : 0)<<22 | BITS(instr, 0, 5)<<16;
|
|
|
-
|
|
|
- VMOVI(state, single, d, imm);
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
-
|
|
|
- if ((OPC_1 & 0xB) == 0xB && CRn == 0 && (OPC_2 & 0x6) == 0x2)
|
|
|
- {
|
|
|
- unsigned int single = BIT(instr, 8) == 0;
|
|
|
- unsigned int d = (single ? BITS(instr, 12,15)<<1 | BIT(instr, 22) : BITS(instr, 12,15) | BIT(instr, 22)<<4);
|
|
|
- unsigned int m = (single ? BITS(instr, 0, 3)<<1 | BIT(instr, 5) : BITS(instr, 0, 3) | BIT(instr, 5)<<4);
|
|
|
- VMOVR(state, single, d, m);
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
-
|
|
|
- int exceptions = 0;
|
|
|
- if (CoProc == 10)
|
|
|
- exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_FPSCR]);
|
|
|
- else
|
|
|
- exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_FPSCR]);
|
|
|
-
|
|
|
- vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_FPSCR]);
|
|
|
-
|
|
|
- return ARMul_DONE;
|
|
|
+ state->VFP[VFP_FPEXC] = state->Reg[Rt];
|
|
|
}
|
|
|
- LOG_WARNING(Core_ARM11, "Can't identify %x\n", instr);
|
|
|
- return ARMul_CANT;
|
|
|
}
|
|
|
|
|
|
-/* ----------- MRC ------------ */
|
|
|
void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value)
|
|
|
{
|
|
|
if (to_arm)
|
|
|
@@ -338,43 +60,7 @@ void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword*
|
|
|
state->ExtReg[n] = *value;
|
|
|
}
|
|
|
}
|
|
|
-void VMRS(ARMul_State* state, ARMword reg, ARMword Rt, ARMword* value)
|
|
|
-{
|
|
|
- if (reg == 1)
|
|
|
- {
|
|
|
- if (Rt != 15)
|
|
|
- {
|
|
|
- *value = state->VFP[VFP_FPSCR];
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- *value = state->VFP[VFP_FPSCR] ;
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- switch (reg)
|
|
|
- {
|
|
|
- case 0:
|
|
|
- *value = state->VFP[VFP_FPSID];
|
|
|
- break;
|
|
|
- case 6:
|
|
|
- /* MVFR1, VFPv3 only ? */
|
|
|
- LOG_TRACE(Core_ARM11, "\tr%d <= MVFR1 unimplemented\n", Rt);
|
|
|
- break;
|
|
|
- case 7:
|
|
|
- /* MVFR0, VFPv3 only? */
|
|
|
- LOG_TRACE(Core_ARM11, "\tr%d <= MVFR0 unimplemented\n", Rt);
|
|
|
- break;
|
|
|
- case 8:
|
|
|
- *value = state->VFP[VFP_FPEXC];
|
|
|
- break;
|
|
|
- default:
|
|
|
- LOG_TRACE(Core_ARM11, "\tSUBARCHITECTURE DEFINED\n");
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
+
|
|
|
void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2)
|
|
|
{
|
|
|
if (to_arm)
|
|
|
@@ -402,301 +88,6 @@ void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMwor
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/* ----------- MCR ------------ */
|
|
|
-void VMSR(ARMul_State* state, ARMword reg, ARMword Rt)
|
|
|
-{
|
|
|
- if (reg == 1)
|
|
|
- {
|
|
|
- state->VFP[VFP_FPSCR] = state->Reg[Rt];
|
|
|
- }
|
|
|
- else if (reg == 8)
|
|
|
- {
|
|
|
- state->VFP[VFP_FPEXC] = state->Reg[Rt];
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/* Memory operation are not inlined, as old Interpreter and Fast interpreter
|
|
|
- don't have the same memory operation interface.
|
|
|
- Old interpreter framework does one access to coprocessor per data, and
|
|
|
- handles already data write, as well as address computation,
|
|
|
- which is not the case for Fast interpreter. Therefore, implementation
|
|
|
- of vfp instructions in old interpreter and fast interpreter are separate. */
|
|
|
-
|
|
|
-/* ----------- STC ------------ */
|
|
|
-int VSTR(ARMul_State* state, int type, ARMword instr, ARMword* value)
|
|
|
-{
|
|
|
- static int i = 0;
|
|
|
- static int single_reg, add, d, n, imm32, regs;
|
|
|
- if (type == ARMul_FIRST)
|
|
|
- {
|
|
|
- single_reg = BIT(instr, 8) == 0; // Double precision
|
|
|
- add = BIT(instr, 23);
|
|
|
- imm32 = BITS(instr, 0,7)<<2; // may not be used
|
|
|
- d = single_reg ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); /* Base register */
|
|
|
- n = BITS(instr, 16, 19); // destination register
|
|
|
-
|
|
|
- i = 0;
|
|
|
- regs = 1;
|
|
|
-
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- else if (type == ARMul_DATA)
|
|
|
- {
|
|
|
- if (single_reg)
|
|
|
- {
|
|
|
- *value = state->ExtReg[d+i];
|
|
|
- i++;
|
|
|
- if (i < regs)
|
|
|
- return ARMul_INC;
|
|
|
- else
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- /* FIXME Careful of endianness, may need to rework this */
|
|
|
- *value = state->ExtReg[d*2+i];
|
|
|
- i++;
|
|
|
- if (i < regs*2)
|
|
|
- return ARMul_INC;
|
|
|
- else
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return -1;
|
|
|
-}
|
|
|
-int VPUSH(ARMul_State* state, int type, ARMword instr, ARMword* value)
|
|
|
-{
|
|
|
- static int i = 0;
|
|
|
- static int single_regs, d, imm32, regs;
|
|
|
- if (type == ARMul_FIRST)
|
|
|
- {
|
|
|
- single_regs = BIT(instr, 8) == 0; // Single precision
|
|
|
- d = single_regs ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); // Base register
|
|
|
- imm32 = BITS(instr, 0,7)<<2; // may not be used
|
|
|
- regs = single_regs ? BITS(instr, 0, 7) : BITS(instr, 1, 7); // FSTMX if regs is odd
|
|
|
-
|
|
|
- state->Reg[R13] = state->Reg[R13] - imm32;
|
|
|
-
|
|
|
- i = 0;
|
|
|
-
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- else if (type == ARMul_DATA)
|
|
|
- {
|
|
|
- if (single_regs)
|
|
|
- {
|
|
|
- *value = state->ExtReg[d + i];
|
|
|
- i++;
|
|
|
- if (i < regs)
|
|
|
- return ARMul_INC;
|
|
|
- else
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- /* FIXME Careful of endianness, may need to rework this */
|
|
|
- *value = state->ExtReg[d*2 + i];
|
|
|
- i++;
|
|
|
- if (i < regs*2)
|
|
|
- return ARMul_INC;
|
|
|
- else
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return -1;
|
|
|
-}
|
|
|
-int VSTM(ARMul_State* state, int type, ARMword instr, ARMword* value)
|
|
|
-{
|
|
|
- static int i = 0;
|
|
|
- static int single_regs, add, wback, d, n, imm32, regs;
|
|
|
- if (type == ARMul_FIRST)
|
|
|
- {
|
|
|
- single_regs = BIT(instr, 8) == 0; // Single precision
|
|
|
- add = BIT(instr, 23);
|
|
|
- wback = BIT(instr, 21); // write-back
|
|
|
- d = single_regs ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); // Base register
|
|
|
- n = BITS(instr, 16, 19); // destination register
|
|
|
- imm32 = BITS(instr, 0,7) * 4; // may not be used
|
|
|
- regs = single_regs ? BITS(instr, 0, 7) : BITS(instr, 0, 7)>>1; // FSTMX if regs is odd
|
|
|
-
|
|
|
- if (wback) {
|
|
|
- state->Reg[n] = (add ? state->Reg[n] + imm32 : state->Reg[n] - imm32);
|
|
|
- }
|
|
|
-
|
|
|
- i = 0;
|
|
|
-
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- else if (type == ARMul_DATA)
|
|
|
- {
|
|
|
- if (single_regs)
|
|
|
- {
|
|
|
- *value = state->ExtReg[d + i];
|
|
|
- i++;
|
|
|
- if (i < regs)
|
|
|
- return ARMul_INC;
|
|
|
- else
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- /* FIXME Careful of endianness, may need to rework this */
|
|
|
- *value = state->ExtReg[d*2 + i];
|
|
|
- i++;
|
|
|
- if (i < regs*2)
|
|
|
- return ARMul_INC;
|
|
|
- else
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return -1;
|
|
|
-}
|
|
|
-
|
|
|
-/* ----------- LDC ------------ */
|
|
|
-int VPOP(ARMul_State* state, int type, ARMword instr, ARMword value)
|
|
|
-{
|
|
|
- static int i = 0;
|
|
|
- static int single_regs, d, imm32, regs;
|
|
|
- if (type == ARMul_FIRST)
|
|
|
- {
|
|
|
- single_regs = BIT(instr, 8) == 0; // Single precision
|
|
|
- d = single_regs ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); // Base register
|
|
|
- imm32 = BITS(instr, 0, 7)<<2; // may not be used
|
|
|
- regs = single_regs ? BITS(instr, 0, 7) : BITS(instr, 1, 7); // FLDMX if regs is odd
|
|
|
-
|
|
|
- state->Reg[R13] = state->Reg[R13] + imm32;
|
|
|
-
|
|
|
- i = 0;
|
|
|
-
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- else if (type == ARMul_TRANSFER)
|
|
|
- {
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- else if (type == ARMul_DATA)
|
|
|
- {
|
|
|
- if (single_regs)
|
|
|
- {
|
|
|
- state->ExtReg[d + i] = value;
|
|
|
- i++;
|
|
|
- if (i < regs)
|
|
|
- return ARMul_INC;
|
|
|
- else
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- /* FIXME Careful of endianness, may need to rework this */
|
|
|
- state->ExtReg[d*2 + i] = value;
|
|
|
- i++;
|
|
|
- if (i < regs*2)
|
|
|
- return ARMul_INC;
|
|
|
- else
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return -1;
|
|
|
-}
|
|
|
-int VLDR(ARMul_State* state, int type, ARMword instr, ARMword value)
|
|
|
-{
|
|
|
- static int i = 0;
|
|
|
- static int single_reg, add, d, n, imm32, regs;
|
|
|
- if (type == ARMul_FIRST)
|
|
|
- {
|
|
|
- single_reg = BIT(instr, 8) == 0; // Double precision
|
|
|
- add = BIT(instr, 23);
|
|
|
- imm32 = BITS(instr, 0, 7)<<2; // may not be used
|
|
|
- d = single_reg ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); // Base register
|
|
|
- n = BITS(instr, 16, 19); // destination register
|
|
|
-
|
|
|
- i = 0;
|
|
|
- regs = 1;
|
|
|
-
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- else if (type == ARMul_TRANSFER)
|
|
|
- {
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- else if (type == ARMul_DATA)
|
|
|
- {
|
|
|
- if (single_reg)
|
|
|
- {
|
|
|
- state->ExtReg[d+i] = value;
|
|
|
- i++;
|
|
|
- if (i < regs)
|
|
|
- return ARMul_INC;
|
|
|
- else
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- /* FIXME Careful of endianness, may need to rework this */
|
|
|
- state->ExtReg[d*2+i] = value;
|
|
|
- i++;
|
|
|
- if (i < regs*2)
|
|
|
- return ARMul_INC;
|
|
|
- else
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return -1;
|
|
|
-}
|
|
|
-int VLDM(ARMul_State* state, int type, ARMword instr, ARMword value)
|
|
|
-{
|
|
|
- static int i = 0;
|
|
|
- static int single_regs, add, wback, d, n, imm32, regs;
|
|
|
- if (type == ARMul_FIRST)
|
|
|
- {
|
|
|
- single_regs = BIT(instr, 8) == 0; // Single precision
|
|
|
- add = BIT(instr, 23);
|
|
|
- wback = BIT(instr, 21); // write-back
|
|
|
- d = single_regs ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); // Base register
|
|
|
- n = BITS(instr, 16, 19); // destination register
|
|
|
- imm32 = BITS(instr, 0, 7) * 4; // may not be used
|
|
|
- regs = single_regs ? BITS(instr, 0, 7) : BITS(instr, 0, 7)>>1; // FLDMX if regs is odd
|
|
|
-
|
|
|
- if (wback) {
|
|
|
- state->Reg[n] = (add ? state->Reg[n] + imm32 : state->Reg[n] - imm32);
|
|
|
- }
|
|
|
-
|
|
|
- i = 0;
|
|
|
-
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- else if (type == ARMul_DATA)
|
|
|
- {
|
|
|
- if (single_regs)
|
|
|
- {
|
|
|
- state->ExtReg[d + i] = value;
|
|
|
- i++;
|
|
|
- if (i < regs)
|
|
|
- return ARMul_INC;
|
|
|
- else
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- /* FIXME Careful of endianness, may need to rework this */
|
|
|
- state->ExtReg[d*2 + i] = value;
|
|
|
- i++;
|
|
|
- if (i < regs*2)
|
|
|
- return ARMul_INC;
|
|
|
- else
|
|
|
- return ARMul_DONE;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return -1;
|
|
|
-}
|
|
|
-
|
|
|
-/* ----------- CDP ------------ */
|
|
|
void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm)
|
|
|
{
|
|
|
if (single)
|