|
|
1.1 root 1: .file "reg_u_sub.S"
2: /*---------------------------------------------------------------------------+
3: | reg_u_sub.S |
4: | |
5: | Core floating point subtraction routine. |
6: | |
7: | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
8: | Australia. E-mail [email protected] |
9: | |
10: | Call from C as: |
11: | void reg_u_sub(reg *arg1, reg *arg2, reg *answ) |
12: | |
13: +---------------------------------------------------------------------------*/
14:
15: /*
16: | Kernel subtraction routine reg_u_sub(reg *arg1, reg *arg2, reg *answ).
17: | Takes two valid reg f.p. numbers (TW_Valid), which are
18: | treated as unsigned numbers,
19: | and returns their difference as a TW_Valid or TW_Zero f.p.
20: | number.
21: | The first number (arg1) must be the larger.
22: | The returned number is normalized.
23: | Basic checks are performed if PARANOID is defined.
24: */
25:
26: #include "exception.h"
27: #include "fpu_asm.h"
28:
29:
30: .text
31: .align 2,144
32: .globl reg_u_sub
33: reg_u_sub:
34: pushl %ebp
35: movl %esp,%ebp
36: pushl %esi
37: pushl %edi
38: pushl %ebx
39:
40: movl PARAM1,%esi /* source 1 */
41: movl PARAM2,%edi /* source 2 */
42:
43: // xorl %ecx,%ecx
44: movl EXP(%esi),%ecx
45: subl EXP(%edi),%ecx /* exp1 - exp2 */
46:
47: #ifdef PARANOID
48: /* source 2 is always smaller than source 1 */
49: // jc L_bugged
50: js L_bugged_1
51:
52: testl $0x80000000,SIGH(%edi) /* The args are assumed to be be normalized */
53: je L_bugged_2
54:
55: testl $0x80000000,SIGH(%esi)
56: je L_bugged_2
57: #endif PARANOID
58:
59: /*--------------------------------------+
60: | Form a register holding the |
61: | smaller number |
62: +--------------------------------------*/
63: movl SIGH(%edi),%eax // register ms word
64: movl SIGL(%edi),%ebx // register ls word
65:
66: movl PARAM3,%edi /* destination */
67: movl EXP(%esi),%edx
68: movl %edx,EXP(%edi) /* Copy exponent to destination */
69:
70: xorl %edx,%edx // register extension
71:
72: /*--------------------------------------+
73: | Shift the temporary register |
74: | right the required number of |
75: | places. |
76: +--------------------------------------*/
77: L_shift_r:
78: cmpl $32,%ecx /* shrd only works for 0..31 bits */
79: jnc L_more_than_31
80:
81: /* less than 32 bits */
82: shrd %cl,%ebx,%edx
83: shrd %cl,%eax,%ebx
84: shr %cl,%eax
85: jmp L_shift_done
86:
87: L_more_than_31:
88: cmpl $64,%ecx
89: jnc L_more_than_63
90:
91: subb $32,%cl
92: shrd %cl,%eax,%edx
93: movl %eax,%ebx
94: shr %cl,%ebx
95: xorl %eax,%eax
96: jmp L_shift_done
97:
98: L_more_than_63:
99: cmpl $66,%ecx
100: jnc L_more_than_65
101:
102: subb $64,%cl
103: movl %eax,%edx
104: shr %cl,%edx
105: xorl %ebx,%ebx
106: xorl %eax,%eax
107: jmp L_shift_done
108:
109: L_more_than_65:
110: /* just copy the larger reg to dest */
111: movw SIGN(%esi),%ax
112: movw %ax,SIGN(%edi)
113: movl EXP(%esi),%eax
114: movl %eax,EXP(%edi)
115: movl SIGL(%esi),%eax
116: movl %eax,SIGL(%edi)
117: movl SIGH(%esi),%eax
118: movl %eax,SIGH(%edi)
119: jmp L_exit // Does not underflow
120:
121: L_shift_done:
122: L_subtr:
123: /*------------------------------+
124: | Do the subtraction |
125: +------------------------------*/
126: xorl %ecx,%ecx
127: subl %edx,%ecx
128: movl %ecx,%edx
129: movl SIGL(%esi),%ecx
130: sbbl %ebx,%ecx
131: movl %ecx,%ebx
132: movl SIGH(%esi),%ecx
133: sbbl %eax,%ecx
134: movl %ecx,%eax
135:
136: #ifdef PARANOID
137: /* We can never get a borrow */
138: jc L_bugged
139: #endif PARANOID
140:
141: /*--------------------------------------+
142: | Normalize the result |
143: +--------------------------------------*/
144: testl $0x80000000,%eax
145: jnz L_round /* no shifting needed */
146:
147: orl %eax,%eax
148: jnz L_shift_1 /* shift left 1 - 31 bits */
149:
150: orl %ebx,%ebx
151: jnz L_shift_32 /* shift left 32 - 63 bits */
152:
153: // A rare case, the only one which is non-zero if we got here
154: // is: 1000000 .... 0000
155: // -0111111 .... 1111 1
156: // --------------------
157: // 0000000 .... 0000 1
158:
159: cmpl $0x80000000,%edx
160: jnz L_must_be_zero
161:
162: /* Shift left 64 bits */
163: subl $64,EXP(%edi)
164: movl %edx,%eax
165: jmp L_store
166:
167: L_must_be_zero:
168: #ifdef PARANOID
169: orl %edx,%edx
170: jnz L_bugged_3
171: #endif PARANOID
172:
173: /* The result is zero */
174: movb TW_Zero,TAG(%edi)
175: movl $0,EXP(%edi) /* exponent */
176: movl $0,SIGL(%edi)
177: movl $0,SIGH(%edi)
178: jmp L_exit // Does not underflow
179:
180: L_shift_32:
181: movl %ebx,%eax
182: movl %edx,%ebx
183: movl $0,%edx
184: subl $32,EXP(%edi) /* Can get underflow here */
185:
186: /* We need to shift left by 1 - 31 bits */
187: L_shift_1:
188: bsrl %eax,%ecx /* get the required shift in %ecx */
189: subl $31,%ecx
190: negl %ecx
191: shld %cl,%ebx,%eax
192: shld %cl,%edx,%ebx
193: shl %cl,%edx
194: subl %ecx,EXP(%edi) /* Can get underflow here */
195:
196: L_round:
197: /*------------------------------+
198: | Round the result |
199: +------------------------------*/
200: cmpl $0x80000000,%edx
201: jc L_store
202:
203: jne L_round_up
204:
205: testb $1,%dl
206: jz L_store
207:
208: L_round_up:
209: addl $1,%ebx
210: adcl $0,%eax
211: jnc L_store
212:
213: /* We just rounded up to (1) 00 00 */
214: /* This *is* possible, if the subtraction is of the
215: form (1. + x) - (x + y) where x is small and y is
216: very small. */
217: incl EXP(%edi)
218: movl $0x80000000,%eax
219:
220: L_store:
221: /*------------------------------+
222: | Store the result |
223: +------------------------------*/
224: movl %eax,SIGH(%edi)
225: movl %ebx,SIGL(%edi)
226:
227: movb TW_Valid,TAG(%edi) /* Set the tags to TW_Valid */
228:
229: cmpl EXP_UNDER,EXP(%edi)
230: jle L_underflow
231:
232: L_exit:
233: popl %ebx
234: popl %edi
235: popl %esi
236: leave
237: ret
238:
239:
240: L_underflow:
241: push %edi
242: call arith_underflow
243: pop %ebx
244: jmp L_exit
245:
246:
247: #ifdef PARANOID
248: L_bugged_1:
249: pushl EX_INTERNAL|0x206
250: call EXCEPTION
251: pop %ebx
252: jmp L_exit
253:
254: L_bugged_2:
255: pushl EX_INTERNAL|0x209
256: call EXCEPTION
257: pop %ebx
258: jmp L_exit
259:
260: L_bugged_3:
261: pushl EX_INTERNAL|0x210
262: call EXCEPTION
263: pop %ebx
264: jmp L_exit
265:
266: L_bugged_4:
267: pushl EX_INTERNAL|0x211
268: call EXCEPTION
269: pop %ebx
270: jmp L_exit
271:
272: L_bugged:
273: pushl EX_INTERNAL|0x212
274: call EXCEPTION
275: pop %ebx
276: jmp L_exit
277: #endif PARANOID
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.