;----------------------------------------------------------------------- ; ; N.ASM ; ; Decimal/hexadecimal/binary number conversion/logical evaluation program ; (C)1985 Norman H. Strassner ; ;----------------------------------------------------------------------- ; Address comments to: Norman H. Strassner ; 1950 N. Normandie Ave. ; Los Angeles, Ca 90027 ; (213-661-5000 Voice) ; Or ; Compuserve PPN 72135,1051 ; MCI MAIL - NSTRASS ; ; Version 4.1 May 17, 1985 ; Fixed several errors, including an "MVI M,A". Previous version ; gave different errors, depending which assembler was used. Now ; gives uniform results with ASM, MAC, M80 and SLRMAC assemblers. ; - Irv Hoff ; Version 4.0 May 14, 1985 ; Major re-write of file to include a local command line and capa- ; bilities for file output with ZCPR style filename specifications. ; -n.h.s. ; ; Version 3.1 May 12. 1985 ; Repaired a bug which caused the program to ignore character ; prefixes such as exclamation mark, "at sign" and circumflex. ; -n.h.s. ; ; Version 3.0 December 20, 1984 ** Major Overhaul ** ; Added multiple command line inputs with: + - AND OR and XOR ; logic functions. ; -n.h.s. ; ; Version 2.2 December 1, 1984 ; Added 'exclamation mark' prefix for lower case numbers as CP/M ; made all letters uppercase. ; -n.h.s. ; ; Version 2.1 July 30, 1984 ; A terrible bug in the source code was found. Some lines of ; source code must have inadvertently been delete from the file. ; Result: program did not work. This code is complete and has ; improvement: Displays the ASCII equivalent of the number if a ; valid ASCII character exists. ; ; Instead of just fixing the code, I also added routines that ; would handle the inputtind and displyaing of ASCII characters, ; making this program much more versatile. ; -n.h.s. ; ; Version 2.0 June 22, 1984 ; Added number/letter conversions. ; ; Version 1.0 August 29, 1983 ; Original writing for number conversions only. ; ;----------------------------------------------------------------------- ; ; Contributed to the public domain for non-profit use as a small thanks ; As A Small Thanks To All Hackers Everywhere ; ;----------------------------------------------------------------------- ; ; Equates ; V1 EQU '4' V2 EQU '0' CR EQU 0DH LF EQU 0AH MXDRV EQU 1+'B'-40H MXUSR EQU 15 TABSPCS EQU 7 + 1 ; Tab value 0 to disable + 1 BDOS EQU 5 ; BDOS entry point DBUF EQU 80H ; Default CP/M buffer FCB EQU 5CH TPA EQU 100H ; Start of transient program area ; ; ORG 100H JMP START ; Skip over title/version ; ; TTL: DB 'N ',V1,'.',V2,' Numerical/Logical Converter/Evaluator' DB ' (C)1985 Norman H. Strassner',CR,LF+80H ; PROMPT: DB 'N',V1,V2,'>'+80H ; Display prompt ; START: LXI H,0 ; Get local stack DAD SP SHLD OLDSTACK LXI SP,STACK ; XRA A STA FFLAG ; No file STA PFLAG ; No output to file STA FQF ; No file rqst ; MVI A,MXDRV ; Set up maximum STA MAXDRV ; Drive and MVI A,MXUSR ; User areas STA MAXUSR ; For save files CALL PUTUD ; Save current drive/user ; LXI H,DBUF ; Point to CP/M buffer MOV A,M ; Get length of command STA LOCAL$COM ; Set local command flag 0=local$com ORA A ; If no command, JNZ RQST ; Process a single command line LXI H,TTL ; Else say hello CALL COMSG JMP DETAILMSG ; RQST: CALL NEXT ; Point to first command, MOV M,A CPI '?' ; A menu request? JZ MENU INX H SHLD LINE$START ; Initialize first command pointer ; RESTART:LXI SP,STACK ; Reset stack pointer LDA LOCAL$COM ; Check for a local command request ORA A ; Z set if no local command JNZ RESTART1 ; Jmp if not a local command ; RST$LP: XRA A STA PFLAG LXI H,PROMPT CALL COMSG LXI H,DBUF MVI M,7EH ; Max length CALL LINEIN ; Get a local line JZ RST$LP INX H ; Point the command INX H CALL WNBMSG ; Send comand line out to file CALL FOUT$ON LXI H,DBUF+1 ; Point to the first character in line SHLD LINE$START ; Initiate the command line pointer ; RESTART1: XRA A ; Clear STA CMD$NUMBER ; The number of requests LXI H,PRODUCT$TABLE ; Point to the results table and MOV M,A ; Clear pending logical operation SHLD PRODUCT$PTR ; Save this table pointer ; ; ; Enter With HL=start of line ; CMD$LOOP: LHLD LINE$START ; Point to next command CALL NEXT ; Is there another ORA A ; One to do? JZ CHK$BYE1 ; No, finished XCHG ; Command pointer in DE LXI B,0 ; Clear a counter register LHLD PRODUCT$PTR ; Get the product pointer INX H ; Skip over opcode XRA A ; And MOV M,A ; Clear product INX H MOV M,A PUSH D POP H CALL FIND$END$OF$CMD ; Returns with HL=space or EOL found JC FERROR SHLD LINE$START DCX H XCHG ; DE has end of line position PUSH H LHLD PRODUCT$PTR MOV A,M ; Get current opcode POP H ORA A CZ OPERATOR$CHK ; Check for opcode only if none before MOV A,M ; Get it CPI '.' JNZ NO$RESTART INX H SHLD LINE$START JMP RESTART1 ; ; ; Look for a character in the command line, skipping over spaces ; Exit with carry set if EOL (0) found ; NEXT: MOV A,M CPI 1 RC ; If it is <1 then return with carry set CPI ' ' RNZ INX H JMP NEXT ; NO$RESTART: CPI ';' ; Note in the file? JZ NOTE CPI '^' ; Is it a control char to convert? JZ CNTRL$CNVRT ; Yes, convert control character CPI '@' ; Is it an upper case ASCII character? JZ CHAR$CNVRT ; Yes, jump CPI '!' ; Is it a lower case character? JZ LOWER$CASE ; Yes, jump CPI '?' ; A menu request? JZ MENU ; ; ; Must be a numeric request, check for decimal, hex, or binary ; LXI H,WRKSPC ; Get start of workspace SHLD WSPNTR ; Store it as initial pointer LDAX D ; Get last character for testing CALL MAKE$UCASE CPI 'H' ; Hex request? JZ HREQUEST ; Yes, process it CPI 'B' ; Binary request? JZ BREQUEST ; Yes, go for it ; ; ; Fall through if it is a decimal request ; LXI H,MULTABLE ; Point to start of multable LXI B,0 ; Clear BC ; Use 'C'for count of characters ; ; ; Fall through to here if decimal number requested ; Exit with C = number of number characters ; DECIMAL:LDAX D ; Get character CALL DELIM$CHK ; Begining of string JZ DECLEN ; Check if more that 5 chars. in number SUI '0' ; Make number CPI 10 ; Is it a number? JNC DERROR ; Error if not number CALL PROCESS ; Convert and add JMP DECIMAL ; Get another character ; DELIM$CHK: CPI ' ' RZ CPI ',' RET ; ; ; Decimal length check (max = 5 characters i.e., 65535) ; DECLEN: MOV A,C ; Get character count to 'A' CPI 6 ; Maximum character count for decimal JM ADDUM ; Ok JMP TOOLARGE ; More than 5 characters ; ; ; Jump here if hex conversion requested ; Exit with C = number of number characters ; HREQUEST: DCX D ; Point to last hex character LXI H,HEXTABLE ; Point to hextable LXI B,0 ; Clear counters ; HEXADECIMAL: LDAX D ; Get it to 'A' CALL DELIM$CHK ; Beggining of string? JZ ADDUM ; Yes, add numbers SUI '0' ; Make number CPI 10 ; Is it a number? CNC LETTER ; No, check if hex letter CALL PROCESS JMP HEXADECIMAL ; ; ; Jump here if possible hex letter found ; LETTER: LDAX D ; Get letter CALL MAKE$UCASE SUI 'A' ; Make number CPI 6 ; Really a hex letter? JNC HEXERROR ADI 10 ; Add hex bias RET ; ; ; Jump here if binary request ; Exit with C = number of number characters ; BREQUEST: DCX D ; Point to last binary character LXI H,BINTABLE ; Point to bintable LXI B,0 ; Clear counters ; BINARY: LDAX D ; Get character CALL DELIM$CHK ; Beggining of string? JZ BINLEN ; Yes, add numbers CPI '0' JZ BINOK ; Its a zero CPI '1' JNZ BERROR ; BINOK: SUI '0' ; Make a one or a zero CALL PROCESS JMP BINARY ; ; ; Binary length check ; BINLEN: MOV A,C CPI 17 JM ADDUM JMP BINLENER ; ; ; Adds all numbers in workspace, result to product ; ADDUM: LXI H,WRKSPC SHLD WSPNTR ; Point to beginning of workspace ; ADDUM1: LHLD WSPNTR MOV E,M ; LSB INX H MOV D,M ; MSB INX H SHLD WSPNTR ; Store new pointer CALL GET$PRODUCT ; Product to HL DAD D ; Add number JC TOOLARGE ; If carry, too large a number CALL SAVE$PRODUCT ; Save HL to current product DCR C JNZ ADDUM1 ; DISP$AND$RECYCLE: CALL INFODISP JMP RECYCLE ; GET$PRODUCT: LHLD PRODUCT$PTR ; Get product address INX H ; Point past opcode MOV A,M ; Get LSB INX H MOV H,M ; Get MSB MOV L,A ; Make it HL=current product RET ; SAVE$PRODUCT: XCHG ; Save product to DE LHLD PRODUCT$PTR INX H ; Point past opcode MOV M,E ; Store result INX H MOV M,D XCHG RET ; OPERATOR$CHK: PUSH D ; Save the end of cmd PUSH H ; And the start LXI D,OPCODE$TBL ; LP1: LDAX D ; Get opcode indicator PUSH H LHLD PRODUCT$PTR MOV M,A ; Store possible indicator POP H ORA A JZ TABLE$END ; End of table, no match INX D ; Point to start of opcode ; LP2: MOV A,M CALL MAKE$UCASE MOV M,A LDAX D ORA A ; End of this opcode, match found JZ FOUND CMP M ; Is there a match? JNZ NO$MATCH INX D INX H JMP LP2 ; FOUND: POP H POP D ; Restore POP PSW ; And cancle return LDA CMD$NUMBER ; The number of requests ORA A JZ EXPERROR JMP CMD$LOOP ; Recycle ; TABLE$END: POP H ; Restore pointer POP D RET ; NO$MATCH: LDAX D ORA A ; End of opcode? JZ REDO INX D JMP NO$MATCH ; REDO: INX D POP H PUSH H ; Restore pointer JMP LP1 ; ; ; Skip over spaces ; HL points to line buffer ; HL exits pointing to one after last character ; FIND$END$OF$CMD: MOV A,M ; Is the CALL DELIM$CHK ; Beggining of string? INX H ; A space JZ FIND$END$OF$CMD ; Keep going DCX H ; Not a delimiter, point back to it ORA A ; Is it a eol JNZ FEOC1 STC RET ; Yes return ; FEOC1: MOV A,M CALL DELIM$CHK ; Beggining of string? RZ ORA A RZ INR C INX H JMP FEOC1 ; LOWER$CASE: CALL EOLERR CALL MAKE$UCASE ADI 32 ; Make lower case CPI 123 JNC CERROR JMP CHAR$VAL ; CHAR$CNVRT: CALL EOLERR JMP CHAR$VAL ; CNTRL$CNVRT: CALL EOLERR CALL MAKE$UCASE SUI 40H ; Make a control character JC CERROR CPI ' ' JNC CERROR ; CHAR$VAL: MOV L,A MVI H,0 CALL SAVE$PRODUCT JMP DISP$AND$RECYCLE ; MAKE$UCASE: CPI 'a' RC CPI 'z'+1 RNC SUI 32 RET ; ; ; Display information to screen ; INFODISP: LXI H,CMD$NUMBER ; Which cmd is it MOV A,M ; If its not ORA M ; The first, don't.... CZ LINEFORMAT ; Present screen information INR M ; Increment count so wont' display again LHLD PRODUCT$PTR ; See if there MOV A,M ; Is an opcode? ORA A JZ VALUE$DISPLAY ; No, just be normal PUSH PSW ; Save the nmenoc CALL OP$DISP ; Display next with a mnemonic POP PSW LXI H,OP$DISP$RET PUSH H ; Set return address LXI H,OP$JMP$TBL-2 ; Point to the function address table ADD A ; Double the mnemonic MOV E,A ; Add MVI D,0 ; This DAD D ; The table adress MOV E,M ; Get the LSB INX H MOV D,M ; Get the MSB XCHG PCHL ; OP$DISP$RET: CALL SAVE$PRODUCT MVI A,'=' CALL CO JMP VALUE$DISPLAY ; ; ; Display the logic sequence ; 1. Get the mnemonic and display it ; OP$DISP:PUSH H LXI H,OPCODE$TBL ; OP$F: CMP M ; Is this the opcode requested? INX H JNZ OP$F CALL COMSG POP H ; VALUE$DISPLAY: MVI A,9 CALL CO CALL GET$PRODUCT ; Get current product to HL CALL DECOUT ; Print decimal equivalent ; HEXPRNT:CALL SPMSG DB 9,9+80H CALL GET$PRODUCT CALL DHW ; Display hex word CALL SPMSG DB 'H',9,9+80H CALL BINPRNT CALL SPMSG DB 'B',9+80H CALL GET$PRODUCT MOV A,H ORA A JNZ NOASCII MOV A,L CPI ' ' JC CNTRLCHAR JMP CHAROUT ; CNTRLCHAR: CPI 128 JNC NOASCII MVI A,'^' CALL CO MOV A,L ADI 40H ; Make ASCII ; CHAROUT: CALL CO JMP CRLF ; And return ; NOASCII:CALL SPMSG DB '[N/A]',CR,LF+80H RET ; ; ; Set next product and recycle ; RECYCLE: LHLD PRODUCT$PTR LXI D,3 DAD D SHLD PRODUCT$PTR MVI M,0 ; No opcode INX H ; Point to product MVI M,0FFH INX H MVI M,0FFH ; Mark end of table JMP CMD$LOOP ; ADD$FN: CALL PREV2DE$PROD2HL ; Get current and previous products DAD D RET ; ; ; HL=DE-HL ; SUB$FN: CALL PREV2DE$PROD2HL MOV A,E SUB L MOV L,A MOV A,D SBB H MOV H,A RET ; ; ; HL=DE and HL ; AND$FN: CALL PREV2DE$PROD2HL MOV A,E ANA L MOV L,A MOV A,D ANA H MOV H,A RET ; OR$FN: CALL PREV2DE$PROD2HL MOV A,E ORA L MOV L,A MOV A,D ORA H MOV H,A RET ; XOR$FN: CALL PREV2DE$PROD2HL MOV A,E XRA L MOV L,A MOV A,D XRA H MOV H,A RET ; MUL$FN: CALL PREV2DE$PROD2HL MOV C,L MOV B,H LXI H,0 MVI A,15 ; MLP: PUSH PSW ORA D JP MLP1 DAD B ; MLP1: DAD H XCHG DAD H XCHG POP PSW DCR A JNZ MLP ORA D RP DAD B RET ; ; ; Divide HL/DE ; DIV$FN: CALL PREV2DE$PROD2HL MOV A,H ORA L JZ DIV$BY$0$ERR XCHG MOV A,H STA SREM XRA D STA SQUOT MOV A,D ORA A JP CHKDE SUB A SUB L MOV L,A SBB A SUB H MOV D,A ; CHKDE: MOV A,H ORA A JP DODIV SUB A SUB E MOV E,A SBB A SUB D MOV H,A ; DODIV: CALL UDIV16 RC LDA SQUOT ORA A JP DOREM MVI A,0 SUB L MOV L,A MVI A,0 SBB H MOV H,A ; DOREM: LDA SREM ORA A RP SUB A SUB E MOV E,A SBB A SUB D MOV D,A RET ; UDIV16: MOV A,E ORA D JNZ DIVIDE LXI H,0 MOV D,H MOV E,L STC RET ; DIVIDE: MOV C,L MOV B,H LXI H,0 MVI A,16 ORA A ; DVLOOP: STA COUNT MOV A,C RAL MOV C,A MOV A,B RAL MOV B,A MOV A,L RAL MOV L,A MOV A,H RAL MOV H,A PUSH H MOV A,L SUB E MOV L,A MOV A,H SBB D MOV H,A CMC JC DROP XTHL ; DROP: INX SP INX SP LDA COUNT DCR A JNZ DVLOOP XCHG MOV A,C RAL MOV L,A MOV A,B RAL MOV H,A ORA A RET ; PREV2DE$PROD2HL: LHLD PRODUCT$PTR DCX H ; Point to MSB of previous product MOV D,M ; Get MSB DCX H ; Point to LSB MOV E,M ; DE=previous product JMP GET$PRODUCT ; HL=current product ; EOLERR: INX H ; Point to character MOV A,M ORA A RNZ MVI A,11 DB 1 ; ILLDU: MVI A,1 DB 1 ; FNAMER: MVI A,2 DB 1 ; FILERR: MVI A,3 DB 1 ; CERROR: MVI A,4 DB 1 ; DERROR: MVI A,5 DB 1 ; BERROR: MVI A,6 DB 1 ; BINLENER: MVI A,7 DB 1 ; HEXERROR: MVI A,8 DB 1 ; TOOLARGE: MVI A,9 DB 1 ; DIV$BY$0$ERR: MVI A,10 DB 1 ; FERROR: MVI A,11 DB 1 ; EXPERROR: MVI A,12 DB 1 ; OUTERROR: MVI A,13 DB 1 ; DETAILMSG: MVI A,16 ; ; ; Enter with error code in register 'A' ; ERROR$PROC: LXI H,ERRORTBL CPI 17 ; Maximum errors JC ER$P1 XRA A ; ER$P1: ADD A ; Double the inden MOV E,A MVI D,0 DAD D MOV E,M INX H MOV D,M XCHG CALL COMSG JMP CHK$BYE ; ; ; Process numbers to decimal equivalents ; PROCESS:INR C ; Increment count DCX D ; Point to next character PUSH D ; Save it MOV E,M ; Get multiplicand to DE INX H MOV D,M ; Make 16 bits INX H ; Point to next in table PUSH H ; Save it LXI H,0 ; Clear product MVI B,8 ; 8 bits to do ; MULT: DAD H RAL JNC CHCNT DAD D ; CHCNT: DCR B JNZ MULT ; Fall through if finished XCHG ; Product to DE LHLD WSPNTR ; Point to next position in workspace MOV M,E ; LSB INX H MOV M,D ; Msb INX H SHLD WSPNTR ; Update pointer POP H POP D ; Restore pointers RET ; ; ; Print HL in decimal on console ; DECOUT: PUSH H ; Save registers PUSH D PUSH B LXI B,-10 ; Conversion radix LXI D,-1 ; DECLP: DAD B INX D JC DECLP LXI B,10 DAD B XCHG MOV A,H ORA L CNZ DECOUT ; This is recursive MOV A,E ADI '0' CALL CO POP B POP D POP H RET ; ; ; Displays hex word ; Entry, HL = word to be displayed ; DHW: PUSH H ; Save the number MOV A,H CALL DHB ; Display high byte POP H ; Restore original number MOV A,L ; Display next byte by falling through ; To dhb and beyond ; ; ; Displays a hex byte, two hex digits ; Entry, A = byte to be displayed ; DHB: PUSH PSW ; Save byte to convert to hex RRC RRC RRC RRC CALL DHD ; Display hex digit POP PSW ; ; ; Display hex digit ; Entry A, low 4 Bits = digit ; DHD: ANI 0FH CPI 10 JNC DHD1 ; If not 0 thru 9 ADI '0' JMP DCH ; DHD1: ADI 'A'-10 ; Create "A,b,c,d,e, Or F" ; DCH: JMP CO ; ; ; Prints binary form of number in product ; BINPRNT:ORA A ; Clear carry CALL GET$PRODUCT MOV A,H ; Get MSB CALL BP1 MVI A,' ' CALL CO MOV A,L ; BP1: MVI B,8 ; Bits to get ; BP2: RAL ; Get bit to carry PUSH PSW JC ONEBIT MVI A,'0' JMP BP3 ; ONEBIT: MVI A,'1' ; BP3: CALL CO POP PSW ; Restore all bits DCR B RZ JMP BP2 ; ; ; Prints screen information ; LINEFORMAT: CALL SPMSG DB '---- DECIMAL ---- ' DB ' HEXIDECIMAL ' DB '-------- BINARY ----- ' DB ' -- ASCII --' DB CR,LF+80H RET ; ; ; Message pointed to by stack out to console ; SPMSG: XTHL MOV A,M INX H XTHL ORA A RZ CALL CO CPI 80H RNC JMP SPMSG ; COMSG: MOV A,M ORA A RZ CALL CO CPI 80H RNC INX H JMP COMSG ; WNBMSG: LDA FFLAG ORA A RZ LDA FFLAG ORA A RZ CALL WNBMSGLP ; WNBCRLF:MVI A,CR CALL WNB MVI A,LF JMP WNB ; WNBMSGLP: MOV A,M CPI ';' RZ ORA A RZ CALL WNB CPI 80H RNC INX H JMP WNBMSGLP ; ; ; Print carriage return and line feed ; CRLF: MVI A,CR CALL CO MVI A,LF ; ; ; Character in register 'A' output to console ; CO: PUSH PSW PUSH B ; Save registers PUSH D PUSH H ANI 7FH ; Clear any high bits MOV B,A LDA PFLAG ; Check the file flag CPI 0FFH ; Check for 0FFH=file MOV A,B CZ WNB ; CO1: MVI C,2 ; Select function MOV E,A ; Select functrion CALL BDOS ; Output by CP/M POP H ; Restore registers POP D POP B POP PSW RET ; ; ; Leave a note in the file ; NOTE: LDA FFLAG ORA A JZ RESTART INX H CALL WNBMSG CALL WNBCRLF JMP RESTART ; LINEIN: PUSH H MOV C,M ; C=buffer length maximum MVI B,0 ; Character count = 0 MOV M,B ; Clear the count INX H ; Point to start of line buffer MVI M,' ' ; Pad a space INX H ; RDLOOP: CALL RDCHAR CPI 27 ; Open a file JZ FLRQ CPI 3 ; Exit to CP/< JZ RDBYE CPI 9 ; Tabout of it? JZ TABOUT CPI CR ; Exit linein routine JZ EXITRD CPI 24 ; Restart the line JZ LRSTRT CPI 07FH ; Restart the line JZ LRSTRT CPI 8 ; Backspace JNZ RDLP0 CALL BACKSP JMP RDLOOP ; FLRQ: LDA FQF ORA A JNZ RDLOOP MOV A,B ORA A JZ FDISPATCH JMP RDLOOP ; RDBYE: MOV A,B ORA A JZ BYE JMP RDLOOP ; TABOUT: MVI D,TABSPCS INR D ; TABLP: MVI A,' ' CALL RDLP1 DCR D JNZ TABLP JMP RDLOOP ; EXITRD: CALL CRLF MOV A,B ; Get character count ORA A ; See if any request JZ EXRDRET ; No, just go away INR A ; Yes, compensate for padding space ; EXRDRET:MVI M,0 ; Terminate line POP H MOV M,A ; Save the length MVI A,0 STA FQF RET ; LRSTRT: CALL BACKSP JNZ LRSTRT JMP RDLOOP ; RDLP0: CALL RDLP1 JMP RDLOOP ; RDLP1: MOV E,A ; Save character MOV A,B CMP C JC STRCH ; LERR: MVI A,7 JMP CO ; ; ; Buffer not full, store character if legal ; STRCH: MOV A,E CPI ' ' JC LERR MOV M,A INX H INR B JMP CO ; RDCHAR: PUSH H PUSH B CALL RDWAIT POP B POP H RET ; RDWAIT: MVI C,6 MVI E,0FFH CALL BDOS ORA A RNZ JMP RDWAIT ; BACKSP: MVI M,' ' ; Clear this character with a space MOV A,B ; Check the length ORA A ; If length=0 RZ ; Then return DCX H ; Else decrement pointer MVI M,' ' ; Also clear current character CALL SPMSG DB 8,' ',8+80H DCR B ; Decrement count RET ; ; ; Cancel current file ; FDISPATCH: LDA FFLAG ORA A JZ FILERQST ; FILECAN:XRA A STA PFLAG CALL CRLF LXI H,FNBUF+2 CALL COMSG CALL SPMSG DB ' <-- lose, elete, or RETURN ','?'+80H CALL RDCHAR CALL MAKE$UCASE CALL CO ; Display the response PUSH PSW CALL CRLF CALL FOUT$ON POP PSW CPI 'D' JZ KILLFILE CPI CR JZ CHK$BYE CPI 'C' JNZ FILECAN CALL WRITE$CLOS JMP CHK$BYE ; WRITE$CLOS: CALL LAST$WRITE LXI D,FCB CALL CLSFIL CALL CRLF LXI H,FNBUF+2 CALL COMSG CALL SPMSG DB ' closed',CR,LF+80H RET ; FOUT$ON:LDA FFLAG STA PFLAG RET ; KILLFILE: LXI D,FCB CALL CLSFIL CALL DELFIL LXI H,FNBUF+2 CALL COMSG CALL SPMSG DB ' delete','d'+80H JMP CHK$BYE ; FILERQST: MVI A,0FFH STA FQF CALL SPMSG DB 'Filename?',' '+80H LXI H,FNBUF MVI M,15 CALL LINEIN JZ RESTART CALL RETUD ; Get current drive/user MOV H,B MOV L,C SHLD USERNO ; Save current du LXI H,FNBUF+2 ; Point to start of filename LXI D,FCB CALL FNAME ; Parse file name JZ FNAMER ; Not a valid file name INX B ; Check if current du: MOV A,B ORA C DCX B ; Restore du: value JZ CURRDU ; Skip this if current MOV A,B ; Get specified drive DCR B ; Get into range 0..f CPI 0FFH ; Ff means current drive LXI H,MAXDRV JNZ NEWDSK ; Skip if different LDA DRIVENO MOV B,A JMP CURDSK ; NEWDSK: CMP M JNC ILLDU ; Yes - complain ; CURDSK: MOV A,C ; Get specified user area CPI '?' ; All user areas??? JZ ILLDU ; Yes - complain CPI 0FFH ; Current user area? JNZ NEWUSR LDA USERNO MOV C,A JMP CURUSR ; NEWUSR: INX H ; Illegal user specified? CMP M JNC ILLDU ; Yes - complain ; CURUSR: CALL LOGUD ; Log into specified du: ; CURRDU: LXI D,FCB CALL DELFIL CALL CREFIL JZ OUTERROR ; FILEOK: CALL CRLF LXI H,FNBUF+2 CALL COMSG CALL SPMSG DB ' ope','n'+80H MVI A,0FFH STA FFLAG LXI H,TTL CALL WNBMSG XRA A STA PFLAG JMP CHK$BYE ; ; ; Save current drive/user ; PUTUD: PUSH PSW PUSH B PUSH D PUSH H MVI C,19H CALL BDOS STA CRNTDSK MVI E,0FFH MVI C,' ' CALL BDOS STA CRNTUSR JMP L05C8 ; ; ; Restore original drive/user ; GETUD: PUSH PSW PUSH B PUSH D PUSH H LDA CRNTDSK MOV E,A MVI C,0EH CALL BDOS LDA CRNTUSR MOV E,A MVI C,' ' CALL BDOS ; L05C8: POP H POP D POP B POP PSW RET ; LOGUD: PUSH PSW PUSH B PUSH D PUSH H MOV E,C MVI C,' ' PUSH B CALL BDOS POP B MOV E,B MVI C,0EH CALL BDOS POP H POP D POP B POP PSW RET ; RETUD: PUSH PSW PUSH D PUSH H MVI C,19H CALL BDOS PUSH PSW MVI E,0FFH MVI C,' ' CALL BDOS MOV C,A POP PSW MOV B,A POP H POP D POP PSW RET ; ; ; Entry - used to call bdos - saves and restores registers ; ENTRY: PUSH D PUSH H CALL BDOS POP H POP D RET ; ; ; Fill rest of file buff with EOFs ; LAST$WRITE: LDA OBP ; Get bytes written CPI 80H ; End of buffer? JZ L$W1 MOV E,A ; Move to DE MVI D,0 LXI H,OUTBUF DAD D ; And offset the outbuf pointer ; LW$LOOP:MVI M,'Z'-40H ; EOF marker fill INR A CPI 80H JZ L$W1 ; Jump to DWRITE, returns to caller INX H JMP LW$LOOP ; L$W1: LXI D,OUTBUF CALL DMASET LXI D,FCB CALL DWRITE RET ; ; ; Close file control block ; DE -> FCB ; Z=1 error, Z=0 success ; CLSFIL: XRA A ; Clear file STA FFLAG ; Option MVI C,16 CALL ENTRY CPI 255 RET ; DELFIL: MVI C,19 CALL ENTRY CPI 0FFH ; 255 if file not found RET ; ; ; Write disk sector ; DE -> FCB ; Z=0 error, Z=1 normal ; DWRITE: MVI C,21 CALL ENTRY CPI 0 RET ; ; ; Create file - reel # assummed to be set ; DE -> FCB ; Z=0 normal, Z=1 error ; CREFIL: MVI C,22 CALL ENTRY CPI 255 RET ; ; ; Set DMA address - buffer address in DE ; DMASET: MVI C,26 CALL ENTRY RET ; ; ; Write next byte (FCB) - byte in 'A' reg ; WNB: PUSH PSW PUSH H PUSH D PUSH B PUSH PSW LDA OBP CPI 80H JNZ WNB0 LXI D,OUTBUF CALL DMASET LXI D,FCB CALL DWRITE JNZ FILERR ; WNB00: XRA A ; WNB0: MOV E,A MVI D,0 INR A STA OBP LXI H,OUTBUF DAD D POP PSW MOV M,A POP B POP D POP H POP PSW RET ; FNAME: PUSH D MVI A,0FFH STA L0485 STA L0486 MVI B,'$' PUSH D XRA A ; L03A0: STAX D INX D DCR B JNZ L03A0 POP D PUSH H ; L03A8: MOV A,M INX H CPI ':' JZ L03BC CPI ',' JZ L0417 CPI '!' JC L0417 JMP L03A8 ; L03BC: POP H MOV A,M CALL MAKE$UCASE CPI 'A' JC L03D5 SUI 'A' CPI 10H JC L03D0 ; L03CD: XRA A POP D RET ; L03D0: INR A STA L0485 INX H ; L03D5: MOV A,M CPI ':' JZ L0418 CPI '?' JNZ L03ED STA L0486 INX H MOV A,M CPI ':' JZ L0418 JMP L03CD ; L03ED: XRA A MOV B,A ; L03EF: MOV A,M INX H CPI ':' JZ L040B SUI '0' JC L03CD CPI 0AH JNC L03CD MOV C,A MOV A,B ADD A ADD A ADD B ADD A ADD C MOV B,A JMP L03EF ; L040B: MOV A,B CPI ' ' JNC L03CD STA L0486 JMP L0418 ; L0417: POP H ; L0418: MOV A,M CPI ':' JNZ L041F INX H ; L041F: MOV A,M CPI ',' JZ L042A CPI '!' JNC L0442 ; L042A: INX D MVI B,0BH MVI A,'?' ; L042F: STAX D INX D DCR B JNZ L042F ; L0435: LDA L0485 MOV B,A LDA L0486 MOV C,A POP D MVI A,0FFH ORA A RET ; L0442: MVI B,8 CALL L045C MVI B,3 MOV A,M CPI '.' JNZ L0456 INX H CALL L045C JMP L0435 ; L0456: CALL L047C JMP L0435 ; L045C: CALL CHAR$CHK JZ L047C INX D CPI '*' JNZ L046E MVI A,'?' STAX D JMP L0470 ; L046E: STAX D INX H ; L0470: DCR B JNZ L045C ; L0474: CALL CHAR$CHK RZ INX H JMP L0474 ; L047C: INX D MVI A,' ' STAX D DCR B JNZ L047C RET ; L0485: DB 0 L0486: DB 0 ; CHAR$CHK: MOV A,M CALL MAKE$UCASE ORA A RZ CPI '!' JC L04AA CPI '=' RZ CPI '_' RZ CPI '.' RZ CPI ':' RZ CPI ';' RZ CPI ',' RZ CPI '<' RZ CPI '>' RET ; L04AA: CMP M RET ; MENU: XRA A STA PFLAG LXI H,TTL CALL COMSG CALL SPMSG DB CR,LF DB 'Type "N" alone for command mode. ' DB 'Use ESCape key to open/close output file.',CR,LF DB 'Use semicolon ";" for notes directly to output file.' DB CR,LF,CR,LF DB 'Inputs : Decimal, Hex, Binary, ASCII, Logical ' DB 'expressions',CR,LF DB 'Results: Numerical operation(s) or conversion(s) ' DB 'in all above forms',CR,LF DB CR,LF DB 'APPEND: number with "H" if Hex, "B" if Binary. ' DB 'No appendage if decimal',CR,LF DB 'ASCII : CONTROL CHARACTERS ' DB '^@ - ^Z prefix with ^',CR,LF DB ' CAPITAL ASCII SPACE - TILDE(~) ' DB 'prefix with @',CR,LF DB ' LOWER CASE ASCII a - z ' DB 'prefix with !',CR,LF,CR,LF DB 'LOGIC: + ADD - SUB * MUL / DIV AND ' DB 'OR XOR . (.=Clear)',CR,LF,CR,LF DB 'From Command Line: ' DB '[ Separate expression(s) with spaces or a ' DB 'comma ]',CR,LF DB 'A> N n n,n,n,n n...n ' DB '<--- Single or multiple ',CR,LF DB 'A> N n [logical op] n,[logical op],n n . n ' DB '<--- Logical operations',CR,LF DB CR,LF DB 'Logical statements and conversions may be mixed. ' DB 'A period (.) in the',CR,LF DB 'command line clears 16 bit accumulator ' DB 'and resumes next operation.',CR,LF DB 'Comments to Norman H. Strassner, ' DB 'VIDEOMAN RCP/M, 213-666-8588','.'+80H ; CHK$BYE:CALL CRLF ; CHK$BYE1: LDA LOCAL$COM ORA A JZ RESTART ; BYE: LDA FFLAG ; Check for file ORA A JZ BYEBYE CALL WRITE$CLOS ; BYEBYE: CALL GETUD LHLD OLDSTACK ; Restore SPHL ; Stack pointer and RET ; Go byebye ; ; ; Error messages ; MBAD$ERROR: DB 'Unprintable error!','?'+80H MILLDU: DB 'Illegal Drive/Use','r'+80H MFNAMER: DB 'Bad file nam','e'+80H MFILERR: DB 'Bad file write. Disk full','?'+80H MCERROR: DB 'Illegal ASCI','I'+80H MDERROR: DB 'Number is not in decimal for','m'+80H MBERROR: DB 'Binary numbers have only ones and zeroe','s'+80H MBINLENER: DB 'Too many binary digit','s'+80H MHEXERROR: DB 'String has non-hexadecimal digit(s',')'+80H MTOOLARGE: DB 'Must be less than 6553','6'+80H MDIV$BY$0$ERR: DB 'Division by zero erro','r'+80H MFERROR: DB 'Format erro','r'+80H MDETAILMSG: DB 'Use ? for useage details',CR,LF+80H MEXPERROR: DB 'Bad logical evaluatio','n'+80H MOUTERROR: DB 'Error in file output.',CR,LF+80H ; ERRORTBL: DW MBAD$ERROR ; 0 DW MILLDU ; 1 DW MFNAMER ; 2 DW MFILERR ; 3 DW MCERROR ; 4 DW MDERROR ; 5 DW MBERROR ; 6 DW MBINLENER ; 7 DW MHEXERROR ; 8 DW MTOOLARGE ; 9 DW MDIV$BY$0$ERR ; 10 DW MFERROR ; 11 DW MEXPERROR ; 12 DW MOUTERROR ; 13 DW 00 ; 14 DW 00 ; 15 DW MDETAILMSG ; 16 DW 00 ; ; ; Table of tens for decimal conversion ; MULTABLE: DW 1 DW 10 DW 100 DW 1000 DW 10000 DW 0 ; End of table ; ; ; Table of hex positions for hex conversion ; HEXTABLE: DW 1 DW 10H DW 100H DW 1000H DW 0 ; End of table ; ; ; Table Of Bit Values For Binary Conversion ; BINTABLE: ; Bit# DW 1 ; 1 DW 2 ; 2 DW 4 ; 3 DW 8 ; 4 DW 16 ; 5 DW 32 ; 6 DW 64 ; 7 DW 128 ; 8 DW 256 ; 9 DW 512 ; 10 DW 1024 ; 11 DW 2048 ; 12 DW 4096 ; 13 DW 8192 ; 14 DW 16384 ; 15 DW 32768 ; 16 DW 0 ; End of table ; OPCODE$TBL: DB 1,'+',0 DB 1,'ADD',0 DB 2,'-',0 DB 2,'SUB',0 DB 3,'AND',0 DB 4,'OR',0 DB 5,'XOR',0 DB 6,'/',0 DB 6,'DIV',0 DB 7,'*',0 DB 7,'MUL',0 DB 0 ; OP$JMP$TBL: DW ADD$FN DW SUB$FN DW AND$FN DW OR$FN DW XOR$FN DW DIV$FN DW MUL$FN DW 00 ; FQF: DB 0 PFLAG: DB 0 ; Display output FFLAG: DB 0 ; File output flag MAXDRV: DB 0 MAXUSR: DB 0 USERNO: DB 0 ; Current user # DRIVENO: DB 0 ; Current drive CRNTDSK: DB 0 CRNTUSR: DB 0 ; PRODUCT$PTR: DS 2 WSPNTR: DS 2 ; Current position in table SQUOT: DS 1 SREM: DS 1 COUNT: DS 1 LOCAL$COM: DB 0 CMD$NUMBER: DB 0 LINE$START: DS 2 OLDSTACK: DS 2 OBP: DS 1 ; Output buff pointer (FCB1) ; ; These following buffer areas have been equated above the program so ; as to save space and leave the .COM file as short as possible ; FNBUF EQU $ ;; DS 17 ; File name buffer WRKSPC EQU FNBUF+17 ;; DS 40 ; Ample Workspace For Any Number ;; OUTBUF EQU WRKSPC+40 ;; DS 128 ; I/O buffers ;; DS 64 ; 32 level stack ;; STACK EQU OUTBUF+128+64 ;; DS 2 ;; PRODUCT$TABLE EQU STACK+2 ; ; END ;