page IF HARD ; HDSEL -- Select appropriate hard disk drive. ; HDSEL: CALL HDALT ;Check for alterate sectors mvi a,2 hdsl1: sta rept LDA CIOPB+1 ;Get unit # ORI '0' STA HDRDY1 ANI 3 ;Strip off ascii bias mov b,a MVI A,10h HDSL0: DCR B JM HDSLD RLC JMP HDSL0 HDSLD: MOV B,A ;Save drive select LDA CIOPB+1 ORI H.DVS OUT HDCTL ;Set select register MOV A,B OUÔ HDDATA IN HDCTL ANI 1000_1000b cpi 80h JZ HDSL2 ;If drive ready lda rept dcr a jnz hdsl1 LXI H,HDRDY CALL PRINT LXI B,500 CALL DELAY CALL J.CST ANA A JZ HDSL1 ;If not abort INR A ;A = 0FFh +1 = 0 INR A ;A = 1 RET HDSL2: LDA CIOPB+1 ORI 0000_0100B OUT HDCTL CALL BADMAP MVI A,0ffh RC ;Error in reading bad map. A = 0ffh INR A ;A + 1 = 0 RET HDRDY: DB CR,LF,'Hard disk unit ' HDRDY1: DB 'x not ready!',0 space 4,10 HDITAB: DB 0, 0, 0, 0 ;Set to one once bad map is read ; BADMAP -- Read in bad map first time a drive is selected BADMAP: LHLD CIOPB+1 ;Pick up drive number in (l) MVI H,0 LXI D,HDITAB ;Point to initilized table DAD D MOV A,M ORA A ;Check for one RNZ ;Bad sector map allready read in MVI M,1 ;Set as read in LHLÄ BUFADÒ ;Savå currenô buffeò address PUSH H LHLD CIOPB+4 ;Save all CIOPB locations PUSH H LHLD CIOPB+2 PUSH H LHLD CIOPB+0 PUSH H XCHG LXI H,CIOPB+0 MVI M,H.RED ;Read a sector command XRA A INX H MOV M,D ;Store unit # INX H MOV M,A ;Cylinder 0 INX H MVI M,2 ;Head 2 INX H INR A MOV M,A ;Sector 0 (1) LXI H,HSTBUF ;Set DMA address to internal buffer SHLD BUFADR CALL HDSEEK lxi h,numsec mov b,m push b mvi m,1 CALÌ HDXFER pop b lxi h,numsec mov m,b STC ;Set error flag JNZ BADERR ;Return if error POP H ;Restore info SHLD CIOPB+0 POP H SHLD CIOPB+2 POP H SHLD CIOPB+4 POP H SHLD BUFADR LXI H,HSTBUF ADDLR: MOV A,M ;Get an entry ORA A JZ HDSEL ;This is the return. It will reselect the head CALL ADDTO LXI D,6 ;Skip to next entry DAD D JMP ADDLR BADERR: POP H POP H POP H POP H STC RET ADDTO: PUSH H ;Save address of current bad sector info MOV B,H MOÖ C,L LXI D,HDBAD ;Start of bad map pointer ADDL: LHLD HDPTR ;Pick up current pointer MOV A,L ;Check if at end of table CMP E JNZ MORE MOV A,H CMP D JNZ MORE ;End of table so append LDA CIOPB+1 ;Pick up drive STAX D ;Store in bad map table INX D MVI L,6 ;Move 6 bytes ATL: LDAX B STAX D INX B INX D DCR L JNZ ATL XCHG SHLD HDPTR ;Restore new bad map pointer POÐ H RET MORE: PUSH B ;Save current bad sector PUSH D ;Save bad map pointer XCHG ;Move LDA CIOPB+1 CMP M INX H JNZ MISS MVI E,3 ;Try to match 3 bytes MORAL: LDAX B CMP M JNZ MISS INX B INX H DCR E JNZ MORAL ;Still more to compare XTHL POP D POP B POP H RET ;Current entry allready in bad map MISS: XCHG POP D POP B LXI H,7 ;Length of a bad map entry DAD D XCHG JMP ADDL ; ; HDSEEK -- Seek to specified cylinder. ; ; ENTRY CIOPB+2 = cylinder. HDSEEK: LDA ACTDSK MVI D,0 MOV E,A LXI H,HDCYL DAD D MOV A,M CMP -1 JNZ HDSK3 ;If not forced home hdsk0: IN HDCTL ANI 0000_0001B JZ HDSK3 LDA ACTDSK ORI 4+H.SOU OUT HDCTL if gbc20 MVI B,0 endif if gbc10 mvi b,0 endif if gbc26 mvi b,1 endif HDSK1: IN HDDATA DCR B JNZ HDSK1 HDSK2: IN HDCTL ANI 0000_0100B JNZ HDSK2 if gbc26 jmp hdsk0 endif HDSK3: MOV C,A ;Save current cylinder LDA CIOPB+2 ;Get desired cylinder MOV M,A ;Set current = desired SUB C ;Desired - current STA HDSKFG ;Save flag RZ ;If current cylinder = desired JC HDSK4 ;If outward MOV B,A ;Move number of tracks LDA CIOPB+1 ORI H.SIN OUT HDCTL JMP HDSTEP HDSK4: CMA INR A MOV B,A ;Save track count LDA CIOPB+1 ORI H.SOU ;Direction = outwards OUT HDCTL HDSTEP: IN HDDATA DCR B JNZ HDSTEP ;If not all steps sent RET ; HDXFER -- Transfer data to/from hard disk. ; ; ENTRY CIOPB+0 = command. HDXFER: XRA A STA SECOFF LXI H,0 SHLD SECADD LDA HDSKFG ;Check seek outstanding ORA A JZ HDX2 ;If not seek HDX1: IN HDCTL ANI 0000_0100B JNZ HDX1 if gbc26 lxi b,32 call delay endif HDX2: LDA CIOPB+1 ;Pick up drive MOV C,A INR C ;Inc drive number MVI A,10h HDXSL: DCR C JZ HDXDN RLC JMP HDXSL HDXDN: MOV C,A LDA CIOPB+1 ORI H.DVS OUT HDCTL ;Output to drive select LDA CIOPB+3 ORA C OUT HDDATA ;Select drive, head LXI H,CIOPB+2 MVI A,H.CYL OUT HDCTL MOV A,M ;Cylinder OUT HDDATA INX H MVI A,H.HED OUT HDCTL MOV A,M ;Head OUT HDDATA INX H MVI A,H.SEC OUT HDCTL LDA SECOFF ADD M ;Sector DCR A OUT HDDATA LHLD BUFADR XCHG LHLD SECADD DAD D MVI B,0 JNC HDX3 MVI B,1 HDX3: IN SELCHAN LDA BUFADE ADD B OUT SELCHAN MOV A,H OUT SELCHAN MOV A,L OUT SELCHAN LDA CIOPB+0 MOV B,A CPI H.RED MVI A,80H+SELBYT JZ HDX4 MVI A,SELBYT HDX4: OUT SELCHAN LDA CIOPB+1 ORA B OUT HDCTL HDX5: IN HDCTL ;Get status ANI 1000_0000b JNZ HDX5 ;If transfer not complete IN HDCTL ANI 0101_0000b ;Mask timeout and over run JNZ HDERR lda numsec dcr a rz sta numsec lxi h,secoff inr m lhld secadd lxi d,1024 dad d shld secadd jmp hdx2 HDERR: XRA A ORI 01h RET HDALT: LXI H,HDBAD ;Point to start of bad map ALTLOP: XCHG LHLD HDPTR ;Pick up end of bad map XCHG PUSH H ;Save current bad map pointer MOV A,D ;Check if at end of bad map CMP H JNZ ALMORE ;Still more to check MOV A,E CMP L JNZ ALMORE POP H RET ;All done with check ALTSKP: POP H LXI D,7 ;Size of bad map entry DAD D JMP ALTLOP ALMORE: LXI D,CIOPB+1 ;Pick up current drive LDAX D CMP M ;Check if alternate drive matches JNZ ALTSKP INX H INX D LDAX D ;Pick up alternate cylinder CMP M ;Check for match JNZ ALTSKP INX H INX D LDAX D CMP M ;Check if head matches JNZ ALTSKP INX H INX D LDAX D ;Pick up sector DCR A ;Dec by one. Sector start at zero CMP M JNZ ALTSKP INX H LXI D,CIOPB+2 MOV A,M ;Pick up alternate cyl STAX D INX H INX D MOV A,M ;Pick up alterate head STAX D INX H INX D MOV A,M ;Pick up alterante sector INR A STAX D POP H ;Fix up stack RET ;Return with alternate info rept db 0 HDSKFG: DB 0 SECOFF: DB 0 SECADD: DW 0 .hrd ENDIF