All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/25] target-sparc improvements
@ 2015-12-17 20:54 Richard Henderson
  2015-12-17 20:54 ` [Qemu-devel] [PATCH 01/25] target-sparc: Mark more flags for helpers Richard Henderson
                   ` (18 more replies)
  0 siblings, 19 replies; 29+ messages in thread
From: Richard Henderson @ 2015-12-17 20:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland, aurelien

The primary focus of this patch set is to reduce the number of
helpers that modify TCG globals, and thus increase the lifetime
of those globals within each TB, and thus decrease the number
of times that tcg must spill and fill them from backing store.

This patch set is relative to the "Improve sparc register windows"
patches, which turned all of the integer registers into TCG globals.
Thus this patch set improves the effect of the previous patch set.

As a byproduct, I also implement the bulk of the interesting v9 ASIs
inline, thus exposing e.g. the little-endian loads and stores as
simple tcg operations.


r~


Richard Henderson (25):
  target-sparc: Mark more flags for helpers
  target-sparc: Remove softint as a TCG global
  target-sparc: Store mmu index in TB flags
  target-sparc: Create gen_exception
  target-sparc: Unify asi handling between 32 and 64-bit
  target-sparc: Store %asi in TB flags
  target-sparc: Introduce get_asi
  target-sparc: Pass TCGMemOp to gen_ld/st_asi
  target-sparc: Import linux/arch/sparc/include/uapi/asm/asi.h
  target-sparc: Add UA2011 defines to asi.h
  target-sparc: Use defines from asi.h
  target-sparc: Add MMU_REAL_IDX
  target-sparc: Directly implement easy ld/st asis
  target-sparc: Use QT0 to return results from ldda
  target-sparc: Introduce gen_check_align
  target-sparc: Directly implement easy ldd/std asis
  target-sparc: Fix obvious error in ASI_M_BFILL
  target-sparc: Pass TCGMemOp constants to helper_ld/st_asi
  target-sparc: Directly implement easy ldf/stf asis
  target-sparc: Directly implement block and short ldf/stf asis
  target-sparc: Remove helper_ldf_asi, helper_stf_asi
  target-sparc: Use explicit writes to cpu_fsr
  target-sparc: Use cpu_fsr in stfsr
  target-sparc: Use cpu_loop_exit_restore from
    helper_check_ieee_exceptions
  target-sparc: Elide duplicate updates to fprs

 target-sparc/asi.h         |  311 +++++++++++
 target-sparc/cpu.h         |   46 +-
 target-sparc/fop_helper.c  |  229 +++-----
 target-sparc/helper.h      |  168 +++---
 target-sparc/ldst_helper.c |  696 +++++++++++-------------
 target-sparc/mmu_helper.c  |   90 ++--
 target-sparc/translate.c   | 1264 ++++++++++++++++++++++++++++----------------
 7 files changed, 1667 insertions(+), 1137 deletions(-)
 create mode 100644 target-sparc/asi.h

