|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: .file "subadd.s"
26:
27: .ident "@(#)kern-fp:subadd.s 1.1"
28: //$tt(*80387 emulator + + + s u b a d d + + + *)
29: // ************************************************************************
30: //
31: // s u b a d d . m o d
32: // ===================
33: //
34: // ===============================================================
35: // intel corporation proprietary information
36: // this software is supplied under the terms of a license
37: // agreement or non-disclosure agreement with intel corporation
38: // and may not be copied nor disclosed except in accordance with
39: // the terms of that agreement.
40: // ===============================================================
41: //
42: // function:
43: // performs floating point add, subtract, or compare
44: // of unpacked, non-zero, valid numbers.
45: //
46: // public procedures:
47: // addx subx subadd
48: // sp_subadd compar mov_neg_frac
49: //
50: // **************************************************************************
51: //
52: //...March 3, 1987...
53: //
54: //$nolist
55: #include "fp_e80387.h"
56: //$list
57: //...declare status register segment...
58: //
59: .data //a_msr segment rw public
60: // extrn %gs:sr_masks,%gs:sr_flags,%gs:sr_errors
61: //a_msr ends
62: //
63: // assume %ds:a_msr
64: .text //a_med segment er public
65: //
66: // extrn sticky_right_shift,right_shift,test_6w
67: // extrn addition_normalize,subtraction_normalize
68: // extrn pop_free,clear_6w,get_rnd_control
69: // extrn set_i_error,affine_infinity_,set_s_bit
70: // extrn clear_s_bit,set_z_bit,clear_z_bit
71: // extrn i_error_,set_d_error,set_stk_u_error
72: //
73: .globl addx
74: .globl subx
75: .globl subadd
76: .globl sp_subadd
77: .globl compar
78: //
79: // ***********************************************************************
80: // addx:
81: // *****
82: // function:
83: // fractional add. result_frac <-- frac1 + frac2.
84: //
85: // inputs:
86: // assumes operand records are set up.
87: //
88: // outputs:
89: // al = 1 if there was a carry-out; al=0 otherwise.
90: //
91: // data accessed:
92: // - word_frac1 word_frac2
93: // - result_word_frac
94: //
95: // data changed:
96: // result_word_frac
97: //
98: // ***********************************************************************
99: ALIGN
100: addx: //proc
101:
102: mov dword_frac1(%ebp),%eax //do fractional add
103: xorw %ax,%ax //clear extra word
104: add dword_frac2(%ebp),%eax
105: mov %eax,result_dword_frac(%ebp)
106: mov dword_frac1+4(%ebp),%eax
107: adc dword_frac2+4(%ebp),%eax
108: mov %eax,result_dword_frac+4(%ebp)
109: mov dword_frac1+8(%ebp),%eax
110: adc dword_frac2+8(%ebp),%eax
111: mov %eax,result_dword_frac+8(%ebp)
112:
113: movb $0,%al
114: rclb $1,%al //put carry into al
115: ret
116: //addx endp
117: //
118: // ****************************************************************************
119: // subx:
120: // ****
121: // function:
122: // 2s complement fractional subtract.
123: // result_frac <-- frac1 - frac2.
124: //
125: // inputs:
126: // assumes operand variables are set up.
127: //
128: // outputs:
129: // al=1 if borrow; al=0 otherwise.
130: //
131: // data accessed:
132: // - word_frac1 word_frac2
133: // - result_word_frac
134: //
135: // data changed:
136: // - result_word_frac
137: //
138: // ***************************************************************************
139: ALIGN
140: subx: //proc
141:
142: mov dword_frac1(%ebp),%eax // fractional subtract
143: andl $0x0ffff0000,dword_frac2(%ebp) // clear low word
144: sub dword_frac2(%ebp),%eax
145: mov %eax,result_dword_frac(%ebp)
146: mov dword_frac1+4(%ebp),%eax
147: sbb dword_frac2+4(%ebp),%eax
148: mov %eax,result_dword_frac+4(%ebp)
149: mov dword_frac1+8(%ebp),%eax
150: sbb dword_frac2+8(%ebp),%eax
151: mov %eax,result_dword_frac+8(%ebp)
152: movb $0,%al //set al to borrow
153: rclb $1,%al
154: ret
155: //subx endp
156: //
157: // ***************************************************************************
158: // subadd:
159: // *******
160: // function:
161: // floating point add or subtract.calculates unpacked result.
162: // sp_subadd is the entry point for log functions.
163: //
164: // inputs:
165: // assumes operands are unpacked, valid, non-zero.
166: //
167: // outputs:
168: //
169: // data accessed:
170: // - operation_type sign1
171: // - expon1 msb_frac
172: // - offset_operand1 sign2
173: // - expon2 msb_frac2
174: // - offset_operand2 offset_result
175: // - result_sign result_expon
176: // - result_word_frac
177: //
178: // data changed:
179: // - result_sign result_expon
180: // - result_word_frac
181: //
182: // procedures called:
183: // sticky_right_shift right_shift
184: // addition_normlized subtraction_normalize
185: // addx subx
186: // test_6w get_rnd_control
187: //
188: // ************************************************************************
189: ALIGN
190: subadd: //proc
191: mov $sticky_right_shift,%esi // load shift proc ptr
192: jmp form_expon_difference // merge with sp_subadd
193: ALIGN
194: sp_subadd:
195: mov $sp_right_shift,%esi // load shift proc ptr
196: form_expon_difference:
197: mov dword_expon1,%ecx
198: sub dword_expon2,%ecx
199: js expon2_larger
200: cmp $67,%ecx //set cl to shift amount =
201: jbe adjust_frac2 //min(67,expon1-expon2)
202: mov $67,%ecx
203: adjust_frac2:
204: movb $0x00,%al //al = bit to inject from left
205: mov $offset_operand2,%edi
206: push %esi
207: call *%esi //shift op2 fraction
208: pop %esi
209: mov expon1(%ebp),%eax //set result expon to expon1
210: mov %eax,result_expon(%ebp)
211: cmpb special, tag1(%ebp)
212: je determine_operation_true
213: testb $0x80,msb_frac1
214: jnz determine_operation_true // branch if frac1 is normal
215: jmp frac2_normal_ // test frac2
216: ALIGN
217: expon2_larger:
218: neg %ecx //set cl to shift amount
219: cmp $67,%ecx
220: jbe adjust_frac1
221: mov $67,%ecx
222: adjust_frac1:
223: push %ecx //save shift amount
224: movb $0x00,%al //al = bit to inject
225: mov $offset_operand1,%edi
226: call *%esi
227: mov expon2(%ebp),%eax //set result expon to expon2
228: mov %eax,result_expon(%ebp)
229: pop %ecx
230: frac2_normal_:
231: cmpb special, tag2(%ebp)
232: je determine_operation_true
233: movb false,%al
234: testb $0x80,msb_frac2 // set al to true if frac2 is
235: jz determine_operation // normalized
236: determine_operation_true:
237: movb true,%al
238: determine_operation:
239: cmpb $sub_op,operation_type(%ebp) //if op=sub_op, negate op2
240: jne add_or_sub_
241: notb sign2(%ebp)
242: add_or_sub_:
243: movb sign1(%ebp),%ah
244: cmpb sign2(%ebp),%ah
245: jne do_subtraction
246: call addx //do fractional add
247: mov $offset_result,%edi
248: call addition_normalize //normalize result after add
249: movb sign1(%ebp),%al
250: movb %al,result_sign(%ebp) //set result sign to sign1
251: testb $0x80, msb_result
252: jnz add_done
253: mov $offset_result, %edi
254: call test_6w
255: jnz norm_result
256: add_done:
257: ret
258: ALIGN
259: do_subtraction:
260: push %eax //save normalization indicator
261: movb sign1(%ebp),%al //initially, set sign to sign1
262: movb %al,result_sign(%ebp)
263: call subx //do fractional subtract
264: mov $offset_result,%edi
265: cmpb $0,%al
266: mov $0,%eax
267: je detect_zero
268:
269: notl (%ebp,%edi) //form 2s comp of result_frac
270: add $1,(%ebp,%edi)
271: notl 4(%ebp,%edi)
272: adc %eax,4(%ebp,%edi)
273: notl 8(%ebp,%edi)
274: adc %eax,8(%ebp,%edi)
275: notb result_sign(%ebp) //and complement result_sign
276: detect_zero:
277: call test_6w //find true zero result
278: jnz do_norm_ // if not zero, test for denorm
279: call get_rnd_control // sign is + unless rnd down
280: xorb rnd_down,%al
281: decw %ax
282: cbtw
283: movb %ah,result_sign(%ebp)
284: pop %eax //if al=true, then result should
285: cmpb true,%al // be true zero
286: jne subtract_done
287: movw $0,result_expon(%ebp)
288: ret
289: ALIGN
290: do_norm_:
291: pop %eax //if al=false, dont normalize
292: cmpb true,%al // the result
293: jne subtract_done
294: norm_result:
295: mov $offset_result,%edi
296: call subtraction_normalize //normalize the result
297: subtract_done:
298: ret
299: ALIGN
300: sp_right_shift:
301: call right_shift
302: mov (%ebp,%edi),%eax // ss:ebp+edi -> dword_frac after call
303: and $0x1fffffff,%eax // mask dword fraction
304: or %eax,%edx // or it to the right_shift output
305: jz sp_nonsticky // if zero, it must be nonsticky
306: orl $0x20000000,(%ebp,%edi) // if nonzero, set bit of dword_frac
307: sp_nonsticky:
308: andl $0x0e0000000,(%ebp,%edi) // now mask off most of dword_frac
309: ret
310: //subadd endp
311: //
312: // ***********************************************************************
313: // compar:
314: // *******
315: //
316: // function:
317: // main procedure for compare and test instructions.
318: //
319: // inputs:
320: // op1 and op2 operand records.
321: //
322: // outputs:
323: // sets zero and sign status bits to indicate the result
324: // of the compare. sets the invalid and denorm error bits
325: // if these errors are detected.
326: //
327: // data accessed:
328: // - operation_type tag1
329: // - expon1 tag2
330: // - expon2 result_sign
331: // - result_word_frac
332: //
333: // data changed:
334: //
335: // procedures called:
336: // pop_free subadd
337: // test_6w clear_6w
338: // set_s_bit clear_s_bit
339: // set_z_bit clear_z_bit
340: //
341: // ***************************************************************************
342: ALIGN
343: compar: //proc
344: jz no_stack_error // branch if no stack error
345: andb $~a_mask,%gs:sr_flags // clear a-bit
346: orb invalid_mask+zero_mask,%gs:sr_errors// clears zf, to 0
347: jmp invalid_error_signal
348: ALIGN
349: no_stack_error:
350: movl $0,before_error_signals(%ebp)
351: andb $~(a_mask+c_mask),%gs:sr_flags
352: cmpb $test_op,operation_type(%ebp) // if not test_op, then
353: jne set_up_check // its compar_op or ucom_op
354: movb positive,sign2(%ebp) // for test_op, set operand2
355: movb special,tag2(%ebp) // to zero
356: mov $dword_frac2,%edi
357: call clear_6w // returns with eax = 0
358: mov %eax,dword_expon2
359: set_up_check:
360: movb tag1(%ebp),%al // both operands valid?
361: orb tag2(%ebp),%al
362: jz ordered_cases // yes, ops are ordered.
363: cmpb special,%al // one op is zero, and the
364: je ordered_cases // other is zero or valid.
365: testb $0x10,%al // is either op unsupported?
366: jnz invalid_error_detected
367: op1_nan_:
368: movb tag1(%ebp),%al // al = value of tag1
369: movb tag2(%ebp),%ah // ah = value of tag2
370: cmpb inv,%al
371: je op1_snan_
372: cmpb inv,%ah
373: jne non_nan_supp_ops
374: jmp signal_invalid_
375: ALIGN
376: op1_snan_:
377: testb $0x40,msb_frac1
378: jz invalid_error_detected
379: op2_also_nan_:
380: cmpb inv,%ah
381: jne set_up_nan_return
382: signal_invalid_:
383: testb $0x40,msb_frac2
384: jz invalid_error_detected
385: set_up_nan_return:
386: cmpb $ucom_op,operation_type(%ebp) // if ucom_op, then
387: je set_uncertain // no invalid signal.
388: jmp invalid_error_detected
389: ALIGN
390: non_nan_supp_ops:
391: cmpb denormd,tag1(%ebp)
392: jne op2_denormd_
393: movb true,signal_d_error_
394: cmp $0,expon1(%ebp)
395: jne op2_denormd_
396: movl $1,expon1(%ebp)
397: op2_denormd_:
398: cmpb denormd,tag2(%ebp)
399: jne ordered_cases
400: movb true,signal_d_error_
401: cmp $0,expon2(%ebp)
402: jne ordered_cases
403: movl $1,expon2(%ebp)
404: ordered_cases:
405: movb $sub_op,operation_type(%ebp) // subtract op2 from op1
406: call subadd
407: mov $offset_result,%edi // detect a zero fraction
408: call test_6w // in result
409: jz operands_equal
410: andb $~(zero_mask+sign_mask),%gs:sr_flags // set zero to false
411: testb $0x01,result_sign(%ebp) // set sign to result
412: jz finish_up
413: orb $sign_mask,%gs:sr_flags
414: finish_up:
415: cmp $0,before_error_signals(%ebp)
416: jne check_i_error
417: jmp pop_free
418: ALIGN
419: check_i_error:
420: cmpb false,signal_i_error_ // recall that false = 00h
421: je set_denorm_error
422: test_invalid_mask:
423: testb invalid_mask,%gs:sr_masks
424: jz unmasked_exit
425: jmp pop_free
426: ALIGN
427: unmasked_exit:
428: ret
429: ALIGN
430: check_d_error:
431: cmpb false,signal_d_error_ // recall that false = 00h
432: jne set_denorm_error
433: jmp pop_free
434: ALIGN
435: set_denorm_error:
436: orb denorm_mask,%gs:sr_errors
437: test_denorm_mask:
438: testb denorm_mask,%gs:sr_masks
439: jz unmasked_exit
440: jmp pop_free
441: ALIGN
442:
443: invalid_error_detected:
444: orb invalid_mask,%gs:sr_errors
445: invalid_error_signal:
446: movl $0x000000ff,before_error_signals(%ebp)
447: jmp set_uncertain
448: ALIGN
449:
450: also_d_error_:
451: cmpb denormd,tag1(%ebp)
452: je d_error_also
453: cmpb denormd,tag2(%ebp)
454: jne set_uncertain
455: d_error_also:
456: movb true, signal_d_error_
457: set_uncertain:
458: orb $(sign_mask + c_mask), %gs:sr_flags
459: jmp zero_true // set zero to true
460: ALIGN
461: operands_equal:
462: andb $~sign_mask,%gs:sr_flags // set sign positive
463: zero_true:
464: orb $zero_mask,%gs:sr_flags
465: jmp finish_up
466: //compar endp
467: //
468: //a_med ends
469: //
470: // end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.