Add support for conditional select operation

This commit is contained in:
rkx1209 2018-02-25 22:55:39 +09:00
parent 1cf270a02e
commit 806ac7dabf
4 changed files with 91 additions and 45 deletions

View file

@ -218,7 +218,6 @@ static void DisasExtract(uint32_t insn, DisasCallback *cb) {
UnallocatedOp (insn);
} else {
if (imm == 0) {
// TODO: mov rd, rm
cb->MovReg(rd, rm, sf);
} else if (rm == rn) { /* ROR */
// TODO:
@ -538,12 +537,39 @@ static void DisasCondCmp(uint32_t insn, DisasCallback *cb) {
UnallocatedOp (insn);
return;
}
/* CCMN, CCMP */
if (is_imm)
cb->CondCmpI64(rn, y, nzcv, cond, op, sf);
else
cb->CondCmpReg(rn, y, nzcv, cond, op, sf);
}
static void DisasCondSel(uint32_t insn, DisasCallback *cb) {
unsigned int sf = extract32(insn, 31, 1);
unsigned int else_inv = extract32(insn, 30, 1);
unsigned int rm = extract32(insn, 16, 5);
unsigned int cond = extract32(insn, 12, 4);
unsigned int else_inc = extract32(insn, 10, 1);
unsigned int rn = extract32(insn, 5, 5);
unsigned int rd = extract32(insn, 0, 5);
if (extract32(insn, 29, 1) || extract32(insn, 11, 1)) {
/* S == 1 or op2<1> == 1 */
UnallocatedOp (insn);
return;
}
bool cond_inv = false;
if (rn == 31 && rm == 31) {
/* CSET (CSINC <Wd>, WZR, WZR, invert(<cond>)) *
* CSETM (CSINV <Wd>, WZR, WZR, invert(<cond>)) */
cond = cond ^ 1; // i.e. invert(<cond>)
}
if (else_inv)
cb->NotReg (rm, rm, sf);
if (else_inc)
cb->AddI64 (rm, rm, 1, false, sf);
cb->CondMovReg (cond, rd, rn, rm);
}
static void DisasDataProcReg(uint32_t insn, DisasCallback *cb) {
switch (extract32(insn, 24, 5)) {
case 0x0a: /* Logical (shifted register) */
@ -568,6 +594,7 @@ static void DisasDataProcReg(uint32_t insn, DisasCallback *cb) {
DisasCondCmp (insn, cb);
break;
case 0x4: /* Conditional select */
DisasCondSel (insn, cb);
break;
case 0x6: /* Data-processing */
if (insn & (1 << 30)) { /* (1 source) */

View file

@ -22,50 +22,7 @@ void Interpreter::Run() {
}
}
void IntprCallback::MoviI64(unsigned int reg_idx, uint64_t imm, bool bit64) {
char regc = bit64? 'X': 'W';
debug_print ("MOV: %c[%u] = 0x%016lx\n", regc, reg_idx, imm);
if (bit64) X(reg_idx) = imm;
else W(reg_idx) = imm;
}
void IntprCallback::DepositiI64(unsigned int reg_idx, unsigned int pos, uint64_t imm, bool bit64) {
char regc = bit64? 'X': 'W';
debug_print ("MOVK: %c[%u] = 0x%016lx\n", regc, reg_idx, imm << pos);
uint32_t mask = (1 << 16) - 1; //XXX: hard coded bit size: 16
if (bit64) {
X(reg_idx) = (X(reg_idx) & ~(mask << pos)) | (imm << pos);
}
else {
W(reg_idx) = (W(reg_idx) & ~(mask << pos)) | (imm << pos);
}
}
/* Mov between registers */
void IntprCallback::MovReg(unsigned int rd_idx, unsigned int rn_idx, bool bit64) {
char regc = bit64? 'X': 'W';
debug_print ("MOV: %c[%u] = %c[%u]\n", regc, rd_idx, regc, rn_idx);
if (bit64)
X(rd_idx) = X(rn_idx);
else
W(rd_idx) = W(rn_idx);
}
static void UpdateFlag(uint64_t res, uint64_t arg1, uint64_t arg2) {
uint32_t nzcv;
if (res & (1ULL << 63)) nzcv |= N_MASK; // N
if (res) nzcv |= Z_MASK; // Z
if (((arg1 & arg2) + (arg1 ^ arg2) >> 1) >> 63) nzcv |= C_MASK; //C (half adder ((x & y) + ((x ^ y) >> 1)))
if ((arg1 ^ arg2) & (arg2 ^ res)) nzcv |= V_MASK; //V
NZCV = nzcv;
}
static uint64_t RotateRight(uint64_t val, uint64_t rot) {
uint64_t left = (val & (1 << rot - 1)) << (64 - rot);
return left | (val >> rot);
}
/* ####### Callbacks ####### */
enum OpType{
AL_TYPE_LSL,
AL_TYPE_LSR,
@ -102,6 +59,62 @@ static bool CondHold(unsigned int cond) {
return false;
}
void IntprCallback::MoviI64(unsigned int reg_idx, uint64_t imm, bool bit64) {
char regc = bit64? 'X': 'W';
debug_print ("MOV: %c[%u] = 0x%016lx\n", regc, reg_idx, imm);
if (bit64) X(reg_idx) = imm;
else W(reg_idx) = imm;
}
void IntprCallback::DepositiI64(unsigned int reg_idx, unsigned int pos, uint64_t imm, bool bit64) {
char regc = bit64? 'X': 'W';
debug_print ("MOVK: %c[%u] = 0x%016lx\n", regc, reg_idx, imm << pos);
uint32_t mask = (1 << 16) - 1; //XXX: hard coded bit size: 16
if (bit64) {
X(reg_idx) = (X(reg_idx) & ~(mask << pos)) | (imm << pos);
}
else {
W(reg_idx) = (W(reg_idx) & ~(mask << pos)) | (imm << pos);
}
}
/* Mov between registers */
void IntprCallback::MovReg(unsigned int rd_idx, unsigned int rn_idx, bool bit64) {
char regc = bit64? 'X': 'W';
debug_print ("MOV: %c[%u] = %c[%u]\n", regc, rd_idx, regc, rn_idx);
if (bit64)
X(rd_idx) = X(rn_idx);
else
W(rd_idx) = W(rn_idx);
}
/* Conditional mov between registers */
void IntprCallback::CondMovReg(unsigned int cond, unsigned int rd_idx, unsigned int rn_idx, bool bit64) {
char regc = bit64? 'X': 'W';
debug_print ("MOV: %c[%u] = %c[%u]\n", regc, rd_idx, regc, rn_idx);
if (bit64) {
if (CondHold(cond))
X(rd_idx) = X(rn_idx);
} else {
if (CondHold(cond))
W(rd_idx) = W(rn_idx);
}
}
static void UpdateFlag(uint64_t res, uint64_t arg1, uint64_t arg2) {
uint32_t nzcv;
if (res & (1ULL << 63)) nzcv |= N_MASK; // N
if (res) nzcv |= Z_MASK; // Z
if (((arg1 & arg2) + (arg1 ^ arg2) >> 1) >> 63) nzcv |= C_MASK; //C (half adder ((x & y) + ((x ^ y) >> 1)))
if ((arg1 ^ arg2) & (arg2 ^ res)) nzcv |= V_MASK; //V
NZCV = nzcv;
}
static uint64_t RotateRight(uint64_t val, uint64_t rot) {
uint64_t left = (val & (1 << rot - 1)) << (64 - rot);
return left | (val >> rot);
}
static uint64_t ALCalc(uint64_t arg1, uint64_t arg2, OpType op) {
if (op == AL_TYPE_ADD)
return arg1 + arg2;

View file

@ -12,6 +12,9 @@ virtual void DepositiI64(unsigned int reg_idx, unsigned int pos, uint64_t imm, b
/* Mov between registers */
virtual void MovReg(unsigned int rd_idx, unsigned int rn_idx, bool bit64) = 0;
/* Conditional mov between registers */
virtual void CondMovReg(unsigned int cond, unsigned int rd_idx, unsigned int rn_idx, bool bit64) = 0;
/* Add/Sub with Immediate value */
virtual void AddI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t imm, bool setflags, bool bit64) = 0;
virtual void SubI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t imm, bool setflags, bool bit64) = 0;

View file

@ -12,6 +12,9 @@ void DepositiI64(unsigned int reg_idx, unsigned int pos, uint64_t imm, bool bit6
/* Mov between registers */
void MovReg(unsigned int rd_idx, unsigned int rn_idx, bool bit64);
/* Conditional mov between registers */
void CondMovReg(unsigned int cond, unsigned int rd_idx, unsigned int rn_idx, bool bit64);
/* Add/Sub with Immediate value */
void AddI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t imm, bool setflags, bool bit64);
void SubI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t imm, bool setflags, bool bit64);