aboutsummaryrefslogtreecommitdiff
path: root/tests/tcg
diff options
context:
space:
mode:
Diffstat (limited to 'tests/tcg')
-rw-r--r--tests/tcg/Makefile.target43
-rw-r--r--tests/tcg/aarch64/Makefile.softmmu-target3
-rw-r--r--tests/tcg/aarch64/system/boot.S172
-rw-r--r--tests/tcg/loongarch64/system/kernel.ld2
-rw-r--r--tests/tcg/mips/include/wrappers_mips64r6.h32
-rw-r--r--tests/tcg/mips/user/isa/mips64r6/crc/Makefile40
-rw-r--r--tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32b.c142
-rw-r--r--tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cb.c142
-rw-r--r--tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cd.c142
-rw-r--r--tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32ch.c142
-rw-r--r--tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cw.c142
-rw-r--r--tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32d.c142
-rw-r--r--tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32h.c142
-rw-r--r--tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32w.c142
-rw-r--r--tests/tcg/multiarch/Makefile.target9
-rw-r--r--tests/tcg/multiarch/fnmsub.c37
-rw-r--r--tests/tcg/multiarch/system/Makefile.softmmu-target16
-rw-r--r--tests/tcg/plugins/mem.c5
-rw-r--r--tests/tcg/plugins/meson.build4
-rw-r--r--tests/tcg/plugins/patch.c251
-rw-r--r--tests/tcg/plugins/syscall.c4
-rw-r--r--tests/tcg/riscv64/Makefile.softmmu-target4
-rw-r--r--tests/tcg/riscv64/test-mepc-masking.S73
-rw-r--r--tests/tcg/x86_64/Makefile.softmmu-target21
-rw-r--r--tests/tcg/x86_64/fma.c17
-rw-r--r--tests/tcg/x86_64/system/patch-target.c22
-rwxr-xr-xtests/tcg/x86_64/system/validate-patch.py39
27 files changed, 1891 insertions, 39 deletions
diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target
index 95ff76e..18afd5b 100644
--- a/tests/tcg/Makefile.target
+++ b/tests/tcg/Makefile.target
@@ -127,8 +127,14 @@ else
# build options for bare programs are usually pretty different. They
# are expected to provide their own build recipes.
EXTRA_CFLAGS += -ffreestanding -fno-stack-protector
+
+# We skip the multiarch tests if the target hasn't provided a boot.S
+MULTIARCH_SOFTMMU_TARGETS = i386 alpha aarch64 arm loongarch64 s390x x86_64
+
+ifneq ($(filter $(TARGET_NAME),$(MULTIARCH_SOFTMMU_TARGETS)),)
-include $(SRC_PATH)/tests/tcg/minilib/Makefile.target
-include $(SRC_PATH)/tests/tcg/multiarch/system/Makefile.softmmu-target
+endif
-include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.softmmu-target
endif
@@ -151,20 +157,41 @@ ifeq ($(CONFIG_PLUGIN),y)
PLUGIN_SRC=$(SRC_PATH)/tests/tcg/plugins
PLUGIN_LIB=../plugins
VPATH+=$(PLUGIN_LIB)
-PLUGINS=$(patsubst %.c, lib%.so, $(notdir $(wildcard $(PLUGIN_SRC)/*.c)))
+# Some plugins need to be disabled for all tests to avoid exponential explosion.
+# For example, libpatch.so only needs to run against the arch-specific patch
+# target test, so we explicitly run it in the arch-specific Makefile.
+DISABLE_PLUGINS=libpatch.so
+
+# Likewise don't bother with the syscall plugin for softmmu
+ifneq ($(filter %-softmmu, $(TARGET)),)
+DISABLE_PLUGINS += libsyscall.so
+endif
+
+PLUGINS=$(filter-out $(DISABLE_PLUGINS), \
+ $(patsubst %.c, lib%.so, $(notdir $(wildcard $(PLUGIN_SRC)/*.c))))
# We need to ensure expand the run-plugin-TEST-with-PLUGIN
# pre-requistes manually here as we can't use stems to handle it. We
# only expand MULTIARCH_TESTS which are common on most of our targets
-# to avoid an exponential explosion as new tests are added. We also
-# add some special helpers the run-plugin- rules can use below.
-# In more, extra tests can be added using ADDITIONAL_PLUGINS_TESTS variable.
+# and rotate the plugins so we don't grow too out of control as new
+# tests are added. Plugins that need to run with a specific test
+# should ensure they add their combination to EXTRA_RUNS.
ifneq ($(MULTIARCH_TESTS),)
-$(foreach p,$(PLUGINS), \
- $(foreach t,$(MULTIARCH_TESTS) $(ADDITIONAL_PLUGINS_TESTS),\
- $(eval run-plugin-$(t)-with-$(p): $t $p) \
- $(eval RUN_TESTS+=run-plugin-$(t)-with-$(p))))
+
+NUM_PLUGINS := $(words $(PLUGINS))
+NUM_TESTS := $(words $(MULTIARCH_TESTS))
+
+define mod_plus_one
+ $(shell $(PYTHON) -c "print( ($(1) % $(2)) + 1 )")
+endef
+
+$(foreach _idx, $(shell seq 1 $(NUM_TESTS)), \
+ $(eval _test := $(word $(_idx), $(MULTIARCH_TESTS))) \
+ $(eval _plugin := $(word $(call mod_plus_one, $(_idx), $(NUM_PLUGINS)), $(PLUGINS))) \
+ $(eval run-plugin-$(_test)-with-$(_plugin): $(_test) $(_plugin)) \
+ $(eval RUN_TESTS+=run-plugin-$(_test)-with-$(_plugin)))
+
endif # MULTIARCH_TESTS
endif # CONFIG_PLUGIN
diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target
index 9c52475..f7a7d2b 100644
--- a/tests/tcg/aarch64/Makefile.softmmu-target
+++ b/tests/tcg/aarch64/Makefile.softmmu-target
@@ -68,7 +68,8 @@ run-plugin-semiconsole-with-%: semiconsole
# vtimer test needs EL2
QEMU_EL2_MACHINE=-machine virt,virtualization=on,gic-version=2 -cpu cortex-a57 -smp 4
-run-vtimer: QEMU_OPTS=$(QEMU_EL2_MACHINE) $(QEMU_BASE_ARGS) -kernel
+QEMU_EL2_BASE_ARGS=-semihosting-config enable=on,target=native,chardev=output,arg="2"
+run-vtimer: QEMU_OPTS=$(QEMU_EL2_MACHINE) $(QEMU_EL2_BASE_ARGS) -kernel
# Simple Record/Replay Test
.PHONY: memory-record
diff --git a/tests/tcg/aarch64/system/boot.S b/tests/tcg/aarch64/system/boot.S
index a5df9c1..8bfa4e4 100644
--- a/tests/tcg/aarch64/system/boot.S
+++ b/tests/tcg/aarch64/system/boot.S
@@ -16,6 +16,7 @@
#define semihosting_call hlt 0xf000
#define SYS_WRITEC 0x03 /* character to debug channel */
#define SYS_WRITE0 0x04 /* string to debug channel */
+#define SYS_GET_CMDLINE 0x15 /* get command line */
#define SYS_EXIT 0x18
.align 12
@@ -70,21 +71,172 @@ lower_a32_sync:
lower_a32_irq:
lower_a32_fiq:
lower_a32_serror:
+ adr x1, .unexp_excp
+exit_msg:
mov x0, SYS_WRITE0
- adr x1, .error
semihosting_call
mov x0, 1 /* EXIT_FAILURE */
bl _exit
/* never returns */
.section .rodata
-.error:
- .string "Terminated by exception.\n"
+.unexp_excp:
+ .string "Unexpected exception.\n"
+.high_el_msg:
+ .string "Started in lower EL than requested.\n"
+.unexp_el0:
+ .string "Started in invalid EL.\n"
+
+ .align 8
+.get_cmd:
+ .quad cmdline
+ .quad 128
.text
.align 4
.global __start
__start:
+ /*
+ * Initialise the stack for whatever EL we are in before
+ * anything else, we need it to be able to _exit cleanly.
+ * It's smaller than the stack we pass to the C code but we
+ * don't need much.
+ */
+ adrp x0, system_stack_end
+ add x0, x0, :lo12:system_stack_end
+ mov sp, x0
+
+ /*
+ * The test can set the semihosting command line to the target
+ * EL needed for the test. However if no semihosting args are set we will
+ * end up with -kernel/-append data (see semihosting_arg_fallback).
+ * Keep the normalised target in w11.
+ */
+ mov x0, SYS_GET_CMDLINE
+ adr x1, .get_cmd
+ semihosting_call
+ adrp x10, cmdline
+ add x10, x10, :lo12:cmdline
+ ldrb w11, [x10]
+
+ /* sanity check, normalise char to EL, clamp to 1 if outside range */
+ subs w11, w11, #'0'
+ b.lt el_default
+ cmp w11, #3
+ b.gt el_default
+ b 1f
+
+el_high:
+ adr x1, .high_el_msg
+ b exit_msg
+
+el_default:
+ mov w11, #1
+
+1:
+ /* Determine current Exception Level */
+ mrs x0, CurrentEL
+ lsr x0, x0, #2 /* CurrentEL[3:2] contains the current EL */
+
+ /* Are we already in a lower EL than we want? */
+ cmp w11, w0
+ bgt el_high
+
+ /* Branch based on current EL */
+ cmp x0, #3
+ b.eq setup_el3
+ cmp x0, #2
+ b.eq setup_el2
+ cmp x0, #1
+ b.eq at_testel /* Already at EL1, skip transition */
+
+ /* Should not be at EL0 - error out */
+ adr x1, .unexp_el0
+ b exit_msg
+
+setup_el3:
+ /* Ensure we trap if we get anything wrong */
+ adr x0, vector_table
+ msr vbar_el3, x0
+
+ /* Does the test want to be at EL3? */
+ cmp w11, #3
+ beq at_testel
+
+ /* Configure EL3 to for lower states (EL2 or EL1) */
+ mrs x0, scr_el3
+ orr x0, x0, #(1 << 10) /* RW = 1: EL2/EL1 execution state is AArch64 */
+ orr x0, x0, #(1 << 0) /* NS = 1: Non-secure state */
+ msr scr_el3, x0
+
+ /*
+ * We need to check if EL2 is actually enabled via ID_AA64PFR0_EL1,
+ * otherwise we should just jump straight to EL1.
+ */
+ mrs x0, id_aa64pfr0_el1
+ ubfx x0, x0, #8, #4 /* Extract EL2 field (bits 11:8) */
+ cbz x0, el2_not_present /* If field is 0 no EL2 */
+
+
+ /* Prepare SPSR for exception return to EL2 */
+ mov x0, #0x3c9 /* DAIF bits and EL2h mode (9) */
+ msr spsr_el3, x0
+
+ /* Set EL2 entry point */
+ adr x0, setup_el2
+ msr elr_el3, x0
+
+ /* Return to EL2 */
+ eret
+
+el2_not_present:
+ /* Initialize SCTLR_EL1 with reset value */
+ msr sctlr_el1, xzr
+
+ /* Set EL1 entry point */
+ adr x0, at_testel
+ msr elr_el3, x0
+
+ /* Prepare SPSR for exception return to EL1h with interrupts masked */
+ mov x0, #0x3c5 /* DAIF bits and EL1h mode (5) */
+ msr spsr_el3, x0
+
+ isb /* Synchronization barrier */
+ eret /* Jump to EL1 */
+
+setup_el2:
+ /* Ensure we trap if we get anything wrong */
+ adr x0, vector_table
+ msr vbar_el2, x0
+
+ /* Does the test want to be at EL2? */
+ cmp w11, #2
+ beq at_testel
+
+ /* Configure EL2 to allow transition to EL1 */
+ mrs x0, hcr_el2
+ orr x0, x0, #(1 << 31) /* RW = 1: EL1 execution state is AArch64 */
+ msr hcr_el2, x0
+
+ /* Initialize SCTLR_EL1 with reset value */
+ msr sctlr_el1, xzr
+
+ /* Set EL1 entry point */
+ adr x0, at_testel
+ msr elr_el2, x0
+
+ /* Prepare SPSR for exception return to EL1 */
+ mov x0, #(0x5 << 0) /* EL1h (SPx), with interrupts disabled */
+ msr spsr_el2, x0
+
+ /* Return to EL1 */
+ eret
+
+ /*
+ * At the target EL for the test, usually EL1. Note we still
+ * set everything up as if we were at EL1.
+ */
+at_testel:
/* Installs a table of exception vectors to catch and handle all
exceptions by terminating the process with a diagnostic. */
adr x0, vector_table
@@ -100,7 +252,7 @@ __start:
* maps RAM to the first Gb. The stage2 tables have two 2mb
* translation block entries covering a series of adjacent
* 4k pages.
- */
+ */
/* Stage 1 entry: indexed by IA[38:30] */
adr x1, . /* phys address */
@@ -198,7 +350,8 @@ __start:
orr x0, x0, #(3 << 16)
msr cpacr_el1, x0
- /* Setup some stack space and enter the test code.
+ /*
+ * Setup some stack space before we enter the test code.
* Assume everything except the return value is garbage when we
* return, we won't need it.
*/
@@ -233,6 +386,11 @@ __sys_outc:
ret
.data
+
+ .align 8
+cmdline:
+ .space 128, 0
+
.align 12
/* Translation table
@@ -246,6 +404,10 @@ ttb_stage2:
.space 4096, 0
.align 12
+system_stack:
+ .space 4096, 0
+system_stack_end:
+
stack:
.space 65536, 0
stack_end:
diff --git a/tests/tcg/loongarch64/system/kernel.ld b/tests/tcg/loongarch64/system/kernel.ld
index f1a7c01..56d8588 100644
--- a/tests/tcg/loongarch64/system/kernel.ld
+++ b/tests/tcg/loongarch64/system/kernel.ld
@@ -3,7 +3,7 @@ ENTRY(_start)
SECTIONS
{
/* Linux kernel legacy start address. */
- . = 0x9000000000200000;
+ . = 0x200000;
_text = .;
.text : {
*(.text)
diff --git a/tests/tcg/mips/include/wrappers_mips64r6.h b/tests/tcg/mips/include/wrappers_mips64r6.h
index d1e5edb..33d03de 100644
--- a/tests/tcg/mips/include/wrappers_mips64r6.h
+++ b/tests/tcg/mips/include/wrappers_mips64r6.h
@@ -23,6 +23,7 @@
#ifndef WRAPPERS_MIPS64R6_H
#define WRAPPERS_MIPS64R6_H
+#include <string.h>
#define DO_MIPS64R6__RD__RS(suffix, mnemonic) \
static inline void do_mips64r6_##suffix(const void *input, \
@@ -80,4 +81,35 @@ DO_MIPS64R6__RD__RS_RT(DMULU, dmulu)
DO_MIPS64R6__RD__RS_RT(DMUHU, dmuhu)
+#define DO_MIPS64R6__RT__RS_RT(suffix, mnemonic) \
+static inline void do_mips64r6_##suffix(const void *input1, \
+ const void *input2, \
+ void *output) \
+{ \
+ if (strncmp(#mnemonic, "crc32", 5) == 0) \
+ __asm__ volatile ( \
+ ".set crc\n\t" \
+ ); \
+ \
+ __asm__ volatile ( \
+ "ld $t1, 0(%0)\n\t" \
+ "ld $t2, 0(%1)\n\t" \
+ #mnemonic " $t2, $t1, $t2\n\t" \
+ "sd $t2, 0(%2)\n\t" \
+ : \
+ : "r" (input1), "r" (input2), "r" (output) \
+ : "t0", "t1", "t2", "memory" \
+ ); \
+}
+
+DO_MIPS64R6__RT__RS_RT(CRC32B, crc32b)
+DO_MIPS64R6__RT__RS_RT(CRC32H, crc32h)
+DO_MIPS64R6__RT__RS_RT(CRC32W, crc32w)
+DO_MIPS64R6__RT__RS_RT(CRC32D, crc32d)
+
+DO_MIPS64R6__RT__RS_RT(CRC32CB, crc32cb)
+DO_MIPS64R6__RT__RS_RT(CRC32CH, crc32ch)
+DO_MIPS64R6__RT__RS_RT(CRC32CW, crc32cw)
+DO_MIPS64R6__RT__RS_RT(CRC32CD, crc32cd)
+
#endif
diff --git a/tests/tcg/mips/user/isa/mips64r6/crc/Makefile b/tests/tcg/mips/user/isa/mips64r6/crc/Makefile
new file mode 100644
index 0000000..b7f5811
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips64r6/crc/Makefile
@@ -0,0 +1,40 @@
+#
+# Test program for MIPS64R6 CRC32 instructions
+#
+# Copyright (C) 2025 Aleksandar Rakic <aleksandar.rakic@htecgroup.com>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+
+ifndef PREFIX
+ $(error "PREFIX not set, please export GNU Toolchain install directory.")
+endif
+
+ifndef SYSROOT
+ $(error "SYSROOT not set, please export GNU Toolchain system root directory.")
+endif
+
+SIM = ../../../../../../../build/qemu-mips64
+SIM_FLAGS = -L $(SYSROOT)
+
+CC = $(PREFIX)/bin/mips64-r6-linux-gnu-gcc
+
+TESTCASES = test_mips64r6_crc32b.tst
+TESTCASES += test_mips64r6_crc32h.tst
+TESTCASES += test_mips64r6_crc32w.tst
+TESTCASES += test_mips64r6_crc32d.tst
+TESTCASES += test_mips64r6_crc32cb.tst
+TESTCASES += test_mips64r6_crc32ch.tst
+TESTCASES += test_mips64r6_crc32cw.tst
+TESTCASES += test_mips64r6_crc32cd.tst
+
+all: $(TESTCASES)
+ @for case in $(TESTCASES); do \
+ echo $(SIM) $(SIM_FLAGS) ./$$case; \
+ $(SIM) $(SIM_FLAGS) ./$$case; \
+ echo $(RM) -rf ./$$case; \
+ $(RM) -rf ./$$case; \
+ done
+
+%.tst: %.c
+ $(CC) $< -o $@
diff --git a/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32b.c b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32b.c
new file mode 100644
index 0000000..bb1f3f6
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32b.c
@@ -0,0 +1,142 @@
+/*
+ * Test program for MIPS64R6 instruction CRC32B
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2025 Aleksandar Rakic <aleksandar.rakic@htecgroup.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_mips64r6.h"
+#include "../../../../include/test_inputs_64.h"
+#include "../../../../include/test_utils_64.h"
+
+#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT)
+
+int32_t main(void)
+{
+ char *isa_ase_name = "mips64r6";
+ char *group_name = "CRC with reversed polynomial 0xEDB88320";
+ char *instruction_name = "CRC32B";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b64_result[TEST_COUNT_TOTAL];
+ uint64_t b64_expect[TEST_COUNT_TOTAL] = {
+ 0x0000000000ffffffULL, /* 0 */
+ 0x000000002d02ef8dULL,
+ 0x000000001bab0fd1ULL,
+ 0x0000000036561fa3ULL,
+ 0xffffffffbf1caddaULL,
+ 0xffffffff92e1bda8ULL,
+ 0x00000000278c7949ULL,
+ 0x000000000a71693bULL,
+ 0x000000002dfd1072ULL, /* 8 */
+ 0x0000000000000000ULL,
+ 0x0000000036a9e05cULL,
+ 0x000000001b54f02eULL,
+ 0xffffffff921e4257ULL,
+ 0xffffffffbfe35225ULL,
+ 0x000000000a8e96c4ULL,
+ 0x00000000277386b6ULL,
+ 0x000000001bfe5a84ULL, /* 16 */
+ 0x0000000036034af6ULL,
+ 0x0000000000aaaaaaULL,
+ 0x000000002d57bad8ULL,
+ 0xffffffffa41d08a1ULL,
+ 0xffffffff89e018d3ULL,
+ 0x000000003c8ddc32ULL,
+ 0x000000001170cc40ULL,
+ 0x0000000036fcb509ULL, /* 24 */
+ 0x000000001b01a57bULL,
+ 0x000000002da84527ULL,
+ 0x0000000000555555ULL,
+ 0xffffffff891fe72cULL,
+ 0xffffffffa4e2f75eULL,
+ 0x00000000118f33bfULL,
+ 0x000000003c7223cdULL,
+ 0xffffffffbf2f9ee9ULL, /* 32 */
+ 0xffffffff92d28e9bULL,
+ 0xffffffffa47b6ec7ULL,
+ 0xffffffff89867eb5ULL,
+ 0x0000000000ccccccULL,
+ 0x000000002d31dcbeULL,
+ 0xffffffff985c185fULL,
+ 0xffffffffb5a1082dULL,
+ 0xffffffff922d7164ULL, /* 40 */
+ 0xffffffffbfd06116ULL,
+ 0xffffffff8979814aULL,
+ 0xffffffffa4849138ULL,
+ 0x000000002dce2341ULL,
+ 0x0000000000333333ULL,
+ 0xffffffffb55ef7d2ULL,
+ 0xffffffff98a3e7a0ULL,
+ 0x0000000027fdbe55ULL, /* 48 */
+ 0x000000000a00ae27ULL,
+ 0x000000003ca94e7bULL,
+ 0x0000000011545e09ULL,
+ 0xffffffff981eec70ULL,
+ 0xffffffffb5e3fc02ULL,
+ 0x00000000008e38e3ULL,
+ 0x000000002d732891ULL,
+ 0x000000000aff51d8ULL, /* 56 */
+ 0x00000000270241aaULL,
+ 0x0000000011aba1f6ULL,
+ 0x000000003c56b184ULL,
+ 0xffffffffb51c03fdULL,
+ 0xffffffff98e1138fULL,
+ 0x000000002d8cd76eULL,
+ 0x000000000071c71cULL,
+ 0x0000000000286255ULL, /* 64 */
+ 0x00000000784a5a65ULL,
+ 0xffffffff9bdd0d3bULL,
+ 0xffffffffe7e61ce5ULL,
+ 0x00000000782fabf7ULL,
+ 0x00000000004d93c7ULL,
+ 0xffffffffe3dac499ULL,
+ 0xffffffff9fe1d547ULL,
+ 0xffffffff9b4ca0e5ULL, /* 72 */
+ 0xffffffffe32e98d5ULL,
+ 0x0000000000b9cf8bULL,
+ 0x000000007c82de55ULL,
+ 0xffffffffe7904f52ULL,
+ 0xffffffff9ff27762ULL,
+ 0x000000007c65203cULL,
+ 0x00000000005e31e2ULL,
+ };
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32B(b64_pattern + i, b64_pattern + j,
+ b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32B(b64_random + i, b64_random + j,
+ b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) *
+ (PATTERN_INPUTS_64_SHORT_COUNT)) +
+ RANDOM_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_64(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time, b64_result,
+ b64_expect);
+
+ return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cb.c b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cb.c
new file mode 100644
index 0000000..1439d44
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cb.c
@@ -0,0 +1,142 @@
+/*
+ * Test program for MIPS64R6 instruction CRC32CB
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2025 Aleksandar Rakic <aleksandar.rakic@htecgroup.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_mips64r6.h"
+#include "../../../../include/test_inputs_64.h"
+#include "../../../../include/test_utils_64.h"
+
+#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT)
+
+int32_t main(void)
+{
+ char *isa_ase_name = "mips64r6";
+ char *group_name = "CRC with reversed polynomial 0x82F63B78";
+ char *instruction_name = "CRC32CB";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b64_result[TEST_COUNT_TOTAL];
+ uint64_t b64_expect[TEST_COUNT_TOTAL] = {
+ 0x0000000000ffffffULL, /* 0 */
+ 0xffffffffad7d5351ULL,
+ 0x00000000647e6465ULL,
+ 0xffffffffc9fcc8cbULL,
+ 0x00000000237f7689ULL,
+ 0xffffffff8efdda27ULL,
+ 0xffffffff837defedULL,
+ 0x000000002eff4343ULL,
+ 0xffffffffad82acaeULL, /* 8 */
+ 0x0000000000000000ULL,
+ 0xffffffffc9033734ULL,
+ 0x0000000064819b9aULL,
+ 0xffffffff8e0225d8ULL,
+ 0x0000000023808976ULL,
+ 0x000000002e00bcbcULL,
+ 0xffffffff83821012ULL,
+ 0x00000000642b3130ULL, /* 16 */
+ 0xffffffffc9a99d9eULL,
+ 0x0000000000aaaaaaULL,
+ 0xffffffffad280604ULL,
+ 0x0000000047abb846ULL,
+ 0xffffffffea2914e8ULL,
+ 0xffffffffe7a92122ULL,
+ 0x000000004a2b8d8cULL,
+ 0xffffffffc9566261ULL, /* 24 */
+ 0x0000000064d4cecfULL,
+ 0xffffffffadd7f9fbULL,
+ 0x0000000000555555ULL,
+ 0xffffffffead6eb17ULL,
+ 0x00000000475447b9ULL,
+ 0x000000004ad47273ULL,
+ 0xffffffffe756deddULL,
+ 0x00000000234c45baULL, /* 32 */
+ 0xffffffff8ecee914ULL,
+ 0x0000000047cdde20ULL,
+ 0xffffffffea4f728eULL,
+ 0x0000000000ccccccULL,
+ 0xffffffffad4e6062ULL,
+ 0xffffffffa0ce55a8ULL,
+ 0x000000000d4cf906ULL,
+ 0xffffffff8e3116ebULL, /* 40 */
+ 0x0000000023b3ba45ULL,
+ 0xffffffffeab08d71ULL,
+ 0x00000000473221dfULL,
+ 0xffffffffadb19f9dULL,
+ 0x0000000000333333ULL,
+ 0x000000000db306f9ULL,
+ 0xffffffffa031aa57ULL,
+ 0xffffffff830c28f1ULL, /* 48 */
+ 0x000000002e8e845fULL,
+ 0xffffffffe78db36bULL,
+ 0x000000004a0f1fc5ULL,
+ 0xffffffffa08ca187ULL,
+ 0x000000000d0e0d29ULL,
+ 0x00000000008e38e3ULL,
+ 0xffffffffad0c944dULL,
+ 0x000000002e717ba0ULL, /* 56 */
+ 0xffffffff83f3d70eULL,
+ 0x000000004af0e03aULL,
+ 0xffffffffe7724c94ULL,
+ 0x000000000df1f2d6ULL,
+ 0xffffffffa0735e78ULL,
+ 0xffffffffadf36bb2ULL,
+ 0x000000000071c71cULL,
+ 0x0000000000286255ULL, /* 64 */
+ 0xffffffffcbefd6b4ULL,
+ 0xffffffffc334e94fULL,
+ 0xffffffffac268ec5ULL,
+ 0xffffffffcb8a2726ULL,
+ 0x00000000004d93c7ULL,
+ 0x000000000896ac3cULL,
+ 0x000000006784cbb6ULL,
+ 0xffffffffc3a54491ULL, /* 72 */
+ 0x000000000862f070ULL,
+ 0x0000000000b9cf8bULL,
+ 0x000000006faba801ULL,
+ 0xffffffffac50dd72ULL,
+ 0x0000000067976993ULL,
+ 0x000000006f4c5668ULL,
+ 0x00000000005e31e2ULL,
+ };
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32CB(b64_pattern + i, b64_pattern + j,
+ b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32CB(b64_random + i, b64_random + j,
+ b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) *
+ (PATTERN_INPUTS_64_SHORT_COUNT)) +
+ RANDOM_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_64(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time, b64_result,
+ b64_expect);
+
+ return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cd.c b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cd.c
new file mode 100644
index 0000000..bf258e0
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cd.c
@@ -0,0 +1,142 @@
+/*
+ * Test program for MIPS64R6 instruction CRC32CD
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2025 Aleksandar Rakic <aleksandar.rakic@htecgroup.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_mips64r6.h"
+#include "../../../../include/test_inputs_64.h"
+#include "../../../../include/test_utils_64.h"
+
+#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT)
+
+int32_t main(void)
+{
+ char *isa_ase_name = "mips64r6";
+ char *group_name = "CRC with reversed polynomial 0x82F63B78";
+ char *instruction_name = "CRC32CD";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b64_result[TEST_COUNT_TOTAL];
+ uint64_t b64_expect[TEST_COUNT_TOTAL] = {
+ 0xffffffffb798b438ULL, /* 0 */
+ 0xffffffffc44ff94dULL,
+ 0xffffffff992a70ebULL,
+ 0xffffffffeafd3d9eULL,
+ 0x000000005152da26ULL,
+ 0x0000000022859753ULL,
+ 0x0000000015cb6d32ULL,
+ 0x00000000661c2047ULL,
+ 0x0000000073d74d75ULL, /* 8 */
+ 0x0000000000000000ULL,
+ 0x000000005d6589a6ULL,
+ 0x000000002eb2c4d3ULL,
+ 0xffffffff951d236bULL,
+ 0xffffffffe6ca6e1eULL,
+ 0xffffffffd184947fULL,
+ 0xffffffffa253d90aULL,
+ 0x0000000008f9ceacULL, /* 16 */
+ 0x000000007b2e83d9ULL,
+ 0x00000000264b0a7fULL,
+ 0x00000000559c470aULL,
+ 0xffffffffee33a0b2ULL,
+ 0xffffffff9de4edc7ULL,
+ 0xffffffffaaaa17a6ULL,
+ 0xffffffffd97d5ad3ULL,
+ 0xffffffffccb637e1ULL, /* 24 */
+ 0xffffffffbf617a94ULL,
+ 0xffffffffe204f332ULL,
+ 0xffffffff91d3be47ULL,
+ 0x000000002a7c59ffULL,
+ 0x0000000059ab148aULL,
+ 0x000000006ee5eeebULL,
+ 0x000000001d32a39eULL,
+ 0x0000000021e3b01bULL, /* 32 */
+ 0x000000005234fd6eULL,
+ 0x000000000f5174c8ULL,
+ 0x000000007c8639bdULL,
+ 0xffffffffc729de05ULL,
+ 0xffffffffb4fe9370ULL,
+ 0xffffffff83b06911ULL,
+ 0xfffffffff0672464ULL,
+ 0xffffffffe5ac4956ULL, /* 40 */
+ 0xffffffff967b0423ULL,
+ 0xffffffffcb1e8d85ULL,
+ 0xffffffffb8c9c0f0ULL,
+ 0x0000000003662748ULL,
+ 0x0000000070b16a3dULL,
+ 0x0000000047ff905cULL,
+ 0x000000003428dd29ULL,
+ 0xffffffffb89d59a6ULL, /* 48 */
+ 0xffffffffcb4a14d3ULL,
+ 0xffffffff962f9d75ULL,
+ 0xffffffffe5f8d000ULL,
+ 0x000000005e5737b8ULL,
+ 0x000000002d807acdULL,
+ 0x000000001ace80acULL,
+ 0x000000006919cdd9ULL,
+ 0x000000007cd2a0ebULL, /* 56 */
+ 0x000000000f05ed9eULL,
+ 0x0000000052606438ULL,
+ 0x0000000021b7294dULL,
+ 0xffffffff9a18cef5ULL,
+ 0xffffffffe9cf8380ULL,
+ 0xffffffffde8179e1ULL,
+ 0xffffffffad563494ULL,
+ 0x000000003a358bb3ULL, /* 64 */
+ 0xffffffff975446ebULL,
+ 0x0000000041d37ad6ULL,
+ 0x000000004be84fe1ULL,
+ 0xffffffff9671b1b3ULL,
+ 0x000000003b107cebULL,
+ 0xffffffffed9740d6ULL,
+ 0xffffffffe7ac75e1ULL,
+ 0xffffffffa1489696ULL, /* 72 */
+ 0x000000000c295bceULL,
+ 0xffffffffdaae67f3ULL,
+ 0xffffffffd09552c4ULL,
+ 0x0000000042bd7071ULL,
+ 0xffffffffefdcbd29ULL,
+ 0x00000000395b8114ULL,
+ 0x000000003360b423ULL,
+ };
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32CD(b64_pattern + i, b64_pattern + j,
+ b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32CD(b64_random + i, b64_random + j,
+ b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) *
+ (PATTERN_INPUTS_64_SHORT_COUNT)) +
+ RANDOM_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_64(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time, b64_result,
+ b64_expect);
+
+ return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32ch.c b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32ch.c
new file mode 100644
index 0000000..0e7b677
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32ch.c
@@ -0,0 +1,142 @@
+/*
+ * Test program for MIPS64R6 instruction CRC32CH
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2025 Aleksandar Rakic <aleksandar.rakic@htecgroup.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_mips64r6.h"
+#include "../../../../include/test_inputs_64.h"
+#include "../../../../include/test_utils_64.h"
+
+#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT)
+
+int32_t main(void)
+{
+ char *isa_ase_name = "mips64r6";
+ char *group_name = "CRC with reversed polynomial 0x82F63B78";
+ char *instruction_name = "CRC32CH";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b64_result[TEST_COUNT_TOTAL];
+ uint64_t b64_expect[TEST_COUNT_TOTAL] = {
+ 0x000000000000ffffULL, /* 0 */
+ 0x000000000e9e77d2ULL,
+ 0xfffffffff92eaa4bULL,
+ 0xfffffffff7b02266ULL,
+ 0x00000000571acc93ULL,
+ 0x00000000598444beULL,
+ 0xfffffffff1e6ca77ULL,
+ 0xffffffffff78425aULL,
+ 0x000000000e9e882dULL, /* 8 */
+ 0x0000000000000000ULL,
+ 0xfffffffff7b0dd99ULL,
+ 0xfffffffff92e55b4ULL,
+ 0x000000005984bb41ULL,
+ 0x00000000571a336cULL,
+ 0xffffffffff78bda5ULL,
+ 0xfffffffff1e63588ULL,
+ 0xfffffffff92eff1eULL, /* 16 */
+ 0xfffffffff7b07733ULL,
+ 0x000000000000aaaaULL,
+ 0x000000000e9e2287ULL,
+ 0xffffffffae34cc72ULL,
+ 0xffffffffa0aa445fULL,
+ 0x0000000008c8ca96ULL,
+ 0x00000000065642bbULL,
+ 0xfffffffff7b088ccULL, /* 24 */
+ 0xfffffffff92e00e1ULL,
+ 0x000000000e9edd78ULL,
+ 0x0000000000005555ULL,
+ 0xffffffffa0aabba0ULL,
+ 0xffffffffae34338dULL,
+ 0x000000000656bd44ULL,
+ 0x0000000008c83569ULL,
+ 0x00000000571affa0ULL, /* 32 */
+ 0x000000005984778dULL,
+ 0xffffffffae34aa14ULL,
+ 0xffffffffa0aa2239ULL,
+ 0x000000000000ccccULL,
+ 0x000000000e9e44e1ULL,
+ 0xffffffffa6fcca28ULL,
+ 0xffffffffa8624205ULL,
+ 0x0000000059848872ULL, /* 40 */
+ 0x00000000571a005fULL,
+ 0xffffffffa0aaddc6ULL,
+ 0xffffffffae3455ebULL,
+ 0x000000000e9ebb1eULL,
+ 0x0000000000003333ULL,
+ 0xffffffffa862bdfaULL,
+ 0xffffffffa6fc35d7ULL,
+ 0xfffffffff1e6bbb0ULL, /* 48 */
+ 0xffffffffff78339dULL,
+ 0x0000000008c8ee04ULL,
+ 0x0000000006566629ULL,
+ 0xffffffffa6fc88dcULL,
+ 0xffffffffa86200f1ULL,
+ 0x0000000000008e38ULL,
+ 0x000000000e9e0615ULL,
+ 0xffffffffff78cc62ULL, /* 56 */
+ 0xfffffffff1e6444fULL,
+ 0x00000000065699d6ULL,
+ 0x0000000008c811fbULL,
+ 0xffffffffa862ff0eULL,
+ 0xffffffffa6fc7723ULL,
+ 0x000000000e9ef9eaULL,
+ 0x00000000000071c7ULL,
+ 0x0000000000002862ULL, /* 64 */
+ 0x000000001190c4cfULL,
+ 0x000000007b7fdbbeULL,
+ 0xffffffff9204da99ULL,
+ 0x000000001190a13eULL,
+ 0x0000000000004d93ULL,
+ 0x000000006aef52e2ULL,
+ 0xffffffff839453c5ULL,
+ 0x000000007b7f4a13ULL, /* 72 */
+ 0x000000006aefa6beULL,
+ 0x000000000000b9cfULL,
+ 0xffffffffe97bb8e8ULL,
+ 0xffffffff9204accaULL,
+ 0xffffffff83944067ULL,
+ 0xffffffffe97b5f16ULL,
+ 0x0000000000005e31ULL,
+ };
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32CH(b64_pattern + i, b64_pattern + j,
+ b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32CH(b64_random + i, b64_random + j,
+ b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) *
+ (PATTERN_INPUTS_64_SHORT_COUNT)) +
+ RANDOM_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_64(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time, b64_result,
+ b64_expect);
+
+ return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cw.c b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cw.c
new file mode 100644
index 0000000..f7110b3
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cw.c
@@ -0,0 +1,142 @@
+/*
+ * Test program for MIPS64R6 instruction CRC32CW
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2025 Aleksandar Rakic <aleksandar.rakic@htecgroup.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_mips64r6.h"
+#include "../../../../include/test_inputs_64.h"
+#include "../../../../include/test_utils_64.h"
+
+#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT)
+
+int32_t main(void)
+{
+ char *isa_ase_name = "mips64r6";
+ char *group_name = "CRC with reversed polynomial 0x82F63B78";
+ char *instruction_name = "CRC32CW";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b64_result[TEST_COUNT_TOTAL];
+ uint64_t b64_expect[TEST_COUNT_TOTAL] = {
+ 0x0000000000000000ULL, /* 0 */
+ 0xffffffffb798b438ULL,
+ 0xffffffff91d3be47ULL,
+ 0x00000000264b0a7fULL,
+ 0x0000000070b16a3dULL,
+ 0xffffffffc729de05ULL,
+ 0x0000000063c5950aULL,
+ 0xffffffffd45d2132ULL,
+ 0xffffffffb798b438ULL, /* 8 */
+ 0x0000000000000000ULL,
+ 0x00000000264b0a7fULL,
+ 0xffffffff91d3be47ULL,
+ 0xffffffffc729de05ULL,
+ 0x0000000070b16a3dULL,
+ 0xffffffffd45d2132ULL,
+ 0x0000000063c5950aULL,
+ 0xffffffff91d3be47ULL, /* 16 */
+ 0x00000000264b0a7fULL,
+ 0x0000000000000000ULL,
+ 0xffffffffb798b438ULL,
+ 0xffffffffe162d47aULL,
+ 0x0000000056fa6042ULL,
+ 0xfffffffff2162b4dULL,
+ 0x00000000458e9f75ULL,
+ 0x00000000264b0a7fULL, /* 24 */
+ 0xffffffff91d3be47ULL,
+ 0xffffffffb798b438ULL,
+ 0x0000000000000000ULL,
+ 0x0000000056fa6042ULL,
+ 0xffffffffe162d47aULL,
+ 0x00000000458e9f75ULL,
+ 0xfffffffff2162b4dULL,
+ 0x0000000070b16a3dULL, /* 32 */
+ 0xffffffffc729de05ULL,
+ 0xffffffffe162d47aULL,
+ 0x0000000056fa6042ULL,
+ 0x0000000000000000ULL,
+ 0xffffffffb798b438ULL,
+ 0x000000001374ff37ULL,
+ 0xffffffffa4ec4b0fULL,
+ 0xffffffffc729de05ULL, /* 40 */
+ 0x0000000070b16a3dULL,
+ 0x0000000056fa6042ULL,
+ 0xffffffffe162d47aULL,
+ 0xffffffffb798b438ULL,
+ 0x0000000000000000ULL,
+ 0xffffffffa4ec4b0fULL,
+ 0x000000001374ff37ULL,
+ 0x0000000063c5950aULL, /* 48 */
+ 0xffffffffd45d2132ULL,
+ 0xfffffffff2162b4dULL,
+ 0x00000000458e9f75ULL,
+ 0x000000001374ff37ULL,
+ 0xffffffffa4ec4b0fULL,
+ 0x0000000000000000ULL,
+ 0xffffffffb798b438ULL,
+ 0xffffffffd45d2132ULL, /* 56 */
+ 0x0000000063c5950aULL,
+ 0x00000000458e9f75ULL,
+ 0xfffffffff2162b4dULL,
+ 0xffffffffa4ec4b0fULL,
+ 0x000000001374ff37ULL,
+ 0xffffffffb798b438ULL,
+ 0x0000000000000000ULL,
+ 0x0000000000000000ULL, /* 64 */
+ 0xffffffffea0755b2ULL,
+ 0x0000000008b188e6ULL,
+ 0xffffffffff3cc8d9ULL,
+ 0xffffffffea0755b2ULL,
+ 0x0000000000000000ULL,
+ 0xffffffffe2b6dd54ULL,
+ 0x00000000153b9d6bULL,
+ 0x0000000008b188e6ULL, /* 72 */
+ 0xffffffffe2b6dd54ULL,
+ 0x0000000000000000ULL,
+ 0xfffffffff78d403fULL,
+ 0xffffffffff3cc8d9ULL,
+ 0x00000000153b9d6bULL,
+ 0xfffffffff78d403fULL,
+ 0x0000000000000000ULL,
+ };
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32CW(b64_pattern + i, b64_pattern + j,
+ b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32CW(b64_random + i, b64_random + j,
+ b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) *
+ (PATTERN_INPUTS_64_SHORT_COUNT)) +
+ RANDOM_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_64(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time, b64_result,
+ b64_expect);
+
+ return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32d.c b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32d.c
new file mode 100644
index 0000000..e391be8
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32d.c
@@ -0,0 +1,142 @@
+/*
+ * Test program for MIPS64R6 instruction CRC32D
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2025 Aleksandar Rakic <aleksandar.rakic@htecgroup.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_mips64r6.h"
+#include "../../../../include/test_inputs_64.h"
+#include "../../../../include/test_utils_64.h"
+
+#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT)
+
+int32_t main(void)
+{
+ char *isa_ase_name = "mips64r6";
+ char *group_name = "CRC with reversed polynomial 0xEDB88320";
+ char *instruction_name = "CRC32D";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b64_result[TEST_COUNT_TOTAL];
+ uint64_t b64_expect[TEST_COUNT_TOTAL] = {
+ 0xffffffffdebb20e3ULL, /* 0 */
+ 0x0000000044660075ULL,
+ 0x000000001e20c2aeULL,
+ 0xffffffff84fde238ULL,
+ 0x00000000281d7ce7ULL,
+ 0xffffffffb2c05c71ULL,
+ 0xffffffffd660a024ULL,
+ 0x000000004cbd80b2ULL,
+ 0xffffffff9add2096ULL, /* 8 */
+ 0x0000000000000000ULL,
+ 0x000000005a46c2dbULL,
+ 0xffffffffc09be24dULL,
+ 0x000000006c7b7c92ULL,
+ 0xfffffffff6a65c04ULL,
+ 0xffffffff9206a051ULL,
+ 0x0000000008db80c7ULL,
+ 0x000000005449dd0fULL, /* 16 */
+ 0xffffffffce94fd99ULL,
+ 0xffffffff94d23f42ULL,
+ 0x000000000e0f1fd4ULL,
+ 0xffffffffa2ef810bULL,
+ 0x000000003832a19dULL,
+ 0x000000005c925dc8ULL,
+ 0xffffffffc64f7d5eULL,
+ 0x00000000102fdd7aULL, /* 24 */
+ 0xffffffff8af2fdecULL,
+ 0xffffffffd0b43f37ULL,
+ 0x000000004a691fa1ULL,
+ 0xffffffffe689817eULL,
+ 0x000000007c54a1e8ULL,
+ 0x0000000018f45dbdULL,
+ 0xffffffff82297d2bULL,
+ 0xffffffffa7157447ULL, /* 32 */
+ 0x000000003dc854d1ULL,
+ 0x00000000678e960aULL,
+ 0xfffffffffd53b69cULL,
+ 0x0000000051b32843ULL,
+ 0xffffffffcb6e08d5ULL,
+ 0xffffffffafcef480ULL,
+ 0x000000003513d416ULL,
+ 0xffffffffe3737432ULL, /* 40 */
+ 0x0000000079ae54a4ULL,
+ 0x0000000023e8967fULL,
+ 0xffffffffb935b6e9ULL,
+ 0x0000000015d52836ULL,
+ 0xffffffff8f0808a0ULL,
+ 0xffffffffeba8f4f5ULL,
+ 0x000000007175d463ULL,
+ 0x000000007a6adc3eULL, /* 48 */
+ 0xffffffffe0b7fca8ULL,
+ 0xffffffffbaf13e73ULL,
+ 0x00000000202c1ee5ULL,
+ 0xffffffff8ccc803aULL,
+ 0x000000001611a0acULL,
+ 0x0000000072b15cf9ULL,
+ 0xffffffffe86c7c6fULL,
+ 0x000000003e0cdc4bULL, /* 56 */
+ 0xffffffffa4d1fcddULL,
+ 0xfffffffffe973e06ULL,
+ 0x00000000644a1e90ULL,
+ 0xffffffffc8aa804fULL,
+ 0x000000005277a0d9ULL,
+ 0x0000000036d75c8cULL,
+ 0xffffffffac0a7c1aULL,
+ 0xffffffffed857593ULL, /* 64 */
+ 0xffffffffe0b6f95fULL,
+ 0x00000000253b462cULL,
+ 0xffffffffe15579b9ULL,
+ 0x0000000074897c83ULL,
+ 0x0000000079baf04fULL,
+ 0xffffffffbc374f3cULL,
+ 0x00000000785970a9ULL,
+ 0xffffffffa6bae0a9ULL, /* 72 */
+ 0xffffffffab896c65ULL,
+ 0x000000006e04d316ULL,
+ 0xffffffffaa6aec83ULL,
+ 0x000000005ae171feULL,
+ 0x0000000057d2fd32ULL,
+ 0xffffffff925f4241ULL,
+ 0x0000000056317dd4ULL,
+ };
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32D(b64_pattern + i, b64_pattern + j,
+ b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32D(b64_random + i, b64_random + j,
+ b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) *
+ (PATTERN_INPUTS_64_SHORT_COUNT)) +
+ RANDOM_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_64(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time, b64_result,
+ b64_expect);
+
+ return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32h.c b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32h.c
new file mode 100644
index 0000000..100f02c
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32h.c
@@ -0,0 +1,142 @@
+/*
+ * Test program for MIPS64R6 instruction CRC32H
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2025 Aleksandar Rakic <aleksandar.rakic@htecgroup.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_mips64r6.h"
+#include "../../../../include/test_inputs_64.h"
+#include "../../../../include/test_utils_64.h"
+
+#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT)
+
+int32_t main(void)
+{
+ char *isa_ase_name = "mips64r6";
+ char *group_name = "CRC with reversed polynomial 0xEDB88320";
+ char *instruction_name = "CRC32H";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b64_result[TEST_COUNT_TOTAL];
+ uint64_t b64_expect[TEST_COUNT_TOTAL] = {
+ 0x000000000000ffffULL, /* 0 */
+ 0xffffffffbe2612ffULL,
+ 0xffffffffdccda6c0ULL,
+ 0x0000000062eb4bc0ULL,
+ 0x000000004bbbc8eaULL,
+ 0xfffffffff59d25eaULL,
+ 0x0000000022259ac0ULL,
+ 0xffffffff9c0377c0ULL,
+ 0xffffffffbe26ed00ULL, /* 8 */
+ 0x0000000000000000ULL,
+ 0x0000000062ebb43fULL,
+ 0xffffffffdccd593fULL,
+ 0xfffffffff59dda15ULL,
+ 0x000000004bbb3715ULL,
+ 0xffffffff9c03883fULL,
+ 0x000000002225653fULL,
+ 0xffffffffdccdf395ULL, /* 16 */
+ 0x0000000062eb1e95ULL,
+ 0x000000000000aaaaULL,
+ 0xffffffffbe2647aaULL,
+ 0xffffffff9776c480ULL,
+ 0x0000000029502980ULL,
+ 0xfffffffffee896aaULL,
+ 0x0000000040ce7baaULL,
+ 0x0000000062ebe16aULL, /* 24 */
+ 0xffffffffdccd0c6aULL,
+ 0xffffffffbe26b855ULL,
+ 0x0000000000005555ULL,
+ 0x000000002950d67fULL,
+ 0xffffffff97763b7fULL,
+ 0x0000000040ce8455ULL,
+ 0xfffffffffee86955ULL,
+ 0x000000004bbbfbd9ULL, /* 32 */
+ 0xfffffffff59d16d9ULL,
+ 0xffffffff9776a2e6ULL,
+ 0x0000000029504fe6ULL,
+ 0x000000000000ccccULL,
+ 0xffffffffbe2621ccULL,
+ 0x00000000699e9ee6ULL,
+ 0xffffffffd7b873e6ULL,
+ 0xfffffffff59de926ULL, /* 40 */
+ 0x000000004bbb0426ULL,
+ 0x000000002950b019ULL,
+ 0xffffffff97765d19ULL,
+ 0xffffffffbe26de33ULL,
+ 0x0000000000003333ULL,
+ 0xffffffffd7b88c19ULL,
+ 0x00000000699e6119ULL,
+ 0x000000002225eb07ULL, /* 48 */
+ 0xffffffff9c030607ULL,
+ 0xfffffffffee8b238ULL,
+ 0x0000000040ce5f38ULL,
+ 0x00000000699edc12ULL,
+ 0xffffffffd7b83112ULL,
+ 0x0000000000008e38ULL,
+ 0xffffffffbe266338ULL,
+ 0xffffffff9c03f9f8ULL, /* 56 */
+ 0x00000000222514f8ULL,
+ 0x0000000040cea0c7ULL,
+ 0xfffffffffee84dc7ULL,
+ 0xffffffffd7b8ceedULL,
+ 0x00000000699e23edULL,
+ 0xffffffffbe269cc7ULL,
+ 0x00000000000071c7ULL,
+ 0x0000000000002862ULL, /* 64 */
+ 0x0000000026a17af6ULL,
+ 0xffffffffaa919152ULL,
+ 0xffffffffcb865590ULL,
+ 0x0000000026a11f07ULL,
+ 0x0000000000004d93ULL,
+ 0xffffffff8c30a637ULL,
+ 0xffffffffed2762f5ULL,
+ 0xffffffffaa9100ffULL, /* 72 */
+ 0xffffffff8c30526bULL,
+ 0x000000000000b9cfULL,
+ 0x0000000061177d0dULL,
+ 0xffffffffcb8623c3ULL,
+ 0xffffffffed277157ULL,
+ 0x0000000061179af3ULL,
+ 0x0000000000005e31ULL
+ };
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32H(b64_pattern + i, b64_pattern + j,
+ b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32H(b64_random + i, b64_random + j,
+ b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) *
+ (PATTERN_INPUTS_64_SHORT_COUNT)) +
+ RANDOM_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_64(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time, b64_result,
+ b64_expect);
+
+ return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32w.c b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32w.c
new file mode 100644
index 0000000..b4f5f4b
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32w.c
@@ -0,0 +1,142 @@
+/*
+ * Test program for MIPS64R6 instruction CRC32W
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2025 Aleksandar Rakic <aleksandar.rakic@htecgroup.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_mips64r6.h"
+#include "../../../../include/test_inputs_64.h"
+#include "../../../../include/test_utils_64.h"
+
+#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT)
+
+int32_t main(void)
+{
+ char *isa_ase_name = "mips64r6";
+ char *group_name = "CRC with reversed polynomial 0xEDB88320";
+ char *instruction_name = "CRC32W";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b64_result[TEST_COUNT_TOTAL];
+ uint64_t b64_expect[TEST_COUNT_TOTAL] = {
+ 0x0000000000000000ULL, /* 0 */
+ 0xffffffffdebb20e3ULL,
+ 0x000000004a691fa1ULL,
+ 0xffffffff94d23f42ULL,
+ 0xffffffff8f0808a0ULL,
+ 0x0000000051b32843ULL,
+ 0x0000000065069dceULL,
+ 0xffffffffbbbdbd2dULL,
+ 0xffffffffdebb20e3ULL, /* 8 */
+ 0x0000000000000000ULL,
+ 0xffffffff94d23f42ULL,
+ 0x000000004a691fa1ULL,
+ 0x0000000051b32843ULL,
+ 0xffffffff8f0808a0ULL,
+ 0xffffffffbbbdbd2dULL,
+ 0x0000000065069dceULL,
+ 0x000000004a691fa1ULL, /* 16 */
+ 0xffffffff94d23f42ULL,
+ 0x0000000000000000ULL,
+ 0xffffffffdebb20e3ULL,
+ 0xffffffffc5611701ULL,
+ 0x000000001bda37e2ULL,
+ 0x000000002f6f826fULL,
+ 0xfffffffff1d4a28cULL,
+ 0xffffffff94d23f42ULL, /* 24 */
+ 0x000000004a691fa1ULL,
+ 0xffffffffdebb20e3ULL,
+ 0x0000000000000000ULL,
+ 0x000000001bda37e2ULL,
+ 0xffffffffc5611701ULL,
+ 0xfffffffff1d4a28cULL,
+ 0x000000002f6f826fULL,
+ 0xffffffff8f0808a0ULL, /* 32 */
+ 0x0000000051b32843ULL,
+ 0xffffffffc5611701ULL,
+ 0x000000001bda37e2ULL,
+ 0x0000000000000000ULL,
+ 0xffffffffdebb20e3ULL,
+ 0xffffffffea0e956eULL,
+ 0x0000000034b5b58dULL,
+ 0x0000000051b32843ULL, /* 40 */
+ 0xffffffff8f0808a0ULL,
+ 0x000000001bda37e2ULL,
+ 0xffffffffc5611701ULL,
+ 0xffffffffdebb20e3ULL,
+ 0x0000000000000000ULL,
+ 0x0000000034b5b58dULL,
+ 0xffffffffea0e956eULL,
+ 0x0000000065069dceULL, /* 48 */
+ 0xffffffffbbbdbd2dULL,
+ 0x000000002f6f826fULL,
+ 0xfffffffff1d4a28cULL,
+ 0xffffffffea0e956eULL,
+ 0x0000000034b5b58dULL,
+ 0x0000000000000000ULL,
+ 0xffffffffdebb20e3ULL,
+ 0xffffffffbbbdbd2dULL, /* 56 */
+ 0x0000000065069dceULL,
+ 0xfffffffff1d4a28cULL,
+ 0x000000002f6f826fULL,
+ 0x0000000034b5b58dULL,
+ 0xffffffffea0e956eULL,
+ 0xffffffffdebb20e3ULL,
+ 0x0000000000000000ULL,
+ 0x0000000000000000ULL, /* 64 */
+ 0xffffffff90485967ULL,
+ 0x000000006dfb974aULL,
+ 0x00000000083e4538ULL,
+ 0xffffffff90485967ULL,
+ 0x0000000000000000ULL,
+ 0xfffffffffdb3ce2dULL,
+ 0xffffffff98761c5fULL,
+ 0x000000006dfb974aULL, /* 72 */
+ 0xfffffffffdb3ce2dULL,
+ 0x0000000000000000ULL,
+ 0x0000000065c5d272ULL,
+ 0x00000000083e4538ULL,
+ 0xffffffff98761c5fULL,
+ 0x0000000065c5d272ULL,
+ 0x0000000000000000ULL,
+ };
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32W(b64_pattern + i, b64_pattern + j,
+ b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32W(b64_random + i, b64_random + j,
+ b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) *
+ (PATTERN_INPUTS_64_SHORT_COUNT)) +
+ RANDOM_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_64(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time, b64_result,
+ b64_expect);
+
+ return ret;
+}
diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target
index 45c9cfe..38345ff 100644
--- a/tests/tcg/multiarch/Makefile.target
+++ b/tests/tcg/multiarch/Makefile.target
@@ -29,6 +29,7 @@ run-float_%: float_%
$(call run-test,$<, $(QEMU) $(QEMU_OPTS) $<)
$(call conditional-diff-out,$<,$(SRC_PATH)/tests/tcg/$(TARGET_NAME)/$<.ref)
+fnmsub: LDFLAGS+=-lm
testthread: LDFLAGS+=-lpthread
@@ -188,6 +189,10 @@ run-plugin-semiconsole-with-%:
TESTS += semihosting semiconsole
endif
+test-plugin-mem-access: CFLAGS+=-pthread -O0
+test-plugin-mem-access: LDFLAGS+=-pthread -O0
+
+ifeq ($(CONFIG_PLUGIN),y)
# Test plugin memory access instrumentation
run-plugin-test-plugin-mem-access-with-libmem.so: \
PLUGIN_ARGS=$(COMMA)print-accesses=true
@@ -196,8 +201,8 @@ run-plugin-test-plugin-mem-access-with-libmem.so: \
$(SRC_PATH)/tests/tcg/multiarch/check-plugin-output.sh \
$(QEMU) $<
-test-plugin-mem-access: CFLAGS+=-pthread -O0
-test-plugin-mem-access: LDFLAGS+=-pthread -O0
+EXTRA_RUNS += run-plugin-test-plugin-mem-access-with-libmem.so
+endif
# Update TESTS
TESTS += $(MULTIARCH_TESTS)
diff --git a/tests/tcg/multiarch/fnmsub.c b/tests/tcg/multiarch/fnmsub.c
new file mode 100644
index 0000000..15dd41d
--- /dev/null
+++ b/tests/tcg/multiarch/fnmsub.c
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <stdio.h>
+#include <math.h>
+#include <fenv.h>
+
+union U {
+ double d;
+ unsigned long long l;
+};
+
+union U x = { .l = 0x4ff0000000000000ULL };
+union U y = { .l = 0x2ff0000000000000ULL };
+union U r;
+
+int main()
+{
+#ifdef FE_DOWNWARD
+ fesetround(FE_DOWNWARD);
+
+#if defined(__loongarch__)
+ asm("fnmsub.d %0, %1, %1, %2" : "=f"(r.d) : "f"(x.d), "f"(y.d));
+#elif defined(__powerpc64__)
+ asm("fnmsub %0,%1,%1,%2" : "=f"(r.d) : "f"(x.d), "f"(y.d));
+#elif defined(__s390x__) && 0 /* need -march=z14 */
+ asm("vfnms %0,%1,%1,%2,0,3" : "=f"(r.d) : "f"(x.d), "f"(y.d));
+#else
+ r.d = -fma(x.d, x.d, -y.d);
+#endif
+
+ if (r.l != 0xdfefffffffffffffULL) {
+ printf("r = %.18a (%016llx)\n", r.d, r.l);
+ return 1;
+ }
+#endif
+ return 0;
+}
diff --git a/tests/tcg/multiarch/system/Makefile.softmmu-target b/tests/tcg/multiarch/system/Makefile.softmmu-target
index 07be001..4171b4e 100644
--- a/tests/tcg/multiarch/system/Makefile.softmmu-target
+++ b/tests/tcg/multiarch/system/Makefile.softmmu-target
@@ -6,6 +6,11 @@
# architecture to add to the test dependencies and deal with the
# complications of building.
#
+# To support the multiarch guests the target arch needs to provide a
+# boot.S that jumps to main and provides a __sys_outc functions.
+# Remember to update MULTIARCH_SOFTMMU_TARGETS in the tcg test
+# Makefile.target when this is done.
+#
MULTIARCH_SRC=$(SRC_PATH)/tests/tcg/multiarch
MULTIARCH_SYSTEM_SRC=$(MULTIARCH_SRC)/system
@@ -66,8 +71,11 @@ endif
MULTIARCH_RUNS += run-gdbstub-memory run-gdbstub-interrupt \
run-gdbstub-untimely-packet run-gdbstub-registers
+ifeq ($(CONFIG_PLUGIN),y)
# Test plugin memory access instrumentation
-run-plugin-memory-with-libmem.so: \
- PLUGIN_ARGS=$(COMMA)region-summary=true
-run-plugin-memory-with-libmem.so: \
- CHECK_PLUGIN_OUTPUT_COMMAND=$(MULTIARCH_SYSTEM_SRC)/validate-memory-counts.py $@.out
+run-plugin-memory-with-libmem.so: memory libmem.so
+run-plugin-memory-with-libmem.so: PLUGIN_ARGS=$(COMMA)region-summary=true
+run-plugin-memory-with-libmem.so: CHECK_PLUGIN_OUTPUT_COMMAND=$(MULTIARCH_SYSTEM_SRC)/validate-memory-counts.py $@.out
+
+EXTRA_RUNS += run-plugin-memory-with-libmem.so
+endif
diff --git a/tests/tcg/plugins/mem.c b/tests/tcg/plugins/mem.c
index d87d662..9649bce 100644
--- a/tests/tcg/plugins/mem.c
+++ b/tests/tcg/plugins/mem.c
@@ -20,6 +20,7 @@
* few things provided by compiler.h.
*/
#include <compiler.h>
+#include <stdbool.h>
#include <bswap.h>
#include <qemu-plugin.h>
@@ -67,7 +68,7 @@ static enum qemu_plugin_mem_rw rw = QEMU_PLUGIN_MEM_RW;
static GMutex lock;
static GHashTable *regions;
-static gint addr_order(gconstpointer a, gconstpointer b)
+static gint addr_order(gconstpointer a, gconstpointer b, gpointer d)
{
RegionInfo *na = (RegionInfo *) a;
RegionInfo *nb = (RegionInfo *) b;
@@ -94,7 +95,7 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
if (do_region_summary) {
GList *counts = g_hash_table_get_values(regions);
- counts = g_list_sort(counts, addr_order);
+ counts = g_list_sort_with_data(counts, addr_order, NULL);
g_string_printf(out, "Region Base, Reads, Writes, Seen all\n");
diff --git a/tests/tcg/plugins/meson.build b/tests/tcg/plugins/meson.build
index 41f02f2..61a007d 100644
--- a/tests/tcg/plugins/meson.build
+++ b/tests/tcg/plugins/meson.build
@@ -1,6 +1,6 @@
t = []
if get_option('plugins')
- foreach i : ['bb', 'empty', 'inline', 'insn', 'mem', 'reset', 'syscall']
+ foreach i : ['bb', 'empty', 'inline', 'insn', 'mem', 'reset', 'syscall', 'patch']
if host_os == 'windows'
t += shared_module(i, files(i + '.c') + '../../../contrib/plugins/win32_linker.c',
include_directories: '../../../include/qemu',
@@ -17,7 +17,7 @@ endif
if t.length() > 0
alias_target('test-plugins', t)
else
- run_target('test-plugins', command: find_program('true'))
+ run_target('test-plugins', command: [python, '-c', ''])
endif
plugin_modules += t
diff --git a/tests/tcg/plugins/patch.c b/tests/tcg/plugins/patch.c
new file mode 100644
index 0000000..111c5c1
--- /dev/null
+++ b/tests/tcg/plugins/patch.c
@@ -0,0 +1,251 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This plugin patches instructions matching a pattern to a different
+ * instruction as they execute
+ *
+ */
+
+#include "glib.h"
+#include "glibconfig.h"
+
+#include <qemu-plugin.h>
+#include <string.h>
+#include <stdio.h>
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
+
+static bool use_hwaddr;
+static GByteArray *target_data;
+static GByteArray *patch_data;
+
+/**
+ * Parse a string of hexadecimal digits into a GByteArray. The string must be
+ * even length
+ */
+static GByteArray *str_to_bytes(const char *str)
+{
+ size_t len = strlen(str);
+
+ if (len == 0 || len % 2 != 0) {
+ return NULL;
+ }
+
+ GByteArray *bytes = g_byte_array_new();
+ char byte[3] = {0};
+ guint8 value = 0;
+
+ for (size_t i = 0; i < len; i += 2) {
+ byte[0] = str[i];
+ byte[1] = str[i + 1];
+ value = (guint8)g_ascii_strtoull(byte, NULL, 16);
+ g_byte_array_append(bytes, &value, 1);
+ }
+
+ return bytes;
+}
+
+static void patch_hwaddr(unsigned int vcpu_index, void *userdata)
+{
+ uintptr_t addr = (uintptr_t) userdata;
+ g_autoptr(GString) str = g_string_new(NULL);
+ g_string_printf(str, "patching: @0x%"
+ PRIxPTR "\n",
+ addr);
+ qemu_plugin_outs(str->str);
+
+ enum qemu_plugin_hwaddr_operation_result result =
+ qemu_plugin_write_memory_hwaddr(addr, patch_data);
+
+
+ if (result != QEMU_PLUGIN_HWADDR_OPERATION_OK) {
+ g_autoptr(GString) errmsg = g_string_new(NULL);
+ g_string_printf(errmsg, "Failed to write memory: %d\n", result);
+ qemu_plugin_outs(errmsg->str);
+ return;
+ }
+
+ GByteArray *read_data = g_byte_array_new();
+
+ result = qemu_plugin_read_memory_hwaddr(addr, read_data,
+ patch_data->len);
+
+ qemu_plugin_outs("Reading memory...\n");
+
+ if (result != QEMU_PLUGIN_HWADDR_OPERATION_OK) {
+ g_autoptr(GString) errmsg = g_string_new(NULL);
+ g_string_printf(errmsg, "Failed to read memory: %d\n", result);
+ qemu_plugin_outs(errmsg->str);
+ return;
+ }
+
+ if (memcmp(patch_data->data, read_data->data, patch_data->len) != 0) {
+ qemu_plugin_outs("Failed to read back written data\n");
+ }
+
+ qemu_plugin_outs("Success!\n");
+
+ return;
+}
+
+static void patch_vaddr(unsigned int vcpu_index, void *userdata)
+{
+ uintptr_t addr = (uintptr_t) userdata;
+ uint64_t hwaddr = 0;
+ if (!qemu_plugin_translate_vaddr(addr, &hwaddr)) {
+ qemu_plugin_outs("Failed to translate vaddr\n");
+ return;
+ }
+ g_autoptr(GString) str = g_string_new(NULL);
+ g_string_printf(str, "patching: @0x%"
+ PRIxPTR " hw: @0x%" PRIx64 "\n",
+ addr, hwaddr);
+ qemu_plugin_outs(str->str);
+
+ qemu_plugin_outs("Writing memory (vaddr)...\n");
+
+ if (!qemu_plugin_write_memory_vaddr(addr, patch_data)) {
+ qemu_plugin_outs("Failed to write memory\n");
+ return;
+ }
+
+ qemu_plugin_outs("Reading memory (vaddr)...\n");
+
+ g_autoptr(GByteArray) read_data = g_byte_array_new();
+
+ if (!qemu_plugin_read_memory_vaddr(addr, read_data, patch_data->len)) {
+ qemu_plugin_outs("Failed to read memory\n");
+ return;
+ }
+
+ if (memcmp(patch_data->data, read_data->data, patch_data->len) != 0) {
+ qemu_plugin_outs("Failed to read back written data\n");
+ }
+
+ qemu_plugin_outs("Success!\n");
+
+ return;
+}
+
+/*
+ * Callback on translation of a translation block.
+ */
+static void vcpu_tb_trans_cb(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
+{
+ g_autoptr(GByteArray) insn_data = g_byte_array_new();
+ uintptr_t addr = 0;
+
+ for (size_t i = 0; i < qemu_plugin_tb_n_insns(tb); i++) {
+ struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
+ uint64_t vaddr = qemu_plugin_insn_vaddr(insn);
+
+ if (use_hwaddr) {
+ uint64_t hwaddr = 0;
+ if (!qemu_plugin_translate_vaddr(vaddr, &hwaddr)) {
+ qemu_plugin_outs("Failed to translate vaddr\n");
+ continue;
+ }
+ /*
+ * As we cannot emulate 64 bit systems on 32 bit hosts we
+ * should never see the top bits set, hence we can safely
+ * cast to uintptr_t.
+ */
+ g_assert(hwaddr <= UINTPTR_MAX);
+ addr = (uintptr_t) hwaddr;
+ } else {
+ g_assert(vaddr <= UINTPTR_MAX);
+ addr = (uintptr_t) vaddr;
+ }
+
+ g_byte_array_set_size(insn_data, qemu_plugin_insn_size(insn));
+ qemu_plugin_insn_data(insn, insn_data->data, insn_data->len);
+
+ if (insn_data->len >= target_data->len &&
+ !memcmp(insn_data->data, target_data->data,
+ MIN(target_data->len, insn_data->len))) {
+ if (use_hwaddr) {
+ qemu_plugin_register_vcpu_tb_exec_cb(tb, patch_hwaddr,
+ QEMU_PLUGIN_CB_NO_REGS,
+ (void *) addr);
+ } else {
+ qemu_plugin_register_vcpu_tb_exec_cb(tb, patch_vaddr,
+ QEMU_PLUGIN_CB_NO_REGS,
+ (void *) addr);
+ }
+ }
+ }
+}
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: <lib>,target=<bytes>,patch=<new_bytes>"
+ "[,use_hwaddr=true|false]");
+}
+
+/*
+ * Called when the plugin is installed
+ */
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
+ const qemu_info_t *info, int argc,
+ char **argv)
+{
+
+ use_hwaddr = true;
+ target_data = NULL;
+ patch_data = NULL;
+
+ if (argc > 4) {
+ usage();
+ return -1;
+ }
+
+ for (size_t i = 0; i < argc; i++) {
+ char *opt = argv[i];
+ g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
+ if (g_strcmp0(tokens[0], "use_hwaddr") == 0) {
+ if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &use_hwaddr)) {
+ fprintf(stderr,
+ "Failed to parse boolean argument use_hwaddr\n");
+ return -1;
+ }
+ } else if (g_strcmp0(tokens[0], "target") == 0) {
+ target_data = str_to_bytes(tokens[1]);
+ if (!target_data) {
+ fprintf(stderr,
+ "Failed to parse target bytes.\n");
+ return -1;
+ }
+ } else if (g_strcmp0(tokens[0], "patch") == 0) {
+ patch_data = str_to_bytes(tokens[1]);
+ if (!patch_data) {
+ fprintf(stderr, "Failed to parse patch bytes.\n");
+ return -1;
+ }
+ } else {
+ fprintf(stderr, "Unknown argument: %s\n", tokens[0]);
+ usage();
+ return -1;
+ }
+ }
+
+ if (!target_data) {
+ fprintf(stderr, "target argument is required\n");
+ usage();
+ return -1;
+ }
+
+ if (!patch_data) {
+ fprintf(stderr, "patch argument is required\n");
+ usage();
+ return -1;
+ }
+
+ if (target_data->len != patch_data->len) {
+ fprintf(stderr, "Target and patch data must be the same length\n");
+ return -1;
+ }
+
+ qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans_cb);
+
+ return 0;
+}
diff --git a/tests/tcg/plugins/syscall.c b/tests/tcg/plugins/syscall.c
index 47aad55..42801f5 100644
--- a/tests/tcg/plugins/syscall.c
+++ b/tests/tcg/plugins/syscall.c
@@ -180,7 +180,7 @@ static void print_entry(gpointer val, gpointer user_data)
qemu_plugin_outs(out);
}
-static gint comp_func(gconstpointer ea, gconstpointer eb)
+static gint comp_func(gconstpointer ea, gconstpointer eb, gpointer d)
{
SyscallStats *ent_a = (SyscallStats *) ea;
SyscallStats *ent_b = (SyscallStats *) eb;
@@ -197,7 +197,7 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
g_mutex_lock(&lock);
GList *entries = g_hash_table_get_values(statistics);
- entries = g_list_sort(entries, comp_func);
+ entries = g_list_sort_with_data(entries, comp_func, NULL);
qemu_plugin_outs("syscall no. calls errors\n");
g_list_foreach(entries, print_entry, NULL);
diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/Makefile.softmmu-target
index 7c1d44d..3ca5953 100644
--- a/tests/tcg/riscv64/Makefile.softmmu-target
+++ b/tests/tcg/riscv64/Makefile.softmmu-target
@@ -20,5 +20,9 @@ EXTRA_RUNS += run-issue1060
run-issue1060: issue1060
$(call run-test, $<, $(QEMU) $(QEMU_OPTS)$<)
+EXTRA_RUNS += run-test-mepc-masking
+run-test-mepc-masking: test-mepc-masking
+ $(call run-test, $<, $(QEMU) $(QEMU_OPTS)$<)
+
# We don't currently support the multiarch system tests
undefine MULTIARCH_TESTS
diff --git a/tests/tcg/riscv64/test-mepc-masking.S b/tests/tcg/riscv64/test-mepc-masking.S
new file mode 100644
index 0000000..fccd2a7
--- /dev/null
+++ b/tests/tcg/riscv64/test-mepc-masking.S
@@ -0,0 +1,73 @@
+/*
+ * Test for MEPC masking bug fix
+ *
+ * This test verifies that MEPC properly masks the lower bits according
+ * to the RISC-V specification when vectored mode bits from STVEC are
+ * written to MEPC.
+ */
+
+ .option norvc
+
+ .text
+ .global _start
+_start:
+ /* Set up machine trap vector */
+ lla t0, machine_trap_handler
+ csrw mtvec, t0
+
+ /* Set STVEC with vectored mode (mode bits = 01) */
+ li t0, 0x80004001
+ csrw stvec, t0
+
+ /* Clear medeleg to handle exceptions in M-mode */
+ csrw medeleg, zero
+
+ /* Trigger illegal instruction exception */
+ .word 0xffffffff
+
+test_completed:
+ /* Exit with result in a0 */
+ /* a0 = 0: success (bits [1:0] were masked) */
+ /* a0 != 0: failure (some bits were not masked) */
+ j _exit
+
+machine_trap_handler:
+ /* Check if illegal instruction (mcause = 2) */
+ csrr t0, mcause
+ li t1, 2
+ bne t0, t1, skip_test
+
+ /* Test: Copy STVEC (with mode bits) to MEPC */
+ csrr t0, stvec /* t0 = 0x80004001 */
+ csrw mepc, t0 /* Write to MEPC */
+ csrr t1, mepc /* Read back MEPC */
+
+ /* Check if bits [1:0] are masked (IALIGN=32 without RVC) */
+ andi a0, t1, 3 /* a0 = 0 if both bits masked correctly */
+
+ /* Set correct return address */
+ lla t0, test_completed
+ csrw mepc, t0
+
+skip_test:
+ mret
+
+/* Exit with semihosting */
+_exit:
+ lla a1, semiargs
+ li t0, 0x20026 /* ADP_Stopped_ApplicationExit */
+ sd t0, 0(a1)
+ sd a0, 8(a1)
+ li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */
+
+ /* Semihosting call sequence */
+ .balign 16
+ slli zero, zero, 0x1f
+ ebreak
+ srai zero, zero, 0x7
+ j .
+
+ .data
+ .balign 8
+semiargs:
+ .space 16
diff --git a/tests/tcg/x86_64/Makefile.softmmu-target b/tests/tcg/x86_64/Makefile.softmmu-target
index ef6bcb4..3e30ca9 100644
--- a/tests/tcg/x86_64/Makefile.softmmu-target
+++ b/tests/tcg/x86_64/Makefile.softmmu-target
@@ -1,13 +1,11 @@
#
-# x86 system tests
-#
-# This currently builds only for i386. The common C code is built
-# with standard compiler flags however so we can support both by
-# adding additional boot files for x86_64.
+# x86_64 system tests
#
-I386_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/i386/system
X64_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/x86_64/system
+X64_SYSTEM_TESTS=$(patsubst $(X64_SYSTEM_SRC)/%.c, %, $(wildcard $(X64_SYSTEM_SRC)/*.c))
+
+VPATH+=$(X64_SYSTEM_SRC)
# These objects provide the basic boot code and helper functions for all tests
CRT_OBJS=boot.o
@@ -18,7 +16,7 @@ LDFLAGS=-Wl,-T$(LINK_SCRIPT) -Wl,-melf_x86_64
CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC)
LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
-TESTS+=$(MULTIARCH_TESTS)
+TESTS+=$(MULTIARCH_TESTS) $(X64_SYSTEM_TESTS)
EXTRA_RUNS+=$(MULTIARCH_RUNS)
# building head blobs
@@ -35,3 +33,12 @@ memory: CFLAGS+=-DCHECK_UNALIGNED=1
# Running
QEMU_OPTS+=-device isa-debugcon,chardev=output -device isa-debug-exit,iobase=0xf4,iosize=0x4 -kernel
+
+ifeq ($(CONFIG_PLUGIN),y)
+run-plugin-patch-target-with-libpatch.so: \
+ PLUGIN_ARGS=$(COMMA)target=ffc0$(COMMA)patch=9090$(COMMA)use_hwaddr=true
+run-plugin-patch-target-with-libpatch.so: \
+ CHECK_PLUGIN_OUTPUT_COMMAND=$(X64_SYSTEM_SRC)/validate-patch.py $@.out
+run-plugin-patch-target-with-libpatch.so: patch-target libpatch.so
+EXTRA_RUNS+=run-plugin-patch-target-with-libpatch.so
+endif
diff --git a/tests/tcg/x86_64/fma.c b/tests/tcg/x86_64/fma.c
index 09c622e..3421961 100644
--- a/tests/tcg/x86_64/fma.c
+++ b/tests/tcg/x86_64/fma.c
@@ -79,14 +79,21 @@ static testdata tests[] = {
/*
* Flushing of denormal outputs to zero should also happen after
* rounding, so setting FTZ should not affect the result or the flags.
- * QEMU currently does not emulate this correctly because we do the
- * flush-to-zero check before rounding, so we incorrectly produce a
- * zero result and set Underflow as well as Precision.
*/
-#ifdef ENABLE_FAILING_TESTS
{ 0x3fdfffffffffffff, 0x001fffffffffffff, 0x801fffffffffffff, true,
0x8010000000000000, 0x20 }, /* Enabling FTZ shouldn't change flags */
-#endif
+ /*
+ * normal * 0 + a denormal. With FTZ disabled this gives an exact
+ * result (equal to the input denormal) that has consumed the denormal.
+ */
+ { 0x3cc8000000000000, 0x0000000000000000, 0x8008000000000000, false,
+ 0x8008000000000000, 0x2 }, /* Denormal */
+ /*
+ * With FTZ enabled, this consumes the denormal, returns zero (because
+ * flushed) and indicates also Underflow and Precision.
+ */
+ { 0x3cc8000000000000, 0x0000000000000000, 0x8008000000000000, true,
+ 0x8000000000000000, 0x32 }, /* Precision, Underflow, Denormal */
};
int main(void)
diff --git a/tests/tcg/x86_64/system/patch-target.c b/tests/tcg/x86_64/system/patch-target.c
new file mode 100644
index 0000000..8c2b6f4
--- /dev/null
+++ b/tests/tcg/x86_64/system/patch-target.c
@@ -0,0 +1,22 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This test target increments a value 100 times. The patcher converts the
+ * inc instruction to a nop, so it only increments the value once.
+ *
+ */
+#include <minilib.h>
+
+int main(void)
+{
+ ml_printf("Running test...\n");
+ unsigned int x = 0;
+ for (int i = 0; i < 100; i++) {
+ asm volatile (
+ "inc %[x]"
+ : [x] "+a" (x)
+ );
+ }
+ ml_printf("Value: %d\n", x);
+ return 0;
+}
diff --git a/tests/tcg/x86_64/system/validate-patch.py b/tests/tcg/x86_64/system/validate-patch.py
new file mode 100755
index 0000000..700950e
--- /dev/null
+++ b/tests/tcg/x86_64/system/validate-patch.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+#
+# validate-patch.py: check the patch applies
+#
+# This program takes two inputs:
+# - the plugin output
+# - the binary output
+#
+# Copyright (C) 2024
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import sys
+from argparse import ArgumentParser
+
+def main() -> None:
+ """
+ Process the arguments, injest the program and plugin out and
+ verify they match up and report if they do not.
+ """
+ parser = ArgumentParser(description="Validate patch")
+ parser.add_argument('test_output',
+ help="The output from the test itself")
+ parser.add_argument('plugin_output',
+ help="The output from plugin")
+ args = parser.parse_args()
+
+ with open(args.test_output, 'r') as f:
+ test_data = f.read()
+ with open(args.plugin_output, 'r') as f:
+ plugin_data = f.read()
+ if "Value: 1" in test_data:
+ sys.exit(0)
+ else:
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()
+