# File cpm22.asm 0000 ;************************************************************** 0000 ;* 0000 ;* C P / M version 2 . 2 0000 ;* 0000 ;* Reconstructed from memory image on February 27, 1981 0000 ;* 0000 ;* by Clark A. Calkins 0000 ;* 0000 ;************************************************************** 0000 ; 0000 ; Set memory limit here. This is the amount of contigeous 0000 ; ram starting from 0000. CP/M will reside at the end of this space. 0000 ; 0000 0000 IOBYTE: EQU 3 ;i/o definition byte. 0000 TDRIVE: EQU 4 ;current drive name and user number. 0000 ENTRY: EQU 5 ;entry point for the cp/m bdos. 0000 TFCB: EQU 5CH ;default file control block. 0000 TBUFF: EQU 80H ;i/o buffer and command line storage. 0000 TBASE: EQU 100H ;transiant program storage area. 0000 ; 0000 ; Set control character equates. 0000 ; 0000 CNTRLC: EQU 3 ;control-c 0000 CNTRLE: EQU 05H ;control-e 0000 BS: EQU 08H ;backspace 0000 TAB: EQU 09H ;tab 0000 LF: EQU 0AH ;line feed 0000 FF: EQU 0CH ;form feed 0000 CR: EQU 0DH ;carriage return 0000 CNTRLP: EQU 10H ;control-p 0000 CNTRLR: EQU 12H ;control-r 0000 CNTRLS: EQU 13H ;control-s 0000 CNTRLU: EQU 15H ;control-u 0000 CNTRLX: EQU 18H ;control-x 0000 CNTRLZ: EQU 1AH ;control-z (end-of-file mark) 0000 DEL: EQU 7FH ;rubout 0000 ; 0000 ; Set origin for CP/M 0000 ; 0000 ORG 0E400H e400 ; e400 c3 5c e7 CBASE: JP COMMAND ;execute command processor (ccp). e403 c3 58 e7 JP CLEARBUF ;entry to empty input buffer before starting ccp. e406 e406 ; e406 ; Standard cp/m ccp input buffer. Format is (max length), e406 ; (actual length), (char #1), (char #2), (char #3), etc. e406 ; e406 7f INBUFF: DB 127 ;length of input buffer. e407 00 DB 0 ;current length of contents. e408 .. DEFM "Copyright" e411 .. DEFM " 1979 (c) by Digital Research " e434 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 e44b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 e462 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 e479 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 e488 08 e4 INPOINT:DW INBUFF+2 ;input line pointer e48a 00 00 NAMEPNT:DW 0 ;input line pointer used for error message. Points to e48c ; ;start of name in error. e48c ; e48c ; Routine to print (A) on the console. All registers used. e48c ; e48c 5f PRINT: LD E,A ;setup bdos call. e48d 0e 02 LD C,2 e48f c3 05 00 JP ENTRY e492 ; e492 ; Routine to print (A) on the console and to save (BC). e492 ; e492 c5 PRINTB: PUSH BC e493 cd 8c e4 CALL PRINT e496 c1 POP BC e497 c9 RET e498 ; e498 ; Routine to send a carriage return, line feed combination e498 ; to the console. e498 ; e498 3e 0d CRLF: LD A,CR e49a cd 92 e4 CALL PRINTB e49d 3e 0a LD A,LF e49f c3 92 e4 JP PRINTB e4a2 ; e4a2 ; Routine to send one space to the console and save (BC). e4a2 ; e4a2 3e 20 SPACE: LD A,' ' e4a4 c3 92 e4 JP PRINTB e4a7 ; e4a7 ; Routine to print character string pointed to be (BC) on the e4a7 ; console. It must terminate with a null byte. e4a7 ; e4a7 c5 PLINE: PUSH BC e4a8 cd 98 e4 CALL CRLF e4ab e1 POP HL e4ac 7e PLINE2: LD A,(HL) e4ad b7 OR A e4ae c8 RET Z e4af 23 INC HL e4b0 e5 PUSH HL e4b1 cd 8c e4 CALL PRINT e4b4 e1 POP HL e4b5 c3 ac e4 JP PLINE2 e4b8 ; e4b8 ; Routine to reset the disk system. e4b8 ; e4b8 0e 0d RESDSK: LD C,13 e4ba c3 05 00 JP ENTRY e4bd ; e4bd ; Routine to select disk (A). e4bd ; e4bd 5f DSKSEL: LD E,A e4be 0e 0e LD C,14 e4c0 c3 05 00 JP ENTRY e4c3 ; e4c3 ; Routine to call bdos and save the return code. The zero e4c3 ; flag is set on a return of 0ffh. e4c3 ; e4c3 cd 05 00 ENTRY1: CALL ENTRY e4c6 32 ee eb LD (RTNCODE),A ;save return code. e4c9 3c INC A ;set zero if 0ffh returned. e4ca c9 RET e4cb ; e4cb ; Routine to open a file. (DE) must point to the FCB. e4cb ; e4cb 0e 0f OPEN: LD C,15 e4cd c3 c3 e4 JP ENTRY1 e4d0 ; e4d0 ; Routine to open file at (FCB). e4d0 ; e4d0 af OPENFCB:XOR A ;clear the record number byte at fcb+32 e4d1 32 ed eb LD (FCB+32),A e4d4 11 cd eb LD DE,FCB e4d7 c3 cb e4 JP OPEN e4da ; e4da ; Routine to close a file. (DE) points to FCB. e4da ; e4da 0e 10 CLOSE: LD C,16 e4dc c3 c3 e4 JP ENTRY1 e4df ; e4df ; Routine to search for the first file with ambigueous name e4df ; (DE). e4df ; e4df 0e 11 SRCHFST:LD C,17 e4e1 c3 c3 e4 JP ENTRY1 e4e4 ; e4e4 ; Search for the next ambigeous file name. e4e4 ; e4e4 0e 12 SRCHNXT:LD C,18 e4e6 c3 c3 e4 JP ENTRY1 e4e9 ; e4e9 ; Search for file at (FCB). e4e9 ; e4e9 11 cd eb SRCHFCB:LD DE,FCB e4ec c3 df e4 JP SRCHFST e4ef ; e4ef ; Routine to delete a file pointed to by (DE). e4ef ; e4ef 0e 13 DELETE: LD C,19 e4f1 c3 05 00 JP ENTRY e4f4 ; e4f4 ; Routine to call the bdos and set the zero flag if a zero e4f4 ; status is returned. e4f4 ; e4f4 cd 05 00 ENTRY2: CALL ENTRY e4f7 b7 OR A ;set zero flag if appropriate. e4f8 c9 RET e4f9 ; e4f9 ; Routine to read the next record from a sequential file. e4f9 ; (DE) points to the FCB. e4f9 ; e4f9 0e 14 RDREC: LD C,20 e4fb c3 f4 e4 JP ENTRY2 e4fe ; e4fe ; Routine to read file at (FCB). e4fe ; e4fe 11 cd eb READFCB:LD DE,FCB e501 c3 f9 e4 JP RDREC e504 ; e504 ; Routine to write the next record of a sequential file. e504 ; (DE) points to the FCB. e504 ; e504 0e 15 WRTREC: LD C,21 e506 c3 f4 e4 JP ENTRY2 e509 ; e509 ; Routine to create the file pointed to by (DE). e509 ; e509 0e 16 CREATE: LD C,22 e50b c3 c3 e4 JP ENTRY1 e50e ; e50e ; Routine to rename the file pointed to by (DE). Note that e50e ; the new name starts at (DE+16). e50e ; e50e 0e 17 RENAM: LD C,23 e510 c3 05 00 JP ENTRY e513 ; e513 ; Get the current user code. e513 ; e513 1e ff GETUSR: LD E,0FFH e515 ; e515 ; Routne to get or set the current user code. e515 ; If (E) is FF then this is a GET, else it is a SET. e515 ; e515 0e 20 GETSETUC: LD C,32 e517 c3 05 00 JP ENTRY e51a ; e51a ; Routine to set the current drive byte at (TDRIVE). e51a ; e51a cd 13 e5 SETCDRV:CALL GETUSR ;get user number e51d 87 ADD A,A ;and shift into the upper 4 bits. e51e 87 ADD A,A e51f 87 ADD A,A e520 87 ADD A,A e521 21 ef eb LD HL,CDRIVE ;now add in the current drive number. e524 b6 OR (HL) e525 32 04 00 LD (TDRIVE),A ;and save. e528 c9 RET e529 ; e529 ; Move currently active drive down to (TDRIVE). e529 ; e529 3a ef eb MOVECD: LD A,(CDRIVE) e52c 32 04 00 LD (TDRIVE),A e52f c9 RET e530 ; e530 ; Routine to convert (A) into upper case ascii. Only letters e530 ; are affected. e530 ; e530 fe 61 UPPER: CP 'a' ;check for letters in the range of 'a' to 'z'. e532 d8 RET C e533 fe 7b CP '{' e535 d0 RET NC e536 e6 5f AND 5FH ;convert it if found. e538 c9 RET e539 ; e539 ; Routine to get a line of input. We must check to see if the e539 ; user is in (BATCH) mode. If so, then read the input from file e539 ; ($$$.SUB). At the end, reset to console input. e539 ; e539 3a ab eb GETINP: LD A,(BATCH) ;if =0, then use console input. e53c b7 OR A e53d ca 96 e5 JP Z,GETINP1 e540 ; e540 ; Use the submit file ($$$.sub) which is prepared by a e540 ; SUBMIT run. It must be on drive (A) and it will be deleted e540 ; if and error occures (like eof). e540 ; e540 3a ef eb LD A,(CDRIVE) ;select drive 0 if need be. e543 b7 OR A e544 3e 00 LD A,0 ;always use drive A for submit. e546 c4 bd e4 CALL NZ,DSKSEL ;select it if required. e549 11 ac eb LD DE,BATCHFCB e54c cd cb e4 CALL OPEN ;look for it. e54f ca 96 e5 JP Z,GETINP1 ;if not there, use normal input. e552 3a bb eb LD A,(BATCHFCB+15) ;get last record number+1. e555 3d DEC A e556 32 cc eb LD (BATCHFCB+32),A e559 11 ac eb LD DE,BATCHFCB e55c cd f9 e4 CALL RDREC ;read last record. e55f c2 96 e5 JP NZ,GETINP1 ;quit on end of file. e562 ; e562 ; Move this record into input buffer. e562 ; e562 11 07 e4 LD DE,INBUFF+1 e565 21 80 00 LD HL,TBUFF ;data was read into buffer here. e568 06 80 LD B,128 ;all 128 characters may be used. e56a cd 42 e8 CALL HL2DE ;(HL) to (DE), (B) bytes. e56d 21 ba eb LD HL,BATCHFCB+14 e570 36 00 LD (HL),0 ;zero out the 's2' byte. e572 23 INC HL ;and decrement the record count. e573 35 DEC (HL) e574 11 ac eb LD DE,BATCHFCB ;close the batch file now. e577 cd da e4 CALL CLOSE e57a ca 96 e5 JP Z,GETINP1 ;quit on an error. e57d 3a ef eb LD A,(CDRIVE) ;re-select previous drive if need be. e580 b7 OR A e581 c4 bd e4 CALL NZ,DSKSEL ;don't do needless selects. e584 ; e584 ; Print line just read on console. e584 ; e584 21 08 e4 LD HL,INBUFF+2 e587 cd ac e4 CALL PLINE2 e58a cd c2 e5 CALL CHKCON ;check console, quit on a key. e58d ca a7 e5 JP Z,GETINP2 ;jump if no key is pressed. e590 ; e590 ; Terminate the submit job on any keyboard input. Delete this e590 ; file such that it is not re-started and jump to normal keyboard e590 ; input section. e590 ; e590 cd dd e5 CALL DELBATCH ;delete the batch file. e593 c3 82 e7 JP CMMND1 ;and restart command input. e596 ; e596 ; Get here for normal keyboard input. Delete the submit file e596 ; incase there was one. e596 ; e596 cd dd e5 GETINP1:CALL DELBATCH ;delete file ($$$.sub). e599 cd 1a e5 CALL SETCDRV ;reset active disk. e59c 0e 0a LD C,10 ;get line from console device. e59e 11 06 e4 LD DE,INBUFF e5a1 cd 05 00 CALL ENTRY e5a4 cd 29 e5 CALL MOVECD ;reset current drive (again). e5a7 ; e5a7 ; Convert input line to upper case. e5a7 ; e5a7 21 07 e4 GETINP2:LD HL,INBUFF+1 e5aa 46 LD B,(HL) ;(B)=character counter. e5ab 23 GETINP3:INC HL e5ac 78 LD A,B ;end of the line? e5ad b7 OR A e5ae ca ba e5 JP Z,GETINP4 e5b1 7e LD A,(HL) ;convert to upper case. e5b2 cd 30 e5 CALL UPPER e5b5 77 LD (HL),A e5b6 05 DEC B ;adjust character count. e5b7 c3 ab e5 JP GETINP3 e5ba 77 GETINP4:LD (HL),A ;add trailing null. e5bb 21 08 e4 LD HL,INBUFF+2 e5be 22 88 e4 LD (INPOINT),HL ;reset input line pointer. e5c1 c9 RET e5c2 ; e5c2 ; Routine to check the console for a key pressed. The zero e5c2 ; flag is set is none, else the character is returned in (A). e5c2 ; e5c2 0e 0b CHKCON: LD C,11 ;check console. e5c4 cd 05 00 CALL ENTRY e5c7 b7 OR A e5c8 c8 RET Z ;return if nothing. e5c9 0e 01 LD C,1 ;else get character. e5cb cd 05 00 CALL ENTRY e5ce b7 OR A ;clear zero flag and return. e5cf c9 RET e5d0 ; e5d0 ; Routine to get the currently active drive number. e5d0 ; e5d0 0e 19 GETDSK: LD C,25 e5d2 c3 05 00 JP ENTRY e5d5 ; e5d5 ; Set the stabdard dma address. e5d5 ; e5d5 11 80 00 STDDMA: LD DE,TBUFF e5d8 ; e5d8 ; Routine to set the dma address to (DE). e5d8 ; e5d8 0e 1a DMASET: LD C,26 e5da c3 05 00 JP ENTRY e5dd ; e5dd ; Delete the batch file created by SUBMIT. e5dd ; e5dd 21 ab eb DELBATCH: LD HL,BATCH ;is batch active? e5e0 7e LD A,(HL) e5e1 b7 OR A e5e2 c8 RET Z e5e3 36 00 LD (HL),0 ;yes, de-activate it. e5e5 af XOR A e5e6 cd bd e4 CALL DSKSEL ;select drive 0 for sure. e5e9 11 ac eb LD DE,BATCHFCB ;and delete this file. e5ec cd ef e4 CALL DELETE e5ef 3a ef eb LD A,(CDRIVE) ;reset current drive. e5f2 c3 bd e4 JP DSKSEL e5f5 ; e5f5 ; Check to two strings at (PATTRN1) and (PATTRN2). They must be e5f5 ; the same or we halt.... e5f5 ; e5f5 11 28 e7 VERIFY: LD DE,PATTRN1 ;these are the serial number bytes. e5f8 21 00 ec LD HL,PATTRN2 ;ditto, but how could they be different? e5fb 06 06 LD B,6 ;6 bytes each. e5fd 1a VERIFY1:LD A,(DE) e5fe be CP (HL) e5ff c2 cf e7 JP NZ,HALT ;jump to halt routine. e602 13 INC DE e603 23 INC HL e604 05 DEC B e605 c2 fd e5 JP NZ,VERIFY1 e608 c9 RET e609 ; e609 ; Print back file name with a '?' to indicate a syntax error. e609 ; e609 cd 98 e4 SYNERR: CALL CRLF ;end current line. e60c 2a 8a e4 LD HL,(NAMEPNT) ;this points to name in error. e60f 7e SYNERR1:LD A,(HL) ;print it until a space or null is found. e610 fe 20 CP ' ' e612 ca 22 e6 JP Z,SYNERR2 e615 b7 OR A e616 ca 22 e6 JP Z,SYNERR2 e619 e5 PUSH HL e61a cd 8c e4 CALL PRINT e61d e1 POP HL e61e 23 INC HL e61f c3 0f e6 JP SYNERR1 e622 3e 3f SYNERR2:LD A,'?' ;add trailing '?'. e624 cd 8c e4 CALL PRINT e627 cd 98 e4 CALL CRLF e62a cd dd e5 CALL DELBATCH ;delete any batch file. e62d c3 82 e7 JP CMMND1 ;and restart from console input. e630 ; e630 ; Check character at (DE) for legal command input. Note that the e630 ; zero flag is set if the character is a delimiter. e630 ; e630 1a CHECK: LD A,(DE) e631 b7 OR A e632 c8 RET Z e633 fe 20 CP ' ' ;control characters are not legal here. e635 da 09 e6 JP C,SYNERR e638 c8 RET Z ;check for valid delimiter. e639 fe 3d CP '=' e63b c8 RET Z e63c fe 5f CP '_' e63e c8 RET Z e63f fe 2e CP '.' e641 c8 RET Z e642 fe 3a CP 03Ah ;':' e644 c8 RET Z e645 fe 3b CP 03BH ; ';' e647 c8 RET Z e648 fe 3c CP '<' e64a c8 RET Z e64b fe 3e CP '>' e64d c8 RET Z e64e c9 RET e64f ; e64f ; Get the next non-blank character from (DE). e64f ; e64f 1a NONBLANK: LD A,(DE) e650 b7 OR A ;string ends with a null. e651 c8 RET Z e652 fe 20 CP ' ' e654 c0 RET NZ e655 13 INC DE e656 c3 4f e6 JP NONBLANK e659 ; e659 ; Add (HL)=(HL)+(A) e659 ; e659 85 ADDHL: ADD A,L e65a 6f LD L,A e65b d0 RET NC ;take care of any carry. e65c 24 INC H e65d c9 RET e65e ; e65e ; Convert the first name in (FCB). e65e ; e65e 3e 00 CONVFST:LD A,0 e660 ; e660 ; Format a file name (convert * to '?', etc.). On return, e660 ; (A)=0 is an unambigeous name was specified. Enter with (A) equal to e660 ; the position within the fcb for the name (either 0 or 16). e660 ; e660 21 cd eb CONVERT:LD HL,FCB e663 cd 59 e6 CALL ADDHL e666 e5 PUSH HL e667 e5 PUSH HL e668 af XOR A e669 32 f0 eb LD (CHGDRV),A ;initialize drive change flag. e66c 2a 88 e4 LD HL,(INPOINT) ;set (HL) as pointer into input line. e66f eb EX DE,HL e670 cd 4f e6 CALL NONBLANK ;get next non-blank character. e673 eb EX DE,HL e674 22 8a e4 LD (NAMEPNT),HL ;save pointer here for any error message. e677 eb EX DE,HL e678 e1 POP HL e679 1a LD A,(DE) ;get first character. e67a b7 OR A e67b ca 89 e6 JP Z,CONVRT1 e67e de 40 SBC A,'A'-1 ;might be a drive name, convert to binary. e680 47 LD B,A ;and save. e681 13 INC DE ;check next character for a ':'. e682 1a LD A,(DE) e683 fe 3a CP ':' e685 ca 90 e6 JP Z,CONVRT2 e688 1b DEC DE ;nope, move pointer back to the start of the line. e689 3a ef eb CONVRT1:LD A,(CDRIVE) e68c 77 LD (HL),A e68d c3 96 e6 JP CONVRT3 e690 78 CONVRT2:LD A,B e691 32 f0 eb LD (CHGDRV),A ;set change in drives flag. e694 70 LD (HL),B e695 13 INC DE e696 ; e696 ; Convert the basic file name. e696 ; e696 06 08 CONVRT3:LD B,08H e698 cd 30 e6 CONVRT4:CALL CHECK e69b ca b9 e6 JP Z,CONVRT8 e69e 23 INC HL e69f fe 2a CP '*' ;note that an '*' will fill the remaining e6a1 c2 a9 e6 JP NZ,CONVRT5 ;field with '?'. e6a4 36 3f LD (HL),'?' e6a6 c3 ab e6 JP CONVRT6 e6a9 77 CONVRT5:LD (HL),A e6aa 13 INC DE e6ab 05 CONVRT6:DEC B e6ac c2 98 e6 JP NZ,CONVRT4 e6af cd 30 e6 CONVRT7:CALL CHECK ;get next delimiter. e6b2 ca c0 e6 JP Z,GETEXT e6b5 13 INC DE e6b6 c3 af e6 JP CONVRT7 e6b9 23 CONVRT8:INC HL ;blank fill the file name. e6ba 36 20 LD (HL),' ' e6bc 05 DEC B e6bd c2 b9 e6 JP NZ,CONVRT8 e6c0 ; e6c0 ; Get the extension and convert it. e6c0 ; e6c0 06 03 GETEXT: LD B,03H e6c2 fe 2e CP '.' e6c4 c2 e9 e6 JP NZ,GETEXT5 e6c7 13 INC DE e6c8 cd 30 e6 GETEXT1:CALL CHECK e6cb ca e9 e6 JP Z,GETEXT5 e6ce 23 INC HL e6cf fe 2a CP '*' e6d1 c2 d9 e6 JP NZ,GETEXT2 e6d4 36 3f LD (HL),'?' e6d6 c3 db e6 JP GETEXT3 e6d9 77 GETEXT2:LD (HL),A e6da 13 INC DE e6db 05 GETEXT3:DEC B e6dc c2 c8 e6 JP NZ,GETEXT1 e6df cd 30 e6 GETEXT4:CALL CHECK e6e2 ca f0 e6 JP Z,GETEXT6 e6e5 13 INC DE e6e6 c3 df e6 JP GETEXT4 e6e9 23 GETEXT5:INC HL e6ea 36 20 LD (HL),' ' e6ec 05 DEC B e6ed c2 e9 e6 JP NZ,GETEXT5 e6f0 06 03 GETEXT6:LD B,3 e6f2 23 GETEXT7:INC HL e6f3 36 00 LD (HL),0 e6f5 05 DEC B e6f6 c2 f2 e6 JP NZ,GETEXT7 e6f9 eb EX DE,HL e6fa 22 88 e4 LD (INPOINT),HL ;save input line pointer. e6fd e1 POP HL e6fe ; e6fe ; Check to see if this is an ambigeous file name specification. e6fe ; Set the (A) register to non zero if it is. e6fe ; e6fe 01 0b 00 LD BC,11 ;set name length. e701 23 GETEXT8:INC HL e702 7e LD A,(HL) e703 fe 3f CP '?' ;any question marks? e705 c2 09 e7 JP NZ,GETEXT9 e708 04 INC B ;count them. e709 0d GETEXT9:DEC C e70a c2 01 e7 JP NZ,GETEXT8 e70d 78 LD A,B e70e b7 OR A e70f c9 RET e710 ; e710 ; CP/M command table. Note commands can be either 3 or 4 characters long. e710 ; e710 NUMCMDS: EQU 6 ;number of commands e710 .. CMDTBL: DEFM "DIR " e714 .. DEFM "ERA " e718 .. DEFM "TYPE" e71c .. DEFM "SAVE" e720 .. DEFM "REN " e724 .. DEFM "USER" e728 ; e728 ; The following six bytes must agree with those at (PATTRN2) e728 ; or cp/m will HALT. Why? e728 ; e728 00 16 00 00 00 00 PATTRN1:DB 0,22,0,0,0,0 ;(* serial number bytes *). e72e ; e72e ; Search the command table for a match with what has just e72e ; been entered. If a match is found, then we jump to the e72e ; proper section. Else jump to (UNKNOWN). e72e ; On return, the (C) register is set to the command number e72e ; that matched (or NUMCMDS+1 if no match). e72e ; e72e 21 10 e7 SEARCH: LD HL,CMDTBL e731 0e 00 LD C,0 e733 79 SEARCH1:LD A,C e734 fe 06 CP NUMCMDS ;this commands exists. e736 d0 RET NC e737 11 ce eb LD DE,FCB+1 ;check this one. e73a 06 04 LD B,4 ;max command length. e73c 1a SEARCH2:LD A,(DE) e73d be CP (HL) e73e c2 4f e7 JP NZ,SEARCH3 ;not a match. e741 13 INC DE e742 23 INC HL e743 05 DEC B e744 c2 3c e7 JP NZ,SEARCH2 e747 1a LD A,(DE) ;allow a 3 character command to match. e748 fe 20 CP ' ' e74a c2 54 e7 JP NZ,SEARCH4 e74d 79 LD A,C ;set return register for this command. e74e c9 RET e74f 23 SEARCH3:INC HL e750 05 DEC B e751 c2 4f e7 JP NZ,SEARCH3 e754 0c SEARCH4:INC C e755 c3 33 e7 JP SEARCH1 e758 ; e758 ; Set the input buffer to empty and then start the command e758 ; processor (ccp). e758 ; e758 af CLEARBUF: XOR A e759 32 07 e4 LD (INBUFF+1),A ;second byte is actual length. e75c ; e75c ;************************************************************** e75c ;* e75c ;* e75c ;* C C P - C o n s o l e C o m m a n d P r o c e s s o r e75c ;* e75c ;************************************************************** e75c ;* e75c 31 ab eb COMMAND:LD SP,CCPSTACK ;setup stack area. e75f c5 PUSH BC ;note that (C) should be equal to: e760 79 LD A,C ;(uuuudddd) where 'uuuu' is the user number e761 1f RRA ;and 'dddd' is the drive number. e762 1f RRA e763 1f RRA e764 1f RRA e765 e6 0f AND 0FH ;isolate the user number. e767 5f LD E,A e768 cd 15 e5 CALL GETSETUC ;and set it. e76b cd b8 e4 CALL RESDSK ;reset the disk system. e76e 32 ab eb LD (BATCH),A ;clear batch mode flag. e771 c1 POP BC e772 79 LD A,C e773 e6 0f AND 0FH ;isolate the drive number. e775 32 ef eb LD (CDRIVE),A ;and save. e778 cd bd e4 CALL DSKSEL ;...and select. e77b 3a 07 e4 LD A,(INBUFF+1) e77e b7 OR A ;anything in input buffer already? e77f c2 98 e7 JP NZ,CMMND2 ;yes, we just process it. e782 ; e782 ; Entry point to get a command line from the console. e782 ; e782 31 ab eb CMMND1: LD SP,CCPSTACK ;set stack straight. e785 cd 98 e4 CALL CRLF ;start a new line on the screen. e788 cd d0 e5 CALL GETDSK ;get current drive. e78b c6 41 ADD A,'A' e78d cd 8c e4 CALL PRINT ;print current drive. e790 3e 3e LD A,'>' e792 cd 8c e4 CALL PRINT ;and add prompt. e795 cd 39 e5 CALL GETINP ;get line from user. e798 ; e798 ; Process command line here. e798 ; e798 11 80 00 CMMND2: LD DE,TBUFF e79b cd d8 e5 CALL DMASET ;set standard dma address. e79e cd d0 e5 CALL GETDSK e7a1 32 ef eb LD (CDRIVE),A ;set current drive. e7a4 cd 5e e6 CALL CONVFST ;convert name typed in. e7a7 c4 09 e6 CALL NZ,SYNERR ;wild cards are not allowed. e7aa 3a f0 eb LD A,(CHGDRV) ;if a change in drives was indicated, e7ad b7 OR A ;then treat this as an unknown command e7ae c2 a5 ea JP NZ,UNKNOWN ;which gets executed. e7b1 cd 2e e7 CALL SEARCH ;else search command table for a match. e7b4 ; e7b4 ; Note that an unknown command returns e7b4 ; with (A) pointing to the last address e7b4 ; in our table which is (UNKNOWN). e7b4 ; e7b4 21 c1 e7 LD HL,CMDADR ;now, look thru our address table for command (A). e7b7 5f LD E,A ;set (DE) to command number. e7b8 16 00 LD D,0 e7ba 19 ADD HL,DE e7bb 19 ADD HL,DE ;(HL)=(CMDADR)+2*(command number). e7bc 7e LD A,(HL) ;now pick out this address. e7bd 23 INC HL e7be 66 LD H,(HL) e7bf 6f LD L,A e7c0 e9 JP (HL) ;now execute it. e7c1 ; e7c1 ; CP/M command address table. e7c1 ; e7c1 77 e8 1f e9 5d e9 ad e9 CMDADR: DW DIRECT,ERASE,TYPE,SAVE e7c9 10 ea 8e ea a5 ea DW RENAME,USER,UNKNOWN e7cf ; e7cf ; Halt the system. Reason for this is unknown at present. e7cf ; e7cf 21 f3 76 HALT: LD HL,76F3H ;'DI HLT' instructions. e7d2 22 00 e4 LD (CBASE),HL e7d5 21 00 e4 LD HL,CBASE e7d8 e9 JP (HL) e7d9 ; e7d9 ; Read error while TYPEing a file. e7d9 ; e7d9 01 df e7 RDERROR:LD BC,RDERR e7dc c3 a7 e4 JP PLINE e7df .. RDERR: DEFM "Read error" e7e9 00 DB 0 e7ea ; e7ea ; Required file was not located. e7ea ; e7ea 01 f0 e7 NONE: LD BC,NOFILE e7ed c3 a7 e4 JP PLINE e7f0 .. NOFILE: DEFM "No file" e7f7 00 DB 0 e7f8 ; e7f8 ; Decode a command of the form 'A>filename number{ filename}. e7f8 ; Note that a drive specifier is not allowed on the first file e7f8 ; name. On return, the number is in register (A). Any error e7f8 ; causes 'filename?' to be printed and the command is aborted. e7f8 ; e7f8 cd 5e e6 DECODE: CALL CONVFST ;convert filename. e7fb 3a f0 eb LD A,(CHGDRV) ;do not allow a drive to be specified. e7fe b7 OR A e7ff c2 09 e6 JP NZ,SYNERR e802 21 ce eb LD HL,FCB+1 ;convert number now. e805 01 0b 00 LD BC,11 ;(B)=sum register, (C)=max digit count. e808 7e DECODE1:LD A,(HL) e809 fe 20 CP ' ' ;a space terminates the numeral. e80b ca 33 e8 JP Z,DECODE3 e80e 23 INC HL e80f d6 30 SUB '0' ;make binary from ascii. e811 fe 0a CP 10 ;legal digit? e813 d2 09 e6 JP NC,SYNERR e816 57 LD D,A ;yes, save it in (D). e817 78 LD A,B ;compute (B)=(B)*10 and check for overflow. e818 e6 e0 AND 0E0H e81a c2 09 e6 JP NZ,SYNERR e81d 78 LD A,B e81e 07 RLCA e81f 07 RLCA e820 07 RLCA ;(A)=(B)*8 e821 80 ADD A,B ;.......*9 e822 da 09 e6 JP C,SYNERR e825 80 ADD A,B ;.......*10 e826 da 09 e6 JP C,SYNERR e829 82 ADD A,D ;add in new digit now. e82a da 09 e6 DECODE2:JP C,SYNERR e82d 47 LD B,A ;and save result. e82e 0d DEC C ;only look at 11 digits. e82f c2 08 e8 JP NZ,DECODE1 e832 c9 RET e833 7e DECODE3:LD A,(HL) ;spaces must follow (why?). e834 fe 20 CP ' ' e836 c2 09 e6 JP NZ,SYNERR e839 23 INC HL e83a 0d DECODE4:DEC C e83b c2 33 e8 JP NZ,DECODE3 e83e 78 LD A,B ;set (A)=the numeric value entered. e83f c9 RET e840 ; e840 ; Move 3 bytes from (HL) to (DE). Note that there is only e840 ; one reference to this at (A2D5h). e840 ; e840 06 03 MOVE3: LD B,3 e842 ; e842 ; Move (B) bytes from (HL) to (DE). e842 ; e842 7e HL2DE: LD A,(HL) e843 12 LD (DE),A e844 23 INC HL e845 13 INC DE e846 05 DEC B e847 c2 42 e8 JP NZ,HL2DE e84a c9 RET e84b ; e84b ; Compute (HL)=(TBUFF)+(A)+(C) and get the byte that's here. e84b ; e84b 21 80 00 EXTRACT:LD HL,TBUFF e84e 81 ADD A,C e84f cd 59 e6 CALL ADDHL e852 7e LD A,(HL) e853 c9 RET e854 ; e854 ; Check drive specified. If it means a change, then the new e854 ; drive will be selected. In any case, the drive byte of the e854 ; fcb will be set to null (means use current drive). e854 ; e854 af DSELECT:XOR A ;null out first byte of fcb. e855 32 cd eb LD (FCB),A e858 3a f0 eb LD A,(CHGDRV) ;a drive change indicated? e85b b7 OR A e85c c8 RET Z e85d 3d DEC A ;yes, is it the same as the current drive? e85e 21 ef eb LD HL,CDRIVE e861 be CP (HL) e862 c8 RET Z e863 c3 bd e4 JP DSKSEL ;no. Select it then. e866 ; e866 ; Check the drive selection and reset it to the previous e866 ; drive if it was changed for the preceeding command. e866 ; e866 3a f0 eb RESETDR:LD A,(CHGDRV) ;drive change indicated? e869 b7 OR A e86a c8 RET Z e86b 3d DEC A ;yes, was it a different drive? e86c 21 ef eb LD HL,CDRIVE e86f be CP (HL) e870 c8 RET Z e871 3a ef eb LD A,(CDRIVE) ;yes, re-select our old drive. e874 c3 bd e4 JP DSKSEL e877 ; e877 ;************************************************************** e877 ;* e877 ;* D I R E C T O R Y C O M M A N D e877 ;* e877 ;************************************************************** e877 ; e877 cd 5e e6 DIRECT: CALL CONVFST ;convert file name. e87a cd 54 e8 CALL DSELECT ;select indicated drive. e87d 21 ce eb LD HL,FCB+1 ;was any file indicated? e880 7e LD A,(HL) e881 fe 20 CP ' ' e883 c2 8f e8 JP NZ,DIRECT2 e886 06 0b LD B,11 ;no. Fill field with '?' - same as *.*. e888 36 3f DIRECT1:LD (HL),'?' e88a 23 INC HL e88b 05 DEC B e88c c2 88 e8 JP NZ,DIRECT1 e88f 1e 00 DIRECT2:LD E,0 ;set initial cursor position. e891 d5 PUSH DE e892 cd e9 e4 CALL SRCHFCB ;get first file name. e895 cc ea e7 CALL Z,NONE ;none found at all? e898 ca 1b e9 DIRECT3:JP Z,DIRECT9 ;terminate if no more names. e89b 3a ee eb LD A,(RTNCODE) ;get file's position in segment (0-3). e89e 0f RRCA e89f 0f RRCA e8a0 0f RRCA e8a1 e6 60 AND 60H ;(A)=position*32 e8a3 4f LD C,A e8a4 3e 0a LD A,10 e8a6 cd 4b e8 CALL EXTRACT ;extract the tenth entry in fcb. e8a9 17 RLA ;check system file status bit. e8aa da 0f e9 JP C,DIRECT8 ;we don't list them. e8ad d1 POP DE e8ae 7b LD A,E ;bump name count. e8af 1c INC E e8b0 d5 PUSH DE e8b1 e6 03 AND 03H ;at end of line? e8b3 f5 PUSH AF e8b4 c2 cc e8 JP NZ,DIRECT4 e8b7 cd 98 e4 CALL CRLF ;yes, end this line and start another. e8ba c5 PUSH BC e8bb cd d0 e5 CALL GETDSK ;start line with ('A:'). e8be c1 POP BC e8bf c6 41 ADD A,'A' e8c1 cd 92 e4 CALL PRINTB e8c4 3e 3a LD A,':' e8c6 cd 92 e4 CALL PRINTB e8c9 c3 d4 e8 JP DIRECT5 e8cc cd a2 e4 DIRECT4:CALL SPACE ;add seperator between file names. e8cf 3e 3a LD A,':' e8d1 cd 92 e4 CALL PRINTB e8d4 cd a2 e4 DIRECT5:CALL SPACE e8d7 06 01 LD B,1 ;'extract' each file name character at a time. e8d9 78 DIRECT6:LD A,B e8da cd 4b e8 CALL EXTRACT e8dd e6 7f AND 7FH ;strip bit 7 (status bit). e8df fe 20 CP ' ' ;are we at the end of the name? e8e1 c2 f9 e8 JP NZ,DRECT65 e8e4 f1 POP AF ;yes, don't print spaces at the end of a line. e8e5 f5 PUSH AF e8e6 fe 03 CP 3 e8e8 c2 f7 e8 JP NZ,DRECT63 e8eb 3e 09 LD A,9 ;first check for no extension. e8ed cd 4b e8 CALL EXTRACT e8f0 e6 7f AND 7FH e8f2 fe 20 CP ' ' e8f4 ca 0e e9 JP Z,DIRECT7 ;don't print spaces. e8f7 3e 20 DRECT63:LD A,' ' ;else print them. e8f9 cd 92 e4 DRECT65:CALL PRINTB e8fc 04 INC B ;bump to next character psoition. e8fd 78 LD A,B e8fe fe 0c CP 12 ;end of the name? e900 d2 0e e9 JP NC,DIRECT7 e903 fe 09 CP 9 ;nope, starting extension? e905 c2 d9 e8 JP NZ,DIRECT6 e908 cd a2 e4 CALL SPACE ;yes, add seperating space. e90b c3 d9 e8 JP DIRECT6 e90e f1 DIRECT7:POP AF ;get the next file name. e90f cd c2 e5 DIRECT8:CALL CHKCON ;first check console, quit on anything. e912 c2 1b e9 JP NZ,DIRECT9 e915 cd e4 e4 CALL SRCHNXT ;get next name. e918 c3 98 e8 JP DIRECT3 ;and continue with our list. e91b d1 DIRECT9:POP DE ;restore the stack and return to command level. e91c c3 86 eb JP GETBACK e91f ; e91f ;************************************************************** e91f ;* e91f ;* E R A S E C O M M A N D e91f ;* e91f ;************************************************************** e91f ; e91f cd 5e e6 ERASE: CALL CONVFST ;convert file name. e922 fe 0b CP 11 ;was '*.*' entered? e924 c2 42 e9 JP NZ,ERASE1 e927 01 52 e9 LD BC,YESNO ;yes, ask for confirmation. e92a cd a7 e4 CALL PLINE e92d cd 39 e5 CALL GETINP e930 21 07 e4 LD HL,INBUFF+1 e933 35 DEC (HL) ;must be exactly 'y'. e934 c2 82 e7 JP NZ,CMMND1 e937 23 INC HL e938 7e LD A,(HL) e939 fe 59 CP 'Y' e93b c2 82 e7 JP NZ,CMMND1 e93e 23 INC HL e93f 22 88 e4 LD (INPOINT),HL ;save input line pointer. e942 cd 54 e8 ERASE1: CALL DSELECT ;select desired disk. e945 11 cd eb LD DE,FCB e948 cd ef e4 CALL DELETE ;delete the file. e94b 3c INC A e94c cc ea e7 CALL Z,NONE ;not there? e94f c3 86 eb JP GETBACK ;return to command level now. e952 .. YESNO: DEFM "All (y/n)?" e95c 00 DB 0 e95d ; e95d ;************************************************************** e95d ;* e95d ;* T Y P E C O M M A N D e95d ;* e95d ;************************************************************** e95d ; e95d cd 5e e6 TYPE: CALL CONVFST ;convert file name. e960 c2 09 e6 JP NZ,SYNERR ;wild cards not allowed. e963 cd 54 e8 CALL DSELECT ;select indicated drive. e966 cd d0 e4 CALL OPENFCB ;open the file. e969 ca a7 e9 JP Z,TYPE5 ;not there? e96c cd 98 e4 CALL CRLF ;ok, start a new line on the screen. e96f 21 f1 eb LD HL,NBYTES ;initialize byte counter. e972 36 ff LD (HL),0FFH ;set to read first sector. e974 21 f1 eb TYPE1: LD HL,NBYTES e977 7e TYPE2: LD A,(HL) ;have we written the entire sector? e978 fe 80 CP 128 e97a da 87 e9 JP C,TYPE3 e97d e5 PUSH HL ;yes, read in the next one. e97e cd fe e4 CALL READFCB e981 e1 POP HL e982 c2 a0 e9 JP NZ,TYPE4 ;end or error? e985 af XOR A ;ok, clear byte counter. e986 77 LD (HL),A e987 34 TYPE3: INC (HL) ;count this byte. e988 21 80 00 LD HL,TBUFF ;and get the (A)th one from the buffer (TBUFF). e98b cd 59 e6 CALL ADDHL e98e 7e LD A,(HL) e98f fe 1a CP CNTRLZ ;end of file mark? e991 ca 86 eb JP Z,GETBACK e994 cd 8c e4 CALL PRINT ;no, print it. e997 cd c2 e5 CALL CHKCON ;check console, quit if anything ready. e99a c2 86 eb JP NZ,GETBACK e99d c3 74 e9 JP TYPE1 e9a0 ; e9a0 ; Get here on an end of file or read error. e9a0 ; e9a0 3d TYPE4: DEC A ;read error? e9a1 ca 86 eb JP Z,GETBACK e9a4 cd d9 e7 CALL RDERROR ;yes, print message. e9a7 cd 66 e8 TYPE5: CALL RESETDR ;and reset proper drive e9aa c3 09 e6 JP SYNERR ;now print file name with problem. e9ad ; e9ad ;************************************************************** e9ad ;* e9ad ;* S A V E C O M M A N D e9ad ;* e9ad ;************************************************************** e9ad ; e9ad cd f8 e7 SAVE: CALL DECODE ;get numeric number that follows SAVE. e9b0 f5 PUSH AF ;save number of pages to write. e9b1 cd 5e e6 CALL CONVFST ;convert file name. e9b4 c2 09 e6 JP NZ,SYNERR ;wild cards not allowed. e9b7 cd 54 e8 CALL DSELECT ;select specified drive. e9ba 11 cd eb LD DE,FCB ;now delete this file. e9bd d5 PUSH DE e9be cd ef e4 CALL DELETE e9c1 d1 POP DE e9c2 cd 09 e5 CALL CREATE ;and create it again. e9c5 ca fb e9 JP Z,SAVE3 ;can't create? e9c8 af XOR A ;clear record number byte. e9c9 32 ed eb LD (FCB+32),A e9cc f1 POP AF ;convert pages to sectors. e9cd 6f LD L,A e9ce 26 00 LD H,0 e9d0 29 ADD HL,HL ;(HL)=number of sectors to write. e9d1 11 00 01 LD DE,TBASE ;and we start from here. e9d4 7c SAVE1: LD A,H ;done yet? e9d5 b5 OR L e9d6 ca f1 e9 JP Z,SAVE2 e9d9 2b DEC HL ;nope, count this and compute the start e9da e5 PUSH HL ;of the next 128 byte sector. e9db 21 80 00 LD HL,128 e9de 19 ADD HL,DE e9df e5 PUSH HL ;save it and set the transfer address. e9e0 cd d8 e5 CALL DMASET e9e3 11 cd eb LD DE,FCB ;write out this sector now. e9e6 cd 04 e5 CALL WRTREC e9e9 d1 POP DE ;reset (DE) to the start of the last sector. e9ea e1 POP HL ;restore sector count. e9eb c2 fb e9 JP NZ,SAVE3 ;write error? e9ee c3 d4 e9 JP SAVE1 e9f1 ; e9f1 ; Get here after writing all of the file. e9f1 ; e9f1 11 cd eb SAVE2: LD DE,FCB ;now close the file. e9f4 cd da e4 CALL CLOSE e9f7 3c INC A ;did it close ok? e9f8 c2 01 ea JP NZ,SAVE4 e9fb ; e9fb ; Print out error message (no space). e9fb ; e9fb 01 07 ea SAVE3: LD BC,NOSPACE e9fe cd a7 e4 CALL PLINE ea01 cd d5 e5 SAVE4: CALL STDDMA ;reset the standard dma address. ea04 c3 86 eb JP GETBACK ea07 .. NOSPACE:DEFM "No space" ea0f 00 DB 0 ea10 ; ea10 ;************************************************************** ea10 ;* ea10 ;* R E N A M E C O M M A N D ea10 ;* ea10 ;************************************************************** ea10 ; ea10 cd 5e e6 RENAME: CALL CONVFST ;convert first file name. ea13 c2 09 e6 JP NZ,SYNERR ;wild cards not allowed. ea16 3a f0 eb LD A,(CHGDRV) ;remember any change in drives specified. ea19 f5 PUSH AF ea1a cd 54 e8 CALL DSELECT ;and select this drive. ea1d cd e9 e4 CALL SRCHFCB ;is this file present? ea20 c2 79 ea JP NZ,RENAME6 ;yes, print error message. ea23 21 cd eb LD HL,FCB ;yes, move this name into second slot. ea26 11 dd eb LD DE,FCB+16 ea29 06 10 LD B,16 ea2b cd 42 e8 CALL HL2DE ea2e 2a 88 e4 LD HL,(INPOINT) ;get input pointer. ea31 eb EX DE,HL ea32 cd 4f e6 CALL NONBLANK ;get next non blank character. ea35 fe 3d CP '=' ;only allow an '=' or '_' seperator. ea37 ca 3f ea JP Z,RENAME1 ea3a fe 5f CP '_' ea3c c2 73 ea JP NZ,RENAME5 ea3f eb RENAME1:EX DE,HL ea40 23 INC HL ;ok, skip seperator. ea41 22 88 e4 LD (INPOINT),HL ;save input line pointer. ea44 cd 5e e6 CALL CONVFST ;convert this second file name now. ea47 c2 73 ea JP NZ,RENAME5 ;again, no wild cards. ea4a f1 POP AF ;if a drive was specified, then it ea4b 47 LD B,A ;must be the same as before. ea4c 21 f0 eb LD HL,CHGDRV ea4f 7e LD A,(HL) ea50 b7 OR A ea51 ca 59 ea JP Z,RENAME2 ea54 b8 CP B ea55 70 LD (HL),B ea56 c2 73 ea JP NZ,RENAME5 ;they were different, error. ea59 70 RENAME2:LD (HL),B ; reset as per the first file specification. ea5a af XOR A ea5b 32 cd eb LD (FCB),A ;clear the drive byte of the fcb. ea5e cd e9 e4 RENAME3:CALL SRCHFCB ;and go look for second file. ea61 ca 6d ea JP Z,RENAME4 ;doesn't exist? ea64 11 cd eb LD DE,FCB ea67 cd 0e e5 CALL RENAM ;ok, rename the file. ea6a c3 86 eb JP GETBACK ea6d ; ea6d ; Process rename errors here. ea6d ; ea6d cd ea e7 RENAME4:CALL NONE ;file not there. ea70 c3 86 eb JP GETBACK ea73 cd 66 e8 RENAME5:CALL RESETDR ;bad command format. ea76 c3 09 e6 JP SYNERR ea79 01 82 ea RENAME6:LD BC,EXISTS ;destination file already exists. ea7c cd a7 e4 CALL PLINE ea7f c3 86 eb JP GETBACK ea82 .. EXISTS: DEFM "File exists" ea8d 00 DB 0 ea8e ; ea8e ;************************************************************** ea8e ;* ea8e ;* U S E R C O M M A N D ea8e ;* ea8e ;************************************************************** ea8e ; ea8e cd f8 e7 USER: CALL DECODE ;get numeric value following command. ea91 fe 10 CP 16 ;legal user number? ea93 d2 09 e6 JP NC,SYNERR ea96 5f LD E,A ;yes but is there anything else? ea97 3a ce eb LD A,(FCB+1) ea9a fe 20 CP ' ' ea9c ca 09 e6 JP Z,SYNERR ;yes, that is not allowed. ea9f cd 15 e5 CALL GETSETUC ;ok, set user code. eaa2 c3 89 eb JP GETBACK1 eaa5 ; eaa5 ;************************************************************** eaa5 ;* eaa5 ;* T R A N S I A N T P R O G R A M C O M M A N D eaa5 ;* eaa5 ;************************************************************** eaa5 ; eaa5 cd f5 e5 UNKNOWN:CALL VERIFY ;check for valid system (why?). eaa8 3a ce eb LD A,(FCB+1) ;anything to execute? eaab fe 20 CP ' ' eaad c2 c4 ea JP NZ,UNKWN1 eab0 3a f0 eb LD A,(CHGDRV) ;nope, only a drive change? eab3 b7 OR A eab4 ca 89 eb JP Z,GETBACK1 ;neither??? eab7 3d DEC A eab8 32 ef eb LD (CDRIVE),A ;ok, store new drive. eabb cd 29 e5 CALL MOVECD ;set (TDRIVE) also. eabe cd bd e4 CALL DSKSEL ;and select this drive. eac1 c3 89 eb JP GETBACK1 ;then return. eac4 ; eac4 ; Here a file name was typed. Prepare to execute it. eac4 ; eac4 11 d6 eb UNKWN1: LD DE,FCB+9 ;an extension specified? eac7 1a LD A,(DE) eac8 fe 20 CP ' ' eaca c2 09 e6 JP NZ,SYNERR ;yes, not allowed. eacd d5 UNKWN2: PUSH DE eace cd 54 e8 CALL DSELECT ;select specified drive. ead1 d1 POP DE ead2 21 83 eb LD HL,COMFILE ;set the extension to 'COM'. ead5 cd 40 e8 CALL MOVE3 ead8 cd d0 e4 CALL OPENFCB ;and open this file. eadb ca 6b eb JP Z,UNKWN9 ;not present? eade ; eade ; Load in the program. eade ; eade 21 00 01 LD HL,TBASE ;store the program starting here. eae1 e5 UNKWN3: PUSH HL eae2 eb EX DE,HL eae3 cd d8 e5 CALL DMASET ;set transfer address. eae6 11 cd eb LD DE,FCB ;and read the next record. eae9 cd f9 e4 CALL RDREC eaec c2 01 eb JP NZ,UNKWN4 ;end of file or read error? eaef e1 POP HL ;nope, bump pointer for next sector. eaf0 11 80 00 LD DE,128 eaf3 19 ADD HL,DE eaf4 11 00 e4 LD DE,CBASE ;enough room for the whole file? eaf7 7d LD A,L eaf8 93 SUB E eaf9 7c LD A,H eafa 9a SBC A,D eafb d2 71 eb JP NC,UNKWN0 ;no, it can't fit. eafe c3 e1 ea JP UNKWN3 eb01 ; eb01 ; Get here after finished reading. eb01 ; eb01 e1 UNKWN4: POP HL eb02 3d DEC A ;normal end of file? eb03 c2 71 eb JP NZ,UNKWN0 eb06 cd 66 e8 CALL RESETDR ;yes, reset previous drive. eb09 cd 5e e6 CALL CONVFST ;convert the first file name that follows eb0c 21 f0 eb LD HL,CHGDRV ;command name. eb0f e5 PUSH HL eb10 7e LD A,(HL) ;set drive code in default fcb. eb11 32 cd eb LD (FCB),A eb14 3e 10 LD A,16 ;put second name 16 bytes later. eb16 cd 60 e6 CALL CONVERT ;convert second file name. eb19 e1 POP HL eb1a 7e LD A,(HL) ;and set the drive for this second file. eb1b 32 dd eb LD (FCB+16),A eb1e af XOR A ;clear record byte in fcb. eb1f 32 ed eb LD (FCB+32),A eb22 11 5c 00 LD DE,TFCB ;move it into place at(005Ch). eb25 21 cd eb LD HL,FCB eb28 06 21 LD B,33 eb2a cd 42 e8 CALL HL2DE eb2d 21 08 e4 LD HL,INBUFF+2 ;now move the remainder of the input eb30 7e UNKWN5: LD A,(HL) ;line down to (0080h). Look for a non blank. eb31 b7 OR A ;or a null. eb32 ca 3e eb JP Z,UNKWN6 eb35 fe 20 CP ' ' eb37 ca 3e eb JP Z,UNKWN6 eb3a 23 INC HL eb3b c3 30 eb JP UNKWN5 eb3e ; eb3e ; Do the line move now. It ends in a null byte. eb3e ; eb3e 06 00 UNKWN6: LD B,0 ;keep a character count. eb40 11 81 00 LD DE,TBUFF+1 ;data gets put here. eb43 7e UNKWN7: LD A,(HL) ;move it now. eb44 12 LD (DE),A eb45 b7 OR A eb46 ca 4f eb JP Z,UNKWN8 eb49 04 INC B eb4a 23 INC HL eb4b 13 INC DE eb4c c3 43 eb JP UNKWN7 eb4f 78 UNKWN8: LD A,B ;now store the character count. eb50 32 80 00 LD (TBUFF),A eb53 cd 98 e4 CALL CRLF ;clean up the screen. eb56 cd d5 e5 CALL STDDMA ;set standard transfer address. eb59 cd 1a e5 CALL SETCDRV ;reset current drive. eb5c cd 00 01 CALL TBASE ;and execute the program. eb5f ; eb5f ; Transiant programs return here (or reboot). eb5f ; eb5f 31 ab eb LD SP,BATCH ;set stack first off. eb62 cd 29 e5 CALL MOVECD ;move current drive into place (TDRIVE). eb65 cd bd e4 CALL DSKSEL ;and reselect it. eb68 c3 82 e7 JP CMMND1 ;back to comand mode. eb6b ; eb6b ; Get here if some error occured. eb6b ; eb6b cd 66 e8 UNKWN9: CALL RESETDR ;inproper format. eb6e c3 09 e6 JP SYNERR eb71 01 7a eb UNKWN0: LD BC,BADLOAD ;read error or won't fit. eb74 cd a7 e4 CALL PLINE eb77 c3 86 eb JP GETBACK eb7a .. BADLOAD:DEFM "Bad load" eb82 00 DB 0 eb83 .. COMFILE:DEFM "COM" ;command file extension. eb86 ; eb86 ; Get here to return to command level. We will reset the eb86 ; previous active drive and then either return to command eb86 ; level directly or print error message and then return. eb86 ; eb86 cd 66 e8 GETBACK:CALL RESETDR ;reset previous drive. eb89 cd 5e e6 GETBACK1: CALL CONVFST ;convert first name in (FCB). eb8c 3a ce eb LD A,(FCB+1) ;if this was just a drive change request, eb8f d6 20 SUB ' ' ;make sure it was valid. eb91 21 f0 eb LD HL,CHGDRV eb94 b6 OR (HL) eb95 c2 09 e6 JP NZ,SYNERR eb98 c3 82 e7 JP CMMND1 ;ok, return to command level. eb9b ; eb9b ; ccp stack area. eb9b ; eb9b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ebab CCPSTACK: EQU $ ;end of ccp stack area. ebab ; ebab ; Batch (or SUBMIT) processing information storage. ebab ; ebab 00 BATCH: DB 0 ;batch mode flag (0=not active). ebac 00 BATCHFCB: DB 0 ebad .. DEFM "$$$ SUB" ebb8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ebcd ; ebcd ; File control block setup by the CCP. ebcd ; ebcd 00 FCB: DB 0 ebce .. DEFM " " ebd9 00 00 00 00 00 DB 0,0,0,0,0 ebde .. DEFM " " ebe9 00 00 00 00 00 DB 0,0,0,0,0 ebee 00 RTNCODE:DB 0 ;status returned from bdos call. ebef 00 CDRIVE: DB 0 ;currently active drive. ebf0 00 CHGDRV: DB 0 ;change in drives flag (0=no change). ebf1 00 00 NBYTES: DW 0 ;byte counter used by TYPE. ebf3 ; ebf3 ; Room for expansion? ebf3 ; ebf3 00 00 00 00 00 00 00 00 00 00 00 00 00 DB 0,0,0,0,0,0,0,0,0,0,0,0,0 ec00 ; ec00 ; Note that the following six bytes must match those at ec00 ; (PATTRN1) or cp/m will HALT. Why? ec00 ; ec00 00 16 00 00 00 00 PATTRN2:DB 0,22,0,0,0,0 ;(* serial number bytes *). ec06 ; ec06 ;************************************************************** ec06 ;* ec06 ;* B D O S E N T R Y ec06 ;* ec06 ;************************************************************** ec06 ; ec06 c3 11 ec FBASE: JP FBASE1 ec09 ; ec09 ; Bdos error table. ec09 ; ec09 99 ec BADSCTR:DW ERROR1 ;bad sector on read or write. ec0b a5 ec BADSLCT:DW ERROR2 ;bad disk select. ec0d ab ec RODISK: DW ERROR3 ;disk is read only. ec0f b1 ec ROFILE: DW ERROR4 ;file is read only. ec11 ; ec11 ; Entry into bdos. (DE) or (E) are the parameters passed. The ec11 ; function number desired is in register (C). ec11 ; ec11 eb FBASE1: EX DE,HL ;save the (DE) parameters. ec12 22 45 ef LD (PARAMS),HL ec15 eb EX DE,HL ec16 7b LD A,E ;and save register (E) in particular. ec17 32 d8 f9 LD (EPARAM),A ec1a 21 00 00 LD HL,0 ec1d 22 47 ef LD (STATUS),HL ;clear return status. ec20 39 ADD HL,SP ec21 22 11 ef LD (USRSTACK),HL ;save users stack pointer. ec24 31 43 ef LD SP,STKAREA ;and set our own. ec27 af XOR A ;clear auto select storage space. ec28 32 e2 f9 LD (AUTOFLAG),A ec2b 32 e0 f9 LD (AUTO),A ec2e 21 76 f9 LD HL,GOBACK ;set return address. ec31 e5 PUSH HL ec32 79 LD A,C ;get function number. ec33 fe 29 CP NFUNCTS ;valid function number? ec35 d0 RET NC ec36 4b LD C,E ;keep single register function here. ec37 21 47 ec LD HL,FUNCTNS ;now look thru the function table. ec3a 5f LD E,A ec3b 16 00 LD D,0 ;(DE)=function number. ec3d 19 ADD HL,DE ec3e 19 ADD HL,DE ;(HL)=(start of table)+2*(function number). ec3f 5e LD E,(HL) ec40 23 INC HL ec41 56 LD D,(HL) ;now (DE)=address for this function. ec42 2a 45 ef LD HL,(PARAMS) ;retrieve parameters. ec45 eb EX DE,HL ;now (DE) has the original parameters. ec46 e9 JP (HL) ;execute desired function. ec47 ; ec47 ; BDOS function jump table. ec47 ; ec47 NFUNCTS: EQU 41 ;number of functions in followin table. ec47 ; ec47 03 fa ca ee 92 ed d0 ee 12 fa 0f fa d6 ee ef ee FUNCTNS:DW WBOOT,GETCON,OUTCON,GETRDR,PUNCH,LIST,DIRCIO,GETIOB ec57 f5 ee fa ee e3 ed 00 ef 80 f8 85 f8 47 f8 9e f8 DW SETIOB,PRTSTR,RDBUFF,GETCSTS,GETVER,RSTDSK,SETDSK,OPENFIL ec67 a7 f8 ad f8 ca f8 d9 f8 e2 f8 e8 f8 ee f8 DW CLOSEFIL,GETFST,GETNXT,DELFILE,READSEQ,WRTSEQ,FCREATE ec75 f7 f8 00 f9 06 f9 0c f9 13 f9 2e f1 19 f9 1f f9 DW RENFILE,GETLOG,GETCRNT,PUTDMA,GETALOC,WRTPRTD,GETROV,SETATTR ec85 28 f9 2f f9 43 f9 49 f9 4f f9 10 f8 55 f9 06 ef DW GETPARM,GETUSER,RDRANDOM,WTRANDOM,FILESIZE,SETRAN,LOGOFF,RTN ec95 06 ef 9d f9 DW RTN,WTSPECL ec99 ; ec99 ; Bdos error message section. ec99 ; ec99 21 cc ec ERROR1: LD HL,BADSEC ;bad sector message. ec9c cd e7 ec CALL PRTERR ;print it and get a 1 char responce. ec9f fe 03 CP CNTRLC ;re-boot request (control-c)? eca1 ca 00 00 JP Z,0 ;yes. eca4 c9 RET ;no, return to retry i/o function. eca5 ; eca5 21 d7 ec ERROR2: LD HL,BADSEL ;bad drive selected. eca8 c3 b4 ec JP ERROR5 ecab ; ecab 21 e3 ec ERROR3: LD HL,DISKRO ;disk is read only. ecae c3 b4 ec JP ERROR5 ecb1 ; ecb1 21 de ec ERROR4: LD HL,FILERO ;file is read only. ecb4 ; ecb4 cd e7 ec ERROR5: CALL PRTERR ecb7 c3 00 00 JP 0 ;always reboot on these errors. ecba ; ecba .. BDOSERR:DEFM "Bdos Err On " ecc6 22 20 3a 20 24 22 BDOSDRV:DEFM 022h,020h,03Ah,020h,024h,022h ;" : $" eccc .. BADSEC: DEFM "Bad Sector$" ecd7 .. BADSEL: DEFM "Select$" ecde .. FILERO: DEFM "File " ece3 .. DISKRO: DEFM "R/O$" ece7 ; ece7 ; Print bdos error message. ece7 ; ece7 e5 PRTERR: PUSH HL ;save second message pointer. ece8 cd cb ed CALL OUTCRLF ;send (cr)(lf). eceb 3a 44 ef LD A,(ACTIVE) ;get active drive. ecee c6 41 ADD A,'A' ;make ascii. ecf0 32 c6 ec LD (BDOSDRV),A ;and put in message. ecf3 01 ba ec LD BC,BDOSERR ;and print it. ecf6 cd d5 ed CALL PRTMESG ecf9 c1 POP BC ;print second message line now. ecfa cd d5 ed CALL PRTMESG ecfd ; ecfd ; Get an input character. We will check our 1 character ecfd ; buffer first. This may be set by the console status routine. ecfd ; ecfd 21 10 ef GETCHAR:LD HL,CHARBUF ;check character buffer. ed00 7e LD A,(HL) ;anything present already? ed01 36 00 LD (HL),0 ;...either case clear it. ed03 b7 OR A ed04 c0 RET NZ ;yes, use it. ed05 c3 09 fa JP CONIN ;nope, go get a character responce. ed08 ; ed08 ; Input and echo a character. ed08 ; ed08 cd fd ec GETECHO:CALL GETCHAR ;input a character. ed0b cd 16 ed CALL CHKCHAR ;carriage control? ed0e d8 RET C ;no, a regular control char so don't echo. ed0f f5 PUSH AF ;ok, save character now. ed10 4f LD C,A ed11 cd 92 ed CALL OUTCON ;and echo it. ed14 f1 POP AF ;get character and return. ed15 c9 RET ed16 ; ed16 ; Check character in (A). Set the zero flag on a carriage ed16 ; control character and the carry flag on any other control ed16 ; character. ed16 ; ed16 fe 0d CHKCHAR:CP CR ;check for carriage return, line feed, backspace, ed18 c8 RET Z ;or a tab. ed19 fe 0a CP LF ed1b c8 RET Z ed1c fe 09 CP TAB ed1e c8 RET Z ed1f fe 08 CP BS ed21 c8 RET Z ed22 fe 20 CP ' ' ;other control char? Set carry flag. ed24 c9 RET ed25 ; ed25 ; Check the console during output. Halt on a control-s, then ed25 ; reboot on a control-c. If anything else is ready, clear the ed25 ; zero flag and return (the calling routine may want to do ed25 ; something). ed25 ; ed25 3a 10 ef CKCONSOL: LD A,(CHARBUF) ;check buffer. ed28 b7 OR A ;if anything, just return without checking. ed29 c2 47 ed JP NZ,CKCON2 ed2c cd 06 fa CALL CONST ;nothing in buffer. Check console. ed2f e6 01 AND 01H ;look at bit 0. ed31 c8 RET Z ;return if nothing. ed32 cd 09 fa CALL CONIN ;ok, get it. ed35 fe 13 CP CNTRLS ;if not control-s, return with zero cleared. ed37 c2 44 ed JP NZ,CKCON1 ed3a cd 09 fa CALL CONIN ;halt processing until another char ed3d fe 03 CP CNTRLC ;is typed. Control-c? ed3f ca 00 00 JP Z,0 ;yes, reboot now. ed42 af XOR A ;no, just pretend nothing was ever ready. ed43 c9 RET ed44 32 10 ef CKCON1: LD (CHARBUF),A ;save character in buffer for later processing. ed47 3e 01 CKCON2: LD A,1 ;set (A) to non zero to mean something is ready. ed49 c9 RET ed4a ; ed4a ; Output (C) to the screen. If the printer flip-flop flag ed4a ; is set, we will send character to printer also. The console ed4a ; will be checked in the process. ed4a ; ed4a 3a 0c ef OUTCHAR:LD A,(OUTFLAG) ;check output flag. ed4d b7 OR A ;anything and we won't generate output. ed4e c2 64 ed JP NZ,OUTCHR1 ed51 c5 PUSH BC ed52 cd 25 ed CALL CKCONSOL ;check console (we don't care whats there). ed55 c1 POP BC ed56 c5 PUSH BC ed57 cd 0c fa CALL CONOUT ;output (C) to the screen. ed5a c1 POP BC ed5b c5 PUSH BC ed5c 3a 0f ef LD A,(PRTFLAG) ;check printer flip-flop flag. ed5f b7 OR A ed60 c4 0f fa CALL NZ,LIST ;print it also if non-zero. ed63 c1 POP BC ed64 79 OUTCHR1:LD A,C ;update cursors position. ed65 21 0e ef LD HL,CURPOS ed68 fe 7f CP DEL ;rubouts don't do anything here. ed6a c8 RET Z ed6b 34 INC (HL) ;bump line pointer. ed6c fe 20 CP ' ' ;and return if a normal character. ed6e d0 RET NC ed6f 35 DEC (HL) ;restore and check for the start of the line. ed70 7e LD A,(HL) ed71 b7 OR A ed72 c8 RET Z ;ingnore control characters at the start of the line. ed73 79 LD A,C ed74 fe 08 CP BS ;is it a backspace? ed76 c2 7b ed JP NZ,OUTCHR2 ed79 35 DEC (HL) ;yes, backup pointer. ed7a c9 RET ed7b fe 0a OUTCHR2:CP LF ;is it a line feed? ed7d c0 RET NZ ;ignore anything else. ed7e 36 00 LD (HL),0 ;reset pointer to start of line. ed80 c9 RET ed81 ; ed81 ; Output (A) to the screen. If it is a control character ed81 ; (other than carriage control), use ^x format. ed81 ; ed81 79 SHOWIT: LD A,C ed82 cd 16 ed CALL CHKCHAR ;check character. ed85 d2 92 ed JP NC,OUTCON ;not a control, use normal output. ed88 f5 PUSH AF ed89 0e 5e LD C,'^' ;for a control character, preceed it with '^'. ed8b cd 4a ed CALL OUTCHAR ed8e f1 POP AF ed8f f6 40 OR '@' ;and then use the letter equivelant. ed91 4f LD C,A ed92 ; ed92 ; Function to output (C) to the console device and expand tabs ed92 ; if necessary. ed92 ; ed92 79 OUTCON: LD A,C ed93 fe 09 CP TAB ;is it a tab? ed95 c2 4a ed JP NZ,OUTCHAR ;use regular output. ed98 0e 20 OUTCON1:LD C,' ' ;yes it is, use spaces instead. ed9a cd 4a ed CALL OUTCHAR ed9d 3a 0e ef LD A,(CURPOS) ;go until the cursor is at a multiple of 8 eda0 eda0 e6 07 AND 07H ;position. eda2 c2 98 ed JP NZ,OUTCON1 eda5 c9 RET eda6 ; eda6 ; Echo a backspace character. Erase the prevoius character eda6 ; on the screen. eda6 ; eda6 cd ae ed BACKUP: CALL BACKUP1 ;backup the screen 1 place. eda9 0e 20 LD C,' ' ;then blank that character. edab cd 0c fa CALL CONOUT edae 0e 08 BACKUP1:LD C,BS ;then back space once more. edb0 c3 0c fa JP CONOUT edb3 ; edb3 ; Signal a deleted line. Print a '#' at the end and start edb3 ; over. edb3 ; edb3 0e 23 NEWLINE:LD C,'#' edb5 cd 4a ed CALL OUTCHAR ;print this. edb8 cd cb ed CALL OUTCRLF ;start new line. edbb 3a 0e ef NEWLN1: LD A,(CURPOS) ;move the cursor to the starting position. edbe 21 0d ef LD HL,STARTING edc1 be CP (HL) edc2 d0 RET NC ;there yet? edc3 0e 20 LD C,' ' edc5 cd 4a ed CALL OUTCHAR ;nope, keep going. edc8 c3 bb ed JP NEWLN1 edcb ; edcb ; Output a (cr) (lf) to the console device (screen). edcb ; edcb 0e 0d OUTCRLF:LD C,CR edcd cd 4a ed CALL OUTCHAR edd0 0e 0a LD C,LF edd2 c3 4a ed JP OUTCHAR edd5 ; edd5 ; Print message pointed to by (BC). It will end with a '$'. edd5 ; edd5 0a PRTMESG:LD A,(BC) ;check for terminating character. edd6 fe 24 CP '$' edd8 c8 RET Z edd9 03 INC BC edda c5 PUSH BC ;otherwise, bump pointer and print it. eddb 4f LD C,A eddc cd 92 ed CALL OUTCON eddf c1 POP BC ede0 c3 d5 ed JP PRTMESG ede3 ; ede3 ; Function to execute a buffered read. ede3 ; ede3 3a 0e ef RDBUFF: LD A,(CURPOS) ;use present location as starting one. ede6 32 0d ef LD (STARTING),A ede9 2a 45 ef LD HL,(PARAMS) ;get the maximum buffer space. edec 4e LD C,(HL) eded 23 INC HL ;point to first available space. edee e5 PUSH HL ;and save. edef 06 00 LD B,0 ;keep a character count. edf1 c5 RDBUF1: PUSH BC edf2 e5 PUSH HL edf3 cd fd ec RDBUF2: CALL GETCHAR ;get the next input character. edf6 e6 7f AND 7FH ;strip bit 7. edf8 e1 POP HL ;reset registers. edf9 c1 POP BC edfa fe 0d CP CR ;en of the line? edfc ca c3 ee JP Z,RDBUF17 edff fe 0a CP LF ee01 ca c3 ee JP Z,RDBUF17 ee04 fe 08 CP BS ;how about a backspace? ee06 c2 18 ee JP NZ,RDBUF3 ee09 78 LD A,B ;yes, but ignore at the beginning of the line. ee0a b7 OR A ee0b ca f1 ed JP Z,RDBUF1 ee0e 05 DEC B ;ok, update counter. ee0f 3a 0e ef LD A,(CURPOS) ;if we backspace to the start of the line, ee12 32 0c ef LD (OUTFLAG),A ;treat as a cancel (control-x). ee15 c3 72 ee JP RDBUF10 ee18 fe 7f RDBUF3: CP DEL ;user typed a rubout? ee1a c2 28 ee JP NZ,RDBUF4 ee1d 78 LD A,B ;ignore at the start of the line. ee1e b7 OR A ee1f ca f1 ed JP Z,RDBUF1 ee22 7e LD A,(HL) ;ok, echo the prevoius character. ee23 05 DEC B ;and reset pointers (counters). ee24 2b DEC HL ee25 c3 ab ee JP RDBUF15 ee28 fe 05 RDBUF4: CP CNTRLE ;physical end of line? ee2a c2 39 ee JP NZ,RDBUF5 ee2d c5 PUSH BC ;yes, do it. ee2e e5 PUSH HL ee2f cd cb ed CALL OUTCRLF ee32 af XOR A ;and update starting position. ee33 32 0d ef LD (STARTING),A ee36 c3 f3 ed JP RDBUF2 ee39 fe 10 RDBUF5: CP CNTRLP ;control-p? ee3b c2 4a ee JP NZ,RDBUF6 ee3e e5 PUSH HL ;yes, flip the print flag filp-flop byte. ee3f 21 0f ef LD HL,PRTFLAG ee42 3e 01 LD A,1 ;PRTFLAG=1-PRTFLAG ee44 96 SUB (HL) ee45 77 LD (HL),A ee46 e1 POP HL ee47 c3 f1 ed JP RDBUF1 ee4a fe 18 RDBUF6: CP CNTRLX ;control-x (cancel)? ee4c c2 61 ee JP NZ,RDBUF8 ee4f e1 POP HL ee50 3a 0d ef RDBUF7: LD A,(STARTING) ;yes, backup the cursor to here. ee53 21 0e ef LD HL,CURPOS ee56 be CP (HL) ee57 d2 e3 ed JP NC,RDBUFF ;done yet? ee5a 35 DEC (HL) ;no, decrement pointer and output back up one space. ee5b cd a6 ed CALL BACKUP ee5e c3 50 ee JP RDBUF7 ee61 fe 15 RDBUF8: CP CNTRLU ;cntrol-u (cancel line)? ee63 c2 6d ee JP NZ,RDBUF9 ee66 cd b3 ed CALL NEWLINE ;start a new line. ee69 e1 POP HL ee6a c3 e3 ed JP RDBUFF ee6d fe 12 RDBUF9: CP CNTRLR ;control-r? ee6f c2 a8 ee JP NZ,RDBUF14 ee72 c5 RDBUF10:PUSH BC ;yes, start a new line and retype the old one. ee73 cd b3 ed CALL NEWLINE ee76 c1 POP BC ee77 e1 POP HL ee78 e5 PUSH HL ee79 c5 PUSH BC ee7a 78 RDBUF11:LD A,B ;done whole line yet? ee7b b7 OR A ee7c ca 8c ee JP Z,RDBUF12 ee7f 23 INC HL ;nope, get next character. ee80 4e LD C,(HL) ee81 05 DEC B ;count it. ee82 c5 PUSH BC ee83 e5 PUSH HL ee84 cd 81 ed CALL SHOWIT ;and display it. ee87 e1 POP HL ee88 c1 POP BC ee89 c3 7a ee JP RDBUF11 ee8c e5 RDBUF12:PUSH HL ;done with line. If we were displaying ee8d 3a 0c ef LD A,(OUTFLAG) ;then update cursor position. ee90 b7 OR A ee91 ca f3 ed JP Z,RDBUF2 ee94 21 0e ef LD HL,CURPOS ;because this line is shorter, we must ee97 96 SUB (HL) ;back up the cursor (not the screen however) ee98 32 0c ef LD (OUTFLAG),A ;some number of positions. ee9b cd a6 ed RDBUF13:CALL BACKUP ;note that as long as (OUTFLAG) is non ee9e 21 0c ef LD HL,OUTFLAG ;zero, the screen will not be changed. eea1 35 DEC (HL) eea2 c2 9b ee JP NZ,RDBUF13 eea5 c3 f3 ed JP RDBUF2 ;now just get the next character. eea8 ; eea8 ; Just a normal character, put this in our buffer and echo. eea8 ; eea8 23 RDBUF14:INC HL eea9 77 LD (HL),A ;store character. eeaa 04 INC B ;and count it. eeab c5 RDBUF15:PUSH BC eeac e5 PUSH HL eead 4f LD C,A ;echo it now. eeae cd 81 ed CALL SHOWIT eeb1 e1 POP HL eeb2 c1 POP BC eeb3 7e LD A,(HL) ;was it an abort request? eeb4 fe 03 CP CNTRLC ;control-c abort? eeb6 78 LD A,B eeb7 c2 bf ee JP NZ,RDBUF16 eeba fe 01 CP 1 ;only if at start of line. eebc ca 00 00 JP Z,0 eebf b9 RDBUF16:CP C ;nope, have we filled the buffer? eec0 da f1 ed JP C,RDBUF1 eec3 e1 RDBUF17:POP HL ;yes end the line and return. eec4 70 LD (HL),B eec5 0e 0d LD C,CR eec7 c3 4a ed JP OUTCHAR ;output (cr) and return. eeca ; eeca ; Function to get a character from the console device. eeca ; eeca cd 08 ed GETCON: CALL GETECHO ;get and echo. eecd c3 03 ef JP SETSTAT ;save status and return. eed0 ; eed0 ; Function to get a character from the tape reader device. eed0 ; eed0 cd 15 fa GETRDR: CALL READER ;get a character from reader, set status and return. eed3 c3 03 ef JP SETSTAT eed6 ; eed6 ; Function to perform direct console i/o. If (C) contains (FF) eed6 ; then this is an input request. If (C) contains (FE) then eed6 ; this is a status request. Otherwise we are to output (C). eed6 ; eed6 79 DIRCIO: LD A,C ;test for (FF). eed7 3c INC A eed8 ca e2 ee JP Z,DIRC1 eedb 3c INC A ;test for (FE). eedc ca 06 fa JP Z,CONST eedf c3 0c fa JP CONOUT ;just output (C). eee2 cd 06 fa DIRC1: CALL CONST ;this is an input request. eee5 b7 OR A eee6 ca 93 f9 JP Z,GOBACK1 ;not ready? Just return (directly). eee9 cd 09 fa CALL CONIN ;yes, get character. eeec c3 03 ef JP SETSTAT ;set status and return. eeef ; eeef ; Function to return the i/o byte. eeef ; eeef 3a 03 00 GETIOB: LD A,(IOBYTE) eef2 c3 03 ef JP SETSTAT eef5 ; eef5 ; Function to set the i/o byte. eef5 ; eef5 21 03 00 SETIOB: LD HL,IOBYTE eef8 71 LD (HL),C eef9 c9 RET eefa ; eefa ; Function to print the character string pointed to by (DE) eefa ; on the console device. The string ends with a '$'. eefa ; eefa eb PRTSTR: EX DE,HL eefb 4d LD C,L eefc 44 LD B,H ;now (BC) points to it. eefd c3 d5 ed JP PRTMESG ef00 ; ef00 ; Function to interigate the console device. ef00 ; ef00 cd 25 ed GETCSTS:CALL CKCONSOL ef03 ; ef03 ; Get here to set the status and return to the cleanup ef03 ; section. Then back to the user. ef03 ; ef03 32 47 ef SETSTAT:LD (STATUS),A ef06 c9 RTN: RET ef07 ; ef07 ; Set the status to 1 (read or write error code). ef07 ; ef07 3e 01 IOERR1: LD A,1 ef09 c3 03 ef JP SETSTAT ef0c ; ef0c 00 OUTFLAG:DB 0 ;output flag (non zero means no output). ef0d 02 STARTING: DB 2 ;starting position for cursor. ef0e 00 CURPOS: DB 0 ;cursor position (0=start of line). ef0f 00 PRTFLAG:DB 0 ;printer flag (control-p toggle). List if non zero. ef10 00 CHARBUF:DB 0 ;single input character buffer. ef11 ; ef11 ; Stack area for BDOS calls. ef11 ; ef11 00 00 USRSTACK: DW 0 ;save users stack pointer here. ef13 ; ef13 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ef2b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ef43 STKAREA: EQU $ ;end of stack area. ef43 ; ef43 00 USERNO: DB 0 ;current user number. ef44 00 ACTIVE: DB 0 ;currently active drive. ef45 00 00 PARAMS: DW 0 ;save (DE) parameters here on entry. ef47 00 00 STATUS: DW 0 ;status returned from bdos function. ef49 ; ef49 ; Select error occured, jump to error routine. ef49 ; ef49 21 0b ec SLCTERR:LD HL,BADSLCT ef4c ; ef4c ; Jump to (HL) indirectly. ef4c ; ef4c 5e JUMPHL: LD E,(HL) ef4d 23 INC HL ef4e 56 LD D,(HL) ;now (DE) contain the desired address. ef4f eb EX DE,HL ef50 e9 JP (HL) ef51 ; ef51 ; Block move. (DE) to (HL), (C) bytes total. ef51 ; ef51 0c DE2HL: INC C ;is count down to zero? ef52 0d DE2HL1: DEC C ef53 c8 RET Z ;yes, we are done. ef54 1a LD A,(DE) ;no, move one more byte. ef55 77 LD (HL),A ef56 13 INC DE ef57 23 INC HL ef58 c3 52 ef JP DE2HL1 ;and repeat. ef5b ; ef5b ; Select the desired drive. ef5b ; ef5b 3a 44 ef SELECT: LD A,(ACTIVE) ;get active disk. ef5e 4f LD C,A ef5f cd 1b fa CALL SELDSK ;select it. ef62 7c LD A,H ;valid drive? ef63 b5 OR L ;valid drive? ef64 c8 RET Z ;return if not. ef65 ; ef65 ; Here, the BIOS returned the address of the parameter block ef65 ; in (HL). We will extract the necessary pointers and save them. ef65 ; ef65 5e LD E,(HL) ;yes, get address of translation table into (DE). ef66 23 INC HL ef67 56 LD D,(HL) ef68 23 INC HL ef69 22 b5 f9 LD (SCRATCH1),HL ;save pointers to scratch areas. ef6c 23 INC HL ef6d 23 INC HL ef6e 22 b7 f9 LD (SCRATCH2),HL ;ditto. ef71 23 INC HL ef72 23 INC HL ef73 22 b9 f9 LD (SCRATCH3),HL ;ditto. ef76 23 INC HL ef77 23 INC HL ef78 eb EX DE,HL ;now save the translation table address. ef79 22 d2 f9 LD (XLATE),HL ef7c 21 bb f9 LD HL,DIRBUF ;put the next 8 bytes here. ef7f 0e 08 LD C,8 ;they consist of the directory buffer ef81 cd 51 ef CALL DE2HL ;pointer, parameter block pointer, ef84 2a bd f9 LD HL,(DISKPB) ;check and allocation vectors. ef87 eb EX DE,HL ef88 21 c3 f9 LD HL,SECTORS ;move parameter block into our ram. ef8b 0e 0f LD C,15 ;it is 15 bytes long. ef8d cd 51 ef CALL DE2HL ef90 2a c8 f9 LD HL,(DSKSIZE) ;check disk size. ef93 7c LD A,H ;more than 256 blocks on this? ef94 21 df f9 LD HL,BIGDISK ef97 36 ff LD (HL),0FFH ;set to samll. ef99 b7 OR A ef9a ca 9f ef JP Z,SELECT1 ef9d 36 00 LD (HL),0 ;wrong, set to large. ef9f 3e ff SELECT1:LD A,0FFH ;clear the zero flag. efa1 b7 OR A efa2 c9 RET efa3 ; efa3 ; Routine to home the disk track head and clear pointers. efa3 ; efa3 cd 18 fa HOMEDRV:CALL HOME ;home the head. efa6 af XOR A efa7 2a b7 f9 LD HL,(SCRATCH2) ;set our track pointer also. efaa 77 LD (HL),A efab 23 INC HL efac 77 LD (HL),A efad 2a b9 f9 LD HL,(SCRATCH3) ;and our sector pointer. efb0 77 LD (HL),A efb1 23 INC HL efb2 77 LD (HL),A efb3 c9 RET efb4 ; efb4 ; Do the actual disk read and check the error return status. efb4 ; efb4 cd 27 fa DOREAD: CALL READ efb7 c3 bd ef JP IORET efba ; efba ; Do the actual disk write and handle any bios error. efba ; efba cd 2a fa DOWRITE:CALL WRITE efbd b7 IORET: OR A efbe c8 RET Z ;return unless an error occured. efbf 21 09 ec LD HL,BADSCTR ;bad read/write on this sector. efc2 c3 4c ef JP JUMPHL efc5 ; efc5 ; Routine to select the track and sector that the desired efc5 ; block number falls in. efc5 ; efc5 2a ec f9 TRKSEC: LD HL,(FILEPOS) ;get position of last accessed file efc8 0e 02 LD C,2 ;in directory and compute sector #. efca cd ec f0 CALL SHIFTR ;sector #=file-position/4. efcd 22 e7 f9 LD (BLKNMBR),HL ;save this as the block number of interest. efd0 22 ee f9 LD (CKSUMTBL),HL ;what's it doing here too? efd3 ; efd3 ; if the sector number has already been set (BLKNMBR), enter efd3 ; at this point. efd3 ; efd3 21 e7 f9 TRKSEC1:LD HL,BLKNMBR efd6 4e LD C,(HL) ;move sector number into (BC). efd7 23 INC HL efd8 46 LD B,(HL) efd9 2a b9 f9 LD HL,(SCRATCH3) ;get current sector number and efdc 5e LD E,(HL) ;move this into (DE). efdd 23 INC HL efde 56 LD D,(HL) efdf 2a b7 f9 LD HL,(SCRATCH2) ;get current track number. efe2 7e LD A,(HL) ;and this into (HL). efe3 23 INC HL efe4 66 LD H,(HL) efe5 6f LD L,A efe6 79 TRKSEC2:LD A,C ;is desired sector before current one? efe7 93 SUB E efe8 78 LD A,B efe9 9a SBC A,D efea d2 fc ef JP NC,TRKSEC3 efed e5 PUSH HL ;yes, decrement sectors by one track. efee 2a c3 f9 LD HL,(SECTORS) ;get sectors per track. eff1 7b LD A,E eff2 95 SUB L eff3 5f LD E,A eff4 7a LD A,D eff5 9c SBC A,H eff6 57 LD D,A ;now we have backed up one full track. eff7 e1 POP HL eff8 2b DEC HL ;adjust track counter. eff9 c3 e6 ef JP TRKSEC2 effc e5 TRKSEC3:PUSH HL ;desired sector is after current one. effd 2a c3 f9 LD HL,(SECTORS) ;get sectors per track. f000 19 ADD HL,DE ;bump sector pointer to next track. f001 da 11 f0 JP C,TRKSEC4 f004 79 LD A,C ;is desired sector now before current one? f005 95 SUB L f006 78 LD A,B f007 9c SBC A,H f008 da 11 f0 JP C,TRKSEC4 f00b eb EX DE,HL ;not yes, increment track counter f00c e1 POP HL ;and continue until it is. f00d 23 INC HL f00e c3 fc ef JP TRKSEC3 f011 ; f011 ; here we have determined the track number that contains the f011 ; desired sector. f011 ; f011 e1 TRKSEC4:POP HL ;get track number (HL). f012 c5 PUSH BC f013 d5 PUSH DE f014 e5 PUSH HL f015 eb EX DE,HL f016 2a d0 f9 LD HL,(OFFSET) ;adjust for first track offset. f019 19 ADD HL,DE f01a 44 LD B,H f01b 4d LD C,L f01c cd 1e fa CALL SETTRK ;select this track. f01f d1 POP DE ;reset current track pointer. f020 2a b7 f9 LD HL,(SCRATCH2) f023 73 LD (HL),E f024 23 INC HL f025 72 LD (HL),D f026 d1 POP DE f027 2a b9 f9 LD HL,(SCRATCH3) ;reset the first sector on this track. f02a 73 LD (HL),E f02b 23 INC HL f02c 72 LD (HL),D f02d c1 POP BC f02e 79 LD A,C ;now subtract the desired one. f02f 93 SUB E ;to make it relative (1-# sectors/track). f030 4f LD C,A f031 78 LD A,B f032 9a SBC A,D f033 47 LD B,A f034 2a d2 f9 LD HL,(XLATE) ;translate this sector according to this table. f037 eb EX DE,HL f038 cd 30 fa CALL SECTRN ;let the bios translate it. f03b 4d LD C,L f03c 44 LD B,H f03d c3 21 fa JP SETSEC ;and select it. f040 ; f040 ; Compute block number from record number (SAVNREC) and f040 ; extent number (SAVEXT). f040 ; f040 21 c5 f9 GETBLOCK: LD HL,BLKSHFT ;get logical to physical conversion. f043 4e LD C,(HL) ;note that this is base 2 log of ratio. f044 3a e5 f9 LD A,(SAVNREC) ;get record number. f047 b7 GETBLK1:OR A ;compute (A)=(A)/2^BLKSHFT. f048 1f RRA f049 0d DEC C f04a c2 47 f0 JP NZ,GETBLK1 f04d 47 LD B,A ;save result in (B). f04e 3e 08 LD A,8 f050 96 SUB (HL) f051 4f LD C,A ;compute (C)=8-BLKSHFT. f052 3a e4 f9 LD A,(SAVEXT) f055 0d GETBLK2:DEC C ;compute (A)=SAVEXT*2^(8-BLKSHFT). f056 ca 5e f0 JP Z,GETBLK3 f059 b7 OR A f05a 17 RLA f05b c3 55 f0 JP GETBLK2 f05e 80 GETBLK3:ADD A,B f05f c9 RET f060 ; f060 ; Routine to extract the (BC) block byte from the fcb pointed f060 ; to by (PARAMS). If this is a big-disk, then these are 16 bit f060 ; block numbers, else they are 8 bit numbers. f060 ; Number is returned in (HL). f060 ; f060 2a 45 ef EXTBLK: LD HL,(PARAMS) ;get fcb address. f063 11 10 00 LD DE,16 ;block numbers start 16 bytes into fcb. f066 19 ADD HL,DE f067 09 ADD HL,BC f068 3a df f9 LD A,(BIGDISK) ;are we using a big-disk? f06b b7 OR A f06c ca 73 f0 JP Z,EXTBLK1 f06f 6e LD L,(HL) ;no, extract an 8 bit number from the fcb. f070 26 00 LD H,0 f072 c9 RET f073 09 EXTBLK1:ADD HL,BC ;yes, extract a 16 bit number. f074 5e LD E,(HL) f075 23 INC HL f076 56 LD D,(HL) f077 eb EX DE,HL ;return in (HL). f078 c9 RET f079 ; f079 ; Compute block number. f079 ; f079 cd 40 f0 COMBLK: CALL GETBLOCK f07c 4f LD C,A f07d 06 00 LD B,0 f07f cd 60 f0 CALL EXTBLK f082 22 e7 f9 LD (BLKNMBR),HL f085 c9 RET f086 ; f086 ; Check for a zero block number (unused). f086 ; f086 2a e7 f9 CHKBLK: LD HL,(BLKNMBR) f089 7d LD A,L ;is it zero? f08a b4 OR H f08b c9 RET f08c ; f08c ; Adjust physical block (BLKNMBR) and convert to logical f08c ; sector (LOGSECT). This is the starting sector of this block. f08c ; The actual sector of interest is then added to this and the f08c ; resulting sector number is stored back in (BLKNMBR). This f08c ; will still have to be adjusted for the track number. f08c ; f08c 3a c5 f9 LOGICAL:LD A,(BLKSHFT) ;get log2(physical/logical sectors). f08f 2a e7 f9 LD HL,(BLKNMBR) ;get physical sector desired. f092 29 LOGICL1:ADD HL,HL ;compute logical sector number. f093 3d DEC A ;note logical sectors are 128 bytes long. f094 c2 92 f0 JP NZ,LOGICL1 f097 22 e9 f9 LD (LOGSECT),HL ;save logical sector. f09a 3a c6 f9 LD A,(BLKMASK) ;get block mask. f09d 4f LD C,A f09e 3a e5 f9 LD A,(SAVNREC) ;get next sector to access. f0a1 a1 AND C ;extract the relative position within physical block. f0a2 b5 OR L ;and add it too logical sector. f0a3 6f LD L,A f0a4 22 e7 f9 LD (BLKNMBR),HL ;and store. f0a7 c9 RET f0a8 ; f0a8 ; Set (HL) to point to extent byte in fcb. f0a8 ; f0a8 2a 45 ef SETEXT: LD HL,(PARAMS) f0ab 11 0c 00 LD DE,12 ;it is the twelth byte. f0ae 19 ADD HL,DE f0af c9 RET f0b0 ; f0b0 ; Set (HL) to point to record count byte in fcb and (DE) to f0b0 ; next record number byte. f0b0 ; f0b0 2a 45 ef SETHLDE:LD HL,(PARAMS) f0b3 11 0f 00 LD DE,15 ;record count byte (#15). f0b6 19 ADD HL,DE f0b7 eb EX DE,HL f0b8 21 11 00 LD HL,17 ;next record number (#32). f0bb 19 ADD HL,DE f0bc c9 RET f0bd ; f0bd ; Save current file data from fcb. f0bd ; f0bd cd b0 f0 STRDATA:CALL SETHLDE f0c0 7e LD A,(HL) ;get and store record count byte. f0c1 32 e5 f9 LD (SAVNREC),A f0c4 eb EX DE,HL f0c5 7e LD A,(HL) ;get and store next record number byte. f0c6 32 e3 f9 LD (SAVNXT),A f0c9 cd a8 f0 CALL SETEXT ;point to extent byte. f0cc 3a c7 f9 LD A,(EXTMASK) ;get extent mask. f0cf a6 AND (HL) f0d0 32 e4 f9 LD (SAVEXT),A ;and save extent here. f0d3 c9 RET f0d4 ; f0d4 ; Set the next record to access. If (MODE) is set to 2, then f0d4 ; the last record byte (SAVNREC) has the correct number to access. f0d4 ; For sequential access, (MODE) will be equal to 1. f0d4 ; f0d4 cd b0 f0 SETNREC:CALL SETHLDE f0d7 3a d7 f9 LD A,(MODE) ;get sequential flag (=1). f0da fe 02 CP 2 ;a 2 indicates that no adder is needed. f0dc c2 e0 f0 JP NZ,STNREC1 f0df af XOR A ;clear adder (random access?). f0e0 4f STNREC1:LD C,A f0e1 3a e5 f9 LD A,(SAVNREC) ;get last record number. f0e4 81 ADD A,C ;increment record count. f0e5 77 LD (HL),A ;and set fcb's next record byte. f0e6 eb EX DE,HL f0e7 3a e3 f9 LD A,(SAVNXT) ;get next record byte from storage. f0ea 77 LD (HL),A ;and put this into fcb as number of records used. f0eb c9 RET f0ec ; f0ec ; Shift (HL) right (C) bits. f0ec ; f0ec 0c SHIFTR: INC C f0ed 0d SHIFTR1:DEC C f0ee c8 RET Z f0ef 7c LD A,H f0f0 b7 OR A f0f1 1f RRA f0f2 67 LD H,A f0f3 7d LD A,L f0f4 1f RRA f0f5 6f LD L,A f0f6 c3 ed f0 JP SHIFTR1 f0f9 ; f0f9 ; Compute the check-sum for the directory buffer. Return f0f9 ; integer sum in (A). f0f9 ; f0f9 0e 80 CHECKSUM: LD C,128 ;length of buffer. f0fb 2a bb f9 LD HL,(DIRBUF) ;get its location. f0fe af XOR A ;clear summation byte. f0ff 86 CHKSUM1:ADD A,(HL) ;and compute sum ignoring carries. f100 23 INC HL f101 0d DEC C f102 c2 ff f0 JP NZ,CHKSUM1 f105 c9 RET f106 ; f106 ; Shift (HL) left (C) bits. f106 ; f106 0c SHIFTL: INC C f107 0d SHIFTL1:DEC C f108 c8 RET Z f109 29 ADD HL,HL ;shift left 1 bit. f10a c3 07 f1 JP SHIFTL1 f10d ; f10d ; Routine to set a bit in a 16 bit value contained in (BC). f10d ; The bit set depends on the current drive selection. f10d ; f10d c5 SETBIT: PUSH BC ;save 16 bit word. f10e 3a 44 ef LD A,(ACTIVE) ;get active drive. f111 4f LD C,A f112 21 01 00 LD HL,1 f115 cd 06 f1 CALL SHIFTL ;shift bit 0 into place. f118 c1 POP BC ;now 'or' this with the original word. f119 79 LD A,C f11a b5 OR L f11b 6f LD L,A ;low byte done, do high byte. f11c 78 LD A,B f11d b4 OR H f11e 67 LD H,A f11f c9 RET f120 ; f120 ; Extract the write protect status bit for the current drive. f120 ; The result is returned in (A), bit 0. f120 ; f120 2a af f9 GETWPRT:LD HL,(WRTPRT) ;get status bytes. f123 3a 44 ef LD A,(ACTIVE) ;which drive is current? f126 4f LD C,A f127 cd ec f0 CALL SHIFTR ;shift status such that bit 0 is the f12a 7d LD A,L ;one of interest for this drive. f12b e6 01 AND 01H ;and isolate it. f12d c9 RET f12e ; f12e ; Function to write protect the current disk. f12e ; f12e 21 af f9 WRTPRTD:LD HL,WRTPRT ;point to status word. f131 4e LD C,(HL) ;set (BC) equal to the status. f132 23 INC HL f133 46 LD B,(HL) f134 cd 0d f1 CALL SETBIT ;and set this bit according to current drive. f137 22 af f9 LD (WRTPRT),HL ;then save. f13a 2a ca f9 LD HL,(DIRSIZE) ;now save directory size limit. f13d 23 INC HL ;remember the last one. f13e eb EX DE,HL f13f 2a b5 f9 LD HL,(SCRATCH1) ;and store it here. f142 73 LD (HL),E ;put low byte. f143 23 INC HL f144 72 LD (HL),D ;then high byte. f145 c9 RET f146 ; f146 ; Check for a read only file. f146 ; f146 cd 60 f1 CHKROFL:CALL FCB2HL ;set (HL) to file entry in directory buffer. f149 11 09 00 CKROF1: LD DE,9 ;look at bit 7 of the ninth byte. f14c 19 ADD HL,DE f14d 7e LD A,(HL) f14e 17 RLA f14f d0 RET NC ;return if ok. f150 21 0f ec LD HL,ROFILE ;else, print error message and terminate. f153 c3 4c ef JP JUMPHL f156 ; f156 ; Check the write protect status of the active disk. f156 ; f156 cd 20 f1 CHKWPRT:CALL GETWPRT f159 c8 RET Z ;return if ok. f15a 21 0d ec LD HL,RODISK ;else print message and terminate. f15d c3 4c ef JP JUMPHL f160 ; f160 ; Routine to set (HL) pointing to the proper entry in the f160 ; directory buffer. f160 ; f160 2a bb f9 FCB2HL: LD HL,(DIRBUF) ;get address of buffer. f163 3a eb f9 LD A,(FCBPOS) ;relative position of file. f166 ; f166 ; Routine to add (A) to (HL). f166 ; f166 85 ADDA2HL:ADD A,L f167 6f LD L,A f168 d0 RET NC f169 24 INC H ;take care of any carry. f16a c9 RET f16b ; f16b ; Routine to get the 's2' byte from the fcb supplied in f16b ; the initial parameter specification. f16b ; f16b 2a 45 ef GETS2: LD HL,(PARAMS) ;get address of fcb. f16e 11 0e 00 LD DE,14 ;relative position of 's2'. f171 19 ADD HL,DE f172 7e LD A,(HL) ;extract this byte. f173 c9 RET f174 ; f174 ; Clear the 's2' byte in the fcb. f174 ; f174 cd 6b f1 CLEARS2:CALL GETS2 ;this sets (HL) pointing to it. f177 36 00 LD (HL),0 ;now clear it. f179 c9 RET f17a ; f17a ; Set bit 7 in the 's2' byte of the fcb. f17a ; f17a cd 6b f1 SETS2B7:CALL GETS2 ;get the byte. f17d f6 80 OR 80H ;and set bit 7. f17f 77 LD (HL),A ;then store. f180 c9 RET f181 ; f181 ; Compare (FILEPOS) with (SCRATCH1) and set flags based on f181 ; the difference. This checks to see if there are more file f181 ; names in the directory. We are at (FILEPOS) and there are f181 ; (SCRATCH1) of them to check. f181 ; f181 2a ec f9 MOREFLS:LD HL,(FILEPOS) ;we are here. f184 eb EX DE,HL f185 2a b5 f9 LD HL,(SCRATCH1) ;and don't go past here. f188 7b LD A,E ;compute difference but don't keep. f189 96 SUB (HL) f18a 23 INC HL f18b 7a LD A,D f18c 9e SBC A,(HL) ;set carry if no more names. f18d c9 RET f18e ; f18e ; Call this routine to prevent (SCRATCH1) from being greater f18e ; than (FILEPOS). f18e ; f18e cd 81 f1 CHKNMBR:CALL MOREFLS ;SCRATCH1 too big? f191 d8 RET C f192 13 INC DE ;yes, reset it to (FILEPOS). f193 72 LD (HL),D f194 2b DEC HL f195 73 LD (HL),E f196 c9 RET f197 ; f197 ; Compute (HL)=(DE)-(HL) f197 ; f197 7b SUBHL: LD A,E ;compute difference. f198 95 SUB L f199 6f LD L,A ;store low byte. f19a 7a LD A,D f19b 9c SBC A,H f19c 67 LD H,A ;and then high byte. f19d c9 RET f19e ; f19e ; Set the directory checksum byte. f19e ; f19e 0e ff SETDIR: LD C,0FFH f1a0 ; f1a0 ; Routine to set or compare the directory checksum byte. If f1a0 ; (C)=0ffh, then this will set the checksum byte. Else the byte f1a0 ; will be checked. If the check fails (the disk has been changed), f1a0 ; then this disk will be write protected. f1a0 ; f1a0 2a ee f9 CHECKDIR: LD HL,(CKSUMTBL) f1a3 eb EX DE,HL f1a4 2a ce f9 LD HL,(ALLOC1) f1a7 cd 97 f1 CALL SUBHL f1aa d0 RET NC ;ok if (CKSUMTBL) > (ALLOC1), so return. f1ab c5 PUSH BC f1ac cd f9 f0 CALL CHECKSUM ;else compute checksum. f1af 2a bf f9 LD HL,(CHKVECT) ;get address of checksum table. f1b2 eb EX DE,HL f1b3 2a ee f9 LD HL,(CKSUMTBL) f1b6 19 ADD HL,DE ;set (HL) to point to byte for this drive. f1b7 c1 POP BC f1b8 0c INC C ;set or check ? f1b9 ca c6 f1 JP Z,CHKDIR1 f1bc be CP (HL) ;check them. f1bd c8 RET Z ;return if they are the same. f1be cd 81 f1 CALL MOREFLS ;not the same, do we care? f1c1 d0 RET NC f1c2 cd 2e f1 CALL WRTPRTD ;yes, mark this as write protected. f1c5 c9 RET f1c6 77 CHKDIR1:LD (HL),A ;just set the byte. f1c7 c9 RET f1c8 ; f1c8 ; Do a write to the directory of the current disk. f1c8 ; f1c8 cd 9e f1 DIRWRITE: CALL SETDIR ;set checksum byte. f1cb cd e2 f1 CALL DIRDMA ;set directory dma address. f1ce 0e 01 LD C,1 ;tell the bios to actually write. f1d0 cd ba ef CALL DOWRITE ;then do the write. f1d3 c3 dc f1 JP DEFDMA f1d6 ; f1d6 ; Read from the directory. f1d6 ; f1d6 cd e2 f1 DIRREAD:CALL DIRDMA ;set the directory dma address. f1d9 cd b4 ef CALL DOREAD ;and read it. f1dc ; f1dc ; Routine to set the dma address to the users choice. f1dc ; f1dc 21 b3 f9 DEFDMA: LD HL,USERDMA ;reset the default dma address and return. f1df c3 e5 f1 JP DIRDMA1 f1e2 ; f1e2 ; Routine to set the dma address for directory work. f1e2 ; f1e2 21 bb f9 DIRDMA: LD HL,DIRBUF f1e5 ; f1e5 ; Set the dma address. On entry, (HL) points to f1e5 ; word containing the desired dma address. f1e5 ; f1e5 4e DIRDMA1:LD C,(HL) f1e6 23 INC HL f1e7 46 LD B,(HL) ;setup (BC) and go to the bios to set it. f1e8 c3 24 fa JP SETDMA f1eb ; f1eb ; Move the directory buffer into user's dma space. f1eb ; f1eb 2a bb f9 MOVEDIR:LD HL,(DIRBUF) ;buffer is located here, and f1ee eb EX DE,HL f1ef 2a b3 f9 LD HL,(USERDMA) ; put it here. f1f2 0e 80 LD C,128 ;this is its length. f1f4 c3 51 ef JP DE2HL ;move it now and return. f1f7 ; f1f7 ; Check (FILEPOS) and set the zero flag if it equals 0ffffh. f1f7 ; f1f7 21 ec f9 CKFILPOS: LD HL,FILEPOS f1fa 7e LD A,(HL) f1fb 23 INC HL f1fc be CP (HL) ;are both bytes the same? f1fd c0 RET NZ f1fe 3c INC A ;yes, but are they each 0ffh? f1ff c9 RET f200 ; f200 ; Set location (FILEPOS) to 0ffffh. f200 ; f200 21 ff ff STFILPOS: LD HL,0FFFFH f203 22 ec f9 LD (FILEPOS),HL f206 c9 RET f207 ; f207 ; Move on to the next file position within the current f207 ; directory buffer. If no more exist, set pointer to 0ffffh f207 ; and the calling routine will check for this. Enter with (C) f207 ; equal to 0ffh to cause the checksum byte to be set, else we f207 ; will check this disk and set write protect if checksums are f207 ; not the same (applies only if another directory sector must f207 ; be read). f207 ; f207 2a ca f9 NXENTRY:LD HL,(DIRSIZE) ;get directory entry size limit. f20a eb EX DE,HL f20b 2a ec f9 LD HL,(FILEPOS) ;get current count. f20e 23 INC HL ;go on to the next one. f20f 22 ec f9 LD (FILEPOS),HL f212 cd 97 f1 CALL SUBHL ;(HL)=(DIRSIZE)-(FILEPOS) f215 d2 1b f2 JP NC,NXENT1 ;is there more room left? f218 c3 00 f2 JP STFILPOS ;no. Set this flag and return. f21b 3a ec f9 NXENT1: LD A,(FILEPOS) ;get file position within directory. f21e e6 03 AND 03H ;only look within this sector (only 4 entries fit). f220 06 05 LD B,5 ;convert to relative position (32 bytes each). f222 87 NXENT2: ADD A,A ;note that this is not efficient code. f223 05 DEC B ;5 'ADD A's would be better. f224 c2 22 f2 JP NZ,NXENT2 f227 32 eb f9 LD (FCBPOS),A ;save it as position of fcb. f22a b7 OR A f22b c0 RET NZ ;return if we are within buffer. f22c c5 PUSH BC f22d cd c5 ef CALL TRKSEC ;we need the next directory sector. f230 cd d6 f1 CALL DIRREAD f233 c1 POP BC f234 c3 a0 f1 JP CHECKDIR f237 ; f237 ; Routine to to get a bit from the disk space allocation f237 ; map. It is returned in (A), bit position 0. On entry to here, f237 ; set (BC) to the block number on the disk to check. f237 ; On return, (D) will contain the original bit position for f237 ; this block number and (HL) will point to the address for it. f237 ; f237 79 CKBITMAP: LD A,C ;determine bit number of interest. f238 e6 07 AND 07H ;compute (D)=(E)=(C and 7)+1. f23a 3c INC A f23b 5f LD E,A ;save particular bit number. f23c 57 LD D,A f23d ; f23d ; compute (BC)=(BC)/8. f23d ; f23d 79 LD A,C f23e 0f RRCA ;now shift right 3 bits. f23f 0f RRCA f240 0f RRCA f241 e6 1f AND 1FH ;and clear bits 7,6,5. f243 4f LD C,A f244 78 LD A,B f245 87 ADD A,A ;now shift (B) into bits 7,6,5. f246 87 ADD A,A f247 87 ADD A,A f248 87 ADD A,A f249 87 ADD A,A f24a b1 OR C ;and add in (C). f24b 4f LD C,A ;ok, (C) ha been completed. f24c 78 LD A,B ;is there a better way of doing this? f24d 0f RRCA f24e 0f RRCA f24f 0f RRCA f250 e6 1f AND 1FH f252 47 LD B,A ;and now (B) is completed. f253 ; f253 ; use this as an offset into the disk space allocation f253 ; table. f253 ; f253 2a c1 f9 LD HL,(ALOCVECT) f256 09 ADD HL,BC f257 7e LD A,(HL) ;now get correct byte. f258 07 CKBMAP1:RLCA ;get correct bit into position 0. f259 1d DEC E f25a c2 58 f2 JP NZ,CKBMAP1 f25d c9 RET f25e ; f25e ; Set or clear the bit map such that block number (BC) will be marked f25e ; as used. On entry, if (E)=0 then this bit will be cleared, if it equals f25e ; 1 then it will be set (don't use anyother values). f25e ; f25e d5 STBITMAP: PUSH DE f25f cd 37 f2 CALL CKBITMAP ;get the byte of interest. f262 e6 fe AND 0FEH ;clear the affected bit. f264 c1 POP BC f265 b1 OR C ;and now set it acording to (C). f266 ; f266 ; entry to restore the original bit position and then store f266 ; in table. (A) contains the value, (D) contains the bit f266 ; position (1-8), and (HL) points to the address within the f266 ; space allocation table for this byte. f266 ; f266 0f STBMAP1:RRCA ;restore original bit position. f267 15 DEC D f268 c2 66 f2 JP NZ,STBMAP1 f26b 77 LD (HL),A ;and stor byte in table. f26c c9 RET f26d ; f26d ; Set/clear space used bits in allocation map for this file. f26d ; On entry, (C)=1 to set the map and (C)=0 to clear it. f26d ; f26d cd 60 f1 SETFILE:CALL FCB2HL ;get address of fcb f270 11 10 00 LD DE,16 f273 19 ADD HL,DE ;get to block number bytes. f274 c5 PUSH BC f275 0e 11 LD C,17 ;check all 17 bytes (max) of table. f277 d1 SETFL1: POP DE f278 0d DEC C ;done all bytes yet? f279 c8 RET Z f27a d5 PUSH DE f27b 3a df f9 LD A,(BIGDISK) ;check disk size for 16 bit block numbers. f27e b7 OR A f27f ca 8a f2 JP Z,SETFL2 f282 c5 PUSH BC ;only 8 bit numbers. set (BC) to this one. f283 e5 PUSH HL f284 4e LD C,(HL) ;get low byte from table, always f285 06 00 LD B,0 ;set high byte to zero. f287 c3 90 f2 JP SETFL3 f28a 0d SETFL2: DEC C ;for 16 bit block numbers, adjust counter. f28b c5 PUSH BC f28c 4e LD C,(HL) ;now get both the low and high bytes. f28d 23 INC HL f28e 46 LD B,(HL) f28f e5 PUSH HL f290 79 SETFL3: LD A,C ;block used? f291 b0 OR B f292 ca 9f f2 JP Z,SETFL4 f295 2a c8 f9 LD HL,(DSKSIZE) ;is this block number within the f298 7d LD A,L ;space on the disk? f299 91 SUB C f29a 7c LD A,H f29b 98 SBC A,B f29c d4 5e f2 CALL NC,STBITMAP ;yes, set the proper bit. f29f e1 SETFL4: POP HL ;point to next block number in fcb. f2a0 23 INC HL f2a1 c1 POP BC f2a2 c3 77 f2 JP SETFL1 f2a5 ; f2a5 ; Construct the space used allocation bit map for the active f2a5 ; drive. If a file name starts with '$' and it is under the f2a5 ; current user number, then (STATUS) is set to minus 1. Otherwise f2a5 ; it is not set at all. f2a5 ; f2a5 2a c8 f9 BITMAP: LD HL,(DSKSIZE) ;compute size of allocation table. f2a8 0e 03 LD C,3 f2aa cd ec f0 CALL SHIFTR ;(HL)=(HL)/8. f2ad 23 INC HL ;at lease 1 byte. f2ae 44 LD B,H f2af 4d LD C,L ;set (BC) to the allocation table length. f2b0 ; f2b0 ; Initialize the bitmap for this drive. Right now, the first f2b0 ; two bytes are specified by the disk parameter block. However f2b0 ; a patch could be entered here if it were necessary to setup f2b0 ; this table in a special mannor. For example, the bios could f2b0 ; determine locations of 'bad blocks' and set them as already f2b0 ; 'used' in the map. f2b0 ; f2b0 2a c1 f9 LD HL,(ALOCVECT) ;now zero out the table now. f2b3 36 00 BITMAP1:LD (HL),0 f2b5 23 INC HL f2b6 0b DEC BC f2b7 78 LD A,B f2b8 b1 OR C f2b9 c2 b3 f2 JP NZ,BITMAP1 f2bc 2a cc f9 LD HL,(ALLOC0) ;get initial space used by directory. f2bf eb EX DE,HL f2c0 2a c1 f9 LD HL,(ALOCVECT) ;and put this into map. f2c3 73 LD (HL),E f2c4 23 INC HL f2c5 72 LD (HL),D f2c6 ; f2c6 ; End of initialization portion. f2c6 ; f2c6 cd a3 ef CALL HOMEDRV ;now home the drive. f2c9 2a b5 f9 LD HL,(SCRATCH1) f2cc 36 03 LD (HL),3 ;force next directory request to read f2ce 23 INC HL ;in a sector. f2cf 36 00 LD (HL),0 f2d1 cd 00 f2 CALL STFILPOS ;clear initial file position also. f2d4 0e ff BITMAP2:LD C,0FFH ;read next file name in directory f2d6 cd 07 f2 CALL NXENTRY ;and set checksum byte. f2d9 cd f7 f1 CALL CKFILPOS ;is there another file? f2dc c8 RET Z f2dd cd 60 f1 CALL FCB2HL ;yes, get its address. f2e0 3e e5 LD A,0E5H f2e2 be CP (HL) ;empty file entry? f2e3 ca d4 f2 JP Z,BITMAP2 f2e6 3a 43 ef LD A,(USERNO) ;no, correct user number? f2e9 be CP (HL) f2ea c2 f8 f2 JP NZ,BITMAP3 f2ed 23 INC HL f2ee 7e LD A,(HL) ;yes, does name start with a '$'? f2ef d6 24 SUB '$' f2f1 c2 f8 f2 JP NZ,BITMAP3 f2f4 3d DEC A ;yes, set atatus to minus one. f2f5 32 47 ef LD (STATUS),A f2f8 0e 01 BITMAP3:LD C,1 ;now set this file's space as used in bit map. f2fa cd 6d f2 CALL SETFILE f2fd cd 8e f1 CALL CHKNMBR ;keep (SCRATCH1) in bounds. f300 c3 d4 f2 JP BITMAP2 f303 ; f303 ; Set the status (STATUS) and return. f303 ; f303 3a d6 f9 STSTATUS: LD A,(FNDSTAT) f306 c3 03 ef JP SETSTAT f309 ; f309 ; Check extents in (A) and (C). Set the zero flag if they f309 ; are the same. The number of 16k chunks of disk space that f309 ; the directory extent covers is expressad is (EXTMASK+1). f309 ; No registers are modified. f309 ; f309 c5 SAMEXT: PUSH BC f30a f5 PUSH AF f30b 3a c7 f9 LD A,(EXTMASK) ;get extent mask and use it to f30e 2f CPL ;to compare both extent numbers. f30f 47 LD B,A ;save resulting mask here. f310 79 LD A,C ;mask first extent and save in (C). f311 a0 AND B f312 4f LD C,A f313 f1 POP AF ;now mask second extent and compare f314 a0 AND B ;with the first one. f315 91 SUB C f316 e6 1f AND 1FH ;(* only check buts 0-4 *) f318 c1 POP BC ;the zero flag is set if they are the same. f319 c9 RET ;restore (BC) and return. f31a ; f31a ; Search for the first occurence of a file name. On entry, f31a ; register (C) should contain the number of bytes of the fcb f31a ; that must match. f31a ; f31a 3e ff FINDFST:LD A,0FFH f31c 32 d6 f9 LD (FNDSTAT),A f31f 21 da f9 LD HL,COUNTER ;save character count. f322 71 LD (HL),C f323 2a 45 ef LD HL,(PARAMS) ;get filename to match. f326 22 db f9 LD (SAVEFCB),HL ;and save. f329 cd 00 f2 CALL STFILPOS ;clear initial file position (set to 0ffffh). f32c cd a3 ef CALL HOMEDRV ;home the drive. f32f ; f32f ; Entry to locate the next occurence of a filename within the f32f ; directory. The disk is not expected to have been changed. If f32f ; it was, then it will be write protected. f32f ; f32f 0e 00 FINDNXT:LD C,0 ;write protect the disk if changed. f331 cd 07 f2 CALL NXENTRY ;get next filename entry in directory. f334 cd f7 f1 CALL CKFILPOS ;is file position = 0ffffh? f337 ca 96 f3 JP Z,FNDNXT6 ;yes, exit now then. f33a 2a db f9 LD HL,(SAVEFCB) ;set (DE) pointing to filename to match. f33d eb EX DE,HL f33e 1a LD A,(DE) f33f fe e5 CP 0E5H ;empty directory entry? f341 ca 4c f3 JP Z,FNDNXT1 ;(* are we trying to reserect erased entries? *) f344 d5 PUSH DE f345 cd 81 f1 CALL MOREFLS ;more files in directory? f348 d1 POP DE f349 d2 96 f3 JP NC,FNDNXT6 ;no more. Exit now. f34c cd 60 f1 FNDNXT1:CALL FCB2HL ;get address of this fcb in directory. f34f 3a da f9 LD A,(COUNTER) ;get number of bytes (characters) to check. f352 4f LD C,A f353 06 00 LD B,0 ;initialize byte position counter. f355 79 FNDNXT2:LD A,C ;are we done with the compare? f356 b7 OR A f357 ca 85 f3 JP Z,FNDNXT5 f35a 1a LD A,(DE) ;no, check next byte. f35b fe 3f CP '?' ;don't care about this character? f35d ca 7e f3 JP Z,FNDNXT4 f360 78 LD A,B ;get bytes position in fcb. f361 fe 0d CP 13 ;don't care about the thirteenth byte either. f363 ca 7e f3 JP Z,FNDNXT4 f366 fe 0c CP 12 ;extent byte? f368 1a LD A,(DE) f369 ca 75 f3 JP Z,FNDNXT3 f36c 96 SUB (HL) ;otherwise compare characters. f36d e6 7f AND 7FH f36f c2 2f f3 JP NZ,FINDNXT ;not the same, check next entry. f372 c3 7e f3 JP FNDNXT4 ;so far so good, keep checking. f375 c5 FNDNXT3:PUSH BC ;check the extent byte here. f376 4e LD C,(HL) f377 cd 09 f3 CALL SAMEXT f37a c1 POP BC f37b c2 2f f3 JP NZ,FINDNXT ;not the same, look some more. f37e ; f37e ; So far the names compare. Bump pointers to the next byte f37e ; and continue until all (C) characters have been checked. f37e ; f37e 13 FNDNXT4:INC DE ;bump pointers. f37f 23 INC HL f380 04 INC B f381 0d DEC C ;adjust character counter. f382 c3 55 f3 JP FNDNXT2 f385 3a ec f9 FNDNXT5:LD A,(FILEPOS) ;return the position of this entry. f388 e6 03 AND 03H f38a 32 47 ef LD (STATUS),A f38d 21 d6 f9 LD HL,FNDSTAT f390 7e LD A,(HL) f391 17 RLA f392 d0 RET NC f393 af XOR A f394 77 LD (HL),A f395 c9 RET f396 ; f396 ; Filename was not found. Set appropriate status. f396 ; f396 cd 00 f2 FNDNXT6:CALL STFILPOS ;set (FILEPOS) to 0ffffh. f399 3e ff LD A,0FFH ;say not located. f39b c3 03 ef JP SETSTAT f39e ; f39e ; Erase files from the directory. Only the first byte of the f39e ; fcb will be affected. It is set to (E5). f39e ; f39e cd 56 f1 ERAFILE:CALL CHKWPRT ;is disk write protected? f3a1 0e 0c LD C,12 ;only compare file names. f3a3 cd 1a f3 CALL FINDFST ;get first file name. f3a6 cd f7 f1 ERAFIL1:CALL CKFILPOS ;any found? f3a9 c8 RET Z ;nope, we must be done. f3aa cd 46 f1 CALL CHKROFL ;is file read only? f3ad cd 60 f1 CALL FCB2HL ;nope, get address of fcb and f3b0 36 e5 LD (HL),0E5H ;set first byte to 'empty'. f3b2 0e 00 LD C,0 ;clear the space from the bit map. f3b4 cd 6d f2 CALL SETFILE f3b7 cd c8 f1 CALL DIRWRITE ;now write the directory sector back out. f3ba cd 2f f3 CALL FINDNXT ;find the next file name. f3bd c3 a6 f3 JP ERAFIL1 ;and repeat process. f3c0 ; f3c0 ; Look through the space allocation map (bit map) for the f3c0 ; next available block. Start searching at block number (BC-1). f3c0 ; The search procedure is to look for an empty block that is f3c0 ; before the starting block. If not empty, look at a later f3c0 ; block number. In this way, we return the closest empty block f3c0 ; on either side of the 'target' block number. This will speed f3c0 ; access on random devices. For serial devices, this should be f3c0 ; changed to look in the forward direction first and then start f3c0 ; at the front and search some more. f3c0 ; f3c0 ; On return, (DE)= block number that is empty and (HL) =0 f3c0 ; if no empry block was found. f3c0 ; f3c0 50 FNDSPACE: LD D,B ;set (DE) as the block that is checked. f3c1 59 LD E,C f3c2 ; f3c2 ; Look before target block. Registers (BC) are used as the lower f3c2 ; pointer and (DE) as the upper pointer. f3c2 ; f3c2 79 FNDSPA1:LD A,C ;is block 0 specified? f3c3 b0 OR B f3c4 ca d3 f3 JP Z,FNDSPA2 f3c7 0b DEC BC ;nope, check previous block. f3c8 d5 PUSH DE f3c9 c5 PUSH BC f3ca cd 37 f2 CALL CKBITMAP f3cd 1f RRA ;is this block empty? f3ce d2 ee f3 JP NC,FNDSPA3 ;yes. use this. f3d1 ; f3d1 ; Note that the above logic gets the first block that it finds f3d1 ; that is empty. Thus a file could be written 'backward' making f3d1 ; it very slow to access. This could be changed to look for the f3d1 ; first empty block and then continue until the start of this f3d1 ; empty space is located and then used that starting block. f3d1 ; This should help speed up access to some files especially on f3d1 ; a well used disk with lots of fairly small 'holes'. f3d1 ; f3d1 c1 POP BC ;nope, check some more. f3d2 d1 POP DE f3d3 ; f3d3 ; Now look after target block. f3d3 ; f3d3 2a c8 f9 FNDSPA2:LD HL,(DSKSIZE) ;is block (DE) within disk limits? f3d6 7b LD A,E f3d7 95 SUB L f3d8 7a LD A,D f3d9 9c SBC A,H f3da d2 f6 f3 JP NC,FNDSPA4 f3dd 13 INC DE ;yes, move on to next one. f3de c5 PUSH BC f3df d5 PUSH DE f3e0 42 LD B,D f3e1 4b LD C,E f3e2 cd 37 f2 CALL CKBITMAP ;check it. f3e5 1f RRA ;empty? f3e6 d2 ee f3 JP NC,FNDSPA3 f3e9 d1 POP DE ;nope, continue searching. f3ea c1 POP BC f3eb c3 c2 f3 JP FNDSPA1 f3ee ; f3ee ; Empty block found. Set it as used and return with (HL) f3ee ; pointing to it (true?). f3ee ; f3ee 17 FNDSPA3:RLA ;reset byte. f3ef 3c INC A ;and set bit 0. f3f0 cd 66 f2 CALL STBMAP1 ;update bit map. f3f3 e1 POP HL ;set return registers. f3f4 d1 POP DE f3f5 c9 RET f3f6 ; f3f6 ; Free block was not found. If (BC) is not zero, then we have f3f6 ; not checked all of the disk space. f3f6 ; f3f6 79 FNDSPA4:LD A,C f3f7 b0 OR B f3f8 c2 c2 f3 JP NZ,FNDSPA1 f3fb 21 00 00 LD HL,0 ;set 'not found' status. f3fe c9 RET f3ff ; f3ff ; Move a complete fcb entry into the directory and write it. f3ff ; f3ff 0e 00 FCBSET: LD C,0 f401 1e 20 LD E,32 ;length of each entry. f403 ; f403 ; Move (E) bytes from the fcb pointed to by (PARAMS) into f403 ; fcb in directory starting at relative byte (C). This updated f403 ; directory buffer is then written to the disk. f403 ; f403 d5 UPDATE: PUSH DE f404 06 00 LD B,0 ;set (BC) to relative byte position. f406 2a 45 ef LD HL,(PARAMS) ;get address of fcb. f409 09 ADD HL,BC ;compute starting byte. f40a eb EX DE,HL f40b cd 60 f1 CALL FCB2HL ;get address of fcb to update in directory. f40e c1 POP BC ;set (C) to number of bytes to change. f40f cd 51 ef CALL DE2HL f412 cd c5 ef UPDATE1:CALL TRKSEC ;determine the track and sector affected. f415 c3 c8 f1 JP DIRWRITE ;then write this sector out. f418 ; f418 ; Routine to change the name of all files on the disk with a f418 ; specified name. The fcb contains the current name as the f418 ; first 12 characters and the new name 16 bytes into the fcb. f418 ; f418 cd 56 f1 CHGNAMES: CALL CHKWPRT ;check for a write protected disk. f41b 0e 0c LD C,12 ;match first 12 bytes of fcb only. f41d cd 1a f3 CALL FINDFST ;get first name. f420 2a 45 ef LD HL,(PARAMS) ;get address of fcb. f423 7e LD A,(HL) ;get user number. f424 11 10 00 LD DE,16 ;move over to desired name. f427 19 ADD HL,DE f428 77 LD (HL),A ;keep same user number. f429 cd f7 f1 CHGNAM1:CALL CKFILPOS ;any matching file found? f42c c8 RET Z ;no, we must be done. f42d cd 46 f1 CALL CHKROFL ;check for read only file. f430 0e 10 LD C,16 ;start 16 bytes into fcb. f432 1e 0c LD E,12 ;and update the first 12 bytes of directory. f434 cd 03 f4 CALL UPDATE f437 cd 2f f3 CALL FINDNXT ;get te next file name. f43a c3 29 f4 JP CHGNAM1 ;and continue. f43d ; f43d ; Update a files attributes. The procedure is to search for f43d ; every file with the same name as shown in fcb (ignoring bit 7) f43d ; and then to update it (which includes bit 7). No other changes f43d ; are made. f43d ; f43d 0e 0c SAVEATTR: LD C,12 ;match first 12 bytes. f43f cd 1a f3 CALL FINDFST ;look for first filename. f442 cd f7 f1 SAVATR1:CALL CKFILPOS ;was one found? f445 c8 RET Z ;nope, we must be done. f446 0e 00 LD C,0 ;yes, update the first 12 bytes now. f448 1e 0c LD E,12 f44a cd 03 f4 CALL UPDATE ;update filename and write directory. f44d cd 2f f3 CALL FINDNXT ;and get the next file. f450 c3 42 f4 JP SAVATR1 ;then continue until done. f453 ; f453 ; Open a file (name specified in fcb). f453 ; f453 0e 0f OPENIT: LD C,15 ;compare the first 15 bytes. f455 cd 1a f3 CALL FINDFST ;get the first one in directory. f458 cd f7 f1 CALL CKFILPOS ;any at all? f45b c8 RET Z f45c cd a8 f0 OPENIT1:CALL SETEXT ;point to extent byte within users fcb. f45f 7e LD A,(HL) ;and get it. f460 f5 PUSH AF ;save it and address. f461 e5 PUSH HL f462 cd 60 f1 CALL FCB2HL ;point to fcb in directory. f465 eb EX DE,HL f466 2a 45 ef LD HL,(PARAMS) ;this is the users copy. f469 0e 20 LD C,32 ;move it into users space. f46b d5 PUSH DE f46c cd 51 ef CALL DE2HL f46f cd 7a f1 CALL SETS2B7 ;set bit 7 in 's2' byte (unmodified). f472 d1 POP DE ;now get the extent byte from this fcb. f473 21 0c 00 LD HL,12 f476 19 ADD HL,DE f477 4e LD C,(HL) ;into (C). f478 21 0f 00 LD HL,15 ;now get the record count byte into (B). f47b 19 ADD HL,DE f47c 46 LD B,(HL) f47d e1 POP HL ;keep the same extent as the user had originally. f47e f1 POP AF f47f 77 LD (HL),A f480 79 LD A,C ;is it the same as in the directory fcb? f481 be CP (HL) f482 78 LD A,B ;if yes, then use the same record count. f483 ca 8d f4 JP Z,OPENIT2 f486 3e 00 LD A,0 ;if the user specified an extent greater than f488 da 8d f4 JP C,OPENIT2 ;the one in the directory, then set record count to 0. f48b 3e 80 LD A,128 ;otherwise set to maximum. f48d 2a 45 ef OPENIT2:LD HL,(PARAMS) ;set record count in users fcb to (A). f490 11 0f 00 LD DE,15 f493 19 ADD HL,DE ;compute relative position. f494 77 LD (HL),A ;and set the record count. f495 c9 RET f496 ; f496 ; Move two bytes from (DE) to (HL) if (and only if) (HL) f496 ; point to a zero value (16 bit). f496 ; Return with zero flag set it (DE) was moved. Registers (DE) f496 ; and (HL) are not changed. However (A) is. f496 ; f496 7e MOVEWORD: LD A,(HL) ;check for a zero word. f497 23 INC HL f498 b6 OR (HL) ;both bytes zero? f499 2b DEC HL f49a c0 RET NZ ;nope, just return. f49b 1a LD A,(DE) ;yes, move two bytes from (DE) into f49c 77 LD (HL),A ;this zero space. f49d 13 INC DE f49e 23 INC HL f49f 1a LD A,(DE) f4a0 77 LD (HL),A f4a1 1b DEC DE ;don't disturb these registers. f4a2 2b DEC HL f4a3 c9 RET f4a4 ; f4a4 ; Get here to close a file specified by (fcb). f4a4 ; f4a4 af CLOSEIT:XOR A ;clear status and file position bytes. f4a5 32 47 ef LD (STATUS),A f4a8 32 ec f9 LD (FILEPOS),A f4ab 32 ed f9 LD (FILEPOS+1),A f4ae cd 20 f1 CALL GETWPRT ;get write protect bit for this drive. f4b1 c0 RET NZ ;just return if it is set. f4b2 cd 6b f1 CALL GETS2 ;else get the 's2' byte. f4b5 e6 80 AND 80H ;and look at bit 7 (file unmodified?). f4b7 c0 RET NZ ;just return if set. f4b8 0e 0f LD C,15 ;else look up this file in directory. f4ba cd 1a f3 CALL FINDFST f4bd cd f7 f1 CALL CKFILPOS ;was it found? f4c0 c8 RET Z ;just return if not. f4c1 01 10 00 LD BC,16 ;set (HL) pointing to records used section. f4c4 cd 60 f1 CALL FCB2HL f4c7 09 ADD HL,BC f4c8 eb EX DE,HL f4c9 2a 45 ef LD HL,(PARAMS) ;do the same for users specified fcb. f4cc 09 ADD HL,BC f4cd 0e 10 LD C,16 ;this many bytes are present in this extent. f4cf 3a df f9 CLOSEIT1: LD A,(BIGDISK) ;8 or 16 bit record numbers? f4d2 b7 OR A f4d3 ca ea f4 JP Z,CLOSEIT4 f4d6 7e LD A,(HL) ;just 8 bit. Get one from users fcb. f4d7 b7 OR A f4d8 1a LD A,(DE) ;now get one from directory fcb. f4d9 c2 dd f4 JP NZ,CLOSEIT2 f4dc 77 LD (HL),A ;users byte was zero. Update from directory. f4dd b7 CLOSEIT2: OR A f4de c2 e3 f4 JP NZ,CLOSEIT3 f4e1 7e LD A,(HL) ;directories byte was zero, update from users fcb. f4e2 12 LD (DE),A f4e3 be CLOSEIT3: CP (HL) ;if neither one of these bytes were zero, f4e4 c2 21 f5 JP NZ,CLOSEIT7 ;then close error if they are not the same. f4e7 c3 ff f4 JP CLOSEIT5 ;ok so far, get to next byte in fcbs. f4ea cd 96 f4 CLOSEIT4: CALL MOVEWORD ;update users fcb if it is zero. f4ed eb EX DE,HL f4ee cd 96 f4 CALL MOVEWORD ;update directories fcb if it is zero. f4f1 eb EX DE,HL f4f2 1a LD A,(DE) ;if these two values are no different, f4f3 be CP (HL) ;then a close error occured. f4f4 c2 21 f5 JP NZ,CLOSEIT7 f4f7 13 INC DE ;check second byte. f4f8 23 INC HL f4f9 1a LD A,(DE) f4fa be CP (HL) f4fb c2 21 f5 JP NZ,CLOSEIT7 f4fe 0d DEC C ;remember 16 bit values. f4ff 13 CLOSEIT5: INC DE ;bump to next item in table. f500 23 INC HL f501 0d DEC C ;there are 16 entries only. f502 c2 cf f4 JP NZ,CLOSEIT1 ;continue if more to do. f505 01 ec ff LD BC,0FFECH ;backup 20 places (extent byte). f508 09 ADD HL,BC f509 eb EX DE,HL f50a 09 ADD HL,BC f50b 1a LD A,(DE) f50c be CP (HL) ;directory's extent already greater than the f50d da 19 f5 JP C,CLOSEIT6 ;users extent? f510 77 LD (HL),A ;no, update directory extent. f511 01 03 00 LD BC,3 ;and update the record count byte in f514 09 ADD HL,BC ;directories fcb. f515 eb EX DE,HL f516 09 ADD HL,BC f517 7e LD A,(HL) ;get from user. f518 12 LD (DE),A ;and put in directory. f519 3e ff CLOSEIT6: LD A,0FFH ;set 'was open and is now closed' byte. f51b 32 d4 f9 LD (CLOSEFLG),A f51e c3 12 f4 JP UPDATE1 ;update the directory now. f521 21 47 ef CLOSEIT7: LD HL,STATUS ;set return status and then return. f524 35 DEC (HL) f525 c9 RET f526 ; f526 ; Routine to get the next empty space in the directory. It f526 ; will then be cleared for use. f526 ; f526 cd 56 f1 GETEMPTY: CALL CHKWPRT ;make sure disk is not write protected. f529 2a 45 ef LD HL,(PARAMS) ;save current parameters (fcb). f52c e5 PUSH HL f52d 21 ae f9 LD HL,EMPTYFCB ;use special one for empty space. f530 22 45 ef LD (PARAMS),HL f533 0e 01 LD C,1 ;search for first empty spot in directory. f535 cd 1a f3 CALL FINDFST ;(* only check first byte *) f538 cd f7 f1 CALL CKFILPOS ;none? f53b e1 POP HL f53c 22 45 ef LD (PARAMS),HL ;restore original fcb address. f53f c8 RET Z ;return if no more space. f540 eb EX DE,HL f541 21 0f 00 LD HL,15 ;point to number of records for this file. f544 19 ADD HL,DE f545 0e 11 LD C,17 ;and clear all of this space. f547 af XOR A f548 77 GETMT1: LD (HL),A f549 23 INC HL f54a 0d DEC C f54b c2 48 f5 JP NZ,GETMT1 f54e 21 0d 00 LD HL,13 ;clear the 's1' byte also. f551 19 ADD HL,DE f552 77 LD (HL),A f553 cd 8e f1 CALL CHKNMBR ;keep (SCRATCH1) within bounds. f556 cd ff f3 CALL FCBSET ;write out this fcb entry to directory. f559 c3 7a f1 JP SETS2B7 ;set 's2' byte bit 7 (unmodified at present). f55c ; f55c ; Routine to close the current extent and open the next one f55c ; for reading. f55c ; f55c af GETNEXT:XOR A f55d 32 d4 f9 LD (CLOSEFLG),A ;clear close flag. f560 cd a4 f4 CALL CLOSEIT ;close this extent. f563 cd f7 f1 CALL CKFILPOS f566 c8 RET Z ;not there??? f567 2a 45 ef LD HL,(PARAMS) ;get extent byte. f56a 01 0c 00 LD BC,12 f56d 09 ADD HL,BC f56e 7e LD A,(HL) ;and increment it. f56f 3c INC A f570 e6 1f AND 1FH ;keep within range 0-31. f572 77 LD (HL),A f573 ca 85 f5 JP Z,GTNEXT1 ;overflow? f576 47 LD B,A ;mask extent byte. f577 3a c7 f9 LD A,(EXTMASK) f57a a0 AND B f57b 21 d4 f9 LD HL,CLOSEFLG ;check close flag (0ffh is ok). f57e a6 AND (HL) f57f ca 90 f5 JP Z,GTNEXT2 ;if zero, we must read in next extent. f582 c3 ae f5 JP GTNEXT3 ;else, it is already in memory. f585 01 02 00 GTNEXT1:LD BC,2 ;Point to the 's2' byte. f588 09 ADD HL,BC f589 34 INC (HL) ;and bump it. f58a 7e LD A,(HL) ;too many extents? f58b e6 0f AND 0FH f58d ca b8 f5 JP Z,GTNEXT5 ;yes, set error code. f590 ; f590 ; Get here to open the next extent. f590 ; f590 0e 0f GTNEXT2:LD C,15 ;set to check first 15 bytes of fcb. f592 cd 1a f3 CALL FINDFST ;find the first one. f595 cd f7 f1 CALL CKFILPOS ;none available? f598 c2 ae f5 JP NZ,GTNEXT3 f59b 3a d5 f9 LD A,(RDWRTFLG) ;no extent present. Can we open an empty one? f59e 3c INC A ;0ffh means reading (so not possible). f59f ca b8 f5 JP Z,GTNEXT5 ;or an error. f5a2 cd 26 f5 CALL GETEMPTY ;we are writing, get an empty entry. f5a5 cd f7 f1 CALL CKFILPOS ;none? f5a8 ca b8 f5 JP Z,GTNEXT5 ;error if true. f5ab c3 b1 f5 JP GTNEXT4 ;else we are almost done. f5ae cd 5c f4 GTNEXT3:CALL OPENIT1 ;open this extent. f5b1 cd bd f0 GTNEXT4:CALL STRDATA ;move in updated data (rec #, extent #, etc.) f5b4 af XOR A ;clear status and return. f5b5 c3 03 ef JP SETSTAT f5b8 ; f5b8 ; Error in extending the file. Too many extents were needed f5b8 ; or not enough space on the disk. f5b8 ; f5b8 cd 07 ef GTNEXT5:CALL IOERR1 ;set error code, clear bit 7 of 's2' f5bb c3 7a f1 JP SETS2B7 ;so this is not written on a close. f5be ; f5be ; Read a sequential file. f5be ; f5be 3e 01 RDSEQ: LD A,1 ;set sequential access mode. f5c0 32 d7 f9 LD (MODE),A f5c3 3e ff RDSEQ1: LD A,0FFH ;don't allow reading unwritten space. f5c5 32 d5 f9 LD (RDWRTFLG),A f5c8 cd bd f0 CALL STRDATA ;put rec# and ext# into fcb. f5cb 3a e5 f9 LD A,(SAVNREC) ;get next record to read. f5ce 21 e3 f9 LD HL,SAVNXT ;get number of records in extent. f5d1 be CP (HL) ;within this extent? f5d2 da e8 f5 JP C,RDSEQ2 f5d5 fe 80 CP 128 ;no. Is this extent fully used? f5d7 c2 fd f5 JP NZ,RDSEQ3 ;no. End-of-file. f5da cd 5c f5 CALL GETNEXT ;yes, open the next one. f5dd af XOR A ;reset next record to read. f5de 32 e5 f9 LD (SAVNREC),A f5e1 3a 47 ef LD A,(STATUS) ;check on open, successful? f5e4 b7 OR A f5e5 c2 fd f5 JP NZ,RDSEQ3 ;no, error. f5e8 cd 79 f0 RDSEQ2: CALL COMBLK ;ok. compute block number to read. f5eb cd 86 f0 CALL CHKBLK ;check it. Within bounds? f5ee ca fd f5 JP Z,RDSEQ3 ;no, error. f5f1 cd 8c f0 CALL LOGICAL ;convert (BLKNMBR) to logical sector (128 byte). f5f4 cd d3 ef CALL TRKSEC1 ;set the track and sector for this block #. f5f7 cd b4 ef CALL DOREAD ;and read it. f5fa c3 d4 f0 JP SETNREC ;and set the next record to be accessed. f5fd ; f5fd ; Read error occured. Set status and return. f5fd ; f5fd c3 07 ef RDSEQ3: JP IOERR1 f600 ; f600 ; Write the next sequential record. f600 ; f600 3e 01 WTSEQ: LD A,1 ;set sequential access mode. f602 32 d7 f9 LD (MODE),A f605 3e 00 WTSEQ1: LD A,0 ;allow an addition empty extent to be opened. f607 32 d5 f9 LD (RDWRTFLG),A f60a cd 56 f1 CALL CHKWPRT ;check write protect status. f60d 2a 45 ef LD HL,(PARAMS) f610 cd 49 f1 CALL CKROF1 ;check for read only file, (HL) already set to fcb. f613 cd bd f0 CALL STRDATA ;put updated data into fcb. f616 3a e5 f9 LD A,(SAVNREC) ;get record number to write. f619 fe 80 CP 128 ;within range? f61b d2 07 ef JP NC,IOERR1 ;no, error(?). f61e cd 79 f0 CALL COMBLK ;compute block number. f621 cd 86 f0 CALL CHKBLK ;check number. f624 0e 00 LD C,0 ;is there one to write to? f626 c2 70 f6 JP NZ,WTSEQ6 ;yes, go do it. f629 cd 40 f0 CALL GETBLOCK ;get next block number within fcb to use. f62c 32 d9 f9 LD (RELBLOCK),A ;and save. f62f 01 00 00 LD BC,0 ;start looking for space from the start f632 b7 OR A ;if none allocated as yet. f633 ca 3d f6 JP Z,WTSEQ2 f636 4f LD C,A ;extract previous block number from fcb f637 0b DEC BC ;so we can be closest to it. f638 cd 60 f0 CALL EXTBLK f63b 44 LD B,H f63c 4d LD C,L f63d cd c0 f3 WTSEQ2: CALL FNDSPACE ;find the next empty block nearest number (BC). f640 7d LD A,L ;check for a zero number. f641 b4 OR H f642 c2 4a f6 JP NZ,WTSEQ3 f645 3e 02 LD A,2 ;no more space? f647 c3 03 ef JP SETSTAT f64a 22 e7 f9 WTSEQ3: LD (BLKNMBR),HL ;save block number to access. f64d eb EX DE,HL ;put block number into (DE). f64e 2a 45 ef LD HL,(PARAMS) ;now we must update the fcb for this f651 01 10 00 LD BC,16 ;newly allocated block. f654 09 ADD HL,BC f655 3a df f9 LD A,(BIGDISK) ;8 or 16 bit block numbers? f658 b7 OR A f659 3a d9 f9 LD A,(RELBLOCK) ;(* update this entry *) f65c ca 66 f6 JP Z,WTSEQ4 ;zero means 16 bit ones. f65f cd 66 f1 CALL ADDA2HL ;(HL)=(HL)+(A) f662 73 LD (HL),E ;store new block number. f663 c3 6e f6 JP WTSEQ5 f666 4f WTSEQ4: LD C,A ;compute spot in this 16 bit table. f667 06 00 LD B,0 f669 09 ADD HL,BC f66a 09 ADD HL,BC f66b 73 LD (HL),E ;stuff block number (DE) there. f66c 23 INC HL f66d 72 LD (HL),D f66e 0e 02 WTSEQ5: LD C,2 ;set (C) to indicate writing to un-used disk space. f670 3a 47 ef WTSEQ6: LD A,(STATUS) ;are we ok so far? f673 b7 OR A f674 c0 RET NZ f675 c5 PUSH BC ;yes, save write flag for bios (register C). f676 cd 8c f0 CALL LOGICAL ;convert (BLKNMBR) over to loical sectors. f679 3a d7 f9 LD A,(MODE) ;get access mode flag (1=sequential, f67c 3d DEC A ;0=random, 2=special?). f67d 3d DEC A f67e c2 bd f6 JP NZ,WTSEQ9 f681 ; f681 ; Special random i/o from function #40. Maybe for M/PM, but the f681 ; current block, if it has not been written to, will be zeroed f681 ; out and then written (reason?). f681 ; f681 c1 POP BC f682 c5 PUSH BC f683 79 LD A,C ;get write status flag (2=writing unused space). f684 3d DEC A f685 3d DEC A f686 c2 bd f6 JP NZ,WTSEQ9 f689 e5 PUSH HL f68a 2a bb f9 LD HL,(DIRBUF) ;zero out the directory buffer. f68d 57 LD D,A ;note that (A) is zero here. f68e 77 WTSEQ7: LD (HL),A f68f 23 INC HL f690 14 INC D ;do 128 bytes. f691 f2 8e f6 JP P,WTSEQ7 f694 cd e2 f1 CALL DIRDMA ;tell the bios the dma address for directory access. f697 2a e9 f9 LD HL,(LOGSECT) ;get sector that starts current block. f69a 0e 02 LD C,2 ;set 'writing to unused space' flag. f69c 22 e7 f9 WTSEQ8: LD (BLKNMBR),HL ;save sector to write. f69f c5 PUSH BC f6a0 cd d3 ef CALL TRKSEC1 ;determine its track and sector numbers. f6a3 c1 POP BC f6a4 cd ba ef CALL DOWRITE ;now write out 128 bytes of zeros. f6a7 2a e7 f9 LD HL,(BLKNMBR) ;get sector number. f6aa 0e 00 LD C,0 ;set normal write flag. f6ac 3a c6 f9 LD A,(BLKMASK) ;determine if we have written the entire f6af 47 LD B,A ;physical block. f6b0 a5 AND L f6b1 b8 CP B f6b2 23 INC HL ;prepare for the next one. f6b3 c2 9c f6 JP NZ,WTSEQ8 ;continue until (BLKMASK+1) sectors written. f6b6 e1 POP HL ;reset next sector number. f6b7 22 e7 f9 LD (BLKNMBR),HL f6ba cd dc f1 CALL DEFDMA ;and reset dma address. f6bd ; f6bd ; Normal disk write. Set the desired track and sector then f6bd ; do the actual write. f6bd ; f6bd cd d3 ef WTSEQ9: CALL TRKSEC1 ;determine track and sector for this write. f6c0 c1 POP BC ;get write status flag. f6c1 c5 PUSH BC f6c2 cd ba ef CALL DOWRITE ;and write this out. f6c5 c1 POP BC f6c6 3a e5 f9 LD A,(SAVNREC) ;get number of records in file. f6c9 21 e3 f9 LD HL,SAVNXT ;get last record written. f6cc be CP (HL) f6cd da d4 f6 JP C,WTSEQ10 f6d0 77 LD (HL),A ;we have to update record count. f6d1 34 INC (HL) f6d2 0e 02 LD C,2 f6d4 ; f6d4 ;* This area has been patched to correct disk update problem f6d4 ;* when using blocking and de-blocking in the BIOS. f6d4 ; f6d4 00 WTSEQ10:NOP ;was 'dcr c' f6d5 00 NOP ;was 'dcr c' f6d6 21 00 00 LD HL,0 ;was 'jnz wtseq99' f6d9 ; f6d9 ; * End of patch. f6d9 ; f6d9 f5 PUSH AF f6da cd 6b f1 CALL GETS2 ;set 'extent written to' flag. f6dd e6 7f AND 7FH ;(* clear bit 7 *) f6df 77 LD (HL),A f6e0 f1 POP AF ;get record count for this extent. f6e1 fe 7f WTSEQ99:CP 127 ;is it full? f6e3 c2 02 f7 JP NZ,WTSEQ12 f6e6 3a d7 f9 LD A,(MODE) ;yes, are we in sequential mode? f6e9 fe 01 CP 1 f6eb c2 02 f7 JP NZ,WTSEQ12 f6ee cd d4 f0 CALL SETNREC ;yes, set next record number. f6f1 cd 5c f5 CALL GETNEXT ;and get next empty space in directory. f6f4 21 47 ef LD HL,STATUS ;ok? f6f7 7e LD A,(HL) f6f8 b7 OR A f6f9 c2 00 f7 JP NZ,WTSEQ11 f6fc 3d DEC A ;yes, set record count to -1. f6fd 32 e5 f9 LD (SAVNREC),A f700 36 00 WTSEQ11:LD (HL),0 ;clear status. f702 c3 d4 f0 WTSEQ12:JP SETNREC ;set next record to access. f705 ; f705 ; For random i/o, set the fcb for the desired record number f705 ; based on the 'r0,r1,r2' bytes. These bytes in the fcb are f705 ; used as follows: f705 ; f705 ; fcb+35 fcb+34 fcb+33 f705 ; | 'r-2' | 'r-1' | 'r-0' | f705 ; |7 0 | 7 0 | 7 0| f705 ; |0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0| f705 ; | overflow | | extra | extent | record # | f705 ; | ______________| |_extent|__number___|_____________| f705 ; also 's2' f705 ; f705 ; On entry, register (C) contains 0ffh if this is a read f705 ; and thus we can not access unwritten disk space. Otherwise, f705 ; another extent will be opened (for writing) if required. f705 ; f705 af POSITION: XOR A ;set random i/o flag. f706 32 d7 f9 LD (MODE),A f709 ; f709 ; Special entry (function #40). M/PM ? f709 ; f709 c5 POSITN1:PUSH BC ;save read/write flag. f70a 2a 45 ef LD HL,(PARAMS) ;get address of fcb. f70d eb EX DE,HL f70e 21 21 00 LD HL,33 ;now get byte 'r0'. f711 19 ADD HL,DE f712 7e LD A,(HL) f713 e6 7f AND 7FH ;keep bits 0-6 for the record number to access. f715 f5 PUSH AF f716 7e LD A,(HL) ;now get bit 7 of 'r0' and bits 0-3 of 'r1'. f717 17 RLA f718 23 INC HL f719 7e LD A,(HL) f71a 17 RLA f71b e6 1f AND 1FH ;and save this in bits 0-4 of (C). f71d 4f LD C,A ;this is the extent byte. f71e 7e LD A,(HL) ;now get the extra extent byte. f71f 1f RRA f720 1f RRA f721 1f RRA f722 1f RRA f723 e6 0f AND 0FH f725 47 LD B,A ;and save it in (B). f726 f1 POP AF ;get record number back to (A). f727 23 INC HL ;check overflow byte 'r2'. f728 6e LD L,(HL) f729 2c INC L f72a 2d DEC L f72b 2e 06 LD L,6 ;prepare for error. f72d c2 8d f7 JP NZ,POSITN5 ;out of disk space error. f730 21 20 00 LD HL,32 ;store record number into fcb. f733 19 ADD HL,DE f734 77 LD (HL),A f735 21 0c 00 LD HL,12 ;and now check the extent byte. f738 19 ADD HL,DE f739 79 LD A,C f73a 96 SUB (HL) ;same extent as before? f73b c2 49 f7 JP NZ,POSITN2 f73e 21 0e 00 LD HL,14 ;yes, check extra extent byte 's2' also. f741 19 ADD HL,DE f742 78 LD A,B f743 96 SUB (HL) f744 e6 7f AND 7FH f746 ca 81 f7 JP Z,POSITN3 ;same, we are almost done then. f749 ; f749 ; Get here when another extent is required. f749 ; f749 c5 POSITN2:PUSH BC f74a d5 PUSH DE f74b cd a4 f4 CALL CLOSEIT ;close current extent. f74e d1 POP DE f74f c1 POP BC f750 2e 03 LD L,3 ;prepare for error. f752 3a 47 ef LD A,(STATUS) f755 3c INC A f756 ca 86 f7 JP Z,POSITN4 ;close error. f759 21 0c 00 LD HL,12 ;put desired extent into fcb now. f75c 19 ADD HL,DE f75d 71 LD (HL),C f75e 21 0e 00 LD HL,14 ;and store extra extent byte 's2'. f761 19 ADD HL,DE f762 70 LD (HL),B f763 cd 53 f4 CALL OPENIT ;try and get this extent. f766 3a 47 ef LD A,(STATUS) ;was it there? f769 3c INC A f76a c2 81 f7 JP NZ,POSITN3 f76d c1 POP BC ;no. can we create a new one (writing?). f76e c5 PUSH BC f76f 2e 04 LD L,4 ;prepare for error. f771 0c INC C f772 ca 86 f7 JP Z,POSITN4 ;nope, reading unwritten space error. f775 cd 26 f5 CALL GETEMPTY ;yes we can, try to find space. f778 2e 05 LD L,5 ;prepare for error. f77a 3a 47 ef LD A,(STATUS) f77d 3c INC A f77e ca 86 f7 JP Z,POSITN4 ;out of space? f781 ; f781 ; Normal return location. Clear error code and return. f781 ; f781 c1 POSITN3:POP BC ;restore stack. f782 af XOR A ;and clear error code byte. f783 c3 03 ef JP SETSTAT f786 ; f786 ; Error. Set the 's2' byte to indicate this (why?). f786 ; f786 e5 POSITN4:PUSH HL f787 cd 6b f1 CALL GETS2 f78a 36 c0 LD (HL),0C0H f78c e1 POP HL f78d ; f78d ; Return with error code (presently in L). f78d ; f78d c1 POSITN5:POP BC f78e 7d LD A,L ;get error code. f78f 32 47 ef LD (STATUS),A f792 c3 7a f1 JP SETS2B7 f795 ; f795 ; Read a random record. f795 ; f795 0e ff READRAN:LD C,0FFH ;set 'read' status. f797 cd 05 f7 CALL POSITION ;position the file to proper record. f79a cc c3 f5 CALL Z,RDSEQ1 ;and read it as usual (if no errors). f79d c9 RET f79e ; f79e ; Write to a random record. f79e ; f79e 0e 00 WRITERAN: LD C,0 ;set 'writing' flag. f7a0 cd 05 f7 CALL POSITION ;position the file to proper record. f7a3 cc 05 f6 CALL Z,WTSEQ1 ;and write as usual (if no errors). f7a6 c9 RET f7a7 ; f7a7 ; Compute the random record number. Enter with (HL) pointing f7a7 ; to a fcb an (DE) contains a relative location of a record f7a7 ; number. On exit, (C) contains the 'r0' byte, (B) the 'r1' f7a7 ; byte, and (A) the 'r2' byte. f7a7 ; f7a7 ; On return, the zero flag is set if the record is within f7a7 ; bounds. Otherwise, an overflow occured. f7a7 ; f7a7 eb COMPRAND: EX DE,HL ;save fcb pointer in (DE). f7a8 19 ADD HL,DE ;compute relative position of record #. f7a9 4e LD C,(HL) ;get record number into (BC). f7aa 06 00 LD B,0 f7ac 21 0c 00 LD HL,12 ;now get extent. f7af 19 ADD HL,DE f7b0 7e LD A,(HL) ;compute (BC)=(record #)+(extent)*128. f7b1 0f RRCA ;move lower bit into bit 7. f7b2 e6 80 AND 80H ;and ignore all other bits. f7b4 81 ADD A,C ;add to our record number. f7b5 4f LD C,A f7b6 3e 00 LD A,0 ;take care of any carry. f7b8 88 ADC A,B f7b9 47 LD B,A f7ba 7e LD A,(HL) ;now get the upper bits of extent into f7bb 0f RRCA ;bit positions 0-3. f7bc e6 0f AND 0FH ;and ignore all others. f7be 80 ADD A,B ;add this in to 'r1' byte. f7bf 47 LD B,A f7c0 21 0e 00 LD HL,14 ;get the 's2' byte (extra extent). f7c3 19 ADD HL,DE f7c4 7e LD A,(HL) f7c5 87 ADD A,A ;and shift it left 4 bits (bits 4-7). f7c6 87 ADD A,A f7c7 87 ADD A,A f7c8 87 ADD A,A f7c9 f5 PUSH AF ;save carry flag (bit 0 of flag byte). f7ca 80 ADD A,B ;now add extra extent into 'r1'. f7cb 47 LD B,A f7cc f5 PUSH AF ;and save carry (overflow byte 'r2'). f7cd e1 POP HL ;bit 0 of (L) is the overflow indicator. f7ce 7d LD A,L f7cf e1 POP HL ;and same for first carry flag. f7d0 b5 OR L ;either one of these set? f7d1 e6 01 AND 01H ;only check the carry flags. f7d3 c9 RET f7d4 ; f7d4 ; Routine to setup the fcb (bytes 'r0', 'r1', 'r2') to f7d4 ; reflect the last record used for a random (or other) file. f7d4 ; This reads the directory and looks at all extents computing f7d4 ; the largerst record number for each and keeping the maximum f7d4 ; value only. Then 'r0', 'r1', and 'r2' will reflect this f7d4 ; maximum record number. This is used to compute the space used f7d4 ; by a random file. f7d4 ; f7d4 0e 0c RANSIZE:LD C,12 ;look thru directory for first entry with f7d6 cd 1a f3 CALL FINDFST ;this name. f7d9 2a 45 ef LD HL,(PARAMS) ;zero out the 'r0, r1, r2' bytes. f7dc 11 21 00 LD DE,33 f7df 19 ADD HL,DE f7e0 e5 PUSH HL f7e1 72 LD (HL),D ;note that (D)=0. f7e2 23 INC HL f7e3 72 LD (HL),D f7e4 23 INC HL f7e5 72 LD (HL),D f7e6 cd f7 f1 RANSIZ1:CALL CKFILPOS ;is there an extent to process? f7e9 ca 0e f8 JP Z,RANSIZ3 ;no, we are done. f7ec cd 60 f1 CALL FCB2HL ;set (HL) pointing to proper fcb in dir. f7ef 11 0f 00 LD DE,15 ;point to last record in extent. f7f2 cd a7 f7 CALL COMPRAND ;and compute random parameters. f7f5 e1 POP HL f7f6 e5 PUSH HL ;now check these values against those f7f7 5f LD E,A ;already in fcb. f7f8 79 LD A,C ;the carry flag will be set if those f7f9 96 SUB (HL) ;in the fcb represent a larger size than f7fa 23 INC HL ;this extent does. f7fb 78 LD A,B f7fc 9e SBC A,(HL) f7fd 23 INC HL f7fe 7b LD A,E f7ff 9e SBC A,(HL) f800 da 08 f8 JP C,RANSIZ2 f803 73 LD (HL),E ;we found a larger (in size) extent. f804 2b DEC HL ;stuff these values into fcb. f805 70 LD (HL),B f806 2b DEC HL f807 71 LD (HL),C f808 cd 2f f3 RANSIZ2:CALL FINDNXT ;now get the next extent. f80b c3 e6 f7 JP RANSIZ1 ;continue til all done. f80e e1 RANSIZ3:POP HL ;we are done, restore the stack and f80f c9 RET ;return. f810 ; f810 ; Function to return the random record position of a given f810 ; file which has been read in sequential mode up to now. f810 ; f810 2a 45 ef SETRAN: LD HL,(PARAMS) ;point to fcb. f813 11 20 00 LD DE,32 ;and to last used record. f816 cd a7 f7 CALL COMPRAND ;compute random position. f819 21 21 00 LD HL,33 ;now stuff these values into fcb. f81c 19 ADD HL,DE f81d 71 LD (HL),C ;move 'r0'. f81e 23 INC HL f81f 70 LD (HL),B ;and 'r1'. f820 23 INC HL f821 77 LD (HL),A ;and lastly 'r2'. f822 c9 RET f823 ; f823 ; This routine select the drive specified in (ACTIVE) and f823 ; update the login vector and bitmap table if this drive was f823 ; not already active. f823 ; f823 2a b1 f9 LOGINDRV: LD HL,(LOGIN) ;get the login vector. f826 3a 44 ef LD A,(ACTIVE) ;get the default drive. f829 4f LD C,A f82a cd ec f0 CALL SHIFTR ;position active bit for this drive f82d e5 PUSH HL ;into bit 0. f82e eb EX DE,HL f82f cd 5b ef CALL SELECT ;select this drive. f832 e1 POP HL f833 cc 49 ef CALL Z,SLCTERR ;valid drive? f836 7d LD A,L ;is this a newly activated drive? f837 1f RRA f838 d8 RET C f839 2a b1 f9 LD HL,(LOGIN) ;yes, update the login vector. f83c 4d LD C,L f83d 44 LD B,H f83e cd 0d f1 CALL SETBIT f841 22 b1 f9 LD (LOGIN),HL ;and save. f844 c3 a5 f2 JP BITMAP ;now update the bitmap. f847 ; f847 ; Function to set the active disk number. f847 ; f847 3a d8 f9 SETDSK: LD A,(EPARAM) ;get parameter passed and see if this f84a 21 44 ef LD HL,ACTIVE ;represents a change in drives. f84d be CP (HL) f84e c8 RET Z f84f 77 LD (HL),A ;yes it does, log it in. f850 c3 23 f8 JP LOGINDRV f853 ; f853 ; This is the 'auto disk select' routine. The firsst byte f853 ; of the fcb is examined for a drive specification. If non f853 ; zero then the drive will be selected and loged in. f853 ; f853 3e ff AUTOSEL:LD A,0FFH ;say 'auto-select activated'. f855 32 e0 f9 LD (AUTO),A f858 2a 45 ef LD HL,(PARAMS) ;get drive specified. f85b 7e LD A,(HL) f85c e6 1f AND 1FH ;look at lower 5 bits. f85e 3d DEC A ;adjust for (1=A, 2=B) etc. f85f 32 d8 f9 LD (EPARAM),A ;and save for the select routine. f862 fe 1e CP 1EH ;check for 'no change' condition. f864 d2 77 f8 JP NC,AUTOSL1 ;yes, don't change. f867 3a 44 ef LD A,(ACTIVE) ;we must change, save currently active f86a 32 e1 f9 LD (OLDDRV),A ;drive. f86d 7e LD A,(HL) ;and save first byte of fcb also. f86e 32 e2 f9 LD (AUTOFLAG),A ;this must be non-zero. f871 e6 e0 AND 0E0H ;whats this for (bits 6,7 are used for f873 77 LD (HL),A ;something)? f874 cd 47 f8 CALL SETDSK ;select and log in this drive. f877 3a 43 ef AUTOSL1:LD A,(USERNO) ;move user number into fcb. f87a 2a 45 ef LD HL,(PARAMS) ;(* upper half of first byte *) f87d b6 OR (HL) f87e 77 LD (HL),A f87f c9 RET ;and return (all done). f880 ; f880 ; Function to return the current cp/m version number. f880 ; f880 3e 22 GETVER: LD A,022H ;version 2.2 f882 c3 03 ef JP SETSTAT f885 ; f885 ; Function to reset the disk system. f885 ; f885 21 00 00 RSTDSK: LD HL,0 ;clear write protect status and log f888 22 af f9 LD (WRTPRT),HL ;in vector. f88b 22 b1 f9 LD (LOGIN),HL f88e af XOR A ;select drive 'A'. f88f 32 44 ef LD (ACTIVE),A f892 21 80 00 LD HL,TBUFF ;setup default dma address. f895 22 b3 f9 LD (USERDMA),HL f898 cd dc f1 CALL DEFDMA f89b c3 23 f8 JP LOGINDRV ;now log in drive 'A'. f89e ; f89e ; Function to open a specified file. f89e ; f89e cd 74 f1 OPENFIL:CALL CLEARS2 ;clear 's2' byte. f8a1 cd 53 f8 CALL AUTOSEL ;select proper disk. f8a4 c3 53 f4 JP OPENIT ;and open the file. f8a7 ; f8a7 ; Function to close a specified file. f8a7 ; f8a7 cd 53 f8 CLOSEFIL: CALL AUTOSEL ;select proper disk. f8aa c3 a4 f4 JP CLOSEIT ;and close the file. f8ad ; f8ad ; Function to return the first occurence of a specified file f8ad ; name. If the first byte of the fcb is '?' then the name will f8ad ; not be checked (get the first entry no matter what). f8ad ; f8ad 0e 00 GETFST: LD C,0 ;prepare for special search. f8af eb EX DE,HL f8b0 7e LD A,(HL) ;is first byte a '?'? f8b1 fe 3f CP '?' f8b3 ca c4 f8 JP Z,GETFST1 ;yes, just get very first entry (zero length match). f8b6 cd a8 f0 CALL SETEXT ;get the extension byte from fcb. f8b9 7e LD A,(HL) ;is it '?'? if yes, then we want f8ba fe 3f CP '?' ;an entry with a specific 's2' byte. f8bc c4 74 f1 CALL NZ,CLEARS2 ;otherwise, look for a zero 's2' byte. f8bf cd 53 f8 CALL AUTOSEL ;select proper drive. f8c2 0e 0f LD C,15 ;compare bytes 0-14 in fcb (12&13 excluded). f8c4 cd 1a f3 GETFST1:CALL FINDFST ;find an entry and then move it into f8c7 c3 eb f1 JP MOVEDIR ;the users dma space. f8ca ; f8ca ; Function to return the next occurence of a file name. f8ca ; f8ca 2a db f9 GETNXT: LD HL,(SAVEFCB) ;restore pointers. note that no f8cd 22 45 ef LD (PARAMS),HL ;other dbos calls are allowed. f8d0 cd 53 f8 CALL AUTOSEL ;no error will be returned, but the f8d3 cd 2f f3 CALL FINDNXT ;results will be wrong. f8d6 c3 eb f1 JP MOVEDIR f8d9 ; f8d9 ; Function to delete a file by name. f8d9 ; f8d9 cd 53 f8 DELFILE:CALL AUTOSEL ;select proper drive. f8dc cd 9e f3 CALL ERAFILE ;erase the file. f8df c3 03 f3 JP STSTATUS ;set status and return. f8e2 ; f8e2 ; Function to execute a sequential read of the specified f8e2 ; record number. f8e2 ; f8e2 cd 53 f8 READSEQ:CALL AUTOSEL ;select proper drive then read. f8e5 c3 be f5 JP RDSEQ f8e8 ; f8e8 ; Function to write the net sequential record. f8e8 ; f8e8 cd 53 f8 WRTSEQ: CALL AUTOSEL ;select proper drive then write. f8eb c3 00 f6 JP WTSEQ f8ee ; f8ee ; Create a file function. f8ee ; f8ee cd 74 f1 FCREATE:CALL CLEARS2 ;clear the 's2' byte on all creates. f8f1 cd 53 f8 CALL AUTOSEL ;select proper drive and get the next f8f4 c3 26 f5 JP GETEMPTY ;empty directory space. f8f7 ; f8f7 ; Function to rename a file. f8f7 ; f8f7 cd 53 f8 RENFILE:CALL AUTOSEL ;select proper drive and then switch f8fa cd 18 f4 CALL CHGNAMES ;file names. f8fd c3 03 f3 JP STSTATUS f900 ; f900 ; Function to return the login vector. f900 ; f900 2a b1 f9 GETLOG: LD HL,(LOGIN) f903 c3 2b f9 JP GETPRM1 f906 ; f906 ; Function to return the current disk assignment. f906 ; f906 3a 44 ef GETCRNT:LD A,(ACTIVE) f909 c3 03 ef JP SETSTAT f90c ; f90c ; Function to set the dma address. f90c ; f90c eb PUTDMA: EX DE,HL f90d 22 b3 f9 LD (USERDMA),HL ;save in our space and then get to f910 c3 dc f1 JP DEFDMA ;the bios with this also. f913 ; f913 ; Function to return the allocation vector. f913 ; f913 2a c1 f9 GETALOC:LD HL,(ALOCVECT) f916 c3 2b f9 JP GETPRM1 f919 ; f919 ; Function to return the read-only status vector. f919 ; f919 2a af f9 GETROV: LD HL,(WRTPRT) f91c c3 2b f9 JP GETPRM1 f91f ; f91f ; Function to set the file attributes (read-only, system). f91f ; f91f cd 53 f8 SETATTR:CALL AUTOSEL ;select proper drive then save attributes. f922 cd 3d f4 CALL SAVEATTR f925 c3 03 f3 JP STSTATUS f928 ; f928 ; Function to return the address of the disk parameter block f928 ; for the current drive. f928 ; f928 2a bd f9 GETPARM:LD HL,(DISKPB) f92b 22 47 ef GETPRM1:LD (STATUS),HL f92e c9 RET f92f ; f92f ; Function to get or set the user number. If (E) was (FF) f92f ; then this is a request to return the current user number. f92f ; Else set the user number from (E). f92f ; f92f 3a d8 f9 GETUSER:LD A,(EPARAM) ;get parameter. f932 fe ff CP 0FFH ;get user number? f934 c2 3d f9 JP NZ,SETUSER f937 3a 43 ef LD A,(USERNO) ;yes, just do it. f93a c3 03 ef JP SETSTAT f93d e6 1f SETUSER:AND 1FH ;no, we should set it instead. keep low f93f 32 43 ef LD (USERNO),A ;bits (0-4) only. f942 c9 RET f943 ; f943 ; Function to read a random record from a file. f943 ; f943 cd 53 f8 RDRANDOM: CALL AUTOSEL ;select proper drive and read. f946 c3 95 f7 JP READRAN f949 ; f949 ; Function to compute the file size for random files. f949 ; f949 cd 53 f8 WTRANDOM: CALL AUTOSEL ;select proper drive and write. f94c c3 9e f7 JP WRITERAN f94f ; f94f ; Function to compute the size of a random file. f94f ; f94f cd 53 f8 FILESIZE: CALL AUTOSEL ;select proper drive and check file length f952 c3 d4 f7 JP RANSIZE f955 ; f955 ; Function #37. This allows a program to log off any drives. f955 ; On entry, set (DE) to contain a word with bits set for those f955 ; drives that are to be logged off. The log-in vector and the f955 ; write protect vector will be updated. This must be a M/PM f955 ; special function. f955 ; f955 2a 45 ef LOGOFF: LD HL,(PARAMS) ;get drives to log off. f958 7d LD A,L ;for each bit that is set, we want f959 2f CPL ;to clear that bit in (LOGIN) f95a 5f LD E,A ;and (WRTPRT). f95b 7c LD A,H f95c 2f CPL f95d 2a b1 f9 LD HL,(LOGIN) ;reset the login vector. f960 a4 AND H f961 57 LD D,A f962 7d LD A,L f963 a3 AND E f964 5f LD E,A f965 2a af f9 LD HL,(WRTPRT) f968 eb EX DE,HL f969 22 b1 f9 LD (LOGIN),HL ;and save. f96c 7d LD A,L ;now do the write protect vector. f96d a3 AND E f96e 6f LD L,A f96f 7c LD A,H f970 a2 AND D f971 67 LD H,A f972 22 af f9 LD (WRTPRT),HL ;and save. all done. f975 c9 RET f976 ; f976 ; Get here to return to the user. f976 ; f976 3a e0 f9 GOBACK: LD A,(AUTO) ;was auto select activated? f979 b7 OR A f97a ca 93 f9 JP Z,GOBACK1 f97d 2a 45 ef LD HL,(PARAMS) ;yes, but was a change made? f980 36 00 LD (HL),0 ;(* reset first byte of fcb *) f982 3a e2 f9 LD A,(AUTOFLAG) f985 b7 OR A f986 ca 93 f9 JP Z,GOBACK1 f989 77 LD (HL),A ;yes, reset first byte properly. f98a 3a e1 f9 LD A,(OLDDRV) ;and get the old drive and select it. f98d 32 d8 f9 LD (EPARAM),A f990 cd 47 f8 CALL SETDSK f993 2a 11 ef GOBACK1:LD HL,(USRSTACK) ;reset the users stack pointer. f996 f9 LD SP,HL f997 2a 47 ef LD HL,(STATUS) ;get return status. f99a 7d LD A,L ;force version 1.4 compatability. f99b 44 LD B,H f99c c9 RET ;and go back to user. f99d ; f99d ; Function #40. This is a special entry to do random i/o. f99d ; For the case where we are writing to unused disk space, this f99d ; space will be zeroed out first. This must be a M/PM special f99d ; purpose function, because why would any normal program even f99d ; care about the previous contents of a sector about to be f99d ; written over. f99d ; f99d cd 53 f8 WTSPECL:CALL AUTOSEL ;select proper drive. f9a0 3e 02 LD A,2 ;use special write mode. f9a2 32 d7 f9 LD (MODE),A f9a5 0e 00 LD C,0 ;set write indicator. f9a7 cd 09 f7 CALL POSITN1 ;position the file. f9aa cc 05 f6 CALL Z,WTSEQ1 ;and write (if no errors). f9ad c9 RET f9ae ; f9ae ;************************************************************** f9ae ;* f9ae ;* BDOS data storage pool. f9ae ;* f9ae ;************************************************************** f9ae ; f9ae e5 EMPTYFCB: DB 0E5H ;empty directory segment indicator. f9af 00 00 WRTPRT: DW 0 ;write protect status for all 16 drives. f9b1 00 00 LOGIN: DW 0 ;drive active word (1 bit per drive). f9b3 80 00 USERDMA:DW 080H ;user's dma address (defaults to 80h). f9b5 ; f9b5 ; Scratch areas from parameter block. f9b5 ; f9b5 00 00 SCRATCH1: DW 0 ;relative position within dir segment for file (0-3). f9b7 00 00 SCRATCH2: DW 0 ;last selected track number. f9b9 00 00 SCRATCH3: DW 0 ;last selected sector number. f9bb ; f9bb ; Disk storage areas from parameter block. f9bb ; f9bb 00 00 DIRBUF: DW 0 ;address of directory buffer to use. f9bd 00 00 DISKPB: DW 0 ;contains address of disk parameter block. f9bf 00 00 CHKVECT:DW 0 ;address of check vector. f9c1 00 00 ALOCVECT: DW 0 ;address of allocation vector (bit map). f9c3 ; f9c3 ; Parameter block returned from the bios. f9c3 ; f9c3 00 00 SECTORS:DW 0 ;sectors per track from bios. f9c5 00 BLKSHFT:DB 0 ;block shift. f9c6 00 BLKMASK:DB 0 ;block mask. f9c7 00 EXTMASK:DB 0 ;extent mask. f9c8 00 00 DSKSIZE:DW 0 ;disk size from bios (number of blocks-1). f9ca 00 00 DIRSIZE:DW 0 ;directory size. f9cc 00 00 ALLOC0: DW 0 ;storage for first bytes of bit map (dir space used). f9ce 00 00 ALLOC1: DW 0 f9d0 00 00 OFFSET: DW 0 ;first usable track number. f9d2 00 00 XLATE: DW 0 ;sector translation table address. f9d4 ; f9d4 ; f9d4 00 CLOSEFLG: DB 0 ;close flag (=0ffh is extent written ok). f9d5 00 RDWRTFLG: DB 0 ;read/write flag (0ffh=read, 0=write). f9d6 00 FNDSTAT:DB 0 ;filename found status (0=found first entry). f9d7 00 MODE: DB 0 ;I/o mode select (0=random, 1=sequential, 2=special random). f9d8 00 EPARAM: DB 0 ;storage for register (E) on entry to bdos. f9d9 00 RELBLOCK: DB 0 ;relative position within fcb of block number written. f9da 00 COUNTER:DB 0 ;byte counter for directory name searches. f9db 00 00 00 00 SAVEFCB:DW 0,0 ;save space for address of fcb (for directory searches). f9df 00 BIGDISK:DB 0 ;if =0 then disk is > 256 blocks long. f9e0 00 AUTO: DB 0 ;if non-zero, then auto select activated. f9e1 00 OLDDRV: DB 0 ;on auto select, storage for previous drive. f9e2 00 AUTOFLAG: DB 0 ;if non-zero, then auto select changed drives. f9e3 00 SAVNXT: DB 0 ;storage for next record number to access. f9e4 00 SAVEXT: DB 0 ;storage for extent number of file. f9e5 00 00 SAVNREC:DW 0 ;storage for number of records in file. f9e7 00 00 BLKNMBR:DW 0 ;block number (physical sector) used within a file or logical sect f9e9 00 00 LOGSECT:DW 0 ;starting logical (128 byte) sector of block (physical sector). f9eb 00 FCBPOS: DB 0 ;relative position within buffer for fcb of file of interest. f9ec 00 00 FILEPOS:DW 0 ;files position within directory (0 to max entries -1). f9ee ; f9ee ; Disk directory buffer checksum bytes. One for each of the f9ee ; 16 possible drives. f9ee ; f9ee 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 CKSUMTBL: DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 f9fe 00 00 DEFB 0,0 ;Adjust to make BOOT at FA00h for 64K system fa00 ; fa00 ;************************************************************** fa00 ;* fa00 ;* B I O S J U M P T A B L E fa00 ;* fa00 ;************************************************************** fa00 ; fa00 c3 00 00 BOOT: JP 0 ;NOTE WE USE FAKE DESTINATIONS fa03 c3 00 00 WBOOT: JP 0 fa06 c3 00 00 CONST: JP 0 fa09 c3 00 00 CONIN: JP 0 fa0c c3 00 00 CONOUT: JP 0 fa0f c3 00 00 LIST: JP 0 fa12 c3 00 00 PUNCH: JP 0 fa15 c3 00 00 READER: JP 0 fa18 c3 00 00 HOME: JP 0 fa1b c3 00 00 SELDSK: JP 0 fa1e c3 00 00 SETTRK: JP 0 fa21 c3 00 00 SETSEC: JP 0 fa24 c3 00 00 SETDMA: JP 0 fa27 c3 00 00 READ: JP 0 fa2a c3 00 00 WRITE: JP 0 fa2d c3 00 00 PRSTAT: JP 0 fa30 c3 00 00 SECTRN: JP 0 fa33 ; fa33 ;* fa33 ;****************** E N D O F C P / M ***************** fa33 ;* fa33 # End of file cpm22.asm fa33