Pārlūkot izejas kodu

Merge tag 'pull-tricore-20230607' of https://github.com/bkoppelmann/qemu into staging

- Refactor PCXI/ICR field handling in newer ISA versions
- Add simple tests written in C

# -----BEGIN PGP SIGNATURE-----
#
# iQJTBAABCgA9FiEEbmNqfoPy3Qz6bm43CtLGOWtpyhQFAmSArqkfHGtiYXN0aWFu
# QG1haWwudW5pLXBhZGVyYm9ybi5kZQAKCRAK0sY5a2nKFKKTD/0dXpexGX7K62d4
# dLZwj9AHOa/9NOD4E6+ub2UYovF7UlydSzy+mgJyxiIUGaPBHYe3dFfktHOppSwn
# OGJp9TTqeutpXYF8/zvDnmf+TDJ71DRQWM40uC0HAUXrjUO43PiK0LMh+fm5D9uG
# vRHSDGBWUNZrNxTZSj8Kx7Sb7PkqeB8qWvpIJh1AVVhIT+dyoAp5V7EkAETpwhtz
# a7qKclQpFNWdaYnthCF5wcmoMawQKMUnO96j0lQWIXfnhDP7XmrWlNM7Ry2cMPEy
# aRxAT3hTOr2dD2Cic8brF/w1NeXJjxWDz65uD7X7Rog54+SD4+SmfZiYwdAs5YMo
# 1XTkbG0qE6HwrtaO+nZDQZFc8tdvLSlDcBd/cjOonwxJyvJVX8qjR2Ufb3PSfTct
# 85R5wRBsEapSbQwicwu71fK0N8ZVkLM3fc4nFEKMxOx8I66eJm3bcTxpT/A8knEw
# OwykEVB3Xiq45JlWOV2BkyZJ1EiHeFQzZfzckW4bYFDdCnuMHlaVG9qpKEAu7mQh
# 4Ug3Y4KhYqZA0UDHG6Ik6Ms64FYU4s+zbFYic/Jhew9NC4MoMXa8oKqXJC5W7RCl
# 1HesyBPu1i/45Xk6/kneJ16YO+i4hcH+Hp/osJrRE6qFHGtbvKJ0EFy1471YHyLf
# HjRQBmsd9XW2TaYBQgST80UvCh9CkQ==
# =5m1P
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 07 Jun 2023 09:22:01 AM PDT
# gpg:                using RSA key 6E636A7E83F2DD0CFA6E6E370AD2C6396B69CA14
# gpg:                issuer "kbastian@mail.uni-paderborn.de"
# gpg: Good signature from "Bastian Koppelmann <kbastian@mail.uni-paderborn.de>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 6E63 6A7E 83F2 DD0C FA6E  6E37 0AD2 C639 6B69 CA14

* tag 'pull-tricore-20230607' of https://github.com/bkoppelmann/qemu:
  tests/tcg/tricore: Add recursion test for CSAs
  target/tricore: Fix wrong PSW for call insns
  target/tricore: Refactor PCXI/ICR register fields
  tests/tcg/tricore: Add first C program
  tests/tcg/tricore: Uses label for memory addresses
  tests/tcg/tricore: Move asm tests into 'asm' directory

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Richard Henderson 2 gadi atpakaļ
vecāks
revīzija
45ae97993a

+ 1 - 0
configure

@@ -1383,6 +1383,7 @@ probe_target_compiler() {
         container_cross_prefix=tricore-
         container_cross_as=tricore-as
         container_cross_ld=tricore-ld
+        container_cross_cc=tricore-gcc
         break
         ;;
       x86_64)

+ 28 - 11
target/tricore/cpu.h

@@ -21,6 +21,7 @@
 #define TRICORE_CPU_H
 
 #include "cpu-qom.h"
+#include "hw/registerfields.h"
 #include "exec/cpu-defs.h"
 #include "qemu/cpu-float.h"
 #include "tricore-defs.h"
@@ -199,13 +200,33 @@ struct ArchCPU {
 hwaddr tricore_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
 void tricore_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
 
-
-#define MASK_PCXI_PCPN 0xff000000
-#define MASK_PCXI_PIE_1_3  0x00800000
-#define MASK_PCXI_PIE_1_6  0x00200000
-#define MASK_PCXI_UL   0x00400000
-#define MASK_PCXI_PCXS 0x000f0000
-#define MASK_PCXI_PCXO 0x0000ffff
+FIELD(PCXI, PCPN_13, 24, 8)
+FIELD(PCXI, PCPN_161, 22, 8)
+FIELD(PCXI, PIE_13, 23, 1)
+FIELD(PCXI, PIE_161, 21, 1)
+FIELD(PCXI, UL_13, 22, 1)
+FIELD(PCXI, UL_161, 20, 1)
+FIELD(PCXI, PCXS, 16, 4)
+FIELD(PCXI, PCXO, 0, 16)
+uint32_t pcxi_get_ul(CPUTriCoreState *env);
+uint32_t pcxi_get_pie(CPUTriCoreState *env);
+uint32_t pcxi_get_pcpn(CPUTriCoreState *env);
+uint32_t pcxi_get_pcxs(CPUTriCoreState *env);
+uint32_t pcxi_get_pcxo(CPUTriCoreState *env);
+void pcxi_set_ul(CPUTriCoreState *env, uint32_t val);
+void pcxi_set_pie(CPUTriCoreState *env, uint32_t val);
+void pcxi_set_pcpn(CPUTriCoreState *env, uint32_t val);
+
+FIELD(ICR, IE_161, 15, 1)
+FIELD(ICR, IE_13, 8, 1)
+FIELD(ICR, PIPN, 16, 8)
+FIELD(ICR, CCPN, 0, 8)
+
+uint32_t icr_get_ie(CPUTriCoreState *env);
+uint32_t icr_get_ccpn(CPUTriCoreState *env);
+
+void icr_set_ccpn(CPUTriCoreState *env, uint32_t val);
+void icr_set_ie(CPUTriCoreState *env, uint32_t val);
 
 #define MASK_PSW_USB 0xff000000
 #define MASK_USB_C   0x80000000
@@ -228,10 +249,6 @@ void tricore_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
 #define MASK_CPUID_MOD_32B 0x0000ff00
 #define MASK_CPUID_REV     0x000000ff
 
-#define MASK_ICR_PIPN 0x00ff0000
-#define MASK_ICR_IE_1_3   0x00000100
-#define MASK_ICR_IE_1_6   0x00008000
-#define MASK_ICR_CCPN 0x000000ff
 
 #define MASK_FCX_FCXS 0x000f0000
 #define MASK_FCX_FCXO 0x0000ffff

+ 45 - 0
target/tricore/helper.c

@@ -17,6 +17,7 @@
 
 #include "qemu/osdep.h"
 #include "qemu/log.h"
+#include "hw/registerfields.h"
 #include "cpu.h"
 #include "exec/exec-all.h"
 #include "fpu/softfloat-helpers.h"
@@ -152,3 +153,47 @@ void psw_write(CPUTriCoreState *env, uint32_t val)
 
     fpu_set_state(env);
 }
