diff options
author | Bastian Koppelmann <kbastian@mail.uni-paderborn.de> | 2016-02-19 14:43:43 +0100 |
---|---|---|
committer | Bastian Koppelmann <kbastian@mail.uni-paderborn.de> | 2016-02-25 12:54:42 +0100 |
commit | 518d7fd2a098730669c0a0707c031dcfe52ece9a (patch) | |
tree | 08aa9ba407f551de623e81123c51c13e808e5d26 | |
parent | 5dc1fbae707513f9664aa88940a2cd52b064cda2 (diff) | |
download | qemu-518d7fd2a098730669c0a0707c031dcfe52ece9a.zip qemu-518d7fd2a098730669c0a0707c031dcfe52ece9a.tar.gz qemu-518d7fd2a098730669c0a0707c031dcfe52ece9a.tar.bz2 |
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>
-rw-r--r-- | target-tricore/cpu.h | 1 | ||||
-rw-r--r-- | target-tricore/helper.h | 3 | ||||
-rw-r--r-- | target-tricore/op_helper.c | 122 | ||||
-rw-r--r-- | target-tricore/translate.c | 23 |
4 files changed, 147 insertions, 2 deletions
diff --git a/target-tricore/cpu.h b/target-tricore/cpu.h index be6f121..5fee376 100644 --- a/target-tricore/cpu.h +++ b/target-tricore/cpu.h @@ -270,6 +270,7 @@ enum { TRAPC_ASSERT = 5, TRAPC_SYSCALL = 6, TRAPC_NMI = 7, + TRAPC_IRQ = 8 }; /* Class 0 TIN */ diff --git a/target-tricore/helper.h b/target-tricore/helper.h index cc221f1..2c8ed78 100644 --- a/target-tricore/helper.h +++ b/target-tricore/helper.h @@ -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) diff --git a/target-tricore/op_helper.c b/target-tricore/op_helper.c index 796fe67..665bb95 100644 --- a/target-tricore/op_helper.c +++ b/target-tricore/op_helper.c @@ -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; diff --git a/target-tricore/translate.c b/target-tricore/translate.c index a70fdf7..c7a3c77 100644 --- a/target-tricore/translate.c +++ b/target-tricore/translate.c @@ -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; } } |