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 96422 2002-05-11 21:20:05Z 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 int opmask[] = {0, 0, 1, 3}; 190 191/* Decode 5 bit register field depending on the type. */ 192#define RN_DECODE(tp, rn) \ 193 ((tp == FTYPE_DBL || tp == FTYPE_EXT ? INSFPdq_RN((rn)) : (rn)) & \ 194 ~opmask[tp]) 195 196/* Operand size in 32-bit registers. */ 197#define OPSZ(tp) ((tp) == FTYPE_LNG ? 2 : (1 << (tp))) 198 199/* 200 * Helper for forming the below case statements. Build only the op3 and opf 201 * field of the instruction, these are the only ones that need to match. 202 */ 203#define FOP(op3, opf) \ 204 ((op3) << IF_F3_OP3_SHIFT | (opf) << IF_F3_OPF_SHIFT) 205 206/* 207 * Implement a move operation for all supported operand types. The additional 208 * nand and xor parameters will be applied to the upper 32 bit word of the 209 * source operand. This allows to implement fabs and fneg (for fp operands 210 * only!) using this functions, too, by passing (1 << 31) for one of the 211 * parameters, and 0 for the other. 212 */ |
213static void |
214__fpu_mov(struct fpemu *fe, int type, int rd, int rs2, u_int32_t nand, 215 u_int32_t xor) |
216{ |
217 u_int64_t tmp64; 218 u_int32_t *p32; |
219 int i; 220 |
221 if (type == FTYPE_INT || type == FTYPE_SNG) 222 __fpu_setreg(rd, (__fpu_getreg(rs2) & ~nand) ^ xor); 223 else { 224 /* 225 * Need to use the double versions to be able to access 226 * the upper 32 fp registers. 227 */ 228 for (i = 0; i < OPSZ(type); i += 2, rd += 2, rs2 += 2) { 229 tmp64 = __fpu_getreg64(rs2); 230 if (i == 0) 231 tmp64 = (tmp64 & ~((u_int64_t)nand << 32)) ^ 232 ((u_int64_t)xor << 32); 233 __fpu_setreg64(rd, tmp64); 234 } 235 } |
236} 237 238static __inline void |
239__fpu_ccmov(struct fpemu *fe, int type, int rd, int rs2, |
240 u_int32_t insn, int fcc) 241{ 242 243 if (IF_F4_COND(insn) == fcc) |
244 __fpu_mov(fe, type, rd, rs2, 0, 0); |
245} 246 247static int 248__fpu_cmpck(struct fpemu *fe) 249{ 250 u_long fsr; 251 int cx; 252 --- 10 unchanged lines hidden (view full) --- 263 return (SIGFPE); 264 } 265 fsr |= FSR_NV << FSR_AEXC_SHIFT; 266 } 267 fe->fe_fsr = fsr; 268 return (0); 269} 270 |
271/* |
272 * Execute an FPU instruction (one that runs entirely in the FPU; not 273 * FBfcc or STF, for instance). On return, fe->fe_fs->fs_fsr will be 274 * modified to reflect the setting the hardware would have left. 275 * 276 * Note that we do not catch all illegal opcodes, so you can, for instance, 277 * multiply two integers this way. 278 */ 279static int 280__fpu_execute(struct utrapframe *uf, struct fpemu *fe, u_int32_t insn, u_long tstate) 281{ 282 struct fpn *fp; 283 int opf, rs1, rs2, rd, type, mask, cx, cond; 284 u_long reg, fsr; 285 u_int space[4]; |
286 int i; |
287 288 /* 289 * `Decode' and execute instruction. Start with no exceptions. 290 * The type of any opf opcode is in the bottom two bits, so we 291 * squish them out here. 292 */ 293 opf = insn & (IF_MASK(IF_F3_OP3_SHIFT, IF_F3_OP3_BITS) | 294 IF_MASK(IF_F3_OPF_SHIFT + 2, IF_F3_OPF_BITS - 2)); 295 type = IF_F3_OPF(insn) & 3; |
296 rs1 = RN_DECODE(type, IF_F3_RS1(insn)); 297 rs2 = RN_DECODE(type, IF_F3_RS2(insn)); 298 rd = RN_DECODE(type, IF_F3_RD(insn)); |
299 cond = 0; 300#ifdef notdef |
301 if ((rs1 | rs2 | rd) & opmask[type]) |
302 return (SIGILL); 303#endif 304 fsr = fe->fe_fsr; 305 fe->fe_fsr &= ~FSR_CEXC_MASK; 306 fe->fe_cx = 0; 307 switch (opf) { 308 case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_FCC(0))): |
309 __fpu_ccmov(fe, type, rd, rs2, insn, FSR_GET_FCC0(fsr)); |
310 return (0); 311 case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_FCC(1))): |
312 __fpu_ccmov(fe, type, rd, rs2, insn, FSR_GET_FCC1(fsr)); |
313 return (0); 314 case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_FCC(2))): |
315 __fpu_ccmov(fe, type, rd, rs2, insn, FSR_GET_FCC2(fsr)); |
316 return (0); 317 case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_FCC(3))): |
318 __fpu_ccmov(fe, type, rd, rs2, insn, FSR_GET_FCC3(fsr)); |
319 return (0); 320 case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_ICC)): |
321 __fpu_ccmov(fe, type, rd, rs2, insn, |
322 (tstate & TSTATE_ICC_MASK) >> TSTATE_ICC_SHIFT); 323 return (0); 324 case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_XCC)): |
325 __fpu_ccmov(fe, type, rd, rs2, insn, |
326 (tstate & TSTATE_XCC_MASK) >> (TSTATE_XCC_SHIFT)); 327 return (0); 328 case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_Z)): 329 reg = __emul_fetch_reg(uf, IF_F4_RS1(insn)); 330 if (reg == 0) |
331 __fpu_mov(fe, type, rd, rs2, 0, 0); |
332 return (0); 333 case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_LEZ)): 334 reg = __emul_fetch_reg(uf, IF_F4_RS1(insn)); 335 if (reg <= 0) |
336 __fpu_mov(fe, type, rd, rs2, 0, 0); |
337 return (0); 338 case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_LZ)): 339 reg = __emul_fetch_reg(uf, IF_F4_RS1(insn)); 340 if (reg < 0) |
341 __fpu_mov(fe, type, rd, rs2, 0, 0); |
342 return (0); 343 case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_NZ)): 344 reg = __emul_fetch_reg(uf, IF_F4_RS1(insn)); 345 if (reg != 0) |
346 __fpu_mov(fe, type, rd, rs2, 0, 0); |
347 return (0); 348 case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_GZ)): 349 reg = __emul_fetch_reg(uf, IF_F4_RS1(insn)); 350 if (reg > 0) |
351 __fpu_mov(fe, type, rd, rs2, 0, 0); |
352 return (0); 353 case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_GEZ)): 354 reg = __emul_fetch_reg(uf, IF_F4_RS1(insn)); 355 if (reg >= 0) |
356 __fpu_mov(fe, type, rd, rs2, 0, 0); |
357 return (0); 358 case FOP(INS2_FPop2, INSFP2_FCMP): 359 __fpu_explode(fe, &fe->fe_f1, type, rs1); 360 __fpu_explode(fe, &fe->fe_f2, type, rs2); 361 __fpu_compare(fe, 0, IF_F3_CC(insn)); 362 return (__fpu_cmpck(fe)); 363 case FOP(INS2_FPop2, INSFP2_FCMPE): 364 __fpu_explode(fe, &fe->fe_f1, type, rs1); 365 __fpu_explode(fe, &fe->fe_f2, type, rs2); 366 __fpu_compare(fe, 1, IF_F3_CC(insn)); 367 return (__fpu_cmpck(fe)); 368 case FOP(INS2_FPop1, INSFP1_FMOV): /* these should all be pretty obvious */ |
369 __fpu_mov(fe, type, rd, rs2, 0, 0); |
370 return (0); 371 case FOP(INS2_FPop1, INSFP1_FNEG): |
372 __fpu_mov(fe, type, rd, rs2, 0, (1 << 31)); |
373 return (0); 374 case FOP(INS2_FPop1, INSFP1_FABS): |
375 __fpu_mov(fe, type, rd, rs2, (1 << 31), 0); |
376 return (0); 377 case FOP(INS2_FPop1, INSFP1_FSQRT): 378 __fpu_explode(fe, &fe->fe_f1, type, rs2); 379 fp = __fpu_sqrt(fe); 380 break; 381 case FOP(INS2_FPop1, INSFP1_FADD): 382 __fpu_explode(fe, &fe->fe_f1, type, rs1); 383 __fpu_explode(fe, &fe->fe_f2, type, rs2); --- 20 unchanged lines hidden (view full) --- 404 return (SIGILL); 405 __fpu_explode(fe, &fe->fe_f1, type, rs1); 406 __fpu_explode(fe, &fe->fe_f2, type, rs2); 407 type++; /* single to double, or double to quad */ 408 /* 409 * Recalculate rd (the old type applied for the source regs 410 * only, the target one has a different size). 411 */ |
412 rd = RN_DECODE(type, IF_F3_RD(insn)); |
413 fp = __fpu_mul(fe); 414 break; 415 case FOP(INS2_FPop1, INSFP1_FxTOs): 416 case FOP(INS2_FPop1, INSFP1_FxTOd): 417 case FOP(INS2_FPop1, INSFP1_FxTOq): 418 type = FTYPE_LNG; 419 __fpu_explode(fe, fp = &fe->fe_f1, type, rs2); 420 /* sneaky; depends on instruction encoding */ 421 type = (IF_F3_OPF(insn) >> 2) & 3; |
422 rd = RN_DECODE(type, IF_F3_RD(insn)); |
423 break; 424 case FOP(INS2_FPop1, INSFP1_FTOx): 425 __fpu_explode(fe, fp = &fe->fe_f1, type, rs2); 426 type = FTYPE_LNG; 427 mask = 1; /* needs 2 registers */ 428 rd = IF_F3_RD(insn) & ~mask; 429 break; 430 case FOP(INS2_FPop1, INSFP1_FTOs): 431 case FOP(INS2_FPop1, INSFP1_FTOd): 432 case FOP(INS2_FPop1, INSFP1_FTOq): 433 case FOP(INS2_FPop1, INSFP1_FTOi): 434 __fpu_explode(fe, fp = &fe->fe_f1, type, rs2); 435 /* sneaky; depends on instruction encoding */ 436 type = (IF_F3_OPF(insn) >> 2) & 3; |
437 rd = RN_DECODE(type, IF_F3_RD(insn)); |
438 break; 439 default: 440 return (SIGILL); 441 } 442 443 /* 444 * ALU operation is complete. Collapse the result and then check 445 * for exceptions. If we got any, and they are enabled, do not --- 9 unchanged lines hidden (view full) --- 455 fsr = (fsr & ~FSR_FTT_MASK) | 456 FSR_FTT(FSR_FTT_IEEE) | 457 FSR_CEXC(cx_to_trapx[(cx & mask) - 1]); 458 return (SIGFPE); 459 } 460 fsr |= (cx << FSR_CEXC_SHIFT) | (cx << FSR_AEXC_SHIFT); 461 } 462 fe->fe_fsr = fsr; |
463 if (type == FTYPE_INT || type == FTYPE_SNG) 464 __fpu_setreg(rd, space[0]); 465 else { 466 for (i = 0; i < OPSZ(type); i += 2) { 467 __fpu_setreg64(rd + i, ((u_int64_t)space[i] << 32) | 468 space[i + 1]); |
469 } 470 } 471 return (0); /* success */ 472} |