diff --git a/gdbstub.c b/gdbstub.c index 5caba0ac1e..4da1e48713 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -2375,7 +2375,7 @@ static void handle_query_e2k_tags_read(GArray *params, void *user_ctx) } for (i = 0; i < len; i++) { - int tag = (tags >> i * E2K_TAG_SIZE) & 0x3; + int tag = (tags >> (i * 2)) & 0x3; g_string_append_c(gdbserver_state.str_buf, tag); } diff --git a/target/e2k/translate/alops.inc b/target/e2k/alops.inc similarity index 99% rename from target/e2k/translate/alops.inc rename to target/e2k/alops.inc index f84eb03b45..1d65cc6b26 100644 --- a/target/e2k/translate/alops.inc +++ b/target/e2k/alops.inc @@ -883,6 +883,10 @@ typedef enum { ARGS_XDX = args3(X, D, X), ARGS_XXS = args3(X, X, S), ARGS_XXD = args3(X, X, D), + ARGS_SXS = args3(S, X, S), + ARGS_DXD = args3(D, X, D), + ARGS_SXX = args3(S, X, X), + ARGS_DXX = args3(D, X, X), ARGS_XXX = args3(X, X, X), ARGS_QSS = args3(Q, S, S), ARGS_QSD = args3(Q, S, D), @@ -1024,15 +1028,15 @@ static AlopDesc alops[] = { { X(OP_FXDIVXX), ALOPF1, ARGS_XXX, SHORT, 0x4f, 1, -1, CHAN_5, { -1 } }, { X(OP_FXDIVXD), ALOPF1, ARGS_XXD, SHORT, 0x4d, 1, -1, CHAN_5, { -1 } }, { X(OP_FXDIVXS), ALOPF1, ARGS_XXS, SHORT, 0x4c, 1, -1, CHAN_5, { -1 } }, - { X(OP_FXDIVTSS), ALOPF1, ARGS_XSS, SHORT, 0x60, 1, -1, CHAN_5, { -1 } }, - { X(OP_FXDIVTDD), ALOPF1, ARGS_XDD, SHORT, 0x61, 1, -1, CHAN_5, { -1 } }, - { X(OP_FXDIVTSX), ALOPF1, ARGS_XSX, SHORT, 0x62, 1, -1, CHAN_5, { -1 } }, - { X(OP_FXDIVTDX), ALOPF1, ARGS_XDX, SHORT, 0x63, 1, -1, CHAN_5, { -1 } }, - { X(OP_FXSQRTUSX), ALOPF1, ARGS_XSX, SHORT, 0x5a, 1, -1, CHAN_5, { -1 } }, - { X(OP_FXSQRTUDX), ALOPF1, ARGS_XDX, SHORT, 0x5b, 1, -1, CHAN_5, { -1 } }, + { X(OP_FXDIVTSS), ALOPF1, ARGS_SXS, SHORT, 0x60, 1, -1, CHAN_5, { -1 } }, + { X(OP_FXDIVTDD), ALOPF1, ARGS_DXD, SHORT, 0x61, 1, -1, CHAN_5, { -1 } }, + { X(OP_FXDIVTSX), ALOPF1, ARGS_SXX, SHORT, 0x62, 1, -1, CHAN_5, { -1 } }, + { X(OP_FXDIVTDX), ALOPF1, ARGS_DXX, SHORT, 0x63, 1, -1, CHAN_5, { -1 } }, + { X(OP_FXSQRTUSX), ALOPF1, ARGS_SXX, SHORT, 0x5a, 1, -1, CHAN_5, { -1 } }, + { X(OP_FXSQRTUDX), ALOPF1, ARGS_DXX, SHORT, 0x5b, 1, -1, CHAN_5, { -1 } }, { X(OP_FXSQRTUXX), ALOPF1, ARGS_XXX, SHORT, 0x59, 1, -1, CHAN_5, { -1 } }, - { X(OP_FXSQRTTSX), ALOPF1, ARGS_XSX, SHORT, 0x5e, 1, -1, CHAN_5, { -1 } }, - { X(OP_FXSQRTTDX), ALOPF1, ARGS_XDX, SHORT, 0x5f, 1, -1, CHAN_5, { -1 } }, + { X(OP_FXSQRTTSX), ALOPF1, ARGS_SXX, SHORT, 0x5e, 1, -1, CHAN_5, { -1 } }, + { X(OP_FXSQRTTDX), ALOPF1, ARGS_DXX, SHORT, 0x5f, 1, -1, CHAN_5, { -1 } }, { X(OP_FXSQRTTXX), ALOPF1, ARGS_XXX, SHORT, 0x5d, 1, -1, CHAN_5, { -1 } }, { X(OP_MOVIF), ALOPF1, ARGS_DSX, SHORT, 0x5e, 1, -1, CHAN_14, { -1 } }, { X(OP_VFSI), ALOPF1, ARGS_SDD, SHORT, 0x63, 1, -1, CHAN_14, { -1 } }, diff --git a/target/e2k/cpu.h b/target/e2k/cpu.h index f95d31d4fc..c7cba59f83 100644 --- a/target/e2k/cpu.h +++ b/target/e2k/cpu.h @@ -34,10 +34,13 @@ void e2k_tcg_initialize(void); #define MMU_USER_IDX 1 #define CPU_RESOLVING_TYPE TYPE_E2K_CPU -#define E2K_TAG_SIZE 2 /* 2-bit tag for 32-bit value */ #define E2K_REG_LEN sizeof(uint64_t) #define E2K_REG_SIZE (E2K_REG_LEN * 8) -#define E2K_REG_TAGS_SIZE (E2K_TAG_SIZE * 2) /* two tags for 32-bit halves */ + +#define E2K_TAG_MASK_32 0x03 +#define E2K_TAG_MASK_64 0x0f +#define E2K_TAG_MASK_80 E2K_TAG_MASK_64 +#define E2K_TAG_MASK_128 0xff #define E2K_WR_COUNT 64 /* %rN [0, 64) */ #define E2K_BR_COUNT 128 /* %b[N] [0, 128) */ @@ -710,7 +713,7 @@ typedef struct CPUArchState { /* temporaries for FX/SIMD ops */ E2KReg t0, t1, t2, t3; - E2KReg tmp[3]; + E2KReg tmp[8]; E2KReg al_result[6]; /* DAM */ diff --git a/target/e2k/helper.c b/target/e2k/helper.c index aa7203d72f..eee87d6193 100644 --- a/target/e2k/helper.c +++ b/target/e2k/helper.c @@ -2,7 +2,6 @@ #include "qemu/log.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" -#include "translate.h" void helper_signal_frame(CPUE2KState *env, int wbs, target_ulong ret_ip); diff --git a/target/e2k/helper.h b/target/e2k/helper.h index b1fd6edc2b..ced84b665f 100644 --- a/target/e2k/helper.h +++ b/target/e2k/helper.h @@ -10,22 +10,19 @@ #define dh_is_signed_f80 dh_is_signed_ptr DEF_HELPER_2(raise_exception, noreturn, env, int) +DEF_HELPER_1(syscall, noreturn, env) +DEF_HELPER_1(break_restore_state, void, env) +DEF_HELPER_1(expand_stacks, void, env) + +DEF_HELPER_4(call, void, env, i64, int, tl) DEF_HELPER_2(prep_return, i64, env, int) DEF_HELPER_1(return, void, env) DEF_HELPER_1(signal_return, void, env) -DEF_HELPER_4(call, void, env, i64, int, tl) -DEF_HELPER_1(expand_stacks, void, env) -DEF_HELPER_1(syscall, void, env) -DEF_HELPER_2(sxt, i64, i64, i32) -DEF_HELPER_2(state_reg_read_i64, i64, env, int) -DEF_HELPER_2(state_reg_read_i32, i32, env, int) -DEF_HELPER_3(state_reg_write_i64, void, env, int, i64) -DEF_HELPER_3(state_reg_write_i32, void, env, int, i32) -DEF_HELPER_2(getsp, i64, env, i32) /* FIXME: return tl? */ -DEF_HELPER_1(break_restore_state, void, env) + DEF_HELPER_4(setwd, void, env, int, int, int) -DEF_HELPER_2(probe_read_access, int, env, tl) -DEF_HELPER_2(probe_write_access, int, env, tl) + +DEF_HELPER_FLAGS_2(probe_read_access, TCG_CALL_NO_RWG, int, env, tl) +DEF_HELPER_FLAGS_2(probe_write_access, TCG_CALL_NO_RWG, int, env, tl) DEF_HELPER_1(aau_load_program, void, env) DEF_HELPER_4(mova_ptr, tl, env, int, int, int) @@ -33,214 +30,259 @@ DEF_HELPER_3(aau_am, void, env, int, int) DEF_HELPER_4(dam_lock_addr, void, env, i64, int, int) DEF_HELPER_4(dam_unlock_addr, int, env, i64, int, int) +DEF_HELPER_2(getsp, i64, env, i32) + +DEF_HELPER_FLAGS_2(rrd, TCG_CALL_NO_WG_SE, i64, env, int) +DEF_HELPER_3(rwd, void, env, int, i64) +DEF_HELPER_3(rws, void, env, int, i32) + +DEF_HELPER_FLAGS_2(sxt, TCG_CALL_NO_RWG_SE, i64, i64, i32) + /* Packed Min/Max */ -DEF_HELPER_2(pminub, i64, i64, i64) -DEF_HELPER_2(pminsb, i64, i64, i64) -DEF_HELPER_2(pminuh, i64, i64, i64) -DEF_HELPER_2(pminsh, i64, i64, i64) -DEF_HELPER_2(pminuw, i64, i64, i64) -DEF_HELPER_2(pminsw, i64, i64, i64) -DEF_HELPER_2(pmaxub, i64, i64, i64) -DEF_HELPER_2(pmaxsb, i64, i64, i64) -DEF_HELPER_2(pmaxuh, i64, i64, i64) -DEF_HELPER_2(pmaxsh, i64, i64, i64) -DEF_HELPER_2(pmaxuw, i64, i64, i64) -DEF_HELPER_2(pmaxsw, i64, i64, i64) +DEF_HELPER_FLAGS_2(pminub, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pminsb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pminuh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pminsh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pminuw, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pminsw, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmaxub, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmaxsb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmaxuh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmaxsh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmaxuw, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmaxsw, TCG_CALL_NO_RWG_SE, i64, i64, i64) /* Packed Cmp */ -DEF_HELPER_2(pcmpeqb, i64, i64, i64) -DEF_HELPER_2(pcmpeqh, i64, i64, i64) -DEF_HELPER_2(pcmpeqw, i64, i64, i64) -DEF_HELPER_2(pcmpeqd, i64, i64, i64) -DEF_HELPER_2(pcmpgtb, i64, i64, i64) -DEF_HELPER_2(pcmpgth, i64, i64, i64) -DEF_HELPER_2(pcmpgtw, i64, i64, i64) -DEF_HELPER_2(pcmpgtd, i64, i64, i64) +DEF_HELPER_FLAGS_2(pcmpeqb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pcmpeqh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pcmpeqw, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pcmpeqd, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pcmpgtb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pcmpgth, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pcmpgtw, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pcmpgtd, TCG_CALL_NO_RWG_SE, i64, i64, i64) /* Pached Horizontal Add */ -DEF_HELPER_2(phaddh, i64, i64, i64) -DEF_HELPER_2(phaddw, i64, i64, i64) -DEF_HELPER_2(phaddsh, i64, i64, i64) +DEF_HELPER_FLAGS_2(phaddh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(phaddw, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(phaddsh, TCG_CALL_NO_RWG_SE, i64, i64, i64) /* Packed Horizontal Sub */ -DEF_HELPER_2(phsubh, i64, i64, i64) -DEF_HELPER_2(phsubw, i64, i64, i64) -DEF_HELPER_2(phsubsh, i64, i64, i64) +DEF_HELPER_FLAGS_2(phsubh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(phsubw, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(phsubsh, TCG_CALL_NO_RWG_SE, i64, i64, i64) /* Packed Add using saturation */ -DEF_HELPER_2(paddsb, i64, i64, i64) -DEF_HELPER_2(paddsh, i64, i64, i64) -DEF_HELPER_2(paddusb, i64, i64, i64) -DEF_HELPER_2(paddush, i64, i64, i64) +DEF_HELPER_FLAGS_2(paddsb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(paddsh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(paddusb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(paddush, TCG_CALL_NO_RWG_SE, i64, i64, i64) /* Packed Sub using saturation */ -DEF_HELPER_2(psubsb, i64, i64, i64) -DEF_HELPER_2(psubsh, i64, i64, i64) -DEF_HELPER_2(psubusb, i64, i64, i64) -DEF_HELPER_2(psubush, i64, i64, i64) +DEF_HELPER_FLAGS_2(psubsb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psubsh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psubusb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psubush, TCG_CALL_NO_RWG_SE, i64, i64, i64) /* Packed shifts */ -DEF_HELPER_2(psllh, i64, i64, i64) -DEF_HELPER_2(psllw, i64, i64, i64) -DEF_HELPER_2(psrlh, i64, i64, i64) -DEF_HELPER_2(psrlw, i64, i64, i64) +DEF_HELPER_FLAGS_2(psllh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psllw, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psrlh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psrlw, TCG_CALL_NO_RWG_SE, i64, i64, i64) /* Packed shifts with sign */ -DEF_HELPER_2(psrah, i64, i64, i64) -DEF_HELPER_2(psraw, i64, i64, i64) +DEF_HELPER_FLAGS_2(psrah, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psraw, TCG_CALL_NO_RWG_SE, i64, i64, i64) /* Packed Mul */ -DEF_HELPER_2(pmaddh, i64, i64, i64) -DEF_HELPER_2(pmaddubsh, i64, i64, i64) -DEF_HELPER_2(pmulhh, i64, i64, i64) -DEF_HELPER_2(pmullh, i64, i64, i64) -DEF_HELPER_2(pmulhuh, i64, i64, i64) -DEF_HELPER_2(pmulubhh, i64, i64, i64) -DEF_HELPER_2(pmulhrsh, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmaddh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmaddubsh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmulhh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmullh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmulhuh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmulubhh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmulhrsh, TCG_CALL_NO_RWG_SE, i64, i64, i64) /* Packed Sign Mul */ -DEF_HELPER_2(psignb, i64, i64, i64) -DEF_HELPER_2(psignh, i64, i64, i64) -DEF_HELPER_2(psignw, i64, i64, i64) +DEF_HELPER_FLAGS_2(psignb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psignh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psignw, TCG_CALL_NO_RWG_SE, i64, i64, i64) /* Packed Move Mask */ -DEF_HELPER_2(pmovmskb, i64, i64, i64) -DEF_HELPER_2(pmovmskps, i64, i64, i64) -DEF_HELPER_2(pmovmskpd, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmovmskb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmovmskps, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmovmskpd, TCG_CALL_NO_RWG_SE, i64, i64, i64) /* Packed packs */ -DEF_HELPER_2(packsshb, i64, i64, i64) -DEF_HELPER_2(packushb, i64, i64, i64) -DEF_HELPER_2(packsswh, i64, i64, i64) -DEF_HELPER_2(packuswh, i64, i64, i64) +DEF_HELPER_FLAGS_2(packsshb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(packushb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(packsswh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(packuswh, TCG_CALL_NO_RWG_SE, i64, i64, i64) /* Packed unpacks */ -DEF_HELPER_2(punpcklbh, i64, i64, i64) -DEF_HELPER_2(punpcklhw, i64, i64, i64) -DEF_HELPER_2(punpcklwd, i64, i64, i64) -DEF_HELPER_2(punpckhbh, i64, i64, i64) -DEF_HELPER_2(punpckhhw, i64, i64, i64) -DEF_HELPER_2(punpckhwd, i64, i64, i64) +DEF_HELPER_FLAGS_2(punpcklbh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(punpcklhw, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(punpcklwd, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(punpckhbh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(punpckhhw, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(punpckhwd, TCG_CALL_NO_RWG_SE, i64, i64, i64) /* Packed shuffle */ -DEF_HELPER_3(pshufb, i64, i64, i64, i64) -DEF_HELPER_3(pmerge, i64, i64, i64, i64) -DEF_HELPER_2(pshufh, i64, i64, i32) -DEF_HELPER_3(pshufw, i64, i64, i64, i32) +DEF_HELPER_FLAGS_3(pshufb, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64) +DEF_HELPER_FLAGS_3(pmerge, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64) +DEF_HELPER_FLAGS_2(pshufh, TCG_CALL_NO_RWG_SE, i64, i64, i32) +DEF_HELPER_FLAGS_3(pshufw, TCG_CALL_NO_RWG_SE, i64, i64, i64, i32) /* Packed uncategorized */ -DEF_HELPER_2(psadbw, i64, i64, i64) -DEF_HELPER_2(pavgusb, i64, i64, i64) -DEF_HELPER_2(pavgush, i64, i64, i64) -DEF_HELPER_2(phminposuh, i64, i64, i64) -DEF_HELPER_2(mpsadbh, i64, i64, i64) -DEF_HELPER_4(plog, i64, i32, i64, i64, i64) +DEF_HELPER_FLAGS_2(psadbw, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pavgusb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pavgush, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(phminposuh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(mpsadbh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_4(plog, TCG_CALL_NO_RWG_SE, i64, i32, i64, i64, i64) /* Float 32/64 Ops */ -#define DEF_HELPER_3_32_64(name) \ - DEF_HELPER_3(name##s, i32, env, i32, i32) \ - DEF_HELPER_3(name##d, i64, env, i64, i64) -DEF_HELPER_3_32_64(fadd) -DEF_HELPER_3_32_64(fsub) -DEF_HELPER_3_32_64(fmin) -DEF_HELPER_3_32_64(fmax) -DEF_HELPER_3_32_64(fmul) -DEF_HELPER_3_32_64(fdiv) -DEF_HELPER_3(fscaled, i64, env, i64, i32) -DEF_HELPER_3(fscales, i32, env, i32, i32) -DEF_HELPER_2(frcps, i32, env, i32) -DEF_HELPER_2(fsqrts, i32, env, i32) -DEF_HELPER_2(frsqrts, i32, env, i32) -DEF_HELPER_3(fsqrttd, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fadds, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fsubs, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fmuls, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fdivs, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fmins, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fmaxs, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fscales, TCG_CALL_NO_RWG, i32, env, i32, i32) + +DEF_HELPER_FLAGS_3(faddd, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fsubd, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmuld, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fdivd, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmind, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmaxd, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fscaled, TCG_CALL_NO_RWG, i64, env, i64, i32) + +DEF_HELPER_FLAGS_2(frcps, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(fsqrts, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(frsqrts, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_3(fsqrttd, TCG_CALL_NO_RWG, i64, env, i64, i64) /* Packed Float ops */ -DEF_HELPER_3(pfadds, i64, env, i64, i64) -DEF_HELPER_3(pfsubs, i64, env, i64, i64) -DEF_HELPER_3(pfmuls, i64, env, i64, i64) -DEF_HELPER_3(pfmaxs, i64, env, i64, i64) -DEF_HELPER_3(pfmins, i64, env, i64, i64) -DEF_HELPER_3(pfhadds, i64, env, i64, i64) -DEF_HELPER_3(pfhsubs, i64, env, i64, i64) -DEF_HELPER_3(pfaddsubs, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(pfadds, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(pfsubs, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(pfmuls, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(pfmaxs, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(pfmins, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(pfhadds, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(pfhsubs, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(pfaddsubs, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_3(pfstoifs, i64, env, i64, i64) -DEF_HELPER_2(pistofs, i64, env, i64) -DEF_HELPER_2(pfstois, i64, env, i64) -DEF_HELPER_2(pfstoistr, i64, env, i64) +DEF_HELPER_FLAGS_3(pfstoifs, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_2(pistofs, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(pfstois, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(pfstoistr, TCG_CALL_NO_RWG, i64, env, i64) -DEF_HELPER_3(pfcmpeqs, i64, env, i64, i64) -DEF_HELPER_3(pfcmplts, i64, env, i64, i64) -DEF_HELPER_3(pfcmples, i64, env, i64, i64) -DEF_HELPER_3(pfcmpuods, i64, env, i64, i64) -DEF_HELPER_3(pfcmpneqs, i64, env, i64, i64) -DEF_HELPER_3(pfcmpnlts, i64, env, i64, i64) -DEF_HELPER_3(pfcmpnles, i64, env, i64, i64) -DEF_HELPER_3(pfcmpods, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(pfcmpeqs, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(pfcmplts, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(pfcmples, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(pfcmpuods, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(pfcmpneqs, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(pfcmpnlts, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(pfcmpnles, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(pfcmpods, TCG_CALL_NO_RWG, i64, env, i64, i64) /* Float x80 ops */ -DEF_HELPER_3(fxaddxx, void, env, f80, f80) -DEF_HELPER_3(fxsubxx, void, env, f80, f80) -DEF_HELPER_3(fxrsubxx, void, env, f80, f80) -DEF_HELPER_3(fxmulxx, void, env, f80, f80) -DEF_HELPER_3(fxdivxx, void, env, f80, f80) -DEF_HELPER_3(fxscalesx, void, env, f80, i32) -DEF_HELPER_3(fxsqrttxx, void, env, f80, f80) +#define DEF_FX_OP2(op) \ + DEF_HELPER_FLAGS_3(glue(op, ss), TCG_CALL_NO_RWG, i32, env, f80, i32) \ + DEF_HELPER_FLAGS_3(glue(op, dd), TCG_CALL_NO_RWG, i64, env, f80, i64) \ + DEF_HELPER_FLAGS_4(glue(op, sx), TCG_CALL_NO_RWG, void, f80, env, f80, i32) \ + DEF_HELPER_FLAGS_4(glue(op, dx), TCG_CALL_NO_RWG, void, f80, env, f80, i64) \ + DEF_HELPER_FLAGS_4(glue(op, xx), TCG_CALL_NO_RWG, void, f80, env, f80, f80) \ + DEF_HELPER_FLAGS_3(glue(op, xd), TCG_CALL_NO_RWG, i64, env, f80, f80) \ + DEF_HELPER_FLAGS_3(glue(op, xs), TCG_CALL_NO_RWG, i32, env, f80, f80) -/* Float 32/64/80 Comparisons */ -#define DEF_HELPER_3_32_64_80(name) \ - DEF_HELPER_3_32_64(f##name) \ - DEF_HELPER_3(fx##name##x, i64, env, f80, f80) -DEF_HELPER_3_32_64_80(cmpeq) -DEF_HELPER_3_32_64_80(cmpneq) -DEF_HELPER_3_32_64_80(cmple) -DEF_HELPER_3_32_64_80(cmpnle) -DEF_HELPER_3_32_64_80(cmplt) -DEF_HELPER_3_32_64_80(cmpnlt) -DEF_HELPER_3_32_64_80(cmpuod) -DEF_HELPER_3_32_64_80(cmpod) +DEF_FX_OP2(fxadd) +DEF_FX_OP2(fxsub) +DEF_FX_OP2(fxmul) +DEF_FX_OP2(fxdiv) + +#undef DEF_FX_OP2 + +DEF_HELPER_FLAGS_3(fxdivtss, TCG_CALL_NO_RWG, f32, env, f32, f80) +DEF_HELPER_FLAGS_3(fxdivtdd, TCG_CALL_NO_RWG, f64, env, f64, f80) +DEF_HELPER_FLAGS_4(fxdivtsx, TCG_CALL_NO_RWG, void, f80, env, f32, f80) +DEF_HELPER_FLAGS_4(fxdivtdx, TCG_CALL_NO_RWG, void, f80, env, f64, f80) + +DEF_HELPER_FLAGS_3(fxrsubss, TCG_CALL_NO_RWG, i32, env, f80, i32) +DEF_HELPER_FLAGS_3(fxrsubdd, TCG_CALL_NO_RWG, i64, env, f80, i64) +DEF_HELPER_FLAGS_4(fxrsubsx, TCG_CALL_NO_RWG, void, f80, env, f80, i32) +DEF_HELPER_FLAGS_4(fxrsubdx, TCG_CALL_NO_RWG, void, f80, env, f80, i64) + +DEF_HELPER_FLAGS_4(fxsqrttsx, TCG_CALL_NO_RWG, void, f80, env, i32, f80) +DEF_HELPER_FLAGS_4(fxsqrttdx, TCG_CALL_NO_RWG, void, f80, env, i64, f80) +DEF_HELPER_FLAGS_4(fxsqrttxx, TCG_CALL_NO_RWG, void, f80, env, f80, f80) + +DEF_HELPER_FLAGS_4(fxscalesx, TCG_CALL_NO_RWG, void, f80, env, f80, i32) + +DEF_HELPER_FLAGS_3(fxcmpodsf, TCG_CALL_NO_RWG, i32, env, f80, f32) +DEF_HELPER_FLAGS_3(fxcmpudsf, TCG_CALL_NO_RWG, i32, env, f80, f32) +DEF_HELPER_FLAGS_3(fxcmpoddf, TCG_CALL_NO_RWG, i32, env, f80, f64) +DEF_HELPER_FLAGS_3(fxcmpuddf, TCG_CALL_NO_RWG, i32, env, f80, f64) +DEF_HELPER_FLAGS_3(fxcmpodxf, TCG_CALL_NO_RWG, i32, env, f80, f80) +DEF_HELPER_FLAGS_3(fxcmpudxf, TCG_CALL_NO_RWG, i32, env, f80, f80) + +/* Float Comparisons */ +#define DEF_HELPER_FP_CMP(P, S, R, A, B) \ + DEF_HELPER_FLAGS_3(glue(glue(P, cmpeq), S), TCG_CALL_NO_RWG, R, env, A, B) \ + DEF_HELPER_FLAGS_3(glue(glue(P, cmpneq), S), TCG_CALL_NO_RWG, R, env, A, B) \ + DEF_HELPER_FLAGS_3(glue(glue(P, cmple), S), TCG_CALL_NO_RWG, R, env, A, B) \ + DEF_HELPER_FLAGS_3(glue(glue(P, cmpnle), S), TCG_CALL_NO_RWG, R, env, A, B) \ + DEF_HELPER_FLAGS_3(glue(glue(P, cmplt), S), TCG_CALL_NO_RWG, R, env, A, B) \ + DEF_HELPER_FLAGS_3(glue(glue(P, cmpnlt), S), TCG_CALL_NO_RWG, R, env, A, B) \ + DEF_HELPER_FLAGS_3(glue(glue(P, cmpuod), S), TCG_CALL_NO_RWG, R, env, A, B) \ + DEF_HELPER_FLAGS_3(glue(glue(P, cmpod), S), TCG_CALL_NO_RWG, R, env, A, B) + +DEF_HELPER_FP_CMP(f, s, i32, i32, i32) +DEF_HELPER_FP_CMP(f, d, i64, i64, i64) +DEF_HELPER_FP_CMP(fx, s, i64, f80, i32) +DEF_HELPER_FP_CMP(fx, d, i64, f80, i64) +DEF_HELPER_FP_CMP(fx, x, i64, f80, f80) /* Float Flag Comparisons */ -DEF_HELPER_3(fcmpodsf, i32, env, i32, i32) -DEF_HELPER_3(fcmpudsf, i32, env, i32, i32) -DEF_HELPER_3(fcmpoddf, i32, env, i64, i64) -DEF_HELPER_3(fcmpuddf, i32, env, i64, i64) -DEF_HELPER_3(fxcmpodxf, i32, env, f80, f80) -DEF_HELPER_3(fxcmpudxf, i32, env, f80, f80) +DEF_HELPER_FLAGS_3(fcmpodsf, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fcmpudsf, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fcmpoddf, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fcmpuddf, TCG_CALL_NO_RWG, i64, env, i64, i64) /* Float Conversions */ -DEF_HELPER_2(fstois, i32, env, i32) -DEF_HELPER_2(istofs, i32, env, i32) -DEF_HELPER_2(fstoistr, i32, env, i32) -DEF_HELPER_3(fstofx, void, f80, env, i32) -DEF_HELPER_3(istofx, void, f80, env, i32) +DEF_HELPER_FLAGS_2(fstofd, TCG_CALL_NO_RWG, i64, env, i32) +DEF_HELPER_FLAGS_3(fstofx, TCG_CALL_NO_RWG, void, f80, env, i32) -DEF_HELPER_2(fdtoid, i64, env, i64) -DEF_HELPER_2(idtofd, i64, env, i64) -DEF_HELPER_2(fdtoidtr, i64, env, i64) -DEF_HELPER_3(fdtofx, void, f80, env, i64) -DEF_HELPER_3(idtofx, void, f80, env, i64) +DEF_HELPER_FLAGS_2(fdtofs, TCG_CALL_NO_RWG, i32, env, i64) +DEF_HELPER_FLAGS_3(fdtofx, TCG_CALL_NO_RWG, void, f80, env, i64) -DEF_HELPER_2(fstofd, i64, env, i32) -DEF_HELPER_2(fstoid, i64, env, i32) -DEF_HELPER_2(istofd, i64, env, i32) -DEF_HELPER_2(fstoidtr, i64, env, i32) +DEF_HELPER_FLAGS_2(fxtofs, TCG_CALL_NO_RWG, i32, env, f80) +DEF_HELPER_FLAGS_2(fxtofd, TCG_CALL_NO_RWG, i64, env, f80) -DEF_HELPER_2(fdtofs, i32, env, i64) -DEF_HELPER_2(fdtois, i32, env, i64) -DEF_HELPER_2(idtofs, i32, env, i64) -DEF_HELPER_2(fdtoistr, i32, env, i64) +DEF_HELPER_FLAGS_2(istofs, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(istofd, TCG_CALL_NO_RWG, i64, env, i32) +DEF_HELPER_FLAGS_3(istofx, TCG_CALL_NO_RWG, void, f80, env, i32) -DEF_HELPER_2(fxtofs, i32, env, f80) -DEF_HELPER_2(fxtois, i32, env, f80) -DEF_HELPER_2(fxtoistr, i32, env, f80) +DEF_HELPER_FLAGS_2(idtofs, TCG_CALL_NO_RWG, i32, env, i64) +DEF_HELPER_FLAGS_2(idtofd, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_3(idtofx, TCG_CALL_NO_RWG, void, f80, env, i64) -DEF_HELPER_2(fxtofd, i64, env, f80) -DEF_HELPER_2(fxtoid, i64, env, f80) -DEF_HELPER_2(fxtoidtr, i64, env, f80) +DEF_HELPER_FLAGS_2(fstois, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(fstoid, TCG_CALL_NO_RWG, i64, env, i32) +DEF_HELPER_FLAGS_2(fstoistr, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(fstoidtr, TCG_CALL_NO_RWG, i64, env, i32) + +DEF_HELPER_FLAGS_2(fdtois, TCG_CALL_NO_RWG, i32, env, i64) +DEF_HELPER_FLAGS_2(fdtoid, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fdtoistr, TCG_CALL_NO_RWG, i32, env, i64) +DEF_HELPER_FLAGS_2(fdtoidtr, TCG_CALL_NO_RWG, i64, env, i64) + +DEF_HELPER_FLAGS_2(fxtois, TCG_CALL_NO_RWG, i32, env, f80) +DEF_HELPER_FLAGS_2(fxtoistr, TCG_CALL_NO_RWG, i32, env, f80) +DEF_HELPER_FLAGS_2(fxtoid, TCG_CALL_NO_RWG, i64, env, f80) +DEF_HELPER_FLAGS_2(fxtoidtr, TCG_CALL_NO_RWG, i64, env, f80) /* Float Rounding */ -DEF_HELPER_3(fstoifs, i32, env, i32, i32) -DEF_HELPER_3(fdtoifd, i64, env, i64, i64) - -#undef DEF_HELPER_3_32_64_80 -#undef DEF_HELPER_3_32_64 +DEF_HELPER_FLAGS_3(fstoifs, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fdtoifd, TCG_CALL_NO_RWG, i64, env, i64, i64) diff --git a/target/e2k/helper_fpu.c b/target/e2k/helper_fpu.c index b7c96dc94a..9c79af6edc 100644 --- a/target/e2k/helper_fpu.c +++ b/target/e2k/helper_fpu.c @@ -75,217 +75,17 @@ void e2k_update_fp_status(CPUE2KState *env) set_float_rounding_mode(rm[env->pfpfr.rc], &env->fp_status); } -#define GENERATE_SIMPLE_FLOAT2_OP(name, function, size) \ - uint##size##_t HELPER(name)(CPUE2KState *env, uint##size##_t x, uint##size##_t y) \ - { \ - int old_flags = fp_save_exception_flags(env); \ - float##size z = float##size##_##function (make_float##size (x), make_float##size (y), &env->fp_status); \ - fp_merge_exception_flags(env, old_flags); \ - return float##size##_val(z); \ - } - -#define GENERATE_SIMPLE_FLOAT2_OPS_32_64(name, function) \ - GENERATE_SIMPLE_FLOAT2_OP(glue(name, s), function, 32) \ - GENERATE_SIMPLE_FLOAT2_OP(glue(name, d), function, 64) - -#define GENERATE_CMP_FLOAT2_OP(ret_type, name, expr, op, in_type, cvt_macro) \ - ret_type HELPER(name)(CPUE2KState *env, in_type x, in_type y) \ - { \ - int old_flags = fp_save_exception_flags(env); \ - ret_type z = expr op(cvt_macro(x), cvt_macro(y), &env->fp_status); \ - fp_merge_exception_flags(env, old_flags); \ - return z ? -1 : 0; \ - } - -#define GENERATE_CMP_XFLOAT2_OP(ret_type, name, expr, op, in_type, cvt_macro) \ - ret_type HELPER(name)(CPUE2KState *env, in_type x, in_type y) \ - { \ - int old_flags = fx_save_exception_flags(env); \ - ret_type z = expr op(cvt_macro(x), cvt_macro(y), &env->fx_status); \ - fx_merge_exception_flags(env, old_flags); \ - return z ? -1 : 0; \ - } - -#define GENERATE_CMP_FLOAT2_OPS_32_64_80(name, expr, op) \ - GENERATE_CMP_FLOAT2_OP(uint32_t, glue3(f, name, s), expr, glue(float32_, op), uint32_t, make_float32) \ - GENERATE_CMP_FLOAT2_OP(uint64_t, glue3(f, name, d), expr, glue(float64_, op), uint64_t, make_float32) \ - GENERATE_CMP_XFLOAT2_OP(uint64_t, glue3(fx, name, x), expr, glue(floatx80_, op), floatx80*, deref) - -#define GENERATE_CVT_FLOAT1_OP(name, from_t, to_t, size_from, size_to, func_from, func_to) \ - size_to HELPER(name)(CPUE2KState *env, size_from x) \ - {\ - int old_flags = fp_save_exception_flags(env); \ - size_to z = func_to( glue3(from_t, _to_, to_t) (func_from(x), &env->fp_status) );\ - fp_merge_exception_flags(env, old_flags); \ - return z; \ - } - -#define GENERATE_CVT_XFLOAT1_OP(name, from_t, to_t, size_from, size_to, func_from, func_to) \ - size_to HELPER(name)(CPUE2KState *env, size_from x) \ - {\ - int old_flags = fx_save_exception_flags(env); \ - size_to z = func_to( glue3(from_t, _to_, to_t) (func_from(x), &env->fx_status) );\ - fx_merge_exception_flags(env, old_flags); \ - return z; \ - } - -GENERATE_SIMPLE_FLOAT2_OPS_32_64(fadd, add) -GENERATE_SIMPLE_FLOAT2_OPS_32_64(fsub, sub) -GENERATE_SIMPLE_FLOAT2_OPS_32_64(fmin, min) -GENERATE_SIMPLE_FLOAT2_OPS_32_64(fmax, max) -GENERATE_SIMPLE_FLOAT2_OPS_32_64(fmul, mul) -GENERATE_SIMPLE_FLOAT2_OPS_32_64(fdiv, div) -GENERATE_CMP_FLOAT2_OPS_32_64_80(cmpeq, , eq) -GENERATE_CMP_FLOAT2_OPS_32_64_80(cmpneq, !, eq) -GENERATE_CMP_FLOAT2_OPS_32_64_80(cmple, , le) -GENERATE_CMP_FLOAT2_OPS_32_64_80(cmpnle, !, le) -GENERATE_CMP_FLOAT2_OPS_32_64_80(cmplt, , lt) -GENERATE_CMP_FLOAT2_OPS_32_64_80(cmpnlt, !, lt) -GENERATE_CMP_FLOAT2_OPS_32_64_80(cmpuod, , unordered) -GENERATE_CMP_FLOAT2_OPS_32_64_80(cmpod, !, unordered) - -GENERATE_CVT_FLOAT1_OP(fstois, float32, int32, uint32_t, uint32_t, make_float32, ident) -GENERATE_CVT_FLOAT1_OP(istofs, int32, float32, uint32_t, uint32_t, ident, float32_val) -GENERATE_CVT_FLOAT1_OP(fstoistr, float32, int32_round_to_zero, uint32_t, uint32_t, make_float32, ident) - -GENERATE_CVT_FLOAT1_OP(fdtoid, float64, int64, uint64_t, uint64_t, make_float64, ident) -GENERATE_CVT_FLOAT1_OP(idtofd, int64, float64, uint64_t, uint64_t, ident, float64_val) -GENERATE_CVT_FLOAT1_OP(fdtoidtr, float64, int64_round_to_zero, uint64_t, uint64_t, make_float64, ident) - -GENERATE_CVT_FLOAT1_OP(fstofd, float32, float64, uint32_t, uint64_t, make_float32, float64_val) -GENERATE_CVT_FLOAT1_OP(fstoid, float32, int64, uint32_t, uint64_t, make_float32, ident) -GENERATE_CVT_FLOAT1_OP(istofd, int32, float64, uint32_t, uint64_t, ident, float64_val) -GENERATE_CVT_FLOAT1_OP(fstoidtr, float32, int64_round_to_zero, uint32_t, uint64_t, make_float32, ident) - -GENERATE_CVT_FLOAT1_OP(fdtofs, float64, float32, uint64_t, uint32_t, make_float64, float32_val) -GENERATE_CVT_FLOAT1_OP(fdtois, float64, int32, uint64_t, uint32_t, make_float64, ident) -GENERATE_CVT_FLOAT1_OP(idtofs, int64, float32, uint64_t, uint32_t, ident, float32_val) -GENERATE_CVT_FLOAT1_OP(fdtoistr, float64, int32_round_to_zero, uint64_t, uint32_t, make_float64, ident) - -GENERATE_CVT_XFLOAT1_OP(fxtofs, floatx80, float32, floatx80*, uint32_t, deref, float32_val) -GENERATE_CVT_XFLOAT1_OP(fxtois, floatx80, int32, floatx80*, uint32_t, deref, ident) -GENERATE_CVT_XFLOAT1_OP(fxtoistr, floatx80, int32_round_to_zero, floatx80*, uint32_t, deref, ident) - -GENERATE_CVT_XFLOAT1_OP(fxtofd, floatx80, float64, floatx80*, uint64_t, deref, float64_val) -GENERATE_CVT_XFLOAT1_OP(fxtoid, floatx80, int64, floatx80*, uint64_t, deref, ident) -GENERATE_CVT_XFLOAT1_OP(fxtoidtr, floatx80, int64_round_to_zero, floatx80*, uint64_t, deref, ident) - -void HELPER(fstofx)(floatx80 *ret, CPUE2KState *env, uint32_t x) -{ - int old_flags = fp_save_exception_flags(env); - *ret = float32_to_floatx80(make_float32(x), &env->fp_status); - fp_merge_exception_flags(env, old_flags); -} - -void HELPER(fdtofx)(floatx80 *ret, CPUE2KState *env, uint64_t x) -{ - int old_flags = fp_save_exception_flags(env); - *ret = float64_to_floatx80(make_float64(x), &env->fp_status); - fp_merge_exception_flags(env, old_flags); -} - -void HELPER(istofx)(floatx80 *ret, CPUE2KState *env, uint32_t x) -{ - int old_flags = fx_save_exception_flags(env); - *ret = int32_to_floatx80(x, &env->fx_status); - fx_merge_exception_flags(env, old_flags); -} - -void HELPER(idtofx)(floatx80 *ret, CPUE2KState *env, uint64_t x) -{ - int old_flags = fx_save_exception_flags(env); - *ret = int64_to_floatx80(x, &env->fx_status); - fx_merge_exception_flags(env, old_flags); -} - -#define GEN_OP2_XX(name, op) \ - void HELPER(name)(CPUE2KState *env, floatx80 *x, floatx80 *y) \ - { \ - int old_flags = fx_save_exception_flags(env); \ - *x = glue(floatx80_, op)(*x, *y, &env->fx_status); \ - fx_merge_exception_flags(env, old_flags); \ - } - -GEN_OP2_XX(fxaddxx, add) -GEN_OP2_XX(fxsubxx, sub) -GEN_OP2_XX(fxmulxx, mul) -GEN_OP2_XX(fxdivxx, div) - -void HELPER(fxrsubxx)(CPUE2KState *env, floatx80 *x, floatx80 *y) -{ - int old_flags = fx_save_exception_flags(env); - *x = floatx80_sub(*y, *x, &env->fx_status); - fx_merge_exception_flags(env, old_flags); -} - -#define GENERATE_FCMPODF(op, IN, F, cvt_macro, status, save_flags, merge_flags) \ - uint32_t HELPER(op)(CPUE2KState *env, IN _x, IN _y) \ - { \ - int old_flags = save_flags(env); \ - uint32_t ret; \ - F x = cvt_macro(_x); \ - F y = cvt_macro(_y); \ - if (glue(F, _is_any_nan)(x) || glue(F, _is_any_nan)(y)) { \ - ret = 0x45; \ - } else { \ - FloatRelation relation = glue(F, _compare_quiet)(x, y, status); \ - switch(relation) \ - { \ - case float_relation_less: \ - ret = 0x01; \ - break; \ - case float_relation_greater: \ - ret = 0x00; \ - break; \ - case float_relation_equal: \ - ret = 0x40; \ - break; \ - case float_relation_unordered: \ - default: \ - ret = 0x45; \ - break; \ - } \ - } \ - merge_flags(env, old_flags); \ - return ret; \ - } -GENERATE_FCMPODF(fcmpodsf, uint32_t, float32, make_float32, &env->fp_status, - fp_save_exception_flags, fp_merge_exception_flags) -GENERATE_FCMPODF(fcmpoddf, uint64_t, float64, make_float64, &env->fp_status, - fp_save_exception_flags, fp_merge_exception_flags) -GENERATE_FCMPODF(fxcmpodxf, floatx80 *, floatx80, deref, &env->fx_status, - fx_save_exception_flags, fx_merge_exception_flags) - -/* didn't found any difference between these instruction - so keep it that way for now */ -uint32_t HELPER(fcmpudsf)(CPUE2KState *env, float32 x, float32 y) -{ - return HELPER(fcmpodsf)(env, x, y); -} - -uint32_t HELPER(fcmpuddf)(CPUE2KState *env, float64 x, float64 y) -{ - return HELPER(fcmpoddf)(env, x, y); -} - -uint32_t HELPER(fxcmpudxf)(CPUE2KState *env, floatx80 *x, floatx80 *y) -{ - return HELPER(fxcmpodxf)(env, x, y); -} - #define TOIF_RC_CURRENT 0x4 #define TOIF_RC_IGNORE_INEXACT 0x8 -static inline void toif_set_round_mode(CPUE2KState *env, uint32_t flags, - float_status *s) +static inline void toif_set_round_mode(uint32_t flags, float_status *s) { if ((flags & TOIF_RC_CURRENT) == 0) { set_float_rounding_mode(rm[flags & FP_RC_CHOP], s); } } -static inline void toif_clear_inexact(CPUE2KState *env, uint32_t flags, - float_status *s) +static inline void toif_clear_inexact(uint32_t flags, float_status *s) { if(flags & TOIF_RC_IGNORE_INEXACT) { int new_flags = get_float_exception_flags(s); @@ -294,59 +94,6 @@ static inline void toif_clear_inexact(CPUE2KState *env, uint32_t flags, } } -uint32_t HELPER(fstoifs)(CPUE2KState *env, uint32_t flags, uint32_t f) -{ - int old_flags = fp_save_exception_flags(env); - FloatRoundMode oldrm = get_float_rounding_mode(&env->fp_status); - uint32_t ret; - toif_set_round_mode(env, flags, &env->fp_status); - ret = float32_val(float32_round_to_int(make_float32(f), &env->fp_status)); - set_float_rounding_mode(oldrm, &env->fp_status); - toif_clear_inexact(env, flags, &env->fp_status); - fp_merge_exception_flags(env, old_flags); - return ret; -} - -uint64_t HELPER(fdtoifd)(CPUE2KState *env, uint64_t flags, uint64_t f) -{ - int old_flags = fp_save_exception_flags(env); - FloatRoundMode oldrm = get_float_rounding_mode(&env->fp_status); - uint64_t ret; - toif_set_round_mode(env, flags, &env->fp_status); - ret = float64_val(float64_round_to_int(make_float64(f), &env->fp_status)); - set_float_rounding_mode(oldrm, &env->fp_status); - toif_clear_inexact(env, flags, &env->fp_status); - fp_merge_exception_flags(env, old_flags); - return ret; -} - -/* TODO: test if valid, test exception flags */ -uint32_t HELPER(frcps)(CPUE2KState *env, uint32_t x) -{ - int old_flags = fp_save_exception_flags(env); - uint32_t y = float32_div(float32_one, make_float32(x), &env->fp_status); - fp_merge_exception_flags(env, old_flags); - return float32_val(y); -} - -uint32_t HELPER(fsqrts)(CPUE2KState *env, uint32_t x) -{ - int old_flags = fp_save_exception_flags(env); - uint32_t y = float32_sqrt(make_float32(x), &env->fp_status); - fp_merge_exception_flags(env, old_flags); - return float32_val(y); -} - -uint32_t HELPER(frsqrts)(CPUE2KState *env, uint32_t x) -{ - int old_flags = fp_save_exception_flags(env); - uint32_t y = float32_div(float32_one, - float32_sqrt(make_float32(x), &env->fp_status), - &env->fp_status); - fp_merge_exception_flags(env, old_flags); - return float32_val(y); -} - #ifdef TARGET_E2K_PRECISE_FSQRTID uint64 HELPER(fsqrtid)(CPUE2KState *env, uint64_t x) { @@ -355,21 +102,6 @@ uint64 HELPER(fsqrtid)(CPUE2KState *env, uint64_t x) } #endif -uint64_t HELPER(fsqrttd)(CPUE2KState *env, uint64_t x, uint64_t unused) -{ - int old_flags = fp_save_exception_flags(env); - uint64_t y = float64_sqrt(make_float64(x), &env->fp_status); - fp_merge_exception_flags(env, old_flags); - return float64_val(y); -} - -void HELPER(fxsqrttxx)(CPUE2KState *env, floatx80 *x, floatx80 *unused) -{ - int old_flags = fx_save_exception_flags(env); - *x = floatx80_sqrt(*x, &env->fx_status); - fx_merge_exception_flags(env, old_flags); -} - #define IMPL_FSCALE(name, ty, exp_len, exp_off, mul, cvt) \ ty HELPER(name)(CPUE2KState *env, ty src1, uint32_t src2) \ { \ @@ -398,26 +130,315 @@ void HELPER(fxsqrttxx)(CPUE2KState *env, floatx80 *x, floatx80 *unused) IMPL_FSCALE(fscaled, uint64_t, 11, 52, helper_fmuld, uint64_to_float64) IMPL_FSCALE(fscales, uint32_t, 8, 23, helper_fmuls, uint32_to_float32) -void HELPER(fxscalesx)(CPUE2KState *env, floatx80 *src1, uint32_t src2) +void HELPER(fxscalesx)(floatx80 *r, CPUE2KState *env, floatx80 *a, uint32_t b) { - floatx80 s2; - int32_t p = (int32_t) src2; + floatx80 v; + int32_t p = (int32_t) b; uint16_t max = (1 << 15) - 1; int16_t bias = max >> 1; if (p <= -bias) { - s2.high = 0; + v.high = 0; p += bias + 62; if (p >= 0 && p < 63) { - s2.low = 1ULL << p; + v.low = 1ULL << p; } else { - s2.low = p == -1; + v.low = p == -1; } } else if (p > bias) { - s2.low = 1UL << 63; - s2.high = max; + v.low = 1UL << 63; + v.high = max; } else { - s2.low = 1UL << 63; - s2.high = bias + p; + v.low = 1UL << 63; + v.high = bias + p; } - helper_fxmulxx(env, src1, &s2); + helper_fxmulxx(r, env, a, &v); } + +#define type_name_i32 int32 +#define type_name_i64 int64 +#define type_name_f32 float32 +#define type_name_f64 float64 +#define type_name_f80 floatx80 +#define type_name(S) glue(type_name_, S) + +#define arg_type_i32 uint32_t +#define arg_type_i64 uint64_t +#define arg_type_f32 uint32_t +#define arg_type_f64 uint64_t +#define arg_type_f80 floatx80 * +#define arg_type(S) glue(arg_type_, S) + +#define ret_arg_i32 +#define ret_arg_i64 +#define ret_arg_f32 +#define ret_arg_f64 +#define ret_arg_f80 floatx80 *ret, +#define ret_arg(S) glue(ret_arg_, S) + +#define ret_type_i32 uint32_t +#define ret_type_i64 uint64_t +#define ret_type_f32 uint32_t +#define ret_type_f64 uint64_t +#define ret_type_f80 void +#define ret_type(S) glue(ret_type_, S) + +#define make_i32(v) (v) +#define make_i64(v) (v) +#define make_f32(v) make_float32(v) +#define make_f64(v) make_float64(v) +#define make_f80(v) (*(v)) +#define make(S, v) glue(make_, S)(v) + +#define type_i32 uint32_t +#define type_i64 uint64_t +#define type_f32 float32 +#define type_f64 float64 +#define type_f80 floatx80 +#define type(S) glue(type_, S) + +#define int32_to_int32(v, s) (v) +#define int64_to_int64(v, s) (v) +#define float32_to_float32(v, s) (v) +#define float64_to_float64(v, s) (v) +#define floatx80_to_floatx80(v, s) (v) +#define convert(F, T, v, s) glue3(type_name(F), _to_, type_name(T))(v, s) + +#define ret_i32(v) return (v) +#define ret_i64(v) return (v) +#define ret_f32(v) return float32_val(v) +#define ret_f64(v) return float64_val(v) +#define ret_f80(v) *ret = v +#define ret(S, v) glue(ret_, S)(v) + +#define fpu_mov(x, s) (x) +#define ident(x) (x) +#define not(x) (!(x)) + +#define IMPL_ALOPF2_FPU_BASIC(FPU, name, S2, R, T2, TR, op) \ + ret_type(R) HELPER(name)(ret_arg(R) CPUE2KState *env, arg_type(S2) s2) \ + { \ + int old_flags = glue(FPU, _save_exception_flags)(env); \ + float_status *s = &env->glue(FPU, _status); \ + type(T2) t2 = convert(S2, T2, make(S2, s2), s); \ + type(TR) tr = op(t2, s); \ + type(R) r = convert(TR, R, tr, s); \ + glue(FPU, _merge_exception_flags)(env, old_flags); \ + ret(R, r); \ + } + +#define IMPL_ALOPF2_FPU(FPU, name, S2, R, op) \ + IMPL_ALOPF2_FPU_BASIC(FPU, name, S2, R, S2, R, op) + +#define IMPL_ALOPF2_FP(name, S2, R, op) \ + IMPL_ALOPF2_FPU_BASIC(fp, name, R, S2, R, S2, op) + +#define IMPL_ALOPF2_FPU_CVT(FPU, name, S2, R) \ + IMPL_ALOPF2_FPU_BASIC(FPU, name, S2, R, R, R, fpu_mov) + +#define IMPL_ALOPF1_FPU(FPU, name, S1, S2, R, T1, T2, TR, op) \ + ret_type(R) HELPER(name)(ret_arg(R) CPUE2KState *env, \ + arg_type(S1) s1, arg_type(S2) s2) \ + { \ + int old_flags = glue(FPU, _save_exception_flags)(env); \ + float_status *s = &env->glue(FPU, _status); \ + type(T1) t1 = convert(S1, T1, make(S1, s1), s); \ + type(T2) t2 = convert(S2, T2, make(S2, s2), s); \ + type(TR) tr = op(t1, t2, s); \ + type(R) r = convert(TR, R, tr, s); \ + glue(FPU, _merge_exception_flags)(env, old_flags); \ + ret(R, r); \ + } + +#define IMPL_ALOPF1_FX(name, S1, S2, R, op) \ + IMPL_ALOPF1_FPU(fx, name, S1, S2, R, f80, f80, f80, op) + +#define IMPL_ALOPF1_FP(name, S1, S2, R, op) \ + IMPL_ALOPF1_FPU(fp, name, S1, S2, R, S1, S2, R, op) + +#define IMPL_ALOPF1_FPU_CMP_BASIC(FPU, name, S1, S2, R, T1, T2, TR, op1, op2) \ + ret_type(R) HELPER(name)(ret_arg(R) CPUE2KState *env, \ + arg_type(S1) s1, arg_type(S2) s2) \ + { \ + int old_flags = glue(FPU, _save_exception_flags)(env); \ + float_status *s = &env->glue(FPU, _status); \ + type(T1) t1 = convert(S1, T1, make(S1, s1), s); \ + type(T2) t2 = convert(S2, T2, make(S2, s2), s); \ + type(TR) tr = op2(op1(t1, t2, s)) ? -1 : 0; \ + type(R) r = convert(TR, R, tr, s); \ + glue(FPU, _merge_exception_flags)(env, old_flags); \ + ret(R, r); \ + } + +#define IMPL_ALOPF1_FPU_CMP(FPU, name, S1, S2, R, T, op1, op2) \ + IMPL_ALOPF1_FPU_CMP_BASIC(FPU, name, S1, S2, R, T, T, R, op1, op2) + +#define IMPL_ALOPF1_FX_MANY(name, op) \ + IMPL_ALOPF1_FX(glue3(fx, name, ss), f80, f32, f32, op) \ + IMPL_ALOPF1_FX(glue3(fx, name, dd), f80, f64, f64, op) \ + IMPL_ALOPF1_FX(glue3(fx, name, sx), f80, f32, f80, op) \ + IMPL_ALOPF1_FX(glue3(fx, name, dx), f80, f64, f80, op) \ + IMPL_ALOPF1_FX(glue3(fx, name, xx), f80, f80, f80, op) \ + IMPL_ALOPF1_FX(glue3(fx, name, xd), f80, f80, f64, op) \ + IMPL_ALOPF1_FX(glue3(fx, name, xs), f80, f80, f32, op) + +IMPL_ALOPF1_FX_MANY(add, floatx80_add) +IMPL_ALOPF1_FX_MANY(sub, floatx80_sub) +IMPL_ALOPF1_FX_MANY(mul, floatx80_mul) +IMPL_ALOPF1_FX_MANY(div, floatx80_div) + +#define floatx80_rsub(x, y, s) floatx80_sub(y, x, s) + +IMPL_ALOPF1_FX(fxrsubss, f80, f32, f32, floatx80_rsub) +IMPL_ALOPF1_FX(fxrsubdd, f80, f64, f64, floatx80_rsub) +IMPL_ALOPF1_FX(fxrsubsx, f80, f32, f80, floatx80_rsub) +IMPL_ALOPF1_FX(fxrsubdx, f80, f64, f80, floatx80_rsub) + +IMPL_ALOPF1_FX(fxdivtss, f32, f80, f32, floatx80_div) +IMPL_ALOPF1_FX(fxdivtdd, f64, f80, f64, floatx80_div) +IMPL_ALOPF1_FX(fxdivtsx, f32, f80, f80, floatx80_div) +IMPL_ALOPF1_FX(fxdivtdx, f64, f80, f80, floatx80_div) + +static floatx80 fxsqrtt(floatx80 a, floatx80 b, float_status *s) +{ + // TODO: fxsqrtt + return floatx80_sqrt(a, s); +} + +IMPL_ALOPF1_FX(fxsqrttsx, f32, f80, f80, fxsqrtt) +IMPL_ALOPF1_FX(fxsqrttdx, f64, f80, f80, fxsqrtt) +IMPL_ALOPF1_FX(fxsqrttxx, f80, f80, f80, fxsqrtt) + +#define CMPODF_BASIC(p, x, y, s) ({ \ + uint32_t ret = 0x45; \ + if (!glue(p, _is_any_nan)(x) && !glue(p, _is_any_nan)(y)) { \ + FloatRelation relation = glue(p, _compare_quiet)(x, y, s); \ + switch (relation) { \ + case float_relation_greater: ret = 0x00; break; \ + case float_relation_less: ret = 0x01; break; \ + case float_relation_equal: ret = 0x40; break; \ + case float_relation_unordered: ret = 0x45; break; \ + } \ + } \ + ret;\ +}) + +#define FXCMPODF(x, y, s) CMPODF_BASIC(floatx80, x, y, s) +#define FCMPODDF(x, y, s) CMPODF_BASIC(float64, x, y, s) +#define FCMPODSF(x, y, s) CMPODF_BASIC(float32, x, y, s) +// TODO: cmpudf +#define FXCMPUDF FXCMPODF +#define FCMPUDSF FCMPODSF +#define FCMPUDDF FCMPODDF + +#define IMPL_CMPF_FX(name, S1, S2, op) \ + IMPL_ALOPF1_FPU(fx, name, S1, S2, i32, f80, f80, i32, op) + +IMPL_CMPF_FX(fxcmpodsf, f80, f32, FXCMPODF) +IMPL_CMPF_FX(fxcmpoddf, f80, f64, FXCMPODF) +IMPL_CMPF_FX(fxcmpodxf, f80, f80, FXCMPODF) + +IMPL_CMPF_FX(fxcmpudsf, f80, f32, FXCMPUDF) +IMPL_CMPF_FX(fxcmpuddf, f80, f64, FXCMPUDF) +IMPL_CMPF_FX(fxcmpudxf, f80, f80, FXCMPUDF) + +#define IMPL_CMPF_FP(name, T, R, op) \ + IMPL_ALOPF1_FPU(fp, name, T, T, R, T, T, R, op) + +IMPL_CMPF_FP(fcmpodsf, f32, i32, FCMPODSF) +IMPL_CMPF_FP(fcmpoddf, f64, i64, FCMPODDF) + +IMPL_CMPF_FP(fcmpudsf, f32, i32, FCMPUDSF) +IMPL_CMPF_FP(fcmpuddf, f64, i64, FCMPUDDF) + +#define cmp_op(T, op) glue3(type_name(T), _, op) + +#define IMPL_ALOPF1_FPU_CMP_ALL(F, P, S, T, R, A, B) \ + IMPL_ALOPF1_FPU_CMP(F, glue3(P, cmpeq, S), A, B, R, T, cmp_op(T, eq), ident) \ + IMPL_ALOPF1_FPU_CMP(F, glue3(P, cmpneq, S), A, B, R, T, cmp_op(T, eq), not) \ + IMPL_ALOPF1_FPU_CMP(F, glue3(P, cmple, S), A, B, R, T, cmp_op(T, le), ident) \ + IMPL_ALOPF1_FPU_CMP(F, glue3(P, cmpnle, S), A, B, R, T, cmp_op(T, le), not) \ + IMPL_ALOPF1_FPU_CMP(F, glue3(P, cmplt, S), A, B, R, T, cmp_op(T, lt), ident) \ + IMPL_ALOPF1_FPU_CMP(F, glue3(P, cmpnlt, S), A, B, R, T, cmp_op(T, lt), not) \ + IMPL_ALOPF1_FPU_CMP(F, glue3(P, cmpuod, S), A, B, R, T, cmp_op(T, unordered), ident) \ + IMPL_ALOPF1_FPU_CMP(F, glue3(P, cmpod, S), A, B, R, T, cmp_op(T, unordered), not) + +IMPL_ALOPF1_FPU_CMP_ALL(fp, f, s, f32, i32, f32, f32) +IMPL_ALOPF1_FPU_CMP_ALL(fp, f, d, f64, i64, f64, f64) +IMPL_ALOPF1_FPU_CMP_ALL(fx, fx, s, f80, i64, f80, f32) +IMPL_ALOPF1_FPU_CMP_ALL(fx, fx, d, f80, i64, f80, f64) +IMPL_ALOPF1_FPU_CMP_ALL(fx, fx, x, f80, i64, f80, f80) + +IMPL_ALOPF2_FPU_CVT(fp, fstofd, f32, f64) +IMPL_ALOPF2_FPU_CVT(fx, fstofx, f32, f80) +IMPL_ALOPF2_FPU_CVT(fp, fstois, f32, i32) +IMPL_ALOPF2_FPU_CVT(fp, fstoid, f32, i64) + +IMPL_ALOPF2_FPU_CVT(fp, fdtofs, f64, f32) +IMPL_ALOPF2_FPU_CVT(fx, fdtofx, f64, f80) +IMPL_ALOPF2_FPU_CVT(fp, fdtois, f64, i32) +IMPL_ALOPF2_FPU_CVT(fp, fdtoid, f64, i64) + +IMPL_ALOPF2_FPU_CVT(fx, fxtofs, f80, f32) +IMPL_ALOPF2_FPU_CVT(fx, fxtofd, f80, f64) +IMPL_ALOPF2_FPU_CVT(fx, fxtois, f80, i32) +IMPL_ALOPF2_FPU_CVT(fx, fxtoid, f80, i64) + +IMPL_ALOPF2_FPU_CVT(fp, istofs, i32, f32) +IMPL_ALOPF2_FPU_CVT(fp, istofd, i32, f64) +IMPL_ALOPF2_FPU_CVT(fx, istofx, i32, f80) + +IMPL_ALOPF2_FPU_CVT(fp, idtofs, i64, f32) +IMPL_ALOPF2_FPU_CVT(fp, idtofd, i64, f64) +IMPL_ALOPF2_FPU_CVT(fx, idtofx, i64, f80) + +IMPL_ALOPF2_FPU(fp, fstoistr, f32, i32, float32_to_int32_round_to_zero) +IMPL_ALOPF2_FPU(fp, fstoidtr, f32, i64, float32_to_int64_round_to_zero) +IMPL_ALOPF2_FPU(fp, fdtoistr, f64, i32, float64_to_int32_round_to_zero) +IMPL_ALOPF2_FPU(fp, fdtoidtr, f64, i64, float64_to_int64_round_to_zero) +IMPL_ALOPF2_FPU(fx, fxtoistr, f80, i32, floatx80_to_int32_round_to_zero) +IMPL_ALOPF2_FPU(fx, fxtoidtr, f80, i64, floatx80_to_int64_round_to_zero) + +#define IMPL_FTOIF(name, A, B) \ + static type(B) name(type(A) flags, type(B) f, float_status *s) \ + { \ + FloatRoundMode oldrm = get_float_rounding_mode(s); \ + type(B) ret; \ + \ + toif_set_round_mode(flags, s); \ + ret = glue(type_name(B), _round_to_int)(f, s); \ + set_float_rounding_mode(oldrm, s); \ + toif_clear_inexact(flags, s); \ + return ret; \ + } + +IMPL_FTOIF(fstoifs, i32, f32) +IMPL_FTOIF(fdtoifd, i64, f64) + +IMPL_ALOPF1_FP(fstoifs, i32, f32, f32, fstoifs) +IMPL_ALOPF1_FP(fdtoifd, i64, f64, f64, fdtoifd) + +/* TODO: frcps: test if valid, test exception flags */ +#define frcps(a, s) float32_div(float32_one, a, s) +#define frsqrts(a, s) float32_div(float32_one, float32_sqrt(a, s), s) + +static float64 fsqrttd(float64 a, float64 b, float_status *s) +{ + // TODO: fxsqrtt + return float64_sqrt(a, s); +} + +#define IMPL_ALOPF1_FP_MANY(S, T) \ + IMPL_ALOPF1_FP(glue(fadd, S), T, T, T, glue(type_name(T), _add)) \ + IMPL_ALOPF1_FP(glue(fsub, S), T, T, T, glue(type_name(T), _sub)) \ + IMPL_ALOPF1_FP(glue(fmul, S), T, T, T, glue(type_name(T), _mul)) \ + IMPL_ALOPF1_FP(glue(fdiv, S), T, T, T, glue(type_name(T), _div)) \ + IMPL_ALOPF1_FP(glue(fmin, S), T, T, T, glue(type_name(T), _min)) \ + IMPL_ALOPF1_FP(glue(fmax, S), T, T, T, glue(type_name(T), _max)) + +IMPL_ALOPF1_FP_MANY(s, f32) +IMPL_ALOPF1_FP_MANY(d, f64) + +IMPL_ALOPF2_FP(fsqrts, f32, f32, float32_sqrt) +IMPL_ALOPF2_FP(frcps, f32, f32, frcps) +IMPL_ALOPF2_FP(frsqrts, f32, f32, frsqrts) +IMPL_ALOPF1_FP(fsqrttd, f64, f64, f64, fsqrttd) diff --git a/target/e2k/helper_int.c b/target/e2k/helper_int.c index 1a1db52e8c..89acf6247d 100644 --- a/target/e2k/helper_int.c +++ b/target/e2k/helper_int.c @@ -5,9 +5,8 @@ #include "exec/exec-all.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" -#include "translate.h" -uint64_t helper_sxt(uint64_t x, uint32_t y) +uint64_t HELPER(sxt)(uint64_t x, uint32_t y) { int size; @@ -36,7 +35,7 @@ static uint64_t cr_read(CPUE2KState *env, size_t offset) return cpu_ldq_le_data(env, addr); } -uint64_t helper_state_reg_read_i64(CPUE2KState *env, int idx) +uint64_t HELPER(rrd)(CPUE2KState *env, int idx) { switch (idx) { case 0x01: return e2k_state_wd(env); /* %wd */ @@ -75,12 +74,7 @@ uint64_t helper_state_reg_read_i64(CPUE2KState *env, int idx) } } -uint32_t helper_state_reg_read_i32(CPUE2KState *env, int idx) -{ - return helper_state_reg_read_i64(env, idx); -} - -void helper_state_reg_write_i64(CPUE2KState *env, int idx, uint64_t val) +void HELPER(rwd)(CPUE2KState *env, int idx, uint64_t val) { switch(idx) { case 0x80: /* %upsr */ @@ -110,7 +104,7 @@ void helper_state_reg_write_i64(CPUE2KState *env, int idx, uint64_t val) } } -void helper_state_reg_write_i32(CPUE2KState *env, int idx, uint32_t val) +void HELPER(rws)(CPUE2KState *env, int idx, uint32_t val) { switch (idx) { case 0x80: /* %upsr */ @@ -134,7 +128,7 @@ void helper_state_reg_write_i32(CPUE2KState *env, int idx, uint32_t val) } } -uint64_t helper_getsp(CPUE2KState *env, uint32_t src2) +uint64_t HELPER(getsp)(CPUE2KState *env, uint32_t src2) { int32_t s2 = src2 & ~0xf; diff --git a/target/e2k/helper_sm.c b/target/e2k/helper_sm.c index ae1c1c2221..6d02cdc8b6 100644 --- a/target/e2k/helper_sm.c +++ b/target/e2k/helper_sm.c @@ -4,7 +4,6 @@ #include "exec/exec-all.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" -#include "translate.h" int HELPER(probe_read_access)(CPUE2KState *env, target_ulong addr) { diff --git a/target/e2k/helper_vec.c b/target/e2k/helper_vec.c index e4a33f8bf8..4a8d23b6c1 100644 --- a/target/e2k/helper_vec.c +++ b/target/e2k/helper_vec.c @@ -5,7 +5,6 @@ #include "exec/exec-all.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" -#include "translate.h" static uint8_t reverse_bits(uint8_t b) { @@ -143,7 +142,8 @@ GEN_HELPER_PACKED_HORIZONTAL_OP(phsubsh, sh, sub, satsh) #define GEN_HELPER_PACKED_SCALAR_BINOP(name, type, op) \ GEN_HELPER_PACKED_SCALAR(name, type, { \ - dst.type[i] = s1.type[i] op s2; \ + int max = sizeof(s1.type[0]) * 8 - 1; \ + dst.type[i] = s2 < s1.type[i] op ( s2 < max ? s2 : max); \ }) GEN_HELPER_PACKED_SCALAR_BINOP(psllh, uh, <<) @@ -153,25 +153,26 @@ GEN_HELPER_PACKED_SCALAR_BINOP(psrlw, uw, >>) #define GEN_HELPER_PACKED_SRA(name, type, t) \ GEN_HELPER_PACKED_SCALAR(name, type, { \ - dst.type[i] = (t) s1.type[i] >> s2; \ + int max = sizeof(s1.type[0]) * 8 - 1; \ + dst.type[i] = (t) s1.type[i] >> (s2 < max ? s2 : max); \ }) GEN_HELPER_PACKED_SRA(psrah, sh, int32_t) GEN_HELPER_PACKED_SRA(psraw, sw, int64_t) -#define GEN_HELPER_PACKED_MAD(name, dst_type, type, cast, op) \ +#define GEN_HELPER_PACKED_MAD(name, dst_type, t0, t1, cast, op) \ GEN_HELPER_PACKED(name, dst_type, { \ int j = i * 2; \ dst.dst_type[i] = op( \ - (cast) s1.type[j + 1] * s2.type[j + 1] + \ - (cast) s1.type[j ] * s2.type[j ] \ + (cast) s1.t0[j + 1] * s2.t1[j + 1] + \ + (cast) s1.t0[j ] * s2.t1[j ] \ ); \ }) -GEN_HELPER_PACKED_MAD(pmaddh, sw, sh, int32_t, ident) -GEN_HELPER_PACKED_MAD(pmaddubsh, sh, ub, int16_t, satsh) +GEN_HELPER_PACKED_MAD(pmaddh, sw, sh, sh, int32_t, ident) +GEN_HELPER_PACKED_MAD(pmaddubsh, sh, sb, ub, int32_t, satsh) -GEN_HELPER_PACKED(psadbw, ub, { dst.uw[0] += s1.ub[i] - s2.ub[i]; }) +GEN_HELPER_PACKED(psadbw, ub, { dst.uw[0] += abs(s1.ub[i] - s2.ub[i]); }) GEN_HELPER_PACKED(pavgusb, ub, { dst.ub[i] = (s1.ub[i] + s2.ub[i] + 1) >> 1; }) GEN_HELPER_PACKED(pavgush, uh, { dst.uh[i] = (s1.uh[i] + s2.uh[i] + 1) >> 1; }) @@ -187,7 +188,7 @@ GEN_HELPER_PACKED_MULH(pmulhuh, uh, uint32_t, shr16) GEN_HELPER_PACKED_MULH(pmulhrsh, sh, int32_t, shr14_add1_shr1) GEN_HELPER_PACKED(pmulubhh, uh, { \ - dst.uh[i] = (((int16_t) s1.ub[i] * s2.sh[i]) + s1.ub[i]) >> 8; \ + dst.uh[i] = ((int16_t) s1.ub[i] * s2.sh[i] + 0x80) >> 8; \ }) GEN_HELPER_PACKED(mpsadbh, uh, { \ @@ -246,28 +247,19 @@ uint64_t HELPER(pshufb)(uint64_t src1, uint64_t src2, uint64_t src3) for (i = 0; i < 8; i++) { uint8_t desc = s3.ub[i]; - int index = extract8(desc, 0, 3); - uint8_t byte; + int index = desc & 7; + uint8_t byte = desc & 8 ? s1.ub[index] : s2.ub[index]; - if (desc < 0x80) { - byte = desc & 0x08 ? s1.ub[index] : s2.ub[index]; + byte = desc & 0x10 ? ~byte : byte; + byte = desc & 0x20 ? reverse_bits(byte) : byte; + byte = desc & 0x40 ? (byte & 0x80 ? 0xff : 0) : byte; - switch(desc >> 5) { - case 0x1: byte = reverse_bits(byte); break; - case 0x2: byte = (byte & 0x80) != 0 ? 0xff : 0; break; - case 0x3: byte = (byte & 1) != 0 ? 0xff : 0; break; - default: break; - } - - if (desc & 0x10) { - byte = ~byte; - } - } else { - switch(desc >> 6) { - case 0xa: byte = 0x7f; break; - case 0xc: byte = 0x80; break; - case 0xe: byte = 0xff; break; - default: byte = 0; break; + if (desc & 0x80) { + switch ((desc & 0x70) >> 4) { + case 2: byte = 0x7f; break; + case 4: byte = 0x80; break; + case 6: byte = 0xff; break; + default: byte = 0; break; } } diff --git a/target/e2k/meson.build b/target/e2k/meson.build index 0174e45dc5..94d89dd5eb 100644 --- a/target/e2k/meson.build +++ b/target/e2k/meson.build @@ -9,10 +9,6 @@ e2k_ss.add(files( 'helper_sm.c', 'helper_vec.c', 'translate.c', - 'translate/alc.c', - 'translate/aau.c', - 'translate/plu.c', - 'translate/state.c', )) # no softmmu support yet diff --git a/target/e2k/translate.c b/target/e2k/translate.c index 1ece553511..d1f52001f5 100644 --- a/target/e2k/translate.c +++ b/target/e2k/translate.c @@ -1,10 +1,627 @@ #include "qemu/osdep.h" #include "qemu.h" #include "exec/log.h" -#include "disas/disas.h" -#include "translate.h" +#include "exec/translator.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" -struct CPUE2KStateTCG e2k_cs; +#define glue3(a, b, c) glue(glue(a, b), c) +#define glue4(a, b, c, d) glue(glue(a, b), glue(c, d)) + +#define DYNAMIC -1 + +#define IS_BASED(i) (((i) & 0x80) == 0) +#define IS_REGULAR(i) (((i) & 0xc0) == 0x80) +#define IS_IMM5(i) (((i) & 0xe0) == 0xc0) +#define IS_IMM4(i) (((i) & 0xf0) == 0xc0) +#define IS_LIT(i) (((i) & 0xf0) == 0xd0) +#define IS_LIT16_LO(i) (((i) & 0x0e) == 0x00) +#define IS_LIT16_HI(i) (((i) & 0x0e) == 0x04) +#define IS_LIT32(i) (((i) & 0x0c) == 0x08) +#define IS_LIT64(i) (((i) & 0x0c) == 0x0c) +#define IS_GLOBAL(i) (((i) & 0xe0) == 0xe0) + +#define GET_BASED(i) ((i) & 0x7f) +#define GET_REGULAR(i) ((i) & 0x3f) +#define GET_IMM5(i) ((i) & 0x1f) +#define GET_IMM4(i) ((i) & 0x0f) +#define GET_LIT(i) ((i) & 0x03) +#define GET_GLOBAL(i) ((i) & 0x1f) + +#define type_name_x ptr +#define type_name_d i64 +#define type_name_s i32 +#define type_name(s) glue(type_name_, s) + +#define call(s, name, ...) glue3(name, _, type_name(s))(__VA_ARGS__) + +#define tagged(s) glue(Tagged_, type_name(s)) +#define tagged_new(s) glue(tagged_new_, type_name(s))() +#define tagged_local_new(s) glue(tagged_local_new_, type_name(s))() +#define tagged_free(s, t) glue(tagged_free_, type_name(s))(t) + +#define temp(s) glue(TCGv_, type_name(s)) +#define temp_new(s) glue(tcg_temp_new_, type_name(s))() +#define temp_local_new(s) glue(tcg_temp_local_new_, type_name(S))() +#define temp_free(s, t) glue(tcg_temp_free_, type_name(s))(t) + +#define gen_tagged_src(i, s, instr, ret) \ + glue4(gen_tagged_src, i, _, s)(instr, ret) + +#define gen_tag3x(r, a, b, c) gen_tag3_i64(r.tag, a.tag, b.tag, c.tag) +#define gen_tag3d(r, a, b, c) gen_tag3_i64(r.tag, a.tag, b.tag, c.tag) +#define gen_tag3s(r, a, b, c) gen_tag3_i32(r.tag, a.tag, b.tag, c.tag) +#define gen_tag3(s, r, a, b, c) glue(gen_tag3, s)(r, a, b, c) + +#define gen_tag2x(r, a, b) gen_tag2_i64(r.tag, a.tag, b.tag) +#define gen_tag2d(r, a, b) gen_tag2_i64(r.tag, a.tag, b.tag) +#define gen_tag2s(r, a, b) gen_tag2_i32(r.tag, a.tag, b.tag) +#define gen_tag2(s, r, a, b) glue(gen_tag2, s)(r, a, b) + +#define gen_tag1x(r, a) gen_tag1_i64(r.tag, a.tag) +#define gen_tag1d(r, a) gen_tag1_i64(r.tag, a.tag) +#define gen_tag1s(r, a) gen_tag1_i32(r.tag, a.tag) +#define gen_tag1(s, r, a) glue(gen_tag1, s)(r, a) + +#define gen_result_init_s(i, r) +#define gen_result_init_d(i, r) +#define gen_result_init_x(i, r) gen_temp_result_ptr(r.val, instr->chan) +#define gen_result_init(R, instr, r) glue(gen_result_init_, R)(instr, r) + +#define gen_al_result(R, instr, r) glue(gen_al_result_, R)(instr, r) + +#define gen_extrl_i32 tcg_gen_mov_i32 +#define gen_extrl_i64 tcg_gen_extrl_i64_i32 + +typedef enum { + ALES_NONE = 0x00, + ALES_PRESENT = 0x01, + ALES_ALLOCATED = 0x02, +} AlesFlag; + +static TCGv cpu_pc; +static TCGv cpu_npc; +static TCGv_i64 cpu_ctprs[3]; +static TCGv_i32 cpu_ct_cond; +static TCGv_i32 cpu_is_bp; /* breakpoint flag */ +static TCGv_i32 cpu_wdbl; +static TCGv_i32 cpu_wd_base; /* holds wbs * 2 */ +static TCGv_i32 cpu_wd_size; /* holds wsz * 2 */ +static TCGv_i32 cpu_boff; /* holds rbs * 2 */ +static TCGv_i32 cpu_bsize; /* holds rsz * 2 + 2 */ +static TCGv_i32 cpu_bcur; /* holds rcur * 2 */ +static TCGv_i64 cpu_pregs; +static TCGv_i32 cpu_psize; /* holds psz */ +static TCGv_i32 cpu_pcur; /* holds pcur */ +static TCGv_i64 cpu_last_value; +/* lsr */ +static TCGv_i32 cpu_lsr_lcnt; +static TCGv_i32 cpu_lsr_ecnt; +static TCGv_i32 cpu_lsr_vlc; +static TCGv_i32 cpu_lsr_over; +static TCGv_i32 cpu_lsr_pcnt; +static TCGv_i32 cpu_lsr_strmd; +/* AAU */ +static TCGv_i32 cpu_aasti[16]; +static TCGv_i32 cpu_aasti_tags; +static TCGv_i32 cpu_aaind[16]; +static TCGv_i32 cpu_aaind_tags; +static TCGv_i32 cpu_aaincr[8]; +static TCGv_i32 cpu_aaincr_tags; +static TCGv_i64 cpu_aad_lo[32]; +static TCGv_i64 cpu_aad_hi[32]; + +typedef struct { + uint32_t hs; + uint32_t ss; + uint32_t als[6]; + uint32_t cs0; + uint16_t ales[6]; + uint32_t cs1; + uint16_t aas[6]; + uint32_t lts[4]; + uint32_t pls[3]; + uint32_t cds[3]; + + bool ss_present; + bool als_present[6]; + bool cs0_present; + AlesFlag ales_present[6]; + bool cs1_present; + bool aas_present[6]; + bool lts_present[4]; + bool pls_present[3]; + bool cds_present[3]; +} UnpackedBundle; + +typedef struct { + int32_t sdisp; /* CS0 28:0 */ +} Cs0IBranch, Cs0Puttsd; + +typedef struct { + int32_t sdisp; /* CS0 28:0 */ + uint8_t ipd; /* SS 31:30 */ + uint8_t ctpr; /* CS0 31:30 */ + uint8_t opc; +} Cs0Disp; + +typedef struct { + uint32_t disp; /* CS0 28:0 */ + uint8_t ipd; /* SS 31:30 */ + uint8_t ctpr; /* CS0 31:30 */ +} Cs0SDisp; + +typedef struct { + uint8_t ipd; +} Cs0Return; + +typedef struct { + uint32_t disp; /* 28:4 */ + uint8_t prefr; /* 2:0 */ + uint8_t ipd; /* 3 */ +} Cs0Pref; + +typedef enum { + CS0_NONE, + CS0_IBRANCH, + CS0_PREF, + CS0_PUTTSD, + CS0_DONE, + CS0_HRET, + CS0_GLAUNCH, + CS0_DISP, + CS0_SDISP, + CS0_GETTSD, + CS0_RETURN, +} Cs0Type; + +typedef struct { + Cs0Type type; + union { + Cs0IBranch ibranch; + Cs0Puttsd puttsd; + Cs0Disp disp; + Cs0SDisp sdisp; + Cs0Pref pref; + Cs0Return ret; + }; +} Cs0; + +typedef enum { + SETR_VFRPSZ = 0x01, + SETR_WD = 0x02, + SETR_BN = 0x04, + SETR_BP = 0x08, +} SetrType; + +typedef struct { + SetrType type; + uint8_t rpsz; + uint8_t wsz; + bool nfx; + bool dbl; + uint8_t rbs; + uint8_t rsz; + uint8_t rcur; + uint8_t psz; +} Cs1Setr; + +typedef struct { + bool ma_c; + bool fl_c; + bool ld_c; + bool st_c; + bool all_e; + bool all_c; + /* v2+ */ + bool trap; + /* v5+ */ + bool sal; + bool sas; +} Cs1Wait; + +typedef struct { + uint8_t wbs; + uint8_t disp; +} Cs1HCall; + +typedef struct { + bool flushr; + bool flushc; +} Cs1Flush; + +typedef struct { + bool chkm4; + uint8_t dmask; + uint8_t umask; +} Cs1Vfbg; + +typedef enum { + CS1_NONE, + CS1_SETR, + CS1_SETEI, + CS1_SETSFT, + CS1_WAIT, + CS1_CALL, + CS1_HCALL, + CS1_MAS, + CS1_FLUSH, + CS1_VFBG, +} Cs1Type; + +typedef struct { + Cs1Type type; + union { + Cs1Setr setr; + uint8_t ei; + Cs1Wait wait; + uint8_t call_wbs; + Cs1HCall hcall; + uint8_t mas[6]; + Cs1Flush flush; + Cs1Vfbg vfbg; + }; +} Cs1; + +typedef enum { + ALOPF_NONE, + ALOPF1, + ALOPF1_MERGE, + ALOPF2, + ALOPF3, + ALOPF7, + ALOPF8, + ALOPF10, + ALOPF11, + ALOPF11_MERGE, + ALOPF11_LIT8, + ALOPF12, + ALOPF12_PSHUFH, + ALOPF12_IBRANCHD, + ALOPF12_ICALLD, + ALOPF13, + ALOPF15, + ALOPF16, + ALOPF17, + ALOPF21, + ALOPF21_ICOMB, + ALOPF21_FCOMB, + ALOPF21_PFCOMB, + ALOPF21_LCOMB, + ALOPF22, +} Alopf; + +typedef struct { + Alopf format; + uint32_t op; + const char *name; +} Alop; + +typedef struct { + Cs0 cs0; + Cs1 cs1; + Alop alops[6]; +} Bundle; + +typedef enum { + AL_RESULT_NONE = 0, + + AL_RESULT_SIZE_MASK = 0x3, + AL_RESULT_32 = 0x00, + AL_RESULT_64 = 0x01, + AL_RESULT_80 = 0x02, + AL_RESULT_128 = 0x03, + + AL_RESULT_TYPE_MASK = 0xc, + AL_RESULT_REG = 0x04, + AL_RESULT_PREG = 0x08, + AL_RESULT_CTPR = 0x0c, + + AL_RESULT_REG32 = AL_RESULT_REG | AL_RESULT_32, + AL_RESULT_REG64 = AL_RESULT_REG | AL_RESULT_64, + AL_RESULT_REG80 = AL_RESULT_REG | AL_RESULT_80, + AL_RESULT_REG128 = AL_RESULT_REG | AL_RESULT_128, + AL_RESULT_CTPR32 = AL_RESULT_CTPR | AL_RESULT_32, + AL_RESULT_CTPR64 = AL_RESULT_CTPR | AL_RESULT_64, +} AlResultType; + +#define e2k_al_result_size(x) ((x) & AL_RESULT_SIZE_MASK) +#define e2k_al_result_type(x) ((x) & AL_RESULT_TYPE_MASK) + +typedef struct { + AlResultType type; + union { + struct { + TCGv_i32 index; + TCGv_i32 tag; + union { + TCGv_i32 v32; + TCGv_i64 v64; + }; + union { + TCGv_i32 x32; /* FX ops */ + TCGv_i64 x64; /* SIMD ops v5+ */ + }; + } reg; + struct { + int index; + union { + TCGv_i32 v32; + TCGv_i64 v64; + }; + } ctpr; + struct { + int index; + TCGv_i32 val; + } preg; + }; +} AlResult; + +typedef struct { + bool is_set; + TCGv_i32 index; + TCGv_i32 tag; + TCGv_i64 value; +} AauResult; + +typedef struct { + int reg; // -1 means do not write + TCGv_i32 value; +} PlResult; + +typedef enum { + CT_NONE, + CT_IBRANCH, + CT_JUMP, + CT_CALL, +} ControlTransferType; + +typedef struct { + ControlTransferType type; + union { + target_ulong target; + TCGv_i64 ctpr; + } u; + int wbs; + uint8_t cond_type; + uint8_t psrc; +} ControlTransfer; + +typedef struct DisasContext { + DisasContextBase base; + UnpackedBundle bundle; + Bundle bundle2; + target_ulong pc; + int jump_ctpr; + int mmuidx; + uint8_t mas[6]; + bool loop_mode; + TCGv_i32 is_epilogue; + /* optional, can be NULL */ + TCGv_i32 mlock; + + int version; + /* Force ILLOP for bad instruction format for cases where real CPU + do not generate it. */ + bool strict; + + // Temporary values. + TCGv_i32 t32[64]; + TCGv_i64 t64[32]; + // Allocated temporary values count. + int t32_len; + int t64_len; + + /* Delayed illegal tag check */ + TCGv_i32 illtag; + bool do_check_illtag; + + /* Delayed window bounds check */ + int wd_size; + int max_r; + int max_r_src; + int max_r_dst; + int bsize; + int max_b; + int max_b_cur; + + TCGv_i64 cond[6]; + AlResult al_results[6]; + TCGv_i32 al_cond[6]; + AauResult aau_results[4]; + int aau_am[4]; + PlResult pl_results[3]; + ControlTransfer ct; +} DisasContext; + +typedef struct { + TCGv_i32 tag; + TCGv_ptr val; +} Tagged_ptr; + +typedef struct { + TCGv_i32 tag; + TCGv_i32 val; +} Tagged_i32; + +typedef struct { + TCGv_i32 tag; + TCGv_i64 val; +} Tagged_i64; + +typedef struct { + DisasContext *ctx; + int chan; + AlesFlag ales_present; + int aaincr_len; + uint8_t mas; + union { + uint32_t als; + struct { + uint32_t src4: 8; + uint32_t src2: 8; + uint32_t src1: 8; + uint32_t opc1: 7; + uint32_t sm: 1; + }; + struct { + uint32_t dst: 8; + uint32_t opce2: 8; + uint32_t opce1: 8; + uint32_t unused1: 8; + }; + struct { + uint32_t dst_preg: 5; + uint32_t opc_cmp: 3; + uint32_t unused2: 24; + }; + /* staa/ldaa/aaurw/aaurr */ + struct { + uint32_t unused3: 8; + uint32_t aalit: 2; + uint32_t aaopc: 2; + uint32_t aaincr: 3; + /* aaind/aasti/aaincr for aaurw/aaurr */ + uint32_t aaind: 4; + uint32_t aad: 5; + uint32_t unused4: 8; + }; + }; + union { + uint16_t ales; + struct { + uint16_t src3: 8; + uint16_t opc2: 8; + }; + struct { + uint16_t opce3: 8; + uint16_t unused5: 8; + }; + }; +} Instr; + +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; + +#include "alops.inc" + +static int16_t alops_map[4][128][6]; + +static inline void gen_save_pc(target_ulong pc) +{ + tcg_gen_movi_tl(cpu_pc, pc); +} + +static inline void gen_save_cpu_state(DisasContext *ctx) +{ + gen_save_pc(ctx->pc); +} + +static inline void gen_tr_exception(DisasContext *ctx, int exception_index) +{ + TCGv_i32 t0 = tcg_const_i32(exception_index); + + ctx->base.is_jmp = DISAS_NORETURN; + gen_save_cpu_state(ctx); + gen_helper_raise_exception(cpu_env, t0); + tcg_temp_free_i32(t0); +} + +#define IMPL_GEN_TR_EXCP(name, excp) \ + static inline void name(DisasContext *ctx) \ + { \ + gen_tr_exception(ctx, excp); \ + } + +IMPL_GEN_TR_EXCP(gen_tr_excp_illopc, EXCP_ILLEGAL_OPCODE) +IMPL_GEN_TR_EXCP(gen_tr_excp_illopn, EXCP_ILLEGAL_OPERAND) +IMPL_GEN_TR_EXCP(gen_tr_excp_window_bounds, EXCP_WINDOW_BOUNDS) +#ifndef TARGET_E2K32 +IMPL_GEN_TR_EXCP(gen_tr_excp_array_bounds, EXCP_ARRAY_BOUNDS) +#endif + +static inline void gen_exception(int excp) +{ + TCGv_i32 t0 = tcg_const_i32(excp); + + // TODO: check if need to save state + gen_helper_raise_exception(cpu_env, t0); + tcg_temp_free_i32(t0); +} + +#define IMPL_GEN_EXCP(name, excp) \ + static inline void name(void) \ + { \ + gen_exception(excp); \ + } + +IMPL_GEN_EXCP(gen_excp_illopc, EXCP_ILLEGAL_OPCODE) +IMPL_GEN_EXCP(gen_excp_window_bounds, EXCP_WINDOW_BOUNDS) + +#define e2k_todo(ctx, fmt, ...) \ + qemu_log(TARGET_FMT_lx ": " fmt " (%s:%d)\n", ctx->pc, \ + ## __VA_ARGS__, __FILE__, __LINE__) + +#define e2k_todo_illop(ctx, fmt, ...) \ + e2k_todo(ctx, fmt, ## __VA_ARGS__); \ + gen_tr_excp_illopc(ctx) + +static inline TCGv_i32 e2k_get_temp_i32(DisasContext *dc) +{ + assert(dc->t32_len < ARRAY_SIZE(dc->t32)); + return dc->t32[dc->t32_len++] = tcg_temp_local_new_i32(); +} + +static inline TCGv_i32 e2k_get_const_i32(DisasContext *dc, uint32_t value) +{ + assert(dc->t32_len < ARRAY_SIZE(dc->t32)); + return dc->t32[dc->t32_len++] = tcg_const_local_i32(value); +} + +static inline TCGv_i64 e2k_get_temp_i64(DisasContext *dc) +{ + assert(dc->t64_len < ARRAY_SIZE(dc->t64)); + return dc->t64[dc->t64_len++] = tcg_temp_local_new_i64(); +} + +#define IMPL_TAGGED_FNS(Self, S) \ + static inline Self glue(tagged_new_, S)(void) \ + { \ + Self r; \ + r.tag = tcg_temp_new_i32(); \ + r.val = glue(tcg_temp_new_, S)(); \ + return r; \ + } \ + \ + static inline Self glue(tagged_local_new_, S)(void) \ + { \ + Self r; \ + r.tag = tcg_temp_local_new_i32(); \ + r.val = glue(tcg_temp_local_new_, S)(); \ + return r; \ + } \ + \ + static inline void glue(tagged_free_, S)(Self t) \ + { \ + tcg_temp_free_i32(t.tag); \ + glue(tcg_temp_free_, S)(t.val); \ + } + +IMPL_TAGGED_FNS(Tagged_i32, i32) +IMPL_TAGGED_FNS(Tagged_i64, i64) +IMPL_TAGGED_FNS(Tagged_ptr, ptr) static inline uint64_t ctpr_new(uint8_t tag, uint8_t opc, uint8_t ipd, target_ulong base) @@ -28,19 +645,15 @@ static void gen_goto_tb(DisasContext *ctx, int tb_num, target_ulong pc) if (translator_use_goto_tb(&ctx->base, pc)) { /* jump to same page: we can use a direct jump */ tcg_gen_goto_tb(tb_num); - tcg_gen_movi_tl(e2k_cs.pc, pc); + tcg_gen_movi_tl(cpu_pc, pc); tcg_gen_exit_tb(ctx->base.tb, tb_num); } else { /* jump to another page: currently not optimized */ - tcg_gen_movi_tl(e2k_cs.pc, pc); + tcg_gen_movi_tl(cpu_pc, pc); tcg_gen_exit_tb(NULL, 0); } } -//////////////////////////////////////////////////////////////////// -//// Decode -//////////////////////////////////////////////////////////////////// - /* returns zero if bundle is invalid */ static size_t unpack_bundle(CPUE2KState *env, DisasContext *ctx) { @@ -452,20 +1065,4600 @@ static inline void decode_ct_cond(DisasContext *ctx, const UnpackedBundle *raw) if (ctx->ct.type == CT_NONE) { ctx->ct.type = CT_JUMP; } - ctx->ct.u.ctpr = e2k_cs.ctprs[ctpr - 1]; + ctx->ct.u.ctpr = cpu_ctprs[ctpr - 1]; } ctx->ct.psrc = extract32(raw->ss, 0, 5); ctx->ct.cond_type = extract32(raw->ss, 5, 4); } -//////////////////////////////////////////////////////////////////// -//// Generate -//////////////////////////////////////////////////////////////////// +static inline void gen_lcntex(TCGv_i32 ret) +{ + tcg_gen_setcondi_i32(TCG_COND_EQ, ret, cpu_lsr_lcnt, 0); +} +static inline bool is_chan_03(int c) +{ + return c == 0 || c == 3; +} + +static inline bool is_chan_14(int c) +{ + return c == 1 || c == 4; +} + +static inline bool is_chan_25(int c) +{ + return c == 2 || c == 5; +} + +static inline bool is_chan_0134(int c) +{ + return is_chan_03(c) || is_chan_14(c); +} + +static inline TCGv_i64 get_temp_i64(Instr *instr) +{ + return e2k_get_temp_i64(instr->ctx); +} + +static inline TCGv_i32 get_temp_i32(Instr *instr) +{ + return e2k_get_temp_i32(instr->ctx); +} + +static inline void gen_ptr_from_index(TCGv_ptr ret, TCGv_ptr ptr, TCGv_i32 idx, + int size) +{ + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_ptr t1 = tcg_temp_new_ptr(); + + tcg_gen_muli_i32(t0, idx, size); + tcg_gen_ext_i32_ptr(t1, t0); + tcg_gen_add_ptr(ret, ptr, t1); + + tcg_temp_free_ptr(t1); + tcg_temp_free_i32(t0); +} + +static inline void gen_preg_index(TCGv_i32 ret, int idx) +{ + TCGv_i32 i = tcg_const_i32(idx); + 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(); + + assert(idx < 32); + + tcg_gen_addi_i32(t0, cpu_psize, 1); + tcg_gen_addi_i32(t1, cpu_pcur, idx); + tcg_gen_remu_i32(t2, t1, t0); + tcg_gen_movi_i32(t3, idx); + tcg_gen_movcond_i32(TCG_COND_LEU, ret, i, cpu_psize, t2, t3); + + tcg_temp_free_i32(t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(i); +} + +static void gen_preg_offset(TCGv_i64 ret, int idx) +{ + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i32 t1 = tcg_temp_new_i32(); + + gen_preg_index(t0, idx); + tcg_gen_muli_i32(t1, t0, 2); + tcg_gen_extu_i32_i64(ret, t1); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); +} + +static void gen_preg_clear(TCGv_i64 ret, TCGv_i64 offset) +{ + TCGv_i64 t0 = tcg_const_i64(3); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + + tcg_gen_shl_i64(t1, t0, offset); + tcg_gen_not_i64(t2, t1); + tcg_gen_and_i64(ret, t2, cpu_pregs); + + tcg_temp_free_i64(t2); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t0); +} + +static inline void gen_preg_i64(TCGv_i64 ret, int reg) +{ + TCGv_i64 one = 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(); + + gen_preg_offset(t0, reg); + tcg_gen_shl_i64(t1, one, t0); + tcg_gen_and_i64(t2, cpu_pregs, t1); + tcg_gen_setcondi_i64(TCG_COND_NE, ret, t2, 0); + + tcg_temp_free_i64(t2); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(one); +} + +static void gen_preg_i32(TCGv_i32 ret, int reg) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + + gen_preg_i64(t0, reg); + tcg_gen_extrl_i64_i32(ret, t0); + tcg_temp_free_i64(t0); +} + +static void gen_preg_set_i32(int idx, TCGv_i32 val) +{ + 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(); + + gen_preg_offset(t0, idx); + gen_preg_clear(t1, t0); + tcg_gen_extu_i32_i64(t2, val); + tcg_gen_andi_i64(t3, t2, 3); + tcg_gen_shl_i64(t4, t2, t0); + tcg_gen_or_i64(cpu_pregs, t1, t4); + + 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); +} + +static void gen_reg_tag_ptr(TCGv_ptr ret, TCGv_i32 idx) +{ + TCGv_ptr t0 = tcg_temp_new_ptr(); + TCGv_ptr t1 = tcg_temp_new_ptr(); + + tcg_gen_ext_i32_ptr(t0, idx); + tcg_gen_addi_ptr(t1, cpu_env, offsetof(CPUE2KState, tags)); + tcg_gen_add_ptr(ret, t1, t0); + + tcg_temp_free_ptr(t1); + tcg_temp_free_ptr(t0); +} + +static inline bool is_tag_mask_all(DisasContext *ctx, uint8_t mask) +{ + if (ctx->version >= 5) { + return mask == E2K_TAG_MASK_128; + } else { + return mask == E2K_TAG_MASK_80; + } +} + +static void gen_reg_tag_mask(DisasContext *ctx, TCGv_i32 ret, + TCGv_i32 index, uint8_t mask) +{ + TCGv_ptr t0 = tcg_temp_new_ptr(); + + gen_reg_tag_ptr(t0, index); + + if (is_tag_mask_all(ctx, mask)) { + tcg_gen_ld8u_i32(ret, t0, 0); + } else { + TCGv_i32 t1 = tcg_temp_new_i32(); + + tcg_gen_ld8u_i32(t1, t0, 0); + tcg_gen_andi_i32(ret, t1, mask); + + tcg_temp_free_i32(t1); + } + + tcg_temp_free_ptr(t0); +} + +#define gen_reg_tag_i32(c, r, i) \ + gen_reg_tag_mask(c, r, i, E2K_TAG_MASK_32) + +#define gen_reg_tag_i64(c, r, i) \ + gen_reg_tag_mask(c, r, i, E2K_TAG_MASK_64) + +#define gen_reg_tag_i80(c, r, i) \ + gen_reg_tag_mask(c, r, i, E2K_TAG_MASK_80) + +#define gen_reg_tag_i128(c, r, i) \ + gen_reg_tag_mask(c, r, i, E2K_TAG_MASK_128) + +static void gen_reg_tag_mask_set(DisasContext *ctx, TCGv_i32 tag, + TCGv_i32 index, uint8_t mask) +{ + TCGv_ptr t0 = tcg_temp_new_ptr(); + + gen_reg_tag_ptr(t0, index); + + if (is_tag_mask_all(ctx, mask)) { + tcg_gen_st8_i32(tag, t0, 0); + } else { + 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(); + + tcg_gen_ld8u_i32(t1, t0, 0); + tcg_gen_andi_i32(t2, t1, ~mask); + tcg_gen_andi_i32(t3, tag, mask); + tcg_gen_or_i32(t4, t2, t3); + tcg_gen_st8_i32(t4, t0, 0); + + tcg_temp_free_i32(t4); + tcg_temp_free_i32(t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); + } + + tcg_temp_free_ptr(t0); +} + +#define gen_reg_tag_set_i32(c, t, i) \ + gen_reg_tag_mask_set(c, t, i, E2K_TAG_MASK_32) + +#define gen_reg_tag_set_i64(c, t, i) \ + gen_reg_tag_mask_set(c, t, i, E2K_TAG_MASK_64) + +#define gen_reg_tag_set_i80(c, t, i) \ + gen_reg_tag_mask_set(c, t, i, E2K_TAG_MASK_80) + +#define gen_reg_tag_set_i128(c, t, i) \ + gen_reg_tag_mask_set(c, t, i, E2K_TAG_MASK_128) + +static void gen_reg_index_i32(DisasContext *ctx, TCGv_i32 ret, uint8_t arg) +{ + if (IS_BASED(arg)) { + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i32 t1 = tcg_temp_new_i32(); + + tcg_gen_addi_i32(t0, cpu_bcur, GET_BASED(arg)); + tcg_gen_remu_i32(t1, t0, cpu_bsize); + tcg_gen_add_i32(ret, cpu_boff, t1); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + } else if (IS_REGULAR(arg)) { + tcg_gen_movi_i32(ret, GET_REGULAR(arg)); + } else if (IS_GLOBAL(arg)) { + tcg_gen_movi_i32(ret, E2K_NR_COUNT + GET_GLOBAL(arg)); + } else { + gen_tr_exception(ctx, EXCP_ILLEGAL_OPERAND); + } +} + +static void gen_reg_lo_ptr(TCGv_ptr ret, TCGv_i32 idx) +{ + TCGv_ptr t0 = tcg_temp_new_ptr(); + + tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, regs)); + gen_ptr_from_index(ret, t0, idx, sizeof(E2KReg)); + tcg_temp_free_ptr(t0); +} + +static void gen_reg_hi_ptr(TCGv_ptr ret, TCGv_i32 idx) +{ + TCGv_ptr t0 = tcg_temp_new_ptr(); + + gen_reg_lo_ptr(t0, idx); + tcg_gen_addi_ptr(ret, t0, offsetof(E2KReg, hi)); + tcg_temp_free_ptr(t0); +} + +#define GEN_REG_WRITE(name, ty, ptr_func, st_func) \ + static void name(ty value, TCGv_i32 idx) \ + { \ + TCGv_ptr t0 = tcg_temp_new_ptr(); \ + ptr_func(t0, idx); \ + st_func(value, t0, 0); \ + tcg_temp_free_ptr(t0); \ + } + +GEN_REG_WRITE(gen_reg_lo_write_i64, TCGv_i64, gen_reg_lo_ptr, tcg_gen_st_i64) +GEN_REG_WRITE(gen_reg_lo_write_i32, TCGv_i32, gen_reg_lo_ptr, tcg_gen_st_i32) +GEN_REG_WRITE(gen_reg_hi_write_i64, TCGv_i64, gen_reg_hi_ptr, tcg_gen_st_i64) +GEN_REG_WRITE(gen_reg_hi_write16u_i32, TCGv_i32, gen_reg_hi_ptr, tcg_gen_st16_i32) + +static int64_t get_literal(DisasContext *ctx, uint8_t arg) +{ + int i = GET_LIT(arg); + int64_t lit = 0; + + if (!ctx->bundle.lts_present[i]) { + gen_tr_excp_illopc(ctx); + } else if (IS_LIT16_LO(arg) && i < 2) { + lit = sextract32(ctx->bundle.lts[i], 0, 16); + } else if (IS_LIT16_HI(arg) && i < 2) { + lit = ((int64_t) lit << 32) >> 48; + lit = sextract32(ctx->bundle.lts[i], 16, 16); + } else if (IS_LIT32(arg)) { + lit = (int32_t) ctx->bundle.lts[i]; + } else if (IS_LIT64(arg) && i < 3) { + if (!ctx->bundle.lts_present[i + 1]) { + gen_tr_excp_illopc(ctx); + } + lit = *(uint64_t *) &ctx->bundle.lts[i]; + } else { + gen_tr_excp_illopc(ctx); + } + + return lit; +} + +static void gen_tagged_temp_ptr(TCGv_ptr ret, int i) +{ + tcg_gen_addi_ptr(ret, cpu_env, offsetof(CPUE2KState, tmp[i])); +} + +static void gen_temp_result_ptr(TCGv_ptr ret, int i) +{ + tcg_gen_addi_ptr(ret, cpu_env, offsetof(CPUE2KState, al_result[i])); +} + +static void gen_tagged_const_ptr(Tagged_ptr ret, uint8_t tag, int64_t val) +{ + TCGv_i64 lo = tcg_const_i64(val); + TCGv_i64 hi = tcg_const_i64(0); + + tcg_gen_movi_i32(ret.tag, tag); + tcg_gen_st_i64(lo, ret.val, offsetof(E2KReg, lo)); + tcg_gen_st_i64(hi, ret.val, offsetof(E2KReg, hi)); + + tcg_temp_free_i64(hi); + tcg_temp_free_i64(lo); +} + +static void gen_tagged_const_x(Tagged_ptr ret, uint8_t tag, int64_t val, int i) +{ + gen_tagged_temp_ptr(ret.val, i); + gen_tagged_const_ptr(ret, tag, val); +} + +static void gen_tagged_const_s(Tagged_i32 ret, uint8_t tag, int64_t val, int i) +{ + tcg_gen_movi_i32(ret.tag, tag); + tcg_gen_movi_i32(ret.val, val); +} + +static void gen_tagged_const_d(Tagged_i64 ret, uint8_t tag, int64_t val, int i) +{ + tcg_gen_movi_i32(ret.tag, tag); + tcg_gen_movi_i64(ret.val, val); +} + +static void gen_tagged_reg_ptr(DisasContext *ctx, Tagged_ptr ret, + uint8_t arg, uint8_t mask) +{ + TCGv_i32 t0 = tcg_temp_new_i32(); + + if (IS_BASED(arg)) { + TCGv_i32 t1 = tcg_temp_new_i32(); + + tcg_gen_addi_i32(t0, cpu_bcur, GET_BASED(arg)); + tcg_gen_sub_i32(t1, t0, cpu_bsize); + tcg_gen_movcond_i32(TCG_COND_LT, t0, t0, cpu_bsize, t0, t1); + tcg_gen_add_i32(t0, t0, cpu_boff); + + tcg_temp_free_i32(t1); + } else if (IS_REGULAR(arg)) { + tcg_gen_movi_i32(t0, GET_REGULAR(arg)); + } else if (IS_GLOBAL(arg)) { + tcg_gen_movi_i32(t0, E2K_NR_COUNT + GET_GLOBAL(arg)); + } else { + gen_tr_excp_illopc(ctx); + } + + gen_reg_tag_mask(ctx, ret.tag, t0, mask); + gen_reg_lo_ptr(ret.val, t0); + + tcg_temp_free_i32(t0); +} + +static void gen_tagged_reg_x(DisasContext *ctx, Tagged_ptr ret, uint8_t arg) +{ + gen_tagged_reg_ptr(ctx, ret, arg, E2K_TAG_MASK_80); +} + +static void gen_tagged_reg_d(DisasContext *ctx, Tagged_i64 ret, uint8_t arg) +{ + Tagged_ptr t0 = tagged_new_ptr(); + + gen_tagged_reg_ptr(ctx, t0, arg, E2K_TAG_MASK_64); + tcg_gen_mov_i32(ret.tag, t0.tag); + tcg_gen_ld_i64(ret.val, t0.val, offsetof(E2KReg, lo)); + + tagged_free_ptr(t0); +} + +static void gen_tagged_reg_s(DisasContext *ctx, Tagged_i32 ret, uint8_t arg) +{ + Tagged_ptr t0 = tagged_new_ptr(); + + gen_tagged_reg_ptr(ctx, t0, arg, E2K_TAG_MASK_32); + tcg_gen_mov_i32(ret.tag, t0.tag); + tcg_gen_ld_i32(ret.val, t0.val, offsetof(E2KReg, lo)); + + tagged_free_ptr(t0); +} + +#define IMPL_GEN_TAGGED_SRC1(S, T) \ + static void glue(gen_tagged_src1_, S)(Instr *instr, T ret) \ + { \ + if (IS_IMM5(instr->src1)) { \ + glue(gen_tagged_const_, S)(ret, 0, GET_IMM5(instr->src1), 1); \ + } else { \ + glue(gen_tagged_reg_, S)(instr->ctx, ret, instr->src1); \ + } \ + } + +IMPL_GEN_TAGGED_SRC1(x, Tagged_ptr) +IMPL_GEN_TAGGED_SRC1(d, Tagged_i64) +IMPL_GEN_TAGGED_SRC1(s, Tagged_i32) + +#define IMPL_GEN_TAGGED_SRC2(S, T) \ + static void glue(gen_tagged_src2_, S)(Instr *instr, T ret) \ + { \ + if (IS_IMM4(instr->src2)) { \ + glue(gen_tagged_const_, S)(ret, 0, GET_IMM4(instr->src2), 2); \ + } else if (IS_LIT(instr->src2)) { \ + int64_t lit = get_literal(instr->ctx, instr->src2); \ + \ + glue(gen_tagged_const_, S)(ret, 0, lit, 2); \ + } else { \ + glue(gen_tagged_reg_, S)(instr->ctx, ret, instr->src2); \ + } \ + } + +IMPL_GEN_TAGGED_SRC2(x, Tagged_ptr) +IMPL_GEN_TAGGED_SRC2(d, Tagged_i64) +IMPL_GEN_TAGGED_SRC2(s, Tagged_i32) + +#define IMPL_GEN_TAGGED_SRC_REG(N, S, T) \ + static void glue4(gen_tagged_src, N, _, S)(Instr *instr, T ret) \ + { \ + glue(gen_tagged_reg_, S)(instr->ctx, ret, glue(instr->src, N)); \ + } + +IMPL_GEN_TAGGED_SRC_REG(3, d, Tagged_i64) +IMPL_GEN_TAGGED_SRC_REG(3, s, Tagged_i32) + +IMPL_GEN_TAGGED_SRC_REG(4, d, Tagged_i64) +IMPL_GEN_TAGGED_SRC_REG(4, s, Tagged_i32) + +/* + * Returns zero if all @args is zero otherwise returns @tag. + */ +static inline void gen_tag3_raw(TCGv_i32 ret, int tag, TCGv_i32 arg1, TCGv_i32 arg2, + TCGv_i32 arg3) +{ + TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 fail = tcg_const_i32(tag); + TCGv_i32 t0 = tcg_temp_new_i32(); + + if (arg1 != NULL) { + tcg_gen_mov_i32(t0, arg1); + } else { + tcg_gen_movi_i32(t0, 0); + } + if (arg2 != NULL) { + tcg_gen_or_i32(t0, t0, arg2); + } + if (arg3 != NULL) { + tcg_gen_or_i32(t0, t0, arg3); + } + tcg_gen_movcond_i32(TCG_COND_NE, ret, t0, zero, fail, zero); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(fail); + tcg_temp_free_i32(zero); +} + +/* + * Returns zero if all @args is zero otherwise returns tag of non 64-bit number. + */ +#define gen_tag3_i64(ret, a1, a2, a3) \ + gen_tag3_raw((ret), E2K_TAG_NON_NUMBER64, (a1), (a2), (a3)) +#define gen_tag2_i64(ret, a1, a2) gen_tag3_i64((ret), (a1), (a2), NULL) +#define gen_tag1_i64(ret, a1) gen_tag2_i64((ret), (a1), NULL) + +/* + * Returns zero if all @args is zero otherwise returns tag of non 32-bit number. + */ +#define gen_tag3_i32(ret, a1, a2, a3) \ + gen_tag3_raw((ret), E2K_TAG_NON_NUMBER32, (a1), (a2), (a3)) +#define gen_tag2_i32(ret, a1, a2) gen_tag3_i32((ret), (a1), (a2), NULL) +#define gen_tag1_i32(ret, a1) gen_tag2_i32((ret), (a1), NULL) + +static inline void gen_tag_check(Instr *instr, TCGv_i32 tag) +{ + if (!instr->sm && tag != NULL) { + instr->ctx->do_check_illtag = true; + TCGv_i32 illtag = instr->ctx->illtag; + tcg_gen_or_i32(illtag, illtag, tag); + } +} + +static inline void gen_dst_poison_i64(TCGv_i64 ret, TCGv_i64 value, + TCGv_i32 tag) +{ + TCGv_i64 zero = tcg_const_i64(0); + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_ori_i64(t0, value, (1UL << 62) | (1 << 30)); + tcg_gen_extu_i32_i64(t1, tag); + tcg_gen_movcond_i64(TCG_COND_NE, ret, t1, zero, t0, value); + + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(zero); +} + +static inline void gen_dst_poison_i32(TCGv_i32 ret, TCGv_i32 value, + TCGv_i32 tag) +{ + TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 t0 = tcg_temp_new_i32(); + + tcg_gen_ori_i32(t0, value, 1 << 30); + tcg_gen_movcond_i32(TCG_COND_NE, ret, tag, zero, t0, value); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(zero); +} + +static void gen_get_lp(TCGv_i32 ret, uint16_t clp, int offset, TCGv_i32 lp[7]) +{ + int p = extract32(clp, offset, 3); + int neg = GET_BIT(clp, offset + 3); + + tcg_gen_xori_i32(ret, lp[p], neg); +} + +static void gen_cond_i32(DisasContext *ctx, TCGv_i32 ret, uint8_t psrc) +{ + if (psrc & 0x80) { + if (psrc == 0xc0) { + // %bgrpred + e2k_todo_illop(ctx, "%%bgrpred"); + } else if ((psrc & 0xe0) == 0xc0) { + // %rndpred + e2k_todo_illop(ctx, "%%rndpred"); + } else { + gen_tr_excp_illopn(ctx); + } + } else { + int idx = extract8(psrc, 0, 5); + if (psrc == 0) { + // %lcntex + gen_lcntex(ret); + } else if ((psrc & 0x40) == 0) { + // %spredMASK + e2k_todo_illop(ctx, "%%spred"); + } else if ((psrc & 0x60) == 0x60) { + // %predN + gen_preg_i32(ret, idx); + } else { + // %pcntN + tcg_gen_setcondi_i32(TCG_COND_LEU, ret, cpu_lsr_pcnt, idx); + } + } +} + +static inline void scan_needed(const UnpackedBundle *bundle, int need[7]) +{ + bool once_more = true; + unsigned int i; + + for (i = 0; i < 3; i++) { + if (bundle->pls_present[i] && GET_BIT(bundle->pls[i], 5)) { + need[4 + i] = 1; + } + } + + while (once_more) { + once_more = false; + + for (i = 0; i < 3; i++) { + int p0, p1; + + if (need[4 + i] != 1) { + continue; + } + + p0 = extract32(bundle->pls[i], 10, 3); + p1 = extract32(bundle->pls[i], 6, 3); + + if (p0 < 7 && need[p0] == 0) { + need[p0] = 1; + + if (p0 >= 4) { + once_more = true; + } + } + + if (p1 < 7 && need[p1] == 0) { + need[p1] = 1; + + if (p1 >= 4) { + once_more = true; + } + } + + need[4 + i] = 2; + } + } +} + +static void gen_plu(DisasContext *ctx) +{ + const UnpackedBundle *bundle = &ctx->bundle; + int need[7] = { 0 }; + unsigned int i; + TCGv_i32 lp[7]; + + scan_needed(bundle, need); + + for (i = 0; i < 7; i++) { + if (need[i]) { + lp[i] = tcg_temp_new_i32(); + } + } + + for (i = 0; i < 3; i++) { + ctx->pl_results[i].reg = -1; + + if (!bundle->pls_present[i]) { + continue; + } + + if (i < 2) { + if (need[i * 2]) { + int elp = extract32(bundle->pls[i], 24, 7); + gen_cond_i32(ctx, lp[i * 2], elp); + } + + if (need[i * 2 + 1]) { + int elp = extract32(bundle->pls[i], 16, 7); + gen_cond_i32(ctx, lp[i * 2 + 1], elp); + } + } + + if (need[4 + i]) { + uint16_t clp = extract32(bundle->pls[i], 0, 16); + int opc = extract32(clp, 14, 2); + TCGv_i32 p0 = tcg_temp_new_i32(); + TCGv_i32 p1 = tcg_temp_new_i32(); + int vdst = GET_BIT(clp, 5); + int pdst = extract32(clp, 0, 5); + + // TODO: check clp arg + // {C/M}LP0 0, 1 => 4 + // {C/M}LP1 0, 1, 2, 3, 4 => 5 + // {C/M}LP2 0, 1, 2, 3, 4, 5 => 6 + // maximal cascading is 2 + + gen_get_lp(p0, clp, 10, lp); + gen_get_lp(p1, clp, 6, lp); + + if (vdst) { + ctx->pl_results[i].reg = pdst; + ctx->pl_results[i].value = e2k_get_temp_i32(ctx); + } + + switch (opc) { + case 0: /* andp */ + // FIXME: what is the difference between `andp` and `landp`? + case 1: /* landp */ + tcg_gen_and_i32(lp[4 + i], p0, p1); + if (vdst) { + tcg_gen_mov_i32(ctx->pl_results[i].value, lp[4 + i]); + } + break; + case 3: { /* movep */ + // FIXME: clp cannot read result of movep??? + tcg_gen_and_i32(lp[4 + i], p0, p1); + + if (vdst) { + TCGv_i32 z = tcg_const_i32(0); + TCGv_i32 t0 = tcg_temp_new_i32(); + + gen_preg_i32(t0, pdst); + tcg_gen_movcond_i32(TCG_COND_NE, ctx->pl_results[i].value, + p0, z, p1, t0); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(z); + } + break; + } + default: + abort(); + break; + } + } + } + + for (i = 0; i < 7; i++) { + if (need[i]) { + tcg_temp_free_i32(lp[i]); + } + } +} + +static void gen_plu_commit(DisasContext *ctx) +{ + unsigned int i; + + for (i = 0; i < 3; i++) { + if (ctx->pl_results[i].reg < 0) { + continue; + } + gen_preg_set_i32(ctx->pl_results[i].reg, ctx->pl_results[i].value); + } +} + +static inline void set_al_result_reg80_tag(Instr *instr, TCGv_i64 lo, + TCGv_i32 hi, TCGv_i32 tag) +{ + uint8_t dst = instr->dst; + AlResult *res = &instr->ctx->al_results[instr->chan]; + + if (dst == 0xdf) { + res->type = AL_RESULT_NONE; + } else { + res->type = AL_RESULT_REG80; + res->reg.tag = tag; + res->reg.v64 = lo; + res->reg.x32 = hi; + res->reg.index = get_temp_i32(instr); + gen_reg_index_i32(instr->ctx, res->reg.index, dst); + } +} + +static inline void set_al_result_reg64_tag(Instr *instr, + TCGv_i64 value, TCGv_i32 tag) +{ + uint8_t arg = instr->dst; + AlResult *res = &instr->ctx->al_results[instr->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 + // TODO: check tag + res->type = AL_RESULT_CTPR64; + res->ctpr.index = (arg & 3) - 1; + res->ctpr.v64 = value; + } else { + res->type = AL_RESULT_REG64; + res->reg.v64 = value; + res->reg.tag = tag; + res->reg.index = e2k_get_temp_i32(instr->ctx); + gen_reg_index_i32(instr->ctx, res->reg.index, arg); + } +} + +static inline void set_al_result_reg64(Instr *instr, TCGv_i64 value) +{ + TCGv_i32 tag = e2k_get_const_i32(instr->ctx, 0); + set_al_result_reg64_tag(instr, value, tag); +} + +static inline void set_al_result_reg32_tag(Instr *instr, + TCGv_i32 value, TCGv_i32 tag) +{ + uint8_t arg = instr->dst; + AlResult *res = &instr->ctx->al_results[instr->chan]; + + // TODO: %tst, %tc, %tcd + if (arg == 0xdf) { /* %empty */ + res->type = AL_RESULT_NONE; + } else if ((arg & 0xfc) == 0xd0 && (arg & 3) != 0) { + // TODO: check if instruction can write to ctpr + res->type = AL_RESULT_CTPR32; + res->ctpr.index = (arg & 3) - 1; + res->ctpr.v32 = value; + } else { + res->type = AL_RESULT_REG32; + res->reg.v32 = value; + res->reg.tag = tag; + res->reg.index = e2k_get_temp_i32(instr->ctx); + gen_reg_index_i32(instr->ctx, res->reg.index, arg); + } +} + +static inline void set_al_result_preg(Instr *instr, int index, TCGv_i32 value) +{ + AlResult *res = &instr->ctx->al_results[instr->chan]; + + res->type = AL_RESULT_PREG; + res->preg.index = index; + res->preg.val = value; +} + +static inline void gen_al_result_i80(Instr *instr, TCGv_i64 lo, TCGv_i32 hi, + TCGv_i32 tag) +{ + set_al_result_reg80_tag(instr, lo, hi, tag); +} + +static inline void gen_al_result_i64(Instr *instr, TCGv_i64 dst, TCGv_i32 tag) +{ + set_al_result_reg64_tag(instr, dst, tag); +} + +static inline void gen_al_result_i32(Instr *instr, TCGv_i32 dst, TCGv_i32 tag) +{ + set_al_result_reg32_tag(instr, dst, tag); +} + +static void gen_al_result_x(Instr *instr, Tagged_ptr result) +{ + TCGv_i32 tag = get_temp_i32(instr); + TCGv_i64 lo = get_temp_i64(instr); + TCGv_i32 hi = get_temp_i32(instr); + + tcg_gen_mov_i32(tag, result.tag); + tcg_gen_ld_i64(lo, result.val, offsetof(E2KReg, lo)); + tcg_gen_ld16u_i32(hi, result.val, offsetof(E2KReg, hi)); + gen_al_result_i80(instr, lo, hi, tag); +} + +static void gen_al_result_d(Instr *instr, Tagged_i64 result) +{ + TCGv_i32 tag = get_temp_i32(instr); + TCGv_i64 val = get_temp_i64(instr); + + tcg_gen_mov_i32(tag, result.tag); + tcg_gen_mov_i64(val, result.val); + gen_al_result_i64(instr, val, tag); +} + +static void gen_al_result_s(Instr *instr, Tagged_i32 result) +{ + TCGv_i32 tag = get_temp_i32(instr); + TCGv_i32 val = get_temp_i32(instr); + + tcg_gen_mov_i32(tag, result.tag); + tcg_gen_mov_i32(val, result.val); + gen_al_result_i32(instr, val, tag); +} + +static void gen_al_result_b(Instr *instr, Tagged_i32 result) +{ + TCGv_i32 res = get_temp_i32(instr); + TCGv_i32 t0 = tcg_const_i32(0); + TCGv_i32 t1 = tcg_const_i32(2); + + tcg_gen_movcond_i32(TCG_COND_NE, res, result.tag, t0, t1, result.val); + set_al_result_preg(instr, instr->dst_preg, res); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); +} + +static inline bool check_qr(uint8_t src, int chan) +{ + int index = 0, o = chan & 1; + if (IS_REGULAR(src)) { + index = GET_REGULAR(src); + } else if (IS_BASED(src)) { + index = GET_BASED(src); + } else if (IS_GLOBAL(src)) { + index = GET_GLOBAL(src); + } else { + return true; + } + return (index & 1) == (chan < 2 ? o : o ^ 1); +} + +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 = extract32(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 uint16_t find_am_cond(DisasContext *ctx, int chan) +{ + unsigned int i, j; + + for (i = 0; i < ctx->bundle.cds_present[i]; i++) { + uint16_t *cds = (uint16_t *) &ctx->bundle.cds[i]; + + for (j = 0; j < 2; j++) { + int opc = extract16(cds[j], 13, 3); + int req = chan <= 2 ? 1 : 3; + + if (opc == req) { + return cds[j]; + } + } + } + + return 0; +} + +static inline void gen_am_cond_i32(DisasContext *ctx, TCGv_i32 ret, int chan, + uint16_t rlp) +{ + TCGv_i32 t0 = tcg_temp_new_i32(); + + gen_cond_i32(ctx, t0, extract16(rlp, 0, 7)); + // FIXME: It isn't clear if am can be the only one cond in RLP. + tcg_gen_xori_i32(ret, t0, GET_BIT(rlp, 7 + chan % 3)); + + tcg_temp_free_i32(t0); +} + +static inline void gen_mrgc_i32(DisasContext *ctx, int chan, TCGv_i32 ret) +{ + uint16_t rlp = find_mrgc(ctx, chan); + + if (rlp) { + int psrc = extract16(rlp, 0, 7); + + if (GET_BIT(rlp, 7 + chan % 3)) { + TCGv_i32 t0 = tcg_temp_new_i32(); + + gen_cond_i32(ctx, t0, psrc); + tcg_gen_setcondi_i32(TCG_COND_EQ, ret, t0, 0); + + tcg_temp_free_i32(t0); + } else { + gen_cond_i32(ctx, ret, psrc); + } + } else { + /* Undefined behavior if MRGC is not provided but CPU returns src2. */ + tcg_gen_movi_i32(ret, 0); + } +} + +static void gen_is_loop_end_i32(TCGv_i32 ret) +{ + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i32 t1 = tcg_temp_new_i32(); + TCGv_i32 t2 = tcg_temp_new_i32(); + + tcg_gen_setcondi_i32(TCG_COND_EQ, t0, cpu_lsr_ecnt, 0); + tcg_gen_setcondi_i32(TCG_COND_LTU, t1, cpu_lsr_lcnt, 2); + tcg_gen_and_i32(t2, t0, t1); + tcg_gen_and_i32(ret, t2, cpu_lsr_vlc); + + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); +} + +static void gen_loop_mode_st(DisasContext *ctx, TCGLabel *l) +{ + if (ctx->loop_mode) { + TCGLabel *l0 = gen_new_label(); + TCGv_i32 t0 = tcg_temp_new_i32(); + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_lsr_pcnt, 0, l); + gen_is_loop_end_i32(t0); + tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l0); + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_lsr_strmd, 0, l); + tcg_gen_subi_i32(cpu_lsr_strmd, cpu_lsr_strmd, 1); + gen_set_label(l0); + tcg_temp_free_i32(t0); + } +} + +#define IMPL_GEN_OPN(name, S, op) \ + static inline void name(glue(TCGv_i, S) ret, glue(TCGv_i, S) src1, \ + glue(TCGv_i, S) src2) \ + { \ + glue(tcg_gen_not_i, S)(ret, src2); \ + op(ret, src1, ret); \ + } + +IMPL_GEN_OPN(gen_andn_i32, 32, tcg_gen_and_i32) +IMPL_GEN_OPN(gen_andn_i64, 64, tcg_gen_and_i64) +IMPL_GEN_OPN(gen_orn_i32, 32, tcg_gen_or_i32) +IMPL_GEN_OPN(gen_orn_i64, 64, tcg_gen_or_i64) +IMPL_GEN_OPN(gen_xorn_i32, 32, tcg_gen_xor_i32) +IMPL_GEN_OPN(gen_xorn_i64, 64, tcg_gen_xor_i64) + +#define IMPL_GEN_MASK(S, T, L) \ + static inline void glue(gen_mask_, S)(T ret, T size) \ + { \ + T t0 = glue(tcg_const_, S)(1); \ + T t1 = glue(tcg_temp_new_, S)(); \ + glue(tcg_gen_shl_, S)(t1, t0, size); \ + glue(tcg_gen_subi_, S)(ret, t1, 1); \ + glue(tcg_temp_free_, S)(t1); \ + glue(tcg_temp_free_, S)(t0); \ + } \ + +IMPL_GEN_MASK(i64, TCGv_i64, 64) +IMPL_GEN_MASK(i32, TCGv_i32, 32) + +#define IMPL_GEN_GETF_SIGN(S, T) \ + static inline void glue(gen_getf_sign_, S)(T ret, T val, T len, \ + T offset, T byte) \ + { \ + T z = glue(tcg_const_, S)(0); \ + T ones = glue(tcg_const_, S)(-1); \ + T t0 = glue(tcg_temp_new_, S)(); \ + T t1 = glue(tcg_temp_new_, S)(); \ + T t2 = glue(tcg_temp_new_, S)(); \ + T t3 = glue(tcg_temp_new_, S)(); \ + T t4 = glue(tcg_temp_new_, S)(); \ + T t5 = glue(tcg_temp_new_, S)(); \ + T t6 = glue(tcg_temp_new_, S)(); \ + T t7 = glue(tcg_temp_new_, S)(); \ + /* sign = (x >> (byte * 8 + ((offset + len - 1) & 7))) & 1 */ \ + glue(tcg_gen_add_, S)(t0, offset, len); \ + glue(tcg_gen_subi_, S)(t1, t0, 1); \ + glue(tcg_gen_andi_, S)(t2, t1, 7); \ + glue(tcg_gen_muli_, S)(t3, byte, 8); \ + glue(tcg_gen_add_, S)(t4, t3, t2); \ + glue(tcg_gen_shr_, S)(t5, val, t4); \ + glue(tcg_gen_andi_, S)(t6, t5, 1); \ + glue(tcg_gen_shl_, S)(t7, ones, len); \ + glue(tcg_gen_movcond_, S)(TCG_COND_NE, ret, t6, z, t7, z); \ + glue(tcg_temp_free_, S)(t7); \ + glue(tcg_temp_free_, S)(t6); \ + glue(tcg_temp_free_, S)(t5); \ + glue(tcg_temp_free_, S)(t4); \ + glue(tcg_temp_free_, S)(t3); \ + glue(tcg_temp_free_, S)(t2); \ + glue(tcg_temp_free_, S)(t1); \ + glue(tcg_temp_free_, S)(t0); \ + glue(tcg_temp_free_, S)(ones); \ + glue(tcg_temp_free_, S)(z); \ + } + +IMPL_GEN_GETF_SIGN(i64, TCGv_i64) +IMPL_GEN_GETF_SIGN(i32, TCGv_i32) + +#define IMPL_GEN_GETF(NAME, S, T, OFFSET, LEN, BYTE, N) \ + static inline void NAME(T ret, T src1, T src2) \ + { \ + T z = glue(tcg_const_, S)(0); \ + T offset = glue(tcg_temp_new_, S)(); \ + T len = glue(tcg_temp_new_, S)(); \ + T sign = glue(tcg_temp_new_, S)(); \ + T byte = glue(tcg_temp_new_, S)(); \ + T t0 = glue(tcg_temp_new_, S)(); \ + T t1 = glue(tcg_temp_new_, S)(); \ + T t2 = glue(tcg_temp_new_, S)(); \ + T t3 = glue(tcg_temp_new_, S)(); \ + T t4 = glue(tcg_temp_new_, S)(); \ + glue(tcg_gen_extract_, S)(offset, src2, 0, OFFSET); \ + glue(tcg_gen_extract_, S)(len, src2, 6, LEN); \ + glue(tcg_gen_extract_, S)(sign, src2, 12, 1); \ + glue(tcg_gen_extract_, S)(byte, src2, 13, BYTE); \ + glue(tcg_gen_rotr_, S)(t0, src1, offset); \ + glue(gen_mask_, S)(t1, len); \ + glue(tcg_gen_and_, S)(t2, t0, t1); \ + glue(gen_getf_sign_, S)(t3, src1, len, offset, byte); \ + glue(tcg_gen_or_, S)(t4, t3, t2); \ + glue(tcg_gen_movcond_, S)(TCG_COND_NE, ret, sign, z, t4, t2); \ + glue(tcg_temp_free_, S)(t4); \ + glue(tcg_temp_free_, S)(t3); \ + glue(tcg_temp_free_, S)(t2); \ + glue(tcg_temp_free_, S)(t1); \ + glue(tcg_temp_free_, S)(t0); \ + glue(tcg_temp_free_, S)(byte); \ + glue(tcg_temp_free_, S)(sign); \ + glue(tcg_temp_free_, S)(len); \ + glue(tcg_temp_free_, S)(offset); \ + glue(tcg_temp_free_, S)(z); \ + } + +IMPL_GEN_GETF(gen_getf_i64, i64, TCGv_i64, 6, 6, 3, 64) +IMPL_GEN_GETF(gen_getf_i32, i32, TCGv_i32, 5, 5, 2, 32) + +#define gen_getfd gen_getf_i64 +#define gen_getfs gen_getf_i32 + +#define IMPL_GEN_BSWAP_MASK(name, S, M) \ + static void name(temp(S) ret, temp(S) arg, int shift, M mask) \ + { \ + temp(S) t0 = temp_new(S); \ + temp(S) t1 = temp_new(S); \ + \ + call(S, tcg_gen_andi, t0, arg, mask); \ + call(S, tcg_gen_andi, t1, arg, mask >> shift); \ + call(S, tcg_gen_shri, t0, t0, shift); \ + call(S, tcg_gen_shli, t1, t1, shift); \ + call(S, tcg_gen_or, ret, t0, t1); \ + \ + temp_free(S, t1); \ + temp_free(S, t0); \ + } + +IMPL_GEN_BSWAP_MASK(gen_bswap_mask_i64, d, uint64_t) +IMPL_GEN_BSWAP_MASK(gen_bswap_mask_i32, s, uint32_t) + +static void gen_bitrevs(TCGv_i32 ret, TCGv_i32 src1) { + tcg_gen_bswap32_i32(ret, src1); + gen_bswap_mask_i32(ret, ret, 4, 0xf0f0f0f0); + gen_bswap_mask_i32(ret, ret, 2, 0xcccccccc); + gen_bswap_mask_i32(ret, ret, 1, 0xaaaaaaaa); +} + +static void gen_bitrevd(TCGv_i64 ret, TCGv_i64 src1) { + tcg_gen_bswap64_i64(ret, src1); + gen_bswap_mask_i64(ret, ret, 4, 0xf0f0f0f0f0f0f0f0); + gen_bswap_mask_i64(ret, ret, 2, 0xcccccccccccccccc); + gen_bswap_mask_i64(ret, ret, 1, 0xaaaaaaaaaaaaaaaa); +} + +static void gen_lzcnts(TCGv_i32 ret, TCGv_i32 src1) { + tcg_gen_clzi_i32(ret, src1, 32); +} + +static void gen_lzcntd(TCGv_i64 ret, TCGv_i64 src1) { + tcg_gen_clzi_i64(ret, src1, 64); +} + +#define IMPL_GEN_PSHIFT(name, op) \ + static void name(TCGv_i64 ret, TCGv_i64 src1, TCGv_i64 src2) \ + { \ + TCGv_i64 t0 = tcg_const_i64(64); \ + TCGv_i64 t1 = tcg_const_i64(0); \ + \ + op(ret, src1, src2); \ + tcg_gen_movcond_i64(TCG_COND_LTU, ret, src2, t0, ret, t1); \ + \ + tcg_temp_free_i64(t1); \ + tcg_temp_free_i64(t0); \ + } + +IMPL_GEN_PSHIFT(gen_pslld, tcg_gen_shl_i64) +IMPL_GEN_PSHIFT(gen_psrld, tcg_gen_shr_i64) + +static void gen_sm_i32(bool sm, TCGv_i32 ret, TCGv_i32 ret_tag, Exception excp) +{ + if (sm) { + tcg_gen_movi_i32(ret_tag, E2K_TAG_NON_NUMBER32); + tcg_gen_movi_i32(ret, 0); + } else { + gen_exception(excp); + } +} + +static void gen_brchecki_i32(bool sm, TCGv_i32 ret, TCGv_i32 ret_tag, + TCGCond cond, TCGv_i32 arg0, uint32_t arg1, TCGLabel *l, Exception excp) +{ + TCGLabel *l0 = gen_new_label(); + tcg_gen_brcondi_i32(cond, arg0, arg1, l0); + gen_sm_i32(sm, ret, ret_tag, excp); + tcg_gen_br(l); + gen_set_label(l0); +} + +static void gen_brchecki_i32_i64(bool sm, TCGv_i32 ret, TCGv_i32 ret_tag, + TCGCond cond, TCGv_i64 arg0, uint64_t arg1, TCGLabel *l, Exception excp) +{ + TCGLabel *l0 = gen_new_label(); + tcg_gen_brcondi_i64(cond, arg0, arg1, l0); + gen_sm_i32(sm, ret, ret_tag, excp); + tcg_gen_br(l); + gen_set_label(l0); +} + +#define GEN_OP_DIVX(name, op, checks) \ + static void glue(gen_, name)(TCGv_i32 ret, TCGv_i32 ret_tag, TCGv_i32 tag, \ + TCGv_i64 src1, TCGv_i32 src2, bool sm) { \ + TCGLabel *l0 = gen_new_label(); \ + TCGv_i64 t0 = tcg_temp_new_i64(); \ + TCGv_i64 t1 = tcg_temp_local_new_i64(); \ + gen_brchecki_i32(sm, ret, ret_tag, \ + TCG_COND_NE, src2, 0, l0, EXCP_DIV); \ + tcg_gen_extu_i32_i64(t0, src2); \ + op(t1, src1, t0); \ + checks \ + tcg_gen_extrl_i64_i32(ret, t1); \ + gen_set_label(l0); \ + tcg_temp_free_i64(t1); \ + tcg_temp_free_i64(t0); \ + } + +GEN_OP_DIVX(udivx, tcg_gen_divu_i64, { \ + gen_brchecki_i32_i64(sm, ret, ret_tag, \ + TCG_COND_LEU, t1, UINT32_MAX, l0, EXCP_DIV); \ +}) +GEN_OP_DIVX(sdivx, tcg_gen_div_i64, { \ + gen_brchecki_i32_i64(sm, ret, ret_tag, \ + TCG_COND_LE, t1, INT32_MAX, l0, EXCP_DIV); \ + gen_brchecki_i32_i64(sm, ret, ret_tag, \ + TCG_COND_GE, t1, INT32_MIN, l0, EXCP_DIV); \ +}) + +#define GEN_OP_MODX(name, op) \ + static void glue(gen_, name)(TCGv_i32 ret, TCGv_i32 tag, TCGv_i32 ret_tag, \ + TCGv_i64 src1, TCGv_i32 src2, bool sm) { \ + TCGLabel *l0 = gen_new_label(); \ + TCGv_i64 t0 = tcg_temp_new_i64(); \ + TCGv_i64 t1 = tcg_temp_new_i64(); \ + gen_brchecki_i32(sm, ret, ret_tag, \ + TCG_COND_NE, src2, 0, l0, EXCP_DIV); \ + tcg_gen_extu_i32_i64(t0, src2); \ + /* FIXME: must gen exception/tag on overflow */ \ + op(t1, src1, t0); \ + tcg_gen_extrl_i64_i32(ret, t1); \ + gen_set_label(l0); \ + tcg_temp_free_i64(t1); \ + tcg_temp_free_i64(t0); \ + } + +GEN_OP_MODX(umodx, tcg_gen_remu_i64) +GEN_OP_MODX(smodx, tcg_gen_rem_i64) + +#define IMPL_GEN_PARITY8(name, S) \ + static void name(temp(S) ret, temp(S) arg) \ + { \ + call(S, tcg_gen_andi, ret, arg, 0xff); \ + call(S, tcg_gen_ctpop, ret, ret); \ + call(S, tcg_gen_andi, ret, ret, 1); \ + call(S, tcg_gen_setcondi, TCG_COND_EQ, ret, ret, 0); \ + } + +IMPL_GEN_PARITY8(gen_parity8_i32, s) +IMPL_GEN_PARITY8(gen_parity8_i64, d) + +#define IMPL_CMPO(name, S) \ + static void name(temp(S) ret, temp(S) src1, temp(S) src2) \ + { \ + temp(S) t0 = temp_new(S); \ + temp(S) t1 = temp_new(S); \ + temp(S) t2 = temp_new(S); \ + \ + call(S, tcg_gen_sub, t0, src1, src2); \ + call(S, tcg_gen_xor, t1, src1, t0); \ + call(S, gen_xorn, t2, t0, src2); \ + call(S, tcg_gen_and, ret, t1, t2); \ + call(S, tcg_gen_setcondi, TCG_COND_LT, ret, ret, 0); \ + \ + temp_free(S, t2); \ + temp_free(S, t1); \ + temp_free(S, t0); \ + } + +IMPL_CMPO(gen_cmposb, s) +IMPL_CMPO(gen_cmpodb, d) + +#define IMPL_CMPS(name, S) \ + static void name(temp(S) ret, temp(S) src1, temp(S) src2) \ + { \ + call(S, tcg_gen_sub, ret, src1, src2); \ + call(S, tcg_gen_setcondi, TCG_COND_LT, ret, ret, 0); \ + } + +IMPL_CMPS(gen_cmpssb, s) +IMPL_CMPS(gen_cmpsdb, d) + +#define IMPL_CMPP(name, S) \ + static void name(temp(S) ret, temp(S) src1, temp(S) src2) \ + { \ + call(S, tcg_gen_sub, ret, src1, src2); \ + call(S, gen_parity8, ret, ret); \ + } + +IMPL_CMPP(gen_cmppsb, s) +IMPL_CMPP(gen_cmppdb, d) + +#define IMPL_CMP(name, S, cond) \ + static void name(temp(S) ret, temp(S) src1, temp(S) src2) \ + { \ + call(S, tcg_gen_setcond, cond, ret, src1, src2); \ + } + +IMPL_CMP(gen_cmpbsb, s, TCG_COND_LTU) +IMPL_CMP(gen_cmpesb, s, TCG_COND_EQ) +IMPL_CMP(gen_cmpbesb, s, TCG_COND_LEU) +IMPL_CMP(gen_cmplsb, s, TCG_COND_LT) +IMPL_CMP(gen_cmplesb, s, TCG_COND_LE) + +IMPL_CMP(gen_cmpbdb, d, TCG_COND_LTU) +IMPL_CMP(gen_cmpedb, d, TCG_COND_EQ) +IMPL_CMP(gen_cmpbedb, d, TCG_COND_LEU) +IMPL_CMP(gen_cmpldb, d, TCG_COND_LT) +IMPL_CMP(gen_cmpledb, d, TCG_COND_LE) + +#define IMPL_GEN_CMPANDP(name, S) \ + static void name(temp(S) ret, temp(S) src1, temp(S) src2) \ + { \ + call(S, tcg_gen_and, ret, src1, src2); \ + call(S, gen_parity8, ret, ret); \ + } + +IMPL_GEN_CMPANDP(gen_cmpandpsb, s) +IMPL_GEN_CMPANDP(gen_cmpandpdb, d) + +#define IMPL_GEN_CMPAND(name, S, cond) \ + static void name(temp(S) ret, temp(S) src1, temp(S) src2) \ + { \ + call(S, tcg_gen_and, ret, src1, src2); \ + call(S, tcg_gen_setcondi, cond, ret, ret, 0); \ + } + +IMPL_GEN_CMPAND(gen_cmpandesb, s, TCG_COND_EQ) +IMPL_GEN_CMPAND(gen_cmpandssb, s, TCG_COND_LT) +IMPL_GEN_CMPAND(gen_cmpandlesb, s, TCG_COND_LE) + +IMPL_GEN_CMPAND(gen_cmpandedb, d, TCG_COND_EQ) +IMPL_GEN_CMPAND(gen_cmpandsdb, d, TCG_COND_LT) +IMPL_GEN_CMPAND(gen_cmpandledb, d, TCG_COND_LE) + +#define glue4(a, b, c, d) glue(glue(a, b), glue(c, d)) + +static inline void gen_merge_i32(TCGv_i32 ret, TCGv_i32 src1, TCGv_i32 src2, + TCGv_i32 cond) +{ + TCGv_i32 zero = tcg_const_i32(0); + tcg_gen_movcond_i32(TCG_COND_EQ, ret, cond, zero, src1, src2); + tcg_temp_free_i32(zero); +} + +static inline void gen_merge_i64(TCGv_i64 ret, TCGv_i64 src1, TCGv_i64 src2, + TCGv_i32 cond) +{ + TCGv_i64 zero = tcg_const_i64(0); + TCGv_i64 t0 = tcg_temp_new_i64(); + + tcg_gen_extu_i32_i64(t0, cond); + tcg_gen_movcond_i64(TCG_COND_EQ, ret, t0, zero, src1, src2); + + tcg_temp_free_i64(t0); + tcg_temp_free_i64(zero); +} + +#define IMPL_MERGE(name, S) \ + static void name(Instr *instr) \ + { \ + tagged(S) r = tagged_new(S); \ + tagged(S) a = tagged_new(S); \ + tagged(S) b = tagged_new(S); \ + TCGv_i32 t0 = tcg_temp_new_i32(); \ + \ + gen_tagged_src(1, S, instr, a); \ + gen_tagged_src(2, S, instr, b); \ + \ + gen_mrgc_i32(instr->ctx, instr->chan, t0); \ + gen_merge_i32(r.tag, a.tag, b.tag, t0); \ + call(S, gen_tag1, r.tag, r.tag); \ + call(S, gen_merge, r.val, a.val, b.val, t0); \ + gen_al_result(S, instr, r); \ + \ + tagged_free(S, b); \ + tagged_free(S, a); \ + tagged_free(S, r); \ + } + +IMPL_MERGE(gen_merges, s) +IMPL_MERGE(gen_merged, d) + +static inline void gen_udivd(TCGv_i64 ret, TCGv_i32 ret_tag, TCGv_i32 tag, + TCGv_i64 src1, TCGv_i64 src2, bool sm) +{ + if (sm) { + TCGLabel *l0 = gen_new_label(); + 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_mov_i32(ret_tag, tag); + tcg_gen_divu_i64(ret, src1, src2); + gen_set_label(l0); + } else { + tcg_gen_mov_i32(ret_tag, tag); + tcg_gen_divu_i64(ret, src1, src2); + } +} + +static inline void gen_udivs(TCGv_i32 ret, TCGv_i32 ret_tag, TCGv_i32 tag, + TCGv_i32 src1, TCGv_i32 src2, bool sm) +{ + if (sm) { + TCGLabel *l0 = gen_new_label(); + 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_mov_i32(ret_tag, tag); + tcg_gen_divu_i32(ret, src1, src2); + gen_set_label(l0); + } else { + tcg_gen_mov_i32(ret_tag, tag); + tcg_gen_divu_i32(ret, src1, src2); + } +} + +#define IMPL_GEN_SDIV(name, S, T, bad_tag) \ + static inline void name(T ret, TCGv_i32 ret_tag, \ + TCGv_i32 tag, T src1, T src2, bool sm) \ + { \ + TCGLabel *l0 = gen_new_label(); \ + TCGLabel *l1 = gen_new_label(); \ + T t0 = glue(tcg_temp_new_i, S)(); \ + T t1 = glue(tcg_temp_new_i, S)(); \ + T t2 = glue(tcg_temp_new_i, S)(); \ + T t3 = glue(tcg_temp_new_i, S)(); \ + T t4 = glue(tcg_temp_new_i, S)(); \ + \ + glue(tcg_gen_brcondi_i, S)(TCG_COND_NE, src2, 0, l1); \ + /* src2 is zero */ \ + tcg_gen_movi_i32(ret_tag, bad_tag); \ + glue(tcg_gen_movi_i, S)(ret, 0); \ + tcg_gen_br(l0); \ + \ + /* src2 is not zero */ \ + gen_set_label(l1); \ + glue(tcg_gen_setcondi_i, S)(TCG_COND_EQ, t0, src1, 1ULL << (S - 1)); \ + glue(tcg_gen_setcondi_i, S)(TCG_COND_EQ, t1, src2, -1); \ + glue(tcg_gen_and_i, S)(t2, t0, t1); \ + glue(tcg_gen_movi_i, S)(t3, 0); \ + glue(tcg_gen_movcond_i, S)(TCG_COND_NE, t4, t2, t3, t2, src2); \ + \ + tcg_gen_mov_i32(ret_tag, tag); \ + glue(tcg_gen_div_i, S)(ret, src1, t4); \ + \ + gen_set_label(l0); \ + \ + glue(tcg_temp_free_i, S)(t4); \ + glue(tcg_temp_free_i, S)(t3); \ + glue(tcg_temp_free_i, S)(t2); \ + glue(tcg_temp_free_i, S)(t1); \ + glue(tcg_temp_free_i, S)(t0); \ + } + +IMPL_GEN_SDIV(gen_sdivd, 64, TCGv_i64, E2K_TAG_NON_NUMBER64) +IMPL_GEN_SDIV(gen_sdivs, 32, TCGv_i32, E2K_TAG_NON_NUMBER32) + +#define IMPL_GEN_GETTAG(name, S, ext) \ + static void name(Instr *instr) \ + { \ + tagged(S) r = tagged_new(S); \ + tagged(S) b = tagged_new(S); \ + \ + gen_tagged_src(2, S, instr, b); \ + tcg_gen_movi_i32(r.tag, 0); \ + ext(r.val, b.tag); \ + gen_al_result(S, instr, r); \ + \ + tagged_free(S, b); \ + tagged_free(S, r); \ + } + +IMPL_GEN_GETTAG(gen_gettagd, d, tcg_gen_extu_i32_i64) +IMPL_GEN_GETTAG(gen_gettags, s, tcg_gen_mov_i32) + +#define IMPL_GEN_PUTTAG(name, R, A, B) \ + static void name(Instr *instr) \ + { \ + TCGLabel *l0 = gen_new_label(); \ + TCGLabel *l1 = gen_new_label(); \ + tagged(R) r = tagged_local_new(R); \ + tagged(A) a = tagged_local_new(A); \ + tagged(B) b = tagged_local_new(B); \ + \ + gen_tagged_src(1, A, instr, a); \ + gen_tagged_src(2, B, instr, b); \ + call(R, tcg_gen_mov, r.val, a.val); \ + tcg_gen_brcondi_i32(TCG_COND_EQ, b.val, 0, l0); \ + gen_tag2(R, r, a, b); \ + tcg_gen_brcondi_i32(TCG_COND_EQ, r.tag, 0, l0); \ + gen_tag_check(instr, r.tag); \ + call(R, gen_dst_poison, r.val, r.val, r.tag); \ + tcg_gen_br(l1); \ + gen_set_label(l0); \ + tcg_gen_mov_i32(r.tag, b.val); \ + gen_set_label(l1); \ + gen_al_result(R, instr, r); \ + \ + tagged_free(B, b); \ + tagged_free(A, a); \ + tagged_free(R, r); \ + } + +IMPL_GEN_PUTTAG(gen_puttagd, d, d, s) +IMPL_GEN_PUTTAG(gen_puttags, s, s, s) + +static inline void gen_insfd_tag_mask(TCGv_i32 ret, TCGv_i32 flags, + TCGv_i32 tag, int offset) +{ + TCGv_i32 z = tcg_const_i32(0); + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i32 t1 = tcg_temp_new_i32(); + tcg_gen_andi_i32(t0, flags, 1 << offset); + tcg_gen_andi_i32(t1, tag, 0x3); + tcg_gen_movcond_i32(TCG_COND_NE, ret, t0, z, t1, tag); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(z); +} + +static inline void gen_insfd_tag(TCGv_i32 ret, TCGv_i64 value, + TCGv_i32 s1_tag, TCGv_i32 s3_tag) +{ + TCGv_i32 z = tcg_const_i32(0); + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i32 t1 = tcg_temp_new_i32(); + TCGv_i32 t2 = tcg_temp_new_i32(); + + tcg_gen_extrl_i64_i32(t0, value); + gen_insfd_tag_mask(t1, t0, s1_tag, 13); + gen_insfd_tag_mask(t2, t0, s3_tag, 15); + tcg_gen_or_i32(ret, t1, t2); + + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(z); +} + +static inline void gen_insfd(Instr *instr) +{ + Tagged_i64 r = tagged_new_i64(); + Tagged_i64 a = tagged_new_i64(); + Tagged_i64 b = tagged_new_i64(); + Tagged_i64 c = tagged_new_i64(); + 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(); + + gen_tagged_src1_d(instr, a); + gen_tagged_src2_d(instr, b); + gen_tagged_src3_d(instr, c); + tcg_gen_extract_i64(offset, b.val, 0, 6); + tcg_gen_extract_i64(len, b.val, 6, 6); + gen_mask_i64(t0, len); + tcg_gen_rotr_i64(t1, a.val, offset); + gen_andn_i64(t2, t1, t0); + tcg_gen_and_i64(t3, c.val, t0); + tcg_gen_or_i64(r.val, t2, t3); + + gen_insfd_tag(r.tag, b.val, a.tag, c.tag); + gen_tag2_i64(r.tag, b.tag, r.tag); + gen_al_result_d(instr, r); + + 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); + tagged_free_i64(c); + tagged_free_i64(b); + tagged_free_i64(a); + tagged_free_i64(r); +} + +static inline void gen_insfs(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_umulx(TCGv_i64 ret, TCGv_i32 src1, TCGv_i32 src2) +{ + TCGv_i32 l = tcg_temp_new_i32(); + TCGv_i32 h = tcg_temp_new_i32(); + + tcg_gen_mulu2_i32(l, h, src1, src2); + tcg_gen_concat_i32_i64(ret, l, h); + + tcg_temp_free_i32(h); + tcg_temp_free_i32(l); +} + +static inline void gen_smulx(TCGv_i64 ret, TCGv_i32 src1, TCGv_i32 src2) +{ + TCGv_i32 l = tcg_temp_new_i32(); + TCGv_i32 h = tcg_temp_new_i32(); + + tcg_gen_muls2_i32(l, h, src1, src2); + tcg_gen_concat_i32_i64(ret, l, h); + + tcg_temp_free_i32(h); + tcg_temp_free_i32(l); +} + +static inline void gen_umulhd(TCGv_i64 ret, TCGv_i64 src1, TCGv_i64 src2) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_mulu2_i64(t0, ret, src1, src2); + tcg_temp_free_i64(t0); +} + +static inline void gen_smulhd(TCGv_i64 ret, TCGv_i64 src1, TCGv_i64 src2) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_muls2_i64(t0, ret, src1, src2); + tcg_temp_free_i64(t0); +} + +static inline void gen_rrd(Instr *instr) +{ + TCGv_i64 dst = get_temp_i64(instr); + TCGv_i32 t0 = tcg_const_i32(instr->src1); + + gen_save_cpu_state(instr->ctx); + gen_helper_rrd(dst, cpu_env, t0); + set_al_result_reg64(instr, dst); + tcg_temp_free_i32(t0); +} + +#define IMPL_GEN_RW(name, S, helper) \ + static inline void name(Instr *instr) \ + { \ + tagged(S) b = tagged_new(S); \ + TCGv_i32 t0 = tcg_const_i32(instr->dst); \ + \ + gen_tagged_src(2, S, instr, b); \ + gen_tag_check(instr, b.tag); \ + helper(cpu_env, t0, b.val); \ + \ + tcg_temp_free_i32(t0); \ + tagged_free(S, b); \ + } + +IMPL_GEN_RW(gen_rwd, d, gen_helper_rwd) +IMPL_GEN_RW(gen_rws, s, gen_helper_rws) + +#define IMPL_GEN_MOV(name, S, code) \ + static void name(Instr *instr) \ + { \ + tagged(S) b = tagged_new(S); \ + \ + gen_tagged_src(2, S, instr, b); \ + { code; } \ + gen_al_result(S, instr, b); \ + \ + tagged_free(S, b); \ + } + +static void gen_qpair_check(Instr *instr) +{ + if (!check_qr(instr->src2, instr->chan) + || !check_qr(instr->dst, instr->chan)) + { + gen_tr_excp_illopc(instr->ctx); + } +} + +IMPL_GEN_MOV(gen_movts, s, { }) +IMPL_GEN_MOV(gen_movtd, d, { }) +IMPL_GEN_MOV(gen_movtq, d, { gen_qpair_check(instr); }) +IMPL_GEN_MOV(gen_movtcs, s, { }) +IMPL_GEN_MOV(gen_movtcd, d, { }) +IMPL_GEN_MOV(gen_movtcq, d, { gen_qpair_check(instr); }) + +static void gen_getpl(Instr *instr) +{ +#ifdef TARGET_E2K32 + Tagged_i64 r = tagged_new_i64(); + Tagged_i32 b = tagged_new_i32(); + + // TODO: CUD + gen_tagged_src2_s(instr, b); + gen_tag1_i64(r.tag, b.tag); + tcg_gen_extu_i32_i64(r.val, b.val); + gen_al_result_d(instr, r); + + tagged_free_i32(b); + tagged_free_i64(r); +#else /* !TARGET_E2K32 */ + // TODO: getpl 64-bit + e2k_todo_illop(instr->ctx, "getpl"); +#endif +} + +static inline bool gen_ld_mas_mod(DisasContext *ctx, Instr *instr, uint8_t mod) +{ + switch (mod) { + case 3: + if (is_chan_25(instr->chan)) { + // TODO: DAM + /* always go to fixing code */ + if (ctx->mlock) { + tcg_gen_movi_i32(ctx->mlock, 1); + } + return true; + } + break; + case 4: + if (instr->sm && is_chan_03(instr->chan)) { + // TODO: DAM + /* always ignore lock load */ + return false; + } else if (!instr->sm && (is_chan_25(instr->chan) || is_chan_03(instr->chan))) { + // TODO + return true; + } + break; + } + + e2k_todo(ctx, "opc %#x, chan %d, mod=%#x", instr->opc1, instr->chan, mod); + return true; +} + +static MemOp gen_mas(Instr *instr, MemOp memop) +{ + DisasContext *ctx = instr->ctx; + uint8_t mas = instr->mas; + + if ((mas & 0x7) == 7) { + int opc = mas >> 3; + // TODO: special mas + switch (opc) { + case 0: + /* handled in a gen_ld_mas */ + // TODO: only chan 0? + return memop | MO_LE; + case 3: + if (!instr->sm && is_chan_25(instr->chan)) { + // TODO: unknown store MAS OPC 0x3 + return 0; + } + break; + } + e2k_todo(ctx, "opc %#x, chan %d, mas=%#x (opc %#x)", instr->opc1, + instr->chan, mas, opc); + return 0; + } else if (mas) { + int mod = extract8(mas, 0, 3); +// int dc = extract8(mas, 5, 2); + + if (mod != 0) { + if (0x64 <= instr->opc1 && instr->opc1 < 0x68) { + if (!gen_ld_mas_mod(ctx, instr, mod)) { + return 0; + } + } else { + switch (mod) { + case 2: + /* handled in a gen_st */ + // TODO: only chan 2? + break; + default: + e2k_todo(ctx, "opc %#x, chan %d, mas=%#x, mod=%#x", instr->opc1, + instr->chan, mas, mod); + break; + } + } + } + + 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_tl(Instr *instr, TCGv_i64 ret, TCGv_i32 ret_tag, TCGv addr, + MemOp memop) +{ + if (instr->sm) { + TCGLabel *l0 = gen_new_label(); + TCGLabel *l1 = gen_new_label(); + TCGv t0 = tcg_temp_local_new(); + TCGv_i32 t1 = tcg_temp_new_i32(); + + tcg_gen_mov_tl(t0, addr); + gen_helper_probe_read_access(t1, cpu_env, t0); + tcg_gen_brcondi_i32(TCG_COND_EQ, t1, 1, l0); + + /* address is not available */ + tcg_gen_movi_i32(ret_tag, E2K_TAG_NON_NUMBER64); + tcg_gen_movi_i64(ret, E2K_LD_RESULT_INVALID); + tcg_gen_br(l1); + + /* address is available */ + gen_set_label(l0); + tcg_gen_qemu_ld_i64(ret, t0, instr->ctx->mmuidx, memop); + + gen_set_label(l1); + + tcg_temp_free_i32(t1); + tcg_temp_free(t0); + } else { + tcg_gen_qemu_ld_i64(ret, addr, instr->ctx->mmuidx, memop); + } +} + +#define IMPL_GEN_LD(name, S, cast) \ + static void name(Instr *instr, Tagged_i64 r, \ + MemOp memop) \ + { \ + tagged(S) a = tagged_new(S); \ + tagged(S) b = tagged_new(S); \ + temp(S) t0 = temp_new(S); \ + TCGv t1 = tcg_temp_local_new(); \ + \ + gen_tagged_src(1, S, instr, a); \ + gen_tagged_src(2, S, instr, b); \ + gen_tag2d(r, a, b); \ + call(S, tcg_gen_add, t0, a.val, b.val); \ + cast(t1, t0); \ + gen_ld_tl(instr, r.val, r.tag, t1, memop); \ + \ + tcg_temp_free(t1); \ + temp_free(S, t0); \ + tagged_free(S, b); \ + tagged_free(S, a); \ + } + +IMPL_GEN_LD(gen_ld_i64, d, tcg_gen_trunc_i64_tl) + +#define IMPL_GEN_LD_MAS(name, load) \ + static void name(Instr *instr, MemOp memop) \ + { \ + Tagged_i64 r = tagged_local_new_i64(); \ + \ + memop = gen_mas(instr, memop); \ + \ + if (memop == 0) { \ + /* ignore load */ \ + tcg_gen_movi_i32(r.tag, E2K_TAG_NON_NUMBER64); \ + tcg_gen_movi_i64(r.val, E2K_LD_RESULT_INVALID); \ + } else { \ + load(instr, r, memop); \ + if (instr->chan == 0 && instr->mas == 7) { \ + /* TODO: gen illop if called twice before st/mod=2 */ \ + tcg_gen_mov_i64(cpu_last_value, r.val); \ + } \ + } \ + \ + gen_al_result_d(instr, r); \ + \ + tagged_free_i64(r); \ + } + +IMPL_GEN_LD_MAS(gen_ld_mas_i64, gen_ld_i64) + +#ifdef TARGET_E2K32 +// TODO: ldgd ops must use GD.base +IMPL_GEN_LD(gen_ld_i32, s, tcg_gen_extu_i32_tl) +IMPL_GEN_LD_MAS(gen_ld_mas_i32, gen_ld_i32) +#endif + +static void gen_atomic_cmpxchg_i64(Instr *instr, TCGv_i64 value, TCGv addr, + MemOp memop) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_atomic_cmpxchg_i64(t0, addr, cpu_last_value, value, + instr->ctx->mmuidx, memop); + tcg_gen_setcond_i64(TCG_COND_NE, t1, t0, cpu_last_value); + tcg_gen_extrl_i64_i32(instr->ctx->mlock, t1); + + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t0); +} + +static void gen_atomic_cmpxchg_i32(Instr *instr, TCGv_i32 value, TCGv addr, + MemOp memop) +{ + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i32 t1 = tcg_temp_new_i32(); + + tcg_gen_extrl_i64_i32(t0, cpu_last_value); + tcg_gen_atomic_cmpxchg_i32(t1, addr, t0, value, + instr->ctx->mmuidx, memop); + tcg_gen_setcond_i32(TCG_COND_NE, instr->ctx->mlock, t1, t0); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); +} + +#define IMPL_ST(NAME, S, N, cast) \ + static void NAME(Instr *instr, MemOp memop) \ + { \ + memop = gen_mas(instr, memop); \ + \ + if (memop != 0) { \ + TCGLabel *l0 = gen_new_label(); \ + tagged(N) a = tagged_local_new(N); \ + tagged(N) b = tagged_local_new(N); \ + tagged(S) d = tagged_local_new(S); \ + temp(N) t0 = temp_new(N); \ + TCGv t1 = tcg_temp_local_new(); \ + \ + gen_tagged_src(1, N, instr, a); \ + gen_tagged_src(2, N, instr, b); \ + gen_tagged_src(4, S, instr, d); \ + gen_loop_mode_st(instr->ctx, l0); \ + gen_tag_check(instr, a.tag); \ + gen_tag_check(instr, b.tag); \ + gen_tag_check(instr, d.tag); \ + call(N, tcg_gen_add, t0, a.val, b.val); \ + cast(t1, t0); \ + \ + if (instr->sm) { \ + TCGv_i32 t2 = tcg_temp_new_i32(); \ + gen_helper_probe_write_access(t2, cpu_env, t1); \ + tcg_gen_brcondi_i32(TCG_COND_EQ, t2, 0, l0); \ + tcg_temp_free_i32(t2); \ + } \ + \ + if (instr->ctx->mlock && instr->chan == 2 \ + && (instr->mas & 7) == 2) \ + { \ + /* FIXME: Does an any write before the st/mod=2 leads to a branch? */ \ + call(S, gen_atomic_cmpxchg, instr, d.val, t1, memop); \ + } else { \ + call(S, tcg_gen_qemu_st, d.val, t1, \ + instr->ctx->mmuidx, memop); \ + } \ + gen_set_label(l0); \ + \ + tcg_temp_free(t1); \ + temp_free(N, t0); \ + tagged_free(S, d); \ + tagged_free(N, b); \ + tagged_free(N, a); \ + } \ + } + +IMPL_ST(gen_st_ddd, d, d, tcg_gen_trunc_i64_tl) +IMPL_ST(gen_st_sdd, s, d, tcg_gen_trunc_i64_tl) + +// TODO: stgd ops must use GD.base +IMPL_ST(gen_st_dss, d, s, tcg_gen_extu_i32_tl) +IMPL_ST(gen_st_sss, s, s, tcg_gen_extu_i32_tl) + +static void gen_movif(TCGv_ptr ret, TCGv_i64 lo, TCGv_i32 hi) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + + tcg_gen_extu_i32_i64(t0, hi); + tcg_gen_st_i64(lo, ret, offsetof(E2KReg, lo)); + tcg_gen_st16_i64(t0, ret, offsetof(E2KReg, hi)); + + tcg_temp_free_i64(t0); +} + +static void gen_movfi(TCGv_i32 ret, TCGv_ptr arg) +{ + tcg_gen_ld16u_i32(ret, arg, offsetof(E2KReg, hi)); +} + +#define IMPL_MOVX(name, op) \ + static void name(TCGv_ptr ret, TCGv_ptr arg) \ + { \ + TCGv_i64 lo = tcg_temp_new_i64(); \ + TCGv_i64 hi = tcg_temp_new_i64(); \ + \ + tcg_gen_ld_i64(lo, arg, offsetof(E2KReg, lo)); \ + tcg_gen_ld16u_i64(hi, arg, offsetof(E2KReg, hi)); \ + op(hi, hi); \ + tcg_gen_st_i64(lo, ret, offsetof(E2KReg, lo)); \ + tcg_gen_st_i64(hi, ret, offsetof(E2KReg, hi)); \ + } + +#define movxa(r, t) tcg_gen_andi_i64(r, t, 0x7fff) +#define movxc(r, t) tcg_gen_xori_i64(r, t, 0x8000) + +IMPL_MOVX(gen_movx, tcg_gen_mov_i64); +IMPL_MOVX(gen_movxa, movxa); +IMPL_MOVX(gen_movxc, movxc); + +static inline void gen_shli2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 l, + TCGv_i64 h, int i) +{ + if (i == 0) { + tcg_gen_mov_i64(rl, l); + } else if (i < 64) { + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + tcg_gen_shri_i64(t0, l, 64 - i); + tcg_gen_shli_i64(t1, h, i); + tcg_gen_shli_i64(rl, l, i); + tcg_gen_or_i64(rh, t1, t0); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t0); + } else if (i < 128) { + tcg_gen_movi_i64(rl, 0); + tcg_gen_shli_i64(rh, l, i - 64); + } else { + tcg_gen_movi_i64(rl, 0); + tcg_gen_movi_i64(rh, 0); + } +} + +static inline void gen_shri2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 l, + TCGv_i64 h, int i) +{ + if (i == 0) { + tcg_gen_mov_i64(rl, l); + } else if (i < 64) { + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + tcg_gen_shli_i64(t0, h, 64 - i); + tcg_gen_shri_i64(t1, l, i); + tcg_gen_or_i64(rl, t1, t0); + tcg_gen_shri_i64(rh, h, i); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t0); + } else if (i < 128) { + tcg_gen_shri_i64(rl, h, i - 64); + tcg_gen_movi_i64(rh, 0); + } else { + tcg_gen_movi_i64(rl, 0); + tcg_gen_movi_i64(rh, 0); + } +} + +static inline void gen_psllql(TCGv_i64 ret, TCGv_i64 src1, + TCGv_i64 src2, int i) +{ + tcg_gen_shli_i64(ret, src2, i * 8); +} + +static inline void gen_psllqh(TCGv_i64 ret, TCGv_i64 src1, + TCGv_i64 src2, int i) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + gen_shli2_i64(t0, ret, src2, src1, i * 8); + tcg_temp_free_i64(t0); +} + +static inline void gen_psrlql(TCGv_i64 ret, TCGv_i64 src1, + TCGv_i64 src2, int i) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + gen_shri2_i64(ret, t0, src2, src1, i * 8); + tcg_temp_free_i64(t0); +} + +static inline void gen_psrlqh(TCGv_i64 ret, TCGv_i64 src1, + TCGv_i64 src2, int i) +{ + tcg_gen_shri_i64(ret, src1, i * 8); +} + +static inline void gen_pinsh(TCGv_i64 ret, TCGv_i64 src1, + TCGv_i64 src2, int i) +{ + if (i < 4) { + tcg_gen_deposit_i64(ret, src1, src2, i * 16, 16); + } else { + tcg_gen_mov_i64(ret, src1); + } +} + +static inline void gen_pextrh(TCGv_i64 ret, TCGv_i64 src1, + TCGv_i64 src2, int i) +{ + if (i < 4) { + tcg_gen_extract_i64(ret, src2, i * 16, 16); + } else if (i < 8) { + tcg_gen_extract_i64(ret, src1, (i - 4) * 16, 16); + } else { + tcg_gen_movi_i64(ret, 0); + } +} + +static inline void gen_pshufw(TCGv_i64 ret, TCGv_i64 src1, + TCGv_i64 src2, int i) +{ + TCGv_i32 imm8 = tcg_const_i32(i); + gen_helper_pshufw(ret, src1, src2, imm8); + tcg_temp_free_i32(imm8); +} + +static void gen_aad_tag(TCGv_i64 ret, TCGv_i32 tag) +{ + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_setcondi_i32(TCG_COND_NE, t0, tag, 0); + tcg_gen_extu_i32_i64(t1, t0); + tcg_gen_shli_i64(ret, t1, 54); + + tcg_temp_free_i64(t1); + tcg_temp_free_i32(t0); +} + +static void gen_aaurw_aad_lo_i64(Instr *instr, TCGv_i64 arg1, TCGv_i32 tag) +{ + TCGv_i64 lo = cpu_aad_lo[instr->aad]; + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_andi_i64(t0, arg1, 3UL << 57); + tcg_gen_andi_i64(lo, lo, ~(0x1fUL << 54)); + tcg_gen_or_i64(lo, lo, t0); + tcg_gen_deposit_i64(lo, lo, arg1, 0, 48); + tcg_gen_ori_i64(lo, lo, 3UL << 59); + gen_aad_tag(t1, tag); + tcg_gen_or_i64(lo, lo, t1); + + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t0); +} + +static void gen_aaurw_aad_hi_i64(Instr *instr, TCGv_i64 arg1, TCGv_i32 tag) +{ + tcg_gen_andi_i64(cpu_aad_hi[instr->aad], arg1, 0xffffffff00000000); +} + +static void gen_aaurw_aad_i32(Instr *instr, TCGv_i32 arg1, TCGv_i32 tag) +{ + TCGv_i64 lo = cpu_aad_lo[instr->aad]; + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + + tcg_gen_extu_i32_i64(t0, arg1); + tcg_gen_deposit_i64(lo, lo, t0, 0, 48); + tcg_gen_ori_i64(lo, lo, 3UL << 59); + tcg_gen_andi_i64(lo, lo, ~(0x7UL << 54)); + gen_aad_tag(t1, tag); + tcg_gen_or_i64(lo, lo, t1); + + tcg_temp_free_i64(t2); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t0); +} + +static void gen_aaurw_rest_i32(Instr* instr, TCGv_i32 arg1, TCGv_i32 tag) +{ + int idx = instr->aaind; + TCGv_i32 t0 = tcg_temp_new_i32(); + tcg_gen_setcondi_i32(TCG_COND_NE, t0, tag, 0); + switch(instr->aaopc) { + case 1: /* aaurwd src4, aasti */ + tcg_gen_mov_i32(cpu_aasti[idx], arg1); + tcg_gen_deposit_i32(cpu_aasti_tags, cpu_aasti_tags, t0, idx, 1); + break; + case 2: { /* aaurwd src4, aaind */ + if (idx == 0) { + tcg_gen_movi_i32(cpu_aaind[idx], 0); + } else { + tcg_gen_mov_i32(cpu_aaind[idx], arg1); + tcg_gen_deposit_i32(cpu_aaind_tags, cpu_aaind_tags, t0, + idx, 1); + } + break; + } + case 3: /* aaurwd src4, aaincr */ + idx &= 7; + if (idx > 0) { + tcg_gen_mov_i32(cpu_aaincr[idx], arg1); + tcg_gen_deposit_i32(cpu_aaincr_tags, cpu_aaincr_tags, t0, + idx, 1); + } + break; + default: + g_assert_not_reached(); + break; + } + tcg_temp_free_i32(t0); +} + +static void gen_aasti_incr(DisasContext *ctx, Instr *instr) +{ + uint16_t rlp = find_am_cond(ctx, instr->chan); + TCGLabel *l0 = gen_new_label(); + TCGv_i32 t0 = tcg_temp_new_i32(); + + if (ctx->loop_mode) { + TCGLabel *l1 = gen_new_label(); + TCGv_i32 t0 = tcg_temp_local_new_i32(); + + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_lsr_pcnt, 0, l0); + gen_is_loop_end_i32(t0); + tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1); + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_lsr_strmd, 0, l0); + gen_set_label(l1); + } + + if (rlp != 0) { + // FIXME: need to test AM RLP + TCGv_i32 t1 = tcg_temp_new_i32(); + + e2k_todo(ctx, "AM RLP found"); + gen_am_cond_i32(ctx, t1, instr->chan, rlp); + tcg_gen_brcondi_i32(TCG_COND_EQ, t1, 0, l0); + tcg_temp_free_i32(t1); + } + + tcg_gen_muli_i32(t0, cpu_aaincr[instr->aaincr], instr->aaincr_len); + tcg_gen_add_i32(cpu_aasti[instr->aaind], cpu_aasti[instr->aaind], t0); + gen_set_label(l0); + + tcg_temp_free_i32(t0); +} + +static void gen_aad_ptr(DisasContext *ctx, TCGv ret, Instr *instr) +{ + uint32_t lit = 0; + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + + if (instr->aalit) { + int lts = instr->aalit - 1; + if (ctx->bundle.lts_present[lts]) { + lit = ctx->bundle.lts[lts]; + } else { + gen_tr_excp_illopn(ctx); + return; + } + } + + tcg_gen_extract_i64(t0, cpu_aad_lo[instr->aad], 0, 48); + tcg_gen_trunc_i64_tl(t1, t0); + tcg_gen_extu_i32_tl(t2, cpu_aasti[instr->aaind]); + if (lit != 0) { + TCGv t3 = tcg_temp_new(); + tcg_gen_add_tl(t3, t1, t2); + tcg_gen_addi_tl(ret, t3, lit); + tcg_temp_free(t3); + } else { + tcg_gen_add_tl(ret, t1, t2); + } + tcg_temp_free(t2); + tcg_temp_free(t1); + tcg_temp_free_i64(t0); +} + +static void gen_staa_i64(Instr *instr) +{ + DisasContext *ctx = instr->ctx; + uint8_t mas = instr->mas; + TCGLabel *l0 = gen_new_label(); + Tagged_i64 s4 = tagged_local_new_i64(); + + gen_loop_mode_st(ctx, l0); + gen_tagged_src4_d(instr, s4); + gen_tag_check(instr, s4.tag); + if (mas == 0x3f) { + /* aaurwd */ + if (instr->aaopc == 0) { + if (instr->chan == 5 && instr->opc1 == 0x3f) { + gen_aaurw_aad_hi_i64(instr, s4.val, s4.tag); + } else { + gen_aaurw_aad_lo_i64(instr, s4.val, s4.tag); + } + } else { + TCGv_i32 t0 = tcg_temp_new_i32(); + tcg_gen_extrl_i64_i32(t0, s4.val); + gen_aaurw_rest_i32(instr, t0, s4.tag); + tcg_temp_free_i32(t0); + } + } else { + /* staad */ + TCGLabel *l0 = gen_new_label(); + TCGv t0 = tcg_temp_local_new(); + + if (mas != 0) { + e2k_todo(ctx, "staad mas=%#x is not implemented", mas); + } + + gen_aad_ptr(ctx, t0, instr); + + if (instr->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, l0); + tcg_temp_free_i32(t1); + } + + tcg_gen_qemu_st_i64(s4.val, t0, ctx->mmuidx, MO_Q); + gen_set_label(l0); + tcg_temp_free(t0); + + if (instr->aaopc & 1) { + /* incr must be executed outside of the staa predicate condition */ + instr->aaincr_len = 8; + } + } + + gen_set_label(l0); + + tagged_free_i64(s4); +} + +static void gen_staa_i32(Instr *instr, MemOp memop) +{ + DisasContext *ctx = instr->ctx; + uint8_t mas = instr->mas; + TCGLabel *l0 = gen_new_label(); + Tagged_i32 s4 = tagged_local_new_i32(); + + gen_loop_mode_st(ctx, l0); + gen_tagged_src4_s(instr, s4); + gen_tag_check(instr, s4.tag); + if (mas == 0x3f) { + /* aaurw */ + /* CPU do nothing if size less than 32 bits */ + if ((memop & MO_SIZE) == MO_32) { + if (instr->aaopc == 0) { + gen_aaurw_aad_i32(instr, s4.val, s4.tag); + } else { + gen_aaurw_rest_i32(instr, s4.val, s4.tag); + } + } + } else { + /* staaw */ + int len; + TCGLabel *l0 = gen_new_label(); + TCGv t0 = tcg_temp_local_new(); + + if (mas != 0) { + char c; + switch(memop & MO_SIZE) { + case MO_8: c = 'b'; break; + case MO_16: c = 'h'; break; + case MO_32: c = 'w'; break; + default: + g_assert_not_reached(); + break; + } + e2k_todo(ctx, "staa%c mas=%#x", c, mas); + } + + gen_aad_ptr(ctx, t0, instr); + + if (instr->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, l0); + tcg_temp_free_i32(t1); + } + + tcg_gen_qemu_st_i32(s4.val, t0, ctx->mmuidx, memop); + gen_set_label(l0); + tcg_temp_free(t0); + + switch(memop & MO_SIZE) { + case MO_8: len = 1; break; + case MO_16: len = 2; break; + case MO_32: len = 4; break; + default: + g_assert_not_reached(); + break; + } + + if (instr->aaopc & 1) { + /* incr must be executed outside of the staa predicate condition */ + instr->aaincr_len = len; + } + } + + gen_set_label(l0); + + tagged_free_i32(s4); +} + +#define IMPL_ALOPF1_BASIC(name, S1, S2, R, T, code) \ + static void name(Instr *instr, T) \ + { \ + tagged(S1) s1 = tagged_local_new(S1); \ + tagged(S2) s2 = tagged_local_new(S2); \ + tagged(R) r = tagged_local_new(R); \ + \ + gen_tagged_src(1, S1, instr, s1); \ + gen_tagged_src(2, S2, instr, s2); \ + gen_result_init(R, instr, r); \ + gen_tag2(R, r, s1, s2); \ + { code; } \ + gen_al_result(R, instr, r); \ + \ + tagged_free(R, r); \ + tagged_free(S2, s2); \ + tagged_free(S1, s1); \ + } + +#define IMPL_ALOPF1(name, S1, S2, R) \ + IMPL_ALOPF1_BASIC(name, S1, S2, R, \ + void (*op)(temp(R), temp(S1), temp(S2)), \ + { (*op)(r.val, s1.val, s2.val); }) + +IMPL_ALOPF1(gen_alopf1_sss, s, s, s) +IMPL_ALOPF1(gen_alopf1_ssd, s, s, d) +IMPL_ALOPF1(gen_alopf1_sdd, d, s, d) +IMPL_ALOPF1(gen_alopf1_ddd, d, d, d) +IMPL_ALOPF1(gen_alopf1_dsx, d, s, x) + +#define IMPL_ALOPF1_TAG_SM(name, S1, S2, R) \ + IMPL_ALOPF1_BASIC(name, S1, S2, R, \ + void (*op)(temp(R), TCGv_i32, TCGv_i32, \ + temp(S1), temp(S2), bool sm), \ + { (*op)(r.val, r.tag, r.tag, s1.val, s2.val, instr->sm); }) + +IMPL_ALOPF1_TAG_SM(gen_alopf1_ttsss, s, s, s) +IMPL_ALOPF1_TAG_SM(gen_alopf1_ttdss, d, s, s) +IMPL_ALOPF1_TAG_SM(gen_alopf1_ttddd, d, d, d) + +#define IMPL_ALOPF1_ENV(name, S1, S2, R) \ + IMPL_ALOPF1_BASIC(name, S1, S2, R, \ + void (*op)(temp(R), TCGv_env, temp(S1), temp(S2)), \ + { (*op)(r.val, cpu_env, s1.val, s2.val); }) + +IMPL_ALOPF1_ENV(gen_alopf1_esss, s, s, s) +IMPL_ALOPF1_ENV(gen_alopf1_edsd, d, s, d) +IMPL_ALOPF1_ENV(gen_alopf1_eddd, d, d, d) +IMPL_ALOPF1_ENV(gen_alopf1_exxs, x, x, s) +IMPL_ALOPF1_ENV(gen_alopf1_exxd, x, x, d) +IMPL_ALOPF1_ENV(gen_alopf1_exss, x, s, s) +IMPL_ALOPF1_ENV(gen_alopf1_exds, x, d, s) +IMPL_ALOPF1_ENV(gen_alopf1_exdd, x, d, d) +IMPL_ALOPF1_ENV(gen_alopf1_exsx, x, s, x) +IMPL_ALOPF1_ENV(gen_alopf1_exdx, x, d, x) +IMPL_ALOPF1_ENV(gen_alopf1_esxs, s, x, s) +IMPL_ALOPF1_ENV(gen_alopf1_edxd, d, x, d) +IMPL_ALOPF1_ENV(gen_alopf1_esxx, s, x, x) +IMPL_ALOPF1_ENV(gen_alopf1_edxx, d, x, x) +IMPL_ALOPF1_ENV(gen_alopf1_exxx, x, x, x) + +#define IMPL_ALOPF2_BASIC(name, S2, R, T, code) \ + static void name(Instr *instr, T) \ + { \ + tagged(S2) s2 = tagged_local_new(S2); \ + tagged(R) r = tagged_local_new(R); \ + \ + gen_tagged_src(2, S2, instr, s2); \ + gen_result_init(R, instr, r); \ + gen_tag1(R, r, s2); \ + { code; } \ + gen_al_result(R, instr, r); \ + \ + tagged_free(R, r); \ + tagged_free(S2, s2); \ + } + +#define IMPL_ALOPF2(name, S2, R) \ + IMPL_ALOPF2_BASIC(name, S2, R, \ + void (*op)(temp(R), temp(S2)), \ + { (*op)(r.val, s2.val); }) + +IMPL_ALOPF2(gen_alopf2_ss, s, s) +IMPL_ALOPF2(gen_alopf2_dd, d, d) +IMPL_ALOPF2(gen_alopf2_xs, x, s) +IMPL_ALOPF2(gen_alopf2_xx, x, x) + +#define IMPL_ALOPF2_ENV(name, S2, R) \ + IMPL_ALOPF2_BASIC(name, S2, R, \ + void (*op)(temp(R), TCGv_env, temp(S2)), \ + { (*op)(r.val, cpu_env, s2.val); }) + +IMPL_ALOPF2_ENV(gen_alopf2_ess, s, s) +IMPL_ALOPF2_ENV(gen_alopf2_eds, d, s) +IMPL_ALOPF2_ENV(gen_alopf2_esd, s, d) +IMPL_ALOPF2_ENV(gen_alopf2_edd, d, d) +IMPL_ALOPF2_ENV(gen_alopf2_edx, d, x) +IMPL_ALOPF2_ENV(gen_alopf2_exs, x, s) +IMPL_ALOPF2_ENV(gen_alopf2_exd, x, d) +IMPL_ALOPF2_ENV(gen_alopf2_esx, s, x) + +#define IMPL_ALOPF2_PSHUFH(name, S2, R) \ + IMPL_ALOPF2_BASIC(name, S2, R, \ + void (*op)(temp(R), temp(S2), TCGv_i32), \ + { \ + TCGv_i32 t0 = tcg_const_i32(instr->src3); \ + (*op)(r.val, s2.val, t0); \ + tcg_temp_free_i32(t0); \ + }) + +IMPL_ALOPF2_PSHUFH(gen_alopf2_pshufh, d, d) + +#define IMPL_ALOPF7_BASIC(name, S1, S2, R, T, code) \ + static void name(Instr *instr, T) \ + { \ + tagged(S1) s1 = tagged_local_new(S1); \ + tagged(S2) s2 = tagged_local_new(S2); \ + tagged(R) r = tagged_local_new(R); \ + Tagged_i32 p = tagged_new_i32(); \ + temp(R) t0 = temp_new(R); \ + \ + gen_tagged_src(1, S1, instr, s1); \ + gen_tagged_src(2, S2, instr, s2); \ + gen_result_init(R, instr, r); \ + gen_tag2(R, r, s1, s2); \ + { code; } \ + tcg_gen_mov_i32(p.tag, r.tag); \ + call(R, tcg_gen_setcondi, TCG_COND_NE, t0, r.val, 0); \ + call(R, gen_extrl, p.val, t0); \ + gen_al_result_b(instr, p); \ + \ + temp_free(R, t0); \ + tagged_free_i32(p); \ + tagged_free(R, r); \ + tagged_free(S2, s2); \ + tagged_free(S1, s1); \ + } + +#define IMPL_ALOPF7(name, S1, S2, R) \ + IMPL_ALOPF7_BASIC(name, S1, S2, R, \ + void (*op)(temp(R), temp(S1), temp(S2)), \ + { (*op)(r.val, s1.val, s2.val); }) + +IMPL_ALOPF7(gen_alopf7_sss, s, s, s) +IMPL_ALOPF7(gen_alopf7_ddd, d, d, d) + +#define IMPL_ALOPF7_ENV(name, S1, S2, R) \ + IMPL_ALOPF7_BASIC(name, S1, S2, R, \ + void (*op)(temp(R), TCGv_env, temp(S1), temp(S2)), \ + { (*op)(r.val, cpu_env, s1.val, s2.val); }) + +IMPL_ALOPF7_ENV(gen_alopf7_esss, s, s, s) +IMPL_ALOPF7_ENV(gen_alopf7_eddd, d, d, d) +IMPL_ALOPF7_ENV(gen_alopf7_exsd, x, s, d) +IMPL_ALOPF7_ENV(gen_alopf7_exdd, x, d, d) +IMPL_ALOPF7_ENV(gen_alopf7_exxd, x, x, d) + +#define IMPL_ALOPF11_LIT8(name, S1, S2, R) \ + IMPL_ALOPF1_BASIC(name, S1, S2, R, \ + void (*op)(temp(R), temp(S1), temp(S2), int), \ + { (*op)(r.val, s1.val, s2.val, instr->src3); }) + +IMPL_ALOPF11_LIT8(gen_alopf11_ddid, d, d, d) + +#define IMPL_ALOPF21_BASIC(name, S1, S2, S3, R, T, code) \ + static void name(Instr *instr, T) \ + { \ + tagged(S1) s1 = tagged_local_new(S1); \ + tagged(S2) s2 = tagged_local_new(S2); \ + tagged(S3) s3 = tagged_local_new(S3); \ + tagged(R) r = tagged_local_new(R); \ + \ + gen_tagged_src(1, S1, instr, s1); \ + gen_tagged_src(2, S2, instr, s2); \ + gen_tagged_src(3, S3, instr, s3); \ + gen_result_init(R, instr, r); \ + gen_tag3(R, r, s1, s2, s3); \ + { code; } \ + gen_al_result(R, instr, r); \ + \ + tagged_free(R, r); \ + tagged_free(S3, s3); \ + tagged_free(S2, s2); \ + tagged_free(S1, s1); \ + } + +#define IMPL_ALOPF21(name, S1, S2, S3, R) \ + IMPL_ALOPF21_BASIC(name, S1, S2, S3, R, \ + void (*op)(temp(R), temp(S1), temp(S2), temp(S3)), \ + { (*op)(r.val, s1.val, s2.val, s3.val); }) + +IMPL_ALOPF21(gen_alopf21_ssss, s, s, s, s) +IMPL_ALOPF21(gen_alopf21_dddd, d, d, d, d) + +static AlopDesc *find_op(Instr *instr) +{ + /* ALES2/5 may be allocated but must not be used */ + int opc2 = instr->ales_present & ALES_PRESENT ? instr->opc2 : 0; + int16_t index = alops_map[opc2][instr->opc1][instr->chan]; + while (index != -1) { + bool is_match = false; + AlopDesc *desc = &alops[index]; + switch(desc->alopf) { + case ALOPF1: + case ALOPF1_MERGE: + case ALOPF3: + case ALOPF10: + case ALOPF11_LIT8: + case ALOPF12_PSHUFH: + case ALOPF21: + is_match = true; + break; + case ALOPF2: + case ALOPF15: + is_match = desc->extra1 == instr->opce1; + break; + case ALOPF7: + is_match = desc->extra1 == instr->opc_cmp; + break; + case ALOPF8: + is_match = desc->extra1 == instr->opc_cmp && instr->opce1 == 0xc0; + break; + case ALOPF11: + case ALOPF11_MERGE: + case ALOPF13: + case ALOPF17: + is_match = desc->extra1 == instr->opce3; + break; + case ALOPF12: + case ALOPF12_IBRANCHD: + case ALOPF12_ICALLD: + case ALOPF22: + is_match = desc->extra1 == instr->opce1 && desc->extra2 == instr->opce3; + break; + case ALOPF16: + is_match = desc->extra1 == instr->opce2; + break; + default: + g_assert_not_reached(); + break; + } + + if (is_match) { + return desc; + } + + index = desc->next[instr->chan]; + } + + 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: + 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: + case ALOPF21_ICOMB: + case ALOPF21_FCOMB: + case ALOPF21_PFCOMB: + case ALOPF21_LCOMB: + 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_alop_simple(Instr *instr, uint32_t op, const char *name) +{ + DisasContext *ctx = instr->ctx; + int chan = instr->chan; + switch(op) { + 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_ANDNS: gen_alopf1_sss(instr, gen_andn_i32); break; + case OP_ANDND: gen_alopf1_ddd(instr, gen_andn_i64); break; + case OP_ORS: gen_alopf1_sss(instr, tcg_gen_or_i32); break; + case OP_ORD: gen_alopf1_ddd(instr, tcg_gen_or_i64); break; + case OP_ORNS: gen_alopf1_sss(instr, gen_orn_i32); break; + case OP_ORND: gen_alopf1_ddd(instr, gen_orn_i64); break; + case OP_XORS: gen_alopf1_sss(instr, tcg_gen_xor_i32); break; + case OP_XORD: gen_alopf1_ddd(instr, tcg_gen_xor_i64); break; + case OP_XORNS: gen_alopf1_sss(instr, gen_xorn_i32); break; + case OP_XORND: gen_alopf1_ddd(instr, gen_xorn_i64); break; + case OP_SXT: gen_alopf1_sdd(instr, gen_helper_sxt); break; + case OP_ADDS: gen_alopf1_sss(instr, tcg_gen_add_i32); break; + case OP_ADDD: gen_alopf1_ddd(instr, tcg_gen_add_i64); break; + case OP_SUBS: gen_alopf1_sss(instr, tcg_gen_sub_i32); break; + case OP_SUBD: gen_alopf1_ddd(instr, tcg_gen_sub_i64); break; + case OP_SCLS: gen_alopf1_sss(instr, tcg_gen_rotl_i32); break; + case OP_SCLD: gen_alopf1_ddd(instr, tcg_gen_rotl_i64); break; + case OP_SCRS: gen_alopf1_sss(instr, tcg_gen_rotr_i32); break; + case OP_SCRD: gen_alopf1_ddd(instr, tcg_gen_rotr_i64); break; + case OP_SHLS: gen_alopf1_sss(instr, tcg_gen_shl_i32); break; + case OP_SHLD: gen_alopf1_ddd(instr, tcg_gen_shl_i64); break; + case OP_SHRS: gen_alopf1_sss(instr, tcg_gen_shr_i32); break; + case OP_SHRD: gen_alopf1_ddd(instr, tcg_gen_shr_i64); break; + case OP_SARS: gen_alopf1_sss(instr, tcg_gen_sar_i32); break; + case OP_SARD: gen_alopf1_ddd(instr, tcg_gen_sar_i64); break; + case OP_GETFS: gen_alopf1_sss(instr, gen_getfs); break; + case OP_GETFD: gen_alopf1_ddd(instr, gen_getfd); break; + case OP_MERGES: gen_merges(instr); break; + case OP_MERGED: gen_merged(instr); break; + case OP_CMPOSB: gen_alopf7_sss(instr, gen_cmposb); break; + case OP_CMPBSB: gen_alopf7_sss(instr, gen_cmpbsb); break; + case OP_CMPESB: gen_alopf7_sss(instr, gen_cmpesb); break; + case OP_CMPBESB: gen_alopf7_sss(instr, gen_cmpbesb); break; + case OP_CMPSSB: gen_alopf7_sss(instr, gen_cmpssb); break; + case OP_CMPPSB: gen_alopf7_sss(instr, gen_cmppsb); break; + case OP_CMPLSB: gen_alopf7_sss(instr, gen_cmplsb); break; + case OP_CMPLESB: gen_alopf7_sss(instr, gen_cmplesb); break; + case OP_CMPODB: gen_alopf7_ddd(instr, gen_cmpodb); break; + case OP_CMPBDB: gen_alopf7_ddd(instr, gen_cmpbdb); break; + case OP_CMPEDB: gen_alopf7_ddd(instr, gen_cmpedb); break; + case OP_CMPBEDB: gen_alopf7_ddd(instr, gen_cmpbedb); break; + case OP_CMPSDB: gen_alopf7_ddd(instr, gen_cmpsdb); break; + case OP_CMPPDB: gen_alopf7_ddd(instr, gen_cmppdb); break; + case OP_CMPLDB: gen_alopf7_ddd(instr, gen_cmpldb); break; + case OP_CMPLEDB: gen_alopf7_ddd(instr, gen_cmpledb); break; + case OP_CMPANDESB: gen_alopf7_sss(instr, gen_cmpandesb); break; + case OP_CMPANDSSB: gen_alopf7_sss(instr, gen_cmpandssb); break; + case OP_CMPANDPSB: gen_alopf7_sss(instr, gen_cmpandpsb); break; + case OP_CMPANDLESB: gen_alopf7_sss(instr, gen_cmpandlesb); break; + case OP_CMPANDEDB: gen_alopf7_ddd(instr, gen_cmpandedb); break; + case OP_CMPANDSDB: gen_alopf7_ddd(instr, gen_cmpandsdb); break; + case OP_CMPANDPDB: gen_alopf7_ddd(instr, gen_cmpandpdb); break; + case OP_CMPANDLEDB: gen_alopf7_ddd(instr, gen_cmpandledb); break; + case OP_FCMPEQSB: gen_alopf7_esss(instr, gen_helper_fcmpeqs); break; + case OP_FCMPLTSB: gen_alopf7_esss(instr, gen_helper_fcmplts); break; + case OP_FCMPLESB: gen_alopf7_esss(instr, gen_helper_fcmples); break; + case OP_FCMPUODSB: gen_alopf7_esss(instr, gen_helper_fcmpuods); break; + case OP_FCMPNEQSB: gen_alopf7_esss(instr, gen_helper_fcmpneqs); break; + case OP_FCMPNLTSB: gen_alopf7_esss(instr, gen_helper_fcmpnlts); break; + case OP_FCMPNLESB: gen_alopf7_esss(instr, gen_helper_fcmpnles); break; + case OP_FCMPODSB: gen_alopf7_esss(instr, gen_helper_fcmpods); break; + case OP_FCMPEQDB: gen_alopf7_eddd(instr, gen_helper_fcmpeqd); break; + case OP_FCMPLTDB: gen_alopf7_eddd(instr, gen_helper_fcmpltd); break; + case OP_FCMPLEDB: gen_alopf7_eddd(instr, gen_helper_fcmpled); break; + case OP_FCMPUODDB: gen_alopf7_eddd(instr, gen_helper_fcmpuodd); break; + case OP_FCMPNEQDB: gen_alopf7_eddd(instr, gen_helper_fcmpneqd); break; + case OP_FCMPNLTDB: gen_alopf7_eddd(instr, gen_helper_fcmpnltd); break; + case OP_FCMPNLEDB: gen_alopf7_eddd(instr, gen_helper_fcmpnled); break; + case OP_FCMPODDB: gen_alopf7_eddd(instr, gen_helper_fcmpodd); break; + case OP_FXCMPEQSB: gen_alopf7_exsd(instr, gen_helper_fxcmpeqs); break; + case OP_FXCMPLTSB: gen_alopf7_exsd(instr, gen_helper_fxcmplts); break; + case OP_FXCMPLESB: gen_alopf7_exsd(instr, gen_helper_fxcmples); break; + case OP_FXCMPUODSB: gen_alopf7_exsd(instr, gen_helper_fxcmpuods); break; + case OP_FXCMPNEQSB: gen_alopf7_exsd(instr, gen_helper_fxcmpneqs); break; + case OP_FXCMPNLTSB: gen_alopf7_exsd(instr, gen_helper_fxcmpnlts); break; + case OP_FXCMPNLESB: gen_alopf7_exsd(instr, gen_helper_fxcmpnles); break; + case OP_FXCMPODSB: gen_alopf7_exsd(instr, gen_helper_fxcmpods); break; + case OP_FXCMPEQDB: gen_alopf7_exdd(instr, gen_helper_fxcmpeqd); break; + case OP_FXCMPLTDB: gen_alopf7_exdd(instr, gen_helper_fxcmpltd); break; + case OP_FXCMPLEDB: gen_alopf7_exdd(instr, gen_helper_fxcmpled); break; + case OP_FXCMPUODDB: gen_alopf7_exdd(instr, gen_helper_fxcmpuodd); break; + case OP_FXCMPNEQDB: gen_alopf7_exdd(instr, gen_helper_fxcmpneqd); break; + case OP_FXCMPNLTDB: gen_alopf7_exdd(instr, gen_helper_fxcmpnltd); break; + case OP_FXCMPNLEDB: gen_alopf7_exdd(instr, gen_helper_fxcmpnled); break; + case OP_FXCMPODDB: gen_alopf7_exdd(instr, gen_helper_fxcmpodd); break; + case OP_FXCMPEQXB: gen_alopf7_exxd(instr, gen_helper_fxcmpeqx); break; + case OP_FXCMPLTXB: gen_alopf7_exxd(instr, gen_helper_fxcmpltx); break; + case OP_FXCMPLEXB: gen_alopf7_exxd(instr, gen_helper_fxcmplex); break; + case OP_FXCMPUODXB: gen_alopf7_exxd(instr, gen_helper_fxcmpuodx); break; + case OP_FXCMPNEQXB: gen_alopf7_exxd(instr, gen_helper_fxcmpneqx); break; + case OP_FXCMPNLTXB: gen_alopf7_exxd(instr, gen_helper_fxcmpnltx); break; + case OP_FXCMPNLEXB: gen_alopf7_exxd(instr, gen_helper_fxcmpnlex); break; + case OP_FXCMPODXB: gen_alopf7_exxd(instr, gen_helper_fxcmpodx); break; + case OP_STB: gen_st_sdd(instr, MO_UB); break; + case OP_STH: gen_st_sdd(instr, MO_UW); break; + case OP_STW: gen_st_sdd(instr, MO_UL); break; + case OP_STD: gen_st_ddd(instr, MO_Q); break; + case OP_STGDB: gen_st_sss(instr, MO_UB); break; + case OP_STGDH: gen_st_sss(instr, MO_UW); break; + case OP_STGDW: gen_st_sss(instr, MO_UL); break; + case OP_STGDD: gen_st_dss(instr, MO_Q); break; + case OP_STGDQ: e2k_todo_illop(instr->ctx, "stgdq"); break; + case OP_LDB: gen_ld_mas_i64(instr, MO_UB); break; + case OP_LDH: gen_ld_mas_i64(instr, MO_UW); break; + case OP_LDW: gen_ld_mas_i64(instr, MO_UL); break; + case OP_LDD: gen_ld_mas_i64(instr, MO_Q); break; +#ifdef TARGET_E2K32 + case OP_LDGDB: gen_ld_mas_i32(instr, MO_UB); break; + case OP_LDGDH: gen_ld_mas_i32(instr, MO_UW); break; + case OP_LDGDW: gen_ld_mas_i32(instr, MO_UL); break; + case OP_LDGDD: gen_ld_mas_i32(instr, MO_Q); break; + case OP_LDGDQ: e2k_todo_illop(instr->ctx, "ldgdq"); break; +#else /* !TARGET_E2K32 */ + case OP_LDGDB: /* fallthrough */ + case OP_LDGDH: /* fallthrough */ + case OP_LDGDW: /* fallthrough */ + case OP_LDGDD: /* fallthrough */ + case OP_LDGDQ: gen_tr_excp_array_bounds(instr->ctx); break; +#endif + case OP_BITREVS: gen_alopf2_ss(instr, gen_bitrevs); break; + case OP_BITREVD: gen_alopf2_dd(instr, gen_bitrevd); break; + case OP_LZCNTS: gen_alopf2_ss(instr, gen_lzcnts); break; + case OP_LZCNTD: gen_alopf2_dd(instr, gen_lzcntd); break; + case OP_POPCNTS: gen_alopf2_ss(instr, tcg_gen_ctpop_i32); break; + case OP_POPCNTD: gen_alopf2_dd(instr, tcg_gen_ctpop_i64); break; + case OP_FADDS: gen_alopf1_esss(instr, gen_helper_fadds); break; + case OP_FADDD: gen_alopf1_eddd(instr, gen_helper_faddd); break; + case OP_FSUBS: gen_alopf1_esss(instr, gen_helper_fsubs); break; + case OP_FSUBD: gen_alopf1_eddd(instr, gen_helper_fsubd); break; + case OP_FMINS: gen_alopf1_esss(instr, gen_helper_fmins); break; + case OP_FMIND: gen_alopf1_eddd(instr, gen_helper_fmind); break; + case OP_FMAXS: gen_alopf1_esss(instr, gen_helper_fmaxs); break; + case OP_FMAXD: gen_alopf1_eddd(instr, gen_helper_fmaxd); break; + case OP_FMULS: gen_alopf1_esss(instr, gen_helper_fmuls); break; + case OP_FMULD: gen_alopf1_eddd(instr, gen_helper_fmuld); break; + case OP_FCMPEQS: gen_alopf1_esss(instr, gen_helper_fcmpeqs); break; + case OP_FCMPLTS: gen_alopf1_esss(instr, gen_helper_fcmplts); break; + case OP_FCMPLES: gen_alopf1_esss(instr, gen_helper_fcmples); break; + case OP_FCMPUODS: gen_alopf1_esss(instr, gen_helper_fcmpuods); break; + case OP_FCMPNEQS: gen_alopf1_esss(instr, gen_helper_fcmpneqs); break; + case OP_FCMPNLTS: gen_alopf1_esss(instr, gen_helper_fcmpnlts); break; + case OP_FCMPNLES: gen_alopf1_esss(instr, gen_helper_fcmpnles); break; + case OP_FCMPODS: gen_alopf1_esss(instr, gen_helper_fcmpods); break; + case OP_FCMPEQD: gen_alopf1_eddd(instr, gen_helper_fcmpeqd); break; + case OP_FCMPLTD: gen_alopf1_eddd(instr, gen_helper_fcmpltd); break; + case OP_FCMPLED: gen_alopf1_eddd(instr, gen_helper_fcmpled); break; + case OP_FCMPUODD: gen_alopf1_eddd(instr, gen_helper_fcmpuodd); break; + case OP_FCMPNEQD: gen_alopf1_eddd(instr, gen_helper_fcmpneqd); break; + case OP_FCMPNLTD: gen_alopf1_eddd(instr, gen_helper_fcmpnltd); break; + case OP_FCMPNLED: gen_alopf1_eddd(instr, gen_helper_fcmpnled); break; + case OP_FCMPODD: gen_alopf1_eddd(instr, gen_helper_fcmpodd); break; + case OP_FSTOIS: gen_alopf2_ess(instr, gen_helper_fstois); break; + case OP_FSTOISTR: gen_alopf2_ess(instr, gen_helper_fstoistr); break; + case OP_ISTOFS: gen_alopf2_ess(instr, gen_helper_istofs); break; + case OP_FDTOID: gen_alopf2_edd(instr, gen_helper_fdtoid); break; + case OP_IDTOFD: gen_alopf2_edd(instr, gen_helper_idtofd); break; + case OP_FXTOFD: gen_alopf2_exd(instr, gen_helper_fxtofd); break; + case OP_FDTOFX: gen_alopf2_edx(instr, gen_helper_fdtofx); break; + case OP_FSTOID: gen_alopf2_esd(instr, gen_helper_fstoid); break; + case OP_FSTOIDTR: gen_alopf2_esd(instr, gen_helper_fstoidtr); break; + case OP_FDTOIDTR: gen_alopf2_edd(instr, gen_helper_fdtoidtr); break; + case OP_ISTOFD: gen_alopf2_esd(instr, gen_helper_istofd); break; + case OP_FSTOFD: gen_alopf2_esd(instr, gen_helper_fstofd); break; + case OP_FSTOFX: gen_alopf2_esx(instr, gen_helper_fstofx); break; + case OP_FDTOISTR: gen_alopf2_eds(instr, gen_helper_fdtoistr); break; + case OP_FDTOIS: gen_alopf2_eds(instr, gen_helper_fdtois); break; + case OP_IDTOFS: gen_alopf2_eds(instr, gen_helper_idtofs); break; + case OP_FDTOFS: gen_alopf2_eds(instr, gen_helper_fdtofs); break; + case OP_FXTOFS: gen_alopf2_exs(instr, gen_helper_fxtofs); break; + case OP_FXTOIS: gen_alopf2_exs(instr, gen_helper_fxtois); break; + case OP_FXTOISTR: gen_alopf2_exs(instr, gen_helper_fxtoistr); break; + case OP_FXTOID: gen_alopf2_exd(instr, gen_helper_fxtoid); break; + case OP_FXTOIDTR: gen_alopf2_exd(instr, gen_helper_fxtoidtr); break; + case OP_ISTOFX: gen_alopf2_esx(instr, gen_helper_istofx); break; + case OP_IDTOFX: gen_alopf2_edx(instr, gen_helper_idtofx); break; + case OP_UDIVS: gen_alopf1_ttsss(instr, gen_udivs); break; + case OP_UDIVD: gen_alopf1_ttddd(instr, gen_udivd); break; + case OP_SDIVS: gen_alopf1_ttsss(instr, gen_sdivs); break; + case OP_SDIVD: gen_alopf1_ttddd(instr, gen_sdivd); break; + case OP_FXADDSS: gen_alopf1_exss(instr, gen_helper_fxaddss); break; + case OP_FXADDDD: gen_alopf1_exdd(instr, gen_helper_fxadddd); break; + case OP_FXADDSX: gen_alopf1_exsx(instr, gen_helper_fxaddsx); break; + case OP_FXADDDX: gen_alopf1_exdx(instr, gen_helper_fxadddx); break; + case OP_FXADDXX: gen_alopf1_exxx(instr, gen_helper_fxaddxx); break; + case OP_FXADDXD: gen_alopf1_exxd(instr, gen_helper_fxaddxd); break; + case OP_FXADDXS: gen_alopf1_exxs(instr, gen_helper_fxaddxs); break; + case OP_FXSUBSS: gen_alopf1_exss(instr, gen_helper_fxsubss); break; + case OP_FXSUBDD: gen_alopf1_exdd(instr, gen_helper_fxsubdd); break; + case OP_FXSUBSX: gen_alopf1_exsx(instr, gen_helper_fxsubsx); break; + case OP_FXSUBDX: gen_alopf1_exdx(instr, gen_helper_fxsubdx); break; + case OP_FXSUBXX: gen_alopf1_exxx(instr, gen_helper_fxsubxx); break; + case OP_FXSUBXD: gen_alopf1_exxd(instr, gen_helper_fxsubxd); break; + case OP_FXSUBXS: gen_alopf1_exxs(instr, gen_helper_fxsubxs); break; + case OP_FXRSUBSS: gen_alopf1_exss(instr, gen_helper_fxrsubss); break; + case OP_FXRSUBDD: gen_alopf1_exdd(instr, gen_helper_fxrsubdd); break; + case OP_FXRSUBSX: gen_alopf1_exsx(instr, gen_helper_fxrsubsx); break; + case OP_FXRSUBDX: gen_alopf1_exdx(instr, gen_helper_fxrsubdx); break; + case OP_FXMULSS: gen_alopf1_exss(instr, gen_helper_fxmulss); break; + case OP_FXMULDD: gen_alopf1_exdd(instr, gen_helper_fxmuldd); break; + case OP_FXMULSX: gen_alopf1_exsx(instr, gen_helper_fxmulsx); break; + case OP_FXMULDX: gen_alopf1_exdx(instr, gen_helper_fxmuldx); break; + case OP_FXMULXX: gen_alopf1_exxx(instr, gen_helper_fxmulxx); break; + case OP_FXMULXD: gen_alopf1_exxd(instr, gen_helper_fxmulxd); break; + case OP_FXMULXS: gen_alopf1_exxs(instr, gen_helper_fxmulxs); break; + case OP_FXDIVSS: gen_alopf1_exss(instr, gen_helper_fxdivss); break; + case OP_FXDIVDD: gen_alopf1_exdd(instr, gen_helper_fxdivdd); break; + case OP_FXDIVSX: gen_alopf1_exsx(instr, gen_helper_fxdivsx); break; + case OP_FXDIVDX: gen_alopf1_exdx(instr, gen_helper_fxdivdx); break; + case OP_FXDIVXX: gen_alopf1_exxx(instr, gen_helper_fxdivxx); break; + case OP_FXDIVXD: gen_alopf1_exxd(instr, gen_helper_fxdivxd); break; + case OP_FXDIVXS: gen_alopf1_exxs(instr, gen_helper_fxdivxs); break; + case OP_MOVFI: gen_alopf2_xs(instr, gen_movfi); break; + case OP_MOVIF: gen_alopf1_dsx(instr, gen_movif); break; + case OP_MOVX: gen_alopf2_xx(instr, gen_movx); break; + case OP_MOVXA: gen_alopf2_xx(instr, gen_movxa); break; + case OP_MOVXC: gen_alopf2_xx(instr, gen_movxc); break; + case OP_MOVTS: gen_movts(instr); break; + case OP_MOVTCS: gen_movtcs(instr); break; + case OP_MOVTD: gen_movtd(instr); break; + case OP_MOVTCD: gen_movtcd(instr); break; + case OP_MOVTQ: gen_movtq(instr); break; + case OP_MOVTCQ: gen_movtcq(instr); break; + case OP_GETPL: gen_getpl(instr); break; + case OP_PANDD: gen_alopf1_ddd(instr, tcg_gen_and_i64); break; + case OP_PANDND: gen_alopf1_ddd(instr, gen_andn_i64); break; + case OP_PORD: gen_alopf1_ddd(instr, tcg_gen_or_i64); break; + case OP_PXORD: gen_alopf1_ddd(instr, tcg_gen_xor_i64); break; + case OP_PMINUB: gen_alopf1_ddd(instr, gen_helper_pminub); break; + case OP_PMINSB: gen_alopf1_ddd(instr, gen_helper_pminsb); break; + case OP_PMINUH: gen_alopf1_ddd(instr, gen_helper_pminuh); break; + case OP_PMINSH: gen_alopf1_ddd(instr, gen_helper_pminsh); break; + case OP_PMINUW: gen_alopf1_ddd(instr, gen_helper_pminuw); break; + case OP_PMINSW: gen_alopf1_ddd(instr, gen_helper_pminsw); break; + case OP_PMAXUB: gen_alopf1_ddd(instr, gen_helper_pmaxub); break; + case OP_PMAXSB: gen_alopf1_ddd(instr, gen_helper_pmaxsb); break; + case OP_PMAXUH: gen_alopf1_ddd(instr, gen_helper_pmaxuh); break; + case OP_PMAXSH: gen_alopf1_ddd(instr, gen_helper_pmaxsh); break; + case OP_PMAXUW: gen_alopf1_ddd(instr, gen_helper_pmaxuw); break; + case OP_PMAXSW: gen_alopf1_ddd(instr, gen_helper_pmaxsw); break; + case OP_PCMPEQB: gen_alopf1_ddd(instr, gen_helper_pcmpeqb); break; + case OP_PCMPEQH: gen_alopf1_ddd(instr, gen_helper_pcmpeqh); break; + case OP_PCMPEQW: gen_alopf1_ddd(instr, gen_helper_pcmpeqw); break; + case OP_PCMPEQD: gen_alopf1_ddd(instr, gen_helper_pcmpeqd); break; + case OP_PCMPGTB: gen_alopf1_ddd(instr, gen_helper_pcmpgtb); break; + case OP_PCMPGTH: gen_alopf1_ddd(instr, gen_helper_pcmpgth); break; + case OP_PCMPGTW: gen_alopf1_ddd(instr, gen_helper_pcmpgtw); break; + case OP_PCMPGTD: gen_alopf1_ddd(instr, gen_helper_pcmpgtd); break; + case OP_PADDB: gen_alopf1_ddd(instr, tcg_gen_vec_add8_i64); break; + case OP_PADDH: gen_alopf1_ddd(instr, tcg_gen_vec_add16_i64); break; + case OP_PADDW: gen_alopf1_ddd(instr, tcg_gen_vec_add32_i64); break; + case OP_PADDD: gen_alopf1_ddd(instr, tcg_gen_add_i64); break; + case OP_PADDSB: gen_alopf1_ddd(instr, gen_helper_paddsb); break; + case OP_PADDSH: gen_alopf1_ddd(instr, gen_helper_paddsh); break; + case OP_PADDUSB: gen_alopf1_ddd(instr, gen_helper_paddusb); break; + case OP_PADDUSH: gen_alopf1_ddd(instr, gen_helper_paddush); break; + case OP_PHADDH: gen_alopf1_ddd(instr, gen_helper_phaddh); break; + case OP_PHADDW: gen_alopf1_ddd(instr, gen_helper_phaddw); break; + case OP_PHADDSH: gen_alopf1_ddd(instr, gen_helper_phaddsh); break; + case OP_PSUBB: gen_alopf1_ddd(instr, tcg_gen_vec_sub8_i64); break; + case OP_PSUBH: gen_alopf1_ddd(instr, tcg_gen_vec_sub16_i64); break; + case OP_PSUBW: gen_alopf1_ddd(instr, tcg_gen_vec_sub32_i64); break; + case OP_PSUBD: gen_alopf1_ddd(instr, tcg_gen_sub_i64); break; + case OP_PSUBSB: gen_alopf1_ddd(instr, gen_helper_psubsb); break; + case OP_PSUBSH: gen_alopf1_ddd(instr, gen_helper_psubsh); break; + case OP_PSUBUSB: gen_alopf1_ddd(instr, gen_helper_psubusb); break; + case OP_PSUBUSH: gen_alopf1_ddd(instr, gen_helper_psubush); break; + case OP_PHSUBH: gen_alopf1_ddd(instr, gen_helper_phsubh); break; + case OP_PHSUBW: gen_alopf1_ddd(instr, gen_helper_phsubw); break; + case OP_PHSUBSH: gen_alopf1_ddd(instr, gen_helper_phsubsh); break; + case OP_PMULHH: gen_alopf1_ddd(instr, gen_helper_pmulhh); break; + case OP_PMULLH: gen_alopf1_ddd(instr, gen_helper_pmullh); break; + case OP_PMULHUH: gen_alopf1_ddd(instr, gen_helper_pmulhuh); break; + case OP_PMULUBHH: gen_alopf1_ddd(instr, gen_helper_pmulubhh); break; + case OP_PMULHRSH: gen_alopf1_ddd(instr, gen_helper_pmulhrsh); break; + case OP_PMADDH: gen_alopf1_ddd(instr, gen_helper_pmaddh); break; + case OP_PMADDUBSH: gen_alopf1_ddd(instr, gen_helper_pmaddubsh); break; + case OP_MPSADBH: gen_alopf1_ddd(instr, gen_helper_mpsadbh); break; + case OP_PSADBW: gen_alopf1_ddd(instr, gen_helper_psadbw); break; + case OP_PSIGNB: gen_alopf1_ddd(instr, gen_helper_psignb); break; + case OP_PSIGNH: gen_alopf1_ddd(instr, gen_helper_psignh); break; + case OP_PSIGNW: gen_alopf1_ddd(instr, gen_helper_psignw); break; + case OP_PSLLH: gen_alopf1_ddd(instr, gen_helper_psllh); break; + case OP_PSLLW: gen_alopf1_ddd(instr, gen_helper_psllw); break; + case OP_PSLLD: gen_alopf1_ddd(instr, gen_pslld); break; + case OP_PSRLH: gen_alopf1_ddd(instr, gen_helper_psrlh); break; + case OP_PSRLW: gen_alopf1_ddd(instr, gen_helper_psrlw); break; + case OP_PSRLD: gen_alopf1_ddd(instr, gen_psrld); break; + case OP_PSRAH: gen_alopf1_ddd(instr, gen_helper_psrah); break; + case OP_PSRAW: gen_alopf1_ddd(instr, gen_helper_psraw); break; + case OP_PAVGUSB: gen_alopf1_ddd(instr, gen_helper_pavgusb); break; + case OP_PAVGUSH: gen_alopf1_ddd(instr, gen_helper_pavgush); break; + case OP_PSLLQL: gen_alopf11_ddid(instr, gen_psllql); break; + case OP_PSLLQH: gen_alopf11_ddid(instr, gen_psllqh); break; + case OP_PSRLQL: gen_alopf11_ddid(instr, gen_psrlql); break; + case OP_PSRLQH: gen_alopf11_ddid(instr, gen_psrlqh); break; + case OP_PINSH: gen_alopf11_ddid(instr, gen_pinsh); break; + case OP_PEXTRH: gen_alopf11_ddid(instr, gen_pextrh); break; + case OP_PSHUFH: gen_alopf2_pshufh(instr, gen_helper_pshufh); break; + case OP_PSHUFW: gen_alopf11_ddid(instr, gen_pshufw); break; + case OP_PMOVMSKB: gen_alopf1_ddd(instr, gen_helper_pmovmskb); break; + case OP_PMOVMSKPS: gen_alopf1_ddd(instr, gen_helper_pmovmskps); break; + case OP_PMOVMSKPD: gen_alopf1_ddd(instr, gen_helper_pmovmskpd); break; + case OP_PACKSSHB: gen_alopf1_ddd(instr, gen_helper_packsshb); break; + case OP_PACKUSHB: gen_alopf1_ddd(instr, gen_helper_packushb); break; + case OP_PACKSSWH: gen_alopf1_ddd(instr, gen_helper_packsswh); break; + case OP_PACKUSWH: gen_alopf1_ddd(instr, gen_helper_packuswh); break; + case OP_PUNPCKLBH: gen_alopf1_ddd(instr, gen_helper_punpcklbh); break; + case OP_PUNPCKLHW: gen_alopf1_ddd(instr, gen_helper_punpcklhw); break; + case OP_PUNPCKLWD: gen_alopf1_ddd(instr, gen_helper_punpcklwd); break; + case OP_PUNPCKHBH: gen_alopf1_ddd(instr, gen_helper_punpckhbh); break; + case OP_PUNPCKHHW: gen_alopf1_ddd(instr, gen_helper_punpckhhw); break; + case OP_PUNPCKHWD: gen_alopf1_ddd(instr, gen_helper_punpckhwd); break; + case OP_PHMINPOSUH: gen_alopf1_ddd(instr, gen_helper_phminposuh); break; + case OP_GETTAGS: gen_gettags(instr); break; + case OP_GETTAGD: gen_gettagd(instr); break; + case OP_PUTTAGS: gen_puttags(instr); break; + case OP_PUTTAGD: gen_puttagd(instr); break; + case OP_STAAB: gen_staa_i32(instr, MO_8); break; + case OP_STAAH: gen_staa_i32(instr, MO_16); break; + case OP_STAAW: gen_staa_i32(instr, MO_32); break; + case OP_STAAD: gen_staa_i64(instr); break; + case OP_STAAQ: { + int pair_chan = chan == 2 ? 5 : 2; + if (!ctx->bundle.als_present[pair_chan] || + extract32(ctx->bundle.als[pair_chan], 24, 7) != 0x3f || + (instr->dst & 1) != (chan == 2 ? 0 : 1)) + { + gen_tr_excp_illopc(ctx); + return; + } + gen_staa_i64(instr); + break; + } + case OP_MULS: gen_alopf1_sss(instr, tcg_gen_mul_i32); break; + case OP_MULD: gen_alopf1_ddd(instr, tcg_gen_mul_i64); break; + case OP_UMULX: gen_alopf1_ssd(instr, gen_umulx); break; + case OP_SMULX: gen_alopf1_ssd(instr, gen_smulx); break; + case OP_RWS: gen_rws(instr); break; + case OP_RWD: gen_rwd(instr); break; + case OP_RRS: gen_rrd(instr); break; + case OP_RRD: gen_rrd(instr); break; + case OP_FDIVS: gen_alopf1_esss(instr, gen_helper_fdivs); break; + case OP_FDIVD: gen_alopf1_eddd(instr, gen_helper_fdivd); break; + case OP_GETSP: gen_alopf2_esd(instr, gen_helper_getsp); break; + case OP_UMULHD: gen_alopf1_ddd(instr, gen_umulhd); break; + case OP_SMULHD: gen_alopf1_ddd(instr, gen_smulhd); break; + case OP_FCMPODSF: gen_alopf1_esss(instr, gen_helper_fcmpodsf); break; + case OP_FCMPUDSF: gen_alopf1_esss(instr, gen_helper_fcmpudsf); break; + case OP_FCMPODDF: gen_alopf1_eddd(instr, gen_helper_fcmpoddf); break; + case OP_FCMPUDDF: gen_alopf1_eddd(instr, gen_helper_fcmpoddf); break; + case OP_FXCMPODSF: gen_alopf1_exss(instr, gen_helper_fxcmpodsf); break; + case OP_FXCMPUDSF: gen_alopf1_exss(instr, gen_helper_fxcmpudsf); break; + case OP_FXCMPODDF: gen_alopf1_exds(instr, gen_helper_fxcmpoddf); break; + case OP_FXCMPUDDF: gen_alopf1_exds(instr, gen_helper_fxcmpuddf); break; + case OP_FXCMPODXF: gen_alopf1_exxs(instr, gen_helper_fxcmpodxf); break; + case OP_FXCMPUDXF: gen_alopf1_exxs(instr, gen_helper_fxcmpudxf); break; + case OP_FSTOIFS: gen_alopf1_esss(instr, gen_helper_fstoifs); break; + case OP_FDTOIFD: gen_alopf1_eddd(instr, gen_helper_fdtoifd); break; + case OP_UDIVX: gen_alopf1_ttdss(instr, gen_udivx); break; + case OP_UMODX: gen_alopf1_ttdss(instr, gen_umodx); break; + case OP_SDIVX: gen_alopf1_ttdss(instr, gen_sdivx); break; + case OP_SMODX: gen_alopf1_ttdss(instr, gen_smodx); break; + case OP_PFMULD: gen_alopf1_eddd(instr, gen_helper_fmuld); break; + case OP_PFADDD: gen_alopf1_eddd(instr, gen_helper_faddd); break; + case OP_PFSUBD: gen_alopf1_eddd(instr, gen_helper_fsubd); break; + case OP_PFDIVD: gen_alopf1_eddd(instr, gen_helper_fdivd); break; + case OP_PFMIND: gen_alopf1_eddd(instr, gen_helper_fmind); break; + case OP_PFMAXD: gen_alopf1_eddd(instr, gen_helper_fmaxd); break; + case OP_PFADDS: gen_alopf1_eddd(instr, gen_helper_pfadds); break; + case OP_PFSUBS: gen_alopf1_eddd(instr, gen_helper_pfsubs); break; + case OP_PFMULS: gen_alopf1_eddd(instr, gen_helper_pfmuls); break; + case OP_PFDIVS: gen_alopf1_esss(instr, gen_helper_fdivs); break; + case OP_PFMAXS: gen_alopf1_eddd(instr, gen_helper_pfmaxs); break; + case OP_PFMINS: gen_alopf1_eddd(instr, gen_helper_pfmins); break; + case OP_PFHADDS: gen_alopf1_eddd(instr, gen_helper_pfhadds); break; + case OP_PFHSUBS: gen_alopf1_eddd(instr, gen_helper_pfhsubs); break; + case OP_PFADDSUBS: gen_alopf1_eddd(instr, gen_helper_pfaddsubs); break; + case OP_PFSQRTS: gen_alopf2_ess(instr, gen_helper_fsqrts); break; + case OP_PFSTOIFS: gen_alopf1_eddd(instr, gen_helper_pfstoifs); break; + case OP_PISTOFS: gen_alopf2_edd(instr, gen_helper_pistofs); break; + case OP_PFSTOIS: gen_alopf2_edd(instr, gen_helper_pfstois); break; + case OP_PFSTOISTR: gen_alopf2_edd(instr, gen_helper_pfstoistr); break; + case OP_PFSTOFD: gen_alopf2_esd(instr, gen_helper_fstofd); break; + case OP_PFDTOFS: gen_alopf2_eds(instr, gen_helper_fdtofs); break; + case OP_PFDTOIFD: gen_alopf1_eddd(instr, gen_helper_fdtoifd); break; + case OP_PFDTOIS: gen_alopf2_eds(instr, gen_helper_fdtois); break; + case OP_PFDTOISTR: gen_alopf2_eds(instr, gen_helper_fdtoistr); break; + case OP_PFCMPEQS: gen_alopf1_eddd(instr, gen_helper_pfcmpeqs); break; + case OP_PFCMPLTS: gen_alopf1_eddd(instr, gen_helper_pfcmplts); break; + case OP_PFCMPLES: gen_alopf1_eddd(instr, gen_helper_pfcmples); break; + case OP_PFCMPUODS: gen_alopf1_eddd(instr, gen_helper_pfcmpuods); break; + case OP_PFCMPNEQS: gen_alopf1_eddd(instr, gen_helper_pfcmpneqs); break; + case OP_PFCMPNLTS: gen_alopf1_eddd(instr, gen_helper_pfcmpnlts); break; + case OP_PFCMPNLES: gen_alopf1_eddd(instr, gen_helper_pfcmpnles); break; + case OP_PFCMPODS: gen_alopf1_eddd(instr, gen_helper_pfcmpods); break; + case OP_PFCMPEQD: gen_alopf1_eddd(instr, gen_helper_fcmpeqd); break; + case OP_PFCMPLTD: gen_alopf1_eddd(instr, gen_helper_fcmpltd); break; + case OP_PFCMPLED: gen_alopf1_eddd(instr, gen_helper_fcmpled); break; + case OP_PFCMPUODD: gen_alopf1_eddd(instr, gen_helper_fcmpuodd); break; + case OP_PFCMPNEQD: gen_alopf1_eddd(instr, gen_helper_fcmpneqd); break; + case OP_PFCMPNLTD: gen_alopf1_eddd(instr, gen_helper_fcmpnltd); break; + case OP_PFCMPNLED: gen_alopf1_eddd(instr, gen_helper_fcmpnled); break; + case OP_PFCMPODD: gen_alopf1_eddd(instr, gen_helper_fcmpodd); break; + case OP_FSCALED: gen_alopf1_edsd(instr, gen_helper_fscaled); break; + case OP_FSCALES: gen_alopf1_esss(instr, gen_helper_fscales); break; + case OP_FXSCALESX: gen_alopf1_exsx(instr, gen_helper_fxscalesx); break; + case OP_FRCPS: gen_alopf2_ess(instr, gen_helper_frcps); break; + case OP_FSQRTS: gen_alopf2_ess(instr, gen_helper_fsqrts); break; + case OP_FRSQRTS: gen_alopf2_ess(instr, gen_helper_frsqrts); break; +#ifndef TARGET_E2K_PRECISE_FSQRTID + case OP_FSQRTID: gen_alopf2_dd(instr, tcg_gen_mov_i64); break; + case OP_FXSQRTISX: gen_alopf2_esx(instr, gen_helper_fstofx); break; + case OP_FXSQRTIDX: gen_alopf2_edx(instr, gen_helper_fdtofx); break; + case OP_FXSQRTIXX: gen_alopf2_xx(instr, gen_movx); break; + /* FIXME: these are not ALOPF2! */ + case OP_FXSQRTUSX: /* fallthrough */ + case OP_FXSQRTUDX: /* fallthrough */ + case OP_FXSQRTUXX: gen_alopf2_xx(instr, gen_movx); break; +#else +#error Not implemented +#endif + case OP_FXSQRTTSX: gen_alopf1_esxx(instr, gen_helper_fxsqrttsx); break; + case OP_FXSQRTTDX: gen_alopf1_edxx(instr, gen_helper_fxsqrttdx); break; + case OP_FXSQRTTXX: gen_alopf1_exxx(instr, gen_helper_fxsqrttxx); break; + case OP_PFSQRTTD: /* fallthrough */ + case OP_FSQRTTD: gen_alopf1_eddd(instr, gen_helper_fsqrttd); break; + case OP_INSFS: gen_alopf21_ssss(instr, gen_insfs); break; + case OP_INSFD: gen_insfd(instr); break; + case OP_PSHUFB: gen_alopf21_dddd(instr, gen_helper_pshufb); break; + case OP_PMERGE: gen_alopf21_dddd(instr, gen_helper_pmerge); break; + case OP_FXDIVTSS: gen_alopf1_esxs(instr, gen_helper_fxdivtss); break; + case OP_FXDIVTDD: gen_alopf1_edxd(instr, gen_helper_fxdivtdd); break; + case OP_FXDIVTSX: gen_alopf1_esxx(instr, gen_helper_fxdivtsx); break; + case OP_FXDIVTDX: gen_alopf1_edxx(instr, gen_helper_fxdivtdx); break; + case OP_VFSI: + case OP_LDCSB: + case OP_LDDSB: + case OP_LDESB: + case OP_LDFSB: + case OP_LDGSB: + case OP_LDSSB: + case OP_LDCSH: + case OP_LDDSH: + case OP_LDESH: + case OP_LDFSH: + case OP_LDGSH: + case OP_LDSSH: + case OP_LDCSW: + case OP_LDDSW: + case OP_LDESW: + case OP_LDFSW: + case OP_LDGSW: + case OP_LDSSW: + case OP_LDCSD: + case OP_LDDSD: + case OP_LDESD: + case OP_LDFSD: + case OP_LDGSD: + case OP_LDSSD: + case OP_MOVTRS: + case OP_MOVTRCS: + case OP_MOVTRD: + case OP_MOVTRCD: + case OP_GETSAP: + case OP_CUDTOAP: + case OP_GDTOAP: + case OP_STCSB: + case OP_STDSB: + case OP_STESB: + case OP_STFSB: + case OP_STGSB: + case OP_STSSB: + case OP_STCSH: + case OP_STDSH: + case OP_STESH: + case OP_STFSH: + case OP_STGSH: + case OP_STSSH: + case OP_STCSW: + case OP_STDSW: + case OP_STESW: + case OP_STFSW: + case OP_STGSW: + case OP_STSSW: + case OP_STCSD: + case OP_STDSD: + case OP_STESD: + case OP_STFSD: + case OP_STGSD: + case OP_STSSD: + case OP_CCTOPO: + case OP_CCTOPB: + case OP_CCTOPE: + case OP_CCTOPBE: + case OP_CCTOPS: + case OP_CCTOPP: + case OP_CCTOPL: + case OP_CCTOPLE: + /* + case OP_AAURW: + case OP_AAURWS: + case OP_AAURWD: + case OP_AAURWQ: + case OP_AAURR: + case OP_AAURRD: + case OP_AAURRQ: + */ + case OP_APTOAP: + case OP_APTOAPB: + case OP_GETVA: + case OP_LDRD: + case OP_PUTTC: + case OP_CAST: + case OP_TDTOMP: + case OP_ODTOAP: + case OP_LDCUDB: + case OP_LDCUDH: + case OP_LDCUDW: + case OP_LDCUDD: + case OP_LDCUDQ: + case OP_LDAPB: + case OP_LDAPH: + case OP_LDAPW: + case OP_LDAPD: + case OP_LDAPQ: + case OP_LDODWB: + case OP_LDODWD: + case OP_LDODWH: + case OP_LDODWQ: + case OP_LDODWW: + case OP_LDODPB: + case OP_LDODPD: + case OP_LDODPH: + case OP_LDODPQ: + case OP_LDODPW: + case OP_LDODRB: + case OP_LDODRD: + case OP_LDODRH: + case OP_LDODRQ: + case OP_LDODRW: + case OP_LDCSQ: + case OP_LDDSQ: + case OP_LDESQ: + case OP_LDFSQ: + case OP_LDGSQ: + case OP_LDSSQ: + case OP_GETTD: + case OP_GETTC: + case OP_INVTC: + case OP_GETSOD: + case OP_STCSQ: + case OP_STDSQ: + case OP_STESQ: + case OP_STFSQ: + case OP_STGSQ: + case OP_STSSQ: + case OP_STRD: + case OP_STAPB: + case OP_STAPH: + case OP_STAPW: + case OP_STAPD: + case OP_STAPQ: + case OP_STODPB: + case OP_STODPD: + case OP_STODPH: + case OP_STODPQ: + case OP_STODPW: + case OP_STODRB: + case OP_STODRD: + case OP_STODRH: + case OP_STODRQ: + case OP_STODRW: + case OP_STODWB: + case OP_STODWD: + case OP_STODWH: + case OP_STODWQ: + case OP_STODWW: + case OP_MOVTRQ: + case OP_MOVTRCQ: + case OP_PUTTST: + case OP_STAAQP: + case OP_QPAND: + case OP_QPANDN: + case OP_QPOR: + case OP_QPXOR: + case OP_QPADDB: + case OP_QPADDH: + case OP_QPADDSB: + case OP_QPADDSH: + case OP_QPADDUSB: + case OP_QPADDUSH: + case OP_QPADDW: + case OP_QPADDD: + case OP_QPSUBB: + case OP_QPSUBH: + case OP_QPSUBSB: + case OP_QPSUBSH: + case OP_QPSUBUSB: + case OP_QPSUBUSH: + case OP_QPSUBW: + case OP_QPSUBD: + case OP_QPFADDS: + case OP_QPFADDD: + case OP_QPFHADDS: + case OP_QPFHSUBS: + case OP_QPFADDSUBS: + case OP_QPFADDSUBD: + case OP_QPFSTOIFS: + case OP_QPFDTOIFD: + case OP_QPFMINS: + case OP_QPFMIND: + case OP_QPFMAXS: + case OP_QPFMAXD: + case OP_QPFMULS: + case OP_QPFMULD: + case OP_QPFSUBS: + case OP_QPFSUBD: + case OP_QPMSK2SGNB: + case OP_QPPACKDL: + case OP_QPSLLH: + case OP_QPSLLW: + case OP_QPSLLD: + case OP_QPSRLH: + case OP_QPSRLW: + case OP_QPSRLD: + case OP_QPSRAH: + case OP_QPSRAW: + case OP_QPACKSSHB: + case OP_QPACKSSWH: + case OP_QPACKUSHB: + case OP_QPACKUSWH: + case OP_QPAVGUSB: + case OP_QPAVGUSH: + case OP_QPCMPEQB: + case OP_QPCMPEQD: + case OP_QPCMPEQH: + case OP_QPCMPEQW: + case OP_QPCMPGTB: + case OP_QPCMPGTD: + case OP_QPCMPGTH: + case OP_QPCMPGTW: + case OP_QPHADDH: + case OP_QPHADDSH: + case OP_QPHADDW: + case OP_QPHSUBH: + case OP_QPHSUBSH: + case OP_QPHSUBW: + case OP_QPMAXSB: + case OP_QPMAXSH: + case OP_QPMAXSW: + case OP_QPMAXUB: + case OP_QPMAXUH: + case OP_QPMAXUW: + case OP_QPMINSB: + case OP_QPMINSH: + case OP_QPMINSW: + case OP_QPMINUB: + case OP_QPMINUH: + case OP_QPMINUW: + case OP_QPMULHH: + case OP_QPMULHRSH: + case OP_QPMULHUH: + case OP_QPMULLH: + case OP_QPMULUBHH: + case OP_QPSIGNB: + case OP_QPSIGNH: + case OP_QPSIGNW: + case OP_QPHMINPOSUH: + case OP_QPMADDH: + case OP_QPMADDUBSH: + case OP_QPMPSADBH: + case OP_QPSADBW: + case OP_QPSRCD: + case OP_QPSRCW: + case OP_PSRCD: + case OP_PSRCW: + case OP_GETFZS: + case OP_GETFZD: + case OP_PUTTAGQP: + case OP_PMULLW: + case OP_QPMULLW: + case OP_QPFCMPEQS: + case OP_QPFCMPLTS: + case OP_QPFCMPLES: + case OP_QPFCMPUODS: + case OP_QPFCMPNEQS: + case OP_QPFCMPNLTS: + case OP_QPFCMPNLES: + case OP_QPFCMPODS: + case OP_QPFCMPEQD: + case OP_QPFCMPLTD: + case OP_QPFCMPLED: + case OP_QPFCMPUODD: + case OP_QPFCMPNEQD: + case OP_QPFCMPNLTD: + case OP_QPFCMPNLED: + case OP_QPFCMPODD: + case OP_LDQ: + case OP_LDQP: + case OP_LDGDQP: + case OP_LDCUDQP: + case OP_LDCSQP: + case OP_LDDSQP: + case OP_LDESQP: + case OP_LDFSQP: + case OP_LDGSQP: + case OP_LDSSQP: + case OP_LDAPQP: + case OP_LDRQP: + case OP_QPSGN2MSKB: + case OP_QPSWITCHW: + case OP_QPSWITCHD: + case OP_QPFSTOIS: + case OP_QPFSTOISTR: + case OP_QPISTOFS: + case OP_QPFSTOID: + case OP_QPFSTOIDTR: + case OP_QPISTOFD: + case OP_QPFSTOFD: + case OP_QPFDTOIS: + case OP_QPFDTOISTR: + case OP_QPIDTOFS: + case OP_QPFDTOFS: + case OP_QPFDTOID: + case OP_QPFDTOIDTR: + case OP_QPIDTOFD: + case OP_STQ: + case OP_STGDMQP: + case OP_STGDQP: + case OP_STAPQP: + case OP_STAPMQP: + case OP_STMQP: + case OP_STQP: + case OP_STCSMQP: + case OP_STCSQP: + case OP_STDSMQP: + case OP_STDSQP: + case OP_STESMQP: + case OP_STESQP: + case OP_STFSMQP: + case OP_STFSQP: + case OP_STGSMQP: + case OP_STGSQP: + case OP_STSSMQP: + case OP_STSSQP: + case OP_STRQP: + case OP_ADDCD: + case OP_ADDCD_C: + case OP_SUBCD: + case OP_SUBCD_C: + case OP_VFBGV: + case OP_MKFSW: + case OP_MODBGV: + case OP_PCMPEQBOP: + case OP_PCMPEQHOP: + case OP_PCMPEQWOP: + case OP_PCMPEQDOP: + case OP_PCMPGTBOP: + case OP_PCMPGTHOP: + case OP_PCMPGTWOP: + case OP_PCMPGTDOP: + case OP_PCMPEQBAP: + case OP_PCMPEQHAP: + case OP_PCMPEQWAP: + case OP_PCMPEQDAP: + case OP_PCMPGTBAP: + case OP_PCMPGTHAP: + case OP_PCMPGTWAP: + case OP_PCMPGTDAP: + case OP_QPCMPEQBOP: + case OP_QPCMPEQHOP: + case OP_QPCMPEQWOP: + case OP_QPCMPEQDOP: + case OP_QPCMPGTBOP: + case OP_QPCMPGTHOP: + case OP_QPCMPGTWOP: + case OP_QPCMPGTDOP: + case OP_QPCMPEQBAP: + case OP_QPCMPEQHAP: + case OP_QPCMPEQWAP: + case OP_QPCMPEQDAP: + case OP_QPCMPGTBAP: + case OP_QPCMPGTHAP: + case OP_QPCMPGTWAP: + case OP_QPCMPGTDAP: + case OP_PMRGP: + case OP_QPMRGP: + case OP_CLMULH: + case OP_CLMULL: + case OP_IBRANCHD: + case OP_ICALLD: + case OP_QPCEXT_0X00: + case OP_QPCEXT_0X7F: + case OP_QPCEXT_0X80: + case OP_QPCEXT_0XFF: + case OP_FMAS: + case OP_FMSS: + case OP_FNMAS: + case OP_FNMSS: + case OP_FMAD: + case OP_FMSD: + case OP_FNMAD: + case OP_FNMSD: + case OP_QPFMAS: + case OP_QPFMSS: + case OP_QPFNMAS: + case OP_QPFNMSS: + case OP_QPFMAD: + case OP_QPFMSD: + case OP_QPFNMAD: + case OP_QPFNMSD: + case OP_QPFMASS: + case OP_QPFMSAS: + case OP_QPFMASD: + case OP_QPFMSAD: + e2k_todo_illop(ctx, "unimplemented %d (%s)", op, name); break; + } +} + +typedef enum { + ICOMB_AND = 0, + ICOMB_ANDN = 1, + ICOMB_OR = 2, + ICOMB_ORN = 3, + ICOMB_XOR = 4, + ICOMB_XORN = 5, + ICOMB_RSUB = 6, + ICOMB_MERGE = 7, + ICOMB_ADD = 8, + ICOMB_SUB = 9, + ICOMB_SCL = 10, + ICOMB_SCR = 11, + ICOMB_SHL = 12, + ICOMB_SHR = 13, + ICOMB_SAR = 14, + ICOMB_GETF = 15, +} IComb; + +#define IMPL_GEN_ICOMB_OP(S) \ + static void glue(gen_icomb_op_, S)(Instr *instr, IComb opc, \ + glue(TCGv_, S) ret, glue(TCGv_, S) arg1, glue(TCGv_, S) arg2) \ + { \ + switch(opc) { \ + case ICOMB_AND: glue(tcg_gen_and_, S)(ret, arg1, arg2); break; \ + case ICOMB_ANDN: glue(gen_andn_, S)(ret, arg1, arg2); break; \ + case ICOMB_OR: glue(tcg_gen_or_, S)(ret, arg1, arg2); break; \ + case ICOMB_ORN: glue(gen_orn_, S)(ret, arg1, arg2); break; \ + case ICOMB_XOR: glue(tcg_gen_xor_, S)(ret, arg1, arg2); break; \ + case ICOMB_XORN: glue(gen_xorn_, S)(ret, arg1, arg2); break; \ + case ICOMB_RSUB: glue(tcg_gen_sub_, S)(ret, arg2, arg1); break; \ + case ICOMB_MERGE: { \ + TCGv_i32 t0 = tcg_temp_new_i32(); \ + gen_mrgc_i32(instr->ctx, instr->chan, t0); \ + glue(gen_merge_, S)(ret, arg1, arg2, t0); \ + tcg_temp_free_i32(t0); \ + break; \ + } \ + case ICOMB_ADD: glue(tcg_gen_add_, S)(ret, arg1, arg2); break; \ + case ICOMB_SUB: glue(tcg_gen_sub_, S)(ret, arg1, arg2); break; \ + case ICOMB_SCL: glue(tcg_gen_rotl_, S)(ret, arg1, arg2); break; \ + case ICOMB_SCR: glue(tcg_gen_rotr_, S)(ret, arg1, arg2); break; \ + case ICOMB_SHL: glue(tcg_gen_shl_, S)(ret, arg1, arg2); break; \ + case ICOMB_SHR: glue(tcg_gen_shr_, S)(ret, arg1, arg2); break; \ + case ICOMB_SAR: glue(tcg_gen_sar_, S)(ret, arg1, arg2); break; \ + case ICOMB_GETF: glue(gen_getf_, S)(ret, arg1, arg2); break; \ + default: g_assert_not_reached(); break; \ + } \ + } + +IMPL_GEN_ICOMB_OP(i64) +IMPL_GEN_ICOMB_OP(i32) + +static inline bool icomb_check(Instr *instr, IComb opc1, IComb opc2) +{ + if (!is_chan_14(instr->chan)) { + return false; + } + + if (instr->ctx->version == 1) { + return opc1 != ICOMB_RSUB; + } else { + return opc1 != ICOMB_RSUB + && opc2 < ICOMB_SCL + && opc2 != ICOMB_MERGE; + } +} + +typedef enum { + FCOMB_ADD = 0, + FCOMB_SUB = 1, + FCOMB_HADD = 2, + FCOMB_HSUB = 3, + FCOMB_MUL = 4, + FCOMB_RSUB = 5, + FCOMB_ADDSUB = 7, + FCOMB_COUNT = 8, +} FComb; + +static inline bool fcomb_is_add_unit(FComb op) +{ + switch (op) { + case FCOMB_ADD: + case FCOMB_SUB: + case FCOMB_RSUB: + return true; + default: + return false; + } +} + +static inline bool fcomb_is_mul_unit(FComb op) +{ + return op == FCOMB_MUL; +} + +static inline bool fcomb_check(Instr *instr, FComb opc1, FComb opc2) +{ + int ver = instr->ctx->version; + + if (opc1 == FCOMB_RSUB || (ver < 4 && is_chan_25(instr->chan))) { + return false; + } + + if (ver >= 2) { + return (fcomb_is_add_unit(opc1) || fcomb_is_mul_unit(opc1)) + && fcomb_is_add_unit(opc2); + } else { + return fcomb_is_add_unit(opc1) == fcomb_is_mul_unit(opc2); + } +} + +static bool pfcomb_map[FCOMB_COUNT][FCOMB_COUNT] = { false }; + +static void pfcomb_map_set(FComb op, FComb *list, int n) +{ + int i; + + for (i = 0; i < n; i++) { + pfcomb_map[op][list[i]] = true; + } +} + +static void pfcomb_map_update(FComb *first, int nf, FComb *second, int ns) +{ + int i; + + for (i = 0; i < nf; i++) { + pfcomb_map_set(first[i], second, ns); + } +} + +static void pfcomb_init(DisasContext *ctx) +{ + FComb l0[] = { FCOMB_ADD, FCOMB_SUB, FCOMB_RSUB }; + + pfcomb_map_set(FCOMB_MUL, l0, ARRAY_SIZE(l0)); + + if (ctx->version == 1) { + pfcomb_map[FCOMB_ADD][FCOMB_MUL] = true; + pfcomb_map[FCOMB_SUB][FCOMB_MUL] = true; + } + + if (ctx->version >= 2) { + FComb l1[] = { FCOMB_ADD, FCOMB_SUB }; + + pfcomb_map_update(l1, ARRAY_SIZE(l1), l0, ARRAY_SIZE(l0)); + } + + if (ctx->version >= 3) { + FComb l1[] = { FCOMB_ADD, FCOMB_SUB, FCOMB_MUL, }; + FComb l2[] = { FCOMB_HADD, FCOMB_HSUB, FCOMB_ADDSUB }; + + pfcomb_map_update(l1, ARRAY_SIZE(l1), l2, ARRAY_SIZE(l2)); + pfcomb_map_update(l2, ARRAY_SIZE(l2), l2, ARRAY_SIZE(l2)); + pfcomb_map_update(l2, ARRAY_SIZE(l2), l0, ARRAY_SIZE(l0)); + } +} + +static inline bool pfcomb_check(Instr *instr, FComb opc1, FComb opc2) +{ + int ver = instr->ctx->version; + + if (ver < 4 && is_chan_25(instr->chan)) { + return false; + } + + return pfcomb_map[opc1][opc2]; +} + +#define IMPL_GEN_FCOMB_OP(S, T) \ + static void glue(gen_fcomb_op_, S)(Instr *instr, FComb opc, \ + glue(TCGv_, S) ret, glue(TCGv_, S) arg1, glue(TCGv_, S) arg2) \ + { \ + switch(opc) { \ + case FCOMB_ADD: glue(gen_helper_fadd, T)(ret, cpu_env, arg1, arg2); break; \ + case FCOMB_SUB: glue(gen_helper_fsub, T)(ret, cpu_env, arg1, arg2); break; \ + case FCOMB_MUL: glue(gen_helper_fmul, T)(ret, cpu_env, arg1, arg2); break; \ + case FCOMB_RSUB: glue(gen_helper_fsub, T)(ret, cpu_env, arg2, arg1); break; \ + default: gen_tr_excp_illopc(instr->ctx); break; \ + } \ + } + +IMPL_GEN_FCOMB_OP(i64, d) +IMPL_GEN_FCOMB_OP(i32, s) + +static void gen_pfcomb_op_i32(Instr *instr, FComb opc, + TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + switch (opc) { + case FCOMB_ADD: gen_helper_pfadds(ret, cpu_env, arg1, arg2); break; + case FCOMB_SUB: gen_helper_pfsubs(ret, cpu_env, arg1, arg2); break; + case FCOMB_HADD: gen_helper_pfhadds(ret, cpu_env, arg1, arg2); break; + case FCOMB_HSUB: gen_helper_pfhsubs(ret, cpu_env, arg1, arg2); break; + case FCOMB_MUL: gen_helper_pfmuls(ret, cpu_env, arg1, arg2); break; + case FCOMB_RSUB: gen_helper_pfsubs(ret, cpu_env, arg2, arg1); break; + case FCOMB_ADDSUB: gen_helper_pfaddsubs(ret, cpu_env, arg1, arg2); break; + default: gen_tr_excp_illopc(instr->ctx); break; + } +} + +static void gen_pfcomb_op_i64(Instr *instr, FComb opc, + TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + switch (opc) { + case FCOMB_ADD: gen_helper_faddd(ret, cpu_env, arg1, arg2); break; + case FCOMB_SUB: gen_helper_fsubd(ret, cpu_env, arg1, arg2); break; + case FCOMB_MUL: gen_helper_fmuld(ret, cpu_env, arg1, arg2); break; + case FCOMB_RSUB: gen_helper_fsubd(ret, cpu_env, arg2, arg1); break; + default: gen_tr_excp_illopc(instr->ctx); break; + } +} + +static inline int comb_opc1(Instr *instr, int m1) +{ + return (instr->opc1 >> 1) & m1; +} + +static inline int comb_opc2(Instr *instr, int m1, int m2) +{ + return ((instr->opc2 & m2) << 2) | ((instr->opc1 >> 5) & m1); +} + +#define icomb_opc1(instr) comb_opc1(instr, 0xf) +#define fcomb_opc1(instr) comb_opc1(instr, 0x7) + +#define icomb_opc2(instr) comb_opc2(instr, 0x3, 0x3) +#define fcomb_opc2(instr) comb_opc2(instr, 0x3, 0x1) + +#define IMPL_GEN_COMB(NAME, P, S, OP) \ + static void NAME(Instr *instr, int opc1, int opc2) \ + { \ + tagged(S) r = tagged_local_new(S); \ + tagged(S) s1 = tagged_local_new(S); \ + tagged(S) s2 = tagged_local_new(S); \ + tagged(S) s3 = tagged_local_new(S); \ + \ + gen_tagged_src(1, S, instr, s1); \ + gen_tagged_src(2, S, instr, s2); \ + gen_tagged_src(3, S, instr, s3); \ + gen_tag3(S, r, s1, s2, s3); \ + OP(instr, opc1, r.val, s1.val, s2.val); \ + OP(instr, opc2, r.val, s3.val, r.val); \ + gen_al_result(S, instr, r); \ + \ + tagged_free(S, s3); \ + tagged_free(S, s2); \ + tagged_free(S, s1); \ + tagged_free(S, r); \ + } + +IMPL_GEN_COMB(gen_icomb_i64, icomb, d, gen_icomb_op_i64) +IMPL_GEN_COMB(gen_icomb_i32, icomb, s, gen_icomb_op_i32) +IMPL_GEN_COMB(gen_fcomb_i64, fcomb, d, gen_fcomb_op_i64) +IMPL_GEN_COMB(gen_fcomb_i32, fcomb, s, gen_fcomb_op_i32) +IMPL_GEN_COMB(gen_pfcomb_i64, pfcomb, d, gen_pfcomb_op_i64) +IMPL_GEN_COMB(gen_pfcomb_i32, pfcomb, d, gen_pfcomb_op_i32) + +#define IMPL_GEN_COMB_SELECT(NAME) \ + static void glue(gen_, NAME)(Instr *instr, uint32_t op) \ + { \ + int opc1 = op & 0xffff; \ + int opc2 = op >> 16; \ + \ + if (instr->opc1 & 1) { \ + glue3(gen_, NAME, _i64)(instr, opc1, opc2); \ + } else { \ + glue3(gen_, NAME, _i32)(instr, opc1, opc2); \ + } \ + } + +IMPL_GEN_COMB_SELECT(icomb) +IMPL_GEN_COMB_SELECT(fcomb) +IMPL_GEN_COMB_SELECT(pfcomb) + +static void gen_lcomb_i64(Instr *instr, uint32_t base) +{ + /* see gen_alopf21_i64 */ + Tagged_i64 r = tagged_new_i64(); + Tagged_i64 s1 = tagged_new_i64(); + Tagged_i64 s2 = tagged_new_i64(); + Tagged_i64 s3 = tagged_new_i64(); + TCGv_i32 opc = tcg_const_i32(base + instr->opc1); + + gen_tagged_src1_d(instr, s1); + gen_tagged_src2_d(instr, s2); + gen_tagged_src3_d(instr, s3); + check_args(ALOPF21, instr); + gen_tag3d(r, s1, s2, s3); + gen_helper_plog(r.val, opc, s1.val, s2.val, s3.val); + gen_al_result_d(instr, r); + + tagged_free_i64(s3); + tagged_free_i64(s2); + tagged_free_i64(s2); + tagged_free_i64(r); +} + +static inline bool rlp_check_chan(uint16_t rlp, int chan) +{ + return extract16(rlp, 14, 1) == (chan > 2) && + extract16(rlp, 10 + chan % 3, 1); +} + +static inline bool rlp_is_chan_pred(uint16_t rlp, int chan) +{ + return !extract16(rlp, 15, 1) && rlp_check_chan(rlp, chan); +} + +static void chan_check_preds(DisasContext *ctx, int chan, TCGLabel *l) +{ + bool has_pcnt = false; + bool has_preg = false; + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i32 t1 = tcg_temp_new_i32(); + TCGv_i32 t2 = tcg_temp_new_i32(); + int i, j; + + tcg_gen_movi_i32(t0, 0); + tcg_gen_movi_i32(t1, 0); + + for (i = 0; i < 3; i++) { + uint16_t *cds = (uint16_t *) &ctx->bundle.cds[i]; + + if (!ctx->bundle.cds_present[i]) { + continue; + } + + for (j = 0; j < 2; j++) { + uint16_t rlp = cds[j]; + uint8_t kind = extract8(rlp, 5, 2); + uint8_t idx = extract8(rlp, 0, 5); + bool invert = extract16(rlp, 7 + chan % 3, 1); + + if (!rlp_is_chan_pred(rlp, chan)) { + continue; + } + + switch(kind) { + case 0x2: { /* %pcntN */ + has_pcnt = true; + tcg_gen_setcondi_i32(TCG_COND_LEU, t2, cpu_lsr_pcnt, idx); + if (invert) { + tcg_gen_xori_i32(t2, t2, 1); + } + tcg_gen_or_i32(t0, t0, t2); + break; + } + case 0x3: /* %predN */ + has_preg = true; + gen_preg_i32(t2, idx); + if (invert) { + tcg_gen_xori_i32(t2, t2, 1); + } + tcg_gen_or_i32(t1, t1, t2); + break; + default: + if (ctx->strict) { + gen_tr_excp_illopc(ctx); + } + break; + } + } + } + + if (has_preg || has_pcnt) { + TCGv_i32 cond = e2k_get_temp_i32(ctx); + + if (has_preg && has_pcnt) { + tcg_gen_and_i32(cond, t0, t1); + } else if (has_preg) { + tcg_gen_mov_i32(cond, t1); + } else { + tcg_gen_mov_i32(cond, t0); + } + + ctx->al_cond[chan] = cond; + tcg_gen_brcondi_i32(TCG_COND_EQ, cond, 0, l); + } + + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); +} + +static void alop_instr_init(Instr *instr, DisasContext *ctx, int chan) +{ + memset(instr, 0, sizeof(Instr)); + + instr->ctx = ctx; + instr->chan = chan; + instr->mas = ctx->bundle2.cs1.type == CS1_MAS ? ctx->bundle2.cs1.mas[chan] : 0; + instr->als = ctx->bundle.als[chan]; + instr->ales = ctx->bundle.ales[chan]; + instr->ales_present = ctx->bundle.ales_present[chan]; +} + +static void alop_decode(Instr *instr) +{ + Alop *alop = &instr->ctx->bundle2.alops[instr->chan]; + + alop->format = ALOPF_NONE; + alop->op = 0; + alop->name = "none"; + + switch (instr->opc2) { + case SHORT: + case EXT: + case EXT1: + case EXT2: { + AlopDesc *desc = find_op(instr); + if (!desc) { + gen_tr_excp_illopc(instr->ctx); + return; + } + alop->format = desc->alopf; + alop->op = desc->op; + alop->name = desc->dsc; + break; + } + case ICMB0: + case ICMB1: + case ICMB2: + case ICMB3: + if (instr->opc2 == ICMB3 + && (instr->opc1 == 0x6c || instr->opc1 == 0x6d)) + { + if (!is_chan_0134(instr->chan)) { + gen_tr_excp_illopc(instr->ctx); + return; + } + alop->format = ALOPF21; + alop->op = instr->opc1 & 1 ? OP_INSFD : OP_INSFS; + } else { + int opc1 = icomb_opc1(instr); + int opc2 = icomb_opc2(instr); + if (!icomb_check(instr, opc1, opc2)) { + gen_tr_excp_illopc(instr->ctx); + return; + } + alop->format = ALOPF21_ICOMB; + alop->op = (opc2 << 16) | opc1; + } + break; + case FLB: + case FLH: + case FLW: + case FLD: + e2k_todo_illop(instr->ctx, "flags ops"); + break; + case FCMB0: + case FCMB1: { + int opc1 = fcomb_opc1(instr); + int opc2 = fcomb_opc2(instr); + if (!fcomb_check(instr, opc1, opc2)) { + gen_tr_excp_illopc(instr->ctx); + return; + } + alop->format = ALOPF21_FCOMB; + alop->op = (opc2 << 16) | opc1; + break; + } + case PFCMB0: + case PFCMB1: + if (instr->opc2 == PFCMB1 && is_chan_0134(instr->chan) + && instr->ctx->version >= 2 && instr->opc1 == 0x4d) + { + alop->format = ALOPF12_PSHUFH; + alop->op = OP_PSHUFB; + } else if (instr->opc2 == PFCMB1 && is_chan_0134(instr->chan) + && instr->ctx->version >= 2 && instr->opc1 == 0x6d) + { + alop->format = ALOPF21; + alop->op = OP_PMERGE; + } else { + int opc1 = fcomb_opc1(instr); + int opc2 = fcomb_opc2(instr); + if (!pfcomb_check(instr, opc1, opc2)) { + gen_tr_excp_illopc(instr->ctx); + return; + } + alop->format = ALOPF21_PFCOMB; + alop->op = (opc2 << 16) | opc1; + } + break; + case LCMBD0: + case LCMBD1: + if (is_chan_0134(instr->chan) && instr->ctx->version >= 5) { + alop->format = ALOPF21_LCOMB; + alop->op = instr->opc2 == LCMBD0 ? 0 : 0x80; + } else { + gen_tr_excp_illopc(instr->ctx); + } + break; + case LCMBQ0: + case LCMBQ1: + e2k_todo_illop(instr->ctx, "logical combined ops"); + break; + case QPFCMB0: + case QPFCMB1: + e2k_todo_illop(instr->ctx, "packed128 float combined ops"); + break; + default: + gen_tr_excp_illopc(instr->ctx); + break; + } +} + +static void alc_decode(DisasContext *ctx) +{ + int i; + + for (i = 0; i < 6; i++) { + if (ctx->bundle.als_present[i]) { + Instr instr; + alop_instr_init(&instr, ctx, i); + alop_decode(&instr); + } + } +} + +static void gen_alop(Instr *instr, Alop *alop) +{ + TCGLabel *l0 = gen_new_label(); + + if (alop->format == ALOPF_NONE) { + return; + } + + chan_check_preds(instr->ctx, instr->chan, l0); + check_args(alop->format, instr); + + switch (alop->format) { + case ALOPF21_ICOMB: + gen_icomb(instr, alop->op); + break; + case ALOPF21_FCOMB: + gen_fcomb(instr, alop->op); + break; + case ALOPF21_PFCOMB: + gen_pfcomb(instr, alop->op); + break; + case ALOPF21_LCOMB: + gen_lcomb_i64(instr, alop->op); + break; + default: + gen_alop_simple(instr, alop->op, alop->name); + break; + } + + gen_set_label(l0); + + if (instr->aaincr_len != 0) { + gen_aasti_incr(instr->ctx, instr); + } +} + +static void gen_alc(DisasContext *ctx) +{ + int i; + + for (i = 0; i < 6; i++) { + Instr instr; + Alop *alop = &ctx->bundle2.alops[i]; + ctx->al_results[i].type = AL_RESULT_NONE; + ctx->al_cond[i] = NULL; + alop_instr_init(&instr, ctx, i); + gen_alop(&instr, alop); + } +} + +static bool is_alop_affected_by_dbl(Alop *alop) +{ + if (alop->format == ALOPF2) { + switch (alop->op) { + case OP_MOVTS: + case OP_MOVTCS: + case OP_MOVTRS: + case OP_MOVTRCS: + return false; + default: + break; + } + } + + return true; +} + +static bool is_alop_check_tag(Alop *alop) +{ + if (alop->format == ALOPF2) { + switch (alop->op) { + case OP_PUTTAGS: + case OP_PUTTAGD: + case OP_MOVTS: + case OP_MOVTRS: + case OP_MOVTD: + case OP_MOVTRD: + case OP_MOVTQ: + case OP_MOVTRQ: + return false; + default: + break; + } + } + + return true; +} + +static bool is_alop_poison_result(Alop *alop) +{ + if (alop->format == ALOPF2) { + switch (alop->op) { + case OP_PUTTAGS: + case OP_PUTTAGD: + case OP_MOVTS: + case OP_MOVTRS: + case OP_MOVTD: + case OP_MOVTRD: + case OP_MOVTQ: + case OP_MOVTRQ: + return false; + default: + break; + } + } + + return true; +} + +static void gen_al_result_commit_reg32(DisasContext *ctx, Alop *alop, + TCGv_i32 index, TCGv_i32 tag, TCGv_i32 value) +{ + TCGv_i32 t0 = tcg_temp_new_i32(); + + gen_reg_tag_set_i32(ctx, tag, index); + if (is_alop_poison_result(alop)) { + gen_dst_poison_i32(t0, value, tag); + } else { + tcg_gen_mov_i32(t0, value); + } + gen_reg_lo_write_i32(t0, index); + + tcg_temp_free_i32(t0); +} + +static void gen_al_result_commit_reg64(DisasContext *ctx, Alop *alop, + TCGv_i32 index, TCGv_i32 tag, TCGv_i64 value) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + + gen_reg_tag_set_i64(ctx, tag, index); + if (is_alop_poison_result(alop)) { + gen_dst_poison_i64(t0, value, tag); + } else { + tcg_gen_mov_i64(t0, value); + } + gen_reg_lo_write_i64(t0, index); + + tcg_temp_free_i64(t0); +} + +static inline void gen_al_result_commit_reg(DisasContext *ctx, Alop *alop, + AlResult *res) +{ + AlResultType size = e2k_al_result_size(res->type); + + if (is_alop_check_tag(alop)) { + // TODO: tag check before alops execution + } + + switch (size) { + case AL_RESULT_32: { + if (is_alop_affected_by_dbl(alop)) { + TCGLabel *l0 = gen_new_label(); + TCGLabel *l1 = gen_new_label(); + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_wdbl, 0, l0); + + /* wdbl is not set */ + gen_al_result_commit_reg32(ctx, alop, res->reg.index, + res->reg.tag, res->reg.v32); + tcg_gen_br(l1); + + /* wdbl is set */ + gen_set_label(l0); + gen_tag1_i64(t0, res->reg.tag); + tcg_gen_extu_i32_i64(t1, res->reg.v32); + gen_al_result_commit_reg64(ctx, alop, res->reg.index, t0, t1); + + /* exit */ + gen_set_label(l1); + + tcg_temp_free_i64(t1); + tcg_temp_free_i32(t0); + } else { + gen_al_result_commit_reg32(ctx, alop, res->reg.index, + res->reg.tag, res->reg.v32); + } + + break; + } + case AL_RESULT_64: + if (alop->format == ALOPF16 && alop->op == OP_RRS) { + TCGLabel *l0 = gen_new_label(); + TCGLabel *l1 = gen_new_label(); + + /* rrs is affected by wdbl but unlike other 32-bit ops + * the upper half must be an actual value */ + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_wdbl, 0, l1); + gen_al_result_commit_reg32(ctx, alop, res->reg.index, + res->reg.tag, res->reg.v32); + tcg_gen_br(l0); + gen_set_label(l1); + gen_al_result_commit_reg64(ctx, alop, res->reg.index, + res->reg.tag, res->reg.v64); + gen_set_label(l0); + } else { + gen_al_result_commit_reg64(ctx, alop, res->reg.index, + res->reg.tag, res->reg.v64); + } + break; + case AL_RESULT_80: + gen_al_result_commit_reg64(ctx, alop, res->reg.index, res->reg.tag, + res->reg.v64); + gen_reg_hi_write16u_i32(res->reg.x32, res->reg.index); + break; + case AL_RESULT_128: + gen_al_result_commit_reg64(ctx, alop, res->reg.index, res->reg.tag, + res->reg.v64); + gen_reg_hi_write_i64(res->reg.x64, res->reg.index); + break; + default: + g_assert_not_reached(); + break; + } +} + +static inline void gen_al_result_commit_ctpr(AlResult *res) +{ + AlResultType size = e2k_al_result_size(res->type); + TCGv_i64 ctpr = cpu_ctprs[res->ctpr.index]; + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_const_i64(CTPR_TAG_DISP); + + assert(res->ctpr.index < 3); + + switch (size) { + case AL_RESULT_32: + tcg_gen_extu_i32_i64(t0, res->ctpr.v32); + break; + case AL_RESULT_64: + tcg_gen_mov_i64(t0, res->ctpr.v64); + break; + default: + g_assert_not_reached(); + break; + } + + tcg_gen_deposit_i64(ctpr, ctpr, t0, CTPR_BASE_OFF, CTPR_BASE_LEN); + tcg_gen_deposit_i64(ctpr, ctpr, t1, CTPR_TAG_OFF, CTPR_TAG_LEN); + + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t0); +} + +static void gen_al_commit(DisasContext *ctx) +{ + int i; + + for (i = 0; i < 6; i++) { + TCGLabel *l0 = gen_new_label(); + AlResult *res = &ctx->al_results[i]; + + if (!ctx->bundle.als_present[i]) { + continue; + } + + if (res->type != AL_RESULT_NONE && ctx->al_cond[i] != NULL) { + tcg_gen_brcondi_i32(TCG_COND_EQ, ctx->al_cond[i], 0, l0); + } + + switch (e2k_al_result_type(res->type)) { + case AL_RESULT_NONE: + /* %empty */ + break; + case AL_RESULT_REG: + /* %rN, %b[N], %gN */ + gen_al_result_commit_reg(ctx, &ctx->bundle2.alops[i], res); + break; + case AL_RESULT_PREG: + /* %predN */ + gen_preg_set_i32(res->preg.index, res->preg.val); + break; + case AL_RESULT_CTPR: + /* %ctprN */ + gen_al_result_commit_ctpr(res); + break; + default: + g_assert_not_reached(); + break; + } + + gen_set_label(l0); + } +} + +static void alc_init(DisasContext *ctx) +{ + int i, j; + + memset(alops_map, -1, sizeof(alops_map)); + memset(pfcomb_map, 0, sizeof(pfcomb_map)); + + // TODO: symmetric alops table + /* Most alops are symmetric and can be stored in a half table. */ + for (i = 0; i < ARRAY_SIZE(alops); i++) { + AlopDesc *desc = &alops[i]; + if (desc->min_version <= ctx->version && ctx->version <= desc->max_version) { + for (j = 0; j < 6; j++) { + if (desc->channels & (1 << j)) { + int16_t *p = &alops_map[desc->opc2][desc->opc1][j]; + desc->next[j] = *p; + *p = i; + } + } + } + } + + pfcomb_init(ctx); +} + +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; + gen_reg_index_i32(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); +} + +static void gen_aau(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); + } +} + +static void gen_aau_commit(DisasContext *ctx) +{ + unsigned int i; + + for (i = 0; i < 4; i++) { + AauResult *res = &ctx->aau_results[i]; + + // TODO: aau.tags + if (res->is_set) { + gen_reg_tag_set_i64(ctx, res->tag, res->index); + 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); + } +} static inline void gen_set_ctpr(int index, uint64_t ctpr) { assert(0 < index && index < 4); - tcg_gen_movi_i64(e2k_cs.ctprs[index - 1], ctpr); + tcg_gen_movi_i64(cpu_ctprs[index - 1], ctpr); } static inline void gen_ctpr_tag(TCGv_i64 ret, TCGv_i64 ctpr) @@ -480,7 +5673,7 @@ static inline void gen_goto_ctpr_disp(TCGv_i64 ctpr) tcg_gen_extract_i64(t0, ctpr, CTPR_BASE_OFF, CTPR_BASE_LEN); tcg_gen_trunc_i64_tl(t1, t0); - tcg_gen_mov_tl(e2k_cs.pc, t1); + tcg_gen_mov_tl(cpu_pc, t1); tcg_gen_lookup_and_goto_ptr(); tcg_temp_free(t1); @@ -521,9 +5714,9 @@ static inline void gen_setbn(DisasContext *ctx) 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.bsize, (setr->rsz + 1) * 2); - tcg_gen_movi_i32(e2k_cs.bcur, setr->rcur * 2); + tcg_gen_movi_i32(cpu_boff, setr->rbs * 2); + tcg_gen_movi_i32(cpu_bsize, (setr->rsz + 1) * 2); + tcg_gen_movi_i32(cpu_bcur, setr->rcur * 2); } } @@ -533,8 +5726,8 @@ static inline void gen_setbp(DisasContext *ctx) Cs1Setr *setr = &cs1->setr; if (cs1->type == CS1_SETR && (setr->type & SETR_BP)) { - tcg_gen_movi_i32(e2k_cs.psize, setr->psz); - tcg_gen_movi_i32(e2k_cs.pcur, 0); + tcg_gen_movi_i32(cpu_psize, setr->psz); + tcg_gen_movi_i32(cpu_pcur, 0); } } @@ -600,7 +5793,7 @@ static inline void gen_cs0(DisasContext *ctx) } case CS0_RETURN: { TCGv_i32 t0 = tcg_const_i32(cs0->ret.ipd); - gen_helper_prep_return(e2k_cs.ctprs[2], cpu_env, t0); + gen_helper_prep_return(cpu_ctprs[2], cpu_env, t0); tcg_temp_free_i32(t0); break; } @@ -620,7 +5813,7 @@ static inline void gen_ct_cond(DisasContext *ctx) } if (ct->cond_type == 1) { - tcg_gen_movi_i32(e2k_cs.ct_cond, 1); + tcg_gen_movi_i32(cpu_ct_cond, 1); return; } @@ -632,13 +5825,13 @@ static inline void gen_ct_cond(DisasContext *ctx) case 0x6: case 0xf: /* %predN */ - e2k_gen_preg_i32(pcond, ct->psrc); + gen_preg_i32(pcond, ct->psrc); break; case 0x3: case 0x7: case 0xe: { TCGv_i32 t0 = tcg_temp_new_i32(); - e2k_gen_preg_i32(t0, ct->psrc); + gen_preg_i32(t0, ct->psrc); tcg_gen_setcondi_i32(TCG_COND_EQ, pcond, t0, 0); tcg_temp_free_i32(t0); break; @@ -652,13 +5845,13 @@ static inline void gen_ct_cond(DisasContext *ctx) case 0x6: case 0xe: /* #LOOP_END */ - e2k_gen_is_loop_end_i32(lcond); + gen_is_loop_end_i32(lcond); break; case 0x5: case 0x7: case 0xf: { /* #NOT_LOOP_END */ TCGv_i32 t0 = tcg_temp_new_i32(); - e2k_gen_is_loop_end_i32(t0); + gen_is_loop_end_i32(t0); tcg_gen_setcondi_i32(TCG_COND_EQ, lcond, t0, 0); tcg_temp_free_i32(t0); break; @@ -669,12 +5862,12 @@ static inline void gen_ct_cond(DisasContext *ctx) case 0x2: case 0x3: /* {,~}%predN */ - tcg_gen_mov_i32(e2k_cs.ct_cond, pcond); + tcg_gen_mov_i32(cpu_ct_cond, pcond); break; case 0x4: case 0x5: /* #{,NOT_}LOOP_END */ - tcg_gen_mov_i32(e2k_cs.ct_cond, lcond); + tcg_gen_mov_i32(cpu_ct_cond, lcond); break; case 0x6: case 0xe: { @@ -683,7 +5876,7 @@ static inline void gen_ct_cond(DisasContext *ctx) TCGv_i32 t0 = tcg_temp_new_i32(); tcg_gen_or_i32(t0, pcond, lcond); - tcg_gen_movcond_i32(TCG_COND_EQ, e2k_cs.ct_cond, e2k_cs.lsr_pcnt, z, t0, lcond); + tcg_gen_movcond_i32(TCG_COND_EQ, cpu_ct_cond, cpu_lsr_pcnt, z, t0, lcond); tcg_temp_free_i32(t0); tcg_temp_free_i32(z); break; @@ -695,7 +5888,7 @@ static inline void gen_ct_cond(DisasContext *ctx) TCGv_i32 t0 = tcg_temp_new_i32(); tcg_gen_and_i32(t0, pcond, lcond); - tcg_gen_movcond_i32(TCG_COND_EQ, e2k_cs.ct_cond, e2k_cs.lsr_pcnt, z, t0, lcond); + tcg_gen_movcond_i32(TCG_COND_EQ, cpu_ct_cond, cpu_lsr_pcnt, z, t0, lcond); tcg_temp_free_i32(t0); tcg_temp_free_i32(z); break; @@ -715,7 +5908,7 @@ static inline void gen_ct_cond(DisasContext *ctx) } } else { /* %MLOCK */ - tcg_gen_mov_i32(e2k_cs.ct_cond, ctx->mlock); + tcg_gen_mov_i32(cpu_ct_cond, ctx->mlock); } break; case 0x9: { @@ -797,7 +5990,7 @@ static inline void gen_cur_dec(DisasContext *ctx, TCGv_i32 ret, int cond, tcg_gen_brcondi_i32(TCG_COND_EQ, size, 0, l0); gen_dec_wrap(t0, cur, n, size); - gen_movcond_flag_i32(ret, cond, e2k_cs.ct_cond, t0, cur); + gen_movcond_flag_i32(ret, cond, cpu_ct_cond, t0, cur); gen_set_label(l0); tcg_temp_free_i32(t0); @@ -821,14 +6014,14 @@ static void gen_advance_loop_counters(void) TCGv_i32 t2 = tcg_temp_new_i32(); TCGv_i32 t3 = tcg_temp_new_i32(); - gen_dec_sat_i32(e2k_cs.lsr_pcnt, e2k_cs.lsr_pcnt); - gen_dec_sat_i32(e2k_cs.lsr_lcnt, e2k_cs.lsr_lcnt); - tcg_gen_setcondi_i32(TCG_COND_EQ, t0, e2k_cs.lsr_pcnt, 0); - tcg_gen_setcondi_i32(TCG_COND_EQ, t1, e2k_cs.lsr_lcnt, 0); - tcg_gen_mov_i32(e2k_cs.lsr_over, t1); - gen_dec_sat_i32(t2, e2k_cs.lsr_ecnt); - tcg_gen_and_i32(t3, t1, e2k_cs.lsr_vlc); - tcg_gen_movcond_i32(TCG_COND_NE, e2k_cs.lsr_ecnt, t3, z, t2, e2k_cs.lsr_ecnt); + gen_dec_sat_i32(cpu_lsr_pcnt, cpu_lsr_pcnt); + gen_dec_sat_i32(cpu_lsr_lcnt, cpu_lsr_lcnt); + tcg_gen_setcondi_i32(TCG_COND_EQ, t0, cpu_lsr_pcnt, 0); + tcg_gen_setcondi_i32(TCG_COND_EQ, t1, cpu_lsr_lcnt, 0); + tcg_gen_mov_i32(cpu_lsr_over, t1); + gen_dec_sat_i32(t2, cpu_lsr_ecnt); + tcg_gen_and_i32(t3, t1, cpu_lsr_vlc); + tcg_gen_movcond_i32(TCG_COND_NE, cpu_lsr_ecnt, t3, z, t2, cpu_lsr_ecnt); tcg_temp_free_i32(t3); tcg_temp_free_i32(t2); @@ -850,20 +6043,20 @@ static inline void gen_stubs(DisasContext *ctx) TCGLabel *l0 = gen_new_label(); TCGCond cond = cond_from_advance(alc); - tcg_gen_brcondi_i32(tcg_invert_cond(cond), e2k_cs.ct_cond, 1, l0); + tcg_gen_brcondi_i32(tcg_invert_cond(cond), cpu_ct_cond, 1, l0); gen_advance_loop_counters(); gen_set_label(l0); } if (abp) { TCGv_i32 t0 = tcg_temp_local_new_i32(); - tcg_gen_addi_i32(t0, e2k_cs.psize, 1); - gen_cur_dec(ctx, e2k_cs.pcur, abp, e2k_cs.pcur, 1, t0); + tcg_gen_addi_i32(t0, cpu_psize, 1); + gen_cur_dec(ctx, cpu_pcur, abp, cpu_pcur, 1, t0); tcg_temp_free_i32(t0); } if (abn) { - gen_cur_dec(ctx, e2k_cs.bcur, abn, e2k_cs.bcur, 2, e2k_cs.bsize); + gen_cur_dec(ctx, cpu_bcur, abn, cpu_bcur, 2, cpu_bsize); } if (abg != 0) { @@ -894,7 +6087,7 @@ static inline target_ulong do_decode(DisasContext *ctx, CPUState *cs) decode_cs1(ctx, &ctx->bundle); decode_cs0(ctx, &ctx->bundle); decode_ct_cond(ctx, &ctx->bundle); - e2k_alc_decode(ctx); + alc_decode(ctx); return ctx->pc + len; } @@ -930,7 +6123,7 @@ static inline void do_checks(DisasContext *ctx) /* %rN src dynamic check */ if (ctx->max_r < ctx->max_r_src) { ctx->max_r = ctx->max_r_src; - gen_window_bounds_checki_i32(TCG_COND_LE, e2k_cs.wd_size, + gen_window_bounds_checki_i32(TCG_COND_LE, cpu_wd_size, ctx->max_r_src); } @@ -943,7 +6136,7 @@ static inline void do_checks(DisasContext *ctx) int max = MAX(ctx->max_r_src, ctx->max_r_dst); if (ctx->max_r < max) { ctx->max_r = max; - gen_window_bounds_checki_i32(TCG_COND_LE, e2k_cs.wd_size, max); + gen_window_bounds_checki_i32(TCG_COND_LE, cpu_wd_size, max); } } @@ -955,7 +6148,7 @@ static inline void do_checks(DisasContext *ctx) } else if (ctx->max_b < ctx->max_b_cur) { /* %b[N] src/dst dynamic check */ ctx->max_b = ctx->max_b_cur; - gen_window_bounds_checki_i32(TCG_COND_LE, e2k_cs.bsize, ctx->max_b); + gen_window_bounds_checki_i32(TCG_COND_LE, cpu_bsize, ctx->max_b); } } @@ -973,17 +6166,17 @@ static void gen_mlock_init(DisasContext *ctx) * Executes instructions from a bundle and store the results to * temporary buffer. */ -static inline void do_execute(DisasContext *ctx) +static inline void gen_ops(DisasContext *ctx) { ctx->loop_mode = (ctx->bundle.hs & (1 << 10)) != 0; gen_cs0(ctx); gen_cs1(ctx); gen_mlock_init(ctx); - e2k_alc_execute(ctx); + gen_alc(ctx); gen_ct_cond(ctx); - e2k_aau_execute(ctx); - e2k_plu_execute(ctx); + gen_aau(ctx); + gen_plu(ctx); } /* @@ -997,9 +6190,9 @@ static inline void do_execute(DisasContext *ctx) static inline void do_commit(DisasContext *ctx) { gen_setr(ctx); - e2k_alc_commit(ctx); - e2k_aau_commit(ctx); - e2k_plu_commit(ctx); + gen_al_commit(ctx); + gen_aau_commit(ctx); + gen_plu_commit(ctx); gen_stubs(ctx); } @@ -1022,7 +6215,7 @@ static inline void do_branch(DisasContext *ctx, target_ulong pc_next) if (ctx->ct.cond_type > 1) { TCGLabel *l0 = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_NE, e2k_cs.ct_cond, 0, l0); + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_ct_cond, 0, l0); gen_goto_tb(ctx, TB_EXIT_IDX1, pc_next); gen_set_label(l0); } @@ -1100,11 +6293,11 @@ static void e2k_tr_tb_start(DisasContextBase *db, CPUState *cs) ctx->max_b = -1; ctx->max_b_cur = -1; - tcg_gen_movi_i32(e2k_cs.ct_cond, 0); + tcg_gen_movi_i32(cpu_ct_cond, 0); if (env->is_bp) { TCGLabel *l0 = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_EQ, e2k_cs.is_bp, 0, l0); + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_is_bp, 0, l0); gen_helper_break_restore_state(cpu_env); gen_set_label(l0); } @@ -1159,7 +6352,7 @@ static void e2k_tr_translate_insn(DisasContextBase *db, CPUState *cs) ctx->base.is_jmp = DISAS_NORETURN; /* force non-zero tb size */ pc_next = ctx->base.pc_next + 8; - gen_helper_prep_return(e2k_cs.ctprs[2], cpu_env, t0); + gen_helper_prep_return(cpu_ctprs[2], cpu_env, t0); gen_helper_return(cpu_env); tcg_gen_exit_tb(NULL, TB_EXIT_IDX0); @@ -1181,7 +6374,7 @@ static void e2k_tr_translate_insn(DisasContextBase *db, CPUState *cs) gen_helper_expand_stacks(cpu_env); } #endif /* CONFIG_USER_ONLY */ - do_execute(ctx); + gen_ops(ctx); do_checks(ctx); do_commit(ctx); do_branch(ctx, pc_next); @@ -1199,10 +6392,6 @@ static void e2k_tr_translate_insn(DisasContextBase *db, CPUState *cs) while(ctx->t64_len) { tcg_temp_free_i64(ctx->t64[--ctx->t64_len]); } - - while(ctx->ttl_len) { - tcg_temp_free(ctx->ttl[--ctx->ttl_len]); - } } static void e2k_tr_tb_stop(DisasContextBase *db, CPUState *cs) @@ -1249,35 +6438,35 @@ void e2k_tcg_initialize(void) { char buf[16] = { 0 }; static const struct { TCGv_i32 *ptr; int off; const char *name; } r32[] = { - { &e2k_cs.wd_base, offsetof(CPUE2KState, wd.base), "woff" }, - { &e2k_cs.wd_size, offsetof(CPUE2KState, wd.size), "wsize" }, - { &e2k_cs.boff, offsetof(CPUE2KState, bn.base), "boff" }, - { &e2k_cs.bsize, offsetof(CPUE2KState, bn.size), "bsize" }, - { &e2k_cs.bcur, offsetof(CPUE2KState, bn.cur), "bcur" }, - { &e2k_cs.psize, offsetof(CPUE2KState, bp.size), "psize" }, - { &e2k_cs.pcur, offsetof(CPUE2KState, bp.cur), "pcur" }, - { &e2k_cs.is_bp, offsetof(CPUE2KState, is_bp), "is_bp" }, - { &e2k_cs.wdbl, offsetof(CPUE2KState, wdbl), "wdbl" }, - { &e2k_cs.lsr_lcnt, offsetof(CPUE2KState, lsr_lcnt), "lsr_lcnt" }, - { &e2k_cs.lsr_ecnt, offsetof(CPUE2KState, lsr_ecnt), "lsr_ecnt" }, - { &e2k_cs.lsr_vlc, offsetof(CPUE2KState, lsr_vlc), "lsr_vlc" }, - { &e2k_cs.lsr_over, offsetof(CPUE2KState, lsr_over), "lsr_over" }, - { &e2k_cs.lsr_pcnt, offsetof(CPUE2KState, lsr_pcnt), "lsr_pcnt" }, - { &e2k_cs.lsr_strmd, offsetof(CPUE2KState, lsr_strmd), "lsr_strmd" }, - { &e2k_cs.aasti_tags, offsetof(CPUE2KState, aau.sti_tags), "aasti_tags" }, - { &e2k_cs.aaind_tags, offsetof(CPUE2KState, aau.ind_tags), "aaind_tags" }, - { &e2k_cs.aaincr_tags, offsetof(CPUE2KState, aau.incr_tags), "aaincr_tags" }, - { &e2k_cs.ct_cond, offsetof(CPUE2KState, ct_cond), "cond" }, + { &cpu_wd_base, offsetof(CPUE2KState, wd.base), "woff" }, + { &cpu_wd_size, offsetof(CPUE2KState, wd.size), "wsize" }, + { &cpu_boff, offsetof(CPUE2KState, bn.base), "boff" }, + { &cpu_bsize, offsetof(CPUE2KState, bn.size), "bsize" }, + { &cpu_bcur, offsetof(CPUE2KState, bn.cur), "bcur" }, + { &cpu_psize, offsetof(CPUE2KState, bp.size), "psize" }, + { &cpu_pcur, offsetof(CPUE2KState, bp.cur), "pcur" }, + { &cpu_is_bp, offsetof(CPUE2KState, is_bp), "is_bp" }, + { &cpu_wdbl, offsetof(CPUE2KState, wdbl), "wdbl" }, + { &cpu_lsr_lcnt, offsetof(CPUE2KState, lsr_lcnt), "lsr_lcnt" }, + { &cpu_lsr_ecnt, offsetof(CPUE2KState, lsr_ecnt), "lsr_ecnt" }, + { &cpu_lsr_vlc, offsetof(CPUE2KState, lsr_vlc), "lsr_vlc" }, + { &cpu_lsr_over, offsetof(CPUE2KState, lsr_over), "lsr_over" }, + { &cpu_lsr_pcnt, offsetof(CPUE2KState, lsr_pcnt), "lsr_pcnt" }, + { &cpu_lsr_strmd, offsetof(CPUE2KState, lsr_strmd), "lsr_strmd" }, + { &cpu_aasti_tags, offsetof(CPUE2KState, aau.sti_tags), "aasti_tags" }, + { &cpu_aaind_tags, offsetof(CPUE2KState, aau.ind_tags), "aaind_tags" }, + { &cpu_aaincr_tags, offsetof(CPUE2KState, aau.incr_tags), "aaincr_tags" }, + { &cpu_ct_cond, offsetof(CPUE2KState, ct_cond), "cond" }, }; static const struct { TCGv_i64 *ptr; int off; const char *name; } r64[] = { - { &e2k_cs.pregs, offsetof(CPUE2KState, pregs), "pregs" }, - { &e2k_cs.last_value, offsetof(CPUE2KState, last_value), "last_value" }, + { &cpu_pregs, offsetof(CPUE2KState, pregs), "pregs" }, + { &cpu_last_value, offsetof(CPUE2KState, last_value), "last_value" }, }; static const struct { TCGv *ptr; int off; const char *name; } rtl[] = { - { &e2k_cs.pc, offsetof(CPUE2KState, ip), "pc" }, - { &e2k_cs.npc, offsetof(CPUE2KState, nip), "npc" }, + { &cpu_pc, offsetof(CPUE2KState, ip), "pc" }, + { &cpu_npc, offsetof(CPUE2KState, nip), "npc" }, }; unsigned int i; @@ -1296,34 +6485,34 @@ void e2k_tcg_initialize(void) { for (i = 0; i < 3; i++) { snprintf(buf, ARRAY_SIZE(buf), "%%ctpr%d", i + 1); - e2k_cs.ctprs[i] = tcg_global_mem_new_i64(cpu_env, + cpu_ctprs[i] = tcg_global_mem_new_i64(cpu_env, offsetof(CPUE2KState, ctprs[i].raw), buf); } for (i = 0; i < 16; i++) { snprintf(buf, ARRAY_SIZE(buf), "%%aasti%d", i); - e2k_cs.aasti[i] = tcg_global_mem_new_i32(cpu_env, + cpu_aasti[i] = tcg_global_mem_new_i32(cpu_env, offsetof(CPUE2KState, aau.stis[i]), buf); } for (i = 0; i < 16; i++) { snprintf(buf, ARRAY_SIZE(buf), "%%aaind%d", i); - e2k_cs.aaind[i] = tcg_global_mem_new_i32(cpu_env, + cpu_aaind[i] = tcg_global_mem_new_i32(cpu_env, offsetof(CPUE2KState, aau.inds[i]), buf); } for (i = 0; i < 7; i++) { snprintf(buf, ARRAY_SIZE(buf), "%%aaincr%d", i); - e2k_cs.aaincr[i] = tcg_global_mem_new_i32(cpu_env, + cpu_aaincr[i] = tcg_global_mem_new_i32(cpu_env, offsetof(CPUE2KState, aau.incrs[i]), buf); } for (i = 0; i < 32; i++) { snprintf(buf, ARRAY_SIZE(buf), "%%aad%d_lo", i); - e2k_cs.aad_lo[i] = tcg_global_mem_new_i64(cpu_env, + cpu_aad_lo[i] = tcg_global_mem_new_i64(cpu_env, offsetof(CPUE2KState, aau.ds[i].lo), buf); snprintf(buf, ARRAY_SIZE(buf), "%%aad%d_hi", i); - e2k_cs.aad_hi[i] = tcg_global_mem_new_i64(cpu_env, + cpu_aad_hi[i] = tcg_global_mem_new_i64(cpu_env, offsetof(CPUE2KState, aau.ds[i].hi), buf); } } diff --git a/target/e2k/translate.h b/target/e2k/translate.h deleted file mode 100644 index 6785aaec14..0000000000 --- a/target/e2k/translate.h +++ /dev/null @@ -1,599 +0,0 @@ -#ifndef E2K_TRANSLATE_H -#define E2K_TRANSLATE_H - -#include "tcg/tcg-op.h" -#include "exec/translator.h" - -#define DYNAMIC -1 - -#define IS_BASED(i) (((i) & 0x80) == 0) -#define IS_REGULAR(i) (((i) & 0xc0) == 0x80) -#define IS_IMM5(i) (((i) & 0xe0) == 0xc0) -#define IS_IMM4(i) (((i) & 0xf0) == 0xc0) -#define IS_LIT(i) (((i) & 0xf0) == 0xd0) -#define IS_LIT16_LO(i) (((i) & 0x0e) == 0x00) -#define IS_LIT16_HI(i) (((i) & 0x0e) == 0x04) -#define IS_LIT32(i) (((i) & 0x0c) == 0x08) -#define IS_LIT64(i) (((i) & 0x0c) == 0x0c) -#define IS_GLOBAL(i) (((i) & 0xe0) == 0xe0) - -#define GET_BASED(i) ((i) & 0x7f) -#define GET_REGULAR(i) ((i) & 0x3f) -#define GET_IMM5(i) ((i) & 0x1f) -#define GET_IMM4(i) ((i) & 0x0f) -#define GET_LIT(i) ((i) & 0x03) -#define GET_GLOBAL(i) ((i) & 0x1f) - -typedef enum { - ALES_NONE = 0x00, - ALES_PRESENT = 0x01, - ALES_ALLOCATED = 0x02, -} AlesFlag; - -typedef struct { - TCGv_i32 cdi[32]; - TCGv_i64 pib[32]; -} CPUE2KAauPrefStateTCG; - -typedef struct CPUE2KStateTCG { - TCGv pc; - TCGv npc; - TCGv_i64 ctprs[3]; - TCGv_i32 ct_cond; - TCGv_i32 is_bp; /* breakpoint flag */ - TCGv_i32 wdbl; - TCGv_i32 wd_base; /* holds wbs * 2 */ - TCGv_i32 wd_size; /* holds wsz * 2 */ - TCGv_i32 boff; /* holds rbs * 2 */ - TCGv_i32 bsize; /* holds rsz * 2 + 2 */ - TCGv_i32 bcur; /* holds rcur * 2 */ - TCGv_i64 pregs; - TCGv_i32 psize; /* holds psz */ - TCGv_i32 pcur; /* holds pcur */ - TCGv_i64 last_value; - /* lsr */ - TCGv_i32 lsr_lcnt; - TCGv_i32 lsr_ecnt; - TCGv_i32 lsr_vlc; - TCGv_i32 lsr_over; - TCGv_i32 lsr_pcnt; - TCGv_i32 lsr_strmd; - /* AAU */ - TCGv_i32 aasti[16]; - TCGv_i32 aasti_tags; - TCGv_i32 aaind[16]; - TCGv_i32 aaind_tags; - TCGv_i32 aaincr[8]; - TCGv_i32 aaincr_tags; - TCGv_i64 aad_lo[32]; - TCGv_i64 aad_hi[32]; - CPUE2KAauPrefStateTCG aapl, aapr; -} CPUE2KStateTCG; - -extern struct CPUE2KStateTCG e2k_cs; - -typedef struct { - uint32_t hs; - uint32_t ss; - uint32_t als[6]; - uint32_t cs0; - uint16_t ales[6]; - uint32_t cs1; - uint16_t aas[6]; - uint32_t lts[4]; - uint32_t pls[3]; - uint32_t cds[3]; - - bool ss_present; - bool als_present[6]; - bool cs0_present; - AlesFlag ales_present[6]; - bool cs1_present; - bool aas_present[6]; - bool lts_present[4]; - bool pls_present[3]; - bool cds_present[3]; -} UnpackedBundle; - -typedef struct { - int32_t sdisp; /* CS0 28:0 */ -} Cs0IBranch, Cs0Puttsd; - -typedef struct { - int32_t sdisp; /* CS0 28:0 */ - uint8_t ipd; /* SS 31:30 */ - uint8_t ctpr; /* CS0 31:30 */ - uint8_t opc; -} Cs0Disp; - -typedef struct { - uint32_t disp; /* CS0 28:0 */ - uint8_t ipd; /* SS 31:30 */ - uint8_t ctpr; /* CS0 31:30 */ -} Cs0SDisp; - -typedef struct { - uint8_t ipd; -} Cs0Return; - -typedef struct { - uint32_t disp; /* 28:4 */ - uint8_t prefr; /* 2:0 */ - uint8_t ipd; /* 3 */ -} Cs0Pref; - -typedef enum { - CS0_NONE, - CS0_IBRANCH, - CS0_PREF, - CS0_PUTTSD, - CS0_DONE, - CS0_HRET, - CS0_GLAUNCH, - CS0_DISP, - CS0_SDISP, - CS0_GETTSD, - CS0_RETURN, -} Cs0Type; - -typedef struct { - Cs0Type type; - union { - Cs0IBranch ibranch; - Cs0Puttsd puttsd; - Cs0Disp disp; - Cs0SDisp sdisp; - Cs0Pref pref; - Cs0Return ret; - }; -} Cs0; - -typedef enum { - SETR_VFRPSZ = 0x01, - SETR_WD = 0x02, - SETR_BN = 0x04, - SETR_BP = 0x08, -} SetrType; - -typedef struct { - SetrType type; - uint8_t rpsz; - uint8_t wsz; - bool nfx; - bool dbl; - uint8_t rbs; - uint8_t rsz; - uint8_t rcur; - uint8_t psz; -} Cs1Setr; - -typedef struct { - bool ma_c; - bool fl_c; - bool ld_c; - bool st_c; - bool all_e; - bool all_c; - /* v2+ */ - bool trap; - /* v5+ */ - bool sal; - bool sas; -} Cs1Wait; - -typedef struct { - uint8_t wbs; - uint8_t disp; -} Cs1HCall; - -typedef struct { - bool flushr; - bool flushc; -} Cs1Flush; - -typedef struct { - bool chkm4; - uint8_t dmask; - uint8_t umask; -} Cs1Vfbg; - -typedef enum { - CS1_NONE, - CS1_SETR, - CS1_SETEI, - CS1_SETSFT, - CS1_WAIT, - CS1_CALL, - CS1_HCALL, - CS1_MAS, - CS1_FLUSH, - CS1_VFBG, -} Cs1Type; - -typedef struct { - Cs1Type type; - union { - Cs1Setr setr; - uint8_t ei; - Cs1Wait wait; - uint8_t call_wbs; - Cs1HCall hcall; - uint8_t mas[6]; - Cs1Flush flush; - Cs1Vfbg vfbg; - }; -} Cs1; - -typedef enum { - ALOPF_NONE, - ALOPF1, - ALOPF1_MERGE, - ALOPF2, - ALOPF3, - ALOPF7, - ALOPF8, - ALOPF10, - ALOPF11, - ALOPF11_MERGE, - ALOPF11_LIT8, - ALOPF12, - ALOPF12_PSHUFH, - ALOPF12_IBRANCHD, - ALOPF12_ICALLD, - ALOPF13, - ALOPF15, - ALOPF16, - ALOPF17, - ALOPF21, - ALOPF21_ICOMB, - ALOPF21_FCOMB, - ALOPF21_PFCOMB, - ALOPF21_LCOMB, - ALOPF22, -} Alopf; - -typedef struct { - Alopf format; - uint32_t op; - const char *name; -} Alop; - -typedef struct { - Cs0 cs0; - Cs1 cs1; - Alop alops[6]; -} Bundle; - -typedef enum { - AL_RESULT_NONE = 0, - - AL_RESULT_SIZE_MASK = 0x3, - AL_RESULT_32 = 0x00, - AL_RESULT_64 = 0x01, - AL_RESULT_80 = 0x02, - AL_RESULT_128 = 0x03, - - AL_RESULT_TYPE_MASK = 0xc, - AL_RESULT_REG = 0x04, - AL_RESULT_PREG = 0x08, - AL_RESULT_CTPR = 0x0c, - - AL_RESULT_REG32 = AL_RESULT_REG | AL_RESULT_32, - AL_RESULT_REG64 = AL_RESULT_REG | AL_RESULT_64, - AL_RESULT_REG80 = AL_RESULT_REG | AL_RESULT_80, - AL_RESULT_REG128 = AL_RESULT_REG | AL_RESULT_128, - AL_RESULT_CTPR32 = AL_RESULT_CTPR | AL_RESULT_32, - AL_RESULT_CTPR64 = AL_RESULT_CTPR | AL_RESULT_64, -} AlResultType; - -#define e2k_al_result_size(x) ((x) & AL_RESULT_SIZE_MASK) -#define e2k_al_result_type(x) ((x) & AL_RESULT_TYPE_MASK) - -typedef struct { - AlResultType type; - /* check tag for 32-bit ops if wdbl is set */ - bool check_tag; - /* poison result if tag is not zero */ - bool poison; - /* Is 32-bit op affected by wdbl */ - bool dbl; - union { - struct { - TCGv_i32 index; - TCGv_i32 tag; - union { - TCGv_i32 v32; - TCGv_i64 v64; - }; - union { - TCGv_i32 x32; /* FX ops */ - TCGv_i64 x64; /* SIMD ops v5+ */ - }; - } reg; - struct { - int index; - union { - TCGv_i32 v32; - TCGv_i64 v64; - }; - } ctpr; - struct { - int index; - TCGv_i32 val; - } preg; - }; -} AlResult; - -typedef struct { - bool is_set; - uint8_t dst; - TCGv_i32 index; - TCGv_i32 tag; - TCGv_i64 value; -} AauResult; - -typedef struct { - int reg; // -1 means do not write - TCGv_i32 value; -} PlResult; - -typedef enum { - CT_NONE, - CT_IBRANCH, - CT_JUMP, - CT_CALL, -} ControlTransferType; - -typedef struct { - ControlTransferType type; - union { - target_ulong target; - TCGv_i64 ctpr; - } u; - int wbs; - uint8_t cond_type; - uint8_t psrc; -} ControlTransfer; - -typedef struct DisasContext { - DisasContextBase base; - UnpackedBundle bundle; - Bundle bundle2; - target_ulong pc; - int jump_ctpr; - int mmuidx; - uint8_t mas[6]; - bool loop_mode; - TCGv_i32 is_epilogue; - /* optional, can be NULL */ - TCGv_i32 mlock; - - int version; - /* Force ILLOP for bad instruction format for cases where real CPU - do not generate it. */ - bool strict; - - // Temporary values. - TCGv_i32 t32[64]; - TCGv_i64 t64[32]; - TCGv ttl[8]; - // Allocated temporary values count. - int t32_len; - int t64_len; - int ttl_len; - - /* Delayed illegal tag check */ - TCGv_i32 illtag; - bool do_check_illtag; - - /* Delayed window bounds check */ - int wd_size; - int max_r; - int max_r_src; - int max_r_dst; - int bsize; - int max_b; - int max_b_cur; - - TCGv_i64 cond[6]; - AlResult al_results[6]; - TCGv_i32 al_cond[6]; - AauResult aau_results[4]; - int aau_am[4]; - PlResult pl_results[3]; - ControlTransfer ct; -} DisasContext; - -static inline void gen_save_pc(target_ulong pc) -{ - tcg_gen_movi_tl(e2k_cs.pc, pc); -} - -static inline void gen_save_cpu_state(DisasContext *ctx) -{ - gen_save_pc(ctx->pc); -} - -static inline void gen_tr_exception(DisasContext *ctx, int exception_index) -{ - TCGv_i32 t0 = tcg_const_i32(exception_index); - - ctx->base.is_jmp = DISAS_NORETURN; - gen_save_cpu_state(ctx); - gen_helper_raise_exception(cpu_env, t0); - tcg_temp_free_i32(t0); -} - -#define IMPL_GEN_TR_EXCP(name, excp) \ - static inline void name(DisasContext *ctx) \ - { \ - gen_tr_exception(ctx, excp); \ - } - -IMPL_GEN_TR_EXCP(gen_tr_excp_illopc, EXCP_ILLEGAL_OPCODE) -IMPL_GEN_TR_EXCP(gen_tr_excp_illopn, EXCP_ILLEGAL_OPERAND) -IMPL_GEN_TR_EXCP(gen_tr_excp_window_bounds, EXCP_WINDOW_BOUNDS) -IMPL_GEN_TR_EXCP(gen_tr_excp_array_bounds, EXCP_ARRAY_BOUNDS) - -static inline void gen_exception(int excp) -{ - TCGv_i32 t0 = tcg_const_i32(excp); - - // TODO: check if need to save state - gen_helper_raise_exception(cpu_env, t0); - tcg_temp_free_i32(t0); -} - -#define IMPL_GEN_EXCP(name, excp) \ - static inline void name(void) \ - { \ - gen_exception(excp); \ - } - -IMPL_GEN_EXCP(gen_excp_illopc, EXCP_ILLEGAL_OPCODE) -IMPL_GEN_EXCP(gen_excp_window_bounds, EXCP_WINDOW_BOUNDS) - -#define e2k_todo(ctx, fmt, ...) \ - qemu_log(TARGET_FMT_lx ": " fmt " (%s:%d)\n", ctx->pc, \ - ## __VA_ARGS__, __FILE__, __LINE__) - -#define e2k_todo_illop(ctx, fmt, ...) \ - e2k_todo(ctx, fmt, ## __VA_ARGS__); \ - gen_tr_excp_illopc(ctx) - -static inline TCGv_i32 e2k_get_temp_i32(DisasContext *dc) -{ - assert(dc->t32_len < ARRAY_SIZE(dc->t32)); - return dc->t32[dc->t32_len++] = tcg_temp_local_new_i32(); -} - -static inline TCGv_i32 e2k_get_const_i32(DisasContext *dc, uint32_t value) -{ - assert(dc->t32_len < ARRAY_SIZE(dc->t32)); - return dc->t32[dc->t32_len++] = tcg_const_local_i32(value); -} - -static inline TCGv_i64 e2k_get_temp_i64(DisasContext *dc) -{ - assert(dc->t64_len < ARRAY_SIZE(dc->t64)); - return dc->t64[dc->t64_len++] = tcg_temp_local_new_i64(); -} - -static inline TCGv_i64 e2k_get_const_i64(DisasContext *dc, uint64_t value) -{ - assert(dc->t64_len < ARRAY_SIZE(dc->t64)); - return dc->t64[dc->t64_len++] = tcg_const_local_i64(value); -} - -static inline TCGv e2k_get_temp(DisasContext *dc) -{ - assert(dc->ttl_len < ARRAY_SIZE(dc->ttl)); - return dc->ttl[dc->ttl_len++] = tcg_temp_local_new(); -} - -static inline TCGv e2k_get_const(DisasContext *dc, target_ulong value) -{ - assert(dc->ttl_len < ARRAY_SIZE(dc->ttl)); - return dc->ttl[dc->ttl_len++] = tcg_const_local_tl(value); -} - -static inline void e2k_gen_lcntex(TCGv_i32 ret) -{ - tcg_gen_setcondi_i32(TCG_COND_EQ, ret, e2k_cs.lsr_lcnt, 0); -} - -void e2k_gen_store_preg(int idx, TCGv_i32 val); - -void e2k_gen_reg_tag_read_i64(TCGv_i32 ret, TCGv_i32 idx); -void e2k_gen_reg_tag_read_i32(TCGv_i32 ret, TCGv_i32 idx); -void e2k_gen_reg_tag_write_i64(TCGv_i32 value, TCGv_i32 idx); -void e2k_gen_reg_tag_write_i32(TCGv_i32 value, TCGv_i32 idx); - -static inline void e2k_gen_reg_tag_writei_i64(int value, TCGv_i32 idx) -{ - TCGv_i32 t0 = tcg_const_i32(value); - e2k_gen_reg_tag_write_i64(t0, idx); - tcg_temp_free_i32(t0); -} - -static inline void e2k_gen_reg_tag_writei_i32(int value, TCGv_i32 idx) -{ - TCGv_i32 t0 = tcg_const_i32(value); - e2k_gen_reg_tag_write_i32(t0, idx); - tcg_temp_free_i32(t0); -} - -static inline void e2k_gen_reg_tag_extract_lo(TCGv_i32 ret, TCGv_i32 tags) -{ - tcg_gen_andi_i32(ret, tags, GEN_MASK(0, E2K_TAG_SIZE)); -} - -static inline void e2k_gen_reg_tag_extract_hi(TCGv_i32 ret, TCGv_i32 tags) -{ - tcg_gen_shri_i32(ret, tags, E2K_TAG_SIZE); -} - -void e2k_gen_reg_tag_check_i64(TCGv_i32 ret, TCGv_i32 tag); -void e2k_gen_reg_tag_check_i32(TCGv_i32 ret, TCGv_i32 tag); - -void e2k_gen_reg_index_from_wregi(TCGv_i32 ret, int idx); -void e2k_gen_reg_index_from_bregi(TCGv_i32 ret, int idx); -void e2k_gen_reg_index_from_gregi(TCGv_i32 ret, int idx); -static inline void e2k_gen_reg_index(DisasContext *ctx, 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 { - gen_tr_exception(ctx, EXCP_ILLEGAL_OPERAND); - } -} - -void e2k_gen_reg_lo_read_i64(TCGv_i64 ret, TCGv_i32 idx); -void e2k_gen_reg_lo_read_i32(TCGv_i32 ret, TCGv_i32 idx); -void e2k_gen_reg_lo_write_i64(TCGv_i64 value, TCGv_i32 idx); -void e2k_gen_reg_lo_write_i32(TCGv_i32 value, TCGv_i32 idx); - -void e2k_gen_reg_hi_read_i64(TCGv_i64 ret, TCGv_i32 idx); -void e2k_gen_reg_hi_read_i32(TCGv_i32 ret, TCGv_i32 idx); -void e2k_gen_reg_hi_read16u_i32(TCGv_i32 ret, TCGv_i32 idx); -void e2k_gen_reg_hi_write_i64(TCGv_i64 value, TCGv_i32 idx); -void e2k_gen_reg_hi_write_i32(TCGv_i32 value, TCGv_i32 idx); -void e2k_gen_reg_hi_write16u_i32(TCGv_i32 value, TCGv_i32 idx); - -void e2k_gen_preg_i32(TCGv_i32 ret, int reg); -void e2k_gen_cond_i32(DisasContext *ctx, TCGv_i32 ret, uint8_t psrc); - -static inline void e2k_gen_is_loop_end_i32(TCGv_i32 ret) -{ - TCGv_i32 t0 = tcg_temp_new_i32(); - TCGv_i32 t1 = tcg_temp_new_i32(); - TCGv_i32 t2 = tcg_temp_new_i32(); - - tcg_gen_setcondi_i32(TCG_COND_EQ, t0, e2k_cs.lsr_ecnt, 0); - tcg_gen_setcondi_i32(TCG_COND_LTU, t1, e2k_cs.lsr_lcnt, 2); - tcg_gen_and_i32(t2, t0, t1); - tcg_gen_and_i32(ret, t2, e2k_cs.lsr_vlc); - - tcg_temp_free_i32(t2); - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t0); -} - -void e2k_decode_jmp(DisasContext *ctx); -void e2k_stubs_commit(DisasContext *ctx); - -void alc_init(DisasContext *ctx); -void e2k_alc_decode(DisasContext *ctx); -void e2k_alc_execute(DisasContext *ctx); -void e2k_alc_commit(DisasContext *ctx); - -void e2k_aau_execute(DisasContext *ctx); -void e2k_aau_commit(DisasContext *ctx); -void e2k_plu_execute(DisasContext *ctx); -void e2k_plu_commit(DisasContext *ctx); - -#endif diff --git a/target/e2k/translate/aau.c b/target/e2k/translate/aau.c deleted file mode 100644 index 96063f316d..0000000000 --- a/target/e2k/translate/aau.c +++ /dev/null @@ -1,188 +0,0 @@ -#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); - } -} diff --git a/target/e2k/translate/alc.c b/target/e2k/translate/alc.c deleted file mode 100644 index 38406f4231..0000000000 --- a/target/e2k/translate/alc.c +++ /dev/null @@ -1,4946 +0,0 @@ -#include "qemu/osdep.h" -#include "qemu.h" -#include "exec/log.h" -#include "translate.h" -#include "tcg/tcg-op-gvec.h" - -#include "alops.inc" - -#define glue3(a, b, c) glue(glue(a, b), c) -#define glue4(a, b, c, d) glue(glue(a, b), glue(c, d)) - -static int16_t alops_map[4][128][6]; - -typedef struct { - TCGv_i32 tag; - TCGv_i64 lo; - TCGv_i32 hi; -} Src80; - -typedef struct { - TCGv_i32 tag; - TCGv_i64 value; -} Src64; - -typedef struct { - TCGv_i32 tag; - TCGv_i32 value; -} Src32; - -typedef struct { - DisasContext *ctx; - int chan; - AlesFlag ales_present; - int aaincr_len; - uint8_t mas; - union { - uint32_t als; - struct { - uint32_t src4: 8; - uint32_t src2: 8; - uint32_t src1: 8; - uint32_t opc1: 7; - uint32_t sm: 1; - }; - struct { - uint32_t dst: 8; - uint32_t opce2: 8; - uint32_t opce1: 8; - uint32_t unused1: 8; - }; - struct { - uint32_t dst_preg: 5; - uint32_t opc_cmp: 3; - uint32_t unused2: 24; - }; - /* staa/ldaa/aaurw/aaurr */ - struct { - uint32_t unused3: 8; - uint32_t aalit: 2; - uint32_t aaopc: 2; - uint32_t aaincr: 3; - /* aaind/aasti/aaincr for aaurw/aaurr */ - uint32_t aaind: 4; - uint32_t aad: 5; - uint32_t unused4: 8; - }; - }; - union { - uint16_t ales; - struct { - uint16_t src3: 8; - uint16_t opc2: 8; - }; - struct { - uint16_t opce3: 8; - uint16_t unused5: 8; - }; - }; -} Instr; - -static inline bool is_chan_03(int c) -{ - return c == 0 || c == 3; -} - -static inline bool is_chan_14(int c) -{ - return c == 1 || c == 4; -} - -static inline bool is_chan_25(int c) -{ - return c == 2 || c == 5; -} - -static inline bool is_chan_0134(int c) -{ - return is_chan_03(c) || is_chan_14(c); -} - -static inline TCGv_i64 get_temp_i64(Instr *instr) -{ - return e2k_get_temp_i64(instr->ctx); -} - -static inline TCGv_i32 get_temp_i32(Instr *instr) -{ - return e2k_get_temp_i32(instr->ctx); -} - -static inline Src80 temp_new_src80(void) -{ - Src80 t = { 0 }; - - t.tag = tcg_temp_new_i32(); - t.lo = tcg_temp_new_i64(); - t.hi = tcg_temp_new_i32(); - - return t; -} - -static inline Src80 temp_local_new_src80(void) -{ - Src80 t = { 0 }; - - t.tag = tcg_temp_local_new_i32(); - t.lo = tcg_temp_local_new_i64(); - t.hi = tcg_temp_local_new_i32(); - - return t; -} - -static inline void temp_free_src80(Src80 *t) -{ - tcg_temp_free_i32(t->tag); - tcg_temp_free_i64(t->lo); - tcg_temp_free_i32(t->hi); -} - -static inline Src80 get_temp_src80(Instr *instr) -{ - Src80 t = { 0 }; - - t.tag = get_temp_i32(instr); - t.lo = get_temp_i64(instr); - t.hi = get_temp_i32(instr); - - return t; -} - -static inline void gen_reg_i80(DisasContext *ctx, Src80 *ret, uint8_t arg) -{ - TCGv_i32 t0 = tcg_temp_new_i32(); - - e2k_gen_reg_index(ctx, t0, arg); - ret->tag = e2k_get_temp_i32(ctx); - ret->lo = e2k_get_temp_i64(ctx); - ret->hi = e2k_get_temp_i32(ctx); - e2k_gen_reg_tag_read_i64(ret->tag, t0); - e2k_gen_reg_lo_read_i64(ret->lo, t0); - e2k_gen_reg_hi_read16u_i32(ret->hi, t0); - tcg_temp_free_i32(t0); -} - -static inline void gen_reg_i64(DisasContext *ctx, Src64 *ret, uint8_t arg) -{ - TCGv_i32 t0 = tcg_temp_new_i32(); - - e2k_gen_reg_index(ctx, 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_lo_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(); - - e2k_gen_reg_index(ctx, 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_lo_read_i32(ret->value, t0); - - tcg_temp_free_i32(t0); -} - -static inline void gen_temp_reg_write_i64_i32(TCGv_i64 lo, TCGv_i32 hi, - TCGv_ptr ptr) -{ - tcg_gen_st_i64(lo, ptr, offsetof(E2KReg, f80.low)); - tcg_gen_st16_i32(hi, ptr, offsetof(E2KReg, f80.high)); -} - -static inline void gen_temp_reg_read_i64_i32(TCGv_ptr ptr, TCGv_i64 ret_lo, - TCGv_i32 ret_hi) -{ - tcg_gen_ld_i64(ret_lo, ptr, offsetof(E2KReg, f80.low)); - tcg_gen_ld16u_i32(ret_hi, ptr, offsetof(E2KReg, f80.high)); -} - -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]) { - gen_tr_excp_illopn(ctx); - } 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]) { - gen_tr_excp_illopn(ctx); - } - lit |= (uint64_t) ctx->bundle.lts[i + 1] << 32; - } else { - gen_tr_excp_illopn(ctx); - } - - ret->tag = e2k_get_const_i32(ctx, 0); - 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]) { - gen_tr_excp_illopn(ctx); - } 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]) { - gen_tr_excp_illopn(ctx); - } - } else { - gen_tr_excp_illopn(ctx); - } - - ret->tag = e2k_get_const_i32(ctx, 0); - ret->value = e2k_get_const_i32(ctx, lit); -} - -static inline Src80 get_src1_i80(Instr *instr) -{ - DisasContext *ctx = instr->ctx; - uint8_t src1 = instr->src1; - Src80 ret = { 0 }; - - if (IS_IMM5(src1)) { - ret.tag = e2k_get_const_i32(ctx, 0); - ret.lo = e2k_get_const_i64(ctx, GET_IMM5(src1)); - ret.hi = e2k_get_const_i32(ctx, 0); - } else { - gen_reg_i80(ctx, &ret, src1); - } - - return ret; -} - -static inline Src64 get_src1_i64(Instr *instr) -{ - DisasContext *ctx = instr->ctx; - uint8_t src1 = instr->src1; - Src64 ret = { 0 }; - - if (IS_IMM5(src1)) { - ret.tag = e2k_get_const_i32(ctx, 0); - ret.value = e2k_get_const_i64(ctx, GET_IMM5(src1)); - } else { - gen_reg_i64(ctx, &ret, src1); - } - - return ret; -} - -static inline Src32 get_src1_i32(Instr *instr) -{ - DisasContext *ctx = instr->ctx; - uint8_t src1 = instr->src1; - Src32 ret = { 0 }; - - if (IS_IMM5(src1)) { - ret.tag = e2k_get_const_i32(ctx, 0); - ret.value = e2k_get_const_i32(ctx, GET_IMM5(src1)); - } else { - gen_reg_i32(ctx, &ret, src1); - } - - return ret; -} - -static inline Src80 get_src2_i80(Instr *instr) -{ - DisasContext *ctx = instr->ctx; - uint8_t src2 = instr->src2; - Src80 ret = { 0 }; - - if (IS_IMM4(src2)) { - ret.tag = e2k_get_const_i32(ctx, 0); - ret.lo = e2k_get_const_i64(ctx, GET_IMM4(src2)); - ret.hi = e2k_get_const_i32(ctx, 0); - } else if (IS_LIT(src2)) { - Src64 t = { 0 }; - gen_literal_i64(ctx, &t, src2); - ret.tag = t.tag; - ret.lo = t.value; - ret.hi = e2k_get_const_i32(ctx, 0); - } else { - gen_reg_i80(ctx, &ret, src2); - } - - return ret; -} - -static inline Src64 get_src2_i64(Instr *instr) -{ - DisasContext *ctx = instr->ctx; - uint8_t src2 = instr->src2; - Src64 ret = { 0 }; - - if (IS_IMM4(src2)) { - ret.tag = e2k_get_const_i32(ctx, 0); - ret.value = e2k_get_const_i64(ctx, GET_IMM4(src2)); - } else if (IS_LIT(src2)) { - gen_literal_i64(ctx, &ret, src2); - } else { - gen_reg_i64(ctx, &ret, src2); - } - - return ret; -} - -static inline Src32 get_src2_i32(Instr *instr) -{ - DisasContext *ctx = instr->ctx; - uint8_t src2 = instr->src2; - Src32 ret = { 0 }; - - if (IS_IMM4(src2)) { - ret.tag = e2k_get_const_i32(ctx, 0); - ret.value = e2k_get_const_i32(ctx, GET_IMM4(src2)); - } else if (IS_LIT(src2)) { - gen_literal_i32(ctx, &ret, src2); - } else { - gen_reg_i32(ctx, &ret, src2); - } - - return ret; -} - -static inline Src64 get_src3_i64(Instr *instr) -{ - Src64 ret = { 0 }; - gen_reg_i64(instr->ctx, &ret, instr->src3); - return ret; -} - -static inline Src32 get_src3_i32(Instr *instr) -{ - Src32 ret = { 0 }; - gen_reg_i32(instr->ctx, &ret, instr->src3); - return ret; -} - -static inline Src64 get_src4_i64(Instr *instr) -{ - Src64 ret = { 0 }; - gen_reg_i64(instr->ctx, &ret, instr->src4); - return ret; -} - -static inline Src32 get_src4_i32(Instr *instr) -{ - Src32 ret = { 0 }; - gen_reg_i32(instr->ctx, &ret, instr->src4); - return ret; -} - -/* - * Returns zero if all @args is zero otherwise returns @tag. - */ -static inline void gen_tag3(TCGv_i32 ret, int tag, TCGv_i32 arg1, TCGv_i32 arg2, - TCGv_i32 arg3) -{ - TCGv_i32 zero = tcg_const_i32(0); - TCGv_i32 fail = tcg_const_i32(tag); - TCGv_i32 t0 = tcg_temp_new_i32(); - - if (arg1 != NULL) { - tcg_gen_mov_i32(t0, arg1); - } else { - tcg_gen_movi_i32(t0, 0); - } - if (arg2 != NULL) { - tcg_gen_or_i32(t0, t0, arg2); - } - if (arg3 != NULL) { - tcg_gen_or_i32(t0, t0, arg3); - } - tcg_gen_movcond_i32(TCG_COND_NE, ret, t0, zero, fail, zero); - - tcg_temp_free_i32(t0); - tcg_temp_free_i32(fail); - tcg_temp_free_i32(zero); -} - -/* - * Returns zero if all @args is zero otherwise returns tag of non 64-bit number. - */ -#define gen_tag3_i64(ret, a1, a2, a3) \ - gen_tag3((ret), E2K_TAG_NON_NUMBER64, (a1), (a2), (a3)) -#define gen_tag2_i64(ret, a1, a2) gen_tag3_i64((ret), (a1), (a2), NULL) -#define gen_tag1_i64(ret, a1) gen_tag2_i64((ret), (a1), NULL) - -/* - * Returns zero if all @args is zero otherwise returns tag of non 32-bit number. - */ -#define gen_tag3_i32(ret, a1, a2, a3) \ - gen_tag3((ret), E2K_TAG_NON_NUMBER32, (a1), (a2), (a3)) -#define gen_tag2_i32(ret, a1, a2) gen_tag3_i32((ret), (a1), (a2), NULL) -#define gen_tag1_i32(ret, a1) gen_tag2_i32((ret), (a1), NULL) - -static inline void gen_tag_check(Instr *instr, TCGv_i32 tag) -{ - if (!instr->sm && tag != NULL) { - instr->ctx->do_check_illtag = true; - TCGv_i32 illtag = instr->ctx->illtag; - tcg_gen_or_i32(illtag, illtag, tag); - } -} - -static inline void gen_dst_poison_i64(TCGv_i64 ret, TCGv_i64 value, - TCGv_i32 tag) -{ - TCGv_i64 zero = tcg_const_i64(0); - TCGv_i64 t0 = tcg_temp_new_i64(); - TCGv_i64 t1 = tcg_temp_new_i64(); - - tcg_gen_ori_i64(t0, value, (1UL << 62) | (1 << 30)); - tcg_gen_extu_i32_i64(t1, tag); - tcg_gen_movcond_i64(TCG_COND_NE, ret, t1, zero, t0, value); - - tcg_temp_free_i64(t1); - tcg_temp_free_i64(t0); - tcg_temp_free_i64(zero); -} - -static inline void gen_dst_poison_i32(TCGv_i32 ret, TCGv_i32 value, - TCGv_i32 tag) -{ - TCGv_i32 zero = tcg_const_i32(0); - TCGv_i32 t0 = tcg_temp_new_i32(); - - tcg_gen_ori_i32(t0, value, 1 << 30); - tcg_gen_movcond_i32(TCG_COND_NE, ret, tag, zero, t0, value); - - tcg_temp_free_i32(t0); - tcg_temp_free_i32(zero); -} - -static inline void set_al_result_reg80_tag(Instr *instr, TCGv_i64 lo, - TCGv_i32 hi, TCGv_i32 tag, bool poison) -{ - uint8_t dst = instr->dst; - AlResult *res = &instr->ctx->al_results[instr->chan]; - - res->poison = poison; - if (dst == 0xdf) { - res->type = AL_RESULT_NONE; - } else { - res->type = AL_RESULT_REG80; - res->reg.tag = tag; - res->reg.v64 = lo; - res->reg.x32 = hi; - res->reg.index = get_temp_i32(instr); - e2k_gen_reg_index(instr->ctx, res->reg.index, dst); - } -} - -static inline void set_al_result_reg64_tag(Instr *instr, - TCGv_i64 value, TCGv_i32 tag, bool poison) -{ - uint8_t arg = instr->dst; - AlResult *res = &instr->ctx->al_results[instr->chan]; - - res->poison = poison; - // 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 - // TODO: check tag - res->type = AL_RESULT_CTPR64; - res->ctpr.index = (arg & 3) - 1; - res->ctpr.v64 = value; - } else { - res->type = AL_RESULT_REG64; - res->reg.v64 = value; - res->reg.tag = tag; - res->reg.index = e2k_get_temp_i32(instr->ctx); - e2k_gen_reg_index(instr->ctx, res->reg.index, arg); - } -} - -static inline void set_al_result_reg64(Instr *instr, TCGv_i64 value) -{ - TCGv_i32 tag = e2k_get_const_i32(instr->ctx, 0); - set_al_result_reg64_tag(instr, value, tag, true); -} - -static inline void set_al_result_reg32_tag(Instr *instr, - TCGv_i32 value, TCGv_i32 tag, bool poison, bool check_tag, bool dbl) -{ - uint8_t arg = instr->dst; - AlResult *res = &instr->ctx->al_results[instr->chan]; - - res->check_tag = check_tag; - res->dbl = dbl; - res->poison = poison; - // 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->ctpr.index = (arg & 3) - 1; - res->ctpr.v32 = value; - } else { - res->type = AL_RESULT_REG32; - res->reg.v32 = value; - res->reg.tag = tag; - res->reg.index = e2k_get_temp_i32(instr->ctx); - e2k_gen_reg_index(instr->ctx, res->reg.index, arg); - } -} - -static inline void set_al_result_reg32(Instr *instr, TCGv_i32 value) -{ - TCGv_i32 tag = e2k_get_const_i32(instr->ctx, 0); - set_al_result_reg32_tag(instr, value, tag, true, true, true); -} - -static inline void set_al_result_preg(Instr *instr, int index, TCGv_i32 value) -{ - AlResult *res = &instr->ctx->al_results[instr->chan]; - - res->type = AL_RESULT_PREG; - res->preg.index = index; - res->preg.val = value; -} - -static inline void gen_al_result_i80(Instr *instr, TCGv_i64 lo, TCGv_i32 hi, - TCGv_i32 tag) -{ - gen_tag_check(instr, tag); - set_al_result_reg80_tag(instr, lo, hi, tag, true); -} - -static inline void gen_al_result_i64(Instr *instr, TCGv_i64 dst, TCGv_i32 tag) -{ - gen_tag_check(instr, tag); - set_al_result_reg64_tag(instr, dst, tag, true); -} - -static inline void gen_al_result_i32(Instr *instr, TCGv_i32 dst, TCGv_i32 tag) -{ - gen_tag_check(instr, tag); - set_al_result_reg32_tag(instr, dst, tag, true, true, true); -} - -static inline bool check_qr(uint8_t src, int chan) -{ - int index = 0, o = chan & 1; - if (IS_REGULAR(src)) { - index = GET_REGULAR(src); - } else if (IS_BASED(src)) { - index = GET_BASED(src); - } else if (IS_GLOBAL(src)) { - index = GET_GLOBAL(src); - } else { - return true; - } - return (index & 1) == (chan < 2 ? o : o ^ 1); -} - -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 = extract32(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 uint16_t find_am_cond(DisasContext *ctx, int chan) -{ - unsigned int i, j; - - for (i = 0; i < ctx->bundle.cds_present[i]; i++) { - uint16_t *cds = (uint16_t *) &ctx->bundle.cds[i]; - - for (j = 0; j < 2; j++) { - int opc = extract16(cds[j], 13, 3); - int req = chan <= 2 ? 1 : 3; - - if (opc == req) { - return cds[j]; - } - } - } - - return 0; -} - -static inline void gen_am_cond_i32(DisasContext *ctx, TCGv_i32 ret, int chan, - uint16_t rlp) -{ - TCGv_i32 t0 = tcg_temp_new_i32(); - - e2k_gen_cond_i32(ctx, t0, extract16(rlp, 0, 7)); - // FIXME: It isn't clear if am can be the only one cond in RLP. - tcg_gen_xori_i32(ret, t0, GET_BIT(rlp, 7 + chan % 3)); - - tcg_temp_free_i32(t0); -} - -static inline void gen_mrgc_i32(DisasContext *ctx, int chan, TCGv_i32 ret) -{ - uint16_t rlp = find_mrgc(ctx, chan); - - if (rlp) { - int psrc = extract16(rlp, 0, 7); - - if (GET_BIT(rlp, 7 + chan % 3)) { - TCGv_i32 t0 = tcg_temp_new_i32(); - - e2k_gen_cond_i32(ctx, t0, psrc); - tcg_gen_setcondi_i32(TCG_COND_EQ, ret, t0, 0); - - tcg_temp_free_i32(t0); - } else { - e2k_gen_cond_i32(ctx, ret, psrc); - } - } else { - /* Undefined behavior if MRGC is not provided but CPU returns src2. */ - tcg_gen_movi_i32(ret, 0); - } -} - -static void gen_loop_mode_st(DisasContext *ctx, TCGLabel *l) -{ - if (ctx->loop_mode) { - TCGLabel *l0 = gen_new_label(); - TCGv_i32 t0 = tcg_temp_new_i32(); - tcg_gen_brcondi_i32(TCG_COND_NE, e2k_cs.lsr_pcnt, 0, l); - e2k_gen_is_loop_end_i32(t0); - tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l0); - tcg_gen_brcondi_i32(TCG_COND_EQ, e2k_cs.lsr_strmd, 0, l); - tcg_gen_subi_i32(e2k_cs.lsr_strmd, e2k_cs.lsr_strmd, 1); - 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); -} - -#define IMPL_GEN_MASK(S, T, L) \ - static inline void glue(gen_mask_, S)(T ret, T size) \ - { \ - T t0 = glue(tcg_const_, S)(1); \ - T t1 = glue(tcg_temp_new_, S)(); \ - glue(tcg_gen_shl_, S)(t1, t0, size); \ - glue(tcg_gen_subi_, S)(ret, t1, 1); \ - glue(tcg_temp_free_, S)(t1); \ - glue(tcg_temp_free_, S)(t0); \ - } \ - -IMPL_GEN_MASK(i64, TCGv_i64, 64) -IMPL_GEN_MASK(i32, TCGv_i32, 32) - -#define IMPL_GEN_GETF_SIGN(S, T) \ - static inline void glue(gen_getf_sign_, S)(T ret, T val, T len, \ - T offset, T byte) \ - { \ - T z = glue(tcg_const_, S)(0); \ - T ones = glue(tcg_const_, S)(-1); \ - T t0 = glue(tcg_temp_new_, S)(); \ - T t1 = glue(tcg_temp_new_, S)(); \ - T t2 = glue(tcg_temp_new_, S)(); \ - T t3 = glue(tcg_temp_new_, S)(); \ - T t4 = glue(tcg_temp_new_, S)(); \ - T t5 = glue(tcg_temp_new_, S)(); \ - T t6 = glue(tcg_temp_new_, S)(); \ - T t7 = glue(tcg_temp_new_, S)(); \ - /* sign = (x >> (byte * 8 + ((offset + len - 1) & 7))) & 1 */ \ - glue(tcg_gen_add_, S)(t0, offset, len); \ - glue(tcg_gen_subi_, S)(t1, t0, 1); \ - glue(tcg_gen_andi_, S)(t2, t1, 7); \ - glue(tcg_gen_muli_, S)(t3, byte, 8); \ - glue(tcg_gen_add_, S)(t4, t3, t2); \ - glue(tcg_gen_shr_, S)(t5, val, t4); \ - glue(tcg_gen_andi_, S)(t6, t5, 1); \ - glue(tcg_gen_shl_, S)(t7, ones, len); \ - glue(tcg_gen_movcond_, S)(TCG_COND_NE, ret, t6, z, t7, z); \ - glue(tcg_temp_free_, S)(t7); \ - glue(tcg_temp_free_, S)(t6); \ - glue(tcg_temp_free_, S)(t5); \ - glue(tcg_temp_free_, S)(t4); \ - glue(tcg_temp_free_, S)(t3); \ - glue(tcg_temp_free_, S)(t2); \ - glue(tcg_temp_free_, S)(t1); \ - glue(tcg_temp_free_, S)(t0); \ - glue(tcg_temp_free_, S)(ones); \ - glue(tcg_temp_free_, S)(z); \ - } - -IMPL_GEN_GETF_SIGN(i64, TCGv_i64) -IMPL_GEN_GETF_SIGN(i32, TCGv_i32) - -#define IMPL_GEN_GETF(NAME, S, T, OFFSET, LEN, BYTE, N) \ - static inline void NAME(T ret, T src1, T src2) \ - { \ - T z = glue(tcg_const_, S)(0); \ - T offset = glue(tcg_temp_new_, S)(); \ - T len = glue(tcg_temp_new_, S)(); \ - T sign = glue(tcg_temp_new_, S)(); \ - T byte = glue(tcg_temp_new_, S)(); \ - T t0 = glue(tcg_temp_new_, S)(); \ - T t1 = glue(tcg_temp_new_, S)(); \ - T t2 = glue(tcg_temp_new_, S)(); \ - T t3 = glue(tcg_temp_new_, S)(); \ - T t4 = glue(tcg_temp_new_, S)(); \ - glue(tcg_gen_extract_, S)(offset, src2, 0, OFFSET); \ - glue(tcg_gen_extract_, S)(len, src2, 6, LEN); \ - glue(tcg_gen_extract_, S)(sign, src2, 12, 1); \ - glue(tcg_gen_extract_, S)(byte, src2, 13, BYTE); \ - glue(tcg_gen_rotr_, S)(t0, src1, offset); \ - glue(gen_mask_, S)(t1, len); \ - glue(tcg_gen_and_, S)(t2, t0, t1); \ - glue(gen_getf_sign_, S)(t3, src1, len, offset, byte); \ - glue(tcg_gen_or_, S)(t4, t3, t2); \ - glue(tcg_gen_movcond_, S)(TCG_COND_NE, ret, sign, z, t4, t2); \ - glue(tcg_temp_free_, S)(t4); \ - glue(tcg_temp_free_, S)(t3); \ - glue(tcg_temp_free_, S)(t2); \ - glue(tcg_temp_free_, S)(t1); \ - glue(tcg_temp_free_, S)(t0); \ - glue(tcg_temp_free_, S)(byte); \ - glue(tcg_temp_free_, S)(sign); \ - glue(tcg_temp_free_, S)(len); \ - glue(tcg_temp_free_, S)(offset); \ - glue(tcg_temp_free_, S)(z); \ - } - -IMPL_GEN_GETF(gen_getf_i64, i64, TCGv_i64, 6, 6, 3, 64) -IMPL_GEN_GETF(gen_getf_i32, i32, TCGv_i32, 5, 5, 2, 32) - -#define gen_getfd gen_getf_i64 -#define gen_getfs gen_getf_i32 - -static void gen_bitrevs(TCGv_i32 ret, TCGv_i32 src1) { - TCGv_i32 ltemp0 = tcg_temp_new_i32(); - TCGv_i32 rtemp0 = tcg_temp_new_i32(); - TCGv_i32 ltemp1 = tcg_temp_new_i32(); - TCGv_i32 rtemp1 = tcg_temp_new_i32(); - - tcg_gen_bswap32_i32(ret, src1); - - tcg_gen_andi_i32(ltemp0, ret, 0xf0f0f0f0); - tcg_gen_andi_i32(rtemp0, ret, 0x0f0f0f0f); - tcg_gen_shri_i32(ltemp1, ltemp0, 4); - tcg_gen_shli_i32(rtemp1, rtemp0, 4); - tcg_gen_or_i32(ret, ltemp1, rtemp1); - - tcg_gen_andi_i32(ltemp0, ret, 0xcccccccc); - tcg_gen_andi_i32(rtemp0, ret, 0x33333333); - tcg_gen_shri_i32(ltemp1, ltemp0, 2); - tcg_gen_shli_i32(rtemp1, rtemp0, 2); - tcg_gen_or_i32(ret, ltemp1, rtemp1); - - tcg_gen_andi_i32(ltemp0, ret, 0xaaaaaaaa); - tcg_gen_andi_i32(rtemp0, ret, 0x55555555); - tcg_gen_shri_i32(ltemp1, ltemp0, 1); - tcg_gen_shli_i32(rtemp1, rtemp0, 1); - tcg_gen_or_i32(ret, ltemp1, rtemp1); - - tcg_temp_free_i32(rtemp1); - tcg_temp_free_i32(ltemp1); - tcg_temp_free_i32(rtemp0); - tcg_temp_free_i32(ltemp0); -} - -static void gen_bitrevd(TCGv_i64 ret, TCGv_i64 src1) { - TCGv_i64 ltemp0 = tcg_temp_new_i64(); - TCGv_i64 rtemp0 = tcg_temp_new_i64(); - TCGv_i64 ltemp1 = tcg_temp_new_i64(); - TCGv_i64 rtemp1 = tcg_temp_new_i64(); - - tcg_gen_bswap64_i64(ret, src1); - - tcg_gen_andi_i64(ltemp0, ret, 0xf0f0f0f0f0f0f0f0); - tcg_gen_andi_i64(rtemp0, ret, 0x0f0f0f0f0f0f0f0f); - tcg_gen_shri_i64(ltemp1, ltemp0, 4); - tcg_gen_shli_i64(rtemp1, rtemp0, 4); - tcg_gen_or_i64(ret, ltemp1, rtemp1); - - tcg_gen_andi_i64(ltemp0, ret, 0xcccccccccccccccc); - tcg_gen_andi_i64(rtemp0, ret, 0x3333333333333333); - tcg_gen_shri_i64(ltemp1, ltemp0, 2); - tcg_gen_shli_i64(rtemp1, rtemp0, 2); - tcg_gen_or_i64(ret, ltemp1, rtemp1); - - tcg_gen_andi_i64(ltemp0, ret, 0xaaaaaaaaaaaaaaaa); - tcg_gen_andi_i64(rtemp0, ret, 0x5555555555555555); - tcg_gen_shri_i64(ltemp1, ltemp0, 1); - tcg_gen_shli_i64(rtemp1, rtemp0, 1); - tcg_gen_or_i64(ret, ltemp1, rtemp1); - - tcg_temp_free_i64(rtemp1); - tcg_temp_free_i64(ltemp1); - tcg_temp_free_i64(rtemp0); - tcg_temp_free_i64(ltemp0); -} - -static void gen_lzcnts(TCGv_i32 ret, TCGv_i32 src1) { - tcg_gen_clzi_i32(ret, src1, 32); -} - -static void gen_lzcntd(TCGv_i64 ret, TCGv_i64 src1) { - tcg_gen_clzi_i64(ret, src1, 64); -} - -static void gen_sm_i32(bool sm, TCGv_i32 ret, TCGv_i32 ret_tag, Exception excp) -{ - if (sm) { - tcg_gen_movi_i32(ret_tag, E2K_TAG_NON_NUMBER32); - tcg_gen_movi_i32(ret, 0); - } else { - gen_exception(excp); - } -} - -static void gen_brchecki_i32(bool sm, TCGv_i32 ret, TCGv_i32 ret_tag, - TCGCond cond, TCGv_i32 arg0, uint32_t arg1, TCGLabel *l, Exception excp) -{ - TCGLabel *l0 = gen_new_label(); - tcg_gen_brcondi_i32(cond, arg0, arg1, l0); - gen_sm_i32(sm, ret, ret_tag, excp); - tcg_gen_br(l); - gen_set_label(l0); -} - -static void gen_brchecki_i32_i64(bool sm, TCGv_i32 ret, TCGv_i32 ret_tag, - TCGCond cond, TCGv_i64 arg0, uint64_t arg1, TCGLabel *l, Exception excp) -{ - TCGLabel *l0 = gen_new_label(); - tcg_gen_brcondi_i64(cond, arg0, arg1, l0); - gen_sm_i32(sm, ret, ret_tag, excp); - tcg_gen_br(l); - gen_set_label(l0); -} - -#define GEN_OP_DIVX(name, op, checks) \ - static void glue(gen_, name)(TCGv_i32 ret, TCGv_i32 ret_tag, TCGv_i32 tag, \ - TCGv_i64 src1, TCGv_i32 src2, bool sm) { \ - TCGLabel *l0 = gen_new_label(); \ - TCGv_i64 t0 = tcg_temp_new_i64(); \ - TCGv_i64 t1 = tcg_temp_local_new_i64(); \ - gen_brchecki_i32(sm, ret, ret_tag, \ - TCG_COND_NE, src2, 0, l0, EXCP_DIV); \ - tcg_gen_extu_i32_i64(t0, src2); \ - op(t1, src1, t0); \ - checks \ - tcg_gen_extrl_i64_i32(ret, t1); \ - gen_set_label(l0); \ - tcg_temp_free_i64(t1); \ - tcg_temp_free_i64(t0); \ - } - -GEN_OP_DIVX(udivx, tcg_gen_divu_i64, { \ - gen_brchecki_i32_i64(sm, ret, ret_tag, \ - TCG_COND_LEU, t1, UINT32_MAX, l0, EXCP_DIV); \ -}) -GEN_OP_DIVX(sdivx, tcg_gen_div_i64, { \ - gen_brchecki_i32_i64(sm, ret, ret_tag, \ - TCG_COND_LE, t1, INT32_MAX, l0, EXCP_DIV); \ - gen_brchecki_i32_i64(sm, ret, ret_tag, \ - TCG_COND_GE, t1, INT32_MIN, l0, EXCP_DIV); \ -}) - -#define GEN_OP_MODX(name, op) \ - static void glue(gen_, name)(TCGv_i32 ret, TCGv_i32 tag, TCGv_i32 ret_tag, \ - TCGv_i64 src1, TCGv_i32 src2, bool sm) { \ - TCGLabel *l0 = gen_new_label(); \ - TCGv_i64 t0 = tcg_temp_new_i64(); \ - TCGv_i64 t1 = tcg_temp_new_i64(); \ - gen_brchecki_i32(sm, ret, ret_tag, \ - TCG_COND_NE, src2, 0, l0, EXCP_DIV); \ - tcg_gen_extu_i32_i64(t0, src2); \ - /* FIXME: must gen exception/tag on overflow */ \ - op(t1, src1, t0); \ - tcg_gen_extrl_i64_i32(ret, t1); \ - gen_set_label(l0); \ - tcg_temp_free_i64(t1); \ - tcg_temp_free_i64(t0); \ - } - -GEN_OP_MODX(umodx, tcg_gen_remu_i64) -GEN_OP_MODX(smodx, tcg_gen_rem_i64) - -static inline void gen_cmp_i64(TCGv_i64 ret, int opc, TCGv_i64 src1, - TCGv_i64 src2) -{ - switch(opc) { - case 0: { /* cmpodb */ - TCGv_i64 s2 = 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(); - - tcg_gen_not_i64(s2, src2); - tcg_gen_sub_i64(t0, src1, src2); - tcg_gen_xor_i64(t1, src1, t0); - tcg_gen_xor_i64(t2, s2, t0); - tcg_gen_and_i64(t3, t1, t2); - tcg_gen_setcondi_i64(TCG_COND_LT, ret, t3, 0); - - tcg_temp_free_i64(t3); - tcg_temp_free_i64(t2); - tcg_temp_free_i64(t1); - tcg_temp_free_i64(t0); - tcg_temp_free_i64(s2); - break; - } - case 1: /* cmpbdb */ - tcg_gen_setcond_i64(TCG_COND_LTU, ret, src1, src2); - break; - case 2: /* cmpedb */ - tcg_gen_setcond_i64(TCG_COND_EQ, ret, src1, src2); - break; - case 3: /* cmpbedb */ - tcg_gen_setcond_i64(TCG_COND_LEU, ret, src1, src2); - break; - case 4: { /* cmpsdb */ - TCGv_i64 t0 = tcg_temp_new_i64(); - - tcg_gen_sub_i64(t0, src1, src2); - tcg_gen_setcondi_i64(TCG_COND_LT, ret, t0, 0); - tcg_temp_free_i64(t0); - break; - } - case 5: { /* cmppdb */ - TCGv_i64 t0 = tcg_temp_new_i64(); - TCGv_i64 t1 = tcg_temp_new_i64(); - TCGv_i64 t2 = tcg_temp_new_i64(); - - tcg_gen_sub_i64(t0, src1, src2); - tcg_gen_ctpop_i64(t1, t0); - tcg_gen_andi_i64(t2, t1, 1); - tcg_gen_setcondi_i64(TCG_COND_EQ, ret, t2, 0); - - tcg_temp_free_i64(t2); - tcg_temp_free_i64(t1); - tcg_temp_free_i64(t0); - break; - } - case 6: /* cmpldb */ - tcg_gen_setcond_i64(TCG_COND_LT, ret, src1, src2); - break; - case 7: /* cmpledb */ - tcg_gen_setcond_i64(TCG_COND_LE, ret, src1, src2); - break; - default: - g_assert_not_reached(); - break; - } -} - -static inline void gen_cmp_i32(TCGv_i32 ret, int opc, TCGv_i32 src1, - TCGv_i32 src2) -{ - switch(opc) { - case 0: { /* cmposb */ - TCGv_i32 s2 = 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(); - - tcg_gen_not_i32(s2, src2); - tcg_gen_sub_i32(t0, src1, src2); - tcg_gen_xor_i32(t1, src1, t0); - tcg_gen_xor_i32(t2, s2, t0); - tcg_gen_and_i32(t3, t1, t2); - tcg_gen_setcondi_i32(TCG_COND_LT, ret, t3, 0); - - tcg_temp_free_i32(t3); - tcg_temp_free_i32(t2); - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t0); - tcg_temp_free_i32(s2); - break; - } - case 1: /* cmpbsb */ - tcg_gen_setcond_i32(TCG_COND_LTU, ret, src1, src2); - break; - case 2: /* cmpesb */ - tcg_gen_setcond_i32(TCG_COND_EQ, ret, src1, src2); - break; - case 3: /* cmpbesb */ - tcg_gen_setcond_i32(TCG_COND_LEU, ret, src1, src2); - break; - case 4: { /* cmpssb */ - TCGv_i32 t0 = tcg_temp_new_i32(); - - tcg_gen_sub_i32(t0, src1, src2); - tcg_gen_setcondi_i32(TCG_COND_LT, ret, t0, 0); - tcg_temp_free_i32(t0); - break; - } - case 5: { /* cmppsb */ - TCGv_i32 t0 = tcg_temp_new_i32(); - TCGv_i32 t1 = tcg_temp_new_i32(); - TCGv_i32 t2 = tcg_temp_new_i32(); - - tcg_gen_sub_i32(t0, src1, src2); - tcg_gen_ctpop_i32(t1, t0); - tcg_gen_andi_i32(t2, t1, 1); - tcg_gen_setcondi_i32(TCG_COND_EQ, ret, t2, 0); - - tcg_temp_free_i32(t2); - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t0); - break; - } - case 6: /* cmplsb */ - tcg_gen_setcond_i32(TCG_COND_LT, ret, src1, src2); - break; - case 7: /* cmplesb */ - tcg_gen_setcond_i32(TCG_COND_LE, ret, src1, src2); - break; - default: - g_assert_not_reached(); - break; - } -} - -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: /* cmpandedb */ - tcg_gen_setcondi_i64(TCG_COND_EQ, ret, t0, 0); - break; - case 4: /* cmpandsdb */ - tcg_gen_setcondi_i64(TCG_COND_LT, ret, t0, 0); - break; - case 5: { /* cmpandpdb */ - TCGv_i64 t1 = tcg_temp_new_i64(); - TCGv_i64 t2 = tcg_temp_new_i64(); - - tcg_gen_ctpop_i64(t1, t0); - tcg_gen_andi_i64(t2, t1, 1); - tcg_gen_setcondi_i64(TCG_COND_EQ, ret, t2, 0); - - tcg_temp_free_i64(t2); - tcg_temp_free_i64(t1); - break; - } - case 7: /* cmpandledb */ - tcg_gen_setcondi_i64(TCG_COND_LE, ret, t0, 0); - break; - default: - g_assert_not_reached(); - 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: /* cmpandesb */ - tcg_gen_setcondi_i32(TCG_COND_EQ, ret, t0, 0); - break; - case 4: /* cmpandssb */ - tcg_gen_setcondi_i32(TCG_COND_LT, ret, t0, 0); - break; - case 5: { /* cmpandpsb */ - TCGv_i32 t1 = tcg_temp_new_i32(); - TCGv_i32 t2 = tcg_temp_new_i32(); - - tcg_gen_ctpop_i32(t1, t0); - tcg_gen_andi_i32(t2, t1, 1); - tcg_gen_setcondi_i32(TCG_COND_EQ, ret, t2, 0); - - tcg_temp_free_i32(t2); - tcg_temp_free_i32(t1); - break; - } - case 7: /* cmpandlesb */ - tcg_gen_setcondi_i32(TCG_COND_LE, ret, t0, 0); - break; - default: - g_assert_not_reached(); - break; - } - - tcg_temp_free_i32(t0); -} - -#define WRAP_FCMP_HELPER_(helper, type) \ - static void glue(gen_, helper)(type ret, type src1, type src2) \ - { \ - glue(gen_helper_, helper)(ret, cpu_env, src1, src2); \ - } -#define WRAP_FCMP_HELPER(op) \ - WRAP_FCMP_HELPER_(glue(op, s), TCGv_i32) \ - WRAP_FCMP_HELPER_(glue(op, d), TCGv_i64) -/* FIXME: currently unused but will be -WRAP_FCMP_HELPER(fcmpeq) -WRAP_FCMP_HELPER(fcmplt) -WRAP_FCMP_HELPER(fcmple) -WRAP_FCMP_HELPER(fcmpuod) -WRAP_FCMP_HELPER(fcmpneq) -WRAP_FCMP_HELPER(fcmpnlt) -WRAP_FCMP_HELPER(fcmpnle) -WRAP_FCMP_HELPER(fcmpod) -*/ -#undef WRAP_FCMP_HELPER -#undef WRAP_FCMP_HELPER_ - -#define glue4(a, b, c, d) glue(glue(a, b), glue(c, d)) - -#define GENERATE_FCMP_SWITCH_TABLE(f, opc, b, pre, suf, post) \ - switch((opc)) { \ - case b + 0: /* eq */ \ - f = glue4(pre, suf, cmpeq, post); \ - break; \ - case b + 1: /* lt */ \ - f = glue4(pre, suf, cmplt, post); \ - break; \ - case b + 2: /* le */ \ - f = glue4(pre, suf, cmple, post); \ - break; \ - case b + 3: /* uod */ \ - f = glue4(pre, suf, cmpuod, post); \ - break; \ - case b + 4: /* neq */ \ - f = glue4(pre, suf, cmpneq, post); \ - break; \ - case b + 5: /* nlt */ \ - f = glue4(pre, suf, cmpnlt, post); \ - break; \ - case b + 6: /* nle */ \ - f = glue4(pre, suf, cmpnle, post); \ - break; \ - case b + 7: /* od */ \ - f = glue4(pre, suf, cmpod, post); \ - break; \ - default: \ - g_assert_not_reached(); \ - break; \ - } - -static void gen_fcmp_i32(TCGv_i32 ret, int opc, TCGv_i32 src1, TCGv_i32 src2) -{ - void (*f)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32) = 0; - TCGv_i32 dst = tcg_temp_new_i32(); - - GENERATE_FCMP_SWITCH_TABLE(f, opc, 0, gen_helper_, f, s) - - (*f)(dst, cpu_env, src1, src2); - tcg_gen_setcondi_i32(TCG_COND_NE, ret, dst, 0); - - tcg_temp_free_i32(dst); -} - -static void gen_fcmp_i64(TCGv_i64 ret, int opc, TCGv_i64 src1, TCGv_i64 src2) -{ - void (*f)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64) = 0; - TCGv_i64 dst = tcg_temp_new_i64(); - - GENERATE_FCMP_SWITCH_TABLE(f, opc, 0, gen_helper_, f, d) - - (*f)(dst, cpu_env, src1, src2); - tcg_gen_setcondi_i64(TCG_COND_NE, ret, dst, 0); - - tcg_temp_free_i64(dst); -} - -static void gen_fcmp_f80(TCGv_i64 ret, int opc, Src80 src1, Src80 src2) -{ - void (*f)(TCGv_i64, TCGv_env, TCGv_ptr, TCGv_ptr) = 0; - TCGv_i64 dst = tcg_temp_new_i64(); - TCGv_ptr t0 = tcg_temp_new_ptr(); - TCGv_ptr t1 = tcg_temp_new_ptr(); - - tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, t0.f80)); - tcg_gen_addi_ptr(t1, cpu_env, offsetof(CPUE2KState, t1.f80)); - - gen_temp_reg_write_i64_i32(src1.lo, src1.hi, t0); - gen_temp_reg_write_i64_i32(src2.lo, src2.hi, t1); - - GENERATE_FCMP_SWITCH_TABLE(f, opc, 0, gen_helper_, fx, x) - - (*f)(dst, cpu_env, t0, t1); - - tcg_gen_setcondi_i64(TCG_COND_NE, ret, dst, 0); - - tcg_temp_free_ptr(t1); - tcg_temp_free_ptr(t0); - tcg_temp_free_i64(dst); -} - -static inline void gen_merge_i32(TCGv_i32 ret, TCGv_i32 src1, TCGv_i32 src2, - TCGv_i32 cond) -{ - TCGv_i32 zero = tcg_const_i32(0); - tcg_gen_movcond_i32(TCG_COND_EQ, ret, cond, zero, src1, src2); - tcg_temp_free_i32(zero); -} - -static inline void gen_merge_i64(TCGv_i64 ret, TCGv_i64 src1, TCGv_i64 src2, - TCGv_i32 cond) -{ - TCGv_i64 zero = tcg_const_i64(0); - TCGv_i64 t0 = tcg_temp_new_i64(); - - tcg_gen_extu_i32_i64(t0, cond); - tcg_gen_movcond_i64(TCG_COND_EQ, ret, t0, zero, src1, src2); - - tcg_temp_free_i64(t0); - tcg_temp_free_i64(zero); -} - -static inline void gen_udivd(TCGv_i64 ret, TCGv_i32 ret_tag, TCGv_i32 tag, - TCGv_i64 src1, TCGv_i64 src2) -{ - TCGLabel *l0 = gen_new_label(); - 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_mov_i32(ret_tag, tag); - tcg_gen_divu_i64(ret, src1, src2); - gen_set_label(l0); -} - -static inline void gen_udivs(TCGv_i32 ret, TCGv_i32 ret_tag, TCGv_i32 tag, - TCGv_i32 src1, TCGv_i32 src2) -{ - TCGLabel *l0 = gen_new_label(); - 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_mov_i32(ret_tag, tag); - tcg_gen_divu_i32(ret, src1, src2); - gen_set_label(l0); -} - -#define IMPL_GEN_SDIV(name, S, T, bad_tag) \ - static inline void name(T ret, TCGv_i32 ret_tag, \ - TCGv_i32 tag, T src1, T src2) \ - { \ - TCGLabel *l0 = gen_new_label(); \ - TCGLabel *l1 = gen_new_label(); \ - T t0 = glue(tcg_temp_new_i, S)(); \ - T t1 = glue(tcg_temp_new_i, S)(); \ - T t2 = glue(tcg_temp_new_i, S)(); \ - T t3 = glue(tcg_temp_new_i, S)(); \ - T t4 = glue(tcg_temp_new_i, S)(); \ - \ - glue(tcg_gen_brcondi_i, S)(TCG_COND_NE, src2, 0, l1); \ - /* src2 is zero */ \ - tcg_gen_movi_i32(ret_tag, bad_tag); \ - glue(tcg_gen_movi_i, S)(ret, 0); \ - tcg_gen_br(l0); \ - \ - /* src2 is not zero */ \ - gen_set_label(l1); \ - glue(tcg_gen_setcondi_i, S)(TCG_COND_EQ, t0, src1, 1ULL << (S - 1)); \ - glue(tcg_gen_setcondi_i, S)(TCG_COND_EQ, t1, src2, -1); \ - glue(tcg_gen_and_i, S)(t2, t0, t1); \ - glue(tcg_gen_movi_i, S)(t3, 0); \ - glue(tcg_gen_movcond_i, S)(TCG_COND_NE, t4, t2, t3, t2, src2); \ - \ - tcg_gen_mov_i32(ret_tag, tag); \ - glue(tcg_gen_div_i, S)(ret, src1, t4); \ - \ - gen_set_label(l0); \ - \ - glue(tcg_temp_free_i, S)(t4); \ - glue(tcg_temp_free_i, S)(t3); \ - glue(tcg_temp_free_i, S)(t2); \ - glue(tcg_temp_free_i, S)(t1); \ - glue(tcg_temp_free_i, S)(t0); \ - } - -IMPL_GEN_SDIV(gen_sdivd, 64, TCGv_i64, E2K_TAG_NON_NUMBER64) -IMPL_GEN_SDIV(gen_sdivs, 32, TCGv_i32, E2K_TAG_NON_NUMBER32) - -static inline void gen_gettag_i64(Instr *instr) -{ - Src64 s2 = get_src2_i64(instr); - TCGv_i64 dst = get_temp_i64(instr); - - if (s2.tag != NULL) { - tcg_gen_extu_i32_i64(dst, s2.tag); - } else { - tcg_gen_movi_i64(dst, 0); - } - - set_al_result_reg64(instr, dst); -} - -static inline void gen_gettag_i32(Instr *instr) -{ - Src32 s2 = get_src2_i32(instr); - TCGv_i32 dst = get_temp_i32(instr); - - if (s2.tag != NULL) { - tcg_gen_mov_i32(dst, s2.tag); - } else { - tcg_gen_movi_i32(dst, 0); - } - - set_al_result_reg32(instr, dst); -} - -static inline void gen_puttag_i64(Instr *instr) -{ - TCGLabel *l0 = gen_new_label(); - TCGLabel *l1 = gen_new_label(); - Src64 s1 = get_src1_i64(instr); - Src32 s2 = get_src2_i32(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i64 dst = get_temp_i64(instr); - - tcg_gen_mov_i64(dst, s1.value); - tcg_gen_brcondi_i32(TCG_COND_EQ, s2.value, 0, l0); - gen_tag2_i64(tag, s1.tag, s2.tag); - tcg_gen_brcondi_i32(TCG_COND_EQ, tag, 0, l0); - gen_tag_check(instr, tag); - gen_dst_poison_i64(dst, dst, tag); - tcg_gen_br(l1); - gen_set_label(l0); - tcg_gen_mov_i32(tag, s2.value); - gen_set_label(l1); - set_al_result_reg64_tag(instr, dst, tag, false); -} - -static inline void gen_puttag_i32(Instr *instr) -{ - TCGLabel *l0 = gen_new_label(); - TCGLabel *l1 = gen_new_label(); - Src32 s1 = get_src1_i32(instr); - Src32 s2 = get_src2_i32(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i32 dst = get_temp_i32(instr); - - tcg_gen_mov_i32(dst, s1.value); - tcg_gen_brcondi_i32(TCG_COND_EQ, s2.value, 0, l0); - gen_tag2_i32(tag, s1.tag, s2.tag); - tcg_gen_brcondi_i32(TCG_COND_EQ, tag, 0, l0); - gen_tag_check(instr, tag); - gen_dst_poison_i32(dst, dst, tag); - tcg_gen_br(l1); - gen_set_label(l0); - tcg_gen_mov_i32(tag, s2.value); - gen_set_label(l1); - set_al_result_reg32_tag(instr, dst, tag, false, false, true); -} - -static inline void gen_insfd_tag_mask(TCGv_i32 ret, TCGv_i32 flags, - TCGv_i32 tag, int offset) -{ - TCGv_i32 z = tcg_const_i32(0); - TCGv_i32 t0 = tcg_temp_new_i32(); - TCGv_i32 t1 = tcg_temp_new_i32(); - tcg_gen_andi_i32(t0, flags, 1 << offset); - tcg_gen_andi_i32(t1, tag, 0x3); - tcg_gen_movcond_i32(TCG_COND_NE, ret, t0, z, t1, tag); - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t0); - tcg_temp_free_i32(z); -} - -static inline void gen_insfd_tag(TCGv_i32 ret, TCGv_i64 value, - TCGv_i32 s1_tag, TCGv_i32 s3_tag) -{ - TCGv_i32 z = tcg_const_i32(0); - TCGv_i32 t0 = tcg_temp_new_i32(); - TCGv_i32 t1 = tcg_temp_new_i32(); - TCGv_i32 t2 = tcg_temp_new_i32(); - - tcg_gen_extrl_i64_i32(t0, value); - gen_insfd_tag_mask(t1, t0, s1_tag, 13); - gen_insfd_tag_mask(t2, t0, s3_tag, 15); - tcg_gen_or_i32(ret, t1, t2); - - tcg_temp_free_i32(t2); - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t0); - tcg_temp_free_i32(z); -} - -static inline void gen_insfd(Instr *instr) -{ - Src64 s1 = get_src1_i64(instr); - Src64 s2 = get_src2_i64(instr); - Src64 s3 = get_src3_i64(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i64 dst = get_temp_i64(instr); - 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(); - TCGv_i32 t6 = tcg_temp_new_i32(); - - tcg_gen_extract_i64(offset, s2.value, 0, 6); - tcg_gen_extract_i64(len, s2.value, 6, 6); - tcg_gen_shl_i64(t0, one, len); - tcg_gen_subi_i64(t1, t0, 1); - tcg_gen_rotr_i64(t2, s1.value, offset); - tcg_gen_not_i64(t3, t1); - tcg_gen_and_i64(t4, t2, t3); - tcg_gen_and_i64(t5, s3.value, t1); - tcg_gen_or_i64(dst, t4, t5); - - gen_insfd_tag(t6, s2.value, s1.tag, s3.tag); - gen_tag2_i64(tag, s2.tag, t6); - gen_al_result_i64(instr, dst, tag); - - tcg_temp_free_i32(t6); - 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_insfs(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_umulx(TCGv_i64 ret, TCGv_i32 src1, TCGv_i32 src2) -{ - TCGv_i32 l = tcg_temp_new_i32(); - TCGv_i32 h = tcg_temp_new_i32(); - - tcg_gen_mulu2_i32(l, h, src1, src2); - tcg_gen_concat_i32_i64(ret, l, h); - - tcg_temp_free_i32(h); - tcg_temp_free_i32(l); -} - -static inline void gen_smulx(TCGv_i64 ret, TCGv_i32 src1, TCGv_i32 src2) -{ - TCGv_i32 l = tcg_temp_new_i32(); - TCGv_i32 h = tcg_temp_new_i32(); - - tcg_gen_muls2_i32(l, h, src1, src2); - tcg_gen_concat_i32_i64(ret, l, h); - - tcg_temp_free_i32(h); - tcg_temp_free_i32(l); -} - -static inline void gen_umulhd(TCGv_i64 ret, TCGv_i64 src1, TCGv_i64 src2) -{ - TCGv_i64 t0 = tcg_temp_new_i64(); - tcg_gen_mulu2_i64(t0, ret, src1, src2); - tcg_temp_free_i64(t0); -} - -static inline void gen_smulhd(TCGv_i64 ret, TCGv_i64 src1, TCGv_i64 src2) -{ - TCGv_i64 t0 = tcg_temp_new_i64(); - tcg_gen_muls2_i64(t0, ret, src1, src2); - tcg_temp_free_i64(t0); -} - -static inline void gen_rr_i64(Instr *instr) -{ - TCGv_i64 dst = get_temp_i64(instr); - TCGv_i32 t0 = tcg_const_i32(instr->src1); - - gen_save_cpu_state(instr->ctx); - gen_helper_state_reg_read_i64(dst, cpu_env, t0); - set_al_result_reg64(instr, dst); - tcg_temp_free_i32(t0); -} - -static inline void gen_rr_i32(Instr *instr) -{ - TCGv_i32 dst = get_temp_i32(instr); - TCGv_i32 t0 = tcg_const_i32(instr->src1); - - gen_save_cpu_state(instr->ctx); - // FIXME: output size should be affected by wdbl - gen_helper_state_reg_read_i32(dst, cpu_env, t0); - set_al_result_reg32(instr, dst); - tcg_temp_free_i32(t0); -} - -static inline void gen_rw_i64(Instr *instr) -{ - Src64 s2 = get_src2_i64(instr); - TCGv_i32 t0 = tcg_const_i32(instr->dst); - - gen_tag_check(instr, s2.tag); - gen_helper_state_reg_write_i64(cpu_env, t0, s2.value); - tcg_temp_free_i32(t0); -} - -static inline void gen_rw_i32(Instr *instr) -{ - Src32 s2 = get_src2_i32(instr); - TCGv_i32 t0 = tcg_const_i32(instr->dst); - - gen_tag_check(instr, s2.tag); - gen_helper_state_reg_write_i32(cpu_env, t0, s2.value); - tcg_temp_free_i32(t0); -} - -static void gen_sxt(DisasContext *ctx, Instr *instr) -{ - Src64 s1 = get_src1_i64(instr); - Src32 s2 = get_src2_i32(instr); - TCGv_i32 tag = e2k_get_temp_i32(ctx); - TCGv_i64 dst = e2k_get_temp_i64(ctx); - - gen_tag2_i64(tag, s1.tag, s2.tag); - gen_helper_sxt(dst, s1.value, s2.value); - gen_al_result_i64(instr, dst, tag); -} - -static void gen_getsp(DisasContext *ctx, Instr *instr) -{ - Src32 s2 = get_src2_i32(instr); - TCGv_i32 tag = e2k_get_temp_i32(ctx); - TCGv_i64 dst = e2k_get_temp_i64(ctx); - - gen_tag1_i64(tag, s2.tag); - gen_helper_getsp(dst, cpu_env, s2.value); - gen_al_result_i64(instr, dst, tag); -} - -static void gen_movts(Instr *instr) -{ - Src32 s2 = get_src2_i32(instr); - set_al_result_reg32_tag(instr, s2.value, s2.tag, false, false, false); -} - -static void gen_movtcs(Instr *instr) -{ - Src32 s2 = get_src2_i32(instr); - gen_tag_check(instr, s2.tag); - set_al_result_reg32_tag(instr, s2.value, s2.tag, false, false, false); -} - -static void gen_movtd(Instr *instr) -{ - Src64 s2 = get_src2_i64(instr); - set_al_result_reg64_tag(instr, s2.value, s2.tag, false); -} - -static void gen_movtcd(Instr *instr) -{ - Src64 s2 = get_src2_i64(instr); - gen_tag_check(instr, s2.tag); - set_al_result_reg64_tag(instr, s2.value, s2.tag, false); -} - -static void gen_movtq_inner(Instr *instr, Src64 src) -{ - if (check_qr(instr->src2, instr->chan) && check_qr(instr->dst, instr->chan)) { - set_al_result_reg64_tag(instr, src.value, src.tag, false); - } else { - gen_tr_excp_illopn(instr->ctx); - } -} - -static void gen_movtq(Instr *instr) -{ - gen_movtq_inner(instr, get_src2_i64(instr)); -} - -static void gen_movtcq(Instr *instr) -{ - Src64 s2 = get_src2_i64(instr); - gen_tag_check(instr, s2.tag); - gen_movtq_inner(instr, s2); -} - -static void gen_getpl(Instr *instr) -{ -#ifdef TARGET_E2K32 - Src32 s2 = get_src2_i32(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i64 dst = get_temp_i64(instr); - - // TODO: CUD - gen_tag1_i64(tag, s2.tag); - tcg_gen_extu_i32_i64(dst, s2.value); - set_al_result_reg64_tag(instr, dst, tag, true); -#else /* !TARGET_E2K32 */ - // TODO: getpl 64-bit - e2k_todo_illop(instr->ctx, "getpl"); -#endif -} - -static inline bool gen_ld_mas_mod(DisasContext *ctx, Instr *instr, uint8_t mod) -{ - switch (mod) { - case 3: - if (is_chan_25(instr->chan)) { - // TODO: DAM - /* always go to fixing code */ - if (ctx->mlock) { - tcg_gen_movi_i32(ctx->mlock, 1); - } - return true; - } - break; - case 4: - if (instr->sm && is_chan_03(instr->chan)) { - // TODO: DAM - /* always ignore lock load */ - return false; - } else if (!instr->sm && (is_chan_25(instr->chan) || is_chan_03(instr->chan))) { - // TODO - return true; - } - break; - } - - e2k_todo(ctx, "opc %#x, chan %d, mod=%#x", instr->opc1, instr->chan, mod); - return true; -} - -static MemOp gen_mas(Instr *instr, MemOp memop) -{ - DisasContext *ctx = instr->ctx; - uint8_t mas = instr->mas; - - if ((mas & 0x7) == 7) { - int opc = mas >> 3; - // TODO: special mas - switch (opc) { - case 0: - /* handled in a gen_ld_mas */ - // TODO: only chan 0? - return memop | MO_LE; - case 3: - if (!instr->sm && is_chan_25(instr->chan)) { - // TODO: unknown store MAS OPC 0x3 - return 0; - } - break; - } - e2k_todo(ctx, "opc %#x, chan %d, mas=%#x (opc %#x)", instr->opc1, - instr->chan, mas, opc); - return 0; - } else if (mas) { - int mod = extract8(mas, 0, 3); -// int dc = extract8(mas, 5, 2); - - if (mod != 0) { - if (0x64 <= instr->opc1 && instr->opc1 < 0x68) { - if (!gen_ld_mas_mod(ctx, instr, mod)) { - return 0; - } - } else { - switch (mod) { - case 2: - /* handled in a gen_st */ - // TODO: only chan 2? - break; - default: - e2k_todo(ctx, "opc %#x, chan %d, mas=%#x, mod=%#x", instr->opc1, - instr->chan, mas, mod); - break; - } - } - } - - 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_tl(Instr *instr, TCGv_i64 ret, TCGv_i32 ret_tag, TCGv addr, - MemOp memop) -{ - if (instr->sm) { - TCGLabel *l0 = gen_new_label(); - TCGLabel *l1 = gen_new_label(); - TCGv t0 = tcg_temp_local_new(); - TCGv_i32 t1 = tcg_temp_new_i32(); - - tcg_gen_mov_tl(t0, addr); - gen_helper_probe_read_access(t1, cpu_env, t0); - tcg_gen_brcondi_i32(TCG_COND_EQ, t1, 1, l0); - - /* address is not available */ - tcg_gen_movi_i32(ret_tag, E2K_TAG_NON_NUMBER64); - tcg_gen_movi_i64(ret, E2K_LD_RESULT_INVALID); - tcg_gen_br(l1); - - /* address is available */ - gen_set_label(l0); - tcg_gen_qemu_ld_i64(ret, t0, instr->ctx->mmuidx, memop); - - gen_set_label(l1); - - tcg_temp_free_i32(t1); - tcg_temp_free(t0); - } else { - tcg_gen_qemu_ld_i64(ret, addr, instr->ctx->mmuidx, memop); - } -} - -#define IMPL_GEN_LD(name, S, cast) \ - static void name(Instr *instr, TCGv_i64 ret, TCGv_i32 ret_tag, \ - MemOp memop) \ - { \ - glue(Src, S) s1 = glue(get_src1_i, S)(instr); \ - glue(Src, S) s2 = glue(get_src2_i, S)(instr); \ - glue(TCGv_i, S) t0 = glue(tcg_temp_new_i, S)(); \ - TCGv t1 = tcg_temp_local_new(); \ - \ - glue(gen_tag2_i, S)(ret_tag, s1.tag, s2.tag); \ - glue(tcg_gen_add_i, S)(t0, s1.value, s2.value); \ - cast(t1, t0); \ - gen_ld_tl(instr, ret, ret_tag, t1, memop); \ - } - -IMPL_GEN_LD(gen_ld_i64, 64, tcg_gen_trunc_i64_tl) - -#define IMPL_GEN_LD_MAS(name, load) \ - static void name(Instr *instr, MemOp memop) \ - { \ - TCGv_i32 tag = get_temp_i32(instr); \ - TCGv_i64 dst = get_temp_i64(instr); \ - \ - memop = gen_mas(instr, memop); \ - \ - if (memop == 0) { \ - /* ignore load */ \ - tcg_gen_movi_i32(tag, E2K_TAG_NON_NUMBER64); \ - tcg_gen_movi_i64(dst, E2K_LD_RESULT_INVALID); \ - } else { \ - load(instr, dst, tag, memop); \ - if (instr->chan == 0 && instr->mas == 7) { \ - /* TODO: gen illop if called twice before st/mod=2 */ \ - tcg_gen_mov_i64(e2k_cs.last_value, dst); \ - } \ - } \ - \ - gen_al_result_i64(instr, dst, tag); \ - } - -IMPL_GEN_LD_MAS(gen_ld_mas_i64, gen_ld_i64) - -#ifdef TARGET_E2K32 -// TODO: ldgd ops must use GD.base -IMPL_GEN_LD(gen_ld_i32, 32, tcg_gen_extu_i32_tl) -IMPL_GEN_LD_MAS(gen_ld_mas_i32, gen_ld_i32) -#endif - -static void gen_atomic_cmpxchg_i64(Instr *instr, TCGv_i64 value, TCGv addr, - MemOp memop) -{ - TCGv_i64 t0 = tcg_temp_new_i64(); - TCGv_i64 t1 = tcg_temp_new_i64(); - - tcg_gen_atomic_cmpxchg_i64(t0, addr, e2k_cs.last_value, value, - instr->ctx->mmuidx, memop); - tcg_gen_setcond_i64(TCG_COND_NE, t1, t0, e2k_cs.last_value); - tcg_gen_extrl_i64_i32(instr->ctx->mlock, t1); - - tcg_temp_free_i64(t1); - tcg_temp_free_i64(t0); -} - -static void gen_atomic_cmpxchg_i32(Instr *instr, TCGv_i32 value, TCGv addr, - MemOp memop) -{ - TCGv_i32 t0 = tcg_temp_new_i32(); - TCGv_i32 t1 = tcg_temp_new_i32(); - - tcg_gen_extrl_i64_i32(t0, e2k_cs.last_value); - tcg_gen_atomic_cmpxchg_i32(t1, addr, t0, value, - instr->ctx->mmuidx, memop); - tcg_gen_setcond_i32(TCG_COND_NE, instr->ctx->mlock, t1, t0); - - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t0); -} - -#define IMPL_ST(NAME, S, N, cast) \ - static void NAME(Instr *instr, MemOp memop) \ - { \ - memop = gen_mas(instr, memop); \ - \ - if (memop != 0) { \ - TCGLabel *l0 = gen_new_label(); \ - glue(Src, N) s1 = glue(get_src1_i, N)(instr); \ - glue(Src, N) s2 = glue(get_src2_i, N)(instr); \ - glue(Src, S) s4 = glue(get_src4_i, S)(instr); \ - glue(TCGv_i, N) t0 = glue(tcg_temp_new_i, N)(); \ - TCGv t1 = tcg_temp_local_new(); \ - \ - gen_loop_mode_st(instr->ctx, l0); \ - gen_tag_check(instr, s1.tag); \ - gen_tag_check(instr, s2.tag); \ - gen_tag_check(instr, s4.tag); \ - glue(tcg_gen_add_i, N)(t0, s1.value, s2.value); \ - cast(t1, t0); \ - \ - if (instr->sm) { \ - TCGv_i32 t2 = tcg_temp_new_i32(); \ - gen_helper_probe_write_access(t2, cpu_env, t1); \ - tcg_gen_brcondi_i32(TCG_COND_EQ, t2, 0, l0); \ - tcg_temp_free_i32(t2); \ - } \ - \ - if (instr->ctx->mlock && instr->chan == 2 \ - && (instr->mas & 7) == 2) \ - { \ - /* FIXME: Does an any write before the st/mod=2 leads to a branch? */ \ - glue(gen_atomic_cmpxchg_i, S)(instr, s4.value, t1, memop); \ - } else { \ - glue(tcg_gen_qemu_st_i, S)(s4.value, t1, \ - instr->ctx->mmuidx, memop); \ - } \ - gen_set_label(l0); \ - \ - tcg_temp_free(t1); \ - glue(tcg_temp_free_i, N)(t0); \ - } \ - } - -IMPL_ST(gen_st_ddd, 64, 64, tcg_gen_trunc_i64_tl) -IMPL_ST(gen_st_sdd, 32, 64, tcg_gen_trunc_i64_tl) - -// TODO: stgd ops must use GD.base -IMPL_ST(gen_st_dss, 64, 32, tcg_gen_extu_i32_tl) -IMPL_ST(gen_st_sss, 32, 32, tcg_gen_extu_i32_tl) - -static inline void gen_movfi(Instr *instr) -{ - Src80 src2 = get_src2_i80(instr); - TCGv_i32 tag = get_temp_i32(instr); - gen_tag1_i32(tag, src2.tag); - gen_al_result_i32(instr, src2.hi, tag); -} - -static inline void gen_movif(Instr *instr) -{ - Src64 src1 = get_src1_i64(instr); - Src32 src2 = get_src2_i32(instr); - TCGv_i32 tag = get_temp_i32(instr); - gen_tag2_i64(tag, src1.tag, src2.tag); - gen_al_result_i80(instr, src1.value, src2.value, tag); -} - -static inline void gen_movx(Instr *instr) -{ - Src80 src2 = get_src2_i80(instr); - TCGv_i32 tag = get_temp_i32(instr); - gen_tag1_i64(tag, src2.tag); - gen_al_result_i80(instr, src2.lo, src2.hi, tag); -} - -static inline void gen_movxa(Instr *instr) -{ - Src80 src2 = get_src2_i80(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i32 dst_hi = get_temp_i32(instr); - gen_tag1_i64(tag, src2.tag); - tcg_gen_andi_i32(dst_hi, src2.hi, 0x7fff); - gen_al_result_i80(instr, src2.lo, dst_hi, tag); -} - -static inline void gen_movxc(Instr *instr) -{ - Src80 src2 = get_src2_i80(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i32 dst_hi = get_temp_i32(instr); - gen_tag1_i64(tag, src2.tag); - tcg_gen_xori_i32(dst_hi, src2.hi, 0x8000); - gen_al_result_i80(instr, src2.lo, dst_hi, tag); -} - -static inline void gen_fstofx(Src80 *ret, TCGv_i32 src2) -{ - TCGv_ptr t0 = tcg_temp_new_ptr(); - - tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, t0.f80)); - gen_helper_fstofx(t0, cpu_env, src2); - gen_temp_reg_read_i64_i32(t0, ret->lo, ret->hi); - tcg_temp_free_ptr(t0); -} - -static inline void gen_istofx(Src80 *ret, TCGv_i32 src2) -{ - TCGv_ptr t0 = tcg_temp_new_ptr(); - - tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, t0.f80)); - gen_helper_istofx(t0, cpu_env, src2); - gen_temp_reg_read_i64_i32(t0, ret->lo, ret->hi); - tcg_temp_free_ptr(t0); -} - -static inline void gen_fdtofx(Src80 *ret, TCGv_i64 src2) -{ - TCGv_ptr t0 = tcg_temp_new_ptr(); - - tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, t0)); - gen_helper_fdtofx(t0, cpu_env, src2); - gen_temp_reg_read_i64_i32(t0, ret->lo, ret->hi); - tcg_temp_free_ptr(t0); -} - -static inline void gen_idtofx(Src80 *ret, TCGv_i64 src2) -{ - TCGv_ptr t0 = tcg_temp_new_ptr(); - - tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, t0)); - gen_helper_idtofx(t0, cpu_env, src2); - gen_temp_reg_read_i64_i32(t0, ret->lo, ret->hi); - tcg_temp_free_ptr(t0); -} - -static inline void gen_fxtofs(TCGv_i32 ret, Src80 src2) -{ - TCGv_ptr t0 = tcg_temp_new_ptr(); - - tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, t0)); - gen_temp_reg_write_i64_i32(src2.lo, src2.hi, t0); - gen_helper_fxtofs(ret, cpu_env, t0); - tcg_temp_free_ptr(t0); -} - -static inline void gen_fxtois(TCGv_i32 ret, Src80 src2) -{ - TCGv_ptr t0 = tcg_temp_new_ptr(); - - tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, t0)); - gen_temp_reg_write_i64_i32(src2.lo, src2.hi, t0); - gen_helper_fxtois(ret, cpu_env, t0); - tcg_temp_free_ptr(t0); -} - -static inline void gen_fxtoistr(TCGv_i32 ret, Src80 src2) -{ - TCGv_ptr t0 = tcg_temp_new_ptr(); - - tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, t0)); - gen_temp_reg_write_i64_i32(src2.lo, src2.hi, t0); - gen_helper_fxtoistr(ret, cpu_env, t0); - tcg_temp_free_ptr(t0); -} - -static inline void gen_fxtofd(TCGv_i64 ret, Src80 src2) -{ - TCGv_ptr t0 = tcg_temp_new_ptr(); - - tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, t0)); - gen_temp_reg_write_i64_i32(src2.lo, src2.hi, t0); - gen_helper_fxtofd(ret, cpu_env, t0); - tcg_temp_free_ptr(t0); -} - -static inline void gen_fxtoid(TCGv_i64 ret, Src80 src2) -{ - TCGv_ptr t0 = tcg_temp_new_ptr(); - - tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, t0)); - gen_temp_reg_write_i64_i32(src2.lo, src2.hi, t0); - gen_helper_fxtoid(ret, cpu_env, t0); - tcg_temp_free_ptr(t0); -} - -static inline void gen_fxtoidtr(TCGv_i64 ret, Src80 src2) -{ - TCGv_ptr t0 = tcg_temp_new_ptr(); - - tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, t0)); - gen_temp_reg_write_i64_i32(src2.lo, src2.hi, t0); - gen_helper_fxtoidtr(ret, cpu_env, t0); - tcg_temp_free_ptr(t0); -} - -static inline void gen_shli2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 l, - TCGv_i64 h, int i) -{ - if (i < 64) { - TCGv_i64 t0 = tcg_temp_new_i64(); - TCGv_i64 t1 = tcg_temp_new_i64(); - tcg_gen_shri_i64(t0, l, 64 - i); - tcg_gen_shli_i64(t1, h, i); - tcg_gen_shli_i64(rl, l, i); - tcg_gen_or_i64(rh, t1, t0); - tcg_temp_free_i64(t1); - tcg_temp_free_i64(t0); - } else if (i < 128) { - tcg_gen_movi_i64(rl, 0); - tcg_gen_shli_i64(rh, l, i - 64); - } else { - tcg_gen_movi_i64(rl, 0); - tcg_gen_movi_i64(rh, 0); - } -} - -static inline void gen_shri2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 l, - TCGv_i64 h, int i) -{ - if (i < 64) { - TCGv_i64 t0 = tcg_temp_new_i64(); - TCGv_i64 t1 = tcg_temp_new_i64(); - tcg_gen_shli_i64(t0, h, 64 - i); - tcg_gen_shri_i64(t1, l, i); - tcg_gen_or_i64(rl, t1, t0); - tcg_gen_shri_i64(rh, h, i); - tcg_temp_free_i64(t1); - tcg_temp_free_i64(t0); - } else if (i < 128) { - tcg_gen_shri_i64(rl, h, i - 64); - tcg_gen_movi_i64(rh, 0); - } else { - tcg_gen_movi_i64(rl, 0); - tcg_gen_movi_i64(rh, 0); - } -} - -static inline void gen_psllql(TCGv_i64 ret, TCGv_i64 src1, - TCGv_i64 src2, int i) -{ - tcg_gen_shli_i64(ret, src2, i * 8); -} - -static inline void gen_psllqh(TCGv_i64 ret, TCGv_i64 src1, - TCGv_i64 src2, int i) -{ - TCGv_i64 t0 = tcg_temp_new_i64(); - gen_shli2_i64(t0, ret, src2, src1, i * 8); - tcg_temp_free_i64(t0); -} - -static inline void gen_psrlql(TCGv_i64 ret, TCGv_i64 src1, - TCGv_i64 src2, int i) -{ - TCGv_i64 t0 = tcg_temp_new_i64(); - gen_shri2_i64(ret, t0, src2, src1, i * 8); - tcg_temp_free_i64(t0); -} - -static inline void gen_psrlqh(TCGv_i64 ret, TCGv_i64 src1, - TCGv_i64 src2, int i) -{ - tcg_gen_shri_i64(ret, src1, i * 8); -} - -static inline void gen_pinsh(TCGv_i64 ret, TCGv_i64 src1, - TCGv_i64 src2, int i) -{ - if (i < 4) { - tcg_gen_deposit_i64(ret, src1, src2, i * 16, 16); - } else { - tcg_gen_mov_i64(ret, src1); - } -} - -static inline void gen_pextrh(TCGv_i64 ret, TCGv_i64 src1, - TCGv_i64 src2, int i) -{ - if (i < 4) { - tcg_gen_extract_i64(ret, src2, i * 16, 16); - } else if (i < 8) { - tcg_gen_extract_i64(ret, src1, (i - 4) * 16, 16); - } else { - tcg_gen_movi_i64(ret, 0); - } -} - -static inline void gen_pshufh(Instr *instr) -{ - Src64 s2 = get_src2_i64(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i64 dst = get_temp_i64(instr); - TCGv_i32 t0 = tcg_const_i32(instr->src3); - - gen_tag1_i64(tag, s2.tag); - gen_helper_pshufh(dst, s2.value, t0); - gen_al_result_i64(instr, dst, tag); - tcg_temp_free_i32(t0); -} - -static inline void gen_pshufw(TCGv_i64 ret, TCGv_i64 src1, - TCGv_i64 src2, int i) -{ - TCGv_i32 imm8 = tcg_const_i32(i); - gen_helper_pshufw(ret, src1, src2, imm8); - tcg_temp_free_i32(imm8); -} - -static void gen_aad_tag(TCGv_i64 ret, TCGv_i32 tag) -{ - TCGv_i32 t0 = tcg_temp_new_i32(); - TCGv_i64 t1 = tcg_temp_new_i64(); - - tcg_gen_setcondi_i32(TCG_COND_NE, t0, tag, 0); - tcg_gen_extu_i32_i64(t1, t0); - tcg_gen_shli_i64(ret, t1, 54); - - tcg_temp_free_i64(t1); - tcg_temp_free_i32(t0); -} - -static void gen_aaurw_aad_lo_i64(Instr *instr, TCGv_i64 arg1, TCGv_i32 tag) -{ - TCGv_i64 lo = e2k_cs.aad_lo[instr->aad]; - TCGv_i64 t0 = tcg_temp_new_i64(); - TCGv_i64 t1 = tcg_temp_new_i64(); - - tcg_gen_andi_i64(t0, arg1, 3UL << 57); - tcg_gen_andi_i64(lo, lo, ~(0x1fUL << 54)); - tcg_gen_or_i64(lo, lo, t0); - tcg_gen_deposit_i64(lo, lo, arg1, 0, 48); - tcg_gen_ori_i64(lo, lo, 3UL << 59); - gen_aad_tag(t1, tag); - tcg_gen_or_i64(lo, lo, t1); - - tcg_temp_free_i64(t1); - tcg_temp_free_i64(t0); -} - -static void gen_aaurw_aad_hi_i64(Instr *instr, TCGv_i64 arg1, TCGv_i32 tag) -{ - tcg_gen_andi_i64(e2k_cs.aad_hi[instr->aad], arg1, 0xffffffff00000000); -} - -static void gen_aaurw_aad_i32(Instr *instr, TCGv_i32 arg1, TCGv_i32 tag) -{ - TCGv_i64 lo = e2k_cs.aad_lo[instr->aad]; - TCGv_i64 t0 = tcg_temp_new_i64(); - TCGv_i64 t1 = tcg_temp_new_i64(); - TCGv_i64 t2 = tcg_temp_new_i64(); - - tcg_gen_extu_i32_i64(t0, arg1); - tcg_gen_deposit_i64(lo, lo, t0, 0, 48); - tcg_gen_ori_i64(lo, lo, 3UL << 59); - tcg_gen_andi_i64(lo, lo, ~(0x7UL << 54)); - gen_aad_tag(t1, tag); - tcg_gen_or_i64(lo, lo, t1); - - tcg_temp_free_i64(t2); - tcg_temp_free_i64(t1); - tcg_temp_free_i64(t0); -} - -static void gen_aaurw_rest_i32(Instr* instr, TCGv_i32 arg1, TCGv_i32 tag) -{ - int idx = instr->aaind; - TCGv_i32 t0 = tcg_temp_new_i32(); - tcg_gen_setcondi_i32(TCG_COND_NE, t0, tag, 0); - switch(instr->aaopc) { - case 1: /* aaurwd src4, aasti */ - tcg_gen_mov_i32(e2k_cs.aasti[idx], arg1); - tcg_gen_deposit_i32(e2k_cs.aasti_tags, e2k_cs.aasti_tags, t0, idx, 1); - break; - case 2: { /* aaurwd src4, aaind */ - if (idx == 0) { - tcg_gen_movi_i32(e2k_cs.aaind[idx], 0); - } else { - tcg_gen_mov_i32(e2k_cs.aaind[idx], arg1); - tcg_gen_deposit_i32(e2k_cs.aaind_tags, e2k_cs.aaind_tags, t0, - idx, 1); - } - break; - } - case 3: /* aaurwd src4, aaincr */ - idx &= 7; - if (idx > 0) { - tcg_gen_mov_i32(e2k_cs.aaincr[idx], arg1); - tcg_gen_deposit_i32(e2k_cs.aaincr_tags, e2k_cs.aaincr_tags, t0, - idx, 1); - } - break; - default: - g_assert_not_reached(); - break; - } - tcg_temp_free_i32(t0); -} - -static void gen_aasti_incr(DisasContext *ctx, Instr *instr) -{ - uint16_t rlp = find_am_cond(ctx, instr->chan); - TCGLabel *l0 = gen_new_label(); - TCGv_i32 t0 = tcg_temp_new_i32(); - - if (ctx->loop_mode) { - TCGLabel *l1 = gen_new_label(); - TCGv_i32 t0 = tcg_temp_local_new_i32(); - - tcg_gen_brcondi_i32(TCG_COND_NE, e2k_cs.lsr_pcnt, 0, l0); - e2k_gen_is_loop_end_i32(t0); - tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1); - tcg_gen_brcondi_i32(TCG_COND_EQ, e2k_cs.lsr_strmd, 0, l0); - gen_set_label(l1); - } - - if (rlp != 0) { - // FIXME: need to test AM RLP - TCGv_i32 t1 = tcg_temp_new_i32(); - - e2k_todo(ctx, "AM RLP found"); - gen_am_cond_i32(ctx, t1, instr->chan, rlp); - tcg_gen_brcondi_i32(TCG_COND_EQ, t1, 0, l0); - tcg_temp_free_i32(t1); - } - - tcg_gen_muli_i32(t0, e2k_cs.aaincr[instr->aaincr], instr->aaincr_len); - tcg_gen_add_i32(e2k_cs.aasti[instr->aaind], e2k_cs.aasti[instr->aaind], t0); - gen_set_label(l0); - - tcg_temp_free_i32(t0); -} - -static void gen_aad_ptr(DisasContext *ctx, TCGv ret, Instr *instr) -{ - uint32_t lit = 0; - TCGv_i64 t0 = tcg_temp_new_i64(); - TCGv t1 = tcg_temp_new(); - TCGv t2 = tcg_temp_new(); - - if (instr->aalit) { - int lts = instr->aalit - 1; - if (ctx->bundle.lts_present[lts]) { - lit = ctx->bundle.lts[lts]; - } else { - gen_tr_excp_illopn(ctx); - return; - } - } - - tcg_gen_extract_i64(t0, e2k_cs.aad_lo[instr->aad], 0, 48); - tcg_gen_trunc_i64_tl(t1, t0); - tcg_gen_extu_i32_tl(t2, e2k_cs.aasti[instr->aaind]); - if (lit != 0) { - TCGv t3 = tcg_temp_new(); - tcg_gen_add_tl(t3, t1, t2); - tcg_gen_addi_tl(ret, t3, lit); - tcg_temp_free(t3); - } else { - tcg_gen_add_tl(ret, t1, t2); - } - tcg_temp_free(t2); - tcg_temp_free(t1); - tcg_temp_free_i64(t0); -} - -static void gen_staa_i64(Instr *instr) -{ - DisasContext *ctx = instr->ctx; - uint8_t mas = instr->mas; - TCGLabel *l0 = gen_new_label(); - Src64 s4 = get_src4_i64(instr); - - gen_loop_mode_st(ctx, l0); - gen_tag_check(instr, s4.tag); - if (mas == 0x3f) { - /* aaurwd */ - if (instr->aaopc == 0) { - if (instr->chan == 5 && instr->opc1 == 0x3f) { - gen_aaurw_aad_hi_i64(instr, s4.value, s4.tag); - } else { - gen_aaurw_aad_lo_i64(instr, s4.value, s4.tag); - } - } else { - TCGv_i32 t0 = tcg_temp_new_i32(); - tcg_gen_extrl_i64_i32(t0, s4.value); - gen_aaurw_rest_i32(instr, t0, s4.tag); - tcg_temp_free_i32(t0); - } - } else { - /* staad */ - TCGLabel *l0 = gen_new_label(); - TCGv t0 = tcg_temp_local_new(); - - if (mas != 0) { - e2k_todo(ctx, "staad mas=%#x is not implemented", mas); - } - - gen_aad_ptr(ctx, t0, instr); - - if (instr->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, l0); - tcg_temp_free_i32(t1); - } - - tcg_gen_qemu_st_i64(s4.value, t0, ctx->mmuidx, MO_Q); - gen_set_label(l0); - tcg_temp_free(t0); - - if (instr->aaopc & 1) { - /* incr must be executed outside of the staa predicate condition */ - instr->aaincr_len = 8; - } - } - - gen_set_label(l0); -} - -static void gen_staa_i32(Instr *instr, MemOp memop) -{ - DisasContext *ctx = instr->ctx; - uint8_t mas = instr->mas; - TCGLabel *l0 = gen_new_label(); - Src32 s4 = get_src4_i32(instr); - - gen_loop_mode_st(ctx, l0); - gen_tag_check(instr, s4.tag); - if (mas == 0x3f) { - /* aaurw */ - /* CPU do nothing if size less than 32 bits */ - if ((memop & MO_SIZE) == MO_32) { - if (instr->aaopc == 0) { - gen_aaurw_aad_i32(instr, s4.value, s4.tag); - } else { - gen_aaurw_rest_i32(instr, s4.value, s4.tag); - } - } - } else { - /* staaw */ - int len; - TCGLabel *l0 = gen_new_label(); - TCGv t0 = tcg_temp_local_new(); - - if (mas != 0) { - char c; - switch(memop & MO_SIZE) { - case MO_8: c = 'b'; break; - case MO_16: c = 'h'; break; - case MO_32: c = 'w'; break; - default: - g_assert_not_reached(); - break; - } - e2k_todo(ctx, "staa%c mas=%#x", c, mas); - } - - gen_aad_ptr(ctx, t0, instr); - - if (instr->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, l0); - tcg_temp_free_i32(t1); - } - - tcg_gen_qemu_st_i32(s4.value, t0, ctx->mmuidx, memop); - gen_set_label(l0); - tcg_temp_free(t0); - - switch(memop & MO_SIZE) { - case MO_8: len = 1; break; - case MO_16: len = 2; break; - case MO_32: len = 4; break; - default: - g_assert_not_reached(); - break; - } - - if (instr->aaopc & 1) { - /* incr must be executed outside of the staa predicate condition */ - instr->aaincr_len = len; - } - } - - gen_set_label(l0); -} - -static void gen_alopf1_ddd(Instr *instr, - void (*op)(TCGv_i64, TCGv_i64, TCGv_i64)) -{ - Src64 s1 = get_src1_i64(instr); - Src64 s2 = get_src2_i64(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i64 dst = get_temp_i64(instr); - - gen_tag2_i64(tag, s1.tag, s2.tag); - (*op)(dst, s1.value, s2.value); - gen_al_result_i64(instr, dst, tag); -} - -static void gen_alopf11_dddi(Instr *instr, - void (*op)(TCGv_i64, TCGv_i64, TCGv_i64, int)) -{ - Src64 s1 = get_src1_i64(instr); - Src64 s2 = get_src2_i64(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i64 dst = get_temp_i64(instr); - - gen_tag2_i64(tag, s1.tag, s2.tag); - (*op)(dst, s1.value, s2.value, instr->src3); - gen_al_result_i64(instr, dst, tag); -} - -static void gen_alopf1_dedd(Instr *instr, - void (*op)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64)) -{ - Src64 s1 = get_src1_i64(instr); - Src64 s2 = get_src2_i64(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i64 dst = get_temp_i64(instr); - - gen_tag2_i64(tag, s1.tag, s2.tag); - (*op)(dst, cpu_env, s1.value, s2.value); - gen_al_result_i64(instr, dst, tag); -} - -static void gen_alopf1_deds(Instr *instr, - void (*op)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i32)) -{ - Src64 s1 = get_src1_i64(instr); - Src32 s2 = get_src2_i32(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i64 dst = get_temp_i64(instr); - - gen_tag2_i64(tag, s1.tag, s2.tag); - (*op)(dst, cpu_env, s1.value, s2.value); - gen_al_result_i64(instr, dst, tag); -} - -static void gen_alopf1_sss(Instr *instr, - void (*op)(TCGv_i32, TCGv_i32, TCGv_i32)) -{ - Src32 s1 = get_src1_i32(instr); - Src32 s2 = get_src2_i32(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i32 dst = get_temp_i32(instr); - - gen_tag2_i32(tag, s1.tag, s2.tag); - (*op)(dst, s1.value, s2.value); - gen_al_result_i32(instr, dst, tag); -} - -static void gen_alopf1_sess(Instr *instr, - void (*op)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32)) -{ - Src32 s1 = get_src1_i32(instr); - Src32 s2 = get_src2_i32(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i32 dst = get_temp_i32(instr); - - gen_tag2_i32(tag, s1.tag, s2.tag); - (*op)(dst, cpu_env, s1.value, s2.value); - gen_al_result_i32(instr, dst, tag); -} - -static void gen_alopf1_sedd(Instr *instr, - void (*op)(TCGv_i32, TCGv_env, TCGv_i64, TCGv_i64)) -{ - Src64 s1 = get_src1_i64(instr); - Src64 s2 = get_src2_i64(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i32 dst = get_temp_i32(instr); - - gen_tag2_i64(tag, s1.tag, s2.tag); - (*op)(dst, cpu_env, s1.value, s2.value); - gen_al_result_i32(instr, dst, tag); -} - -static inline void gen_alopf1_sf80(TCGv_i32 dst, Src80 src1, Src80 src2, - void (*op)(TCGv_i32, TCGv_env, TCGv_ptr, TCGv_ptr)) -{ - TCGv_ptr t0 = tcg_temp_new_ptr(); - TCGv_ptr t1 = tcg_temp_new_ptr(); - - tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, t0.f80)); - tcg_gen_addi_ptr(t1, cpu_env, offsetof(CPUE2KState, t1.f80)); - - gen_temp_reg_write_i64_i32(src1.lo, src1.hi, t0); - gen_temp_reg_write_i64_i32(src2.lo, src2.hi, t1); - - (*op)(dst, cpu_env, t0, t1); - - tcg_temp_free_ptr(t1); - tcg_temp_free_ptr(t0); -} - -static void gen_alopf1_sexs(Instr *instr, - void (*op)(TCGv_i32, TCGv_env, TCGv_ptr, TCGv_ptr)) -{ - Src80 s1 = get_src1_i80(instr); - Src32 s2 = get_src2_i32(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i32 dst = get_temp_i32(instr); - Src80 t0 = temp_new_src80(); - - gen_tag2_i32(tag, s1.tag, s2.tag); - gen_fstofx(&t0, s2.value); - gen_alopf1_sf80(dst, s1, t0, op); - gen_al_result_i32(instr, dst, tag); - - temp_free_src80(&t0); -} - -static void gen_alopf1_sexd(Instr *instr, - void (*op)(TCGv_i32, TCGv_env, TCGv_ptr, TCGv_ptr)) -{ - Src80 s1 = get_src1_i80(instr); - Src64 s2 = get_src2_i64(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i32 dst = get_temp_i32(instr); - Src80 t0 = temp_new_src80(); - - gen_tag2_i64(tag, s1.tag, s2.tag); - gen_fdtofx(&t0, s2.value); - gen_alopf1_sf80(dst, s1, t0, op); - gen_al_result_i32(instr, dst, tag); - - temp_free_src80(&t0); -} - -static void gen_alopf1_sexx(Instr *instr, - void (*op)(TCGv_i32, TCGv_env, TCGv_ptr, TCGv_ptr)) -{ - Src80 s1 = get_src1_i80(instr); - Src80 s2 = get_src2_i80(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i32 dst = get_temp_i32(instr); - - gen_tag2_i32(tag, s1.tag, s2.tag); - gen_alopf1_sf80(dst, s1, s2, op); - gen_al_result_i32(instr, dst, tag); -} - -static void gen_alopf1_dss(Instr *instr, - void (*op)(TCGv_i64, TCGv_i32, TCGv_i32)) -{ - Src32 s1 = get_src1_i32(instr); - Src32 s2 = get_src2_i32(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i64 dst = get_temp_i64(instr); - - gen_tag2_i64(tag, s1.tag, s2.tag); - (*op)(dst, s1.value, s2.value); - gen_al_result_i64(instr, dst, tag); -} - -static void gen_alopf1_dttdd(Instr *instr, - void (*op)(TCGv_i64, TCGv_i32, TCGv_i32, TCGv_i64, TCGv_i64)) -{ - Src64 s1 = get_src1_i64(instr); - Src64 s2 = get_src2_i64(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i64 dst = get_temp_i64(instr); - - gen_tag2_i64(tag, s1.tag, s2.tag); - (*op)(dst, tag, tag, s1.value, s2.value); - gen_al_result_i64(instr, dst, tag); -} - -static void gen_alopf1_sttss(Instr *instr, - void (*op)(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32)) -{ - Src32 s1 = get_src1_i32(instr); - Src32 s2 = get_src2_i32(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i32 dst = get_temp_i32(instr); - - gen_tag2_i32(tag, s1.tag, s2.tag); - (*op)(dst, tag, tag, s1.value, s2.value); - gen_al_result_i32(instr, dst, tag); -} - -static void gen_alopf1_sttds(Instr *instr, - void (*op)(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i64, TCGv_i32, bool)) -{ - Src64 s1 = get_src1_i64(instr); - Src32 s2 = get_src2_i32(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i32 dst = get_temp_i32(instr); - - gen_tag2_i32(tag, s1.tag, s2.tag); - (*op)(dst, tag, tag, s1.value, s2.value, instr->sm); - gen_al_result_i32(instr, dst, tag); -} - -static void gen_alopf1_cmp_ddb(Instr *instr, - void (*op)(TCGv_i64, int, TCGv_i64, TCGv_i64)) -{ - TCGLabel *l0 = gen_new_label(); - TCGLabel *l1 = gen_new_label(); - Src64 s1 = get_src1_i64(instr); - Src64 s2 = get_src2_i64(instr); - TCGv_i32 dst = get_temp_i32(instr); - TCGv_i32 t0 = tcg_temp_new_i32(); - TCGv_i64 t1 = tcg_temp_new_i64(); - - gen_tag2_i64(t0, s1.tag, s2.tag); - gen_tag_check(instr, t0); - tcg_gen_brcondi_i32(TCG_COND_NE, t0, 0, l0); - (*op)(t1, instr->opc_cmp, s1.value, s2.value); - tcg_gen_extrl_i64_i32(dst, t1); - tcg_gen_br(l1); - gen_set_label(l0); - tcg_gen_movi_i32(dst, 2); - gen_set_label(l1); - set_al_result_preg(instr, instr->dst_preg, dst); - tcg_temp_free_i64(t1); - tcg_temp_free_i32(t0); -} - -static void gen_alopf1_cmp_ssb(Instr *instr, - void (*op)(TCGv_i32, int, TCGv_i32, TCGv_i32)) -{ - TCGLabel *l0 = gen_new_label(); - TCGLabel *l1 = gen_new_label(); - Src32 s1 = get_src1_i32(instr); - Src32 s2 = get_src2_i32(instr); - TCGv_i32 dst = get_temp_i32(instr); - TCGv_i32 t0 = tcg_temp_new_i32(); - - gen_tag2_i32(t0, s1.tag, s2.tag); - gen_tag_check(instr, t0); - tcg_gen_brcondi_i32(TCG_COND_NE, t0, 0, l0); - (*op)(dst, instr->opc_cmp, s1.value, s2.value); - tcg_gen_br(l1); - gen_set_label(l0); - tcg_gen_movi_i32(dst, 2); - gen_set_label(l1); - set_al_result_preg(instr, instr->dst_preg, dst); - tcg_temp_free_i32(t0); -} - -static void gen_alopf1_cmp_f80(Instr *instr, Src80 s2, TCGv_i32 s2tag) -{ - TCGLabel *l0 = gen_new_label(); - TCGLabel *l1 = gen_new_label(); - Src80 s1 = get_src1_i80(instr); - TCGv_i32 dst = get_temp_i32(instr); - TCGv_i32 t0 = tcg_temp_new_i32(); - TCGv_i64 t1 = tcg_temp_new_i64(); - - gen_tag2_i64(t0, s1.tag, s2tag); - gen_tag_check(instr, t0); - tcg_gen_brcondi_i32(TCG_COND_NE, t0, 0, l0); - gen_fcmp_f80(t1, instr->opc_cmp, s1, s2); - tcg_gen_extrl_i64_i32(dst, t1); - tcg_gen_br(l1); - gen_set_label(l0); - tcg_gen_movi_i32(dst, 2); - gen_set_label(l1); - set_al_result_preg(instr, instr->dst_preg, dst); - tcg_temp_free_i64(t1); - tcg_temp_free_i32(t0); -} - -static void gen_alopf1_cmp_xx(Instr *instr) -{ - Src80 s2 = get_src2_i80(instr); - gen_alopf1_cmp_f80(instr, s2, s2.tag); -} - -static void gen_alopf1_cmp_xd(Instr *instr) -{ - Src64 s2 = get_src2_i64(instr); - Src80 t2 = temp_local_new_src80(); - - gen_fdtofx(&t2, s2.value); - gen_alopf1_cmp_f80(instr, t2, s2.tag); - - temp_free_src80(&t2); -} - -static void gen_alopf1_cmp_xs(Instr *instr) -{ - Src32 s2 = get_src2_i32(instr); - Src80 t2 = temp_local_new_src80(); - - gen_fstofx(&t2, s2.value); - gen_alopf1_cmp_f80(instr, t2, s2.tag); - - temp_free_src80(&t2); -} - -static void gen_alopf1_mrgc_sss(Instr *instr) -{ - Src32 s1 = get_src1_i32(instr); - Src32 s2 = get_src2_i32(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i32 dst = get_temp_i32(instr); - TCGv_i32 t0 = tcg_temp_new_i32(); - TCGv_i32 t1 = tcg_temp_new_i32(); - - gen_mrgc_i32(instr->ctx, instr->chan, t0); - gen_merge_i32(t1, s1.tag, s2.tag, t0); - gen_merge_i32(dst, s1.value, s2.value, t0); - gen_tag1_i32(tag, t1); - gen_al_result_i32(instr, dst, tag); - - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t0); -} - -static void gen_alopf1_mrgc_ddd(Instr *instr) -{ - Src64 s1 = get_src1_i64(instr); - Src64 s2 = get_src2_i64(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i64 dst = get_temp_i64(instr); - TCGv_i32 t0 = tcg_temp_new_i32(); - TCGv_i32 t1 = tcg_temp_new_i32(); - - gen_mrgc_i32(instr->ctx, instr->chan, t0); - gen_merge_i32(t1, s1.tag, s2.tag, t0); - gen_merge_i64(dst, s1.value, s2.value, t0); - gen_tag1_i64(tag, t1); - gen_al_result_i64(instr, dst, tag); - - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t0); -} - -static void gen_alopf21_i64(Instr *instr, - void (*op)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64)) -{ - Src64 s1 = get_src1_i64(instr); - Src64 s2 = get_src2_i64(instr); - Src64 s3 = get_src3_i64(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i64 dst = get_temp_i64(instr); - - gen_tag3_i64(tag, s1.tag, s2.tag, s3.tag); - (*op)(dst, s1.value, s2.value, s3.value); - gen_al_result_i64(instr, dst, tag); -} - -static void gen_alopf21_i32(Instr *instr, - void (*op)(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32)) -{ - Src32 s1 = get_src1_i32(instr); - Src32 s2 = get_src2_i32(instr); - Src32 s3 = get_src3_i32(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i32 dst = get_temp_i32(instr); - - gen_tag3_i32(tag, s1.tag, s2.tag, s3.tag); - (*op)(dst, s1.value, s2.value, s3.value); - gen_al_result_i32(instr, dst, tag); -} - -static void gen_alopf2_ss(Instr *instr, void (*op)(TCGv_i32, TCGv_i32)) -{ - Src32 s2 = get_src2_i32(instr); - TCGv_i32 dst = get_temp_i32(instr); - TCGv_i32 tag = get_temp_i32(instr); - - gen_tag1_i32(tag, s2.tag); - (*op)(dst, s2.value); - gen_al_result_i32(instr, dst, tag); -} - -static void gen_alopf2_dd(Instr *instr, void (*op)(TCGv_i64, TCGv_i64)) -{ - Src64 s2 = get_src2_i64(instr); - TCGv_i64 dst = get_temp_i64(instr); - TCGv_i32 tag = get_temp_i32(instr); - - gen_tag1_i64(tag, s2.tag); - (*op)(dst, s2.value); - gen_al_result_i64(instr, dst, tag); -} - -static void gen_alopf2_ses(Instr *instr, - void (*op)(TCGv_i32, TCGv_env, TCGv_i32)) -{ - Src32 s2 = get_src2_i32(instr); - TCGv_i32 dst = get_temp_i32(instr); - TCGv_i32 tag = get_temp_i32(instr); - - gen_tag1_i32(tag, s2.tag); - (*op)(dst, cpu_env, s2.value); - gen_al_result_i32(instr, dst, tag); -} - -static void gen_alopf2_ded(Instr *instr, - void (*op)(TCGv_i64, TCGv_env, TCGv_i64)) -{ - Src64 s2 = get_src2_i64(instr); - TCGv_i64 dst = get_temp_i64(instr); - TCGv_i32 tag = get_temp_i32(instr); - - gen_tag1_i64(tag, s2.tag); - (*op)(dst, cpu_env, s2.value); - gen_al_result_i64(instr, dst, tag); -} - -static void gen_alopf2_sed(Instr *instr, - void (*op)(TCGv_i32, TCGv_env, TCGv_i64)) -{ - Src64 s2 = get_src2_i64(instr); - TCGv_i32 dst = get_temp_i32(instr); - TCGv_i32 tag = get_temp_i32(instr); - - gen_tag1_i32(tag, s2.tag); - (*op)(dst, cpu_env, s2.value); - gen_al_result_i32(instr, dst, tag); -} - -static void gen_alopf2_des(Instr *instr, - void (*op)(TCGv_i64, TCGv_env, TCGv_i32)) -{ - Src32 s2 = get_src2_i32(instr); - TCGv_i64 dst = get_temp_i64(instr); - TCGv_i32 tag = get_temp_i32(instr); - - gen_tag1_i64(tag, s2.tag); - (*op)(dst, cpu_env, s2.value); - gen_al_result_i64(instr, dst, tag); -} - -static inline void gen_alopf1_f80(Src80 *ret, Src80 src1, Src80 src2, - void (*op)(TCGv_env, TCGv_ptr, TCGv_ptr)) -{ - TCGv_ptr t0 = tcg_temp_new_ptr(); - TCGv_ptr t1 = tcg_temp_new_ptr(); - - gen_tag2_i64(ret->tag, src1.tag, src2.tag); - - tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, t0.f80)); - tcg_gen_addi_ptr(t1, cpu_env, offsetof(CPUE2KState, t1.f80)); - - gen_temp_reg_write_i64_i32(src1.lo, src1.hi, t0); - gen_temp_reg_write_i64_i32(src2.lo, src2.hi, t1); - - (*op)(cpu_env, t0, t1); - - gen_temp_reg_read_i64_i32(t0, ret->lo, ret->hi); - - tcg_temp_free_ptr(t1); - tcg_temp_free_ptr(t0); -} - -static inline void gen_alopf1_xexs_raw(Src80 *ret, Src80 src1, Src32 src2, - void (*op)(TCGv_env, TCGv_ptr, TCGv_i32)) -{ - TCGv_ptr t0 = tcg_temp_new_ptr(); - - gen_tag2_i64(ret->tag, src1.tag, src2.tag); - tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, t0.f80)); - gen_temp_reg_write_i64_i32(src1.lo, src1.hi, t0); - (*op)(cpu_env, t0, src2.value); - gen_temp_reg_read_i64_i32(t0, ret->lo, ret->hi); - tcg_temp_free_ptr(t0); -} - -static inline void gen_alopf1_xxx(Instr *instr, - void (*op)(TCGv_env, TCGv_ptr, TCGv_ptr)) -{ - Src80 src1 = get_src1_i80(instr); - Src80 src2 = get_src2_i80(instr); - Src80 res = get_temp_src80(instr); - gen_alopf1_f80(&res, src1, src2, op); - gen_al_result_i80(instr, res.lo, res.hi, res.tag); -} - -static inline void gen_alopf1_xxs(Instr *instr, - void (*op)(TCGv_env, TCGv_ptr, TCGv_ptr)) -{ - Src80 src1 = get_src1_i80(instr); - Src80 src2 = get_src2_i80(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i32 dst = get_temp_i32(instr); - Src80 t0 = temp_new_src80(); - - gen_tag2_i32(tag, src1.tag, src2.tag); - gen_alopf1_f80(&t0, src1, src2, op); - gen_fxtofs(dst, t0); - gen_al_result_i32(instr, dst, tag); - - temp_free_src80(&t0); -} - -static inline void gen_alopf1_xexi(Instr *instr, - void (*op)(TCGv_env, TCGv_ptr, TCGv_i32)) -{ - Src80 src1 = get_src1_i80(instr); - Src32 src2 = get_src2_i32(instr); - Src80 res = get_temp_src80(instr); - - gen_alopf1_xexs_raw(&res, src1, src2, op); - gen_al_result_i80(instr, res.lo, res.hi, res.tag); -} - -static inline void gen_alopf1_xxd(Instr *instr, - void (*op)(TCGv_env, TCGv_ptr, TCGv_ptr)) -{ - Src80 src1 = get_src1_i80(instr); - Src80 src2 = get_src2_i80(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i64 dst = get_temp_i64(instr); - Src80 t0 = temp_new_src80(); - - gen_tag2_i64(tag, src1.tag, src2.tag); - gen_alopf1_f80(&t0, src1, src2, op); - gen_fxtofd(dst, t0); - gen_al_result_i64(instr, dst, tag); - - temp_free_src80(&t0); -} - -static inline void gen_alopf1_xss(Instr *instr, - void (*op)(TCGv_env, TCGv_ptr, TCGv_ptr)) -{ - Src80 src1 = get_src1_i80(instr); - Src32 src2 = get_src2_i32(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i32 dst = get_temp_i32(instr); - Src80 t0 = temp_new_src80(); - Src80 t1 = temp_new_src80(); - - gen_tag2_i32(tag, src1.tag, src2.tag); - gen_fstofx(&t0, src2.value); - gen_alopf1_f80(&t1, src1, t0, op); - gen_fxtofs(dst, t1); - gen_al_result_i32(instr, dst, tag); - - temp_free_src80(&t1); - temp_free_src80(&t0); -} - -static inline void gen_alopf1_xdd(Instr *instr, - void (*op)(TCGv_env, TCGv_ptr, TCGv_ptr)) -{ - Src80 src1 = get_src1_i80(instr); - Src64 src2 = get_src2_i64(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i64 dst = get_temp_i64(instr); - Src80 t0 = temp_new_src80(); - Src80 t1 = temp_new_src80(); - - gen_tag2_i64(tag, src1.tag, src2.tag); - gen_fdtofx(&t0, src2.value); - gen_alopf1_f80(&t1, src1, t0, op); - gen_fxtofd(dst, t1); - gen_al_result_i64(instr, dst, tag); - - temp_free_src80(&t1); - temp_free_src80(&t0); -} - -static inline void gen_alopf1_xsx(Instr *instr, - void (*op)(TCGv_env, TCGv_ptr, TCGv_ptr)) -{ - Src80 src1 = get_src1_i80(instr); - Src32 src2 = get_src2_i32(instr); - TCGv_i32 tag = get_temp_i32(instr); - Src80 t0 = temp_new_src80(); - Src80 t1 = get_temp_src80(instr); - - gen_tag2_i64(tag, src1.tag, src2.tag); - gen_fstofx(&t0, src2.value); - gen_alopf1_f80(&t1, src1, t0, op); - gen_al_result_i80(instr, t1.lo, t1.hi, tag); - - temp_free_src80(&t0); -} - -static inline void gen_alopf1_xdx(Instr *instr, - void (*op)(TCGv_env, TCGv_ptr, TCGv_ptr)) -{ - Src80 src1 = get_src1_i80(instr); - Src64 src2 = get_src2_i64(instr); - TCGv_i32 tag = get_temp_i32(instr); - Src80 t0 = temp_new_src80(); - Src80 t1 = get_temp_src80(instr); - - gen_tag2_i64(tag, src1.tag, src2.tag); - gen_fdtofx(&t0, src2.value); - gen_alopf1_f80(&t1, src1, t0, op); - gen_al_result_i80(instr, t1.lo, t1.hi, tag); - - temp_free_src80(&t0); -} - -static inline void gen_alopf2_xs(Instr *instr, - void (*op)(TCGv_i32 ret, Src80 src2)) -{ - Src80 src2 = get_src2_i80(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i32 dst = get_temp_i32(instr); - - gen_tag1_i32(tag, src2.tag); - (*op)(dst, src2); - gen_al_result_i32(instr, dst, tag); -} - -static inline void gen_alopf2_xd(Instr *instr, - void (*op)(TCGv_i64 ret, Src80 src2)) -{ - Src80 src2 = get_src2_i80(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i64 dst = get_temp_i64(instr); - - gen_tag1_i32(tag, src2.tag); - (*op)(dst, src2); - gen_al_result_i64(instr, dst, tag); -} - -static inline void gen_alopf2_sx(Instr *instr, - void (*op)(Src80 *ret, TCGv_i32 src2)) -{ - Src32 src2 = get_src2_i32(instr); - Src80 res = get_temp_src80(instr); - - gen_tag1_i64(res.tag, src2.tag); - (*op)(&res, src2.value); - gen_al_result_i80(instr, res.lo, res.hi, res.tag); -} - -static inline void gen_alopf2_dx(Instr *instr, - void (*op)(Src80 *ret, TCGv_i64 src2)) -{ - Src64 src2 = get_src2_i64(instr); - Src80 res = get_temp_src80(instr); - - gen_tag1_i64(res.tag, src2.tag); - (*op)(&res, src2.value); - gen_al_result_i80(instr, res.lo, res.hi, res.tag); -} - -static inline void gen_mov_f80(Src80 *ret, Src80 src2) -{ - tcg_gen_mov_i32(ret->hi, src2.hi); - tcg_gen_mov_i64(ret->lo, src2.lo); -} - -static inline void gen_alopf2_xx(Instr *instr, - void (*op)(Src80 *ret, Src80 src2)) -{ - Src80 src2 = get_src2_i80(instr); - Src80 res = get_temp_src80(instr); - - gen_tag1_i64(res.tag, src2.tag); - (*op)(&res, src2); - gen_al_result_i80(instr, res.lo, res.hi, res.tag); -} - -static AlopDesc *find_op(Instr *instr) -{ - /* ALES2/5 may be allocated but must not be used */ - int opc2 = instr->ales_present & ALES_PRESENT ? instr->opc2 : 0; - int16_t index = alops_map[opc2][instr->opc1][instr->chan]; - while (index != -1) { - bool is_match = false; - AlopDesc *desc = &alops[index]; - switch(desc->alopf) { - case ALOPF1: - case ALOPF1_MERGE: - case ALOPF3: - case ALOPF10: - case ALOPF11_LIT8: - case ALOPF12_PSHUFH: - case ALOPF21: - is_match = true; - break; - case ALOPF2: - case ALOPF15: - is_match = desc->extra1 == instr->opce1; - break; - case ALOPF7: - is_match = desc->extra1 == instr->opc_cmp; - break; - case ALOPF8: - is_match = desc->extra1 == instr->opc_cmp && instr->opce1 == 0xc0; - break; - case ALOPF11: - case ALOPF11_MERGE: - case ALOPF13: - case ALOPF17: - is_match = desc->extra1 == instr->opce3; - break; - case ALOPF12: - case ALOPF12_IBRANCHD: - case ALOPF12_ICALLD: - case ALOPF22: - is_match = desc->extra1 == instr->opce1 && desc->extra2 == instr->opce3; - break; - case ALOPF16: - is_match = desc->extra1 == instr->opce2; - break; - default: - g_assert_not_reached(); - break; - } - - if (is_match) { - return desc; - } - - index = desc->next[instr->chan]; - } - - 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: - 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: - case ALOPF21_ICOMB: - case ALOPF21_FCOMB: - case ALOPF21_PFCOMB: - case ALOPF21_LCOMB: - 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_alop_simple(Instr *instr, uint32_t op, const char *name) -{ - DisasContext *ctx = instr->ctx; - int chan = instr->chan; - switch(op) { - 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_ANDNS: gen_alopf1_sss(instr, gen_andn_i32); break; - case OP_ANDND: gen_alopf1_ddd(instr, gen_andn_i64); break; - case OP_ORS: gen_alopf1_sss(instr, tcg_gen_or_i32); break; - case OP_ORD: gen_alopf1_ddd(instr, tcg_gen_or_i64); break; - case OP_ORNS: gen_alopf1_sss(instr, gen_orn_i32); break; - case OP_ORND: gen_alopf1_ddd(instr, gen_orn_i64); break; - case OP_XORS: gen_alopf1_sss(instr, tcg_gen_xor_i32); break; - case OP_XORD: gen_alopf1_ddd(instr, tcg_gen_xor_i64); break; - case OP_XORNS: gen_alopf1_sss(instr, gen_xorn_i32); break; - case OP_XORND: gen_alopf1_ddd(instr, gen_xorn_i64); break; - case OP_SXT: gen_sxt(ctx, instr); break; - case OP_ADDS: gen_alopf1_sss(instr, tcg_gen_add_i32); break; - case OP_ADDD: gen_alopf1_ddd(instr, tcg_gen_add_i64); break; - case OP_SUBS: gen_alopf1_sss(instr, tcg_gen_sub_i32); break; - case OP_SUBD: gen_alopf1_ddd(instr, tcg_gen_sub_i64); break; - case OP_SCLS: gen_alopf1_sss(instr, tcg_gen_rotl_i32); break; - case OP_SCLD: gen_alopf1_ddd(instr, tcg_gen_rotl_i64); break; - case OP_SCRS: gen_alopf1_sss(instr, tcg_gen_rotr_i32); break; - case OP_SCRD: gen_alopf1_ddd(instr, tcg_gen_rotr_i64); break; - case OP_SHLS: gen_alopf1_sss(instr, tcg_gen_shl_i32); break; - case OP_SHLD: gen_alopf1_ddd(instr, tcg_gen_shl_i64); break; - case OP_SHRS: gen_alopf1_sss(instr, tcg_gen_shr_i32); break; - case OP_SHRD: gen_alopf1_ddd(instr, tcg_gen_shr_i64); break; - case OP_SARS: gen_alopf1_sss(instr, tcg_gen_sar_i32); break; - case OP_SARD: gen_alopf1_ddd(instr, tcg_gen_sar_i64); break; - case OP_GETFS: gen_alopf1_sss(instr, gen_getfs); break; - case OP_GETFD: gen_alopf1_ddd(instr, gen_getfd); break; - case OP_MERGES: gen_alopf1_mrgc_sss(instr); break; - case OP_MERGED: gen_alopf1_mrgc_ddd(instr); break; - case OP_CMPOSB: - case OP_CMPBSB: - case OP_CMPESB: - case OP_CMPBESB: - case OP_CMPSSB: - case OP_CMPPSB: - case OP_CMPLSB: - case OP_CMPLESB: - gen_alopf1_cmp_ssb(instr, gen_cmp_i32); - break; - case OP_CMPODB: - case OP_CMPBDB: - case OP_CMPEDB: - case OP_CMPBEDB: - case OP_CMPSDB: - case OP_CMPPDB: - case OP_CMPLDB: - case OP_CMPLEDB: - gen_alopf1_cmp_ddb(instr, gen_cmp_i64); - break; - case OP_CMPANDESB: - case OP_CMPANDSSB: - case OP_CMPANDPSB: - case OP_CMPANDLESB: - gen_alopf1_cmp_ssb(instr, gen_cmpand_i32); - break; - case OP_CMPANDEDB: - case OP_CMPANDSDB: - case OP_CMPANDPDB: - case OP_CMPANDLEDB: - gen_alopf1_cmp_ddb(instr, gen_cmpand_i64); - break; - case OP_FCMPEQSB: - case OP_FCMPLTSB: - case OP_FCMPLESB: - case OP_FCMPUODSB: - case OP_FCMPNEQSB: - case OP_FCMPNLTSB: - case OP_FCMPNLESB: - case OP_FCMPODSB: - gen_alopf1_cmp_ssb(instr, gen_fcmp_i32); - break; - case OP_FCMPEQDB: - case OP_FCMPLTDB: - case OP_FCMPLEDB: - case OP_FCMPUODDB: - case OP_FCMPNEQDB: - case OP_FCMPNLTDB: - case OP_FCMPNLEDB: - case OP_FCMPODDB: - gen_alopf1_cmp_ddb(instr, gen_fcmp_i64); - break; - case OP_FXCMPEQSB: - case OP_FXCMPLTSB: - case OP_FXCMPLESB: - case OP_FXCMPUODSB: - case OP_FXCMPNEQSB: - case OP_FXCMPNLTSB: - case OP_FXCMPNLESB: - case OP_FXCMPODSB: - gen_alopf1_cmp_xs(instr); - break; - case OP_FXCMPEQDB: - case OP_FXCMPLTDB: - case OP_FXCMPLEDB: - case OP_FXCMPUODDB: - case OP_FXCMPNEQDB: - case OP_FXCMPNLTDB: - case OP_FXCMPNLEDB: - case OP_FXCMPODDB: - gen_alopf1_cmp_xd(instr); - break; - case OP_FXCMPEQXB: - case OP_FXCMPLTXB: - case OP_FXCMPLEXB: - case OP_FXCMPUODXB: - case OP_FXCMPNEQXB: - case OP_FXCMPNLTXB: - case OP_FXCMPNLEXB: - case OP_FXCMPODXB: - gen_alopf1_cmp_xx(instr); - break; - case OP_STB: gen_st_sdd(instr, MO_UB); break; - case OP_STH: gen_st_sdd(instr, MO_UW); break; - case OP_STW: gen_st_sdd(instr, MO_UL); break; - case OP_STD: gen_st_ddd(instr, MO_Q); break; - case OP_STGDB: gen_st_sss(instr, MO_UB); break; - case OP_STGDH: gen_st_sss(instr, MO_UW); break; - case OP_STGDW: gen_st_sss(instr, MO_UL); break; - case OP_STGDD: gen_st_dss(instr, MO_Q); break; - case OP_STGDQ: e2k_todo_illop(instr->ctx, "stgdq"); break; - case OP_LDB: gen_ld_mas_i64(instr, MO_UB); break; - case OP_LDH: gen_ld_mas_i64(instr, MO_UW); break; - case OP_LDW: gen_ld_mas_i64(instr, MO_UL); break; - case OP_LDD: gen_ld_mas_i64(instr, MO_Q); break; -#ifdef TARGET_E2K32 - case OP_LDGDB: gen_ld_mas_i32(instr, MO_UB); break; - case OP_LDGDH: gen_ld_mas_i32(instr, MO_UW); break; - case OP_LDGDW: gen_ld_mas_i32(instr, MO_UL); break; - case OP_LDGDD: gen_ld_mas_i32(instr, MO_Q); break; - case OP_LDGDQ: e2k_todo_illop(instr->ctx, "ldgdq"); break; -#else /* !TARGET_E2K32 */ - case OP_LDGDB: /* fallthrough */ - case OP_LDGDH: /* fallthrough */ - case OP_LDGDW: /* fallthrough */ - case OP_LDGDD: /* fallthrough */ - case OP_LDGDQ: gen_tr_excp_array_bounds(instr->ctx); break; -#endif - case OP_BITREVS: gen_alopf2_ss(instr, gen_bitrevs); break; - case OP_BITREVD: gen_alopf2_dd(instr, gen_bitrevd); break; - case OP_LZCNTS: gen_alopf2_ss(instr, gen_lzcnts); break; - case OP_LZCNTD: gen_alopf2_dd(instr, gen_lzcntd); break; - case OP_POPCNTS: gen_alopf2_ss(instr, tcg_gen_ctpop_i32); break; - case OP_POPCNTD: gen_alopf2_dd(instr, tcg_gen_ctpop_i64); break; - case OP_FADDS: gen_alopf1_sess(instr, gen_helper_fadds); break; - case OP_FADDD: gen_alopf1_dedd(instr, gen_helper_faddd); break; - case OP_FSUBS: gen_alopf1_sess(instr, gen_helper_fsubs); break; - case OP_FSUBD: gen_alopf1_dedd(instr, gen_helper_fsubd); break; - case OP_FMINS: gen_alopf1_sess(instr, gen_helper_fmins); break; - case OP_FMIND: gen_alopf1_dedd(instr, gen_helper_fmind); break; - case OP_FMAXS: gen_alopf1_sess(instr, gen_helper_fmaxs); break; - case OP_FMAXD: gen_alopf1_dedd(instr, gen_helper_fmaxd); break; - case OP_FMULS: gen_alopf1_sess(instr, gen_helper_fmuls); break; - case OP_FMULD: gen_alopf1_dedd(instr, gen_helper_fmuld); break; - case OP_FCMPEQS: gen_alopf1_sess(instr, gen_helper_fcmpeqs); break; - case OP_FCMPLTS: gen_alopf1_sess(instr, gen_helper_fcmplts); break; - case OP_FCMPLES: gen_alopf1_sess(instr, gen_helper_fcmples); break; - case OP_FCMPUODS: gen_alopf1_sess(instr, gen_helper_fcmpuods); break; - case OP_FCMPNEQS: gen_alopf1_sess(instr, gen_helper_fcmpneqs); break; - case OP_FCMPNLTS: gen_alopf1_sess(instr, gen_helper_fcmpnlts); break; - case OP_FCMPNLES: gen_alopf1_sess(instr, gen_helper_fcmpnles); break; - case OP_FCMPODS: gen_alopf1_sess(instr, gen_helper_fcmpods); break; - case OP_FCMPEQD: gen_alopf1_dedd(instr, gen_helper_fcmpeqd); break; - case OP_FCMPLTD: gen_alopf1_dedd(instr, gen_helper_fcmpltd); break; - case OP_FCMPLED: gen_alopf1_dedd(instr, gen_helper_fcmpled); break; - case OP_FCMPUODD: gen_alopf1_dedd(instr, gen_helper_fcmpuodd); break; - case OP_FCMPNEQD: gen_alopf1_dedd(instr, gen_helper_fcmpneqd); break; - case OP_FCMPNLTD: gen_alopf1_dedd(instr, gen_helper_fcmpnltd); break; - case OP_FCMPNLED: gen_alopf1_dedd(instr, gen_helper_fcmpnled); break; - case OP_FCMPODD: gen_alopf1_dedd(instr, gen_helper_fcmpodd); break; - case OP_FSTOIS: gen_alopf2_ses(instr, gen_helper_fstois); break; - case OP_FSTOISTR: gen_alopf2_ses(instr, gen_helper_fstoistr); break; - case OP_ISTOFS: gen_alopf2_ses(instr, gen_helper_istofs); break; - case OP_FDTOID: gen_alopf2_ded(instr, gen_helper_fdtoid); break; - case OP_IDTOFD: gen_alopf2_ded(instr, gen_helper_idtofd); break; - case OP_FXTOFD: gen_alopf2_xd(instr, gen_fxtofd); break; - case OP_FDTOFX: gen_alopf2_dx(instr, gen_fdtofx); break; - case OP_FSTOID: gen_alopf2_des(instr, gen_helper_fstoid); break; - case OP_FSTOIDTR: gen_alopf2_des(instr, gen_helper_fstoidtr); break; - case OP_FDTOIDTR: gen_alopf2_ded(instr, gen_helper_fdtoidtr); break; - case OP_ISTOFD: gen_alopf2_des(instr, gen_helper_istofd); break; - case OP_FSTOFD: gen_alopf2_des(instr, gen_helper_fstofd); break; - case OP_FSTOFX: gen_alopf2_sx(instr, gen_fstofx); break; - case OP_FDTOISTR: gen_alopf2_sed(instr, gen_helper_fdtoistr); break; - case OP_FDTOIS: gen_alopf2_sed(instr, gen_helper_fdtois); break; - case OP_IDTOFS: gen_alopf2_sed(instr, gen_helper_idtofs); break; - case OP_FDTOFS: gen_alopf2_sed(instr, gen_helper_fdtofs); break; - case OP_FXTOFS: gen_alopf2_xs(instr, gen_fxtofs); break; - case OP_FXTOIS: gen_alopf2_xs(instr, gen_fxtois); break; - case OP_FXTOISTR: gen_alopf2_xs(instr, gen_fxtoistr); break; - case OP_FXTOID: gen_alopf2_xd(instr, gen_fxtoid); break; - case OP_FXTOIDTR: gen_alopf2_xd(instr, gen_fxtoidtr); break; - case OP_ISTOFX: gen_alopf2_sx(instr, gen_istofx); break; - case OP_IDTOFX: gen_alopf2_dx(instr, gen_idtofx); break; - case OP_UDIVS: gen_alopf1_sttss(instr, gen_udivs); break; - case OP_UDIVD: gen_alopf1_dttdd(instr, gen_udivd); break; - case OP_SDIVS: gen_alopf1_sttss(instr, gen_sdivs); break; - case OP_SDIVD: gen_alopf1_dttdd(instr, gen_sdivd); break; - case OP_FXADDSS: gen_alopf1_xss(instr, gen_helper_fxaddxx); break; - case OP_FXADDDD: gen_alopf1_xdd(instr, gen_helper_fxaddxx); break; - case OP_FXADDSX: gen_alopf1_xsx(instr, gen_helper_fxaddxx); break; - case OP_FXADDDX: gen_alopf1_xdx(instr, gen_helper_fxaddxx); break; - case OP_FXADDXX: gen_alopf1_xxx(instr, gen_helper_fxaddxx); break; - case OP_FXADDXD: gen_alopf1_xxd(instr, gen_helper_fxaddxx); break; - case OP_FXADDXS: gen_alopf1_xxs(instr, gen_helper_fxaddxx); break; - case OP_FXSUBSS: gen_alopf1_xss(instr, gen_helper_fxsubxx); break; - case OP_FXSUBDD: gen_alopf1_xdd(instr, gen_helper_fxsubxx); break; - case OP_FXSUBSX: gen_alopf1_xsx(instr, gen_helper_fxsubxx); break; - case OP_FXSUBDX: gen_alopf1_xdx(instr, gen_helper_fxsubxx); break; - case OP_FXSUBXX: gen_alopf1_xxx(instr, gen_helper_fxsubxx); break; - case OP_FXSUBXD: gen_alopf1_xxd(instr, gen_helper_fxsubxx); break; - case OP_FXSUBXS: gen_alopf1_xxs(instr, gen_helper_fxsubxx); break; - case OP_FXRSUBSS: gen_alopf1_xss(instr, gen_helper_fxrsubxx); break; - case OP_FXRSUBDD: gen_alopf1_xdd(instr, gen_helper_fxrsubxx); break; - case OP_FXRSUBSX: gen_alopf1_xsx(instr, gen_helper_fxrsubxx); break; - case OP_FXRSUBDX: gen_alopf1_xdx(instr, gen_helper_fxrsubxx); break; - case OP_FXMULSS: gen_alopf1_xss(instr, gen_helper_fxmulxx); break; - case OP_FXMULDD: gen_alopf1_xdd(instr, gen_helper_fxmulxx); break; - case OP_FXMULSX: gen_alopf1_xsx(instr, gen_helper_fxmulxx); break; - case OP_FXMULDX: gen_alopf1_xdx(instr, gen_helper_fxmulxx); break; - case OP_FXMULXX: gen_alopf1_xxx(instr, gen_helper_fxmulxx); break; - case OP_FXMULXD: gen_alopf1_xxd(instr, gen_helper_fxmulxx); break; - case OP_FXMULXS: gen_alopf1_xxs(instr, gen_helper_fxmulxx); break; - case OP_FXDIVSS: gen_alopf1_xss(instr, gen_helper_fxdivxx); break; - case OP_FXDIVDD: gen_alopf1_xdd(instr, gen_helper_fxdivxx); break; - case OP_FXDIVSX: gen_alopf1_xsx(instr, gen_helper_fxdivxx); break; - case OP_FXDIVDX: gen_alopf1_xdx(instr, gen_helper_fxdivxx); break; - case OP_FXDIVXX: gen_alopf1_xxx(instr, gen_helper_fxdivxx); break; - case OP_FXDIVXD: gen_alopf1_xxd(instr, gen_helper_fxdivxx); break; - case OP_FXDIVXS: gen_alopf1_xxs(instr, gen_helper_fxdivxx); break; - case OP_MOVFI: gen_movfi(instr); break; - case OP_MOVIF: gen_movif(instr); break; - case OP_MOVX: gen_movx(instr); break; - case OP_MOVXA: gen_movxa(instr); break; - case OP_MOVXC: gen_movxc(instr); break; - case OP_MOVTS: gen_movts(instr); break; - case OP_MOVTCS: gen_movtcs(instr); break; - case OP_MOVTD: gen_movtd(instr); break; - case OP_MOVTCD: gen_movtcd(instr); break; - case OP_MOVTQ: gen_movtq(instr); break; - case OP_MOVTCQ: gen_movtcq(instr); break; - case OP_GETPL: gen_getpl(instr); break; - case OP_PANDD: gen_alopf1_ddd(instr, tcg_gen_and_i64); break; - case OP_PANDND: gen_alopf1_ddd(instr, gen_andn_i64); break; - case OP_PORD: gen_alopf1_ddd(instr, tcg_gen_or_i64); break; - case OP_PXORD: gen_alopf1_ddd(instr, tcg_gen_xor_i64); break; - case OP_PMINUB: gen_alopf1_ddd(instr, gen_helper_pminub); break; - case OP_PMINSB: gen_alopf1_ddd(instr, gen_helper_pminsb); break; - case OP_PMINUH: gen_alopf1_ddd(instr, gen_helper_pminuh); break; - case OP_PMINSH: gen_alopf1_ddd(instr, gen_helper_pminsh); break; - case OP_PMINUW: gen_alopf1_ddd(instr, gen_helper_pminuw); break; - case OP_PMINSW: gen_alopf1_ddd(instr, gen_helper_pminsw); break; - case OP_PMAXUB: gen_alopf1_ddd(instr, gen_helper_pmaxub); break; - case OP_PMAXSB: gen_alopf1_ddd(instr, gen_helper_pmaxsb); break; - case OP_PMAXUH: gen_alopf1_ddd(instr, gen_helper_pmaxuh); break; - case OP_PMAXSH: gen_alopf1_ddd(instr, gen_helper_pmaxsh); break; - case OP_PMAXUW: gen_alopf1_ddd(instr, gen_helper_pmaxuw); break; - case OP_PMAXSW: gen_alopf1_ddd(instr, gen_helper_pmaxsw); break; - case OP_PCMPEQB: gen_alopf1_ddd(instr, gen_helper_pcmpeqb); break; - case OP_PCMPEQH: gen_alopf1_ddd(instr, gen_helper_pcmpeqh); break; - case OP_PCMPEQW: gen_alopf1_ddd(instr, gen_helper_pcmpeqw); break; - case OP_PCMPEQD: gen_alopf1_ddd(instr, gen_helper_pcmpeqd); break; - case OP_PCMPGTB: gen_alopf1_ddd(instr, gen_helper_pcmpgtb); break; - case OP_PCMPGTH: gen_alopf1_ddd(instr, gen_helper_pcmpgth); break; - case OP_PCMPGTW: gen_alopf1_ddd(instr, gen_helper_pcmpgtw); break; - case OP_PCMPGTD: gen_alopf1_ddd(instr, gen_helper_pcmpgtd); break; - case OP_PADDB: gen_alopf1_ddd(instr, tcg_gen_vec_add8_i64); break; - case OP_PADDH: gen_alopf1_ddd(instr, tcg_gen_vec_add16_i64); break; - case OP_PADDW: gen_alopf1_ddd(instr, tcg_gen_vec_add32_i64); break; - case OP_PADDD: gen_alopf1_ddd(instr, tcg_gen_add_i64); break; - case OP_PADDSB: gen_alopf1_ddd(instr, gen_helper_paddsb); break; - case OP_PADDSH: gen_alopf1_ddd(instr, gen_helper_paddsh); break; - case OP_PADDUSB: gen_alopf1_ddd(instr, gen_helper_paddusb); break; - case OP_PADDUSH: gen_alopf1_ddd(instr, gen_helper_paddush); break; - case OP_PHADDH: gen_alopf1_ddd(instr, gen_helper_phaddh); break; - case OP_PHADDW: gen_alopf1_ddd(instr, gen_helper_phaddw); break; - case OP_PHADDSH: gen_alopf1_ddd(instr, gen_helper_phaddsh); break; - case OP_PSUBB: gen_alopf1_ddd(instr, tcg_gen_vec_sub8_i64); break; - case OP_PSUBH: gen_alopf1_ddd(instr, tcg_gen_vec_sub16_i64); break; - case OP_PSUBW: gen_alopf1_ddd(instr, tcg_gen_vec_sub32_i64); break; - case OP_PSUBD: gen_alopf1_ddd(instr, tcg_gen_sub_i64); break; - case OP_PSUBSB: gen_alopf1_ddd(instr, gen_helper_psubsb); break; - case OP_PSUBSH: gen_alopf1_ddd(instr, gen_helper_psubsh); break; - case OP_PSUBUSB: gen_alopf1_ddd(instr, gen_helper_psubusb); break; - case OP_PSUBUSH: gen_alopf1_ddd(instr, gen_helper_psubush); break; - case OP_PHSUBH: gen_alopf1_ddd(instr, gen_helper_phsubh); break; - case OP_PHSUBW: gen_alopf1_ddd(instr, gen_helper_phsubw); break; - case OP_PHSUBSH: gen_alopf1_ddd(instr, gen_helper_phsubsh); break; - case OP_PMULHH: gen_alopf1_ddd(instr, gen_helper_pmulhh); break; - case OP_PMULLH: gen_alopf1_ddd(instr, gen_helper_pmullh); break; - case OP_PMULHUH: gen_alopf1_ddd(instr, gen_helper_pmulhuh); break; - case OP_PMULUBHH: gen_alopf1_ddd(instr, gen_helper_pmulubhh); break; - case OP_PMULHRSH: gen_alopf1_ddd(instr, gen_helper_pmulhrsh); break; - case OP_PMADDH: gen_alopf1_ddd(instr, gen_helper_pmaddh); break; - case OP_PMADDUBSH: gen_alopf1_ddd(instr, gen_helper_pmaddubsh); break; - case OP_MPSADBH: gen_alopf1_ddd(instr, gen_helper_mpsadbh); break; - case OP_PSADBW: gen_alopf1_ddd(instr, gen_helper_psadbw); break; - case OP_PSIGNB: gen_alopf1_ddd(instr, gen_helper_psignb); break; - case OP_PSIGNH: gen_alopf1_ddd(instr, gen_helper_psignh); break; - case OP_PSIGNW: gen_alopf1_ddd(instr, gen_helper_psignw); break; - case OP_PSLLH: gen_alopf1_ddd(instr, gen_helper_psllh); break; - case OP_PSLLW: gen_alopf1_ddd(instr, gen_helper_psllw); break; - case OP_PSLLD: gen_alopf1_ddd(instr, tcg_gen_shl_i64); break; - case OP_PSRLH: gen_alopf1_ddd(instr, gen_helper_psrlh); break; - case OP_PSRLW: gen_alopf1_ddd(instr, gen_helper_psrlw); break; - case OP_PSRLD: gen_alopf1_ddd(instr, tcg_gen_shr_i64); break; - case OP_PSRAH: gen_alopf1_ddd(instr, gen_helper_psrah); break; - case OP_PSRAW: gen_alopf1_ddd(instr, gen_helper_psraw); break; - case OP_PAVGUSB: gen_alopf1_ddd(instr, gen_helper_pavgusb); break; - case OP_PAVGUSH: gen_alopf1_ddd(instr, gen_helper_pavgush); break; - case OP_PSLLQL: gen_alopf11_dddi(instr, gen_psllql); break; - case OP_PSLLQH: gen_alopf11_dddi(instr, gen_psllqh); break; - case OP_PSRLQL: gen_alopf11_dddi(instr, gen_psrlql); break; - case OP_PSRLQH: gen_alopf11_dddi(instr, gen_psrlqh); break; - case OP_PINSH: gen_alopf11_dddi(instr, gen_pinsh); break; - case OP_PEXTRH: gen_alopf11_dddi(instr, gen_pextrh); break; - case OP_PSHUFH: gen_pshufh(instr); break; - case OP_PSHUFW: gen_alopf11_dddi(instr, gen_pshufw); break; - case OP_PMOVMSKB: gen_alopf1_ddd(instr, gen_helper_pmovmskb); break; - case OP_PMOVMSKPS: gen_alopf1_ddd(instr, gen_helper_pmovmskps); break; - case OP_PMOVMSKPD: gen_alopf1_ddd(instr, gen_helper_pmovmskpd); break; - case OP_PACKSSHB: gen_alopf1_ddd(instr, gen_helper_packsshb); break; - case OP_PACKUSHB: gen_alopf1_ddd(instr, gen_helper_packushb); break; - case OP_PACKSSWH: gen_alopf1_ddd(instr, gen_helper_packsswh); break; - case OP_PACKUSWH: gen_alopf1_ddd(instr, gen_helper_packuswh); break; - case OP_PUNPCKLBH: gen_alopf1_ddd(instr, gen_helper_punpcklbh); break; - case OP_PUNPCKLHW: gen_alopf1_ddd(instr, gen_helper_punpcklhw); break; - case OP_PUNPCKLWD: gen_alopf1_ddd(instr, gen_helper_punpcklwd); break; - case OP_PUNPCKHBH: gen_alopf1_ddd(instr, gen_helper_punpckhbh); break; - case OP_PUNPCKHHW: gen_alopf1_ddd(instr, gen_helper_punpckhhw); break; - case OP_PUNPCKHWD: gen_alopf1_ddd(instr, gen_helper_punpckhwd); break; - case OP_PHMINPOSUH: gen_alopf1_ddd(instr, gen_helper_phminposuh); break; - case OP_GETTAGS: gen_gettag_i32(instr); break; - case OP_GETTAGD: gen_gettag_i64(instr); break; - case OP_PUTTAGS: gen_puttag_i32(instr); break; - case OP_PUTTAGD: gen_puttag_i64(instr); break; - case OP_STAAB: gen_staa_i32(instr, MO_8); break; - case OP_STAAH: gen_staa_i32(instr, MO_16); break; - case OP_STAAW: gen_staa_i32(instr, MO_32); break; - case OP_STAAD: gen_staa_i64(instr); break; - case OP_STAAQ: { - int pair_chan = chan == 2 ? 5 : 2; - if (!ctx->bundle.als_present[pair_chan] || - extract32(ctx->bundle.als[pair_chan], 24, 7) != 0x3f || - (instr->dst & 1) != (chan == 2 ? 0 : 1)) - { - gen_tr_excp_illopc(ctx); - return; - } - gen_staa_i64(instr); - break; - } - case OP_MULS: gen_alopf1_sss(instr, tcg_gen_mul_i32); break; - case OP_MULD: gen_alopf1_ddd(instr, tcg_gen_mul_i64); break; - case OP_UMULX: gen_alopf1_dss(instr, gen_umulx); break; - case OP_SMULX: gen_alopf1_dss(instr, gen_smulx); break; - case OP_RWS: gen_rw_i32(instr); break; - case OP_RWD: gen_rw_i64(instr); break; - case OP_RRS: gen_rr_i32(instr); break; - case OP_RRD: gen_rr_i64(instr); break; - case OP_FDIVS: gen_alopf1_sess(instr, gen_helper_fdivs); break; - case OP_FDIVD: gen_alopf1_dedd(instr, gen_helper_fdivd); break; - case OP_GETSP: gen_getsp(ctx, instr); break; - case OP_UMULHD: gen_alopf1_ddd(instr, gen_umulhd); break; - case OP_SMULHD: gen_alopf1_ddd(instr, gen_smulhd); break; - case OP_FCMPODSF: gen_alopf1_sess(instr, gen_helper_fcmpodsf); break; - case OP_FCMPUDSF: gen_alopf1_sess(instr, gen_helper_fcmpudsf); break; - case OP_FCMPODDF: gen_alopf1_sedd(instr, gen_helper_fcmpoddf); break; - case OP_FCMPUDDF: gen_alopf1_sedd(instr, gen_helper_fcmpoddf); break; - case OP_FXCMPODSF: gen_alopf1_sexs(instr, gen_helper_fxcmpodxf); break; - case OP_FXCMPUDSF: gen_alopf1_sexs(instr, gen_helper_fxcmpudxf); break; - case OP_FXCMPODDF: gen_alopf1_sexd(instr, gen_helper_fxcmpodxf); break; - case OP_FXCMPUDDF: gen_alopf1_sexd(instr, gen_helper_fxcmpudxf); break; - case OP_FXCMPODXF: gen_alopf1_sexx(instr, gen_helper_fxcmpodxf); break; - case OP_FXCMPUDXF: gen_alopf1_sexx(instr, gen_helper_fxcmpudxf); break; - case OP_FSTOIFS: gen_alopf1_sess(instr, gen_helper_fstoifs); break; - case OP_FDTOIFD: gen_alopf1_dedd(instr, gen_helper_fdtoifd); break; - case OP_UDIVX: gen_alopf1_sttds(instr, gen_udivx); break; - case OP_UMODX: gen_alopf1_sttds(instr, gen_umodx); break; - case OP_SDIVX: gen_alopf1_sttds(instr, gen_sdivx); break; - case OP_SMODX: gen_alopf1_sttds(instr, gen_smodx); break; - case OP_PFMULD: gen_alopf1_dedd(instr, gen_helper_fmuld); break; - case OP_PFADDD: gen_alopf1_dedd(instr, gen_helper_faddd); break; - case OP_PFSUBD: gen_alopf1_dedd(instr, gen_helper_fsubd); break; - case OP_PFDIVD: gen_alopf1_dedd(instr, gen_helper_fdivd); break; - case OP_PFMIND: gen_alopf1_dedd(instr, gen_helper_fmind); break; - case OP_PFMAXD: gen_alopf1_dedd(instr, gen_helper_fmaxd); break; - case OP_PFADDS: gen_alopf1_dedd(instr, gen_helper_pfadds); break; - case OP_PFSUBS: gen_alopf1_dedd(instr, gen_helper_pfsubs); break; - case OP_PFMULS: gen_alopf1_dedd(instr, gen_helper_pfmuls); break; - case OP_PFDIVS: gen_alopf1_sess(instr, gen_helper_fdivs); break; - case OP_PFMAXS: gen_alopf1_dedd(instr, gen_helper_pfmaxs); break; - case OP_PFMINS: gen_alopf1_dedd(instr, gen_helper_pfmins); break; - case OP_PFHADDS: gen_alopf1_dedd(instr, gen_helper_pfhadds); break; - case OP_PFHSUBS: gen_alopf1_dedd(instr, gen_helper_pfhsubs); break; - case OP_PFADDSUBS: gen_alopf1_dedd(instr, gen_helper_pfaddsubs); break; - case OP_PFSQRTS: gen_alopf2_ses(instr, gen_helper_fsqrts); break; - case OP_PFSTOIFS: gen_alopf1_dedd(instr, gen_helper_pfstoifs); break; - case OP_PISTOFS: gen_alopf2_ded(instr, gen_helper_pistofs); break; - case OP_PFSTOIS: gen_alopf2_ded(instr, gen_helper_pfstois); break; - case OP_PFSTOISTR: gen_alopf2_ded(instr, gen_helper_pfstoistr); break; - case OP_PFSTOFD: gen_alopf2_des(instr, gen_helper_fstofd); break; - case OP_PFDTOFS: gen_alopf2_sed(instr, gen_helper_fdtofs); break; - case OP_PFDTOIFD: gen_alopf1_dedd(instr, gen_helper_fdtoifd); break; - case OP_PFDTOIS: gen_alopf2_sed(instr, gen_helper_fdtois); break; - case OP_PFDTOISTR: gen_alopf2_sed(instr, gen_helper_fdtoistr); break; - case OP_PFCMPEQS: gen_alopf1_dedd(instr, gen_helper_pfcmpeqs); break; - case OP_PFCMPLTS: gen_alopf1_dedd(instr, gen_helper_pfcmplts); break; - case OP_PFCMPLES: gen_alopf1_dedd(instr, gen_helper_pfcmples); break; - case OP_PFCMPUODS: gen_alopf1_dedd(instr, gen_helper_pfcmpuods); break; - case OP_PFCMPNEQS: gen_alopf1_dedd(instr, gen_helper_pfcmpneqs); break; - case OP_PFCMPNLTS: gen_alopf1_dedd(instr, gen_helper_pfcmpnlts); break; - case OP_PFCMPNLES: gen_alopf1_dedd(instr, gen_helper_pfcmpnles); break; - case OP_PFCMPODS: gen_alopf1_dedd(instr, gen_helper_pfcmpods); break; - case OP_PFCMPEQD: gen_alopf1_dedd(instr, gen_helper_fcmpeqd); break; - case OP_PFCMPLTD: gen_alopf1_dedd(instr, gen_helper_fcmpltd); break; - case OP_PFCMPLED: gen_alopf1_dedd(instr, gen_helper_fcmpled); break; - case OP_PFCMPUODD: gen_alopf1_dedd(instr, gen_helper_fcmpuodd); break; - case OP_PFCMPNEQD: gen_alopf1_dedd(instr, gen_helper_fcmpneqd); break; - case OP_PFCMPNLTD: gen_alopf1_dedd(instr, gen_helper_fcmpnltd); break; - case OP_PFCMPNLED: gen_alopf1_dedd(instr, gen_helper_fcmpnled); break; - case OP_PFCMPODD: gen_alopf1_dedd(instr, gen_helper_fcmpodd); break; - case OP_FSCALED: gen_alopf1_deds(instr, gen_helper_fscaled); break; - case OP_FSCALES: gen_alopf1_sess(instr, gen_helper_fscales); break; - case OP_FXSCALESX: gen_alopf1_xexi(instr, gen_helper_fxscalesx); break; - case OP_FRCPS: gen_alopf2_ses(instr, gen_helper_frcps); break; - case OP_FSQRTS: gen_alopf2_ses(instr, gen_helper_fsqrts); break; - case OP_FRSQRTS: gen_alopf2_ses(instr, gen_helper_frsqrts); break; -#ifndef TARGET_E2K_PRECISE_FSQRTID - case OP_FSQRTID: gen_alopf2_dd(instr, tcg_gen_mov_i64); break; - case OP_FXSQRTISX: gen_alopf2_sx(instr, gen_fstofx); break; - case OP_FXSQRTIDX: gen_alopf2_dx(instr, gen_fdtofx); break; - case OP_FXSQRTIXX: gen_alopf2_xx(instr, gen_mov_f80); break; - /* FIXME: these are not ALOPF2! */ - case OP_FXSQRTUSX: /* fallthrough */ - case OP_FXSQRTUDX: /* fallthrough */ - case OP_FXSQRTUXX: gen_alopf2_xx(instr, gen_mov_f80); break; -#else -#error Not implemented -#endif - case OP_PFSQRTTD: /* fallthrough */ - case OP_FSQRTTD: gen_alopf1_dedd(instr, gen_helper_fsqrttd); break; - case OP_FXSQRTTSX: gen_alopf1_xsx(instr, gen_helper_fxsqrttxx); break; - case OP_FXSQRTTDX: gen_alopf1_xdx(instr, gen_helper_fxsqrttxx); break; - case OP_FXSQRTTXX: gen_alopf1_xxx(instr, gen_helper_fxsqrttxx); break; - case OP_INSFS: gen_alopf21_i32(instr, gen_insfs); break; - case OP_INSFD: gen_insfd(instr); break; - case OP_PSHUFB: gen_alopf21_i64(instr, gen_helper_pshufb); break; - case OP_PMERGE: gen_alopf21_i64(instr, gen_helper_pmerge); break; - case OP_FXDIVTSS: - case OP_FXDIVTDD: - case OP_FXDIVTSX: - case OP_FXDIVTDX: - case OP_VFSI: - case OP_LDCSB: - case OP_LDDSB: - case OP_LDESB: - case OP_LDFSB: - case OP_LDGSB: - case OP_LDSSB: - case OP_LDCSH: - case OP_LDDSH: - case OP_LDESH: - case OP_LDFSH: - case OP_LDGSH: - case OP_LDSSH: - case OP_LDCSW: - case OP_LDDSW: - case OP_LDESW: - case OP_LDFSW: - case OP_LDGSW: - case OP_LDSSW: - case OP_LDCSD: - case OP_LDDSD: - case OP_LDESD: - case OP_LDFSD: - case OP_LDGSD: - case OP_LDSSD: - case OP_MOVTRS: - case OP_MOVTRCS: - case OP_MOVTRD: - case OP_MOVTRCD: - case OP_GETSAP: - case OP_CUDTOAP: - case OP_GDTOAP: - case OP_STCSB: - case OP_STDSB: - case OP_STESB: - case OP_STFSB: - case OP_STGSB: - case OP_STSSB: - case OP_STCSH: - case OP_STDSH: - case OP_STESH: - case OP_STFSH: - case OP_STGSH: - case OP_STSSH: - case OP_STCSW: - case OP_STDSW: - case OP_STESW: - case OP_STFSW: - case OP_STGSW: - case OP_STSSW: - case OP_STCSD: - case OP_STDSD: - case OP_STESD: - case OP_STFSD: - case OP_STGSD: - case OP_STSSD: - case OP_CCTOPO: - case OP_CCTOPB: - case OP_CCTOPE: - case OP_CCTOPBE: - case OP_CCTOPS: - case OP_CCTOPP: - case OP_CCTOPL: - case OP_CCTOPLE: - /* - case OP_AAURW: - case OP_AAURWS: - case OP_AAURWD: - case OP_AAURWQ: - case OP_AAURR: - case OP_AAURRD: - case OP_AAURRQ: - */ - case OP_APTOAP: - case OP_APTOAPB: - case OP_GETVA: - case OP_LDRD: - case OP_PUTTC: - case OP_CAST: - case OP_TDTOMP: - case OP_ODTOAP: - case OP_LDCUDB: - case OP_LDCUDH: - case OP_LDCUDW: - case OP_LDCUDD: - case OP_LDCUDQ: - case OP_LDAPB: - case OP_LDAPH: - case OP_LDAPW: - case OP_LDAPD: - case OP_LDAPQ: - case OP_LDODWB: - case OP_LDODWD: - case OP_LDODWH: - case OP_LDODWQ: - case OP_LDODWW: - case OP_LDODPB: - case OP_LDODPD: - case OP_LDODPH: - case OP_LDODPQ: - case OP_LDODPW: - case OP_LDODRB: - case OP_LDODRD: - case OP_LDODRH: - case OP_LDODRQ: - case OP_LDODRW: - case OP_LDCSQ: - case OP_LDDSQ: - case OP_LDESQ: - case OP_LDFSQ: - case OP_LDGSQ: - case OP_LDSSQ: - case OP_GETTD: - case OP_GETTC: - case OP_INVTC: - case OP_GETSOD: - case OP_STCSQ: - case OP_STDSQ: - case OP_STESQ: - case OP_STFSQ: - case OP_STGSQ: - case OP_STSSQ: - case OP_STRD: - case OP_STAPB: - case OP_STAPH: - case OP_STAPW: - case OP_STAPD: - case OP_STAPQ: - case OP_STODPB: - case OP_STODPD: - case OP_STODPH: - case OP_STODPQ: - case OP_STODPW: - case OP_STODRB: - case OP_STODRD: - case OP_STODRH: - case OP_STODRQ: - case OP_STODRW: - case OP_STODWB: - case OP_STODWD: - case OP_STODWH: - case OP_STODWQ: - case OP_STODWW: - case OP_MOVTRQ: - case OP_MOVTRCQ: - case OP_PUTTST: - case OP_STAAQP: - case OP_QPAND: - case OP_QPANDN: - case OP_QPOR: - case OP_QPXOR: - case OP_QPADDB: - case OP_QPADDH: - case OP_QPADDSB: - case OP_QPADDSH: - case OP_QPADDUSB: - case OP_QPADDUSH: - case OP_QPADDW: - case OP_QPADDD: - case OP_QPSUBB: - case OP_QPSUBH: - case OP_QPSUBSB: - case OP_QPSUBSH: - case OP_QPSUBUSB: - case OP_QPSUBUSH: - case OP_QPSUBW: - case OP_QPSUBD: - case OP_QPFADDS: - case OP_QPFADDD: - case OP_QPFHADDS: - case OP_QPFHSUBS: - case OP_QPFADDSUBS: - case OP_QPFADDSUBD: - case OP_QPFSTOIFS: - case OP_QPFDTOIFD: - case OP_QPFMINS: - case OP_QPFMIND: - case OP_QPFMAXS: - case OP_QPFMAXD: - case OP_QPFMULS: - case OP_QPFMULD: - case OP_QPFSUBS: - case OP_QPFSUBD: - case OP_QPMSK2SGNB: - case OP_QPPACKDL: - case OP_QPSLLH: - case OP_QPSLLW: - case OP_QPSLLD: - case OP_QPSRLH: - case OP_QPSRLW: - case OP_QPSRLD: - case OP_QPSRAH: - case OP_QPSRAW: - case OP_QPACKSSHB: - case OP_QPACKSSWH: - case OP_QPACKUSHB: - case OP_QPACKUSWH: - case OP_QPAVGUSB: - case OP_QPAVGUSH: - case OP_QPCMPEQB: - case OP_QPCMPEQD: - case OP_QPCMPEQH: - case OP_QPCMPEQW: - case OP_QPCMPGTB: - case OP_QPCMPGTD: - case OP_QPCMPGTH: - case OP_QPCMPGTW: - case OP_QPHADDH: - case OP_QPHADDSH: - case OP_QPHADDW: - case OP_QPHSUBH: - case OP_QPHSUBSH: - case OP_QPHSUBW: - case OP_QPMAXSB: - case OP_QPMAXSH: - case OP_QPMAXSW: - case OP_QPMAXUB: - case OP_QPMAXUH: - case OP_QPMAXUW: - case OP_QPMINSB: - case OP_QPMINSH: - case OP_QPMINSW: - case OP_QPMINUB: - case OP_QPMINUH: - case OP_QPMINUW: - case OP_QPMULHH: - case OP_QPMULHRSH: - case OP_QPMULHUH: - case OP_QPMULLH: - case OP_QPMULUBHH: - case OP_QPSIGNB: - case OP_QPSIGNH: - case OP_QPSIGNW: - case OP_QPHMINPOSUH: - case OP_QPMADDH: - case OP_QPMADDUBSH: - case OP_QPMPSADBH: - case OP_QPSADBW: - case OP_QPSRCD: - case OP_QPSRCW: - case OP_PSRCD: - case OP_PSRCW: - case OP_GETFZS: - case OP_GETFZD: - case OP_PUTTAGQP: - case OP_PMULLW: - case OP_QPMULLW: - case OP_QPFCMPEQS: - case OP_QPFCMPLTS: - case OP_QPFCMPLES: - case OP_QPFCMPUODS: - case OP_QPFCMPNEQS: - case OP_QPFCMPNLTS: - case OP_QPFCMPNLES: - case OP_QPFCMPODS: - case OP_QPFCMPEQD: - case OP_QPFCMPLTD: - case OP_QPFCMPLED: - case OP_QPFCMPUODD: - case OP_QPFCMPNEQD: - case OP_QPFCMPNLTD: - case OP_QPFCMPNLED: - case OP_QPFCMPODD: - case OP_LDQ: - case OP_LDQP: - case OP_LDGDQP: - case OP_LDCUDQP: - case OP_LDCSQP: - case OP_LDDSQP: - case OP_LDESQP: - case OP_LDFSQP: - case OP_LDGSQP: - case OP_LDSSQP: - case OP_LDAPQP: - case OP_LDRQP: - case OP_QPSGN2MSKB: - case OP_QPSWITCHW: - case OP_QPSWITCHD: - case OP_QPFSTOIS: - case OP_QPFSTOISTR: - case OP_QPISTOFS: - case OP_QPFSTOID: - case OP_QPFSTOIDTR: - case OP_QPISTOFD: - case OP_QPFSTOFD: - case OP_QPFDTOIS: - case OP_QPFDTOISTR: - case OP_QPIDTOFS: - case OP_QPFDTOFS: - case OP_QPFDTOID: - case OP_QPFDTOIDTR: - case OP_QPIDTOFD: - case OP_STQ: - case OP_STGDMQP: - case OP_STGDQP: - case OP_STAPQP: - case OP_STAPMQP: - case OP_STMQP: - case OP_STQP: - case OP_STCSMQP: - case OP_STCSQP: - case OP_STDSMQP: - case OP_STDSQP: - case OP_STESMQP: - case OP_STESQP: - case OP_STFSMQP: - case OP_STFSQP: - case OP_STGSMQP: - case OP_STGSQP: - case OP_STSSMQP: - case OP_STSSQP: - case OP_STRQP: - case OP_ADDCD: - case OP_ADDCD_C: - case OP_SUBCD: - case OP_SUBCD_C: - case OP_VFBGV: - case OP_MKFSW: - case OP_MODBGV: - case OP_PCMPEQBOP: - case OP_PCMPEQHOP: - case OP_PCMPEQWOP: - case OP_PCMPEQDOP: - case OP_PCMPGTBOP: - case OP_PCMPGTHOP: - case OP_PCMPGTWOP: - case OP_PCMPGTDOP: - case OP_PCMPEQBAP: - case OP_PCMPEQHAP: - case OP_PCMPEQWAP: - case OP_PCMPEQDAP: - case OP_PCMPGTBAP: - case OP_PCMPGTHAP: - case OP_PCMPGTWAP: - case OP_PCMPGTDAP: - case OP_QPCMPEQBOP: - case OP_QPCMPEQHOP: - case OP_QPCMPEQWOP: - case OP_QPCMPEQDOP: - case OP_QPCMPGTBOP: - case OP_QPCMPGTHOP: - case OP_QPCMPGTWOP: - case OP_QPCMPGTDOP: - case OP_QPCMPEQBAP: - case OP_QPCMPEQHAP: - case OP_QPCMPEQWAP: - case OP_QPCMPEQDAP: - case OP_QPCMPGTBAP: - case OP_QPCMPGTHAP: - case OP_QPCMPGTWAP: - case OP_QPCMPGTDAP: - case OP_PMRGP: - case OP_QPMRGP: - case OP_CLMULH: - case OP_CLMULL: - case OP_IBRANCHD: - case OP_ICALLD: - case OP_QPCEXT_0X00: - case OP_QPCEXT_0X7F: - case OP_QPCEXT_0X80: - case OP_QPCEXT_0XFF: - case OP_FMAS: - case OP_FMSS: - case OP_FNMAS: - case OP_FNMSS: - case OP_FMAD: - case OP_FMSD: - case OP_FNMAD: - case OP_FNMSD: - case OP_QPFMAS: - case OP_QPFMSS: - case OP_QPFNMAS: - case OP_QPFNMSS: - case OP_QPFMAD: - case OP_QPFMSD: - case OP_QPFNMAD: - case OP_QPFNMSD: - case OP_QPFMASS: - case OP_QPFMSAS: - case OP_QPFMASD: - case OP_QPFMSAD: - e2k_todo_illop(ctx, "unimplemented %d (%s)", op, name); break; - } -} - -typedef enum { - ICOMB_AND = 0, - ICOMB_ANDN = 1, - ICOMB_OR = 2, - ICOMB_ORN = 3, - ICOMB_XOR = 4, - ICOMB_XORN = 5, - ICOMB_RSUB = 6, - ICOMB_MERGE = 7, - ICOMB_ADD = 8, - ICOMB_SUB = 9, - ICOMB_SCL = 10, - ICOMB_SCR = 11, - ICOMB_SHL = 12, - ICOMB_SHR = 13, - ICOMB_SAR = 14, - ICOMB_GETF = 15, -} IComb; - -#define IMPL_GEN_ICOMB_OP(S) \ - static void glue(gen_icomb_op_, S)(Instr *instr, IComb opc, \ - glue(TCGv_, S) ret, glue(TCGv_, S) arg1, glue(TCGv_, S) arg2) \ - { \ - switch(opc) { \ - case ICOMB_AND: glue(tcg_gen_and_, S)(ret, arg1, arg2); break; \ - case ICOMB_ANDN: glue(gen_andn_, S)(ret, arg1, arg2); break; \ - case ICOMB_OR: glue(tcg_gen_or_, S)(ret, arg1, arg2); break; \ - case ICOMB_ORN: glue(gen_orn_, S)(ret, arg1, arg2); break; \ - case ICOMB_XOR: glue(tcg_gen_xor_, S)(ret, arg1, arg2); break; \ - case ICOMB_XORN: glue(gen_xorn_, S)(ret, arg1, arg2); break; \ - case ICOMB_RSUB: glue(tcg_gen_sub_, S)(ret, arg2, arg1); break; \ - case ICOMB_MERGE: { \ - TCGv_i32 t0 = tcg_temp_new_i32(); \ - gen_mrgc_i32(instr->ctx, instr->chan, t0); \ - glue(gen_merge_, S)(ret, arg1, arg2, t0); \ - tcg_temp_free_i32(t0); \ - break; \ - } \ - case ICOMB_ADD: glue(tcg_gen_add_, S)(ret, arg1, arg2); break; \ - case ICOMB_SUB: glue(tcg_gen_sub_, S)(ret, arg1, arg2); break; \ - case ICOMB_SCL: glue(tcg_gen_rotl_, S)(ret, arg1, arg2); break; \ - case ICOMB_SCR: glue(tcg_gen_rotr_, S)(ret, arg1, arg2); break; \ - case ICOMB_SHL: glue(tcg_gen_shl_, S)(ret, arg1, arg2); break; \ - case ICOMB_SHR: glue(tcg_gen_shr_, S)(ret, arg1, arg2); break; \ - case ICOMB_SAR: glue(tcg_gen_sar_, S)(ret, arg1, arg2); break; \ - case ICOMB_GETF: glue(gen_getf_, S)(ret, arg1, arg2); break; \ - default: g_assert_not_reached(); break; \ - } \ - } - -IMPL_GEN_ICOMB_OP(i64) -IMPL_GEN_ICOMB_OP(i32) - -static inline bool icomb_check(Instr *instr, IComb opc1, IComb opc2) -{ - if (!is_chan_14(instr->chan)) { - return false; - } - - if (instr->ctx->version == 1) { - return opc1 != ICOMB_RSUB; - } else { - return opc1 != ICOMB_RSUB - && opc2 < ICOMB_SCL - && opc2 != ICOMB_MERGE; - } -} - -typedef enum { - FCOMB_ADD = 0, - FCOMB_SUB = 1, - FCOMB_HADD = 2, - FCOMB_HSUB = 3, - FCOMB_MUL = 4, - FCOMB_RSUB = 5, - FCOMB_ADDSUB = 7, - FCOMB_COUNT = 8, -} FComb; - -static inline bool fcomb_is_add_unit(FComb op) -{ - switch (op) { - case FCOMB_ADD: - case FCOMB_SUB: - case FCOMB_RSUB: - return true; - default: - return false; - } -} - -static inline bool fcomb_is_mul_unit(FComb op) -{ - return op == FCOMB_MUL; -} - -static inline bool fcomb_check(Instr *instr, FComb opc1, FComb opc2) -{ - int ver = instr->ctx->version; - - if (opc1 == FCOMB_RSUB || (ver < 4 && is_chan_25(instr->chan))) { - return false; - } - - if (ver >= 2) { - return (fcomb_is_add_unit(opc1) || fcomb_is_mul_unit(opc1)) - && fcomb_is_add_unit(opc2); - } else { - return fcomb_is_add_unit(opc1) == fcomb_is_mul_unit(opc2); - } -} - -static bool pfcomb_map[FCOMB_COUNT][FCOMB_COUNT] = { false }; - -static void pfcomb_init(DisasContext *ctx) -{ - pfcomb_map[FCOMB_MUL][FCOMB_ADD] = true; - pfcomb_map[FCOMB_MUL][FCOMB_SUB] = true; - pfcomb_map[FCOMB_MUL][FCOMB_RSUB] = true; - - if (ctx->version == 1) { - pfcomb_map[FCOMB_ADD][FCOMB_MUL] = true; - pfcomb_map[FCOMB_SUB][FCOMB_MUL] = true; - } - - if (ctx->version >= 2) { - pfcomb_map[FCOMB_ADD][FCOMB_ADD] = true; - pfcomb_map[FCOMB_ADD][FCOMB_SUB] = true; - pfcomb_map[FCOMB_ADD][FCOMB_RSUB] = true; - - pfcomb_map[FCOMB_SUB][FCOMB_ADD] = true; - pfcomb_map[FCOMB_SUB][FCOMB_SUB] = true; - pfcomb_map[FCOMB_SUB][FCOMB_RSUB] = true; - } - - if (ctx->version >= 3) { - pfcomb_map[FCOMB_HADD][FCOMB_ADD] = true; - pfcomb_map[FCOMB_HADD][FCOMB_SUB] = true; - pfcomb_map[FCOMB_HADD][FCOMB_RSUB] = true; - pfcomb_map[FCOMB_HADD][FCOMB_HADD] = true; - pfcomb_map[FCOMB_HADD][FCOMB_HSUB] = true; - pfcomb_map[FCOMB_HADD][FCOMB_ADDSUB] = true; - - pfcomb_map[FCOMB_HSUB][FCOMB_ADD] = true; - pfcomb_map[FCOMB_HSUB][FCOMB_SUB] = true; - pfcomb_map[FCOMB_HSUB][FCOMB_RSUB] = true; - pfcomb_map[FCOMB_HSUB][FCOMB_HADD] = true; - pfcomb_map[FCOMB_HSUB][FCOMB_HSUB] = true; - pfcomb_map[FCOMB_HSUB][FCOMB_ADDSUB] = true; - - pfcomb_map[FCOMB_ADDSUB][FCOMB_ADD] = true; - pfcomb_map[FCOMB_ADDSUB][FCOMB_SUB] = true; - pfcomb_map[FCOMB_ADDSUB][FCOMB_RSUB] = true; - pfcomb_map[FCOMB_ADDSUB][FCOMB_HADD] = true; - pfcomb_map[FCOMB_ADDSUB][FCOMB_HSUB] = true; - pfcomb_map[FCOMB_ADDSUB][FCOMB_ADDSUB] = true; - - pfcomb_map[FCOMB_ADD][FCOMB_HADD] = true; - pfcomb_map[FCOMB_ADD][FCOMB_HSUB] = true; - pfcomb_map[FCOMB_ADD][FCOMB_ADDSUB] = true; - - pfcomb_map[FCOMB_SUB][FCOMB_HADD] = true; - pfcomb_map[FCOMB_SUB][FCOMB_HSUB] = true; - pfcomb_map[FCOMB_SUB][FCOMB_ADDSUB] = true; - - pfcomb_map[FCOMB_MUL][FCOMB_HADD] = true; - pfcomb_map[FCOMB_MUL][FCOMB_HSUB] = true; - pfcomb_map[FCOMB_MUL][FCOMB_ADDSUB] = true; - } -} - -static inline bool pfcomb_check(Instr *instr, FComb opc1, FComb opc2) -{ - int ver = instr->ctx->version; - - if (ver < 4 && is_chan_25(instr->chan)) { - return false; - } - - return pfcomb_map[opc1][opc2]; -} - -#define IMPL_GEN_FCOMB_OP(S, T) \ - static void glue(gen_fcomb_op_, S)(Instr *instr, FComb opc, \ - glue(TCGv_, S) ret, glue(TCGv_, S) arg1, glue(TCGv_, S) arg2) \ - { \ - switch(opc) { \ - case FCOMB_ADD: glue(gen_helper_fadd, T)(ret, cpu_env, arg1, arg2); break; \ - case FCOMB_SUB: glue(gen_helper_fsub, T)(ret, cpu_env, arg1, arg2); break; \ - case FCOMB_MUL: glue(gen_helper_fmul, T)(ret, cpu_env, arg1, arg2); break; \ - case FCOMB_RSUB: glue(gen_helper_fsub, T)(ret, cpu_env, arg2, arg1); break; \ - default: gen_tr_excp_illopc(instr->ctx); break; \ - } \ - } - -IMPL_GEN_FCOMB_OP(i64, d) -IMPL_GEN_FCOMB_OP(i32, s) - -static void gen_pfcomb_op_i32(Instr *instr, FComb opc, - TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) -{ - switch (opc) { - case FCOMB_ADD: gen_helper_pfadds(ret, cpu_env, arg1, arg2); break; - case FCOMB_SUB: gen_helper_pfsubs(ret, cpu_env, arg1, arg2); break; - case FCOMB_HADD: gen_helper_pfhadds(ret, cpu_env, arg1, arg2); break; - case FCOMB_HSUB: gen_helper_pfhsubs(ret, cpu_env, arg1, arg2); break; - case FCOMB_MUL: gen_helper_pfmuls(ret, cpu_env, arg1, arg2); break; - case FCOMB_RSUB: gen_helper_pfsubs(ret, cpu_env, arg2, arg1); break; - case FCOMB_ADDSUB: gen_helper_pfaddsubs(ret, cpu_env, arg1, arg2); break; - default: gen_tr_excp_illopc(instr->ctx); break; - } -} - -static void gen_pfcomb_op_i64(Instr *instr, FComb opc, - TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) -{ - switch (opc) { - case FCOMB_ADD: gen_helper_faddd(ret, cpu_env, arg1, arg2); break; - case FCOMB_SUB: gen_helper_fsubd(ret, cpu_env, arg1, arg2); break; - case FCOMB_MUL: gen_helper_fmuld(ret, cpu_env, arg1, arg2); break; - case FCOMB_RSUB: gen_helper_fsubd(ret, cpu_env, arg2, arg1); break; - default: gen_tr_excp_illopc(instr->ctx); break; - } -} - -static inline int comb_opc1(Instr *instr, int m1) -{ - return (instr->opc1 >> 1) & m1; -} - -static inline int comb_opc2(Instr *instr, int m1, int m2) -{ - return ((instr->opc2 & m2) << 2) | ((instr->opc1 >> 5) & m1); -} - -#define icomb_opc1(instr) comb_opc1(instr, 0xf) -#define fcomb_opc1(instr) comb_opc1(instr, 0x7) - -#define icomb_opc2(instr) comb_opc2(instr, 0x3, 0x3) -#define fcomb_opc2(instr) comb_opc2(instr, 0x3, 0x1) - -#define IMPL_GEN_COMB(NAME, P, S, T, OP) \ - static void NAME(Instr *instr, int opc1, int opc2) \ - { \ - glue(Src, T) s1 = glue(get_src1_, S)(instr); \ - glue(Src, T) s2 = glue(get_src2_, S)(instr); \ - glue(Src, T) s3 = glue(get_src3_, S)(instr); \ - TCGv_i32 tag = get_temp_i32(instr); \ - glue(TCGv_, S) dst = glue(get_temp_, S)(instr); \ - glue(gen_tag3_, S)(tag, s1.tag, s2.tag, s3.tag); \ - OP(instr, opc1, dst, s1.value, s2.value); \ - OP(instr, opc2, dst, s3.value, dst); \ - glue(gen_al_result_, S)(instr, dst, tag); \ - } - -IMPL_GEN_COMB(gen_icomb_i64, icomb, i64, 64, gen_icomb_op_i64) -IMPL_GEN_COMB(gen_icomb_i32, icomb, i32, 32, gen_icomb_op_i32) -IMPL_GEN_COMB(gen_fcomb_i64, fcomb, i64, 64, gen_fcomb_op_i64) -IMPL_GEN_COMB(gen_fcomb_i32, fcomb, i32, 32, gen_fcomb_op_i32) -IMPL_GEN_COMB(gen_pfcomb_i64, pfcomb, i64, 64, gen_pfcomb_op_i64) -IMPL_GEN_COMB(gen_pfcomb_i32, pfcomb, i64, 64, gen_pfcomb_op_i32) - -#define IMPL_GEN_COMB_SELECT(NAME) \ - static void glue(gen_, NAME)(Instr *instr, uint32_t op) \ - { \ - int opc1 = op & 0xffff; \ - int opc2 = op >> 16; \ - \ - if (instr->opc1 & 1) { \ - glue3(gen_, NAME, _i64)(instr, opc1, opc2); \ - } else { \ - glue3(gen_, NAME, _i32)(instr, opc1, opc2); \ - } \ - } - -IMPL_GEN_COMB_SELECT(icomb) -IMPL_GEN_COMB_SELECT(fcomb) -IMPL_GEN_COMB_SELECT(pfcomb) - -static void gen_lcomb_i64(Instr *instr, uint32_t base) -{ - /* see gen_alopf21_i64 */ - Src64 s1 = get_src1_i64(instr); - Src64 s2 = get_src2_i64(instr); - Src64 s3 = get_src3_i64(instr); - TCGv_i32 tag = get_temp_i32(instr); - TCGv_i64 dst = get_temp_i64(instr); - TCGv_i32 opc = tcg_const_i32(base + instr->opc1); - - check_args(ALOPF21, instr); - gen_tag3_i64(tag, s1.tag, s2.tag, s3.tag); - gen_helper_plog(dst, opc, s1.value, s2.value, s3.value); - gen_al_result_i64(instr, dst, tag); -} - -static inline bool rlp_check_chan(uint16_t rlp, int chan) -{ - return extract16(rlp, 14, 1) == (chan > 2) && - extract16(rlp, 10 + chan % 3, 1); -} - -static inline bool rlp_is_chan_pred(uint16_t rlp, int chan) -{ - return !extract16(rlp, 15, 1) && rlp_check_chan(rlp, chan); -} - -static void chan_check_preds(DisasContext *ctx, int chan, TCGLabel *l) -{ - unsigned int i; - bool has_pcnt = false; - bool has_preg = false; - TCGv_i32 t0 = tcg_temp_new_i32(); - TCGv_i32 t1 = tcg_temp_new_i32(); - TCGv_i32 t2 = tcg_temp_new_i32(); - - tcg_gen_movi_i32(t0, 0); - tcg_gen_movi_i32(t1, 0); - - for (i = 0; i < 3; i++) { - unsigned int j; - uint16_t *cds = (uint16_t *) &ctx->bundle.cds[i]; - - if (!ctx->bundle.cds_present[i]) { - continue; - } - - for (j = 0; j < 2; j++) { - uint16_t rlp = cds[j]; - uint8_t kind = extract8(rlp, 5, 2); - uint8_t idx = extract8(rlp, 0, 5); - bool invert = extract16(rlp, 7 + chan % 3, 1); - - if (!rlp_is_chan_pred(rlp, chan)) { - continue; - } - - switch(kind) { - case 0x2: { /* %pcntN */ - has_pcnt = true; - tcg_gen_setcondi_i32(TCG_COND_LEU, t2, e2k_cs.lsr_pcnt, idx); - if (invert) { - tcg_gen_xori_i32(t2, t2, 1); - } - tcg_gen_or_i32(t0, t0, t2); - break; - } - case 0x3: /* %predN */ - has_preg = true; - e2k_gen_preg_i32(t2, idx); - if (invert) { - tcg_gen_xori_i32(t2, t2, 1); - } - tcg_gen_or_i32(t1, t1, t2); - break; - default: - if (ctx->strict) { - gen_tr_excp_illopc(ctx); - } - break; - } - } - } - - if (has_preg || has_pcnt) { - TCGv_i32 cond = e2k_get_temp_i32(ctx); - - if (has_preg && has_pcnt) { - tcg_gen_and_i32(cond, t0, t1); - } else if (has_preg) { - tcg_gen_mov_i32(cond, t1); - } else { - tcg_gen_mov_i32(cond, t0); - } - - ctx->al_cond[chan] = cond; - tcg_gen_brcondi_i32(TCG_COND_EQ, cond, 0, l); - } - - tcg_temp_free_i32(t2); - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t0); -} - -static inline void alop_instr_init(Instr *instr, DisasContext *ctx, int chan) -{ - memset(instr, 0, sizeof(Instr)); - - instr->ctx = ctx; - instr->chan = chan; - instr->mas = ctx->bundle2.cs1.type == CS1_MAS ? ctx->bundle2.cs1.mas[chan] : 0; - instr->als = ctx->bundle.als[chan]; - instr->ales = ctx->bundle.ales[chan]; - instr->ales_present = ctx->bundle.ales_present[chan]; -} - -static void alop_decode(Instr *instr) -{ - Alop *alop = &instr->ctx->bundle2.alops[instr->chan]; - - alop->format = ALOPF_NONE; - alop->op = 0; - alop->name = "none"; - - switch (instr->opc2) { - case SHORT: - case EXT: - case EXT1: - case EXT2: { - AlopDesc *desc = find_op(instr); - if (!desc) { - gen_tr_excp_illopc(instr->ctx); - return; - } - alop->format = desc->alopf; - alop->op = desc->op; - alop->name = desc->dsc; - break; - } - case ICMB0: - case ICMB1: - case ICMB2: - case ICMB3: - if (instr->opc2 == ICMB3 - && (instr->opc1 == 0x6c || instr->opc1 == 0x6d)) - { - if (!is_chan_0134(instr->chan)) { - gen_tr_excp_illopc(instr->ctx); - return; - } - alop->format = ALOPF21; - alop->op = instr->opc1 & 1 ? OP_INSFD : OP_INSFS; - } else { - int opc1 = icomb_opc1(instr); - int opc2 = icomb_opc2(instr); - if (!icomb_check(instr, opc1, opc2)) { - gen_tr_excp_illopc(instr->ctx); - return; - } - alop->format = ALOPF21_ICOMB; - alop->op = (opc2 << 16) | opc1; - } - break; - case FLB: - case FLH: - case FLW: - case FLD: - e2k_todo_illop(instr->ctx, "flags ops"); - break; - case FCMB0: - case FCMB1: { - int opc1 = fcomb_opc1(instr); - int opc2 = fcomb_opc2(instr); - if (!fcomb_check(instr, opc1, opc2)) { - gen_tr_excp_illopc(instr->ctx); - return; - } - alop->format = ALOPF21_FCOMB; - alop->op = (opc2 << 16) | opc1; - break; - } - case PFCMB0: - case PFCMB1: - if (instr->opc2 == PFCMB1 && is_chan_0134(instr->chan) - && instr->ctx->version >= 2 && instr->opc1 == 0x4d) - { - alop->format = ALOPF12_PSHUFH; - alop->op = OP_PSHUFB; - } else if (instr->opc2 == PFCMB1 && is_chan_0134(instr->chan) - && instr->ctx->version >= 2 && instr->opc1 == 0x6d) - { - alop->format = ALOPF21; - alop->op = OP_PMERGE; - } else { - int opc1 = fcomb_opc1(instr); - int opc2 = fcomb_opc2(instr); - if (!pfcomb_check(instr, opc1, opc2)) { - gen_tr_excp_illopc(instr->ctx); - return; - } - alop->format = ALOPF21_PFCOMB; - alop->op = (opc2 << 16) | opc1; - } - break; - case LCMBD0: - case LCMBD1: - if (is_chan_0134(instr->chan) && instr->ctx->version >= 5) { - alop->format = ALOPF21_LCOMB; - alop->op = instr->opc2 == LCMBD0 ? 0 : 0x80; - } else { - gen_tr_excp_illopc(instr->ctx); - } - break; - case LCMBQ0: - case LCMBQ1: - e2k_todo_illop(instr->ctx, "logical combined ops"); - break; - case QPFCMB0: - case QPFCMB1: - e2k_todo_illop(instr->ctx, "packed128 float combined ops"); - break; - default: - gen_tr_excp_illopc(instr->ctx); - break; - } -} - -void e2k_alc_decode(DisasContext *ctx) -{ - int i; - - for (i = 0; i < 6; i++) { - if (ctx->bundle.als_present[i]) { - Instr instr; - alop_instr_init(&instr, ctx, i); - alop_decode(&instr); - } - } -} - -static void gen_alop(Instr *instr, Alop *alop) -{ - TCGLabel *l0 = gen_new_label(); - - if (alop->format == ALOPF_NONE) { - return; - } - - chan_check_preds(instr->ctx, instr->chan, l0); - check_args(alop->format, instr); - - switch (alop->format) { - case ALOPF21_ICOMB: - gen_icomb(instr, alop->op); - break; - case ALOPF21_FCOMB: - gen_fcomb(instr, alop->op); - break; - case ALOPF21_PFCOMB: - gen_pfcomb(instr, alop->op); - break; - case ALOPF21_LCOMB: - gen_lcomb_i64(instr, alop->op); - break; - default: - gen_alop_simple(instr, alop->op, alop->name); - break; - } - - gen_set_label(l0); - - if (instr->aaincr_len != 0) { - gen_aasti_incr(instr->ctx, instr); - } -} - -static void gen_alops(DisasContext *ctx) -{ - int i; - - for (i = 0; i < 6; i++) { - Instr instr; - Alop *alop = &ctx->bundle2.alops[i]; - ctx->al_results[i].type = AL_RESULT_NONE; - ctx->al_cond[i] = NULL; - alop_instr_init(&instr, ctx, i); - gen_alop(&instr, alop); - } -} - -void e2k_alc_execute(DisasContext *ctx) -{ - gen_alops(ctx); -} - -static inline void gen_al_result_commit_reg32(bool poison, TCGv_i32 index, - TCGv_i32 tag, TCGv_i32 value) -{ - TCGv_i32 t0 = tcg_temp_new_i32(); - - e2k_gen_reg_tag_write_i32(tag, index); - if (poison) { - gen_dst_poison_i32(t0, value, tag); - } else { - tcg_gen_mov_i32(t0, value); - } - e2k_gen_reg_lo_write_i32(t0, index); - - tcg_temp_free_i32(t0); -} - -static inline void gen_al_result_commit_reg64(bool poison, TCGv_i32 index, - TCGv_i32 tag, TCGv_i64 value) -{ - TCGv_i64 t0 = tcg_temp_new_i64(); - - e2k_gen_reg_tag_write_i64(tag, index); - if (poison) { - gen_dst_poison_i64(t0, value, tag); - } else { - tcg_gen_mov_i64(t0, value); - } - e2k_gen_reg_lo_write_i64(t0, index); - - tcg_temp_free_i64(t0); -} - -static inline void gen_al_result_commit_reg(AlResult *res) -{ - AlResultType size = e2k_al_result_size(res->type); - - switch (size) { - case AL_RESULT_32: { - TCGLabel *l0 = gen_new_label(); - - if (res->dbl) { - tcg_gen_brcondi_i32(TCG_COND_NE, e2k_cs.wdbl, 0, l0); - /* wdbl is not set */ - } - - gen_al_result_commit_reg32(res->poison, res->reg.index, res->reg.tag, - res->reg.v32); - - if (res->dbl) { - TCGv_i32 t0 = tcg_temp_new_i32(); - TCGv_i64 t1 = tcg_temp_new_i64(); - TCGLabel *l1 = gen_new_label(); - tcg_gen_br(l1); - - /* wdbl is set */ - gen_set_label(l0); - if (res->check_tag) { - gen_tag1_i64(t0, res->reg.tag); - } else { - tcg_gen_mov_i32(t0, res->reg.tag); - } - tcg_gen_extu_i32_i64(t1, res->reg.v32); - gen_al_result_commit_reg64(res->poison, res->reg.index, t0, t1); - - /* exit */ - gen_set_label(l1); - tcg_temp_free_i64(t1); - tcg_temp_free_i32(t0); - } - - break; - } - case AL_RESULT_64: - gen_al_result_commit_reg64(res->poison, res->reg.index, res->reg.tag, - res->reg.v64); - break; - case AL_RESULT_80: - gen_al_result_commit_reg64(res->poison, res->reg.index, res->reg.tag, - res->reg.v64); - e2k_gen_reg_hi_write16u_i32(res->reg.x32, res->reg.index); - break; - case AL_RESULT_128: - gen_al_result_commit_reg64(res->poison, res->reg.index, res->reg.tag, - res->reg.v64); - e2k_gen_reg_hi_write_i64(res->reg.x64, res->reg.index); - break; - default: - g_assert_not_reached(); - break; - } -} - -static inline void gen_al_result_commit_ctpr(AlResult *res) -{ - AlResultType size = e2k_al_result_size(res->type); - TCGv_i64 ctpr = e2k_cs.ctprs[res->ctpr.index]; - TCGv_i64 t0 = tcg_temp_new_i64(); - TCGv_i64 t1 = tcg_const_i64(CTPR_TAG_DISP); - - assert(res->ctpr.index < 3); - - switch (size) { - case AL_RESULT_32: - tcg_gen_extu_i32_i64(t0, res->ctpr.v32); - break; - case AL_RESULT_64: - tcg_gen_mov_i64(t0, res->ctpr.v64); - break; - default: - g_assert_not_reached(); - break; - } - - tcg_gen_deposit_i64(ctpr, ctpr, t0, CTPR_BASE_OFF, CTPR_BASE_LEN); - tcg_gen_deposit_i64(ctpr, ctpr, t1, CTPR_TAG_OFF, CTPR_TAG_LEN); - - tcg_temp_free_i64(t1); - tcg_temp_free_i64(t0); -} - -void e2k_alc_commit(DisasContext *ctx) -{ - int i; - - for (i = 0; i < 6; i++) { - TCGLabel *l0 = gen_new_label(); - AlResult *res = &ctx->al_results[i]; - - if (!ctx->bundle.als_present[i]) { - continue; - } - - if (res->type != AL_RESULT_NONE && ctx->al_cond[i] != NULL) { - tcg_gen_brcondi_i32(TCG_COND_EQ, ctx->al_cond[i], 0, l0); - } - - switch (e2k_al_result_type(res->type)) { - case AL_RESULT_NONE: - /* %empty */ - break; - case AL_RESULT_REG: - /* %rN, %b[N], %gN */ - gen_al_result_commit_reg(res); - break; - case AL_RESULT_PREG: - /* %predN */ - e2k_gen_store_preg(res->preg.index, res->preg.val); - break; - case AL_RESULT_CTPR: - /* %ctprN */ - gen_al_result_commit_ctpr(res); - break; - default: - g_assert_not_reached(); - break; - } - - gen_set_label(l0); - } -} - - -void alc_init(DisasContext *ctx) -{ - int i, j; - - memset(alops_map, -1, sizeof(alops_map)); - memset(pfcomb_map, 0, sizeof(pfcomb_map)); - - // TODO: symmetric alops table - /* Most alops are symmetric and can be stored in a half table. */ - for (i = 0; i < ARRAY_SIZE(alops); i++) { - AlopDesc *desc = &alops[i]; - if (desc->min_version <= ctx->version && ctx->version <= desc->max_version) { - for (j = 0; j < 6; j++) { - if (desc->channels & (1 << j)) { - int16_t *p = &alops_map[desc->opc2][desc->opc1][j]; - desc->next[j] = *p; - *p = i; - } - } - } - } - - pfcomb_init(ctx); -} diff --git a/target/e2k/translate/plu.c b/target/e2k/translate/plu.c deleted file mode 100644 index 9498f4858c..0000000000 --- a/target/e2k/translate/plu.c +++ /dev/null @@ -1,195 +0,0 @@ -#include "qemu/osdep.h" -#include "qemu.h" -#include "exec/log.h" -#include "translate.h" - -static void gen_get_lp(TCGv_i32 ret, uint16_t clp, int offset, TCGv_i32 lp[7]) -{ - int p = extract32(clp, offset, 3); - int neg = GET_BIT(clp, offset + 3); - - tcg_gen_xori_i32(ret, lp[p], neg); -} - -void e2k_gen_cond_i32(DisasContext *ctx, TCGv_i32 ret, uint8_t psrc) -{ - if (psrc & 0x80) { - if (psrc == 0xc0) { - // %bgrpred - e2k_todo_illop(ctx, "%%bgrpred"); - } else if ((psrc & 0xe0) == 0xc0) { - // %rndpred - e2k_todo_illop(ctx, "%%rndpred"); - } else { - gen_tr_excp_illopn(ctx); - } - } else { - int idx = extract8(psrc, 0, 5); - if (psrc == 0) { - // %lcntex - e2k_gen_lcntex(ret); - } else if ((psrc & 0x40) == 0) { - // %spredMASK - e2k_todo_illop(ctx, "%%spred"); - } else if ((psrc & 0x60) == 0x60) { - // %predN - e2k_gen_preg_i32(ret, idx); - } else { - // %pcntN - tcg_gen_setcondi_i32(TCG_COND_LEU, ret, e2k_cs.lsr_pcnt, idx); - } - } -} - -static inline void scan_needed(const UnpackedBundle *bundle, int need[7]) -{ - bool once_more = true; - unsigned int i; - - for (i = 0; i < 3; i++) { - if (bundle->pls_present[i] && GET_BIT(bundle->pls[i], 5)) { - need[4 + i] = 1; - } - } - - while (once_more) { - once_more = false; - - for (i = 0; i < 3; i++) { - int p0, p1; - - if (need[4 + i] != 1) { - continue; - } - - p0 = extract32(bundle->pls[i], 10, 3); - p1 = extract32(bundle->pls[i], 6, 3); - - if (p0 < 7 && need[p0] == 0) { - need[p0] = 1; - - if (p0 >= 4) { - once_more = true; - } - } - - if (p1 < 7 && need[p1] == 0) { - need[p1] = 1; - - if (p1 >= 4) { - once_more = true; - } - } - - need[4 + i] = 2; - } - } -} - -void e2k_plu_execute(DisasContext *ctx) -{ - const UnpackedBundle *bundle = &ctx->bundle; - int need[7] = { 0 }; - unsigned int i; - TCGv_i32 lp[7]; - - scan_needed(bundle, need); - - for (i = 0; i < 7; i++) { - if (need[i]) { - lp[i] = tcg_temp_new_i32(); - } - } - - for (i = 0; i < 3; i++) { - ctx->pl_results[i].reg = -1; - - if (!bundle->pls_present[i]) { - continue; - } - - if (i < 2) { - if (need[i * 2]) { - int elp = extract32(bundle->pls[i], 24, 7); - e2k_gen_cond_i32(ctx, lp[i * 2], elp); - } - - if (need[i * 2 + 1]) { - int elp = extract32(bundle->pls[i], 16, 7); - e2k_gen_cond_i32(ctx, lp[i * 2 + 1], elp); - } - } - - if (need[4 + i]) { - uint16_t clp = extract32(bundle->pls[i], 0, 16); - int opc = extract32(clp, 14, 2); - TCGv_i32 p0 = tcg_temp_new_i32(); - TCGv_i32 p1 = tcg_temp_new_i32(); - int vdst = GET_BIT(clp, 5); - int pdst = extract32(clp, 0, 5); - - // TODO: check clp arg - // {C/M}LP0 0, 1 => 4 - // {C/M}LP1 0, 1, 2, 3, 4 => 5 - // {C/M}LP2 0, 1, 2, 3, 4, 5 => 6 - // maximal cascading is 2 - - gen_get_lp(p0, clp, 10, lp); - gen_get_lp(p1, clp, 6, lp); - - if (vdst) { - ctx->pl_results[i].reg = pdst; - ctx->pl_results[i].value = e2k_get_temp_i32(ctx); - } - - switch (opc) { - case 0: /* andp */ - // FIXME: what is the difference between `andp` and `landp`? - case 1: /* landp */ - tcg_gen_and_i32(lp[4 + i], p0, p1); - if (vdst) { - tcg_gen_mov_i32(ctx->pl_results[i].value, lp[4 + i]); - } - break; - case 3: { /* movep */ - // FIXME: clp cannot read result of movep??? - tcg_gen_and_i32(lp[4 + i], p0, p1); - - if (vdst) { - TCGv_i32 z = tcg_const_i32(0); - TCGv_i32 t0 = tcg_temp_new_i32(); - - e2k_gen_preg_i32(t0, pdst); - tcg_gen_movcond_i32(TCG_COND_NE, ctx->pl_results[i].value, - p0, z, p1, t0); - - tcg_temp_free_i32(t0); - tcg_temp_free_i32(z); - } - break; - } - default: - abort(); - break; - } - } - } - - for (i = 0; i < 7; i++) { - if (need[i]) { - tcg_temp_free_i32(lp[i]); - } - } -} - -void e2k_plu_commit(DisasContext *ctx) -{ - unsigned int i; - - for (i = 0; i < 3; i++) { - if (ctx->pl_results[i].reg < 0) { - continue; - } - e2k_gen_store_preg(ctx->pl_results[i].reg, ctx->pl_results[i].value); - } -} diff --git a/target/e2k/translate/state.c b/target/e2k/translate/state.c deleted file mode 100644 index 25077ea3a4..0000000000 --- a/target/e2k/translate/state.c +++ /dev/null @@ -1,275 +0,0 @@ -#include "qemu/osdep.h" -#include "qemu.h" -#include "exec/log.h" -#include "translate.h" - -static inline void gen_ptr_from_index(TCGv_ptr ret, TCGv_ptr ptr, TCGv_i32 idx, - int size) -{ - TCGv_i32 t0 = tcg_temp_new_i32(); - TCGv_ptr t1 = tcg_temp_new_ptr(); - - tcg_gen_muli_i32(t0, idx, size); - tcg_gen_ext_i32_ptr(t1, t0); - tcg_gen_add_ptr(ret, ptr, t1); - - tcg_temp_free_ptr(t1); - tcg_temp_free_i32(t0); -} - -static inline void gen_preg_index(TCGv_i32 ret, int idx) -{ - TCGv_i32 i = tcg_const_i32(idx); - 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(); - - assert(idx < 32); - - tcg_gen_addi_i32(t0, e2k_cs.psize, 1); - tcg_gen_addi_i32(t1, e2k_cs.pcur, idx); - tcg_gen_remu_i32(t2, t1, t0); - tcg_gen_movi_i32(t3, idx); - tcg_gen_movcond_i32(TCG_COND_LEU, ret, i, e2k_cs.psize, t2, t3); - - tcg_temp_free_i32(t3); - tcg_temp_free_i32(t2); - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t0); - tcg_temp_free_i32(i); -} - -static void gen_preg_offset(TCGv_i64 ret, int idx) -{ - TCGv_i32 t0 = tcg_temp_new_i32(); - TCGv_i32 t1 = tcg_temp_new_i32(); - - gen_preg_index(t0, idx); - tcg_gen_muli_i32(t1, t0, 2); - tcg_gen_extu_i32_i64(ret, t1); - - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t0); -} - -static void gen_preg_clear(TCGv_i64 ret, TCGv_i64 offset) -{ - TCGv_i64 t0 = tcg_const_i64(3); - TCGv_i64 t1 = tcg_temp_new_i64(); - TCGv_i64 t2 = tcg_temp_new_i64(); - - tcg_gen_shl_i64(t1, t0, offset); - tcg_gen_not_i64(t2, t1); - tcg_gen_and_i64(ret, t2, e2k_cs.pregs); - - tcg_temp_free_i64(t2); - tcg_temp_free_i64(t1); - tcg_temp_free_i64(t0); -} - -static inline void gen_preg_i64(TCGv_i64 ret, int reg) -{ - TCGv_i64 one = 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(); - - gen_preg_offset(t0, reg); - tcg_gen_shl_i64(t1, one, t0); - tcg_gen_and_i64(t2, e2k_cs.pregs, t1); - tcg_gen_setcondi_i64(TCG_COND_NE, ret, t2, 0); - - tcg_temp_free_i64(t2); - tcg_temp_free_i64(t1); - tcg_temp_free_i64(t0); - tcg_temp_free_i64(one); -} - -void e2k_gen_preg_i32(TCGv_i32 ret, int reg) -{ - TCGv_i64 t0 = tcg_temp_new_i64(); - - gen_preg_i64(t0, reg); - tcg_gen_extrl_i64_i32(ret, t0); - tcg_temp_free_i64(t0); -} - -void e2k_gen_store_preg(int idx, TCGv_i32 val) -{ - 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(); - - gen_preg_offset(t0, idx); - gen_preg_clear(t1, t0); - tcg_gen_extu_i32_i64(t2, val); - tcg_gen_andi_i64(t3, t2, 3); - tcg_gen_shl_i64(t4, t2, t0); - tcg_gen_or_i64(e2k_cs.pregs, t1, t4); - - 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); -} - -static inline void gen_reg_tag_ptr(TCGv_ptr ret, TCGv_i32 idx) -{ - TCGv_ptr t0 = tcg_temp_new_ptr(); - TCGv_ptr t1 = tcg_temp_new_ptr(); - - tcg_gen_ext_i32_ptr(t0, idx); - tcg_gen_addi_ptr(t1, cpu_env, offsetof(CPUE2KState, tags)); - tcg_gen_add_ptr(ret, t1, t0); - - tcg_temp_free_ptr(t1); - tcg_temp_free_ptr(t0); -} - -void e2k_gen_reg_tag_read_i64(TCGv_i32 ret, TCGv_i32 idx) -{ - TCGv_ptr t0 = tcg_temp_new_ptr(); - - gen_reg_tag_ptr(t0, idx); - tcg_gen_ld8u_i32(ret, t0, 0); - tcg_temp_free_ptr(t0); -} - -void e2k_gen_reg_tag_read_i32(TCGv_i32 ret, TCGv_i32 idx) -{ - TCGv_ptr t0 = tcg_temp_new_ptr(); - TCGv_i32 t1 = tcg_temp_new_i32(); - - gen_reg_tag_ptr(t0, idx); - tcg_gen_ld8u_i32(t1, t0, 0); - tcg_gen_andi_i32(ret, t1, GEN_MASK(0, E2K_TAG_SIZE)); - tcg_temp_free_ptr(t0); -} - -static inline void gen_tag_check(TCGv_i32 ret, TCGv_i32 tag) -{ - // FIXME: what CPU does if tag is greater than 1? - tcg_gen_setcondi_i32(TCG_COND_NE, ret, tag, 0); -} - -void e2k_gen_reg_tag_check_i64(TCGv_i32 ret, TCGv_i32 tag) -{ - gen_tag_check(ret, tag); -} - -void e2k_gen_reg_tag_check_i32(TCGv_i32 ret, TCGv_i32 tag) -{ - TCGv_i32 t0 = tcg_temp_new_i32(); - - e2k_gen_reg_tag_extract_lo(t0, tag); - gen_tag_check(ret, t0); - tcg_temp_free_i32(t0); -} - -void e2k_gen_reg_tag_write_i64(TCGv_i32 value, TCGv_i32 idx) -{ - TCGv_ptr t0 = tcg_temp_new_ptr(); - - gen_reg_tag_ptr(t0, idx); - tcg_gen_st8_i32(value, t0, 0); - tcg_temp_free_ptr(t0); -} - -void e2k_gen_reg_tag_write_i32(TCGv_i32 value, TCGv_i32 idx) -{ - TCGv_ptr t0 = tcg_temp_new_ptr(); - TCGv_i32 t1 = tcg_temp_new_i32(); - TCGv_i32 t2 = tcg_temp_new_i32(); - - gen_reg_tag_ptr(t0, idx); - tcg_gen_ld8u_i32(t1, t0, 0); - tcg_gen_deposit_i32(t2, t1, value, 0, E2K_TAG_SIZE); - tcg_gen_st8_i32(t2, t0, 0); - - tcg_temp_free_i32(t2); - tcg_temp_free_i32(t1); - tcg_temp_free_ptr(t0); -} - -static inline void gen_reg_index_from_wreg(TCGv_i32 ret, TCGv_i32 idx) -{ - tcg_gen_mov_i32(ret, idx); -} - -void e2k_gen_reg_index_from_wregi(TCGv_i32 ret, int idx) -{ - tcg_gen_movi_i32(ret, idx); -} - -void e2k_gen_reg_index_from_bregi(TCGv_i32 ret, int idx) -{ - TCGv_i32 t0 = tcg_temp_new_i32(); - TCGv_i32 t1 = tcg_temp_new_i32(); - TCGv_i32 t2 = tcg_temp_new_i32(); - - tcg_gen_addi_i32(t0, e2k_cs.bcur, idx); - tcg_gen_remu_i32(t1, t0, e2k_cs.bsize); - tcg_temp_free_i32(t0); - tcg_gen_add_i32(t2, e2k_cs.boff, t1); - tcg_temp_free_i32(t1); - gen_reg_index_from_wreg(ret, t2); - tcg_temp_free_i32(t2); -} - -void e2k_gen_reg_index_from_gregi(TCGv_i32 ret, int idx) -{ - // TODO: based global registers index - tcg_gen_movi_i32(ret, E2K_NR_COUNT + idx); -} - -static inline void gen_reg_lo_ptr(TCGv_ptr ret, TCGv_i32 idx) -{ - TCGv_ptr t0 = tcg_temp_new_ptr(); - - tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, regs)); - gen_ptr_from_index(ret, t0, idx, sizeof(E2KReg)); - tcg_temp_free_ptr(t0); -} - -static inline void gen_reg_hi_ptr(TCGv_ptr ret, TCGv_i32 idx) -{ - TCGv_ptr t0 = tcg_temp_new_ptr(); - - gen_reg_lo_ptr(t0, idx); - tcg_gen_addi_ptr(ret, t0, offsetof(E2KReg, hi)); - tcg_temp_free_ptr(t0); -} - -#define GEN_REG_READ(name, ty, ptr_func, ld_func) \ - void name(ty ret, TCGv_i32 idx) \ - { \ - TCGv_ptr t0 = tcg_temp_new_ptr(); \ - ptr_func(t0, idx); \ - ld_func(ret, t0, 0); \ - tcg_temp_free_ptr(t0); \ - } - -GEN_REG_READ(e2k_gen_reg_lo_read_i64, TCGv_i64, gen_reg_lo_ptr, tcg_gen_ld_i64) -GEN_REG_READ(e2k_gen_reg_lo_read_i32, TCGv_i32, gen_reg_lo_ptr, tcg_gen_ld_i32) -GEN_REG_READ(e2k_gen_reg_hi_read_i64, TCGv_i64, gen_reg_hi_ptr, tcg_gen_ld_i64) -GEN_REG_READ(e2k_gen_reg_hi_read_i32, TCGv_i32, gen_reg_hi_ptr, tcg_gen_ld_i32) -GEN_REG_READ(e2k_gen_reg_hi_read16u_i32, TCGv_i32, gen_reg_hi_ptr, tcg_gen_ld16u_i32) - -#define GEN_REG_WRITE(name, ty, ptr_func, st_func) \ - void name(ty value, TCGv_i32 idx) \ - { \ - TCGv_ptr t0 = tcg_temp_new_ptr(); \ - ptr_func(t0, idx); \ - st_func(value, t0, 0); \ - tcg_temp_free_ptr(t0); \ - } - -GEN_REG_WRITE(e2k_gen_reg_lo_write_i64, TCGv_i64, gen_reg_lo_ptr, tcg_gen_st_i64) -GEN_REG_WRITE(e2k_gen_reg_lo_write_i32, TCGv_i32, gen_reg_lo_ptr, tcg_gen_st_i32) -GEN_REG_WRITE(e2k_gen_reg_hi_write_i64, TCGv_i64, gen_reg_hi_ptr, tcg_gen_st_i64) -GEN_REG_WRITE(e2k_gen_reg_hi_write_i32, TCGv_i32, gen_reg_hi_ptr, tcg_gen_st_i32) -GEN_REG_WRITE(e2k_gen_reg_hi_write16u_i32, TCGv_i32, gen_reg_hi_ptr, tcg_gen_st16_i32)