程序11-9 linux/kernel/math/div.c
1 /*
2 * linux/kernel/math/div.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7 /*
8 * temporary real division routine.
9 */
10
11 #include <linux/math_emu.h> // 协处理器头文件。定义临时实数结构和387寄存器操作宏等。
12
// 将指针c指向的4字节中内容左移1位。
13 static void shift_left(int * c)
14 {
15 __asm__ __volatile__("movl (%0),%%eax ; addl %%eax,(%0)\n\t"
16 "movl 4(%0),%%eax ; adcl %%eax,4(%0)\n\t"
17 "movl 8(%0),%%eax ; adcl %%eax,8(%0)\n\t"
18 "movl 12(%0),%%eax ; adcl %%eax,12(%0)"
19 ::"r" ((long) c):"ax");
20 }
21
// 将指针c指向的4字节中内容右移1位。
22 static void shift_right(int * c)
23 {
24 __asm__("shrl $1,12(%0) ; rcrl $1,8(%0) ; rcrl $1,4(%0) ; rcrl $1,(%0)"
25 ::"r" ((long) c));
26 }
27
// 减法运算。
// 16字节减法运算,a - b è a。最后根据是否有借位(CF=1)设置ok。若无借位(CF=0)
// 则ok = 1。否则ok=0。
28 static int try_sub(int * a, int * b)
29 {
30 char ok;
31
32 __asm__ __volatile__("movl (%1),%%eax ; subl %%eax,(%2)\n\t"
33 "movl 4(%1),%%eax ; sbbl %%eax,4(%2)\n\t"
34 "movl 8(%1),%%eax ; sbbl %%eax,8(%2)\n\t"
35 "movl 12(%1),%%eax ; sbbl %%eax,12(%2)\n\t"
36 "setae %%al":"=a" (ok):"c" ((long) a),"d" ((long) b));
37 return ok;
38 }
39
// 16字节除法。
// 参数 a /b è c。利用减法模拟多字节除法。
40 static void div64(int * a, int * b, int * c)
41 {
42 int tmp[4];
43 int i;
44 unsigned int mask = 0;
45
46 c += 4;
47 for (i = 0 ; i<64 ; i++) {
48 if (!(mask >>= 1)) {
49 c--;
50 mask = 0x80000000;
51 }
52 tmp[0] = a[0]; tmp[1] = a[1];
53 tmp[2] = a[2]; tmp[3] = a[3];
54 if (try_sub(b,tmp)) {
55 *c |= mask;
56 a[0] = tmp[0]; a[1] = tmp[1];
57 a[2] = tmp[2]; a[3] = tmp[3];
58 }
59 shift_right(b);
60 }
61 }
62
// 仿真浮点指令FDIV。
63 void fdiv(const temp_real * src1, const temp_real * src2, temp_real * result)
64 {
65 int i,sign;
66 int a[4],b[4],tmp[4] = {0,0,0,0};
67
68 sign = (src1->exponent ^ src2->exponent) & 0x8000;
69 if (!(src2->a || src2->b)) {
70 set_ZE();
71 return;
72 }
73 i = (src1->exponent & 0x7fff) - (src2->exponent & 0x7fff) + 16383;
74 if (i<0) {
75 set_UE();
76 result->exponent = sign;
77 result->a = result->b = 0;
78 return;
79 }
80 a[0] = a[1] = 0;
81 a[2] = src1->a;
82 a[3] = src1->b;
83 b[0] = b[1] = 0;
84 b[2] = src2->a;
85 b[3] = src2->b;
86 while (b[3] >= 0) {
87 i++;
88 shift_left(b);
89 }
90 div64(a,b,tmp);
91 if (tmp[0] || tmp[1] || tmp[2] || tmp[3]) {
92 while (i && tmp[3] >= 0) {
93 i--;
94 shift_left(tmp);
95 }
96 if (tmp[3] >= 0)
97 set_DE();
98 } else
99 i = 0;
100 if (i>0x7fff) {
101 set_OE();
102 return;
103 }
104 if (tmp[0] || tmp[1])
105 set_PE();
106 result->exponent = i | sign;
107 result->a = tmp[2];
108 result->b = tmp[3];
109 }
110