;	Figure 9-5
;
;	This shows slightly more user-friendly error processor
;	for disk errors than that shown in the enhanced BIOS
;	in Figure 8-10. 
;	This version outputs a recommended course of action 
;	depending on the nature of the error detected.
;	Code that remains unchanged from Figure 8-10 has been
;	abbreviated.
;
;	Dummy Equates and data declarations needed to get
;	an error free assembly of this example.
;
Floppy$Read$Code	EQU	01H	;Read Command for controller
Floppy$Write$Code	EQU	02H	;Write Command for controller
;
Disk$Hung$Flag:		DB	0	;Set NZ when Watchdog timer times
					;  out.
Disk$Timer		EQU	600	;10 seconds delay (16.66ms tick)
;
Disk$Status$Block	EQU	43H	;Address in memory where controller
					;  returns status
					;Values from controller command table
Floppy$Command:		DB	0
Floppy$Head:		DB	0
Floppy$Track:		DB	0
Floppy$Sector:		DB	0

Deblocking$Required:	DB	0	;Flag set by SELDSK according
					;  to selected disk type

Disk$Error$Flag:	DB	0	;Error flag returned to BDOS
;
In$Buffer$Disk:		DB	0	;Logical disk Id. relating to current
					;  disk sector in deblocking buffer
;
;	Equates for Messages
;
BELL	EQU	07H	;Sound terminal Bell
CR	EQU	0DH	;Carriage Return
LF	EQU	0AH	;Line Feed
;
BDOS	EQU	5	;BDOS Entry Point (for system reset)
;
;
;
;
No$Deblock$Retry:
	;----------------------------------------------------
	; Omitted code to setup disk controller command table
	; and initiate the disk operation
	;----------------------------------------------------
	JMP	Wait$For$Disk$Complete
;
;
Write$Physical:			;Write contents of Disk Buffer to
				;  correct sector.
	MVI	A,Floppy$Write$Code	;Get Write Function code
	JMP	Common$Physical	;Go to common code
Read$Physical:			;Read previously selected Sector
				;  into Disk Buffer.
	MVI	A,Floppy$Read$Code	;Get Read Function code
Common$Physical:
	STA	Floppy$Command	;Set command table

;
Deblock$Retry:			;Re-entry point to re-try after error
	;---------------------------------------------------
	; Omitted code sets up disk controller command block
	; and initiates the disk operation
	;---------------------------------------------------
;
Wait$For$Disk$Complete:		;Wait until Disk Status Block indicates
				;  operation has completed, then check
				;  if any errors occurred.
				;On entry HL -> Disk Control byte
	XRA	A			;Ensure hung flag clear
	STA	Disk$Hung$Flag

	LXI	H,Disk$Timed$Out	;Setup Watchdog timer
	LXI	B,Disk$Timer		;Time delay
	CALL	Set$Watchdog
Disk$Wait$Loop:
	MOV	A,M			;Get control byte
	ORA	A
	JZ	Disk$Complete		;Operation done

	LDA	Disk$Hung$Flag		;Also check if timed out
	ORA	A
	JNZ	Disk$Error		;Will be set to 40H

	JMP	Disk$Wait$Loop

Disk$Timed$Out:			;Control arrives here from Watchdog
				;  routine itself - so this is effectively
				;  part of the interrupt service routine.
	MVI	A,40H			;Set Disk Hung error code
	STA	Disk$Hung$Flag		;  into error flag to pull
					;  control out of loop
	RET				;Return to Watchdog routine

Disk$Complete:
	LXI	B,0			;Reset Watchdog timer
					;HL is irrelevant here
	CALL	Set$Watchdog

	LDA	Disk$Status$Block	;Complete - now check status
	CPI	80H			;Check if any errors occurred
	JC	Disk$Error		;Yes
;
Disk$Error$Ignore:
	XRA	A			;No
	STA	Disk$Error$Flag		;Clear error flag
	RET

