|
|
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 "remsc.s"
26:
27: .ident "@(#)kern-fp:remsc.s 1.1"
28:
29: // ********************************************************************
30: //
31: // r e m s c . 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: // functions:
43: // implements 80387 fprem instruction.
44: // implements 80387 fprem1 instruction.
45: // implements 80387 fscale instruction.
46: //
47: // public procedures:
48: // remr scale
49: // add_to_frac add_to_frac_2
50: //
51: // internal procedures:
52: // remrx
53: //
54: // ************************************************************************
55: //
56: //...March 3, 1987...
57: //
58: //
59: //$nolist
60: #include "fp_e80387.h"
61: //$list
62: .data //a_msr segment rw public
63: // extrn %gs:sr_masks,%gs:sr_flags,%gs:sr_errors,%gs:sr_controls
64: //a_msr ends
65: //
66: // assume %ds:a_msr
67: //
68: .text //a_med segment er public
69: //
70: // extrn put_result,set_up_indefinite,test_4w
71: // extrn subtraction_normalize,move_op_to_result
72: // extrn underflow_response,right_shift_frac1_cl
73: // extrn right_shift_frac2_cl,left_shift_frac1_1
74: // extrn fix32,overflow_response,set_stk_u_error
75: // extrn subadd,put_arith_result,set_up_nan_return
76: // extrn test_6w,clear_6w,norm_denorm
77: // extrn left_shift_frac2_cl
78: .globl remr
79: .globl add_to_frac
80: .globl add_to_frac_2
81: .globl scale
82: .globl remrx
83: //
84: // ***************************************************************************
85: // remrx:
86: // ******
87: // function:
88: // fractional remainder.
89: //
90: // inputs:
91: // assumes dividend is in op1, divisor is in op2,
92: // number of quotient bits to generate is in ax,
93: // and q is cleared to all zeroes.
94: //
95: // outputs:
96: // it returns the fractional remainder in op1, and
97: // the low bits of the quotient in q.
98: //
99: // data accessed:
100: // - offset_operand1 offset_operand2
101: // - offset_result
102: //
103: // data changed:
104: // - frac1 frac2
105: //
106: // procedures called:
107: // right_shift_frac1_cl right_shift_frac2_cl
108: // left_shift_frac1_1 add_to_frac
109: //
110: // ************************************************************************
111: ALIGN
112: remrx: //proc
113: push %eax // save the loop count
114: movb $1,%cl // shift frac1 right 1 bit
115: call right_shift_frac1_cl
116: movb $1,%cl // shift frac2 right 1 bit
117: call right_shift_frac2_cl // returns cf clear, ch = 0
118: mov $offset_operand2,%esi // result_frac <-- - frac2
119: mov $offset_result,%edi
120: movw $0,(%ebp,%esi) // clear extra bytes
121: mov $0x03,%ecx // load loop count
122: FALLSTHRU
123: complement_frac2:
124: mov $0x0000,%eax // clear ax, leave cf intact
125: sbb (%ebp,%esi),%eax // 0 - frac2
126: mov %eax,(%ebp,%edi) // store into result frac
127: inc %esi // bump offsets
128: inc %esi // (doesnt affect cf)
129: inc %esi
130: inc %esi
131: inc %edi
132: inc %edi
133: inc %edi
134: inc %edi
135: LOOP(complement_frac2) // loop until result = -frac2
136: jmp enter_loop
137: ALIGN
138: form_next_frac1:
139: push %ecx // stack loop count
140: call left_shift_frac1_1 // shift frac1 left one bit
141: mov $offset_operand2,%esi
142: testb $0x01,q // if lsb of q = 1 then
143: jz do_add // frac1 <-- frac1 + frac2
144: enter_loop:
145: mov $offset_result,%esi // else, frac1 <-- frac1 - frac2
146: do_add:
147: mov $offset_operand1,%edi
148: call add_to_frac // move carry-out from add
149: rclb $1,q // shift carry-out into q
150: // adc hi_q, 0 ; hi_q counts non-0 quotient bits
151: pop %ecx // above bit b7 of the quotient.
152: LOOP(form_next_frac1) // if looping done,
153: testb $0x01,q // then one last iteration
154: jnz last_shift // frac1 <-- frac1 + frac2
155: mov $offset_operand2,%esi
156: mov $offset_operand1,%edi
157: call add_to_frac
158: last_shift:
159: jmp left_shift_frac1_1 // shift frac1 left 1 bit
160: //remrx endp
161: //
162: // **************************************************************************
163: // add_to_frac:
164: // ***********
165: // function:
166: // adds a 10-byte fraction to another 10-byte fraction.
167: //
168: // inputs:
169: // ss:ebp+esi points to the source fraction, and ss:ebp+edi points
170: // to the destination fraction.
171: //
172: // outputs:
173: // carry flag set if there was a carry out, else reset.
174: //
175: // data accessed:
176: //
177: // data changed:
178: //
179: // ***************************************************************************
180: ALIGN
181: add_to_frac: //proc
182: mov (%ebp,%esi),%eax
183: xorw %ax,%ax
184: add_to_frac_2:
185: add %eax,(%ebp,%edi)
186: mov frac64(%ebp,%esi),%eax
187: adc %eax,frac64(%ebp,%edi)
188: mov frac32(%ebp,%esi),%eax
189: adc %eax,frac32(%ebp,%edi)
190: simple_return:
191: ret
192: ALIGN
193: //add_to_frac endp
194: // *************************************************************************
195: ALIGN
196: mov_esi_edi: //proc
197: add %ebp, %edi //add global record offsets
198: add %ebp, %esi
199: // push %ds //save a_msr ??
200: // push %ss //load source segment register
201: // pop %ds
202: // push %ss //load destination segment register
203: // pop %es //into es
204:
205: /* FAST_MOVSL */
206: movl %ss:0(%esi),%ecx
207: movl %ecx,%ss:0(%esi)
208: movl %ss:4(%esi),%ecx
209: movl %ecx,%ss:4(%esi)
210: movl %ss:8(%esi),%ecx
211: movl %ecx,%ss:8(%esi)
212: // addl $12,%esi
213: // addl $12,%edi
214: // movl $0,%ecx
215:
216: // pop %ds //reload a_msr
217: ret
218: //mov_esi_edi endp
219: // *************************************************************************
220:
221:
222: //
223: // ***************************************************************************
224: // remr:
225: // *****
226: // function:
227: // 80387 remainder instruction
228: //
229: // inputs:
230: // assumes the operand records are set up.
231: //
232: // outputs:
233: // results in result record.
234: //
235: // data accessed:
236: // - result_rec_offset offset_operand1
237: // - tag1 expon1
238: // - word_frac1 tag2
239: // - expon2 msb_frac2
240: // - offset_result
241: //
242: // data changed:
243: // - tag1 expon1
244: //
245: // procedures called:
246: // set_up_indefinite set_stk_u_error
247: // remrx subtraction_normalize
248: // move_op_to_result underflow_response
249: // put_result test_4w
250: // subadd mov_esi_edi
251: //
252: // ***************************************************************************
253: ALIGN
254: remr: //proc
255: lahf // save stack empty flag (86 z-flag)
256: andb $~(a_mask+c_mask),%gs:sr_flags// clear 87 a-flag, and also
257: // c-flag for 387 compatibility
258: movw $0,exp_tmp // initialize q and hi_q to 0.
259: sahf // restore stack empty flag (86 z-flag)
260: jz catch_special_cases // branch if no stack error
261: call set_stk_u_error // stack underflow occurred
262: jmp unmasked_i_error_
263: ALIGN
264: catch_special_cases:
265: movb tag1(%ebp),%al // both operands valid?
266: orb tag2(%ebp),%al
267: jnz special_cases_handler // no, branch to handler of special cases
268: valid_case:
269: mov dword_expon1,%eax // eax <- expon_diff = exp1 - exp2
270: sub dword_expon2,%eax // if expon_diff < zero,
271: mov $offset_operand1,%edi // then op1 is the modulus
272: jl rem_or_mod_
273: cmp $63,%eax // if expon_diff > 63,
274: jle calc_exponent // then set c-bit for incomplete
275: orb $c_mask,%gs:sr_flags // reduction and replace expon_diff
276: or $32,%eax // by ((expon_diff or 32) mod 64)
277: and $63,%eax
278: calc_exponent:
279: sub %eax,dword_expon1 // expon1 <- remainder exponent
280: inc %eax // num_quotient_bits = expon_diff + 1
281: call remrx // calculate remainder fraction
282: xor %eax,%eax // detect zero result
283: mov $dword_frac1+frac64,%edi
284: call test_4w
285: jnz do_normalize
286: testb $c_mask,%gs:sr_flags // was reduction complete?
287: jz remr_zero // if so, process q as well
288: movb %al,q // else, make q 0 (value of al)
289: jmp remr_zero
290: ALIGN
291: do_normalize:
292: mov $offset_operand1,%edi
293: call subtraction_normalize
294: // mov (ebp).tag1, valid ; unneeded if denormals retagged
295: reduction_incomplete_:
296: testb $c_mask,%gs:sr_flags
297: jz rem_or_mod_ // rem or mod matters only if complete
298: movb $0,q // if incomplete, make q 0.
299: jmp check_rem_underflow // branch to check unmasked underflow
300: ALIGN
301: rem_or_mod_:
302: lahf //save zf to indicate whether
303: //op2 needs restoration
304: cmpb $rem1_op,operation_type(%ebp)
305: jne check_rem_underflow
306: sahf
307: jnz op2_restored
308: movb $1, %cl
309: call left_shift_frac2_cl
310: op2_restored:
311:
312: decl dword_expon2
313: push sign1(%ebp)
314: movb positive,sign2(%ebp)
315: movb positive,sign1(%ebp)
316: movb $sub_op,operation_type(%ebp)
317: mov dword_expon1, %eax
318: cmp dword_expon2, %eax
319: mov $offset_operand1, %esi
320: jle save_shiftable_op
321: mov $offset_operand2, %esi
322: save_shiftable_op:
323: mov $offset_cop, %edi
324: call mov_esi_edi
325: call subadd
326: mov $offset_result,%edi
327: call test_6w
328: pop sign1(%ebp)
329: mov $offset_operand1, %edi
330: jnz check_sign
331: tiebreaker:
332: testb $1,q
333: jz check_rem_underflow
334: incb q
335: notb sign1(%ebp)
336: jmp check_rem_underflow
337: ALIGN
338: check_sign:
339: mov $offset_cop, %esi
340: cmpb positive,result_sign(%ebp)
341: je restore_op2_
342: call mov_esi_edi
343: mov $offset_operand1, %edi
344: jmp check_rem_underflow
345: ALIGN
346: restore_op2_:
347: mov dword_expon1, %eax
348: cmp dword_expon2, %eax
349: je reduce_modulus
350: mov $offset_operand2, %edi
351: call mov_esi_edi
352: reduce_modulus:
353: incb q
354: incl dword_expon2
355: movb sign1(%ebp),%al
356: movb %al,sign2(%ebp)
357: call subadd
358: mov $offset_result,%edi
359: check_rem_underflow:
360: cmp $0x0001,expon(%ebp,%edi) // if expon1 < 1, then underflow
361: jge do_put_result
362: mov %edi,%esi // give std underflow response
363: call move_op_to_result
364: push %gs:sr_masks
365: orb prec64,%gs:sr_controls // *or* works only because prec64
366: movb false,rnd1_inexact // sets all bits in the pc field
367: call underflow_response
368: pop %gs:sr_masks
369: move_result_to_result:
370: mov $offset_result,%edi
371: jmp do_put_result
372: ALIGN
373: remr_zero:
374: mov %eax,dword_expon1 // if remainder fraction = 0,
375: movb special,tag1(%ebp) // then set result to 0
376: cmpb $rem1_op,operation_type(%ebp)
377: jne put_op1
378: movb positive,sign1(%ebp)
379: testb rnd_down,%gs:sr_controls
380: jz put_op1
381: testb rnd_up,%gs:sr_controls
382: jnz put_op1
383: movb negative,sign1(%ebp)
384: put_op1:
385: mov $offset_operand1,%edi
386: do_put_result:
387: mov offset_result_rec,%esi
388: call put_result
389: andb $~(zero_mask+a_mask+sign_mask),%gs:sr_flags
390: movb q,%al
391: shlb $6,%al // move 3 low bits of q to
392: jnc fix_z_bit // s, z, and a bits
393: orb $sign_mask,%gs:sr_flags
394: fix_z_bit:
395: shlb $1,%al
396: jnc fix_a_bit
397: orb $zero_mask,%gs:sr_flags
398: fix_a_bit:
399: shlb $1,%al
400: jnc remr_done
401: orb $a_mask,%gs:sr_flags
402: remr_done:
403: ret
404: ALIGN
405: special_cases_handler:
406: testb $0x10,%al // al contains (ebp).tag1 or (ebp).tag2
407: jz op1_nan_ // no branch if at least one op unsupported
408: invalid_operand:
409: orb invalid_mask,%gs:sr_errors
410: unmasked_i_error_:
411: testb invalid_mask,%gs:sr_masks// if unmasked, just exit
412: jz remr_done // (c-bit remains clear here,
413: // to indicate complete reduction.)
414: // else, return indefinite
415: remr_indef:
416: mov $offset_operand1,%edi
417: call set_up_indefinite
418: load_esi_for_result:
419: mov offset_result_rec,%esi
420: jmp put_arith_result
421: ALIGN
422: op1_nan_: // here, neither op is unsupported.
423: movb tag2(%ebp),%al
424: movb tag1(%ebp),%ah
425: cmpb inv,%ah
426: je op1_snan_
427: cmpb inv,%al
428: jne non_nan_supp_ops
429: jmp signal_invalid_
430: ALIGN
431: op1_snan_:
432: testb $0x40,msb_frac1
433: jz signal_for_snan
434: op2_also_nan_:
435: cmpb inv,%al
436: jne jmp_set_up_nan_return
437: signal_invalid_:
438: testb $0x40,msb_frac2
439: jnz jmp_set_up_nan_return
440: signal_for_snan:
441: orb invalid_mask,%gs:sr_errors// set i-error for signaling nan operand
442: testb invalid_mask,%gs:sr_masks// if unmasked, return forthwith
443: jz remr_done // else, masked, so return max nan.
444: jmp_set_up_nan_return:
445: jmp set_up_nan_return
446: ALIGN
447: non_nan_supp_ops:
448: cmpb $scale_op,operation_type(%ebp)
449: je scale_non_nan_supp_ops
450: rem_non_nan_supp_ops:
451: cmpb infinty,%ah
452: je invalid_operand
453: cmpb special,%al
454: je invalid_operand
455: cmpb denormd,%ah
456: jne op2_denorm_
457: orb denorm_mask,%gs:sr_errors
458: testb denorm_mask,%gs:sr_masks
459: jz remr_done
460: mov $offset_operand1,%edi
461: cmpb infinty,%al
462: jne norm_op1
463: testb $0x80,msb_frac1
464: jz op1_true_denormal
465: movl $1,dword_expon1
466: movb valid,tag1(%ebp)
467: jmp load_esi_for_result
468: ALIGN
469: op1_true_denormal:
470: testb underflow_mask,%gs:sr_masks
471: jnz load_esi_for_result
472: call norm_denorm
473: addl wrap_around_constant,dword_expon1// add wrap-around
474: orb underflow_mask,%gs:sr_errors
475: jmp load_esi_for_result
476: ALIGN
477: norm_op1:
478: push %eax
479: call norm_denorm
480: pop %eax
481: op2_denorm_:
482: cmpb denormd,%al
483: jne non_error_specials
484: orb denorm_mask,%gs:sr_errors
485: testb denorm_mask,%gs:sr_masks
486: jz remr_done
487: mov $offset_operand2,%edi
488: push %eax
489: call norm_denorm
490: pop %eax
491: non_error_specials:
492: cmpb special,%ah
493: je put_op1
494: op2_inf_:
495: cmpb infinty,%al
496: je put_op1
497: jmp valid_case
498: ALIGN
499: //
500: scale_non_nan_supp_ops:
501: cmpb infinty,%ah
502: jne scaler_denormd_
503: cmpb positive,sign1(%ebp)
504: jne op2_also_inf_
505: cmpb special,%al
506: je invalid_operand
507: cmpb denormd,%al
508: jne xfer_sign
509: orb denorm_mask,%gs:sr_errors
510: testb denorm_mask,%gs:sr_masks
511: jz exit_scale
512: xfer_sign:
513: movb sign2(%ebp),%al
514: movb %al,sign1(%ebp)
515: mov $offset_operand1,%edi
516: jmp put_scaled_result
517: ALIGN
518: op2_also_inf_:
519: cmpb infinty,%al
520: je invalid_operand
521: cmpb denormd,%al
522: jne zero_op2
523: orb denorm_mask,%gs:sr_errors
524: testb denorm_mask,%gs:sr_masks
525: jz exit_scale
526: zero_op2:
527: mov $offset_operand2,%edi
528: call clear_6w
529: mov %eax,dword_expon2 // clear eax
530: movb special,tag2(%ebp)
531: jmp put_scaled_result
532: ALIGN
533: scaler_denormd_:
534: cmpb denormd,%ah
535: jne scalend_denormd_
536: orb denorm_mask,%gs:sr_errors
537: testb denorm_mask,%gs:sr_masks
538: jnz scalend_denormd_
539: exit_scale:
540: ret
541: ALIGN
542: scalend_denormd_:
543: cmpb denormd,%al
544: jne give_op2
545: orb denorm_mask, %gs:sr_errors
546: testb denorm_mask, %gs:sr_masks
547: jz exit_scale
548: cmpb valid,%ah
549: jne check_unfl_mask
550: mov $offset_operand2,%edi
551: call norm_denorm
552: jmp valid_scale_case
553: ALIGN
554: check_unfl_mask:
555: testb underflow_mask,%gs:sr_masks
556: jnz give_op2
557: jmp scale_underflow
558:
559: //remr endp
560: //
561: //
562: // **********************************************************************
563: // scale:
564: // ******
565: // function:
566: // emulates the 80387 scale instruction.
567: //
568: // inputs:
569: // scale term (scaler) from st(1) in operand1, and
570: // scalend (*to be scaled*) from st(0) in operand2
571: //
572: // outputs:
573: // scaled operand in operand2 record or result_record.
574: // error indicators set.
575: //
576: // data accessed:
577: // - result_rec_offset tag1
578: // - word_frac1 offset_operand2
579: // - tag2 expon2
580: // - offset_result extra_word_reg
581: //
582: // data changed:
583: // - expon2
584: //
585: // procedures called:
586: // set_up_indefinite fix32 put_result
587: // move_op_to_result underflow_response
588: // overflow_response
589: //
590: // *************************************************************************
591: ALIGN
592: scale: //proc
593: jz catch_spcl_scale_cases // branch if no stack error
594: call set_stk_u_error // stack underflow occurred
595: jmp unmasked_i_error_
596: ALIGN
597: catch_spcl_scale_cases:
598: andb $~(a_mask),%gs:sr_flags// clear 87 a-bit
599: movb tag1(%ebp),%al // both operands valid?
600: orb tag2(%ebp),%al
601: jnz special_cases_handler // no, branch to handler of special cases
602: valid_scale_case:
603: push %gs:sr_masks // save current rounding controls
604: orb rnd_to_zero,%gs:sr_controls // institute round by chopping
605: // this *or* works only because
606: // rnd_to_zero sets entire rc field
607: call fix32 // convert scale factor to int32
608: pop %gs:sr_masks // restore rnd control
609: jz add_scale_term // if zf=1, no overflow in fix32
610: cmpb positive,sign1(%ebp)
611: je get_least_sf_xtrm_ovfl
612: jmp get_grtst_sf_xtrm_unfl
613: ALIGN
614: add_scale_term:
615: mov dword_frac1+frac32(%ebp),%eax // int32 scale factor
616: cmp least_sf_xtrm_ovfl,%eax
617: jle check_xtrm_unfl
618: get_least_sf_xtrm_ovfl:
619: mov least_sf_xtrm_ovfl,%eax
620: jmp add_int32_to_dword_exp
621: ALIGN
622: check_xtrm_unfl:
623: cmp grtst_sf_xtrm_unfl,%eax
624: jge add_int32_to_dword_exp
625: get_grtst_sf_xtrm_unfl:
626: mov grtst_sf_xtrm_unfl,%eax
627: add_int32_to_dword_exp:
628: add %eax,dword_expon2 // add scale term to op2s expon
629: cmpl $0x7ffe,dword_expon2
630: jg scale_overflow
631: cmp $1,dword_expon2
632: jl scale_underflow
633: give_op2:
634: mov $offset_operand2,%edi
635: put_scaled_result:
636: mov offset_result_rec,%esi
637: jmp put_result
638: ALIGN
639: scale_overflow:
640: mov $offset_operand2,%esi // move op2 to result
641: call move_op_to_result
642: call overflow_response
643: jmp set_up_result
644: ALIGN
645: scale_underflow:
646: mov $offset_operand2,%esi // move op2 to result
647: call move_op_to_result
648: push %gs:sr_masks
649: orb prec64,%gs:sr_controls // *or* works only because prec64
650: movb false,rnd1_inexact // sets all bits in the pc field
651: call underflow_response
652: pop %gs:sr_masks
653: set_up_result:
654: mov $offset_result,%edi
655: jmp put_scaled_result
656: ALIGN
657: //scale endp
658: //
659: //a_med ends
660: //
661: // end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.