- Implement privilege levels for TriCore

- Fix missing REG_PAIR() for insns using two 32 regs
 - Fix erroneously saving PSW.CDC on CALL insns
 - Added some missing v1.6.2 insns
 -----BEGIN PGP SIGNATURE-----
 
 iQJTBAABCgA9FiEEbmNqfoPy3Qz6bm43CtLGOWtpyhQFAmSTIWsfHGtiYXN0aWFu
 QG1haWwudW5pLXBhZGVyYm9ybi5kZQAKCRAK0sY5a2nKFEVCEACQFRGj/7ADOWm3
 lhkHGgkwpTgx+YKgeI4rfQ5/AKie9b7BUNljPVp1m2AvPFHU/r/0POzziCTDM+Ty
 M90h5gsEgxNRRVS1T+VkfFTKop7yImo48niDBF4mByP9DZGweCvGEvPD2g/FYvLP
 0Up13F0NiWKMvocKp/jjI5qejpJqwtn1hjWHTpEXya3u+K/iEku1alI72Xo2oMKW
 pKW2iO/mC4cuEzOdpZt4LSzs9ZMsVpFzVn81VIda9CU2rlSpu+oQevgdWWJhgZGa
 520JnIsrervsJumBWPxh9R0nrjuhHu34I4HXD38eGhD+Ioz2DQnHy2bA99pIVR7B
 qtHoDNhl7wqWgXBqntS9HvnvDAFyYdVM6aLqw9C7AxKXdRBuxy14R3/hrwMZghRs
 vYx3GUcFHSMJT1tkc8a/P14/mz5SB6/cdjVgPQtTCPBJccly4oc4EG3qn7wYqowZ
 Pbq48h+3+QZ7BsC9sT2AiPq+AmLjxRZRq7SE6YrYrjRDIJz/3IoTR600KW5XsFsj
 gZu/SYWdbNXAVr4c7CCg77lXXQ2/GhPHgCYFjL3djIKwlPP79bhT4cvLXK71yF/4
 3RcCBt9kRggxDz6E/4I+u5cE4oMbyN1f6AoIn80GUheDstWMACYph5RhbIskxRhY
 PWwJ8ML0c7SOy0A74UbCT82gn1He1A==
 =IKrz
 -----END PGP SIGNATURE-----

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

- Implement privilege levels for TriCore
- Fix missing REG_PAIR() for insns using two 32 regs
- Fix erroneously saving PSW.CDC on CALL insns
- Added some missing v1.6.2 insns

# -----BEGIN PGP SIGNATURE-----
#
# iQJTBAABCgA9FiEEbmNqfoPy3Qz6bm43CtLGOWtpyhQFAmSTIWsfHGtiYXN0aWFu
# QG1haWwudW5pLXBhZGVyYm9ybi5kZQAKCRAK0sY5a2nKFEVCEACQFRGj/7ADOWm3
# lhkHGgkwpTgx+YKgeI4rfQ5/AKie9b7BUNljPVp1m2AvPFHU/r/0POzziCTDM+Ty
# M90h5gsEgxNRRVS1T+VkfFTKop7yImo48niDBF4mByP9DZGweCvGEvPD2g/FYvLP
# 0Up13F0NiWKMvocKp/jjI5qejpJqwtn1hjWHTpEXya3u+K/iEku1alI72Xo2oMKW
# pKW2iO/mC4cuEzOdpZt4LSzs9ZMsVpFzVn81VIda9CU2rlSpu+oQevgdWWJhgZGa
# 520JnIsrervsJumBWPxh9R0nrjuhHu34I4HXD38eGhD+Ioz2DQnHy2bA99pIVR7B
# qtHoDNhl7wqWgXBqntS9HvnvDAFyYdVM6aLqw9C7AxKXdRBuxy14R3/hrwMZghRs
# vYx3GUcFHSMJT1tkc8a/P14/mz5SB6/cdjVgPQtTCPBJccly4oc4EG3qn7wYqowZ
# Pbq48h+3+QZ7BsC9sT2AiPq+AmLjxRZRq7SE6YrYrjRDIJz/3IoTR600KW5XsFsj
# gZu/SYWdbNXAVr4c7CCg77lXXQ2/GhPHgCYFjL3djIKwlPP79bhT4cvLXK71yF/4
# 3RcCBt9kRggxDz6E/4I+u5cE4oMbyN1f6AoIn80GUheDstWMACYph5RhbIskxRhY
# PWwJ8ML0c7SOy0A74UbCT82gn1He1A==
# =IKrz
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 21 Jun 2023 06:12:27 PM CEST
# gpg:                using RSA key 6E636A7E83F2DD0CFA6E6E370AD2C6396B69CA14
# gpg:                issuer "kbastian@mail.uni-paderborn.de"
# gpg: Good signature from "Bastian Koppelmann <kbastian@mail.uni-paderborn.de>" [undefined]
# 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-20230621-1' of https://github.com/bkoppelmann/qemu:
  target/tricore: Fix ICR.IE offset in RESTORE insn
  target/tricore: Honour privilege changes on PSW write
  target/tricore: Implement privilege level for all insns
  target/tricore: Introduce priv tb flag
  target/tricore: Indirect jump insns use tcg_gen_lookup_and_goto_ptr()
  target/tricore: ENABLE exit to main-loop
  target/tricore: Introduce DISAS_TARGET_EXIT
  target/tricore: Fix RR_JLI clobbering reg A[11]
  target/tricore: Fix helper_ret() not correctly restoring PSW
  target/tricore: Add CHECK_REG_PAIR() for insn accessing 64 bit regs
  target/tricore: Correctly fix saving PSW.CDE to CSA on call
  target/tricore: Fix out-of-bounds index in imask instruction
  target/tricore: Add DISABLE insn variant
  target/tricore: Implement SYCSCALL insn
  target/tricore: Add shuffle insn
  target/tricore: Add crc32.b insn
  target/tricore: Add crc32l.w insn
  target/tricore: Add LHA insn
  target/tricore: Add popcnt.w insn
  target/tricore: Introduce ISA 1.6.2 feature

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2023-06-21 20:08:48 +02:00
commit 67fe6ae41d
6 changed files with 237 additions and 51 deletions