;
;	Disk Error Message handling
;
;
Disk$Error$Messages:		;This table is scanned, comparing the
				;  Disk Error Status with those in the
				;  table. Given a match, or even when
				;  then end of the table is reached, the
				;  address following the status value
				;  points to the correct advisory message text.
				;  Following this is the address of an
				;  error description message.
	DB	40H
	DW	Disk$Advice1,Disk$Msg$40
	DB	41H
	DW	Disk$Advice2,Disk$Msg$41
	DB	42H
	DW	Disk$Advice3,Disk$Msg$42
	DB	21H
	DW	Disk$Advice4,Disk$Msg$21
	DB	22H
	DW	Disk$Advice5,Disk$Msg$22
	DB	23H
	DW	Disk$Advice5,Disk$Msg$23
	DB	24H
	DW	Disk$Advice6,Disk$Msg$24
	DB	25H
	DW	Disk$Advice6,Disk$Msg$25
	DB	11H
	DW	Disk$Advice7,Disk$Msg$11
	DB	12H
	DW	Disk$Advice7,Disk$Msg$12
	DB	13H
	DW	Disk$Advice7,Disk$Msg$13
	DB	14H
	DW	Disk$Advice7,Disk$Msg$14
	DB	15H
	DW	Disk$Advice7,Disk$Msg$15
	DB	16H
	DW	Disk$Advice7,Disk$Msg$16
	DB	0			;<== Terminator
	DW	Disk$Advice7,Disk$Msg$Unknown	;Unmatched code
;
DEM$Entry$Size	EQU	5	;Entry size in Error Message Table
;
;
;	Message Texts
;
Disk$Msg$40:	DB	'Hung',0	;Timeout message
Disk$Msg$41:	DB	'Not Ready',0
Disk$Msg$42:	DB	'Write Protected',0
Disk$Msg$21:	DB	'Data',0
Disk$Msg$22:	DB	'Format',0
Disk$Msg$23:	DB	'Missing Data Mark',0
Disk$Msg$24:	DB	'Bus Timeout',0
Disk$Msg$25:	DB	'Controller Timeout',0
Disk$Msg$11:	DB	'Drive Address',0
Disk$Msg$12:	DB	'Head Address',0
Disk$Msg$13:	DB	'Track Address',0
Disk$Msg$14:	DB	'Sector Address',0
Disk$Msg$15:	DB	'Bus Address',0
Disk$Msg$16:	DB	'Illegal Command',0
Disk$Msg$Unknown:	DB	'Unknown',0
;
Disk$EM$1:			;Main disk error message - part 1
		DB	BELL,CR,LF
		DB	'Disk ',0
;
				;Error Text output next
;
Disk$EM$2:			;Main disk error message - part 2
		DB	' Error ('
Disk$EM$Status:	DB	0,0	;Status code in Hex
		DB	')',CR,LF,'     Drive '
Disk$EM$Drive:	DB	0	;Disk Drive code, A,B...
		DB	', Head '
Disk$EM$Head:	DB	0	;Head number
		DB	', Track '
Disk$EM$Track:	DB	0,0	;Track number
		DB	', Sector '
Disk$EM$Sector:	DB	0,0	;Sector number
		DB	', Operation - '
		DB	0		;Terminator
;
Disk$EM$Read:	DB	'Read.',0	;Operation names
Disk$EM$Write:	DB	'Write.',0
;
Disk$Advice0:	DB	CR,LF,'     ',0
Disk$Advice1:	DB	'Check disk loaded, Retry',0
Disk$Advice2:	DB	'Possible hardware problem',0
Disk$Advice3:	DB	'Write enable if correct disk, Retry',0
Disk$Advice4:	DB	'Retry several times',0
Disk$Advice5:	DB	'Reformat disk or use another disk',0
Disk$Advice6:	DB	'Hardware error, Retry',0
Disk$Advice7:	DB	'Hardware or Software error, Retry',0
;
Disk$Advice9:	DB	', or call for help if error persists',CR,LF
;
Disk$Action$Confirm:
		DB	0	;Set to character entered by user
		DB	CR,LF,0
