TITLE 'CPM+ DISK IO MODULE FOR XCOMP HARD DISK CONTROLLER' ; ;This is a self contained module to link in a Xcomp controler to CPM+. It ;is setup for a 10 Mg byte miniscribe at the moment ; ; John Monahan (201) 783 1548 ; ; DEFINE LOGICAL VALUES: TRUE EQU -1 FALSE EQU NOT TRUE ; ; DETERMINE IF BANK SELECTING: BANKED EQU TRUE ;FULL BLOWN VERSION ; ; BELL EQU 07H CR EQU 0DH LF EQU 0AH MAXCYL EQU 500 ;<---WILL ALLOW A MAX OF ONLY 8 MBYTES LZONE EQU 656 ; ; DRIVE COMMANDS ; SKCMD EQU 3 ;SEEK SKOUT EQU 1 ;SEEK OUTWARD NOPC EQU 40H ;NO PRE-COMPENSATION LOWRT EQU 80H ;LOW WRITE CURRENT VSA EQU 8 ;SEEK VERIFY START ADDRESS VCA EQU 1BH ;SEEK VERIFY COMMAND ADDRESS ; ; DRIVE STATUS ; READY EQU 1 ;DRIVE READY WRTFLT EQU 2 ;WRITE FAULT TK00 EQU 4 ;TRACK ZERO RAWINDX EQU 20H ;RAW INDEX ; ; CONTROLLER COMMANDS ; BANK0 EQU 0 ;BANK 0 SELECT BANK1 EQU 1 ;BANK 1 SELECT DBENB EQU 2 ;DATA BUFFER ENABLE CBENB EQU 4 ;COMPARE BUFFER ENABLE START EQU 8 ;START COMMAND ; ; DRIVE/CONTROLLER I/O ; CBASE EQU 70H ;BASE ADR OF THE CONTROLLER DRCSR EQU CBASE ;DRIVE COMMAND/STATUS EXTCMD EQU CBASE+1 ;EXTENDED COMMNAND REGISTER LOSC EQU CBASE+2 ;SEEK COUNT, LSB HISC EQU CBASE+3 ; * MSB CTCSR EQU CBASE+4 ;CONTROLLER COMMAND/STATUS CTBFR EQU CBASE+5 ;CONTROLLER BUFFER ADDRESS CTDP EQU CBASE+6 ;CONTROLLER DATA PORT ; DEFINE PUBLIC LABELS: PUBLIC DPH0 ;DISK PARAMETER HEADERS ; DEFINE EXTERNAL LABELS: EXTRN @ADRV,@RDRV EXTRN @DMA,@TRK,@SECT EXTRN @CBNK EXTRN @DBNK ;BANK FOR DMA OPERATION EXTRN @ERMDE ;BDOS ERROR MODE EXTRN ?WBOOT ;WARM BOOT VECTOR EXTRN ?PMSG ;PRINT MESSAGE @ UP TO 00, SAVES ; [BC] AND [DE] EXTRN ?PDERR ;PRINT BIOS DISK ERROR HEADER EXTRN ?CONIN,?CONO ;CONSOLE IN AND OUT EXTRN ?CONST ;CONSOLE STATUS EXTRN ?BNKSL ;SELECT PROCESSOR MEMORY BANK EXTRN ?SMSG ;MY ROUTINE TO SPEAK A MESSAGE ;YOU CAN REMOVE REFERENCES TO THIS ; INCLUDE CP/M 3.0 DISK DEFINITION MACROS: MACLIB CPM3 ; INCLUDE Z-80 MACRO LIBRARY: MACLIB Z80 IF BANKED DSEG ;PUT IN OP SYS BANK IF BANKING ELSE CSEG ;ELSE KEEP IN COMMON MEMORY ENDIF ; EXTENDED DISK PARAMETER HEADER FOR DRIVE 0: DW HDWRT ;HARD DISK WRITE ROUTINE DW HDRD ;HARD DISK READ ROUTINE DW HDLOGIN ;HARD DISK LOGIN PROCEDURE DW HDINIT ;HARD DISK DRIVE INITIALIZATION ROUTINE DB 0 ;RELATIVE DRIVE 0 ON THIS CONTROLLER DB 0 ;MEDIA TYPE: ; HI BIT SET : DRIVE NEEDS RECALIBRATING DPH0: DPH 0,HD$DPB,0, ; MAKE SURE DPB'S ARE IN COMMON MEMORY: CSEG ; 256 BYTE SECTORS ON HARD DISK HD$DPB: DPB 256,32,1000,2048,1024,2,8000H IF BANKED DSEG ;CAN SET BACK TO BANKED SEGMENT IF BANKING ENDIF ;;;;; HDINIT: HDINIT RET ;DO NOT INITILIZE HARD DISK YET ; ;;;;; HDLOGIN ;------ INITILIZE THE XCOMP HARD DISK CONTROLLER (MUST DOWNLOAD MICROCODE) --- HDLOGIN: CALL XTKZ ;RESTORE JNZ RESERR LXI H,SAYSIGNON CALL ?SMSG ;SPEAK MESSAGE XRA A ;RETURN WITH NO ERROR RET RESERR: LXI H,MSGH2 ;RESTORE FAILED CALL ?PMSG ORI 1 RET ; ;;;;; HDWRT ; ROUTINE WRITES 1 SECTOR TO THE DISK: ; HDWRT: XRA A STA ERFLG CALL GETDMA ;GET DMA ADR, SET POINTERS IF BANKED JMP ADJBNNN CSEG ADJBNNN:LDA @CBNK PUSH PSW LDA @DBNK CALL ?BNKSL OUTIR POP PSW CALL ?BNKSL JMP ADJDDD DSEG ELSE OUTIR ENDIF ADJDDD: CALL XWRT LDA ERFLG RET XWRT: LXI H,WTBL ;GET COMMAND TABLE CALL DORW ;EXICUTE WR/RD COMMANDS JMP XR1 ;;;;; HDRD ; ROUTINE READS 1 PHYSICAL SECTOR FROM THE DRIVE: ; HDRD: XRA A STA ERFLG ;CLEAR THE ERROR FLAG CALL XREAD ;READ A BLOCK CALL GETDMA ;GET DMA ADR, SET POINTERS IF BANKED JMP ADJBNKS CSEG ;MUST HAVE THE FOLLOWING CODE IN COMMON ADJBNKS:LDA @CBNK PUSH PSW LDA @DBNK ;MUST HAVE THIS CODE IN COMMON CALL ?BNKSL ;NOW DMA ADDRESS IS AT THE CORRECT BANK IN CTDP ;PRIME DATA INPUT NOP INIR ;BLOCK INPUT POP PSW CALL ?BNKSL JMP ADJDON DSEG ELSE IN CTDP ;PRIME DATA INPUT NOP INIR ;BLOCK INPUT ENDIF ADJDON: LDA ERFLG ;ERROR FLAG RET ; XREAD: LXI H,RTBL ;SEEK SECTOR COMMAND TABLE IS SENT TO CONTROLLER CALL DORW ;SEND IT XR1: MVI A,0 RZ ;RIF READ/WRITE OK INR A STA ERFLG ;SET ERROR FLAG RET ; DORW: SHLD CTA ;SAVE CMD TBL ADR CALL XSEK ;SEEK TO NEW TRACK (IF REQUIRED) RNZ ;RIF SEEK FAILED CALL XSEL ;HEAD SELECT LHLD CTA ; DO0: MOV A,M STA RETRY ;SET RETRY COUNT INX H MOV A,M OUT CTCSR ;ENB CMP BFR INX H MOV A,M OUT CTBFR ;SET CMP BFR ADR INX H SHLD CTA ;SAVE CMD TBL ADR ; LXI H,RCA ;REAL TK ADR MVI B,3 DO1: MOV A,M OUT CTDP ;PUT HDR INFO INTO CMP BFR INX H DCR B JNZ DO1 LDA @SECT OUT CTDP ;SET SECT ADR FOR COMPARE ; DO2: CALL XRDY ;DRIVE READY ? RNZ ; RIF NO LHLD CTA ;CMD TBL ADR MOV A,M ;A = CNTL BANK INX H MOV B,A OUT CTCSR ;SLCT CNTL BANK MOV A,M OUT CTBFR ;SET START ADR INX H MOV A,B ORI START OUT CTCSR ;START R/W CMD ; DO3: CALL WFD ;WAIT FOR READ/WRITE TO FINISH RC ;ABORT IF TIMEOUT ANA M ;TEST CTLR STATUS (0=OK) MOV B,A IN DRCSR ;DRIVE STATUS ANI WRTFLT CNZ CLRDF ;CIF CLEAR DRIVE FAULT ORA B ;SET/CLEAR ERROR FLAG (0=OK) RZ ;RIF READ/WRITE OK LXI H,RETRY DCR M ;DECR RETRY COUNT JNZ DO2 ;JIF RETRY READ/WRITE ; ; SET ERROR FLAG ; SEF: MVI A,1 ;A = ERROR FLAG ORA A ;SET 8080 FLAGS RET ;TAKE ERROR EXIT ; ; ---WAIT FOR DONE--- ; WFD: PUSH H LXI H,0 ;TIMEOUT DELAY COUNT ; WFD1: IN CTCSR ;CTLR STATUS RRC JC WFD2 ;WAIT FOR DONE DCX H MOV A,H ORA L JNZ WFD1 ; OUT CTCSR POP H MVI A,1 ORA A STC RET ; WFD2: POP H IN CTCSR ;GET NON-CHANGING STATUS MOV B,A XRA A OUT CTCSR ;STOP CTLR MOV A,B RET ; ; SETS THE CONTROLLER BUFFER ADDRESS TO THE CORRECT ; STARTING POINT. ALSO SETS B=256 & H/L=@DMA ; GETDMA: LHLD @DMA MVI C,CTDP ;FOR BLOCK I/O MVI B,0 ;B = COUNT (256 BYTES) MVI A,DBENB OUT CTCSR ;ENB DATA BFR MVI A,0 GET1: OUT CTBFR ;SET CTLR DATA BFR ADR RET ; ; ---REZERO--- ; XTKZ: LXI H,0 SHLD RCA CALL TZT ;TEST IF TRK 0 RZ ; LXI H,511 ;#OF CYLINDERS WE CAN COUNT ON CONTROLLER CALL RTZ ;SEEK OUT RC ;ABORT DRIVE NOT READY RZ ;IS AT 0 LXI H,LZONE+10-511 CALL RTZ ;TRY SECOND PUMP RC RZ JMP SEF ;ABORT RESTORE FAILED ; ; SEEK OUTWARD ; RTZ: CALL XRDY STC RNZ MOV A,L OUT LOSC ;SET LSB OF SEEK COUNT MOV A,H OUT HISC ;SET MSB MVI A,SKOUT OUT EXTCMD ;SET SEEK DIRECTION OUTWARD MVI A,SKCMD OUT DRCSR ;ISSUE SEEK CALL WSC RC ; TZT: IN DRCSR ;GET DRIVE STATUS ANI TK00 XRI TK00 RET ; ; ; ---SEEK--- ; XSEK: MVI A,3 STA SKRTC ;SET SEEK RETRY COUNT ; XSEK1: LHLD @TRK ;REQUESTED TRACK MVI B,1 CALL DRS ;SHIFT H/L RIGHT ONCE LXI D,MAXCYL CALL TSUB RAL JNC SEF ;ABORT IF INVALID ADDRESS XSEK2: XCHG ;[DE] = NEW CYLINDER ADDRESS LHLD RCA ;LOAD UP CURRENT REAL ADR XCHG SHLD RCA ;SAVE NEW ADDRESS XCHG CALL SUBT ;GET DIFFERENCE RZ ;RETURN IF SAME MVI B,1 ;DIR = OUT RAL JNC XSEK3 ;OK SEEK OUTWARD ; MVI B,3 ;SEEK INWARD MOV A,L CMA ;MAKE SEEK POSITIVE MOV L,A MOV A,H CMA MOV H,A INX H ; XSEK3: MOV A,B ;GO TO SEEKING INWARD STA SKDIR LXI D,512 CALL TSUB RAL JNC XSEK4 ;JIF DOUBLE PUMP IS REQ CALL PSK ;DO PARTIAL SEEK RNZ JMP XSEK5 ; XSEK4: DCX D ;[DE] =511 CALL SUBT ;[HL]-[DE] SHLD RSKNT ;SAVE RESIDUAL COUNT XCHG CALL PSK RNZ ;ABORT IF SEEK FAILED LHLD RSKNT CALL PSK ;SEND THE REST RNZ ; ; ;SEEK VERIFY XSEK5: MVI A,3 STA VSRTC ;SET RETRY COUNT MVI A,CBENB OUT CTCSR ;ENABLE BANK ZERO CMP BFR MVI A,VCA OUT CTBFR ;SET CMP BFR ADR LHLD RCA ;REAL (CURR) CYL ADR MOV A,L OUT CTDP ;SET CYL ADR, LSB MOV A,H OUT CTDP ;SET CYL ADR, MSB XSEK6: MVI A,VSA OUT CTBFR ;SET M/CODE START ADR MVI A,START OUT CTCSR ;START VERIFY CALL WFD ;WAIT FOR DONE ANI 0CH ;TEST CTLR STATUS RZ ;RIF VERIFY OK LXI H,VSRTC DCR M ;DECR RETRY COUNT JNZ XSEK6 ;JIF RETRY SEEK VERIFY ; VERIFY FAILED CALL XTKZ ;RESTORE LXI H,SKRTC DCR M ;DECR RETRY COUNT JNZ XSEK1 ;JIF RETRY SEEK ; UNRECOVERABLE SEEK ERROR ORI 1 ;SET ERROR FLAG RET ;ABORT ; ; PARTIAL SEEK ; PSK: CALL XRDY ;DRIVE READY ? RNZ ;ABORT, DRIVE NOT RDY MOV A,L OUT LOSC ;SET SEEK COUNT, LSB MOV A,H OUT HISC ; * MSB LDA SKDIR OUT EXTCMD ;SET SEEK DIRECTION MVI A,3 OUT DRCSR ;ISSUE SEEK CMD ; ; ---> FALL THRU TO 'WSC' <--- ; ; ---WAIT FOR SEEK COMPLETE--- ; ; WSC: PUSH H ;SAVE REGS PUSH B LXI H,0 ;TIME-OUT DELAY COUNT MVI B,6 ;XCOMP HAD 3 NEED 6 FOR 5MHz ; WSC1: IN DRCSR ;DRIVE STATUS RAL JC WSC2 ;JIF SEEK DONE DCX H ;DECR DELAY COUNT MOV A,H ORA L JNZ WSC1 ;JIF CON'T WAITING DCR B JNZ WSC1 ; TIME-OUT ERROR POP B ;RESTORE REGS POP H MVI A,1 ORA A ;SET CPM ERROR FLAG STC ;SET INTERNAL ERROR FLAG RET ; WSC2: POP B ;RESTORE REGS POP H XRA A ;SET FLAG = OK RET ; ; ; ; ---CLEAR DRIVE FAULT--- ; CLRDF: XRA A OUT EXTCMD ;DE-SELECT THE DRIVE (FALL THRU TO 'XSEL' TO ;RE-SELECT THE DRIVE) ; ; ---HEAD SELECT--- ; XSEL: LDA @TRK ;REQUESTED TRACK ANI 1 ;2 HEADS STA RHD ;SAVE REAL HEAD # ADD A ;SHIFT HEAD # LEFT TWICE FOR H/W ADD A ORI 1 ;TO MAINTAIN DRIVE SLCT OUT EXTCMD ;SELECT HEAD 0 OR 1 RET ; ; ---DRIVE READY TEST--- ; XRDY: IN DRCSR ;DRIVE STATUS ANI 1 ;DRIVE RDY BIT XRI 1 ; MAKE IT LO-TRUE RZ ;RIF DRIVE READY LXI H,MSGH1 ;ERROR MSG CALL ?PMSG ORI 1 ;SET ERROR FLAG RET ; ; ; SHIFTS THE CONTENTS OF H/L RIGHT 'N' TIMES. ; DRS: PUSH PSW ;SAVE 'A' DRS1: MOV A,H ;MSB ORA A ;CLEAR CY RAR MOV H,A MOV A,L ;LSB RAR MOV L,A DCR B ;B = SHIFT COUNT JNZ DRS1 POP PSW ;RESTORE 'A' RET ; SUBT: MOV A,L ;16 BIT SUBTRACTION SUB E MOV L,A MOV A,H SBB D MOV H,A ORA L MOV A,H RET ; TSUB: PUSH H ;SAVE [HL] CALL SUBT POP H RET ; ;------------------------- DATA STORAGE AREA ------------------------------- ; ; --- COMMAND TABLE TO SEEK SECTOR/TRACK --- ; ; WTBL: DB 5 ;RETRY COUNT DB 5 ;CMP BFR ENB DB 0E6H ;CMP BFR ADR DB BANK1 ;CNTL BANK DB 0D3H ;START ADR DB 0EH ;STATUS MASK ; RTBL: DB 10 ;RETRY COUNT DB 4 ;CMP BFR ENB DB 0EAH ;CMP BFR ADR DB BANK0 ;CNTL BANK DB 0D7H ;START ADDRESS DB 0EH ;STATUS MASK ; MSGH1: DB BELL,CR,LF,'Drive not Ready',0 MSGH2: DB BELL,CR,LF,'Restore Failed',0 SAYSIGNON: DB 'HHARD DISK ON DRIVE AEE ',0 ; RCA: DS 2 ;REAL TRACK ADDRESS RHD: DS 1 ; HEAD RSA: DS 1 ; SECTOR ; RETRY: DS 1 ;RETRY COUNT CTA: DS 2 ;COMMAND TABLE ADDRESS ERFLG: DS 1 ;ERROR FLAG SKRTC: DS 1 ;SEEK RETRY COUNT VSRTC: DS 1 ;SEEK VERIFY COUNT SKDIR: DS 1 ;SEEK DIRECTION RSKNT: DS 2 ;RESIDUAL SEEK COUNT SPARE: DS 2 ; ;