程序11-8 linux/kernel/math/mul.c
1 /*
2 * linux/kernel/math/mul.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7 /*
8 * temporary real multiplication routine.
9 */
/*
* 临时实数乘法子程序。
*/
10
11 #include <linux/math_emu.h> // 协处理器头文件。定义临时实数结构和387寄存器操作宏等。
12
// 把c指针处的16字节值左移1位(乘2)。
13 static void shift(int * c)
14 {
15 __asm__("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
// 2个临时实数相乘,结果放在c指针处(16字节)。
22 static void mul64(const temp_real * a, const temp_real * b, int * c)
23 {
24 __asm__("movl (%0),%%eax\n\t"
25 "mull (%1)\n\t"
26 "movl %%eax,(%2)\n\t"
27 "movl %%edx,4(%2)\n\t"
28 "movl 4(%0),%%eax\n\t"
29 "mull 4(%1)\n\t"
30 "movl %%eax,8(%2)\n\t"
31 "movl %%edx,12(%2)\n\t"
32 "movl (%0),%%eax\n\t"
33 "mull 4(%1)\n\t"
34 "addl %%eax,4(%2)\n\t"
35 "adcl %%edx,8(%2)\n\t"
36 "adcl $0,12(%2)\n\t"
37 "movl 4(%0),%%eax\n\t"
38 "mull (%1)\n\t"
39 "addl %%eax,4(%2)\n\t"
40 "adcl %%edx,8(%2)\n\t"
41 "adcl $0,12(%2)"
42 ::"b" ((long) a),"c" ((long) b),"D" ((long) c)
43 :"ax","dx");
44 }
45
// 仿真浮点指令FMUL。
// 临时实数src1 * scr2 è result处。
46 void fmul(const temp_real * src1, const temp_real * src2, temp_real * result)
47 {
48 int i,sign;
49 int tmp[4] = {0,0,0,0};
50
// 首先确定两数相乘的符号。符号值等于两者符号位异或值。然后计算乘后的指数值。相乘时
// 指数值需要相加。但是由于指数使用偏执数格式保存,两个数的指数相加时偏置量也被加了
// 两次,因此需要减掉一个偏置量值(临时实数的偏置量是16383)。
51 sign = (src1->exponent ^ src2->exponent) & 0x8000;
52 i = (src1->exponent & 0x7fff) + (src2->exponent & 0x7fff) - 16383 + 1;
// 如果结果指数变成了负值,表示两数相乘后产生下溢。于是直接返回带符号的零值。
// 如果结果指数大于0x7fff,表示产生上溢,于是设置状态字溢出异常标志位,并返回。
53 if (i<0) {
54 result->exponent = sign;
55 result->a = result->b = 0;
56 return;
57 }
58 if (i>0x7fff) {
59 set_OE();
60 return;
61 }
// 如果两数尾数相乘后结果不为0,则对结果尾数进行规格化处理。即左移结果尾数值,使得
// 最高有效位为1。同时相应地调整指数值。如果两数的尾数相乘后16字节的结果尾数为0,
// 则也设置指数值为0。最后把相乘结果保存在临时实数变量result中。
62 mul64(src1,src2,tmp);
63 if (tmp[0] || tmp[1] || tmp[2] || tmp[3])
64 while (i && tmp[3] >= 0) {
65 i--;
66 shift(tmp);
67 }
68 else
69 i = 0;
70 result->exponent = i | sign;
71 result->a = tmp[2];
72 result->b = tmp[3];
73 }
74