@@ -46,6 +46,7 @@ DEF_HELPER_FLAGS_3(stmw, TCG_CALL_NO_WG, void, env, tl, i32)
DEF_HELPER_4(lsw, void, env, tl, i32, i32)
DEF_HELPER_5(lswx, void, env, tl, i32, i32, i32)
DEF_HELPER_FLAGS_4(stsw, TCG_CALL_NO_WG, void, env, tl, i32, i32)
+DEF_HELPER_FLAGS_2(dcbz_size, TCG_CALL_NO_WG_SE, tl, env, i32)
DEF_HELPER_FLAGS_3(dcbz, TCG_CALL_NO_WG, void, env, tl, i32)
DEF_HELPER_FLAGS_3(dcbzep, TCG_CALL_NO_WG, void, env, tl, i32)
DEF_HELPER_FLAGS_2(icbi, TCG_CALL_NO_WG, void, env, tl)
@@ -270,6 +270,20 @@ void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
}
}
+target_ulong helper_dcbz_size(CPUPPCState *env, uint32_t opcode)
+{
+ target_ulong dcbz_size = env->dcache_line_size;
+
+#if defined(TARGET_PPC64)
+ /* Check for dcbz vs dcbzl on 970 */
+ if (env->excp_model == POWERPC_EXCP_970 &&
+ !(opcode & 0x00200000) && ((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
+ dcbz_size = 32;
+ }
+#endif
+ return dcbz_size;
+}
+
static void dcbz_common(CPUPPCState *env, target_ulong addr,
uint32_t opcode, bool epid, uintptr_t retaddr)
{
@@ -4445,14 +4445,36 @@ static void gen_dcblc(DisasContext *ctx)
/* dcbz */
static void gen_dcbz(DisasContext *ctx)
{
- TCGv tcgv_addr;
- TCGv_i32 tcgv_op;
+ TCGv addr, mask, dcbz_size, t0;
+ TCGv_i32 op = tcg_constant_i32(ctx->opcode & 0x03FF000);
+ TCGv_i64 z64 = tcg_constant_i64(0);
+ TCGv_i128 z128 = tcg_temp_new_i128();
+ TCGLabel *l;
+
+ addr = tcg_temp_new();
+ mask = tcg_temp_new();
+ dcbz_size = tcg_temp_new();
+ t0 = tcg_temp_new();
+ l = gen_new_label();
gen_set_access_type(ctx, ACCESS_CACHE);
- tcgv_addr = tcg_temp_new();
- tcgv_op = tcg_constant_i32(ctx->opcode & 0x03FF000);
- gen_addr_reg_index(ctx, tcgv_addr);
- gen_helper_dcbz(tcg_env, tcgv_addr, tcgv_op);
+ gen_helper_dcbz_size(dcbz_size, tcg_env, op);
+ tcg_gen_mov_tl(mask, dcbz_size);
+ tcg_gen_subi_tl(mask, mask, 1);
+ tcg_gen_not_tl(mask, mask);
+ gen_addr_reg_index(ctx, addr);
+ tcg_gen_and_tl(addr, addr, mask);
+ tcg_gen_mov_tl(t0, cpu_reserve);
+ tcg_gen_and_tl(t0, t0, mask);
+ tcg_gen_movcond_tl(TCG_COND_EQ, cpu_reserve, addr, t0,
+ tcg_constant_tl(-1), cpu_reserve);
+
+ tcg_gen_concat_i64_i128(z128, z64, z64);
+ gen_set_label(l);
+ tcg_gen_qemu_st_i128(z128, addr, ctx->mem_idx, DEF_MEMOP(MO_128));
+ tcg_gen_addi_tl(addr, addr, 16);
+ tcg_gen_subi_tl(dcbz_size, dcbz_size, 16);
+ tcg_gen_brcondi_tl(TCG_COND_GT, dcbz_size, 0, l);
}
/* dcbzep */
This is an RFC patch, not finished, just to show the idea and test this approach. I'm not sure it's correct but I'm sure it can be improved so comments are requested. The test case I've used came out of a discussion about very slow access to VRAM of a graphics card passed through with vfio the reason for which is still not clear but it was already known that dcbz is often used by MacOS and AmigaOS for clearing memory and to avoid reading values about to be overwritten which is faster on real CPU but was found to be slower on QEMU. The optimised copy routines were posted here: https://www.amigans.net/modules/newbb/viewtopic.php?post_id=149123#forumpost149123 and the rest of it I've written to make it a test case is here: http://zero.eik.bme.hu/~balaton/qemu/vramcopy.tar.xz Replace the body of has_altivec() with just "return false". Sorry for only giving pieces but the code posted above has a copyright that does not allow me to include it in the test. This is not measuring VRAM access now just memory copy but shows the effect of dcbz. I've got these results with this patch: Linux user master: Linux user patch: byte loop: 2.2 sec byte loop: 2.2 sec memcpy: 2.19 sec memcpy: 2.19 sec copyToVRAMNoAltivec: 1.7 sec copyToVRAMNoAltivec: 1.71 sec copyToVRAMAltivec: 2.13 sec copyToVRAMAltivec: 2.12 sec copyFromVRAMNoAltivec: 5.11 sec copyFromVRAMNoAltivec: 2.79 sec copyFromVRAMAltivec: 5.87 sec copyFromVRAMAltivec: 3.26 sec Linux system master: Linux system patch: byte loop: 5.86 sec byte loop: 5.9 sec memcpy: 5.45 sec memcpy: 5.47 sec copyToVRAMNoAltivec: 2.51 sec copyToVRAMNoAltivec: 2.53 sec copyToVRAMAltivec: 3.84 sec copyToVRAMAltivec: 3.85 sec copyFromVRAMNoAltivec: 6.11 sec copyFromVRAMNoAltivec: 3.92 sec copyFromVRAMAltivec: 7.22 sec copyFromVRAMAltivec: 5.51 sec It could probably be further optimised with using vector instuctions (dcbz_size is between 32 and 128) or by eliminating the check left in the helper for 970 but I don't know how to do those. (Also the series that convert AltiVec to use 128 bit access may help but I haven't tested that, only trying to optimise dcbz here,) Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> --- target/ppc/helper.h | 1 + target/ppc/mem_helper.c | 14 ++++++++++++++ target/ppc/translate.c | 34 ++++++++++++++++++++++++++++------ 3 files changed, 43 insertions(+), 6 deletions(-)