;************************************************************ ;IEEE 64 Bit Floating Point Library (c) 2003 M.Cibulski ; ;Conversion Routines ; ;************************************************************ ;************************************************************ ;Convert double to 2 byte integer ; ;Parameters: ;AKKU double ; ;Result: ;AKKU2/3 2 byte integer ; ;************************************************************ .CSEG flt_double2word: ;f_subexp r16 ,0x3ff+12 ldi r16 ,low(0x3ff+12) ;???adx sub AKKU_E2 ,r16 ldi r16 ,high(0x3ff+12) sbc AKKU_E1 ,r16 brcc flt_d2w_big ;no underflow, shift left inc AKKU_E1 ;exponent much too small ? brne flt_d2w_toosmall ;yes, return zero ldi r16 ,-13 cp AKKU_E2 ,r16 ;exponent too small ? brcc flt_d2w_shift_right ;no, shift bits flt_d2w_toosmall: clr AKKU_2 ;return zero clr AKKU_3 set ;status: OK ret flt_d2w_shift_right: asr AKKU_2 ;shift right ror AKKU_3 ror AKKU_4 inc AKKU_E2 ;exponent++ brmi flt_d2w_shift_right ;still negative, shift again tst AKKU_S ;negative number brmi flt_d2w_negative ;yes, make negative flt_d2w_positive: tst AKKU_4 ;next bit after result brpl flt_d2w_positive_end ;zero, no round up sec ;round up, add 1 to result adc AKKU_3 ,AKKU_E2 ;AKKU_E2 = zero adc AKKU_2 ,AKKU_E2 brmi flt_d2w_toobig_positive ;overflow ? flt_d2w_positive_end: set ;status:OK ret ;return positive result flt_d2w_big: tst AKKU_E1 ;more than 255 positions to shift brne flt_d2w_toobig ;much too big for word integer inc AKKU_E2 ldi r16 ,4 ;3 or more positions to shift cp AKKU_E2 ,r16 brcs flt_d2w_shift_left_start ;no, shift bits flt_d2w_toobig: tst AKKU_S ;negative number ? brpl flt_d2w_toobig_positive ;no, return biggest positive integer flt_d2w_toobig_negative: ldi r16 ,0x80 ;smallest negative word integer mov AKKU_2 ,r16 clr AKKU_3 ;0x8000 = -32768 clt ;status: ERROR ret flt_d2w_toobig_positive: ldi r16 ,0x7F ;biggest positive word integer mov AKKU_2 ,r16 ldi r16 ,0xFF ;0x7FFF = +32767 mov AKKU_3 ,r16 clt ;status: ERROR ret flt_d2w_shift_left: lsl AKKU_4 rol AKKU_3 rol AKKU_2 flt_d2w_shift_left_start: dec AKKU_E2 brne flt_d2w_shift_left tst AKKU_S ;negative number ? brpl flt_d2w_positive ;no, return positive result flt_d2w_negative: com AKKU_3 ;make negative com AKKU_2 ldi r16 ,0xFF sub AKKU_3 ,r16 sbc AKKU_2 ,r16 tst AKKU_4 ;next bit after (absolute) result brpl flt_d2w_negative_end ;zero, no round up sec sbc AKKU_3 ,AKKU_E2 ;zero sbc AKKU_2 ,AKKU_E2 brpl flt_d2w_toobig_negative ;handle underflow (possible ?) flt_d2w_negative_end: set ;status: OK ret ;return negative result ;************************************************************ ;Convert double to 4 byte integer ; ;Parameters: ;AKKU double ; ;Result: ;AKKU2/3/4/5 4 byte integer ; ;************************************************************ .CSEG flt_double2long: ;f_subexp r16 ,0x3ff+28 ldi r16 ,low(0x3ff+28) sub AKKU_E2 ,r16 ldi r16 ,high(0x3ff+28) sbc AKKU_E1 ,r16 brcc flt_d2l_big ;no underflow, shift left inc AKKU_E1 ;exponent much too small ? brne flt_d2l_toosmall ;yes, return zero ldi r16 ,-29 cp AKKU_E2 ,r16 ;exponent too small ? brcc flt_d2l_shift_right ;no, shift bits flt_d2l_toosmall: clr AKKU_2 ;return zero clr AKKU_3 clr AKKU_4 clr AKKU_5 set ;status: OK ret flt_d2l_shift_right: asr AKKU_2 ;shift right ror AKKU_3 ror AKKU_4 ror AKKU_5 ror AKKU_6 inc AKKU_E2 ;exponent++ brmi flt_d2l_shift_right ;still negative, shift again tst AKKU_S ;negative number brmi flt_d2l_negative ;yes, make negative flt_d2l_positive: tst AKKU_6 ;next bit after result brpl flt_d2l_positive_end ;zero, no round up sec ;round up, add 1 to result adc AKKU_5 ,AKKU_E2 ;AKKU_E2 = zero adc AKKU_4 ,AKKU_E2 adc AKKU_3 ,AKKU_E2 adc AKKU_2 ,AKKU_E2 brmi flt_d2l_toobig_positive ;overflow ? flt_d2l_positive_end: set ;status:OK ret ;return positive result flt_d2l_big: tst AKKU_E1 ;more than 255 positions to shift brne flt_d2l_toobig ;much too big for word integer inc AKKU_E2 ldi r16 ,4 ;3 or more positions to shift cp AKKU_E2 ,r16 brcs flt_d2l_shift_left_start ;no, shift bits flt_d2l_toobig: tst AKKU_S ;negative number ? brpl flt_d2l_toobig_positive ;no, return biggest positive integer flt_d2l_toobig_negative: ldi r16 ,0x80 ;smallest negative long integer mov AKKU_2 ,r16 clr AKKU_3 ;0x80000000 = -2147483648 clr AKKU_4 clr AKKU_5 clt ;status: ERROR ret flt_d2l_toobig_positive: ldi r16 ,0x7F mov AKKU_2 ,r16 ;biggest positive word integer ldi r16 ,0xFF ;0x7FFFFFFF = +2147483647 mov AKKU_3 ,r16 mov AKKU_4 ,r16 mov AKKU_5 ,r16 clt ;status: ERROR ret flt_d2l_shift_left: lsl AKKU_6 rol AKKU_5 rol AKKU_4 rol AKKU_3 rol AKKU_2 flt_d2l_shift_left_start: dec AKKU_E2 brne flt_d2l_shift_left tst AKKU_S ;negative number ? brpl flt_d2l_positive ;no, return positive result flt_d2l_negative: com AKKU_5 ;make negative com AKKU_4 com AKKU_3 com AKKU_2 ldi r16 ,0xFF sub AKKU_5 ,r16 sbc AKKU_4 ,r16 sbc AKKU_3 ,r16 sbc AKKU_2 ,r16 tst AKKU_6 ;next bit after (absolute) result brpl flt_d2l_negative_end ;zero, no round up sec sbc AKKU_5 ,AKKU_E2 ;zero sbc AKKU_4 ,AKKU_E2 sbc AKKU_3 ,AKKU_E2 sbc AKKU_2 ,AKKU_E2 brpl flt_d2l_toobig_negative ;handle underflow (possible ?) flt_d2l_negative_end: set ;status: OK ret ;return negative result ;************************************************************ ;Convert 2 byte integer value to double ; ;Parameters: ;AKKU2/3 2 byte interger ; ;Result: ;AKKU floating point akkumulator A ; ;************************************************************ .CSEG flt_convert_word: mov r0 ,AKKU_2 or r0 ,AKKU_3 brne flt_convert_word_nonzero jmp flt_load_zero flt_convert_word_nonzero: clr AKKU_S tst AKKU_2 brpl flt_convert_word_plus com AKKU_2 com AKKU_3 ldi r16 ,0xFF sub AKKU_3 ,r16 sbc AKKU_2 ,r16 ldi r16 ,0x80 mov AKKU_S ,r16 ;minus sign flt_convert_word_plus: clr AKKU_4 clr AKKU_5 clr AKKU_6 clr AKKU_7 clr AKKU_8 f_ldiexp r16 ,0x3FF+12 flt_convert_word_rshift: ldi r16 ,0x20 ;mantissa too big cp AKKU_2 ,r16 brcs flt_convert_word_lshift ;no, not right shifting asr AKKU_2 ;shift right ror AKKU_3 ror AKKU_4 ;f_addexp r16 ,1 ldi r16 ,low(1) ;exponent +1 add AKKU_E2 ,r16 ldi r16 ,high(1) adc AKKU_E1 ,r16 rjmp flt_convert_word_rshift flt_convert_word_lshift: ldi r16 ,0x10 ;small mantissa without leading 1 cp AKKU_2 ,r16 brcc flt_convert_word_end lsl AKKU_3 ;shift left rol AKKU_2 ;f_subexp r16 ,1 ldi r16 ,low(1) ;exponent -1 sub AKKU_E2 ,r16 ldi r16 ,high(1) sbc AKKU_E1 ,r16 rjmp flt_convert_word_lshift flt_convert_word_end: ret ;************************************************************ ;Convert 4 byte integer value do double ; ;Parameters: ;AKKU2/3/4/5 4 byte integer ; ;Result: ;AKKU floating point akkumulator A ; ;************************************************************ .CSEG flt_convert_long: mov r0 ,AKKU_2 or r0 ,AKKU_3 or r0 ,AKKU_4 or r0 ,AKKU_5 brne flt_convert_long_nonzero jmp flt_load_zero flt_convert_long_nonzero: clr AKKU_S tst AKKU_2 brpl flt_convert_long_plus com AKKU_2 com AKKU_3 com AKKU_4 com AKKU_5 ldi r16 ,0xFF sub AKKU_5 ,r16 sbc AKKU_4 ,r16 sbc AKKU_3 ,r16 sbc AKKU_2 ,r16 ldi r16 ,0x80 mov AKKU_S ,r16 ;minus sign flt_convert_long_plus: clr AKKU_6 clr AKKU_7 clr AKKU_8 f_ldiexp r16 ,0x3FF+28 flt_convert_long_rshift: ldi r16 ,0x20 cp AKKU_2 ,r16 ;mantissa too big brcs flt_convert_long_lshift ;no, not right shifting asr AKKU_2 ;shift right ror AKKU_3 ror AKKU_4 ror AKKU_5 ror AKKU_6 ;f_addexp r16 ,1 ldi r16 ,low(1) ;exponent +1 add AKKU_E2 ,r16 ldi r16 ,high(1) adc AKKU_E1 ,r16 rjmp flt_convert_long_rshift flt_convert_long_lshift: ldi r16 ,0x10 cp AKKU_2 ,r16 ;small mantissa without leading 1 brcc flt_convert_long_end lsl AKKU_5 ;shift left rol AKKU_4 ;shift left rol AKKU_3 ;shift left rol AKKU_2 ;f_subexp r16 ,1 ldi r16 ,low(1) ;exponent -1 sub AKKU_E2 ,r16 ldi r16 ,high(1) sbc AKKU_E1 ,r16 rjmp flt_convert_long_lshift flt_convert_long_end: ret ;************************************************************