@@ -42,6 +42,12 @@ void cpu_loop(CPUNios2State *env)
force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc);
break;
+ case EXCP_UNALIGN:
+ case EXCP_UNALIGND:
+ force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN,
+ env->ctrl[CR_BADADDR]);
+ break;
+
case EXCP_TRAP:
/*
* TODO: This advance should be done in the translator, as
@@ -64,6 +64,13 @@ uint32_t helper_divu(CPUNios2State *env, uint32_t num, uint32_t den)
void helper_eret(CPUNios2State *env, uint32_t new_status, uint32_t new_pc)
{
Nios2CPU *cpu = env_archcpu(env);
+ CPUState *cs = env_cpu(env);
+
+ if (unlikely(new_pc & 3)) {
+ env->ctrl[CR_BADADDR] = new_pc;
+ cs->exception_index = EXCP_UNALIGND;
+ cpu_loop_exit_restore(cs, GETPC());
+ }
/*
* Both estatus and bstatus have no constraints on write;
@@ -74,6 +81,6 @@ void helper_eret(CPUNios2State *env, uint32_t new_status, uint32_t new_pc)
env->ctrl[CR_STATUS] = new_status;
env->pc = new_pc;
- cpu_loop_exit(env_cpu(env));
+ cpu_loop_exit(cs);
}
#endif /* !CONFIG_USER_ONLY */
@@ -191,11 +191,24 @@ static void gen_goto_tb(DisasContext *dc, int n, uint32_t dest)
static void gen_jumpr(DisasContext *dc, int regno, bool is_call)
{
- tcg_gen_mov_tl(cpu_pc, load_gpr(dc, regno));
+ TCGLabel *l = gen_new_label();
+ TCGv test = tcg_temp_new();
+ TCGv dest = load_gpr(dc, regno);
+
+ tcg_gen_andi_tl(test, dest, 3);
+ tcg_gen_brcondi_tl(TCG_COND_NE, test, 0, l);
+ tcg_temp_free(test);
+
+ tcg_gen_mov_tl(cpu_pc, dest);
if (is_call) {
tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next);
}
tcg_gen_lookup_and_goto_ptr();
+
+ gen_set_label(l);
+ tcg_gen_st_tl(dest, cpu_env, offsetof(CPUNios2State, ctrl[CR_BADADDR]));
+ t_gen_helper_raise_exception(dc, EXCP_UNALIGND);
+
dc->base.is_jmp = DISAS_NORETURN;
}