|
|
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 "store.s"
26:
27: .ident "@(#)kern-fp:store.s 1.1"
28:
29: //$tt(*80387 emulator+++s t o r e+++*)
30: // ***************************************************************************
31: //
32: // s t o r e . 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 80387 store, fix, and storex instructions.
45: //
46: // public procedures:
47: // store fix16 fix32 fix64 move_op_to_op
48: //
49: // internal procedures:
50: // extended_store bcd_store
51: // single_real_store double_real_store
52: // store_valid int64_store
53: // int16_store int32_store
54: //
55: // ************************************************************************
56: //
57: //...december 12, 1986..
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 pop_free,clear_6w,test_3w,subadd
71: // extrn gradual_underflow,right_shift_frac2_cl
72: // extrn special_round_test,directed_round_test
73: // extrn right_shift_result_cl,set_up_indefinite
74: // extrn right_shift_frac1_cl,sticky_right_shift
75: // extrn left_shift_frac1_cl,left_shift_result_cl
76: // extrn put_op1_result,divid,addition_normalize
77: // extrn round,get_precision,get_rnd_control
78: // extrn store_precision,set_i_error,i_masked_
79: // extrn set_o_error,o_masked_,set_p_error
80: // extrn set_u_error,test_4w,subtraction_normalize
81: // extrn p_error_,clear_p_error,add_to_frac
82: // extrn move_constant,set_stk_u_error,norm_denorm
83: // extrn %gs:sr_mem_offset
84: // --------to be added for unix
85: //.. extrn fpfulong:far,fpfushort:far,fpsulong:far,fpsushort:far
86: //
87: .globl store
88: .globl fix16
89: .globl fix32
90: .globl fix64
91: .globl move_op_to_op
92: //
93: store_routine:
94: .long single_real_store,double_real_store,int16_store
95: .long int32_store,int64_store,extended_store
96: .long int16_store,int16_store,bcd_store
97: //
98: // *************************************************************************
99: // store:
100: // ******
101: // function:
102: // implements all store instructions .
103: //
104: // inputs:
105: // operand1; format of result.
106: //
107: // outputs:
108: // operand in *result_format* stored in memory
109: // destination pointed to by es:di.
110: //
111: // data accessed:
112: // - result_rec_offset result_format
113: // - offset_operand1
114: //
115: // data changed:
116: // - result record
117: //
118: // procedures called:
119: // set_up_indefinite store routine (result format)
120: // i_masked?
121: //
122: // ****************************************************************************
123: ALIGN
124: store: //proc
125: jz no_unmasked_stack_error // branch if no stack error
126: call set_stk_u_error // stack underflow occurred
127: testb invalid_mask,%gs:sr_masks // if unmasked, just exit
128: jz return // else, store indef set up
129: no_unmasked_stack_error: // in operand1 by fetch_an_op
130: andb $~a_mask,%gs:sr_flags // clear a-bit
131: get_result_loc:
132: cmpb $reg,result_location(%ebp)
133: jne store_to_memory // branch if memop
134: call put_op1_result // give opnd1 as result
135: jmp pop_free
136: ALIGN
137: store_to_memory:
138: movzbl result_format(%ebp),%ebx// call a different rtn
139: shll $2,%ebx // for each of the
140: cmp $8,%ebx
141: jge go_to_storer // do store of temporary real
142: cmpb unsupp,tag1(%ebp) // detect unsupported pattern
143: jne go_to_storer
144: orb invalid_mask,%gs:sr_errors // set i_error
145: testb invalid_mask,%gs:sr_masks // if unmasked, just exit
146: jz return // else, set up indef in
147: mov $offset_operand1,%edi // operand1.
148: call set_up_indefinite
149: go_to_storer:
150: jmp *%cs:store_routine(%ebx) // output formats
151: //store endp
152: //
153: // ****************************************************************************
154: // move_op_to_op:
155: //
156: // function:
157: // moves operand record (op1,op2,result_op,result2_op) to
158: // another op.
159: //
160: // inputs:
161: // ss:esi points to the source, and
162: // ss:edi points to the destination
163: // outputs:
164: // operand record in destination
165: //
166: // data accessed:
167: // operand or result variables
168: //
169: // data changed:
170: // operand or result variables
171: //
172: // *****************************************************************************
173: ALIGN
174: move_op_to_op: //proc
175: // push %ds // save a?msr
176: // push %ss
177: // pop %ds
178: push %ss
179: pop %es
180: mov $((sign2-sign1)>> 2),%ecx / set record length
181:
182: /* FAST_MOVSL */
183: push %eax
184: 1:
185: movl %ss:0(%esi),%eax
186: movl %eax,%es:0(%edi)
187: addl $4,%esi
188: addl $4,%edi
189: decl %ecx
190: testl %ecx,%ecx
191: jg 1b
192:
193: pop %eax
194: // pop %ds // reload a?msr
195: return:
196: ret
197: //move_op_to_op endp
198: //
199: // ***************************************************************************
200: // extended_store:
201: // ***************
202: // function:
203: // stores into double extended format.
204: //
205: // inputs:
206: // operand1
207: //
208: // outputs:
209: // double extended operand in memory.
210: // stack popped if indicated
211: //
212: // data accessed:
213: // - mem_operand_pointer sign1
214: // - expon1 word_frac1
215: //
216: // data changed:
217: //
218: // procedures called:
219: // pop_free
220: //
221: // *****************************************************************************
222: ALIGN
223: extended_store: //proc
224: les mem_operand_pointer(%ebp),%edi //move frac to memory
225: // push %ds // save a?msr
226: // push %ss
227: // pop %ds // set up source pointer
228: lea 2+word_frac1,%esi
229:
230: /* FAST_MOVSL */
231: movl %ss:0(%esi),%ecx
232: movl %ecx,%es:0(%edi)
233: movl %ss:4(%esi),%ecx
234: movl %ecx,%es:4(%edi)
235: // addl $8,%esi
236: // addl $8,%edi
237: // movl $0,%ecx
238:
239: // pop %ds // reload a?msr
240: movb sign1(%ebp),%ah // merge sign & exponent
241: andw $0x8000,%ax // and move to memory
242: orw expon1(%ebp),%ax
243: movw %ax,%es:8(%edi)
244:
245: //..
246: //.. pushad
247: //.. push es
248: //.. push edi
249: //.. push ax
250: //.. call fpsushort
251: //.. add esp,12
252: //.. popad
253: //.. cld
254: jmp pop_free // pop stack, if needed
255: //extended_store endp
256: //
257: // ****************************************************************************
258: // bcd_store:
259: // **********
260: // function:
261: // stores into bcd format
262: //
263: // inputs:
264: // operand1
265: //
266: // outputs:
267: // bcd operand in memory; stack popped
268: //
269: // data accessed:
270: // - mem_operand_pointer operation_type
271: // - offset_operand1 sign1
272: // - tag1 word_frac1
273: // - msb_frac1 offset_operand1
274: // - offset_operand2 sign2
275: // - expon2 word_frac2
276: // - offset_operand2 offset_result
277: // - result_expon result_word_frac
278: // - msb_result offset_result
279: //
280: // data changed:
281: // - operation_type word_frac1
282: // - msb_frac1 sign2
283: // - expon2 word_frac2
284: // - result_word_frac msb_result
285: //
286: // procedures called:
287: // move_op_to_op right_shift_frac1_cl
288: // right_shift_frac2_cl right_shift_result_cl
289: // left_shift_frac1_cl left_shift_result_cl
290: // divid clear_6w
291: // pop_free test_4w
292: // add_to_frac move_constant
293: //
294: // **************************************************************************
295: ten_18:
296: .value 0x0000,0x0000,0x0000,0x7640,0x6b3a,0x0de0b// frac for 10**18
297: //
298: ALIGN
299: bcd_store: //proc
300: push %gs:sr_masks // save current precision
301: orb prec64,%gs:sr_controls // and set to 64-bit
302: cmpb special,tag1(%ebp) // separate bcd cases
303: jne finite_value_
304: jmp store_signed_bcd
305: ALIGN
306: finite_value_:
307: cmpl $0x07fff,dword_expon1 // is it a finite number?
308: jne check_bcd_denorm // yes, branch to valid
309: invalid_bcd:
310: orb invalid_mask,%gs:sr_errors // set i_error
311: testb invalid_mask,%gs:sr_masks // is i_error unmasked?
312: jnz store_bcd_indef
313: jmp bcd_store_done // no, so exit at once
314: ALIGN
315: store_bcd_indef: // yes, store bcd_indef
316: movl $0, dword_frac1+frac80(%ebp) // clear low frac
317: movl $0x80000000, dword_frac1+6(%ebp)// set only ms bit of hi frac
318: movw $0x0ffff, 8+word_frac1 //set msw to all ones,
319: jmp store_bcd_result // and give as answer
320: ALIGN
321: check_bcd_denorm:
322: cmpb denormd,tag1(%ebp) // separate bcd cases
323: jne round_to_int
324: movl $0x0001,dword_expon1 // if masked d-error, make valid
325: movb valid,tag1(%ebp)
326: round_to_int:
327: mov $0x403e,%eax
328: cmp %eax,dword_expon1 // if expon >= 63, then number
329: jge invalid_bcd // is already too big for bcd
330: mov $offset_operand1,%edi // gradual uflow until expon=63
331: push %edi
332: call gradual_underflow
333: pop %edi // round to precision 64
334: movb prec64,%dl
335: movb false,%al
336: call round
337: detect_zero:
338: xor %eax,%eax
339: mov $dword_frac1+4,%edi // if fraction = 0, result = 0
340: call test_4w
341: jnz below_10_to_18_
342: mov %eax,dword_expon1 // set result to true zero
343: movb special,tag1(%ebp)
344: jmp store_bcd_round_data
345: ALIGN
346: below_10_to_18_:
347: mov 4(%ebp,%edi),%edx
348: cmp $0x0de0b6b3,%edx
349: ja invalid_bcd
350: mov (%ebp,%edi),%eax
351: jb divide_by_10_to_9
352: cmp $0x0a7640000,%eax
353: jae invalid_bcd
354: divide_by_10_to_9:
355: movl $0,4(%ebp,%edi) // clear high dword of frac1
356: movl $0,(%ebp,%edi)// clear low dword of 8 byte frac1
357: sub $2,%edi // make edi point to 10 byte frac1
358: mov $0x3b9aca00,%ebx // ten to the 9th, as hex ordinal
359: div %ebx
360: push %eax // save quotient
361: mov $4,%ecx
362: mov $100,%ebx
363: FALLSTHRU
364: next_pair_nibbles:
365: mov %edx,%eax
366: xor %edx,%edx
367: div %ebx
368: xchgl %edx,%eax
369: aam
370: second_half_loop_start:
371: shlb $4,%ah
372: orb %ah,%al
373: movb %al,(%ebp,%edi)
374: inc %edi
375: LOOP(next_pair_nibbles)
376: do_second_half_:
377: pop %eax
378: or %eax,%eax // is eax 0?
379: movb %dl,(%ebp,%edi)
380: jz store_bcd_round_data
381: push %edx
382: xor %edx,%edx
383: mov $10,%ecx
384: div %ecx
385: xchgl %edx,%eax
386: pop %ecx
387: movb %al, %ah
388: movb %cl, %al
389: push $0
390: mov $5, %ecx
391: jmp second_half_loop_start
392: ALIGN
393: store_bcd_round_data:
394: cmpb true,rnd1_inexact
395: jne store_signed_bcd
396: orb $inexact_mask,%gs:sr_errors
397: cmpb true,added_one
398: jne store_signed_bcd
399: orb $a_mask,%gs:sr_flags
400: store_signed_bcd:
401: movb sign1(%ebp),%ah // set sign in bcd number
402: andb $0x080,%ah
403: movb %ah,msb_frac1
404: store_bcd_result:
405: les %gs:sr_mem_offset,%edi //move frac1 to memory
406: // push %ds // save a?msr
407: // push %ss
408: // pop %ds
409: lea word_frac1,%esi
410:
411: /* FAST_MOVSL */
412: movl %ss:0(%esi),%ecx
413: movl %ecx,%es:0(%edi)
414: movl %ss:4(%esi),%ecx
415: movl %ecx,%es:4(%edi)
416: movw %ss:8(%esi),%cx
417: movw %cx,%es:8(%edi)
418: // addl $10,%esi
419: // addl $10,%edi
420: // movl $0,%ecx
421:
422: // pop %ds // reload a?msr
423: call pop_free
424: bcd_store_done:
425: pop %gs:sr_masks // restore old setting
426: ret
427: //bcd_store endp
428: //
429: // *****************************************************************************
430: // single_real_store:
431: // ******************
432: // function:
433: // implements store to single-precision real format
434: //
435: // inputs:
436: // operand1
437: //
438: // outputs:
439: // single_precision real in memory;
440: // stack popped if indicated.
441: //
442: // data accessed:
443: // - mem_operand_pointer offset_operand1
444: // - sign1 tag1
445: // - expon1 word_frac
446: // - msb_frac1
447: //
448: // data changed:
449: //
450: // procedures called:
451: // round store_valid
452: // addition_normalized special_round_test
453: // directed_round_test gradual_underflow
454: // pop_free test_3w
455: // u_masked? set_o_error
456: // o_masked? set_p_error
457: // set_u_error set_i_masked?
458: // store_denormd
459: //
460: // ************************************************************************
461: ALIGN
462: single_real_store: //proc
463: push $pop_free // return to pop_free
464: les mem_operand_pointer(%ebp),%edi //set es:di to memop
465: mov low_extended_expon_for_single,%esi
466: movb prec24,%dl // 24-bit precision
467: movb tag1(%ebp),%al // load op1 tag
468: cmpb valid,%al
469: je single_valid // detect valid, infinity,
470: cmpb denormd,%al // denormd, invalid, and
471: je single_denormd // special cases
472: cmpb inv,%al // check whether op1 is nan
473: jne single_special // branch unless op1 is nan
474: testb $0x40,msb_frac1 // check whether nan is quiet
475: jnz single_special // branch if nan is quiet
476: orb invalid_mask,%gs:sr_errors // set i_error for snan
477: testb invalid_mask,%gs:sr_masks // if unmasked, just exit
478: jz special_return // else, change to qnan
479: orb $0x40,msb_frac1
480: single_special:
481: mov dword_frac1+frac32+1(%ebp),%ecx
482: and $0x807fffff,%ecx
483: movzbl expon1(%ebp),%eax
484: shl $23,%eax
485: or %ecx,%eax
486: mov %eax,%es:(%edi)
487: //..
488: //.. pushad
489: //.. push es
490: //.. push edi
491: //.. push eax
492: //.. call fpsulong
493: //.. add esp, 12
494: //.. popad
495: //.. cld
496: //..
497: special_return:
498: ret
499: ALIGN
500:
501: single_denormd:
502: mov $offset_operand1,%edi // op1 is denormal or pseudo-denormal
503: call norm_denorm // dont set d_error; just normalize
504: single_valid:
505: mov high_extended_expon_for_single,%edi // load parameter
506: call store_valid
507: les mem_operand_pointer(%ebp),%edi // es:edi --> memop
508: jz single_infinity // zf = 1 => store infinity
509: js single_max // sf = 1 => store max
510: jc single_qnan // cf = 1 => store qnan
511: single_store:
512: mov dword_frac1+frac32+1(%ebp),%eax
513: and $0x80ffffff,%eax
514: test $0x00ffffff,%eax
515: jz single_store_it
516: and $0x807fffff,%eax
517: movzbl expon1(%ebp),%ecx
518: addb $0x80,%cl
519: shl $23,%ecx
520: or %ecx,%eax
521: single_store_it:
522: mov %eax,%es:(%edi)
523: //..
524: //.. pushad
525: //.. push es
526: //.. push edi
527: //.. push eax
528: //.. call fpsulong
529: //.. add esp,12
530: //.. popad
531: //.. cld
532: //..
533: ret //do needed pop or free
534: ALIGN
535:
536: single_max:
537: mov $0x7fffff7f,%eax
538: jmp single_sign_on
539: ALIGN
540: single_infinity:
541: mov $0x8000007f,%eax
542: single_sign_on:
543: orb sign1(%ebp),%al
544: ror $8,%eax
545: jmp single_store_it
546: ALIGN
547: single_qnan:
548: movl $0xffffffff,%es:(%edi)
549: pop %eax // skip pop or free
550: ret // since this happens on error
551: ALIGN
552:
553: store_valid:
554: push %edi // stack high_expon
555: push %esi // stack low_expon
556: push %edx // stack prec control
557: movb false,%al // not second rounding
558: mov $offset_operand1,%edi // round to prec (dl)
559: // push edi ; round preserves edi
560: call round
561: // pop edi
562: call addition_normalize // and renormalize
563: pop %edx // unstack prec control
564: pop %esi // unstack low_expon
565: pop %edi // unstack high_expon
566: cmp %esi,dword_expon1 // is underflow possible?
567: jl store_underflow_ // < low_expon, so underflow possible
568: je decrement_exponent // no, = low_expon?
569: cmp %edi,dword_expon1 // no, > high_expon?
570: jle do_store_valid // no, store number
571: orb overflow_mask,%gs:sr_errors // set o_error
572: testb overflow_mask,%gs:sr_masks // if unmasked, violate ieee standard
573: jnz masked_overflow // and abort without rounding source
574: unmasked_ov_underflow:
575: //
576: // the commentized instructions immediately following are appropriate for
577: // unmasked over/underflow response in accord with the ieee standard. on the
578: // 80387, unmasked over/underflows on conversion leave for the trap handler the
579: // source operand, unmodified by rounding, exponent rebiasing, or anything else.
580: // therefore, to report that preliminary rounding was inexact or achieved by
581: // increasing the source seems inconsistent with the 80387s philosophy
582: // of entering an over/underflow trap handler with the 80387s state changed
583: // only insofar as the over/underflow flag has been set, so skip that report.
584: //
585: // cmp rnd1_inexact, true ; detect inexact result
586: // jne move_op1_to_87_tos ; if exact, branch to replace source
587: // or %gs:sr_errors, inexact_mask ; else, set i_error
588: // cmp added_one, true ; was rounding done by adding one?
589: // jne move_op1_to_87_tos ; if not, branch to replace source
590: // or %gs:sr_flags, a_mask ; else, set a_bit
591: //move_op1_to_87_tos:
592: // mov (ebp).result_location, stack_top
593: // pop %edi ; discard callers return address
594: // pop %edi ; discard pop_free address
595: // jmp put_op1_result
596: //
597: // Instead, we return a special error condition (sf=0 zf=0 cf=1)
598: // to our caller, to cause a quiet NaN to be generated, as the 80387 does.
599: movb $1, %ah
600: sahf
601: ret
602: ALIGN
603:
604: masked_overflow:
605: orb $inexact_mask,%gs:sr_errors // set inexact_error
606: movb %gs:sr_controls,%al // load control byte
607: andb $rnd_control_mask,%al // mask in rounding control
608: movb rnd_up,%ah
609: cmpb %al,%ah
610: js store_valid_done // branch if zf = 0 & sf = 1
611: movb sign1(%ebp),%al // get sign of op1
612: call special_round_test // after round test, cf=0
613: pushf // (zf=0 sf=1)/(zf=1 sf=0)
614: js pop_store_valid_done // sf = 1 => store max
615: orb $a_mask,%gs:sr_flags // set a_bit
616: pop_store_valid_done:
617: popf // reload flags
618: store_valid_done:
619: ret // exit
620: ALIGN
621: store_underflow_:
622: testb underflow_mask,%gs:sr_masks // if underflow masked,
623: jnz check_masked_underflow // then branch to check for inexact
624: orb underflow_mask,%gs:sr_errors// else, set u_error
625: //
626: // after the underflow exception has been set, the response to unmasked
627: // underflow ought to be the same as that to unmasked overflow.
628: jmp unmasked_ov_underflow
629: ALIGN
630:
631: check_masked_underflow:
632: mov $offset_operand1,%edi // load op1 offset
633: mov %esi,%eax // load low exponent
634: push %edi // save op1 offset
635: push %edx // save prec control
636: call gradual_underflow // do gradual underflow
637: pop %edx // reload prec control
638: pop %edi // reload op1 offset
639: movb true,%al // perform second round
640: call round
641: cmpw $0,rnd_history // signal_u_error?
642: je decrement_exponent
643: orb underflow_mask+inexact_mask,%gs:sr_errors
644: decrement_exponent:
645: testb $0x80,msb_frac1 // test msb of fraction
646: jnz do_store_valid // dont decrement if 800..0h
647: decw expon1(%ebp) // else, decrement expon
648: do_store_valid:
649: cmpw $0,rnd_history // signal_p_error?
650: je adjust_flags
651: orb $inexact_mask,%gs:sr_errors // signal_p_error.
652: cmpb true,added_one // was rounding done by adding one?
653: jne adjust_flags // if not, branch to adjust flags
654: orb $a_mask,%gs:sr_flags // else, set a_bit
655: adjust_flags:
656: xor %eax,%eax // cf = 0, sf = 0, zf = 0 for
657: inc %eax // store valid exit
658: ret
659:
660: //single_real_store endp
661: //
662: // ************************************************************************
663: // double_real_store:
664: // ******************
665: // function:
666: // implements store to double-precision real format
667: //
668: // inputs:
669: // operand1
670: //
671: // outputs:
672: // double precision real in memory;
673: // stack popped if indicated.
674: //
675: // data accessed:
676: // - mem_operand_pointer offset_operand1
677: // - sign1 tag1
678: // - expon1 word_frac1
679: // - msb_frac1 offset_operand1
680: //
681: // data changed:
682: // - sign1 word_frac1
683: //
684: // procedures called:
685: // test_3w store_valid
686: // right_shift_frac1_cl pop_free
687: // double_zero double_fill
688: // store_denormd double_frac_mem
689: //
690: // ***************************************************************************
691: ALIGN
692: double_real_store: //proc
693: push $pop_free // return to pop_free
694: mov low_extended_expon_for_double,%esi
695: movb prec53,%dl // 53-bit precision
696: movb tag1(%ebp),%al // separate special cases
697: cmpb valid,%al
698: je double_valid
699: cmpb denormd,%al
700: je double_denormd
701: cmpb special,%al
702: jne inv_or_inf
703: movw $0x3c00,expon1(%ebp)
704: jmp double_frac_mem
705: ALIGN
706: inv_or_inf:
707: cmpb inv,%al
708: jne double_special
709: testb $0x40,msb_frac1 // check whether nan is quiet
710: jnz double_special // branch if nan is quiet
711: orb invalid_mask,%gs:sr_errors // set i_error for snan
712: testb invalid_mask,%gs:sr_masks // if unmasked, just exit
713: jnz make_dbl_qnan // else, change to qnan
714: dbl_special_return:
715: ret
716: ALIGN
717: make_dbl_qnan:
718: orb $0x40,msb_frac1
719: double_special:
720: movw $0x3c00+0x07ff,expon1(%ebp)
721: jmp double_frac_mem // store frac to memory
722: ALIGN
723: double_denormd:
724: mov $offset_operand1,%edi // op1 is denormal or pseudo-denormal
725: call norm_denorm // dont set d_error; just normalize
726: double_valid:
727: mov high_extended_expon_for_double,%edi
728: call store_valid
729: jz double_infinity // zf = 1 ==> store infinity
730: js double_max // sf = 1 ==> store max
731: jc double_qnan // cf = 1 ==> store qnan
732: double_store:
733: movb 3+lsb_frac1,%al // else store double
734: cbtw
735: mov $dword_frac1+6,%edi
736: call test_3w
737: jz double_zero // store signed zero
738: double_frac_mem:
739: movb $3,%cl // start by shifting
740: call right_shift_frac1_cl // fraction right 3 bits
741: les mem_operand_pointer(%ebp),%edi // es:edi points to memop
742: // push %ds // save a?msr
743: // push %ss
744: // pop %ds // set up source pointer
745: lea 3+word_frac1,%esi // move frac to memory
746:
747: /* FAST_MOVSL */
748: movl %ss:0(%esi),%ecx
749: movl %ecx,%es:0(%edi)
750: movw %ss:4(%esi),%ecx
751: movw %ecx,%es:4(%edi)
752: // addl $6,%esi
753: // addl $6,%edi
754: // movl $0,%ecx
755:
756: // pop %ds // reload a?msr
757: movw expon1(%ebp),%ax // fetch high-order word,
758: subw $0x3c00,%ax // with expon, sign, and
759: shlw $4,%ax // top 4 bits of fraction
760: andb $0x0f,msb_frac1
761: orb msb_frac1,%al
762: andb $0x80,sign1(%ebp)
763: orb sign1(%ebp),%ah
764: movw %ax,%es:6(%edi) // es:di points to expon
765: //..
766: //.. pushad
767: //.. push es
768: //.. push edi
769: //.. push ax
770: //.. call fpsushort
771: //.. add esp,12
772: //.. popad
773: //.. cld
774: //..
775:
776: ret // do pop or free
777: ALIGN
778:
779: double_zero:
780: xor %eax,%eax // store +/- 0 to memory
781: double_fill:
782: les mem_operand_pointer(%ebp),%edi // es:edi points to memop
783: mov %eax,%es:(%edi)
784: //..
785: //.. pushad
786: //.. push es
787: //.. push edi
788: //.. push eax
789: //.. call fpsulong
790: //.. add esp,12
791: //..
792:
793: movw %ax,%es:4(%edi)
794: //..
795: //.. push es
796: //.. push edi+4
797: //.. push ax
798: //.. call fpsushort
799: //.. add esp,12
800: //.. popad
801: //.. cld
802: //..
803: movb sign1(%ebp),%ah
804: andb $0x80,%ah
805: double_expon:
806: movw %ax,%es:6(%edi) // store the exponent
807: //..
808: //.. pushad
809: //.. push es
810: //.. push edi+12
811: //.. push ax
812: //.. call fpsushort
813: //.. add esp,12
814: //.. popad
815: //.. cld
816: //..
817: ret
818: ALIGN
819:
820: double_max:
821: mov $0x0ffffffff,%eax // set fraction to ff..f
822: call double_fill
823: movw $0x7fef,%ax // set exponent to 7feh
824: orb sign1(%ebp),%ah // or sign bit
825: jmp double_expon
826: ALIGN
827: double_infinity:
828: call double_zero // first clear the memop
829: orw $0x7ff0,%es:6(%edi) // es:di -> memop
830: //..
831: //.. pushad
832: //.. push es
833: //.. push edi+6
834: //.. call fpfushort
835: //.. or ax,7ff0h
836: //.. push ax
837: //.. call fpsushort
838: //.. add esp,12
839: //.. popad
840: //.. cld
841: //..
842: ret
843: ALIGN
844: double_qnan:
845: mov $0xffffffff,%eax // set fraction to ff..f
846: call double_fill
847: movw $0xffff,%es:6(%edi) // es:di -> memop (set exp to ff..f)
848: pop %eax // skip pop or free
849: ret // since this happens on error
850: //double_real_store endp
851: //
852: // ***********************************************************************
853: // fix16:
854: //
855: // function:
856: // fixes valid number to a 16-bit integer.
857: //
858: // inputs:
859: // operand1
860: //
861: // outputs:
862: // 16-bit integer in word_frac1 + 8;
863: // overflow indication in zf (zf:1 => no overflow)
864: //
865: // data accessed:
866: // - offset_operand1 sign1
867: // - expon1 word_frac1
868: // - offset_operand1
869: //
870: // data changed:
871: // - word_frac1 extra_word_reg
872: //
873: // procedures called:
874: // sticky_right_shift round
875: // careful_round p_error?
876: //
877: // ***************************************************************************
878: ALIGN
879: fix16: //proc
880: mov high_int16_exponent,%ecx // calc shift amount
881: sub dword_expon1,%ecx // if expon1 > high expon
882: js no_fix16_ovf // then overflow (zf=0)
883: cmp max_int16_shift,%ecx // dont let shift amount
884: jbe do_shift_16 // exceed max_int16_shift
885: mov max_int16_shift,%ecx
886: do_shift_16:
887: mov $offset_operand1,%edi // shift frac1 by cl
888: xorb %al,%al
889: call sticky_right_shift
890: mov $offset_operand1,%edi // round to 16-bit prec
891: movb prec16,%dl
892: movb false,%al
893: call round
894: cmpb false,%al // overflow if al=true
895: jnz no_fix16_ovf // round cy out (zf=1)
896: cmpw $0x8000,8+word_frac1
897: jb check_sign_16 // no overflow if < 8000h
898: ja no_fix16_ovf // else, overflow (zf=0)
899: cmpb negative,sign1(%ebp) // oflow if = 8000h and
900: jnz no_fix16_ovf // sign1 = pos (zf=0)
901: check_sign_16:
902: movb positive,%al // al is overflow flag
903: cmpb sign1(%ebp),%al // negate integer if
904: jz no_fix16_ovf // sign is neg (zf=1)
905: negw 8+word_frac1
906: xorb %al,%al // no overflow (zf=1)
907: no_fix16_ovf:
908: ret
909: //fix16 endp
910: //
911: // ***********************************************************************
912: // int16_store:
913: //
914: // function:
915: // stores into 16-bit integer format
916: //
917: // inputs:
918: // operand1
919: //
920: // outputs:
921: // 16-bit integer in memory operand location
922: //
923: // data accessed:
924: // - mem_operand_pointer tag1
925: // - word_frac1 msb_frac1
926: // - offset_operand1 extra_word_reg
927: //
928: // data changed:
929: //
930: // procedures called:
931: // fix16 pop_free
932: // invalid_or_special get_rnd_control
933: // set_i_error i_masked?
934: // set_p_error clear_p_error
935: //
936: // ************************************************************************
937: ALIGN
938: int16_store: //proc
939: //
940: cmpb valid,tag1(%ebp)
941: je valid_16
942: cmpb denormd,tag1(%ebp)
943: jne special_16
944: valid_16:
945: call fix16 // make op1 a 16-bit int
946: jnz special_16 // if zf=0, oflow on fix
947: cmpw $0,rnd_history
948: je store_16
949: orb $inexact_mask,%gs:sr_errors
950: cmpb true,added_one
951: jne store_16
952: orb $a_mask,%gs:sr_flags
953: store_16:
954: movw 8+word_frac1,%ax // move integer to memory
955: pointer_16:
956: les mem_operand_pointer(%ebp),%edi //set es:di to location
957: finish_16:
958: movw %ax,%es:(%edi) // store integer to mem
959: //..
960: //.. pushad
961: //.. push es
962: //.. push edi
963: //.. push ax
964: //.. call fpsushort
965: //.. add esp,12
966: //.. popad
967: //.. cld
968: //..
969: jmp pop_free // pop stack and go home
970: ALIGN
971: special_16:
972: xorw %ax,%ax
973: cmpb special,tag1(%ebp) // is operand tagged special?
974: je pointer_16 // yes, load memop ptr and exit
975: orb invalid_mask,%gs:sr_errors// no, set invalid error
976: movw $0x8000,%ax // load inv constant into ax
977: testb invalid_mask,%gs:sr_masks// is invalid error masked?
978: jnz pointer_16 // yes, store invalid constant
979: ret
980: //int16_store endp
981: //
982: // ***********************************************************************
983: // fix32:
984: //
985: // function:
986: // fixes valid number to a 32-bit integer.
987: //
988: // inputs:
989: // operand1
990: //
991: // outputs:
992: // 32-bit integer in word_frac1 + 6;
993: // overflow indication in zf (zf:1 => no overflow)
994: //
995: // data accessed:
996: // - offset_operand1 sign1
997: // - dword_expon1 word_frac1
998: // - offset_operand1
999: //
1000: // data changed:
1001: // - word_frac1
1002: //
1003: // procedures called:
1004: // sticky_right_shift round
1005: //
1006: // ***************************************************************************
1007: ALIGN
1008: fix32: //proc
1009: mov high_int32_exponent,%ecx // calc shift amount
1010: sub dword_expon1,%ecx // if expon1 > high expon
1011: js no_fix32_ovf // then overflow (zf=0)
1012: cmp max_int32_shift,%ecx // dont let shift amount
1013: jbe do_shift_32 // exceed max_int32_shift
1014: mov max_int32_shift,%ecx
1015: do_shift_32:
1016: mov $offset_operand1,%edi // shift frac1 by cl
1017: xorb %al,%al
1018: call sticky_right_shift
1019: mov $offset_operand1,%edi // round to 16-bit prec
1020: movb prec32,%dl
1021: movb false,%al
1022: call round
1023: cmpb false,%al // overflow if al=true
1024: jnz no_fix32_ovf // round cy out (zf=1)
1025: cmpl $0x080000000,dword_frac1+frac32(%ebp)
1026: jb check_sign_32 // no overflow if < 80000000h
1027: ja no_fix32_ovf // else, overflow (zf=0)
1028: cmpb negative,sign1(%ebp) // oflow if = 80000000h and
1029: jnz no_fix32_ovf // sign1 = pos (zf=0)
1030: check_sign_32:
1031: movb positive,%al // al is overflow flag
1032: cmpb sign1(%ebp),%al // negate integer if
1033: jz no_fix32_ovf // sign is neg (zf=1)
1034: negl dword_frac1+frac32(%ebp)
1035: xorb %al,%al // no overflow (zf=1)
1036: no_fix32_ovf:
1037: ret
1038: //fix32 endp
1039: //
1040: // **************************************************************************
1041: // int32_store:
1042: //
1043: // function:
1044: // stores into 32-bit integer format
1045: //
1046: // input:
1047: // operand1
1048: //
1049: // output:
1050: // 32-bit integer in location pointed to by es:di.
1051: //
1052: // data accessed:
1053: // - mem_operand_pointer offset_operand1
1054: // - sign1 tag1
1055: // - expon1 word_frac1
1056: // - msb_frac1 offset_operand1
1057: //
1058: // data changed:
1059: // - word_frac1
1060: //
1061: // procedures called:
1062: // pop_free
1063: // fix32
1064: //
1065: // **************************************************************************
1066: ALIGN
1067: int32_store: //proc
1068: cmpb valid,tag1(%ebp)
1069: je valid_32
1070: cmpb denormd,tag1(%ebp)
1071: jne special_32
1072: valid_32:
1073: call fix32 // make op1 a 32-bit int
1074: jnz special_32 // if zf=0, oflow on fix
1075: cmpw $0,rnd_history
1076: je store_32
1077: orb $inexact_mask,%gs:sr_errors
1078: cmpb true,added_one
1079: jne store_32
1080: orb $a_mask,%gs:sr_flags
1081: store_32:
1082: mov dword_frac1+frac32(%ebp),%eax // move integer to eax
1083: pointer_32:
1084: les mem_operand_pointer(%ebp),%edi //set es:di to location
1085: finish_32:
1086: mov %eax,%es:(%edi) // store integer to mem
1087: //..
1088: //.. pushad
1089: //.. push es
1090: //.. push edi
1091: //.. push eax
1092: //.. call fpsulong
1093: //.. add esp,12
1094: //.. popad
1095: //.. cld
1096: //..
1097: jmp pop_free // pop stack and go home
1098: ALIGN
1099: special_32:
1100: xor %eax,%eax
1101: cmpb special,tag1(%ebp) // is operand tagged special?
1102: je pointer_32 // yes, load memop ptr and exit
1103: orb invalid_mask,%gs:sr_errors// no, set invalid error
1104: mov $0x080000000,%eax // load inv constant into ax
1105: testb invalid_mask,%gs:sr_masks// is invalid error masked?
1106: jnz pointer_32 // yes, store invalid constant
1107: ret
1108: //int32_store endp
1109: //
1110: // ***********************************************************************
1111: // fix64:
1112: //
1113: // function:
1114: // fixes valid number to a 64-bit integer.
1115: //
1116: // inputs:
1117: // operand1
1118: //
1119: // outputs:
1120: // 64-bit integer in word_frac1 + 2;
1121: // overflow indication in zf (zf:1 => no overflow)
1122: //
1123: // data accessed:
1124: // - offset_operand1 sign1
1125: // - dword_expon1 word_frac1
1126: // - offset_operand1
1127: //
1128: // data changed:
1129: // - word_frac1
1130: //
1131: // procedures called:
1132: // sticky_right_shift round
1133: //
1134: // ***************************************************************************
1135: ALIGN
1136: fix64: //proc
1137: mov high_int64_exponent,%ecx // calc shift amount
1138: sub dword_expon1,%ecx // if expon1 > high expon
1139: js no_fix64_ovf // then overflow (zf=0)
1140: cmp max_int64_shift,%ecx // dont let shift amount
1141: jbe do_shift_64 // exceed max_int64_shift
1142: mov max_int64_shift,%ecx
1143: do_shift_64:
1144: mov $offset_operand1,%edi // shift frac1 by cl
1145: xorb %al,%al
1146: call sticky_right_shift
1147: mov $offset_operand1,%edi // round to 64-bit prec
1148: movb prec64,%dl
1149: movb false,%al
1150: call round
1151: cmpb false,%al // overflow if al=true
1152: jnz no_fix64_ovf // round cy out (zf=1)
1153: cmpl $0x080000000,dword_frac1+frac32(%ebp)
1154: jb check_sign_64 // no overflow if < 80000000h
1155: ja no_fix64_ovf // else, overflow (zf=0)
1156: cmp $0,dword_frac1+frac64(%ebp)
1157: jnz no_fix64_ovf
1158: cmpb negative,sign1(%ebp) // oflow if = 800..0h and
1159: jnz no_fix64_ovf // sign1 = pos (zf=0)
1160: check_sign_64:
1161: movb positive,%al // al is overflow flag
1162: cmpb sign1(%ebp),%al // negate integer if
1163: jz no_fix64_ovf // sign is neg (zf=1)
1164: xor %eax,%eax
1165: negl dword_frac1+frac64(%ebp)
1166: sbb dword_frac1+frac32(%ebp),%eax
1167: mov %eax,dword_frac1+frac32(%ebp)
1168: xorb %al,%al // no overflow (zf=1)
1169: no_fix64_ovf:
1170: ret
1171: //fix64 endp
1172: //
1173: // *****************************************************************************
1174: // int64_store:
1175: // ************
1176: // function:
1177: // stores into 64-bit integer format
1178: //
1179: // input:
1180: // operand1
1181: //
1182: // output:
1183: // 64-bit integer in memory location pointed to by es:edi.
1184: //
1185: // data accessed:
1186: // - mem_operand_pointer offset_operand1
1187: // - sign1 tag1
1188: // - expon1 word_frac1
1189: // - msb_frac1 offset_operand1
1190: //
1191: // data changed:
1192: // - word_frac1
1193: //
1194: // procedures called:
1195: // pop_free
1196: //
1197: // ***************************************************************************
1198: ALIGN
1199: int64_store: //proc
1200: cmpb valid,tag1(%ebp)
1201: je valid_64
1202: cmpb denormd,tag1(%ebp)
1203: jne special_64
1204: valid_64:
1205: call fix64 // make op1 a 64-bit int
1206: jnz special_64 // if zf=0, oflow on fix
1207: cmpw $0,rnd_history
1208: je store_64
1209: orb $inexact_mask,%gs:sr_errors
1210: cmpb true,added_one
1211: jne store_64
1212: orb $a_mask,%gs:sr_flags
1213: store_64:
1214: mov dword_frac1+frac64(%ebp),%eax // move integer to edx:eax
1215: mov dword_frac1+frac32(%ebp),%edx // move integer to edx:eax
1216: pointer_64:
1217: les mem_operand_pointer(%ebp),%edi //set es:edi to location
1218: finish_64:
1219: mov %eax,%es:(%edi) // store low integer to low mem
1220: //..
1221: //.. pushad
1222: //.. push es
1223: //.. push edi
1224: //.. push eax
1225: //.. call fpsulong
1226: //.. add esp,12
1227: //.. popad
1228: //.. cld
1229: //..
1230: mov %edx,%es:4(%edi) // store high integer to high mem
1231: //..
1232: //.. pushad
1233: //.. push es
1234: //.. push edi
1235: //.. push edx
1236: //.. call fpsulong
1237: //.. add esp,12
1238: //.. popad
1239: //.. cld
1240: //..
1241: jmp pop_free // pop stack and go home
1242: ALIGN
1243: special_64:
1244: xor %eax,%eax
1245: cltd
1246: cmpb special,tag1(%ebp) // is operand tagged special?
1247: je pointer_64 // yes, load memop ptr and exit
1248: orb invalid_mask,%gs:sr_errors// no, set invalid error
1249: mov $0x080000000,%edx // load inv constant into ax
1250: testb invalid_mask,%gs:sr_masks// is invalid error masked?
1251: jnz pointer_64 // yes, store invalid constant
1252: ret
1253:
1254: //int64_store endp
1255: //
1256: //a_med ends
1257: //
1258: // end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.