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