Fix Sparc64 shifts
[qemu] / target-sparc / translate.c
index 4412363..4429063 100644 (file)
@@ -57,6 +57,7 @@ typedef struct DisasContext {
     int is_br;
     int mem_idx;
     int fpu_enabled;
+    int address_mask_32bit;
     struct TranslationBlock *tb;
     uint32_t features;
 } DisasContext;
@@ -201,12 +202,22 @@ static void gen_op_store_QT0_fpr(unsigned int dst)
 #endif
 #endif
 
-#ifdef TARGET_ABI32
-#define ABI32_MASK(addr) tcg_gen_andi_tl(addr, addr, 0xffffffffULL);
+#ifdef TARGET_SPARC64
+#ifndef TARGET_ABI32
+#define AM_CHECK(dc) ((dc)->address_mask_32bit)
 #else
-#define ABI32_MASK(addr)
+#define AM_CHECK(dc) (1)
+#endif
 #endif
 
+static inline void gen_address_mask(DisasContext *dc, TCGv addr)
+{
+#ifdef TARGET_SPARC64
+    if (AM_CHECK(dc))
+        tcg_gen_andi_tl(addr, addr, 0xffffffffULL);
+#endif
+}
+
 static inline void gen_movl_reg_TN(int reg, TCGv tn)
 {
     if (reg == 0)
@@ -375,7 +386,7 @@ static inline void gen_cc_V_add_icc(TCGv dst, TCGv src1, TCGv src2)
     tcg_gen_xori_tl(r_temp, r_temp, -1);
     tcg_gen_xor_tl(cpu_tmp0, src1, dst);
     tcg_gen_and_tl(r_temp, r_temp, cpu_tmp0);
-    tcg_gen_andi_tl(r_temp, r_temp, (1 << 31));
+    tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31));
     tcg_gen_shri_tl(r_temp, r_temp, 31 - PSR_OVF_SHIFT);
     tcg_gen_trunc_tl_i32(cpu_tmp32, r_temp);
     tcg_temp_free(r_temp);
@@ -412,7 +423,7 @@ static inline void gen_add_tv(TCGv dst, TCGv src1, TCGv src2)
     tcg_gen_xori_tl(r_temp, r_temp, -1);
     tcg_gen_xor_tl(cpu_tmp0, src1, dst);
     tcg_gen_and_tl(r_temp, r_temp, cpu_tmp0);
-    tcg_gen_andi_tl(r_temp, r_temp, (1 << 31));
+    tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31));
     tcg_gen_brcondi_tl(TCG_COND_EQ, r_temp, 0, l1);
     r_const = tcg_const_i32(TT_TOVF);
     tcg_gen_helper_0_1(raise_exception, r_const);
@@ -573,7 +584,7 @@ static inline void gen_cc_V_sub_icc(TCGv dst, TCGv src1, TCGv src2)
     tcg_gen_xor_tl(r_temp, src1, src2);
     tcg_gen_xor_tl(cpu_tmp0, src1, dst);
     tcg_gen_and_tl(r_temp, r_temp, cpu_tmp0);
-    tcg_gen_andi_tl(r_temp, r_temp, (1 << 31));
+    tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31));
     tcg_gen_shri_tl(r_temp, r_temp, 31 - PSR_OVF_SHIFT);
     tcg_gen_trunc_tl_i32(cpu_tmp32, r_temp);
     tcg_gen_or_i32(cpu_psr, cpu_psr, cpu_tmp32);
@@ -608,7 +619,7 @@ static inline void gen_sub_tv(TCGv dst, TCGv src1, TCGv src2)
     tcg_gen_xor_tl(r_temp, src1, src2);
     tcg_gen_xor_tl(cpu_tmp0, src1, dst);
     tcg_gen_and_tl(r_temp, r_temp, cpu_tmp0);
-    tcg_gen_andi_tl(r_temp, r_temp, (1 << 31));
+    tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31));
     tcg_gen_brcondi_tl(TCG_COND_EQ, r_temp, 0, l1);
     r_const = tcg_const_i32(TT_TOVF);
     tcg_gen_helper_0_1(raise_exception, r_const);
