]> git.proxmox.com Git - mirror_qemu.git/commitdiff
target-microblaze: Add Extended Addressing
authorEdgar E. Iglesias <edgar.iglesias@xilinx.com>
Fri, 13 Apr 2018 20:04:37 +0000 (22:04 +0200)
committerEdgar E. Iglesias <edgar.iglesias@xilinx.com>
Tue, 29 May 2018 07:35:14 +0000 (09:35 +0200)
Add support for Extended Addressing. Load/stores with EA
enabled concatenate two 32bit registers to form an extended
address.

We don't allow users to enable address sizes larger than
32 bits quite yet though. Once the MMU support is in, we'll
turn it on.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
target/microblaze/cpu.c
target/microblaze/cpu.h
target/microblaze/translate.c

index a6f1ce65493cf74dad3a312186ca6b3fb2a64a85..6ee15ac80002d9596c3621f43a5d29a35cd567ea 100644 (file)
@@ -154,6 +154,13 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp)
         return;
     }
 
+    if (cpu->cfg.addr_size != 32) {
+        error_setg(errp, "addr-size %d is out of range. "
+                   "Only 32bit is supported.",
+                   cpu->cfg.addr_size);
+        return;
+    }
+
     qemu_init_vcpu(cs);
 
     env->pvr.regs[0] = PVR0_USE_EXC_MASK \
@@ -200,7 +207,8 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp)
     env->pvr.regs[5] |= cpu->cfg.dcache_writeback ?
                                         PVR5_DCACHE_WRITEBACK_MASK : 0;
 
-    env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family.  */
+    env->pvr.regs[10] = 0x0c000000 | /* Default to spartan 3a dsp family.  */
+                        (cpu->cfg.addr_size - 32) << PVR10_ASIZE_SHIFT;
     env->pvr.regs[11] = (cpu->cfg.use_mmu ? PVR11_USE_MMU : 0) |
                         16 << 17;
 
@@ -232,6 +240,14 @@ static Property mb_properties[] = {
     DEFINE_PROP_UINT32("base-vectors", MicroBlazeCPU, cfg.base_vectors, 0),
     DEFINE_PROP_BOOL("use-stack-protection", MicroBlazeCPU, cfg.stackprot,
                      false),
+    /*
+     * This is the C_ADDR_SIZE synth-time configuration option of the
+     * MicroBlaze cores. Supported values range between 32 and 64.
+     *
+     * When set to > 32, 32bit MicroBlaze can emit load/stores
+     * with extended addressing.
+     */
+    DEFINE_PROP_UINT8("addr-size", MicroBlazeCPU, cfg.addr_size, 32),
     /* If use-fpu > 0 - FPU is enabled
      * If use-fpu = 2 - Floating point conversion and square root instructions
      *                  are enabled
index b631b7dc4c3eabdeab3458f8586120b0ea1c828a..e62c456ccf7ec337ddaf9324fbd56384de74aa37 100644 (file)
@@ -203,6 +203,7 @@ typedef struct CPUMBState CPUMBState;
 
 /* Target family PVR mask */
 #define PVR10_TARGET_FAMILY_MASK        0xFF000000
+#define PVR10_ASIZE_SHIFT               18
 
 /* MMU descrtiption */
 #define PVR11_USE_MMU                   0xC0000000
@@ -297,6 +298,7 @@ struct MicroBlazeCPU {
     struct {
         bool stackprot;
         uint32_t base_vectors;
+        uint8_t addr_size;
         uint8_t use_fpu;
         uint8_t use_hw_mul;
         bool use_barrel;
index 7db4bdcf09f5b09a73c7f7ddd488364c7ab123fc..504db888902c91846afd2848210adf849ef3f585 100644 (file)
@@ -824,7 +824,7 @@ static void dec_imm(DisasContext *dc)
     dc->clear_imm = 0;
 }
 
-static inline void compute_ldst_addr(DisasContext *dc, TCGv t)
+static inline void compute_ldst_addr(DisasContext *dc, bool ea, TCGv t)
 {
     bool extimm = dc->tb_flags & IMM_FLAG;
     /* Should be set to true if r1 is used by loadstores.  */
@@ -838,6 +838,22 @@ static inline void compute_ldst_addr(DisasContext *dc, TCGv t)
 
     /* Treat the common cases first.  */
     if (!dc->type_b) {
+        if (ea) {
+            int addr_size = dc->cpu->cfg.addr_size;
+
+            if (addr_size == 32) {
+                tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]);
+                return;
+            }
+
+            tcg_gen_concat_i32_i64(t, cpu_R[dc->rb], cpu_R[dc->ra]);
+            if (addr_size < 64) {
+                /* Mask off out of range bits.  */
+                tcg_gen_andi_i64(t, t, MAKE_64BIT_MASK(0, addr_size));
+            }
+            return;
+        }
+
         /* If any of the regs is r0, set t to the value of the other reg.  */
         if (dc->ra == 0) {
             tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]);
@@ -887,12 +903,14 @@ static void dec_load(DisasContext *dc)
     TCGv_i32 v;
     TCGv addr;
     unsigned int size;
-    bool rev = false, ex = false;
+    bool rev = false, ex = false, ea = false;
+    int mem_index = cpu_mmu_index(&dc->cpu->env, false);
     TCGMemOp mop;
 
     mop = dc->opcode & 3;
     size = 1 << mop;
     if (!dc->type_b) {
+        ea = extract32(dc->ir, 7, 1);
         rev = extract32(dc->ir, 9, 1);
         ex = extract32(dc->ir, 10, 1);
     }
@@ -905,12 +923,19 @@ static void dec_load(DisasContext *dc)
         return;
     }
 
-    LOG_DIS("l%d%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "",
-                                                        ex ? "x" : "");
+    if (trap_userspace(dc, ea)) {
+        return;
+    }
+
+    LOG_DIS("l%d%s%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "",
+                                                        ex ? "x" : "",
+                                                        ea ? "ea" : "");
 
     t_sync_flags(dc);
     addr = tcg_temp_new();
-    compute_ldst_addr(dc, addr);
+    compute_ldst_addr(dc, ea, addr);
+    /* Extended addressing bypasses the MMU.  */
+    mem_index = ea ? MMU_NOMMU_IDX : mem_index;
 
     /*
      * When doing reverse accesses we need to do two things.
@@ -964,7 +989,7 @@ static void dec_load(DisasContext *dc)
      * address and if that succeeds we write into the destination reg.
      */
     v = tcg_temp_new_i32();
-    tcg_gen_qemu_ld_i32(v, addr, cpu_mmu_index(&dc->cpu->env, false), mop);
+    tcg_gen_qemu_ld_i32(v, addr, mem_index, mop);
 
     if ((dc->cpu->env.pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {
         tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc);
@@ -994,12 +1019,14 @@ static void dec_store(DisasContext *dc)
     TCGv addr;
     TCGLabel *swx_skip = NULL;
     unsigned int size;
-    bool rev = false, ex = false;
+    bool rev = false, ex = false, ea = false;
+    int mem_index = cpu_mmu_index(&dc->cpu->env, false);
     TCGMemOp mop;
 
     mop = dc->opcode & 3;
     size = 1 << mop;
     if (!dc->type_b) {
+        ea = extract32(dc->ir, 7, 1);
         rev = extract32(dc->ir, 9, 1);
         ex = extract32(dc->ir, 10, 1);
     }
@@ -1012,14 +1039,19 @@ static void dec_store(DisasContext *dc)
         return;
     }
 
-    LOG_DIS("s%d%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "",
-                                                        ex ? "x" : "");
+    trap_userspace(dc, ea);
+
+    LOG_DIS("s%d%s%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "",
+                                                        ex ? "x" : "",
+                                                        ea ? "ea" : "");
     t_sync_flags(dc);
     /* If we get a fault on a dslot, the jmpstate better be in sync.  */
     sync_jmpstate(dc);
     /* SWX needs a temp_local.  */
     addr = ex ? tcg_temp_local_new() : tcg_temp_new();
-    compute_ldst_addr(dc, addr);
+    compute_ldst_addr(dc, ea, addr);
+    /* Extended addressing bypasses the MMU.  */
+    mem_index = ea ? MMU_NOMMU_IDX : mem_index;
 
     if (ex) { /* swx */
         TCGv_i32 tval;
@@ -1074,8 +1106,7 @@ static void dec_store(DisasContext *dc)
                 break;
         }
     }
-    tcg_gen_qemu_st_i32(cpu_R[dc->rd], addr,
-                        cpu_mmu_index(&dc->cpu->env, false), mop);
+    tcg_gen_qemu_st_i32(cpu_R[dc->rd], addr, mem_index, mop);
 
     /* Verify alignment if needed.  */
     if ((dc->cpu->env.pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {