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 */
|
|
|
|
static target_ulong 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. */
|
|
|
|
pos = ((GET_FIELD(hs, 4, 6) + 1) << 3) - 4;
|
|
|
|
|
|
|
|
/* Check for CDSj syllables. */
|
|
|
|
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;
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
|
2020-11-11 18:06:46 +01:00
|
|
|
/* Check for PLSj syllables. */
|
|
|
|
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;
|
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-11 18:06:46 +01:00
|
|
|
return 8 + GET_FIELD(hs, 4, 6) * 8;
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
|
2020-11-10 13:06:44 +01:00
|
|
|
static inline void save_state(DisasContext *dc)
|
|
|
|
{
|
2020-11-11 20:03:51 +01:00
|
|
|
tcg_gen_movi_tl(e2k_cs.pc, dc->pc);
|
2020-11-15 16:05:27 +01:00
|
|
|
tcg_gen_movi_tl(e2k_cs.npc, dc->npc);
|
2020-11-10 13:06:44 +01:00
|
|
|
}
|
|
|
|
|
2020-11-11 20:03:51 +01:00
|
|
|
void e2k_gen_exception(DisasContext *dc, 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
|
|
|
|
|
|
|
save_state(dc);
|
|
|
|
gen_helper_raise_exception(cpu_env, t);
|
|
|
|
tcg_temp_free_i32(t);
|
|
|
|
dc->base.is_jmp = DISAS_NORETURN;
|
|
|
|
}
|
|
|
|
|
2020-11-08 19:27:47 +01:00
|
|
|
static target_ulong disas_e2k_insn(DisasContext *dc, CPUState *cs)
|
|
|
|
{
|
|
|
|
E2KCPU *cpu = E2K_CPU(cs);
|
|
|
|
CPUE2KState *env = &cpu->env;
|
2020-11-11 18:06:46 +01:00
|
|
|
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;
|
2020-11-08 19:27:47 +01:00
|
|
|
|
2020-11-11 22:30:14 +01:00
|
|
|
dc->jmp.dest = tcg_const_i64(0);
|
2020-11-11 21:45:55 +01:00
|
|
|
dc->jmp.cond = tcg_const_i64(0);
|
2020-11-10 13:06:44 +01:00
|
|
|
|
2020-11-11 20:03:51 +01:00
|
|
|
e2k_alc_gen(dc);
|
2020-11-11 21:45:55 +01:00
|
|
|
e2k_control_gen(dc);
|
2020-11-11 09:06:13 +01:00
|
|
|
|
2020-11-11 20:03:51 +01:00
|
|
|
e2k_alc_commit(dc);
|
|
|
|
e2k_win_commit(dc);
|
2020-11-11 10:28:06 +01:00
|
|
|
|
2020-11-11 21:45:55 +01:00
|
|
|
/* Control transfer */
|
|
|
|
switch(dc->base.is_jmp) {
|
|
|
|
case DISAS_NEXT:
|
|
|
|
case DISAS_TOO_MANY:
|
|
|
|
dc->base.pc_next = pc_next;
|
|
|
|
break;
|
|
|
|
case DISAS_NORETURN:
|
|
|
|
/* exception */
|
2020-11-11 20:03:51 +01:00
|
|
|
tcg_gen_movi_tl(e2k_cs.pc, dc->pc);
|
2020-11-11 11:23:38 +01:00
|
|
|
tcg_gen_exit_tb(NULL, 0);
|
2020-11-11 21:45:55 +01:00
|
|
|
break;
|
|
|
|
case STATIC_JUMP:
|
|
|
|
tcg_gen_mov_i64(e2k_cs.pc, dc->jmp.dest);
|
|
|
|
tcg_gen_exit_tb(NULL, 0);
|
|
|
|
break;
|
|
|
|
case DYNAMIC_JUMP: {
|
|
|
|
TCGv_i64 one = tcg_const_i64(1);
|
|
|
|
TCGv_i64 next = tcg_const_i64(pc_next);
|
|
|
|
tcg_gen_movcond_i64(TCG_COND_EQ, e2k_cs.pc,
|
|
|
|
dc->jmp.cond, one,
|
|
|
|
dc->jmp.dest, next
|
|
|
|
);
|
|
|
|
tcg_temp_free_i64(next);
|
|
|
|
tcg_temp_free_i64(one);
|
|
|
|
tcg_gen_exit_tb(NULL, 0);
|
|
|
|
break;
|
2020-11-11 11:23:38 +01:00
|
|
|
}
|
2020-11-11 21:45:55 +01:00
|
|
|
default:
|
|
|
|
/* TODO: unreachable */
|
|
|
|
abort();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-11-11 22:30:14 +01:00
|
|
|
tcg_temp_free_i64(dc->jmp.dest);
|
2020-11-11 21:45:55 +01:00
|
|
|
tcg_temp_free_i64(dc->jmp.cond);
|
2020-11-11 11:23:38 +01:00
|
|
|
|
2020-11-11 21:45:55 +01:00
|
|
|
/* Free temporary values */
|
2020-11-10 13:06:44 +01:00
|
|
|
while(dc->t32_len) {
|
|
|
|
tcg_temp_free_i32(dc->t32[--dc->t32_len]);
|
|
|
|
}
|
|
|
|
|
|
|
|
while(dc->t64_len) {
|
|
|
|
tcg_temp_free_i64(dc->t64[--dc->t64_len]);
|
|
|
|
}
|
|
|
|
|
2020-11-10 23:32:28 +01:00
|
|
|
while(dc->ttl_len) {
|
|
|
|
tcg_temp_free(dc->ttl[--dc->ttl_len]);
|
|
|
|
}
|
|
|
|
|
2020-11-10 13:06:44 +01:00
|
|
|
return pc_next;
|
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-16 15:26:39 +01:00
|
|
|
dc->pc = 0;
|
|
|
|
dc->npc = dc->base.pc_first;
|
2020-11-11 21:45:55 +01:00
|
|
|
dc->version = env->version;
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void e2k_tr_insn_start(DisasContextBase *db, CPUState *cs)
|
|
|
|
{
|
|
|
|
DisasContext *dc = container_of(db, DisasContext, base);
|
|
|
|
tcg_gen_insn_start(dc->pc);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2020-11-12 14:52:51 +01:00
|
|
|
E2KCPU *cpu = E2K_CPU(cs);
|
|
|
|
CPUE2KState *env = &cpu->env;
|
|
|
|
UnpackedBundle *bundle = &dc->bundle;
|
2020-11-16 15:26:39 +01:00
|
|
|
unsigned int bundle_len;
|
2020-11-15 16:05:27 +01:00
|
|
|
|
2020-11-16 15:26:39 +01:00
|
|
|
dc->pc = dc->npc;
|
|
|
|
bundle_len = unpack_bundle(env, dc->pc, bundle);
|
2020-11-12 14:52:51 +01:00
|
|
|
/* TODO: exception, check bundle_len */
|
2020-11-16 15:26:39 +01:00
|
|
|
dc->npc = dc->base.pc_next = dc->pc + bundle_len;
|
2020-11-12 14:52:51 +01:00
|
|
|
|
|
|
|
e2k_alc_gen(dc);
|
|
|
|
e2k_control_gen(dc);
|
|
|
|
|
|
|
|
e2k_alc_commit(dc);
|
|
|
|
e2k_win_commit(dc);
|
|
|
|
|
|
|
|
/* Free temporary values */
|
|
|
|
while(dc->t32_len) {
|
|
|
|
tcg_temp_free_i32(dc->t32[--dc->t32_len]);
|
|
|
|
}
|
|
|
|
|
|
|
|
while(dc->t64_len) {
|
|
|
|
tcg_temp_free_i64(dc->t64[--dc->t64_len]);
|
|
|
|
}
|
|
|
|
|
|
|
|
while(dc->ttl_len) {
|
|
|
|
tcg_temp_free(dc->ttl[--dc->ttl_len]);
|
|
|
|
}
|
2020-11-10 13:06:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void e2k_tr_tb_start(DisasContextBase *db, CPUState *cs)
|
|
|
|
{
|
2020-11-16 15:26:39 +01:00
|
|
|
tcg_gen_movi_tl(e2k_cs.cond, 0);
|
|
|
|
tcg_gen_movi_i32(e2k_cs.call_wbs, 0);
|
2020-11-08 19:27:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void e2k_tr_tb_stop(DisasContextBase *db, CPUState *cs)
|
|
|
|
{
|
2020-11-12 14:52:51 +01:00
|
|
|
DisasContext *dc = container_of(db, DisasContext, base);
|
|
|
|
|
|
|
|
/* Control transfer */
|
|
|
|
switch(dc->base.is_jmp) {
|
|
|
|
case DISAS_NEXT:
|
|
|
|
case DISAS_TOO_MANY:
|
|
|
|
break;
|
2020-11-12 18:12:18 +01:00
|
|
|
case DISAS_NORETURN: {
|
|
|
|
/* exception */
|
2020-11-12 14:52:51 +01:00
|
|
|
tcg_gen_exit_tb(NULL, 0);
|
|
|
|
break;
|
2020-11-12 18:12:18 +01:00
|
|
|
}
|
2020-11-16 15:26:39 +01:00
|
|
|
case DISAS_JUMP_STATIC:
|
2020-11-15 16:05:27 +01:00
|
|
|
tcg_gen_movi_tl(e2k_cs.pc, dc->jmp.dest);
|
2020-11-12 14:52:51 +01:00
|
|
|
tcg_gen_exit_tb(NULL, 0);
|
|
|
|
break;
|
2020-11-16 15:26:39 +01:00
|
|
|
case DISAS_BRANCH_STATIC: {
|
|
|
|
TCGv z = tcg_const_tl(0);
|
|
|
|
TCGv t = tcg_const_tl(dc->jmp.dest);
|
|
|
|
TCGv f = tcg_const_tl(dc->npc);
|
|
|
|
|
|
|
|
tcg_gen_movcond_tl(TCG_COND_NE, e2k_cs.pc, e2k_cs.cond, z, t, f);
|
|
|
|
tcg_gen_exit_tb(NULL, 0);
|
|
|
|
|
|
|
|
tcg_temp_free(f);
|
|
|
|
tcg_temp_free(t);
|
|
|
|
tcg_temp_free(z);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case DISAS_JUMP: {
|
|
|
|
TCGv_i32 ctpr = tcg_const_i32(dc->jump_ctpr);
|
|
|
|
|
2020-11-15 16:05:27 +01:00
|
|
|
save_state(dc);
|
2020-11-16 15:26:39 +01:00
|
|
|
gen_helper_jump(e2k_cs.pc, cpu_env, ctpr);
|
2020-11-15 16:05:27 +01:00
|
|
|
tcg_gen_exit_tb(NULL, 0);
|
2020-11-16 15:26:39 +01:00
|
|
|
|
|
|
|
tcg_temp_free_i32(ctpr);
|
2020-11-15 16:05:27 +01:00
|
|
|
break;
|
|
|
|
}
|
2020-11-16 15:26:39 +01:00
|
|
|
case DISAS_BRANCH: {
|
|
|
|
TCGv_i32 ctpr = tcg_const_i32(dc->jump_ctpr);
|
|
|
|
TCGv z = tcg_const_tl(0);
|
|
|
|
TCGv t = tcg_temp_new();
|
|
|
|
TCGv f = tcg_const_tl(dc->npc);
|
|
|
|
|
2020-11-15 16:05:27 +01:00
|
|
|
save_state(dc);
|
2020-11-16 15:26:39 +01:00
|
|
|
gen_helper_branch(t, cpu_env, ctpr, e2k_cs.cond);
|
|
|
|
tcg_gen_movcond_tl(TCG_COND_NE, e2k_cs.pc, e2k_cs.cond, z, t, f);
|
2020-11-12 14:52:51 +01:00
|
|
|
tcg_gen_exit_tb(NULL, 0);
|
2020-11-16 15:26:39 +01:00
|
|
|
|
|
|
|
tcg_temp_free(f);
|
|
|
|
tcg_temp_free(t);
|
|
|
|
tcg_temp_free(z);
|
|
|
|
tcg_temp_free_i32(ctpr);
|
2020-11-12 14:52:51 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
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,
|
|
|
|
.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)
|
|
|
|
{
|
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)
|
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
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-15 16:05:27 +01:00
|
|
|
{ &e2k_cs.call_wbs, offsetof(CPUE2KState, call_wbs), "call_wbs" },
|
2020-11-16 15:26:39 +01:00
|
|
|
{ &e2k_cs.woff, offsetof(CPUE2KState, woff), "woff" },
|
|
|
|
{ &e2k_cs.wsize, offsetof(CPUE2KState, wsize), "wsize" },
|
|
|
|
{ &e2k_cs.boff, offsetof(CPUE2KState, boff), "boff" },
|
|
|
|
{ &e2k_cs.bsize, offsetof(CPUE2KState, bsize), "bsize" },
|
|
|
|
{ &e2k_cs.bcur, offsetof(CPUE2KState, bcur), "bcur" },
|
|
|
|
{ &e2k_cs.psize, offsetof(CPUE2KState, psize), "psize" },
|
|
|
|
{ &e2k_cs.pcur, offsetof(CPUE2KState, pcur), "pcur" },
|
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-16 15:26:39 +01:00
|
|
|
{ &e2k_cs.cond, offsetof(CPUE2KState, 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-15 16:05:27 +01:00
|
|
|
for (i = 0; i < 4; 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
|
|
|
}
|