Message ID | 1566216496-17375-6-git-send-email-aleksandar.markovic@rt-rk.com |
---|---|
State | New |
Headers | show |
Series | target/mips: Misc patches for 4.2 | expand |
On Monday, August 19, 2019, Aleksandar Markovic < aleksandar.markovic@rt-rk.com> wrote: > From: Yongbok Kim <yongbok.kim@mips.com> > > Add emulation of MIPS' CRC32 (Cyclic Redundancy Check) instructions. > Reuse zlib crc32() and Linux crc32c(). Note that, at the time being, > there is no MIPS CPU that supports CRC32 instructions (they are an > optional part of MIPS64/32 R6 anf nanoMIPS ISAs). > > Signed-off-by: Yongbok Kim <yongbok.kim@mips.com> > Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com> > --- > disas/mips.c | 8 ++++++++ > target/mips/helper.h | 2 ++ > target/mips/op_helper.c | 22 ++++++++++++++++++++++ > target/mips/translate.c | 41 +++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 73 insertions(+) > > This solution is not optimal (see arm equivalent). Also, support for nanomips crc instructions is not included. In spite of that: Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com> All outstanding issues will be handled post-4.2. diff --git a/disas/mips.c b/disas/mips.c > index c3a3059..b9a5204 100644 > --- a/disas/mips.c > +++ b/disas/mips.c > @@ -1411,6 +1411,14 @@ const struct mips_opcode mips_builtin_opcodes[] = > {"evp", "t", 0x41600004, 0xffe0ffff, TRAP|WR_t, 0, > I32R6}, > {"ginvi", "v", 0x7c00003d, 0xfc1ffcff, TRAP | INSN_TLB, 0, > I32R6}, > {"ginvt", "v", 0x7c0000bd, 0xfc1ffcff, TRAP | INSN_TLB, 0, > I32R6}, > +{"crc32b", "t,v,t", 0x7c00000f, 0xfc00ff3f, WR_d | RD_s | RD_t, 0, > I32R6}, > +{"crc32h", "t,v,t", 0x7c00004f, 0xfc00ff3f, WR_d | RD_s | RD_t, 0, > I32R6}, > +{"crc32w", "t,v,t", 0x7c00008f, 0xfc00ff3f, WR_d | RD_s | RD_t, 0, > I32R6}, > +{"crc32d", "t,v,t", 0x7c0000cf, 0xfc00ff3f, WR_d | RD_s | RD_t, 0, > I64R6}, > +{"crc32cb", "t,v,t", 0x7c00010f, 0xfc00ff3f, WR_d | RD_s | RD_t, 0, > I32R6}, > +{"crc32ch", "t,v,t", 0x7c00014f, 0xfc00ff3f, WR_d | RD_s | RD_t, 0, > I32R6}, > +{"crc32cw", "t,v,t", 0x7c00018f, 0xfc00ff3f, WR_d | RD_s | RD_t, 0, > I32R6}, > +{"crc32cd", "t,v,t", 0x7c0001cf, 0xfc00ff3f, WR_d | RD_s | RD_t, 0, > I64R6}, > > /* MSA */ > {"sll.b", "+d,+e,+f", 0x7800000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, > MSA}, > diff --git a/target/mips/helper.h b/target/mips/helper.h > index c7d35bd..0e61043 100644 > --- a/target/mips/helper.h > +++ b/target/mips/helper.h > @@ -40,6 +40,8 @@ DEF_HELPER_FLAGS_1(bitswap, TCG_CALL_NO_RWG_SE, tl, tl) > DEF_HELPER_FLAGS_1(dbitswap, TCG_CALL_NO_RWG_SE, tl, tl) > #endif > > +DEF_HELPER_3(crc32, tl, tl, tl, i32) > +DEF_HELPER_3(crc32c, tl, tl, tl, i32) > DEF_HELPER_FLAGS_4(rotx, TCG_CALL_NO_RWG_SE, tl, tl, i32, i32, i32) > > #ifndef CONFIG_USER_ONLY > diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c > index 3104904..5874029 100644 > --- a/target/mips/op_helper.c > +++ b/target/mips/op_helper.c > @@ -25,6 +25,8 @@ > #include "exec/exec-all.h" > #include "exec/cpu_ldst.h" > #include "sysemu/kvm.h" > +#include "qemu/crc32c.h" > +#include <zlib.h> > > /*********************************************************** > ******************/ > /* Exceptions processing helpers */ > @@ -343,6 +345,26 @@ target_ulong helper_rotx(target_ulong rs, uint32_t > shift, uint32_t shiftx, > return (int64_t)(int32_t)(uint32_t)tmp5; > } > > +/* these crc32 functions are based on target/arm/helper-a64.c */ > +target_ulong helper_crc32(target_ulong val, target_ulong m, uint32_t sz) > +{ > + uint8_t buf[8]; > + target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - > 1); > + > + m &= mask; > + stq_le_p(buf, m); > + return (int32_t) (crc32(val ^ 0xffffffff, buf, sz) ^ 0xffffffff); > +} > + > +target_ulong helper_crc32c(target_ulong val, target_ulong m, uint32_t sz) > +{ > + uint8_t buf[8]; > + target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - > 1); > + m &= mask; > + stq_le_p(buf, m); > + return (int32_t) (crc32c(val, buf, sz) ^ 0xffffffff); > +} > + > #ifndef CONFIG_USER_ONLY > > static inline hwaddr do_translate_address(CPUMIPSState *env, > diff --git a/target/mips/translate.c b/target/mips/translate.c > index 3f73be0..3f9f113 100644 > --- a/target/mips/translate.c > +++ b/target/mips/translate.c > @@ -452,6 +452,7 @@ enum { > OPC_LWE = 0x2F | OPC_SPECIAL3, > > /* R6 */ > + OPC_CRC32 = 0x0F | OPC_SPECIAL3, > R6_OPC_PREF = 0x35 | OPC_SPECIAL3, > R6_OPC_CACHE = 0x25 | OPC_SPECIAL3, > R6_OPC_LL = 0x36 | OPC_SPECIAL3, > @@ -2550,6 +2551,7 @@ typedef struct DisasContext { > bool saar; > bool mi; > int gi; > + bool crcp; > } DisasContext; > > #define DISAS_STOP DISAS_TARGET_0 > @@ -27041,6 +27043,33 @@ static void decode_opc_special2_legacy(CPUMIPSState > *env, DisasContext *ctx) > } > } > > +static void gen_crc32(DisasContext *ctx, int rd, int rs, int rt, int sz, > + int crc32c) > +{ > + TCGv t0; > + TCGv t1; > + TCGv_i32 tsz = tcg_const_i32(1 << sz); > + if (rd == 0) { > + /* Treat as NOP. */ > + return; > + } > + t0 = tcg_temp_new(); > + t1 = tcg_temp_new(); > + > + gen_load_gpr(t0, rt); > + gen_load_gpr(t1, rs); > + > + if (crc32c) { > + gen_helper_crc32c(cpu_gpr[rd], t0, t1, tsz); > + } else { > + gen_helper_crc32(cpu_gpr[rd], t0, t1, tsz); > + } > + > + tcg_temp_free(t0); > + tcg_temp_free(t1); > + tcg_temp_free_i32(tsz); > +} > + > static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx) > { > int rs, rt, rd, sa; > @@ -27055,6 +27084,17 @@ static void decode_opc_special3_r6(CPUMIPSState > *env, DisasContext *ctx) > > op1 = MASK_SPECIAL3(ctx->opcode); > switch (op1) { > + case OPC_CRC32: > + if (unlikely(!ctx->crcp) || > + unlikely((extract32(ctx->opcode, 6, 2) == 3) && > + (!(ctx->hflags & MIPS_HFLAG_64))) || > + unlikely((extract32(ctx->opcode, 8, 3) >= 2))) { > + generate_exception_end(ctx, EXCP_RI); > + } > + gen_crc32(ctx, rt, rs, rt, > + extract32(ctx->opcode, 6, 2), > + extract32(ctx->opcode, 8, 3)); > + break; > case R6_OPC_PREF: > if (rt >= 24) { > /* hint codes 24-31 are reserved and signal RI */ > @@ -30049,6 +30089,7 @@ static void mips_tr_init_disas_context(DisasContextBase > *dcbase, CPUState *cs) > ctx->abs2008 = (env->active_fpu.fcr31 >> FCR31_ABS2008) & 1; > ctx->mi = (env->CP0_Config5 >> CP0C5_MI) & 1; > ctx->gi = (env->CP0_Config5 >> CP0C5_GI) & 3; > + ctx->crcp = (env->CP0_Config5 >> CP0C5_CRCP) & 1; > restore_cpu_state(env, ctx); > #ifdef CONFIG_USER_ONLY > ctx->mem_idx = MIPS_HFLAG_UM; > -- > 2.7.4 > > >
diff --git a/disas/mips.c b/disas/mips.c index c3a3059..b9a5204 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -1411,6 +1411,14 @@ const struct mips_opcode mips_builtin_opcodes[] = {"evp", "t", 0x41600004, 0xffe0ffff, TRAP|WR_t, 0, I32R6}, {"ginvi", "v", 0x7c00003d, 0xfc1ffcff, TRAP | INSN_TLB, 0, I32R6}, {"ginvt", "v", 0x7c0000bd, 0xfc1ffcff, TRAP | INSN_TLB, 0, I32R6}, +{"crc32b", "t,v,t", 0x7c00000f, 0xfc00ff3f, WR_d | RD_s | RD_t, 0, I32R6}, +{"crc32h", "t,v,t", 0x7c00004f, 0xfc00ff3f, WR_d | RD_s | RD_t, 0, I32R6}, +{"crc32w", "t,v,t", 0x7c00008f, 0xfc00ff3f, WR_d | RD_s | RD_t, 0, I32R6}, +{"crc32d", "t,v,t", 0x7c0000cf, 0xfc00ff3f, WR_d | RD_s | RD_t, 0, I64R6}, +{"crc32cb", "t,v,t", 0x7c00010f, 0xfc00ff3f, WR_d | RD_s | RD_t, 0, I32R6}, +{"crc32ch", "t,v,t", 0x7c00014f, 0xfc00ff3f, WR_d | RD_s | RD_t, 0, I32R6}, +{"crc32cw", "t,v,t", 0x7c00018f, 0xfc00ff3f, WR_d | RD_s | RD_t, 0, I32R6}, +{"crc32cd", "t,v,t", 0x7c0001cf, 0xfc00ff3f, WR_d | RD_s | RD_t, 0, I64R6}, /* MSA */ {"sll.b", "+d,+e,+f", 0x7800000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, diff --git a/target/mips/helper.h b/target/mips/helper.h index c7d35bd..0e61043 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -40,6 +40,8 @@ DEF_HELPER_FLAGS_1(bitswap, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(dbitswap, TCG_CALL_NO_RWG_SE, tl, tl) #endif +DEF_HELPER_3(crc32, tl, tl, tl, i32) +DEF_HELPER_3(crc32c, tl, tl, tl, i32) DEF_HELPER_FLAGS_4(rotx, TCG_CALL_NO_RWG_SE, tl, tl, i32, i32, i32) #ifndef CONFIG_USER_ONLY diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c index 3104904..5874029 100644 --- a/target/mips/op_helper.c +++ b/target/mips/op_helper.c @@ -25,6 +25,8 @@ #include "exec/exec-all.h" #include "exec/cpu_ldst.h" #include "sysemu/kvm.h" +#include "qemu/crc32c.h" +#include <zlib.h> /*****************************************************************************/ /* Exceptions processing helpers */ @@ -343,6 +345,26 @@ target_ulong helper_rotx(target_ulong rs, uint32_t shift, uint32_t shiftx, return (int64_t)(int32_t)(uint32_t)tmp5; } +/* these crc32 functions are based on target/arm/helper-a64.c */ +target_ulong helper_crc32(target_ulong val, target_ulong m, uint32_t sz) +{ + uint8_t buf[8]; + target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1); + + m &= mask; + stq_le_p(buf, m); + return (int32_t) (crc32(val ^ 0xffffffff, buf, sz) ^ 0xffffffff); +} + +target_ulong helper_crc32c(target_ulong val, target_ulong m, uint32_t sz) +{ + uint8_t buf[8]; + target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1); + m &= mask; + stq_le_p(buf, m); + return (int32_t) (crc32c(val, buf, sz) ^ 0xffffffff); +} + #ifndef CONFIG_USER_ONLY static inline hwaddr do_translate_address(CPUMIPSState *env, diff --git a/target/mips/translate.c b/target/mips/translate.c index 3f73be0..3f9f113 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -452,6 +452,7 @@ enum { OPC_LWE = 0x2F | OPC_SPECIAL3, /* R6 */ + OPC_CRC32 = 0x0F | OPC_SPECIAL3, R6_OPC_PREF = 0x35 | OPC_SPECIAL3, R6_OPC_CACHE = 0x25 | OPC_SPECIAL3, R6_OPC_LL = 0x36 | OPC_SPECIAL3, @@ -2550,6 +2551,7 @@ typedef struct DisasContext { bool saar; bool mi; int gi; + bool crcp; } DisasContext; #define DISAS_STOP DISAS_TARGET_0 @@ -27041,6 +27043,33 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx) } } +static void gen_crc32(DisasContext *ctx, int rd, int rs, int rt, int sz, + int crc32c) +{ + TCGv t0; + TCGv t1; + TCGv_i32 tsz = tcg_const_i32(1 << sz); + if (rd == 0) { + /* Treat as NOP. */ + return; + } + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + + gen_load_gpr(t0, rt); + gen_load_gpr(t1, rs); + + if (crc32c) { + gen_helper_crc32c(cpu_gpr[rd], t0, t1, tsz); + } else { + gen_helper_crc32(cpu_gpr[rd], t0, t1, tsz); + } + + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free_i32(tsz); +} + static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx) { int rs, rt, rd, sa; @@ -27055,6 +27084,17 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx) op1 = MASK_SPECIAL3(ctx->opcode); switch (op1) { + case OPC_CRC32: + if (unlikely(!ctx->crcp) || + unlikely((extract32(ctx->opcode, 6, 2) == 3) && + (!(ctx->hflags & MIPS_HFLAG_64))) || + unlikely((extract32(ctx->opcode, 8, 3) >= 2))) { + generate_exception_end(ctx, EXCP_RI); + } + gen_crc32(ctx, rt, rs, rt, + extract32(ctx->opcode, 6, 2), + extract32(ctx->opcode, 8, 3)); + break; case R6_OPC_PREF: if (rt >= 24) { /* hint codes 24-31 are reserved and signal RI */ @@ -30049,6 +30089,7 @@ static void mips_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->abs2008 = (env->active_fpu.fcr31 >> FCR31_ABS2008) & 1; ctx->mi = (env->CP0_Config5 >> CP0C5_MI) & 1; ctx->gi = (env->CP0_Config5 >> CP0C5_GI) & 3; + ctx->crcp = (env->CP0_Config5 >> CP0C5_CRCP) & 1; restore_cpu_state(env, ctx); #ifdef CONFIG_USER_ONLY ctx->mem_idx = MIPS_HFLAG_UM;