From: Claudiu Zissulescu <claziss@synopsys.com>
The added tests verify basic instructions execution as well
as more advanced features such as zero overhead loops interrupt
system, memory management unit and memory protection unit.
Signed-off-by: Claudiu Zissulescu <claziss@synopsys.com>
Signed-off-by: Cupertino Miranda <cmiranda@synopsys.com>
---
tests/Makefile.include | 1 +
tests/tcg/arc/Makefile | 114 ++++
tests/tcg/arc/Makefile.softmmu-target | 43 ++
tests/tcg/arc/Makefile.target | 101 ++++
tests/tcg/arc/check_add.S | 11 +
tests/tcg/arc/check_addx.S | 71 +++
tests/tcg/arc/check_andx.S | 36 ++
tests/tcg/arc/check_aslx.S | 57 ++
tests/tcg/arc/check_asrx.S | 86 ++++
tests/tcg/arc/check_basic1.S | 30 ++
tests/tcg/arc/check_basic2.S | 26 +
tests/tcg/arc/check_beq.S | 14 +
tests/tcg/arc/check_beqx.S | 26 +
tests/tcg/arc/check_bi.S | 32 ++
tests/tcg/arc/check_big_tb.S | 173 +++++++
tests/tcg/arc/check_bih.S | 29 ++
tests/tcg/arc/check_bnex.S | 26 +
tests/tcg/arc/check_breqx.S | 26 +
tests/tcg/arc/check_brgex.S | 26 +
tests/tcg/arc/check_brhsx.S | 27 +
tests/tcg/arc/check_brlox.S | 26 +
tests/tcg/arc/check_brltx.S | 26 +
tests/tcg/arc/check_brnex.S | 26 +
tests/tcg/arc/check_bta.S | 294 +++++++++++
tests/tcg/arc/check_carry.S | 15 +
tests/tcg/arc/check_enter_leave.S | 715 ++++++++++++++++++++++++++
tests/tcg/arc/check_excp.S | 17 +
tests/tcg/arc/check_excp_1.c | 15 +
tests/tcg/arc/check_excp_jumpdl_mmu.S | 44 ++
tests/tcg/arc/check_excp_mmu.S | 69 +++
tests/tcg/arc/check_flags.S | 23 +
tests/tcg/arc/check_ldaw_mmu.S | 71 +++
tests/tcg/arc/check_ldstx.S | 37 ++
tests/tcg/arc/check_lp.S | 12 +
tests/tcg/arc/check_lp02.S | 72 +++
tests/tcg/arc/check_lp03.S | 49 ++
tests/tcg/arc/check_lp04.S | 48 ++
tests/tcg/arc/check_lp05.S | 23 +
tests/tcg/arc/check_lp06.S | 163 ++++++
tests/tcg/arc/check_lsrx.S | 33 ++
tests/tcg/arc/check_mac.S | 228 ++++++++
tests/tcg/arc/check_manip_10_mmu.S | 173 +++++++
tests/tcg/arc/check_manip_4_mmu.S | 158 ++++++
tests/tcg/arc/check_manip_5_mmu.S | 166 ++++++
tests/tcg/arc/check_manip_mmu.S | 565 ++++++++++++++++++++
tests/tcg/arc/check_mmu.S | 59 +++
tests/tcg/arc/check_mpu.S | 703 +++++++++++++++++++++++++
tests/tcg/arc/check_mpyd.S | 543 +++++++++++++++++++
tests/tcg/arc/check_mpyw.S | 41 ++
tests/tcg/arc/check_norm.S | 40 ++
tests/tcg/arc/check_orx.S | 34 ++
tests/tcg/arc/check_prefetch.S | 37 ++
tests/tcg/arc/check_rolx.S | 47 ++
tests/tcg/arc/check_rorx.S | 64 +++
tests/tcg/arc/check_rtc.S | 29 ++
tests/tcg/arc/check_rtie_user.S | 30 ++
tests/tcg/arc/check_stld.S | 10 +
tests/tcg/arc/check_subf.S | 67 +++
tests/tcg/arc/check_subx.S | 43 ++
tests/tcg/arc/check_swi.S | 115 +++++
tests/tcg/arc/check_swirq.S | 27 +
tests/tcg/arc/check_swirq1.S | 31 ++
tests/tcg/arc/check_swirq3.S | 49 ++
tests/tcg/arc/check_t01.S | 12 +
tests/tcg/arc/check_t02.S | 9 +
tests/tcg/arc/check_timer0.S | 36 ++
tests/tcg/arc/check_timer0_loop.S | 34 ++
tests/tcg/arc/check_timer0_loop3.S | 46 ++
tests/tcg/arc/check_timer0_retrig.S | 29 ++
tests/tcg/arc/check_timer0_sleep.S | 33 ++
tests/tcg/arc/check_timerX_freq.S | 87 ++++
tests/tcg/arc/check_vadd.S | 510 ++++++++++++++++++
tests/tcg/arc/check_vsub.S | 510 ++++++++++++++++++
tests/tcg/arc/check_xorx.S | 32 ++
tests/tcg/arc/ivt.S | 38 ++
tests/tcg/arc/macros.inc | 261 ++++++++++
tests/tcg/arc/memory.x | 12 +
tests/tcg/arc/mmu.inc | 132 +++++
tests/tcg/arc/mpu.inc | 269 ++++++++++
tests/tcg/arc/tarc.ld | 15 +
tests/tcg/arc/tarc_mmu.ld | 15 +
tests/tcg/arc/test_macros.h | 257 +++++++++
tests/tcg/configure.sh | 3 +-
83 files changed, 8331 insertions(+), 1 deletion(-)
create mode 100644 tests/tcg/arc/Makefile
create mode 100644 tests/tcg/arc/Makefile.softmmu-target
create mode 100644 tests/tcg/arc/Makefile.target
create mode 100644 tests/tcg/arc/check_add.S
create mode 100644 tests/tcg/arc/check_addx.S
create mode 100644 tests/tcg/arc/check_andx.S
create mode 100644 tests/tcg/arc/check_aslx.S
create mode 100644 tests/tcg/arc/check_asrx.S
create mode 100644 tests/tcg/arc/check_basic1.S
create mode 100644 tests/tcg/arc/check_basic2.S
create mode 100644 tests/tcg/arc/check_beq.S
create mode 100644 tests/tcg/arc/check_beqx.S
create mode 100644 tests/tcg/arc/check_bi.S
create mode 100644 tests/tcg/arc/check_big_tb.S
create mode 100644 tests/tcg/arc/check_bih.S
create mode 100644 tests/tcg/arc/check_bnex.S
create mode 100644 tests/tcg/arc/check_breqx.S
create mode 100644 tests/tcg/arc/check_brgex.S
create mode 100644 tests/tcg/arc/check_brhsx.S
create mode 100644 tests/tcg/arc/check_brlox.S
create mode 100644 tests/tcg/arc/check_brltx.S
create mode 100644 tests/tcg/arc/check_brnex.S
create mode 100644 tests/tcg/arc/check_bta.S
create mode 100644 tests/tcg/arc/check_carry.S
create mode 100644 tests/tcg/arc/check_enter_leave.S
create mode 100644 tests/tcg/arc/check_excp.S
create mode 100644 tests/tcg/arc/check_excp_1.c
create mode 100644 tests/tcg/arc/check_excp_jumpdl_mmu.S
create mode 100644 tests/tcg/arc/check_excp_mmu.S
create mode 100644 tests/tcg/arc/check_flags.S
create mode 100644 tests/tcg/arc/check_ldaw_mmu.S
create mode 100644 tests/tcg/arc/check_ldstx.S
create mode 100644 tests/tcg/arc/check_lp.S
create mode 100644 tests/tcg/arc/check_lp02.S
create mode 100644 tests/tcg/arc/check_lp03.S
create mode 100644 tests/tcg/arc/check_lp04.S
create mode 100644 tests/tcg/arc/check_lp05.S
create mode 100644 tests/tcg/arc/check_lp06.S
create mode 100644 tests/tcg/arc/check_lsrx.S
create mode 100644 tests/tcg/arc/check_mac.S
create mode 100644 tests/tcg/arc/check_manip_10_mmu.S
create mode 100644 tests/tcg/arc/check_manip_4_mmu.S
create mode 100644 tests/tcg/arc/check_manip_5_mmu.S
create mode 100644 tests/tcg/arc/check_manip_mmu.S
create mode 100644 tests/tcg/arc/check_mmu.S
create mode 100644 tests/tcg/arc/check_mpu.S
create mode 100644 tests/tcg/arc/check_mpyd.S
create mode 100644 tests/tcg/arc/check_mpyw.S
create mode 100644 tests/tcg/arc/check_norm.S
create mode 100644 tests/tcg/arc/check_orx.S
create mode 100644 tests/tcg/arc/check_prefetch.S
create mode 100644 tests/tcg/arc/check_rolx.S
create mode 100644 tests/tcg/arc/check_rorx.S
create mode 100644 tests/tcg/arc/check_rtc.S
create mode 100644 tests/tcg/arc/check_rtie_user.S
create mode 100644 tests/tcg/arc/check_stld.S
create mode 100644 tests/tcg/arc/check_subf.S
create mode 100644 tests/tcg/arc/check_subx.S
create mode 100644 tests/tcg/arc/check_swi.S
create mode 100644 tests/tcg/arc/check_swirq.S
create mode 100644 tests/tcg/arc/check_swirq1.S
create mode 100644 tests/tcg/arc/check_swirq3.S
create mode 100644 tests/tcg/arc/check_t01.S
create mode 100644 tests/tcg/arc/check_t02.S
create mode 100644 tests/tcg/arc/check_timer0.S
create mode 100644 tests/tcg/arc/check_timer0_loop.S
create mode 100644 tests/tcg/arc/check_timer0_loop3.S
create mode 100644 tests/tcg/arc/check_timer0_retrig.S
create mode 100644 tests/tcg/arc/check_timer0_sleep.S
create mode 100644 tests/tcg/arc/check_timerX_freq.S
create mode 100644 tests/tcg/arc/check_vadd.S
create mode 100644 tests/tcg/arc/check_vsub.S
create mode 100644 tests/tcg/arc/check_xorx.S
create mode 100644 tests/tcg/arc/ivt.S
create mode 100644 tests/tcg/arc/macros.inc
create mode 100644 tests/tcg/arc/memory.x
create mode 100644 tests/tcg/arc/mmu.inc
create mode 100644 tests/tcg/arc/mpu.inc
create mode 100644 tests/tcg/arc/tarc.ld
create mode 100644 tests/tcg/arc/tarc_mmu.ld
create mode 100644 tests/tcg/arc/test_macros.h
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 3a0524ce74..9dd0472dfa 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -54,6 +54,7 @@ $(BUILD_TCG_TARGET_RULES): build-tcg-tests-%: $(if $(CONFIG_PLUGIN),test-plugins
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) \
-f $(SRC_PATH)/tests/tcg/Makefile.qemu \
SRC_PATH=$(SRC_PATH) \
+ BUILD_DIR=$(BUILD_DIR) \
V="$(V)" TARGET="$*" guest-tests, \
"BUILD", "TCG tests for $*")
diff --git a/tests/tcg/arc/Makefile b/tests/tcg/arc/Makefile
new file mode 100644
index 0000000000..81226d294e
--- /dev/null
+++ b/tests/tcg/arc/Makefile
@@ -0,0 +1,114 @@
+-include ../../../config-host.mak
+
+CROSS = arc-elf32-
+#CROSS = arc-snps-linux-uclibc-
+
+SIM = ../../../arc-softmmu/qemu-system-arc
+SIM_FLAGS = -M arc-sim -m 3G -nographic -no-reboot -monitor none \
+ -serial stdio -global cpu.mpu-numreg=8 -kernel
+#SIM_FLAGS=-cpu archs
+TST_PATH = $(SRC_PATH)/tests/tcg/arc
+
+CC = $(CROSS)gcc
+LD = $(CROSS)ld
+AS = $(CROSS)as
+CFLAGS = -mcpu=archs -O2 --specs=qemu.specs
+ASFLAGS = -mcpu=archs
+
+TESTCASES = check_add.tst
+TESTCASES += check_lp.tst
+TESTCASES += check_lp02.tst
+TESTCASES += check_lp03.tst
+TESTCASES += check_lp04.tst
+TESTCASES += check_lp05.tst
+TESTCASES += check_lp06.tst
+TESTCASES += check_addx.tst
+TESTCASES += check_andx.tst
+TESTCASES += check_aslx.tst
+TESTCASES += check_asrx.tst
+TESTCASES += check_orx.tst
+TESTCASES += check_rolx.tst
+TESTCASES += check_rorx.tst
+TESTCASES += check_subx.tst
+TESTCASES += check_xorx.tst
+TESTCASES += check_beqx.tst
+TESTCASES += check_bnex.tst
+TESTCASES += check_brhsx.tst
+TESTCASES += check_brlox.tst
+TESTCASES += check_breqx.tst
+TESTCASES += check_brnex.tst
+TESTCASES += check_brltx.tst
+TESTCASES += check_brgex.tst
+TESTCASES += check_ldstx.tst
+TESTCASES += check_stld.tst
+TESTCASES += check_lsrx.tst
+TESTCASES += check_beq.tst
+TESTCASES += check_carry.tst
+TESTCASES += check_flags.tst
+TESTCASES += check_t01.tst
+TESTCASES += check_t02.tst
+TESTCASES += check_basic1.tst
+TESTCASES += check_basic2.tst
+TESTCASES += check_norm.tst
+TESTCASES += check_excp.tst
+TESTCASES += check_excp_1.ctst
+TESTCASES += check_mmu.tst
+TESTCASES += check_excp_mmu.tst
+TESTCASES += check_excp_jumpdl_mmu.tst
+TESTCASES += check_timer0.tst
+TESTCASES += check_timer0_loop.tst
+TESTCASES += check_timer0_loop3.tst
+TESTCASES += check_timer0_retrig.tst
+TESTCASES += check_timer0_sleep.tst
+TESTCASES += check_timerX_freq.tst
+TESTCASES += check_swi.tst
+TESTCASES += check_swirq.tst
+TESTCASES += check_swirq1.tst
+TESTCASES += check_swirq3.tst
+TESTCASES += check_mpyw.tst
+TESTCASES += check_subf.tst
+TESTCASES += check_prefetch.tst
+TESTCASES += check_mac.tst
+TESTCASES += check_ldaw_mmu.tst
+TESTCASES += check_manip_4_mmu.tst
+TESTCASES += check_manip_5_mmu.tst
+TESTCASES += check_manip_10_mmu.tst
+TESTCASES += check_manip_mmu.tst
+TESTCASES += check_rtie_user.tst
+TESTCASES += check_rtc.tst
+TESTCASES += check_mpu.tst
+TESTCASES += check_big_tb.tst
+TESTCASES += check_enter_leave.tst
+TESTCASES += check_bta.tst
+TESTCASES += check_vadd.tst
+TESTCASES += check_vsub.tst
+TESTCASES += check_mpyd.tst
+TESTCASES += check_bi.tst
+TESTCASES += check_bih.tst
+
+all: $(TESTCASES)
+OBJECTS = ivt.o
+
+%.o: $(SRC_PATH)/tests/tcg/arc/%.S
+ echo "Running: $(CC) $(ASFLAGS) -c $< -o $@ -I$(TST_PATH)"; \
+ $(CC) $(ASFLAGS) -c $< -o $@ -I$(TST_PATH)
+
+%_mmu.tst: %_mmu.o ${OBJECTS} $(SRC_PATH)/tests/tcg/arc/macros.inc $(SRC_PATH)/tests/tcg/arc/mmu.inc
+ echo "Running: $(LD) -T $(TST_PATH)/tarc_mmu.ld ${OBJECTS} $< -o $@"; \
+ $(LD) -T $(TST_PATH)/tarc_mmu.ld ${OBJECTS} $< -o $@
+
+%.tst: %.o ${OBJECTS} $(SRC_PATH)/tests/tcg/arc/macros.inc
+ echo "Running: $(LD) -T $(TST_PATH)/tarc.ld ${OBJECTS} $< -o $@"; \
+ $(LD) -T $(TST_PATH)/tarc.ld ${OBJECTS} $< -o $@
+
+%.ctst: $(SRC_PATH)/tests/tcg/arc/%.c
+ $(CC) $(CFLAGS) -Wl,-marcv2elfx -L $(SRC_PATH)/tests/tcg/arc/ $< -o $@
+
+check: $(TESTCASES)
+ @for case in $(TESTCASES); do \
+ echo $(SIM) $(SIM_FLAGS) ./$$case;\
+ $(SIM) $(SIM_FLAGS) ./$$case; \
+ done
+
+clean:
+ $(RM) -rf $(TESTCASES)
diff --git a/tests/tcg/arc/Makefile.softmmu-target b/tests/tcg/arc/Makefile.softmmu-target
new file mode 100644
index 0000000000..3a0db7ef8c
--- /dev/null
+++ b/tests/tcg/arc/Makefile.softmmu-target
@@ -0,0 +1,43 @@
+#
+# ARC softmmu tests
+#
+
+ARC_SRC = $(SRC_PATH)/tests/tcg/arc
+ARC_ALL = $(filter-out $(ARC_SRC)/ivt.S,$(wildcard $(ARC_SRC)/*.S))
+ARC_TESTS = $(patsubst $(ARC_SRC)/%.S, %, $(ARC_ALL))
+
+# Filter out common blobs and broken tests
+ARC_BROKEN_TESTS = check_carry check_excp_jumpdl_mmu
+ARC_USABLE_TESTS = $(filter-out $(ARC_BROKEN_TESTS), $(ARC_TESTS))
+
+# add to the list of tests
+TESTS += $(ARC_USABLE_TESTS)
+VPATH += $(ARC_SRC)
+
+QEMU_OPTS+=-M arc-sim -m 3G -nographic -no-reboot -serial stdio -global cpu.mpu-numreg=8 -kernel
+
+CROSS = arc-elf32-
+
+ASFLAGS = -mcpu=archs
+LDFLAGS = --specs=qemu.specs -T $(ARC_SRC)/tarc.ld -nostartfiles -nostdlib
+MMU_LDFLAGS = --specs=qemu.specs -T $(ARC_SRC)/tarc_mmu.ld -nostartfiles -nostdlib
+CRT = ivt.o
+
+SIM = ../../../qemu-system-arc
+SIM_FLAGS = -M arc-sim -m 3G -nographic -no-reboot -monitor none \
+ -serial stdio -global cpu.mpu-numreg=8 -kernel
+
+$(ARC_USABLE_TESTS): $(CRT) Makefile.softmmu-target
+
+# special rule for common blobs
+%.o: %.S
+ cd ${BUILD_DIR} && \
+ $(CC) -I$(ARC_SRC) $($*ASFLAGS) $(ASFLAGS) $(EXTRACFLAGS) -c $< -o ./$@
+
+%_mmu: %_mmu.o
+ cd ${BUILD_DIR} && \
+ $(CC) -I$(ARC_SRC) $(ASFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(MMU_LDFLAGS) $(NOSTDFLAGS) $(CRT)
+
+%: %.o
+ cd ${BUILD_DIR} && \
+ $(CC) -I$(ARC_SRC) $(ASFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) $(NOSTDFLAGS) $(CRT)
diff --git a/tests/tcg/arc/Makefile.target b/tests/tcg/arc/Makefile.target
new file mode 100644
index 0000000000..abbf1a7b79
--- /dev/null
+++ b/tests/tcg/arc/Makefile.target
@@ -0,0 +1,101 @@
+# -*- Mode: makefile -*-
+#
+# ARC specific tweaks
+
+ARC_SRC=$(SRC_PATH)/tests/tcg/arc-softmmu
+VPATH+=$(ARC_SRC)
+
+ARC_TESTS = check_add.tst
+ARC_TESTS += check_lp.tst
+ARC_TESTS += check_lp02.tst
+ARC_TESTS += check_lp03.tst
+ARC_TESTS += check_lp04.tst
+ARC_TESTS += check_lp05.tst
+ARC_TESTS += check_lp06.tst
+ARC_TESTS += check_addx.tst
+ARC_TESTS += check_andx.tst
+ARC_TESTS += check_aslx.tst
+ARC_TESTS += check_asrx.tst
+ARC_TESTS += check_orx.tst
+ARC_TESTS += check_rolx.tst
+ARC_TESTS += check_rorx.tst
+ARC_TESTS += check_subx.tst
+ARC_TESTS += check_xorx.tst
+ARC_TESTS += check_beqx.tst
+ARC_TESTS += check_bnex.tst
+ARC_TESTS += check_brhsx.tst
+ARC_TESTS += check_brlox.tst
+ARC_TESTS += check_breqx.tst
+ARC_TESTS += check_brnex.tst
+ARC_TESTS += check_brltx.tst
+ARC_TESTS += check_brgex.tst
+ARC_TESTS += check_ldstx.tst
+ARC_TESTS += check_stld.tst
+ARC_TESTS += check_lsrx.tst
+ARC_TESTS += check_beq.tst
+ARC_TESTS += check_carry.tst
+ARC_TESTS += check_flags.tst
+ARC_TESTS += check_t01.tst
+ARC_TESTS += check_t02.tst
+ARC_TESTS += check_basic1.tst
+ARC_TESTS += check_basic2.tst
+ARC_TESTS += check_norm.tst
+ARC_TESTS += check_excp.tst
+ARC_TESTS += check_excp_1.ctst
+ARC_TESTS += check_mmu.tst
+ARC_TESTS += check_excp_mmu.tst
+ARC_TESTS += check_excp_jumpdl_mmu.tst
+ARC_TESTS += check_timer0.tst
+ARC_TESTS += check_timer0_loop.tst
+ARC_TESTS += check_timer0_loop3.tst
+ARC_TESTS += check_timer0_retrig.tst
+ARC_TESTS += check_timer0_sleep.tst
+ARC_TESTS += check_timerX_freq.tst
+ARC_TESTS += check_swi.tst
+ARC_TESTS += check_swirq.tst
+ARC_TESTS += check_swirq1.tst
+ARC_TESTS += check_swirq3.tst
+ARC_TESTS += check_mpyw.tst
+ARC_TESTS += check_subf.tst
+ARC_TESTS += check_prefetch.tst
+ARC_TESTS += check_mac.tst
+ARC_TESTS += check_ldaw_mmu.tst
+ARC_TESTS += check_manip_4_mmu.tst
+ARC_TESTS += check_manip_5_mmu.tst
+ARC_TESTS += check_manip_10_mmu.tst
+ARC_TESTS += check_manip_mmu.tst
+ARC_TESTS += check_rtie_user.tst
+ARC_TESTS += check_rtc.tst
+ARC_TESTS += check_mpu.tst
+ARC_TESTS += check_big_tb.tst
+ARC_TESTS += check_enter_leave.tst
+ARC_TESTS += check_bta.tst
+ARC_TESTS += check_vadd.tst
+ARC_TESTS += check_vsub.tst
+ARC_TESTS += check_mpyd.tst
+
+TESTS+=$(ARC_TESTS)
+
+%.o: $(ARC_SRC)/%.S
+ echo "Running: $(CC) $(ASFLAGS) -c $< -o $@ -I$(TST_PATH)"; \
+ $(CC) $(ASFLAGS) -c $< -o $@ -I$(TST_PATH)
+
+%_mmu.tst: %_mmu.o ${OBJECTS} $(ARC_SRC)/macros.inc $(ARC_SRC)/mmu.inc
+ echo "Running: $(LD) -T $(TST_PATH)/tarc_mmu.ld ${OBJECTS} $< -o $@"; \
+ $(LD) -T $(TST_PATH)/tarc_mmu.ld ${OBJECTS} $< -o $@
+
+%.tst: %.o ${OBJECTS} $(ARC_SRC)/macros.inc
+ echo "Running: $(LD) -T $(TST_PATH)/tarc.ld ${OBJECTS} $< -o $@"; \
+ $(LD) -T $(TST_PATH)/tarc.ld ${OBJECTS} $< -o $@
+
+%.ctst: $(ARC_SRC)/%.c
+ $(CC) $(CFLAGS) -Wl,-marcv2elfx -L $(ARC_SRC)/ $< -o $@
+
+#test-cmov: EXTRA_CFLAGS=-DTEST_CMOV
+#test-cmov: test-cond.c
+# $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
+#
+#run-test-cmov: test-cmov
+#
+## On Alpha Linux only supports 8k pages
+#EXTRA_RUNS+=run-test-mmap-8192
diff --git a/tests/tcg/arc/check_add.S b/tests/tcg/arc/check_add.S
new file mode 100644
index 0000000000..be400cf788
--- /dev/null
+++ b/tests/tcg/arc/check_add.S
@@ -0,0 +1,11 @@
+.include "macros.inc"
+
+ start
+
+ test_name ADD_1
+ mov r2,0x10ff01ff
+ mov r3,0x10010001
+ add r2,r2,r3
+ check_r2 0x21000200
+
+ end
diff --git a/tests/tcg/arc/check_addx.S b/tests/tcg/arc/check_addx.S
new file mode 100644
index 0000000000..467679823f
--- /dev/null
+++ b/tests/tcg/arc/check_addx.S
@@ -0,0 +1,71 @@
+#define ARCTEST_ARC32
+
+#*****************************************************************************
+# add.S
+#-----------------------------------------------------------------------------
+#
+# Test add instruction.
+#
+
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+
+ #-------------------------------------------------------------
+ # Arithmetic tests
+ #-------------------------------------------------------------
+
+ TEST_IMM_OP( 2, add, 0x00000000, 0x00000000, 0x000 )
+ TEST_IMM_OP( 3, add, 0x00000002, 0x00000001, 0x001 )
+ TEST_IMM_OP( 4, add, 0x0000000a, 0x00000003, 0x007 )
+
+ TEST_IMM_OP( 5, add, 0xfffffffffffff800, 0x0000000000000000, 0x800 )
+ TEST_IMM_OP( 6, add, 0xffffffff80000000, 0xffffffff80000000, 0x000 )
+ TEST_IMM_OP( 7, add, 0xffffffff7ffff800, 0xffffffff80000000, 0x800 )
+
+ TEST_IMM_OP( 8, add, 0x00000000000007ff, 0x00000000, 0x7ff )
+ TEST_IMM_OP( 9, add, 0x000000007fffffff, 0x7fffffff, 0x000 )
+ TEST_IMM_OP( 10, add, 0x00000000800007fe, 0x7fffffff, 0x7ff )
+
+ TEST_IMM_OP( 11, add, 0xffffffff800007ff, 0xffffffff80000000, 0x7ff )
+ TEST_IMM_OP( 12, add, 0x000000007ffff7ff, 0x000000007fffffff, 0x800 )
+
+ TEST_IMM_OP( 13, add, 0xffffffffffffffff, 0x0000000000000000, 0xfff )
+ TEST_IMM_OP( 14, add, 0x0000000000000000, 0xffffffffffffffff, 0x001 )
+ TEST_IMM_OP( 15, add, 0xfffffffffffffffe, 0xffffffffffffffff, 0xfff )
+
+ TEST_IMM_OP( 16, add, 0x0000000080000000, 0x7fffffff, 0x001 )
+
+ TEST_RR_3OP( 17, add, 0x00000000, 0x00000000, 0x00000000 )
+ TEST_RR_3OP( 18, add, 0x00000002, 0x00000001, 0x00000001 )
+ TEST_RR_3OP( 19, add, 0x0000000a, 0x00000003, 0x00000007 )
+
+ TEST_RR_3OP( 20, add, 0xffffffffffff8000, 0x0000000000000000, 0xffffffffffff8000 )
+ TEST_RR_3OP( 21, add, 0xffffffff80000000, 0xffffffff80000000, 0x00000000 )
+ TEST_RR_3OP( 22, add, 0xffffffff7fff8000, 0xffffffff80000000, 0xffffffffffff8000 )
+
+ TEST_RR_3OP( 23, add, 0x0000000000007fff, 0x0000000000000000, 0x0000000000007fff )
+ TEST_RR_3OP( 24, add, 0x000000007fffffff, 0x000000007fffffff, 0x0000000000000000 )
+ TEST_RR_3OP( 25, add, 0x0000000080007ffe, 0x000000007fffffff, 0x0000000000007fff )
+
+ TEST_RR_3OP( 26, add, 0xffffffff80007fff, 0xffffffff80000000, 0x0000000000007fff )
+ TEST_RR_3OP( 27, add, 0x000000007fff7fff, 0x000000007fffffff, 0xffffffffffff8000 )
+
+ TEST_RR_3OP( 28, add, 0xffffffffffffffff, 0x0000000000000000, 0xffffffffffffffff )
+ TEST_RR_3OP( 29, add, 0x0000000000000000, 0xffffffffffffffff, 0x0000000000000001 )
+ TEST_RR_3OP( 30, add, 0xfffffffffffffffe, 0xffffffffffffffff, 0xffffffffffffffff )
+
+ TEST_RR_3OP( 31, add, 0x0000000080000000, 0x0000000000000001, 0x000000007fffffff )
+
+
+ #-------------------------------------------------------------
+ # Source/Destination tests
+ #-------------------------------------------------------------
+
+ TEST_IMM_SRC1_EQ_DEST( 32, add, 24, 13, 11 )
+
+ TEST_RR_SRC1_EQ_DEST( 33, add, 24, 13, 11 )
+ TEST_RR_SRC2_EQ_DEST( 34, add, 25, 14, 11 )
+ TEST_RR_SRC12_EQ_DEST( 35, add, 26, 13 )
+
+ARCTEST_END
diff --git a/tests/tcg/arc/check_andx.S b/tests/tcg/arc/check_andx.S
new file mode 100644
index 0000000000..efdec10ae3
--- /dev/null
+++ b/tests/tcg/arc/check_andx.S
@@ -0,0 +1,36 @@
+#define ARCTEST_ARC32
+
+#*****************************************************************************
+# and.S
+#-----------------------------------------------------------------------------
+#
+# Test and instruction.
+#
+
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+
+ #-------------------------------------------------------------
+ # Logical tests
+ #-------------------------------------------------------------
+
+ TEST_IMM_OP( 2, and, 0xff00ff00, 0xff00ff00, 0xf0f );
+ TEST_IMM_OP( 3, and, 0x000000f0, 0x0ff00ff0, 0x0f0 );
+ TEST_IMM_OP( 4, and, 0x0000000f, 0x00ff00ff, 0x70f );
+ TEST_IMM_OP( 5, and, 0x00000000, 0xf00ff00f, 0x0f0 );
+ TEST_RR_3OP( 6, and, 0x0f000f00, 0xff00ff00, 0x0f0f0f0f );
+ TEST_RR_3OP( 7, and, 0x00f000f0, 0x0ff00ff0, 0xf0f0f0f0 );
+ TEST_RR_3OP( 8, and, 0x000f000f, 0x00ff00ff, 0x0f0f0f0f );
+ TEST_RR_3OP( 9, and, 0xf000f000, 0xf00ff00f, 0xf0f0f0f0 );
+
+ #-------------------------------------------------------------
+ # Source/Destination tests
+ #-------------------------------------------------------------
+
+ TEST_IMM_SRC1_EQ_DEST( 10, and, 0x00000000, 0xff00ff00, 0x0f0 );
+ TEST_RR_SRC1_EQ_DEST( 11, and, 0x0f000f00, 0xff00ff00, 0x0f0f0f0f );
+ TEST_RR_SRC2_EQ_DEST( 12, and, 0x00f000f0, 0x0ff00ff0, 0xf0f0f0f0 );
+ TEST_RR_SRC12_EQ_DEST( 13, and, 0xff00ff00, 0xff00ff00 );
+
+ARCTEST_END
diff --git a/tests/tcg/arc/check_aslx.S b/tests/tcg/arc/check_aslx.S
new file mode 100644
index 0000000000..77eb3c65cc
--- /dev/null
+++ b/tests/tcg/arc/check_aslx.S
@@ -0,0 +1,57 @@
+#define ARCTEST_ARC32
+
+#*****************************************************************************
+# check_aslx.S
+#-----------------------------------------------------------------------------
+#
+# Test or instruction.
+#
+# .--------------.----------.--------------.
+# | instruction | check CC | update flags |
+# |--------------+----------+--------------|
+# | asl | no | Z, N, C, V |
+# | asl multiple | yes | Z, N, C |
+# `--------------^----------^--------------'
+
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+
+ #-------------------------------------------------------------
+ # Logical tests
+ #-------------------------------------------------------------
+ TEST_RR_3OP(2, asl, 0x12345678, 0x12345678, 0);
+ TEST_RR_3OP(3, asl, 0x23456780, 0x12345678, 4);
+ TEST_RR_3OP(4, asl, 0x80000000, 0x12345671, 31);
+
+ TEST_RR_2OP(5, asl, 0x00000002, 0x00000001);
+ TEST_RR_2OP(6, asl, 0x00000000, 0x80000000);
+
+ #-------------------------------------------------------------
+ # Source/Destination tests
+ #-------------------------------------------------------------
+ TEST_RR_SRC1_EQ_DEST (7, asl, 0xf7780000, 0xdeedbeef, 0x00000013);
+ TEST_RR_2OP_SRC1_EQ_DEST(8, asl, 0x000804ca, 0x80040265);
+
+ #-------------------------------------------------------------
+ # Flag tests
+ #-------------------------------------------------------------
+ TEST_2OP_CARRY ( 9, asl, 0, 0x10000000, 0x02);
+ TEST_2OP_CARRY (10, asl, 1, 0x80000000, 0x01);
+ TEST_2OP_CARRY (11, asl, 0, 0xffffffff, 0x00);
+ TEST_2OP_ZERO (12, asl, 1, 0x12345670, 0xbf);
+ TEST_2OP_NEGATIVE(13, asl, 1, 0x1F345678, 0x04);
+ # no overflow flag update in "asl multiple"
+ TEST_2OP_OVERFLOW(14, asl, 0, 0x80000000, 0x01);
+
+ TEST_1OP_CARRY (15, asl, 0, 0x40000000);
+ TEST_1OP_CARRY (16, asl, 1, 0x80000000);
+ TEST_1OP_ZERO (17, asl, 0, 0x00001000);
+ TEST_1OP_ZERO (18, asl, 1, 0x80000000);
+ TEST_1OP_NEGATIVE(19, asl, 0, 0x20000000);
+ TEST_1OP_NEGATIVE(20, asl, 1, 0x40000000);
+ TEST_1OP_OVERFLOW(21, asl, 1, 0x80000000);
+ TEST_1OP_OVERFLOW(22, asl, 0, 0xffffffff);
+ TEST_1OP_OVERFLOW(23, asl, 1, 0x40000000);
+
+ARCTEST_END
diff --git a/tests/tcg/arc/check_asrx.S b/tests/tcg/arc/check_asrx.S
new file mode 100644
index 0000000000..6729f0c42b
--- /dev/null
+++ b/tests/tcg/arc/check_asrx.S
@@ -0,0 +1,86 @@
+#define ARCTEST_ARC32
+
+#*****************************************************************************
+# check_asrx.S
+#-----------------------------------------------------------------------------
+#
+# Test or instruction.
+#
+# .--------------.----------.--------------.
+# | instruction | check CC | update flags |
+# |--------------+----------+--------------|
+# | asr | no | Z, N, C |
+# | asr multiple | yes | Z, N, C |
+# | asr8 | no | Z, N |
+# | asr16 | no | Z, N |
+# `--------------^----------^--------------'
+
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+
+ #-------------------------------------------------------------
+ # Logical tests
+ #-------------------------------------------------------------
+ TEST_RR_3OP( 2, asr , 0x12345678, 0x12345678, 0);
+ TEST_RR_3OP( 3, asr , 0x01234567, 0x12345678, 4);
+ TEST_RR_3OP( 4, asr , 0xFF234567, 0xF2345678, 4);
+ TEST_RR_3OP( 5, asr , 0xffffffff, 0x8fffffff, 31);
+ TEST_RR_3OP( 6, asr , 0x00000001, 0x7fffffff, 30);
+
+ TEST_RR_2OP( 7, asr , 0x00000009, 0x00000012);
+ TEST_RR_2OP( 8, asr , 0xc0000000, 0x80000000);
+ TEST_RR_2OP( 9, asr , 0x20000000, 0x40000000);
+
+ TEST_RR_2OP(10, asr8 , 0x00000100, 0x00010000);
+ TEST_RR_2OP(11, asr8 , 0xffff0000, 0xff000000);
+ TEST_RR_2OP(12, asr8 , 0xff800000, 0x80000000);
+ TEST_RR_2OP(13, asr8 , 0x007f0000, 0x7f000000);
+ TEST_RR_2OP(14, asr8 , 0x00000000, 0x000000ff);
+
+ TEST_RR_2OP(15, asr16, 0x00000001, 0x00010000);
+ TEST_RR_2OP(16, asr16, 0xffffffff, 0xffff0000);
+ TEST_RR_2OP(17, asr16, 0xffff8000, 0x80000000);
+ TEST_RR_2OP(18, asr16, 0x00007fff, 0x7fff0000);
+ TEST_RR_2OP(19, asr16, 0x00000000, 0x0000ff00);
+
+ #-------------------------------------------------------------
+ # Source/Destination tests
+ #-------------------------------------------------------------
+ TEST_RR_SRC1_EQ_DEST (20, asr , 0xfffffbdd, 0xdeedbeef, 0x00000013);
+ TEST_RR_2OP_SRC1_EQ_DEST(21, asr , 0xc0020132, 0x80040265);
+ TEST_RR_2OP_SRC1_EQ_DEST(22, asr8 , 0xff800402, 0x80040265);
+ TEST_RR_2OP_SRC1_EQ_DEST(23, asr16, 0xffff8004, 0x80040265);
+
+ #-------------------------------------------------------------
+ # Flag tests
+ #-------------------------------------------------------------
+ TEST_2OP_CARRY (24, asr , 0, 0x00000001, 0x02);
+ TEST_2OP_CARRY (25, asr , 1, 0x00000001, 0x01);
+ TEST_2OP_ZERO (26, asr , 0, 0x00000004, 0x02);
+ TEST_2OP_ZERO (27, asr , 1, 0x12345678, 0xbf);
+ TEST_2OP_NEGATIVE(28, asr , 1, 0xFF345678, 0x04);
+ TEST_2OP_NEGATIVE(29, asr , 0, 0x7F345678, 0x04);
+
+ TEST_1OP_CARRY (30, asr , 0, 0x00000002);
+ TEST_1OP_CARRY (31, asr , 1, 0x00000001);
+ TEST_1OP_ZERO (32, asr , 0, 0x00000002);
+ TEST_1OP_ZERO (33, asr , 1, 0x00000001);
+ TEST_1OP_NEGATIVE(34, asr , 1, 0x80000000);
+ TEST_1OP_NEGATIVE(35, asr , 0, 0x7fffffff);
+
+ TEST_1OP_CARRY (36, asr8 , 0, 0x0000007f);
+ TEST_1OP_CARRY (37, asr8 , 0, 0xffffffff);
+ TEST_1OP_ZERO (38, asr8 , 0, 0x00000100);
+ TEST_1OP_ZERO (39, asr8 , 1, 0x000000ff);
+ TEST_1OP_NEGATIVE(40, asr8 , 1, 0x80000000);
+ TEST_1OP_NEGATIVE(41, asr8 , 0, 0x7fffffff);
+
+ TEST_1OP_CARRY (42, asr16, 0, 0x00007fff);
+ TEST_1OP_CARRY (43, asr16, 0, 0xffffffff);
+ TEST_1OP_ZERO (44, asr16, 0, 0x00010000);
+ TEST_1OP_ZERO (45, asr16, 1, 0x0000ffff);
+ TEST_1OP_NEGATIVE(46, asr16, 1, 0x80000000);
+ TEST_1OP_NEGATIVE(47, asr16, 0, 0x7fffffff);
+
+ARCTEST_END
diff --git a/tests/tcg/arc/check_basic1.S b/tests/tcg/arc/check_basic1.S
new file mode 100644
index 0000000000..b26c548bc2
--- /dev/null
+++ b/tests/tcg/arc/check_basic1.S
@@ -0,0 +1,30 @@
+#define ARCTEST_ARC32
+
+#*****************************************************************************
+# ror.S
+#-----------------------------------------------------------------------------
+#
+# Test or instruction.
+#
+
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+
+ #-------------------------------------------------------------
+ # Logical tests
+ #-------------------------------------------------------------
+ TEST_RR_3OP( 2, ror, 0xca000804, 0x000804ca, 0xfff80008);
+ TEST_RR_3OP( 3, add1, 0x00000096, 0x00000002, 0x0000004a);
+ TEST_RR_3OP( 4, add2, 0x0000025a, 0x00000002, 0x00000096);
+ TEST_RR_3OP( 5, asr, 0x000007da, 0x00000fb5, 0xfff00001);
+ TEST_RR_3OP( 6, bic, 0x01010101, 0x29292909, 0x2a2a2a0a);
+ TEST_RR_3OP( 7, rsub, 0x00000011, 0x50005134, 0x50005145);
+ TEST_RR_3OP( 8, sub1, 0xfffff720, 0x0000046e, 0x000006a7);
+ TEST_RR_3OP( 9, sub3, 0xfffff9e4, 0x000008ac, 0x000001d9);
+
+ #-------------------------------------------------------------
+ # Source/Destination tests
+ #-------------------------------------------------------------
+
+ARCTEST_END
diff --git a/tests/tcg/arc/check_basic2.S b/tests/tcg/arc/check_basic2.S
new file mode 100644
index 0000000000..31de81a2e4
--- /dev/null
+++ b/tests/tcg/arc/check_basic2.S
@@ -0,0 +1,26 @@
+#define ARCTEST_ARC32
+
+#*****************************************************************************
+# ror.S
+#-----------------------------------------------------------------------------
+#
+# Test or instruction.
+#
+
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+
+ #-------------------------------------------------------------
+ # Logical tests
+ #-------------------------------------------------------------
+ TEST_RR_3OP( 2, bmsk, 0x010101FF, 0x010101FF, 0x800289bf);
+ TEST_RR_3OP( 3, bmsk, 0x00000001, 0x01010101, 0x89000007);
+ TEST_RR_3OP( 4, min, 0xffffff00, 0xffffff00, 0x000000ff);
+ TEST_RR_3OP( 5, lsr, 0x658403fd, 0xcb0807fb, 0x89000001);
+
+ #-------------------------------------------------------------
+ # Source/Destination tests
+ #-------------------------------------------------------------
+
+ARCTEST_END
diff --git a/tests/tcg/arc/check_beq.S b/tests/tcg/arc/check_beq.S
new file mode 100644
index 0000000000..841f4c6760
--- /dev/null
+++ b/tests/tcg/arc/check_beq.S
@@ -0,0 +1,14 @@
+.include "macros.inc"
+
+ start
+ test_name BEQ_1
+ mov.f r2,0
+ beq 1f
+ check_r2 0x01
+1:
+ beq.d 2f
+ mov r2,0x01
+ check_r2 0x00
+2:
+ check_r2 0x01
+ end
diff --git a/tests/tcg/arc/check_beqx.S b/tests/tcg/arc/check_beqx.S
new file mode 100644
index 0000000000..2c246da2ce
--- /dev/null
+++ b/tests/tcg/arc/check_beqx.S
@@ -0,0 +1,26 @@
+#*****************************************************************************
+# beq.S
+#-----------------------------------------------------------------------------
+#
+# Test beq instruction.
+#
+
+#define ARCTEST_ARC32
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+ #-------------------------------------------------------------
+ # Branch tests
+ #-------------------------------------------------------------
+
+ # Each test checks both forward and backward branches
+
+ TEST_BR2_OP_TAKEN( 2, beq, 0, 0 );
+ TEST_BR2_OP_TAKEN( 3, beq, 1, 1 );
+ TEST_BR2_OP_TAKEN( 4, beq, -1, -1 );
+
+ TEST_BR2_OP_NOTTAKEN( 5, beq, 0, 1 );
+ TEST_BR2_OP_NOTTAKEN( 6, beq, 1, 0 );
+ TEST_BR2_OP_NOTTAKEN( 7, beq, -1, 1 );
+ TEST_BR2_OP_NOTTAKEN( 8, beq, 1, -1 );
+ARCTEST_END
diff --git a/tests/tcg/arc/check_bi.S b/tests/tcg/arc/check_bi.S
new file mode 100644
index 0000000000..f71748a346
--- /dev/null
+++ b/tests/tcg/arc/check_bi.S
@@ -0,0 +1,32 @@
+ .include "macros.inc"
+
+ start
+ test_name BI
+ mov_s r0,0
+.Lloop:
+ bi [r0]
+ b @.L1
+ b @.L2
+ b @.L3
+ b @.L4
+ b @.Lfail
+ b @.Lfail
+ b @.Lfail
+.L1:
+ add r0,r0,1
+ print "[PASS] BI:jmp0\n"
+ b @.Lloop
+.L2:
+ add r0,r0,1
+ print "[PASS] BI:jmp1\n"
+ b @.Lloop
+.L3:
+ add r0,r0,1
+ print "[PASS] BI:jmp2\n"
+ b @.Lloop
+.L4:
+ print "[PASS] BI\n"
+ end
+.Lfail:
+ print "[FAIL] BI\n"
+ end
diff --git a/tests/tcg/arc/check_big_tb.S b/tests/tcg/arc/check_big_tb.S
new file mode 100644
index 0000000000..1c22b811ae
--- /dev/null
+++ b/tests/tcg/arc/check_big_tb.S
@@ -0,0 +1,173 @@
+.equ POWER_DEVICE, 0xF0000008 ; power management device
+
+.text
+.global main
+.align 4
+main:
+
+add3 r6,sp,0x38
+mov_s r7,0x152f8
+ldd r4r5,[r7]
+ldd r2r3,[r7,8]
+std r4r5,[r6]
+ldd r4r5,[r7,16]
+std r2r3,[r6,8]
+ldd r2r3,[r7,24]
+std r4r5,[r6,16]
+std r2r3,[r6,24]
+add3 r6,sp,0x34
+mov_s r7,0x152d8
+ldd r4r5,[r7]
+ldd r2r3,[r7,8]
+std r4r5,[r6]
+ldd r4r5,[r7,16]
+std r2r3,[r6,8]
+ldd r2r3,[r7,24]
+std r4r5,[r6,16]
+std r2r3,[r6,24]
+add3 r6,sp,0x30
+mov_s r7,0x152b8
+ldd r4r5,[r7]
+ldd r2r3,[r7,8]
+std r4r5,[r6]
+ldd r4r5,[r7,16]
+std r2r3,[r6,8]
+ldd r2r3,[r7,24]
+std r4r5,[r6,16]
+std r2r3,[r6,24]
+add3 r6,sp,0x2c
+mov_s r7,0x15298
+ldd r4r5,[r7]
+ldd r2r3,[r7,8]
+std r4r5,[r6]
+ldd r4r5,[r7,16]
+std r2r3,[r6,8]
+ldd r2r3,[r7,24]
+std r4r5,[r6,16]
+std r2r3,[r6,24]
+add3 r6,sp,0x28
+mov_s r7,0x15278
+ldd r4r5,[r7]
+ldd r2r3,[r7,8]
+std r4r5,[r6]
+ldd r4r5,[r7,16]
+std r2r3,[r6,8]
+ldd r2r3,[r7,24]
+std r4r5,[r6,16]
+std r2r3,[r6,24]
+add3 r6,sp,0x24
+mov_s r7,0x15258
+ldd r4r5,[r7]
+ldd r2r3,[r7,8]
+std r4r5,[r6]
+ldd r4r5,[r7,16]
+std r2r3,[r6,8]
+ldd r2r3,[r7,24]
+std r4r5,[r6,16]
+std r2r3,[r6,24]
+add3 r6,sp,0x20
+mov_s r7,0x15238
+ldd r4r5,[r7]
+ldd r2r3,[r7,8]
+std r4r5,[r6]
+ldd r4r5,[r7,16]
+std r2r3,[r6,8]
+ldd r2r3,[r7,24]
+std r4r5,[r6,16]
+std r2r3,[r6,24]
+add3 r6,sp,0x1c
+mov_s r7,0x15218
+ldd r4r5,[r7]
+ldd r2r3,[r7,8]
+std r4r5,[r6]
+ldd r4r5,[r7,16]
+std r2r3,[r6,8]
+ldd r2r3,[r7,24]
+std r4r5,[r6,16]
+std r2r3,[r6,24]
+add3 r6,sp,0x18
+mov_s r7,0x151f8
+ldd r4r5,[r7]
+ldd r2r3,[r7,8]
+std r4r5,[r6]
+ldd r4r5,[r7,16]
+std r2r3,[r6,8]
+ldd r2r3,[r7,24]
+std r4r5,[r6,16]
+std r2r3,[r6,24]
+add3 r6,sp,0x14
+mov_s r7,0x151d8
+ldd r4r5,[r7]
+ldd r2r3,[r7,8]
+std r4r5,[r6]
+ldd r4r5,[r7,16]
+std r2r3,[r6,8]
+ldd r2r3,[r7,24]
+std r4r5,[r6,16]
+std r2r3,[r6,24]
+add3 r6,sp,0x10
+mov_s r7,0x151b8
+ldd r4r5,[r7]
+ldd r2r3,[r7,8]
+std r4r5,[r6]
+ldd r4r5,[r7,16]
+std r2r3,[r6,8]
+ldd r2r3,[r7,24]
+std r4r5,[r6,16]
+std r2r3,[r6,24]
+add3 r6,sp,0xc
+mov_s r7,0x15198
+ldd r4r5,[r7]
+ldd r2r3,[r7,8]
+std r4r5,[r6]
+ldd r4r5,[r7,16]
+std r2r3,[r6,8]
+ldd r2r3,[r7,24]
+std r4r5,[r6,16]
+std r2r3,[r6,24]
+add3 r6,sp,0x8
+mov_s r7,0x15178
+ldd r4r5,[r7]
+ldd r2r3,[r7,8]
+std r4r5,[r6]
+ldd r4r5,[r7,16]
+std r2r3,[r6,8]
+ldd r2r3,[r7,24]
+std r4r5,[r6,16]
+std r2r3,[r6,24]
+add r6,sp,0x20
+mov_s r7,0x15158
+ldd r4r5,[r7]
+ldd r2r3,[r7,8]
+std r4r5,[r6]
+ldd r4r5,[r7,16]
+std r2r3,[r6,8]
+ldd r2r3,[r7,24]
+std r4r5,[r6,16]
+std r2r3,[r6,24]
+mov_s r6,sp
+mov_s r7,0x15138
+ldd r4r5,[r7]
+ldd r2r3,[r7,8]
+std r4r5,[r6]
+ldd r4r5,[r7,16]
+std r2r3,[r6,8]
+ldd r2r3,[r7,24]
+std r4r5,[r6,16]
+std r2r3,[r6,24]
+ld r0,[0x15118]
+ld r1,[0x1511c]
+ld r2,[0x15120]
+ld r3,[0x15124]
+ld r4,[0x15128]
+ld r5,[0x1512c]
+ld r6,[0x15130]
+ld r7,[0x15134]
+bl @fin
+
+nop_s
+nop_s
+.align 4
+
+fin:
+st 1, [POWER_DEVICE]
diff --git a/tests/tcg/arc/check_bih.S b/tests/tcg/arc/check_bih.S
new file mode 100644
index 0000000000..c099d72b96
--- /dev/null
+++ b/tests/tcg/arc/check_bih.S
@@ -0,0 +1,29 @@
+ .include "macros.inc"
+
+ start
+ test_name BIH
+ mov_s r0,0
+.Lloop:
+ bih [r0]
+ b_s @.L1
+ b_s @.L2
+ b_s @.L3
+ b_s @.L4
+ b_s @.Lfail
+ b_s @.Lfail
+ b_s @.Lfail
+.L1:
+ add r0,r0,1
+ b @.Lloop
+.L2:
+ add r0,r0,1
+ b @.Lloop
+.L3:
+ add r0,r0,1
+ b @.Lloop
+.L4:
+ print "[PASS] BIH\n"
+ end
+.Lfail:
+ print "[FAIL] BIH\n"
+ end
diff --git a/tests/tcg/arc/check_bnex.S b/tests/tcg/arc/check_bnex.S
new file mode 100644
index 0000000000..4b7c0cfed9
--- /dev/null
+++ b/tests/tcg/arc/check_bnex.S
@@ -0,0 +1,26 @@
+#*****************************************************************************
+# bne.S
+#-----------------------------------------------------------------------------
+#
+# Test bne instruction.
+#
+
+#define ARCTEST_ARC32
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+ #-------------------------------------------------------------
+ # Branch tests
+ #-------------------------------------------------------------
+
+ # Each test checks both forward and backward branches
+
+ TEST_BR2_OP_TAKEN( 2, bne, 0, 1 );
+ TEST_BR2_OP_TAKEN( 3, bne, 1, 0 );
+ TEST_BR2_OP_TAKEN( 4, bne, -1, 1 );
+ TEST_BR2_OP_TAKEN( 5, bne, 1, -1 );
+
+ TEST_BR2_OP_NOTTAKEN( 6, bne, 0, 0 );
+ TEST_BR2_OP_NOTTAKEN( 7, bne, 1, 1 );
+ TEST_BR2_OP_NOTTAKEN( 8, bne, -1, -1 );
+ARCTEST_END
diff --git a/tests/tcg/arc/check_breqx.S b/tests/tcg/arc/check_breqx.S
new file mode 100644
index 0000000000..a3a3dd1160
--- /dev/null
+++ b/tests/tcg/arc/check_breqx.S
@@ -0,0 +1,26 @@
+#*****************************************************************************
+# breq.S
+#-----------------------------------------------------------------------------
+#
+# Test breq instruction.
+#
+
+#define ARCTEST_ARC32
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+ #-------------------------------------------------------------
+ # Branch tests
+ #-------------------------------------------------------------
+
+ # Each test checks both forward and backward branches
+
+ TEST_BR_OP_TAKEN( 2, breq, 0, 0 );
+ TEST_BR_OP_TAKEN( 3, breq, 1, 1 );
+ TEST_BR_OP_TAKEN( 4, breq, -1, -1 );
+
+ TEST_BR_OP_NOTTAKEN( 5, breq, 0, 1 );
+ TEST_BR_OP_NOTTAKEN( 6, breq, 1, 0 );
+ TEST_BR_OP_NOTTAKEN( 7, breq, -1, 1 );
+ TEST_BR_OP_NOTTAKEN( 8, breq, 1, -1 );
+ARCTEST_END
diff --git a/tests/tcg/arc/check_brgex.S b/tests/tcg/arc/check_brgex.S
new file mode 100644
index 0000000000..ddd6003b7c
--- /dev/null
+++ b/tests/tcg/arc/check_brgex.S
@@ -0,0 +1,26 @@
+#*****************************************************************************
+# brge.S
+#-----------------------------------------------------------------------------
+#
+# Test brge instruction.
+#
+
+#defirge ARCTEST_ARC32
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+ #-------------------------------------------------------------
+ # Branch tests
+ #-------------------------------------------------------------
+
+ # Each test checks both forward and backward branches
+
+ TEST_BR_OP_NOTTAKEN( 2, brge, 0, 1 );
+ TEST_BR_OP_TAKEN( 3, brge, 1, 0 );
+ TEST_BR_OP_NOTTAKEN( 4, brge, -1, 1 );
+ TEST_BR_OP_TAKEN( 5, brge, 1, -1 );
+
+ TEST_BR_OP_TAKEN( 6, brge, 0, 0 );
+ TEST_BR_OP_TAKEN( 7, brge, 1, 1 );
+ TEST_BR_OP_TAKEN( 8, brge, -1, -1 );
+ARCTEST_END
diff --git a/tests/tcg/arc/check_brhsx.S b/tests/tcg/arc/check_brhsx.S
new file mode 100644
index 0000000000..6a05b53f8e
--- /dev/null
+++ b/tests/tcg/arc/check_brhsx.S
@@ -0,0 +1,27 @@
+#*****************************************************************************
+# brhs.S
+#-----------------------------------------------------------------------------
+#
+# Test brhs instruction.
+#
+
+#define ARCTEST_ARC32
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+ #-------------------------------------------------------------
+ # Branch tests
+ #-------------------------------------------------------------
+
+ # Each test checks both forward and backward branches
+
+ TEST_BR_OP_TAKEN( 2, brhs, 0, 0 );
+ TEST_BR_OP_TAKEN( 3, brhs, 1, 1 );
+ TEST_BR_OP_TAKEN( 4, brhs, -1, -1 );
+ TEST_BR_OP_TAKEN( 5, brhs, -1, 1 );
+
+ TEST_BR_OP_NOTTAKEN( 6, brhs, 0, 1 );
+ TEST_BR_OP_NOTTAKEN( 7, brhs, 1, -1 );
+ TEST_BR_OP_NOTTAKEN( 8, brhs, 33, 0x2aaaaaab );
+ TEST_BR_OP_NOTTAKEN( 9, brhs, 123, 124 );
+ARCTEST_END
diff --git a/tests/tcg/arc/check_brlox.S b/tests/tcg/arc/check_brlox.S
new file mode 100644
index 0000000000..53a15b27d1
--- /dev/null
+++ b/tests/tcg/arc/check_brlox.S
@@ -0,0 +1,26 @@
+#*****************************************************************************
+# brlo.S
+#-----------------------------------------------------------------------------
+#
+# Test brlo instruction.
+#
+
+#define ARCTEST_ARC32
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+ #-------------------------------------------------------------
+ # Branch tests
+ #-------------------------------------------------------------
+
+ # Each test checks both forward and backward branches
+
+ TEST_BR_OP_NOTTAKEN( 2, brlo, 0, 0 );
+ TEST_BR_OP_NOTTAKEN( 3, brlo, 1, 1 );
+ TEST_BR_OP_NOTTAKEN( 4, brlo, -1, -1 );
+ TEST_BR_OP_NOTTAKEN( 5, brlo, -1, 1 );
+
+ TEST_BR_OP_TAKEN( 6, brlo, 0, 1 );
+ TEST_BR_OP_TAKEN( 7, brlo, 1, -1 );
+ TEST_BR_OP_TAKEN( 8, brlo, 33, 0x2aaaaaab );
+ARCTEST_END
diff --git a/tests/tcg/arc/check_brltx.S b/tests/tcg/arc/check_brltx.S
new file mode 100644
index 0000000000..475d3ddf1c
--- /dev/null
+++ b/tests/tcg/arc/check_brltx.S
@@ -0,0 +1,26 @@
+#*****************************************************************************
+# brlt.S
+#-----------------------------------------------------------------------------
+#
+# Test brlt instruction.
+#
+
+#defirlt ARCTEST_ARC32
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+ #-------------------------------------------------------------
+ # Branch tests
+ #-------------------------------------------------------------
+
+ # Each test checks both forward and backward branches
+
+ TEST_BR_OP_TAKEN( 2, brlt, 0, 1 );
+ TEST_BR_OP_NOTTAKEN( 3, brlt, 1, 0 );
+ TEST_BR_OP_TAKEN( 4, brlt, -1, 1 );
+ TEST_BR_OP_NOTTAKEN( 5, brlt, 1, -1 );
+
+ TEST_BR_OP_NOTTAKEN( 6, brlt, 0, 0 );
+ TEST_BR_OP_NOTTAKEN( 7, brlt, 1, 1 );
+ TEST_BR_OP_NOTTAKEN( 8, brlt, -1, -1 );
+ARCTEST_END
diff --git a/tests/tcg/arc/check_brnex.S b/tests/tcg/arc/check_brnex.S
new file mode 100644
index 0000000000..6f37c33930
--- /dev/null
+++ b/tests/tcg/arc/check_brnex.S
@@ -0,0 +1,26 @@
+#*****************************************************************************
+# brne.S
+#-----------------------------------------------------------------------------
+#
+# Test brne instruction.
+#
+
+#defirne ARCTEST_ARC32
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+ #-------------------------------------------------------------
+ # Branch tests
+ #-------------------------------------------------------------
+
+ # Each test checks both forward and backward branches
+
+ TEST_BR_OP_TAKEN( 2, brne, 0, 1 );
+ TEST_BR_OP_TAKEN( 3, brne, 1, 0 );
+ TEST_BR_OP_TAKEN( 4, brne, -1, 1 );
+ TEST_BR_OP_TAKEN( 5, brne, 1, -1 );
+
+ TEST_BR_OP_NOTTAKEN( 6, brne, 0, 0 );
+ TEST_BR_OP_NOTTAKEN( 7, brne, 1, 1 );
+ TEST_BR_OP_NOTTAKEN( 8, brne, -1, -1 );
+ARCTEST_END
diff --git a/tests/tcg/arc/check_bta.S b/tests/tcg/arc/check_bta.S
new file mode 100644
index 0000000000..abef1a33fc
--- /dev/null
+++ b/tests/tcg/arc/check_bta.S
@@ -0,0 +1,294 @@
+; check_bta.S
+; Tests for setting Branch Target Address register.
+; The BTA register is updated if and only if the
+; branch is going to be taken (cc = true) AND there
+; is a delay slot:
+; ,-----------.-----------.
+; | not taken | taken |
+; ,---------------|-----------+-----------|
+; | no delay slot | - | - |
+; |---------------|-----------+-----------|
+; | delay slot | - | UPDATE |
+; `---------------^-----------^-----------'
+; In other words, BTA is updated only when STATUS32.DE is set.
+;
+; TODO: Add test cases for Bcc, JL, JLcc, BBITn
+; TODO: the following test cases fail in QEMU: 3, 9
+; the condition of the tests are (not taken, delay slot)
+; and yet QEMU insists on updating the BTA.
+
+ .include "macros.inc"
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;; Test checking routines ;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+.data
+; Test case counter
+test_nr:
+ .word 0x0
+; Saved BTA
+saved_bta:
+ .word 0x0
+
+; Increment the test counter
+.macro prep_test_case
+ ld r13, [test_nr]
+ add_s r13, r13, 1 ; Increase test case counter
+ st r13, [test_nr]
+ lr r13, [bta]
+ st r13, [saved_bta] ; Some tests need this to check if BTA changed.
+.endm
+
+; Compares the current BTA with the value saved at the start of a
+; test by PREP_TEST_CASE. If not the same, the test will fail.
+.macro check_bta_remained_intact
+ ld r13, [saved_bta]
+ lr r12, [bta]
+ cmp r13, r12
+ bne @fail
+.endm
+
+; Checks the BTA against the EXPECTED_BTA.
+; If they're not the same, the test will fail.
+.macro check_bta expected_bta
+ mov r13, \expected_bta
+ lr r12, [bta]
+ cmp r13, r12
+ bne @fail
+.endm
+
+; Checks if the given REGs are equal. Fails, if not.
+.macro check_equal reg, expected_reg
+ cmp \expected_reg, \reg
+ bne @fail
+.endm
+
+; Checks if REG is one number bigger than ORIG_REG.
+.macro check_one_above reg, orig_reg
+ mov r13, \orig_reg
+ add_s r13, r13, 1
+ cmp r13, \reg
+ bne @fail
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;; Conditonal branches ;;;;;;;;;;;;;;;;;;;;;;;;;
+
+start
+
+; Test case 1
+; Conditional branch is not taken and there is no delay slot.
+; BTA mustn't be updated.
+ prep_test_case
+ ld r0, [test_nr]
+ add r1, r0, 1
+ breq r0, r1, @test_01_target
+ check_bta_remained_intact
+ b @test_01_end
+test_01_target:
+ b @fail
+test_01_end:
+ ; Fall through
+
+; Test case 2
+; Conditional branch is taken but there is no delay slot.
+; BTA mustn't be updated.
+ prep_test_case
+ ld r0, [test_nr]
+ mov r1, r0
+ breq r0, r1, @test_02_target
+ b @fail
+test_02_target:
+ check_bta_remained_intact
+
+; Test case 3
+; Conditional branch is not taken but there is a delay slot.
+; BTA mustn't be updated.
+ prep_test_case
+ ld r0, [test_nr]
+ add r1, r0, 1
+ breq.d r0, r1, @test_03_target
+ add_s r0, r0, 1
+ check_bta_remained_intact
+ check_equal r0, r1
+ b @test_03_end
+test_03_target:
+ b @fail
+test_03_end:
+ ; Fall through
+
+; Test case 4
+; Conditional branch is taken AND there is a delay slot.
+; BTA must be updated.
+ prep_test_case
+ ld r0, [test_nr]
+ mov r1, r0
+ breq.d r0, r1, @test_04_target
+ add_s r0, r0, 1
+ b @fail
+test_04_target:
+ check_bta @test_04_target
+ check_one_above r0, r1
+
+;;;;;;;;;;;;;;;;;;;;;;;; Unconditonal branches ;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Test case 5
+; Branch unconditionally but there is no delay slot.
+; BTA mustn't be updated.
+ prep_test_case
+ b @test_05_target
+ b @fail
+test_05_target:
+ check_bta_remained_intact
+
+; Test case 6
+; Branch unconditionally AND there is a delay slot.
+; BTA must be updated.
+ prep_test_case
+ ld r0, [test_nr]
+ mov r1, r0
+ b.d @test_06_target
+ add_s r0, r0, 1
+ b @fail
+test_06_target:
+ check_bta @test_06_target
+ check_one_above r0, r1
+
+;;;;;;;;;;;;;;;;;;;;;;;;;; Conditonal jumps ;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Test case 7
+; Conditional jump is not taken and there is no delay slot.
+; BTA mustn't be updated.
+ prep_test_case
+ ld r0, [test_nr]
+ add r1, r0, 1
+ cmp r0, r1
+ jz @test_07_target
+ check_bta_remained_intact
+ b @test_07_end
+test_07_target:
+ b @fail
+test_07_end:
+ ; Fall through
+
+; Test case 8
+; Conditional jump is taken but there is no delay slot.
+; BTA mustn't be updated.
+ prep_test_case
+ ld r0, [test_nr]
+ mov r1, r0
+ cmp r0, r1
+ jz @test_08_target
+ add_s r0, r0, 1
+
+ b @fail
+test_08_target:
+ check_bta_remained_intact
+
+; Test case 9
+; Conditional jump is not taken but there is a delay slot.
+; BTA mustn't be updated.
+ prep_test_case
+ ld r0, [test_nr]
+ add r1, r0, 1
+ mov r2, @test_09_target
+ cmp r0, r1
+ jz.d [r2]
+ add_s r0, r0, 1
+ check_bta_remained_intact
+ check_equal r0, r1
+ b @test_09_end
+test_09_target:
+ b @fail
+test_09_end:
+ ; Fall through
+
+; Test case 10
+; Conditional jump is taken AND there is a delay slot.
+; BTA must be updated.
+ prep_test_case
+ ld r0, [test_nr]
+ mov r1, r0
+ mov r2, @test_10_target
+ cmp r0, r1
+ jz.d [r2]
+ add_s r0, r0, 1
+ b @fail
+test_10_target:
+ check_bta @test_10_target
+ check_one_above r0, r1
+
+;;;;;;;;;;;;;;;;;;;;;;; Conditonal short jumps ;;;;;;;;;;;;;;;;;;;;;;;
+
+; Test case 11
+; Conditional short jump is not taken (there can't be a delay slot).
+; BTA mustn't be updated.
+ prep_test_case
+ ld r0, [test_nr]
+ add r1, r0, 1
+ mov blink, @test_11_target
+ cmp r0, r1
+ jeq_s [blink]
+ check_bta_remained_intact
+ check_one_above r1, r0
+ b @test_11_end
+test_11_target:
+ b @fail
+test_11_end:
+ ; Fall through
+
+; Test case 12
+; Conditional short jump is taken (there can't be a delay slot).
+; BTA mustn't be updated.
+ prep_test_case
+ ld r0, [test_nr]
+ add r1, r0, 1
+ mov blink, @test_12_target
+ cmp r0, r1
+ jne_s [blink]
+ add_s r0, r0, 1
+ b @fail
+test_12_target:
+ check_bta_remained_intact
+ check_one_above r1, r0
+
+;;;;;;;;;;;;;;;;;;;;;;;;; Unconditonal jumps ;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Test case 13
+; Jump unconditionally but there is no delay slot.
+; BTA mustn't be updated.
+ prep_test_case
+ j @test_13_target
+ b @fail
+test_13_target:
+ check_bta_remained_intact
+
+; Test case 14
+; Jump unconditionally AND there is a delay slot.
+; BTA must be updated.
+ prep_test_case
+ ld r0, [test_nr]
+ mov r1, r0
+ mov r2, @test_14_target
+ j.d [r2]
+ add_s r0, r0, 1
+ b @fail
+test_14_target:
+ check_bta @test_14_target
+ check_one_above r0, r1
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Reporting ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+valhalla:
+ print "[PASS]"
+ b @1f
+
+; If a test fails, it jumps here. Although, for the sake of uniformity,
+; the printed output does not say much about which test case failed,
+; one can uncomment the print_number line below or set a breakpoint
+; here to check the R0 register for the test case number.
+fail:
+ ld r0, [test_nr]
+ ;print_number r0
+ print "[FAIL]"
+1:
+ print " BTA register (implicit) writing\n"
+ end
diff --git a/tests/tcg/arc/check_carry.S b/tests/tcg/arc/check_carry.S
new file mode 100644
index 0000000000..5928897911
--- /dev/null
+++ b/tests/tcg/arc/check_carry.S
@@ -0,0 +1,15 @@
+#define ARCTEST_ARC32
+#include "test_macros.h"
+
+ ARCTEST_BEGIN
+
+test_2:
+ mov r0, 10
+ mov r1, 12
+ cmp r0,r1 ;Carry is set here
+ mov.lo.f 0, 0x0
+ mov.hs.f 0, 0x1
+
+ bne @fail
+
+ ARCTEST_END
diff --git a/tests/tcg/arc/check_enter_leave.S b/tests/tcg/arc/check_enter_leave.S
new file mode 100644
index 0000000000..9bb8180b29
--- /dev/null
+++ b/tests/tcg/arc/check_enter_leave.S
@@ -0,0 +1,715 @@
+;; These are the tests cases for verifying the functionality of
+;; enter_s and leave_s. It is assumed that there are 32 general
+;; purpose registers available (r0 ... r31). It is also good to
+;; remark the aliases for some of the registers:
+;; r27: fp
+;; r28: sp
+;; r31: blink
+
+ .include "macros.inc"
+
+;;;;;;;;;;;;;;;;;;; / Exception Verification Helpers \ ;;;;;;;;;;;;;;;;;;;;;;
+; these are the parameters that the exception routine uses as reference
+ .data
+ .align 4
+ecr_ref : .word 0x0
+eret_ref : .word 0x0
+efa_ref : .word 0x0
+erbta_ref : .word 0x0
+cont_addr : .word 0x0
+test_number: .word 0x0
+ .text
+ .align 4
+
+; macro: set_excep_params
+; regs used: r11
+;
+; this macro writes the provided parameters to a temporary place holder
+; that later will be used by ProtV exception above to verify as reference
+.macro set_excep_params ecr, eret, efa, erbta, continue, test_num
+ mov r11, \ecr
+ st r11, [ecr_ref]
+ mov r11, \efa
+ st r11, [efa_ref]
+ mov r11, \eret
+ st r11, [eret_ref]
+ mov r11, \erbta
+ st r11, [erbta_ref]
+ mov r11, \continue
+ st r11, [cont_addr]
+ mov r11, \test_num
+ st r11, [test_number]
+.endm
+
+; exception verification routine
+; regs used: r11, r12
+;
+; this is a parameterized exception that will check the followings:
+; ecr == ecr_ref
+; efa == efa_ref
+; eret == eret_ref
+; if everything passes, it will jump to 'cont_addr' parameter. it will clear
+; the user bit before the jump, ie if an exception is raised in user mode,
+; the continuation after exception will be in kernel mode.
+; the parameters must be set beforehand using 'set_except_params' macro.
+; last but not least, this requires ivt.S file to be compiled and linked.
+ .align 4
+ .global instruction_error
+ .global EV_Misaligned
+ .type instruction_error, @function
+ .type EV_Misaligned, @function
+instruction_error:
+EV_Misaligned:
+ ld r11, [ecr_ref]
+ lr r12, [ecr]
+ brne r12, r11, @exc_fail
+ ld r11, [eret_ref]
+ lr r12, [eret]
+ brne r12, r11, @exc_fail
+ ld r11, [efa_ref]
+ lr r12, [efa]
+ brne r12, r11, @exc_fail
+ ld r11, [erbta_ref]
+ lr r12, [erbta]
+ brne r12, r11, @exc_fail
+ ; do not pursue the branch target anymore
+ lr r11, [erstatus]
+ and r11, r11, ~0x8040 ; clear ES and DE bit
+ sr r11, [erstatus]
+ ; going back to given address
+ ld r11, [cont_addr]
+ sr r11, [eret]
+ rtie
+exc_fail:
+ ld r11, [test_number]
+ print_number r11
+ print "[FAIL] :exception is not sane:"
+ b @endtest
+;;;;;;;;;;;;;;;;;;; \ Exception Verification Helpers / ;;;;;;;;;;;;;;;;;;;;;;
+
+ start
+ mov sp , 0x1000 ; let's set sp to 0x100 for all the tests
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; u6=0 leads to doing nothing
+test00:
+ mov r10, sp
+ enter_s 0 ; enter_s []
+ brne sp, r10, @test00_fail
+ j @test01
+
+test00_fail:
+ print "[FAIL] :test00:"
+ b @endtest
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; saving first 3 general purpose registers
+test01:
+ mov r10, sp ; ,-- top ---.
+ mov r13, 13 ; | r13 = 13 |
+ mov r14, 14 ; | r14 = 14 |
+ mov r15, 15 ; | r15 = 15 |
+ enter_s [r13-r15] ; `- bottom -'
+ pop r3
+ pop r4
+ pop r5
+ brne r3, 13, @test01_fail
+ brne r4, 14, @test01_fail
+ brne r5, 15, @test01_fail
+ brne sp, r10, @test01_fail
+ j @test02
+
+test01_fail:
+ print "[FAIL] :test01:"
+ b @endtest
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; saving blink register
+test02:
+ mov r10, sp
+ mov blink, 0x123
+ enter_s [blink]
+ pop r1
+ brne r1, 0x123, @test02_fail
+ brne sp, r10, @test02_fail
+ j @test03
+
+test02_fail:
+ print "[FAIL] :test02:"
+ b @endtest
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; saving fp register
+test03:
+ mov r10, sp
+ mov fp, 0x321
+
+ enter_s [fp]
+ mov r9, sp ; save current sp before poping
+ pop r1
+ brne r1, 0x321, @test03_fail
+ brne fp, r9, @test03_fail
+ brne sp, r10, @test03_fail
+ j @test04
+
+test03_fail:
+ print "[FAIL] :test03:"
+ b @endtest
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; saving all registers
+ .data
+ .align 4
+sp_orig: .word 0x0
+ .text
+test04:
+ st sp , [sp_orig] ; ,----- top -----.
+ mov blink, 0x456 ; | blink = 0x456 |
+ mov r13 , 13 ; | r13 = 13 |
+ mov r14 , 14 ; | r14 = 14 |
+ mov r15 , 15 ; | r15 = 15 |
+ mov r16 , 16 ; | r16 = 16 |
+ mov r17 , 17 ; | r17 = 17 |
+ mov r18 , 18 ; | r18 = 18 |
+ mov r19 , 19 ; | r19 = 19 |
+ mov r20 , 20 ; | r20 = 20 |
+ mov r21 , 21 ; | r21 = 21 |
+ mov r22 , 22 ; | r22 = 22 |
+ mov r23 , 23 ; | r23 = 23 |
+ mov r24 , 24 ; | r24 = 24 |
+ mov r25 , 25 ; | r25 = 25 |
+ mov r26 , 26 ; | r26 = 26 |
+ mov fp , 0x789 ; | fp = 0x789 |
+ enter_s [r13-r26, fp, blink] ; `--- bottom ----'
+ mov r0, sp ; save current sp before poping
+ pop r1 ; blink
+ pop r3 ; r13
+ pop r4 ; r14
+ pop r5 ; r15
+ pop r6 ; r16
+ pop r7 ; r17
+ pop r8 ; r18
+ pop r9 ; r19
+ pop r10 ; r20
+ pop r11 ; r21
+ pop r12 ; r22
+ pop r13 ; r23
+ pop r14 ; r24
+ pop r15 ; r25
+ pop r16 ; r26
+ pop r2 ; fp
+ brne fp, r0, @test04_fail ; sp value before all the pops
+ brne r1, 0x456, @test04_fail ; blink value during save
+ brne r2, 0x789, @test04_fail ; frame pointer value during save
+ brne r3, 13, @test04_fail ; stored r13 value
+ brne r4, 14, @test04_fail ; stored r14 value
+ brne r5, 15, @test04_fail ; stored r15 value
+ brne r6, 16, @test04_fail ; stored r16 value
+ brne r7, 17, @test04_fail ; stored r17 value
+ brne r8, 18, @test04_fail ; stored r18 value
+ brne r9, 19, @test04_fail ; stored r19 value
+ brne r10, 20, @test04_fail ; stored r20 value
+ brne r11, 21, @test04_fail ; stored r21 value
+ brne r12, 22, @test04_fail ; stored r22 value
+ brne r13, 23, @test04_fail ; stored r23 value
+ brne r14, 24, @test04_fail ; stored r24 value
+ brne r15, 25, @test04_fail ; stored r25 value
+ brne r16, 26, @test04_fail ; stored r26 value
+ ld r10, [sp_orig] ; original sp value spilled
+ brne sp, r10, @test04_fail ; original sp value
+ j @test05
+
+test04_fail:
+ print "[FAIL] :test04:"
+ b @endtest
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; sp's value is not 32-bit aligned --> misaligned exception
+; this happens irrelevant of status32.AD bit
+test05:
+ .equ TEST05_SP , 0x111 ; an address which is not 32-bit aligned
+ .equ TEST05_STACK_SIZE, 60 ; saving r13-r26 (14x4) + fp (4)
+ .equ TEST05_EFA , TEST05_SP - TEST05_STACK_SIZE
+ lr r1, [status32]
+ or r1, r1, 0x80000 ; set AD bit
+ mov r2, @test05_excep_prep
+ sr r1, [erstatus] ; enable AD bit
+ sr r2, [eret] ; continue with the test
+ rtie
+
+test05_excep_prep:
+ lr r7, [erbta] ; don't care for erbta
+ set_excep_params ecr=MISALIGNED_DATA_ACCESS, \
+ eret=@test05_enter , \
+ efa=TEST05_EFA , \
+ erbta=r7 , \
+ continue=@test05_wrapup , \
+ test_num=5
+ mov r10, sp ; backup sp to restore later
+ mov sp, TEST05_SP ; an address which is not 32-bit aligned
+test05_enter:
+ enter_s [r13-r26, fp] ; just being flamboyant
+ print "[FAIL] :test05:" ; this code must not fall through
+ b @endtest
+
+test05_wrapup:
+ mov sp, r10
+ lr r1, [status32]
+ and r1, r1, ~0x80000 ; clear AD bit
+ mov r2, @test06 ; go to next test
+ sr r1, [erstatus] ; disable AD bit
+ sr r2, [eret] ; continue with next test
+ rtie
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; a delay slot instruction --> illegal instruction sequence exception
+; the tricky thing in this test is that gas does not allow us to put
+; an "enter_s" in a delay slot (good job there!). however, we work
+; around it by writing the opcode at runtime.
+test06:
+ set_excep_params ecr=ILLEGAL_INSTRUCTION_SEQUENCE, \
+ eret=@test06_delay , \
+ efa=@test06_delay , \
+ erbta=@test06_fail , \
+ continue=@test07 , \
+ test_num=6
+ mov r1, 0xc0e2 ; opcode for enter_s [r13]
+ sth r1, [test06_delay]
+ b @test06_dummy_tb ; by having 'b' here, it is end of this tb.
+test06_dummy_tb: ; so this one will be decoded after mutation.
+ b.d @test06_fail
+test06_delay:
+ nop_s
+ nop_s
+
+test06_fail:
+ print "[FAIL] :test06:"
+ b @endtest
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; an execution slot instruction --> illegal instruction sequence exception
+; TODO (issue #73): enable this after EI_S has been implemented.
+test07:
+; mov r1, @test07_ei_table
+; sr r1, [ei_base]
+; j @test07_begin
+;
+; .align 4
+;test07_ei_table:
+; enter_s [r13]
+;
+;test07_begin:
+; set_excep_params ecr=ILLEGAL_INSTRUCTION_SEQUENCE, \
+; eret=@test07_ei_table , \
+; efa=@test07_ei_table , \
+; erbta=@test07_fail , \
+; continue=@test08 , \
+; test_num=7
+; ei_s 0
+;
+;test07_fail:
+; print "failed: test07\n"
+; end
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; it is allowed to have "enter_s 0" in delay/execution slot because it is
+; like a nop then and is not a multi-cycle instruction.
+; TODO (issue #73): enable the ei_check part after EI_S has been done.
+test08:
+ mov r1, 0xc0e0 ; opcode for enter_s []
+ sth r1, [test08_delay]
+ b @test08_dummy_tb ; by having 'b' here, it is end of this tb.
+test08_dummy_tb: ; so this one will be decoded after mutation.
+ b.d @test08_ei_check
+test08_delay:
+ nop_s ; at runtime this is enter_s [] and is ok
+ nop_s
+
+ .align 4
+test08_ei_table:
+ enter_s 0
+
+test08_ei_check:
+ ; TODO (issue #73): enable after EI_S is implemented.
+ ;mov r1, @test08_ei_table
+ ;sr r1, [ei_base]
+ ;ei_s 0
+ ; fall through to the next test
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; 32 general registers configured AND u[3:0] > 14 (r13-r26)
+; OR
+; 16 general registers configured AND u[3:0] > 3 (r13-r15)
+; --> illegal instruction exception
+; TODO (issue #52): this test case must be executed with
+; -global cpu.num-regs=16.
+test09:
+; lr r7, [bta] ; don't care for erbta (use current bta)
+; set_excep_params ecr=ILLEGAL_INSTRUCTION, \
+; eret=@test09_big_u3 , \
+; efa=@test09_big_u3 , \
+; erbta=r7 , \
+; continue=@test10 , \
+; test_num=9
+;test09_big_u3: ; enter_s encoding : 1100 00UU 111u uuu0
+; enter_s 4
+;
+;test09_fail:
+; print "failed: test09\n"
+; end
+;;;;;;;;;;;;;;;;;;;;;;;;;;;; \ Enter Tests / ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;; / Leave Tests \ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; u7=0 leads to doing nothing
+test10:
+ mov r10, sp
+ leave_s 0
+ brne sp, r10, @test10_fail
+ j @test11
+
+test10_fail:
+ print "[FAIL] :test10:"
+ b @endtest
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; restoring first 3 general purpose registers
+test11:
+ mov r10, sp ; ,--- top ---.
+ mov r3, 113 ; | r13 = 113 |
+ mov r4, 114 ; | r14 = 114 |
+ mov r5, 115 ; | r15 = 115 |
+ push r5 ; `-- bottom -'
+ push r4
+ push r3
+ leave_s [r13-r15]
+ brne r13, 113, @test11_fail
+ brne r14, 114, @test11_fail
+ brne r15, 115, @test11_fail
+ brne sp , r10, @test11_fail
+ j @test12
+
+test11_fail:
+ print "[FAIL] :test11:"
+ b @endtest
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; restoring blink register
+test12:
+ mov r10, sp
+ mov r1, 0x10123
+ push r1
+ leave_s [blink]
+ brne blink, 0x10123, @test12_fail
+ brne sp , r10, @test12_fail
+ j @test13
+
+test12_fail:
+ print "[FAIL] :test12:"
+ b @endtest
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; restoring fp register
+test13:
+ mov r10, sp
+ mov r1, 0x11321
+ push r1
+ mov fp, sp ; fp is pointing current frame now
+ mov sp, 0x4009 ; botch sp
+ leave_s [fp] ; 'leave_s' must look into fp for restoring
+ brne fp, 0x11321, @test13_fail
+ brne sp, r10, @test13_fail
+ j @test14
+
+test13_fail:
+ print "[FAIL] :test13"
+ b @endtest
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; jumping to what blink holds
+test14:
+ mov r10, sp
+ mov blink, @test14_cont
+ leave_s [pcl] ; jump to whatever blink points to
+ j @test14_fail ; this should not be reached
+test14_cont:
+ brne sp, r10, @test14_fail
+ j @test15
+
+test14_fail:
+ print "[FAIL] :test14:"
+ b @endtest
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; restoring first 3 general purpose registers
+test15:
+ mov r0 , sp ; ,--------- top ----------.
+ mov r1 , @test15_return ; | blink = @test15_return |
+ mov r3 , 213 ; | r3 = 213 |
+ mov r4 , 214 ; | r4 = 214 |
+ mov r5 , 215 ; | r5 = 215 |
+ mov r6 , 216 ; | r6 = 216 |
+ mov r7 , 217 ; | r7 = 217 |
+ mov r8 , 218 ; | r8 = 218 |
+ mov r9 , 219 ; | r9 = 219 |
+ mov r10, 220 ; | r10 = 220 |
+ mov r11, 221 ; | r11 = 221 |
+ mov r12, 222 ; | r12 = 222 |
+ mov r13, 223 ; | r13 = 223 |
+ mov r14, 224 ; | r14 = 224 |
+ mov r15, 225 ; | r15 = 225 |
+ mov r16, 226 ; | r16 = 226 |
+ mov r2, 0x14456 ; | fp = 0x14456 |
+ push r2 ; `-------- bottom --------'
+ push r16
+ push r15
+ push r14
+ push r13
+ push r12
+ push r11
+ push r10
+ push r9
+ push r8
+ push r7
+ push r6
+ push r5
+ push r4
+ push r3
+ push r1
+ mov fp, sp
+ mov sp, 0x1337 ; both sp again
+ leave_s [r13-r26, fp, blink, pcl] ; restore and do everything
+ j @test15_fail
+test15_return:
+ brne sp , r0, @test15_fail
+ brne blink, @test15_return, @test15_fail
+ brne r13 , 213, @test15_fail
+ brne r14 , 214, @test15_fail
+ brne r15 , 215, @test15_fail
+ brne r16 , 216, @test15_fail
+ brne r17 , 217, @test15_fail
+ brne r18 , 218, @test15_fail
+ brne r19 , 219, @test15_fail
+ brne r20 , 220, @test15_fail
+ brne r21 , 221, @test15_fail
+ brne r22 , 222, @test15_fail
+ brne r23 , 223, @test15_fail
+ brne r24 , 224, @test15_fail
+ brne r25 , 225, @test15_fail
+ brne r26 , 226, @test15_fail
+ brne fp , 0x14456, @test15_fail
+ j @test16
+
+test15_fail:
+ print "[FAIL] :test15:"
+ b @endtest
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; sp's value is not 32-bit aligned --> misaligned exception
+; this happens irrelevant of status32.AD bit
+test16:
+ .equ TEST16_FP, 0x777 ; an address which is not 32-bit aligned
+ lr r1, [status32]
+ or r1, r1, 0x80000 ; set AD bit
+ mov r2, @test16_excep_prep
+ sr r1, [erstatus] ; enable AD bit
+ sr r2, [eret] ; continue with the test
+ rtie
+
+test16_excep_prep:
+ lr r7, [erbta] ; don't care for erbta
+ set_excep_params ecr=MISALIGNED_DATA_ACCESS, \
+ eret=@test16_enter , \
+ efa=TEST16_FP , \
+ erbta=r7 , \
+ continue=@test16_wrapup , \
+ test_num=16
+ mov r10, sp ; backup sp to restore later
+ mov fp, TEST16_FP ; an address which is not 32-bit aligned
+test16_enter:
+ leave_s [r13-r26, fp] ; first fp's value is put into sp
+ print "[FAIL] :test16:" ; this code must not fall through
+ b @endtest
+
+test16_wrapup:
+ mov sp, r10
+ lr r1, [status32]
+ and r1, r1, ~0x80000 ; clear AD bit
+ mov r2, @test17 ; go to next test
+ sr r1, [erstatus] ; disable AD bit
+ sr r2, [eret] ; continue with next test
+ rtie
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; a delay slot instruction --> illegal instruction sequence exception
+; the tricky thing in this test is that gas does not allow us to put
+; an "leave_s" in a delay slot (good job there!). however, we work
+; around it by writing the opcode at runtime.
+test17:
+ set_excep_params ecr=ILLEGAL_INSTRUCTION_SEQUENCE, \
+ eret=@test17_delay , \
+ efa=@test17_delay , \
+ erbta=@test17_fail , \
+ continue=@test18 , \
+ test_num=17
+ mov r1, 0xc0c2 ; opcode for leave_s [13]
+ sth r1, [test17_delay]
+ b @test17_dummy_tb ; by having 'b' here, it is end of this tb.
+test17_dummy_tb: ; so this one will be decoded after mutation.
+ b.d @test17_fail
+test17_delay:
+ nop_s
+ nop_s
+
+test17_fail:
+ print "[FAIL] :test17:"
+ b @endtest
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; an execution slot instruction --> illegal instruction sequence exception
+; TODO (issue #73): enable this after EI_S has been implemented.
+test18:
+; mov r1, @test18_ei_table
+; sr r1, [ei_base]
+; j @test18_begin
+;
+; .align 4
+;test18_ei_table:
+; leave_s [r13]
+;
+;test18_begin:
+; set_excep_params ecr=ILLEGAL_INSTRUCTION_SEQUENCE, \
+; eret=@test18_ei_table , \
+; efa=@test18_ei_table , \
+; erbta=@test18_fail , \
+; continue=@test19 , \
+; test_num=18
+; ei_s 0
+;
+;test18_fail:
+; print "[FAIL] : test18\n"
+; end
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; it is allowed to have "leave_s 0" in delay/execution slot because it is
+; like a nop then and is not a multi-cycle instruction.
+; TODO (issue #73): enable the ei_check part after EI_S has been done.
+test19:
+ mov r1, 0xc0c0 ; opcode for leave_s []
+ sth r1, [test19_delay]
+ b @test19_dummy_tb ; by having 'b' here, it is end of this tb.
+test19_dummy_tb: ; so this one will be decoded after mutation.
+ b.d @test19_ei_check
+test19_delay:
+ nop_s ; at runtime this is leave_s [] and is ok
+ nop_s
+
+ .align 4
+test19_ei_table:
+ leave_s 0
+
+test19_ei_check:
+ ; TODO (issue #73): enable after EI_S is implemented.
+ ;mov r1, @test19_ei_table
+ ;sr r1, [ei_base]
+ ;ei_s 0
+ ; fall through to the next test
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; 32 general registers configured AND u[3:0] > 14 (r13-r26)
+; OR
+; 16 general registers configured AND u[3:0] > 3 (r13-r15)
+; --> illegal instruction exception
+; TODO (issue #52): this test case must be executed with
+; -global cpu.num-regs=16.
+test20:
+; lr r7, [bta] ; don't care for erbta (use current bta)
+; set_excep_params ecr=ILLEGAL_INSTRUCTION, \
+; eret=@test20_big_u3 , \
+; efa=@test20_big_u3 , \
+; erbta=r7 , \
+; continue=@test21 , \
+; test_num=20
+;test20_big_u3: ; leave_s encoding : 1100 0UUU 110u uuu0
+; leave_s 4
+;
+;test20_fail:
+; print "[FAIL] : test20\n"
+; b @endtest
+;;;;;;;;;;;;;;;;;;;;;;;;;;;; \ Leave Tests / ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;;;;;;;;;;;;;;;;;;;;;;; / Enter/Leave Test \ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; testing enter_s/leave_s together full fledged.
+test21:
+ mov r0 , sp ; original sp
+ mov r13, 0x80000013
+ mov r14, 0x80000014
+ mov r15, 0x80000015
+ mov r16, 0x80000016
+ mov r17, 0x80000017
+ mov r18, 0x80000018
+ mov r19, 0x80000019
+ mov r20, 0x8000001a
+ mov r21, 0x8000001b
+ mov r22, 0x8000001c
+ mov r23, 0x8000001d
+ mov r24, 0x8000001e
+ mov r25, 0x8000001f
+ mov r26, 0x80000020
+ mov r27, 0x88888888 ; fp
+ mov r31, @test21_verify ; blink
+
+ enter_s [r13-r26, fp, blink]
+ ; botching all except for fp. it's already changed to current sp.
+ breq r28, 0x88888888, @test21_fail ; sanity check that fp changed
+ mov r1 , 0xdeadbeef
+ mov r13, r1
+ mov r14, r1
+ mov r15, r1
+ mov r16, r1
+ mov r17, r1
+ mov r18, r1
+ mov r19, r1
+ mov r20, r1
+ mov r21, r1
+ mov r22, r1
+ mov r23, r1
+ mov r24, r1
+ mov r25, r1
+ mov r26, r1
+ mov r28, r1 ; botch sp
+ mov r31, r1 ; botch blink
+ leave_s [r13-r26, fp, blink, pcl]
+ j @test21_fail
+
+test21_verify:
+ brne r13, 0x80000013, @test21_fail
+ brne r14, 0x80000014, @test21_fail
+ brne r15, 0x80000015, @test21_fail
+ brne r16, 0x80000016, @test21_fail
+ brne r17, 0x80000017, @test21_fail
+ brne r18, 0x80000018, @test21_fail
+ brne r19, 0x80000019, @test21_fail
+ brne r20, 0x8000001a, @test21_fail
+ brne r21, 0x8000001b, @test21_fail
+ brne r22, 0x8000001c, @test21_fail
+ brne r23, 0x8000001d, @test21_fail
+ brne r24, 0x8000001e, @test21_fail
+ brne r25, 0x8000001f, @test21_fail
+ brne r26, 0x80000020, @test21_fail
+ brne r27, 0x88888888, @test21_fail
+ brne r28, r0, @test21_fail
+ breq r31, @test21_verify, @valhalla
+
+test21_fail:
+ print "[FAIL] :test20:"
+ b @endtest
+;;;;;;;;;;;;;;;;;;;;;;;;; \ Enter/Leave Test / ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+valhalla:
+ print "[PASS]"
+endtest:
+ print " enter/leave\n"
+ end
+
+
+; vim: set syntax=asm ts=2 sw=2 et:
diff --git a/tests/tcg/arc/check_excp.S b/tests/tcg/arc/check_excp.S
new file mode 100644
index 0000000000..18b436dec7
--- /dev/null
+++ b/tests/tcg/arc/check_excp.S
@@ -0,0 +1,17 @@
+ .include "macros.inc"
+
+ start
+
+ test_name TRAP_1
+ trap_s 0
+ print "[PASS] TRAP_1:1\n"
+ trap_s 1
+ print "[PASS] TRAP_1:2\n"
+ end
+
+ .align 4
+ .global EV_Trap
+ .type EV_Trap, @function
+EV_SWI:
+EV_Trap:
+ rtie
diff --git a/tests/tcg/arc/check_excp_1.c b/tests/tcg/arc/check_excp_1.c
new file mode 100644
index 0000000000..f06720c119
--- /dev/null
+++ b/tests/tcg/arc/check_excp_1.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+void main (void)
+{
+ __builtin_arc_trap_s (0);
+ printf ("[PASS] TRAPC:1\n");
+ __builtin_arc_trap_s (1);
+ printf ("[PASS] TRAPC:2\n");
+}
+
+void __attribute__ ((interrupt("ilink")))
+EV_Trap (void)
+{
+ printf ("[PASS] TRAPC:IRQ\n");
+}
diff --git a/tests/tcg/arc/check_excp_jumpdl_mmu.S b/tests/tcg/arc/check_excp_jumpdl_mmu.S
new file mode 100644
index 0000000000..a98229eba2
--- /dev/null
+++ b/tests/tcg/arc/check_excp_jumpdl_mmu.S
@@ -0,0 +1,44 @@
+.include "macros.inc"
+
+.equ PHYSICAL_ADDRESS_START, 0x80000000
+.equ MMU_ENABLE_FLAG , 0x80000000
+
+start
+
+; use physical address range for handling exceptions (ivt)
+mov r0, PHYSICAL_ADDRESS_START
+sr r0, [int_vector_base]
+
+# enable mmu
+mov r3, MMU_ENABLE_FLAG
+sr r3, [pid]
+xor_s r3, r3, r3
+
+; write to some virtual address range in a delay slot
+mov r2, 0x1000
+mov r1, @check
+j_s.d [r1] # let's enjoy the code after delay slot is executed.
+st r0, [r2] # oh, oh: exception!
+
+# this line should not be executed
+add_s r3, r3, 1
+
+check:
+brgt r3, 0, @fail
+print "[ OK]"
+b @rest
+fail:
+print "[NOK]"
+
+rest:
+print " Exception in a delay slot.\n"
+
+end
+
+ .align 4
+ .global EV_TLBMissD
+ .type EV_TLBMissD, @function
+EV_TLBMissD:
+ # disable mmu
+ sr r3, [pid]
+ rtie
diff --git a/tests/tcg/arc/check_excp_mmu.S b/tests/tcg/arc/check_excp_mmu.S
new file mode 100644
index 0000000000..8d1cf83445
--- /dev/null
+++ b/tests/tcg/arc/check_excp_mmu.S
@@ -0,0 +1,69 @@
+.include "macros.inc"
+.include "mmu.inc"
+
+; courtesy of macros.inc and mmu.inc
+.extern REG_IVT_BASE
+.extern PAGE_NUMBER_MSK
+.extern REG_PD0_GLOBAL
+.extern REG_PD0_VALID
+.extern REG_PD1_KRNL_W
+
+; test data
+; making an entry for the TLB
+;
+; ,------------------------------------.
+; | VPN(VA), G=1, V=1 | PPN(PHY), Wk=1 |
+; `------------------------------------'
+; where:
+; VPN(VA) is the virtual page number of logical address
+; G is the global bit
+; V is the validity bit
+; PPN(PHY) is the physical page number
+; Wk is the write permission in kernel mode
+
+; obviously, the offsets in both addresses must be the same
+.equ VIRT_ADR , 0x13371334 ; the virtual address; word aligned
+.equ PHYS_ADR , 0x73311334 ; the physical address > 0x7FFFFFFF
+.equ MAGICDATA, 0x00BADB07 ; the test value to write and verify
+.equ PD0_VPN , (VIRT_ADR & PAGE_NUMBER_MSK)
+.equ PD1_PPN , (PHYS_ADR & PAGE_NUMBER_MSK)
+.equ PD0_BITS , (PD0_VPN | REG_PD0_GLOBAL | REG_PD0_VALID)
+.equ PD1_BITS , (PD1_PPN | REG_PD1_KRNL_W)
+.equ INT_VECT_ADDRESS, 0x80000000 ; physical address for IVT
+
+start
+
+; use physicall address range for handling exceptions (ivt)
+mov r0, INT_VECT_ADDRESS
+sr r0, [REG_IVT_BASE]
+
+mmu_enable
+
+; write to the mapped virtual address
+mov r0, MAGICDATA
+st r0, [VIRT_ADR]
+
+mmu_disable
+
+; with mmu disabled, read from physical address and
+; verify that it is the same as the value written
+; to the mapped virtual address earlier
+ld r1, [PHYS_ADR]
+cmp r0, r1 ; r0 contains the MAGICDATA
+beq @goodboy
+
+print "nope, still no MMU!\n"
+j @adios
+
+goodboy:
+print "Yay, you got the MMU right :)\n"
+
+adios:
+end
+
+ .align 4
+ .global EV_TLBMissD
+ .type EV_TLBMissD, @function
+EV_TLBMissD:
+ mmu_tlb_insert PD0_BITS, PD1_BITS
+ rtie
diff --git a/tests/tcg/arc/check_flags.S b/tests/tcg/arc/check_flags.S
new file mode 100644
index 0000000000..92faf18c15
--- /dev/null
+++ b/tests/tcg/arc/check_flags.S
@@ -0,0 +1,23 @@
+#define ARCTEST_ARC32
+
+#*****************************************************************************
+# flags.S
+#-----------------------------------------------------------------------------
+#
+# Test or instruction.
+#
+
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+
+ TEST_2OP_CARRY (2, sub, 0, 0x00000000, 0x0000000) ;
+ TEST_2OP_CARRY (3, sub, 1, 0x00000000, 0x0000001) ;
+ TEST_2OP_ZERO (4, sub, 0, 0x00000001, 0x0000000) ;
+ TEST_2OP_ZERO (5, sub, 1, 0x00000001, 0x0000001) ;
+ TEST_2OP_NEGATIVE (6, sub, 0, 0x00000000, 0x00000000) ;
+ TEST_2OP_NEGATIVE (7, sub, 1, 0x00000000, 0x00000001) ;
+ TEST_2OP_OVERFLOW (8, sub, 0, 0x00000000, 0x00000000) ;
+ TEST_2OP_OVERFLOW (9, sub, 1, 0x00000000, 0x80000000) ;
+
+ARCTEST_END
diff --git a/tests/tcg/arc/check_ldaw_mmu.S b/tests/tcg/arc/check_ldaw_mmu.S
new file mode 100644
index 0000000000..a503c607b9
--- /dev/null
+++ b/tests/tcg/arc/check_ldaw_mmu.S
@@ -0,0 +1,71 @@
+.include "macros.inc"
+.include "mmu.inc"
+
+; courtesy of mmu.inc
+.extern PAGE_NUMBER_MSK
+.extern REG_PD0_GLOBAL
+.extern REG_PD0_VALID
+.extern REG_PD1_KRNL_W
+
+; test data
+; making an entry for the TLB
+;
+; ,------------------------------------.
+; | VPN(VA), G=1, V=1 | PPN(PHY), Wk=1 |
+; `------------------------------------'
+; where:
+; VPN(VA) is the virtual page number of logical address
+; G is the global bit
+; V is the validity bit
+; PPN(PHY) is the physical page number
+; Wk is the write permission in kernel mode
+
+; obviously, the offsets in both addresses must be the same
+.equ VIRT_ADR , 0x13371334 ; the virtual address; word aligned
+.equ PHYS_ADR , 0x73311334 ; the physical address > 0x7FFFFFFF
+.equ MAGICDATA, 0x00BADB07 ; the test value to write and verify
+.equ PD0_VPN , (VIRT_ADR & PAGE_NUMBER_MSK)
+.equ PD1_PPN , (PHYS_ADR & PAGE_NUMBER_MSK)
+.equ PD0_BITS , (PD0_VPN | REG_PD0_GLOBAL | REG_PD0_VALID)
+.equ PD1_BITS , (PD1_PPN | REG_PD1_KRNL_R)
+.equ INT_VECT_ADDRESS, 0x80000000 ; physical address for IVT
+
+start
+
+; use physicall address range for handling exceptions (ivt)
+mov r0, INT_VECT_ADDRESS
+sr r0, [REG_IVT_BASE]
+
+; initialize the data in physical address
+mov r0, MAGICDATA
+st r0, [PHYS_ADR]
+
+mmu_enable
+
+; read from the mapped virtual address
+mov r2, 0
+ld.aw r1, [r2, VIRT_ADR]
+
+mmu_disable
+
+; with mmu disabled, read from physical address and
+; verify that it is the same as the value written
+; to the mapped virtual address earlier
+cmp r0, r1 ; r0 contains the MAGICDATA
+beq @goodboy
+
+print "nope, still no MMU!\n"
+j @adios
+
+goodboy:
+print "Yay, you got the MMU right :)\n"
+
+adios:
+end
+
+.align 4
+.global EV_TLBMissD
+.type EV_TLBMissD, @function
+EV_TLBMissD:
+mmu_tlb_insert PD0_BITS, PD1_BITS
+rtie
diff --git a/tests/tcg/arc/check_ldstx.S b/tests/tcg/arc/check_ldstx.S
new file mode 100644
index 0000000000..ac181d9a51
--- /dev/null
+++ b/tests/tcg/arc/check_ldstx.S
@@ -0,0 +1,37 @@
+#*****************************************************************************
+# ldst.S
+#-----------------------------------------------------------------------------
+#
+# This test verifies that ld, ldb, ldw work as expected.
+#
+
+#define ARCTEST_ARC32
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+
+ TEST_CASE(2, r0, 0x40000000, "ld:2", ld r1,[@tdat]` ld r0,[r1,@tdat])
+ TEST_CASE(3, r0, 0xbeef, "ld:3", mov r1, 16` ldw r0,[r1, @tdat])
+ TEST_CASE(4, r0, 0xbe, "ld:4", mov r1, 20` ldb r0,[r1, @tdat])
+ TEST_CASE(5, r0, 0xffffbeef, "ld:5", mov r1, 16` ldw.x r0,[r1, @tdat])
+ TEST_CASE(6, r0, 0xffffffbe, "ld:6", mov r1, 20` ldb.x r0,[r1, @tdat])
+
+ TEST_CASE(7, r0, 0xbeef, "ld:7", mov r1, @tdat` ldw.as r0,[r1,8])
+ TEST_CASE(8, r0, 0xcafebabe, "ld:8", mov r1, @tdat` ld.as r0,[r1, 5])
+ TEST_CASE(9, r0, 0xcafebabe, "ld:9", mov r2, 5` mov r1, @tdat` ld_s.as r0,[r1, r2])
+ TEST_CASE(10, r0, 0x40400000, "ld:10", ldd.as r0,[@tdat,2])
+ TEST_CASE(11, r1, 0xc0800000, "ld:11", ldd.as r0,[@tdat,2])
+
+
+ARCTEST_END
+# TEST_DATA
+
+tdat:
+.word 0x00000004
+.word 0x40000000
+.word 0x40400000
+.word 0xc0800000
+.word 0xdeadbeef
+.word 0xcafebabe
+.word 0xabad1dea
+.word 0x1337d00d
diff --git a/tests/tcg/arc/check_lp.S b/tests/tcg/arc/check_lp.S
new file mode 100644
index 0000000000..4074cfa1e5
--- /dev/null
+++ b/tests/tcg/arc/check_lp.S
@@ -0,0 +1,12 @@
+.include "macros.inc"
+
+ start
+ mov_s r2,0x28cc
+ sub r3,0x28d8,r2
+ mov lp_count,0x00fffff0
+ lpne bla
+ st.ab r3,[r2,4]
+ mov 0,0
+bla:
+ print "[PASS] LP: simple\n"
+ end
diff --git a/tests/tcg/arc/check_lp02.S b/tests/tcg/arc/check_lp02.S
new file mode 100644
index 0000000000..866fa01f36
--- /dev/null
+++ b/tests/tcg/arc/check_lp02.S
@@ -0,0 +1,72 @@
+.include "macros.inc"
+
+ start
+ mov r3,0
+ mov r2, 0x2e10
+ mov.f lp_count,0x10
+ lpne 2f
+ st.ab r3,[r2,4]
+2:
+ mov r2,0x1000
+ mov_s r3,0xa
+ and.f lp_count,r3, 0x1f
+ lpnz 2f
+ add r2,r2,r2
+2: # end single insn loop
+ mov r2,0x1000
+ mov_s r3,0xa
+ and.f lp_count,r3, 0x1f
+ lpnz 2f
+ add r2,r2,r2
+2: # end single insn loop
+ mov r2,0x1000
+ mov_s r3,0xa
+ and.f lp_count,r3, 0x1f
+ lpnz 2f
+ add r2,r2,r2
+2: # end single insn loop
+ mov r2,0x1000
+ mov_s r3,0xa
+ and.f lp_count,r3, 0x1f
+ lpnz 2f
+ add r2,r2,r2
+2: # end single insn loop
+ mov r2,0x1000
+ mov_s r3,0xa
+ and.f lp_count,r3, 0x1f
+ lpnz 2f
+ add r2,r2,r2
+2: # end single insn loop
+ mov r2,0x1000
+ mov_s r3,0xa
+ and.f lp_count,r3, 0x1f
+ lpnz 2f
+ add r2,r2,r2
+2: # end single insn loop
+ mov r2,0x1000
+ mov_s r3,0xa
+ and.f lp_count,r3, 0x1f
+ lpnz 2f
+ add r2,r2,r2
+2: # end single insn loop
+ mov r2,0x1000
+ mov_s r3,0xa
+ and.f lp_count,r3, 0x1f
+ lpnz 2f
+ add r2,r2,r2
+2: # end single insn loop
+ mov r2,0x1000
+ mov_s r3,0xa
+ and.f lp_count,r3, 0x1f
+ lpnz 2f
+ add r2,r2,r2
+2: # end single insn loop
+ mov r2,0x1000
+ mov_s r3,0xa
+ and.f lp_count,r3, 0x1f
+ lpnz 2f
+ add r2,r2,r2
+2: # end single insn loop
+
+ print "[PASS] LP01\n"
+ end
diff --git a/tests/tcg/arc/check_lp03.S b/tests/tcg/arc/check_lp03.S
new file mode 100644
index 0000000000..76e70958f0
--- /dev/null
+++ b/tests/tcg/arc/check_lp03.S
@@ -0,0 +1,49 @@
+ .include "macros.inc"
+
+ start
+ test_name ZOLvsIRQ
+ ;; Program the Timer such that we get fast interrupts
+ sr 0x01,[control0]
+ sr 0x1ff,[limit0]
+ sr 0,[count0]
+ mov r0,0
+ mov sp,0x1000
+ ;; enable global interrupts
+ seti
+ ;; Make a short ZOL
+ mov lp_count,0x1ffff
+ lp 1f
+ nop
+1:
+ clri
+ stb.ab 0,[sp,1]
+2:
+ rem r2,r0,10
+ add r2,r2,0x30
+ stb.ab r2,[sp,1]
+ div.f r0,r0,10
+ bne 2b
+3:
+ ld.aw r2,[sp,-1]
+ breq r2,0,4f
+ ;; stb r2,[OUTPUT_DEVICE]
+ brne r2,0,3b
+4:
+ print "[PASS] "
+ printl r30
+ end
+
+ ;; Timer ISR
+ .align 4
+ .global IRQ_Timer0
+ .type IRQ_Timer0, @function
+IRQ_Timer0:
+ clri
+ ;; reset the pending interrupt and reneable it.
+ sr 0x01,[control0]
+ sr 0,[count0]
+ add r0,r0,1
+ rtie
+ print "[FAIL] "
+ printl r30
+ end
diff --git a/tests/tcg/arc/check_lp04.S b/tests/tcg/arc/check_lp04.S
new file mode 100644
index 0000000000..8a2ca6e432
--- /dev/null
+++ b/tests/tcg/arc/check_lp04.S
@@ -0,0 +1,48 @@
+.include "macros.inc"
+
+ start
+
+ ; memset params
+ mov r0, data ; address to write
+ mov r1, 0 ; data to write
+ mov r2, 0x13 ; size of memory to clear
+
+ ; align the address
+ and r4, r0, 3
+ rsub.f lp_count, r4, 4
+ lpne @main_clear
+ stb.ab r1, [r0, 1]
+ sub r2, r2, 1
+
+main_clear:
+ ; main setting to zero
+ and.f lp_count, r2, 0x1f
+ lpne @verify
+ stb.ab r1, [r0, 1]
+
+verify:
+ ld r1, [data, 0x12]
+ cmp r1, 0x66665500
+ beq @good
+ print "[FAIL] "
+ j @the_end
+good:
+ print "[PASS] "
+the_end:
+ print "LP04\n"
+ end
+
+.align 4
+make_unaligned:
+ .2byte 0xffff
+data:
+ .4byte 0x11111111
+ .4byte 0x22222222
+ .4byte 0x33333333
+ .4byte 0x44444444
+ .4byte 0x55555555
+ .4byte 0x66666666
+ .4byte 0x77777777
+ .4byte 0x88888888
+ .4byte 0x99999999
+ .4byte 0xAAAAAAAA
diff --git a/tests/tcg/arc/check_lp05.S b/tests/tcg/arc/check_lp05.S
new file mode 100644
index 0000000000..2fc9e40b97
--- /dev/null
+++ b/tests/tcg/arc/check_lp05.S
@@ -0,0 +1,23 @@
+ .include "macros.inc"
+;;; Test what is happening when we have a trap_s at the end of a zol
+ start
+ mov r0,0
+ mov lp_count, 0x1f
+ lp 1f
+ trap_s 0
+1:
+ breq r0,0x1f,1f
+ print "[FAIL]"
+ b 2f
+1:
+ print "[PASS]"
+2:
+ print " LP05\n"
+ end
+
+ .align 4
+ .global EV_Trap
+ .type EV_Trap, @function
+EV_Trap:
+ add r0,r0,1
+ rtie
diff --git a/tests/tcg/arc/check_lp06.S b/tests/tcg/arc/check_lp06.S
new file mode 100644
index 0000000000..60e7a66309
--- /dev/null
+++ b/tests/tcg/arc/check_lp06.S
@@ -0,0 +1,163 @@
+; check_lp06.S
+;
+; Tests for Zero overhead loop: interrupting the loop
+; If the test fails, check the end of this file for how to troubleshoot.
+
+ .include "macros.inc"
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;; Test checking routines ;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Test case counter
+.data
+test_nr:
+ .word 0x0
+
+; Increment the test counter.
+.macro prep_test_case
+ ld r13, [test_nr]
+ add_s r13, r13, 1 ; increase test case counter
+ st r13, [test_nr]
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;; Exception related code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Handler of the day.
+ .align 4
+handler : .word 0x0
+
+; An exception handler routine that merely jumps to whatever address
+; it was told to by the test. See set_except_handler macro. This
+; requires ivt.S file to be compiled and linked.
+ .align 4
+ .global EV_Trap
+ .global EV_SWI
+ .type EV_Trap, @function
+ .type EV_SWI, @function
+EV_SWI:
+EV_Trap:
+ ld r11, [handler]
+ j [r11]
+
+; macro: set_except_handler
+; regs used: r11
+;
+; This macro writes the provided ADDR to a temporary place holder
+; that later the exception handler routine will jump to.
+.macro set_except_handler addr
+ mov r11, \addr
+ st r11, [handler]
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ZOL ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Let the tests begin
+ start
+
+; Test case 1
+; Having a 'trap_s' at the end of a loop body. The exception handler
+; must return to the _next instruction_ after the trap which is the
+; LOOP_END. Consequently, it should end up in the LOOP_START if the
+; LP_COUNT != 1. To cut a long story short:
+; next instruction(trap) = loop_start and all iterations should finish
+; before getting out of the loop.
+ prep_test_case
+ set_except_handler @test_1_except_handler
+ mov r0, 0
+ mov lp_count, 0x1f
+ lp @test_1_loop_end
+ trap_s 0
+test_1_loop_end:
+ cmp r0, 0x1f ; has the loop finished completely?
+ bne @fail
+ b @test_1_end ; success
+test_1_except_handler:
+ add r0, r0, 1
+ rtie
+test_1_end:
+ ; Fall through
+
+; Test case 2
+; Having a 'swi' at the end of a loop body. The exception handler
+; must return to the _last instruction_ of the loop body and the
+; whole loop must finish completely.
+; Going back to 'swi' is tricky because it keeps triggering the
+; exception. So, after the first trigger, we change it to NOPs.
+ prep_test_case
+ set_except_handler @test_2_except_handler
+ mov r0, 0 ; exception trigger mark
+ mov r1, 0 ; loop counting
+ mov lp_count, 0x1f
+ lp @test_2_loop_end
+ add r1, r1, 1
+test_2_last_insn_loop:
+ swi
+test_2_loop_end:
+ cmp r1, 0x1f ; has the loop finished completely?
+ bne @fail
+ cmp r0, 1 ; exception triggered?
+ bne @fail
+ b @test_2_end ; success
+test_2_except_handler:
+ add r0, r0, 1
+ mov r11, @test_2_last_insn_loop
+ mov r12, 0x78e0 ; NOP_S opcode
+ sth.ab r12, [r11,2] ; write two NOP_S instead of one NOP
+ sth r12, [r11] ; to avoid misaligned exception.
+ rtie
+test_2_end:
+ ; Fall through
+
+; Test case 3
+; Check if _any_ fetch of instruction at address LOOP_END trigger
+; going back to the loop start if the LP_COUNT is not 1. To test
+; that:
+; Jump out of the loop prematurely.
+; Then outside the loop jump back inside the lopp.
+; This should trigger going back to the loop, but do not jump out
+; prematurely anymore.
+ prep_test_case
+ mov r0, 0 ; loop counter
+ mov r2, 0 ; indicator if we jumped to LOOP_END before
+ mov lp_count, 17
+ lp @test_3_loop_end
+ cmp r2, 1
+ bne @test_3_outside_loop
+test_3_last_insn_loop:
+ add r0, r0, 1
+test_3_loop_end:
+ add r3, r2, r0 ; r3 = 1 + 17
+test_3_outside_loop:
+ add r2, r2, 1
+ cmp r2, 1
+ beq @test_3_last_insn_loop
+ cmp r0, 17 ; sanity checks begin
+ bne @fail
+ cmp r2, 2 ; once we jumped there, once fall through.
+ bne @fail
+ cmp r3, 18
+ bne @fail
+
+; Next test cases
+; Timer interrupt and a single insn ZOL. We need to check if indeed we get multiple interrupts, while in ZOL.
+; Timer interrupt and CLRI/SETI body ZOL. The same as above, 2 tests with seti/clri and clri/seti instruction order.
+; Last instruction of a ZOL gets a MMU TLBI miss.
+; Last instruction of a ZOL gets a MMU TLBD miss (load/store).
+; Last instruction of a ZOL gets a MMU TLBI fallowed by a MMU TLBD miss.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Reporting ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+valhalla:
+ print "[PASS]"
+ b @1f
+
+; If a test fails, it jumps here. Although, for the sake of uniformity,
+; the printed output does not say much about which test case failed,
+; one can uncomment the print_number line below or set a breakpoint
+; here to check the R0 register for the test case number.
+fail:
+ ld r0, [test_nr]
+ ;print_number r0
+ print "[FAIL]"
+1:
+ print " Zero overhead loop: interrupting the loop\n"
+ end
diff --git a/tests/tcg/arc/check_lsrx.S b/tests/tcg/arc/check_lsrx.S
new file mode 100644
index 0000000000..9f72e84eb5
--- /dev/null
+++ b/tests/tcg/arc/check_lsrx.S
@@ -0,0 +1,33 @@
+#define ARCTEST_ARC32
+
+#*****************************************************************************
+# lsr.S
+#-----------------------------------------------------------------------------
+#
+# Test or instruction.
+#
+
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+
+ #-------------------------------------------------------------
+ # Logical tests
+ #-------------------------------------------------------------
+ TEST_RR_3OP ( 2, lsr, 0x00000000, 0x00000000, 0);
+ TEST_RR_3OP ( 3, lsr, 0x12345678, 0x12345678, 0);
+ TEST_RR_3OP ( 4, lsr, 0x01234567, 0x12345678, 4);
+ TEST_RR_3OP ( 5, lsr, 0x0ABCDEF4, 0xABCDEF45, 4);
+ TEST_RR_3OP ( 6, lsr, 0x00000000, 0x7FFFFFFF, 31);
+ TEST_RR_3OP ( 7, lsr, 0x00000001, 0xFFFFFFFF, 31);
+
+ #-------------------------------------------------------------
+ # Flag tests
+ #-------------------------------------------------------------
+ TEST_2OP_CARRY( 9, lsr, 0, 0x00000001, 0x02);
+ TEST_2OP_CARRY(10, lsr, 1, 0x00000001, 0x01);
+ TEST_2OP_ZERO( 11, lsr, 1, 0x00000001, 0x01);
+ TEST_2OP_NEGATIVE( 12, lsr, 1, 0x80000000, 0x00);
+
+
+ARCTEST_END
diff --git a/tests/tcg/arc/check_mac.S b/tests/tcg/arc/check_mac.S
new file mode 100644
index 0000000000..7e172457ab
--- /dev/null
+++ b/tests/tcg/arc/check_mac.S
@@ -0,0 +1,228 @@
+.include "macros.inc"
+
+.equ NOTSET, 47806
+
+; conditionally sets the ACC data
+.macro setup_acc acch, accl
+ .if \accl <> NOTSET
+ mov r58, \accl
+ .endif
+ .if \acch <> NOTSET
+ mov r59, \acch
+ .endif
+.endm
+
+; conditionally checks if ACC holds the given value
+.macro verify_acc racch, raccl, test_num
+ .if \raccl <> NOTSET
+ assert_eq r58, \raccl, \test_num
+ .endif
+ .if \racch <> NOTSET
+ assert_eq r59, \racch, \test_num
+ .endif
+.endm
+
+; all Z, N, C, V flags are cleared and ACC will become 0
+.macro clear_flags_and_accu
+ ; clearing the Z N C V flags
+ mov r0, 1
+ add.f r0, r0, r0
+ ; clearing the acc
+ mov r58, 0
+ mov r59, 0
+.endm
+
+; checks if Z, N, C, and V flags are set correctly
+.macro verify_flags z=0, n=0, c=0, v=0, test_num
+ assert_flag REG_STAT_Z, \z, \test_num
+ assert_flag REG_STAT_N, \n, \test_num
+ assert_flag REG_STAT_C, \c, \test_num
+ assert_flag REG_STAT_V, \v, \test_num
+.endm
+
+; macro for testing "MAC" instruction
+.macro mac_test acch=NOTSET, accl=NOTSET, val1, val2, res, racch=NOTSET, raccl=NOTSET, n=0, v=0, test_num
+ ; initializing data
+ setup_acc \acch, \accl
+ mov r0, \val1
+ mov r1, \val2
+ ; operation under test
+ mac.f r0, r0, r1
+ ; checking the results
+ verify_flags n=\n, v=\v, test_num=\test_num
+ assert_eq \res, r0, \test_num
+ verify_acc \racch, \raccl, \test_num
+.endm
+
+; macro for testing "MACU" instruction
+.macro macu_test acch=NOTSET, accl=NOTSET, val1, val2, res, racch=NOTSET, raccl=NOTSET, v=0, test_num
+ ; initializing data
+ setup_acc \acch, \accl
+ mov r0, \val1
+ mov r1, \val2
+ ; operation under test
+ macu.f r0, r0, r1
+ ; checking the results
+ verify_flags v=\v, test_num=\test_num
+ assert_eq \res, r0, \test_num
+ verify_acc \racch, \raccl, \test_num
+.endm
+
+
+; macro for testing "MACD" instruction
+.macro macd_test acch=NOTSET, accl=NOTSET, val1, val2, resh, resl, racch=NOTSET, raccl=NOTSET, n=0, v=0, test_num
+ ; initializing data
+ setup_acc \acch, \accl
+ mov r0, \val1
+ mov r1, \val2
+ ; operation under test
+ macd.f r0, r0, r1
+ ; checking the results
+ verify_flags n=\n, v=\v, test_num=\test_num
+ assert_eq \resl, r0, \test_num
+ assert_eq \resh, r1, \test_num
+ verify_acc \racch, \raccl, \test_num
+.endm
+
+; macro for testing "MACU" instruction
+.macro macdu_test acch=NOTSET, accl=NOTSET, val1, val2, resh, resl, racch=NOTSET, raccl=NOTSET, v=0, test_num
+ ; initializing data
+ setup_acc \acch, \accl
+ mov r0, \val1
+ mov r1, \val2
+ ; operation under test
+ macdu.f r0, r0, r1
+ ; checking the results
+ verify_flags v=\v, test_num=\test_num
+ assert_eq \resl, r0, \test_num
+ assert_eq \resh, r1, \test_num
+ verify_acc \racch, \raccl, \test_num
+.endm
+
+
+start
+
+;;;;;;;;;;;;;;;;;;;;;; MAC ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; acc = 0 + 4*5 = 20
+mac_test val1=4, val2=5, res=20, test_num=1
+; acc = 20 + 5*1 = 25
+mac_test val1=1, val2=5, res=25, test_num=2
+; acc = 25 + -1*5 = 20
+mac_test val1=0xFFFFFFFF, val2=0x5, res=20, racch=0x0, raccl=20, n=0, test_num=3
+; acc = 20 + -3*9 = -7
+mac_test val1=0xFFFFFFFD, val2=0x09, res=0xFFFFFFF9, racch=0xFFFFFFFF, raccl=0xFFFFFFF9, n=1, test_num=4
+; producing a result that sets both acch and accl
+mac_test acch=0, accl=0, val1=0x7FFFFFFF, val2=0x7FFFFFFF, res=1, racch=0x3FFFFFFF, raccl=0x01, n=0, v=0, test_num=5
+; acc is 0x3FFFFFFF00000001
+mac_test val1=0x80000000, val2=0x80000000, res=1, racch=0x7FFFFFFF, raccl=0x01, n=0, v=0, test_num=6
+; acc is 0x7FFFFFFF00000001; going for the kill: N and V will be set
+mac_test val1=0x12344321, val2=0x56788654, res=0xE1C14CD5, racch=0x86262098, raccl=0xE1C14CD5, n=1, v=1, test_num=7
+; "mac" is not supposed to clear the overflow bit
+mac_test acch=0, accl=0, val1=0, val2=0, res=0, racch=0, raccl=0, n=0, v=1, test_num=8
+clear_flags_and_accu
+
+
+;;;;;;;;;;;;;;;;;;;;;; MACU ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; acc = 0 + 4*5 = 20
+macu_test val1=4, val2=5, res=20, test_num=9
+; acc = 20 + 5*1 = 25
+macu_test val1=1, val2=5, res=25, test_num=10
+; acc = 25 + 21,474,836,475 = 21,474,836,500 (0x00000005,0x00000014)
+macu_test val1=0xFFFFFFFF, val2=0x5, res=20, racch=5, raccl=20, test_num=11
+; acc = 21,474,836,500 + 38,654,705,637 = 60,129,542,137 (0x0000000D,0xFFFFFFF9)
+macu_test val1=0xFFFFFFFD, val2=0x09, res=0xFFFFFFF9, racch=0x0D, raccl=0xFFFFFFF9, test_num=12
+; producing a result that sets both acch and accl
+macu_test acch=0, accl=0, val1=0x7FFFFFFF, val2=0x7FFFFFFF, res=1, racch=0x3FFFFFFF, raccl=0x01, v=0, test_num=13
+; acc is 0x3FFFFFFF00000001
+macu_test val1=0x80000000, val2=0x80000000, res=1, racch=0x7FFFFFFF, raccl=0x01, v=0, test_num=14
+; acc is 0x7FFFFFFF00000001; line below still will not trigger an overflow for MACU
+macu_test val1=0x12344321, val2=0x56788654, res=0xE1C14CD5, racch=0x86262098, raccl=0xE1C14CD5, v=0, test_num=15
+; cause an overflow
+macu_test acch=0xFFFFFFFF, accl=0xFFFFFFFF, val1=1, val2=1, res=0, racch=0, raccl=0, v=1, test_num=16
+; "macu" is not supposed to clear the overflow bit
+macu_test acch=0, accl=0, val1=0, val2=0, res=0, racch=0, raccl=0, v=1, test_num=17
+clear_flags_and_accu
+
+
+;;;;;;;;;;;;;;;;;;;;; MACD ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+macd_test val1=4, val2=5, resh=0, resl=20, test_num=18
+; acc is now 20
+macd_test val1=1, val2=5, resh=0, resl=25, test_num=19
+; acc = 25 + -1*5 = 20
+macd_test val1=0xFFFFFFFF, val2=0x5, resh=0, resl=20, racch=0x0, raccl=20, n=0, test_num=20
+; acc = 20 + -3*9 = -7
+macd_test val1=0xFFFFFFFD, val2=0x09, resh = 0xFFFFFFFF, resl=0xFFFFFFF9, racch=0xFFFFFFFF, raccl=0xFFFFFFF9, n=1, test_num=21
+; producing a result that sets both acch and accl
+macd_test acch=0, accl=0, val1=0x7FFFFFFF, val2=0x7FFFFFFF, resh=0x3FFFFFFF, resl=0x01, racch=0x3FFFFFFF, raccl=0x01, v=0, test_num=22
+; acc is 0x3FFFFFFF00000001
+macd_test val1=0x80000000, val2=0x80000000, resh=0x7FFFFFFF, resl=0x01, racch=0x7FFFFFFF, raccl=0x01, v=0, test_num=23
+; acc is 0x7FFFFFFF00000001; going for the kill: N and V will be set
+macd_test val1=0x12344321, val2=0x56788654, resh=0x86262098, resl=0xE1C14CD5, racch=0x86262098, raccl=0xE1C14CD5, n=1, v=1, test_num=24
+; "macd" is not supposed to clear the overflow bit
+macd_test acch=0, accl=0, val1=0, val2=0, resh=0, resl=0, racch=0, raccl=0, n=0, v=1, test_num=25
+clear_flags_and_accu
+
+
+;;;;;;;;;;;;;;;;;;;; MACDU ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+macdu_test val1=4, val2=5, resh=0, resl=20, test_num=26
+; acc is now 20
+macdu_test val1=1, val2=5, resh=0, resl=25, test_num=27
+; acc = 25 + 21,474,836,475 = 21,474,836,500 (0x00000005,0x00000014)
+macdu_test val1=0xFFFFFFFF, val2=0x5, resh=5, resl=20, racch=5, raccl=20, test_num=28
+; acc = 21,474,836,500 + 38,654,705,637 = 60,129,542,137 (0x0000000D,0xFFFFFFF9)
+macdu_test val1=0xFFFFFFFD, val2=0x09, resh=0x0D, resl=0xFFFFFFF9, racch=0x0D, raccl=0xFFFFFFF9, test_num=29
+; producing a result that sets both acch and accl
+macdu_test acch=0, accl=0, val1=0x7FFFFFFF, val2=0x7FFFFFFF, resh=0x3FFFFFFF, resl=0x01, racch=0x3FFFFFFF, raccl=0x01, v=0, test_num=30
+; acc is 0x3FFFFFFF00000001
+macdu_test val1=0x80000000, val2=0x80000000, resh=0x7FFFFFFF, resl=0x01, racch=0x7FFFFFFF, raccl=0x01, v=0, test_num=31
+; acc is 0x7FFFFFFF00000001; line below still will not trigger an overflow for MACU
+macdu_test val1=0x12344321, val2=0x56788654, resh=0x86262098, resl=0xE1C14CD5, racch=0x86262098, raccl=0xE1C14CD5, v=0, test_num=32
+; cause an overflow
+macdu_test acch=0xFFFFFFFF, accl=0xFFFFFFFF, val1=1, val2=1, resh=0, resl=0, racch=0, raccl=0, v=1, test_num=33
+; "macdu" is not supposed to clear the overflow bit
+macdu_test acch=0, accl=0, val1=0, val2=0, resh=0, resl=0, racch=0, raccl=0, v=1, test_num=34
+clear_flags_and_accu
+
+
+;;;;;;;;;;;;;;;;;;; CC anf FF ;;;;;;;;;;;;;;;;;;;;;;;;;
+mov r0, 0xFFFFFFFF
+mov r1, 0x11111111
+mac.f r2, r0, r1
+assert_flag REG_STAT_N, 1, test_num=35
+clear_flags_and_accu
+
+mov r0, 0xFFFFFFFF
+mov r1, 0x11111111
+mac r2, r0, r1
+assert_flag REG_STAT_N, 0, test_num=36
+clear_flags_and_accu
+
+setup_acc acch=0xFFFFFFFF, accl=0xFFFFFFFF
+mov r0, 0x01
+mov r1, 0x01
+; earlier, this caused an overflow; see test case 25
+macdu r2, r0, r1
+assert_flag REG_STAT_V, 0, test_num=37
+clear_flags_and_accu
+
+; FIXME: uncomment code below when assmbler starts supporting conditon codes
+; cause an overflow and then execute based on CC
+;mov r0, 42
+;mov r1, 1
+;mov r2, 0x1337
+;;macu.v r2, r1, r0 ; assembler does not support this line
+;assert_eq 0x1337, r2, test_num=38
+;
+;mov r0, 42
+;mov r1, 1
+;; causing the N bit to be set
+;mov r4, 0xFFFFFFFF
+;add.f r4, r4, r4
+;; conditional execution and update flags
+;macd.N.f r2, r1, r0 ; assembler does not support this line
+;assert_flag REG_STAT_N, 0, test_num=39
+;assert_eq 42, r2, test_num=39
+
+
+;;;;;;;;;;;;;;;;;;; Finished ;;;;;;;;;;;;;;;;;;;;;;;;;;
+end
diff --git a/tests/tcg/arc/check_manip_10_mmu.S b/tests/tcg/arc/check_manip_10_mmu.S
new file mode 100644
index 0000000000..be426d89e9
--- /dev/null
+++ b/tests/tcg/arc/check_manip_10_mmu.S
@@ -0,0 +1,173 @@
+; check_manip_5_mmu.S
+;
+; Tests for MMU: manipulate MMU table in exception routines.
+; If the test fails, check the end of this file for how to troubleshoot.
+; The running code for this test needs to be in address range >= 0x8000_0000.
+
+ .include "macros.inc"
+ .include "mmu.inc"
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;; Bunch of constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ .equ INT_VECT_ADDRESS, 0x80000000 ; physical address for IVT
+ .equ STATUS32_AD_BIT , 19 ; Alignment Disable bit
+ ; courtesy of macros.inc and mmu.inc
+ .extern REG_IVT_BASE
+ .extern PAGE_NUMBER_MSK
+ .extern REG_PD0_GLOBAL
+ .extern REG_PD0_VALID
+ .extern REG_PD1_KRNL_W
+
+;;;;;;;;;;;;;;;;;;;;;;;;; Exception related code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Handler of the day.
+ .align 4
+handler : .word 0x0
+
+; An exception handler routine that merely jumps to whatever address
+; it was told to by the test. See set_except_handler macro. This
+; requires ivt.S file to be compiled and linked.
+ .align 4
+ .global EV_TLBMissI
+ .global EV_TLBMissD
+ .global EV_ProtV
+ .type EV_TLBMissI, @function
+ .type EV_TLBMissD, @function
+ .type EV_ProtV, @function
+EV_TLBMissI:
+EV_TLBMissD:
+EV_ProtV:
+ ld r11, [handler]
+ j [r11]
+
+; macro: set_except_handler
+; regs used: r11
+;
+; This macro writes the provided ADDR to a temporary place holder
+; that later the exception handler routine will jump to.
+.macro set_except_handler addr
+ mov r11, \addr
+ st r11, [handler]
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Tests ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Let the tests begin
+ start
+ ; use physicall address range for handling exceptions (ivt)
+ mov r0, INT_VECT_ADDRESS
+ sr r0, [REG_IVT_BASE]
+
+; Test case 5
+; Like previous test but with a "branch and link". This is even trickier.
+; BL needs to decode the delay instruction to know its length. It uses
+; this information to determine what value should "BLINK" register hold.
+; Below is the pertinent semantic:
+;
+; delay_insn_addr = bl_insn_addr + bl_insn_len
+; delay_insn_len = decode(delay_insn_addr)
+; BLINK = bl_insn_addr + bl_insn_len + delay_insn_len
+;
+; If the "delay slot" instruction is on a missing page, a TLBMissI is
+; raised during "decode(delay_insn_addr)". This all happens while the
+; "BL" instruction is being handled (and not the delay slot):
+;
+; ecr = 0x40000 (TLBMissI)
+; eret = bl_insn_addr --> for previous test, this is delay_insn_addr
+; efa = delay_insn_addr
+; blink = old value (not updated)
+ .equ T5_VIRT_ADDR, 0x00602000 ; virtual page address
+ .equ T5_PHYS_ADDR, 0xA0008000 ; physical page address
+ .equ T5_ADDR_OFS, 0x00001FF8 ; the offset in the page
+ .equ T5_PD0, ((T5_VIRT_ADDR+T5_ADDR_OFS & PAGE_NUMBER_MSK) | REG_PD0_GLOBAL | REG_PD0_VALID)
+ .equ T5_PD1, ((T5_PHYS_ADDR+T5_ADDR_OFS & PAGE_NUMBER_MSK) | REG_PD1_KRNL_R | REG_PD1_KRNL_E)
+ .equ T5_size, test_10_embedded_code_end - test_10_embedded_code_start
+
+ mmu_prep_test_case
+ mmu_prep_test_case
+ ; Copy the embedded code into physical page
+ xor_s r3, r3, r3
+ mov r0, @test_10_embedded_code_start
+ mov r1, @T5_PHYS_ADDR+T5_ADDR_OFS
+test_10_copy:
+ ldb.ab r2, [r0, 1]
+ stb.ab r2, [r1, 1]
+ add_s r3, r3, 1
+ cmp r3, T5_size
+ blt @test_10_copy
+ ; Add MMU
+ set_except_handler @test_10_except_handler
+ mmu_tlb_insert T5_PD0, T5_PD1
+ mmu_enable
+ lr r8, [bta] ; remember the old bta value
+ mov r0, 0x80000000 ; will be used by the code to be executed
+ mov r1, T5_VIRT_ADDR+T5_ADDR_OFS ; jump to the copied code
+ ; Have embedded code word-aligned at a place where it will be put.
+
+ mov r5, 0
+ mov r4, 1
+ sub.f 0, r5, r4
+ j [r1]
+
+test_10_control:
+ sub r7, r4, r5 ; 1
+ sub.f 0, r7, r6 ;
+
+ bne @fail
+ add r5, r5, 1
+
+ sub.f 0, r5, 2
+ beq @test_10_end
+
+ sub.f 0, r5, r4
+ j [r1]
+
+ .align 4
+test_10_embedded_code_start:
+ mov r6, 1
+ bne.d @to_jump
+ ld r7, [r0]
+ mov r6, 0
+to_jump:
+ j @test_10_control
+ nop
+test_10_virt_finish:
+ mov r6, 1
+ j @test_10_control
+test_10_embedded_code_end:
+; Exception routine that will add entry for the second page
+test_10_except_handler:
+ mmu_prep_test_case_address
+ lr r9, [ecr]
+ cmp r9, 0x40000 ; TLBMissI?
+ bne @fail
+ mmu_prep_test_case_address
+ lr r9, [eret]
+ cmp r9, @T5_VIRT_ADDR+0x2000 ; Beginning of second page?
+ jne @fail
+ mmu_prep_test_case_address
+ lr r9, [efa]
+ cmp r9, @T5_VIRT_ADDR+0x2000 ; Beginning of second page?
+ jne @fail
+ mmu_tlb_insert T5_PD0+0x2000, T5_PD1+0x2000
+ rtie
+test_10_end:
+ ; Fall through
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Reporting ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+valhalla:
+ print "[PASS]"
+ b @1f
+
+; If a test fails, it jumps here. Although, for the sake of uniformity,
+; the printed output does not say much about which test case failed,
+; one can uncomment the print_number line below or set a breakpoint
+; here to check the R0 register for the test case number.
+fail:
+ ld r0, [mmu_test_nr]
+ ;print_number r0
+ print "[FAIL]"
+1:
+ print " MMU: manipulate MMU table in exception routines\n"
+ end
diff --git a/tests/tcg/arc/check_manip_4_mmu.S b/tests/tcg/arc/check_manip_4_mmu.S
new file mode 100644
index 0000000000..599cd2a95a
--- /dev/null
+++ b/tests/tcg/arc/check_manip_4_mmu.S
@@ -0,0 +1,158 @@
+; check_manip_4_mmu.S
+;
+; Tests for MMU: manipulate MMU table in exception routines.
+; If the test fails, check the end of this file for how to troubleshoot.
+; The running code for this test needs to be in address range >= 0x8000_0000.
+
+ .include "macros.inc"
+ .include "mmu.inc"
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;; Bunch of constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ .equ INT_VECT_ADDRESS, 0x80000000 ; physical address for IVT
+ .equ STATUS32_AD_BIT , 19 ; Alignment Disable bit
+ ; courtesy of macros.inc and mmu.inc
+ .extern REG_IVT_BASE
+ .extern PAGE_NUMBER_MSK
+ .extern REG_PD0_GLOBAL
+ .extern REG_PD0_VALID
+ .extern REG_PD1_KRNL_W
+
+;;;;;;;;;;;;;;;;;;;;;;;;; Exception related code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Handler of the day.
+ .align 4
+handler : .word 0x0
+
+; An exception handler routine that merely jumps to whatever address
+; it was told to by the test. See set_except_handler macro. This
+; requires ivt.S file to be compiled and linked.
+ .align 4
+ .global EV_TLBMissI
+ .global EV_TLBMissD
+ .global EV_ProtV
+ .type EV_TLBMissI, @function
+ .type EV_TLBMissD, @function
+ .type EV_ProtV, @function
+EV_TLBMissI:
+EV_TLBMissD:
+EV_ProtV:
+ ld r11, [handler]
+ j [r11]
+
+; macro: set_except_handler
+; regs used: r11
+;
+; This macro writes the provided ADDR to a temporary place holder
+; that later the exception handler routine will jump to.
+.macro set_except_handler addr
+ mov r11, \addr
+ st r11, [handler]
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Tests ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Let the tests begin
+ start
+ ; use physicall address range for handling exceptions (ivt)
+ mov r0, INT_VECT_ADDRESS
+ sr r0, [REG_IVT_BASE]
+; Test case 4
+; Straddle a "branch" and its "delay slot" on two consecutive pages.
+; The first virtual page has an entry in TLB, but the second one (which
+; the delay slot is on) does not. We want to see when fetching the delay
+; slot causes a TLBMissI, things will go back smoothly.
+;
+; first page with TLB entry
+; ,-----.
+; | ... |
+; | nop |
+; | b.d | branch instruction as the last instruction of the page
+; `-----'
+; ,-----.
+; | dly | delay instruction on the next page
+; | ... |
+; | |
+; `-----'
+; second page without TLB entry
+ .equ T4_VIRT_ADDR, 0x00402000 ; virtual page address
+ .equ T4_PHYS_ADDR, 0x90008000 ; physical page address
+ .equ T4_ADDR_OFS, 0x00001FF8 ; the offset in the page
+ .equ T4_PD0, ((T4_VIRT_ADDR+T4_ADDR_OFS & PAGE_NUMBER_MSK) | REG_PD0_GLOBAL | REG_PD0_VALID)
+ .equ T4_PD1, ((T4_PHYS_ADDR+T4_ADDR_OFS & PAGE_NUMBER_MSK) | REG_PD1_KRNL_R | REG_PD1_KRNL_E)
+ .equ T4_size, test_4_embedded_code_end - test_4_embedded_code_start
+
+ mmu_prep_test_case
+ ; Copy the embedded code into physical page
+ xor_s r3, r3, r3
+ mov r0, @test_4_embedded_code_start
+ mov r1, @T4_PHYS_ADDR+T4_ADDR_OFS
+test_4_copy:
+ ldb.ab r2, [r0, 1]
+ stb.ab r2, [r1, 1]
+ add_s r3, r3, 1
+ cmp r3, T4_size
+ blt @test_4_copy
+ ; Add MMU
+ set_except_handler @test_4_except_handler
+ mmu_tlb_insert T4_PD0, T4_PD1
+ mmu_enable
+ mov r0, 0x80000000 ; will be used by the code to be executed
+ mov r1, T4_VIRT_ADDR+T4_ADDR_OFS ; jump to the copied code
+ j [r1]
+ ; Have embedded code word-aligned at a place where it will be put.
+ .align 4
+test_4_embedded_code_start:
+ nop
+ b.d @test_4_virt_finish
+ ld r1, [r0]
+ nop
+ j @fail
+ nop
+test_4_virt_finish:
+ j @test_4_end
+test_4_embedded_code_end:
+; Exception routine that will add entry for the second page
+test_4_except_handler:
+ mmu_prep_test_case_address
+ lr r9, [ecr]
+ cmp r9, 0x40000 ; TLBMissI?
+ bne @fail
+ mmu_prep_test_case_address
+ lr r9, [eret]
+ cmp r9, @T4_VIRT_ADDR+0x2000 ; Beginning of second page?
+ jne @fail
+ mmu_prep_test_case_address
+ lr r9, [efa]
+ cmp r9, @T4_VIRT_ADDR+0x2000 ; Beginning of second page?
+ jne @fail
+ mmu_prep_test_case_address
+ lr r9, [bta]
+ cmp r9, @T4_VIRT_ADDR+T4_ADDR_OFS+T4_size-8 ; BTA correct?
+ jne @fail
+ mmu_prep_test_case_address
+ lr r9, [erbta]
+ cmp r9, @T4_VIRT_ADDR+T4_ADDR_OFS+T4_size-8 ; ERBTA correct?
+ jne @fail
+ mmu_tlb_insert T4_PD0+0x2000, T4_PD1+0x2000
+ rtie
+test_4_end:
+ ; Fall through
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Reporting ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+valhalla:
+ print "[PASS]"
+ b @1f
+
+; If a test fails, it jumps here. Although, for the sake of uniformity,
+; the printed output does not say much about which test case failed,
+; one can uncomment the print_number line below or set a breakpoint
+; here to check the R0 register for the test case number.
+fail:
+ ld r0, [mmu_test_nr]
+ ;print_number r0
+ print "[FAIL]"
+1:
+ print " MMU: manipulate MMU table in exception routines\n"
+ end
diff --git a/tests/tcg/arc/check_manip_5_mmu.S b/tests/tcg/arc/check_manip_5_mmu.S
new file mode 100644
index 0000000000..17ea00bfe8
--- /dev/null
+++ b/tests/tcg/arc/check_manip_5_mmu.S
@@ -0,0 +1,166 @@
+; check_manip_5_mmu.S
+;
+; Tests for MMU: manipulate MMU table in exception routines.
+; If the test fails, check the end of this file for how to troubleshoot.
+; The running code for this test needs to be in address range >= 0x8000_0000.
+
+ .include "macros.inc"
+ .include "mmu.inc"
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;; Bunch of constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ .equ INT_VECT_ADDRESS, 0x80000000 ; physical address for IVT
+ .equ STATUS32_AD_BIT , 19 ; Alignment Disable bit
+ ; courtesy of macros.inc and mmu.inc
+ .extern REG_IVT_BASE
+ .extern PAGE_NUMBER_MSK
+ .extern REG_PD0_GLOBAL
+ .extern REG_PD0_VALID
+ .extern REG_PD1_KRNL_W
+
+;;;;;;;;;;;;;;;;;;;;;;;;; Exception related code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Handler of the day.
+ .align 4
+handler : .word 0x0
+
+; An exception handler routine that merely jumps to whatever address
+; it was told to by the test. See set_except_handler macro. This
+; requires ivt.S file to be compiled and linked.
+ .align 4
+ .global EV_TLBMissI
+ .global EV_TLBMissD
+ .global EV_ProtV
+ .type EV_TLBMissI, @function
+ .type EV_TLBMissD, @function
+ .type EV_ProtV, @function
+EV_TLBMissI:
+EV_TLBMissD:
+EV_ProtV:
+ ld r11, [handler]
+ j [r11]
+
+; macro: set_except_handler
+; regs used: r11
+;
+; This macro writes the provided ADDR to a temporary place holder
+; that later the exception handler routine will jump to.
+.macro set_except_handler addr
+ mov r11, \addr
+ st r11, [handler]
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Tests ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Let the tests begin
+ start
+ ; use physicall address range for handling exceptions (ivt)
+ mov r0, INT_VECT_ADDRESS
+ sr r0, [REG_IVT_BASE]
+
+; Test case 5
+; Like previous test but with a "branch and link". This is even trickier.
+; BL needs to decode the delay instruction to know its length. It uses
+; this information to determine what value should "BLINK" register hold.
+; Below is the pertinent semantic:
+;
+; delay_insn_addr = bl_insn_addr + bl_insn_len
+; delay_insn_len = decode(delay_insn_addr)
+; BLINK = bl_insn_addr + bl_insn_len + delay_insn_len
+;
+; If the "delay slot" instruction is on a missing page, a TLBMissI is
+; raised during "decode(delay_insn_addr)". This all happens while the
+; "BL" instruction is being handled (and not the delay slot):
+;
+; ecr = 0x40000 (TLBMissI)
+; eret = bl_insn_addr --> for previous test, this is delay_insn_addr
+; efa = delay_insn_addr
+; blink = old value (not updated)
+ .equ T5_VIRT_ADDR, 0x00602000 ; virtual page address
+ .equ T5_PHYS_ADDR, 0xA0008000 ; physical page address
+ .equ T5_ADDR_OFS, 0x00001FF8 ; the offset in the page
+ .equ T5_PD0, ((T5_VIRT_ADDR+T5_ADDR_OFS & PAGE_NUMBER_MSK) | REG_PD0_GLOBAL | REG_PD0_VALID)
+ .equ T5_PD1, ((T5_PHYS_ADDR+T5_ADDR_OFS & PAGE_NUMBER_MSK) | REG_PD1_KRNL_R | REG_PD1_KRNL_E)
+ .equ T5_size, test_5_embedded_code_end - test_5_embedded_code_start
+
+ mmu_prep_test_case
+ mmu_prep_test_case
+ ; Copy the embedded code into physical page
+ xor_s r3, r3, r3
+ mov r0, @test_5_embedded_code_start
+ mov r1, @T5_PHYS_ADDR+T5_ADDR_OFS
+test_5_copy:
+ ldb.ab r2, [r0, 1]
+ stb.ab r2, [r1, 1]
+ add_s r3, r3, 1
+ cmp r3, T5_size
+ blt @test_5_copy
+ ; Add MMU
+ set_except_handler @test_5_except_handler
+ mmu_tlb_insert T5_PD0, T5_PD1
+ mmu_enable
+ lr r4, [bta] ; remember the old bta value
+ mov r0, 0x80000000 ; will be used by the code to be executed
+ mov r1, T5_VIRT_ADDR+T5_ADDR_OFS ; jump to the copied code
+ j [r1]
+ ; Have embedded code word-aligned at a place where it will be put.
+ .align 4
+test_5_embedded_code_start:
+ nop
+ bl.d @test_5_virt_finish
+ ld r1, [r0]
+ nop
+ j @fail
+ nop
+test_5_virt_finish:
+ j @test_5_end
+test_5_embedded_code_end:
+; Exception routine that will add entry for the second page
+test_5_except_handler:
+ mmu_prep_test_case_address
+ lr r9, [ecr]
+ print_number_hex r9
+ cmp r9, 0x40000 ; TLBMissI?
+ bne @fail
+ mmu_prep_test_case_address
+ lr r9, [eret]
+ print_number_hex r9
+ cmp r9, @T5_VIRT_ADDR+0x2000-4 ; Beginning of second page?
+ jne @fail
+ mmu_prep_test_case_address
+ lr r9, [efa]
+ print_number_hex r9
+ cmp r9, @T5_VIRT_ADDR+0x2000 ; Beginning of second page?
+ jne @fail
+ mmu_prep_test_case_address
+ lr r9, [bta]
+ print_number_hex r9
+ cmp r9, r4 ; BTA not updated? (still old?)
+ jne @fail
+ mmu_prep_test_case_address
+ lr r9, [erbta]
+ cmp r9, r4 ; ERBTA same as not updated BTA?
+ jne @fail
+ mmu_tlb_insert T5_PD0+0x2000, T5_PD1+0x2000
+ rtie
+test_5_end:
+ ; Fall through
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Reporting ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+valhalla:
+ print "[PASS]"
+ b @1f
+
+; If a test fails, it jumps here. Although, for the sake of uniformity,
+; the printed output does not say much about which test case failed,
+; one can uncomment the print_number line below or set a breakpoint
+; here to check the R0 register for the test case number.
+fail:
+ ld r0, [mmu_test_nr]
+ ;print_number r0
+ print "[FAIL]"
+1:
+ print " MMU: manipulate MMU table in exception routines\n"
+ end
diff --git a/tests/tcg/arc/check_manip_mmu.S b/tests/tcg/arc/check_manip_mmu.S
new file mode 100644
index 0000000000..c2bab099f9
--- /dev/null
+++ b/tests/tcg/arc/check_manip_mmu.S
@@ -0,0 +1,565 @@
+; check_manip_mmu.S
+;
+; Tests for MMU: manipulate MMU table in exception routines.
+; If the test fails, check the end of this file for how to troubleshoot.
+; The running code for this test needs to be in address range >= 0x8000_0000.
+
+ .include "macros.inc"
+ .include "mmu.inc"
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;; Bunch of constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ .equ INT_VECT_ADDRESS, 0x80000000 ; physical address for IVT
+ .equ STATUS32_AD_BIT , 19 ; Alignment Disable bit
+ ; courtesy of macros.inc and mmu.inc
+ .extern REG_IVT_BASE
+ .extern PAGE_NUMBER_MSK
+ .extern REG_PD0_GLOBAL
+ .extern REG_PD0_VALID
+ .extern REG_PD1_KRNL_W
+
+;;;;;;;;;;;;;;;;;;;;;;;;; Exception related code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Handler of the day.
+ .align 4
+handler : .word 0x0
+
+; An exception handler routine that merely jumps to whatever address
+; it was told to by the test. See set_except_handler macro. This
+; requires ivt.S file to be compiled and linked.
+ .align 4
+ .global EV_TLBMissI
+ .global EV_TLBMissD
+ .global EV_ProtV
+ .global instruction_error
+ .type EV_TLBMissI, @function
+ .type EV_TLBMissD, @function
+ .type EV_ProtV, @function
+ .type instruction_error, @function
+EV_TLBMissI:
+EV_TLBMissD:
+EV_ProtV:
+instruction_error:
+ ld r11, [handler]
+ j [r11]
+
+; macro: set_except_handler
+; regs used: r11
+;
+; This macro writes the provided ADDR to a temporary place
+; that later the exception handler routine will jump to.
+.macro set_except_handler addr
+ mov r11, \addr
+ st r11, [handler]
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Tests ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Let the tests begin
+ start
+ ; use physicall address range for handling exceptions (ivt)
+ mov r0, INT_VECT_ADDRESS
+ sr r0, [REG_IVT_BASE]
+
+; Test case 1:
+; Reading from a virtual address that has no entry in TLB. This will
+; cause a TLBMissD exception. In return, the exception routine handler
+; will add the corresponding entry:
+; ,-----------------.------------------.----------------------.
+; | virtual address | physical address | (kernel) permissions |
+; |-----------------+------------------+----------------------|
+; | 0x1337_1334 | 0x7331_1334 | R-- |
+; `-----------------^------------------^----------------------'
+; After returning from the exception, the "ld" should go OK.
+; Then there comes a write ("st") that will trigger a ProtV exception.
+; This time, we allow writing as well:
+; ,-----------------.------------------.----------------------.
+; | virtual address | physical address | (kernel) permissions |
+; |-----------------+------------------+----------------------|
+; | 0x1337_1334 | 0x7331_1334 | RW- |
+; `-----------------^------------------^----------------------'
+; the "st" to the same address should go fine.
+ .equ T1_VIRT_ADDR, 0x13371334 ; the virtual address; word aligned
+ .equ T1_PHYS_ADDR, 0x73311334 ; the physical address (same page offset as VA)
+ .equ T1_DATA_1 , 0x00BADB07 ; the test value to read and verify
+ .equ T1_DATA_2 , 0x00B07BAD ; the test value to write and verify
+ .equ T1_PD0 , ((T1_VIRT_ADDR & PAGE_NUMBER_MSK) | REG_PD0_GLOBAL | REG_PD0_VALID)
+ .equ T1_PD1_R , ((T1_PHYS_ADDR & PAGE_NUMBER_MSK) | REG_PD1_KRNL_R)
+ .equ T1_PD1_RW, (T1_PD1_R | REG_PD1_KRNL_W)
+ mmu_prep_test_case
+ mov r2, 0 ; exception handler counter
+ mov r1, T1_DATA_1 ; plant the data ...
+ st r1, [T1_PHYS_ADDR] ; ... into the physical address
+ set_except_handler @test_1_except_handler
+ mmu_enable
+test_1_ld:
+ ld r0, [T1_VIRT_ADDR] ; TLBMissD causing instruction
+ cmp r0, T1_DATA_1
+ bne @fail
+ mov r0, T1_DATA_2
+test_1_st:
+ st r0, [T1_VIRT_ADDR] ; TLBProtV causing instruction
+ mmu_disable ; MMU bye-bye!
+ ld r1, [T1_PHYS_ADDR] ; Load the final destination of "st"
+ cmp r1, T1_DATA_2 ; was it written successfuly?
+ bne @fail
+ b @test_1_end
+test_1_except_handler:
+ add_s r2, r2, 1
+ cmp r2, 1 ; TLBMissD while loading?
+ bne @1f
+ lr r11, [ecr]
+ cmp r11, TLB_MISS_D_READ; TLBMissD during a load?
+ bne @fail
+ lr r11, [eret]
+ cmp r11, @test_1_ld ; instruction causing the exception
+ lr r11, [efa]
+ cmp r11, T1_VIRT_ADDR ; faulty address is correct?
+ jne @fail
+ mov r11, 0
+ sr r11, [efa] ; clearing EFA
+ mmu_tlb_insert T1_PD0, T1_PD1_R
+ rtie
+1:
+ cmp r2, 2 ; ProtV during write?
+ bne @fail
+ lr r11, [ecr]
+ cmp r11, 0x60208 ; ProtV from MMU during a write?
+ bne @fail
+ lr r11, [eret]
+ cmp r11, @test_1_st ; instruction causing the exception
+ lr r11, [efa]
+ cmp r11, T1_VIRT_ADDR ; faulty address is correct?
+ jne @fail
+ mmu_tlb_insert T1_PD0, T1_PD1_RW
+ rtie
+test_1_end:
+ ; Fall through
+
+; Test case 2
+; Load a double word data straddled over two consecutive virtual pages:
+; ,-------------------------------.,-----------------------------.
+; | ... x0 x1 x2 x3 || x4 x5 x6 x7 x8 ... |
+; `-------------------------------'`-----------------------------'
+; virt=0x0050_2000..0x0050_4000 virt=0x0050_4000..0x050_6000
+;
+; Only the first page has an entry in TLB:
+; ,-----------------.------------------.----------------------.
+; | virtual address | physical address | (kernel) permissions |
+; |-----------------+------------------+----------------------|
+; | 0x0050_2000 | 0x3000_8000 | R-- |
+; `-----------------^------------------^----------------------'
+;
+; An "ldd" from the last 4 byte of the first page will span to
+; the second page. This will lead to an exception (TLBMissD).
+ .equ T2_VIRT_ADDR, 0x00502000 ; virtual page address
+ .equ T2_PHYS_ADDR, 0x30008000 ; physical page address
+ .equ T2_ADDR_OFS, 0x00001FFC ; the offset in the page
+ .equ T2_PD0, ((T2_VIRT_ADDR+T2_ADDR_OFS & PAGE_NUMBER_MSK) | REG_PD0_GLOBAL | REG_PD0_VALID)
+ .equ T2_PD1, ((T2_PHYS_ADDR & PAGE_NUMBER_MSK) | REG_PD1_KRNL_R)
+
+ mmu_prep_test_case
+ mov r2, 0 ; exception handler counter
+ set_except_handler @test_2_except_handler
+ mmu_tlb_insert T2_PD0, T2_PD1
+ mmu_enable
+test_2_ldd:
+ ldd r0, [T2_VIRT_ADDR+T2_ADDR_OFS]
+ cmp r2, 1
+ bne @fail
+ b @test_2_end ; success!
+test_2_except_handler:
+ add r2, r2, 1 ; increase the counter
+ lr r11, [ecr]
+ cmp r11, 0x50100 ; TLBMissD during a load?
+ bne @fail
+ lr r11, [eret]
+ cmp r11, @test_2_ldd
+ jne @fail
+ lr r11, [efa]
+ cmp r11, T2_VIRT_ADDR+T2_ADDR_OFS+4 ; beginning of next page
+ jne @fail
+ mmu_disable
+ rtie
+test_2_end:
+ ; Fall through
+
+; Test case 3
+; Load a data word (0x12345678) straddled over two consecutive
+; virtual pages:
+; ,--------------------.,--------------------.
+; | ... 0x78 || 0x56 0x34 0x12 ... |
+; `--------------------'`--------------------'
+; virt=0x0000...0x2000 virt=0x2000...0x4000
+;
+; Only the first page has an entry in TLB:
+; ,-----------------.------------------.----------------------.
+; | virtual address | physical address | (kernel) permissions |
+; |-----------------+------------------+----------------------|
+; | 0x0000_0000 | 0x7000_0000 | R-- |
+; `-----------------^------------------^----------------------'
+;
+; An "ld" (word-sized) from the last byte of the first page will
+; span to the first 3 bytes of the second page. This will lead
+; to an exception (TLBMissD). The exception routine will add the
+; entry for the second page:
+; ,-----------------.------------------.----------------------.
+; | virtual address | physical address | (kernel) permissions |
+; |-----------------+------------------+----------------------|
+; | 0x0000_0000 | 0x7000_0000 | R-- |
+; | 0x0000_2000 | 0x6000_2000 | R-- |
+; `-----------------^------------------^----------------------'
+;
+; And in the end, we must have fetched the data (0x12345678).
+; To make the test realistic, the physical page addresses are not
+; consecutive as opposed to their virtual counter parts.
+; The alignment check should be disabled for this test.
+ .equ T3_VIRT_ADDR_1, 0x00000000 ; two virtual page addresses ...
+ .equ T3_VIRT_ADDR_2, 0x00002000 ; ... that are consecutive.
+ .equ T3_PHYS_ADDR_1, 0x70000000 ; two physical page addresses ...
+ .equ T3_PHYS_ADDR_2, 0x60002000 ; ... that are inconsecutive.
+ .equ T3_ADDR_1_OFS, 0x00001FFF ; the offset in the first pages.
+ .equ T3_PD0_ENT1, ((T3_VIRT_ADDR_1+T3_ADDR_1_OFS & PAGE_NUMBER_MSK) | REG_PD0_GLOBAL | REG_PD0_VALID)
+ .equ T3_PD1_ENT1, ((T3_PHYS_ADDR_1 & PAGE_NUMBER_MSK) | REG_PD1_KRNL_R)
+ .equ T3_PD0_ENT2, ((T3_VIRT_ADDR_2 & PAGE_NUMBER_MSK) | REG_PD0_GLOBAL | REG_PD0_VALID)
+ .equ T3_PD1_ENT2, ((T3_PHYS_ADDR_2 & PAGE_NUMBER_MSK) | REG_PD1_KRNL_R)
+ mmu_prep_test_case
+ ; Plant data at the physical addresses
+ mov r1, 0x12345678
+ stb r1, [T3_PHYS_ADDR_1+T3_ADDR_1_OFS] ; 0x78 at the end of first page
+ lsr8 r1, r1
+ sth r1, [T3_PHYS_ADDR_2] ; 0x56 0x34 at the beginning of 2nd page
+ lsr16 r1, r1
+ stb r1, [T3_PHYS_ADDR_2+2] ; 0x12 The 3rd byte on the 2nd page
+ mov r1, 0 ; exception handler counter
+ disable_alignment
+ set_except_handler @test_3_except_handler
+ mmu_tlb_insert T3_PD0_ENT1, T3_PD1_ENT1
+ mmu_enable
+ ; Exception-causing instruction
+test_3_ld:
+ ld r0, [T3_VIRT_ADDR_1+T3_ADDR_1_OFS]
+ mov r3, 0x12345678
+ cmp r0, r3
+ bne @fail
+ cmp r1, 1
+ bne @fail
+ b @test_3_end ; success!
+test_3_except_handler:
+ add r1, r1, 1 ; increase the counter
+ lr r11, [ecr]
+ cmp r11, 0x50100 ; TLBMissD during a load?
+ bne @fail
+ lr r11, [eret]
+ cmp r11, @test_3_ld
+ jne @fail
+ lr r11, [efa]
+ cmp r11, @T3_VIRT_ADDR_2
+ jne @fail
+ mmu_tlb_insert T3_PD0_ENT2, T3_PD1_ENT2
+ rtie
+test_3_end:
+ ; Fall through
+
+; Test case 4
+; Straddle a "branch" and its "delay slot" on two consecutive pages.
+; The first virtual page has an entry in TLB, but the second one (which
+; the delay slot is on) does not. We want to see when fetching the delay
+; slot causes a TLBMissI, things will go back smoothly.
+;
+; first page with TLB entry
+; ,-----.
+; | ... |
+; | nop |
+; | b.d | branch instruction as the last instruction of the page
+; `-----'
+; ,-----.
+; | dly | delay instruction on the next page
+; | ... |
+; | |
+; `-----'
+; second page without TLB entry
+ .equ T4_VIRT_ADDR, 0x00402000 ; virtual page address
+ .equ T4_PHYS_ADDR, 0x90008000 ; physical page address
+ .equ T4_ADDR_OFS, 0x00001FF8 ; the offset in the page
+ .equ T4_PD0, ((T4_VIRT_ADDR+T4_ADDR_OFS & PAGE_NUMBER_MSK) | REG_PD0_GLOBAL | REG_PD0_VALID)
+ .equ T4_PD1, ((T4_PHYS_ADDR+T4_ADDR_OFS & PAGE_NUMBER_MSK) | REG_PD1_KRNL_R | REG_PD1_KRNL_E)
+ .equ T4_size, test_4_embedded_code_end - test_4_embedded_code_start
+
+ mmu_prep_test_case
+ ; Copy the embedded code into physical page
+ xor_s r3, r3, r3
+ mov r0, @test_4_embedded_code_start
+ mov r1, @T4_PHYS_ADDR+T4_ADDR_OFS
+test_4_copy:
+ ldb.ab r2, [r0, 1]
+ stb.ab r2, [r1, 1]
+ add_s r3, r3, 1
+ cmp r3, T4_size
+ blt @test_4_copy
+ ; Add MMU
+ set_except_handler @test_4_except_handler
+ mmu_tlb_insert T4_PD0, T4_PD1
+ mmu_enable
+ mov r1, T4_VIRT_ADDR+T4_ADDR_OFS ; jump to the copied code
+ j [r1]
+ ; Have embedded code word-aligned at a place where it will be put.
+ .align 4
+test_4_embedded_code_start:
+ nop
+ b.d @test_4_virt_finish
+ add r1, r0, r0
+ nop
+ j @fail
+ nop
+test_4_virt_finish:
+ j @test_4_end
+test_4_embedded_code_end:
+; Exception routine that will add entry for the second page
+test_4_except_handler:
+ lr r11, [ecr]
+ cmp r11, TLB_MISS_I
+ bne @fail
+ lr r11, [eret]
+ cmp r11, @T4_VIRT_ADDR+0x2000 ; Beginning of second page?
+ jne @fail
+ lr r11, [efa]
+ cmp r11, @T4_VIRT_ADDR+0x2000 ; Beginning of second page?
+ jne @fail
+ lr r11, [bta]
+ cmp r11, @T4_VIRT_ADDR+T4_ADDR_OFS+T4_size-8 ; BTA correct?
+ jne @fail
+ lr r11, [erbta]
+ cmp r11, @T4_VIRT_ADDR+T4_ADDR_OFS+T4_size-8 ; ERBTA correct?
+ jne @fail
+ mmu_tlb_insert T4_PD0+0x2000, T4_PD1+0x2000
+ rtie
+test_4_end:
+ ; Fall through
+
+; Test case 5
+; Like previous test but with a "branch and link". This is even trickier.
+; BL needs to decode the delay instruction to know its length. It uses
+; this information to determine what value should "BLINK" register hold.
+; Below is the pertinent semantic:
+;
+; delay_insn_addr = bl_insn_addr + bl_insn_len
+; delay_insn_len = decode(delay_insn_addr)
+; BLINK = bl_insn_addr + bl_insn_len + delay_insn_len
+;
+; If the "delay slot" instruction is on a missing page, a TLBMissI is
+; raised during "decode(delay_insn_addr)". This all happens while the
+; "BL" instruction is being handled (and not the delay slot):
+;
+; ecr = 0x40000 (TLBMissI)
+; eret = bl_insn_addr --> for previous test, this is delay_insn_addr
+; efa = delay_insn_addr
+; bta = old value (not updated)
+; blink = old value (not updated)
+ .equ T5_VIRT_ADDR, 0x00602000 ; virtual page address
+ .equ T5_PHYS_ADDR, 0xA0008000 ; physical page address
+ .equ T5_ADDR_OFS, 0x00001FF8 ; the offset in the page
+ .equ T5_PD0, ((T5_VIRT_ADDR+T5_ADDR_OFS & PAGE_NUMBER_MSK) | REG_PD0_GLOBAL | REG_PD0_VALID)
+ .equ T5_PD1, ((T5_PHYS_ADDR+T5_ADDR_OFS & PAGE_NUMBER_MSK) | REG_PD1_KRNL_R | REG_PD1_KRNL_E)
+ .equ T5_size, test_5_embedded_code_end - test_5_embedded_code_start
+
+ mmu_prep_test_case
+ ; Copy the embedded code into physical page
+ xor_s r3, r3, r3
+ mov r0, @test_5_embedded_code_start
+ mov r1, @T5_PHYS_ADDR+T5_ADDR_OFS
+test_5_copy:
+ ldb.ab r2, [r0, 1]
+ stb.ab r2, [r1, 1]
+ add_s r3, r3, 1
+ cmp r3, T5_size
+ blt @test_5_copy
+ ; Add MMU
+ set_except_handler @test_5_except_handler
+ mmu_tlb_insert T5_PD0, T5_PD1
+ mmu_enable
+ lr r4, [bta] ; remember the old bta value
+ mov r5, blink ; remember the old blink value
+ mov r1, T5_VIRT_ADDR+T5_ADDR_OFS ; jump to the copied code
+ j [r1]
+ ; Have embedded code word-aligned at a place where it will be put.
+ .align 4
+test_5_embedded_code_start:
+ nop
+ bl.d @test_5_virt_finish
+ add r1, r0, r0
+ nop
+ j @fail
+ nop
+test_5_virt_finish:
+ j @test_5_end
+test_5_embedded_code_end:
+; Exception routine that will add entry for the second page
+test_5_except_handler:
+ lr r11, [ecr]
+ cmp r11, TLB_MISS_I
+ bne @fail
+ lr r11, [eret]
+ cmp r11, @T5_VIRT_ADDR+0x2000-4 ; Last instruction of the first page (bl)?
+ jne @fail
+ lr r11, [efa]
+ cmp r11, @T5_VIRT_ADDR+0x2000 ; Beginning of second page?
+ jne @fail
+ lr r11, [bta]
+ cmp r11, r4 ; BTA not updated? (still old?)
+ jne @fail
+ lr r11, [erbta]
+ cmp r11, r4 ; ERBTA same as not-updated-BTA?
+ mov r11, blink
+ cmp r11, r5 ; BLINK not updated? (still old?)
+ jne @fail
+ mmu_tlb_insert T5_PD0+0x2000, T5_PD1+0x2000
+ rtie
+test_5_end:
+ ; Fall through
+
+; Test case 6: BLINK register must be updated immediately after "BL".
+ mmu_prep_test_case
+ bl.d @test_6_branch_taken
+ mov r0, blink
+test_6_after_delay_slot:
+ b @fail
+ .align 4
+test_6_branch_taken:
+ mov r1, @test_6_after_delay_slot
+ cmp r0, r1
+ bne @fail
+
+; Test case 7: BTA register must be updated immediately after "BL".
+ mmu_prep_test_case
+ bl.d @test_7_branch_taken
+ lr r0, [bta]
+ b @fail
+ .align 4
+test_7_branch_taken:
+ mov r1, @test_7_branch_taken
+ cmp r0, r1
+ bne @fail
+
+;; Test case 8: Exceptions other than TLBMissI for the delay slot of BL
+;; In this case, such exceptions are deep in decoding pipeline and should
+;; cause a normal exception like any other instructions, where ERET is
+;; pointing to the delay slot and not the BL instruction, like the previous
+;; tests.
+; mmu_prep_test_case
+; set_except_handler @test_8_except_handler
+; bl.d @test_8_end
+;test_8_delay_slot:
+; lr r0, [blink] ; InstructionError
+; b @fail
+;; Exception routine that will add entry for the second page
+;test_8_except_handler:
+; lr r11, [ecr]
+; cmp r11, ILLEGAL_INSTRUCTION
+; bne @fail
+; lr r11, [eret]
+; cmp r11, @test_8_delay_slot
+; jne @fail
+; lr r11, [efa]
+; cmp r11, @test_8_delay_slot
+; jne @fail
+; lr r11, [erbta]
+; cmp r11, @test_8_end
+; jne @fail
+; lr r11, [bta]
+; cmp r11, @test_8_end
+; jne @fail
+; sr r11, [eret] ; Get out of delay slot by jumping to BTA
+; lr r11, [erstatus]
+; bclr r11, r11, 6 ; Clear delay slot execution flag
+; sr r11, [erstatus]
+; rtie
+; b @fail
+; .align 4
+;test_8_end:
+; ; Fall through
+
+; Test case 9
+; Like test case 5, but the CC is false here. Although, there is no need
+; for the calculation of BLINK and the _early_ decode of delay slot
+; instruction, still TLBMissI exception for the delay slot instruction
+; happens during the execution of "BLne.D". This is how the hardware
+; works.
+; ecr = 0x40000 (TLBMissI)
+; eret = bl_insn_addr
+; efa = delay_insn_addr
+; bta = old value (not updated)
+; blink = old value (not updated)
+ .equ T9_VIRT_ADDR, 0x00606000 ; virtual page address
+ .equ T9_PHYS_ADDR, 0xA000A000 ; physical page address
+ .equ T9_ADDR_OFS, 0x00001FF4 ; the offset in the page
+ .equ T9_PD0, ((T9_VIRT_ADDR+T9_ADDR_OFS & PAGE_NUMBER_MSK) | REG_PD0_GLOBAL | REG_PD0_VALID)
+ .equ T9_PD1, ((T9_PHYS_ADDR+T9_ADDR_OFS & PAGE_NUMBER_MSK) | REG_PD1_KRNL_R | REG_PD1_KRNL_E)
+ .equ T9_size, test_9_embedded_code_end - test_9_embedded_code_start
+
+ mmu_prep_test_case
+ ; Copy the embedded code into physical page
+ xor_s r3, r3, r3
+ mov r0, @test_9_embedded_code_start
+ mov r1, @T9_PHYS_ADDR+T9_ADDR_OFS
+test_9_copy:
+ ldb.ab r2, [r0, 1]
+ stb.ab r2, [r1, 1]
+ add_s r3, r3, 1
+ cmp r3, T9_size
+ blt @test_9_copy
+ ; Add MMU
+ set_except_handler @test_9_except_handler
+ mmu_tlb_insert T9_PD0, T9_PD1
+ mmu_enable
+ lr r4, [bta] ; remember the old bta value
+ mov r1, T9_VIRT_ADDR+T9_ADDR_OFS ; jump to the copied code
+ j [r1]
+ ; Have embedded code word-aligned at a place where it will be put.
+ .align 4
+test_9_embedded_code_start:
+ add.f 0, 0, 0
+ blne.d @fail
+ add r0, r0, r0
+ j @test_9_end
+test_9_embedded_code_end:
+; Exception routine that will add entry for the second page
+test_9_except_handler:
+ lr r11, [ecr]
+ cmp r11, TLB_MISS_I
+ bne @fail
+ lr r11, [eret]
+ cmp r11, @T9_VIRT_ADDR+0x2000-4 ; Last instruction of the first page (blne.d)?
+ jne @fail
+ lr r11, [efa]
+ cmp r11, @T9_VIRT_ADDR+0x2000 ; Beginning of second page?
+ jne @fail
+ lr r11, [bta]
+ cmp r11, r4 ; BTA not updated? (still old?)
+ jne @fail
+ lr r11, [erbta]
+ cmp r11, r4 ; ERBTA same as not updated BTA?
+ jne @fail
+ mmu_tlb_insert T9_PD0+0x2000, T9_PD1+0x2000
+ rtie
+test_9_end:
+ ; Fall through
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Reporting ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+valhalla:
+ print "[PASS]"
+ b @1f
+
+.align 4
+; If a test fails, it jumps here. Although, for the sake of uniformity,
+; the printed output does not say much about which test case failed,
+; one can uncomment the print_number line below or set a breakpoint
+; here to check the R0 register for the test case number.
+fail:
+ ld r0, [mmu_test_nr]
+ ;print_number r0
+ print "[FAIL]"
+1:
+ print " MMU: manipulate MMU table in exception routines\n"
+ end
diff --git a/tests/tcg/arc/check_mmu.S b/tests/tcg/arc/check_mmu.S
new file mode 100644
index 0000000000..69a38e30d5
--- /dev/null
+++ b/tests/tcg/arc/check_mmu.S
@@ -0,0 +1,59 @@
+.include "macros.inc"
+.include "mmu.inc"
+
+; courtesy of mmu.inc
+.extern PAGE_NUMBER_MSK
+.extern REG_PD0_GLOBAL
+.extern REG_PD0_VALID
+.extern REG_PD1_KRNL_W
+
+; test data
+; making an entry for the TLB
+;
+; ,------------------------------------.
+; | VPN(VA), G=1, V=1 | PPN(PHY), Wk=1 |
+; `------------------------------------'
+; where:
+; VPN(VA) is the virtual page number of logical address
+; G is the global bit
+; V is the validity bit
+; PPN(PHY) is the physical page number
+; Wk is the write permission in kernel mode
+
+; obviously, the offsets in both addresses must be the same
+.equ VIRT_ADR , 0x13371334 ; the virtual address; word aligned
+.equ PHYS_ADR , 0x73311334 ; the physical address > 0x7FFFFFFF
+.equ MAGICDATA, 0x00BADB07 ; the test value to write and verify
+.equ PD0_VPN , (VIRT_ADR & PAGE_NUMBER_MSK)
+.equ PD1_PPN , (PHYS_ADR & PAGE_NUMBER_MSK)
+.equ PD0_BITS , (PD0_VPN | REG_PD0_GLOBAL | REG_PD0_VALID)
+.equ PD1_BITS , (PD1_PPN | REG_PD1_KRNL_W)
+
+start
+
+mmu_enable
+
+; insert into table: VA 0x13371337 (Global) --> PHY: 0x73311337 (RW kernel)
+mmu_tlb_insert PD0_BITS, PD1_BITS
+
+; write to the mapped virtual address
+mov r0, MAGICDATA
+st r0, [VIRT_ADR]
+
+mmu_disable
+
+; with mmu disabled, read from physical address and
+; verify that it is the same as the value written
+; to the mapped virtual address earlier
+ld r1, [PHYS_ADR]
+cmp r0, r1 ; r0 contains the MAGICDATA
+beq @goodboy
+
+print "nope, still no MMU!\n"
+j @adios
+
+goodboy:
+print "Yay, you got the MMU right :)\n"
+
+adios:
+end
diff --git a/tests/tcg/arc/check_mpu.S b/tests/tcg/arc/check_mpu.S
new file mode 100644
index 0000000000..e840b95403
--- /dev/null
+++ b/tests/tcg/arc/check_mpu.S
@@ -0,0 +1,703 @@
+; check_mpu.S
+;
+; Tests for MPUv3: Memory protection unit v3.
+; If the test fails, check the end of this file for how to troubleshoot.
+
+ .include "macros.inc"
+ .include "mpu.inc"
+ .include "mmu.inc"
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;; Test checking routines ;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Test case counter
+.data
+test_nr:
+ .word 0x0
+
+; Increment the test counter and set (Z,N,C,V) to (0,0,0,0).
+.macro prep_test_case
+ ld r13, [test_nr]
+ add_s r13, r13, 1 ; increase test case counter
+ st r13, [test_nr]
+ add.f 0, 0, 1 ; (Z, N, C, V) = (0, 0, 0, 0)
+.endm
+
+; macro: auxreg_write_read
+; input: reg - the register we are talking about
+; write - value to write
+; read - value expected to be read
+; regs used: r11, r12
+; example: auxreg_write_read mpuen, 0xffffffff, 0x400001f8
+;
+; description:
+; Not always, "write" and "read" values are the same. This true about
+; the registers who have reserved bits or read as zero in user mode,
+; etc.
+; Be careful, what is the result of you writing to to "reg". It may
+; have consequences like enabling page protection or so.
+.macro auxreg_write_read reg, write, read
+ mov r11, \write
+ sr r11, [\reg]
+ ; using a different register to reduce the chande of false equality
+ lr r12, [\reg]
+ cmp r12, \read
+ bne @fail
+.endm
+
+ start
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; check the MPU_BUILD
+test_00:
+ .equ VERSION , 0x03
+ .equ NR_REGIONS, 0x08
+ .equ MPU_BCR_REF, (NR_REGIONS << 8) | VERSION
+ lr r0, [mpu_build]
+ cmp r0, MPU_BCR_REF
+ bne @fail
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; All of the registers should be accessible in kernel mode
+; this test (check_mpu) is based on 8 regions.
+test_01:
+ prep_test_case
+ ; mpuen : momentarily enabled with full access
+ ; when read, only relevant bits must be set.
+ auxreg_write_read mpuen , 0xffffffff, 0x400001f8
+ ; disable mpu at once
+ mpu_disable
+ auxreg_write_read mpurdb0 , 0xffffffff, 0xffffffe1
+ auxreg_write_read mpurdp0 , 0xffffffff, 0x00000ffb
+ auxreg_write_read mpurdb1 , 0xffffffff, 0xffffffe1
+ auxreg_write_read mpurdp1 , 0xffffffff, 0x00000ffb
+ auxreg_write_read mpurdb2 , 0xffffffff, 0xffffffe1
+ auxreg_write_read mpurdp2 , 0xffffffff, 0x00000ffb
+ auxreg_write_read mpurdb3 , 0xffffffff, 0xffffffe1
+ auxreg_write_read mpurdp3 , 0xffffffff, 0x00000ffb
+ auxreg_write_read mpurdb4 , 0xffffffff, 0xffffffe1
+ auxreg_write_read mpurdp4 , 0xffffffff, 0x00000ffb
+ auxreg_write_read mpurdb5 , 0xffffffff, 0xffffffe1
+ auxreg_write_read mpurdp5 , 0xffffffff, 0x00000ffb
+ auxreg_write_read mpurdb6 , 0xffffffff, 0xffffffe1
+ auxreg_write_read mpurdp6 , 0xffffffff, 0x00000ffb
+ auxreg_write_read mpurdb7 , 0xffffffff, 0xffffffe1
+ auxreg_write_read mpurdp7 , 0xffffffff, 0x00000ffb
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; None of the registers should be accessible in user mode
+test_02:
+ prep_test_case
+ mpu_reset
+ ; prep the exception for the end
+ lr r0, [mpuic] ; don't care for mpu_ecr value
+ mpu_set_except_params mpu_ecr = r0 , \
+ ecr = PRIVILEGE_VIOLATION , \
+ efa = @test_02_user_space+4, \
+ eret = @test_02_user_space+4, \
+ continue = @test_02_end
+ enter_user_mode @test_02_user_space
+test_02_user_space:
+ add r0, r0, r0 ; some filler to make a basic block
+ ; accessing MPU registers in user mode is not allowed
+ lr r0, [mpu_build]
+ b @fail ; an exception must have been raised
+test_02_end:
+ ; Fall through
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Running with -global cpu.has-mpu=false or reading a region register
+; which is higher than the configured number of regions causes an
+; instuction error: ecr=0x020000
+test_03:
+ prep_test_case
+ mpu_reset
+ ; prep the exception for 'lr'ing a region that does not exist
+ lr r0, [mpuic] ; don't care for mpu_ecr value
+ mpu_set_except_params mpu_ecr = r0 , \
+ ecr = ILLEGAL_INSTRUCTION , \
+ efa = @test_03_illegal_lr_rgn, \
+ eret = @test_03_illegal_lr_rgn, \
+ continue = @test_03_cont
+test_03_illegal_lr_rgn:
+ lr r1, [mpurdb15]
+ b @fail ; exception must have been raised
+test_03_cont:
+ ; prep the exception for 'sr'ing a region that does not exist
+ lr r0, [mpuic] ; don't care for mpu_ecr value
+ mpu_set_except_params mpu_ecr = r0 , \
+ ecr = ILLEGAL_INSTRUCTION , \
+ efa = @test_03_illegal_sr_rgn, \
+ eret = @test_03_illegal_sr_rgn, \
+ continue = @test_03_end
+test_03_illegal_sr_rgn:
+ sr r1, [mpurdp8]
+ b @fail ; an exception must have been raised
+test_03_end:
+ ; Fall through
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Verifying the KR permission for region 1.
+; Checking if "read" is OK and "write" raises an exception.
+test_04:
+ .equ MEM_ADDR04 , 0x16000
+ .equ DATA04 , 0x1337
+ .equ MPU_ECR_W_R1, MPU_ECR_WRITE | 1
+ prep_test_case
+ mpu_reset
+ mpu_add_base mpurdb1, MEM_ADDR04
+ mpu_add_region mpurdp1, REG_MPU_EN_KR, MPU_SIZE_32B
+ mpu_write_data DATA04, MEM_ADDR04
+ mpu_enable
+ ; read permission check
+ mpu_verify_data DATA04, MEM_ADDR04
+ ; write permission check
+ mpu_set_except_params mpu_ecr = MPU_ECR_W_R1 , \
+ ecr = PROTV_WRITE_MPU , \
+ efa = MEM_ADDR04 , \
+ eret = @test_04_illegal_store+4, \
+ continue = @test_04_end
+test_04_illegal_store:
+ add r0, r0, r0 ; filler; so exception happens in...
+ st r1, [MEM_ADDR04] ; ...the middle of a translation block
+ b @fail ; an exception must have been raised
+test_04_end:
+ ; Fall through
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Having 2 small regions next to each other: one with write permission
+; and the other with read permission. Check if permissions are respected
+; accordingly. This tests how MPU sets QEmu's internal TLB and if it is
+; able to set the TLB's entry size correctly.
+test_05:
+ .equ MEM_ADDR05, 0x16024 ; 4 bytes above the multiple of 32
+ .equ DATA05 , 0xbabe
+ prep_test_case
+ mpu_reset
+ mpu_add_base mpurdb0, MEM_ADDR05 ; effective address would be 0x4020
+ mpu_add_region mpurdp0, REG_MPU_EN_KW, MPU_SIZE_32B
+ mpu_add_base mpurdb1, MEM_ADDR05+32; effective address would be 0x4040
+ mpu_add_region mpurdp1, REG_MPU_EN_KR, MPU_SIZE_32B
+ mpu_write_data DATA05, MEM_ADDR05+32 ; write to 0x4044 (region1)
+ ; let the fun begin
+ mpu_enable
+ mpu_verify_data DATA05, MEM_ADDR05+32
+ st r7, [MEM_ADDR05] ; write bogus data (region 0)
+ ; now time for some exception
+ mpu_set_except_params mpu_ecr = MPU_ECR_W_R1 , \
+ ecr = PROTV_WRITE_MPU , \
+ efa = MEM_ADDR05+32 , \
+ eret = @test_05_illegal_store, \
+ continue = @test_05_end
+test_05_illegal_store:
+ st r7, [MEM_ADDR05+32] ; this shouldn't be allowed
+ b @fail ; an exception must have been raised
+test_05_end:
+ ; Fall through
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Update a region's permission and size to check if they are taken
+; into account.
+test_06:
+ .equ MEM_ADDR06, 0x30000
+ .equ MPU_ECR_R_R3, MPU_ECR_READ | 3
+ prep_test_case
+ mpu_reset
+ mpu_add_base mpurdb3, MEM_ADDR06
+ mpu_add_region mpurdp3, REG_MPU_EN_KR, MPU_SIZE_64B
+ mpu_enable
+ ld r7, [MEM_ADDR06+32] ; this should be allowed
+ ; changing permission (deliberately mpu is not disabled)
+ mpu_add_region mpurdp3, REG_MPU_EN_KE, MPU_SIZE_64B ; update (KR -> KE)
+ ; prep for exception
+ mpu_set_except_params mpu_ecr = MPU_ECR_R_R3 , \
+ ecr = PROTV_READ_MPU , \
+ efa = MEM_ADDR06+32 , \
+ eret = @test_06_illegal_read, \
+ continue = @test_06_change_size
+test_06_illegal_read:
+ ld r7, [MEM_ADDR06+32] ; this is not allowed anymore
+ b @fail ; an exception must have been raised
+test_06_change_size:
+ ; changing size (deliberately mpu is not disabled)
+ mpu_add_region mpurdp3, REG_MPU_EN_KE, MPU_SIZE_32B ; update (64 -> 32)
+ mpu_enable
+ ld r7, [MEM_ADDR06+32] ; this is allowed again (+32 is in def. region)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Check a permission that has only execute permission.
+; The read should not be possible.
+test_07:
+ .equ NOP_OPCODE, 0x7000264a
+ .equ JR1_OPCODE, 0x00402020
+ .equ CODE_CAVE07, 0x40000
+ .equ MPU_ECR_R_R0, MPU_ECR_READ | 0
+ prep_test_case
+ mpu_reset
+ mpu_add_base mpurdb0, CODE_CAVE07
+ mpu_add_region mpurdp0, REG_MPU_EN_KE, MPU_SIZE_32B
+ mov r0, NOP_OPCODE
+ mov r1, @test_07_rest
+ mov r2, JR1_OPCODE
+ st r0, [CODE_CAVE07] ; nop
+ st r2, [CODE_CAVE07+4] ; j [r1]
+ st r0, [CODE_CAVE07+8] ; nop
+ mpu_enable
+ ; let's take a leap of faith
+ j CODE_CAVE07
+
+test_07_rest:
+ ; wow, if we just came back, let's raise hell
+ mpu_set_except_params mpu_ecr = MPU_ECR_R_R0 , \
+ ecr = PROTV_READ_MPU , \
+ efa = CODE_CAVE07+4 , \
+ eret = @test_07_illegal_read, \
+ continue = @test_07_end
+test_07_illegal_read:
+ ld r7, [CODE_CAVE07+4] ; this shouldn't be allowed
+ b @fail ; an exception must have been raised
+test_07_end:
+ ; Fall through
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; One region to rule them all
+; 1) We are testing a very big region here.
+; 2) Moreover we change its permission and size in the middle
+test_08:
+ .equ MEM_ADDR08 , 0x00000000
+ .equ BIG_ADDR08 , 0x7FFFFFE0
+ .equ MPU_ECR_W_R7 , MPU_ECR_WRITE | 7
+ .equ MPU_ECR_R_DEF, MPU_ECR_READ | 0xFF
+ .equ DATA08_1 , 0x34fa ; random magic
+ .equ DATA08_2 , 0x987afb ; random magic
+ prep_test_case
+ mpu_reset
+ ; planting the data
+ mpu_write_data DATA08_1, BIG_ADDR08
+ ; a 4 gigabyte region with read and execute permissions
+ mpu_add_base mpurdb7, MEM_ADDR08
+ mpu_add_region mpurdp7, REG_MPU_EN_KR | REG_MPU_EN_KE , MPU_SIZE_4G
+ ; prepping exception (must be before enable, otherwise no write access)
+ mpu_set_except_params mpu_ecr = MPU_ECR_W_R7 , \
+ ecr = PROTV_WRITE_MPU , \
+ efa = BIG_ADDR08 , \
+ eret = @test_08_illegal_write , \
+ continue = @test_08_change_permission, \
+ ; default region with only write permission
+ mpu_enable REG_MPU_EN_KW
+ ; checking read (BIG_ADDR08) and exec (current instruction) permissions
+ mpu_verify_data DATA08_1, BIG_ADDR08
+test_08_illegal_write:
+ st r7, [BIG_ADDR08] ; no write is allowed
+ b @fail ; an exception must have been raised
+test_08_change_permission:
+ ; change permission _and_ size
+ mpu_add_region mpurdp7, REG_MPU_EN_FULL_ACCESS , MPU_SIZE_2G
+ ; now there should be no problem in writing either
+ mpu_write_data DATA08_2, BIG_ADDR08
+ mpu_verify_data DATA08_2, BIG_ADDR08
+ ; prepping second exception: default region has no read access
+ mpu_set_except_params mpu_ecr = MPU_ECR_R_DEF , \
+ ecr = PROTV_READ_MPU , \
+ efa = BIG_ADDR08+0xF0 , \
+ eret = @test_08_illegal_def_read, \
+ continue = @test_08_end
+test_08_illegal_def_read:
+ ld r7, [BIG_ADDR08+0xF0] ; this is default region now and not sanctioned
+ b @fail ; an exception must have been raised
+test_08_end:
+ ; Fall through
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; A user cannot have kernel permissions, but a kernel inherits granted
+; user permissions as well.
+test_09:
+ .equ MEM_ADDR09_1, 0x60000
+ .equ MEM_ADDR09_2, 0x62000 ; 8k after
+ .equ MPU_ECR_W_R6, MPU_ECR_WRITE | 6
+ .equ DATA09 , 0x89091 ; another random data from beyond
+ prep_test_case
+ mpu_reset
+ ; a region for user to write
+ mpu_add_base mpurdb5, MEM_ADDR09_1
+ mpu_add_region mpurdp5, REG_MPU_EN_UW, MPU_SIZE_8K
+ ; a region only for kernel
+ mpu_add_base mpurdb6, MEM_ADDR09_2
+ mpu_add_region mpurdp6, REG_MPU_EN_KR | REG_MPU_EN_KW, MPU_SIZE_8K
+ ; prep the exception for the end
+ mpu_set_except_params mpu_ecr = MPU_ECR_W_R6 , \
+ ecr = PROTV_WRITE_MPU , \
+ efa = MEM_ADDR09_2 , \
+ eret = @test_09_user_space+8 , \
+ continue = @test_09_rest_kernel_mode
+ ; let's have at it
+ mpu_enable REG_MPU_EN_UE | REG_MPU_EN_KR
+ enter_user_mode @test_09_user_space
+test_09_user_space:
+ st r7, [MEM_ADDR09_2-4] ; write to the end of user region
+ st r7, [MEM_ADDR09_2] ; uh-oh: causing trouble
+ b @fail ; an exception must have been raised
+test_09_rest_kernel_mode:
+ ; a simple write and verify chore in kernel mode
+ mpu_write_data DATA09, MEM_ADDR09_2+64
+ mpu_verify_data DATA09, MEM_ADDR09_2+64
+ ; also writing to user region because of implied write access
+ mpu_write_data DATA09, MEM_ADDR09_1+64
+ mpu_disable ; else we cannot verify (no read access)
+ mpu_verify_data DATA09, MEM_ADDR09_1+64
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; A region with only user read access should not be fetchable.
+test_10:
+ .equ CODE_CAVE10 , 0x100000
+ .equ DATA10 , 0x010101
+ .equ MPU_ECR_E_R4, MPU_ECR_FETCH | 4
+ prep_test_case
+ mpu_reset
+ mpu_add_base mpurdb4, CODE_CAVE10
+ mpu_add_region mpurdp4, REG_MPU_EN_UR, MPU_SIZE_64K
+ ; plant the data
+ mpu_write_data DATA10, CODE_CAVE10
+ ; prep the exception for the region being not executable
+ mpu_set_except_params mpu_ecr = MPU_ECR_E_R4 , \
+ ecr = PROTV_FETCH_MPU, \
+ efa = CODE_CAVE10 , \
+ eret = CODE_CAVE10 , \
+ continue = @test_10_end
+ mpu_enable
+ enter_user_mode @test_10_user_space
+test_10_user_space:
+ mpu_verify_data DATA10, CODE_CAVE10 ; read must be OK
+ j @CODE_CAVE10 ; this one not
+ b @fail ; an exception must have been raised
+test_10_end:
+ ; Fall through
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; KE must be enough for raising exceptions.
+; The tricky thing about this test is that it is allowing the
+; parameters for the exceptions to be readable. As a result,
+; the test assumes that there is 32 byte region that these
+; parameters fit in AND it does not overlap with the exception
+; routine itself.
+test_11:
+ .equ MEM_ADDR11, 0x900
+ prep_test_case
+ mpu_reset
+ ; allowing exception parameters to be read
+ mpu_add_base mpurdb0, @mpu_ecr_ref
+ mpu_add_region mpurdp0, REG_MPU_EN_KR, MPU_SIZE_32B
+ ; prep for the exception
+ mpu_set_except_params mpu_ecr = MPU_ECR_R_DEF , \
+ ecr = PROTV_READ_MPU , \
+ efa = MEM_ADDR11 , \
+ eret = @test_11_illegal_read, \
+ continue = @test_11_end
+ mpu_enable REG_MPU_EN_KE
+ add r0, r0, r0 ; just a random guy making a difference
+test_11_illegal_read:
+ ld r0, [MEM_ADDR11]
+ b @fail ; an exception must have been raised
+test_11_end:
+ mpu_disable
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Double exception must raise Machine Check with memory management disabled.
+; This test hangs in nSIM if MMU exists. Apparently, nSIM sets the halt flag
+; if a MachineCheck is raised and there is MMU in the system. The presence
+; of MMU is necessary for test 14.
+test_12:
+ .equ MPU_ECR_E_DEF, MPU_ECR_FETCH | 0xFF
+ prep_test_case
+ mpu_reset
+ ; enable MPU with no access whatsoever
+ mpu_enable 0x0
+test_12_doomed:
+ add r0, r0, r0
+ lr r0, [mpuen]
+ cmp r0, 0
+ bne @fail
+ j @test_12_end
+ ; the machine check routine to be executed eventually
+ .global EV_MachineCheck
+ .type EV_MachineCheck, @function
+ .align 4
+EV_MachineCheck:
+ lr r0, [mpuen]
+ cmp r0, REG_MPU_EN_EN
+ bne @fail
+ lr r0, [mpuic]
+ cmp r0, MPU_ECR_E_DEF
+ bne @fail
+ lr r0, [ecr]
+ cmp r0, MACHINE_CHECK
+ bne @fail
+ lr r0, [eret]
+ cmp r0, @test_12_doomed
+ bne @fail
+ lr r1, [efa]
+ cmp r0, r1
+ bne @fail
+ mpu_disable ; disable MPU in a civilized way
+ lr r0, [erstatus] ; undo the mess:
+ and r0, r0, ~32 ; clear AE bit
+ sr r0, [erstatus] ; and
+ rtie ; return
+test_12_end:
+ ; Fall through
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Page size for the default region: best effort 8K, else 1 byte. You need
+; to look into tracing to see if it is doing the right thing.
+test_13:
+ .equ TWO_PAGES_BEFORE , 0x7C000
+ .equ ONE_PAGE_BEFORE , 0x7E000
+ .equ MEM_ADDR13_1 , 0x80000
+ .equ SAME_PAGE_BETWEEN, 0x80050
+ .equ MEM_ADDR13_2 , 0x80100
+ .equ SAME_PAGE_AFTER , 0x81000
+ .equ ONE_PAGE_AFTER , 0x82000
+ .equ MPU_ECR_R_R1 , MPU_ECR_READ | 1
+ prep_test_case
+ mpu_reset
+ mpu_add_base mpurdb3, MEM_ADDR13_1 ; \
+ mpu_add_region mpurdp3, 0x0, MPU_SIZE_32B ; | two black holes
+ mpu_add_base mpurdb1, MEM_ADDR13_2 ; | alike regions
+ mpu_add_region mpurdp1, 0x0, MPU_SIZE_32B ; /
+ ; your exception shall be your salvation
+ mpu_set_except_params mpu_ecr = MPU_ECR_R_R1 , \
+ ecr = PROTV_READ_MPU , \
+ efa = MEM_ADDR13_2 , \
+ eret = @test_13_illegal_read, \
+ continue = @test_13_end
+ mpu_enable
+ ld r0, [TWO_PAGES_BEFORE+0x1000] ; must cache the page
+ ld r0, [TWO_PAGES_BEFORE+0x1100] ; reuse same information
+ ld r0, [ONE_PAGE_BEFORE +0x1FFC] ; oooh, just before the black hole
+ ld r0, [ONE_PAGE_BEFORE +0x0500] ; reuse from above
+ ld r0, [SAME_PAGE_BETWEEN ] ; too narrow to cache the page
+ ld r0, [SAME_PAGE_BETWEEN+0x10 ] ; permissions must be totally checked
+ ld r0, [SAME_PAGE_AFTER ] ; same page as the black holes
+ ld r0, [SAME_PAGE_AFTER+0x10 ] ; no caching must be used
+ ld r0, [ONE_PAGE_AFTER ] ; this area is safe and ...
+ ld r0, [ONE_PAGE_AFTER+0x04 ] ; ...can be cached
+test_13_illegal_read:
+ ld r0, [MEM_ADDR13_2 ] ; oops!
+ b @fail ; an exception must have been raised
+test_13_end:
+ ; Fall through
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; MMU and MPU may coexist but do not overlap.
+; This test assumes an "rwe" access for exception routine checks and an "re"
+; access for the page this test case is loaded in. If these two pages happen
+; to be the same, e.g. previous tests are commented out, then things will
+; get nasty, because the last attribute will be used for both.
+test_14:
+ .equ MMU_KRNL_RE , REG_PD1_KRNL_E | REG_PD1_KRNL_R
+ .equ MMU_KRNL_RWE, REG_PD1_KRNL_E | REG_PD1_KRNL_W | REG_PD1_KRNL_R
+ .equ MMU_VPN_GV , REG_PD0_GLOBAL | REG_PD0_VALID
+ .equ MEM_ADDR14 , 0x80000100 ; an address in MPU's interest
+ ; creates an entry in TLB with given permissions.
+ ; the translation is identical (virt = physical)
+ .macro add_mmu_entry addr, permission
+ mov r2, \addr
+ and r2, r2, PAGE_NUMBER_MSK
+ or r3, r2, \permission ; r3 holds physical address and permissoins
+ or r2, r2, MMU_VPN_GV ; r2 is a global valid virtual address
+ mmu_tlb_insert r2, r3 ; add entry for MMU
+ .endm
+ prep_test_case
+ mpu_reset
+ b @test_14_after_align
+ ; guarantee that current page won't be the same as @mp_ecr_ref's page
+ .align 0x2000
+test_14_after_align:
+ ; add a read/write/execute permission for exception part page
+ ; @mpu_ecr_ref and ProtV handler must be in the same page.
+ add_mmu_entry @mpu_ecr_ref, MMU_KRNL_RWE
+ ; add a read/write/execute permission for vector table.
+ add_mmu_entry 0x0, MMU_KRNL_RWE
+ ; add a read/execute permission for current page
+ lr r1, [pc]
+ add_mmu_entry r1, MMU_KRNL_RE
+ ; exception for writing to the (2nd) MMU page
+ lr r0, [mpuic] ; don't care for mpu_ecr value
+ mpu_set_except_params mpu_ecr = r0 , \
+ ecr = PROTV_WRITE_MMU , \
+ efa = r1 , \
+ eret = @test_14_illegal_write, \
+ continue = @test_14_mpu
+ ; enable the guys
+ mmu_enable ; enable MMU
+ mpu_enable REG_MPU_EN_KW ; enable MPU with kernel write access
+ ; this is happening in MMU's territory
+test_14_illegal_write:
+ st r0, [r1] ; no write for this entry in TLB
+ b @fail ; an exception must have been raised
+
+test_14_mpu:
+ add r0, r0, r0 ; a happy camper
+ st r0, [MEM_ADDR14] ; in MPU realm
+ ; MPU exception now
+ mpu_set_except_params mpu_ecr = MPU_ECR_R_DEF , \
+ ecr = PROTV_READ_MPU , \
+ efa = MEM_ADDR14 , \
+ eret = @test_14_illegal_read, \
+ continue = @test_14_end
+test_14_illegal_read:
+ ld r0, [MEM_ADDR14] ; uh-oh...
+ b @fail ; an exception must have been raised
+test_14_end:
+ mpu_disable
+ mmu_disable
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Two overlapping regions test. One is 2 pages long and the other is inside
+; the second page of the first region:
+; ,----------.
+; | R2:rw- | region nr 2 with read/write permission.
+; page1 | |
+; | |
+; .......|..........|.......
+; | |
+; page2 |,________.|
+; ||R1:r-- || region nr 1 with read only permission.
+; |`--------'| this region is inside region nr 2.
+; `----------'
+; setup: R2 is 16kb with rw-
+; R1 is 4kb with r--
+; write to the first page --> must go ok.
+; write to the first half of page 2 --> must go ok.
+; write to R1 --> expect an exception.
+; in the end read from R1 --> must go ok.
+test_15:
+ .equ MEM_ADDR15_R2 , 0x150000
+ .equ MEM_ADDR15_R2_P2, MEM_ADDR15_R2 + PAGE_SIZE
+ .equ MEM_ADDR15_R1 , MEM_ADDR15_R2_P2 + PAGE_SIZE/2
+ .equ DATA15_1 , 0x3ff0293f ; random magic
+ .equ DATA15_2 , DATA15_1+1
+ .equ DATA15_3 , DATA15_1+2
+ .equ MPU_ECR_W_R1, MPU_ECR_WRITE | 1
+ prep_test_case
+ mpu_reset
+ mpu_add_base mpurdb1, MEM_ADDR15_R1
+ mpu_add_region mpurdp1, REG_MPU_EN_KR, MPU_SIZE_4K
+ mpu_add_base mpurdb2, MEM_ADDR15_R2
+ mpu_add_region mpurdp2, REG_MPU_EN_KR|REG_MPU_EN_KW, MPU_SIZE_16K
+ ; planting some data (for later read)
+ mpu_write_data DATA15_1, MEM_ADDR15_R1+24
+ ; let the fun begin
+ mpu_enable
+ mpu_write_data DATA15_2, MEM_ADDR15_R2+20
+ mpu_verify_data DATA15_2, MEM_ADDR15_R2+20
+ mpu_write_data DATA15_3, MEM_ADDR15_R2+20+PAGE_SIZE
+ mpu_verify_data DATA15_3, MEM_ADDR15_R2+20+PAGE_SIZE
+ ; now time for some exception
+ mpu_set_except_params mpu_ecr = MPU_ECR_W_R1 , \
+ ecr = PROTV_WRITE_MPU , \
+ efa = MEM_ADDR15_R1+24 , \
+ eret = @test_15_illegal_store, \
+ continue = @test_15_cont
+ st r7, [MEM_ADDR15_R2_P2+32] ; write bogus data (region 2, page 2)
+test_15_illegal_store:
+ st r7, [MEM_ADDR15_R1+24] ; this shouldn't be allowed
+ b @fail ; an exception must have been raised
+test_15_cont:
+ mpu_verify_data DATA15_1, MEM_ADDR15_R1+24 ; this is allowed
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Another overlapping regions test. In previous one, a page (nr=2) was split
+; among two regions. in this test, the page is contained inside another
+; region, which in return is inside yet another region:
+; ,----------.
+; page1 | R5:r--- | region nr 5 with read only permission.
+; .......|..........|.......
+; page2 | |
+; .......|..........|.......
+; page3 | |
+; .......|..........|.......
+; page4 | |
+; .......|,________.|.......
+; page5 ||R3:-w- || region nr 3 with write only permission.
+; .......||........||.......
+; page6 || || this region is inside region nr 5.
+; .......|`--------'|.......
+; page7 | |
+; .......|..........|.......
+; page8 | |
+; `----------'
+; setup: R3 is 16kb with -w-
+; R5 is 64kb with r--
+; read from the fourth page --> must go ok.
+; read from page 7 --> must go ok.
+; write to page 4 --> expect an exception.
+; write to page 5 --> must go ok.
+; read from page 6 --> expect an exception.
+test_16:
+ .equ MEM_ADDR16_R5 , 0x160000
+ .equ MEM_ADDR16_R5_P4, MEM_ADDR16_R5 + 3*PAGE_SIZE
+ .equ MEM_ADDR16_R5_P7, MEM_ADDR16_R5 + 6*PAGE_SIZE
+ .equ MEM_ADDR16_R3 , MEM_ADDR16_R5 + 4*PAGE_SIZE
+ .equ MEM_ADDR16_R3_P5, MEM_ADDR16_R3
+ .equ MEM_ADDR16_R3_P6, MEM_ADDR16_R5 + 5*PAGE_SIZE
+ .equ DATA16_1 , 0x93822093 ; random magic
+ .equ DATA16_2 , DATA16_1+1
+ .equ DATA16_3 , DATA16_1+2
+ .equ MPU_ECR_R_R3, MPU_ECR_READ | 3
+ .equ MPU_ECR_W_R5, MPU_ECR_WRITE | 5
+ prep_test_case
+ mpu_reset
+ mpu_add_base mpurdb3, MEM_ADDR16_R3
+ mpu_add_region mpurdp3, REG_MPU_EN_KW, MPU_SIZE_16K
+ mpu_add_base mpurdb5, MEM_ADDR16_R5
+ mpu_add_region mpurdp5, REG_MPU_EN_KR, MPU_SIZE_64K
+ ; planting some data (for later read)
+ mpu_write_data DATA16_1, MEM_ADDR16_R5_P4+24
+ mpu_write_data DATA16_3, MEM_ADDR16_R5_P7+24
+ ; let the fun begin
+ mpu_enable
+ mpu_verify_data DATA16_1, MEM_ADDR16_R5_P4+24
+ mpu_verify_data DATA16_3, MEM_ADDR16_R5_P7+24
+ ; first exception because of writing in region 5
+ mpu_set_except_params mpu_ecr = MPU_ECR_W_R5 , \
+ ecr = PROTV_WRITE_MPU , \
+ efa = MEM_ADDR16_R5_P4+24 , \
+ eret = @test_16_illegal_store, \
+ continue = @test_16_cont
+test_16_illegal_store:
+ st r7, [MEM_ADDR16_R5_P4+24] ; this shouldn't be allowed
+ b @fail ; an exception must have been raised
+test_16_cont:
+ mpu_write_data DATA16_2, MEM_ADDR16_R3_P5+24 ;will be checked later
+ ; second exception while reading in region 3
+ mpu_set_except_params mpu_ecr = MPU_ECR_R_R3 , \
+ ecr = PROTV_READ_MPU , \
+ efa = MEM_ADDR16_R3_P6+24 , \
+ eret = @test_16_illegal_read, \
+ continue = @test_16_end
+test_16_illegal_read:
+ ld r7, [MEM_ADDR16_R3_P6+24] ; this shouldn't be allowed
+ b @fail ; an exception must have been raised
+test_16_end:
+ mpu_disable
+ mpu_verify_data DATA16_2, MEM_ADDR16_R3_P5+24 ; check if written
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Reporting ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+valhalla:
+ print "[PASS]"
+ b @1f
+
+; If a test fails, it jumps here. Although, for the sake of uniformity,
+; the printed output does not say much about which test case failed,
+; one can uncomment the print_number line below or set a breakpoint
+; here to check the R0 register for the test case number.
+fail:
+ ld r0, [test_nr]
+ print "[FAIL"
+ print ":"
+ print_number r0
+ print "]"
+1:
+ print " MPUv3: Memory protection unit v3.\n"
+ end
diff --git a/tests/tcg/arc/check_mpyd.S b/tests/tcg/arc/check_mpyd.S
new file mode 100644
index 0000000000..1e94431d21
--- /dev/null
+++ b/tests/tcg/arc/check_mpyd.S
@@ -0,0 +1,543 @@
+; check_mpyd.S
+;
+; Tests for mpyd: mpyd mpydu
+; If the test fails, check the end of this file for how to troubleshoot.
+
+ .include "macros.inc"
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;; Test checking routines ;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Test case counter
+.data
+test_nr:
+ .word 0x0
+
+; Increment the test counter and set (Z,N,C,V) to (0,0,0,0).
+.macro prep_test_case
+ ld r13, [test_nr]
+ add_s r13, r13, 1 ; increase test case counter
+ st r13, [test_nr]
+ add.f 0, 0, 1 ; (Z, N, C, V) = (0, 0, 0, 0)
+.endm
+
+; These flag checking macros do not directly load the
+; status32 register. Instead, they rely on the value
+; provided by the caller. The rationale is with all these
+; "cmp"s status32 will change. One must use a recorded
+; version of status32 at the right time and then try the
+; macros.
+.macro check_Z_is_clear status
+ mov r11, \status
+ mov r12, REG_STAT_Z
+ and r11, r11, r12
+ cmp r11, 0
+ bne @fail
+.endm
+.macro check_N_is_set status
+ mov r11, \status
+ mov r12, REG_STAT_N
+ and r11, r11, r12
+ cmp r11, REG_STAT_N
+ bne @fail
+.endm
+.macro check_N_is_clear status
+ mov r11, \status
+ mov r12, REG_STAT_N
+ and r11, r11, r12
+ cmp r11, 0
+ bne @fail
+.endm
+.macro check_V_is_set status
+ mov r11, \status
+ mov r12, REG_STAT_V
+ and r11, r11, r12
+ cmp r11, REG_STAT_V
+ bne @fail
+.endm
+.macro check_V_is_clear status
+ mov r11, \status
+ mov r12, REG_STAT_V
+ and r11, r11, r12
+ cmp r11, 0
+ bne @fail
+.endm
+
+; pair(HI, LOW) == pair(REG_HI, REG_LO) == pair(R59, R58)
+.macro check_64bit_result hi, low, reg_hi, reg_lo
+ mov r11, \hi
+ mov r10, \low
+ cmp r11, \reg_hi
+ bne @fail
+ cmp r11, r59
+ bne @fail
+ cmp r10, \reg_lo
+ bne @fail
+ cmp r10, r58
+ bne @fail
+.endm
+
+; (Z, N, C, V) = (0, 0, 0, 1)
+.macro clear_N_set_V
+ mov r11, 0x80000000 ; very small negative number
+ add.f 0, r11, r11 ; cause an overflow (with carry)
+ rol.f 0, 0x01 ; keep the V flag, set the rests to 0
+.endm
+
+; (Z, N, C, V) = (0, 1, 0, 1)
+.macro set_N_set_V
+ add.f 0, 0x7fffffff, 1 ; negative result with an overflow
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;; Exception related code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; parameters that an IllegalInstruction exception may set.
+ .align 4
+ecr_ref : .word ILLEGAL_INSTRUCTION
+addr_ref : .word 0x0 ; for both eret and efa
+cont_addr: .word 0x0
+
+; exception: IllegalInstruction
+; regs used: r11, r12
+;
+; A parameterized IllegalInstruction exception that checks the followings:
+; ecr == Illegal instruction
+; efa == efa_ref
+; eret == eret_ref
+; If everything passes, it will jump to 'cont_addr' parameter. The parameters
+; must be set beforehand using 'set_except_params' macro. This requires
+; ivt.S file to be compiled and linked.
+ .align 4
+ .global instruction_error
+ .type instruction_error, @function
+instruction_error:
+ ld r11, [ecr_ref]
+ lr r12, [ecr]
+ cmp r12, r11
+ bne @fail
+ ld r11, [addr_ref]
+ lr r12, [eret]
+ cmp r12, r11
+ bne @fail
+ lr r12, [efa]
+ cmp r12, r11
+ bne @fail
+ ; Success: continuing
+ ld r11, [cont_addr]
+ sr r11, [eret]
+ rtie
+
+; macro: set_except_params
+; regs used: r11
+;
+; This macro writes the provided parameters to a temporary place holder
+; that later will be used by exception above to verify as reference.
+.macro set_except_params addr, continue
+ mov r11, \addr
+ st r11, [addr_ref]
+ mov r11, \continue
+ st r11, [cont_addr]
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MPYD ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Let the tests begin
+ start
+
+; Test case 1
+; reg4 <- reg4, reg4
+; 1 = (-1)*(-1)
+ prep_test_case
+ mov r4, -1
+ mpyd r4, r4, r4
+ check_64bit_result 0x0, 0x1, r5, r4
+
+; Test case 2
+; reg0 <- reg1, reg0
+; 0 = 0 * 0x22334455
+ prep_test_case
+ mov r0, 0x22334455 ; bogus data
+ mov r1, 0
+ set_N_set_V ; (Z,N,C,V)=(0,1,0,1)
+ mpyd.f r0, r1, r0
+ lr r5, [status32] ; take a snapshot of statu32 as is
+ check_Z_is_clear r5
+ check_N_is_clear r5
+ check_V_is_clear r5
+ check_64bit_result 0x0, 0x0, r1, r0
+
+; Test case 3
+; reg2 <- reg3, limm
+; 0xc0000000_80000000 = 0x7ffffffff*0x80000000
+; -4611686016279904256= 2147483647 * -2147483648
+ prep_test_case
+ mov r3, 0x7fffffff ; biggest 32-bit positive number
+ clear_N_set_V ; (Z,N,C,V)=(0,0,0,1)
+ mpyd.f r2, r3, 0x80000000 ; smallest 32-bit negative number
+ lr r5, [status32] ; take a snapshot of statu32 as is
+ check_N_is_set r5
+ check_V_is_clear r5
+ check_64bit_result 0xc0000000, 0x80000000, r3, r2
+
+; Test case 4
+; reg2 <- limm, reg3
+; 0xffffffff_87654321 = 0x87654321 * 1
+; This is like a sign extension
+ prep_test_case
+ mov r3, 1
+ clear_N_set_V ; (Z,N,C,V)=(0,0,0,1)
+ mpyd.f r2, 0x87654321, r3
+ lr r5, [status32] ; take a snapshot of statu32 as is
+ check_N_is_set r5
+ check_V_is_clear r5
+ check_64bit_result 0xffffffff, 0x87654321, r3, r2
+
+; Test case 5
+; reg0 <- limm, limm
+; 0x3fffffff_00000001 = 0x7fffffff*0x7fffffff
+; 4611686014132420609 = 2147483647*2147483647
+ prep_test_case
+ set_N_set_V ; (Z,N,C,V)=(0,1,0,1)
+ mpyd r0, 0x7fffffff, 0x7fffffff
+ lr r5, [status32] ; take a snapshot of statu32 as is
+ check_N_is_set r5
+ check_V_is_set r5
+ check_64bit_result 0x3fffffff, 0x00000001, r1, r0
+
+; Test case 6
+; 0 <- limm, limm only (acch,accl) will be set.
+; It is expected that V=0 and N=0
+; 4761 = 69 * 69
+ prep_test_case
+ set_N_set_V ; (Z,N,C,V)=(0,1,0,1)
+ mpyd.f 0, 69, 69
+ lr r5, [status32] ; take a snapshot of statu32 as is
+ check_N_is_clear r5
+ check_V_is_clear r5
+ check_64bit_result 0, 4761, r59, r58
+
+; Test case 7
+; 0 <- limm, u6 only (acch,accl) will be set.
+; Checking that a result of 0 does not set the Z flag.
+; 0 = 0x12345678 * 0
+ prep_test_case
+ set_N_set_V ; (Z,N,C,V)=(0,1,0,1)
+ mpyd.f 0, 0x12345678, 0
+ lr r5, [status32] ; take a snapshot of statu32 as is
+ check_Z_is_clear r5 ; Z must have remained 0
+ check_N_is_clear r5
+ check_V_is_clear r5
+ check_64bit_result 0, 0, r59, r58
+
+; Test case 8
+; 0 <- reg2, limm (V is already 1)
+; Nothing should change, other than (acch,accl).
+; 0x2468a = 2 * 0x12345
+ prep_test_case
+ mov r2, 2
+ clear_N_set_V ; (Z,N,C,V)=(0,0,0,1)
+ mpyd 0, r2, 0x12345
+ lr r5, [status32] ; take a snapshot of statu32 as is
+ check_V_is_set r5
+ check_64bit_result 0, 0x2468a, r59, r58
+
+; Test case 9
+; reg0 <- reg2, u6
+; -63 = -1 * 63
+ prep_test_case
+ mov r2, -1
+ mpyd r0, r2, 63
+ check_64bit_result 0xffffffff, 0xffffffc1, r1, r0
+
+; Test case 10
+; reg2 <- limm, u6
+; 0x2_7d27d268 = 0x12345678 * 35
+ prep_test_case
+ mpyd r2, 0x12345678, 35
+ check_64bit_result 0x00000002, 0x7d27d268, r3, r2
+
+; Test case 11
+; reg4 <- reg4, s12
+; 0x0000002f_1c71c71c = 0x87654321 * 0xf9c
+; 202340681500 = -2023406815 * -100
+ prep_test_case
+ mov r4, 0x87654321
+ mpyd r4, r4, -100
+ check_64bit_result 0x0000002f, 0x1c71c71c, r5, r4
+
+; Test case 12
+; 0 <- limm, s12
+; It is expected that V is cleared and N=1
+; -1250000 = -10000 * 125
+ prep_test_case
+ clear_N_set_V ; (Z,N,C,V)=(0,0,0,1)
+ mpyd.f 0, -10000 , 125
+ lr r5, [status32] ; take a snapshot of statu32 as is
+ check_N_is_set r5
+ check_V_is_clear r5
+ check_64bit_result -1, -1250000, r59, r58
+
+; Test case 13
+; Testing when cc condition is met
+; 0 <- limm, u6 (V is already set)
+; It is expected that V is cleared and N=1
+; -126 = -2 * 63
+ prep_test_case
+ clear_N_set_V ; (Z,N,C,V)=(0,0,0,1)
+ mpyd.v.f 0, -2, 63
+ lr r5, [status32] ; take a snapshot of statu32 as is
+ check_N_is_set r5
+ check_V_is_clear r5
+ check_64bit_result -1, -126, r59, r58
+
+; Test case 14
+; Testing when cc condition is not met
+; reg0 <- reg0, reg2 (V is already set)
+; It is expected that V is remanins set
+ prep_test_case
+ clear_N_set_V ; (Z,N,C,V)=(0,0,0,1)
+ mov r0, 0xc0de ; must remain ...
+ mov r1, 0x1337 ; ... (0x1337,0xc0de)
+ mov r2, 0xf00d ; don't care ...
+ mov r3, 0xbad ; as long as not (0x0,0x1)
+ mov r4, r58 ; record accl
+ mov r5, r59 ; record acch
+ mpyd.nv.f r0, r0, r2
+ lr r2, [status32] ; take a snapshot of statu32 as is
+ check_V_is_set r2
+ cmp r1, 0x1337
+ bne @fail
+ cmp r0, 0xc0de
+ bne @fail
+ check_64bit_result r5, r4, r59, r58
+
+; Test case 15
+; Raise an Illegal Instruction exception if an odd register as dest.
+ prep_test_case
+ set_except_params @test_15_exception, @test_15_end
+test_15_exception:
+ mpyd r3, r2, r4
+ b @fail
+test_15_end:
+ ; Fall through
+
+; Test case 16
+; Raise an Illegal Instruction exception if an odd register as dest.
+; The exception should be made even if the CC indicates no execution.
+ prep_test_case
+ set_except_params @test_16_exception, @test_16_end
+ add.f 0,0,1 ; (Z,N,C,V)=(0,0,0,0)
+test_16_exception:
+ mpyd.z r1, r1, r4
+ b @fail
+test_16_end:
+ ; Fall through
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MPYDU ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Test case 17
+; reg2 <- reg2, reg2
+; 1 = (-1)*(-1)
+; 0xfffffffe_00000001 = 0xffffffff * 0xffffffff
+ prep_test_case
+ mov r2, -1
+ mpydu r2, r2, r2
+ check_64bit_result 0xfffffffe, 0x00000001, r3, r2
+
+; Test case 18
+; reg2 <- reg3, reg2
+; 0 = 0 * 0x22334455
+ prep_test_case
+ mov r2, 0x22334455 ; bogus data
+ mov r3, 0
+ set_N_set_V ; (Z,N,C,V)=(0,1,0,1)
+ mpydu.f r2, r3, r2
+ lr r5, [status32] ; take a snapshot of statu32 as is
+ check_Z_is_clear r5
+ check_N_is_set r5
+ check_V_is_clear r5
+ check_64bit_result 0x0, 0x0, r3, r2
+
+; Test case 19
+; reg2 <- reg3, limm
+; 0x3fffffff_80000000 = 0x7ffffffff*0x80000000
+; 4611686016279904256 = 2147483647 * 2147483648
+ prep_test_case
+ mov r3, 0x7fffffff ; what used to be the largest 32-bit number
+ clear_N_set_V ; (Z,N,C,V)=(0,0,0,1)
+ mpydu.f r2, r3, 0x80000000 ; just another positive number
+ lr r5, [status32] ; take a snapshot of statu32 as is
+ check_V_is_clear r5
+ check_64bit_result 0x3fffffff, 0x80000000, r3, r2
+
+; Test case 20
+; reg4 <- limm, reg5
+; 0x00000000_87654321 = 0x87654321 * 1
+; This is like an unsigned extension
+ prep_test_case
+ mov r5, 1
+ set_N_set_V ; (Z,N,C,V)=(0,1,0,1)
+ mpydu.f r4, 0x87654321, r5
+ lr r3, [status32] ; take a snapshot of statu32 as is
+ check_N_is_set r3
+ check_V_is_clear r3
+ check_64bit_result 0x00000000, 0x87654321, r5, r4
+
+; Test case 21
+; reg0 <- limm, limm
+; 0x40000000_00000000 = 0x80000000*0x80000000
+; 4611686018427387904 = 2147483648*2147483648
+ prep_test_case
+ set_N_set_V ; (Z,N,C,V)=(0,1,0,1)
+ mpydu r0, 0x80000000, 0x80000000
+ lr r5, [status32] ; take a snapshot of statu32 as is
+ check_N_is_set r5
+ check_V_is_set r5
+ check_64bit_result 0x40000000, 0x00000000, r1, r0
+
+; Test case 22
+; 0 <- limm, limm only (acch,accl) will be set.
+; It is expected that V=0 and N=0
+; 3876961 = 1969 * 1969
+ prep_test_case
+ set_N_set_V ; (Z,N,C,V)=(0,1,0,1)
+ mpydu.f 0, 1969, 1969
+ lr r5, [status32] ; take a snapshot of statu32 as is
+ check_N_is_set r5
+ check_V_is_clear r5
+ check_64bit_result 0, 3876961, r59, r58
+
+; Test case 23
+; 0 <- limm, u6 only (acch,accl) will be set.
+; Checking that a result of 0 does not set the Z flag.
+; 0 = 0x12345678 * 0
+ prep_test_case
+ set_N_set_V ; (Z,N,C,V)=(0,1,0,1)
+ mpydu.f 0, 0x12345678, 0
+ lr r5, [status32] ; take a snapshot of statu32 as is
+ check_Z_is_clear r5 ; Z must have remained 0
+ check_N_is_set r5
+ check_V_is_clear r5
+ check_64bit_result 0, 0, r59, r58
+
+; Test case 24
+; 0 <- reg2, limm (V is already 1)
+; Nothing should change, other than (acch,accl).
+; 0x00001eac_0d5d17a4 = 0x1af54154 * 0x12345
+; 33724307412900 = 452280660 * 74565
+ prep_test_case
+ mov r2, 0x1af54154 ; I let an ant walk on the keyboard
+ clear_N_set_V ; (Z,N,C,V)=(0,0,0,1)
+ mpydu 0, r2, 0x12345
+ lr r5, [status32] ; take a snapshot of statu32 as is
+ check_V_is_set r5
+ check_64bit_result 0x1eac, 0x0d5d17a4, r59, r58
+
+; Test case 25
+; reg0 <- reg2, u6
+; 0x3e_ffffffc1 = 0xffffffff * 0x3f
+; 270582939585 = 4294967295 * 63
+ prep_test_case
+ mov r2, -1
+ mpydu r0, r2, 63
+ check_64bit_result 0x3e, 0xffffffc1, r1, r0
+
+; Test case 26
+; reg4 <- limm, u6
+; 0x2_7d27d268 = 0x12345678 * 35
+ prep_test_case
+ mpydu r4, 0x12345678, 35
+ check_64bit_result 0x00000002, 0x7d27d268, r5, r4
+
+; Test case 27
+; reg2 <- reg2, s12
+; 0x000003e3_8e36b328 = 0xfedcba09 * 0x3e8
+; 4275878409000 = 4275878409 * 1000
+ prep_test_case
+ mov r2, 0xfedcba09
+ mpydu r2, r2, 1000
+ check_64bit_result 0x000003e3, 0x8e36b328, r3, r2
+
+; Test case 28
+; 0 <- limm, s12
+; It is expected that V is cleared
+; 1250000 = 10000 * 125
+ prep_test_case
+ clear_N_set_V ; (Z,N,C,V)=(0,0,0,1)
+ mpydu.f 0, 10000 , 125
+ lr r5, [status32] ; take a snapshot of statu32 as is
+ check_V_is_clear r5
+ check_64bit_result 0, 1250000, r59, r58
+
+; Test case 29
+; Testing when cc condition is met
+; 0 <- limm, u6 (V is already set)
+; It is expected that V is cleared and N=1
+; 1781818164 = 28282828 * 63
+ prep_test_case
+ set_N_set_V ; (Z,N,C,V)=(0,1,0,1)
+ mpydu.n.f 0, 28282828, 63
+ lr r5, [status32] ; take a snapshot of statu32 as is
+ check_N_is_set r5
+ check_V_is_clear r5
+ check_64bit_result 0, 1781818164, r59, r58
+
+; Test case 30
+; Testing when cc condition is not met
+; reg0 <- reg0, reg2 (V is already set)
+; It is expected that V is remanins set
+ prep_test_case
+ set_N_set_V ; (Z,N,C,V)=(0,1,0,1)
+ mov r0, 0xc0de ; must remain ...
+ mov r1, 0x1337 ; ... (0x1337,0xc0de)
+ mov r2, 0xf00d ; don't care ...
+ mov r3, 0xbad ; as long as not (0x0,0x1)
+ mov r4, r58 ; record accl
+ mov r5, r59 ; record acch
+ mpyd.p.f r0, r0, r2 ; execute only if positive (N==0)
+ lr r2, [status32] ; take a snapshot of statu32 as is
+ check_V_is_set r2
+ cmp r1, 0x1337
+ bne @fail
+ cmp r0, 0xc0de
+ bne @fail
+ check_64bit_result r5, r4, r59, r58
+
+; Test case 31
+; Raise an Illegal Instruction exception if an odd register as dest.
+ prep_test_case
+ set_except_params @test_31_exception, @test_31_end
+test_31_exception:
+ mpydu r1, r4, r0
+ b @fail
+test_31_end:
+ ; Fall through
+
+; Test case 32
+; Raise an Illegal Instruction exception if an odd register as dest.
+; The exception should be made even if the CC indicates no execution.
+ prep_test_case
+ set_except_params @test_32_exception, @test_32_end
+ add.f 0,0,1 ; (Z,N,C,V)=(0,0,0,0)
+test_32_exception:
+ mpydu.v r5, r5, r4
+ b @fail
+test_32_end:
+ ; Fall through
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Reporting ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+valhalla:
+ print "[PASS]"
+ b @1f
+
+; If a test fails, it jumps here. Although, for the sake of uniformity,
+; the printed output does not say much about which test case failed,
+; one can uncomment the print_number line below or set a breakpoint
+; here to check the R0 register for the test case number.
+fail:
+ ld r0, [test_nr]
+ print_number r0
+ print "[FAIL]"
+1:
+ print " mpyd: mpyd mpydu\n"
+ end
diff --git a/tests/tcg/arc/check_mpyw.S b/tests/tcg/arc/check_mpyw.S
new file mode 100644
index 0000000000..091ee98975
--- /dev/null
+++ b/tests/tcg/arc/check_mpyw.S
@@ -0,0 +1,41 @@
+.include "macros.inc"
+
+
+.macro mul_test val1, val2, res, test_num
+ mov r0, \val1
+ mov r1, \val2
+ mpyw r2, r0, r1
+ assert_eq \res, r2, \test_num
+.endm
+
+
+.macro mul_flags_test val1, val2, res, z=0, n=0, v=0, test_num
+ mov r0, \val1
+ mov r1, \val2
+ mpyw.f r2, r0, r1
+ assert_eq \res, r2, \test_num
+ assert_flag REG_STAT_Z, \z, \test_num
+ assert_flag REG_STAT_N, \n, \test_num
+ assert_flag REG_STAT_C, 0, \test_num
+ assert_flag REG_STAT_V, \v, \test_num
+.endm
+
+start
+
+; 21 * 2 = 42
+mul_test 21, 2, 42, test_num=1
+
+; make sure only the lower 16 bits are taken into account
+; 0x11220005 * 0x00120020 --> 0x0005 * 0x0020 = 160
+mul_test 0x11220005, 0x00120020, 160, test_num=2
+
+; testing sign extension and the signed result
+; 0xFFFFFFFF * 0x00000007 --> 0xFFFF (-1) * 0x0007 = 0xFFFFFFF9 (-7)
+mul_test 0xFFFFFFFF, 0x00000007, 0xFFFFFFF9, test_num=3
+
+; testing flags
+mul_flags_test 1337 , 0 , res=0 , z=1, test_num=4
+mul_flags_test 0x7FFF, 0x7FFF, res=0x3FFF0001, v=0, test_num=5
+mul_flags_test 0xFFFF, 0x0C , res=0xFFFFFFF4, n=1, test_num=6
+
+end
diff --git a/tests/tcg/arc/check_norm.S b/tests/tcg/arc/check_norm.S
new file mode 100644
index 0000000000..4e55b71589
--- /dev/null
+++ b/tests/tcg/arc/check_norm.S
@@ -0,0 +1,40 @@
+.include "macros.inc"
+
+ start
+
+ test_name NORM_1
+ norm r2, 0x0
+ check_r2 0x1f
+
+ test_name NORM_2
+ norm r2, 0x1
+ check_r2 0x1e
+
+ test_name NORM_3
+ norm r2, 0x1fffffff
+ check_r2 0x02
+
+ test_name NORM_4
+ norm r2, 0x3fffffff
+ check_r2 0x01
+
+ test_name NORM_5
+ norm r2, 0x7fffffff
+ check_r2 0x00
+
+ test_name NORM_6
+ norm r2, 0x80000000
+ check_r2 0x00
+
+ test_name NORM_8
+ norm r2, 0xc0000000
+ check_r2 0x01
+
+ test_name NORM_9
+ norm r2, 0xe0000000
+ check_r2 0x02
+
+ test_name NORM_10
+ norm r2, 0xffffffff
+ check_r2 0x1f
+ end
diff --git a/tests/tcg/arc/check_orx.S b/tests/tcg/arc/check_orx.S
new file mode 100644
index 0000000000..c7a96b4edb
--- /dev/null
+++ b/tests/tcg/arc/check_orx.S
@@ -0,0 +1,34 @@
+#define ARCTEST_ARC32
+
+#*****************************************************************************
+# or.S
+#-----------------------------------------------------------------------------
+#
+# Test or instruction.
+#
+
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+
+ #-------------------------------------------------------------
+ # Logical tests
+ #-------------------------------------------------------------
+ TEST_IMM_OP( 2, or, 0xffffffffffffff0f, 0xffffffffff00ff00, 0xf0f );
+ TEST_IMM_OP( 3, or, 0x000000000ff00ff0, 0x000000000ff00ff0, 0x0f0 );
+ TEST_IMM_OP( 4, or, 0x0000000000ff07ff, 0x0000000000ff00ff, 0x70f );
+ TEST_IMM_OP( 5, or, 0xfffffffff00ff0ff, 0xfffffffff00ff00f, 0x0f0 );
+ TEST_RR_3OP( 6, or, 0xff0fff0f, 0xff00ff00, 0x0f0f0f0f );
+ TEST_RR_3OP( 7, or, 0xfff0fff0, 0x0ff00ff0, 0xf0f0f0f0 );
+ TEST_RR_3OP( 8, or, 0x0fff0fff, 0x00ff00ff, 0x0f0f0f0f );
+ TEST_RR_3OP( 9, or, 0xf0fff0ff, 0xf00ff00f, 0xf0f0f0f0 );
+
+ #-------------------------------------------------------------
+ # Source/Destination tests
+ #-------------------------------------------------------------
+
+ TEST_IMM_SRC1_EQ_DEST( 10, or, 0xff00fff0, 0xff00ff00, 0x0f0 );
+ TEST_RR_SRC1_EQ_DEST( 11, or, 0xff0fff0f, 0xff00ff00, 0x0f0f0f0f );
+ TEST_RR_SRC2_EQ_DEST( 12, or, 0xff0fff0f, 0xff00ff00, 0x0f0f0f0f );
+ TEST_RR_SRC12_EQ_DEST( 13, or, 0xff00ff00, 0xff00ff00 );
+ARCTEST_END
diff --git a/tests/tcg/arc/check_prefetch.S b/tests/tcg/arc/check_prefetch.S
new file mode 100644
index 0000000000..3eb9900de0
--- /dev/null
+++ b/tests/tcg/arc/check_prefetch.S
@@ -0,0 +1,37 @@
+#*****************************************************************************
+# prefetch
+#-----------------------------------------------------------------------------
+#
+# This test verifies that prefetch works as expected
+#
+
+#define ARCTEST_ARC32
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+
+ # testing the decoding
+ TEST_CASE( 2, r0, 0x00000000, "prefetch:2", prefetch [0x12]` mov r0, 0x0)
+ TEST_CASE( 3, r0, 0x00000000, "prefetch:3", prefetchw [0x12]` mov r0, 0x0)
+ TEST_CASE( 4, r0, 0x00000000, "prefetch:4", prefetchw [r1, r2]` mov r0, 0x0)
+ TEST_CASE( 5, r0, 0x00000000, "prefetch:5", prefetchw [0x12, 0x1]` mov r0, 0x0)
+ TEST_CASE( 6, r0, 0x00000000, "prefetch:6", prefetch [r1, r2]` mov r0, 0x0)
+ TEST_CASE( 7, r0, 0x00000000, "prefetch:7", prefetch [0x12, 0x1]` mov r0, 0x0)
+
+ mov r13, @tdat
+ TEST_CASE( 8, r0, 0x00000004, "prefetch:8", prefetch [r13]` ld r0,[r13])
+ TEST_CASE( 9, r0, 0x40000000, "prefetch:9", prefetch.aw [r13,4]` ld r0,[r13])
+ TEST_CASE(10, r0, 0x40400000, "prefetch:10", prefetch.ab [r13,4]` ld r0,[r13])
+
+ARCTEST_END
+# TEST_DATA
+
+tdat:
+.word 0x00000004
+.word 0x40000000
+.word 0x40400000
+.word 0xc0800000
+.word 0xdeadbeef
+.word 0xcafebabe
+.word 0xabad1dea
+.word 0x1337d00d
diff --git a/tests/tcg/arc/check_rolx.S b/tests/tcg/arc/check_rolx.S
new file mode 100644
index 0000000000..4f2d939f69
--- /dev/null
+++ b/tests/tcg/arc/check_rolx.S
@@ -0,0 +1,47 @@
+#define ARCTEST_ARC32
+
+#*****************************************************************************
+# check_rolx.S
+#-----------------------------------------------------------------------------
+#
+# Test or instruction.
+#
+# .-------------.----------.--------------.
+# | instruction | check CC | update flags |
+# |-------------+----------+--------------|
+# | rol | no | Z, N, C |
+# | rol8 | no | Z, N |
+# `-------------^----------^--------------'
+
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+
+ #-------------------------------------------------------------
+ # Logical tests
+ #-------------------------------------------------------------
+ TEST_RR_2OP(2, rol , 0xbd5b7ddf, 0xdeadbeef);
+ TEST_RR_2OP(3, rol8, 0x00000001, 0x01000000);
+
+ #-------------------------------------------------------------
+ # Source/Destination tests
+ #-------------------------------------------------------------
+ TEST_RR_2OP_SRC1_EQ_DEST(4, rol, 0x94001009, 0xca000804);
+
+ #-------------------------------------------------------------
+ # Flag tests
+ #-------------------------------------------------------------
+ TEST_1OP_CARRY ( 5, rol , 0, 0x40000000);
+ TEST_1OP_CARRY ( 6, rol , 1, 0x80000000);
+ TEST_1OP_ZERO ( 8, rol , 0, 0x00001000);
+ TEST_1OP_ZERO ( 9, rol , 1, 0x00000000);
+ TEST_1OP_NEGATIVE(10, rol , 0, 0x80000000);
+ TEST_1OP_NEGATIVE(11, rol , 1, 0x40000000);
+ #rol8 does not update carry
+ TEST_1OP_CARRY (12, rol8, 0, 0x000000ff);
+ TEST_1OP_ZERO (13, rol8, 0, 0x00001000);
+ TEST_1OP_ZERO (14, rol8, 1, 0x00000000);
+ TEST_1OP_NEGATIVE(15, rol8, 0, 0x00000040);
+ TEST_1OP_NEGATIVE(16, rol8, 1, 0x00800000);
+
+ARCTEST_END
diff --git a/tests/tcg/arc/check_rorx.S b/tests/tcg/arc/check_rorx.S
new file mode 100644
index 0000000000..2634e4e4a5
--- /dev/null
+++ b/tests/tcg/arc/check_rorx.S
@@ -0,0 +1,64 @@
+#define ARCTEST_ARC32
+
+#*****************************************************************************
+# check_rorx.S
+#-----------------------------------------------------------------------------
+#
+# Test or instruction.
+#
+# .--------------.----------.--------------.
+# | instruction | check CC | update flags |
+# |--------------+----------+--------------|
+# | ror | no | Z, N, C |
+# | ror multiple | yes | Z, N, C |
+# | ror8 | no | Z, N |
+# `--------------^----------^--------------'
+
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+
+ #-------------------------------------------------------------
+ # Logical tests
+ #-------------------------------------------------------------
+ TEST_RR_3OP( 2, ror , 0xdeadbeef, 0xdeadbeef, 0x00000000);
+ TEST_RR_3OP( 3, ror , 0x00000001, 0x00000001, 0x00000000);
+ TEST_RR_3OP( 4, ror , 0x80000000, 0x80000000, 0x00000000);
+ TEST_RR_3OP( 5, ror , 0xbd5b7ddf, 0xdeadbeef, 0x0000001f);
+ TEST_RR_3OP( 6, ror , 0x00000002, 0x00000001, 0x0000001f);
+ TEST_RR_3OP( 7, ror , 0x00000001, 0x80000000, 0x0000001f);
+ TEST_RR_2OP( 8, ror , 0x80000000, 0x00000001);
+ TEST_RR_2OP( 9, ror , 0xdeadbeef, 0xbd5b7ddf);
+ TEST_RR_2OP(10, ror8, 0x01000000, 0x00000001);
+
+ #-------------------------------------------------------------
+ # Source/Destination tests
+ #-------------------------------------------------------------
+ TEST_RR_SRC1_EQ_DEST (11, ror, 0xca000804, 0x000804ca, 0xfff80008);
+ TEST_RR_2OP_SRC1_EQ_DEST(12, ror, 0x80040265, 0x000804cb);
+
+ #-------------------------------------------------------------
+ # Flag tests
+ #-------------------------------------------------------------
+ TEST_2OP_CARRY (13, ror , 0, 0x00000001, 0x02);
+ TEST_2OP_CARRY (14, ror , 1, 0x00000001, 0x01);
+ TEST_2OP_ZERO (15, ror , 0, 0x00000100, 0xbf);
+ TEST_2OP_ZERO (16, ror , 1, 0x00000000, 0xbf);
+ TEST_2OP_NEGATIVE(17, ror , 0, 0x00000001, 0x02);
+ TEST_2OP_NEGATIVE(18, ror , 1, 0x80000000, 0x00);
+ TEST_2OP_CARRY (19, ror , 1, 0x000000ff, 0x08);
+ TEST_1OP_CARRY (20, ror , 0, 0x00000002);
+ TEST_1OP_CARRY (21, ror , 1, 0x00000001);
+ TEST_1OP_ZERO (22, ror , 0, 0x00000100);
+ TEST_1OP_ZERO (23, ror , 1, 0x00000000);
+ TEST_1OP_NEGATIVE(24, ror , 0, 0x80000000);
+ TEST_1OP_NEGATIVE(25, ror , 1, 0x00000001);
+ TEST_1OP_CARRY (26, ror , 1, 0x80000001);
+ #ror8 does not update carry
+ TEST_1OP_CARRY (27, ror8, 0, 0x000000ff);
+ TEST_1OP_ZERO (28, ror8, 0, 0x00001000);
+ TEST_1OP_ZERO (29, ror8, 1, 0x00000000);
+ TEST_1OP_NEGATIVE(30, ror8, 0, 0x00000040);
+ TEST_1OP_NEGATIVE(31, ror8, 1, 0x00000080);
+
+ARCTEST_END
diff --git a/tests/tcg/arc/check_rtc.S b/tests/tcg/arc/check_rtc.S
new file mode 100644
index 0000000000..cb8a6ead9f
--- /dev/null
+++ b/tests/tcg/arc/check_rtc.S
@@ -0,0 +1,29 @@
+ .include "macros.inc"
+
+;;; Simple RTC test, read RTC value if it exists, spend some time, and
+;;; re-read it. Fail if the value is the same..data
+test_nr:
+ .word 0x0
+
+ start
+ test_name RTC
+ lr r0,[timer_build]
+ and.f 0,r0,0x400
+ beq @.lfail
+ sr 1,[0x103]
+ lr r2,[0x104]
+.loop:
+ sub.f r0,r0,1
+ bnz @.loop
+ lr r0,[0x104]
+ breq r0,r2,@.lfail
+ print "[PASS] "
+ b @1f
+
+.lfail:
+ ld r0, [test_nr]
+ ;print_number r0
+ print "[FAIL] "
+1:
+ printl r30
+ end
diff --git a/tests/tcg/arc/check_rtie_user.S b/tests/tcg/arc/check_rtie_user.S
new file mode 100644
index 0000000000..b29618a6ac
--- /dev/null
+++ b/tests/tcg/arc/check_rtie_user.S
@@ -0,0 +1,30 @@
+ .include "macros.inc"
+
+ start
+ enter_user_mode @user_mode
+
+user_mode:
+ nop
+ ; must cause privilege violation exception
+faulty:
+ rtie
+
+good:
+ print "You're on a righteous path.\n"
+ end
+
+ .align 4
+ .global EV_PrivilegeV
+ .type EV_PrivilegeV, @function
+EV_PrivilegeV:
+ lr r0, [eret]
+ brne r0, @faulty, @sucks
+ lr r0, [efa]
+ brne r0, @faulty, @sucks
+ mov r0, @good
+ sr r0, [eret]
+ rtie
+
+sucks:
+ print "Life sucks. Get over it!\n"
+ end
diff --git a/tests/tcg/arc/check_stld.S b/tests/tcg/arc/check_stld.S
new file mode 100644
index 0000000000..3817678b98
--- /dev/null
+++ b/tests/tcg/arc/check_stld.S
@@ -0,0 +1,10 @@
+.include "macros.inc"
+
+ start
+
+ test_name STLD_1
+ st -32,[0x10000]
+ ld r2,[0x10000]
+ check_r2 -32
+
+ end
diff --git a/tests/tcg/arc/check_subf.S b/tests/tcg/arc/check_subf.S
new file mode 100644
index 0000000000..10b98e803b
--- /dev/null
+++ b/tests/tcg/arc/check_subf.S
@@ -0,0 +1,67 @@
+.include "macros.inc"
+
+.macro validate res, actual, z, n, c, v, test_num
+ assert_eq \res, \actual, \test_num
+ assert_flag REG_STAT_Z, \z, \test_num
+ assert_flag REG_STAT_N, \n, \test_num
+ assert_flag REG_STAT_C, \c, \test_num
+ assert_flag REG_STAT_V, \v, \test_num
+.endm
+
+.macro sub0_flags_test val1, val2, res, z=0, n=0, c=0, v=0, test_num=1
+ mov r0, \val1
+ mov r1, \val2
+ sub.f r2, r0, r1
+ validate \res, r2, \z, \n, \c, \v, \test_num
+.endm
+
+.macro sub1_flags_test val1, val2, res, z=0, n=0, c=0, v=0, test_num=1
+ mov r0, \val1
+ mov r1, \val2
+ sub1.f r2, r0, r1
+ validate \res, r2, \z, \n, \c, \v, \test_num
+.endm
+
+.macro sub2_flags_test val1, val2, res, z=0, n=0, c=0, v=0, test_num=1
+ mov r0, \val1
+ mov r1, \val2
+ sub2.f r2, r0, r1
+ validate \res, r2, \z, \n, \c, \v, \test_num
+.endm
+
+.macro sub3_flags_test val1, val2, res, z=0, n=0, c=0, v=0, test_num=1
+ mov r0, \val1
+ mov r1, \val2
+ sub3.f r2, r0, r1
+ validate \res, r2, \z, \n, \c, \v, \test_num
+.endm
+
+
+start
+
+sub0_flags_test 0xA0000000, 0xB0000000, 0xF0000000, z=0, n=1, c=1, v=0, test_num=0x01
+sub1_flags_test 0xA0000000, 0x58000000, 0xF0000000, z=0, n=1, c=1, v=0, test_num=0x02
+sub2_flags_test 0xA0000000, 0x2C000000, 0xF0000000, z=0, n=1, c=1, v=0, test_num=0x03
+sub3_flags_test 0xA0000000, 0x16000000, 0xF0000000, z=0, n=1, c=1, v=0, test_num=0x04
+
+sub0_flags_test 0xFFFFFF80, 0xF0000000, 0x0FFFFF80, z=0, n=0, c=0, v=0, test_num=0x05
+sub1_flags_test 0xFFFFFF80, 0x78000000, 0x0FFFFF80, z=0, n=0, c=0, v=0, test_num=0x06
+sub2_flags_test 0xFFFFFF80, 0x3C000000, 0x0FFFFF80, z=0, n=0, c=0, v=0, test_num=0x07
+sub3_flags_test 0xFFFFFF80, 0x1E000000, 0x0FFFFF80, z=0, n=0, c=0, v=0, test_num=0x08
+
+sub0_flags_test 0x80000000, 0x80000000, 0x00000000, z=1, n=0, c=0, v=0, test_num=0x09
+sub1_flags_test 0x80000000, 0x40000000, 0x00000000, z=1, n=0, c=0, v=0, test_num=0x10
+sub2_flags_test 0x80000000, 0x20000000, 0x00000000, z=1, n=0, c=0, v=0, test_num=0x11
+sub3_flags_test 0x80000000, 0x10000000, 0x00000000, z=1, n=0, c=0, v=0, test_num=0x12
+
+sub0_flags_test 0x80000000, 0xC0000000, 0xC0000000, z=0, n=1, c=1, v=0, test_num=0x13
+sub1_flags_test 0x80000000, 0x60000000, 0xC0000000, z=0, n=1, c=1, v=0, test_num=0x14
+sub2_flags_test 0x80000000, 0x30000000, 0xC0000000, z=0, n=1, c=1, v=0, test_num=0x15
+sub3_flags_test 0x80000000, 0x18000000, 0xC0000000, z=0, n=1, c=1, v=0, test_num=0x16
+
+sub0_flags_test 0x80000000, 0x00000008, 0x7FFFFFF8, z=0, n=0, c=0, v=1, test_num=0x17
+sub1_flags_test 0x80000000, 0x00000004, 0x7FFFFFF8, z=0, n=0, c=0, v=1, test_num=0x18
+sub2_flags_test 0x80000000, 0x00000002, 0x7FFFFFF8, z=0, n=0, c=0, v=1, test_num=0x19
+sub3_flags_test 0x80000000, 0x00000001, 0x7FFFFFF8, z=0, n=0, c=0, v=1, test_num=0x20
+
+end
diff --git a/tests/tcg/arc/check_subx.S b/tests/tcg/arc/check_subx.S
new file mode 100644
index 0000000000..7e4c4b1009
--- /dev/null
+++ b/tests/tcg/arc/check_subx.S
@@ -0,0 +1,43 @@
+#*****************************************************************************
+# sub.S
+#-----------------------------------------------------------------------------
+#
+# Test sub instruction.
+#
+
+#define ARCTEST_ARC32
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+
+ #-------------------------------------------------------------
+ # Arithmetic tests
+ #-------------------------------------------------------------
+
+ TEST_RR_3OP( 2, sub, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 );
+ TEST_RR_3OP( 3, sub, 0x0000000000000000, 0x0000000000000001, 0x0000000000000001 );
+ TEST_RR_3OP( 4, sub, 0xfffffffffffffffc, 0x0000000000000003, 0x0000000000000007 );
+
+ TEST_RR_3OP( 5, sub, 0x0000000000008000, 0x0000000000000000, 0xffffffffffff8000 );
+ TEST_RR_3OP( 6, sub, 0xffffffff80000000, 0xffffffff80000000, 0x0000000000000000 );
+ TEST_RR_3OP( 7, sub, 0xffffffff80008000, 0xffffffff80000000, 0xffffffffffff8000 );
+
+ TEST_RR_3OP( 8, sub, 0xffffffffffff8001, 0x0000000000000000, 0x0000000000007fff );
+ TEST_RR_3OP( 9, sub, 0x000000007fffffff, 0x000000007fffffff, 0x0000000000000000 );
+ TEST_RR_3OP( 10, sub, 0x000000007fff8000, 0x000000007fffffff, 0x0000000000007fff );
+
+ TEST_RR_3OP( 11, sub, 0xffffffff7fff8001, 0xffffffff80000000, 0x0000000000007fff );
+ TEST_RR_3OP( 12, sub, 0x0000000080007fff, 0x000000007fffffff, 0xffffffffffff8000 );
+
+ TEST_RR_3OP( 13, sub, 0x0000000000000001, 0x0000000000000000, 0xffffffffffffffff );
+ TEST_RR_3OP( 14, sub, 0xfffffffffffffffe, 0xffffffffffffffff, 0x0000000000000001 );
+ TEST_RR_3OP( 15, sub, 0x0000000000000000, 0xffffffffffffffff, 0xffffffffffffffff );
+
+ #-------------------------------------------------------------
+ # Source/Destination tests
+ #-------------------------------------------------------------
+
+ TEST_RR_SRC1_EQ_DEST( 16, sub, 2, 13, 11 );
+ TEST_RR_SRC2_EQ_DEST( 17, sub, 3, 14, 11 );
+ TEST_RR_SRC12_EQ_DEST( 18, sub, 0, 13 );
+ARCTEST_END
diff --git a/tests/tcg/arc/check_swi.S b/tests/tcg/arc/check_swi.S
new file mode 100644
index 0000000000..6786807acd
--- /dev/null
+++ b/tests/tcg/arc/check_swi.S
@@ -0,0 +1,115 @@
+ .include "macros.inc"
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; exception facilitators
+ .align 4
+ecr_ref : .word 0x0
+efa_ref : .word 0x0
+eret_ref : .word 0x0
+cont_addr : .word 0x0
+test_number: .word 0x0
+
+; macro: set_excep_params
+; regs used: r11
+;
+; this macro writes the provided parameters to a temporary place holder
+; later it will be used by SWI exception routine as a reference
+.macro set_excep_params ecr, efa, eret, continue, test_num
+ mov r11, \ecr
+ st r11, [ecr_ref]
+ mov r11, \efa
+ st r11, [efa_ref]
+ mov r11, \eret
+ st r11, [eret_ref]
+ mov r11, \continue
+ st r11, [cont_addr]
+ mov r11, \test_num
+ st r11, [test_number]
+.endm
+
+; exception: software interrupt
+; regs used: r11, r12
+;
+; this is a parameterized SWI exception that will check the followings:
+; ecr == ecr_ref
+; efa == efa_ref
+; eret == eret_ref
+; if everything passes, it will jump to 'cont_addr' parameter.
+; the parameters must be set beforehand using 'set_except_params' macro.
+; last but not least, this requires ivt.S file to be compiled and linked.
+ .align 4
+ .global EV_SWI
+ .type EV_SWI, @function
+EV_SWI:
+ ld r11, [ecr_ref]
+ lr r12, [ecr]
+ brne r12, r11, @exc_fail
+ ld r11, [eret_ref]
+ lr r12, [eret]
+ brne r12, r11, @exc_fail
+ ld r11, [efa_ref]
+ lr r12, [efa]
+ brne r12, r11, @exc_fail
+ ; going back to the given address
+ ld r11, [cont_addr]
+ sr r11, [eret]
+ rtie
+exc_fail:
+ ld r11, [test_number]
+ print "[FAIL] "
+ print_number r11
+ print ": exception is not sane!\n"
+ end
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; let the test code begin
+ start
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; check swi_s with no argument
+test01:
+ set_excep_params ecr = SOFTWARE_INTERRUPT, \
+ efa = @test01_swis_addr , \
+ eret = @test01_swis_addr , \
+ continue = @test02 , \
+ test_num = 0x01
+
+test01_swis_addr:
+ swi_s
+
+ assert_eq 0, 1, 1 ; exception must have been raised
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; check swi_s with a u6 immediate
+test02:
+ .equ INTERRUPT_NUM , 42
+ .equ TEST02_EXCP_REF, SOFTWARE_INTERRUPT | INTERRUPT_NUM
+ set_excep_params ecr = TEST02_EXCP_REF,\
+ efa = @test02_swis_addr , \
+ eret = @test02_swis_addr , \
+ continue = @test03 , \
+ test_num = 0x02
+
+test02_swis_addr:
+ swi_s INTERRUPT_NUM
+
+ assert_eq 0, 1, 2 ; exception must have been raised
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; check swi
+test03:
+ set_excep_params ecr = SOFTWARE_INTERRUPT, \
+ efa = @test03_swi_addr , \
+ eret = @test03_swi_addr , \
+ continue = @finish , \
+ test_num = 0x01
+
+test03_swi_addr:
+ swi
+
+ assert_eq 0, 1, 3 ; exception must have been raised
+
+
+finish:
+ print "[PASS] Software Interrupt\n"
+ end
diff --git a/tests/tcg/arc/check_swirq.S b/tests/tcg/arc/check_swirq.S
new file mode 100644
index 0000000000..f3fb69d1ed
--- /dev/null
+++ b/tests/tcg/arc/check_swirq.S
@@ -0,0 +1,27 @@
+ .include "macros.inc"
+
+ start
+ ;; print "Start\n"
+ mov sp, 0x1000
+ seti
+ sr 18, [aux_irq_hint]
+ print "[PASS] SW-IRQ:End\n"
+ end
+
+ /* The delay between writing to the AUX_IRQ_HINT register and
+ the interrupt being taken is implementation specific. Hence,
+ we need to save/restore any clobber register by ISR. */
+ .align 4
+ .global IRQ_18
+ .type IRQ_18, @function
+IRQ_18:
+ clri
+ push r11
+ push r12
+ sr 0, [aux_irq_hint]
+ print "[PASS] SW-IRQ:IRQ\n"
+ pop r12
+ pop r11
+ rtie
+ print "[FAIL] SW-IRQ\n"
+ end
diff --git a/tests/tcg/arc/check_swirq1.S b/tests/tcg/arc/check_swirq1.S
new file mode 100644
index 0000000000..ca8e301dd3
--- /dev/null
+++ b/tests/tcg/arc/check_swirq1.S
@@ -0,0 +1,31 @@
+ .include "macros.inc"
+
+ start
+ ;; print "Check normal IRQ functioning.\n"
+ ;; Set the stack somewhere
+ mov sp, 0x1000
+ ;; Use IRQ18 for the test, change to a level 1, irq so we can
+ ;; avoid firq.
+ sr 18,[REG_IRQ_SELECT]
+ sr 1,[irq_priority]
+ set_interrupt_prio_level 1
+ sr 16,[aux_irq_ctrl]
+ ;; Enable the interrupt system, and trigger the IRQ 18.
+ seti
+ sr 18, [aux_irq_hint]
+ print "[PASS] IRQ:End\n"
+ end
+
+ /* The delay between writing to the AUX_IRQ_HINT register and
+ the interrupt being taken is implementation specific. Hence,
+ we need to save/restore any clobber register by ISR. */
+ .align 4
+ .global IRQ_18
+ .type IRQ_18, @function
+IRQ_18:
+ clri
+ sr 0, [aux_irq_hint]
+ print "[PASS] IRQ:IRQ\n"
+ rtie
+ print "[FAIL] IRQ\n"
+ end
diff --git a/tests/tcg/arc/check_swirq3.S b/tests/tcg/arc/check_swirq3.S
new file mode 100644
index 0000000000..2aa5bb8d82
--- /dev/null
+++ b/tests/tcg/arc/check_swirq3.S
@@ -0,0 +1,49 @@
+ .include "macros.inc"
+
+ start
+;;; print "Check if an IRQ gets re-trigger while in ISR:"
+ ;; Set the stack somewhere
+ mov sp, 0x1000
+ seti
+ mov r0,0
+ ;; Use IRQ18 for the test.
+ sr 18, [AUX_IRQ_HINT]
+ ;; wait (sleep doesn't work as expected because all the irq
+ ;; are triggered BEFORE sleep is even fetch/executed.
+.llocal00:
+ breq r0, 0, @.llocal00
+ brlt r0, 2, @.failMe
+ print "[PASS] SW-IRQ3\n"
+ end
+.failMe:
+ print "[PASS] SW-IRQ3\n"
+ end
+
+ /* The delay between writing to the AUX_IRQ_HINT register and
+ the interrupt being taken is implementation specific. Hence,
+ we need to save/restore any clobber register by ISR. */
+ .align 4
+ .global IRQ_18
+ .type IRQ_18, @function
+IRQ_18:
+#define AUX_IRQ_SELECT 0x40b
+#define AUX_IRQ_ENABLE 0x40c
+ clri
+ add r0,r0,1
+ mov r1, AUX_IRQ_SELECT
+ mov r2, AUX_IRQ_ENABLE
+ ;; clean the IRQ
+ sr 18, [r1]
+ sr 0, [r2]
+ sr 0, [AUX_IRQ_HINT]
+ brgt r0,1,@.extisr
+ ;; retrigger the irq
+ sr 18, [AUX_IRQ_HINT]
+ sr 18, [r1]
+ sr 1, [r2]
+ ;; print " SW-IRQ 0,"
+ rtie
+.extisr:
+ ;; print " SW-IRQ 1,"
+ rtie
+ end
diff --git a/tests/tcg/arc/check_t01.S b/tests/tcg/arc/check_t01.S
new file mode 100644
index 0000000000..c6cb9d0052
--- /dev/null
+++ b/tests/tcg/arc/check_t01.S
@@ -0,0 +1,12 @@
+ .include "macros.inc"
+
+ start
+ test_name LOOP_1
+ mov r2, 4
+.L1:
+ sub_s r2,r2,1
+ tst_s r2,r2
+ bne @.L1
+ check_r2 0x0
+
+ end
diff --git a/tests/tcg/arc/check_t02.S b/tests/tcg/arc/check_t02.S
new file mode 100644
index 0000000000..1567bfe1d4
--- /dev/null
+++ b/tests/tcg/arc/check_t02.S
@@ -0,0 +1,9 @@
+ .include "macros.inc"
+ start
+ test_name PREDICATE_1
+ mov r2,2
+ lsr.f r2,r2
+ mov.nc r2,1
+ mov.cs r2,-1 # Should not execute
+ check_r2 0x01
+ end
diff --git a/tests/tcg/arc/check_timer0.S b/tests/tcg/arc/check_timer0.S
new file mode 100644
index 0000000000..f2afa83200
--- /dev/null
+++ b/tests/tcg/arc/check_timer0.S
@@ -0,0 +1,36 @@
+ .include "macros.inc"
+
+ start
+ test_name TIMER0
+ sr 0,[count0]
+ print "......"
+ lr r2,[count0]
+ breq r2, 0, @.lfail
+ print "X"
+ lr r0,[count0]
+ breq r0,r2,@.lfail
+ print "Pass\n"
+ sr 0x01,[control0]
+ mov r0, 0xffff
+ sr r0,[limit0]
+ sr 0,[count0]
+ mov r3, 0
+ seti
+.loop0:
+ breq r3, 0, @.loop0
+ print "The end\n"
+ end
+.lfail:
+ print "Fail\n"
+ end
+
+ .align 4
+ .global IRQ_Timer0
+ .type IRQ_Timer0, @function
+IRQ_Timer0:
+ clri
+ sr 0x00,[control0]
+ print "Pass IRQ\n"
+ mov r3, 1
+ rtie
+ end
diff --git a/tests/tcg/arc/check_timer0_loop.S b/tests/tcg/arc/check_timer0_loop.S
new file mode 100644
index 0000000000..a1910a02ae
--- /dev/null
+++ b/tests/tcg/arc/check_timer0_loop.S
@@ -0,0 +1,34 @@
+ .include "macros.inc"
+
+ start
+ test_name TIMER0
+ ;; enable TIMER0 interrupts
+ sr 0x01,[control0]
+ mov r0, 0x1fffff
+ sr r0,[limit0]
+ sr 0,[count0]
+ ;; Now wait for the counter to reach it's limit
+ mov r0,0
+.loop1:
+ lr r0,[control0]
+ bbit0 r0,3,@.loop1
+ ;; Now enable PIC interrupts, we expect the pending interrupt
+ ;; to kick in.
+ mov r3, 0
+ seti
+.loop0:
+ breq r3, 0, @.loop0
+ print "The end\n"
+ end
+
+ .align 4
+ .global IRQ_Timer0
+ .type IRQ_Timer0, @function
+IRQ_Timer0:
+ clri
+ ;; reset interrupts
+ sr 0x00,[control0]
+ print "Pass IRQ\n"
+ mov r3, 1
+ rtie
+ end
diff --git a/tests/tcg/arc/check_timer0_loop3.S b/tests/tcg/arc/check_timer0_loop3.S
new file mode 100644
index 0000000000..c5a1013db4
--- /dev/null
+++ b/tests/tcg/arc/check_timer0_loop3.S
@@ -0,0 +1,46 @@
+
+ .include "macros.inc"
+
+.equ LIMIT, 0x1ff
+
+ start
+ test_name TIMER0
+ ;; enable TIMER0 interrupts
+ sr 0x01,[control0]
+ mov r0, LIMIT
+ sr r0,[limit0]
+ sr 0,[count0]
+ ;; Now wait for the counter to reach it's limit
+ mov r0,0
+.loop1:
+ lr r0,[count0]
+ brgt r0,LIMIT,@.loop0
+ ;; Now enable PIC interrupts, we expect the pending interrupt
+ ;; to kick in.
+ mov r3, 0
+ seti
+.loop0:
+ lr r4,[count0]
+ breq r3, 1, @.pass
+ brgt r4,LIMIT,@.fail1
+ j @.loop0
+.pass:
+ print "[PASS]"
+ j @.end
+.fail1:
+ print "[FAIL]"
+ ;; print_number r4
+.end:
+ print " TIMER0: Overflow\n"
+ end
+
+ .align 4
+ .global IRQ_Timer0
+ .type IRQ_Timer0, @function
+IRQ_Timer0:
+ clri
+ ;; reset interrupts
+ sr 0x00,[control0]
+ mov r3, 1
+ rtie
+ end
diff --git a/tests/tcg/arc/check_timer0_retrig.S b/tests/tcg/arc/check_timer0_retrig.S
new file mode 100644
index 0000000000..f48e09504a
--- /dev/null
+++ b/tests/tcg/arc/check_timer0_retrig.S
@@ -0,0 +1,29 @@
+ .include "macros.inc"
+
+ start
+ test_name TIMER0_RETRIG
+ ;; enable TIMER0 interrupts
+ sr 0x01,[control0]
+ mov r0, 0x1fffff
+ sr r0,[limit0]
+ sr 0,[count0]
+ ;; Now wait for the counter to reach it's limit
+ mov r0,0
+ seti
+.loop0:
+ brlt r3, 2, @.loop0
+ print "[PASS] TIMER0: Re-trigger\n"
+ end
+
+ .align 4
+ .global IRQ_Timer0
+ .type IRQ_Timer0, @function
+IRQ_Timer0:
+ clri
+ ;; reset interrupts & enable IRQ
+ sr 0x01,[control0]
+ ;; The timer needs to continue counting, and we expect a new
+ ;; interrupt soon.
+ add r3, r3, 1
+ rtie
+ end
diff --git a/tests/tcg/arc/check_timer0_sleep.S b/tests/tcg/arc/check_timer0_sleep.S
new file mode 100644
index 0000000000..87b58fcc78
--- /dev/null
+++ b/tests/tcg/arc/check_timer0_sleep.S
@@ -0,0 +1,33 @@
+ .include "macros.inc"
+
+ start
+
+ ; enable TIMER0 interrupts
+ sr 0x01,[control0]
+ mov r0, 0x5ffff
+ sr r0,[limit0]
+ sr 0,[count0]
+ mov r3, 0
+ seti
+
+ sleep
+
+ breq r3, 1, @.passMe
+ print "[FAIL]"
+ b @.endtest
+.passMe:
+ print "[PASS]"
+.endtest:
+ print " TIMER0: sleep irq\n"
+ end
+
+ .align 4
+ .global IRQ_Timer0
+ .type IRQ_Timer0, @function
+IRQ_Timer0:
+ clri
+ ; reset interrupts
+ sr 0x00,[control0]
+ mov r3, 1
+ rtie
+ end
diff --git a/tests/tcg/arc/check_timerX_freq.S b/tests/tcg/arc/check_timerX_freq.S
new file mode 100644
index 0000000000..606c3ca82d
--- /dev/null
+++ b/tests/tcg/arc/check_timerX_freq.S
@@ -0,0 +1,87 @@
+ .include "macros.inc"
+
+ start
+ test_name TIMER0vsTIMER1
+ ;; enable TIMER0 interrupts
+ sr 0x01,[control0]
+ mov r0, 0x1ffff
+ sr r0,[limit0]
+ sr 0,[count0]
+
+ ;; enable TIMER1 interrupts
+ sr 0x01,[control1]
+ mov r0, 0x3fffe ;Twice slower
+ sr r0,[limit1]
+ sr 0,[count1]
+ mov r4,0
+ mov r5,0
+ mov sp,0x1000
+ seti
+ mov r3, 0
+.loop:
+ sleep
+ add r3,r3,1
+ brne r3,10,@.loop
+ clri
+ stb.ab 0,[sp,1]
+ mov r0,r4
+.L02:
+ rem r2,r0,10
+ add r2,r2,0x30
+ stb.ab r2,[sp,1]
+ div.f r0,r0,10
+ bne @.L02
+.L03:
+ ld.aw r2,[sp,-1]
+ breq r2,0,@.L04
+ ;; stb r2,[OUTPUT_DEVICE]
+ brne r2,0,@.L03
+.L04:
+
+ ;; print ">>>"
+ stb.ab 0,[sp,1]
+ mov r0,r5
+.L12:
+ rem r2,r0,10
+ add r2,r2,0x30
+ stb.ab r2,[sp,1]
+ div.f r0,r0,10
+ bne @.L12
+.L13:
+ ld.aw r2,[sp,-1]
+ breq r2,0,@.L14
+ ;; stb r2,[OUTPUT_DEVICE]
+ brne r2,0,@.L13
+.L14:
+ breq r5, 0, @.failMe
+ brgt r4,r5, @.passMe
+.failMe:
+ print "[FAIL] "
+ b 1f
+.passMe:
+ print "[PASS] "
+1:
+ printl r30
+ end
+
+ .align 4
+ .global IRQ_Timer0
+ .type IRQ_Timer0, @function
+IRQ_Timer0:
+ clri
+ ;; reset interrupts
+ sr 0x01,[control0]
+ sr 0,[count0]
+ add r4,r4,1
+ rtie
+
+ .global IRQ_Timer1
+ .type IRQ_Timer1, @function
+IRQ_Timer1:
+ clri
+ ;; reset interrupts
+ sr 0x01,[control1]
+ sr 0,[count1]
+ add r5,r5,1
+ rtie
+ end
diff --git a/tests/tcg/arc/check_vadd.S b/tests/tcg/arc/check_vadd.S
new file mode 100644
index 0000000000..39ceac3743
--- /dev/null
+++ b/tests/tcg/arc/check_vadd.S
@@ -0,0 +1,510 @@
+; check_vadd.S
+;
+; Tests for vadd: vadd2 vadd2h vadd4h
+; If the test fails, check the end of this file for how to troubleshoot.
+
+ .include "macros.inc"
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;; Test checking routines ;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Test case counter
+.data
+test_nr:
+ .word 0x0
+
+; Increment the test counter and set (Z,N,C,V) to (0,0,0,0).
+.macro prep_test_case
+ ld r13, [test_nr]
+ add_s r13, r13, 1 ; increase test case counter
+ st r13, [test_nr]
+ add.f 0, 0, 1 ; (Z, N, C, V) = (0, 0, 0, 0)
+.endm
+
+; Checks if (Z,N,C,V) == (0,0,0,0). This relies on "ADD.F 0,0,1"
+; instruction in PREP_TEST_CASE macro. From a PREP_TEST_CASE macro
+; in a test case, and thence to a VECTOR instruction and finally to
+; this macro, none of the aforementioned flags must have been set,
+; because VECTOR instructions aren't supposed to do so.
+.macro check_flags_remained_zero
+ lr r11, [status32]
+ mov r12, REG_STAT_Z
+ or r12, r12, REG_STAT_N
+ or r12, r12, REG_STAT_C
+ or r12, r12, REG_STAT_V
+ and r11, r11, r12
+ cmp r11, 0
+ bne @fail
+.endm
+
+; pair(HI, LOW) == pair(REG_HI, REG_LO)
+; HI, LO: 32-bit
+; REG_HI, REG_LO: 32-bit
+.macro check_64bit_double hi, low, reg_hi, reg_lo
+ check_flags_remained_zero
+ mov r11, \hi
+ mov r10, \low
+ cmp r11, \reg_hi
+ bne @fail
+ cmp r10, \reg_lo
+ bne @fail
+.endm
+
+; REG == (HI, LO)
+; HI, LO: 16-bit
+; REG: 32-bit
+.macro check_32bit_double hi, low, reg
+ check_flags_remained_zero
+ mov r11, \hi
+ and r11, r11, 0xffff
+ lsl16 r11, r11
+ mov r12, \low
+ and r12, r12, 0xffff
+ or r11, r11, r12
+ cmp r11, \reg
+ bne @fail
+.endm
+
+; quartet(q3, q2, q1, q0) == pair64(REG_HI, REG_LO)
+; Q3, Q2, Q1, Q0: 16-bit
+; REG_HI, REG_LO: 32-bit
+.macro check_64bit_quadruple q3, q2, q1, q0, reg_hi, reg_lo
+ check_flags_remained_zero
+ mov r11, \q3
+ and r11, r11, 0xffff
+ lsl16 r11, r11
+ mov r12, \q2
+ and r12, r12, 0xffff
+ or r11, r11, r12
+ mov r10, \q1
+ and r10, r10, 0xffff
+ lsl16 r10, r10
+ mov r12, \q0
+ and r12, r12, 0xffff
+ or r10, r10, r12
+ cmp r11, \reg_hi
+ bne @fail
+ cmp r10, \reg_lo
+ bne @fail
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;; Exception related code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; parameters that an IllegalInstruction exception may set.
+ .align 4
+ecr_ref : .word ILLEGAL_INSTRUCTION
+addr_ref : .word 0x0 ; for both eret and efa
+cont_addr: .word 0x0
+
+; exception: IllegalInstruction
+; regs used: r11, r12
+;
+; A parameterized IllegalInstruction exception that checks the followings:
+; ecr == Illegal instruction
+; efa == efa_ref
+; eret == eret_ref
+; If everything passes, it will jump to 'cont_addr' parameter. The parameters
+; must be set beforehand using 'set_except_params' macro. This requires
+; ivt.S file to be compiled and linked.
+ .align 4
+ .global instruction_error
+ .type instruction_error, @function
+instruction_error:
+ ld r11, [ecr_ref]
+ lr r12, [ecr]
+ cmp r12, r11
+ bne @fail
+ ld r11, [addr_ref]
+ lr r12, [eret]
+ cmp r12, r11
+ bne @fail
+ lr r12, [efa]
+ cmp r12, r11
+ bne @fail
+ ; Success: continuing
+ ld r11, [cont_addr]
+ sr r11, [eret]
+ rtie
+
+; macro: set_except_params
+; regs used: r11
+;
+; This macro writes the provided parameters to a temporary place holder
+; that later will be used by exception above to verify as reference.
+.macro set_except_params addr, continue
+ mov r11, \addr
+ st r11, [addr_ref]
+ mov r11, \continue
+ st r11, [cont_addr]
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; VADD2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Let the tests begin
+ start
+
+; Test case 1
+; reg2 <- reg2, reg2
+; (0x00000006,0x00000004)=(0x80000003,0x80000002)+(0x80000003,0x80000002)
+; To boot, C and V flags must not be set.
+ prep_test_case
+ mov r2, 0x80000002
+ mov r3, 0x80000003
+ vadd2 r2, r2, r2
+ check_64bit_double 0x00000006, 0x00000004, r3, r2
+
+; Test case 2
+; reg0 <- reg2, reg0
+; (4,6)=(1,2)+(3,4)
+ prep_test_case
+ mov r3, 0x00000001
+ mov r2, 0x00000002
+ mov r1, 0x00000003
+ mov r0, 0x00000004
+ vadd2 r0, r2, r0
+ check_64bit_double 4, 6, r1, r0
+
+; Test case 3
+; reg0 <- limm, reg4
+; (0x00000000,0x00000000)=(0x12345678,0x12345678)+(0xedcba988,0xedcba988)
+; Moreover, Z flag mustn't be set.
+ prep_test_case
+ mov r0, 0x11111111 ; bogus data
+ mov r1, 0x22222222 ; bogus data
+ mov r4, 0xedcba988 ; neg(0x12345678)
+ mov r5, 0xedcba988 ; neg(0x12345678)
+ vadd2 r0, 0x12345678, r4
+ check_64bit_double 0x00, 0x00, r1, r0
+
+; Test case 4
+; reg4 <- reg2, limm
+; (-3,-2)=(-2,-1)+(-1,-1)
+; The N flag must not be set, irrespective of having negative results.
+ prep_test_case
+ mov r2, -1
+ mov r3, -2
+ vadd2 r4, r2, -1
+ check_64bit_double -3, -2, r5, r4
+
+; Test case 5
+; reg2 <- limm, limm (both limm should be the same)
+; (0x2468acf0,0x2468acf0)=(0x12345678,0x12345678)+(0x12345678,0x12345678)
+ prep_test_case
+ vadd2 r2, 0x12345678, 0x12345678
+ check_64bit_double 0x2468acf0, 0x2468acf0, r3, r2
+
+; Test case 6
+; reg4 <- limm, u6
+; (0x01020343,0x01020343)=(0x01020304,0x01020304)+(0x3f,0x3f)
+ prep_test_case
+ vadd2 r4, 0x01020304, 63
+ check_64bit_double 0x01020343, 0x01020343, r5, r4
+
+; Test case 7
+; reg2 <- reg4, 0(u6)
+; (0x08070605,0x04030201)=(0x08070605,0x04030201)+(0,0)
+ prep_test_case
+ mov r5, 0x08070605
+ mov r4, 0x04030201
+ vadd2 r2, r4, 0
+ check_64bit_double 0x08070605, 0x04030201, r3, r2
+
+; Test case 8
+; reg2 <- reg2, s12
+; (3000002048,2000002048)=(3000004096,2000004096)+(-2048,-2048)
+ prep_test_case
+ mov r3, 3000004096
+ mov r2, 2000004096
+ vadd2 r2, r2, -2048
+ check_64bit_double 3000002048, 2000002048, r3, r2
+
+; Test case 9
+; 0 <- limm, s12
+; (X,X)=(0xffeeddbb,0xffeeddbb)+(-2048,-2048)
+ prep_test_case
+ vadd2 0, 0xffeeddbb, -2048
+
+; Test case 10
+; Testing when cc condition is met
+; (6,4)=(3,2)+(3,2)
+ prep_test_case
+ mov r2, 2
+ mov r3, 3
+ mov r4, 0x80000000 ; setting...
+ add.f 0,r4,r4 ; ...C=1
+ vadd2.c r2, r2, r2
+ add.f 0,0,1 ; so that CHECK_FLAGS_REMAINED_ZERO won't fail.
+ check_64bit_double 6, 4, r3, r2
+
+; Test case 11
+; Testing when cc condition is not met
+; (2,0)
+ prep_test_case
+ mov r2, 0
+ mov r3, 2
+ vadd2.z r2, r2, r2 ; Z=0 because of PREP_TEST_CASE
+ check_64bit_double 2, 0, r3, r2
+
+; Test case 12
+; Raise an Illegal Instruction exception if an odd register is used.
+; Even if there is no register to save the result to.
+ prep_test_case
+ set_except_params @test_12_exception, @test_12_end
+test_12_exception:
+ vadd2 0, r3, r0
+ b @fail
+test_12_end:
+ ; Fall through
+
+; Test case 13
+; Raise an Illegal Instruction exception if an odd register is used.
+; The exception should be made even if the CC indicates no execution.
+ prep_test_case ; (Z,N,C,V)=(0,0,0,0)
+ set_except_params @test_13_exception, @test_13_end
+test_13_exception:
+ vadd2.z r5, r5, r0
+ b @fail
+test_13_end:
+ ; Fall through
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; VADD2H ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Test case 14
+; reg1 <- reg1, reg1
+; (0x0006,0x0004)=(0x8003,0x8002)+(0x8003,0x8002)
+; Moreover, the C and V flags are not going to be set.
+ prep_test_case
+ mov r1, 0x80038002
+ vadd2h r1, r1, r1
+ check_32bit_double 0x0006, 0x0004, r1
+
+; Test case 15
+; reg1 <- reg1, reg3
+; (4,6)=(1,2)+(3,4)
+ prep_test_case
+ mov r3, 0x00010002
+ mov r1, 0x00030004
+ vadd2h r1, r1, r3
+ check_32bit_double 4, 6, r1
+
+; Test case 16
+; reg0 <- limm, reg4
+; (0x0000,0x0000)=(0x1234,0x5678)+(0xedcc,0xa988)
+; The Z flag must not be set.
+ prep_test_case
+ mov r0, 0x11112222 ; bogus data
+ mov r4, 0xedcca988 ; (neg(0x1234),neg(0x5678))
+ vadd2h r0, 0x12345678, r4
+ check_32bit_double 0x0000, 0x0000, r0
+
+; Test case 17
+; reg5 <- reg3, limm
+; (-3,-2)=(-2,-1)+(-1,-1)
+; The N flag mustn't be set, irrespective of having negative results.
+ prep_test_case
+ mov r3, 0xfffeffff ; (-2,-1)
+ vadd2h r5, r3, -1
+ check_32bit_double -3, -2, r5
+
+; Test case 18
+; reg1 <- limm, limm (both limm should be the same)
+; (0x2468,0xacf0)=(0x1234,0x5678)+(0x1234,0x5678)
+ prep_test_case
+ vadd2h r1, 0x12345678, 0x12345678
+ check_32bit_double 0x2468, 0xacf0, r1
+
+; Test case 19
+; reg0 <- limm, u6
+; (0x0141,0x0343)=(0x0102,0x0304)+(0x3f,0x3f)
+ prep_test_case
+ vadd2h r0, 0x01020304, 63
+ check_32bit_double 0x0141, 0x0343, r0
+
+; Test case 20
+; reg1 <- reg0, 0(u6)
+; (0x0403,0x0201)=(0x0403,0x0201)+(0,0)
+ prep_test_case
+ mov r0, 0x04030201
+ vadd2h r1, r0, 0
+ check_32bit_double 0x0403, 0x0201, r1
+
+; Test case 21
+; reg3 <- reg3, s12
+ ; (30064,-1)=(30000,-65)+(-125,-125)
+ prep_test_case
+ mov r3, 0x7530ffbf ; (30000,-65)
+ vadd2h r3, r3, -125
+ check_32bit_double 29875, -190, r3
+
+; Test case 22
+; 0 <- limm, s12
+; (X,X)=(0xffee,0xddbb)+(-2048,-2048)
+ prep_test_case
+ vadd2h 0, 0xffeeddbb, -2048
+
+; Test case 23
+; Testing when cc condition is met
+; (6,4)=(3,2)+(3,2)
+ prep_test_case
+ mov r1, 0x00030002
+ mov r0, 0x80000000 ; setting...
+ add.f 0,r0,r0 ; ...V=1
+ vadd2h.v r1, r1, r1
+ add.f 0,0,1 ; so that CHECK_FLAGS_REMAINED_ZERO won't fail.
+ check_32bit_double 6, 4, r1
+
+; Test case 24
+; Testing when cc condition is not met
+; (2,0)
+ prep_test_case
+ mov r4, 0x00020000
+ vadd2h.n r4, r4, r4 ; N is already 0 because of PRE_TEST_CASE.
+ check_32bit_double 2, 0, r4
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; VADD4H ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Test case 25
+; reg2 <- reg2, reg2
+; (0x0000,0x0006,0x0000,0x0004)=(0x8000,0x8003,0x8000,0x8002)+
+; (0x8000,0x8003,0x8000,0x8002)
+; Moreover, the C and V flags must not be set.
+ prep_test_case
+ mov r2, 0x80008002
+ mov r3, 0x80008003
+ vadd4h r2, r2, r2
+ check_64bit_quadruple 0x0000, 0x0006, 0x0000, 0x0004, r3, r2
+
+; Test case 26
+; reg0 <- reg2, reg0
+; (6,8,10,12)=(1,2,3,4)+(5,6,7,8)
+ prep_test_case
+ mov r3, 0x00010002
+ mov r2, 0x00030004
+ mov r1, 0x00050006
+ mov r0, 0x00070008
+ vadd4h r0, r2, r0
+ check_64bit_quadruple 6, 8, 10, 12, r1, r0
+
+; Test case 27
+; reg0 <- limm, reg4
+; (0x0000,0x0000,0x0000,0x0000)=(0x1234,0x5678,0x1234,0x5678)+
+; (0xedcc,0xa988,0xedcc,0xa988)
+; also the Z flag mustn't be set.
+ prep_test_case
+ mov r0, 0x11111111 ; bogus data
+ mov r1, 0x22222222 ; bogus data
+ mov r4, 0xedcca988 ; (neg(0x1234),neg(0x5678))
+ mov r5, 0xedcca988 ; (neg(0x1234),neg(0x5678))
+ vadd4h r0, 0x12345678, r4
+ check_64bit_quadruple 0x00, 0x00, 0x00, 0x00, r1, r0
+
+; Test case 28
+; reg4 <- reg2, limm
+; (-5,-4,-3,-2)=(-4,-3,-2,-1)+(-1,-1,-1,-1)
+; The N flag must not be set, irrespective of having negative results.
+ prep_test_case
+ mov r2, 0xfffeffff ; (-2,-1)
+ mov r3, 0xfffcfffd ; (-4,-3)
+ vadd4h r4, r2, -1
+ check_64bit_quadruple -5, -4, -3, -2, r5, r4
+
+; Test case 29
+; reg2 <- limm, limm (both limm should be the same)
+; (0x2468,0xacf0,0x2468,0xacf0)=(0x1234,0x5678,0x1234,0x5678)+
+; (0x1234,0x5678,0x1234,0x5678)
+ prep_test_case
+ vadd4h r2, 0x12345678, 0x12345678
+ check_64bit_quadruple 0x2468, 0xacf0, 0x2468, 0xacf0, r3, r2
+
+; Test case 30
+; reg4 <- limm, u6
+; (0x0141,0x0343,0x0141,0x0343)=(0x0102,0x0304,0x0102,0x0304)+
+; ( 0x3f, 0x3f, 0x3f, 0x3f)
+ prep_test_case
+ vadd4h r4, 0x01020304, 63
+ check_64bit_quadruple 0x0141, 0x0343, 0x0141, 0x0343, r5, r4
+
+; Test case 31
+; reg0 <- reg4, 0(u6)
+; (0x1122,0x3344,0x5566,0x7788)=(0x1122,0x3344,0x5566,0x7788)+
+; (0x0000,0x0000,0x0000,0x0000)
+ prep_test_case
+ mov r5, 0x11223344
+ mov r4, 0x55667788
+ vadd4h r0, r4, 0
+ check_64bit_quadruple 0x1122, 0x3344, 0x5566, 0x7788, r1, r0
+
+; Test case 32
+; reg0 <- reg0, s12
+; (2048,2046,2049,2035)=(1,-1,2,-12)+(2047,2047,2047,2047)
+ prep_test_case
+ mov r1, 0x0001ffff ; (1,-1)
+ mov r0, 0x0002fff4 ; (2,-12)
+ vadd4h r0, r0, 2047
+ check_64bit_quadruple 2048, 2046, 2049, 2035, r1, r0
+
+; Test case 33
+; 0 <- limm, s12
+; (X,X,X,X)=(0xffee,0xddbb,0xffee,0xddbb)+(-2048,-2048,-2048,-2048)
+ prep_test_case
+ vadd4h 0, 0xffeeddbb, -2048
+
+; Test case 34
+; Testing when cc condition is met
+; (40,80,120,160)=(20,40,60,80)+(20,40,60,80)
+ prep_test_case
+ mov r2, 0x003c0050 ; (60,80)
+ mov r3, 0x00140028 ; (20,40)
+ mov r4, 0x80000000 ; setting...
+ add.f 0,r4,r4 ; ...C=1
+ vadd4h.c r2, r2, r2
+ add.f 0,0,1 ; so that CHECK_FLAGS_REMAINED_ZERO won't fail.
+ check_64bit_quadruple 40, 80, 120, 160, r3, r2
+
+; Test case 35
+; Testing when cc condition is not met
+; (2,0)
+ prep_test_case
+ mov r2, 0x00020000
+ mov r3, 0x00020000
+ vadd4h.z r2, r2, r2 ; Z is already 0 because of PREP_TEST_CASE.
+ check_64bit_quadruple 2, 0, 2, 0, r3, r2
+
+; Test case 36
+; Raise an Illegal Instruction exception if an odd register is used.
+; Even if there is no register to save the result to.
+ prep_test_case
+ set_except_params @test_36_exception, @test_36_end
+test_36_exception:
+ vadd4h 0, r2, r3
+ b @fail
+test_36_end:
+ ; Fall through
+
+; Test case 37
+; Raise an Illegal Instruction exception if an odd register is used.
+; The exception should be made even if the CC indicates no execution.
+ prep_test_case ; (Z,N,C,V)=(0,0,0,0)
+ set_except_params @test_37_exception, @test_37_end
+test_37_exception:
+ vadd4h.n r1, r1, r0
+ b @fail
+test_37_end:
+ ; Fall through
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Reporting ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+valhalla:
+ print "[PASS]"
+ b @1f
+
+; If a test fails, it jumps here. Although, for the sake of uniformity,
+; the printed output does not say much about which test case failed,
+; one can uncomment the print_number line below or set a breakpoint
+; here to check the R0 register for the test case number.
+fail:
+ ld r0, [test_nr]
+ ;print_number r0
+ print "[FAIL]"
+1:
+ print " vadd: vadd2 vadd2h vadd4h\n"
+ end
diff --git a/tests/tcg/arc/check_vsub.S b/tests/tcg/arc/check_vsub.S
new file mode 100644
index 0000000000..db25bbdf16
--- /dev/null
+++ b/tests/tcg/arc/check_vsub.S
@@ -0,0 +1,510 @@
+; check_vsub.S
+;
+; Tests for vsub: vsub2 vsub2h vsub4h
+; If the test fails, check the end of this file for how to troubleshoot.
+
+ .include "macros.inc"
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;; Test checking routines ;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Test case counter
+.data
+test_nr:
+ .word 0x0
+
+; Increment the test counter and set (Z,N,C,V) to (0,0,0,0).
+.macro prep_test_case
+ ld r13, [test_nr]
+ add_s r13, r13, 1 ; increase test case counter
+ st r13, [test_nr]
+ add.f 0, 0, 1 ; (Z, N, C, V) = (0, 0, 0, 0)
+.endm
+
+; Checks if (Z,N,C,V) == (0,0,0,0). This relies on "ADD.F 0,0,1"
+; instruction in PREP_TEST_CASE macro. From a PREP_TEST_CASE macro
+; in a test case, and thence to a VECTOR instruction and finally to
+; this macro, none of the aforementioned flags must have been set,
+; because VECTOR instructions aren't supposed to do so.
+.macro check_flags_remained_zero
+ lr r11, [status32]
+ mov r12, REG_STAT_Z
+ or r12, r12, REG_STAT_N
+ or r12, r12, REG_STAT_C
+ or r12, r12, REG_STAT_V
+ and r11, r11, r12
+ cmp r11, 0
+ bne @fail
+.endm
+
+; pair(HI, LOW) == pair(REG_HI, REG_LO)
+; HI, LO: 32-bit
+; REG_HI, REG_LO: 32-bit
+.macro check_64bit_double hi, low, reg_hi, reg_lo
+ check_flags_remained_zero
+ mov r11, \hi
+ mov r10, \low
+ cmp r11, \reg_hi
+ bne @fail
+ cmp r10, \reg_lo
+ bne @fail
+.endm
+
+; REG == (HI, LO)
+; HI, LO: 16-bit
+; REG: 32-bit
+.macro check_32bit_double hi, low, reg
+ check_flags_remained_zero
+ mov r11, \hi
+ and r11, r11, 0xffff
+ lsl16 r11, r11
+ mov r12, \low
+ and r12, r12, 0xffff
+ or r11, r11, r12
+ cmp r11, \reg
+ bne @fail
+.endm
+
+; quartet(q3, q2, q1, q0) == pair64(REG_HI, REG_LO)
+; Q3, Q2, Q1, Q0: 16-bit
+; REG_HI, REG_LO: 32-bit
+.macro check_64bit_quadruple q3, q2, q1, q0, reg_hi, reg_lo
+ check_flags_remained_zero
+ mov r11, \q3
+ and r11, r11, 0xffff
+ lsl16 r11, r11
+ mov r12, \q2
+ and r12, r12, 0xffff
+ or r11, r11, r12
+ mov r10, \q1
+ and r10, r10, 0xffff
+ lsl16 r10, r10
+ mov r12, \q0
+ and r12, r12, 0xffff
+ or r10, r10, r12
+ cmp r11, \reg_hi
+ bne @fail
+ cmp r10, \reg_lo
+ bne @fail
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;; Exception related code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; parameters that an IllegalInstruction exception may set.
+ .align 4
+ecr_ref : .word ILLEGAL_INSTRUCTION
+addr_ref : .word 0x0 ; for both eret and efa
+cont_addr: .word 0x0
+
+; exception: IllegalInstruction
+; regs used: r11, r12
+;
+; A parameterized IllegalInstruction exception that checks the followings:
+; ecr == Illegal instruction
+; efa == efa_ref
+; eret == eret_ref
+; If everything passes, it will jump to 'cont_addr' parameter. The parameters
+; must be set beforehand using 'set_except_params' macro. This requires
+; ivt.S file to be compiled and linked.
+ .align 4
+ .global instruction_error
+ .type instruction_error, @function
+instruction_error:
+ ld r11, [ecr_ref]
+ lr r12, [ecr]
+ cmp r12, r11
+ bne @fail
+ ld r11, [addr_ref]
+ lr r12, [eret]
+ cmp r12, r11
+ bne @fail
+ lr r12, [efa]
+ cmp r12, r11
+ bne @fail
+ ; Success: continuing
+ ld r11, [cont_addr]
+ sr r11, [eret]
+ rtie
+
+; macro: set_except_params
+; regs used: r11
+;
+; This macro writes the provided parameters to a temporary place holder
+; that later will be used by exception above to verify as reference.
+.macro set_except_params addr, continue
+ mov r11, \addr
+ st r11, [addr_ref]
+ mov r11, \continue
+ st r11, [cont_addr]
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; VSUB2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Let the tests begin
+ start
+
+; Test case 1
+; reg2 <- reg2, reg2
+; (0x00000000,0x00000000)=(0x80000000,0xffffffff)-(0x80000000,0xffffffff)
+; The Z flag must remain 0.
+ prep_test_case
+ mov r2, 0xffffffff
+ mov r3, 0x80000000
+ vsub2 r2, r2, r2
+ check_64bit_double 0, 0, r3, r2
+
+; Test case 2
+; reg0 <- reg2, reg0
+; (0x7fffffff,0x80000000)=(-1,0x7fffffff)-(0x80000000,-1)
+; The V and N flags must remain zero.
+ prep_test_case
+ mov r3, 0xffffffff
+ mov r2, 0x7fffffff
+ mov r1, 0x80000000
+ mov r0, 0xffffffff
+ vsub2 r0, r2, r0
+ check_64bit_double 0x7fffffff, 0x80000000, r1, r0
+
+; Test case 3
+; reg0 <- limm, reg4
+; (0x90abcdef,0x00000001)=(0x12345678,0x12345678)-(0x81888889,0x12345677)
+ prep_test_case
+ mov r0, 0x11111111 ; bogus data
+ mov r1, 0x22222222 ; bogus data
+ mov r4, 0x12345677
+ mov r5, 0x81888889
+ vsub2 r0, 0x12345678, r4
+ check_64bit_double 0x90abcdef, 0x01, r1, r0
+
+; Test case 4
+; reg4 <- reg2, limm
+; (-999999999,-999999998)=(1,2)-(1000000000,1000000000)
+; The N flag must not be set, irrespective of having negative results.
+ prep_test_case
+ mov r2, 2
+ mov r3, 1
+ vsub2 r4, r2, 0x3b9aca00 ; 0x3b9aca00=1000000000
+ check_64bit_double -999999999, -999999998, r5, r4
+
+; Test case 5
+; reg2 <- limm, limm (both limm should be the same)
+; (0x00,0x00)=(0x12345678,0x12345678)-(0x12345678,0x12345678)
+ prep_test_case
+ vsub2 r2, 0x12345678, 0x12345678
+ check_64bit_double 0, 0, r3, r2
+
+; Test case 6
+; reg4 <- limm, u6
+; (0x010202c5,0x010202c5)=(0x01020304,0x01020304)-(0x3f,0x3f)
+ prep_test_case
+ vsub2 r4, 0x01020304, 63
+ check_64bit_double 0x010202c5, 0x010202c5, r5, r4
+
+; Test case 7
+; reg2 <- reg4, 0(u6)
+; (0x08070605,0x04030201)=(0x08070605,0x04030201)-(0,0)
+ prep_test_case
+ mov r5, 0x08070605
+ mov r4, 0x04030201
+ vsub2 r2, r4, 0
+ check_64bit_double 0x08070605, 0x04030201, r3, r2
+
+; Test case 8
+; reg0 <- reg0, s12
+; (2048,-200000000)=(0,-2000002048)-(-2048,-2048)
+ prep_test_case
+ mov r1, 0
+ mov r0, -2000002048
+ vsub2 r0, r0, -2048
+ check_64bit_double 2048, -2000000000, r1, r0
+
+; Test case 9
+; 0 <- limm, s12
+; (X,X)=(0xffeeddbb,0xffeeddbb)-(-2048,-2048)
+ prep_test_case
+ vsub2 0, 0xffeeddbb, -2048
+
+; Test case 10
+; Testing when cc condition is met
+; (0,0)=(3,2)+(3,2)
+ prep_test_case
+ mov r2, 2
+ mov r3, 3
+ mov r4, 0x80000000 ; setting...
+ add.f 0,r4,r4 ; ...C=1
+ vsub2.c r2, r2, r2
+ add.f 0,0,1 ; so that CHECK_FLAGS_REMAINED_ZERO won't fail.
+ check_64bit_double 0, 0, r3, r2
+
+; Test case 11
+; Testing when cc condition is not met
+; (2,0)
+ prep_test_case
+ mov r2, 0
+ mov r3, 2
+ vsub2.z r2, r2, r2 ; Z=0 because of PREP_TEST_CASE
+ check_64bit_double 2, 0, r3, r2
+
+; Test case 12
+; Raise an Illegal Instruction exception if an odd register is used.
+; Even if there is no register to save the result to.
+ prep_test_case
+ set_except_params @test_12_exception, @test_12_end
+test_12_exception:
+ vsub2 0, r5, r0
+ b @fail
+test_12_end:
+ ; Fall through
+
+; Test case 13
+; Raise an Illegal Instruction exception if an odd register is used.
+; The exception should be made even if the CC indicates no execution.
+ prep_test_case ; (Z,N,C,V)=(0,0,0,0)
+ set_except_params @test_13_exception, @test_13_end
+test_13_exception:
+ vsub2.c r1, r1, r0
+ b @fail
+test_13_end:
+ ; Fall through
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; VSUB2H ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Test case 14
+; reg1 <- reg1, reg1
+; (0x0000,0x0000)=(0x8000,0xffff)-(0x8000,0xffff)
+; To boot, the Z flag must remain unsett.
+ prep_test_case
+ mov r1, 0x8000ffff
+ vsub2h r1, r1, r1
+ check_32bit_double 0, 0, r1
+
+; Test case 15
+; reg1 <- reg1, reg3
+; (0x7fff,0x8000)=(-1,0x7fff)-(0x8000,-1)
+; The V and N flags must remain zero.
+ prep_test_case
+ mov r1, 0xffff7fff
+ mov r3, 0x8000ffff
+ vsub2h r1, r1, r3
+ check_32bit_double 0x7fff, 0x8000, r1
+
+; Test case 16
+; reg0 <- limm, reg4
+; (0x4321,0x0001)=(0x1234,0x5678)-(0xcf13,0x5677)
+ prep_test_case
+ mov r0, 0x11111111 ; bogus data
+ mov r4, 0xcf135677
+ vsub2h r0, 0x12345678, r4
+ check_32bit_double 0x4321, 0x0001, r0
+
+; Test case 17
+; reg5 <- reg3, limm
+; (-9999,-9998)=(1,2)-(10000,10000)
+; The N flag must not be set, irrespective of having negative results.
+ prep_test_case
+ mov r3, 0x00010002 ; (1,2)
+ vsub2h r5, r3, 0x27102710 ; (1,2)-(10000,10000)
+ check_32bit_double -9999, -9998, r5
+
+; Test case 18
+; reg1 <- limm, limm (both limm should be the same)
+; (0x00,0x00)=(0x1234,0x5678)-(0x1234,0x5678)
+ prep_test_case
+ vsub2h r1, 0x12345678, 0x12345678
+ check_32bit_double 0, 0, r1
+
+; Test case 19
+; reg0 <- limm, u6
+; (0x00c3,0x02c5)=(0x0102,0x0304)-(0x3f,0x3f)
+ prep_test_case
+ vsub2h r0, 0x01020304, 63
+ check_32bit_double 0x00c3, 0x02c5, r0
+
+; Test case 20
+; reg1 <- reg0, 0(u6)
+; (0x0403,0x0201)=(0x0403,0x0201)-(0,0)
+ prep_test_case
+ mov r0, 0x04030201
+ vsub2h r1, r0, 0
+ check_32bit_double 0x0403, 0x0201, r1
+
+; Test case 21
+; reg5 <- reg5, s12
+; (66,-20415)=(1,-20480)-(-65,-65)
+ prep_test_case
+ mov r5, 0x0001b000 ; (1,-20480)
+ vsub2h r5, r5, -65
+ check_32bit_double 66, -20415, r5
+
+; Test case 22
+; 0 <- limm, s12
+; (X,X)=(0xffee,0xddbb)-(-2048,-2048)
+ prep_test_case
+ vsub2h 0, 0xffeeddbb, -2048
+
+; Test case 23
+; Testing when cc condition is met
+; (0,0)=(3,2)+(3,2)
+ prep_test_case
+ mov r1, 0x00030002
+ mov r0, 0x80000000 ; setting...
+ add.f 0,r0,r0 ; ...V=1
+ vsub2h.v r1, r1, r1
+ add.f 0,0,1 ; so that CHECK_FLAGS_REMAINED_ZERO won't fail.
+ check_32bit_double 0, 0, r1
+
+; Test case 24
+; Testing when cc condition is not met
+; (2,0)
+ prep_test_case
+ mov r4, 0x00020000
+ vsub2h.n r4, r4, r4 ; N=0 because of PREP_TEST_CASE
+ check_32bit_double 2, 0, r4
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; VSUB4H ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Test case 25
+; reg2 <- reg2, reg2
+; (0x0000,0x0000,0x0000,0x0000)=(0x8000,0x7000,0xfffe,0xffff)-
+; (0x8000,0x7000,0xfffe,0xffff)
+; The Z flag must remain 0.
+ prep_test_case
+ mov r2, 0xfffeffff
+ mov r3, 0x80007000
+ vsub4h r2, r2, r2
+ check_64bit_quadruple 0, 0, 0, 0, r3, r2
+
+; Test case 26
+; reg0 <- reg2, reg0
+; (0x7fff,-2,977,0x8000)=(-1,10,1000,0x7fff)-(0x8000,12,23,-1)
+; The V and N flags must remain zero.
+ prep_test_case
+ mov r3, 0xffff000a ; (-1 , 10)
+ mov r2, 0x03e87fff ; (1000 , 0x7fff)
+ mov r1, 0x8000000c ; (0x8000, 12)
+ mov r0, 0x0017ffff ; (23 , -1)
+ vsub4h r0, r2, r0
+ check_64bit_quadruple 0x7fff, -2, 977, 0x8000, r1, r0
+
+; Test case 27
+; reg0 <- limm, reg4
+; (0x4321,0x8765,0x90ab,0xcdef)=(0x1234,0x5678,0x1234,0x5678)-
+; (0xcf13,0xcf13,0x8189,0x8889)
+ prep_test_case
+ mov r0, 0x11111111 ; bogus data
+ mov r1, 0x22222222 ; bogus data
+ mov r5, 0xcf13cf13
+ mov r4, 0x81898889
+ vsub4h r0, 0x12345678, r4
+ check_64bit_quadruple 0x4321, 0x8765, 0x90ab, 0xcdef, r1, r0
+
+; Test case 28
+; reg4 <- reg2, limm
+; (-9999,-10,-9653,417)=(1,2,347,429)-(10000,12,10000,12)
+; The N flag must not be set, irrespective of having negative results.
+ prep_test_case
+ mov r3, 0x00010002 ; (1 , 2)
+ mov r2, 0x015b01ad ; (347, 429)
+ vsub4h r4, r2, 0x2710000c ; (0x2710,000c)=(10000,12)
+ check_64bit_quadruple -9999, -10, -9653, 417, r5, r4
+
+; Test case 29
+; reg2 <- limm, limm (both limm should be the same)
+; (0x0000,0x0000,0x0000,0x0000)=(0x1234,0x5678,0x1234,0x5678)-
+; (0x1234,0x5678,0x1234,0x5678)
+ prep_test_case
+ vsub4h r2, 0x12345678, 0x12345678
+ check_64bit_quadruple 0, 0, 0, 0, r3, r2
+
+; Test case 30
+; reg4 <- limm, u6
+; (0x00c3,0x02c5,0x00c3,0x02c5)=(0x0102,0x0304,0x0102,0x0304)-
+; ( 0x3f, 0x3f, 0x3f, 0x3f)
+ prep_test_case
+ vsub4h r4, 0x01020304, 63
+ check_64bit_quadruple 0x00c3,0x02c5, 0x00c3, 0x02c5, r5, r4
+
+; Test case 31
+; reg0 <- reg4, 0(u6)
+; (0x1122,0x3344,0x5566,0x7788)=(0x1122,0x3344,0x5566,0x7788)-
+; (0x0000,0x0000,0x0000,0x0000)
+ prep_test_case
+ mov r5, 0x11223344
+ mov r4, 0x55667788
+ vsub4h r0, r4, 0
+ check_64bit_quadruple 0x1122, 0x3344, 0x5566, 0x7788, r1, r0
+
+; Test case 32
+; reg2 <- reg2, s12
+; (-4094,1,-2035,-2049)=(-2047,2048,12,-2)-(2047,2047,2047,2047)
+ prep_test_case
+ mov r3, 0xf8010800
+ mov r2, 0x000cfffe ; (12, -2)
+ vsub4h r2, r2, 2047
+ check_64bit_quadruple -4094, 1, -2035, -2049, r3, r2
+
+; Test case 33
+; 0 <- limm, s12
+; (X,X,X,X)=(0xffee,0xddbb,0xffee,0xddbb)-(-2048,-2048,-2048,-2048)
+ prep_test_case
+ vsub4h 0, 0xffeeddbb, -2048
+
+; Test case 34
+; Testing when cc condition is met
+; (0,0,0,0)=(3,2,1,0)-(3,2,1,0)
+ prep_test_case
+ mov r3, 0x00030002
+ mov r2, 0x00010000
+ mov r4, 0x80000000 ; setting...
+ add.f 0,r4,r4 ; ...C=1
+ vsub4h.c r2, r2, r2
+ add.f 0,0,1 ; so that CHECK_FLAGS_REMAINED_ZERO won't fail.
+ check_64bit_quadruple 0, 0, 0, 0, r3, r2
+
+; Test case 35
+; Testing when cc condition is not met
+; (2,0,2,0)
+ prep_test_case
+ mov r3, 0x00020000
+ mov r2, 0x00020000
+ vsub4h.z r2, r2, r2 ; Z=0 because of PREP_TEST_CASE
+ check_64bit_quadruple 2, 0, 2, 0, r3, r2
+
+; Test case 36
+; Raise an Illegal Instruction exception if an odd register is used.
+; Even if there is no register to save the result to.
+ prep_test_case
+ set_except_params @test_36_exception, @test_36_end
+test_36_exception:
+ vsub4h 0, r3, r0
+ b @fail
+test_36_end:
+ ; Fall through
+
+; Test case 37
+; Raise an Illegal Instruction exception if an odd register is used.
+; The exception should be made even if the CC indicates no execution.
+ prep_test_case ; (Z,N,C,V)=(0,0,0,0)
+ set_except_params @test_37_exception, @test_37_end
+test_37_exception:
+ vsub4h.v r5, r5, r0
+ b @fail
+test_37_end:
+ ; Fall through
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Reporting ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+valhalla:
+ print "[PASS]"
+ b @1f
+
+; If a test fails, it jumps here. Although, for the sake of uniformity,
+; the printed output does not say much about which test case failed,
+; one can uncomment the print_number line below or set a breakpoint
+; here to check the R0 register for the test case number.
+fail:
+ ld r0, [test_nr]
+ ;print_number r0
+ print "[FAIL]"
+1:
+ print " vsub: vsub2 vsub2h vsub4h\n"
+ end
diff --git a/tests/tcg/arc/check_xorx.S b/tests/tcg/arc/check_xorx.S
new file mode 100644
index 0000000000..b0f5963eac
--- /dev/null
+++ b/tests/tcg/arc/check_xorx.S
@@ -0,0 +1,32 @@
+#*****************************************************************************
+# xor.S
+#-----------------------------------------------------------------------------
+#
+# Test xor instruction.
+#
+#define ARCTEST_ARC32
+#include "test_macros.h"
+
+ARCTEST_BEGIN
+ #-------------------------------------------------------------
+ # Logical tests
+ #-------------------------------------------------------------
+
+ TEST_IMM_OP( 2, xor, 0xffffffffff00f00f, 0x0000000000ff0f00, 0xf0f );
+ TEST_IMM_OP( 3, xor, 0x000000000ff00f00, 0x000000000ff00ff0, 0x0f0 );
+ TEST_IMM_OP( 4, xor, 0x0000000000ff0ff0, 0x0000000000ff08ff, 0x70f );
+ TEST_IMM_OP( 5, xor, 0xfffffffff00ff0ff, 0xfffffffff00ff00f, 0x0f0 );
+ TEST_RR_3OP( 6, xor, 0xf00ff00f, 0xff00ff00, 0x0f0f0f0f );
+ TEST_RR_3OP( 7, xor, 0xff00ff00, 0x0ff00ff0, 0xf0f0f0f0 );
+ TEST_RR_3OP( 8, xor, 0x0ff00ff0, 0x00ff00ff, 0x0f0f0f0f );
+ TEST_RR_3OP( 9, xor, 0x00ff00ff, 0xf00ff00f, 0xf0f0f0f0 );
+
+ #-------------------------------------------------------------
+ # Source/Destination tests
+ #-------------------------------------------------------------
+
+ TEST_IMM_SRC1_EQ_DEST( 10, xor, 0xffffffffff00f00f, 0xffffffffff00f700, 0x70f );
+ TEST_RR_SRC1_EQ_DEST( 11, xor, 0xf00ff00f, 0xff00ff00, 0x0f0f0f0f );
+ TEST_RR_SRC2_EQ_DEST( 12, xor, 0xf00ff00f, 0xff00ff00, 0x0f0f0f0f );
+ TEST_RR_SRC12_EQ_DEST( 13, xor, 0x00000000, 0xff00ff00 );
+ARCTEST_END
diff --git a/tests/tcg/arc/ivt.S b/tests/tcg/arc/ivt.S
new file mode 100644
index 0000000000..39af256ed8
--- /dev/null
+++ b/tests/tcg/arc/ivt.S
@@ -0,0 +1,38 @@
+ .include "macros.inc"
+
+ .section .ivt, "a", @progbits
+#define IVT_ENTRY(name) \
+ .word name `\
+ .weak name `\
+ .set name, _exit_halt
+
+; handler's name, number, name, offset in IVT (hex/dec)
+ IVT_ENTRY(main) ; 0 program entry point 0x00 0
+ IVT_ENTRY(memory_error) ; 1 memory_error 0x04 4
+ IVT_ENTRY(instruction_error) ; 2 instruction_error 0x08 8
+ IVT_ENTRY(EV_MachineCheck) ; 3 EV_MachineCheck 0x0C 12
+ IVT_ENTRY(EV_TLBMissI) ; 4 EV_TLBMissI 0x10 16
+ IVT_ENTRY(EV_TLBMissD) ; 5 EV_TLBMissD 0x14 20
+ IVT_ENTRY(EV_ProtV) ; 6 EV_ProtV 0x18 24
+ IVT_ENTRY(EV_PrivilegeV) ; 7 EV_PrivilegeV 0x1C 28
+ IVT_ENTRY(EV_SWI) ; 8 EV_SWI 0x20 32
+ IVT_ENTRY(EV_Trap) ; 9 EV_Trap 0x24 36
+ IVT_ENTRY(EV_Extension) ; 10 EV_Extension 0x28 40
+ IVT_ENTRY(EV_DivZero) ; 11 EV_DivZero 0x2C 44
+ IVT_ENTRY(EV_DCError) ; 12 EV_DCError 0x30 48
+ IVT_ENTRY(EV_Misaligned) ; 13 EV_Misaligned 0x34 52
+ IVT_ENTRY(EV_Ex14) ; 14 unused 0x38 56
+ IVT_ENTRY(EV_Ex15) ; 15 unused 0x3C 60
+ IVT_ENTRY(IRQ_Timer0) ; 16 Timer 0 0x40 64
+ IVT_ENTRY(IRQ_Timer1) ; 17 Timer 1 0x44 68
+ IVT_ENTRY(IRQ_18) ; 18 0x48 72
+ IVT_ENTRY(IRQ_19) ; 19 0x4C 76
+ IVT_ENTRY(IRQ_20) ; 20 0x50 80
+
+ .text
+ .global _exit_halt
+ .type _exit_halt, @function
+ .align 4
+_exit_halt:
+ print "Fail\n"
+ end
diff --git a/tests/tcg/arc/macros.inc b/tests/tcg/arc/macros.inc
new file mode 100644
index 0000000000..37530ecf3e
--- /dev/null
+++ b/tests/tcg/arc/macros.inc
@@ -0,0 +1,261 @@
+.equ MAX_TESTNAME_LEN, 32
+.macro test_name name
+ .data
+tn_\name:
+ .asciz "\name\n"
+ .space MAX_TESTNAME_LEN - (. - tn_\name), ' '
+ .align 4
+ .text
+ mov r30, @tn_\name
+.endm
+
+.macro check_r2 val
+ sub.f r0, r2, \val
+ bne @1000f
+ print "[PASS] "
+ b @1001f
+1000:
+ print "[FAIL] "
+1001:
+ printl r30
+.endm
+
+
+.macro start
+ .text
+ .global main
+ .align 4
+ main:
+.endm
+
+.macro end
+1001:
+ st 1, [POWER_DEVICE]
+ b @1001b
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+.equ OUTPUT_DEVICE, 0x90000000 ; output device address in QEMU
+.equ POWER_DEVICE, 0xF0000008 ; power management device
+
+; macro: print
+; input: message - the string to be printed
+; regs used: r11, r12
+; example: print "hello world\n"
+.macro print message
+
+ .data
+ 2010:
+ .asciz "\message"
+ .align 4
+
+ .text
+ mov_s r11, @2010b ; the message to be printed
+ 1010:
+ ldb.ab r12, [r11, 1]
+ breq r12, 0, @1011f
+ stb r12, [OUTPUT_DEVICE]
+ j @1010b
+ 1011:
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; macro: printl
+; input: label - pointer to the string to be printed
+; regs used: r11, r12
+; example: print @l1
+.macro printl reg
+
+ .text
+ mov r11, \reg ; the message to be printed
+ 3010:
+ ldb.ab r12, [r11, 1]
+ breq r12, 0, @3011f
+ stb r12, [OUTPUT_DEVICE]
+ j @3010b
+ 3011:
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; macro: print_number
+; input: number
+; regs used: r11, r12, r13, r14
+; example: print_number 0x123
+; print_number 11
+;
+; description:
+; given a number, prints it to the output as a decimal string.
+.macro print_number number
+ .data
+ .align 4
+2020: ; place holder for printed number in reverse
+ .skip 12
+
+ .text
+ mov r11, \number
+ mov r13, @2020b
+ mov r14, @2020b
+1020:
+ remu r12, r11, 10
+ add_s r12, r12, 0x30
+ stb.ab r12, [r13, 1]
+ divu r11, r11, 10
+ brne r11, 0, @1020b
+
+1021:
+ ldb.aw r12, [r13, -1]
+ stb r12, [0x90000000]
+ brne r13, r14, @1021b
+.endm
+
+
+; macro: print_number_hex
+; input: number
+; regs used: r11, r12, r13, r14
+; example: print_number_hex 0x123
+; print_number_hex 11
+;
+; description:
+; given a number, prints it to the output with "0x" prefix and in
+; hexadecimal format.
+.macro print_number_hex num
+ .data
+ .align 4
+2030: ; number printed in reverse order
+ .skip 12
+
+ .text
+ mov r11, \num
+ mov r13, @2030b
+ mov r14, @2030b
+1030:
+ and r12, r11, 0x0F
+ brgt r12, 9, @1031f
+ add_s r12, r12, '0'
+ j @1032f
+1031:
+ add_s r12, r12, 'W'
+1032:
+ stb.ab r12, [r13, 1]
+ lsr.f r11, r11, 4
+ bnz @1030b
+
+ print "0x"
+10333:
+ ldb.aw r12, [r13, -1]
+ stb r12, [OUTPUT_DEVICE]
+ brgt r13, r14, @10333b
+.endm
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; macro: assert_eq
+; input: a, b - two values/registers to be compared
+; test_num - optional: printed error number, default is 1.
+; regs used: r11, r12
+; example: assert_eq 12, r2
+; assert_eq r1, 8
+; assert_eq r3, r4
+; assert_eq 8 , 9 (although useless for tests)
+;
+; description:
+; compares the two inputs. if they are equal, nothing happens.
+; but if not, then it is going to print "Ret:1" and exit.
+.macro assert_eq a, b, test_num=1
+ mov r11, \a
+ mov r12, \b
+ breq r11, r12, @1040f
+ print "FAIL:"
+ print_number \test_num
+ end
+1040:
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Auxilary registers
+.equ REG_IRQ_SELECT, 0x40B
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Exceptions
+.equ ILLEGAL_INSTRUCTION , 0x00020000
+.equ ILLEGAL_INSTRUCTION_SEQUENCE, 0x00020100
+.equ MACHINE_CHECK , 0x00030000
+.equ TLB_MISS_I , 0x00040000
+.equ TLB_MISS_D_READ , 0x00050100
+.equ PRIVILEGE_VIOLATION , 0x00070000
+.equ SOFTWARE_INTERRUPT , 0x00080000
+.equ MISALIGNED_DATA_ACCESS , 0x000D0000
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; macro: set_interrupt_prio_level
+; input: prio - number in range 0..7
+; regs used: r11
+; example: set_interrupt_prio_level 1
+;
+; description:
+; sets the bits 1 to 3 of "status" register to the given priority.
+.macro set_interrupt_prio_level prio
+ lr r11, [status32]
+ asl r12, \prio
+ and r12, r12, 0xE
+ or r11, r11, r12
+ sr r11, [status32]
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; STATUS register and its masks
+.equ REG_STAT, 0x0A ; STATUS32 register
+.equ REG_IVT_BASE, 0x25 ; Interrupt vector base
+.equ REG_STAT_V, 0x0100 ; mask for Over flow bit
+.equ REG_STAT_C, 0x0200 ; mask for Carry bit
+.equ REG_STAT_N, 0x0400 ; mask for Negative bit
+.equ REG_STAT_Z, 0x0800 ; mask for Zero bit
+
+; macro: assert_flag
+; input: reg_stat_flag - index to get the corresponding flag
+; bit - verification value: 0 or 1
+; test_num - optional: printed error number, default
+; is 1. valid range is: [0 ... 9]
+; regs used: r11, r12
+; example: assert_flag REG_STAT_Z, 1, num=8
+; assert_flag 0x0200 , 0, num=3
+;
+; description:
+; extracts the corresponding bit at given index by reg_stat_flag.
+; if it holds the same value as given 'bit', nothing happens,
+; else it will print an error and exit.
+.macro assert_flag reg_stat_flag, bit, test_num
+ lr r11, [REG_STAT]
+ and r11, r11, \reg_stat_flag
+ ; if bit=0 then checking if r11 == 0
+ ; if bit=1 then checking if r11 == bit_mask
+ assert_eq r11, \bit*\reg_stat_flag, \test_num
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; macro: enter_user_mode
+; input: user_space - where the user code begins
+;
+; regs used: r11
+; example: enter_user_mode @my_user_space_entry
+;
+; description:
+; this piece of code sets the user flag and jumps to given address
+.macro enter_user_mode user_space
+ lr r11, [status32]
+ or r11, r11, 0x80 ; set the STATUS32.U
+ sr r11, [erstatus]
+ mov r11, \user_space
+ sr r11, [eret]
+ rtie
+.endm
diff --git a/tests/tcg/arc/memory.x b/tests/tcg/arc/memory.x
new file mode 100644
index 0000000000..53772484fc
--- /dev/null
+++ b/tests/tcg/arc/memory.x
@@ -0,0 +1,12 @@
+MEMORY
+{
+ RAM : ORIGIN = 0x00000000, LENGTH = 128M
+}
+
+REGION_ALIAS("startup", RAM)
+REGION_ALIAS("text", RAM)
+REGION_ALIAS("data", RAM)
+REGION_ALIAS("sdata", RAM)
+
+PROVIDE (__stack_top = (0xFFFF & -4) );
+PROVIDE (__end_heap = (0xFFFF) );
diff --git a/tests/tcg/arc/mmu.inc b/tests/tcg/arc/mmu.inc
new file mode 100644
index 0000000000..c20c6e6bdd
--- /dev/null
+++ b/tests/tcg/arc/mmu.inc
@@ -0,0 +1,132 @@
+
+; auxilary registers
+.equ REG_PD0 , 0x460 ; TLBPD0
+.equ REG_PD1 , 0x461 ; TLBPD1
+.equ REG_TLB_INDX, 0x464 ; TLB index
+.equ REG_TLB_CMD , 0x465 ; TLB command
+.equ REG_PID , 0x468 ; Process Identity
+
+; exceptions (ecr values)
+.equ PROTV_FETCH_MMU, 0x060008
+.equ PROTV_READ_MMU , 0x060108
+.equ PROTV_WRITE_MMU, 0x060208
+.equ PROTV_RW_MMU , 0x060308
+
+; PID register bit masks
+.equ REG_PID_TLB_SET, 0x80000000 ; TLB enable bit in PID
+.equ REG_PID_TLB_CLR, ~REG_PID_TLB_SET ; TLB disable bit in PID
+
+; bit masks related to page size
+.equ PAGE_INDEX_BITS, 13 ; page size is _assumed_ to be 8 KB
+.equ PAGE_SIZE , 1 << PAGE_INDEX_BITS
+.equ PAGE_OFFSET_MSK, PAGE_SIZE - 1
+.equ PAGE_NUMBER_MSK, ~PAGE_OFFSET_MSK
+
+; TLBPD0 bit masks
+.equ REG_PD0_GLOBAL, 0x100 ; Global bit
+.equ REG_PD0_VALID , 0x200 ; Valid bit
+
+; TLBPD1 bit masks
+.equ REG_PD1_KRNL_E, 0x10 ; kernel execute
+.equ REG_PD1_KRNL_W, 0x20 ; kernel write
+.equ REG_PD1_KRNL_R, 0x40 ; kernel read
+
+; TLB commands
+.equ TLB_CMD_WRITE , 0x01 ; write
+.equ TLB_CMD_READ , 0x02 ; read
+.equ TLB_CMD_GET_INDX, 0x03 ; get index
+.equ TLB_CMD_PROBE , 0x04 ; probe
+.equ TLB_CMD_INSERT , 0x07 ; insert
+.equ TLB_CMD_DELETE , 0x08 ; delete
+
+
+.macro extract_page_number address
+ (address & PAGE_NUMBER_MSK)
+.endm
+
+
+; macro: mmu_enable
+; regs used: r11
+;
+; enable MMU on ARC HS systems
+.macro mmu_enable
+ lr r11, [REG_PID]
+ or r11, r11, REG_PID_TLB_SET
+ sr r11, [REG_PID]
+.endm
+
+
+; macro: mmu_disable
+; regs used: r11
+;
+; disable MMU on ARC HS systems
+.macro mmu_disable
+ lr r11, [REG_PID]
+ and r11, r11, REG_PID_TLB_CLR
+ sr r11, [REG_PID]
+.endm
+
+
+; macro: mmu_tlb_insert
+; regs used: r11
+;
+; inserts (TLBPD0, TLBPD1) registers as a TLB entry
+.macro mmu_tlb_insert PD0, PD1
+ mov r11, \PD0
+ sr r11, [REG_PD0]
+ mov r11, \PD1
+ sr r11, [REG_PD1]
+ mov r11, TLB_CMD_INSERT
+ sr r11, [REG_TLB_CMD]
+.endm
+
+
+; macro: mmu_tlb_delete
+; regs used: r11
+;
+; removes any entry with PD0 as page description
+.macro mmu_tlb_delete PD0, PD1
+ mov r11, \PD0
+ sr r11, [REG_PD0]
+ mov r11, \PD1
+ sr r11, [REG_PD1]
+ mov r11, TLB_CMD_INSERT
+ sr r11, [REG_TLB_CMD]
+.endm
+; vim: set syntax=asm ts=2 sw=2 et:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;; Test checking routines ;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Test case counter
+.data
+mmu_test_nr:
+ .word 0x0
+
+; Increment the test counter
+.macro mmu_prep_test_case
+ ld r13, [mmu_test_nr]
+ add_s r13, r13, 1 ; increase test case counter
+ st r13, [mmu_test_nr]
+ mmu_disable
+ set_except_handler 0x0
+ enable_alignment
+.endm
+
+; Increment the test counter
+.macro mmu_prep_test_case_address
+ st pcl, [mmu_test_nr]
+.endm
+
+; Disable alignment so there will be no Misaligned exception
+.macro disable_alignment
+ lr r11, [status32]
+ bset r11, r11, STATUS32_AD_BIT
+ flag r11
+.endm
+
+; Enable alignment again.
+.macro enable_alignment
+ lr r11, [status32]
+ bclr r11, r11, STATUS32_AD_BIT
+ flag r11
+.endm
diff --git a/tests/tcg/arc/mpu.inc b/tests/tcg/arc/mpu.inc
new file mode 100644
index 0000000000..421cd96846
--- /dev/null
+++ b/tests/tcg/arc/mpu.inc
@@ -0,0 +1,269 @@
+; MPU related defines and macros
+
+ .equ REG_MPU_EN_EN , 0x40000000 ; enable bit
+ .equ REG_MPU_EN_KR , 0b100000000 ; kernel read
+ .equ REG_MPU_EN_KW , 0b010000000 ; kernel write
+ .equ REG_MPU_EN_KE , 0b001000000 ; kernel execute
+ .equ REG_MPU_EN_UR , 0b000100000 ; user read
+ .equ REG_MPU_EN_UW , 0b000010000 ; user write
+ .equ REG_MPU_EN_UE , 0b000001000 ; user execute
+ .equ REG_MPU_EN_MSK, REG_MPU_EN_EN | REG_MPU_EN_KR | REG_MPU_EN_KW | REG_MPU_EN_KE | REG_MPU_EN_UR | REG_MPU_EN_UW | REG_MPU_EN_UE
+
+ ; full access for user ===> if a user can access, kernel can too
+ .equ REG_MPU_EN_FULL_ACCESS, REG_MPU_EN_UR | REG_MPU_EN_UW | REG_MPU_EN_UE
+
+ .equ MPU_SIZE_32B , 0b00100
+ .equ MPU_SIZE_64B , 0b00101
+ .equ MPU_SIZE_128B, 0b00110
+ .equ MPU_SIZE_256B, 0b00111
+ .equ MPU_SIZE_512B, 0b01000
+ .equ MPU_SIZE_1K , 0b01001
+ .equ MPU_SIZE_2K , 0b01010
+ .equ MPU_SIZE_4K , 0b01011
+ .equ MPU_SIZE_8K , 0b01100
+ .equ MPU_SIZE_16K , 0b01101
+ .equ MPU_SIZE_32K , 0b01110
+ .equ MPU_SIZE_64K , 0b01111
+ .equ MPU_SIZE_128K, 0b10000
+ .equ MPU_SIZE_256K, 0b10001
+ .equ MPU_SIZE_512K, 0b10010
+ .equ MPU_SIZE_1M , 0b10011
+ .equ MPU_SIZE_2M , 0b10100
+ .equ MPU_SIZE_4M , 0b10101
+ .equ MPU_SIZE_8M , 0b10110
+ .equ MPU_SIZE_16M , 0b10111
+ .equ MPU_SIZE_32M , 0b11000
+ .equ MPU_SIZE_64M , 0b11001
+ .equ MPU_SIZE_128M, 0b11010
+ .equ MPU_SIZE_256M, 0b11011
+ .equ MPU_SIZE_512M, 0b11100
+ .equ MPU_SIZE_1G , 0b11101
+ .equ MPU_SIZE_2G , 0b11110
+ .equ MPU_SIZE_4G , 0b11111
+
+ ; least byte is used for region
+ .equ MPU_ECR_FETCH, 0x060000
+ .equ MPU_ECR_READ, 0x060100
+ .equ MPU_ECR_WRITE, 0x060200
+ .equ MPU_ECR_RW, 0x060300
+
+ .equ PROTV_FETCH_MPU, 0x060004
+ .equ PROTV_READ_MPU, 0x060104
+ .equ PROTV_WRITE_MPU, 0x060204
+ .equ PROTV_RW_MPU, 0x060304
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Macro: mpu_enable
+; Regs used: r11
+;
+; Enable MPU on ARC HS systems
+; "def_access" determines the _default region_ access
+.macro mpu_enable def_access=REG_MPU_EN_FULL_ACCESS
+ mov r11, \def_access
+ or r11, r11, REG_MPU_EN_EN
+ and r11, r11, REG_MPU_EN_MSK
+ sr r11, [mpuen]
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+.macro mpu_disable
+ mov r11, 0
+ sr r11, [mpuen]
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Macro: mpu_add_base
+; Regs used: r11
+;
+; Adds the base address to the given MPU base register.
+; "reg" is the mpu base register: mpurdb0 ... mpurdb15
+; "addr" is the base address you are interested in, e.g.: 0x4000
+.macro mpu_add_base reg, addr
+ mov r11, \addr
+ and r11, r11, 0xffffffe0 ; the last 5 bits must be 0
+ or r11, r11, 1 ; set valid flag
+ sr r11, [\reg]
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Macro: mpu_add_region
+; Regs used: r11, r12
+;
+; Adds the region permission and size to the given MPU permission register.
+; "reg" is the mpu permission register: mpurdp0 ... mpurdp15
+; "access" detemines the access type
+; "size" is the region size: 00100b (32 bytes) ... 11111b (4 gigabytes)
+.macro mpu_add_region reg, access, size=0b100
+ mov r12, \size
+ and r11, r12, 3 ; get the lower 2 bits
+ asl r12, r12, 7 ; getting the upper 3 bits in position
+ and r12, r12, 0xe00 ; keeping only bits[11:9] in place
+ or r11, r11, r12 ; r11 has the size bits now
+ or r11, r11, \access
+ sr r11, [\reg]
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Macro: mpu_reset
+; Regs used: r11
+;
+; Resets all the regions and disables MPU
+.macro mpu_reset
+ lr r12, [mpu_build]
+ and r11, r12, 0xff
+ breq r11, 0, @6666f ; no mpu? then skip!
+ mpu_disable
+ lsr r12, r12, 8
+ brlt r12, 1, @6666f ; no region at all? then skip!
+ mov r11, 0
+ sr r11, [mpurdb0]
+ sr r11, [mpurdp0]
+ brlt r12, 2, @6666f ; only 1 region? then skip!
+ sr r11, [mpurdb1]
+ sr r11, [mpurdp1]
+ brlt r12, 4, @6666f ; only 2 regions? then skip!
+ sr r11, [mpurdb2]
+ sr r11, [mpurdp2]
+ sr r11, [mpurdb3]
+ sr r11, [mpurdp3]
+ brlt r12, 8, @6666f ; only 4 regions? then skip!
+ sr r11, [mpurdb4]
+ sr r11, [mpurdp4]
+ sr r11, [mpurdb5]
+ sr r11, [mpurdp5]
+ sr r11, [mpurdb6]
+ sr r11, [mpurdp6]
+ sr r11, [mpurdb7]
+ sr r11, [mpurdp7]
+ brlt r12, 16, @6666f ; only 8 regions? then skip!
+ sr r11, [mpurdb8]
+ sr r11, [mpurdp8]
+ sr r11, [mpurdb9]
+ sr r11, [mpurdp9]
+ sr r11, [mpurdb10]
+ sr r11, [mpurdp10]
+ sr r11, [mpurdb11]
+ sr r11, [mpurdp11]
+ sr r11, [mpurdb12]
+ sr r11, [mpurdp12]
+ sr r11, [mpurdb13]
+ sr r11, [mpurdp13]
+ sr r11, [mpurdb14]
+ sr r11, [mpurdp14]
+ sr r11, [mpurdb15]
+ sr r11, [mpurdp15]
+6666:
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; These are the parameters that the ProtV exception routine uses as reference
+; There are tests that want to disable the R(ead) permission for the whole
+; memory layout, but they do make an exception for the parameters below. To
+; achieve that, they allow reading for a region of 32 bytes (minimum possible
+; size for a region) that these parameters reside in. Therefore, we have to
+; make sure these are the one and only things in this region by guarding them
+; with ".align 32" and nothing else.
+ .align 32
+mpu_ecr_ref: .word 0x0
+ecr_ref : .word 0x0
+efa_ref : .word 0x0
+eret_ref : .word 0x0
+cont_addr : .word 0x0
+ .align 32
+
+; Exception: Protection Violation
+; Regs used: r11, r12
+;
+; This is a parameterized ProtV exception that will check the followings:
+; mpuic == mpu_ecr_ref
+; ecr == ecr_ref
+; efa == efa_ref
+; eret == eret_ref
+; If everything passes, it will jump to 'cont_addr' parameter. It will clear
+; the user bit before the jump, i.e. if an exception is raised in user mode,
+; the continuation after exception will be in kernel mode. If the check
+; should fail, it jumps to "fail" label which must exist in the test file.
+; The parameters must be set beforehand using 'mpu_set_except_params' macro.
+; Last but not least, this requires ivt.S file to be compiled and linked.
+ .align 4
+ .global instruction_error
+ .global EV_PrivilegeV
+ .global EV_ProtV
+ .type instruction_error, @function
+ .type EV_PrivilegeV, @function
+ .type EV_ProtV, @function
+instruction_error:
+EV_PrivilegeV:
+EV_ProtV:
+ ld r11, [mpu_ecr_ref]
+ lr r12, [mpuic]
+ cmp r12, r11
+ bne @fail
+ ld r11, [ecr_ref]
+ lr r12, [ecr]
+ cmp r12, r11
+ bne @fail
+ ld r11, [eret_ref]
+ lr r12, [eret]
+ cmp r12, r11
+ bne @fail
+ ld r11, [efa_ref]
+ lr r12, [efa]
+ cmp r12, r11
+ bne @fail
+ ; going back to the given address in kernel mode
+ ld r11, [cont_addr]
+ sr r11, [eret]
+ lr r11, [erstatus]
+ and r11, r11, ~0x80 ; clear user mode bit
+ sr r11, [erstatus]
+ rtie
+
+; Macro: mpu_set_except_params
+; Regs used: r11
+;
+; This macro writes the provided parameters to a temporary place holder
+; that later will be used by ProtV exception above to verify as reference.
+.macro mpu_set_except_params mpu_ecr, ecr, efa, eret, continue
+ mov r11, \mpu_ecr
+ st r11, [mpu_ecr_ref]
+ mov r11, \ecr
+ st r11, [ecr_ref]
+ mov r11, \efa
+ st r11, [efa_ref]
+ mov r11, \eret
+ st r11, [eret_ref]
+ mov r11, \continue
+ st r11, [cont_addr]
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Macro: mpu_verify_data
+; Regs used: r11, r12
+;
+; Reads the data at the given address and check if it holds a certain value.
+; It requires the test source file to have "fail" label.
+.macro mpu_verify_data ref, addr
+ ld r11, [\addr]
+ mov r12, \ref
+ cmp r11, r12
+ bne @fail
+.endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Macro: mpu_write_data
+; Regs used: r11, r12
+.macro mpu_write_data data, addr
+ mov r11, \data
+ st r11, [\addr]
+.endm
+
+; vim: set syntax=asm ts=2 sw=2 et:
diff --git a/tests/tcg/arc/tarc.ld b/tests/tcg/arc/tarc.ld
new file mode 100644
index 0000000000..8146162d12
--- /dev/null
+++ b/tests/tcg/arc/tarc.ld
@@ -0,0 +1,15 @@
+ENTRY(main)
+SECTIONS
+{
+ .ivt 0x00 :
+ {
+ KEEP (*(.ivt));
+ }
+ . = 0x100;
+ .text : { *(.text) }
+ .data : { *(.data) }
+ .bss : { *(.bss COMMON) }
+ . = ALIGN(8);
+ . = . + 0x1000; /* 4kB of stack memory */
+ stack_top = .;
+}
diff --git a/tests/tcg/arc/tarc_mmu.ld b/tests/tcg/arc/tarc_mmu.ld
new file mode 100644
index 0000000000..4112c0a927
--- /dev/null
+++ b/tests/tcg/arc/tarc_mmu.ld
@@ -0,0 +1,15 @@
+ENTRY(main)
+SECTIONS
+{
+ .ivt 0x80000000 :
+ {
+ KEEP (*(.ivt));
+ }
+ . = 0x80000100;
+ .text : { *(.text) }
+ .data : { *(.data) }
+ .bss : { *(.bss COMMON) }
+ . = ALIGN(8);
+ . = . + 0x1000; /* 4kB of stack memory */
+ stack_top = .;
+}
diff --git a/tests/tcg/arc/test_macros.h b/tests/tcg/arc/test_macros.h
new file mode 100644
index 0000000000..15325e1ffa
--- /dev/null
+++ b/tests/tcg/arc/test_macros.h
@@ -0,0 +1,257 @@
+#ifndef __TEST_MACROS_SCALAR_H
+#define __TEST_MACROS_SCALAR_H
+
+#ifdef ARCTEST_ARC32
+#define __arc_xlen 32
+#else
+#define __arc_xlen 64
+#endif
+
+#define xstr(a) str(a)
+#define str(a) #a
+
+#define MASK_XLEN(x) ((x) & ((1 << (__arc_xlen - 1) << 1) - 1))
+#define SEXT_IMM(x) ((x) | (-(((x) >> 11) & 1) << 11))
+
+#define TEST_CASE( testnum, testreg, correctval, name, code... ) \
+ test_ ## testnum: \
+ code` \
+ mov r12, testnum` \
+ sub.f 0,testreg, correctval` \
+ bne @fail` \
+ PASS_TEST(name)
+
+#define TEST_IMM_OP( testnum, inst, result, val1, imm ) \
+ TEST_CASE( testnum, r0, result, xstr(inst) ":" xstr(testnum), \
+ mov r1, MASK_XLEN(val1)` \
+ inst r0, r1, SEXT_IMM(imm) \
+ )
+
+#define TEST_RR_3OP( testnum, inst, result, val1, val2 ) \
+ TEST_CASE( testnum, r0, result, xstr(inst) ":" xstr(testnum), \
+ mov r1, MASK_XLEN(val1)` \
+ mov r2, MASK_XLEN(val2)` \
+ inst r0, r1, r2 \
+ )
+
+#define TEST_RR_2OP( testnum, inst, result, val) \
+ TEST_CASE( testnum, r0, result, xstr(inst) ":" xstr(testnum), \
+ mov r1, MASK_XLEN(val)` \
+ inst r0, r1 \
+ )
+
+#define TEST_IMM_SRC1_EQ_DEST( testnum, inst, result, val1, imm ) \
+ TEST_CASE( testnum, r1, result, xstr(inst) ":" xstr(testnum), \
+ mov r1, MASK_XLEN(val1)` \
+ inst r1, r1, SEXT_IMM(imm) \
+ )
+
+#define TEST_RR_SRC1_EQ_DEST( testnum, inst, result, val1, val2 ) \
+ TEST_CASE( testnum, r1, result, xstr(inst) ":" xstr(testnum), \
+ mov r1, MASK_XLEN(val1)` \
+ mov r2, MASK_XLEN(val2)` \
+ inst r1, r1, r2 \
+ )
+
+#define TEST_RR_2OP_SRC1_EQ_DEST( testnum, inst, result, val ) \
+ TEST_CASE( testnum, r1, result, xstr(inst) ":" xstr(testnum), \
+ mov r1, MASK_XLEN(val)` \
+ inst r1, r1 \
+ )
+
+#define TEST_RR_SRC2_EQ_DEST( testnum, inst, result, val1, val2 ) \
+ TEST_CASE( testnum, r2, result, xstr(inst) ":" xstr(testnum), \
+ mov r1, MASK_XLEN(val1)` \
+ mov r2, MASK_XLEN(val2)` \
+ inst r2, r1, r2 \
+ )
+
+#define TEST_RR_SRC12_EQ_DEST( testnum, inst, result, val1 ) \
+ TEST_CASE( testnum, r1, result, xstr(inst) ":" xstr(testnum), \
+ mov r1, MASK_XLEN(val1)` \
+ inst r1, r1, r1 \
+ )
+
+#define TEST_2OP_CARRY( testnum, inst, expected, val1, val2) \
+ test_ ## testnum: \
+ mov r12, testnum` \
+ mov r1, MASK_XLEN(val1)` \
+ mov r2, MASK_XLEN(val2)` \
+ inst.f 0, r1, r2` \
+ mov.cs r3,(~expected) & 0x01` \
+ mov.cc r3, (expected) & 0x01` \
+ cmp r3, 0` \
+ bne @fail
+
+#define TEST_1OP_CARRY( testnum, inst, expected, val) \
+ test_ ## testnum: \
+ mov r12, testnum` \
+ add.f 0, r0, r0` \
+ mov r1, MASK_XLEN(val)` \
+ inst.f 0, r1` \
+ mov.cs r3,(~expected) & 0x01` \
+ mov.cc r3, (expected) & 0x01` \
+ cmp r3, 0` \
+ bne @fail
+
+#define TEST_2OP_ZERO( testnum, inst, expected, val1, val2) \
+ test_ ## testnum: \
+ mov r12, testnum` \
+ mov r1, MASK_XLEN(val1)` \
+ mov r2, MASK_XLEN(val2)` \
+ inst.f 0, r1, r2` \
+ mov.eq r3, (~expected) & 0x01` \
+ mov.ne r3, (expected) & 0x01` \
+ cmp r3, 0` \
+ bne @fail
+
+#define TEST_1OP_ZERO( testnum, inst, expected, val) \
+ test_ ## testnum: \
+ mov r12, testnum` \
+ add.f 0, r0, r0` \
+ mov r1, MASK_XLEN(val)` \
+ inst.f 0, r1` \
+ mov.eq r3, (~expected) & 0x01` \
+ mov.ne r3, (expected) & 0x01` \
+ cmp r3, 0` \
+ bne @fail
+
+#define TEST_2OP_OVERFLOW( testnum, inst, expected, val1, val2) \
+ test_ ## testnum: \
+ mov r12, testnum` \
+ mov r1, MASK_XLEN(val1)` \
+ mov r2, MASK_XLEN(val2)` \
+ inst.f 0, r1, r2` \
+ mov.vs r3,(~expected) & 0x01` \
+ mov.vc r3, (expected) & 0x01` \
+ cmp r3, 0` \
+ bne @fail
+
+#define TEST_1OP_OVERFLOW( testnum, inst, expected, val) \
+ test_ ## testnum: \
+ mov r12, testnum` \
+ add.f 0, r0, r0` \
+ mov r1, MASK_XLEN(val)` \
+ inst.f 0, r1` \
+ mov.vs r3,(~expected) & 0x01` \
+ mov.vc r3, (expected) & 0x01` \
+ cmp r3, 0` \
+ bne @fail
+
+#define TEST_2OP_NEGATIVE( testnum, inst, expected, val1, val2) \
+ test_ ## testnum: \
+ mov r12, testnum` \
+ mov r1, MASK_XLEN(val1)` \
+ mov r2, MASK_XLEN(val2)` \
+ inst.f 0, r1, r2` \
+ mov.mi r3,(~expected) & 0x01` \
+ mov.pl r3, (expected) & 0x01` \
+ cmp r3, 0` \
+ bne @fail
+
+#define TEST_1OP_NEGATIVE( testnum, inst, expected, val) \
+ test_ ## testnum: \
+ mov r12, testnum` \
+ add.f 0, r0, r0` \
+ mov r1, MASK_XLEN(val)` \
+ inst.f 0, r1` \
+ mov.mi r3,(~expected) & 0x01` \
+ mov.pl r3, (expected) & 0x01` \
+ cmp r3, 0` \
+ bne @fail
+
+
+#endif
+
+#define TEST_BR2_OP_TAKEN( testnum, inst, val1, val2 ) \
+ test_ ## testnum:` \
+ mov r12, testnum` \
+ mov r1, val1` \
+ mov r2, val2` \
+ sub.f 0,r1,r2` \
+ inst 1f` \
+ b @fail` \
+ 1:
+
+#define TEST_BR2_OP_NOTTAKEN( testnum, inst, val1, val2 ) \
+ test_ ## testnum:` \
+ mov r12,testnum` \
+ mov r1, val1` \
+ mov r2, val2` \
+ sub.f 0,r1,r2` \
+ inst @fail
+
+#define TEST_BR_OP_TAKEN( testnum, inst, val1, val2 ) \
+ test_ ## testnum:` \
+ mov r12, testnum` \
+ mov r1, val1` \
+ mov r2, val2` \
+ inst r1,r2,1f` \
+ b @fail` \
+ 1:
+
+#define TEST_BR_OP_NOTTAKEN( testnum, inst, val1, val2 ) \
+ test_ ## testnum:` \
+ mov r12,testnum` \
+ mov r1, val1` \
+ mov r2, val2` \
+ inst r1,r2,@fail
+
+#define ARCTEST_BEGIN \
+ .text` \
+ .align 4 ` \
+ .global main` \
+ main: \
+ test_1:` \
+ mov r12,1` \
+ mov.f 0,0` \
+ bne @fail
+
+#define ARCTEST_END \
+ .align 4 ` \
+1:`\
+ st 1,[0xf0000008]`\
+ b @1b`\
+fail:`\
+ mov r2, '['`\
+ st r2, [0x90000000]`\
+ mov r2, 'F'`\
+ st r2, [0x90000000]`\
+ mov r2, 'a'`\
+ st r2, [0x90000000]`\
+ mov r2, 'i'`\
+ st r2, [0x90000000]`\
+ mov r2, 'l'`\
+ st r2, [0x90000000]`\
+ mov r2, ']'`\
+ st r2, [0x90000000]`\
+ mov r2, ' '`\
+ st r2, [0x90000000]`\
+ mov r13, r12`\
+ mov r15, 0x30`\
+ mov r14, r12`\
+loop_z: `\
+ sub.f r13, r13, 0x0A`\
+ add.pl r15, r15, 1`\
+ mov.pl r14, r13 `\
+ bpl @loop_z`\
+ st r15, [0x90000000]`\
+ add r14, r14, 0x30`\
+ st r14, [0x90000000]`\
+ mov r2, '\n'`\
+ st r2, [0x90000000]`\
+ b 1b`
+
+#define PASS_TEST(name)\
+ .data ` \
+2010:`\
+ .ascii "[PASS] ",name ,"\n\0"` \
+ .align 4`\
+ .text`\
+ mov_s r11, @2010b`\
+ 1010:`\
+ ldb.ab r12, [r11, 1]`\
+ breq r12, 0, @1011f`\
+ stb r12, [0x90000000]`\
+ j @1010b`\
+ 1011:`
diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh
index e1b70e25f2..a486ad9b32 100755
--- a/tests/tcg/configure.sh
+++ b/tests/tcg/configure.sh
@@ -47,6 +47,7 @@ fi
: ${cross_cc_aarch64_be="$cross_cc_aarch64"}
: ${cross_cc_cflags_aarch64_be="-mbig-endian"}
: $(cross_cc_alpha="alpha-linux-gnu-gcc")
+: ${cross_cc_arc="arc-elf32-gcc"}
: ${cross_cc_arm="arm-linux-gnueabihf-gcc"}
: ${cross_cc_cflags_armeb="-mbig-endian"}
: ${cross_cc_hppa="hppa-linux-gnu-gcc"}
@@ -94,7 +95,7 @@ for target in $target_list; do
xtensa|xtensaeb)
arches=xtensa
;;
- alpha|cris|hppa|i386|lm32|microblaze|microblazeel|m68k|openrisc|riscv64|s390x|sh4|sparc64)
+ arc|alpha|cris|hppa|i386|lm32|microblaze|microblazeel|m68k|openrisc|riscv64|s390x|sh4|sparc64)
arches=$target
;;
*)
--
2.20.1
© 2016 - 2024 Red Hat, Inc.