Home | History | Annotate | Line # | Download | only in fpe
fpu_fscale.c revision 1.12.78.1
      1  1.12.78.1    yamt /*	$NetBSD: fpu_fscale.c,v 1.12.78.1 2009/05/04 08:11:25 yamt 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.12.78.1    yamt __KERNEL_RCSID(0, "$NetBSD: fpu_fscale.c,v 1.12.78.1 2009/05/04 08:11:25 yamt 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.12.78.1    yamt 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