qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] MIPS instruction set configuration


From: Dirk Behme
Subject: [Qemu-devel] [PATCH] MIPS instruction set configuration
Date: Sun, 02 Jul 2006 18:27:29 +0200
User-agent: Mozilla Thunderbird 1.0.7 (X11/20050923)

Fabrice Bellard wrote:
You should add a runtime selection system : see the ARM and PowerPC targets (I would prefer a parameter to cpu_init(). It was not done that way on PowerPC for legacy reasons). Each machine should be able to select the processor it needs (and allow the user to change it if needed, but it is not the main point). There is no good reason to make the selection at compile time because the translator can efficiently handle any CPU differences at runtime.

Find in the attachment a first proposal for runtime
instruction set configuration for MIPS target. Please
comment, correct etc.

Some notes:

- As first step, only three options for R4K, NEC (partly,
see below) and FPU are used. The different MIPS ISA levels
aren't used at the moment and are there for future use.
Fabrice mentioned that he likes to split the different MIPS
intstruction set configurations clearly.

- As I understand it, MIPS III is an extension of MIPS II,
MIPS IV is an extension of MIPS III etc. Therefore I used
definitions for ISAx which include the smaller ones as well.

- With the

#ifdef MIPS_USES_xxx
#define mips_uses_xxx()  (env->features & MIPS_FEATURE_xxx)
#else
#define mips_uses_xxx()  0
#endif

logic it should be possible to enable or disable a feature
at compile time by setting the corresponding macro *or* at
runtime by adding machines with different features to
cpu_mips_set_model().

- If mips_uses_xxx()  is set to 0 at compile time, I think
gcc should optimize away the if(mips_uses_xxx()) parts in
translate.c. Therefore I think we can remove some #if
defined (MIPS_USES_xxx).

- An cpu_mips_set_model() is introduced similiar to the ARM
one. Because in mips-defs.h there was a hardcoded CPU, some
reorganization for runtime selection was necessary.

- Later, it should be possible to move more options to
runtime configuration, like endianess and the #if defined
(MIPS_CONFIGx) in cpu_mips_init(). For the moment, to keep
patch small I concentrated only on instruction set. I don't
want to mix to much instruction set configuration and
machine runtime selection for the moment.

- cpu_mips_init() moved from translate.c to helper.c and was
extended there by set_feature() and cpu_mips_set_model()
(same file location like used by ARM). Setting of FPU
options moved from cpu_mips_init() to model configuration
cpu_mips_set_model().

- My patch for NEC instruction set extension (the main
reason for the whole stuff ;) ) will be send and updated if
you like the configuration in this patch and something like
this is applied. For the moment, there's only a stub in
decode_opc() which should generate an exception.

Best regards

Dirk


--- ./target-mips/cpu.h_orig    2006-07-02 14:44:59.000000000 +0200
+++ ./target-mips/cpu.h 2006-07-02 17:32:41.000000000 +0200
@@ -210,6 +210,8 @@ struct CPUMIPSState {
     int bcond;                   /* Branch condition (if needed)       */
 
     int halted; /* TRUE if the CPU is in suspend state */
+    
+    uint32_t features;           /* Internal CPU feature flags */
 
     CPU_COMMON
 };
