|
|
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 "round.s"
26:
27: .ident "@(#)kern-fp:round.s 1.1"
28:
29: //$tt(*80387 emulator + + + r o u n d + + + *)
30: // **********************************************************************
31: //
32: // r o u n d . m o d
33: // =================
34: //
35: // ===============================================================
36: // intel corporation proprietary information
37: // this software is supplied under the terms of a license
38: // agreement or non-disclosure agreement with intel corporation
39: // and may not be copied nor disclosed except in accordance with
40: // the terms of that agreement.
41: // ===============================================================
42: //
43: // function:
44: // implements all rounding modes for all precisions
45: //
46: // public procedures:
47: // round special_round_test
48: // directed_round_test
49: //
50: // internal procedures:
51: // prec16_case prec24_case
52: // prec32_case prec53_case
53: // prec64_case
54: //
55: // ***************************************************************************
56: //
57: //...october 31, 1986...
58: //
59: // .file *a_mro*
60: //
61: //$nolist
62: #include "fp_e80387.h"
63: //$list
64: //...declare status register segment...
65: //
66: .data //a_msr segment rw public
67: // extrn %gs:sr_flags
68: //a_msr ends
69: //
70: // assume %ds:a_msr
71: //
72: .text //a_med segment er public
73: //
74: // extrn get_rnd_control
75: //
76: .globl round
77: .globl directed_round_test
78: .globl special_round_test
79: //
80: // ***********************************************************************
81: // prec16_case:
82: // ************
83: // function:
84: // sets up for rounding to 16 bits.
85: //
86: // inputs:
87: // assumes edi points to operand record.
88: //
89: // outputs:
90: // sets: dl if round or sticky bit set
91: // dh if guard bit set
92: // ah if lsb set
93: // cl to number of rounded bytes
94: // ch to pattern to add to low byte for rounding
95: // and clears the guard, round, and sticky bytes.
96: // doesnt affect al.
97: //
98: // data accessed:
99: //
100: // data changed:
101: //
102: // procecures called:
103: //
104: // *************************************************************************
105: ALIGN
106: prec16_case: //proc ; initially, assume all guard,
107: xchg frac80+4(%ebp,%edi),%ecx// round, and sticky info zero
108: and %ecx,%ecx // examine and clear grst word
109: jns get_round_sticky_16
110: notb %dh // et guard byte
111: get_round_sticky_16:
112: and $0x7fffffff,%ecx
113: or frac80(%ebp,%edi),%ecx
114: orw (%ebp,%edi),%cx
115: jz get_lsb_16
116: notb %dl // set round-sticky byte
117: get_lsb_16:
118: xorb %ah,%ah // initially, assume lsb is zero
119: testb $0x01,frac80+8(%ebp,%edi)
120: jz set_rnd_info_16
121: notb %ah // set lsb byte
122: movl $0,frac80(%ebp,%edi)
123: movw $0,(%ebp,%edi)
124: set_rnd_info_16:
125: mov $0x0102,%ecx // the rounded result has 2 bytes
126: ret // the pattern to add is 01h
127: //prec16_case endp
128: //
129: // *************************************************************************
130: // prec24_case:
131: // ************
132: // function:
133: // sets up for rounding to 24 bits.
134: //
135: // inputs:
136: // assumes edi points to operand record.
137: //
138: // outputs:
139: // sets: dl if round or sticky bit set
140: // dh if guard bit set
141: // ah if lsb set
142: // cl to number of rounded bytes
143: // ch to pattern to add to low byte for rounding
144: // and clears the guard, round, and sticky bytes.
145: // doesnt affect al.
146: //
147: // data accessed:
148: //
149: // data changed:
150: //
151: // *************************************************************************
152: ALIGN
153: prec24_case: //proc ; initially, assume all guard,
154: xchgb frac32(%ebp,%edi),%cl // round, and sticky info zero
155: andb %cl,%cl // examine and clear grst word
156: jns get_round_sticky_24
157: notb %dh // set guard byte
158: get_round_sticky_24:
159: andb $0x7f,%cl
160: or frac64(%ebp,%edi),%ecx
161: or (%ebp,%edi),%ecx
162: jz get_lsb_24
163: notb %dl // set round-sticky byte
164: get_lsb_24:
165: xorb %ah,%ah // initially, assume lsb is zero
166: testb $0x01,frac32+1(%ebp,%edi)
167: jz clear_sticky_bytes_24
168: notb %ah // set lsb byte
169: clear_sticky_bytes_24:
170: movl $0,frac64(%ebp,%edi)
171: movl $0,(%ebp,%edi)
172: mov $0x0103,%ecx // the rounded result has 3 bytes
173: ret // the pattern to add is 01h
174: //prec24_case endp
175: //
176: // *****************************************************************************
177: // prec32_case:
178: // ************
179: // function:
180: // sets up for rounding to 32 bits.
181: //
182: // inputs:
183: // assumes edi points to operand record.
184: //
185: // outputs:
186: // sets: dl if round or sticky bit set
187: // dh if guard bit set
188: // ah if lsb set
189: // cl to number of rounded bytes
190: // ch to pattern to add to low byte for rounding
191: // and clears the guard, round, and sticky bytes.
192: // doesnt affect al.
193: //
194: // data accessed:
195: //
196: // data changed:
197: //
198: // *************************************************************************
199: ALIGN
200: prec32_case: //proc ; initially, assume all guard,
201: xchg frac64(%ebp,%edi),%ecx // round, and sticky info zero
202: and %ecx,%ecx
203: jns get_round_sticky_32
204: notb %dh // set guard byte
205: get_round_sticky_32:
206: and $0x7fffffff,%ecx
207: or (%ebp,%edi),%ecx
208: jz get_lsb_32
209: notb %dl // set round-sticky byte
210: get_lsb_32:
211: xorb %ah,%ah // initially, assume lsb is zero
212: testb $0x01,frac32(%ebp,%edi)
213: jz clear_sticky_bytes_32
214: not_ah_clear_32:
215: notb %ah // set lsb byte
216: clear_sticky_bytes_32:
217: movl $0,(%ebp,%edi)
218: mov $0x0104,%ecx// the rounded result has 4 bytes
219: ret // the pattern to add is 01h
220: //prec32_case endp
221: //
222: // ***********************************************************************
223: // prec53_case:
224: // ***********
225: // function:
226: // sets up for rounding to 53 bits.
227: //
228: // inputs:
229: // assumes edi points to operand record.
230: //
231: // outputs:
232: // sets: dl if round or sticky bit set
233: // dh if guard bit set
234: // ah if lsb set
235: // cl to number of rounded bytes
236: // ch to pattern to add to low byte for rounding
237: // and clears the guard, round, and sticky bytes.
238: // doesnt affect al.
239: //
240: // data accessed:
241: //
242: // data changed:
243: //
244: // ***************************************************************************
245: ALIGN
246: prec53_case: //proc ; initially, assume all guard,
247: mov frac64(%ebp,%edi),%ecx // round, and sticky info zero
248: testb $0x04,%ch // examine guard bit
249: jz get_round_sticky_53
250: notb %dh // set guard byte
251: get_round_sticky_53:
252: and $0x03ff,%ecx
253: or (%ebp,%edi),%ecx
254: jz get_lsb_53
255: notb %dl // set round-sticky byte
256: get_lsb_53:
257: xorb %ah,%ah // initially, assume lsb is zero
258: testb $0x08,frac64+1(%ebp,%edi)
259: jz clear_grst_bits_53
260: notb %ah // set lsb byte
261: clear_grst_bits_53:
262: movl $0,(%ebp,%edi)
263: andw $0x0f800,frac64(%ebp,%edi)
264: mov $0x0807,%ecx// the rounded result has 7 bytes
265: ret // the pattern to add is 08h
266: //prec53_case endp
267: //
268: // ****************************************************************************
269: // prec64_case:
270: // ************
271: // function:
272: // sets up for rounding to 64 bits.
273: //
274: // inputs:
275: // assumes edi points to operand record.
276: //
277: // outputs:
278: // sets: dl if round or sticky bit set
279: // dh if guard bit set
280: // ah if lsb set
281: // cl to number of rounded bytes
282: // ch to pattern to add to low byte for rounding
283: // and clears the guard, round, and sticky bytes.
284: // doesnt affect al.
285: //
286: // data accessed:
287: //
288: // data changed:
289: //
290: // *************************************************************************
291: ALIGN
292: prec64_case: //proc ; initially assume all guard,
293: xchg (%ebp,%edi),%ecx // round, and sticky info zero
294: and %ecx,%ecx // examine and clear grst word
295: jns get_round_sticky_64
296: notb %dh // set guard byte
297: get_round_sticky_64:
298: and $0x7fffffff,%ecx
299: jz get_lsb_64
300: notb %dl // set round-sticky byte
301: get_lsb_64:
302: xorb %ah,%ah // initially, assume lsb is zero
303: testb $0x01,frac64(%ebp,%edi)
304: jz set_round_info_64
305: notb %ah // set lsb byte
306: set_round_info_64:
307: mov $0x0108,%ecx // rounded result has 8 bytes
308: common_return:
309: ret // the pattern to add is 01h
310: //prec64_case endp
311: //
312: // **********************************************************************
313: // round:
314: // *****
315: // function:
316: // implements rounding.
317: //
318: // inputs:
319: // assumes: edi points to record to round,
320: // dl contains rounding precision,
321: // al is true if second rounding, false if first.
322: //
323: // outputs:
324: // on return, al is true if there was an high-bit carry-out
325: // as a result of incrementing the significand to do the rounding.
326: //
327: // data accessed:
328: // added_one
329: //
330: // data changed:
331: // added_one
332: //
333: // procedures called:
334: // prec16_case prec24_case
335: // prec32_case prec53_case
336: // prec64_case get_rnd_control
337: //
338: // ************************************************************************
339: precn_case:
340: .long prec24_case,prec32_case,prec53_case,prec64_case,prec16_case
341: //
342: rnd_case:
343: .long case_rnd_to_even,case_rnd_down,case_rnd_up,case_rnd_to_zero
344: //
345: ALIGN
346: round: //proc ; access unpacked status info
347: xorb %dh,%dh // set to zero the following:
348: movswl %dx,%esi // cl to num bytes in rnd frac
349: shl $2,%esi // ch to pattern to add to low
350: xorw %dx,%dx // byte in rounding
351: xor %ecx,%ecx // dl if round or sticky set
352: // mov (ebp+edi),dx ;*** zeroing low word
353: call *%cs:precn_case(%esi) // dh if grd set, ah if lsb set
354: andw %dx,%dx // if dl and dh both zero, then
355: jnz inexact_case // result is exact
356: cmpb true,%al
357: movb %dl,%al // no carry out from rounding
358: jne exact_1st_rnd
359: movb %al,rnd2_inexact
360: ret
361: ALIGN
362: exact_1st_rnd:
363: movw %dx,rnd_history
364: movb %al,added_one // clear flag, no overflow
365: ret
366: ALIGN
367: //
368: inexact_case:
369: cmpb true,%al
370: jne inexact_1st_rnd
371: movb %al,rnd2_inexact
372: jmp get_rnd_case
373: ALIGN
374: inexact_1st_rnd:
375: movw true,rnd_history// makes rnd1_inexact true, rnd2_inexact false
376: get_rnd_case:
377: push %eax // save lsb/2nd rounding flags
378: call get_rnd_control // round different rnd_control
379: movzbl %al,%ebx // cases separately
380: pop %eax // reload lsb/2nd rounding flags
381: jmp *%cs:rnd_case(%ebx)
382: ALIGN
383: case_rnd_up:
384: notb %bh //if + increment, else truncate
385: case_rnd_down:
386: cmpb %bh,sign(%ebp,%edi) //increment if neg,
387: jne do_increment // truncate if pos
388: jmp case_rnd_to_zero
389: ALIGN
390: case_rnd_to_even:
391: movb %dl,%bh // save round-sticky info in bh
392: orb %ah,%dl // if guard and (round or sticky
393: cmpb true,%al // or lsb), set dx to round up
394: jne do_add_ // if 2nd round, if ((lsb=added)
395: // mov bl, added_one ; and not (round or sticky)
396: // cmp al, rnd1_inexact ; and ((added=1) or last round
397: // jne p_error_0 ; inexact)), round in opposite
398: // mov bl, al ; al is true (0ffh), hence so is bl
399: // the preceding four instructions are equivalent to the next one
400: movb rnd1_inexact,%bl
401: p_error_0:
402: cmpw $0x00ff,%bx // unless first round was inexact and
403: jne do_add_ // current round-sticky bits are clear,
404: // decide how to round as for first round
405: cmpb added_one,%ah // else, dh (guard) must be true here because
406: // exact second rounds were ruled out earlier
407: jne do_add_ // branch if ah <> added_one
408: incw %dx // here, dh = guard, dl = lsb
409: jz case_rnd_to_zero // truncate
410: jmp do_increment
411: ALIGN
412: do_add_:
413: incw %dx
414: jz do_increment
415: case_rnd_to_zero:
416: movb false,%al // clear flag, indicate nothing
417: movb %al,added_one // added in round (al = false)
418: // and %gs:sr_flags,not a_mask ; clear the a-bit ---> defer
419: jmp set_inexact
420: ALIGN
421: do_increment:
422: // or %gs:sr_flags,a_mask ; set the a-bit ---> defer
423: movb true,added_one // set flag for 1 added in round
424: movb %ch,%dl // put pattern to add in dl
425: xorb %ch,%ch // ecx = num bytes in rounded res
426: mov $12,%ebx
427: sub %ecx,%ebx // ebx = num of low byte
428: add %ebx,%edi // edi = true offset
429: xorb %al,%al
430: addb %dl,(%ebp,%edi) // add pattern to low byte and
431: inc %edi // propogate carries
432: dec %ecx
433: FALLSTHRU
434: inc_loop:
435: adcb %al,(%ebp,%edi)
436: inc %edi
437: LOOP(inc_loop)
438: sbbb %al,%al // set al if carry set
439: sub $12,%edi // restore edi to entry value
440: set_inexact:
441: // jmp set_p_error ---> defer
442: ret
443: //round endp
444: //
445: // ****************************************************************************
446: // special_round_test:
447: // ******************
448: // function:
449: // test for rounding toward zero.
450: //
451: // inputs:
452: // assumes sign to be in al upon entry.
453: //
454: // outputs:
455: // returns true (in al) and clears zf if:
456: // (rnd_down and sign is positive) or
457: // (rnd_up and sign is negative);
458: // else returns false (in al) and sets zf.
459: //
460: // data accessed:
461: //
462: // data changed:
463: //
464: // procedures called:
465: // get_rnd_control
466: //
467: // **************************************************************************
468: ALIGN
469: special_round_test: //proc
470: movb %al,%ah // save sign
471: call get_rnd_control //get rounding mode
472: cmpb rnd_down,%al
473: jne round_up_ // branch if not down
474: andb %ah,%ah
475: jz is_true // true if +rnd_down
476: is_false:
477: xorb %al,%al // sets zf.
478: ret
479: ALIGN
480: round_up_:
481: cmpb rnd_up,%al
482: jne is_false // branch if not up
483: andb %ah,%ah
484: jz is_false // branch if +rnd_up
485: is_true:
486: orb true,%al // clears zf.
487: exit_round_test:
488: ret
489: //special_round_test endp
490: //
491: // **************************************************************************
492: // directed_round_test:
493: // *******************
494: // function:
495: // test for round control (up or down).
496: //
497: // inputs:
498: // none
499: //
500: // outputs:
501: // returns true (in al) and clears zf if the round control
502: // is rnd_up or rnd_down. otherwise, returns false and sets zf.
503: //
504: // data accessed:
505: //
506: // data changed:
507: //
508: // procedures called:
509: // get_rnd_conrol
510: //
511: // *************************************************************************
512: ALIGN
513: directed_round_test: //proc
514: call get_rnd_control
515: cmpb rnd_down,%al
516: je is_true
517: cmpb rnd_up,%al
518: je is_true
519: jmp is_false
520: //directed_round_test endp
521: //
522: //a_med ends
523: //
524: // end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.