aboutsummaryrefslogtreecommitdiff
path: root/target/m68k/op_helper.c
diff options
context:
space:
mode:
authorLaurent Vivier <laurent@vivier.eu>2018-01-18 20:38:41 +0100
committerLaurent Vivier <laurent@vivier.eu>2018-01-25 16:02:24 +0100
commit88b2fef6c3c3b45ac0dc2196ace7248a09c8e41d (patch)
tree3b1acfcbd019e96dd15217f52066fcd314797e02 /target/m68k/op_helper.c
parent98670d47cd8d63a529ff230fd39ddaa186156f8c (diff)
downloadqemu-88b2fef6c3c3b45ac0dc2196ace7248a09c8e41d.zip
qemu-88b2fef6c3c3b45ac0dc2196ace7248a09c8e41d.tar.gz
qemu-88b2fef6c3c3b45ac0dc2196ace7248a09c8e41d.tar.bz2
target/m68k: add MC68040 MMU
Only add MC68040 MMU page table processing and related registers (Special Status Word, Translation Control Register, User Root Pointer and Supervisor Root Pointer). Transparent Translation Registers, DFC/SFC and pflush/ptest will be added later. Signed-off-by: Laurent Vivier <laurent@vivier.eu> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20180118193846.24953-3-laurent@vivier.eu>
Diffstat (limited to 'target/m68k/op_helper.c')
-rw-r--r--target/m68k/op_helper.c94
1 files changed, 93 insertions, 1 deletions
diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c
index 67697d4..f023901 100644
--- a/target/m68k/op_helper.c
+++ b/target/m68k/op_helper.c
@@ -360,7 +360,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\n",
+ env->mmu.ssw, env->mmu.ar);
+ }
+ } 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 ||
@@ -408,6 +450,56 @@ 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.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)