View File

@ -104,6 +104,10 @@ static void tricore_cpu_realizefn(DeviceState *dev, Error **errp)
} }
/* Some features automatically imply others */ /* Some features automatically imply others */
if (tricore_feature(env, TRICORE_FEATURE_162)) {
set_feature(env, TRICORE_FEATURE_161);
}
if (tricore_feature(env, TRICORE_FEATURE_161)) { if (tricore_feature(env, TRICORE_FEATURE_161)) {
set_feature(env, TRICORE_FEATURE_16); set_feature(env, TRICORE_FEATURE_16);
} }
@ -164,6 +168,14 @@ static void tc27x_initfn(Object *obj)
set_feature(&cpu->env, TRICORE_FEATURE_161); set_feature(&cpu->env, TRICORE_FEATURE_161);
} }
static void tc37x_initfn(Object *obj)
{
TriCoreCPU *cpu = TRICORE_CPU(obj);
set_feature(&cpu->env, TRICORE_FEATURE_162);
}
#include "hw/core/sysemu-cpu-ops.h" #include "hw/core/sysemu-cpu-ops.h"
static const struct SysemuCPUOps tricore_sysemu_ops = { static const struct SysemuCPUOps tricore_sysemu_ops = {
@ -226,6 +238,7 @@ static const TypeInfo tricore_cpu_type_infos[] = {
DEFINE_TRICORE_CPU_TYPE("tc1796", tc1796_initfn), DEFINE_TRICORE_CPU_TYPE("tc1796", tc1796_initfn),
DEFINE_TRICORE_CPU_TYPE("tc1797", tc1797_initfn), DEFINE_TRICORE_CPU_TYPE("tc1797", tc1797_initfn),
DEFINE_TRICORE_CPU_TYPE("tc27x", tc27x_initfn), DEFINE_TRICORE_CPU_TYPE("tc27x", tc27x_initfn),
DEFINE_TRICORE_CPU_TYPE("tc37x", tc37x_initfn),
}; };
DEFINE_TYPES(tricore_cpu_type_infos) DEFINE_TYPES(tricore_cpu_type_infos)

View File

@ -263,16 +263,18 @@ void icr_set_ie(CPUTriCoreState *env, uint32_t val);
#define MASK_DBGSR_PEVT 0x40 #define MASK_DBGSR_PEVT 0x40
#define MASK_DBGSR_EVTSRC 0x1f00 #define MASK_DBGSR_EVTSRC 0x1f00
#define TRICORE_HFLAG_KUU 0x3 enum tricore_priv_levels {
#define TRICORE_HFLAG_UM0 0x00002 /* user mode-0 flag */ TRICORE_PRIV_UM0 = 0x0, /* user mode-0 flag */
#define TRICORE_HFLAG_UM1 0x00001 /* user mode-1 flag */ TRICORE_PRIV_UM1 = 0x1, /* user mode-1 flag */
#define TRICORE_HFLAG_SM 0x00000 /* kernel mode flag */ TRICORE_PRIV_SM = 0x2, /* kernel mode flag */
};
enum tricore_features { enum tricore_features {
TRICORE_FEATURE_13, TRICORE_FEATURE_13,
TRICORE_FEATURE_131, TRICORE_FEATURE_131,
TRICORE_FEATURE_16, TRICORE_FEATURE_16,
TRICORE_FEATURE_161, TRICORE_FEATURE_161,
TRICORE_FEATURE_162,
}; };
static inline int tricore_feature(CPUTriCoreState *env, int feature) static inline int tricore_feature(CPUTriCoreState *env, int feature)
@ -377,15 +379,21 @@ static inline int cpu_mmu_index(CPUTriCoreState *env, bool ifetch)
#include "exec/cpu-all.h" #include "exec/cpu-all.h"
FIELD(TB_FLAGS, PRIV, 0, 2)
void cpu_state_reset(CPUTriCoreState *s); void cpu_state_reset(CPUTriCoreState *s);
void tricore_tcg_init(void); void tricore_tcg_init(void);
static inline void cpu_get_tb_cpu_state(CPUTriCoreState *env, target_ulong *pc, static inline void cpu_get_tb_cpu_state(CPUTriCoreState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *flags) target_ulong *cs_base, uint32_t *flags)
{ {
uint32_t new_flags = 0;
*pc = env->PC; *pc = env->PC;
*cs_base = 0; *cs_base = 0;
*flags = 0;
new_flags |= FIELD_DP32(new_flags, TB_FLAGS, PRIV,
extract32(env->PSW, 10, 2));
*flags = new_flags;
} }
#define TRICORE_CPU_TYPE_SUFFIX "-" TYPE_TRICORE_CPU #define TRICORE_CPU_TYPE_SUFFIX "-" TYPE_TRICORE_CPU

View File

