;FLOP ;************************************************************** ; ; BEGINNING OF FLOPPY DRIVERS ; 10/15/82 ;************************************************************** ; ; DISK IO PORTS ; FLOPPY EQU 3 ;MAX NO. OF FLOPPY DISK EQU 0F8H ;DISK BASE ADDRESS. DCOM EQU DISK ;DISK COMMAND PORT. DSTAT EQU DISK ;DISK STATUS PORT. TRACK EQU DISK+1 ;DISK TRACK PORT. SECTP EQU DISK+2 ;DISK SECTOR PORT. DDATA EQU DISK+3 ;DISK DATA PORT. WAIT EQU DISK+4 ;DISK WAIT PORT. DSEL EQU WAIT+1 ;DENSITY SELECT DCONT EQU DISK+4 ;DISK CONTROL PORT. ; SD128 EQU 0E5H DSBIT EQU 0000$0100B RTCNT EQU 10 ; SIDE1 DB 00 NRDISK DB 00 SEKTRK DB 00 SERCNT DB 00 ERCNT DB 00 CMDBKT DB 00 TEMPSEC DW 0000H TEMPTRK DW 0000H TEMPDMA DW 0000H ; ; SUBSTITUTE JUMP TABLES FOR HARD OR FLOPPY DISKS ; IF PRIAM or SHUGART or QUANTUM FDJT: JMP READ JMP WRITE ENDIF ; ;****************************************************************** FSELECT: ; has floppy density been logged in ? LXI D,DFLAGS ;USE FLAG NOT CLEARED AS LOGGED MVI H,0 MOV L,C DAD D ;POINT TO THIS DRIVE MOV A,M ORA A ;IF ZERO, NOT LOGGED JNZ MOVPARMS ;IF LOGGED, JUST SELECT IT CALL BLDPTR ;POINT TO HEADER CALL DENSITY ;FIND DENSITY CALL SETBPM ;ALL DONE, SO RET THRU SETBPM EI RET ; delayed select for floppy drives only ; note: LASTFLOP is updated here instead of in SELDSK ; ; ; test LASTFLOP & newdisk UPDATETRK: ; skip if LASTFLOP = newdisk LDA NEWDISK ; purpose of routine is to update track MOV C,A ; register only, head will be done by LDA LASTFLOP ; select STA NRDISK ; for not ready CMP C RZ ; SAME RETURN ; ; GO SELECT AND UPDATE LASTFLOP IF DUAL ;IF DUAL DRIVE, ANI 0FEH ;CLEAR OUT BIT 0. ENDIF ; MOV E,A ; put current disk in D & E MVI D,0 LXI H,TRTAB ;GET ADDRESS OF TRACK TABLE. DAD D ;ADD DISK NO. TO ADDRESS. IN TRACK ;READ 1791 TRACK REGISTER. MOV M,A ;PUT INTO TABLE. ; IF DUAL ;IF A DUAL DRIVE, ANI 0FEH ;CLEAR BIT 0. ENDIF ; MOV E,C ;PUT NEW DISK NO. IN D&E. LXI H,TRTAB ;GET ADDRESS OF TRACK TABLE. DAD D ;ADD DISK NO. TO ADDRESS. MOV A,M ;GET NEW TRACK NUMBER. OUT TRACK ;PUT INTO 1791 TRACK REG. ; MOV A,C ;GET NEW DISK NUMBER. STA LASTFLOP ;UPDATE RET ; SELECT: LDA NEWDISK ; SELECT1: MOV E,A ; ; IF DBLOCK ; ; LDA HSTTRK ;SAVE DESTINATION TRACK. ELSE ; LDA TRK ; ENDIF ; ; STA SEKTRK ; in case not ds MOV B,A ; ORA A ; MVI A,0 ; in case we do not select side 1 STA SIDE1 ; MVI A,2 ;SET UP FOR SINGLE DENS JZ SINGLD ;IF TK 0 THEN SINGLE LXI H,DFLAGS ;FIND DENSITY MVI D,0 ; DAD D ;NOW POINTING TO DENS MOV A,M ; ANI DSBIT ; get double sided bit and clear carry JZ NOT$DS ; if single sided skip MOV A,B ; get track # SRLR A ; put lsb in carry, also devide trk by 2, msb = 0 STA SEKTRK ; now seek will not seek if dbl sided JNC NOTDS ; MVI A,DSBIT ; tack head 1 bit onto drive number ORA E ; MOV E,A ; ; ; IF SIDE2BIT ; MVI A,02H ; for 1795 side 2 test STA SIDE1 ; in case anyone else needs to know we MOV C,A ; are on back side LDA CMDBKT ; ORA C ; set side bit onto r/w command STA CMDBKT ; ENDIF ; NOT$DS: ; MOV A,M ; get density ANI 3 ; strip dsbit SINGLD: ; OUT DSEL ;SELECT DENSITY MOV A,E ; CMA ; OUT DCONT ; set head bit RET ; SEEK ROUTINE ; ; PARAMETERS ; TRACK IN 'SEKTRK' DONE IN SELECT RTN ; SEEK: LDA SEKTRK ; MOV B,A ; CPI 77 ; JNC OVERDSK ; PUSH H ;SAVE H&L. PUSH D ;SAVE D&E. PUSH B ;SAVE B&C. PUSH PSW ; MVI A,RTCNT ;GET RETRY COUNT. SRETRY: STA SERCNT ;STORE IN ERROR COUNTER. IN TRACK ;READ PRESENT TRACK NO. MOV C,A ;SAVE IN C. CMP B ;SAME AS NEW TRACK NO.? MOV A,B ;RESTORE A FROM B. JZ THERE ;JUMP IF THERE. OUT DDATA ;TRACK TO DATA REGISTER. BUSY: IN DSTAT ;READ DISK STATUS. RRC ;LOOK AT BIT 0. JC BUSY ;WAIT TILL NOT BUSY. MOV A,B ;GET TRACK OUT DDATA ;DO VERIFY LDA SKRATE ; ORI 1CH ; OUT DCOM ; IF MMPM CALL DISKWAIT ;INTERRUPT WHEN SEEK COMPLETE ELSE ; IN WAIT ; ENDIF ; XTHL ; XTHL ; IN DSTAT ;READ STATUS. ANI 91H ;LOOK AT BITS. JZ THERE ;OK IF ZERO. ; LDA SERCNT DCR A ;DECREMENT COUNT. JNZ SRETRY ;RETRY SEK. LXI H,SKMSG ;PRINT "SEEK ". CALL PMSG IN DSTAT ;READ DISK STATUS. ANI 91H ;LOOK AT ERROR BITS. MOV D,A ;PUT IN REG D. LXI H,SEEKRTY PUSH H CALL ERMSG1 POP H THERE: POP PSW POP B POP D POP H RET SEEKRTY: POP PSW POP B POP D POP H JMP SEEK ; ;************************************************************* ; READ ; READ THE SECTOR AT HSTSEC FROM THE TRACK AT HSTTRK, ; USING THE STARTING ADDRESS AT HSTDMA ; READ: MVI A,RTCNT STA ERCNT RIORTY: MVI A,88H ;1791 CODE FOR READ WITH HEAD LOAD LXI H,RLOOP ;POINT TO READ I/O LOGIC CALL IOCOM ;DO COMMON I/O ANI 9DH ;LOOK AT ERROR BITS. RZ ;RETURN IF NONE. CALL ERCHK ;CHECK FOR SEEK ERROR. LDA ERCNT DCR A STA ERCNT JNZ RIORTY LXI H,RDMSG ;PRINT "READ ". CALL PMSG ;PRINT ORIGIN MESSAGE. LXI H,READ ; return from common error messages ; to the read routine for retry PUSH H ; JMP ERMSG1 ; print common messages **************** COMMON ERROR PRINT SUBOUTINE ******************** ERMSG1: MOV A,D ;GET ERROR BITS. ANI 80H ;IF BIT 7 HIGH, LXI H,NRMSG ;"NOT READY". CNZ PMSG MOV A,D ;GET ERROR BITS. ANI 10H ;IF BIT 4 IS HIGH, LXI H,RNMSG ;PRINT "RECORD NOT FOUND" CNZ PMSG MOV A,D ;GET ERROR BITS. ANI 8H ;IF BIT 3 IS HIGH, LXI H,CRCMSG ;PRINT "CRC ERROR". CNZ PMSG MOV A,D ;GET ERROR BITS. ANI 4H ;IF BIT 2 IS HIGH, LXI H,LDMSG ;PRINT "LOST DATA". CNZ PMSG MOV A,D ;GET ERROR BITS. ANI 1 ;IF BIT 1 IS HIGH, LXI H,BSYMSG ;PRINT "BUSY" CNZ PMSG LXI H,ERRMSG ;PRINT "ERROR." CALL PMSG LXI H,READYMSG CALL PMSG CALL CONIN ; wait for keyboard response CPI 0DH ; abort JZ ABORT CPI ' ' ; is it a space ? RZ ; go retry POP H ; throw away return retry address RET ; OVERDSK: LXI H,DFMSG ; over ran end of disk CALL PMSG ; ABORT: LDA BOOTDISK ; STA CDISK ; STA NEWDISK ; XRA A ; STA HSTACT ; JMP 0 ; ; READYERR: IF MMPM ; if mpm sys, cannot JMP 0 ; hang system, so abort ENDIF LXI H,NNMSG CALL PMSG CALL CONIN CPI ' ' ; retry JZ CHKRDY LDA NRDISK STA NEWDISK STA 4 ; SO WE WONT TRY AGAIN CALL SELECT1 JMP 0 ; reboot ; IF NOT MMPM ; RLOOP: IN WAIT ;WAIT FOR DRQ OR INTRQ. ORA A ;SET FLAGS. RP ;INTRQ - OPERATION COMPLETE ; IN DDATA ;READ A DATA BYTE FROM DISK. STAX D INX D ;INCREMENT MEMORY POINTER. PCHL ENDIF ; ; ERCHK - CHECK FOR RECORD NOT FOUND ERROR. ; ERCHK: MOV D,A ;SAVE ERROR BITS IN D. ANI 10H ;IF RECORD NOT FOUND, JNZ CHKSK ;DO A CHECK ON SEEK. MOV A,D ;OTHERWISE RESTORE BITS ORA A ;SET FLAGS, RET ;AND RETURN. ;CHECK FOR SEEK TO CORRECT TRACK, ;AND CHANGE IF NECESSARY. ; CHKSK: MVI A,0C4H ;SEND COMMAND TO 1791 OUT DCOM ;TO READ ADDRESS. IN WAIT ;WAIT FOR DRQ OR INTRQ. IN DDATA ;READ THE TRACK ADDRESS. MOV B,A ;SAVE IN REGISTER B. CHKS2: IN WAIT ;WAIT FOR INTRQ. ORA A ;SET FLAGS. JP CHKS3 ;DONE WITH READ ADR OP. IN DDATA ;READ ANOTHER BYTE. JMP CHKS2 ;DO IT AGAIN. CHKS3: IN DSTAT ;READ DISK STATUS. ORA A ;SET FLAGS. JZ CHKS4 ;READ ADR OK IF 0. CALL DOHOME1 ;OTHERWISE, DO HARDWARE RESTORE JMP CHKS5 CHKS4: MOV A,B ;UPDATE TRACK REGISTER. OUT TRACK CHKS5: CALL SEEK ;MOVE THE HEAD TO IT. MOV A,D ;GET ERROR BITS. ORA A ;SET FLAGS. RET ;RETURN FROM ERCHK. ; ; WRITE THE SECTOR AT HSTSEC ON THE TRACK IN HSTTRK, ; USING THE STARTING ADDRESS AT DMAADD ;************************************************************** ; WRITE WRITE: MVI A,RTCNT STA ERCNT WIORTY: MVI A,0A8H ;1791 CODE FOR WRITE WITH HEAD LOAD LXI H,WLOOP ;POINT TO WRITE I/O LOGIC CALL IOCOM ;DO COMMON I/O ANI 0FDH ;LOOK AT THESE BITS. LXI H,0 PROCER: RZ ;RETURN IF NO ERR. CALL ERCHK ;CHECK/CORRECT SEEK ERR. LDA ERCNT DCR A ;DECREMENT COUNT. STA ERCNT JNZ WIORTY LXI H,WTMSG ; print ' write' CALL PMSG MOV A,D ;GET ERROR BITS. ANI 40H ;LOOK AT BIT 6. LXI H,WPMSG ;PRINT "PROTECT ". CNZ PMSG MOV A,D ;GET ERROR BITS. ANI 20H ;LOOK AT BIT 5. LXI H,WFMSG ;PRINT "FAULT ". CNZ PMSG LXI H,WRITE PUSH H ; return from common messages ; to write routine JMP ERMSG1 ;DO COMMON MESSAGES. ; IF NOT MMPM ; WLOOP: ; IN WAIT ;WAIT FOR READY. ORA A ;SET FLAGS. RP ;INTRQ - OPERATION COMPLETE ; LDAX D OUT DDATA ;WRITE ONTO DISK. INX D ;INCREMENT MEM PTR. PCHL ENDIF ; ;*************************************************************** ; MISC. SUBROUTINES IOCOM: DI STA CMDBKT ;SAVE 1791 COMMAND PUSH H ;SAVE READ/WRITE LOOP POINTER CALL UPDATETRK ; replace trk regs to what they were if needed CALL SELECT ; LXI D,0 ; CHKRDY: DCX D ; MOV A,E ; ORA D ; JZ READYERR ; MVI A,0D0H ; 1791 Reset command to check ready OUT DCOM ; XTHL ; XTHL ; IN DSTAT ; RLC ; check not ready JC CHKRDY ; CALL SEEK ; ; LDA OLDISK ; MOV C,A ; LDA NEWDISK ; CMP C ; if new drive, wait for head to stop bounce STA OLDISK ; ; CNZ HDELAY ; no bounces please ; IF DBLOCK LHLD HSTDMA ELSE LHLD DMAADD ;GET STARTING ADR. ENDIF ; IF DBLOCK LDA HSTSEC ; dblocking decides what trk ELSE LDA SECT ; includes head info ENDIF ; IOENT2: OUT SECTP ;SET THE SECTOR INTO 1791. PUSH H ; delay for valid status POP H ; IN DSTAT ;GET 1791 STATUS. ANI 20H ;CHECK FOR HEAD LOAD. JNZ IODCMD ; head loaded = 20h ; LDA SEKTRK ; in case of timeout re-issue seek ; s/b on correct trk, just a way to ; reload head if a long delay on another ; drive (hard disk?) caused a timeout OUT DDATA ; MVI A,19H+04 ; seek + headload + step = 6ms and verify OUT DCOM ; PUSH H ; status not always immediatly availble POP H ; IN WAIT ; in case seek error CALL HDELAY ; ; IF NOT MMPM IODCMD: ; LDA CMDBKT ; OUT DCOM ; XCHG ;DMA IN DE POP H ;(R/W LOOP PTR.) LXI B,IOCOMP ;EFFECTIVE RETURN ADDRESS PUSH B ;PRETEND IT'S A RETURN PCHL ;GO TO RLOOP OR WLOOP ; ELSE JMP IODCMD ENDIF IOCOMP: IN DSTAT ;READ DISK STATUS. RET ; DOHOME: LXI H,0 ; IF DBLOCK SHLD HSTTRK ; ELSE SHLD TRK ; ENDIF DOHOME1: CALL SELECT ; select disk MVI A,1 OR 0CH ;6MS RESTORE OUT DCOM ; PUSH H ; POP H ; time for status to become valid IN WAIT ; PUSH H ; POP H ; IN DSTAT ; ANI 04H ; RNZ ;RETURN IF OK LXI H,HEMSG ;HOME ERROR CALL PMSG ; LXI H,DOHOME1 ; PUSH H ; JMP ERMSG1 ;DO COMMON ERROR MESSAGES ; DENSITY: PUSH B PUSH H ;SAVE DRIVE HEADER VECTOR LXI H,DFLAGS ;POINT AT DENSITY FLAGS MVI B,0 DAD B PUSH H ;WE WILL WANT POINTER IF DBLOCK LHLD HSTTRK ; dblocking decides what trk ELSE LHLD TRK ; includes head info ENDIF SHLD TEMPTRK ;DONT LEAVE NO TRACKS LXI H,0 ;FORCE TO ZERO IF DBLOCK SHLD HSTTRK ELSE SHLD TRK ; includes head info ENDIF CALL DOHOME1 ;MAY NOT WANT TO RESET HOST ACTIV FLAG IF DBLOCK LHLD HSTSEC ; dblocking decides what SEC ELSE LHLD SECT ; ENDIF SHLD TEMPSEC LXI H,1 IF DBLOCK SHLD HSTSEC ; ELSE SHLD SECT ; ENDIF IF DBLOCK LHLD HSTDMA ELSE LHLD DMAADD ENDIF SHLD TEMPDMA LXI H,DIRBF IF DBLOCK SHLD HSTDMA ELSE SHLD DMAADD ;POINT TO SCRATCHPAD AREA ENDIF CALL READ ;READ TK 0 SECTOR 1 TO GET DENSITY LHLD TEMPDMA IF DBLOCK SHLD HSTDMA ELSE SHLD DMAADD ENDIF LHLD TEMPSEC IF DBLOCK SHLD HSTSEC ELSE SHLD SECT ENDIF LHLD TEMPTRK IF DBLOCK LHLD HSTTRK ; dblocking decides what trk ELSE LHLD TRK ; includes head info ENDIF LDA DIRBF+07FH ; get density flag MOV C,A ; pass to getblock in c LXI H,PARAMTBL ; point at start of tables CALL GETBLOCK ; find a match & return pointer INX H ; point to internal code MOV A,M ; get code LXI B,0 ; assume no sector trans. ANI 2 ; is code single density? JZ NOTRANS ; if yes then get trans table LXI B,TRANS NOTRANS: MOV A,M ; get code again INX H ; point at header block XCHG ;SAVE DE POP H ;DENSITY FLAG POINTER MOV M,A ;UPDATE DFLAGS WITH DENSITY POP H ;GET DISK HEADER VECTOR PUSH H ;SAVE IT FOR RETURN MOV M,C INX H MOV M,B ;SET UP TRANSLATE TABLE ADDRESS LXI B,9 ;POINT TO PARM BLOCK DAD B MOV M,E ;SET UP ADDRESS INX H MOV M,D POP H ;RETURN SEL. DISK. HDR. VECTOR POP B RET ; ; find a match for the density flag , leave pointer pointing at flag. ; default at single sided single density. therefore single sided single density ; must be the last block in the list of tables. ; GETBLOCK: LXI D,TBLEND-TBLSTART ; length of one block + flag and GETBLOCK1: ; internal code MOV A,M ; get test match CPI SD128 ; end of table ? RZ CMP C ; match RZ DAD D ; point to next table JMP GETBLOCK1 ; look again ; ; software delay routine HDELAY: LXI D,8000 ;5555=25 MS DELAY AT 4MZ SDELAY: DCX D MOV A,D ORA E JNZ SDELAY RET ; CBIOS MESSAGES ; NRMSG: DB 'ready ',0 RNMSG: DB 'id not found ',0 CRCMSG: DB 'crc ',0 LDMSG: DB 'lost data ',0 BSYMSG: DB 'busy ',0 WPMSG: DB 'protect ',0 WFMSG: DB 'flt ',0 DFMSG: DB 0DH,0AH,'Track Error',0 BTMSG: DB 0DH,0AH,'boot ' ERRMSG: DB 'error' CRLFMS: DB 0DH,0AH,0 RDMSG: DB 0DH,0AH,'Read ',0 WTMSG: DB 0DH,0AH,'Write ',0 SKMSG: DB 0DH,0AH,'Seek ',0 HEMSG: DB 0DH,0AH,'Home ',0 NNMSG: DB 0DH,0AH,'No disk in drive...' READYMSG: DB 0DH,0AH,'Hit space bar to retry, to reboot, ' DB 'any other key to continue ',0 ;******************************************************************* ; ; END OF FLOPPY DRIVERS ; ;******************************************************************* ; PAGE