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

1797 lines
50 KiB
C

#include "qemu/osdep.h"
#include "qemu.h"
#include "exec/log.h"
#include "translate.h"
typedef struct {
TCGv_i32 tag;
TCGv_i64 value;
} Src64;
typedef struct {
TCGv_i32 tag;
TCGv_i32 value;
} Src32;
static inline void gen_reg_index(TCGv_i32 ret, uint8_t arg)
{
if (IS_BASED(arg)) {
e2k_gen_reg_index_from_bregi(ret, GET_BASED(arg));
} else if (IS_REGULAR(arg)) {
e2k_gen_reg_index_from_wregi(ret, GET_REGULAR(arg));
} else if (IS_GLOBAL(arg)) {
e2k_gen_reg_index_from_gregi(ret, GET_GLOBAL(arg));
} else {
e2k_gen_exception(E2K_EXCP_ILLOPN);
}
}
static inline void gen_reg_i64(DisasContext *ctx, Src64 *ret, uint8_t arg)
{
TCGv_i32 t0 = tcg_temp_new_i32();
gen_reg_index(t0, arg);
ret->tag = e2k_get_temp_i32(ctx);
ret->value = e2k_get_temp_i64(ctx);
e2k_gen_reg_tag_read_i64(ret->tag, t0);
e2k_gen_reg_read_i64(ret->value, t0);
tcg_temp_free_i32(t0);
}
static inline void gen_reg_i32(DisasContext *ctx, Src32 *ret, uint8_t arg)
{
TCGv_i32 t0 = tcg_temp_new_i32();
gen_reg_index(t0, arg);
ret->tag = e2k_get_temp_i32(ctx);
ret->value = e2k_get_temp_i32(ctx);
e2k_gen_reg_tag_read_i32(ret->tag, t0);
e2k_gen_reg_read_i32(ret->value, t0);
tcg_temp_free_i32(t0);
}
static inline void gen_literal_i64(DisasContext *ctx, Src64 *ret, uint8_t arg)
{
int i = GET_LIT(arg);
uint64_t lit = ctx->bundle.lts[i];
if (!ctx->bundle.lts_present[i]) {
e2k_gen_exception(E2K_EXCP_ILLOPN);
} else if (IS_LIT16_LO(arg) && i < 2) {
lit = ((int64_t) lit << 48) >> 48;
} else if (IS_LIT16_HI(arg) && i < 2) {
lit = ((int64_t) lit << 32) >> 48;
} else if (IS_LIT32(arg)) {
lit = ((int64_t) lit << 32) >> 32;
} else if (IS_LIT64(arg) && i < 3) {
if (!ctx->bundle.lts_present[i + 1]) {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
}
lit |= (uint64_t) ctx->bundle.lts[i + 1] << 32;
} else {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
}
ret->value = e2k_get_const_i64(ctx, lit);
}
static inline void gen_literal_i32(DisasContext *ctx, Src32 *ret, uint8_t arg)
{
int i = GET_LIT(arg);
int32_t lit = ctx->bundle.lts[i];
if (!ctx->bundle.lts_present[i]) {
e2k_gen_exception(E2K_EXCP_ILLOPN);
} else if (IS_LIT16_LO(arg) && i < 2) {
lit = (lit << 16) >> 16;
} else if (IS_LIT16_HI(arg) && i < 2) {
lit = lit >> 16;
} else if (IS_LIT32(arg)) {
// nop
} else if (IS_LIT64(arg) && i < 3) {
// FIXME: check CPU behavior in such situation
if (!ctx->bundle.lts_present[i + 1]) {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
}
} else {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
}
ret->value = e2k_get_const_i32(ctx, lit);
}
static inline Src64 get_src1_i64(DisasContext *ctx, int chan)
{
uint8_t arg = extract32(ctx->bundle.als[chan], 16, 8);
Src64 ret = { 0 };
if (IS_IMM5(arg)) {
ret.value = e2k_get_const_i64(ctx, GET_IMM5(arg));
} else {
gen_reg_i64(ctx, &ret, arg);
}
return ret;
}
static inline Src32 get_src1_i32(DisasContext *ctx, int chan)
{
uint8_t arg = extract32(ctx->bundle.als[chan], 16, 8);
Src32 ret = { 0 };
if (IS_IMM5(arg)) {
ret.value = e2k_get_const_i32(ctx, GET_IMM5(arg));
} else {
gen_reg_i32(ctx, &ret, arg);
}
return ret;
}
static inline Src64 get_src2_i64(DisasContext *ctx, int chan)
{
uint8_t arg = extract32(ctx->bundle.als[chan], 8, 8);
Src64 ret = { 0 };
if (IS_IMM4(arg)) {
ret.value = e2k_get_const_i64(ctx, GET_IMM4(arg));
} else if (IS_LIT(arg)) {
gen_literal_i64(ctx, &ret, arg);
} else {
gen_reg_i64(ctx, &ret, arg);
}
return ret;
}
static inline Src32 get_src2_i32(DisasContext *ctx, int chan)
{
uint8_t arg = extract32(ctx->bundle.als[chan], 8, 8);
Src32 ret = { 0 };
if (IS_IMM4(arg)) {
ret.tag = NULL;
ret.value = e2k_get_const_i32(ctx, GET_IMM4(arg));
} else if (IS_LIT(arg)) {
gen_literal_i32(ctx, &ret, arg);
} else {
gen_reg_i32(ctx, &ret, arg);
}
return ret;
}
static inline Src64 get_src3_i64(DisasContext *ctx, int chan)
{
uint8_t arg = extract32(ctx->bundle.ales[chan], 0, 8);
Src64 ret = { 0 };
gen_reg_i64(ctx, &ret, arg);
return ret;
}
static inline Src32 get_src3_i32(DisasContext *ctx, int chan)
{
uint8_t arg = extract32(ctx->bundle.ales[chan], 0, 8);
Src32 ret = { 0 };
gen_reg_i32(ctx, &ret, arg);
return ret;
}
static inline Src64 get_src4_i64(DisasContext *ctx, int chan)
{
uint8_t arg = extract32(ctx->bundle.als[chan], 0, 8);
Src64 ret = { 0 };
gen_reg_i64(ctx, &ret, arg);
return ret;
}
static inline Src32 get_src4_i32(DisasContext *ctx, int chan)
{
uint8_t arg = extract32(ctx->bundle.als[chan], 0, 8);
Src32 ret = { 0 };
gen_reg_i32(ctx, &ret, arg);
return ret;
}
static inline void set_al_result_reg64_tag(DisasContext *ctx, int chan,
TCGv_i64 value, TCGv_i32 tag)
{
uint8_t arg = extract32(ctx->bundle.als[chan], 0, 8);
AlResult *res = &ctx->al_results[chan];
// TODO: %tst, %tc, %tcd
if (arg == 0xdf) { /* %empty */
res->type = AL_RESULT_NONE;
res->reg.index = NULL;
res->reg.v64 = NULL;
res->reg.tag = NULL;
} else if ((arg & 0xfc) == 0xd0 && (arg & 3) != 0) {
// TODO: check if instruction can write to ctpr
res->type = AL_RESULT_CTPR64;
res->ctpr64.index = (arg & 3) - 1;
res->ctpr64.value = value;
} else {
res->type = AL_RESULT_REG64;
res->reg.v64 = value;
res->reg.tag = tag;
res->reg.index = e2k_get_temp_i32(ctx);
gen_reg_index(res->reg.index, arg);
}
}
static inline void set_al_result_reg64(DisasContext *ctx, int chan,
TCGv_i64 value)
{
set_al_result_reg64_tag(ctx, chan, value, e2k_get_const_i32(ctx, 0));
}
static inline void set_al_result_reg32_tag(DisasContext *ctx, int chan,
TCGv_i32 value, TCGv_i32 tag)
{
uint8_t arg = extract32(ctx->bundle.als[chan], 0, 8);
AlResult *res = &ctx->al_results[chan];
// TODO: %tst, %tc, %tcd
if (arg == 0xdf) { /* %empty */
res->type = AL_RESULT_NONE;
res->reg.index = NULL;
res->reg.v32 = NULL;
res->reg.tag = NULL;
} else if ((arg & 0xfc) == 0xd0 && (arg & 3) != 0) {
// TODO: check if instruction can write to ctpr
res->type = AL_RESULT_CTPR32;
res->ctpr32.index = (arg & 3) - 1;
res->ctpr32.value = value;
} else {
res->type = AL_RESULT_REG32;
res->reg.v32 = value;
res->reg.tag = tag;
res->reg.index = e2k_get_temp_i32(ctx);
gen_reg_index(res->reg.index, arg);
}
}
static inline void set_al_result_reg32(DisasContext *ctx, int chan,
TCGv_i32 value)
{
set_al_result_reg32_tag(ctx, chan, value, e2k_get_const_i32(ctx, 0));
}
static inline void set_al_result_preg(DisasContext *ctx, int chan, int index,
TCGv_i64 value)
{
AlResult *res = &ctx->al_results[chan];
res->type = AL_RESULT_PREG;
res->preg.index = index;
res->preg.value = value;
}
static void gen_tag_check_i64(bool sm, TCGv_i64 dst, TCGv_i32 dst_tag,
TCGv_i32 src_tag, TCGLabel *l)
{
if (src_tag != NULL) {
TCGLabel *l0 = gen_new_label();
TCGv_i32 t0 = tcg_temp_new_i32();
e2k_gen_reg_tag_check_i64(t0, src_tag);
tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l0);
if (sm) {
if (dst_tag != NULL) {
tcg_gen_movi_i32(dst_tag, 5);
}
if (dst != NULL) {
tcg_gen_ori_i64(dst, dst, (1UL << 62) | (1UL << 30));
}
} else {
e2k_gen_exception(E2K_EXCP_ILLOPN);
}
if (l != NULL) {
tcg_gen_br(l);
}
gen_set_label(l0);
tcg_temp_free_i32(t0);
}
}
static void gen_tag_check_i32(bool sm, TCGv_i32 dst, TCGv_i32 dst_tag,
TCGv_i32 tag, TCGLabel *l)
{
if (tag != NULL) {
TCGLabel *l0 = gen_new_label();
TCGv_i32 t0 = tcg_temp_new_i32();
e2k_gen_reg_tag_check_i32(t0, tag);
tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l0);
if (sm) {
if (dst_tag != NULL) {
tcg_gen_movi_i32(dst_tag, 1);
}
if (dst != NULL) {
tcg_gen_ori_i32(dst, dst, 1 << 30);
}
} else {
e2k_gen_exception(E2K_EXCP_ILLOPN);
}
if (l != NULL) {
tcg_gen_br(l);
}
gen_set_label(l0);
tcg_temp_free_i32(t0);
}
}
static inline void gen_andn_i32(TCGv_i32 ret, TCGv_i32 src1, TCGv_i32 src2)
{
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_not_i32(t0, src2);
tcg_gen_and_i32(ret, src1, t0);
tcg_temp_free_i32(t0);
}
static inline void gen_andn_i64(TCGv_i64 ret, TCGv_i64 src1, TCGv_i64 src2)
{
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_not_i64(t0, src2);
tcg_gen_and_i64(ret, src1, t0);
tcg_temp_free_i64(t0);
}
static inline void gen_orn_i32(TCGv_i32 ret, TCGv_i32 src1, TCGv_i32 src2)
{
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_not_i32(t0, src2);
tcg_gen_or_i32(ret, src1, t0);
tcg_temp_free_i32(t0);
}
static inline void gen_orn_i64(TCGv_i64 ret, TCGv_i64 src1, TCGv_i64 src2)
{
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_not_i64(t0, src2);
tcg_gen_or_i64(ret, src1, t0);
tcg_temp_free_i64(t0);
}
static inline void gen_xorn_i32(TCGv_i32 ret, TCGv_i32 src1, TCGv_i32 src2)
{
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_not_i32(t0, src2);
tcg_gen_xor_i32(ret, src1, t0);
tcg_temp_free_i32(t0);
}
static inline void gen_xorn_i64(TCGv_i64 ret, TCGv_i64 src1, TCGv_i64 src2)
{
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_not_i64(t0, src2);
tcg_gen_xor_i64(ret, src1, t0);
tcg_temp_free_i64(t0);
}
static inline void gen_getfield_i32(TCGv_i32 ret, TCGv_i32 src1,
TCGv_i32 shift, TCGv_i32 size, TCGv_i32 sign)
{
TCGv_i32 n32 = tcg_const_i32(32);
TCGv_i32 n1 = tcg_const_i32(1);
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_temp_new_i32();
TCGv_i32 t3 = tcg_temp_new_i32();
TCGv_i32 t4 = tcg_temp_new_i32();
TCGv_i32 t5 = tcg_temp_new_i32();
tcg_gen_add_i32(t0, shift, size);
tcg_gen_sub_i32(t1, n32, t0);
tcg_gen_add_i32(t2, shift, t1);
tcg_gen_shl_i32(t3, src1, t1);
tcg_gen_shr_i32(t4, t3, t2);
tcg_gen_sar_i32(t5, t3, t2);
tcg_gen_movcond_i32(TCG_COND_NE, ret, sign, n1, t4, t5);
tcg_temp_free_i32(t5);
tcg_temp_free_i32(t4);
tcg_temp_free_i32(t3);
tcg_temp_free_i32(t2);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
tcg_temp_free_i32(n1);
tcg_temp_free_i32(n32);
}
static inline void gen_getfield_i64(TCGv_i64 ret, TCGv_i64 src1,
TCGv_i64 shift, TCGv_i64 size, TCGv_i64 sign)
{
TCGv_i64 n64 = tcg_const_i64(64);
TCGv_i64 n1 = tcg_const_i64(1);
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv_i64 t2 = tcg_temp_new_i64();
TCGv_i64 t3 = tcg_temp_new_i64();
TCGv_i64 t4 = tcg_temp_new_i64();
TCGv_i64 t5 = tcg_temp_new_i64();
tcg_gen_add_i64(t0, shift, size);
tcg_gen_sub_i64(t1, n64, t0);
tcg_gen_add_i64(t2, shift, t1);
tcg_gen_shl_i64(t3, src1, t1);
tcg_gen_shr_i64(t4, t3, t2);
tcg_gen_sar_i64(t5, t3, t2);
tcg_gen_movcond_i64(TCG_COND_NE, ret, sign, n1, t4, t5);
tcg_temp_free_i64(t5);
tcg_temp_free_i64(t4);
tcg_temp_free_i64(t3);
tcg_temp_free_i64(t2);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t0);
tcg_temp_free_i64(n1);
tcg_temp_free_i64(n64);
}
static inline void gen_getfs(TCGv_i32 ret, TCGv_i32 src1, TCGv_i32 src2)
{
TCGv_i32 shift = tcg_temp_new_i32();
TCGv_i32 size = tcg_temp_new_i32();
TCGv_i32 sign = tcg_temp_new_i32();
tcg_gen_extract_i32(shift, src2, 0, 5);
tcg_gen_extract_i32(size, src2, 6, 5);
tcg_gen_extract_i32(sign, src2, 12, 1);
gen_getfield_i32(ret, src1, shift, size, sign);
tcg_temp_free_i32(sign);
tcg_temp_free_i32(size);
tcg_temp_free_i32(shift);
}
static inline void gen_getfd(TCGv_i64 ret, TCGv_i64 src1, TCGv_i64 src2)
{
TCGv_i64 shift = tcg_temp_new_i64();
TCGv_i64 size = tcg_temp_new_i64();
TCGv_i64 sign = tcg_temp_new_i64();
tcg_gen_extract_i64(shift, src2, 0, 6);
tcg_gen_extract_i64(size, src2, 6, 6);
tcg_gen_extract_i64(sign, src2, 12, 1);
gen_getfield_i64(ret, src1, shift, size, sign);
tcg_temp_free_i64(sign);
tcg_temp_free_i64(size);
tcg_temp_free_i64(shift);
}
static TCGCond e2k_gen_cmp_op(unsigned int cmp_op)
{
switch(cmp_op) {
case 0: abort(); break;
case 1: return TCG_COND_LTU; break;
case 2: return TCG_COND_EQ; break;
case 3: return TCG_COND_LEU; break;
case 4: abort(); break;
case 5: abort(); break;
case 6: return TCG_COND_LT; break;
case 7: return TCG_COND_LE; break;
default: g_assert_not_reached(); break;
}
return TCG_COND_NEVER; /* unreachable */
}
static inline void gen_cmp_i32(TCGv_i32 ret, int opc,
TCGv_i32 src1, TCGv_i32 src2)
{
TCGCond cond = e2k_gen_cmp_op(opc);
tcg_gen_setcond_i32(cond, ret, src1, src2);
}
static inline void gen_cmp_i64(TCGv_i64 ret, int opc, TCGv_i64 src1,
TCGv_i64 src2)
{
TCGCond cond = e2k_gen_cmp_op(opc);
tcg_gen_setcond_i64(cond, ret, src1, src2);
}
static inline void gen_cmpand_i64(TCGv_i64 ret, int opc, TCGv_i64 src1,
TCGv_i64 src2)
{
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_and_i64(t0, src1, src2);
switch (opc) {
case 2: /* is zero */
tcg_gen_setcondi_i64(TCG_COND_EQ, ret, t0, 0);
break;
case 4: /* is negative */
tcg_gen_setcondi_i64(TCG_COND_LT, ret, t0, 0);
break;
case 5: { /* is odd and greater than 3 */
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv_i64 t2 = tcg_temp_new_i64();
TCGv_i64 t3 = tcg_temp_new_i64();
tcg_gen_andi_i64(t1, t0, 1);
tcg_gen_setcondi_i64(TCG_COND_NE, t2, t1, 0);
tcg_gen_setcondi_i64(TCG_COND_GTU, t3, t0, 2);
tcg_gen_setcond_i64(TCG_COND_EQ, ret, t2, t3);
tcg_temp_free_i64(t3);
tcg_temp_free_i64(t2);
tcg_temp_free_i64(t1);
break;
}
case 7: /* signed less or equal 0 */
tcg_gen_setcondi_i64(TCG_COND_LE, ret, t0, 0);
break;
default:
e2k_gen_exception(E2K_EXCP_ILLOPC);
break;
}
tcg_temp_free_i64(t0);
}
static inline void gen_cmpand_i32(TCGv_i32 ret, int opc, TCGv_i32 src1,
TCGv_i32 src2)
{
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_and_i32(t0, src1, src2);
switch (opc) {
case 2: /* is zero */
tcg_gen_setcondi_i32(TCG_COND_EQ, ret, t0, 0);
break;
case 4: /* is negative */
tcg_gen_setcondi_i32(TCG_COND_LT, ret, t0, 0);
break;
case 5: { /* is odd and greater than 3 */
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_temp_new_i32();
TCGv_i32 t3 = tcg_temp_new_i32();
tcg_gen_andi_i32(t1, t0, 1);
tcg_gen_setcondi_i32(TCG_COND_NE, t2, t1, 0);
tcg_gen_setcondi_i32(TCG_COND_GTU, t3, t0, 2);
tcg_gen_setcond_i32(TCG_COND_EQ, ret, t2, t3);
tcg_temp_free_i32(t3);
tcg_temp_free_i32(t2);
tcg_temp_free_i32(t1);
break;
}
case 7: /* signed less or equal 0 */
tcg_gen_setcondi_i32(TCG_COND_LE, ret, t0, 0);
break;
default:
e2k_gen_exception(E2K_EXCP_ILLOPC);
break;
}
tcg_temp_free_i32(t0);
}
/*
* ret[31:0] = x[31:0]
* ret[63:32] = y[63:32]
*/
static inline void gen_movehl_i64(TCGv_i64 ret, TCGv_i64 x, TCGv_i64 y)
{
TCGv_i32 lo = tcg_temp_new_i32();
TCGv_i32 hi = tcg_temp_new_i32();
tcg_gen_extrl_i64_i32(lo, x);
tcg_gen_extrh_i64_i32(hi, y);
tcg_gen_concat_i32_i64(ret, lo, hi);
tcg_temp_free_i32(hi);
tcg_temp_free_i32(lo);
}
static inline void gen_merge_i32(TCGv_i32 ret, TCGv_i32 x, TCGv_i32 y, TCGv_i32 cond)
{
TCGv_i32 zero = tcg_const_i32(0);
tcg_gen_movcond_i32(TCG_COND_EQ, ret, cond, zero, x, y);
tcg_temp_free_i32(zero);
}
static inline void gen_merge_i64(TCGv_i64 ret, TCGv_i64 x, TCGv_i64 y, TCGv_i64 cond)
{
TCGv_i64 zero = tcg_const_i64(0);
tcg_gen_movcond_i64(TCG_COND_EQ, ret, cond, zero, x, y);
tcg_temp_free_i64(zero);
}
static inline bool is_mrgc(uint16_t rlp, int chan)
{
int is_mrgc = GET_BIT(rlp, 15);
int cluster = GET_BIT(rlp, 14);
int alc_mask = GET_FIELD(rlp, 10, 3);
int alc = GET_BIT(alc_mask, chan % 3);
return is_mrgc && (cluster == (chan > 2)) && (alc != 0);
}
static uint16_t find_mrgc(DisasContext *dc, int chan)
{
unsigned int i;
for (i = 0; dc->bundle.cds_present[i]; i++) {
uint32_t cds = dc->bundle.cds[i];
uint16_t rlp0 = cds >> 16;
uint16_t rlp1 = cds & 0xffff;
if (is_mrgc(rlp0, chan)) {
return rlp0;
}
if (is_mrgc(rlp1, chan)) {
return rlp1;
}
}
return 0;
}
static inline bool is_cond(uint16_t rlp, int chan)
{
int is_mrgc = GET_BIT(rlp, 15);
int cluster = GET_BIT(rlp, 14);
int alc_mask = GET_FIELD(rlp, 10, 3);
int alc = GET_BIT(alc_mask, chan % 3);
return !is_mrgc && (cluster == (chan > 2)) && (alc != 0);
}
static uint16_t find_cond(DisasContext *ctx, int chan)
{
unsigned int i;
for (i = 0; ctx->bundle.cds_present[i]; i++) {
uint32_t cds = ctx->bundle.cds[i];
uint16_t rlp0 = cds >> 16;
uint16_t rlp1 = cds & 0xffff;
if (is_cond(rlp0, chan)) {
return rlp0;
}
if (is_cond(rlp1, chan)) {
return rlp1;
}
}
return 0;
}
static inline void gen_mrgc_i64(DisasContext *ctx, int chan, TCGv_i64 ret)
{
uint16_t rlp = find_mrgc(ctx, chan);
TCGv_i64 t0 = tcg_temp_new_i64();
e2k_gen_cond_i64(ctx, t0, rlp & 0x7f);
tcg_gen_xori_i64(ret, t0, GET_BIT(rlp, 7 + chan % 3));
tcg_temp_free_i64(t0);
}
static inline void gen_mrgc_i32(DisasContext *dc, int chan, TCGv_i32 ret)
{
TCGv_i64 t0 = tcg_temp_new_i64();
gen_mrgc_i64(dc, chan, t0);
tcg_gen_extrl_i64_i32(ret, t0);
tcg_temp_free(t0);
}
static inline void gen_udivd(TCGv_i64 ret, TCGv_i32 ret_tag, bool sm,
TCGv_i64 src1, TCGv_i64 src2)
{
TCGLabel *l0 = gen_new_label();
if (sm) {
TCGLabel *l1 = gen_new_label();
tcg_gen_brcondi_i64(TCG_COND_NE, src2, 0, l1);
tcg_gen_movi_i32(ret_tag, 5);
tcg_gen_movi_i64(ret, 0);
tcg_gen_br(l0);
gen_set_label(l1);
}
tcg_gen_movi_i32(ret_tag, 0);
tcg_gen_divu_i64(ret, src1, src2);
gen_set_label(l0);
}
static inline void gen_udivs(TCGv_i32 ret, TCGv_i32 ret_tag, bool sm,
TCGv_i32 src1, TCGv_i32 src2)
{
TCGLabel *l0 = gen_new_label();
if (sm) {
TCGLabel *l1 = gen_new_label();
tcg_gen_brcondi_i32(TCG_COND_NE, src2, 0, l1);
tcg_gen_movi_i32(ret_tag, 5);
tcg_gen_movi_i32(ret, 0);
tcg_gen_br(l0);
gen_set_label(l1);
}
tcg_gen_movi_i32(ret_tag, 0);
tcg_gen_divu_i32(ret, src1, src2);
gen_set_label(l0);
}
static inline void gen_sdivd(TCGv_i64 ret, TCGv_i32 ret_tag, bool sm,
TCGv_i64 src1, TCGv_i64 src2)
{
TCGLabel *l0 = gen_new_label();
if (sm) {
TCGLabel *l1 = gen_new_label();
tcg_gen_brcondi_i64(TCG_COND_NE, src2, 0, l1);
tcg_gen_movi_i32(ret_tag, 5);
tcg_gen_movi_i64(ret, 0);
tcg_gen_br(l0);
gen_set_label(l1);
}
tcg_gen_movi_i32(ret_tag, 0);
tcg_gen_div_i64(ret, src1, src2);
gen_set_label(l0);
}
static inline void gen_sdivs(TCGv_i32 ret, TCGv_i32 ret_tag, bool sm,
TCGv_i32 src1, TCGv_i32 src2)
{
TCGLabel *l0 = gen_new_label();
if (sm) {
TCGLabel *l1 = gen_new_label();
tcg_gen_brcondi_i32(TCG_COND_NE, src2, 0, l1);
tcg_gen_movi_i32(ret_tag, 5);
tcg_gen_movi_i32(ret, 0);
tcg_gen_br(l0);
gen_set_label(l1);
}
tcg_gen_movi_i32(ret_tag, 0);
tcg_gen_div_i32(ret, src1, src2);
gen_set_label(l0);
}
static inline void gen_gettag_i64(DisasContext *ctx, int chan)
{
Src64 s2 = get_src2_i64(ctx, chan);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
if (s2.tag != NULL) {
tcg_gen_extu_i32_i64(dst, s2.tag);
} else {
tcg_gen_movi_i64(dst, 0);
}
set_al_result_reg64(ctx, chan, dst);
}
static inline void gen_gettag_i32(DisasContext *ctx, int chan)
{
Src32 s2 = get_src2_i32(ctx, chan);
TCGv_i32 dst = e2k_get_temp_i32(ctx);
if (s2.tag != NULL) {
tcg_gen_mov_i32(dst, s2.tag);
} else {
tcg_gen_movi_i32(dst, 0);
}
set_al_result_reg32(ctx, chan, dst);
}
static inline void gen_puttag_i64(DisasContext *ctx, int chan)
{
bool sm = extract32(ctx->bundle.als[chan], 31, 1);
TCGLabel *l0 = gen_new_label();
TCGLabel *l1 = gen_new_label();
Src64 s1 = get_src1_i64(ctx, chan);
Src32 s2 = get_src2_i32(ctx, chan);
TCGv_i32 tag = e2k_get_temp_i32(ctx);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
tcg_gen_movi_i32(tag, 0);
tcg_gen_mov_i64(dst, s1.value);
tcg_gen_brcondi_i32(TCG_COND_EQ, s2.value, 0, l0);
gen_tag_check_i64(sm, dst, tag, s1.tag, l1);
gen_tag_check_i64(sm, dst, tag, s2.tag, l1);
gen_set_label(l0);
tcg_gen_mov_i32(tag, s2.value);
gen_set_label(l1);
set_al_result_reg64_tag(ctx, chan, dst, tag);
}
static inline void gen_puttag_i32(DisasContext *ctx, int chan)
{
bool sm = extract32(ctx->bundle.als[chan], 31, 1);
TCGLabel *l0 = gen_new_label();
TCGLabel *l1 = gen_new_label();
Src32 s1 = get_src1_i32(ctx, chan);
Src32 s2 = get_src2_i32(ctx, chan);
TCGv_i32 tag = e2k_get_temp_i32(ctx);
TCGv_i32 dst = e2k_get_temp_i32(ctx);
tcg_gen_movi_i32(tag, 0);
tcg_gen_mov_i32(dst, s1.value);
tcg_gen_brcondi_i32(TCG_COND_EQ, s2.value, 0, l0);
gen_tag_check_i32(sm, dst, tag, s1.tag, l1);
gen_tag_check_i32(sm, dst, tag, s2.tag, l1);
gen_set_label(l0);
tcg_gen_mov_i32(tag, s2.value);
gen_set_label(l1);
set_al_result_reg32_tag(ctx, chan, dst, tag);
}
static inline void gen_insert_field_i64(TCGv_i64 ret, TCGv_i64 src1,
TCGv_i64 src2, TCGv_i64 src3)
{
TCGv_i64 one = tcg_const_i64(1);
TCGv_i64 offset = tcg_temp_new_i64();
TCGv_i64 len = tcg_temp_new_i64();
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv_i64 t2 = tcg_temp_new_i64();
TCGv_i64 t3 = tcg_temp_new_i64();
TCGv_i64 t4 = tcg_temp_new_i64();
TCGv_i64 t5 = tcg_temp_new_i64();
tcg_gen_extract_i64(offset, src2, 0, 6);
tcg_gen_extract_i64(len, src2, 6, 6);
tcg_gen_shl_i64(t0, one, len);
tcg_gen_subi_i64(t1, t0, 1);
tcg_gen_rotr_i64(t2, src1, offset);
tcg_gen_not_i64(t3, t1);
tcg_gen_and_i64(t4, t2, t3);
tcg_gen_and_i64(t5, src3, t1);
tcg_gen_or_i64(ret, t4, t5);
tcg_temp_free_i64(t5);
tcg_temp_free_i64(t4);
tcg_temp_free_i64(t3);
tcg_temp_free_i64(t2);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t0);
tcg_temp_free_i64(len);
tcg_temp_free_i64(offset);
tcg_temp_free_i64(one);
}
static inline void gen_insert_field_i32(TCGv_i32 ret, TCGv_i32 src1,
TCGv_i32 src2, TCGv_i32 src3)
{
TCGv_i32 one = tcg_const_i32(1);
TCGv_i32 offset = tcg_temp_new_i32();
TCGv_i32 len = tcg_temp_new_i32();
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_temp_new_i32();
TCGv_i32 t3 = tcg_temp_new_i32();
TCGv_i32 t4 = tcg_temp_new_i32();
TCGv_i32 t5 = tcg_temp_new_i32();
tcg_gen_extract_i32(offset, src2, 0, 6);
tcg_gen_extract_i32(len, src2, 6, 6);
tcg_gen_shl_i32(t0, one, len);
tcg_gen_subi_i32(t1, t0, 1);
tcg_gen_rotr_i32(t2, src1, offset);
tcg_gen_not_i32(t3, t1);
tcg_gen_and_i32(t4, t2, t3);
tcg_gen_and_i32(t5, src3, t1);
tcg_gen_or_i32(ret, t4, t5);
tcg_temp_free_i32(t5);
tcg_temp_free_i32(t4);
tcg_temp_free_i32(t3);
tcg_temp_free_i32(t2);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
tcg_temp_free_i32(len);
tcg_temp_free_i32(offset);
tcg_temp_free_i32(one);
}
static inline void gen_rr_i64(DisasContext *ctx, int chan)
{
uint32_t als = ctx->bundle.als[chan];
uint8_t state_reg = extract32(als, 16, 8);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
TCGv_i32 t0 = tcg_const_i32(state_reg);
gen_helper_state_reg_read_i64(dst, cpu_env, t0);
set_al_result_reg64(ctx, chan, dst);
tcg_temp_free_i32(t0);
}
static inline void gen_rr_i32(DisasContext *ctx, int chan)
{
uint32_t als = ctx->bundle.als[chan];
uint8_t state_reg = extract32(als, 16, 8);
TCGv_i32 dst = e2k_get_temp_i32(ctx);
TCGv_i32 t0 = tcg_const_i32(state_reg);
gen_helper_state_reg_read_i32(dst, cpu_env, t0);
set_al_result_reg32(ctx, chan, dst);
tcg_temp_free_i32(t0);
}
static inline void gen_rw_i64(DisasContext *ctx, int chan)
{
uint32_t als = ctx->bundle.als[chan];
Src64 s2 = get_src2_i64(ctx, chan);
TCGv_i32 t0;
gen_tag_check_i64(false, NULL, NULL, s2.tag, NULL);
t0 = tcg_const_i32(als & 0xff);
gen_helper_state_reg_write_i64(cpu_env, t0, s2.value);
tcg_temp_free_i32(t0);
}
static inline void gen_rw_i32(DisasContext *ctx, int chan)
{
uint32_t als = ctx->bundle.als[chan];
Src32 s2 = get_src2_i32(ctx, chan);
TCGv_i32 t0;
gen_tag_check_i32(false, NULL, NULL, s2.tag, NULL);
t0 = tcg_const_i32(als & 0xff);
gen_helper_state_reg_write_i32(cpu_env, t0, s2.value);
tcg_temp_free_i32(t0);
}
static void gen_getsp(DisasContext *ctx, int chan)
{
Src64 s2 = get_src2_i64(ctx, chan);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
// TODO: check tags
gen_helper_getsp(dst, cpu_env, s2.value);
set_al_result_reg64(ctx, chan, dst);
}
static void gen_movtd(DisasContext *ctx, int chan)
{
Src64 s2 = get_src2_i64(ctx, chan);
set_al_result_reg64_tag(ctx, chan, s2.value, s2.tag);
}
static MemOp gen_mas(DisasContext *ctx, int chan, MemOp memop, TCGv_i64 addr)
{
uint8_t mas = ctx->mas[chan];
if ((mas & 0x7) == 7) {
// TODO: special mas
// e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
qemu_log_mask(LOG_UNIMP, "0x%lx: mas=0x%x is not implemented!\n",
ctx->pc, mas);
} else if (mas) {
int mod = extract8(mas, 0, 3);
// int dc = extract8(mas, 5, 2);
if (mod != 0) {
// TODO: mas modes
// e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
qemu_log_mask(LOG_UNIMP, "0x%lx: mas=0x%x is not implemented!\n",
ctx->pc, mas);
}
memop |= GET_BIT(mas, 3) ? MO_BE : MO_LE;
memop |= GET_BIT(mas, 4) ? MO_UNALN : MO_ALIGN;
} else {
memop |= MO_LE | MO_ALIGN;
}
return memop;
}
static void gen_ld(DisasContext *ctx, int chan, MemOp memop)
{
bool sm = GET_BIT(ctx->bundle.als[chan], 31);
TCGLabel *l0 = gen_new_label();
TCGLabel *l1 = gen_new_label();
Src64 s1 = get_src1_i64(ctx, chan);
Src64 s2 = get_src2_i64(ctx, chan);
TCGv_i64 t0 = tcg_temp_local_new_i64();
TCGv_i32 tag = e2k_get_temp_i32(ctx);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
tcg_gen_movi_i64(dst, 0);
gen_tag_check_i64(sm, dst, tag, s1.tag, l1);
gen_tag_check_i64(sm, dst, tag, s2.tag, l1);
tcg_gen_add_i64(t0, s1.value, s2.value);
memop = gen_mas(ctx, chan, memop, t0);
if (sm) {
TCGv_i32 t1 = tcg_temp_new_i32();
gen_helper_probe_read_access(t1, cpu_env, t0);
tcg_gen_brcondi_i32(TCG_COND_EQ, t1, 1, l0);
tcg_temp_free_i32(t1);
tcg_gen_movi_i32(tag, 5);
tcg_gen_movi_i64(dst, 0x4afafafa4afafafa);
tcg_gen_br(l1);
}
gen_set_label(l0);
tcg_gen_movi_i32(tag, 0);
tcg_gen_qemu_ld_i64(dst, t0, ctx->mmuidx, memop);
gen_set_label(l1);
set_al_result_reg64_tag(ctx, chan, dst, tag);
tcg_temp_free_i64(t0);
}
static void gen_staa_i64(DisasContext *ctx, int chan)
{
uint32_t als = ctx->bundle.als[chan];
uint8_t mas = ctx->mas[chan];
bool sm = extract32(als, 31, 1);
int lit = extract32(als, 8, 2);
int am = extract32(als, 10, 1);
int incr = extract32(als, 12, 3);
int ind = extract32(als, 15, 4);
int d = extract32(als, 19, 5);
Src64 s4 = get_src4_i64(ctx, chan);
TCGv_i32 t0 = tcg_const_i32(am);
TCGv_i32 t1 = tcg_const_i32(incr);
TCGv_i32 t2 = tcg_const_i32(ind);
TCGv_i32 t3 = tcg_const_i32(d);
TCGv_i32 t4;
if (lit) {
if (!ctx->bundle.lts_present[lit - 1]) {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
return;
}
t4 = tcg_const_i32(ctx->bundle.lts[lit - 1]);
} else {
t4 = tcg_const_i32(0);
}
if (sm) {
qemu_log_mask(LOG_UNIMP, "staad: sm is not implemented\n");
abort();
}
if (mas == 0) {
gen_helper_staa_i64(cpu_env, s4.value, t4, t0, t1, t2, t3);
} else if (mas == 0x3f) {
if (!am) {
gen_helper_set_aad_i64(cpu_env, s4.value, t1, t3);
} else {
gen_helper_set_aasti_i64(cpu_env, s4.value, t2);
}
} else {
qemu_log_mask(LOG_UNIMP, "staad: not implemented mas\n");
abort();
}
tcg_temp_free_i32(t4);
tcg_temp_free_i32(t3);
tcg_temp_free_i32(t2);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
static void gen_staa_i32(DisasContext *ctx, int chan)
{
uint32_t als = ctx->bundle.als[chan];
uint8_t mas = ctx->mas[chan];
bool sm = extract32(als, 31, 1);
int lit = extract32(als, 8, 2);
int am = extract32(als, 10, 1);
int incr = extract32(als, 12, 3);
int ind = extract32(als, 15, 4);
int d = extract32(als, 19, 5);
Src32 s4 = get_src4_i32(ctx, chan);
TCGv_i32 t0 = tcg_const_i32(am);
TCGv_i32 t1 = tcg_const_i32(incr);
TCGv_i32 t2 = tcg_const_i32(ind);
TCGv_i32 t3 = tcg_const_i32(d);
TCGv_i32 t4;
if (lit) {
if (!ctx->bundle.lts_present[lit - 1]) {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
return;
}
t4 = tcg_const_i32(ctx->bundle.lts[lit - 1]);
} else {
t4 = tcg_const_i32(0);
}
if (sm) {
qemu_log_mask(LOG_UNIMP, "staaw: sm is not implemented\n");
abort();
}
if (mas == 0) {
gen_helper_staa_i32(cpu_env, s4.value, t4, t0, t1, t2, t3);
} else if (mas == 0x3f) {
if (!am) {
gen_helper_set_aad_i32(cpu_env, s4.value, t1, t3);
} else {
gen_helper_set_aasti_i32(cpu_env, s4.value, t2);
}
} else {
qemu_log_mask(LOG_UNIMP, "staaw: not implemented mas\n");
abort();
}
tcg_temp_free_i32(t4);
tcg_temp_free_i32(t3);
tcg_temp_free_i32(t2);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
static void gen_st(DisasContext *ctx, int chan, MemOp memop)
{
bool sm = GET_BIT(ctx->bundle.als[chan], 31);
TCGLabel *l0 = gen_new_label();
TCGLabel *l1 = gen_new_label();
Src64 s1 = get_src1_i64(ctx, chan);
Src64 s2 = get_src2_i64(ctx, chan);
Src64 s4 = get_src4_i64(ctx, chan);
TCGv_i64 t0 = tcg_temp_local_new_i64();
gen_tag_check_i64(sm, NULL, NULL, s1.tag, l1);
gen_tag_check_i64(sm, NULL, NULL, s2.tag, l1);
gen_tag_check_i64(sm, NULL, NULL, s4.tag, l1);
tcg_gen_add_i64(t0, s1.value, s2.value);
memop = gen_mas(ctx, chan, memop, t0);
if (sm) {
TCGv_i32 t1 = tcg_temp_new_i32();
gen_helper_probe_write_access(t1, cpu_env, t0);
tcg_gen_brcondi_i32(TCG_COND_EQ, t1, 0, l1);
tcg_temp_free_i32(t1);
}
gen_set_label(l0);
tcg_gen_qemu_st_i64(s4.value, t0, ctx->mmuidx, memop);
gen_set_label(l1);
tcg_temp_free_i64(t0);
}
static void gen_alopf1_i32(DisasContext *ctx, int chan,
void (*op)(TCGv_i32, TCGv_i32, TCGv_i32))
{
bool sm = GET_BIT(ctx->bundle.als[chan], 31);
Src32 s1 = get_src1_i32(ctx, chan);
Src32 s2 = get_src2_i32(ctx, chan);
TCGv_i32 tag = e2k_get_temp_i32(ctx);
TCGv_i32 dst = e2k_get_temp_i32(ctx);
tcg_gen_movi_i32(tag, 0);
(*op)(dst, s1.value, s2.value);
gen_tag_check_i32(sm, dst, tag, s1.tag, NULL);
gen_tag_check_i32(sm, dst, tag, s2.tag, NULL);
set_al_result_reg32_tag(ctx, chan, dst, tag);
}
static void gen_alopf1_i64(DisasContext *ctx, int chan,
void (*op)(TCGv_i64, TCGv_i64, TCGv_i64))
{
bool sm = GET_BIT(ctx->bundle.als[chan], 31);
Src64 s1 = get_src1_i64(ctx, chan);
Src64 s2 = get_src2_i64(ctx, chan);
TCGv_i32 tag = e2k_get_temp_i32(ctx);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
tcg_gen_movi_i32(tag, 0);
(*op)(dst, s1.value, s2.value);
gen_tag_check_i64(sm, dst, tag, s1.tag, NULL);
gen_tag_check_i64(sm, dst, tag, s2.tag, NULL);
set_al_result_reg64_tag(ctx, chan, dst, tag);
}
static void gen_alopf1_tag_i64(DisasContext *ctx, int chan,
void (*op)(TCGv_i64, TCGv_i32, bool, TCGv_i64, TCGv_i64))
{
bool sm = GET_BIT(ctx->bundle.als[chan], 31);
TCGLabel *l0 = gen_new_label();
TCGLabel *l1 = gen_new_label();
Src64 s1 = get_src1_i64(ctx, chan);
Src64 s2 = get_src2_i64(ctx, chan);
TCGv_i32 tag = e2k_get_temp_i32(ctx);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
tcg_gen_movi_i32(tag, 0);
(*op)(dst, tag, sm, s1.value, s2.value);
tcg_gen_brcondi_i32(TCG_COND_EQ, tag, 0, l0);
tcg_gen_ori_i64(dst, dst, (1UL << 62) | (1UL << 30));
tcg_gen_br(l1);
gen_set_label(l0);
gen_tag_check_i64(sm, dst, tag, s1.tag, NULL);
gen_tag_check_i64(sm, dst, tag, s2.tag, NULL);
gen_set_label(l1);
set_al_result_reg64_tag(ctx, chan, dst, tag);
}
static void gen_alopf1_tag_i32(DisasContext *ctx, int chan,
void (*op)(TCGv_i32, TCGv_i32, bool, TCGv_i32, TCGv_i32))
{
bool sm = GET_BIT(ctx->bundle.als[chan], 31);
TCGLabel *l0 = gen_new_label();
TCGLabel *l1 = gen_new_label();
Src32 s1 = get_src1_i32(ctx, chan);
Src32 s2 = get_src2_i32(ctx, chan);
TCGv_i32 tag = e2k_get_temp_i32(ctx);
TCGv_i32 dst = e2k_get_temp_i32(ctx);
tcg_gen_movi_i32(tag, 0);
(*op)(dst, tag, sm, s1.value, s2.value);
tcg_gen_brcondi_i32(TCG_COND_EQ, tag, 0, l0);
tcg_gen_ori_i32(dst, dst, 1UL << 30);
tcg_gen_br(l1);
gen_set_label(l0);
gen_tag_check_i32(sm, dst, tag, s1.tag, NULL);
gen_tag_check_i32(sm, dst, tag, s2.tag, NULL);
gen_set_label(l1);
set_al_result_reg32_tag(ctx, chan, dst, tag);
}
static void gen_alopf1_cmp_i64(DisasContext *ctx, int chan,
void (*op)(TCGv_i64, int, TCGv_i64, TCGv_i64))
{
uint32_t als = ctx->bundle.als[chan];
bool sm = extract32(als, 31, 1);
int opc = extract32(als, 5, 3);
int idx = extract32(als, 0, 5);
TCGLabel *l0 = gen_new_label();
TCGLabel *l1 = gen_new_label();
Src64 s1 = get_src1_i64(ctx, chan);
Src64 s2 = get_src2_i64(ctx, chan);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
gen_tag_check_i32(sm, NULL, NULL, s1.tag, l0);
gen_tag_check_i32(sm, NULL, NULL, s2.tag, l0);
(*op)(dst, opc, s1.value, s2.value);
tcg_gen_br(l1);
gen_set_label(l0);
tcg_gen_movi_i64(dst, 2);
gen_set_label(l1);
set_al_result_preg(ctx, chan, idx, dst);
}
static void gen_alopf1_cmp_i32(DisasContext *ctx, int chan,
void (*op)(TCGv_i32, int, TCGv_i32, TCGv_i32))
{
uint32_t als = ctx->bundle.als[chan];
bool sm = extract32(als, 31, 1);
int opc = extract32(als, 5, 3);
int idx = extract32(als, 0, 5);
TCGLabel *l0 = gen_new_label();
TCGLabel *l1 = gen_new_label();
Src32 s1 = get_src1_i32(ctx, chan);
Src32 s2 = get_src2_i32(ctx, chan);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
TCGv_i32 t0 = tcg_temp_new_i32();
gen_tag_check_i32(sm, NULL, NULL, s1.tag, l0);
gen_tag_check_i32(sm, NULL, NULL, s2.tag, l0);
(*op)(t0, opc, s1.value, s2.value);
tcg_gen_extu_i32_i64(dst, t0);
tcg_gen_br(l1);
tcg_temp_free_i32(t0);
gen_set_label(l0);
tcg_gen_movi_i64(dst, 2);
gen_set_label(l1);
set_al_result_preg(ctx, chan, idx, dst);
}
static void gen_alopf1_mrgc_i32(DisasContext *ctx, int chan)
{
bool sm = extract32(ctx->bundle.als[chan], 31, 1);
Src32 s1 = get_src1_i32(ctx, chan);
Src32 s2 = get_src2_i32(ctx, chan);
TCGv_i32 tag = e2k_get_temp_i32(ctx);
TCGv_i32 dst = e2k_get_temp_i32(ctx);
TCGv_i32 cond = tcg_temp_new_i32();
gen_mrgc_i32(ctx, chan, cond);
gen_merge_i32(dst, s1.value, s2.value, cond);
tcg_gen_movi_i32(tag, 0);
gen_tag_check_i32(sm, dst, tag, s1.tag, NULL);
gen_tag_check_i32(sm, dst, tag, s2.tag, NULL);
set_al_result_reg32_tag(ctx, chan, dst, tag);
tcg_temp_free_i32(cond);
}
static void gen_alopf1_mrgc_i64(DisasContext *ctx, int chan)
{
bool sm = extract32(ctx->bundle.als[chan], 31, 1);
Src64 s1 = get_src1_i64(ctx, chan);
Src64 s2 = get_src2_i64(ctx, chan);
TCGv_i64 cond = tcg_temp_new_i64();
TCGv_i32 tag = e2k_get_temp_i32(ctx);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
gen_mrgc_i64(ctx, chan, cond);
gen_merge_i64(dst, s1.value, s2.value, cond);
tcg_gen_movi_i32(tag, 0);
gen_tag_check_i64(sm, dst, tag, s1.tag, NULL);
gen_tag_check_i64(sm, dst, tag, s2.tag, NULL);
set_al_result_reg64_tag(ctx, chan, dst, tag);
tcg_temp_free_i64(cond);
}
static void gen_alopf21_i64(DisasContext *ctx, int chan,
void (*op)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64))
{
bool sm = GET_BIT(ctx->bundle.als[chan], 31);
Src64 s1 = get_src1_i64(ctx, chan);
Src64 s2 = get_src2_i64(ctx, chan);
Src64 s3 = get_src3_i64(ctx, chan);
TCGv_i32 tag = e2k_get_temp_i32(ctx);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
tcg_gen_movi_i32(tag, 0);
(*op)(dst, s1.value, s2.value, s3.value);
gen_tag_check_i64(sm, dst, tag, s1.tag, NULL);
gen_tag_check_i64(sm, dst, tag, s2.tag, NULL);
gen_tag_check_i64(sm, dst, tag, s3.tag, NULL);
set_al_result_reg64_tag(ctx, chan, dst, tag);
}
static void gen_alopf21_i32(DisasContext *ctx, int chan,
void (*op)(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32))
{
bool sm = GET_BIT(ctx->bundle.als[chan], 31);
Src32 s1 = get_src1_i32(ctx, chan);
Src32 s2 = get_src2_i32(ctx, chan);
Src32 s3 = get_src3_i32(ctx, chan);
TCGv_i32 tag = e2k_get_temp_i32(ctx);
TCGv_i32 dst = e2k_get_temp_i32(ctx);
tcg_gen_movi_i32(tag, 0);
(*op)(dst, s1.value, s2.value, s3.value);
gen_tag_check_i32(sm, dst, tag, s1.tag, NULL);
gen_tag_check_i32(sm, dst, tag, s2.tag, NULL);
gen_tag_check_i32(sm, dst, tag, s3.tag, NULL);
set_al_result_reg32_tag(ctx, chan, dst, tag);
}
static void execute_alopf_simple(DisasContext *dc, int chan)
{
uint32_t als = dc->bundle.als[chan];
int opc = GET_FIELD(als, 24, 7);
switch(opc) {
case 0x00: /* ands */ gen_alopf1_i32(dc, chan, tcg_gen_and_i32); break;
case 0x01: /* andd */ gen_alopf1_i64(dc, chan, tcg_gen_and_i64); break;
case 0x02: /* andns */ gen_alopf1_i32(dc, chan, gen_andn_i32); break;
case 0x03: /* andnd */ gen_alopf1_i64(dc, chan, gen_andn_i64); break;
case 0x04: /* ors */ gen_alopf1_i32(dc, chan, tcg_gen_or_i32); break;
case 0x05: /* ord */ gen_alopf1_i64(dc, chan, tcg_gen_or_i64); break;
case 0x06: /* orns */ gen_alopf1_i32(dc, chan, gen_orn_i32); break;
case 0x07: /* ornd */ gen_alopf1_i64(dc, chan, gen_orn_i64); break;
case 0x08: /* xors */ gen_alopf1_i32(dc, chan, tcg_gen_xor_i32); break;
case 0x09: /* xord */ gen_alopf1_i64(dc, chan, tcg_gen_xor_i64); break;
case 0x0a: /* xorns */ gen_alopf1_i32(dc, chan, gen_xorn_i32); break;
case 0x0b: /* xornd */ gen_alopf1_i64(dc, chan, gen_xorn_i64); break;
case 0x0c: /* sxt */ gen_alopf1_i64(dc, chan, gen_helper_sxt); break;
case 0x0e: /* merges */ gen_alopf1_mrgc_i32(dc, chan); break;
case 0x0f: /* merged */ gen_alopf1_mrgc_i64(dc, chan); break;
case 0x10: /* adds */ gen_alopf1_i32(dc, chan, tcg_gen_add_i32); break;
case 0x11: /* addd */ gen_alopf1_i64(dc, chan, tcg_gen_add_i64); break;
case 0x12: /* subs */ gen_alopf1_i32(dc, chan, tcg_gen_sub_i32); break;
case 0x13: /* subd */ gen_alopf1_i64(dc, chan, tcg_gen_sub_i64); break;
case 0x14: /* scls */ gen_alopf1_i32(dc, chan, tcg_gen_rotl_i32); break;
case 0x15: /* scld */ gen_alopf1_i64(dc, chan, tcg_gen_rotl_i64); break;
case 0x16: /* scrs */ gen_alopf1_i32(dc, chan, tcg_gen_rotr_i32); break;
case 0x17: /* scrd */ gen_alopf1_i64(dc, chan, tcg_gen_rotr_i64); break;
case 0x18: /* shls */ gen_alopf1_i32(dc, chan, tcg_gen_shl_i32); break;
case 0x19: /* shld */ gen_alopf1_i64(dc, chan, tcg_gen_shl_i64); break;
case 0x1a: /* shrs */ gen_alopf1_i32(dc, chan, tcg_gen_shr_i32); break;
case 0x1b: /* shrd */ gen_alopf1_i64(dc, chan, tcg_gen_shr_i64); break;
case 0x1c: /* sars */ gen_alopf1_i32(dc, chan, tcg_gen_sar_i32); break;
case 0x1d: /* sard */ gen_alopf1_i64(dc, chan, tcg_gen_sar_i64); break;
case 0x1e: /* getfs */ gen_alopf1_i32(dc, chan, gen_getfs); break;
case 0x1f: /* getfd */ gen_alopf1_i64(dc, chan, gen_getfd); break;
case 0x20:
if (is_cmp_chan(chan)) {
gen_alopf1_cmp_i32(dc, chan, gen_cmp_i32); /* cmp{op}sb */
} else {
abort();
}
break;
case 0x21:
if (is_cmp_chan(chan)) {
gen_alopf1_cmp_i64(dc, chan, gen_cmp_i64); /* cmp{op}db */
} else {
abort();
}
break;
case 0x22:
if (is_cmp_chan(chan)) {
gen_alopf1_cmp_i32(dc, chan, gen_cmpand_i32); /* cmpand{op}sb */
} else {
abort();
}
break;
case 0x23:
if (is_cmp_chan(chan)) {
gen_alopf1_cmp_i64(dc, chan, gen_cmpand_i64); /* cmpand{op}db */
} else {
abort();
}
break;
case 0x24: { /* stb */
if (is_store_chan(chan)) {
gen_st(dc, chan, MO_UB);
} else {
abort();
}
break;
}
case 0x25: { /* sth */
if (is_store_chan(chan)) {
gen_st(dc, chan, MO_UW);
} else {
abort();
}
break;
}
case 0x26: { /* stw */
if (is_store_chan(chan)) {
gen_st(dc, chan, MO_UL);
} else {
abort();
}
break;
}
case 0x27: { /* std */
if (is_store_chan(chan)) {
gen_st(dc, chan, MO_Q);
} else {
abort();
}
break;
}
case 0x40:
if (is_div_chan(chan)) {
// FIXME: temp hack
TCGLabel *l0 = gen_new_label();
Src64 s2 = get_src2_i64(dc, chan);
tcg_gen_brcondi_i64(TCG_COND_NE, s2.value, 0, l0);
e2k_gen_exception(0);
gen_set_label(l0);
gen_alopf1_tag_i32(dc, chan, gen_udivs); /* udivs */
} else {
abort();
}
break;
case 0x41:
if (is_div_chan(chan)) {
gen_alopf1_tag_i64(dc, chan, gen_udivd); /* udivd */
} else {
abort();
}
break;
case 0x42:
if (is_div_chan(chan)) {
gen_alopf1_tag_i32(dc, chan, gen_sdivs); /* sdivs */
} else {
abort();
}
break;
case 0x43:
if (is_div_chan(chan)) {
gen_alopf1_tag_i64(dc, chan, gen_sdivd); /* sdivd */
} else {
abort();
}
break;
case 0x61:
if (chan == 2 || chan == 5) {
abort();
} else {
gen_movtd(dc, chan);
}
break;
case 0x64: { /* ldb */
if (is_load_chan(chan)) {
gen_ld(dc, chan, MO_UB);
} else {
abort();
}
break;
}
case 0x65: { /* ldh */
if (is_load_chan(chan)) {
gen_ld(dc, chan, MO_UW);
} else {
abort();
}
break;
}
case 0x66: { /* ldw */
if (is_load_chan(chan)) {
gen_ld(dc, chan, MO_UL);
} else {
abort();
}
break;
}
case 0x67: { /* ldd */
if (is_load_chan(chan)) {
gen_ld(dc, chan, MO_Q);
} else {
abort();
}
break;
}
default:
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
break;
}
}
static void execute_ext_01_25(DisasContext *ctx, int chan)
{
uint8_t opc = GET_FIELD(ctx->bundle.als[chan], 24, 7);
if (chan != 2 && chan != 5) {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
return;
}
switch(opc) {
case 0x08: gen_gettag_i32(ctx, chan); break; /* gettags */
case 0x09: gen_gettag_i64(ctx, chan); break; /* gettagd */
case 0x0a: gen_puttag_i32(ctx, chan); break; /* puttags */
case 0x0b: gen_puttag_i64(ctx, chan); break; /* puttagd */
case 0x1e: gen_staa_i32(ctx, chan); break; /* staaw */
case 0x1f: gen_staa_i64(ctx, chan); break; /* staad */
default:
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
break;
}
}
static void execute_ext_01(DisasContext *dc, int chan)
{
uint8_t opc = GET_FIELD(dc->bundle.als[chan], 24, 7);
switch (opc) {
case 0x0f:
if (chan == 0 || chan == 3) {
// FIXME: what is the point in packed add on vector of 64-bit elements if reg size is 64 bits?
gen_alopf1_i64(dc, chan, tcg_gen_add_i64); /* paddd */
} else {
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
}
break;
case 0x20:
if (is_cmp_chan(chan)) {
gen_alopf1_i32(dc, chan, tcg_gen_mul_i32); /* muls */
} else {
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
}
break;
case 0x21:
if (is_cmp_chan(chan)) {
gen_alopf1_i64(dc, chan, tcg_gen_mul_i64); /* muld */
} else {
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
}
break;
case 0x3c: /* rws */ gen_rw_i32(dc, chan); break; /* TODO: only channel 1 */
case 0x3d: /* rwd */ gen_rw_i64(dc, chan); break; /* TODO: only channel 1 */
case 0x3e: /* rrs */ gen_rr_i32(dc, chan); break; /* TODO: only channel 1 */
case 0x3f: /* rrd */ gen_rr_i64(dc, chan); break; /* TODO: only channel 1 */
case 0x58: {
if (chan == 0 || chan == 3) {
gen_getsp(dc, chan);
}
/* TODO: exception */
break;
}
default:
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
break;
}
}
static void execute_ext_0b(DisasContext *ctx, int chan)
{
uint8_t opc = GET_FIELD(ctx->bundle.als[chan], 24, 7);
switch(opc) {
case 0x6c:
if (is_cmp_chan(chan) && ctx->version >= 4) {
gen_alopf21_i32(ctx, chan, gen_insert_field_i32); /* insfs */
} else {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
}
break;
case 0x6d:
if (is_cmp_chan(chan) && ctx->version>= 4) {
gen_alopf21_i64(ctx, chan, gen_insert_field_i64); /* insfd */
} else {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
}
break;
default:
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
break;
}
}
static void execute_ext_0f(DisasContext *ctx, int chan)
{
uint8_t opc = GET_FIELD(ctx->bundle.als[chan], 24, 7);
switch(opc) {
case 0x4d:
if (is_cmp_chan(chan) && ctx->version >= 2) {
gen_alopf21_i64(ctx, chan, gen_helper_packed_shuffle_i64); /* pshufb */
} else {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
}
break;
default:
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
break;
}
}
void e2k_alc_execute(DisasContext *ctx, int chan)
{
const UnpackedBundle *bundle = &ctx->bundle;
uint16_t rlp = find_cond(ctx, chan);
TCGLabel *l0 = gen_new_label();
TCGv_i64 cond = NULL;
if (rlp != 0) {
TCGv_i64 t0 = tcg_temp_new_i64();
uint8_t psrc = GET_FIELD(rlp, 0, 7);
bool neg = GET_BIT(rlp, 7 + chan % 3);
e2k_gen_cond_i64(ctx, t0, psrc);
cond = e2k_get_temp_i64(ctx);
tcg_gen_xori_i64(cond, t0, neg);
tcg_gen_brcondi_i64(TCG_COND_EQ, cond, 0, l0);
tcg_temp_free_i64(t0);
}
switch(bundle->ales_present[chan]) {
case ALES_NONE:
execute_alopf_simple(ctx, chan);
break;
case ALES_ALLOCATED: // 2 or 5 channel
execute_ext_01_25(ctx, chan);
break;
case ALES_PRESENT: {
uint8_t opc = GET_FIELD(bundle->ales[chan], 8, 8);
switch (opc) {
case 0x01:
execute_ext_01(ctx, chan);
break;
case 0x0b:
execute_ext_0b(ctx, chan);
break;
case 0x0f:
execute_ext_0f(ctx, chan);
break;
default:
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
break;
}
break;
}
default:
g_assert_not_reached();
break;
}
gen_set_label(l0);
ctx->al_cond[chan].is_set = rlp != 0;
ctx->al_cond[chan].value = cond;
}
void e2k_alc_commit(DisasContext *ctx)
{
unsigned int i;
for (i = 0; i < 6; i++) {
TCGLabel *l0;
AlResult *res = &ctx->al_results[i];
AlCond *cond = &ctx->al_cond[i];
if (!ctx->bundle.als_present[i]) {
continue;
}
if (res->type != AL_RESULT_NONE && cond->is_set) {
l0 = gen_new_label();
tcg_gen_brcondi_i64(TCG_COND_EQ, cond->value, 0, l0);
}
switch(res->type) {
case AL_RESULT_REG32:
e2k_gen_reg_tag_write_i32(res->reg.tag, res->reg.index);
e2k_gen_reg_write_i32(res->reg.v32, res->reg.index);
break;
case AL_RESULT_REG64:
e2k_gen_reg_tag_write_i64(res->reg.tag, res->reg.index);
e2k_gen_reg_write_i64(res->reg.v64, res->reg.index);
break;
case AL_RESULT_PREG:
e2k_gen_store_preg(res->preg.index, res->preg.value);
break;
case AL_RESULT_CTPR32: {
TCGv_i64 ctpr = e2k_cs.ctprs[res->ctpr32.index];
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_const_i64(CTPR_TAG_DISP);
assert(res->ctpr32.index < 3);
tcg_gen_extu_i32_i64(t0, res->ctpr32.value);
tcg_gen_deposit_i64(ctpr, ctpr, t0, 0, 48);
tcg_gen_deposit_i64(ctpr, ctpr, t1, CTPR_TAG_OFF,
CTPR_TAG_LEN);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t0);
break;
}
case AL_RESULT_CTPR64: {
TCGv_i64 ctpr = e2k_cs.ctprs[res->ctpr64.index];
TCGv_i64 t0 = tcg_const_i64(CTPR_TAG_DISP);
assert(res->ctpr64.index < 3);
tcg_gen_deposit_i64(ctpr, ctpr, res->ctpr64.value, 0, 48);
tcg_gen_deposit_i64(ctpr, ctpr, t0, CTPR_TAG_OFF,
CTPR_TAG_LEN);
tcg_temp_free_i64(t0);
break;
}
default:
break;
}
if (res->type != AL_RESULT_NONE && cond->is_set) {
gen_set_label(l0);
}
}
}