Home | History | Annotate | Line # | Download | only in fpe
fpu_fscale.c revision 1.13
      1  1.13     dsl /*	$NetBSD: fpu_fscale.c,v 1.13 2009/03/14 15:36:09 dsl 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.13     dsl __KERNEL_RCSID(0, "$NetBSD: fpu_fscale.c,v 1.13 2009/03/14 15:36:09 dsl 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.13     dsl fpu_emul_fscale(struct fpemu *fe, struct instruction *insn)
     52   1.1  briggs {
     53   1.1  briggs     struct frame *frame;
     54   1.1  briggs     u_int *fpregs;
     55   1.1  briggs     int word1, sig;
     56   1.1  briggs     int regnum, format;
     57   1.1  briggs     int scale, sign, exp;
     58   1.1  briggs     u_int m0, m1;
     59   1.1  briggs     u_int buf[3], fpsr;
     60  1.10  briggs #if DEBUG_FPE
     61   1.1  briggs     int flags;
     62   1.1  briggs     char regname;
     63  1.10  briggs #endif
     64   1.1  briggs 
     65   1.4     leo     scale = sig = 0;
     66   1.1  briggs     frame = fe->fe_frame;
     67   1.1  briggs     fpregs = &(fe->fe_fpframe->fpf_regs[0]);
     68   1.1  briggs     /* clear all exceptions and conditions */
     69   1.1  briggs     fpsr = fe->fe_fpsr & ~FPSR_EXCP & ~FPSR_CCB;
     70  1.10  briggs #if DEBUG_FPE
     71  1.10  briggs     printf("fpu_emul_fscale: FPSR = %08x, FPCR = %08x\n", fpsr, fe->fe_fpcr);
     72  1.10  briggs #endif
     73   1.1  briggs 
     74   1.1  briggs     word1 = insn->is_word1;
     75   1.1  briggs     format = (word1 >> 10) & 7;
     76   1.1  briggs     regnum = (word1 >> 7) & 7;
     77   1.1  briggs 
     78   1.1  briggs     fe->fe_fpcr &= FPCR_ROUND;
     79   1.1  briggs     fe->fe_fpcr |= FPCR_ZERO;
     80   1.1  briggs 
     81   1.1  briggs     /* get the source operand */
     82   1.1  briggs     if ((word1 & 0x4000) == 0) {
     83  1.10  briggs #if DEBUG_FPE
     84  1.10  briggs 	printf("fpu_emul_fscale: FP%d op FP%d => FP%d\n",
     85  1.10  briggs 	       format, regnum, regnum);
     86   1.1  briggs 	/* the operand is an FP reg */
     87  1.10  briggs 	printf("fpu_emul_scale: src opr FP%d=%08x%08x%08x\n",
     88  1.10  briggs 	       format, fpregs[format*3], fpregs[format*3+1],
     89  1.10  briggs 	       fpregs[format*3+2]);
     90  1.10  briggs #endif
     91   1.1  briggs 	fpu_explode(fe, &fe->fe_f2, FTYPE_EXT, &fpregs[format * 3]);
     92   1.1  briggs 	fpu_implode(fe, &fe->fe_f2, FTYPE_LNG, buf);
     93   1.7      is       scale = buf[0];
     94   1.1  briggs     } else {
     95   1.1  briggs 	/* the operand is in memory */
     96   1.1  briggs 	if (format == FTYPE_DBL) {
     97   1.1  briggs 	    insn->is_datasize = 8;
     98   1.1  briggs 	} else if (format == FTYPE_SNG || format == FTYPE_LNG) {
     99   1.1  briggs 	    insn->is_datasize = 4;
    100   1.1  briggs 	} else if (format == FTYPE_WRD) {
    101   1.1  briggs 	    insn->is_datasize = 2;
    102   1.1  briggs 	} else if (format == FTYPE_BYT) {
    103   1.1  briggs 	    insn->is_datasize = 1;
    104   1.1  briggs 	} else if (format == FTYPE_EXT) {
    105   1.1  briggs 	    insn->is_datasize = 12;
    106   1.1  briggs 	} else {
    107   1.1  briggs 	    /* invalid or unsupported operand format */
    108   1.1  briggs 	    sig = SIGFPE;
    109   1.1  briggs 	    return sig;
    110   1.1  briggs 	}
    111   1.1  briggs 
    112   1.1  briggs 	/* Get effective address. (modreg=opcode&077) */
    113  1.10  briggs 	sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode);
    114   1.1  briggs 	if (sig) {
    115  1.10  briggs #if DEBUG_FPE
    116  1.10  briggs 	    printf("fpu_emul_fscale: error in decode_ea\n");
    117  1.10  briggs #endif
    118   1.1  briggs 	    return sig;
    119   1.1  briggs 	}
    120   1.1  briggs 
    121  1.10  briggs #if DEBUG_FPE
    122  1.10  briggs 	printf("fpu_emul_fscale: addr mode = ");
    123  1.10  briggs 	flags = insn->is_ea.ea_flags;
    124  1.10  briggs 	regname = (insn->is_ea.ea_regnum & 8) ? 'a' : 'd';
    125  1.10  briggs 
    126  1.10  briggs 	if (flags & EA_DIRECT) {
    127  1.10  briggs 	    printf("%c%d\n", regname, insn->is_ea.ea_regnum & 7);
    128  1.10  briggs 	} else if (flags & EA_PREDECR) {
    129  1.10  briggs 	    printf("%c%d@-\n", regname, insn->is_ea.ea_regnum & 7);
    130  1.10  briggs 	} else if (flags & EA_POSTINCR) {
    131  1.10  briggs 		printf("%c%d@+\n", regname, insn->is_ea.ea_regnum & 7);
    132  1.10  briggs 	} else if (flags & EA_OFFSET) {
    133  1.10  briggs 	    printf("%c%d@(%d)\n", regname, insn->is_ea.ea_regnum & 7,
    134  1.10  briggs 		   insn->is_ea.ea_offset);
    135  1.10  briggs 	} else if (flags & EA_INDEXED) {
    136  1.10  briggs 	    printf("%c%d@(...)\n", regname, insn->is_ea.ea_regnum & 7);
    137  1.10  briggs 	} else if (flags & EA_ABS) {
    138  1.10  briggs 		printf("0x%08x\n", insn->is_ea.ea_absaddr);
    139  1.10  briggs 	} else if (flags & EA_PC_REL) {
    140  1.10  briggs 	    printf("pc@(%d)\n", insn->is_ea.ea_offset);
    141  1.10  briggs 	} else if (flags & EA_IMMED) {
    142  1.10  briggs 	    printf("#0x%08x%08x%08x\n",
    143  1.10  briggs 		       insn->is_ea.ea_immed[0], insn->is_ea.ea_immed[1],
    144  1.10  briggs 		   insn->is_ea.ea_immed[2]);
    145  1.10  briggs 	} else {
    146  1.10  briggs 	    printf("%c%d@\n", regname, insn->is_ea.ea_regnum & 7);
    147   1.1  briggs 	}
    148  1.10  briggs #endif
    149  1.10  briggs 	fpu_load_ea(frame, insn, &insn->is_ea, (char*)buf);
    150   1.1  briggs 
    151  1.10  briggs #if DEBUG_FPE
    152  1.10  briggs 	printf("fpu_emul_fscale: src = %08x%08x%08x, siz = %d\n",
    153  1.10  briggs 	       buf[0], buf[1], buf[2], insn->is_datasize);
    154  1.10  briggs #endif
    155   1.1  briggs 	if (format == FTYPE_LNG) {
    156   1.1  briggs 	    /* nothing */
    157   1.7      is           scale = buf[0];
    158   1.1  briggs 	} else if (format == FTYPE_WRD) {
    159   1.1  briggs 	    /* sign-extend */
    160   1.1  briggs 	    scale = buf[0] & 0xffff;
    161   1.1  briggs 	    if (scale & 0x8000) {
    162   1.1  briggs 		scale |= 0xffff0000;
    163   1.1  briggs 	    }
    164   1.1  briggs 	} else if (format == FTYPE_BYT) {
    165   1.1  briggs 	    /* sign-extend */
    166   1.1  briggs 	    scale = buf[0] & 0xff;
    167   1.1  briggs 	    if (scale & 0x80) {
    168   1.1  briggs 		scale |= 0xffffff00;
    169   1.1  briggs 	    }
    170   1.1  briggs 	} else if (format == FTYPE_DBL || format == FTYPE_SNG ||
    171   1.1  briggs 		   format == FTYPE_EXT) {
    172   1.1  briggs 	    fpu_explode(fe, &fe->fe_f2, format, buf);
    173   1.1  briggs 	    fpu_implode(fe, &fe->fe_f2, FTYPE_LNG, buf);
    174   1.7      is           scale = buf[0];
    175   1.1  briggs 	}
    176   1.1  briggs 	/* make it look like we've got an FP oprand */
    177   1.1  briggs 	fe->fe_f2.fp_class = (buf[0] == 0) ? FPC_ZERO : FPC_NUM;
    178   1.1  briggs     }
    179   1.1  briggs 
    180   1.1  briggs     /* assume there's no exception */
    181   1.1  briggs     sig = 0;
    182   1.1  briggs 
    183   1.1  briggs     /* it's barbaric but we're going to operate directly on
    184   1.1  briggs      * the dst operand's bit pattern */
    185   1.1  briggs     sign = fpregs[regnum * 3] & 0x80000000;
    186   1.1  briggs     exp = (fpregs[regnum * 3] & 0x7fff0000) >> 16;
    187   1.1  briggs     m0 = fpregs[regnum * 3 + 1];
    188   1.1  briggs     m1 = fpregs[regnum * 3 + 2];
    189   1.1  briggs 
    190   1.1  briggs     switch (fe->fe_f2.fp_class) {
    191   1.1  briggs     case FPC_SNAN:
    192   1.1  briggs 	fpsr |= FPSR_SNAN;
    193   1.1  briggs     case FPC_QNAN:
    194   1.1  briggs 	/* dst = NaN */
    195   1.1  briggs 	exp = 0x7fff;
    196   1.1  briggs 	m0 = m1 = 0xffffffff;
    197   1.1  briggs 	break;
    198   1.1  briggs     case FPC_ZERO:
    199   1.1  briggs     case FPC_NUM:
    200   1.1  briggs 	if ((0 < exp && exp < 0x7fff) ||
    201   1.1  briggs 	    (exp == 0 && (m0 | m1) != 0)) {
    202   1.1  briggs 	    /* normal or denormal */
    203   1.1  briggs 	    exp += scale;
    204   1.1  briggs 	    if (exp < 0) {
    205   1.1  briggs 		/* underflow */
    206   1.1  briggs 		u_int grs;	/* guard, round and sticky */
    207   1.1  briggs 
    208   1.1  briggs 		exp = 0;
    209   1.1  briggs 		grs = m1 << (32 + exp);
    210   1.1  briggs 		m1 = m0 << (32 + exp) | m1 >> -exp;
    211   1.1  briggs 		m0 >>= -exp;
    212   1.1  briggs 		if (grs != 0) {
    213   1.1  briggs 		    fpsr |= FPSR_INEX2;
    214   1.1  briggs 
    215   1.1  briggs 		    switch (fe->fe_fpcr & 0x30) {
    216   1.1  briggs 		    case FPCR_MINF:
    217   1.1  briggs 			if (sign != 0) {
    218   1.1  briggs 			    if (++m1 == 0 &&
    219   1.1  briggs 				++m0 == 0) {
    220   1.1  briggs 				m0 = 0x80000000;
    221   1.1  briggs 				exp++;
    222   1.1  briggs 			    }
    223   1.1  briggs 			}
    224   1.1  briggs 			break;
    225   1.1  briggs 		    case FPCR_NEAR:
    226   1.1  briggs 			if (grs == 0x80000000) {
    227   1.1  briggs 			    /* tie */
    228   1.1  briggs 			    if ((m1 & 1) &&
    229   1.1  briggs 				++m1 == 0 &&
    230   1.1  briggs 				++m0 == 0) {
    231   1.1  briggs 				m0 = 0x80000000;
    232   1.1  briggs 				exp++;
    233   1.1  briggs 			    }
    234   1.1  briggs 			} else if (grs & 0x80000000) {
    235   1.1  briggs 			    if (++m1 == 0 &&
    236   1.1  briggs 				++m0 == 0) {
    237   1.1  briggs 				m0 = 0x80000000;
    238   1.1  briggs 				exp++;
    239   1.1  briggs 			    }
    240   1.1  briggs 			}
    241   1.1  briggs 			break;
    242   1.1  briggs 		    case FPCR_PINF:
    243   1.1  briggs 			if (sign == 0) {
    244   1.1  briggs 			    if (++m1 == 0 &&
    245   1.1  briggs 				++m0 == 0) {
    246   1.1  briggs 				m0 = 0x80000000;
    247   1.1  briggs 				exp++;
    248   1.1  briggs 			    }
    249   1.1  briggs 			}
    250   1.1  briggs 			break;
    251   1.1  briggs 		    case FPCR_ZERO:
    252   1.1  briggs 			break;
    253   1.1  briggs 		    }
    254   1.1  briggs 		}
    255   1.1  briggs 		if (exp == 0 && (m0 & 0x80000000) == 0) {
    256   1.1  briggs 		    fpsr |= FPSR_UNFL;
    257   1.1  briggs 		    if ((m0 | m1) == 0) {
    258   1.1  briggs 			fpsr |= FPSR_ZERO;
    259   1.1  briggs 		    }
    260   1.1  briggs 		}
    261   1.1  briggs 	    } else if (exp >= 0x7fff) {
    262   1.1  briggs 		/* overflow --> result = Inf */
    263   1.1  briggs 		/* but first, try to normalize in case it's an unnormalized */
    264   1.1  briggs 		while ((m0 & 0x80000000) == 0) {
    265   1.1  briggs 		    exp--;
    266   1.1  briggs 		    m0 = (m0 << 1) | (m1 >> 31);
    267   1.1  briggs 		    m1 = m1 << 1;
    268   1.1  briggs 		}
    269   1.1  briggs 		/* if it's still too large, then return Inf */
    270   1.1  briggs 		if (exp >= 0x7fff) {
    271   1.1  briggs 		    exp = 0x7fff;
    272   1.1  briggs 		    m0 = m1 = 0;
    273   1.1  briggs 		    fpsr |= FPSR_OVFL | FPSR_INF;
    274   1.1  briggs 		}
    275   1.1  briggs 	    } else if ((m0 & 0x80000000) == 0) {
    276   1.1  briggs 		/*
    277   1.1  briggs 		 * it's a denormal; we try to normalize but
    278   1.1  briggs 		 * result may and may not be a normal.
    279   1.1  briggs 		 */
    280   1.1  briggs 		while (exp > 0 && (m0 & 0x80000000) == 0) {
    281   1.1  briggs 		    exp--;
    282   1.1  briggs 		    m0 = (m0 << 1) | (m1 >> 31);
    283   1.1  briggs 		    m1 = m1 << 1;
    284   1.1  briggs 		}
    285   1.1  briggs 		if ((m0 & 0x80000000) == 0) {
    286   1.1  briggs 		    fpsr |= FPSR_UNFL;
    287   1.1  briggs 		}
    288   1.1  briggs 	    } /* exp in range and mantissa normalized */
    289   1.1  briggs 	} else if (exp == 0 && m0 == 0 && m1 == 0) {
    290   1.1  briggs 	    /* dst is Zero */
    291   1.1  briggs 	    fpsr |= FPSR_ZERO;
    292   1.1  briggs 	} /* else we know exp == 0x7fff */
    293   1.1  briggs 	else if ((m0 | m1) == 0) {
    294   1.1  briggs 	    fpsr |= FPSR_INF;
    295   1.1  briggs 	} else if ((m0 & 0x40000000) == 0) {
    296   1.1  briggs 	    /* a signaling NaN */
    297   1.1  briggs 	    fpsr |= FPSR_NAN | FPSR_SNAN;
    298   1.1  briggs 	} else {
    299   1.1  briggs 	    /* a quiet NaN */
    300   1.1  briggs 	    fpsr |= FPSR_NAN;
    301   1.1  briggs 	}
    302   1.1  briggs 	break;
    303   1.1  briggs     case FPC_INF:
    304   1.1  briggs 	/* dst = NaN */
    305   1.1  briggs 	exp = 0x7fff;
    306   1.1  briggs 	m0 = m1 = 0xffffffff;
    307   1.1  briggs 	fpsr |= FPSR_OPERR | FPSR_NAN;
    308   1.1  briggs 	break;
    309   1.1  briggs     default:
    310   1.1  briggs #ifdef DEBUG
    311  1.10  briggs 	panic("fpu_emul_fscale: invalid fp class");
    312   1.1  briggs #endif
    313   1.1  briggs 	break;
    314   1.1  briggs     }
    315   1.1  briggs 
    316   1.1  briggs     /* store the result */
    317   1.1  briggs     fpregs[regnum * 3] = sign | (exp << 16);
    318   1.1  briggs     fpregs[regnum * 3 + 1] = m0;
    319   1.1  briggs     fpregs[regnum * 3 + 2] = m1;
    320   1.1  briggs 
    321   1.1  briggs     if (sign) {
    322   1.1  briggs 	fpsr |= FPSR_NEG;
    323   1.1  briggs     }
    324   1.1  briggs 
    325   1.1  briggs     /* update fpsr according to the result of operation */
    326   1.1  briggs     fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr = fpsr;
    327   1.1  briggs 
    328  1.10  briggs #if DEBUG_FPE
    329  1.10  briggs     printf("fpu_emul_fscale: FPSR = %08x, FPCR = %08x\n",
    330  1.10  briggs 	   fe->fe_fpsr, fe->fe_fpcr);
    331  1.10  briggs #endif
    332   1.1  briggs 
    333   1.1  briggs     return (fpsr & fe->fe_fpcr & FPSR_EXCP) ? SIGFPE : sig;
    334   1.1  briggs }
    335