|
|
Darwin 0.1 Mach+BSD kernel
/* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights * Reserved. This file contains Original Code and/or Modifications of * Original Code as defined in and that are subject to the Apple Public * Source License Version 1.1 (the "License"). You may not use this file * except in compliance with the License. Please obtain a copy of the * License at http://www.apple.com/publicsource and read it before using * this file. * * The Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ .file "round.s" .ident "@(#)kern-fp:round.s 1.1" //$tt(*80387 emulator + + + r o u n d + + + *) // ********************************************************************** // // r o u n d . m o d // ================= // // =============================================================== // intel corporation proprietary information // this software is supplied under the terms of a license // agreement or non-disclosure agreement with intel corporation // and may not be copied nor disclosed except in accordance with // the terms of that agreement. // =============================================================== // // function: // implements all rounding modes for all precisions // // public procedures: // round special_round_test // directed_round_test // // internal procedures: // prec16_case prec24_case // prec32_case prec53_case // prec64_case // // *************************************************************************** // //...october 31, 1986... // // .file *a_mro* // //$nolist #include "fp_e80387.h" //$list //...declare status register segment... // .data //a_msr segment rw public // extrn %gs:sr_flags //a_msr ends // // assume %ds:a_msr // .text //a_med segment er public // // extrn get_rnd_control // .globl round .globl directed_round_test .globl special_round_test // // *********************************************************************** // prec16_case: // ************ // function: // sets up for rounding to 16 bits. // // inputs: // assumes edi points to operand record. // // outputs: // sets: dl if round or sticky bit set // dh if guard bit set // ah if lsb set // cl to number of rounded bytes // ch to pattern to add to low byte for rounding // and clears the guard, round, and sticky bytes. // doesnt affect al. // // data accessed: // // data changed: // // procecures called: // // ************************************************************************* ALIGN prec16_case: //proc ; initially, assume all guard, xchg frac80+4(%ebp,%edi),%ecx// round, and sticky info zero and %ecx,%ecx // examine and clear grst word jns get_round_sticky_16 notb %dh // et guard byte get_round_sticky_16: and $0x7fffffff,%ecx or frac80(%ebp,%edi),%ecx orw (%ebp,%edi),%cx jz get_lsb_16 notb %dl // set round-sticky byte get_lsb_16: xorb %ah,%ah // initially, assume lsb is zero testb $0x01,frac80+8(%ebp,%edi) jz set_rnd_info_16 notb %ah // set lsb byte movl $0,frac80(%ebp,%edi) movw $0,(%ebp,%edi) set_rnd_info_16: mov $0x0102,%ecx // the rounded result has 2 bytes ret // the pattern to add is 01h //prec16_case endp // // ************************************************************************* // prec24_case: // ************ // function: // sets up for rounding to 24 bits. // // inputs: // assumes edi points to operand record. // // outputs: // sets: dl if round or sticky bit set // dh if guard bit set // ah if lsb set // cl to number of rounded bytes // ch to pattern to add to low byte for rounding // and clears the guard, round, and sticky bytes. // doesnt affect al. // // data accessed: // // data changed: // // ************************************************************************* ALIGN prec24_case: //proc ; initially, assume all guard, xchgb frac32(%ebp,%edi),%cl // round, and sticky info zero andb %cl,%cl // examine and clear grst word jns get_round_sticky_24 notb %dh // set guard byte get_round_sticky_24: andb $0x7f,%cl or frac64(%ebp,%edi),%ecx or (%ebp,%edi),%ecx jz get_lsb_24 notb %dl // set round-sticky byte get_lsb_24: xorb %ah,%ah // initially, assume lsb is zero testb $0x01,frac32+1(%ebp,%edi) jz clear_sticky_bytes_24 notb %ah // set lsb byte clear_sticky_bytes_24: movl $0,frac64(%ebp,%edi) movl $0,(%ebp,%edi) mov $0x0103,%ecx // the rounded result has 3 bytes ret // the pattern to add is 01h //prec24_case endp // // ***************************************************************************** // prec32_case: // ************ // function: // sets up for rounding to 32 bits. // // inputs: // assumes edi points to operand record. // // outputs: // sets: dl if round or sticky bit set // dh if guard bit set // ah if lsb set // cl to number of rounded bytes // ch to pattern to add to low byte for rounding // and clears the guard, round, and sticky bytes. // doesnt affect al. // // data accessed: // // data changed: // // ************************************************************************* ALIGN prec32_case: //proc ; initially, assume all guard, xchg frac64(%ebp,%edi),%ecx // round, and sticky info zero and %ecx,%ecx jns get_round_sticky_32 notb %dh // set guard byte get_round_sticky_32: and $0x7fffffff,%ecx or (%ebp,%edi),%ecx jz get_lsb_32 notb %dl // set round-sticky byte get_lsb_32: xorb %ah,%ah // initially, assume lsb is zero testb $0x01,frac32(%ebp,%edi) jz clear_sticky_bytes_32 not_ah_clear_32: notb %ah // set lsb byte clear_sticky_bytes_32: movl $0,(%ebp,%edi) mov $0x0104,%ecx// the rounded result has 4 bytes ret // the pattern to add is 01h //prec32_case endp // // *********************************************************************** // prec53_case: // *********** // function: // sets up for rounding to 53 bits. // // inputs: // assumes edi points to operand record. // // outputs: // sets: dl if round or sticky bit set // dh if guard bit set // ah if lsb set // cl to number of rounded bytes // ch to pattern to add to low byte for rounding // and clears the guard, round, and sticky bytes. // doesnt affect al. // // data accessed: // // data changed: // // *************************************************************************** ALIGN prec53_case: //proc ; initially, assume all guard, mov frac64(%ebp,%edi),%ecx // round, and sticky info zero testb $0x04,%ch // examine guard bit jz get_round_sticky_53 notb %dh // set guard byte get_round_sticky_53: and $0x03ff,%ecx or (%ebp,%edi),%ecx jz get_lsb_53 notb %dl // set round-sticky byte get_lsb_53: xorb %ah,%ah // initially, assume lsb is zero testb $0x08,frac64+1(%ebp,%edi) jz clear_grst_bits_53 notb %ah // set lsb byte clear_grst_bits_53: movl $0,(%ebp,%edi) andw $0x0f800,frac64(%ebp,%edi) mov $0x0807,%ecx// the rounded result has 7 bytes ret // the pattern to add is 08h //prec53_case endp // // **************************************************************************** // prec64_case: // ************ // function: // sets up for rounding to 64 bits. // // inputs: // assumes edi points to operand record. // // outputs: // sets: dl if round or sticky bit set // dh if guard bit set // ah if lsb set // cl to number of rounded bytes // ch to pattern to add to low byte for rounding // and clears the guard, round, and sticky bytes. // doesnt affect al. // // data accessed: // // data changed: // // ************************************************************************* ALIGN prec64_case: //proc ; initially assume all guard, xchg (%ebp,%edi),%ecx // round, and sticky info zero and %ecx,%ecx // examine and clear grst word jns get_round_sticky_64 notb %dh // set guard byte get_round_sticky_64: and $0x7fffffff,%ecx jz get_lsb_64 notb %dl // set round-sticky byte get_lsb_64: xorb %ah,%ah // initially, assume lsb is zero testb $0x01,frac64(%ebp,%edi) jz set_round_info_64 notb %ah // set lsb byte set_round_info_64: mov $0x0108,%ecx // rounded result has 8 bytes common_return: ret // the pattern to add is 01h //prec64_case endp // // ********************************************************************** // round: // ***** // function: // implements rounding. // // inputs: // assumes: edi points to record to round, // dl contains rounding precision, // al is true if second rounding, false if first. // // outputs: // on return, al is true if there was an high-bit carry-out // as a result of incrementing the significand to do the rounding. // // data accessed: // added_one // // data changed: // added_one // // procedures called: // prec16_case prec24_case // prec32_case prec53_case // prec64_case get_rnd_control // // ************************************************************************ precn_case: .long prec24_case,prec32_case,prec53_case,prec64_case,prec16_case // rnd_case: .long case_rnd_to_even,case_rnd_down,case_rnd_up,case_rnd_to_zero // ALIGN round: //proc ; access unpacked status info xorb %dh,%dh // set to zero the following: movswl %dx,%esi // cl to num bytes in rnd frac shl $2,%esi // ch to pattern to add to low xorw %dx,%dx // byte in rounding xor %ecx,%ecx // dl if round or sticky set // mov (ebp+edi),dx ;*** zeroing low word call *%cs:precn_case(%esi) // dh if grd set, ah if lsb set andw %dx,%dx // if dl and dh both zero, then jnz inexact_case // result is exact cmpb true,%al movb %dl,%al // no carry out from rounding jne exact_1st_rnd movb %al,rnd2_inexact ret ALIGN exact_1st_rnd: movw %dx,rnd_history movb %al,added_one // clear flag, no overflow ret ALIGN // inexact_case: cmpb true,%al jne inexact_1st_rnd movb %al,rnd2_inexact jmp get_rnd_case ALIGN inexact_1st_rnd: movw true,rnd_history// makes rnd1_inexact true, rnd2_inexact false get_rnd_case: push %eax // save lsb/2nd rounding flags call get_rnd_control // round different rnd_control movzbl %al,%ebx // cases separately pop %eax // reload lsb/2nd rounding flags jmp *%cs:rnd_case(%ebx) ALIGN case_rnd_up: notb %bh //if + increment, else truncate case_rnd_down: cmpb %bh,sign(%ebp,%edi) //increment if neg, jne do_increment // truncate if pos jmp case_rnd_to_zero ALIGN case_rnd_to_even: movb %dl,%bh // save round-sticky info in bh orb %ah,%dl // if guard and (round or sticky cmpb true,%al // or lsb), set dx to round up jne do_add_ // if 2nd round, if ((lsb=added) // mov bl, added_one ; and not (round or sticky) // cmp al, rnd1_inexact ; and ((added=1) or last round // jne p_error_0 ; inexact)), round in opposite // mov bl, al ; al is true (0ffh), hence so is bl // the preceding four instructions are equivalent to the next one movb rnd1_inexact,%bl p_error_0: cmpw $0x00ff,%bx // unless first round was inexact and jne do_add_ // current round-sticky bits are clear, // decide how to round as for first round cmpb added_one,%ah // else, dh (guard) must be true here because // exact second rounds were ruled out earlier jne do_add_ // branch if ah <> added_one incw %dx // here, dh = guard, dl = lsb jz case_rnd_to_zero // truncate jmp do_increment ALIGN do_add_: incw %dx jz do_increment case_rnd_to_zero: movb false,%al // clear flag, indicate nothing movb %al,added_one // added in round (al = false) // and %gs:sr_flags,not a_mask ; clear the a-bit ---> defer jmp set_inexact ALIGN do_increment: // or %gs:sr_flags,a_mask ; set the a-bit ---> defer movb true,added_one // set flag for 1 added in round movb %ch,%dl // put pattern to add in dl xorb %ch,%ch // ecx = num bytes in rounded res mov $12,%ebx sub %ecx,%ebx // ebx = num of low byte add %ebx,%edi // edi = true offset xorb %al,%al addb %dl,(%ebp,%edi) // add pattern to low byte and inc %edi // propogate carries dec %ecx FALLSTHRU inc_loop: adcb %al,(%ebp,%edi) inc %edi LOOP(inc_loop) sbbb %al,%al // set al if carry set sub $12,%edi // restore edi to entry value set_inexact: // jmp set_p_error ---> defer ret //round endp // // **************************************************************************** // special_round_test: // ****************** // function: // test for rounding toward zero. // // inputs: // assumes sign to be in al upon entry. // // outputs: // returns true (in al) and clears zf if: // (rnd_down and sign is positive) or // (rnd_up and sign is negative); // else returns false (in al) and sets zf. // // data accessed: // // data changed: // // procedures called: // get_rnd_control // // ************************************************************************** ALIGN special_round_test: //proc movb %al,%ah // save sign call get_rnd_control //get rounding mode cmpb rnd_down,%al jne round_up_ // branch if not down andb %ah,%ah jz is_true // true if +rnd_down is_false: xorb %al,%al // sets zf. ret ALIGN round_up_: cmpb rnd_up,%al jne is_false // branch if not up andb %ah,%ah jz is_false // branch if +rnd_up is_true: orb true,%al // clears zf. exit_round_test: ret //special_round_test endp // // ************************************************************************** // directed_round_test: // ******************* // function: // test for round control (up or down). // // inputs: // none // // outputs: // returns true (in al) and clears zf if the round control // is rnd_up or rnd_down. otherwise, returns false and sets zf. // // data accessed: // // data changed: // // procedures called: // get_rnd_conrol // // ************************************************************************* ALIGN directed_round_test: //proc call get_rnd_control cmpb rnd_down,%al je is_true cmpb rnd_up,%al je is_true jmp is_false //directed_round_test endp // //a_med ends // // end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.