+2002-06-06 Chris Demetriou <cgd@broadcom.com>
+ Ed Satterthwaite <ehs@broadcom.com>
+
+ * cp1.h: New file.
+ * sim-main.h: Include cp1.h.
+ (SETFCC, GETFCC, IR, UF, OF, DX, IO, UO, FP_FLAGS, FP_ENABLE)
+ (FP_CAUSE, GETFS, FP_RM_NEAREST, FP_RM_TOZERO, FP_RM_TOPINF)
+ (FP_RM_TOMINF, GETRM): Remove. Moved to cp1.h.
+ (FP_FS, FP_MASK_RM, FP_SH_RM, Nan, Less, Equal): Remove.
+ (value_fcr, store_fcr, test_fcsr, fp_cmp): New prototypes.
+ (ValueFCR, StoreFCR, TestFCSR, Compare): New macros.
+ * cp1.c: Don't include sim-fpu.h; already included by
+ sim-main.h. Clean up formatting of some comments.
+ (NaN, Equal, Less): Remove.
+ (test_fcsr, value_fcr, store_fcr, update_fcsr, fp_test)
+ (fp_cmp): New functions.
+ * mips.igen (do_c_cond_fmt): Remove.
+ (C.cond.fmta, C.cond.fmtb): Replace uses of do_c_cond_fmt_a with
+ Compare. Add result tracing.
+ (CxC1): Remove, replace with...
+ (CFC1a, CFC1b, CFC1c, CTC1a, CTC1b, CTC1c): New instructions.
+ (DMxC1): Remove, replace with...
+ (DMFC1a, DMFC1b, DMTC1a, DMTC1b): New instructions.
+ (MxC1): Remove, replace with...
+ (MFC1a, MFC1b, MTC1a, MTC1b): New instructions.
+
2002-06-04 Chris Demetriou <cgd@broadcom.com>
* sim-main.h (FGRIDX): Remove, replace all uses with...
*/
#include "sim-main.h"
-#include "sim-fpu.h"
/* Within cp1.c we refer to sim_cpu directly. */
#define CPU cpu
return;
}
-int
-NaN (op, fmt)
- uword64 op;
- FP_formats fmt;
+
+/* CP1 control/status registers */
+
+void
+test_fcsr (sim_cpu *cpu,
+ address_word cia)
{
- int boolean = 0;
- switch (fmt)
+ unsigned int cause;
+
+ cause = (FCSR & fcsr_CAUSE_mask) >> fcsr_CAUSE_shift;
+ if ((cause & ((FCSR & fcsr_ENABLES_mask) >> fcsr_ENABLES_shift)) != 0
+ || (cause & (1 << UO)))
{
- case fmt_single:
- case fmt_word:
- {
- sim_fpu wop;
- sim_fpu_32to (&wop, op);
- boolean = sim_fpu_is_nan (&wop);
- break;
- }
- case fmt_double:
- case fmt_long:
- {
- sim_fpu wop;
- sim_fpu_64to (&wop, op);
- boolean = sim_fpu_is_nan (&wop);
- break;
- }
- default:
- fprintf (stderr, "Bad switch\n");
- abort ();
+ SignalExceptionFPE();
}
+}
-#ifdef DEBUG
- printf ("DBG: NaN: returning %d for 0x%s (format = %s)\n",
- boolean, pr_addr (op), fpu_format_name (fmt));
-#endif /* DEBUG */
+unsigned_word
+value_fcr(sim_cpu *cpu,
+ address_word cia,
+ int fcr)
+{
+ unsigned32 value = 0;
+
+ switch (fcr)
+ {
+ case 0: /* FP Implementation and Revision Register */
+ value = FCR0;
+ break;
+ case 25: /* FP Condition Codes Register */
+ value = (FCR31 & fcsr_FCC_mask) >> fcsr_FCC_shift;
+ value = (value & 0x1) | (value >> 1); /* close FCC gap */
+ break;
+ case 26: /* FP Exceptions Register */
+ value = FCR31 & (fcsr_CAUSE_mask | fcsr_FLAGS_mask);
+ break;
+ case 28: /* FP Enables Register */
+ value = FCR31 & (fcsr_ENABLES_mask | fcsr_RM_mask);
+ if (FCR31 & fcsr_FS)
+ value |= 0x4; /* nonstandard FS bit */
+ break;
+ case 31: /* FP Control/Status Register */
+ value = FCR31 & ~fcsr_ZERO_mask;
+ break;
+ }
- return (boolean);
+ return (EXTEND32 (value));
}
-int
-Less (op1, op2, fmt)
- uword64 op1;
- uword64 op2;
- FP_formats fmt;
+void
+store_fcr(sim_cpu *cpu,
+ address_word cia,
+ int fcr,
+ unsigned_word value)
{
- int boolean = 0;
+ unsigned32 v;
- /* Argument checking already performed by the FPCOMPARE code */
+ v = VL4_8(value);
+ switch (fcr)
+ {
+ case 25: /* FP Condition Codes Register */
+ v = (v << 1) | (v & 0x1); /* adjust for FCC gap */
+ FCR31 &= ~fcsr_FCC_mask;
+ FCR31 |= ((v << fcsr_FCC_shift) & fcsr_FCC_mask);
+ break;
+ case 26: /* FP Exceptions Register */
+ FCR31 &= ~(fcsr_CAUSE_mask | fcsr_FLAGS_mask);
+ FCR31 |= (v & (fcsr_CAUSE_mask | fcsr_FLAGS_mask));
+ test_fcsr(cpu, cia);
+ break;
+ case 28: /* FP Enables Register */
+ if (v & 0x4) /* nonstandard FS bit */
+ v |= fcsr_FS;
+ else
+ v &= ~fcsr_FS;
+ FCR31 &= (fcsr_FCC_mask | fcsr_CAUSE_mask | fcsr_FLAGS_mask);
+ FCR31 |= (v & (fcsr_FS | fcsr_ENABLES_mask | fcsr_RM_mask));
+ test_fcsr(cpu, cia);
+ break;
+ case 31: /* FP Control/Status Register */
+ FCR31 = v & ~fcsr_ZERO_mask;
+ test_fcsr(cpu, cia);
+ break;
+ }
+}
-#ifdef DEBUG
- printf ("DBG: Less: %s: op1 = 0x%s : op2 = 0x%s\n",
- fpu_format_name (fmt), pr_addr (op1), pr_addr (op2));
-#endif /* DEBUG */
+void
+update_fcsr (sim_cpu *cpu,
+ address_word cia,
+ sim_fpu_status status)
+{
+ FCSR &= ~fcsr_CAUSE_mask;
- /* The format type should already have been checked: */
+ if (status != 0)
+ {
+ unsigned int cause = 0;
+
+ /* map between sim_fpu codes and MIPS FCSR */
+ if (status & (sim_fpu_status_invalid_snan
+ | sim_fpu_status_invalid_isi
+ | sim_fpu_status_invalid_idi
+ | sim_fpu_status_invalid_zdz
+ | sim_fpu_status_invalid_imz
+ | sim_fpu_status_invalid_cmp
+ | sim_fpu_status_invalid_sqrt
+ | sim_fpu_status_invalid_cvi))
+ cause |= (1 << IO);
+ if (status & sim_fpu_status_invalid_div0)
+ cause |= (1 << DZ);
+ if (status & sim_fpu_status_overflow)
+ cause |= (1 << OF);
+ if (status & sim_fpu_status_underflow)
+ cause |= (1 << UF);
+ if (status & sim_fpu_status_inexact)
+ cause |= (1 << IR);
+#if 0 /* Not yet. */
+ /* Implicit clearing of other bits by unimplemented done by callers. */
+ if (status & sim_fpu_status_unimplemented)
+ cause |= (1 << UO);
+#endif
+
+ FCSR |= (cause << fcsr_CAUSE_shift);
+ test_fcsr (cpu, cia);
+ FCSR |= ((cause & ~(1 << UO)) << fcsr_FLAGS_shift);
+ }
+ return;
+}
+
+
+/* Comparison operations. */
+
+static sim_fpu_status
+fp_test(unsigned64 op1,
+ unsigned64 op2,
+ FP_formats fmt,
+ int abs,
+ int cond,
+ int *condition)
+{
+ sim_fpu wop1;
+ sim_fpu wop2;
+ sim_fpu_status status = 0;
+ int less, equal, unordered;
+
+ /* The format type has already been checked: */
switch (fmt)
{
case fmt_single:
{
- sim_fpu wop1;
- sim_fpu wop2;
sim_fpu_32to (&wop1, op1);
sim_fpu_32to (&wop2, op2);
- boolean = sim_fpu_is_lt (&wop1, &wop2);
break;
}
case fmt_double:
{
- sim_fpu wop1;
- sim_fpu wop2;
sim_fpu_64to (&wop1, op1);
sim_fpu_64to (&wop2, op2);
- boolean = sim_fpu_is_lt (&wop1, &wop2);
break;
}
default:
abort ();
}
-#ifdef DEBUG
- printf ("DBG: Less: returning %d (format = %s)\n",
- boolean, fpu_format_name (fmt));
-#endif /* DEBUG */
-
- return (boolean);
+ 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))
+ status = sim_fpu_status_invalid_snan;
+ less = 0;
+ equal = 0;
+ unordered = 1;
+ }
+ else
+ {
+ if (abs)
+ {
+ status |= sim_fpu_abs (&wop1, &wop1);
+ status |= sim_fpu_abs (&wop2, &wop2);
+ }
+ equal = sim_fpu_is_eq (&wop1, &wop2);
+ less = !equal && sim_fpu_is_lt (&wop1, &wop2);
+ unordered = 0;
+ }
+ *condition = (((cond & (1 << 2)) && less)
+ || ((cond & (1 << 1)) && equal)
+ || ((cond & (1 << 0)) && unordered));
+ return status;
}
-int
-Equal (op1, op2, fmt)
- uword64 op1;
- uword64 op2;
- FP_formats fmt;
+void
+fp_cmp(sim_cpu *cpu,
+ address_word cia,
+ unsigned64 op1,
+ unsigned64 op2,
+ FP_formats fmt,
+ int abs,
+ int cond,
+ int cc)
{
- int boolean = 0;
-
- /* Argument checking already performed by the FPCOMPARE code */
+ sim_fpu_status status = 0;
-#ifdef DEBUG
- printf ("DBG: Equal: %s: op1 = 0x%s : op2 = 0x%s\n",
- fpu_format_name (fmt), pr_addr (op1), pr_addr (op2));
-#endif /* DEBUG */
-
- /* The format type should already have been checked: */
+ /* The format type should already have been checked: */
switch (fmt)
{
case fmt_single:
- {
- sim_fpu wop1;
- sim_fpu wop2;
- sim_fpu_32to (&wop1, op1);
- sim_fpu_32to (&wop2, op2);
- boolean = sim_fpu_is_eq (&wop1, &wop2);
- break;
- }
case fmt_double:
{
- sim_fpu wop1;
- sim_fpu wop2;
- sim_fpu_64to (&wop1, op1);
- sim_fpu_64to (&wop2, op2);
- boolean = sim_fpu_is_eq (&wop1, &wop2);
+ int result;
+ status = fp_test(op1, op2, fmt, abs, cond, &result);
+ update_fcsr (cpu, cia, status);
+ SETFCC (cc, result);
break;
}
default:
- fprintf (stderr, "Bad switch\n");
+ sim_io_eprintf (SD, "Bad switch\n");
abort ();
}
-
-#ifdef DEBUG
- printf ("DBG: Equal: returning %d (format = %s)\n",
- boolean, fpu_format_name (fmt));
-#endif /* DEBUG */
-
- return (boolean);
}
}
+/* Conversion operations. */
+
uword64
convert (sim_cpu *cpu,
address_word cia,
--- /dev/null
+/*> cp1.h <*/
+/* MIPS Simulator FPU (CoProcessor 1) definitions.
+ Copyright (C) 1997, 1998, 2002 Free Software Foundation, Inc.
+ Derived from sim-main.h contributed by Cygnus Solutions,
+ modified substially by Broadcom Corporation (SiByte).
+
+This file is part of GDB, the GNU debugger.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef CP1_H
+#define CP1_H
+
+/* See sim-main.h for allocation of registers FCR0 and FCR31 (FCSR)
+ in CPU state (struct sim_cpu), and for FPU functions. */
+
+#define fcsr_FCC_mask (0xFE800000)
+#define fcsr_FCC_shift (23)
+#define fcsr_FCC_bit(cc) ((cc) == 0 ? 23 : (24 + (cc)))
+#define fcsr_FS (1 << 24) /* MIPS III onwards : Flush to Zero */
+#define fcsr_ZERO_mask (0x007C0000)
+#define fcsr_CAUSE_mask (0x0003F000)
+#define fcsr_CAUSE_shift (12)
+#define fcsr_ENABLES_mask (0x00000F80)
+#define fcsr_ENABLES_shift (7)
+#define fcsr_FLAGS_mask (0x0000007C)
+#define fcsr_FLAGS_shift (2)
+#define fcsr_RM_mask (0x00000003)
+#define fcsr_RM_shift (0)
+
+
+/* Macros to update and retrieve the FCSR condition-code bits. This
+ is complicated by the fact that there is a hole in the index range
+ of the bits within the FCSR register. (Note that the number of bits
+ visible depends on the ISA in use, but that is handled elsewhere.) */
+#define SETFCC(cc,v) \
+ do { \
+ (FCSR = ((FCSR & ~(1 << fcsr_FCC_bit(cc))) | ((v) << fcsr_FCC_bit(cc)))); \
+ } while (0)
+#define GETFCC(cc) ((FCSR & (1 << fcsr_FCC_bit(cc))) != 0 ? 1 : 0)
+
+
+/* Read flush-to-zero bit (not right-justified). */
+#define GETFS() ((int)(FCSR & fcsr_FS))
+
+
+/* FCSR flag bits definitions and access macros. */
+#define IR 0 /* I: Inexact Result */
+#define UF 1 /* U: UnderFlow */
+#define OF 2 /* O: OverFlow */
+#define DZ 3 /* Z: Division by Zero */
+#define IO 4 /* V: Invalid Operation */
+#define UO 5 /* E: Unimplemented Operation (CAUSE field only) */
+
+#define FP_FLAGS(b) (1 << ((b) + fcsr_FLAGS_shift))
+#define FP_ENABLE(b) (1 << ((b) + fcsr_ENABLES_shift))
+#define FP_CAUSE(b) (1 << ((b) + fcsr_CAUSE_shift))
+
+
+/* Rounding mode bit definitions and access macros. */
+#define FP_RM_NEAREST 0 /* Round to nearest (Round). */
+#define FP_RM_TOZERO 1 /* Round to zero (Trunc). */
+#define FP_RM_TOPINF 2 /* Round to Plus infinity (Ceil). */
+#define FP_RM_TOMINF 3 /* Round to Minus infinity (Floor). */
+
+#define GETRM() ((FCSR >> fcsr_RM_shift) & fcsr_RM_mask)
+
+
+#endif /* CP1_H */
}
-
-
-
-
-// C.EQ.S
-// C.EQ.D
-// ...
-
-:function:::void:do_c_cond_fmt:int fmt, int ft, int fs, int cc, int cond, instruction_word insn
-{
- int less;
- int equal;
- int unordered;
- int condition;
- unsigned64 ofs = ValueFPR (fs, fmt);
- unsigned64 oft = ValueFPR (ft, fmt);
- if (NaN (ofs, fmt) || NaN (oft, fmt))
- {
- if (FCSR & FP_ENABLE (IO))
- {
- FCSR |= FP_CAUSE (IO);
- SignalExceptionFPE ();
- }
- less = 0;
- equal = 0;
- unordered = 1;
- }
- else
- {
- less = Less (ofs, oft, fmt);
- equal = Equal (ofs, oft, fmt);
- unordered = 0;
- }
- condition = (((cond & (1 << 2)) && less)
- || ((cond & (1 << 1)) && equal)
- || ((cond & (1 << 0)) && unordered));
- SETFCC (cc, condition);
-}
-
010001,10,3.FMT,5.FT,5.FS,3.0,00,11,4.COND:COP1:32,f::C.cond.fmta
"c.%s<COND>.%s<FMT> f<FS>, f<FT>"
*mipsI:
int fmt = FMT;
check_fpu (SD_);
check_fmt_p (SD_, fmt, instruction_0);
- do_c_cond_fmt (SD_, fmt, FT, FS, 0, COND, instruction_0);
+ Compare (ValueFPR (FS, fmt), ValueFPR (FT, fmt), fmt, COND, 0);
+ TRACE_ALU_RESULT (ValueFCR (31));
}
010001,10,3.FMT,5.FT,5.FS,3.CC,00,11,4.COND:COP1:32,f::C.cond.fmtb
int fmt = FMT;
check_fpu (SD_);
check_fmt_p (SD_, fmt, instruction_0);
- do_c_cond_fmt (SD_, fmt, FT, FS, CC, COND, instruction_0);
+ Compare (ValueFPR (FS, fmt), ValueFPR (FT, fmt), fmt, COND, CC);
+ TRACE_ALU_RESULT (ValueFCR (31));
}
}
-// CFC1
-// CTC1
-010001,00,X,10,5.RT,5.FS,00000000000:COP1Sa:32,f::CxC1
-"c%s<X>c1 r<RT>, f<FS>"
+010001,00010,5.RT,5.FS,00000000000:COP1:32,f::CFC1a
+"cfc1 r<RT>, f<FS>"
*mipsI:
*mipsII:
*mipsIII:
{
check_fpu (SD_);
- if (X)
+ if (FS == 0)
+ PENDING_FILL (RT, EXTEND32 (FCR0));
+ else if (FS == 31)
+ PENDING_FILL (RT, EXTEND32 (FCR31));
+ /* else NOP */
+}
+
+010001,00010,5.RT,5.FS,00000000000:COP1:32,f::CFC1b
+"cfc1 r<RT>, f<FS>"
+*mipsIV:
+*vr4100:
+*vr5000:
+*r3900:
+{
+ check_fpu (SD_);
+ if (FS == 0 || FS == 31)
{
- if (FS == 0)
- PENDING_FILL(FCR0IDX,VL4_8(GPR[RT]));
- else if (FS == 31)
- PENDING_FILL(FCR31IDX,VL4_8(GPR[RT]));
- /* else NOP */
- PENDING_SCHED(FCSR, FCR31 & (1<<23), 1, 23);
- }
- else
- { /* control from */
- if (FS == 0)
- PENDING_FILL(RT, EXTEND32 (FCR0));
- else if (FS == 31)
- PENDING_FILL(RT, EXTEND32 (FCR31));
- /* else NOP */
+ unsigned_word fcr = ValueFCR (FS);
+ TRACE_ALU_INPUT1 (fcr);
+ GPR[RT] = fcr;
}
+ /* else NOP */
+ TRACE_ALU_RESULT (GPR[RT]);
}
-010001,00,X,10,5.RT,5.FS,00000000000:COP1Sb:32,f::CxC1
-"c%s<X>c1 r<RT>, f<FS>"
-*mipsIV:
+
+010001,00010,5.RT,5.FS,00000000000:COP1:32,f::CFC1c
+"cfc1 r<RT>, f<FS>"
*mipsV:
*mips32:
*mips64:
+{
+ check_fpu (SD_);
+ if (FS == 0 || FS == 25 || FS == 26 || FS == 28 || FS == 31)
+ {
+ unsigned_word fcr = ValueFCR (FS);
+ TRACE_ALU_INPUT1 (fcr);
+ GPR[RT] = fcr;
+ }
+ /* else NOP */
+ TRACE_ALU_RESULT (GPR[RT]);
+}
+
+010001,00110,5.RT,5.FS,00000000000:COP1:32,f::CTC1a
+"ctc1 r<RT>, f<FS>"
+*mipsI:
+*mipsII:
+*mipsIII:
+{
+ check_fpu (SD_);
+ if (FS == 31)
+ PENDING_FILL (FCRCS_REGNUM, VL4_8 (GPR[RT]));
+ /* else NOP */
+}
+
+010001,00110,5.RT,5.FS,00000000000:COP1:32,f::CTC1b
+"ctc1 r<RT>, f<FS>"
+*mipsIV:
*vr4100:
*vr5000:
*r3900:
{
check_fpu (SD_);
- if (X)
- {
- /* control to */
- TRACE_ALU_INPUT1 (GPR[RT]);
- if (FS == 0)
- {
- FCR0 = VL4_8(GPR[RT]);
- TRACE_ALU_RESULT (FCR0);
- }
- else if (FS == 31)
- {
- FCR31 = VL4_8(GPR[RT]);
- SETFCC(0,((FCR31 & (1 << 23)) ? 1 : 0));
- TRACE_ALU_RESULT (FCR31);
- }
- else
- {
- TRACE_ALU_RESULT0 ();
- }
- /* else NOP */
- }
- else
- { /* control from */
- if (FS == 0)
- {
- TRACE_ALU_INPUT1 (FCR0);
- GPR[RT] = EXTEND32 (FCR0);
- }
- else if (FS == 31)
- {
- TRACE_ALU_INPUT1 (FCR31);
- GPR[RT] = EXTEND32 (FCR31);
- }
- TRACE_ALU_RESULT (GPR[RT]);
- /* else NOP */
- }
+ TRACE_ALU_INPUT1 (GPR[RT]);
+ if (FS == 31)
+ StoreFCR (FS, GPR[RT]);
+ /* else NOP */
+}
+
+010001,00110,5.RT,5.FS,00000000000:COP1:32,f::CTC1c
+"ctc1 r<RT>, f<FS>"
+*mipsV:
+*mips32:
+*mips64:
+{
+ check_fpu (SD_);
+ TRACE_ALU_INPUT1 (GPR[RT]);
+ if (FS == 25 || FS == 26 || FS == 28 || FS == 31)
+ StoreFCR (FS, GPR[RT]);
+ /* else NOP */
}
}
-// DMFC1
-// DMTC1
-010001,00,X,01,5.RT,5.FS,00000000000:COP1Sa:64,f::DMxC1
-"dm%s<X>c1 r<RT>, f<FS>"
+010001,00001,5.RT,5.FS,00000000000:COP1:64,f::DMFC1a
+"dmfc1 r<RT>, f<FS>"
*mipsIII:
{
+ unsigned64 v;
check_fpu (SD_);
check_u64 (SD_, instruction_0);
- if (X)
- {
- if (SizeFGR() == 64)
- PENDING_FILL((FS + FGR_BASE),GPR[RT]);
- else if ((FS & 0x1) == 0)
- {
- PENDING_FILL(((FS + 1) + FGR_BASE),VH4_8(GPR[RT]));
- PENDING_FILL((FS + FGR_BASE),VL4_8(GPR[RT]));
- }
- }
+ if (SizeFGR () == 64)
+ v = FGR[FS];
+ else if ((FS & 0x1) == 0)
+ v = SET64HI (FGR[FS+1]) | FGR[FS];
else
- {
- if (SizeFGR() == 64)
- PENDING_FILL(RT,FGR[FS]);
- else if ((FS & 0x1) == 0)
- PENDING_FILL(RT,(SET64HI(FGR[FS+1]) | FGR[FS]));
- else
- {
- if (STATE_VERBOSE_P(SD))
- sim_io_eprintf (SD,
- "Warning: PC 0x%lx: semantic_DMxC1_COP1Sa 32-bit use of odd FPR number\n",
- (long) CIA);
- PENDING_FILL(RT,SET64HI(0xDEADC0DE) | 0xBAD0BAD0);
- }
- }
+ v = SET64HI (0xDEADC0DE) | 0xBAD0BAD0;
+ PENDING_FILL (RT, v);
+ TRACE_ALU_RESULT (v);
}
-010001,00,X,01,5.RT,5.FS,00000000000:COP1Sb:64,f::DMxC1
-"dm%s<X>c1 r<RT>, f<FS>"
+
+010001,00001,5.RT,5.FS,00000000000:COP1:64,f::DMFC1b
+"dmfc1 r<RT>, f<FS>"
*mipsIV:
*mipsV:
*mips64:
{
check_fpu (SD_);
check_u64 (SD_, instruction_0);
- if (X)
- {
- if (SizeFGR() == 64)
- StoreFPR (FS, fmt_uninterpreted_64, GPR[RT]);
- else if ((FS & 0x1) == 0)
- StoreFPR (FS, fmt_uninterpreted_64, SET64HI (FGR[FS+1]) | FGR[FS]);
- }
+ if (SizeFGR () == 64)
+ GPR[RT] = FGR[FS];
+ else if ((FS & 0x1) == 0)
+ GPR[RT] = SET64HI (FGR[FS+1]) | FGR[FS];
else
+ GPR[RT] = SET64HI (0xDEADC0DE) | 0xBAD0BAD0;
+ TRACE_ALU_RESULT (GPR[RT]);
+}
+
+
+010001,00101,5.RT,5.FS,00000000000:COP1:64,f::DMTC1a
+"dmtc1 r<RT>, f<FS>"
+*mipsIII:
+{
+ unsigned64 v;
+ check_fpu (SD_);
+ check_u64 (SD_, instruction_0);
+ if (SizeFGR () == 64)
+ PENDING_FILL ((FS + FGR_BASE), GPR[RT]);
+ else if ((FS & 0x1) == 0)
{
- if (SizeFGR() == 64)
- GPR[RT] = FGR[FS];
- else if ((FS & 0x1) == 0)
- GPR[RT] = SET64HI (FGR[FS+1]) | FGR[FS];
- else
- {
- if (STATE_VERBOSE_P(SD))
- sim_io_eprintf (SD,
- "Warning: PC 0x%lx: DMxC1 32-bit use of odd FPR number\n",
- (long) CIA);
- GPR[RT] = SET64HI (0xDEADC0DE) | 0xBAD0BAD0;
- }
+ PENDING_FILL (((FS + 1) + FGR_BASE), VH4_8 (GPR[RT]));
+ PENDING_FILL ((FS + FGR_BASE), VL4_8 (GPR[RT]));
}
+ else
+ Unpredictable ();
+ TRACE_FP_RESULT (GPR[RT]);
+}
+
+010001,00101,5.RT,5.FS,00000000000:COP1:64,f::DMTC1b
+"dmtc1 r<RT>, f<FS>"
+*mipsIV:
+*mipsV:
+*mips64:
+*vr4100:
+*vr5000:
+*r3900:
+{
+ check_fpu (SD_);
+ check_u64 (SD_, instruction_0);
+ if (SizeFGR () == 64)
+ StoreFPR (FS, fmt_uninterpreted_64, GPR[RT]);
+ else if ((FS & 0x1) == 0)
+ StoreFPR (FS, fmt_uninterpreted_64, GPR[RT]);
+ else
+ Unpredictable ();
}
}
-// MFC1
-// MTC1
-010001,00,X,00,5.RT,5.FS,00000000000:COP1Sa:32,f::MxC1
-"m%s<X>c1 r<RT>, f<FS>"
+010001,00000,5.RT,5.FS,00000000000:COP1:32,f::MFC1a
+"mfc1 r<RT>, f<FS>"
*mipsI:
*mipsII:
*mipsIII:
{
+ unsigned64 v;
check_fpu (SD_);
- if (X)
- { /*MTC1*/
- if (SizeFGR() == 64)
- {
- if (STATE_VERBOSE_P(SD))
- sim_io_eprintf (SD,
- "Warning: PC 0x%lx: MTC1 not DMTC1 with 64 bit regs\n",
- (long) CIA);
- PENDING_FILL ((FS + FGR_BASE), (SET64HI(0xDEADC0DE) | VL4_8(GPR[RT])));
- }
- else
- PENDING_FILL ((FS + FGR_BASE), VL4_8(GPR[RT]));
- }
- else /*MFC1*/
- PENDING_FILL (RT, EXTEND32 (FGR[FS]));
+ v = EXTEND32 (FGR[FS]);
+ PENDING_FILL (RT, v);
+ TRACE_ALU_RESULT (v);
}
-010001,00,X,00,5.RT,5.FS,00000000000:COP1Sb:32,f::MxC1
-"m%s<X>c1 r<RT>, f<FS>"
+
+010001,00000,5.RT,5.FS,00000000000:COP1:32,f::MFC1b
+"mfc1 r<RT>, f<FS>"
*mipsIV:
*mipsV:
*mips32:
*vr4100:
*vr5000:
*r3900:
-{
- int fs = FS;
+{
check_fpu (SD_);
- if (X)
- /*MTC1*/
- StoreFPR (FS, fmt_uninterpreted_32, VL4_8 (GPR[RT]));
- else /*MFC1*/
- GPR[RT] = EXTEND32 (FGR[FS]);
+ GPR[RT] = EXTEND32 (FGR[FS]);
+ TRACE_ALU_RESULT (GPR[RT]);
}
}
-// MTC1 see MxC1
+010001,00100,5.RT,5.FS,00000000000:COP1:32,f::MTC1a
+"mtc1 r<RT>, f<FS>"
+*mipsI:
+*mipsII:
+*mipsIII:
+{
+ check_fpu (SD_);
+ if (SizeFGR () == 64)
+ PENDING_FILL ((FS + FGR_BASE), (SET64HI (0xDEADC0DE) | VL4_8 (GPR[RT])));
+ else
+ PENDING_FILL ((FS + FGR_BASE), VL4_8 (GPR[RT]));
+ TRACE_FP_RESULT (GPR[RT]);
+}
+
+010001,00100,5.RT,5.FS,00000000000:COP1:32,f::MTC1b
+"mtc1 r<RT>, f<FS>"
+*mipsIV:
+*mipsV:
+*mips32:
+*mips64:
+*vr4100:
+*vr5000:
+*r3900:
+{
+ check_fpu (SD_);
+ StoreFPR (FS, fmt_uninterpreted_32, VL4_8 (GPR[RT]));
+}
010001,10,3.FMT,5.FT,5.FS,5.FD,000010:COP1:32,f::MUL.fmt
/* Floating-point operations: */
#include "sim-fpu.h"
+#include "cp1.h"
/* FPU registers must be one of the following types. All other values
are reserved (and undefined). */
fmt_uninterpreted_64 = 0x80000000U,
} FP_formats;
-/* Macro to update FPSR condition-code field. This is complicated by
- the fact that there is a hole in the index range of the bits within
- the FCSR register. Also, the number of bits visible depends on the
- MIPS ISA version being supported. */
-
-#define SETFCC(cc,v) {\
- int bit = ((cc == 0) ? 23 : (24 + (cc)));\
- FCSR = ((FCSR & ~(1 << bit)) | ((v) << bit));\
-}
-#define GETFCC(cc) (((((cc) == 0) ? (FCSR & (1 << 23)) : (FCSR & (1 << (24 + (cc))))) != 0) ? 1U : 0)
-
/* This should be the COC1 value at the start of the preceding
instruction: */
#define PREVCOC1() ((STATE & simPCOC1) ? 1 : 0)
#define SizeFGR() (WITH_TARGET_FLOATING_POINT_BITSIZE)
#endif
-/* Standard FCRS bits: */
-#define IR (0) /* Inexact Result */
-#define UF (1) /* UnderFlow */
-#define OF (2) /* OverFlow */
-#define DZ (3) /* Division by Zero */
-#define IO (4) /* Invalid Operation */
-#define UO (5) /* Unimplemented Operation */
-
-/* Get masks for individual flags: */
-#if 1 /* SAFE version */
-#define FP_FLAGS(b) (((unsigned)(b) < 5) ? (1 << ((b) + 2)) : 0)
-#define FP_ENABLE(b) (((unsigned)(b) < 5) ? (1 << ((b) + 7)) : 0)
-#define FP_CAUSE(b) (((unsigned)(b) < 6) ? (1 << ((b) + 12)) : 0)
-#else
-#define FP_FLAGS(b) (1 << ((b) + 2))
-#define FP_ENABLE(b) (1 << ((b) + 7))
-#define FP_CAUSE(b) (1 << ((b) + 12))
-#endif
-
-#define FP_FS (1 << 24) /* MIPS III onwards : Flush to Zero */
-
-#define FP_MASK_RM (0x3)
-#define FP_SH_RM (0)
-#define FP_RM_NEAREST (0) /* Round to nearest (Round) */
-#define FP_RM_TOZERO (1) /* Round to zero (Trunc) */
-#define FP_RM_TOPINF (2) /* Round to Plus infinity (Ceil) */
-#define FP_RM_TOMINF (3) /* Round to Minus infinity (Floor) */
-#define GETRM() (int)((FCSR >> FP_SH_RM) & FP_MASK_RM)
-
-
#define StoreFPR(FPR,FMT,VALUE) store_fpr (SIM_ARGS, (FPR), (FMT), (VALUE))
+/* FCR access. */
+unsigned_word value_fcr (SIM_STATE, int fcr);
+#define ValueFCR(FCR) value_fcr (SIM_ARGS, (FCR))
+void store_fcr (SIM_STATE, int fcr, unsigned_word value);
+#define StoreFCR(FCR,VALUE) store_fcr (SIM_ARGS, (FCR), (VALUE))
+void test_fcsr (SIM_STATE);
+#define TestFCSR() test_fcsr (SIM_ARGS)
+
+
/* FPU operations. */
-int NaN (unsigned64 op, FP_formats fmt);
-int Less (unsigned64 op1, unsigned64 op2, FP_formats fmt);
-int Equal (unsigned64 op1, unsigned64 op2, FP_formats fmt);
+void fp_cmp (SIM_STATE, unsigned64 op1, unsigned64 op2, FP_formats fmt, int abs, int cond, int cc);
+#define Compare(op1,op2,fmt,cond,cc) fp_cmp(SIM_ARGS, op1, op2, fmt, 0, cond, cc)
unsigned64 fp_abs (SIM_STATE, unsigned64 op, FP_formats fmt);
#define AbsoluteValue(op,fmt) fp_abs(SIM_ARGS, op, fmt)
unsigned64 fp_neg (SIM_STATE, unsigned64 op, FP_formats fmt);