-- 
2.5.0

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 01/25] target-sparc: Mark more flags for helpers
  2015-12-17 20:54 [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
@ 2015-12-17 20:54 ` Richard Henderson
  2015-12-17 20:54 ` [Qemu-devel] [PATCH 02/25] target-sparc: Remove softint as a TCG global Richard Henderson
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2015-12-17 20:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland, aurelien

Quite a few helpers do not modify tcg globals but did not so indicate.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-sparc/helper.h | 48 ++++++++++++++++++++++++------------------------
 1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 1ad23e8..336a80c 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -4,34 +4,34 @@ DEF_HELPER_2(wrpsr, void, env, tl)
 DEF_HELPER_1(rdpsr, tl, env)
 DEF_HELPER_1(power_down, void, env)
 #else
-DEF_HELPER_2(wrpil, void, env, tl)
+DEF_HELPER_FLAGS_2(wrpil, TCG_CALL_NO_RWG, void, env, tl)
 DEF_HELPER_2(wrpstate, void, env, tl)
 DEF_HELPER_1(done, void, env)
 DEF_HELPER_1(retry, void, env)
-DEF_HELPER_1(flushw, void, env)
-DEF_HELPER_1(saved, void, env)
-DEF_HELPER_1(restored, void, env)
+DEF_HELPER_FLAGS_1(flushw, TCG_CALL_NO_WG, void, env)
+DEF_HELPER_FLAGS_1(saved, TCG_CALL_NO_RWG, void, env)
+DEF_HELPER_FLAGS_1(restored, TCG_CALL_NO_RWG, void, env)
 DEF_HELPER_1(rdccr, tl, env)
 DEF_HELPER_2(wrccr, void, env, tl)
 DEF_HELPER_1(rdcwp, tl, env)
 DEF_HELPER_2(wrcwp, void, env, tl)
 DEF_HELPER_FLAGS_2(array8, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_1(popc, tl, tl)
+DEF_HELPER_FLAGS_1(popc, TCG_CALL_NO_RWG_SE, tl, tl)
 DEF_HELPER_4(ldda_asi, void, env, tl, int, int)
 DEF_HELPER_5(ldf_asi, void, env, tl, int, int, int)
-DEF_HELPER_5(stf_asi, void, env, tl, int, int, int)
-DEF_HELPER_5(casx_asi, tl, env, tl, tl, tl, i32)
+DEF_HELPER_FLAGS_5(stf_asi, TCG_CALL_NO_WG, void, env, tl, int, int, int)
+DEF_HELPER_FLAGS_5(casx_asi, TCG_CALL_NO_WG, tl, env, tl, tl, tl, i32)
 DEF_HELPER_2(set_softint, void, env, i64)
 DEF_HELPER_2(clear_softint, void, env, i64)
 DEF_HELPER_2(write_softint, void, env, i64)
-DEF_HELPER_2(tick_set_count, void, ptr, i64)
-DEF_HELPER_1(tick_get_count, i64, ptr)
-DEF_HELPER_2(tick_set_limit, void, ptr, i64)
+DEF_HELPER_FLAGS_2(tick_set_count, TCG_CALL_NO_RWG, void, ptr, i64)
+DEF_HELPER_FLAGS_1(tick_get_count, TCG_CALL_NO_RWG_SE, i64, ptr)
+DEF_HELPER_FLAGS_2(tick_set_limit, TCG_CALL_NO_RWG, void, ptr, i64)
 #endif
 #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
-DEF_HELPER_5(cas_asi, tl, env, tl, tl, tl, i32)
+DEF_HELPER_FLAGS_5(cas_asi, TCG_CALL_NO_WG, tl, env, tl, tl, tl, i32)
 #endif
-DEF_HELPER_3(check_align, void, env, tl, i32)
+DEF_HELPER_FLAGS_3(check_align, TCG_CALL_NO_WG, void, env, tl, i32)
 DEF_HELPER_1(debug, void, env)
 DEF_HELPER_1(save, void, env)
 DEF_HELPER_1(restore, void, env)
@@ -42,14 +42,14 @@ DEF_HELPER_3(sdiv_cc, tl, env, tl, tl)
 DEF_HELPER_3(taddcctv, tl, env, tl, tl)
 DEF_HELPER_3(tsubcctv, tl, env, tl, tl)
 #ifdef TARGET_SPARC64
-DEF_HELPER_3(sdivx, s64, env, s64, s64)
-DEF_HELPER_3(udivx, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(sdivx, TCG_CALL_NO_WG, s64, env, s64, s64)
+DEF_HELPER_FLAGS_3(udivx, TCG_CALL_NO_WG, i64, env, i64, i64)
 #endif
-DEF_HELPER_3(ldqf, void, env, tl, int)
-DEF_HELPER_3(stqf, void, env, tl, int)
+DEF_HELPER_FLAGS_3(ldqf, TCG_CALL_NO_WG, void, env, tl, int)
+DEF_HELPER_FLAGS_3(stqf, TCG_CALL_NO_WG, void, env, tl, int)
 #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
-DEF_HELPER_5(ld_asi, i64, env, tl, int, int, int)
-DEF_HELPER_5(st_asi, void, env, tl, i64, int, int)
+DEF_HELPER_FLAGS_5(ld_asi, TCG_CALL_NO_WG, i64, env, tl, int, int, int)
+DEF_HELPER_FLAGS_5(st_asi, TCG_CALL_NO_WG, void, env, tl, i64, int, int)
 #endif
 DEF_HELPER_2(ldfsr, void, env, i32)
 DEF_HELPER_FLAGS_1(fabss, TCG_CALL_NO_RWG_SE, f32, f32)
@@ -77,7 +77,7 @@ DEF_HELPER_3(fcmpes_fcc3, void, env, f32, f32)
 DEF_HELPER_3(fcmped_fcc1, void, env, f64, f64)
 DEF_HELPER_3(fcmped_fcc2, void, env, f64, f64)
 DEF_HELPER_3(fcmped_fcc3, void, env, f64, f64)
-DEF_HELPER_1(fabsq, void, env)
+DEF_HELPER_FLAGS_1(fabsq, TCG_CALL_NO_RWG, void, env)
 DEF_HELPER_1(fcmpq_fcc1, void, env)
 DEF_HELPER_1(fcmpq_fcc2, void, env)
 DEF_HELPER_1(fcmpq_fcc3, void, env)
@@ -106,17 +106,17 @@ DEF_HELPER_3(fsmuld, f64, env, f32, f32)
 DEF_HELPER_3(fdmulq, void, env, f64, f64)
 
 DEF_HELPER_FLAGS_1(fnegs, TCG_CALL_NO_RWG_SE, f32, f32)
-DEF_HELPER_2(fitod, f64, env, s32)
-DEF_HELPER_2(fitoq, void, env, s32)
+DEF_HELPER_FLAGS_2(fitod, TCG_CALL_NO_RWG_SE, f64, env, s32)
+DEF_HELPER_FLAGS_2(fitoq, TCG_CALL_NO_RWG, void, env, s32)
 
 DEF_HELPER_2(fitos, f32, env, s32)
 
 #ifdef TARGET_SPARC64
 DEF_HELPER_FLAGS_1(fnegd, TCG_CALL_NO_RWG_SE, f64, f64)
-DEF_HELPER_1(fnegq, void, env)
+DEF_HELPER_FLAGS_1(fnegq, TCG_CALL_NO_RWG, void, env)
 DEF_HELPER_2(fxtos, f32, env, s64)
 DEF_HELPER_2(fxtod, f64, env, s64)
-DEF_HELPER_2(fxtoq, void, env, s64)
+DEF_HELPER_FLAGS_2(fxtoq, TCG_CALL_NO_RWG, void, env, s64)
 #endif
 DEF_HELPER_2(fdtos, f32, env, f64)
 DEF_HELPER_2(fstod, f64, env, f32)
@@ -172,4 +172,4 @@ VIS_CMPHELPER(cmpne)
 #undef VIS_HELPER
 #undef VIS_CMPHELPER
 DEF_HELPER_1(compute_psr, void, env)
-DEF_HELPER_1(compute_C_icc, i32, env)
+DEF_HELPER_FLAGS_1(compute_C_icc, TCG_CALL_NO_WG_SE, i32, env)
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 02/25] target-sparc: Remove softint as a TCG global
  2015-12-17 20:54 [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
  2015-12-17 20:54 ` [Qemu-devel] [PATCH 01/25] target-sparc: Mark more flags for helpers Richard Henderson
@ 2015-12-17 20:54 ` Richard Henderson
  2015-12-17 20:54 ` [Qemu-devel] [PATCH 03/25] target-sparc: Store mmu index in TB flags Richard Henderson
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2015-12-17 20:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland, aurelien

The global is only ever read for one insn; we can just as well
use a load from env instead and generate the same code.  This
also allows us to indicate the the associated helpers do not
touch TCG globals.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-sparc/helper.h    | 6 +++---
 target-sparc/translate.c | 5 ++---
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 336a80c..5268f28 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -21,9 +21,9 @@ DEF_HELPER_4(ldda_asi, void, env, tl, int, int)
 DEF_HELPER_5(ldf_asi, void, env, tl, int, int, int)
 DEF_HELPER_FLAGS_5(stf_asi, TCG_CALL_NO_WG, void, env, tl, int, int, int)
 DEF_HELPER_FLAGS_5(casx_asi, TCG_CALL_NO_WG, tl, env, tl, tl, tl, i32)
-DEF_HELPER_2(set_softint, void, env, i64)
-DEF_HELPER_2(clear_softint, void, env, i64)
-DEF_HELPER_2(write_softint, void, env, i64)
+DEF_HELPER_FLAGS_2(set_softint, TCG_CALL_NO_RWG, void, env, i64)
+DEF_HELPER_FLAGS_2(clear_softint, TCG_CALL_NO_RWG, void, env, i64)
+DEF_HELPER_FLAGS_2(write_softint, TCG_CALL_NO_RWG, void, env, i64)
 DEF_HELPER_FLAGS_2(tick_set_count, TCG_CALL_NO_RWG, void, ptr, i64)
 DEF_HELPER_FLAGS_1(tick_get_count, TCG_CALL_NO_RWG_SE, i64, ptr)
 DEF_HELPER_FLAGS_2(tick_set_limit, TCG_CALL_NO_RWG, void, ptr, i64)
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index c818a36..e517726 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -58,7 +58,6 @@ static TCGv_i32 cpu_xcc, cpu_asi, cpu_fprs;
 static TCGv cpu_gsr;
 static TCGv cpu_tick_cmpr, cpu_stick_cmpr, cpu_hstick_cmpr;
 static TCGv cpu_hintp, cpu_htba, cpu_hver, cpu_ssr, cpu_ver;
-static TCGv_i32 cpu_softint;
 #else
 static TCGv cpu_wim;
 #endif
@@ -2737,7 +2736,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     gen_store_gpr(dc, rd, cpu_gsr);
                     break;
                 case 0x16: /* Softint */
-                    tcg_gen_ext_i32_tl(cpu_dst, cpu_softint);
+                    tcg_gen_ld32s_tl(cpu_dst, cpu_env,
+                                     offsetof(CPUSPARCState, softint));
                     gen_store_gpr(dc, rd, cpu_dst);
                     break;
                 case 0x17: /* Tick compare */
@@ -5335,7 +5335,6 @@ void gen_intermediate_code_init(CPUSPARCState *env)
         { &cpu_xcc, offsetof(CPUSPARCState, xcc), "xcc" },
         { &cpu_asi, offsetof(CPUSPARCState, asi), "asi" },
         { &cpu_fprs, offsetof(CPUSPARCState, fprs), "fprs" },
-        { &cpu_softint, offsetof(CPUSPARCState, softint), "softint" },
 #else
         { &cpu_wim, offsetof(CPUSPARCState, wim), "wim" },
 #endif
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 03/25] target-sparc: Store mmu index in TB flags
  2015-12-17 20:54 [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
  2015-12-17 20:54 ` [Qemu-devel] [PATCH 01/25] target-sparc: Mark more flags for helpers Richard Henderson
  2015-12-17 20:54 ` [Qemu-devel] [PATCH 02/25] target-sparc: Remove softint as a TCG global Richard Henderson
@ 2015-12-17 20:54 ` Richard Henderson
  2015-12-17 20:54 ` [Qemu-devel] [PATCH 04/25] target-sparc: Create gen_exception Richard Henderson
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2015-12-17 20:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland, aurelien

Doing this instead of saving the raw PS_PRIV and TL.  This means
that all nucleus mode TBs (TL > 0) can be shared.  This fixes a
bug in that we didn't include HS_PRIV in the TB flags, and so could
produce incorrect TB matches for hypervisor state.

The LSU and DMMU states were unused by the translator.  Including
them in TB flags meant unnecessary mismatches from tb_find_fast.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-sparc/cpu.h       | 26 ++++++++++++--------------
 target-sparc/translate.c |  2 +-
 2 files changed, 13 insertions(+), 15 deletions(-)

diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 9fa770b..f3ae242 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -688,34 +688,32 @@ void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit);
 trap_state* cpu_tsptr(CPUSPARCState* env);
 #endif
 
-#define TB_FLAG_FPU_ENABLED (1 << 4)
-#define TB_FLAG_AM_ENABLED (1 << 5)
+#define TB_FLAG_MMU_MASK     7
+#define TB_FLAG_FPU_ENABLED  (1 << 4)
+#define TB_FLAG_AM_ENABLED   (1 << 5)
 
 static inline void cpu_get_tb_cpu_state(CPUSPARCState *env, target_ulong *pc,
-                                        target_ulong *cs_base, int *flags)
+                                        target_ulong *cs_base, int *pflags)
 {
+    int flags;
     *pc = env->pc;
     *cs_base = env->npc;
+    flags = cpu_mmu_index(env, false);
 #ifdef TARGET_SPARC64
-    // AM . Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
-    *flags = (env->pstate & PS_PRIV)               /* 2 */
-        | ((env->lsu & (DMMU_E | IMMU_E)) >> 2)    /* 1, 0 */
-        | ((env->tl & 0xff) << 8)
-        | (env->dmmu.mmu_primary_context << 16);   /* 16... */
     if (env->pstate & PS_AM) {
-        *flags |= TB_FLAG_AM_ENABLED;
+        flags |= TB_FLAG_AM_ENABLED;
     }
-    if ((env->def->features & CPU_FEATURE_FLOAT) && (env->pstate & PS_PEF)
+    if ((env->def->features & CPU_FEATURE_FLOAT)
+        && (env->pstate & PS_PEF)
         && (env->fprs & FPRS_FEF)) {
-        *flags |= TB_FLAG_FPU_ENABLED;
+        flags |= TB_FLAG_FPU_ENABLED;
     }
 #else
-    // FPU enable . Supervisor
-    *flags = env->psrs;
     if ((env->def->features & CPU_FEATURE_FLOAT) && env->psref) {
-        *flags |= TB_FLAG_FPU_ENABLED;
+        flags |= TB_FLAG_FPU_ENABLED;
     }
 #endif
+    *pflags = flags;
 }
 
 static inline bool tb_fpu_enabled(int tb_flags)
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index e517726..a42496b 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -5220,7 +5220,7 @@ void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
     last_pc = dc->pc;
     dc->npc = (target_ulong) tb->cs_base;
     dc->cc_op = CC_OP_DYNAMIC;
-    dc->mem_idx = cpu_mmu_index(env, false);
+    dc->mem_idx = tb->flags & TB_FLAG_MMU_MASK;
     dc->def = env->def;
     dc->fpu_enabled = tb_fpu_enabled(tb->flags);
     dc->address_mask_32bit = tb_am_enabled(tb->flags);
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 04/25] target-sparc: Create gen_exception
  2015-12-17 20:54 [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
                   ` (2 preceding siblings ...)
  2015-12-17 20:54 ` [Qemu-devel] [PATCH 03/25] target-sparc: Store mmu index in TB flags Richard Henderson
@ 2015-12-17 20:54 ` Richard Henderson
  2015-12-17 20:56 ` [Qemu-devel] [PATCH 10/25] target-sparc: Add UA2011 defines to asi.h Richard Henderson
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2015-12-17 20:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland, aurelien

This unifies quite a few duplicate code fragments.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-sparc/translate.c | 75 +++++++++++++-----------------------------------
 1 file changed, 20 insertions(+), 55 deletions(-)

diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index a42496b..079d3b1 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -1034,6 +1034,17 @@ static inline void save_state(DisasContext *dc)
     save_npc(dc);
 }
 
+static void gen_exception(DisasContext *dc, int which)
+{
+    TCGv_i32 t;
+
+    save_state(dc);
+    t = tcg_const_i32(which);
+    gen_helper_raise_exception(cpu_env, t);
+    tcg_temp_free_i32(t);
+    dc->is_br = 1;
+}
+
 static inline void gen_mov_pc_npc(DisasContext *dc)
 {
     if (dc->npc == JUMP_PC) {
@@ -1624,28 +1635,18 @@ static inline void gen_op_fcmpeq(int fccno)
 }
 #endif
 
-static inline void gen_op_fpexception_im(int fsr_flags)
+static void gen_op_fpexception_im(DisasContext *dc, int fsr_flags)
 {
-    TCGv_i32 r_const;
-
     tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_NMASK);
     tcg_gen_ori_tl(cpu_fsr, cpu_fsr, fsr_flags);
-    r_const = tcg_const_i32(TT_FP_EXCP);
-    gen_helper_raise_exception(cpu_env, r_const);
-    tcg_temp_free_i32(r_const);
+    gen_exception(dc, TT_FP_EXCP);
 }
 
 static int gen_trap_ifnofpu(DisasContext *dc)
 {
 #if !defined(CONFIG_USER_ONLY)
     if (!dc->fpu_enabled) {
-        TCGv_i32 r_const;
-
-        save_state(dc);
-        r_const = tcg_const_i32(TT_NFPU_INSN);
-        gen_helper_raise_exception(cpu_env, r_const);
-        tcg_temp_free_i32(r_const);
-        dc->is_br = 1;
+        gen_exception(dc, TT_NFPU_INSN);
         return 1;
     }
 #endif
@@ -5127,63 +5128,27 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
  jmp_insn:
     goto egress;
  illegal_insn:
-    {
-        TCGv_i32 r_const;
-
-        save_state(dc);
-        r_const = tcg_const_i32(TT_ILL_INSN);
-        gen_helper_raise_exception(cpu_env, r_const);
-        tcg_temp_free_i32(r_const);
-        dc->is_br = 1;
-    }
+    gen_exception(dc, TT_ILL_INSN);
     goto egress;
  unimp_flush:
-    {
-        TCGv_i32 r_const;
-
-        save_state(dc);
-        r_const = tcg_const_i32(TT_UNIMP_FLUSH);
-        gen_helper_raise_exception(cpu_env, r_const);
-        tcg_temp_free_i32(r_const);
-        dc->is_br = 1;
-    }
+    gen_exception(dc, TT_UNIMP_FLUSH);
     goto egress;
 #if !defined(CONFIG_USER_ONLY)
  priv_insn:
-    {
-        TCGv_i32 r_const;
-
-        save_state(dc);
-        r_const = tcg_const_i32(TT_PRIV_INSN);
-        gen_helper_raise_exception(cpu_env, r_const);
-        tcg_temp_free_i32(r_const);
-        dc->is_br = 1;
-    }
+    gen_exception(dc, TT_PRIV_INSN);
     goto egress;
 #endif
  nfpu_insn:
-    save_state(dc);
-    gen_op_fpexception_im(FSR_FTT_UNIMPFPOP);
-    dc->is_br = 1;
+    gen_op_fpexception_im(dc, FSR_FTT_UNIMPFPOP);
     goto egress;
 #if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64)
  nfq_insn:
-    save_state(dc);
-    gen_op_fpexception_im(FSR_FTT_SEQ_ERROR);
-    dc->is_br = 1;
+    gen_op_fpexception_im(dc, FSR_FTT_SEQ_ERROR);
     goto egress;
 #endif
 #ifndef TARGET_SPARC64
  ncp_insn:
-    {
-        TCGv r_const;
-
-        save_state(dc);
-        r_const = tcg_const_i32(TT_NCP_INSN);
-        gen_helper_raise_exception(cpu_env, r_const);
-        tcg_temp_free(r_const);
-        dc->is_br = 1;
-    }
+    gen_exception(dc, TT_NCP_INSN);
     goto egress;
 #endif
  egress:
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 10/25] target-sparc: Add UA2011 defines to asi.h
  2015-12-17 20:54 [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
                   ` (3 preceding siblings ...)
  2015-12-17 20:54 ` [Qemu-devel] [PATCH 04/25] target-sparc: Create gen_exception Richard Henderson
@ 2015-12-17 20:56 ` Richard Henderson
  2016-01-12 13:17   ` Artyom Tarasenko
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 12/25] target-sparc: Add MMU_REAL_IDX Richard Henderson
                   ` (13 subsequent siblings)
  18 siblings, 1 reply; 29+ messages in thread
From: Richard Henderson @ 2015-12-17 20:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland, aurelien

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-sparc/asi.h | 22 ++++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/target-sparc/asi.h b/target-sparc/asi.h
index aace6f3..c9a1849 100644
--- a/target-sparc/asi.h
+++ b/target-sparc/asi.h
@@ -144,24 +144,36 @@
  * ASIs, "(4V)" designates SUN4V specific ASIs.  "(NG4)" designates SPARC-T4
  * and later ASIs.
  */
+#define ASI_REAL                0x14 /* Real address, cachable          */
 #define ASI_PHYS_USE_EC		0x14 /* PADDR, E-cachable		*/
+#define ASI_REAL_IO             0x15 /* Real address, non-cachable      */
 #define ASI_PHYS_BYPASS_EC_E	0x15 /* PADDR, E-bit			*/
 #define ASI_BLK_AIUP_4V		0x16 /* (4V) Prim, user, block ld/st	*/
 #define ASI_BLK_AIUS_4V		0x17 /* (4V) Sec, user, block ld/st	*/
+#define ASI_REAL_L              0x1c /* Real address, cachable, LE      */
 #define ASI_PHYS_USE_EC_L	0x1c /* PADDR, E-cachable, little endian*/
+#define ASI_REAL_IO_L           0x1d /* Real address, non-cachable, LE  */
 #define ASI_PHYS_BYPASS_EC_E_L	0x1d /* PADDR, E-bit, little endian	*/
 #define ASI_BLK_AIUP_L_4V	0x1e /* (4V) Prim, user, block, l-endian*/
 #define ASI_BLK_AIUS_L_4V	0x1f /* (4V) Sec, user, block, l-endian	*/
 #define ASI_SCRATCHPAD		0x20 /* (4V) Scratch Pad Registers	*/
 #define ASI_MMU			0x21 /* (4V) MMU Context Registers	*/
+#define ASI_TWINX_AIUP          0x22 /* twin load, primary user         */
+#define ASI_TWINX_AIUS          0x23 /* twin load, secondary user       */
 #define ASI_BLK_INIT_QUAD_LDD_AIUS 0x23 /* (NG) init-store, twin load,
 					 * secondary, user
 					 */
 #define ASI_NUCLEUS_QUAD_LDD	0x24 /* Cachable, qword load		*/
 #define ASI_QUEUE		0x25 /* (4V) Interrupt Queue Registers	*/
+#define ASI_TWINX_REAL          0x26 /* twin load, real, cachable       */
 #define ASI_QUAD_LDD_PHYS_4V	0x26 /* (4V) Physical, qword load	*/
+#define ASI_TWINX_N             0x27 /* twin load, nucleus              */
+#define ASI_TWINX_AIUP_L        0x2a /* twin load, primary user, LE     */
+#define ASI_TWINX_AIUS_L        0x2b /* twin load, secondary user, LE   */
 #define ASI_NUCLEUS_QUAD_LDD_L	0x2c /* Cachable, qword load, l-endian 	*/
+#define ASI_TWINX_REAL_L        0x2e /* twin load, real, cachable, LE   */
 #define ASI_QUAD_LDD_PHYS_L_4V	0x2e /* (4V) Phys, qword load, l-endian	*/
+#define ASI_TWINX_NL            0x2f /* twin load, nucleus, LE          */
 #define ASI_PCACHE_DATA_STATUS	0x30 /* (III) PCache data stat RAM diag	*/
 #define ASI_PCACHE_DATA		0x31 /* (III) PCache data RAM diag	*/
 #define ASI_PCACHE_TAG		0x32 /* (III) PCache tag RAM diag	*/
@@ -267,12 +279,14 @@
 #define ASI_FL16_SL		0xdb /* Secondary, 1 16-bit, fpu ld/st,L*/
 #define ASI_BLK_COMMIT_P	0xe0 /* Primary, blk store commit	*/
 #define ASI_BLK_COMMIT_S	0xe1 /* Secondary, blk store commit	*/
+#define ASI_TWINX_P             0xe2 /* twin load, primary implicit     */
 #define ASI_BLK_INIT_QUAD_LDD_P	0xe2 /* (NG) init-store, twin load,
-				      * primary, implicit
-				      */
+				      * primary, implicit */
+#define ASI_TWINX_S             0xe3 /* twin load, secondary implicit   */
 #define ASI_BLK_INIT_QUAD_LDD_S	0xe3 /* (NG) init-store, twin load,
-				      * secondary, implicit
-				      */
+				      * secondary, implicit */
+#define ASI_TWINX_PL            0xea /* twin load, primary implicit, LE */
+#define ASI_TWINX_SL            0xeb /* twin load, secondary implicit, LE */
 #define ASI_BLK_P		0xf0 /* Primary, blk ld/st		*/
 #define ASI_BLK_S		0xf1 /* Secondary, blk ld/st		*/
 #define ASI_ST_BLKINIT_MRU_P	0xf2 /* (NG4) init-store, twin load,
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 12/25] target-sparc: Add MMU_REAL_IDX
  2015-12-17 20:54 [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
                   ` (4 preceding siblings ...)
  2015-12-17 20:56 ` [Qemu-devel] [PATCH 10/25] target-sparc: Add UA2011 defines to asi.h Richard Henderson
@ 2015-12-17 20:57 ` Richard Henderson
  2016-01-11 11:15   ` Artyom Tarasenko
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 14/25] target-sparc: Use QT0 to return results from ldda Richard Henderson
                   ` (12 subsequent siblings)
  18 siblings, 1 reply; 29+ messages in thread
From: Richard Henderson @ 2015-12-17 20:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland, aurelien

This gives us a trivial way to access physical addresses
(aka "real addresses", in sun4v terminology) directly from
qemu_ld/st, without having to go through another helper.

This also fixes a bug in get_physical_address_code where
it inferred NUCLEUS from env->tl instead of from mmu_idx.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-sparc/cpu.h        | 18 +++++++---
 target-sparc/mmu_helper.c | 90 +++++++++++++++++++++++++++++------------------
 2 files changed, 69 insertions(+), 39 deletions(-)

diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 7f4d47f..b1222a1 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -220,9 +220,9 @@ enum {
 #define MAX_NWINDOWS 32
 
 #if !defined(TARGET_SPARC64)
-#define NB_MMU_MODES 2
+#define NB_MMU_MODES 3
 #else
-#define NB_MMU_MODES 6
+#define NB_MMU_MODES 7
 typedef struct trap_state {
     uint64_t tpc;
     uint64_t tnpc;
@@ -612,11 +612,13 @@ int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
 #define MMU_MODE4_SUFFIX _nucleus
 #define MMU_HYPV_IDX   5
 #define MMU_MODE5_SUFFIX _hypv
+#define MMU_REAL_IDX   6
 #else
 #define MMU_USER_IDX   0
 #define MMU_MODE0_SUFFIX _user
 #define MMU_KERNEL_IDX 1
 #define MMU_MODE1_SUFFIX _kernel
+#define MMU_REAL_IDX   2
 #endif
 
 #if defined (TARGET_SPARC64)
@@ -641,9 +643,17 @@ static inline int cpu_mmu_index(CPUSPARCState *env1, bool ifetch)
 #if defined(CONFIG_USER_ONLY)
     return MMU_USER_IDX;
 #elif !defined(TARGET_SPARC64)
-    return env1->psrs;
+    if (!(env1->mmuregs[0] & MMU_E)) {
+        return MMU_REAL_IDX; /* MMU disabled */
+    } else {
+        return env1->psrs;
+    }
 #else
-    if (env1->tl > 0) {
+    if (ifetch
+        ? !(env1->lsu & IMMU_E) || (env1->pstate & PS_RED)
+        : !(env1->lsu & DMMU_E)) {
+        return MMU_REAL_IDX; /* MMU disabled */
+    } else if (env1->tl > 0) {
         return MMU_NUCLEUS_IDX;
     } else if (cpu_hypervisor_mode(env1)) {
         return MMU_HYPV_IDX;
diff --git a/target-sparc/mmu_helper.c b/target-sparc/mmu_helper.c
index 7495406..105f00d 100644
--- a/target-sparc/mmu_helper.c
+++ b/target-sparc/mmu_helper.c
@@ -90,7 +90,7 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
 
     is_user = mmu_idx == MMU_USER_IDX;
 
-    if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
+    if (mmu_idx == MMU_REAL_IDX) { /* MMU bypass access */
         *page_size = TARGET_PAGE_SIZE;
         /* Boot mode: instruction fetches are taken from PROM */
         if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
@@ -492,33 +492,40 @@ static int get_physical_address_data(CPUSPARCState *env,
     unsigned int i;
     uint64_t context;
     uint64_t sfsr = 0;
+    bool is_user = false;
 
-    int is_user = (mmu_idx == MMU_USER_IDX ||
-                   mmu_idx == MMU_USER_SECONDARY_IDX);
-
-    if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
+    switch (mmu_idx) {
+    case MMU_REAL_IDX:
+        /* MMU bypass access */
         *physical = ultrasparc_truncate_physical(address);
-        *prot = PAGE_READ | PAGE_WRITE;
+        *prot = PAGE_EXEC | PAGE_READ | PAGE_WRITE;
         return 0;
-    }
 
-    switch (mmu_idx) {
+    case MMU_NUCLEUS_IDX:
+        sfsr |= SFSR_CT_NUCLEUS;
+        /* fallthru */
+    case MMU_HYPV_IDX:
+        /* No context. */
+        context = 0;
+        break;
     case MMU_USER_IDX:
+        is_user = true;
+        /* fallthru */
     case MMU_KERNEL_IDX:
+        /* PRIMARY context */
         context = env->dmmu.mmu_primary_context & 0x1fff;
         sfsr |= SFSR_CT_PRIMARY;
         break;
     case MMU_USER_SECONDARY_IDX:
+        is_user = true;
+        /* fallthru */
     case MMU_KERNEL_SECONDARY_IDX:
+        /* PRIMARY context */
         context = env->dmmu.mmu_secondary_context & 0x1fff;
         sfsr |= SFSR_CT_SECONDARY;
         break;
-    case MMU_NUCLEUS_IDX:
-        sfsr |= SFSR_CT_NUCLEUS;
-        /* FALLTHRU */
     default:
-        context = 0;
-        break;
+        g_assert_not_reached();
     }
 
     if (rw == 1) {
@@ -573,8 +580,8 @@ static int get_physical_address_data(CPUSPARCState *env,
             }
 
             if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
-                sfsr |= SFSR_OW_BIT; /* overflow (not read before
-                                        another fault) */
+                /* overflow (not read before another fault) */
+                sfsr |= SFSR_OW_BIT;
             }
 
             if (env->pstate & PS_PRIV) {
@@ -611,23 +618,41 @@ static int get_physical_address_code(CPUSPARCState *env,
     CPUState *cs = CPU(sparc_env_get_cpu(env));
     unsigned int i;
     uint64_t context;
+    uint64_t sfsr = 0;
+    bool is_user = false;
 
-    int is_user = (mmu_idx == MMU_USER_IDX ||
-                   mmu_idx == MMU_USER_SECONDARY_IDX);
-
-    if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
-        /* IMMU disabled */
+    switch (mmu_idx) {
+    case MMU_REAL_IDX:
+        /* MMU bypass access */
         *physical = ultrasparc_truncate_physical(address);
-        *prot = PAGE_EXEC;
+        *prot = PAGE_EXEC | PAGE_READ | PAGE_WRITE;
         return 0;
-    }
 
-    if (env->tl == 0) {
+    case MMU_NUCLEUS_IDX:
+        sfsr |= SFSR_CT_NUCLEUS;
+        /* fallthru */
+    case MMU_HYPV_IDX:
+        /* No context. */
+        context = 0;
+        break;
+    case MMU_USER_IDX:
+        is_user = true;
+        /* fallthru */
+    case MMU_KERNEL_IDX:
         /* PRIMARY context */
         context = env->dmmu.mmu_primary_context & 0x1fff;
-    } else {
-        /* NUCLEUS context */
-        context = 0;
+        sfsr |= SFSR_CT_PRIMARY;
+        break;
+    case MMU_USER_SECONDARY_IDX:
+        is_user = true;
+        /* fallthru */
+    case MMU_KERNEL_SECONDARY_IDX:
+        /* PRIMARY context */
+        context = env->dmmu.mmu_secondary_context & 0x1fff;
+        sfsr |= SFSR_CT_SECONDARY;
+        break;
+    default:
+        g_assert_not_reached();
     }
 
     for (i = 0; i < 64; i++) {
@@ -638,20 +663,15 @@ static int get_physical_address_code(CPUSPARCState *env,
             if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
                 /* Fault status register */
                 if (env->immu.sfsr & SFSR_VALID_BIT) {
-                    env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
-                                                     another fault) */
-                } else {
-                    env->immu.sfsr = 0;
+                    /* overflow (not read before another fault) */
+                    sfsr |= SFSR_OW_BIT;
                 }
                 if (env->pstate & PS_PRIV) {
-                    env->immu.sfsr |= SFSR_PR_BIT;
-                }
-                if (env->tl > 0) {
-                    env->immu.sfsr |= SFSR_CT_NUCLEUS;
+                    sfsr |= SFSR_PR_BIT;
                 }
 
                 /* FIXME: ASI field in SFSR must be set */
-                env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
+                env->immu.sfsr |= sfsr | SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
                 cs->exception_index = TT_TFAULT;
 
                 env->immu.tag_access = (address & ~0x1fffULL) | context;
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 14/25] target-sparc: Use QT0 to return results from ldda
  2015-12-17 20:54 [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
                   ` (5 preceding siblings ...)
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 12/25] target-sparc: Add MMU_REAL_IDX Richard Henderson
@ 2015-12-17 20:57 ` Richard Henderson
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 15/25] target-sparc: Introduce gen_check_align Richard Henderson
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2015-12-17 20:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland, aurelien

Also implement a few more twinx asis.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-sparc/helper.h      |   2 +-
 target-sparc/ldst_helper.c | 156 ++++++++++++++++++++++++++++++++-------------
 target-sparc/translate.c   |  12 +++-
 3 files changed, 120 insertions(+), 50 deletions(-)

diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 5268f28..6a47442 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -17,7 +17,7 @@ DEF_HELPER_1(rdcwp, tl, env)
 DEF_HELPER_2(wrcwp, void, env, tl)
 DEF_HELPER_FLAGS_2(array8, TCG_CALL_NO_RWG_SE, tl, tl, tl)
 DEF_HELPER_FLAGS_1(popc, TCG_CALL_NO_RWG_SE, tl, tl)
-DEF_HELPER_4(ldda_asi, void, env, tl, int, int)
+DEF_HELPER_FLAGS_3(ldda_asi, TCG_CALL_NO_WG, void, env, tl, int)
 DEF_HELPER_5(ldf_asi, void, env, tl, int, int, int)
 DEF_HELPER_FLAGS_5(stf_asi, TCG_CALL_NO_WG, void, env, tl, int, int, int)
 DEF_HELPER_FLAGS_5(casx_asi, TCG_CALL_NO_WG, tl, env, tl, tl, tl, i32)
diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
index 89594e40..9179eaa 100644
--- a/target-sparc/ldst_helper.c
+++ b/target-sparc/ldst_helper.c
@@ -1327,8 +1327,6 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
     case ASI_S:  /* Secondary */
     case ASI_PL: /* Primary LE */
     case ASI_SL: /* Secondary LE */
-    case ASI_BLK_INIT_QUAD_LDD_P: /* UA2007 Primary block init */
-    case ASI_BLK_INIT_QUAD_LDD_S: /* UA2007 Secondary block init */
         if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
             if (cpu_hypervisor_mode(env)) {
                 switch (size) {
@@ -1441,11 +1439,6 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
             }
             break;
         }
-    case ASI_NUCLEUS_QUAD_LDD:   /* Nucleus quad LDD 128 bit atomic */
-    case ASI_NUCLEUS_QUAD_LDD_L: /* Nucleus quad LDD 128 bit atomic LE */
-        /* Only ldda allowed */
-        helper_raise_exception(env, TT_ILL_INSN);
-        return 0;
     case ASI_N:  /* Nucleus */
     case ASI_NL: /* Nucleus Little Endian (LE) */
         {
@@ -1593,6 +1586,25 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
         cpu_unassigned_access(cs, addr, false, false, 1, size);
         ret = 0;
         break;
+
+    case ASI_NUCLEUS_QUAD_LDD:   /* Nucleus quad LDD 128 bit atomic */
+    case ASI_NUCLEUS_QUAD_LDD_L: /* Nucleus quad LDD 128 bit atomic LE */
+    case ASI_TWINX_AIUP:   /* As if user primary, twinx */
+    case ASI_TWINX_AIUS:   /* As if user secondary, twinx */
+    case ASI_TWINX_REAL:   /* Real address, twinx */
+    case ASI_TWINX_AIUP_L: /* As if user primary, twinx, LE */
+    case ASI_TWINX_AIUS_L: /* As if user secondary, twinx, LE */
+    case ASI_TWINX_REAL_L: /* Real address, twinx, LE */
+    case ASI_TWINX_N:  /* Nucleus, twinx */
+    case ASI_TWINX_NL: /* Nucleus, twinx, LE */
+    /* ??? From the UA2011 document; overlaps BLK_INIT_QUAD_LDD_* */
+    case ASI_TWINX_P:  /* Primary, twinx */
+    case ASI_TWINX_PL: /* Primary, twinx, LE */
+    case ASI_TWINX_S:  /* Secondary, twinx */
+    case ASI_TWINX_SL: /* Secondary, twinx, LE */
+        /* These are all 128-bit atomic; only ldda (now ldtxa) allowed */
+        helper_raise_exception(env, TT_ILL_INSN);
+        return 0;
     }
 
     /* Convert from little endian */
@@ -1700,8 +1712,6 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
     case ASI_S:  /* Secondary */
     case ASI_PL: /* Primary LE */
     case ASI_SL: /* Secondary LE */
-    case ASI_BLK_INIT_QUAD_LDD_P: /* UA2007 Primary block init */
-    case ASI_BLK_INIT_QUAD_LDD_S: /* UA2007 Secondary block init */
         if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
             if (cpu_hypervisor_mode(env)) {
                 switch (size) {
@@ -1814,11 +1824,6 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
             }
         }
         return;
-    case ASI_NUCLEUS_QUAD_LDD:   /* Nucleus quad LDD 128 bit atomic */
-    case ASI_NUCLEUS_QUAD_LDD_L: /* Nucleus quad LDD 128 bit atomic LE */
-        /* Only ldda allowed */
-        helper_raise_exception(env, TT_ILL_INSN);
-        return;
     case ASI_N:  /* Nucleus */
     case ASI_NL: /* Nucleus Little Endian (LE) */
         {
@@ -1999,6 +2004,24 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
     case ASI_INTR_RECEIVE: /* Interrupt data receive */
         env->ivec_status = val & 0x20;
         return;
+    case ASI_NUCLEUS_QUAD_LDD:   /* Nucleus quad LDD 128 bit atomic */
+    case ASI_NUCLEUS_QUAD_LDD_L: /* Nucleus quad LDD 128 bit atomic LE */
+    case ASI_TWINX_AIUP:   /* As if user primary, twinx */
+    case ASI_TWINX_AIUS:   /* As if user secondary, twinx */
+    case ASI_TWINX_REAL:   /* Real address, twinx */
+    case ASI_TWINX_AIUP_L: /* As if user primary, twinx, LE */
+    case ASI_TWINX_AIUS_L: /* As if user secondary, twinx, LE */
+    case ASI_TWINX_REAL_L: /* Real address, twinx, LE */
+    case ASI_TWINX_N:  /* Nucleus, twinx */
+    case ASI_TWINX_NL: /* Nucleus, twinx, LE */
+    /* ??? From the UA2011 document; overlaps BLK_INIT_QUAD_LDD_* */
+    case ASI_TWINX_P:  /* Primary, twinx */
+    case ASI_TWINX_PL: /* Primary, twinx, LE */
+    case ASI_TWINX_S:  /* Secondary, twinx */
+    case ASI_TWINX_SL: /* Secondary, twinx, LE */
+        /* Only stda allowed */
+        helper_raise_exception(env, TT_ILL_INSN);
+        return;
     case ASI_DCACHE_DATA: /* D-cache data */
     case ASI_DCACHE_TAG: /* D-cache tag access */
     case ASI_ESTATE_ERROR_EN: /* E-cache error enable */
@@ -2032,8 +2055,11 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
 }
 #endif /* CONFIG_USER_ONLY */
 
-void helper_ldda_asi(CPUSPARCState *env, target_ulong addr, int asi, int rd)
+/* 128-bit LDDA; result returned in QT0.  */
+void helper_ldda_asi(CPUSPARCState *env, target_ulong addr, int asi)
 {
+    uint64_t h, l;
+
     if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
         || (cpu_has_hypervisor(env)
             && asi >= 0x30 && asi < 0x80
@@ -2045,44 +2071,82 @@ void helper_ldda_asi(CPUSPARCState *env, target_ulong addr, int asi, int rd)
 
     switch (asi) {
 #if !defined(CONFIG_USER_ONLY)
-    case ASI_NUCLEUS_QUAD_LDD: /* Nucleus quad LDD 128 bit atomic */
-    case ASI_NUCLEUS_QUAD_LDD_L: /* Nucleus quad LDD 128 bit atomic LE */
+    case ASI_TWINX_AIUP:   /* As if user primary, twinx */
+    case ASI_TWINX_AIUP_L: /* As if user primary, twinx, LE */
         helper_check_align(env, addr, 0xf);
-        if (rd == 0) {
-            env->gregs[1] = cpu_ldq_nucleus(env, addr + 8);
-            if (asi == ASI_NUCLEUS_QUAD_LDD_L) {
-                bswap64s(&env->gregs[1]);
-            }
-        } else if (rd < 8) {
-            env->gregs[rd] = cpu_ldq_nucleus(env, addr);
-            env->gregs[rd + 1] = cpu_ldq_nucleus(env, addr + 8);
-            if (asi == ASI_NUCLEUS_QUAD_LDD_L) {
-                bswap64s(&env->gregs[rd]);
-                bswap64s(&env->gregs[rd + 1]);
-            }
-        } else {
-            env->regwptr[rd] = cpu_ldq_nucleus(env, addr);
-            env->regwptr[rd + 1] = cpu_ldq_nucleus(env, addr + 8);
-            if (asi == ASI_NUCLEUS_QUAD_LDD_L) {
-                bswap64s(&env->regwptr[rd]);
-                bswap64s(&env->regwptr[rd + 1]);
+        h = cpu_ldq_user(env, addr);
+        l = cpu_ldq_user(env, addr + 8);
+        break;
+    case ASI_TWINX_AIUS:   /* As if user secondary, twinx */
+    case ASI_TWINX_AIUS_L: /* As if user secondary, twinx, LE */
+        helper_check_align(env, addr, 0xf);
+        h = cpu_ldq_user_secondary(env, addr);
+        l = cpu_ldq_user_secondary(env, addr + 8);
+        break;
+    case ASI_TWINX_REAL:   /* Real address, twinx */
+    case ASI_TWINX_REAL_L: /* Real address, twinx, LE */
+        helper_check_align(env, addr, 0xf);
+        {
+            CPUState *cs = CPU(sparc_env_get_cpu(env));
+            h = ldq_phys(cs->as, addr);
+            l = ldq_phys(cs->as, addr + 8);
+        }
+        break;
+    case ASI_NUCLEUS_QUAD_LDD:
+    case ASI_NUCLEUS_QUAD_LDD_L:
+    case ASI_TWINX_N:  /* Nucleus, twinx */
+    case ASI_TWINX_NL: /* Nucleus, twinx, LE */
+        helper_check_align(env, addr, 0xf);
+        h = cpu_ldq_nucleus(env, addr);
+        l = cpu_ldq_nucleus(env, addr + 8);
+        break;
+    case ASI_TWINX_S: /* Secondary, twinx */
+    case ASI_TWINX_SL: /* Secondary, twinx, LE */
+        if (!cpu_hypervisor_mode(env)) {
+            helper_check_align(env, addr, 0xf);
+            if (env->pstate & PS_PRIV) {
+                h = cpu_ldq_kernel_secondary(env, addr);
+                l = cpu_ldq_kernel_secondary(env, addr + 8);
+            } else {
+                h = cpu_ldq_user_secondary(env, addr);
+                l = cpu_ldq_user_secondary(env, addr + 8);
             }
+            break;
         }
+        /* fallthru */
+    case ASI_TWINX_P:  /* Primary, twinx */
+    case ASI_TWINX_PL: /* Primary, twinx, LE */
+        helper_check_align(env, addr, 0xf);
+        h = cpu_ldq_data(env, addr);
+        l = cpu_ldq_data(env, addr + 8);
         break;
+#else
+    case ASI_TWINX_P:  /* Primary, twinx */
+    case ASI_TWINX_PL: /* Primary, twinx, LE */
+    case ASI_TWINX_S:  /* Primary, twinx */
+    case ASI_TWINX_SL: /* Primary, twinx, LE */
+        /* ??? Should be available, but we need to implement
+           an atomic 128-bit load.  */
+        helper_raise_exception(env, TT_PRIV_ACT);
 #endif
     default:
-        helper_check_align(env, addr, 0x3);
-        if (rd == 0) {
-            env->gregs[1] = helper_ld_asi(env, addr + 4, asi, 4, 0);
-        } else if (rd < 8) {
-            env->gregs[rd] = helper_ld_asi(env, addr, asi, 4, 0);
-            env->gregs[rd + 1] = helper_ld_asi(env, addr + 4, asi, 4, 0);
-        } else {
-            env->regwptr[rd] = helper_ld_asi(env, addr, asi, 4, 0);
-            env->regwptr[rd + 1] = helper_ld_asi(env, addr + 4, asi, 4, 0);
-        }
-        break;
+        /* Non-twinx asi, so this is the legacy ldda insn, which
+           performs two word sized operations.  */
+        /* ??? The UA2011 manual recommends emulating this with
+           a single 64-bit load.  However, LE asis *are* treated
+           as two 32-bit loads individually byte swapped.  */
+        helper_check_align(env, addr, 0x7);
+        QT0.high = (uint32_t)helper_ld_asi(env, addr, asi, 4, 0);
+        QT0.low = (uint32_t)helper_ld_asi(env, addr + 4, asi, 4, 0);
+        return;
+    }
+
+    if (asi & 8) {
+        h = bswap64(h);
+        l = bswap64(l);
     }
+    QT0.high = h;
+    QT0.low = l;
 }
 
 void helper_ldf_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 059dc3c..18e249b 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -2311,12 +2311,18 @@ static void gen_ldda_asi(DisasContext *dc, TCGv hi, TCGv addr,
     default:
         {
             TCGv_i32 r_asi = tcg_const_i32(da.asi);
-            TCGv_i32 r_rd = tcg_const_i32(rd);
+            TCGv_i64 tmp;
 
             save_state(dc);
-            gen_helper_ldda_asi(cpu_env, addr, r_asi, r_rd);
-            tcg_temp_free_i32(r_rd);
+            gen_helper_ldda_asi(cpu_env, addr, r_asi);
             tcg_temp_free_i32(r_asi);
+
+            tmp = gen_dest_gpr(dc, rd);
+            tcg_gen_ld_i64(tmp, cpu_env, offsetof(CPUSPARCState, qt0.high));
+            gen_store_gpr(dc, rd, tmp);
+            tmp = gen_dest_gpr(dc, rd + 1);
+            tcg_gen_ld_i64(tmp, cpu_env, offsetof(CPUSPARCState, qt0.low));
+            gen_store_gpr(dc, rd + 1, tmp);
         }
         break;
     }
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 15/25] target-sparc: Introduce gen_check_align
  2015-12-17 20:54 [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
                   ` (6 preceding siblings ...)
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 14/25] target-sparc: Use QT0 to return results from ldda Richard Henderson
@ 2015-12-17 20:57 ` Richard Henderson
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 17/25] target-sparc: Fix obvious error in ASI_M_BFILL Richard Henderson
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2015-12-17 20:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland, aurelien

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-sparc/translate.c | 48 +++++++++++++-----------------------------------
 1 file changed, 13 insertions(+), 35 deletions(-)

diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 18e249b..01559bd 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -1049,6 +1049,13 @@ static void gen_exception(DisasContext *dc, int which)
     dc->is_br = 1;
 }
 
+static void gen_check_align(TCGv addr, int mask)
+{
+    TCGv_i32 r_mask = tcg_const_i32(mask);
+    gen_helper_check_align(cpu_env, addr, r_mask);
+    tcg_temp_free_i32(r_mask);
+}
+
 static inline void gen_mov_pc_npc(DisasContext *dc)
 {
     if (dc->npc == JUMP_PC) {
@@ -4684,8 +4691,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
 #endif
 #ifdef TARGET_SPARC64
             } else if (xop == 0x39) { /* V9 return */
-                TCGv_i32 r_const;
-
                 save_state(dc);
                 cpu_src1 = get_src1(dc, insn);
                 cpu_tmp0 = get_temp_tl(dc);
@@ -4703,9 +4708,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                 }
                 gen_helper_restore(cpu_env);
                 gen_mov_pc_npc(dc);
-                r_const = tcg_const_i32(3);
-                gen_helper_check_align(cpu_env, cpu_tmp0, r_const);
-                tcg_temp_free_i32(r_const);
+                gen_check_align(cpu_tmp0, 3);
                 tcg_gen_mov_tl(cpu_npc, cpu_tmp0);
                 dc->npc = DYNAMIC_PC;
                 goto jmp_insn;
@@ -4728,16 +4731,12 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                 switch (xop) {
                 case 0x38:      /* jmpl */
                     {
-                        TCGv t;
-                        TCGv_i32 r_const;
-
-                        t = gen_dest_gpr(dc, rd);
+                        TCGv t = gen_dest_gpr(dc, rd);
                         tcg_gen_movi_tl(t, dc->pc);
                         gen_store_gpr(dc, rd, t);
+
                         gen_mov_pc_npc(dc);
-                        r_const = tcg_const_i32(3);
-                        gen_helper_check_align(cpu_env, cpu_tmp0, r_const);
-                        tcg_temp_free_i32(r_const);
+                        gen_check_align(cpu_tmp0, 3);
                         gen_address_mask(dc, cpu_tmp0);
                         tcg_gen_mov_tl(cpu_npc, cpu_tmp0);
                         dc->npc = DYNAMIC_PC;
@@ -4746,14 +4745,10 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
 #if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64)
                 case 0x39:      /* rett, V9 return */
                     {
-                        TCGv_i32 r_const;
-
                         if (!supervisor(dc))
                             goto priv_insn;
                         gen_mov_pc_npc(dc);
-                        r_const = tcg_const_i32(3);
-                        gen_helper_check_align(cpu_env, cpu_tmp0, r_const);
-                        tcg_temp_free_i32(r_const);
+                        gen_check_align(cpu_tmp0, 3);
                         tcg_gen_mov_tl(cpu_npc, cpu_tmp0);
                         dc->npc = DYNAMIC_PC;
                         gen_helper_rett(cpu_env);
@@ -4849,14 +4844,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     if (rd & 1)
                         goto illegal_insn;
                     else {
-                        TCGv_i32 r_const;
                         TCGv_i64 t64;
 
-                        save_state(dc);
-                        r_const = tcg_const_i32(7);
-                        /* XXX remove alignment check */
-                        gen_helper_check_align(cpu_env, cpu_addr, r_const);
-                        tcg_temp_free_i32(r_const);
                         gen_address_mask(dc, cpu_addr);
                         t64 = tcg_temp_new_i64();
                         tcg_gen_qemu_ld64(t64, cpu_addr, dc->mem_idx);
@@ -5064,18 +5053,11 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     if (rd & 1)
                         goto illegal_insn;
                     else {
-                        TCGv_i32 r_const;
                         TCGv_i64 t64;
                         TCGv lo;
 
-                        save_state(dc);
                         gen_address_mask(dc, cpu_addr);
-                        r_const = tcg_const_i32(7);
-                        /* XXX remove alignment check */
-                        gen_helper_check_align(cpu_env, cpu_addr, r_const);
-                        tcg_temp_free_i32(r_const);
                         lo = gen_load_gpr(dc, rd + 1);
-
                         t64 = tcg_temp_new_i64();
                         tcg_gen_concat_tl_i64(t64, lo, cpu_val);
                         tcg_gen_qemu_st64(t64, cpu_addr, dc->mem_idx);
@@ -5188,15 +5170,11 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     break;
                 case 0x36: /* V9 stqfa */
                     {
-                        TCGv_i32 r_const;
-
                         CHECK_FPU_FEATURE(dc, FLOAT128);
                         if (gen_trap_ifnofpu(dc)) {
                             goto jmp_insn;
                         }
-                        r_const = tcg_const_i32(7);
-                        gen_helper_check_align(cpu_env, cpu_addr, r_const);
-                        tcg_temp_free_i32(r_const);
+                        gen_check_align(cpu_addr, 7);
                         gen_stf_asi(dc, cpu_addr, insn, 16, QFPREG(rd));
                     }
                     break;
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 17/25] target-sparc: Fix obvious error in ASI_M_BFILL
  2015-12-17 20:54 [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
                   ` (7 preceding siblings ...)
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 15/25] target-sparc: Introduce gen_check_align Richard Henderson
@ 2015-12-17 20:57 ` Richard Henderson
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 19/25] target-sparc: Directly implement easy ldf/stf asis Richard Henderson
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2015-12-17 20:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland, aurelien

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-sparc/ldst_helper.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
index 9179eaa..efb0b75 100644
--- a/target-sparc/ldst_helper.c
+++ b/target-sparc/ldst_helper.c
@@ -987,7 +987,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi,
             /* addr = dst
                fill 32 bytes with val */
             unsigned int i;
-            uint32_t dst = addr & 7;
+            uint32_t dst = addr & ~7;
 
             for (i = 0; i < 32; i += 8, dst += 8) {
                 cpu_stq_kernel(env, dst, val);
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 19/25] target-sparc: Directly implement easy ldf/stf asis
  2015-12-17 20:54 [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
                   ` (8 preceding siblings ...)
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 17/25] target-sparc: Fix obvious error in ASI_M_BFILL Richard Henderson
@ 2015-12-17 20:57 ` Richard Henderson
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 20/25] target-sparc: Directly implement block and short " Richard Henderson
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2015-12-17 20:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland, aurelien

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-sparc/translate.c | 43 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index a10f588..d28e5f6 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -2290,10 +2290,32 @@ static void gen_ldf_asi(DisasContext *dc, TCGv addr,
                         int insn, int size, int rd)
 {
     DisasASI da = get_asi(dc, insn, (size == 4 ? MO_TEUL : MO_TEQ));
+    TCGv_i32 d32;
 
     switch (da.type) {
     case GET_ASI_EXCP:
         break;
+
+    case GET_ASI_DIRECT:
+        switch (size) {
+        case 4:
+            d32 = gen_dest_fpr_F(dc);
+            tcg_gen_qemu_ld_i32(d32, addr, da.mem_idx, da.memop);
+            gen_store_fpr_F(dc, rd, d32);
+            break;
+        case 8:
+            tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2], addr, da.mem_idx, da.memop);
+            break;
+        case 16:
+            tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2], addr, da.mem_idx, da.memop);
+            tcg_gen_addi_tl(addr, addr, 8);
+            tcg_gen_qemu_ld_i64(cpu_fpr[rd/2+1], addr, da.mem_idx, da.memop);
+            break;
+        default:
+            g_assert_not_reached();
+        }
+        break;
+
     default:
         {
             TCGv_i32 r_asi = tcg_const_i32(da.asi);
@@ -2314,10 +2336,31 @@ static void gen_stf_asi(DisasContext *dc, TCGv addr,
                         int insn, int size, int rd)
 {
     DisasASI da = get_asi(dc, insn, (size == 4 ? MO_TEUL : MO_TEQ));
+    TCGv_i32 d32;
 
     switch (da.type) {
     case GET_ASI_EXCP:
         break;
+
+    case GET_ASI_DIRECT:
+        switch (size) {
+        case 4:
+            d32 = gen_load_fpr_F(dc, rd);
+            tcg_gen_qemu_st_i32(d32, addr, da.mem_idx, da.memop);
+            break;
+        case 8:
+            tcg_gen_qemu_st_i64(cpu_fpr[rd / 2], addr, da.mem_idx, da.memop);
+            break;
+        case 16:
+            tcg_gen_qemu_st_i64(cpu_fpr[rd / 2], addr, da.mem_idx, da.memop);
+            tcg_gen_addi_tl(addr, addr, 8);
+            tcg_gen_qemu_st_i64(cpu_fpr[rd/2+1], addr, da.mem_idx, da.memop);
+            break;
+        default:
+            g_assert_not_reached();
+        }
+        break;
+
     default:
         {
             TCGv_i32 r_asi = tcg_const_i32(da.asi);
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 20/25] target-sparc: Directly implement block and short ldf/stf asis
  2015-12-17 20:54 [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
                   ` (9 preceding siblings ...)
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 19/25] target-sparc: Directly implement easy ldf/stf asis Richard Henderson
@ 2015-12-17 20:57 ` Richard Henderson
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 21/25] target-sparc: Remove helper_ldf_asi, helper_stf_asi Richard Henderson
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2015-12-17 20:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland, aurelien

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-sparc/translate.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 106 insertions(+)

diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index d28e5f6..2224ff2 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -1980,6 +1980,8 @@ typedef enum {
     GET_ASI_EXCP,
     GET_ASI_DIRECT,
     GET_ASI_DTWINX,
+    GET_ASI_BLOCK,
+    GET_ASI_SHORT,
 } ASIType;
 
 typedef struct {
@@ -2051,12 +2053,20 @@ static DisasASI get_asi(DisasContext *dc, int insn, TCGMemOp memop)
         case ASI_AIUPL: /* As if user primary LE */
         case ASI_TWINX_AIUP:
         case ASI_TWINX_AIUP_L:
+        case ASI_BLK_AIUP_4V:
+        case ASI_BLK_AIUP_L_4V:
+        case ASI_BLK_AIUP:
+        case ASI_BLK_AIUPL:
             mem_idx = MMU_USER_IDX;
             break;
         case ASI_AIUS:  /* As if user secondary */
         case ASI_AIUSL: /* As if user secondary LE */
         case ASI_TWINX_AIUS:
         case ASI_TWINX_AIUS_L:
+        case ASI_BLK_AIUS_4V:
+        case ASI_BLK_AIUS_L_4V:
+        case ASI_BLK_AIUS:
+        case ASI_BLK_AIUSL:
             mem_idx = MMU_USER_SECONDARY_IDX;
             break;
         case ASI_REAL:      /* Bypass */
@@ -2071,6 +2081,12 @@ static DisasASI get_asi(DisasContext *dc, int insn, TCGMemOp memop)
         case ASI_SL: /* Secondary LE */
         case ASI_TWINX_S:
         case ASI_TWINX_SL:
+        case ASI_BLK_S:
+        case ASI_BLK_SL:
+        case ASI_FL8_S:
+        case ASI_FL8_SL:
+        case ASI_FL16_S:
+        case ASI_FL16_SL:
             if (mem_idx == MMU_USER_IDX) {
                 mem_idx = MMU_USER_SECONDARY_IDX;
             } else if (mem_idx == MMU_KERNEL_IDX) {
@@ -2081,6 +2097,12 @@ static DisasASI get_asi(DisasContext *dc, int insn, TCGMemOp memop)
         case ASI_PL: /* Primary LE */
         case ASI_TWINX_P:
         case ASI_TWINX_PL:
+        case ASI_BLK_P:
+        case ASI_BLK_PL:
+        case ASI_FL8_P:
+        case ASI_FL8_PL:
+        case ASI_FL16_P:
+        case ASI_FL16_PL:
             break;
         }
         switch (asi) {
@@ -2114,6 +2136,34 @@ static DisasASI get_asi(DisasContext *dc, int insn, TCGMemOp memop)
         case ASI_TWINX_SL:
             type = GET_ASI_DTWINX;
             break;
+        case ASI_BLK_AIUP_4V:
+        case ASI_BLK_AIUP_L_4V:
+        case ASI_BLK_AIUP:
+        case ASI_BLK_AIUPL:
+        case ASI_BLK_AIUS_4V:
+        case ASI_BLK_AIUS_L_4V:
+        case ASI_BLK_AIUS:
+        case ASI_BLK_AIUSL:
+        case ASI_BLK_S:
+        case ASI_BLK_SL:
+        case ASI_BLK_P:
+        case ASI_BLK_PL:
+            type = GET_ASI_BLOCK;
+            break;
+        case ASI_FL8_S:
+        case ASI_FL8_SL:
+        case ASI_FL8_P:
+        case ASI_FL8_PL:
+            memop = MO_UB;
+            type = GET_ASI_SHORT;
+            break;
+        case ASI_FL16_S:
+        case ASI_FL16_SL:
+        case ASI_FL16_P:
+        case ASI_FL16_PL:
+            memop = MO_TEUW;
+            type = GET_ASI_SHORT;
+            break;
         }
         /* The little-endian asis all have bit 3 set.  */
         if (asi & 8) {
@@ -2316,6 +2366,34 @@ static void gen_ldf_asi(DisasContext *dc, TCGv addr,
         }
         break;
 
+    case GET_ASI_BLOCK:
+        /* Valid for lddfa on aligned registers only.  */
+        if (size == 8 && (rd & 7) == 0) {
+            int i;
+
+            gen_check_align(addr, 0x3f);
+            for (i = 0; ; ++i) {
+                tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2 + i], addr,
+                                    da.mem_idx, da.memop);
+                if (i == 7) {
+                    break;
+                }
+                tcg_gen_addi_tl(addr, addr, 8);
+            }
+        } else {
+            gen_exception(dc, TT_ILL_INSN);
+        }
+        break;
+
+    case GET_ASI_SHORT:
+        /* Valid for lddfa only.  */
+        if (size == 8) {
+            tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2], addr, da.mem_idx, da.memop);
+        } else {
+            gen_exception(dc, TT_ILL_INSN);
+        }
+        break;
+
     default:
         {
             TCGv_i32 r_asi = tcg_const_i32(da.asi);
@@ -2361,6 +2439,34 @@ static void gen_stf_asi(DisasContext *dc, TCGv addr,
         }
         break;
 
+    case GET_ASI_BLOCK:
+        /* Valid for stdfa on aligned registers only.  */
+        if (size == 8 && (rd & 7) == 0) {
+            int i;
+
+            gen_check_align(addr, 0x3f);
+            for (i = 0; ; ++i) {
+                tcg_gen_qemu_st_i64(cpu_fpr[rd / 2 + i], addr,
+                                    da.mem_idx, da.memop);
+                if (i == 7) {
+                    break;
+                }
+                tcg_gen_addi_tl(addr, addr, 8);
+            }
+        } else {
+            gen_exception(dc, TT_ILL_INSN);
+        }
+        break;
+
+    case GET_ASI_SHORT:
+        /* Valid for stdfa only.  */
+        if (size == 8) {
+            tcg_gen_qemu_st_i64(cpu_fpr[rd / 2], addr, da.mem_idx, da.memop);
+        } else {
+            gen_exception(dc, TT_ILL_INSN);
+        }
+        break;
+
     default:
         {
             TCGv_i32 r_asi = tcg_const_i32(da.asi);
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 21/25] target-sparc: Remove helper_ldf_asi, helper_stf_asi
  2015-12-17 20:54 [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
                   ` (10 preceding siblings ...)
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 20/25] target-sparc: Directly implement block and short " Richard Henderson
@ 2015-12-17 20:57 ` Richard Henderson
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 23/25] target-sparc: Use cpu_fsr in stfsr Richard Henderson
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2015-12-17 20:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland, aurelien

We've now implemented all fp asis inline, except for the no-fault
memory reads.  The latter can be passed directly to helper_ld_asi.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-sparc/helper.h      |   2 -
 target-sparc/ldst_helper.c | 148 ---------------------------------------------
 target-sparc/translate.c   |  48 ++++++++++-----
 3 files changed, 32 insertions(+), 166 deletions(-)

diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index bf0f727..8e8a3d1 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -18,8 +18,6 @@ DEF_HELPER_2(wrcwp, void, env, tl)
 DEF_HELPER_FLAGS_2(array8, TCG_CALL_NO_RWG_SE, tl, tl, tl)
 DEF_HELPER_FLAGS_1(popc, TCG_CALL_NO_RWG_SE, tl, tl)
 DEF_HELPER_FLAGS_3(ldda_asi, TCG_CALL_NO_WG, void, env, tl, int)
-DEF_HELPER_5(ldf_asi, void, env, tl, int, int, int)
-DEF_HELPER_FLAGS_5(stf_asi, TCG_CALL_NO_WG, void, env, tl, int, int, int)
 DEF_HELPER_FLAGS_5(casx_asi, TCG_CALL_NO_WG, tl, env, tl, tl, tl, i32)
 DEF_HELPER_FLAGS_2(set_softint, TCG_CALL_NO_RWG, void, env, i64)
 DEF_HELPER_FLAGS_2(clear_softint, TCG_CALL_NO_RWG, void, env, i64)
diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
index 8cab20b..36764d1 100644
--- a/target-sparc/ldst_helper.c
+++ b/target-sparc/ldst_helper.c
@@ -2159,154 +2159,6 @@ void helper_ldda_asi(CPUSPARCState *env, target_ulong addr, int asi)
     QT0.low = l;
 }
 
-void helper_ldf_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
-                    int rd)
-{
-    unsigned int i;
-    target_ulong val;
-
-    helper_check_align(env, addr, 3);
-    addr = asi_address_mask(env, asi, addr);
-
-    switch (asi) {
-    case ASI_BLK_P:  /* UA2007/JPS1 Block load primary */
-    case ASI_BLK_S:  /* UA2007/JPS1 Block load secondary */
-    case ASI_BLK_PL: /* UA2007/JPS1 Block load primary LE */
-    case ASI_BLK_SL: /* UA2007/JPS1 Block load secondary LE */
-        if (rd & 7) {
-            helper_raise_exception(env, TT_ILL_INSN);
-            return;
-        }
-        helper_check_align(env, addr, 0x3f);
-        for (i = 0; i < 8; i++, rd += 2, addr += 8) {
-            env->fpr[rd / 2].ll = helper_ld_asi(env, addr, asi & 0x8f, MO_Q);
-        }
-        return;
-
-    case ASI_BLK_AIUP_4V:   /* UA2007 Block load primary, user privilege */
-    case ASI_BLK_AIUS_4V:   /* UA2007 Block load secondary, user privilege */
-    case ASI_BLK_AIUP_L_4V: /* UA2007 Block load primary LE, user privilege */
-    case ASI_BLK_AIUS_L_4V: /* UA2007 Block load secondary LE, user privilege */
-    case ASI_BLK_AIUP:  /* JPS1 Block load primary, user privilege */
-    case ASI_BLK_AIUS:  /* JPS1 Block load secondary, user privilege */
-    case ASI_BLK_AIUPL: /* JPS1 Block load primary LE, user privilege */
-    case ASI_BLK_AIUSL: /* JPS1 Block load secondary LE, user privilege */
-        if (rd & 7) {
-            helper_raise_exception(env, TT_ILL_INSN);
-            return;
-        }
-        helper_check_align(env, addr, 0x3f);
-        for (i = 0; i < 8; i++, rd += 2, addr += 8) {
-            env->fpr[rd / 2].ll = helper_ld_asi(env, addr, asi & 0x19, MO_Q);
-        }
-        return;
-
-    default:
-        break;
-    }
-
-    switch (size) {
-    default:
-    case 4:
-        val = helper_ld_asi(env, addr, asi, MO_UL);
-        if (rd & 1) {
-            env->fpr[rd / 2].l.lower = val;
-        } else {
-            env->fpr[rd / 2].l.upper = val;
-        }
-        break;
-    case 8:
-        env->fpr[rd / 2].ll = helper_ld_asi(env, addr, asi, MO_Q);
-        break;
-    case 16:
-        env->fpr[rd / 2].ll = helper_ld_asi(env, addr, asi, MO_Q);
-        env->fpr[rd / 2 + 1].ll = helper_ld_asi(env, addr + 8, asi, MO_Q);
-        break;
-    }
-}
-
-void helper_stf_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
-                    int rd)
-{
-    unsigned int i;
-    target_ulong val;
-
-    addr = asi_address_mask(env, asi, addr);
-
-    switch (asi) {
-    case ASI_BLK_COMMIT_P: /* UA2007/JPS1 Block store primary (cache flush) */
-    case ASI_BLK_COMMIT_S: /* UA2007/JPS1 Block store secondary (cache flush) */
-    case ASI_BLK_P: /* UA2007/JPS1 Block store primary */
-    case ASI_BLK_S: /* UA2007/JPS1 Block store secondary */
-    case ASI_BLK_PL: /* UA2007/JPS1 Block store primary LE */
-    case ASI_BLK_SL: /* UA2007/JPS1 Block store secondary LE */
-        if (rd & 7) {
-            helper_raise_exception(env, TT_ILL_INSN);
-            return;
-        }
-        helper_check_align(env, addr, 0x3f);
-        for (i = 0; i < 8; i++, rd += 2, addr += 8) {
-            helper_st_asi(env, addr, env->fpr[rd / 2].ll, asi & 0x8f, MO_Q);
-        }
-
-        return;
-    case ASI_BLK_AIUP_4V: /* UA2007 Block load primary, user privilege */
-    case ASI_BLK_AIUS_4V: /* UA2007 Block load secondary, user privilege */
-    case ASI_BLK_AIUP_L_4V: /* UA2007 Block load primary LE, user privilege */
-    case ASI_BLK_AIUS_L_4V: /* UA2007 Block load secondary LE, user privilege */
-    case ASI_BLK_AIUP: /* JPS1 Block store primary, user privilege */
-    case ASI_BLK_AIUS: /* JPS1 Block store secondary, user privilege */
-    case ASI_BLK_AIUPL: /* JPS1 Block load primary LE, user privilege */
-    case ASI_BLK_AIUSL: /* JPS1 Block load secondary LE, user privilege */
-        if (rd & 7) {
-            helper_raise_exception(env, TT_ILL_INSN);
-            return;
-        }
-        helper_check_align(env, addr, 0x3f);
-        for (i = 0; i < 8; i++, rd += 2, addr += 8) {
-            helper_st_asi(env, addr, env->fpr[rd / 2].ll, asi & 0x19, MO_Q);
-        }
-
-        return;
-    case ASI_FL16_P: /* 16-bit floating point load primary */
-    case ASI_FL16_S: /* 16-bit floating point load secondary */
-    case ASI_FL16_PL: /* 16-bit floating point load primary, LE */
-    case ASI_FL16_SL: /* 16-bit floating point load secondary, LE */
-        val = env->fpr[rd / 2].l.lower;
-        helper_st_asi(env, addr, val, asi & 0x8d, MO_UW);
-        return;
-    case ASI_FL8_P: /* 8-bit floating point load primary */
-    case ASI_FL8_S: /* 8-bit floating point load secondary */
-    case ASI_FL8_PL: /* 8-bit floating point load primary, LE */
-    case ASI_FL8_SL: /* 8-bit floating point load secondary, LE */
-        val = env->fpr[rd / 2].l.lower;
-        helper_st_asi(env, addr, val, asi & 0x8d, MO_UB);
-        return;
-    default:
-        helper_check_align(env, addr, 3);
-        break;
-    }
-
-    switch (size) {
-    default:
-    case 4:
-        if (rd & 1) {
-            val = env->fpr[rd / 2].l.lower;
-        } else {
-            val = env->fpr[rd / 2].l.upper;
-        }
-        helper_st_asi(env, addr, val, asi, MO_UL);
-        break;
-    case 8:
-        helper_st_asi(env, addr, env->fpr[rd / 2].ll, asi, MO_Q);
-        break;
-    case 16:
-        helper_st_asi(env, addr, env->fpr[rd / 2].ll, asi, MO_Q);
-        helper_st_asi(env, addr + 8, env->fpr[rd / 2 + 1].ll, asi, MO_Q);
-        break;
-    }
-}
-
 target_ulong helper_casx_asi(CPUSPARCState *env, target_ulong addr,
                              target_ulong val1, target_ulong val2,
                              uint32_t asi)
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 2224ff2..542c3a1 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -2397,13 +2397,36 @@ static void gen_ldf_asi(DisasContext *dc, TCGv addr,
     default:
         {
             TCGv_i32 r_asi = tcg_const_i32(da.asi);
-            TCGv_i32 r_size = tcg_const_i32(size);
-            TCGv_i32 r_rd = tcg_const_i32(rd);
+            TCGv_i32 r_mop = tcg_const_i32(da.memop);
 
             save_state(dc);
-            gen_helper_ldf_asi(cpu_env, addr, r_asi, r_size, r_rd);
-            tcg_temp_free_i32(r_rd);
-            tcg_temp_free_i32(r_size);
+            /* According to the table in the UA2011 manual, the only
+               other asis that are valid for ldfa/lddfa/ldqfa are
+               the NO_FAULT asis.  We still need a helper for these,
+               but we can just use the integer asi helper for them.  */
+            switch (size) {
+            case 4:
+                {
+                    TCGv d64 = tcg_temp_new_i64();
+                    gen_helper_ld_asi(d64, cpu_env, addr, r_asi, r_mop);
+                    d32 = gen_dest_fpr_F(dc);
+                    tcg_gen_extrl_i64_i32(d32, d64);
+                    tcg_temp_free_i64(d64);
+                    gen_store_fpr_F(dc, rd, d32);
+                }
+                break;
+            case 8:
+                gen_helper_ld_asi(cpu_fpr[rd / 2], cpu_env, addr, r_asi, r_mop);
+                break;
+            case 16:
+                gen_helper_ld_asi(cpu_fpr[rd / 2], cpu_env, addr, r_asi, r_mop);
+                tcg_gen_addi_tl(addr, addr, 8);
+                gen_helper_ld_asi(cpu_fpr[rd/2+1], cpu_env, addr, r_asi, r_mop);
+                break;
+            default:
+                g_assert_not_reached();
+            }
+            tcg_temp_free_i32(r_mop);
             tcg_temp_free_i32(r_asi);
         }
         break;
@@ -2468,17 +2491,10 @@ static void gen_stf_asi(DisasContext *dc, TCGv addr,
         break;
 
     default:
-        {
-            TCGv_i32 r_asi = tcg_const_i32(da.asi);
-            TCGv_i32 r_size = tcg_const_i32(size);
-            TCGv_i32 r_rd = tcg_const_i32(rd);
-
-            save_state(dc);
-            gen_helper_stf_asi(cpu_env, addr, r_asi, r_size, r_rd);
-            tcg_temp_free_i32(r_rd);
-            tcg_temp_free_i32(r_size);
-            tcg_temp_free_i32(r_asi);
-        }
+        /* According to the table in the UA2011 manual, the only
+           other asis that are valid for ldfa/lddfa/ldqfa are
+           the PST* asis, which aren't currently handled.  */
+        gen_exception(dc, TT_ILL_INSN);
         break;
     }
 }
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 23/25] target-sparc: Use cpu_fsr in stfsr
  2015-12-17 20:54 [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
                   ` (11 preceding siblings ...)
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 21/25] target-sparc: Remove helper_ldf_asi, helper_stf_asi Richard Henderson
@ 2015-12-17 20:57 ` Richard Henderson
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 24/25] target-sparc: Use cpu_loop_exit_restore from helper_check_ieee_exceptions Richard Henderson
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2015-12-17 20:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland, aurelien

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-sparc/translate.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 809d4c9..8bdb953 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -5368,17 +5368,14 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     break;
                 case 0x25: /* stfsr, V9 stxfsr */
                     {
-                        TCGv t = get_temp_tl(dc);
-
-                        tcg_gen_ld_tl(t, cpu_env, offsetof(CPUSPARCState, fsr));
 #ifdef TARGET_SPARC64
                         gen_address_mask(dc, cpu_addr);
                         if (rd == 1) {
-                            tcg_gen_qemu_st64(t, cpu_addr, dc->mem_idx);
+                            tcg_gen_qemu_st64(cpu_fsr, cpu_addr, dc->mem_idx);
                             break;
                         }
 #endif
-                        tcg_gen_qemu_st32(t, cpu_addr, dc->mem_idx);
+                        tcg_gen_qemu_st32(cpu_fsr, cpu_addr, dc->mem_idx);
                     }
                     break;
                 case 0x26:
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 24/25] target-sparc: Use cpu_loop_exit_restore from helper_check_ieee_exceptions
  2015-12-17 20:54 [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
                   ` (12 preceding siblings ...)
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 23/25] target-sparc: Use cpu_fsr in stfsr Richard Henderson
@ 2015-12-17 20:57 ` Richard Henderson
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 25/25] target-sparc: Elide duplicate updates to fprs Richard Henderson
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2015-12-17 20:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland, aurelien

This avoids needing to save state before every FP operation.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-sparc/fop_helper.c | 16 ++++++++++++----
 target-sparc/translate.c  |  6 +-----
 2 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/target-sparc/fop_helper.c b/target-sparc/fop_helper.c
index 9d86cd1..08d5e42 100644
--- a/target-sparc/fop_helper.c
+++ b/target-sparc/fop_helper.c
@@ -23,7 +23,7 @@
 #define QT0 (env->qt0)
 #define QT1 (env->qt1)
 
-target_ulong helper_check_ieee_exceptions(CPUSPARCState *env)
+static target_ulong do_check_ieee_exceptions(CPUSPARCState *env, uintptr_t ra)
 {
     target_ulong status = get_float_exception_flags(&env->fp_status);
     target_ulong fsr = env->fsr;
@@ -50,12 +50,15 @@ target_ulong helper_check_ieee_exceptions(CPUSPARCState *env)
         }
 
         if ((fsr & FSR_CEXC_MASK) & ((fsr & FSR_TEM_MASK) >> 23)) {
+            CPUState *cs = CPU(sparc_env_get_cpu(env));
+
             /* Unmasked exception, generate a trap.  Note that while
                the helper is marked as NO_WG, we can get away with
                writing to cpu state along the exception path, since
                TCG generated code will never see the write.  */
             env->fsr = fsr | FSR_FTT_IEEE_EXCP;
-            helper_raise_exception(env, TT_FP_EXCP);
+            cs->exception_index = TT_FP_EXCP;
+            cpu_loop_exit_restore(cs, ra);
         } else {
             /* Accumulate exceptions */
             fsr |= (fsr & FSR_CEXC_MASK) << 5;
@@ -65,6 +68,11 @@ target_ulong helper_check_ieee_exceptions(CPUSPARCState *env)
     return fsr;
 }
 
+target_ulong helper_check_ieee_exceptions(CPUSPARCState *env)
+{
+    return do_check_ieee_exceptions(env, GETPC());
+}
+
 #define F_HELPER(name, p) void helper_f##name##p(CPUSPARCState *env)
 
 #define F_BINOP(name)                                           \
@@ -261,7 +269,7 @@ void helper_fsqrtq(CPUSPARCState *env)
             ret = glue(size, _compare_quiet)(reg1, reg2,                \
                                              &env->fp_status);          \
         }                                                               \
-        fsr = helper_check_ieee_exceptions(env);                        \
+        fsr = do_check_ieee_exceptions(env, GETPC());                   \
         switch (ret) {                                                  \
         case float_relation_unordered:                                  \
             fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                         \
@@ -292,7 +300,7 @@ void helper_fsqrtq(CPUSPARCState *env)
             ret = glue(size, _compare_quiet)(src1, src2,                \
                                              &env->fp_status);          \
         }                                                               \
-        fsr = helper_check_ieee_exceptions(env);                        \
+        fsr = do_check_ieee_exceptions(env, GETPC());                   \
         switch (ret) {                                                  \
         case float_relation_unordered:                                  \
             fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                         \
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 8bdb953..4b6b12f 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -3432,7 +3432,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                 rs1 = GET_FIELD(insn, 13, 17);
                 rs2 = GET_FIELD(insn, 27, 31);
                 xop = GET_FIELD(insn, 18, 26);
-                save_state(dc);
+
                 switch (xop) {
                 case 0x1: /* fmovs */
                     cpu_src1_32 = gen_load_fpr_F(dc, rs2);
@@ -3607,7 +3607,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                 rs1 = GET_FIELD(insn, 13, 17);
                 rs2 = GET_FIELD(insn, 27, 31);
                 xop = GET_FIELD(insn, 18, 26);
-                save_state(dc);
 
 #ifdef TARGET_SPARC64
 #define FMOVR(sz)                                                  \
@@ -5241,7 +5240,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                 if (gen_trap_ifnofpu(dc)) {
                     goto jmp_insn;
                 }
-                save_state(dc);
                 switch (xop) {
                 case 0x20:      /* ldf, load fpreg */
                     gen_address_mask(dc, cpu_addr);
@@ -5355,7 +5353,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                 if (gen_trap_ifnofpu(dc)) {
                     goto jmp_insn;
                 }
-                save_state(dc);
                 switch (xop) {
                 case 0x24: /* stf, store fpreg */
                     {
@@ -5414,7 +5411,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     goto illegal_insn;
                 }
             } else if (xop > 0x33 && xop < 0x3f) {
-                save_state(dc);
                 switch (xop) {
 #ifdef TARGET_SPARC64
                 case 0x34: /* V9 stfa */
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 25/25] target-sparc: Elide duplicate updates to fprs
  2015-12-17 20:54 [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
                   ` (13 preceding siblings ...)
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 24/25] target-sparc: Use cpu_loop_exit_restore from helper_check_ieee_exceptions Richard Henderson
@ 2015-12-17 20:57 ` Richard Henderson
  2015-12-17 23:11 ` [Qemu-devel] [PATCH 06/25] target-sparc: Store %asi in TB flags Richard Henderson
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2015-12-17 20:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland, aurelien

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-sparc/translate.c | 45 +++++++++++++++++++++++++++------------------
 1 file changed, 27 insertions(+), 18 deletions(-)

diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 4b6b12f..0df45af 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -84,6 +84,7 @@ typedef struct DisasContext {
     int n_t32;
     int n_ttl;
 #ifdef TARGET_SPARC64
+    int fprs_dirty;
     int asi;
 #endif
 } DisasContext;
@@ -141,10 +142,16 @@ static inline TCGv get_temp_tl(DisasContext *dc)
     return t;
 }
 
-static inline void gen_update_fprs_dirty(int rd)
+static inline void gen_update_fprs_dirty(DisasContext *dc, int rd)
 {
 #if defined(TARGET_SPARC64)
-    tcg_gen_ori_i32(cpu_fprs, cpu_fprs, (rd < 32) ? 1 : 2);
+    int bit = (rd < 32) ? 1 : 2;
+    /* If we know we've already set this bit within the TB,
+       we can avoid setting it again.  */
+    if (!(dc->fprs_dirty & bit)) {
+        dc->fprs_dirty |= bit;
+        tcg_gen_ori_i32(cpu_fprs, cpu_fprs, bit);
+    }
 #endif
 }
 
@@ -186,7 +193,7 @@ static void gen_store_fpr_F(DisasContext *dc, unsigned int dst, TCGv_i32 v)
     tcg_gen_deposit_i64(cpu_fpr[dst / 2], cpu_fpr[dst / 2], t,
                         (dst & 1 ? 0 : 32), 32);
 #endif
