Add support of 3src data proc(i.e MADD,SUB/MUL)

This commit is contained in:
rkx1209 2018-03-18 20:12:48 +09:00
parent fce85f7a91
commit b0e8996b59
4 changed files with 140 additions and 9 deletions

View file

@ -531,6 +531,61 @@ static void DisasAddSubReg(uint32_t insn, DisasCallback *cb) {
}
}
static void DisasDataProc3src(uint32_t insn, DisasCallback *cb) {
unsigned int rd = extract32(insn, 0, 5);
unsigned int rn = extract32(insn, 5, 5);
unsigned int ra = extract32(insn, 10, 5);
unsigned int rm = extract32(insn, 16, 5);
unsigned int op_id = (extract32(insn, 29, 3) << 4) |
(extract32(insn, 21, 3) << 1) | extract32(insn, 15, 1);
bool sf = extract32(insn, 31, 1);
bool is_sub = extract32(op_id, 0, 1);
bool is_high = extract32(op_id, 2, 1);
bool is_signed = false;
bool src64 = false;
/* Note that op_id is sf:op54:op31:o0 so it includes the 32/64 size flag */
switch (op_id) {
case 0x42: /* SMADDL */
case 0x43: /* SMSUBL */
case 0x44: /* SMULH */
is_signed = true;
break;
case 0x0: /* MADD (32bit) */
case 0x1: /* MSUB (32bit) */
case 0x40: /* MADD (64bit) */
case 0x41: /* MSUB (64bit) */
case 0x4a: /* UMADDL */
case 0x4b: /* UMSUBL */
case 0x4c: /* UMULH */
break;
default:
UnallocatedOp (insn);
return;
}
if (is_high) {
/* SMULH, UMULH ... [Multiply High] */
cb->Mul2Reg (rd, GPR_DUMMY, rn, rm, is_signed);
} else {
/*
* sf = 0: MADD(32bit), MSUB(32bit) ... Wd = Wa +/- Wn * Wm
* sf = 1: (op_id < 0x42) MADD(64bit), MSUB(64bit) ... Xd = Xa +/- Xn * Xm
(sign = 0) UMADDL(UMULL), UMSUBL(UMNEGL) ... [Multiply Long 32bit*32bit] Xd = Wa +/- Wn * Wm
* (sign = 1) SMADDL(SMULL), SMSUBL(SMNEGL) ... [Multiply Long 32bit*32bit] Xd = Wa +/- Wn * Wm
*/
if (op_id < 0x42) {
/* MADD(64bit), MSUB(64bit) */
src64 = true;
}
cb->MulReg (rd, rn, rm, is_signed, sf, src64);
if (is_sub)
cb->SubReg (rd, ra, rd, false, src64);
else
cb->AddReg (rd, ra, rd, false, src64);
}
}
static void DisasAddSubcReg(uint32_t insn, DisasCallback *cb) {
unsigned int sf = extract32(insn, 31, 1);
unsigned int sub_op = extract32(insn, 30, 1);
@ -681,7 +736,7 @@ static void DisasDataProc2src(uint32_t insn, DisasCallback *cb) {
static void DisasDataProcReg(uint32_t insn, DisasCallback *cb) {
switch (extract32(insn, 24, 5)) {
case 0x0a: /* Logical (shifted register) */
DisasLogicReg(insn, cb);
DisasLogicReg (insn, cb);
break;
case 0x0b: /* Add/subtract */
if (insn & (1 << 21)) { /* (extended register) */
@ -691,8 +746,7 @@ static void DisasDataProcReg(uint32_t insn, DisasCallback *cb) {
}
break;
case 0x1b: /* Data-processing (3 source) */
/* TODO */
UnsupportedOp ("DataProc3src");
DisasDataProc3src (insn, cb);
break;
case 0x1a:
switch (extract32(insn, 21, 3)) {
@ -793,7 +847,7 @@ static void DisasLdstRegRoffset(uint32_t insn, DisasCallback *cb,
is_store = (opc == 0);
is_signed = extract32(opc, 1, 1);
//is_extended = (size < 3) && extract32(opc, 0, 1);
is_extended = (size < 3); //TODO: treat other case, size = 0, 1(8bit-> or 16bit->)
is_extended = (size < 3); //TODO: treat other case, size = 0, 1(8bit-> or 16bit->)
}
bool sf = DisasLdstCompute64bit (size, is_signed, opc);
cb->ExtendReg (GPR_DUMMY, rm, opt, sf); //FIXME: When rm == GPR_ZERO, it should be handled as GPR_SP

View file

@ -17,11 +17,12 @@ int Interpreter::SingleStep() {
void Interpreter::Run() {
debug_print ("Running with Interpreter\n");
static uint64_t counter = 0;
uint64_t estimate = 3404800;
uint64_t estimate = 3404800, mx = 1000;
while (Cpu::GetState () == Cpu::State::Running) {
char c;
//scanf("%c", &c);
if (counter >= estimate) {
//if (counter >= estimate && counter <= estimate + mx){
Cpu::DumpMachine ();
}
SingleStep ();
@ -42,6 +43,7 @@ enum OpType{
AL_TYPE_EOR,
AL_TYPE_SDIV,
AL_TYPE_UDIV,
AL_TYPE_MUL,
};
const char *OpStrs[] = { "<<", ">>", ">>", "ROR", "+", "-", "&", "|", "^" };
@ -119,11 +121,53 @@ static int64_t Sdiv64(int64_t arg1, int64_t arg2) {
return arg1 / arg2;
}
static void Umul64(uint64_t *res_h, uint64_t *res_l, uint64_t arg1, uint64_t arg2) {
typedef union {
uint64_t ll;
struct {
uint32_t low, high;
} l;
} LL;
LL rl, rm, rn, rh, a0, b0;
uint64_t c;
a0.ll = arg1;
b0.ll = arg2;
rl.ll = (uint64_t)a0.l.low * b0.l.low;
rm.ll = (uint64_t)a0.l.low * b0.l.high;
rn.ll = (uint64_t)a0.l.high * b0.l.low;
rh.ll = (uint64_t)a0.l.high * b0.l.high;
c = (uint64_t)rl.l.high + rm.l.low + rn.l.low;
rl.l.high = c;
c >>= 32;
c = c + rm.l.high + rn.l.high + rh.l.low;
rh.l.low = c;
rh.l.high += (uint32_t)(c >> 32);
*res_l = rl.ll;
*res_h = rh.ll;
}
static void Smul64(uint64_t *res_h, uint64_t *res_l, uint64_t arg1, uint64_t arg2) {
uint64_t rh;
Umul64(res_l, &rh, arg1, arg2);
/* Adjust for signs. */
if (arg2 < 0) {
rh -= arg1;
}
if (arg1 < 0) {
rh -= arg2;
}
*res_h = rh;
}
static uint64_t ALCalc(uint64_t arg1, uint64_t arg2, OpType op) {
if (op == AL_TYPE_ADD)
return arg1 + arg2;
// if (op == AL_TYPE_SUB)
// return arg1 - arg2;
if (op == AL_TYPE_AND)
return arg1 & arg2;
if (op == AL_TYPE_OR)
@ -144,6 +188,9 @@ static uint64_t ALCalc(uint64_t arg1, uint64_t arg2, OpType op) {
if (op == AL_TYPE_SDIV) {
return Sdiv64 (arg1, arg2);
}
if (op == AL_TYPE_MUL) {
return arg1 * arg2;
}
return 0;
}
@ -262,6 +309,32 @@ void IntprCallback::SubReg(unsigned int rd_idx, unsigned int rn_idx, unsigned in
else
ArithmeticLogic (rd_idx, W(rn_idx), W(rm_idx), setflags, bit64, AL_TYPE_SUB);
}
void IntprCallback::MulReg(unsigned int rd_idx, unsigned int rn_idx, unsigned int rm_idx, bool sign, bool dst64, bool src64) {
char regdc = dst64? 'X': 'W';
char regsc = src64? 'X': 'W';
debug_print ("%cMUL: %c[%u] = %c[%u] * %c[%u] \n", sign?'S':'U', regdc, rd_idx, regsc, rn_idx, regsc, rm_idx);
if (dst64) {
if (src64) {
X(rd_idx) = X(rn_idx) * X(rm_idx);
} else {
if (sign)
X(rd_idx) = (int64_t)((int32_t)W(rn_idx) * (int32_t)W(rm_idx));
else
X(rd_idx) = W(rn_idx) * W(rm_idx);
}
} else {
W(rd_idx) = W(rn_idx) * W(rm_idx);
}
}
//64bit * 64bit
void IntprCallback::Mul2Reg(unsigned int rh_idx, unsigned int rl_idx, unsigned int rn_idx, unsigned int rm_idx, bool sign) {
debug_print ("%cMUL2: X[%u], X[%u] = X[%u] * X[%u] \n", sign?'S':'U', rh_idx, rl_idx, rn_idx, rm_idx);
if (sign)
Smul64(&X(rh_idx), &X(rl_idx), X(rn_idx), X(rm_idx));
else
Umul64(&X(rh_idx), &X(rl_idx), X(rn_idx), X(rm_idx));
}
void IntprCallback::DivReg(unsigned int rd_idx, unsigned int rn_idx, unsigned int rm_idx, bool sign, bool bit64) {
char regc = bit64? 'X': 'W';
debug_print ("%cDIV: %c[%u] = %c[%u] / %c[%u] \n", sign?'S':'U', regc, rd_idx, regc, rn_idx, regc, rm_idx);

View file

@ -22,9 +22,11 @@ virtual void CondMovReg(unsigned int cond, unsigned int rd_idx, unsigned int rn_
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;
/* Add/Sub/Div between registers */
/* Add/Sub/Mul/Div between registers */
virtual void AddReg(unsigned int rd_idx, unsigned int rn_idx, unsigned int rm_idx, bool setflags, bool bit64) = 0;
virtual void SubReg(unsigned int rd_idx, unsigned int rn_idx, unsigned int rm_idx, bool setflags, bool bit64) = 0;
virtual void MulReg(unsigned int rd_idx, unsigned int rn_idx, unsigned int rm_idx, bool sign, bool dst64, bool src64) = 0;
virtual void Mul2Reg(unsigned int rh_idx, unsigned int rl_idx, unsigned int rn_idx, unsigned int rm_idx, bool sign) = 0; //64bit * 64bit
virtual void DivReg(unsigned int rd_idx, unsigned int rn_idx, unsigned int rm_idx, bool sign, bool bit64) = 0;
virtual void ShiftReg(unsigned int rd_idx, unsigned int rn_idx, unsigned int rm_idx, unsigned int shift_type, bool bit64) = 0;

View file

@ -22,9 +22,11 @@ void CondMovReg(unsigned int cond, unsigned int rd_idx, unsigned int rn_idx, boo
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);
/* Add/Sub/Div between registers */
/* Add/Sub/Mul/Div between registers */
void AddReg(unsigned int rd_idx, unsigned int rn_idx, unsigned int rm_idx, bool setflags, bool bit64);
void SubReg(unsigned int rd_idx, unsigned int rn_idx, unsigned int rm_idx, bool setflags, bool bit64);
void MulReg(unsigned int rd_idx, unsigned int rn_idx, unsigned int rm_idx, bool sign, bool dst64, bool src64);
void Mul2Reg(unsigned int rh_idx, unsigned int rl_idx, unsigned int rn_idx, unsigned int rm_idx, bool sign); //64bit * 64bit
void DivReg(unsigned int rd_idx, unsigned int rn_idx, unsigned int rm_idx, bool sign, bool bit64);
void ShiftReg(unsigned int rd_idx, unsigned int rn_idx, unsigned int rm_idx, unsigned int shift_type, bool bit64) ;