target: e2k: Move TCG CPU State to translate.h.

This commit is contained in:
Denis Drakhnia 2020-11-11 19:06:46 +02:00 committed by Denis Drakhnia
parent baa5780663
commit 1d5f74624f
2 changed files with 337 additions and 370 deletions

View File

@ -4,102 +4,11 @@
#include "exec/translator.h"
#include "tcg/tcg-op.h"
#include "exec/log.h"
#include "translate.h"
#define TEMP_COUNT_32 16
#define TEMP_COUNT_64 16
#define TEMP_COUNT_TL 8
#define COND_NEVER 0
static TCGv_ptr cpu_win_ptr;
static TCGv_i64 cpu_wregs[WREGS_SIZE];
static TCGv_i64 cpu_gregs[32];
static TCGv cpu_pc;
static TCGv_i32 cpu_is_jmp;
static TCGv_i64 cpu_pregs;
static TCGv cpu_ctprs[3];
static TCGv_i32 cpu_wbs;
static TCGv_i32 cpu_wsz;
static TCGv_i32 cpu_nfx;
static TCGv_i32 cpu_dbl;
static TCGv_i32 cpu_rbs;
static TCGv_i32 cpu_rsz;
static TCGv_i32 cpu_rcur;
static TCGv_i32 cpu_psz;
enum ResultType {
RESULT_NONE,
RESULT_BASED_REG,
RESULT_REGULAR_REG,
RESULT_GLOBAL_REG,
RESULT_PREG,
};
typedef struct {
enum ResultType tag;
union {
struct {
unsigned int i;
TCGv_i64 v;
} reg;
} u;
} Result;
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;
typedef struct {
DisasContextBase base;
struct unpacked_instr instr;
target_ulong pc;
// Temporary values.
TCGv_i32 t32[TEMP_COUNT_32];
TCGv_i64 t64[TEMP_COUNT_64];
TCGv ttl[TEMP_COUNT_TL];
// Allocated temporary values count.
int t32_len;
int t64_len;
int ttl_len;
struct {
// raw condition code from SS[8:0]
unsigned int cond;
TCGv dest;
} jmp;
Result alc[6];
} DisasContext;
struct CPUE2KStateTCG e2k_cpu;
#define GET_BIT(v, index) (((v) >> index) & 1)
#define GET_FIELD(v, start, end) \
(((v) >> (start)) & ((1 << ((end) - (start) + 1)) - 1))
@ -121,169 +30,137 @@ typedef struct {
#define GET_LIT(i) ((i) & 0x03)
#define GET_GLOBAL(i) ((i) & 0x1f)
// TODO: return error on invalid instruction
static target_ulong unpack_instr(CPUE2KState *env, DisasContext *ctx, target_ulong pc,
struct unpacked_instr *instr)
/* returns zero if bundle is invalid */
static target_ulong unpack_bundle(CPUE2KState *env, DisasContext *ctx)
{
unsigned int i;
target_ulong gap, pos = pc, next_pc = pos + 8;
int hsyll_cntr = 0;
unsigned int hs;
unsigned int gap;
unsigned int pos = 0;
unsigned int mdl;
memset (instr, 0, sizeof (unpacked_instr));
unsigned int hsyll_cntr = 0;
unsigned int i;
uint32_t hs;
UnpackedBundle *bundle = &ctx->bundle;
target_ulong pc = ctx->pc;
hs = translator_ldl(env, &ctx->base, pos);
memset(bundle, 0, sizeof(UnpackedBundle));
bundle->hs = hs = translator_ldl(env, &ctx->base, pc + 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);
if (GET_BIT(hs, 12)) {
bundle->ss_present = true;
bundle->ss = translator_ldl(env, &ctx->base, pc + 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);
for (i = 0; i < 6; i++) {
if (GET_BIT(hs, 26 + i)) {
bundle->als_present[i] = true;
bundle->als[i] = translator_ldl(env, &ctx->base, pc + pos);
pos += 4;
}
}
/* Check for CS0. */
if (hs & (0x1 << 14))
{
instr->cs0_present = 1;
instr->cs0 = translator_ldl(env, &ctx->base, pos);
if (GET_BIT(hs, 14)) {
bundle->cs0_present = true;
bundle->cs0 = translator_ldl(env, &ctx->base, pc + 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 (GET_BIT(hs, 25)) {
bundle->ales_present[5] = ALES_ALLOCATED;
bundle->ales[5] = 0x01c0;
}
if (hs & (0x1 << 22))
{
instr->ales_present[2] = 1;
instr->ales[2] = 0x01c0;
if (GET_BIT(hs, 22)) {
bundle->ales_present[2] = ALES_ALLOCATED;
bundle->ales[2] = 0x01c0;
}
/* Calculate the size of f1 fragment in bytes. For a valid instruction it
/* Calculate the size of f1 fragment in bytes. For a valid bundle it
should be equal to either of `pos', `pos + 4' or `pos + 8'. What should I
do if it's not? */
mdl = pc + ((hs & 0xf) + 1) * 4;
/* TODO: exception */
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))
{
if ((GET_BIT(hs, 15) && mdl == pos + 8) ||
(!GET_BIT(hs, 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);
bundle->ales[5] = translator_lduw(env, &ctx->base, pc + pos);
bundle->ales[2] = translator_lduw(env, &ctx->base, pc + 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;
bundle->ales_present[5] |= ALES_PRESENT;
bundle->ales_present[2] |= ALES_PRESENT;
pos += 4;
}
/* Check for CS1. */
if (hs & (0x1 << 15))
{
instr->cs1_present = 1;
instr->cs1 = translator_ldl(env, &ctx->base, pos);
if (GET_BIT(hs, 15)) {
bundle->cs1_present = 1;
bundle->cs1 = translator_ldl(env, &ctx->base, pc + pos);
pos += 4;
}
/* A primitive control just for a moment. */
if (mdl != pos)
{
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;
return 0;
}
/* Check for ALES{0,1,3,4}. */
for (i = 0; i < 5; i++)
{
for (i = 0; i < 5; i++) {
if (i == 2)
continue;
if (hs & (0x1 << (20 + i)))
{
instr->ales_present[i] = 1;
if (GET_BIT(hs, 20 + i)) {
unsigned int offset = 2 * ((hsyll_cntr & ~0x1) + 1 - (hsyll_cntr & 0x1));
bundle->ales_present[i] = ALES_PRESENT;
/* 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)));
bundle->ales[i] = translator_lduw(env, &ctx->base, pc + pos + offset);
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;
if (bundle->ss_present && !GET_BIT(bundle->ss, 20)) {
for (i = 0; i < 4; i++) {
if (GET_BIT(bundle->ss, 12 + i)) {
bundle->aas_present[i >> 1] = true;
bundle->aas_present[i + 2] = true;
}
}
for (i = 0; i < 6; i++)
{
if (instr->aas_present[i])
{
for (i = 0; i < 6; i++) {
if (bundle->aas_present[i]) {
unsigned int offset = 2 * ((hsyll_cntr & ~0x1) + 1 - (hsyll_cntr & 0x1));
/* 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)));
bundle->aas[i] = translator_lduw(env, &ctx->base, pc + pos + offset);
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++;
}
/* align half-syllables */
hsyll_cntr += hsyll_cntr & 1;
/* 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
@ -294,22 +171,19 @@ static target_ulong unpack_instr(CPUE2KState *env, DisasContext *ctx, target_ulo
/* Set POS to point to the last syllable in the current wide instruction and
extract CDSj and PLSj syllables if any. */
pos = pc + ((((hs & 0x70) >> 4) + 1) << 3) - 4;
pos = ((GET_FIELD(hs, 4, 6) + 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);
for (i = 0; i < GET_FIELD(hs, 16, 17); i++) {
bundle->cds_present[i] = true;
bundle->cds[i] = translator_ldl(env, &ctx->base, pc + 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);
for (i = 0; i < GET_FIELD(hs, 18, 19); i++) {
bundle->pls_present[i] = true;
bundle->pls[i] = translator_ldl(env, &ctx->base, pc + pos);
pos -= 4;
}
@ -322,28 +196,18 @@ static target_ulong unpack_instr(CPUE2KState *env, DisasContext *ctx, target_ulo
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;
if (pos < gap && pos != gap - 4) {
return 0;
}
/* 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);
for (i = 0; i < 4 && pos >= gap; i++) {
bundle->lts_present[i] = true;
bundle->lts[i] = translator_ldl(env, &ctx->base, pc + 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;
return 8 + GET_FIELD(hs, 4, 6) * 8;
}
static inline TCGv_i32 get_temp_i32(DisasContext *dc)
@ -366,7 +230,7 @@ static inline TCGv get_temp(DisasContext *dc)
static inline void save_state(DisasContext *dc)
{
tcg_gen_movi_tl(cpu_pc, dc->pc);
tcg_gen_movi_tl(e2k_cpu.pc, dc->pc);
}
static void gen_exception(DisasContext *dc, int which)
@ -393,19 +257,19 @@ static inline void gen_wrap_i32(TCGv_i32 ret, TCGv_i32 x, TCGv_i32 y)
static inline void reset_is_jmp()
{
tcg_gen_movi_i32(cpu_is_jmp, 0);
tcg_gen_movi_i32(e2k_cpu.is_jmp, 0);
}
static inline void set_is_jmp()
{
tcg_gen_movi_i32(cpu_is_jmp, 1);
tcg_gen_movi_i32(e2k_cpu.is_jmp, 1);
}
static inline void gen_rcur_move()
{
TCGv_i32 tmp = tcg_temp_new_i32();
tcg_gen_addi_i32(tmp, cpu_rcur, 2);
gen_wrap_i32(cpu_rcur, tmp, cpu_rsz);
tcg_gen_addi_i32(tmp, e2k_cpu.rcur, 2);
gen_wrap_i32(e2k_cpu.rcur, tmp, e2k_cpu.rsz);
tcg_temp_free_i32(tmp);
}
@ -414,7 +278,7 @@ static inline TCGv_i64 get_preg(DisasContext *dc, int reg)
TCGv_i64 ret = get_temp(dc);
TCGv_i64 tmp = tcg_temp_new_i64();
assert(reg < 32);
tcg_gen_shri_i64(tmp, cpu_pregs, reg * 2);
tcg_gen_shri_i64(tmp, e2k_cpu.pregs, reg * 2);
// TODO: should return preg tag?
tcg_gen_andi_i64(ret, tmp, 0x01);
tcg_temp_free_i64(tmp);
@ -426,10 +290,10 @@ static inline void gen_store_preg(int reg, TCGv_i64 val)
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv_i64 t2 = tcg_temp_new_i64();
tcg_gen_andi_i64(t0, cpu_pregs, ~(3 << (reg * 2)));
tcg_gen_andi_i64(t0, e2k_cpu.pregs, ~(3 << (reg * 2)));
tcg_gen_andi_i64(t1, val, 0x03);
tcg_gen_shli_i64(t2, t1, reg * 2);
tcg_gen_or_i64(cpu_pregs, t0, t2);
tcg_gen_or_i64(e2k_cpu.pregs, t0, t2);
tcg_temp_free_i64(t2);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t0);
@ -444,7 +308,7 @@ static inline void gen_wreg_offset(TCGv_i32 ret, int reg)
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_const_i32(WREGS_SIZE);
tcg_gen_addi_i32(t0, cpu_wbs, reg); // t = win_start + reg_index
tcg_gen_addi_i32(t0, e2k_cpu.wbs, reg); // t = win_start + reg_index
gen_wrap_i32(t1, t0, t2); // t = t % WIN_REGS_COUNT
tcg_gen_muli_i32(ret, t1, REG_SIZE); // t = t * REG_SIZE_IN_BYTES
@ -459,7 +323,7 @@ static inline void gen_wreg_ptr(TCGv_ptr ret, int reg)
TCGv_ptr t1 = tcg_temp_new_ptr();
gen_wreg_offset(t0, reg);
tcg_gen_ext_i32_ptr(t1, t0);
tcg_gen_add_ptr(ret, cpu_win_ptr, t1);
tcg_gen_add_ptr(ret, e2k_cpu.win_ptr, t1);
tcg_temp_free_ptr(t1);
tcg_temp_free_i32(t0);
}
@ -495,12 +359,12 @@ static inline void gen_breg_offset(TCGv_i32 ret, int reg)
TCGv_i32 t6 = tcg_temp_new_i32();
// t2 = (index + rsz + rcur) % rsz
tcg_gen_sub_i32(t0, cpu_rsz, cpu_rcur);
tcg_gen_sub_i32(t0, e2k_cpu.rsz, e2k_cpu.rcur);
tcg_gen_addi_i32(t1, t0, reg);
gen_wrap_i32(t2, t1, cpu_rsz);
gen_wrap_i32(t2, t1, e2k_cpu.rsz);
// (t2 + wbs + rbs) % WIN_REGS_COUNT
tcg_gen_add_i32(t3, cpu_wbs, cpu_rbs);
tcg_gen_add_i32(t3, e2k_cpu.wbs, e2k_cpu.rbs);
tcg_gen_add_i32(t4, t2, t3);
gen_wrap_i32(t6, t4, t5);
@ -522,7 +386,7 @@ static inline void gen_breg_ptr(TCGv_ptr ret, int reg)
TCGv_ptr t1 = tcg_temp_new_ptr();
gen_breg_offset(t0, reg);
tcg_gen_ext_i32_ptr(t1, t0);
tcg_gen_add_ptr(ret, cpu_win_ptr, t1);
tcg_gen_add_ptr(ret, e2k_cpu.win_ptr, t1);
tcg_temp_free_ptr(t1);
tcg_temp_free_i32(t0);
}
@ -549,13 +413,13 @@ static inline TCGv_i64 gen_load_greg(DisasContext *dc, int reg)
{
// TODO: rotated gregs
assert(reg < 32);
return cpu_gregs[reg];
return e2k_cpu.gregs[reg];
}
static inline void gen_store_greg(DisasContext *dc, int reg, TCGv_i64 val)
{
// TODO: rotated gregs
tcg_gen_mov_i64(cpu_gregs[reg], val);
tcg_gen_mov_i64(e2k_cpu.gregs[reg], val);
}
static TCGv_i64 get_src1(DisasContext *dc, unsigned int als)
@ -595,9 +459,9 @@ static TCGv_i64 get_src2(DisasContext *dc, unsigned int als)
} else if (IS_LIT(src2)) {
TCGv t = get_temp_i64(dc);
unsigned int i = GET_LIT(src2);
uint64_t lit = dc->instr.lts[i];
uint64_t lit = dc->bundle.lts[i];
// TODO: exception
assert(dc->instr.lts_present[i]);
assert(dc->bundle.lts_present[i]);
if (IS_LIT16_LO(src2) && i < 2) {
lit &= 0xffff;
} else if (IS_LIT16_HI(src2) && i < 2) {
@ -606,8 +470,8 @@ static TCGv_i64 get_src2(DisasContext *dc, unsigned int als)
// nop
} else if (IS_LIT64(src2) && i < 3) {
// TODO: exception
assert(dc->instr.lts_present[i + 1]);
lit |= ((uint64_t) dc->instr.lts[i + 1]) << 32;
assert(dc->bundle.lts_present[i + 1]);
lit |= ((uint64_t) dc->bundle.lts[i + 1]) << 32;
} else {
// TODO: exception
abort();
@ -661,8 +525,8 @@ static void gen_cs0(DisasContext *dc, CPUE2KState *env)
{DISP, LDISP, SDISP, GETTSD},
{DISP, NOTHING, SDISP, RETURN}
};
const struct unpacked_instr *instr = &dc->instr;
unsigned int cs0 = instr->cs0;
const UnpackedBundle *bundle = &dc->bundle;
uint32_t cs0 = bundle->cs0;
unsigned int ctpr = (cs0 & 0xc0000000) >> 30;
unsigned int ctp_opc = (cs0 & 0x30000000) >> 28;
@ -682,11 +546,11 @@ static void gen_cs0(DisasContext *dc, CPUE2KState *env)
if (type == IBRANCH || type == DONE || type == HRET || type == GLAUNCH) {
/* IBRANCH, DONE, HRET and GLAUNCH are special because they require SS
to be properly encoded. */
if (! instr->ss_present
if (! bundle->ss_present
/* SS.ctop should be equal to zero for IBRANCH, DONE, HRET and
GLAUNCH (see C.17.1.1, note that they don't mention the latter two
instructions there which is probably an omission ). */
|| (instr->ss & 0x00000c00))
|| (bundle->ss & 0x00000c00))
{
// TODO: invalid
abort();
@ -694,14 +558,14 @@ static void gen_cs0(DisasContext *dc, CPUE2KState *env)
/* Don't output either of the aforementioned instructions under "never"
condition. Don't disassemble CS0 being a part of HCALL. Unlike ldis
HCALL is currently disassembled on behalf of CS1. */
else if ((instr->ss & 0x1ff)
&& !(instr->cs1_present
else if ((bundle->ss & 0x1ff)
&& !(bundle->cs1_present
/* CS1.opc == CALL */
&& (instr->cs1 & 0xf0000000) >> 28 == 5
&& (bundle->cs1 & 0xf0000000) >> 28 == 5
/* CS1.param.ctopc == HCALL */
&& (instr->cs1 & 0x380) >> 7 == 2))
&& (bundle->cs1 & 0x380) >> 7 == 2))
{
unsigned int cond = instr->ss & 0x1ff;
unsigned int cond = bundle->ss & 0x1ff;
if (type == IBRANCH) {
/* C0F2 has `disp' field. In `C0F1' it's called `param'. Is this
the only difference between these two formats? Funnily enough,
@ -764,9 +628,9 @@ static void gen_cs0(DisasContext *dc, CPUE2KState *env)
}
if (type == PREF) {
unsigned int pdisp = (instr->cs0 & 0x0ffffff0) >> 4;
unsigned int ipd = (instr->cs0 & 0x00000008) >> 3;
unsigned int prefr = instr->cs0 & 0x00000007;
unsigned int pdisp = (bundle->cs0 & 0x0ffffff0) >> 4;
unsigned int ipd = (bundle->cs0 & 0x00000008) >> 3;
unsigned int prefr = bundle->cs0 & 0x00000007;
}
}
}
@ -786,8 +650,8 @@ static void gen_cs1(DisasContext *dc, CPUE2KState *env)
BG
};
const struct unpacked_instr *instr = &dc->instr;
unsigned int cs1 = instr->cs1;
const UnpackedBundle *bundle = &dc->bundle;
unsigned int cs1 = bundle->cs1;
unsigned int opc = (cs1 & 0xf0000000) >> 28;
if (opc == SETR0 || opc == SETR1 || opc == SETBR) {
@ -800,13 +664,13 @@ static void gen_cs1(DisasContext *dc, CPUE2KState *env)
a binary with these commands by hand right now. */
if (opc == SETR1) {
if (! instr->lts_present[0]) {
if (! bundle->lts_present[0]) {
// my_printf ("<bogus vfrpsz>");
} else {
/* Find out if VFRPSZ is always encoded together with SETWD. This
seems to be the case even if no SETWD has been explicitly
specified. */
unsigned int rpsz = (instr->lts[0] & 0x0001f000) >> 12;
unsigned int rpsz = (bundle->lts[0] & 0x0001f000) >> 12;
// my_printf ("vfrpsz rpsz = 0x%x", rpsz);
}
}
@ -814,22 +678,22 @@ static void gen_cs1(DisasContext *dc, CPUE2KState *env)
// FIXME: Should windowing registers be precomputed or not?
if (opc == SETR0 || opc == SETR1) {
if (! instr->lts_present[0]) {
if (! bundle->lts_present[0]) {
// TODO: <bogus setwd>
abort();
} else {
unsigned int lts0 = instr->lts[0];
unsigned int lts0 = bundle->lts[0];
unsigned int wsz = (lts0 & 0x00000fe0) >> 5;
unsigned int nfx = (lts0 & 0x00000010) >> 4;
tcg_gen_movi_i32(cpu_wsz, wsz * 2);
tcg_gen_movi_i32(cpu_nfx, nfx);
tcg_gen_movi_i32(e2k_cpu.wsz, wsz * 2);
tcg_gen_movi_i32(e2k_cpu.nfx, nfx);
if (env->version >= 3) {
// DBL parameter of SETWD was added only starting from
// elbrus-v3.
unsigned int dbl = (lts0 & 0x00000008) >> 3;
tcg_gen_movi_i32(cpu_dbl, dbl);
tcg_gen_movi_i32(e2k_cpu.dbl, dbl);
}
}
}
@ -839,15 +703,15 @@ static void gen_cs1(DisasContext *dc, CPUE2KState *env)
unsigned int rsz = (cs1 & 0x00000fc0) >> 6;
unsigned int rbs = cs1 & 0x0000003f;
tcg_gen_movi_i32(cpu_rcur, rcur * 2);
tcg_gen_movi_i32(cpu_rsz, rsz * 2 + 2);
tcg_gen_movi_i32(cpu_rbs, rbs * 2);
tcg_gen_movi_i32(e2k_cpu.rcur, rcur * 2);
tcg_gen_movi_i32(e2k_cpu.rsz, rsz * 2 + 2);
tcg_gen_movi_i32(e2k_cpu.rbs, rbs * 2);
}
if (setbp) {
unsigned int psz = (cs1 & 0x007c0000) >> 18;
tcg_gen_movi_i32(cpu_psz, psz);
tcg_gen_movi_i32(e2k_cpu.psz, psz);
}
} else if (opc == SETEI) {
/* Verify that CS1.param.sft = CS1.param[27] is equal to zero as required
@ -891,7 +755,7 @@ static void gen_cs1(DisasContext *dc, CPUE2KState *env)
// my_printf ("ma_c = %d, fl_c = %d, ld_c = %d, st_c = %d, all_e = %d, "
// "all_c = %d", ma_c, fl_c, ld_c, st_c, all_e, all_c);
} else if (opc == CALL) {
unsigned int ctop = (instr->ss & 0x00000c00) >> 10;
unsigned int ctop = (bundle->ss & 0x00000c00) >> 10;
/* In C.17.4 it's said that other bits in CS1.param except for the
seven lowermost ones are ignored. */
unsigned int wbs = cs1 & 0x7f;
@ -902,8 +766,8 @@ static void gen_cs1(DisasContext *dc, CPUE2KState *env)
} else {
unsigned int cs1_ctopc = (cs1 & 0x380) >> 7;
/* CS1.param.ctpopc == HCALL. CS0 is required to encode HCALL. */
if (cs1_ctopc == 2 && instr->cs0_present) {
unsigned int cs0 = instr->cs0;
if (cs1_ctopc == 2 && bundle->cs0_present) {
unsigned int cs0 = bundle->cs0;
unsigned int cs0_opc = (cs0 & 0xf0000000) >> 28;
/* CS0.opc == HCALL, which means
CS0.opc.ctpr == CS0.opc.ctp_opc == 0 */
@ -997,8 +861,8 @@ static void gen_op21_i32(TCGv_i64 ret, TCGv_i64 s1, TCGv_i64 s2, TCGv_i64 dst,
static Result gen_alc(DisasContext *dc, CPUE2KState *env, int chan)
{
const struct unpacked_instr *instr = &dc->instr;
unsigned int als = instr->als[chan];
const UnpackedBundle *bundle = &dc->bundle;
unsigned int als = bundle->als[chan];
int opc = (als >> 24) & 0x7f;
int sm = als >> 31;
unsigned int dst = als & 0xff;
@ -1177,7 +1041,7 @@ static void gen_jmp(DisasContext *dc, target_ulong next_pc)
if (cond_type == 1) {
dc->base.is_jmp = DISAS_NORETURN;
tcg_gen_mov_tl(cpu_pc, dc->jmp.dest);
tcg_gen_mov_tl(e2k_cpu.pc, dc->jmp.dest);
tcg_gen_exit_tb(NULL, 0);
return;
}
@ -1188,7 +1052,7 @@ static void gen_jmp(DisasContext *dc, target_ulong next_pc)
TCGv_i64 cond = tcg_const_i64(1);
TCGv next = tcg_const_tl(next_pc);
dc->base.is_jmp = DISAS_NORETURN;
tcg_gen_movcond_i64(TCG_COND_EQ, cpu_pc,
tcg_gen_movcond_i64(TCG_COND_EQ, e2k_cpu.pc,
preg, cond,
dc->jmp.dest, next
);
@ -1285,22 +1149,27 @@ static target_ulong disas_e2k_insn(DisasContext *dc, CPUState *cs)
{
E2KCPU *cpu = E2K_CPU(cs);
CPUE2KState *env = &cpu->env;
struct unpacked_instr *instr = &dc->instr;
UnpackedBundle *bundle = &dc->bundle;
unsigned int i;
target_ulong pc_next = unpack_instr(env, dc, dc->pc, instr);
unsigned int bundle_len = unpack_bundle(env, dc);
if (bundle_len == 0) {
gen_exception(dc, 1);
return dc->pc + 8;
}
target_ulong pc_next = dc->pc + bundle_len;
reset_is_jmp();
if (dc->instr.cs0_present) {
if (bundle->cs0_present) {
gen_cs0(dc, env);
}
if (dc->instr.cs1_present) {
if (bundle->cs1_present) {
gen_cs1(dc, env);
}
for (i = 0; i < 6; i++) {
if (!instr->als_present[i]) {
if (!bundle->als_present[i]) {
continue;
}
dc->alc[i] = gen_alc(dc, env, i);
@ -1309,7 +1178,7 @@ static target_ulong disas_e2k_insn(DisasContext *dc, CPUState *cs)
// Commit results after all instructions in the bundle was executed
for (i = 0; i < 6; i++) {
Result *res = &dc->alc[i];
if (!instr->als_present[i]) {
if (!bundle->als_present[i]) {
continue;
}
switch(res->tag) {
@ -1331,7 +1200,7 @@ static target_ulong disas_e2k_insn(DisasContext *dc, CPUState *cs)
}
// Change windowing registers after commit is done.
unsigned int ss = dc->instr.ss;
unsigned int ss = dc->bundle.ss;
unsigned int vfdi = (ss & 0x04000000) >> 26;
unsigned int abg = (ss & 0x01800000) >> 23;
unsigned int abn = (ss & 0x00600000) >> 21;
@ -1345,9 +1214,11 @@ static target_ulong disas_e2k_insn(DisasContext *dc, CPUState *cs)
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 zero = tcg_const_i32(0);
tcg_gen_addi_i32(t0, cpu_rcur, 2);
gen_wrap_i32(t1, t0, cpu_rsz);
tcg_gen_movcond_i32(TCG_COND_EQ, cpu_rcur, cpu_is_jmp, zero, t1, cpu_rcur);
tcg_gen_addi_i32(t0, e2k_cpu.rcur, 2);
gen_wrap_i32(t1, t0, e2k_cpu.rsz);
tcg_gen_movcond_i32(TCG_COND_EQ, e2k_cpu.rcur,
e2k_cpu.is_jmp, zero,
t1, e2k_cpu.rcur);
tcg_temp_free_i32(zero);
tcg_temp_free_i32(t1);
@ -1357,7 +1228,7 @@ static target_ulong disas_e2k_insn(DisasContext *dc, CPUState *cs)
// Control transfer
if (env->interrupt_index != 0) {
tcg_gen_movi_tl(cpu_pc, dc->pc);
tcg_gen_movi_tl(e2k_cpu.pc, dc->pc);
tcg_gen_exit_tb(NULL, 0);
dc->base.is_jmp = DISAS_NORETURN;
} else if (dc->jmp.cond != 0) {
@ -1406,8 +1277,7 @@ static void e2k_tr_translate_insn(DisasContextBase *db, CPUState *cs)
{
DisasContext *dc = container_of(db, DisasContext, base);
dc->pc = dc->base.pc_next;
target_ulong pc_next = disas_e2k_insn(dc, cs);
dc->base.pc_next = pc_next;
dc->base.pc_next = disas_e2k_insn(dc, cs);
}
static void e2k_tr_tb_start(DisasContextBase *db, CPUState *cs)
@ -1464,22 +1334,22 @@ void e2k_tcg_initialize(void) {
char buf[8] = { 0 };
static const struct { TCGv_i32 *ptr; int off; const char *name; } r32[] = {
{ &cpu_wbs, offsetof(CPUE2KState, wbs), "wbs" },
{ &cpu_wsz, offsetof(CPUE2KState, wsz), "wsz" },
{ &cpu_nfx, offsetof(CPUE2KState, nfx), "nfx" },
{ &cpu_dbl, offsetof(CPUE2KState, dbl), "dbl" },
{ &cpu_rbs, offsetof(CPUE2KState, rbs), "rbs" },
{ &cpu_rsz, offsetof(CPUE2KState, rsz), "rsz" },
{ &cpu_rcur, offsetof(CPUE2KState, rcur), "rcur" },
{ &cpu_psz, offsetof(CPUE2KState, psz), "psz" },
{ &e2k_cpu.wbs, offsetof(CPUE2KState, wbs), "wbs" },
{ &e2k_cpu.wsz, offsetof(CPUE2KState, wsz), "wsz" },
{ &e2k_cpu.nfx, offsetof(CPUE2KState, nfx), "nfx" },
{ &e2k_cpu.dbl, offsetof(CPUE2KState, dbl), "dbl" },
{ &e2k_cpu.rbs, offsetof(CPUE2KState, rbs), "rbs" },
{ &e2k_cpu.rsz, offsetof(CPUE2KState, rsz), "rsz" },
{ &e2k_cpu.rcur, offsetof(CPUE2KState, rcur), "rcur" },
{ &e2k_cpu.psz, offsetof(CPUE2KState, psz), "psz" },
};
static const struct { TCGv_i64 *ptr; int off; const char *name; } r64[] = {
{ &cpu_pregs, offsetof(CPUE2KState, pregs), "pregs" },
{ &e2k_cpu.pregs, offsetof(CPUE2KState, pregs), "pregs" },
};
static const struct { TCGv *ptr; int off; const char *name; } rtl[] = {
{ &cpu_pc, offsetof(CPUE2KState, ip), "pc" },
{ &e2k_cpu.pc, offsetof(CPUE2KState, ip), "pc" },
};
unsigned int i;
@ -1496,26 +1366,26 @@ void e2k_tcg_initialize(void) {
*rtl[i].ptr = tcg_global_mem_new(cpu_env, rtl[i].off, rtl[i].name);
}
cpu_win_ptr = tcg_global_mem_new_ptr(cpu_env, offsetof(CPUE2KState, win_ptr), "win_ptr");
cpu_is_jmp = tcg_global_mem_new_i32(cpu_env, offsetof(CPUE2KState, is_jmp), "is_jmp");
e2k_cpu.win_ptr = tcg_global_mem_new_ptr(cpu_env, offsetof(CPUE2KState, win_ptr), "win_ptr");
e2k_cpu.is_jmp = tcg_global_mem_new_i32(cpu_env, offsetof(CPUE2KState, is_jmp), "is_jmp");
for (i = 0; i < WREGS_SIZE; i++) {
snprintf(buf, ARRAY_SIZE(buf), "%%r%d", i);
cpu_wregs[i] = tcg_global_mem_new(cpu_win_ptr,
e2k_cpu.wregs[i] = tcg_global_mem_new(e2k_cpu.win_ptr,
i * REG_SIZE,
buf);
}
for (i = 0; i < 32; i++) {
snprintf(buf, ARRAY_SIZE(buf), "%%g%d", i);
cpu_gregs[i] = tcg_global_mem_new(cpu_env,
e2k_cpu.gregs[i] = tcg_global_mem_new(cpu_env,
offsetof(CPUE2KState, gregs[i]),
buf);
}
for (i = 0; i < 3; i++) {
snprintf(buf, ARRAY_SIZE(buf), "%%ctpr%d", i + 1);
cpu_ctprs[i] = tcg_global_mem_new(cpu_env,
e2k_cpu.ctprs[i] = tcg_global_mem_new(cpu_env,
offsetof(CPUE2KState, ctprs[i]),
buf
);

97
target/e2k/translate.h Normal file
View File

@ -0,0 +1,97 @@
#ifndef E2K_TRANSLATE_H
#define E2K_TRANSLATE_H
#include "exec/translator.h"
#define COND_NEVER 0
typedef enum AlesFlag {
ALES_NONE = 0x00,
ALES_PRESENT = 0x01,
ALES_ALLOCATED = 0x02,
} AlesFlag;
typedef struct CPUE2KStateTCG {
TCGv pc;
TCGv ctprs[3];
TCGv_i32 is_jmp;
TCGv_i32 wbs;
TCGv_i32 wsz;
TCGv_i32 nfx;
TCGv_i32 dbl;
TCGv_i32 rbs;
TCGv_i32 rsz;
TCGv_i32 rcur;
TCGv_i32 psz;
TCGv_ptr win_ptr;
TCGv_i64 wregs[WREGS_SIZE];
TCGv_i64 gregs[32];
TCGv_i64 pregs;
} CPUE2KStateTCG;
extern struct CPUE2KStateTCG e2k_cpu;
typedef struct UnpackedBundle {
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;
enum ResultType {
RESULT_NONE,
RESULT_BASED_REG,
RESULT_REGULAR_REG,
RESULT_GLOBAL_REG,
RESULT_PREG,
};
typedef struct {
enum ResultType tag;
union {
struct {
unsigned int i;
TCGv_i64 v;
} reg;
} u;
} Result;
typedef struct DisasContext {
DisasContextBase base;
UnpackedBundle bundle;
target_ulong pc;
// Temporary values.
TCGv_i32 t32[16];
TCGv_i64 t64[16];
TCGv ttl[8];
// Allocated temporary values count.
int t32_len;
int t64_len;
int ttl_len;
Result alc[6];
struct {
// raw condition code from SS[8:0]
unsigned int cond;
TCGv dest;
} jmp;
} DisasContext;
#endif