mirror of
https://github.com/RKX1209/nsemu.git
synced 2024-06-22 22:22:34 -04:00
Add support of Dup operation for SIMD
This commit is contained in:
parent
c1ec38a76c
commit
0d9d94f1ec
|
@ -15,6 +15,19 @@ static inline bool FpAccessCheck(uint32_t insn) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Currently used only fo disassemble fo SIMD operations */
|
||||
static inline A64DecodeFn *LookupDisasFn(const A64DecodeTable *table,
|
||||
uint32_t insn) {
|
||||
const A64DecodeTable *tptr = table;
|
||||
while (tptr->mask) {
|
||||
if ((insn & tptr->mask) == tptr->pattern) {
|
||||
return tptr->disas_fn;
|
||||
}
|
||||
tptr++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool LogicImmDecode(uint64_t *wmask, unsigned int immn, unsigned int imms, unsigned int immr) {
|
||||
assert (immn < 2 && imms < 64 && immr < 64);
|
||||
uint64_t mask;
|
||||
|
@ -204,13 +217,11 @@ static void DisasBitfield(uint32_t insn, DisasCallback *cb) {
|
|||
|
||||
if (opc == 1) { /* BFM, BXFIL */
|
||||
cb->DepositReg (rd, rd, pos, len, is_64bit);
|
||||
//UnsupportedOp ("BFM/BXFIL");
|
||||
} else {
|
||||
/* SBFM or UBFM: We start with zero, and we haven't modified
|
||||
any bits outside bitsize, therefore the zero-extension
|
||||
below is unneeded. */
|
||||
cb->DepositZeroReg (rd, rd, pos, len, is_64bit);
|
||||
//UnsupportedOp ("SBFM/UBFM");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -722,7 +733,8 @@ static void DisasLdLit(uint32_t insn, DisasCallback *cb) {
|
|||
bool is_signed = false;
|
||||
int size = 2;
|
||||
if (is_vector) {
|
||||
UnsupportedOp("LDR (SIMD&FP)");
|
||||
/* LDR (SIMD&FP) */
|
||||
size = opc + 2;
|
||||
} else {
|
||||
if (opc == 3) {
|
||||
return;
|
||||
|
@ -730,7 +742,8 @@ static void DisasLdLit(uint32_t insn, DisasCallback *cb) {
|
|||
size = 2 + extract32(opc, 0, 1);
|
||||
is_signed = extract32(opc, 1, 1);
|
||||
}
|
||||
cb->LoadRegI64 (rt, PC_IDX, imm - 4, size, false, false);
|
||||
cb->AddI64 (rt, PC_IDX, imm - 4, false, true);
|
||||
cb->LoadRegI64 (rt, rt, size, false);
|
||||
}
|
||||
|
||||
static bool DisasLdstCompute64bit(unsigned int size, bool is_signed, unsigned int opc) {
|
||||
|
@ -765,7 +778,9 @@ static void DisasLdstRegRoffset(uint32_t insn, DisasCallback *cb,
|
|||
}
|
||||
|
||||
if (is_vector) {
|
||||
UnsupportedOp ("LDR/STR [base, Xm/Wm] (SIMD&FP)");
|
||||
/* "LDR/STR [base, Xm/Wm] (SIMD&FP)") */
|
||||
size = (opc & 2) << 1;
|
||||
is_store = !extract32(opc, 0, 1);
|
||||
} else {
|
||||
if (size == 3 && opc == 2) {
|
||||
/* PRFM - prefetch */
|
||||
|
@ -799,7 +814,7 @@ static void DisasLdstRegImm9(uint32_t insn, DisasCallback *cb,
|
|||
unsigned int size,
|
||||
unsigned int rt,
|
||||
bool is_vector) {
|
||||
unsigned int rn = extract32(insn, 5, 5);
|
||||
unsigned int rn = ARMv8::HandleAsSP (extract32(insn, 5, 5));
|
||||
uint64_t imm9 = sextract32(insn, 12, 9);
|
||||
unsigned int idx = extract32(insn, 10, 2);
|
||||
bool is_signed = false;
|
||||
|
@ -813,7 +828,13 @@ static void DisasLdstRegImm9(uint32_t insn, DisasCallback *cb,
|
|||
//debug_print ("ldst uimm9\n");
|
||||
|
||||
if (is_vector) {
|
||||
UnsupportedOp ("LDR/STR [base, #imm9] (SIMD&FP)");
|
||||
/* LDR/STR [base, #imm9] (SIMD&FP) */
|
||||
size |= (opc & 2) << 1;
|
||||
if (size > 4 && is_unpriv) {
|
||||
UnallocatedOp (insn);
|
||||
return;
|
||||
}
|
||||
is_store = ((opc & 1) == 0);
|
||||
} else {
|
||||
if (size == 3 && opc == 2) {
|
||||
/* PRFM - prefetch */
|
||||
|
@ -849,10 +870,15 @@ static void DisasLdstRegImm9(uint32_t insn, DisasCallback *cb,
|
|||
default:
|
||||
ns_abort ("Unreachable status\n");
|
||||
}
|
||||
|
||||
cb->MovReg (GPR_DUMMY, rn, true);
|
||||
if (!post_index) {
|
||||
cb->AddI64 (GPR_DUMMY, rn, imm9, false, true);
|
||||
}
|
||||
if (is_store) {
|
||||
cb->StoreRegI64 (rt, rn, imm9, size, is_extended, post_index);
|
||||
cb->StoreRegI64 (rt, GPR_DUMMY, size, is_extended);
|
||||
} else {
|
||||
cb->LoadRegI64 (rt, rn, imm9, size, is_extended, post_index);
|
||||
cb->LoadRegI64 (rt, GPR_DUMMY, size, is_extended);
|
||||
}
|
||||
if (writeback) {
|
||||
cb->AddI64 (rn, rn, imm9, false, true);
|
||||
|
@ -864,7 +890,7 @@ static void DisasLdstRegUnsignedImm(uint32_t insn, DisasCallback *cb,
|
|||
unsigned int size,
|
||||
unsigned int rt,
|
||||
bool is_vector) {
|
||||
unsigned int rn = extract32(insn, 5, 5);
|
||||
unsigned int rn = ARMv8::HandleAsSP (extract32(insn, 5, 5));
|
||||
uint64_t imm12 = extract32(insn, 10, 12);
|
||||
uint64_t offset;
|
||||
|
||||
|
@ -897,19 +923,20 @@ static void DisasLdstRegUnsignedImm(uint32_t insn, DisasCallback *cb,
|
|||
is_extended = (size < 3) && extract32(opc, 0, 1);
|
||||
}
|
||||
offset = imm12 << size;
|
||||
cb->AddI64 (GPR_DUMMY, rn, offset, false, true);
|
||||
if (is_vector) {
|
||||
/* size must be 4 (128-bit) */
|
||||
if (is_store) {
|
||||
cb->StoreRegI64 (rt, rn, offset, size, false, false);
|
||||
cb->StoreRegI64 (rt, GPR_DUMMY, size, false);
|
||||
} else {
|
||||
cb->LoadRegI64 (rt, rn, offset, size, false, false);
|
||||
cb->LoadRegI64 (rt, GPR_DUMMY, size, false);
|
||||
}
|
||||
} else {
|
||||
bool sf = DisasLdstCompute64bit (size, is_signed, opc);
|
||||
if (is_store) {
|
||||
cb->StoreRegI64 (rt, rn, offset, size, is_extended, false);
|
||||
cb->StoreRegI64 (rt, GPR_DUMMY, size, is_extended);
|
||||
} else {
|
||||
cb->LoadRegI64 (rt, rn, offset, size, is_extended, false);
|
||||
cb->LoadRegI64 (rt, GPR_DUMMY, size, is_extended);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -950,7 +977,7 @@ static void DisasLdstReg(uint32_t insn, DisasCallback *cb) {
|
|||
*/
|
||||
static void DisasLdstPair(uint32_t insn, DisasCallback *cb) {
|
||||
unsigned int rt = extract32(insn, 0, 5);
|
||||
unsigned int rn = extract32(insn, 5, 5);
|
||||
unsigned int rn = ARMv8::HandleAsSP (extract32(insn, 5, 5));
|
||||
unsigned int rt2 = extract32(insn, 10, 5);
|
||||
uint64_t offset = sextract64(insn, 15, 7);
|
||||
unsigned int index = extract32(insn, 23, 2);
|
||||
|
@ -970,7 +997,8 @@ static void DisasLdstPair(uint32_t insn, DisasCallback *cb) {
|
|||
}
|
||||
|
||||
if (is_vector) {
|
||||
UnsupportedOp ("LDP/STP Xt1, Xt2, [base, #simm7] (SIMD&FP)");
|
||||
/* LDP/STP Xt1, Xt2, [base, #simm7] (SIMD&FP) */
|
||||
size = 2 + opc;
|
||||
} else {
|
||||
size = 2 + extract32 (opc, 1, 1);
|
||||
is_signed = extract32 (opc, 0, 1);
|
||||
|
@ -1007,14 +1035,20 @@ static void DisasLdstPair(uint32_t insn, DisasCallback *cb) {
|
|||
}
|
||||
|
||||
offset <<= size;
|
||||
cb->MovReg (GPR_DUMMY, rn, true);
|
||||
if (!post_index) {
|
||||
cb->AddI64 (GPR_DUMMY, rn, offset, false, true);
|
||||
}
|
||||
if (is_load) {
|
||||
/* XXX: Do not modify rt register before recognizing any exception
|
||||
* from the second load. */
|
||||
cb->LoadRegI64 (rt, rn, offset, size, false, post_index);
|
||||
cb->LoadRegI64 (rt2, rn, offset + (1 << size), size, false, post_index);
|
||||
cb->LoadRegI64 (rt, GPR_DUMMY, size, false);
|
||||
cb->AddI64 (GPR_DUMMY, GPR_DUMMY, 1 << size, false, true);
|
||||
cb->LoadRegI64 (rt2, GPR_DUMMY, size, false);
|
||||
} else {
|
||||
cb->StoreRegI64 (rt, rn, offset, size, false, post_index);
|
||||
cb->StoreRegI64 (rt2, rn, offset + (1 << size), size, false, post_index);
|
||||
cb->StoreRegI64 (rt, GPR_DUMMY, size, false);
|
||||
cb->AddI64 (GPR_DUMMY, GPR_DUMMY, 1 << size, false, true);
|
||||
cb->StoreRegI64 (rt2, GPR_DUMMY, size, false);
|
||||
}
|
||||
if (writeback) {
|
||||
cb->AddI64 (rn, rn, offset, false, true);
|
||||
|
@ -1050,6 +1084,205 @@ static void DisasLdSt(uint32_t insn, DisasCallback *cb) {
|
|||
}
|
||||
}
|
||||
|
||||
static void DisasFp1Src(uint32_t insn, DisasCallback *cb) {
|
||||
//TODO:
|
||||
}
|
||||
|
||||
static void DisasDataProcFp(uint32_t insn, DisasCallback *cb) {
|
||||
if (extract32(insn, 24, 1)) {
|
||||
/* Floating point data-processing (3 source) */
|
||||
//DisasFp3Src (insn);
|
||||
UnsupportedOp ("FP 3 source");
|
||||
} else if (extract32(insn, 21, 1) == 0) {
|
||||
/* Floating point to fixed point conversions */
|
||||
//DisasFpFixedConv (insn);
|
||||
UnsupportedOp ("FP fixed conv");
|
||||
} else {
|
||||
switch (extract32(insn, 10, 2)) {
|
||||
case 1:
|
||||
/* Floating point conditional compare */
|
||||
//DisasFpCcomp (insn);
|
||||
break;
|
||||
case 2:
|
||||
/* Floating point data-processing (2 source) */
|
||||
//DisasFp2Src (insn);
|
||||
break;
|
||||
case 3:
|
||||
/* Floating point conditional select */
|
||||
//DisasFpCsel (insn);
|
||||
break;
|
||||
case 0:
|
||||
switch (ctz32(extract32(insn, 12, 4))) {
|
||||
case 0: /* [15:12] == xxx1 */
|
||||
/* Floating point immediate */
|
||||
//DisasFpImm (insn);
|
||||
break;
|
||||
case 1: /* [15:12] == xx10 */
|
||||
/* Floating point compare */
|
||||
//DisasFpCompare (insn);
|
||||
break;
|
||||
case 2: /* [15:12] == x100 */
|
||||
/* Floating point data-processing (1 source) */
|
||||
DisasFp1Src (insn, cb);
|
||||
break;
|
||||
case 3: /* [15:12] == 1000 */
|
||||
UnallocatedOp (insn);
|
||||
break;
|
||||
default: /* [15:12] == 0000 */
|
||||
/* Floating point <-> integer conversions */
|
||||
//disas_fp_int_conv(s, insn);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void DisasSimdDupe(uint32_t insn, int is_q, int rd, int rn,
|
||||
int imm5, DisasCallback *cb) {
|
||||
int size = ctz32(imm5);
|
||||
unsigned int index = imm5 >> (size + 1);
|
||||
|
||||
if (size > 3 || (size == 3 && !is_q)) {
|
||||
UnallocatedOp (insn);
|
||||
return;
|
||||
}
|
||||
cb->DupVecReg(rd, rn, index, size, (imm5 >> 4) ? 128 : 64);
|
||||
}
|
||||
|
||||
static void DisasSimdDupg(uint32_t insn, int is_q, int rd, int rn,
|
||||
int imm5, DisasCallback *cb) {
|
||||
int size = ctz32(imm5);
|
||||
|
||||
if (size > 3 || (size == 3 && !is_q)) {
|
||||
UnallocatedOp (insn);
|
||||
return;
|
||||
}
|
||||
cb->DupVecRegFromGen(rd, rn, size, is_q ? 128 : 64);
|
||||
}
|
||||
|
||||
static void DisasSimdCopy(uint32_t insn, DisasCallback *cb) {
|
||||
unsigned int rd = extract32(insn, 0, 5);
|
||||
unsigned int rn = extract32(insn, 5, 5);
|
||||
unsigned int imm4 = extract32(insn, 11, 4);
|
||||
unsigned int op = extract32(insn, 29, 1);
|
||||
unsigned int is_q = extract32(insn, 30, 1);
|
||||
unsigned int imm5 = extract32(insn, 16, 5);
|
||||
|
||||
if (op) {
|
||||
if (is_q) {
|
||||
/* INS (element) */
|
||||
//handle_simd_inse(s, rd, rn, imm4, imm5);
|
||||
} else {
|
||||
UnallocatedOp (insn);
|
||||
}
|
||||
} else {
|
||||
switch (imm4) {
|
||||
case 0:
|
||||
/* DUP (element - vector) */
|
||||
DisasSimdDupe(insn, is_q, rd, rn, imm5, cb);
|
||||
break;
|
||||
case 1:
|
||||
/* DUP (general) */
|
||||
DisasSimdDupg(insn, is_q, rd, rn, imm5, cb);
|
||||
break;
|
||||
case 3:
|
||||
if (is_q) {
|
||||
/* INS (general) */
|
||||
//handle_simd_insg(s, rd, rn, imm5);
|
||||
} else {
|
||||
UnallocatedOp (insn);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
case 7:
|
||||
/* UMOV/SMOV (is_q indicates 32/64; imm4 indicates signedness) */
|
||||
//handle_simd_umov_smov(s, is_q, (imm4 == 5), rn, rd, imm5);
|
||||
break;
|
||||
default:
|
||||
UnallocatedOp (insn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void DisasSimdScalarCopy(uint32_t insn, DisasCallback *cb) {
|
||||
unsigned int fd = extract32(insn, 0, 5);
|
||||
unsigned int rn = extract32(insn, 5, 5);
|
||||
unsigned int imm4 = extract32(insn, 11, 4);
|
||||
unsigned int imm5 = extract32(insn, 16, 5);
|
||||
unsigned int op = extract32(insn, 29, 1);
|
||||
int size = ctz32(imm5);
|
||||
|
||||
if (op != 0 || imm4 != 0) {
|
||||
UnallocatedOp (insn);
|
||||
return;
|
||||
}
|
||||
if (size > 3) {
|
||||
UnallocatedOp (insn);
|
||||
}
|
||||
int index = imm5 >> (size + 1);
|
||||
cb->ReadVecReg (fd, rn, index, size);
|
||||
}
|
||||
|
||||
/* C4.1.5 Data Processing -- Scalar Floating-Point and Advanced SIMD
|
||||
*/
|
||||
static const A64DecodeTable data_proc_simd[] = {
|
||||
/* pattern , mask , fn */
|
||||
// { 0x0e200400, 0x9f200400, disas_simd_three_reg_same },
|
||||
// { 0x0e008400, 0x9f208400, disas_simd_three_reg_same_extra },
|
||||
// { 0x0e200000, 0x9f200c00, disas_simd_three_reg_diff },
|
||||
// { 0x0e200800, 0x9f3e0c00, disas_simd_two_reg_misc },
|
||||
// { 0x0e300800, 0x9f3e0c00, disas_simd_across_lanes },
|
||||
{ 0x0e000400, 0x9fe08400, DisasSimdCopy },
|
||||
// { 0x0f000000, 0x9f000400, disas_simd_indexed }, /* vector indexed */
|
||||
// /* simd_mod_imm decode is a subset of simd_shift_imm, so must precede it */
|
||||
// { 0x0f000400, 0x9ff80400, disas_simd_mod_imm },
|
||||
// { 0x0f000400, 0x9f800400, disas_simd_shift_imm },
|
||||
// { 0x0e000000, 0xbf208c00, disas_simd_tb },
|
||||
// { 0x0e000800, 0xbf208c00, disas_simd_zip_trn },
|
||||
// { 0x2e000000, 0xbf208400, disas_simd_ext },
|
||||
// { 0x5e200400, 0xdf200400, disas_simd_scalar_three_reg_same },
|
||||
// { 0x5e008400, 0xdf208400, disas_simd_scalar_three_reg_same_extra },
|
||||
// { 0x5e200000, 0xdf200c00, disas_simd_scalar_three_reg_diff },
|
||||
// { 0x5e200800, 0xdf3e0c00, disas_simd_scalar_two_reg_misc },
|
||||
// { 0x5e300800, 0xdf3e0c00, disas_simd_scalar_pairwise },
|
||||
{ 0x5e000400, 0xdfe08400, DisasSimdScalarCopy },
|
||||
// { 0x5f000000, 0xdf000400, disas_simd_indexed }, /* scalar indexed */
|
||||
// { 0x5f000400, 0xdf800400, disas_simd_scalar_shift_imm },
|
||||
// { 0x4e280800, 0xff3e0c00, disas_crypto_aes },
|
||||
// { 0x5e000000, 0xff208c00, disas_crypto_three_reg_sha },
|
||||
// { 0x5e280800, 0xff3e0c00, disas_crypto_two_reg_sha },
|
||||
// { 0xce608000, 0xffe0b000, disas_crypto_three_reg_sha512 },
|
||||
// { 0xcec08000, 0xfffff000, disas_crypto_two_reg_sha512 },
|
||||
// { 0xce000000, 0xff808000, disas_crypto_four_reg },
|
||||
// { 0xce800000, 0xffe00000, disas_crypto_xar },
|
||||
// { 0xce408000, 0xffe0c000, disas_crypto_three_reg_imm2 },
|
||||
// { 0x0e400400, 0x9f60c400, disas_simd_three_reg_same_fp16 },
|
||||
// { 0x0e780800, 0x8f7e0c00, disas_simd_two_reg_misc_fp16 },
|
||||
// { 0x5e400400, 0xdf60c400, disas_simd_scalar_three_reg_same_fp16 },
|
||||
{ 0x00000000, 0x00000000, NULL }
|
||||
};
|
||||
|
||||
static void DisasDataProcSimd(uint32_t insn, DisasCallback *cb) {
|
||||
A64DecodeFn *fn = LookupDisasFn (&data_proc_simd[0], insn);
|
||||
if (fn) {
|
||||
fn (insn, cb);
|
||||
} else {
|
||||
UnallocatedOp (insn);
|
||||
}
|
||||
}
|
||||
|
||||
static void DisasDataProcSimdFp(uint32_t insn, DisasCallback *cb) {
|
||||
if (extract32(insn, 28, 1) == 1 && extract32(insn, 30, 1) == 0) {
|
||||
UnsupportedOp ("FP ops");
|
||||
//DisasDataProcFp(s, insn);
|
||||
} else {
|
||||
/* SIMD, including crypto */
|
||||
DisasDataProcSimd(insn, cb);
|
||||
}
|
||||
}
|
||||
|
||||
void DisasA64(uint32_t insn, DisasCallback *cb) {
|
||||
switch (extract32 (insn, 25, 4)) {
|
||||
case 0x0: case 0x1: case 0x2: case 0x3: // Unallocated
|
||||
|
@ -1073,7 +1306,7 @@ void DisasA64(uint32_t insn, DisasCallback *cb) {
|
|||
break;
|
||||
case 0x7:
|
||||
case 0xf: /* Data processing - SIMD and floating point */
|
||||
UnsupportedOp ("SIMD and FP");
|
||||
DisasDataProcSimdFp (insn, cb);
|
||||
break;
|
||||
default:
|
||||
ns_abort ("Invalid encoding operation: 0x%016lx\n", insn); /* all 15 cases should be handled above */
|
||||
|
|
|
@ -22,8 +22,8 @@ void Interpreter::Run() {
|
|||
//scanf("%c", &c);
|
||||
Cpu::DumpMachine ();
|
||||
SingleStep ();
|
||||
if (counter >= 242)
|
||||
break;
|
||||
// if (counter >= 242)
|
||||
// break;
|
||||
counter++;
|
||||
// if (PC == 0x2d54) {
|
||||
// SingleStep ();
|
||||
|
@ -51,11 +51,6 @@ enum OpType{
|
|||
|
||||
const char *OpStrs[] = { "<<", ">>", ">>", "ROR", "+", "-", "&", "|", "^" };
|
||||
|
||||
/* See: C6.1.3 Use of the stack pointer */
|
||||
static inline unsigned int HandleAsSP(unsigned r_idx) {
|
||||
return r_idx == GPR_ZERO ? GPR_SP : r_idx;
|
||||
}
|
||||
|
||||
static bool CondHold(unsigned int cond) {
|
||||
bool result = false;
|
||||
if (cond >> 1 == 0x0) {
|
||||
|
@ -233,8 +228,8 @@ void IntprCallback::CondMovReg(unsigned int cond, unsigned int rd_idx, unsigned
|
|||
void IntprCallback::AddI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t imm, bool setflags, bool bit64) {
|
||||
char regc = bit64? 'X': 'W';
|
||||
if (!setflags) {
|
||||
rd_idx = HandleAsSP (rd_idx);
|
||||
rn_idx = HandleAsSP (rn_idx);
|
||||
rd_idx = ARMv8::HandleAsSP (rd_idx);
|
||||
rn_idx = ARMv8::HandleAsSP (rn_idx);
|
||||
}
|
||||
debug_print ("Add: %c[%u] = %c[%u] + 0x%lx (flag: %s)\n", regc, rd_idx, regc, rn_idx, imm, setflags? "update": "no");
|
||||
if (bit64)
|
||||
|
@ -245,8 +240,8 @@ void IntprCallback::AddI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t im
|
|||
void IntprCallback::SubI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t imm, bool setflags, bool bit64) {
|
||||
char regc = bit64? 'X': 'W';
|
||||
if (!setflags) {
|
||||
rd_idx = HandleAsSP (rd_idx);
|
||||
rn_idx = HandleAsSP (rn_idx);
|
||||
rd_idx = ARMv8::HandleAsSP (rd_idx);
|
||||
rn_idx = ARMv8::HandleAsSP (rn_idx);
|
||||
}
|
||||
debug_print ("Sub: %c[%u] = %c[%u] - 0x%lx (flag: %s)\n", regc, rd_idx, regc, rn_idx, imm, setflags? "update": "no");
|
||||
if (bit64)
|
||||
|
@ -315,7 +310,7 @@ void IntprCallback::SubcReg(unsigned int rd_idx, unsigned int rn_idx, unsigned i
|
|||
/* AND/OR/EOR... with Immediate value */
|
||||
void IntprCallback::AndI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wmask, bool setflags, bool bit64) {
|
||||
char regc = bit64? 'X': 'W';
|
||||
rd_idx = HandleAsSP (rd_idx);
|
||||
rd_idx = ARMv8::HandleAsSP (rd_idx);
|
||||
debug_print ("And: %c[%u] = %c[%u] & 0x%lx (flag: %s)\n", regc, rd_idx, regc, rn_idx, wmask, setflags? "update": "no");
|
||||
if (bit64)
|
||||
ArithmeticLogic (rd_idx, X(rn_idx), wmask, setflags, bit64, AL_TYPE_AND);
|
||||
|
@ -325,7 +320,7 @@ void IntprCallback::AndI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wm
|
|||
}
|
||||
void IntprCallback::OrrI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wmask, bool bit64) {
|
||||
char regc = bit64? 'X': 'W';
|
||||
rd_idx = HandleAsSP (rd_idx);
|
||||
rd_idx = ARMv8::HandleAsSP (rd_idx);
|
||||
debug_print ("Or: %c[%u] = %c[%u] | 0x%lx \n", regc, rd_idx, regc, rn_idx, wmask);
|
||||
if (bit64)
|
||||
ArithmeticLogic (rd_idx, X(rn_idx), wmask, false, bit64, AL_TYPE_OR);
|
||||
|
@ -334,7 +329,7 @@ void IntprCallback::OrrI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wm
|
|||
}
|
||||
void IntprCallback::EorI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wmask, bool bit64) {
|
||||
char regc = bit64? 'X': 'W';
|
||||
rd_idx = HandleAsSP (rd_idx);
|
||||
rd_idx = ARMv8::HandleAsSP (rd_idx);
|
||||
debug_print ("Eor: %c[%u] = %c[%u] ^ 0x%lx \n", regc, rd_idx, regc, rn_idx, wmask);
|
||||
if (bit64)
|
||||
ArithmeticLogic (rd_idx, X(rn_idx), wmask, false, bit64, AL_TYPE_EOR);
|
||||
|
@ -343,7 +338,7 @@ void IntprCallback::EorI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wm
|
|||
}
|
||||
void IntprCallback::ShiftI64(unsigned int rd_idx, unsigned int rn_idx, unsigned int shift_type, unsigned int shift_amount, bool bit64) {
|
||||
char regc = bit64? 'X': 'W';
|
||||
rd_idx = HandleAsSP (rd_idx);
|
||||
rd_idx = ARMv8::HandleAsSP (rd_idx);
|
||||
debug_print ("Shift: %c[%u] = %c[%u] %s 0x%lx \n", regc, rd_idx, regc, rn_idx, OpStrs[shift_type], shift_amount);
|
||||
if (bit64)
|
||||
ArithmeticLogic (rd_idx, X(rn_idx), shift_amount, false, bit64, (OpType)shift_type);
|
||||
|
@ -442,7 +437,7 @@ void IntprCallback::LoadReg(unsigned int rd_idx, unsigned int base_idx, unsigned
|
|||
bool extend, bool post, bool bit64) {
|
||||
char regc = bit64? 'X': 'W';
|
||||
char regdc = size >= 4 ? 'Q' : (size < 3 ? 'W' : 'X');
|
||||
base_idx = HandleAsSP (base_idx);
|
||||
base_idx = ARMv8::HandleAsSP (base_idx);
|
||||
debug_print ("Load(%d): %c[%u] <= [%c[%u], %c[%u]]\n", size, regdc, rd_idx, regc, base_idx, regc, rm_idx);
|
||||
uint64_t addr;
|
||||
if (bit64) {
|
||||
|
@ -459,23 +454,17 @@ void IntprCallback::LoadReg(unsigned int rd_idx, unsigned int base_idx, unsigned
|
|||
_LoadReg (rd_idx, addr, size, extend);
|
||||
}
|
||||
}
|
||||
void IntprCallback::LoadRegI64(unsigned int rd_idx, unsigned int base_idx, uint64_t offset, int size,
|
||||
bool extend, bool post) {
|
||||
void IntprCallback::LoadRegI64(unsigned int rd_idx, unsigned int ad_idx, int size,
|
||||
bool extend) {
|
||||
char regdc = size >= 4 ? 'Q' : (size < 3 ? 'W' : 'X');
|
||||
base_idx = HandleAsSP (base_idx);
|
||||
debug_print ("Load(%d): %c[%u] <= [X[%u], 0x%lx]\n", size, regdc, rd_idx, base_idx, offset);
|
||||
uint64_t addr;
|
||||
if (post)
|
||||
addr = X(base_idx);
|
||||
else
|
||||
addr = X(base_idx) + offset;
|
||||
_LoadReg (rd_idx, addr, size, extend);
|
||||
debug_print ("Load(%d): %c[%u] <= [0x%lx]\n", size, regdc, rd_idx, X(ad_idx));
|
||||
_LoadReg (rd_idx, X(ad_idx), size, extend);
|
||||
}
|
||||
void IntprCallback::StoreReg(unsigned int rd_idx, unsigned int base_idx, unsigned int rm_idx, int size,
|
||||
bool extend, bool post, bool bit64) {
|
||||
char regc = bit64? 'X': 'W';
|
||||
char regdc = size >= 4 ? 'Q' : (size < 3 ? 'W' : 'X');
|
||||
base_idx = HandleAsSP (base_idx);
|
||||
base_idx = ARMv8::HandleAsSP (base_idx);
|
||||
debug_print ("Store(%d): %c[%u] => [%c[%u], %c[%u]]\n", size, regdc, rd_idx, regc, base_idx, regc, rm_idx);
|
||||
uint64_t addr;
|
||||
if (bit64) {
|
||||
|
@ -492,17 +481,11 @@ void IntprCallback::StoreReg(unsigned int rd_idx, unsigned int base_idx, unsigne
|
|||
_StoreReg (rd_idx, addr, size, extend);
|
||||
}
|
||||
}
|
||||
void IntprCallback::StoreRegI64(unsigned int rd_idx, unsigned int base_idx, uint64_t offset, int size,
|
||||
bool extend, bool post) {
|
||||
void IntprCallback::StoreRegI64(unsigned int rd_idx, unsigned int ad_idx, int size,
|
||||
bool extend) {
|
||||
char regdc = size >= 4 ? 'Q' : (size < 3 ? 'W' : 'X');
|
||||
base_idx = HandleAsSP (base_idx);
|
||||
debug_print ("Store(%d): %c[%u] => [X[%u], 0x%lx]\n", size, regdc, rd_idx, base_idx, offset);
|
||||
uint64_t addr;
|
||||
if (post)
|
||||
addr = X(base_idx);
|
||||
else
|
||||
addr = X(base_idx) + offset;
|
||||
_StoreReg (rd_idx, addr, size, extend);
|
||||
debug_print ("Store(%d): %c[%u] => [0x%lx]\n", size, regdc, rd_idx, X(ad_idx));
|
||||
_StoreReg (rd_idx, X(ad_idx), size, extend);
|
||||
}
|
||||
|
||||
/* Bitfield Signed/Unsigned Extract... with Immediate value */
|
||||
|
@ -665,3 +648,65 @@ void IntprCallback::SVC(unsigned int svc_num) {
|
|||
else
|
||||
ns_print ("Invalid svc number: %u\n", svc_num);
|
||||
}
|
||||
|
||||
/* Read Vector register to FP register */
|
||||
void IntprCallback::ReadVecReg(unsigned int rd_idx, unsigned int vn_idx, unsigned int index, int size) {
|
||||
if (size == 0) {
|
||||
D(rd_idx) = VREG(vn_idx).b[index];
|
||||
} else if (size == 1) {
|
||||
D(rd_idx) = VREG(vn_idx).h[index];
|
||||
} else if (size == 2) {
|
||||
D(rd_idx) = VREG(vn_idx).s[index];
|
||||
} else if (size == 3) {
|
||||
D(rd_idx) = VREG(vn_idx).d[index];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void DupVecImm(unsigned int vd_idx, T imm, int size, int dstsize) {
|
||||
uint32_t i;
|
||||
int sec_size = sizeof(T) * 8;
|
||||
for (i = 0; i + sec_size <= dstsize; i += sec_size){
|
||||
if (size == 0)
|
||||
VREG(vd_idx).b[i / sec_size] = imm;
|
||||
else if (size == 1)
|
||||
VREG(vd_idx).h[i / sec_size] = imm;
|
||||
else if (size == 2)
|
||||
VREG(vd_idx).s[i / sec_size] = imm;
|
||||
else
|
||||
VREG(vd_idx).d[i / sec_size] = imm;
|
||||
}
|
||||
}
|
||||
/* Duplicate an element of vector register to new one */
|
||||
void IntprCallback::DupVecReg(unsigned int vd_idx, unsigned int vn_idx, unsigned int index, int size, int dstsize) {
|
||||
if (size == 0) {
|
||||
DupVecImm(vd_idx, VREG(vn_idx).b[index], size, dstsize);
|
||||
} else if (size == 1) {
|
||||
DupVecImm(vd_idx, VREG(vn_idx).h[index], size, dstsize);
|
||||
} else if (size == 2) {
|
||||
DupVecImm(vd_idx, VREG(vn_idx).s[index], size, dstsize);
|
||||
} else if (size == 3) {
|
||||
DupVecImm(vd_idx, VREG(vn_idx).d[index], size, dstsize);
|
||||
}
|
||||
}
|
||||
|
||||
/* Duplicate an general register into vector register */
|
||||
void IntprCallback::DupVecRegFromGen(unsigned int vd_idx, unsigned int rn_idx, int size, int dstsize) {
|
||||
if (size == 0) {
|
||||
DupVecImm(vd_idx, (uint8_t) (X(rn_idx) & 0xff), size, dstsize);
|
||||
} else if (size == 1) {
|
||||
DupVecImm(vd_idx, (uint16_t) (X(rn_idx) & 0xffff), size, dstsize);
|
||||
} else if (size == 2) {
|
||||
DupVecImm(vd_idx, (uint32_t) (X(rn_idx) & 0xffffffff), size, dstsize);
|
||||
} else if (size == 3) {
|
||||
DupVecImm(vd_idx, X(rn_idx), size, dstsize);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write to FP register */
|
||||
void IntprCallback::WriteFpReg(unsigned int fd_idx, unsigned int fn_idx) {
|
||||
D(fd_idx) = D(fn_idx);
|
||||
}
|
||||
void IntprCallback::WriteFpRegI64(unsigned int fd_idx, uint64_t imm) {
|
||||
D(fd_idx) = imm;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ struct ARMv8State {
|
|||
reg_t gpr[35];
|
||||
|
||||
/* v0 - v31 (128 bit vector register, sometime treated as set of smaller size regs) */
|
||||
vreg_t vreg[32];
|
||||
vreg_t vreg[33];
|
||||
|
||||
uint32_t nzcv; // flag register
|
||||
};
|
||||
|
@ -39,12 +39,15 @@ extern ARMv8State arm_state;
|
|||
#define GPR_SP 32
|
||||
#define PC_IDX 33 // XXX: bit tricky
|
||||
#define GPR_DUMMY 34
|
||||
#define VREG_DUMMY 32
|
||||
|
||||
#define GPR(r) ARMv8::arm_state.gpr[r]
|
||||
#define VREG(r) ARMv8::arm_state.vreg[r]
|
||||
#define VREG(r) ARMv8::arm_state.vreg[r] // SIMD registers
|
||||
|
||||
#define X(r) GPR(r).x
|
||||
#define W(r) GPR(r).w[0]
|
||||
|
||||
/* FP registers */
|
||||
#define D(r) VREG(r).d[0]
|
||||
#define S(r) VREG(r).s[0]
|
||||
#define H(r) VREG(r).h[0]
|
||||
|
@ -61,6 +64,11 @@ extern ARMv8State arm_state;
|
|||
#define C_MASK 0x20000000UL
|
||||
#define V_MASK 0x10000000UL
|
||||
|
||||
/* See: C6.1.3 Use of the stack pointer */
|
||||
inline unsigned int HandleAsSP(unsigned r_idx) {
|
||||
return r_idx == GPR_ZERO ? GPR_SP : r_idx;
|
||||
}
|
||||
|
||||
void Init();
|
||||
|
||||
void RunLoop();
|
||||
|
|
|
@ -48,9 +48,9 @@ virtual void ExtendReg(unsigned int rd_idx, unsigned int rn_idx, unsigned int ex
|
|||
|
||||
/* Load/Store */
|
||||
virtual void LoadReg(unsigned int rd_idx, unsigned int base_idx, unsigned int rm_idx, int size, bool extend, bool post, bool bit64) = 0;
|
||||
virtual void LoadRegI64(unsigned int rd_idx, unsigned int base_idx, uint64_t offset, int size, bool extend, bool post) = 0;
|
||||
virtual void LoadRegI64(unsigned int rd_idx, unsigned int ad_idx, int size, bool extend) = 0;
|
||||
virtual void StoreReg(unsigned int rd_idx, unsigned int base_idx, unsigned int rm_idx, int size, bool extend, bool post, bool bit64) = 0;
|
||||
virtual void StoreRegI64(unsigned int rd_idx, unsigned int base_idx, uint64_t offset, int size, bool extend, bool post) = 0;
|
||||
virtual void StoreRegI64(unsigned int rd_idx, unsigned int ad_idx, int size, bool extend) = 0;
|
||||
|
||||
/* Bitfield Signed/Unsigned Extract... with Immediate value */
|
||||
virtual void SExtractI64(unsigned int rd_idx, unsigned int rn_idx, unsigned int pos, unsigned int len, bool bit64) = 0;
|
||||
|
@ -89,6 +89,18 @@ virtual void SetPCReg(unsigned int rt_idx) = 0;
|
|||
|
||||
/* Super Visor Call */
|
||||
virtual void SVC(unsigned int svc_num) = 0;
|
||||
|
||||
/* Read Vector register to FP regsiter */
|
||||
virtual void ReadVecReg(unsigned int fd_idx, unsigned int vn_idx, unsigned int index, int size) = 0;
|
||||
/* Duplicate an element of vector register to new one */
|
||||
virtual void DupVecReg(unsigned int vd_idx, unsigned int vn_idx, unsigned int index, int size, int dstsize) = 0;
|
||||
/* Duplicate an general register into vector register */
|
||||
virtual void DupVecRegFromGen(unsigned int vd_idx, unsigned int rn_idx, int size, int dstsize) = 0;
|
||||
|
||||
/* Write to FP register */
|
||||
virtual void WriteFpReg(unsigned int fd_idx, unsigned int fn_idx) = 0;
|
||||
virtual void WriteFpRegI64(unsigned int fd_idx, uint64_t imm) = 0;
|
||||
|
||||
};
|
||||
|
||||
namespace Disassembler {
|
||||
|
@ -131,6 +143,14 @@ enum CondType {
|
|||
CondType_NV
|
||||
};
|
||||
|
||||
typedef void A64DecodeFn(uint32_t insn, DisasCallback *cb);
|
||||
|
||||
typedef struct AArch64DecodeTable {
|
||||
uint32_t pattern;
|
||||
uint32_t mask;
|
||||
A64DecodeFn *disas_fn;
|
||||
} A64DecodeTable;
|
||||
|
||||
void DisasA64(uint32_t insn, DisasCallback *cb);
|
||||
|
||||
};
|
||||
|
|
|
@ -48,9 +48,9 @@ void ExtendReg(unsigned int rd_idx, unsigned int rn_idx, unsigned int extend_typ
|
|||
|
||||
/* Load/Store */
|
||||
void LoadReg(unsigned int rd_idx, unsigned int base_idx, unsigned int rm_idx, int size, bool extend, bool post, bool bit64);
|
||||
void LoadRegI64(unsigned int rd_idx, unsigned int base_idx, uint64_t offset, int size, bool extend, bool post);
|
||||
void LoadRegI64(unsigned int rd_idx, unsigned int ad_idx, int size, bool extend);
|
||||
void StoreReg(unsigned int rd_idx, unsigned int base_idx, unsigned int rm_idx, int size, bool extend, bool post, bool bit64);
|
||||
void StoreRegI64(unsigned int rd_idx, unsigned int base_idx, uint64_t offset, int size, bool extend, bool post);
|
||||
void StoreRegI64(unsigned int rd_idx, unsigned int ad_idx, int size, bool extend);
|
||||
|
||||
/* Bitfield Signed/Unsigned Extract... with Immediate value */
|
||||
void SExtractI64(unsigned int rd_idx, unsigned int rn_idx, unsigned int pos, unsigned int len, bool bit64);
|
||||
|
@ -88,6 +88,18 @@ void SetPCReg(unsigned int rt_idx);
|
|||
|
||||
/* Super Visor Call */
|
||||
void SVC(unsigned int svc_num);
|
||||
|
||||
/* Read Vector register to FP register */
|
||||
void ReadVecReg(unsigned int fd_idx, unsigned int vn_idx, unsigned int index, int size);
|
||||
/* Duplicate an element of vector register to new one */
|
||||
void DupVecReg(unsigned int vd_idx, unsigned int vn_idx, unsigned int index, int size, int dstsize);
|
||||
/* Duplicate an general register into vector register */
|
||||
void DupVecRegFromGen(unsigned int vd_idx, unsigned int rn_idx, int size, int dstsize);
|
||||
|
||||
/* Write to FP register */
|
||||
void WriteFpReg(unsigned int fd_idx, unsigned int fn_idx);
|
||||
void WriteFpRegI64(unsigned int fd_idx, uint64_t imm);
|
||||
|
||||
};
|
||||
|
||||
/* Global Interpreter singleton class .*/
|
||||
|
|
|
@ -98,6 +98,14 @@ static inline int clz64(uint64_t bitfield) {
|
|||
return bitfield? __builtin_clzll (bitfield): 64;
|
||||
}
|
||||
|
||||
static inline int ctz32(uint32_t bitfield) {
|
||||
return bitfield? __builtin_ctz (bitfield): 32;
|
||||
}
|
||||
|
||||
static inline int ctz64(uint64_t bitfield) {
|
||||
return bitfield? __builtin_ctzll (bitfield): 64;
|
||||
}
|
||||
|
||||
/* Return a value with the bottom len bits set (where 0 < len <= 64) */
|
||||
static inline uint64_t bitmask64(unsigned int length) {
|
||||
assert(length > 0 && length <= 64);
|
||||
|
|
Loading…
Reference in a new issue