; 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                   ;
