1 /* $NetBSD: fpu_fscale.c,v 1.12 2005/12/11 12:17:52 christos Exp $ */
4 * Copyright (c) 1995 Ken Nakata
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 * 4. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Gordon Ross
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * FSCALE - separated from the other type0 arithmetic instructions
35 * for performance reason; maybe unnecessary, but FSCALE assumes
36 * the source operand be an integer. It performs type conversion
37 * only if the source operand is *not* an integer.
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: fpu_fscale.c,v 1.12 2005/12/11 12:17:52 christos Exp $");
43 #include <sys/types.h>
44 #include <sys/signal.h>
45 #include <sys/systm.h>
46 #include <machine/frame.h>
48 #include "fpu_emulate.h"
51 fpu_emul_fscale(struct fpemu
*fe
, struct instruction
*insn
)
67 fpregs
= &(fe
->fe_fpframe
->fpf_regs
[0]);
68 /* clear all exceptions and conditions */
69 fpsr
= fe
->fe_fpsr
& ~FPSR_EXCP
& ~FPSR_CCB
;
71 printf("fpu_emul_fscale: FPSR = %08x, FPCR = %08x\n", fpsr
, fe
->fe_fpcr
);
74 word1
= insn
->is_word1
;
75 format
= (word1
>> 10) & 7;
76 regnum
= (word1
>> 7) & 7;
78 fe
->fe_fpcr
&= FPCR_ROUND
;
79 fe
->fe_fpcr
|= FPCR_ZERO
;
81 /* get the source operand */
82 if ((word1
& 0x4000) == 0) {
84 printf("fpu_emul_fscale: FP%d op FP%d => FP%d\n",
85 format
, regnum
, regnum
);
86 /* the operand is an FP reg */
87 printf("fpu_emul_scale: src opr FP%d=%08x%08x%08x\n",
88 format
, fpregs
[format
*3], fpregs
[format
*3+1],
91 fpu_explode(fe
, &fe
->fe_f2
, FTYPE_EXT
, &fpregs
[format
* 3]);
92 fpu_implode(fe
, &fe
->fe_f2
, FTYPE_LNG
, buf
);
95 /* the operand is in memory */
96 if (format
== FTYPE_DBL
) {
97 insn
->is_datasize
= 8;
98 } else if (format
== FTYPE_SNG
|| format
== FTYPE_LNG
) {
99 insn
->is_datasize
= 4;
100 } else if (format
== FTYPE_WRD
) {
101 insn
->is_datasize
= 2;
102 } else if (format
== FTYPE_BYT
) {
103 insn
->is_datasize
= 1;
104 } else if (format
== FTYPE_EXT
) {
105 insn
->is_datasize
= 12;
107 /* invalid or unsupported operand format */
112 /* Get effective address. (modreg=opcode&077) */
113 sig
= fpu_decode_ea(frame
, insn
, &insn
->is_ea
, insn
->is_opcode
);
116 printf("fpu_emul_fscale: error in decode_ea\n");
122 printf("fpu_emul_fscale: addr mode = ");
123 flags
= insn
->is_ea
.ea_flags
;
124 regname
= (insn
->is_ea
.ea_regnum
& 8) ? 'a' : 'd';
126 if (flags
& EA_DIRECT
) {
127 printf("%c%d\n", regname
, insn
->is_ea
.ea_regnum
& 7);
128 } else if (flags
& EA_PREDECR
) {
129 printf("%c%d@-\n", regname
, insn
->is_ea
.ea_regnum
& 7);
130 } else if (flags
& EA_POSTINCR
) {
131 printf("%c%d@+\n", regname
, insn
->is_ea
.ea_regnum
& 7);
132 } else if (flags
& EA_OFFSET
) {
133 printf("%c%d@(%d)\n", regname
, insn
->is_ea
.ea_regnum
& 7,
134 insn
->is_ea
.ea_offset
);
135 } else if (flags
& EA_INDEXED
) {
136 printf("%c%d@(...)\n", regname
, insn
->is_ea
.ea_regnum
& 7);
137 } else if (flags
& EA_ABS
) {
138 printf("0x%08x\n", insn
->is_ea
.ea_absaddr
);
139 } else if (flags
& EA_PC_REL
) {
140 printf("pc@(%d)\n", insn
->is_ea
.ea_offset
);
141 } else if (flags
& EA_IMMED
) {
142 printf("#0x%08x%08x%08x\n",
143 insn
->is_ea
.ea_immed
[0], insn
->is_ea
.ea_immed
[1],
144 insn
->is_ea
.ea_immed
[2]);
146 printf("%c%d@\n", regname
, insn
->is_ea
.ea_regnum
& 7);
149 fpu_load_ea(frame
, insn
, &insn
->is_ea
, (char*)buf
);
152 printf("fpu_emul_fscale: src = %08x%08x%08x, siz = %d\n",
153 buf
[0], buf
[1], buf
[2], insn
->is_datasize
);
155 if (format
== FTYPE_LNG
) {
158 } else if (format
== FTYPE_WRD
) {
160 scale
= buf
[0] & 0xffff;
161 if (scale
& 0x8000) {
164 } else if (format
== FTYPE_BYT
) {
166 scale
= buf
[0] & 0xff;
170 } else if (format
== FTYPE_DBL
|| format
== FTYPE_SNG
||
171 format
== FTYPE_EXT
) {
172 fpu_explode(fe
, &fe
->fe_f2
, format
, buf
);
173 fpu_implode(fe
, &fe
->fe_f2
, FTYPE_LNG
, buf
);
176 /* make it look like we've got an FP oprand */
177 fe
->fe_f2
.fp_class
= (buf
[0] == 0) ? FPC_ZERO
: FPC_NUM
;
180 /* assume there's no exception */
183 /* it's barbaric but we're going to operate directly on
184 * the dst operand's bit pattern */
185 sign
= fpregs
[regnum
* 3] & 0x80000000;
186 exp
= (fpregs
[regnum
* 3] & 0x7fff0000) >> 16;
187 m0
= fpregs
[regnum
* 3 + 1];
188 m1
= fpregs
[regnum
* 3 + 2];
190 switch (fe
->fe_f2
.fp_class
) {
196 m0
= m1
= 0xffffffff;
200 if ((0 < exp
&& exp
< 0x7fff) ||
201 (exp
== 0 && (m0
| m1
) != 0)) {
202 /* normal or denormal */
206 u_int grs
; /* guard, round and sticky */
209 grs
= m1
<< (32 + exp
);
210 m1
= m0
<< (32 + exp
) | m1
>> -exp
;
215 switch (fe
->fe_fpcr
& 0x30) {
226 if (grs
== 0x80000000) {
234 } else if (grs
& 0x80000000) {
255 if (exp
== 0 && (m0
& 0x80000000) == 0) {
257 if ((m0
| m1
) == 0) {
261 } else if (exp
>= 0x7fff) {
262 /* overflow --> result = Inf */
263 /* but first, try to normalize in case it's an unnormalized */
264 while ((m0
& 0x80000000) == 0) {
266 m0
= (m0
<< 1) | (m1
>> 31);
269 /* if it's still too large, then return Inf */
273 fpsr
|= FPSR_OVFL
| FPSR_INF
;
275 } else if ((m0
& 0x80000000) == 0) {
277 * it's a denormal; we try to normalize but
278 * result may and may not be a normal.
280 while (exp
> 0 && (m0
& 0x80000000) == 0) {
282 m0
= (m0
<< 1) | (m1
>> 31);
285 if ((m0
& 0x80000000) == 0) {
288 } /* exp in range and mantissa normalized */
289 } else if (exp
== 0 && m0
== 0 && m1
== 0) {
292 } /* else we know exp == 0x7fff */
293 else if ((m0
| m1
) == 0) {
295 } else if ((m0
& 0x40000000) == 0) {
296 /* a signaling NaN */
297 fpsr
|= FPSR_NAN
| FPSR_SNAN
;
306 m0
= m1
= 0xffffffff;
307 fpsr
|= FPSR_OPERR
| FPSR_NAN
;
311 panic("fpu_emul_fscale: invalid fp class");
316 /* store the result */
317 fpregs
[regnum
* 3] = sign
| (exp
<< 16);
318 fpregs
[regnum
* 3 + 1] = m0
;
319 fpregs
[regnum
* 3 + 2] = m1
;
325 /* update fpsr according to the result of operation */
326 fe
->fe_fpframe
->fpf_fpsr
= fe
->fe_fpsr
= fpsr
;
329 printf("fpu_emul_fscale: FPSR = %08x, FPCR = %08x\n",
330 fe
->fe_fpsr
, fe
->fe_fpcr
);
333 return (fpsr
& fe
->fe_fpcr
& FPSR_EXCP
) ? SIGFPE
: sig
;