Improve ColdFire CPU selection.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2925 c046a42c-6fe2-441c-8c8c-71466251a162
diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index 6f29d5e..2d43354 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -184,14 +184,20 @@
 
 void do_m68k_semihosting(CPUM68KState *env, int nr);
 
+/* There are 4 ColdFire core ISA revisions: A, A+, B and C.
+   Each feature covers the subset of instructions common to the
+   ISA revisions mentioned.  */
+
 enum m68k_features {
     M68K_FEATURE_CF_ISA_A,
-    M68K_FEATURE_CF_ISA_B,
-    M68K_FEATURE_CF_ISA_C,
+    M68K_FEATURE_CF_ISA_B, /* (ISA B or C).  */
+    M68K_FEATURE_CF_ISA_APLUSC, /* BIT/BITREV, FF1, STRLDSR (ISA A+ or C).  */
+    M68K_FEATURE_BRAL, /* Long unconditional branch.  (ISA A+ or B).  */
     M68K_FEATURE_CF_FPU,
     M68K_FEATURE_CF_MAC,
     M68K_FEATURE_CF_EMAC,
-    M68K_FEATURE_USP,
+    M68K_FEATURE_CF_EMAC_B, /* Revision B EMAC (dual accumulate).  */
+    M68K_FEATURE_USP, /* User Stack Pointer.  (ISA A+, B or C).  */
     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 bb213a7..1330522 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -68,13 +68,15 @@
         break;
     case M68K_CPUID_M5208:
         m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
+        m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC);
+        m68k_set_feature(env, M68K_FEATURE_BRAL);
         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_BRAL);
         m68k_set_feature(env, M68K_FEATURE_CF_FPU);
         m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
         m68k_set_feature(env, M68K_FEATURE_USP);
@@ -82,13 +84,16 @@
     case M68K_CPUID_ANY:
         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_ISA_APLUSC);
+        m68k_set_feature(env, M68K_FEATURE_BRAL);
         m68k_set_feature(env, M68K_FEATURE_CF_FPU);
         /* 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_CF_EMAC_B);
         m68k_set_feature(env, M68K_FEATURE_USP);
         m68k_set_feature(env, M68K_FEATURE_EXT_FULL);
+        m68k_set_feature(env, M68K_FEATURE_WORD_INDEX);
         break;
     }
 
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index da3e72a..1c0e431 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2473,6 +2473,10 @@
 
     acc = ((insn >> 7) & 1) | ((ext >> 3) & 2);
     dual = ((insn & 0x30) != 0 && (ext & 3) != 0);
+    if (dual && !m68k_feature(s->env, M68K_FEATURE_CF_EMAC_B)) {
+        disas_undef(s, insn);
+        return;
+    }
     if (insn & 0x30) {
         /* MAC with load.  */
         tmp = gen_lea(s, insn, OS_LONG);
@@ -2745,20 +2749,21 @@
    Later insn override earlier ones.  */
 void register_m68k_insns (CPUM68KState *env)
 {
-#define INSN(name, opcode, mask, feature) \
+#define INSN(name, opcode, mask, feature) do { \
     if (m68k_feature(env, M68K_FEATURE_##feature)) \
-        register_opcode(disas_##name, 0x##opcode, 0x##mask)
+        register_opcode(disas_##name, 0x##opcode, 0x##mask); \
+    } while(0)
     INSN(undef,     0000, 0000, CF_ISA_A);
     INSN(arith_im,  0080, fff8, CF_ISA_A);
-    INSN(bitrev,    00c0, fff8, CF_ISA_C);
+    INSN(bitrev,    00c0, fff8, CF_ISA_APLUSC);
     INSN(bitop_reg, 0100, f1c0, CF_ISA_A);
     INSN(bitop_reg, 0140, f1c0, CF_ISA_A);
     INSN(bitop_reg, 0180, f1c0, CF_ISA_A);
     INSN(bitop_reg, 01c0, f1c0, CF_ISA_A);
     INSN(arith_im,  0280, fff8, CF_ISA_A);
-    INSN(byterev,   02c0, fff8, CF_ISA_A);
+    INSN(byterev,   02c0, fff8, CF_ISA_APLUSC);
     INSN(arith_im,  0480, fff8, CF_ISA_A);
-    INSN(ff1,       04c0, fff8, CF_ISA_C);
+    INSN(ff1,       04c0, fff8, CF_ISA_APLUSC);
     INSN(arith_im,  0680, fff8, CF_ISA_A);
     INSN(bitop_im,  0800, ffc0, CF_ISA_A);
     INSN(bitop_im,  0840, ffc0, CF_ISA_A);
@@ -2769,7 +2774,7 @@
     INSN(move,      1000, f000, CF_ISA_A);
     INSN(move,      2000, f000, CF_ISA_A);
     INSN(move,      3000, f000, CF_ISA_A);
-    INSN(strldsr,   40e7, ffff, CF_ISA_A);
+    INSN(strldsr,   40e7, ffff, CF_ISA_APLUSC);
     INSN(negx,      4080, fff8, CF_ISA_A);
     INSN(move_from_sr, 40c0, fff8, CF_ISA_A);
     INSN(lea,       41c0, f1c0, CF_ISA_A);
@@ -2810,7 +2815,15 @@
     INSN(scc,       50c0, f0f8, CF_ISA_A);
     INSN(addsubq,   5080, f1c0, CF_ISA_A);
     INSN(tpf,       51f8, fff8, CF_ISA_A);
+
+    /* Branch instructions.  */
     INSN(branch,    6000, f000, CF_ISA_A);
+    /* Disable long branch instructions, then add back the ones we want.  */
+    INSN(undef,     60ff, f0ff, CF_ISA_A); /* All long branches.  */
+    INSN(branch,    60ff, f0ff, CF_ISA_B);
+    INSN(undef,     60ff, ffff, CF_ISA_B); /* bra.l */
+    INSN(branch,    60ff, ffff, BRAL);
+
     INSN(moveq,     7000, f100, CF_ISA_A);
     INSN(mvzs,      7100, f100, CF_ISA_B);
     INSN(or,        8000, f000, CF_ISA_A);