; ; CONVERSI.ASM ver 1.2 ; Base conversion program ; ;From Heathkit course on assembly language ; ;Converts between ASCII, Binary, Decimal, ;Hexadecimal, Octal, and Split Octal. ; VERN EQU 1 REVN EQU 2 ; ; v1.2 Added upper case conversion to input. Added ; version display in message. Since ends input ; the Ascii conversion won't show a 'return' key and ; I can't figure a good way around it. ; 09/26/84 Dick Mead WB6NGC ; ; v1.1 Entered by Ben Miller WB8LGH ; on 02/20/80, with routines for CP/M ; I/O. Added prompt for input info. ; Added lower case print on ASCII output. ; CR EQU 0DH ;CARRIAGE RETURN LF EQU 0AH ;LINE FEED BDOS EQU 0005H ;CP/M ENTRY POINT ; ORG 100H ;ORIGIN OF OBJECT CODE ; BEGIN LXI SP,STACK;DEFINE TOP OF STACK LXI H,MESS6 ;SET H-L TO MESSAGE #6 CALL PRINT ;GO PRINT MESSAGE ; BEGIN1 LXI H,MESS1 ;SET H-L TO MESSAGE #1 CALL PRINT ;GO PRINT MESSAGE LXI D,0000H ;LOAD D-E REGISTERS WITH 0 CALL INPUT ;GET BASE OF ENTRY CPI 'a' ;..lower to JC BEG2 ;..upper case CPI 'z'+1 ;..conversion JNC BEG2 ;..for XRI 20H ;..commands BEG2: CPI 'D' ;IS IT DECIMAL? JZ DECIN ;IF DECIMAL GO DECIN CPI 'H' ;IS IT HEXADECIMAL? JZ HEXIN ;IF HEXADECIMAL GO HEXIN CPI 'O' ;IS IT OCTAL? JZ OCTIN ;IF OCTAL GO OCTIN CPI 'S' ;IS IT SPLIT OCTAL JZ SOCTN ;IF SPLIT OCTAL GO SOCTN CPI 'B' ;IS IT BINARY JZ BININ ;IF BINARY GO BININ CPI 'A' ;IS IT ASCII? JZ ASCIN ;IF ASCII GO ASCIN CPI 'X' ;ARE YOU DONE? JZ 0000H ;DO A WARM BOOT LXI H,MESS2 ;NONE OF THE ABOVE? -MUST BE AN ERROR CALL PRINT ;GO PRINT ERROR MESSAGE JMP BEGIN ;START AGAIN TURKEY INPUT IN ERROR ; PRINT MOV A,M ;GET MESSAGE CHARACTER ORA A ;CHECK FOR DELIMITER RZ ;RETURN IF DONE CALL OUTPT ;DISPLAY CHARACTER INX H ;SET H-L TO NEXT CHARACTER JMP PRINT ;DO ANOTHER CHARACTER ; INPUT PUSH B ;SAVE REGISTERS PUSH D PUSH H MVI C,1 ;READ CONSOLE KBD CALL BDOS ;CALL CP/M ENTRY POP H ;RESTORE REGISTERS POP D POP B RET ;RETURN TO MAIN PROGRAM ; OUTPT PUSH PSW ;SAVE REGISTERS PUSH B PUSH D PUSH H MOV E,A ;GET CHARACTER FOR CP/M MVI C,2 ;WRITE CHARACTER TO CRT CALL BDOS ;CALL CP/M ENTRY POP H ;RESTORE REGISTERS POP D POP B POP PSW RET ;RETURN TO MAIN PROGRAM ; DECIN LXI H,DECIMAL;POINT TO ASCII FOR DECIMAL CALL VALIN ;SHOW QUESTIONS WITH PROPER BASE ; NEXT1 CALL GETIN ;GET CHARACTER AND ECHO JZ CNVRT ;GO CONVERT TO ALL BASES IF SO SUI 30H ;SUBTRACT 30 HEX FROM ASCII JC ERROR ;NO GOOD IF CARRY CPI 10 ;HIGHER THAN "9"? JNC ERROR ;NO GOOD IF SO LXI H,0000H ;CLEAR H-L FOR MULTIPLICATION DAD D ;H-L=D-E TIMES ONE DAD H ;H-L=D-E TIMES TWO DAD H ;H-L=D-E TIMES FOUR DAD D ;H-L=D-E TIMES FIVE DAD H ;H-L=D-E TIMES TEN MOV E,A ;NEW KEY VALUE TO E MVI D,00H ;CLEAR D DAD D ;ADD UNIT VALUE TO D-E XCHG ;NEW TOTAL TO D-E JMP NEXT1 ;LOOP FOR NEXT CHARACTER ; OCTIN LXI H,OCTAL ;POINT TO ASCII FOR OCTAL CALL VALIN ;SHOWS QUESTION WITH PROPER BASE ; NEXT2 CALL GETIN ;GET CHARACTER AND ECHO IT JZ CNVRT ;GO CONVERT TO ALL BASES IF SO SUI 30H ;SUBTRACT 30 HEX FROM ASCII JC ERROR ;NO GOOD IF CARRY CPI 8 ;HIGHER THAN "7"? JNC ERROR ;NO GOOD IF SO LXI H,0000H ;CLEAR H-L FOR MULTIPLICATION DAD D ;H-L=D-E TIMES ONE DAD H ;H-L=D-E TIMES TWO DAD H ;H-L=D-E TIMES FOUR DAD H ;H-L=D-E TIMES EIGHT MOV E,A ;NEW KEY VALUE TO E MVI D,00H ;CLEAR D DAD D ;ADD UNIT VALUE TO TOTAL XCHG ;NEW TOTAL TO D-E JMP NEXT2 ;LOOP FOR NEXT DIGIT ; HEXIN LXI H,HEXAD ;POINT TO ASCII FOR HEXADECIMAL CALL VALIN ;SHOWS QUESTION WITH PROPER BASE ; NEXT3 CALL GETIN ;GET CHARACTER AND ECHO IT JZ CNVRT ;GO CONVERT TO ALL BASES IF DONE CPI 'a' ;force JC HEX4 ;..lower CPI 'z'+1 ;...to JNC HEX4 ;...upper XRI 20H ;..case HEX4 SUI 30H ;SUBTRACT 30 HEX ASCII JC ERROR ;NO GOOD IF CARRY CPI 10 ;IS IT 0 THROUGH 9? JC HEXOK ;IT'S OK IF SO SUI 7 ;SUBTRACT 7 MORE FOR LETTERS CPI 10 ;LOWER THAN 10? JC ERROR ;NO GOOD IF SO CPI 16 ;HIGHER THAN 16? JNC ERROR ;NO GOOD IF SO ; HEXOK LXI H,0000H ;CLEAR H-L FOR MULTIPLICATION DAD D ;H-L=D-E TIMES ONE DAD H ;H-L=D-E TIMES TWO DAD H ;H-L=D-E TIMES FOUR DAD H ;H-L=D-E TIMES EIGHT DAD H ;H-L=D-E TIMES SIXTEEN MOV E,A ;NEW KEY VALUE TO E MVI D,00H ;CLEAR D DAD D ;ADD UNIT VALUE TO TOTAL XCHG ;NEW TOTAL TO D-E JMP NEXT3 ;LOOP FOR NEXT DIGIT ; BININ LXI H,BINRY ;SHOWS ASCII FOR BINARY CALL VALIN ;SHOWS QUESTION WITH PROPER BASE ; NEXT4 CALL GETIN ;GET CHARACTER AND ECHO IT JZ CNVRT ;GO CONVERT IF SO SUI 30H ;SUBTRACT 30H FROM ASCII JC ERROR ;NO GOOD IF CARRY CPI 2 ;IF HIGHER THAN "1"? JNC ERROR ;NO GOOD IF SO LXI H,0000H ;CLEAR H-L FOR MULTIPLICATION DAD D ;H-L=D-E TIMES ONE DAD H ;H-L=D-E TIMES TWO MOV E,A ;NEW KEY VALUE TO E MVI D,00H ;CLEAR D DAD D ;ADD UNIT VALUE TO TOTAL XCHG ;NEW TOTAL TO D-E JMP NEXT4 ;LOOP FOR NEXT DIGIT ; SOCTN LXI H,SPLIT ;POINT TO ASCII FOR SPLIT OCTAL CALL VALIN ;SHOWS QUESTION WITH PROPER BASE ; NEXT5 CALL GETIN ;GET CHARACTER AND ECHO IT JZ CNVRT ;GO CONVERT TO ALL BASES IF SO CPI '/' ;IS CHARACTER A SLASH? JNZ NODOT ;NO-CONTINUE MOV D,E ;YES - TOTAL IN E BECOMES HIGH BYTE MVI E,00H ;CLEAR E JMP NEXT5 ;GO GET NEXT CHARACTER ; NODOT SUI 30H ;SUBTRACT30H FROM ASCII JC ERROR ;NO GOOD IF CARRY CPI 8 ;HIGHER THAN "7"? JNC ERROR ;NO GOOD IF SO MOV L,A ;SAVE NEW KEY VALUE IN L MOV A,E ;PREVIOUS TOTAL TO A ADD A ;PREVIOUS TOTAL TIMES TWO ADD A ;PREVIOUS TOTAL TIMES FOUR ADD A ;PREVIOUS TOTAL TIMES EIGHT ADD L ;ADD NEW KEY TO MULTIPLIED TOTAL MOV E,A ;NEWTOTAL BACK TO E JMP NEXT5 ;LOOP FOR NEXT DIGIT ; ASCIN LXI H,ASCII ;POINT TO ASCII FOR ASCII CALL VALIN ;SHOWS QUESTION WITH PROPER BASE ; NEXT6 CALL GETIN ;GET CHARACTER AND ECHO IT JZ CNVRT ;GO CONVERT TO ALL BASES IF SO MOV D,E ;LAST CHARACTER MOVES TO D MOV E,A ;NEW CHARACTER GOES IN E JMP NEXT6 ;LOOP FOR NEXT CHARACTER ; CNVRT LXI H,MESS5 ;SET H-L TO BEGINNING OF MESSAGE CALL PRINT ;DISPLAY MESSAGE ; DOUT XCHG ;SWAP UNKNOWN INTO H-L PUSH H ;SAVE UNKNOWN ON STACK LXI B,10000D;LOAD B-C WITH 10000 DECIMAL CALL SUBTR ;SUBTRACT AND DISPLAY LXI B,1000D ;LOAD B-C WITH 1000 DECIMAL CALL SUBTR ;SUBTRACT AND DISPLAY LXI B,100D ;LOAD B-C WITH 100 DECIMAL CALL SUBTR ;SUBTRACT AND DISPLAY LXI B,10D ;LOAD B-C WITH 10 DECIMAL CALL SUBTR ;SUBTRACT AND DISPLAY MOV A,L ;WHAT'S LEFT IS UNITS ONLY ADI 30H ;MAKE IT ASCII CALL OUTPT ;DISPLAY UNITS POP D ;GET ORIGINAL BACK CALL SPACES ;OUTPUT TWO SPACES ; HOUT MOV A,D ;HIGH BYTE OF UNKNOWN TO A CALL DOHEX ;CONVERT HEX AND DISPLAY MOV A,E ;LOW BYTE OF UNKNOWN TO A CALL DOHEX ;CONVERT AND DISPLAY CALL SPACES ;OUTPUT TWO SPACES ; OOUT MOV A,D ;HIGH BYTE OF UNKNOWN TO A RAL ;ROTATE LEFT MOST BIT RAL ; INTO RIGHTMOST POSITION PUSH PSW ;SAVE NEW BYTE ON STACK ANI 01H ;ZER0 ALL BUT RIGHT BIT CALL OCTOUT ;MAKE ASCII AND DISPLAY ON CRT POP PSW ;GET MODIFIED BYTE BACK CALL ROTES ;GO NEXT 3 BYTES 2 TIMES MOV A,E ;LOW BYTE OF UNKNOWN TO A CALL ROTES ;DO LEFTOVER OF HIGH AND 5 OF LOW CALL ROTER ;DO LAST THREE BYETE CALL SPACES ;OUTPUT TWO SPACES ; SOOUT MOV A,D ;HIGH BYTE OF UNKNOWN TO A CALL SOCT ;CONVERT TO OCTAL DISPLAY MVI A,'/' ;SET UP A '/' TO DISPLAY CALL OUTPT ;DISPLAY ON CRT MOV A,E ;LOW BYTE OF UNKNOWN TO A CALL SOCT ;CONVERT TO OCTAL AND DISPLAY CALL SPACES ;OUTPUT TWO SPACES ; BOUT MOV A,D ;HIGH BYTE OF UNKNOWN TO A CALL BINOUT ;DISPLAY AS 0'S AND 1'S MOV A,E ;LOW BYTE OF UNKNOWN TO A CALL BINOUT ;DISPLAY AS O'S AND 1'S CALL SPACES ;OUTPUT TWO SPACES ; AOUT MOV A,D ;HIGH BYTE OF UNKNOWN TO A CALL ATEST ;TEST FOR LEGAL AND DISPLAY MVI A,' ' ;NEED A SPACE TO SEPERATE CALL OUTPT ;DISPLAY THE SPACE MOV A,E ;LOW BYTE OF UNKNOWN TO A CALL ATEST ;TEST FOR LEGAL AND DISPLAY CALL CRLF ;DO A CAR RET AND LINE FEED CALL CRLF ;ONE MORE MAKES IT NICE JMP BEGIN1 ;START ALL OVER AGAIN??? ; CRLF MVI A,0DH ;SETUP A CARRIAGE RETURN CALL OUTPT ;DISPLAY IT MVI A,0AH ;SET UP A LINE FEED JMP OUTPT ;DISPLAY IT AND RETURN TO WHEREVER ; ATEST CPI ' ' ;LOWER THAN A SPACE? JC DODOT ;DISPLAY A '.' IF SO CPI 7FH ;HIGHER THAN A RUBOUT? JC OUTPT ;DISPLAY A CHARACTER IF SO ; DODOT MVI A,'.' ;SETUP A DOT TO DISPLAY JMP OUTPT ;DISPLAY THE DOT ON THE CRT BINOUT MVI B,08H ;8 BITS TO DO - SETUP COUNTER ; BLOOP RAL ;ROTATE A BIT INTO CARRY PUSH PSW ;SAVE THE MODIFIED BYTE MVI A,'1' ;ASSUME BIT LOGIC IS 1 JC BINOK ;DISPLAY IT IF A-OK MVI A,'0' ;OOPS CHANGED MY MIND FICKLE ; BINOK CALL OUTPT ;DISPLAY WHATEVER POP PSW ;GET MODIFIED BYTE BACK DCR B ;COUNT ONE BIT COMPLETED JNZ BLOOP ;DO ANOTHER UNTILL ALL 8 ARE DONE RET ;THEN GO BACK TO WHEREVER ; SOCT RAL ;ROTATE TWO LEFTMOST BITS RAL ; INTO TWO RIGHTMOST RAL ; POSITIONS PUSH PSW ;SAVE MODIFIED BYTE ON STACK ANI 03H ;ZERO ALL BUT TWO RIGHTMOST BITS CALL SPOUT ;MAKE ASCII AND DISPLAY ON CRT POP PSW ;GET MODIFIED BYTE BACK CALL SPINR ;DO 3 BITS AND FALL INTO 3 MORE ; SPINR RAL ;ROTATE TWO LEFTMOST BITS RAL ; INOT TWO RIGHTMOST RAL ; POSITIONS ; SPOUT PUSH PSW ;SAVE MODIFIED BYTE ON STACK ANI 07H ;ZERO ALL BUT THREE RIGHT BITS ADI 30H ;ADD ASCII OFFSET CALL OUTPT ;DISPLAY CHARACTER ON CRT POP PSW ;GET MODIFIED BYTE BACK RET ;GO BACK TO WHERE YOU CAME FROM ; ROTES CALL ROTER ;DO 3 BITS AND FALL INTO 3 MORE ; ROTER RAL ;ROTATE CARRY PLUS LEFTMOST RAL ; TWO BITS OF DATA BYTE INTO RAL ; THREE RIGHTMOST BITS ; OCTOUT PUSH PSW ;SAVE MODIFIED BYTE ON STACK ANI 07H ;ZERO ALL BUT RIGHT THREE BITS ADI 30H ;ADD IN ASCII OFFSET CALL OUTPT ;DISPLAY CHARACTER ON CRT POP PSW ;GET MODIFIEY BYTE BACK RET ;RETURN TO MAIN PROGRAM ; DOHEX PUSH PSW ;SAVE BYTE ON STACK RRC ;ROTATE RRC ;LEFT RRC ; FOUR BITS RRC ; INTO PLACE CALL HEXOUT ;MAKE ASCII AND DISPLAY POP PSW ;GET BYTE BACK ; HEXOUT ANI 0FH ;KEEP ONLY RIGHT FOUR BITS ADI 30H ;ADD ASCII OFFSET CPI ':' ;IS IT A NUMBER JC OUTPT ;DISPLAY IT ON CRT IF SO ADI 07H ;MAKE IT A LETTER JMP OUTPT ;AND DISPLAY ON CRT ; SUBTR MVI D,0FFH ;D REGISTER TO MINUS ONE ; LOOP5 MOV A,L ;LOW BYTE OF UNKNOWN TO A SUB C ;SUBTRACT LOW BYTE OF DIVISOR MOV L,A ;DIFFERENCE BACK TO L MOV A,H ;HIGHT BYTE OF UNKNOWN TO A SBB B ;SUBTRACT B AND BORROW IF ANY MOV H,A ;DIFFERENCE BACK TO H INR D ;COUNT ONE SUBTRACTION JNC LOOP5 ;SUBTRACT AGAIN IF NO BORROW DAD B ;ADD DIVISOR BACK TO UNKNOWN MOV A,D ;COUNT TO A ADI 30H ;MAKE IT ASCII JMP OUTPT ;DISPLAY ON CRT ; ERROR LXI H,MESS4 ;SET H-L TO BEGINNING OF MESSAGE CALL PRINT ;GO PRINT IT JMP BEGIN ;START OVER ; SPACES MVI A,' ' ;PUT A SPACE IN REGISTER A CALL OUTPT ;PRINT IT JMP OUTPT ;OUTPUT ANOTHER SPACE THEN RETURN ; GETIN CALL INPUT ;GET CHARACTER FROM KEYBOARD CPI 0DH ;ARE THEY DONE ENTERING? RNZ ;BACK TO WHOEVER IF NOT JMP CNVRT ;JMP TO CONVERT ALL BASES ; VALIN PUSH H ;SAVE BASE POINTER LXI H,WHAT ;POINT TO QUESTION CALL PRINT ;SHOWS THE QUESTION POP H ;GET THE BASE NAME POINTER BACK CALL PRINT ;PRINT IT LXI H,VALUE ;POINT TO VALUE JMP PRINT ;PRINT IT THEN JUMP WHEREVER ; WHAT DB CR,LF,'What''s your ',0 VALUE DB ' Value? ',0 DECIMAL DB 'Decimal',0 HEXAD DB 'Hexadecimal',0 OCTAL DB 'Octal',0 SPLIT DB 'Split Octal',0 BINRY DB 'Binary',0 ASCII DB 'ASCII',0 MESS1 DB CR,LF,'What base is your entry? ',0 MESS2 DB CR,LF,'Sorry that is not a base I can work with. ',0 MESS4 DB CR,LF DB 'Input character wrong for base specified, ' DB 're-enter',0 MESS5 DB CR,LF,' Decimal Hex Octal S/Octal Binary' DB ' ASCII',CR,LF,' ',0 MESS6 DB CR,LF,'Base Converter Ver. ',(VERN MOD 10)+'0','.' DB REVN/10+'0',(REVN MOD 10)+'0' DB CR,LF,'Possible choices are: ',CR,LF DB CR,LF,' A = ASCII ' DB CR,LF,' B = Binary ' DB CR,LF,' D = Decimal ' DB CR,LF,' H = Hexadecimal' DB CR,LF,' O = Octal ' DB CR,LF,' S = Split Octal ' DB CR,LF,' X = Exit ' DB CR,LF,0 ; DS 60 ;RESERVE SPACE FOR STACK STACK EQU $ ;TOP OF STACK ; END