; *************************************************************** ; * * ; * Z80MACRO.LIB Macro Library for CP/M System Routines * ; * * ; * Ref: "Mastering CP/M" by Alan R. Miller * ; * Modified and adapted to Z80MR by Rich Brewster * ; * R.D.1 Brackney, PA 18812 (717) 663-2408 * ; * * ; *************************************************************** ; Z80MACRO.LIB Table of Contents 06/23 10:15.24 ; MACRO PARAMETERS FLAG EMBEDDED MACROS ; AMBIG UFNFCB,AFNFCB AMFLAG ; CLOSE FCB,ERRJMP CLFLAG SYSF ; CMPBLK ADDR1,ADDR2,SIZE CMFLAG ; CMPDAT ADDR,SIZE CMFLAG ; CPABLK ADDR1,ADDR2,SIZE CPFLAG ; CPATXT TEXT,ADDR CPFLAG ; CPMVER ; CRLF CRFLAG PCHAR ; DELETE FCB,ERRJMP DEFLAG CRLF GCHAR PFNAME PRINT SYSF UCASE UNPROT ; DIVIDE TWOS DVFLAG ; DRIVE DRFLAG SYSF ; ENTER ; EXIT BOOT ; FILL ADDR,SIZE,VAL FLFLAG ; GCHAR CIFLAG SYSF ; GFNAME FCB FNFLAG CRLF PCHAR PRINT READB UCASE ; HEXHL HXFLAG UCASE ; HLDEC HLFLAG PCHAR ; LCHAR LOFLAG SYSF ; MAKE FCB,ERRJMP MKFLAG SYSF ; MOVBLK FROM,TO,SIZE ; MOVDAT TO,SIZE ; MULT TWOS MLFLAG ; OPEN FCB,ERRJMP OPFLAG SYSF ; OUTBIN BNFLAG PCHAR ; OUTHEX REG CXFLAG PCHAR ; OUTHL OUTHEX ; PCHAR COFLAG SYSF ; PFNAME FCB PFFLAG PCHAR PRINTB ; PRINT TEXT PRFLAG PCHAR ; PRINTB ADDR,SIZE PRFLAG PCHAR ; PROTEC FCB PTFLAG SYSF ; READB RBFLAG ; READS FCB,ERRJMP RSFLAG SYSF ; RENAME FCB RNFLAG CRLF PFNAME PRINT SYSF UNPROT ; SCAN CHAR,JMP ; SETDMA DMFLAG SYSF ; SYSF FUNC,AE ; UCASE ; UNPROT FCB PTFLAG SYSF ; UPPER ; VERSN TEXT ; WRITES FCB,ERRJMP WSFLAG SYSF ; *INCLUDE MRFLAGS.H in .AZM files for flag initialization. ; See MRFLAGS.DOC for MACRO/FLAG/GLOBAL cross listing. ; DEFINED CHARACTERS BEL EQU 07 ; ^G Console Beep TAB EQU 09 ; ^I Horizontal Tab LF EQU 0AH ; ^J Line Feed FF EQU 0CH ; ^L Form Feed CR EQU 0DH ; ^M Carriage Return EOF EQU 1AH ; ^Z End of File ESC EQU 1BH ; ^[ Escape BLANK EQU 20H ; Space ; CP/M CONVENTIONS BOOT EQU 0 ; Warm Boot entry vector BDOS EQU 5 ; BDOS entry vector FCB1 EQU 5CH ; Input file control block FCB2 EQU 6CH ; Second command line parameter DBUFF EQU 80H ; Default disk sector buffer TPA EQU 100H ; Transient program area ; MACRO OPTIONS STKSIZ EQU 32 ; EXIT macro user stack size BUFSIZ EQU 16 ; READB macro console input buffer size ; FLAG SETTINGS FALSE EQU 0 TRUE EQU .NOT.FALSE ; MACROS AMBIG MACRO #UFNFCB,#AFNFCB ; ; Inline macro to change an ambiguous filename at address #AFNFCB ; to match an unambiguous filename at address #UFNFCB. ; ; e.g. AMBIG FCB1,FCB2 ; LOCAL #AROUND PUSH HL PUSH DE PUSH BC LD HL,#AFNFCB+1 LD DE,#UFNFCB+1 LD B,11 ; number of characters in a filename CALL AMBI2? POP BC POP DE POP HL ; IF .NOT.AMFLAG JP #AROUND AMBI2?: LD A,'?' CP (HL) JR NZ,AMBI3? LD A,(DE) ; get UFN LD (HL),A ; put AFN AMBI3?: INC HL INC DE DJNZ AMBI2? RET ; AMFLAG DEFL TRUE #AROUND: ENDIF ; AMBIG ENDM CLOSE MACRO #FCB,#ERRJMP ; ; Inline macro to close a file using FCB at address #FCB. ; Jumps to #ERRJMP if the filename is not in the disk directory. ; ; e.g. CLOSE DFCB,NOFILE ; LOCAL #AROUND LD DE,#FCB CALL CLOS2? INC A ; A returns 0FFH if name not in directory JP Z,#ERRJMP ; IF .NOT.CLFLAG JP #AROUND CLOS2?: SYSF 16,0 ; Close File CLFLAG DEFL TRUE #AROUND: ENDIF ; CLOSE ENDM CMPBLK MACRO #ADDR1,#ADDR2,#SIZE ; ; Inline macro to compare two memory blocks of length ; #SIZE bytes at addresses #ADDR1 and #ADDR2. ; Z flag is set if the blocks are identical. ; ; e.g. CMPBLK FCB1,FCB2,12 ; LOCAL #AROUND PUSH HL PUSH DE PUSH BC LD BC,#SIZE LD HL,#ADDR1 LD DE,#ADDR2 CALL COMP2? POP BC POP DE POP HL ; IF .NOT.CMFLAG JP #AROUND COMP2?: LD A,(DE) CPI RET NZ INC DE JP PE,COMP2? RET ; CMFLAG DEFL TRUE #AROUND: ENDIF ; CMPBLK ENDM CMPDAT MACRO #ADDR,#SIZE ; ; Inline macro to compare immediately following data ; of length #SIZE bytes with a memory block at #ADDR. ; Z flag is set if the data are identical. ; ; e.g. CMPDAT FCB1+9,5 ; DB '???',2,10H ; LOCAL #DATA PUSH HL PUSH DE PUSH BC LD BC,#SIZE LD HL,#DATA LD DE,#ADDR CALL COMP2? POP BC POP DE POP HL JP #DATA+#SIZE ; IF .NOT.CMFLAG COMP2?: LD A,(DE) CPI RET NZ INC DE JP PE,COMP2? RET ; CMFLAG DEFL TRUE ENDIF #DATA: ; CMPDAT - DB here ENDM CPABLK MACRO #ADDR1,#ADDR2,#SIZE ; ; Inline macro to compare two memory blocks at #ADDR1 and #ADDR2 ; of length #SIZE bytes, 256 bytes max. ; 7-bit ASCII compare, Z flag is set if the blocks are identical. ; ; e.g. CPABLK FCB1+1,FCB2+1,11 ; LOCAL #AROUND PUSH HL PUSH DE PUSH BC LD B,#SIZE LD HL,#ADDR1 LD DE,#ADDR2 CALL CPAS2? POP BC POP DE POP HL ; IF .NOT.CPFLAG JP #AROUND CPAS2?: LD A,(DE) RES 7,A LD C,A LD A,(HL) RES 7,A CP C RET NZ INC HL INC DE DJNZ CPAS2? RET ; CPFLAG DEFL TRUE #AROUND: ENDIF ; CPABLK ENDM CPATXT MACRO #TEXT,#ADDR ; ; Inline macro to compare #TEXT string with a memory block at #ADDR. ; 7-bit ASCII compare, Z flag is set if the strings are identical. ; ; e.g. CPATXT 'COM',FCB1+9 ; LOCAL #AROUND,#STRING PUSH HL PUSH DE PUSH BC LD B,#AROUND-#STRING LD HL,#STRING LD DE,#ADDR CALL CPAS2? POP BC POP DE POP HL JP #AROUND ; IF .NOT.CPFLAG CPAS2?: LD A,(DE) RES 7,A LD C,A LD A,(HL) RES 7,A CP C RET NZ INC HL INC DE DJNZ CPAS2? RET ; CPFLAG DEFL TRUE ENDIF #STRING: DB '#TEXT' #AROUND: ; CPATXT ENDM CPMVER MACRO ; ; Inline macro to determine the CP/M version number. ; Returns version number in A, in BCD times 10. ; PUSH HL PUSH DE PUSH BC LD C,12 ; BDOS function 12 CALL BDOS POP BC POP DE POP HL ; CPMVER ENDM CRLF MACRO ; ; Inline macro to send carriage return and line feed to console. ; LOCAL #AROUND CALL CRLF2? ; IF .NOT.CRFLAG JP #AROUND CRLF2?: PUSH AF LD A,CR ; carriage return PCHAR LD A,LF ; line feed PCHAR POP AF RET ; CRFLAG DEFL TRUE #AROUND: ENDIF ; CRLF ENDM DELETE MACRO #FCB,#ERRJMP ; ; Inline macro to delete an existing disk file using the FCB ; at address #FCB. ; Prompts user if file is R/O, and gives option to abort. ; If aborting the deletion of a R/O file, jumps to #ERRJMP. ; ; e.g. DELETE FCB1,CONT ; LOCAL #AROUND,#DEL LD DE,#FCB LD A,(#FCB+9) ;first char of file type BIT 7,A ;R/O? JP Z,#DEL CRLF PFNAME #FCB PRINT ' is R/O, delete?' GCHAR UCASE CP 'Y' JP NZ,#ERRJMP UNPROT #FCB #DEL: CALL DELE2? ; IF .NOT.DEFLAG JP #AROUND DELE2?: SYSF 19,0 ; Delete File DEFLAG DEFL TRUE #AROUND: ENDIF ; DELETE ENDM DIVIDE MACRO #TWOS ; ; Inline macro to divide HL by #TWOS. ; #TWOS must be a power of 2. ; HL unchanged if #TWOS is 0 or 1. ; ; e.g. DIVIDE 4 ; LOCAL #AROUND PUSH BC LD B,#TWOS CALL DIVI2? POP BC ; IF .NOT.DVFLAG JP #AROUND DIVI2?: LD A,B OR A RET Z ; by zero RRA RET C ; by one LD B,A DIVI3?: CALL DIVI4? LD A,B ; get divisor RRA LD B,A JR NC,DIVI3? RET DIVI4?: XOR A ; clear carry LD A,H RRA LD H,A LD A,L RRA LD L,A RET ; DVFLAG DEFL TRUE #AROUND: ENDIF ; DIVIDE ENDM DRIVE MACRO ; ; Inline macro to return current drive in A. ; A:=1, B:=2, etc. ; LOCAL #AROUND CALL DRIV2? INC A ; func 25 returns 0 for A: ; IF .NOT.DRFLAG JP #AROUND DRIV2?: SYSF 25,0 ; Return Current Disk DRFLAG DEFL TRUE #AROUND: ENDIF ; DRIVE ENDM ENTER MACRO ; ; Inline macro to save incoming stack. ; LD (OLDSTK),SP LD SP,STACK ; ENTER ENDM EXIT MACRO #BOOT ; ; Inline macro to restore the stack. ; If #BOOT is 0 then warm boot on exit. ; LD SP,(OLDSTK) ; IF #BOOT RET ELSE LD C,0 ; warm boot CALL BDOS ENDIF ; OLDSTK: DS 2 ; incoming SP saved here DS STKSIZ ; user stack STACK EQU $ ; stack top here ; EXIT ENDM FILL MACRO #ADDR,#SIZE,#VAL ; ; Inline macro to fill memory with byte #VAL, ; starting at #ADDR, continuing for #SIZE locations. ; ; e.g. FILL FCB1+1,8,BLANK ; LOCAL #AROUND PUSH HL PUSH BC LD HL,#ADDR LD BC,#SIZE LD A,#VAL CALL FILL2? POP BC POP HL ; IF .NOT.FLFLAG JP #AROUND FILL2?: PUSH DE LD D,A FILL3?: LD (HL),D INC HL DEC BC LD A,C OR B JR NZ,FILL3? POP DE RET ; FLFLAG DEFL TRUE #AROUND: ENDIF ; FILL ENDM GCHAR MACRO ; ; Inline macro to read one character from console. ; Suspends program execution and waits for character. ; Character is returned in A. ; LOCAL #AROUND CALL GCHA2? ; IF .NOT.CIFLAG JP #AROUND GCHA2?: SYSF 1,0 ; Console Input CIFLAG DEFL TRUE #AROUND: ENDIF ; GCHAR ENDM GFNAME MACRO #FCB ; ; Inline macro to get a filename from the ; console and place it in a memory FCB at address #FCB. ; ; e.g. GFNAME FCB1 ; LOCAL #AROUND PUSH HL PUSH DE PUSH BC LD HL,#FCB LD (?FCBAD),HL ; save FCB address CALL GNAM2? POP BC POP DE POP HL ; IF .NOT.FNFLAG JP #AROUND ?FCBAD: DS 2 ; FCB address saved here GNAM2?: CRLF GNAM3?: PRINT ' ' LD A,CR PCHAR PRINT 'Enter file name: ' LD HL,(?FCBAD) PUSH HL XOR A ; 0 = default drive LD (HL),A ; initialize to default drive LD B,11 ; chars in name LD A,BLANK ZNAME?: ; initialize name to blanks INC HL LD (HL),A DJNZ ZNAME? POP DE ; FCB address INC DE ; point to first char of name READB CALL GETCH? ; char returns in A JP C,GNAM3? ; nothing entered, so start again CP BLANK JP Z,GNAM3? ; leading space entered, so start again UCASE LD (DE),A ; store first char of name CALL GETCH? ; char returns in A RET C ; done: short name CP BLANK ; same, with trailing space RET Z LD B,7 ; 7 characters to go UCASE CP '.' JP Z,ENAME? ; end of name CP ':' JP NZ,PNAME? ; no drive specification LD A,(DE) ; get the drive spec SUB 40H ; make it binary DEC DE ; point to 1st FCB location LD (DE),A ; put binary drive spec CALL GETCH? ; start filename JP C,GNAM3? ; only drive spec entered, so start again UCASE INC B ; 8 characters to go PNAME?: INC DE LD (DE),A CALL GETCH? RET C CP BLANK RET Z UCASE CP '.' JP Z,ENAME? DJNZ PNAME? JP GNAM3? ; if 9 characters ENAME?: LD HL,(?FCBAD) ; get FCB LD DE,9 ; extent offset ADD HL,DE EX DE,HL LD B,3 ENAM2?: CALL GETCH? RET C CP BLANK RET Z UCASE LD (DE),A INC DE DJNZ ENAM2? RET ; FNFLAG DEFL TRUE #AROUND: ENDIF ; GFNAME ENDM HEXHL MACRO ; ; Inline macro to convert ASCII characters in the console ; buffer of READB into a 16-bit binary number in HL. ; Carry flag is set if invalid hex character found. ; ; e.g. READB ; HEXHL ; LOCAL #AROUND CALL RDHL2? ; IF .NOT.HXFLAG JP #AROUND RDHL2?: LD HL,0 ; clear HL RDHL3?: CALL GETCH? CCF ; check for last character RET NC UCASE CALL RDHL4? ; convert to binary RET C ; error of input ADD HL,HL ; multiply previous digit by 16 ADD HL,HL ADD HL,HL ADD HL,HL OR L ; combine new LD L,A ; put back into L JR RDHL3? ; next RDHL4?: SUB 30H ; ASCII bias RET C ; < 0 CP 17H CCF RET C ; > F CP 10 CCF RET NC ; 0-9 SUB 7 CP 10 ; A-F or error RET ; HXFLAG DEFL TRUE #AROUND: ENDIF ; HEXHL ENDM HLDEC MACRO ; ; Inline macro to print HL as a decimal string. ; LOCAL #AROUND CALL HLDC2? ; IF .NOT.HLFLAG JP #AROUND HLDC2?: PUSH HL PUSH DE PUSH BC LD B,0 ; leading-zero flag LD DE,-10000 ; two's complement CALL HLDC3? ; ten thousands LD DE,-1000 CALL HLDC3? ; thousands LD DE,-100 CALL HLDC3? ; hundreds LD DE,-10 CALL HLDC3? ; tens LD A,L ADD A,'0' ; make ASCII PCHAR POP BC POP DE POP HL RET HLDC3?: LD C,'0'-1 HLDC4?: INC C ADD HL,DE ; add neg until result negative JP C,HLDC4? ; OR A SBC HL,DE ; get back last value LD A,C ; decimal ASCII digit CP '1' JP NC,HLDC5? LD A,B ; check zero flag OR A LD A,C RET Z ; don't print if leading zero ; PCHAR ; print a non-leading zero RET HLDC5?: LD B,0FFH ; print all zeros from now on PCHAR ; first non-zero digit RET ; HLFLAG DEFL TRUE #AROUND: ENDIF ;HLDEC ENDM LCHAR MACRO ; ; Inline macro to send char in A to printer. ; ; e.g. LD A,CR ; LCHAR ; LOCAL #AROUND CALL LOCH2? ; IF .NOT.LOFLAG JP #AROUND LOCH2?: SYSF 5,1 ; List Output LOFLAG DEFL TRUE #AROUND: ENDIF ; LCHAR ENDM MAKE MACRO #FCB,#ERRJMP ; ; Inline macro to create a new disk file ; using FCB at address #FCB. ; Jumps to #ERRJMP if disk directory is full. ; ; e.g. MAKE FCB1,FULDIR ; LOCAL #AROUND LD DE,#FCB XOR A ; zero LD (#FCB+12),A ; ex LD (#FCB+32),A ; cr CALL MAKE2? INC A ; A returns 0FFH if no directory space left JP Z,#ERRJMP ; IF .NOT.MKFLAG JP #AROUND MAKE2?: SYSF 22,0 ; Make File MKFLAG DEFL TRUE #AROUND: ENDIF ; MAKE ENDM MOVBLK MACRO #FROM,#TO,#SIZE ; ; Inline macro to move a block of length #SIZE bytes ; from address #FROM to address #TO. ; ; e.g. MOVBLK FCB1,4000H,0FH ; PUSH HL PUSH DE PUSH BC LD HL,#FROM LD DE,#TO LD BC,#SIZE LDIR POP BC POP DE POP HL ; MOVBLK ENDM MOVDAT MACRO #TO,#SIZE ; ; Inline macro to move immediately following data ; of length #SIZE bytes to address #TO. ; ; e.g. MOVDAT NEWBUF,7 ; DB 30H,CR,LF,'TEST' ; LOCAL #DATA PUSH HL PUSH DE PUSH BC LD BC,#SIZE LD DE,#TO LD HL,#DATA LDIR POP BC POP DE POP HL JP #DATA+#SIZE #DATA: ; MOVDAT - DB here ENDM MULT MACRO #TWOS ; ; Inline macro to multiply HL by #TWOS. ; #TWOS must be 0, 1, or a power of 2. ; If #TWOS is 0, A is presumed loaded with multiplier. ; ; e.g. MULT 8 ; LOCAL #AROUND PUSH BC ; IF #TWOS LD B,#TWOS ELSE LD B,A ENDIF ; CALL MULT2? POP BC ; IF .NOT.MLFLAG JP #AROUND MULT2?: LD A,B OR A ; times 0 JR NZ,MULT3? LD L,A LD H,A RET MULT3?: RRA RET C ; times 1 LD B,A MULT4?: ADD HL,HL ; shift left LD A,B RRA LD B,A JR NC,MULT4? RET ; MLFLAG DEFL TRUE #AROUND: ENDIF ; MULT ENDM OPEN MACRO #FCB,#ERRJMP ; ; Inline macro to open an existing disk file ; using the FCB at address #FCB. ; Jumps to #ERRJMP if no file is found. ; ; e.g. OPEN FCB1,NOFILE ; LOCAL #AROUND LD DE,#FCB XOR A ; zero accumulator LD (#FCB+12),A ; extent LD (#FCB+32),A ; current record CALL OPEN2? INC A ; A returns 0FFH if no file JP Z,#ERRJMP ; IF .NOT.OPFLAG JP #AROUND OPEN2?: SYSF 15,0 ; Open File OPFLAG DEFL TRUE #AROUND: ENDIF ; OPEN ENDM OUTBIN MACRO ; ; Inline macro to print A as a binary string. ; LOCAL #AROUND CALL BINB2? ; IF .NOT.BNFLAG JP #AROUND BINB2?: PUSH BC LD C,A LD B,8 BINB3?: LD A,C ADD A,A ; left shift into carry LD C,A LD A,'0'/2 ADC A,A ; yields ASCII '0' or '1' PCHAR DEC B JP NZ,BINB3? POP BC RET ; BNFLAG DEFL TRUE #AROUND: ENDIF ; OUTBIN ENDM OUTHEX MACRO #REG ; ; Inline macro to convert binary number in register #REG ; to two hex ASCII characters, and print them. ; Original number is left in A. ; ; e.g. OUTHEX A ; LOCAL #AROUND LD A,#REG CALL OTHX2? ; IF .NOT.CXFLAG JP #AROUND OTHX2?: PUSH BC LD C,A ; save number in C RRA ; shift high nybble to low RRA RRA RRA CALL OTHX3? ; high byte LD A,C ; retrieve number CALL OTHX3? ; low byte LD A,C ; retrieve again POP BC RET OTHX3?: AND 0FH ; zero upper nybble ADD A,90H ; ASCII conversion DAA ADC A,40H DAA PCHAR ; send it RET ; CXFLAG DEFL TRUE #AROUND: ENDIF ; OUTHEX ENDM OUTHL MACRO ; ; Inline macro to print HL as a hexadecimal string. ; LOCAL #OVER LD A,H OR A ; is H zero? JP Z,#OVER OUTHEX H #OVER: OUTHEX L ; OUTHL ENDM PCHAR MACRO ; ; Inline macro to send char in A to console. ; ; e.g. LD A,(HL) ; PCHAR ; LOCAL #AROUND CALL PCHR2? ; IF .NOT.COFLAG JP #AROUND PCHR2?: SYSF 2,1 ; Console Output COFLAG DEFL TRUE #AROUND: ENDIF ; PCHAR ENDM PFNAME MACRO #FCB ; ; Inline macro to print file name in FCB at address #FCB. ; ; e.g. PFNAME FCB1 ; LOCAL #AROUND PUSH HL PUSH BC LD B,8 ; length of primary name LD HL,#FCB+1 CALL PFNA2? POP BC POP HL PRINTB #FCB+9,3 ; the file type ; IF .NOT.PFFLAG JP #AROUND PFNA2?: LD A,(HL) ; get char CP BLANK JP Z,PFNA3? RES 7,A ; make printable if 8th bit options used PCHAR INC HL DEC B JP NZ,PFNA2? PFNA3?: LD A,'.' PCHAR RET ; PFFLAG DEFL TRUE #AROUND: ENDIF ; PFNAME ENDM PRINT MACRO #TEXT ; ; Inline macro to print a string literal to the console. ; ; e.g. PRINT 'Message ' ; LOCAL #AROUND,#MESG PUSH HL PUSH BC LD C,#AROUND-#MESG LD HL,#MESG CALL PBUF2? POP BC POP HL JP #AROUND ; IF .NOT.PRFLAG PBUF2?: LD A,(HL) PCHAR INC HL DEC C JP NZ,PBUF2? RET ; PRFLAG DEFL TRUE ENDIF ; #MESG: DB '#TEXT' #AROUND: ; PRINT ENDM PRINTB MACRO #ADDR,#SIZE ; ; Inline macro to print a string at address #ADDR ; of length #SIZE bytes, 256 max. ; ; e.g. PRINTB FCB1+1,11 ; LOCAL #AROUND PUSH HL PUSH BC LD C,#SIZE LD HL,#ADDR CALL PBUF2? POP BC POP HL ; IF .NOT.PRFLAG JP #AROUND PBUF2?: LD A,(HL) PCHAR INC HL DEC C JP NZ,PBUF2? RET ; PRFLAG DEFL TRUE #AROUND: ENDIF ; PRINTB ENDM PROTEC MACRO #FCB ; ; Inline macro to set file attribute to R/O, ; using FCB at address #FCB. ; ; e.g. PROTEC FCB1 ; LOCAL #AROUND LD DE,#FCB LD A,(#FCB+9) ; get t1' bit SET 7,A ; set for R/O LD (#FCB+9),A ; put it back CALL PROT2? ; IF .NOT.PTFLAG JP #AROUND PROT2?: SYSF 30,0 ; Set File Attributes PTFLAG DEFL TRUE #AROUND: ENDIF ; PROTEC ENDM READB MACRO ; ; Inline macro to read a line from the console into a buffer. ; Buffer size is set by BUFSIZ. ; GETCH? subroutine retrieves characters from the buffer. ; ; e.g. READB ; LOCAL #AROUND CALL RDBF2? ; IF .NOT.RBFLAG JP #AROUND RDBF2?: PUSH HL PUSH DE PUSH BC LD DE,?MBUFF ; address of max length LD C,10 ; BDOS function 10 CALL BDOS LD HL,?RBUFF ; start of buffer LD (?BUFFP),HL ; initialize buffer pointer POP BC POP DE POP HL RET GETCH?: LD A,(?CBUFF) ; get character count SUB 1 ; decrement with carry RET C ; no more characters LD (?CBUFF),A ; update the count PUSH HL LD HL,(?BUFFP) ; get buffer pointer LD A,(HL) ; get the character INC HL ; increment pointer LD (?BUFFP),HL ; update the pointer POP HL RET ; RBFLAG DEFL TRUE ; ?BUFFP: DW ?RBUFF ; buffer pointer is here ?MBUFF: DB BUFSIZ ; max buffer length ?CBUFF: DS 1 ; character count placed here by BDOS call ?RBUFF: DS BUFSIZ ; buffer is here ; #AROUND: ENDIF ; READB ENDM READS MACRO #FCB,#ERRJMP ; ; Inline macro to read a disk sector into the DMA buffer, ; using FCB at address #FCB. ; Jumps to address #ERRJMP if EOF is read. ; ; e.g. READS FCB1,EOFILE ; LOCAL #AROUND LD DE,#FCB CALL READ2? OR A ; set flags JP NZ,#ERRJMP ; EOF read ; IF .NOT.RSFLAG JP #AROUND READ2?: SYSF 20,0 ; Read Sequential RSFLAG DEFL TRUE #AROUND: ENDIF ; READS ENDM RENAME MACRO #FCB ; ; Inline macro to rename an existing disk file. ; #FCB is FCB address holding original name. ; New name must exist at #FCB + 10H. ; ; e.g. RENAME FCB1 ; LOCAL #AROUND UNPROT #FCB ; make it R/W CALL RENA2? CRLF PFNAME #FCB PRINT ' renamed to ' PFNAME #FCB+10H ; IF .NOT.RNFLAG JP #AROUND RENA2?: SYSF 23,0 ; Rename File RNFLAG DEFL TRUE #AROUND: ENDIF ; RENAME ENDM SCAN MACRO #CHAR,#JMP ; ; Inline macro which generates a jump to #JMP if ; the console key #CHAR has been pressed. ; ; e.g. SCAN 3,BOOT ; Warm boot if ^C pressed ; LOCAL #OVER PUSH HL PUSH DE PUSH BC LD C,11 ; Get Console Status CALL BDOS POP BC POP DE POP HL RRCA ; 0FFH returned if char ready JP NC,#OVER ; no char GCHAR CP #CHAR JP Z,#JMP #OVER: ; SCAN ENDM SETDMA MACRO ; ; Inline macro to set the DMA address. ; DE must be loaded with the DMA address prior to SETDMA. ; ; e.g. SETDMA BUFFP ; LOCAL #AROUND CALL SDMA2? ; IF .NOT.DMFLAG JP #AROUND SDMA2?: SYSF 26,0 ; Set DMA Address DMFLAG DEFL TRUE #AROUND: ENDIF ; SETDMA ENDM SYSF MACRO #FUNC,#AE ; ; Macro to generate BDOS call #FUNC. ; NOT AN INLINE MACRO: needs branch around instructions. ; Referenced only by other macros in Z80MACRO.LIB ; If BDOS function is 2,5,8,or 14, then #AE=1; otherwise #AE = 0. ; ; e.g. SYSF 9,0 ; Print String ; SYSF 2,1 ; Console Output ; PUSH HL PUSH DE PUSH BC LD C,#FUNC ; IF #AE LD E,A PUSH AF CALL BDOS POP AF ELSE CALL BDOS ENDIF ; POP BC POP DE POP HL RET ; SYSF ENDM UCASE MACRO ; ; Inline macro to convert ASCII char in A to uppercase. ; Will not alter values other than ASCII lower case. ; ; e.g. UCASE ; LOCAL #SKIP CP 61H JP C,#SKIP CP 7BH JP NC,#SKIP AND 5FH ; make uppercase #SKIP: ; UCASE ENDM UNPROT MACRO #FCB ; ; Inline macro to convert R/O file to R/W ; using FCB at address #FCB. ; ; e.g. UNPROT FCB1 ; LOCAL #AROUND LD DE,#FCB LD A,(#FCB+9) ; get t1' bit RES 7,A ; reset for R/W LD (#FCB+9),A ; put it back CALL PROT2? ; IF .NOT.PTFLAG ; PROT2? shared with PROTEC macro JP #AROUND PROT2?: SYSF 30,0 ; Set File Attributes PTFLAG DEFL TRUE #AROUND: ENDIF ; UNPROT ENDM UPPER MACRO ; ; Inline macro to isolate upper digit of packed BCD in A ; and shift it to lower place. ; ; e.g. UPPER ; RRA RRA RRA RRA AND 0FH ; zero upper nybble ; UPPER ENDM VERSN MACRO #TEXT ; ; Inline macro to embed the version number. ; ; e.g. VERSN 'dd.mm.yy.NAME' ; LOCAL #AROUND JP #AROUND DB 'Ver ','#TEXT' #AROUND: ; VERSN ENDM WRITES MACRO #FCB,#ERRJMP ; ; Inline macro to write a sector to disk, ; using the FCB address at #FCB. ; Jumps to #ERRJMP if disk is full. ; ; e.g. WRITES FCB1,FULL ; LOCAL #AROUND LD DE,#FCB CALL WRIT2? OR A ; A is 0 if successful JP NZ,#ERRJMP ; disk is full ; IF .NOT.WSFLAG JP #AROUND WRIT2?: SYSF 21,0 ; Write Sequential WSFLAG DEFL TRUE #AROUND: ENDIF ; WRITES ENDM