@@ -1630,13 +1641,11 @@ static inline void gen_clear_float_exceptions(void)
 #ifdef TARGET_SPARC64
 static inline TCGv gen_get_asi(int insn, TCGv r_addr)
 {
-    int asi, offset;
+    int asi;
     TCGv r_asi;
 
     if (IS_IMM) {
         r_asi = tcg_temp_new(TCG_TYPE_I32);
-        offset = GET_FIELD(insn, 25, 31);
-        tcg_gen_addi_tl(r_addr, r_addr, offset);
         tcg_gen_ld_i32(r_asi, cpu_env, offsetof(CPUSPARCState, asi));
     } else {
         asi = GET_FIELD(insn, 19, 26);
@@ -1711,20 +1720,15 @@ static inline void gen_swap_asi(TCGv dst, TCGv addr, int insn)
     tcg_gen_trunc_i64_tl(dst, cpu_tmp64);
 }
 
-static inline void gen_ldda_asi(TCGv lo, TCGv hi, TCGv addr, int insn)
+static inline void gen_ldda_asi(TCGv hi, TCGv addr, int insn, int rd)
 {
-    TCGv r_asi, r_size, r_sign;
+    TCGv r_asi, r_rd;
 
     r_asi = gen_get_asi(insn, addr);
-    r_size = tcg_const_i32(8);
-    r_sign = tcg_const_i32(0);
-    tcg_gen_helper_1_4(helper_ld_asi, cpu_tmp64, addr, r_asi, r_size, r_sign);
-    tcg_temp_free(r_sign);
-    tcg_temp_free(r_size);
+    r_rd = tcg_const_i32(rd);
+    tcg_gen_helper_0_3(helper_ldda_asi, addr, r_asi, r_rd);
+    tcg_temp_free(r_rd);
     tcg_temp_free(r_asi);
-    tcg_gen_andi_i64(lo, cpu_tmp64, 0xffffffffULL);
-    tcg_gen_shri_i64(cpu_tmp64, cpu_tmp64, 32);
-    tcg_gen_andi_i64(hi, cpu_tmp64, 0xffffffffULL);
 }
 
 static inline void gen_stda_asi(TCGv hi, TCGv addr, int insn, int rd)
@@ -1811,7 +1815,7 @@ static inline void gen_swap_asi(TCGv dst, TCGv addr, int insn)
     tcg_gen_trunc_i64_tl(dst, cpu_tmp64);
 }
 
-static inline void gen_ldda_asi(TCGv lo, TCGv hi, TCGv addr, int insn)
+static inline void gen_ldda_asi(TCGv hi, TCGv addr, int insn, int rd)
 {
     TCGv r_asi, r_size, r_sign;
 
@@ -1822,9 +1826,11 @@ static inline void gen_ldda_asi(TCGv lo, TCGv hi, TCGv addr, int insn)
     tcg_temp_free(r_sign);
     tcg_temp_free(r_size);
     tcg_temp_free(r_asi);
-    tcg_gen_trunc_i64_tl(lo, cpu_tmp64);
+    tcg_gen_trunc_i64_tl(cpu_tmp0, cpu_tmp64);
+    gen_movl_TN_reg(rd + 1, cpu_tmp0);
     tcg_gen_shri_i64(cpu_tmp64, cpu_tmp64, 32);
     tcg_gen_trunc_i64_tl(hi, cpu_tmp64);
+    gen_movl_TN_reg(rd, hi);
 }
 
 static inline void gen_stda_asi(TCGv hi, TCGv addr, int insn, int rd)
@@ -2167,6 +2173,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     goto priv_insn;
                 tcg_gen_helper_1_0(helper_rdpsr, cpu_dst);
 #else
+                CHECK_IU_FEATURE(dc, HYPV);
                 if (!hypervisor(dc))
                     goto priv_insn;
                 rs1 = GET_FIELD(insn, 13, 17);
@@ -2193,9 +2200,8 @@ static void disas_sparc_insn(DisasContext * dc)
                     tcg_gen_ext_i32_tl(cpu_dst, cpu_tmp32);
                     break;
                 case 31: // hstick_cmpr
-                    tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_dst);
-                    tcg_gen_st_i32(cpu_tmp32, cpu_env,
-                                   offsetof(CPUSPARCState, hstick_cmpr));
+                    tcg_gen_ld_tl(cpu_dst, cpu_env,
+                                  offsetof(CPUSPARCState, hstick_cmpr));
                     break;
                 default:
                     goto illegal_insn;
@@ -2318,11 +2324,13 @@ static void disas_sparc_insn(DisasContext * dc)
                     tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32);
                     break;
                 case 16: // UA2005 gl
+                    CHECK_IU_FEATURE(dc, GL);
                     tcg_gen_ld_i32(cpu_tmp32, cpu_env,
                                    offsetof(CPUSPARCState, gl));
                     tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32);
                     break;
                 case 26: // UA2005 strand status
