;Format - Data Technology Corporation CP/M 2.2 Format.
;
;	+-----------------------+
;	|			|
;	|      F O R M A T 	|
;	|			|
;	+-----------------------+
;
;
;	Version number:	2.2B
;	Version date:	October 24, 1980
;
;	UPDATE	JANUARY 6,1981
;	ADD MRX101D DISK SIZE CONDITIONALS
;
;	Update March 31, 1981
;		Modified for assembly with ASM.
;		Parameterized for hard disk.
;
;	Update April 27, 1981
;		Modified for controller timeout.
;
;	Update date:	June 15, 1981
;		Modified for new configuration parameters.
;		Formats full hard disk only.

;	The following code is supplied to customers who
;	purchase a hard/floppy disk system from DTC.
;	The following code formats floppy disks and the
;	hard disk contained within the DTC hard disk unit.





VERS:	EQU	22

CR:	EQU	0Dh		;ASCII carrriage return
LF:	EQU	0Ah		;ASCII line feed
EOS:	EQU	'$'		;BDOS End of string
TAB:	EQU	9		;ASCII horizontal tab
ERRCD:	EQU	0FFh		;BDOS error code





;	BDOS function equates.

PRTSTR:	EQU	09	;Print String    DE = buffer address.
RDCB:	EQU	10	;Read console buffer   DE = buffer address.
OPEN:	EQU	15	;Open file   DE = FCB address.
READS:	EQU	20	;Read sequential file    DE = FCB.
SETDMA:	EQU	26	;Set DMA address    DE = DMA address.

;	Page zero locations.

BDOSV:	EQU	5	;BDOS JUMP ADDRESS.
DFCB:	EQU	005Ch	;Default FCB address.
DBUF:	EQU	0080h	;Default DMA buffer.







	ORG	100h


FORMAT:
	PUSH	PSW
	PUSH	B
	PUSH	D
	PUSH	H
	LXI	H,0
	DAD	SP
	SHLD	SYSTK		;save system stack


	LXI	SP,STACK
	LXI	D,SMESSG	;Output sign-on message
	MVI	C,PRTSTR
	CALL	BDOSV

	CALL	INITBF		;intialize data buffer
FORM1:	CALL	INITL		;Intialize for formatting
	LDA	DTYPE
	MOV	B,A
	ANI	TYPEDRV
	JZ	FORM2		;If floppy disk
	MOV	A,B
	ANI	TYPEN48+TYPEN96
	JNZ	FORM2
	CALL	FORMH		;Format hard disk
	JNZ	FORM1		;If new disk requested
	JMP	SYSRET

FORM2:	CALL	FORMF		;Format floppy disk
	JNZ	FORM1		;If new disk requested
	JMP	SYSRET


;	Return to system gracefully.

SYSRET:	LHLD	SYSTK
	SPHL
	POP	H
	POP	D
	POP	B
	POP	PSW
	RET			;return to system

SMESSG:	DB	CR,LF,LF,LF
	DB	'Data Technology Disk Format Program'
	DB	' Version ',VERS/10+'0','.',VERS mod 10 + '0'
	DB	CR,LF,EOS




;	INITBF - Intialize data buffer with constant pettern.

INITBF:
	MVI	C,0E5h
	LHLD	BDOSV+1		;Get buffer end address
	XCHG
	LXI	H,BUFFER
IBF1:	MOV	M,C		;Set a byte
	INX	H
	MOV	A,D
	CMP	H
	JNZ	IBF1
	MOV	A,E
	CMP	L
	JNZ	IBF1		;If entire buffer not set

	RET



;	INITL - Get parameters from operator.

INITL:
	XRA	A		;Reset E5FLAG
	STA	E5FLAG
INIL1:	LXI	D,DMESSG	;Output disk selection message
	CALL	INFCRT
	STA	LETTER
	SUI	'0'
	JM	INIL1		;If invalid entry
	CPI	4
	JP	INIL1		;If invalid entry
	RRC
	RRC
	RRC
	STA	DRVNO

	CALL	DDTYPE		;Determine Disk type
	JNZ	INIL4
	LDA	DTYPE
	MOV	B,A
	ANI	TYPEDRV
	JZ	INILf		;If floppy disk unit
	MOV	A,B		; or mini floppy
	ANI	18h
	JNZ	INILf

	XRA	A
INIL2:	LXI	D,HDMESG
	CALL	INFCRT		;Get hard disk response
	CPI	'Y'
	RNZ

INIL3:	LXI	D,INTMSG	;Get interleave code
	CALL	INFCRT
	SUI	'1'
	JM	INIL3		;If invalid interleave code
	CPI	16
	JP	INIL3		;If invlaid interleave code
	INR	A
	STA	HDILC		;Save interleave code

	RET

INIL4:
	LXI	D,ADTMSG
	MVI	C,PRTSTR
	CALL	BDOSV
	JMP	INITL


INILf:	LXI	D,DENMSG	;Output density seclection
	CALL	INFCRT
	SUI	'1'
	JM	INILf		;If invalid density
	CPI	2
	JP	INILf		;If invalid density
	STA	FPDEN

INILg:	LXI	D,SIDMSG	;Get number of sides
	CALL	INFCRT
	SUI	'1'
	JM	INILg		;If invalid number of sides
	CPI	2
	JP	INILg		;If invalid number of sides
	MOV	C,A
	LDA	FPDEN
	ADD	A
	ADD	C
	STA	FPSLV		;Save format selection value
	RET

DMESSG:	DB	CR,LF
	DB	'Select Drive (0, 1, 2, 3): ',EOS

DENMSG:	DB	CR,LF
	DB	'Select a sector size:'
	DB	CR,LF
	DB	'     1) 128 Byte Single density.'
	DB	CR,LF
	DB	'     2) 256 Byte Double density.'
	DB	CR,LF
	DB	'Sector Size: ',EOS

HDMESG:	DB	CR,LF
	DB	'This program will format the entire hard disk.',CR,LF
	DB	'Do you wish to continue (Y or N)? ',EOS

ADTMSG:	DB	CR,LF,'Assign Drive Type error.',EOS

INTMSG:	DB	CR,LF
	DB	'Enter interleave value (1--16): '
	DB	EOS

SIDMSG:	DB	CR,LF
	DB	'Enter number of sides (1 or 2): '
	DB	EOS





;	FORMH - Format a hard disk unit.

FORMH:
	CALL	SCMND		;Set command buffers
	LDA	HDILC		;Set interleave code
	STA	CIOFDC+4
	LXI	H,CIOSTC
	CALL	EXEC		;Output command buffer
	CZ	WAITF		;Wait completion
	MOV	A,C
	ANI	FERR
	JZ	FRMH1		;If unit is ready
	LXI	D,UNDMSG	;Unit not available
	MVI	C,PRTSTR
	CALL	BDOSV
	ORI	0FFh
	RET

FRMH1:

	LXI	D,BFDMSG		;Output message
	MVI	C,PRTSTR
	CALL	BDOSV

	LXI	H,CIOFDC
	CALL	EXEC		;Output Command
	CZ	WAITF		;Wait for completion
	MOV	A,C
	ANI	FERR
	JZ	FRMH2		;If no errors
	LXI	H,CIOFDC
	CALL	ERROR		;Print error message
	JMP	FORMH

FRMH2:
	CALL	FRME5		;Fill disk with E5s
	JC	FORMH		;Error
	RET


FRME5:
	LDA	E5FLAG		;Is data E5?
	CPI	0E5h
	JZ	FRMH7
	ORA	A		;No.  Has data been checked?
	JNZ	FRMH12
	LXI	H,0
	SHLD	CIORED+2
	LXI	H,CIORED	;No.  Read a sector.
	LXI	D,BUFFER
	CALL	RDISK
	MOV	A,C
	ANI	FERR
	JZ	FRMH3
	LXI	H,CIORED
	CALL	ERROR
	STC
	RET
FRMH3:
	LDA	BUFFER		;Set E5FLAG
	ORA	A
	JNZ	FRMH4
	INR	A
FRMH4:
	STA	E5FLAG
	CPI	0E5h		;Is data E5?
	JZ	FRMH12
	CALL	INITBF		;No.  Set buffer to E5s
	LHLD	BDOSV+1		;Compute # sectors in buffer
	LXI	D,-BUFFER
	DAD	D
	LDA	DTYPE
	ANI	TYPESEC
	RRC
	MOV	B,A
	MVI	D,3
	CALL	DBLSHR
FRMH5:
	DCR	B
	JM	FRMH6
	MVI	D,1
	CALL	DBLSHR
	JMP	FRMH5
FRMH6:
	MOV	A,L
	STA	CIOWRT+4	;# SECTORS
	XCHG
	LXI	H,0
	SHLD	CIOWRT+2
FRMH7:
	PUSH	D
	LXI	H,CIOWRT
	LXI	D,BUFFER
	CALL	WDISK		;Output  buffer
	POP	D
	MOV	A,C
	ANI	FERR
	JZ	FRMH8		;If no errors
	LXI	H,CIOWRT
	CALL	ERROR
	STC
	RET

FRMH8:
	PUSH	D		;Increment logical address
	LXI	H,CIOWRT+2
	MOV	D,M		;It's in reverse order
	INX	H
	MOV	E,M
	POP	H
	XCHG
	DAD	D
	PUSH	D
	XCHG
	LXI	H,CIOWRT+1
	JNC	FRMH9
	INR	M
FRMH9:
	INX	H
	MOV	M,D
	INX	H
	MOV	M,E
	LXI	D,ESECTOR	;Done?
	LXI	H,CIOWRT+1
	MOV	A,M
	ANI	1Fh
	XCHG
FRMH10:
	CMP	M
	JZ	FRMH11
	POP	D
	JMP	FRMH8
FRMH11:
	INX	D
	INX	H
	DCR	B
	LDAX	D
	JNZ	FRMH10

FRMH12:
	LXI	D,FCMSG
	CALL	INFCRT
	CPI	CR
	RET

UNDMSG:	DB	CR,LF,'Unit is not present.',CR,LF,EOS

BFDMSG:	DB	CR,LF,'Begin formatting hard disk.'
	DB	CR,LF,EOS

FNAMSG:	DB	CR,LF,'Function is not presently available.'
	DB	CR,LF,EOS




;	FORMF - Format a floppy disk unit.

FORMF:
	CALL	SCMND		;Set command buffers
	MVI	A,1		;Set interleave code
	STA	CIOFDC+4
	LXI	H,CIOSTC
	CALL	EXEC		;Output command buffer
	CZ	WAITF		;Wait completion
	MOV	A,C
	ANI	FERR
	JZ	FRMF1		;If unit is ready
	LXI	D,NRYMSG	;Output not ready message
	CALL	INFCRT
	JMP	FORMF		;retry on any character

FRMF1:
	LDA	FPSLV		;Get selection value
	MOV	E,A
	MVI	D,0
	LXI	H,FPYTFC
	LDA	DTYPE
	MOV	B,A
	ANI	TYPEDRV
	JZ	FRMF2
	LXI	H,M48TFC
	MOV	A,B
	ANI	TYPEN48
	JNZ	FRMF2
	LXI	H,M96TFC
FRMF2:
	DAD	D
	MOV	A,M
	STA	CIOFSC+5
	LXI	H,CIOFSC
	CALL	EXEC		;Output Command
	CZ	WAITF		;Wait function complete

	LXI	D,FDKMSG
	MVI	C,PRTSTR
	CALL	BDOSV		;Output format disk
	LXI	H,CIOFDC
	CALL	EXEC		;Output Command
	CZ	WAITF		;Wait for completion
	MOV	A,C
	ANI	FERR
	JZ	FRMF3		;If no errors
	LXI	H,CIOFDC
	CALL	ERROR		;PRINT ERROR MESSAGE
	JMP	FORMF

FRMF3:
	LHLD	ESECTOR		;Fill 1/4th of disk with E5s
	MVI	D,2
	CALL	DBLSHR
	SHLD	ESECTOR
	CALL	FRME5
	JC	FORMF
	RZ			;If request to return to CP/M
	CPI	'F'
	JZ	FORMF		;If request for another
	RET
;	Track format code tables (indexed by density*2+# sides)
;
FPYTFC:	DB	0,1,6,7
M48TFC:	DB	0,1,4,5
M96TFC:	DB	2,3,6,7
;

FCMSG:
	DB	CR,LF,'Function Complete.'
	DB	CR,LF,LF
	DB	'Type RETURN to return to CP/M, '
	DB	'or F to Format another: '
	DB	EOS

NRYMSG:	DB	CR,LF
	DB	'Disk unit is not ready. ',CR,LF
	DB	'Please ready unit and hit RETURN. '
	DB	EOS

FDKMSG:	DB	CR,LF,'Formatting the entire disk.'
	DB	CR,LF,EOS




;	INFCRT - Output message and input from console.
;
;	ENTRY	DE = message address.
;
;	EXIT	A = First character entered (upper case).

INFCRT:
	MVI	C,PRTSTR
	CALL	BDOSV		;Output message
	LXI	D,INBUFX
	MVI	C,RDCB
	CALL	BDOSV
	LDA	INBUFX+1
	ANA	A
	MVI	A,CR
	RZ
	LDA	INBUF
	CPI	'A'+20h
	RC			;If upper case
	CPI	'Z'+20h+1
	RNC			;If upper case
	SUI	20h		;Fold to uppercase
	RET

INBUFX	DB	10,0
INBUF	DB	0,0,0,0,0,0,0,0,0,0




;	DDTYPE - determine disk type (hard or floppy).

DDTYPE:
	XRA	A
	STA	CIOFSC+5
	LDA	DRVNO
	STA	CIOFSC+1
	STA	CIOADT+1
	LXI	H,DT
	LXI	D,6
	MVI	B,NLUN
DDTYP1:
	CMP	M
	JZ	DDTYP2
	DAD	D
	DCR	B
	JNZ	DDTYP1
	ORI	0FFH		;Configuration error.
	RET
DDTYP2:
	INX	H
	MOV	A,M
	STA	DTYPE
	INX	H
	MOV	A,M
	STA	CIOADT+4	;ASSIGN DRIVE TYPE
	INX	H		;Compute end sector
	MOV	C,M
	INX	H
	MOV	E,M
	INX	H
	MOV	D,M
	CALL	MUL
	XCHG
	LXI	H,ESECTOR
	MOV	M,B
	INX	H
	MOV	M,D
	INX	H
	MOV	M,E
	LDA	CIOADT+4	;Does controller have Class 6,
	CPI	0FFh		;  op code 1?
	RZ
	LXI	H,CIOADT
	CALL	EXEC		;Output Command
	CZ	WAITF		;Wait function complete
	MOV	A,C
	ANI	FERR		;Mask for errors
	RET
;
;	Drive Type table (indexed by LUN)
;
DT:
	IF	LUN0
	DB	0 SHL 5
	DB	LUN0TYPE+TYPEN48*N48M0+TYPEN96*N96M0
	DB	LUN0DAT,LUN0NLD
	DW	LUN0SEC
	ENDIF
	IF	LUN1
	DB	1 SHL 5
	DB	LUN1TYPE+TYPEN48*N48M1+TYPEN96*N96M1
	DB	LUN1DAT,LUN1NLD
	DW	LUN1SEC
	ENDIF
	IF	LUN2
	DB	2 SHL 5
	DB	LUN2TYPE+TYPEN48*N48M2+TYPEN96*N96M2 
	DB	LUN2DAT,LUN2NLD
	DW	LUN2SEC
	ENDIF
	IF	LUN3
	DB	3 SHL 5
	DB	LUN3TYPE+TYPEN48*N48M3+TYPEN96*N96M3
	DB	LUN3DAT,LUN3NLD
	DW	LUN3SEC
	ENDIF
;




;	SCMND - Set drive into command buffers.

SCMND:
	LDA	DRVNO
	LXI	H,CIOFSC+1
	LXI	D,6
	MVI	B,CIONUM
SCMD1:	MOV	M,A
	DAD	D
	DCR	B
	JNZ	SCMD1		;If not all buffer set
	RET





;	MOVDTA - Move data utility program.
;
;	ENTRY	H = Source field.
;		DE = Destination field.
;		BC = number of bytes.

MOVDTA:
	MOV	A,M
	STAX	D
	INX	H
	INX	D
	DCX	B
	MOV	A,B
	ANA	C
	CPI	0FFh		;-1
	JNZ	MOVDTA
	RET



;MULTIPLY SINGLE X DOUBLE
;
;	ENTRY:	DE = MULTIPLICAND
;		 C = MULTIPLIER
;	EXIT:	HL = PRODUCT (LEAST SIGNIFICANT)
;		 B = PRODUCT (MOST SIGNIFICANT)
;
MUL:	LXI	H,0
	MOV	A,C
	ORA	A
	RZ
	MVI	B,0
MUL1:	DAD	D
	JNC	MUL2
	INR	B
MUL2:
	DCR	A
	JNZ	MUL1
	RET
;
;
;Shift HL right by (D)
;
DBLSHR:
	XRA	A
	MOV	A,H
	RAR
	MOV	H,A
	MOV	A,L
	RAR
	MOV	L,A
	DCR	D
	JNZ	DBLSHR
	RET
;
;
;
CIOBGN:
CIOFSC:	DB	FSCMD,0,0,0,0,0
CIOWRT:	DB	WTCMD,0,0,0,1,0C0h
CIORED:	DB	RDCMD,0,0,0,1,0
CIOESC:	DB	ESCMD,0,0,0,0,0
CIOSTC:	DB	STCMD,0,0,0,0,0
CIOFDC:	DB	FDCMD,0,0,0,0,0
CIOADT:	DB	ADCMD,0,0,0,0,0
CIONUM:	EQU	($-CIOBGN)/6	;Number of entries above




SYSTK:	DW	0		;Hold stack



	DS	50
STACK:	DS	1





LETTER:	DB	0,EOS

STRACK:	DW	0		;Starting track number
CTRACK:	DW	0		;Current track number
ETRACK:	DW	0		;Ending track number
ESECTOR: DS	3		;Ending sector



DRVNO:	DB	0
DTYPE:	DB	0
HDFTP:	DB	0		;Hard disk format type
HDILC:	DB	0		;Hard disk interleave code
FPDEN:	DB	0		;floppy Density selection
FPSLV:	DB	0		;floppy format selection value

E5FLAG:	DB	0		;Format data value



;	Disk I/O Routines
;
;
	IF	I696
;	E X E C

EXEC:	MVI	B,BUSY		;Wait for not busy.
	MVI	C,BUSY and (not BUSY)
	CALL	WAITM
	RNZ
	

	MVI	A,SLCT		;Alert controller
	OUT	DIO+1
EXEC1:
	MOV	C,B		;Wait for controller busy
	CALL	WAITM
	RNZ

	MVI	A,DODTA		;Enable data in
	OUT	DIO+1

EXEC2:	IN	DIO+2		;Get status
	XRI	0FFh
	JM	EXEC2		;If not requesting next byte
	ANI	CMND+DIROUT
	JNZ	EXEC3		;If CMND or DIROUT false
	MOV	A,M
	INX	H
	OUT	DIO		;Send byte from command buffer
	JMP	EXEC2

EXEC3:	CMP	A		;Z:=1
	RET
;
;
;
;
;	WDISK - Output from memory buffer.
;	ENTRY:	HL = COMMAND BUFFER ADDRESS
;		DE = DATA BUFFER ADDRESS
;

WDISK:	CALL	EXEC		;Output command
	RNZ			;Return if timeout
WDISK1:	IN	DIO+2		;Read status
	ORA	A
	JP	WDISK1		;If request is present
	ANI	CMND
	JNZ	GCMPS		;If done with transfer
	LDAX	D		;Get the data byte
	OUT	DIO
	INX	D		;Advance buffer address
	JMP	WDISK1
;
;
;
;
;	RDISK - Input to memory buffer.
;
;	Entry:	HL = command buffer address
;		DE = data buffer address

RDISK:	CALL	EXEC
	RNZ			;Return if timeout
RDISK1:	IN	DIO+2		;Read status
	ORA	A
	JP	RDISK1		;If request is present
	ANI	CMND
	JNZ	GCMPS
	IN	DIO
	STAX	D
	INX	D
	JMP	RDISK1
;
;
;
;
;	WAITF - Wait for function to complete.

WAITF:	MVI	B,REQ+CMND	;Wait for both REQ and CMND
	MOV	C,B
	CALL	WAITM
	RNZ
;
;	Get completion status.

GCMPS:	IN	DIO		;Get completion status
	MOV	C,A

GCMP1:	IN	DIO+2
	ORA	A
	JP	GCMP1		;If REQ not set

	MOV	B,A
	IN	DIO		;Get message byte
	RET
	ENDIF
;

;
;
;
	IF	I796
;	EXEC - Output the command
;
;	Enter:	HL is the command buffer address
;		DE - data transfer address.

EXEC:
	MOV	A,E		;Output DMA address
	OUT	DIO+2
	MOV	A,D
	OUT	DIO+3
	MOV	A,L
	OUT	DIO+4
	MOV	A,H
	OUT	DIO+5
	MVI	A,0
	OUT	DIO+6
	OUT	DIO+7
	OUT	DIO
	CMP	A		;Z:=1
	RET


;	Disk read/write
;
;	Entry:	same as EXEC
;
RDISK:
WDISK:	CALL	EXEC
	RNZ			;Return if timeout

;	WAITF - Wait until transfer done
;
;	Enter:	none
;	Exit:	when transfer completed

WAITF:	MVI	B,CMDDON	;Wait for CMDDON
	MOV	C,B
	CALL	WAITM
	RNZ			;Return if timeout
;

;	GCMPS - Get completion status
;
;	Enter:	none
;	Exit:	Status in C
GCMPS:	IN	DIO+1
	MOV	C,A
	RET
	ENDIF

;	WAITM - Wait for controller with timeout
;
;	Entry:	B=Status mask
;		C=Status value
;	Exit:	Z=1 if OK, else timeout with A=C=TERR
;
WAITM:
	PUSH	D		;Save D
	PUSH	H
	LXI	H,138		;Two minute timeout
	LXI	D,0		;Max wait @4MHZ is 868 ms
WAITML:
	IF	I696
	IN	DIO+2
	ENDIF
	IF	I796
	IN	DIO
	ENDIF
	ANA	B		;Mask wait bits
	CMP	C		;Check value
	JZ	WAITM1
	DCX	D		;Not ready.  Decrement time
	MOV	A,D
	ORA	E
	JNZ	WAITML
	DCX	H
	MOV	A,H
	ORA	L
	JNZ	WAITML
	MVI	B,0		;Timeout
	MVI	A,TERR
	ORA	A
WAITM1:
	POP	H
	POP	D		;Restore D
	MOV	C,A		;Return status in C
	RET
;	DTC Error Print Routine
;
;Called at completion of disk command when error status is returned.
;
;	Entry:	HL = Address of Command Descriptor Block
;		C = Status byte
;
ERROR:
	PUSH	B		;Save status
	PUSH	H		;SAVE ADDRESS OF CDB
	MOV	A,M		;GET CLASS CODE
	ANI	0E0H
	RAL			;MAKE CDB LENGTH INDEX
	RAL
	RAL
	MOV	E,A		;GET CDB LENGTH
	MVI	D,0
	LXI	H,CDBLEN
	DAD	D
	MOV	C,M
	POP	H		;RESTORE CDB ADDRESS
	PUSH	H
	LXI	D,ERRCDB
	CALL	PUTHEX		;BUILD CDB FOR PRINT
	LXI	D,EHEAD		;Print header
	MVI	C,PRTSTR
	CALL	BDOSV
	POP	H		;Get status
	POP	B
	PUSH	H
	MOV	A,C		;Timeout?
	ANI	TERR
	LXI	D,TOMSG
	JNZ	ERROR1
	LXI	H,CIOESC	;No. READ ERROR SENSE
	LXI	D,SENSE
	CALL	RDISK
	LXI	D,ESENSE
	MVI	C,PRTSTR
	CALL	BDOSV
	LXI	D,ESENS1
	LXI	H,SENSE
	MOV	A,M
	MVI	C,PRTSTR
	ORA	A
	CM	BDOSV
	LXI	D,ETYPE
	LXI	H,SENSE		;BUILD ERROR SENSE MESSAGE
	MOV	A,M
	RAR
	RAR
	RAR
	RAR
	ANI	3
	CALL	HEXASC
	LXI	D,ECODE
	MOV	A,M
	CALL	HEXASC
	LXI	D,ELUN
	INX	H
	MOV	A,M
	RLC
	RLC
	RLC
	ANI	7
	CALL	HEXASC
	MOV	A,M
	ANI	01FH
	MOV	M,A
	LXI	D,ELAD
	MVI	C,3
	CALL	PUTHEX
	LXI	D,ESENS2	;PRINT MESSAGE
ERROR1:
	MVI	C,PRTSTR
	CALL	BDOSV
	POP	H		;RESTORE CDB ADDRESS
	RET
;
;

;	PUT HEXADECIMAL STRING
;
;	ENTRY:	HL = ADDRESS OF HEX NUMBER STRING
;		DE = ADDRESS OF HEX ASCII STRING
;		 C = NUMBER OF BYTES TO CONVERT
;
PUTHEX:	CALL	HEXBYT
	MVI	A,' '
	STAX	D
	INX	D
	DCR	C
	JNZ	PUTHEX
	MVI	A,EOS
	STAX	D
	RET
;
;
HEXBYT:	MOV	A,M
	RAR
	RAR
	RAR
	RAR
	CALL	HEXASC
	MOV	A,M
	INX	H
HEXASC:	ANI	0FH
	ADI	090H
	DAA
	ACI	040H
	DAA
	STAX	D
	INX	D
	RET
;
;
;	CDB length table (indexed by class)
CDBLEN:	DB	6,10,0,0,0,0,6,6
;
EHEAD:	DB	CR,LF,LF,'Disk error:'
	DB	CR,LF,'Command Descriptor:',TAB,TAB
ERRCDB:	DS	31
;
TOMSG:	DB	CR,LF,TAB,TAB,TAB,TAB,'Timeout',EOS
ESENSE:	DB	CR,LF,'Error Sense:',EOS
ESENS1:	DB	CR,LF,TAB,TAB,TAB,TAB,'Block address valid.',EOS
ESENS2:	DB	CR,LF,TAB,'Error type:',TAB,TAB
ETYPE:	DS	1
	DB	CR,LF,TAB,'Error code:',TAB,TAB
ECODE:	DS	1
	DB	CR,LF,TAB,'Logical unit:',TAB,TAB
ELUN:	DS	1
	DB	CR,LF,TAB,'Logical address:',TAB
ELAD:	DS	4
SENSE:	DS	4
;
BUFFER:	EQU	$
;
	END
