mirror of
https://github.com/RKX1209/nsemu.git
synced 2024-06-21 13:42:37 -04:00
Add disassembler for all data proc imm operations
This commit is contained in:
parent
713b1e0818
commit
da24be5562
|
@ -8,7 +8,37 @@ static void UnallocatedOp(uint32_t insn) {
|
|||
|
||||
static bool LogicImmDecode(uint64_t *wmask, unsigned int immn, unsigned int imms, unsigned int immr) {
|
||||
assert (immn < 2 && imms < 64 && immr < 64);
|
||||
uint64_t mask;
|
||||
unsigned int e, levels, s, r;
|
||||
int len = 31 - clz32((immn << 6 | (~imms & 0x3f)));
|
||||
if (len < 1) {
|
||||
/* This is the immn == 0, imms == 0x11111x case */
|
||||
return false;
|
||||
}
|
||||
e = 1 << len;
|
||||
|
||||
levels = e - 1;
|
||||
s = imms & levels;
|
||||
r = immr & levels;
|
||||
|
||||
if (s == levels) {
|
||||
/* <length of run - 1> mustn't be all-ones. */
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Create the value of one element: s+1 set bits rotated
|
||||
* by r within the element (which is e bits wide)...
|
||||
*/
|
||||
mask = bitmask64(s + 1);
|
||||
if (r) {
|
||||
mask = (mask >> r) | (mask << (e - r));
|
||||
mask &= bitmask64(e);
|
||||
}
|
||||
mask = replicate64 (mask, e);
|
||||
*wmask = mask;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void DisasPCRelAddr(uint32_t insn, DisasCallback *cb) {
|
||||
unsigned int rd, page;
|
||||
uint64_t offset, base;
|
||||
|
@ -24,7 +54,7 @@ static void DisasPCRelAddr(uint32_t insn, DisasCallback *cb) {
|
|||
offset <<= 12;
|
||||
}
|
||||
|
||||
cb->MoviI64 (rd, base + offset);
|
||||
cb->MoviI64 (rd, base + offset, false, true);
|
||||
}
|
||||
|
||||
static void DisasAddSubImm(uint32_t insn, DisasCallback *cb) {
|
||||
|
@ -87,6 +117,121 @@ static void DisasLogImm(uint32_t insn, DisasCallback *cb) {
|
|||
}
|
||||
}
|
||||
|
||||
static void DisasMovwImm(uint32_t insn, DisasCallback *cb) {
|
||||
unsigned int is_64bit = extract32(insn, 31, 1);
|
||||
unsigned int opc = extract32(insn, 29, 2);
|
||||
uint64_t imm = extract32(insn, 5, 16);
|
||||
unsigned int pos = extract32(insn, 21, 2) << 4;
|
||||
unsigned int rd = extract32(insn, 0, 5);
|
||||
|
||||
if (!is_64bit && (pos >= 32)) {
|
||||
UnallocatedOp (insn);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (opc) {
|
||||
case 0: /* MOVN */
|
||||
case 2: /* MOVZ */
|
||||
imm <<= pos;
|
||||
if (opc == 0) {
|
||||
imm = ~imm;
|
||||
}
|
||||
cb->MoviI64 (rd, imm, false, is_64bit);
|
||||
break;
|
||||
case 3: /* MOVK */
|
||||
cb->MoviI64 (rd, imm, true, is_64bit);
|
||||
break;
|
||||
default:
|
||||
UnallocatedOp (insn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void DisasBitfield(uint32_t insn, DisasCallback *cb) {
|
||||
unsigned int is_64bit = extract32(insn, 31, 1);
|
||||
unsigned int opc = extract32(insn, 29, 2);
|
||||
unsigned int n = extract32(insn, 22, 1);
|
||||
unsigned int ri = extract32(insn, 16, 6);
|
||||
unsigned int si = extract32(insn, 10, 6);
|
||||
unsigned int rn = extract32(insn, 5, 5);
|
||||
unsigned int rd = extract32(insn, 0, 5);
|
||||
unsigned int bitsize = is_64bit ? 64 : 32;
|
||||
unsigned int pos, len;
|
||||
if (is_64bit != n || ri >= bitsize || si >= bitsize || opc > 2) {
|
||||
UnallocatedOp(insn);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Recognize simple(r) extractions. */
|
||||
if (si >= ri) {
|
||||
/* Wd<s-r:0> = Wn<s:r> */
|
||||
len = (si - ri) + 1;
|
||||
if (opc == 0) { /* SBFM: ASR, SBFX, SXTB, SXTH, SXTW */
|
||||
cb->SExtractI64(rd, rn, ri, len, is_64bit);
|
||||
return;
|
||||
} else if (opc == 2) { /* UBFM: UBFX, LSR, UXTB, UXTH */
|
||||
cb->UExtractI64(rd, rn, ri, len, is_64bit);
|
||||
return;
|
||||
}
|
||||
pos = 0;
|
||||
} else {
|
||||
/* Handle the ri > si case with a deposit
|
||||
* Wd<32+s-r,32-r> = Wn<s:0>
|
||||
*/
|
||||
len = si + 1;
|
||||
pos = (bitsize - ri) & (bitsize - 1);
|
||||
}
|
||||
|
||||
if (opc == 0 && len < ri) {
|
||||
/* SBFM: sign extend the destination field from len to fill
|
||||
the balance of the word. Let the deposit below insert all
|
||||
of those sign bits. */
|
||||
cb->SExtractI64(rd, rn, 0, len, is_64bit);
|
||||
len = ri;
|
||||
}
|
||||
|
||||
if (opc == 1) { /* BFM, BXFIL */
|
||||
//TODO: deposit
|
||||
} 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);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void DisasExtract(uint32_t insn, DisasCallback *cb) {
|
||||
unsigned int sf = extract32(insn, 31, 1);
|
||||
unsigned int n = extract32(insn, 22, 1);
|
||||
unsigned int rm = extract32(insn, 16, 5);
|
||||
unsigned int imm = extract32(insn, 10, 6);
|
||||
unsigned int rn = extract32(insn, 5, 5);
|
||||
unsigned int rd = extract32(insn, 0, 5);
|
||||
unsigned int op21 = extract32(insn, 29, 2);
|
||||
unsigned int op0 = extract32(insn, 21, 1);
|
||||
unsigned int bitsize = sf ? 64 : 32;
|
||||
|
||||
if (sf != n || op21 || op0 || imm >= bitsize) {
|
||||
UnallocatedOp (insn);
|
||||
} else {
|
||||
if (imm == 0) {
|
||||
// TODO: mov rd, rm
|
||||
//cb->MovI64(rd, rm, sf);
|
||||
} else if (rm == rn) { /* ROR */
|
||||
// TODO:
|
||||
//cb->RorI64(rd, rm, imm)
|
||||
} else {
|
||||
// TODO:
|
||||
//cb->ShriI64(rm, rm, imm)
|
||||
//cb->ShliI64(rn, rn, imm)
|
||||
//cb->OrrI64(rd, rm, rn);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void DisasDataProcImm(uint32_t insn, DisasCallback *cb) {
|
||||
switch (extract32 (insn, 23, 6)) {
|
||||
case 0x20: case 0x21: /* PC-rel. addressing */
|
||||
|
@ -99,10 +244,13 @@ static void DisasDataProcImm(uint32_t insn, DisasCallback *cb) {
|
|||
DisasLogImm (insn, cb);
|
||||
break;
|
||||
case 0x25: /* Move wide (immediate) */
|
||||
DisasMovwImm (insn, cb);
|
||||
break;
|
||||
case 0x26: /* Bitfield */
|
||||
DisasBitfield (insn, cb);
|
||||
break;
|
||||
case 0x27: /* Extract */
|
||||
DisasExtract (insn, cb);
|
||||
break;
|
||||
default:
|
||||
UnallocatedOp (insn);
|
||||
|
|
|
@ -1,37 +1,40 @@
|
|||
/* nsemu - LGPL - Copyright 2017 rkx1209<rkx1209dev@gmail.com> */
|
||||
#include "Nsemu.hpp"
|
||||
|
||||
Interpreter *Interpreter ::inst = nullptr;
|
||||
IntprCallback *Interpreter ::disas_cb = nullptr;
|
||||
Interpreter *Interpreter::inst = nullptr;
|
||||
IntprCallback *Interpreter::disas_cb = nullptr;
|
||||
|
||||
int Interpreter ::SingleStep() {
|
||||
uint32_t inst = ARMv8 ::ReadInst (PC);
|
||||
int Interpreter::SingleStep() {
|
||||
uint32_t inst = ARMv8::ReadInst (PC);
|
||||
debug_print ("Run Code: 0x%08lx\n", inst);
|
||||
PC += sizeof(uint32_t);
|
||||
Disassembler ::DisasA64 (inst, disas_cb);
|
||||
Disassembler::DisasA64 (inst, disas_cb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Interpreter ::Run() {
|
||||
void Interpreter::Run() {
|
||||
debug_print ("Running with Interpreter\n");
|
||||
while (Cpu ::GetState () == Cpu ::State ::Running) {
|
||||
while (Cpu::GetState () == Cpu::State::Running) {
|
||||
SingleStep ();
|
||||
}
|
||||
}
|
||||
|
||||
void IntprCallback ::MoviI64(unsigned int reg_idx, uint64_t imm) {
|
||||
debug_print ("Mov: X[%u] = 0x%016lx\n", reg_idx, imm);
|
||||
void IntprCallback::MoviI64(unsigned int reg_idx, uint64_t imm, bool unchanged, bool bit64) {
|
||||
char regc = bit64? 'X': 'W';
|
||||
debug_print ("MOV%c: %c[%u] = 0x%016lx\n", unchanged? 'K' : ' ', regc, reg_idx, imm);
|
||||
}
|
||||
|
||||
/* Add/Sub with Immediate value */
|
||||
void IntprCallback ::AddiI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t imm, bool setflags, bool bit64) {
|
||||
void IntprCallback::AddiI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t imm, bool setflags, bool bit64) {
|
||||
char regc = bit64? 'X': 'W';
|
||||
debug_print ("Add: %c[%u] = %c[%u] + 0x%016lx (flag: %s)\n", regc, rd_idx, regc, rn_idx, imm, setflags? "update": "no");
|
||||
}
|
||||
void IntprCallback ::SubiI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t imm, bool setflags, bool bit64) {
|
||||
void IntprCallback::SubiI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t imm, bool setflags, bool bit64) {
|
||||
char regc = bit64? 'X': 'W';
|
||||
debug_print ("Sub: %c[%u] = %c[%u] + 0x%016lx (flag: %s)\n", regc, rd_idx, regc, rn_idx, imm, setflags? "update": "no");
|
||||
}
|
||||
void IntprCallback ::AndiI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wmask, bool setflags, bool bit64) {}
|
||||
void IntprCallback ::OrrI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wmask, bool bit64) {}
|
||||
void IntprCallback ::EorI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wmask, bool bit64) {}
|
||||
void IntprCallback::AndiI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wmask, bool setflags, bool bit64) {}
|
||||
void IntprCallback::OrrI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wmask, bool bit64) {}
|
||||
void IntprCallback::EorI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wmask, bool bit64) {}
|
||||
void IntprCallback::SExtractI64(unsigned int rd_idx, unsigned int rn_idx, unsigned int pos, unsigned int len, bool bit64) {}
|
||||
void IntprCallback::UExtractI64(unsigned int rd_idx, unsigned int rn_idx, unsigned int pos, unsigned int len, bool bit64) {}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
class DisasCallback {
|
||||
public:
|
||||
virtual void MoviI64(unsigned int reg_idx, uint64_t imm) = 0;
|
||||
virtual void MoviI64(unsigned int reg_idx, uint64_t imm, bool unchanged, bool bit64) = 0;
|
||||
/* Add/Sub with Immediate value */
|
||||
virtual void AddiI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t imm, bool setflags, bool bit64) = 0;
|
||||
virtual void SubiI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t imm, bool setflags, bool bit64) = 0;
|
||||
|
@ -11,6 +11,10 @@ virtual void SubiI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t imm, boo
|
|||
virtual void AndiI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wmask, bool setflags, bool bit64) = 0;
|
||||
virtual void OrrI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wmask, bool bit64) = 0;
|
||||
virtual void EorI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wmask, bool bit64) = 0;
|
||||
/* Bitfield Signed/Unsigned Extract... with Immediate value */
|
||||
virtual void SExtractI64(unsigned int rd_idx, unsigned int rn_idx, unsigned int pos, unsigned int len, bool bit64) = 0;
|
||||
virtual void UExtractI64(unsigned int rd_idx, unsigned int rn_idx, unsigned int pos, unsigned int len, bool bit64) = 0;
|
||||
|
||||
};
|
||||
|
||||
namespace Disassembler {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
class IntprCallback : public DisasCallback {
|
||||
public:
|
||||
void MoviI64(unsigned int reg_idx, uint64_t imm);
|
||||
void MoviI64(unsigned int reg_idx, uint64_t imm, bool unchanged, bool bit64);
|
||||
/* Add/Sub with Immediate value */
|
||||
void AddiI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t imm, bool setflags, bool bit64);
|
||||
void SubiI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t imm, bool setflags, bool bit64);
|
||||
|
@ -11,6 +11,10 @@ void SubiI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t imm, bool setfla
|
|||
void AndiI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wmask, bool setflags, bool bit64);
|
||||
void OrrI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wmask, bool bit64);
|
||||
void EorI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wmask, bool bit64);
|
||||
/* Bitfield Signed/Unsigned Extract... with Immediate value */
|
||||
void SExtractI64(unsigned int rd_idx, unsigned int rn_idx, unsigned int pos, unsigned int len, bool bit64);
|
||||
void UExtractI64(unsigned int rd_idx, unsigned int rn_idx, unsigned int pos, unsigned int len, bool bit64);
|
||||
|
||||
};
|
||||
|
||||
/* Global Interpreter singleton class .*/
|
||||
|
|
|
@ -61,10 +61,26 @@ static inline int64_t sextract64(uint64_t bitfield, int from, int len) {
|
|||
return ((int64_t) (bitfield << (64 - from - len))) >> (64 - len);
|
||||
}
|
||||
|
||||
static inline int clz32(uint32_t val) {
|
||||
return val? __builtin_clz (val): 32;
|
||||
static inline int clz32(uint32_t bitfield) {
|
||||
return bitfield? __builtin_clz (bitfield): 32;
|
||||
}
|
||||
static inline int clz64(uint64_t val) {
|
||||
return val? __builtin_clzll (val): 64;
|
||||
|
||||
static inline int clz64(uint64_t bitfield) {
|
||||
return bitfield? __builtin_clzll (bitfield): 64;
|
||||
}
|
||||
|
||||
/* Return a value with the bottom len bits set (where 0 < len <= 64) */
|
||||
static inline uint64_t bitmask64(unsigned int length) {
|
||||
assert(length > 0 && length <= 64);
|
||||
return ~0ULL >> (64 - length);
|
||||
}
|
||||
|
||||
static uint64_t replicate64(uint64_t mask, unsigned int e) {
|
||||
assert(e != 0);
|
||||
while (e < 64) {
|
||||
mask |= mask << e;
|
||||
e *= 2;
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue