2020-11-08 19:27:47 +01:00
|
|
|
#include "qemu/osdep.h"
|
|
|
|
#include "qemu.h"
|
2020-11-10 23:00:32 +01:00
|
|
|
#include "exec/log.h"
|
2020-11-11 20:03:51 +01:00
|
|
|
#include "disas/disas.h"
|
2020-11-11 18:06:46 +01:00
|
|
|
#include "translate.h"
|
2020-11-08 19:27:47 +01:00
|
|
|
|
2020-11-11 20:03:51 +01:00
|
|
|
struct CPUE2KStateTCG e2k_cs;
|
2020-11-10 13:06:44 +01:00
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
/* returns zero if bundle is invalid */
|
2020-11-17 19:58:22 +01:00
|
|
|
static size_t unpack_bundle(CPUE2KState *env, DisasContext *ctx)
|
2020-11-08 19:27:47 +01:00
|
|
|
{
|
2020-11-11 18:06:46 +01:00
|
|
|
unsigned int gap;
|
|
|
|
unsigned int pos = 0;
|
|
|
|
unsigned int mdl;
|
|
|
|
unsigned int hsyll_cntr = 0;
|
|
|
|
unsigned int i;
|
|
|
|
uint32_t hs;
|
|
|
|
UnpackedBundle *bundle = &ctx->bundle;
|
|
|
|
target_ulong pc = ctx->pc;
|
2020-11-08 19:27:47 +01:00
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
memset(bundle, 0, sizeof(UnpackedBundle));
|
2020-11-08 19:27:47 +01:00
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
bundle->hs = hs = translator_ldl(env, &ctx->base, pc + pos);
|
2020-11-08 19:27:47 +01:00
|
|
|
pos += 4;
|
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
/* Check for SS. */
|
|
|
|
if (GET_BIT(hs, 12)) {
|
|
|
|
bundle->ss_present = true;
|
|
|
|
bundle->ss = translator_ldl(env, &ctx->base, pc + pos);
|
|
|
|
pos += 4;
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
/* Check for available ALS syllables. */
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2020-11-08 19:27:47 +01:00
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
/* Check for CS0. */
|
|
|
|
if (GET_BIT(hs, 14)) {
|
|
|
|
bundle->cs0_present = true;
|
|
|
|
bundle->cs0 = translator_ldl(env, &ctx->base, pc + pos);
|
|
|
|
pos += 4;
|
|
|
|
}
|
2020-11-08 19:27:47 +01:00
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
if (GET_BIT(hs, 25)) {
|
|
|
|
bundle->ales_present[5] = ALES_ALLOCATED;
|
|
|
|
bundle->ales[5] = 0x01c0;
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
if (GET_BIT(hs, 22)) {
|
|
|
|
bundle->ales_present[2] = ALES_ALLOCATED;
|
|
|
|
bundle->ales[2] = 0x01c0;
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
/* 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? */
|
|
|
|
/* 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 ((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. */
|
|
|
|
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. */
|
|
|
|
bundle->ales_present[5] |= ALES_PRESENT;
|
|
|
|
bundle->ales_present[2] |= ALES_PRESENT;
|
|
|
|
|
|
|
|
pos += 4;
|
|
|
|
}
|
2020-11-08 19:27:47 +01:00
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
/* Check for CS1. */
|
|
|
|
if (GET_BIT(hs, 15)) {
|
|
|
|
bundle->cs1_present = 1;
|
|
|
|
bundle->cs1 = translator_ldl(env, &ctx->base, pc + pos);
|
|
|
|
pos += 4;
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
/* 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 0;
|
|
|
|
}
|
2020-11-08 19:27:47 +01:00
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
/* Check for ALES{0,1,3,4}. */
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
|
|
if (i == 2)
|
|
|
|
continue;
|
2020-11-08 19:27:47 +01:00
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
if (GET_BIT(hs, 20 + i)) {
|
|
|
|
unsigned int offset = 2 * ((hsyll_cntr & ~0x1) + 1 - (hsyll_cntr & 0x1));
|
|
|
|
bundle->ales_present[i] = ALES_PRESENT;
|
2020-11-08 19:27:47 +01:00
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
/* Recall the idiotic order of half-syllables in the packed wide
|
|
|
|
instruction. */
|
|
|
|
bundle->ales[i] = translator_lduw(env, &ctx->base, pc + pos + offset);
|
|
|
|
hsyll_cntr++;
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
/* Check for AASj half-syllables. To encode them SS syllable of SF1 type
|
|
|
|
should be present. */
|
|
|
|
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;
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
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. */
|
|
|
|
bundle->aas[i] = translator_lduw(env, &ctx->base, pc + pos + offset);
|
|
|
|
hsyll_cntr++;
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
/* 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
|
|
|
|
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. */
|
2020-11-23 21:26:47 +01:00
|
|
|
pos = ((GET_FIELD(hs, 4, 3) + 1) << 3) - 4;
|
2020-11-11 18:06:46 +01:00
|
|
|
|
|
|
|
/* Check for CDSj syllables. */
|
2020-11-23 21:26:47 +01:00
|
|
|
for (i = 0; i < GET_FIELD(hs, 16, 2); i++) {
|
2020-11-11 18:06:46 +01:00
|
|
|
bundle->cds_present[i] = true;
|
|
|
|
bundle->cds[i] = translator_ldl(env, &ctx->base, pc + pos);
|
|
|
|
pos -= 4;
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
/* Check for PLSj syllables. */
|
2020-11-23 21:26:47 +01:00
|
|
|
for (i = 0; i < GET_FIELD(hs, 18, 2); i++) {
|
2020-11-11 18:06:46 +01:00
|
|
|
bundle->pls_present[i] = true;
|
|
|
|
bundle->pls[i] = translator_ldl(env, &ctx->base, pc + pos);
|
|
|
|
pos -= 4;
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
/* 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 0;
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
/* Extract available LTSj syllables. */
|
|
|
|
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;
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
|
2020-11-23 21:26:47 +01:00
|
|
|
return 8 + GET_FIELD(hs, 4, 3) * 8;
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
|
2020-11-17 19:58:22 +01:00
|
|
|
static inline void gen_save_pc(target_ulong pc)
|
2020-11-10 13:06:44 +01:00
|
|
|
{
|
2020-11-17 19:58:22 +01:00
|
|
|
tcg_gen_movi_tl(e2k_cs.pc, pc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void gen_save_cpu_state(DisasContext *ctx)
|
|
|
|
{
|
|
|
|
gen_save_pc(ctx->pc);
|
2020-11-10 13:06:44 +01:00
|
|
|
}
|
|
|
|
|
2020-11-16 17:54:28 +01:00
|
|
|
static void gen_goto_tb(DisasContext *ctx, int tb_num, target_ulong pc)
|
|
|
|
{
|
|
|
|
if (translator_use_goto_tb(&ctx->base, pc)) {
|
|
|
|
/* jump to same page: we can use a direct jump */
|
|
|
|
tcg_gen_goto_tb(tb_num);
|
|
|
|
tcg_gen_movi_tl(e2k_cs.pc, pc);
|
2020-11-28 08:44:53 +01:00
|
|
|
tcg_gen_exit_tb(ctx->base.tb, tb_num);
|
2020-11-16 17:54:28 +01:00
|
|
|
} else {
|
|
|
|
/* jump to another page: currently not optimized */
|
|
|
|
tcg_gen_movi_tl(e2k_cs.pc, pc);
|
|
|
|
tcg_gen_exit_tb(NULL, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-28 08:44:53 +01:00
|
|
|
void e2k_tr_gen_exception(DisasContext *ctx, int which)
|
2020-11-10 13:06:44 +01:00
|
|
|
{
|
2020-11-11 20:03:51 +01:00
|
|
|
TCGv_i32 t = tcg_const_i32(which);
|
2020-11-10 13:06:44 +01:00
|
|
|
|
2020-11-17 19:58:22 +01:00
|
|
|
gen_save_cpu_state(ctx);
|
2020-11-10 13:06:44 +01:00
|
|
|
gen_helper_raise_exception(cpu_env, t);
|
2020-11-28 08:44:53 +01:00
|
|
|
ctx->base.is_jmp = DISAS_NORETURN;
|
2020-11-16 17:54:28 +01:00
|
|
|
|
|
|
|
tcg_temp_free_i32(t);
|
2020-11-10 13:06:44 +01:00
|
|
|
}
|
|
|
|
|
2020-11-19 22:20:03 +01:00
|
|
|
static inline void gen_ctpr_tag(TCGv_i64 ret, TCGv_i64 ctpr)
|
|
|
|
{
|
|
|
|
tcg_gen_extract_i64(ret, ctpr, CTPR_TAG_OFF, CTPR_TAG_LEN);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void gen_goto_ctpr_disp(TCGv_i64 ctpr)
|
|
|
|
{
|
|
|
|
TCGv_i64 t0 = tcg_temp_new_i64();
|
|
|
|
TCGv t1 = tcg_temp_new();
|
|
|
|
|
|
|
|
tcg_gen_extract_i64(t0, ctpr, CTPR_BASE_OFF, CTPR_BASE_LEN);
|
|
|
|
tcg_gen_trunc_i64_tl(t1, t0);
|
|
|
|
tcg_gen_mov_tl(e2k_cs.pc, t1);
|
|
|
|
tcg_gen_lookup_and_goto_ptr();
|
|
|
|
|
|
|
|
tcg_temp_free(t1);
|
|
|
|
tcg_temp_free_i64(t0);
|
|
|
|
}
|
|
|
|
|
2020-11-24 21:41:27 +01:00
|
|
|
static inline void do_reset(DisasContext *ctx)
|
|
|
|
{
|
|
|
|
memset(ctx->mas, 0, sizeof(ctx->mas));
|
|
|
|
}
|
|
|
|
|
2020-11-28 08:44:53 +01:00
|
|
|
static inline target_ulong do_decode(DisasContext *ctx, CPUState *cs)
|
2020-11-08 19:27:47 +01:00
|
|
|
{
|
|
|
|
E2KCPU *cpu = E2K_CPU(cs);
|
|
|
|
CPUE2KState *env = &cpu->env;
|
2020-11-28 08:44:53 +01:00
|
|
|
unsigned int len;
|
2020-11-17 19:58:22 +01:00
|
|
|
|
|
|
|
ctx->pc = ctx->base.pc_next;
|
2020-11-28 08:44:53 +01:00
|
|
|
len = unpack_bundle(env, ctx);
|
|
|
|
|
|
|
|
if (len == 0) {
|
|
|
|
len = 8;
|
|
|
|
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
|
2020-11-11 18:06:46 +01:00
|
|
|
}
|
2020-11-28 08:44:53 +01:00
|
|
|
|
|
|
|
return ctx->pc + len;
|
2020-11-17 19:58:22 +01:00
|
|
|
}
|
2020-11-08 19:27:47 +01:00
|
|
|
|
2020-11-17 19:58:22 +01:00
|
|
|
/*
|
|
|
|
* Executes instructions from a bundle and store the results to
|
|
|
|
* temporary buffer.
|
|
|
|
*/
|
|
|
|
static inline void do_execute(DisasContext *ctx)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
2020-11-10 13:06:44 +01:00
|
|
|
|
2020-11-24 21:41:27 +01:00
|
|
|
e2k_plu_execute(ctx);
|
|
|
|
e2k_control_gen(ctx);
|
|
|
|
|
2020-11-17 19:58:22 +01:00
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
if (ctx->bundle.als_present[i]) {
|
|
|
|
ctx->alc[i].tag = RESULT_NONE;
|
|
|
|
e2k_execute_alc(ctx, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-11-11 10:28:06 +01:00
|
|
|
|
2020-11-17 19:58:22 +01:00
|
|
|
/*
|
|
|
|
* Writes results of instructions from a bundle to the state
|
|
|
|
*
|
|
|
|
* Note
|
|
|
|
* ====
|
|
|
|
*
|
|
|
|
* Must not generate any exception.
|
|
|
|
* */
|
|
|
|
static inline void do_commit(DisasContext *ctx)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 6; i++) {
|
2020-11-24 10:12:01 +01:00
|
|
|
TCGLabel *l0 = gen_new_label();
|
2020-11-17 19:58:22 +01:00
|
|
|
Result *res = &ctx->alc[i];
|
2020-11-24 10:12:01 +01:00
|
|
|
|
2020-11-17 19:58:22 +01:00
|
|
|
if (!ctx->bundle.als_present[i]) {
|
|
|
|
continue;
|
|
|
|
}
|
2020-11-24 10:12:01 +01:00
|
|
|
|
|
|
|
if (res->has_cond) {
|
|
|
|
tcg_gen_brcondi_i64(TCG_COND_EQ, res->cond, 0, l0);
|
|
|
|
}
|
|
|
|
|
2020-11-17 19:58:22 +01:00
|
|
|
switch(res->tag) {
|
|
|
|
case RESULT_BASED_REG:
|
2020-11-26 12:34:37 +01:00
|
|
|
e2k_gen_store_breg(ctx, res->u.reg.i, res->u.reg.v);
|
2020-11-17 19:58:22 +01:00
|
|
|
break;
|
|
|
|
case RESULT_REGULAR_REG:
|
2020-11-26 12:34:37 +01:00
|
|
|
e2k_gen_store_wreg(ctx, res->u.reg.i, res->u.reg.v);
|
2020-11-17 19:58:22 +01:00
|
|
|
break;
|
|
|
|
case RESULT_GLOBAL_REG:
|
|
|
|
e2k_gen_store_greg(res->u.reg.i, res->u.reg.v);
|
|
|
|
break;
|
|
|
|
case RESULT_PREG:
|
|
|
|
e2k_gen_store_preg(res->u.reg.i, res->u.reg.v);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2020-11-24 10:12:01 +01:00
|
|
|
|
|
|
|
gen_set_label(l0);
|
2020-11-11 11:23:38 +01:00
|
|
|
}
|
2020-11-17 19:58:22 +01:00
|
|
|
|
2020-11-23 20:57:46 +01:00
|
|
|
e2k_plu_commit(ctx);
|
2020-11-17 19:58:22 +01:00
|
|
|
e2k_commit_stubs(ctx);
|
|
|
|
}
|
|
|
|
|
2020-11-28 08:44:53 +01:00
|
|
|
static inline void do_branch(DisasContext *ctx, target_ulong pc_next)
|
2020-11-17 19:58:22 +01:00
|
|
|
{
|
2020-11-19 21:57:06 +01:00
|
|
|
TCGLabel *l0;
|
|
|
|
|
|
|
|
if (ctx->ct.type == CT_NONE) {
|
2020-11-28 08:44:53 +01:00
|
|
|
// FIXME: do not write to e2k_cs.pc if not necessary
|
|
|
|
tcg_gen_movi_tl(e2k_cs.pc, pc_next);
|
2020-11-19 21:57:06 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx->base.is_jmp = DISAS_NORETURN;
|
|
|
|
|
|
|
|
l0 = gen_new_label();
|
|
|
|
tcg_gen_brcondi_tl(TCG_COND_NE, e2k_cs.ct_cond, 0, l0);
|
2020-11-28 08:44:53 +01:00
|
|
|
gen_goto_tb(ctx, TB_EXIT_IDX0, ctx->pc, pc_next);
|
2020-11-19 21:57:06 +01:00
|
|
|
gen_set_label(l0);
|
|
|
|
|
2020-11-17 19:58:22 +01:00
|
|
|
switch(ctx->ct.type) {
|
|
|
|
case CT_NONE:
|
2020-11-11 21:45:55 +01:00
|
|
|
break;
|
2020-11-17 19:58:22 +01:00
|
|
|
case CT_IBRANCH:
|
2020-11-28 08:44:53 +01:00
|
|
|
gen_goto_tb(ctx, TB_EXIT_IDX0, ctx->ct.u.target);
|
2020-11-17 19:58:22 +01:00
|
|
|
break;
|
2020-11-19 22:20:03 +01:00
|
|
|
case CT_JUMP: {
|
|
|
|
TCGLabel *l0 = gen_new_label();
|
|
|
|
TCGLabel *l1 = gen_new_label();
|
2020-11-23 07:14:26 +01:00
|
|
|
TCGv_i64 t0 = tcg_temp_local_new_i64();
|
2020-11-19 22:20:03 +01:00
|
|
|
|
|
|
|
gen_ctpr_tag(t0, ctx->ct.u.ctpr);
|
|
|
|
tcg_gen_brcondi_i64(TCG_COND_EQ, t0, CTPR_TAG_DISP, l0);
|
|
|
|
tcg_gen_brcondi_i64(TCG_COND_EQ, t0, CTPR_TAG_RETURN, l1);
|
2020-11-23 07:14:26 +01:00
|
|
|
tcg_temp_free_i64(t0);
|
|
|
|
|
2020-11-19 22:20:03 +01:00
|
|
|
// TODO: ldisp, sdisp
|
2020-11-28 08:44:53 +01:00
|
|
|
e2k_gen_exception(0);
|
2020-11-19 22:20:03 +01:00
|
|
|
|
|
|
|
gen_set_label(l1);
|
2020-11-23 07:14:26 +01:00
|
|
|
gen_helper_return(cpu_env);
|
2020-11-28 11:26:26 +01:00
|
|
|
|
|
|
|
gen_set_label(l0);
|
|
|
|
gen_goto_ctpr_disp(ctx->ct.u.ctpr);
|
2020-11-17 19:58:22 +01:00
|
|
|
break;
|
2020-11-19 22:20:03 +01:00
|
|
|
}
|
2020-11-19 21:57:06 +01:00
|
|
|
case CT_CALL: {
|
2020-11-17 19:58:22 +01:00
|
|
|
TCGv_i32 wbs = tcg_const_i32(ctx->ct.wbs);
|
2020-11-28 08:44:53 +01:00
|
|
|
TCGv npc = tcg_const_tl(pc_next);
|
|
|
|
|
|
|
|
gen_helper_call(cpu_env, ctx->ct.u.ctpr, wbs, npc);
|
2020-11-17 19:58:22 +01:00
|
|
|
tcg_gen_lookup_and_goto_ptr();
|
2020-11-28 08:44:53 +01:00
|
|
|
|
|
|
|
tcg_temp_free(npc);
|
|
|
|
tcg_temp_free_i32(wbs);
|
2020-11-17 19:58:22 +01:00
|
|
|
break;
|
2020-11-10 13:06:44 +01:00
|
|
|
}
|
2020-11-10 23:32:28 +01:00
|
|
|
}
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void e2k_tr_init_disas_context(DisasContextBase *db, CPUState *cs)
|
|
|
|
{
|
|
|
|
DisasContext *dc = container_of(db, DisasContext, base);
|
2020-11-11 21:45:55 +01:00
|
|
|
E2KCPU *cpu = E2K_CPU(cs);
|
|
|
|
CPUE2KState *env = &cpu->env;
|
2020-11-08 19:27:47 +01:00
|
|
|
|
2020-11-11 21:45:55 +01:00
|
|
|
dc->version = env->version;
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
|
2020-11-17 19:58:22 +01:00
|
|
|
static void e2k_tr_tb_start(DisasContextBase *db, CPUState *cs)
|
|
|
|
{
|
2020-11-23 07:14:26 +01:00
|
|
|
// DisasContext *ctx = container_of(db, DisasContext, base);
|
2020-11-17 19:58:22 +01:00
|
|
|
|
2020-11-25 18:56:05 +01:00
|
|
|
tcg_gen_movi_tl(e2k_cs.ct_cond, 0);
|
2020-11-17 19:58:22 +01:00
|
|
|
}
|
|
|
|
|
2020-11-08 19:27:47 +01:00
|
|
|
static void e2k_tr_insn_start(DisasContextBase *db, CPUState *cs)
|
|
|
|
{
|
2020-11-27 08:45:35 +01:00
|
|
|
DisasContext *ctx = container_of(db, DisasContext, base);
|
|
|
|
|
|
|
|
tcg_gen_insn_start(ctx->base.pc_next);
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void e2k_tr_translate_insn(DisasContextBase *db, CPUState *cs)
|
|
|
|
{
|
2020-11-17 19:58:22 +01:00
|
|
|
DisasContext *ctx = container_of(db, DisasContext, base);
|
2020-11-23 07:14:26 +01:00
|
|
|
TCGLabel *l0 = gen_new_label();
|
2020-11-28 08:44:53 +01:00
|
|
|
target_ulong pc_next;
|
2020-11-23 07:14:26 +01:00
|
|
|
|
|
|
|
tcg_gen_brcondi_i32(TCG_COND_EQ, e2k_cs.is_bp, 0, l0);
|
|
|
|
gen_helper_break_restore_state(cpu_env);
|
|
|
|
gen_set_label(l0);
|
2020-11-12 14:52:51 +01:00
|
|
|
|
2020-11-24 21:41:27 +01:00
|
|
|
do_reset(ctx);
|
2020-11-28 08:44:53 +01:00
|
|
|
pc_next = do_decode(ctx, cs);
|
2020-11-17 19:58:22 +01:00
|
|
|
do_execute(ctx);
|
|
|
|
do_commit(ctx);
|
2020-11-28 08:44:53 +01:00
|
|
|
do_branch(ctx, pc_next);
|
|
|
|
|
|
|
|
ctx->base.pc_next = pc_next;
|
2020-11-12 14:52:51 +01:00
|
|
|
|
|
|
|
/* Free temporary values */
|
2020-11-17 19:58:22 +01:00
|
|
|
while(ctx->t32_len) {
|
|
|
|
tcg_temp_free_i32(ctx->t32[--ctx->t32_len]);
|
2020-11-12 14:52:51 +01:00
|
|
|
}
|
|
|
|
|
2020-11-17 19:58:22 +01:00
|
|
|
while(ctx->t64_len) {
|
|
|
|
tcg_temp_free_i64(ctx->t64[--ctx->t64_len]);
|
2020-11-12 14:52:51 +01:00
|
|
|
}
|
|
|
|
|
2020-11-17 19:58:22 +01:00
|
|
|
while(ctx->ttl_len) {
|
|
|
|
tcg_temp_free(ctx->ttl[--ctx->ttl_len]);
|
2020-11-12 14:52:51 +01:00
|
|
|
}
|
2020-11-10 13:06:44 +01:00
|
|
|
}
|
|
|
|
|
2020-11-08 19:27:47 +01:00
|
|
|
static void e2k_tr_tb_stop(DisasContextBase *db, CPUState *cs)
|
|
|
|
{
|
2020-11-17 19:58:22 +01:00
|
|
|
DisasContext *ctx = container_of(db, DisasContext, base);
|
2020-11-12 14:52:51 +01:00
|
|
|
|
2020-11-17 19:58:22 +01:00
|
|
|
switch(ctx->base.is_jmp) {
|
2020-11-12 14:52:51 +01:00
|
|
|
case DISAS_NEXT:
|
|
|
|
case DISAS_TOO_MANY:
|
2020-11-28 08:44:53 +01:00
|
|
|
if (ctx->ct.type != CT_NONE) {
|
|
|
|
gen_goto_tb(ctx, TB_EXIT_IDX0, ctx->pc, ctx->base.pc_next);
|
|
|
|
}
|
2020-11-12 14:52:51 +01:00
|
|
|
break;
|
2020-11-16 17:54:28 +01:00
|
|
|
case DISAS_NORETURN:
|
|
|
|
break;
|
2020-11-12 14:52:51 +01:00
|
|
|
default:
|
2020-11-12 22:46:57 +01:00
|
|
|
g_assert_not_reached();
|
2020-11-12 14:52:51 +01:00
|
|
|
break;
|
|
|
|
}
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
|
2020-11-10 23:00:32 +01:00
|
|
|
static void e2k_tr_disas_log(const DisasContextBase *db,
|
|
|
|
CPUState *cpu, FILE *logfile)
|
2020-11-08 19:27:47 +01:00
|
|
|
{
|
2020-11-10 23:00:32 +01:00
|
|
|
DisasContext *dc = container_of(db, DisasContext, base);
|
|
|
|
|
|
|
|
fprintf(logfile, "IN: %s\n", lookup_symbol(dc->base.pc_first));
|
|
|
|
target_disas(logfile, cpu, dc->base.pc_first, dc->base.tb->size);
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
.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)
|
|
|
|
{
|
2020-11-10 23:32:28 +01:00
|
|
|
DisasContext dc = { 0 };
|
2020-11-08 19:27:47 +01:00
|
|
|
|
|
|
|
translator_loop(&e2k_tr_ops, &dc.base, cs, tb, max_insns);
|
|
|
|
}
|
|
|
|
|
|
|
|
void restore_state_to_opc(CPUE2KState *env, TranslationBlock *tb,
|
|
|
|
target_ulong *data)
|
|
|
|
{
|
2020-11-28 09:08:22 +01:00
|
|
|
// TODO: restore_state_to_opc
|
2020-11-08 19:27:47 +01:00
|
|
|
qemu_log_mask(LOG_UNIMP, "restore_state_to_opc: not implemented\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void e2k_tcg_initialize(void) {
|
2020-11-15 16:05:27 +01:00
|
|
|
char buf[16] = { 0 };
|
2020-11-10 13:06:44 +01:00
|
|
|
|
2020-11-11 10:28:06 +01:00
|
|
|
static const struct { TCGv_i32 *ptr; int off; const char *name; } r32[] = {
|
2020-11-26 19:35:07 +01:00
|
|
|
{ &e2k_cs.wd_base, offsetof(CPUE2KState, wd.base), "woff" },
|
|
|
|
{ &e2k_cs.wd_size, offsetof(CPUE2KState, wd.size), "wsize" },
|
2020-11-26 19:25:43 +01:00
|
|
|
{ &e2k_cs.boff, offsetof(CPUE2KState, bn.base), "boff" },
|
|
|
|
{ &e2k_cs.bsize, offsetof(CPUE2KState, bn.size), "bsize" },
|
|
|
|
{ &e2k_cs.bcur, offsetof(CPUE2KState, bn.cur), "bcur" },
|
|
|
|
{ &e2k_cs.psize, offsetof(CPUE2KState, bp.size), "psize" },
|
|
|
|
{ &e2k_cs.pcur, offsetof(CPUE2KState, bp.cur), "pcur" },
|
2020-11-23 07:14:26 +01:00
|
|
|
{ &e2k_cs.is_bp, offsetof(CPUE2KState, is_bp), "is_bp" },
|
2020-11-11 10:28:06 +01:00
|
|
|
};
|
|
|
|
|
2020-11-10 23:32:28 +01:00
|
|
|
static const struct { TCGv_i64 *ptr; int off; const char *name; } r64[] = {
|
2020-11-14 13:23:58 +01:00
|
|
|
{ &e2k_cs.pregs, offsetof(CPUE2KState, pf), "pregs" },
|
2020-11-13 17:40:56 +01:00
|
|
|
{ &e2k_cs.lsr, offsetof(CPUE2KState, lsr), "lsr" },
|
2020-11-10 13:06:44 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct { TCGv *ptr; int off; const char *name; } rtl[] = {
|
2020-11-11 20:03:51 +01:00
|
|
|
{ &e2k_cs.pc, offsetof(CPUE2KState, ip), "pc" },
|
2020-11-15 16:05:27 +01:00
|
|
|
{ &e2k_cs.npc, offsetof(CPUE2KState, nip), "npc" },
|
2020-11-19 21:47:25 +01:00
|
|
|
{ &e2k_cs.ct_cond, offsetof(CPUE2KState, ct_cond), "cond" },
|
2020-11-10 13:06:44 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
unsigned int i;
|
|
|
|
|
2020-11-11 10:28:06 +01:00
|
|
|
for (i = 0; i < ARRAY_SIZE(r32); i++) {
|
2020-11-11 15:56:46 +01:00
|
|
|
*r32[i].ptr = tcg_global_mem_new_i32(cpu_env, r32[i].off, r32[i].name);
|
2020-11-11 10:28:06 +01:00
|
|
|
}
|
|
|
|
|
2020-11-10 23:32:28 +01:00
|
|
|
for (i = 0; i < ARRAY_SIZE(r64); i++) {
|
2020-11-11 15:56:46 +01:00
|
|
|
*r64[i].ptr = tcg_global_mem_new_i64(cpu_env, r64[i].off, r64[i].name);
|
2020-11-10 13:06:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(rtl); i++) {
|
|
|
|
*rtl[i].ptr = tcg_global_mem_new(cpu_env, rtl[i].off, rtl[i].name);
|
|
|
|
}
|
|
|
|
|
2020-11-15 16:05:27 +01:00
|
|
|
e2k_cs.wptr = tcg_global_mem_new_ptr(cpu_env,
|
|
|
|
offsetof(CPUE2KState, wptr), "wptr");
|
2020-11-11 10:28:06 +01:00
|
|
|
|
2020-11-10 13:06:44 +01:00
|
|
|
for (i = 0; i < WREGS_SIZE; i++) {
|
|
|
|
snprintf(buf, ARRAY_SIZE(buf), "%%r%d", i);
|
2020-11-15 16:05:27 +01:00
|
|
|
e2k_cs.wregs[i] = tcg_global_mem_new_i64(e2k_cs.wptr,
|
|
|
|
i * REG_SIZE, buf);
|
2020-11-10 13:06:44 +01:00
|
|
|
}
|
|
|
|
|
2020-11-15 16:05:27 +01:00
|
|
|
for (i = 0; i < GREGS_SIZE; i++) {
|
2020-11-10 13:06:44 +01:00
|
|
|
snprintf(buf, ARRAY_SIZE(buf), "%%g%d", i);
|
2020-11-15 16:05:27 +01:00
|
|
|
e2k_cs.gregs[i] = tcg_global_mem_new_i64(cpu_env,
|
|
|
|
offsetof(CPUE2KState, gregs[i]), buf);
|
2020-11-10 13:06:44 +01:00
|
|
|
}
|
2020-11-10 23:32:28 +01:00
|
|
|
|
2020-11-22 08:37:45 +01:00
|
|
|
for (i = 0; i < 3; i++) {
|
2020-11-10 23:32:28 +01:00
|
|
|
snprintf(buf, ARRAY_SIZE(buf), "%%ctpr%d", i + 1);
|
2020-11-11 20:03:51 +01:00
|
|
|
e2k_cs.ctprs[i] = tcg_global_mem_new(cpu_env,
|
2020-11-15 16:05:27 +01:00
|
|
|
offsetof(CPUE2KState, ctprs[i]), buf);
|
2020-11-10 23:32:28 +01:00
|
|
|
}
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|