target: e2k: Add loop_end/not_loop_end condition.

This commit is contained in:
Denis Drakhnia 2020-11-13 18:40:56 +02:00 committed by Denis Drakhnia
parent 37acf287ad
commit 24b5d5c7fb
8 changed files with 227 additions and 90 deletions

View File

@ -84,6 +84,7 @@ void e2k_cpu_dump_state(CPUState *cs, FILE *f, int flags)
qemu_fprintf(f, "usd_hi: %016lx, usd_lo: %016lx\n",
env->usd_hi, env->usd_lo);
qemu_fprintf(f, "psz: %d, pcur: %d\n", (int) env->psz, (int) env->pcur);
qemu_fprintf(f, "lsr: %016lx\n", env->lsr);
for (i = 0; i < 192; i += 4) {
const char *s1 = i < 10 ? " " : (i < 100 ? " " : "");

View File

@ -13,6 +13,35 @@ void e2k_tcg_initialize(void);
// size of regular reg in bytes
#define REG_SIZE (sizeof(target_ulong))
#define CTPR_BASE_OFF 0
#define CTPR_BASE_END 47
#define CTPR_TAG_OFF 54
#define CTPR_TAG_END 56
#define CTPR_OPC_OFF 57
#define CTPR_OPC_END 58
#define CTPR_IPD_OFF 59
#define CTPR_IPD_END 60
#define LSR_LCNT_OFF 0 /* loop counter */
#define LSR_LCNT_END 31
#define LSR_LCNT_LEN (LSR_LCNT_END - LSR_LCNT_OFF + 1)
#define LSR_ECNT_OFF 32 /* epilogue counter */
#define LSR_ECNT_END 36
#define LSR_ECNT_LEN (LSR_ECNT_END - LSR_ECNT_OFF + 1)
#define LSR_VLC_OFF 37 /* loop count valid bit */
#define LSR_OVER_OFF 38 /* loop count overflow */
#define LSR_LDMC_OFF 39 /* loads manual control */
#define LSR_LDOVL_OFF 40 /* load overlap */
#define LSR_LDOVL_END 47
#define LSR_LDOVL_SIZE (LSR_LDOVL_END - LSR_LDOVL_OFF + 1)
#define LSR_PCNT_OFF 48 /* prologue counter */
#define LSR_PCNT_END 52
#define LSR_PCNT_LEN (LSR_PCNT_END - LSR_PCNT_OFF + 1)
#define LSR_STRMD_OFF 53 /* store remainder counter */
#define LSR_STRMD_END 59
#define LSR_STRMD_LEN (LSR_STRMD_END - LSR_STRMD_OFF + 1)
#define LSR_SEMC_OFF /* side effects manual control */
typedef enum {
E2K_EXCP_UNIMPL = 0x01,
E2K_EXCP_SYSCALL = 0x02,
@ -43,6 +72,8 @@ typedef struct CPUArchState {
uint64_t psz; // pred regs window size
uint64_t pcur; // pred regs current offset
uint64_t lsr; /* loop status register */
uint32_t syscall_wbs;
uint64_t usd_lo;

View File

@ -5,7 +5,6 @@ e2k_ss.add(files(
'helper_int.c',
'translate.c',
'translate/state.c',
'translate/win.c',
'translate/control.c',
'translate/alc.c',
))

View File

@ -435,8 +435,9 @@ void e2k_tcg_initialize(void) {
{ &e2k_cs.pregs, offsetof(CPUE2KState, pregs), "pregs" },
{ &e2k_cs.psz, offsetof(CPUE2KState, psz), "psz" },
{ &e2k_cs.pcur, offsetof(CPUE2KState, pcur), "pcur" },
{ &e2k_cs.usd_lo, offsetof(CPUE2KState, usd_lo), "%usd.lo" },
{ &e2k_cs.usd_hi, offsetof(CPUE2KState, usd_hi), "%usd.hi" },
{ &e2k_cs.usd_lo, offsetof(CPUE2KState, usd_lo), "usd.lo" },
{ &e2k_cs.usd_hi, offsetof(CPUE2KState, usd_hi), "usd.hi" },
{ &e2k_cs.lsr, offsetof(CPUE2KState, lsr), "lsr" },
};
static const struct { TCGv *ptr; int off; const char *name; } rtl[] = {

View File

@ -32,15 +32,6 @@
#define GET_LIT(i) ((i) & 0x03)
#define GET_GLOBAL(i) ((i) & 0x1f)
#define CTPR_BASE_OFF 0
#define CTPR_BASE_END 47
#define CTPR_TAG_OFF 54
#define CTPR_TAG_END 56
#define CTPR_OPC_OFF 57
#define CTPR_OPC_END 58
#define CTPR_IPD_OFF 59
#define CTPR_IPD_END 60
typedef enum {
CTPR_TAG_RETURN = 0x2,
CTPR_TAG_DISP = 0x3,
@ -70,6 +61,7 @@ typedef struct CPUE2KStateTCG {
TCGv_i32 rcur;
TCGv_i64 psz;
TCGv_i64 pcur;
TCGv_i64 lsr;
TCGv_i32 syscall_wbs;
TCGv_ptr win_ptr;
TCGv_i64 wregs[WREGS_SIZE];
@ -142,7 +134,9 @@ typedef struct DisasContext {
int t64_len;
int ttl_len;
/* TODO: move to CPUE2KState */
Result alc[6];
/* TODO: move to CPUE2KState */
struct {
TCGv dest;
TCGv_i64 cond;
@ -216,6 +210,26 @@ static inline void e2k_gen_set_field_i64(TCGv_i64 ret, TCGv_i64 val,
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_lcnt(TCGv_i64 ret)
{
tcg_gen_andi_i64(ret, e2k_cs.lsr, (1UL << 32) - 1);
}
static inline void e2k_gen_ecnt(TCGv_i64 ret)
{
tcg_gen_extract_i64(ret, e2k_cs.lsr, LSR_ECNT_OFF, LSR_ECNT_LEN);
}
static inline void e2k_gen_pcnt(TCGv_i32 ret)
{
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_extract_i64(t0, e2k_cs.lsr, LSR_PCNT_OFF, LSR_PCNT_LEN);
tcg_gen_extrl_i64_i32(ret, t0);
tcg_temp_free_i64(t0);
}
void e2k_gen_preg(TCGv_i64 ret, int reg);
TCGv_i64 e2k_get_preg(DisasContext *dc, int reg);
void e2k_gen_store_preg(int reg, TCGv_i64 val);

View File

@ -266,6 +266,9 @@ static inline void gen_rr_i64(TCGv_i64 ret, uint8_t state_reg)
case 0x2d: /* %usd.lo */
tcg_gen_mov_i64(ret, e2k_cs.usd_lo);
break;
case 0x83: /* %lsr */
tcg_gen_mov_i64(ret, e2k_cs.lsr);
break;
default:
/* TODO: exception */
abort();
@ -308,6 +311,9 @@ static inline void gen_rw_i64(uint8_t state_reg, TCGv_i64 val)
/* FIXME: user cannot write */
tcg_gen_mov_i64(e2k_cs.usd_lo, val);
break;
case 0x83: /* %lsr */
tcg_gen_mov_i64(e2k_cs.lsr, val);
break;
default:
/* TODO: exception */
abort();

View File

@ -3,6 +3,137 @@
#include "exec/log.h"
#include "translate.h"
static inline void gen_alc_dec(DisasContext *dc, TCGCond cond)
{
TCGv_i64 one = tcg_const_i64(1);
TCGv_i32 zero = 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();
TCGv_i32 t3 = tcg_temp_new_i32();
TCGv_i32 t4 = tcg_temp_new_i32();
TCGv_i32 t5 = tcg_temp_new_i32();
TCGv_i32 t6 = tcg_temp_new_i32();
TCGv_i64 t7 = tcg_temp_new_i64();
tcg_gen_extrl_i64_i32(t0, e2k_cs.lsr);
tcg_gen_subi_i32(t1, t0, 1);
tcg_gen_movcond_i32(TCG_COND_LTU, t2, t1, t0, t1, t0);
tcg_gen_setcondi_i32(TCG_COND_EQ, t3, t1, 0);
tcg_gen_shli_i32(t4, t3, LSR_OVER_OFF - 32);
tcg_gen_extrh_i64_i32(t5, e2k_cs.lsr);
tcg_gen_or_i32(t6, t5, t4);
tcg_gen_concat_i32_i64(t7, t2, t6);
tcg_gen_movcond_i64(cond, e2k_cs.lsr,
dc->jmp.cond, one,
t7, e2k_cs.lsr);
tcg_temp_free_i64(t7);
tcg_temp_free_i32(t6);
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(zero);
tcg_temp_free_i64(one);
}
static inline void gen_abp_inc(DisasContext *dc, TCGCond cond)
{
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv_i64 one = tcg_const_i64(1);
tcg_gen_subi_i64(t0, e2k_cs.pcur, 1);
tcg_gen_umin_i64(t1, t0, e2k_cs.psz);
tcg_gen_movcond_i64(cond, e2k_cs.pcur, dc->jmp.cond, one, t1, e2k_cs.pcur);
tcg_temp_free_i64(one);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t0);
}
static inline void gen_abn_inc(DisasContext *dc, TCGCond cond)
{
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 one = tcg_const_i32(1);
TCGv_i32 jmp_cond = tcg_temp_new_i32();
tcg_gen_addi_i32(t0, e2k_cs.rcur, 2);
e2k_gen_wrap_i32(t1, t0, e2k_cs.rsz);
tcg_gen_extrl_i64_i32(jmp_cond, dc->jmp.cond);
tcg_gen_movcond_i32(cond, e2k_cs.rcur,
jmp_cond, one,
t1, e2k_cs.rcur);
tcg_temp_free_i32(jmp_cond);
tcg_temp_free_i32(one);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
void e2k_win_commit(DisasContext *dc)
{
// Change windowing registers after commit is done.
uint32_t ss = dc->bundle.ss;
// unsigned int vfdi = (ss & 0x04000000) >> 26;
// unsigned int abg = (ss & 0x01800000) >> 23;
if (GET_BIT(ss, 16)) {
gen_alc_dec(dc, TCG_COND_EQ);
}
if (GET_BIT(ss, 17)) {
gen_alc_dec(dc, TCG_COND_NE);
}
if (GET_BIT(ss, 18)) {
gen_abp_inc(dc, TCG_COND_EQ);
}
if (GET_BIT(ss, 19)) {
gen_abp_inc(dc, TCG_COND_NE);
}
if (GET_BIT(ss, 21)) {
gen_abn_inc(dc, TCG_COND_EQ);
}
if (GET_BIT(ss, 22)) {
gen_abn_inc(dc, TCG_COND_NE);
}
}
static inline void gen_is_last_iter(TCGv_i64 ret)
{
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv_i64 t2 = tcg_temp_new_i64();
e2k_gen_lcnt(t0);
tcg_gen_setcondi_i64(TCG_COND_LTU, t1, t0, 2);
tcg_gen_extract_i64(t2, e2k_cs.lsr, LSR_VLC_OFF, 1);
tcg_gen_and_i64(ret, t1, t2);
tcg_temp_free(t2);
tcg_temp_free(t1);
tcg_temp_free(t0);
}
static inline void gen_is_loop_end(TCGv_i64 ret)
{
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv_i64 t2 = tcg_temp_new_i64();
e2k_gen_ecnt(t0);
tcg_gen_setcondi_i64(TCG_COND_EQ, t1, t0, 0);
gen_is_last_iter(t2);
tcg_gen_and_i64(ret, t1, t2);
tcg_temp_free_i64(t2);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t0);
}
static void gen_cs0(DisasContext *dc)
{
typedef enum {
@ -327,16 +458,19 @@ static void gen_jmp(DisasContext *dc)
dc->base.is_jmp = STATIC_JUMP;
tcg_gen_movi_i64(dc->jmp.cond, 1);
} else {
/* TODO: single assign */
TCGv_i64 cond = tcg_temp_new_i64();
dc->base.is_jmp = DYNAMIC_JUMP;
if (cond_type == 2 || cond_type == 6 || cond_type == 0xf) {
/* if pred is true */
tcg_gen_mov_i64(dc->jmp.cond, e2k_get_preg(dc, psrc));
tcg_gen_mov_i64(cond, e2k_get_preg(dc, psrc));
} else if (cond_type == 3 || cond_type == 7 || cond_type == 0xe) {
/* if pred is false */
TCGv_i64 one = tcg_const_i64(1);
TCGv_i64 zero = tcg_const_i64(0);
tcg_gen_movcond_i64(TCG_COND_EQ, dc->jmp.cond,
tcg_gen_movcond_i64(TCG_COND_EQ, cond,
e2k_get_preg(dc, psrc), zero,
one, zero);
tcg_temp_free_i64(zero);
@ -345,27 +479,35 @@ static void gen_jmp(DisasContext *dc)
/* TODO: other kinds of conditions */
if (cond_type == 4
|| cond_type == 6
|| cond_type == 0xe)
{
if (cond_type == 4 || cond_type == 6 || cond_type == 0xe) {
TCGv_i64 is_loop_end = tcg_temp_new_i64();
gen_is_loop_end(is_loop_end);
if (cond_type == 6 || cond_type == 0xe) {
// or
tcg_gen_or_i64(cond, cond, is_loop_end);
} else {
tcg_gen_mov_i64(cond, is_loop_end);
}
// %LOOP_END
tcg_temp_free_i64(is_loop_end);
}
if (cond_type == 5
|| cond_type == 7
|| cond_type == 0xf)
{
if(cond_type == 7
|| cond_type == 0xf)
{
// AND
if (cond_type == 5 || cond_type == 7 || cond_type == 0xf) {
TCGv_i64 is_loop_end = tcg_temp_new_i64();
TCGv_i64 t0 = tcg_temp_new_i64();
gen_is_loop_end(is_loop_end);
tcg_gen_setcondi_i64(TCG_COND_EQ, t0, is_loop_end, 0);
if(cond_type == 7 || cond_type == 0xf) {
tcg_gen_and_i64(cond, cond, t0);
} else {
tcg_gen_mov_i64(cond, t0);
}
// %NOT_LOOP_END
tcg_temp_free_i64(t0);
tcg_temp_free_i64(is_loop_end);
}
if (cond_type == 8) {
@ -416,6 +558,10 @@ static void gen_jmp(DisasContext *dc)
qemu_log_mask(LOG_UNIMP, "Undefined control transfer type %#x\n", cond_type);
abort();
}
tcg_gen_mov_i64(dc->jmp.cond, cond);
tcg_temp_free_i64(cond);
}
/* TODO: check CPU behavior if present ibranch and ctpr is not zero */

View File

@ -1,61 +0,0 @@
#include "qemu/osdep.h"
#include "qemu.h"
#include "exec/log.h"
#include "translate.h"
static inline void gen_abp_inc(DisasContext *dc, TCGCond cond)
{
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv_i64 one = tcg_const_i64(1);
tcg_gen_subi_i64(t0, e2k_cs.pcur, 1);
tcg_gen_umin_i64(t1, t0, e2k_cs.psz);
tcg_gen_movcond_i64(cond, e2k_cs.pcur, dc->jmp.cond, one, t1, e2k_cs.pcur);
tcg_temp_free_i64(one);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t0);
}
static inline void gen_abn_inc(DisasContext *dc, TCGCond cond)
{
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 one = tcg_const_i32(1);
TCGv_i32 jmp_cond = tcg_temp_new_i32();
tcg_gen_addi_i32(t0, e2k_cs.rcur, 2);
e2k_gen_wrap_i32(t1, t0, e2k_cs.rsz);
tcg_gen_extrl_i64_i32(jmp_cond, dc->jmp.cond);
tcg_gen_movcond_i32(cond, e2k_cs.rcur,
jmp_cond, one,
t1, e2k_cs.rcur);
tcg_temp_free_i32(jmp_cond);
tcg_temp_free_i32(one);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
void e2k_win_commit(DisasContext *dc)
{
// Change windowing registers after commit is done.
uint32_t ss = dc->bundle.ss;
// unsigned int vfdi = (ss & 0x04000000) >> 26;
// unsigned int abg = (ss & 0x01800000) >> 23;
// unsigned int alc = (ss & 0x00030000) >> 16;
if (GET_BIT(ss, 21)) {
gen_abn_inc(dc, TCG_COND_EQ);
}
if (GET_BIT(ss, 22)) {
gen_abn_inc(dc, TCG_COND_NE);
}
if (GET_BIT(ss, 18)) {
gen_abp_inc(dc, TCG_COND_EQ);
}
if (GET_BIT(ss, 19)) {
gen_abp_inc(dc, TCG_COND_NE);
}
}