-    gen_update_fprs_dirty(dst);
+    gen_update_fprs_dirty(dc, dst);
 }
 
 static TCGv_i32 gen_dest_fpr_F(DisasContext *dc)
@@ -204,7 +211,7 @@ static void gen_store_fpr_D(DisasContext *dc, unsigned int dst, TCGv_i64 v)
 {
     dst = DFPREG(dst);
     tcg_gen_mov_i64(cpu_fpr[dst / 2], v);
-    gen_update_fprs_dirty(dst);
+    gen_update_fprs_dirty(dc, dst);
 }
 
 static TCGv_i64 gen_dest_fpr_D(DisasContext *dc, unsigned int dst)
@@ -237,14 +244,14 @@ static void gen_op_store_QT0_fpr(unsigned int dst)
 }
 
 #ifdef TARGET_SPARC64
-static void gen_move_Q(unsigned int rd, unsigned int rs)
+static void gen_move_Q(DisasContext *dc, unsigned int rd, unsigned int rs)
 {
     rd = QFPREG(rd);
     rs = QFPREG(rs);
 
     tcg_gen_mov_i64(cpu_fpr[rd / 2], cpu_fpr[rs / 2]);
     tcg_gen_mov_i64(cpu_fpr[rd / 2 + 1], cpu_fpr[rs / 2 + 1]);
-    gen_update_fprs_dirty(rd);
+    gen_update_fprs_dirty(dc, rd);
 }
 #endif
 
