189 lines
4.6 KiB
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);
|
|
}
|
|
}
|