TriCore Support (#1568)

* TriCore Support

python sample

* Update sample_tricore.py

Correct attribution

* Update sample_tricore.py

Fixed byte code to execute properly.

* Update sample_tricore.py

Removed testing artifact

* Added tricore msvc config-file.h

* Added STATIC to tricore config and added helper methods to symbol file generation.

* Update op_helper.c

Use built in crc32

* Fix tricore samples and small code blocks are now handled properly

* Add CPU types

* Generate bindings

* Format code

Co-authored-by: lazymio <mio@lazym.io>
This commit is contained in:
Eric Poole
2022-04-29 17:11:34 -04:00
committed by GitHub
parent f49f62ecef
commit cfee2139a0
42 changed files with 18103 additions and 12 deletions

View File

@@ -0,0 +1,17 @@
/*
* TriCore cpu parameters for qemu.
*
* Copyright (c) 2012-2014 Bastian Koppelmann C-Lab/University Paderborn
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef TRICORE_CPU_PARAM_H
#define TRICORE_CPU_PARAM_H 1
#define TARGET_LONG_BITS 32
#define TARGET_PAGE_BITS 14
#define TARGET_PHYS_ADDR_SPACE_BITS 32
#define TARGET_VIRT_ADDR_SPACE_BITS 32
#define NB_MMU_MODES 3
#endif

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2012-2014 Bastian Koppelmann C-Lab/University Paderborn
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
Modified for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
Copyright 2022 Aptiv
*/
#ifndef QEMU_TRICORE_CPU_QOM_H
#define QEMU_TRICORE_CPU_QOM_H
#include "hw/core/cpu.h"
#define TYPE_TRICORE_CPU "tricore-cpu"
#define TRICORE_CPU(obj) ((TriCoreCPU *)obj)
#define TRICORE_CPU_CLASS(klass) ((TriCoreCPUClass *)klass)
#define TRICORE_CPU_GET_CLASS(obj) (&((TriCoreCPU *)obj)->cc)
typedef struct TriCoreCPUClass {
/*< private >*/
CPUClass parent_class;
/*< public >*/
void (*parent_reset)(CPUState *cpu);
} TriCoreCPUClass;
#endif /* QEMU_TRICORE_CPU_QOM_H */

205
qemu/target/tricore/cpu.c Normal file
View File

@@ -0,0 +1,205 @@
/*
* TriCore emulation for qemu: main translation routines.
*
* Copyright (c) 2012-2014 Bastian Koppelmann C-Lab/University Paderborn
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
Modified for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
Copyright 2022 Aptiv
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "cpu-qom.h"
#include "exec/exec-all.h"
#include <uc_priv.h>
static inline void set_feature(CPUTriCoreState *env, int feature)
{
env->features |= 1ULL << feature;
}
static void tricore_cpu_set_pc(CPUState *cs, vaddr value)
{
TriCoreCPU *cpu = TRICORE_CPU(cs);
CPUTriCoreState *env = &cpu->env;
env->PC = value & ~(target_ulong)1;
}
static void tricore_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
{
TriCoreCPU *cpu = TRICORE_CPU(cs);
CPUTriCoreState *env = &cpu->env;
env->PC = tb->pc;
}
static void tricore_cpu_reset(CPUState *dev)
{
CPUState *s = CPU(dev);
TriCoreCPU *cpu = TRICORE_CPU(s);
TriCoreCPUClass *tcc = TRICORE_CPU_GET_CLASS(cpu);
CPUTriCoreState *env = &cpu->env;
tcc->parent_reset(dev);
memset(env, 0, offsetof(CPUTriCoreState, end_reset_fields));
cpu_state_reset(env);
}
static bool tricore_cpu_has_work(CPUState *cs)
{
return true;
}
static void tricore_cpu_realizefn(CPUState *dev)
{
CPUState *cs = CPU(dev);
TriCoreCPU *cpu = TRICORE_CPU(dev);
CPUTriCoreState *env = &cpu->env;
cpu_exec_realizefn(cs);
/* Some features automatically imply others */
if (tricore_feature(env, TRICORE_FEATURE_161)) {
set_feature(env, TRICORE_FEATURE_16);
}
if (tricore_feature(env, TRICORE_FEATURE_16)) {
set_feature(env, TRICORE_FEATURE_131);
}
if (tricore_feature(env, TRICORE_FEATURE_131)) {
set_feature(env, TRICORE_FEATURE_13);
}
cpu_reset(cs);
}
static void tricore_cpu_initfn(struct uc_struct *uc, CPUState *obj)
{
TriCoreCPU *cpu = TRICORE_CPU(obj);
CPUTriCoreState *env = &cpu->env;
env->uc = uc;
cpu_set_cpustate_pointers(cpu);
}
static void tc1796_initfn(CPUState *obj)
{
TriCoreCPU *cpu = TRICORE_CPU(obj);
set_feature(&cpu->env, TRICORE_FEATURE_13);
}
static void tc1797_initfn(CPUState *obj)
{
TriCoreCPU *cpu = TRICORE_CPU(obj);
set_feature(&cpu->env, TRICORE_FEATURE_131);
}
static void tc27x_initfn(CPUState *obj)
{
TriCoreCPU *cpu = TRICORE_CPU(obj);
set_feature(&cpu->env, TRICORE_FEATURE_161);
}
static void tricore_cpu_class_init(CPUClass *c)
{
TriCoreCPUClass *mcc = TRICORE_CPU_CLASS(c);
CPUClass *cc = CPU_CLASS(c);
/* parent class is CPUClass, parent_reset() is cpu_common_reset(). */
mcc->parent_reset = cc->reset;
cc->reset = tricore_cpu_reset;
cc->has_work = tricore_cpu_has_work;
cc->set_pc = tricore_cpu_set_pc;
cc->synchronize_from_tb = tricore_cpu_synchronize_from_tb;
cc->get_phys_page_debug = tricore_cpu_get_phys_page_debug;
cc->tlb_fill = tricore_cpu_tlb_fill;
cc->tcg_initialize = tricore_tcg_init;
}
#define DEFINE_TRICORE_CPU_TYPE(cpu_model, initfn) \
{ \
.parent = TYPE_TRICORE_CPU, \
.initfn = initfn, \
.name = TRICORE_CPU_TYPE_NAME(cpu_model), \
}
struct TriCoreCPUInfo {
const char *name;
void (*initfn)(CPUState *obj);
};
static struct TriCoreCPUInfo tricore_cpus_type_infos[] = {
{ "tc1796", tc1796_initfn },
{ "tc1797", tc1797_initfn },
{ "tc27x", tc27x_initfn },
};
TriCoreCPU *cpu_tricore_init(struct uc_struct *uc)
{
TriCoreCPU *cpu;
CPUState *cs;
CPUClass *cc;
cpu = calloc(1, sizeof(*cpu));
if (cpu == NULL) {
return NULL;
}
if (uc->cpu_model == INT_MAX) {
uc->cpu_model = 2; // tc27x
} else if (uc->cpu_model >= ARRAY_SIZE(tricore_cpus_type_infos)) {
free(cpu);
return NULL;
}
cs = (CPUState *)cpu;
cc = (CPUClass *)&cpu->cc;
cs->cc = cc;
cs->uc = uc;
uc->cpu = cs;
cpu_class_init(uc, cc);
tricore_cpu_class_init(cc);
cpu_common_initfn(uc, cs);
tricore_cpu_initfn(uc, cs);
tricore_cpus_type_infos[uc->cpu_model].initfn(cs);
tricore_cpu_realizefn(cs);
// init address space
cpu_address_space_init(cs, 0, cs->memory);
qemu_init_vcpu(cs);
return cpu;
}

410
qemu/target/tricore/cpu.h Normal file
View File

@@ -0,0 +1,410 @@
/*
* TriCore emulation for qemu: main CPU struct.
*
* Copyright (c) 2012-2014 Bastian Koppelmann C-Lab/University Paderborn
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
Modified for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
Copyright 2022 Aptiv
*/
#ifndef TRICORE_CPU_H
#define TRICORE_CPU_H
#include "cpu-qom.h"
#include "exec/cpu-defs.h"
#include "tricore-defs.h"
struct tricore_boot_info;
typedef struct tricore_def_t tricore_def_t;
// struct CPUTriCoreState {
typedef struct CPUTriCoreState {
/* GPR Register */
uint32_t gpr_a[16];
uint32_t gpr_d[16];
/* CSFR Register */
uint32_t PCXI;
/* Frequently accessed PSW_USB bits are stored separately for efficiency.
This contains all the other bits. Use psw_{read,write} to access
the whole PSW. */
uint32_t PSW;
/* PSW flag cache for faster execution
*/
uint32_t PSW_USB_C;
uint32_t PSW_USB_V; /* Only if bit 31 set, then flag is set */
uint32_t PSW_USB_SV; /* Only if bit 31 set, then flag is set */
uint32_t PSW_USB_AV; /* Only if bit 31 set, then flag is set. */
uint32_t PSW_USB_SAV; /* Only if bit 31 set, then flag is set. */
uint32_t PC;
uint32_t SYSCON;
uint32_t CPU_ID;
uint32_t CORE_ID;
uint32_t BIV;
uint32_t BTV;
uint32_t ISP;
uint32_t ICR;
uint32_t FCX;
uint32_t LCX;
uint32_t COMPAT;
/* Mem Protection Register */
uint32_t DPR0_0L;
uint32_t DPR0_0U;
uint32_t DPR0_1L;
uint32_t DPR0_1U;
uint32_t DPR0_2L;
uint32_t DPR0_2U;
uint32_t DPR0_3L;
uint32_t DPR0_3U;
uint32_t DPR1_0L;
uint32_t DPR1_0U;
uint32_t DPR1_1L;
uint32_t DPR1_1U;
uint32_t DPR1_2L;
uint32_t DPR1_2U;
uint32_t DPR1_3L;
uint32_t DPR1_3U;
uint32_t DPR2_0L;
uint32_t DPR2_0U;
uint32_t DPR2_1L;
uint32_t DPR2_1U;
uint32_t DPR2_2L;
uint32_t DPR2_2U;
uint32_t DPR2_3L;
uint32_t DPR2_3U;
uint32_t DPR3_0L;
uint32_t DPR3_0U;
uint32_t DPR3_1L;
uint32_t DPR3_1U;
uint32_t DPR3_2L;
uint32_t DPR3_2U;
uint32_t DPR3_3L;
uint32_t DPR3_3U;
uint32_t CPR0_0L;
uint32_t CPR0_0U;
uint32_t CPR0_1L;
uint32_t CPR0_1U;
uint32_t CPR0_2L;
uint32_t CPR0_2U;
uint32_t CPR0_3L;
uint32_t CPR0_3U;
uint32_t CPR1_0L;
uint32_t CPR1_0U;
uint32_t CPR1_1L;
uint32_t CPR1_1U;
uint32_t CPR1_2L;
uint32_t CPR1_2U;
uint32_t CPR1_3L;
uint32_t CPR1_3U;
uint32_t CPR2_0L;
uint32_t CPR2_0U;
uint32_t CPR2_1L;
uint32_t CPR2_1U;
uint32_t CPR2_2L;
uint32_t CPR2_2U;
uint32_t CPR2_3L;
uint32_t CPR2_3U;
uint32_t CPR3_0L;
uint32_t CPR3_0U;
uint32_t CPR3_1L;
uint32_t CPR3_1U;
uint32_t CPR3_2L;
uint32_t CPR3_2U;
uint32_t CPR3_3L;
uint32_t CPR3_3U;
uint32_t DPM0;
uint32_t DPM1;
uint32_t DPM2;
uint32_t DPM3;
uint32_t CPM0;
uint32_t CPM1;
uint32_t CPM2;
uint32_t CPM3;
/* Memory Management Registers */
uint32_t MMU_CON;
uint32_t MMU_ASI;
uint32_t MMU_TVA;
uint32_t MMU_TPA;
uint32_t MMU_TPX;
uint32_t MMU_TFA;
/* {1.3.1 only */
uint32_t BMACON;
uint32_t SMACON;
uint32_t DIEAR;
uint32_t DIETR;
uint32_t CCDIER;
uint32_t MIECON;
uint32_t PIEAR;
uint32_t PIETR;
uint32_t CCPIER;
/*} */
/* Debug Registers */
uint32_t DBGSR;
uint32_t EXEVT;
uint32_t CREVT;
uint32_t SWEVT;
uint32_t TR0EVT;
uint32_t TR1EVT;
uint32_t DMS;
uint32_t DCX;
uint32_t DBGTCR;
uint32_t CCTRL;
uint32_t CCNT;
uint32_t ICNT;
uint32_t M1CNT;
uint32_t M2CNT;
uint32_t M3CNT;
/* Floating Point Registers */
float_status fp_status;
/* QEMU */
int error_code;
uint32_t hflags; /* CPU State */
const tricore_def_t *cpu_model;
void *irq[8];
struct QEMUTimer *timer; /* Internal timer */
/* Fields up to this point are cleared by a CPU reset */
int end_reset_fields;
/* Fields from here on are preserved across CPU reset. */
uint32_t features;
// Unicorn engine
struct uc_struct *uc;
} CPUTriCoreState;
/**
* TriCoreCPU:
* @env: #CPUTriCoreState
*
* A TriCore CPU.
*/
// TODO: Why is the type def needed? Without it the later typedef fails to find this... ?
typedef struct TriCoreCPU {
/*< private >*/
CPUState parent_obj;
/*< public >*/
CPUNegativeOffsetState neg;
CPUTriCoreState env;
struct TriCoreCPUClass cc;
} TriCoreCPU;
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
#define MASK_PSW_USB 0xff000000
#define MASK_USB_C 0x80000000
#define MASK_USB_V 0x40000000
#define MASK_USB_SV 0x20000000
#define MASK_USB_AV 0x10000000
#define MASK_USB_SAV 0x08000000
#define MASK_PSW_PRS 0x00003000
#define MASK_PSW_IO 0x00000c00
#define MASK_PSW_IS 0x00000200
#define MASK_PSW_GW 0x00000100
#define MASK_PSW_CDE 0x00000080
#define MASK_PSW_CDC 0x0000007f
#define MASK_PSW_FPU_RM 0x3000000
#define MASK_SYSCON_PRO_TEN 0x2
#define MASK_SYSCON_FCD_SF 0x1
#define MASK_CPUID_MOD 0xffff0000
#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
#define MASK_LCX_LCXS 0x000f0000
#define MASK_LCX_LCX0 0x0000ffff
#define MASK_DBGSR_DE 0x1
#define MASK_DBGSR_HALT 0x6
#define MASK_DBGSR_SUSP 0x10
#define MASK_DBGSR_PREVSUSP 0x20
#define MASK_DBGSR_PEVT 0x40
#define MASK_DBGSR_EVTSRC 0x1f00
#define TRICORE_HFLAG_KUU 0x3
#define TRICORE_HFLAG_UM0 0x00002 /* user mode-0 flag */
#define TRICORE_HFLAG_UM1 0x00001 /* user mode-1 flag */
#define TRICORE_HFLAG_SM 0x00000 /* kernel mode flag */
enum tricore_features {
TRICORE_FEATURE_13,
TRICORE_FEATURE_131,
TRICORE_FEATURE_16,
TRICORE_FEATURE_161,
};
static inline int tricore_feature(CPUTriCoreState *env, int feature)
{
return (env->features & (1ULL << feature)) != 0;
}
/* TriCore Traps Classes*/
enum {
TRAPC_NONE = -1,
TRAPC_MMU = 0,
TRAPC_PROT = 1,
TRAPC_INSN_ERR = 2,
TRAPC_CTX_MNG = 3,
TRAPC_SYSBUS = 4,
TRAPC_ASSERT = 5,
TRAPC_SYSCALL = 6,
TRAPC_NMI = 7,
TRAPC_IRQ = 8
};
/* Class 0 TIN */
enum {
TIN0_VAF = 0,
TIN0_VAP = 1,
};
/* Class 1 TIN */
enum {
TIN1_PRIV = 1,
TIN1_MPR = 2,
TIN1_MPW = 3,
TIN1_MPX = 4,
TIN1_MPP = 5,
TIN1_MPN = 6,
TIN1_GRWP = 7,
};
/* Class 2 TIN */
enum {
TIN2_IOPC = 1,
TIN2_UOPC = 2,
TIN2_OPD = 3,
TIN2_ALN = 4,
TIN2_MEM = 5,
};
/* Class 3 TIN */
enum {
TIN3_FCD = 1,
TIN3_CDO = 2,
TIN3_CDU = 3,
TIN3_FCU = 4,
TIN3_CSU = 5,
TIN3_CTYP = 6,
TIN3_NEST = 7,
};
/* Class 4 TIN */
enum {
TIN4_PSE = 1,
TIN4_DSE = 2,
TIN4_DAE = 3,
TIN4_CAE = 4,
TIN4_PIE = 5,
TIN4_DIE = 6,
};
/* Class 5 TIN */
enum {
TIN5_OVF = 1,
TIN5_SOVF = 1,
};
/* Class 6 TIN
*
* Is always TIN6_SYS
*/
/* Class 7 TIN */
enum {
TIN7_NMI = 0,
};
uint32_t psw_read(CPUTriCoreState *env);
void psw_write(CPUTriCoreState *env, uint32_t val);
int tricore_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n);
int tricore_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n);
void fpu_set_state(CPUTriCoreState *env);
#define MMU_USER_IDX 2
void tricore_cpu_list(void);
#define cpu_list tricore_cpu_list
static inline int cpu_mmu_index(CPUTriCoreState *env, bool ifetch)
{
return 0;
}
typedef CPUTriCoreState CPUArchState;
typedef TriCoreCPU ArchCPU;
#include "exec/cpu-all.h"
void cpu_state_reset(CPUTriCoreState *s);
void tricore_tcg_init(struct uc_struct *uc);
static inline void cpu_get_tb_cpu_state(CPUTriCoreState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *flags)
{
*pc = env->PC;
*cs_base = 0;
*flags = 0;
}
#define TRICORE_CPU_TYPE_SUFFIX "-" TYPE_TRICORE_CPU
#define TRICORE_CPU_TYPE_NAME(model) model TRICORE_CPU_TYPE_SUFFIX
#define CPU_RESOLVING_TYPE TYPE_TRICORE_CPU
/* helpers.c */
bool tricore_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
MMUAccessType access_type, int mmu_idx,
bool probe, uintptr_t retaddr);
#endif /* TRICORE_CPU_H */

View File

@@ -0,0 +1,125 @@
/* A(ll) access permited
R(ead only) access
E(nd init protected) access
A|R|E(offset, register, feature introducing reg)
NOTE: PSW is handled as a special case in gen_mtcr/mfcr */
A(0xfe00, PCXI, TRICORE_FEATURE_13)
A(0xfe08, PC, TRICORE_FEATURE_13)
A(0xfe14, SYSCON, TRICORE_FEATURE_13)
R(0xfe18, CPU_ID, TRICORE_FEATURE_13)
R(0xfe1c, CORE_ID, TRICORE_FEATURE_161)
E(0xfe20, BIV, TRICORE_FEATURE_13)
E(0xfe24, BTV, TRICORE_FEATURE_13)
E(0xfe28, ISP, TRICORE_FEATURE_13)
A(0xfe2c, ICR, TRICORE_FEATURE_13)
A(0xfe38, FCX, TRICORE_FEATURE_13)
A(0xfe3c, LCX, TRICORE_FEATURE_13)
E(0x9400, COMPAT, TRICORE_FEATURE_131)
/* memory protection register */
A(0xC000, DPR0_0L, TRICORE_FEATURE_13)
A(0xC004, DPR0_0U, TRICORE_FEATURE_13)
A(0xC008, DPR0_1L, TRICORE_FEATURE_13)
A(0xC00C, DPR0_1U, TRICORE_FEATURE_13)
A(0xC010, DPR0_2L, TRICORE_FEATURE_13)
A(0xC014, DPR0_2U, TRICORE_FEATURE_13)
A(0xC018, DPR0_3L, TRICORE_FEATURE_13)
A(0xC01C, DPR0_3U, TRICORE_FEATURE_13)
A(0xC400, DPR1_0L, TRICORE_FEATURE_13)
A(0xC404, DPR1_0U, TRICORE_FEATURE_13)
A(0xC408, DPR1_1L, TRICORE_FEATURE_13)
A(0xC40C, DPR1_1U, TRICORE_FEATURE_13)
A(0xC410, DPR1_2L, TRICORE_FEATURE_13)
A(0xC414, DPR1_2U, TRICORE_FEATURE_13)
A(0xC418, DPR1_3L, TRICORE_FEATURE_13)
A(0xC41C, DPR1_3U, TRICORE_FEATURE_13)
A(0xC800, DPR2_0L, TRICORE_FEATURE_13)
A(0xC804, DPR2_0U, TRICORE_FEATURE_13)
A(0xC808, DPR2_1L, TRICORE_FEATURE_13)
A(0xC80C, DPR2_1U, TRICORE_FEATURE_13)
A(0xC810, DPR2_2L, TRICORE_FEATURE_13)
A(0xC814, DPR2_2U, TRICORE_FEATURE_13)
A(0xC818, DPR2_3L, TRICORE_FEATURE_13)
A(0xC81C, DPR2_3U, TRICORE_FEATURE_13)
A(0xCC00, DPR3_0L, TRICORE_FEATURE_13)
A(0xCC04, DPR3_0U, TRICORE_FEATURE_13)
A(0xCC08, DPR3_1L, TRICORE_FEATURE_13)
A(0xCC0C, DPR3_1U, TRICORE_FEATURE_13)
A(0xCC10, DPR3_2L, TRICORE_FEATURE_13)
A(0xCC14, DPR3_2U, TRICORE_FEATURE_13)
A(0xCC18, DPR3_3L, TRICORE_FEATURE_13)
A(0xCC1C, DPR3_3U, TRICORE_FEATURE_13)
A(0xD000, CPR0_0L, TRICORE_FEATURE_13)
A(0xD004, CPR0_0U, TRICORE_FEATURE_13)
A(0xD008, CPR0_1L, TRICORE_FEATURE_13)
A(0xD00C, CPR0_1U, TRICORE_FEATURE_13)
A(0xD010, CPR0_2L, TRICORE_FEATURE_13)
A(0xD014, CPR0_2U, TRICORE_FEATURE_13)
A(0xD018, CPR0_3L, TRICORE_FEATURE_13)
A(0xD01C, CPR0_3U, TRICORE_FEATURE_13)
A(0xD400, CPR1_0L, TRICORE_FEATURE_13)
A(0xD404, CPR1_0U, TRICORE_FEATURE_13)
A(0xD408, CPR1_1L, TRICORE_FEATURE_13)
A(0xD40C, CPR1_1U, TRICORE_FEATURE_13)
A(0xD410, CPR1_2L, TRICORE_FEATURE_13)
A(0xD414, CPR1_2U, TRICORE_FEATURE_13)
A(0xD418, CPR1_3L, TRICORE_FEATURE_13)
A(0xD41C, CPR1_3U, TRICORE_FEATURE_13)
A(0xD800, CPR2_0L, TRICORE_FEATURE_13)
A(0xD804, CPR2_0U, TRICORE_FEATURE_13)
A(0xD808, CPR2_1L, TRICORE_FEATURE_13)
A(0xD80C, CPR2_1U, TRICORE_FEATURE_13)
A(0xD810, CPR2_2L, TRICORE_FEATURE_13)
A(0xD814, CPR2_2U, TRICORE_FEATURE_13)
A(0xD818, CPR2_3L, TRICORE_FEATURE_13)
A(0xD81C, CPR2_3U, TRICORE_FEATURE_13)
A(0xDC00, CPR3_0L, TRICORE_FEATURE_13)
A(0xDC04, CPR3_0U, TRICORE_FEATURE_13)
A(0xDC08, CPR3_1L, TRICORE_FEATURE_13)
A(0xDC0C, CPR3_1U, TRICORE_FEATURE_13)
A(0xDC10, CPR3_2L, TRICORE_FEATURE_13)
A(0xDC14, CPR3_2U, TRICORE_FEATURE_13)
A(0xDC18, CPR3_3L, TRICORE_FEATURE_13)
A(0xDC1C, CPR3_3U, TRICORE_FEATURE_13)
A(0xE000, DPM0, TRICORE_FEATURE_13)
A(0xE080, DPM1, TRICORE_FEATURE_13)
A(0xE100, DPM2, TRICORE_FEATURE_13)
A(0xE180, DPM3, TRICORE_FEATURE_13)
A(0xE200, CPM0, TRICORE_FEATURE_13)
A(0xE280, CPM1, TRICORE_FEATURE_13)
A(0xE300, CPM2, TRICORE_FEATURE_13)
A(0xE380, CPM3, TRICORE_FEATURE_13)
/* memory management registers */
A(0x8000, MMU_CON, TRICORE_FEATURE_13)
A(0x8004, MMU_ASI, TRICORE_FEATURE_13)
A(0x800C, MMU_TVA, TRICORE_FEATURE_13)
A(0x8010, MMU_TPA, TRICORE_FEATURE_13)
A(0x8014, MMU_TPX, TRICORE_FEATURE_13)
A(0x8018, MMU_TFA, TRICORE_FEATURE_13)
E(0x9004, BMACON, TRICORE_FEATURE_131)
E(0x900C, SMACON, TRICORE_FEATURE_131)
A(0x9020, DIEAR, TRICORE_FEATURE_131)
A(0x9024, DIETR, TRICORE_FEATURE_131)
A(0x9028, CCDIER, TRICORE_FEATURE_131)
E(0x9044, MIECON, TRICORE_FEATURE_131)
A(0x9210, PIEAR, TRICORE_FEATURE_131)
A(0x9214, PIETR, TRICORE_FEATURE_131)
A(0x9218, CCPIER, TRICORE_FEATURE_131)
/* debug registers */
A(0xFD00, DBGSR, TRICORE_FEATURE_13)
A(0xFD08, EXEVT, TRICORE_FEATURE_13)
A(0xFD0C, CREVT, TRICORE_FEATURE_13)
A(0xFD10, SWEVT, TRICORE_FEATURE_13)
A(0xFD20, TR0EVT, TRICORE_FEATURE_13)
A(0xFD24, TR1EVT, TRICORE_FEATURE_13)
A(0xFD40, DMS, TRICORE_FEATURE_13)
A(0xFD44, DCX, TRICORE_FEATURE_13)
A(0xFD48, DBGTCR, TRICORE_FEATURE_131)
A(0xFC00, CCTRL, TRICORE_FEATURE_131)
A(0xFC04, CCNT, TRICORE_FEATURE_131)
A(0xFC08, ICNT, TRICORE_FEATURE_131)
A(0xFC0C, M1CNT, TRICORE_FEATURE_131)
A(0xFC10, M2CNT, TRICORE_FEATURE_131)
A(0xFC14, M3CNT, TRICORE_FEATURE_131)

