; ; TITLE CP/M SPEED-UP BY DISK I/O BUFFERING ; FILENAME FAST.ASM ; AUTHOR Robert A. Van Valzah 12/25/78 ; LAST REVISED 8-Oct-1981 David Bennett ; REASON Upgrade to CP/M 2.0 compatibility ; ; ; \\\\\\\\\\\\\\\\\ ///////////////// ; >>>>>>>>>>>>>>>>> E Q U A T E S <<<<<<<<<<<<<<<<< ; ///////////////// \\\\\\\\\\\\\\\\\ ; BASE EQU 100H ;ORG FOR THIS ASSEMBLY OF FAST VERS EQU 201 ;FAST VERSION NUMBER ; ; CP/M SYSTEM ENTRY POINTS AND RAM EQUATES ; BOOT EQU 0 ;ADDRESS OF WARM BOOT VECTOR CURDSK EQU 4 ;ADDRESS OF CURRENTLY LOGGED DRIVE BDOS EQU 5 ;ADDRESS OF BDOS ENTRY VECTOR DBUF EQU 80H ;BUFFER USED FOR COMMAND LINE HOLDING TPA EQU 100H ;TRANSIENT PROGRAM AREA ; ; GLOBAL EQUATES ; SECLEN EQU 80H ;LENGTH OF A SECTOR IN BYTES DIRTRK EQU 2 ;TRACK WHICH HOLDS DIRECTORY ; ; TOKEN VALUE EQUATES ; SENTTOK EQU 1 ;TOKEN SHOWING DRIVE & TRACK INFO SENT UPDTTOK EQU 1 ;TOKEN SHOWING SECTOR GETS WRITTEN ONLNTOK EQU 3 ;TOKEN SHOWING THAT A DRIVE IS 'ON LINE' ; ; ASCII CHARACTER EQUATES ; CR EQU 13 ;CARRIAGE RETURN LF EQU 10 ;LINE FEED ; ; BDOS FUNCTION NUMBER EQUATES ; READ EQU 20 ;READ A RECORD FROM A FILE OPEN EQU 15 ;OPEN A FILE FOR READING SETDMA EQU 26 ;CHANGE DMA ADDRESS PAGE ; ; ; \\\\\\\\\\\\\\\\ //////////////// ; >>>>>>>>>>>>>>>> M A C R O S <<<<<<<<<<<<<<<< ; //////////////// \\\\\\\\\\\\\\\\ ; $-MACRO ; ; THE CPM MACRO CALLS BDOS TO EXECUTE THE FUNCTION PASSED ; AS THE FIRST ARGUMENT. THE SECOND ARGUMENT IS THE ; 'INFORMATION' TO PASSED TO CP/M (IF ANY). ; CPM MACRO FUNC,INFO MVI C,FUNC IF NOT NUL INFO LXI D,INFO ENDIF CALL BDOS ENDM PAGE ; ; \\\\\\\\\\\\\\\\ F A S T //////////////// ; >>>>>>>>>>>>>>>> I N I T <<<<<<<<<<<<<<<< ; //////////////// M O D U L E \\\\\\\\\\\\\\\\ ; ; ; THIS MODULE MAY BE COMPLETELY OVERLAID ONCE FAST HAS BEEN ; SUCCESSFULLY INSTALLED IN THE SYSTEM. IT BECOMES PART OF ; THE TPA. ; ; ; CONTROL IS TRANSFERED TO THIS ADDRESS (THE BASE OF FAST) ; UPON COMPLETION OF THE PACKUP MODULE. HERE, WE INSTALL ; FAST AND LOAD THE TRANSIENT. ; ORG BASE JMP FASTNTRY ;JUMP AROUND FIRST PARAMETER BLOCK ; ; THIS IS THE FIRST (OF TWO) PARAMETER PASSING BLOCKS. ; INFORMATION IS PASSED BETWEEN THE FAST AND PACKUP MODULES. ; ANY CHANGES MADE TO THIS BLOCK MUST ALSO BE MADE TO THE ; CORRESPONDING BLOCK IN THE PACKUP MODULE. ; ;************************************************************** ; * LEN: ; * DW CODELEN ;RELOCATION LENGTH * ; * FCB: ;FCB USED TO LOAD COM FILE * DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; * DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; * ; * ;************************************************************** ; ; END OF FIRST PARAMETER BLOCK ; FASTNTRY: LXI SP,STACK ;USE LOCAL STACK SPACE CALL LINKUP ;INSTALL FAST BY LINKING TO CP/M LDA CURDSK ;INIT DDB POINTERS TO CURRENT DRIVE MOV C,A CALL FSETDSK CALL LOADTRAN ;LOAD THE TRANSIENT CALL MSGP ;PRINT FAST SIGNON MESSAGE DB 'Alfred Hospital FAST ' ;DEFINE VERSION NUMBER IN ASCII DB '0'+vers/100 db '.' DB '0'+(VERS/10) mod 10 DB '0'+VERS MOD 10 DB CR, LF+80H JMP BEGINE ;BEGIN EXECUTION OF TRANSIENT PAGE ; ; LINKUP INSTALLS FAST IN A CP/M SYSTEM IN TWO STEPS. ; INTERNALLY REFERENCED ROUTINE. ; FIRST, THE EXISTING BIOS JUMP TABLE IS SAVED AND IT IS ; REPLACED WITH A JUMP TABLE INTO FAST, AND ; SECOND, THE BDOS VECTOR IS MODIFIED TO JUMP TO THE BASE OF ; FAST, WHICH, IN TURN, JUMPS TO THE REAL BDOS. THUS, ; TRANSIENTS THINK THE TPA ENDS BELOW FAST INSTEAD OF BELOW ; BDOS. ; LINKUP: ; STEP 1 LDA BOOT+2 ;GET BIOS BASE ADDRESS INTO DE MOV D,A MVI E,0 PUSH D ;SAVE FOR SECOND PART OF TRANSFER LXI H,SAVEJMP MVI C,jtablen ;length of jump table CALL XF1 ;MOVE FROM BIOS INTO SAVEJMP ;REPLACE OLD TABLE WITH LINK TO FAST LXI D,FASTLINK POP H MVI C,jtablen CALL XF1 ;MOVE FROM FAST LINK INTO BIOS ; STEP 2 LHLD BDOS+1 ;GET CURRENT BDOS BASE ADDRESS SHLD NEWBVECT+1 ;COPY IT INTO THE NEW BDOS VECTOR LXI H,NEWBVECT ;MODIFY BDOS VECTOR TO JMP TO SHLD BDOS+1 ;NEW BDOS VECTOR RET ; ; LOADTRAN LOAD THE TRANSIENT NAMED IN THE ARGUMENT TO FAST ; INTO THE TPA WITH CHECKING FOR OVERLAY (LOAD ERROR - ; TRANSIENT TOO BIG OR TPA TOO SMALL). ; RETURNS ONLY IF LOAD WENT OK. BAILS OUT WITH ERROR MESSAGE ; VIA UNLINK OTHERWISE. ; INTERNALLY REFERENCED ROUTINE. ; LOADTRAN: LXI D,TPA ;SET DMA ADDRESS INTO TPA FOR OPEN PUSH D ;SAVE DMA ADDRESS FOR INCREMENTING CPM SETDMA CPM OPEN,FCB ;OPEN THE COM FILE INR A ;WAS OPEN SUCCESSFULL? JZ NOCMERR ;NO - ISSUE NO COM FILE ERROR READSEC: POP D ;GET DMA ADDRESS FROM STACK PUSH D ;AND SAVE BACK FOR LATER MVI A,HIGH (BASE-100H) ;MAX ALLOWABLE DMA ADDRESS CMP D ;IS COM FILE TOO BIG? JC LOADERR ;YES - ISSUE LOAD ERROR CPM SETDMA ;PASS DMA ADDRESS TO CP/M POP D ;INCREMENT DMA ADDRESS BY ONE SECTOR LXI H,SECLEN DAD D PUSH H ;PUT NEW DMA ADDRESS BACK CPM READ,FCB ;READ A SECTOR FROM COM FILE INTO TPA ORA A ;WAS READ OK? JZ READSEC ;YES - KEEP READING ;NOPE - ALL DONE LOADING CPM SETDMA,DBUF ;SET DMA ADDRESS LIKE CCP WOULD POP B ;CLEAN GARBAGE DMA ADDRESS OFF STACK RET ; LOADERR: CALL MSGP ;PRINT LOAD ERROR MESSAGE DB 'OUT OF MEMOR', 'Y'+80H JMP UNLINK ;RETURN TO CP/M ; NOCMERR: CALL MSGP ;PRINT 'NO COM FILE' DB 'NO COM FIL', 'E'+80H JMP UNLINK ;RETURN TO CP/M ; ; END OF INIT MODULE PAGE ; ; \\\\\\\\\\\\\\\\ //////////////// ; >>>>>>>>>>>>>>>> F A S T <<<<<<<<<<<<<<<< ; //////////////// M O D U L E \\\\\\\\\\\\\\\\ ; ; ; THIS MODULE CONTAINS THE ACTUAL DISK I/O BUFFERING CODE. ; ; THIS ADDRESS BECOMES THE NEW TOP OF THE TPA. ; ORG (($-1) OR 255) + 1 ;ORG TO PAGE BOUNDRY DS 6 ;SO BDOS VECTOR ADDRESS = XXX6 NEWBVECT: JMP $-$ ;ADDRESS WILL BE MODIFIED BY LINKUP ; ; DDB ADDRESS BUFFERS. EACH BUFFER IS FOUR W-O-R-D-S LONG, ; ONE WORD FOR THE ADDRESS OF THE BUFFER FOR EACH OF FOUR ; POSSIBLE DRIVES. IF THERE IS NO DDB FOR A GIVEN DRIVE, ; THE DDB ADDRESS IS ZERO. ; RDBUF DW 0, 0, 0, 0 WRBUF DW 0, 0, 0, 0 DIRBUF DW 0, 0, 0, 0 ; ; 8-10-81 upgrade to CP/M compatibility ; when off-line disc is first used, BIOS routine SETDSK is called ; CP/M 2.x BIOS returns a vital parameter in HL, which must be ; passed back to BDOS. It is stored here for that purpose. ; online dw 0, 0, 0, 0 ; stored HL return from SETDSK ; ; USER PATCHABLE MEMORY HIT (ERROR) ROUTINE ; INTERNALLY REFERENCED ROUTINE. ; MEMHIT: PUSH D ! PUSH B ;SAVE REGISTERS CALL MSGP DB 'MEMORY HI', 'T'+80H POP B ! POP D RET ; FASTLINK: ;JMP TABLE TO REPLACE EXISTING BIOS'S JMP UNLINK ;FOR EITHER BOOT, REMOVE FAST AND BOOT JMP UNLINK JMP CCONST ;JUST PASS ALL CHARACTER I/O THRU JMP FCONIN ;EXCEPT CONSOLE IN JMP CCONOUT JMP CLIST JMP CPUNCH JMP CREADER JMP FHOME ;USE FAST HOME INSTEAD OF BIOS JMP FSETDSK ;USE FAST SET DISK JMP FSETTRK ;USE FAST SET TRACK JMP FSETSEC ;USE FAST SET SECTOR JMP FSETDMA ;USE FAST SET DMA JMP FREAD ;USE FAST READ SECTOR JMP FWRITE ;USE FAST WRITE SECTOR jtablen equ $-fastlink ; ; BEGINE: ;ENTRY POINT FROM INIT TO EXEC. TRANS. CALL TPA ;EXECUTE TRANS. ;IF HE RETURNS, FALL THRU TO UNLINK ; ; UNLINK IS THE COMPLIMENTARY ROUTINE TO LINKUP. IT RESTORES ; THE BIOS JUMP TABLE AND THE BDOS VECTOR TO THEIR STATES ; BEFORE FAST WAS INSTALLED (BY LINKUP). ; INTERNALLY AND EXTERNALLY REFERENCED ROUTINE. ; UNLINK: LXI SP,STACK ;SETUP LOCAL STACK ;RETURN BIOS VECTORS UNHARMED LXI D,SAVEJMP LDA BOOT+2 ;GET BIOS BASE INTO DE MOV H,A MVI L,0 MVI C,jtablen ;length of jump table CALL XF1 ;MOVE FROM SAVEJMP TO BIOS BASE LHLD NEWBVECT+1 ;GET REAL BDOS VECTOR ADDRESS SHLD BDOS+1 ;STORE IT INTO REAL BDOS VECTOR CALL CLOSE ;EMPTY ANY DDB'S WHICH MAY HAVE DATA CALL MSGP ;PRINT FAST SIGN OFF MESSAGE DB CR, LF DB 'FAST terminate', 'd'+80H JMP BOOT ;AND REBOOT ; ; FAST CONSOLE IN ; EXTERNALLY REFERENCED ROUTINE ; WRITES ALL SECTORS WAITING TO BE WRITTEN SO THAT USER ; CAN'T GET HIMSELF INTO TROUBLE BY REMOVING THE DISK ; EXTERNALLY REFERENCED ROUTINE. ; FCONIN: CALL CLOSE ;WRITE ALL DDB'S JMP CCONIN ;NOW DO THE CONSOLE INPUT ; ; FAST HOME ROUTINE ; INTERNALLY AND EXTERNALLY REFERENCED ; FHOME: MVI C,0 ;JUST PASS 0 TO FAST SET TRACK ;FALL THRU ; ; FAST SET TRACK ; EXTERNALLY REFERENCED ROUTINE ; REQUESTED TRACK IS JUST STORED AWAY UNTIL ; A READ OR WRITE REQUEST COMES IN. ; FSETTRK: MOV A,C ;GET REQUEST TO REG A STA REQTRK ;STORE IT RET ; ; FAST SET SECTOR ; EXTERNALLY REFERENCED ROUTINE ; THE REQUESTED SECTOR IS JUST ; STORED AWAY UNTIL A READ OR WRITE COMES IN. ; FSETSEC: MOV A,C ;GET REQUESTED SECTOR TO REG A STA REQSEC ;STORE IT RET ; ; FAST SET DMA ADDRESS ; EXTERNALLY REFERENCED ROUTINE. ; FSETDMA: MOV H,B ;REQUESTED DMA ADR INTO HL MOV L,C SHLD REQDMA ;SAVE IT RET ; ; FAST SET DISK DRIVE ; EXTERNALLY REFERENCED ROUTINE ; FSETDSK: MOV E,C ;SAVE DRIVE FOR ON LINE CODE MOV A,C ;GET REQUESTED DRIVE STA REQDSK ;SAVE FOR PASS THRU ADD A MOV C,A ;FORM word INDEX IN REG BC MVI B,0 LXI H,DIRBUF ;GET NEW DIR DDB POINTER CALL INDXIND SHLD DIRADR ;AND SAVE IT LXI H,RDBUF ;GET NEW READ TRACK DDB POINTER CALL INDXIND SHLD RDADR ;AND SAVE IT LXI H,WRBUF ;GET NEW WRITE TRACK DDB POINTER CALL INDXIND SHLD WRADR LXI H,ONLINE ;BASE OF 'ON LINE' VECTOR call indxind MOV A,h ;IS THIS DRIVE ON LINE? ORA l RNZ ;->yes, return to BDOS with HL set ; get this drive on-line push b ;preserve word index into table mov c,e CALL CSETDSK ;first, really select it pop b mov a,h ;check the return in HL ora l rz ;->zero is error, return to BDOS with HL zero push h ;ok, save (HL) lxi h,online;..in online table dad b ;..word-indexed by drive number pop b mov m,c inx h mov m,b push b ;we still need this for later lda reqdsk ;get disc again, home it mov c,a CALL CHOME LHLD DIRADR ;AND READ THE DIRECTORY IF IT IS BUFFERED call RDDDB pop h ret ;return to BDOS with HL set ; ; FAST READ SECTOR ; EXTERNALLY REFERENCED ROUTINE. ; FREAD: LHLD RDADR ;GET ADDRESS OF READ TRACK DDB CALL GETSEC ;TRY TO FIND SECTOR IN READ DDB RC ;FOUND IT LHLD DIRADR ;TRY TO FIND SECTOR IN DIRECTORY DDB CALL GETSEC RC ;FOUND IT LHLD WRADR ;TRY TO FIND SECTOR IN WRITE DDB CALL GETWSEC RC ;FOUND IT LHLD RDADR ;SEE IF THERE IS A READ TRACK BUFFER MOV A,H ORA L JZ RDPASS ;NO - THEN JUST PASS THE READ THRU LDA REQTRK ;YES - SEE IF READING FROM NON-DIRECTORY CPI DIRTRK ;SECTORS OF DIRECTORY TRACK JZ RDPASS ;YES - JUST LET THAT PASS THRU PUSH PSW ;NO - WRITE ANY DATA IN READ BUFFER PUSH H CALL WRDDB POP H POP PSW MOV M,A ;FILL NEW TRACK INTO READ DDB PUSH H ;SAVE READ DDB ADDRESS CALL RDDDB ;AND FILL NEW DDB WITH DATA POP H ;GET READ DDB ADDRESS BACK JMP GETSEC ;TRANSFER SECTOR FROM DDB TO CALLER ;AND RETURN FROM GETSEC ; ; FAST SECTOR WRITE ; EXTERNALLY REFERENCED ROUTINE. ; FWRITE: LHLD WRADR ;TRY TO PUT SECTOR INTO WRITE BUFFER CALL PUTSEC RC ;IT WENT - ALL DONE LHLD DIRADR ;TRY TO PUT IT INTO DIRECTORY BUFFER CALL PUTSEC RC ;IT WENT - ALL DONE LHLD RDADR ;TRY TO PUT INTO READ BUFFER CALL PUTSEC RC ;IT WENT - ALL DONE LHLD WRADR ;IS THERE A WRITE TRACK BUFFER? MOV A,H ORA L JZ WRPASS ;NO - JUST PASS THIS WRITE THRU LDA REQTRK ;YES - SEE IF THIS IS A NON-DIRECTORY CPI DIRTRK ;SECTOR ON THE DIRECTORY TRACK? JZ WRPASS ;YES - JUST PASS THAT THRU PUSH PSW ;NO - DUMP EXISTING WRITE BUFFER TO DISK PUSH H CALL WRDDB POP H POP PSW MOV M,A ;AND BUFFER UP REQUESTED TRACK CALL PUTSEC ;MOVE SECTOR INTO WRITE BUFFER LDA WRTERRF ;RETURN WRITE ERROR FLAG RET ; ; CLOSE ALL OPEN DDB'S. WRITE ANY DATA LEFT IN THEM OUT TO ; DISK ; INTERNALLY REFERENCED ROUTINE. ; CLOSE: MVI C,4*3 ;DDB COUNT LXI H,RDBUF ;START OF DDB ADDRESS TABLES CLOS: MOV E,M ;GET DDB ADDRESS TO REG DE INX H MOV D,M INX H PUSH H ;SAVE TABLE ADDRESS PUSH B XCHG ;DDB ADDRESS TO REG HL CALL WRDDB ;CLOSE ONE DDB LDA WRTERRF ;ANY WRITE ERRORS IN CLOSING? ORA A JZ CLOSOK ;NO - KEEP CLOSING CALL MSGP DB 'DISK WRITE ERROR', CR, LF+80H CLOSOK: POP B ;GET COUNT POP H ;GET TABLE ADDRESS DCR C ;DONE ALL DDBS YET? JNZ CLOS ;NO - KEEP CLOSING RET ;YES - ALL DONE ; ; INDEXED INDIRECT ADDRESSING. RETURNS THE WORD AT THE ; ADDRESS BASE + INDEX ; INTERNALLY REFERENCED ROUTINE. ; INDXIND: DAD B ;ADD IN INDEX MOV A,M ;GET LOW ORDER OF RESULT INX H MOV H,M ;GET HIGH ORDER OF RESULT MOV L,A RET ; ; GET A SECTOR FROM A WRITE DDB INTO REQDMA. MATCHES ONLY ; IF UPDATE FLAG IS SET. RETURNS FLAG IF FOUND. ; INTERNALLY REFERENCED ROUTINE. ; GETWSEC: CALL SRCHDDB ;FIND A SECTOR AND TRACK MATCH? RNC ;NO - RETURN WITHOUT FLAG INX H ;YES - SEE IF SECTOR HAS BEEN MOV A,M ;WRITTEN (UPDATE FLAG=1)? ORA A JNZ GS1 ;YES - TRANSFER FROM WRITE DDB CALL RDPASS ;NO - BYPASS BUFFERING STC ;SET FOUND IT FLAG RET ; ; GET A SECTOR FROM A DDB INTO REQDMA. FLAG SET IF FOUND. ; INTERNALLY REFERENCED ROUTINE. ; GETSEC: CALL SRCHDDB ;DO WE HAVE THE REQUESTED SECTOR? RNC ;NO - RETURN WITHOUT FLAG INX H ;YES - POINT TO SECTOR DATA GS1: ;ENTRY FROM GETWSEC (ABOVE) INX H XCHG ;DATA ADDRESS TO REG DE LHLD REQDMA ;DESTINATION TO REG HL CALL XFER ;PERFORM THE TRANSFER LDAX D ;GET GOOD/BAD FLAG STC ;SET 'FOUND IT' FLAG RET ; ; SEARCH A DDB FOR THE REQUESTED TRACK AND SECTOR ; INTERNALLY REFERENCED ROUTINE. ; SRCHDDB: MOV A,H ;SEE IF DDB IS PRESENT AT ALL ORA L RZ ;NO - WE DON'T HAVE IT LDA REQTRK ;YES - SEE IF REQTRK MATCHES DDB TRACK XRA M RNZ ;NO MATCH - WE DON'T HAVE IT INX H ;TRACKS MATCH - CHECK SECTORS INX H LDA REQSEC MOV C,A LXI D,SECLEN+3 ;BYTES BETWEEN SECTOR NUMBERS SRCH1: MOV A,M ;GET A SECTOR NUMBER FROM DDB ORA A ;END OF DDB? RZ ;YES - RETURN WITHOUT FLAG CMP C ;NO - SEE IF REQSEC MATCHES DDB SECTOR STC ;PREPARE TO RETURN FLAG IF SO RZ ;THEY MATCH - RETURN FLAG DAD D ;NO MATCH - ON TO NEXT SECTOR JMP SRCH1 ; RDPASS: CALL PASSTHRU JMP CREAD ; ; MOVE A SECTOR FROM MEMORY INTO A DDB ; INTERNALLY REFERENCED ROUTINE. ; PUTSEC: CALL SRCHDDB ;DOES IT GO IN THIS DDB? RNC ;NO - RETURN WITHOUT FLAG INX H ;POINT TO DATA FIELD OF DDB MVI M,UPDTTOK ;SET UPDATE FLAG INX H XCHG ;SAVE DDB ADDRESS IN REG DE LHLD REQDMA ;GET SOURCE ADDRESS INTO REG HL XCHG ;NOW REG HL=DDB ADDRESS (DEST) AND . . CALL XFER ;REG DE=MEMORY (SOURCE) XRA A ;RETURN WITHOUT WRITE ERROR MOV M,A ;SET GOOD/BAD FLAG TO GOOD STC ;SET SECTOR PUT FLAG RET WRPASS: CALL PASSTHRU JMP CWRITE ; ; PASS ALL DISK I/O PARAMETERS THRU TO BIOS ; INTERNALLY REFERENCED ROUTINE ; PASSTHRU: LDA REQDSK ;PASS REQUESTED DISK THRU MOV C,A CALL CSETDSK LDA REQTRK ;PASS REQUESTED TRACK THRU MOV C,A CALL CSETTRK LDA REQSEC ;PASS REQUESTED SECTOR MOV C,A CALL CSETSEC LHLD REQDMA ;PASS REQUESTED DMA ADDRESS MOV B,H MOV C,L JMP CSETDMA ;RETURN FROM CSETDMA ; ; READ A DDB FROM DISK. ALL SECTORS ARE FILED IN, AND THEIR ; UPDATE FLAGS ARE RESET. ; INTERNALLY REFERENCED ROUTINE. ; RDDDB: MOV A,H ;DO NOTHING FI NO DDB ORA L RZ PUSH H ;SAVE DDB ADDRESS CALL SENDDT ;SEND DRIVE AND TRACK INFO TO BIOS POP H ;GET DDB ADDRESS INX H ;POINT TO FIRST SECTOR BYTE INX H RDDSEC: MOV A,M ;GET SECTOR NUMBER ORA A ;END OF DDB? RZ ;YES - ALL DONE MOV C,A ;PASS SECTOR TO BIOS PUSH H ;SAVE WHILE CALLING CALL CSETSEC POP H ;GET DDB ADDRESS BACK INX H ;POINT TO UPDATE FLAG MVI M,0 ;RESET UPDATE FLAG INX H ;POINT TO DATA FIELD PUSH H ;SAVE DATA POINTER MOV B,H ;DATA ADDRESS TO REG BC MOV C,L CALL CSETDMA ;PASS DATA ADDRESS TO BIOS CALL CREAD ;PERFORM THE READ POP H ;GET DATA ADDRESS BACK LXI B,SECLEN ;BYTES TO GOOD/BAD FLAG DAD B MOV M,A ;STORE GOOD/BAD FLAG FROM BIOS IN DDB INX H JMP RDDSEC ;ON TO NEXT SECTOR ; ; WRITE A DDB BACK TO DISK. ONLY SECTORS WITH THE UPDATE FLAG ; SET GET WRITTEN. ; THE DRIVE AND TRACK INFORMATION FROM THE DDB IS SAVED BY ; THIS ROUTINE AND PASSED TO THE BIOS BY RCLDT ONLY IF ; A SECTOR IS TO BE WRITTEN. THIS IS DONE TO BYPASS BIOS ; DELAYS WHEN SWITCHING DRIVES AND TO PREVENT NEEDLESS ; SEEKING TO TRACKS WHICH MIGHT NOT RECIEVE ANY DATA. ; INTERNALLY REFERENCED ROUTINE. ; WRDDB: XRA A ;CLEAR WRITE ERROR FLAG STA WRTERRF MOV A,H ;SEE IF A DDB IS PRESENT ORA L RZ ;NO - ALL DONE WRITING MOV A,M ;GET TRACK NUMBER INR A ;TRACK = 0FFH (MEANING EMPTY)? RZ ;YES - NO WRITING TO DO SHLD TRKPTR ;NO - SAVE DISK & TRACK POINTER FOR XRA A ;RECALL LATER, AND RESET FLAG STA SENTFLG ;SHOWING THAT THEY HAVEN'T BEEN SENT INX H ;POINT TO FIRST SECTOR NUMBER INX H TSTUPDT: MOV A,M ;GET SECTOR TO REG A ORA A ;END OF DDB? RZ ;YES - ALL DONE MOV C,A ;SAVE SECTOR IN REG C INX H ;POINT TO UPDATE FLAG MOV A,M ;GET UPDATE FLAG ORA A ;DOES THIS SECTOR NEED UPDATING ON DISK? CNZ WRSEC ;YES - WRITE IT BACK LXI D,SECLEN+2 ;BYTES TO NEXT SECTOR NUMBER DAD D JMP TSTUPDT ;CHECK THE NEXT UPDATE FLAG ; ; WRITE A SECTOR FROM A DDB BACK OUT TO DISK. ; INTERNALLY REFERENCED ROUTINE. ; WRSEC: MVI M,0 ;RESET UPDATE FLAG PUSH H ;SAVE UPDATE FLAG POINTER CALL CSETSEC ;PASS SECTOR NUBER TO BIOS CALL RCLDT ;PASS DRIVE AND TRACK TO BIOS POP H ;GET UPDATE FLAG POINTER PUSH H ;AND SAVE AGAIN INX H ;POINT TO DATA MOV B,H ;DATA ADDRESS TO REG BC MOV C,L CALL CSETDMA ;PASS DMA ADDRESS TO BIOS CALL CWRITE ;WRITE THE DATA OUT LXI H,WRTERRF ;OR THIS WRITE ERROR FLAG IN WITH ORA M ;THE REST FROM THIS WRDDB MOV M,A POP H ;GET CALLERS REG HL BACK RET ; ; RECALL DISK AND TRACK INFO FROM A DDB, PASS IT TO THE BIOS, ; AND SET FLAG SHOWING THAT IS HAS BEEN SENT. ; INTERNALLY REFERENCED ROUTINE. ; RCLDT: LXI H,SENTFLG ;HAS THIS INFO ALREADY BEEN SENT? MOV A,M ORA A RNZ ;YES - SKIP SENDING AGAIN MVI M,SENTTOK ;NO - SET FLAG SHOWING IT HAS BEEN SENT LHLD TRKPTR ;GET POINTER TO DRIVE & TRACK INFO ;AND FALL THRU TO SEND IT TO BIOS ; ; SEND DRIVE AND TRACK INFO FROM A DDB TO THE BIOS. ; INTERNALLY REFERENCED ROUTINE. ; SENDDT: PUSH H ;SAVE TRACK POINTER INX H ;POINT TO DRIVE MOV C,M ;GET DRIVE TO REG C CALL CSETDSK ;PASS DISK POP H ;GET TRACK POINTER MOV C,M ;GET TRACK TO REG C JMP CSETTRK ;PASS TRACK AND RETURN FROM THERE ; ; MOVE A SECTOR FROM ONE PLACE IN MEMORY TO ANOTHER. GIVE ; ERROR MESSAGE IF DATA CAN'T BE WRITTEN INTO DESTINATION. ; INTERNALLY REFERENCED ROUTINE. ; XFER: MVI C,SECLEN ;COUNT NUMBER OF BYTES TO XFER IN C XF1: LDAX D ;GET BYTE FROM SOURCE MOV M,A ;STORE INTO DESTINATION XRA M ;DID IT GO? CNZ MEMHIT ;NO - GIVE WARNING MESSAGE INX H ;INCREMENT DEST POINTER INX D ;INCREMENT SOURCE POINTER DCR C ;DONE WITH MOVE YET? JNZ XF1 ;NO - KEEP MOVING RET ;YES - ALL DONE ; ; LOCAL MESSAGE PRINTER. WE CAN'T USE BDOS BECAUSE BDOS IS NOT ; RE-ENTRANT (WE MIGHT HAVE GOTTEN HERE VIA BDOS). FOLLOW ; THE CALL TO MSGP WITH THE TEXT OF THE MESSAGE. THE LAST ; CHARACTER OF THE MESSAGE MUST HAVE BIT SEVEN ON (I.E. +80H) ; INTERNALLY REFERENCED ROUTINE. ; MSGP: XTHL ;GET MESSAGE ADDRESS TO REG HL MSG1: MOV C,M ;GET MESSAGE CHARACTER PUSH H ;SAVE MESSAGE ADDRESS DURING PRINTING CALL CCONOUT ;SEND IT POP H ;RESTORE MESSAGE ADDRESS MOV A,M ;GET CHR JUST SENT INX H ;POINT TO NEXT CHARACTER ORA A ;WAS THAT THE LAST CHR TO PRINT? JP MSG1 ;NO - KEEP PRINTING XTHL ;YES - PUT MODIFIED RETURN ADDREESS RET ;BACK ON STACK AND RETURN PAST MESSAGE PAGE ; ; \\\\\\\\\\\\\\\\ //////////////// ; >>>>>>>>>>>>>>>> R A M <<<<<<<<<<<<<<<< ; //////////////// A R E A S \\\\\\\\\\\\\\\\ ; ; ; SAVE SPACE FOR A COPY OF THE BIOS JUMP TABLE BEFORE THE ; INSTALLATION OF FAST ; SAVEJMP: CBOOT: JMP $-$ CWBOOT: JMP $-$ CCONST: JMP $-$ CCONIN: JMP $-$ CCONOUT: JMP $-$ CLIST: JMP $-$ CPUNCH: JMP $-$ CREADER: JMP $-$ CHOME: JMP $-$ CSETDSK: JMP $-$ CSETTRK: JMP $-$ CSETSEC: JMP $-$ CSETDMA: JMP $-$ CREAD: JMP $-$ CWRITE: JMP $-$ ; DIRADR DW 0 ;ADDRESS OF CURRENT DIRECTORY DDB RDADR DW 0 ;ADDRESS OF CURRENT READ TRACK DDB WRADR DW 0 ;ADDRESS OF CURRENT WRITE TRACK DDB ; TRKPTR DW 0 ;POINTER TO TRACK & DRIVE INFO IN DDB SENTFLG DB 0 ;ZERO IF TRACK & DRIVE HAVEN'T BEEN SENT WRTERRF DB 0 ;WRITE DDB ERROR FLAG, 0 IF NO ERROR ; REQDSK DB 0FFH REQTRK DB 0FFH REQSEC DB 0FFH REQDMA DW 0FFFFH ; DS 10H ;AT LEAST AS MUCH STACK AS CCP ; ORG (($-1) OR 255) + 1 ;ORG TO NEXT PAGE BOUNDRY STACK: ; CODELEN EQU $-BASE ; ORG CODELEN ;INFORM OPERATOR OF CODE LENGTH END FASTNTRY