@ -131,7 +131,10 @@ DEF_HELPER_FLAGS_5(mul_h, TCG_CALL_NO_RWG_SE, i64, i32, i32, i32, i32, i32)
DEF_HELPER_FLAGS_5(mulm_h, TCG_CALL_NO_RWG_SE, i64, i32, i32, i32, i32, i32) DEF_HELPER_FLAGS_5(mulm_h, TCG_CALL_NO_RWG_SE, i64, i32, i32, i32, i32, i32)
DEF_HELPER_FLAGS_5(mulr_h, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32, i32, i32) DEF_HELPER_FLAGS_5(mulr_h, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32, i32, i32)
/* crc32 */ /* crc32 */
DEF_HELPER_FLAGS_2(crc32, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_2(crc32b, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(crc32_be, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(crc32_le, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(shuffle, TCG_CALL_NO_RWG_SE, i32, i32, i32)
/* CSA */ /* CSA */
DEF_HELPER_2(call, void, env, i32) DEF_HELPER_2(call, void, env, i32)
DEF_HELPER_1(ret, void, env) DEF_HELPER_1(ret, void, env)

View File

@ -2284,7 +2284,15 @@ uint32_t helper_mulr_h(uint32_t arg00, uint32_t arg01,
return (result1 & 0xffff0000) | (result0 >> 16); return (result1 & 0xffff0000) | (result0 >> 16);
} }
uint32_t helper_crc32(uint32_t arg0, uint32_t arg1) uint32_t helper_crc32b(uint32_t arg0, uint32_t arg1)
{
uint8_t buf[1] = { arg0 & 0xff };
return crc32(arg1, buf, 1);
}
uint32_t helper_crc32_be(uint32_t arg0, uint32_t arg1)
{ {
uint8_t buf[4]; uint8_t buf[4];
stl_be_p(buf, arg0); stl_be_p(buf, arg0);
@ -2292,6 +2300,50 @@ uint32_t helper_crc32(uint32_t arg0, uint32_t arg1)
return crc32(arg1, buf, 4); return crc32(arg1, buf, 4);
} }
uint32_t helper_crc32_le(uint32_t arg0, uint32_t arg1)
{
uint8_t buf[4];
stl_le_p(buf, arg0);
return crc32(arg1, buf, 4);
}
uint32_t helper_shuffle(uint32_t arg0, uint32_t arg1)
{
uint32_t resb;
uint32_t byte_select;
uint32_t res = 0;
byte_select = arg1 & 0x3;
resb = extract32(arg0, byte_select * 8, 8);
res |= resb << 0;
byte_select = (arg1 >> 2) & 0x3;
resb = extract32(arg0, byte_select * 8, 8);
res |= resb << 8;
byte_select = (arg1 >> 4) & 0x3;
resb = extract32(arg0, byte_select * 8, 8);
res |= resb << 16;
byte_select = (arg1 >> 6) & 0x3;
resb = extract32(arg0, byte_select * 8, 8);
res |= resb << 24;
if (arg1 & 0x100) {
/* Assign the correct nibble position. */
res = ((res & 0xf0f0f0f0) >> 4)
| ((res & 0x0f0f0f0f) << 4);
/* Assign the correct bit position. */
res = ((res & 0x88888888) >> 3)
| ((res & 0x44444444) >> 1)
| ((res & 0x22222222) << 1)
| ((res & 0x11111111) << 3);
}
return res;
}
/* context save area (CSA) related helpers */ /* context save area (CSA) related helpers */
static int cdc_increment(target_ulong *psw) static int cdc_increment(target_ulong *psw)
@ -2447,7 +2499,12 @@ void helper_call(CPUTriCoreState *env, uint32_t next_pc)
} }
/* PSW.CDE = 1;*/ /* PSW.CDE = 1;*/
psw |= MASK_PSW_CDE; psw |= MASK_PSW_CDE;
psw_write(env, psw); /*
* we need to save PSW.CDE and not PSW.CDC into the CSAs. psw already
* contains the CDC from cdc_increment(), so we cannot call psw_write()
* here.
*/
env->PSW |= MASK_PSW_CDE;
/* tmp_FCX = FCX; */ /* tmp_FCX = FCX; */
tmp_FCX = env->FCX; tmp_FCX = env->FCX;
@ -2527,12 +2584,12 @@ void helper_ret(CPUTriCoreState *env)
/* PCXI = new_PCXI; */ /* PCXI = new_PCXI; */
env->PCXI = new_PCXI; env->PCXI = new_PCXI;
if (tricore_feature(env, TRICORE_FEATURE_13)) { if (tricore_feature(env, TRICORE_FEATURE_131)) {
/* PSW = new_PSW */
psw_write(env, new_PSW);
} else {
/* PSW = {new_PSW[31:26], PSW[25:24], new_PSW[23:0]}; */ /* PSW = {new_PSW[31:26], PSW[25:24], new_PSW[23:0]}; */
psw_write(env, (new_PSW & ~(0x3000000)) + (psw & (0x3000000))); psw_write(env, (new_PSW & ~(0x3000000)) + (psw & (0x3000000)));
} else { /* TRICORE_FEATURE_13 only */
/* PSW = new_PSW */
psw_write(env, new_PSW);
} }
} }

View File

