; From Steve Leach
;
; This is a short TSR to trap <CTR><ALT><DEL> and display current
; Registers, flags, and a dump of the next instruction...
; hitting <CTRL><ALT><DEL> again will reboot.
;
; Based on Paul Cullum's NOCAD program


CODE_SEG SEGMENT
BEGSEG	EQU	$
	ASSUME	CS:CODE_SEG, DS:CODE_SEG, ES:CODE_SEG, SS:CODE_SEG
	ORG	100H
BEGIN:
	JMP	INIT			; Install in memory and exit to DOS
INT9:					;
	STI				; Enable interrupts
	PUSH	AX			;
	IN	AL, 60H			; Get key from keyboard controller
	CMP	AL, 53H			; Is it Del?
	JNZ	NOT_DEL			; Nope, let it through
	PUSH	BX			;
	PUSH	ES			;
	XOR	BX, BX			; Segment 0
	MOV	ES, BX			;
	MOV	BX, 417H		; Offset 417 - key flags
	TEST	BYTE PTR ES:[BX], 08H	; Test for Alt press
	JZ	NOT_OURS		; Nope
	TEST	BYTE PTR ES:[BX], 04H	; Test for Ctrl press
	JZ	NOT_OURS		; Nope
	JMP	DEL_PRESS		; Yep, absorb this keystroke
NOT_OURS:				;
	POP	ES			; Restore ES and BX
	POP	BX			;
NOT_DEL:				;
	POP	AX			;
	DB	0EAH			; Call old INT 9 handler
INT9OFF	DW	0000			; Offset and
INT9SEG	DW	0000			; Segment stored here
DEL_PRESS:				;
	IN	AL, 61H			; This stuff is to tell the
	MOV	AH, AL			; Key controller that we
	OR	AL, 80H			; Have gotten the key.
	OUT	61H, AL			; (for XT's)
	MOV	AL, AH			;
	OUT	61H, AL			;
	MOV	AL,020H			; Send EOI to 8259 command reg.
	OUT	020H,AL			;

	MOV	AX,3			; Set Vid. mode 3
	INT	10H			;
	POP	ES			; Restore ES and BX
	POP	BX			;
	MOV	AX,ES			; Save all registers
	PUSH	AX			; To stack
	MOV	AX,DS			;
	PUSH	AX			;
	PUSH	BP			;
	PUSH	DI			;
	PUSH	SI			;
	PUSH	DX			;
	PUSH	CX			;
	PUSH	BX			;

	JMP	PAST_DATA		;
REGS	DB	13,10,13,10,"ANYONE ELSE MISS FRONT PANNELS?  HIT <CTRL><ALT><DEL>"
	DB " AGAIN TO EXIT",13,10,13,10	;
	DB "BX",9,"CX",9,"DX",9,"SI",9,"DI",9,"BP",9,"DS",9,"ES",9,"AX"
	DB 13,10,0			;
					;
FLAG_MSG DB	13,10,13,10,"FLAGS: ",0	;
					;
INST_MSG DB	13,10,13,10,"NEXT INSTRUCTION: ",0
PAST_DATA:
					;
	MOV	BX,OFFSET REGS		; Display register names
	CALL	DISP_MSG		;
	MOV CX,9			; Number of registers to display
PE_L2:					;
	POP AX				; Pop register value from stack
	MOV BX,16			; Base
	MOV SI,4			; Didgits
	CALL DISP_UAX			; Display value
	MOV AH,0EH			; Tty print
	MOV AL," "			; Space
	INT 10H				; Print it
	INT 10H				;
	LOOP PE_L2			;
	MOV WORD PTR CS:DEL_PRESS, 00EAH ; Next time <CTRL><ALT><DEL>
	MOV WORD PTR CS:DEL_PRESS+2,0FF00H ; Is pressed, JMP FFFF:0000
	MOV BYTE PTR CS:DEL_PRESS+4,0FFH ; Will be executed

	MOV BX,OFFSET INST_MSG		; Display instruction message
	CALL DISP_MSG			;
	POP DI				; Ds:di points to instruction
	POP DS				;
	MOV DX,10			; Number of words to display
					;
PRINT_INSTRUCTION:			;
	MOV AX,DS:[DI]			; Load next instruction word
	MOV SI,4			; Didgits
	MOV BX,16			; Base
	CALL DISP_UAX			; Display value
	INC DI				; Update pointer
	INC DI				;
	DEC DX				; Decrement counter
	JNZ  PRINT_INSTRUCTION		; Loop until 10 words displayed

	MOV BX,OFFSET FLAG_MSG		; Display flag message
	CALL DISP_MSG			;
	POP AX				; Flags
	MOV SI,16			; Didgits
	MOV BX,2			; Base
	CALL DISP_UAX			; Display flags value


WAIT_FOR_RELEASE:			; Infinate loop (until user presses
	JMP WAIT_FOR_RELEASE		; <Ctrl><Alt><Del> again)
; -----------------------------------------------------------
DISP_MSG:				; Display string
	MOV AH,0EH			; Tty write
PRNT_MSG:				;
	MOV AL,CS:[BX]			;
	OR AL,AL			;
	JZ PRINT_DONE			;
	CMP AL,9			;
	JNE NO_TAB			;
	MOV AL," "			;
	MOV CX,3			;
TAB:					;
	INT 10H				;
	LOOP TAB			;
NO_TAB:					;
	INT 10H				;
	INC BX				;
	JMP PRNT_MSG			;
PRINT_DONE:				;
	RET				;
					;
; -----------------------------------------
					;
DISP_UAX:				; Display unsigned number in AX
	PUSH BX				;
	PUSH CX				; Bx = base to convert to
	PUSH DX				;
	MOV CX,SI			; Cx = number of didgets

DISP_UAX_LOOP:				;
	XOR DX,DX			; Devide by base storing remainders
	DIV BX				;
	CMP DX,9			;
	JBE DU_NH			;
	ADD DX,55			;
	JMP DU_H			;
DU_NH:
	ADD DX,'0'			;
DU_H:					;
	PUSH DX				;
	LOOP DISP_UAX_LOOP		;
	MOV CX,SI			;
DISP_UAX_LOOP2:				;
	POP AX				; Restore remainders and print in
	MOV AH,0EH			;
	INT 10H				; Reverse order...
	LOOP DISP_UAX_LOOP2		;
	POP DX				;
	POP CX				;
	POP BX				;
	RET				;

DW	15H	DUP (0)			;
RESSIZ	EQU	(($ - BEGSEG) /	16) + 1	; Number of para. to keep
INIT:					;
	MOV	AX, 3509H		; Get interrupt vector for key press
	INT	21H			; Call DOS
	MOV	[INT9OFF], BX		; Store offset
	MOV	[INT9SEG], ES		; And segment
	MOV	AX, 2509H		; Set interrupt vector for key press
	MOV	DX, OFFSET INT9		; To our interrupt handler
	INT	21H			; Call DOS
	MOV	AX, 3100H		; Terminate and Stay Resident
	MOV	DX, RESSIZ		; Number of paragraphs needed
	INT	21H			; Call DOS
CODE_SEG ENDS				;
	END	BEGIN			;

