Fixed determination logic of which x31 is 'Zero register' or 'Stack Pointer'

According to C6.1.3 Use of the stack pointer, X31 must be Stack pointer,
when Add/Sub, Logical with Imm and base index of address used by Load/Store.
This commit is contained in:
rkx1209 2018-03-10 01:30:18 +09:00
parent 2052f8e8af
commit cb6c19f046
7 changed files with 50 additions and 28 deletions

View file

@ -17,7 +17,7 @@ void RunLoop() {
}
void Dump() {
for (int r = 0; r < 32; r++) {
for (int r = 0; r < GPR_DUMMY; r++) {
if (!X(r))
continue;
if (r == GPR_LR)

View file

@ -780,7 +780,7 @@ static void DisasLdstRegRoffset(uint32_t insn, DisasCallback *cb,
is_extended = (size < 3) && extract32(opc, 0, 1);
}
bool sf = DisasLdstCompute64bit (size, is_signed, opc);
cb->ExtendReg (rm, rm, opt, sf);
cb->ExtendReg (rm, rm, opt, sf); //FIXME: When rm == GPR_ZERO, it should be handled as GPR_SP
cb->ShiftReg (rm, rm, ShiftType_LSL, shift ? size : 0, sf);
if (is_store) {
cb->StoreReg (rt, rn, rm, size, is_extended, false, sf);

View file

@ -6,6 +6,7 @@ IntprCallback *Interpreter::disas_cb = nullptr;
int Interpreter::SingleStep() {
uint32_t inst = byte_swap32_uint (ARMv8::ReadInst (PC));
X(GPR_ZERO) = 0; //Reset Zero register
debug_print ("Run Code: 0x%lx: 0x%08lx\n", PC, inst);
Disassembler::DisasA64 (inst, disas_cb);
PC += sizeof(uint32_t);
@ -39,6 +40,11 @@ enum OpType{
const char *OpStrs[] = { "<<", ">>", ">>", "ROR", "+", "-", "&", "|", "^" };
/* See: C6.1.3 Use of the stack pointer */
static inline unsigned int HandleAsSP(unsigned r_idx) {
return r_idx == GPR_ZERO ? GPR_SP : r_idx;
}
static bool CondHold(unsigned int cond) {
cond >>= 1;
if (cond == 0x0)
@ -193,6 +199,10 @@ void IntprCallback::CondMovReg(unsigned int cond, unsigned int rd_idx, unsigned
/* 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';
if (!setflags) {
rd_idx = HandleAsSP (rd_idx);
rn_idx = HandleAsSP (rn_idx);
}
debug_print ("Add: %c[%u] = %c[%u] + 0x%lx (flag: %s)\n", regc, rd_idx, regc, rn_idx, imm, setflags? "update": "no");
if (bit64)
ArithmeticLogic (rd_idx, X(rn_idx), imm, setflags, bit64, AL_TYPE_ADD);
@ -201,6 +211,10 @@ void IntprCallback::AddI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t im
}
void IntprCallback::SubI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t imm, bool setflags, bool bit64) {
char regc = bit64? 'X': 'W';
if (!setflags) {
rd_idx = HandleAsSP (rd_idx);
rn_idx = HandleAsSP (rn_idx);
}
debug_print ("Sub: %c[%u] = %c[%u] - 0x%lx (flag: %s)\n", regc, rd_idx, regc, rn_idx, imm, setflags? "update": "no");
if (bit64)
ArithmeticLogic (rd_idx, X(rn_idx), imm, setflags, bit64, AL_TYPE_SUB);
@ -268,6 +282,7 @@ void IntprCallback::SubcReg(unsigned int rd_idx, unsigned int rn_idx, unsigned i
/* AND/OR/EOR... with Immediate value */
void IntprCallback::AndI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wmask, bool setflags, bool bit64) {
char regc = bit64? 'X': 'W';
rd_idx = HandleAsSP (rd_idx);
debug_print ("And: %c[%u] = %c[%u] & 0x%lx (flag: %s)\n", regc, rd_idx, regc, rn_idx, wmask, setflags? "update": "no");
if (bit64)
ArithmeticLogic (rd_idx, X(rn_idx), wmask, setflags, bit64, AL_TYPE_AND);
@ -277,6 +292,7 @@ void IntprCallback::AndI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wm
}
void IntprCallback::OrrI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wmask, bool bit64) {
char regc = bit64? 'X': 'W';
rd_idx = HandleAsSP (rd_idx);
debug_print ("Or: %c[%u] = %c[%u] | 0x%lx \n", regc, rd_idx, regc, rn_idx, wmask);
if (bit64)
ArithmeticLogic (rd_idx, X(rn_idx), wmask, false, bit64, AL_TYPE_OR);
@ -285,6 +301,7 @@ void IntprCallback::OrrI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wm
}
void IntprCallback::EorI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wmask, bool bit64) {
char regc = bit64? 'X': 'W';
rd_idx = HandleAsSP (rd_idx);
debug_print ("Eor: %c[%u] = %c[%u] ^ 0x%lx \n", regc, rd_idx, regc, rn_idx, wmask);
if (bit64)
ArithmeticLogic (rd_idx, X(rn_idx), wmask, false, bit64, AL_TYPE_EOR);
@ -293,6 +310,7 @@ void IntprCallback::EorI64(unsigned int rd_idx, unsigned int rn_idx, uint64_t wm
}
void IntprCallback::ShiftI64(unsigned int rd_idx, unsigned int rn_idx, unsigned int shift_type, unsigned int shift_amount, bool bit64) {
char regc = bit64? 'X': 'W';
rd_idx = HandleAsSP (rd_idx);
debug_print ("Shift: %c[%u] = %c[%u] %s 0x%lx \n", regc, rd_idx, regc, rn_idx, OpStrs[shift_type], shift_amount);
if (bit64)
ArithmeticLogic (rd_idx, X(rn_idx), shift_amount, false, bit64, (OpType)shift_type);
@ -381,7 +399,8 @@ void IntprCallback::LoadReg(unsigned int rd_idx, unsigned int base_idx, unsigned
bool extend, bool post, bool bit64) {
char regc = bit64? 'X': 'W';
char regdc = size >= 4 ? 'Q' : (size < 3 ? 'W' : 'X');
debug_print ("Load(%d): %c[%u] <= [%c[%u], %c[%u]]\n", size, regdc, rd_idx, regc, base_idx, regc, rm_idx);
base_idx = HandleAsSP (base_idx);
debug_print ("Load(%d): %c[%u] <= [%c[%u], %c[%u]]\n", size, regdc, rd_idx, regc, base_idx, regc, rm_idx);
uint64_t addr;
if (bit64) {
if (post)
@ -400,6 +419,7 @@ void IntprCallback::LoadReg(unsigned int rd_idx, unsigned int base_idx, unsigned
void IntprCallback::LoadRegI64(unsigned int rd_idx, unsigned int base_idx, uint64_t offset, int size,
bool extend, bool post) {
char regdc = size >= 4 ? 'Q' : (size < 3 ? 'W' : 'X');
base_idx = HandleAsSP (base_idx);
debug_print ("Load(%d): %c[%u] <= [X[%u], 0x%lx]\n", size, regdc, rd_idx, base_idx, offset);
uint64_t addr;
if (post)
@ -412,6 +432,7 @@ void IntprCallback::StoreReg(unsigned int rd_idx, unsigned int base_idx, unsigne
bool extend, bool post, bool bit64) {
char regc = bit64? 'X': 'W';
char regdc = size >= 4 ? 'Q' : (size < 3 ? 'W' : 'X');
base_idx = HandleAsSP (base_idx);
debug_print ("Store(%d): %c[%u] => [%c[%u], %c[%u]]\n", size, regdc, rd_idx, regc, base_idx, regc, rm_idx);
uint64_t addr;
if (bit64) {
@ -431,6 +452,7 @@ void IntprCallback::StoreReg(unsigned int rd_idx, unsigned int base_idx, unsigne
void IntprCallback::StoreRegI64(unsigned int rd_idx, unsigned int base_idx, uint64_t offset, int size,
bool extend, bool post) {
char regdc = size >= 4 ? 'Q' : (size < 3 ? 'W' : 'X');
base_idx = HandleAsSP (base_idx);
debug_print ("Store(%d): %c[%u] => [X[%u], 0x%lx]\n", size, regdc, rd_idx, base_idx, offset);
uint64_t addr;
if (post)
@ -515,15 +537,9 @@ void IntprCallback::CntLeadSign(unsigned int rd_idx, unsigned int rn_idx, bool b
void IntprCallback::CondCmpI64(unsigned int rn_idx, unsigned int imm, unsigned int nzcv, unsigned int cond, unsigned int op, bool bit64) {
if (CondHold (cond)) {
if (op) {
if (bit64)
ArithmeticLogic (GPR_DUMMY, X(rn_idx), imm, true, bit64, AL_TYPE_SUB);
else
ArithmeticLogic (GPR_DUMMY, W(rn_idx), imm, true, bit64, AL_TYPE_SUB);
SubI64 (GPR_ZERO, rn_idx, imm, true, bit64);
} else {
if (bit64)
ArithmeticLogic (GPR_DUMMY, X(rn_idx), imm, true, bit64, AL_TYPE_ADD);
else
ArithmeticLogic (GPR_DUMMY, W(rn_idx), imm, true, bit64, AL_TYPE_ADD);
AddI64 (GPR_ZERO, rn_idx, imm, true, bit64);
}
} else {
/* Set new nzcv */
@ -534,15 +550,9 @@ void IntprCallback::CondCmpI64(unsigned int rn_idx, unsigned int imm, unsigned i
void IntprCallback::CondCmpReg(unsigned int rn_idx, unsigned int rm_idx, unsigned int nzcv, unsigned int cond, unsigned int op, bool bit64) {
if (CondHold (cond)) {
if (op) {
if (bit64)
ArithmeticLogic (GPR_DUMMY, X(rn_idx), X(rm_idx), true, bit64, AL_TYPE_SUB);
else
ArithmeticLogic (GPR_DUMMY, W(rn_idx), W(rm_idx), true, bit64, AL_TYPE_SUB);
SubReg (GPR_ZERO, rn_idx, rm_idx, true, bit64);
} else {
if (bit64)
ArithmeticLogic (GPR_DUMMY, X(rn_idx), X(rm_idx), true, bit64, AL_TYPE_ADD);
else
ArithmeticLogic (GPR_DUMMY, W(rn_idx), W(rm_idx), true, bit64, AL_TYPE_ADD);
AddReg (GPR_ZERO, rn_idx, rm_idx, true, bit64);
}
} else {
/* Set new nzcv */
@ -589,5 +599,6 @@ void IntprCallback::SetPCReg(unsigned int rt_idx) {
/* Super Visor Call */
void IntprCallback::SVC(unsigned int svc_num) {
debug_print ("SVC: %u\n", svc_num);
//debug_print ("SVC: %u\n", svc_num);
ns_print ("SVC: %u\n", svc_num);
}

View file

@ -21,7 +21,7 @@ struct ARMv8State {
* x0 - x31 (x30 is usually "link regsiter" and x31 is "stack pointer" or "zero register" )
* NOTE: In nsemu, 'PC' register is respresented as x32 internally.
*/
reg_t gpr[34];
reg_t gpr[35];
/* v0 - v31 (128 bit vector register, sometime treated as set of smaller size regs) */
vreg_t vreg[32];
@ -32,10 +32,13 @@ struct ARMv8State {
extern ARMv8State arm_state;
#define GPR_LR 30
#define GPR_SP 31
#define GPR_ZERO 31
#define PC_IDX 32 // XXX: bit tricky
#define GPR_DUMMY 33
/* Zero register share the same encoding as SP register.
* In emulator, it's not necessary to follow it.
*/
#define GPR_ZERO 31
#define GPR_SP 32
#define PC_IDX 33 // XXX: bit tricky
#define GPR_DUMMY PC_IDX
#define GPR(r) ARMv8::arm_state.gpr[r]
#define VREG(r) ARMv8::arm_state.vreg[r]

View file

@ -13,7 +13,8 @@ enum RunLevel {
RUN_LEVEL_DEBUG,
};
static RunLevel curlevel = RUN_LEVEL_DEBUG;
//static RunLevel curlevel = RUN_LEVEL_DEBUG;
static RunLevel curlevel = RUN_LEVEL_RELEASE;
static void util_print(RunLevel level, const char *format, ...) {
if (curlevel >= level) {

View file

@ -4,13 +4,12 @@
int main() {
svcSleepThread(100000000);
result_t r;
if((r = sm_init()) != RESULT_OK) {
dbg_printf("failed to init sm: 0x%x", r);
return 1;
}
svcSleepThread(100000000);
if((r = bsd_init()) != RESULT_OK) {
dbg_printf("failed to init bsd: 0x%x, %d", r, bsd_errno);
goto err_only_sm;

View file

@ -8,4 +8,12 @@ main:
sub x3, x1, #0x431 // x3 = 0xbabe
movk x4, 0xcafe, lsl 16 // x4 = 0xcafe0000
orr x3, x3, x4 // x3 = 0xcafebabe
cmp w9, 0
subs wzr, w9, #0
subs w31, w9, #0
cmp x9, 0
subs xzr, x9, #0
subs x31, x9, #0
//subs sp, x9, #0 assembler error!
sub sp, x9, #0
b main