JNZ CONOU1 ;if nonzero jump over PUSH B ;otherwise save input character CALL CONBRK ;Check for abort POP B ;recover the char PUSH B ;save it again CALL CONOF ;and print the character on the console POP B ;recover once more PUSH B ;would you believe save it again LDA LSTCPY ;get the list flag byte ORA A ;to set flags CNZ LISTF ; and to list if LSTCPY=true POP B ;restore char one last time CONOU1: MOV A,C ;put the byte into A LXI H,COLUMN ;point to the buffer column counter CPI 7FH ;Rubout ? RZ ;return if so INR M ;Increment column CPI ' ' ;is the character a space? RNC ;return if less - must be control DCR M ;Decrement column MOV A,M ;and get the character there ORA A ;check for a null RZ ;return if it is MOV A,C ;move the char into C CPI BACKSP ;was it a backspace? JNZ CONOU2 ;if not jump over DCR M ;Decrement column RET ;and return ; CONOU2: CPI LF ;was it a linefeed? RNZ ;return if not again MVI M,0 ;Set column to 0 RET ;and return ; ;****************************************************************************** ; Print char in C at console, convert Ctrl chars to ^[char] ; CTLOUT: MOV A,C ;move the char into A CALL GRAFIC ;see if it is printable JNC WRTCON ;jump past cause it is ok PUSH PSW ;otherwise save ctrl char on the stack MVI C,5EH ;get the "^" char CALL CONOUT ;and print it POP PSW ;get the char back ORI 40H ;add in the bias to make it print MOV C,A ;put it into C for the next ; ;****************************************************************************** ; BDOS function 2: write to the system console char in C ; WRTCON: MOV A,C ;which puts it into A CPI TAB ;check for tab JNZ CONOUT ;if not jump and print TABOUT: MVI C,' ' ;Space gets printed to expand tabs CALL CONOUT ; to LDA COLUMN ; next ANI 07H ; tab JNZ TABOUT ; stop RET ;Return ; DELAST: CALL BACKUP ;back up one character MVI C,' ' ;then get a blank CALL CONOF ;and print it out BACKUP: MVI C,BACKSP ;get a backspace JMP CONOF ;and print it as well to move into spot ; ;****************************************************************************** ; Print pound sign, CRLF, and fix columns ; LBCRLF: MVI C,'#' ;get a pound sign CALL CONOUT ;and print it CALL CRLF ;Turn up a new line LB1: LDA COLUMN ;get the column counter LXI H,CTEMP2 ;point to the temp counter CMP M ;are they equal? RNC ;not there yet MVI C,' ' ;so get a space CALL CONOUT ;and print it out JMP LB1 ;loop til the counts are the same ; ;****************************************************************************** ; Print CR/LF at console ; CRLF: MVI C,CR ; get a cr CALL CONOUT ;and print it out MVI C,LF ;followed by a lf JMP CONOUT ;which goes out too ; ;****************************************************************************** ; Print string at (BC) until '$' with TAB expansion ; PRINT: LDAX B ;get the byte at (BC) CPI '$' ;is it the end mark? RZ ;if so we are done INX B ;otherwise bump the pointer PUSH B ;and save it in the stack MOV C,A ;get the character into C CALL WRTCON ;write it out expanding tabs POP B ;recover the pointer JMP PRINT ;and loop til we hit the stop ; ;****************************************************************************** ; BDOS function 10: Read console buffer at ; enter with BC -> console buffer address ; REDBUF: LDA COLUMN ;get the column counter into A STA CTEMP2 ;save it at CTEMP2 LHLD FCB ;get the information into HL MOV C,M ;get the buffer count byte INX H ;and bump the pointer to the next spot PUSH H ;save it for later MVI B,0 ;zero B RB0: PUSH B ;save BC for later PUSH H ;and HL as well RB1: CALL CONIN ;go get a char from the console ANI 7FH ;strip the parity bit POP H ;recover HL POP B ;and BC CPI CR ;is this character a CR? JZ RBEXIT ;if so jump over CPI LF ;how about a LF JZ RBEXIT ;jump with that as well CPI BACKSP ;do we have a backspace? JNZ CHKRUB ;if not over we go MOV A,B ;put B into A ORA A ;is it still zero? JZ RB0 ;if so go get another character DCR B ;if not decrement the count in B LDA COLUMN ;get the column counter STA CTEMP1 ;save it at CTEMP1 for later JMP RB65 ;jump over ; ; Check for Rubout (remove & echo last char.) ; CHKRUB: CPI 7FH ;do we have a rubout? JNZ CHKEOL ;if not jump over MOV A,B ;if so move b into A ORA A ;set the flags JZ RB0 ;if b was zero go get another MOV A,M ;get the char at (ODATA) DCR B ;decrement the count in B DCX H ;point back to FCB JMP RB10 ;jump to echo the char ; ; Check for Control-E (physical end-of-line) ; CHKEOL: CPI CTRLE ; is it end of line? JNZ CKPTOG ;jump over if not PUSH B ;if so save BC PUSH H ;and FCB address CALL CRLF ;Turn up a new line XRA A ;zero A STA CTEMP2 ;set it into CTEMP2 JMP RB1 ;and go get more ; ; Check for Control-P ; CKPTOG: CPI CTRLP ;is it the print toggle JNZ CKBOL ;if not jump past PUSH H ;if so save FCB address LXI H,LSTCPY ;get the pointer to print toggle byte MVI A,01H ;put a 1 into A SUB M ;subtract it from the toggle MOV M,A ;and put it back POP H ;recover FCB JMP RB0 ;and go get more ; ; Check for Control-X (bac+space to beg. current line) ; CKBOL: CPI CTRLX ;do we back up? JNZ CKREML ;if not on to the next choice POP H ;if so restore the stack pointer BLOOP: LDA CTEMP2 ;get the byte at CTEMP2 LXI H,COLUMN ;and point to the column counter CMP M ;are they the same? JNC REDBUF ;if so go try again for input DCR M ;if not decrement the CTEMP2 count CALL DELAST ;delete the character there JMP BLOOP ;and loop until we are done ; ; check for control-U ; CKREML: CPI CTRLU ;do we remove the line after newline? JNZ CKRETL ;if not try again CALL LBCRLF ;if so print a "#" and CR POP H ;restore the stack JMP REDBUF ;and try for input again ; ; Check for Control-R (retype current line after new line) ; CKRETL: CPI CTLGO ;Go to routine ; ;****************************************************************************** ;routine to get the next directory sector location for reading ; GETDS: LHLD COUNT ;get the directory count MVI C,02H ;ready to slide it over 2 bits right CALL SPINHL ;spin hl into position - sector number SHLD GROUP ;save a copy at group SHLD DIRPNT ;and another at directory pointer GETD1: LXI H,GROUP ;point to directory sector number MOV C,M ;pull it INX H ; into MOV B,M ; BC LHLD SCRT2 ;pull current sector address MOV E,M ;pull (scratch2) 16 bits wide INX H ; into MOV D,M ; DE LHLD SCRT1 ;pull current track address MOV A,M ;pull (scratch1) into A INX H ; into MOV H,M ; HL MOV L,A ; 16 bits at (scratch1) into HL ; ;next two blocks set the track and starting sector number for the track ; so the directory disk access will be right ; GETD2: MOV A,C ;subtract SUB E ; track start sector MOV A,B ; from SBB D ; desired sector number JNC GETD3 ;if too far jump PUSH H ;save current track on stack LHLD DPBLK ;get sectors per track out MOV A,E ;subtract SUB L ; value MOV E,A ; from MOV A,D ; track start sector SBB H ; and leave MOV D,A ; result in DE POP H ;restore track count DCX H ;decrement count JMP GETD2 ;and loop until start is less than desired ; ; BC has the sector we want, DE the track start sector number, HL the track ; GETD3: PUSH H ;save the track count LHLD DPBLK ;get the sectors per track DAD D ;compute the next track start sector number JC GETD4 ;if this exceeds the desired number jump MOV A,C ;otherwise SUB L ; subtract MOV A,B ; new track start number SBB H ; from the desired sector JC GETD4 ;if ok then jump over XCHG ;otherwise swap DE and HL POP H ;recover track number INX H ;bump it by 1 JMP GETD3 ;and loop until done ; ;point the disk to the right spot for access now that the computing is done ; GETD4: POP H ;recover track number PUSH B ;save desired sector number PUSH D ;and the track starting sector number PUSH H ;and the track number again XCHG ;swap DE and HL LHLD TOFS ;get track offset into HL DAD D ;add in the desired track number MOV B,H ;and move it MOV C,L ; into BC CALL TRKF ;Select track POP D ;recover entry track into DE LHLD SCRT1 ;get pointer to current track storage MOV M,E ;and put INX H ; the new track MOV M,D ; back into scratch POP D ;recover current sector number LHLD SCRT2 ;get storage address MOV M,E ;and save INX H ; the new current sector number MOV M,D ; there POP B ;recover new track sector start number MOV A,C ;subtract SUB E ; track sector start number MOV C,A ; from MOV A,B ; the desired number SBB D ; and MOV B,A ; leave result in BC LHLD TRANS ;point to translation routine XCHG ;put address into DE CALL SECTRN ;go do the translation MOV C,L ;put the result MOV B,H ; into BC JMP SECF ;finish setting up the disk pointers ; ;****************************************************************************** ;routine gets extent sector count from storage and figures block number ; COMBLK: LXI H,BLSHFT ;point to block shift factor MOV C,M ;pull it into C LDA ESCNT2 ; pull in the extent low byte COMBL1: ORA A ;set flags - clear carry RAR ;rotate right through carry DCR C ;decrement count JNZ COMBL1 ;loop until done MOV B,A ;then save the byte into B MVI A,08H ;get bit 3 set SUB M ;subtract block shift from this value MOV C,A ;and save it into C LDA ESCNT1 ;get the extent high byte COMBL2: DCR C ;decrement count again JZ COMBL3 ;if done jump ORA A ;otherwise set flags - clear carry RAL ;rotate left through carry JMP COMBL2 ;loop until done ; COMBL3: ADD B ;add in the offset RET ;and return ; ;****************************************************************************** ;routine points into the FCB block and returns with group pointer. ;If BSIZE=0 blocks are>1024 and 16 bits come back ; GETGRP: LHLD FCB ;get the FCB address LXI D,16 ;and a 16 DAD D ;add in the offset DAD B ;add in BC as well LDA BSIZE ;get the block size byte ORA A ;set flags JZ HLPBC ;if zero add HL and BC MOV L,M ;pull in this byte MVI H,0 ;set upper byte 0 RET ;return with HL set ; ; routine sets HL = (HL+BC) ; HLPBC: DAD B ;add HL and BC MOV E,M ;move this address byte into E INX H ;point to next MOV D,M ;pull this one into D XCHG ;swap DE and HL RET ;and go back ; ;****************************************************************************** ;routine takes sector count for directory area and gets the group pointer out ; SECGRP: CALL COMBLK ;get the block number MOV C,A ;and put it into C MVI B,0 ;zero out B CALL GETGRP ;now go get the right group SHLD GROUP ;save it at group storage RET ;and go back ; ;****************************************************************************** ; routine checks group and sets flags if zero - no group 0 should be there ; TSTGRP: LHLD GROUP ;get the group pointer out MOV A,L ;move low into A ORA H ;or with H to set flags RET ;and go back ; ;****************************************************************************** ; routine appears to figure actual sector number from group pointer ; COMSEC: LDA BLSHFT ;get the block shift factor LHLD GROUP ;and the group pointer into HL COMS1: DAD H ;slide it right DCR A ;and decrement count JNZ COMS1 ;looping until it has shifted right amount SHLD DIRPNT ;then save it in the directory pointer LDA BLKMSK ;now get the block mask out MOV C,A ;save it in C LDA ESCNT2 ;get the low extent counter ANA C ;and it with the block mask ORA L ;or in the directory pointer low byte MOV L,A ;slide this back into L SHLD GROUP ;and save this address at group RET ;then back to sender ; ;****************************************************************************** ;routine to point to information + 12 - the extent byte of the FCB ; GETEX: LHLD FCB ;get the FCB pointer LXI D,12 ;and get a 12 DAD D ;add in the offset RET ;return with HL set to extent address ; ;****************************************************************************** ;routine sets HL to current record (CR) and DE to record count (RC) ; SETPT: LHLD FCB ;get the FCB address LXI D,15 ;get an offset of 15 DAD D ;HL now points to RC address XCHG ;swap new value into DE LXI H,17 ;now get an offset of 17 DAD D ;add this in so HL points to CR RET ;return with HL and DE set ; ;****************************************************************************** ;routine appears to get the extent byte from FCB and set up extent pointers ; FIXEXT: CALL SETPT ;set record pointers MOV A,M ;get the current record for sequential I/O STA ESCNT2 ;and save it XCHG ;swap DE and HL MOV A,M ;pull in the record count for this extent STA RECCNT ;and save it CALL GETEX ;point to extent byte in FCB LDA EXTMSK ;get the extent mask ANA M ;and the extent byte extent mask STA ESCNT1 ;saving the result RET ;and return ; ;****************************************************************************** ;routine appears to set up record counters ; FIXREC: CALL SETPT ;set the record pointers LDA DCODE ;get the byte CPI 02H ;is it a 2? JNZ FIXRC1 ;if not jump past XRA A ;zero out A FIXRC1: MOV C,A ;move A into C LDA ESCNT2 ;get the byte ADD C ;add it to C MOV M,A ;put the result away at CR in FCB XCHG ;swap DE and HL LDA RECCNT ;get the byte ( record count) MOV M,A ;place it at RC in FCB RET ;and return ; ;****************************************************************************** ; spin HL by C bits right ; SPINHL: INR C ;set up for the loop decrement of C SPH1: DCR C ;decrement loop count RZ ;return if all is well MOV A,H ;otherwise get H into A ORA A ;clearount MOV A,M ;check to INX H ; see CMP M ; if it is zero RNZ ; return if it is not INR A ;bump up to 1 if it is RET ;and then return ; ;****************************************************************************** ;routine sets counter to -1 for starting loop ; SETCNT: LXI H,-1 ;start off with a 16 bit -1 SHLD COUNT ;and save it at count RET ;return to sender ; ;****************************************************************************** ;routine moves to next directory entry - COUNT says the last one looked at ; NXTDIR: LHLD DIRMAX ;get the number of directory entries XCHG ;save it in DE LHLD COUNT ;now get the directory counter INX H ;add one to it SHLD COUNT ;and save it back for later CALL SUBHD ;looking too far? JNC GOTDIR ;if no carry still entries left JMP SETCNT ;otherwise return with a 16 bit -1 ; ;****************************************************************************** ;routine to get the next directory sector off of the disk ; GOTDIR: LDA COUNT ;get the directory count low byte ANI 03H ;strip off all but low two (4 entries per sec) MVI B,5 ;set to spin low 3 over 5 SPINAB: ADD A ;move over 1 bit DCR B ;decrement count JNZ SPINAB ;loop until done STA DIROFF ;save this for later ORA A ;set flags RNZ ;return if not zero PUSH B ;otherwise save BC CALL GETDS ;looks like we set for getting the next dir CALL GETNXT ;and read the next sector POP B ;recover the BC pair JMP CHKCNG ;see if the disk changed and return ; ;****************************************************************************** ;routine gets an allocation bit set into position ; and sets pointer to allocation byte for marking blocks ; BC has the group pointer - Exit with BC -> allocation byte ; D -> bit for this group ; A -> allocation byte spun into place ; GETBIT: MOV A,C ;save entry C into A ANI 07H ;strip off all but low 3 INR A ;add one to the result - bit number for group MOV E,A ;and put this into E MOV D,A ;and another into D for exit MOV A,C ;get another copy of C RRC ;spin RRC ; it RRC ; right 3 ANI 1FH ;strip off high 3 leaving high 5 in place MOV C,A ;put this into C MOV A,B ;now get entry B ADD A ;and spin ADD A ; it left ADD A ; four ADD A ; bits ADD A ; ORA C ;or in the word at C MOV C,A ;and put it back into C MOV A,B ;get another copy of B RRC ;slide RRC ; over 3 RRC ; right ANI 1FH ;strip off all but low 3 MOV B,A ;place this into B, BC is set LHLD ALLOCA ;now get the allocation pointer DAD B ;add in the offset MOV A,M ;and pull in this byte of it GBLOOP: RLC ;rotate it left through carry DCR E ;decrement the rotate count JNZ GBLOOP ;loop until the bit is in place RET ;and then return with it ; ;****************************************************************************** ;routine to set allocation bit - BC has the group pointer ;enter with E set with current allocation byte ; SETBIT: PUSH D ;save DE CALL GETBIT ;get allocation bit into position ANI 0FEH ;clear bit zero POP B ;restore BC - C has bit to set ORA C ;or in the allocation bit PUTBAK: RRC ;spin right DCR D ;decrement count JNZ PUTBAK ;loop til it is back in place MOV M,A ;and then put it back in RET ;and return ; ;****************************************************************************** ;routine to update allocation map for current directory ; FIXALL: CALL PNTDIR ;set pointer to DMA + offset LXI D,16 ;get offset of 16 DAD D ;add this in - point to group bytes PUSH B ;save BC with set bit in C MVI C,17 ;set up to spin 16 times FIXAL1: POP D ;get data off stack DCR C ;decrement counter RZ ;return if it is zero PUSH D ;otherwise save the data again LDA BSIZE ;get the block size ORA A ;set the flags JZ FIXAL2 ;if zero jump - blocks are > 1024 PUSH B ;otherwise save the current count PUSH H ;and the address data MOV C,M ;pull in the word at (HL) MVI B,0 ;zero out B - BC now has group pointer JMP FIXAL3 ;and jump over ; FIXAL2: DCR C ;these groups are two bytes wide so dec again PUSH B ;save the new count on the stack MOV C,M ;pull in the high group byte INX H ; point to low MOV B,M ; and pull it in so BC has both PUSH H ;save this address FIXAL3: MOV A,C ;put the new data into A ORA B ;compare with B JZ FIXAL4 ;if it is zero block is not allocated LHLD DSIZE ;get the number of disk blocks MOV A,L ;subtract SUB C ; HL MOV A,H ; from SBB B ; BC CNC SETBIT ;if not too big, go set the bit FIXAL4: POP H ;recover the group pointer INX H ;bump it by one POP B ;recover count JMP FIXAL1 ;and spin until done ; ;****************************************************************************** ;routine to get the allocation vector ; GETAL: LHLD DSIZE ;get the max number of blocks MVI C,03H ;set to CALL SPINHL ; divide by eight INX H ;add 1 for the map size MOV B,H ;and put map size MOV C,L ; into BC - number of bytes in allocation map LHLD ALLOCA ;point to allocation storage area CLRALL: MVI M,0 ;put in a zero INX H ;bump the pointer DCX B ;one less group to zero out MOV A,B ;put the new count into A ORA C ;check for done JNZ CLRALL ;if not loop until so LHLD AL01 ;if done get directory allocation bits XCHG ;swap DE and AL01 LHLD ALLOCA ;point to allocation stogare MOV M,E ;put directory allocation bits INX H ; into that MOV M,D ; storage area cause they are busy CALL HOMDSK ;home the selected disk LHLD SCRT0 ;get the scratch 0 address MVI M,03H ;save a 3 at (scratch0) INX H ;point to (scratch0+1) MVI M,0 ;and zero this out - it has 16 bit 3 now CALL SETCNT ;set a counter to -1 GETA1: MVI C,0FFH ;set the exit code in CALL NXTDIR ;set the next directory pointers CALL CHKCNT ;was there one? RZ ;return if not CALL PNTDIR ;point to the right spot MVI A,DELDAT ;get the file deleted mark CMP M ;is this what we see? JZ GETA1 ;keep looking for a nonempty block LDA USRCOD ;get the user byte CMP M ;test this against the first byte JNZ GETA2 ;if we don't match mark this block INX H ;bump pointer to file name entry MOV A,M ;pull the byte in SUI '$' ;is this a submit file name $$$.SUB JNZ GETA2 ;if not take this block also DCR A ;otherwise set A to FF STA ODATA ;and save it at ODATA for CCP to use GETA2: MVI C,01H ;set the bit into C CALL FIXALL ;fix this allocation bit CALL CHKINC ;test for too far - bump count if not JMP GETA1 ;spin until done with the scan ; ;****************************************************************************** ;routine loads return code and goes back to sender ; RETCOD: LDA SCODE1 ; JMP GOBAK ; ; ;****************************************************************************** ;routine appears to check extent byte ; CHKEXT: PUSH B ;get the entry BC safe PUSH PSW ;and the accumulator LDA EXTMSK ;get the extent mask CMA ;flip it over MOV B,A ;and save it into B MOV A,C ;move C into A ANA B ;and it with the flipped extent mask MOV C,A ;save this into C POP PSW ;get the entry A back ANA B ;and with flip extent mask SUB C ;subtract C ANI 1FH ;mask off high bit POP B ;recover the entry BC RET ;and go back confused ; ;****************************************************************************** ;search for a specified file - set flags to say how it went ;used by all file routines to set up file information ; SEARCH: MVI A,0FFH ;set return code up STA SCODE1 ;and save it for later LXI H,SCODE ;point to search code area MOV M,C ;save entry code away LHLD FCB ;get the entry FCB address SHLD SEARA ;save a copy CALL SETCNT ;set the search counter up CALL HOMDSK ;home the selected disk SERCHN: MVI C,0 ; CALL NXTDIR ;locate next directory entry CALL CHKCNT ;check to see if one was found JZ NOTFND ;jump over if not LHLD SEARA ;gete from the FCB ANI 80H ;strip off the low eight bits RNZ ;return if not zero MVI C,0FH ;otherwise set to look through S2 in FCB CALL SEARCH ;search for the file CALL CHKCNT ;was it there RZ ;zero says done LXI B,16 ;get the pointer for group bytes in dir CALL PNTDIR ;point to the directory DAD B ;add in the offset - pointing right XCHG ;swap DE and HL LHLD FCB ;point to the FCB DAD B ;add in the offset again MVI C,10H ;get set for 16 bytes to move CLOSF1: LDA BSIZE ;get the block size byte out ORA A ;is it zero JZ CLOSF4 ;if so blocks > 1024 so jump past ; ;small blocks ; MOV A,M ;pull the byte out ORA A ;test for zero LDAX D ;get the (DE) out JNZ CLOSF2 ;if not zero jump over MOV M,A ;otherwise put A into place CLOSF2: ORA A ;test the byte again JNZ CLOSF3 ;if not zero jump past MOV A,M ;otherwise pull in the byte STAX D ;stuff it back at (DE) CLOSF3: CMP M ;are they the same JNZ CLOSF7 ;if not jump JMP CLOSF5 ;otherwise skip over ; ;big blocks ; CLOSF4: CALL CHKCPY ;check and increment XCHG ;exchange again CALL CHKCPY ;check again for next byte XCHG ;exchange back - ready to continue LDAX D ;get the new byte from (DE) CMP M ;does it match (HL) JNZ CLOSF7 ;if not over we go INX D ;bump pointer INX H ; data LDAX D ;get next byte CMP M ;compare it as well JNZ CLOSF7 ;again if no match jump DCR C ;decrement the count CLOSF5: INX D ;increment the INX H ; pointers DCR C ;decrement the count JNZ CLOSF1 ;if not done spinn around again LXI B,-20 ;point back DAD B ; 20 bytes XCHG ;swap pointers DAD B ;and back this one up as well LDAX D ;pull in the byte at (DE) CMP M ;test against (HL) JC CLOSF6 ;if (HL)>(DE) jump MOV M,A ;if not put A into (HL) LXI B,3 ;get a 3 DAD B ;point down 3 XCHG ;swap pointers again DAD B ;down three also MOV A,M ;get the byte at (HL) STAX D ;stuff it in at (DE) CLOSF6: MVI A,0FFH ;get the flag data STA RWFLG1 ;set flag to say reading JMP SETD1 ;write out the directory block and return ; CLOSF7: LXI H,ODATA ;point to output data byte DCR M ;decrement it 1 RET ;and go back ; ;****************************************************************************** ;make a new directory entry for a new file ; MAKE: CALL ROCHK ; is the disk read only LHLD FCB ;nope - so get the FCB address PUSH H ;and save it on the stack LXI H,TINFO ;point to the TINFO area SHLD FCB ;save this as the FCB address MVI C,01H ;set to look at only the ET byte in the FCB CALL SEARCH ;search for the new file name CALL CHKCNT ;was it there POP H ;get the old FCB back SHLD FCB ;restore it right RZ ;return if it was there XCHG ;save FCB in DE LXI H,15 ;get offset to record count DAD D ;and set the pointer there MVI C,17 ;get set to spin through 16 bytes XRA A ;get a zero ready MAK1: MOV M,A ;and move zero INX H ; into DCR C ; all JNZ MAK1 ; the group bytes LXI H,13 ;get the offset to the S1 byte DAD D ;and point to it MOV M,A ;zero this as well CALL CHKINC ;see if we have more to do CALL MOVDIR ;copy the directory in place JMP SETS28 ;set bit 7 of S2 and return ; ;****************************************************************************** ;routine sets up for the next extent access for either read or write ; NEXTEX: XRA A ;get a zero STA RWFLG1 ;say we are writing CALL CLOSEF ;close the file CALL CHKCNT ;did it exist RZ ;return if not LHLD FCB ;get the FCB address LXI B,12 ;set to point to extent byte DAD B ;now it does MOV A,M ;pull the thing in INR A ;bump by one ANI 1FH ;strip off bit 7 MOV M,A ;and put it back JZ NEXTE1 ;if it was zero jump over MOV B,A ;otherwise save it in B LDA EXTMSK ;get the extent mask ANA B ;and use it LXI H,RWFLG1 ;and point to the flag ANA M ;and in this byte as well JZ NEXTE2 ;if zero jump past JMP NEXTE3 ;otherwise off to ; NEXTE1: LXI B,2 ;ready to bump 2 more DAD B ;add it in INR M ;increment this byte MOV A,M ;then pull it in ANI 0FH ;strip off the high 4 bits JZ NEXTE5 ;if zero jump NEXTE2: MVI C,0FH ;look through S2 byte in FCB CALL SEARCH ;look for the indicated file CALL CHKCNT ;see if it was there JNZ NEXTE3 ;if so open the next extent LDA RWFLG2 ;get the read/write flag INR A ;add one JZ NEXTE5 ;if it was FF then return CALL MAKE ;make a new file directory entry CALL CHKCNT ;was it ok JZ NEXTE5 ;if not set up exit routine JMP NEXTE4 ;otherwise set up extent pointers and return ; NEXTE3: CALL OPEN1 ;go open the next extent NEXTE4: CALL FIXEXT ;set the pointers up XRA A ;zero A for the return JMP GOBAK ;and go back ; NEXTE5: CALL JR1 ;set to return with problems JMP SETS28 ;set bit 7 of S2 to say so ; ;****************************************************************************** ;routine to read the disk ; DSKRED: MVI A,01H ;get a ! STA DCODE ;save it for the disk code byte RRERR: MVI A,0FFH ;get a read flag STA RWFLG2 ;set it in for the control CALL FIXEXT ;go fix the extent LDA ESCNT2 ;get the extent low byte LXI H,RECCNT ;point to the record count CMP M ;are they the same? JC DSKR1 ;if record count was bigger, jump over CPI 80H ;was the count 80 hex? JNZ DERR ;if not jump out with an error CALL NEXTEX ;go get the next extent XRA A ;set a=0 STA ESCNT2 ;save this as the new extent low byte LDA ODATA ;get the output data ORA A ;set the flags JNZ DERR ;if it was not zero exit with error DSKR1: CALL SECGRP ;otherwise group from the sector count CALL TSTGRP ;see if it is ok JZ DERR ;if not go back CALL COMSEC ;if co compute the right sector CALL GETD1 ;get the directory set right CALL RDSEC ;read the sector JMP FIXREC ;fix up the record and return ; DERR: JMP JR1 ;set the error exit and return ; ;****************************************************************************** ;routine to write the disk ; DSKWRT: MVI A,01H ;set the disk STA DCODE ; code up RWERR: MVI A,0 ;set the read write flag for write STA RWFLG2 ;and save it for later CALL ROCHK ;see if the drive is protected LHLD FCB ;get the FCB address CALL CHKFR1 ;see if the file is read only CALL FIXEXT ;fix up the extent LDA ESCNT2 ;and get the low extent byte CPI 80H ;is it greater that 80h JNC JR1 ;if so exit with errors CALL SECGRP ;compute the right group CALL TSTGRP ;see if it is ok MVI C,0 ;get a zero JNZ DSKW05 ;if ok jump over CALL COMBLK ;compute the block STA EXTBLK ;save it at extent block area LXI B,0 ;get a 16 bit 0 ORA A ;set flags JZ DSKW01 ;if zero jump over MOV C,A ; DCX B ; CALL GETGRP ;get the group counter out MOV B,H ;save it MOV C,L ; in BC DSKW01: CALL BLKAVL ;see if a block is available MOV A,L ;check for ORA H ; zero returned JNZ DSKW02 ;if not zero jump over MVI A,02H ;set the disk full message JMP GOBAK ;and return ; DSKW02: SHLD GROUP ;save the group counter XCHG ;put it inti DE as well LHLD FCB ;get the FCB address LXI B,16 ;set the offset to the record count DAD B ;and point to it LDA BSIZE ;get the block size ORA A ;is it zero LDA EXTBLK ;get the extent block out JZ DSKW03 ;if blocks are greater than 1024 jump CALL PNTD1 ;point to the directory entry MOV M,E ;save in the group low byte JMP DSKW04 ;and jump over ; DSKW03: MOV C,A ;save the extblk byte into C MVI B,0 ;zero out B DAD B ;slide the offset DAD B ; right 2 bits MOV M,E ;put the group low byte into place INX H ;point to the high byte MOV M,D ;and put this in too DSKW04: MVI C,02H ;set the exit code DSKW05: LDA ODATA ;and the exit data ORA A ;see if it is zero RNZ ;return if not PUSH B ;otherwise save the extent block pointer CALL COMSEC ;go compute the sector LDA DCODE ;get the disk code out DCR A ;count it DCR A ; down 2 JNZ DSKW08 ;if not zero jump over POP B ;recover the block offsct the byte from the FCB INX H ;point to the R1 byte MOV A,B ;put B in A SBB M ;subtract with borrow from here as well INX H ;once more with the overflow byte MOV A,E ;E into A SBB M ;subtract the overflow JC GETSZ1 ;if carry jump over - file is too big MOV M,E ;put R2 into place DCX H ;point back MOV M,B ;set R1 in as well DCX H ;back again MOV M,C ;and set R0 into place GETSZ1: CALL SERCHN ;go look for next extent JMP GSLOOP ;loop until we hit the end ; GSEXIT: POP H ;recover the address of random file size RET ;and return with it ; ;****************************************************************************** ; BDOS function 36 - set random record with data set by RANFIL ; SETRND: LHLD FCB ;get the FCB address LXI D,32 ;and the offset to the record count CALL COMREC ;get the file pointers into A b and c LXI H,33 ;offset to the R0 byte DAD D ;point to it MOV M,C ;put the byte in C into R0 INX H ;point to R1 MOV M,B ;put B in there INX H ;point to overflow byte MOV M,A ;stuff A there RET ;and return ; ;****************************************************************************** ;routine to log the selected disk ; LOGDSK: LHLD DLOG ;point to the login vector LDA CURDSK ;get the current disk byte MOV C,A ;and put it into C CALL SPINHL ;spin the selected disk bit into place PUSH H ;save this vector on the stack XCHG ;careful study says this is useless CALL DISKID ;go get the disk information set POP H ;recover the vector CZ PTSERR ;if trouble say so and quit MOV A,L ;otherwise put the low byte into A RAR ;slide it right bit 0 into carry RC ;return if bit was set - we already got it LHLD DLOG ;otherwise point to the login vector MOV C,L ;put the vector MOV B,H ; into BC CALL SETDBT ;set the disk bit using setro SHLD DLOG ;save the vector into place again JMP GETAL ;get the new allocation vector ; ;****************************************************************************** ; BDOS function 14: select disk ; enter with selected disk in IDATA ; LOGIN: LDA IDATA ;get the disk to log LXI H,CURDSK ;point to the current disk storage CMP M ;are they the same RZ ;return if so MOV M,A ;otherwise make this current JMP LOGDSK ;and log it in then return ; ;****************************************************************************** ;routine to select disk indicated in FCB drive code ; RSELCT: MVI A,0FFH ;get an FF STA OUT1 ;save it to force disk reset on exit LHLD FCB ;point to the FCB MOV A,M ;pull in the new drive code ANI 1FH ;strip off the user bits DCR A ;decrement to make it right STA IDATA ;save it for the login routines CPI 1EH ;is it too big JNC XIT ;if so go back LDA CURDSK ;get the current disk out STA OUTDSK ;save it for the return MOV A,M ;pull in the new code again STA OLDDSK ;save the value as the olddisk ANI 0E0H ;strip off the drive bits MOV M,A ;put the user bits back CALL LOGIN ;go log the new disk XIT: LDA USRCOD ;get the user code out LHLD FCB ;point back to the FCB ORA M ;set in the new user code bits MOV M,A ;and put the result back RET ;then return ; ;****************************************************************************** ;BDOS function 12: routine returns CP/M version in A ; GETVER: MVI A,22H ;say this is CP/M version 2.2 JMP GOBAK ;and return ; ;****************************************************************************** ; BDOS function 13: routine to reset the system disk ; RESET: LXI H,0 ;get ready to reset the vectors SHLD ROVEC ;set both read only bits SHLD DLOG ; and login bits to off XRA A ;zero A STA CURDSK ; and make it the current disk LXI H,TBUFF ;Set DMA addr to 80H SHLD DMAADR ;save this as the new DMA value CALL SETDMA ;make it so for real JMP LOGDSK ;go log in drive A and return ; ;****************************************************************************** ; BDOS function 15: open file ; enter with FCB address in HL and INFO ; exit with directory code in A ; OPEN: CALL ZS2 ;set S2 to zero for the new file CALL RSELCT ;select the right disk JMP OPENF ;then open the file in the FCB ; ;****************************************************************************** ; BDOS function 16: close the selected file ; enter with FCB address ; exit with directory code in A ; CLOSE: CALL RSELCT ;select the right drive JMP CLOSEF ;and finish off the close operation ; ;****************************************************************************** ; BDOS function 17: search for first file entry ; enter with FCB address ; exit with directory code in A ; SEAR1: MVI C,0 ;set the search code into C XCHG ;swap FCB into DE MOV A,M ;pull in the file name byte CPI '?' ;is it a wild card JZ SRF2 ;if so jump over CALL GETEX ;otherwise get the extent MOV A,M ;pull in the byte here CPI '?' ;is it a wild card CNZ ZS2 ;if not set S2 to 0 CALL RSELCT ;select the right drive MVI C,0FH ;look at name thru S2 byte SRF2: CALL SEARCH ;search for the file JMP MOVSEC ;jump to move the sector and return ; ;****************************************************************************** ;BDOS function 18: search for next directory entry ; enter with FCB set as before ; exit with directory code in A 255 says not found ; SEARN: LHLD SEARA ;get the last search FCB out SHLD FCB ;save this as the FCB CALL RSELCT ;select the right drive CALL SERCHN ;then search for the nex extent JMP MOVSEC ;move the sector and return ; ;****************************************************************************** ; BDOS function 19: delete file ; enter with FCB address set ; exit with directory code in A ; DELETE: CALL RSELCT ;select the right drive CALL DELETF ;delete the indicated file JMP RETCOD ;set the return code and go back ; ;****************************************************************************** ; BDOS function 20: read sequential ; enter with FCB address ; exit with directory code in A ; READ: CALL RSELCT ;select the indicated drive JMP DSKRED ;and go read the disk ; ;****************************************************************************** ; BDOS function 21: write sequential ; enter with FCB address ; exit with directory code in A ; WRITE: CALL RSELCT ;select the drive JMP DSKWRT ;and go write the disk ; ;****************************************************************************** ; BDOS function 22: make new file entry ; enter with FCB ; exit with directory code in A ; CREATE: CALL ZS2 ;zero out S2 CALL RSELCT ;select the drive JMP MAKE ;and make a new directory entry ; ;****************************************************************************** ; BDOS function 23: rename file ; enter with FCB address ; exit with directory code in A ; RENAME: CALL RSELCT ;select the drive CALL RENAMF ;and go rename the file JMP RETCOD ;set the return code and exit ; ;****************************************************************************** ; BDOS function 24: return login vector ; exit with login vector in HL ; GLOGIN: LHLD DLOG ;get the login vector out JMP RETHL ;return with it ; ;****************************************************************************** ; BDOS function 25: return current disk ; exit with current disk in A ; GETDRV: LDA CURDSK ;get the current disk out JMP GOBAK ;and go back with it ; ;****************************************************************************** ; BDOS function 26: set DMA address ; enter with DMA address set ; DMASET: XCHG ;save the new address into HL SHLD DMAADR ;save it into place JMP SETDMA ;then make it true ; ;****************************************************************************** ; BDOS function 27: get allocation vector address ; return address in HL ; GALLOC: LHLD ALLOCA ;get the allocation vector out JMP RETHL ;and go back with it ; ;******************************************************************************VOLUME CP/M MISC DESCRIPTION: MISC. CP/M PATCHES, DISASSEMBLED PARTS,... NUMBER SIZE NAME COMMENTS CATALOG.DOC THIS CATALOG FILE 10K DCON11.COM ENHANCED CP/M DEBUGGER BASED ON "SID" 15K DCON11.DOC DOCUMENT FILE FOR ABOVE PROGRAM 7K ZDT.COM VERSION OF DDT.COM THAT WILL DISASSEMBLE WITH TDL Z-80 MNEMONICS IF USED ON A Z80 2K ZDT.DOC A SHORT DOCUMENT FILE FOR ZDT.COM. 2K DDTX.ASM A PROGRAM TO LOAD DDT BELOW CCP (NO OVERLAY) 28K CCP22.ASM A DISASSEMBLY OF THE CP/M 2.2 CCP. 2K BDOS22.PAT A PATCH TO THE CP/M 2.2 BDOS TO MAKE USER 0 SUBDIRECTORY "PUBLIC". 1K CCPPATCH.ASM A PATCH TO THE CP/M 2.2 CCP TO ADD SEVERAL FEATURES. 51K CCPZ-V41.ASM A Z-80 VERSION OF THE CP/M 2.2 CCP WITH A NUMBER OF ENHANCEMENTS. 39K CCPZ-V40.DOC A DOCUMENT FILE FOR THE ABOVE PROGRAM. 17K CCPZ-V41.NOT ANOTHER DOCUMENT FILE 13K CCPZ27.HLP A SUMMARY OF THE NEW FEATURES 9K CPMFILE.DOC A DESCRIPTION OF THE CP/M FILE DIRECTORY STRUCTURE 11K INCPM.DOC SOME COMMENTS ON THE "INSIDES" OF CP/M 1.4.  ;Last unallocated disk unatrk: ds 1 ;Last unallocated track unasec: ds 1 ;Last unallocated sector erflag: ds 1 ;Error flag rsflag: ds 1 ;Read sector flag readop: ds 1 ;Read=1 Write=0 wrtype: ds 1 ;Write operation type dmaadr: ds 2 ;Disk DMA transfer address ramsel: ds 1 ;Local disk selected flag endz equ $ ;End of zeroed memory Š; Host data buffer memory area hstbuf: ds hstsiz ;Host buffer storage ; Scratch area for BDOS use endef ;Let DISKDEF set up BDOS buffers end åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå TITLE 'CP/M Console Command Processor (CCP) Vers 2.2' ; Refer to CCP 1.4 disassembly listing for comments ; This current file is not completely commented. FALSE EQU 0 TRUE EQU NOT FALSE ABORT$LOC EQU 0F000H PAGE1$DRV EQU 04H BDOS EQU 05H TPA EQU 100H ACR EQU 0DH ALF EQU 0AH UC$MASK EQU 5FH BIAS EQU 40H DEF$DMA$LOC EQU 80H REC$LENGTH EQU 80H TRANS$FCB EQU 5CH SECOND$NAME EQU TRANS$FCB+10H NAME$OFFSET EQU 01 TYPE$OFFSET EQU 09 ATTR$OFFSET EQU 10 NAME$LEN EQU 08 TYPE$LEN EQU 03 CPM$EOF EQU 1AH ; The following 'REL' equates are to allow generation ; of page 0 and page 1 .HEX files, used to create ; relocation bit tables in programs like MOVCPM.COM REL EQU TRUE ; set true to generate relocatable code IF REL CCPBIAS EQU 0 ; set 0 for "0K" system ENDIF IF NOT REL MSIZE EQU 56 ; current memory configuration CCPBIAS EQU (MSIZE-20)*1024+2D00H ; starting address of CCP ENDIF ; CCP starts here ORG CCPBIAS CCP$LEN EQU 800H BDOS$START EQU $+CCP$LEN CCP: JMP START ; cold entry point to CCP JMP ALT$START ; warm entry point to CCP ; CCP command buffer MAX$LN: DB 7FH ; maximum buffer capacity CHARS$TYPED: DB 0 ; number char's typed CON$BUF: ; command buffer starts here DB ' ' DB 'COPYRIGHT (C) 1979, DIGITAL RESEARCH ' DS 4AH ; ; Next 2 labels are storage loc'ns used to ; temporarily store the loc'n of the next ; char in the console buffer to be processed. ; NXTCHR: DW CON$BUF NEXT1: DW 0000 ; ; Send character in to console output ; PUT$CON: MOV E,A MVI C,2 JMP BDOS ; ; Save and send char in to console ; PUT1$CON: PUSH B CALL PUT$CON POP B RET ; ; Send CR, LF to Console ; CRLF: MVI A,ACR CALL PUT1$CON MVI A,ALF JMP PUT1$CON ; ; Send blank to console ; SPACE: MVI A,' ' JMP PUT1$CON ; ; Precede ascii string print with crlf ; PUT$MSG: PUSH B CALL CRLF POP H ; ; Send Ascii string to console ; Address of string in ; String terminated by 0 ; PUT1$MSG: MOV A,M ORA A RZ INX H PUSH H CALL PUT$CON POP H JMP PUT1$MSG ; ; Initialize BDOS, selects drive 'A' and ; sets dma address to 80H ; Reset Disk System ; INIT$BDOS: MVI C,0DH JMP BDOS ; ; Log in and select drive no. passed in ; LOG$ACC:MOV E,A MVI C,0EH JMP BDOS ; ; Call to BDOS, =dir/err code ; BDOS$R: CALL BDOS STA DIR$ADDR ; save byte address in directory ; of fcb at location INR A ; set zero flag if 0FFH returned RET ; ; Open File =dir Code ; =fcb ; OPEN$FILE: MVI C,0FH JMP BDOS$R ; ; Routine opens file, fcb=default fcb ; of ccp ; OPEN$CCP: XRA A ; set next record.. STA CCP$FCB$NXT$REC ; .. equal to zero LXI D,CCP$FCB JMP OPEN$FILE ; ; Close File =dir Code ; =fcb ; CLOSE$FIL: MVI C,10H JMP BDOS$R ; ; Search for first =dir Code ; =fcb ; SEARCH: MVI C,11H JMP BDOS$R ; ; Search for next ; =fcb ; SEARCH$NXT: MVI C,12H JMP BDOS$R ; ; Search directory for next occurrance of ; file whose fcb address in ; FIND$CCP: LXI D,CCP$FCB JMP SEARCH ; ; Delete File =fcb ; =dir Code ; DELETE$FIL: MVI C,13H JMP BDOS ; ; Call BDOS, =return code ; BDOS$E: CALL BDOS ORA A ; set flags RET ; ; Read next record =err code ; =fcb ; READ$NXT: MVI C,14H JMP BDOS$E ; ; Read next record of file in default fcb ; READ$CCP: LXI D,CCP$FCB JMP READ$NXT ; ; Write next =err code ; =fcb ; WRITE$NXT: MVI C,15H JMP BDOS$E ; ; Make file =dir code ; =fcb ; MAKE$FILE: MVI C,16H JMP BDOS$R ; ; Rename file =dir code ; =fcb ; REN$FIL: MVI C,17H JMP BDOS ; ; Get/Set user code ; =0ffh (get) ; =user code (set) ; =current code ; GETUSR: MVI E,0FFH ; set =0FFH to get user no. SETUSR: MVI C,20H ; set =function number JMP BDOS ; ; Get current user number and shift up to high nybble, ; logically OR with current drive, and save this in ; location 4 for system use. ; SET4: CALL GETUSR ; get current user code ADD A ; *2 ADD A ; *4 ADD A ; *8 ADD A ; *16 (shift left 8 bits) LXI H,CUR$DRV ; get current drive no. ORA M ; OR with user code STA PAGE1$DRV ; and save it for system use RET ; ; Get current drive no. and save it in 4 ; INIT4: LDA CUR$DRV ; get current drive no. STA PAGE1$DRV ; store in 4 RET ; ; Convert lower case alpha character to UPPER ; UPRCASE:CPI 61H ; return if already RC ; upper case CPI 7BH RNC ANI 5FH ; make UPPER case RET ; ; If no submit is in progress, this routine will get ; a new command line from the console, convert it to ; upper case, put a null char at the end, and initialize ; next$char to point to start of console buffer. ; ; If a submit is in progress, the next record of the submit ; file is loaded into the console buffer and executed as a ; command string. ; GET$CMD: LDA STK$TOP ; get submit status flag ORA A ; set flags JZ FIL$BUF ; no submit in progress, get cmd string LDA CUR$DRV ; get current drive ORA A ; set flags MVI A,0 ; set A=0 without changing flags CNZ LOG$ACC ; make drive A if not already A LXI D,SUB$FCB ; point to $$$.SUB fcb CALL OPEN$FILE ; open the submit file JZ FIL$BUF LDA SUB$REC$CNT ; get current record count DCR A ; in current extent, decrement it STA SUB$FCB$NXT$REC ; ..save it as next record to read LXI D,SUB$FCB ; point to $$$.SUB fcb again CALL READ$NXT ; read next record JNZ FIL$BUF ; if not zero, then error, so get ; command string from console buffer LXI D,CHARS$TYPED ; point to console buffer LXI H,DEF$DMA$LOC ; source DEFAULT buffer MVI B,REC$LENGTH ; 128 bytes CALL MOV$HL2DE ; move sector just read to console ; buffer LXI H,SUB$FCB+10H MVI M,0 INX H DCR M LXI D,SUB$FCB CALL CLOSE$FIL ; CLOSE the file JZ FIL$BUF LDA CUR$DRV ; get current drive ORA A ; set status CNZ LOG$ACC ; reset if not A LXI H,CON$BUF CALL PUT1$MSG ; print the command CALL GET$IF ; check forAME: DB 'DIR ' DB 'ERA ' DB 'TYPE' DB 'SAVE' DB 'REN ' DB 'USER' ; ; CCP Serial Number and Version ; CCP$SN: DB 00,00 ; type & version number DB 00,00,00,00 ; serial number ; ; Search for CP/M command ; Return =index to vector table ; LOOK$CMD: LXI H,CMD$NAME ; get addr of ccp commands MVI C,0 ; preset counter LOOK2$CMD: MOV A,C ; get counter CPI 6 ; finished? RNC ; yes, if no match after 6 bytes LXI D,CCP$FCB+1 MVI B,4 LOOK1$CMD: LDAX D CMP M JNZ FAIL INX D INX H DCR B JNZ LOOK1$CMD LDAX D CPI ' ' JNZ TRY$AGN MOV A,C RET ; FAIL: INX H DCR B JNZ FAIL TRY$AGN: INR C JMP LOOK2$CMD ; ; If entered here, set the command string length to zero ; to avoid executing whatever may be in the buffer ; ALT$START: XRA A ; set command length STA CHARS$TYPED ; to zero ; ; Normal entry point to CCP. Initialize the stack, initialize ; the BDOS, log-in the drive number which was in register C ; upon entry, go see if a submit is in progress (if INIT$BDOS ; returns 0FFH in acc and drive to log-in is zero, then a submit ; is taking place), and finally see if CHARS$TYPED is non-zero ; (if non-zero a command string waits, so go do it) ; START: LXI SP,STK$TOP ; init stack PUSH B ; save entry parm MOV A,C ; get user/drive parm RAR ; get high order nibble RAR ; moved into low nibble RAR RAR ANI 0FH ; strip off high 8 bits MOV E,A CALL SETUSR ; and set it CALL INIT$BDOS ; reset the disk system STA STK$TOP POP B ; pop entry parm MOV A,C ; get user/drive code ANI 0FH ; strip off high nibble STA CUR$DRV ; and save it in locn 4 CALL LOG$ACC ; select the drive LDA CHARS$TYPED ; check if command buffer ORA A ; has anything in it JNZ DO$CMD ; if so, goto DO$CMD ; ; Prompt the user and get a command string ; PROMPT: LXI SP,STK$TOP CALL CRLF ; new line CALL GET$DRV ADI 'A' ; add ascii bias CALL PUT$CON ; print current disk MVI A,'>' ; print arrow prompt CALL PUT$CON CALL GET$CMD ; ; Execute the command string in the console buffer ; DO$CMD: LXI D,DEF$DMA$LOC ; set default DMA address CALL SET$DMA CALL GET$DRV ; get current disk STA CUR$DRV ; store it CALL MAKE$FCB CNZ ECHO$BUF LDA NEW$DRV$PLUS ORA A JNZ USERCOMMAND CALL LOOK$CMD ; check if non-transient command LXI H,JMP$TBL ; get table address MOV E,A ; and command index MVI D,0 DAD D DAD D ; and compute position in table MOV A,M INX H MOV H,M MOV L,A PCHL ; go do it! ; ; Address table to resident CCP commands ; and to the user command routine ; JMP$TBL: DW DIRECTORY DW ERASE DW TYPE DW SAVE DW RENAME DW USER DW USERCOMMAND ; ; Write a permanent error jump at the entry ; point to the CCP and then exit ; GET$LOST: LXI H,ABORT$LOC SHLD CCP+1 LXI H,CCP PCHL ; ; Display read error message ; DO$RERR: LXI B,RERR$MSG ; get string address JMP PUT$MSG ; RERR$MSG: DB 'READ ERROR',0 ; ; Display 'NO FILE' error message ; DO$NFERR: LXI B,NFERR$MSG JMP PUT$MSG ; NFERR$MSG: DB 'NO FILE',0 ; ; Calculate binary number of records (256 bytes each) ; to be written by the SAVE command (return with the ; count in ) ; CALC$BIN$SEC: CALL MAKE$FCB LDA NEW$DRV$PLUS ORA A JNZ ECHO$BUF LXI H,CCP$FCB+1 LXI B,0BH CALC$LOOP: MOV A,M CPI ' ' JZ CONFIRM$SPC INX H SUI '0' CPI 0AH JNC ECHO$BUF MOV D,A MOV A,B ANI 0E0H JNZ ECHO$BUF MOV A,B RLC RLC RLC ADD B JC ECHO$BUF ADD B JC ECHO$BUF ADD D JC ECHO$BUF MOV B,A DCR C JNZ CALC$LOOP RET ; ; Confirm that only spaces remain following the number ; of records to be saved (the ascii number of decimal ; records was set up in the fcb by MAKE$FCB as if it ; were a filename) ; CONFIRM$SPC: MOV A,M CPI ' ' JNZ ECHO$BUF INX H DCR C JNZ CONFIRM$SPC MOV A,B RET ; ; If entered here, routine will move 3 characters from ; address in to address in ; MOV3$HL2DE: MVI B,3 ; set for 3 bytes ; ; Move routine: ; Source addr=, Destination addr= ; Number of bytes to move in ; MOV$HL2DE: MOV A,M ; get source byte STAX D ; move to dest INX H ; bump source addr INX D ; bump dest addr DCR B ; bump byte count JNZ MOV$HL2DE ; continue til finished RET ; ; Get the relative character (acc = offset) from the ; directory entry whose converted byte address is in ; the register (used by DIR command) ; CALC$DIS$GET: LXI H,80H ADD C CALL ADD$ACC MOV A,M RET ; ; Set the entry type of the CCP$FCB equal to ; zero and then execute the LOG$DRV$MYST routine ; SET$ET$DRV: XRA A STA CCP$FCB LDA NEW$DRV$PLUS ORA A RZ DCR A LXI H,CUR$DRV CMP M RZ JMP LOG$ACC ; ; If drive was specified in the command string and if ; the specified drive is different from the ; current drive, go log the current drive back in ; LOG$CUR$DRV: LDA NEW$DRV$PLUS ORA A RZ DCR A LXI H,CUR$DRV CMP M RZ LDA CUR$DRV JMP LOG$ACC ; ; DIRectory command of the Console Command Processor ; DIRECTORY: CALL MAKE$FCB CALL SET$ET$DRV LXI H,CCP$FCB+1 MOV A,M CPI ' ' JNZ FILE$NAME$N$DIR MVI B,0BH PUT$N$DIR: MVI M,'?' INX H DCR B JNZ PUT$N$DIR FILE$NAME$N$DIR: MVI E,0 PUSH D CALL FIND$CCP CZ DO$NFERR DIR$DO$LOOP: JZ FINISH$DIR$CMD LDA DIR$ADDR RRC RRC RRC ANI 60H MOV C,A MVI A,0AH ; get file attribute bit CALL CALC$DIS$GET ; which is MSB of 10th byte RAL ; rotate MSB into CY JC DIR$SKIP$ALL ; don't display if set ($SYS) ; ; Print 4 directory entries per line ; POP D ; get directory entry address MOV A,E ; move LSbyte to acc INR E ; bump the address PUSH D ; push address back on stack ANI 3 ; look at 2 LSbits PUSH PSW ; save this too JNZ PUT$FENCE ; don't print drive unless ; this is 1st filename on line CALL CRLF PUSH B CALL GET$DRV POP B ADI 'A' CALL PUT1$CON MVI A,':' CALL PUT1$CON JMP SKIP$FENCE ; don't print the fence ; ; Print 'Fence' character between filenames ; PUT$FENCE: CALL SPACE MVI A,':' CALL PUT1$CON SKIP$FENCE: CALL SPACE MVI B,1 DIR$NXT$CHAR: MOV A,B CALL CALC$DIS$GET ANI 7FH CPI ' ' JNZ DIR$CON$OUT POP PSW ; get LSbits of address again PUSH PSW ; save them back CPI 3 ; JNZ A61F7 MVI A,9 CALL CALC$DIS$GET ANI 7FH CPI ' ' JZ DIR$KEY$LOOK A61F7: MVI A,' ' DIR$CON$OUT: CALL PUT1$CON INR B MOV A,B CPI 0CH JNC DIR$KEY$LOOK CPI 9 JNZ DIR$NXT$CHAR CALL SPACE JMP DIR$NXT$CHAR ; DIR$KEY$LOOK: POP PSW DIR$SKIP$ALL: CALL GET$IF JNZ FINISH$DIR$CMD CALL SEARCH$NXT JMP DIR$DO$LOOP ; FINISH$DIR$CMD: POP D JMP CMD$END ; ; ERAse file command of the Console Command Processor ; ERASE: CALL MAKE$FCB CPI 0BH JNZ ERASE1 LXI B,ALL$MSG CALL PUT$MSG CALL GET$CMD LXI H,CHARS$TYPED DCR M JNZ PROMPT INX H MOV A,M CPI 'Y' JNZ PROMPT INX H SHLD NXTCHR ERASE1: CALL SET$ET$DRV LXI D,CCP$FCB CALL DELETE$FIL INR A CZ DO$NFERR JMP CMD$END ; ALL$MSG: DB 'ALL (Y/N)?',0 ; ; TYPE file command of the Console Command Processor ; TYPE: CALL MAKE$FCB JNZ ECHO$BUF CALL SET$ET$DRV CALL OPEN$CCP JZ CANT$TYPE CALL CRLF LXI H,REL$BUF$CNT MVI M,0FFH TYPE$DO$LOOP: LXI H,REL$BUF$CNT MOV A,M CPI 80H JC NOT$END PUSH H CALL READ$CCP POP H JNZ TYPE$DONE XRA A MOV M,A NOT$END: INR M LXI H,DEF$DMA$LOC CALL ADD$ACC MOV A,M CPI 1AH JZ CMD$END CALL PUT$CON CALL GET$IF JNZ CMD$END JMP TYPE$DO$LOOP ; TYPE$DONE: DCR A JZ CMD$END CALL DO$RERR CANT$TYPE: CALL LOG$CUR$DRV JMP ECHO$BUF ; ; SAVE file command of the Console Command Processor ; SAVE: CALL CALC$BIN$SEC PUSH PSW CALL MAKE$FCB JNZ ECHO$BUF CALL SET$ET$DRV LXI D,CCP$FCB PUSH D CALL DELETE$FIL POP D CALL MAKE$FILE JZ DISP$NSERR XRA A STA CCP$FCB$NXT$REC POP PSW MOV L,A MVI H,0 DAD H LXI D,TPA WRITE$LOOP: MOV A,H ORA L JZ CLOSE$THE$SAV DCX H PUSH H LXI H,80H DAD D PUSH H CALL SET$DMA LXI D,CCP$FCB CALL WRITE$NXT POP D POP H Documentation on new features of CCPZ vers 2.7 ---------------------------------------------- CCPZ version 2.7 is completely compatible with the preceding version 2.6, but contains an additional command (GO), an alternate method of setting the CCPLOC equate value with two new symbols (MSIZE and BIOSEX), and an additional customization equate (FENCE). To provide additional space for implementing the GO command, some furthur jump optimization was performed in various places in the code. In addition, changes were made to the Z80 branch macros for esthetic reasons and to provide more information if a "branch out of range" error occurred. Specifically, a V(alue) error was forced to get MAC to print out the current location counter value to help locate the exact jump that was out of range. The release CCP and CCPZ version 2.6 do not reset the default DMA address after calling a program in the TPA (or elsewhere for CCPZ). As a result, if the called program changes the DMA address, and CCP is in a SUBMIT run, the next read on the SUBMIT file will NOT go into the default buffer as desired, but SOMEWHERE ELSE! Funny cases surrounding the use of STAT in a SUBMIT run can usually be traced to this bug. CCPZ version 2.7 has this problem corrected. New GO command -------------- CCPZ version 2.6 supports a JUMP command which has the capability of "calling" a program anywhere in memory. Certain serially re-entrant programs like STAT can be "used again" after having been run once by issuing the command "JUMP 100 ", where are legitimate input on the command line to be passed to STAT. This command has the same effect as issuing the command "STAT ", without loading a new copy of STAT from the disk. Many popular directory programs also may be used in this way. Using the above form of the JUMP command may be recognizable to users of the old IMSAI IMDOS system, as it is equivalent to the IMDOS "GO" command. However, as described in the program source and implementation notes, the potentially-disastrous JUMP command may be undesirable for remote CP/M system usage, and can be disabled with the RAS option. It is for this reason and for convenience that CCPZ version 2.7 contains an IMDOS-style "GO " command, exactly equivalent to the "JUMP 100 " command described above, but not subject to being disabled by the RAS option, since there is no reason to do so. Alternate CCPLOC value determination ------------------------------------ The implementation notes describe how an earlier version of CCPZ contained system parameters for determining the value of CCPLOC, and that these were deleted along the way in favor of just using a program called BDOSLOC to determine the current location of the user's CCP. This value could then be used as the value of the CCPLOC symbol. That is fine for the committee that came up with that decision. The implementer of the version 2.7 changes feels that while that may be adequate for them, others desire the documentation inherent in relating CCPLOC to actual system parameters. The source now contains the following to allow either method to be used: ; ; If REL is FALSE, the value of CCPLOC may be set in one ; of two ways. The first way is to set MSIZE and BIOSEX ; as described above, using the following three lines: ; MSIZE EQU 56 ;SIZE OF MEM IN K-BYTES BIOSEX EQU 1 ;EXTRA # K-BYTES IN BIOS CCPLOC EQU 3400H+(MSIZE-20-BIOSEX)*1024 ;CCP ORIGIN ; ; The second way is to obtain the origin of your current ; CCP using BDOSLOC or its equivalent, then merely set CCPLOC ; to that value, as in the following line: ; ;CCPLOC EQU 0C000H ;FILL IN WITH BDOSLOC-SUPPLIED VALUE ; ; Note that you should only use one method or the other. ; Do NOT define CCPLOC TWICE! ; Either CCPLOC equate will define the origin of CCPZ in a 56K system where the BIOS is 1K larger than the standard Digital Research release BIOS. Note that a semi-colon was placed in front of the second CCPLOC equate line, which was unused. By deleting the semi-colon, and setting the value to that supplied by BDOSLOC, that line would be valid, and the first CCPLOC equate line should then have a semi-colon inserted at its front instead. Directory file name separater (FENCE) ------------------------------------- For those people who prefer another character to the colon that was used to separate file names on the DIR and ERA reports, the FENCE symbol may be equated to the character of their choice. A popular alternative is the vertical bar ("|") symbol, and is in fact the value of FENCE in CCPZ version 2.7. For those who disagree with that choice, FENCE may be set to the colon or any other character. Colon and vertical bar are the usual choices. åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå; ; CCPZ V2.7 ; ;**** Revision History **** ; ; MODS BY SBB 08/01/81: ; 1) MINOR ADDITIONAL CODE OPTIMIZATIONS TO GAIN A BIT MORE SPACE. ; 2) ADDED "GO" COMMAND FOR COMPATIBILITY WITH MANY OTHER CCP'S. ; SAME AS "JUMP 0100", BUT IS NOT A "RAS" COMMAND (NO REASON ; IT SHOULD BE). ; 3) PUT "RESETUSER" CALL MADE JUST AFTER "CALLPROG" BACK INTO ; "MEMLOAD" WHERE IT BELONGS TO PREVENT FUNNY USER NUMBER ; CHANGING AFTER CALLED PROGRAM RETURNS. "MEMLOAD" WAS THE ; REASON FOR "RESETUSER" ANYWAY. ; 4) RESET DEFAULT DMA BUFFER WITH "DEFDMA" RIGHT AFTER CALLED ; PROGRAM RETURNS. THIS IS THE REASON PROGRAMS LIKE "STAT" ; WILL MESS UP A "SUBMIT" RUN. FIX THIS IN ANY OTHER CCP ; YOU RUN INTO. ; 5) DEFINED "FENCE" EQUATE TO ALLOW SEPARATION CHAR IN DIR ; TO BE SET TO TASTE (":" OR "|" ARE TYPICAL). ; 6) PUT IN SYSTEM SIZE (MSIZE) AND EXTRA BIOS SIZE (BIOSEX) ; EQUATES FOR CCPLOC CALCULATION, IN CASE USER KNOWS THOSE ; AND DOESN'T HAVE BDOSLOC. IF BDOSLOC IS AROUND, ITS SUPPLIED ; VALUE IS EASILY INSERTED INSTEAD. ; ; MODS BY RLC 07/29/81: ; 1) CODE COMPRESSION MADE BY FJW AND MENTIONED IN HIS MESSAGE ; OF THIS DATE INCORPORATED ; 2) HEXNUM (HEXADECIMAL NUMBER INPUT ROUTINE) EXTENDED TO ALLOW ; 16-BIT VALUES; GET AND JUMP CORRESPONDINGLY MODIFIED, AS WELL ; AS DEC NUMBER ROUTINE FOR HEX ESCAPE ; 3) DEFAULT HEX VALUE IS NOW ZERO (NOT 1 AS BEFORE) ; 4) ADDITIONAL PARSE CHECKING IN USER ROUTINE REMOVED; USER WITHOUT ; AN ARGUMENT NOW DROPS THE USER INTO USER NUMBER 0 ; ; MODS BY RLC 07/27/81: ; 1) ESCAPE FROM DEC TO HEX INSTALLED AND ESCAPE FROM HEX TO ; DEC REMOVED; THIS REFERS TO THE '#' CHAR WHICH IS USED TO ; CHANGE NUMBER BASES; Change as per group discussion ; 2) SAVE CHANGED TO DEFAULT TO DEC AS NUMBER ARGUMENT; ORIGINAL ; FORM OF SAVE COMMAND EFFECTIVELY RESTORED; Change as per group ; discussion ; ; MODS BY RLC 07/20/81: ; 1) RADICAL RESTRUCTURING AND ADDITIONAL DOCUMENTATION ; 2) REMOVED MOST SYSTEM-RELATIVE CONDI give room to implement the additional functions ; H. The input line buffer has been reduced in size to 100 bytes ; I. The ERA Command displays the names of the files it is to ; erase ; J. The DIR Command has an additional special form of "DIR @" ; which displays all files (both non-system and system), ; while "DIR" displays just the non-system files ; K. The Directory Display no longer displays the disk name at ; the beginning of each line and it now includes a '.' between ; the file name and file type (FILENAME.TYP) ; L. The SUBMIT File Facility now expects the $$$.SUB file to be ; on the currently logged-in disk (as opposed to always A:) ; M. The Command Line Prompt is now '$' if the command comes from ; a $$$.SUB file and '>' if the command comes from the user; ; also, the '>' is not printed until all preprocessing is ; completed ; N. The TYPE and LIST Commands mask the MSB of each byte, so that ; files created by editors such as EDIT80 are "printable" ; ;**** End of Revision History **** ; åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå.po 4 .he CCPZ - A Z80 Version of the CP/M CCP .fo Page # Documentation on CCPZ - A Z80 Version of the CP/M CCP CCPZ is a Group Project By RLC, FJW, KBP, RGF, RJM, SBB CCPZ Documentation By RLC Table of Contents ----- -- -------- Introduction 2 Part A: Installation Instructions 4 CCPZ Integration Example 5 Setting the CCPZ Inline Options 8 REL, BASE, CCPLOC, RAS 8 Customization Symbols 8 NLINES, WIDE, PGDFLT 8 PGDFLG, MAXUSR, SYSFLG, SOFLG, SUPRES, DEFUSR, SPRMPT, CPRMPT, NUMBASE, 9 SECTFLG, FENCE 10 Part B: Usage Instructions and Explanation of Commands 11 The CCPZ Command Hierarchy Search 11 The CCPZ-Resident Commands 13 DIR, ERA 13 LIST, TYPE, SAVE, REN 14 USER, DFU, JUMP, GO 15 GET 16 CCPZ Error Messages 17 Documentation on CCPZ - A Z80 Version of the CP/M CCP CCPÚ  ió  basicallù á rewritå oæ thå  CP/Í  Consolå  Commanä Processoò  (CCP© whicè ió designeä tï ruî aó parô oæ CP/Í oî Z80- baseä microcomputers® Iî mosô caseó iô ió upward-compatablå witè thå originaì CP/Í Versioî 2.² CCP. CCPZ¬  however¬  provideó  manù extensionó tï thå CP/Í  CCP® Amonç theså are: ® Thå TYPÅ functioî caî bå madå tï pagå oò noô pagå itó outpuô aô thå user'ó discretion ®  Á LISÔ functioî ió availablå whicè sendó itó  outpuô tï thå CP/Í LSTº Devicå anä doeó NOÔ page ®  Thå  DIÒ commanä haó beeî extendeä tï allo÷ thå dis plaù oæ thå systeí fileó oò alì files ® Thå ERÁ commanä no÷ printó ouô thå nameó oæ thå fileó iô ió erasing ®  Thå  currenô useò numbeò maù bå includeä aó parô  oæ thå commanä prompt»  iæ thå useò ió undeò á numbeò otheò thaî  0¬ thå prompô ió oæ thå forí 'du>§ (likå 'A2>§ oò 'B10>')¬  and¬  iæ thå  useò ió undeò 0¬  thå prompô maù bå 'd>§ oò 'd0>§ aó peò hió choice ®  Thå  SUBMIÔ facilitù haó beeî changeä iî  twï  basiã ways: - thå  prompô  changeó tï 'du$§ oò 'd$§  wheî  thå SUBMIÔ commanä ió printed - thå  $$$.SU ió executeä froí thå currentlù log ged-iî disë (NOÔ jusô froí A:) ®  Á command-searcè hierarchù ió no÷ implementeä  whicè ió executeä roughlù aó follows: - thå  user'ó commanä ió checkeä againsô thå  CCP- residenô commandó anä executeä immediatelù iæ á matcè ió found - failinç  that¬  thå  currenô useò numbeò oî  thå currenô disë ió scanneä foò thå COÍ file»  thå COÍ filå ió loadeä anä executeä iæ found - failinç that¬ á defaulô useò numbeò (initiallù ° buô  caî bå reseô witè thå DFÕ CCP-residenô command© oî thå  cur renô disë ió scanneä foò thå COÍ file» thå COÍ filå ió loadeä anä executeä iæ found - finally¬  failinç that¬  thå defaulô useò numbeò oî disë Aº  ió scanneä foò thå COÍ file»  thå COÍ filå ió  loadeä anä executeä iæ founä oò aî erroò messagå (COMMAND?¬ wheî COMMANÄ waó thå user'ó commanä name© ió printed Š ®  Thå  numeriã  argumenô foò thå SAVÅ commanä caî  bå specifieä  iî hexadecimaì sï thaô thå useò maù emploù thå  valueó presented by tools such as DDT exactly as they are given ®  Á  GEÔ  commanä whicè loadó á filå  aô  á  specifieä memorù addresó anä á JUMÐ commanä whicè "calls¢ thå subroutinå aô á  specifieä memorù addresó havå beeî added»  á GÏ commanä  whicè "calls¢  thå  subroutinå aô 100È (subseô oæ thå JUMР capability© has also been added Thió  documenô provideó thå useò oæ CCPÚ witè thå  followinç information: Part A: Installation Instructions Part B: Usage Instructions and Explanation of Commands Part A Installation Instructions Iî  ordeò tï instalì CCPÚ oî á targeô microcomputeò (musô bå currently running CP/M 2.2), the user must know two basic things: 1) Where his CCP is currently running in memory 2©  Wherå hió CCÐ ió locateä iî thå SYSGEΠ image¬  or¬ foò systemó whicè don'ô supporô SYSGEÎ (sucè aó P&Ô CP/Í 2.²  foò thå TRS-8° Modeì II)¬ wherå hió CCÐ ió locateä oî disë anä ho÷ tï place the new CCPZ on top of it Thå  firsô questioî ió answereä relativelù easily®  Á  pro gram¬  knowî  aó eitheò BDOSLOà oò BDLOà (foò BDOÓ  Locator)¬  ió provideä  witè CCPZ®  Yoõ shoulä assemblå thió prograí foò  youò particulaò  computeò (changå thå baså ORÇ iæ yoõ arå runninç non- ORG-° CP/M© anä executå it®  Upoî execution¬ iô wilì providå yoõ witè  thå baså addresó oæ (1© thå BDOÓ anä (2© thå CCР foò  youò particulaò system®  BDOSLOà haó workeä correctlù foò alì systemó testeä sï far¬  buô therå ió alwayó á chancå thaô iô maù NOÔ worë foò somå non-testeä system®  Foò thå timå being¬  assumå thaô iô workó correctlù anä recorä thå startinç baså pagå addresó oæ youò CCP. Thå  seconä questioî ió answereä noô nearlù sï  easily®  Iæ yoõ  havå  thå abilitù tï SYSGEÎ youò system¬  iô ió mucè  easieò (commonly© thaî iæ yoõ dï not®  Yoõ must¬  afteò assemblinç  thå CCPÚ  properly¬  integratå iô intï thå sysgeî (oò disk© imagå  oæ CP/M®  Thió  caî  bå  donå bù obtaininç á SYSGEÎ imagå  oæ  youò system¬ scanninç iô viá á debuggeò sucè aó DDÔ tï finä thå offseô foò thå CCP¬  readinç thå ne÷ CCÐ iî oî toð oæ th Number of lines on the user's CRT for paging WIDE This equate is used to select a narrow or wide display under the DIR command; if WIDE is equated to TRUE, each file name is separated by two spaces, a FENCE, and two more spaces; if WIDE is equated to FALSE, each file name is separated by one space, a FENCE, and one more space PGDFLT This is the Paging Default flag for the TYPE command; if PGDFLT is set to TRUE, the TYPE command will page its output by default and the P option on the TYPE command (see below) will prohibit paging; if PGDFLT is set to FALSE, the TYPE command will NOT page its output by default and the P option will enable paging Š PGDFLG This sets the option character in the command line for the TYPE command (the 'P' mentioned above); if the user wishes to change this option character, he need only change this equate MAXUSR This is the largest user number recognized by the USER command; if the user wishes to protect the higher user areas, he may set this symbol to the highest area normally accessable SYSFLG This is the option character for the DIR command line which is used to specify that DIR search All Files (both $SYS and $DIR) for its display; the distributed default for this is 'A' SOFLG This is the option character for the DIR command line which is used to specify that DIR search ONLY the $SYS files for its display; the distri- buted default for this is 'S' SUPRES Set SUPRES to TRUE to suppress printing the user number when the user is under User Number 0 or set SUPRES to FALSE to ALWAYS display the User Number with the CCP prompt; with SUPRES set to TRUE, a user on B: in user 0 sees 'B>' as the prompt, but with SUPRES set to FALSE, a user on B: in user 0 sees 'B0>' as the prompt DEFUSR This is the CCP-default user number which is searched in the command hierarchy for the COM files (distributed as 0); the DFU changes this temporarily until a Warm Boot or Cold Boot is done, at which time the search reverts to this value SPRMPT This is the CCP prompt character which indicates that a SUBMIT file is in execution; by default it is set to '$', so prompts like 'A$' appear during SUBMIT file execution CPRMPT This is the CCP prompt character which indicates that the CCP is awaiting a user console command; by default it is set to '>', so prompts like 'A>' appear during user input to the CCP NUMBASÅ Thió ió thå escapå characteò useä bù thoså commands which require a DECIMAL number as an argument; placing this character after the number argument switches the base to HEXADECIMAL; for example, 'SAVE 15 MYFILE' can be expressed as 'SAVE FH MYFILE' if NUMBASE is set to 'H' (the default) Š SECTFLG This character constant is the suffix option for the SAVE command which specifies that sectors, as opposed to pages, are to be saved; the default value is 'S' FENCE This is the character printed to separate entries in a directory listing; it's default value is '|' Nï  otheò customizatioî ió necessarù unlesó thå useò  wisheó tï  changå  thå commandó disableä bù RAS®  Thió caî bå  donå  bù goinç tï thå commanä tablå 'CMDTBL§ anä changinç thå IÆ statemenô to the user's desires. Part B Usage Instructions and Explanation of Commands Thå  followinç instructionó arå writteî witè thå  assumptioî thaô  thå readeò ió quitå familiaò witè ho÷ tï uså CP/Í  2.²  anä itó  CCP®  CCPÚ  ió  writteî aó á logicaì extensioî  anä  slighô modificatioî  oæ  thå  CP/Í  2.² CCР philosophù  anä  shoulä  bå addressed as such. The CCPZ Command Hierarchy Search Thå first¬  anä mosô basiã thing¬ tï learî abouô CCPÚ ió thå ordeò iî whicè ió searcheó foò á COÍ filå foò executioî oò á filå specifieä  bù thå GEÔ command®  Undeò thå CP/Í 2.² CCP¬  iæ  thå specifieä  COÍ filå commanä waó noô founä oî thå currenô drivå iî thå  currenô useò area¬  thå CCÐ aborteä witè aî  erroò  message® CCPZ¬  however¬  continueó searchinç froí thió poinô á maximuí oæ twï  morå  levels®  Thió commanä hierarchù searcè  waó  outlineä abovå anä ió describeä herå iî furtheò detail. 1®  Iæ  thå  commanä ió oæ thå forí 'COMMAND§ anä  NOÔ 'd:COMMAND'¬  thå  CCP-residenô  commanä lisô ió searcheä  foò  á match®  Iæ  thå  matcè ió found¬  thå  CCP-residenô  commanä  ió immediatelù processed®  Iæ thå matcè ió noô founä oò thå commanä ió  oæ thå forí 'd:COMMAND'¬  thå nexô steð ió taken®  Notå thaô thå  'd:COMMAND§  forí ió gooä foò executinç á commanä  COÍ  filå whicè  haó thå samå namå aó á CCP-residenô commanä (sucè aó  SAVÅ or DIR). 2®  Iæ  thå commanä ió oæ thå forí  'd:COMMAND'¬  disë drivå  'd:§  ió  temporarilù loggeä iî foò  thå  purposå  oæ  thå commanä  search®  Otherwise¬  thå  currentlù logged-iî drivå  ió used. 3® No÷ thå filå nameä COMMAND.COÍ ió searcheä for® Iæ found¬  iô  ió loadeä intï memorù startinç aô 100È anä  executed® If not, proceed to step 4. 4®  No÷  thaô  thå firsô searcè  foò  COMMAND.COÍ  haó failed¬  thå  CCÐ checkó tï seå iæ thå useò ió undeò thå  currenô Defaulô Useò Number®  Thå Defaulô Useò Numbeò maù bå thaô seô bù thå  DEFUSÒ equatå iî thå CCÐ oò thaô seô bù thå useò viá thå DFÕ command®  DEFUSÒ  ió iî effecô iæ DFÕ haó noô beeî issueä  sincå thå lasô Warí oò Colä Boot¬ anä DFÕ ió iî effecô iæ iô waó issueä sincå thå lasô Warí oò Colä Boot®  Iæ thå useò ió NOÔ undeò  thå currenô  Defaulô Useò Number¬  CCPÚ temporarilù logó hií intï  iô anä  searcheó  thå directory®  Iæ COMMAND.COÍ ió  found¬  iô  ió loadeä aó describeä abovå anä executed® Iæ not¬ CCPÚ proceedó tï the next step. Š 5®  Thå useò ió no÷ iî thå Defaulô Useò Number¬ anä aô thió  point¬  CCPÚ checkó tï seå iæ thå useò ió oî disë drivå A:® Iæ not¬ iô temporarilù logó intï Aº anä searcheó thå defaulô useò numbeò  oæ  Aº  foò  COMMAND.COM®  Iæ found¬  iô  ió  loadeä  aó describeä abovå anä executed®  Iæ not¬  CCPÚ printó thå  commanä namå  aó  aî  erroò messagå anä returnó tï  commanä  inpuô  mode¬ aborting the SUBMIT file if COMMAND came from it. Iî  alì caseó oæ thå searcè above¬  iæ COMMAND.COÍ ió found¬ afteò  iô  ió loadeä intï memory¬  CCPÚ resetó thå  useò  tï  hió originaì disë drivå anä useò number® Hence¬ thå fileó referenceä by the user by default are obtained from this environment. Tï  illustratå thió commanä hierarchù search¬  consideò  thå following examples: Example 1: DEFUSR equ 0 {default user number is 0} B10> <-- User is on Drive B:, User Number 10 B10>ASM TEST.BBZ <-- User wishes to assemble TEST.ASM in Drive B:, User 10 <-- At this point, CCPZ looks on B:/10 for ASM.COM, fails, looks on B:/0, fails, and finally looks on A:/0; it finds ASM.COM here and goes back to B:/10 for the file Example 2: DEFUSR equ 0 and DFU issued B10> <-- User is on Drive B:, User Number 10 B10>DFU 5 <-- User Selects User 5 as default B10>ASM TEST.BBZ <-- As above <-- At this point, CCPZ looks on B:/10 for ASM.COM, fails, look on B:/5, fails, and finally looks on A:/5; it Summary of the New Features of CCPZ The CCPZ Command Hierarchy Search CCPZ-Resident Command DIR CCPZ-Resident Command ERA CCPZ-Resident Command LIST CCPZ-Resident Command TYPE CCPZ-Resident Command SAVE CCPZ-Resident Command REN CCPZ-Resident Command USER CCPZ-Resident Command DFU CCPZ-Resident Command JUMP CCPZ-Resident Command GO CCPZ-Resident Command GET CCPZ Error Messages :Summary of the New Features of CCPZ CCPÚ ió basicallù á rewritå oæ thå CP/Í CCÐ whicè ió design- eä tï ruî aó parô oæ CP/Í oî Z80-baseä microcomputers®  Iî  mosô caseó  iô ió upward-compatablå witè thå originaì CP/Í Versioî 2.² CCP. CCPZ¬  however¬  provideó  manù extensionó tï thå CP/Í  CCP® Amonç theså are: ® Thå TYPÅ functioî caî bå madå tï pagå oò noô pagå itó outpuô aô thå user'ó discretion ®  Á LISÔ functioî ió availablå whicè sendó itó  outpuô tï thå CP/Í LSTº Devicå anä doeó NOÔ page ®  Thå  DIÒ commanä haó beeî extendeä tï allo÷ thå dis- plaù oæ thå systeí fileó oò alì files ® Thå ERÁ commanä no÷ printó ouô thå nameó oæ thå fileó iô ió erasing ®  Thå  currenô useò numbeò maù bå includeä aó parô  oæ thå commanä prompt»  iæ thå useò ió undeò á numbeò otheò thaî  0¬ thå prompô ió oæ thå forí 'du>§ (likå 'A2>§ oò 'B10>')¬  and¬  iæ thå  useò ió undeò 0¬  thå prompô maù bå 'd>§ oò 'd0>§ aó peò hió choice ®  Thå  SUBMIÔ facilitù haó beeî changeä iî  twï  basiã ways: - thå  prompô  changeó tï 'du$§ oò 'd$§  wheî  thå SUBMIÔ commanä ió printed - thå  $$$.SU ió executeä froí thå currentlù log- ged-iî disë (NOÔ jusô froí A:) ®  Á command-searcè hierarchù ió no÷ implementeä  whicè ió executeä roughlù aó follows: - thå  user'ó commanä ió checkeä againsô thå  CCP- residenô commandó anä executeä immediatelù iæ á matcè ió found - failinç  that¬  thå  currenô useò numbeò oî  thå currenô disë ió scanneä foò thå COÍ file»  thå COÍ filå ió loadeä anä executeä iæ found - failinç that¬ á defaulô useò numbeò (initiallù ° buô  caî bå reseô witè thå DFÕ CCP-residenô command© oî thå  cur- renô disë ió scanneä foò thå COÍ file» thå COÍ filå ió loadeä anä executeä iæ found - finally¬  failinç that¬  thå defaulô useò numbeò oî disë Aº  ió scanneä foò thå COÍ file»  thå COÍ filå ió  loadeä anä executeä iæ founä oò aî erroò messagå (COMMAND?¬ wheî COMMANÄ waó thå user'ó commanä name© ió printed ®  Thå  numeriã argumenô foò thå SAVÅ CCP-residenô com- manä  (viú thå numbeò oæ 256-bytå pageó tï save© caî bå inpuô  iî HEØ ratheò thaî decimal ®  Á  GEÔ  commanä whicè loadó á filå  aô  á  specifieä memorù addresó anä á JUMÐ commanä whicè "calls¢ thå subroutinå aô á  specifieä memorù addresó havå beeî added»  á GÏ commanä  whicè "calls¢  thå  subroutinå startinç aô 100È ió alsï addeä (thió  ió redundant with JUMP 100H) :The CCPZ Command Hierarchy Search Thå first¬  anä mosô basiã thing¬ tï learî abouô CCPÚ ió thå ordeò iî whicè ió searcheó foò á COÍ filå foò executioî oò á filå specifieä  bù thå GEÔ command®  Undeò thå CP/Í 2.² CCP¬  iæ  thå specifieä  COÍ filå commanä waó noô founä oî thå currenô drivå iî thå  currenô useò area¬  thå CCÐ aborteä witè aî  erroò  message® CCPZ¬  however¬  continueó searchinç froí thió poinô á maximuí oæ twï  morå  levels®  Thió commanä hierarchù searcè  waó  outlineä abovå anä ió describeä herå iî furtheò detail. 1®  Iæ  thå  commanä ió oæ thå forí 'COMMAND§ anä  NOÔ 'd:COMMAND'¬  thå  CCP-residenô  commanä lisô ió searcheä  foò  á match®  Iæ  thå  matcè ió found¬  thå  CCP-residenô  commanä  ió immediatelù processed®  Iæ thå matcè ió noô founä oò thå commanä ió  oæ thå forí 'd:COMMAND'¬  thå nexô steð ió taken®  Notå thaô thå  'd:COMMAND§  forí ió gooä foò executinç á commanä  COÍ  filå whicè  haó thå samå namå aó á CCP-residenô commanä (sucè aó  SAVÅ or DIR). 2®  Iæ  thå commanä ió oæ thå forí  'd:COMMAND'¬  disë drivå  'd:§  ió  temporarilù loggeä iî foò  thå  purposå  oæ  thå commanä  search®  Otherwise¬  thå  currentlù logged-iî drivå  ió used. 3® No÷ thå filå nameä COMMAND.COÍ ió searcheä for® Iæ found¬  iô  ió loadeä intï memorù startinç aô 100È anä  executed® If not, proceed to step 4. 4®  No÷  thaô  thå firsô searcè  foò  COMMAND.COÍ  haó failed¬  thå  CCÐ checkó tï seå iæ thå useò ió undeò thå  currenô Defaulô Useò Number®  Thå Defaulô Useò Numbeò maù bå thaô seô bù thå  DEFUSÒ equatå iî thå CCÐ oò thaô seô bù thå useò viá thå DFÕ command®  DEFUSÒ  ió iî effecô iæ DFÕ haó noô beeî issueä  sincå thå lasô Warí oò Colä Boot¬ anä DFÕ ió iî effecô iæ iô waó issueä sincå thå lasô Warí oò Colä Boot®  Iæ thå useò ió NOÔ undeò  thå currenô  Defaulô Useò Number¬  CCPÚ temporarilù logó hií intï  iô anä  searcheó  thå directory®  Iæ COMMAND.COÍ ió  found¬  iô  ió loadeä aó describeä abovå anä executed® Iæ not¬ CCPÚ proceedó tï the next step. 5®  Thå useò ió no÷ iî thå Defaulô Useò Number¬ anä aô thió  point¬  CCPÚ checkó tï seå iæ thå useò ió oî disë drivå A:® Iæ not¬ iô temporarilù logó intï Aº anä searcheó thå defaulô useò numbeò  oæ  Aº  foò  COMMAND.COM®  Iæ found¬  iô  ió  loadeä  aó describeä abovå anä executed®  Iæ not¬  CCPÚ printó thå  commanä namå  aó  aî  erroò messagå anä returnó tï  commanä  inpuô  mode¬ aborting the SUBMIT file if COMMAND came from it. Iî  alì caseó oæ thå searcè above¬  iæ COMMAND.COÍ ió found¬ afteò  iô  ió loadeä intï memory¬  CCPÚ resetó thå  useò  tï  hió originaì disë drivå anä useò number® Hence¬ thå fileó referenceä by the user by default are obtained from this environment. Tï  illustratå thió commanä hierarchù search¬  consideò  thå following examples: Example 1: DEFUSR equ 0 {default user number is 0} B10> <-- User is on Drive B:, User Number 10 B10>ASM TEST.BBZ <-- User wishes to assemble TEST.ASM in Drive B:, User 10 <-- At this point, CCPZ looks on B:/10 for ASM.COM, fails, looks on B:/0, fails, and finally looks on A:/0; it finds ASM.COM here and goes back to B:/10 for the file Example 2: DEFUSR equ 0 and DFU issued B10> <-- User is on Drive B:, User Number 10 B10>DFU 5 <-- User Selects User 5 as default B10>ASM TEST.BBZ <-- As above <-- At this point, CCPZ looks on B:/10 for ASM.COM, fails, look on B:/5, fails, and finally looks on A:/5; it fails here also and prints ASM? as an error message Exampl