2020-11-23 20:57:46 +01:00
|
|
|
#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])
|
|
|
|
{
|
2020-11-23 21:26:47 +01:00
|
|
|
int p = GET_FIELD(clp, offset, 3);
|
2020-11-23 20:57:46 +01:00
|
|
|
int neg = GET_BIT(clp, offset + 3);
|
|
|
|
|
|
|
|
tcg_gen_xori_i32(ret, lp[p], neg);
|
|
|
|
}
|
|
|
|
|
2020-11-24 10:12:01 +01:00
|
|
|
void e2k_gen_cond_i32(DisasContext *ctx, TCGv_i32 ret, uint8_t psrc)
|
2020-11-23 20:57:46 +01:00
|
|
|
{
|
2020-12-10 13:52:56 +01:00
|
|
|
if (psrc & 0x80) {
|
|
|
|
if (psrc == 0xc0) {
|
|
|
|
// TODO: %bgrpred
|
|
|
|
qemu_log_mask(LOG_UNIMP, "%#lx: %%bgrpred is not implemented!\n", ctx->pc);
|
2020-11-24 21:50:33 +01:00
|
|
|
abort();
|
2020-12-10 13:52:56 +01:00
|
|
|
} else if ((psrc & 0xe0) == 0xc0) {
|
|
|
|
// TODO: %rndpredN
|
|
|
|
qemu_log_mask(LOG_UNIMP, "%#lx: %%rndpred is not implemented!\n", ctx->pc);
|
2020-11-24 21:50:33 +01:00
|
|
|
abort();
|
2020-11-23 20:57:46 +01:00
|
|
|
} else {
|
2020-11-28 08:44:53 +01:00
|
|
|
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
|
2020-11-23 20:57:46 +01:00
|
|
|
}
|
|
|
|
} else {
|
2020-12-10 13:52:56 +01:00
|
|
|
int idx = extract8(psrc, 0, 5);
|
|
|
|
if (psrc == 0) {
|
|
|
|
// %lcntex
|
|
|
|
e2k_gen_lcntex(ret);
|
|
|
|
} else if ((psrc & 0x40) == 0) {
|
|
|
|
// TODO: %spredMASK
|
|
|
|
qemu_log_mask(LOG_UNIMP, "%#lx: %%spred is not implemented!\n", ctx->pc);
|
|
|
|
abort();
|
|
|
|
} else if ((psrc & 0x60) == 0x60) {
|
|
|
|
// %predN
|
|
|
|
e2k_gen_preg_i32(ret, idx);
|
|
|
|
} else {
|
|
|
|
// %pcntN
|
|
|
|
TCGv_i32 t0 = tcg_temp_new_i32();
|
2020-11-23 20:57:46 +01:00
|
|
|
|
2020-12-10 13:52:56 +01:00
|
|
|
e2k_gen_pcnt_i32(t0);
|
|
|
|
tcg_gen_setcondi_i32(TCG_COND_LEU, ret, t0, idx);
|
|
|
|
tcg_temp_free_i32(t0);
|
|
|
|
}
|
2020-11-23 20:57:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-11-24 08:47:10 +01:00
|
|
|
p0 = GET_FIELD(bundle->pls[i], 10, 3);
|
|
|
|
p1 = GET_FIELD(bundle->pls[i], 6, 3);
|
2020-11-23 20:57:46 +01:00
|
|
|
|
|
|
|
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++) {
|
2020-12-05 13:52:38 +01:00
|
|
|
ctx->pl_results[i].reg = -1;
|
|
|
|
|
2020-11-23 20:57:46 +01:00
|
|
|
if (!bundle->pls_present[i]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i < 2) {
|
|
|
|
if (need[i * 2]) {
|
2020-11-23 21:26:47 +01:00
|
|
|
int elp = GET_FIELD(bundle->pls[i], 24, 7);
|
2020-11-24 10:12:01 +01:00
|
|
|
e2k_gen_cond_i32(ctx, lp[i * 2], elp);
|
2020-11-23 20:57:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (need[i * 2 + 1]) {
|
2020-11-23 21:26:47 +01:00
|
|
|
int elp = GET_FIELD(bundle->pls[i], 16, 7);
|
2020-11-24 10:12:01 +01:00
|
|
|
e2k_gen_cond_i32(ctx, lp[i * 2 + 1], elp);
|
2020-11-23 20:57:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (need[4 + i]) {
|
2020-11-23 21:26:47 +01:00
|
|
|
uint16_t clp = GET_FIELD(bundle->pls[i], 0, 16);
|
|
|
|
int opc = GET_FIELD(clp, 14, 2);
|
2020-11-23 20:57:46 +01:00
|
|
|
TCGv_i32 p0 = tcg_temp_new_i32();
|
|
|
|
TCGv_i32 p1 = tcg_temp_new_i32();
|
|
|
|
int vdst = GET_BIT(clp, 5);
|
2020-11-23 21:26:47 +01:00
|
|
|
int pdst = GET_FIELD(clp, 0, 5);
|
2020-11-23 20:57:46 +01:00
|
|
|
|
|
|
|
// 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) {
|
2020-12-01 13:00:12 +01:00
|
|
|
ctx->pl_results[i].reg = pdst;
|
|
|
|
ctx->pl_results[i].value = e2k_get_temp_i32(ctx);
|
2020-11-23 20:57:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2020-12-01 13:00:12 +01:00
|
|
|
tcg_gen_mov_i32(ctx->pl_results[i].value, lp[4 + i]);
|
2020-11-23 20:57:46 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3: { /* movep */
|
|
|
|
// FIXME: clp cannot read result of movep???
|
|
|
|
tcg_gen_and_i32(lp[4 + i], p0, p1);
|
|
|
|
|
|
|
|
if (vdst) {
|
|
|
|
TCGv_i32 one = tcg_const_i32(1);
|
|
|
|
TCGv_i64 t0 = tcg_temp_new_i64();
|
|
|
|
TCGv_i32 t1 = tcg_temp_new_i32();
|
|
|
|
|
2020-12-08 23:08:55 +01:00
|
|
|
e2k_gen_preg_i64(t0, pdst);
|
2020-11-23 20:57:46 +01:00
|
|
|
tcg_gen_extrl_i64_i32(t1, t0);
|
2020-12-01 13:00:12 +01:00
|
|
|
tcg_gen_movcond_i32(TCG_COND_EQ, ctx->pl_results[i].value,
|
2020-11-23 20:57:46 +01:00
|
|
|
p0, one, p1, t1);
|
|
|
|
|
|
|
|
tcg_temp_free_i32(t1);
|
|
|
|
tcg_temp_free_i64(t0);
|
|
|
|
tcg_temp_free_i32(one);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
2020-11-24 21:50:33 +01:00
|
|
|
abort();
|
2020-11-23 20:57:46 +01:00
|
|
|
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++) {
|
|
|
|
TCGv_i64 t0;
|
|
|
|
|
2020-12-01 13:00:12 +01:00
|
|
|
if (ctx->pl_results[i].reg < 0) {
|
2020-11-23 20:57:46 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
t0 = tcg_temp_new_i64();
|
|
|
|
|
2020-12-01 13:00:12 +01:00
|
|
|
tcg_gen_extu_i32_i64(t0, ctx->pl_results[i].value);
|
|
|
|
e2k_gen_store_preg(ctx->pl_results[i].reg, t0);
|
2020-11-23 20:57:46 +01:00
|
|
|
|
|
|
|
tcg_temp_free_i64(t0);
|
|
|
|
}
|
|
|
|
}
|