$title(Bootstrap Error Routine)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;	TITLE:		bserr.inc
;			Bootstrap Error Routine code and configuration macros
;
;	DATE:		25 Sept 1985
;
;	ABSTRACT:	Include file to generate bootstrap Error Routine
;			Optionally generates code for to display error messages.
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%SET (is_console, 0)
%*DEFINE(CONSOLE) (
	%SET(is_console, -1)
)

%SET (is_text, 0)
%*DEFINE(TEXT) (
	%SET(is_text, -1)
	%SET(is_console, -1)
)

%SET (is_list, 0)
%*DEFINE(LIST) (
	%SET(is_list, -1)
	%SET(is_text, -1)
	%SET(is_console, -1)
)
%SET(made_choice, 0)

%SET (is_halt, 0)
%*DEFINE(HALT) (
	%SET(is_halt, -1)
	%IF (%made_choice) THEN (
		%error ; More than ONE invocation of HALT, AGAIN and/or INT3 is invalid
	) FI
	%SET(made_choice, -1)
)

%SET (is_again, 0)
%*DEFINE(AGAIN) (
	%SET(is_again, -1)
	%IF (%made_choice) THEN (
		%error ; More than ONE invocation of HALT, AGAIN and/or INT1/3 is invalid
	) FI
	%SET(made_choice, -1)
)

%SET (is_int1, 0)
%*DEFINE(INT1) (
	%SET(is_int1, -1)
	%IF (%made_choice) THEN (
		%error ; More than ONE invocation of HALT, AGAIN and/or INT1/3 is invalid
	) FI
	%SET(made_choice, -1)
)

%SET (is_int3, 0)
%*DEFINE(INT3) (
	%SET(is_int3, -1)
	%IF (%made_choice) THEN (
		%error ; More than ONE invocation of HALT, AGAIN and/or INT1/3 is invalid
	) FI
	%SET(made_choice, -1)
)

