aboutsummaryrefslogtreecommitdiff
path: root/target/xtensa/cpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/xtensa/cpu.c')
-rw-r--r--target/xtensa/cpu.c113
1 files changed, 99 insertions, 14 deletions
diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c
index a08c7a0..ea9b6df 100644
--- a/target/xtensa/cpu.c
+++ b/target/xtensa/cpu.c
@@ -35,8 +35,9 @@
#include "qemu/module.h"
#include "migration/vmstate.h"
#include "hw/qdev-clock.h"
+#include "accel/tcg/cpu-ops.h"
#ifndef CONFIG_USER_ONLY
-#include "exec/memory.h"
+#include "system/memory.h"
#endif
@@ -54,6 +55,80 @@ static vaddr xtensa_cpu_get_pc(CPUState *cs)
return cpu->env.pc;
}
+static TCGTBCPUState xtensa_get_tb_cpu_state(CPUState *cs)
+{
+ CPUXtensaState *env = cpu_env(cs);
+ uint32_t flags = 0;
+ target_ulong cs_base = 0;
+
+ flags |= xtensa_get_ring(env);
+ if (env->sregs[PS] & PS_EXCM) {
+ flags |= XTENSA_TBFLAG_EXCM;
+ } else if (xtensa_option_enabled(env->config, XTENSA_OPTION_LOOP)) {
+ target_ulong lend_dist =
+ env->sregs[LEND] - (env->pc & -(1u << TARGET_PAGE_BITS));
+
+ /*
+ * 0 in the csbase_lend field means that there may not be a loopback
+ * for any instruction that starts inside this page. Any other value
+ * means that an instruction that ends at this offset from the page
+ * start may loop back and will need loopback code to be generated.
+ *
+ * lend_dist is 0 when LEND points to the start of the page, but
+ * no instruction that starts inside this page may end at offset 0,
+ * so it's still correct.
+ *
+ * When an instruction ends at a page boundary it may only start in
+ * the previous page. lend_dist will be encoded as TARGET_PAGE_SIZE
+ * for the TB that contains this instruction.
+ */
+ if (lend_dist < (1u << TARGET_PAGE_BITS) + env->config->max_insn_size) {
+ target_ulong lbeg_off = env->sregs[LEND] - env->sregs[LBEG];
+
+ cs_base = lend_dist;
+ if (lbeg_off < 256) {
+ cs_base |= lbeg_off << XTENSA_CSBASE_LBEG_OFF_SHIFT;
+ }
+ }
+ }
+ if (xtensa_option_enabled(env->config, XTENSA_OPTION_EXTENDED_L32R) &&
+ (env->sregs[LITBASE] & 1)) {
+ flags |= XTENSA_TBFLAG_LITBASE;
+ }
+ if (xtensa_option_enabled(env->config, XTENSA_OPTION_DEBUG)) {
+ if (xtensa_get_cintlevel(env) < env->config->debug_level) {
+ flags |= XTENSA_TBFLAG_DEBUG;
+ }
+ if (xtensa_get_cintlevel(env) < env->sregs[ICOUNTLEVEL]) {
+ flags |= XTENSA_TBFLAG_ICOUNT;
+ }
+ }
+ if (xtensa_option_enabled(env->config, XTENSA_OPTION_COPROCESSOR)) {
+ flags |= env->sregs[CPENABLE] << XTENSA_TBFLAG_CPENABLE_SHIFT;
+ }
+ if (xtensa_option_enabled(env->config, XTENSA_OPTION_WINDOWED_REGISTER) &&
+ (env->sregs[PS] & (PS_WOE | PS_EXCM)) == PS_WOE) {
+ uint32_t windowstart = xtensa_replicate_windowstart(env) >>
+ (env->sregs[WINDOW_BASE] + 1);
+ uint32_t w = ctz32(windowstart | 0x8);
+
+ flags |= (w << XTENSA_TBFLAG_WINDOW_SHIFT) | XTENSA_TBFLAG_CWOE;
+ flags |= extract32(env->sregs[PS], PS_CALLINC_SHIFT,
+ PS_CALLINC_LEN) << XTENSA_TBFLAG_CALLINC_SHIFT;
+ } else {
+ flags |= 3 << XTENSA_TBFLAG_WINDOW_SHIFT;
+ }
+ if (env->yield_needed) {
+ flags |= XTENSA_TBFLAG_YIELD;
+ }
+
+ return (TCGTBCPUState){
+ .pc = env->pc,
+ .flags = flags,
+ .cs_base = cs_base,
+ };
+}
+
static void xtensa_restore_state_to_opc(CPUState *cs,
const TranslationBlock *tb,
const uint64_t *data)
@@ -63,16 +138,14 @@ static void xtensa_restore_state_to_opc(CPUState *cs,
cpu->env.pc = data[0];
}
+#ifndef CONFIG_USER_ONLY
static bool xtensa_cpu_has_work(CPUState *cs)
{
-#ifndef CONFIG_USER_ONLY
- XtensaCPU *cpu = XTENSA_CPU(cs);
+ CPUXtensaState *env = cpu_env(cs);
- return !cpu->env.runstall && cpu->env.pending_irq_level;
-#else
- return true;
-#endif
+ return !env->runstall && env->pending_irq_level;
}
+#endif /* !CONFIG_USER_ONLY */
static int xtensa_cpu_mmu_index(CPUState *cs, bool ifetch)
{
@@ -133,8 +206,12 @@ static void xtensa_cpu_reset_hold(Object *obj, ResetType type)
reset_mmu(env);
cs->halted = env->runstall;
#endif
+ /* For inf * 0 + NaN, return the input NaN */
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
set_no_signaling_nans(!dfpu, &env->fp_status);
- set_use_first_nan(!dfpu, &env->fp_status);
+ /* Default NaN value: sign bit clear, set frac msb */
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
+ xtensa_use_first_nan(env, !dfpu);
}
static ObjectClass *xtensa_cpu_class_by_name(const char *cpu_model)
@@ -155,6 +232,8 @@ static void xtensa_cpu_disas_set_info(CPUState *cs, disassemble_info *info)
info->private_data = cpu->env.config->isa;
info->print_insn = print_insn_xtensa;
+ info->endian = TARGET_BIG_ENDIAN ? BFD_ENDIAN_BIG
+ : BFD_ENDIAN_LITTLE;
}
static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp)
@@ -204,7 +283,7 @@ XtensaCPU *xtensa_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk)
{
DeviceState *cpu;
- cpu = DEVICE(object_new(cpu_type));
+ cpu = qdev_new(cpu_type);
qdev_connect_clock_in(cpu, "clk-in", cpu_refclk);
qdev_realize(cpu, NULL, &error_abort);
@@ -220,21 +299,29 @@ static const VMStateDescription vmstate_xtensa_cpu = {
#include "hw/core/sysemu-cpu-ops.h"
static const struct SysemuCPUOps xtensa_sysemu_ops = {
+ .has_work = xtensa_cpu_has_work,
.get_phys_page_debug = xtensa_cpu_get_phys_page_debug,
};
#endif
-#include "hw/core/tcg-cpu-ops.h"
-
static const TCGCPUOps xtensa_tcg_ops = {
+ /* Xtensa processors have a weak memory model */
+ .guest_default_memory_order = 0,
+ .mttcg_supported = true,
+
.initialize = xtensa_translate_init,
+ .translate_code = xtensa_translate_code,
.debug_excp_handler = xtensa_breakpoint_handler,
+ .get_tb_cpu_state = xtensa_get_tb_cpu_state,
.restore_state_to_opc = xtensa_restore_state_to_opc,
+ .mmu_index = xtensa_cpu_mmu_index,
#ifndef CONFIG_USER_ONLY
.tlb_fill = xtensa_cpu_tlb_fill,
+ .pointer_wrap = cpu_pointer_wrap_uint32,
.cpu_exec_interrupt = xtensa_cpu_exec_interrupt,
.cpu_exec_halt = xtensa_cpu_has_work,
+ .cpu_exec_reset = cpu_reset,
.do_interrupt = xtensa_cpu_do_interrupt,
.do_transaction_failed = xtensa_cpu_do_transaction_failed,
.do_unaligned_access = xtensa_cpu_do_unaligned_access,
@@ -242,7 +329,7 @@ static const TCGCPUOps xtensa_tcg_ops = {
#endif /* !CONFIG_USER_ONLY */
};
-static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
+static void xtensa_cpu_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
CPUClass *cc = CPU_CLASS(oc);
@@ -256,8 +343,6 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
&xcc->parent_phases);
cc->class_by_name = xtensa_cpu_class_by_name;
- cc->has_work = xtensa_cpu_has_work;
- cc->mmu_index = xtensa_cpu_mmu_index;
cc->dump_state = xtensa_cpu_dump_state;
cc->set_pc = xtensa_cpu_set_pc;
cc->get_pc = xtensa_cpu_get_pc;