@@ -1825,7 +1832,7 @@ static inline void gen_fop_QQ(DisasContext *dc, int rd, int rs,
     gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_op_store_QT0_fpr(QFPREG(rd));
-    gen_update_fprs_dirty(QFPREG(rd));
+    gen_update_fprs_dirty(dc, QFPREG(rd));
 }
 
 #ifdef TARGET_SPARC64
@@ -1837,7 +1844,7 @@ static inline void gen_ne_fop_QQ(DisasContext *dc, int rd, int rs,
     gen(cpu_env);
 
     gen_op_store_QT0_fpr(QFPREG(rd));
-    gen_update_fprs_dirty(QFPREG(rd));
+    gen_update_fprs_dirty(dc, QFPREG(rd));
 }
 #endif
 
@@ -1851,7 +1858,7 @@ static inline void gen_fop_QQQ(DisasContext *dc, int rd, int rs1, int rs2,
     gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_op_store_QT0_fpr(QFPREG(rd));
-    gen_update_fprs_dirty(QFPREG(rd));
+    gen_update_fprs_dirty(dc, QFPREG(rd));
 }
 
 static inline void gen_fop_DFF(DisasContext *dc, int rd, int rs1, int rs2,
@@ -1882,7 +1889,7 @@ static inline void gen_fop_QDD(DisasContext *dc, int rd, int rs1, int rs2,
     gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_op_store_QT0_fpr(QFPREG(rd));
-    gen_update_fprs_dirty(QFPREG(rd));
+    gen_update_fprs_dirty(dc, QFPREG(rd));
 }
 
 #ifdef TARGET_SPARC64
@@ -1969,7 +1976,7 @@ static inline void gen_ne_fop_QF(DisasContext *dc, int rd, int rs,
     gen(cpu_env, src);
 
     gen_op_store_QT0_fpr(QFPREG(rd));
-    gen_update_fprs_dirty(QFPREG(rd));
+    gen_update_fprs_dirty(dc, QFPREG(rd));
 }
 
 static inline void gen_ne_fop_QD(DisasContext *dc, int rd, int rs,
@@ -1982,7 +1989,7 @@ static inline void gen_ne_fop_QD(DisasContext *dc, int rd, int rs,
     gen(cpu_env, src);
 
     gen_op_store_QT0_fpr(QFPREG(rd));
-    gen_update_fprs_dirty(QFPREG(rd));
+    gen_update_fprs_dirty(dc, QFPREG(rd));
 }
 
 /* asi moves */
@@ -2770,7 +2777,7 @@ static void gen_fmovq(DisasContext *dc, DisasCompare *cmp, int rd, int rs)
     tcg_gen_movcond_i64(cmp->cond, cpu_fpr[qd / 2 + 1], cmp->c1, cmp->c2,
                         cpu_fpr[qs / 2 + 1], cpu_fpr[qd / 2 + 1]);
 
-    gen_update_fprs_dirty(qd);
+    gen_update_fprs_dirty(dc, qd);
 }
 
 #ifndef CONFIG_USER_ONLY
@@ -3556,7 +3563,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     break;
                 case 0x3: /* V9 fmovq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_move_Q(rd, rs2);
+                    gen_move_Q(dc, rd, rs2);
                     break;
                 case 0x6: /* V9 fnegd */
                     gen_ne_fop_DD(dc, rd, rs2, gen_helper_fnegd);
@@ -4106,6 +4113,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                             case 0x6: /* V9 wrfprs */
                                 tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
                                 tcg_gen_trunc_tl_i32(cpu_fprs, cpu_tmp0);
+                                dc->fprs_dirty = 0;
                                 save_state(dc);
                                 gen_op_next_insn();
                                 tcg_gen_exit_tb(0);
@@ -5207,14 +5215,14 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                         goto jmp_insn;
                     }
                     gen_ldf_asi(dc, cpu_addr, insn, 4, rd);
-                    gen_update_fprs_dirty(rd);
+                    gen_update_fprs_dirty(dc, rd);
                     goto skip_move;
                 case 0x33: /* V9 lddfa */
                     if (gen_trap_ifnofpu(dc)) {
                         goto jmp_insn;
                     }
                     gen_ldf_asi(dc, cpu_addr, insn, 8, DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    gen_update_fprs_dirty(dc, DFPREG(rd));
                     goto skip_move;
                 case 0x3d: /* V9 prefetcha, no effect */
                     goto skip_move;
@@ -5224,7 +5232,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                         goto jmp_insn;
                     }
                     gen_ldf_asi(dc, cpu_addr, insn, 16, QFPREG(rd));
-                    gen_update_fprs_dirty(QFPREG(rd));
+                    gen_update_fprs_dirty(dc, QFPREG(rd));
                     goto skip_move;
 #endif
                 default:
@@ -5276,7 +5284,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                         gen_helper_ldqf(cpu_env, cpu_addr, r_const);
                         tcg_temp_free_i32(r_const);
                         gen_op_store_QT0_fpr(QFPREG(rd));
-                        gen_update_fprs_dirty(QFPREG(rd));
+                        gen_update_fprs_dirty(dc, QFPREG(rd));
                     }
                     break;
                 case 0x23:      /* lddf, load double fpreg */
@@ -5544,6 +5552,7 @@ void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
     dc->address_mask_32bit = tb_am_enabled(tb->flags);
     dc->singlestep = (cs->singlestep_enabled || singlestep);
 #ifdef TARGET_SPARC64
+    dc->fprs_dirty = 0;
     dc->asi = (tb->flags >> TB_FLAG_ASI_SHIFT) & 0xff;
 #endif
 
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 06/25] target-sparc: Store %asi in TB flags
  2015-12-17 20:54 [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
                   ` (14 preceding siblings ...)
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 25/25] target-sparc: Elide duplicate updates to fprs Richard Henderson
@ 2015-12-17 23:11 ` Richard Henderson
  2015-12-17 23:11 ` [Qemu-devel] [PATCH 08/25] target-sparc: Pass TCGMemOp to gen_ld/st_asi Richard Henderson
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2015-12-17 23:11 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland, aurelien

Knowing the value of %asi at translation time means that we
can handle the common settings without a function call.

The steady state appears to be %asi == ASI_P, so that sparcv9
code can use offset forms of lda/sta.  The %asi register gets
pushed and popped on entry to certain functions, but it rarely
takes on values other than ASI_P or ASI_AIUP.  Therefore we're
unlikely to be expanding the set of TBs created.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-sparc/cpu.h       |  2 ++
 target-sparc/translate.c | 29 ++++++++++++++++++++---------
 2 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index f3ae242..7f4d47f 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -691,6 +691,7 @@ trap_state* cpu_tsptr(CPUSPARCState* env);
 #define TB_FLAG_MMU_MASK     7
 #define TB_FLAG_FPU_ENABLED  (1 << 4)
 #define TB_FLAG_AM_ENABLED   (1 << 5)
+#define TB_FLAG_ASI_SHIFT    24
 
 static inline void cpu_get_tb_cpu_state(CPUSPARCState *env, target_ulong *pc,
                                         target_ulong *cs_base, int *pflags)
@@ -708,6 +709,7 @@ static inline void cpu_get_tb_cpu_state(CPUSPARCState *env, target_ulong *pc,
         && (env->fprs & FPRS_FEF)) {
         flags |= TB_FLAG_FPU_ENABLED;
     }
+    flags |= env->asi << TB_FLAG_ASI_SHIFT;
 #else
     if ((env->def->features & CPU_FEATURE_FLOAT) && env->psref) {
         flags |= TB_FLAG_FPU_ENABLED;
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 146060a..0e51ee4 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -54,7 +54,7 @@ static TCGv cpu_tbr;
 #endif
 static TCGv cpu_cond;
 #ifdef TARGET_SPARC64
-static TCGv_i32 cpu_xcc, cpu_asi, cpu_fprs;
+static TCGv_i32 cpu_xcc, cpu_fprs;
 static TCGv cpu_gsr;
 static TCGv cpu_tick_cmpr, cpu_stick_cmpr, cpu_hstick_cmpr;
 static TCGv cpu_hintp, cpu_htba, cpu_hver, cpu_ssr, cpu_ver;
@@ -82,6 +82,9 @@ typedef struct DisasContext {
     TCGv ttl[5];
     int n_t32;
     int n_ttl;
+#ifdef TARGET_SPARC64
+    int asi;
+#endif
 } DisasContext;
 
 typedef struct {
@@ -1966,19 +1969,19 @@ static inline void gen_ne_fop_QD(DisasContext *dc, int rd, int rs,
 #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
 static TCGv_i32 gen_get_asi(DisasContext *dc, int insn)
 {
-    TCGv_i32 r_asi = tcg_temp_new_i32();
+    int asi;
 
     if (IS_IMM) {
 #ifdef TARGET_SPARC64
-        tcg_gen_mov_i32(r_asi, cpu_asi);
+        asi = dc->asi;
 #else
         gen_exception(dc, TT_ILL_INSN);
-        tcg_gen_movi_i32(r_asi, 0);
+        asi = 0;
 #endif
     } else {
-        tcg_gen_movi_i32(r_asi, GET_FIELD(insn, 19, 26));
+        asi = GET_FIELD(insn, 19, 26);
     }
-    return r_asi;
+    return tcg_const_i32(asi);
 }
 
 static void gen_ld_asi(DisasContext *dc, TCGv dst, TCGv addr,
@@ -2675,7 +2678,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     gen_store_gpr(dc, rd, cpu_dst);
                     break;
                 case 0x3: /* V9 rdasi */
-                    tcg_gen_ext_i32_tl(cpu_dst, cpu_asi);
+                    tcg_gen_movi_tl(cpu_dst, dc->asi);
                     gen_store_gpr(dc, rd, cpu_dst);
                     break;
                 case 0x4: /* V9 rdtick */
@@ -3589,7 +3592,13 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                             case 0x3: /* V9 wrasi */
                                 tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
                                 tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0xff);
-                                tcg_gen_trunc_tl_i32(cpu_asi, cpu_tmp0);
+                                tcg_gen_st32_tl(cpu_tmp0, cpu_env,
+                                                offsetof(CPUSPARCState, asi));
+                                /* End TB to notice changed ASI.  */
+                                save_state(dc);
+                                gen_op_next_insn();
+                                tcg_gen_exit_tb(0);
+                                dc->is_br = 1;
                                 break;
                             case 0x6: /* V9 wrfprs */
                                 tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
@@ -5167,6 +5176,9 @@ void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
     dc->fpu_enabled = tb_fpu_enabled(tb->flags);
     dc->address_mask_32bit = tb_am_enabled(tb->flags);
     dc->singlestep = (cs->singlestep_enabled || singlestep);
+#ifdef TARGET_SPARC64
+    dc->asi = (tb->flags >> TB_FLAG_ASI_SHIFT) & 0xff;
+#endif
 
     num_insns = 0;
     max_insns = tb->cflags & CF_COUNT_MASK;
@@ -5275,7 +5287,6 @@ void gen_intermediate_code_init(CPUSPARCState *env)
     static const struct { TCGv_i32 *ptr; int off; const char *name; } r32[] = {
 #ifdef TARGET_SPARC64
         { &cpu_xcc, offsetof(CPUSPARCState, xcc), "xcc" },
-        { &cpu_asi, offsetof(CPUSPARCState, asi), "asi" },
         { &cpu_fprs, offsetof(CPUSPARCState, fprs), "fprs" },
 #else
         { &cpu_wim, offsetof(CPUSPARCState, wim), "wim" },
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 08/25] target-sparc: Pass TCGMemOp to gen_ld/st_asi
  2015-12-17 20:54 [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
                   ` (15 preceding siblings ...)
  2015-12-17 23:11 ` [Qemu-devel] [PATCH 06/25] target-sparc: Store %asi in TB flags Richard Henderson
@ 2015-12-17 23:11 ` Richard Henderson
  2015-12-17 23:13 ` [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
  2015-12-29 18:59 ` Mark Cave-Ayland
  18 siblings, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2015-12-17 23:11 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland, aurelien

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-sparc/translate.c | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index caad473..ab37372 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -2007,7 +2007,7 @@ static DisasASI get_asi(DisasContext *dc, int insn)
 }
 
 static void gen_ld_asi(DisasContext *dc, TCGv dst, TCGv addr,
-                       int insn, int size, int sign)
+                       int insn, TCGMemOp memop)
 {
     DisasASI da = get_asi(dc, insn);
 
@@ -2017,8 +2017,8 @@ static void gen_ld_asi(DisasContext *dc, TCGv dst, TCGv addr,
     default:
         {
             TCGv_i32 r_asi = tcg_const_i32(da.asi);
-            TCGv_i32 r_size = tcg_const_i32(size);
-            TCGv_i32 r_sign = tcg_const_i32(sign);
+            TCGv_i32 r_size = tcg_const_i32(1 << (memop & MO_SIZE));
+            TCGv_i32 r_sign = tcg_const_i32(!!(memop & MO_SIGN));
 
             save_state(dc);
 #ifdef TARGET_SPARC64
@@ -2040,7 +2040,7 @@ static void gen_ld_asi(DisasContext *dc, TCGv dst, TCGv addr,
 }
 
 static void gen_st_asi(DisasContext *dc, TCGv src, TCGv addr,
-                       int insn, int size)
+                       int insn, TCGMemOp memop)
 {
     DisasASI da = get_asi(dc, insn);
 
@@ -2050,7 +2050,7 @@ static void gen_st_asi(DisasContext *dc, TCGv src, TCGv addr,
     default:
         {
             TCGv_i32 r_asi = tcg_const_i32(da.asi);
-            TCGv_i32 r_size = tcg_const_i32(size);
+            TCGv_i32 r_size = tcg_const_i32(1 << (memop & MO_SIZE));
 
             save_state(dc);
 #ifdef TARGET_SPARC64
@@ -4805,13 +4805,13 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     break;
 #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
                 case 0x10:      /* lda, V9 lduwa, load word alternate */
-                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, 4, 0);
+                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, MO_TEUL);
                     break;
                 case 0x11:      /* lduba, load unsigned byte alternate */
-                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, 1, 0);
+                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, MO_UB);
                     break;
                 case 0x12:      /* lduha, load unsigned halfword alternate */
-                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, 2, 0);
+                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, MO_TEUW);
                     break;
                 case 0x13:      /* ldda, load double word alternate */
                     if (rd & 1) {
@@ -4820,10 +4820,10 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     gen_ldda_asi(dc, cpu_val, cpu_addr, insn, rd);
                     goto skip_move;
                 case 0x19:      /* ldsba, load signed byte alternate */
-                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, 1, 1);
+                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, MO_SB);
                     break;
                 case 0x1a:      /* ldsha, load signed halfword alternate */
