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