forked from Imagelibrary/binutils-gdb
sim: mips: Add simulator support for mips32r6/mips64r6
2022-02-01 Ali Lown <ali.lown@imgtec.com> Andrew Bennett <andrew.bennett@imgtec.com> Dragan Mladjenovic <dragan.mladjenovic@rt-rk.com> Faraz Shahbazker <fshahbazker@wavecomp.com> sim/common/ChangeLog: * sim-bits.h (EXTEND9, EXTEND18 ,EXTEND19, EXTEND21, EXTEND26): New macros. sim/mips/ChangeLog: * Makefile.in (IGEN_INCLUDE): Add mips3264r6.igen. * configure: Regenerate. * configure.ac: Support mipsisa32r6 and mipsisa64r6. (sim_engine_run): Pick simulator model from processor specified in e_flags. * cp1.c (value_fpr): Handle fmt_dc32. (fp_unary, fp_binary): Zero initialize locals. (update_fcsr, fp_classify, fp_rint, fp_r6_cmp, inner_fmac, fp_fmac, fp_min, fp_max, fp_mina, fp_maxa, fp_fmadd, fp_fmsub): New functions. (sim_fpu_class_mips_mapping): New. * cp1.h (fcsr_ABS2008_mask, fcsr_ABS2008_shift): New define. * interp.c (MIPSR6_P): New. (load_word): Allow unaligned memory access for MIPSR6. * micromips.igen (sc, scd): Adapt to new do_sc* helper signature. * mips.igen: Add *r6 models. (signal_if_cti, forbiddenslot32): New helpers. (delayslot32): Use signal_if_cti. (do_sc, do_scd); Add store_ll_bit parameter. (sc, scd): Adapt to previous change. (nal, beq, bal): New definitions for *r6. (sll): Split nop and ssnop cases into ... (nop, ssnop): New definitions. (loadstore_ea): Use the 32-bit compatibility adressing. (cache): Split logic into ... (do_cache): New helper. (check_fpu): Select IEEE 754-2008 mode for R6. (not_word_value, unpredictable, check_mt_hilo, check_mf_hilo, check_multi_hilo, check_div_hilo, check_u64, do_dmfc1b, add, li, addu, and, andi, bgez, bgtz, blez, bltz, bne, break, dadd, daddiu, daddu, dror, dror32, drorv, dsll, dsll32, dsllv, dsra, dsra32, dsrav, dsrl, dsrl32, dsub, dsubu, j, jal, jalr, jalr.hb, lb, lbu, ld, lh, lhu, lui, lw, lwu, nor, or, ori, ror, rorv, sb, sd, sh, sll, sllv, slt, slti, sltiu, sltu, sra, srav, srl, srlv, sub, subu, sw, sync, syscall, teq, tge, tgeu, tlt, tltu, tne, xor, xori, check_fmt_p, do_load_double, do_store_double, abs.FMT, add.FMT, ceil.l.FMT, ceil.w.FMT, cfc1, ctc1, cvt.d.FMT, cvt.l.FMT, cvt.w.FMT, div.FMT, dfmc1, dmtc1, floor.l.FMT, floor.w.FMT, ldc1, lwc1, mfc1, mov.FMT, mtc1, mul.FMT, recip.FMT, round.l.FMT, round.w.FMT, rsqrt.FMT, sdc1, sqrt.FMT, sub.FMT, swc1, trunc.l.FMT, trunc.w.FMT, bc0f, bc0fl, bc0t, bc0tl, dmfc0, dmtc0, eret, mfc0, mtc0, cop, tlbp, tlbr, tlbwi, tlbwr): Enable on *r6 models. * mips3264r2.igen (dext, dextm, dextu, di, dins, dinsm, dinsu, dsbh, dshd, ei, ext, mfhc1, mthc1, ins, seb, seh, synci, rdhwr, wsbh): Likewise. * mips3264r6.igen: New file. * sim-main.h (FP_formats): Add fmt_dc32. (FORBIDDEN_SLOT): New macros. (simFORBIDDENSLOT, FP_R6CMP_*, FP_R6CLASS_*): New defines. (fp_r6_cmp, fp_classify, fp_rint, fp_min, fp_max, fp_mina, fp_maxa, fp_fmadd, fp_fmsub): New declarations. (R6Compare, Classify, RoundToIntegralExact, Min, Max, MinA, MaxA, FusedMultiplyAdd, FusedMultiplySub): New macros. Wrapping previous declarations. sim/testsuite/mips/ChangeLog: * basic.exp: Add r6-*.s tests. (run_r6_removed_test): New function. (run_endian_tests): New function. * hilo-hazard-3.s: Skip for mips*r6. * r2-fpu.s: New test. * r6-64.s: New test. * r6-branch.s: New test. * r6-forbidden.s: New test. * r6-fpu.s: New test. * r6-llsc-dp.s: New test. * r6-llsc-wp.s: New test. * r6-removed.csv: New test. * r6-removed.s: New test. * r6.s: New test. * utils-r6.inc: New inc.
This commit is contained in:
committed by
Mike Frysinger
parent
fc3c199fac
commit
06c441ccef
432
sim/mips/cp1.c
432
sim/mips/cp1.c
@@ -100,6 +100,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
#define FPQNaN_LONG (UNSIGNED64 (0x7FFFFFFFFFFFFFFF))
|
||||
#define FPQNaN_PS (FP_PS_cat (FPQNaN_SINGLE, FPQNaN_SINGLE))
|
||||
|
||||
static void update_fcsr (sim_cpu *, address_word, sim_fpu_status);
|
||||
|
||||
static const char *fpu_format_name (FP_formats fmt);
|
||||
#ifdef DEBUG
|
||||
static const char *fpu_rounding_mode_name (int rm);
|
||||
@@ -127,7 +129,7 @@ value_fpr (sim_cpu *cpu,
|
||||
}
|
||||
|
||||
/* For values not yet accessed, set to the desired format. */
|
||||
if (fmt < fmt_uninterpreted)
|
||||
if (fmt < fmt_uninterpreted && fmt != fmt_dc32)
|
||||
{
|
||||
if (FPR_STATE[fpr] == fmt_uninterpreted)
|
||||
{
|
||||
@@ -137,7 +139,10 @@ value_fpr (sim_cpu *cpu,
|
||||
fpu_format_name (fmt));
|
||||
#endif /* DEBUG */
|
||||
}
|
||||
else if (fmt != FPR_STATE[fpr])
|
||||
else if (fmt != FPR_STATE[fpr]
|
||||
&& !(fmt == fmt_single
|
||||
&& FPR_STATE[fpr] == fmt_double
|
||||
&& (FGR[fpr] == 0 || FGR[fpr] == 0xFFFFFFFF)))
|
||||
{
|
||||
sim_io_eprintf (SD, "FPR %d (format %s) being accessed with format %s - setting to unknown (PC = 0x%s)\n",
|
||||
fpr, fpu_format_name (FPR_STATE[fpr]),
|
||||
@@ -166,6 +171,7 @@ value_fpr (sim_cpu *cpu,
|
||||
case fmt_uninterpreted_32:
|
||||
case fmt_single:
|
||||
case fmt_word:
|
||||
case fmt_dc32:
|
||||
value = (FGR[fpr] & 0xFFFFFFFF);
|
||||
break;
|
||||
|
||||
@@ -557,8 +563,8 @@ fp_test(uint64_t op1,
|
||||
|
||||
if (sim_fpu_is_nan (&wop1) || sim_fpu_is_nan (&wop2))
|
||||
{
|
||||
if ((cond & (1 << 3)) ||
|
||||
sim_fpu_is_snan (&wop1) || sim_fpu_is_snan (&wop2))
|
||||
if ((cond & (1 << 3))
|
||||
|| sim_fpu_is_snan (&wop1) || sim_fpu_is_snan (&wop2))
|
||||
status = sim_fpu_status_invalid_snan;
|
||||
less = 0;
|
||||
equal = 0;
|
||||
@@ -581,6 +587,109 @@ fp_test(uint64_t op1,
|
||||
return status;
|
||||
}
|
||||
|
||||
static const int sim_fpu_class_mips_mapping[] = {
|
||||
FP_R6CLASS_SNAN, /* SIM_FPU_IS_SNAN = 1, Noisy not-a-number */
|
||||
FP_R6CLASS_QNAN, /* SIM_FPU_IS_QNAN = 2, Quiet not-a-number */
|
||||
FP_R6CLASS_NEGINF, /* SIM_FPU_IS_NINF = 3, -infinity */
|
||||
FP_R6CLASS_POSINF, /* SIM_FPU_IS_PINF = 4, +infinity */
|
||||
FP_R6CLASS_NEGNORM, /* SIM_FPU_IS_NNUMBER = 5, -num - [-MAX .. -MIN] */
|
||||
FP_R6CLASS_POSNORM, /* SIM_FPU_IS_PNUMBER = 6, +num - [+MIN .. +MAX] */
|
||||
FP_R6CLASS_NEGSUB, /* SIM_FPU_IS_NDENORM = 7, -denorm - (MIN .. 0) */
|
||||
FP_R6CLASS_POSSUB, /* SIM_FPU_IS_PDENORM = 8, +denorm - (0 .. MIN) */
|
||||
FP_R6CLASS_NEGZERO, /* SIM_FPU_IS_NZERO = 9, -0 */
|
||||
FP_R6CLASS_POSZERO /* SIM_FPU_IS_PZERO = 10, +0 */
|
||||
};
|
||||
|
||||
uint64_t
|
||||
fp_classify (sim_cpu *cpu,
|
||||
address_word cia,
|
||||
uint64_t op,
|
||||
FP_formats fmt)
|
||||
{
|
||||
sim_fpu wop;
|
||||
|
||||
switch (fmt)
|
||||
{
|
||||
case fmt_single:
|
||||
sim_fpu_32to (&wop, op);
|
||||
break;
|
||||
case fmt_double:
|
||||
sim_fpu_64to (&wop, op);
|
||||
break;
|
||||
default:
|
||||
sim_io_error (SD, "Bad switch\n");
|
||||
}
|
||||
return sim_fpu_class_mips_mapping[sim_fpu_classify (&wop) - 1];
|
||||
}
|
||||
|
||||
int
|
||||
fp_rint (sim_cpu *cpu,
|
||||
address_word cia,
|
||||
uint64_t op,
|
||||
uint64_t *ans,
|
||||
FP_formats fmt)
|
||||
{
|
||||
sim_fpu wop = {0}, wtemp = {0}, wmagic = {0}, wans = {0};
|
||||
int64_t intermediate;
|
||||
int status = 0;
|
||||
sim_fpu_round round = rounding_mode (GETRM());
|
||||
|
||||
switch (fmt)
|
||||
{
|
||||
case fmt_single:
|
||||
sim_fpu_32to (&wop, op);
|
||||
sim_fpu_32to (&wmagic, 0x4b000000);
|
||||
break;
|
||||
case fmt_double:
|
||||
sim_fpu_64to (&wop, op);
|
||||
sim_fpu_64to (&wmagic, 0x4330000000000000);
|
||||
break;
|
||||
default:
|
||||
sim_io_error (SD, "Bad switch\n");
|
||||
}
|
||||
|
||||
if (sim_fpu_is_nan (&wop) || sim_fpu_is_infinity (&wop))
|
||||
{
|
||||
status = sim_fpu_status_invalid_cvi;
|
||||
update_fcsr (cpu, cia, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
switch (fmt)
|
||||
{
|
||||
case fmt_single:
|
||||
if (sim_fpu_is_ge (&wop, &wmagic))
|
||||
wans = wop;
|
||||
else
|
||||
{
|
||||
sim_fpu_add (&wtemp, &wop, &wmagic);
|
||||
sim_fpu_round_32 (&wtemp, round, sim_fpu_denorm_default);
|
||||
sim_fpu_sub (&wans, &wtemp, &wmagic);
|
||||
}
|
||||
sim_fpu_to32 ((uint32_t *) ans, &wans);
|
||||
break;
|
||||
case fmt_double:
|
||||
if (sim_fpu_is_ge (&wop, &wmagic))
|
||||
wans = wop;
|
||||
else
|
||||
{
|
||||
sim_fpu_add (&wtemp, &wop, &wmagic);
|
||||
sim_fpu_round_64 (&wtemp, round, sim_fpu_denorm_default);
|
||||
sim_fpu_sub (&wans, &wtemp, &wmagic);
|
||||
}
|
||||
sim_fpu_to64 (ans, &wans);
|
||||
break;
|
||||
default:
|
||||
sim_io_error (SD, "Bad switch\n");
|
||||
}
|
||||
|
||||
if (*ans != op && status == 0)
|
||||
status = sim_fpu_status_inexact;
|
||||
|
||||
update_fcsr (cpu, cia, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
void
|
||||
fp_cmp(sim_cpu *cpu,
|
||||
address_word cia,
|
||||
@@ -620,11 +729,91 @@ fp_cmp(sim_cpu *cpu,
|
||||
break;
|
||||
}
|
||||
default:
|
||||
sim_io_eprintf (SD, "Bad switch\n");
|
||||
abort ();
|
||||
sim_io_error (SD, "Bad switch\n");
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
fp_r6_cmp (sim_cpu *cpu,
|
||||
address_word cia,
|
||||
uint64_t op1,
|
||||
uint64_t op2,
|
||||
FP_formats fmt,
|
||||
int cond)
|
||||
{
|
||||
sim_fpu wop1, wop2;
|
||||
int result = 0;
|
||||
int signalling = cond & 0x8;
|
||||
|
||||
switch (fmt)
|
||||
{
|
||||
case fmt_single:
|
||||
sim_fpu_32to (&wop1, op1);
|
||||
sim_fpu_32to (&wop2, op2);
|
||||
break;
|
||||
case fmt_double:
|
||||
sim_fpu_64to (&wop1, op1);
|
||||
sim_fpu_64to (&wop2, op2);
|
||||
break;
|
||||
default:
|
||||
sim_io_error (SD, "Bad switch\n");
|
||||
}
|
||||
|
||||
switch (cond)
|
||||
{
|
||||
case FP_R6CMP_AF:
|
||||
result = 0;
|
||||
break;
|
||||
case FP_R6CMP_UN:
|
||||
result = sim_fpu_is_un (&wop1, &wop2);
|
||||
break;
|
||||
case FP_R6CMP_OR:
|
||||
result = sim_fpu_is_or (&wop1, &wop2);
|
||||
break;
|
||||
case FP_R6CMP_EQ:
|
||||
result = sim_fpu_is_eq (&wop1, &wop2);
|
||||
break;
|
||||
case FP_R6CMP_NE:
|
||||
result = sim_fpu_is_ne (&wop1, &wop2);
|
||||
break;
|
||||
case FP_R6CMP_LT:
|
||||
result = sim_fpu_is_lt (&wop1, &wop2);
|
||||
break;
|
||||
case FP_R6CMP_LE:
|
||||
result = sim_fpu_is_le (&wop1, &wop2);
|
||||
break;
|
||||
case FP_R6CMP_UEQ:
|
||||
result = sim_fpu_is_un (&wop1, &wop2) || sim_fpu_is_eq (&wop1, &wop2);
|
||||
break;
|
||||
case FP_R6CMP_UNE:
|
||||
result = sim_fpu_is_un (&wop1, &wop2) || sim_fpu_is_ne (&wop1, &wop2);
|
||||
break;
|
||||
case FP_R6CMP_ULT:
|
||||
result = sim_fpu_is_un (&wop1, &wop2) || sim_fpu_is_lt (&wop1, &wop2);
|
||||
break;
|
||||
case FP_R6CMP_ULE:
|
||||
result = sim_fpu_is_un (&wop1, &wop2) || sim_fpu_is_le (&wop1, &wop2);
|
||||
break;
|
||||
default:
|
||||
update_fcsr (cpu, cia, sim_fpu_status_invalid_cmp);
|
||||
break;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
switch (fmt)
|
||||
{
|
||||
case fmt_single:
|
||||
return 0xFFFFFFFF;
|
||||
case fmt_double:
|
||||
return 0xFFFFFFFFFFFFFFFF;
|
||||
default:
|
||||
sim_io_error (SD, "Bad switch\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Basic arithmetic operations. */
|
||||
|
||||
@@ -635,7 +824,7 @@ fp_unary(sim_cpu *cpu,
|
||||
uint64_t op,
|
||||
FP_formats fmt)
|
||||
{
|
||||
sim_fpu wop;
|
||||
sim_fpu wop = {0};
|
||||
sim_fpu ans;
|
||||
sim_fpu_round round = rounding_mode (GETRM());
|
||||
sim_fpu_denorm denorm = denorm_mode (cpu);
|
||||
@@ -680,8 +869,7 @@ fp_unary(sim_cpu *cpu,
|
||||
break;
|
||||
}
|
||||
default:
|
||||
sim_io_eprintf (SD, "Bad switch\n");
|
||||
abort ();
|
||||
sim_io_error (SD, "Bad switch\n");
|
||||
}
|
||||
|
||||
update_fcsr (cpu, cia, status);
|
||||
@@ -696,9 +884,9 @@ fp_binary(sim_cpu *cpu,
|
||||
uint64_t op2,
|
||||
FP_formats fmt)
|
||||
{
|
||||
sim_fpu wop1;
|
||||
sim_fpu wop2;
|
||||
sim_fpu ans;
|
||||
sim_fpu wop1 = {0};
|
||||
sim_fpu wop2 = {0};
|
||||
sim_fpu ans = {0};
|
||||
sim_fpu_round round = rounding_mode (GETRM());
|
||||
sim_fpu_denorm denorm = denorm_mode (cpu);
|
||||
sim_fpu_status status = 0;
|
||||
@@ -746,8 +934,7 @@ fp_binary(sim_cpu *cpu,
|
||||
break;
|
||||
}
|
||||
default:
|
||||
sim_io_eprintf (SD, "Bad switch\n");
|
||||
abort ();
|
||||
sim_io_error (SD, "Bad switch\n");
|
||||
}
|
||||
|
||||
update_fcsr (cpu, cia, status);
|
||||
@@ -786,7 +973,7 @@ inner_mac(int (*sim_fpu_op)(sim_fpu *, const sim_fpu *, const sim_fpu *),
|
||||
ans.normal_exp += scale;
|
||||
status |= sim_fpu_round_32 (&ans, round, denorm);
|
||||
wop1 = ans;
|
||||
op_status = 0;
|
||||
op_status = 0;
|
||||
sim_fpu_32to (&wop2, op3);
|
||||
op_status |= (*sim_fpu_op) (&ans, &wop1, &wop2);
|
||||
op_status |= sim_fpu_round_32 (&ans, round, denorm);
|
||||
@@ -812,7 +999,7 @@ inner_mac(int (*sim_fpu_op)(sim_fpu *, const sim_fpu *, const sim_fpu *),
|
||||
ans.normal_exp += scale;
|
||||
status |= sim_fpu_round_64 (&ans, round, denorm);
|
||||
wop1 = ans;
|
||||
op_status = 0;
|
||||
op_status = 0;
|
||||
sim_fpu_64to (&wop2, op3);
|
||||
op_status |= (*sim_fpu_op) (&ans, &wop1, &wop2);
|
||||
op_status |= sim_fpu_round_64 (&ans, round, denorm);
|
||||
@@ -881,8 +1068,89 @@ fp_mac(sim_cpu *cpu,
|
||||
break;
|
||||
}
|
||||
default:
|
||||
sim_io_eprintf (SD, "Bad switch\n");
|
||||
abort ();
|
||||
sim_io_error (SD, "Bad switch\n");
|
||||
}
|
||||
|
||||
update_fcsr (cpu, cia, status);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Common FMAC code for .s, .d. Defers setting FCSR to caller. */
|
||||
static sim_fpu_status
|
||||
inner_fmac (sim_cpu *cpu,
|
||||
int (*sim_fpu_op) (sim_fpu *, const sim_fpu *, const sim_fpu *),
|
||||
uint64_t op1,
|
||||
uint64_t op2,
|
||||
uint64_t op3,
|
||||
sim_fpu_round round,
|
||||
sim_fpu_denorm denorm,
|
||||
FP_formats fmt,
|
||||
uint64_t *result)
|
||||
{
|
||||
sim_fpu wop1, wop2, ans;
|
||||
sim_fpu_status status = 0;
|
||||
sim_fpu_status op_status;
|
||||
uint32_t t32 = 0;
|
||||
uint64_t t64 = 0;
|
||||
|
||||
switch (fmt)
|
||||
{
|
||||
case fmt_single:
|
||||
sim_fpu_32to (&wop1, op1);
|
||||
sim_fpu_32to (&wop2, op2);
|
||||
status |= sim_fpu_mul (&ans, &wop1, &wop2);
|
||||
wop1 = ans;
|
||||
op_status = 0;
|
||||
sim_fpu_32to (&wop2, op3);
|
||||
op_status |= (*sim_fpu_op) (&ans, &wop2, &wop1);
|
||||
op_status |= sim_fpu_round_32 (&ans, round, denorm);
|
||||
status |= op_status;
|
||||
sim_fpu_to32 (&t32, &ans);
|
||||
t64 = t32;
|
||||
break;
|
||||
case fmt_double:
|
||||
sim_fpu_64to (&wop1, op1);
|
||||
sim_fpu_64to (&wop2, op2);
|
||||
status |= sim_fpu_mul (&ans, &wop1, &wop2);
|
||||
wop1 = ans;
|
||||
op_status = 0;
|
||||
sim_fpu_64to (&wop2, op3);
|
||||
op_status |= (*sim_fpu_op) (&ans, &wop2, &wop1);
|
||||
op_status |= sim_fpu_round_64 (&ans, round, denorm);
|
||||
status |= op_status;
|
||||
sim_fpu_to64 (&t64, &ans);
|
||||
break;
|
||||
default:
|
||||
sim_io_error (SD, "Bad switch\n");
|
||||
}
|
||||
|
||||
*result = t64;
|
||||
return status;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
fp_fmac (sim_cpu *cpu,
|
||||
address_word cia,
|
||||
int (*sim_fpu_op) (sim_fpu *, const sim_fpu *, const sim_fpu *),
|
||||
uint64_t op1,
|
||||
uint64_t op2,
|
||||
uint64_t op3,
|
||||
FP_formats fmt)
|
||||
{
|
||||
sim_fpu_round round = rounding_mode (GETRM());
|
||||
sim_fpu_denorm denorm = denorm_mode (cpu);
|
||||
sim_fpu_status status = 0;
|
||||
uint64_t result = 0;
|
||||
|
||||
switch (fmt)
|
||||
{
|
||||
case fmt_single:
|
||||
case fmt_double:
|
||||
status = inner_fmac (cpu, sim_fpu_op, op1, op2, op3,
|
||||
round, denorm, fmt, &result);
|
||||
break;
|
||||
default:
|
||||
sim_io_error (SD, "Bad switch\n");
|
||||
}
|
||||
|
||||
update_fcsr (cpu, cia, status);
|
||||
@@ -972,8 +1240,7 @@ fp_inv_sqrt(sim_cpu *cpu,
|
||||
break;
|
||||
}
|
||||
default:
|
||||
sim_io_eprintf (SD, "Bad switch\n");
|
||||
abort ();
|
||||
sim_io_error (SD, "Bad switch\n");
|
||||
}
|
||||
|
||||
update_fcsr (cpu, cia, status);
|
||||
@@ -1039,6 +1306,94 @@ fp_div(sim_cpu *cpu,
|
||||
return fp_binary(cpu, cia, &sim_fpu_div, op1, op2, fmt);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
fp_min (sim_cpu *cpu,
|
||||
address_word cia,
|
||||
uint64_t op1,
|
||||
uint64_t op2,
|
||||
FP_formats fmt)
|
||||
{
|
||||
return fp_binary (cpu, cia, &sim_fpu_min, op1, op2, fmt);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
fp_max (sim_cpu *cpu,
|
||||
address_word cia,
|
||||
uint64_t op1,
|
||||
uint64_t op2,
|
||||
FP_formats fmt)
|
||||
{
|
||||
return fp_binary (cpu, cia, &sim_fpu_max, op1, op2, fmt);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
fp_mina (sim_cpu *cpu,
|
||||
address_word cia,
|
||||
uint64_t op1,
|
||||
uint64_t op2,
|
||||
FP_formats fmt)
|
||||
{
|
||||
uint64_t ret;
|
||||
sim_fpu wop1 = {0}, wop2 = {0}, waop1, waop2, wans;
|
||||
sim_fpu_status status = 0;
|
||||
|
||||
switch (fmt)
|
||||
{
|
||||
case fmt_single:
|
||||
sim_fpu_32to (&wop1, op1);
|
||||
sim_fpu_32to (&wop2, op2);
|
||||
break;
|
||||
case fmt_double:
|
||||
sim_fpu_64to (&wop1, op1);
|
||||
sim_fpu_64to (&wop2, op2);
|
||||
break;
|
||||
default:
|
||||
sim_io_error (SD, "Bad switch\n");
|
||||
}
|
||||
|
||||
status |= sim_fpu_abs (&waop1, &wop1);
|
||||
status |= sim_fpu_abs (&waop2, &wop2);
|
||||
status |= sim_fpu_min (&wans, &waop1, &waop2);
|
||||
ret = (sim_fpu_is_eq (&wans, &waop1)) ? op1 : op2;
|
||||
|
||||
update_fcsr (cpu, cia, status);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
fp_maxa (sim_cpu *cpu,
|
||||
address_word cia,
|
||||
uint64_t op1,
|
||||
uint64_t op2,
|
||||
FP_formats fmt)
|
||||
{
|
||||
uint64_t ret;
|
||||
sim_fpu wop1 = {0}, wop2 = {0}, waop1, waop2, wans;
|
||||
sim_fpu_status status = 0;
|
||||
|
||||
switch (fmt)
|
||||
{
|
||||
case fmt_single:
|
||||
sim_fpu_32to (&wop1, op1);
|
||||
sim_fpu_32to (&wop2, op2);
|
||||
break;
|
||||
case fmt_double:
|
||||
sim_fpu_64to (&wop1, op1);
|
||||
sim_fpu_64to (&wop2, op2);
|
||||
break;
|
||||
default:
|
||||
sim_io_error (SD, "Bad switch\n");
|
||||
}
|
||||
|
||||
status |= sim_fpu_abs (&waop1, &wop1);
|
||||
status |= sim_fpu_abs (&waop2, &wop2);
|
||||
status |= sim_fpu_max (&wans, &waop1, &waop2);
|
||||
ret = (sim_fpu_is_eq (&wans, &waop1)) ? op1 : op2;
|
||||
|
||||
update_fcsr (cpu, cia, status);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
fp_recip(sim_cpu *cpu,
|
||||
address_word cia,
|
||||
@@ -1088,6 +1443,28 @@ fp_msub(sim_cpu *cpu,
|
||||
return fp_mac(cpu, cia, &sim_fpu_sub, op1, op2, op3, 0, 0, fmt);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
fp_fmadd (sim_cpu *cpu,
|
||||
address_word cia,
|
||||
uint64_t op1,
|
||||
uint64_t op2,
|
||||
uint64_t op3,
|
||||
FP_formats fmt)
|
||||
{
|
||||
return fp_fmac (cpu, cia, &sim_fpu_add, op1, op2, op3, fmt);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
fp_fmsub (sim_cpu *cpu,
|
||||
address_word cia,
|
||||
uint64_t op1,
|
||||
uint64_t op2,
|
||||
uint64_t op3,
|
||||
FP_formats fmt)
|
||||
{
|
||||
return fp_fmac (cpu, cia, &sim_fpu_sub, op1, op2, op3, fmt);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
fp_nmadd(sim_cpu *cpu,
|
||||
address_word cia,
|
||||
@@ -1394,8 +1771,7 @@ convert (sim_cpu *cpu,
|
||||
status = sim_fpu_i64to (&wop, op, round);
|
||||
break;
|
||||
default:
|
||||
sim_io_eprintf (SD, "Bad switch\n");
|
||||
abort ();
|
||||
sim_io_error (SD, "Bad switch\n");
|
||||
}
|
||||
|
||||
/* Convert sim_fpu format into the output */
|
||||
@@ -1430,8 +1806,7 @@ convert (sim_cpu *cpu,
|
||||
break;
|
||||
default:
|
||||
result64 = 0;
|
||||
sim_io_eprintf (SD, "Bad switch\n");
|
||||
abort ();
|
||||
sim_io_error (SD, "Bad switch\n");
|
||||
}
|
||||
|
||||
update_fcsr (cpu, cia, status);
|
||||
@@ -1481,8 +1856,7 @@ pack_ps(sim_cpu *cpu,
|
||||
break;
|
||||
}
|
||||
default:
|
||||
sim_io_eprintf (SD, "Bad switch\n");
|
||||
abort ();
|
||||
sim_io_error (SD, "Bad switch\n");
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1517,8 +1891,7 @@ convert_ps (sim_cpu *cpu,
|
||||
sim_fpu_32to (&wop_l, FP_PS_lower(op));
|
||||
break;
|
||||
default:
|
||||
sim_io_eprintf (SD, "Bad switch\n");
|
||||
abort ();
|
||||
sim_io_error (SD, "Bad switch\n");
|
||||
}
|
||||
|
||||
/* Convert sim_fpu format into the output */
|
||||
@@ -1538,8 +1911,7 @@ convert_ps (sim_cpu *cpu,
|
||||
break;
|
||||
default:
|
||||
result = 0;
|
||||
sim_io_eprintf (SD, "Bad switch\n");
|
||||
abort ();
|
||||
sim_io_error (SD, "Bad switch\n");
|
||||
}
|
||||
|
||||
update_fcsr (cpu, cia, status_u | status_l);
|
||||
|
||||
Reference in New Issue
Block a user