mirror of
https://github.com/RKX1209/nsemu.git
synced 2024-06-23 14:43:16 -04:00
Add support for conditional select operation
This commit is contained in:
parent
1cf270a02e
commit
806ac7dabf
|
@ -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) */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue