2 * linux/kernel/math/math_emulate.c
4 * (C) 1991 Linus Torvalds
6 * [expediant "port" of linux 8087 emulator to 386BSD, with apologies -wfj]
9 * $FreeBSD: src/sys/i386/i386/math_emulate.c,v 1.35 1999/08/28 00:43:47 peter Exp $
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.
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.
23 * 30.12.91 - add/sub/mul/div/com seem to work mostly. I should really
24 * test every possible combination.
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.
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.
38 #include <sys/param.h>
39 #include <sys/systm.h>
41 #include <machine/frame.h>
42 #include <machine/reg.h>
45 #include <sys/kernel.h>
50 #include <vm/vm_map.h>
53 #define __ALIGNED_TEMP_REAL 1
54 #include <i386/i386/math_emu.h>
56 #define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((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);
62 * We don't want these inlined - it gets too messy in the machine-code.
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);
70 get_fs_byte(char *adr)
71 { return(fubyte(adr)); }
74 get_fs_word(unsigned short *adr)
75 { return(fuword(adr)); }
78 get_fs_long(u_int32_t *adr)
79 { return(fuword(adr)); }
82 put_fs_byte(unsigned char val, char *adr)
83 { (void)subyte(adr,val); }
86 put_fs_word(unsigned short val, short *adr)
87 { (void)susword(adr,val); }
90 put_fs_long(u_long val, u_int32_t *adr)
91 { (void)suword(adr,val); }
94 math_emulate(struct trapframe * info)
102 if ((((struct pcb *)curproc->p_addr)->pcb_flags & FP_SOFTFP) == 0) {
103 ((struct pcb *)curproc->p_addr)->pcb_flags |= FP_SOFTFP;
109 if (I387.cwd & I387.swd & 0x3f)
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,
118 panic("?Math emulation needed in kernel?");
120 /* completely ignore an operand-size prefix */
121 if (get_fs_byte((char *) info->tf_eip) == 0x66)
123 code = get_fs_word((unsigned short *) info->tf_eip);
127 *(unsigned short *) &I387.fcs = (u_short) info->tf_cs;
128 *(1+(unsigned short *) &I387.fcs) = code;
131 case 0x1d0: /* fnop */
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;
139 case 0x1e1: /* fabs */
140 ST(0).exponent &= 0x7fff;
142 case 0x1e2: case 0x1e3:
143 math_abort(info,SIGILL);
144 case 0x1e4: /* ftst */
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 */
156 case 0x1e9: /* fld2t */
160 case 0x1ea: /* fld2e */
164 case 0x1eb: /* fldpi */
168 case 0x1ec: /* fldlg2 */
172 case 0x1ed: /* fldln2 */
176 case 0x1ee: /* fldz */
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 */
197 "math_emulate: instruction %04x not implemented\n",
199 math_abort(info,SIGILL);
200 case 0x1fc: /* frndint */
201 frndint(PST(0),&tmp);
202 real_to_real(&tmp,&ST(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));
214 case 0x3d0: case 0x3d1: /* fist ?? */
216 case 0x3e2: /* fclex */
219 case 0x3e3: /* fninit */
226 case 0x6d9: /* fcompp */
230 case 0x7e0: /* fstsw ax */
231 *(short *) &info->tf_eax = I387.swd;
235 case 0x18: /* fadd */
236 fadd(PST(0),PST(code & 7),&tmp);
237 real_to_real(&tmp,&ST(0));
239 case 0x19: /* fmul */
240 fmul(PST(0),PST(code & 7),&tmp);
241 real_to_real(&tmp,&ST(0));
243 case 0x1a: /* fcom */
244 fcom(PST(code & 7),PST(0));
246 case 0x1b: /* fcomp */
247 fcom(PST(code & 7),PST(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));
256 case 0x1d: /* fsub */
257 ST(0).exponent ^= 0x8000;
258 fadd(PST(0),PST(code & 7),&tmp);
259 real_to_real(&tmp,&ST(0));
261 case 0x1e: /* fdivr */
262 fdiv(PST(0),PST(code & 7),&tmp);
263 real_to_real(&tmp,&ST(0));
265 case 0x1f: /* fdiv */
266 fdiv(PST(code & 7),PST(0),&tmp);
267 real_to_real(&tmp,&ST(0));
271 ST(0) = ST((code & 7)+1); /* why plus 1 ????? ATS */
273 case 0x39: /* fxch */
274 fxchg(&ST(0),&ST(code & 7));
276 case 0x3b: /* ??? ??? wrong ???? ATS */
277 ST(code & 7) = ST(0);
280 case 0x98: /* fadd */
281 fadd(PST(0),PST(code & 7),&tmp);
282 real_to_real(&tmp,&ST(code & 7));
284 case 0x99: /* fmul */
285 fmul(PST(0),PST(code & 7),&tmp);
286 real_to_real(&tmp,&ST(code & 7));
288 case 0x9a: /* ???? , my manual don't list a direction bit
289 for fcom , ??? ATS */
290 fcom(PST(code & 7),PST(0));
292 case 0x9b: /* same as above , ATS */
293 fcom(PST(code & 7),PST(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));
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));
307 case 0x9e: /* fdivr */
308 fdiv(PST(0),PST(code & 7),&tmp);
309 real_to_real(&tmp,&ST(code & 7));
311 case 0x9f: /* fdiv */
312 fdiv(PST(code & 7),PST(0),&tmp);
313 real_to_real(&tmp,&ST(code & 7));
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));
322 ST(code & 7) = ST(0);
324 case 0xbb: /* ????? encoding of fstp to mem ? ATS */
325 ST(code & 7) = ST(0);
328 case 0xbc: /* fucom */
329 fucom(PST(code & 7),PST(0));
331 case 0xbd: /* fucomp */
332 fucom(PST(code & 7),PST(0));
335 case 0xd8: /* faddp */
336 fadd(PST(code & 7),PST(0),&tmp);
337 real_to_real(&tmp,&ST(code & 7));
340 case 0xd9: /* fmulp */
341 fmul(PST(code & 7),PST(0),&tmp);
342 real_to_real(&tmp,&ST(code & 7));
345 case 0xda: /* ??? encoding of ficom with 16 bit mem ? ATS */
346 fcom(PST(code & 7),PST(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));
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));
362 case 0xde: /* fdivrp */
363 fdiv(PST(0),PST(code & 7),&tmp);
364 real_to_real(&tmp,&ST(code & 7));
367 case 0xdf: /* fdivp */
368 fdiv(PST(code & 7),PST(0),&tmp);
369 real_to_real(&tmp,&ST(code & 7));
372 case 0xf8: /* fild 16-bit mem ???? ATS */
373 printf("ffree not implemented\n");
374 math_abort(info,SIGILL);
377 case 0xf9: /* ????? ATS */
378 fxchg(&ST(0),&ST(code & 7));
380 case 0xfa: /* fist 16-bit mem ? ATS */
381 case 0xfb: /* fistp 16-bit mem ? ATS */
382 ST(code & 7) = ST(0);
386 switch ((code>>3) & 0xe7) {
388 put_short_real(PST(0),info,code);
391 put_short_real(PST(0),info,code);
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);
403 address = ea(info,code);
404 *(unsigned short *) &I387.cwd =
405 get_fs_word((unsigned short *) address);
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);
417 address = ea(info,code);
418 /*verify_area(address,2);*/
419 put_fs_word(I387.cwd,(short *) address);
422 put_long_int(PST(0),info,code);
425 put_long_int(PST(0),info,code);
430 get_temp_real(&tmp,info,code);
431 real_to_real(&tmp,&ST(0));
434 put_temp_real(PST(0),info,code);
438 put_long_real(PST(0),info,code);
441 put_long_real(PST(0),info,code);
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);
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);
465 address = ea(info,code);
466 /*verify_area(address,2);*/
467 put_fs_word(I387.swd,(short *) address);
470 put_short_int(PST(0),info,code);
473 put_short_int(PST(0),info,code);
478 get_BCD(&tmp,info,code);
479 real_to_real(&tmp,&ST(0));
483 get_longlong_int(&tmp,info,code);
484 real_to_real(&tmp,&ST(0));
487 put_BCD(PST(0),info,code);
491 put_longlong_int(PST(0),info,code);
497 get_short_real(&tmp,info,code);
500 get_long_int(&tmp,info,code);
503 get_long_real(&tmp,info,code);
506 get_short_int(&tmp,info,code);
508 switch ((code>>3) & 0x27) {
510 fadd(&tmp,PST(0),&tmp);
511 real_to_real(&tmp,&ST(0));
514 fmul(&tmp,PST(0),&tmp);
515 real_to_real(&tmp,&ST(0));
525 tmp.exponent ^= 0x8000;
526 fadd(&tmp,PST(0),&tmp);
527 real_to_real(&tmp,&ST(0));
530 ST(0).exponent ^= 0x8000;
531 fadd(&tmp,PST(0),&tmp);
532 real_to_real(&tmp,&ST(0));
535 fdiv(PST(0),&tmp,&tmp);
536 real_to_real(&tmp,&ST(0));
539 fdiv(&tmp,PST(0),&tmp);
540 real_to_real(&tmp,&ST(0));
543 if ((code & 0x138) == 0x100) {
545 real_to_real(&tmp,&ST(0));
548 printf("Unknown math-insns: %04x:%08x %04x\n",(u_short)info->tf_cs,
550 math_abort(info,SIGFPE);
558 tmp = I387.swd & 0xffffc7ffUL;
559 I387.swd += 0x00000800;
560 I387.swd &= 0x00003800;
569 tmp = I387.swd & 0xffffc7ffUL;
570 I387.swd += 0x00003800;
571 I387.swd &= 0x00003800;
576 fxchg(temp_real_unaligned * a, temp_real_unaligned * b)
578 temp_real_unaligned c;
585 static temp_real_unaligned *
590 return (temp_real_unaligned *) (i*10 + (char *)(I387.st_space));
594 * linux/kernel/math/ea.c
596 * (C) 1991 Linus Torvalds
600 * Calculate the effective address.
604 static int __regoffset[] = {
605 tEAX, tECX, tEDX, tEBX, tESP, tEBP, tESI, tEDI
608 #define REG(x) (((int *)curproc->p_md.md_regs)[__regoffset[(x)]])
611 sib(struct trapframe * info, int mod)
613 unsigned char ss,index,base;
616 base = get_fs_byte((char *) info->tf_eip);
619 index = (base >> 3) & 7;
626 if (mod || base != 5)
629 offset += (signed char) get_fs_byte((char *) info->tf_eip);
631 } else if (mod == 2 || base == 5) {
632 offset += (signed) get_fs_long((u_int32_t *) info->tf_eip);
637 return (char *) offset;
641 ea(struct trapframe * info, unsigned short code)
643 unsigned char mod,rm;
647 mod = (code >> 6) & 3;
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);
656 return (char *) offset;
658 tmp = (int32_t *) ®(rm);
660 case 0: offset = 0; break;
662 offset = (signed char) get_fs_byte((char *) info->tf_eip);
666 offset = (signed) get_fs_long((u_int32_t *) info->tf_eip);
671 math_abort(info,1<<(SIGILL-1));
676 return offset + (char *) *tmp;
679 * linux/kernel/math/get_put.c
681 * (C) 1991 Linus Torvalds
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.
691 get_short_real(temp_real * tmp, struct trapframe * info, unsigned short code)
696 addr = ea(info,code);
697 sr = get_fs_long((u_int32_t *) addr);
698 short_to_temp(&sr,tmp);
702 get_long_real(temp_real * tmp, struct trapframe * info, unsigned short code)
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);
714 get_temp_real(temp_real * tmp, struct trapframe * info, unsigned short code)
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);
725 get_short_int(temp_real * tmp, struct trapframe * info, unsigned short code)
730 addr = ea(info,code);
731 ti.a = (signed short) get_fs_word((unsigned short *) addr);
733 if ((ti.sign = (ti.a < 0)) != 0)
735 int_to_real(&ti,tmp);
739 get_long_int(temp_real * tmp, struct trapframe * info, unsigned short code)
744 addr = ea(info,code);
745 ti.a = get_fs_long((u_int32_t *) addr);
747 if ((ti.sign = (ti.a < 0)) != 0)
749 int_to_real(&ti,tmp);
753 get_longlong_int(temp_real * tmp, struct trapframe * info, unsigned short code)
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)) != 0)
762 __asm__("notl %0 ; notl %1\n\t"
763 "addl $1,%0 ; adcl $0,%1"
764 :"=r" (ti.a),"=r" (ti.b)
765 :"0" (ti.a),"1" (ti.b));
766 int_to_real(&ti,tmp);
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 :"0" (low),"1" (high):"cx","bx")
778 #define ADD64(val,low,high) \
779 __asm__("addl %4,%0 ; adcl $0,%1":"=r" (low),"=r" (high) \
780 :"0" (low),"1" (high),"r" ((u_int32_t) (val)))
783 get_BCD(temp_real * tmp, struct trapframe * info, unsigned short code)
790 addr = ea(info,code);
792 i.sign = 0x80 & get_fs_byte(addr--);
794 for (k = 0; k < 9; k++) {
795 c = get_fs_byte(addr--);
797 ADD64((c>>4), i.a, i.b);
799 ADD64((c&0xf), i.a, i.b);
805 put_short_real(const temp_real * tmp,
806 struct trapframe * info, unsigned short code)
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);
818 put_long_real(const temp_real * tmp,
819 struct trapframe * info, unsigned short code)
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);
832 put_temp_real(const temp_real * tmp,
833 struct trapframe * info, unsigned short code)
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);
845 put_short_int(const temp_real * tmp,
846 struct trapframe * info, unsigned short code)
851 addr = ea(info,code);
852 real_to_int(tmp,&ti);
853 /*verify_area(addr,2);*/
856 put_fs_word(ti.a,(short *) addr);
860 put_long_int(const temp_real * tmp,
861 struct trapframe * info, unsigned short code)
866 addr = ea(info,code);
867 real_to_int(tmp,&ti);
868 /*verify_area(addr,4);*/
871 put_fs_long(ti.a,(u_int32_t *) addr);
875 put_longlong_int(const temp_real * tmp,
876 struct trapframe * info, unsigned short code)
881 addr = ea(info,code);
882 real_to_int(tmp,&ti);
883 /*verify_area(addr,8);*/
885 __asm__("notl %0 ; notl %1\n\t"
886 "addl $1,%0 ; adcl $0,%1"
887 :"=r" (ti.a),"=r" (ti.b)
888 :"0" (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);
893 #define DIV10(low,high,rem) \
894 __asm__("divl %6 ; xchgl %1,%2 ; divl %6" \
895 :"=d" (rem),"=a" (low),"=r" (high) \
896 :"0" (0),"1" (high),"2" (low),"c" (10))
899 put_BCD(const temp_real * tmp,struct trapframe * info, unsigned short code)
906 addr = ea(info,code);
907 /*verify_area(addr,10);*/
910 put_fs_byte(0x80, addr+9);
912 put_fs_byte(0, addr+9);
913 for (k = 0; k < 9; k++) {
918 put_fs_byte(c,addr++);
923 * linux/kernel/math/mul.c
925 * (C) 1991 Linus Torvalds
929 * temporary real multiplication routine.
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)"
944 mul64(const temp_real * a, const temp_real * b, int * c)
946 __asm__("movl (%0),%%eax\n\t"
948 "movl %%eax,(%2)\n\t"
949 "movl %%edx,4(%2)\n\t"
950 "movl 4(%0),%%eax\n\t"
952 "movl %%eax,8(%2)\n\t"
953 "movl %%edx,12(%2)\n\t"
954 "movl (%0),%%eax\n\t"
956 "addl %%eax,4(%2)\n\t"
957 "adcl %%edx,8(%2)\n\t"
959 "movl 4(%0),%%eax\n\t"
961 "addl %%eax,4(%2)\n\t"
962 "adcl %%edx,8(%2)\n\t"
964 ::"S" (a),"c" (b),"D" (c)
969 fmul(const temp_real * src1, const temp_real * src2, temp_real * result)
972 int tmp[4] = {0,0,0,0};
974 sign = (src1->exponent ^ src2->exponent) & 0x8000;
975 i = (src1->exponent & 0x7fff) + (src2->exponent & 0x7fff) - 16383 + 1;
977 result->exponent = sign;
978 result->a = result->b = 0;
985 mul64(src1,src2,tmp);
986 if (tmp[0] || tmp[1] || tmp[2] || tmp[3])
987 while (i && tmp[3] >= 0) {
993 result->exponent = i | sign;
999 * linux/kernel/math/div.c
1001 * (C) 1991 Linus Torvalds
1005 * temporary real division routine.
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)"
1019 shift_right(int * c)
1021 __asm__("shrl $1,12(%0) ; rcrl $1,8(%0) ; rcrl $1,4(%0) ; rcrl $1,(%0)"
1026 try_sub(int * a, int * b)
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));
1039 div64(int * a, int * b, int * c)
1043 unsigned int mask = 0;
1046 for (i = 0 ; i<64 ; i++) {
1047 if (!(mask >>= 1)) {
1049 mask = 0x80000000UL;
1051 tmp[0] = a[0]; tmp[1] = a[1];
1052 tmp[2] = a[2]; tmp[3] = a[3];
1053 if (try_sub(b,tmp)) {
1055 a[0] = tmp[0]; a[1] = tmp[1];
1056 a[2] = tmp[2]; a[3] = tmp[3];
1063 fdiv(const temp_real * src1, const temp_real * src2, temp_real * result)
1066 int a[4],b[4],tmp[4] = {0,0,0,0};
1068 sign = (src1->exponent ^ src2->exponent) & 0x8000;
1069 if (!(src2->a || src2->b)) {
1073 i = (src1->exponent & 0x7fff) - (src2->exponent & 0x7fff) + 16383;
1076 result->exponent = sign;
1077 result->a = result->b = 0;
1091 if (tmp[0] || tmp[1] || tmp[2] || tmp[3]) {
1092 while (i && tmp[3] >= 0) {
1104 if (tmp[0] || tmp[1])
1106 result->exponent = i | sign;
1112 * linux/kernel/math/add.c
1114 * (C) 1991 Linus Torvalds
1118 * temporary real addition routine.
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.
1131 __asm__("notl %0 ; notl %1 ; addl $1,%0 ; adcl $0,%1" \
1132 :"=r" (a->a),"=r" (a->b) \
1133 :"0" (a->a),"1" (a->b))
1135 static void signify(temp_real * a)
1138 __asm__("shrdl $2,%1,%0 ; shrl $2,%1"
1139 :"=r" (a->a),"=r" (a->b)
1140 :"0" (a->a),"1" (a->b));
1141 if (a->exponent < 0)
1143 a->exponent &= 0x7fff;
1146 static void unsignify(temp_real * a)
1148 if (!(a->a || a->b)) {
1152 a->exponent &= 0x7fff;
1155 a->exponent |= 0x8000;
1159 __asm__("addl %0,%0 ; adcl %1,%1"
1160 :"=r" (a->a),"=r" (a->b)
1161 :"0" (a->a),"1" (a->b));
1166 fadd(const temp_real * src1, const temp_real * src2, temp_real * result)
1171 x1 = src1->exponent & 0x7fff;
1172 x2 = src2->exponent & 0x7fff;
1191 __asm__("shrdl %4,%1,%0 ; shrl %4,%1"
1192 :"=r" (b.a),"=r" (b.b)
1193 :"0" (b.a),"1" (b.b),"c" ((char) shift));
1196 __asm__("addl %4,%0 ; adcl %5,%1"
1197 :"=r" (a.a),"=r" (a.b)
1198 :"0" (a.a),"1" (a.b),"g" (b.a),"g" (b.b));
1204 * linux/kernel/math/compare.c
1206 * (C) 1991 Linus Torvalds
1210 * temporary real comparison routines
1214 #define clear_Cx() (I387.swd &= ~0x4500)
1217 normalize(temp_real * a)
1219 int i = a->exponent & 0x7fff;
1220 int sign = a->exponent & 0x8000;
1222 if (!(a->a || a->b)) {
1226 while (i && a->b >= 0) {
1228 __asm__("addl %0,%0 ; adcl %1,%1"
1229 :"=r" (a->a),"=r" (a->b)
1230 :"0" (a->a),"1" (a->b));
1232 a->exponent = i | sign;
1236 ftst(const temp_real * a)
1243 if (b.a || b.b || b.exponent) {
1251 fcom(const temp_real * src1, const temp_real * src2)
1256 a.exponent ^= 0x8000;
1262 fucom(const temp_real * src1, const temp_real * src2)
1268 * linux/kernel/math/convert.c
1270 * (C) 1991 Linus Torvalds
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.
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.)
1287 short_to_temp(const short_real * a, temp_real * b)
1289 if (!(*a & 0x7fffffff)) {
1292 b->exponent = 0x8000;
1297 b->exponent = ((*a>>23) & 0xff)-127+16383;
1299 b->exponent |= 0x8000;
1300 b->b = (*a<<8) | 0x80000000UL;
1305 long_to_temp(const long_real * a, temp_real * b)
1307 if (!a->a && !(a->b & 0x7fffffff)) {
1310 b->exponent = 0x8000;
1315 b->exponent = ((a->b >> 20) & 0x7ff)-1023+16383;
1317 b->exponent |= 0x8000;
1318 b->b = 0x80000000UL | (a->b<<11) | (((u_int32_t)a->a)>>21);
1323 temp_to_short(const temp_real * a, short_real * b)
1325 if (!(a->exponent & 0x7fff)) {
1326 *b = (a->exponent)?0x80000000UL:0;
1329 *b = ((((int32_t) a->exponent)-16383+127) << 23) & 0x7f800000;
1330 if (a->exponent < 0)
1332 *b |= (a->b >> 8) & 0x007fffff;
1333 switch ((int)ROUNDING) {
1335 if ((a->b & 0xff) > 0x80)
1339 if ((a->exponent & 0x8000) && (a->b & 0xff))
1343 if (!(a->exponent & 0x8000) && (a->b & 0xff))
1350 temp_to_long(const temp_real * a, long_real * b)
1352 if (!(a->exponent & 0x7fff)) {
1354 b->b = (a->exponent)?0x80000000UL:0;
1357 b->b = (((0x7fff & (int32_t) a->exponent)-16383+1023) << 20) &
1359 if (a->exponent < 0)
1360 b->b |= 0x80000000UL;
1361 b->b |= (a->b >> 11) & 0x000fffff;
1363 b->a |= (a->a >> 11) & 0x001fffff;
1364 switch ((int)ROUNDING) {
1366 if ((a->a & 0x7ff) > 0x400)
1367 __asm__("addl $1,%0 ; adcl $0,%1"
1368 :"=r" (b->a),"=r" (b->b)
1369 :"0" (b->a),"1" (b->b));
1372 if ((a->exponent & 0x8000) && (a->b & 0xff))
1373 __asm__("addl $1,%0 ; adcl $0,%1"
1374 :"=r" (b->a),"=r" (b->b)
1375 :"0" (b->a),"1" (b->b));
1378 if (!(a->exponent & 0x8000) && (a->b & 0xff))
1379 __asm__("addl $1,%0 ; adcl $0,%1"
1380 :"=r" (b->a),"=r" (b->b)
1381 :"0" (b->a),"1" (b->b));
1387 frndint(const temp_real * a, temp_real * b)
1389 int shift = 16383 + 63 - (a->exponent & 0x7fff);
1390 u_int32_t underflow;
1392 if ((shift < 0) || (shift == 16383+63)) {
1396 b->a = b->b = underflow = 0;
1397 b->exponent = a->exponent;
1399 b->b = a->b; b->a = a->a;
1400 } else if (shift < 64) {
1401 b->a = a->b; underflow = a->a;
1404 } else if (shift < 96) {
1412 b->exponent += shift;
1413 __asm__("shrdl %2,%1,%0"
1414 :"=r" (underflow),"=r" (b->a)
1415 :"c" ((char) shift),"0" (underflow),"1" (b->a));
1416 __asm__("shrdl %2,%1,%0"
1417 :"=r" (b->a),"=r" (b->b)
1418 :"c" ((char) shift),"0" (b->a),"1" (b->b));
1419 __asm__("shrl %1,%0"
1421 :"c" ((char) shift),"0" (b->b));
1422 switch ((int)ROUNDING) {
1424 __asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1"
1425 :"=r" (b->a),"=r" (b->b)
1426 :"0" (b->a),"1" (b->b)
1427 ,"r" (0x7fffffff + (b->a & 1))
1428 ,"m" (*&underflow));
1431 if ((b->exponent >= 0) && underflow)
1432 __asm__("addl $1,%0 ; adcl $0,%1"
1433 :"=r" (b->a),"=r" (b->b)
1434 :"0" (b->a),"1" (b->b));
1437 if ((b->exponent < 0) && underflow)
1438 __asm__("addl $1,%0 ; adcl $0,%1"
1439 :"=r" (b->a),"=r" (b->b)
1440 :"0" (b->a),"1" (b->b));
1446 __asm__("addl %0,%0 ; adcl %1,%1"
1447 :"=r" (b->a),"=r" (b->b)
1448 :"0" (b->a),"1" (b->b));
1455 Fscale(const temp_real *a, const temp_real *b, temp_real *c)
1460 if(!c->a && !c->b) { /* 19 Sep 92*/
1464 real_to_int(b, &ti);
1466 c->exponent -= ti.a;
1468 c->exponent += ti.a;
1472 real_to_int(const temp_real * a, temp_int * b)
1474 int shift = 16383 + 63 - (a->exponent & 0x7fff);
1475 u_int32_t underflow;
1477 b->a = b->b = underflow = 0;
1478 b->sign = (a->exponent < 0);
1484 b->b = a->b; b->a = a->a;
1485 } else if (shift < 64) {
1486 b->a = a->b; underflow = a->a;
1488 } else if (shift < 96) {
1495 __asm__("shrdl %2,%1,%0"
1496 :"=r" (underflow),"=r" (b->a)
1497 :"c" ((char) shift),"0" (underflow),"1" (b->a));
1498 __asm__("shrdl %2,%1,%0"
1499 :"=r" (b->a),"=r" (b->b)
1500 :"c" ((char) shift),"0" (b->a),"1" (b->b));
1501 __asm__("shrl %1,%0"
1503 :"c" ((char) shift),"0" (b->b));
1504 switch ((int)ROUNDING) {
1506 __asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1"
1507 :"=r" (b->a),"=r" (b->b)
1508 :"0" (b->a),"1" (b->b)
1509 ,"r" (0x7fffffff + (b->a & 1))
1510 ,"m" (*&underflow));
1513 if (!b->sign && underflow)
1514 __asm__("addl $1,%0 ; adcl $0,%1"
1515 :"=r" (b->a),"=r" (b->b)
1516 :"0" (b->a),"1" (b->b));
1519 if (b->sign && underflow)
1520 __asm__("addl $1,%0 ; adcl $0,%1"
1521 :"=r" (b->a),"=r" (b->b)
1522 :"0" (b->a),"1" (b->b));
1528 int_to_real(const temp_int * a, temp_real * b)
1533 b->exponent = 16383 + 63 + (a->sign? 0x8000:0);
1540 __asm__("addl %0,%0 ; adcl %1,%1"
1541 :"=r" (b->a),"=r" (b->b)
1542 :"0" (b->a),"1" (b->b));
1547 fpu_modevent(module_t mod, int type, void *unused)
1551 if (pmath_emulate) {
1552 printf("Another Math emulator already present\n");
1555 pmath_emulate = math_emulate;
1557 printf("Math emulator present\n");
1560 if (pmath_emulate != math_emulate) {
1561 printf("Cannot unload another math emulator\n");
1566 printf("Math emulator unloaded\n");
1573 static moduledata_t fpumod = {
1578 DECLARE_MODULE(fpu, fpumod, SI_SUB_DRIVERS, SI_ORDER_ANY);