page ; Read a CP/M 128 byte sector. ; ; EXIT A = 0, successful read operation. ; A = 1, unsucessful read operation. ; Z bit = 1, successful read operation. ; Z bit = 0, unsuccessful read operation. READ: CALL CHKBKD ;Check for blocked drive MVI A,F.RDAT ;Read from single density floppy JC FINAL ;If non-blocked transfer XRA A ;Set flag to force a read STA UNACNT ;Clear sector counter CALL FILL ;Fill buffer with data POP H POP D IF C8080 MVI C,128 CALL MOVDTA ;Move 128 bytes endif IF Z80 LXI B,128 ;Move 128 bytes LDIR endif LDA ERFLAG ORA A RZ ;If no error XRA A STA HSTACT ;Clear host active ORI 001h ;Set error flag RET space 4,20 ; Write the selected 128 byte CP/M sector. ; ; ENTRY C = 0, write to a previously allocated block. ; C = 1, write to the directory. ; C = 2, write to the first sector of unallocated ; data block. ; ; EXIT A = 0, write was successful. ; A = 1, write was unsucessful. ; Z bit = 1, write was successful. ; Z bit = 0, write was unsucessful. WRITE: CALL CHKBKD ;Check for blocked drive MVI A,F.WRT ;Write to single density floppy JC FINAL ;If non-blocked transfer MOV A,C ;Write type in c STA WRTYPE CPI WRUAL JNZ WRIT2 ;If write to allocated LDA SEKTYP CPI MAXFTP+1 MVI A,2048/128 JC WRIT1 ;If floppy disk MVI A,4096/128 WRIT1: STA UNACNT LHLD SEKTRK SHLD UNATRK ;UNATRK = SEKTRK LDA LOGSEC INR A JMP WRIT3 WRIT2: LDA UNACNT ORA A JZ WRIT4 ;If no unallocated records DCR A STA UNACNT LDA SEKTYP RAR MOV L,A MVI H,0 LXI D,LSITT-1 DAD D LDA UNASEC ;Increment logical sector INR A CMP M ;Last sector in track table JNZ WRIT3 ;If not end of track LHLD UNATRK INX H SHLD UNATRK XRA A WRIT3: STA UNASEC MVI A,0FFh WRIT4: CALL FILL POP D POP H IF C8080 MVI C,128 CALL MOVDTA ;Move 128 bytes endif IF Z80 LXI B,128 LDIR endif MVI A,1 STA HSTWRT ;HSTWRT = 1 LDA ERFLAG ORA A RNZ ;If any errors occurred LDA WRTYPE ;write type CPI WRDIR ;to directory? CZ FLUSH ;Force write of directory LDA ERFLAG ORA A RET LSITT: DB 2*26 ;Double 256 byte DB 4*15 ;Double 512 byte DB 8*8 ;Double 1024 byte if hard if gbc20 DB 8*11 ;Fujitsu 20 magabyte 1024 byte endif if gbc10 DB 4*11 ;Fujitsu 10 magabyte 1024 byte endif if gbc26 DB 8*18 ;Shugart 26 magabyte 1024 byte endif endif page ; TREAD - Determine floppy disk type. ; ; ENTRY C = Selected drive. ; ; Exit Zbit set = no error ; A = disk type (0-3) TREAD: MOV A,C ADI 'A' STA NRDYM2 ;Set drive into message CALL SPECIFY ;Set disk parameters LXI B,240 ;Delay for selecting sides CALL DELAY LDA SEKDSK ;Move drive to command buffer STA ACTDSK ;Set into ACTDSK LDK HL,DSTS LDK B,DSTSL CALL EXECP ;Perform command LDK B,1 CALL GCMPS ;Get the one status byte ANI 020h ;Mask ready bit JNZ TRD1 ;If drive is ready LDK HL,NRDYM1 CALL PRINT ORI 0FFh ;Clear zero flag RET TRD1: LDA TEMPBF ;Get status byte ANI 008h ;Mask TS bit RRC RRC RRC STA SEKTYP ;Save sided flag LDK HL,RECAL ;Do a test seek LDK B,LRECAL CALL MOVETO ;Process command RNZ ;If error LDK A,2 ;Seek to track two CALL DOSEEK ;Do seek RNZ ;If error LDK A,F.DRID STA DRID TRD2: LDK HL,DRID LDK B,DRIDL LDK C,7 CALL EXECX ;Process command JZ TRD3 ;If read valid LDA DRID XRI 040h ;Compliment MFM bit STA DRID ANI 040h JNZ TRD2 ;If MFM not tried ORI 0FFh RET TRD3: LDA TEMPBF+6 ;Get number of bytes ADD A MOV B,A LDA SEKTYP ORA B ;Combine N with sided flag CMP A ;Set zero flag RET DSTS: DB F.DSTS,0 DSTSL: = *-DSTS RECAL: DB F.RECA,0 LRECAL: = *-RECAL DRID: DB F.DRID,0 DRIDL: = *-DRID NRDYM1: DB CR,LF,'Drive ' NRDYM2: DB 'x' DB ' not ready.',0 page ; FILL - fill host buffer with approprite host sector. ; ; ENTRY A = 0, Read required if not in buffer. ; 0therwise read not required. ; ; EXIT On exit the stack will contain the following ; values: ; POP x ;x = host record address. ; POP y ;y = caller's buffer address. FILL: STA RDFLAG ;Save read flag LDA SEKTYP ;Get disk type CPI MAXFTP+1 JC FILL1 ;If floppy disk mvi a,6 ;2*((log base 2 (1024))-7) (for hard disks) FILL1: RRC ;divide by 2 ANI 3h MOV B,A ;B = log base 2 (sector size) - 7 LXI D,HSTBUF ;initial offset LXI H,128 ;128 byte records LDA SEKSEC ;Get logical sector FILL2: XCHG RRC JNC FILL3 ;If low bit not set DAD D ;Add bias to offset FILL3: XCHG DAD H ANI 07Fh ;Mask sector DCR B JNZ FILL2 ;If not all bits checked STA SEKSEC LHLD DMAADR XTHL ;Set return parameters PUSH D PUSH H ;Set return address LXI H,HSTACT ;host active flag MOV A,M MVI M,1 ;always becomes 1 ORA A JZ FILL6 ;If host buffer inactive LXI H,HSTSEC LXI D,SEKSEC MVI C,SEKTYP-SEKSEC+1 FILL4: LDAX D CMP M JNZ FILL5 ;If mis-match INX H INX D DCR C JNZ FILL4 ;If all bytes not checked RET FILL5: CALL FLUSH ;Flush host buffer FILL6: LHLD SEKDSK ;Move disk and type SHLD HSTDSK SHLD ACTDSK LHLD SEKTRK SHLD HSTTRK SHLD ACTTRK LDA SEKSEC STA HSTSEC STA ACTSEC LDA RDFLAG ORA A RNZ ;If no read required MVI A,F.RDAT+040h ;Read double density JMP BLKXFR space 4,10 ; FLUSH - Write out active host buffer onto disk. FLUSH: LXI H,HSTWRT MOV A,M ORA A RZ ;If host buffer already on disk MVI M,0 LHLD HSTDSK ;Move disk and type SHLD ACTDSK LHLD HSTTRK SHLD ACTTRK LDA HSTSEC STA ACTSEC MVI A,F.WRT+040h ;Write double density ; JMP BLKXFR space 4,10 ; BLKXFR -- blocked mode transfer. ; ; ENTRY A = command. BLKXFR: MOV C,A LXI H,HSTBUF ;Set buffer address SHLD BUFADR LDK A,BXADR STA BUFADE MOV A,C ; JMP FINAL space 4,10 ; F I N A L -- Preform final transfer processing. ; ; ENTRY A = Command. FINAL: CALL PRCDCH ;Process command, drive, cylinder LDK HL,CIOPB+0 ;Set buffer address STO C,[hl] ;Set command INC HL STO B,[hl] ;Set drive INC HL STO E,[hl] ;Set cylinder INC HL STO D,[hl] ;Set head INC HL MOV E,A ;Save N field LDA ACTSEC ;Get sector MOV C,A INR A STO A,[hl] ;Set beginning sector INC HL MOV A,E ;Get type CPI 4 JP HDFNL ;If hard disk STO A,[hl] ;Set N field INC HL ADD A,A ;N*2 ADI low CMDTYP MOV E,A MVI A,0 ACI high CMDTYP MOV D,A LDA NUMSEC ;Compute ending sector number ADD A,C STO A,[hl] ;Set EOT INC HL LD A,[de] STO A,[hl] ;Set GPL field INC DE INC HL LD A,[de] STO A,[hl] ;Set DTL MVI A,MRTRY ;Set retry count FNL1: STA RTRY ;Clear retry count LDA CIOPB+2 ;Get cylinder number CALL DOSEEK ;Seek to proper track JNZ FNL3 ;If seek error LDK HL,BUFADE LDK B,3 FNL2: LD A,[hl] ;get ext adr OUT DMA DEC HL ;data is backward in memory DEC B JNZ FNL2 ;If not all 3 bytes LDK HL,CIOPB LDK B,CIOPL ;Set command buffer length LDK C,7 CALL EXEC ;perform operation CMP 40h JNZ FNL3 ;If error LDA TEMPBF+1 SUI 80h STA ERFLAG RZ ;If no errors FNL3: LDA RTRY ;Get retry counter DCR A JNZ FNL1 ;If not permanent error ORI 01h STA ERFLAG ;Set error flag RET ; HDFNL -- Hard disk final command processing. ; HDFNL: .hrd IF hard CALL HDSEL STA ERFLAG RNZ ;If select error MVI A,MRTRY ;Set retry count HDFNL1: STA RTRY CALL HDSEEK ;Seek to correct track CALL HDXFER ;Perform hard disk transfer STA ERFLAG RZ ;If no errors LDA RTRY DCR A JNZ HDFNL1 ;If attempts left LDA ACTDSK MVI D,0 MOV E,A LXI H,HDCYL DAD D MVI M,-1 ;Force track zero seek .hrd endif XRA A ORI 001h STA ERFLAG RET RTRY: DB 0 MRTRY: EQU 10 ;Maximum retry count ; Command buffer disk type dependent values. CMDTYP: ; GPL DTL DB 007h,128 ;Single density DB 00Eh,255 ;Double density 256 bytes DB 01Bh,255 ;Double density 512 bytes DB 035h,255 ;Double density 1024 bytes space 4,10 ; PRCDCH -- Process Command, Drive, Cylinder, and Head. ; ; ENTRY A = command. ; ; EXIT A = N field (0..4). ; B = drive. ; C = command. ; D = head. ; E = cylinder. PRCDCH: MOV C,A ;Save Command LDA ACTDSK MOV B,A LHLD ACTTRK ;Get track number LDA ACTTYP ;Get type CPI MAXFTP+1 JNC CDCH2 ;If hard disk XCHG MOV H,A ;Save type ANI 1 JZ CDCH1 ;If single sided MOV A,E ANI 1 MOV D,A ;Set head RLC RLC ORA B ;Combine head with drive MOV B,A MOV A,E ;Adjust track for cylinder RAR MOV E,A CDCH1: MOV A,H ANI 0FEh ;Remove sided bit RRC RET CDCH2: .hrd IF hard MOV A,L if gbc20 ANI 7 endif if gbc10 ani 3 endif if gbc26 ani 7 endif MOV D,A ;Save head DAD H ;*2 DAD H ;*4 DAD H ;*8 DAD H ;*16 DAD H ;*32 if gbc10 dad h endif MOV E,H ;track*32/256 = track/8 MOV A,C ANI 00Fh CPI F.RDAT MVI A,(MAXFTP+1)/2 MVI C,H.RED RZ ;If read command MVI C,H.WRT .hrd ENDIF RET space 4,10 ; Seek to specified Track/Sector ; ; Entry A = Track DOSEEK: STO A,DSEKC+2 LDK HL,DSEKC LDK B,DSEKL ; JMP MOVETO ; Move head according to command. ; ; ENTRY HL = address of command buffer. ; B = length of command buffer. ; ; Exit Z bit set if no error. MOVETO: CALL EXECP ;Perform seek MVTO1: IN INTS OR A JP MVTO1 ;if not complete LDK A,F.RSTS OUT FDCD ;request status LDK B,2 CALL GCMPS ;Get status CMP 20h RZ ;If seek complete LDA TEMPBF ;Get true status byte ANI 3h ;Mask disk unit MOV C,A LDA ACTDSK CMP C JNZ MVTO1 ;If not proper unit ORI 001h ;Clear zero flag RET space 4,10 ; SPECIFY - Specify disk drive characteristics. SPECIFY: LDK HL,SPEC+1 LDK B,LSPEC LDK C,0 LDA STEPMS ORI HUT STO A,[hl] DEC HL JMP EXEC ;Specify disk command DSEKC DB F.SEEK,0,0 DSEKL: = *-DSEKC SPEC DB F.SPEC VFD 4\SRT,4\HUT VFD 7\HLT,1\ND LSPEC = *-SPEC page ; E X E C ; Entry HL = FWA of command buffer. ; B = # of bytes to output ; C = # of bytes for status ; ; Exit If C <> 0 then see GCMPS. EXECP: LDK C,0 ;Set no status byte EXECX: INX H LDA ACTDSK ;Set drive into command buffer MOV M,A DCX H EXEC: EXEC1: IN FDCS OR A JP EXEC1 ;if no master ready bit LD A,[hl] ;command byte OUT FDCD ;to controller INC HL DCR B JNZ EXEC1 ;if more bytes MOV A,C ;# of status bytes+1 OR A RZ ;if no status bytes MOV B,C ;# of status bytes EXEC2: IN INTS OR A JP EXEC2 ;If operation not complete space 4,10 ; Get completion status. ; ; Entry B= # of status bytes to read ; ; Exit TEMPBF = status bytes read in. ; A = [TEMPBF] and 0F8h. ; Flags set according to above value in A. GCMPS: LDK HL,TEMPBF ;Set status buffer address GCMPS2: IN FDCS OR A JP GCMPS2 ;if not ready IN FDCD ;Get status byte STO A,[hl] INC HL DEC B ;decrement counter JNZ GCMPS2 ;wait until all done LDA TEMPBF ;Get first status byte ANI 0F8h RET