@ -37,6 +37,9 @@
#include "exec/helper-info.c.inc" #include "exec/helper-info.c.inc"
#undef HELPER_H #undef HELPER_H
#define DISAS_EXIT DISAS_TARGET_0
#define DISAS_EXIT_UPDATE DISAS_TARGET_1
#define DISAS_JUMP DISAS_TARGET_2
/* /*
* TCG registers * TCG registers
@ -73,9 +76,9 @@ typedef struct DisasContext {
uint32_t opcode; uint32_t opcode;
/* Routine used to access memory */ /* Routine used to access memory */
int mem_idx; int mem_idx;
uint32_t hflags, saved_hflags; int priv;
uint64_t features; uint64_t features;
uint32_t icr_ie_mask; uint32_t icr_ie_mask, icr_ie_offset;
} DisasContext; } DisasContext;
static int has_feature(DisasContext *ctx, int feature) static int has_feature(DisasContext *ctx, int feature)
@ -309,6 +312,7 @@ static void gen_cmpswap(DisasContext *ctx, int reg, TCGv ea)
{ {
TCGv temp = tcg_temp_new(); TCGv temp = tcg_temp_new();
TCGv temp2 = tcg_temp_new(); TCGv temp2 = tcg_temp_new();
CHECK_REG_PAIR(reg);
tcg_gen_qemu_ld_tl(temp, ea, ctx->mem_idx, MO_LEUL); tcg_gen_qemu_ld_tl(temp, ea, ctx->mem_idx, MO_LEUL);
tcg_gen_movcond_tl(TCG_COND_EQ, temp2, cpu_gpr_d[reg+1], temp, tcg_gen_movcond_tl(TCG_COND_EQ, temp2, cpu_gpr_d[reg+1], temp,
cpu_gpr_d[reg], temp); cpu_gpr_d[reg], temp);
@ -321,7 +325,7 @@ static void gen_swapmsk(DisasContext *ctx, int reg, TCGv ea)
TCGv temp = tcg_temp_new(); TCGv temp = tcg_temp_new();
TCGv temp2 = tcg_temp_new(); TCGv temp2 = tcg_temp_new();
TCGv temp3 = tcg_temp_new(); TCGv temp3 = tcg_temp_new();
CHECK_REG_PAIR(reg);
tcg_gen_qemu_ld_tl(temp, ea, ctx->mem_idx, MO_LEUL); tcg_gen_qemu_ld_tl(temp, ea, ctx->mem_idx, MO_LEUL);
tcg_gen_and_tl(temp2, cpu_gpr_d[reg], cpu_gpr_d[reg+1]); tcg_gen_and_tl(temp2, cpu_gpr_d[reg], cpu_gpr_d[reg+1]);
tcg_gen_andc_tl(temp3, temp, cpu_gpr_d[reg+1]); tcg_gen_andc_tl(temp3, temp, cpu_gpr_d[reg+1]);
@ -330,7 +334,6 @@ static void gen_swapmsk(DisasContext *ctx, int reg, TCGv ea)
tcg_gen_mov_tl(cpu_gpr_d[reg], temp); tcg_gen_mov_tl(cpu_gpr_d[reg], temp);
} }
/* We generate loads and store to core special function register (csfr) through /* We generate loads and store to core special function register (csfr) through
the function gen_mfcr and gen_mtcr. To handle access permissions, we use 3 the function gen_mfcr and gen_mtcr. To handle access permissions, we use 3
makros R, A and E, which allow read-only, all and endinit protected access. makros R, A and E, which allow read-only, all and endinit protected access.
@ -374,17 +377,18 @@ static inline void gen_mfcr(DisasContext *ctx, TCGv ret, int32_t offset)
static inline void gen_mtcr(DisasContext *ctx, TCGv r1, static inline void gen_mtcr(DisasContext *ctx, TCGv r1,
int32_t offset) int32_t offset)
{ {
if ((ctx->hflags & TRICORE_HFLAG_KUU) == TRICORE_HFLAG_SM) { if (ctx->priv == TRICORE_PRIV_SM) {
/* since we're caching PSW make this a special case */ /* since we're caching PSW make this a special case */
if (offset == 0xfe04) { if (offset == 0xfe04) {
gen_helper_psw_write(cpu_env, r1); gen_helper_psw_write(cpu_env, r1);
ctx->base.is_jmp = DISAS_EXIT_UPDATE;
} else { } else {
switch (offset) { switch (offset) {
#include "csfr.h.inc" #include "csfr.h.inc"
} }
} }
} else { } else {
/* generate privilege trap */ generate_trap(ctx, TRAPC_PROT, TIN1_PRIV);
} }
} }
@ -2835,6 +2839,7 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
gen_save_pc(dest); gen_save_pc(dest);
tcg_gen_lookup_and_goto_ptr(); tcg_gen_lookup_and_goto_ptr();
} }
ctx->base.is_jmp = DISAS_NORETURN;
} }
static void generate_trap(DisasContext *ctx, int class, int tin) static void generate_trap(DisasContext *ctx, int class, int tin)
@ -2895,8 +2900,7 @@ static void gen_fret(DisasContext *ctx)
tcg_gen_qemu_ld_tl(cpu_gpr_a[11], cpu_gpr_a[10], ctx->mem_idx, MO_LESL); tcg_gen_qemu_ld_tl(cpu_gpr_a[11], cpu_gpr_a[10], ctx->mem_idx, MO_LESL);
tcg_gen_addi_tl(cpu_gpr_a[10], cpu_gpr_a[10], 4); tcg_gen_addi_tl(cpu_gpr_a[10], cpu_gpr_a[10], 4);
tcg_gen_mov_tl(cpu_PC, temp); tcg_gen_mov_tl(cpu_PC, temp);
tcg_gen_exit_tb(NULL, 0); ctx->base.is_jmp = DISAS_EXIT;
ctx->base.is_jmp = DISAS_NORETURN;
} }
static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int r1, static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int r1,
@ -2995,12 +2999,12 @@ static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int r1,
/* SR-format jumps */ /* SR-format jumps */
case OPC1_16_SR_JI: case OPC1_16_SR_JI:
tcg_gen_andi_tl(cpu_PC, cpu_gpr_a[r1], 0xfffffffe); tcg_gen_andi_tl(cpu_PC, cpu_gpr_a[r1], 0xfffffffe);
tcg_gen_exit_tb(NULL, 0); ctx->base.is_jmp = DISAS_EXIT;
break; break;
case OPC2_32_SYS_RET: case OPC2_32_SYS_RET:
case OPC2_16_SR_RET: case OPC2_16_SR_RET:
gen_helper_ret(cpu_env); gen_helper_ret(cpu_env);
tcg_gen_exit_tb(NULL, 0); ctx->base.is_jmp = DISAS_EXIT;
break; break;
/* B-format */ /* B-format */
case OPC1_32_B_CALLA: case OPC1_32_B_CALLA:
@ -3152,7 +3156,6 @@ static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int r1,
default: default:
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
} }
ctx->base.is_jmp = DISAS_NORETURN;
} }
@ -3219,6 +3222,7 @@ static void decode_src_opc(DisasContext *ctx, int op1)
break; break;
case OPC1_16_SRC_MOV_E: case OPC1_16_SRC_MOV_E:
if (has_feature(ctx, TRICORE_FEATURE_16)) { if (has_feature(ctx, TRICORE_FEATURE_16)) {
CHECK_REG_PAIR(r1);
tcg_gen_movi_tl(cpu_gpr_d[r1], const4); tcg_gen_movi_tl(cpu_gpr_d[r1], const4);
tcg_gen_sari_tl(cpu_gpr_d[r1+1], cpu_gpr_d[r1], 31); tcg_gen_sari_tl(cpu_gpr_d[r1+1], cpu_gpr_d[r1], 31);
} else { } else {
@ -3371,7 +3375,11 @@ static void decode_sc_opc(DisasContext *ctx, int op1)
tcg_gen_andi_tl(cpu_gpr_d[15], cpu_gpr_d[15], const16); tcg_gen_andi_tl(cpu_gpr_d[15], cpu_gpr_d[15], const16);
break; break;
case OPC1_16_SC_BISR: case OPC1_16_SC_BISR:
gen_helper_1arg(bisr, const16 & 0xff); if (ctx->priv == TRICORE_PRIV_SM) {
gen_helper_1arg(bisr, const16 & 0xff);
} else {
generate_trap(ctx, TRAPC_PROT, TIN1_PRIV);
}
break; break;
case OPC1_16_SC_LD_A: case OPC1_16_SC_LD_A:
gen_offset_ld(ctx, cpu_gpr_a[15], cpu_gpr_a[10], const16 * 4, MO_LESL); gen_offset_ld(ctx, cpu_gpr_a[15], cpu_gpr_a[10], const16 * 4, MO_LESL);
@ -3493,8 +3501,7 @@ static void decode_sr_system(DisasContext *ctx)
break; break;
case OPC2_16_SR_RFE: case OPC2_16_SR_RFE:
gen_helper_rfe(cpu_env); gen_helper_rfe(cpu_env);
tcg_gen_exit_tb(NULL, 0); ctx->base.is_jmp = DISAS_EXIT;
ctx->base.is_jmp = DISAS_NORETURN;
break; break;
case OPC2_16_SR_DEBUG: case OPC2_16_SR_DEBUG:
/* raise EXCP_DEBUG */ /* raise EXCP_DEBUG */
@ -5011,6 +5018,14 @@ static void decode_rc_logical_shift(DisasContext *ctx)
case OPC2_32_RC_XOR: case OPC2_32_RC_XOR:
tcg_gen_xori_tl(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); tcg_gen_xori_tl(cpu_gpr_d[r2], cpu_gpr_d[r1], const9);
break; break;
case OPC2_32_RC_SHUFFLE:
if (has_feature(ctx, TRICORE_FEATURE_162)) {
TCGv temp = tcg_constant_i32(const9);
gen_helper_shuffle(cpu_gpr_d[r2], cpu_gpr_d[r1], temp);
} else {
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
}
break;
default: default:
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
} }
@ -5225,10 +5240,14 @@ static void decode_rc_serviceroutine(DisasContext *ctx)
switch (op2) { switch (op2) {
case OPC2_32_RC_BISR: case OPC2_32_RC_BISR:
gen_helper_1arg(bisr, const9); if (ctx->priv == TRICORE_PRIV_SM) {
gen_helper_1arg(bisr, const9);
} else {
generate_trap(ctx, TRAPC_PROT, TIN1_PRIV);
}
break; break;
case OPC2_32_RC_SYSCALL: case OPC2_32_RC_SYSCALL:
/* TODO: Add exception generation */ generate_trap(ctx, TRAPC_SYSCALL, const9 & 0xff);
break; break;
default: default:
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
@ -5331,6 +5350,7 @@ static void decode_rcrw_insert(DisasContext *ctx)
switch (op2) { switch (op2) {
case OPC2_32_RCRW_IMASK: case OPC2_32_RCRW_IMASK:
CHECK_REG_PAIR(r4);
tcg_gen_andi_tl(temp, cpu_gpr_d[r3], 0x1f); tcg_gen_andi_tl(temp, cpu_gpr_d[r3], 0x1f);
tcg_gen_movi_tl(temp2, (1 << width) - 1); tcg_gen_movi_tl(temp2, (1 << width) - 1);
tcg_gen_shl_tl(cpu_gpr_d[r4 + 1], temp2, temp); tcg_gen_shl_tl(cpu_gpr_d[r4 + 1], temp2, temp);
@ -6053,8 +6073,8 @@ static void decode_rr_idirect(DisasContext *ctx)
tcg_gen_andi_tl(cpu_PC, cpu_gpr_a[r1], ~0x1); tcg_gen_andi_tl(cpu_PC, cpu_gpr_a[r1], ~0x1);
break; break;
case OPC2_32_RR_JLI: case OPC2_32_RR_JLI:
tcg_gen_movi_tl(cpu_gpr_a[11], ctx->pc_succ_insn);
tcg_gen_andi_tl(cpu_PC, cpu_gpr_a[r1], ~0x1); tcg_gen_andi_tl(cpu_PC, cpu_gpr_a[r1], ~0x1);
tcg_gen_movi_tl(cpu_gpr_a[11], ctx->pc_succ_insn);
break; break;
case OPC2_32_RR_CALLI: case OPC2_32_RR_CALLI:
gen_helper_1arg(call, ctx->pc_succ_insn); gen_helper_1arg(call, ctx->pc_succ_insn);
@ -6066,9 +6086,9 @@ static void decode_rr_idirect(DisasContext *ctx)
break; break;
default: default:
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
return;
} }
tcg_gen_exit_tb(NULL, 0); ctx->base.is_jmp = DISAS_JUMP;
ctx->base.is_jmp = DISAS_NORETURN;
} }
static void decode_rr_divide(DisasContext *ctx) static void decode_rr_divide(DisasContext *ctx)
@ -6171,6 +6191,7 @@ static void decode_rr_divide(DisasContext *ctx)
tcg_gen_sari_tl(cpu_gpr_d[r3+1], cpu_gpr_d[r1], 31); tcg_gen_sari_tl(cpu_gpr_d[r3+1], cpu_gpr_d[r1], 31);
break; break;
case OPC2_32_RR_DVINIT_U: case OPC2_32_RR_DVINIT_U:
CHECK_REG_PAIR(r3);
/* overflow = (D[b] == 0) */ /* overflow = (D[b] == 0) */
tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_PSW_V, cpu_gpr_d[r2], 0); tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_PSW_V, cpu_gpr_d[r2], 0);
tcg_gen_shli_tl(cpu_PSW_V, cpu_PSW_V, 31); tcg_gen_shli_tl(cpu_PSW_V, cpu_PSW_V, 31);
@ -6190,15 +6211,38 @@ static void decode_rr_divide(DisasContext *ctx)
CHECK_REG_PAIR(r3); CHECK_REG_PAIR(r3);
gen_unpack(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1]); gen_unpack(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1]);
break; break;
case OPC2_32_RR_CRC32: case OPC2_32_RR_CRC32_B:
if (has_feature(ctx, TRICORE_FEATURE_162)) {
gen_helper_crc32b(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
} else {
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
}
break;
case OPC2_32_RR_CRC32: /* CRC32B.W in 1.6.2 */
if (has_feature(ctx, TRICORE_FEATURE_161)) { if (has_feature(ctx, TRICORE_FEATURE_161)) {
gen_helper_crc32(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); gen_helper_crc32_be(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
} else {
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
}
break;
case OPC2_32_RR_CRC32L_W:
if (has_feature(ctx, TRICORE_FEATURE_162)) {
gen_helper_crc32_le(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
} else {
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
}
break;
case OPC2_32_RR_POPCNT_W:
if (has_feature(ctx, TRICORE_FEATURE_162)) {
tcg_gen_ctpop_tl(cpu_gpr_d[r3], cpu_gpr_d[r1]);
} else { } else {
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
} }
break; break;
case OPC2_32_RR_DIV: case OPC2_32_RR_DIV:
if (has_feature(ctx, TRICORE_FEATURE_16)) { if (has_feature(ctx, TRICORE_FEATURE_16)) {
CHECK_REG_PAIR(r3);
GEN_HELPER_RR(divide, cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], GEN_HELPER_RR(divide, cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1],
cpu_gpr_d[r2]); cpu_gpr_d[r2]);
} else { } else {
@ -6207,6 +6251,7 @@ static void decode_rr_divide(DisasContext *ctx)
break; break;
case OPC2_32_RR_DIV_U: case OPC2_32_RR_DIV_U:
if (has_feature(ctx, TRICORE_FEATURE_16)) { if (has_feature(ctx, TRICORE_FEATURE_16)) {
CHECK_REG_PAIR(r3);
GEN_HELPER_RR(divide_u, cpu_gpr_d[r3], cpu_gpr_d[r3+1], GEN_HELPER_RR(divide_u, cpu_gpr_d[r3], cpu_gpr_d[r3+1],
cpu_gpr_d[r1], cpu_gpr_d[r2]); cpu_gpr_d[r1], cpu_gpr_d[r2]);
} else { } else {
@ -6733,6 +6778,8 @@ static void decode_rrr2_msub(DisasContext *ctx)
cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]);
break; break;
case OPC2_32_RRR2_MSUB_U_64: case OPC2_32_RRR2_MSUB_U_64:
CHECK_REG_PAIR(r4);
CHECK_REG_PAIR(r3);
gen_msubu64_d(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], gen_msubu64_d(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1],
cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]);
break; break;
@ -7816,7 +7863,7 @@ static void decode_rrrw_extract_insert(DisasContext *ctx)
break; break;
case OPC2_32_RRRW_IMASK: case OPC2_32_RRRW_IMASK:
temp2 = tcg_temp_new(); temp2 = tcg_temp_new();
CHECK_REG_PAIR(r4);
tcg_gen_andi_tl(temp, cpu_gpr_d[r3], 0x1f); tcg_gen_andi_tl(temp, cpu_gpr_d[r3], 0x1f);
tcg_gen_movi_tl(temp2, (1 << width) - 1); tcg_gen_movi_tl(temp2, (1 << width) - 1);
tcg_gen_shl_tl(temp2, temp2, temp); tcg_gen_shl_tl(temp2, temp2, temp);
@ -7851,12 +7898,33 @@ static void decode_sys_interrupts(DisasContext *ctx)
/* raise EXCP_DEBUG */ /* raise EXCP_DEBUG */
break; break;
case OPC2_32_SYS_DISABLE: case OPC2_32_SYS_DISABLE:
tcg_gen_andi_tl(cpu_ICR, cpu_ICR, ~ctx->icr_ie_mask); if (ctx->priv == TRICORE_PRIV_SM || ctx->priv == TRICORE_PRIV_UM1) {
tcg_gen_andi_tl(cpu_ICR, cpu_ICR, ~ctx->icr_ie_mask);
} else {
generate_trap(ctx, TRAPC_PROT, TIN1_PRIV);
}
break; break;
case OPC2_32_SYS_DISABLE_D:
if (has_feature(ctx, TRICORE_FEATURE_16)) {
if (ctx->priv == TRICORE_PRIV_SM || ctx->priv == TRICORE_PRIV_UM1) {
tcg_gen_extract_tl(cpu_gpr_d[r1], cpu_ICR,
ctx->icr_ie_offset, 1);
tcg_gen_andi_tl(cpu_ICR, cpu_ICR, ~ctx->icr_ie_mask);
} else {
generate_trap(ctx, TRAPC_PROT, TIN1_PRIV);
}
} else {
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
}
case OPC2_32_SYS_DSYNC: case OPC2_32_SYS_DSYNC:
break; break;
case OPC2_32_SYS_ENABLE: case OPC2_32_SYS_ENABLE:
tcg_gen_ori_tl(cpu_ICR, cpu_ICR, ctx->icr_ie_mask); if (ctx->priv == TRICORE_PRIV_SM || ctx->priv == TRICORE_PRIV_UM1) {
tcg_gen_ori_tl(cpu_ICR, cpu_ICR, ctx->icr_ie_mask);
ctx->base.is_jmp = DISAS_EXIT_UPDATE;
} else {
generate_trap(ctx, TRAPC_PROT, TIN1_PRIV);
}
break; break;
case OPC2_32_SYS_ISYNC: case OPC2_32_SYS_ISYNC:
break; break;
@ -7870,11 +7938,10 @@ static void decode_sys_interrupts(DisasContext *ctx)
break; break;
case OPC2_32_SYS_RFE: case OPC2_32_SYS_RFE:
gen_helper_rfe(cpu_env); gen_helper_rfe(cpu_env);
tcg_gen_exit_tb(NULL, 0); ctx->base.is_jmp = DISAS_EXIT;
ctx->base.is_jmp = DISAS_NORETURN;
break; break;
case OPC2_32_SYS_RFM: case OPC2_32_SYS_RFM:
if ((ctx->hflags & TRICORE_HFLAG_KUU) == TRICORE_HFLAG_SM) { if (ctx->priv == TRICORE_PRIV_SM) {
tmp = tcg_temp_new(); tmp = tcg_temp_new();
l1 = gen_new_label(); l1 = gen_new_label();
@ -7883,10 +7950,9 @@ static void decode_sys_interrupts(DisasContext *ctx)
tcg_gen_brcondi_tl(TCG_COND_NE, tmp, 1, l1); tcg_gen_brcondi_tl(TCG_COND_NE, tmp, 1, l1);
gen_helper_rfm(cpu_env); gen_helper_rfm(cpu_env);
gen_set_label(l1); gen_set_label(l1);
tcg_gen_exit_tb(NULL, 0); ctx->base.is_jmp = DISAS_EXIT;
ctx->base.is_jmp = DISAS_NORETURN;
} else { } else {
/* generate privilege trap */ generate_trap(ctx, TRAPC_PROT, TIN1_PRIV);
} }
break; break;
case OPC2_32_SYS_RSLCX: case OPC2_32_SYS_RSLCX:
@ -7897,10 +7963,13 @@ static void decode_sys_interrupts(DisasContext *ctx)
break; break;
case OPC2_32_SYS_RESTORE: case OPC2_32_SYS_RESTORE:
if (has_feature(ctx, TRICORE_FEATURE_16)) { if (has_feature(ctx, TRICORE_FEATURE_16)) {
if ((ctx->hflags & TRICORE_HFLAG_KUU) == TRICORE_HFLAG_SM || if (ctx->priv == TRICORE_PRIV_SM || ctx->priv == TRICORE_PRIV_UM1) {
(ctx->hflags & TRICORE_HFLAG_KUU) == TRICORE_HFLAG_UM1) { tcg_gen_deposit_tl(cpu_ICR, cpu_ICR, cpu_gpr_d[r1],
tcg_gen_deposit_tl(cpu_ICR, cpu_ICR, cpu_gpr_d[r1], 8, 1); ctx->icr_ie_offset, 1);
} /* else raise privilege trap */ ctx->base.is_jmp = DISAS_EXIT_UPDATE;
} else {
generate_trap(ctx, TRAPC_PROT, TIN1_PRIV);
}
} else { } else {
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
} }
@ -7924,7 +7993,7 @@ static void decode_sys_interrupts(DisasContext *ctx)
static void decode_32Bit_opc(DisasContext *ctx) static void decode_32Bit_opc(DisasContext *ctx)
{ {
int op1; int op1, op2;
int32_t r1, r2, r3; int32_t r1, r2, r3;
int32_t address, const16; int32_t address, const16;
int8_t b, const4; int8_t b, const4;
@ -7975,9 +8044,19 @@ static void decode_32Bit_opc(DisasContext *ctx)
tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LEUW); tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LEUW);
tcg_gen_shli_tl(cpu_gpr_d[r1], cpu_gpr_d[r1], 16); tcg_gen_shli_tl(cpu_gpr_d[r1], cpu_gpr_d[r1], 16);
break; break;
case OPC1_32_ABS_LEA: case OPCM_32_ABS_LEA_LHA:
address = MASK_OP_ABS_OFF18(ctx->opcode); address = MASK_OP_ABS_OFF18(ctx->opcode);
r1 = MASK_OP_ABS_S1D(ctx->opcode); r1 = MASK_OP_ABS_S1D(ctx->opcode);
if (has_feature(ctx, TRICORE_FEATURE_162)) {
op2 = MASK_OP_ABS_OP2(ctx->opcode);
if (op2 == OPC2_32_ABS_LHA) {
tcg_gen_movi_tl(cpu_gpr_a[r1], address << 14);
break;
}
/* otherwise translate regular LEA */
}
tcg_gen_movi_tl(cpu_gpr_a[r1], EA_ABS_FORMAT(address)); tcg_gen_movi_tl(cpu_gpr_a[r1], EA_ABS_FORMAT(address));
break; break;
/* ABSB-format */ /* ABSB-format */
@ -8258,12 +8337,17 @@ static void tricore_tr_init_disas_context(DisasContextBase *dcbase,
DisasContext *ctx = container_of(dcbase, DisasContext, base); DisasContext *ctx = container_of(dcbase, DisasContext, base);
CPUTriCoreState *env = cs->env_ptr; CPUTriCoreState *env = cs->env_ptr;
ctx->mem_idx = cpu_mmu_index(env, false); ctx->mem_idx = cpu_mmu_index(env, false);
ctx->hflags = (uint32_t)ctx->base.tb->flags;
uint32_t tb_flags = (uint32_t)ctx->base.tb->flags;
ctx->priv = FIELD_EX32(tb_flags, TB_FLAGS, PRIV);
ctx->features = env->features; ctx->features = env->features;
if (has_feature(ctx, TRICORE_FEATURE_161)) { if (has_feature(ctx, TRICORE_FEATURE_161)) {
ctx->icr_ie_mask = R_ICR_IE_161_MASK; ctx->icr_ie_mask = R_ICR_IE_161_MASK;
ctx->icr_ie_offset = R_ICR_IE_161_SHIFT;
} else { } else {
ctx->icr_ie_mask = R_ICR_IE_13_MASK; ctx->icr_ie_mask = R_ICR_IE_13_MASK;
ctx->icr_ie_offset = R_ICR_IE_13_SHIFT;
} }
} }
@ -8334,6 +8418,15 @@ static void tricore_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
case DISAS_TOO_MANY: case DISAS_TOO_MANY:
gen_goto_tb(ctx, 0, ctx->base.pc_next); gen_goto_tb(ctx, 0, ctx->base.pc_next);
break; break;
case DISAS_EXIT_UPDATE:
gen_save_pc(ctx->base.pc_next);
/* fall through */
case DISAS_EXIT:
tcg_gen_exit_tb(NULL, 0);
break;
case DISAS_JUMP:
tcg_gen_lookup_and_goto_ptr();
break;
case DISAS_NORETURN: case DISAS_NORETURN:
break; break;
default: default:

