Deleted Added
sdiff udiff text old ( 95587 ) new ( 96422 )
full compact
1/*
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This software was developed by the Computer Systems Engineering group
6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
7 * contributed to Berkeley.
8 *

--- 53 unchanged lines hidden (view full) ---

62 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
63 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64 *
65 * @(#)fpu.c 8.1 (Berkeley) 6/11/93
66 * $NetBSD: fpu.c,v 1.11 2000/12/06 01:47:50 mrg Exp $
67 */
68
69#include <sys/cdefs.h>
70__FBSDID("$FreeBSD: head/lib/libc/sparc64/fpu/fpu.c 95587 2002-04-27 21:56:28Z jake $");
71
72#include <sys/param.h>
73
74#include "namespace.h"
75#include <errno.h>
76#include <unistd.h>
77#include <signal.h>
78#include <stdlib.h>

--- 102 unchanged lines hidden (view full) ---

181 printf("%s %c.%x %x %x %xE%d", class[fp->fp_class + 2],
182 fp->fp_sign ? '-' : ' ',
183 fp->fp_mant[0], fp->fp_mant[1],
184 fp->fp_mant[2], fp->fp_mant[3],
185 fp->fp_exp);
186}
187#endif
188
189static void
190__fpu_mov(struct fpemu *fe, int type, int rd, int rs1, int rs2)
191{
192 int i;
193
194 i = 1 << type;
195 __fpu_setreg(rd++, rs1);
196 while (--i)
197 __fpu_setreg(rd++, __fpu_getreg(++rs2));
198}
199
200static __inline void
201__fpu_ccmov(struct fpemu *fe, int type, int rd, int rs1, int rs2,
202 u_int32_t insn, int fcc)
203{
204
205 if (IF_F4_COND(insn) == fcc)
206 __fpu_mov(fe, type, rd, __fpu_getreg(rs2), rs2);
207}
208
209static int
210__fpu_cmpck(struct fpemu *fe)
211{
212 u_long fsr;
213 int cx;
214

--- 10 unchanged lines hidden (view full) ---

225 return (SIGFPE);
226 }
227 fsr |= FSR_NV << FSR_AEXC_SHIFT;
228 }
229 fe->fe_fsr = fsr;
230 return (0);
231}
232
233static int opmask[] = {0, 0, 1, 3};
234
235/*
236 * Helper for forming the below case statements. Build only the op3 and opf
237 * field of the instruction, these are the only that need to match.
238 */
239#define FOP(op3, opf) \
240 ((op3) << IF_F3_OP3_SHIFT | (opf) << IF_F3_OPF_SHIFT)
241
242/*
243 * Execute an FPU instruction (one that runs entirely in the FPU; not
244 * FBfcc or STF, for instance). On return, fe->fe_fs->fs_fsr will be
245 * modified to reflect the setting the hardware would have left.
246 *
247 * Note that we do not catch all illegal opcodes, so you can, for instance,
248 * multiply two integers this way.
249 */
250static int
251__fpu_execute(struct utrapframe *uf, struct fpemu *fe, u_int32_t insn, u_long tstate)
252{
253 struct fpn *fp;
254 int opf, rs1, rs2, rd, type, mask, cx, cond;
255 u_long reg, fsr;
256 u_int space[4];
257
258 /*
259 * `Decode' and execute instruction. Start with no exceptions.
260 * The type of any opf opcode is in the bottom two bits, so we
261 * squish them out here.
262 */
263 opf = insn & (IF_MASK(IF_F3_OP3_SHIFT, IF_F3_OP3_BITS) |
264 IF_MASK(IF_F3_OPF_SHIFT + 2, IF_F3_OPF_BITS - 2));
265 type = IF_F3_OPF(insn) & 3;
266 mask = opmask[type];
267 rs1 = IF_F3_RS1(insn) & ~mask;
268 rs2 = IF_F3_RS2(insn) & ~mask;
269 rd = IF_F3_RD(insn) & ~mask;
270 cond = 0;
271#ifdef notdef
272 if ((rs1 | rs2 | rd) & mask)
273 return (SIGILL);
274#endif
275 fsr = fe->fe_fsr;
276 fe->fe_fsr &= ~FSR_CEXC_MASK;
277 fe->fe_cx = 0;
278 switch (opf) {
279 case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_FCC(0))):
280 __fpu_ccmov(fe, type, rd, __fpu_getreg(rs2), rs2, insn,
281 FSR_GET_FCC0(fsr));
282 return (0);
283 case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_FCC(1))):
284 __fpu_ccmov(fe, type, rd, __fpu_getreg(rs2), rs2, insn,
285 FSR_GET_FCC1(fsr));
286 return (0);
287 case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_FCC(2))):
288 __fpu_ccmov(fe, type, rd, __fpu_getreg(rs2), rs2, insn,
289 FSR_GET_FCC2(fsr));
290 return (0);
291 case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_FCC(3))):
292 __fpu_ccmov(fe, type, rd, __fpu_getreg(rs2), rs2, insn,
293 FSR_GET_FCC3(fsr));
294 return (0);
295 case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_ICC)):
296 __fpu_ccmov(fe, type, rd, __fpu_getreg(rs2), rs2, insn,
297 (tstate & TSTATE_ICC_MASK) >> TSTATE_ICC_SHIFT);
298 return (0);
299 case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_XCC)):
300 __fpu_ccmov(fe, type, rd, __fpu_getreg(rs2), rs2, insn,
301 (tstate & TSTATE_XCC_MASK) >> (TSTATE_XCC_SHIFT));
302 return (0);
303 case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_Z)):
304 reg = __emul_fetch_reg(uf, IF_F4_RS1(insn));
305 if (reg == 0)
306 __fpu_mov(fe, type, rd, __fpu_getreg(rs2), rs2);
307 return (0);
308 case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_LEZ)):
309 reg = __emul_fetch_reg(uf, IF_F4_RS1(insn));
310 if (reg <= 0)
311 __fpu_mov(fe, type, rd, __fpu_getreg(rs2), rs2);
312 return (0);
313 case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_LZ)):
314 reg = __emul_fetch_reg(uf, IF_F4_RS1(insn));
315 if (reg < 0)
316 __fpu_mov(fe, type, rd, __fpu_getreg(rs2), rs2);
317 return (0);
318 case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_NZ)):
319 reg = __emul_fetch_reg(uf, IF_F4_RS1(insn));
320 if (reg != 0)
321 __fpu_mov(fe, type, rd, __fpu_getreg(rs2), rs2);
322 return (0);
323 case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_GZ)):
324 reg = __emul_fetch_reg(uf, IF_F4_RS1(insn));
325 if (reg > 0)
326 __fpu_mov(fe, type, rd, __fpu_getreg(rs2), rs2);
327 return (0);
328 case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_GEZ)):
329 reg = __emul_fetch_reg(uf, IF_F4_RS1(insn));
330 if (reg >= 0)
331 __fpu_mov(fe, type, rd, __fpu_getreg(rs2), rs2);
332 return (0);
333 case FOP(INS2_FPop2, INSFP2_FCMP):
334 __fpu_explode(fe, &fe->fe_f1, type, rs1);
335 __fpu_explode(fe, &fe->fe_f2, type, rs2);
336 __fpu_compare(fe, 0, IF_F3_CC(insn));
337 return (__fpu_cmpck(fe));
338 case FOP(INS2_FPop2, INSFP2_FCMPE):
339 __fpu_explode(fe, &fe->fe_f1, type, rs1);
340 __fpu_explode(fe, &fe->fe_f2, type, rs2);
341 __fpu_compare(fe, 1, IF_F3_CC(insn));
342 return (__fpu_cmpck(fe));
343 case FOP(INS2_FPop1, INSFP1_FMOV): /* these should all be pretty obvious */
344 __fpu_mov(fe, type, rd, __fpu_getreg(rs2), rs2);
345 return (0);
346 case FOP(INS2_FPop1, INSFP1_FNEG):
347 __fpu_mov(fe, type, rd, __fpu_getreg(rs2) ^ (1 << 31), rs2);
348 return (0);
349 case FOP(INS2_FPop1, INSFP1_FABS):
350 __fpu_mov(fe, type, rd, __fpu_getreg(rs2) & ~(1 << 31), rs2);
351 return (0);
352 case FOP(INS2_FPop1, INSFP1_FSQRT):
353 __fpu_explode(fe, &fe->fe_f1, type, rs2);
354 fp = __fpu_sqrt(fe);
355 break;
356 case FOP(INS2_FPop1, INSFP1_FADD):
357 __fpu_explode(fe, &fe->fe_f1, type, rs1);
358 __fpu_explode(fe, &fe->fe_f2, type, rs2);

