/* * fixsfsi.s * * Floating point to signed long conversion, single precision: * r0r1 = (long) float r0r1 * Floating point to unsigned long conversion, single precision: * r0r1 = (unsigned long) float r0r1 * * As far as I can tell, conversions for out-of-range values not well-defined * I chose to implement the following: * * For conversion to signed long, values for out-of-range conversions are: * * converted value < -MAXINT -> -MAXINT * converted value > +MAXINT -> +MAXINT * input value == NaN -> +MAXINT * * For conversion to unsigned long, values for out-of-range conversions are: * * converted value < 0 -> +MAXUINT * converted value > +MAXUINT -> +MAXUINT * input value == NaN -> +MAXUINT * * -MAXINT is -2^31, +MAXINT is 2^31-1, +MAXUINT is 2^32-1 * * Another possibility would have been to return numbers modulo 2^31 or 2^32 * Or, could have returned either +MAXINT or +MAXUINT given out-of-range input * * The contents of this file are subject to the Mozilla Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * The Original Code is Librcx floating point code, released May 27, 1999. * * The Initial Developer of the Original Code is Kekoa Proudfoot. * Portions created by Kekoa Proudfoot are Copyright (C) 1999 * Kekoa Proudfoot. All Rights Reserved. * * Contributor(s): Kekoa Proudfoot */ .section .text ;; ;; function: fixsfsi ;; input: float in r0r1 ;; output: signed long in r0r1 ;; .global ___fixsfsi ___fixsfsi: ; Assume r2 and r3 saved by caller mov.b #0,r2h ; load sign mask mov.b #157,r2l ; load maximum exponent (bias + 30) mov.b #0x80,r3h ; load upper byte of lower return value mov.b #0x7f,r3l ; load upper byte of higher return value ; Jump to fix routine bra fix ;; ;; function: fixunssfsi ;; input: float in r0r1 ;; output: unsigned long in r0r1 ;; .global ___fixunssfsi ___fixunssfsi: ; Assume r2 and r3 saved by caller mov.b #0x80,r2h ; load sign mask mov.b #158,r2l ; load maximum exponent (bias + 31) mov.b #0xff,r3h ; load upper byte of lower return value mov.b #0xff,r3l ; load upper byte of higher return value ; Fall through to fix routine ;; ;; function: fix ;; input: float in r0r1, sign mask in r2h, max exp in r2l, return values in r3 ;; output: signed or unsigned long in r0r1 ;; fix: ; Save registers push r4 push r5 push r6 ; Rearrange registers mov.w r0,r5 ; copy input operand to r5r6 mov.w r1,r6 mov.w r3,r0 ; copy return values to r0 ; Expand the input operand jsr ___expandsf ; expand to r3h r3l r4 r5r6 ; At this point, registers contain the following: ; r0h - upper byte of lower return value ; r0l - upper byte of higher return value (also used if input is NaN) ; r1 - [empty] ; r2h - sign mask ; r2l - maximum exponent ; r3h - input operand flags ; r3l - input operand sign ; r4 - input operand exponent ; r5r6 - input operand mantissa ; Note on flag bits: 0=zero, 1=inf, 2=nan ; Is the exponent small enough to make the number effectively zero? mov.w #127,r1 ; load bias to r1 cmp.w r1,r4 ; is exponent < bias? bge endif_0 ; greater than or equal indicates false ; Return zero result sub.w r0,r0 ; load zero to result (r0r1) sub.w r1,r1 bra return endif_0: ; Are we doing an unsigned conversion and is the number negative? ; Or does number's exponent exceed the maximum allowed value? ; Use sign mask to implement first test ; Also, note that if first test false, r2h cleared to zero for second test and.b r3l,r2h ; and sign into sign mask bne if_1 ; not equal indicates true cmp.w r2,r4 ; is exponent > maximum value for conversion? ble endif_1 ; less than or equal indicates false if_1: ; Input is out of range. ; Is the number positive or NaN? bild #7,r3l ; load ~sign bit to carry bor #2,r3h ; or with nan flag bit bcc endif_2 ; carry clear indicates false ; Move upper byte of higher return value to r0h mov.b r0l,r0h endif_2: ; Correct upper byte of return value now in r0h ; Push lsb down into lower bytes bld #0,r0h ; load lsb to carry subx.b r0l,r0l ; bit extend right subx.b r1h,r1h subx.b r1l,r1l bra return endif_1: ; At this point, we no longer need r0 r1 r2 ; Left shift mantissa by 8 places ; This makes later shift take more time, but it also makes code smaller mov.b r5l,r5h ; shift by rearranging bytes mov.b r6h,r5l mov.b r6l,r6h sub.b r6l,r6l ; Subtract bias + 31 from exponent add.b #-158,r4l ; subtract bias + 31 from exponent addx.b #-1,r4h ; Is exponent < 0 ? ; Note: do nothing if exponent >= 0 ; Also note exponent should not be greater than zero if maximum ; exponent checks done correctly bge endif_3 ; greater than or equal indicates false ; Shift mantissa right, increasing exponent until it reaches zero ; Note exponent only has 1 significant byte dowhile_4: shlr.b r5h ; shift mantissa right one place rotxr.b r5l rotxr.b r6h rotxr.b r6l inc r4l ; increment exponent blt dowhile_4 ; continue while less than zero endif_3: ; Copy result to output mov.w r5,r0 ; copy result (r5r6) to output (r0r1) mov.w r6,r1 ; Is sign < 0 ? mov.b r3l,r3l ; is sign < 0 ? bge endif_5 ; greater than or equal indicates false ; Negate result sub.w r0,r0 ; zero destination sub.w r1,r1 sub.w r6,r1 ; subtract result (result in r5r6) subx.b r5l,r0l subx.b r5h,r0h endif_5: return: ; Restore registers pop r6 pop r5 pop r4 rts