.Z80 ; ***************** ; SECTOR DEBLOCKING ; ***************** ; ; HOME DISK ENTRY ROUTINE ; THIS ROUTINE IS USED TO RECALIBRATE ; THE CURRENT SELECTED DISK TO TRACK #0 ; HOME: IF USRCPM XOR A LD (TRK),A LD (TRK16),A LD (TRK16+1),A ; 2.0 COMPATIBLE LD A,(NODISK) ; CHECK CURRENT SELECT DISK CP 'M'-'A' ; LOCAL DISK? JP NC,DHOME ; YES RET ; NO ENDIF ; DHOME: LD A,(HSTWRT) ; CHECK WRITE PENDING DATA IN BUFFER OR A JR NZ,HOMED ; IF WRITE DATA PENDING THEN SKIP LD (HSTACT),A HOMED: IF USRCPM XOR A LD (TRK),A ; RESET SEEK TRACK TO ZERO LD H,A LD L,A LD (TRK16),HL ENDIF ; IF STDCPM LD BC,0 CALL SETTRK ENDIF ; RET ; ; WE JUMP TO HERE WHENEVER THE USER WANTS TO ; RESTART THE SYSTEM, I.E., REREAD CP/M WITHOUT ; MODIFYING THE BIOS. FLUSH ALL WRITE PENDING ; DATA TO DISKS. ; IF USRCPM DWBOOT: LD HL,HSTACT ;CHECK DISK BUFFER ACTIVE BIT 0,(HL) RES 0,(HL) ;RESET BUFFER ACTIVE FLAG ANY WAY RET Z LD HL,HSTWRT BIT 0,(HL) ;ELSE CHECK BUFFER WRITE PENDING RES 0,(HL) ;RESET BUFFER WRITE PENDING CALL NZ,WRITEHST ;IF WRITE PENDING THEN WRITE TO IT RET ;SOMEBODY ELSE IS RESPONSIBLE ENDIF ; DISK SELECT ENTRY ROUTINE ; ACCEPTS: C = DRIVE SELECT (WITH C=0 FOR SELECT DRIVE"A") ; RETURNS: HL = DPB POINTER OF DRIVE SELECT (IF C=VALID DRIVE NUMBER) ; HL = 0H IF (C=INVALID DRIVE NUMBER) ; SETS: CP/M SECTORS PER TRACK ; NUMBER OF SECTORS PER BLOCK SELDSK: IF USRCPM .8080 LXI H,0 ;SET UP FOR ERROR CODE MOV A,E ;LOW BIT 0 IF FIRST TIME STA SELFLG ;SAVE IN REQBLK LDA NDISK ;GET NUMBER OF REMOTE DISK MOV B,A MOV A,C ;GET NEW DISK NUMBER. CMP B ;CHECK IF DRIVE EXISTS STA NODISK STA SELDRV ;SAVE SELECTED DRIVE MMMOST2.0 JNC DSELDSK ;SELECT LOCAL DISK DRIVES ; ; SELECT DRIVE AS A FUNCTION OF H,L ; SELDS1: MOV L,A ;LOAD DISK NUMBER AND ZERO BYTE LXI D,DPBASE ;POINT TO DISK PARM START. DAD H ;*2 DAD H ; *4 DAD H ; *8 DAD H ; *16 DAD D ;COMPUTE INDEX FOR THE DRIVE ; ; IF LOW BIT OF E=0 THEN GET NEW DPB FROM MMMOST ; LDA SELFLG ANI 01H MVI A,0 RET ;SHOULD BE RNZ FOR NORMAL USE ENDIF .Z80 DSELDSK: LD A,C ; GET CURRENT DRIVE LD (SEKDSK),A ; IF STDCPM CP MAXDRV ; CHECK WITH MAXIMUM DRIVES JR C,SELDR1 LD HL,0 ; ERROR FOR ILLEGAL DRIVE RET SELDR1: LD B,0 ; SELDR2: LD HL,DISKTAB ; DISK PARAMETER BLOCK OFFSET ADD HL,BC LD A,(HL) RLCA RLCA RLCA RLCA LD C,A ; LD HL,DPBH ; DISK PARAMETER BLOCK BASE ADDRESS ADD HL,BC PUSH HL ; SAVE DPB ADDRESS LD DE,DPBOFF ADD HL,DE LD E,(HL) INC HL LD D,(HL) EX DE,HL LD A,(HL) LD (SPTCPM),A ; CP/M SECTOR PER TRACK LD DE,HDBOFF ADD HL,DE LD A,(HL) INC A LD (SECBLK),A ; # OF SECTORS PER BLOCK POP HL ENDIF ; IF USRCPM ; ; ACCEPTS: C = DRIVE SELECT (WITH C=0 FOR SELECT DRIVE"A") ; RETURNS: HL = DPB POINTER OF DRIVE SELECT (IF C=VALID DRIVE NUMBER) ; HL = 0H IF (C=INVALID DRIVE NUMBER) ; LD B,A IN A,(IDSWITCH) AND 38H CP 30H LD A,B LD HL,0 RET Z SUB 'M'-'A' RET M CP MAXDRV RET NC ;EXIT IF INVALID DRIVE CALL FLPHR1 ;CONVERT TO REAL DISK LD A,(REALDSK) ;GET REAL DISK NUMBER TO A ; ; ; DISK NUMBER IS IN PROPER RANGE ; LD L,A LD H,0 ADD HL,HL ADD HL,HL ADD HL,HL ADD HL,HL ;MULTIPLY BY 16 LD DE,DPBH ;BASE OF PARAMETER BLOCK ADD HL,DE ;HL=.DPB(CURDSK) EX DE,HL LD HL,10 ADD HL,DE LD C,(HL) INC HL LD B,(HL) LD A,(BC) LD (SECPTRK),A ;SET SECTOR PER TRACK FOR BLOCK/DEBLOCKING INC BC INC BC INC BC LD A,(BC) LD (SECBLK),A EX DE,HL ;RESTORE DPB POINTER TO HL ENDIF RET ; ; SETTRK -- SET READ/WRITE TRACK ; ACCEPTS: C = TRACK NUMBER ; SETTRK: IF STDCPM LD (SEKTRK),BC ENDIF ; IF USRCPM LD A,C ;GET NEW TRACK NUMBER LD (TRK),A ;UPDATE OLD WITH NEW LD (TRK16),A LD A,B LD (TRK16+1),A ;2.0 COMPATIBLE ENDIF ; RET ; ; SETSEC -- SET READ/WRITE SECTOR ; ACCEPTS: C = SECTOR NUMBER ; SETSEC: LD A,C ; IF STDCPM LD (SEKSEC),A ENDIF ; IF USRCPM LD (SECT),A LD A,B LD (SECT+1),A ;2.0 COMPATIBLE ENDIF ; RET ; ; SETDMA -- SET READ/WRITE DMA BUFFER ADDRESS ; SETDMA: LD (DMAADR),BC RET ; ; SECTRAN -- TRANSLATE SECTOR ; ACCEPTS: BC = LOGICAL SECTOR ; RETURNS; HL = PHYSICAL SECTOR ; SECTRN: IF USRCPM LD A,(NODISK) ;GET CURRENT SELECTED DRIVE CP 'M'-'A' ;LOCAL? ENDIF ; LD H,B LD L,C ; IF USRCPM RET C ;NO INC HL ;YES, LOCAL DRIVE ENDIF ; RET ; ; READ CP/M SECTOR ENTRY POINT ; THIS ROUTINE READ THE SELECTED CP/M SECTOR ; INTO SELECTED DMA BUFFER POINTER ; READ: IF STDCPM LD A,(SEKDSK) ; CHECK IF SELECTED DISK EXISTS CP MAXDRV LD A,1 RET NC ; IF NOT, RETURN WITH ERROR FLAG ENDIF ; IF USRCPM ; ; READ THE SECTOR AT SECT, FROM THE PRESENT TRACK. ; USE STARTING ADDRESS AT DMAADR. .8080 LDA NODISK ;IF CURRENT SELECTED CPI 'M'-'A' ;DRIVE IS LOCAL JNC DREAD ;READ FROM LOCAL FLOPPY/HARD READH1: LXI D,128 ;SAVE BYTE AT END OF BUFFER LHLD DMAADR DAD D MOV A,M STA SAVBUF MVI A,READC STA IRQCOD ;INITIATE A READ REQUEST ; CALL SETERRC ;SET ERROR RETRY COUNT ; READ1: LXI H,IRQBLK MVI B,10 CALL PNXO CPI 0 JZ XIIOST ;CONTINUE ; CALL DECERRC ;RETRY - 1 JNZ READ1 ;RETRY TO SEND ;RQBLK AGAIN IF ERROR. MVI B,6 ;XER OUT ERROR MMMOST2.0 JMP PRNTERR ; MMMOST2.0 ; XIIOST: LXI H,STABUF ;GET READ RETURN CODE MVI B,4 CALL PNXI CPI 0 MVI A,1 ; MMMOST2.0 STA SELFLG ; MMMOST2.0 JZ TSTRER ;IF RETURN CODE OK THEN SKIP CALL DECERRC ;ELSE ERROR RETRY - 1 JNZ READ1 ;RETRY AGAIN IF ;COUNT IS NOT EQUAL ZERO MVI B,7 ; MMMOST2.0 JMP PRNTERR ; MMMOST2.0 TSTRER: LDA STABUF+3 ; MMMOST2.0 CPI 0 JZ GETSEC MOV B,A ; MMMOST2.0 MVI C,1 ; MMMOST2.0 CALL PRNTERR ; MMMOST2.0 LDA STABUF+2 ; MMMOST2.0 RET ; MMMOST2.0 ; GETSEC: LHLD DMAADR MVI B,128 CALL PNXI ;TRANSFER SECTOR IN MOV C,A ;SAVE RETURN CODE LXI D,128 LHLD DMAADR DAD D LDA SAVBUF MOV M,A MOV A,C CPI 0 RZ ; CALL DECERRC ;RETRY -1 JNZ READ1 ;IF NOT ZERO THEN DO AGAIN ; MVI B,7 ;TRANSFER IN ERROR CODE MMMOST2.0 JMP PRNTERR ; MMMOST2.0 ENDIF .Z80 DREAD: XOR A LD (UNACNT),A LD A,1 LD (READOP),A ; SET READ OPERATION LD (RSFLAG),A ; MUST READ DATA LD A,WRUAL LD (WRTYPE),A ; TREAT AS UNALLOC JP RWOPER ; PERFORM THE READ ; ; WRITE ROUTINE ENTRY POINT ; THIS ROUTINE WRITE THE SELECTED DMA BUUFER POINTER ; INTO SELECTED CP/M SECTOR ; WRITE: IF STDCPM LD A,(SEKDSK) CP MAXDRV LD A,1 RET NC ENDIF .8080 IF USRCPM LDA NODISK ;IF CURRENT SELECTED CPI 'M'-'A' ;DRIVE IS LOCAL JNC DWRITE ;WRITE TO LOCAL FLOPPY/HARD DISK ; WITEH1: MVI A,WRTCD STA IRQCOD MOV A,C ;GET WRITE TYPE FROM BDOS STA WRTYPE ;0=NORMAL ;1=DIRECTORY ;2=FIRST IN BLOCK CALL SETERRC ;SET ERROR RETRY COUNT ; WRITE1: LXI H,IRQBLK MVI B,10 CALL PNXO ;MAKE THE READ REQUEST CPI 0 JZ XFRDAT ; CALL DECERRC ;RETRY -1 JNZ WRITE1 ;RETRY TO SEND ;THE RQBLK AGAIN MVI B,6 ; MMMOST2.0 JMP PRNTERR ; MMMOST2.0 ; XFRDAT: LHLD DMAADR MVI B,128 CALL PNXO CPI 0 JZ CKWCD ; CALL DECERRC ;RETRY - 1 JNZ WRITE1 ; MVI B,6 ; MMMOST2.0 CALL PRNTERR ; MMMOST2.0 JMP CKTYP2 ; CKWCD: LXI H,STABUF ;CHECK WRITE RETURN CODE MVI B,4 CALL PNXI CPI 0 MVI A,1 ; MMMOST2.0 STA SELFLG ; MMMOST2.0 JZ TSTER ; CALL DECERRC ;DO IT AGAIN IF JNZ WRITE1 ;MORE RETRY COUNT LEFT ; MVI B,7 ; MMMOST2.0 CALL PRNTERR ; MMMOST2.0 JMP CKTYP2 ; MMMOST2.0 ; TSTER: LDA STABUF+3 ; MMMOST2.0 CPI 0 RZ ;* ;* M M M O S T 2 . 0 ;* MOV B,A MVI C,2 ;TO ERROR PRINTING ROUTINE CALL PRNTERR LDA WRTYPE CPI 2 JZ WBOOT JMP BRET ; CKTYP2: LDA WRTYPE CPI 2 JZ WBOOT BBDRET: MVI A,0FFH STA STABUF+2 BRET: LDA STABUF+2 RET ENDIF .Z80 DWRITE: XOR A LD (READOP),A ; SET OPERATION TO WRITE LD A,C ; SAVE WRITE TYPE LD (WRTYPE),A CP WRUAL ; WRITE UNALLOCATED? JR NZ,CHKUNA ; CHECK FOR UNALLOC ; ; WRITE TO UNALLOCATION, SET PARAMETERS ; IF STDCPM LD HL,SECBLK ; NEXT UNALLOCATION LD DE,UNACNT LD BC,5 LDIR ENDIF ; IF USRCPM LD HL,(SECBLK) ;NEXT UNALLOCATION LD (UNACNT),HL ;UNACNT, UNADSK LD HL,(TRK16) LD (UNATRK),HL ;UNATRK LD A,(SECT) LD (UNASEC),A ;UNASEC ENDIF ; CHKUNA: ; CHECK FOR WRITE TO UNALLOCATED SECTOR ; LD A,(UNACNT) ; ANY UNALLOCATED SECTOR REMAIN? OR A JR Z,ALLOC ; SKIP IF NOT ; ; MORE UNALLOCATED SECTOR REMAIN ; DEC A ; UNACNT = UNACNT-1 LD (UNACNT),A LD A,(SEKDSK) ; GET SEEK DISK INTO A LD HL,UNADSK CP (HL) ; SEEK.DSK = UNALL.DSK? JR NZ,ALLOC ; SKIP IF NOT ; ; DISK ARE THE SAME ; LD HL,(UNATRK) CALL SKTRKCMP JR NZ,ALLOC ; SKIP IF NOT ; ; TRACKS ARE THE SAME ; IF STDCPM LD A,(SEKSEC) ; GET SEEK SECTOR INTO A ENDIF ; IF USRCPM LD A,(SECT) ENDIF ; LD HL,UNASEC CP (HL) ; SEEK.SEC = UNALL.SEC? JR NZ,ALLOC ; SKIP IF NOT ; ; MATCH, MOVE "UNASEC" TO NEXT SECTOR FOR FUTURE REF. ; INC (HL) ; UNASEC = UNASEC+1 LD C,(HL) ; IF STDCPM LD A,(SPTCPM) ENDIF IF USRCPM LD A,(SECPTRK) ENDIF ; CP C ; CHECK END OF SEC IN CURRENT TRACK ; IF STDCPM JR NZ,NOOVF ; SKIP IF NO OVERFLOW ENDIF IF USRCPM JR NC,NOOVF ENDIF ; ; OVERFLOW TO NEXT TRACK ; LD (HL),0 ; PRESET UNASEC = 1 LD HL,UNATRK INC (HL) ; UNATRK = UNATRK+1 ; NOOVF: ; ; MATCH FOUND, MARK AS UNNECESSARY READ ; XOR A LD (RSFLAG),A ; SET PRE-READ FLAG = NO JR RWOPER ; PERFORM WRITE CP/M SECTOR ; ALLOC: ; ; NOT AN UNALLOCATED SECTOR, REQUIRES PRE-READ ; XOR A LD (UNACNT),A ; RESET UNALLOC. COUNTER = 0 INC A LD (RSFLAG),A ; SET PRE-READ FLAG = YES. ; ; COMMON CODE FOR READ AND WRITE ROUTINE ; RWOPER: XOR A LD (ERFLAG),A ; RESET ERROR FLAG ; IF STDCPM LD A,(SEKSEC) ; CONVERT SEEEK SECTOR TO HOST SECTOR ENDIF ; IF USRCPM LD A,(SECT) DEC A ENDIF OR A ; CLEAR CARRY FLAG RRA ; IF USRCPM INC A ENDIF ; LD (SEKHST),A ; SEKHST = ((SEKSEC-1)/2)+1 ; ; ACTIVE HOST SECTOR? ; LD HL,HSTACT BIT 0,(HL) SET 0,(HL) ; ALWAY BECOMES 1 JR Z,FILHST ; FILL BUFFER IN ACTIVE FLAG = 0 ; ; HOST BUFFER ACTIVE, SAME AS SEEK BUFFER? ; LD A,(SEKDSK) LD HL,HSTDSK CP (HL) ; SAME DISK? JR NZ,NOMATCH ; SKIP IF NOT MATCH ; ; SAME DISK, SAME TRACK? ; LD HL,(HSTTRK) CALL SKTRKCMP JR NZ,NOMATCH ; SKIP IF NOT MATCH ; ; SAME DISK, SAME TRACK, SAME BUFFER? ; LD A,(SEKHST) LD HL,HSTSEC CP (HL) JR Z,MATCH ; SKIP IF MATCH ; NOMATCH: ; ; PROPER DISK, BUT NOT CORRECT SECTOR ; LD A,(HSTWRT) ; WRITE DATA PENDING IN BUFFER? OR A JR Z,FILHST ; SKIP IF NO WRITE PENDING CALL WRITEHST ; IF YES, THEN WRITE DATA TO DISK LD A,(ERFLAG) OR A JR Z,FILHST ; SKIP IF NO ERROR FILHS2: XOR A LD (HSTACT),A ; RESET HOST ACTIVE FLAG ; MEXIT: LD A,FDTOUT LD (FDTIME),A LD A,(ERFLAG) OR A RET ; FILHST: ; MAY HAVE TO PRE-READ DATA TO HOST BUFFER ; LD A,(SEKDSK) LD (HSTDSK),A ; IF STDCPM LD HL,(SEKTRK) ENDIF ; IF USRCPM LD HL,(TRK16) ENDIF ; LD (HSTTRK),HL LD A,(SEKHST) LD (HSTSEC),A LD A,(RSFLAG) ; CHECK BUFFER REQUIRES PRE-READ OR A CALL NZ,READHST ; IF YES, THEN READ DATA FROM DISK ; LD A,(ERFLAG) ; CHECK FOR I/O ERROR OR A JR NZ,FILHS2 ; IF ERROR THEN SKIP ; FILHS1: XOR A ; INTO BUFFER LD (HSTWRT),A ; RESET PENDING WRITE FLAG ; MATCH: ; ; COPY DATA TO OR FROM BUFFER ; IF STDCPM LD A,(SEKSEC) ; COMPUTE RELATIVE HOST BUFFER ADDRESS ENDIF ; IF USRCPM LD A,(SECT) DEC A ENDIF ; AND SECMSK RRA LD H,A LD A,0 RRA LD L,A ; HL = ((SEKSEC-1)&SECMSK)*128 ; ; HL HAS RELATIVE HOST BUFFER ADDRESS ; LD DE,HSTBUF ADD HL,DE EX DE,HL ; SAVE HOST ADDRESS INTO DE LD HL,(DMAADR) ; GET/PUT CP/M DATA BUFFER POINTER EX DE,HL LD BC,128 ; SET BC = LENGTH TO MOVE LD A,(READOP) ; WHICH WAY? OR A JR NZ,RWMOVE ; SKIP IF READ OPERATION ; ; WRITE OPERATION, MARK AND SWITCH DIRECTION ; LD A,1 LD (HSTWRT),A ; SET WRITE PENDING FLAG ON EX DE,HL ; SOURCE/DESTINATION POINTERS SWAP ; RWMOVE: ; ; BC INITIALLY 128, DE DESTINATION, HL IS SOURCE POINTER ; LDIR ; ; DATA HAS BEEN MOVE TO/FROM HOST BUFFER ; LD A,(WRTYPE) ; CHECK WRITE TYPE OPERATION CP WRDIR ; DIRECTORY WRITE? JR NZ,RWEXIT ; IF NOT A DIRECTORY WRITE THEN EXIT ; WITH ERROR FLAG IN A LD A,(ERFLAG) OR A ; ELSE CHECK FOR ERROR JP NZ,FILHS2 ; IF ERROR THEN EXIT XOR A LD (HSTWRT),A ; RESET WRITE PENDING FLAG CALL WRITEHST RWEXIT: LD A,(ERFLAG) OR A JP Z,MEXIT ; EXIT IF NO ERROR JP FILHS2 ; ; 16-BIT COMPARE BETWEEN (HL) AND (SEKTRK) ; SKTRKCMP: IF STDCPM LD DE,(SEKTRK) ENDIF ; IF USRCPM LD DE,(TRK16) ENDIF ; OR A SBC HL,DE RET ; ; IDENTIFY WHICH DRIVE WE'RE TALKING TO, FLOPPY OR HARD ; IF STDCPM LOCREL: LD A,(HSTDSK) LD C,A LD B,0 LD HL,CTLTAB ADD HL,BC LD A,(HL) RET ENDIF ; IF USRCPM FLPHRD: LD A,(HSTDSK) SUB 'M'-'A' FLPHR1: AND 03 ;STRIP OFF UNUSED BITS LD L,A LD H,0 ADD HL,HL ;COMPUTE OFFSET ADDRESS LD DE,LDSKTB ADD HL,DE ;ADDRESS REAL DISK # AND TYPE LD A,(HL) LD (REALDSK),A ;SAVE REAL DISK NUMBER INC HL LD A,(HL) OR A ;RETURN Z = 1 IF FLOPPY ; Z = 0 IF HARD DISK RET ENDIF ; ; PERFORM PHYSICAL READ ; READHST: IF STDCPM CALL LOCREL DEC A ENDIF ; IF USRCPM CALL FLPHRD ENDIF ; JP FREAD ; ; PERFORM PHYSICAL WRITE ; WRITEHST: IF STDCPM CALL LOCREL DEC A ENDIF ; IF USRCPM CALL FLPHRD ENDIF ; JP FWRITE ; ; HERE ARE THE SECTOR READ/WRITE FUNCTIONS. WE ; WANT TO READ/WRITE TO DISK USING THE PARAMETERS ; SECTOR, TRACK, DMA ADDRESS. ; FREAD: LD A,RDSCMD ; FDC READ COMMAND JR RDWRSEC ; CODE COMMON TO READ AND WRITE ; FWRITE: LD A,WTSCMD ; FDC WRITE COMMAND ; RDWRSEC: LD (COMAND),A ; LD HL,FDTIME LD (HL),0 ; DISABLE MOTOR INC HL LD A,(HL) ; CHECK FLOPPY MOTOR LD (HL),1 ; INDICATE FLOPPY MOTOR IS ON OR A LD A,(DSELCMD) ; CURRENT DISK SELECT AND CONFIGURE OUT (DSELOP),A ; NOW TURN ON MOTOR JR NZ,RWCM0 ; ; WAIT 541 MS FOR MOTOR TO GET SPEED ; SBC HL,HL ; SET HL = 0 RWCM2: DEC HL LD A,H OR L LD A,(HL) ; DUMMY INST. JR NZ,RWCM2 ; RWCM0: IF STDCPM LD A,(HSTDSK) ENDIF ; IF USRCPM LD A,(REALDSK) ENDIF ; LD HL,DRIVE ; CURRENT DRIVE CP (HL) ; SAME DRIVE? CALL NZ,DRVSEL ; NO. HARDWARE SELECTS DRIVE ; RWCM1: LD A,(HSTSEC) ; CHECK SELECT SECTOR > PHYSICAL SEC/TRK ; IF STDCPM CP FPSPT0 ENDIF ; IF USRCPM CP FPSPT0+1 ENDIF ; JP C,SSIDE1 ; IF NOT THEN SELECT SIDE #1 ; ; ELSE SELECT SIDE #2 OF SELETED DISK ; LD A,(DSELCMD) AND 11110000B ; DDEN, SIDE#2, MOTOR ON SET 0,A LD (DSELCMD),A OUT (DSELOP),A LD A,(HSTSEC) SUB FPSPT0 ; SET TSEC=HSTSEC-PSPT0 SETSIDE: IF STDCPM INC A ; PHYSICAL SECTOR TRANSLATION ENDIF ; LD (TSEC),A IN A,(FDCDAT) ; CLEAR DATA REGISTER ; ; CODE COMMON TO READ/WRITE SECTOR OPERATIONS ; LD A,10 ; NO. OF RETRIES LD (FRETRY),A ; ON DISK I/O OPERATION ; RDWT10: CALL SEEK ; SEEK THE USER DEFINED TRACK JP NZ,RDWT30 ; ADJUST RETRY COUNTER ; LD A,(TSEC) ; SET UP FDC OUT (FDCSEC),A ; SECTOR REGISTER ; LD HL,HSTBUF ; SET HL = HOST BUFFER ADDRESS LD C,FDCDAT ; SET C = FDC DATA REGISTER LD B,0 ; SET B = 256 BYTE COUNTER LD A,(COMAND) ; SET UP FDC BIT 5,A ; DECIDE READ/WRITE OPERATION JR Z,RREAD ; GO TO READ OPERATION LD DE,CPUWT ; RETURN ADDRESS FOR OUTPUT PUSH DE ; PUT IT ON STACK JP COMMIO ; JUMP TO COMMON I/O ROUTINE RREAD: LD DE,CPURD ; RETURN ADDRESS FOR INPUT PUSH DE ; PUT IT ON STACK ; COMMIO: DI ; DISABLE SYSTEM INTERRUPT LD DE,0FFFFH ; SET DE = TIMER OUT (FDCCMD),A ; COMMAND READ/WRITE OPERATION ; LD A,15 ; WAIT FOR 60 US TO READ STATUS REGISTER DELAY1: DEC A JR NZ,DELAY1 ; DRQRDY: IN A,(FDCCMD) ; READ STATUS REGISTER BIT 1,A ; DRQ BIT SET? RET NZ ; YES DEC DE ; DECREMENT TIMER LD A,D OR E JR Z,TERROR ; TIME-OUT(ERROR) IN A,(FDCCMD) ; READ STATUS REGISTER AGAIN BIT 1,A ; DRQ BIT SET? RET NZ ; YES BIT 0,A ; FDC BUSY? JR NZ,DRQRDY ; YES ; TERROR: POP DE ; RESTORE REGISTERS CALL WAITW3 ; ERROR PUSH AF ; SAVE ERROR CODE IN A REG ; ; IN A,(FDCDAT) ; CLEAR DATA REGISTER BUFFER POP AF ; RESTORE ERROR CODE IN A REG JP RDWT30 ; CHECK FOR RETRY ; RDDRQ: IN A,(FDCCMD) ; GET FDC STATUS AND 02H ; DRQ BIT SET FOR NEXT BYTE? JR Z,RDDRQ ; NOT YET CPURD: INI ; INPUT AN ASSEMBLED BYTE JR NZ,RDDRQ ; ALL BYTES READ-IN? JR ALDONE ; YES ; WTDRQ: IN A,(FDCCMD) ; READ STATUS AND 02H ; DRQ BIT SET FOR NEXT BYTE? JR Z,WTDRQ ; NO, WAIT CPUWT: OUTI ; OUPUT AN ASSEMBLED BYTE JR NZ,WTDRQ ; ALL BYTES WRITE-OUT? ; ALDONE: IN A,(FDCCMD) ; YES, GET FDC STATUS BIT 0,A ; COMMAND COMPLETED? JR NZ,ALDONE ; NO, WAIT AND 00011100B ; MASK OUT THE BITS ; LD (ERFLAG),A ; SAVE ERROR FLAG AND 0CH ; ANY ERROR: CRC, DATA LOST? JR NZ,RDWT30 ; ERROR ON READ/WRITE ; RDWT20: LD A,(ERFLAG) ; RETURN CODE EI ; ENABLE SYSTEM INTERRUPT RET ; DISK I/O SUCCESSFUL ; ; WE HAD AN ERROR ON READ/WRITE OPERATION ; RDWT30: LD HL,FRETRY ; MORE RETRIES LEFT? DEC (HL) ; BUMP DOWN COUNT JR Z,RDWT33 ; EXIT IF RETRY COUNT = 0 LD A,(HL) CP 7 ; CHECK RETRY COUNT = 7 JR Z,RDWT31 ; IF YES, THEN HOME THE HEAD. CP 4 ; CHECK RETRY COUNT = 4 JP NZ,RDWT10 ; RDWT31: LD A,FRCCMD ; FORCE FDC TO TERMINATE. OUT (FDCCMD),A CALL WAIT ; WAIT FOR FDC COMPLETED LD A,RESCMD OUT (FDCCMD),A ; THEN FORCE FDC TO HOME THE HEAD TO TRACK #0 CALL WAIT ; WAIT FOR FDC COMPLETED. JP RDWT10 ; NOW RETRY READ/WRITE OPERATION. ; RDWT33: CALL ERRPRT ; PRINT DETAILED ERROR MESSAGE JR RDWT20 ; SSIDE1: LD A,(DSELCMD) SET 2,A ; SET SIDE SELECT = SIDE #1 LD (DSELCMD),A OUT (DSELOP),A LD A,(HSTSEC) ; AND (TSEC)=HSTSEC JP SETSIDE ; ; THIS ROUTINE DOES THE ACTUAL SEEKING. ; TRACK NO. IS PASSED IN TRACK VARIABLE. ; SEEK: PUSH HL IN A,(FDCTRK) ; SAVE FDC DEVICE TRACK REG. LD L,A LD A,(HSTTRK) ; GET TRACK NO. BACK CP L ; TEST CURRENT TRACK = SELECT TRACK JR Z,SEEK0 ; IF YES THEN SKIP. OUT (FDCDAT),A ; OUTPUT TO DATA PORT LD A,SEECMD ; THIS IS THE SEEK COMMAND OUT (FDCCMD),A ; GIVE THE ORDER TO FDC ; ; NOW TEST FOR COMPLETION ; CALL WAIT ; WAIT UNTIL NOT BUSY AND SEEMSK ; AND OUT TRACK 0 BIT JR Z,SEEK1 ; IF NO ERROR THEN SKIP. ; SEEK0: POP HL RET ; SEEK1: LD HL,FDCDEL SEEK2: DEC HL LD A,H OR L JP NZ,SEEK2 POP HL RET ; ; THIS ROUTINE LOOPS UNTIL THE FDC IS ; IN A NON-BUSY STATE, OR UNTIL A NOT- ; READY CONDITION IS DETECTED. ; WAIT: LD A,15 ; WE MUST DELAY ABOUT WAIT10: DEC A ; 60 USECS. BEFORE READING JR NZ,WAIT10 ; THE STATUS. ; WAIT20: IN A,(FDCCMD) ; READ THE FDC STATUS LD (ERFLAG),A ; SAVE IT FOR LATER BIT FDCBSY,A ; ARE WE PROCESSING A COMMAND? JR NZ,WAIT20 ; YES, LOOP UNTIL NOT BUSY LD (UNMSTA),A ; UNMASKED STATUS (FOR DEBUG) AND ERRMSK ; MASK OFF NON-ERROR BITS LD (ERFLAG),A ; SAVE STATUS FOR LATER RET ; ; THIS ROUTINE LOOPS UNTIL THE FDC IS ; IN A NON-BUSY STATE, OR UNTIL A NOT- ; READY CONDITION IS DETECTED. TIME-OUT ; FOR DRIVE BUSY OCCURS AT APPROX. ; 1.25 SECONDS AFTER COMMAND INITIATION. ; WAITWT: LD A,15 ; WE MUST DELAY ABOUT WAITW1: DEC A ; 60 USECS. BEFORE READING JR NZ,WAITW1 ; THE STATUS. ; WAITW3: LD (TEMPBC),BC ; SAVE REGISTERS LD (TEMPDE),DE LD (TEMPHL),HL LD BC,0C000H ; TIME OUT FOR 1.25 SECONDS LD A,0 LD (JMPSW),A ; RESET THE FLAG FOR MESSAGE ; WAITW2: IN A,(FDCCMD) ; READ THE FDC STATUS--2.75 LD (ERFLAG),A ; SAVE IT FOR LATER--3.25 LD (ERFLAG),A ; ; PUSH AF ; SAVE REGISTERS--2.75 LD A,(JMPSW) ; GET MESSAGE FLAG--3.25 CP 0 ; MESSAGE ALREADY SENT OUT?--1.75 JR NZ,WAIT30 ; YES, SKIP--1.75 DEC BC ; COUNT DOWN--1.50 LD A,B ; --2.25 OR C ; TIME OUT?--1.00 CALL Z,SIGMSG ; YES, PRINT MESSAGE--2.50 ; WAIT40: POP AF ; RESTORE REGISTERS--2.50 BIT FDCBSY,A ; ARE WE PROCESSING A COMMAND?--2.00 JR NZ,WAITW2 ; NO, RETURN ERROR CODE--3.00 ; LD (UNMSTA),A ; UNMASKED STATUS (FOR DEBUG) AND ERRMSK ; MASK OFF NON-ERROR BITS LD (ERFLAG),A ; SAVE STATUS FOR LATER ; WAIT50: LD HL,(TEMPHL) ; RESTORE REGISTERS LD DE,(TEMPDE) LD BC,(TEMPBC) RET ; WAIT30: CALL CONST ; CONSOLE STATUS CP 0 ; AVAILABLE INPUT? JR Z,WAIT40 ; NO, SKIP CALL CONIN ; GET CHARACTER CP 03H ; CONTROL-C? JR NZ,WAIT40 ; NO, LOOP BACK ; POP AF ; RESTORE REGISTERS LD HL,(TEMPHL) LD DE,(TEMPDE) LD BC,(TEMPBC) ; LD A,FRCCMD ; FORCE TERMINATE OUT (FDCCMD),A OUT (FDCCMD),A LD A,(HSTDSK) ; GET CURRENTLY SELECTED DRIVE LD B,A LD A,(CDISK) ; GET LOGGED DRIVE AND 0FH CP B JR NZ,GOWBT LD A,(CDISK) AND 0F0H LD (CDISK),A GOWBT: JP BIOS+3H ; WARM-BOOT ; ; SELECT THE DRIVE IN HARDWARE. ; DRIVE TO BE SELECTED IS PASSED IN REGISTER A. ; DRVSEL: LD (HL),A ; CURRENT SELECT DISK = HSTDSK IF TPCI LD B,A LD A,(NODRV) ; CHECK SINGLE DRIVE SYSTEM DEC A ; IF TWO DRIVE EXIST, BRANCH TO NORMAL LD A,B ; RESTORE DISK SELECTED JR Z,DRSEL1 ; OPERATION LD HL,CURDRV ; COMPARE CURRENT DRIVE WITH PREVIOUS CP (HL) ; DRIVE JR Z,DRSEL1 ; IF SAME BRANCH TO NORMAL OPERATION LD (CURDRV),A ; OTHERWISE, UPDATE CURRENT DRIVE IF STDCPM ADD A,041H ; MAKE IT TO ASCII STARTING 'A' ENDIF IF USRCPM ADD A,4DH ; MAKE IT TO ASCII STARTING 'M' ENDIF LD (DISKET),A ; SAVE IT FOR MESSAGE LD HL,DRMSG ; PRINT MESSAGE CALL PRNT CALL CONIN LD HL,CRLF CALL PRNT LD A,0 ; ALWAYS SELECT DISK "A" ENDIF DRSEL1: LD B,A ; CONVERT SELECT DISK TO HARDWARE SWITCH INC B ; B = 1 --> A = 1110 1111B LD A,11110111B ; B = 2 --> A = 1101 1111B ; B = 3 --> A = 1011 1111B ; B = 4 --> A = 0111 1111B SW1: RLCA DJNZ SW1 ; AND 0F0H ; PICK-UP HIGH ORDER 4-BITS LD B,A LD A,(DSELCMD) ; GET DRIVE SELECT COMMAND AND 0FH ; STRIP OFF CURRENT DRIVE SELECTED BIT OR B ; MERGE WITH NEW DRIVE SELECT BIT LD (DSELCMD),A OUT (DSELOP),A ; SET HARDWARE TO SELECT NEW DRIVE ; ; UPDATE TRACK-REG BYTE READ SECTOR ID HEADER ; READID: LD A,10 ; SET RETRY COUNT = 10 LD (FRETRY),A ; RDID2: LD A,RDACMD ; SET A = FDC READ ID COMMAND OUT (FDCCMD),A CALL WAITWT IN A,(FDCDAT) ; CLEAR DATA REGISTER IN FDC LD A,(ERFLAG) AND 00011000B JR NZ,RDID1 ; IF ERROR THEN TRY AGAIN IN A,(FDCSEC) ; GET TRACK ADDRESS TO A OUT (FDCTRK),A ; UPDATE TRACK REG IN FDC RET ; RDID1: LD HL,FRETRY ; MORE RETRY LEFT? LD A,(HL) DEC (HL) ; BUMP DOWN COUNT OR A JR NZ,RDID2 ; TRY AGAIN IF COUNT NOT ZERO ; LD A,RESCMD ; THEN FORCE FDC TO HOME HEAD TO TRACK #0 OUT (FDCCMD),A CALL WAIT LD A,(ERFLAG) ; RETUREN WITH ERROR FLAG IN A-REG OR A RET ; ; ; THIS ROUTINE PRINTS DOOR MESSAGE WHEN THERE ; IS AN ACCESS TO A DRIVE WITH DOOR OPENED. ; SIGMSG: LD A,1 ; SET FLAG LD (JMPSW),A LD A,(HSTDSK) ; CURRENT DRIVE ADD A,41H ; MAKE IT ASCII LD (VDRIVE),A ; SAVE FOR LATER LD HL,RDYMSG ; PRINT DOOR MESSAGE CALL PRNT RET ; ; THIS ROUTINE FILLS OUT THE VARIABLE VALUES FROM CURRENT ; STATE AND FDC STATUS CODE IN TABLE AND REPORT TO OPERATOR ; ERRPRT: LD HL,MSG3 ; MESSAGE HEADER CALL PRNT LD A,(COMAND) ; GET CURRENT COMMAND CP 80H ; READ COMMAND? JR NZ,WRMSG ; NO, SKIP LD HL,MSGRC ; READ MESSAGE JR EEP WRMSG: LD HL,MSGWC ; WRITE MESSAGE EEP: CALL PRNT ; CURRENT COMMAND MESSAGE CALL ERRHST ; GET DETAILED MESSAGE AND PRINT LD HL,FSCODE ; GET STATUS TABLE ADDRESS LD A,(ERFLAG) ; GET FDC STATUS CODE CALL FTAB ; CONVERT IT TO HEX AND FILL IN TABLE LD HL,MSG5 CALL PRNT RET ; ; GENERAL PORT INITIALIZATION ROUTINE ; ENTRY: HL -> PORT ADDRESS ; BYTE COUNT ; DATA ; | ; | ; PRTINI: LD C,(HL) ; GET PORT ADDRESS INC HL LD B,(HL) ; GET THE COUNT INC HL ; POINT TO FIRST DATA BYTE OTIR ; BLOCK OUTPUT RET ; ; END OF TPCIFLOP.MAC