target-tricore: Add trap handling & SOVF/OVF traps
Add the infrastructure needed to generate and handle traps and implement the generation of SOVF and OVF traps. Reviewed-by: Richard Henderson <rth@twiddle.net> Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de> Message-Id: <1455889426-1923-2-git-send-email-kbastian@mail.uni-paderborn.de>
This commit is contained in:
parent
5dc1fbae70
commit
518d7fd2a0
@ -270,6 +270,7 @@ enum {
|
||||
TRAPC_ASSERT = 5,
|
||||
TRAPC_SYSCALL = 6,
|
||||
TRAPC_NMI = 7,
|
||||
TRAPC_IRQ = 8
|
||||
};
|
||||
|
||||
/* Class 0 TIN */
|
||||
|
@ -132,6 +132,7 @@ DEF_HELPER_2(lducx, void, env, i32)
|
||||
DEF_HELPER_2(stlcx, void, env, i32)
|
||||
DEF_HELPER_2(stucx, void, env, i32)
|
||||
DEF_HELPER_1(svlcx, void, env)
|
||||
DEF_HELPER_1(svucx, void, env)
|
||||
DEF_HELPER_1(rslcx, void, env)
|
||||
/* Address mode helper */
|
||||
DEF_HELPER_1(br_update, i32, i32)
|
||||
@ -139,3 +140,5 @@ DEF_HELPER_2(circ_update, i32, i32, i32)
|
||||
/* PSW cache helper */
|
||||
DEF_HELPER_2(psw_write, void, env, i32)
|
||||
DEF_HELPER_1(psw_read, i32, env)
|
||||
/* Exceptions */
|
||||
DEF_HELPER_3(raise_exception_sync, noreturn, env, i32, i32)
|
||||
|
@ -21,6 +21,87 @@
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include <zlib.h> /* for crc32 */
|
||||
|
||||
|
||||
/* Exception helpers */
|
||||
|
||||
static void QEMU_NORETURN
|
||||
raise_exception_sync_internal(CPUTriCoreState *env, uint32_t class, int tin,
|
||||
uintptr_t pc, uint32_t fcd_pc)
|
||||
{
|
||||
CPUState *cs = CPU(tricore_env_get_cpu(env));
|
||||
/* in case we come from a helper-call we need to restore the PC */
|
||||
if (pc) {
|
||||
cpu_restore_state(cs, pc);
|
||||
}
|
||||
|
||||
/* Tin is loaded into d[15] */
|
||||
env->gpr_d[15] = tin;
|
||||
|
||||
if (class == TRAPC_CTX_MNG && tin == TIN3_FCU) {
|
||||
/* upper context cannot be saved, if the context list is empty */
|
||||
} else {
|
||||
helper_svucx(env);
|
||||
}
|
||||
|
||||
/* The return address in a[11] is updated */
|
||||
if (class == TRAPC_CTX_MNG && tin == TIN3_FCD) {
|
||||
env->SYSCON |= MASK_SYSCON_FCD_SF;
|
||||
/* when we run out of CSAs after saving a context a FCD trap is taken
|
||||
and the return address is the start of the trap handler which used
|
||||
the last CSA */
|
||||
env->gpr_a[11] = fcd_pc;
|
||||
} else if (class == TRAPC_SYSCALL) {
|
||||
env->gpr_a[11] = env->PC + 4;
|
||||
} else {
|
||||
env->gpr_a[11] = env->PC;
|
||||
}
|
||||
/* The stack pointer in A[10] is set to the Interrupt Stack Pointer (ISP)
|
||||
when the processor was not previously using the interrupt stack
|
||||
(in case of PSW.IS = 0). The stack pointer bit is set for using the
|
||||
interrupt stack: PSW.IS = 1. */
|
||||
if ((env->PSW & MASK_PSW_IS) == 0) {
|
||||
env->gpr_a[10] = env->ISP;
|
||||
}
|
||||
env->PSW |= MASK_PSW_IS;
|
||||
/* The I/O mode is set to Supervisor mode, which means all permissions
|
||||
are enabled: PSW.IO = 10 B .*/
|
||||
env->PSW |= (2 << 10);
|
||||
|
||||
/*The current Protection Register Set is set to 0: PSW.PRS = 00 B .*/
|
||||
env->PSW &= ~MASK_PSW_PRS;
|
||||
|
||||
/* The Call Depth Counter (CDC) is cleared, and the call depth limit is
|
||||
set for 64: PSW.CDC = 0000000 B .*/
|
||||
env->PSW &= ~MASK_PSW_CDC;
|
||||
|
||||
/* Call Depth Counter is enabled, PSW.CDE = 1. */
|
||||
env->PSW |= MASK_PSW_CDE;
|
||||
|
||||
/* Write permission to global registers A[0], A[1], A[8], A[9] is
|
||||
disabled: PSW.GW = 0. */
|
||||
env->PSW &= ~MASK_PSW_GW;
|
||||
|
||||
/*The interrupt system is globally disabled: ICR.IE = 0. The ‘old’
|
||||
ICR.IE and ICR.CCPN are saved */
|
||||
|
||||
/* PCXI.PIE = ICR.IE */
|
||||
env->PCXI = ((env->PCXI & ~MASK_PCXI_PIE) +
|
||||
((env->ICR & MASK_ICR_IE) << 15));
|
||||
/* PCXI.PCPN = ICR.CCPN */
|
||||
env->PCXI = (env->PCXI & 0xffffff) +
|
||||
((env->ICR & MASK_ICR_CCPN) << 24);
|
||||
/* Update PC using the trap vector table */
|
||||
env->PC = env->BTV | (class << 5);
|
||||
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
||||
void helper_raise_exception_sync(CPUTriCoreState *env, uint32_t class,
|
||||
uint32_t tin)
|
||||
{
|
||||
raise_exception_sync_internal(env, class, tin, 0, 0);
|
||||
}
|
||||
|
||||
/* Addressing mode helper */
|
||||
|
||||
static uint16_t reverse16(uint16_t val)
|
||||
@ -2625,6 +2706,47 @@ void helper_svlcx(CPUTriCoreState *env)
|
||||
}
|
||||
}
|
||||
|
||||
void helper_svucx(CPUTriCoreState *env)
|
||||
{
|
||||
target_ulong tmp_FCX;
|
||||
target_ulong ea;
|
||||
target_ulong new_FCX;
|
||||
|
||||
if (env->FCX == 0) {
|
||||
/* FCU trap */
|
||||
}
|
||||
/* tmp_FCX = FCX; */
|
||||
tmp_FCX = env->FCX;
|
||||
/* EA = {FCX.FCXS, 6'b0, FCX.FCXO, 6'b0}; */
|
||||
ea = ((env->FCX & MASK_FCX_FCXS) << 12) +
|
||||
((env->FCX & MASK_FCX_FCXO) << 6);
|
||||
/* new_FCX = M(EA, word); */
|
||||
new_FCX = cpu_ldl_data(env, ea);
|
||||
/* M(EA, 16 * word) = {PCXI, PSW, A[10], A[11], D[8], D[9], D[10], D[11],
|
||||
A[12], A[13], A[14], A[15], D[12], D[13], D[14],
|
||||
D[15]}; */
|
||||
save_context_upper(env, ea);
|
||||
|
||||
/* PCXI.PCPN = ICR.CCPN; */
|
||||
env->PCXI = (env->PCXI & 0xffffff) +
|
||||
((env->ICR & MASK_ICR_CCPN) << 24);
|
||||
/* PCXI.PIE = ICR.IE; */
|
||||
env->PCXI = ((env->PCXI & ~MASK_PCXI_PIE) +
|
||||
((env->ICR & MASK_ICR_IE) << 15));
|
||||
/* PCXI.UL = 1; */
|
||||
env->PCXI |= MASK_PCXI_UL;
|
||||
|
||||
/* PCXI[19: 0] = FCX[19: 0]; */
|
||||
env->PCXI = (env->PCXI & 0xfff00000) + (env->FCX & 0xfffff);
|
||||
/* FCX[19: 0] = new_FCX[19: 0]; */
|
||||
env->FCX = (env->FCX & 0xfff00000) + (new_FCX & 0xfffff);
|
||||
|
||||
/* if (tmp_FCX == LCX) trap(FCD);*/
|
||||
if (tmp_FCX == env->LCX) {
|
||||
/* FCD trap */
|
||||
}
|
||||
}
|
||||
|
||||
void helper_rslcx(CPUTriCoreState *env)
|
||||
{
|
||||
target_ulong ea;
|
||||
|
@ -3244,6 +3244,19 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
|
||||
}
|
||||
}
|
||||
|
||||
static void generate_trap(DisasContext *ctx, int class, int tin)
|
||||
{
|
||||
TCGv_i32 classtemp = tcg_const_i32(class);
|
||||
TCGv_i32 tintemp = tcg_const_i32(tin);
|
||||
|
||||
gen_save_pc(ctx->pc);
|
||||
gen_helper_raise_exception_sync(cpu_env, classtemp, tintemp);
|
||||
ctx->bstate = BS_EXCP;
|
||||
|
||||
tcg_temp_free(classtemp);
|
||||
tcg_temp_free(tintemp);
|
||||
}
|
||||
|
||||
static inline void gen_branch_cond(DisasContext *ctx, TCGCond cond, TCGv r1,
|
||||
TCGv r2, int16_t address)
|
||||
{
|
||||
@ -7910,10 +7923,16 @@ static void decode_sys_interrupts(CPUTriCoreState *env, DisasContext *ctx)
|
||||
} /* else raise illegal opcode trap */
|
||||
break;
|
||||
case OPC2_32_SYS_TRAPSV:
|
||||
/* TODO: raise sticky overflow trap */
|
||||
l1 = gen_new_label();
|
||||
tcg_gen_brcondi_tl(TCG_COND_GE, cpu_PSW_SV, 0, l1);
|
||||
generate_trap(ctx, TRAPC_ASSERT, TIN5_SOVF);
|
||||
gen_set_label(l1);
|
||||
break;
|
||||
case OPC2_32_SYS_TRAPV:
|
||||
/* TODO: raise overflow trap */
|
||||
l1 = gen_new_label();
|
||||
tcg_gen_brcondi_tl(TCG_COND_GE, cpu_PSW_V, 0, l1);
|
||||
generate_trap(ctx, TRAPC_ASSERT, TIN5_OVF);
|
||||
gen_set_label(l1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user