+                    CHECK_IU_FEATURE(dc, HYPV);
                     if (!hypervisor(dc))
                         goto priv_insn;
                     tcg_gen_ld_i32(cpu_tmp32, cpu_env,
@@ -2346,6 +2354,7 @@ static void disas_sparc_insn(DisasContext * dc)
                 break;
             } else if (xop == 0x2b) { /* rdtbr / V9 flushw */
 #ifdef TARGET_SPARC64
+                save_state(dc, cpu_cond);
                 tcg_gen_helper_0_0(helper_flushw);
 #else
                 if (!supervisor(dc))
@@ -2911,20 +2920,17 @@ static void disas_sparc_insn(DisasContext * dc)
                     if (insn & (1 << 12)) {
                         tcg_gen_shli_i64(cpu_dst, cpu_src1, rs2 & 0x3f);
                     } else {
-                        tcg_gen_andi_i64(cpu_dst, cpu_src1, 0xffffffffULL);
-                        tcg_gen_shli_i64(cpu_dst, cpu_dst, rs2 & 0x1f);
+                        tcg_gen_shli_i64(cpu_dst, cpu_src1, rs2 & 0x1f);
                     }
                 } else {                /* register */
                     rs2 = GET_FIELD(insn, 27, 31);
                     gen_movl_reg_TN(rs2, cpu_src2);
                     if (insn & (1 << 12)) {
                         tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x3f);
-                        tcg_gen_shl_i64(cpu_dst, cpu_src1, cpu_tmp0);
                     } else {
                         tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x1f);
-                        tcg_gen_andi_i64(cpu_dst, cpu_src1, 0xffffffffULL);
-                        tcg_gen_shl_i64(cpu_dst, cpu_dst, cpu_tmp0);
                     }
+                    tcg_gen_shl_i64(cpu_dst, cpu_src1, cpu_tmp0);
                 }
                 gen_movl_TN_reg(rd, cpu_dst);
             } else if (xop == 0x26) { /* srl, V9 srlx */
@@ -2970,6 +2976,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     } else {
                         tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x1f);
                         tcg_gen_andi_i64(cpu_dst, cpu_src1, 0xffffffffULL);
+                        tcg_gen_ext_i32_i64(cpu_dst, cpu_dst);
                         tcg_gen_sar_i64(cpu_dst, cpu_dst, cpu_tmp0);
                     }
                 }
@@ -3423,11 +3430,13 @@ static void disas_sparc_insn(DisasContext * dc)
                                                         wstate));
                                 break;
                             case 16: // UA2005 gl
+                                CHECK_IU_FEATURE(dc, GL);
                                 tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
                                 tcg_gen_st_i32(cpu_tmp32, cpu_env,
                                                offsetof(CPUSPARCState, gl));
                                 break;
                             case 26: // UA2005 strand status
+                                CHECK_IU_FEATURE(dc, HYPV);
                                 if (!hypervisor(dc))
                                     goto priv_insn;
                                 tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
@@ -3453,6 +3462,7 @@ static void disas_sparc_insn(DisasContext * dc)
                             tcg_gen_st_tl(cpu_tmp0, cpu_env,
                                           offsetof(CPUSPARCState, tbr));
 #else
+                            CHECK_IU_FEATURE(dc, HYPV);
                             if (!hypervisor(dc))
                                 goto priv_insn;
                             tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
@@ -4198,15 +4208,15 @@ static void disas_sparc_insn(DisasContext * dc)
                 (xop > 0x2c && xop <= 0x33) || xop == 0x1f || xop == 0x3d) {
                 switch (xop) {
                 case 0x0:       /* load unsigned word */
-                    ABI32_MASK(cpu_addr);
+                    gen_address_mask(dc, cpu_addr);
                     tcg_gen_qemu_ld32u(cpu_val, cpu_addr, dc->mem_idx);
                     break;
                 case 0x1:       /* load unsigned byte */
-                    ABI32_MASK(cpu_addr);
+                    gen_address_mask(dc, cpu_addr);
                     tcg_gen_qemu_ld8u(cpu_val, cpu_addr, dc->mem_idx);
                     break;
                 case 0x2:       /* load unsigned halfword */
-                    ABI32_MASK(cpu_addr);
+                    gen_address_mask(dc, cpu_addr);
                     tcg_gen_qemu_ld16u(cpu_val, cpu_addr, dc->mem_idx);
                     break;
                 case 0x3:       /* load double word */
@@ -4220,7 +4230,7 @@ static void disas_sparc_insn(DisasContext * dc)
                         tcg_gen_helper_0_2(helper_check_align, cpu_addr,
                                            r_const); // XXX remove
                         tcg_temp_free(r_const);
-                        ABI32_MASK(cpu_addr);
+                        gen_address_mask(dc, cpu_addr);
                         tcg_gen_qemu_ld64(cpu_tmp64, cpu_addr, dc->mem_idx);
                         tcg_gen_trunc_i64_tl(cpu_tmp0, cpu_tmp64);
                         tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0xffffffffULL);
@@ -4231,18 +4241,18 @@ static void disas_sparc_insn(DisasContext * dc)
                     }
                     break;
                 case 0x9:       /* load signed byte */
