DataMuseum.dk

Presents historical artifacts from the history of:

Christian Rovsing CR7, CR8 & CR16 CP/M

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Christian Rovsing CR7, CR8 & CR16 CP/M

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦4dcb1f824⟧ TextFile

    Length: 28288 (0x6e80)
    Types: TextFile
    Names: »HDIO.ASM«

Derivation

└─⟦b445f10af⟧ Bits:30004389 CP/M Plus Source files
    └─ ⟦this⟧ »HDIO.ASM« 

TextFile


	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»