qemu-e2k/target/e2k/translate.h

599 lines
14 KiB
C

#ifndef E2K_TRANSLATE_H
#define E2K_TRANSLATE_H
#include "tcg/tcg-op.h"
#include "exec/translator.h"
#define DYNAMIC -1
#define IS_BASED(i) (((i) & 0x80) == 0)
#define IS_REGULAR(i) (((i) & 0xc0) == 0x80)
#define IS_IMM5(i) (((i) & 0xe0) == 0xc0)
#define IS_IMM4(i) (((i) & 0xf0) == 0xc0)
#define IS_LIT(i) (((i) & 0xf0) == 0xd0)
#define IS_LIT16_LO(i) (((i) & 0x0e) == 0x00)
#define IS_LIT16_HI(i) (((i) & 0x0e) == 0x04)
#define IS_LIT32(i) (((i) & 0x0c) == 0x08)
#define IS_LIT64(i) (((i) & 0x0c) == 0x0c)
#define IS_GLOBAL(i) (((i) & 0xe0) == 0xe0)
#define GET_BASED(i) ((i) & 0x7f)
#define GET_REGULAR(i) ((i) & 0x3f)
#define GET_IMM5(i) ((i) & 0x1f)
#define GET_IMM4(i) ((i) & 0x0f)
#define GET_LIT(i) ((i) & 0x03)
#define GET_GLOBAL(i) ((i) & 0x1f)
typedef enum {
ALES_NONE = 0x00,
ALES_PRESENT = 0x01,
ALES_ALLOCATED = 0x02,
} AlesFlag;
typedef struct {
TCGv_i32 cdi[32];
TCGv_i64 pib[32];
} CPUE2KAauPrefStateTCG;
typedef struct CPUE2KStateTCG {
TCGv pc;
TCGv npc;
TCGv_i64 ctprs[3];
TCGv_i32 ct_cond;
TCGv_i32 is_bp; /* breakpoint flag */
TCGv_i32 wdbl;
TCGv_i32 wd_base; /* holds wbs * 2 */
TCGv_i32 wd_size; /* holds wsz * 2 */
TCGv_i32 boff; /* holds rbs * 2 */
TCGv_i32 bsize; /* holds rsz * 2 + 2 */
TCGv_i32 bcur; /* holds rcur * 2 */
TCGv_i64 pregs;
TCGv_i32 psize; /* holds psz */
TCGv_i32 pcur; /* holds pcur */
/* lsr */
TCGv_i32 lsr_lcnt;
TCGv_i32 lsr_ecnt;
TCGv_i32 lsr_vlc;
TCGv_i32 lsr_over;
TCGv_i32 lsr_pcnt;
TCGv_i32 lsr_strmd;
/* AAU */
TCGv_i32 aasti[16];
TCGv_i32 aasti_tags;
TCGv_i32 aaind[16];
TCGv_i32 aaind_tags;
TCGv_i32 aaincr[8];
TCGv_i32 aaincr_tags;
TCGv_i64 aad_lo[32];
TCGv_i64 aad_hi[32];
CPUE2KAauPrefStateTCG aapl, aapr;
} CPUE2KStateTCG;
extern struct CPUE2KStateTCG e2k_cs;
typedef struct {
uint32_t hs;
uint32_t ss;
uint32_t als[6];
uint32_t cs0;
uint16_t ales[6];
uint32_t cs1;
uint16_t aas[6];
uint32_t lts[4];
uint32_t pls[3];
uint32_t cds[3];
bool ss_present;
bool als_present[6];
bool cs0_present;
AlesFlag ales_present[6];
bool cs1_present;
bool aas_present[6];
bool lts_present[4];
bool pls_present[3];
bool cds_present[3];
} UnpackedBundle;
typedef struct {
int32_t sdisp; /* CS0 28:0 */
} Cs0IBranch, Cs0Puttsd;
typedef struct {
int32_t sdisp; /* CS0 28:0 */
uint8_t ipd; /* SS 31:30 */
uint8_t ctpr; /* CS0 31:30 */
uint8_t opc;
} Cs0Disp;
typedef struct {
uint32_t disp; /* CS0 28:0 */
uint8_t ipd; /* SS 31:30 */
uint8_t ctpr; /* CS0 31:30 */
} Cs0SDisp;
typedef struct {
uint8_t ipd;
} Cs0Return;
typedef struct {
uint32_t disp; /* 28:4 */
uint8_t prefr; /* 2:0 */
uint8_t ipd; /* 3 */
} Cs0Pref;
typedef enum {
CS0_NONE,
CS0_IBRANCH,
CS0_PREF,
CS0_PUTTSD,
CS0_DONE,
CS0_HRET,
CS0_GLAUNCH,
CS0_DISP,
CS0_SDISP,
CS0_GETTSD,
CS0_RETURN,
} Cs0Type;
typedef struct {
Cs0Type type;
union {
Cs0IBranch ibranch;
Cs0Puttsd puttsd;
Cs0Disp disp;
Cs0SDisp sdisp;
Cs0Pref pref;
Cs0Return ret;
};
} Cs0;
typedef enum {
SETR_VFRPSZ = 0x01,
SETR_WD = 0x02,
SETR_BN = 0x04,
SETR_BP = 0x08,
} SetrType;
typedef struct {
SetrType type;
uint8_t rpsz;
uint8_t wsz;
bool nfx;
bool dbl;
uint8_t rbs;
uint8_t rsz;
uint8_t rcur;
uint8_t psz;
} Cs1Setr;
typedef struct {
bool ma_c;
bool fl_c;
bool ld_c;
bool st_c;
bool all_e;
bool all_c;
/* v2+ */
bool trap;
/* v5+ */
bool sal;
bool sas;
} Cs1Wait;
typedef struct {
uint8_t wbs;
uint8_t disp;
} Cs1HCall;
typedef struct {
bool flushr;
bool flushc;
} Cs1Flush;
typedef struct {
bool chkm4;
uint8_t dmask;
uint8_t umask;
} Cs1Vfbg;
typedef enum {
CS1_NONE,
CS1_SETR,
CS1_SETEI,
CS1_SETSFT,
CS1_WAIT,
CS1_CALL,
CS1_HCALL,
CS1_MAS,
CS1_FLUSH,
CS1_VFBG,
} Cs1Type;
typedef struct {
Cs1Type type;
union {
Cs1Setr setr;
uint8_t ei;
Cs1Wait wait;
uint8_t call_wbs;
Cs1HCall hcall;
uint8_t mas[6];
Cs1Flush flush;
Cs1Vfbg vfbg;
};
} Cs1;
typedef enum {
ALOPF_NONE,
ALOPF1,
ALOPF1_MERGE,
ALOPF2,
ALOPF3,
ALOPF7,
ALOPF8,
ALOPF10,
ALOPF11,
ALOPF11_MERGE,
ALOPF11_LIT8,
ALOPF12,
ALOPF12_PSHUFH,
ALOPF12_IBRANCHD,
ALOPF12_ICALLD,
ALOPF13,
ALOPF15,
ALOPF16,
ALOPF17,
ALOPF21,
ALOPF21_ICOMB,
ALOPF21_FCOMB,
ALOPF21_PFCOMB,
ALOPF21_LCOMB,
ALOPF22,
} Alopf;
typedef struct {
Alopf format;
uint32_t op;
const char *name;
} Alop;
typedef struct {
Cs0 cs0;
Cs1 cs1;
Alop alops[6];
} Bundle;
typedef enum {
AL_RESULT_NONE = 0,
AL_RESULT_SIZE_MASK = 0x3,
AL_RESULT_32 = 0x00,
AL_RESULT_64 = 0x01,
AL_RESULT_80 = 0x02,
AL_RESULT_128 = 0x03,
AL_RESULT_TYPE_MASK = 0xc,
AL_RESULT_REG = 0x04,
AL_RESULT_PREG = 0x08,
AL_RESULT_CTPR = 0x0c,
AL_RESULT_REG32 = AL_RESULT_REG | AL_RESULT_32,
AL_RESULT_REG64 = AL_RESULT_REG | AL_RESULT_64,
AL_RESULT_REG80 = AL_RESULT_REG | AL_RESULT_80,
AL_RESULT_REG128 = AL_RESULT_REG | AL_RESULT_128,
AL_RESULT_CTPR32 = AL_RESULT_CTPR | AL_RESULT_32,
AL_RESULT_CTPR64 = AL_RESULT_CTPR | AL_RESULT_64,
} AlResultType;
#define e2k_al_result_size(x) ((x) & AL_RESULT_SIZE_MASK)
#define e2k_al_result_type(x) ((x) & AL_RESULT_TYPE_MASK)
typedef struct {
AlResultType type;
/* check tag for 32-bit ops if wdbl is set */
bool check_tag;
/* poison result if tag is not zero */
bool poison;
/* Is 32-bit op affected by wdbl */
bool dbl;
union {
struct {
TCGv_i32 index;
TCGv_i32 tag;
union {
TCGv_i32 v32;
TCGv_i64 v64;
};
union {
TCGv_i32 x32; /* FX ops */
TCGv_i64 x64; /* SIMD ops v5+ */
};
} reg;
struct {
int index;
union {
TCGv_i32 v32;
TCGv_i64 v64;
};
} ctpr;
struct {
int index;
TCGv_i32 val;
} preg;
};
} AlResult;
typedef struct {
bool is_set;
uint8_t dst;
TCGv_i32 index;
TCGv_i32 tag;
TCGv_i64 value;
} AauResult;
typedef struct {
int reg; // -1 means do not write
TCGv_i32 value;
} PlResult;
typedef enum {
CT_NONE,
CT_IBRANCH,
CT_JUMP,
CT_CALL,
} ControlTransferType;
typedef struct {
ControlTransferType type;
union {
target_ulong target;
TCGv_i64 ctpr;
} u;
int wbs;
uint8_t cond_type;
uint8_t psrc;
} ControlTransfer;
typedef struct DisasContext {
DisasContextBase base;
UnpackedBundle bundle;
Bundle bundle2;
target_ulong pc;
int jump_ctpr;
int mmuidx;
uint8_t mas[6];
bool loop_mode;
TCGv_i32 is_epilogue;
/* optional, can be NULL */
TCGv_i32 mlock;
int version;
/* Force ILLOP for bad instruction format for cases where real CPU
do not generate it. */
bool strict;
// Temporary values.
TCGv_i32 t32[64];
TCGv_i64 t64[32];
TCGv ttl[8];
// Allocated temporary values count.
int t32_len;
int t64_len;
int ttl_len;
/* Delayed illegal tag check */
TCGv_i32 illtag;
bool do_check_illtag;
/* Delayed window bounds check */
int wd_size;
int max_r;
int max_r_src;
int max_r_dst;
int bsize;
int max_b;
int max_b_cur;
TCGv_i64 cond[6];
AlResult al_results[6];
TCGv_i32 al_cond[6];
AauResult aau_results[4];
int aau_am[4];
PlResult pl_results[3];
ControlTransfer ct;
} DisasContext;
static inline void gen_save_pc(target_ulong pc)
{
tcg_gen_movi_tl(e2k_cs.pc, pc);
}
static inline void gen_save_cpu_state(DisasContext *ctx)
{
gen_save_pc(ctx->pc);
}
static inline void gen_tr_exception(DisasContext *ctx, int exception_index)
{
TCGv_i32 t0 = tcg_const_i32(exception_index);
ctx->base.is_jmp = DISAS_NORETURN;
gen_save_cpu_state(ctx);
gen_helper_raise_exception(cpu_env, t0);
tcg_temp_free_i32(t0);
}
#define IMPL_GEN_TR_EXCP(name, excp) \
static inline void name(DisasContext *ctx) \
{ \
gen_tr_exception(ctx, excp); \
}
IMPL_GEN_TR_EXCP(gen_tr_excp_illopc, EXCP_ILLEGAL_OPCODE)
IMPL_GEN_TR_EXCP(gen_tr_excp_illopn, EXCP_ILLEGAL_OPERAND)
IMPL_GEN_TR_EXCP(gen_tr_excp_window_bounds, EXCP_WINDOW_BOUNDS)
IMPL_GEN_TR_EXCP(gen_tr_excp_array_bounds, EXCP_ARRAY_BOUNDS)
static inline void gen_exception(int excp)
{
TCGv_i32 t0 = tcg_const_i32(excp);
// TODO: check if need to save state
gen_helper_raise_exception(cpu_env, t0);
tcg_temp_free_i32(t0);
}
#define IMPL_GEN_EXCP(name, excp) \
static inline void name(void) \
{ \
gen_exception(excp); \
}
IMPL_GEN_EXCP(gen_excp_illopc, EXCP_ILLEGAL_OPCODE)
IMPL_GEN_EXCP(gen_excp_window_bounds, EXCP_WINDOW_BOUNDS)
#define e2k_todo(ctx, fmt, ...) \
qemu_log(TARGET_FMT_lx ": " fmt " (%s:%d)\n", ctx->pc, \
## __VA_ARGS__, __FILE__, __LINE__)
#define e2k_todo_illop(ctx, fmt, ...) \
e2k_todo(ctx, fmt, ## __VA_ARGS__); \
gen_tr_excp_illopc(ctx)
static inline TCGv_i32 e2k_get_temp_i32(DisasContext *dc)
{
assert(dc->t32_len < ARRAY_SIZE(dc->t32));
return dc->t32[dc->t32_len++] = tcg_temp_local_new_i32();
}
static inline TCGv_i32 e2k_get_const_i32(DisasContext *dc, uint32_t value)
{
assert(dc->t32_len < ARRAY_SIZE(dc->t32));
return dc->t32[dc->t32_len++] = tcg_const_local_i32(value);
}
static inline TCGv_i64 e2k_get_temp_i64(DisasContext *dc)
{
assert(dc->t64_len < ARRAY_SIZE(dc->t64));
return dc->t64[dc->t64_len++] = tcg_temp_local_new_i64();
}
static inline TCGv_i64 e2k_get_const_i64(DisasContext *dc, uint64_t value)
{
assert(dc->t64_len < ARRAY_SIZE(dc->t64));
return dc->t64[dc->t64_len++] = tcg_const_local_i64(value);
}
static inline TCGv e2k_get_temp(DisasContext *dc)
{
assert(dc->ttl_len < ARRAY_SIZE(dc->ttl));
return dc->ttl[dc->ttl_len++] = tcg_temp_local_new();
}
static inline TCGv e2k_get_const(DisasContext *dc, target_ulong value)
{
assert(dc->ttl_len < ARRAY_SIZE(dc->ttl));
return dc->ttl[dc->ttl_len++] = tcg_const_local_tl(value);
}
static inline void e2k_gen_lcntex(TCGv_i32 ret)
{
tcg_gen_setcondi_i32(TCG_COND_EQ, ret, e2k_cs.lsr_lcnt, 0);
}
void e2k_gen_store_preg(int idx, TCGv_i32 val);
void e2k_gen_reg_tag_read_i64(TCGv_i32 ret, TCGv_i32 idx);
void e2k_gen_reg_tag_read_i32(TCGv_i32 ret, TCGv_i32 idx);
void e2k_gen_reg_tag_write_i64(TCGv_i32 value, TCGv_i32 idx);
void e2k_gen_reg_tag_write_i32(TCGv_i32 value, TCGv_i32 idx);
static inline void e2k_gen_reg_tag_writei_i64(int value, TCGv_i32 idx)
{
TCGv_i32 t0 = tcg_const_i32(value);
e2k_gen_reg_tag_write_i64(t0, idx);
tcg_temp_free_i32(t0);
}
static inline void e2k_gen_reg_tag_writei_i32(int value, TCGv_i32 idx)
{
TCGv_i32 t0 = tcg_const_i32(value);
e2k_gen_reg_tag_write_i32(t0, idx);
tcg_temp_free_i32(t0);
}
static inline void e2k_gen_reg_tag_extract_lo(TCGv_i32 ret, TCGv_i32 tags)
{
tcg_gen_andi_i32(ret, tags, GEN_MASK(0, E2K_TAG_SIZE));
}
static inline void e2k_gen_reg_tag_extract_hi(TCGv_i32 ret, TCGv_i32 tags)
{
tcg_gen_shri_i32(ret, tags, E2K_TAG_SIZE);
}
void e2k_gen_reg_tag_check_i64(TCGv_i32 ret, TCGv_i32 tag);
void e2k_gen_reg_tag_check_i32(TCGv_i32 ret, TCGv_i32 tag);
void e2k_gen_reg_index_from_wregi(TCGv_i32 ret, int idx);
void e2k_gen_reg_index_from_bregi(TCGv_i32 ret, int idx);
void e2k_gen_reg_index_from_gregi(TCGv_i32 ret, int idx);
static inline void e2k_gen_reg_index(DisasContext *ctx, TCGv_i32 ret, uint8_t arg)
{
if (IS_BASED(arg)) {
e2k_gen_reg_index_from_bregi(ret, GET_BASED(arg));
} else if (IS_REGULAR(arg)) {
e2k_gen_reg_index_from_wregi(ret, GET_REGULAR(arg));
} else if (IS_GLOBAL(arg)) {
e2k_gen_reg_index_from_gregi(ret, GET_GLOBAL(arg));
} else {
gen_tr_exception(ctx, EXCP_ILLEGAL_OPERAND);
}
}
void e2k_gen_reg_read_i64(TCGv_i64 ret, TCGv_i32 idx);
void e2k_gen_reg_read_i32(TCGv_i32 ret, TCGv_i32 idx);
void e2k_gen_reg_write_i64(TCGv_i64 value, TCGv_i32 idx);
void e2k_gen_reg_write_i32(TCGv_i32 value, TCGv_i32 idx);
void e2k_gen_xreg_read_i64(TCGv_i64 ret, TCGv_i32 idx);
void e2k_gen_xreg_read_i32(TCGv_i32 ret, TCGv_i32 idx);
void e2k_gen_xreg_read16u_i32(TCGv_i32 ret, TCGv_i32 idx);
void e2k_gen_xreg_write_i64(TCGv_i64 value, TCGv_i32 idx);
void e2k_gen_xreg_write_i32(TCGv_i32 value, TCGv_i32 idx);
void e2k_gen_xreg_write16u_i32(TCGv_i32 value, TCGv_i32 idx);
void e2k_gen_preg_i32(TCGv_i32 ret, int reg);
void e2k_gen_cond_i32(DisasContext *ctx, TCGv_i32 ret, uint8_t psrc);
static inline void e2k_gen_is_loop_end_i32(TCGv_i32 ret)
{
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_temp_new_i32();
tcg_gen_setcondi_i32(TCG_COND_EQ, t0, e2k_cs.lsr_ecnt, 0);
tcg_gen_setcondi_i32(TCG_COND_LTU, t1, e2k_cs.lsr_lcnt, 2);
tcg_gen_and_i32(t2, t0, t1);
tcg_gen_and_i32(ret, t2, e2k_cs.lsr_vlc);
tcg_temp_free_i32(t2);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
void e2k_decode_jmp(DisasContext *ctx);
void e2k_stubs_commit(DisasContext *ctx);
void alc_init(DisasContext *ctx);
void e2k_alc_decode(DisasContext *ctx);
void e2k_alc_execute(DisasContext *ctx);
void e2k_alc_commit(DisasContext *ctx);
void e2k_aau_execute(DisasContext *ctx);
void e2k_aau_commit(DisasContext *ctx);
void e2k_plu_execute(DisasContext *ctx);
void e2k_plu_commit(DisasContext *ctx);
#endif