|
DataMuseum.dkPresents historical artifacts from the history of: CP/M |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about CP/M Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - download
Length: 28288 (0x6e80) Types: TextFile Names: »HDIO.ASM«
└─⟦b445f10af⟧ Bits:30004389 CP/M Plus Source files └─ ⟦this⟧ »HDIO.ASM«
TITLE 'HARD DISK I/O HANDLER FOR CP/M 3.0 BIOS - DATE:840403' PAGE 43 ;************************************************************************* ;* HDIO MODULE * ;* * ;* THE HARD DISK FORMAT * ;* * ;* DISK DRIVE TYPE ø CDC-WREN ø ST-406 ø ST-412 ø ST-506 * ;* ----------------------ø----------ø----------ø----------ø-------- * ;* SIZE ø 32 MBYTE ø 10 MBYTE ø 10 MBYTE ø 5 MBYTE * ;* TRACKS (TRKS) ø 675 ø 306 ø 306 ø 153 * ;* SECTORS PR TRACK(PSPT)ø ø ø ø * ;* MSC9205/DTC510A ø 17/18 ø 17/18 ø 17/18 ø 17/18 * ;* RECORD SIZE ø 512 ø 512 ø 512 ø 512 * ;* HEADS(SURFACES) ø 5 ø 2 ø 4 ø 4 * ;* * ;************************************************************************* MACLIB CPM3 ; MACLIB PORTS ; MACLIB Z80 ; hdtype equ (hwconfig and 0fh) if (hdtype eq st506) or (hdtype eq st412) or (hdtype eq st406) or (hdtype eq cdcwren) PUBLIC HD0DPH,HD1DPH if (hdtype eq st506) or (hdtype eq st412) or (hdtype eq cdcwren) PUBLIC HD2DPH,HD3DPH endif if (hdtype eq cdcwren) PUBLIC HD4DPH endif EXTRN @ADRV ;ABSOLUTE DRIVE NUMBER (8 BITS) EXTRN @RDRV ;RELATIVE DRIVE NUMBER (8 BITS) EXTRN @DMA ;DISK TRANSFER ADDRESS (16 BITS) EXTRN @TRK ;DISK TRACK ADDRESS (16 BITS) EXTRN @SECT ;DISK SECTOR ADDRESS (16 BITS) EXTRN @CNT ;RECORD COUNT FOR MULTI SECTOR TRANSFER EXTRN @DBNK ;DISK TRANSFER BANK (8 BITS) EXTRN @CBNK ;CURRENT BANK FOR PROCESSOR EXTRN @ERMDE ;BDOS ERROR MODE EXTRN ?BNKSL EXTRN ?PDERR ;PRINT BIOS ERROR HEADER EXTRN ?PMSG ;PRINT MESSAGE UNTIL 0 EXTRN ?PDEC ;PRINT HEX VALUE CONVERTED TO DEC VALUE EXTRN ?CONIN ; EXTRN ?WBOOT ; EXTRN ?MOVE,?XMOVE ; ;EXTENDED DISK PARAMETER HEADERS (XDPH'S) DSEG ;BANKED MEMORY dw hd$ret dw hd$ret dw hd$ret DW HD$WRITE ; DW HD$READ ; DW HD$LOGIN ; DW HD$INIT0 ; DB 0,0 ; HD0DPH: DPH 0,HD$DPB,0 dw hd$ret dw hd$ret dw hd$ret DW HD$WRITE ; DW HD$READ ; DW HD$LOGIN ; DW HD$INIT1 ; DB 1,0 ; HD1DPH: DPH 0,HD$DPB,0 if (hdtype eq st506) or (hdtype eq st412) or (hdtype eq cdcwren) dw hd$ret dw hd$ret dw hd$ret DW HD$WRITE ; DW HD$READ ; DW HD$LOGIN ; DW HD$INIT1 ; DB 2,0 ; HD2DPH: DPH 0,HD$DPB,0 dw hd$ret dw hd$ret dw hd$ret DW HD$WRITE ; DW HD$READ ; DW HD$LOGIN ; DW HD$INIT1 ; DB 3,0 ; HD3DPH: DPH 0,HD$DPB,0 endif if (hdtype eq cdcwren) dw hd$ret dw hd$ret dw hd$ret DW HD$WRITE ; DW HD$READ ; DW HD$LOGIN ; DW HD$INIT1 ; DB 4,0 ; HD4DPH: DPH 0,HD$DPB,0 endif CSEG ;COMMON MEMORY HD$DPB: DPB 512,HD$PSPT,HD$TRKS,2048,1024,2,8000H DSEG ;REST IS BANKED MEMORY ;************************************************************************ ;* * ;************************************************************************ HD$LOGIN: hd$ret: RET ;************************************************************************ ;* THE PARAMETERS FOR THE READ/WRITE ROUTINES ARE CONTAINED IN * ;* THE PUBLIC VARIABLES : @ADRV,@RDRV,@TRK,@SECT,@DMA AND @DBNK * ;* * ;* INPUT : <DE> = ADDRESS OF XDPH * ;* * ;* OUTPUT: <A> = 00H ,NO ERROR * ;* <A> = 01H ,PERMANENT ERROR * ;* * ;************************************************************************ HD$READ: LXI H,RD$MSG ;Point at 'READ' MVI A,C$HD$READ ;read sector command JMP RW$COMMON HD$WRITE: LXI H,WR$MSG ;Point at 'WRITE' MVI A,C$HD$WRITE ;write sector command RW$COMMON: SHLD RW$NAME ;Save message for errors STA DISK$COMMAND ;Save command ;; CALL TESTMSG ; MVI A,1 STA @CNT CONTINUE: XRA A ; STA DISK$STATUS ;No error <=> 0 CALL CMDEXEC ; ORA A ;test error status STA DISK$STATUS ; RZ RW$ERROR: LDA @ERMDE ; CPI 0FFH ; JZ HARD$ERROR ; CALL ?PDERR ;PRINT BIOS ERROR HEADER LHLD RW$NAME ; CALL ?PMSG ;PRINT OPERATION NAME LDA DISK$STATUS ; MOV L,A ; MVI H,00H ; CALL ?PDEC ;PRINT ERROR CODE CALL ?CONIN ;GET RESPONSE CPI 'C'-040 ;IF CTL-C WARM BOOT JZ ?WBOOT ; HARD$ERROR: MVI A,01H ;RETURN HARD ERROR TO BDOS RET ;;TESTMSG: ; LXI H,TSTMS ; CALL ?PMSG ; LDA @CNT ; MOV L,A ; MVI H,0 ; CALL ?PDEC ; LXI H,SPACE ; CALL ?PMSG ; LHLD @DMA ; CALL ?PDEC ; LXI H,SPACE ; CALL ?PMSG ; LHLD @SECT ; CALL ?PDEC ; LXI H,SPACE ; CALL ?PMSG ; LHLD @TRK ; CALL ?PDEC ; LXI H,SPACE ; CALL ?PMSG ; LDA @DBNK ; MOV L,A ; MVI H,0 ; CALL ?PDEC ; LXI H,SPACE ; CALL ?PMSG ; RET ;TSTMS: DB CR,LF,0 ;TSTMS1: DB ' DUMMY',0 ;SPACE: DB ' ',0 ;------------------------------------------------------------------------- ; SHORT DELAY ROUTINE FOR TIME DELAYS OF (A REG) X 0.5 MSEC SDLY: MVI L,86H ;ONE MILLISECOND TIME FACTOR DCR L ;..COUNT IN (A) JNZ $-1 DCR A JNZ SDLY RET ;-------------------------------------------------------------------------- RD$MSG: DB CR,LF,'READ CODE:',0 ;FOR ERROR MESSAGES WR$MSG: DB CR,LF,'WRITE CODE:',0 ;FOR ERROR MESSAGES RW$NAME:DW RD$MSG ;FOR ERROR MESSAGES DISK$STATUS: DB 00H ;ERROR FLAG PAGE if (hdctrl eq dtc510a) if (crtype eq CR8) ;************************************************************************ ;* THE BOOT ENTRY CALLS EACH INIT ROUTINE DURING THE COLD START * ;* AND PRIOR TO ANY OTHER DISK ACCESS,THE INIT ROUTINE PERFORMS * ;* ANY NECESSARY HARDWARE INIT SUCH AS SETTING UP THE CONTROLLER * ;* AND INTERRUPT VECTORS. * ;************************************************************************ HD$INIT0: ; XRA A ;SET HARD DISK UNIT 00 STA HDUNIT ;STORE NEW UNIT ;ALL INIT DONE BY HD$INIT0 DR$RDY: MVI D,0FFH RDY$LP: PUSH D MVI A,0 STA DISK$COMMAND CALL HD$CMDEXEC ORA A POP D JZ READY DCR D JNZ RDY$LP READY: IN P$CCSR MVI A,100 CALL SDLY LDA @CBNK MOV C,A MVI B,0 CALL ?XMOVE LXI D,HDIMAGE LXI H,DATBUF LXI B,IMAGEEND-HDIMAGE CALL ?MOVE MVI A,C$DISET STA DISK$COMMAND CALL HD$CMDEXEC HD$INIT1: RET ; ;========================================================================= ;ROUTINE TO PERFORM DISK CONTROLLER COMMAND, BUSY WAIT, AND STATUS ;CHECKS WITH RETRIES. RETURNS ZERO IN (A) IF THE OPERATION IS SUCCESSFUL ;AND REAL ERROR CODE IF OPERATION DID NOT SUCCEEDE. ; CMDEXEC: LDA DISK$COMMAND CPI C$HD$WRITE JNZ NO$WRITE CALL MOVWRD ;move from @DMA-addr to DATBUF NO$WRITE: CALL HD$CMDEXEC PUSH PSW LDA DISK$COMMAND CPI C$HD$READ JNZ NO$READ CALL MOVRDD ;mov from DATBUF to @DMA-addr NO$READ: POP PSW RET HD$CMDEXEC: CALL COMPSEC ;COMPUTE LOGICAL DISK ADDRESS MOV B,A LDA HDUNIT ;GET UNIT NUMBER ANI 01 ;MASK UNUSED BITS RRC RRC RRC ;ROTATE INTO PROPER POSITION ORA B ;MERGE WITH HIGH DISK ADDRESS STA MSBADR ;SAVE COMPLETE ADDRESS IN MOV A,H ;... COMMAND DESCIPTOR BLOCK STA MIDADR MOV A,L STA LSBADR LDA @CNT ;MOVE COUNT INTO IOPB STA BLOCK MVI B,03 ;SET RETRY COUNT CMDLP: PUSH B CALL HCMD ;START OPERATION CALL BUSYW ;WAIT TILL COMMAND DONE OR TIMEOUT CALL STCHK ;GET STATUS POP B RZ ;DONE WITH COMMAND IF O.K. DCR B ;DEC RETRY COUNT JNZ CMDLP ;GO TRY AGAIN CPI 0FFH ;TEST IF ERROR IS TIMEOUT RZ ;EXIT SINCE NO SENCE STATUS AVAIL. MOV B,A ANI 02H ;TEST IF ERROR OCCURRED MOV A,B CNZ GETERR ;GET ERROR FROM CONTROLLER, IF ANY RET ;RETURN WITH ERROR CODE IF REALLY BAD ;------------------------------------------------------------------------ ;ROUTINE TO SEND PARAMETER BLOCK ADDRESS TO DISK CONTROLLER AND ;THUS INITIATE AN OPERATION. PARAMETER BLOCK ADDRESSING IS SENT ;SO AS TO ENABLE THE 20-BIT ADDRESSING MODE. ; HCMD: IN P$CCSR ;CLEAR OLD STATUS, IF ANY CALL MOVIOPB ;COPY IOPB INTO IOPBBF LXI H,IOPBBF ;GET ADDRESS OF MOVED IOPB MOV A,L ;SEND LOW BYTE OF IOPB ADDRESS OUT P$CADDRL MOV A,H ;SEND MID BYTE OF IOPB ADDR OUT P$CADDRM MVI A,01 ;SEND HIGH BYTE OF IOPB ADDR OUT P$CADDRH LXI H,DATBUF ;GET ADDRESS OF TEMPORARY DATA BUFFER MOV A,L OUT P$DADDRL ;SEND DATA BUFFER LOW ADDRESS MOV A,H OUT P$DADDRM ;SEND DATA BUFFER MID ADDRESS MVI A,01 OUT P$DADDRH ;SEND DATA BUFFER HIGH ADDRESS XRA A OUT P$CSR ;START COMMAND EXECUTION RET ;------------------------------------------------------------------------ ; ROUTINE TO WAIT TILL COMMAND COMPLETION INDICATED BY COMMAND ; DONE BIT IN HOST ADAPTER STATUS REGISTER. ; ; ROUTINE WILL RETURN 0FFH IN (A) IF HOST ADAPTER DO NOT ; INDICATE COMMAND TERMINATION BY SETTING THE "DONE" BIT ; IN IT'S STATUS REGISTER WITHIN THE SPECIFIED TIME. ; BUSYW: LXI B,0 ;APPROX 4.4 MINUTE DELAY LDA DISK$COMMAND ;... USED IF THIS IS FORMAT DISK CPI C$DIFORM JZ BSYW1 LXI B,1000H ;APPROX 16 SECOND BUSY TIMEOUT BSYW1: IN P$CSR ;GET STATUS BYTE ANI 080H ;MASK BUSY BIT RNZ ;EXIT IF COMMAND DONE MVI A,08 ;4 MILLISECOND CALL SDLY DCX B ;DEC TOTAL TIMEOUT VALUE MOV A,B ORA C JNZ BSYW1 ;MORE DELAY IF NOT COUNTED OUT MVI A,0FFH ;SEND BUSY TIMEOUT TO STCHK ROUTINE RET ;------------------------------------------------------------------------- ; ; ROUTINE TO CHECK COMMAND COMPLETION STATUS. ; BUSY WAIT WILL SENT (A)=0FFH IF THERE WAS A TIMEOUT ; ON COMMAND EXECUTION. ; ; RETURNS (A): ; 000H=SUCCESSFUL COMPLETION ; 0FFH=TIMEOUT ON COMMAND COMPLETION ; 0XXH=OTHER ERRORS ; STCHK: CPI 0FFH ;CHECK ENTRY STATUS RZ ;SEND STATUS = 0FFH IF ALWAYS BUSY IN P$CSR ;GET CHANNEL STATUS ANI 40H ;TEST FOR PARITY ERROR (CORRECTION 830525/NF) MOV B,A IN P$CCSR ;GET COMPLETION CODE ANI 03H ;REMOVE UNUSED BITS ORA B ;INSERT PARITY ERROR BIT (CORRECTION 830525/NF) RET ;****************************************************************************** ; ROUTINE TO GET SENCE STATUS (ERROR) FROM CONTROLLER ;****************************************************************************** ; GETERR: MVI A,C$DIRSS ;REQUEST SENCE STATUS OPCODE STA DISK$COMMAND CALL HCMD ;SEND COMMAND TO CONTROLLER CALL BUSYW ;WAIT FOR COMMAND TO TERMINATE CALL STCHK ;GET COMPLETION STATUS RNZ ;EXIT IF ERROR TERMINATION LDA @CBNK ; MVI C,0 ;SOURCE BANK MOV B,A ;DESTINATION BANK CALL ?XMOVE ;SET MAP REGISTERS FOR DESIRED TRANSFER LXI D,DATBUF ;SOURCE BUFFER ADDRESS LXI H,SNSBUF ;DESTINATION BUFFER ADDRESS LXI B,0004H ; CALL ?MOVE ;GET SENSE STATUS INTO LOCAL RAM LDA SNSBUF ;GET ERROR CODE RET endif if (crtype eq CR7) ;************************************************************************ ;* THE BOOT ENTRY CALLS EACH INIT ROUTINE DURING THE COLD START * ;* AND PRIOR TO ANY OTHER DISK ACCESS,THE INIT ROUTINE PERFORMS * ;* ANY NECESSARY HARDWARE INIT SUCH AS SETTING UP THE CONTROLLER * ;* AND INTERRUPT VECTORS. * ;************************************************************************ HD$INIT0: ; XRA A ;SET HARD DISK UNIT 00 STA HDUNIT ;STORE NEW UNIT CALL RESET ;ALL INIT DONE BY HD$INIT0 HD$INIT1: RET ; RESET: XRA A OUT P$HD$RESET ;RESET CONTROLLER MVI A,0FFH CALL SDLY ;WAIT MVI A,C$DISET STA DISK$COMMAND CALL SELCTLR ;SELECT CONTROLLER RNZ CALL SENDCMD ;SEND IOPB RNZ LDA @CBNK STA CBNK STA DBNK LXI B,0AH LXI H,STEPM MVI C,P$HD$DATA MVI E,0EH CALL MOVWRD1 ;SEND DISK IMAGE TO CONTROLLER RNZ CALL STCHK RET ;****************************************************************************** ; ROUTINE TO PERFORM DISK CONTROLLER COMMAND, BUSY WAIT, AND STATUS ; CHECKS WITH RETRIES. RETURNS ZERO IN (A) IF OPEATION SUCCESSFUL ; AND REAL ERROR CODE IF OPERATION DID NOT SUCCEEDE AFTER SPECIFIED ; NUMBER OF RETRIES. ;****************************************************************************** ; CMDEXEC: LDA @CBNK STA CBNK LDA @DBNK STA DBNK LDA DISK$COMMAND STA DSK$CMD MVI A,3 ;SET RETRY COUNT CMDLP: STA HDRTRYC LDA @CNT STA BLOCK CALL SELCTLR ;START OPERATION JNZ CMDEXIT ;BALE OUT IF NO RESPONCE CALL COMPSEC ;COMPUTE GET LOGICAL DISK ADDRESS MOV B,A ;SAVE HIGH ADDRESS LDA HDUNIT ;GET DRIVE NUMBER ANI 01H ;CONTROLLER ONLY SUPPORTS DRIVE 0 AND 1 RRC RRC RRC ;ROTATE INTO POSITION ORA B ;COMBINE WITH HIGH ADDRESS STA MSBADR ;STORE IN COMMAND BLOCK MOV A,H STA MIDADR MOV A,L STA LSBADR ;COMMAND BLOCK BUILD-UP COMPLETE CALL SENDCMD ;SEND COMMAND TO CONTROLLER JNZ CMDEXIT ;BALE OUT IF COMMAND TRANSFERE FAILED LDA DISK$COMMAND ;GET OPCODE CPI C$HD$WRITE ;TEST IF WRITE OPERATION JNZ TSTBSY ;SKIP IF NO DATA REQUIRED CALL MOVWRD JNZ CMDEXIT ;BALE OUT IF DATA TRANSFERE FAILED TSTBSY: CALL BUSYW ;WAIT TILL CONTROLLER NOT BUSY JNZ CMDEXIT ;BALE OUT IF COMMAND ABNORMAL TERMINATED LDA DISK$COMMAND ;GET OPCODE CPI C$HD$READ ;TEST IF READ OPERATION JNZ TSTCC ;GO TEST COMPLETION CODE IF NOT READ CALL MOVRDD ;IF READ - GO GET DATA JNZ CMDEXIT ;GO TEST COMPLETION CODE IF ALL DATA READ IN TSTCC: CALL STCHK ;GET STATUS JRZ CMDEXIT ;ALL DONE IF NO ERROR MOV B,A ;SAVE ERROR STATUS LDA DSK$CMD ; STA DISK$COMMAND ; LDA HDRTRYC ;GET RETRY COUNTER DCR A ;DEC RETRY COUNT JNZ CMDLP ;GO TRY AGAIN MOV A,B CMDEXIT: ANA A RET ;RETURN WITH ERROR CODE IF REALLY BAD ;****************************************************************************** ; ROUTINE TO SEND SELECT TO DISK CONTROLLER AND THUS INITIATE AN ; OPERATION. CONTROLLER BUSY STATUS IS MONITORED FOR UP TO 2 SECONDS ; BEFORE SENDING COMMAND. IF NOT UNBUSY WITHIN TWO SECOND TIME, ; THE ROUTINE IS EXITED WITH ERROR STATUS = 0FEH. ;****************************************************************************** ; SELCTLR: MVI B,32 ;2 SECOND DELAY PARAMETER BUSYC: IN P$HD$STAT ;GET CONTROLLER STATUS ANI 01H ;TEST BUSY BIT JRNZ NOTBUSY ;GO ON IF NOT BUSY MVI A,64 ;DELAY FOR 64 MILLISECONDS CALL SDLY DJNZ BUSYC ;IF NOT TWO SECONDS, GO CHECK STATUS BADSLCT: MVI A,0F1H ;0F1H = SELECT CONTROLLER ERROR ANA A ;SET FLAGS RET NOTBUSY: MVI A,01 OUT P$HD$STAT ;SEND SELECT TO CONTROLLER IN P$HD$STAT ;GET STATUS ANI 01H ;MUST BE BUSY NOW JRNZ BADSLCT ;ERROR IF CONTROLLER DID NOT GO BUSY RET ;****************************************************************************** ; ROUTINE TO SEND THE 6 BYTE COMMAND BLOCK TO THE CONTROLLER ;****************************************************************************** ; SENDCMD: LXI H,IOPB ; MVI B,IOPBEND-IOPB ;COMMAND BLOCK LENGTH PUSH B CALL BUSYW ;GO WAIT FOR CONTROLLER REQUEST POP B RNZ ;EXIT IF NO REQUEST OCCURED CPI 0CH ;TEST IF PROPPER KIND OF REQUEST JRZ SENDNXT MVI A,0F2H ;CONTROLLER ERROR ANA A RET SENDNXT: MOV A,M ;GET NEXT BYTE OUT P$HD$DATA ;SEND IT TO CONTROLLER INX H ;POINT TO NEXT DJNZ SENDNXT ;LOOP UNTIL COMMAND BLOCK ALL SEND XRA A ;SET STATUS = OK RET ;****************************************************************************** ; ROUTINE TO WAIT TILL COMMAND COMPLETION INDICATED BY ; CONTROLLER REQ BIT IN CONTROLLER STATUS REGISTER. ; ROUTINE WILL RETURN 0FFH IN (A) IF CONTROLLER DID NOT SET ; REQ, AND AS A RESULT BECAME HUNG ON CURRENT COMMAND. ;****************************************************************************** ; BUSYW: MVI A,30 ;MSB RETRY COUNT BSYW2: ;MAX WAIT IS 33 SEC STA RETRY$CNT LXI B,0FFFFH ;RETRY COUNT ;TIMEOUT TYP. 1,1 SEC. BSYW1: IN P$HD$STAT ;GET SASI STATUS BIT 4,A ;TEST REQUEST (L) RZ MOV A,B ;TEST RETRY COUNT ZERO ORA C JNZ BSYW1 LDA RETRY$CNT DCR A DJNZ BSYW2 MVI A,0FFH ;SET ERROR ORA A ;SET FLAGS RET ;****************************************************************************** ; ; ROUTINE TO CHECK COMMAND COMPLETION STATUS ; EXIT: <A>=000H,SUCCESSFUL COMPLETION ; <A> <> 0,CONTROLLER PROVIDED ERROR CODE ; <A>=0FEH,CONTROLLER ERROR ;****************************************************************************** STCHK: CALL GETRST ;GET COMMAND RESULT STATUS ANI 02 ;LEAVE ONLY ERROR BIT JRNZ GETERR ;GET ERROR CODE IF OPERATION FAILED RET GETERR: MVI A,C$DIRSS ;REQUEST SENCE STATUS CODE STA DISK$COMMAND CALL SELCTLR ;SELECT CONTROLLER JNZ BADSTC CALL SENDCMD ;SEND COMMAND TO CONTROLLER JNZ BADSTC CALL BUSYW ;WAIT FOR CONTROLLER REQUEST JNZ BADSTC IN P$HD$DATA ;GET FIRST STATUS BYTE MOV E,A CALL BUSYW JNZ BADSTC IN P$HD$DATA CALL BUSYW JNZ BADSTC IN P$HD$DATA CALL BUSYW JNZ BADSTC IN P$HD$DATA CALL GETRST ;GET COMMAND RESULT STATUS MOV A,E ANI 3FH ;MASK OUT ADDRESSE VALID BIT CPI 18H ;IS CORRECTABLE ERROR ? JRNZ NCORR ;JMP IF NOT XRA A NCORR: ANA A RET ;------ GETRST: CALL BUSYW ;GO WAIT FOR CONTROLLER REQUEST JRNZ BADSTC ;BALE OUT IF NO REQUEST OCCURED CPI 08H ;TEST FOR PROPER REQUEST TYPE JRNZ BADSTC ;BALE OUT IF WRONG TYPE IN P$HD$DATA ;GET CONTROLLER STATUS MOV D,A CALL BUSYW ;WAIT FOR SECOND BYTE JRNZ BADSTC ;BALE OUT IF NO REQUEST CPI 0 ;SHOULD BE COMMAND COMPLETE MESSAGE JRNZ BADSTC ;BALE OUT IF NOT IN P$HD$DATA ;GET ZERO BYTE MOV A,D RET BADSTC: POP B MVI A,0F3H ANA A RET ;****************************************************************************** ; ROUTINE TO SEND WRITE DATA TO CONTROLLER ;****************************************************************************** MOVWRD: CALL BUSYW ;WAIT FOR REQUEST FROM CONTROLLER RNZ ;EXIT IF TIMEOUT OCCURED MVI C,P$HD$DATA MVI E,0EH LHLD @DMA JMP MOVWRD1 CSEG MOVWRD1: LDA DBNK CALL ?BNKSL IN P$HD$STAT CMP E JNZ WBSYW2 OUTI JMP MOVWRD1 WBSYW2: CPI 08 JZ EXIT$RW BIT 4,A JRZ MDERROR JMP MOVWRD1 ;****************************************************************************** ; ROUTINE TO RECEIVE READ DATA FROM CONTROLLER ;****************************************************************************** DSEG MOVRDD: CALL BUSYW ;WAIT FOR REQUEST FROM CONTROLLER RNZ ;EXIT IF TIMEOUT OCCURED MVI C,P$HD$DATA MVI E,0AH LHLD @DMA JMP MOVRDD1 CSEG MOVRDD1: LDA DBNK CALL ?BNKSL IN P$HD$STAT CMP E ;TEST IF PROPER KIND OF REQUEST JRNZ RBSYW2 INI JMP MOVRDD1 RBSYW2: CPI 08H ;MUST BE STATUS OF NOT DATA JZ EXIT$RW BIT 4,A JRZ MDERROR JMP MOVRDD1 MDERROR: CALL EXIT$RW ;RESELECT SYSBANK MVI A,0F0H ;RETURN ERROR CODE ORA A RET EXIT$RW: LDA CBNK CALL ?BNKSL LDA DBNK STA @DBNK XRA A RET DBNK DB 0 CBNK DB 0 DSEG endif PAGE ;****************************************************************************** ; ROUTINE TO COMPUTE LOGICAL SECTOR NUMBER FROM PHYSICAL TRACK, ; PHYSICAL SECTOR, MAX HEAD,CURRENT HEAD AND CURRENT SECTOR. ;****************************************************************************** ; ; THE ALGORITHM IS AS FOLLOWS: ; LOGSEC = (((CYADR*HDCYL)+HDADR)*SETRK)+SEADR ; CYADR = CYLINDER ADDRESS ; HDCYL = NUMBER OF HEADS ; HDADR = HEAD ADDRESS ; SETRK = SECTORS PER TRACK ; SEADR = SECTOR ADDRESS ; ; ENTRY: ; BEFORE THIS ROUTINE IS CALLED, ALL THE USED PARAMETER MUST ; BE SETUP BY CALLS TO THE PARAMETER TRANSFERE ROUTINES. ; USED PARAMETERS ARE: ; (@TRK) (@SECT) (@RDRV) AND (MAXHD=3) ; ; EXIT: ; REG. A,H,L = 21 BIT LOGICAL SECTOR ADDRESS ; A = 5 MSB, H = MID 8 BITS, L = 8 LSB ; ; DESTROY: A,B,D,E,F,H,L ; COMPSEC: LHLD @TRK ;GET CYLINDER NUMBER LDA MAXHEAD ;GET MAX HEAD NUMBER ORA A JZ MAXFOUND ;ONLY 1 HEAD(0) MOV E,L MOV D,H COMP1: DAD D DCR A JRNZ COMP1 ;MULTIPLY (RESULT IN HL) MAXFOUND: LDA @RDRV ;GET HEAD NUMBER MOV E,A ;EXPAND INTO 16 BITS IN DE MVI D,0 DAD D MVI B,HD$PSPT ;GET NBR.OF SECTORS PER TRACK LXI D,0 XCHG ;PREPARE FOR 24 BIT MULTIPLY MVI A,0 COMP2: ORA A ;CLEAR CARRY DADC DE JNC NOOVFL ; INR A ;SUM OVERFLOWS FROM 16 BIT ADD NOOVFL: DJNZ COMP2 ;MULTIPLY LOOP ; MOV B,A LDA @SECT ;GET SECTOR NUMBER MOV E,A MVI D,0 ;EXPAND TO 16 BITS IN DE MOV A,B ORA A ;CLEAR CARRY DADC DE JNC MASK21 ;OK IF NO OVERFLOW INR A MASK21: ANI 1FH ;STRIP TO 21 BITS RESULT RET ;****************************************************************************** ; HARD DISK CONTROLLER I/O PARAMETER BLOCK ;****************************************************************************** IOPB EQU $ ;INPUT/OUTPUT PARAMETER BLOCK DISK$COMMAND: DB 0 ;COMMAND CLASS AND OPCODE MSBADR: DB 0 ;HIGH DISK ADDRESS + LOGICAL UNIT NUMBER MIDADR: DB 0 ;MID DISK ADDRESS LSBADR: DB 0 ;LOW DISK ADDRESS BLOCK: DB 0 ;BLOCKCOUNT FOR READ,WRITE AND INTERLEAVE CTLFLT: DB 0 ;CONTROL FIELD ( =0 FOR NORMAL OPERATION ) IOPBEND: ;----------------------------------------------------------------------- HDIMAGE: STEPM: DB 03 ;11 STEPP: DB 01 ;60 STEPT: DB 0 MAXHEAD: DB HD$HEAD MAXCYL: DB HD$MC1,HD$MC2 ;01H,31H LOWWRT: DB 80H OVERLP: DB 0 SPARE: DB 0,0 IMAGEEND: ;------------------------------------------------------------------------- DSK$CMD: DB 0 RETRY$CNT: DB 0 HDUNIT: DB 0 ;DRIVE NUMBER SNSBUF: DB 0,0,0,0 ;STATUS BUFFER HDRTRYC: DB 0 ;HARD DISK RETRY COUNTER endif if (hdctrl eq msc9205) and (crtype eq CR8) ;************************************************************************ ;* THE BOOT ENTRY CALLS EACH INIT ROUTINE DURING THE COLD START * ;* AND PRIOR TO ANY OTHER DISK ACCESS,THE INIT ROUTINE PERFORMS * ;* ANY NECESSARY HARDWARE INIT SUCH AS SETTING UP THE CONTROLLER * ;* AND INTERRUPT VECTORS. * ;************************************************************************ HD$INIT0: ; MVI C,00H ;SET HARD DISK UNIT 00 LDA INSTR ;GET PRESENT INSTRUCTION ANI 0CFH ;STRIP OUT OLD UNIT ORA C ; STA INSTR ;STORE NEW UNIT HD$INIT1: HD$INIT2: ;ALL INIT DONE BY HD$INIT0 RET ; PAGE ;=============HARD DISK I/O PARAMETER BLOCK SET UP ROUTINE============== HIOPB: ; ;-----------------SET PLATTER NUMBER------------------------------------ HSETPLAT: LXI H,@RDRV ; MOV C,M ; MVI A,03H ;GET PLATTER MASK ANA C ;GET ONLY PLATTER BITS RRC ;MOVE BITS INTO POSITION RRC ; MOV C,A ; LDA INSTR ;GET PRESENT IOPB BYTE ANI 03FH ;STRIP OUT OLD PLATTER BITS ORA C ;PUT IN NEW BITS STA INSTR ;SAVE IN IOPB ;---------------SET SURFACE NUMBER----------------------------------------- HSETSUR: MVI C,00H ; MVI A,01H ;GET SURFACE MASK ANA C ;GET ONLY SURFACE MASK RLC ; RLC ; RLC ;MOVED INTO POSITION MOV C,A ; LDA INSTR ; ANI 0F7H ;STRIP OUT OLD SURFACE BIT ORA C ;PUT IN NEW BIT STA INSTR ;SAVE IN IOPB ;---------------SET CYLINDER NUMBER INTO IOPB------------------------------ HSETCYL: LHLD @TRK ; MOV A,L ; STA CYL ;PUT CYLINDER NUMBER INTO IOPB MVI A,03H ;GET HIGH BIT CYLINDER MASK ANA H ; RRC ;SHIFT LOW BITS INTO HIGH POSITION RRC ; MOV H,A ;PUT NEW CYLINDER HIGH BIT INTO <H> LDA REC ;GET OLD HIGH BIT ANI 03FH ;STRIP OUT OLD BIT ORA H ; STA REC ;SAVE NEW BIT IN IOPB ;-----------------SET BUFFER ADDRESS INTO IOPB------------------------------------ HSETBUF: LXI H,DATBUF ;GET BUFFER ADDR SHLD DMAOFST LXI H,1000H ;SEGMENT ADDRESS OF THIS BUFFER SHLD DMASEG ;SAVE ;------------------SET COUNT INTO IOPB------------------------------- HSETCNT: MVI A,01H ;SET FOR SINGLE SECTOR TRANSFER STA RECNT ; ;------------------SET RECORD NUMBER INTO IOPB-------------------------- HSETREC: LDA @SECT ; INR A ;THE CONTROLLER STARTS WITH 1 NOT 0 MOV C,A ; MVI A,03FH ; ANA C ; MOV C,A ; LDA REC ; ANI 0C0H ; ORA C ; STA REC ; RET ; ;======================================================================== CMDEXEC: CALL HIOPB LDA DISK$COMMAND CPI C$HD$WRITE JNZ NO$WRITE CALL MOVWRD ;move from @DMA-addr to DATBUF NO$WRITE: CALL HD$CMDEXEC PUSH PSW LDA DISK$COMMAND CPI C$HD$READ JNZ NO$READ CALL MOVRDD ;mov from DATBUF to @DMA-addr NO$READ: POP PSW RET HD$CMDEXEC: LDA DISK$COMMAND ; MOV C,A ; MVI A,07H ; ANA C ; MOV C,A ; LDA INSTR ; ANI 0F8H ; ORA C ; STA INSTR ; MVI B,03H ;SET RETRY COUNT CMDLP: PUSH B ; CALL HCMD ;START OPERATION CALL BUSYW ;WAIT UNTIL CONTROLLER NOT BUSY CALL STCHK ;GET STATUS POP B ; RZ ;DONE WITH COMMAND IF OK DCR B ;DEC RETRY COUNT JNZ CMDLP ;GO TRY AGAIN RET ; ;------------------------------------------------------------------------ HCMD: MVI A,02H ; STA RSTFLG ; TRY2: MVI B,32 ; 2 SEC DELAY BUSYC: IN P$HD$2 ; ANI 080H ; JZ CTLRDY ; MVI A,64 ; CALL SDLY ; DCR B ; JNZ BUSYC ; LDA RSTFLG ; DCR A ; STA RSTFLG ; RZ ; XRA A ;ZERO DATA OUT P$HD$7 ;COMMAND CONTROLLER MVI A,100 ;DO 100 mSEC DELAY AFTER CALL SDLY ;....CONTROLLER RESET JMP TRY2 ; CTLRDY: CALL MOVIOPB ;COPY IOPB INTO IOPBBF LXI H,IOPBBF ;GET ADDRESS OF IOBP COPY LXI D,1000H ;GET SEGMENT ADDRESS OF IOPB MOV A,L ;SEND IOPB ADDRESS TO CONTROLLER OUT P$HD$1 ;LOW BYTE OF OFFSET ADDR MOV A,E ; OUT P$HD$0 ;LOW BYTE OF SEGMENT ADDR MOV A,D ; OUT P$HD$0 ;HIGH BYTE OF OFFSET ADDR MOV A,H ; OUT P$HD$2 ;HIGH BYTE OF SEGMENT ADDR RET ; ;------------------------------------------------------------------------ BUSYW: LXI B,04000H ;APPROX 15 SEC TIMEOUT BSYW1: IN P$HD$2 ;GET STATUS BYTE ANI 080H ;MASK BUSY BIT RZ ;EXIT IF NOT BUSY ANY MORE MVI A,01H ;1 mSEC CALL SDLY ; DCX B ;DEC TOTAL TIMEOUT VALUE MOV A,B ; ORA C ; JNZ BSYW1 ;MORE DELAY IF TIMEOUT VALUE <>0 MVI A,0FFH ;SEN BUSY TIMEOUT TO STATCHECK RET ;------------------------------------------------------------------------ STCHK: CPI 0FFH ;CHECK ENTRY STATUS RZ ;SEND STATUS = 0FFH IF ALWAYS BUSY IN P$HD$1 ;GET RESULT TYPE ANI 03H ;GET RID OF UNUSED BITS JZ ERSTAT ;GO PROCESS AN ERROR STATUS BYTE CTLFAL: IN P$HD$3 ;CHECK CONTROLLER BUSY CLEAR MVI A,0FEH ;RETURN 0FEH IF CONTROLLER FAILURE RET ; ERSTAT: IN P$HD$3 ;GET RESULT BYTE ORA A ;CHECK FOR SUCCESSFUL COMPLETION RET ; ;------------------------------------------------------------------------- ;THIS MUST BE IN MEMORY ACCESSABLE BY DISK CONTROLLER VIA DMA IOPB EQU $ ; INCTL DB 010H ; INSTR DB 0 ; RECNT DB 1 ; CYL DB 0 ; REC DB 1 ; DMAOFST DW 0 ; DMASEG DW 0 ; IOPBEND: ; RSTFLG DB 0 ; DISK$COMMAND DB 0 ; endif PAGE if (crtype eq CR8) if (banked eq false) DATBUF EQU 8000H ;START OF DATA BUFFER IN 8088 MEMORY RECSIZE EQU 0200H ; IOPBBF EQU 8200H ;START OF IOPB BUFFER IN 8088 MEMORY MOVIOPB: LDA @CBNK ; MOV C,A ;SOURCE BANK MVI B,0 ;DESTINATION BANK CALL ?XMOVE ; LXI D,IOPB ;START SOURCE ADDRESS LXI H,IOPBBF ;START DESTINATION ADDRESS LXI B,IOPBEND-IOPB ;BYTE COUNT CALL ?MOVE ;COPY IOPB INTO 8088 RAM RET else RECSIZE EQU 0200H ; IOPBBF EQU IOPB DATBUF EQU $ ;START OF DATA BUFFER DS 200H ; MOVIOPB: RET endif ;------------------------------------------------------------------------- MOVRDD: ;ROUTINE TO MOVE DATA FROM DATBUF TO ;DMA BUFFER LDA @DBNK ; MVI C,0 ;SOURCE BANK MOV B,A ;DESTINATION BANK CALL ?XMOVE ;SET MAP REGISTER FOR DESIRED TRANSFER LHLD @DMA ;DESTINATION DATA BUFFER START ADDRESS LXI D,DATBUF ;SOURCE DATA BUFFER START ADDRESS LXI B,RECSIZE ;LENGTH OF BLOCK TO MOVE CALL ?MOVE ; RET ; ;------------------------------------------------------------------------- MOVWRD: ;ROUTINE TO MOVE DATA FROM DMA BUFFER ;TO DATBUF LDA @DBNK ; MOV C,A ;SOURCE BANK MVI B,0 ;DESTINATION BANK CALL ?XMOVE ;SET MAP REGISTER FOR DESIRED MOVE LHLD @DMA ;SOURCE DATA BUFFER START ADDRESS XCHG ; LXI H,DATBUF ;DESTINATION DATA BUFFER START ADDRESS LXI B,RECSIZE ;LENGTH OF BLOCK TO MOVE CALL ?MOVE ; RET ; endif endif END «eof»