mirror of
https://github.com/RKX1209/nsemu.git
synced 2024-06-23 14:43:16 -04:00
Add support for data processing with 2 src operation
This commit is contained in:
parent
8331633c7f
commit
405c2a8fbe
|
@ -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:
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue