target: e2k: unpack long instructions.
This commit is contained in:
parent
c42af9ff35
commit
ff5127d36a
62
disas/e2k.h
62
disas/e2k.h
@ -364,44 +364,44 @@ typedef struct
|
||||
|
||||
|
||||
|
||||
int parse_alf_args (char **, const e2k_opcode_templ *);
|
||||
int parse_copf2_args (char **, const e2k_opcode_templ *);
|
||||
int parse_pref_args (char **, const e2k_opcode_templ *);
|
||||
int parse_copf4_args (char **, const e2k_opcode_templ *);
|
||||
int parse_nop_args (char **, const e2k_opcode_templ *);
|
||||
int parse_setcmd_args (char **, const e2k_opcode_templ *);
|
||||
int parse_setsft_args (char **, const e2k_opcode_templ *);
|
||||
int parse_wait_args (char **, const e2k_opcode_templ *);
|
||||
int parse_ct_args (char **, const e2k_opcode_templ *);
|
||||
int parse_hcall_args (char **, const e2k_opcode_templ *);
|
||||
int parse_ipd_args (char **, const e2k_opcode_templ *);
|
||||
static int parse_alf_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_copf2_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_pref_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_copf4_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_nop_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_setcmd_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_setsft_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_wait_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_ct_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_hcall_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_ipd_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
int parse_loop_mode_args (char **, const e2k_opcode_templ *);
|
||||
int parse_alc_args (char **, const e2k_opcode_templ *);
|
||||
int parse_abn_args (char **, const e2k_opcode_templ *);
|
||||
int parse_abp_args (char **, const e2k_opcode_templ *);
|
||||
int parse_abg_args (char **, const e2k_opcode_templ *);
|
||||
int parse_bap_args (char **, const e2k_opcode_templ *);
|
||||
int parse_eap_args (char **, const e2k_opcode_templ *);
|
||||
static int parse_loop_mode_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_alc_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_abn_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_abp_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_abg_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_bap_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_eap_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
|
||||
int parse_pass_args (char **, const e2k_opcode_templ *);
|
||||
int parse_andp_args (char **, const e2k_opcode_templ *);
|
||||
int parse_landp_args (char **, const e2k_opcode_templ *);
|
||||
int parse_ibranch_args (char **, const e2k_opcode_templ *);
|
||||
int parse_done_hret_glaunch_args (char **, const e2k_opcode_templ *);
|
||||
static int parse_pass_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_andp_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_landp_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_ibranch_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_done_hret_glaunch_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
int parse_incr_args (char **, const e2k_opcode_templ *);
|
||||
int parse_mova_args (char **, const e2k_opcode_templ *);
|
||||
int parse_fapb_args (char **, const e2k_opcode_templ *);
|
||||
int parse_movep_args (char **, const e2k_opcode_templ *);
|
||||
static int parse_incr_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_mova_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_fapb_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_movep_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
int parse_flushts_args (char **, const e2k_opcode_templ *);
|
||||
static int parse_flushts_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
int parse_cpl_args (char **, const e2k_opcode_templ *);
|
||||
static int parse_cpl_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
int parse_set_mark_args (char **, const e2k_opcode_templ *);
|
||||
int parse_vfdi_args (char **, const e2k_opcode_templ *);
|
||||
static int parse_set_mark_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_vfdi_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
|
||||
|
||||
|
@ -28,10 +28,10 @@
|
||||
void cpu_loop(CPUE2KState *env)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
int trapnr, n, sig;
|
||||
target_siginfo_t info;
|
||||
target_ulong addr;
|
||||
abi_long ret;
|
||||
int trapnr; //TODO , n, sig;
|
||||
//target_siginfo_t info;
|
||||
//target_ulong addr;
|
||||
//abi_long ret;
|
||||
|
||||
while (1) {
|
||||
cpu_exec_start(cs);
|
||||
@ -51,5 +51,6 @@ void cpu_loop(CPUE2KState *env)
|
||||
|
||||
void target_cpu_copy_regs(CPUE2KState *env, struct target_pt_regs *regs)
|
||||
{
|
||||
env->ip = regs->ip;
|
||||
// TODO
|
||||
}
|
||||
|
@ -77,6 +77,7 @@ struct target_sigcontext {
|
||||
void setup_frame(int sig, struct target_sigaction *ka,
|
||||
target_sigset_t *set, CPUE2KState *env)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "setup_frame: not implemented\n");
|
||||
}
|
||||
|
||||
void setup_rt_frame(int sig, struct target_sigaction *ka,
|
||||
@ -88,6 +89,8 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
||||
|
||||
long do_sigreturn(CPUE2KState *env)
|
||||
{
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
long do_rt_sigreturn(CPUE2KState *env)
|
||||
@ -96,3 +99,11 @@ long do_rt_sigreturn(CPUE2KState *env)
|
||||
qemu_log_mask(LOG_UNIMP, "do_rt_sigreturn: not implemented\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx,
|
||||
abi_ulong unew_ctx, abi_long ctx_size)
|
||||
{
|
||||
// TODO
|
||||
qemu_log_mask(LOG_UNIMP, "do_swapcontext: not implemented\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -20,11 +20,13 @@ static inline void cpu_set_tls(CPUE2KState *env, target_ulong newtls)
|
||||
static inline target_ulong cpu_get_tls(CPUE2KState *env)
|
||||
{
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline abi_ulong get_sp_from_cpustate(CPUE2KState *state)
|
||||
{
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* E2K_TARGET_CPU_H */
|
||||
|
@ -4,11 +4,17 @@
|
||||
/*
|
||||
* sigaltstack controls
|
||||
*/
|
||||
#define SS_ONSTACK 1
|
||||
#define SS_DISABLE 2
|
||||
#define TARGET_SS_ONSTACK 1
|
||||
#define TARGET_SS_DISABLE 2
|
||||
|
||||
#define MINSIGSTKSZ 4096
|
||||
#define SIGSTKSZ 8192
|
||||
#define TARGET_MINSIGSTKSZ 4096
|
||||
#define TARGET_SIGSTKSZ 8192
|
||||
#define TARGET_MCL_CURRENT 1
|
||||
#define TARGET_MCL_FUTURE 2
|
||||
#define TARGET_MCL_ONFAULT 4
|
||||
|
||||
#define TARGET_ARCH_HAS_SETUP_FRAME
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 0
|
||||
|
||||
#include "generic/signal.h"
|
||||
|
||||
|
@ -0,0 +1,28 @@
|
||||
#ifndef E2K_TARGET_STRUCTS_H
|
||||
#define E2K_TARGET_STRUCTS_H
|
||||
|
||||
struct target_ipc_perm {
|
||||
abi_int __key;
|
||||
abi_uint uid;
|
||||
abi_uint gid;
|
||||
abi_uint cuid;
|
||||
abi_uint cgid;
|
||||
abi_uint mode;
|
||||
abi_ushort __seq;
|
||||
};
|
||||
|
||||
struct target_shmid_ds {
|
||||
struct target_ipc_perm shm_perm;
|
||||
abi_int shm_segsz;
|
||||
abi_long shm_atime;
|
||||
abi_long shm_dtime;
|
||||
abi_long shm_ctime;
|
||||
abi_int shm_cpid;
|
||||
abi_int shm_lpid;
|
||||
abi_ushort shm_nattch;
|
||||
abi_ushort shm_unused;
|
||||
void *shm_unused2;
|
||||
void *shm_unused3;
|
||||
};
|
||||
|
||||
#endif
|
@ -2,7 +2,7 @@
|
||||
#define E2K_TARGET_SYSCALL_H
|
||||
|
||||
#define UNAME_MACHINE "e2k"
|
||||
#define UNAME_MINUMIM_RELEASE "2.6.32"
|
||||
#define UNAME_MINIMUM_RELEASE "2.6.32"
|
||||
|
||||
#define E2K_MAXNR 128 /* The total number of */
|
||||
/* quad-NRs */
|
||||
|
@ -1616,12 +1616,15 @@ typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
regs->ip = infop->entry;
|
||||
// TODO
|
||||
qemu_log_mask(LOG_UNIMP, "init_thread: not implemented\n");
|
||||
}
|
||||
|
||||
static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUE2KState *env)
|
||||
{
|
||||
// TODO
|
||||
qemu_log_mask(LOG_UNIMP, "elf_core_copy_regs: not implemented\n");
|
||||
}
|
||||
|
||||
#endif /* TARGET_E2K */
|
||||
|
@ -68,7 +68,9 @@ typedef struct target_sigaltstack {
|
||||
#define TARGET_SS_ONSTACK 1
|
||||
#define TARGET_SS_DISABLE 2
|
||||
|
||||
#ifndef TARGET_MINSIGSTKSZ
|
||||
#define TARGET_MINSIGSTKSZ 2048
|
||||
#endif
|
||||
|
||||
/* bit-flags */
|
||||
#define TARGET_SS_AUTODISARM (1U << 31) /* disable sas during sighandling */
|
||||
|
@ -85,7 +85,7 @@
|
||||
|
||||
#elif defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
|
||||
defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) || \
|
||||
defined(TARGET_MIPS)
|
||||
defined(TARGET_MIPS) || defined(TARGET_E2K)
|
||||
|
||||
#define TARGET_IOC_SIZEBITS 13
|
||||
#define TARGET_IOC_DIRBITS 3
|
||||
@ -1552,6 +1552,55 @@ struct target_stat64 {
|
||||
unsigned int __unused2;
|
||||
};
|
||||
|
||||
#elif defined(TARGET_E2K)
|
||||
#define TARGET_STAT_HAVE_NSEC
|
||||
struct target_stat {
|
||||
unsigned long st_dev;
|
||||
unsigned long st_ino;
|
||||
unsigned int st_mode;
|
||||
unsigned int st_nlink;
|
||||
unsigned int st_uid;
|
||||
unsigned int st_gid;
|
||||
unsigned long st_rdev;
|
||||
unsigned long __pad1;
|
||||
long st_size;
|
||||
int st_blksize;
|
||||
int __pad2;
|
||||
long st_blocks;
|
||||
int target_st_atime;
|
||||
unsigned int target_st_atime_nsec;
|
||||
int target_st_mtime;
|
||||
unsigned int target_st_mtime_nsec;
|
||||
int target_st_ctime;
|
||||
unsigned int target_st_ctime_nsec;
|
||||
unsigned int __unused4;
|
||||
unsigned int __unused5;
|
||||
};
|
||||
|
||||
#define TARGET_HAS_STRUCT_STAT64
|
||||
struct target_stat64 {
|
||||
unsigned long long st_dev;
|
||||
unsigned long long st_ino;
|
||||
unsigned int st_mode;
|
||||
unsigned int st_nlink;
|
||||
unsigned int st_uid;
|
||||
unsigned int st_gid;
|
||||
unsigned long long st_rdev;
|
||||
unsigned long long __pad0;
|
||||
long long st_size;
|
||||
int st_blksize;
|
||||
int __pad1;
|
||||
long long st_blocks;
|
||||
int target_st_atime;
|
||||
unsigned int target_st_atime_nsec;
|
||||
int target_st_mtime;
|
||||
unsigned int target_st_mtime_nsec;
|
||||
int target_st_ctime;
|
||||
unsigned int target_st_ctime_nsec;
|
||||
unsigned int __unused4;
|
||||
unsigned int __unused5;
|
||||
};
|
||||
|
||||
#elif defined(TARGET_PPC)
|
||||
|
||||
#define TARGET_STAT_HAVE_NSEC
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
OBJECT_DECLARE_CPU_TYPE(E2KCPU, E2KCPUClass, E2K_CPU)
|
||||
|
||||
typedef struct e2k_def_t e2k_def_t;
|
||||
/**
|
||||
* E2KCPUClass:
|
||||
* @parent_realize: The parent class' realize handler.
|
||||
@ -41,6 +42,7 @@ struct E2KCPUClass {
|
||||
|
||||
DeviceRealize parent_realize;
|
||||
DeviceReset parent_reset;
|
||||
e2k_def_t *cpu_def;
|
||||
};
|
||||
|
||||
|
||||
|
108
target/e2k/cpu.c
108
target/e2k/cpu.c
@ -30,14 +30,25 @@
|
||||
|
||||
//#define DEBUG_FEATURES
|
||||
|
||||
void cpu_e2k_set_id(CPUE2KState *env, unsigned int cpu);
|
||||
void e2k_cpu_dump_state(CPUState *cs, FILE *f, int flags);
|
||||
|
||||
static void e2k_cpu_reset(DeviceState *dev)
|
||||
{
|
||||
CPUState *cs = CPU(dev);
|
||||
E2KCPU *cpu = E2K_CPU(cs);
|
||||
E2KCPUClass *ecc = E2K_CPU_GET_CLASS(cpu);
|
||||
CPUE2KState *env = &cpu->env;
|
||||
|
||||
ecc->parent_reset(dev);
|
||||
|
||||
memset(env, 0, offsetof(CPUE2KState, end_reset_fields));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SOFTMMU
|
||||
static bool e2k_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||
{
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -47,30 +58,54 @@ static void cpu_e2k_disas_set_info(CPUState *cpu, disassemble_info *info)
|
||||
}
|
||||
|
||||
|
||||
void cpu_e2k_set_id(CPUSPARCState *env, unsigned int cpu)
|
||||
void cpu_e2k_set_id(CPUE2KState *env, unsigned int cpu)
|
||||
{
|
||||
// TODO
|
||||
qemu_log_mask(LOG_UNIMP, "cpu_e2k_set_id: not implemented\n");
|
||||
}
|
||||
|
||||
static const struct e2k_def_t e2k_defs[] = {
|
||||
{
|
||||
.name = "any",
|
||||
.isa_version = 0xffffffff,
|
||||
}
|
||||
};
|
||||
|
||||
void e2k_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
||||
{
|
||||
E2KCPU *cpu = E2K_CPU(cs);
|
||||
CPUE2KState *env = &cpu->env;
|
||||
|
||||
qemu_fprintf(f, "ip: " TARGET_FMT_lx " nip: " TARGET_FMT_lx "\n", env->ip,
|
||||
env->nip);
|
||||
}
|
||||
|
||||
static void e2k_cpu_set_pc(CPUState *cs, vaddr value)
|
||||
{
|
||||
E2KCPU *cpu = E2K_CPU(cs);
|
||||
|
||||
cpu->env.ip = value;
|
||||
// FIXME: what next IP should be?
|
||||
cpu->env.nip = value + 8;
|
||||
}
|
||||
|
||||
static void e2k_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb)
|
||||
{
|
||||
E2KCPU *cpu = E2K_CPU(cs);
|
||||
|
||||
cpu->env.ip = tb->pc;
|
||||
cpu->env.nip = tb->cs_base;
|
||||
}
|
||||
|
||||
static bool e2k_cpu_has_work(CPUState *cs)
|
||||
{
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *e2k_cpu_type_name(const char *cpu_model)
|
||||
{
|
||||
// TODO
|
||||
char *name = g_strdup_printf("%s", cpu_model);
|
||||
return name;
|
||||
}
|
||||
@ -88,23 +123,69 @@ static ObjectClass *e2k_cpu_class_by_name(const char *cpu_model)
|
||||
|
||||
static void e2k_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||
{
|
||||
CPUState *cs = CPU(dev);
|
||||
E2KCPUClass *ecc = E2K_CPU_GET_CLASS(dev);
|
||||
Error *local_err = NULL;
|
||||
E2KCPU *cpu = E2K_CPU(dev);
|
||||
CPUE2KState *env = &cpu->env;
|
||||
|
||||
env->version = env->def.isa_version;
|
||||
|
||||
cpu_exec_realizefn(cs, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_init_vcpu(cs);
|
||||
|
||||
ecc->parent_realize(dev, errp);
|
||||
}
|
||||
|
||||
static void e2k_cpu_initfn(Object* obj)
|
||||
{
|
||||
E2KCPU *cpu = E2K_CPU(obj);
|
||||
E2KCPUClass *ecc = E2K_CPU_GET_CLASS(obj);
|
||||
CPUE2KState *env = &cpu->env;
|
||||
|
||||
cpu_set_cpustate_pointers(cpu);
|
||||
|
||||
if (ecc->cpu_def) {
|
||||
env->def = *ecc->cpu_def;
|
||||
}
|
||||
}
|
||||
|
||||
static struct TCGCPUOps e2k_tcg_ops = {
|
||||
.initialize = e2k_tcg_initialize,
|
||||
.synchronize_from_tb = e2k_cpu_synchronize_from_tb,
|
||||
.do_interrupt = e2k_cpu_do_interrupt,
|
||||
#ifdef CONFIG_SOFTMMU
|
||||
.cpu_exec_interrupt = e2k_cpu_exec_interrupt,
|
||||
.tlb_fill = e2k_cpu_tlb_fill,
|
||||
#endif
|
||||
};
|
||||
|
||||
static void e2k_cpu_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
E2KCPUClass *scc = E2K_CPU_CLASS(oc);
|
||||
E2KCPUClass *ecc = E2K_CPU_CLASS(oc);
|
||||
CPUClass *cc = CPU_CLASS(oc);
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
device_class_set_parent_realize(dc, e2k_cpu_realizefn,
|
||||
&scc->parent_realize);
|
||||
&ecc->parent_realize);
|
||||
|
||||
device_class_set_parent_reset(dc, e2k_cpu_reset, &scc->parent_reset);
|
||||
device_class_set_parent_reset(dc, e2k_cpu_reset, &ecc->parent_reset);
|
||||
|
||||
cc->has_work = e2k_cpu_has_work;
|
||||
cc->dump_state = e2k_cpu_dump_state;
|
||||
cc->set_pc = e2k_cpu_set_pc;
|
||||
cc->class_by_name = e2k_cpu_class_by_name;
|
||||
cc->disas_set_info = cpu_e2k_disas_set_info;
|
||||
|
||||
cc->tcg_ops = &e2k_tcg_ops;
|
||||
}
|
||||
|
||||
static const TypeInfo sparc_cpu_type_info = {
|
||||
static const TypeInfo e2k_cpu_type_info = {
|
||||
.name = TYPE_E2K_CPU,
|
||||
.parent = TYPE_CPU,
|
||||
.instance_size = sizeof(E2KCPU),
|
||||
@ -116,11 +197,11 @@ static const TypeInfo sparc_cpu_type_info = {
|
||||
|
||||
static void e2k_cpu_cpudef_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
E2KCCPUClass *scc = E2K_CPU_CLASS(oc);
|
||||
scc->cpu_def = data;
|
||||
E2KCPUClass *ecc = E2K_CPU_CLASS(oc);
|
||||
ecc->cpu_def = data;
|
||||
}
|
||||
|
||||
/*static void e2k_register_cpudef_type(const struct e2k_def_t *def)
|
||||
static void e2k_register_cpudef_type(const struct e2k_def_t *def)
|
||||
{
|
||||
char *typename = e2k_cpu_type_name(def->name);
|
||||
TypeInfo ti = {
|
||||
@ -134,11 +215,14 @@ static void e2k_cpu_cpudef_class_init(ObjectClass *oc, void *data)
|
||||
g_free(typename);
|
||||
}
|
||||
|
||||
static void sparc_cpu_register_types(void)
|
||||
static void e2k_cpu_register_types(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
type_register_static(&sparc_cpu_type_info);
|
||||
type_register_static(&e2k_cpu_type_info);
|
||||
for (i = 0; i < ARRAY_SIZE(e2k_defs); i++) {
|
||||
e2k_register_cpudef_type(&e2k_defs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
type_init(sparc_cpu_register_types)
|
||||
type_init(e2k_cpu_register_types)
|
||||
|
@ -5,25 +5,46 @@
|
||||
#include "cpu-qom.h"
|
||||
#include "exec/cpu-defs.h"
|
||||
|
||||
void e2k_tcg_initialize(void);
|
||||
|
||||
#define MMU_USER_IDX 1
|
||||
#define CPU_RESOLVING_TYPE TYPE_E2K_CPU
|
||||
|
||||
struct e2k_def_t {
|
||||
const char *name;
|
||||
uint32_t isa_version;
|
||||
};
|
||||
|
||||
typedef struct CPUArchState {
|
||||
|
||||
/* register file */
|
||||
uint64_t gregs[32]; /* general registers */
|
||||
uint64_t pregs[224]; /* procedure regs, access through wreg */
|
||||
CPU_QuadU gregs[32]; /* general registers */
|
||||
CPU_QuadU pregs[224]; /* procedure regs, access through wreg */
|
||||
uint8_t greg_tags[32];
|
||||
uint8_t preg_tags[224];
|
||||
|
||||
/* control registers */
|
||||
uint64_t ctpr1; // Control Transfer Preparation Register (CTPR)
|
||||
uint64_t ctpr2;
|
||||
uint64_t ctpr3;
|
||||
target_ulong ctpr1; // Control Transfer Preparation Register (CTPR)
|
||||
target_ulong ctpr2;
|
||||
target_ulong ctpr3;
|
||||
|
||||
/* special registers */
|
||||
uint64_t *wreg; /* pointer to current window */
|
||||
target_ulong *wreg; /* pointer to current window */
|
||||
uint32_t br; /* base rsegister offset, max 128 */
|
||||
uint64_t ip, nip; /* instruction address, next instruction address */
|
||||
target_ulong ip, nip; /* instruction address, next instruction address */
|
||||
|
||||
uint32_t pfpfr; // Packed Floating Point Flag Register (PFPFR)
|
||||
uint32_t fpcr; // Floating point control register (FPCR)
|
||||
uint32_t fpsr; // Floating point state register (FPSR)
|
||||
|
||||
int interrupt_index;
|
||||
|
||||
/* Fields up to this point are cleared by a CPU reset */
|
||||
struct {} end_reset_fields;
|
||||
|
||||
uint32_t version;
|
||||
|
||||
struct e2k_def_t def;
|
||||
} CPUE2KState;
|
||||
|
||||
/**
|
||||
@ -41,4 +62,27 @@ struct ArchCPU {
|
||||
CPUE2KState env;
|
||||
};
|
||||
|
||||
static inline void cpu_get_tb_cpu_state(CPUE2KState *env, target_ulong *pc,
|
||||
target_ulong *cs_base, uint32_t *pflags)
|
||||
{
|
||||
*pc = env->ip;
|
||||
*cs_base = env->nip;
|
||||
*pflags = MMU_USER_IDX;
|
||||
}
|
||||
|
||||
static inline int cpu_mmu_index(CPUE2KState *env, bool ifetch)
|
||||
{
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
return MMU_USER_IDX;
|
||||
#else
|
||||
#error softmmu is not supported on E2K
|
||||
#endif
|
||||
}
|
||||
|
||||
int e2k_cpu_signal_handler(int host_signum, void *pinfo, void *puc);
|
||||
|
||||
#define cpu_signal_handler e2k_cpu_signal_handler
|
||||
|
||||
#include "exec/cpu-all.h"
|
||||
|
||||
#endif
|
||||
|
1
target/e2k/helper.h
Normal file
1
target/e2k/helper.h
Normal file
@ -0,0 +1 @@
|
||||
// include/exec/helper-proto.h needs this file
|
@ -1,5 +1,8 @@
|
||||
e2k_ss = ss.source_set()
|
||||
e2k_ss.add(files())
|
||||
e2k_ss.add(files(
|
||||
'cpu.c',
|
||||
'translate.c',
|
||||
))
|
||||
|
||||
# no softmmu support yet
|
||||
|
||||
|
360
target/e2k/translate.c
Normal file
360
target/e2k/translate.c
Normal file
@ -0,0 +1,360 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/translator.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
|
||||
typedef struct {
|
||||
DisasContextBase base;
|
||||
target_ulong pc;
|
||||
target_ulong npc;
|
||||
} DisasContext;
|
||||
|
||||
static struct unpacked_instr {
|
||||
unsigned int hs;
|
||||
unsigned int ss;
|
||||
unsigned int als[6];
|
||||
unsigned int cs0;
|
||||
unsigned short ales[6];
|
||||
unsigned int cs1;
|
||||
unsigned short aas[6];
|
||||
unsigned short half_gap;
|
||||
|
||||
/* It should be impossible to have more than 16 words of GAP
|
||||
in principle. */
|
||||
unsigned int gap[16];
|
||||
|
||||
unsigned int lts[4];
|
||||
unsigned int pls[3];
|
||||
unsigned int cds[3];
|
||||
|
||||
unsigned char ss_present;
|
||||
unsigned char als_present[6];
|
||||
unsigned char cs0_present;
|
||||
unsigned char ales_present[6];
|
||||
unsigned char cs1_present;
|
||||
unsigned char aas_present[6];
|
||||
unsigned char half_gap_present;
|
||||
unsigned char gap_present[16];
|
||||
unsigned char lts_present[4];
|
||||
unsigned char pls_present[3];
|
||||
unsigned char cds_present[3];
|
||||
|
||||
unsigned int api_l[2];
|
||||
unsigned int api_r[2];
|
||||
} unpacked_instr;
|
||||
|
||||
// TODO: return error on invalid instruction
|
||||
static target_ulong unpack_instr(CPUE2KState *env, DisasContext *ctx, target_ulong pos,
|
||||
struct unpacked_instr *instr)
|
||||
{
|
||||
unsigned int i;
|
||||
target_ulong gap, next_pc = pos + 8;
|
||||
int hsyll_cntr = 0;
|
||||
unsigned int hs;
|
||||
unsigned int mdl;
|
||||
memset (instr, 0, sizeof (unpacked_instr));
|
||||
|
||||
hs = translator_ldl(env, &ctx->base, pos);
|
||||
pos += 4;
|
||||
instr->hs = hs;
|
||||
next_pc += ((hs & 0x70) >> 4) * 8;
|
||||
|
||||
/* Check for SS. */
|
||||
if (hs & (0x1 << 12))
|
||||
{
|
||||
instr->ss_present = 1;
|
||||
instr->ss = translator_ldl(env, &ctx->base, pos);
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
/* Check for available ALS syllables. */
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
if (hs & (1 << (26 + i)))
|
||||
{
|
||||
instr->als_present[i] = 1;
|
||||
instr->als[i] = translator_ldl(env, &ctx->base, pos);
|
||||
pos += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for CS0. */
|
||||
if (hs & (0x1 << 14))
|
||||
{
|
||||
instr->cs0_present = 1;
|
||||
instr->cs0 = translator_ldl(env, &ctx->base, pos);
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
/* If either `ALES5' or `ALES2' has been marked as present in HS, set its
|
||||
value to default to properly account for the case when it's not allocated.
|
||||
`ALES_PRESENT[{2,5}]' are treated this way in the code below: 0 means that
|
||||
the syllable has been neither marked in HS, nor allocated; 1 - marked in
|
||||
HS, but not allocated; 2 - not marked in HS, but allocated; 3 - both marked
|
||||
in HS and allocated. */
|
||||
if (hs & (0x1 << 25))
|
||||
{
|
||||
instr->ales_present[5] = 1;
|
||||
instr->ales[5] = 0x01c0;
|
||||
}
|
||||
|
||||
if (hs & (0x1 << 22))
|
||||
{
|
||||
instr->ales_present[2] = 1;
|
||||
instr->ales[2] = 0x01c0;
|
||||
}
|
||||
|
||||
|
||||
/* Calculate the size of f1 fragment in bytes. For a valid instruction it
|
||||
should be equal to either of `pos', `pos + 4' or `pos + 8'. What should I
|
||||
do if it's not? */
|
||||
mdl = ((hs & 0xf) + 1) * 4;
|
||||
|
||||
/* The following condition means that ALES{2,5} are physically present within
|
||||
the wide instruction. However, they should be probably taken into account
|
||||
only if HS.ale{2,5} are set. Should I disassemble them if these bits are
|
||||
not set but the syllables physically exist? */
|
||||
if (((hs & (0x1 << 15)) && mdl == pos + 8)
|
||||
|| (!(hs & (0x1 << 15)) && mdl == pos + 4))
|
||||
{
|
||||
/* Fill in ALES5 and ALES2 syllables even if none of them is specified in
|
||||
HS as present. This will let me output this syllable into disassembly
|
||||
whichever case takes place. */
|
||||
instr->ales[5] = translator_lduw(env, &ctx->base, pos);
|
||||
instr->ales[2] = translator_lduw(env, &ctx->base, pos + 2);
|
||||
|
||||
/* Adjust `ALES_PRESENT[{5,2}]' as proposed above now that we know that
|
||||
they are allocated. */
|
||||
instr->ales_present[5] |= 0x2;
|
||||
instr->ales_present[2] |= 0x2;
|
||||
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
/* Check for CS1. */
|
||||
if (hs & (0x1 << 15))
|
||||
{
|
||||
instr->cs1_present = 1;
|
||||
instr->cs1 = translator_ldl(env, &ctx->base, pos);
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
/* A primitive control just for a moment. */
|
||||
if (mdl != pos)
|
||||
{
|
||||
/* This is either an APB instruction or an invalid one. Let's stupidly
|
||||
believe that the former takes place and signalize our caller about
|
||||
that by returning 0. */
|
||||
|
||||
return next_pc;
|
||||
}
|
||||
|
||||
|
||||
/* Check for ALES{0,1,3,4}. */
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
if (i == 2)
|
||||
continue;
|
||||
|
||||
if (hs & (0x1 << (20 + i)))
|
||||
{
|
||||
instr->ales_present[i] = 1;
|
||||
|
||||
/* Recall the idiotic order of half-syllables in the packed wide
|
||||
instruction. */
|
||||
instr->ales[i] = translator_lduw(env,
|
||||
pos + 2 * ((hsyll_cntr & ~0x1) + 1 - (hsyll_cntr & 0x1)));
|
||||
hsyll_cntr++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for AASj half-syllables. To encode them SS syllable of SF1 type
|
||||
should be present. */
|
||||
if (instr->ss_present && (instr->ss & (0x1 << 20)) == 0)
|
||||
{
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (instr->ss & (0x1 << (12 + i)))
|
||||
{
|
||||
instr->aas_present[i >> 1] = 1;
|
||||
instr->aas_present[2 + i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
if (instr->aas_present[i])
|
||||
{
|
||||
/* Recall the idiotic order of half-syllables in the packed wide
|
||||
instruction. Note that the first AAS half-syllable may share a
|
||||
syllable with the last ALES. */
|
||||
instr->aas[i] = translator_lduw(env,
|
||||
pos + 2 * ((hsyll_cntr & ~0x1) + 1 - (hsyll_cntr & 0x1)));
|
||||
hsyll_cntr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hsyll_cntr & 0x1)
|
||||
{
|
||||
/* Simplify the calculation of offset in BUF[] a bit by taking the above
|
||||
condition into account. */
|
||||
instr->half_gap = translator_lduw(env, pos + 2 * (hsyll_cntr & ~0x1));
|
||||
instr->half_gap_present = 1;
|
||||
|
||||
/* Ensure that hsyll_cntr is even. This is implied when calculating GAP
|
||||
below. */
|
||||
hsyll_cntr++;
|
||||
}
|
||||
|
||||
/* Calculate the next 32-bit syllable's position. It may be the uppermost LTS
|
||||
syllable. Note that I don't consider the case when LTS syllables reuse the
|
||||
values encoded in the preceding ones, though according to `iset-v5.single'
|
||||
this is quite legal. GAS doesn't produce such a code. Hopefully neither LAS
|
||||
has ever done that . . . */
|
||||
gap = pos + 2 * hsyll_cntr;
|
||||
|
||||
/* Set POS to point to the last syllable in the current wide instruction and
|
||||
extract CDSj and PLSj syllables if any. */
|
||||
pos = ((((hs & 0x70) >> 4) + 1) << 3) - 4;
|
||||
|
||||
/* Check for CDSj syllables. */
|
||||
for (i = 0; i < ((hs & 0x30000) >> 16); i++)
|
||||
{
|
||||
instr->cds_present[i] = 1;
|
||||
instr->cds[i] = translator_ldl(env, &ctx->base, pos);
|
||||
pos -= 4;
|
||||
}
|
||||
|
||||
|
||||
/* Check for PLSj syllables. */
|
||||
for (i = 0; i < ((hs & 0xc0000) >> 18); i++)
|
||||
{
|
||||
instr->pls_present[i] = 1;
|
||||
instr->pls[i] = translator_ldl(env, &ctx->base, pos);
|
||||
pos -= 4;
|
||||
}
|
||||
|
||||
/* Now POS should point to the lowermost LTS0 syllable if any. If there are
|
||||
no LTSj syllables in this instruction, POS should point to the last
|
||||
syllable consisting of half-syllables.
|
||||
|
||||
If neither of these conditions holds true, believe that it's not a valid
|
||||
synchronous instruction by analogy with the middle point test above.
|
||||
Engineers are said to customize instructions with references to missing
|
||||
literal syllables occasionally, but the lack of space for more substantial
|
||||
syllables should not be allowed for. */
|
||||
if (pos < gap && pos != gap - 4)
|
||||
return next_pc;
|
||||
|
||||
/* Extract available LTSj syllables. */
|
||||
for (i = 0; i < 4 && pos >= gap; i++)
|
||||
{
|
||||
instr->lts_present[i] = 1;
|
||||
instr->lts[i] = translator_ldl(env, &ctx->base, pos);
|
||||
pos -= 4;
|
||||
}
|
||||
|
||||
/* It makes sense to enumerate GAP syllables in a normal order unlike LTS
|
||||
ones. */
|
||||
for (i = 0; i < 16 && gap <= pos; i++)
|
||||
{
|
||||
instr->gap_present[i] = 1;
|
||||
instr->gap[i] = translator_ldl(env, &ctx->base, gap);
|
||||
gap += 4;
|
||||
}
|
||||
|
||||
|
||||
return next_pc;
|
||||
}
|
||||
|
||||
static target_ulong disas_e2k_insn(DisasContext *dc, CPUState *cs)
|
||||
{
|
||||
E2KCPU *cpu = E2K_CPU(cs);
|
||||
CPUE2KState *env = &cpu->env;
|
||||
struct unpacked_instr *instr = &unpacked_instr;
|
||||
target_ulong next_pc = unpack_instr(env, dc, dc->base.pc_next, instr);
|
||||
|
||||
// TODO: gen ops
|
||||
qemu_log_mask(LOG_UNIMP, "disas_e2k_insn: not implemented, ip 0x%lx, HS 0x%x\n",
|
||||
dc->base.pc_next, instr->hs);
|
||||
|
||||
return next_pc;
|
||||
}
|
||||
|
||||
static void e2k_tr_init_disas_context(DisasContextBase *db, CPUState *cs)
|
||||
{
|
||||
DisasContext *dc = container_of(db, DisasContext, base);
|
||||
|
||||
dc->pc = dc->base.pc_first;
|
||||
dc->npc = dc->base.pc_next;
|
||||
}
|
||||
|
||||
static void e2k_tr_tb_start(DisasContextBase *db, CPUState *cs)
|
||||
{
|
||||
// TODO
|
||||
qemu_log_mask(LOG_UNIMP, "e2k_tr_tb_start: not implemented\n");
|
||||
}
|
||||
|
||||
static void e2k_tr_insn_start(DisasContextBase *db, CPUState *cs)
|
||||
{
|
||||
DisasContext *dc = container_of(db, DisasContext, base);
|
||||
tcg_gen_insn_start(dc->pc);
|
||||
// FIXME: stop decoding on page boundary?
|
||||
}
|
||||
|
||||
static bool e2k_tr_breakpoint_check(DisasContextBase *db, CPUState *cs,
|
||||
const CPUBreakpoint *bp)
|
||||
{
|
||||
// TODO
|
||||
qemu_log_mask(LOG_UNIMP, "e2k_tr_breakpoint_check: not implemented\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
static void e2k_tr_translate_insn(DisasContextBase *db, CPUState *cs)
|
||||
{
|
||||
DisasContext *dc = container_of(db, DisasContext, base);
|
||||
dc->base.pc_next = disas_e2k_insn(dc, cs);
|
||||
}
|
||||
|
||||
static void e2k_tr_tb_stop(DisasContextBase *db, CPUState *cs)
|
||||
{
|
||||
// TODO
|
||||
qemu_log_mask(LOG_UNIMP, "e2k_tr_tb_stop: not implemented\n");
|
||||
}
|
||||
|
||||
static void e2k_tr_disas_log(const DisasContextBase *db, CPUState *cpu)
|
||||
{
|
||||
// TODO
|
||||
qemu_log_mask(LOG_UNIMP, "e2k_tr_disas_log: not implemented\n");
|
||||
}
|
||||
|
||||
static const TranslatorOps e2k_tr_ops = {
|
||||
.init_disas_context = e2k_tr_init_disas_context,
|
||||
.tb_start = e2k_tr_tb_start,
|
||||
.insn_start = e2k_tr_insn_start,
|
||||
.breakpoint_check = e2k_tr_breakpoint_check,
|
||||
.translate_insn = e2k_tr_translate_insn,
|
||||
.tb_stop = e2k_tr_tb_stop,
|
||||
.disas_log = e2k_tr_disas_log,
|
||||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
|
||||
{
|
||||
DisasContext dc = {};
|
||||
|
||||
translator_loop(&e2k_tr_ops, &dc.base, cs, tb, max_insns);
|
||||
}
|
||||
|
||||
void restore_state_to_opc(CPUE2KState *env, TranslationBlock *tb,
|
||||
target_ulong *data)
|
||||
{
|
||||
// TODO
|
||||
qemu_log_mask(LOG_UNIMP, "restore_state_to_opc: not implemented\n");
|
||||
}
|
||||
|
||||
void e2k_tcg_initialize(void) {
|
||||
// TODO
|
||||
qemu_log_mask(LOG_UNIMP, "e2k_tcg_initialize: not implemented\n");
|
||||
}
|
Loading…
Reference in New Issue
Block a user