--- 20 unchanged lines hidden (view full) ---

379 return (SIGILL);
380 __fpu_explode(fe, &fe->fe_f1, type, rs1);
381 __fpu_explode(fe, &fe->fe_f2, type, rs2);
382 type++; /* single to double, or double to quad */
383 /*
384 * Recalculate rd (the old type applied for the source regs
385 * only, the target one has a different size).
386 */
387 mask = opmask[type];
388 rd = IF_F3_RD(insn) & ~mask;
389 fp = __fpu_mul(fe);
390 break;
391 case FOP(INS2_FPop1, INSFP1_FxTOs):
392 case FOP(INS2_FPop1, INSFP1_FxTOd):
393 case FOP(INS2_FPop1, INSFP1_FxTOq):
394 type = FTYPE_LNG;
395 __fpu_explode(fe, fp = &fe->fe_f1, type, rs2);
396 /* sneaky; depends on instruction encoding */
397 type = (IF_F3_OPF(insn) >> 2) & 3;
398 mask = opmask[type];
399 rd = IF_F3_RD(insn) & ~mask;
400 break;
401 case FOP(INS2_FPop1, INSFP1_FTOx):
402 __fpu_explode(fe, fp = &fe->fe_f1, type, rs2);
403 type = FTYPE_LNG;
404 mask = 1; /* needs 2 registers */
405 rd = IF_F3_RD(insn) & ~mask;
406 break;
407 case FOP(INS2_FPop1, INSFP1_FTOs):
408 case FOP(INS2_FPop1, INSFP1_FTOd):
409 case FOP(INS2_FPop1, INSFP1_FTOq):
410 case FOP(INS2_FPop1, INSFP1_FTOi):
411 __fpu_explode(fe, fp = &fe->fe_f1, type, rs2);
412 /* sneaky; depends on instruction encoding */
413 type = (IF_F3_OPF(insn) >> 2) & 3;
414 mask = opmask[type];
415 rd = IF_F3_RD(insn) & ~mask;
416 break;
417 default:
418 return (SIGILL);
419 }
420
421 /*
422 * ALU operation is complete. Collapse the result and then check
423 * for exceptions. If we got any, and they are enabled, do not

--- 9 unchanged lines hidden (view full) ---

433 fsr = (fsr & ~FSR_FTT_MASK) |
434 FSR_FTT(FSR_FTT_IEEE) |
435 FSR_CEXC(cx_to_trapx[(cx & mask) - 1]);
436 return (SIGFPE);
437 }
438 fsr |= (cx << FSR_CEXC_SHIFT) | (cx << FSR_AEXC_SHIFT);
439 }
440 fe->fe_fsr = fsr;
441 __fpu_setreg(rd, space[0]);
442 if (type >= FTYPE_DBL || type == FTYPE_LNG) {
443 __fpu_setreg(rd + 1, space[1]);
444 if (type > FTYPE_DBL) {
445 __fpu_setreg(rd + 2, space[2]);
446 __fpu_setreg(rd + 3, space[3]);
447 }
448 }
449 return (0); /* success */
450}