The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/i386/math_emulate.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * linux/kernel/math/math_emulate.c
    3  *
    4  * (C) 1991 Linus Torvalds
    5  *
    6  * [expediant "port" of linux 8087 emulator to 386BSD, with apologies -wfj]
    7  *
    8  *      from: 386BSD 0.1
    9  * $FreeBSD: releng/5.1/sys/i386/i386/math_emulate.c 98482 2002-06-20 07:23:08Z peter $
   10  */
   11 
   12 /*
   13  * Limited emulation 27.12.91 - mostly loads/stores, which gcc wants
   14  * even for soft-float, unless you use bruce evans' patches. The patches
   15  * are great, but they have to be re-applied for every version, and the
   16  * library is different for soft-float and 80387. So emulation is more
   17  * practical, even though it's slower.
   18  *
   19  * 28.12.91 - loads/stores work, even BCD. I'll have to start thinking
   20  * about add/sub/mul/div. Urgel. I should find some good source, but I'll
   21  * just fake up something.
   22  *
   23  * 30.12.91 - add/sub/mul/div/com seem to work mostly. I should really
   24  * test every possible combination.
   25  */
   26 
   27 /*
   28  * This file is full of ugly macros etc: one problem was that gcc simply
   29  * didn't want to make the structures as they should be: it has to try to
   30  * align them. Sickening code, but at least I've hidden the ugly things
   31  * in this one file: the other files don't need to know about these things.
   32  *
   33  * The other files also don't care about ST(x) etc - they just get addresses
   34  * to 80-bit temporary reals, and do with them as they please. I wanted to
   35  * hide most of the 387-specific things here.
   36  */
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/kernel.h>
   41 #include <sys/lock.h>
   42 #include <sys/proc.h>
   43 #include <sys/user.h>
   44 
   45 #include <machine/frame.h>
   46 #include <machine/reg.h>
   47 
   48 #include <vm/vm.h>
   49 #include <vm/pmap.h>
   50 #include <vm/vm_map.h>
   51 
   52 #define __ALIGNED_TEMP_REAL 1
   53 #include <i386/i386/math_emu.h>
   54 
   55 #define bswapw(x) __asm__("xchgb %%al,%%ah":"+a" ((short)(x)))
   56 #define ST(x) (*__st((x)))
   57 #define PST(x) ((const temp_real *) __st((x)))
   58 #define math_abort(tfp, signo) tfp->tf_eip = oldeip; return (signo);
   59 
   60 /*
   61  * We don't want these inlined - it gets too messy in the machine-code.
   62  */
   63 static void fpop(void);
   64 static void fpush(void);
   65 static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b);
   66 static temp_real_unaligned * __st(int i);
   67 
   68 static unsigned char
   69 get_fs_byte(char *adr) 
   70         { return(fubyte(adr)); }
   71 
   72 static unsigned short
   73 get_fs_word(unsigned short *adr)
   74         { return(fuword16(adr)); }
   75 
   76 static u_int32_t
   77 get_fs_long(u_int32_t *adr)
   78         { return(fuword(adr)); }
   79 
   80 static void 
   81 put_fs_byte(unsigned char val, char *adr)
   82         { (void)subyte(adr,val); }
   83 
   84 static void 
   85 put_fs_word(unsigned short val, short *adr)
   86         { (void)suword16(adr,val); }
   87 
   88 static void 
   89 put_fs_long(u_long val, u_int32_t *adr)
   90         { (void)suword(adr,val); }
   91 
   92 static int
   93 math_emulate(struct trapframe * info)
   94 {
   95         unsigned short code;
   96         temp_real tmp;
   97         char * address;
   98         u_int32_t oldeip;
   99 
  100         /* ever used fp? */
  101         if ((curthread->td_pcb->pcb_flags & FP_SOFTFP) == 0) {
  102                 curthread->td_pcb->pcb_flags |= FP_SOFTFP;
  103                 I387.cwd = 0x037f;
  104                 I387.swd = 0x0000;
  105                 I387.twd = 0x0000;
  106         }
  107 
  108         if (I387.cwd & I387.swd & 0x3f)
  109                 I387.swd |= 0x8000;
  110         else
  111                 I387.swd &= 0x7fff;
  112         oldeip = info->tf_eip;
  113 /* 0x001f means user code space */
  114         if ((u_short)info->tf_cs != 0x001F) {
  115                 printf("math_emulate: %04x:%08lx\n", (u_short)info->tf_cs,
  116                         (u_long)oldeip);
  117                 panic("?Math emulation needed in kernel?");
  118         }
  119         /* completely ignore an operand-size prefix */
  120         if (get_fs_byte((char *) info->tf_eip) == 0x66)
  121                 info->tf_eip++;
  122         code = get_fs_word((unsigned short *) info->tf_eip);
  123         bswapw(code);
  124         code &= 0x7ff;
  125         I387.fip = oldeip;
  126         *(unsigned short *) &I387.fcs = (u_short) info->tf_cs;
  127         *(1+(unsigned short *) &I387.fcs) = code;
  128         info->tf_eip += 2;
  129         switch (code) {
  130                 case 0x1d0: /* fnop */
  131                         return(0);
  132                 case 0x1d1: case 0x1d2: case 0x1d3:  /* fst to 32-bit mem */
  133                 case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7:
  134                         math_abort(info,SIGILL);
  135                 case 0x1e0: /* fchs */
  136                         ST(0).exponent ^= 0x8000;
  137                         return(0);
  138                 case 0x1e1: /* fabs */
  139                         ST(0).exponent &= 0x7fff;
  140                         return(0);
  141                 case 0x1e2: case 0x1e3:
  142                         math_abort(info,SIGILL);
  143                 case 0x1e4: /* ftst */
  144                         ftst(PST(0));
  145                         return(0);
  146                 case 0x1e5: /* fxam */
  147                         printf("fxam not implemented\n");
  148                         math_abort(info,SIGILL);
  149                 case 0x1e6: case 0x1e7: /* fldenv */
  150                         math_abort(info,SIGILL);
  151                 case 0x1e8: /* fld1 */
  152                         fpush();
  153                         ST(0) = CONST1;
  154                         return(0);
  155                 case 0x1e9: /* fld2t */
  156                         fpush();
  157                         ST(0) = CONSTL2T;
  158                         return(0);
  159                 case 0x1ea: /* fld2e */
  160                         fpush();
  161                         ST(0) = CONSTL2E;
  162                         return(0);
  163                 case 0x1eb: /* fldpi */
  164                         fpush();
  165                         ST(0) = CONSTPI;
  166                         return(0);
  167                 case 0x1ec: /* fldlg2 */
  168                         fpush();
  169                         ST(0) = CONSTLG2;
  170                         return(0);
  171                 case 0x1ed: /* fldln2 */
  172                         fpush();
  173                         ST(0) = CONSTLN2;
  174                         return(0);
  175                 case 0x1ee: /* fldz */
  176                         fpush();
  177                         ST(0) = CONSTZ;
  178                         return(0);
  179                 case 0x1ef:
  180                         math_abort(info,SIGILL);
  181                 case 0x1f0: /* f2xm1 */
  182                 case 0x1f1: /* fyl2x */
  183                 case 0x1f2: /* fptan */
  184                 case 0x1f3: /* fpatan */
  185                 case 0x1f4: /* fxtract */
  186                 case 0x1f5: /* fprem1 */
  187                 case 0x1f6: /* fdecstp */
  188                 case 0x1f7: /* fincstp */
  189                 case 0x1f8: /* fprem */
  190                 case 0x1f9: /* fyl2xp1 */
  191                 case 0x1fa: /* fsqrt */
  192                 case 0x1fb: /* fsincos */
  193                 case 0x1fe: /* fsin */
  194                 case 0x1ff: /* fcos */
  195                         uprintf(
  196                          "math_emulate: instruction %04x not implemented\n",
  197                           code + 0xd800);
  198                         math_abort(info,SIGILL);
  199                 case 0x1fc: /* frndint */
  200                         frndint(PST(0),&tmp);
  201                         real_to_real(&tmp,&ST(0));
  202                         return(0);
  203                 case 0x1fd: /* fscale */
  204                         /* incomplete and totally inadequate -wfj */
  205                         Fscale(PST(0), PST(1), &tmp);
  206                         real_to_real(&tmp,&ST(0));
  207                         return(0);                      /* 19 Sep 92*/
  208                 case 0x2e9: /* ????? */
  209 /* if this should be a fucomp ST(0),ST(1) , it must be a 0x3e9  ATS */
  210                         fucom(PST(1),PST(0));
  211                         fpop(); fpop();
  212                         return(0);
  213                 case 0x3d0: case 0x3d1: /* fist ?? */
  214                         return(0);
  215                 case 0x3e2: /* fclex */
  216                         I387.swd &= 0x7f00;
  217                         return(0);
  218                 case 0x3e3: /* fninit */
  219                         I387.cwd = 0x037f;
  220                         I387.swd = 0x0000;
  221                         I387.twd = 0x0000;
  222                         return(0);
  223                 case 0x3e4:
  224                         return(0);
  225                 case 0x6d9: /* fcompp */
  226                         fcom(PST(1),PST(0));
  227                         fpop(); fpop();
  228                         return(0);
  229                 case 0x7e0: /* fstsw ax */
  230                         *(short *) &info->tf_eax = I387.swd;
  231                         return(0);
  232         }
  233         switch (code >> 3) {
  234                 case 0x18: /* fadd */
  235                         fadd(PST(0),PST(code & 7),&tmp);
  236                         real_to_real(&tmp,&ST(0));
  237                         return(0);
  238                 case 0x19: /* fmul */
  239                         fmul(PST(0),PST(code & 7),&tmp);
  240                         real_to_real(&tmp,&ST(0));
  241                         return(0);
  242                 case 0x1a: /* fcom */
  243                         fcom(PST(code & 7),PST(0));
  244                         return(0);
  245                 case 0x1b: /* fcomp */
  246                         fcom(PST(code & 7),PST(0));
  247                         fpop();
  248                         return(0);
  249                 case 0x1c: /* fsubr */
  250                         real_to_real(&ST(code & 7),&tmp);
  251                         tmp.exponent ^= 0x8000;
  252                         fadd(PST(0),&tmp,&tmp);
  253                         real_to_real(&tmp,&ST(0));
  254                         return(0);
  255                 case 0x1d: /* fsub */
  256                         ST(0).exponent ^= 0x8000;
  257                         fadd(PST(0),PST(code & 7),&tmp);
  258                         real_to_real(&tmp,&ST(0));
  259                         return(0);
  260                 case 0x1e: /* fdivr */
  261                         fdiv(PST(0),PST(code & 7),&tmp);
  262                         real_to_real(&tmp,&ST(0));
  263                         return(0);
  264                 case 0x1f: /* fdiv */
  265                         fdiv(PST(code & 7),PST(0),&tmp);
  266                         real_to_real(&tmp,&ST(0));
  267                         return(0);
  268                 case 0x38: /* fld */
  269                         fpush();
  270                         ST(0) = ST((code & 7)+1);  /* why plus 1 ????? ATS */
  271                         return(0);
  272                 case 0x39: /* fxch */
  273                         fxchg(&ST(0),&ST(code & 7));
  274                         return(0);
  275                 case 0x3b: /*  ??? ??? wrong ???? ATS */
  276                         ST(code & 7) = ST(0);
  277                         fpop();
  278                         return(0);
  279                 case 0x98: /* fadd */
  280                         fadd(PST(0),PST(code & 7),&tmp);
  281                         real_to_real(&tmp,&ST(code & 7));
  282                         return(0);
  283                 case 0x99: /* fmul */
  284                         fmul(PST(0),PST(code & 7),&tmp);
  285                         real_to_real(&tmp,&ST(code & 7));
  286                         return(0);
  287                 case 0x9a: /* ???? , my manual don't list a direction bit
  288 for fcom , ??? ATS */
  289                         fcom(PST(code & 7),PST(0));
  290                         return(0);
  291                 case 0x9b: /* same as above , ATS */
  292                         fcom(PST(code & 7),PST(0));
  293                         fpop();
  294                         return(0);
  295                 case 0x9c: /* fsubr */
  296                         ST(code & 7).exponent ^= 0x8000;
  297                         fadd(PST(0),PST(code & 7),&tmp);
  298                         real_to_real(&tmp,&ST(code & 7));
  299                         return(0);
  300                 case 0x9d: /* fsub */
  301                         real_to_real(&ST(0),&tmp);
  302                         tmp.exponent ^= 0x8000;
  303                         fadd(PST(code & 7),&tmp,&tmp);
  304                         real_to_real(&tmp,&ST(code & 7));
  305                         return(0);
  306                 case 0x9e: /* fdivr */
  307                         fdiv(PST(0),PST(code & 7),&tmp);
  308                         real_to_real(&tmp,&ST(code & 7));
  309                         return(0);
  310                 case 0x9f: /* fdiv */
  311                         fdiv(PST(code & 7),PST(0),&tmp);
  312                         real_to_real(&tmp,&ST(code & 7));
  313                         return(0);
  314                 case 0xb8: /* ffree */
  315                         printf("ffree not implemented\n");
  316                         math_abort(info,SIGILL);
  317                 case 0xb9: /* fstp ???? where is the pop ? ATS */
  318                         fxchg(&ST(0),&ST(code & 7));
  319                         return(0);
  320                 case 0xba: /* fst */
  321                         ST(code & 7) = ST(0);
  322                         return(0);
  323                 case 0xbb: /* ????? encoding of fstp to mem ? ATS */
  324                         ST(code & 7) = ST(0);
  325                         fpop();
  326                         return(0);
  327                 case 0xbc: /* fucom */
  328                         fucom(PST(code & 7),PST(0));
  329                         return(0);
  330                 case 0xbd: /* fucomp */
  331                         fucom(PST(code & 7),PST(0));
  332                         fpop();
  333                         return(0);
  334                 case 0xd8: /* faddp */
  335                         fadd(PST(code & 7),PST(0),&tmp);
  336                         real_to_real(&tmp,&ST(code & 7));
  337                         fpop();
  338                         return(0);
  339                 case 0xd9: /* fmulp */
  340                         fmul(PST(code & 7),PST(0),&tmp);
  341                         real_to_real(&tmp,&ST(code & 7));
  342                         fpop();
  343                         return(0);
  344                 case 0xda: /* ??? encoding of ficom with 16 bit mem ? ATS */
  345                         fcom(PST(code & 7),PST(0));
  346                         fpop();
  347                         return(0);
  348                 case 0xdc: /* fsubrp */
  349                         ST(code & 7).exponent ^= 0x8000;
  350                         fadd(PST(0),PST(code & 7),&tmp);
  351                         real_to_real(&tmp,&ST(code & 7));
  352                         fpop();
  353                         return(0);
  354                 case 0xdd: /* fsubp */
  355                         real_to_real(&ST(0),&tmp);
  356                         tmp.exponent ^= 0x8000;
  357                         fadd(PST(code & 7),&tmp,&tmp);
  358                         real_to_real(&tmp,&ST(code & 7));
  359                         fpop();
  360                         return(0);
  361                 case 0xde: /* fdivrp */
  362                         fdiv(PST(0),PST(code & 7),&tmp);
  363                         real_to_real(&tmp,&ST(code & 7));
  364                         fpop();
  365                         return(0);
  366                 case 0xdf: /* fdivp */
  367                         fdiv(PST(code & 7),PST(0),&tmp);
  368                         real_to_real(&tmp,&ST(code & 7));
  369                         fpop();
  370                         return(0);
  371                 case 0xf8: /* fild 16-bit mem ???? ATS */
  372                         printf("ffree not implemented\n");
  373                         math_abort(info,SIGILL);
  374                         fpop();
  375                         return(0);
  376                 case 0xf9: /*  ????? ATS */
  377                         fxchg(&ST(0),&ST(code & 7));
  378                         return(0);
  379                 case 0xfa: /* fist 16-bit mem ? ATS */
  380                 case 0xfb: /* fistp 16-bit mem ? ATS */
  381                         ST(code & 7) = ST(0);
  382                         fpop();
  383                         return(0);
  384         }
  385         switch ((code>>3) & 0xe7) {
  386                 case 0x22:
  387                         put_short_real(PST(0),info,code);
  388                         return(0);
  389                 case 0x23:
  390                         put_short_real(PST(0),info,code);
  391                         fpop();
  392                         return(0);
  393                 case 0x24:
  394                         address = ea(info,code);
  395                         for (code = 0 ; code < 7 ; code++) {
  396                                 ((int32_t *) & I387)[code] =
  397                                    get_fs_long((u_int32_t *) address);
  398                                 address += 4;
  399                         }
  400                         return(0);
  401                 case 0x25:
  402                         address = ea(info,code);
  403                         *(unsigned short *) &I387.cwd =
  404                                 get_fs_word((unsigned short *) address);
  405                         return(0);
  406                 case 0x26:
  407                         address = ea(info,code);
  408                         /*verify_area(address,28);*/
  409                         for (code = 0 ; code < 7 ; code++) {
  410                                 put_fs_long( ((int32_t *) & I387)[code],
  411                                         (u_int32_t *) address);
  412                                 address += 4;
  413                         }
  414                         return(0);
  415                 case 0x27:
  416                         address = ea(info,code);
  417                         /*verify_area(address,2);*/
  418                         put_fs_word(I387.cwd,(short *) address);
  419                         return(0);
  420                 case 0x62:
  421                         put_long_int(PST(0),info,code);
  422                         return(0);
  423                 case 0x63:
  424                         put_long_int(PST(0),info,code);
  425                         fpop();
  426                         return(0);
  427                 case 0x65:
  428                         fpush();
  429                         get_temp_real(&tmp,info,code);
  430                         real_to_real(&tmp,&ST(0));
  431                         return(0);
  432                 case 0x67:
  433                         put_temp_real(PST(0),info,code);
  434                         fpop();
  435                         return(0);
  436                 case 0xa2:
  437                         put_long_real(PST(0),info,code);
  438                         return(0);
  439                 case 0xa3:
  440                         put_long_real(PST(0),info,code);
  441                         fpop();
  442                         return(0);
  443                 case 0xa4:
  444                         address = ea(info,code);
  445                         for (code = 0 ; code < 27 ; code++) {
  446                                 ((int32_t *) & I387)[code] =
  447                                    get_fs_long((u_int32_t *) address);
  448                                 address += 4;
  449                         }
  450                         return(0);
  451                 case 0xa6:
  452                         address = ea(info,code);
  453                         /*verify_area(address,108);*/
  454                         for (code = 0 ; code < 27 ; code++) {
  455                                 put_fs_long( ((int32_t *) & I387)[code],
  456                                         (u_int32_t *) address);
  457                                 address += 4;
  458                         }
  459                         I387.cwd = 0x037f;
  460                         I387.swd = 0x0000;
  461                         I387.twd = 0x0000;
  462                         return(0);
  463                 case 0xa7:
  464                         address = ea(info,code);
  465                         /*verify_area(address,2);*/
  466                         put_fs_word(I387.swd,(short *) address);
  467                         return(0);
  468                 case 0xe2:
  469                         put_short_int(PST(0),info,code);
  470                         return(0);
  471                 case 0xe3:
  472                         put_short_int(PST(0),info,code);
  473                         fpop();
  474                         return(0);
  475                 case 0xe4:
  476                         fpush();
  477                         get_BCD(&tmp,info,code);
  478                         real_to_real(&tmp,&ST(0));
  479                         return(0);
  480                 case 0xe5:
  481                         fpush();
  482                         get_longlong_int(&tmp,info,code);
  483                         real_to_real(&tmp,&ST(0));
  484                         return(0);
  485                 case 0xe6:
  486                         put_BCD(PST(0),info,code);
  487                         fpop();
  488                         return(0);
  489                 case 0xe7:
  490                         put_longlong_int(PST(0),info,code);
  491                         fpop();
  492                         return(0);
  493         }
  494         switch (code >> 9) {
  495                 case 0:
  496                         get_short_real(&tmp,info,code);
  497                         break;
  498                 case 1:
  499                         get_long_int(&tmp,info,code);
  500                         break;
  501                 case 2:
  502                         get_long_real(&tmp,info,code);
  503                         break;
  504                 case 4:
  505                         get_short_int(&tmp,info,code);
  506         }
  507         switch ((code>>3) & 0x27) {
  508                 case 0:
  509                         fadd(&tmp,PST(0),&tmp);
  510                         real_to_real(&tmp,&ST(0));
  511                         return(0);
  512                 case 1:
  513                         fmul(&tmp,PST(0),&tmp);
  514                         real_to_real(&tmp,&ST(0));
  515                         return(0);
  516                 case 2:
  517                         fcom(&tmp,PST(0));
  518                         return(0);
  519                 case 3:
  520                         fcom(&tmp,PST(0));
  521                         fpop();
  522                         return(0);
  523                 case 4:
  524                         tmp.exponent ^= 0x8000;
  525                         fadd(&tmp,PST(0),&tmp);
  526                         real_to_real(&tmp,&ST(0));
  527                         return(0);
  528                 case 5:
  529                         ST(0).exponent ^= 0x8000;
  530                         fadd(&tmp,PST(0),&tmp);
  531                         real_to_real(&tmp,&ST(0));
  532                         return(0);
  533                 case 6:
  534                         fdiv(PST(0),&tmp,&tmp);
  535                         real_to_real(&tmp,&ST(0));
  536                         return(0);
  537                 case 7:
  538                         fdiv(&tmp,PST(0),&tmp);
  539                         real_to_real(&tmp,&ST(0));
  540                         return(0);
  541         }
  542         if ((code & 0x138) == 0x100) {
  543                         fpush();
  544                         real_to_real(&tmp,&ST(0));
  545                         return(0);
  546         }
  547         printf("Unknown math-insns: %04x:%08x %04x\n",(u_short)info->tf_cs,
  548                 info->tf_eip,code);
  549         math_abort(info,SIGFPE);
  550 }
  551 
  552 static void
  553 fpop(void)
  554 {
  555         u_int32_t tmp;
  556 
  557         tmp = I387.swd & 0xffffc7ffUL;
  558         I387.swd += 0x00000800;
  559         I387.swd &= 0x00003800;
  560         I387.swd |= tmp;
  561 }
  562 
  563 static void
  564 fpush(void)
  565 {
  566         u_int32_t tmp;
  567 
  568         tmp = I387.swd & 0xffffc7ffUL;
  569         I387.swd += 0x00003800;
  570         I387.swd &= 0x00003800;
  571         I387.swd |= tmp;
  572 }
  573 
  574 static void 
  575 fxchg(temp_real_unaligned * a, temp_real_unaligned * b)
  576 {
  577         temp_real_unaligned c;
  578 
  579         c = *a;
  580         *a = *b;
  581         *b = c;
  582 }
  583 
  584 static temp_real_unaligned *
  585 __st(int i)
  586 {
  587         i += I387.swd >> 11;
  588         i &= 7;
  589         return (temp_real_unaligned *) (i*10 + (char *)(I387.st_space));
  590 }
  591 
  592 /*
  593  * linux/kernel/math/ea.c
  594  *
  595  * (C) 1991 Linus Torvalds
  596  */
  597 
  598 /*
  599  * Calculate the effective address.
  600  */
  601 
  602 
  603 static int __regoffset[] = {
  604         tEAX, tECX, tEDX, tEBX, tESP, tEBP, tESI, tEDI
  605 };
  606 
  607 #define REG(x) (((int *)curthread->td_frame)[__regoffset[(x)]])
  608 
  609 static char *
  610 sib(struct trapframe * info, int mod)
  611 {
  612         unsigned char ss,index,base;
  613         int32_t offset = 0;
  614 
  615         base = get_fs_byte((char *) info->tf_eip);
  616         info->tf_eip++;
  617         ss = base >> 6;
  618         index = (base >> 3) & 7;
  619         base &= 7;
  620         if (index == 4)
  621                 offset = 0;
  622         else
  623                 offset = REG(index);
  624         offset <<= ss;
  625         if (mod || base != 5)
  626                 offset += REG(base);
  627         if (mod == 1) {
  628                 offset += (signed char) get_fs_byte((char *) info->tf_eip);
  629                 info->tf_eip++;
  630         } else if (mod == 2 || base == 5) {
  631                 offset += (signed) get_fs_long((u_int32_t *) info->tf_eip);
  632                 info->tf_eip += 4;
  633         }
  634         I387.foo = offset;
  635         I387.fos = 0x17;
  636         return (char *) offset;
  637 }
  638 
  639 static char *
  640 ea(struct trapframe * info, unsigned short code)
  641 {
  642         unsigned char mod,rm;
  643         int32_t * tmp;
  644         int offset = 0;
  645 
  646         mod = (code >> 6) & 3;
  647         rm = code & 7;
  648         if (rm == 4 && mod != 3)
  649                 return sib(info,mod);
  650         if (rm == 5 && !mod) {
  651                 offset = get_fs_long((u_int32_t *) info->tf_eip);
  652                 info->tf_eip += 4;
  653                 I387.foo = offset;
  654                 I387.fos = 0x17;
  655                 return (char *) offset;
  656         }
  657         tmp = (int32_t *) &REG(rm);
  658         switch (mod) {
  659                 case 0: offset = 0; break;
  660                 case 1:
  661                         offset = (signed char) get_fs_byte((char *) info->tf_eip);
  662                         info->tf_eip++;
  663                         break;
  664                 case 2:
  665                         offset = (signed) get_fs_long((u_int32_t *) info->tf_eip);
  666                         info->tf_eip += 4;
  667                         break;
  668 #ifdef notyet
  669                 case 3:
  670                         math_abort(info,1<<(SIGILL-1));
  671 #endif
  672         }
  673         I387.foo = offset;
  674         I387.fos = 0x17;
  675         return offset + (char *) *tmp;
  676 }
  677 /*
  678  * linux/kernel/math/get_put.c
  679  *
  680  * (C) 1991 Linus Torvalds
  681  */
  682 
  683 /*
  684  * This file handles all accesses to user memory: getting and putting
  685  * ints/reals/BCD etc. This is the only part that concerns itself with
  686  * other than temporary real format. All other cals are strictly temp_real.
  687  */
  688 
  689 static void 
  690 get_short_real(temp_real * tmp, struct trapframe * info, unsigned short code)
  691 {
  692         char * addr;
  693         short_real sr;
  694 
  695         addr = ea(info,code);
  696         sr = get_fs_long((u_int32_t *) addr);
  697         short_to_temp(&sr,tmp);
  698 }
  699 
  700 static void
  701 get_long_real(temp_real * tmp, struct trapframe * info, unsigned short code)
  702 {
  703         char * addr;
  704         long_real lr;
  705 
  706         addr = ea(info,code);
  707         lr.a = get_fs_long((u_int32_t *) addr);
  708         lr.b = get_fs_long(1 + (u_int32_t *) addr);
  709         long_to_temp(&lr,tmp);
  710 }
  711 
  712 static void
  713 get_temp_real(temp_real * tmp, struct trapframe * info, unsigned short code)
  714 {
  715         char * addr;
  716 
  717         addr = ea(info,code);
  718         tmp->a = get_fs_long((u_int32_t *) addr);
  719         tmp->b = get_fs_long(1 + (u_int32_t *) addr);
  720         tmp->exponent = get_fs_word(4 + (unsigned short *) addr);
  721 }
  722 
  723 static void
  724 get_short_int(temp_real * tmp, struct trapframe * info, unsigned short code)
  725 {
  726         char * addr;
  727         temp_int ti;
  728 
  729         addr = ea(info,code);
  730         ti.a = (signed short) get_fs_word((unsigned short *) addr);
  731         ti.b = 0;
  732         if ((ti.sign = (ti.a < 0)) != 0)
  733                 ti.a = - ti.a;
  734         int_to_real(&ti,tmp);
  735 }
  736 
  737 static void
  738 get_long_int(temp_real * tmp, struct trapframe * info, unsigned short code)
  739 {
  740         char * addr;
  741         temp_int ti;
  742 
  743         addr = ea(info,code);
  744         ti.a = get_fs_long((u_int32_t *) addr);
  745         ti.b = 0;
  746         if ((ti.sign = (ti.a < 0)) != 0)
  747                 ti.a = - ti.a;
  748         int_to_real(&ti,tmp);
  749 }
  750 
  751 static void 
  752 get_longlong_int(temp_real * tmp, struct trapframe * info, unsigned short code)
  753 {
  754         char * addr;
  755         temp_int ti;
  756 
  757         addr = ea(info,code);
  758         ti.a = get_fs_long((u_int32_t *) addr);
  759         ti.b = get_fs_long(1 + (u_int32_t *) addr);
  760         if ((ti.sign = (ti.b < 0)) != 0)
  761                 __asm__("notl %0 ; notl %1\n\t"
  762                         "addl $1,%0 ; adcl $0,%1"
  763                         :"=r" (ti.a),"=r" (ti.b)
  764                         :"" (ti.a),"1" (ti.b));
  765         int_to_real(&ti,tmp);
  766 }
  767 
  768 #define MUL10(low, high)                                                \
  769         __asm__("addl %0,%0 ; adcl %1,%1\n\t"                           \
  770                 "movl %0,%%ecx ; movl %1,%%ebx\n\t"                     \
  771                 "addl %0,%0 ; adcl %1,%1\n\t"                           \
  772                 "addl %0,%0 ; adcl %1,%1\n\t"                           \
  773                 "addl %%ecx,%0 ; adcl %%ebx,%1"                         \
  774                 : "=a" (low), "=d" (high)                               \
  775                 : "" (low), "1" (high)                                 \
  776                 : "cx", "bx")
  777 
  778 #define ADD64(val, low, high)                                           \
  779         __asm__("addl %4,%0 ; adcl $0,%1"                               \
  780                 :"=r" (low),"=r" (high)                                 \
  781                 :"" (low),"1" (high),"r" ((u_int32_t) (val)))
  782 
  783 static void
  784 get_BCD(temp_real * tmp, struct trapframe * info, unsigned short code)
  785 {
  786         int k;
  787         char * addr;
  788         temp_int i;
  789         unsigned char c;
  790 
  791         addr = ea(info,code);
  792         addr += 9;
  793         i.sign = 0x80 & get_fs_byte(addr--);
  794         i.a = i.b = 0;
  795         for (k = 0; k < 9; k++) {
  796                 c = get_fs_byte(addr--);
  797                 MUL10(i.a, i.b);
  798                 ADD64((c>>4), i.a, i.b);
  799                 MUL10(i.a, i.b);
  800                 ADD64((c&0xf), i.a, i.b);
  801         }
  802         int_to_real(&i,tmp);
  803 }
  804 
  805 static void 
  806 put_short_real(const temp_real * tmp,
  807         struct trapframe * info, unsigned short code)
  808 {
  809         char * addr;
  810         short_real sr;
  811 
  812         addr = ea(info,code);
  813         /*verify_area(addr,4);*/
  814         temp_to_short(tmp,&sr);
  815         put_fs_long(sr,(u_int32_t *) addr);
  816 }
  817 
  818 static void
  819 put_long_real(const temp_real * tmp,
  820         struct trapframe * info, unsigned short code)
  821 {
  822         char * addr;
  823         long_real lr;
  824 
  825         addr = ea(info,code);
  826         /*verify_area(addr,8);*/
  827         temp_to_long(tmp,&lr);
  828         put_fs_long(lr.a, (u_int32_t *) addr);
  829         put_fs_long(lr.b, 1 + (u_int32_t *) addr);
  830 }
  831 
  832 static void
  833 put_temp_real(const temp_real * tmp,
  834         struct trapframe * info, unsigned short code)
  835 {
  836         char * addr;
  837 
  838         addr = ea(info,code);
  839         /*verify_area(addr,10);*/
  840         put_fs_long(tmp->a, (u_int32_t *) addr);
  841         put_fs_long(tmp->b, 1 + (u_int32_t *) addr);
  842         put_fs_word(tmp->exponent, 4 + (short *) addr);
  843 }
  844 
  845 static void
  846 put_short_int(const temp_real * tmp,
  847         struct trapframe * info, unsigned short code)
  848 {
  849         char * addr;
  850         temp_int ti;
  851 
  852         addr = ea(info,code);
  853         real_to_int(tmp,&ti);
  854         /*verify_area(addr,2);*/
  855         if (ti.sign)
  856                 ti.a = -ti.a;
  857         put_fs_word(ti.a,(short *) addr);
  858 }
  859 
  860 static void
  861 put_long_int(const temp_real * tmp,
  862         struct trapframe * info, unsigned short code)
  863 {
  864         char * addr;
  865         temp_int ti;
  866 
  867         addr = ea(info,code);
  868         real_to_int(tmp,&ti);
  869         /*verify_area(addr,4);*/
  870         if (ti.sign)
  871                 ti.a = -ti.a;
  872         put_fs_long(ti.a,(u_int32_t *) addr);
  873 }
  874 
  875 static void
  876 put_longlong_int(const temp_real * tmp,
  877         struct trapframe * info, unsigned short code)
  878 {
  879         char * addr;
  880         temp_int ti;
  881 
  882         addr = ea(info,code);
  883         real_to_int(tmp,&ti);
  884         /*verify_area(addr,8);*/
  885         if (ti.sign)
  886                 __asm__("notl %0 ; notl %1\n\t"
  887                         "addl $1,%0 ; adcl $0,%1"
  888                         :"=r" (ti.a),"=r" (ti.b)
  889                         :"" (ti.a),"1" (ti.b));
  890         put_fs_long(ti.a,(u_int32_t *) addr);
  891         put_fs_long(ti.b,1 + (u_int32_t *) addr);
  892 }
  893 
  894 #define DIV10(low,high,rem)                                             \
  895         __asm__("divl %6 ; xchgl %1,%2 ; divl %6"                       \
  896                 :"=d" (rem),"=a" (low),"=r" (high)                      \
  897                 :"" (0),"1" (high),"2" (low),"c" (10))
  898 
  899 static void
  900 put_BCD(const temp_real * tmp,struct trapframe * info, unsigned short code)
  901 {
  902         int k,rem;
  903         char * addr;
  904         temp_int i;
  905         unsigned char c;
  906 
  907         addr = ea(info,code);
  908         /*verify_area(addr,10);*/
  909         real_to_int(tmp,&i);
  910         if (i.sign)
  911                 put_fs_byte(0x80, addr+9);
  912         else
  913                 put_fs_byte(0, addr+9);
  914         for (k = 0; k < 9; k++) {
  915                 DIV10(i.a,i.b,rem);
  916                 c = rem;
  917                 DIV10(i.a,i.b,rem);
  918                 c += rem<<4;
  919                 put_fs_byte(c,addr++);
  920         }
  921 }
  922 
  923 /*
  924  * linux/kernel/math/mul.c
  925  *
  926  * (C) 1991 Linus Torvalds
  927  */
  928 
  929 /*
  930  * temporary real multiplication routine.
  931  */
  932 
  933 
  934 static void
  935 shift(int * c)
  936 {
  937         __asm__("movl (%0),%%eax ; addl %%eax,(%0)\n\t"
  938                 "movl 4(%0),%%eax ; adcl %%eax,4(%0)\n\t"
  939                 "movl 8(%0),%%eax ; adcl %%eax,8(%0)\n\t"
  940                 "movl 12(%0),%%eax ; adcl %%eax,12(%0)"
  941                 ::"r" (c):"ax");
  942 }
  943 
  944 static void
  945 mul64(const temp_real * a, const temp_real * b, int * c)
  946 {
  947         __asm__("movl (%0),%%eax\n\t"
  948                 "mull (%1)\n\t"
  949                 "movl %%eax,(%2)\n\t"
  950                 "movl %%edx,4(%2)\n\t"
  951                 "movl 4(%0),%%eax\n\t"
  952                 "mull 4(%1)\n\t"
  953                 "movl %%eax,8(%2)\n\t"
  954                 "movl %%edx,12(%2)\n\t"
  955                 "movl (%0),%%eax\n\t"
  956                 "mull 4(%1)\n\t"
  957                 "addl %%eax,4(%2)\n\t"
  958                 "adcl %%edx,8(%2)\n\t"
  959                 "adcl $0,12(%2)\n\t"
  960                 "movl 4(%0),%%eax\n\t"
  961                 "mull (%1)\n\t"
  962                 "addl %%eax,4(%2)\n\t"
  963                 "adcl %%edx,8(%2)\n\t"
  964                 "adcl $0,12(%2)"
  965                 ::"S" (a),"c" (b),"D" (c)
  966                 :"ax","dx");
  967 }
  968 
  969 static void
  970 fmul(const temp_real * src1, const temp_real * src2, temp_real * result)
  971 {
  972         int i,sign;
  973         int tmp[4] = {0,0,0,0};
  974 
  975         sign = (src1->exponent ^ src2->exponent) & 0x8000;
  976         i = (src1->exponent & 0x7fff) + (src2->exponent & 0x7fff) - 16383 + 1;
  977         if (i<0) {
  978                 result->exponent = sign;
  979                 result->a = result->b = 0;
  980                 return;
  981         }
  982         if (i>0x7fff) {
  983                 set_OE();
  984                 return;
  985         }
  986         mul64(src1,src2,tmp);
  987         if (tmp[0] || tmp[1] || tmp[2] || tmp[3])
  988                 while (i && tmp[3] >= 0) {
  989                         i--;
  990                         shift(tmp);
  991                 }
  992         else
  993                 i = 0;
  994         result->exponent = i | sign;
  995         result->a = tmp[2];
  996         result->b = tmp[3];
  997 }
  998 
  999 /*
 1000  * linux/kernel/math/div.c
 1001  *
 1002  * (C) 1991 Linus Torvalds
 1003  */
 1004 
 1005 /*
 1006  * temporary real division routine.
 1007  */
 1008 
 1009 static void 
 1010 shift_left(int * c)
 1011 {
 1012         __asm__ __volatile__("movl (%0),%%eax ; addl %%eax,(%0)\n\t"
 1013                 "movl 4(%0),%%eax ; adcl %%eax,4(%0)\n\t"
 1014                 "movl 8(%0),%%eax ; adcl %%eax,8(%0)\n\t"
 1015                 "movl 12(%0),%%eax ; adcl %%eax,12(%0)"
 1016                 ::"r" (c):"ax");
 1017 }
 1018 
 1019 static void
 1020 shift_right(int * c)
 1021 {
 1022         __asm__("shrl $1,12(%0) ; rcrl $1,8(%0) ; rcrl $1,4(%0) ; rcrl $1,(%0)"
 1023                 ::"r" (c));
 1024 }
 1025 
 1026 static int
 1027 try_sub(int * a, int * b)
 1028 {
 1029         char ok;
 1030 
 1031         __asm__ __volatile__("movl (%1),%%eax ; subl %%eax,(%2)\n\t"
 1032                 "movl 4(%1),%%eax ; sbbl %%eax,4(%2)\n\t"
 1033                 "movl 8(%1),%%eax ; sbbl %%eax,8(%2)\n\t"
 1034                 "movl 12(%1),%%eax ; sbbl %%eax,12(%2)\n\t"
 1035                 "setae %%al":"=a" (ok):"c" (a),"d" (b));
 1036         return ok;
 1037 }
 1038 
 1039 static void
 1040 div64(int * a, int * b, int * c)
 1041 {
 1042         int tmp[4];
 1043         int i;
 1044         unsigned int mask = 0;
 1045 
 1046         c += 4;
 1047         for (i = 0 ; i<64 ; i++) {
 1048                 if (!(mask >>= 1)) {
 1049                         c--;
 1050                         mask = 0x80000000UL;
 1051                 }
 1052                 tmp[0] = a[0]; tmp[1] = a[1];
 1053                 tmp[2] = a[2]; tmp[3] = a[3];
 1054                 if (try_sub(b,tmp)) {
 1055                         *c |= mask;
 1056                         a[0] = tmp[0]; a[1] = tmp[1];
 1057                         a[2] = tmp[2]; a[3] = tmp[3];
 1058                 }
 1059                 shift_right(b);
 1060         }
 1061 }
 1062 
 1063 static void
 1064 fdiv(const temp_real * src1, const temp_real * src2, temp_real * result)
 1065 {
 1066         int i,sign;
 1067         int a[4],b[4],tmp[4] = {0,0,0,0};
 1068 
 1069         sign = (src1->exponent ^ src2->exponent) & 0x8000;
 1070         if (!(src2->a || src2->b)) {
 1071                 set_ZE();
 1072                 return;
 1073         }
 1074         i = (src1->exponent & 0x7fff) - (src2->exponent & 0x7fff) + 16383;
 1075         if (i<0) {
 1076                 set_UE();
 1077                 result->exponent = sign;
 1078                 result->a = result->b = 0;
 1079                 return;
 1080         }
 1081         a[0] = a[1] = 0;
 1082         a[2] = src1->a;
 1083         a[3] = src1->b;
 1084         b[0] = b[1] = 0;
 1085         b[2] = src2->a;
 1086         b[3] = src2->b;
 1087         while (b[3] >= 0) {
 1088                 i++;
 1089                 shift_left(b);
 1090         }
 1091         div64(a,b,tmp);
 1092         if (tmp[0] || tmp[1] || tmp[2] || tmp[3]) {
 1093                 while (i && tmp[3] >= 0) {
 1094                         i--;
 1095                         shift_left(tmp);
 1096                 }
 1097                 if (tmp[3] >= 0)
 1098                         set_DE();
 1099         } else
 1100                 i = 0;
 1101         if (i>0x7fff) {
 1102                 set_OE();
 1103                 return;
 1104         }
 1105         if (tmp[0] || tmp[1])
 1106                 set_PE();
 1107         result->exponent = i | sign;
 1108         result->a = tmp[2];
 1109         result->b = tmp[3];
 1110 }
 1111 
 1112 /*
 1113  * linux/kernel/math/add.c
 1114  *
 1115  * (C) 1991 Linus Torvalds
 1116  */
 1117 
 1118 /*
 1119  * temporary real addition routine.
 1120  *
 1121  * NOTE! These aren't exact: they are only 62 bits wide, and don't do
 1122  * correct rounding. Fast hack. The reason is that we shift right the
 1123  * values by two, in order not to have overflow (1 bit), and to be able
 1124  * to move the sign into the mantissa (1 bit). Much simpler algorithms,
 1125  * and 62 bits (61 really - no rounding) accuracy is usually enough. The
 1126  * only time you should notice anything weird is when adding 64-bit
 1127  * integers together. When using doubles (52 bits accuracy), the
 1128  * 61-bit accuracy never shows at all.
 1129  */
 1130 
 1131 #define NEGINT(a)                                                       \
 1132         __asm__("notl %0 ; notl %1 ; addl $1,%0 ; adcl $0,%1"           \
 1133                 : "=r" (a->a), "=r" (a->b)                              \
 1134                 : "" (a->a), "1" (a->b))
 1135 
 1136 static void signify(temp_real * a)
 1137 {
 1138         a->exponent += 2;
 1139         __asm__("shrdl $2,%1,%0 ; shrl $2,%1"
 1140                 :"=r" (a->a),"=r" (a->b)
 1141                 :"" (a->a),"1" (a->b));
 1142         if (a->exponent < 0)
 1143                 NEGINT(a);
 1144         a->exponent &= 0x7fff;
 1145 }
 1146 
 1147 static void unsignify(temp_real * a)
 1148 {
 1149         if (!(a->a || a->b)) {
 1150                 a->exponent = 0;
 1151                 return;
 1152         }
 1153         a->exponent &= 0x7fff;
 1154         if (a->b < 0) {
 1155                 NEGINT(a);
 1156                 a->exponent |= 0x8000;
 1157         }
 1158         while (a->b >= 0) {
 1159                 a->exponent--;
 1160                 __asm__("addl %0,%0 ; adcl %1,%1"
 1161                         :"=r" (a->a),"=r" (a->b)
 1162                         :"" (a->a),"1" (a->b));
 1163         }
 1164 }
 1165 
 1166 static void
 1167 fadd(const temp_real * src1, const temp_real * src2, temp_real * result)
 1168 {
 1169         temp_real a,b;
 1170         int x1,x2,shift;
 1171 
 1172         x1 = src1->exponent & 0x7fff;
 1173         x2 = src2->exponent & 0x7fff;
 1174         if (x1 > x2) {
 1175                 a = *src1;
 1176                 b = *src2;
 1177                 shift = x1-x2;
 1178         } else {
 1179                 a = *src2;
 1180                 b = *src1;
 1181                 shift = x2-x1;
 1182         }
 1183         if (shift >= 64) {
 1184                 *result = a;
 1185                 return;
 1186         }
 1187         if (shift >= 32) {
 1188                 b.a = b.b;
 1189                 b.b = 0;
 1190                 shift -= 32;
 1191         }
 1192         __asm__("shrdl %4,%1,%0 ; shrl %4,%1"
 1193                 :"=r" (b.a),"=r" (b.b)
 1194                 :"" (b.a),"1" (b.b),"c" ((char) shift));
 1195         signify(&a);
 1196         signify(&b);
 1197         __asm__("addl %4,%0 ; adcl %5,%1"
 1198                 :"=r" (a.a),"=r" (a.b)
 1199                 :"" (a.a),"1" (a.b),"g" (b.a),"g" (b.b));
 1200         unsignify(&a);
 1201         *result = a;
 1202 }
 1203 
 1204 /*
 1205  * linux/kernel/math/compare.c
 1206  *
 1207  * (C) 1991 Linus Torvalds
 1208  */
 1209 
 1210 /*
 1211  * temporary real comparison routines
 1212  */
 1213 
 1214 
 1215 #define clear_Cx() (I387.swd &= ~0x4500)
 1216 
 1217 static void 
 1218 normalize(temp_real * a)
 1219 {
 1220         int i = a->exponent & 0x7fff;
 1221         int sign = a->exponent & 0x8000;
 1222 
 1223         if (!(a->a || a->b)) {
 1224                 a->exponent = 0;
 1225                 return;
 1226         }
 1227         while (i && a->b >= 0) {
 1228                 i--;
 1229                 __asm__("addl %0,%0 ; adcl %1,%1"
 1230                         :"=r" (a->a),"=r" (a->b)
 1231                         :"" (a->a),"1" (a->b));
 1232         }
 1233         a->exponent = i | sign;
 1234 }
 1235 
 1236 static void
 1237 ftst(const temp_real * a)
 1238 {
 1239         temp_real b;
 1240 
 1241         clear_Cx();
 1242         b = *a;
 1243         normalize(&b);
 1244         if (b.a || b.b || b.exponent) {
 1245                 if (b.exponent < 0)
 1246                         set_C0();
 1247         } else
 1248                 set_C3();
 1249 }
 1250 
 1251 static void
 1252 fcom(const temp_real * src1, const temp_real * src2)
 1253 {
 1254         temp_real a;
 1255 
 1256         a = *src1;
 1257         a.exponent ^= 0x8000;
 1258         fadd(&a,src2,&a);
 1259         ftst(&a);
 1260 }
 1261 
 1262 static void
 1263 fucom(const temp_real * src1, const temp_real * src2)
 1264 {
 1265         fcom(src1,src2);
 1266 }
 1267 
 1268 /*
 1269  * linux/kernel/math/convert.c
 1270  *
 1271  * (C) 1991 Linus Torvalds
 1272  */
 1273 
 1274 
 1275 /*
 1276  * NOTE!!! There is some "non-obvious" optimisations in the temp_to_long
 1277  * and temp_to_short conversion routines: don't touch them if you don't
 1278  * know what's going on. They are the adding of one in the rounding: the
 1279  * overflow bit is also used for adding one into the exponent. Thus it
 1280  * looks like the overflow would be incorrectly handled, but due to the
 1281  * way the IEEE numbers work, things are correct.
 1282  *
 1283  * There is no checking for total overflow in the conversions, though (ie
 1284  * if the temp-real number simply won't fit in a short- or long-real.)
 1285  */
 1286 
 1287 static void
 1288 short_to_temp(const short_real * a, temp_real * b)
 1289 {
 1290         if (!(*a & 0x7fffffff)) {
 1291                 b->a = b->b = 0;
 1292                 if (*a)
 1293                         b->exponent = 0x8000;
 1294                 else
 1295                         b->exponent = 0;
 1296                 return;
 1297         }
 1298         b->exponent = ((*a>>23) & 0xff)-127+16383;
 1299         if (*a<0)
 1300                 b->exponent |= 0x8000;
 1301         b->b = (*a<<8) | 0x80000000UL;
 1302         b->a = 0;
 1303 }
 1304 
 1305 static void
 1306 long_to_temp(const long_real * a, temp_real * b)
 1307 {
 1308         if (!a->a && !(a->b & 0x7fffffff)) {
 1309                 b->a = b->b = 0;
 1310                 if (a->b)
 1311                         b->exponent = 0x8000;
 1312                 else
 1313                         b->exponent = 0;
 1314                 return;
 1315         }
 1316         b->exponent = ((a->b >> 20) & 0x7ff)-1023+16383;
 1317         if (a->b<0)
 1318                 b->exponent |= 0x8000;
 1319         b->b = 0x80000000UL | (a->b<<11) | (((u_int32_t)a->a)>>21);
 1320         b->a = a->a<<11;
 1321 }
 1322 
 1323 static void 
 1324 temp_to_short(const temp_real * a, short_real * b)
 1325 {
 1326         if (!(a->exponent & 0x7fff)) {
 1327                 *b = (a->exponent)?0x80000000UL:0;
 1328                 return;
 1329         }
 1330         *b = ((((int32_t) a->exponent)-16383+127) << 23) & 0x7f800000;
 1331         if (a->exponent < 0)
 1332                 *b |= 0x80000000UL;
 1333         *b |= (a->b >> 8) & 0x007fffff;
 1334         switch ((int)ROUNDING) {
 1335                 case ROUND_NEAREST:
 1336                         if ((a->b & 0xff) > 0x80)
 1337                                 ++*b;
 1338                         break;
 1339                 case ROUND_DOWN:
 1340                         if ((a->exponent & 0x8000) && (a->b & 0xff))
 1341                                 ++*b;
 1342                         break;
 1343                 case ROUND_UP:
 1344                         if (!(a->exponent & 0x8000) && (a->b & 0xff))
 1345                                 ++*b;
 1346                         break;
 1347         }
 1348 }
 1349 
 1350 static void
 1351 temp_to_long(const temp_real * a, long_real * b)
 1352 {
 1353         if (!(a->exponent & 0x7fff)) {
 1354                 b->a = 0;
 1355                 b->b = (a->exponent)?0x80000000UL:0;
 1356                 return;
 1357         }
 1358         b->b = (((0x7fff & (int32_t) a->exponent)-16383+1023) << 20) &
 1359             0x7ff00000;
 1360         if (a->exponent < 0)
 1361                 b->b |= 0x80000000UL;
 1362         b->b |= (a->b >> 11) & 0x000fffff;
 1363         b->a = a->b << 21;
 1364         b->a |= (a->a >> 11) & 0x001fffff;
 1365         switch ((int)ROUNDING) {
 1366                 case ROUND_NEAREST:
 1367                         if ((a->a & 0x7ff) > 0x400)
 1368                                 __asm__("addl $1,%0 ; adcl $0,%1"
 1369                                         :"=r" (b->a),"=r" (b->b)
 1370                                         :"" (b->a),"1" (b->b));
 1371                         break;
 1372                 case ROUND_DOWN:
 1373                         if ((a->exponent & 0x8000) && (a->b & 0xff))
 1374                                 __asm__("addl $1,%0 ; adcl $0,%1"
 1375                                         :"=r" (b->a),"=r" (b->b)
 1376                                         :"" (b->a),"1" (b->b));
 1377                         break;
 1378                 case ROUND_UP:
 1379                         if (!(a->exponent & 0x8000) && (a->b & 0xff))
 1380                                 __asm__("addl $1,%0 ; adcl $0,%1"
 1381                                         :"=r" (b->a),"=r" (b->b)
 1382                                         :"" (b->a),"1" (b->b));
 1383                         break;
 1384         }
 1385 }
 1386 
 1387 static void 
 1388 frndint(const temp_real * a, temp_real * b)
 1389 {
 1390         int shift =  16383 + 63 - (a->exponent & 0x7fff);
 1391         u_int32_t underflow;
 1392 
 1393         if ((shift < 0) || (shift == 16383+63)) {
 1394                 *b = *a;
 1395                 return;
 1396         }
 1397         b->a = b->b = underflow = 0;
 1398         b->exponent = a->exponent;
 1399         if (shift < 32) {
 1400                 b->b = a->b; b->a = a->a;
 1401         } else if (shift < 64) {
 1402                 b->a = a->b; underflow = a->a;
 1403                 shift -= 32;
 1404                 b->exponent += 32;
 1405         } else if (shift < 96) {
 1406                 underflow = a->b;
 1407                 shift -= 64;
 1408                 b->exponent += 64;
 1409         } else {
 1410                 underflow = 1;
 1411                 shift = 0;
 1412         }
 1413         b->exponent += shift;
 1414         __asm__("shrdl %2,%1,%0"
 1415                 :"=r" (underflow),"=r" (b->a)
 1416                 :"c" ((char) shift),"" (underflow),"1" (b->a));
 1417         __asm__("shrdl %2,%1,%0"
 1418                 :"=r" (b->a),"=r" (b->b)
 1419                 :"c" ((char) shift),"" (b->a),"1" (b->b));
 1420         __asm__("shrl %1,%0"
 1421                 :"=r" (b->b)
 1422                 :"c" ((char) shift),"" (b->b));
 1423         switch ((int)ROUNDING) {
 1424                 case ROUND_NEAREST:
 1425                         __asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1"
 1426                                 :"=r" (b->a),"=r" (b->b)
 1427                                 :"" (b->a),"1" (b->b)
 1428                                 ,"r" (0x7fffffff + (b->a & 1))
 1429                                 ,"m" (*&underflow));
 1430                         break;
 1431                 case ROUND_UP:
 1432                         if ((b->exponent >= 0) && underflow)
 1433                                 __asm__("addl $1,%0 ; adcl $0,%1"
 1434                                         :"=r" (b->a),"=r" (b->b)
 1435                                         :"" (b->a),"1" (b->b));
 1436                         break;
 1437                 case ROUND_DOWN:
 1438                         if ((b->exponent < 0) && underflow)
 1439                                 __asm__("addl $1,%0 ; adcl $0,%1"
 1440                                         :"=r" (b->a),"=r" (b->b)
 1441                                         :"" (b->a),"1" (b->b));
 1442                         break;
 1443         }
 1444         if (b->a || b->b)
 1445                 while (b->b >= 0) {
 1446                         b->exponent--;
 1447                         __asm__("addl %0,%0 ; adcl %1,%1"
 1448                                 :"=r" (b->a),"=r" (b->b)
 1449                                 :"" (b->a),"1" (b->b));
 1450                 }
 1451         else
 1452                 b->exponent = 0;
 1453 }
 1454 
 1455 static void
 1456 Fscale(const temp_real *a, const temp_real *b, temp_real *c)
 1457 {
 1458         temp_int ti;
 1459 
 1460         *c = *a;
 1461         if(!c->a && !c->b) {                            /* 19 Sep 92*/
 1462                 c->exponent = 0;
 1463                 return;
 1464         }
 1465         real_to_int(b, &ti);
 1466         if(ti.sign)
 1467                 c->exponent -= ti.a;
 1468         else
 1469                 c->exponent += ti.a;
 1470 }
 1471 
 1472 static void
 1473 real_to_int(const temp_real * a, temp_int * b)
 1474 {
 1475         int shift =  16383 + 63 - (a->exponent & 0x7fff);
 1476         u_int32_t underflow;
 1477 
 1478         b->a = b->b = underflow = 0;
 1479         b->sign = (a->exponent < 0);
 1480         if (shift < 0) {
 1481                 set_OE();
 1482                 return;
 1483         }
 1484         if (shift < 32) {
 1485                 b->b = a->b; b->a = a->a;
 1486         } else if (shift < 64) {
 1487                 b->a = a->b; underflow = a->a;
 1488                 shift -= 32;
 1489         } else if (shift < 96) {
 1490                 underflow = a->b;
 1491                 shift -= 64;
 1492         } else {
 1493                 underflow = 1;
 1494                 shift = 0;
 1495         }
 1496         __asm__("shrdl %2,%1,%0"
 1497                 :"=r" (underflow),"=r" (b->a)
 1498                 :"c" ((char) shift),"" (underflow),"1" (b->a));
 1499         __asm__("shrdl %2,%1,%0"
 1500                 :"=r" (b->a),"=r" (b->b)
 1501                 :"c" ((char) shift),"" (b->a),"1" (b->b));
 1502         __asm__("shrl %1,%0"
 1503                 :"=r" (b->b)
 1504                 :"c" ((char) shift),"" (b->b));
 1505         switch ((int)ROUNDING) {
 1506                 case ROUND_NEAREST:
 1507                         __asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1"
 1508                                 :"=r" (b->a),"=r" (b->b)
 1509                                 :"" (b->a),"1" (b->b)
 1510                                 ,"r" (0x7fffffff + (b->a & 1))
 1511                                 ,"m" (*&underflow));
 1512                         break;
 1513                 case ROUND_UP:
 1514                         if (!b->sign && underflow)
 1515                                 __asm__("addl $1,%0 ; adcl $0,%1"
 1516                                         :"=r" (b->a),"=r" (b->b)
 1517                                         :"" (b->a),"1" (b->b));
 1518                         break;
 1519                 case ROUND_DOWN:
 1520                         if (b->sign && underflow)
 1521                                 __asm__("addl $1,%0 ; adcl $0,%1"
 1522                                         :"=r" (b->a),"=r" (b->b)
 1523                                         :"" (b->a),"1" (b->b));
 1524                         break;
 1525         }
 1526 }
 1527 
 1528 static void
 1529 int_to_real(const temp_int * a, temp_real * b)
 1530 {
 1531         b->a = a->a;
 1532         b->b = a->b;
 1533         if (b->a || b->b)
 1534                 b->exponent = 16383 + 63 + (a->sign? 0x8000:0);
 1535         else {
 1536                 b->exponent = 0;
 1537                 return;
 1538         }
 1539         while (b->b >= 0) {
 1540                 b->exponent--;
 1541                 __asm__("addl %0,%0 ; adcl %1,%1"
 1542                         :"=r" (b->a),"=r" (b->b)
 1543                         :"" (b->a),"1" (b->b));
 1544         }
 1545 }
 1546 
 1547 static int
 1548 fpu_modevent(module_t mod, int type, void *unused)
 1549 {
 1550         switch (type) {
 1551         case MOD_LOAD:
 1552                 if (pmath_emulate) {
 1553                         printf("Another Math emulator already present\n");
 1554                         return EBUSY;
 1555                 }
 1556                 pmath_emulate = math_emulate;
 1557                 if (bootverbose)
 1558                         printf("Math emulator present\n");
 1559                 break;
 1560         case MOD_UNLOAD:
 1561                 if (pmath_emulate != math_emulate) {
 1562                         printf("Cannot unload another math emulator\n");
 1563                         return EACCES;
 1564                 }
 1565                 pmath_emulate = 0;
 1566                 if (bootverbose)
 1567                         printf("Math emulator unloaded\n");
 1568                 break;
 1569         default:
 1570                 break;
 1571         }
 1572         return 0;
 1573 }
 1574 static moduledata_t fpumod = {
 1575         "fpu",
 1576         fpu_modevent,
 1577         0
 1578 };
 1579 DECLARE_MODULE(fpu, fpumod, SI_SUB_DRIVERS, SI_ORDER_ANY);

Cache object: c7da40781fa7eeb469d47e67483e174b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.