Home | History | Annotate | Line # | Download | only in fpe
fpu_fscale.c revision 1.11
      1  1.11   lukem /*	$NetBSD: fpu_fscale.c,v 1.11 2003/07/15 02:43:10 lukem Exp $	*/
      2   1.1  briggs 
      3   1.1  briggs /*
      4   1.1  briggs  * Copyright (c) 1995 Ken Nakata
      5   1.1  briggs  * All rights reserved.
      6   1.1  briggs  *
      7   1.1  briggs  * Redistribution and use in source and binary forms, with or without
      8   1.1  briggs  * modification, are permitted provided that the following conditions
      9   1.1  briggs  * are met:
     10   1.1  briggs  * 1. Redistributions of source code must retain the above copyright
     11   1.1  briggs  *    notice, this list of conditions and the following disclaimer.
     12   1.1  briggs  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1  briggs  *    notice, this list of conditions and the following disclaimer in the
     14   1.1  briggs  *    documentation and/or other materials provided with the distribution.
     15   1.1  briggs  * 3. The name of the author may not be used to endorse or promote products
     16   1.1  briggs  *    derived from this software without specific prior written permission.
     17   1.1  briggs  * 4. All advertising materials mentioning features or use of this software
     18   1.1  briggs  *    must display the following acknowledgement:
     19   1.1  briggs  *      This product includes software developed by Gordon Ross
     20   1.1  briggs  *
     21   1.1  briggs  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22   1.1  briggs  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23   1.1  briggs  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24   1.1  briggs  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25   1.1  briggs  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26   1.1  briggs  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27   1.1  briggs  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28   1.1  briggs  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29   1.1  briggs  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30   1.1  briggs  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31   1.1  briggs  */
     32   1.1  briggs 
     33   1.1  briggs /*
     34   1.1  briggs  * FSCALE - separated from the other type0 arithmetic instructions
     35   1.1  briggs  * for performance reason; maybe unnecessary, but FSCALE assumes
     36   1.1  briggs  * the source operand be an integer.  It performs type conversion
     37   1.1  briggs  * only if the source operand is *not* an integer.
     38   1.1  briggs  */
     39  1.11   lukem 
     40  1.11   lukem #include <sys/cdefs.h>
     41  1.11   lukem __KERNEL_RCSID(0, "$NetBSD: fpu_fscale.c,v 1.11 2003/07/15 02:43:10 lukem Exp $");
     42   1.1  briggs 
     43   1.1  briggs #include <sys/types.h>
     44   1.1  briggs #include <sys/signal.h>
     45   1.3  briggs #include <sys/systm.h>
     46   1.1  briggs #include <machine/frame.h>
     47   1.1  briggs 
     48   1.1  briggs #include "fpu_emulate.h"
     49   1.1  briggs 
     50   1.1  briggs int
     51   1.1  briggs fpu_emul_fscale(fe, insn)
     52   1.1  briggs      struct fpemu *fe;
     53   1.1  briggs      struct instruction *insn;
     54   1.1  briggs {
     55   1.1  briggs     struct frame *frame;
     56   1.1  briggs     u_int *fpregs;
     57   1.1  briggs     int word1, sig;
     58   1.1  briggs     int regnum, format;
     59   1.1  briggs     int scale, sign, exp;
     60   1.1  briggs     u_int m0, m1;
     61   1.1  briggs     u_int buf[3], fpsr;
     62  1.10  briggs #if DEBUG_FPE
     63   1.1  briggs     int flags;
     64   1.1  briggs     char regname;
     65  1.10  briggs #endif
     66   1.1  briggs 
     67   1.4     leo     scale = sig = 0;
     68   1.1  briggs     frame = fe->fe_frame;
     69   1.1  briggs     fpregs = &(fe->fe_fpframe->fpf_regs[0]);
     70   1.1  briggs     /* clear all exceptions and conditions */
     71   1.1  briggs     fpsr = fe->fe_fpsr & ~FPSR_EXCP & ~FPSR_CCB;
     72  1.10  briggs #if DEBUG_FPE
     73  1.10  briggs     printf("fpu_emul_fscale: FPSR = %08x, FPCR = %08x\n", fpsr, fe->fe_fpcr);
     74  1.10  briggs #endif
     75   1.1  briggs 
     76   1.1  briggs     word1 = insn->is_word1;
     77   1.1  briggs     format = (word1 >> 10) & 7;
     78   1.1  briggs     regnum = (word1 >> 7) & 7;
     79   1.1  briggs 
     80   1.1  briggs     fe->fe_fpcr &= FPCR_ROUND;
     81   1.1  briggs     fe->fe_fpcr |= FPCR_ZERO;
     82   1.1  briggs 
     83   1.1  briggs     /* get the source operand */
     84   1.1  briggs     if ((word1 & 0x4000) == 0) {
     85  1.10  briggs #if DEBUG_FPE
     86  1.10  briggs 	printf("fpu_emul_fscale: FP%d op FP%d => FP%d\n",
     87  1.10  briggs 	       format, regnum, regnum);
     88   1.1  briggs 	/* the operand is an FP reg */
     89  1.10  briggs 	printf("fpu_emul_scale: src opr FP%d=%08x%08x%08x\n",
     90  1.10  briggs 	       format, fpregs[format*3], fpregs[format*3+1],
     91  1.10  briggs 	       fpregs[format*3+2]);
     92  1.10  briggs #endif
     93   1.1  briggs 	fpu_explode(fe, &fe->fe_f2, FTYPE_EXT, &fpregs[format * 3]);
     94   1.1  briggs 	fpu_implode(fe, &fe->fe_f2, FTYPE_LNG, buf);
     95   1.7      is       scale = buf[0];
     96   1.1  briggs     } else {
     97   1.1  briggs 	/* the operand is in memory */
     98   1.1  briggs 	if (format == FTYPE_DBL) {
     99   1.1  briggs 	    insn->is_datasize = 8;
    100   1.1  briggs 	} else if (format == FTYPE_SNG || format == FTYPE_LNG) {
    101   1.1  briggs 	    insn->is_datasize = 4;
    102   1.1  briggs 	} else if (format == FTYPE_WRD) {
    103   1.1  briggs 	    insn->is_datasize = 2;
    104   1.1  briggs 	} else if (format == FTYPE_BYT) {
    105   1.1  briggs 	    insn->is_datasize = 1;
    106   1.1  briggs 	} else if (format == FTYPE_EXT) {
    107   1.1  briggs 	    insn->is_datasize = 12;
    108   1.1  briggs 	} else {
    109   1.1  briggs 	    /* invalid or unsupported operand format */
    110   1.1  briggs 	    sig = SIGFPE;
    111   1.1  briggs 	    return sig;
    112   1.1  briggs 	}
    113   1.1  briggs 
    114   1.1  briggs 	/* Get effective address. (modreg=opcode&077) */
    115  1.10  briggs 	sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode);
    116   1.1  briggs 	if (sig) {
    117  1.10  briggs #if DEBUG_FPE
    118  1.10  briggs 	    printf("fpu_emul_fscale: error in decode_ea\n");
    119  1.10  briggs #endif
    120   1.1  briggs 	    return sig;
    121   1.1  briggs 	}
    122   1.1  briggs 
    123  1.10  briggs #if DEBUG_FPE
    124  1.10  briggs 	printf("fpu_emul_fscale: addr mode = ");
    125  1.10  briggs 	flags = insn->is_ea.ea_flags;
    126  1.10  briggs 	regname = (insn->is_ea.ea_regnum & 8) ? 'a' : 'd';
    127  1.10  briggs 
    128  1.10  briggs 	if (flags & EA_DIRECT) {
    129  1.10  briggs 	    printf("%c%d\n", regname, insn->is_ea.ea_regnum & 7);
    130  1.10  briggs 	} else if (flags & EA_PREDECR) {
    131  1.10  briggs 	    printf("%c%d@-\n", regname, insn->is_ea.ea_regnum & 7);
    132  1.10  briggs 	} else if (flags & EA_POSTINCR) {
    133  1.10  briggs 		printf("%c%d@+\n", regname, insn->is_ea.ea_regnum & 7);
    134  1.10  briggs 	} else if (flags & EA_OFFSET) {
    135  1.10  briggs 	    printf("%c%d@(%d)\n", regname, insn->is_ea.ea_regnum & 7,
    136  1.10  briggs 		   insn->is_ea.ea_offset);
    137  1.10  briggs 	} else if (flags & EA_INDEXED) {
    138  1.10  briggs 	    printf("%c%d@(...)\n", regname, insn->is_ea.ea_regnum & 7);
    139  1.10  briggs 	} else if (flags & EA_ABS) {
    140  1.10  briggs 		printf("0x%08x\n", insn->is_ea.ea_absaddr);
    141  1.10  briggs 	} else if (flags & EA_PC_REL) {
    142  1.10  briggs 	    printf("pc@(%d)\n", insn->is_ea.ea_offset);
    143  1.10  briggs 	} else if (flags & EA_IMMED) {
    144  1.10  briggs 	    printf("#0x%08x%08x%08x\n",
    145  1.10  briggs 		       insn->is_ea.ea_immed[0], insn->is_ea.ea_immed[1],
    146  1.10  briggs 		   insn->is_ea.ea_immed[2]);
    147  1.10  briggs 	} else {
    148  1.10  briggs 	    printf("%c%d@\n", regname, insn->is_ea.ea_regnum & 7);
    149   1.1  briggs 	}
    150  1.10  briggs #endif
    151  1.10  briggs 	fpu_load_ea(frame, insn, &insn->is_ea, (char*)buf);
    152   1.1  briggs 
    153  1.10  briggs #if DEBUG_FPE
    154  1.10  briggs 	printf("fpu_emul_fscale: src = %08x%08x%08x, siz = %d\n",
    155  1.10  briggs 	       buf[0], buf[1], buf[2], insn->is_datasize);
    156  1.10  briggs #endif
    157   1.1  briggs 	if (format == FTYPE_LNG) {
    158   1.1  briggs 	    /* nothing */
    159   1.7      is           scale = buf[0];
    160   1.1  briggs 	} else if (format == FTYPE_WRD) {
    161   1.1  briggs 	    /* sign-extend */
    162   1.1  briggs 	    scale = buf[0] & 0xffff;
    163   1.1  briggs 	    if (scale & 0x8000) {
    164   1.1  briggs 		scale |= 0xffff0000;
    165   1.1  briggs 	    }
    166   1.1  briggs 	} else if (format == FTYPE_BYT) {
    167   1.1  briggs 	    /* sign-extend */
    168   1.1  briggs 	    scale = buf[0] & 0xff;
    169   1.1  briggs 	    if (scale & 0x80) {
    170   1.1  briggs 		scale |= 0xffffff00;
    171   1.1  briggs 	    }
    172   1.1  briggs 	} else if (format == FTYPE_DBL || format == FTYPE_SNG ||
    173   1.1  briggs 		   format == FTYPE_EXT) {
    174   1.1  briggs 	    fpu_explode(fe, &fe->fe_f2, format, buf);
    175   1.1  briggs 	    fpu_implode(fe, &fe->fe_f2, FTYPE_LNG, buf);
    176   1.7      is           scale = buf[0];
    177   1.1  briggs 	}
    178   1.1  briggs 	/* make it look like we've got an FP oprand */
    179   1.1  briggs 	fe->fe_f2.fp_class = (buf[0] == 0) ? FPC_ZERO : FPC_NUM;
    180   1.1  briggs     }
    181   1.1  briggs 
    182   1.1  briggs     /* assume there's no exception */
    183   1.1  briggs     sig = 0;
    184   1.1  briggs 
    185   1.1  briggs     /* it's barbaric but we're going to operate directly on
    186   1.1  briggs      * the dst operand's bit pattern */
    187   1.1  briggs     sign = fpregs[regnum * 3] & 0x80000000;
    188   1.1  briggs     exp = (fpregs[regnum * 3] & 0x7fff0000) >> 16;
    189   1.1  briggs     m0 = fpregs[regnum * 3 + 1];
    190   1.1  briggs     m1 = fpregs[regnum * 3 + 2];
    191   1.1  briggs 
    192   1.1  briggs     switch (fe->fe_f2.fp_class) {
    193   1.1  briggs     case FPC_SNAN:
    194   1.1  briggs 	fpsr |= FPSR_SNAN;
    195   1.1  briggs     case FPC_QNAN:
    196   1.1  briggs 	/* dst = NaN */
    197   1.1  briggs 	exp = 0x7fff;
    198   1.1  briggs 	m0 = m1 = 0xffffffff;
    199   1.1  briggs 	break;
    200   1.1  briggs     case FPC_ZERO:
    201   1.1  briggs     case FPC_NUM:
    202   1.1  briggs 	if ((0 < exp && exp < 0x7fff) ||
    203   1.1  briggs 	    (exp == 0 && (m0 | m1) != 0)) {
    204   1.1  briggs 	    /* normal or denormal */
    205   1.1  briggs 	    exp += scale;
    206   1.1  briggs 	    if (exp < 0) {
    207   1.1  briggs 		/* underflow */
    208   1.1  briggs 		u_int grs;	/* guard, round and sticky */
    209   1.1  briggs 
    210   1.1  briggs 		exp = 0;
    211   1.1  briggs 		grs = m1 << (32 + exp);
    212   1.1  briggs 		m1 = m0 << (32 + exp) | m1 >> -exp;
    213   1.1  briggs 		m0 >>= -exp;
    214   1.1  briggs 		if (grs != 0) {
    215   1.1  briggs 		    fpsr |= FPSR_INEX2;
    216   1.1  briggs 
    217   1.1  briggs 		    switch (fe->fe_fpcr & 0x30) {
    218   1.1  briggs 		    case FPCR_MINF:
    219   1.1  briggs 			if (sign != 0) {
    220   1.1  briggs 			    if (++m1 == 0 &&
    221   1.1  briggs 				++m0 == 0) {
    222   1.1  briggs 				m0 = 0x80000000;
    223   1.1  briggs 				exp++;
    224   1.1  briggs 			    }
    225   1.1  briggs 			}
    226   1.1  briggs 			break;
    227   1.1  briggs 		    case FPCR_NEAR:
    228   1.1  briggs 			if (grs == 0x80000000) {
    229   1.1  briggs 			    /* tie */
    230   1.1  briggs 			    if ((m1 & 1) &&
    231   1.1  briggs 				++m1 == 0 &&
    232   1.1  briggs 				++m0 == 0) {
    233   1.1  briggs 				m0 = 0x80000000;
    234   1.1  briggs 				exp++;
    235   1.1  briggs 			    }
    236   1.1  briggs 			} else if (grs & 0x80000000) {
    237   1.1  briggs 			    if (++m1 == 0 &&
    238   1.1  briggs 				++m0 == 0) {
    239   1.1  briggs 				m0 = 0x80000000;
    240   1.1  briggs 				exp++;
    241   1.1  briggs 			    }
    242   1.1  briggs 			}
    243   1.1  briggs 			break;
    244   1.1  briggs 		    case FPCR_PINF:
    245   1.1  briggs 			if (sign == 0) {
    246   1.1  briggs 			    if (++m1 == 0 &&
    247   1.1  briggs 				++m0 == 0) {
    248   1.1  briggs 				m0 = 0x80000000;
    249   1.1  briggs 				exp++;
    250   1.1  briggs 			    }
    251   1.1  briggs 			}
    252   1.1  briggs 			break;
    253   1.1  briggs 		    case FPCR_ZERO:
    254   1.1  briggs 			break;
    255   1.1  briggs 		    }
    256   1.1  briggs 		}
    257   1.1  briggs 		if (exp == 0 && (m0 & 0x80000000) == 0) {
    258   1.1  briggs 		    fpsr |= FPSR_UNFL;
    259   1.1  briggs 		    if ((m0 | m1) == 0) {
    260   1.1  briggs 			fpsr |= FPSR_ZERO;
    261   1.1  briggs 		    }
    262   1.1  briggs 		}
    263   1.1  briggs 	    } else if (exp >= 0x7fff) {
    264   1.1  briggs 		/* overflow --> result = Inf */
    265   1.1  briggs 		/* but first, try to normalize in case it's an unnormalized */
    266   1.1  briggs 		while ((m0 & 0x80000000) == 0) {
    267   1.1  briggs 		    exp--;
    268   1.1  briggs 		    m0 = (m0 << 1) | (m1 >> 31);
    269   1.1  briggs 		    m1 = m1 << 1;
    270   1.1  briggs 		}
    271   1.1  briggs 		/* if it's still too large, then return Inf */
    272   1.1  briggs 		if (exp >= 0x7fff) {
    273   1.1  briggs 		    exp = 0x7fff;
    274   1.1  briggs 		    m0 = m1 = 0;
    275   1.1  briggs 		    fpsr |= FPSR_OVFL | FPSR_INF;
    276   1.1  briggs 		}
    277   1.1  briggs 	    } else if ((m0 & 0x80000000) == 0) {
    278   1.1  briggs 		/*
    279   1.1  briggs 		 * it's a denormal; we try to normalize but
    280   1.1  briggs 		 * result may and may not be a normal.
    281   1.1  briggs 		 */
    282   1.1  briggs 		while (exp > 0 && (m0 & 0x80000000) == 0) {
    283   1.1  briggs 		    exp--;
    284   1.1  briggs 		    m0 = (m0 << 1) | (m1 >> 31);
    285   1.1  briggs 		    m1 = m1 << 1;
    286   1.1  briggs 		}
    287   1.1  briggs 		if ((m0 & 0x80000000) == 0) {
    288   1.1  briggs 		    fpsr |= FPSR_UNFL;
    289   1.1  briggs 		}
    290   1.1  briggs 	    } /* exp in range and mantissa normalized */
    291   1.1  briggs 	} else if (exp == 0 && m0 == 0 && m1 == 0) {
    292   1.1  briggs 	    /* dst is Zero */
    293   1.1  briggs 	    fpsr |= FPSR_ZERO;
    294   1.1  briggs 	} /* else we know exp == 0x7fff */
    295   1.1  briggs 	else if ((m0 | m1) == 0) {
    296   1.1  briggs 	    fpsr |= FPSR_INF;
    297   1.1  briggs 	} else if ((m0 & 0x40000000) == 0) {
    298   1.1  briggs 	    /* a signaling NaN */
    299   1.1  briggs 	    fpsr |= FPSR_NAN | FPSR_SNAN;
    300   1.1  briggs 	} else {
    301   1.1  briggs 	    /* a quiet NaN */
    302   1.1  briggs 	    fpsr |= FPSR_NAN;
    303   1.1  briggs 	}
    304   1.1  briggs 	break;
    305   1.1  briggs     case FPC_INF:
    306   1.1  briggs 	/* dst = NaN */
    307   1.1  briggs 	exp = 0x7fff;
    308   1.1  briggs 	m0 = m1 = 0xffffffff;
    309   1.1  briggs 	fpsr |= FPSR_OPERR | FPSR_NAN;
    310   1.1  briggs 	break;
    311   1.1  briggs     default:
    312   1.1  briggs #ifdef DEBUG
    313  1.10  briggs 	panic("fpu_emul_fscale: invalid fp class");
    314   1.1  briggs #endif
    315   1.1  briggs 	break;
    316   1.1  briggs     }
    317   1.1  briggs 
    318   1.1  briggs     /* store the result */
    319   1.1  briggs     fpregs[regnum * 3] = sign | (exp << 16);
    320   1.1  briggs     fpregs[regnum * 3 + 1] = m0;
    321   1.1  briggs     fpregs[regnum * 3 + 2] = m1;
    322   1.1  briggs 
    323   1.1  briggs     if (sign) {
    324   1.1  briggs 	fpsr |= FPSR_NEG;
    325   1.1  briggs     }
    326   1.1  briggs 
    327   1.1  briggs     /* update fpsr according to the result of operation */
    328   1.1  briggs     fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr = fpsr;
    329   1.1  briggs 
    330  1.10  briggs #if DEBUG_FPE
    331  1.10  briggs     printf("fpu_emul_fscale: FPSR = %08x, FPCR = %08x\n",
    332  1.10  briggs 	   fe->fe_fpsr, fe->fe_fpcr);
    333  1.10  briggs #endif
    334   1.1  briggs 
    335   1.1  briggs     return (fpsr & fe->fe_fpcr & FPSR_EXCP) ? SIGFPE : sig;
    336   1.1  briggs }
    337