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

Cache object: a3c3250ca2723f4af9f160be7dda59c1


[ 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.