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:
Faraz Shahbazker
2022-02-02 11:17:25 +01:00
committed by Mike Frysinger
parent fc3c199fac
commit 06c441ccef
26 changed files with 3749 additions and 75 deletions

View File

@@ -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);