;******************************************************
;		  TPERRHAN.ASM 4.03
;		Runtime error recovery
;	 Copyright (c) TurboPower Software 1987.
; Portions copyright (c) Sunny Hill Software 1985, 1986
;     and used under license to TurboPower Software
;		 All rights reserved.
;******************************************************

DATA	SEGMENT BYTE PUBLIC

	;Pascal variables

	EXTRN	SystemContinue : DWORD		;Continuation of system error handler
	EXTRN	UserHandler : DWORD		;Address of user error handler
	EXTRN	ExitCode : WORD 		;Stores error code
	EXTRN	ErrorAddr : DWORD		;Stores error location
	EXTRN	PrefixSeg : WORD		;Stores PSP segment of program

DATA	ENDS

CODE	SEGMENT BYTE PUBLIC

	ASSUME	CS:CODE,DS:DATA

	PUBLIC	Handler
	PUBLIC	ErrHanInt0

;****************************************************** ErrHanInt0

;interrupt 0 entry point

ErrHanInt0 PROC FAR
	STI				;Enable interrupts
	MOV    AX,00C8h 		;Error code for divide by zero
	POP    CX			;Return address into BX:CX
	POP    BX
	POP    DX			;Take flags off stack
					;Control continues in Handler
ErrHanInt0 ENDP

;****************************************************** Handler

;procedure Handler
;recover from Turbo runtime errors
;on entry BX:CX has address to return to, more or less

Handler PROC FAR

	MOV    DX,SEG DATA
	MOV    DS,DX			;Restore DS

	MOV    DX,BX			;Check for Ctrl-Break or normal exit
	OR     DX,CX			;Is return address nil?
	JNZ    CheckErrorClass		;No, check error class
	JMP    NoRecover		;Yes, should not recover

CheckErrorClass:			;Check for classes of run time errors
	CMP    AX,200			;Divide by zero error?
	JZ     CheckInstrClass		;Yes, check for special cases
	CMP    AX,202			;Stack overflow error?
	JZ     NoRecover		;Yes, can't recover
	CMP    AX,203			;Heap overflow error?
	JZ     NoRecover		;Yes, can't recover
	CMP    AX,204			;Floating point error?
	JA     CheckInstrClass		;Yes, check for special cases
	JMP SHORT Recover		;Else recover immediately

CheckInstrClass:			;Check for classes of erring instructions
	MOV    ES,BX			;Error segment
	MOV    DI,CX			;Error offset
	MOV    DX,ES:[DI]		;Get word at error
	MOV    SI,2			;Minimum two bytes for integer DIV
	CMP    DL,0F7h			;Was it a DIV or IDIV?
	JZ     InstrLen 		;Yes, must fix up return address
	CMP    DL,09Bh			;Was it a WAIT?
	JZ     NoRecover		;Yes, can't recover, 8087 wiped out
	CMP    DL,0D8h			;Was it a floating point instruction?
	JB     Recover
	CMP    DL,0DFh
	JA     Recover
	JMP SHORT NoRecover		;Can't recover, 8087 stack wiped out

InstrLen:
	MOV    DL,DH			;Copy second byte into DL
	PUSH   CX
	MOV    CL,6
	SHR    DL,CL			;Get Mod field
	POP    CX
	CMP    DL,3			;Is it register addressing?
	JZ     Fixup			;Yes, no displacement bytes
	OR     DL,DL			;Is it direct addressing?
	JZ     Direct			;Yes, look further
	XOR    DH,DH
	ADD    SI,DX			;Add displacement bytes
	JMP SHORT Fixup
Direct:
	AND    DH,7			;Get r/m field
	CMP    DH,6			;Direct addressing?
	JNZ    Fixup			;No, two byte instruction
	ADD    SI,2			;Else two address bytes
Fixup:
	ADD    CX,SI			;Add length of instruction

Recover:
	MOV    ExitCode,AX		;Save error code
	PUSH   BX			;Return address on stack
	PUSH   CX
	SUB    BX,PrefixSeg
	SUB    BX,10h			;Report relative error segment
	MOV    SI,offset ErrorAddr
	MOV    [SI],CX			;Store error address offset
	MOV    [SI+2],BX		; and segment
	LES    DI,UserHandler		;Get address of user handler
	MOV    AX,ES
	OR     AX,DI
	JZ     Done			;Skip call if pointer nil
	CALL DWORD PTR UserHandler	;Else call user pointer
	OR     AL,AL			;Did UserHandler return true?
	JNZ    Done			;Yes, return to program
	POP    CX			;Get error address back
	POP    BX
	MOV    AX,ExitCode		;Get exitcode back
	JMP SHORT NoRecover		;Back to system handler
Done:
	RET				;Return beyond error

NoRecover:
	JMP DWORD PTR [SystemContinue]	;Transfer back to system handler

Handler ENDP

CODE	ENDS
	END