View File

@@ -0,0 +1,478 @@
/*
* TriCore emulation for qemu: fpu helper.
*
* Copyright (c) 2016 Bastian Koppelmann University of Paderborn
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
Modified for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
Copyright 2022 Aptiv
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "qemu/host-utils.h"
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "fpu/softfloat.h"
#define QUIET_NAN 0x7fc00000
#define ADD_NAN 0x7fc00001
#define SQRT_NAN 0x7fc00004
#define DIV_NAN 0x7fc00008
#define MUL_NAN 0x7fc00002
#define FPU_FS PSW_USB_C
#define FPU_FI PSW_USB_V
#define FPU_FV PSW_USB_SV
#define FPU_FZ PSW_USB_AV
#define FPU_FU PSW_USB_SAV
#define float32_sqrt_nan make_float32(SQRT_NAN)
#define float32_quiet_nan make_float32(QUIET_NAN)
/* we don't care about input_denormal */
static inline uint8_t f_get_excp_flags(CPUTriCoreState *env)
{
return get_float_exception_flags(&env->fp_status)
& (float_flag_invalid
| float_flag_overflow
| float_flag_underflow
| float_flag_output_denormal
| float_flag_divbyzero
| float_flag_inexact);
}
static inline float32 f_maddsub_nan_result(float32 arg1, float32 arg2,
float32 arg3, float32 result,
uint32_t muladd_negate_c)
{
uint32_t aSign, bSign, cSign;
uint32_t aExp, bExp, cExp;
if (float32_is_any_nan(arg1) || float32_is_any_nan(arg2) ||
float32_is_any_nan(arg3)) {
return QUIET_NAN;
} else if (float32_is_infinity(arg1) && float32_is_zero(arg2)) {
return MUL_NAN;
} else if (float32_is_zero(arg1) && float32_is_infinity(arg2)) {
return MUL_NAN;
} else {
aSign = arg1 >> 31;
bSign = arg2 >> 31;
cSign = arg3 >> 31;
aExp = (arg1 >> 23) & 0xff;
bExp = (arg2 >> 23) & 0xff;
cExp = (arg3 >> 23) & 0xff;
if (muladd_negate_c) {
cSign ^= 1;
}
if (((aExp == 0xff) || (bExp == 0xff)) && (cExp == 0xff)) {
if (aSign ^ bSign ^ cSign) {
return ADD_NAN;
}
}
}
return result;
}
static void f_update_psw_flags(CPUTriCoreState *env, uint8_t flags)
{
uint8_t some_excp = 0;
set_float_exception_flags(0, &env->fp_status);
if (flags & float_flag_invalid) {
env->FPU_FI = 1 << 31;
some_excp = 1;
}
if (flags & float_flag_overflow) {
env->FPU_FV = 1 << 31;
some_excp = 1;
}
if (flags & float_flag_underflow || flags & float_flag_output_denormal) {
env->FPU_FU = 1 << 31;
some_excp = 1;
}
if (flags & float_flag_divbyzero) {
env->FPU_FZ = 1 << 31;
some_excp = 1;
}
if (flags & float_flag_inexact || flags & float_flag_output_denormal) {
env->PSW |= 1 << 26;
some_excp = 1;
}
env->FPU_FS = some_excp;
}
#define FADD_SUB(op) \
uint32_t helper_f##op(CPUTriCoreState *env, uint32_t r1, uint32_t r2) \
{ \
float32 arg1 = make_float32(r1); \
float32 arg2 = make_float32(r2); \
uint32_t flags; \
float32 f_result; \
\
f_result = float32_##op(arg2, arg1, &env->fp_status); \
flags = f_get_excp_flags(env); \
if (flags) { \
/* If the output is a NaN, but the inputs aren't, \
we return a unique value. */ \
if ((flags & float_flag_invalid) \
&& !float32_is_any_nan(arg1) \
&& !float32_is_any_nan(arg2)) { \
f_result = ADD_NAN; \
} \
f_update_psw_flags(env, flags); \
} else { \
env->FPU_FS = 0; \
} \
return (uint32_t)f_result; \
}
FADD_SUB(add)
FADD_SUB(sub)
uint32_t helper_fmul(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
{
uint32_t flags;
float32 arg1 = make_float32(r1);
float32 arg2 = make_float32(r2);
float32 f_result;
f_result = float32_mul(arg1, arg2, &env->fp_status);
flags = f_get_excp_flags(env);
if (flags) {
/* If the output is a NaN, but the inputs aren't,
we return a unique value. */
if ((flags & float_flag_invalid)
&& !float32_is_any_nan(arg1)
&& !float32_is_any_nan(arg2)) {
f_result = MUL_NAN;
}
f_update_psw_flags(env, flags);
} else {
env->FPU_FS = 0;
}
return (uint32_t)f_result;
}
/*
* Target TriCore QSEED.F significand Lookup Table
*
* The QSEED.F output significand depends on the least-significant
* exponent bit and the 6 most-significant significand bits.
*
* IEEE 754 float datatype
* partitioned into Sign (S), Exponent (E) and Significand (M):
*
* S E E E E E E E E M M M M M M ...
* | | |
* +------+------+-------+-------+
* | |
* for lookup table
* calculating index for
* output E output M
*
* This lookup table was extracted by analyzing QSEED output
* from the real hardware
*/
static const uint8_t target_qseed_significand_table[128] = {
253, 252, 245, 244, 239, 238, 231, 230, 225, 224, 217, 216,
211, 210, 205, 204, 201, 200, 195, 194, 189, 188, 185, 184,
179, 178, 175, 174, 169, 168, 165, 164, 161, 160, 157, 156,
153, 152, 149, 148, 145, 144, 141, 140, 137, 136, 133, 132,
131, 130, 127, 126, 123, 122, 121, 120, 117, 116, 115, 114,
111, 110, 109, 108, 103, 102, 99, 98, 93, 92, 89, 88, 83,
82, 79, 78, 75, 74, 71, 70, 67, 66, 63, 62, 59, 58, 55,
54, 53, 52, 49, 48, 45, 44, 43, 42, 39, 38, 37, 36, 33,
32, 31, 30, 27, 26, 25, 24, 23, 22, 19, 18, 17, 16, 15,
14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2
};
uint32_t helper_qseed(CPUTriCoreState *env, uint32_t r1)
{
uint32_t arg1, S, E, M, E_minus_one, m_idx;
uint32_t new_E, new_M, new_S, result;
arg1 = make_float32(r1);
/* fetch IEEE-754 fields S, E and the uppermost 6-bit of M */
S = extract32(arg1, 31, 1);
E = extract32(arg1, 23, 8);
M = extract32(arg1, 17, 6);
if (float32_is_any_nan(arg1)) {
result = float32_quiet_nan;
} else if (float32_is_zero_or_denormal(arg1)) {
if (float32_is_neg(arg1)) {
result = float32_infinity | (1 << 31);
} else {
result = float32_infinity;
}
} else if (float32_is_neg(arg1)) {
result = float32_sqrt_nan;
} else if (float32_is_infinity(arg1)) {
result = float32_zero;
} else {
E_minus_one = E - 1;
m_idx = ((E_minus_one & 1) << 6) | M;
new_S = S;
new_E = 0xBD - E_minus_one / 2;
new_M = target_qseed_significand_table[m_idx];
result = 0;
result = deposit32(result, 31, 1, new_S);
result = deposit32(result, 23, 8, new_E);
result = deposit32(result, 15, 8, new_M);
}
if (float32_is_signaling_nan(arg1, &env->fp_status)
|| result == float32_sqrt_nan) {
env->FPU_FI = 1 << 31;
env->FPU_FS = 1;
} else {
env->FPU_FS = 0;
}
return (uint32_t) result;
}
uint32_t helper_fdiv(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
{
uint32_t flags;
float32 arg1 = make_float32(r1);
float32 arg2 = make_float32(r2);
float32 f_result;
f_result = float32_div(arg1, arg2 , &env->fp_status);
flags = f_get_excp_flags(env);
if (flags) {
/* If the output is a NaN, but the inputs aren't,
we return a unique value. */
if ((flags & float_flag_invalid)
&& !float32_is_any_nan(arg1)
&& !float32_is_any_nan(arg2)) {
f_result = DIV_NAN;
}
f_update_psw_flags(env, flags);
} else {
env->FPU_FS = 0;
}
return (uint32_t)f_result;
}
uint32_t helper_fmadd(CPUTriCoreState *env, uint32_t r1,
uint32_t r2, uint32_t r3)
{
uint32_t flags;
float32 arg1 = make_float32(r1);
float32 arg2 = make_float32(r2);
float32 arg3 = make_float32(r3);
float32 f_result;
f_result = float32_muladd(arg1, arg2, arg3, 0, &env->fp_status);
flags = f_get_excp_flags(env);
if (flags) {
if (flags & float_flag_invalid) {
arg1 = float32_squash_input_denormal(arg1, &env->fp_status);
arg2 = float32_squash_input_denormal(arg2, &env->fp_status);
arg3 = float32_squash_input_denormal(arg3, &env->fp_status);
f_result = f_maddsub_nan_result(arg1, arg2, arg3, f_result, 0);
}
f_update_psw_flags(env, flags);
} else {
env->FPU_FS = 0;
}
return (uint32_t)f_result;
}
uint32_t helper_fmsub(CPUTriCoreState *env, uint32_t r1,
uint32_t r2, uint32_t r3)
{
uint32_t flags;
float32 arg1 = make_float32(r1);
float32 arg2 = make_float32(r2);
float32 arg3 = make_float32(r3);
float32 f_result;
f_result = float32_muladd(arg1, arg2, arg3, float_muladd_negate_product,
&env->fp_status);
flags = f_get_excp_flags(env);
if (flags) {
if (flags & float_flag_invalid) {
arg1 = float32_squash_input_denormal(arg1, &env->fp_status);
arg2 = float32_squash_input_denormal(arg2, &env->fp_status);
arg3 = float32_squash_input_denormal(arg3, &env->fp_status);
f_result = f_maddsub_nan_result(arg1, arg2, arg3, f_result, 1);
}
f_update_psw_flags(env, flags);
} else {
env->FPU_FS = 0;
}
return (uint32_t)f_result;
}
uint32_t helper_fcmp(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
{
uint32_t result, flags;
float32 arg1 = make_float32(r1);
float32 arg2 = make_float32(r2);
set_flush_inputs_to_zero(0, &env->fp_status);
result = 1 << (float32_compare_quiet(arg1, arg2, &env->fp_status) + 1);
result |= float32_is_denormal(arg1) << 4;
result |= float32_is_denormal(arg2) << 5;
flags = f_get_excp_flags(env);
if (flags) {
f_update_psw_flags(env, flags);
} else {
env->FPU_FS = 0;
}
set_flush_inputs_to_zero(1, &env->fp_status);
return result;
}
uint32_t helper_ftoi(CPUTriCoreState *env, uint32_t arg)
{
float32 f_arg = make_float32(arg);
int32_t result, flags;
result = float32_to_int32(f_arg, &env->fp_status);
flags = f_get_excp_flags(env);
if (flags) {
if (float32_is_any_nan(f_arg)) {
result = 0;
}
f_update_psw_flags(env, flags);
} else {
env->FPU_FS = 0;
}
return (uint32_t)result;
}
uint32_t helper_itof(CPUTriCoreState *env, uint32_t arg)
{
float32 f_result;
uint32_t flags;
f_result = int32_to_float32(arg, &env->fp_status);
flags = f_get_excp_flags(env);
if (flags) {
f_update_psw_flags(env, flags);
} else {
env->FPU_FS = 0;
}
return (uint32_t)f_result;
}
uint32_t helper_utof(CPUTriCoreState *env, uint32_t arg)
{
float32 f_result;
uint32_t flags;
f_result = uint32_to_float32(arg, &env->fp_status);
flags = f_get_excp_flags(env);
if (flags) {
f_update_psw_flags(env, flags);
} else {
env->FPU_FS = 0;
}
return (uint32_t)f_result;
}
uint32_t helper_ftoiz(CPUTriCoreState *env, uint32_t arg)
{
float32 f_arg = make_float32(arg);
uint32_t result;
int32_t flags;
result = float32_to_int32_round_to_zero(f_arg, &env->fp_status);
flags = f_get_excp_flags(env);
if (flags & float_flag_invalid) {
flags &= ~float_flag_inexact;
if (float32_is_any_nan(f_arg)) {
result = 0;
}
}
if (flags) {
f_update_psw_flags(env, flags);
} else {
env->FPU_FS = 0;
}
return result;
}
uint32_t helper_ftouz(CPUTriCoreState *env, uint32_t arg)
{
float32 f_arg = make_float32(arg);
uint32_t result;
int32_t flags;
result = float32_to_uint32_round_to_zero(f_arg, &env->fp_status);
flags = f_get_excp_flags(env);
if (flags & float_flag_invalid) {
flags &= ~float_flag_inexact;
if (float32_is_any_nan(f_arg)) {
result = 0;
}
} else if (float32_lt_quiet(f_arg, 0, &env->fp_status)) {
flags = float_flag_invalid;
result = 0;
}
if (flags) {
f_update_psw_flags(env, flags);
} else {
env->FPU_FS = 0;
}
return result;
}
void helper_updfl(CPUTriCoreState *env, uint32_t arg)
{
env->FPU_FS = extract32(arg, 7, 1) & extract32(arg, 15, 1);
env->FPU_FI = (extract32(arg, 6, 1) & extract32(arg, 14, 1)) << 31;
env->FPU_FV = (extract32(arg, 5, 1) & extract32(arg, 13, 1)) << 31;
env->FPU_FZ = (extract32(arg, 4, 1) & extract32(arg, 12, 1)) << 31;
env->FPU_FU = (extract32(arg, 3, 1) & extract32(arg, 11, 1)) << 31;
/* clear FX and RM */
env->PSW &= ~(extract32(arg, 10, 1) << 26);
env->PSW |= (extract32(arg, 2, 1) & extract32(arg, 10, 1)) << 26;
fpu_set_state(env);
}

View File

@@ -0,0 +1,162 @@
/*
* Copyright (c) 2012-2014 Bastian Koppelmann C-Lab/University Paderborn
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
Modified for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
Copyright 2022 Aptiv
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "exec/exec-all.h"
#include "fpu/softfloat-helpers.h"
enum {
TLBRET_DIRTY = -4,
TLBRET_INVALID = -3,
TLBRET_NOMATCH = -2,
TLBRET_BADADDR = -1,
TLBRET_MATCH = 0
};
#if defined(CONFIG_SOFTMMU)
static int get_physical_address(CPUTriCoreState *env, hwaddr *physical,
int *prot, target_ulong address,
MMUAccessType access_type, int mmu_idx)
{
int ret = TLBRET_MATCH;
*physical = address & 0xFFFFFFFF;
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
return ret;
}
hwaddr tricore_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
TriCoreCPU *cpu = TRICORE_CPU(cs);
hwaddr phys_addr;
int prot;
int mmu_idx = cpu_mmu_index(&cpu->env, false);
if (get_physical_address(&cpu->env, &phys_addr, &prot, addr,
MMU_DATA_LOAD, mmu_idx)) {
return -1;
}
return phys_addr;
}
#endif
/* TODO: Add exeption support*/
static void raise_mmu_exception(CPUTriCoreState *env, target_ulong address,
int rw, int tlb_error)
{
}
bool tricore_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
MMUAccessType rw, int mmu_idx,
bool probe, uintptr_t retaddr)
{
TriCoreCPU *cpu = TRICORE_CPU(cs);
CPUTriCoreState *env = &cpu->env;
hwaddr physical;
int prot;
int ret = 0;
rw &= 1;
ret = get_physical_address(env, &physical, &prot,
address, rw, mmu_idx);
// qemu_log_mask(CPU_LOG_MMU, "%s address=" TARGET_FMT_lx " ret %d physical "
// TARGET_FMT_plx " prot %d\n",
// __func__, (target_ulong)address, ret, physical, prot);
if (ret == TLBRET_MATCH) {
tlb_set_page(cs, address & TARGET_PAGE_MASK,
physical & TARGET_PAGE_MASK, prot | PAGE_EXEC,
mmu_idx, TARGET_PAGE_SIZE);
return true;
} else {
assert(ret < 0);
if (probe) {
return false;
}
raise_mmu_exception(env, address, rw, ret);
cpu_loop_exit_restore(cs, retaddr);
}
}
#if 0
static void tricore_cpu_list_entry(gpointer data, gpointer user_data)
{
ObjectClass *oc = data;
const char *typename;
char *name;
typename = object_class_get_name(oc);
name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_TRICORE_CPU));
qemu_printf(" %s\n", name);
g_free(name);
}
#endif
#if 0
void tricore_cpu_list(void)
{
GSList *list;
list = object_class_get_list_sorted(TYPE_TRICORE_CPU, false);
qemu_printf("Available CPUs:\n");
g_slist_foreach(list, tricore_cpu_list_entry, NULL);
g_slist_free(list);
}
#endif
void fpu_set_state(CPUTriCoreState *env)
{
set_float_rounding_mode(env->PSW & MASK_PSW_FPU_RM, &env->fp_status);
set_flush_inputs_to_zero(1, &env->fp_status);
set_flush_to_zero(1, &env->fp_status);
set_default_nan_mode(1, &env->fp_status);
}
uint32_t psw_read(CPUTriCoreState *env)
{
/* clear all USB bits */
env->PSW &= 0x6ffffff;
/* now set them from the cache */
env->PSW |= ((env->PSW_USB_C != 0) << 31);
env->PSW |= ((env->PSW_USB_V & (1 << 31)) >> 1);
env->PSW |= ((env->PSW_USB_SV & (1 << 31)) >> 2);
env->PSW |= ((env->PSW_USB_AV & (1 << 31)) >> 3);
env->PSW |= ((env->PSW_USB_SAV & (1 << 31)) >> 4);
return env->PSW;
}
void psw_write(CPUTriCoreState *env, uint32_t val)
{
env->PSW_USB_C = (val & MASK_USB_C);
env->PSW_USB_V = (val & MASK_USB_V) << 1;
env->PSW_USB_SV = (val & MASK_USB_SV) << 2;
env->PSW_USB_AV = (val & MASK_USB_AV) << 3;
env->PSW_USB_SAV = (val & MASK_USB_SAV) << 4;
env->PSW = val;
fpu_set_state(env);
}

