diff mbox

[v2,1/4] target-tricore: Add trap handling

Message ID 1455541846-19126-2-git-send-email-kbastian@mail.uni-paderborn.de (mailing list archive)
State New, archived
Headers show

Commit Message

Bastian Koppelmann Feb. 15, 2016, 1:10 p.m. UTC
Add the infrastructure needed to generate and handle traps.

Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
---
v1 -> v2:
    - replace helper raise_exception_error by raise_exception_sync,
      that takes care of saving the pre-interrupt state.
    - rewrite of generate_trap() in translate.c. It directly
      calls the raise_exception_sync helper instead of saving the 
      pre-interrupt state itself.

 target-tricore/cpu-qom.h   |   2 +-
 target-tricore/cpu.c       |   2 +-
 target-tricore/cpu.h       |   1 +
 target-tricore/helper.c    |  16 ++++++
 target-tricore/helper.h    |   3 ++
 target-tricore/op_helper.c | 119 +++++++++++++++++++++++++++++++++++++++++++++
 target-tricore/translate.c |  12 +++++
 7 files changed, 153 insertions(+), 2 deletions(-)

Comments

Richard Henderson Feb. 15, 2016, 8:52 p.m. UTC | #1
On 02/16/2016 12:10 AM, Bastian Koppelmann wrote:
> +
> +void tricore_cpu_do_interrupt(CPUState *cs)
> +{
> +    TriCoreCPU *cpu = TRICORE_CPU(cs);
> +    CPUTriCoreState *env = &cpu->env;
> +
> +    if (cs->exception_index <= TRAPC_NMI) {
> +        /* The trap vector table is accessed to fetch the first instruction of
> +           the trap handler. */
> +        env->PC = env->BTV | (cs->exception_index << 5);
> +    } else if (cs->exception_index == TRAPC_IRQ) {
> +        /* The interrupt vector table is accessed to fetch the first instruction
> +           of the interrupt handler. */
> +        env->PC = env->BIV | ((env->ICR & MASK_ICR_PIPN) >> 10);
> +    }
> +}

You've still got a path whereby you modify PC without saving the old one.

I don't think you want to add the do_interrupt hook at all until you're ready 
to do real async interrupts.

> +    /* PCXI.PCPN = ICR.CCPN */
> +    env->PCXI = (env->PCXI & 0xffffff) +
> +                ((env->ICR & MASK_ICR_CCPN) << 24);
> +    cs->exception_index = class;
> +    cpu_loop_exit(cs);
> +}
> +

There's no reason you can't modify PC here at the end of 
raise_exception_sync_internal.  If you omit the set of exception_index here, 
you'll simply exit the cpu loop and immediately re-enter it at the new PC, 
without having to go through the do_interrupt hook.


r~
diff mbox

Patch

diff --git a/target-tricore/cpu-qom.h b/target-tricore/cpu-qom.h
index 66c9664..0909c0c 100644
--- a/target-tricore/cpu-qom.h
+++ b/target-tricore/cpu-qom.h
@@ -65,6 +65,6 @@  static inline TriCoreCPU *tricore_env_get_cpu(CPUTriCoreState *env)
 hwaddr tricore_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
 void tricore_cpu_dump_state(CPUState *cpu, FILE *f,
                             fprintf_function cpu_fprintf, int flags);
-
+void tricore_cpu_do_interrupt(CPUState *cs);
 
 #endif /*QEMU_TRICORE_CPU_QOM_H */
diff --git a/target-tricore/cpu.c b/target-tricore/cpu.c
index f8b8518..01e39dc 100644
--- a/target-tricore/cpu.c
+++ b/target-tricore/cpu.c
@@ -166,7 +166,7 @@  static void tricore_cpu_class_init(ObjectClass *c, void *data)
     cc->reset = tricore_cpu_reset;
     cc->class_by_name = tricore_cpu_class_by_name;
     cc->has_work = tricore_cpu_has_work;
-
+    cc->do_interrupt = tricore_cpu_do_interrupt;
     cc->dump_state = tricore_cpu_dump_state;
     cc->set_pc = tricore_cpu_set_pc;
     cc->synchronize_from_tb = tricore_cpu_synchronize_from_tb;
diff --git a/target-tricore/cpu.h b/target-tricore/cpu.h
index 20a12f3..b4cc2ef 100644
--- a/target-tricore/cpu.h
+++ b/target-tricore/cpu.h
@@ -271,6 +271,7 @@  enum {
     TRAPC_ASSERT   = 5,
     TRAPC_SYSCALL  = 6,
     TRAPC_NMI      = 7,
+    TRAPC_IRQ      = 8
 };
 
 /* Class 0 TIN */
diff --git a/target-tricore/helper.c b/target-tricore/helper.c
index a8fd418..c1fc43c 100644
--- a/target-tricore/helper.c
+++ b/target-tricore/helper.c
@@ -133,3 +133,19 @@  void psw_write(CPUTriCoreState *env, uint32_t val)
     env->PSW_USB_SAV = ((val & MASK_USB_SAV) << 4);
     env->PSW = val;
 }
+
+void tricore_cpu_do_interrupt(CPUState *cs)
+{
+    TriCoreCPU *cpu = TRICORE_CPU(cs);
+    CPUTriCoreState *env = &cpu->env;
+
+    if (cs->exception_index <= TRAPC_NMI) {
+        /* The trap vector table is accessed to fetch the first instruction of
+           the trap handler. */
+        env->PC = env->BTV | (cs->exception_index << 5);
+    } else if (cs->exception_index == TRAPC_IRQ) {
+        /* The interrupt vector table is accessed to fetch the first instruction
+           of the interrupt handler. */
+        env->PC = env->BIV | ((env->ICR & MASK_ICR_PIPN) >> 10);
+    }
+}
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 3aa6326..eaaa591 100644
--- a/target-tricore/op_helper.c
+++ b/target-tricore/op_helper.c
@@ -21,6 +21,84 @@ 
 #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)
+{
+    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 fault here, the return address is the start of the
+           faulting trap handler */
+        env->gpr_a[11] = env->BTV | cs->exception_index << 5;
+    }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);
+    cs->exception_index = class;
+    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);
+}
+
 /* Addressing mode helper */
 
 static uint16_t reverse16(uint16_t val)
@@ -2625,6 +2703,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..4423130 100644
--- a/target-tricore/translate.c
+++ b/target-tricore/translate.c
@@ -3244,6 +3244,18 @@  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_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)
 {