target-tricore: Add instructions of RRR opcode format

Add microcode generator function gen_cond_sub.

Add helper functions:
    * ixmax/ixmin: search for the max/min value and its related index in a
                   vector of 16-bit values.
    * pack: dack two data registers into an IEEE-754 single precision floating
            point format number.
    * dvadj: divide-adjust the result after dvstep instructions.
    * dvstep: divide a reg by a divisor, producing 8-bits of quotient at a time.

OPCM_32_RRR_FLOAT -> OPCM_32_RRR_DIVIDE

Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
Reviewed-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Bastian Koppelmann 2015-01-19 15:43:07 +00:00
parent 8fb9d0eb68
commit 0953225588
4 changed files with 319 additions and 1 deletions

View File

@ -60,10 +60,14 @@ DEF_HELPER_FLAGS_2(max_b, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(max_bu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(max_h, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(max_hu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(ixmax, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_FLAGS_2(ixmax_u, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_FLAGS_2(min_b, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(min_bu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(min_h, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(min_hu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(ixmin, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_FLAGS_2(ixmin_u, TCG_CALL_NO_RWG_SE, i64, i64, i32)
/* count leading ... */
DEF_HELPER_FLAGS_1(clo, TCG_CALL_NO_RWG_SE, i32, i32)
DEF_HELPER_FLAGS_1(clo_h, TCG_CALL_NO_RWG_SE, i32, i32)
@ -81,12 +85,16 @@ DEF_HELPER_FLAGS_2(bmerge, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_1(bsplit, TCG_CALL_NO_RWG_SE, i64, i32)
DEF_HELPER_FLAGS_1(parity, TCG_CALL_NO_RWG_SE, i32, i32)
/* float */
DEF_HELPER_FLAGS_4(pack, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32, i32)
DEF_HELPER_1(unpack, i64, i32)
/* dvinit */
DEF_HELPER_3(dvinit_b_13, i64, env, i32, i32)
DEF_HELPER_3(dvinit_b_131, i64, env, i32, i32)
DEF_HELPER_3(dvinit_h_13, i64, env, i32, i32)
DEF_HELPER_3(dvinit_h_131, i64, env, i32, i32)
DEF_HELPER_FLAGS_2(dvadj, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_FLAGS_2(dvstep, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_FLAGS_2(dvstep_u, TCG_CALL_NO_RWG_SE, i64, i64, i32)
/* mulh */
DEF_HELPER_FLAGS_5(mul_h, TCG_CALL_NO_RWG_SE, i64, i32, i32, i32, i32, i32)
DEF_HELPER_FLAGS_5(mulm_h, TCG_CALL_NO_RWG_SE, i64, i32, i32, i32, i32, i32)

View File

@ -883,6 +883,50 @@ uint32_t helper_##name ##_hu(target_ulong r1, target_ulong r2)\
\
return ret; \
} \
\
uint64_t helper_ix##name(uint64_t r1, uint32_t r2) \
{ \
int64_t r2l, r2h, r1hl; \
uint64_t ret = 0; \
\
ret = ((r1 + 2) & 0xffff); \
r2l = sextract64(r2, 0, 16); \
r2h = sextract64(r2, 16, 16); \
r1hl = sextract64(r1, 32, 16); \
\
if ((r2l op ## = r2h) && (r2l op r1hl)) { \
ret |= (r2l & 0xffff) << 32; \
ret |= extract64(r1, 0, 16) << 16; \
} else if ((r2h op r2l) && (r2h op r1hl)) { \
ret |= extract64(r2, 16, 16) << 32; \
ret |= extract64(r1 + 1, 0, 16) << 16; \
} else { \
ret |= r1 & 0xffffffff0000ull; \
} \
return ret; \
} \
\
uint64_t helper_ix##name ##_u(uint64_t r1, uint32_t r2) \
{ \
int64_t r2l, r2h, r1hl; \
uint64_t ret = 0; \
\
ret = ((r1 + 2) & 0xffff); \
r2l = extract64(r2, 0, 16); \
r2h = extract64(r2, 16, 16); \
r1hl = extract64(r1, 32, 16); \
\
if ((r2l op ## = r2h) && (r2l op r1hl)) { \
ret |= (r2l & 0xffff) << 32; \
ret |= extract64(r1, 0, 16) << 16; \
} else if ((r2h op r2l) && (r2h op r1hl)) { \
ret |= extract64(r2, 16, 16) << 32; \
ret |= extract64(r1 + 1, 0, 16) << 16; \
} else { \
ret |= r1 & 0xffffffff0000ull; \
} \
return ret; \
}
EXTREMA_H_B(max, >)
EXTREMA_H_B(min, <)
@ -1116,6 +1160,48 @@ uint32_t helper_parity(target_ulong r1)
return ret;
}
uint32_t helper_pack(uint32_t carry, uint32_t r1_low, uint32_t r1_high,
target_ulong r2)
{
uint32_t ret;
int32_t fp_exp, fp_frac, temp_exp, fp_exp_frac;
int32_t int_exp = r1_high;
int32_t int_mant = r1_low;
uint32_t flag_rnd = (int_mant & (1 << 7)) && (
(int_mant & (1 << 8)) ||
(int_mant & 0x7f) ||
(carry != 0));
if (((int_mant & (1<<31)) == 0) && (int_exp == 255)) {
fp_exp = 255;
fp_frac = extract32(int_mant, 8, 23);
} else if ((int_mant & (1<<31)) && (int_exp >= 127)) {
fp_exp = 255;
fp_frac = 0;
} else if ((int_mant & (1<<31)) && (int_exp <= -128)) {
fp_exp = 0;
fp_frac = 0;
} else if (int_mant == 0) {
fp_exp = 0;
fp_frac = 0;
} else {
if (((int_mant & (1 << 31)) == 0)) {
temp_exp = 0;
} else {
temp_exp = int_exp + 128;
}
fp_exp_frac = (((temp_exp & 0xff) << 23) |
extract32(int_mant, 8, 23))
+ flag_rnd;
fp_exp = extract32(fp_exp_frac, 23, 8);
fp_frac = extract32(fp_exp_frac, 0, 23);
}
ret = r2 & (1 << 31);
ret = ret + (fp_exp << 23);
ret = ret + (fp_frac & 0x7fffff);
return ret;
}
uint64_t helper_unpack(target_ulong arg1)
{
int32_t fp_exp = extract32(arg1, 23, 8);
@ -1244,6 +1330,80 @@ uint64_t helper_dvinit_h_131(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
return ret;
}
uint64_t helper_dvadj(uint64_t r1, uint32_t r2)
{
int32_t x_sign = (r1 >> 63);
int32_t q_sign = x_sign ^ (r2 >> 31);
int32_t eq_pos = x_sign & ((r1 >> 32) == r2);
int32_t eq_neg = x_sign & ((r1 >> 32) == -r2);
uint32_t quotient;
uint64_t ret, remainder;
if ((q_sign & ~eq_neg) | eq_pos) {
quotient = (r1 + 1) & 0xffffffff;
} else {
quotient = r1 & 0xffffffff;
}
if (eq_pos | eq_neg) {
remainder = 0;
} else {
remainder = (r1 & 0xffffffff00000000ull);
}
ret = remainder|quotient;
return ret;
}
uint64_t helper_dvstep(uint64_t r1, uint32_t r2)
{
int32_t dividend_sign = extract64(r1, 63, 1);
int32_t divisor_sign = extract32(r2, 31, 1);
int32_t quotient_sign = (dividend_sign != divisor_sign);
int32_t addend, dividend_quotient, remainder;
int32_t i, temp;
if (quotient_sign) {
addend = r2;
} else {
addend = -r2;
}
dividend_quotient = (int32_t)r1;
remainder = (int32_t)(r1 >> 32);
for (i = 0; i < 8; i++) {
remainder = (remainder << 1) | extract32(dividend_quotient, 31, 1);
dividend_quotient <<= 1;
temp = remainder + addend;
if ((temp < 0) == dividend_sign) {
remainder = temp;
}
if (((temp < 0) == dividend_sign)) {
dividend_quotient = dividend_quotient | !quotient_sign;
} else {
dividend_quotient = dividend_quotient | quotient_sign;
}
}
return ((uint64_t)remainder << 32) | (uint32_t)dividend_quotient;
}
uint64_t helper_dvstep_u(uint64_t r1, uint32_t r2)
{
int32_t dividend_quotient = extract64(r1, 0, 32);
int64_t remainder = extract64(r1, 32, 32);
int32_t i;
int64_t temp;
for (i = 0; i < 8; i++) {
remainder = (remainder << 1) | extract32(dividend_quotient, 31, 1);
dividend_quotient <<= 1;
temp = (remainder & 0xffffffff) - r2;
if (temp >= 0) {
remainder = temp;
}
dividend_quotient = dividend_quotient | !(temp < 0);
}
return ((uint64_t)remainder << 32) | (uint32_t)dividend_quotient;
}
uint64_t helper_mul_h(uint32_t arg00, uint32_t arg01,
uint32_t arg10, uint32_t arg11, uint32_t n)
{

View File

@ -182,6 +182,18 @@ void tricore_cpu_dump_state(CPUState *cs, FILE *f,
tcg_temp_free(arg11); \
} while (0)
#define GEN_HELPER_RRR(name, rl, rh, al1, ah1, arg2) do { \
TCGv_i64 ret = tcg_temp_new_i64(); \
TCGv_i64 arg1 = tcg_temp_new_i64(); \
\
tcg_gen_concat_i32_i64(arg1, al1, ah1); \
gen_helper_##name(ret, arg1, arg2); \
tcg_gen_extr_i64_i32(rl, rh, ret); \
\
tcg_temp_free_i64(ret); \
tcg_temp_free_i64(arg1); \
} while (0)
#define EA_ABS_FORMAT(con) (((con & 0x3C000) << 14) + (con & 0x3FFF))
#define EA_B_ABSOLUT(con) (((offset & 0xf00000) << 8) | \
((offset & 0x0fffff) << 1))
@ -820,6 +832,45 @@ static inline void gen_subc_CC(TCGv ret, TCGv r1, TCGv r2)
tcg_temp_free(temp);
}
static inline void gen_cond_sub(TCGCond cond, TCGv r1, TCGv r2, TCGv r3,
TCGv r4)
{
TCGv temp = tcg_temp_new();
TCGv temp2 = tcg_temp_new();
TCGv result = tcg_temp_new();
TCGv mask = tcg_temp_new();
TCGv t0 = tcg_const_i32(0);
/* create mask for sticky bits */
tcg_gen_setcond_tl(cond, mask, r4, t0);
tcg_gen_shli_tl(mask, mask, 31);
tcg_gen_sub_tl(result, r1, r2);
/* Calc PSW_V */
tcg_gen_xor_tl(temp, result, r1);
tcg_gen_xor_tl(temp2, r1, r2);
tcg_gen_and_tl(temp, temp, temp2);
tcg_gen_movcond_tl(cond, cpu_PSW_V, r4, t0, temp, cpu_PSW_V);
/* Set PSW_SV */
tcg_gen_and_tl(temp, temp, mask);
tcg_gen_or_tl(cpu_PSW_SV, temp, cpu_PSW_SV);
/* calc AV bit */
tcg_gen_add_tl(temp, result, result);
tcg_gen_xor_tl(temp, temp, result);
tcg_gen_movcond_tl(cond, cpu_PSW_AV, r4, t0, temp, cpu_PSW_AV);
/* calc SAV bit */
tcg_gen_and_tl(temp, temp, mask);
tcg_gen_or_tl(cpu_PSW_SAV, temp, cpu_PSW_SAV);
/* write back result */
tcg_gen_movcond_tl(cond, r3, r4, t0, result, r1);
tcg_temp_free(t0);
tcg_temp_free(temp);
tcg_temp_free(temp2);
tcg_temp_free(result);
tcg_temp_free(mask);
}
static inline void gen_abs(TCGv ret, TCGv r1)
{
TCGv temp = tcg_temp_new();
@ -5042,6 +5093,99 @@ static void decode_rrpw_extract_insert(CPUTriCoreState *env, DisasContext *ctx)
}
}
/* RRR format */
static void decode_rrr_cond_select(CPUTriCoreState *env, DisasContext *ctx)
{
uint32_t op2;
int r1, r2, r3, r4;
TCGv temp;
op2 = MASK_OP_RRR_OP2(ctx->opcode);
r1 = MASK_OP_RRR_S1(ctx->opcode);
r2 = MASK_OP_RRR_S2(ctx->opcode);
r3 = MASK_OP_RRR_S3(ctx->opcode);
r4 = MASK_OP_RRR_D(ctx->opcode);
switch (op2) {
case OPC2_32_RRR_CADD:
gen_cond_add(TCG_COND_NE, cpu_gpr_d[r1], cpu_gpr_d[r2],
cpu_gpr_d[r4], cpu_gpr_d[r3]);
break;
case OPC2_32_RRR_CADDN:
gen_cond_add(TCG_COND_EQ, cpu_gpr_d[r1], cpu_gpr_d[r2], cpu_gpr_d[r4],
cpu_gpr_d[r3]);
break;
case OPC2_32_RRR_CSUB:
gen_cond_sub(TCG_COND_NE, cpu_gpr_d[r1], cpu_gpr_d[r2], cpu_gpr_d[r4],
cpu_gpr_d[r3]);
break;
case OPC2_32_RRR_CSUBN:
gen_cond_sub(TCG_COND_EQ, cpu_gpr_d[r1], cpu_gpr_d[r2], cpu_gpr_d[r4],
cpu_gpr_d[r3]);
break;
case OPC2_32_RRR_SEL:
temp = tcg_const_i32(0);
tcg_gen_movcond_tl(TCG_COND_NE, cpu_gpr_d[r4], cpu_gpr_d[r3], temp,
cpu_gpr_d[r1], cpu_gpr_d[r2]);
tcg_temp_free(temp);
break;
case OPC2_32_RRR_SELN:
temp = tcg_const_i32(0);
tcg_gen_movcond_tl(TCG_COND_EQ, cpu_gpr_d[r4], cpu_gpr_d[r3], temp,
cpu_gpr_d[r1], cpu_gpr_d[r2]);
tcg_temp_free(temp);
break;
}
}
static void decode_rrr_divide(CPUTriCoreState *env, DisasContext *ctx)
{
uint32_t op2;
int r1, r2, r3, r4;
op2 = MASK_OP_RRR_OP2(ctx->opcode);
r1 = MASK_OP_RRR_S1(ctx->opcode);
r2 = MASK_OP_RRR_S2(ctx->opcode);
r3 = MASK_OP_RRR_S3(ctx->opcode);
r4 = MASK_OP_RRR_D(ctx->opcode);
switch (op2) {
case OPC2_32_RRR_DVADJ:
GEN_HELPER_RRR(dvadj, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3],
cpu_gpr_d[r3+1], cpu_gpr_d[r2]);
break;
case OPC2_32_RRR_DVSTEP:
GEN_HELPER_RRR(dvstep, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3],
cpu_gpr_d[r3+1], cpu_gpr_d[r2]);
break;
case OPC2_32_RRR_DVSTEP_U:
GEN_HELPER_RRR(dvstep_u, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3],
cpu_gpr_d[r3+1], cpu_gpr_d[r2]);
break;
case OPC2_32_RRR_IXMAX:
GEN_HELPER_RRR(ixmax, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3],
cpu_gpr_d[r3+1], cpu_gpr_d[r2]);
break;
case OPC2_32_RRR_IXMAX_U:
GEN_HELPER_RRR(ixmax_u, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3],
cpu_gpr_d[r3+1], cpu_gpr_d[r2]);
break;
case OPC2_32_RRR_IXMIN:
GEN_HELPER_RRR(ixmin, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3],
cpu_gpr_d[r3+1], cpu_gpr_d[r2]);
break;
case OPC2_32_RRR_IXMIN_U:
GEN_HELPER_RRR(ixmin_u, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3],
cpu_gpr_d[r3+1], cpu_gpr_d[r2]);
break;
case OPC2_32_RRR_PACK:
gen_helper_pack(cpu_gpr_d[r4], cpu_PSW_C, cpu_gpr_d[r3],
cpu_gpr_d[r3+1], cpu_gpr_d[r1]);
break;
}
}
static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx)
{
int op1;
@ -5325,6 +5469,12 @@ static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx)
tcg_temp_free(temp);
}
break;
/* RRR Format */
case OPCM_32_RRR_COND_SELECT:
decode_rrr_cond_select(env, ctx);
break;
case OPCM_32_RRR_DIVIDE:
decode_rrr_divide(env, ctx);
}
}

View File

@ -516,7 +516,7 @@ enum {
OPC1_32_RRPW_DEXTR = 0x77,
/* RRR Format */
OPCM_32_RRR_COND_SELECT = 0x2b,
OPCM_32_RRR_FLOAT = 0x6b,
OPCM_32_RRR_DIVIDE = 0x6b,
/* RRR1 Format */
OPCM_32_RRR1_MADD = 0x83,
OPCM_32_RRR1_MADDQ_H = 0x43,