comparison src/fps.s @ 98:6837d10b67fb

Add integer <-> float conversion routines and combine some code for parsing
author William Astle <lost@l-w.ca>
date Sun, 22 Oct 2023 23:54:24 -0600
parents 69af7224f614
children 4d7fa11ebe3f
comparison
equal deleted inserted replaced
97:b375a38b2b1a 98:6837d10b67fb
338 ; Once the leftmost digit is nonzero, the leftmost extra precision digit is checked to see if it is >= 5. If so, the 338 ; Once the leftmost digit is nonzero, the leftmost extra precision digit is checked to see if it is >= 5. If so, the
339 ; significand will have 1 added to it. If that triggers a carry, the decimal exponent will be incremented and the 339 ; significand will have 1 added to it. If that triggers a carry, the decimal exponent will be incremented and the
340 ; significand will have its leftmost digit set to 1. 340 ; significand will have its leftmost digit set to 1.
341 ; 341 ;
342 ; This will trigger an overflow if the decimal exponent exceeds the allowed range. 342 ; This will trigger an overflow if the decimal exponent exceeds the allowed range.
343 fps_normalize clrb ; initialize the exponent adjustment counter 343 fps_normalize bsr fps_normalizea0 ; do the normalization in fpa0
344 leax ,y ; point to the desired destination
345 jmp fps_pack0 ; go pack the result to the correct destination
346 fps_normalizea0 clrb ; initialize the exponent adjustment counter
344 fps_normalize0 lda fpa0+fpa.sig ; do we have a nonzero digit in the first pair? 347 fps_normalize0 lda fpa0+fpa.sig ; do we have a nonzero digit in the first pair?
345 bne fps_normalize1 ; brif so 348 bne fps_normalize1 ; brif so
346 lda fpa0+fpa.sig+1 ; shift everything left 2 spaces 349 lda fpa0+fpa.sig+1 ; shift everything left 2 spaces
347 sta fpa0+fpa.sig 350 sta fpa0+fpa.sig
348 lda fpa0+fpa.sig+2 351 lda fpa0+fpa.sig+2
365 subb #2 ; account for two digit positions 368 subb #2 ; account for two digit positions
366 cmpb #-10 ; have we shifted the whole set of digits (assumes originally normalized) 369 cmpb #-10 ; have we shifted the whole set of digits (assumes originally normalized)
367 bgt fps_normalize0 ; brif not 370 bgt fps_normalize0 ; brif not
368 fps_normalize4 clr fpa0+fpa.exp ; set result to zero 371 fps_normalize4 clr fpa0+fpa.exp ; set result to zero
369 clr fpa0+fpa.sign 372 clr fpa0+fpa.sign
370 fps_normalize5 leax ,y ; point to return location 373 fps_normalize5 rts
371 jmp fps_pack0 ; return result
372 fps_normalize1 bita #0xf0 ; is the high digit zero? 374 fps_normalize1 bita #0xf0 ; is the high digit zero?
373 bne fps_normalize3 ; brif not 375 bne fps_normalize3 ; brif not
374 lsl fpaextra ; only need to shift one extra position here since there won't be more shifts 376 lsl fpaextra ; only need to shift one extra position here since there won't be more shifts
375 rol fpa0+fpa.sig+4 377 rol fpa0+fpa.sig+4
376 rol fpa0+fpa.sig+3 378 rol fpa0+fpa.sig+3
883 bra fps_toascii5 ; go convert the significand 885 bra fps_toascii5 ; go convert the significand
884 fps_toascii15 ldb #1 ; put decimal after the first digit 886 fps_toascii15 ldb #1 ; put decimal after the first digit
885 stb fpaextra+1 887 stb fpaextra+1
886 sta fpaextra+3 ; enable the "E" notation with the correct exponent 888 sta fpaextra+3 ; enable the "E" notation with the correct exponent
887 bra fps_toascii5 ; actually convert the number 889 bra fps_toascii5 ; actually convert the number
890 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
891 ; Convert a 32 bit integer at (X) to BCD floating point. This requires converting the 32 bit binary value to BCD which
892 ; can be done using the double/dabble algorithm. fpa0 and fpaextra is used as temporary storage. X must point to a value.
893 ; Enter at fps_fromuint to treat the 32 value as unsigned.
894 fps_fromint ldb val.int,x ; is the integer negative?
895 bpl fps_fromuint ; brif not
896 sex ; set sign to negative
897 sta fpa0+fpa.sign
898 ldd zero ; negate the value and store it to temporary location
899 subd val.int+2,x
900 std fpaextra+2
901 ldd zero
902 sbcb val.int+1,x
903 sbca val.int,x
904 std fpaextra
905 bra fps_fromint0 ; go finish the conversion
906 fps_fromuint clr fpa0+fpa.sign ; set sign to positive
907 ldd val.int+2,x ; copy value to temporary accumulator
908 std fpaextra+2
909 ldd val.int,x
910 std fpaextra
911 fps_fromint0 leay ,x ; set result destination pointer
912 ldd zero ; zero out destination
913 std fpa0+fpa.sig
914 std fpa0+fpa.sig+2
915 sta fpa0+fpa.sig+4
916 ldd #0x5f20 ; set exponent for decimal right of significand and 32 bit shifts
917 sta fpa0+fpa.exp ; save exponent
918 stb fpaextra+5 ; save counter
919 bra fps_fromint2 ; skip digit check on the first iteration since none need adjustment
920 fps_fromint1 ldu #fpa0+fpa.sig ; point to significand
921 bsr fps_fromint3 ; do adjustments, 5 bytes worth of digits
922 bsr fps_fromint3
923 bsr fps_fromint3
924 bsr fps_fromint3
925 bsr fps_fromint3
926 fps_fromint2 lsl fpaextra+3 ; shift left
927 rol fpaextra+2
928 rol fpaextra+1
929 rol fpaextra
930 rol fpa0+fpa.sig+4
931 rol fpa0+fpa.sig+3
932 rol fpa0+fpa.sig+2
933 rol fpa0+fpa.sig+1
934 rol fpa0+fpa.sig
935 dec fpaextra+5 ; done all digits?
936 bne fps_fromint1 ; brif not
937 jsr fps_normalizea0 ; go normalize the result in fpa0
938 ldd fpa0+fpa.sig ; copy result to destination
939 std val.fpssig,y
940 ldd fpa0+fpa.sig+2
941 std val.fpssig+2,y
942 lda fpa0+fpa.sig+4
943 sta val.fpssig+4,y
944 lda fpa0+fpa.exp
945 sta val.fpsexp,y
946 lda fpa0+fpa.sign
947 sta val.fpssign,y
948 lda #valtype_float ; set result type to floating point
949 sta val.type,y
950 rts
951 ; This is the digit check for the double-dabble algorith. The left digit check is only concerned if the left digit
952 ; is 5 or higher. Since we can make that comparison without masking the bits, we don't bother. For the right digit,
953 ; however, we do have to mask the upper digit off. It saves and ANDA and a subsequent indexed reload.
954 fps_fromint3 clrb ; set adjustment to none
955 lda ,u ; get digits
956 cmpa #0x50 ; is digit 5 or higher?
957 blo fps_fromint4 ; brif not
958 ldb #0x30 ; set adjustment factor for first digit
959 fps_fromint4 anda #0x0f ; keep low digit
960 cmpa #5 ; is it 5 or higher?
961 blo fps_fromint5 ; brif not
962 orb #0x03 ; set adjustment for second digit
963 fps_fromint5 addb ,u ; add adjustment to digits
964 stb ,u+ ; save new digit values and move on
965 rts
966 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
967 ; Convert the floating point value in the value accumulator at (X) to a 32 bit signed integer. Will trigger an overflow
968 ; if the magnitude is too large and it will truncate (round toward zero) any fractional value.
969 fps_toint lda val.fpsexp,x ; copy the exponent, sign, and significand to fpa0
970 sta fpa0+fpa.exp
971 ldd val.fpssig,x
972 std fpa0+fpa.sig
973 ldd val.fpssig+2,x
974 std fpa0+fpa.sig+2
975 lda val.fpssig+4,x
976 sta fpa0+fpa.sig+4
977 lda val.fpssign,x
978 sta fpa0+fpa.sign
979 bsr fps_tointa0 ; convert value to integer in fpa0 significand
980 lda #valtype_int ; set result to integer
981 sta val.type,x
982 ldd fpa0+fpa.sig+1
983 std val.int,x
984 ldd fpa0+fpa.sig+3
985 std val.int+2,x
986 rts
987 fps_tointa0 ldb fpa0+fpa.exp ; compare exponent (is it too big?)
988 cmpb #64+9
989 bne fps_toint0
990 ldd fpa0+fpa.sig ; compare top of significand
991 cmpd #0x2147
992 bne fps_toint0
993 ldd fpa0+fpa.sig+2 ; compare middle of significand
994 cmpd #0x4836
995 bne fps_toint0
996 ldd fpa0+fpa.sig+4 ; compare bottom of significand plus extra digits
997 cmpd #0x4800
998 fps_toint0 blt fps_toint1 ; brif it fits positive or negative
999 lbgt OVERROR ; brif it doesn't fit negative either
1000 ldb fpa0+fpa.sign ; do we want negative?
1001 lbpl OVERROR ; brif not - it doesn't fit
1002 ; Enter here if we already know that the value will fit
1003 fps_toint1 ldb #64+9 ; biased exponent needed for decimal point to the right of significand
1004 subb fpa0+fpa.exp ; number of digit shifts needed to denormalize
1005 beq fps_toint3 ; brif already denormalized
1006 lslb ; do 4 shifts per digit; we're going to simply lose extra digits
1007 lslb
1008 fps_toint2 lsr fpa0+fpa.sig ; shift a digit right
1009 ror fpa0+fpa.sig+1
1010 ror fpa0+fpa.sig+2
1011 ror fpa0+fpa.sig+3
1012 ror fpa0+fpa.sig+4
1013 decb ; done all shifts?
1014 bne fps_toint2
1015 ; Now convert BCD digit sequence in fpa0 significand to binary value in the low 32 bits of the significand
1016 fps_toint3 ldb #32 ; 32 bit shifts needed for whole significand
1017 stb fpa0+fpa.extra ; use extra precision byte as counter
1018 fps_toint4 lsr fpa0+fpa.sig ; shift a bit into the binary result
1019 ror fpa0+fpa.sig+1
1020 ror fpa0+fpa.sig+2
1021 ror fpa0+fpa.sig+3
1022 ror fpa0+fpa.sig+4
1023 ror fpa0+fpa.extra+1
1024 ror fpa0+fpa.extra+2
1025 ror fpa0+fpa.extra+3
1026 ror fpa0+fpa.extra+4
1027 ldu #fpa0+fpa.sig ; point to BCD digits
1028 fps_toint5 lda ,u ; get byte to check
1029 beq fps_toint8 ; short circuit check if digits are 0
1030 anda #0x88 ; keep bit 3 of each digit; adjustment on >= 8
1031 lsra ; shift over and mulply by adjustment factor
1032 lsra
1033 lsra
1034 ldb #3 ; the adjustment is a subtraction by 3
1035 mul
1036 negb ; now subtract from digit
1037 addb ,u
1038 stb ,u+
1039 fps_toint6 cmpu #fpa0+fpa.sig+5 ; done all 5 bytes?
1040 blo fps_toint5 ; brif not
1041 dec fpa0+fpa.extra ; done all bits?
1042 bne fps_toint6 ; brif not
1043 ldb fpa0+fpa.sign ; do we want negative?
1044 bpl fps_toint7 ; brif not
1045 ldd zero ; negate the value through subtracting from 0
1046 subd fpa0+fpa.extra+3
1047 std fpa0+fpa.extra+3
1048 ldd zero
1049 sbcb fpa0+fpa.extra+1
1050 sbca fpa0+fpa.extra
1051 std fpa0+fpa.sig+1
1052 fps_toint7 ldd fpa0+fpa.extra+1 ; put result in the significand
1053 std fpa0+fpa.sig+1
1054 ldd fpa0+fpa.extra+3
1055 std fpa0+fpa.sig+3
1056 rts
1057 fps_toint8 leau 1,u ; move to next digit
1058 bra fps_toint6 ; go back to mainline
888 *pragmapop list 1059 *pragmapop list