aboutsummaryrefslogtreecommitdiffstats
path: root/tests/t_bas52/bas52.fp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/t_bas52/bas52.fp')
-rw-r--r--tests/t_bas52/bas52.fp1616
1 files changed, 1616 insertions, 0 deletions
diff --git a/tests/t_bas52/bas52.fp b/tests/t_bas52/bas52.fp
new file mode 100644
index 0000000..c8a137c
--- /dev/null
+++ b/tests/t_bas52/bas52.fp
@@ -0,0 +1,1616 @@
+;************************************************************
+;
+; This is a complete BCD floating point package for the 8051 micro-
+; controller. It provides 8 digits of accuracy with exponents that
+; range from +127 to -127. The mantissa is in packed BCD, while the
+; exponent is expressed in pseudo-twos complement. A ZERO exponent
+; is used to express the number ZERO. An exponent value of 80H or
+; greater than means the exponent is positive, i.e. 80H = E 0,
+; 81H = E+1, 82H = E+2 and so on. If the exponent is 7FH or less,
+; the exponent is negative, 7FH = E-1, 7EH = E-2, and so on.
+; ALL NUMBERS ARE ASSUMED TO BE NORMALIZED and all results are
+; normalized after calculation. A normalized mantissa is >=.10 and
+; <=.99999999.
+;
+; The numbers in memory assumed to be stored as follows:
+;
+; EXPONENT OF ARGUMENT 2 = VALUE OF ARG_STACK+FP_NUMBER_SIZE
+; SIGN OF ARGUMENT 2 = VALUE OF ARG_STACK+FP_NUMBER_SIZE-1
+; DIGIT 78 OF ARGUMENT 2 = VALUE OF ARG_STACK+FP_NUMBER_SIZE-2
+; DIGIT 56 OF ARGUMENT 2 = VALUE OF ARG_STACK+FP_NUMBER_SIZE-3
+; DIGIT 34 OF ARGUMENT 2 = VALUE OF ARG_STACK+FP_NUMBER_SIZE-4
+; DIGIT 12 OF ARGUMENT 2 = VALUE OF ARG_STACK+FP_NUMBER_SIZE-5
+;
+; EXPONENT OF ARGUMENT 1 = VALUE OF ARG_STACK
+; SIGN OF ARGUMENT 1 = VALUE OF ARG_STACK-1
+; DIGIT 78 OF ARGUMENT 1 = VALUE OF ARG_STACK-2
+; DIGIT 56 OF ARGUMENT 1 = VALUE OF ARG_STACK-3
+; DIGIT 34 OF ARGUMENT 1 = VALUE OF ARG_STACK-4
+; DIGIT 12 OF ARGUMENT 1 = VALUE OF ARG_STACK-5
+;
+; The operations are performed thusly:
+;
+; ARG_STACK+FP_NUMBER_SIZE = ARG_STACK+FP_NUMBER_SIZE # ARG_STACK
+;
+; Which is ARGUMENT 2 = ARGUMENT 2 # ARGUMENT 1
+;
+; Where # can be ADD, SUBTRACT, MULTIPLY OR DIVIDE.
+;
+; Note that the stack gets popped after an operation.
+;
+; The FP_COMP instruction POPS the ARG_STACK TWICE and returns status.
+;
+;**********************************************************************
+;
+
+ segment code
+ newpage
+ section float ; protect symbols
+;**********************************************************************
+;
+; STATUS ON RETURN - After performing an operation (+, -, *, /)
+; the accumulator contains the following status
+;
+; ACCUMULATOR - BIT 0 - FLOATING POINT UNDERFLOW OCCURED
+;
+; - BIT 1 - FLOATING POINT OVERFLOW OCCURED
+;
+; - BIT 2 - RESULT WAS ZER0
+;
+; - BIT 3 - DIVIDE BY ZERO ATTEMPTED
+;
+; - BIT 4 - NOT USED, 0 RETURNED
+;
+; - BIT 5 - NOT USED, 0 RETURNED
+;
+; - BIT 6 - NOT USED, 0 RETURNED
+;
+; - BIT 7 - NOT USED, 0 RETURNED
+;
+; NOTE: When underflow occures, a ZERO result is returned.
+; When overflow or divide by zero occures, a result of
+; .99999999 E+127 is returned and it is up to the user
+; to handle these conditions as needed in the program.
+;
+; NOTE: The Compare instruction returns F0 = 0 if ARG 1 = ARG 2
+; and returns a CARRY FLAG = 1 if ARG 1 is > ARG 2
+;
+;***********************************************************************
+;
+ newpage
+;***********************************************************************
+;
+; The following values MUST be provided by the user
+;
+;***********************************************************************
+;
+ARG_STACK EQU 9 ;ARGUMENT STACK POINTER
+ARG_STACK_PAGE EQU 1
+FORMAT EQU 23 ;LOCATION OF OUTPUT FORMAT BYTE
+OUTPUT EQU 1990H ;CALL LOCATION TO OUTPUT A CHARACTER
+CONVT EQU 58H ;LOCATION TO CONVERT NUMBERS
+INTGRC BIT 25 ;BIT SET IF INTGER ERROR
+ZSURP BIT 54 ;ZERO SUPRESSION FOR HEX PRINT
+;
+;***********************************************************************
+;
+; The following equates are used internally
+;
+;***********************************************************************
+;
+FP_NUMBER_SIZE EQU 6
+DIGIT EQU FP_NUMBER_SIZE-2
+R0B0 EQU 0
+R1B0 EQU 1
+UNDERFLOW EQU 0
+ACC_UNDERFLOW BIT ACC.0 ; ******AA added
+OVERFLOW EQU 1
+ACC_OVERFLOW BIT ACC.1 ; ******AA added
+ZERO EQU 2
+ACC_ZERO BIT ACC.2 ; ******AA added
+ZERO_DIVIDE EQU 3
+ACC_ZERO_DIVIDE BIT ACC.3 ; ******AA added
+;
+;***********************************************************************
+ newpage
+ ;**************************************************************
+ ;
+ ; The following internal locations are used by the math pack
+ ; ordering is important and the FP_DIGITS must be bit
+ ; addressable
+ ;
+ ;***************************************************************
+ ;
+FP_STATUS EQU 28H ;NOT USED
+FP_TEMP EQU FP_STATUS+1 ;NOT USED
+FP_CARRY SFRB FP_STATUS+2 ;USED FOR BITS ******AA EQU-->SFRB
+ADD_IN BIT 35 ;DCMPXZ IN BASIC BACKAGE
+XSIGN BIT FP_CARRY.0
+FOUND_RADIX BIT FP_CARRY.1
+FIRST_RADIX BIT FP_CARRY.2
+DONE_LOAD BIT FP_CARRY.3
+FP_DIG12 EQU FP_CARRY+1
+FP_DIG34 EQU FP_CARRY+2
+FP_DIG56 EQU FP_CARRY+3
+FP_DIG78 EQU FP_CARRY+4
+FP_SIGN SFRB FP_CARRY+5 ; ******AA EQU-->SFRB
+MSIGN BIT FP_SIGN.0
+FP_EXP EQU FP_CARRY+6
+FP_NIB1 EQU FP_DIG12
+FP_NIB2 EQU FP_NIB1+1
+FP_NIB3 EQU FP_NIB1+2
+FP_NIB4 EQU FP_NIB1+3
+FP_NIB5 EQU FP_NIB1+4
+FP_NIB6 EQU FP_NIB1+5
+FP_NIB7 EQU FP_NIB1+6
+FP_NIB8 EQU FP_NIB1+7
+FP_ACCX EQU FP_NIB1+8
+FP_ACCC EQU FP_NIB1+9
+FP_ACC1 EQU FP_NIB1+10
+FP_ACC2 EQU FP_NIB1+11
+FP_ACC3 EQU FP_NIB1+12
+FP_ACC4 EQU FP_NIB1+13
+FP_ACC5 EQU FP_NIB1+14
+FP_ACC6 EQU FP_NIB1+15
+FP_ACC7 EQU FP_NIB1+16
+FP_ACC8 EQU FP_NIB1+17
+FP_ACCS EQU FP_NIB1+18
+ ;
+ newpage
+ ORG 1993H
+ ;
+ ;**************************************************************
+ ;
+ ; The floating point entry points and jump table
+ ;
+ ;**************************************************************
+ ;
+ AJMP FLOATING_ADD
+ AJMP FLOATING_SUB
+ AJMP FLOATING_COMP
+ AJMP FLOATING_MUL
+ AJMP FLOATING_DIV
+ AJMP HEXSCAN
+ AJMP FLOATING_POINT_INPUT
+ AJMP FLOATING_POINT_OUTPUT
+ AJMP CONVERT_BINARY_TO_ASCII_STRING
+ AJMP CONVERT_ASCII_STRING_TO_BINARY
+ AJMP MULNUM10
+ AJMP HEXOUT
+ AJMP PUSHR2R0
+ ;
+ newpage
+ ;
+FLOATING_SUB:
+ ;
+ MOV P2,#ARG_STACK_PAGE
+ MOV R0,ARG_STACK
+ DEC R0 ;POINT TO SIGN
+ MOVX A,@R0 ;READ SIGN
+ CPL ACC.0
+ MOVX @R0,A
+ ;
+ ;AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ ;
+FLOATING_ADD:
+ ;
+ ;AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ ;
+ ;
+ ACALL MDES1 ;R7=TOS EXP, R6=TOS-1 EXP, R4=TOS SIGN
+ ;R3=TOS-1 SIGN, OPERATION IS R1 # R0
+ ;
+ MOV A,R7 ;GET TOS EXPONENT
+ JZ POP_AND_EXIT ;IF TOS=0 THEN POP AND EXIT
+ CJNE R6,#0,LOAD1 ;CLEAR CARRY EXIT IF ZERO
+ ;
+ ;**************************************************************
+ ;
+SWAP_AND_EXIT: ; Swap external args and return
+ ;
+ ;**************************************************************
+ ;
+ ACALL LOAD_POINTERS
+ MOV R7,#FP_NUMBER_SIZE
+ ;
+SE1: MOVX A,@R0 ;SWAP THE ARGUMENTS
+ MOVX @R1,A
+ DEC R0
+ DEC R1
+ DJNZ R7,SE1
+ ;
+POP_AND_EXIT:
+ ;
+ MOV A,ARG_STACK ;POP THE STACK
+ ADD A,#FP_NUMBER_SIZE
+ MOV ARG_STACK,A
+ CLR A
+ RET
+ ;
+ ;
+LOAD1: SUBB A,R6 ;A = ARG 1 EXP - ARG 2 EXP
+ MOV FP_EXP,R7 ;SAVE EXPONENT AND SIGN
+ MOV FP_SIGN,R4
+ JNC LOAD2 ;ARG1 EXPONENT IS LARGER OR SAME
+ MOV FP_EXP,R6
+ MOV FP_SIGN,R3
+ CPL A
+ INC A ;COMPENSATE FOR EXP DELTA
+ XCH A,R0 ;FORCE R0 TO POINT AT THE LARGEST
+ XCH A,R1 ;EXPONENT
+ XCH A,R0
+ ;
+LOAD2: MOV R7,A ;SAVE THE EXPONENT DELTA IN R7
+ CLR ADD_IN
+ CJNE R5,#0,$+5
+ SETB ADD_IN
+ ;
+ newpage
+ ; Load the R1 mantissa
+ ;
+ ACALL LOADR1_MANTISSA ;LOAD THE SMALLEST NUMBER
+ ;
+ ; Now align the number to the delta exponent
+ ; R4 points to the string of the last digits lost
+ ;
+ CJNE R7,#DIGIT+DIGIT+3,$+3
+ JC $+4
+ MOV R7,#DIGIT+DIGIT+2
+ ;
+ MOV FP_CARRY,#00 ;CLEAR THE CARRY
+ ACALL RIGHT ;SHIFT THE NUMBER
+ ;
+ ; Set up for addition and subtraction
+ ;
+ MOV R7,#DIGIT ;LOOP COUNT
+ MOV R1,#FP_DIG78
+ MOV A,#9EH
+ CLR C
+ SUBB A,R4
+ DA A
+ XCH A,R4
+ JNZ $+3
+ MOV R4,A
+ CJNE A,#50H,$+3 ;TEST FOR SUBTRACTION
+ JNB ADD_IN,SUBLP ;DO SUBTRACTION IF NO ADD_IN
+ CPL C ;FLIP CARRY FOR ADDITION
+ ACALL ADDLP ;DO ADDITION
+ ;
+ JNC ADD_R
+ INC FP_CARRY
+ MOV R7,#1
+ ACALL RIGHT
+ ACALL INC_FP_EXP ;SHIFT AND BUMP EXPONENT
+ ;
+ADD_R: AJMP STORE_ALIGN_TEST_AND_EXIT
+ ;
+ADDLP: MOVX A,@R0
+ ADDC A,@R1
+ DA A
+ MOV @R1,A
+ DEC R0
+ DEC R1
+ DJNZ R7,ADDLP ;LOOP UNTIL DONE
+ RET
+ ;
+ newpage
+ ;
+SUBLP: MOVX A,@R0 ;NOW DO SUBTRACTION
+ MOV R6,A
+ CLR A
+ ADDC A,#99H
+ SUBB A,@R1
+ ADD A,R6
+ DA A
+ MOV @R1,A
+ DEC R0
+ DEC R1
+ DJNZ R7,SUBLP
+ JC FSUB6
+ ;
+ newpage
+ ;
+ ; Need to complement the result and sign because the floating
+ ; point accumulator mantissa was larger than the external
+ ; memory and their signs were equal.
+ ;
+ CPL FP_SIGN.0
+ MOV R1,#FP_DIG78
+ MOV R7,#DIGIT ;LOOP COUNT
+ ;
+FSUB5: MOV A,#9AH
+ SUBB A,@R1
+ ADD A,#0
+ DA A
+ MOV @R1,A
+ DEC R1
+ CPL C
+ DJNZ R7,FSUB5 ;LOOP
+ ;
+ ; Now see how many zeros their are
+ ;
+FSUB6: MOV R0,#FP_DIG12
+ MOV R7,#0
+ ;
+FSUB7: MOV A,@R0
+ JNZ FSUB8
+ INC R7
+ INC R7
+ INC R0
+ CJNE R0,#FP_SIGN,FSUB7
+ AJMP ZERO_AND_EXIT
+ ;
+FSUB8: CJNE A,#10H,$+3
+ JNC FSUB9
+ INC R7
+ ;
+ ; Now R7 has the number of leading zeros in the FP ACC
+ ;
+FSUB9: MOV A,FP_EXP ;GET THE OLD EXPONENT
+ CLR C
+ SUBB A,R7 ;SUBTRACT FROM THE NUMBER OF ZEROS
+ JZ FSUB10
+ JC FSUB10
+ ;
+ MOV FP_EXP,A ;SAVE THE NEW EXPONENT
+ ;
+ ACALL LEFT1 ;SHIFT THE FP ACC
+ MOV FP_CARRY,#0
+ AJMP STORE_ALIGN_TEST_AND_EXIT
+ ;
+FSUB10: AJMP UNDERFLOW_AND_EXIT
+ ;
+ newpage
+ ;***************************************************************
+ ;
+FLOATING_COMP: ; Compare two floating point numbers
+ ; used for relational operations and is faster
+ ; than subtraction. ON RETURN, The carry is set
+ ; if ARG1 is > ARG2, else carry is not set
+ ; if ARG1 = ARG2, F0 gets set
+ ;
+ ;***************************************************************
+ ;
+ ACALL MDES1 ;SET UP THE REGISTERS
+ MOV A,ARG_STACK
+ ADD A,#FP_NUMBER_SIZE+FP_NUMBER_SIZE
+ MOV ARG_STACK,A ;POP THE STACK TWICE, CLEAR THE CARRY
+ MOV A,R6 ;CHECK OUT EXPONENTS
+ CLR F0
+ SUBB A,R7
+ JZ EXPONENTS_EQUAL
+ JC ARG1_EXP_IS_LARGER
+ ;
+ ; Now the ARG2 EXPONENT is > ARG1 EXPONENT
+ ;
+SIGNS_DIFFERENT:
+ ;
+ MOV A,R3 ;SEE IF SIGN OF ARG2 IS POSITIVE
+ SJMP $+3
+ ;
+ARG1_EXP_IS_LARGER:
+ ;
+ MOV A,R4 ;GET THE SIGN OF ARG1 EXPONENT
+ JZ $+3
+ CPL C
+ RET
+ ;
+EXPONENTS_EQUAL:
+ ;
+ ; First, test the sign, then the mantissa
+ ;
+ CJNE R5,#0,SIGNS_DIFFERENT
+ ;
+BOTH_PLUS:
+ ;
+ MOV R7,#DIGIT ;POINT AT MS DIGIT
+ DEC R0
+ DEC R0
+ DEC R0
+ DEC R1
+ DEC R1
+ DEC R1
+ ;
+ ; Now do the compare
+ ;
+CLOOP: MOVX A,@R0
+ MOV R6,A
+ MOVX A,@R1
+ SUBB A,R6
+ JNZ ARG1_EXP_IS_LARGER
+ INC R0
+ INC R1
+ DJNZ R7,CLOOP
+ ;
+ ; If here, the numbers are the same, the carry is cleared
+ ;
+ SETB F0
+ RET ;EXIT WITH EQUAL
+ ;
+ newpage
+;MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+;
+FLOATING_MUL: ; Floating point multiply
+;
+;MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+;
+ ACALL MUL_DIV_EXP_AND_SIGN
+ ;
+ ; check for zero exponents
+ ;
+ CJNE R6,#00,$+5 ;ARG 2 EXP ZERO?
+ AJMP ZERO_AND_EXIT
+ ;
+ ; calculate the exponent
+ ;
+FMUL1: MOV FP_SIGN,R5 ;SAVE THE SIGN, IN CASE OF FAILURE
+ ;
+ MOV A,R7
+ JZ FMUL1-2
+ ADD A,R6 ;ADD THE EXPONENTS
+ JB ACC.7,FMUL_OVER
+ JBC CY,FMUL2 ;SEE IF CARRY IS SET
+ ;
+ AJMP UNDERFLOW_AND_EXIT
+ ;
+FMUL_OVER:
+ ;
+ JNC FMUL2 ;OK IF SET
+ ;
+FOV: AJMP OVERFLOW_AND_EXIT
+ ;
+FMUL2: SUBB A,#129 ;SUBTRACT THE EXPONENT BIAS
+ MOV R6,A ;SAVE IT FOR LATER
+ ;
+ ; Unpack and load R0
+ ;
+ ACALL UNPACK_R0
+ ;
+ ; Now set up for loop multiply
+ ;
+ MOV R3,#DIGIT
+ MOV R4,R1B0
+ ;
+ newpage
+ ;
+ ; Now, do the multiply and accumulate the product
+ ;
+FMUL3: MOV R1B0,R4
+ MOVX A,@R1
+ MOV R2,A
+ ACALL MUL_NIBBLE
+ ;
+ MOV A,R2
+ SWAP A
+ ACALL MUL_NIBBLE
+ DEC R4
+ DJNZ R3,FMUL3
+ ;
+ ; Now, pack and restore the sign
+ ;
+ MOV FP_EXP,R6
+ MOV FP_SIGN,R5
+ AJMP PACK ;FINISH IT OFF
+ ;
+ newpage
+ ;DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
+ ;
+FLOATING_DIV:
+ ;
+ ;DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
+ ;
+ ACALL MDES1
+ ;
+ ; Check the exponents
+ ;
+ MOV FP_SIGN,R5 ;SAVE THE SIGN
+ CJNE R7,#0,DIV0 ;CLEARS THE CARRY
+ ACALL OVERFLOW_AND_EXIT
+ CLR A
+ SETB ACC_ZERO_DIVIDE
+ RET
+ ;
+DIV0: MOV A,R6 ;GET EXPONENT
+ JZ FMUL1-2 ;EXIT IF ZERO
+ SUBB A,R7 ;DELTA EXPONENT
+ JB ACC.7,D_UNDER
+ JNC DIV3
+ AJMP UNDERFLOW_AND_EXIT
+ ;
+D_UNDER:JNC FOV
+ ;
+DIV3: ADD A,#129 ;CORRECTLY BIAS THE EXPONENT
+ MOV FP_EXP,A ;SAVE THE EXPONENT
+ ACALL LOADR1_MANTISSA ;LOAD THE DIVIDED
+ ;
+ MOV R2,#FP_ACCC ;SAVE LOCATION
+ MOV R3,R0B0 ;SAVE POINTER IN R3
+ MOV FP_CARRY,#0 ;ZERO CARRY BYTE
+ ;
+DIV4: MOV R5,#0FFH ;LOOP COUNT
+ SETB C
+ ;
+DIV5: MOV R0B0,R3 ;RESTORE THE EXTERNAL POINTER
+ MOV R1,#FP_DIG78 ;SET UP INTERNAL POINTER
+ MOV R7,#DIGIT ;LOOP COUNT
+ JNC DIV7 ;EXIT IF NO CARRY
+ ;
+DIV6: MOVX A,@R0 ;DO ACCUMLATION
+ MOV R6,A
+ CLR A
+ ADDC A,#99H
+ SUBB A,R6
+ ADD A,@R1
+ DA A
+ MOV @R1,A
+ DEC R0
+ DEC R1
+ DJNZ R7,DIV6 ;LOOP
+ ;
+ INC R5 ;SUBTRACT COUNTER
+ JC DIV5 ;KEEP LOOPING IF CARRY
+ MOV A,@R1 ;GET CARRY
+ SUBB A,#1 ;CARRY IS CLEARED
+ MOV @R1,A ;SAVE CARRY DIGIT
+ CPL C
+ SJMP DIV5 ;LOOP
+ ;
+ ; Restore the result if carry was found
+ ;
+DIV7: ACALL ADDLP ;ADD NUMBER BACK
+ MOV @R1,#0 ;CLEAR CARRY
+ MOV R0B0,R2 ;GET SAVE COUNTER
+ MOV @R0,5 ;SAVE COUNT BYTE
+ ;
+ INC R2 ;ADJUST SAVE COUNTER
+ MOV R7,#1 ;BUMP DIVIDEND
+ ACALL LEFT
+ CJNE R2,#FP_ACC8+2,DIV4
+ ;
+ DJNZ FP_EXP,DIV8
+ AJMP UNDERFLOW_AND_EXIT
+ ;
+DIV8: MOV FP_CARRY,#0
+ ;
+ newpage
+ ;***************************************************************
+ ;
+PACK: ; Pack the mantissa
+ ;
+ ;***************************************************************
+ ;
+ ; First, set up the pointers
+ ;
+ MOV R0,#FP_ACCC
+ MOV A,@R0 ;GET FP_ACCC
+ MOV R6,A ;SAVE FOR ZERO COUNT
+ JZ PACK0 ;JUMP OVER IF ZERO
+ ACALL INC_FP_EXP ;BUMP THE EXPONENT
+ DEC R0
+ ;
+PACK0: INC R0 ;POINT AT FP_ACC1
+ ;
+PACK1: MOV A,#8 ;ADJUST NIBBLE POINTER
+ MOV R1,A
+ ADD A,R0
+ MOV R0,A
+ CJNE @R0,#5,$+3 ;SEE IF ADJUSTING NEEDED
+ JC PACK3+1
+ ;
+PACK2: SETB C
+ CLR A
+ DEC R0
+ ADDC A,@R0
+ DA A
+ XCHD A,@R0 ;SAVE THE VALUE
+ JNB ACC.4,PACK3
+ DJNZ R1,PACK2
+ ;
+ DEC R0
+ MOV @R0,#1
+ ACALL INC_FP_EXP
+ SJMP PACK4
+ ;
+PACK3: DEC R1
+ MOV A,R1
+ CLR C
+ XCH A,R0
+ SUBB A,R0
+ MOV R0,A
+ ;
+PACK4: MOV R1,#FP_DIG12
+ ;
+ ; Now, pack
+ ;
+PLOOP: MOV A,@R0
+ SWAP A ;FLIP THE DIGITS
+ INC R0
+ XCHD A,@R0
+ ORL 6,A ;ACCUMULATE THE OR'ED DIGITS
+ MOV @R1,A
+ INC R0
+ INC R1
+ CJNE R1,#FP_SIGN,PLOOP
+ MOV A,R6
+ JNZ STORE_ALIGN_TEST_AND_EXIT
+ MOV FP_EXP,#0 ;ZERO EXPONENT
+ ;
+ ;**************************************************************
+ ;
+STORE_ALIGN_TEST_AND_EXIT: ;Save the number align carry and exit
+ ;
+ ;**************************************************************
+ ;
+ ACALL LOAD_POINTERS
+ MOV ARG_STACK,R1 ;SET UP THE NEW STACK
+ MOV R0,#FP_EXP
+ ;
+ ; Now load the numbers
+ ;
+STORE2: MOV A,@R0
+ MOVX @R1,A ;SAVE THE NUMBER
+ DEC R0
+ DEC R1
+ CJNE R0,#FP_CARRY,STORE2
+ ;
+ CLR A ;NO ERRORS
+ ;
+PRET: RET ;EXIT
+ ;
+ newpage
+INC_FP_EXP:
+ ;
+ INC FP_EXP
+ MOV A,FP_EXP
+ JNZ PRET ;EXIT IF NOT ZERO
+ POP ACC ;WASTE THE CALLING STACK
+ POP ACC
+ AJMP OVERFLOW_AND_EXIT
+ ;
+;***********************************************************************
+;
+UNPACK_R0: ; Unpack BCD digits and load into nibble locations
+;
+;***********************************************************************
+ ;
+ PUSH R1B0
+ MOV R1,#FP_NIB8
+ ;
+ULOOP: MOVX A,@R0
+ ANL A,#0FH
+ MOV @R1,A ;SAVE THE NIBBLE
+ MOVX A,@R0
+ SWAP A
+ ANL A,#0FH
+ DEC R1
+ MOV @R1,A ;SAVE THE NIBBLE AGAIN
+ DEC R0
+ DEC R1
+ CJNE R1,#FP_NIB1-1,ULOOP
+ ;
+ POP R1B0
+ ;
+LOAD7: RET
+ ;
+ newpage
+ ;**************************************************************
+ ;
+OVERFLOW_AND_EXIT: ;LOAD 99999999 E+127, SET OV BIT, AND EXIT
+ ;
+ ;**************************************************************
+ ;
+ MOV R0,#FP_DIG78
+ MOV A,#99H
+ ;
+OVE1: MOV @R0,A
+ DEC R0
+ CJNE R0,#FP_CARRY,OVE1
+ ;
+ MOV FP_EXP,#0FFH
+ ACALL STORE_ALIGN_TEST_AND_EXIT
+ ;
+ SETB ACC_OVERFLOW ; ******AA
+ RET
+ ;
+ newpage
+ ;**************************************************************
+ ;
+UNDERFLOW_AND_EXIT: ;LOAD 0, SET UF BIT, AND EXIT
+ ;
+ ;**************************************************************
+ ;
+ ACALL ZERO_AND_EXIT
+ CLR A
+ SETB ACC_UNDERFLOW ; ******AA
+ RET
+ ;
+ ;**************************************************************
+ ;
+ZERO_AND_EXIT: ;LOAD 0, SET ZERO BIT, AND EXIT
+ ;
+ ;**************************************************************
+ ;
+ ACALL FP_CLEAR
+ ACALL STORE_ALIGN_TEST_AND_EXIT
+ SETB ACC_ZERO ; ******AA
+ RET ;EXIT
+ ;
+ ;**************************************************************
+ ;
+FP_CLEAR:
+ ;
+ ; Clear internal storage
+ ;
+ ;**************************************************************
+ ;
+ CLR A
+ MOV R0,#FP_ACC8+1
+ ;
+FPC1: MOV @R0,A
+ DEC R0
+ CJNE R0,#FP_TEMP,FPC1
+ RET
+ ;
+ newpage
+ ;**************************************************************
+ ;
+RIGHT: ; Shift ACCUMULATOR RIGHT the number of nibbles in R7
+ ; Save the shifted values in R4 if SAVE_ROUND is set
+ ;
+ ;**************************************************************
+ ;
+ MOV R4,#0 ;IN CASE OF NO SHIFT
+ ;
+RIGHT1: CLR C
+ MOV A,R7 ;GET THE DIGITS TO SHIFT
+ JZ RIGHT5-1 ;EXIT IF ZERO
+ SUBB A,#2 ;TWO TO DO?
+ JNC RIGHT5 ;SHIFT TWO NIBBLES
+ ;
+ ; Swap one nibble then exit
+ ;
+RIGHT3: PUSH R0B0 ;SAVE POINTER REGISTER
+ PUSH R1B0
+ ;
+ MOV R1,#FP_DIG78 ;LOAD THE POINTERS
+ MOV R0,#FP_DIG56
+ MOV A,R4 ;GET THE OVERFLOW REGISTER
+ XCHD A,@R1 ;GET DIGIT 8
+ SWAP A ;FLIP FOR LOAD
+ MOV R4,A
+ ;
+RIGHTL: MOV A,@R1 ;GET THE LOW ORDER BYTE
+ XCHD A,@R0 ;SWAP NIBBLES
+ SWAP A ;FLIP FOR STORE
+ MOV @R1,A ;SAVE THE DIGITS
+ DEC R0 ;BUMP THE POINTERS
+ DEC R1
+ CJNE R1,#FP_DIG12-1,RIGHTL ;LOOP
+ ;
+ MOV A,@R1 ;ACC = CH8
+ SWAP A ;ACC = 8CH
+ ANL A,#0FH ;ACC = 0CH
+ MOV @R1,A ;CARRY DONE
+ POP R1B0 ;EXIT
+ POP R0B0 ;RESTORE REGISTER
+ RET
+ ;
+RIGHT5: MOV R7,A ;SAVE THE NEW SHIFT NUMBER
+ CLR A
+ XCH A,FP_CARRY ;SWAP THE NIBBLES
+ XCH A,FP_DIG12
+ XCH A,FP_DIG34
+ XCH A,FP_DIG56
+ XCH A,FP_DIG78
+ MOV R4,A ;SAVE THE LAST DIGIT SHIFTED
+ SJMP RIGHT1+1
+ ;
+ newpage
+ ;***************************************************************
+ ;
+LEFT: ; Shift ACCUMULATOR LEFT the number of nibbles in R7
+ ;
+ ;***************************************************************
+ ;
+ MOV R4,#00H ;CLEAR FOR SOME ENTRYS
+ ;
+LEFT1: CLR C
+ MOV A,R7 ;GET SHIFT VALUE
+ JZ LEFT5-1 ;EXIT IF ZERO
+ SUBB A,#2 ;SEE HOW MANY BYTES TO SHIFT
+ JNC LEFT5
+ ;
+LEFT3: PUSH R0B0 ;SAVE POINTER
+ PUSH R1B0
+ MOV R0,#FP_CARRY
+ MOV R1,#FP_DIG12
+ ;
+ MOV A,@R0 ;ACC=CHCL
+ SWAP A ;ACC = CLCH
+ MOV @R0,A ;ACC = CLCH, @R0 = CLCH
+ ;
+LEFTL: MOV A,@R1 ;DIG 12
+ SWAP A ;DIG 21
+ XCHD A,@R0
+ MOV @R1,A ;SAVE IT
+ INC R0 ;BUMP POINTERS
+ INC R1
+ CJNE R0,#FP_DIG78,LEFTL
+ ;
+ MOV A,R4
+ SWAP A
+ XCHD A,@R0
+ ANL A,#0F0H
+ MOV R4,A
+ ;
+ POP R1B0
+ POP R0B0 ;RESTORE
+ RET ;DONE
+ ;
+LEFT5: MOV R7,A ;RESTORE COUNT
+ CLR A
+ XCH A,R4 ;GET THE RESTORATION BYTE
+ XCH A,FP_DIG78 ;DO THE SWAP
+ XCH A,FP_DIG56
+ XCH A,FP_DIG34
+ XCH A,FP_DIG12
+ XCH A,FP_CARRY
+ SJMP LEFT1+1
+ ;
+ newpage
+MUL_NIBBLE:
+ ;
+ ; Multiply the nibble in R7 by the FP_NIB locations
+ ; accumulate the product in FP_ACC
+ ;
+ ; Set up the pointers for multiplication
+ ;
+ ANL A,#0FH ;STRIP OFF MS NIBBLE
+ MOV R7,A
+ MOV R0,#FP_ACC8
+ MOV R1,#FP_NIB8
+ CLR A
+ MOV FP_ACCX,A
+ ;
+MNLOOP: DEC R0 ;BUMP POINTER TO PROPAGATE CARRY
+ ADD A,@R0 ;ATTEMPT TO FORCE CARRY
+ DA A ;BCD ADJUST
+ JNB ACC.4,MNL0 ;DON'T ADJUST IF NO NEED
+ DEC R0 ;PROPAGATE CARRY TO THE NEXT DIGIT
+ INC @R0 ;DO THE ADJUSTING
+ INC R0 ;RESTORE R0
+ ;
+MNL0: XCHD A,@R0 ;RESTORE INITIAL NUMBER
+ MOV B,R7 ;GET THE NUBBLE TO MULTIPLY
+ MOV A,@R1 ;GET THE OTHER NIBBLE
+ MUL AB ;DO THE MULTIPLY
+ MOV B,#10 ;NOW BCD ADJUST
+ DIV AB
+ XCH A,B ;GET THE REMAINDER
+ ADD A,@R0 ;PROPAGATE THE PARTIAL PRODUCTS
+ DA A ;BCD ADJUST
+ JNB ACC.4,MNL1 ;PROPAGATE PARTIAL PRODUCT CARRY
+ INC B
+ ;
+MNL1: INC R0
+ XCHD A,@R0 ;SAVE THE NEW PRODUCT
+ DEC R0
+ MOV A,B ;GET BACK THE QUOTIENT
+ DEC R1
+ CJNE R1,#FP_NIB1-1,MNLOOP
+ ;
+ ADD A,FP_ACCX ;GET THE OVERFLOW
+ DA A ;ADJUST
+ MOV @R0,A ;SAVE IT
+ RET ;EXIT
+ ;
+ newpage
+ ;***************************************************************
+ ;
+LOAD_POINTERS: ; Load the ARG_STACK into R0 and bump R1
+ ;
+ ;***************************************************************
+ ;
+ MOV P2,#ARG_STACK_PAGE
+ MOV R0,ARG_STACK
+ MOV A,#FP_NUMBER_SIZE
+ ADD A,R0
+ MOV R1,A
+ RET
+ ;
+ ;***************************************************************
+ ;
+MUL_DIV_EXP_AND_SIGN:
+ ;
+ ; Load the sign into R7, R6. R5 gets the sign for
+ ; multiply and divide.
+ ;
+ ;***************************************************************
+ ;
+ ACALL FP_CLEAR ;CLEAR INTERNAL MEMORY
+ ;
+MDES1: ACALL LOAD_POINTERS ;LOAD REGISTERS
+ MOVX A,@R0 ;ARG 1 EXP
+ MOV R7,A ;SAVED IN R7
+ MOVX A,@R1 ;ARG 2 EXP
+ MOV R6,A ;SAVED IN R6
+ DEC R0 ;BUMP POINTERS TO SIGN
+ DEC R1
+ MOVX A,@R0 ;GET THE SIGN
+ MOV R4,A ;SIGN OF ARG1
+ MOVX A,@R1 ;GET SIGN OF NEXT ARG
+ MOV R3,A ;SIGN OF ARG2
+ XRL A,R4 ;ACC GETS THE NEW SIGN
+ MOV R5,A ;R5 GETS THE NEW SIGN
+ ;
+ ; Bump the pointers to point at the LS digit
+ ;
+ DEC R0
+ DEC R1
+ ;
+ RET
+ ;
+ newpage
+ ;***************************************************************
+ ;
+LOADR1_MANTISSA:
+ ;
+ ; Load the mantissa of R0 into FP_Digits
+ ;
+ ;***************************************************************
+ ;
+ PUSH R0B0 ;SAVE REGISTER 1
+ MOV R0,#FP_DIG78 ;SET UP THE POINTER
+ ;
+LOADR1: MOVX A,@R1
+ MOV @R0,A
+ DEC R1
+ DEC R0
+ CJNE R0,#FP_CARRY,LOADR1
+ ;
+ POP R0B0
+ RET
+ ;
+ newpage
+ ;***************************************************************
+ ;
+HEXSCAN: ; Scan a string to determine if it is a hex number
+ ; set carry if hex, else carry = 0
+ ;
+ ;***************************************************************
+ ;
+ ACALL GET_DPTR_CHARACTER
+ PUSH DPH
+ PUSH DPL ;SAVE THE POINTER
+ ;
+HEXSC1: MOVX A,@DPTR ;GET THE CHARACTER
+ ACALL DIGIT_CHECK ;SEE IF A DIGIT
+ JC HS1 ;CONTINUE IF A DIGIT
+ ACALL HEX_CHECK ;SEE IF HEX
+ JC HS1
+ ;
+ CLR ACC.5 ;NO LOWER CASE
+ CJNE A,#'H',HEXDON
+ SETB C
+ SJMP HEXDO1 ;NUMBER IS VALID HEX, MAYBE
+ ;
+HEXDON: CLR C
+ ;
+HEXDO1: POP DPL ;RESTORE POINTER
+ POP DPH
+ RET
+ ;
+HS1: INC DPTR ;BUMP TO NEXT CHARACTER
+ SJMP HEXSC1 ;LOOP
+ ;
+HEX_CHECK: ;CHECK FOR A VALID ASCII HEX, SET CARRY IF FOUND
+ ;
+ CLR ACC.5 ;WASTE LOWER CASE
+ CJNE A,#'F'+1,$+3 ;SEE IF F OR LESS
+ JC HC1
+ RET
+ ;
+HC1: CJNE A,#'A',$+3 ;SEE IF A OR GREATER
+ CPL C
+ RET
+ ;
+ newpage
+ ;
+PUSHR2R0:
+ ;
+ MOV R3,#HI(CONVT) ;CONVERSION LOCATION
+ MOV R1,#LO(CONVT)
+ ACALL CONVERT_BINARY_TO_ASCII_STRING
+ MOV A,#0DH ;A CR TO TERMINATE
+ MOVX @R1,A ;SAVE THE CR
+ MOV DPTR,#CONVT
+ ;
+ ; Falls thru to FLOATING INPUT
+ ;
+ newpage
+ ;***************************************************************
+ ;
+FLOATING_POINT_INPUT: ; Input a floating point number pointed to by
+ ; the DPTR
+ ;
+ ;***************************************************************
+ ;
+ ACALL FP_CLEAR ;CLEAR EVERYTHING
+ ACALL GET_DPTR_CHARACTER
+ ACALL PLUS_MINUS_TEST
+ MOV MSIGN,C ;SAVE THE MANTISSA SIGN
+ ;
+ ; Now, set up for input loop
+ ;
+ MOV R0,#FP_ACCC
+ MOV R6,#7FH ;BASE EXPONENT
+ SETB F0 ;SET INITIAL FLAG
+ ;
+INLOOP: ACALL GET_DIGIT_CHECK
+ JNC GTEST ;IF NOT A CHARACTER, WHAT IS IT?
+ ANL A,#0FH ;STRIP ASCII
+ ACALL STDIG ;STORE THE DIGITS
+ ;
+INLPIK: INC DPTR ;BUMP POINTER FOR LOOP
+ SJMP INLOOP ;LOOP FOR INPUT
+ ;
+GTEST: CJNE A,#'.',GT1 ;SEE IF A RADIX
+ JB FOUND_RADIX,INERR
+ SETB FOUND_RADIX
+ CJNE R0,#FP_ACCC,INLPIK
+ SETB FIRST_RADIX ;SET IF FIRST RADIX
+ SJMP INLPIK ;GET ADDITIONAL DIGITS
+ ;
+GT1: JB F0,INERR ;ERROR IF NOT CLEARED
+ CJNE A,#'e',$+5 ;CHECK FOR LOWER CASE
+ SJMP $+5
+ CJNE A,#'E',FINISH_UP
+ ACALL INC_AND_GET_DPTR_CHARACTER
+ ACALL PLUS_MINUS_TEST
+ MOV XSIGN,C ;SAVE SIGN STATUS
+ ACALL GET_DIGIT_CHECK
+ JNC INERR
+ ;
+ ANL A,#0FH ;STRIP ASCII BIAS OFF THE CHARACTER
+ MOV R5,A ;SAVE THE CHARACTER IN R5
+ ;
+GT2: INC DPTR
+ ACALL GET_DIGIT_CHECK
+ JNC FINISH1
+ ANL A,#0FH ;STRIP OFF BIAS
+ XCH A,R5 ;GET THE LAST DIGIT
+ MOV B,#10 ;MULTIPLY BY TEN
+ MUL AB
+ ADD A,R5 ;ADD TO ORIGINAL VALUE
+ MOV R5,A ;SAVE IN R5
+ JNC GT2 ;LOOP IF NO CARRY
+ MOV R5,#0FFH ;FORCE AN ERROR
+ ;
+FINISH1:MOV A,R5 ;GET THE SIGN
+ JNB XSIGN,POSNUM ;SEE IF EXPONENT IS POS OR NEG
+ CLR C
+ SUBB A,R6
+ CPL A
+ INC A
+ JC FINISH2
+ MOV A,#01H
+ RET
+ ;
+POSNUM: ADD A,R6 ;ADD TO EXPONENT
+ JNC FINISH2
+ ;
+POSNM1: MOV A,#02H
+ RET
+ ;
+FINISH2:XCH A,R6 ;SAVE THE EXPONENT
+ ;
+FINISH_UP:
+ ;
+ MOV FP_EXP,R6 ;SAVE EXPONENT
+ CJNE R0,#FP_ACCC,$+5
+ ACALL FP_CLEAR ;CLEAR THE MEMORY IF 0
+ MOV A,ARG_STACK ;GET THE ARG STACK
+ CLR C
+ SUBB A,#FP_NUMBER_SIZE+FP_NUMBER_SIZE
+ MOV ARG_STACK,A ;ADJUST FOR STORE
+ AJMP PACK
+ ;
+STDIG: CLR F0 ;CLEAR INITIAL DESIGNATOR
+ JNZ STDIG1 ;CONTINUE IF NOT ZERO
+ CJNE R0,#FP_ACCC,STDIG1
+ JNB FIRST_RADIX,RET_X
+ ;
+DECX: DJNZ R6,RET_X
+ ;
+INERR: MOV A,#0FFH
+ ;
+RET_X: RET
+ ;
+STDIG1: JB DONE_LOAD,FRTEST
+ CLR FIRST_RADIX
+ ;
+FRTEST: JB FIRST_RADIX,DECX
+ ;
+FDTEST: JB FOUND_RADIX,FDT1
+ INC R6
+ ;
+FDT1: JB DONE_LOAD,RET_X
+ CJNE R0,#FP_ACC8+1,FDT2
+ SETB DONE_LOAD
+ ;
+FDT2: MOV @R0,A ;SAVE THE STRIPPED ACCUMULATOR
+ INC R0 ;BUMP THE POINTER
+ RET ;EXIT
+ ;
+ newpage
+ ;***************************************************************
+ ;
+ ; I/O utilities
+ ;
+ ;***************************************************************
+ ;
+INC_AND_GET_DPTR_CHARACTER:
+ ;
+ INC DPTR
+ ;
+GET_DPTR_CHARACTER:
+ ;
+ MOVX A,@DPTR ;GET THE CHARACTER
+ CJNE A,#' ',PMT1 ;SEE IF A SPACE
+ ;
+ ; Kill spaces
+ ;
+ SJMP INC_AND_GET_DPTR_CHARACTER
+ ;
+PLUS_MINUS_TEST:
+ ;
+ CJNE A,#0E3H,$+5 ;SEE IF A PLUS, PLUS TOKEN FROM BASIC
+ SJMP PMT3
+ CJNE A,#'+',$+5
+ SJMP PMT3
+ CJNE A,#0E5H,$+5 ;SEE IF MINUS, MINUS TOKEN FROM BASIC
+ SJMP PMT2
+ CJNE A,#'-',PMT1
+ ;
+PMT2: SETB C
+ ;
+PMT3: INC DPTR
+ ;
+PMT1: RET
+ ;
+ newpage
+ ;***************************************************************
+ ;
+FLOATING_POINT_OUTPUT: ; Output the number, format is in location 23
+ ;
+ ; IF FORMAT = 00 - FREE FLOATING
+ ; = FX - EXPONENTIAL (X IS THE NUMBER OF SIG DIGITS)
+ ; = NX - N = NUM BEFORE RADIX, X = NUM AFTER RADIX
+ ; N + X = 8 MAX
+ ;
+ ;***************************************************************
+ ;
+ ACALL MDES1 ;GET THE NUMBER TO OUTPUT, R0 IS POINTER
+ ACALL POP_AND_EXIT ;OUTPUT POPS THE STACK
+ MOV A,R7
+ MOV R6,A ;PUT THE EXPONENT IN R6
+ ACALL UNPACK_R0 ;UNPACK THE NUMBER
+ MOV R0,#FP_NIB1 ;POINT AT THE NUMBER
+ MOV A,FORMAT ;GET THE FORMAT
+ MOV R3,A ;SAVE IN CASE OF EXP FORMAT
+ JZ FREE ;FREE FLOATING?
+ CJNE A,#0F0H,$+3 ;SEE IF EXPONENTIAL
+ JNC EXPOUT
+ ;
+ ; If here, must be integer USING format
+ ;
+ MOV A,R6 ;GET THE EXPONENT
+ JNZ $+4
+ MOV R6,#80H
+ MOV A,R3 ;GET THE FORMAT
+ SWAP A ;SPLIT INTEGER AND FRACTION
+ ANL A,#0FH
+ MOV R2,A ;SAVE INTEGER
+ ACALL NUM_LT ;GET THE NUMBER OF INTEGERS
+ XCH A,R2 ;FLIP FOR SUBB
+ CLR C
+ SUBB A,R2
+ MOV R7,A
+ JNC $+8
+ MOV R5,#'?' ;OUTPUT A QUESTION MARK
+ ACALL SOUT1 ;NUMBER IS TOO LARGE FOR FORMAT
+ AJMP FREE
+ CJNE R2,#00,USING0 ;SEE IF ZERO
+ DEC R7
+ ACALL SS7
+ ACALL ZOUT ;OUTPUT A ZERO
+ SJMP USING1
+ ;
+USING0: ACALL SS7 ;OUTPUT SPACES, IF NEED TO
+ MOV A,R2 ;OUTPUT DIGITS
+ MOV R7,A
+ ACALL OUTR0
+ ;
+USING1: MOV A,R3
+ ANL A,#0FH ;GET THE NUMBER RIGHT OF DP
+ MOV R2,A ;SAVE IT
+ JZ PMT1 ;EXIT IF ZERO
+ ACALL ROUT ;OUTPUT DP
+ ACALL NUM_RT
+ CJNE A,2,USINGX ;COMPARE A TO R2
+ ;
+USINGY: MOV A,R2
+ AJMP Z7R7
+ ;
+USINGX: JNC USINGY
+ ;
+USING2: XCH A,R2
+ CLR C
+ SUBB A,R2
+ XCH A,R2
+ ACALL Z7R7 ;OUTPUT ZEROS IF NEED TO
+ MOV A,R2
+ MOV R7,A
+ AJMP OUTR0
+ ;
+ ; First, force exponential output, if need to
+ ;
+FREE: MOV A,R6 ;GET THE EXPONENT
+ JNZ FREE1 ;IF ZERO, PRINT IT
+ ACALL SOUT
+ AJMP ZOUT
+ ;
+FREE1: MOV R3,#0F0H ;IN CASE EXP NEEDED
+ MOV A,#80H-DIGIT-DIGIT-1
+ ADD A,R6
+ JC EXPOUT
+ SUBB A,#0F7H
+ JC EXPOUT
+ ;
+ ; Now, just print the number
+ ;
+ ACALL SINOUT ;PRINT THE SIGN OF THE NUMBER
+ ACALL NUM_LT ;GET THE NUMBER LEFT OF DP
+ CJNE A,#8,FREE4
+ AJMP OUTR0
+ ;
+FREE4: ACALL OUTR0
+ ACALL ZTEST ;TEST FOR TRAILING ZEROS
+ JZ U_RET ;DONE IF ALL TRAILING ZEROS
+ ACALL ROUT ;OUTPUT RADIX
+ ;
+FREE2: MOV R7,#1 ;OUTPUT ONE DIGIT
+ ACALL OUTR0
+ JNZ U_RET
+ ACALL ZTEST
+ JZ U_RET
+ SJMP FREE2 ;LOOP
+ ;
+EXPOUT: ACALL SINOUT ;PRINT THE SIGN
+ MOV R7,#1 ;OUTPUT ONE CHARACTER
+ ACALL OUTR0
+ ACALL ROUT ;OUTPUT RADIX
+ MOV A,R3 ;GET FORMAT
+ ANL A,#0FH ;STRIP INDICATOR
+ JZ EXPOTX
+ ;
+ MOV R7,A ;OUTPUT THE NUMBER OF DIGITS
+ DEC R7 ;ADJUST BECAUSE ONE CHAR ALREADY OUT
+ ACALL OUTR0
+ SJMP EXPOT4
+ ;
+EXPOTX: ACALL FREE2 ;OUTPUT UNTIL TRAILING ZEROS
+ ;
+EXPOT4: ACALL SOUT ;OUTPUT A SPACE
+ MOV R5,#'E'
+ ACALL SOUT1 ;OUTPUT AN E
+ MOV A,R6 ;GET THE EXPONENT
+ JZ XOUT0 ;EXIT IF ZERO
+ DEC A ;ADJUST FOR THE DIGIT ALREADY OUTPUT
+ CJNE A,#80H,XOUT2 ;SEE WHAT IT IS
+ ;
+XOUT0: ACALL SOUT
+ CLR A
+ SJMP XOUT4
+ ;
+XOUT2: JC XOUT3 ;NEGATIVE EXPONENT
+ MOV R5,#'+' ;OUTPUT A PLUS SIGN
+ ACALL SOUT1
+ SJMP XOUT4
+ ;
+XOUT3: ACALL MOUT
+ CPL A ;FLIP BITS
+ INC A ;BUMP
+ ;
+XOUT4: CLR ACC.7
+ MOV R0,A
+ MOV R2,#0
+ MOV R1,#LO(CONVT) ;CONVERSION LOCATION
+ MOV R3,#HI(CONVT)
+ ACALL CONVERT_BINARY_TO_ASCII_STRING
+ MOV R0,#LO(CONVT) ;NOW, OUTPUT EXPONENT
+ ;
+EXPOT5: MOVX A,@R0 ;GET THE CHARACTER
+ MOV R5,A ;OUTPUT IT
+ ACALL SOUT1
+ INC R0 ;BUMP THE POINTER
+ MOV A,R0 ;GET THE POINTER
+ CJNE A,R1B0,EXPOT5 ;LOOP
+ ;
+U_RET: RET ;EXIT
+ ;
+OUTR0: ; Output the characters pointed to by R0, also bias ascii
+ ;
+ MOV A,R7 ;GET THE COUNTER
+ JZ OUTR ;EXIT IF DONE
+ MOV A,@R0 ;GET THE NUMBER
+ ORL A,#30H ;ASCII BIAS
+ INC R0 ;BUMP POINTER AND COUNTER
+ DEC R7
+ MOV R5,A ;PUT CHARACTER IN OUTPUT REGISTER
+ ACALL SOUT1 ;OUTPUT THE CHARACTER
+ CLR A ;JUST FOR TEST
+ CJNE R0,#FP_NIB8+1,OUTR0
+ MOV A,#55H ;KNOW WHERE EXIT OCCURED
+ ;
+OUTR: RET
+ ;
+ZTEST: MOV R1,R0B0 ;GET POINTER REGISTER
+ ;
+ZT0: MOV A,@R1 ;GET THE VALUE
+ JNZ ZT1
+ INC R1 ;BUMP POINTER
+ CJNE R1,#FP_NIB8+1,ZT0
+ ;
+ZT1: RET
+ ;
+NUM_LT: MOV A,R6 ;GET EXPONENT
+ CLR C ;GET READY FOR SUBB
+ SUBB A,#80H ;SUB EXPONENT BIAS
+ JNC NL1 ;OK IF NO CARRY
+ CLR A ;NO DIGITS LEFT
+ ;
+NL1: MOV R7,A ;SAVE THE COUNT
+ RET
+ ;
+NUM_RT: CLR C ;SUBB AGAIN
+ MOV A,#80H ;EXPONENT BIAS
+ SUBB A,R6 ;GET THE BIASED EXPONENT
+ JNC NR1
+ CLR A
+ ;
+NR1: RET ;EXIT
+ ;
+SPACE7: MOV A,R7 ;GET THE NUMBER OF SPACES
+ JZ NR1 ;EXIT IF ZERO
+ ACALL SOUT ;OUTPUT A SPACE
+ DEC R7 ;BUMP COUNTER
+ SJMP SPACE7 ;LOOP
+ ;
+Z7R7: MOV R7,A
+ ;
+ZERO7: MOV A,R7 ;GET COUNTER
+ JZ NR1 ;EXIT IF ZERO
+ ACALL ZOUT ;OUTPUT A ZERO
+ DEC R7 ;BUMP COUNTER
+ SJMP ZERO7 ;LOOP
+ ;
+SS7: ACALL SPACE7
+ ;
+SINOUT: MOV A,R4 ;GET THE SIGN
+ JZ SOUT ;OUTPUT A SPACE IF ZERO
+ ;
+MOUT: MOV R5,#'-'
+ SJMP SOUT1 ;OUTPUT A MINUS IF NOT
+ ;
+ROUT: MOV R5,#'.' ;OUTPUT A RADIX
+ SJMP SOUT1
+ ;
+ZOUT: MOV R5,#'0' ;OUTPUT A ZERO
+ SJMP SOUT1
+ ;
+SOUT: MOV R5,#' ' ;OUTPUT A SPACE
+ ;
+SOUT1: AJMP OUTPUT
+ ;
+ newpage
+ ;***************************************************************
+ ;
+CONVERT_ASCII_STRING_TO_BINARY:
+ ;
+ ;DPTR POINTS TO ASCII STRING
+ ;PUT THE BINARY NUMBER IN R2:R0, ERROR IF >64K
+ ;
+ ;***************************************************************
+ ;
+CASB: ACALL HEXSCAN ;SEE IF HEX NUMBER
+ MOV ADD_IN,C ;IF ADD_IN IS SET, THE NUMBER IS HEX
+ ACALL GET_DIGIT_CHECK
+ CPL C ;FLIP FOR EXIT
+ JC RCASB
+ MOV R3,#00H ;ZERO R3:R1 FOR LOOP
+ MOV R1,#00H
+ SJMP CASB5
+ ;
+CASB2: INC DPTR
+ MOV R0B0,R1 ;SAVE THE PRESENT CONVERTED VALUE
+ MOV R0B0+2,R3 ;IN R2:R0
+ ACALL GET_DIGIT_CHECK
+ JC CASB5
+ JNB ADD_IN,RCASB ;CONVERSION COMPLETE
+ ACALL HEX_CHECK ;SEE IF HEX NUMBER
+ JC CASB4 ;PROCEED IF GOOD
+ INC DPTR ;BUMP PAST H
+ SJMP RCASB
+ ;
+CASB4: ADD A,#9 ;ADJUST HEX ASCII BIAS
+ ;
+CASB5: MOV B,#10
+ JNB ADD_IN,CASB6
+ MOV B,#16 ;HEX MODE
+ ;
+CASB6: ACALL MULNUM ;ACCUMULATE THE DIGITS
+ JNC CASB2 ;LOOP IF NO CARRY
+ ;
+RCASB: CLR A ;RESET ACC
+ MOV ACC_OVERFLOW,C ;IF OVERFLOW, SAY SO ******AA
+ RET ;EXIT
+ ;
+ newpage
+ ;
+MULNUM10:MOV B,#10
+ ;
+ ;***************************************************************
+ ;
+MULNUM: ; Take the next digit in the acc (masked to 0FH)
+ ; accumulate in R3:R1
+ ;
+ ;***************************************************************
+ ;
+ PUSH ACC ;SAVE ACC
+ PUSH B ;SAVE MULTIPLIER
+ MOV A,R1 ;PUT LOW ORDER BITS IN ACC
+ MUL AB ;DO THE MULTIPLY
+ MOV R1,A ;PUT THE RESULT BACK
+ MOV A,R3 ;GET THE HIGH ORDER BYTE
+ MOV R3,B ;SAVE THE OVERFLOW
+ POP B ;GET THE MULTIPLIER
+ MUL AB ;DO IT
+ MOV C,OV ;SAVE OVERFLOW IN F0
+ MOV F0,C
+ ADD A,R3 ;ADD OVERFLOW TO HIGH RESULT
+ MOV R3,A ;PUT IT BACK
+ POP ACC ;GET THE ORIGINAL ACC BACK
+ ORL C,F0 ;OR CARRY AND OVERFLOW
+ JC MULX ;NO GOOD IF THE CARRY IS SET
+ ;
+MUL11: ANL A,#0FH ;MASK OFF HIGH ORDER BITS
+ ADD A,R1 ;NOW ADD THE ACC
+ MOV R1,A ;PUT IT BACK
+ CLR A ;PROPAGATE THE CARRY
+ ADDC A,R3
+ MOV R3,A ;PUT IT BACK
+ ;
+MULX: RET ;EXIT WITH OR WITHOUT CARRY
+ ;
+ ;***************************************************************
+ ;
+CONVERT_BINARY_TO_ASCII_STRING:
+ ;
+ ;R3:R1 contains the address of the string
+ ;R2:R0 contains the value to convert
+ ;DPTR, R7, R6, and ACC gets clobbered
+ ;
+ ;***************************************************************
+ ;
+ CLR A ;NO LEADING ZEROS
+ MOV DPTR,#10000 ;SUBTRACT 10000
+ ACALL RSUB ;DO THE SUBTRACTION
+ MOV DPTR,#1000 ;NOW 1000
+ ACALL RSUB
+ MOV DPTR,#100 ;NOW 100
+ ACALL RSUB
+ MOV DPTR,#10 ;NOW 10
+ ACALL RSUB
+ MOV DPTR,#1 ;NOW 1
+ ACALL RSUB
+ JZ RSUB2 ;JUMP OVER RET
+ ;
+RSUB_R: RET
+ ;
+RSUB: MOV R6,#-1 ;SET UP THE COUNTER
+ ;
+RSUB1: INC R6 ;BUMP THE COUNTER
+ XCH A,R2 ;DO A FAST COMPARE
+ CJNE A,DPH,$+3
+ XCH A,R2
+ JC FAST_DONE
+ XCH A,R0 ;GET LOW BYTE
+ SUBB A,DPL ;SUBTRACT, CARRY IS CLEARED
+ XCH A,R0 ;PUT IT BACK
+ XCH A,R2 ;GET THE HIGH BYTE
+ SUBB A,DPH ;ADD THE HIGH BYTE
+ XCH A,R2 ;PUT IT BACK
+ JNC RSUB1 ;LOOP UNTIL CARRY
+ ;
+ XCH A,R0
+ ADD A,DPL ;RESTORE R2:R0
+ XCH A,R0
+ XCH A,R2
+ ADDC A,DPH
+ XCH A,R2
+ ;
+FAST_DONE:
+ ;
+ ORL A,R6 ;OR THE COUNT VALUE
+ JZ RSUB_R ;RETURN IF ZERO
+ ;
+RSUB2: MOV A,#'0' ;GET THE ASCII BIAS
+ ADD A,R6 ;ADD THE COUNT
+ ;
+RSUB4: MOV P2,R3 ;SET UP P2
+ MOVX @R1,A ;PLACE THE VALUE IN MEMORY
+ INC R1
+ CJNE R1,#00H,RSUB3 ;SEE IF RAPPED AROUND
+ INC R3 ;BUMP HIGH BYTE
+ ;
+RSUB3: RET ;EXIT
+ ;
+ newpage
+ ;***************************************************************
+ ;
+HEXOUT: ; Output the hex number in R3:R1, supress leading zeros, if set
+ ;
+ ;***************************************************************
+ ;
+ ACALL SOUT ;OUTPUT A SPACE
+ MOV C,ZSURP ;GET ZERO SUPPRESSION BIT
+ MOV ADD_IN,C
+ MOV A,R3 ;GET HIGH NIBBLE AND PRINT IT
+ ACALL HOUTHI
+ MOV A,R3
+ ACALL HOUTLO
+ ;
+HEX2X: CLR ADD_IN ;DON'T SUPPRESS ZEROS
+ MOV A,R1 ;GET LOW NIBBLE AND PRINT IT
+ ACALL HOUTHI
+ MOV A,R1
+ ACALL HOUTLO
+ MOV R5,#'H' ;OUTPUT H TO INDICATE HEX MODE
+ ;
+SOUT_1: AJMP SOUT1
+ ;
+HOUT1: CLR ADD_IN ;PRINTED SOMETHING, SO CLEAR ADD_IN
+ ADD A,#90H ;CONVERT TO ASCII
+ DA A
+ ADDC A,#40H
+ DA A ;GOT IT HERE
+ MOV R5,A ;OUTPUT THE BYTE
+ SJMP SOUT_1
+ ;
+HOUTHI: SWAP A ;SWAP TO OUTPUT HIGH NIBBLE
+ ;
+HOUTLO: ANL A,#0FH ;STRIP
+ JNZ HOUT1 ;PRINT IF NOT ZERO
+ JNB ADD_IN,HOUT1 ;OUTPUT A ZERO IF NOT SUPRESSED
+ RET
+ ;
+ newpage
+ ORG 1FEBH ;FOR LINK COMPATABILITY
+ ;
+ ;
+GET_DIGIT_CHECK: ; Get a character, then check for digit
+ ;
+ ACALL GET_DPTR_CHARACTER
+ ;
+DIGIT_CHECK: ;CHECK FOR A VALID ASCII DIGIT, SET CARRY IF FOUND
+ ;
+ CJNE A,#'9'+1,$+3 ;SEE IF ASCII 9 OR LESS
+ JC DC1
+ RET
+ ;
+DC1: CJNE A,#'0',$+3 ;SEE IF ASCII 0 OR GREATER
+ CPL C
+ RET
+
+ endsection