@@ -275,5 +277,58 @@ enum {
 int cpu_mips_exec(CPUMIPSState *s);
 CPUMIPSState *cpu_mips_init(void);
 uint32_t cpu_mips_get_clock (void);
+void cpu_mips_set_model(CPUMIPSState *env, uint32_t id);
+
+enum mips_features {
+    MIPS_FEATURE_ISA1 = 0x1, /* MIPS I   instruction set architecture */
+    MIPS_FEATURE_ISA2 = 0x3, /* MIPS II  instruction set architecture */
+    MIPS_FEATURE_ISA3 = 0x7, /* MIPS III instruction set architecture */
+    MIPS_FEATURE_ISA4 = 0xF, /* MIPS IV  instruction set architecture */
+    MIPS_FEATURE_R4K_EXT = 0x10, /* instruction set extension for MIPS R4K */
+    MIPS_FEATURE_NEC_EXT = 0x20, /* instruction set extension for NEC CPUs */
+    MIPS_FEATURE_FPU = 0x40,  /* floating point instruction set */
+};
+
+#ifdef MIPS_USES_ISA1
+#define mips_uses_isa1()  (env->features & MIPS_FEATURE_ISA1)
+#else
+#define mips_uses_isa1()  0
+#endif
+
+#ifdef MIPS_USES_ISA2
+#define mips_uses_isa2()  (env->features & MIPS_FEATURE_ISA2)
+#else
+#define mips_uses_isa2()  0
+#endif
+
+#ifdef MIPS_USES_ISA3
+#define mips_uses_isa3()  (env->features & MIPS_FEATURE_ISA3)
+#else
+#define mips_uses_isa3()  0
+#endif
+
+#ifdef MIPS_USES_ISA4
+#define mips_uses_isa4()  (env->features & MIPS_FEATURE_ISA4)
+#else
+#define mips_uses_isa4()  0
+#endif
+
+#ifdef MIPS_USES_R4K_EXT
+#define mips_uses_r4k_ext()  (env->features & MIPS_FEATURE_R4K_EXT)
+#else
+#define mips_uses_r4k_ext()  0
+#endif
+
+#ifdef MIPS_FEATURE_NEC_EXT
+#define mips_uses_nec_ext()  (env->features & MIPS_FEATURE_NEC_EXT)
+#else
+#define mips_uses_nec_ext()  0
+#endif
+
+#ifdef MIPS_USES_FPU
+#define mips_uses_fpu()  (env->features & MIPS_FEATURE_FPU)
+#else
+#define mips_uses_fpu()  0
+#endif
 
 #endif /* !defined (__MIPS_CPU_H__) */
--- ./target-mips/helper.c_orig 2006-07-02 15:30:49.000000000 +0200
+++ ./target-mips/helper.c      2006-07-02 17:41:01.000000000 +0200
@@ -430,3 +430,69 @@ void do_interrupt (CPUState *env)
     }
     env->exception_index = EXCP_NONE;
 }
+
+CPUMIPSState *cpu_mips_init (void)
+{
+    CPUMIPSState *env;
+
+    env = qemu_mallocz(sizeof(CPUMIPSState));
+    if (!env)
+        return NULL;
+    cpu_exec_init(env);
+    tlb_flush(env, 1);
+    /* Minimal init */
+    env->PC = 0xBFC00000;
+#if defined (MIPS_USES_R4K_TLB)
+    env->CP0_random = MIPS_TLB_NB - 1;
+#endif
+    env->CP0_Wired = 0;
+    env->CP0_Config0 = MIPS_CONFIG0;
+#if defined (MIPS_CONFIG1)
+        env->CP0_Config1 = MIPS_CONFIG1;
+#endif
+#if defined (MIPS_CONFIG2)
+        env->CP0_Config2 = MIPS_CONFIG2;
+#endif
+#if defined (MIPS_CONFIG3)
+        env->CP0_Config3 = MIPS_CONFIG3;
+#endif
+    env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
+    env->CP0_WatchLo = 0;
+    env->hflags = MIPS_HFLAG_ERL;
+    /* Count register increments in debug mode, EJTAG version 1 */
+    env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
+    env->exception_index = EXCP_NONE;
+#if defined(CONFIG_USER_ONLY)
+    env->hflags |= MIPS_HFLAG_UM;
+#endif
+    return env;
+}
+
+static inline void set_feature(CPUMIPSState *env, int feature)
+{
+    env->features |= feature;
+}
+
+void cpu_mips_set_model(CPUMIPSState *env, uint32_t id)
+{
+    env->CP0_PRid = id;
+    env->features = 0;
+    switch (id) {
+    case MIPS_R4Kc:
+        set_feature(env, MIPS_FEATURE_ISA3);
+        set_feature(env, MIPS_FEATURE_R4K_EXT);
+        set_feature(env, MIPS_FEATURE_FPU);
+        break;
+    default:
+        cpu_abort(env, "Bad CPU ID: %x\n", id);
+        break;
+    }
+
+    if(mips_uses_fpu()) {
+        env->fcr0 = MIPS_FCR0;
+#if defined (MIPS_CONFIG1)
+       env->CP0_Config1 |= (1 << CP0C1_FP);
+#endif
+    }
+}
+
--- ./target-mips/translate.c_orig      2006-07-02 17:06:18.000000000 +0200
+++ ./target-mips/translate.c   2006-07-02 17:40:17.000000000 +0200
@@ -1887,7 +1887,7 @@ static void gen_blikely(DisasContext *ct
     gen_set_label(l1);
 }
 
