interrupts	segment at 0h	; This is where the disk interrupt
	org	13h*4		; holds the address of its service routine
disk_int	label	dword
interrupts	ends

screen	segment at 0B000h	; A dummy segment to use as the Extra
screen	ends			; Segment so we can write to the display

code_seg	segment
	assume	cs:code_seg
	org	0100h		; ORG = 100h to make this a .COM file
first:	jmp	load_watch	; First time through jump to initialize routine

	msg_part_1	db	'Disk error: '	; Here are the error messages
	msg_part_2	db	'No response Failed Seek NEC Error   '
			db	'Bad CRC SeenDMA Overrun Impos Sector'
			db	'No Addr MarkW. ProtectedErr Unknown '
	first_position	dw	?		; Position of 1st char on screen
	flags		dw	?
	screen_seg_offset dw	0		; 0 for mono, 8000h for graphics
	old_disk_int	dd	?		; Location of old disk interrupt
	ret_addr	label dword		; Used in fooling around with
	ret_addr_word	dw 2 dup(?)		;   the stack

disk_watch	proc	far	; The disk interrupt will now come here
	assume	cs:code_seg
	pushf			; First, call old disk interrupt
	call	old_disk_int
	pushf			; Save the flags in memory location "FLAGS"
	pop	flags		; (cunning name)
	jc	error		; If there was an error, carry flag will have
	jmp	fin		;  been set by Disk Interrupt
error:	push	ax		; AH has the status of the error
	push	cx		; Push all used registers for politeness
	push	dx
	push	di
	push	si
	push	es
	lea	si,msg_part_1	; Always print "Disk Error: " part.
	assume	es:screen	; Use screen as extra segment
	mov	dx,screen
	mov	es,dx
	mov	di,screen_seg_offset	; DI will be pointer to screen position
	add	di,first_position	; Add to point to desired area on screen
	call	write_to_screen		; This writes 12 chars from [SI] to [DI]
	mov	dx,80h			; Initialize for later comparisons
	mov	cx,7			; Loop seven times
e_loop:	cmp	ah,dh			; Are error code and DH the same?
	je	e_found			; If yes, Error has been found
	add	si,12			; Point to next error message
	shr	dh,1			; Divide DH by 2
	loop	e_loop			; Keep going until matched  DH = 0
	cmp	ah,3			; Error code no even number; 3 perhaps?
	je	e_found			; If yes, have found the error
	add	si,12			; Err unknown; unknown error returned
e_found:call	write_to_screen		; Write the error message to the screen
	pop	es		; Restore the registers
	pop	si
	pop	di
	pop	dx
	pop	cx
	pop	ax
fin:	pop	ret_addr_word		; Fooling with the stack. We want to
	pop	ret_addr_word[2]	; preserve the flags but the old flags
	add	sp,2			; are still on the stack. First remove
	push	flags			; return address, then flags. Fill flags
	popf				; from "FLAGS", return to correct addr.
	jmp	ret_addr
disk_watch	endp

write_to_screen	proc	near	; Puts 12 characters on screen
	mov	cx,12		; Loop 12 times
w_loop:	movs	es:byte ptr[di],cs:[si] ; Move to the screen
	mov	al,7		; Move screen attribute into screen buffer
	mov	es:[di],al
	inc	di		; Point to next byte in screen buffer
	loop	w_loop		; Keep going until done
	ret
write_to_screen	endp

load_watch	proc	near	; This procedure initializes everything
	assume	ds:interrupts	; The data segment will be the interrupt area
	mov	ax,interrupts
	mov	ds,ax

	mov	ax,disk_int	; Get the old interrupt service routine
	mov	old_disk_int,ax	; address and put it into our location
	mov	ax,disk_int[2]	; OLD_DISK_INT so we can call it.
	mov	old_disk_int[2],ax

	mov	disk_int,offset disk_watch  ; Now load the address of DskWatch
	mov	disk_int[2],cs		; routine into the disk interrupt

	mov	ah,15		; Ask for service 15 of INT 10h
	int	10h		; This tells us how display is set up
	sub	ah,25		; Move to twenty five places before edge
	shl	ah,1		; Mult. by two (char & attribute bytes)
	mov	byte ptr first_position,ah	; Set screen cursor
	test	al,4		; Is it a monochrome display?
	jnz	exit		; Yes - jump out
	mov	screen_seg_offset,8000h	; No, set up for graphics display
exit:	mov	dx,offset load_watch	; Set up everything but this program to
	int	27h			; stay and attach itself to DOS
load_watch	endp
	code_seg	ends
	end	first	; END "FIRST" so 8088 will go to FIRST first.