View File

@@ -0,0 +1,163 @@
/*
* Copyright (c) 2012-2014 Bastian Koppelmann C-Lab/University Paderborn
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
Modified for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
Copyright 2022 Aptiv
*/
DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64)
DEF_HELPER_6(uc_traceopcode, void, ptr, i64, i64, i32, ptr, i64)
/* Arithmetic */
DEF_HELPER_3(add_ssov, i32, env, i32, i32)
DEF_HELPER_3(add64_ssov, i64, env, i64, i64)
DEF_HELPER_3(add_suov, i32, env, i32, i32)
DEF_HELPER_3(add_h_ssov, i32, env, i32, i32)
DEF_HELPER_3(add_h_suov, i32, env, i32, i32)
DEF_HELPER_4(addr_h_ssov, i32, env, i64, i32, i32)
DEF_HELPER_4(addsur_h_ssov, i32, env, i64, i32, i32)
DEF_HELPER_3(sub_ssov, i32, env, i32, i32)
DEF_HELPER_3(sub64_ssov, i64, env, i64, i64)
DEF_HELPER_3(sub_suov, i32, env, i32, i32)
DEF_HELPER_3(sub_h_ssov, i32, env, i32, i32)
DEF_HELPER_3(sub_h_suov, i32, env, i32, i32)
DEF_HELPER_4(subr_h_ssov, i32, env, i64, i32, i32)
DEF_HELPER_4(subadr_h_ssov, i32, env, i64, i32, i32)
DEF_HELPER_3(mul_ssov, i32, env, i32, i32)
DEF_HELPER_3(mul_suov, i32, env, i32, i32)
DEF_HELPER_3(sha_ssov, i32, env, i32, i32)
DEF_HELPER_3(absdif_ssov, i32, env, i32, i32)
DEF_HELPER_4(madd32_ssov, i32, env, i32, i32, i32)
DEF_HELPER_4(madd32_suov, i32, env, i32, i32, i32)
DEF_HELPER_4(madd64_ssov, i64, env, i32, i64, i32)
DEF_HELPER_5(madd64_q_ssov, i64, env, i64, i32, i32, i32)
DEF_HELPER_3(madd32_q_add_ssov, i32, env, i64, i64)
DEF_HELPER_5(maddr_q_ssov, i32, env, i32, i32, i32, i32)
DEF_HELPER_4(madd64_suov, i64, env, i32, i64, i32)
DEF_HELPER_4(msub32_ssov, i32, env, i32, i32, i32)
DEF_HELPER_4(msub32_suov, i32, env, i32, i32, i32)
DEF_HELPER_4(msub64_ssov, i64, env, i32, i64, i32)
DEF_HELPER_5(msub64_q_ssov, i64, env, i64, i32, i32, i32)
DEF_HELPER_3(msub32_q_sub_ssov, i32, env, i64, i64)
DEF_HELPER_5(msubr_q_ssov, i32, env, i32, i32, i32, i32)
DEF_HELPER_4(msub64_suov, i64, env, i32, i64, i32)
DEF_HELPER_3(absdif_h_ssov, i32, env, i32, i32)
DEF_HELPER_2(abs_ssov, i32, env, i32)
DEF_HELPER_2(abs_h_ssov, i32, env, i32)
/* hword/byte arithmetic */
DEF_HELPER_2(abs_b, i32, env, i32)
DEF_HELPER_2(abs_h, i32, env, i32)
DEF_HELPER_3(absdif_b, i32, env, i32, i32)
DEF_HELPER_3(absdif_h, i32, env, i32, i32)
DEF_HELPER_4(addr_h, i32, env, i64, i32, i32)
DEF_HELPER_4(addsur_h, i32, env, i64, i32, i32)
DEF_HELPER_5(maddr_q, i32, env, i32, i32, i32, i32)
DEF_HELPER_3(add_b, i32, env, i32, i32)
DEF_HELPER_3(add_h, i32, env, i32, i32)
DEF_HELPER_3(sub_b, i32, env, i32, i32)
DEF_HELPER_3(sub_h, i32, env, i32, i32)
DEF_HELPER_4(subr_h, i32, env, i64, i32, i32)
DEF_HELPER_4(subadr_h, i32, env, i64, i32, i32)
DEF_HELPER_5(msubr_q, i32, env, i32, i32, i32, i32)
DEF_HELPER_FLAGS_2(eq_b, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(eq_h, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(eqany_b, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(eqany_h, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(lt_b, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(lt_bu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(lt_h, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(lt_hu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(max_b, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(max_bu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(max_h, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(max_hu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(ixmax, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_FLAGS_2(ixmax_u, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_FLAGS_2(min_b, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(min_bu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(min_h, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(min_hu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(ixmin, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_FLAGS_2(ixmin_u, TCG_CALL_NO_RWG_SE, i64, i64, i32)
/* count leading ... */
DEF_HELPER_FLAGS_1(clo_h, TCG_CALL_NO_RWG_SE, i32, i32)
DEF_HELPER_FLAGS_1(clz_h, TCG_CALL_NO_RWG_SE, i32, i32)
DEF_HELPER_FLAGS_1(cls_h, TCG_CALL_NO_RWG_SE, i32, i32)
/* sh */
DEF_HELPER_FLAGS_2(sh, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(sh_h, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_3(sha, i32, env, i32, i32)
DEF_HELPER_2(sha_h, i32, i32, i32)
/* merge/split/parity */
DEF_HELPER_FLAGS_2(bmerge, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_1(bsplit, TCG_CALL_NO_RWG_SE, i64, i32)
DEF_HELPER_FLAGS_1(parity, TCG_CALL_NO_RWG_SE, i32, i32)
/* float */
DEF_HELPER_FLAGS_4(pack, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32, i32)
DEF_HELPER_1(unpack, i64, i32)
DEF_HELPER_3(fadd, i32, env, i32, i32)
DEF_HELPER_3(fsub, i32, env, i32, i32)
DEF_HELPER_3(fmul, i32, env, i32, i32)
DEF_HELPER_3(fdiv, i32, env, i32, i32)
DEF_HELPER_4(fmadd, i32, env, i32, i32, i32)
DEF_HELPER_4(fmsub, i32, env, i32, i32, i32)
DEF_HELPER_3(fcmp, i32, env, i32, i32)
DEF_HELPER_2(qseed, i32, env, i32)
DEF_HELPER_2(ftoi, i32, env, i32)
DEF_HELPER_2(itof, i32, env, i32)
DEF_HELPER_2(utof, i32, env, i32)
DEF_HELPER_2(ftoiz, i32, env, i32)
DEF_HELPER_2(ftouz, i32, env, i32)
DEF_HELPER_2(updfl, void, env, i32)
/* dvinit */
DEF_HELPER_3(dvinit_b_13, i64, env, i32, i32)
DEF_HELPER_3(dvinit_b_131, i64, env, i32, i32)
DEF_HELPER_3(dvinit_h_13, i64, env, i32, i32)
DEF_HELPER_3(dvinit_h_131, i64, env, i32, i32)
DEF_HELPER_FLAGS_2(dvadj, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_FLAGS_2(dvstep, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_FLAGS_2(dvstep_u, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_3(divide, i64, env, i32, i32)
DEF_HELPER_3(divide_u, i64, env, i32, i32)
/* mulh */
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(mulr_h, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32, i32, i32)
/* crc32 */
DEF_HELPER_FLAGS_2(crc32, TCG_CALL_NO_RWG_SE, i32, i32, i32)
/* CSA */
DEF_HELPER_2(call, void, env, i32)
DEF_HELPER_1(ret, void, env)
DEF_HELPER_2(bisr, void, env, i32)
DEF_HELPER_1(rfe, void, env)
DEF_HELPER_1(rfm, void, env)
DEF_HELPER_2(ldlcx, void, env, i32)
DEF_HELPER_2(lducx, void, env, i32)
DEF_HELPER_2(stlcx, void, env, i32)
DEF_HELPER_2(stucx, void, env, i32)
DEF_HELPER_1(svlcx, void, env)
DEF_HELPER_1(svucx, void, env)
DEF_HELPER_1(rslcx, void, env)
/* Address mode helper */
DEF_HELPER_1(br_update, i32, i32)
DEF_HELPER_2(circ_update, i32, i32, i32)
/* PSW cache helper */
DEF_HELPER_2(psw_write, void, env, i32)
DEF_HELPER_1(psw_read, i32, env)
/* Exceptions */
DEF_HELPER_3(raise_exception_sync, noreturn, env, i32, i32)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2012-2014 Bastian Koppelmann C-Lab/University Paderborn
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef QEMU_TRICORE_DEFS_H
#define QEMU_TRICORE_DEFS_H
#define TRICORE_TLB_MAX 128
#endif /* QEMU_TRICORE_DEFS_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,270 @@
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
/*
Created for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
Copyright 2022 Aptiv
*/
#include "qemu/typedefs.h"
#include "unicorn/unicorn.h"
#include "sysemu/cpus.h"
#include "sysemu/tcg.h"
#include "cpu.h"
#include "uc_priv.h"
#include "unicorn_common.h"
#include "unicorn.h"
TriCoreCPU *cpu_tricore_init(struct uc_struct *uc);
void tricore_set_pc(struct uc_struct *uc, uint64_t address)
{
((CPUTriCoreState *)uc->cpu->env_ptr)->PC = address;
}
void tricore_reg_reset(struct uc_struct *uc)
{
CPUTriCoreState *env;
(void)uc;
env = uc->cpu->env_ptr;
memset(env->gpr_a, 0, sizeof(env->gpr_a));
memset(env->gpr_d, 0, sizeof(env->gpr_d));
env->PC = 0;
}
static void reg_read(CPUTriCoreState *env, unsigned int regid, void *value)
{
if (regid >= UC_TRICORE_REG_A0 && regid <= UC_TRICORE_REG_A9)
*(int32_t *)value = env->gpr_a[regid - UC_TRICORE_REG_A0];
if (regid >= UC_TRICORE_REG_A12 && regid <= UC_TRICORE_REG_A15)
*(int32_t *)value = env->gpr_a[regid - UC_TRICORE_REG_A0];
else if (regid >= UC_TRICORE_REG_D0 && regid <= UC_TRICORE_REG_D15)
*(int32_t *)value = env->gpr_d[regid - UC_TRICORE_REG_D0];
else {
switch (regid) {
// case UC_TRICORE_REG_SP:
case UC_TRICORE_REG_A10:
*(int32_t *)value = env->gpr_a[10];
break;
// case UC_TRICORE_REG_LR:
case UC_TRICORE_REG_A11:
*(int32_t *)value = env->gpr_a[11];
break;
case UC_TRICORE_REG_PC:
*(int32_t *)value = env->PC;
break;
case UC_TRICORE_REG_PCXI:
*(int32_t *)value = env->PCXI;
break;
case UC_TRICORE_REG_PSW:
*(int32_t *)value = env->PSW;
break;
case UC_TRICORE_REG_PSW_USB_C:
*(int32_t *)value = env->PSW_USB_C;
break;
case UC_TRICORE_REG_PSW_USB_V:
*(int32_t *)value = env->PSW_USB_V;
break;
case UC_TRICORE_REG_PSW_USB_SV:
*(int32_t *)value = env->PSW_USB_SV;
break;
case UC_TRICORE_REG_PSW_USB_AV:
*(int32_t *)value = env->PSW_USB_AV;
break;
case UC_TRICORE_REG_PSW_USB_SAV:
*(int32_t *)value = env->PSW_USB_SAV;
break;
case UC_TRICORE_REG_SYSCON:
*(int32_t *)value = env->SYSCON;
break;
case UC_TRICORE_REG_CPU_ID:
*(int32_t *)value = env->CPU_ID;
break;
case UC_TRICORE_REG_BIV:
*(int32_t *)value = env->BIV;
break;
case UC_TRICORE_REG_BTV:
*(int32_t *)value = env->BTV;
break;
case UC_TRICORE_REG_ISP:
*(int32_t *)value = env->ISP;
break;
case UC_TRICORE_REG_ICR:
*(int32_t *)value = env->ICR;
break;
case UC_TRICORE_REG_FCX:
*(int32_t *)value = env->FCX;
break;
case UC_TRICORE_REG_LCX:
*(int32_t *)value = env->LCX;
break;
case UC_TRICORE_REG_COMPAT:
*(int32_t *)value = env->COMPAT;
break;
}
}
}
int tricore_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
int count)
{
CPUTriCoreState *env = &(TRICORE_CPU(uc->cpu)->env);
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
reg_read(env, regid, value);
}
return 0;
}
int tricore_context_reg_read(struct uc_context *uc, unsigned int *regs,
void **vals, int count)
{
CPUTriCoreState *env = (CPUTriCoreState *)uc->data;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
reg_read(env, regid, value);
}
return 0;
}
static void reg_write(CPUTriCoreState *env, unsigned int regid,
const void *value)
{
if (regid >= UC_TRICORE_REG_A0 && regid <= UC_TRICORE_REG_A9)
env->gpr_a[regid - UC_TRICORE_REG_A0] = *(int32_t *)value;
if (regid >= UC_TRICORE_REG_A12 && regid <= UC_TRICORE_REG_A15)
env->gpr_a[regid - UC_TRICORE_REG_A0] = *(int32_t *)value;
else if (regid >= UC_TRICORE_REG_D0 && regid <= UC_TRICORE_REG_D15)
env->gpr_d[regid - UC_TRICORE_REG_D0] = *(int32_t *)value;
else {
switch (regid) {
// case UC_TRICORE_REG_SP:
case UC_TRICORE_REG_A10:
env->gpr_a[10] = *(int32_t *)value;
break;
// case UC_TRICORE_REG_LR:
case UC_TRICORE_REG_A11:
env->gpr_a[11] = *(int32_t *)value;
break;
case UC_TRICORE_REG_PC:
env->PC = *(int32_t *)value;
break;
case UC_TRICORE_REG_PCXI:
env->PCXI = *(int32_t *)value;
break;
case UC_TRICORE_REG_PSW:
env->PSW = *(int32_t *)value;
break;
case UC_TRICORE_REG_PSW_USB_C:
env->PSW_USB_C = *(int32_t *)value;
break;
case UC_TRICORE_REG_PSW_USB_V:
env->PSW_USB_V = *(int32_t *)value;
break;
case UC_TRICORE_REG_PSW_USB_SV:
env->PSW_USB_SV = *(int32_t *)value;
break;
case UC_TRICORE_REG_PSW_USB_AV:
env->PSW_USB_AV = *(int32_t *)value;
break;
case UC_TRICORE_REG_PSW_USB_SAV:
env->PSW_USB_SAV = *(int32_t *)value;
break;
case UC_TRICORE_REG_SYSCON:
env->SYSCON = *(int32_t *)value;
break;
case UC_TRICORE_REG_CPU_ID:
env->CPU_ID = *(int32_t *)value;
break;
case UC_TRICORE_REG_BIV:
env->BIV = *(int32_t *)value;
break;
case UC_TRICORE_REG_BTV:
env->BTV = *(int32_t *)value;
break;
case UC_TRICORE_REG_ISP:
env->ISP = *(int32_t *)value;
break;
case UC_TRICORE_REG_ICR:
env->ICR = *(int32_t *)value;
break;
case UC_TRICORE_REG_FCX:
env->FCX = *(int32_t *)value;
break;
case UC_TRICORE_REG_LCX:
env->LCX = *(int32_t *)value;
break;
case UC_TRICORE_REG_COMPAT:
env->COMPAT = *(int32_t *)value;
break;
}
}
}
int tricore_reg_write(struct uc_struct *uc, unsigned int *regs,
void *const *vals, int count)
{
CPUTriCoreState *env = &(TRICORE_CPU(uc->cpu)->env);
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
reg_write(env, regid, value);
if (regid == UC_TRICORE_REG_PC) {
// force to quit execution and flush TB
uc->quit_request = true;
uc_emu_stop(uc);
}
}
return 0;
}
int tricore_context_reg_write(struct uc_context *uc, unsigned int *regs,
void *const *vals, int count)
{
CPUTriCoreState *env = (CPUTriCoreState *)uc->data;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
const void *value = vals[i];
reg_write(env, regid, value);
}
return 0;
}
static int tricore_cpus_init(struct uc_struct *uc, const char *cpu_model)
{
TriCoreCPU *cpu;
cpu = cpu_tricore_init(uc);
if (cpu == NULL) {
return -1;
}
return 0;
}
void tricore_uc_init(struct uc_struct *uc)
{
uc->reg_read = tricore_reg_read;
uc->reg_write = tricore_reg_write;
uc->reg_reset = tricore_reg_reset;
uc->set_pc = tricore_set_pc;
uc->cpus_init = tricore_cpus_init;
uc->cpu_context_size = offsetof(CPUTriCoreState, end_reset_fields);
uc_common_init(uc);
}

View File

@@ -0,0 +1,27 @@
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
/*
Modified for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
Copyright 2022 Aptiv
*/
#ifndef UC_QEMU_TARGET_TRICORE_H
#define UC_QEMU_TARGET_TRICORE_H
// functions to read & write registers
int tricore_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
int count);
int tricore_reg_write(struct uc_struct *uc, unsigned int *regs,
void *const *vals, int count);
int tricore_context_reg_read(struct uc_context *uc, unsigned int *regs,
void **vals, int count);
int tricore_context_reg_write(struct uc_context *uc, unsigned int *regs,
void *const *vals, int count);
void tricore_reg_reset(struct uc_struct *uc);
void tricore_uc_init(struct uc_struct *uc);
#endif