Mercurial > hg > index.cgi
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 |