-                    ABI32_MASK(cpu_addr);
+                    gen_address_mask(dc, cpu_addr);
                     tcg_gen_qemu_ld8s(cpu_val, cpu_addr, dc->mem_idx);
                     break;
                 case 0xa:       /* load signed halfword */
-                    ABI32_MASK(cpu_addr);
+                    gen_address_mask(dc, cpu_addr);
                     tcg_gen_qemu_ld16s(cpu_val, cpu_addr, dc->mem_idx);
                     break;
                 case 0xd:       /* ldstub -- XXX: should be atomically */
                     {
                         TCGv r_const;
 
-                        ABI32_MASK(cpu_addr);
+                        gen_address_mask(dc, cpu_addr);
                         tcg_gen_qemu_ld8s(cpu_val, cpu_addr, dc->mem_idx);
                         r_const = tcg_const_tl(0xff);
                         tcg_gen_qemu_st8(r_const, cpu_addr, dc->mem_idx);
@@ -4253,7 +4263,7 @@ static void disas_sparc_insn(DisasContext * dc)
                                    atomically */
                     CHECK_IU_FEATURE(dc, SWAP);
                     gen_movl_reg_TN(rd, cpu_val);
-                    ABI32_MASK(cpu_addr);
+                    gen_address_mask(dc, cpu_addr);
                     tcg_gen_qemu_ld32u(cpu_tmp32, cpu_addr, dc->mem_idx);
                     tcg_gen_qemu_st32(cpu_val, cpu_addr, dc->mem_idx);
                     tcg_gen_extu_i32_tl(cpu_val, cpu_tmp32);
@@ -4299,9 +4309,8 @@ static void disas_sparc_insn(DisasContext * dc)
                     if (rd & 1)
                         goto illegal_insn;
                     save_state(dc, cpu_cond);
-                    gen_ldda_asi(cpu_tmp0, cpu_val, cpu_addr, insn);
-                    gen_movl_TN_reg(rd + 1, cpu_tmp0);
-                    break;
+                    gen_ldda_asi(cpu_val, cpu_addr, insn, rd);
+                    goto skip_move;
                 case 0x19:      /* load signed byte alternate */
 #ifndef TARGET_SPARC64
                     if (IS_IMM)
@@ -4355,11 +4364,11 @@ static void disas_sparc_insn(DisasContext * dc)
 #endif
 #ifdef TARGET_SPARC64
                 case 0x08: /* V9 ldsw */
-                    ABI32_MASK(cpu_addr);
+                    gen_address_mask(dc, cpu_addr);
                     tcg_gen_qemu_ld32s(cpu_val, cpu_addr, dc->mem_idx);
                     break;
                 case 0x0b: /* V9 ldx */
-                    ABI32_MASK(cpu_addr);
+                    gen_address_mask(dc, cpu_addr);
                     tcg_gen_qemu_ld64(cpu_val, cpu_addr, dc->mem_idx);
                     break;
                 case 0x18: /* V9 ldswa */
@@ -4392,7 +4401,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     goto illegal_insn;
                 }
                 gen_movl_TN_reg(rd, cpu_val);
-#ifdef TARGET_SPARC64
+#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
             skip_move: ;
 #endif
             } else if (xop >= 0x20 && xop < 0x24) {
@@ -4401,13 +4410,13 @@ static void disas_sparc_insn(DisasContext * dc)
                 save_state(dc, cpu_cond);
                 switch (xop) {
                 case 0x20:      /* load fpreg */
-                    ABI32_MASK(cpu_addr);
+                    gen_address_mask(dc, cpu_addr);
                     tcg_gen_qemu_ld32u(cpu_tmp32, cpu_addr, dc->mem_idx);
                     tcg_gen_st_i32(cpu_tmp32, cpu_env,
                                    offsetof(CPUState, fpr[rd]));
                     break;
                 case 0x21:      /* load fsr */
-                    ABI32_MASK(cpu_addr);
+                    gen_address_mask(dc, cpu_addr);
                     tcg_gen_qemu_ld32u(cpu_tmp32, cpu_addr, dc->mem_idx);
                     tcg_gen_st_i32(cpu_tmp32, cpu_env,
                                    offsetof(CPUState, ft0));
@@ -4442,15 +4451,15 @@ static void disas_sparc_insn(DisasContext * dc)
                 gen_movl_reg_TN(rd, cpu_val);
                 switch (xop) {
                 case 0x4: /* store word */
-                    ABI32_MASK(cpu_addr);
+                    gen_address_mask(dc, cpu_addr);
                     tcg_gen_qemu_st32(cpu_val, cpu_addr, dc->mem_idx);
                     break;
                 case 0x5: /* store byte */
-                    ABI32_MASK(cpu_addr);
+                    gen_address_mask(dc, cpu_addr);
                     tcg_gen_qemu_st8(cpu_val, cpu_addr, dc->mem_idx);
                     break;
                 case 0x6: /* store halfword */
-                    ABI32_MASK(cpu_addr);
+                    gen_address_mask(dc, cpu_addr);
                     tcg_gen_qemu_st16(cpu_val, cpu_addr, dc->mem_idx);
                     break;
                 case 0x7: /* store double word */
@@ -4460,7 +4469,7 @@ static void disas_sparc_insn(DisasContext * dc)
                         TCGv r_low, r_const;
 
                         save_state(dc, cpu_cond);
-                        ABI32_MASK(cpu_addr);
+                        gen_address_mask(dc, cpu_addr);
                         r_const = tcg_const_i32(7);
                         tcg_gen_helper_0_2(helper_check_align, cpu_addr,
                                            r_const); // XXX remove
@@ -4521,7 +4530,7 @@ static void disas_sparc_insn(DisasContext * dc)
 #endif
 #ifdef TARGET_SPARC64
                 case 0x0e: /* V9 stx */
-                    ABI32_MASK(cpu_addr);
+                    gen_address_mask(dc, cpu_addr);
                     tcg_gen_qemu_st64(cpu_val, cpu_addr, dc->mem_idx);
                     break;
                 case 0x1e: /* V9 stxa */
@@ -4538,13 +4547,13 @@ static void disas_sparc_insn(DisasContext * dc)
                 save_state(dc, cpu_cond);
                 switch (xop) {
                 case 0x24: /* store fpreg */
-                    ABI32_MASK(cpu_addr);
+                    gen_address_mask(dc, cpu_addr);
                     tcg_gen_ld_i32(cpu_tmp32, cpu_env,
                                    offsetof(CPUState, fpr[rd]));
                     tcg_gen_qemu_st32(cpu_tmp32, cpu_addr, dc->mem_idx);
                     break;
                 case 0x25: /* stfsr, V9 stxfsr */
-                    ABI32_MASK(cpu_addr);
+                    gen_address_mask(dc, cpu_addr);
                     tcg_gen_helper_0_0(helper_stfsr);
                     tcg_gen_ld_i32(cpu_tmp32, cpu_env,
                                    offsetof(CPUState, ft0));
@@ -4713,8 +4722,8 @@ static void disas_sparc_insn(DisasContext * dc)
 #endif
 }
 
-static inline int gen_intermediate_code_internal(TranslationBlock * tb,
-                                                 int spc, CPUSPARCState *env)
+static inline void gen_intermediate_code_internal(TranslationBlock * tb,
+                                                  int spc, CPUSPARCState *env)
 {
     target_ulong pc_start, last_pc;
     uint16_t *gen_opc_end;
@@ -4738,6 +4747,9 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
 #endif
     } else
         dc->fpu_enabled = 0;
+#ifdef TARGET_SPARC64
+    dc->address_mask_32bit = env->pstate & PS_AM;
+#endif
     gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
 
     cpu_tmp0 = tcg_temp_new(TCG_TYPE_TL);
@@ -4855,17 +4867,16 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
         fprintf(logfile, "\n");
     }
 #endif
-    return 0;
 }
 
-int gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
+void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
 {
-    return gen_intermediate_code_internal(tb, 0, env);
+    gen_intermediate_code_internal(tb, 0, env);
 }
 
-int gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb)
+void gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb)
 {
-    return gen_intermediate_code_internal(tb, 1, env);
+    gen_intermediate_code_internal(tb, 1, env);
 }
 
 void gen_intermediate_code_init(CPUSPARCState *env)