* Print a warning if config for VM was NULL. * Add warning if register is not added to VM due to overlap. * Update PPC register profile. * Add vector and float registers. As well as some control and system registers. * Enable to write values 4bit registers. * PPC: Uplift most common instructions. * Print warning if reserved SPR instruction is encountered. * Update PC/LR addresses and add ca32 writes. * Write cache needs to get flushed so load and store tests don't share the same memory. * Add missing T/F branch mnemonics. * Add Move to/from CR/CR0-7 * Fix TA address calculation for branch instructions. * Add branch tests for branch mnemonics. * Add XNOP * NOP cache touch instructions. * Add undocumented ATTN instruction to the not_implemented group. * Add isel instruction. * Implement CRCLR, CRSET, CROR. * Add CNTLZ instructions. * Add mcrf instructions. * Add inacive test for cmpb. * Add Load bytes reverse instructions. * Add test and add address alignment to dcbz. * Add eqv test * Correct DIV and MUL operations * Add div tests. * Add tests and correct MT/MFXER * Remove register ca32, ov32 * Remove explici setting of cr register because QEMU does not do it. Otherwise we get a mismatch in the trace * Simplify carry set for add and sub. Sub instructions are exclusivly defined with addition. Hence no sub case needed. * Unify BD and fix branch instructions. Fix: Check the single bit not the cr reg * Document Conditional branches and replace NOPs with EMPTY * Add mulli instruction to double word instructions. * Fix ca set for shift instructions: * ca value had to be determined before the shift happened. The wrong ca value was calculated if the src and target reg were the same. * Replace NOP wit EMPTY. * Use MSB isntead of SLT. * Brought fixup of ADD and SUB instructions: The add and sub instructions had several issues which let to incorrect execution. * The carry was incorrectly if three add operations happened (only the last add were checked, not both). * The carry was incorrectly set if the src and target register matched. * Same applies for the CR bit. * It was too complex. Several local variables were introduced for this. * Set result in local var, since it would change if src and target reg are the same. * Remove MTMSR and MFMSR since it is too complex and untestable currently. * Use unsigned int for shift. Otherwise the 0x1c shift produces a runtime error since 0xf is int as default. * Fix mtxer: Only write flag bits. * Let NOT_IMPLEMENTED macro return NULL. * Mark st[wd]cx and l[wd]cx as not implemented. * Increase dcache_line_size to 128 bytes. * Fix cntlz for ppc32. m was set incorrectly, since it is 0 not 32 for 32bit cpus. * Fix isel: Use op.crx reg instead of imm. * Unify helper function names: Prependnig `ppc_` mark as IPI * Add more "Move to SPR" cases. * MULLI opeartes only on double word on 64bit CPUs. * Most registers are now assigned the control register type and no longer show up in the ar command. * Fix xor if dest and src registers match by saving result in local var. * Fix BE/LE issue for Load BRX instructions. * Fix shifts: Use only lower 6bits of n. * User Pure local variables for ROT macros. * Fix rldimi instructions. * n was not inverted. * more than 6 bits of n could be used * Add 32bit emulateme tests. * Add 64bit emulateme tests. * Determine lg(v) in inline function. * Calculate CR bit in C not in the VM. * Check if `~mask = 0` and skip mask calculation if yes. * Check for `sh == 0` and skip rotations where possible. * Remove `la` instruction. `la` is a mnemonic for `addi`. * Remove SPR instructions which are not supported by QEMU or not traced yet. For most set/read SPR instructions QEMU segfaults. In case of SPR 1 (xer), 8 (lr) and 9 (ctr) the assembler resolves them to their mnemonics (mtxer, mtlr etc.). This means the code here is never reached. To test the get_xer code MFXER was added again. The rz-tracetests will fail for this instructions (due to missing ca32, ov32). But this case is covert in an issue.
136 lines
3.8 KiB
C
136 lines
3.8 KiB
C
// SPDX-FileCopyrightText: 2021 Florian Märkl <info@florianmaerkl.de>
|
|
// SPDX-FileCopyrightText: 2021 heersin <teablearcher@gmail.com>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include <rz_il/rz_il_opcodes.h>
|
|
#include <rz_il/rz_il_vm.h>
|
|
|
|
static RzILEvent *il_event_new_write_from_var(RzILVM *vm, RzILVar *var, RzILVal *new_val) {
|
|
rz_return_val_if_fail(vm && var && new_val, NULL);
|
|
RzILVal *old_val = rz_il_vm_get_var_value(vm, RZ_IL_VAR_KIND_GLOBAL, var->name);
|
|
if (!old_val) {
|
|
return NULL;
|
|
}
|
|
return rz_il_event_var_write_new(var->name, old_val, new_val);
|
|
}
|
|
|
|
static void rz_il_set(RzILVM *vm, const char *var_name, bool is_local, RZ_OWN RzILVal *val) {
|
|
if (is_local) {
|
|
rz_il_vm_set_local_var(vm, var_name, val);
|
|
} else {
|
|
RzILVar *var = rz_il_vm_get_var(vm, RZ_IL_VAR_KIND_GLOBAL, var_name);
|
|
RzILEvent *evt = il_event_new_write_from_var(vm, var, val);
|
|
rz_il_vm_event_add(vm, evt);
|
|
rz_il_vm_set_global_var(vm, var_name, val);
|
|
}
|
|
}
|
|
|
|
bool rz_il_handler_empty(RzILVM *vm, RzILOpEffect *op) {
|
|
rz_return_val_if_fail(vm && op, false);
|
|
RZ_LOG_INFO("Encountered an empty instruction at %s\n", rz_bv_as_string(vm->pc))
|
|
return true;
|
|
}
|
|
|
|
bool rz_il_handler_nop(RzILVM *vm, RzILOpEffect *op) {
|
|
rz_return_val_if_fail(vm && op, false);
|
|
return true;
|
|
}
|
|
|
|
bool rz_il_handler_set(RzILVM *vm, RzILOpEffect *op) {
|
|
rz_return_val_if_fail(vm && op, false);
|
|
RzILOpArgsSet *set_op = &op->op.set;
|
|
RzILVal *val = rz_il_evaluate_val(vm, set_op->x);
|
|
if (!val) {
|
|
return false;
|
|
}
|
|
rz_il_set(vm, set_op->v, set_op->is_local, val);
|
|
return true;
|
|
}
|
|
|
|
static void perform_jump(RzILVM *vm, RZ_OWN RzBitVector *dst) {
|
|
rz_il_vm_event_add(vm, rz_il_event_pc_write_new(vm->pc, dst));
|
|
rz_bv_free(vm->pc);
|
|
vm->pc = dst;
|
|
}
|
|
|
|
bool rz_il_handler_jmp(RzILVM *vm, RzILOpEffect *op) {
|
|
rz_return_val_if_fail(vm && op, false);
|
|
RzBitVector *dst = rz_il_evaluate_bitv(vm, op->op.jmp.dst);
|
|
if (!dst) {
|
|
return false;
|
|
}
|
|
perform_jump(vm, dst);
|
|
return true;
|
|
}
|
|
|
|
bool rz_il_handler_goto(RzILVM *vm, RzILOpEffect *op) {
|
|
rz_return_val_if_fail(vm && op, false);
|
|
RzILOpArgsGoto *op_goto = &op->op.goto_;
|
|
const char *lname = op_goto->lbl;
|
|
RzILEffectLabel *label = rz_il_vm_find_label_by_name(vm, lname);
|
|
if (!label) {
|
|
return false;
|
|
}
|
|
if (label->type == EFFECT_LABEL_SYSCALL || label->type == EFFECT_LABEL_HOOK) {
|
|
RzILVmHook internal_hook = (RzILVmHook)label->hook;
|
|
internal_hook(vm, op);
|
|
} else {
|
|
perform_jump(vm, rz_bv_dup(label->addr));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool rz_il_handler_seq(RzILVM *vm, RzILOpEffect *op) {
|
|
rz_return_val_if_fail(vm && op, false);
|
|
RzILOpArgsSeq *op_seq = &op->op.seq;
|
|
return rz_il_evaluate_effect(vm, op_seq->x) && rz_il_evaluate_effect(vm, op_seq->y);
|
|
}
|
|
|
|
bool rz_il_handler_blk(RzILVM *vm, RzILOpEffect *op) {
|
|
rz_return_val_if_fail(vm && op, false);
|
|
|
|
RzILOpArgsBlk *op_blk = &op->op.blk;
|
|
if (op_blk->label) {
|
|
rz_il_vm_create_label(vm, op_blk->label, vm->pc); // create the label if `blk` is labelled
|
|
}
|
|
|
|
return rz_il_evaluate_effect(vm, op_blk->data_eff) && rz_il_evaluate_effect(vm, op_blk->ctrl_eff);
|
|
}
|
|
|
|
bool rz_il_handler_repeat(RzILVM *vm, RzILOpEffect *op) {
|
|
rz_return_val_if_fail(vm && op, NULL);
|
|
|
|
RzILOpArgsRepeat *op_repeat = &op->op.repeat;
|
|
bool res = true;
|
|
RzILBool *condition;
|
|
while ((condition = rz_il_evaluate_bool(vm, op_repeat->condition))) {
|
|
if (!condition->b) {
|
|
break;
|
|
}
|
|
res = res && rz_il_evaluate_effect(vm, op_repeat->data_eff);
|
|
rz_il_bool_free(condition);
|
|
}
|
|
rz_il_bool_free(condition);
|
|
|
|
return res;
|
|
}
|
|
|
|
bool rz_il_handler_branch(RzILVM *vm, RzILOpEffect *op) {
|
|
rz_return_val_if_fail(vm && op, false);
|
|
|
|
RzILOpArgsBranch *op_branch = &op->op.branch;
|
|
|
|
RzILBool *condition = rz_il_evaluate_bool(vm, op_branch->condition);
|
|
if (!condition) {
|
|
return false;
|
|
}
|
|
bool ret;
|
|
if (condition->b) {
|
|
ret = rz_il_evaluate_effect(vm, op_branch->true_eff);
|
|
} else {
|
|
ret = rz_il_evaluate_effect(vm, op_branch->false_eff);
|
|
}
|
|
rz_il_bool_free(condition);
|
|
|
|
return ret;
|
|
}
|