From 333b605b2afd472b823aeda0adf0e8b1ea9843c0 Mon Sep 17 00:00:00 2001 From: fishsoupisgood Date: Mon, 27 May 2019 02:41:51 +0100 Subject: initial commit from asl-1.41r8.tar.gz --- tests/t_bas52/bas52.fp | 1616 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1616 insertions(+) create mode 100644 tests/t_bas52/bas52.fp (limited to 'tests/t_bas52/bas52.fp') 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 -- cgit v1.2.3