e2k: Add delayed window bounds static/dynamic checks.
This commit is contained in:
parent
f56cad7923
commit
9e8c927036
|
@ -533,6 +533,7 @@ static inline void gen_setwd(DisasContext *ctx)
|
||||||
TCGv_i32 t0 = tcg_const_i32(setr->wsz);
|
TCGv_i32 t0 = tcg_const_i32(setr->wsz);
|
||||||
TCGv_i32 t1 = tcg_const_i32(setr->nfx);
|
TCGv_i32 t1 = tcg_const_i32(setr->nfx);
|
||||||
TCGv_i32 t2 = tcg_const_i32(setr->dbl);
|
TCGv_i32 t2 = tcg_const_i32(setr->dbl);
|
||||||
|
ctx->wd_size = setr->wsz * 2;
|
||||||
gen_helper_setwd(cpu_env, t0, t1, t2);
|
gen_helper_setwd(cpu_env, t0, t1, t2);
|
||||||
tcg_temp_free_i32(t2);
|
tcg_temp_free_i32(t2);
|
||||||
tcg_temp_free_i32(t1);
|
tcg_temp_free_i32(t1);
|
||||||
|
@ -546,6 +547,7 @@ static inline void gen_setbn(DisasContext *ctx)
|
||||||
Cs1Setr *setr = &cs1->setr;
|
Cs1Setr *setr = &cs1->setr;
|
||||||
|
|
||||||
if (cs1->type == CS1_SETR && (setr->type & SETR_BN)) {
|
if (cs1->type == CS1_SETR && (setr->type & SETR_BN)) {
|
||||||
|
ctx->bsize = (setr->rsz + 1) * 2;
|
||||||
tcg_gen_movi_i32(e2k_cs.boff, setr->rbs * 2);
|
tcg_gen_movi_i32(e2k_cs.boff, setr->rbs * 2);
|
||||||
tcg_gen_movi_i32(e2k_cs.bsize, (setr->rsz + 1) * 2);
|
tcg_gen_movi_i32(e2k_cs.bsize, (setr->rsz + 1) * 2);
|
||||||
tcg_gen_movi_i32(e2k_cs.bcur, setr->rcur * 2);
|
tcg_gen_movi_i32(e2k_cs.bcur, setr->rcur * 2);
|
||||||
|
@ -923,6 +925,64 @@ static inline target_ulong do_decode(DisasContext *ctx, CPUState *cs)
|
||||||
return ctx->pc + len;
|
return ctx->pc + len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void gen_maperr_condi_i32(TCGCond cond, TCGv_i32 arg1, int arg2)
|
||||||
|
{
|
||||||
|
TCGLabel *l0 = gen_new_label();
|
||||||
|
tcg_gen_brcondi_i32(tcg_invert_cond(cond), arg1, arg2, l0);
|
||||||
|
e2k_gen_exception(E2K_EXCP_MAPERR);
|
||||||
|
gen_set_label(l0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void do_checks(DisasContext *ctx)
|
||||||
|
{
|
||||||
|
const Bundle *b = &ctx->bundle2;
|
||||||
|
const Cs1Setr *setr = &b->cs1.setr;
|
||||||
|
|
||||||
|
if (ctx->wd_size != DYNAMIC) {
|
||||||
|
/* %rN src static check */
|
||||||
|
if (ctx->wd_size <= ctx->max_r_src) {
|
||||||
|
e2k_tr_gen_exception(ctx, E2K_EXCP_MAPERR);
|
||||||
|
}
|
||||||
|
/* %rN dst static check */
|
||||||
|
if (b->cs1.type == CS1_SETR && (setr->type & SETR_WD)) {
|
||||||
|
if (setr->wsz * 2 <= ctx->max_r_dst) {
|
||||||
|
e2k_tr_gen_exception(ctx, E2K_EXCP_MAPERR);
|
||||||
|
}
|
||||||
|
} else if (ctx->wd_size <= ctx->max_r_dst) {
|
||||||
|
e2k_tr_gen_exception(ctx, E2K_EXCP_MAPERR);
|
||||||
|
}
|
||||||
|
} else if (b->cs1.type == CS1_SETR && (setr->type & SETR_WD)) {
|
||||||
|
/* %rN src dynamic check */
|
||||||
|
if (ctx->max_r < ctx->max_r_src) {
|
||||||
|
ctx->max_r = ctx->max_r_src;
|
||||||
|
gen_maperr_condi_i32(TCG_COND_LE, e2k_cs.wd_size, ctx->max_r_src);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* %rN dst static check */
|
||||||
|
if (setr->wsz * 2 <= ctx->max_r_dst) {
|
||||||
|
e2k_tr_gen_exception(ctx, E2K_EXCP_MAPERR);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* %rN src/dst dynamic check */
|
||||||
|
int max = MAX(ctx->max_r_src, ctx->max_r_dst);
|
||||||
|
if (ctx->max_r < max) {
|
||||||
|
ctx->max_r = max;
|
||||||
|
gen_maperr_condi_i32(TCG_COND_LE, e2k_cs.wd_size, max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->bsize != DYNAMIC) {
|
||||||
|
/* %b[N] src/dst static check */
|
||||||
|
if (ctx->bsize <= ctx->max_b_cur) {
|
||||||
|
e2k_tr_gen_exception(ctx, E2K_EXCP_MAPERR);
|
||||||
|
}
|
||||||
|
} else if (ctx->max_b < ctx->max_b_cur) {
|
||||||
|
/* %b[N] src/dst dynamic check */
|
||||||
|
ctx->max_b = ctx->max_b_cur;
|
||||||
|
gen_maperr_condi_i32(TCG_COND_LE, e2k_cs.bsize, ctx->max_b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Executes instructions from a bundle and store the results to
|
* Executes instructions from a bundle and store the results to
|
||||||
* temporary buffer.
|
* temporary buffer.
|
||||||
|
@ -1040,10 +1100,18 @@ static void e2k_tr_init_disas_context(DisasContextBase *db, CPUState *cs)
|
||||||
|
|
||||||
static void e2k_tr_tb_start(DisasContextBase *db, CPUState *cs)
|
static void e2k_tr_tb_start(DisasContextBase *db, CPUState *cs)
|
||||||
{
|
{
|
||||||
// DisasContext *ctx = container_of(db, DisasContext, base);
|
DisasContext *ctx = container_of(db, DisasContext, base);
|
||||||
E2KCPU *cpu = E2K_CPU(cs);
|
E2KCPU *cpu = E2K_CPU(cs);
|
||||||
CPUE2KState *env = &cpu->env;
|
CPUE2KState *env = &cpu->env;
|
||||||
|
|
||||||
|
ctx->wd_size = DYNAMIC;
|
||||||
|
ctx->max_r = -1;
|
||||||
|
ctx->max_r_src = -1;
|
||||||
|
ctx->max_r_dst = -1;
|
||||||
|
ctx->bsize = DYNAMIC;
|
||||||
|
ctx->max_b = -1;
|
||||||
|
ctx->max_b_cur = -1;
|
||||||
|
|
||||||
tcg_gen_movi_i32(e2k_cs.ct_cond, 0);
|
tcg_gen_movi_i32(e2k_cs.ct_cond, 0);
|
||||||
|
|
||||||
if (env->is_bp) {
|
if (env->is_bp) {
|
||||||
|
@ -1062,6 +1130,11 @@ static void e2k_tr_insn_start(DisasContextBase *db, CPUState *cs)
|
||||||
|
|
||||||
memset(ctx->mas, 0, sizeof(ctx->mas));
|
memset(ctx->mas, 0, sizeof(ctx->mas));
|
||||||
memset(&ctx->bundle2, 0, sizeof(ctx->bundle2));
|
memset(&ctx->bundle2, 0, sizeof(ctx->bundle2));
|
||||||
|
|
||||||
|
ctx->max_r_src = -1;
|
||||||
|
ctx->max_r_dst = -1;
|
||||||
|
ctx->max_b_cur = -1;
|
||||||
|
|
||||||
ctx->do_check_illtag = false;
|
ctx->do_check_illtag = false;
|
||||||
ctx->illtag = e2k_get_temp_i32(ctx);
|
ctx->illtag = e2k_get_temp_i32(ctx);
|
||||||
tcg_gen_movi_i32(ctx->illtag, 0);
|
tcg_gen_movi_i32(ctx->illtag, 0);
|
||||||
|
@ -1074,6 +1147,7 @@ static void e2k_tr_translate_insn(DisasContextBase *db, CPUState *cs)
|
||||||
|
|
||||||
pc_next = do_decode(ctx, cs);
|
pc_next = do_decode(ctx, cs);
|
||||||
do_execute(ctx);
|
do_execute(ctx);
|
||||||
|
do_checks(ctx);
|
||||||
do_commit(ctx);
|
do_commit(ctx);
|
||||||
do_branch(ctx, pc_next);
|
do_branch(ctx, pc_next);
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include "tcg/tcg-op.h"
|
#include "tcg/tcg-op.h"
|
||||||
#include "exec/translator.h"
|
#include "exec/translator.h"
|
||||||
|
|
||||||
|
#define DYNAMIC -1
|
||||||
|
|
||||||
#define IS_BASED(i) (((i) & 0x80) == 0)
|
#define IS_BASED(i) (((i) & 0x80) == 0)
|
||||||
#define IS_REGULAR(i) (((i) & 0xc0) == 0x80)
|
#define IS_REGULAR(i) (((i) & 0xc0) == 0x80)
|
||||||
#define IS_IMM5(i) (((i) & 0xe0) == 0xc0)
|
#define IS_IMM5(i) (((i) & 0xe0) == 0xc0)
|
||||||
|
@ -355,8 +357,11 @@ typedef struct DisasContext {
|
||||||
bool do_check_illtag;
|
bool do_check_illtag;
|
||||||
|
|
||||||
/* Delayed window bounds check */
|
/* Delayed window bounds check */
|
||||||
|
int wd_size;
|
||||||
int max_r;
|
int max_r;
|
||||||
int max_r_cur;
|
int max_r_src;
|
||||||
|
int max_r_dst;
|
||||||
|
int bsize;
|
||||||
int max_b;
|
int max_b;
|
||||||
int max_b_cur;
|
int max_b_cur;
|
||||||
|
|
||||||
|
|
|
@ -1462,7 +1462,7 @@ static inline void gen_puttag_i32(Instr *instr)
|
||||||
set_al_result_reg32_tag(instr, dst, tag, false, false);
|
set_al_result_reg32_tag(instr, dst, tag, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void gen_insert_field_i64(TCGv_i64 ret, TCGv_i64 src1,
|
static inline void gen_insfd(TCGv_i64 ret, TCGv_i64 src1,
|
||||||
TCGv_i64 src2, TCGv_i64 src3)
|
TCGv_i64 src2, TCGv_i64 src3)
|
||||||
{
|
{
|
||||||
TCGv_i64 one = tcg_const_i64(1);
|
TCGv_i64 one = tcg_const_i64(1);
|
||||||
|
@ -1496,7 +1496,7 @@ static inline void gen_insert_field_i64(TCGv_i64 ret, TCGv_i64 src1,
|
||||||
tcg_temp_free_i64(one);
|
tcg_temp_free_i64(one);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void gen_insert_field_i32(TCGv_i32 ret, TCGv_i32 src1,
|
static inline void gen_insfs(TCGv_i32 ret, TCGv_i32 src1,
|
||||||
TCGv_i32 src2, TCGv_i32 src3)
|
TCGv_i32 src2, TCGv_i32 src3)
|
||||||
{
|
{
|
||||||
TCGv_i32 one = tcg_const_i32(1);
|
TCGv_i32 one = tcg_const_i32(1);
|
||||||
|
@ -2922,7 +2922,7 @@ static inline void gen_alopf2_dx(Instr *instr,
|
||||||
gen_al_result_i80(instr, res.lo, res.hi, res.tag);
|
gen_al_result_i80(instr, res.lo, res.hi, res.tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Alop find_op(Instr *instr)
|
static AlopDesc *find_op(Instr *instr)
|
||||||
{
|
{
|
||||||
/* ALES2/5 may be allocated but must not be used */
|
/* ALES2/5 may be allocated but must not be used */
|
||||||
int opc2 = instr->ales_present & ALES_PRESENT ? instr->opc2 : 0;
|
int opc2 = instr->ales_present & ALES_PRESENT ? instr->opc2 : 0;
|
||||||
|
@ -2965,25 +2965,109 @@ static Alop find_op(Instr *instr)
|
||||||
case ALOPF16:
|
case ALOPF16:
|
||||||
is_match = desc->extra1 == instr->opce2;
|
is_match = desc->extra1 == instr->opce2;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_match) {
|
if (is_match) {
|
||||||
return desc->op;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
index = desc->next[instr->chan];
|
index = desc->next[instr->chan];
|
||||||
}
|
}
|
||||||
|
|
||||||
return OP_NONE;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void check_reg_src(DisasContext *ctx, uint8_t src)
|
||||||
|
{
|
||||||
|
if (IS_REGULAR(src)) {
|
||||||
|
ctx->max_r_src = MAX(ctx->max_r_src, GET_REGULAR(src));
|
||||||
|
} else if (IS_BASED(src)) {
|
||||||
|
ctx->max_b_cur = MAX(ctx->max_b_cur, GET_BASED(src));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void check_reg_dst(DisasContext *ctx, uint8_t dst)
|
||||||
|
{
|
||||||
|
if (IS_REGULAR(dst)) {
|
||||||
|
ctx->max_r_dst = MAX(ctx->max_r_dst, GET_REGULAR(dst));
|
||||||
|
} else if (IS_BASED(dst)) {
|
||||||
|
ctx->max_b_cur = MAX(ctx->max_b_cur, GET_BASED(dst));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_args(Alopf alopf, Instr *instr)
|
||||||
|
{
|
||||||
|
DisasContext *ctx = instr->ctx;
|
||||||
|
|
||||||
|
switch(alopf) {
|
||||||
|
case ALOPF1:
|
||||||
|
case ALOPF1_MERGE:
|
||||||
|
case ALOPF11:
|
||||||
|
case ALOPF11_MERGE:
|
||||||
|
case ALOPF11_LIT8:
|
||||||
|
check_reg_src(ctx, instr->src1);
|
||||||
|
check_reg_src(ctx, instr->src2);
|
||||||
|
check_reg_dst(ctx, instr->dst);
|
||||||
|
break;
|
||||||
|
case ALOPF2:
|
||||||
|
case ALOPF12:
|
||||||
|
case ALOPF12_PSHUFH:
|
||||||
|
case ALOPF15:
|
||||||
|
case ALOPF22:
|
||||||
|
check_reg_src(ctx, instr->src2);
|
||||||
|
check_reg_dst(ctx, instr->dst);
|
||||||
|
break;
|
||||||
|
case ALOPF3:
|
||||||
|
check_reg_src(ctx, instr->src1);
|
||||||
|
check_reg_src(ctx, instr->src2);
|
||||||
|
check_reg_src(ctx, instr->src4);
|
||||||
|
break;
|
||||||
|
case ALOPF7:
|
||||||
|
case ALOPF17:
|
||||||
|
check_reg_src(ctx, instr->src1);
|
||||||
|
check_reg_src(ctx, instr->src2);
|
||||||
|
break;
|
||||||
|
case ALOPF8:
|
||||||
|
check_reg_src(ctx, instr->src2);
|
||||||
|
break;
|
||||||
|
case ALOPF10:
|
||||||
|
check_reg_src(ctx, instr->src4);
|
||||||
|
break;
|
||||||
|
case ALOPF13:
|
||||||
|
// FIXME: not tested
|
||||||
|
e2k_todo(ctx, "check_args ALOPF13");
|
||||||
|
check_reg_src(ctx, instr->src1);
|
||||||
|
check_reg_src(ctx, instr->src2);
|
||||||
|
check_reg_src(ctx, instr->src4);
|
||||||
|
break;
|
||||||
|
case ALOPF16:
|
||||||
|
check_reg_dst(ctx, instr->dst);
|
||||||
|
break;
|
||||||
|
case ALOPF21:
|
||||||
|
check_reg_src(ctx, instr->src1);
|
||||||
|
check_reg_src(ctx, instr->src2);
|
||||||
|
check_reg_src(ctx, instr->src3);
|
||||||
|
check_reg_dst(ctx, instr->dst);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
e2k_todo(ctx, "check_args %d", alopf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gen_op(DisasContext *ctx, Instr *instr)
|
static void gen_op(DisasContext *ctx, Instr *instr)
|
||||||
{
|
{
|
||||||
int chan = instr->chan;
|
int chan = instr->chan;
|
||||||
Alop op = find_op(instr);
|
AlopDesc *desc = find_op(instr);
|
||||||
|
if (desc == NULL) {
|
||||||
switch(op) {
|
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
|
||||||
case OP_NONE: e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC); break;
|
return;
|
||||||
|
}
|
||||||
|
check_args(desc->alopf, instr);
|
||||||
|
switch(desc->op) {
|
||||||
case OP_ANDS: gen_alopf1_sss(instr, tcg_gen_and_i32); break;
|
case OP_ANDS: gen_alopf1_sss(instr, tcg_gen_and_i32); break;
|
||||||
case OP_ANDD: gen_alopf1_ddd(instr, tcg_gen_and_i64); break;
|
case OP_ANDD: gen_alopf1_ddd(instr, tcg_gen_and_i64); break;
|
||||||
case OP_ANDNS: gen_alopf1_sss(instr, gen_andn_i32); break;
|
case OP_ANDNS: gen_alopf1_sss(instr, gen_andn_i32); break;
|
||||||
|
@ -3809,7 +3893,7 @@ static void gen_op(DisasContext *ctx, Instr *instr)
|
||||||
case OP_QPFMSAS:
|
case OP_QPFMSAS:
|
||||||
case OP_QPFMASD:
|
case OP_QPFMASD:
|
||||||
case OP_QPFMSAD:
|
case OP_QPFMSAD:
|
||||||
e2k_todo_illop(ctx, "unimplemented %d\n", op); break;
|
e2k_todo_illop(ctx, "unimplemented %d\n", desc->op); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4245,18 +4329,21 @@ static void gen_icmb3(DisasContext *ctx, Instr *instr)
|
||||||
case 0x6c:
|
case 0x6c:
|
||||||
if (is_chan_0134(instr->chan) && ctx->version >= 4) {
|
if (is_chan_0134(instr->chan) && ctx->version >= 4) {
|
||||||
/* insfs */
|
/* insfs */
|
||||||
gen_alopf21_i32(ctx, instr, gen_insert_field_i32);
|
check_args(ALOPF21, instr);
|
||||||
|
gen_alopf21_i32(ctx, instr, gen_insfs);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x6d:
|
case 0x6d:
|
||||||
if (is_chan_0134(instr->chan) && ctx->version>= 4) {
|
if (is_chan_0134(instr->chan) && ctx->version>= 4) {
|
||||||
/* insfd */
|
/* insfd */
|
||||||
gen_alopf21_i64(ctx, instr, gen_insert_field_i64);
|
check_args(ALOPF21, instr);
|
||||||
|
gen_alopf21_i64(ctx, instr, gen_insfd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
check_args(ALOPF21, instr);
|
||||||
gen_icmb012(ctx, instr);
|
gen_icmb012(ctx, instr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4408,6 +4495,8 @@ gen_illopc:
|
||||||
|
|
||||||
static void gen_fcmb(DisasContext *ctx, Instr *instr)
|
static void gen_fcmb(DisasContext *ctx, Instr *instr)
|
||||||
{
|
{
|
||||||
|
check_args(ALOPF21, instr);
|
||||||
|
|
||||||
if (instr->opc1 & 1) {
|
if (instr->opc1 & 1) {
|
||||||
execute_fcomb_i64(ctx, instr);
|
execute_fcomb_i64(ctx, instr);
|
||||||
} else {
|
} else {
|
||||||
|
@ -4421,6 +4510,7 @@ static void gen_pfcmb1(DisasContext *ctx, Instr *instr)
|
||||||
case 0x4d:
|
case 0x4d:
|
||||||
if (is_chan_0134(instr->chan) && ctx->version >= 2) {
|
if (is_chan_0134(instr->chan) && ctx->version >= 2) {
|
||||||
/* pshufb */
|
/* pshufb */
|
||||||
|
check_args(ALOPF21, instr);
|
||||||
gen_alopf21_i64(ctx, instr, gen_helper_pshufb);
|
gen_alopf21_i64(ctx, instr, gen_helper_pshufb);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4443,6 +4533,7 @@ static void gen_lcmbd(DisasContext *ctx, Instr *instr, uint32_t base)
|
||||||
TCGv_i64 dst = e2k_get_temp_i64(ctx);
|
TCGv_i64 dst = e2k_get_temp_i64(ctx);
|
||||||
TCGv_i32 opc = tcg_const_i32(base + instr->opc1);
|
TCGv_i32 opc = tcg_const_i32(base + instr->opc1);
|
||||||
|
|
||||||
|
check_args(ALOPF21, instr);
|
||||||
gen_tag3_i64(tag, s1.tag, s2.tag, s3.tag);
|
gen_tag3_i64(tag, s1.tag, s2.tag, s3.tag);
|
||||||
gen_helper_plog(dst, opc, s1.value, s2.value, s3.value);
|
gen_helper_plog(dst, opc, s1.value, s2.value, s3.value);
|
||||||
gen_al_result_i64(instr, dst, tag);
|
gen_al_result_i64(instr, dst, tag);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
typedef enum {
|
typedef enum {
|
||||||
OP_NONE,
|
|
||||||
OP_ANDS,
|
OP_ANDS,
|
||||||
OP_ANDD,
|
OP_ANDD,
|
||||||
OP_ANDNS,
|
OP_ANDNS,
|
||||||
|
|
Loading…
Reference in New Issue