diff options
author | Richard Henderson <rth@twiddle.net> | 2015-09-03 00:53:40 -0700 |
---|---|---|
committer | Richard Henderson <rth@twiddle.net> | 2016-07-12 11:02:27 -0700 |
commit | f0913be04be13cfb4f9341ae79e035fc8479fd28 (patch) | |
tree | 856422b512902706566537ffcbf7ee0616259cee /target-sparc | |
parent | 0cc1f4bf76a20c7fee0bab5c9bba9ad7302198b5 (diff) | |
download | qemu-f0913be04be13cfb4f9341ae79e035fc8479fd28.zip qemu-f0913be04be13cfb4f9341ae79e035fc8479fd28.tar.gz qemu-f0913be04be13cfb4f9341ae79e035fc8479fd28.tar.bz2 |
target-sparc: Directly implement easy ld/st asis
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Richard Henderson <rth@twiddle.net>
Diffstat (limited to 'target-sparc')
-rw-r--r-- | target-sparc/translate.c | 104 |
1 files changed, 90 insertions, 14 deletions
diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 8865864..55364ad 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1980,17 +1980,21 @@ static inline void gen_ne_fop_QD(DisasContext *dc, int rd, int rs, typedef enum { GET_ASI_HELPER, GET_ASI_EXCP, + GET_ASI_DIRECT, } ASIType; typedef struct { ASIType type; int asi; + int mem_idx; + TCGMemOp memop; } DisasASI; -static DisasASI get_asi(DisasContext *dc, int insn) +static DisasASI get_asi(DisasContext *dc, int insn, TCGMemOp memop) { int asi = GET_FIELD(insn, 19, 26); ASIType type = GET_ASI_HELPER; + int mem_idx = dc->mem_idx; #ifndef TARGET_SPARC64 /* Before v9, all asis are immediate and privileged. */ @@ -2004,6 +2008,16 @@ static DisasASI get_asi(DisasContext *dc, int insn) for LEON, which is incorrect. */ || (asi == ASI_USERDATA && (dc->def->features & CPU_FEATURE_CASA))) { + switch (asi) { + case ASI_USERDATA: /* User data access */ + mem_idx = MMU_USER_IDX; + type = GET_ASI_DIRECT; + break; + case ASI_KERNELDATA: /* Supervisor data access */ + mem_idx = MMU_KERNEL_IDX; + type = GET_ASI_DIRECT; + break; + } } else { gen_exception(dc, TT_PRIV_INSN); type = GET_ASI_EXCP; @@ -2012,19 +2026,77 @@ static DisasASI get_asi(DisasContext *dc, int insn) if (IS_IMM) { asi = dc->asi; } + /* With v9, all asis below 0x80 are privileged. */ + /* ??? We ought to check cpu_has_hypervisor, but we didn't copy + down that bit into DisasContext. For the moment that's ok, + since the direct implementations below doesn't have any ASIs + in the restricted [0x30, 0x7f] range, and the check will be + done properly in the helper. */ + if (!supervisor(dc) && asi < 0x80) { + gen_exception(dc, TT_PRIV_ACT); + type = GET_ASI_EXCP; + } else { + switch (asi) { + case ASI_N: /* Nucleus */ + case ASI_NL: /* Nucleus LE */ + mem_idx = MMU_NUCLEUS_IDX; + break; + case ASI_AIUP: /* As if user primary */ + case ASI_AIUPL: /* As if user primary LE */ + mem_idx = MMU_USER_IDX; + break; + case ASI_AIUS: /* As if user secondary */ + case ASI_AIUSL: /* As if user secondary LE */ + mem_idx = MMU_USER_SECONDARY_IDX; + break; + case ASI_S: /* Secondary */ + case ASI_SL: /* Secondary LE */ + if (mem_idx == MMU_USER_IDX) { + mem_idx = MMU_USER_SECONDARY_IDX; + } else if (mem_idx == MMU_KERNEL_IDX) { + mem_idx = MMU_KERNEL_SECONDARY_IDX; + } + break; + case ASI_P: /* Primary */ + case ASI_PL: /* Primary LE */ + break; + } + switch (asi) { + case ASI_N: + case ASI_NL: + case ASI_AIUP: + case ASI_AIUPL: + case ASI_AIUS: + case ASI_AIUSL: + case ASI_S: + case ASI_SL: + case ASI_P: + case ASI_PL: + type = GET_ASI_DIRECT; + break; + } + /* The little-endian asis all have bit 3 set. */ + if (asi & 8) { + memop ^= MO_BSWAP; + } + } #endif - return (DisasASI){ type, asi }; + return (DisasASI){ type, asi, mem_idx, memop }; } static void gen_ld_asi(DisasContext *dc, TCGv dst, TCGv addr, int insn, TCGMemOp memop) { - DisasASI da = get_asi(dc, insn); + DisasASI da = get_asi(dc, insn, memop); switch (da.type) { case GET_ASI_EXCP: break; + case GET_ASI_DIRECT: + gen_address_mask(dc, addr); + tcg_gen_qemu_ld_tl(dst, addr, da.mem_idx, da.memop); + break; default: { TCGv_i32 r_asi = tcg_const_i32(da.asi); @@ -2053,11 +2125,15 @@ static void gen_ld_asi(DisasContext *dc, TCGv dst, TCGv addr, static void gen_st_asi(DisasContext *dc, TCGv src, TCGv addr, int insn, TCGMemOp memop) { - DisasASI da = get_asi(dc, insn); + DisasASI da = get_asi(dc, insn, memop); switch (da.type) { case GET_ASI_EXCP: break; + case GET_ASI_DIRECT: + gen_address_mask(dc, addr); + tcg_gen_qemu_st_tl(src, addr, da.mem_idx, da.memop); + break; default: { TCGv_i32 r_asi = tcg_const_i32(da.asi); @@ -2087,7 +2163,7 @@ static void gen_st_asi(DisasContext *dc, TCGv src, TCGv addr, static void gen_swap_asi(DisasContext *dc, TCGv dst, TCGv src, TCGv addr, int insn) { - DisasASI da = get_asi(dc, insn); + DisasASI da = get_asi(dc, insn, MO_TEUL); switch (da.type) { case GET_ASI_EXCP: @@ -2121,7 +2197,7 @@ static void gen_swap_asi(DisasContext *dc, TCGv dst, TCGv src, static void gen_cas_asi(DisasContext *dc, TCGv addr, TCGv val2, int insn, int rd) { - DisasASI da = get_asi(dc, insn); + DisasASI da = get_asi(dc, insn, MO_TEUL); TCGv val1, dst; TCGv_i32 r_asi; @@ -2140,7 +2216,7 @@ static void gen_cas_asi(DisasContext *dc, TCGv addr, TCGv val2, static void gen_ldstub_asi(DisasContext *dc, TCGv dst, TCGv addr, int insn) { - DisasASI da = get_asi(dc, insn); + DisasASI da = get_asi(dc, insn, MO_UB); switch (da.type) { case GET_ASI_EXCP: @@ -2175,7 +2251,7 @@ static void gen_ldstub_asi(DisasContext *dc, TCGv dst, TCGv addr, int insn) static void gen_ldf_asi(DisasContext *dc, TCGv addr, int insn, int size, int rd) { - DisasASI da = get_asi(dc, insn); + DisasASI da = get_asi(dc, insn, (size == 4 ? MO_TEUL : MO_TEQ)); switch (da.type) { case GET_ASI_EXCP: @@ -2199,7 +2275,7 @@ static void gen_ldf_asi(DisasContext *dc, TCGv addr, static void gen_stf_asi(DisasContext *dc, TCGv addr, int insn, int size, int rd) { - DisasASI da = get_asi(dc, insn); + DisasASI da = get_asi(dc, insn, (size == 4 ? MO_TEUL : MO_TEQ)); switch (da.type) { case GET_ASI_EXCP: @@ -2223,7 +2299,7 @@ static void gen_stf_asi(DisasContext *dc, TCGv addr, static void gen_ldda_asi(DisasContext *dc, TCGv hi, TCGv addr, int insn, int rd) { - DisasASI da = get_asi(dc, insn); + DisasASI da = get_asi(dc, insn, MO_TEQ); switch (da.type) { case GET_ASI_EXCP: @@ -2245,7 +2321,7 @@ static void gen_ldda_asi(DisasContext *dc, TCGv hi, TCGv addr, static void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr, int insn, int rd) { - DisasASI da = get_asi(dc, insn); + DisasASI da = get_asi(dc, insn, MO_TEQ); TCGv lo = gen_load_gpr(dc, rd + 1); switch (da.type) { @@ -2273,7 +2349,7 @@ static void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr, static void gen_casx_asi(DisasContext *dc, TCGv addr, TCGv val2, int insn, int rd) { - DisasASI da = get_asi(dc, insn); + DisasASI da = get_asi(dc, insn, MO_TEQ); TCGv val1 = gen_load_gpr(dc, rd); TCGv dst = gen_dest_gpr(dc, rd); TCGv_i32 r_asi; @@ -2297,9 +2373,9 @@ static void gen_ldda_asi(DisasContext *dc, TCGv hi, TCGv addr, whereby "rd + 1" elicits "error: array subscript is above array". Since we have already asserted that rd is even, the semantics are unchanged. */ - DisasASI da = get_asi(dc, insn); TCGv lo = gen_dest_gpr(dc, rd | 1); TCGv_i64 t64 = tcg_temp_new_i64(); + DisasASI da = get_asi(dc, insn, MO_TEQ); switch (da.type) { case GET_ASI_EXCP: @@ -2329,7 +2405,7 @@ static void gen_ldda_asi(DisasContext *dc, TCGv hi, TCGv addr, static void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr, int insn, int rd) { - DisasASI da = get_asi(dc, insn); + DisasASI da = get_asi(dc, insn, MO_TEQ); TCGv lo = gen_load_gpr(dc, rd + 1); TCGv_i64 t64 = tcg_temp_new_i64(); |