; ;================================================================================================== ; FLOPPY DISK DRIVER ;================================================================================================== ; ; TODO: ; ; ; PORTS ; #IF ((FDMODE == FDMODE_DIO) | (FDMODE == FDMODE_ZETA) | (FDMODE == FDMODE_DIO3)) FDC_MSR .EQU $36 ; 8272 MAIN STATUS REGISTER FDC_DATA .EQU $37 ; 8272 DATA PORT FDC_DIR .EQU $38 ; DATA INPUT REGISTER FDC_DOR .EQU $3A ; DIGITAL OUTPUT REGISTER (LATCH) FDC_DMA .EQU $3C ; PSEUDO DMA DATA PORT #ENDIF #IF (FDMODE = FDMODE_ZETA2) FDC_MSR .EQU $30 ; 8272 MAIN STATUS REGISTER FDC_DATA .EQU $31 ; 8272 DATA PORT FDC_DOR .EQU $38 ; DIGITAL OUTPUT REGISTER FDC_DCR .EQU $28 ; CONFIGURATION CONTROL REGISTER FDC_TC .EQU $38 ; TERMINAL COUNT (W/ DACK) #ENDIF #IF (FDMODE == FDMODE_DIDE) FDC_BID .EQU $20 ; IO RANGE 20H-3FH FDC_MSR .EQU $2A ; 8272 MAIN STATUS REGISTER FDC_DATA .EQU $2B ; 8272 DATA PORT FDC_DOR .EQU $2C ; DOR FDC_DCR .EQU $2D ; DCR FDC_DACK .EQU $3C ; DACK FDC_TC .EQU $3D ; TERMINAL COUNT (W/ DACK) FDC_DMA .EQU $3C ; NOT USED BY DIDE #ENDIF #IF (FDMODE == FDMODE_N8) FDC_MSR .EQU $8C ; 8272 MAIN STATUS REGISTER FDC_DATA .EQU $8D ; 8272 DATA PORT FDC_DOR .EQU $92 ; DOR FDC_DCR .EQU $91 ; DCR FDC_DACK .EQU $90 ; DACK FDC_TC .EQU $93 ; TERMINAL COUNT (W/ DACK) FDC_DMA .EQU $3C ; NOT USED BY N8 #ENDIF #IF (FDMODE == FDMODE_RCSMC) FDC_MSR .EQU $50 ; 8272 MAIN STATUS REGISTER FDC_DATA .EQU $51 ; 8272 DATA PORT FDC_DOR .EQU $58 ; DIGITAL OUTPUT REGISTER (LATCH) #ENDIF #IF (FDMODE == FDMODE_RCWDC) FDC_MSR .EQU $50 ; 8272 MAIN STATUS REGISTER FDC_DATA .EQU $51 ; 8272 DATA PORT FDC_DOR .EQU $58 ; DIGITAL OUTPUT REGISTER FDC_DCR .EQU $48 ; CONFIGURATION CONTROL REGISTER FDC_TC .EQU $58 ; TERMINAL COUNT (W/ DACK) #ENDIF #IF (FDMODE == FDMODE_DYNO) FDC_BASE .EQU $84 FDC_MSR .EQU FDC_BASE + $00 ; 8272 MAIN STATUS REGISTER FDC_DATA .EQU FDC_BASE + $01 ; 8272 DATA PORT FDC_DOR .EQU FDC_BASE + $02 ; DIGITAL OUTPUT REGISTER FDC_DCR .EQU FDC_BASE + $03 ; CONFIGURATION CONTROL REGISTER FDC_TC .EQU FDC_BASE + $02 ; TERMINAL COUNT (W/ DACK) #ENDIF #IF (FDMODE == FDMODE_EPFDC) FDC_MSR .EQU $48 ; 8272 MAIN STATUS REGISTER FDC_DATA .EQU $49 ; 8272 DATA PORT FDC_DOR .EQU $4A ; DIGITAL OUTPUT REGISTER FDC_DCR .EQU $4B ; CONFIGURATION CONTROL REGISTER FDC_TC .EQU $4C ; TERMINAL COUNT (W/ DACK) #ENDIF #IF (FDMODE == FDMODE_MBC) FDC_MSR .EQU $30 ; 8272 MAIN STATUS REGISTER FDC_DATA .EQU $31 ; 8272 DATA PORT FDC_DOR .EQU $36 ; DIGITAL OUTPUT REGISTER FDC_DCR .EQU $35 ; CONFIGURATION CONTROL REGISTER FDC_TC .EQU $37 ; TERMINAL COUNT (W/ DACK) #ENDIF ; ; DISK OPERATIONS ; DOP_READ .EQU 0 ; READ OPERATION DOP_WRITE .EQU 1 ; WRITE OPERATION DOP_FORMAT .EQU 2 ; FORMAT OPERATION DOP_READID .EQU 3 ; READ ID OPERATION ; ; FDC RESULT CODES ; FRC_OK .EQU 0 ; 00 FRC_NOTIMPL .EQU -01H ; FF FRC_CMDERR .EQU -02H ; FE FRC_ERROR .EQU -03H ; FD FRC_ABORT .EQU -04H ; FC FRC_BUFMAX .EQU -05H ; FB FRC_ABTERM .EQU -08H ; F8 FRC_INVCMD .EQU -09H ; F7 FRC_DSKCHG .EQU -0AH ; F6 FRC_ENDCYL .EQU -0BH ; F5 FRC_DATAERR .EQU -0CH ; F4 FRC_OVERRUN .EQU -0DH ; F3 FRC_NODATA .EQU -0EH ; F2 FRC_NOTWRIT .EQU -0FH ; F1 FRC_MISADR .EQU -10H ; F0 FRC_TOFDCRDY .EQU -11H ; EF FRC_TOSNDCMD .EQU -12H ; EE FRC_TOGETRES .EQU -13H ; ED FRC_TOEXEC .EQU -14H ; EC FRC_TOSEEKWT .EQU -15H ; EB ; ; FD DEVICE CONFIGURATION ; FD_DEVCNT .EQU FDCNT ; 2 DEVICES SUPPORTED FD_CFGSIZ .EQU 8 ; SIZE OF CFG TBL ENTRIES ; ; PER DEVICE DATA OFFSETS ; ; OFFSET OF... FD_DEV .EQU 0 ; DEVICE NUMBER (BYTE) FD_STAT .EQU 1 ; LAST STATUS (BYTE) FD_MEDTYP .EQU 2 ; MEDIA TYPE FDM... (BYTE) FD_CURTRK .EQU 3 ; CURRENT TRACK (BYTE) FD_HST .EQU 4 ; HOSTS SEEK POSITION FD_HSTTRK .EQU FD_HST + 0 ; HOST TRACK (WORD) FD_HSTSEC .EQU FD_HST + 2 ; HOST SECTOR (BYTE) FD_HSTHD .EQU FD_HST + 3 ; HOST HEAD (BYTE) ; FD_CFGTBL: ; DEVICE 0, PRIMARY MASTER .DB 0 ; DEVICE NUMBER .DB 0 ; DEVICE STATUS .DB FDMEDIA ; MEDIA TYPE .DB $FF ; CURRENT TRACK .DW 0 ; HOST TRACK .DB 0 ; HOST SECTOR .DB 0 ; HOST HEAD #IF (FD_DEVCNT >= 2) ; DEVICE 1, PRIMARY SLAVE .DB 1 ; DRIVER DEVICE NUMBER .DB 0 ; DEVICE STATUS .DB FDMEDIA ; MEDIA TYPE .DB $FF ; CURRENT TRACK .DW 0 ; HOST TRACK .DB 0 ; HOST SECTOR .DB 0 ; HOST HEAD #ENDIF ; #IF ($ - FD_CFGTBL) != (FD_DEVCNT * FD_CFGSIZ) .ECHO "*** INVALID FD CONFIG TABLE ***\n" #ENDIF ; .DB $FF ; END MARKER ; #IF (FDTRACE > 0) ; ; FDC STATUS CODE STRINGS ; FSS_OK .TEXT "OK$" FSS_NOTIMPL .TEXT "NOT IMPLEMENTED$" FSS_CMDERR .TEXT "COMMAND ERROR$" FSS_ERROR .TEXT "ERROR$" FSS_ABORT .TEXT "ABORT$" FSS_BUFMAX .TEXT "BUFFER EXCEEDED$" FSS_ABTERM .TEXT "ABNORMAL TERMINATION$" FSS_INVCMD .TEXT "INVALID COMMAND$" FSS_DSKCHG .TEXT "DISK CHANGE$" FSS_ENDCYL .TEXT "END OF CYLINDER$" FSS_DATAERR .TEXT "DATA ERROR$" FSS_OVERRUN .TEXT "OVERRUN$" FSS_NODATA .TEXT "NO DATA$" FSS_NOTWRIT .TEXT "NOT WRITABLE$" FSS_MISADR .TEXT "MISSING ADDRESS MARK$" FSS_TOFDCRDY .TEXT "FDC READY TIMEOUT$" FSS_TOSNDCMD .TEXT "SENDCMD TIMEOUT$" FSS_TOGETRES .TEXT "GET RESULTS TIMEOUT$" FSS_TOEXEC .TEXT "EXEC TIMEOUT$" FSS_TOSEEKWT .TEXT "SEEK WAIT TIMEOUT$" ; ; FDC STATUS STRING TABLE ; FSST: .DB FRC_OK \ .DW FSS_OK FSST_ENTSIZ .EQU $ - FSST .DB FRC_NOTIMPL \ .DW FSS_NOTIMPL .DB FRC_CMDERR \ .DW FSS_CMDERR .DB FRC_ERROR \ .DW FSS_ERROR .DB FRC_ABORT \ .DW FSS_ABORT .DB FRC_BUFMAX \ .DW FSS_BUFMAX .DB FRC_ABTERM \ .DW FSS_ABTERM .DB FRC_INVCMD \ .DW FSS_INVCMD .DB FRC_DSKCHG \ .DW FSS_DSKCHG .DB FRC_ENDCYL \ .DW FSS_ENDCYL .DB FRC_DATAERR \ .DW FSS_DATAERR .DB FRC_OVERRUN \ .DW FSS_OVERRUN .DB FRC_NODATA \ .DW FSS_NODATA .DB FRC_NOTWRIT \ .DW FSS_NOTWRIT .DB FRC_MISADR \ .DW FSS_MISADR .DB FRC_TOFDCRDY \ .DW FSS_TOFDCRDY .DB FRC_TOSNDCMD \ .DW FSS_TOSNDCMD .DB FRC_TOGETRES \ .DW FSS_TOGETRES .DB FRC_TOEXEC \ .DW FSS_TOEXEC .DB FRC_TOSEEKWT \ .DW FSS_TOSEEKWT FSST_COUNT .EQU (($ - FSST) / FSST_ENTSIZ) ; # ENTRIES IN TABLE #ENDIF ; ; FDC COMMANDS ; CFD_READ .EQU 00000110B ; CMD,HDS/DS,C,H,R,N,EOT,GPL,DTL --> ST0,ST1,ST2,C,H,R,N CFD_READDEL .EQU 00001100B ; CMD,HDS/DS,C,H,R,N,EOT,GPL,DTL --> ST0,ST1,ST2,C,H,R,N CFD_WRITE .EQU 00000101B ; CMD,HDS/DS,C,H,R,N,EOT,GPL,DTL --> ST0,ST1,ST2,C,H,R,N CFD_WRITEDEL .EQU 00001001B ; CMD,HDS/DS,C,H,R,N,EOT,GPL,DTL --> ST0,ST1,ST2,C,H,R,N CFD_READTRK .EQU 00000010B ; CMD,HDS/DS,C,H,R,N,EOT,GPL,DTL --> ST0,ST1,ST2,C,H,R,N CFD_READID .EQU 00001010B ; CMD,HDS/DS --> ST0,ST1,ST2,C,H,R,N CFD_FMTTRK .EQU 00001101B ; CMD,HDS/DS,N,SC,GPL,D --> ST0,ST1,ST2,C,H,R,N CFD_SCANEQ .EQU 00010001B ; CMD,HDS/DS,C,H,R,N,EOT,GPL,STP --> ST0,ST1,ST2,C,H,R,N CFD_SCANLOEQ .EQU 00011001B ; CMD,HDS/DS,C,H,R,N,EOT,GPL,STP --> ST0,ST1,ST2,C,H,R,N CFD_SCANHIEQ .EQU 00011101B ; CMD,HDS/DS,C,H,R,N,EOT,GPL,STP --> ST0,ST1,ST2,C,H,R,N CFD_RECAL .EQU 00000111B ; CMD,DS --> CFD_SENSEINT .EQU 00001000B ; CMD --> ST0,PCN CFD_SPECIFY .EQU 00000011B ; CMD,SRT/HUT,HLT/ND --> CFD_DRVSTAT .EQU 00000100B ; CMD,HDS/DS --> ST3 CFD_SEEK .EQU 00001111B ; CMD,HDS/DS --> CFD_VERSION .EQU 00010000B ; CMD --> ST0 ; ; ; Specify Command: ; +-----+-----+-----+-----+-----+-----+-----+-----+-----+ ; |Byte | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ; +-----+-----+-----+-----+-----+-----+-----+-----+-----+ ; | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | ; | 1 | ----- STEP RATE ----- | -- HEAD UNLOAD TIME - | ; | 2 | ------------ HEAD LOAD TIME ----------- | NDM | ; +-----+-----+-----+-----+-----+-----+-----+-----+-----+ ; ; ; Step Rate (milliseconds): Head Unload Time (milliseconds): Head Load Time (milliseconds): ; +------+------+------+------+------+ +------+------+------+------+------+ +------+------+------+------+------+ ; | | BITRATE | | | BITRATE | | | BITRATE | ; | VAL | 1.0M | 500K | 300K | 250K | | VAL | 1.0M | 500K | 300K | 250K | | VAL | 1.0M | 500K | 300K | 250K | ; +------+------+------+------+------+ +------+------+------+------+------+ +------+------+------+------+------+ ; | 0 | 8.0 | 16.0 | 26.7 | 32.0 | | 0 | 128 | 256 | 426 | 512 | | 0 | 128 | 256 | 426 | 512 | ; | 1 | 7.5 | 15.0 | 25.0 | 30.0 | | 1 | 8 | 16 | 26.7 | 32 | | 1 | 1 | 2 | 3.3 | 4 | ; | 2 | 7.0 | 14.0 | 23.3 | 28.0 | | 2 | 16 | 32 | 53.3 | 64 | | 2 | 2 | 4 | 6.7 | 8 | ; | ... | ... | ... | ... | ... | | ... | ... | ... | ... | ... | | ... | ... | ... | ... | ... | ; | 14 | 1.0 | 2.0 | 3.3 | 4.0 | | 14 | 112 | 224 | 373 | 448 | | 126 | 126 | 252 | 420 | 504 | ; | 15 | 0.5 | 1.0 | 1.7 | 2.0 | | 15 | 120 | 240 | 400 | 480 | | 127 | 127 | 254 | 423 | 508 | ; +------+------+------+------+------+ +------+------+------+------+------+ +------+------+------+------+------+ ; ; IBM PS/2 CALLS FOR: ; STEP RATE: 3ms (6ms FOR ALL 41mm OR 720K DRIVES) ; HEAD LOAD TIME: 15ms ; ; STATIC CONFIGURATION, NEVER CHANGES (PRIVATE) ; FCD_MT .EQU 000H ; MULTI-TRACK, WE DON'T USE, SET TO 0 FCD_MFM .EQU 001H ; MFM, 0=FM, 1=MFM, WE USE MFM ALWAYS FCD_SK .EQU 000H ; SKIP MODE, WE DON'T USE, SET TO 0 FCD_N .EQU 002H ; SECTOR SIZE, N=2 FOR 512 BYTES FCD_DTL .EQU 0FFH ; DATA LENGTH (WHEN N=0, SET TO FF OTHERWISE) FCD_STP .EQU 001H ; SECTOR SCAN TYPE, 1=CONTIG, 2=ALTERNATING ; FCD_PC720 .DB 050H ; NUMBER OF CYLINDERS .DB 002H ; NUMBER OF HEADS .DB 009H ; NUMBER OF SECTORS .DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1) .DB 009H ; SECTOR COUNT .DW 200H ; SECTOR SIZE IN BYTES .DB 02AH ; GAP LENGTH (R/W) .DB 050H ; GAP LENGTH (FORMAT) .DB (13 << 4) | 0 ; SRT = 6ms, HUT = 512ms .DB (4 << 1) | 1 ; HLT = 16ms, ND = YES .DB DOR_BR250 ; DOR .DB DCR_BR250 ; DCR .IF (($ - FCD_PC720) != FCD_LEN) .ECHO "*** FCD_PC720 SIZE ERROR!!! ***\n" .ENDIF ; FCD_PC144 .DB 050H ; NUMBER OF CYLINDERS .DB 002H ; NUMBER OF HEADS .DB 012H ; NUMBER OF SECTORS .DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1) .DB 012H ; SECTOR COUNT .DW 200H ; SECTOR SIZE IN BYTES .DB 01BH ; GAP LENGTH (R/W) .DB 06CH ; GAP LENGTH (FORMAT) .DB (13 << 4) | 0 ; SRT = 3ms, HUT = 256ms .DB (8 << 1) | 1 ; HLT = 16ms, ND = YES .DB DOR_BR500 ; DOR .DB DCR_BR500 ; DCR .IF (($ - FCD_PC144) != FCD_LEN) .ECHO "*** FCD_PC144 SIZE ERROR!!! ***\n" .ENDIF ; FCD_PC360 .DB 028H ; NUMBER OF CYLINDERS .DB 002H ; NUMBER OF HEADS .DB 009H ; NUMBER OF SECTORS .DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1) .DB 009H ; SECTOR COUNT .DW 200H ; SECTOR SIZE IN BYTES .DB 02AH ; GAP LENGTH (R/W) .DB 050H ; GAP LENGTH (FORMAT) .DB (13 << 4) | 0 ; SRT = 6ms, HUT = 512ms .DB (4 << 1) | 1 ; HLT = 16ms, ND = YES .DB DOR_BR250 ; DOR .DB DCR_BR250 ; DCR .IF (($ - FCD_PC360) != FCD_LEN) .ECHO "*** FCD_PC360 SIZE ERROR!!! ***\n" .ENDIF ; FCD_PC120 .DB 050H ; NUMBER OF CYLINDERS .DB 002H ; NUMBER OF HEADS .DB 00FH ; NUMBER OF SECTORS .DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1) .DB 00FH ; SECTOR COUNT .DW 200H ; SECTOR SIZE IN BYTES .DB 01BH ; GAP LENGTH (R/W) .DB 054H ; GAP LENGTH (FORMAT) .DB (10 << 4) | 0 ; SRT = 6ms, HUT = 256ms .DB (8 << 1) | 1 ; HLT = 16ms, ND = YES .DB DOR_BR500 ; DOR .DB DCR_BR500 ; DCR .IF (($ - FCD_PC120) != FCD_LEN) .ECHO "*** FCD_PC120 SIZE ERROR!!! ***\n" .ENDIF ; FCD_PC111 .DB 04DH ; NUMBER OF CYLINDERS .DB 002H ; NUMBER OF HEADS .DB 00FH ; NUMBER OF SECTORS .DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1) .DB 00FH ; SECTOR COUNT .DW 200H ; SECTOR SIZE IN BYTES .DB 01BH ; GAP LENGTH (R/W) .DB 054H ; GAP LENGTH (FORMAT) .DB (13 << 4) | 0 ; SRT = 3ms, HUT = 256ms .DB (25 << 1) | 1 ; HLT = 50ms, ND = YES .DB DOR_BR500 ; DOR .DB DCR_BR500 ; DCR .IF (($ - FCD_PC111) != FCD_LEN) .ECHO "*** FCD_PC111 SIZE ERROR!!! ***\n" .ENDIF ; ; FCD LOOKUP TABLE (CALLED TO SET HL TO ADDRESS OF MEDIA DATA ABOVE) ; ENTRIES BELOW MUST MATCH COUNT AND VALUES OF FDMXXX IN STD.ASM ; FCD_TBL: LD HL,FCD_PC720 \ RET ; FDM720 = 0 LD HL,FCD_PC144 \ RET ; FDM144 = 1 LD HL,FCD_PC360 \ RET ; FDM360 = 2 LD HL,FCD_PC120 \ RET ; FDM120 = 3 LD HL,FCD_PC111 \ RET ; FDM111 = 4 ; ; DOR BITS (3AH) ; ; DISKIO 250KBPS 500KBPS ; ------- ------- ------- ;D7 /DC/RDY 1 (N/A) 1 (N/A) ;D6 /REDWC (DENSITY) 0 (DD) 1 (HD) ;D5 P0* (PRECOMP BIT 0) 1 \ 0 \ ;D4 P1* (PRECOMP BIT 1) 0 (125NS) 1 (125NS) ;D3 P2* (PRECOMP BIT 2) 0 / 0 / ;D2 MINI (BITRATE) 1 (250KBPS) 0 (500KBPS) ;D1 /MOTOR (ACTIVE LO) 1 (OFF) 1 (OFF) ;D0 TC (TERMINAL COUNT) 0 (OFF) 0 (OFF) ; ; *NOTE: FOR 9229 DATA SEPARATOR USED IN DISKIO, VALUE OF PRECOMP BITS CHANGES WITH MINI ; IF MINI=1 (250KBPS), USE 001 FOR 125NS PRECOMP, IF MINI=0, USE 010 FOR 125NS PRECOMP ; #IF (FDMODE == FDMODE_DIO) DOR_BR250 .EQU 10100100B ; 250KBPS W/ MOTOR ON DOR_BR500 .EQU 11010000B ; 500KBPS W/ MOTOR ON DOR_INIT .EQU 11010010B ; INITIAL DEFAULT LATCH VALUE #ENDIF ; ; ZETA/DISKIO3 250KBPS 500KBPS ; ------------ ------- ------- ;D7 /FDC_RST 1 (RUN) 1 (RUN) ;D6 DENSEL 1 (DD) 0 (HD) ;D5 P0 (PRECOMP BIT 0) 1 \ 1 \ ;D4 P1 (PRECOMP BIT 1) 0 (125NS) 0 (125NS) ;D3 P2 (PRECOMP BIT 2) 0 / 0 / ;D2 MINI (BITRATE) 1 (250KBPS) 0 (500KBPS) ;D1 MOTOR 0 (OFF) 0 (OFF) ;D0 TC 0 (OFF) 0 (OFF) ; ; MOTOR AND DENSITY SELECT ARE INVERTED ON ZETA/DISKIO3 VS. DIO ; #IF ((FDMODE == FDMODE_ZETA) | (FDMODE == FDMODE_DIO3)) DOR_BR250 .EQU 11100110B ; 250KBPS W/ MOTOR ON DOR_BR500 .EQU 10100010B ; 500KBPS W/ MOTOR ON DOR_INIT .EQU 10100000B ; INITIAL DEFAULT LATCH VALUE #ENDIF ; ; RCSMC 250KBPS 500KBPS ; ------------ ------- ------- ;D7 /FDC_RST 1 (RUN) 1 (RUN) ;D6 DENSEL 0 (DD) 1 (HD) ;D5 P0 (PRECOMP BIT 0) 1 \ 1 \ ;D4 P1 (PRECOMP BIT 1) 0 (125NS) 0 (125NS) ;D3 P2 (PRECOMP BIT 2) 0 / 0 / ;D2 MOTORB 0 (OFF) 0 (OFF) ;D1 MOTORA 0 (OFF) 0 (OFF) ;D0 TC 0 (OFF) 0 (OFF) ; ; MOTOR INVERTED VS. DIO, DENSITY SELECT LIKE DIO ; #IF (FDMODE == FDMODE_RCSMC) ; RCSMC HAS NO MINI (BITRATE) LATCH AT D2. INSTEAD, D1 AND ; D2 PROVIDE INDEPENDENT MOTOR CONTROL FOR EACH DRIVE. ; MINI (BITRATE) IS A HARDWARE JUMPER (JP3) ; JP3: 1-2 IS DD (MINI HIGH) AND 2-3 IS HD (MINI LOW) ; JP3 *MUST* BE SET CORRECTLY FOR MEDIA USED ; THE CORRECT MOTOR BIT IS SET IN MOTOR ON, NEITHER SET HERE DOR_BR250 .EQU 10100000B ; 250KBPS W/ MOTOR OFF! DOR_BR500 .EQU 11100000B ; 500KBPS W/ MOTOR OFF! DOR_INIT .EQU 11100000B ; INITIAL DEFAULT LATCH VALUE #ENDIF ; ; *** DIDE/N8/ZETA V2 *** ; #IF ((FDMODE == FDMODE_DIDE) | (FDMODE == FDMODE_N8) | (FDMODE == FDMODE_ZETA2) | (FDMODE == FDMODE_RCWDC) | (FDMODE == FDMODE_DYNO) | (FDMODE == FDMODE_EPFDC) | (FDMODE == FDMODE_MBC)) DOR_INIT .EQU 00001100B ; SOFT RESET INACTIVE, DMA ENABLED DOR_BR250 .EQU DOR_INIT DOR_BR500 .EQU DOR_INIT #ENDIF ; ; DCR (ONLY APPLIES TO DIDE, N8, AND ZETA V2) ; DCR_BR250 .EQU 01H ; 250KBPS DCR_BR500 .EQU 00H ; 500KBPS ; #IF (FDTRACE > 0) ; ; FDC COMMAND STRINGS ; FCS_NOP .DB "NOP$" FCS_READ .DB "READ$" FCS_READDEL .DB "READDEL$" FCS_WRITE .DB "WRITE$" FCS_WRITEDEL .DB "WRITEDEL$" FCS_READTRK .DB "READTRK$" FCS_READID .DB "READID$" FCS_FMTTRK .DB "FMTTRK$" FCS_SCANEQ .DB "SCANEQ$" FCS_SCANLOEQ .DB "SCANLOEQ$" FCS_SCANHIEQ .DB "SCANHIEQ$" FCS_RECAL .DB "RECAL$" FCS_SENSEINT .DB "SENSEINT$" FCS_SPECIFY .DB "SPECIFY$" FCS_DRVSTAT .DB "DRVSTAT$" FCS_SEEK .DB "SEEK$" FCS_VERSION .DB "VER$" ; ; FDC COMMAND TABLE ; FCT .DB CFD_READ \ .DW FCS_READ FCT_ENTSIZ .EQU $ - FCT .DB CFD_READDEL \ .DW FCS_READDEL .DB CFD_WRITE \ .DW FCS_WRITE .DB CFD_WRITEDEL \ .DW FCS_WRITEDEL .DB CFD_READTRK \ .DW FCS_READTRK .DB CFD_READID \ .DW FCS_READID .DB CFD_FMTTRK \ .DW FCS_FMTTRK .DB CFD_SCANEQ \ .DW FCS_SCANEQ .DB CFD_SCANLOEQ \ .DW FCS_SCANLOEQ .DB CFD_SCANHIEQ \ .DW FCS_SCANHIEQ .DB CFD_RECAL \ .DW FCS_RECAL .DB CFD_SENSEINT \ .DW FCS_SENSEINT .DB CFD_SPECIFY \ .DW FCS_SPECIFY .DB CFD_DRVSTAT \ .DW FCS_DRVSTAT .DB CFD_SEEK \ .DW FCS_SEEK .DB CFD_VERSION \ .DW FCS_VERSION FCT_COUNT .EQU (($ - FCT) / FCT_ENTSIZ) ; # ENTRIES IN TABLE #ENDIF ; ; DRIVER FUNCTION TABLE ; FD_FNTBL: .DW FD_STATUS .DW FD_RESET .DW FD_SEEK .DW FD_READ .DW FD_WRITE .DW FD_VERIFY .DW FD_FORMAT .DW FD_DEVICE .DW FD_MEDIA .DW FD_DEFMED .DW FD_CAP .DW FD_GEOM #IF (($ - FD_FNTBL) != (DIO_FNCNT * 2)) .ECHO "*** INVALID FD FUNCTION TABLE ***\n" #ENDIF ; FD_VERIFY: FD_FORMAT: FD_DEFMED: SYSCHKERR(ERR_NOTIMPL) ; INVALID SUB-FUNCTION RET ; ; ; FD_DEVICE: LD D,DIODEV_FD ; D := DEVICE TYPE LD E,(IY+FD_DEV) ; E := PHYSICAL DEVICE NUMBER #IF (FDMEDIA == FDM720) LD C,%11010100 ; 3.5" DS/DD #ENDIF #IF (FDMEDIA == FDM144) LD C,%11011000 ; 3.5" DS/HD #ENDIF #IF (FDMEDIA == FDM360) LD C,%10110100 ; 5.25" DS/DD #ENDIF #IF (FDMEDIA == FDM120) LD C,%10111000 ; 5.25" DS/HD #ENDIF #IF (FDMEDIA == FDM111) LD C,%10010100 ; 8" DS/DD #ENDIF LD H,FDMODE ; H := MODE LD L,FDC_MSR ; L := BASE I/O ADDRESS XOR A ; SIGNAL SUCCESS RET ; ; FD_MEDIA ; FD_MEDIA: LD A,E ; GET FLAGS OR A ; SET FLAGS JR Z,FD_MEDIA4 ; JUST REPORT CURRENT STATUS AND MEDIA #IF (FDMAUTO) ; SETUP TO READ TRK 0, HD 0, SEC 0 ;LD A,C ; C STILL HAS REQUESTED DRIVE LD A,(IY+FD_DEV) ; GET DRIVE UNIT ;AND 0FH LD (FCD_DS),A LD A,0 LD (FCD_C),A LD (FCD_H),A INC A LD (FCD_R),A LD A,DOP_READID LD (FCD_DOP),A #IF (FDTRACE < 3) ; SUPPRESS TRACING FOR MEDIA TESTS LD A,0 LD (FCD_TRACE),A #ENDIF LD B,5 FD_MEDIARETRY: ; TRY PRIMARY MEDIA CHOICE FIRST LD A,FDMEDIA CALL FD_TESTMEDIA JR Z,FD_MEDIA3 ; IF SUCCESS, WE ARE DONE ; TRY ALTERNATE MEDIA CHOICE LD A,FDMEDIAALT CALL FD_TESTMEDIA JR Z,FD_MEDIA3 ; IF SUCCESS, WE ARE DONE DJNZ FD_MEDIARETRY ; NO JOY, RETURN WITH E=0 (NO MEDIA) ;LD HL,(FDDS_MEDIAADR) ;LD (HL),0 ; SET TO NO MEDIA LD (IY+FD_MEDTYP),0 ; SET DRIVE = NO MEDIA LD E,0 LD A,ERR_NOMEDIA ; SIGNAL ERROR OR A ; SET FLAGS RET FD_TESTMEDIA: ;LD HL,(FDDS_MEDIAADR) ;LD (HL),A LD (IY+FD_MEDTYP),A PUSH BC CALL FD_START POP BC RET FD_MEDIA3: #IF (FDTRACE < 3) ; RESTORE TRACING FOR MEDIA TESTS LD A,FDTRACE LD (FCD_TRACE),A #ENDIF #ENDIF FD_MEDIA4: #IF (FDTRACE >= 3) LD DE,FDSTR_SELECT CALL WRITESTR ;LD BC,(FDDS_MEDIAADR) ;CALL PRTHEXWORD #ENDIF ; LOAD THE MEDIA BYTE ;LD HL,(FDDS_MEDIAADR) ;LD A,(HL) LD A,(IY+FD_MEDTYP) ; GET CURRENT MEDIA TYPE ADD A,MID_FD720 ; ASSUMES MID_ VALUES ARE IN SAME ORDER AS FDM VALUES #IF (FDTRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF LD E,A ; MOVE MEDIA VALUE TO E XOR A ; SIGNAL SUCCESS RET ; ; ; FD_CAP: CALL FD_GEOM ; GET GEOMETRY ; HL=TRACKS, D=HEADS, E=SECTORS PUSH HL ; SAVE TRACK COUNT LD H,D ; HEADS COUNT TO H RES 7,H ; MAKE SURE LBA CAPABILITY BIT IS CLEARED CALL MULT8 ; HL := H * E FOR SECTORS / CYL POP DE ; RECOVER TRACKS, E == TRACK COUNT LD H,L ; MOVE WORKING COUNT L --> H CALL MULT8 ; HL := H * E FOR TOTAL SECTORS LD DE,0 ; HI WORD ALWAYS ZERO XOR A ; SIGNAL SUCCESS RET ; DONE ; ; ; FD_GEOM: LD A,(IY+FD_MEDTYP) ; GET CURRENT MEDIA TYPE RLCA ; TABLE IS 4 BYTE ENTRIES RLCA ; A = A * 4 LD HL,FCD_TBL ; HL = START OF TABLE LD D,0 ; SET DE TO TABLE OFFSET LD E,A ADD HL,DE ; OFFSET BASED ON DESIRED MEDIA CALL JPHL ; CALL THE TABLE ENTRY (SEE FCD_TBL) ; HL NOW POINTS TO START OF DESIRED MEDIA INFO LD A,(HL) ; GET TRACKS INC HL ; POINT TO HEADS LD D,(HL) ; GET HEADS SET 7,D ; SET LBA CAPABILITY BIT INC HL ; POINT TO SECTORS LD E,(HL) ; GET SECTORS LD L,A ; L := TRACKS LD H,0 ; HI WORD OF TRACKS IS ALWAYS ZERO XOR A ; SIGNAL SUCCESS RET ; DONE ; ; FD_INIT ; FD_INIT: CALL NEWLINE ; FORMATTING PRTS("FD: MODE=$") ; #IF (FDMODE == FDMODE_DIO) PRTS("DIO$") #ENDIF ; #IF (FDMODE == FDMODE_ZETA) PRTS("ZETA$") #ENDIF ; #IF (FDMODE == FDMODE_DIO3) PRTS("DIO3$") #ENDIF ; #IF (FDMODE == FDMODE_ZETA2) PRTS("ZETA2$") #ENDIF ; #IF (FDMODE == FDMODE_DIDE) PRTS("DIDE$") #ENDIF ; #IF (FDMODE == FDMODE_N8) PRTS("N8$") #ENDIF ; #IF (FDMODE == FDMODE_RCSMC) PRTS("RCSMC$") #ENDIF ; #IF (FDMODE == FDMODE_RCWDC) PRTS("RCWDC$") #ENDIF ; #IF (FDMODE == FDMODE_DYNO) PRTS("DYNO$") #ENDIF ; #IF (FDMODE == FDMODE_EPFDC) PRTS("EPFDC$") #ENDIF ; #IF (FDMODE == FDMODE_MBC) PRTS("MBC$") #ENDIF ; PRTS(" IO=0x$") LD A,FDC_MSR CALL PRTHEXBYTE CALL FD_DETECT ; CHECK FOR FDC JR Z,FD_INIT00 ; CONTINUE IF FOUND PRTS(" NOT PRESENT$") ; NOT ZERO, H/W NOT PRESENT OR $FF ; SIGNAL FAILURE RET ; BAIL OUT ; FD_INIT00: PRTS(" UNITS=$") LD A, FD_DEVCNT + '0' CALL COUT ; ; SETUP THE DISPATCH TABLE ENTRIES ; LD B,FD_DEVCNT ; LOOP CONTROL LD IY,FD_CFGTBL ; START OF CFG TABLE FD_INIT0: PUSH BC ; SAVE LOOP CONTROL LD BC,FD_FNTBL ; BC := FUNC TABLE ADR PUSH IY ; CFG ENTRY POINTER POP DE ; COPY TO DE CALL DIO_ADDENT ; ADD ENTRY, BC IS NOT DESTROYED CALL FD_INITUNIT ; DO UNIT INITIALIZATION LD BC,FD_CFGSIZ ; SIZE OF CFG ENTRY ADD IY,BC ; BUMP IY TO NEXT ENTRY POP BC ; RESTORE BC DJNZ FD_INIT0 ; LOOP AS NEEDED ; LD A,FDTRACE LD (FCD_TRACE),A ; LD BC,0 LD (FCD_IDLECNT),BC ; LD A,DOR_INIT LD (FST_DOR),A ; CALL FC_RESETFDC CALL FD_CLRDSKCHG ; LD A,TRUE LD (FCD_FDCRDY),A ; RET ; ; HARDWARE PRESENCE DETECTION ; ; CURRENTLY JUST DETERMINES IF FDC EXISTS AT PRE-DEFINED ADDRESS, ; DOES NOT ATTEMPT TO DETERMINE THE ACTUAL VARIANT. ; FD_DETECT: ; BLINDLY RESET FDC (WHICH MAY OR MAY NOT EXIST) LD A,DOR_INIT ; MAKE SURE INITIAL DOR VALUE IS SETUP LD (FST_DOR),A ; AND PUT IN SHADOW REGISTER CALL FC_RESETFDC ; RESET FDC IN A,(FDC_MSR) ; READ MSR ;CALL PC_SPACE ; *DEBUG* ;CALL PRTHEXBYTE ; *DEBUG* CP $80 JR Z,FD_DETECT1 ; $80 IS OK CP $D0 JR Z,FD_DETECT1 ; $D0 IS OK RET ; NOPE, ABORT WITH ZF=NZ ; FD_DETECT1: CALL DLY32 ; WAIT A BIT FOR FDC IN A,(FDC_MSR) ; READ MSR AGAIN ;CALL PC_SPACE ; *DEBUG* ;CALL PRTHEXBYTE ; *DEBUG* CP $80 RET ; $80 OK, ELSE NOT PRESENT ; ; UNIT INITIALIZATION ; FD_INITUNIT: LD (IY+FD_STAT),0 ; CLEAR STATUS LD (IY+FD_MEDTYP),FDMEDIA ; SET DEFAULT MEDIA TYPE LD (IY+FD_CURTRK),$FE ; SPECIAL VALUE FOR CURTRK RET ; ; FD_IDLE QUIESCES THE FLOPPY SUBSYSTEM (MOTOR OFF) ; AFTER BEING CALLED ENOUGH TIMES... ; SHOULD IT INVALIDATE THE BUFFER??? ; FD_IDLE: LD BC,(FCD_IDLECNT) LD A,B OR C RET Z ; COUNTER ALREADY FIRED DEC BC ; DECREMENT COUNTER LD (FCD_IDLECNT),BC ; SAVE IT LD A,B OR C RET NZ ; STILL COUNTING DOWN, RETURN CALL FC_MOTOROFF ; COUNTER JUST EXPIRED, SHUTDOWN MOTOR! RET ; ; FD_STATUS ; FD_STATUS: LD A,(IY+FD_CURTRK) ; A = CURRENT TRACK CP 0FFH ; IS CURRENT TRACK = $FF? JR Z,FD_STATUS1 ; IF SO, NOT READY XOR A ; A = 0 = OK RET ; RETURN FD_STATUS1: OR A ; A ALREADY = $FF, JUST SET FLAGS RET ; ; ; FD_RESET: XOR A ; ALWAYS OK RET ; ; FD_CLRDSKCHG ; FD_CLRDSKCHG: ; PROCESS ANY PENDING DISK CHANGE NOTIFICATIONS LD B,5 FD_CLRDSKCHG1: PUSH BC CALL FC_SENSEINT POP BC LD A,(FST_RC) CP FRC_DSKCHG RET NZ ; NO MORE DISK CHANGE NOTIFICATIONS DJNZ FD_CLRDSKCHG1 ; ; FD_WTSEEK ; ; WAIT FOR PENDING SEEK OPERATION TO COMPLETE BY POLLING SENSEINT ; AND WAITING FOR ABTERM OR OK. ; FD_WTSEEK: LD BC,1000H FD_WTSEEKLOOP: PUSH BC CALL FC_SENSEINT POP BC LD A,(FST_RC) ; CHECK RC CP FRC_ABTERM ; ABTERM = DONE/FAILED JR Z,FD_RETRC CP FRC_OK ; OK = DONE/SUCCESS JR Z,FD_RETRC DEC BC ; CHECK LOOP COUNTER IN BC LD A,B ; " OR C ; " JR NZ,FD_WTSEEKLOOP ; LOOP UNTIL COUNTER EXHAUSTED FD_RETRC: LD A,(FST_RC) OR A RET ; TIMEOUT/FAILED ; ; FD_FDCRESET ; FD_FDCRESET: CALL FC_RESETFDC CALL FD_CLRDSKCHG LD A,TRUE LD (FCD_FDCRDY),A ; MARK ALL DRIVES AS NEEDING RECALIBRATION ; NOTE THAT IF THE VALUE IS CURRENTLY $FF, ; WE NEED TO LEAVE IT ALONE, SO WE 'OR' IN THE ; $FE TO AVOID THIS SCENARIO. PUSH IY ; SAVE CURRENT IY LD B,FD_DEVCNT ; LOOP CONTROL LD DE,FD_CFGSIZ ; SIZE OF CFG ENTRY LD IY,FD_CFGTBL ; START OF CFG TABLE FD_FDCRESET1: LD A,(IY+FD_CURTRK) ; GET CURRENT TRACK OR $FE ; APPLY NEW VALUE LD (IY+FD_CURTRK),A ; UPDATE TRACK ADD IY,DE ; BUMP IY TO NEXT ENTRY DJNZ FD_FDCRESET1 ; LOOP AS NEEDED POP IY ; RESTORE IY RET ; ; FD_DRIVERESET ; ; ATTEMPT TO FULLY RESET FLOPPY DRIVE, PRIMARILY RECALIBRATE ; FD_DRIVERESET: CALL FC_SPECIFY RET NZ ; ERROR, BAIL OUT CALL FC_RECAL RET NZ ; ERROR, BAIL OUT ; FIRST RECAL MAY FAIL TO REACH TRACK 0 ; SO WE TRY ONCE MORE IN CASE OF A FAILURE CALL FD_WTSEEK RET Z ; SECOND TRY, ONLY IF NEEDED CALL FC_RECAL RET NZ ; ERROR, BAIL OUT CALL FD_WTSEEK RET ; ; ; FD_SEEK: ; DE:HL CONTAINS EITHER LBA OR CHS BIT 7,D ; TEST LBA BIT JR Z,FD_SEEK9 ; IF NOT LBA, JUST SAVE INCOMING VALUE ; NEED TO CONVERT LBA IN DE:HL TO CHS ; NOTE: FLOPPY LBA WILL NEVER EXCEED 16 BITS, SO WE IGNORE DE ENTIRELY PUSH HL ; SAVE HL CALL FD_GEOM ; E := SPT, D := HDS POP HL ; RESTORE HL RET NZ ; BAIL OUT ON ERROR RES 7,D ; MAKE SURE LBA BIT IS CLEARED LD (FD_CURGEOM),DE ; SAVE AS FD_CURSPT & FD_CURHDS LD A,(FD_CURSPT) ; A := SECTORS PER TRACK LD D,0 ; DE := SPT LD E,A CALL DIV16 ; DIVIDE, REMAINDER (SECTOR #) IN HL PUSH HL ; SAVE SECTOR # PUSH BC ; CYLINDERS AND HEADS BACK TO HL POP HL LD A,(FD_CURHDS) ; A := HEADS PER CYLINDER LD D,0 ; DE : = HEADS PER CYLINDER LD E,A CALL DIV16 ; DIVIDE, BC := TRACK, REMAINDER (HEAD #) IN HL PUSH HL ; SAVE HEAD # PUSH BC ; COPY TRACK # TO HL POP HL POP BC ; RECOVER HEAD # LD D,C ; HEAD # TO D POP BC ; RECOVER SECTOR # LD E,C ; SECTOR # TO E FD_SEEK9: ; NOT LBA, JUST SAVE THE CHS VALUE IN CFG ENTRY PUSH HL ; SAVE INCOMING HL TO (SP) LD A,FD_HST ; A := HST OFFSET IN CFG ENTRY CALL LDHLIYA ; HL := HST VALUE ADR EX (SP),HL ; RESTORE INCOMING HL, HST ADR TO (SP) POP BC ; HST ADR TO BC CALL ST32 ; SAVE HST IN CFG ENTRY XOR A ; SIGNAL SUCCESS RET ; FD_READ: CALL HB_DSKREAD ; HOOK HBIOS DISK READ SUPERVISOR LD (FD_DSKBUF),HL ; SAVE DISK BUFFER ADDRESS LD A,DOP_READ JR FD_RW ; FD_WRITE: CALL HB_DSKWRITE ; HOOK HBIOS DISK WRITE SUPERVISOR LD (FD_DSKBUF),HL ; SAVE DISK BUFFER ADDRESS LD A,DOP_WRITE JR FD_RW ; FD_RW: LD (FCD_DOP),A ; SAVE REQUESTED DISK OPERATION LD A,E ; BLOCK COUNT TO A OR A ; SET FLAGS RET Z ; ZERO SECTOR I/O, RETURN W/ E=0 & A=0 LD B,A ; INIT SECTOR DOWNCOUNTER LD C,0 ; INIT SECTOR READ/WRITE COUNT PUSH BC ; SAVE COUNTERS CALL FD_GEOM ; E := SPT, D := HDS POP BC ; RESTORE COUNTERS JR NZ,FD_RW4 ; BAIL OUT ON ERROR RES 7,D ; MAKE SURE LBA BIT IS CLEARED LD (FD_CURGEOM),DE ; SAVE AS FD_CURSPT & FD_CURHDS FD_RW1: PUSH BC ; SAVE COUNTERS CALL FD_RUN ; PERFORM SECTOR READ/WRITE JR NZ,FD_RW3 ; IF ERROR, SKIP INCREMENT ; INCREMENT SECTOR AND CHECK FOR TRACK OVERFLOW LD A,FD_HSTSEC ; HST SECTOR OFFSET IN CFG CALL LDHLIYA ; HL := ADR OF HST SECTOR INC (HL) ; INCREMENT SECTOR LD A,(FD_CURSPT) ; A := SECTORS PER TRACK CP (HL) ; COMPARE SPT TO CURRENT SECTOR JR NZ,FD_RW2 ; IF NO OVERFLOW, DONE ; RESET SECTOR, INCREMENT HEAD, AND CHECK FOR CYLINDER OVERFLOW LD (HL),0 ; RESET SECTOR TO ZERO INC HL ; POINT TO HST HEAD INC (HL) ; INCREMENT HEAD LD A,(FD_CURHDS) ; A : = HEADS CP (HL) ; COMPARE HEADS TO HST HEAD JR NZ,FD_RW2 ; IF NO OVERFLOW, DONE ; RESET HEAD AND INCREMENT TRACK LD (HL),0 ; RESET HEAD TO ZERO DEC HL ; POINT TO HST TRACK DEC HL ; ... DEC HL ; ... INC (HL) ; INCREMENT HST TRACK LSB FD_RW2: LD HL,FD_DSKBUF+1 ; POINT TO MSB OF BUFFER ADR INC (HL) ; BUMP DMA BY INC (HL) ; ... 512 BYTES XOR A ; SIGNAL SUCCESS FD_RW3: POP BC ; RECOVER COUNTERS JR NZ,FD_RW4 ; IF ERROR, BAIL OUT INC C ; BUMP COUNT OF SECTORS READ DJNZ FD_RW1 ; LOOP AS NEEDED FD_RW4: LD E,C ; SECTOR READ COUNT TO E LD HL,(FD_DSKBUF) ; CURRENT DMA TO HL OR A ; SET FLAGS BASED ON RETURN CODE RET ; AND RETURN, A HAS RETURN CODE ; FD_RUN: ; UPDATE DRIVE SELECTION LD A,(IY+FD_DEV) ; GET UNIT LD (FCD_DS),A ; UPDATE FCD_DS TO NEW VALUE ; MAP HSTTRK TO FCD_H, FCD_C LD A,(IY+FD_HSTTRK) ; GET TRACK VALUE (CYLINDER IS MORE ACCURATE) LD (FCD_C),A ; ... AND MOVE IT TO CYL PARM LD A,(IY+FD_HSTHD) ; GET HEAD VALUE LD (FCD_H),A ; ... AND MOVE IT TO HEAD PARM ; MAP HSTSEC TO FCD_R LD A,(IY+FD_HSTSEC) INC A ; SWITCH FROM ZERO BASED TO ONE BASED LD (FCD_R),A ; SET RETRY COUNTER LD B,5 FD_RETRY: PUSH BC CALL FD_START POP BC LD A,(FST_RC) ; CHECK RESULT OR A RET Z ; SUCCESS DJNZ FD_RETRY ; RETRY TILL COUNTER EXHAUSTED #IF (FDTRACE == 1) CALL FC_PRTRESULTS #ENDIF ; RETURN APPROPRIATE HBIOS ERROR LD A,(FST_RC) CP FRC_NOTWRIT LD A,ERR_READONLY ; ASSUME WRITE PROTECTED ERROR JR Z,FD_RETRY1 LD A,ERR_IO ; OTHERWISE I/O ERROR FD_RETRY1: OR A ; SET FLAGS RET ; AND GIVE UP ; ; ; FD_START: ; #IF (DSKYENABLE) LD A,4 CALL LDHLIYA CALL HB_DSKACTCHS ; SHOW ACTIVITY #ENDIF ; LD A,(FCD_FDCRDY) CP TRUE CALL NZ,FD_FDCRESET ; COPY MEDIA CONFIG INTO FCD ; THIS IS HERE TO ACCOMMODATE DIFFERENT MEDIA ; IN DIFFERENT FLOPPY UNITS. LD A,(IY+FD_MEDTYP) ; A = MEDIA BYTE RLCA ; TABLE IS 4 BYTE ENTRIES RLCA ; A = A * 4 LD HL,FCD_TBL ; HL = START OF TABLE LD D,0 ; SET DE TO TABLE OFFSET LD E,A ADD HL,DE ; OFFSET BASED ON DESIRED MEDIA CALL JPHL ; CALL THE TABLE ENTRY (SEE FCD_TBL) LD DE,FCD ; DE = DESTINATION LD BC,FCD_LEN ; BC = BYTES TO COPY LDIR ; BYTES COPY FROM MDB TO FCD CALL FC_MOTORON ; INCLUDES LATCH SETUP LD A,(IY+FD_CURTRK) CP 0FEH ; FF = DRIVE NEEDS TO BE RESET JR C,FD_RUN0 ; NO RESET NEEDED, BYPASS CALL FD_DRIVERESET JR NZ,FD_RUNERR LD (IY+FD_CURTRK),0 ; ZERO CUR TRACK POS FD_RUN0: ; COMPARE CURRENT TRACK WITH REQUESTED TRACK TO SEE IF SEEK NEEDED LD A,(FCD_C) CP (IY+FD_CURTRK) JR Z,FD_RUN1 ; FDDS_TRKADR == FCD_C, SKIP SEEK ; INITIATE SEEK TO NEW TRACK CALL FC_SEEK JR NZ,FD_RUNERR ; WAIT FOR SEEK TO COMPLETE CALL FD_WTSEEK JR NZ,FD_RUNERR ; RECORD NEW CURRENT TRACK LD A,(FCD_C) LD (IY+FD_CURTRK),A FD_RUN1: ; GET THE REQUESTED OPERATION LD A,(FCD_DOP) ; SETUP RETURN ADDRESS LD HL,FD_RUNCHK PUSH HL ; DISPATCH TO FUNCTION CP DOP_READ JR Z,FC_READ CP DOP_WRITE JR Z,FC_WRITE CP DOP_READID JR Z,FC_READID SYSCHKERR(ERR_NOFUNC) RET FD_RUNCHK: ;;#IF (DSKYENABLE) ;; CALL FD_DSKY ;;#ENDIF FD_RUNEXIT: LD A,(FST_RC) OR A RET Z FD_RUNERR: ; INDICATE THAT A CONTROLLER RESET IS DESIRED LD A,FALSE LD (FCD_FDCRDY),A ; FLAG DRIVE IN ERROR STATUS BY SETTING TRKADR == FF LD (IY+FD_CURTRK),$FF JP FD_RETRC ;;#IF (DSKYENABLE) ;;FD_DSKY: ;; LD HL,DSKY_HEXBUF ;; LD A,(FCD_C) ;; LD (HL),A ;; INC HL ;; LD A,(FCD_R) ;; LD (HL),A ;; INC HL ;; LD A,(FRB_ST0) ;; LD (HL),A ;; INC HL ;; LD A,(FRB_ST1) ;; LD (HL),A ;; CALL DSKY_HEXOUT ;; RET ;;#ENDIF ; ;=============================================================================== ; FLOPPY DISK CONTROL SERVICES (PHYSICAL DEVICE CONTROL FOR FDC HARDWARE) ;=============================================================================== ; ; ENTRY POINTS FOR FDC COMMANDS ; FC_READ: LD A,CFD_READ | 11100000B CALL FC_SETUPIO JP FOP FC_WRITE: LD A,CFD_WRITE | 11000000B CALL FC_SETUPIO JP FOP FC_READID: LD A,CFD_READID | 01000000B CALL FC_SETUPCMD JP FOP FC_RECAL: LD A,CFD_RECAL | 00000000B CALL FC_SETUPCMD JP FOP ; FIX: DO WE NEED TO REMOVE HDS BITS FROM SECOND BYTE? FC_SENSEINT: LD A,CFD_SENSEINT | 00000000B CALL FC_SETUPCMD LD A,1 ; GENERIC COMMAND, BUT JUST FIRST COMMAND CODE LD (FCP_LEN),A JP FOP FC_SPECIFY: LD A,CFD_SPECIFY | 00000000B CALL FC_SETUPSPECIFY JP FOP FC_DRVSTAT: LD A,CFD_DRVSTAT | 00000000B CALL FC_SETUPCMD JP FOP FC_SEEK: LD A,CFD_SEEK | 00000000B CALL FC_SETUPSEEK JP FOP ; ; HELPER FUNCTIONS TO SETUP CMDBUF ; FC_SETUPCMD: ; TRICKY... THE INCOMING BYTE IN A MUST CONTAIN THE COMMAND CODE ITSELF ; IN THE LOW 5 BITS PLUS IT MUST SET WHICH OF THE DESIRED BITS IT WANTS ; IN THE HIGH 3 BITS. WE 'AND' THIS WITH THE TEMPATE BITS TO PRODUCE ; THE CORRECT FINAL COMMAND BYTE LD DE,FCP_BUF AND 5FH ; MT=0, MFM=1, SK=0, CMD=11111 LD (DE),A ; SAVE THE BYTE AND 00011111B ; ISOLATE JUST THE COMMAND BITS LD (FCP_CMD),A ; SAVE IT FOR LATER INC DE LD A,(FCD_H) ; START WITH HDS AND 01H ; MASK TO REMOVE IRRELEVANT BITS FOR SAFETY RLCA ; MAKE ROOM FOR DS BITS RLCA ; LD B,A ; SAVE WHAT WE HAVE SO FAR IN B LD A,(FCD_DS) ; GET DS VALUE AND 03H ; MASK TO REMOVE IRRELEVANT BITS FOR SAFETY OR B ; COMBINE WITH SAVED LD (DE),A ; SAVE THE BYTE INC DE LD A,2 ; LENGTH IS 2 BYTES AT THIS POINT LD (FCP_LEN),A RET FC_SETUPIO: CALL FC_SETUPCMD LD A,(FCD_C) LD (DE),A INC DE LD A,(FCD_H) LD (DE),A INC DE LD A,(FCD_R) LD (DE),A INC DE LD A,FCD_N LD (DE),A INC DE LD A,(FCD_EOT) LD (DE),A INC DE LD A,(FCD_GPL) LD (DE),A INC DE LD A,FCD_DTL LD (DE),A INC DE LD A,9 LD (FCP_LEN),A RET FC_SETUPSEEK: CALL FC_SETUPCMD ; START WITH GENERIC IO CMD LD A,(FCD_C) LD (DE),A INC DE LD A,3 LD (FCP_LEN),A RET FC_SETUPSPECIFY: CALL FC_SETUPCMD DEC DE ; BACKUP 1 BYTE, WE ONLY WANT FIRST BYTE LD A,(FCD_SRTHUT) LD (DE),A ; SAVE THE BYTE INC DE LD A,(FCD_HLTND) LD (DE),A ; SAVE THE BYTE INC DE LD A,3 LD (FCP_LEN),A RET ; ; SET FST_DOR ; FC_SETDOR: LD (FST_DOR),A OUT (FDC_DOR),A #IF (FDTRACE >= 3) CALL NEWLINE LD DE,FDSTR_DOR CALL WRITESTR LD DE,FDSTR_ARROW CALL WRITESTR CALL PC_SPACE LD A,(FST_DOR) CALL PRTHEXBYTE #ENDIF RET ; ; SET FST_DCR ; #IF ((FDMODE == FDMODE_DIDE) | (FDMODE == FDMODE_N8) | (FDMODE == FDMODE_ZETA2) | (FDMODE == FDMODE_RCWDC) | (FDMODE == FDMODE_DYNO) | (FDMODE == FDMODE_EPFDC) | (FDMODE == FDMODE_MBC)) ; FC_SETDCR LD (FST_DCR),A OUT (FDC_DCR),A #IF (FDTRACE >= 3) CALL NEWLINE LD DE,FDSTR_DCR CALL WRITESTR LD DE,FDSTR_ARROW CALL WRITESTR CALL PC_SPACE LD A,(FST_DCR) CALL PRTHEXBYTE #ENDIF RET ; #ENDIF ; ; RESET FDC BY PULSING BIT 7 OF LATCH LOW ; FC_RESETFDC: #IF (FDTRACE >= 3) LD DE,FDSTR_RESETFDC CALL WRITESTR #ENDIF LD A,(FST_DOR) PUSH AF #IF ((FDMODE == FDMODE_ZETA) | (FDMODE == FDMODE_DIO3) | (FDMODE == FDMODE_RCSMC)) RES 7,A #ENDIF #IF ((FDMODE == FDMODE_DIDE) | (FDMODE == FDMODE_N8) | (FDMODE == FDMODE_ZETA2) | (FDMODE == FDMODE_RCWDC) | (FDMODE == FDMODE_DYNO) | (FDMODE == FDMODE_EPFDC) | (FDMODE == FDMODE_MBC)) LD A,0 #ENDIF CALL FC_SETDOR CALL DELAY POP AF CALL FC_SETDOR LD DE,150 ; DELAY: 16us * 150 = 2.4ms CALL VDELAY RET ; ; PULSE TERMCT TO TERMINATE ANY ACTIVE EXECUTION PHASE ; FC_PULSETC: #IF ((FDMODE == FDMODE_DIDE) | (FDMODE == FDMODE_N8) | (FDMODE == FDMODE_ZETA2) | (FDMODE == FDMODE_RCWDC) | (FDMODE == FDMODE_DYNO) | (FDMODE == FDMODE_EPFDC) | (FDMODE == FDMODE_MBC)) IN A,(FDC_TC) #ELSE LD A,(FST_DOR) SET 0,A OUT (FDC_DOR),A RES 0,A OUT (FDC_DOR),A #ENDIF RET ; ; SET FST_DOR FOR MOTOR CONTROL ON ; FC_MOTORON: ; LD BC,300H ; LD BC,50H ; LD (FCD_IDLECNT),BC LD A,(CB_CPUMHZ) RLCA LD (FCD_IDLECNT),A #IF (FDTRACE >= 3) LD DE,FDSTR_MOTON CALL WRITESTR #ENDIF #IF ((FDMODE == FDMODE_DIO) | (FDMODE == FDMODE_ZETA) | (FDMODE == FDMODE_DIO3)) LD A,(FST_DOR) PUSH AF LD A,(FCD_DOR) ; GET NEW LATCH VALUE (W/ MOTOR ON) CALL FC_SETDOR ; AND IMPLEMENT IT POP AF #IF ((FDMODE == FDMODE_ZETA) | (FDMODE == FDMODE_DIO3)) XOR 00000010B ; MOTOR BIT INVERTED ON ZETA #ENDIF BIT 1,A ; SET FLAGS SET BASED ON CURRENT MOTOR BIT RET Z ; MOTOR WAS PREVIOUSLY ON, WE ARE DONE #ENDIF #IF (FDMODE == FDMODE_RCSMC) LD A,(FCD_DS) ; GET DRIVE SELECTED (0 OR 1) LD C,%00000010 ; MASK FOR MOTORA ON (BIT 1 IS MOTORA) OR A ; SET FLAGS BASED ON FCD_DS JR Z,FC_MOTORON1 ; IF FCD_DS == 0, MOTORA IS CORRECT LD C,%00000100 ; ELSE MASK FOR MOTORB ON (BIT 2 IS MOTORB) FC_MOTORON1: LD A,(FST_DOR) ; GET CURRENT DOR VALUE PUSH AF ; SAVE IT LD A,(FCD_DOR) ; GET NEW DOR VALUE (W/O MOTOR BITS SET) OR C ; ADD THE MOTOR BITS CALL FC_SETDOR ; AND IMPLEMENT NEW VALUE POP AF ; RECOVER PREVIOUS DOR VALUE AND %00000110 ; ISOLATE PREVIOUS MOTOR BITS CP C ; COMPARE TO NEW MOTOR BITS RET Z ; SKIP DELAY, MOTOR WAS ALREADY ON #ENDIF #IF ((FDMODE == FDMODE_DIDE) | (FDMODE == FDMODE_N8) | (FDMODE == FDMODE_ZETA2) | (FDMODE == FDMODE_RCWDC) | (FDMODE == FDMODE_DYNO) | (FDMODE == FDMODE_EPFDC) | (FDMODE == FDMODE_MBC)) ; SETUP DCR FOR DIDE HARDWARE LD A,(FCD_DCR) ; GET NEW DCR VALUE CALL FC_SETDCR ; AND IMPLEMENT IT LD HL,FST_DOR ; POINT TO FDC_DOR LD A,(HL) ; START WITH CURRENT DOR PUSH AF AND 11111100B ; GET RID OF ANY ACTIVE DS BITS LD C,A ; SAVE IT FOR NOW LD A,(FCD_DS) ; NOW GET CURRENT DS LD B,A ; PUT IN B FOR LATER OR C ; COMBINE WITH SAVED DOR LD C,A ; RE-SAVE IT INC B ; SET UP B AS LOOP COUNTER (DS + 1) LD A,00001000B ; STARTING BIT PATTERN FOR MOTOR FC_MOTORON1: RLA ; SHIFT LEFT DJNZ FC_MOTORON1 ; DS TIMES OR C ; COMBINE WITH SAVED LD (HL),A ; COMMIT THE NEW VALUE TO FST_DOR CALL FC_SETDOR ; OUTPUT TO CONTROLLER LD C,A POP AF CP C RET Z ; MOTOR WAS PREVIOUSLY ON #ENDIF #IF (FDTRACE >= 3) LD DE,FDSTR_MOTDELAY CALL WRITESTR #ENDIF CALL LDELAY ; DELAY FOR MOTOR SPINUP IF NOT PREVIOUSLY ON RET ; ; SET FST_DOR FOR MOTOR CONTROL OFF ; FC_MOTOROFF: LD A,(FCD_FDCRDY) CP TRUE CALL NZ,FD_FDCRESET LD A,DOR_INIT CALL FC_SETDOR ; OUTPUT TO CONTROLLER #IF (FDTRACE >= 3) LD DE,FDSTR_MOTOFF CALL WRITESTR #ENDIF RET ; ;=============================================================================== ; FDC OPERATIONS ;=============================================================================== ; FOP: ; ; INITIALIZATION ; LD A,0 LD (FRB_LEN),A LD A,FRC_OK LD (FST_RC),A ; ; CLEAR FDC, DISCARD ANY PENDING BYTES (GARBAGE?) ; LD B,0 ; B IS LOOP COUNTER FOP_CLR1: CALL DELAY ; FDC MAY TAKE UP TO 12us TO UPDATE MSR IN A,(FDC_MSR) ; GET STATUS AND 0C0H ; ISOLATE HIGH NIBBLE, RQM/DIO/NDM/CB CP 0C0H ; LOOKING FOR RQM=1, DIO=1, BYTES PENDING JR NZ,FOP_CMD1 ; NO BYTES PENDING, GO TO NEXT PHASE IN A,(FDC_DATA) ; GET THE PENDING BYTE AND DISCARD DJNZ FOP_CLR1 JP FOP_TOFDCRDY ; OTHERWISE, TIMEOUT ; ; SEND COMMAND ; FOP_CMD1: LD HL,FCP_BUF LD A,(FCP_LEN) LD D,A ; D = CMD BYTES TO SEND FOP_CMD2: ; START OF LOOP TO SEND NEXT BYTE LD B,0 ; B IS LOOP COUNTER FOP_CMD4: ; START OF STATUS LOOP, WAIT FOR FDC TO BE READY FOR BYTE CALL DELAY ; FDC MAY TAKE UP TO 12us TO UPDATE MSR IN A,(FDC_MSR) ; READ MAIN STATUS REGISTER AND 0C0H ; ISOLATE RQM/DIO CP 080H ; LOOKING FOR RQM=1, DIO=0 (FDC READY FOR A BYTE) JR Z,FOP_CMD6 ; GOOD, GO TO SEND BYTE CP 0C0H ; HMMMM... RQM=1 & DIO=1, FDC WANTS TO SEND US DATA, UNEXPECTED JP Z,FOP_RES ; GO IMMEDIATELY TO RESULTS??? DJNZ FOP_CMD4 ; LOOP TILL COUNTER EXHAUSTED JP FOP_TOSNDCMD ; COUNTER EXHAUSTED, TIMEOUT / EXIT FOP_CMD6: ; SEND NEXT BYTE LD A,(HL) ; POINT TO NEXT BYTE TO SEND OUT (FDC_DATA),A ; PUSH IT TO FDC INC HL ; INCREMENT POINTER FOR NEXT TIME DEC D ; DECREMENT NUM BYTES LEFT TO SEND JR NZ,FOP_CMD2 ; DO NEXT BYTE ; ; EXECUTION PHASE ; FOP_X1: LD A,(FCP_CMD) CP CFD_READ JR Z,FXR_READ CP CFD_WRITE JR Z,FXR_WRITE CP CFD_READID JR Z,FXR_NULL JP FOP_RES ;; ;; EXECUTION ROUTINES ;; ; ; NULL EXECUTION, NO DATA TO READ/WRITE (USED BY SPECIFY, READID, ETC.) ; ; DO NOTHING, BUT WAIT FOR EXEC B IT TO CLEAR FDC READY. ; LOOP NEEDS TO ALLOW FOR 2 FULL ROTATIONS OF THE DISK ; WHICH IS 400ms AT 300RPM ; FXR_NULL: LD BC,$7000 ; LOOP COUNTER, $7000 * 16us = ~485ms FXR_NULL1: CALL DELAY ; FDC MAY TAKE UP TO 12us TO UPDATE MSR IN A,(FDC_MSR) ; GET MSR AND 0E0H ; ISOLATE RQM/DIO/NDM CP 0C0H ; WE WANT RQM=1,DIO=1,NDM=0 (READY TO READ A BYTE W/ EXEC INACTIVE) JP Z,FOP_RES ; EXEC DONE, EXIT CLEAN W/O PULSING TC ;JP Z,FXR_NULL2 ; *DEBUG* DEC BC ; DECREMENT COUNTER (16 BIT) LD A,B ; CHECK FOR ZERO OR C ; " JR NZ,FXR_NULL1 ; NOT ZERO YET, KEEP CHECKING JP FOP_TOEXEC ; TIMEOUT EXIT ;FXR_NULL2: ; *DEBUG* ; CALL PRTHEXBYTE ; CALL PRTHEXWORD ; JP FOP_RES ; ; READ DATA ; FXR_READ: HB_DI ; TIME CRITICAL , INTERRUPTS WILL CAUSE I/O ERRS LD HL,(FD_DSKBUF) ; POINT TO SECTOR BUFFER START LD DE,(FCD_SECSZ) ; TIMEOUT COUNTER IS CPU MHZ / 4 (MAKING SURE IT IS AT LEAST 1) ; LD A,(CPUMHZ + 3) / 4 LD A,(CB_CPUMHZ) ; GET CPU SPEED IN MHZ ADD A,3 ; ROUND UP SRL A ; SHIFT RIGHT TWICE ;SRL A ; ... TO DIVIDE BY 4 ;INC A ; MAKE SURE RESULT IS AT LEAST 1 LD (FCD_TO),A ; INIT TIMEOUT COUNTER FXRR1 LD C,0 ; OUTER LOOP TIMEOUT COUNTER FXRR2: LD B,0 ; SETUP FOR 256 ITERATIONS FXRR3: IN A,(FDC_MSR) ; GET MSR CP 0F0H ; WE WANT RQM=1,DIO=1,NDM=1,BUSY=1 (READY TO RECEIVE A BYTE W/ EXEC ACTIVE) JR Z,FXRR4 ; GOT IT, DO BYTE READ DJNZ FXRR3 ; NOT READY, LOOP IF COUNTER NOT ZERO JR FXRR5 ; COUNTER ZERO, GO TO OUTER LOOP LOGIC FXRR4: IN A,(FDC_DATA) ; GET PENDING BYTE LD (HL),A ; STORE IT IN BUFFER INC HL ; INCREMENT THE BUFFER POINTER DEC DE ; DECREMENT BYTE COUNT LD A,D OR E JR NZ,FXRR2 ; IF NOT ZERO, REPEAT LOOP JR FXR_END ; CLEAN EXIT FXRR5: ; OUTER LOOP, REALLY ONLY HAPPENS WHEN WAITING FOR FIRST BYTE OR ABORTED AND 0E0H ; ISOLATE RQM/DIO/NDM CP 0C0H ; IF RQM=1, DIO=1, NDM=0 (EXECUTION ABORTED) JR Z,FXR_ABORT ; BAIL OUT TO ERR ROUTINE, FIX: GO TO SPECIFIC ROUTINE FOR THIS??? DEC C JR NZ,FXRR2 ; IF NOT ZERO, LOOP SOME MORE LD A,(FCD_TO) DEC A LD (FCD_TO),A JR NZ,FXRR1 JR FXR_TO ; OTHERWISE, TIMEOUT ERROR ; ; WRITE DATA ; FXR_WRITE: HB_DI ; TIME CRITICAL , INTERRUPTS WILL CAUSE I/O ERRS LD HL,(FD_DSKBUF) ; POINT TO SECTOR BUFFER START LD DE,(FCD_SECSZ) ; TIMEOUT COUNTER IS CPU MHZ / 4 (MAKING SURE IT IS AT LEAST 1) ; LD A,(CPUMHZ + 3) / 4 LD A,(CB_CPUMHZ) ; GET CPU SPEED IN MHZ ADD A,3 ; ROUND UP SRL A ; SHIFT RIGHT TWICE ;SRL A ; ... TO DIVIDE BY 4 ;INC A ; MAKE SURE RESULT IS AT LEAST 1 LD (FCD_TO),A FXRW1 LD C,0 ; OUTER LOOP TIMEOUT COUNTER FXRW2: LD B,0 ; SETUP FOR 256 ITERATIONS FXRW3: IN A,(FDC_MSR) ; GET MSR CP 0B0H ; WE WANT RQM=1,DIO=0,NDM=1,BUSY=1 (READY TO SEND A BYTE W/ EXEC ACTIVE) JR Z,FXRW4 ; GOT IT, DO BYTE WRITE DJNZ FXRW3 ; NOT READY, LOOP IF COUNTER NOT ZERO JR FXRW5 ; COUNTER ZERO, GO TO OUTER LOOP LOGIC FXRW4: LD A,(HL) ; GET NEXT BYTE TO WRITE OUT (FDC_DATA),A ; WRITE IT INC HL ; INCREMENT THE BUFFER POINTER DEC DE ; DECREMENT LOOP COUNTER LD A,D OR E JR NZ,FXRW2 ; IF NOT ZERO, REPEAT LOOP JR FXR_END ; CLEAN EXIT FXRW5: ; OUTER LOOP, REALLY ONLY HAPPENS WHEN WAITING FOR FIRST BYTE OR ABORTED AND 0E0H ; ISOLATE RQM/DIO/NDM CP 0C0H ; IF RQM=1, DIO=1, NDM=0 (EXECUTION ABORTED) JR Z,FXR_ABORT ; BAIL OUT TO ERR ROUTINE DEC C JR NZ,FXRW2 ; IF NOT ZERO, LOOP SOME MORE LD A,(FCD_TO) DEC A LD (FCD_TO),A JR NZ,FXRW1 JR FXR_TO ; OTHERWISE, TIMEOUT ERROR ; ; COMMON COMPLETION CODE FOR ALL EXECUTION ROUTINES ; FXR_TO: ; TIMEOUT HB_EI ; INTERRUPTS OK AGAIN JP FOP_TOEXEC ; EXEC TIMEOUT ; FXR_ABORT: ; EXECUTION ABORTED HB_EI ; INTERRUPTS OK AGAIN JR FOP_RES ; GET RSEULTS, NO NEED TO PULSE TC ; FXR_END: ; EXECUTION COMPLETED NORMALLY CALL FC_PULSETC ; PULSE TC TO END EXECUTION HB_EI ; INTERRUPTS OK AGAIN JR FOP_RES ; GET RSEULTS ; ; RESULTS PHASE ; FOP_RES: LD HL,FRB ; POINT TO RECEIVE BUFFER FOP_RES0: LD BC,$7000 ; LOOP COUNTER, $7000 * 16us = ~458ms FOP_RES1: CALL DELAY ; FDC MAY TAKE UP TO 12us TO UPDATE MSR IN A,(FDC_MSR) ; READ MAIN STATUS REGISTER AND 0F0H ; ISOLATE RQM/DIO/EXEC/BUSY CP 0D0H ; LOOKING FOR RQM/DIO/BUSY JR Z,FOP_RES2 ; GOOD, GO TO RECEIVE BYTE CP 080H ; CHECK FOR RQM=1, DIO=0 (NOTHING LEFT) JR Z,FOP_EVAL ; IF NOTHING LEFT, ALL DONE, GO TO EOD/EXIT DEC BC ; DECREMENT COUNTER (16 BIT) LD A,B ; CHECK FOR ZERO OR C ; "" JR NZ,FOP_RES1 ; LOOP TILL COUNTER EXHAUSTED ;IN A,(FDC_MSR) ; *DEBUG* ;CALL PRTHEXBYTE ; *DEBUG* JR FOP_TOGETRES ; OTHERWISE TIMEOUT ERROR FOP_RES2: ; PROCESS NEXT PENDING BYTE LD A,FRB_SIZ ; GET BUF SIZE CP D ; REACHED MAX? JR Z,FOP_BUFMAX ; HANDLE BUF MAX/EXIT IN A,(FDC_DATA) ; GET THE BYTE LD (HL),A ; SAVE VALUE INC HL ; INCREMENT BUF POS INC D ; INCREMENT BYTES RECEIVED PUSH HL LD HL,FRB_LEN ; POINT TO BUFFER LENGTH LD (HL),D ; UPDATE NUMBER OF BYTES RECEIVED POP HL JR FOP_RES0 ; CONTINUE READ LOOP ; ; EXIT POINTS ; FOP_NOTIMPL: LD A,FRC_NOTIMPL JR FOP_ERR FOP_CMDERR: LD A,FRC_CMDERR JR FOP_ERR FOP_ERROR: LD A,FRC_ERROR JR FOP_ERR FOP_ABORT: LD A,FRC_ABORT JR FOP_ERR FOP_BUFMAX: LD A,FRC_BUFMAX JR FOP_ERR FOP_TOFDCRDY: LD A,FRC_TOFDCRDY JR FOP_ERR FOP_TOSNDCMD: LD A,FRC_TOSNDCMD JR FOP_ERR FOP_TOGETRES: LD A,FRC_TOGETRES JR FOP_ERR FOP_TOEXEC: LD A,FRC_TOEXEC JR FOP_ERR FOP_ERR: LD (FST_RC),A FOP_EVAL: LD A,(FCP_CMD) ; DRVSTAT IS WEIRD, HAS ONLY ST3, NOTHING TO EVAL CP CFD_DRVSTAT JR Z,FOP_EXIT ; DO WE HAVE ST0? LD A,(FRB_LEN) CP 1 JP M,FOP_EXIT FOP_EVALST0: LD A,(FRB_ST0) AND 11000000B CP 01000000B ; ABTERM JR Z,FOP_ABTERM CP 10000000B ; INVCMD JR Z,FOP_INVCMD CP 11000000B ; DSKCHG JR Z,FOP_DSKCHG JR FOP_EXIT FOP_ABTERM: ; SENSEINT DOES NOT USE ST1 LD A,(FCP_CMD) CP CFD_SENSEINT JR Z,FOP_ABTERM1 ; DO WE HAVE ST1? LD A,(FRB_LEN) CP 2 JP M,FOP_ABTERM1 JR FOP_EVALST1 FOP_ABTERM1: ; NO FURTHER DATA, SET FST TO ABTERM LD C,FRC_ABTERM JR FOP_SETFST FOP_INVCMD: LD C,FRC_INVCMD JR FOP_SETFST FOP_DSKCHG: LD C,FRC_DSKCHG JR FOP_SETFST FOP_EVALST1: LD A,(FRB_ST1) LD C,FRC_ENDCYL BIT 7,A JR NZ,FOP_SETFST LD C,FRC_DATAERR BIT 5,A JR NZ,FOP_SETFST LD C,FRC_OVERRUN BIT 4,A JR NZ,FOP_SETFST LD C,FRC_NODATA BIT 2,A JR NZ,FOP_SETFST LD C,FRC_NOTWRIT BIT 1,A JR NZ,FOP_SETFST LD C,FRC_MISADR BIT 0,A JR NZ,FOP_SETFST JR FOP_EXIT FOP_SETFST: LD A,C LD (FST_RC),A FOP_EXIT: #IF (FDTRACE >= 2) CALL FC_PRTRESULTS #ENDIF JP FD_RETRC #IF (FDTRACE > 0) ; ;=============================================================================== ; COMMAND PROCESSING STATUS DISPLAY ;=============================================================================== ; ; PRINT STATUS ; FC_PRTFST: PUSH AF PUSH BC PUSH DE PUSH HL LD A,(FST_RC) ; A GETS FST_RC LD B,FSST_COUNT ; B GETS TABLE ENTRY COUNT LD HL,FSST LD DE,FSST_ENTSIZ ; TABLE ENTRY LENGTH FC_PRTFST0: ; START OF LOOP LD C,(HL) CP C JR Z,FC_PRTFST1 ; FOUND CODE ADD HL,DE ; POINT TO NEXT ENTRY DJNZ FC_PRTFST0 ; CHECK NEXT ENTRY TILL COUNT IS ZERO ; NO MATCHING ENTRY, PRINT THE HEX VALUE CALL PC_SPACE CALL PC_LBKT CALL PRTHEXBYTE CALL PC_RBKT JR FC_PRTFSTX FC_PRTFST1: ; ENTRY FOUND, PRINT IT CALL PC_SPACE INC HL LD E,(HL) INC HL LD D,(HL) CALL PC_LBKT CALL WRITESTR CALL PC_RBKT FC_PRTFSTX: POP HL POP DE POP BC POP AF RET ; ; PRINT COMMAND ; FC_PRTCMD: PUSH AF PUSH BC PUSH DE PUSH HL LD A,(FCP_CMD) ; A GETS THE COMMAND CODE LD B,FCT_COUNT ; B GETS TABLE ENTRY COUNT LD HL,FCT LD DE,FCT_ENTSIZ ; TABLE ENTRY LENGTH FCPC_LOOP: ; START OF LOOP LD C,(HL) CP C JR Z,FCPC_MATCH ; FOUND CODE ADD HL,DE ; POINT TO NEXT ENTRY DJNZ FCPC_LOOP ; CHECK NEXT ENTRY TILL COUNT IS ZERO ; NO MATCHING ENTRY, PRINT THE HEX VALUE CALL PC_SPACE CALL PC_LBKT CALL PRTHEXBYTE CALL PC_RBKT JR FCPC_EXIT FCPC_MATCH: ; ENTRY FOUND, PRINT IT INC HL LD E,(HL) INC HL LD D,(HL) CALL WRITESTR FCPC_EXIT: POP HL POP DE POP BC POP AF RET ; ; PRINT RESULTS ; FC_PRTRESULTS: ; IF TRACE IS SET, FORCE PRINT RESULTS LD A,(FCD_TRACE) OR A RET Z ; IF TRACE = 0, BE SILENT! CP 3 ; IS TRACE >= 3 ? JR NC,FCPR2 ; YES, SO FORCE PRINT EVERYTHING! ; IF RC=OK, GET OUT, NOTHING TO PRINT LD A,(FST_RC) CP FRC_OK RET Z ; SPECIAL CASE, DON'T PRINT IF SENSEINT & INVCMD/DSK CHG/ABTERM LD A,(FCP_CMD) CP CFD_SENSEINT JR NZ,FCPR2 LD A,(FST_RC) CP FRC_INVCMD JR Z,FCPR_EXIT CP FRC_DSKCHG JR Z,FCPR_EXIT CP FRC_ABTERM JR Z,FCPR_EXIT JR FCPR_EXIT FCPR2: CALL NEWLINE LD DE,FDSTR_FD CALL WRITESTR CALL PC_COLON CALL PC_SPACE CALL FC_PRTCMD LD A,(FCP_LEN) LD DE,FCP_BUF CALL PRTHEXBUF LD DE,FDSTR_ARROW CALL WRITESTR LD A,(FRB_LEN) LD DE,FRB CALL PRTHEXBUF LD A,(FST_RC) CALL FC_PRTFST FCPR_EXIT: RET ; ; STRING CONSTANTS ; FDSTR_ARROW .TEXT " -->$" FDSTR_NORESP .TEXT "DRIVE NOT RESPONDING$" FDSTR_FD .TEXT "FD$" #IF (FDTRACE >= 3) FDSTR_MOTON .TEXT "\r\nMOTOR ON$" FDSTR_MOTOFF .TEXT "\r\nMOTOR OFF$" FDSTR_MOTDELAY .TEXT "\r\nMOTOR DELAY$" FDSTR_DOR .TEXT "DOR$" FDSTR_DCR .TEXT "DCR$" FDSTR_RESETFDC .TEXT "\r\nRESET FDC$" FDSTR_SELECT .TEXT "\r\nSELECT: $" #ENDIF ; (FDTRACE >= 3) #ENDIF ; (FDTRACE > 0) ; ; ;================================================================================================== ; FLOPPY DISK DRIVER - DATA ;================================================================================================== ; ; FDC COMMAND PHASE ; FCP_CMD .DB 000H FCP_LEN .DB 00H FCP_BUF: FCP_CMDX .DB 0 FCP_HDSDS .DB 0 FCP_C .DB 0 FCP_H .DB 0 FCP_R .DB 0 FCP_N .DB 0 FCP_EOT .DB 0 FCP_GPL .DB 0 FCP_DTL .DB 0 FCP_BUFSIZ .EQU $-FCP_BUF ; ; FDC STATUS ; FST_RC .DB 00H FST_DOR .DB 00H FST_DCR .DB 00H ; ; FDC RESULTS BUFFER ; FRB_LEN .DB 00H FRB FRB_ST0 FRB_ST3 .DB 0 FRB_ST1 FRB_PCN .DB 0 FRB_ST2 .DB 0 FRB_C .DB 0 FRB_H .DB 0 FRB_R .DB 0 FRB_N .DB 0 FRB_SIZ .EQU $-FRB ; ; FDC COMMAND DATA ; FCD: ; FLOPPY CONFIGURATION DATA (PUBLIC) MANAGED AS A "BLOCK" FCD_NUMCYL .DB 000H ; NUMBER OF CYLINDERS FCD_NUMHD .DB 000H ; NUMBER OF HEADS FCD_NUMSEC .DB 000H ; NUMBER OF SECTORS FCD_SOT .DB 000H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1) FCD_EOT ; END OF TRACK SECTOR (SAME AS SC SINCE SOT ALWAYS 1) FCD_SC .DB 000H ; SECTOR COUNT FCD_SECSZ .DW 000H ; SECTOR SIZE IN BYTES FCD_GPL .DB 000H ; GAP LENGTH (R/W) FCD_GPLF .DB 000H ; GAP LENGTH (FORMAT) FCD_SRTHUT .DB 000H ; STEP RATE, IBM PS/2 CALLS FOR 3ms, 0DH = 3ms SRT, HEAD UNLOAD TIME FCD_HLTND .DB 000H ; HEAD LOAD TIME, IBM PS/2 CALLS FOR 15ms 08H = 16ms HUT FCD_DOR .DB 000H ; DOR VALUE FCD_DCR .DB 000H ; DCR VALUE FCD_LEN .EQU $ - FCD ; DYNAMICALLY MANAGED (PUBLIC) FCD_DS .DB 001H ; DRIVE SELECT (UNIT NUMBER 0-3) FCD_C .DB 000H ; CYLINDER FCD_H .DB 000H ; HEAD FCD_R .DB 001H ; RECORD FCD_D .DB 0E5H ; DATA FILL BYTE ; STATUS MANAGEMENT FCD_DOP .DB 0FFH ; CURRENT OPERATION (SEE DOP_...) FCD_IDLECNT .DW 0 ; IDLE COUNT FCD_TRACE .DB 0 ; TRACE LEVEL FCD_TO .DB 0 ; TIMEOUT COUNTDOWN TIMER FCD_FDCRDY .DB 0 ; FALSE MEANS FDC RESET NEEDED ; ; GENERAL WORKING STORAGE ; FD_DSKBUF .DW 0 FD_CURGEOM .EQU $ ; TWO BYTES BELOW FD_CURSPT .DB 0 ; CURRENT SECTORS PER TRACK FD_CURHDS .DB 0 ; CURRENT HEADS