View File

@ -430,7 +430,7 @@ enum {
OPCM_32_ABS_STOREB_H = 0x25, OPCM_32_ABS_STOREB_H = 0x25,
OPC1_32_ABS_STOREQ = 0x65, OPC1_32_ABS_STOREQ = 0x65,
OPC1_32_ABS_LD_Q = 0x45, OPC1_32_ABS_LD_Q = 0x45,
OPC1_32_ABS_LEA = 0xc5, OPCM_32_ABS_LEA_LHA = 0xc5,
/* ABSB Format */ /* ABSB Format */
OPC1_32_ABSB_ST_T = 0xd5, OPC1_32_ABSB_ST_T = 0xd5,
/* B Format */ /* B Format */
@ -592,6 +592,13 @@ enum {
OPC2_32_ABS_ST_B = 0x00, OPC2_32_ABS_ST_B = 0x00,
OPC2_32_ABS_ST_H = 0x02, OPC2_32_ABS_ST_H = 0x02,
}; };
/* OPCM_32_ABS_LEA_LHA */
enum {
OPC2_32_ABS_LEA = 0x00,
OPC2_32_ABS_LHA = 0x01,
};
/* /*
* Bit Format * Bit Format
*/ */
@ -878,6 +885,7 @@ enum {
OPC2_32_RC_SHAS = 0x02, OPC2_32_RC_SHAS = 0x02,
OPC2_32_RC_XNOR = 0x0d, OPC2_32_RC_XNOR = 0x0d,
OPC2_32_RC_XOR = 0x0c, OPC2_32_RC_XOR = 0x0c,
OPC2_32_RC_SHUFFLE = 0x07, /* v1.6.2 only */
}; };
/* OPCM_32_RC_ACCUMULATOR */ /* OPCM_32_RC_ACCUMULATOR */
enum { enum {
@ -1132,7 +1140,10 @@ enum {
OPC2_32_RR_DVINIT_U = 0x0a, OPC2_32_RR_DVINIT_U = 0x0a,
OPC2_32_RR_PARITY = 0x02, OPC2_32_RR_PARITY = 0x02,
OPC2_32_RR_UNPACK = 0x08, OPC2_32_RR_UNPACK = 0x08,
OPC2_32_RR_CRC32 = 0x03, OPC2_32_RR_CRC32 = 0x03, /* CRC32B.W in 1.6.2 */
OPC2_32_RR_CRC32_B = 0x06, /* 1.6.2 only */
OPC2_32_RR_CRC32L_W = 0x07, /* 1.6.2 only */
OPC2_32_RR_POPCNT_W = 0x22, /* 1.6.2 only */
OPC2_32_RR_DIV = 0x20, OPC2_32_RR_DIV = 0x20,
OPC2_32_RR_DIV_U = 0x21, OPC2_32_RR_DIV_U = 0x21,
OPC2_32_RR_MUL_F = 0x04, OPC2_32_RR_MUL_F = 0x04,
@ -1456,6 +1467,7 @@ enum {
enum { enum {
OPC2_32_SYS_DEBUG = 0x04, OPC2_32_SYS_DEBUG = 0x04,
OPC2_32_SYS_DISABLE = 0x0d, OPC2_32_SYS_DISABLE = 0x0d,
OPC2_32_SYS_DISABLE_D = 0x0f, /* 1.6 up */
OPC2_32_SYS_DSYNC = 0x12, OPC2_32_SYS_DSYNC = 0x12,
OPC2_32_SYS_ENABLE = 0x0c, OPC2_32_SYS_ENABLE = 0x0c,
OPC2_32_SYS_ISYNC = 0x13, OPC2_32_SYS_ISYNC = 0x13,