target: e2k: unpack long instructions.

This commit is contained in:
Denis Drakhnia 2020-11-08 20:27:47 +02:00 committed by Denis Drakhnia
parent c42af9ff35
commit ff5127d36a
16 changed files with 658 additions and 62 deletions

View File

@ -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; }

View File

@ -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
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -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"

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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;
};

View File

@ -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)

View File

@ -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
View File

@ -0,0 +1 @@
// include/exec/helper-proto.h needs this file

View 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
View 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");
}