Add emulation of MIPS' CRC32 (Cyclic Redundancy Check) instructions.
Reuse zlib crc32() and Linux crc32c().
Cherry-picked 4cc974938aee1588f852590509004e340c072940
from https://github.com/MIPS/gnutools-qemu
Signed-off-by: Yongbok Kim <yongbok.kim@mips.com>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Aleksandar Rakic <aleksandar.rakic@htecgroup.com>
Reviewed-by: Aleksandar Rikalo <arikalo@gmail.com>
---
target/mips/helper.h | 2 ++
target/mips/meson.build | 1 +
target/mips/tcg/op_helper.c | 26 ++++++++++++++++++++++++++
target/mips/tcg/rel6.decode | 5 +++++
target/mips/tcg/rel6_translate.c | 14 ++++++++++++++
target/mips/tcg/translate.c | 25 +++++++++++++++++++++++++
target/mips/tcg/translate.h | 3 +++
7 files changed, 76 insertions(+)
diff --git a/target/mips/helper.h b/target/mips/helper.h
index 0f8462febb..752748d5e6 100644
--- a/target/mips/helper.h
+++ b/target/mips/helper.h
@@ -21,6 +21,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)
/* microMIPS functions */
diff --git a/target/mips/meson.build b/target/mips/meson.build
index a26d1e1f79..d2d686fc0c 100644
--- a/target/mips/meson.build
+++ b/target/mips/meson.build
@@ -7,6 +7,7 @@ mips_ss.add(files(
'gdbstub.c',
'msa.c',
))
+mips_ss.add(zlib)
if have_system
subdir('sysemu')
diff --git a/target/mips/tcg/op_helper.c b/target/mips/tcg/op_helper.c
index 65403f1a87..22600697f0 100644
--- a/target/mips/tcg/op_helper.c
+++ b/target/mips/tcg/op_helper.c
@@ -25,6 +25,8 @@
#include "exec/exec-all.h"
#include "exec/memop.h"
#include "fpu_helper.h"
+#include "qemu/crc32c.h"
+#include <zlib.h>
static inline target_ulong bitswap(target_ulong v)
{
@@ -143,6 +145,30 @@ 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) ?
+ (target_ulong) -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) ?
+ (target_ulong) -1ULL :
+ ((1ULL << (sz * 8)) - 1);
+ m &= mask;
+ stq_le_p(buf, m);
+ return (int32_t) (crc32c(val, buf, sz) ^ 0xffffffff);
+}
+
void helper_fork(target_ulong arg1, target_ulong arg2)
{
/*
diff --git a/target/mips/tcg/rel6.decode b/target/mips/tcg/rel6.decode
index d6989cf56e..5074338aa5 100644
--- a/target/mips/tcg/rel6.decode
+++ b/target/mips/tcg/rel6.decode
@@ -16,11 +16,16 @@
&r rs rt rd sa
+&special3_crc rs rt c sz
+
@lsa ...... rs:5 rt:5 rd:5 ... sa:2 ...... &r
+@crc32 ...... rs:5 rt:5 ..... c:3 sz:2 ...... &special3_crc
LSA 000000 ..... ..... ..... 000 .. 000101 @lsa
DLSA 000000 ..... ..... ..... 000 .. 010101 @lsa
+CRC32 011111 ..... ..... 00000 ... .. 001111 @crc32
+
REMOVED 010011 ----- ----- ----- ----- ------ # COP1X (COP3)
REMOVED 011100 ----- ----- ----- ----- ------ # SPECIAL2
diff --git a/target/mips/tcg/rel6_translate.c b/target/mips/tcg/rel6_translate.c
index 59f237ba3b..423b323ba7 100644
--- a/target/mips/tcg/rel6_translate.c
+++ b/target/mips/tcg/rel6_translate.c
@@ -33,3 +33,17 @@ static bool trans_DLSA(DisasContext *ctx, arg_r *a)
}
return gen_dlsa(ctx, a->rd, a->rt, a->rs, a->sa);
}
+
+static bool trans_CRC32(DisasContext *ctx, arg_special3_crc *a)
+{
+ if (unlikely(!ctx->crcp) ||
+ unlikely((a->sz == 3) &&
+ (!(ctx->hflags & MIPS_HFLAG_64))) ||
+ unlikely((a->c >= 2))) {
+ gen_reserved_instruction(ctx);
+ return true;
+ }
+ gen_crc32(ctx, a->rt, a->rs, a->rt,
+ a->sz, a->c);
+ return true;
+}
diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c
index de7045874d..c97d1d37bd 100644
--- a/target/mips/tcg/translate.c
+++ b/target/mips/tcg/translate.c
@@ -13448,6 +13448,30 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx)
}
}
+void gen_crc32(DisasContext *ctx, int rd, int rs, int rt, int sz,
+ int crc32c)
+{
+ TCGv t0;
+ TCGv t1;
+ TCGv_i32 tsz = tcg_constant_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);
+ }
+
+}
+
static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx)
{
int rs, rt, rd, sa;
@@ -15094,6 +15118,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;
diff --git a/target/mips/tcg/translate.h b/target/mips/tcg/translate.h
index 1bf153d183..cb27ae78ae 100644
--- a/target/mips/tcg/translate.h
+++ b/target/mips/tcg/translate.h
@@ -51,6 +51,7 @@ typedef struct DisasContext {
bool abs2008;
bool mi;
int gi;
+ bool crcp;
} DisasContext;
#define DISAS_STOP DISAS_TARGET_0
@@ -181,6 +182,8 @@ bool gen_lsa(DisasContext *ctx, int rd, int rt, int rs, int sa);
bool gen_dlsa(DisasContext *ctx, int rd, int rt, int rs, int sa);
void gen_rdhwr(DisasContext *ctx, int rt, int rd, int sel);
+void gen_crc32(DisasContext *ctx, int rd, int rs, int rt, int sz,
+ int crc32c);
extern TCGv cpu_gpr[32], cpu_PC;
#if defined(TARGET_MIPS64)
--
2.34.1
© 2016 - 2024 Red Hat, Inc.