]> Git Repo - qemu.git/blobdiff - target/m68k/op_helper.c
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-3.1-20180907' into staging
[qemu.git] / target / m68k / op_helper.c
index 7e97d03f82ab23551fc8e58184437fe06ca96313..8d09ed91c4922137d15c51fa42330d5e81073a4d 100644 (file)
@@ -39,18 +39,15 @@ static inline void do_interrupt_m68k_hardirq(CPUM68KState *env)
 /* Try to fill the TLB and return an exception if error. If retaddr is
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
-void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type,
-              int mmu_idx, uintptr_t retaddr)
+void tlb_fill(CPUState *cs, target_ulong addr, int size,
+              MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
 {
     int ret;
 
-    ret = m68k_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx);
+    ret = m68k_cpu_handle_mmu_fault(cs, addr, size, access_type, mmu_idx);
     if (unlikely(ret)) {
-        if (retaddr) {
-            /* now we have a real cpu fault */
-            cpu_restore_state(cs, retaddr);
-        }
-        cpu_loop_exit(cs);
+        /* now we have a real cpu fault */
+        cpu_loop_exit_restore(cs, retaddr);
     }
 }
 
@@ -290,22 +287,25 @@ static inline void do_stack_frame(CPUM68KState *env, uint32_t *sp,
                                   uint16_t format, uint16_t sr,
                                   uint32_t addr, uint32_t retaddr)
 {
-    CPUState *cs = CPU(m68k_env_get_cpu(env));
-    switch (format) {
-    case 4:
-        *sp -= 4;
-        cpu_stl_kernel(env, *sp, env->pc);
-        *sp -= 4;
-        cpu_stl_kernel(env, *sp, addr);
-        break;
-    case 3:
-    case 2:
-        *sp -= 4;
-        cpu_stl_kernel(env, *sp, addr);
-        break;
+    if (m68k_feature(env, M68K_FEATURE_QUAD_MULDIV)) {
+        /*  all except 68000 */
+        CPUState *cs = CPU(m68k_env_get_cpu(env));
+        switch (format) {
+        case 4:
+            *sp -= 4;
+            cpu_stl_kernel(env, *sp, env->pc);
+            *sp -= 4;
+            cpu_stl_kernel(env, *sp, addr);
+            break;
+        case 3:
+        case 2:
+            *sp -= 4;
+            cpu_stl_kernel(env, *sp, addr);
+            break;
+        }
+        *sp -= 2;
+        cpu_stw_kernel(env, *sp, (format << 12) + (cs->exception_index << 2));
     }
-    *sp -= 2;
-    cpu_stw_kernel(env, *sp, (format << 12) + (cs->exception_index << 2));
     *sp -= 4;
     cpu_stl_kernel(env, *sp, retaddr);
     *sp -= 2;
@@ -363,7 +363,49 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw)
     sp = env->aregs[7];
 
     sp &= ~1;
-    if (cs->exception_index == EXCP_ADDRESS) {
+    if (cs->exception_index == EXCP_ACCESS) {
+        if (env->mmu.fault) {
+            cpu_abort(cs, "DOUBLE MMU FAULT\n");
+        }
+        env->mmu.fault = true;
+        sp -= 4;
+        cpu_stl_kernel(env, sp, 0); /* push data 3 */
+        sp -= 4;
+        cpu_stl_kernel(env, sp, 0); /* push data 2 */
+        sp -= 4;
+        cpu_stl_kernel(env, sp, 0); /* push data 1 */
+        sp -= 4;
+        cpu_stl_kernel(env, sp, 0); /* write back 1 / push data 0 */
+        sp -= 4;
+        cpu_stl_kernel(env, sp, 0); /* write back 1 address */
+        sp -= 4;
+        cpu_stl_kernel(env, sp, 0); /* write back 2 data */
+        sp -= 4;
+        cpu_stl_kernel(env, sp, 0); /* write back 2 address */
+        sp -= 4;
+        cpu_stl_kernel(env, sp, 0); /* write back 3 data */
+        sp -= 4;
+        cpu_stl_kernel(env, sp, env->mmu.ar); /* write back 3 address */
+        sp -= 4;
+        cpu_stl_kernel(env, sp, env->mmu.ar); /* fault address */
+        sp -= 2;
+        cpu_stw_kernel(env, sp, 0); /* write back 1 status */
+        sp -= 2;
+        cpu_stw_kernel(env, sp, 0); /* write back 2 status */
+        sp -= 2;
+        cpu_stw_kernel(env, sp, 0); /* write back 3 status */
+        sp -= 2;
+        cpu_stw_kernel(env, sp, env->mmu.ssw); /* special status word */
+        sp -= 4;
+        cpu_stl_kernel(env, sp, env->mmu.ar); /* effective address */
+        do_stack_frame(env, &sp, 7, oldsr, 0, retaddr);
+        env->mmu.fault = false;
+        if (qemu_loglevel_mask(CPU_LOG_INT)) {
+            qemu_log("            "
+                     "ssw:  %08x ea:   %08x sfc:  %d    dfc: %d\n",
+                     env->mmu.ssw, env->mmu.ar, env->sfc, env->dfc);
+        }
+    } else if (cs->exception_index == EXCP_ADDRESS) {
         do_stack_frame(env, &sp, 2, oldsr, 0, retaddr);
     } else if (cs->exception_index == EXCP_ILLEGAL ||
                cs->exception_index == EXCP_DIV0 ||
@@ -411,6 +453,57 @@ static inline void do_interrupt_m68k_hardirq(CPUM68KState *env)
 {
     do_interrupt_all(env, 1);
 }
+
+void m68k_cpu_unassigned_access(CPUState *cs, hwaddr addr, bool is_write,
+                                bool is_exec, int is_asi, unsigned size)
+{
+    M68kCPU *cpu = M68K_CPU(cs);
+    CPUM68KState *env = &cpu->env;
+#ifdef DEBUG_UNASSIGNED
+    qemu_log_mask(CPU_LOG_INT, "Unassigned " TARGET_FMT_plx " wr=%d exe=%d\n",
+             addr, is_write, is_exec);
+#endif
+    if (env == NULL) {
+        /* when called from gdb, env is NULL */
+        return;
+    }
+
+    if (m68k_feature(env, M68K_FEATURE_M68040)) {
+        env->mmu.mmusr = 0;
+        env->mmu.ssw |= M68K_ATC_040;
+        /* FIXME: manage MMU table access error */
+        env->mmu.ssw &= ~M68K_TM_040;
+        if (env->sr & SR_S) { /* SUPERVISOR */
+            env->mmu.ssw |= M68K_TM_040_SUPER;
+        }
+        if (is_exec) { /* instruction or data */
+            env->mmu.ssw |= M68K_TM_040_CODE;
+        } else {
+            env->mmu.ssw |= M68K_TM_040_DATA;
+        }
+        env->mmu.ssw &= ~M68K_BA_SIZE_MASK;
+        switch (size) {
+        case 1:
+            env->mmu.ssw |= M68K_BA_SIZE_BYTE;
+            break;
+        case 2:
+            env->mmu.ssw |= M68K_BA_SIZE_WORD;
+            break;
+        case 4:
+            env->mmu.ssw |= M68K_BA_SIZE_LONG;
+            break;
+        }
+
+        if (!is_write) {
+            env->mmu.ssw |= M68K_RW_040;
+        }
+
+        env->mmu.ar = addr;
+
+        cs->exception_index = EXCP_ACCESS;
+        cpu_loop_exit(cs);
+    }
+}
 #endif
 
 bool m68k_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
@@ -966,7 +1059,7 @@ void HELPER(chk)(CPUM68KState *env, int32_t val, int32_t ub)
         CPUState *cs = CPU(m68k_env_get_cpu(env));
 
         /* Recover PC and CC_OP for the beginning of the insn.  */
-        cpu_restore_state(cs, GETPC());
+        cpu_restore_state(cs, GETPC(), true);
 
         /* flags have been modified by gen_flush_flags() */
         env->cc_op = CC_OP_FLAGS;
@@ -997,7 +1090,7 @@ void HELPER(chk2)(CPUM68KState *env, int32_t val, int32_t lb, int32_t ub)
         CPUState *cs = CPU(m68k_env_get_cpu(env));
 
         /* Recover PC and CC_OP for the beginning of the insn.  */
-        cpu_restore_state(cs, GETPC());
+        cpu_restore_state(cs, GETPC(), true);
 
         /* flags have been modified by gen_flush_flags() */
         env->cc_op = CC_OP_FLAGS;
This page took 0.026866 seconds and 4 git commands to generate.