Add support for data processing with 2 src operation

This commit is contained in:
rkx1209 2018-02-26 19:10:45 +09:00
parent 8331633c7f
commit 405c2a8fbe
5 changed files with 185 additions and 78 deletions

View file

@ -2,7 +2,11 @@
#include "Nsemu.hpp"
namespace Disassembler {
static void UnallocatedOp(uint32_t insn) {
static inline void UnsupportedOp (const char *op) {
ns_abort ("[TODO] Unsupported op %s (Disas fail)\n", op);
}
static inline void UnallocatedOp(uint32_t insn) {
ns_abort ("Unallocated operation 0x%08lx\n", insn);
}
@ -139,7 +143,6 @@ static void DisasMovwImm(uint32_t insn, DisasCallback *cb) {
cb->MoviI64 (rd, imm, is_64bit);
break;
case 3: /* MOVK */
//TODO: deposit(keep destionation bit)
cb->DepositiI64 (rd, pos, imm, is_64bit);
break;
default:
@ -193,12 +196,14 @@ static void DisasBitfield(uint32_t insn, DisasCallback *cb) {
if (opc == 1) { /* BFM, BXFIL */
//TODO: deposit
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. */
//TODO: ???
//tcg_gen_deposit_z_i64(tcg_rd, tcg_tmp, pos, len);
UnsupportedOp ("SBFM/UBFM");
}
return;
}
@ -220,12 +225,10 @@ static void DisasExtract(uint32_t insn, DisasCallback *cb) {
if (imm == 0) {
cb->MovReg(rd, rm, sf);
} else if (rm == rn) { /* ROR */
// TODO:
//cb->RorI64(rd, rm, imm)
cb->ShiftI64 (rd, rm, ShiftType_ROR, imm, sf);
} else {
// TODO:
//cb->ShriI64(rm, rm, imm)
//cb->ShliI64(rn, rn, imm)
cb->ShiftI64 (rm, rm, ShiftType_LSR, imm, sf);
cb->ShiftI64 (rn, rn, ShiftType_LSR, imm, sf);
cb->OrrReg(rd, rm, rn, sf);
}
}
@ -326,10 +329,11 @@ static void DisasUncondBrReg(uint32_t insn, DisasCallback *cb) {
break;
case 4: /* ERET */
//TODO:
UnsupportedOp ("ERET");
break;
case 5: /* DRPS */
//TODO:
UnallocatedOp (insn);
UnsupportedOp ("DRPS");
break;
default:
UnallocatedOp (insn);
@ -349,9 +353,11 @@ static void DisasException(uint32_t insn, DisasCallback *cb) {
break;
case 2: /* HVC */
//TODO:
UnsupportedOp ("HVC");
break;
case 3: /* SMC */
//TODO:
UnsupportedOp ("SMC");
break;
default:
UnallocatedOp (insn);
@ -359,12 +365,15 @@ static void DisasException(uint32_t insn, DisasCallback *cb) {
}
case 1: /* BRK */
//TODO:
UnsupportedOp ("BRK");
break;
case 2: /* HLT */
UnsupportedOp ("HLT");
//TODO:
break;
case 5: /* DCPS1,2,3 */
//TODO:
UnsupportedOp ("DCPS");
break;
default:
UnallocatedOp (insn);
@ -392,6 +401,7 @@ static void DisasBranchExcSys(uint32_t insn, DisasCallback *cb) {
if (insn & (1 << 24)) {
//TODO:
//DisasSystem (insn, cb);
UnsupportedOp ("System");
} else {
DisasException (insn, cb);
}
@ -602,6 +612,56 @@ static void DisasDataProc1src(uint32_t insn, DisasCallback *cb) {
}
}
static void DisasDataProc2src(uint32_t insn, DisasCallback *cb) {
unsigned int sf = extract32(insn, 31, 1);
unsigned int rm = extract32(insn, 16, 5);
unsigned int opcode = extract32(insn, 10, 6);
unsigned int rn = extract32(insn, 5, 5);
unsigned int rd = extract32(insn, 0, 5);
if (extract32(insn, 29, 1)) {
UnallocatedOp (insn);
return;
}
switch (opcode) {
case 2: /* UDIV */
cb->DivReg (rd, rn, rm, false, sf);
break;
case 3: /* SDIV */
cb->DivReg (rd, rn, rm, true, sf);
break;
case 8: /* LSLV */
cb->ShiftReg (rd, rn, rm, ShiftType_LSL, sf);
break;
case 9: /* LSRV */
cb->ShiftReg (rd, rn, rm, ShiftType_LSR, sf);
break;
case 10: /* ASRV */
cb->ShiftReg (rd, rn, rm, ShiftType_ASR, sf);
break;
case 11: /* RORV */
cb->ShiftReg (rd, rn, rm, ShiftType_ROR, sf);
break;
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23: /* CRC32 */
{
unsigned int sz = extract32(opcode, 0, 2);
bool crc32c = extract32(opcode, 2, 1);
/* TODO: */
UnsupportedOp ("CRC32");
break;
}
default:
UnallocatedOp (insn);
break;
}
}
static void DisasDataProcReg(uint32_t insn, DisasCallback *cb) {
switch (extract32(insn, 24, 5)) {
case 0x0a: /* Logical (shifted register) */
@ -616,6 +676,7 @@ static void DisasDataProcReg(uint32_t insn, DisasCallback *cb) {
break;
case 0x1b: /* Data-processing (3 source) */
/* TODO */
UnsupportedOp ("DataProc3src");
break;
case 0x1a:
switch (extract32(insn, 21, 3)) {
@ -632,7 +693,7 @@ static void DisasDataProcReg(uint32_t insn, DisasCallback *cb) {
if (insn & (1 << 30)) { /* (1 source) */
DisasDataProc1src (insn, cb);
} else { /* (2 source) */
DisasDataProc2src (insn, cb);
}
break;
default:

View file

@ -33,6 +33,8 @@ enum OpType{
AL_TYPE_AND,
AL_TYPE_OR,
AL_TYPE_EOR,
AL_TYPE_SDIV,
AL_TYPE_UDIV,
};
const char *OpStrs[] = { "<<", ">>", ">>", "ROR", "+", "-", "&", "|", "^" };
@ -59,6 +61,93 @@ static bool CondHold(unsigned int cond) {
return false;
}
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 ReverseBit64(uint64_t x) {
/* Assign the correct byte position. */
x = byte_swap64_uint(x);
/* Assign the correct nibble position. */
x = ((x & 0xf0f0f0f0f0f0f0f0ull) >> 4)
| ((x & 0x0f0f0f0f0f0f0f0full) << 4);
/* Assign the correct bit position. */
x = ((x & 0x8888888888888888ull) >> 3)
| ((x & 0x4444444444444444ull) >> 1)
| ((x & 0x2222222222222222ull) << 1)
| ((x & 0x1111111111111111ull) << 3);
return x;
}
static uint64_t Udiv64(uint64_t arg1, uint64_t arg2) {
if (arg2 == 0)
return 0;
return arg1 / arg2;
}
static int64_t Sdiv64(int64_t arg1, int64_t arg2) {
if (arg2 == 0)
return 0;
if (arg1 == LLONG_MIN && arg2 == -1) {
return LLONG_MIN;
}
return arg1 / arg2;
}
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)
return arg1 | arg2;
if (op == AL_TYPE_EOR)
return arg1 ^ arg2;
if (op == AL_TYPE_LSL)
return arg1 << arg2;
if (op == AL_TYPE_LSR)
return arg1 >> arg2;
if (op == AL_TYPE_ASR)
return (int64_t) arg1 >> arg2;
if (op == AL_TYPE_ROR)
return RotateRight (arg1, arg2);
if (op == AL_TYPE_UDIV) {
return Udiv64 (arg1, arg2);
}
if (op == AL_TYPE_SDIV) {
return Sdiv64 (arg1, arg2);
}
return 0;
}
static void ArithmeticLogic(unsigned int rd_idx, uint64_t arg1, uint64_t arg2, bool setflags, bool bit64, OpType op) {
uint64_t result;
if (bit64) {
result = ALCalc (arg1, arg2, op);
if (setflags)
UpdateFlag (result, arg1, arg2);
X(rd_idx) = result;
}
else {
result = ALCalc (arg1, arg2, op);
if (setflags)
UpdateFlag (result, arg1, arg2);
W(rd_idx) = result;
}
}
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);
@ -101,72 +190,6 @@ void IntprCallback::CondMovReg(unsigned int cond, unsigned int rd_idx, unsigned
}
}
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 ReverseBit64(uint64_t x) {
/* Assign the correct byte position. */
x = byte_swap64_uint(x);
/* Assign the correct nibble position. */
x = ((x & 0xf0f0f0f0f0f0f0f0ull) >> 4)
| ((x & 0x0f0f0f0f0f0f0f0full) << 4);
/* Assign the correct bit position. */
x = ((x & 0x8888888888888888ull) >> 3)
| ((x & 0x4444444444444444ull) >> 1)
| ((x & 0x2222222222222222ull) << 1)
| ((x & 0x1111111111111111ull) << 3);
return x;
}
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)
return arg1 | arg2;
if (op == AL_TYPE_EOR)
return arg1 ^ arg2;
if (op == AL_TYPE_LSL)
return arg1 << arg2;
if (op == AL_TYPE_LSR)
return arg1 >> arg2;
if (op == AL_TYPE_ASR)
return (int64_t) arg1 >> arg2;
if (op == AL_TYPE_ROR)
return RotateRight (arg1, arg2);
return 0;
}
static void ArithmeticLogic(unsigned int rd_idx, uint64_t arg1, uint64_t arg2, bool setflags, bool bit64, OpType op) {
uint64_t result;
if (bit64) {
result = ALCalc (arg1, arg2, op);
if (setflags)
UpdateFlag (result, arg1, arg2);
X(rd_idx) = result;
}
else {
result = ALCalc (arg1, arg2, op);
if (setflags)
UpdateFlag (result, arg1, arg2);
W(rd_idx) = result;
}
}
/* Add/Sub with Immediate value */
void IntprCallback::AddI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t imm, bool setflags, bool bit64) {
char regc = bit64? 'X': 'W';
@ -185,7 +208,7 @@ void IntprCallback::SubI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t im
ArithmeticLogic (rd_idx, W(rn_idx), imm, setflags, bit64, AL_TYPE_SUB);
}
/* Add/Sub between registers */
/* Add/Sub/Div/Shift between registers */
void IntprCallback::AddReg(unsigned int rd_idx, unsigned int rn_idx, unsigned int rm_idx, bool setflags, bool bit64) {
char regc = bit64? 'X': 'W';
debug_print ("Add: %c[%u] = %c[%u] + %c[%u] (flag: %s)\n", regc, rd_idx, regc, rn_idx, regc, rm_idx, setflags? "update": "no");
@ -202,6 +225,23 @@ 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::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);
if (bit64)
ArithmeticLogic (rd_idx, X(rn_idx), X(rm_idx), false, bit64, sign?AL_TYPE_SDIV:AL_TYPE_UDIV);
else
ArithmeticLogic (rd_idx, W(rn_idx), W(rm_idx), false, bit64, sign?AL_TYPE_SDIV:AL_TYPE_UDIV);
}
void IntprCallback::ShiftReg(unsigned int rd_idx, unsigned int rn_idx, unsigned int rm_idx, unsigned int shift_type, bool bit64) {
char regc = bit64? 'X': 'W';
debug_print ("Shift: %c[%u] = %c[%u] %s %c[%u] \n", regc, rd_idx, regc, rn_idx, OpStrs[shift_type], regc, rm_idx);
if (bit64)
ArithmeticLogic (rd_idx, X(rn_idx), X(rm_idx), false, bit64, (OpType)shift_type);
else
ArithmeticLogic (rd_idx, W(rn_idx), W(rm_idx), false, bit64, (OpType)shift_type);
}
/* Add/Sub with carry flag between registers */
void IntprCallback::AddcReg(unsigned int rd_idx, unsigned int rn_idx, unsigned int rm_idx, bool setflags, bool bit64) {

View file

@ -19,9 +19,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 between registers */
/* Add/Sub/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 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;
/* Add/Sub with carry flag between registers */
virtual void AddcReg(unsigned int rd_idx, unsigned int rn_idx, unsigned int rm_idx, bool setflags, bool bit64) = 0;

View file

@ -19,9 +19,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 between registers */
/* Add/Sub/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 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) ;
/* Add/Sub with carry flag between registers */
void AddcReg(unsigned int rd_idx, unsigned int rn_idx, unsigned int rm_idx, bool setflags, bool bit64);

View file

@ -3,6 +3,7 @@
#include <stdint.h>
#include <cassert>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <fstream>
@ -10,6 +11,7 @@
#include <string>
#include <map>
#include <vector>
using namespace std;
#include "Memory.hpp"