fpu_emu.c revision 1.27 1 /* $NetBSD: fpu_emu.c,v 1.27 2020/07/15 07:54:25 rin Exp $ */
2
3 /*
4 * Copyright 2001 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Eduardo Horvath and Simon Burge for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 /*
39 * Copyright (c) 1992, 1993
40 * The Regents of the University of California. All rights reserved.
41 *
42 * This software was developed by the Computer Systems Engineering group
43 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
44 * contributed to Berkeley.
45 *
46 * All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the University of
49 * California, Lawrence Berkeley Laboratory.
50 *
51 * Redistribution and use in source and binary forms, with or without
52 * modification, are permitted provided that the following conditions
53 * are met:
54 * 1. Redistributions of source code must retain the above copyright
55 * notice, this list of conditions and the following disclaimer.
56 * 2. Redistributions in binary form must reproduce the above copyright
57 * notice, this list of conditions and the following disclaimer in the
58 * documentation and/or other materials provided with the distribution.
59 * 3. Neither the name of the University nor the names of its contributors
60 * may be used to endorse or promote products derived from this software
61 * without specific prior written permission.
62 *
63 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
64 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
65 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
66 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
67 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
68 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
69 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
70 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
71 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
72 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
73 * SUCH DAMAGE.
74 *
75 * @(#)fpu.c 8.1 (Berkeley) 6/11/93
76 */
77
78 #include <sys/cdefs.h>
79 __KERNEL_RCSID(0, "$NetBSD: fpu_emu.c,v 1.27 2020/07/15 07:54:25 rin Exp $");
80
81 #ifdef _KERNEL_OPT
82 #include "opt_ddb.h"
83 #endif
84
85 #include <sys/param.h>
86 #include <sys/systm.h>
87 #include <sys/evcnt.h>
88 #include <sys/proc.h>
89 #include <sys/siginfo.h>
90 #include <sys/signal.h>
91 #include <sys/signalvar.h>
92 #include <sys/syslog.h>
93
94 #include <powerpc/instr.h>
95 #include <machine/fpu.h>
96 #include <machine/reg.h>
97 #include <machine/trap.h>
98
99 #include <powerpc/fpu/fpu_emu.h>
100 #include <powerpc/fpu/fpu_extern.h>
101
102 #define FPU_EMU_EVCNT_DECL(name) \
103 static struct evcnt fpu_emu_ev_##name = \
104 EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, NULL, "fpemu", #name); \
105 EVCNT_ATTACH_STATIC(fpu_emu_ev_##name)
106
107 #define FPU_EMU_EVCNT_INCR(name) \
108 fpu_emu_ev_##name.ev_count++
109
110 FPU_EMU_EVCNT_DECL(stfiwx);
111 FPU_EMU_EVCNT_DECL(fpstore);
112 FPU_EMU_EVCNT_DECL(fpload);
113 FPU_EMU_EVCNT_DECL(fcmpu);
114 FPU_EMU_EVCNT_DECL(frsp);
115 FPU_EMU_EVCNT_DECL(fctiw);
116 FPU_EMU_EVCNT_DECL(fcmpo);
117 FPU_EMU_EVCNT_DECL(mtfsb1);
118 FPU_EMU_EVCNT_DECL(fnegabs);
119 FPU_EMU_EVCNT_DECL(mcrfs);
120 FPU_EMU_EVCNT_DECL(mtfsb0);
121 FPU_EMU_EVCNT_DECL(fmr);
122 FPU_EMU_EVCNT_DECL(mtfsfi);
123 FPU_EMU_EVCNT_DECL(fnabs);
124 FPU_EMU_EVCNT_DECL(fabs);
125 FPU_EMU_EVCNT_DECL(mffs);
126 FPU_EMU_EVCNT_DECL(mtfsf);
127 FPU_EMU_EVCNT_DECL(fctid);
128 FPU_EMU_EVCNT_DECL(fcfid);
129 FPU_EMU_EVCNT_DECL(fdiv);
130 FPU_EMU_EVCNT_DECL(fsub);
131 FPU_EMU_EVCNT_DECL(fadd);
132 FPU_EMU_EVCNT_DECL(fsqrt);
133 FPU_EMU_EVCNT_DECL(fsel);
134 FPU_EMU_EVCNT_DECL(fpres);
135 FPU_EMU_EVCNT_DECL(fmul);
136 FPU_EMU_EVCNT_DECL(frsqrte);
137 FPU_EMU_EVCNT_DECL(fmulsub);
138 FPU_EMU_EVCNT_DECL(fmuladd);
139 FPU_EMU_EVCNT_DECL(fnmsub);
140 FPU_EMU_EVCNT_DECL(fnmadd);
141
142 /* FPSR exception masks */
143 #define FPSR_EX_MSK (FPSCR_VX|FPSCR_OX|FPSCR_UX|FPSCR_ZX| \
144 FPSCR_XX|FPSCR_VXSNAN|FPSCR_VXISI|FPSCR_VXIDI| \
145 FPSCR_VXZDZ|FPSCR_VXIMZ|FPSCR_VXVC|FPSCR_VXSOFT|\
146 FPSCR_VXSQRT|FPSCR_VXCVI)
147 #define FPSR_EX (FPSCR_VE|FPSCR_OE|FPSCR_UE|FPSCR_ZE|FPSCR_XE)
148 #define FPSR_EXOP (FPSR_EX_MSK&(~FPSR_EX))
149
150
151 int fpe_debug = 0;
152
153 #ifdef DDB
154 extern vaddr_t opc_disasm(vaddr_t loc, int opcode);
155 #endif
156
157 #ifdef DEBUG
158 /*
159 * Dump a `fpn' structure.
160 */
161 void
162 fpu_dumpfpn(struct fpn *fp)
163 {
164 static const char *class[] = {
165 "SNAN", "QNAN", "ZERO", "NUM", "INF"
166 };
167
168 KASSERT(fp != NULL);
169
170 printf("%s %c.%x %x %x %xE%d\n", class[fp->fp_class + 2],
171 fp->fp_sign ? '-' : ' ',
172 fp->fp_mant[0], fp->fp_mant[1],
173 fp->fp_mant[2], fp->fp_mant[3],
174 fp->fp_exp);
175 }
176 #endif
177
178 /*
179 * fpu_execute returns the following error numbers (0 = no error):
180 */
181 #define FPE 1 /* take a floating point exception */
182 #define NOTFPU 2 /* not an FPU instruction */
183 #define FAULT 3
184
185
186 /*
187 * Emulate a floating-point instruction.
188 * Return zero for success, else signal number.
189 * (Typically: zero, SIGFPE, SIGILL, SIGSEGV)
190 */
191 bool
192 fpu_emulate(struct trapframe *tf, struct fpreg *fpf, ksiginfo_t *ksi)
193 {
194 union instr insn;
195 struct fpemu fe;
196
197 KSI_INIT_TRAP(ksi);
198 ksi->ksi_signo = 0;
199 ksi->ksi_addr = (void *)tf->tf_srr0;
200
201 /* initialize insn.is_datasize to tell it is *not* initialized */
202 fe.fe_fpstate = fpf;
203 fe.fe_cx = 0;
204
205 /* always set this (to avoid a warning) */
206
207 if (copyin((void *) (tf->tf_srr0), &insn.i_int, sizeof (insn.i_int))) {
208 #ifdef DEBUG
209 printf("fpu_emulate: fault reading opcode\n");
210 #endif
211 ksi->ksi_signo = SIGSEGV;
212 ksi->ksi_trap = EXC_ISI;
213 ksi->ksi_code = SEGV_MAPERR;
214 return true;
215 }
216
217 DPRINTF(FPE_EX, ("fpu_emulate: emulating insn %x at %p\n",
218 insn.i_int, (void *)tf->tf_srr0));
219
220 if ((insn.i_any.i_opcd == OPC_TWI) ||
221 ((insn.i_any.i_opcd == OPC_integer_31) &&
222 (insn.i_x.i_xo == OPC31_TW))) {
223 /* Check for the two trap insns. */
224 DPRINTF(FPE_EX, ("fpu_emulate: SIGTRAP\n"));
225 ksi->ksi_signo = SIGTRAP;
226 ksi->ksi_trap = EXC_PGM;
227 ksi->ksi_code = TRAP_BRKPT;
228 return true;
229 }
230 switch (fpu_execute(tf, &fe, &insn)) {
231 case 0:
232 DPRINTF(FPE_EX, ("fpu_emulate: success\n"));
233 tf->tf_srr0 += 4;
234 return true;
235
236 case FPE:
237 DPRINTF(FPE_EX, ("fpu_emulate: SIGFPE\n"));
238 ksi->ksi_signo = SIGFPE;
239 ksi->ksi_trap = EXC_PGM;
240 return true;
241
242 case FAULT:
243 DPRINTF(FPE_EX, ("fpu_emulate: SIGSEGV\n"));
244 ksi->ksi_signo = SIGSEGV;
245 ksi->ksi_trap = EXC_DSI;
246 ksi->ksi_code = SEGV_MAPERR;
247 ksi->ksi_addr = (void *)fe.fe_addr;
248 return true;
249
250 case NOTFPU:
251 default:
252 DPRINTF(FPE_EX, ("fpu_emulate: SIGILL\n"));
253 #if defined(DDB) && defined(DEBUG)
254 if (fpe_debug & FPE_EX) {
255 printf("fpu_emulate: illegal insn %x at %p:",
256 insn.i_int, (void *) (tf->tf_srr0));
257 opc_disasm((vaddr_t)(tf->tf_srr0), insn.i_int);
258 }
259 #endif
260 return false;
261 }
262 }
263
264 /*
265 * Execute an FPU instruction (one that runs entirely in the FPU; not
266 * FBfcc or STF, for instance). On return, fe->fe_fs->fs_fsr will be
267 * modified to reflect the setting the hardware would have left.
268 *
269 * Note that we do not catch all illegal opcodes, so you can, for instance,
270 * multiply two integers this way.
271 */
272 int
273 fpu_execute(struct trapframe *tf, struct fpemu *fe, union instr *insn)
274 {
275 struct fpn *fp;
276 union instr instr = *insn;
277 int *a;
278 vaddr_t addr;
279 int ra, rb, rc, rt, type, mask, fsr, cx, bf, setcr;
280 unsigned int cond;
281 struct fpreg *fs;
282
283 /* Setup work. */
284 fp = NULL;
285 fs = fe->fe_fpstate;
286 fe->fe_fpscr = ((int *)&fs->fpscr)[1];
287
288 /*
289 * On PowerPC all floating point values are stored in registers
290 * as doubles, even when used for single precision operations.
291 */
292 type = FTYPE_DBL;
293 cond = instr.i_any.i_rc;
294 setcr = 0;
295 bf = 0; /* XXX gcc */
296
297 #if defined(DDB) && defined(DEBUG)
298 if (fpe_debug & FPE_EX) {
299 vaddr_t loc = tf->tf_srr0;
300
301 printf("Trying to emulate: %p ", (void *)loc);
302 opc_disasm(loc, instr.i_int);
303 }
304 #endif
305
306 /*
307 * `Decode' and execute instruction.
308 */
309
310 if ((instr.i_any.i_opcd >= OPC_LFS && instr.i_any.i_opcd <= OPC_STFDU) ||
311 instr.i_any.i_opcd == OPC_integer_31) {
312 /*
313 * Handle load/store insns:
314 *
315 * Convert to/from single if needed, calculate addr,
316 * and update index reg if needed.
317 */
318 uint64_t buf;
319 size_t size = sizeof(float);
320 int store, update;
321
322 cond = 0; /* ld/st never set condition codes */
323
324
325 if (instr.i_any.i_opcd == OPC_integer_31) {
326 if (instr.i_x.i_xo == OPC31_STFIWX) {
327 FPU_EMU_EVCNT_INCR(stfiwx);
328
329 /* Store as integer */
330 ra = instr.i_x.i_ra;
331 rb = instr.i_x.i_rb;
332 DPRINTF(FPE_INSN, ("reg %d has %lx reg %d has %lx\n",
333 ra, tf->tf_fixreg[ra], rb, tf->tf_fixreg[rb]));
334
335 addr = tf->tf_fixreg[rb];
336 if (ra != 0)
337 addr += tf->tf_fixreg[ra];
338 rt = instr.i_x.i_rt;
339 a = (int *)&fs->fpreg[rt];
340 DPRINTF(FPE_INSN,
341 ("fpu_execute: Store INT %x at %p\n",
342 a[1], (void *)addr));
343 if (copyout(&a[1], (void *)addr, sizeof(int))) {
344 fe->fe_addr = addr;
345 return (FAULT);
346 }
347 return (0);
348 }
349
350 if ((instr.i_x.i_xo & OPC31_FPMASK) != OPC31_FPOP)
351 /* Not an indexed FP load/store op */
352 return (NOTFPU);
353
354 store = (instr.i_x.i_xo & 0x80);
355 if (instr.i_x.i_xo & 0x40)
356 size = sizeof(double);
357 else
358 type = FTYPE_SNG;
359 update = (instr.i_x.i_xo & 0x20);
360
361 /* calculate EA of load/store */
362 ra = instr.i_x.i_ra;
363 rb = instr.i_x.i_rb;
364 DPRINTF(FPE_INSN, ("reg %d has %lx reg %d has %lx\n",
365 ra, tf->tf_fixreg[ra], rb, tf->tf_fixreg[rb]));
366 addr = tf->tf_fixreg[rb];
367 if (ra != 0)
368 addr += tf->tf_fixreg[ra];
369 rt = instr.i_x.i_rt;
370 } else {
371 store = instr.i_d.i_opcd & 0x4;
372 if (instr.i_d.i_opcd & 0x2)
373 size = sizeof(double);
374 else
375 type = FTYPE_SNG;
376 update = instr.i_d.i_opcd & 0x1;
377
378 /* calculate EA of load/store */
379 ra = instr.i_d.i_ra;
380 addr = instr.i_d.i_d;
381 DPRINTF(FPE_INSN, ("reg %d has %lx displ %lx\n",
382 ra, tf->tf_fixreg[ra], addr));
383 if (ra != 0)
384 addr += tf->tf_fixreg[ra];
385 rt = instr.i_d.i_rt;
386 }
387
388 if (update && ra == 0)
389 return (NOTFPU);
390
391 if (store) {
392 /* Store */
393 FPU_EMU_EVCNT_INCR(fpstore);
394 if (type != FTYPE_DBL) {
395 DPRINTF(FPE_INSN,
396 ("fpu_execute: Store SNG at %p\n",
397 (void *)addr));
398 fpu_explode(fe, fp = &fe->fe_f1, FTYPE_DBL, rt);
399 fpu_implode(fe, fp, type, (void *)&buf);
400 if (copyout(&buf, (void *)addr, size)) {
401 fe->fe_addr = addr;
402 return (FAULT);
403 }
404 } else {
405 DPRINTF(FPE_INSN,
406 ("fpu_execute: Store DBL at %p\n",
407 (void *)addr));
408 if (copyout(&fs->fpreg[rt], (void *)addr, size)) {
409 fe->fe_addr = addr;
410 return (FAULT);
411 }
412 }
413 } else {
414 /* Load */
415 FPU_EMU_EVCNT_INCR(fpload);
416 DPRINTF(FPE_INSN, ("fpu_execute: Load from %p\n",
417 (void *)addr));
418 if (copyin((const void *)addr, &fs->fpreg[rt], size)) {
419 fe->fe_addr = addr;
420 return (FAULT);
421 }
422 if (type != FTYPE_DBL) {
423 fpu_explode(fe, fp = &fe->fe_f1, type, rt);
424 fpu_implode(fe, fp, FTYPE_DBL,
425 (u_int *)&fs->fpreg[rt]);
426 }
427 }
428 if (update)
429 tf->tf_fixreg[ra] = addr;
430 /* Complete. */
431 return (0);
432 #ifdef notyet
433 } else if (instr.i_any.i_opcd == OPC_load_st_62) {
434 /* These are 64-bit extenstions */
435 return (NOTFPU);
436 #endif
437 } else if (instr.i_any.i_opcd == OPC_sp_fp_59 ||
438 instr.i_any.i_opcd == OPC_dp_fp_63) {
439
440
441 if (instr.i_any.i_opcd == OPC_dp_fp_63 &&
442 !(instr.i_a.i_xo & OPC63M_MASK)) {
443 /* Format X */
444 rt = instr.i_x.i_rt;
445 ra = instr.i_x.i_ra;
446 rb = instr.i_x.i_rb;
447
448
449 /* One of the special opcodes.... */
450 switch (instr.i_x.i_xo) {
451 case OPC63_FCMPU:
452 FPU_EMU_EVCNT_INCR(fcmpu);
453 DPRINTF(FPE_INSN, ("fpu_execute: FCMPU\n"));
454 rt >>= 2;
455 fpu_explode(fe, &fe->fe_f1, type, ra);
456 fpu_explode(fe, &fe->fe_f2, type, rb);
457 fpu_compare(fe, 0);
458 /* Make sure we do the condition regs. */
459 cond = 0;
460 /* N.B.: i_rs is already left shifted by two. */
461 bf = instr.i_x.i_rs & 0xfc;
462 setcr = 1;
463 break;
464
465 case OPC63_FRSP:
466 /*
467 * Convert to single:
468 *
469 * PowerPC uses this to round a double
470 * precision value to single precision,
471 * but values in registers are always
472 * stored in double precision format.
473 */
474 FPU_EMU_EVCNT_INCR(frsp);
475 DPRINTF(FPE_INSN, ("fpu_execute: FRSP\n"));
476 fpu_explode(fe, fp = &fe->fe_f1, FTYPE_DBL, rb);
477 fpu_implode(fe, fp, FTYPE_SNG,
478 (u_int *)&fs->fpreg[rt]);
479 fpu_explode(fe, fp = &fe->fe_f1, FTYPE_SNG, rt);
480 type = FTYPE_DBL;
481 break;
482 case OPC63_FCTIW:
483 case OPC63_FCTIWZ:
484 FPU_EMU_EVCNT_INCR(fctiw);
485 DPRINTF(FPE_INSN, ("fpu_execute: FCTIW\n"));
486 fpu_explode(fe, fp = &fe->fe_f1, type, rb);
487 type = FTYPE_INT;
488 break;
489 case OPC63_FCMPO:
490 FPU_EMU_EVCNT_INCR(fcmpo);
491 DPRINTF(FPE_INSN, ("fpu_execute: FCMPO\n"));
492 rt >>= 2;
493 fpu_explode(fe, &fe->fe_f1, type, ra);
494 fpu_explode(fe, &fe->fe_f2, type, rb);
495 fpu_compare(fe, 1);
496 /* Make sure we do the condition regs. */
497 cond = 0;
498 /* N.B.: i_rs is already left shifted by two. */
499 bf = instr.i_x.i_rs & 0xfc;
500 setcr = 1;
501 break;
502 case OPC63_MTFSB1:
503 FPU_EMU_EVCNT_INCR(mtfsb1);
504 DPRINTF(FPE_INSN, ("fpu_execute: MTFSB1\n"));
505 fe->fe_fpscr |=
506 (~(FPSCR_VX|FPSR_EX) & (1<<(31-rt)));
507 break;
508 case OPC63_FNEG:
509 FPU_EMU_EVCNT_INCR(fnegabs);
510 DPRINTF(FPE_INSN, ("fpu_execute: FNEGABS\n"));
511 memcpy(&fs->fpreg[rt], &fs->fpreg[rb],
512 sizeof(double));
513 a = (int *)&fs->fpreg[rt];
514 *a ^= (1 << 31);
515 break;
516 case OPC63_MCRFS:
517 FPU_EMU_EVCNT_INCR(mcrfs);
518 DPRINTF(FPE_INSN, ("fpu_execute: MCRFS\n"));
519 cond = 0;
520 rt &= 0x1c;
521 ra &= 0x1c;
522 /* Extract the bits we want */
523 mask = (fe->fe_fpscr >> (28 - ra)) & 0xf;
524 /* Clear the bits we copied. */
525 fe->fe_cx =
526 (FPSR_EX_MSK | (0xf << (28 - ra)));
527 fe->fe_fpscr &= fe->fe_cx;
528 /* Now shove them in the right part of cr */
529 tf->tf_cr &= ~(0xf << (28 - rt));
530 tf->tf_cr |= (mask << (28 - rt));
531 break;
532 case OPC63_MTFSB0:
533 FPU_EMU_EVCNT_INCR(mtfsb0);
534 DPRINTF(FPE_INSN, ("fpu_execute: MTFSB0\n"));
535 fe->fe_fpscr &=
536 ((FPSCR_VX|FPSR_EX) & ~(1<<(31-rt)));
537 break;
538 case OPC63_FMR:
539 FPU_EMU_EVCNT_INCR(fmr);
540 DPRINTF(FPE_INSN, ("fpu_execute: FMR\n"));
541 memcpy(&fs->fpreg[rt], &fs->fpreg[rb],
542 sizeof(double));
543 break;
544 case OPC63_MTFSFI:
545 FPU_EMU_EVCNT_INCR(mtfsfi);
546 DPRINTF(FPE_INSN, ("fpu_execute: MTFSFI\n"));
547 rb >>= 1;
548 rt &= 0x1c; /* Already left-shifted 4 */
549 fe->fe_cx = rb << (28 - rt);
550 mask = 0xf<<(28 - rt);
551 fe->fe_fpscr = (fe->fe_fpscr & ~mask) |
552 fe->fe_cx;
553 /* XXX weird stuff about OX, FX, FEX, and VX should be handled */
554 break;
555 case OPC63_FNABS:
556 FPU_EMU_EVCNT_INCR(fnabs);
557 DPRINTF(FPE_INSN, ("fpu_execute: FABS\n"));
558 memcpy(&fs->fpreg[rt], &fs->fpreg[rb],
559 sizeof(double));
560 a = (int *)&fs->fpreg[rt];
561 *a |= (1 << 31);
562 break;
563 case OPC63_FABS:
564 FPU_EMU_EVCNT_INCR(fabs);
565 DPRINTF(FPE_INSN, ("fpu_execute: FABS\n"));
566 memcpy(&fs->fpreg[rt], &fs->fpreg[rb],
567 sizeof(double));
568 a = (int *)&fs->fpreg[rt];
569 *a &= ~(1 << 31);
570 break;
571 case OPC63_MFFS:
572 FPU_EMU_EVCNT_INCR(mffs);
573 DPRINTF(FPE_INSN, ("fpu_execute: MFFS\n"));
574 memcpy(&fs->fpreg[rt], &fs->fpscr,
575 sizeof(fs->fpscr));
576 break;
577 case OPC63_MTFSF:
578 FPU_EMU_EVCNT_INCR(mtfsf);
579 DPRINTF(FPE_INSN, ("fpu_execute: MTFSF\n"));
580 if ((rt = instr.i_xfl.i_flm) == -1)
581 mask = -1;
582 else {
583 mask = 0;
584 /* Convert 1 bit -> 4 bits */
585 for (ra = 0; ra < 8; ra ++)
586 if (rt & (1<<ra))
587 mask |= (0xf<<(4*ra));
588 }
589 a = (int *)&fs->fpreg[rt];
590 fe->fe_cx = mask & a[1];
591 fe->fe_fpscr = (fe->fe_fpscr&~mask) |
592 (fe->fe_cx);
593 /* XXX weird stuff about OX, FX, FEX, and VX should be handled */
594 break;
595 case OPC63_FCTID:
596 case OPC63_FCTIDZ:
597 FPU_EMU_EVCNT_INCR(fctid);
598 DPRINTF(FPE_INSN, ("fpu_execute: FCTID\n"));
599 fpu_explode(fe, fp = &fe->fe_f1, type, rb);
600 type = FTYPE_LNG;
601 break;
602 case OPC63_FCFID:
603 FPU_EMU_EVCNT_INCR(fcfid);
604 DPRINTF(FPE_INSN, ("fpu_execute: FCFID\n"));
605 type = FTYPE_LNG;
606 fpu_explode(fe, fp = &fe->fe_f1, type, rb);
607 type = FTYPE_DBL;
608 break;
609 default:
610 return (NOTFPU);
611 break;
612 }
613 } else {
614 /* Format A */
615 rt = instr.i_a.i_frt;
616 ra = instr.i_a.i_fra;
617 rb = instr.i_a.i_frb;
618 rc = instr.i_a.i_frc;
619
620 /*
621 * All arithmetic operations work on registers, which
622 * are stored as doubles.
623 */
624 type = FTYPE_DBL;
625 switch ((unsigned int)instr.i_a.i_xo) {
626 case OPC59_FDIVS:
627 FPU_EMU_EVCNT_INCR(fdiv);
628 DPRINTF(FPE_INSN, ("fpu_execute: FDIV\n"));
629 fpu_explode(fe, &fe->fe_f1, type, ra);
630 fpu_explode(fe, &fe->fe_f2, type, rb);
631 fp = fpu_div(fe);
632 break;
633 case OPC59_FSUBS:
634 FPU_EMU_EVCNT_INCR(fsub);
635 DPRINTF(FPE_INSN, ("fpu_execute: FSUB\n"));
636 fpu_explode(fe, &fe->fe_f1, type, ra);
637 fpu_explode(fe, &fe->fe_f2, type, rb);
638 fp = fpu_sub(fe);
639 break;
640 case OPC59_FADDS:
641 FPU_EMU_EVCNT_INCR(fadd);
642 DPRINTF(FPE_INSN, ("fpu_execute: FADD\n"));
643 fpu_explode(fe, &fe->fe_f1, type, ra);
644 fpu_explode(fe, &fe->fe_f2, type, rb);
645 fp = fpu_add(fe);
646 break;
647 case OPC59_FSQRTS:
648 FPU_EMU_EVCNT_INCR(fsqrt);
649 DPRINTF(FPE_INSN, ("fpu_execute: FSQRT\n"));
650 fpu_explode(fe, &fe->fe_f1, type, rb);
651 fp = fpu_sqrt(fe);
652 break;
653 case OPC63M_FSEL:
654 FPU_EMU_EVCNT_INCR(fsel);
655 DPRINTF(FPE_INSN, ("fpu_execute: FSEL\n"));
656 a = (int *)&fe->fe_fpstate->fpreg[ra];
657 if ((*a & 0x80000000) && (*a & 0x7fffffff))
658 /* fra < 0 */
659 rc = rb;
660 DPRINTF(FPE_INSN, ("f%d => f%d\n", rc, rt));
661 memcpy(&fs->fpreg[rt], &fs->fpreg[rc],
662 sizeof(double));
663 break;
664 case OPC59_FRES:
665 FPU_EMU_EVCNT_INCR(fpres);
666 DPRINTF(FPE_INSN, ("fpu_execute: FPRES\n"));
667 fpu_explode(fe, &fe->fe_f1, type, rb);
668 fp = fpu_sqrt(fe);
669 /* now we've gotta overwrite the dest reg */
670 *((int *)&fe->fe_fpstate->fpreg[rt]) = 1;
671 fpu_explode(fe, &fe->fe_f1, FTYPE_INT, rt);
672 fpu_div(fe);
673 break;
674 case OPC59_FMULS:
675 FPU_EMU_EVCNT_INCR(fmul);
676 DPRINTF(FPE_INSN, ("fpu_execute: FMUL\n"));
677 fpu_explode(fe, &fe->fe_f1, type, ra);
678 fpu_explode(fe, &fe->fe_f2, type, rc);
679 fp = fpu_mul(fe);
680 break;
681 case OPC63M_FRSQRTE:
682 /* Reciprocal sqrt() estimate */
683 FPU_EMU_EVCNT_INCR(frsqrte);
684 DPRINTF(FPE_INSN, ("fpu_execute: FRSQRTE\n"));
685 fpu_explode(fe, &fe->fe_f1, type, rb);
686 fp = fpu_sqrt(fe);
687 fe->fe_f2 = *fp;
688 /* now we've gotta overwrite the dest reg */
689 *((int *)&fe->fe_fpstate->fpreg[rt]) = 1;
690 fpu_explode(fe, &fe->fe_f1, FTYPE_INT, rt);
691 fpu_div(fe);
692 break;
693 case OPC59_FMSUBS:
694 FPU_EMU_EVCNT_INCR(fmulsub);
695 DPRINTF(FPE_INSN, ("fpu_execute: FMULSUB\n"));
696 fpu_explode(fe, &fe->fe_f1, type, ra);
697 fpu_explode(fe, &fe->fe_f2, type, rc);
698 fp = fpu_mul(fe);
699 fe->fe_f1 = *fp;
700 fpu_explode(fe, &fe->fe_f2, type, rb);
701 fp = fpu_sub(fe);
702 break;
703 case OPC59_FMADDS:
704 FPU_EMU_EVCNT_INCR(fmuladd);
705 DPRINTF(FPE_INSN, ("fpu_execute: FMULADD\n"));
706 fpu_explode(fe, &fe->fe_f1, type, ra);
707 fpu_explode(fe, &fe->fe_f2, type, rc);
708 fp = fpu_mul(fe);
709 fe->fe_f1 = *fp;
710 fpu_explode(fe, &fe->fe_f2, type, rb);
711 fp = fpu_add(fe);
712 break;
713 case OPC59_FNMSUBS:
714 FPU_EMU_EVCNT_INCR(fnmsub);
715 DPRINTF(FPE_INSN, ("fpu_execute: FNMSUB\n"));
716 fpu_explode(fe, &fe->fe_f1, type, ra);
717 fpu_explode(fe, &fe->fe_f2, type, rc);
718 fp = fpu_mul(fe);
719 fe->fe_f1 = *fp;
720 fpu_explode(fe, &fe->fe_f2, type, rb);
721 fp = fpu_sub(fe);
722 /* Negate */
723 fp->fp_sign ^= 1;
724 break;
725 case OPC59_FNMADDS:
726 FPU_EMU_EVCNT_INCR(fnmadd);
727 DPRINTF(FPE_INSN, ("fpu_execute: FNMADD\n"));
728 fpu_explode(fe, &fe->fe_f1, type, ra);
729 fpu_explode(fe, &fe->fe_f2, type, rc);
730 fp = fpu_mul(fe);
731 fe->fe_f1 = *fp;
732 fpu_explode(fe, &fe->fe_f2, type, rb);
733 fp = fpu_add(fe);
734 /* Negate */
735 fp->fp_sign ^= 1;
736 break;
737 default:
738 return (NOTFPU);
739 break;
740 }
741
742 /* If the instruction was single precision, round */
743 if (!(instr.i_any.i_opcd & 0x4)) {
744 fpu_implode(fe, fp, FTYPE_SNG,
745 (u_int *)&fs->fpreg[rt]);
746 fpu_explode(fe, fp = &fe->fe_f1, FTYPE_SNG, rt);
747 }
748 }
749 } else {
750 return (NOTFPU);
751 }
752
753 /*
754 * ALU operation is complete. Collapse the result and then check
755 * for exceptions. If we got any, and they are enabled, do not
756 * alter the destination register, just stop with an exception.
757 * Otherwise set new current exceptions and accrue.
758 */
759 if (fp)
760 fpu_implode(fe, fp, type, (u_int *)&fs->fpreg[rt]);
761 cx = fe->fe_cx;
762 fsr = fe->fe_fpscr;
763 if (cx != 0) {
764 fsr &= ~FPSCR_FX;
765 if ((cx^fsr)&FPSR_EX_MSK)
766 fsr |= FPSCR_FX;
767 mask = fsr & FPSR_EX;
768 mask <<= (25-3);
769 if (cx & mask)
770 fsr |= FPSCR_FEX;
771 if (cx & FPSCR_FPRF) {
772 /* Need to replace CC */
773 fsr &= ~FPSCR_FPRF;
774 }
775 if (cx & (FPSR_EXOP))
776 fsr |= FPSCR_VX;
777 fsr |= cx;
778 DPRINTF(FPE_INSN, ("fpu_execute: cx %x, fsr %x\n", cx, fsr));
779 }
780
781 if (cond) {
782 cond = fsr & 0xf0000000;
783 /* Isolate condition codes */
784 cond >>= 28;
785 /* Move fpu condition codes to cr[1] */
786 tf->tf_cr &= (0x0f000000);
787 tf->tf_cr |= (cond<<24);
788 DPRINTF(FPE_INSN, ("fpu_execute: cr[1] <= %x\n", cond));
789 }
790
791 if (setcr) {
792 cond = fsr & FPSCR_FPCC;
793 /* Isolate condition codes */
794 cond <<= 16;
795 /* Move fpu condition codes to cr[1] */
796 tf->tf_cr &= ~(0xf0000000>>bf);
797 tf->tf_cr |= (cond>>bf);
798 DPRINTF(FPE_INSN, ("fpu_execute: cr[%d] (cr=%x) <= %x\n", bf/4, tf->tf_cr, cond));
799 }
800
801 ((int *)&fs->fpscr)[1] = fsr;
802 if (fsr & FPSCR_FEX)
803 return(FPE);
804 return (0); /* success */
805 }
806