* * * * * ************************* * * * * *** DISK DRIVER *** * * * * ************************* * * VERSION: 77.08.29 * * * * EQUATES //// * * * * CONTROLLER PORTS * STAPT EQU 0F0H STATUS INPUT PORT TRAPT EQU 0F1H TRANSFER COMMAND PORT BYTLO EQU 0F3H LOW BYTE COUNT PORT BYTHI EQU 0F4H HIGH BYTE COUNT PORT ADRLO EQU 0F5H LOW TRANSFER ADDRESS PORT ADRHI EQU 0F6H HIGH TRANSFER ADDRESS PORT COMPT EQU 0F7H COMMAND OUTPUT PORT * * TRANSFER COMMANDS * RDATA EQU 3 READ DATA COMMAND WDATA EQU 1 WRITE DATA COMMAND READH EQU 7 READ HEADER COMMAND WRITH EQU 5 WRITE HEADER COMMAND * * BIT MASKS * TRCOM EQU 1 TRANSFER COMPLETE SREDY EQU 2 CONTROLLER READY ABERR EQU 4 ABORT FLAG CCERR EQU 8 CRC ERROR FLAG CKCOM EQU 16 CRC CHECK COMPLETE DREDY EQU 32 SELECTED DRIVE READY SKCOM EQU 64 SEEK COMPLETE FLAG INDEX EQU 128 INDEX MARK * * ERROR CODES * SIZER EQU ERBSC SIZE CONFLICT FIDER EQU ERFIC FILE ID CONFLICT SECER EQU ERSCC SECTOR CONFLICT FORER EQU ERCFS FORMAT ERROR (CAN'T FIND SECTOR) TRIER EQU ERCRC ABORTS AND CRCC'S TRKER EQU ERCFT CAN'T FIND TRACK RWERR EQU ERRBC READ AFTER WRITE ERROR LOCER EQU ERLOK SYSTEM LOCKED * * MISC * HELEN EQU 13 LENGTH OF HEADER //// DIRDT EQU 25 Directory track. //// * * * DISK DRIVER PARAMETERS * DTRIES DB 0 DSECN DB 0 DNERR DB 0 DTERR DB 0 DRLEN DW 0 DOPER DB 0 * * DISK DRIVER LOCALS * CUNIT DB 0 Current unit. RUNIT DB 0 CTRCK DB 0 Current track. UNTAB DW 0 Table of current tracks for various units. DW 0 * ******************************** * * * * * ENTRY POINTS FOR READ AND WRITE DATA * * * * ON CALL: TDAD HAS TRANSFER DESCRIPTOR * RETURNS: CALL+3 FOR NORMAL * RET FOR ERRORS * * * WRITE DISK BLOCK * WDSK MVI A,WDATA WRITE OPERATION JMP OPSET SET IT FOR FUTURE * * * READ DISK BLOCK * RDSK MVI A,RDATA READ OPERATION * OPSET CALL OPSE1 SET OPERATION AND CLEAR INT STUFF DI . NO INTERRUPTS * * * LOOP TO THESE ENTRIES UNTIL SUCCESFUL READ OR GO * TO ERROR RETURN. * DATRN CALL DATNS CLEAR ERROR CONTROL FLAGS * DOVER CALL HDVER CLEAR HEADER ATTEMPT COUNT * DATAOP DI . NO INTERRUPTS THROUGH HERE CALL HDATOP READ NEXT HEADER JC TKERR ON WRONG TRACK JNZ DATER PROCESS THE ERROR * * REG "C" HAS DESIRED TRACK, "B" HAS DESIRED SECTOR * LDA IHSEC GET THE READ IN SECTOR CMP B JNZ NOSEC FOUND WRONG ONE, GO TRY SOME MORE * * * TEST HEADER PARAMETERS * LXI H,TBCNT POINT TO TRANSFER DESCRIPTOR LDA IHSIZ GET SPECIFIED SIZE CMP M IS IT THE SAME? RNZ . Blocksize conflict. INX H LDA IHSIZ+1 OTHER PORTION GETS TESTED NOW CMP M RNZ . Blocksize conflict. * * BYTE COUNT IS OK NOW CHECK FILE ID * INX H LDA IHFID CMP M RNZ . File ID error. INX H LDA IHFID+1 CMP M RNZ . File ID error. * * WE EVEN CHECK THE SECTOR COUNT * LDA OHPRO GET PROTECT WORD ANI 15 STRIP OFF HIGH BIT MOV B,A LDA IHPRO GET READ IN VALUE ANI 15 CMP B RNZ . Error if not the same. * * ALL SYSTEMS GO!!! 5,4,3....... * LHLD DRLEN = LENGTH OF TRANSFER XCHG . TO DE FOR OUTPUT LHLD TBUF = TRANSFER ADDRESS LDA DOPER THE OPERATION R/W CALL CTOUT GIVE COMMANDS TO CONTROLER * * * NOW WAIT FOR TRANSFER * LDA DOPER GET THE OPERATION CPI WDATA TEST IF WRITE JNZ RCCHK CHECK FOR READ COMPLETE CALL WFCHK CHECK FOR WRITE COMPLETE JNZ DATER WE HAVE AN ERROR CALL DELY0 WAIT FOR HEAD RECOVERY * * HERE WE RETURN TO THE SYSTEM * RP2 POP H This is the normal return. INX H INX H INX H PCHL . Return CALL+3. * ****************** * * DELAY ROUTINE * DELY0 MVI C,1 ONLY 10 MS * DELAY LXI D,1290H/7 DELY1 DCX D MOV A,D ORA E JNZ DELY1 DCR C DOUBLE LOOP JNZ DELAY RET * ****************** * * * * TEST READ OPERATION * RCCHK CALL RFCHK JNZ DATER * LOOP HERE FOR CHECK COMPLETE RCCHA IN STAPT ANI CKCOM RNZ IN STAPT ANI CCERR+ABERR JZ RCCHA ERROR IF NOT ZERO * ********************** * * ERROR ROUTINES * * DATER CALL ERRPR PROCESS THE ERROR RET Bad error. DW 0 JMP DOVER SUCCESSFUL RETURN * * TKERR CALL TERRP PROCESS THE TRACK ERROR RET . Hopeless error. DW 0 Padding. JMP DOVER AND RETURN * * * DATA ERROR FOUND...PROCESS COUNT * ERRPR MVI A,0FFH CANCEL THE COMMAND OUT TRAPT * ERRP1 CALL WAITS WAIT FOR SREDY CONT LDA TTRK MOV C,A KEEP IN C LDA DTRIES GET NUMBER OF ATTEMPTS INR A STA DTRIES CPI 20 CNC ERRN DONE 20.. GO SEEK LDA DNERR CPI 2 RZ . Error return. JMP RP2 Regular return. * * * SEEK BACK AND FORTH * ERRN XRA A STA DTRIES RESTORE TRIES LDA DNERR GET SWITCH INR A STA DNERR JZ FIUP FIRST ONE DIRECTION DCR A SEE IF IT IS > 1 RNZ . Give up--this is the third time through. * * MOVE DOWN 2 TRACKS * FIDWN MOV A,C SUI 2 BACK DOWN TWO TRACKS JP ERRO XRA A DON'T GO LOWER THAN ZERO ERRO MOV C,A JMP SEEKT SEEK TO THIS TRACK AND RETRY OPERATION * * * MOVE UP 2 TRACKS * FIUP MOV A,C ADI 2 STEP UP TWO TRACKS CPI 77 JC ERRO MVI A,76 NO MORE OUT THAN 76 JMP ERRO * * * WASN'T THE RIGHT SECTOR * NOSEC CALL SCTER PROCESS THE COUNT RET DW 0 JMP DATAOP RETURNS HERE IF OK * * * ERROR FLAG SET UP USED BY RDSKH & WDSKH * DATNS XRA A START WITH NO TRIES STA DTRIES CMA STA DNERR SET IN/OUT SEEK SWITCH STA DTERR MINUS TRACK ERRORS RET * * * SET UP FOR HEADER SEARCH * HDVER XRA A STA DSECN SET NO SECTORS TRIED JMP SECHK GO TO PROPER TRACK AND RETURN * ****************** * * * * READ NEXT HEADER * * * ON CALL: REG "A" HAS READ OR WRITE COMMAND * ON RETURN: THE HEADER IS IN IHEAD * CARRY IS SET IF TRACK ERROR * FLAG NZ = READ ERROR * B HAS DESIRED SECTOR, C HAS DESIRED TRACK * HDATOP CALL WAITS BE SURE CONTROLLER IS READY LXI H,IHEAD -> HEADER BUFFER LXI D,HELEN -> LENGTH OF HEADER MVI A,READH -> READ HEADER COMMAND CALL CTOUT GIVE THE COMMANDS CALL RFCHK RNZ . REPORT THE ERROR LXI H,TDAD THE TRANSFER DESCRIPTOR MOV B,M SECTOR INX H MOV C,M TRACK * LOOP FOR ERROR OR CHECK COMPLETE HDAT1 IN STAPT GET STATUS ANI ABERR+CCERR+SREDY SREADY IS ERROR WITH HEADERS RNZ IN STAPT ANI CKCOM WE WAIT FOR THIS JZ HDAT1 IF MORE WAIT * LDA IHTRK GET READ IN TRACK CMP C STC . IN CASE OF RETURN RNZ . NOT ON PROPER TRACK XRA A CLEAR THE FLAGS RET * **************** * **************** * * * READ FLAG CHECK ROUTINES (SECOND LEVEL INTERRUPT) * * RFCHK IN STAPT THE STATUS ANI CCERR+ABERR+SREDY+TRCOM JZ RFCHK ANI CCERR+ABERR TEST FOR ERRORS RET . NZ TELLS THE TALE * ******************** * * * WRITE FLAG CHECK ROUTINES (SECOND LEVEL AGAIN) * * WFCHK IN STAPT GET STATUS ANI ABERR+SREDY+TRCOM JZ WFCHK LOOP UNTIL ONE IS SET * WFCH2 IN STAPT ANI ABERR RNZ IN STAPT ANI SREDY JZ WFCH2 LOOP FOR SREADY OR ABORT IN STAPT ANI ABERR RET . FLAGS ARE SET * ***************** * * * GIVE SEQUENCE OF COMMANDS TO CONTROLLER * CTOUT PUSH PSW "A" HAS THE COMMAND MOV A,L OUTPUT ADDRESS OUT ADRLO LOW BYTE RESETS CONTROLLER TOO MOV A,H OUT ADRHI * NOW THE COUNT MOV A,E OUT BYTLO MOV A,D OUT BYTHI POP PSW OUT TRAPT THE TRANSFER COMMAND RET . DONE QUICKLY * * * *** RDSKH *** * * Read the header at (TSEC,TTRK) to IHEAD. Return CALL+3 * if successful, otherwise RET. * * RDSKH CALL DATNS Clear error control flags. TOVER CALL HDVER Clear header attempt count. * Desired track is in C, desired sector is in B. READIT CALL HDATOP Read next header. JC TTKER Wrong track. JNZ HERRA An error. LDA IHSEC Did we read the right sector? CMP B JNZ TNSEC Nope. Keep looking. JMP RP2 Okay. Do CALL+3 return. * * RDSKH error routines. * HERRA CALL ERRPR Process the error. RET . Error return -- give up. DW 0 JMP TOVER Try again. * * Track error: * TTKER CALL TERRP Process track error. RET . Error return. DW 0 JMP TOVER Try again. * * Haven't found sector yet. * TNSEC CALL WAITS LDA DSECN INR A STA DSECN CPI 25 JC READIT Try again (up to 25 times). RET . Else error return. * * ******************* * * * * *** WDSKH *** * * * OHEAD IS SET UP BY CALLER * * WRITE HEADER FOLLOWED BY DATA BLOCK * WDSKH LHLD OHFID OUTGOING FILE ID SHLD TFID SET THE TRANSFER DESCRIPTOR * MVI A,WDATA CALL OPSE1 SET OPERATION AND CLEAR STUFF * * SET UP THE HEADER * LXI H,OHEAD LDA TSEC GET SECTOR MOV M,A MOV B,A KEEP IN "B" ALSO LDA TTRK INX H MOV M,A PUT IN THE TRACK * * CHECK FOR WRITE OVER INDEX * LDA OHPRO NUMBER OF SECTORS REQUIRED BY TRANSFER ANI 15 STRIP OFF HIGH BIT ADD B THE DESIRED SECTOR CPI 17 15 WITH 1 IS 16 RNC . Error...would try to write over index. * * * NOW FIND THE SECTOR BEFORE THE DESIRED ONE * CALL DATNS HERE WE GO, SET FIELDS HOVER CALL HDVER HEADD CALL HDATOP READ THE NEXT HEADER DI . NO INTERRUPTS FOR AWHILE JC HTERR WRONG TRACK JNZ CRCER ERROR FLAG * * NOW CHECK HEADER VALUES * LDA IHPRO NUMBER OF SECTORS ANI 15 MOV E,A SAVE IN E * * CHECK FOR DIREC TRACK (SECTOR HANDLING IS SPECIAL) * MOV A,C DESIRED TRACK IS IN C CPI DIRDT JZ ONFIN PROCESS SPECIAL IF DIRECTORY TRACK LDA IHSEC GET READ IN SECTOR ADD E CALCULATE NEXT SECTOR ANI 15 MASK OFF 16 CARRY * SECOM CMP B IS IT THE ONE WE WANT? JNZ HNSEC IF NOT TRY AGAIN * *************** * * * WRITE THE HEADER * DI . NO INTERRUPTS FOR A BIT LXI H,OHEAD HERE'S WHERE WE GET IT FROM LXI D,HELEN HOW MANY MVI A,WRITH WRITE HEADER COMMAND CALL CTOUT THE CONTROLLER GETS THEM * CALL WFCHK WAIT FOR TRANSFER JNZ CRCER ERROR CALL DELY0 HEAD RECOVERY TIME JMP DATRN ALL DONE GO WRITE DATA * ****************** * * * PROCESS CALCULATION FOR TRACK ONE * * SECTORS ARE WRITTEN IN A 0,8,1,9,2,10,3....SEQUENCE * ONFIN LDA TSEC GET DESIRED SECTOR CPI 8 TEST IF ADD OR SUBTRACT JNC OVER8 EXIT WITH TSEC-8 (eg. 9 LOOKS FOR 1) ORA A TEST IF SECTOR ZERO JNZ UNDR8 EXIT WITH TSEC+7 (eg. 1 LOOKS FOR 8) MVI A,8 WE'LL EXIT WITH 15 TO FIND 0 * UNDR8 ADI 7+8 WE'LL ADD SEVEN HERE OVER8 SUI 8 DONE!! ONFI1 MOV B,A SAVE NEW DESIRED VALUE LDA IHSEC GET READ IN SECTOR JMP SECOM AND DO COMPARE * **************** * * * WDSKH ERROR HANDLING * * DATA ERRORS * CRCER CALL ERRPR PROCESS THE ERROR RET DW 0 JMP HOVER AND DO IT OVER * * TRACK ERRORS * HTERR CALL TERRP PROCESS THE TRACK ERROR RET . Error. DW 0 Padding. JMP HOVER * * PROCESS SECTOR NOT FOUND COUNT FOR WDSKH * HNSEC CALL SCTER PROCESS THE COUNT RET DW 0 JMP HEADD RETURNS HERE IF OK * ***************** * * * PROCESS TRACK ERROR * TERRP CALL WAITS LDA DTERR ORA A Set flags. JM ONCMO If first time try the difference. INR A STA DTERR INCREMENT THE COUNT * * NOW SEEK BACK AND FORTH FOR THE NEXT FEW TIMES * CPI 11 JUST TEN TIMES RNC . Give up if more. RRC . EVEN OR ODD SWITCH JC SEDN2 Seek out 2. CALL FIUP This time in 2. JMP RP2 * SEDN2 CALL FIDWN SEDN3 JMP RP2 * * * SET CURRENT TRACK TO SEEK TO IF OK * ONCMO XRA A STA DTERR Set as second time. CALL IFIND LDA IHTRK GET READ IN TRACK CPI 77 SEE IF REASONABLE JNC SEDN4 If not then restore. STA CTRCK MAKE IT THE CURRENT ONE JMP RP2 and try again. * SEDN4 CALL SEEK0 JMP RP2 * * * ROUTINE TO SEEK TRACK ZERO AND RESET THE * TRACK COUNTER. * SEEK0 LDA TUNIT GET CURRENT UNIT CALL USET GET PROPER COMMAND STA RUNIT OUT COMPT SELECT THE DRIVE ANI 0EFH SET RESTORE LOW OUT COMPT NEXT SEEK WILL CLEAR THE RESTORE XRA A CALL SETU1 KEEP THE TRACK COUNTER PROPER XRA A MOV M,A IN THE TABLE TOO JMP SKDON AND WAIT FOR SEEK COMPLETE * ****************** * * * THIS ROUTINE SEEKS TO THE TRACK GIVEN IN TTRK * * SECHK CALL DRLOP GET DRIVE STATUS LDA TTRK GET DESIRED TRACK MOV C,A WE KEEP IT HERE * * COME HERE WITH "C"= TRACK TO GO TO * SEEKT LDA CTRCK GET CURRENT TRACK SUB C THE DIFFERENCE RZ . ALL DONE IF EQUAL DI . WE HAVE TO DO THIS FAST JP SECH1 THE SIGN FLAG TELLS DIRECTION TO STEP * * GO UP IN TRACK NUMBERS * CMA . DO THE COMPLEMENT FOR NEGATIVE RESULTS INR A MOV B,A "B" HAS NUMBER TO MOVE LDA RUNIT GET PROPER COMMAND ANI 0FDH BIT "1" LOW JMP SECH2 * * * GO DOWN IN TRACK NUMBERS * SECH1 MOV B,A LDA RUNIT THE PROPER ONE * SECH2 OUT COMPT SET THE DIRECTION ANI 0FEH TURN ON THE STEP BIT * * GIVE "B" COUNT STEPS TO THE CONTROLLER * SECH3 OUT COMPT GIVE THE STEPS DCR B JNZ SECH3 GIVE B STEPS MOV A,C GET TRACK CALL SETU1 MAKE IT THE CURRENT ONE MOV M,C IN THE TABLE TOO * * WAIT HERE FOR SEEK COMPLETE * SKDON IN STAPT WAIT FOR SEEK COMPLETE ANI SKCOM JNZ SKDON WHEN FINISHED WAIT FOR AN INDEX MARK * * * THIS ROUTINE FINDS THE NEXT INDEX MARK * IFIND IN STAPT RLC . TEST THE HIGH BIT JC IFIND RET . GOT IT * * ************* * * * SAVE OPERATION AND CLEAR THE TASK AND INTERRUPT * STUFF * OPSE1 STA DOPER SET OPERATION FOR LATER CALL BLKLN SET UP TRANSFER PARAMETERS * * * * THIS ROUTINE IS CALLED PRIOR TO DRIVER OPERATIONS * TO SET UP THE DRIVER PARAMETERS RELATING TO UNIT AND * TRACK. * * SET CURRENT UNIT INTO RUNIT * SUNIT LDA TUNIT GET DESIRED UNIT CALL USET SET DESIRED DRIVE AND UNIT IN "A" STA RUNIT SAVE IT FOR THE DRIVER ROUTINES OUT COMPT SELECT THE DRIVE OUT ADRLO RESET HEAD UNLOAD TIMER CALL DRLOP SEE IF DRIVE IS READY * * GET CURRENT TRACK FOR THIS DRIVE * SETUN CALL SETU1 GET THIS TRACK STA CTRCK SET IT AS CURRENT RET * * * STORE "A" AS CURRENT TRACK AND RETURN WITH * TRACK TABLE VALUE IN "A". HL POINT TO VALUE * * SETU1 STA CTRCK SAVE IT LXI H,UNTAB POINT TO UNIT TABLE LDA TUNIT GET UNIT ORA A CLEAR THE !"#$%"! CARRY BIT RAR . DIVIDE BY TWO TO GET DRIVE SPECIFICATION ADD L POINT TO PROPER ONE MOV L,A MOV A,M GET TRACK POINTER FROM IT RET * * * CALCULATE PHYSICAL DRIVE AND UNIT FROM NUMBER IN "A" * USET ANI 7 IN CASE OF ERROR AND CLEAR CARRY LXI B,0D030H LOWER AND UPPER UNIT RRC . PUT BIT ZERO IN CARRY RLC . RESTORE A JNC STDRV ODD UNIT IF NO CARRY MOV B,C SELECT EVEN UNIT (0,2,4) * STDRV ANI 6 STRIP OFF UNUSED LOWER BIT RLC . MOVE DRIVE SELECT TO PROPER POSITION CMA . DOUG'S DELIGHT ANI 0CH ONLY KEEP THE DRIVE SELECT ORA B ADD IN THE UNIT ORI 3 NO STEP OR DIRECTION RET * ****************** * * * * THIS ROUTINE CALCULATES THE TRANSFER SIZE FROM THE * HEADER INFORMATION AND SETS THE NUMBER OF SECTORS * INTO OHPRO. * * IF A "WRITE" TRANSFER IS LESS THAN 108 BYTES THE * PHYSICAL (AS OPPOSED TO LOGICAL) LENGTH IS INCREASED. * (HELPS THE POOR OLD CONTROLLER) * BLKLN LHLD TBCNT GET COUNT FROM TRANSFER DESCRIPTOR MVI C,0 START WITH ONE SECTOR LXI D,-256 FIRST SECTOR IS 256 * BSUB DAD D SUBTRACT AMOUNT IN THIS SECTOR INR C SECTOR COUNT UP FOR EACH DAD MOV A,H ORA L JZ BRON RIGHT ON!! (SOMEBODY HAS A CALCULATOR) MOV A,H ORA A TEST FOR MINUS JM BREM TEST IF FUDGE IS NEEDED LXI D,-320 MORE SECTORS WILL BE 320 JMP BSUB WE STILL NEED MORE * * FIND OUT IF REMAINDER IS => 108 * BREM MOV A,E CMA . COMPLEMENT "DE" MOV E,A MOV A,D CMA MOV D,A LONG DRAWN OUT PROCESS INX D TWO'S COMPLEMENT * DAD D PUT REMAINDER IN HL MOV A,H TEST HIGH BITS ORA A JNZ BRON HAS TO BE ENOUGH MOV A,L LOW PART COUNTS FOR THE TEST CPI 108 FUDGE IF NOT THIS BIG JC BMORE IF NOT GO TEST IF READ FIRST * * LOGICAL AND PHYSICAL ARE THE SAME THROUGH HERE * BRON LHLD TBCNT SHLD OHSIZ OUTGOING HEADER SIZE * BSECT SHLD DRLEN TRANSFER LENGTH FOR THE DRIVER LDA OHPRO OUTGOING HEADER PROTECTION WORD ANI 80H CLEAR PREVIOUS COUNT ORA C ADD IN THE SECTOR COUNT STA OHPRO PUT IT BACK RET * * * FUDGE THE TRANSFER LENGTH FOR WRITES....... * WE MUSN'T LEAVE THE SECTOR MARK HANGING!! * BMORE LDA DOPER GET THE OPERATION CPI WDATA IS IT A WRITE OPERATION? JNZ BRON READS DON'T NEED FUDGE LHLD TBCNT SHLD OHSIZ LOGICAL COUNT TO HEADER LXI D,108 ADD THE FUDGE FACTOR DAD D ADD EM UP JMP BSECT FILL EM IN * * ******************* * * * * READ VALID HEADER BUT STILL NOT DESIRED SECTOR * * SCTER LDA DSECN GET ATTEMPT COUNT INR A STA DSECN CPI 25 RNC . ERROR IF GREATER THAN 25 CALL WAITS JMP RP2 * * WAIT FOR SREDY * WAITS IN STAPT GET CONTROLLER STATUS ANI SREDY JZ WAITS LOOP UNTIL SREADY GOES HI RET * * * * DRIVE AND DRIVER INITIALIZATION. * * This routine initializes all drives and sets the * track count values in the unit table to zero. * DDRI MVI B,4 Number of possible drives. LXI H,UNTAB * DDRI1 MVI M,0 Clear the unit table. INX H DCR B JNZ DDRI1 * Initialize the relevent unit. LDA TUNIT STA CUNIT For SEEK0. CALL SEEK0 RET * ****************** * * * DRIVE NOT READY * * GIVE MESSAGE AND WAIT FOR DRIVE READY (CONTINUE * OPERATION OR CHARACTER FROM TERMINAL FOR ABORT.) * DRERR CALL OUST OUTPUT MESSAGE DB 0DH CR DB 0AH LF ASC "DRIVE NOT READY DW 0A0DH DB 0 CALL CONIN READ BYTE FROM CONSOL ORA A JZ EXIT RETURN TO DOS IF CTRL-SHIFT-P * DRLOP IN STAPT SEE IF NOW READY ANI DREDY RZ . DRIVE IS READY JMP DRERR * ******************