summary refs log tree commit diff stats
path: root/target-m68k
diff options
context:
space:
mode:
Diffstat (limited to 'target-m68k')
-rw-r--r--target-m68k/cpu.h13
-rw-r--r--target-m68k/helper.c26
-rw-r--r--target-m68k/op.c7
-rw-r--r--target-m68k/op_helper.c18
-rw-r--r--target-m68k/translate.c9
5 files changed, 60 insertions, 13 deletions
diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index acbb51690d..6f29d5e5c4 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -59,6 +59,10 @@ typedef struct CPUM68KState {
     uint32_t pc;
     uint32_t sr;
 
+    /* SSP and USP.  The current_sp is stored in aregs[7], the other here.  */
+    int current_sp;
+    uint32_t sp[2];
+
     /* Condition flags.  */
     uint32_t cc_op;
     uint32_t cc_dest;
@@ -92,6 +96,7 @@ typedef struct CPUM68KState {
     uint32_t vbr;
     uint32_t mbar;
     uint32_t rambar0;
+    uint32_t cacr;
 
     uint32_t features;
 
@@ -151,6 +156,12 @@ enum {
 #define SR_S  0x2000
 #define SR_T  0x8000
 
+#define M68K_SSP    0
+#define M68K_USP    1
+
+/* CACR fields are implementation defined, but some bits are common.  */
+#define M68K_CACR_EUSP  0x10
+
 #define MACSR_PAV0  0x100
 #define MACSR_OMC   0x080
 #define MACSR_SU    0x040
@@ -167,6 +178,7 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name);
 
 void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector);
 void m68k_set_macsr(CPUM68KState *env, uint32_t val);
+void m68k_switch_sp(CPUM68KState *env);
 
 #define M68K_FPCR_PREC (1 << 6)
 
@@ -179,6 +191,7 @@ enum m68k_features {
     M68K_FEATURE_CF_FPU,
     M68K_FEATURE_CF_MAC,
     M68K_FEATURE_CF_EMAC,
+    M68K_FEATURE_USP,
     M68K_FEATURE_EXT_FULL, /* 68020+ full extension word.  */
     M68K_FEATURE_WORD_INDEX /* word sized address index registers.  */
 };
diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index bdbc1de396..bb213a7603 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -28,6 +28,7 @@
 
 enum m68k_cpuid {
     M68K_CPUID_M5206,
+    M68K_CPUID_M5208,
     M68K_CPUID_CFV4E,
     M68K_CPUID_ANY,
 };
@@ -39,6 +40,7 @@ struct m68k_def_t {
 
 static m68k_def_t m68k_cpu_defs[] = {
     {"m5206", M68K_CPUID_M5206}, 
+    {"m5208", M68K_CPUID_M5208}, 
     {"cfv4e", M68K_CPUID_CFV4E},
     {"any", M68K_CPUID_ANY},
     {NULL, 0}, 
@@ -64,12 +66,18 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name)
     case M68K_CPUID_M5206:
         m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
         break;
+    case M68K_CPUID_M5208:
+        m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
+        m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
+        m68k_set_feature(env, M68K_FEATURE_USP);
+        break;
     case M68K_CPUID_CFV4E:
         m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
         m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
         m68k_set_feature(env, M68K_FEATURE_CF_ISA_C);
         m68k_set_feature(env, M68K_FEATURE_CF_FPU);
         m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
+        m68k_set_feature(env, M68K_FEATURE_USP);
         break;
     case M68K_CPUID_ANY:
         m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
@@ -79,6 +87,7 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name)
         /* MAC and EMAC are mututally exclusive, so pick EMAC.
            It's mostly backwards compatible.  */
         m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
+        m68k_set_feature(env, M68K_FEATURE_USP);
         m68k_set_feature(env, M68K_FEATURE_EXT_FULL);
         break;
     }
@@ -215,7 +224,11 @@ void helper_movec(CPUM68KState *env, int reg, uint32_t val)
 {
     switch (reg) {
     case 0x02: /* CACR */
-        /* Ignored.  */
+        env->cacr = val;
+        m68k_switch_sp(env);
+        break;
+    case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
+        /* TODO: Implement Access Control Registers.  */
         break;
     case 0x801: /* VBR */
         env->vbr = val;
@@ -261,6 +274,17 @@ void m68k_set_macsr(CPUM68KState *env, uint32_t val)
     env->macsr = val;
 }
 
+void m68k_switch_sp(CPUM68KState *env)
+{
+    int new_sp;
+
+    env->sp[env->current_sp] = env->aregs[7];
+    new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
+             ? M68K_SSP : M68K_USP;
+    env->aregs[7] = env->sp[new_sp];
+    env->current_sp = new_sp;
+}
+
 /* MMU */
 
 /* TODO: This will need fixing once the MMU is implemented.  */
diff --git a/target-m68k/op.c b/target-m68k/op.c
index febfe034c1..932c994357 100644
--- a/target-m68k/op.c
+++ b/target-m68k/op.c
@@ -478,6 +478,13 @@ OP(fp_result)
     FORCE_RET();
 }
 
