target/mips: Add support for emulation of CRC32 instructions

Add emulation of MIPS' CRC32 (Cyclic Redundancy Check) instructions.
Reuse zlib crc32() and Linux crc32c().

Corresponding disassembly has been added in commit 99029be1c2
("target/mips: Add implementation of GINVT instruction").

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>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <PA4PR09MB486489692D843DDFC25F3CF1846B2@PA4PR09MB4864.eurprd09.prod.outlook.com>
This commit is contained in:
Yongbok Kim 2019-07-29 19:23:33 +02:00 committed by Philippe Mathieu-Daudé
parent 9a4e273dde
commit 9253773cb7
8 changed files with 78 additions and 4 deletions

View file

@ -756,8 +756,9 @@ const mips_def_t mips_defs[] =
(1 << CP0C3_RXI) | (1 << CP0C3_LPA) | (1 << CP0C3_VInt),
.CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) | (3 << CP0C4_IE) |
(1 << CP0C4_AE) | (0xfc << CP0C4_KScrExist),
.CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_XNP) | (1 << CP0C5_VP) |
(1 << CP0C5_LLB) | (1 << CP0C5_MRP) | (3 << CP0C5_GI),
.CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_CRCP) | (1 << CP0C5_XNP) |
(1 << CP0C5_VP) | (1 << CP0C5_LLB) | (1 << CP0C5_MRP) |
(3 << CP0C5_GI),
.CP0_Config5_rw_bitmask = (1 << CP0C5_MSAEn) | (1 << CP0C5_SBRI) |
(1 << CP0C5_FRE) | (1 << CP0C5_UFE),
.CP0_LLAddr_rw_bitmask = 0,
@ -796,8 +797,9 @@ const mips_def_t mips_defs[] =
(1 << CP0C3_RXI) | (1 << CP0C3_LPA) | (1 << CP0C3_VInt),
.CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) | (3 << CP0C4_IE) |
(1 << CP0C4_AE) | (0xfc << CP0C4_KScrExist),
.CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_XNP) | (1 << CP0C5_VP) |
(1 << CP0C5_LLB) | (1 << CP0C5_MRP) | (3 << CP0C5_GI),
.CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_CRCP) | (1 << CP0C5_XNP) |
(1 << CP0C5_VP) | (1 << CP0C5_LLB) | (1 << CP0C5_MRP) |
(3 << CP0C5_GI),
.CP0_Config5_rw_bitmask = (1 << CP0C5_MSAEn) | (1 << CP0C5_SBRI) |
(1 << CP0C5_FRE) | (1 << CP0C5_UFE),
.CP0_LLAddr_rw_bitmask = 0,

View file

@ -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 */

View file

@ -7,6 +7,7 @@ mips_ss.add(files(
'gdbstub.c',
'msa.c',
))
mips_ss.add(zlib)
if have_system
subdir('system')

View file

@ -24,6 +24,8 @@
#include "exec/helper-proto.h"
#include "exec/memop.h"
#include "fpu_helper.h"
#include "qemu/crc32c.h"
#include <zlib.h>
static inline target_ulong bitswap(target_ulong v)
{
@ -142,6 +144,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/loongarch/tcg/op_helper.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)
{
/*

View file

@ -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

View file

@ -33,3 +33,15 @@ 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;
}

View file

@ -13449,6 +13449,29 @@ 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;
@ -15095,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;

View file

@ -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,7 @@ 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)