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

Cache object: 33b1c5d55351c34b3bff87fea2ed0840


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