Message ID | 1579613937-5774-3-git-send-email-aleksandar.markovic@rt-rk.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | target/mips: Misc MIPS fixes and improvements for 5.0 | expand |
> From: Aleksandar Markovic <amarkovic@wavecomp.com> > > Add support for eight CRC-related MIPS<32|64>R6 instructions. > > Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com> > --- > disas/mips.c | 8 +++ > target/mips/helper.h | 2 + > target/mips/op_helper.c | 19 ++++++++ > target/mips/translate.c | 127 > ++++++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 156 insertions(+) > > diff --git a/disas/mips.c b/disas/mips.c index dfefe5e..75c48b3 100644 > --- a/disas/mips.c > +++ b/disas/mips.c > @@ -1409,6 +1409,14 @@ const struct mips_opcode mips_builtin_opcodes[] > = > {"dvp", "t", 0x41600024, 0xffe0ffff, TRAP|WR_t, 0, I32R6}, > {"evp", "", 0x41600004, 0xffffffff, TRAP, 0, I32R6}, > {"evp", "t", 0x41600004, 0xffe0ffff, TRAP|WR_t, 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 > 7b8ad74..2095330 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 > 18fcee4..5cd396d 100644 > --- a/target/mips/op_helper.c > +++ b/target/mips/op_helper.c > @@ -27,6 +27,8 @@ > #include "exec/memop.h" > #include "sysemu/kvm.h" > #include "fpu/softfloat.h" > +#include "qemu/crc32c.h" > +#include <zlib.h> > > > /********************************************************** > *******************/ > /* Exceptions processing helpers */ > @@ -350,6 +352,23 @@ 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 Shouldn't this be "HELPER(crc32)"? > +sz) { > + uint8_t buf[8]; > + > + 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 Shouldn't this be "HELPER(crc32c)"? > +sz) { > + uint8_t buf[8]; > + > + 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 4bff585..1b38356 > 100644 > --- a/target/mips/translate.c > +++ b/target/mips/translate.c > @@ -451,6 +451,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, > @@ -2547,6 +2548,7 @@ typedef struct DisasContext { > bool nan2008; > bool abs2008; > bool saar; > + bool crcp; > } DisasContext; > > #define DISAS_STOP DISAS_TARGET_0 > @@ -27117,11 +27119,96 @@ 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); > + uint64_t mask = 0; Should be uint32_t > + > + if (rd == 0) { > + /* Treat as NOP. */ Need to free tsz on this path or wait to assign with t0/t1 > + return; > + } > + t0 = tcg_temp_new(); > + t1 = tcg_temp_new(); > + > + gen_load_gpr(t0, rt); > + gen_load_gpr(t1, rs); > + > + if (sz != 3) { > + switch (sz) { > + case 0: > + mask = 0xFF; > + break; > + case 1: > + mask = 0xFFFF; > + break; > + case 2: > + mask = 0xFFFFFFFF; > + break; > + } > + tcg_gen_andi_tl(t1, t1, mask); > + } > + > + 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 gen_crc32b(DisasContext *ctx, int rd, int rs, int rt) { > + gen_crc32(ctx, rd, rs, rt, 0, 0); > +} > + > +static void gen_crc32h(DisasContext *ctx, int rd, int rs, int rt) { > + gen_crc32(ctx, rd, rs, rt, 1, 0); > +} > + > +static void gen_crc32w(DisasContext *ctx, int rd, int rs, int rt) { > + gen_crc32(ctx, rd, rs, rt, 2, 0); > +} > + > +static void gen_crc32d(DisasContext *ctx, int rd, int rs, int rt) { > + gen_crc32(ctx, rd, rs, rt, 3, 0); > +} > + > +static void gen_crc32cb(DisasContext *ctx, int rd, int rs, int rt) { > + gen_crc32(ctx, rd, rs, rt, 0, 1); > +} > + > +static void gen_crc32ch(DisasContext *ctx, int rd, int rs, int rt) { > + gen_crc32(ctx, rd, rs, rt, 1, 1); > +} > + > +static void gen_crc32cw(DisasContext *ctx, int rd, int rs, int rt) { > + gen_crc32(ctx, rd, rs, rt, 2, 1); > +} > + > +static void gen_crc32cd(DisasContext *ctx, int rd, int rs, int rt) { > + gen_crc32(ctx, rd, rs, rt, 3, 1); > +} > + > static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx) > { > int rs, rt, rd, sa; > uint32_t op1, op2; > int16_t imm; > + int sz, crc32c; > > rs = (ctx->opcode >> 21) & 0x1f; > rt = (ctx->opcode >> 16) & 0x1f; > @@ -27131,6 +27218,45 @@ static void > decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx) > > op1 = MASK_SPECIAL3(ctx->opcode); > switch (op1) { > + case OPC_CRC32: > + sz = extract32(ctx->opcode, 6, 2); > + crc32c = extract32(ctx->opcode, 8, 3); > + if (unlikely(!ctx->crcp) || > + unlikely((sz == 3) && (!(ctx->hflags & MIPS_HFLAG_64))) || > + unlikely((crc32c >= 2))) { > + generate_exception_end(ctx, EXCP_RI); > + } > + switch (sz) { > + case 0: > + if (crc32c) { > + gen_crc32cb(ctx, rt, rs, rt); > + } else { > + gen_crc32b(ctx, rt, rs, rt); > + } > + break; > + case 1: > + if (crc32c) { > + gen_crc32ch(ctx, rt, rs, rt); > + } else { > + gen_crc32h(ctx, rt, rs, rt); > + } > + break; > + case 2: > + if (crc32c) { > + gen_crc32cw(ctx, rt, rs, rt); > + } else { > + gen_crc32w(ctx, rt, rs, rt); > + } > + break; > + case 3: > + if (crc32c) { > + gen_crc32cd(ctx, rt, rs, rt); > + } else { > + gen_crc32d(ctx, rt, rs, rt); > + } > + break; > + } > + break; > case R6_OPC_PREF: > if (rt >= 24) { > /* hint codes 24-31 are reserved and signal RI */ @@ -30727,6 > +30853,7 @@ static void mips_tr_init_disas_context(DisasContextBase > *dcbase, CPUState *cs) > ctx->mrp = (env->CP0_Config5 >> CP0C5_MRP) & 1; > ctx->nan2008 = (env->active_fpu.fcr31 >> FCR31_NAN2008) & 1; > ctx->abs2008 = (env->active_fpu.fcr31 >> FCR31_ABS2008) & 1; > + 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 > >
On Wed, Jan 22, 2020 at 3:17 AM Taylor Simpson <tsimpson@quicinc.com> wrote: > > > > > From: Aleksandar Markovic <amarkovic@wavecomp.com> > > > > Add support for eight CRC-related MIPS<32|64>R6 instructions. > > > > Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com> > > --- > > disas/mips.c | 8 +++ > > target/mips/helper.h | 2 + > > target/mips/op_helper.c | 19 ++++++++ > > target/mips/translate.c | 127 > > ++++++++++++++++++++++++++++++++++++++++++++++++ > > 4 files changed, 156 insertions(+) > > > > diff --git a/disas/mips.c b/disas/mips.c index dfefe5e..75c48b3 100644 > > --- a/disas/mips.c > > +++ b/disas/mips.c > > @@ -1409,6 +1409,14 @@ const struct mips_opcode mips_builtin_opcodes[] > > = > > {"dvp", "t", 0x41600024, 0xffe0ffff, TRAP|WR_t, 0, I32R6}, > > {"evp", "", 0x41600004, 0xffffffff, TRAP, 0, I32R6}, > > {"evp", "t", 0x41600004, 0xffe0ffff, TRAP|WR_t, 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 > > 7b8ad74..2095330 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 > > 18fcee4..5cd396d 100644 > > --- a/target/mips/op_helper.c > > +++ b/target/mips/op_helper.c > > @@ -27,6 +27,8 @@ > > #include "exec/memop.h" > > #include "sysemu/kvm.h" > > #include "fpu/softfloat.h" > > +#include "qemu/crc32c.h" > > +#include <zlib.h> > > > > > > /********************************************************** > > *******************/ > > /* Exceptions processing helpers */ > > @@ -350,6 +352,23 @@ 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 > > Shouldn't this be "HELPER(crc32)"? > It should. > > +sz) { > > + uint8_t buf[8]; > > + > > + 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 > > Shouldn't this be "HELPER(crc32c)"? > You are correct. It should. I will correct this in the next version. But, I plan also to refactor the code of the entire patch, so that a each CRC32 instruction (there are eight) has it own helper. > > +sz) { > > + uint8_t buf[8]; > > + > > + 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 4bff585..1b38356 > > 100644 > > --- a/target/mips/translate.c > > +++ b/target/mips/translate.c > > @@ -451,6 +451,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, > > @@ -2547,6 +2548,7 @@ typedef struct DisasContext { > > bool nan2008; > > bool abs2008; > > bool saar; > > + bool crcp; > > } DisasContext; > > > > #define DISAS_STOP DISAS_TARGET_0 > > @@ -27117,11 +27119,96 @@ 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); > > + uint64_t mask = 0; > > Should be uint32_t > It could. But, the need for this variable will I think dissapear in upcoming refactoring that I am going to do for he next version. > > + > > + if (rd == 0) { > > + /* Treat as NOP. */ > > Need to free tsz on this path or wait to assign with t0/t1 > You are absolutely right. It will be fixed. > > + return; > > + } > > + t0 = tcg_temp_new(); > > + t1 = tcg_temp_new(); > > + > > + gen_load_gpr(t0, rt); > > + gen_load_gpr(t1, rs); > > + > > + if (sz != 3) { > > + switch (sz) { > > + case 0: > > + mask = 0xFF; > > + break; > > + case 1: > > + mask = 0xFFFF; > > + break; > > + case 2: > > + mask = 0xFFFFFFFF; > > + break; > > + } > > + tcg_gen_andi_tl(t1, t1, mask); > > + } > > + > > + 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 gen_crc32b(DisasContext *ctx, int rd, int rs, int rt) { > > + gen_crc32(ctx, rd, rs, rt, 0, 0); > > +} > > + > > +static void gen_crc32h(DisasContext *ctx, int rd, int rs, int rt) { > > + gen_crc32(ctx, rd, rs, rt, 1, 0); > > +} > > + > > +static void gen_crc32w(DisasContext *ctx, int rd, int rs, int rt) { > > + gen_crc32(ctx, rd, rs, rt, 2, 0); > > +} > > + > > +static void gen_crc32d(DisasContext *ctx, int rd, int rs, int rt) { > > + gen_crc32(ctx, rd, rs, rt, 3, 0); > > +} > > + > > +static void gen_crc32cb(DisasContext *ctx, int rd, int rs, int rt) { > > + gen_crc32(ctx, rd, rs, rt, 0, 1); > > +} > > + > > +static void gen_crc32ch(DisasContext *ctx, int rd, int rs, int rt) { > > + gen_crc32(ctx, rd, rs, rt, 1, 1); > > +} > > + > > +static void gen_crc32cw(DisasContext *ctx, int rd, int rs, int rt) { > > + gen_crc32(ctx, rd, rs, rt, 2, 1); > > +} > > + > > +static void gen_crc32cd(DisasContext *ctx, int rd, int rs, int rt) { > > + gen_crc32(ctx, rd, rs, rt, 3, 1); > > +} > > + > > static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx) > > { > > int rs, rt, rd, sa; > > uint32_t op1, op2; > > int16_t imm; > > + int sz, crc32c; > > > > rs = (ctx->opcode >> 21) & 0x1f; > > rt = (ctx->opcode >> 16) & 0x1f; > > @@ -27131,6 +27218,45 @@ static void > > decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx) > > > > op1 = MASK_SPECIAL3(ctx->opcode); > > switch (op1) { > > + case OPC_CRC32: > > + sz = extract32(ctx->opcode, 6, 2); > > + crc32c = extract32(ctx->opcode, 8, 3); > > + if (unlikely(!ctx->crcp) || > > + unlikely((sz == 3) && (!(ctx->hflags & MIPS_HFLAG_64))) || > > + unlikely((crc32c >= 2))) { > > + generate_exception_end(ctx, EXCP_RI); > > + } > > + switch (sz) { > > + case 0: > > + if (crc32c) { > > + gen_crc32cb(ctx, rt, rs, rt); > > + } else { > > + gen_crc32b(ctx, rt, rs, rt); > > + } > > + break; > > + case 1: > > + if (crc32c) { > > + gen_crc32ch(ctx, rt, rs, rt); > > + } else { > > + gen_crc32h(ctx, rt, rs, rt); > > + } > > + break; > > + case 2: > > + if (crc32c) { > > + gen_crc32cw(ctx, rt, rs, rt); > > + } else { > > + gen_crc32w(ctx, rt, rs, rt); > > + } > > + break; > > + case 3: > > + if (crc32c) { > > + gen_crc32cd(ctx, rt, rs, rt); > > + } else { > > + gen_crc32d(ctx, rt, rs, rt); > > + } > > + break; > > + } > > + break; > > case R6_OPC_PREF: > > if (rt >= 24) { > > /* hint codes 24-31 are reserved and signal RI */ @@ -30727,6 > > +30853,7 @@ static void mips_tr_init_disas_context(DisasContextBase > > *dcbase, CPUState *cs) > > ctx->mrp = (env->CP0_Config5 >> CP0C5_MRP) & 1; > > ctx->nan2008 = (env->active_fpu.fcr31 >> FCR31_NAN2008) & 1; > > ctx->abs2008 = (env->active_fpu.fcr31 >> FCR31_ABS2008) & 1; > > + 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 dfefe5e..75c48b3 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -1409,6 +1409,14 @@ const struct mips_opcode mips_builtin_opcodes[] = {"dvp", "t", 0x41600024, 0xffe0ffff, TRAP|WR_t, 0, I32R6}, {"evp", "", 0x41600004, 0xffffffff, TRAP, 0, I32R6}, {"evp", "t", 0x41600004, 0xffe0ffff, TRAP|WR_t, 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 7b8ad74..2095330 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 18fcee4..5cd396d 100644 --- a/target/mips/op_helper.c +++ b/target/mips/op_helper.c @@ -27,6 +27,8 @@ #include "exec/memop.h" #include "sysemu/kvm.h" #include "fpu/softfloat.h" +#include "qemu/crc32c.h" +#include <zlib.h> /*****************************************************************************/ /* Exceptions processing helpers */ @@ -350,6 +352,23 @@ 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]; + + 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]; + + 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 4bff585..1b38356 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -451,6 +451,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, @@ -2547,6 +2548,7 @@ typedef struct DisasContext { bool nan2008; bool abs2008; bool saar; + bool crcp; } DisasContext; #define DISAS_STOP DISAS_TARGET_0 @@ -27117,11 +27119,96 @@ 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); + uint64_t mask = 0; + + 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 (sz != 3) { + switch (sz) { + case 0: + mask = 0xFF; + break; + case 1: + mask = 0xFFFF; + break; + case 2: + mask = 0xFFFFFFFF; + break; + } + tcg_gen_andi_tl(t1, t1, mask); + } + + 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 gen_crc32b(DisasContext *ctx, int rd, int rs, int rt) +{ + gen_crc32(ctx, rd, rs, rt, 0, 0); +} + +static void gen_crc32h(DisasContext *ctx, int rd, int rs, int rt) +{ + gen_crc32(ctx, rd, rs, rt, 1, 0); +} + +static void gen_crc32w(DisasContext *ctx, int rd, int rs, int rt) +{ + gen_crc32(ctx, rd, rs, rt, 2, 0); +} + +static void gen_crc32d(DisasContext *ctx, int rd, int rs, int rt) +{ + gen_crc32(ctx, rd, rs, rt, 3, 0); +} + +static void gen_crc32cb(DisasContext *ctx, int rd, int rs, int rt) +{ + gen_crc32(ctx, rd, rs, rt, 0, 1); +} + +static void gen_crc32ch(DisasContext *ctx, int rd, int rs, int rt) +{ + gen_crc32(ctx, rd, rs, rt, 1, 1); +} + +static void gen_crc32cw(DisasContext *ctx, int rd, int rs, int rt) +{ + gen_crc32(ctx, rd, rs, rt, 2, 1); +} + +static void gen_crc32cd(DisasContext *ctx, int rd, int rs, int rt) +{ + gen_crc32(ctx, rd, rs, rt, 3, 1); +} + static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx) { int rs, rt, rd, sa; uint32_t op1, op2; int16_t imm; + int sz, crc32c; rs = (ctx->opcode >> 21) & 0x1f; rt = (ctx->opcode >> 16) & 0x1f; @@ -27131,6 +27218,45 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx) op1 = MASK_SPECIAL3(ctx->opcode); switch (op1) { + case OPC_CRC32: + sz = extract32(ctx->opcode, 6, 2); + crc32c = extract32(ctx->opcode, 8, 3); + if (unlikely(!ctx->crcp) || + unlikely((sz == 3) && (!(ctx->hflags & MIPS_HFLAG_64))) || + unlikely((crc32c >= 2))) { + generate_exception_end(ctx, EXCP_RI); + } + switch (sz) { + case 0: + if (crc32c) { + gen_crc32cb(ctx, rt, rs, rt); + } else { + gen_crc32b(ctx, rt, rs, rt); + } + break; + case 1: + if (crc32c) { + gen_crc32ch(ctx, rt, rs, rt); + } else { + gen_crc32h(ctx, rt, rs, rt); + } + break; + case 2: + if (crc32c) { + gen_crc32cw(ctx, rt, rs, rt); + } else { + gen_crc32w(ctx, rt, rs, rt); + } + break; + case 3: + if (crc32c) { + gen_crc32cd(ctx, rt, rs, rt); + } else { + gen_crc32d(ctx, rt, rs, rt); + } + break; + } + break; case R6_OPC_PREF: if (rt >= 24) { /* hint codes 24-31 are reserved and signal RI */ @@ -30727,6 +30853,7 @@ static void mips_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->mrp = (env->CP0_Config5 >> CP0C5_MRP) & 1; ctx->nan2008 = (env->active_fpu.fcr31 >> FCR31_NAN2008) & 1; ctx->abs2008 = (env->active_fpu.fcr31 >> FCR31_ABS2008) & 1; + ctx->crcp = (env->CP0_Config5 >> CP0C5_CRCP) & 1; restore_cpu_state(env, ctx); #ifdef CONFIG_USER_ONLY ctx->mem_idx = MIPS_HFLAG_UM;