-                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, 2, 1);
+                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, MO_TESW);
                     break;
                 case 0x1d:      /* ldstuba -- XXX: should be atomically */
                     gen_ldstub_asi(dc, cpu_val, cpu_addr, insn);
@@ -4852,10 +4852,10 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     tcg_gen_qemu_ld64(cpu_val, cpu_addr, dc->mem_idx);
                     break;
                 case 0x18: /* V9 ldswa */
-                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, 4, 1);
+                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, MO_TESL);
                     break;
                 case 0x1b: /* V9 ldxa */
-                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, 8, 0);
+                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, MO_TEQ);
                     break;
                 case 0x2d: /* V9 prefetch, no effect */
                     goto skip_move;
@@ -4987,13 +4987,13 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     break;
 #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
                 case 0x14: /* sta, V9 stwa, store word alternate */
-                    gen_st_asi(dc, cpu_val, cpu_addr, insn, 4);
+                    gen_st_asi(dc, cpu_val, cpu_addr, insn, MO_TEUL);
                     break;
                 case 0x15: /* stba, store byte alternate */
-                    gen_st_asi(dc, cpu_val, cpu_addr, insn, 1);
+                    gen_st_asi(dc, cpu_val, cpu_addr, insn, MO_UB);
                     break;
                 case 0x16: /* stha, store halfword alternate */