-static void decode_opc (DisasContext *ctx)
+static void decode_opc (CPUState *env, DisasContext *ctx)
 {
     int32_t offset;
     int rs, rt, rd, sa;
@@ -1927,7 +1927,17 @@ static void decode_opc (DisasContext *ct
             gen_arith(ctx, op1 | EXT_SPECIAL, rd, rs, rt);
             break;
         case 0x18 ... 0x1B: /* MULT / DIV */
-            gen_muldiv(ctx, op1 | EXT_SPECIAL, rs, rt);
+           if(!sa) {
+                gen_muldiv(ctx, op1 | EXT_SPECIAL, rs, rt);
+           } else {
+               if(mips_uses_nec_ext()) {
+                   op1 = ctx->opcode & 0x7FF;
+                   /* tbd: call handler for special NEC instructions */
+                } else {
+                   MIPS_INVAL("NEC extension");
+                    generate_exception(ctx, EXCP_RI);
+                }
+            }
             break;
         case 0x08 ... 0x09: /* Jumps */
             gen_compute_branch(ctx, op1 | EXT_SPECIAL, rs, rd, sa);
@@ -1985,19 +1995,32 @@ static void decode_opc (DisasContext *ct
     case 0x1C:          /* Special2 opcode */
         op1 = ctx->opcode & 0x3F;
         switch (op1) {
-#if defined (MIPS_USES_R4K_EXT)
         /* Those instructions are not part of MIPS32 core */
         case 0x00 ... 0x01: /* Multiply and add/sub */
         case 0x04 ... 0x05:
-            gen_muldiv(ctx, op1 | EXT_SPECIAL2, rs, rt);
+           if(mips_uses_r4k_ext()) {
+                gen_muldiv(ctx, op1 | EXT_SPECIAL2, rs, rt);
+            } else {
+               MIPS_INVAL("r4k extension");
+                generate_exception(ctx, EXCP_RI);
+            }
             break;
         case 0x02:          /* MUL */
-            gen_arith(ctx, op1 | EXT_SPECIAL2, rd, rs, rt);
+           if(mips_uses_r4k_ext()) {
+                gen_arith(ctx, op1 | EXT_SPECIAL2, rd, rs, rt);
+            } else {
+               MIPS_INVAL("r4k extension");
+                generate_exception(ctx, EXCP_RI);
+            }
             break;
         case 0x20 ... 0x21: /* CLO / CLZ */
-            gen_cl(ctx, op1 | EXT_SPECIAL2, rd, rs);
+           if(mips_uses_r4k_ext()) {
+                gen_cl(ctx, op1 | EXT_SPECIAL2, rd, rs);
+            } else {
+               MIPS_INVAL("r4k extension");
+                generate_exception(ctx, EXCP_RI);
+            }
             break;
-#endif
         case 0x3F:          /* SDBBP */
             /* XXX: not clear which exception should be raised
              *      when in debug mode...
@@ -2074,43 +2097,43 @@ static void decode_opc (DisasContext *ct
     case 0x35: /* LDC1 */
     case 0x39: /* SWC1 */
     case 0x3D: /* SDC1 */
-#if defined(MIPS_USES_FPU)
-        gen_op_cp1_enabled();
-        gen_flt_ldst(ctx, op, rt, rs, imm);
-#else
-        generate_exception_err(ctx, EXCP_CpU, 1);
-#endif
+        if(mips_uses_fpu()) {
+            gen_op_cp1_enabled();
+            gen_flt_ldst(ctx, op, rt, rs, imm);
+        } else {
+            generate_exception_err(ctx, EXCP_CpU, 1);
+       }
         break;
 
     case 0x11:          /* CP1 opcode */
-#if defined(MIPS_USES_FPU)
-        gen_op_cp1_enabled();
-        op1 = ((ctx->opcode >> 21) & 0x1F);
-        switch (op1) {
-        case 0x00: /* mfc1 */
-        case 0x02: /* cfc1 */
-        case 0x04: /* mtc1 */
-        case 0x06: /* ctc1 */
-            gen_cp1(ctx, op1 | EXT_CP1, rt, rd);
-            break;
-        case 0x08: /* bc */
-            gen_compute_branch1(ctx, rt, imm << 2);
-            return;
-        case 0x10: /* 16: fmt=single fp */
-        case 0x11: /* 17: fmt=double fp */
-        case 0x14: /* 20: fmt=32bit fixed */
-        case 0x15: /* 21: fmt=64bit fixed */
-            gen_farith(ctx, op1, rt, rd, sa, ctx->opcode & 0x3f);
-            break;
-        default:
-            generate_exception_err(ctx, EXCP_RI, 1);
+        if(mips_uses_fpu()) {
+            gen_op_cp1_enabled();
+            op1 = ((ctx->opcode >> 21) & 0x1F);
+            switch (op1) {
+            case 0x00: /* mfc1 */
+            case 0x02: /* cfc1 */
+            case 0x04: /* mtc1 */
+            case 0x06: /* ctc1 */
+                gen_cp1(ctx, op1 | EXT_CP1, rt, rd);
+                break;
+            case 0x08: /* bc */
+                gen_compute_branch1(ctx, rt, imm << 2);
+                return;
+            case 0x10: /* 16: fmt=single fp */
+            case 0x11: /* 17: fmt=double fp */
+            case 0x14: /* 20: fmt=32bit fixed */
+            case 0x15: /* 21: fmt=64bit fixed */
+                gen_farith(ctx, op1, rt, rd, sa, ctx->opcode & 0x3f);
+                break;
+            default:
+                generate_exception_err(ctx, EXCP_RI, 1);
+                break;
+            }
             break;
+        } else {
+            generate_exception_err(ctx, EXCP_CpU, 1);
         }
         break;
-#else
-        generate_exception_err(ctx, EXCP_CpU, 1);
-#endif
-        break;
 
     /* COP2.  */
     case 0x32: /* LWC2 */
@@ -2262,7 +2285,7 @@ int gen_intermediate_code_internal (CPUS
             gen_opc_instr_start[lj] = 1;
         }
         ctx.opcode = ldl_code(ctx.pc);
-        decode_opc(&ctx);
+        decode_opc(env, &ctx);
         ctx.pc += 4;
 
         if (env->singlestep_enabled)
@@ -2400,44 +2423,3 @@ void cpu_dump_state (CPUState *env, FILE
     fpu_dump_state(env, f, cpu_fprintf, flags);
 #endif
 }
-
-CPUMIPSState *cpu_mips_init (void)
-{
-    CPUMIPSState *env;
-
-    env = qemu_mallocz(sizeof(CPUMIPSState));
-    if (!env)
-        return NULL;
-    cpu_exec_init(env);
-    tlb_flush(env, 1);
-    /* Minimal init */
-    env->PC = 0xBFC00000;
-#if defined (MIPS_USES_R4K_TLB)
-    env->CP0_random = MIPS_TLB_NB - 1;
-#endif
-    env->CP0_Wired = 0;
-    env->CP0_Config0 = MIPS_CONFIG0;
-#if defined (MIPS_CONFIG1)
-        env->CP0_Config1 = MIPS_CONFIG1;
-#endif
-#if defined (MIPS_CONFIG2)
-        env->CP0_Config2 = MIPS_CONFIG2;
-#endif
-#if defined (MIPS_CONFIG3)
-        env->CP0_Config3 = MIPS_CONFIG3;
-#endif
-    env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
-    env->CP0_WatchLo = 0;
-    env->hflags = MIPS_HFLAG_ERL;
-    /* Count register increments in debug mode, EJTAG version 1 */
-    env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
-    env->CP0_PRid = MIPS_CPU;
-    env->exception_index = EXCP_NONE;
-#if defined(CONFIG_USER_ONLY)
-    env->hflags |= MIPS_HFLAG_UM;
-#endif
-#ifdef MIPS_USES_FPU
-    env->fcr0 = MIPS_FCR0;     
-#endif
-    return env;
-}
--- ./target-mips/mips-defs.h_orig      2006-07-02 15:22:18.000000000 +0200
+++ ./target-mips/mips-defs.h   2006-07-02 17:01:35.000000000 +0200
@@ -9,10 +9,6 @@
 #define MIPS_R4Kc 0x00018000
 #define MIPS_R4Kp 0x00018300
 
-/* Emulate MIPS R4Kc for now */
-#define MIPS_CPU MIPS_R4Kc
-
-#if (MIPS_CPU == MIPS_R4Kc)
 /* 32 bits target */
 #define TARGET_LONG_BITS 32
 /* real pages are variable size... */
@@ -40,28 +36,13 @@
 /* 16 TLBs, 64 sets Icache, 16 bytes Icache line, 2-way Icache,
  * 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache,
  * no performance counters, watch registers present, no code compression,
- * EJTAG present, FPU enable bit depending on MIPS_USES_FPU
+ * EJTAG present, FPU bit is set depending on runtime FPU selection
  */
 #define MIPS_CONFIG1                                            \
 ((15 << CP0C1_MMU) |                                            \
  (0x000 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x01 << CP0C1_IA) | \
  (0x000 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x01 << CP0C1_DA) | \
  (0 << CP0C1_PC) | (1 << CP0C1_WR) | (0 << CP0C1_CA) |          \
- (1 << CP0C1_EP) | (MIPS_USES_FPU << CP0C1_FP))
-#elif (MIPS_CPU == MIPS_R4Kp)
-/* 32 bits target */
-#define TARGET_LONG_BITS 32
-/* real pages are variable size... */
-#define TARGET_PAGE_BITS 12
-/* Uses MIPS R4Kx enhancements to MIPS32 architecture */
-#define MIPS_USES_R4K_EXT
-/* Uses MIPS R4Km FPM MMU model */
-#define MIPS_USES_R4K_FPM
-#else
-#error "MIPS CPU not defined"
-/* Remainder for other flags */
-//#define TARGET_MIPS64
-//#define MIPS_USES_FPU
-#endif
+ (1 << CP0C1_EP))
 
 #endif /* !defined (__QEMU_MIPS_DEFS_H__) */
--- ./vl.c_orig 2006-07-02 16:31:19.000000000 +0200
+++ ./vl.c      2006-07-02 16:38:57.000000000 +0200
@@ -5455,7 +5455,7 @@ void register_machines(void)
     qemu_register_machine(&core99_machine);
     qemu_register_machine(&prep_machine);
 #elif defined(TARGET_MIPS)
-    qemu_register_machine(&mips_machine);
+    qemu_register_machine(&mips_r4kc_machine);
 #elif defined(TARGET_SPARC)
 #ifdef TARGET_SPARC64
     qemu_register_machine(&sun4u_machine);
--- ./hw/mips_r4k.c_orig        2006-07-02 16:29:14.000000000 +0200
+++ ./hw/mips_r4k.c     2006-07-02 17:34:00.000000000 +0200
@@ -189,10 +189,10 @@ CPUReadMemoryFunc *io_read[] = {
     &io_readl,
 };
 
-void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
-                    DisplayState *ds, const char **fd_filename, int snapshot,
-                    const char *kernel_filename, const char *kernel_cmdline,
-                    const char *initrd_filename)
+void mips_r4kc_init (int ram_size, int vga_ram_size, int boot_device,
+                     DisplayState *ds, const char **fd_filename, int snapshot,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename)
 {
     char buf[1024];
     int64_t entry = 0;
@@ -203,6 +203,7 @@ void mips_r4k_init (int ram_size, int vg
     long kernel_size;
 
     env = cpu_init();
+    cpu_mips_set_model(env, MIPS_R4Kc);
     register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
 
     /* allocate RAM */
@@ -284,8 +285,8 @@ void mips_r4k_init (int ram_size, int vg
     }
 }
 
-QEMUMachine mips_machine = {
-    "mips",
-    "mips r4k platform",
-    mips_r4k_init,
+QEMUMachine mips_r4kc_machine = {
+    "r4kc",
+    "mips r4kc platform",
+    mips_r4kc_init,
 };
--- ./vl.h_orig 2006-07-02 16:31:24.000000000 +0200
+++ ./vl.h      2006-07-02 16:39:18.000000000 +0200
@@ -913,7 +913,7 @@ extern QEMUMachine core99_machine;
 extern QEMUMachine heathrow_machine;
 
 /* mips_r4k.c */
-extern QEMUMachine mips_machine;
+extern QEMUMachine mips_r4kc_machine;
 
 /* shix.c */
 extern QEMUMachine shix_machine;

reply via email to

[Prev in Thread] Current Thread [Next in Thread]