%*DEFINE(END) (

	%IF(NOT %made_choice) THEN (
		%error ; HALT, AGAIN, or INT1/3 MUST be specified in the configuration file
	) FI

		name bserror
		public bserror 

;
;	Define the error messages
;

	IO_ERROR		equ 01h
	DEVICE_NOT_READY	equ 11h
	DEVICE_NEXIST		equ 12h
	NO_DEVICE_READY		equ 13h
	FILE_NOT_FOUND		equ 21h
	CHECKSUM_ERROR		equ 22h
	PREMATURE_EOF		equ 23h
	NO_START_ADDRESS	equ 24h

error_code			equ [bp+6]; error code on pl/m style stack

	extrn	co: far
	extrn	firststage: far

code		segment	public 'CODE'
%IF (%is_list) THEN (
		extrn	device_table:far
) FI
code		ends

code_error segment byte public 'CODE'

		assume cs: code_error, ds: code_error
bserror proc	far

	push	bp
	mov	bp, sp
	mov	cx, word ptr error_code; get the error into cx

%IF (%is_console) THEN (	; console
	mov	ax, seg mess01
	mov	ds, ax
	lea	bx, ermess			; print bootstrap error
	call	print

	lea	bx, mess01			; IO ERROR
	cmp	cl, IO_ERROR
	je	printnow

	lea	bx, mess11			; DEVICE NOT READY
	cmp	cl, DEVICE_NOT_READY
	je	printnow

	lea	bx,mess12			; DEVICE DOES NOT EXIST
	cmp	cl, DEVICE_NEXIST
	je	printnow

	lea	bx,mess13			; NO_DEVICE_READY
	cmp	cl, NO_DEVICE_READY
	je	printnow

	lea	bx, mess21			; FILE NOT FOUND
	cmp	cl, FILE_NOT_FOUND
	je	printnow

	lea	bx, mess22			; CHECKSUM ERROR
	cmp	cl, CHECKSUM_ERROR
	je	printnow

	lea	bx, mess23			; PREMATURE END OF FILE
	cmp	cl, PREMATURE_EOF
	je	printnow

	lea	bx, mess24			; NO START ADDRESS FOUND IN FILE
	cmp	cl, NO_START_ADDRESS
	je	printnow
;
;	Called with unknown code
;
	lea	bx, unknown
;
;	print the message and then a cr,lf,lf and go to the 957
;

printnow:
	push	cx; save the code for later
	call	print
	lea	bx,		crlf
	call	print
	pop	cx
%IF (%is_list) THEN (
;
;	check for device doesn't exist error
;
	cmp	cx,DEVICE_NEXIST
	jne	done
	lea	bx, avail; print the available devices title
	call	print		
	mov	ax, 0	; initialize the list counter
	push	ax	; save it on the stack
	mov	ax, seg device_table
	mov	es, ax
	mov	si, offset device_table	; print the list of possible devices
list_loop:
	mov	cl, es:byte ptr [si]	; get the name length in cl
	inc	si				; first true character
	mov	ch, 0
	or	cx, cx			; check for null name
	jz	next_dev
	cmp	cl, 0FFH		; end delimeter
	je	end_of_table
ploop:
	lods	es:byte ptr [si]; load character from device name
	push	es
	push	ax			; al has the character in it
	call	co			; print it
	pop	es
	pop	ax				; increment the line count
	inc	ax
	push	ax
	loop	ploop
next_dev:
	lea	bx, spaces		; print spaces in between
	call	print
	pop	ax
	add	ax, 3
	push	ax			; if more than 60 chars on this line
	cmp	ax,60			; then print a new line
	jb	same_line
	lea	bx, crlf
	call	print
	pop	ax				; clear the count
	xor	ax,ax
	push	ax
same_line:
	add	si,14			; skip over other data in the table
	jmp	list_loop
end_of_table:			; all printed
	lea	bx, crlf
	call	print
) FI	

done:
%IF(%is_halt) THEN (
	hlt		) FI
%IF(%is_again) THEN (
	jmp		firststage	) FI
%IF(%is_int1) THEN (
	int 1	)FI
%IF(%is_int3) THEN (
	int 3	)FI

bserror endp

;
;	This routine prints the string pointed to by BX.
;
print	proc	near
	mov	al, byte ptr [bx]; get a byte from the message
	cmp	al, 0			; if a null then done
	jnz	continue
	ret
Continue:
	push	es
	push	ax			; put the character where co wants it
	call	co			; print it
	pop	es
	inc	bx				; next character
	jmp	print
print	endp

mess01		db '01'
%IF (%is_text) THEN (			db ':  I/O error') FI
			db 0

mess11		db '11'
%IF (%is_text) THEN (			db ':  Device not ready') FI
			db 0

mess12		db '12'
%IF (%is_text) THEN (			db ':  Device does not exist') FI
			db 0
			
mess13		db '13'
%IF (%is_text) THEN (			db ':  No device is ready') FI
			db 0

mess21		db '21'
%IF (%is_text) THEN (			db ':  File not found') FI
			db 0

mess22		db '22'
%IF (%is_text) THEN (			db ':  Bad checksum') FI
			db 0

mess23		db '23'
%IF (%is_text) THEN (			db ':  Premature end of file') FI
			db 0

mess24		db '24'
%IF (%is_text) THEN (			db ':  No start address in load file') FI
			db 0


%IF (%is_text) THEN (
ermess		db 0dh,0ah,'Bootstrap Error ',0
) ELSE (
ermess		db 0dh,0ah,'E ',0
) FI
crlf		db 0dh,0ah,0
%IF (%is_text) THEN (
unknown		db 'of unknown type',0
) ELSE (
unknown		db '??',0
) FI
%IF (%is_list) THEN (
avail		db 'Available devices:',0dh,0ah,0
spaces		db '   ',0
) FI

; No console code follows

) ELSE (
	%IF(%is_halt) THEN (
		hlt		) FI
	%IF(%is_again) THEN (
		jmp		firststage	) FI
	%IF(%is_int3) THEN (
		int 3	)FI
bserror endp
) FI

code_error ends

	end)
	