-                    gen_st_asi(dc, cpu_val, cpu_addr, insn, 2);
+                    gen_st_asi(dc, cpu_val, cpu_addr, insn, MO_TEUW);
                     break;
                 case 0x17: /* stda, store double word alternate */
                     if (rd & 1) {
@@ -5008,7 +5008,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     tcg_gen_qemu_st64(cpu_val, cpu_addr, dc->mem_idx);
                     break;
                 case 0x1e: /* V9 stxa */
-                    gen_st_asi(dc, cpu_val, cpu_addr, insn, 8);
+                    gen_st_asi(dc, cpu_val, cpu_addr, insn, MO_TEQ);
                     break;
 #endif
                 default:
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH 00/25] target-sparc improvements
  2015-12-17 20:54 [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
                   ` (16 preceding siblings ...)
  2015-12-17 23:11 ` [Qemu-devel] [PATCH 08/25] target-sparc: Pass TCGMemOp to gen_ld/st_asi Richard Henderson
@ 2015-12-17 23:13 ` Richard Henderson
  2015-12-29 18:59 ` Mark Cave-Ayland
  18 siblings, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2015-12-17 23:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland, aurelien

On 12/17/2015 12:54 PM, Richard Henderson wrote:
> The primary focus of this patch set is to reduce the number of
> helpers that modify TCG globals, and thus increase the lifetime
> of those globals within each TB, and thus decrease the number
> of times that tcg must spill and fill them from backing store.
>
> This patch set is relative to the "Improve sparc register windows"
> patches, which turned all of the integer registers into TCG globals.
> Thus this patch set improves the effect of the previous patch set.
>
> As a byproduct, I also implement the bulk of the interesting v9 ASIs
> inline, thus exposing e.g. the little-endian loads and stores as
> simple tcg operations.

Ho hum.  I dunno what's wrong today, but "git send-email" is
throwing lots of errors for me today.

If in doubt, the complete tree is at

   git://github.com/rth7680/qemu.git tgt-sparc


r~

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH 00/25] target-sparc improvements
  2015-12-17 20:54 [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
                   ` (17 preceding siblings ...)
  2015-12-17 23:13 ` [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
@ 2015-12-29 18:59 ` Mark Cave-Ayland
  2016-01-08 15:08   ` Richard Henderson
  18 siblings, 1 reply; 29+ messages in thread
From: Mark Cave-Ayland @ 2015-12-29 18:59 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: aurelien

On 17/12/15 20:54, Richard Henderson wrote:

> The primary focus of this patch set is to reduce the number of
> helpers that modify TCG globals, and thus increase the lifetime
> of those globals within each TB, and thus decrease the number
> of times that tcg must spill and fill them from backing store.
> 
> This patch set is relative to the "Improve sparc register windows"
> patches, which turned all of the integer registers into TCG globals.
> Thus this patch set improves the effect of the previous patch set.
> 
> As a byproduct, I also implement the bulk of the interesting v9 ASIs
> inline, thus exposing e.g. the little-endian loads and stores as
> simple tcg operations.
> 
> 
> r~
> 
> 
> Richard Henderson (25):
>   target-sparc: Mark more flags for helpers
>   target-sparc: Remove softint as a TCG global
>   target-sparc: Store mmu index in TB flags
>   target-sparc: Create gen_exception
>   target-sparc: Unify asi handling between 32 and 64-bit
>   target-sparc: Store %asi in TB flags
>   target-sparc: Introduce get_asi
>   target-sparc: Pass TCGMemOp to gen_ld/st_asi
>   target-sparc: Import linux/arch/sparc/include/uapi/asm/asi.h
>   target-sparc: Add UA2011 defines to asi.h
>   target-sparc: Use defines from asi.h
>   target-sparc: Add MMU_REAL_IDX
>   target-sparc: Directly implement easy ld/st asis
>   target-sparc: Use QT0 to return results from ldda
>   target-sparc: Introduce gen_check_align
>   target-sparc: Directly implement easy ldd/std asis
>   target-sparc: Fix obvious error in ASI_M_BFILL
>   target-sparc: Pass TCGMemOp constants to helper_ld/st_asi
>   target-sparc: Directly implement easy ldf/stf asis
>   target-sparc: Directly implement block and short ldf/stf asis
>   target-sparc: Remove helper_ldf_asi, helper_stf_asi
>   target-sparc: Use explicit writes to cpu_fsr
>   target-sparc: Use cpu_fsr in stfsr
>   target-sparc: Use cpu_loop_exit_restore from
>     helper_check_ieee_exceptions
>   target-sparc: Elide duplicate updates to fprs
> 
>  target-sparc/asi.h         |  311 +++++++++++
>  target-sparc/cpu.h         |   46 +-
>  target-sparc/fop_helper.c  |  229 +++-----
>  target-sparc/helper.h      |  168 +++---
>  target-sparc/ldst_helper.c |  696 +++++++++++-------------
>  target-sparc/mmu_helper.c  |   90 ++--
>  target-sparc/translate.c   | 1264 ++++++++++++++++++++++++++++----------------
>  7 files changed, 1667 insertions(+), 1137 deletions(-)
>  create mode 100644 target-sparc/asi.h

Hi Richard,

I've given your tgt-sparc branch a good run with my OpenBIOS test suite,
and I don't see any regressions here so this is looking good from my
point of view. As a general comment, qemu-system-sparc64 feels
noticeably slicker with this patchset applied.

Also with SPARC32 this branch apparently fixes at least one bug since my
pre-installed Solaris 8 image will now start X windows (although it
still hangs for long periods of time - but I believe that is the
long-standing MUTEX_HELD bug rather than anything new).

If there are explicit bug-fixes related to above then my preference
would be to have them as a separate patchset outside of the performance
improvements, but then if this isn't feasible then I don't feel that
this should block getting this patches applied to master.

Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>

Thanks once again for all your work on this!


ATB,

Mark.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH 00/25] target-sparc improvements
  2015-12-29 18:59 ` Mark Cave-Ayland
@ 2016-01-08 15:08   ` Richard Henderson
  2016-01-15 20:44     ` Artyom Tarasenko
  0 siblings, 1 reply; 29+ messages in thread
From: Richard Henderson @ 2016-01-08 15:08 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel; +Cc: aurelien

On 12/29/2015 10:59 AM, Mark Cave-Ayland wrote:
> If there are explicit bug-fixes related to above then my preference
> would be to have them as a separate patchset outside of the performance
> improvements, but then if this isn't feasible then I don't feel that
> this should block getting this patches applied to master.

Heh.  If there are bugs fixed, it's accidental.  I was attempting to preserve
behaviour with each patch.  I wonder what changed...


r~

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH 12/25] target-sparc: Add MMU_REAL_IDX
  2015-12-17 20:57 ` [Qemu-devel] [PATCH 12/25] target-sparc: Add MMU_REAL_IDX Richard Henderson
@ 2016-01-11 11:15   ` Artyom Tarasenko
  2016-01-11 12:01     ` Artyom Tarasenko
  0 siblings, 1 reply; 29+ messages in thread
From: Artyom Tarasenko @ 2016-01-11 11:15 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Mark Cave-Ayland, qemu-devel, Aurelien Jarno

Hi Richard,

first of all, this is a very nice series.
I really enjoy reading it, thank you very much.
It makes the code is more readable and likely to be more performant.
A nitpick below.

On Thu, Dec 17, 2015 at 9:57 PM, Richard Henderson <rth@twiddle.net> wrote:
> This gives us a trivial way to access physical addresses
> (aka "real addresses", in sun4v terminology) directly from
> qemu_ld/st, without having to go through another helper.
>
> This also fixes a bug in get_physical_address_code where
> it inferred NUCLEUS from env->tl instead of from mmu_idx.
>
> Signed-off-by: Richard Henderson <rth@twiddle.net>
> ---
>  target-sparc/cpu.h        | 18 +++++++---
>  target-sparc/mmu_helper.c | 90 +++++++++++++++++++++++++++++------------------
>  2 files changed, 69 insertions(+), 39 deletions(-)
>
> diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
> index 7f4d47f..b1222a1 100644
> --- a/target-sparc/cpu.h
> +++ b/target-sparc/cpu.h
> @@ -220,9 +220,9 @@ enum {
>  #define MAX_NWINDOWS 32
>
>  #if !defined(TARGET_SPARC64)
> -#define NB_MMU_MODES 2
> +#define NB_MMU_MODES 3
>  #else
> -#define NB_MMU_MODES 6
> +#define NB_MMU_MODES 7
>  typedef struct trap_state {
>      uint64_t tpc;
>      uint64_t tnpc;
> @@ -612,11 +612,13 @@ int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
>  #define MMU_MODE4_SUFFIX _nucleus
>  #define MMU_HYPV_IDX   5
>  #define MMU_MODE5_SUFFIX _hypv
> +#define MMU_REAL_IDX   6
>  #else
>  #define MMU_USER_IDX   0
>  #define MMU_MODE0_SUFFIX _user
>  #define MMU_KERNEL_IDX 1
>  #define MMU_MODE1_SUFFIX _kernel
> +#define MMU_REAL_IDX   2
>  #endif
>
>  #if defined (TARGET_SPARC64)
> @@ -641,9 +643,17 @@ static inline int cpu_mmu_index(CPUSPARCState *env1, bool ifetch)
>  #if defined(CONFIG_USER_ONLY)
>      return MMU_USER_IDX;
>  #elif !defined(TARGET_SPARC64)
> -    return env1->psrs;
> +    if (!(env1->mmuregs[0] & MMU_E)) {
> +        return MMU_REAL_IDX; /* MMU disabled */
> +    } else {
> +        return env1->psrs;
> +    }
>  #else
> -    if (env1->tl > 0) {
> +    if (ifetch
> +        ? !(env1->lsu & IMMU_E) || (env1->pstate & PS_RED)
> +        : !(env1->lsu & DMMU_E)) {
> +        return MMU_REAL_IDX; /* MMU disabled */
> +    } else if (env1->tl > 0) {
>          return MMU_NUCLEUS_IDX;
>      } else if (cpu_hypervisor_mode(env1)) {
>          return MMU_HYPV_IDX;
> diff --git a/target-sparc/mmu_helper.c b/target-sparc/mmu_helper.c
> index 7495406..105f00d 100644
> --- a/target-sparc/mmu_helper.c
> +++ b/target-sparc/mmu_helper.c
> @@ -90,7 +90,7 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
>
>      is_user = mmu_idx == MMU_USER_IDX;
>
> -    if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
> +    if (mmu_idx == MMU_REAL_IDX) { /* MMU bypass access */
>          *page_size = TARGET_PAGE_SIZE;
>          /* Boot mode: instruction fetches are taken from PROM */
>          if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
> @@ -492,33 +492,40 @@ static int get_physical_address_data(CPUSPARCState *env,
>      unsigned int i;
>      uint64_t context;
>      uint64_t sfsr = 0;
> +    bool is_user = false;
>
> -    int is_user = (mmu_idx == MMU_USER_IDX ||
> -                   mmu_idx == MMU_USER_SECONDARY_IDX);
> -
> -    if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */

^^^^

in case of ASI instructions, mmu_idx can come from dc->mem_idx, right?
So the check may be still necessary here,

> +    switch (mmu_idx) {
> +    case MMU_REAL_IDX:
> +        /* MMU bypass access */
>          *physical = ultrasparc_truncate_physical(address);
> -        *prot = PAGE_READ | PAGE_WRITE;
> +        *prot = PAGE_EXEC | PAGE_READ | PAGE_WRITE;
>          return 0;
> -    }
>
> -    switch (mmu_idx) {
> +    case MMU_NUCLEUS_IDX:
> +        sfsr |= SFSR_CT_NUCLEUS;
> +        /* fallthru */
> +    case MMU_HYPV_IDX:
> +        /* No context. */
> +        context = 0;
> +        break;
>      case MMU_USER_IDX:
> +        is_user = true;
> +        /* fallthru */
>      case MMU_KERNEL_IDX:
> +        /* PRIMARY context */
>          context = env->dmmu.mmu_primary_context & 0x1fff;
>          sfsr |= SFSR_CT_PRIMARY;
>          break;
>      case MMU_USER_SECONDARY_IDX:
> +        is_user = true;
> +        /* fallthru */
>      case MMU_KERNEL_SECONDARY_IDX:
> +        /* PRIMARY context */
>          context = env->dmmu.mmu_secondary_context & 0x1fff;
>          sfsr |= SFSR_CT_SECONDARY;
>          break;
> -    case MMU_NUCLEUS_IDX:
> -        sfsr |= SFSR_CT_NUCLEUS;
> -        /* FALLTHRU */
>      default:
> -        context = 0;
> -        break;
> +        g_assert_not_reached();
>      }
>
>      if (rw == 1) {
> @@ -573,8 +580,8 @@ static int get_physical_address_data(CPUSPARCState *env,
>              }
>
>              if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
> -                sfsr |= SFSR_OW_BIT; /* overflow (not read before
> -                                        another fault) */
> +                /* overflow (not read before another fault) */
> +                sfsr |= SFSR_OW_BIT;
>              }
>
>              if (env->pstate & PS_PRIV) {
> @@ -611,23 +618,41 @@ static int get_physical_address_code(CPUSPARCState *env,
>      CPUState *cs = CPU(sparc_env_get_cpu(env));
>      unsigned int i;
>      uint64_t context;
> +    uint64_t sfsr = 0;
> +    bool is_user = false;
>
> -    int is_user = (mmu_idx == MMU_USER_IDX ||
> -                   mmu_idx == MMU_USER_SECONDARY_IDX);
> -
> -    if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
> -        /* IMMU disabled */

and here.

Artyom

> +    switch (mmu_idx) {
> +    case MMU_REAL_IDX:
> +        /* MMU bypass access */
>          *physical = ultrasparc_truncate_physical(address);
> -        *prot = PAGE_EXEC;
> +        *prot = PAGE_EXEC | PAGE_READ | PAGE_WRITE;
>          return 0;
> -    }
>
> -    if (env->tl == 0) {
> +    case MMU_NUCLEUS_IDX:
> +        sfsr |= SFSR_CT_NUCLEUS;
> +        /* fallthru */
> +    case MMU_HYPV_IDX:
> +        /* No context. */
> +        context = 0;
> +        break;
> +    case MMU_USER_IDX:
> +        is_user = true;
> +        /* fallthru */
> +    case MMU_KERNEL_IDX:
>          /* PRIMARY context */
>          context = env->dmmu.mmu_primary_context & 0x1fff;
> -    } else {
> -        /* NUCLEUS context */
> -        context = 0;
> +        sfsr |= SFSR_CT_PRIMARY;
> +        break;
> +    case MMU_USER_SECONDARY_IDX:
> +        is_user = true;
> +        /* fallthru */
> +    case MMU_KERNEL_SECONDARY_IDX:
> +        /* PRIMARY context */
> +        context = env->dmmu.mmu_secondary_context & 0x1fff;
> +        sfsr |= SFSR_CT_SECONDARY;
> +        break;
> +    default:
> +        g_assert_not_reached();
>      }
>
>      for (i = 0; i < 64; i++) {
> @@ -638,20 +663,15 @@ static int get_physical_address_code(CPUSPARCState *env,
>              if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
>                  /* Fault status register */
>                  if (env->immu.sfsr & SFSR_VALID_BIT) {
> -                    env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
> -                                                     another fault) */
> -                } else {
> -                    env->immu.sfsr = 0;
> +                    /* overflow (not read before another fault) */
> +                    sfsr |= SFSR_OW_BIT;
>                  }
>                  if (env->pstate & PS_PRIV) {
> -                    env->immu.sfsr |= SFSR_PR_BIT;
> -                }
> -                if (env->tl > 0) {
> -                    env->immu.sfsr |= SFSR_CT_NUCLEUS;
> +                    sfsr |= SFSR_PR_BIT;
>                  }
>
>                  /* FIXME: ASI field in SFSR must be set */
> -                env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
> +                env->immu.sfsr |= sfsr | SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
>                  cs->exception_index = TT_TFAULT;
>
>                  env->immu.tag_access = (address & ~0x1fffULL) | context;
> --
> 2.5.0
>
>



-- 
Regards,
Artyom Tarasenko

SPARC and PPC PReP under qemu blog: http://tyom.blogspot.com/search/label/qemu

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH 12/25] target-sparc: Add MMU_REAL_IDX
  2016-01-11 11:15   ` Artyom Tarasenko
@ 2016-01-11 12:01     ` Artyom Tarasenko
  0 siblings, 0 replies; 29+ messages in thread
From: Artyom Tarasenko @ 2016-01-11 12:01 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Mark Cave-Ayland, qemu-devel, Aurelien Jarno

On Mon, Jan 11, 2016 at 12:15 PM, Artyom Tarasenko <atar4qemu@gmail.com> wrote:
> Hi Richard,
>
> first of all, this is a very nice series.
> I really enjoy reading it, thank you very much.
> It makes the code is more readable and likely to be more performant.
> A nitpick below.
>
> On Thu, Dec 17, 2015 at 9:57 PM, Richard Henderson <rth@twiddle.net> wrote:
>> This gives us a trivial way to access physical addresses
>> (aka "real addresses", in sun4v terminology) directly from
>> qemu_ld/st, without having to go through another helper.
>>
>> This also fixes a bug in get_physical_address_code where
>> it inferred NUCLEUS from env->tl instead of from mmu_idx.
>>
>> Signed-off-by: Richard Henderson <rth@twiddle.net>
>> ---
>>  target-sparc/cpu.h        | 18 +++++++---
>>  target-sparc/mmu_helper.c | 90 +++++++++++++++++++++++++++++------------------
>>  2 files changed, 69 insertions(+), 39 deletions(-)
>>
>> diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
>> index 7f4d47f..b1222a1 100644
>> --- a/target-sparc/cpu.h
>> +++ b/target-sparc/cpu.h
>> @@ -220,9 +220,9 @@ enum {
>>  #define MAX_NWINDOWS 32
>>
>>  #if !defined(TARGET_SPARC64)
>> -#define NB_MMU_MODES 2
>> +#define NB_MMU_MODES 3
>>  #else
>> -#define NB_MMU_MODES 6
>> +#define NB_MMU_MODES 7
>>  typedef struct trap_state {
>>      uint64_t tpc;
>>      uint64_t tnpc;
>> @@ -612,11 +612,13 @@ int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
>>  #define MMU_MODE4_SUFFIX _nucleus
>>  #define MMU_HYPV_IDX   5
>>  #define MMU_MODE5_SUFFIX _hypv
>> +#define MMU_REAL_IDX   6
>>  #else
>>  #define MMU_USER_IDX   0
>>  #define MMU_MODE0_SUFFIX _user
>>  #define MMU_KERNEL_IDX 1
>>  #define MMU_MODE1_SUFFIX _kernel
>> +#define MMU_REAL_IDX   2
>>  #endif
>>
>>  #if defined (TARGET_SPARC64)
>> @@ -641,9 +643,17 @@ static inline int cpu_mmu_index(CPUSPARCState *env1, bool ifetch)
>>  #if defined(CONFIG_USER_ONLY)
>>      return MMU_USER_IDX;
>>  #elif !defined(TARGET_SPARC64)
>> -    return env1->psrs;
>> +    if (!(env1->mmuregs[0] & MMU_E)) {
>> +        return MMU_REAL_IDX; /* MMU disabled */
>> +    } else {
>> +        return env1->psrs;
>> +    }
>>  #else
>> -    if (env1->tl > 0) {
>> +    if (ifetch
>> +        ? !(env1->lsu & IMMU_E) || (env1->pstate & PS_RED)
>> +        : !(env1->lsu & DMMU_E)) {
>> +        return MMU_REAL_IDX; /* MMU disabled */
>> +    } else if (env1->tl > 0) {
>>          return MMU_NUCLEUS_IDX;
>>      } else if (cpu_hypervisor_mode(env1)) {
>>          return MMU_HYPV_IDX;
>> diff --git a/target-sparc/mmu_helper.c b/target-sparc/mmu_helper.c
>> index 7495406..105f00d 100644
>> --- a/target-sparc/mmu_helper.c
>> +++ b/target-sparc/mmu_helper.c
>> @@ -90,7 +90,7 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
>>
>>      is_user = mmu_idx == MMU_USER_IDX;
>>
>> -    if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
>> +    if (mmu_idx == MMU_REAL_IDX) { /* MMU bypass access */
>>          *page_size = TARGET_PAGE_SIZE;
>>          /* Boot mode: instruction fetches are taken from PROM */
>>          if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
>> @@ -492,33 +492,40 @@ static int get_physical_address_data(CPUSPARCState *env,
>>      unsigned int i;
>>      uint64_t context;
>>      uint64_t sfsr = 0;
>> +    bool is_user = false;
>>
>> -    int is_user = (mmu_idx == MMU_USER_IDX ||
>> -                   mmu_idx == MMU_USER_SECONDARY_IDX);
>> -
>> -    if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
>
> ^^^^
>
> in case of ASI instructions, mmu_idx can come from dc->mem_idx, right?
> So the check may be still necessary here,
>
>> +    switch (mmu_idx) {
>> +    case MMU_REAL_IDX:
>> +        /* MMU bypass access */
>>          *physical = ultrasparc_truncate_physical(address);
>> -        *prot = PAGE_READ | PAGE_WRITE;
>> +        *prot = PAGE_EXEC | PAGE_READ | PAGE_WRITE;
>>          return 0;
>> -    }
>>
>> -    switch (mmu_idx) {
>> +    case MMU_NUCLEUS_IDX:
>> +        sfsr |= SFSR_CT_NUCLEUS;
>> +        /* fallthru */
>> +    case MMU_HYPV_IDX:
>> +        /* No context. */
>> +        context = 0;
>> +        break;
>>      case MMU_USER_IDX:
>> +        is_user = true;
>> +        /* fallthru */
>>      case MMU_KERNEL_IDX:
>> +        /* PRIMARY context */
>>          context = env->dmmu.mmu_primary_context & 0x1fff;
>>          sfsr |= SFSR_CT_PRIMARY;
>>          break;
>>      case MMU_USER_SECONDARY_IDX:
>> +        is_user = true;
>> +        /* fallthru */
>>      case MMU_KERNEL_SECONDARY_IDX:
>> +        /* PRIMARY context */
>>          context = env->dmmu.mmu_secondary_context & 0x1fff;
>>          sfsr |= SFSR_CT_SECONDARY;
>>          break;
>> -    case MMU_NUCLEUS_IDX:
>> -        sfsr |= SFSR_CT_NUCLEUS;
>> -        /* FALLTHRU */
>>      default:
>> -        context = 0;
>> -        break;
>> +        g_assert_not_reached();
>>      }
>>
>>      if (rw == 1) {
>> @@ -573,8 +580,8 @@ static int get_physical_address_data(CPUSPARCState *env,
>>              }
>>
>>              if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
>> -                sfsr |= SFSR_OW_BIT; /* overflow (not read before
>> -                                        another fault) */
>> +                /* overflow (not read before another fault) */
>> +                sfsr |= SFSR_OW_BIT;
>>              }
>>
>>              if (env->pstate & PS_PRIV) {
>> @@ -611,23 +618,41 @@ static int get_physical_address_code(CPUSPARCState *env,
>>      CPUState *cs = CPU(sparc_env_get_cpu(env));
>>      unsigned int i;
>>      uint64_t context;
>> +    uint64_t sfsr = 0;
>> +    bool is_user = false;
>>
>> -    int is_user = (mmu_idx == MMU_USER_IDX ||
>> -                   mmu_idx == MMU_USER_SECONDARY_IDX);
>> -
>> -    if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
>> -        /* IMMU disabled */
>
> and here.

On a second thought, IMMU check is not necessary, because there is no
ASI access for instructions.
So, here no check is necessary, only above.

Artyom
>
>> +    switch (mmu_idx) {
>> +    case MMU_REAL_IDX:
>> +        /* MMU bypass access */
>>          *physical = ultrasparc_truncate_physical(address);
>> -        *prot = PAGE_EXEC;
>> +        *prot = PAGE_EXEC | PAGE_READ | PAGE_WRITE;
>>          return 0;
>> -    }
>>
>> -    if (env->tl == 0) {
>> +    case MMU_NUCLEUS_IDX:
>> +        sfsr |= SFSR_CT_NUCLEUS;
>> +        /* fallthru */
>> +    case MMU_HYPV_IDX:
>> +        /* No context. */
>> +        context = 0;
>> +        break;
>> +    case MMU_USER_IDX:
>> +        is_user = true;
>> +        /* fallthru */
>> +    case MMU_KERNEL_IDX:
>>          /* PRIMARY context */
>>          context = env->dmmu.mmu_primary_context & 0x1fff;
>> -    } else {
>> -        /* NUCLEUS context */
>> -        context = 0;
>> +        sfsr |= SFSR_CT_PRIMARY;
>> +        break;
>> +    case MMU_USER_SECONDARY_IDX:
>> +        is_user = true;
>> +        /* fallthru */
>> +    case MMU_KERNEL_SECONDARY_IDX:
>> +        /* PRIMARY context */
>> +        context = env->dmmu.mmu_secondary_context & 0x1fff;
>> +        sfsr |= SFSR_CT_SECONDARY;
>> +        break;
>> +    default:
>> +        g_assert_not_reached();
>>      }
>>
>>      for (i = 0; i < 64; i++) {
>> @@ -638,20 +663,15 @@ static int get_physical_address_code(CPUSPARCState *env,
>>              if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
>>                  /* Fault status register */
>>                  if (env->immu.sfsr & SFSR_VALID_BIT) {
>> -                    env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
>> -                                                     another fault) */
>> -                } else {
>> -                    env->immu.sfsr = 0;
>> +                    /* overflow (not read before another fault) */
>> +                    sfsr |= SFSR_OW_BIT;
>>                  }
>>                  if (env->pstate & PS_PRIV) {
>> -                    env->immu.sfsr |= SFSR_PR_BIT;
>> -                }
>> -                if (env->tl > 0) {
>> -                    env->immu.sfsr |= SFSR_CT_NUCLEUS;
>> +                    sfsr |= SFSR_PR_BIT;
>>                  }
>>
>>                  /* FIXME: ASI field in SFSR must be set */
>> -                env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
>> +                env->immu.sfsr |= sfsr | SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
>>                  cs->exception_index = TT_TFAULT;
>>
>>                  env->immu.tag_access = (address & ~0x1fffULL) | context;
>> --
>> 2.5.0
>>
>>
>
>
>
> --
> Regards,
> Artyom Tarasenko
>
> SPARC and PPC PReP under qemu blog: http://tyom.blogspot.com/search/label/qemu

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH 10/25] target-sparc: Add UA2011 defines to asi.h
  2015-12-17 20:56 ` [Qemu-devel] [PATCH 10/25] target-sparc: Add UA2011 defines to asi.h Richard Henderson
@ 2016-01-12 13:17   ` Artyom Tarasenko
  0 siblings, 0 replies; 29+ messages in thread
From: Artyom Tarasenko @ 2016-01-12 13:17 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Mark Cave-Ayland, qemu-devel, Aurelien Jarno

I have a weak suggestion we call them UA2005 defines,
because all of them are already described in UA2005 and
the commit message can make it easier to distinguish what ASIs have to
be implemented for UST1+ and what on UST4+ only).

Otherwise,

Reviewed-By: Artyom Tarasenko <atar4qemu@gmail.com>

On Thu, Dec 17, 2015 at 9:56 PM, Richard Henderson <rth@twiddle.net> wrote:
> Signed-off-by: Richard Henderson <rth@twiddle.net>
> ---
>  target-sparc/asi.h | 22 ++++++++++++++++++----
>  1 file changed, 18 insertions(+), 4 deletions(-)
>
> diff --git a/target-sparc/asi.h b/target-sparc/asi.h
> index aace6f3..c9a1849 100644
> --- a/target-sparc/asi.h
> +++ b/target-sparc/asi.h
> @@ -144,24 +144,36 @@
>   * ASIs, "(4V)" designates SUN4V specific ASIs.  "(NG4)" designates SPARC-T4
>   * and later ASIs.
>   */
> +#define ASI_REAL                0x14 /* Real address, cachable          */
>  #define ASI_PHYS_USE_EC                0x14 /* PADDR, E-cachable               */
> +#define ASI_REAL_IO             0x15 /* Real address, non-cachable      */
>  #define ASI_PHYS_BYPASS_EC_E   0x15 /* PADDR, E-bit                    */
>  #define ASI_BLK_AIUP_4V                0x16 /* (4V) Prim, user, block ld/st    */
>  #define ASI_BLK_AIUS_4V                0x17 /* (4V) Sec, user, block ld/st     */
> +#define ASI_REAL_L              0x1c /* Real address, cachable, LE      */
>  #define ASI_PHYS_USE_EC_L      0x1c /* PADDR, E-cachable, little endian*/
> +#define ASI_REAL_IO_L           0x1d /* Real address, non-cachable, LE  */
>  #define ASI_PHYS_BYPASS_EC_E_L 0x1d /* PADDR, E-bit, little endian     */
>  #define ASI_BLK_AIUP_L_4V      0x1e /* (4V) Prim, user, block, l-endian*/
>  #define ASI_BLK_AIUS_L_4V      0x1f /* (4V) Sec, user, block, l-endian */
>  #define ASI_SCRATCHPAD         0x20 /* (4V) Scratch Pad Registers      */
>  #define ASI_MMU                        0x21 /* (4V) MMU Context Registers      */
> +#define ASI_TWINX_AIUP          0x22 /* twin load, primary user         */
> +#define ASI_TWINX_AIUS          0x23 /* twin load, secondary user       */
>  #define ASI_BLK_INIT_QUAD_LDD_AIUS 0x23 /* (NG) init-store, twin load,
>                                          * secondary, user
>                                          */
>  #define ASI_NUCLEUS_QUAD_LDD   0x24 /* Cachable, qword load            */
>  #define ASI_QUEUE              0x25 /* (4V) Interrupt Queue Registers  */
> +#define ASI_TWINX_REAL          0x26 /* twin load, real, cachable       */
>  #define ASI_QUAD_LDD_PHYS_4V   0x26 /* (4V) Physical, qword load       */
> +#define ASI_TWINX_N             0x27 /* twin load, nucleus              */
> +#define ASI_TWINX_AIUP_L        0x2a /* twin load, primary user, LE     */
> +#define ASI_TWINX_AIUS_L        0x2b /* twin load, secondary user, LE   */
>  #define ASI_NUCLEUS_QUAD_LDD_L 0x2c /* Cachable, qword load, l-endian  */
> +#define ASI_TWINX_REAL_L        0x2e /* twin load, real, cachable, LE   */
>  #define ASI_QUAD_LDD_PHYS_L_4V 0x2e /* (4V) Phys, qword load, l-endian */
> +#define ASI_TWINX_NL            0x2f /* twin load, nucleus, LE          */
>  #define ASI_PCACHE_DATA_STATUS 0x30 /* (III) PCache data stat RAM diag */
>  #define ASI_PCACHE_DATA                0x31 /* (III) PCache data RAM diag      */
>  #define ASI_PCACHE_TAG         0x32 /* (III) PCache tag RAM diag       */
> @@ -267,12 +279,14 @@
>  #define ASI_FL16_SL            0xdb /* Secondary, 1 16-bit, fpu ld/st,L*/
>  #define ASI_BLK_COMMIT_P       0xe0 /* Primary, blk store commit       */
>  #define ASI_BLK_COMMIT_S       0xe1 /* Secondary, blk store commit     */
> +#define ASI_TWINX_P             0xe2 /* twin load, primary implicit     */
>  #define ASI_BLK_INIT_QUAD_LDD_P        0xe2 /* (NG) init-store, twin load,
> -                                     * primary, implicit
> -                                     */
> +                                     * primary, implicit */
> +#define ASI_TWINX_S             0xe3 /* twin load, secondary implicit   */
>  #define ASI_BLK_INIT_QUAD_LDD_S        0xe3 /* (NG) init-store, twin load,
> -                                     * secondary, implicit
> -                                     */
> +                                     * secondary, implicit */
> +#define ASI_TWINX_PL            0xea /* twin load, primary implicit, LE */
> +#define ASI_TWINX_SL            0xeb /* twin load, secondary implicit, LE */
>  #define ASI_BLK_P              0xf0 /* Primary, blk ld/st              */
>  #define ASI_BLK_S              0xf1 /* Secondary, blk ld/st            */
>  #define ASI_ST_BLKINIT_MRU_P   0xf2 /* (NG4) init-store, twin load,
> --
> 2.5.0
>
>



-- 
Regards,
Artyom Tarasenko

SPARC and PPC PReP under qemu blog: http://tyom.blogspot.com/search/label/qemu

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH 00/25] target-sparc improvements
  2016-01-08 15:08   ` Richard Henderson
@ 2016-01-15 20:44     ` Artyom Tarasenko
  0 siblings, 0 replies; 29+ messages in thread
From: Artyom Tarasenko @ 2016-01-15 20:44 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Mark Cave-Ayland, qemu-devel, Aurelien Jarno

On Fri, Jan 8, 2016 at 4:08 PM, Richard Henderson <rth@twiddle.net> wrote:
> On 12/29/2015 10:59 AM, Mark Cave-Ayland wrote:
>> If there are explicit bug-fixes related to above then my preference
>> would be to have them as a separate patchset outside of the performance
>> improvements, but then if this isn't feasible then I don't feel that
>> this should block getting this patches applied to master.
>
> Heh.  If there are bugs fixed, it's accidental.  I was attempting to preserve
> behaviour with each patch.  I wonder what changed...

Actually I observe a regression in the patch 13/25 (which btw seems
not to have make it to the list).
A quick attempt to debug it didn't succeed: from a log it looks like
the corruption happens after a 'nop' instruction, and setting a
breakpoint changes the behavior (optimizer bug?)
I'll send you a reproducer off list.

-- 
Regards,
Artyom Tarasenko

SPARC and PPC PReP under qemu blog: http://tyom.blogspot.com/search/label/qemu

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH 12/25] target-sparc: Add MMU_REAL_IDX
  2016-01-15 20:32   ` Artyom Tarasenko
@ 2016-01-15 21:47     ` Richard Henderson
  0 siblings, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2016-01-15 21:47 UTC (permalink / raw)
  To: Artyom Tarasenko; +Cc: Mark Cave-Ayland, qemu-devel, Aurelien Jarno

On 01/15/2016 12:32 PM, Artyom Tarasenko wrote:
>> If we ever properly implement a sun4v platform, we will implement the bulk of
>> the hypervisor within qemu itself, for speed.  At which point REAL will in fact
>> undergo that final layer of translation exactly as expected.
>>
>> I think the naming is exactly correct, for the current sun4u implementation.
> 
> But sun4u has neither real mode nor any ASI having "real" as a part of
> its name, no?

Correct-ish.  The ASI is called ASI_PHYS_USE_EC.  But it has the same number as
ASI_REAL.  When there's a conflict I'm preferring the newer names.  I think
that it will cause less confusion in the end.


> I thought it is much easier to implement the RA translation than the hypervisor,
> but maybe implementing the hypervisor is not as complex as I thought.
> 
> Indeed, your variant would be more performant.
> In any case it looks like an interesting challenge.

The Alpha PALcode layer (equivalent to the sun4v hypervisor) is 99% implemented
in qemu, and performs significantly better because of it.
There are a few stubs in the qemu bios calling into some special helpers; I'd
expect OpenBIOS for qemu to be the same.



r~

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH 12/25] target-sparc: Add MMU_REAL_IDX
  2016-01-15 18:03 ` Richard Henderson
@ 2016-01-15 20:32   ` Artyom Tarasenko
  2016-01-15 21:47     ` Richard Henderson
  0 siblings, 1 reply; 29+ messages in thread
From: Artyom Tarasenko @ 2016-01-15 20:32 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Mark Cave-Ayland, qemu-devel, Aurelien Jarno

On Fri, Jan 15, 2016 at 7:03 PM, Richard Henderson <rth@twiddle.net> wrote:
> On 01/15/2016 05:17 AM, Artyom Tarasenko wrote:
>> Hi Richard,
>>
>> please ignore my 2 previous mails: I've misread the commit message.
>> The actual problem and a possible solution below.
>>
>> On Thu, Dec 17, 2015 at 9:57 PM, Richard Henderson <rth@twiddle.net> wrote:
>>> This gives us a trivial way to access physical addresses
>>> (aka "real addresses", in sun4v terminology)
>>
>> In sun4v terminology "real address" is not "physical addresses".
>> There is just one more level of translation:
>> VA->RA->PA
>> which it's only visible from the hypervisor mode.
>
> Correct, but...
>
>> With MMU_REAL_IDX renamed to MMU_PHYS_IDX, I think we are fine.
>
> ... no.  REAL is currently implemented as PHYS, true, but that's only because
> we don't actually implemnet sun4v.
>
> If we ever properly implement a sun4v platform, we will implement the bulk of
> the hypervisor within qemu itself, for speed.  At which point REAL will in fact
> undergo that final layer of translation exactly as expected.
>
> I think the naming is exactly correct, for the current sun4u implementation.

But sun4u has neither real mode nor any ASI having "real" as a part of
its name, no?

>> (As I was reading this patch the last time, I thought the plan was to
>> use the MMU_REAL_IDX for both real and physical accesses, hence the
>> confusion. But using one index for two modes would have been a bad
>> idea because we'd have to flush the translations every time we switch
>> to/from hypervisor mode which is too often).
>
> And that is exactly why hypervisor mode would not be implemented like you
> think, but within qemu itself.

In my case it is sort of implemented it like I think: few years back
I've implemented
its subset (incomplete but capable to boot the OpenSPARC firmware)
and have been trying to merge it with your work. :-)

I thought it is much easier to implement the RA translation than the hypervisor,
but maybe implementing the hypervisor is not as complex as I thought.

Indeed, your variant would be more performant.
In any case it looks like an interesting challenge.

I'd still prefer to call it MMU_PHYS_IDX for now and rename it once
the hypervisor layer is implemented.
But I'm not insisting on the naming. The naming issues are always hard. :-)

-- 
Regards,
Artyom Tarasenko

SPARC and PPC PReP under qemu blog: http://tyom.blogspot.com/search/label/qemu

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH 12/25] target-sparc: Add MMU_REAL_IDX
  2016-01-15 13:17 [Qemu-devel] [PATCH 12/25] target-sparc: Add MMU_REAL_IDX Artyom Tarasenko
@ 2016-01-15 18:03 ` Richard Henderson
  2016-01-15 20:32   ` Artyom Tarasenko
  0 siblings, 1 reply; 29+ messages in thread
From: Richard Henderson @ 2016-01-15 18:03 UTC (permalink / raw)
  To: Artyom Tarasenko, Mark Cave-Ayland; +Cc: qemu-devel, Aurelien Jarno

On 01/15/2016 05:17 AM, Artyom Tarasenko wrote:
> Hi Richard,
> 
> please ignore my 2 previous mails: I've misread the commit message.
> The actual problem and a possible solution below.
> 
> On Thu, Dec 17, 2015 at 9:57 PM, Richard Henderson <rth@twiddle.net> wrote:
>> This gives us a trivial way to access physical addresses
>> (aka "real addresses", in sun4v terminology)
> 
> In sun4v terminology "real address" is not "physical addresses".
> There is just one more level of translation:
> VA->RA->PA
> which it's only visible from the hypervisor mode.

Correct, but...

> With MMU_REAL_IDX renamed to MMU_PHYS_IDX, I think we are fine.

... no.  REAL is currently implemented as PHYS, true, but that's only because
we don't actually implemnet sun4v.

If we ever properly implement a sun4v platform, we will implement the bulk of
the hypervisor within qemu itself, for speed.  At which point REAL will in fact
undergo that final layer of translation exactly as expected.

I think the naming is exactly correct, for the current sun4u implementation.

> (As I was reading this patch the last time, I thought the plan was to
> use the MMU_REAL_IDX for both real and physical accesses, hence the
> confusion. But using one index for two modes would have been a bad
> idea because we'd have to flush the translations every time we switch
> to/from hypervisor mode which is too often).

And that is exactly why hypervisor mode would not be implemented like you
think, but within qemu itself.


r~

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH 12/25] target-sparc: Add MMU_REAL_IDX
@ 2016-01-15 13:17 Artyom Tarasenko
  2016-01-15 18:03 ` Richard Henderson
  0 siblings, 1 reply; 29+ messages in thread
From: Artyom Tarasenko @ 2016-01-15 13:17 UTC (permalink / raw)
  To: Richard Henderson, Mark Cave-Ayland; +Cc: qemu-devel, Aurelien Jarno

Hi Richard,

please ignore my 2 previous mails: I've misread the commit message.
The actual problem and a possible solution below.

On Thu, Dec 17, 2015 at 9:57 PM, Richard Henderson <rth@twiddle.net> wrote:
> This gives us a trivial way to access physical addresses
> (aka "real addresses", in sun4v terminology)

In sun4v terminology "real address" is not "physical addresses".
There is just one more level of translation:
VA->RA->PA
which it's only visible from the hypervisor mode.

But I see where the confusion is coming from:
to make the hypervisor presence transparent for the existing sun4u drivers,
Sun mapped all sun4u ASIs that used to access physical space, to
access real space in sun4v instead.
This way every virtual machine (a "partition" in sun4v terminology)
may have it's own pseudo-physical ("real") space without overlapping
with other virtual machines.
I.e. "ASI_PHYS_USE_EC_L" became "ASI_REAL_L" which triggers one more
translation and so on.

The support of sun4v in current QEMU is very rudimentary, so if we
just ignore it for the moment and focus on sun4u, the approach of this
patch is correct, except for the naming.
With MMU_REAL_IDX renamed to MMU_PHYS_IDX, I think we are fine.

I suggest we keep sun4v names also for the sun4u ASIs (as in this
series) because having different names for sun4u and sun4v would make
the code ugly: it's not possible to #ifdef them because the
sun4u/sun4v cpu/mmu type is a runtime information [1].

Luckily I'm not a maintainer, so it's up to you guys to decide.

As for the sun4v support, I think, we can add one more index, this
time the real MMU_REAL_IDX, which can only be used by sun4v MMU(s).

(As I was reading this patch the last time, I thought the plan was to
use the MMU_REAL_IDX for both real and physical accesses, hence the
confusion. But using one index for two modes would have been a bad
idea because we'd have to flush the translations every time we switch
to/from hypervisor mode which is too often).

Kind regards,
Artyom

1. https://lists.gnu.org/archive/html/qemu-devel/2012-04/msg04281.html

> directly from
> qemu_ld/st, without having to go through another helper.
>
> This also fixes a bug in get_physical_address_code where
> it inferred NUCLEUS from env->tl instead of from mmu_idx.
>
> Signed-off-by: Richard Henderson <rth@twiddle.net>
> ---
>  target-sparc/cpu.h        | 18 +++++++---
>  target-sparc/mmu_helper.c | 90 +++++++++++++++++++++++++++++------------------
>  2 files changed, 69 insertions(+), 39 deletions(-)
>
> diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
> index 7f4d47f..b1222a1 100644
> --- a/target-sparc/cpu.h
> +++ b/target-sparc/cpu.h
> @@ -220,9 +220,9 @@ enum {
>  #define MAX_NWINDOWS 32
>
>  #if !defined(TARGET_SPARC64)
> -#define NB_MMU_MODES 2
> +#define NB_MMU_MODES 3
>  #else
> -#define NB_MMU_MODES 6
> +#define NB_MMU_MODES 7
>  typedef struct trap_state {
>      uint64_t tpc;
>      uint64_t tnpc;
> @@ -612,11 +612,13 @@ int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
>  #define MMU_MODE4_SUFFIX _nucleus
>  #define MMU_HYPV_IDX   5
>  #define MMU_MODE5_SUFFIX _hypv
> +#define MMU_REAL_IDX   6
>  #else
>  #define MMU_USER_IDX   0
>  #define MMU_MODE0_SUFFIX _user
>  #define MMU_KERNEL_IDX 1
>  #define MMU_MODE1_SUFFIX _kernel
> +#define MMU_REAL_IDX   2
>  #endif
>
>  #if defined (TARGET_SPARC64)
> @@ -641,9 +643,17 @@ static inline int cpu_mmu_index(CPUSPARCState *env1, bool ifetch)
>  #if defined(CONFIG_USER_ONLY)
>      return MMU_USER_IDX;
>  #elif !defined(TARGET_SPARC64)
> -    return env1->psrs;
> +    if (!(env1->mmuregs[0] & MMU_E)) {
> +        return MMU_REAL_IDX; /* MMU disabled */
> +    } else {
> +        return env1->psrs;
> +    }
>  #else
> -    if (env1->tl > 0) {
> +    if (ifetch
> +        ? !(env1->lsu & IMMU_E) || (env1->pstate & PS_RED)
> +        : !(env1->lsu & DMMU_E)) {
> +        return MMU_REAL_IDX; /* MMU disabled */
> +    } else if (env1->tl > 0) {
>          return MMU_NUCLEUS_IDX;
>      } else if (cpu_hypervisor_mode(env1)) {
>          return MMU_HYPV_IDX;
> diff --git a/target-sparc/mmu_helper.c b/target-sparc/mmu_helper.c
> index 7495406..105f00d 100644
> --- a/target-sparc/mmu_helper.c
> +++ b/target-sparc/mmu_helper.c
> @@ -90,7 +90,7 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
>
>      is_user = mmu_idx == MMU_USER_IDX;
>
> -    if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
> +    if (mmu_idx == MMU_REAL_IDX) { /* MMU bypass access */
>          *page_size = TARGET_PAGE_SIZE;
>          /* Boot mode: instruction fetches are taken from PROM */
>          if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
> @@ -492,33 +492,40 @@ static int get_physical_address_data(CPUSPARCState *env,
>      unsigned int i;
>      uint64_t context;
>      uint64_t sfsr = 0;
> +    bool is_user = false;
>
> -    int is_user = (mmu_idx == MMU_USER_IDX ||
> -                   mmu_idx == MMU_USER_SECONDARY_IDX);
> -
> -    if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
> +    switch (mmu_idx) {
> +    case MMU_REAL_IDX:
> +        /* MMU bypass access */
>          *physical = ultrasparc_truncate_physical(address);
> -        *prot = PAGE_READ | PAGE_WRITE;
> +        *prot = PAGE_EXEC | PAGE_READ | PAGE_WRITE;
>          return 0;
> -    }
>
> -    switch (mmu_idx) {
> +    case MMU_NUCLEUS_IDX:
> +        sfsr |= SFSR_CT_NUCLEUS;
> +        /* fallthru */
> +    case MMU_HYPV_IDX:
> +        /* No context. */
> +        context = 0;
> +        break;
>      case MMU_USER_IDX:
> +        is_user = true;
> +        /* fallthru */
>      case MMU_KERNEL_IDX:
> +        /* PRIMARY context */
>          context = env->dmmu.mmu_primary_context & 0x1fff;
>          sfsr |= SFSR_CT_PRIMARY;
>          break;
>      case MMU_USER_SECONDARY_IDX:
> +        is_user = true;
> +        /* fallthru */
>      case MMU_KERNEL_SECONDARY_IDX:
> +        /* PRIMARY context */
>          context = env->dmmu.mmu_secondary_context & 0x1fff;
>          sfsr |= SFSR_CT_SECONDARY;
>          break;
> -    case MMU_NUCLEUS_IDX:
> -        sfsr |= SFSR_CT_NUCLEUS;
> -        /* FALLTHRU */
>      default:
> -        context = 0;
> -        break;
> +        g_assert_not_reached();
>      }
>
>      if (rw == 1) {
> @@ -573,8 +580,8 @@ static int get_physical_address_data(CPUSPARCState *env,
>              }
>
>              if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
> -                sfsr |= SFSR_OW_BIT; /* overflow (not read before
> -                                        another fault) */
> +                /* overflow (not read before another fault) */
> +                sfsr |= SFSR_OW_BIT;
>              }
>
>              if (env->pstate & PS_PRIV) {
> @@ -611,23 +618,41 @@ static int get_physical_address_code(CPUSPARCState *env,
>      CPUState *cs = CPU(sparc_env_get_cpu(env));
>      unsigned int i;
>      uint64_t context;
> +    uint64_t sfsr = 0;
> +    bool is_user = false;
>
> -    int is_user = (mmu_idx == MMU_USER_IDX ||
> -                   mmu_idx == MMU_USER_SECONDARY_IDX);
> -
> -    if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
> -        /* IMMU disabled */
> +    switch (mmu_idx) {
> +    case MMU_REAL_IDX:
> +        /* MMU bypass access */
>          *physical = ultrasparc_truncate_physical(address);
> -        *prot = PAGE_EXEC;
> +        *prot = PAGE_EXEC | PAGE_READ | PAGE_WRITE;
>          return 0;
> -    }
>
> -    if (env->tl == 0) {
> +    case MMU_NUCLEUS_IDX:
> +        sfsr |= SFSR_CT_NUCLEUS;
> +        /* fallthru */
> +    case MMU_HYPV_IDX:
> +        /* No context. */
> +        context = 0;
> +        break;
> +    case MMU_USER_IDX:
> +        is_user = true;
> +        /* fallthru */
> +    case MMU_KERNEL_IDX:
>          /* PRIMARY context */
>          context = env->dmmu.mmu_primary_context & 0x1fff;
> -    } else {
> -        /* NUCLEUS context */
> -        context = 0;
> +        sfsr |= SFSR_CT_PRIMARY;
> +        break;
> +    case MMU_USER_SECONDARY_IDX:
> +        is_user = true;
> +        /* fallthru */
> +    case MMU_KERNEL_SECONDARY_IDX:
> +        /* PRIMARY context */
> +        context = env->dmmu.mmu_secondary_context & 0x1fff;
> +        sfsr |= SFSR_CT_SECONDARY;
> +        break;
> +    default:
> +        g_assert_not_reached();
>      }
>
>      for (i = 0; i < 64; i++) {
> @@ -638,20 +663,15 @@ static int get_physical_address_code(CPUSPARCState *env,
>              if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
>                  /* Fault status register */
>                  if (env->immu.sfsr & SFSR_VALID_BIT) {
> -                    env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
> -                                                     another fault) */
> -                } else {
> -                    env->immu.sfsr = 0;
> +                    /* overflow (not read before another fault) */
> +                    sfsr |= SFSR_OW_BIT;
>                  }
>                  if (env->pstate & PS_PRIV) {
> -                    env->immu.sfsr |= SFSR_PR_BIT;
> -                }
> -                if (env->tl > 0) {
> -                    env->immu.sfsr |= SFSR_CT_NUCLEUS;
> +                    sfsr |= SFSR_PR_BIT;
>                  }
>
>                  /* FIXME: ASI field in SFSR must be set */
> -                env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
> +                env->immu.sfsr |= sfsr | SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
>                  cs->exception_index = TT_TFAULT;
>
>                  env->immu.tag_access = (address & ~0x1fffULL) | context;
> --
> 2.5.0
>
>


-- 
Regards,
Artyom Tarasenko

SPARC and PPC PReP under qemu blog: http://tyom.blogspot.com/search/label/qemu

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2016-01-15 21:47 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-17 20:54 [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
2015-12-17 20:54 ` [Qemu-devel] [PATCH 01/25] target-sparc: Mark more flags for helpers Richard Henderson
2015-12-17 20:54 ` [Qemu-devel] [PATCH 02/25] target-sparc: Remove softint as a TCG global Richard Henderson
2015-12-17 20:54 ` [Qemu-devel] [PATCH 03/25] target-sparc: Store mmu index in TB flags Richard Henderson
2015-12-17 20:54 ` [Qemu-devel] [PATCH 04/25] target-sparc: Create gen_exception Richard Henderson
2015-12-17 20:56 ` [Qemu-devel] [PATCH 10/25] target-sparc: Add UA2011 defines to asi.h Richard Henderson
2016-01-12 13:17   ` Artyom Tarasenko
2015-12-17 20:57 ` [Qemu-devel] [PATCH 12/25] target-sparc: Add MMU_REAL_IDX Richard Henderson
2016-01-11 11:15   ` Artyom Tarasenko
2016-01-11 12:01     ` Artyom Tarasenko
2015-12-17 20:57 ` [Qemu-devel] [PATCH 14/25] target-sparc: Use QT0 to return results from ldda Richard Henderson
2015-12-17 20:57 ` [Qemu-devel] [PATCH 15/25] target-sparc: Introduce gen_check_align Richard Henderson
2015-12-17 20:57 ` [Qemu-devel] [PATCH 17/25] target-sparc: Fix obvious error in ASI_M_BFILL Richard Henderson
2015-12-17 20:57 ` [Qemu-devel] [PATCH 19/25] target-sparc: Directly implement easy ldf/stf asis Richard Henderson
2015-12-17 20:57 ` [Qemu-devel] [PATCH 20/25] target-sparc: Directly implement block and short " Richard Henderson
2015-12-17 20:57 ` [Qemu-devel] [PATCH 21/25] target-sparc: Remove helper_ldf_asi, helper_stf_asi Richard Henderson
2015-12-17 20:57 ` [Qemu-devel] [PATCH 23/25] target-sparc: Use cpu_fsr in stfsr Richard Henderson
2015-12-17 20:57 ` [Qemu-devel] [PATCH 24/25] target-sparc: Use cpu_loop_exit_restore from helper_check_ieee_exceptions Richard Henderson
2015-12-17 20:57 ` [Qemu-devel] [PATCH 25/25] target-sparc: Elide duplicate updates to fprs Richard Henderson
2015-12-17 23:11 ` [Qemu-devel] [PATCH 06/25] target-sparc: Store %asi in TB flags Richard Henderson
2015-12-17 23:11 ` [Qemu-devel] [PATCH 08/25] target-sparc: Pass TCGMemOp to gen_ld/st_asi Richard Henderson
2015-12-17 23:13 ` [Qemu-devel] [PATCH 00/25] target-sparc improvements Richard Henderson
2015-12-29 18:59 ` Mark Cave-Ayland
2016-01-08 15:08   ` Richard Henderson
2016-01-15 20:44     ` Artyom Tarasenko
2016-01-15 13:17 [Qemu-devel] [PATCH 12/25] target-sparc: Add MMU_REAL_IDX Artyom Tarasenko
2016-01-15 18:03 ` Richard Henderson
2016-01-15 20:32   ` Artyom Tarasenko
2016-01-15 21:47     ` Richard Henderson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.