;
;	Disk Error Processor
;
;	This routine builds and outputs an error message.
;	The user is then given the opportunity to :
;
;		R - Retry the operation that caused the error.
;		I - Ignore the error and attempt to continue.
;		A - Abort the program and return to CP/M.
;
Disk$Error:
	PUSH	PSW		;Preserve error code from controller
	LXI	H,Disk$EM$Status	;Convert code for message
	CALL	CAH			;Converts A to hex

	LDA	In$Buffer$Disk		;Convert disk id. for message
	ADI	'A'			;Make into letter
	STA	Disk$EM$Drive

	LDA	Floppy$Head		;Convert head number
	ADI	'0'
	STA	Disk$EM$Head

	LDA	Floppy$Track		;Convert track number
	LXI	H,Disk$EM$Track
	CALL	CAH

	LDA	Floppy$Sector		;Convert sector number
	LXI	H,Disk$EM$Sector
	CALL	CAH

	LXI	H,Disk$EM$1		;Output first part of message
	CALL	Output$Error$Message

	POP	PSW			;Recover error status code
	MOV	B,A			;For comparisons
	LXI	H,Disk$Error$Messages - DEM$Entry$Size
					;HL -> Table - one entry
	LXI	D,DEM$Entry$Size	;For loop below
Disk$Error$Next$Code:
	DAD	D			;Move to next (or first) entry

	MOV	A,M			;Get code number from table
	ORA	A			;Check if end of table
	JZ	Disk$Error$Matched	;Yes - pretend a match occurred
	CMP	B			;Compare to actual code
	JZ	Disk$Error$Matched	;Yes - exit from loop
	JMP	Disk$Error$Next$Code	;Check next code
;
Disk$Error$Matched:
	INX	H			;HL -> Advisory text address
	MOV	E,M
	INX	H
	MOV	D,M			;DE -> Advisory test
	PUSH	D			;Save for later
	
	INX	H			;HL -> Message text address
	MOV	E,M			;Get Address into DE
	INX	H
	MOV	D,M

	XCHG				;HL -> Text
	CALL	Output$Error$Message	;Display explanatory text

	LXI	H,Disk$EM$2		;Display second part of message
	CALL	Output$Error$Message

	LXI	H,Disk$EM$Read		;Choose operation text
					;  (assume a read)
	LDA	Floppy$Command		;Get controller command
	CPI	Floppy$Read$Code
	JZ	Disk$Error$Read		;Yes
	LXI	H,Disk$EM$Write		;No - change address in HL
Disk$Error$Read:
	CALL	Output$Error$Message	;Display operation type

	LXI	H,Disk$Advice0		;Display leading blanks
	CALL	Output$Error$Message

	POP	H			;Recover Advisory text pointer
	CALL	Output$Error$Message

	LXI	H,Disk$Advice9		;Display trailing component
	CALL	Output$Error$Message
;
Disk$Error$Request$Action:		;Ask the user what to do next
	CALL	Request$User$Choice	;Display prompt and get single
					;  character response (folded to 
					;  upper case)
	CPI	'R'			;Retry?
	JZ	Disk$Error$Retry
	CPI	'A'			;Abort
	JZ	System$Reset
	CPI	'I'			;Ignore
	JZ	Disk$Error$Ignore
	JMP	Disk$Error$Request$Action
;
Disk$Error$Retry:			;The decision on where to return to
					;  depends on whether the operation
					;  failed on a deblocked or
					;  non-deblocked drive
	LDA	Deblocking$Required
	ORA	A
	JNZ	Deblock$Retry
	JMP	No$Deblock$Retry
;
System$Reset:				;This is a radical approach, but
					;  it does cause CP/M to restart
	MVI	C,0			;System Reset
	CALL	BDOS

;
;	Omitted subroutines (listed in full in Figure 8-10)
;
Set$Watchdog:		;Set Watchdog timer (to number of "ticks" in BC, and
			;  to transfer control to (HL) if timer hits zero).
CAH:			;Convert A to two ASCII hex characters, storing
			;  the output in (HL) and (HL+1)
Output$Error$Message:	;Display the 00-byte terminated error message 
			;  pointed to by HL. Output is directed only to
			;  those console devices not being used for list
			;  output as well.
Request$User$Choice:	;Display prompt "Enter R, A, I..." and return
			;  single keyboard character (upper case) in A
	RET		;Dummy