+
+#define FIELD_GETTER_WITH_FEATURE(NAME, REG, FIELD, FEATURE)     \
+uint32_t NAME(CPUTriCoreState *env)                             \
+{                                                                \
+    if (tricore_feature(env, TRICORE_FEATURE_##FEATURE)) {       \
+        return FIELD_EX32(env->REG, REG, FIELD ## _ ## FEATURE); \
+    }                                                            \
+    return FIELD_EX32(env->REG, REG, FIELD ## _13);              \
+}
+
+#define FIELD_GETTER(NAME, REG, FIELD)       \
+uint32_t NAME(CPUTriCoreState *env)         \
+{                                            \
+    return FIELD_EX32(env->REG, REG, FIELD); \
+}
+
+#define FIELD_SETTER_WITH_FEATURE(NAME, REG, FIELD, FEATURE)              \
+void NAME(CPUTriCoreState *env, uint32_t val)                            \
+{                                                                         \
+    if (tricore_feature(env, TRICORE_FEATURE_##FEATURE)) {                \
+        env->REG = FIELD_DP32(env->REG, REG, FIELD ## _ ## FEATURE, val); \
+    }                                                                     \
+    env->REG = FIELD_DP32(env->REG, REG, FIELD ## _13, val);              \
+}
+
+#define FIELD_SETTER(NAME, REG, FIELD)                \
+void NAME(CPUTriCoreState *env, uint32_t val)        \
+{                                                     \
+    env->REG = FIELD_DP32(env->REG, REG, FIELD, val); \
+}
+
+FIELD_GETTER_WITH_FEATURE(pcxi_get_pcpn, PCXI, PCPN, 161)
+FIELD_SETTER_WITH_FEATURE(pcxi_set_pcpn, PCXI, PCPN, 161)
+FIELD_GETTER_WITH_FEATURE(pcxi_get_pie, PCXI, PIE, 161)
+FIELD_SETTER_WITH_FEATURE(pcxi_set_pie, PCXI, PIE, 161)
+FIELD_GETTER_WITH_FEATURE(pcxi_get_ul, PCXI, UL, 161)
+FIELD_SETTER_WITH_FEATURE(pcxi_set_ul, PCXI, UL, 161)
+FIELD_GETTER(pcxi_get_pcxs, PCXI, PCXS)
+FIELD_GETTER(pcxi_get_pcxo, PCXI, PCXO)
+
+FIELD_GETTER_WITH_FEATURE(icr_get_ie, ICR, IE, 161)
+FIELD_SETTER_WITH_FEATURE(icr_set_ie, ICR, IE, 161)
+FIELD_GETTER(icr_get_ccpn, ICR, CCPN)
+FIELD_SETTER(icr_set_ccpn, ICR, CCPN)

+ 44 - 43
target/tricore/op_helper.c

@@ -84,11 +84,10 @@ void raise_exception_sync_internal(CPUTriCoreState *env, uint32_t class, int tin
       ICR.IE and ICR.CCPN are saved */
 
     /* PCXI.PIE = ICR.IE */
-    env->PCXI = ((env->PCXI & ~MASK_PCXI_PIE_1_3) +
-                ((env->ICR & MASK_ICR_IE_1_3) << 15));
+    pcxi_set_pie(env, icr_get_ie(env));
+
     /* PCXI.PCPN = ICR.CCPN */
-    env->PCXI = (env->PCXI & 0xffffff) +
-                ((env->ICR & MASK_ICR_CCPN) << 24);
+    pcxi_set_pcpn(env, icr_get_ccpn(env));
     /* Update PC using the trap vector table */
     env->PC = env->BTV | (class << 5);
 
@@ -2448,6 +2447,8 @@ void helper_call(CPUTriCoreState *env, uint32_t next_pc)
     }
     /* PSW.CDE = 1;*/
     psw |= MASK_PSW_CDE;
+    psw_write(env, psw);
+
     /* tmp_FCX = FCX; */
     tmp_FCX = env->FCX;
     /* EA = {FCX.FCXS, 6'b0, FCX.FCXO, 6'b0}; */
@@ -2461,13 +2462,11 @@ void helper_call(CPUTriCoreState *env, uint32_t next_pc)
     save_context_upper(env, ea);
 
     /* PCXI.PCPN = ICR.CCPN; */
-    env->PCXI = (env->PCXI & 0xffffff) +
-                ((env->ICR & MASK_ICR_CCPN) << 24);
+    pcxi_set_pcpn(env, icr_get_ccpn(env));
     /* PCXI.PIE = ICR.IE; */
-    env->PCXI = ((env->PCXI & ~MASK_PCXI_PIE_1_3) +
-                ((env->ICR & MASK_ICR_IE_1_3) << 15));
+    pcxi_set_pie(env, icr_get_ie(env));
     /* PCXI.UL = 1; */
-    env->PCXI |= MASK_PCXI_UL;
+    pcxi_set_ul(env, 1);
 
     /* PCXI[19: 0] = FCX[19: 0]; */
     env->PCXI = (env->PCXI & 0xfff00000) + (env->FCX & 0xfffff);
@@ -2506,7 +2505,7 @@ void helper_ret(CPUTriCoreState *env)
         raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_CSU, GETPC());
     }
     /* if (PCXI.UL == 0) then trap(CTYP); */
-    if ((env->PCXI & MASK_PCXI_UL) == 0) {
+    if (pcxi_get_ul(env) == 0) {
         /* CTYP trap */
         cdc_increment(&psw); /* restore to the start of helper */
         psw_write(env, psw);
@@ -2516,8 +2515,8 @@ void helper_ret(CPUTriCoreState *env)
     env->PC = env->gpr_a[11] & 0xfffffffe;
 
     /* EA = {PCXI.PCXS, 6'b0, PCXI.PCXO, 6'b0}; */
-    ea = ((env->PCXI & MASK_PCXI_PCXS) << 12) +
-         ((env->PCXI & MASK_PCXI_PCXO) << 6);
+    ea = (pcxi_get_pcxs(env) << 28) |
+         (pcxi_get_pcxo(env) << 6);
     /* {new_PCXI, new_PSW, A[10], A[11], D[8], D[9], D[10], D[11], A[12],
         A[13], A[14], A[15], D[12], D[13], D[14], D[15]} = M(EA, 16 * word); */
     restore_context_upper(env, ea, &new_PCXI, &new_PSW);
@@ -2559,21 +2558,21 @@ void helper_bisr(CPUTriCoreState *env, uint32_t const9)
 
 
     /* PCXI.PCPN = ICR.CCPN */
-    env->PCXI = (env->PCXI & 0xffffff) +
-                 ((env->ICR & MASK_ICR_CCPN) << 24);
+    pcxi_set_pcpn(env, icr_get_ccpn(env));
     /* PCXI.PIE  = ICR.IE */
-    env->PCXI = ((env->PCXI & ~MASK_PCXI_PIE_1_3) +
-                 ((env->ICR & MASK_ICR_IE_1_3) << 15));
+    pcxi_set_pie(env, icr_get_ie(env));
     /* PCXI.UL = 0 */
-    env->PCXI &= ~(MASK_PCXI_UL);
+    pcxi_set_ul(env, 0);
+
     /* PCXI[19: 0] = FCX[19: 0] */
     env->PCXI = (env->PCXI & 0xfff00000) + (env->FCX & 0xfffff);
     /* FXC[19: 0] = new_FCX[19: 0] */
     env->FCX = (env->FCX & 0xfff00000) + (new_FCX & 0xfffff);
+
     /* ICR.IE = 1 */
-    env->ICR |= MASK_ICR_IE_1_3;
+    icr_set_ie(env, 1);
 
-    env->ICR |= const9; /* ICR.CCPN = const9[7: 0];*/
+    icr_set_ccpn(env, const9);
 
     if (tmp_FCX == env->LCX) {
         /* FCD trap */
@@ -2592,7 +2591,7 @@ void helper_rfe(CPUTriCoreState *env)
         raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_CSU, GETPC());
     }
     /* if (PCXI.UL == 0) then trap(CTYP); */
-    if ((env->PCXI & MASK_PCXI_UL) == 0) {
+    if (pcxi_get_ul(env) == 0) {
         /* raise CTYP trap */
         raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_CTYP, GETPC());
     }
@@ -2603,14 +2602,15 @@ void helper_rfe(CPUTriCoreState *env)
     }
     env->PC = env->gpr_a[11] & ~0x1;
     /* ICR.IE = PCXI.PIE; */
-    env->ICR = (env->ICR & ~MASK_ICR_IE_1_3)
-            + ((env->PCXI & MASK_PCXI_PIE_1_3) >> 15);
+    icr_set_ie(env, pcxi_get_pie(env));
+
     /* ICR.CCPN = PCXI.PCPN; */
-    env->ICR = (env->ICR & ~MASK_ICR_CCPN) +
-               ((env->PCXI & MASK_PCXI_PCPN) >> 24);
+    icr_set_ccpn(env, pcxi_get_pcpn(env));
+
     /*EA = {PCXI.PCXS, 6'b0, PCXI.PCXO, 6'b0};*/
-    ea = ((env->PCXI & MASK_PCXI_PCXS) << 12) +
-         ((env->PCXI & MASK_PCXI_PCXO) << 6);
+    ea = (pcxi_get_pcxs(env) << 28) |
+         (pcxi_get_pcxo(env) << 6);
+
     /*{new_PCXI, PSW, A[10], A[11], D[8], D[9], D[10], D[11], A[12],
       A[13], A[14], A[15], D[12], D[13], D[14], D[15]} = M(EA, 16 * word); */
     restore_context_upper(env, ea, &new_PCXI, &new_PSW);
@@ -2628,11 +2628,10 @@ void helper_rfm(CPUTriCoreState *env)
 {
     env->PC = (env->gpr_a[11] & ~0x1);
     /* ICR.IE = PCXI.PIE; */
-    env->ICR = (env->ICR & ~MASK_ICR_IE_1_3)
-            | ((env->PCXI & MASK_PCXI_PIE_1_3) >> 15);
+    icr_set_ie(env, pcxi_get_pie(env));
     /* ICR.CCPN = PCXI.PCPN; */
-    env->ICR = (env->ICR & ~MASK_ICR_CCPN) |
-               ((env->PCXI & MASK_PCXI_PCPN) >> 24);
+    icr_set_ccpn(env, pcxi_get_pcpn(env));
+
     /* {PCXI, PSW, A[10], A[11]} = M(DCX, 4 * word); */
     env->PCXI = cpu_ldl_data(env, env->DCX);
     psw_write(env, cpu_ldl_data(env, env->DCX+4));
@@ -2691,13 +2690,13 @@ void helper_svlcx(CPUTriCoreState *env)
     save_context_lower(env, ea);
 
     /* PCXI.PCPN = ICR.CCPN; */
-    env->PCXI = (env->PCXI & 0xffffff) +
-                ((env->ICR & MASK_ICR_CCPN) << 24);
+    pcxi_set_pcpn(env, icr_get_ccpn(env));
+
     /* PCXI.PIE = ICR.IE; */
-    env->PCXI = ((env->PCXI & ~MASK_PCXI_PIE_1_3) +
-                ((env->ICR & MASK_ICR_IE_1_3) << 15));
+    pcxi_set_pie(env, icr_get_ie(env));
+
     /* PCXI.UL = 0; */
-    env->PCXI &= ~MASK_PCXI_UL;
+    pcxi_set_ul(env, 0);
 
     /* PCXI[19: 0] = FCX[19: 0]; */
     env->PCXI = (env->PCXI & 0xfff00000) + (env->FCX & 0xfffff);
@@ -2734,13 +2733,13 @@ void helper_svucx(CPUTriCoreState *env)
     save_context_upper(env, ea);
 
     /* PCXI.PCPN = ICR.CCPN; */
-    env->PCXI = (env->PCXI & 0xffffff) +
-                ((env->ICR & MASK_ICR_CCPN) << 24);
+    pcxi_set_pcpn(env, icr_get_ccpn(env));
+
     /* PCXI.PIE = ICR.IE; */
-    env->PCXI = ((env->PCXI & ~MASK_PCXI_PIE_1_3) +
-                ((env->ICR & MASK_ICR_IE_1_3) << 15));
+    pcxi_set_pie(env, icr_get_ie(env));
+
     /* PCXI.UL = 1; */
-    env->PCXI |= MASK_PCXI_UL;
+    pcxi_set_ul(env, 1);
 
     /* PCXI[19: 0] = FCX[19: 0]; */
     env->PCXI = (env->PCXI & 0xfff00000) + (env->FCX & 0xfffff);
@@ -2764,13 +2763,15 @@ void helper_rslcx(CPUTriCoreState *env)
         raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_CSU, GETPC());
     }
     /* if (PCXI.UL == 1) then trap(CTYP); */
-    if ((env->PCXI & MASK_PCXI_UL) != 0) {
+    if (pcxi_get_ul(env) == 1) {
         /* CTYP trap */
         raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_CTYP, GETPC());
     }
     /* EA = {PCXI.PCXS, 6'b0, PCXI.PCXO, 6'b0}; */
-    ea = ((env->PCXI & MASK_PCXI_PCXS) << 12) +
-         ((env->PCXI & MASK_PCXI_PCXO) << 6);
+    /* EA = {PCXI.PCXS, 6'b0, PCXI.PCXO, 6'b0}; */
+    ea = (pcxi_get_pcxs(env) << 28) |
+         (pcxi_get_pcxo(env) << 6);
+
     /* {new_PCXI, A[11], A[10], A[11], D[8], D[9], D[10], D[11], A[12],
         A[13], A[14], A[15], D[12], D[13], D[14], D[15]} = M(EA, 16 * word); */
     restore_context_lower(env, ea, &env->gpr_a[11], &new_PCXI);

+ 8 - 2
target/tricore/translate.c

@@ -75,6 +75,7 @@ typedef struct DisasContext {
     int mem_idx;
     uint32_t hflags, saved_hflags;
     uint64_t features;
+    uint32_t icr_ie_mask;
 } DisasContext;
 
 static int has_feature(DisasContext *ctx, int feature)
@@ -7850,12 +7851,12 @@ static void decode_sys_interrupts(DisasContext *ctx)
         /* raise EXCP_DEBUG */
         break;
     case OPC2_32_SYS_DISABLE:
-        tcg_gen_andi_tl(cpu_ICR, cpu_ICR, ~MASK_ICR_IE_1_3);
+        tcg_gen_andi_tl(cpu_ICR, cpu_ICR, ~ctx->icr_ie_mask);
         break;
     case OPC2_32_SYS_DSYNC:
         break;
     case OPC2_32_SYS_ENABLE:
-        tcg_gen_ori_tl(cpu_ICR, cpu_ICR, MASK_ICR_IE_1_3);
+        tcg_gen_ori_tl(cpu_ICR, cpu_ICR, ctx->icr_ie_mask);
         break;
     case OPC2_32_SYS_ISYNC:
         break;
@@ -8259,6 +8260,11 @@ static void tricore_tr_init_disas_context(DisasContextBase *dcbase,
     ctx->mem_idx = cpu_mmu_index(env, false);
     ctx->hflags = (uint32_t)ctx->base.tb->flags;
     ctx->features = env->features;
+    if (has_feature(ctx, TRICORE_FEATURE_161)) {
+        ctx->icr_ie_mask = R_ICR_IE_161_MASK;
+    } else {
+        ctx->icr_ie_mask = R_ICR_IE_13_MASK;
+    }
 }
 
 static void tricore_tr_tb_start(DisasContextBase *db, CPUState *cpu)

+ 32 - 17
tests/tcg/tricore/Makefile.softmmu-target

@@ -1,34 +1,49 @@
 TESTS_PATH = $(SRC_PATH)/tests/tcg/tricore
+ASM_TESTS_PATH = $(TESTS_PATH)/asm
+C_TESTS_PATH = $(TESTS_PATH)/c
 
 LDFLAGS = -T$(TESTS_PATH)/link.ld --mcpu=tc162
 ASFLAGS = -mtc162
+CFLAGS = -mtc162 -c -I$(TESTS_PATH)
 
-TESTS += test_abs.tst
-TESTS += test_bmerge.tst
-TESTS += test_clz.tst
-TESTS += test_dextr.tst
-TESTS += test_dvstep.tst
-TESTS += test_fadd.tst
-TESTS += test_fmul.tst
-TESTS += test_ftoi.tst
-TESTS += test_imask.tst
-TESTS += test_insert.tst
-TESTS += test_ld_bu.tst
-TESTS += test_ld_h.tst
-TESTS += test_madd.tst
-TESTS += test_msub.tst
-TESTS += test_muls.tst
+TESTS += test_abs.asm.tst
+TESTS += test_bmerge.asm.tst
+TESTS += test_clz.asm.tst
+TESTS += test_dextr.asm.tst
+TESTS += test_dvstep.asm.tst
+TESTS += test_fadd.asm.tst
+TESTS += test_fmul.asm.tst
+TESTS += test_ftoi.asm.tst
+TESTS += test_imask.asm.tst
+TESTS += test_insert.asm.tst
+TESTS += test_ld_bu.asm.tst
+TESTS += test_ld_h.asm.tst
+TESTS += test_madd.asm.tst
+TESTS += test_msub.asm.tst
+TESTS += test_muls.asm.tst
+
+TESTS += test_boot_to_main.c.tst
+TESTS += test_context_save_areas.c.tst
 
 QEMU_OPTS += -M tricore_testboard -cpu tc27x -nographic -kernel
 
-%.pS: $(TESTS_PATH)/%.S
+%.pS: $(ASM_TESTS_PATH)/%.S
 	$(HOST_CC) -E -o $@ $<
 
 %.o: %.pS
 	$(AS) $(ASFLAGS) -o $@ $<
 
-%.tst: %.o
+%.asm.tst: %.o
 	$(LD) $(LDFLAGS) $< -o $@
 
+crt0-tc2x.o: $(C_TESTS_PATH)/crt0-tc2x.S
+	$(AS) $(ASFLAGS) -o $@ $<
+
+%.o: $(C_TESTS_PATH)/%.c
+	$(CC) $(CFLAGS) -o $@ $<
+
+%.c.tst: %.o crt0-tc2x.o
+	$(LD) $(LDFLAGS) -o $@ $^
+
 # We don't currently support the multiarch system tests
 undefine MULTIARCH_TESTS

+ 0 - 1
tests/tcg/tricore/macros.h → tests/tcg/tricore/asm/macros.h

@@ -25,7 +25,6 @@
 
 #define AREG_ADDR %a0
 #define AREG_CORRECT_RESULT %a3
-#define MEM_BASE_ADDR 0xd0000000
 
 #define DREG_DEV_ADDR %a15
 

+ 0 - 0
tests/tcg/tricore/test_abs.S → tests/tcg/tricore/asm/test_abs.S


+ 0 - 0
tests/tcg/tricore/test_bmerge.S → tests/tcg/tricore/asm/test_bmerge.S


+ 0 - 0
tests/tcg/tricore/test_clz.S → tests/tcg/tricore/asm/test_clz.S


+ 0 - 0
tests/tcg/tricore/test_dextr.S → tests/tcg/tricore/asm/test_dextr.S


+ 0 - 0
tests/tcg/tricore/test_dvstep.S → tests/tcg/tricore/asm/test_dvstep.S


+ 0 - 0
tests/tcg/tricore/test_fadd.S → tests/tcg/tricore/asm/test_fadd.S


+ 0 - 0
tests/tcg/tricore/test_fmul.S → tests/tcg/tricore/asm/test_fmul.S


+ 0 - 0
tests/tcg/tricore/test_ftoi.S → tests/tcg/tricore/asm/test_ftoi.S


+ 0 - 0
tests/tcg/tricore/test_imask.S → tests/tcg/tricore/asm/test_imask.S


+ 0 - 0
tests/tcg/tricore/test_insert.S → tests/tcg/tricore/asm/test_insert.S


+ 2 - 2
tests/tcg/tricore/test_ld_bu.S → tests/tcg/tricore/asm/test_ld_bu.S

@@ -9,7 +9,7 @@ _start:
 #                            expect. addr reg val after load
 #           insn  num  expect. load value |          pattern for loading
 #             |    |     |                |              |
-    TEST_LD(ld.bu, 1, 0xff, MEM_BASE_ADDR + 4, [+AREG_ADDR]4) # pre_inc
-    TEST_LD(ld.bu, 2, 0xad, MEM_BASE_ADDR + 4, [AREG_ADDR+]4) # post_inc
+    TEST_LD(ld.bu, 1, 0xff, test_data + 4, [+AREG_ADDR]4) # pre_inc
+    TEST_LD(ld.bu, 2, 0xad, test_data + 4, [AREG_ADDR+]4) # post_inc
 
     TEST_PASSFAIL

+ 15 - 0
tests/tcg/tricore/asm/test_ld_h.S

@@ -0,0 +1,15 @@
+#include "macros.h"
+.data
+test_data:
+    .word 0xaffedead
+    .word 0x001122ff
+.text
+.global _start
+_start:
+#                               expect. addr reg val after load
+#              insn  num expect. load value |    pattern for loading
+#                |    |     |               |          |
+    TEST_LD    (ld.h, 1, 0xffffaffe, test_data, [AREG_ADDR]2)
+    TEST_LD_SRO(ld.h, 2, 0x000022ff, test_data, [AREG_ADDR]4)
+
+    TEST_PASSFAIL

+ 0 - 0
tests/tcg/tricore/test_madd.S → tests/tcg/tricore/asm/test_madd.S


+ 0 - 0
tests/tcg/tricore/test_msub.S → tests/tcg/tricore/asm/test_msub.S


+ 0 - 0
tests/tcg/tricore/test_muls.S → tests/tcg/tricore/asm/test_muls.S


+ 335 - 0
tests/tcg/tricore/c/crt0-tc2x.S

@@ -0,0 +1,335 @@
+/*
+ * crt0-tc2x.S -- Startup code for GNU/TriCore applications.
+ *
+ * Copyright (C) 1998-2014 HighTec EDV-Systeme GmbH.
+ *
+ * This file is part of GCC.
+ *
+ * GCC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GCC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Under Section 7 of GPL version 3, you are granted additional
+ * permissions described in the GCC Runtime Library Exception, version
+ * 3.1, as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License and
+ * a copy of the GCC Runtime Library Exception along with this program;
+ * see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+ * <http://www.gnu.org/licenses/>.  */
+
+/* Define the Derivate Name as a hexvalue. This value
+ * is built-in defined in tricore-c.c (from tricore-devices.c)
+ * the derivate number as a hexvalue (e.g. TC1796 => 0x1796
+ * This name will be used in the memory.x Memory description to
+ * to confirm that the crt0.o and the memory.x will be get from
+ * same directory
+ */
+    .section ".startup_code", "ax", @progbits
+    .global _start
+    .type _start,@function
+
+/* default BMI header (only TC2xxx devices) */
+    .word   0x00000000
+    .word   0xb3590070
+    .word   0x00000000
+    .word   0x00000000
+    .word   0x00000000
+    .word   0x00000000
+    .word   0x791eb864
+    .word   0x86e1479b
+
+_start:
+    .code32
+    j   _startaddr
+    .align  2
+
+_startaddr:
+    /*
+     * initialize user and interrupt stack pointers
+     */
+    movh.a  %sp,hi:__USTACK         # load %sp
+    lea %sp,[%sp]lo:__USTACK
+    movh    %d0,hi:__ISTACK         # load $isp
+    addi    %d0,%d0,lo:__ISTACK
+    mtcr    $isp,%d0
+    isync
+
+#;  install trap handlers
+
+    movh    %d0,hi:first_trap_table     #; load $btv
+    addi    %d0,%d0,lo:first_trap_table
+    mtcr    $btv,%d0
+    isync
+
+    /*
+     * initialize call depth counter
+     */
+
+    mfcr    %d0,$psw
+    or  %d0,%d0,0x7f            # disable call depth counting
+    andn    %d0,%d0,0x80            # clear CDE bit
+    mtcr    $psw,%d0
+    isync
+
+    /*
+     * initialize access to system global registers
+     */
+
+    mfcr    %d0,$psw
+    or  %d0,%d0,0x100           # set GW bit
+    mtcr    $psw,%d0
+    isync
+
+    /*
+     * initialize SDA base pointers
+     */
+    .global _SMALL_DATA_,_SMALL_DATA2_,_SMALL_DATA3_,_SMALL_DATA4_
+    .weak _SMALL_DATA_,_SMALL_DATA2_,_SMALL_DATA3_,_SMALL_DATA4_
+
+    movh.a  %a0,hi:_SMALL_DATA_     # %a0 addresses .sdata/.sbss
+    lea %a0,[%a0]lo:_SMALL_DATA_
+    movh.a  %a1,hi:_SMALL_DATA2_        # %a1 addresses .sdata2/.sbss2
+    lea %a1,[%a1]lo:_SMALL_DATA2_
+    movh.a  %a8,hi:_SMALL_DATA3_        # %a8 addresses .sdata3/.sbss3
+    lea %a8,[%a8]lo:_SMALL_DATA3_
+    movh.a  %a9,hi:_SMALL_DATA4_        # %a9 addresses .sdata4/.sbss4
+    lea %a9,[%a9]lo:_SMALL_DATA4_
+
+    /*
+     * reset access to system global registers
+     */
+
+    mfcr    %d0,$psw
+    andn    %d0,%d0,0x100           # clear GW bit
+    mtcr    $psw,%d0
+    isync
+
+    /*
+     * initialize context save areas
+     */
+
+    jl  __init_csa
+
+
+
+    /*
+     * handle clear table (i.e., fill BSS with zeros)
+     */
+
+    jl  __clear_table_func
+
+
+    /*
+     * handle copy table (support for romable code)
+     */
+
+    jl  __copy_table_func
+
+
+    /*
+     * _exit (main (0, NULL));
+     */
+    mov %d4,0               # argc = 0
+    sub.a   %sp,8
+    st.w    [%sp]0,%d4
+    st.w    [%sp]4,%d4
+    mov.aa  %a4,%sp             # argv
+
+    call    main                # int retval = main (0, NULL);
+    mov.a   %a14,%d2        # move exit code to match trap handler
+    j   _exit               # _exit (retval);
+
+    debug                   # should never come here
+
+
+    /*
+     * initialize context save areas (CSAs), PCXI, LCX and FCX
+     */
+
+    .global __init_csa
+    .type __init_csa,function
+
+__init_csa:
+    movh    %d0,0
+    mtcr    $pcxi,%d0
+    isync
+    movh    %d0,hi:__CSA_BEGIN      #; %d0 = begin of CSA
+    addi    %d0,%d0,lo:__CSA_BEGIN
+    addi    %d0,%d0,63          #; force alignment (2^6)
+    andn    %d0,%d0,63
+    movh    %d2,hi:__CSA_END        #; %d2 = end of CSA
+    addi    %d2,%d2,lo:__CSA_END
+    andn    %d2,%d2,63          #; force alignment (2^6)
+    sub %d2,%d2,%d0
+    sh  %d2,%d2,-6          #; %d2 = number of CSAs
+    mov.a   %a3,%d0             #; %a3 = address of first CSA
+    extr.u  %d0,%d0,28,4            #; %d0 = segment << 16
+    sh  %d0,%d0,16
+    lea %a4,0               #; %a4 = previous CSA = 0
+    st.a    [%a3],%a4           #; store it in 1st CSA
+    mov.aa  %a4,%a3             #; %a4 = current CSA
+    lea %a3,[%a3]64         #; %a3 = %a3->nextCSA
+    mov.d   %d1,%a3
+    extr.u  %d1,%d1,6,16            #; get CSA index
+    or  %d1,%d1,%d0         #; add segment number
+    mtcr    $lcx,%d1            #; initialize LCX
+    add %d2,%d2,-2          #; CSAs to initialize -= 2
+    mov.a   %a5,%d2             #; %a5 = loop counter
+csa_loop:
+    mov.d   %d1,%a4             #; %d1 = current CSA address
+    extr.u  %d1,%d1,6,16            #; get CSA index
+    or  %d1,%d1,%d0         #; add segment number
+    st.w    [%a3],%d1           #; store "nextCSA" pointer
+    mov.aa  %a4,%a3             #; %a4 = current CSA address
+    lea %a3,[%a3]64         #; %a3 = %a3->nextCSA
+    loop    %a5,csa_loop            #; repeat until done
+
+    mov.d   %d1,%a4             #; %d1 = current CSA address
+    extr.u  %d1,%d1,6,16            #; get CSA index
+    or  %d1,%d1,%d0         #; add segment number
+    mtcr    $fcx,%d1            #; initialize FCX
+    isync
+    ji  %a11
+
+
+
+
+    /*
+     * handle clear table (i.e., fill BSS with zeros)
+     */
+    .global __clear_table_func
+    .type __clear_table_func,@function
+
+__clear_table_func:
+    mov %d14,0              # %e14 = 0
+    mov %d15,0
+    movh.a  %a13,hi:__clear_table       # %a13 = &first table entry
+    lea %a13,[%a13]lo:__clear_table
+
+__clear_table_next:
+    ld.a    %a15,[%a13+]4           # %a15 = current block base
+    ld.w    %d3,[%a13+]4            # %d3 = current block length
+    jeq %d3,-1,__clear_table_done   # length == -1 => end of table
+    sh  %d0,%d3,-3          # %d0 = length / 8 (doublewords)
+    and %d1,%d3,7           # %d1 = length % 8 (rem. bytes)
+    jz  %d0,__clear_word        # block size < 8 => clear word
+    addi    %d0,%d0,-1          # else doublewords -= 1
+    mov.a   %a2,%d0             # %a2 = loop counter
+__clear_dword:
+    st.d    [%a15+]8,%e14           # clear one doubleword
+    loop    %a2,__clear_dword
+__clear_word:
+    jz  %d1,__clear_table_next
+    sh  %d0,%d1,-2          # %d0 = length / 4 (words)
+    and %d1,%d1,3           # %d1 = length % 4 (rem. bytes)
+    jz  %d0,__clear_hword       # block size < 4 => clear hword
+    st.w    [%a15+]4,%d15           # clear one word
+__clear_hword:
+    jz  %d1,__clear_table_next
+    sh  %d0,%d1,-1          # %d0 = length / 2 (halfwords)
+    and %d1,%d1,1           # %d1 = length % 2 (rem. bytes)
+    jz  %d0,__clear_byte        # block size < 2 => clear byte
+    st.h    [%a15+]2,%d15           # clear one halfword
+__clear_byte:
+    jz  %d1,__clear_table_next
+    st.b    [%a15],%d15         # clear one byte
+    j   __clear_table_next      # handle next clear table entry
+__clear_table_done:
+
+    ji  %a11
+
+
+
+    /*
+     * handle copy table (support for romable code)
+     */
+    .global __copy_table_func
+    .type __copy_table_func,@function
+
+__copy_table_func:
+    movh.a  %a13,hi:__copy_table        # %a13 = &first table entry
+    lea %a13,[%a13]lo:__copy_table
+
+__copy_table_next:
+    ld.a    %a15,[%a13+]4           # %a15 = src address
+    ld.a    %a14,[%a13+]4           # %a14 = dst address
+    ld.w    %d3,[%a13+]4            # %d3 = block length
+    jeq %d3,-1,__copy_table_done    # length == -1 => end of table
+    sh  %d0,%d3,-3          # %d0 = length / 8 (doublewords)
+    and %d1,%d3,7           # %d1 = lenght % 8 (rem. bytes)
+    jz  %d0,__copy_word         # block size < 8 => copy word
+    addi    %d0,%d0,-1          # else doublewords -= 1
+    mov.a   %a2,%d0             # %a2 = loop counter
+__copy_dword:
+    ld.d    %e14,[%a15+]8           # copy one doubleword
+    st.d    [%a14+]8,%e14
+    loop    %a2,__copy_dword
+__copy_word:
+    jz  %d1,__copy_table_next
+    sh  %d0,%d1,-2          # %d0 = length / 4 (words)
+    and %d1,%d1,3           # %d1 = lenght % 4 (rem. bytes)
+    jz  %d0,__copy_hword        # block size < 4 => copy hword
+    ld.w    %d14,[%a15+]4           # copy one word
+    st.w    [%a14+]4,%d14
+__copy_hword:
+    jz  %d1,__copy_table_next
+    sh  %d0,%d1,-1          # %d0 = length / 2 (halfwords)
+    and %d1,%d1,1           # %d1 = length % 2 (rem. bytes)
+    jz  %d0,__copy_byte         # block size < 2 => copy byte
+    ld.h    %d14,[%a15+]2           # copy one halfword
+    st.h    [%a14+]2,%d14
+__copy_byte:
+    jz  %d1,__copy_table_next
+    ld.b    %d14,[%a15]0            # copy one byte
+    st.b    [%a14],%d14
+    j   __copy_table_next       # handle next copy table entry
+__copy_table_done:
+
+    ji  %a11
+
+_exit:
+    movh.a %a15, hi:__TESTDEVICE
+    lea %a15,[%a15]lo:__TESTDEVICE
+    mov.d %d2, %a14
+    st.w [%a15], %d2 # write exit code to testdevice
+    debug
+
+/*============================================================================*
+ * Exception handlers (exceptions in startup code)
+ *
+ * This is a minimal trap vector table, which consists of eight
+ * entries, each consisting of eight words (32 bytes).
+ *============================================================================*/
+
+
+#;  .section .traptab, "ax", @progbits
+
+.macro trapentry from=0, to=7
+    mov.u   %d14, \from << 8
+    add %d14,%d14,%d15
+    mov.a   %a14,%d14
+    addih.a %a14,%a14,0 # if we trap, we fail
+    j   _exit
+0:
+    j   0b
+    nop
+    rfe
+    .align 5
+
+    .if \to-\from
+    trapentry "(\from+1)",\to
+    .endif
+.endm
+
+    .align 8
+    .global first_trap_table
+first_trap_table:
+    trapentry 0, 7
+

+ 13 - 0
tests/tcg/tricore/c/test_boot_to_main.c

@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2023 Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+#include "testdev_assert.h"
+int main(int argc, char **argv)
+{
+    testdev_assert(1);
+    return 0;
+}

+ 15 - 0
tests/tcg/tricore/c/test_context_save_areas.c

@@ -0,0 +1,15 @@
+#include "testdev_assert.h"
+
+static int fib(int n)
+{
+    if (n == 1 || n == 2) {
+        return 1;
+    }
+    return fib(n - 2) + fib(n - 1);
+}
+
+int main(int argc, char **argv)
+{
+    testdev_assert(fib(10) == 55);
+    return 0;
+}

+ 18 - 0
tests/tcg/tricore/c/testdev_assert.h

@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2023 Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+int *testdev = (int *)0xf0000000;
+
+#define FAIL 1
+static inline void testdev_assert(int condition)
+{
+    if (!condition) {
+        *testdev = FAIL;
+        asm("debug");
+    }
+}
+

+ 16 - 0
tests/tcg/tricore/link.ld

@@ -12,6 +12,7 @@ MEMORY
 /*
  * Define the sizes of the user and system stacks.
  */
+__ISTACK_SIZE = DEFINED (__ISTACK_SIZE) ? __ISTACK_SIZE : 256 ;
 __USTACK_SIZE = DEFINED (__USTACK_SIZE) ? __USTACK_SIZE : 1K ;
 /*
  * Define the start address and the size of the context save area.
@@ -20,6 +21,8 @@ __CSA_BEGIN =  0xd0000000 ;
 __CSA_SIZE =  8k ;
 __CSA_END = __CSA_BEGIN + __CSA_SIZE ;
 
+__TESTDEVICE = 0xf0000000 ;
+
 SECTIONS
 {
   .text  :
@@ -32,6 +35,18 @@ SECTIONS
   {
     *(.rodata)
     *(.rodata1)
+    /*
+     * Create the clear and copy tables that tell the startup code
+     * which memory areas to clear and to copy, respectively.
+     */
+    . = ALIGN(4) ;
+    PROVIDE(__clear_table = .) ;
+    LONG(0 + ADDR(.bss));     LONG(SIZEOF(.bss));
+    LONG(-1);                 LONG(-1);
+    PROVIDE(__copy_table = .) ;
+    LONG(LOADADDR(.data));    LONG(0 + ADDR(.data));    LONG(SIZEOF(.data));
+    LONG(-1);                 LONG(-1);                 LONG(-1);
+    . = ALIGN(8);
   } > data_ram
 
   .data :
@@ -40,6 +55,7 @@ SECTIONS
     *(.data)
     *(.data.*)
     . = ALIGN(8) ;
+    __ISTACK = . + __ISTACK_SIZE ;
     __USTACK = . + __USTACK_SIZE -768;
 
   } > data_ram

+ 0 - 15
tests/tcg/tricore/test_ld_h.S

@@ -1,15 +0,0 @@
-#include "macros.h"
-.data
-test_data:
-    .word 0xaffedead
-    .word 0x001122ff
-.text
-.global _start
-_start:
-#                               expect. addr reg val after load
-#              insn  num  expect. load value |          pattern for loading
-#                |    |     |                |              |
-    TEST_LD    (ld.h, 1, 0xffffaffe, MEM_BASE_ADDR, [AREG_ADDR]2)
-    TEST_LD_SRO(ld.h, 2, 0x000022ff, MEM_BASE_ADDR, [AREG_ADDR]4)
-
-    TEST_PASSFAIL