+OP(set_sr)
+{
+    env->sr = get_op(PARAM1);
+    m68k_switch_sp(env);
+    FORCE_RET();
+}
+
 OP(jmp)
 {
     GOTO_LABEL_PARAM(1);
diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c
index 8086238db4..4c423ca984 100644
--- a/target-m68k/op_helper.c
+++ b/target-m68k/op_helper.c
@@ -87,6 +87,7 @@ static void do_rte(void)
     env->pc = ldl_kernel(sp + 4);
     sp |= (fmt >> 28) & 3;
     env->sr = fmt & 0xffff;
+    m68k_switch_sp(env);
     env->aregs[7] = sp + 8;
 }
 
@@ -128,9 +129,6 @@ void do_interrupt(int is_hw)
         }
     }
 
-    /* TODO: Implement USP.  */
-    sp = env->aregs[7];
-
     vector = env->exception_index << 2;
 
     fmt |= 0x40000000;
@@ -138,6 +136,15 @@ void do_interrupt(int is_hw)
     fmt |= vector << 16;
     fmt |= env->sr;
 
+    env->sr |= SR_S;
+    if (is_hw) {
+        env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT);
+        env->sr &= ~SR_M;
+    }
+    m68k_switch_sp(env);
+
+    sp = env->aregs[7];
+
     /* ??? This could cause MMU faults.  */
     sp &= ~3;
     sp -= 4;
@@ -145,11 +152,6 @@ void do_interrupt(int is_hw)
     sp -= 4;
     stl_kernel(sp, fmt);
     env->aregs[7] = sp;
-    env->sr |= SR_S;
-    if (is_hw) {
-        env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT);
-        env->sr &= ~SR_M;
-    }
     /* Jump to vector.  */
     env->pc = ldl_kernel(env->vbr + vector);
 }
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 1d32e8f0f7..da3e72a473 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -1345,7 +1345,7 @@ static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only)
     gen_op_logic_cc(gen_im32(val & 0xf));
     gen_op_update_xflag_tst(gen_im32((val & 0x10) >> 4));
     if (!ccr_only) {
-        gen_op_mov32(QREG_SR, gen_im32(val & 0xff00));
+        gen_op_set_sr(gen_im32(val & 0xff00));
     }
 }
 
@@ -1365,7 +1365,7 @@ static void gen_set_sr(DisasContext *s, uint16_t insn, int ccr_only)
         gen_op_and32(src1, src1, gen_im32(1));
         gen_op_update_xflag_tst(src1);
         if (!ccr_only) {
-            gen_op_and32(QREG_SR, reg, gen_im32(0xff00));
+            gen_op_set_sr(reg);
         }
       }
     else if ((insn & 0x3f) == 0x3c)
@@ -2797,8 +2797,8 @@ void register_m68k_insns (CPUM68KState *env)
     INSN(trap,      4e40, fff0, CF_ISA_A);
     INSN(link,      4e50, fff8, CF_ISA_A);
     INSN(unlk,      4e58, fff8, CF_ISA_A);
-    INSN(move_to_usp, 4e60, fff8, CF_ISA_B);
-    INSN(move_from_usp, 4e68, fff8, CF_ISA_B);
+    INSN(move_to_usp, 4e60, fff8, USP);
+    INSN(move_from_usp, 4e68, fff8, USP);
     INSN(nop,       4e71, ffff, CF_ISA_A);
     INSN(stop,      4e72, ffff, CF_ISA_A);
     INSN(rte,       4e73, ffff, CF_ISA_A);
@@ -3261,6 +3261,7 @@ void cpu_reset(CPUM68KState *env)
 #if !defined (CONFIG_USER_ONLY)
     env->sr = 0x2700;
 #endif
+    m68k_switch_sp(env);
     /* ??? FP regs should be initialized to NaN.  */
     env->cc_op = CC_OP_FLAGS;
     /* TODO: We should set PC from the interrupt vector.  */