qemu-e2k/target/e2k/translate/aau.c

189 lines
4.6 KiB
C

#include "qemu/osdep.h"
#include "qemu.h"
#include "exec/log.h"
#include "translate.h"
typedef struct {
int chan;
union {
struct {
uint16_t am: 1;
uint16_t ind: 5;
uint16_t area: 6;
uint16_t opc: 3;
uint16_t be: 1;
};
uint16_t aas;
};
uint8_t dst;
} Mova;
static void gen_load_prefetch_program(DisasContext *ctx)
{
gen_helper_aau_load_program(cpu_env);
}
static void gen_aau_result(DisasContext *ctx, Mova *instr, TCGv_i64 dst,
TCGv_i32 tag)
{
AauResult *res = &ctx->aau_results[instr->chan];
res->is_set = true;
res->index = e2k_get_temp_i32(ctx);
res->value = dst;
res->tag = tag;
if (IS_REGULAR(instr->dst)) {
res->dst = instr->dst;
} else {
res->dst = 0;
e2k_gen_reg_index(ctx, res->index, instr->dst);
}
}
static void gen_checked_ld(DisasContext *ctx, Mova *instr, TCGv ptr)
{
TCGLabel *l0 = gen_new_label();
TCGLabel *l1 = gen_new_label();
TCGv_i32 tag = e2k_get_temp_i32(ctx);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
MemOp memop = instr->be ? MO_BE : MO_LE;
switch(instr->opc) {
case 1: memop |= MO_8; break; /* movab */
case 2: memop |= MO_16; break; /* movah */
case 3: memop |= MO_32; break; /* movaw */
case 4: memop |= MO_64; break; /* movad */
default:
g_assert_not_reached();
break;
}
tcg_gen_brcondi_tl(TCG_COND_NE, ptr, 0, l0);
/* if address is invalid */
tcg_gen_movi_i32(tag, E2K_TAG_NON_NUMBER64);
tcg_gen_movi_i64(dst, E2K_MOVA_RESULT_INVALID);
tcg_gen_br(l1);
/* if address is valid */
gen_set_label(l0);
tcg_gen_movi_i32(tag, E2K_TAG_NUMBER64);
tcg_gen_qemu_ld_i64(dst, ptr, 0, memop);
gen_set_label(l1);
gen_aau_result(ctx, instr, dst, tag);
}
static inline void gen_mova_ptr(TCGv ret, Mova *instr)
{
TCGv_i32 t0 = tcg_const_i32(instr->chan);
TCGv_i32 t1 = tcg_const_i32(instr->area);
TCGv_i32 t2 = tcg_const_i32(instr->ind);
gen_helper_mova_ptr(ret, cpu_env, t0, t1, t2);
tcg_temp_free_i32(t2);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
static void gen_mova(DisasContext *ctx, Mova *instr)
{
/* branch in gen_checked_ld */
TCGv t5 = tcg_temp_local_new();
ctx->aau_am[instr->chan] = instr->am ? instr->area : -1;
// TODO: check ind has proper alignment
// TODO: check ind is less than mrng
gen_mova_ptr(t5, instr);
switch(instr->opc) {
case 1: /* movab */
case 2: /* movah */
case 3: /* movaw */
case 4: /* movad */
gen_checked_ld(ctx, instr, t5);
break;
case 5: /* movaq */
e2k_todo_illop(ctx, "movaq");
break;
case 7: /* movaqp */
e2k_todo_illop(ctx, "movaqp");
break;
default:
gen_tr_excp_illopc(ctx);
break;
}
tcg_temp_free(t5);
}
static inline void gen_aau_am(DisasContext *ctx, int chan, int area)
{
TCGv_i32 t0 = tcg_const_i32(chan);
TCGv_i32 t1 = tcg_const_i32(area);
gen_helper_aau_am(cpu_env, t0, t1);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
void e2k_aau_execute(DisasContext *ctx)
{
const UnpackedBundle *bundle = &ctx->bundle;
unsigned int i;
for (i = 0; i < 4; i++) {
Mova instr = { 0 };
AauResult *res = &ctx->aau_results[i];
instr.chan = i;
instr.aas = bundle->aas[i + 2];
instr.dst = extract16(bundle->aas[i / 2], ((i & 1) ^ 1) * 8, 8);
if (!bundle->aas_present[i + 2] || instr.opc == 0) {
ctx->aau_am[i] = -1;
res->is_set = false;
continue;
}
// TODO: invalid value if addr is unaligned
gen_mova(ctx, &instr);
}
/* bap */
if (ctx->bundle.ss & (1 << 28)) {
gen_load_prefetch_program(ctx);
}
}
void e2k_aau_commit(DisasContext *ctx)
{
unsigned int i;
for (i = 0; i < 4; i++) {
AauResult *res = &ctx->aau_results[i];
if (res->is_set) {
if (IS_REGULAR(res->dst)) {
e2k_gen_reg_index_from_wregi(res->index, GET_REGULAR(res->dst));
}
}
}
for (i = 0; i < 4; i++) {
AauResult *res = &ctx->aau_results[i];
// TODO: aau.tags
if (res->is_set) {
e2k_gen_reg_tag_write_i64(res->tag, res->index);
e2k_gen_reg_lo_write_i64(res->value, res->index);
}
}
for (i = 0; i < 4; i++) {
int area = ctx->aau_am[i];
if (area == -1 || ((i == 1 || i == 3) && ctx->aau_am[i - 1] == area)) {
continue;
}
gen_aau_am(ctx, i, area);
}
}