diff --git a/disas/e2k.h b/disas/e2k.h index 5f5e8f316d..c749a10be3 100644 --- a/disas/e2k.h +++ b/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; } diff --git a/linux-user/e2k/cpu_loop.c b/linux-user/e2k/cpu_loop.c index 6a3ebd1aaa..e395f86674 100644 --- a/linux-user/e2k/cpu_loop.c +++ b/linux-user/e2k/cpu_loop.c @@ -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 } diff --git a/linux-user/e2k/signal.c b/linux-user/e2k/signal.c index 6a641d06ba..4bfcfe2c53 100644 --- a/linux-user/e2k/signal.c +++ b/linux-user/e2k/signal.c @@ -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; +} diff --git a/linux-user/e2k/target_cpu.h b/linux-user/e2k/target_cpu.h index dc48cc5925..3f19fec363 100644 --- a/linux-user/e2k/target_cpu.h +++ b/linux-user/e2k/target_cpu.h @@ -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 */ diff --git a/linux-user/e2k/target_signal.h b/linux-user/e2k/target_signal.h index 76234bfef6..0d0bbff886 100644 --- a/linux-user/e2k/target_signal.h +++ b/linux-user/e2k/target_signal.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" diff --git a/linux-user/e2k/target_structs.h b/linux-user/e2k/target_structs.h index e69de29bb2..888c836b47 100644 --- a/linux-user/e2k/target_structs.h +++ b/linux-user/e2k/target_structs.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 diff --git a/linux-user/e2k/target_syscall.h b/linux-user/e2k/target_syscall.h index c9cfacab31..06e2df3e2e 100644 --- a/linux-user/e2k/target_syscall.h +++ b/linux-user/e2k/target_syscall.h @@ -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 */ diff --git a/linux-user/elfload.c b/linux-user/elfload.c index e11a7a360f..bb6bde5648 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -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 */ diff --git a/linux-user/generic/signal.h b/linux-user/generic/signal.h index 6fd05b77bb..3c58a5a962 100644 --- a/linux-user/generic/signal.h +++ b/linux-user/generic/signal.h @@ -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 */ diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 4587b62ac9..7402c41578 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -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 diff --git a/target/e2k/cpu-qom.h b/target/e2k/cpu-qom.h index 1d0065e07c..98d7ad88de 100644 --- a/target/e2k/cpu-qom.h +++ b/target/e2k/cpu-qom.h @@ -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; }; diff --git a/target/e2k/cpu.c b/target/e2k/cpu.c index a4b2480005..2bba447e7d 100644 --- a/target/e2k/cpu.c +++ b/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); - - device_class_set_parent_reset(dc, e2k_cpu_reset, &scc->parent_reset); + &ecc->parent_realize); + 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) diff --git a/target/e2k/cpu.h b/target/e2k/cpu.h index 6a97eb7c79..a411c3514a 100644 --- a/target/e2k/cpu.h +++ b/target/e2k/cpu.h @@ -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 diff --git a/target/e2k/helper.h b/target/e2k/helper.h new file mode 100644 index 0000000000..6892886640 --- /dev/null +++ b/target/e2k/helper.h @@ -0,0 +1 @@ +// include/exec/helper-proto.h needs this file diff --git a/target/e2k/meson.build b/target/e2k/meson.build index 33e43ceaa8..9dfaadae50 100644 --- a/target/e2k/meson.build +++ b/target/e2k/meson.build @@ -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 diff --git a/target/e2k/translate.c b/target/e2k/translate.c new file mode 100644 index 0000000000..95c02133c8 --- /dev/null +++ b/target/e2k/translate.c @@ -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"); +}