Add support for load/store operation with 128bit register(FP)

This commit is contained in:
rkx1209 2018-03-07 20:05:53 +09:00
parent 3679e913a5
commit adde42797b
3 changed files with 87 additions and 48 deletions

View file

@ -10,6 +10,11 @@ static inline void UnallocatedOp(uint32_t insn) {
ns_abort ("Unallocated operation 0x%08lx\n", insn);
}
static inline bool FpAccessCheck(uint32_t insn) {
/* TODO: */
return true;
}
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;
@ -863,7 +868,16 @@ static void DisasLdstRegUnsignedImm(uint32_t insn, DisasCallback *cb,
bool is_extended = false;
if (is_vector) {
UnsupportedOp ("LDR/STR [base, #simm12] (SIMD&FP)");
/* LDR/STR [base, #simm12] (SIMD&FP) */
size |= (opc & 2) << 1;
if (size > 4) {
UnallocatedOp (insn);
return;
}
is_store = !extract32(opc, 0, 1);
if (!FpAccessCheck (insn)) {
return;
}
} else {
if (size == 3 && opc == 2) {
/* PRFM - prefetch */
@ -877,12 +891,21 @@ static void DisasLdstRegUnsignedImm(uint32_t insn, DisasCallback *cb,
is_signed = extract32(opc, 1, 1);
is_extended = (size < 3) && extract32(opc, 0, 1);
}
bool sf = DisasLdstCompute64bit (size, is_signed, opc);
offset = imm12 << size;
if (is_store) {
cb->StoreRegImm64 (rt, rn, offset, size, is_extended, false, false, sf);
if (is_vector) {
/* size must be 4 (128-bit) */
if (is_store) {
cb->StoreRegImm64 (rt, rn, offset, size, false, false, false, true);
} else {
cb->LoadRegImm64 (rt, rn, offset, size, false, false, false, true);
}
} else {
cb->LoadRegImm64 (rt, rn, offset, size, is_extended, false, false, sf);
bool sf = DisasLdstCompute64bit (size, is_signed, opc);
if (is_store) {
cb->StoreRegImm64 (rt, rn, offset, size, is_extended, false, false, sf);
} else {
cb->LoadRegImm64 (rt, rn, offset, size, is_extended, false, false, sf);
}
}
}

View file

@ -346,49 +346,43 @@ void IntprCallback::ExtendReg(unsigned int rd_idx, unsigned int rn_idx, unsigned
}
/* Load/Store */
static void _LoadReg(unsigned int rd_idx, uint64_t addr, int size, bool extend, bool bit64) {
if (bit64) {
if (size == 4)
W(rd_idx) = ARMv8::ReadU32 (addr);
if (size == 8)
X(rd_idx) = ARMv8::ReadU64 (addr);
/* TODO: if (extend)
ExtendReg(rd_idx, rd_idx, type, true); */
} else {
if (size == 4)
W(rd_idx) = ARMv8::ReadU32 (addr);
/* TODO: if (extend)
ExtendReg(rd_idx, rd_idx, type, true); */
}
static void _LoadReg(unsigned int rd_idx, uint64_t addr, int size, bool extend) {
if (size < 4) {
X(rd_idx) = ARMv8::ReadU64 (addr);
} else {
/* 128-bit Qt */
VREG(rd_idx).d[0] = ARMv8::ReadU64 (addr + 8);
VREG(rd_idx).d[1] = ARMv8::ReadU64 (addr);
}
/* TODO: if (extend)
ExtendReg(rd_idx, rd_idx, type, true); */
}
static void _StoreReg(unsigned int rd_idx, uint64_t addr, int size, bool extend, bool bit64) {
if (bit64) {
if (size == 4)
ARMv8::WriteU32 (addr, X(rd_idx));
if (size == 8)
ARMv8::WriteU64 (addr, X(rd_idx));
/* TODO: if (extend)
ExtendReg(rd_idx, rd_idx, type, true); */
} else {
if (size == 4)
ARMv8::WriteU32 (addr, W(rd_idx));
/* TODO: if (extend)
ExtendReg(rd_idx, rd_idx, type, true); */
}
static void _StoreReg(unsigned int rd_idx, uint64_t addr, int size, bool extend) {
if (size < 4) {
ARMv8::WriteU64 (addr, X(rd_idx));
} else {
/* 128-bit Qt */
ARMv8::WriteU64 (addr + 8, VREG(rd_idx).d[0]);
ARMv8::WriteU64 (addr, VREG(rd_idx).d[1]);
}
/* TODO: if (extend)
ExtendReg(rd_idx, rd_idx, type, true); */
}
void IntprCallback::LoadReg(unsigned int rd_idx, unsigned int base_idx, unsigned int rm_idx, int size,
bool extend, bool post, bool writeback, bool bit64) {
char regc = bit64? 'X': 'W';
debug_print ("Load(%d): %c[%u] <= [%c[%u], %c[%u]]\n", size, regc, rd_idx, regc, base_idx, regc, rm_idx);
char regdc = bit64 && size >= 4 ? 'Q' : regc;
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) {
if (post)
addr = X(base_idx);
else
addr = X(base_idx) + X(rm_idx);
_LoadReg (rd_idx, addr, size, extend, true);
_LoadReg (rd_idx, addr, size, extend);
if (writeback)
X(base_idx) = addr;
} else {
@ -396,7 +390,7 @@ void IntprCallback::LoadReg(unsigned int rd_idx, unsigned int base_idx, unsigned
addr = W(base_idx);
else
addr = W(base_idx) + W(rm_idx);
_LoadReg (rd_idx, addr, size, extend, false);
_LoadReg (rd_idx, addr, size, extend);
if (writeback)
W(base_idx) = addr;
}
@ -404,14 +398,15 @@ void IntprCallback::LoadReg(unsigned int rd_idx, unsigned int base_idx, unsigned
void IntprCallback::LoadRegImm64(unsigned int rd_idx, unsigned int base_idx, uint64_t offset, int size,
bool extend, bool post, bool writeback, bool bit64) {
char regc = bit64? 'X': 'W';
debug_print ("Load(%d): %c[%u] <= [%c[%u], 0x%lx]\n", size, regc, rd_idx, regc, base_idx, offset);
char regdc = bit64 && size >= 4 ? 'Q' : regc;
debug_print ("Load(%d): %c[%u] <= [%c[%u], 0x%lx]\n", size, regdc, rd_idx, regc, base_idx, offset);
uint64_t addr;
if (bit64) {
if (post)
addr = X(base_idx);
else
addr = X(base_idx) + offset;
_LoadReg (rd_idx, addr, size, extend, true);
_LoadReg (rd_idx, addr, size, extend);
if (writeback)
X(base_idx) = addr;
} else {
@ -419,7 +414,7 @@ void IntprCallback::LoadRegImm64(unsigned int rd_idx, unsigned int base_idx, uin
addr = W(base_idx);
else
addr = W(base_idx) + offset;
_LoadReg (rd_idx, addr, size, extend, false);
_LoadReg (rd_idx, addr, size, extend);
if (writeback)
W(base_idx) = addr;
}
@ -427,14 +422,15 @@ void IntprCallback::LoadRegImm64(unsigned int rd_idx, unsigned int base_idx, uin
void IntprCallback::StoreReg(unsigned int rd_idx, unsigned int base_idx, unsigned int rm_idx, int size,
bool extend, bool post, bool writeback, bool bit64) {
char regc = bit64? 'X': 'W';
debug_print ("Store(%d): %c[%u] => [%c[%u], %c[%u]]\n", size, regc, rd_idx, regc, base_idx, regc, rm_idx);
char regdc = bit64 && size >= 4 ? 'Q' : regc;
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) {
if (post)
addr = X(base_idx);
else
addr = X(base_idx) + X(rm_idx);
_StoreReg (rd_idx, addr, size, extend, true);
_StoreReg (rd_idx, addr, size, extend);
if (writeback)
X(base_idx) = addr;
} else {
@ -442,7 +438,7 @@ void IntprCallback::StoreReg(unsigned int rd_idx, unsigned int base_idx, unsigne
addr = W(base_idx);
else
addr = W(base_idx) + W(rm_idx);
_StoreReg (rd_idx, addr, size, extend, false);
_StoreReg (rd_idx, addr, size, extend);
if (writeback)
W(base_idx) = addr;
}
@ -450,14 +446,15 @@ void IntprCallback::StoreReg(unsigned int rd_idx, unsigned int base_idx, unsigne
void IntprCallback::StoreRegImm64(unsigned int rd_idx, unsigned int base_idx, uint64_t offset, int size,
bool extend, bool post, bool writeback, bool bit64) {
char regc = bit64? 'X': 'W';
debug_print ("Store(%d): %c[%u] => [%c[%u], 0x%lx]\n", size, regc, rd_idx, regc, base_idx, offset);
char regdc = bit64 && size >= 4 ? 'Q' : regc;
debug_print ("Store(%d): %c[%u] => [%c[%u], 0x%lx]\n", size, regdc, rd_idx, regc, base_idx, offset);
uint64_t addr;
if (bit64) {
if (post)
addr = X(base_idx);
else
addr = X(base_idx) + offset;
_StoreReg (rd_idx, addr, size, extend, true);
_StoreReg (rd_idx, addr, size, extend);
if (writeback)
X(base_idx) = addr;
} else {
@ -465,7 +462,7 @@ void IntprCallback::StoreRegImm64(unsigned int rd_idx, unsigned int base_idx, ui
addr = W(base_idx);
else
addr = W(base_idx) + offset;
_StoreReg (rd_idx, addr, size, extend, false);
_StoreReg (rd_idx, addr, size, extend);
if (writeback)
W(base_idx) = addr;
}

View file

@ -8,11 +8,24 @@ typedef union {
uint64_t x;
}reg_t;
/* NEON & FP register */
typedef union {
uint8_t b[16];
uint16_t h[8];
uint32_t s[4];
uint64_t d[2];
}vreg_t;
struct ARMv8State {
reg_t gpr[34];
/*
* x0 - x31 (x30 is usually "link regsiter" and x31 is "stack pointer" or "zero register" )
* NOTE: In nsemu, 'PC' register is respresented as x32 internally. */
* NOTE: In nsemu, 'PC' register is respresented as x32 internally.
*/
reg_t gpr[34];
/* v0 - v31 (128 bit vector register, sometime treated as set of smaller size regs) */
vreg_t vreg[32];
uint32_t nzcv; // flag register
};
@ -25,8 +38,14 @@ extern ARMv8State arm_state;
#define GPR_DUMMY 33
#define GPR(r) ARMv8::arm_state.gpr[r]
#define VREG(r) ARMv8::arm_state.vreg[r]
#define X(r) GPR(r).x
#define W(r) GPR(r).w[1]
#define W(r) GPR(r).w[0]
#define D(r) VREG(r).d[0]
#define S(r) VREG(r).s[0]
#define H(r) VREG(r).h[0]
#define B(r) VREG(r).b[0]
#define LR X(GPR_LR)
#define SP X(GPR_SP)