target/mips: Extract break code into env->error_code

Simplify cpu_loop by doing all of the decode in translate.

This fixes a bug in that cpu_loop was not handling the
different layout of the R6 version of break16.  This fixes
a bug in that cpu_loop extracted the wrong bits for the
mips16e break16 instruction.

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20220107213243.212806-17-richard.henderson@linaro.org>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
This commit is contained in:
Richard Henderson 2022-01-07 13:32:35 -08:00 committed by Laurent Vivier
parent 73c0aa6a85
commit 6f3533dd1b
5 changed files with 25 additions and 69 deletions

View file

@ -65,6 +65,7 @@ void cpu_loop(CPUMIPSState *env)
{
CPUState *cs = env_cpu(env);
int trapnr, si_code;
unsigned int code;
abi_long ret;
# ifdef TARGET_ABI_MIPSO32
unsigned int syscall_num;
@ -185,71 +186,15 @@ done_syscall:
* handling code in arch/mips/kernel/traps.c.
*/
case EXCP_BREAK:
{
abi_ulong trap_instr;
unsigned int code;
/*
* FIXME: It would be better to decode the trap number
* during translate, and store it in error_code while
* raising the exception. We should not be re-reading
* the opcode here.
*/
if (env->hflags & MIPS_HFLAG_M16) {
if (env->insn_flags & ASE_MICROMIPS) {
/* microMIPS mode */
ret = get_user_u16(trap_instr, env->active_tc.PC);
if (ret != 0) {
goto error;
}
if ((trap_instr >> 10) == 0x11) {
/* 16-bit instruction */
code = trap_instr & 0xf;
} else {
/* 32-bit instruction */
abi_ulong instr_lo;
ret = get_user_u16(instr_lo,
env->active_tc.PC + 2);
if (ret != 0) {
goto error;
}
trap_instr = (trap_instr << 16) | instr_lo;
code = ((trap_instr >> 6) & ((1 << 20) - 1));
/* Unfortunately, microMIPS also suffers from
the old assembler bug... */
if (code >= (1 << 10)) {
code >>= 10;
}
}
} else {
/* MIPS16e mode */
ret = get_user_u16(trap_instr, env->active_tc.PC);
if (ret != 0) {
goto error;
}
code = (trap_instr >> 6) & 0x3f;
}
} else {
ret = get_user_u32(trap_instr, env->active_tc.PC);
if (ret != 0) {
goto error;
}
/* As described in the original Linux kernel code, the
* below checks on 'code' are to work around an old
* assembly bug.
*/
code = ((trap_instr >> 6) & ((1 << 20) - 1));
if (code >= (1 << 10)) {
code >>= 10;
}
}
do_tr_or_bp(env, code, false);
/*
* As described in the original Linux kernel code, the below
* checks on 'code' are to work around an old assembly bug.
*/
code = env->error_code;
if (code >= (1 << 10)) {
code >>= 10;
}
do_tr_or_bp(env, code, false);
break;
case EXCP_TRAP:
{