]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/mips/cp1.c
2002-07-29 Andrew Cagney <ac131313@redhat.com>
[thirdparty/binutils-gdb.git] / sim / mips / cp1.c
CommitLineData
487f79b7 1/*> cp1.c <*/
d3eb724f
CD
2/* MIPS Simulator FPU (CoProcessor 1) support.
3 Copyright (C) 2002 Free Software Foundation, Inc.
4 Originally created by Cygnus Solutions, modified substially
e7e81181
CD
5 by Broadcom Corporation (SiByte). Paired-single operation support
6 and MIPS-3D support contributed by Broadcom Corporation (SiByte).
d3eb724f
CD
7
8This file is part of GDB, the GNU debugger.
9
10This program is free software; you can redistribute it and/or modify
11it under the terms of the GNU General Public License as published by
12the Free Software Foundation; either version 2, or (at your option)
13any later version.
14
15This program is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License along
21with this program; if not, write to the Free Software Foundation, Inc.,
2259 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23
24/* XXX: The following notice should be removed as soon as is practical: */
487f79b7
CD
25/* Floating Point Support for gdb MIPS simulators
26
27 This file is part of the MIPS sim
28
29 THIS SOFTWARE IS NOT COPYRIGHTED
d3eb724f 30 (by Cygnus.)
487f79b7
CD
31
32 Cygnus offers the following for use in the public domain. Cygnus
33 makes no warranty with regard to the software or it's performance
34 and the user accepts the software "AS IS" with all faults.
35
36 CYGNUS DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO
37 THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
38 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
39
40 (Originally, this code was in interp.c)
41*/
42
43#include "sim-main.h"
487f79b7
CD
44
45/* Within cp1.c we refer to sim_cpu directly. */
46#define CPU cpu
18d8a52d 47#define SD CPU_STATE(cpu)
487f79b7
CD
48
49/*-- FPU support routines ---------------------------------------------------*/
50
51/* Numbers are held in normalized form. The SINGLE and DOUBLE binary
bad673a9
CD
52 formats conform to ANSI/IEEE Std 754-1985.
53
54 SINGLE precision floating:
55 seeeeeeeefffffffffffffffffffffff
56 s = 1bit = sign
57 e = 8bits = exponent
58 f = 23bits = fraction
59
60 SINGLE precision fixed:
61 siiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
62 s = 1bit = sign
63 i = 31bits = integer
64
65 DOUBLE precision floating:
66 seeeeeeeeeeeffffffffffffffffffffffffffffffffffffffffffffffffffff
67 s = 1bit = sign
68 e = 11bits = exponent
69 f = 52bits = fraction
70
71 DOUBLE precision fixed:
72 siiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
73 s = 1bit = sign
74 i = 63bits = integer
3a2b820e
CD
75
76 PAIRED SINGLE precision floating:
77 seeeeeeeefffffffffffffffffffffffseeeeeeeefffffffffffffffffffffff
78 | upper || lower |
79 s = 1bit = sign
80 e = 8bits = exponent
81 f = 23bits = fraction
82 Note: upper = [63..32], lower = [31..0]
487f79b7
CD
83 */
84
3a2b820e
CD
85/* Extract packed single values: */
86#define FP_PS_upper(v) (((v) >> 32) & (unsigned)0xFFFFFFFF)
87#define FP_PS_lower(v) ((v) & (unsigned)0xFFFFFFFF)
88#define FP_PS_cat(u,l) (((unsigned64)((u) & (unsigned)0xFFFFFFFF) << 32) \
89 | (unsigned64)((l) & 0xFFFFFFFF))
90
52714ff9 91/* Explicit QNaN values. */
487f79b7
CD
92#define FPQNaN_SINGLE (0x7FBFFFFF)
93#define FPQNaN_WORD (0x7FFFFFFF)
bad673a9
CD
94#define FPQNaN_DOUBLE (UNSIGNED64 (0x7FF7FFFFFFFFFFFF))
95#define FPQNaN_LONG (UNSIGNED64 (0x7FFFFFFFFFFFFFFF))
3a2b820e 96#define FPQNaN_PS (FP_PS_cat (FPQNaN_SINGLE, FPQNaN_SINGLE))
487f79b7 97
07892c0b
CD
98static const char *fpu_format_name (FP_formats fmt);
99#ifdef DEBUG
100static const char *fpu_rounding_mode_name (int rm);
101#endif
487f79b7
CD
102
103uword64
18d8a52d 104value_fpr (sim_cpu *cpu,
487f79b7
CD
105 address_word cia,
106 int fpr,
107 FP_formats fmt)
108{
109 uword64 value = 0;
110 int err = 0;
111
52714ff9 112 /* Treat unused register values, as fixed-point 64bit values. */
487f79b7 113 if ((fmt == fmt_uninterpreted) || (fmt == fmt_unknown))
37d146fa 114 {
487f79b7 115#if 1
37d146fa
CD
116 /* If request to read data as "uninterpreted", then use the current
117 encoding: */
118 fmt = FPR_STATE[fpr];
487f79b7 119#else
37d146fa 120 fmt = fmt_long;
487f79b7 121#endif
37d146fa 122 }
487f79b7 123
52714ff9 124 /* For values not yet accessed, set to the desired format. */
37d146fa
CD
125 if (FPR_STATE[fpr] == fmt_uninterpreted)
126 {
127 FPR_STATE[fpr] = fmt;
487f79b7 128#ifdef DEBUG
37d146fa
CD
129 printf ("DBG: Register %d was fmt_uninterpreted. Now %s\n", fpr,
130 fpu_format_name (fmt));
487f79b7 131#endif /* DEBUG */
487f79b7 132 }
37d146fa
CD
133 if (fmt != FPR_STATE[fpr])
134 {
18d8a52d 135 sim_io_eprintf (SD, "FPR %d (format %s) being accessed with format %s - setting to unknown (PC = 0x%s)\n",
37d146fa
CD
136 fpr, fpu_format_name (FPR_STATE[fpr]),
137 fpu_format_name (fmt), pr_addr (cia));
138 FPR_STATE[fpr] = fmt_unknown;
139 }
487f79b7 140
37d146fa
CD
141 if (FPR_STATE[fpr] == fmt_unknown)
142 {
143 /* Set QNaN value: */
144 switch (fmt)
145 {
196496ed
CD
146 case fmt_single: value = FPQNaN_SINGLE; break;
147 case fmt_double: value = FPQNaN_DOUBLE; break;
148 case fmt_word: value = FPQNaN_WORD; break;
149 case fmt_long: value = FPQNaN_LONG; break;
3a2b820e 150 case fmt_ps: value = FPQNaN_PS; break;
196496ed 151 default: err = -1; break;
37d146fa
CD
152 }
153 }
154 else if (SizeFGR () == 64)
155 {
156 switch (fmt)
157 {
158 case fmt_single:
159 case fmt_word:
160 value = (FGR[fpr] & 0xFFFFFFFF);
161 break;
162
163 case fmt_uninterpreted:
164 case fmt_double:
165 case fmt_long:
3a2b820e 166 case fmt_ps:
37d146fa
CD
167 value = FGR[fpr];
168 break;
169
170 default:
171 err = -1;
172 break;
173 }
174 }
175 else
176 {
177 switch (fmt)
178 {
179 case fmt_single:
180 case fmt_word:
181 value = (FGR[fpr] & 0xFFFFFFFF);
182 break;
183
184 case fmt_uninterpreted:
185 case fmt_double:
186 case fmt_long:
187 if ((fpr & 1) == 0)
188 {
52714ff9 189 /* Even register numbers only. */
487f79b7 190#ifdef DEBUG
37d146fa
CD
191 printf ("DBG: ValueFPR: FGR[%d] = %s, FGR[%d] = %s\n",
192 fpr + 1, pr_uword64 ((uword64) FGR[fpr+1]),
193 fpr, pr_uword64 ((uword64) FGR[fpr]));
487f79b7 194#endif
37d146fa
CD
195 value = ((((uword64) FGR[fpr+1]) << 32)
196 | (FGR[fpr] & 0xFFFFFFFF));
197 }
198 else
199 {
200 SignalException (ReservedInstruction, 0);
201 }
202 break;
203
3a2b820e
CD
204 case fmt_ps:
205 SignalException (ReservedInstruction, 0);
206 break;
207
e80fc152 208 default:
37d146fa
CD
209 err = -1;
210 break;
211 }
487f79b7 212 }
487f79b7
CD
213
214 if (err)
37d146fa 215 SignalExceptionSimulatorFault ("Unrecognised FP format in ValueFPR ()");
487f79b7
CD
216
217#ifdef DEBUG
37d146fa
CD
218 printf ("DBG: ValueFPR: fpr = %d, fmt = %s, value = 0x%s : PC = 0x%s : SizeFGR () = %d\n",
219 fpr, fpu_format_name (fmt), pr_uword64 (value), pr_addr (cia),
220 SizeFGR ());
487f79b7
CD
221#endif /* DEBUG */
222
37d146fa 223 return (value);
487f79b7
CD
224}
225
226void
18d8a52d 227store_fpr (sim_cpu *cpu,
487f79b7
CD
228 address_word cia,
229 int fpr,
230 FP_formats fmt,
231 uword64 value)
232{
233 int err = 0;
234
235#ifdef DEBUG
37d146fa
CD
236 printf ("DBG: StoreFPR: fpr = %d, fmt = %s, value = 0x%s : PC = 0x%s : SizeFGR () = %d, \n",
237 fpr, fpu_format_name (fmt), pr_uword64 (value), pr_addr (cia),
238 SizeFGR ());
487f79b7
CD
239#endif /* DEBUG */
240
37d146fa
CD
241 if (SizeFGR () == 64)
242 {
243 switch (fmt)
244 {
245 case fmt_uninterpreted_32:
246 fmt = fmt_uninterpreted;
e80fc152
CD
247 case fmt_single:
248 case fmt_word:
37d146fa
CD
249 if (STATE_VERBOSE_P (SD))
250 sim_io_eprintf (SD,
251 "Warning: PC 0x%s: interp.c store_fpr DEADCODE\n",
252 pr_addr (cia));
253 FGR[fpr] = (((uword64) 0xDEADC0DE << 32) | (value & 0xFFFFFFFF));
254 FPR_STATE[fpr] = fmt;
255 break;
256
257 case fmt_uninterpreted_64:
258 fmt = fmt_uninterpreted;
259 case fmt_uninterpreted:
e80fc152
CD
260 case fmt_double:
261 case fmt_long:
3a2b820e 262 case fmt_ps:
37d146fa
CD
263 FGR[fpr] = value;
264 FPR_STATE[fpr] = fmt;
265 break;
266
e80fc152 267 default:
37d146fa
CD
268 FPR_STATE[fpr] = fmt_unknown;
269 err = -1;
270 break;
271 }
487f79b7 272 }
37d146fa
CD
273 else
274 {
275 switch (fmt)
276 {
277 case fmt_uninterpreted_32:
278 fmt = fmt_uninterpreted;
e80fc152
CD
279 case fmt_single:
280 case fmt_word:
487f79b7 281 FGR[fpr] = (value & 0xFFFFFFFF);
487f79b7 282 FPR_STATE[fpr] = fmt;
37d146fa
CD
283 break;
284
285 case fmt_uninterpreted_64:
286 fmt = fmt_uninterpreted;
287 case fmt_uninterpreted:
e80fc152
CD
288 case fmt_double:
289 case fmt_long:
37d146fa
CD
290 if ((fpr & 1) == 0)
291 {
196496ed 292 /* Even register numbers only. */
37d146fa
CD
293 FGR[fpr+1] = (value >> 32);
294 FGR[fpr] = (value & 0xFFFFFFFF);
295 FPR_STATE[fpr + 1] = fmt;
296 FPR_STATE[fpr] = fmt;
297 }
298 else
299 {
300 FPR_STATE[fpr] = fmt_unknown;
301 FPR_STATE[fpr + 1] = fmt_unknown;
302 SignalException (ReservedInstruction, 0);
303 }
304 break;
305
3a2b820e
CD
306 case fmt_ps:
307 FPR_STATE[fpr] = fmt_unknown;
308 SignalException (ReservedInstruction, 0);
309 break;
310
e80fc152 311 default:
487f79b7 312 FPR_STATE[fpr] = fmt_unknown;
37d146fa
CD
313 err = -1;
314 break;
487f79b7 315 }
487f79b7 316 }
487f79b7
CD
317
318 if (err)
37d146fa 319 SignalExceptionSimulatorFault ("Unrecognised FP format in StoreFPR ()");
487f79b7
CD
320
321#ifdef DEBUG
37d146fa
CD
322 printf ("DBG: StoreFPR: fpr[%d] = 0x%s (format %s)\n",
323 fpr, pr_uword64 (FGR[fpr]), fpu_format_name (fmt));
487f79b7
CD
324#endif /* DEBUG */
325
326 return;
327}
328
cfe9ea23 329
52714ff9 330/* CP1 control/status register access functions. */
cfe9ea23
CD
331
332void
333test_fcsr (sim_cpu *cpu,
334 address_word cia)
487f79b7 335{
cfe9ea23
CD
336 unsigned int cause;
337
338 cause = (FCSR & fcsr_CAUSE_mask) >> fcsr_CAUSE_shift;
339 if ((cause & ((FCSR & fcsr_ENABLES_mask) >> fcsr_ENABLES_shift)) != 0
340 || (cause & (1 << UO)))
487f79b7 341 {
cfe9ea23 342 SignalExceptionFPE();
487f79b7 343 }
cfe9ea23 344}
487f79b7 345
cfe9ea23
CD
346unsigned_word
347value_fcr(sim_cpu *cpu,
348 address_word cia,
349 int fcr)
350{
351 unsigned32 value = 0;
352
353 switch (fcr)
354 {
52714ff9 355 case 0: /* FP Implementation and Revision Register. */
cfe9ea23
CD
356 value = FCR0;
357 break;
52714ff9 358 case 25: /* FP Condition Codes Register (derived from FCSR). */
cfe9ea23 359 value = (FCR31 & fcsr_FCC_mask) >> fcsr_FCC_shift;
52714ff9 360 value = (value & 0x1) | (value >> 1); /* Close FCC gap. */
cfe9ea23 361 break;
52714ff9 362 case 26: /* FP Exceptions Register (derived from FCSR). */
cfe9ea23
CD
363 value = FCR31 & (fcsr_CAUSE_mask | fcsr_FLAGS_mask);
364 break;
52714ff9 365 case 28: /* FP Enables Register (derived from FCSR). */
cfe9ea23 366 value = FCR31 & (fcsr_ENABLES_mask | fcsr_RM_mask);
52714ff9
CD
367 if ((FCR31 & fcsr_FS) != 0)
368 value |= fenr_FS;
cfe9ea23 369 break;
52714ff9 370 case 31: /* FP Control/Status Register (FCSR). */
cfe9ea23
CD
371 value = FCR31 & ~fcsr_ZERO_mask;
372 break;
373 }
374
375 return (EXTEND32 (value));
376}
377
378void
379store_fcr(sim_cpu *cpu,
380 address_word cia,
381 int fcr,
382 unsigned_word value)
383{
384 unsigned32 v;
487f79b7 385
cfe9ea23
CD
386 v = VL4_8(value);
387 switch (fcr)
388 {
52714ff9
CD
389 case 25: /* FP Condition Codes Register (stored into FCSR). */
390 v = (v << 1) | (v & 0x1); /* Adjust for FCC gap. */
cfe9ea23
CD
391 FCR31 &= ~fcsr_FCC_mask;
392 FCR31 |= ((v << fcsr_FCC_shift) & fcsr_FCC_mask);
393 break;
52714ff9 394 case 26: /* FP Exceptions Register (stored into FCSR). */
cfe9ea23
CD
395 FCR31 &= ~(fcsr_CAUSE_mask | fcsr_FLAGS_mask);
396 FCR31 |= (v & (fcsr_CAUSE_mask | fcsr_FLAGS_mask));
397 test_fcsr(cpu, cia);
398 break;
52714ff9
CD
399 case 28: /* FP Enables Register (stored into FCSR). */
400 if ((v & fenr_FS) != 0)
cfe9ea23
CD
401 v |= fcsr_FS;
402 else
403 v &= ~fcsr_FS;
404 FCR31 &= (fcsr_FCC_mask | fcsr_CAUSE_mask | fcsr_FLAGS_mask);
405 FCR31 |= (v & (fcsr_FS | fcsr_ENABLES_mask | fcsr_RM_mask));
406 test_fcsr(cpu, cia);
407 break;
52714ff9 408 case 31: /* FP Control/Status Register (FCSR). */
cfe9ea23
CD
409 FCR31 = v & ~fcsr_ZERO_mask;
410 test_fcsr(cpu, cia);
411 break;
412 }
487f79b7
CD
413}
414
cfe9ea23
CD
415void
416update_fcsr (sim_cpu *cpu,
417 address_word cia,
418 sim_fpu_status status)
487f79b7 419{
cfe9ea23 420 FCSR &= ~fcsr_CAUSE_mask;
487f79b7 421
cfe9ea23
CD
422 if (status != 0)
423 {
424 unsigned int cause = 0;
425
426 /* map between sim_fpu codes and MIPS FCSR */
427 if (status & (sim_fpu_status_invalid_snan
428 | sim_fpu_status_invalid_isi
429 | sim_fpu_status_invalid_idi
430 | sim_fpu_status_invalid_zdz
431 | sim_fpu_status_invalid_imz
432 | sim_fpu_status_invalid_cmp
433 | sim_fpu_status_invalid_sqrt
434 | sim_fpu_status_invalid_cvi))
435 cause |= (1 << IO);
436 if (status & sim_fpu_status_invalid_div0)
437 cause |= (1 << DZ);
438 if (status & sim_fpu_status_overflow)
439 cause |= (1 << OF);
440 if (status & sim_fpu_status_underflow)
441 cause |= (1 << UF);
442 if (status & sim_fpu_status_inexact)
443 cause |= (1 << IR);
444#if 0 /* Not yet. */
52714ff9 445 /* Implicit clearing of other bits by unimplemented done by callers. */
cfe9ea23
CD
446 if (status & sim_fpu_status_unimplemented)
447 cause |= (1 << UO);
448#endif
487f79b7 449
cfe9ea23
CD
450 FCSR |= (cause << fcsr_CAUSE_shift);
451 test_fcsr (cpu, cia);
452 FCSR |= ((cause & ~(1 << UO)) << fcsr_FLAGS_shift);
453 }
454 return;
455}
456
577d8c4b
CD
457static sim_fpu_round
458rounding_mode(int rm)
459{
460 sim_fpu_round round;
461
462 switch (rm)
463 {
464 case FP_RM_NEAREST:
465 /* Round result to nearest representable value. When two
466 representable values are equally near, round to the value
52714ff9 467 that has a least significant bit of zero (i.e. is even). */
577d8c4b
CD
468 round = sim_fpu_round_near;
469 break;
470 case FP_RM_TOZERO:
471 /* Round result to the value closest to, and not greater in
52714ff9 472 magnitude than, the result. */
577d8c4b
CD
473 round = sim_fpu_round_zero;
474 break;
475 case FP_RM_TOPINF:
476 /* Round result to the value closest to, and not less than,
52714ff9 477 the result. */
577d8c4b
CD
478 round = sim_fpu_round_up;
479 break;
480 case FP_RM_TOMINF:
481 /* Round result to the value closest to, and not greater than,
52714ff9 482 the result. */
577d8c4b
CD
483 round = sim_fpu_round_down;
484 break;
485 default:
486 round = 0;
487 fprintf (stderr, "Bad switch\n");
488 abort ();
489 }
490 return round;
491}
492
52714ff9
CD
493/* When the FS bit is set, MIPS processors return zero for
494 denormalized results and optionally replace denormalized inputs
495 with zero. When FS is clear, some implementation trap on input
496 and/or output, while other perform the operation in hardware. */
497static sim_fpu_denorm
498denorm_mode(sim_cpu *cpu)
499{
500 sim_fpu_denorm denorm;
501
502 /* XXX: FIXME: Eventually should be CPU model dependent. */
503 if (GETFS())
504 denorm = sim_fpu_denorm_zero;
505 else
506 denorm = 0;
507 return denorm;
508}
509
cfe9ea23
CD
510
511/* Comparison operations. */
512
513static sim_fpu_status
514fp_test(unsigned64 op1,
515 unsigned64 op2,
516 FP_formats fmt,
517 int abs,
518 int cond,
519 int *condition)
520{
521 sim_fpu wop1;
522 sim_fpu wop2;
523 sim_fpu_status status = 0;
524 int less, equal, unordered;
487f79b7 525
cfe9ea23 526 /* The format type has already been checked: */
37d146fa 527 switch (fmt)
487f79b7 528 {
37d146fa
CD
529 case fmt_single:
530 {
37d146fa
CD
531 sim_fpu_32to (&wop1, op1);
532 sim_fpu_32to (&wop2, op2);
37d146fa
CD
533 break;
534 }
535 case fmt_double:
536 {
37d146fa
CD
537 sim_fpu_64to (&wop1, op1);
538 sim_fpu_64to (&wop2, op2);
37d146fa
CD
539 break;
540 }
541 default:
542 fprintf (stderr, "Bad switch\n");
543 abort ();
487f79b7 544 }
487f79b7 545
cfe9ea23
CD
546 if (sim_fpu_is_nan (&wop1) || sim_fpu_is_nan (&wop2))
547 {
548 if ((cond & (1 << 3)) ||
549 sim_fpu_is_snan (&wop1) || sim_fpu_is_snan (&wop2))
550 status = sim_fpu_status_invalid_snan;
551 less = 0;
552 equal = 0;
553 unordered = 1;
554 }
555 else
556 {
557 if (abs)
558 {
559 status |= sim_fpu_abs (&wop1, &wop1);
560 status |= sim_fpu_abs (&wop2, &wop2);
561 }
562 equal = sim_fpu_is_eq (&wop1, &wop2);
563 less = !equal && sim_fpu_is_lt (&wop1, &wop2);
564 unordered = 0;
565 }
566 *condition = (((cond & (1 << 2)) && less)
567 || ((cond & (1 << 1)) && equal)
568 || ((cond & (1 << 0)) && unordered));
569 return status;
487f79b7
CD
570}
571
cfe9ea23
CD
572void
573fp_cmp(sim_cpu *cpu,
574 address_word cia,
575 unsigned64 op1,
576 unsigned64 op2,
577 FP_formats fmt,
578 int abs,
579 int cond,
580 int cc)
487f79b7 581{
cfe9ea23 582 sim_fpu_status status = 0;
487f79b7 583
52714ff9
CD
584 /* The format type should already have been checked. The FCSR is
585 updated before the condition codes so that any exceptions will
586 be signalled before the condition codes are changed. */
37d146fa 587 switch (fmt)
487f79b7 588 {
37d146fa 589 case fmt_single:
37d146fa
CD
590 case fmt_double:
591 {
cfe9ea23
CD
592 int result;
593 status = fp_test(op1, op2, fmt, abs, cond, &result);
594 update_fcsr (cpu, cia, status);
595 SETFCC (cc, result);
37d146fa
CD
596 break;
597 }
3a2b820e
CD
598 case fmt_ps:
599 {
600 int result0, result1;
601 status = fp_test(FP_PS_lower (op1), FP_PS_lower (op2), fmt_single,
602 abs, cond, &result0);
603 status |= fp_test(FP_PS_upper (op1), FP_PS_upper (op2), fmt_single,
604 abs, cond, &result1);
605 update_fcsr (cpu, cia, status);
606 SETFCC (cc, result0);
607 SETFCC (cc+1, result1);
608 break;
609 }
37d146fa 610 default:
cfe9ea23 611 sim_io_eprintf (SD, "Bad switch\n");
37d146fa 612 abort ();
487f79b7 613 }
487f79b7
CD
614}
615
487f79b7 616
ba46ddd0 617/* Basic arithmetic operations. */
487f79b7 618
ba46ddd0
CD
619static unsigned64
620fp_unary(sim_cpu *cpu,
621 address_word cia,
622 int (*sim_fpu_op)(sim_fpu *, const sim_fpu *),
623 unsigned64 op,
624 FP_formats fmt)
487f79b7 625{
ba46ddd0
CD
626 sim_fpu wop;
627 sim_fpu ans;
52714ff9
CD
628 sim_fpu_round round = rounding_mode (GETRM());
629 sim_fpu_denorm denorm = denorm_mode (cpu);
630 sim_fpu_status status = 0;
ba46ddd0 631 unsigned64 result = 0;
487f79b7 632
ba46ddd0 633 /* The format type has already been checked: */
37d146fa 634 switch (fmt)
487f79b7 635 {
37d146fa
CD
636 case fmt_single:
637 {
37d146fa 638 unsigned32 res;
ba46ddd0 639 sim_fpu_32to (&wop, op);
52714ff9
CD
640 status |= (*sim_fpu_op) (&ans, &wop);
641 status |= sim_fpu_round_32 (&ans, round, denorm);
37d146fa
CD
642 sim_fpu_to32 (&res, &ans);
643 result = res;
644 break;
645 }
646 case fmt_double:
647 {
37d146fa 648 unsigned64 res;
ba46ddd0 649 sim_fpu_64to (&wop, op);
52714ff9
CD
650 status |= (*sim_fpu_op) (&ans, &wop);
651 status |= sim_fpu_round_64 (&ans, round, denorm);
37d146fa
CD
652 sim_fpu_to64 (&res, &ans);
653 result = res;
654 break;
655 }
3a2b820e
CD
656 case fmt_ps:
657 {
658 int status_u = 0, status_l = 0;
659 unsigned32 res_u, res_l;
660 sim_fpu_32to (&wop, FP_PS_upper(op));
661 status_u |= (*sim_fpu_op) (&ans, &wop);
662 sim_fpu_to32 (&res_u, &ans);
663 sim_fpu_32to (&wop, FP_PS_lower(op));
664 status_l |= (*sim_fpu_op) (&ans, &wop);
665 sim_fpu_to32 (&res_l, &ans);
666 result = FP_PS_cat(res_u, res_l);
667 status = status_u | status_l;
668 break;
669 }
37d146fa 670 default:
ba46ddd0 671 sim_io_eprintf (SD, "Bad switch\n");
37d146fa 672 abort ();
487f79b7 673 }
487f79b7 674
52714ff9 675 update_fcsr (cpu, cia, status);
ba46ddd0 676 return result;
487f79b7
CD
677}
678
ba46ddd0
CD
679static unsigned64
680fp_binary(sim_cpu *cpu,
681 address_word cia,
682 int (*sim_fpu_op)(sim_fpu *, const sim_fpu *, const sim_fpu *),
683 unsigned64 op1,
684 unsigned64 op2,
685 FP_formats fmt)
487f79b7 686{
ba46ddd0
CD
687 sim_fpu wop1;
688 sim_fpu wop2;
689 sim_fpu ans;
52714ff9
CD
690 sim_fpu_round round = rounding_mode (GETRM());
691 sim_fpu_denorm denorm = denorm_mode (cpu);
692 sim_fpu_status status = 0;
ba46ddd0 693 unsigned64 result = 0;
487f79b7 694
ba46ddd0 695 /* The format type has already been checked: */
37d146fa 696 switch (fmt)
487f79b7 697 {
37d146fa
CD
698 case fmt_single:
699 {
37d146fa
CD
700 unsigned32 res;
701 sim_fpu_32to (&wop1, op1);
702 sim_fpu_32to (&wop2, op2);
52714ff9
CD
703 status |= (*sim_fpu_op) (&ans, &wop1, &wop2);
704 status |= sim_fpu_round_32 (&ans, round, denorm);
37d146fa
CD
705 sim_fpu_to32 (&res, &ans);
706 result = res;
707 break;
708 }
709 case fmt_double:
710 {
37d146fa
CD
711 unsigned64 res;
712 sim_fpu_64to (&wop1, op1);
713 sim_fpu_64to (&wop2, op2);
52714ff9
CD
714 status |= (*sim_fpu_op) (&ans, &wop1, &wop2);
715 status |= sim_fpu_round_64 (&ans, round, denorm);
37d146fa
CD
716 sim_fpu_to64 (&res, &ans);
717 result = res;
718 break;
719 }
3a2b820e
CD
720 case fmt_ps:
721 {
722 int status_u = 0, status_l = 0;
723 unsigned32 res_u, res_l;
724 sim_fpu_32to (&wop1, FP_PS_upper(op1));
725 sim_fpu_32to (&wop2, FP_PS_upper(op2));
726 status_u |= (*sim_fpu_op) (&ans, &wop1, &wop2);
727 sim_fpu_to32 (&res_u, &ans);
728 sim_fpu_32to (&wop1, FP_PS_lower(op1));
729 sim_fpu_32to (&wop2, FP_PS_lower(op2));
730 status_l |= (*sim_fpu_op) (&ans, &wop1, &wop2);
731 sim_fpu_to32 (&res_l, &ans);
732 result = FP_PS_cat(res_u, res_l);
733 status = status_u | status_l;
734 break;
735 }
37d146fa 736 default:
ba46ddd0 737 sim_io_eprintf (SD, "Bad switch\n");
37d146fa 738 abort ();
487f79b7 739 }
487f79b7 740
52714ff9 741 update_fcsr (cpu, cia, status);
ba46ddd0 742 return result;
487f79b7
CD
743}
744
f3c08b7e
CD
745/* Common MAC code for single operands (.s or .d), defers setting FCSR. */
746static sim_fpu_status
747inner_mac(int (*sim_fpu_op)(sim_fpu *, const sim_fpu *, const sim_fpu *),
748 unsigned64 op1,
749 unsigned64 op2,
750 unsigned64 op3,
751 int scale,
752 int negate,
753 FP_formats fmt,
754 sim_fpu_round round,
755 sim_fpu_denorm denorm,
756 unsigned64 *result)
757{
758 sim_fpu wop1;
759 sim_fpu wop2;
760 sim_fpu ans;
761 sim_fpu_status status = 0;
762 sim_fpu_status op_status;
763 unsigned64 temp = 0;
764
765 switch (fmt)
766 {
767 case fmt_single:
768 {
769 unsigned32 res;
770 sim_fpu_32to (&wop1, op1);
771 sim_fpu_32to (&wop2, op2);
772 status |= sim_fpu_mul (&ans, &wop1, &wop2);
773 if (scale != 0 && sim_fpu_is_number (&ans)) /* number or denorm */
774 ans.normal_exp += scale;
775 status |= sim_fpu_round_32 (&ans, round, denorm);
776 wop1 = ans;
777 op_status = 0;
778 sim_fpu_32to (&wop2, op3);
779 op_status |= (*sim_fpu_op) (&ans, &wop1, &wop2);
780 op_status |= sim_fpu_round_32 (&ans, round, denorm);
781 status |= op_status;
782 if (negate)
783 {
784 wop1 = ans;
785 op_status = sim_fpu_neg (&ans, &wop1);
786 op_status |= sim_fpu_round_32 (&ans, round, denorm);
787 status |= op_status;
788 }
789 sim_fpu_to32 (&res, &ans);
790 temp = res;
791 break;
792 }
793 case fmt_double:
794 {
795 unsigned64 res;
796 sim_fpu_64to (&wop1, op1);
797 sim_fpu_64to (&wop2, op2);
798 status |= sim_fpu_mul (&ans, &wop1, &wop2);
799 if (scale != 0 && sim_fpu_is_number (&ans)) /* number or denorm */
800 ans.normal_exp += scale;
801 status |= sim_fpu_round_64 (&ans, round, denorm);
802 wop1 = ans;
803 op_status = 0;
804 sim_fpu_64to (&wop2, op3);
805 op_status |= (*sim_fpu_op) (&ans, &wop1, &wop2);
806 op_status |= sim_fpu_round_64 (&ans, round, denorm);
807 status |= op_status;
808 if (negate)
809 {
810 wop1 = ans;
811 op_status = sim_fpu_neg (&ans, &wop1);
812 op_status |= sim_fpu_round_64 (&ans, round, denorm);
813 status |= op_status;
814 }
815 sim_fpu_to64 (&res, &ans);
816 temp = res;
817 break;
818 }
819 default:
820 fprintf (stderr, "Bad switch\n");
821 abort ();
822 }
823 *result = temp;
824 return status;
825}
826
827/* Common implementation of madd, nmadd, msub, nmsub that does
828 intermediate rounding per spec. Also used for recip2 and rsqrt2,
829 which are transformed into equivalent nmsub operations. The scale
830 argument is an adjustment to the exponent of the intermediate
831 product op1*op2. It is currently non-zero for rsqrt2 (-1), which
832 requires an effective division by 2. */
833static unsigned64
834fp_mac(sim_cpu *cpu,
835 address_word cia,
836 int (*sim_fpu_op)(sim_fpu *, const sim_fpu *, const sim_fpu *),
837 unsigned64 op1,
838 unsigned64 op2,
839 unsigned64 op3,
840 int scale,
841 int negate,
842 FP_formats fmt)
843{
844 sim_fpu_round round = rounding_mode (GETRM());
845 sim_fpu_denorm denorm = denorm_mode (cpu);
846 sim_fpu_status status = 0;
847 unsigned64 result = 0;
848
849 /* The format type has already been checked: */
850 switch (fmt)
851 {
852 case fmt_single:
853 case fmt_double:
854 status = inner_mac(sim_fpu_op, op1, op2, op3, scale,
855 negate, fmt, round, denorm, &result);
856 break;
3a2b820e
CD
857 case fmt_ps:
858 {
859 int status_u, status_l;
860 unsigned64 result_u, result_l;
861 status_u = inner_mac(sim_fpu_op, FP_PS_upper(op1), FP_PS_upper(op2),
862 FP_PS_upper(op3), scale, negate, fmt_single,
863 round, denorm, &result_u);
864 status_l = inner_mac(sim_fpu_op, FP_PS_lower(op1), FP_PS_lower(op2),
865 FP_PS_lower(op3), scale, negate, fmt_single,
866 round, denorm, &result_l);
867 result = FP_PS_cat(result_u, result_l);
868 status = status_u | status_l;
869 break;
870 }
f3c08b7e
CD
871 default:
872 sim_io_eprintf (SD, "Bad switch\n");
873 abort ();
874 }
875
876 update_fcsr (cpu, cia, status);
877 return result;
878}
879
880/* Common rsqrt code for single operands (.s or .d), intermediate rounding. */
881static sim_fpu_status
882inner_rsqrt(unsigned64 op1,
883 FP_formats fmt,
884 sim_fpu_round round,
885 sim_fpu_denorm denorm,
886 unsigned64 *result)
887{
888 sim_fpu wop1;
889 sim_fpu ans;
890 sim_fpu_status status = 0;
891 sim_fpu_status op_status;
892 unsigned64 temp = 0;
893
894 switch (fmt)
895 {
896 case fmt_single:
897 {
898 unsigned32 res;
899 sim_fpu_32to (&wop1, op1);
900 status |= sim_fpu_sqrt (&ans, &wop1);
901 status |= sim_fpu_round_32 (&ans, status, round);
902 wop1 = ans;
903 op_status = sim_fpu_inv (&ans, &wop1);
904 op_status |= sim_fpu_round_32 (&ans, round, denorm);
905 sim_fpu_to32 (&res, &ans);
906 temp = res;
907 status |= op_status;
908 break;
909 }
910 case fmt_double:
911 {
912 unsigned64 res;
913 sim_fpu_64to (&wop1, op1);
914 status |= sim_fpu_sqrt (&ans, &wop1);
915 status |= sim_fpu_round_64 (&ans, round, denorm);
916 wop1 = ans;
917 op_status = sim_fpu_inv (&ans, &wop1);
918 op_status |= sim_fpu_round_64 (&ans, round, denorm);
919 sim_fpu_to64 (&res, &ans);
920 temp = res;
921 status |= op_status;
922 break;
923 }
924 default:
925 fprintf (stderr, "Bad switch\n");
926 abort ();
927 }
928 *result = temp;
929 return status;
930}
931
932static unsigned64
933fp_inv_sqrt(sim_cpu *cpu,
934 address_word cia,
935 unsigned64 op1,
936 FP_formats fmt)
937{
938 sim_fpu_round round = rounding_mode (GETRM());
939 sim_fpu_round denorm = denorm_mode (cpu);
940 sim_fpu_status status = 0;
941 unsigned64 result = 0;
942
943 /* The format type has already been checked: */
944 switch (fmt)
945 {
946 case fmt_single:
947 case fmt_double:
948 status = inner_rsqrt (op1, fmt, round, denorm, &result);
949 break;
3a2b820e
CD
950 case fmt_ps:
951 {
952 int status_u, status_l;
953 unsigned64 result_u, result_l;
954 status_u = inner_rsqrt (FP_PS_upper(op1), fmt_single, round, denorm,
955 &result_u);
956 status_l = inner_rsqrt (FP_PS_lower(op1), fmt_single, round, denorm,
957 &result_l);
958 result = FP_PS_cat(result_u, result_l);
959 status = status_u | status_l;
960 break;
961 }
f3c08b7e
CD
962 default:
963 sim_io_eprintf (SD, "Bad switch\n");
964 abort ();
965 }
966
967 update_fcsr (cpu, cia, status);
968 return result;
969}
970
487f79b7 971
ba46ddd0
CD
972unsigned64
973fp_abs(sim_cpu *cpu,
974 address_word cia,
975 unsigned64 op,
976 FP_formats fmt)
977{
978 return fp_unary(cpu, cia, &sim_fpu_abs, op, fmt);
487f79b7
CD
979}
980
ba46ddd0
CD
981unsigned64
982fp_neg(sim_cpu *cpu,
983 address_word cia,
984 unsigned64 op,
985 FP_formats fmt)
487f79b7 986{
ba46ddd0 987 return fp_unary(cpu, cia, &sim_fpu_neg, op, fmt);
487f79b7
CD
988}
989
ba46ddd0
CD
990unsigned64
991fp_add(sim_cpu *cpu,
992 address_word cia,
993 unsigned64 op1,
994 unsigned64 op2,
995 FP_formats fmt)
487f79b7 996{
ba46ddd0
CD
997 return fp_binary(cpu, cia, &sim_fpu_add, op1, op2, fmt);
998}
487f79b7 999
ba46ddd0
CD
1000unsigned64
1001fp_sub(sim_cpu *cpu,
1002 address_word cia,
1003 unsigned64 op1,
1004 unsigned64 op2,
1005 FP_formats fmt)
1006{
1007 return fp_binary(cpu, cia, &sim_fpu_sub, op1, op2, fmt);
1008}
487f79b7 1009
ba46ddd0
CD
1010unsigned64
1011fp_mul(sim_cpu *cpu,
1012 address_word cia,
1013 unsigned64 op1,
1014 unsigned64 op2,
1015 FP_formats fmt)
1016{
1017 return fp_binary(cpu, cia, &sim_fpu_mul, op1, op2, fmt);
1018}
487f79b7 1019
ba46ddd0
CD
1020unsigned64
1021fp_div(sim_cpu *cpu,
1022 address_word cia,
1023 unsigned64 op1,
1024 unsigned64 op2,
1025 FP_formats fmt)
1026{
1027 return fp_binary(cpu, cia, &sim_fpu_div, op1, op2, fmt);
1028}
487f79b7 1029
ba46ddd0
CD
1030unsigned64
1031fp_recip(sim_cpu *cpu,
1032 address_word cia,
1033 unsigned64 op,
1034 FP_formats fmt)
1035{
1036 return fp_unary(cpu, cia, &sim_fpu_inv, op, fmt);
1037}
487f79b7 1038
ba46ddd0
CD
1039unsigned64
1040fp_sqrt(sim_cpu *cpu,
1041 address_word cia,
1042 unsigned64 op,
1043 FP_formats fmt)
1044{
1045 return fp_unary(cpu, cia, &sim_fpu_sqrt, op, fmt);
487f79b7
CD
1046}
1047
f3c08b7e
CD
1048unsigned64
1049fp_rsqrt(sim_cpu *cpu,
1050 address_word cia,
1051 unsigned64 op,
1052 FP_formats fmt)
1053{
1054 return fp_inv_sqrt(cpu, cia, op, fmt);
1055}
1056
1057unsigned64
1058fp_madd(sim_cpu *cpu,
1059 address_word cia,
1060 unsigned64 op1,
1061 unsigned64 op2,
1062 unsigned64 op3,
1063 FP_formats fmt)
1064{
1065 return fp_mac(cpu, cia, &sim_fpu_add, op1, op2, op3, 0, 0, fmt);
1066}
1067
1068unsigned64
1069fp_msub(sim_cpu *cpu,
1070 address_word cia,
1071 unsigned64 op1,
1072 unsigned64 op2,
1073 unsigned64 op3,
1074 FP_formats fmt)
1075{
1076 return fp_mac(cpu, cia, &sim_fpu_sub, op1, op2, op3, 0, 0, fmt);
1077}
1078
1079unsigned64
1080fp_nmadd(sim_cpu *cpu,
1081 address_word cia,
1082 unsigned64 op1,
1083 unsigned64 op2,
1084 unsigned64 op3,
1085 FP_formats fmt)
1086{
1087 return fp_mac(cpu, cia, &sim_fpu_add, op1, op2, op3, 0, 1, fmt);
1088}
1089
1090unsigned64
1091fp_nmsub(sim_cpu *cpu,
1092 address_word cia,
1093 unsigned64 op1,
1094 unsigned64 op2,
1095 unsigned64 op3,
1096 FP_formats fmt)
1097{
1098 return fp_mac(cpu, cia, &sim_fpu_sub, op1, op2, op3, 0, 1, fmt);
1099}
1100
ba46ddd0 1101
e7e81181
CD
1102/* MIPS-3D ASE operations. */
1103
1104/* Variant of fp_binary for *r.ps MIPS-3D operations. */
1105static unsigned64
1106fp_binary_r(sim_cpu *cpu,
1107 address_word cia,
1108 int (*sim_fpu_op)(sim_fpu *, const sim_fpu *, const sim_fpu *),
1109 unsigned64 op1,
1110 unsigned64 op2)
1111{
1112 sim_fpu wop1;
1113 sim_fpu wop2;
1114 sim_fpu ans;
1115 sim_fpu_round round = rounding_mode (GETRM ());
1116 sim_fpu_denorm denorm = denorm_mode (cpu);
1117 sim_fpu_status status_u, status_l;
1118 unsigned64 result;
1119 unsigned32 res_u, res_l;
1120
1121 /* The format must be fmt_ps. */
1122 status_u = 0;
1123 sim_fpu_32to (&wop1, FP_PS_upper (op1));
1124 sim_fpu_32to (&wop2, FP_PS_lower (op1));
1125 status_u |= (*sim_fpu_op) (&ans, &wop1, &wop2);
1126 status_u |= sim_fpu_round_32 (&ans, round, denorm);
1127 sim_fpu_to32 (&res_u, &ans);
1128 status_l = 0;
1129 sim_fpu_32to (&wop1, FP_PS_upper (op2));
1130 sim_fpu_32to (&wop2, FP_PS_lower (op2));
1131 status_l |= (*sim_fpu_op) (&ans, &wop1, &wop2);
1132 status_l |= sim_fpu_round_32 (&ans, round, denorm);
1133 sim_fpu_to32 (&res_l, &ans);
1134 result = FP_PS_cat (res_u, res_l);
1135
1136 update_fcsr (cpu, cia, status_u | status_l);
1137 return result;
1138}
1139
1140unsigned64
1141fp_add_r(sim_cpu *cpu,
1142 address_word cia,
1143 unsigned64 op1,
1144 unsigned64 op2,
1145 FP_formats fmt)
1146{
1147 return fp_binary_r (cpu, cia, &sim_fpu_add, op1, op2);
1148}
1149
1150unsigned64
1151fp_mul_r(sim_cpu *cpu,
1152 address_word cia,
1153 unsigned64 op1,
1154 unsigned64 op2,
1155 FP_formats fmt)
1156{
1157 return fp_binary_r (cpu, cia, &sim_fpu_mul, op1, op2);
1158}
1159
1160#define NR_FRAC_GUARD (60)
1161#define IMPLICIT_1 LSBIT64 (NR_FRAC_GUARD)
1162
1163static int
1164fpu_inv1(sim_fpu *f, const sim_fpu *l)
1165{
1166 static const sim_fpu sim_fpu_one = {
1167 sim_fpu_class_number, 0, IMPLICIT_1, 0
1168 };
1169 int status = 0;
1170 sim_fpu t;
1171
1172 if (sim_fpu_is_zero (l))
1173 {
1174 *f = sim_fpu_maxfp;
1175 f->sign = l->sign;
1176 return sim_fpu_status_invalid_div0;
1177 }
1178 if (sim_fpu_is_infinity (l))
1179 {
1180 *f = sim_fpu_zero;
1181 f->sign = l->sign;
1182 return status;
1183 }
1184 status |= sim_fpu_div (f, &sim_fpu_one, l);
1185 return status;
1186}
1187
1188static int
1189fpu_inv1_32(sim_fpu *f, const sim_fpu *l)
1190{
1191 if (sim_fpu_is_zero (l))
1192 {
1193 *f = sim_fpu_max32;
1194 f->sign = l->sign;
1195 return sim_fpu_status_invalid_div0;
1196 }
1197 return fpu_inv1 (f, l);
1198}
1199
1200static int
1201fpu_inv1_64(sim_fpu *f, const sim_fpu *l)
1202{
1203 if (sim_fpu_is_zero (l))
1204 {
1205 *f = sim_fpu_max64;
1206 f->sign = l->sign;
1207 return sim_fpu_status_invalid_div0;
1208 }
1209 return fpu_inv1 (f, l);
1210}
1211
1212unsigned64
1213fp_recip1(sim_cpu *cpu,
1214 address_word cia,
1215 unsigned64 op,
1216 FP_formats fmt)
1217{
1218 switch (fmt)
1219 {
1220 case fmt_single:
1221 case fmt_ps:
1222 return fp_unary (cpu, cia, &fpu_inv1_32, op, fmt);
1223 case fmt_double:
1224 return fp_unary (cpu, cia, &fpu_inv1_64, op, fmt);
1225 }
1226 return 0;
1227}
1228
1229unsigned64
1230fp_recip2(sim_cpu *cpu,
1231 address_word cia,
1232 unsigned64 op1,
1233 unsigned64 op2,
1234 FP_formats fmt)
1235{
1236 static const unsigned64 one_single = UNSIGNED64 (0x3F800000);
1237 static const unsigned64 one_double = UNSIGNED64 (0x3FF0000000000000);
1238 static const unsigned64 one_ps = (one_single << 32 | one_single);
1239 unsigned64 one;
1240
1241 /* Implemented as nmsub fd, 1, fs, ft. */
1242 switch (fmt)
1243 {
1244 case fmt_single: one = one_single; break;
1245 case fmt_double: one = one_double; break;
1246 case fmt_ps: one = one_ps; break;
1247 default: one = 0; abort ();
1248 }
1249 return fp_mac (cpu, cia, &sim_fpu_sub, op1, op2, one, 0, 1, fmt);
1250}
1251
1252static int
1253fpu_inv_sqrt1(sim_fpu *f, const sim_fpu *l)
1254{
1255 static const sim_fpu sim_fpu_one = {
1256 sim_fpu_class_number, 0, IMPLICIT_1, 0
1257 };
1258 int status = 0;
1259 sim_fpu t;
1260
1261 if (sim_fpu_is_zero (l))
1262 {
1263 *f = sim_fpu_maxfp;
1264 f->sign = l->sign;
1265 return sim_fpu_status_invalid_div0;
1266 }
1267 if (sim_fpu_is_infinity (l))
1268 {
1269 if (!l->sign)
1270 {
1271 f->class = sim_fpu_class_zero;
1272 f->sign = 0;
1273 }
1274 else
1275 {
1276 *f = sim_fpu_qnan;
1277 status = sim_fpu_status_invalid_sqrt;
1278 }
1279 return status;
1280 }
1281 status |= sim_fpu_sqrt (&t, l);
1282 status |= sim_fpu_div (f, &sim_fpu_one, &t);
1283 return status;
1284}
1285
1286static int
1287fpu_inv_sqrt1_32(sim_fpu *f, const sim_fpu *l)
1288{
1289 if (sim_fpu_is_zero (l))
1290 {
1291 *f = sim_fpu_max32;
1292 f->sign = l->sign;
1293 return sim_fpu_status_invalid_div0;
1294 }
1295 return fpu_inv_sqrt1 (f, l);
1296}
1297
1298static int
1299fpu_inv_sqrt1_64(sim_fpu *f, const sim_fpu *l)
1300{
1301 if (sim_fpu_is_zero (l))
1302 {
1303 *f = sim_fpu_max64;
1304 f->sign = l->sign;
1305 return sim_fpu_status_invalid_div0;
1306 }
1307 return fpu_inv_sqrt1 (f, l);
1308}
1309
1310unsigned64
1311fp_rsqrt1(sim_cpu *cpu,
1312 address_word cia,
1313 unsigned64 op,
1314 FP_formats fmt)
1315{
1316 switch (fmt)
1317 {
1318 case fmt_single:
1319 case fmt_ps:
1320 return fp_unary (cpu, cia, &fpu_inv_sqrt1_32, op, fmt);
1321 case fmt_double:
1322 return fp_unary (cpu, cia, &fpu_inv_sqrt1_64, op, fmt);
1323 }
1324 return 0;
1325}
1326
1327unsigned64
1328fp_rsqrt2(sim_cpu *cpu,
1329 address_word cia,
1330 unsigned64 op1,
1331 unsigned64 op2,
1332 FP_formats fmt)
1333{
1334 static const unsigned64 half_single = UNSIGNED64 (0x3F000000);
1335 static const unsigned64 half_double = UNSIGNED64 (0x3FE0000000000000);
1336 static const unsigned64 half_ps = (half_single << 32 | half_single);
1337 unsigned64 half;
1338
1339 /* Implemented as (nmsub fd, 0.5, fs, ft)/2, where the divide is
1340 done by scaling the exponent during multiply. */
1341 switch (fmt)
1342 {
1343 case fmt_single: half = half_single; break;
1344 case fmt_double: half = half_double; break;
1345 case fmt_ps: half = half_ps; break;
1346 default: half = 0; abort ();
1347 }
1348 return fp_mac (cpu, cia, &sim_fpu_sub, op1, op2, half, -1, 1, fmt);
1349}
1350
1351
cfe9ea23
CD
1352/* Conversion operations. */
1353
487f79b7 1354uword64
18d8a52d 1355convert (sim_cpu *cpu,
487f79b7
CD
1356 address_word cia,
1357 int rm,
1358 uword64 op,
1359 FP_formats from,
1360 FP_formats to)
1361{
1362 sim_fpu wop;
577d8c4b 1363 sim_fpu_round round = rounding_mode (rm);
52714ff9 1364 sim_fpu_denorm denorm = denorm_mode (cpu);
487f79b7
CD
1365 unsigned32 result32;
1366 unsigned64 result64;
52714ff9 1367 sim_fpu_status status = 0;
487f79b7 1368
487f79b7
CD
1369 /* Convert the input to sim_fpu internal format */
1370 switch (from)
1371 {
1372 case fmt_double:
1373 sim_fpu_64to (&wop, op);
1374 break;
1375 case fmt_single:
1376 sim_fpu_32to (&wop, op);
1377 break;
1378 case fmt_word:
52714ff9 1379 status = sim_fpu_i32to (&wop, op, round);
487f79b7
CD
1380 break;
1381 case fmt_long:
52714ff9 1382 status = sim_fpu_i64to (&wop, op, round);
487f79b7
CD
1383 break;
1384 default:
52714ff9 1385 sim_io_eprintf (SD, "Bad switch\n");
487f79b7
CD
1386 abort ();
1387 }
1388
1389 /* Convert sim_fpu format into the output */
1390 /* The value WOP is converted to the destination format, rounding
1391 using mode RM. When the destination is a fixed-point format, then
1392 a source value of Infinity, NaN or one which would round to an
3a2b820e
CD
1393 integer outside the fixed point range then an IEEE Invalid Operation
1394 condition is raised. Not used if destination format is PS. */
487f79b7
CD
1395 switch (to)
1396 {
1397 case fmt_single:
52714ff9
CD
1398 status |= sim_fpu_round_32 (&wop, round, denorm);
1399 /* For a NaN, normalize mantissa bits (cvt.s.d can't preserve them) */
1400 if (sim_fpu_is_qnan (&wop))
1401 wop = sim_fpu_qnan;
487f79b7
CD
1402 sim_fpu_to32 (&result32, &wop);
1403 result64 = result32;
1404 break;
1405 case fmt_double:
52714ff9
CD
1406 status |= sim_fpu_round_64 (&wop, round, denorm);
1407 /* For a NaN, normalize mantissa bits (make cvt.d.s consistent) */
1408 if (sim_fpu_is_qnan (&wop))
1409 wop = sim_fpu_qnan;
487f79b7
CD
1410 sim_fpu_to64 (&result64, &wop);
1411 break;
1412 case fmt_word:
52714ff9 1413 status |= sim_fpu_to32i (&result32, &wop, round);
487f79b7
CD
1414 result64 = result32;
1415 break;
1416 case fmt_long:
52714ff9 1417 status |= sim_fpu_to64i (&result64, &wop, round);
487f79b7
CD
1418 break;
1419 default:
1420 result64 = 0;
52714ff9 1421 sim_io_eprintf (SD, "Bad switch\n");
487f79b7
CD
1422 abort ();
1423 }
37d146fa 1424
52714ff9
CD
1425 update_fcsr (cpu, cia, status);
1426 return result64;
487f79b7
CD
1427}
1428
3a2b820e
CD
1429unsigned64
1430ps_lower(sim_cpu *cpu,
1431 address_word cia,
1432 unsigned64 op)
1433{
1434 return FP_PS_lower (op);
1435}
1436
1437unsigned64
1438ps_upper(sim_cpu *cpu,
1439 address_word cia,
1440 unsigned64 op)
1441{
1442 return FP_PS_upper(op);
1443}
1444
1445unsigned64
1446pack_ps(sim_cpu *cpu,
1447 address_word cia,
1448 unsigned64 op1,
1449 unsigned64 op2,
1450 FP_formats fmt)
1451{
1452 unsigned64 result = 0;
1453
1454 /* The registers must specify FPRs valid for operands of type
1455 "fmt". If they are not valid, the result is undefined. */
1456
1457 /* The format type should already have been checked: */
1458 switch (fmt)
1459 {
1460 case fmt_single:
1461 {
1462 sim_fpu wop;
1463 unsigned32 res_u, res_l;
1464 sim_fpu_32to (&wop, op1);
1465 sim_fpu_to32 (&res_u, &wop);
1466 sim_fpu_32to (&wop, op2);
1467 sim_fpu_to32 (&res_l, &wop);
1468 result = FP_PS_cat(res_u, res_l);
1469 break;
1470 }
1471 default:
1472 sim_io_eprintf (SD, "Bad switch\n");
1473 abort ();
1474 }
1475
1476 return result;
1477}
1478
1479unsigned64
1480convert_ps (sim_cpu *cpu,
1481 address_word cia,
1482 int rm,
1483 unsigned64 op,
1484 FP_formats from,
1485 FP_formats to)
1486{
1487 sim_fpu wop_u, wop_l;
1488 sim_fpu_round round = rounding_mode (rm);
1489 sim_fpu_denorm denorm = denorm_mode (cpu);
1490 unsigned32 res_u, res_l;
1491 unsigned64 result;
1492 sim_fpu_status status_u = 0, status_l = 0;
1493
1494 /* As convert, but used only for paired values (formats PS, PW) */
1495
1496 /* Convert the input to sim_fpu internal format */
1497 switch (from)
1498 {
1499 case fmt_word: /* fmt_pw */
1500 sim_fpu_i32to (&wop_u, (op >> 32) & (unsigned)0xFFFFFFFF, round);
1501 sim_fpu_i32to (&wop_l, op & (unsigned)0xFFFFFFFF, round);
1502 break;
1503 case fmt_ps:
1504 sim_fpu_32to (&wop_u, FP_PS_upper(op));
1505 sim_fpu_32to (&wop_l, FP_PS_lower(op));
1506 break;
1507 default:
1508 sim_io_eprintf (SD, "Bad switch\n");
1509 abort ();
1510 }
1511
1512 /* Convert sim_fpu format into the output */
1513 switch (to)
1514 {
1515 case fmt_word: /* fmt_pw */
1516 status_u |= sim_fpu_to32i (&res_u, &wop_u, round);
1517 status_l |= sim_fpu_to32i (&res_l, &wop_l, round);
1518 result = (((unsigned64)res_u) << 32) | (unsigned64)res_l;
1519 break;
1520 case fmt_ps:
1521 status_u |= sim_fpu_round_32 (&wop_u, 0, round);
1522 status_l |= sim_fpu_round_32 (&wop_l, 0, round);
1523 sim_fpu_to32 (&res_u, &wop_u);
1524 sim_fpu_to32 (&res_l, &wop_l);
1525 result = FP_PS_cat(res_u, res_l);
1526 break;
1527 default:
1528 result = 0;
1529 sim_io_eprintf (SD, "Bad switch\n");
1530 abort ();
1531 }
1532
1533 update_fcsr (cpu, cia, status_u | status_l);
1534 return result;
1535}
1536
07892c0b
CD
1537static const char *
1538fpu_format_name (FP_formats fmt)
1539{
1540 switch (fmt)
1541 {
1542 case fmt_single:
1543 return "single";
1544 case fmt_double:
1545 return "double";
1546 case fmt_word:
1547 return "word";
1548 case fmt_long:
1549 return "long";
3a2b820e
CD
1550 case fmt_ps:
1551 return "ps";
07892c0b
CD
1552 case fmt_unknown:
1553 return "<unknown>";
1554 case fmt_uninterpreted:
1555 return "<uninterpreted>";
1556 case fmt_uninterpreted_32:
1557 return "<uninterpreted_32>";
1558 case fmt_uninterpreted_64:
1559 return "<uninterpreted_64>";
1560 default:
1561 return "<format error>";
1562 }
1563}
487f79b7 1564
07892c0b
CD
1565#ifdef DEBUG
1566static const char *
1567fpu_rounding_mode_name (int rm)
1568{
1569 switch (rm)
1570 {
1571 case FP_RM_NEAREST:
1572 return "Round";
1573 case FP_RM_TOZERO:
1574 return "Trunc";
1575 case FP_RM_TOPINF:
1576 return "Ceil";
1577 case FP_RM_TOMINF:
1578 return "Floor";
1579 default:
1580 return "<rounding mode error>";
1581 }
1582}
1583#endif /* DEBUG */