⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cint16.asm

📁 CINT16 - DOS下的C语言中断驻留子程序范例
💻 ASM
字号:
        TITLE   LC Interrupt trap routine
        NAME    LCINT
        INCLUDE DOS.MAC                 ; BE SURE TO INCLUDE THE CORRECT
                                        ; DOS.MAC!!

;****************************************************************************
;
; This is the heart of a C driven interrupt handler. This file was used to
; write a critical error handler that remained resident. (It replaced the
; "Abort, Retry, Ignore" prompt with a window.) This file can be adapted to
; any interrupt and any C routine with a little work. THIS HAS BEEN USED ONLY
; IN THE S MODEL.
;
; REVISION HISTORY:
;
;       7/19/87         Thomas A. Lundin
;                       Graphics Unlimited Inc.
;                       3000 Second St. No.
;                       Minneapolis, MN 55411
;                       (612) 588-7571
;
; Implemented DOS stack save/restore for a more stable exit from & reentry to
; the original DOS environment which called us.
;
;       8/4/87          TAL again
;
; Now try the keyboard interrupt vector. Also added some routines (but did
; not activate them here) which save/restore the caller's PSP and DTA. Why?
; I had some silly notion that it might help my TSR program from bombing when
; issuing DOS calls when other DOS calls are in process. Hah! I should have
; known better. But I left them in, in case you are interested. The kludge I
; ended up with checks the DOS "Critical Section Flag" and disables any calls
; to DOS when other calls are in process. That section of code has also been
; commented out. Also made some changes to my 7/19/87 modifications.
;****************************************************************************

DOS_INT         EQU 16H                 ; int to be replaced (keyboard)

WRITE_INT       EQU 25H                 ; DOS write int vector
READ_INT        EQU 35H                 ; DOS read int vector
;******************************************************************************
HOTKEY          EQU 1300H               ; ALT-R here - can be anything you want
;******************************************************************************
STAK_LEN        EQU 800H                ; size of stack area to save ;;;;;;;;;;


XREG    STRUC
REG_AX  DW      ?                       ; general purpose registers
REG_BX  DW      ?                       
REG_CX  DW      ?
REG_DX  DW      ?
REG_SI  DW      ?
REG_DI  DW      ?
XREG    ENDS

SREGS   STRUC
REG_ES  DW      ?                       ; segment registers
REG_CS  DW      ?
REG_SS  DW      ?
REG_DS  DW      ?
SREGS   ENDS

        DSEG

        INT_REGS        XREG    <>              ; saved regs. at int time
        INT_SEGREGS     SREGS   <>              ; saved seg. regs.
        EXTRN           _TOP:WORD               ; declared by C.ASM -- points
                                                ; to top of stack
        EXTRN           _STACK:WORD             ; size of stack
        PUBLIC          _INDOS                  ; if _INDOS is non-zero...
_INDOS          DW      0                       ; ...then don't interrupt DOS
        ENDDS

        EXTRN   INTTIME:NEAR                    ; your int routine goes here!

        PSEG
;;
; interrupt time data storage
;;
C_ENVIRONMENT_DS DW ?                   ; filled by int init, used...
C_ENVIRONMENT_ES DW ?                   ; ...to recreate C environment
C_ENVIRONMENT_SS DW ?
C_ENVIRONMENT_SP DW ?

INT_TIME_ES     DW ?
INT_TIME_DS     DW ?                    ; temp save of DS at int time
INT_TIME_SI     DW ?                    ; temp save of SI at int time

INT_TIME_BP     DW ?                    ; added to account for no BP or SP...
INT_TIME_SP     DW ?                    ; ...in above structures

RETURN_VALUE    DW ?                    ; return value from C service routine

DOS_SERVICE     DD      ?               ; address of DOS Service routine
INT_TWOONE      DD ?                    ; old INT 21 vector

INT_IN_PROGRESS DB 0                    ; interrupt in progress flag

CALSTK  DB      STAK_LEN DUP(?) ;caller's stack save area ;;;;;;;;;;;;;;;;;;;;;
STKSEG  DW      ?               ;which stack segment ;;;;;;;;;;;;;;;;;;;;;;;;;;
FLAGS   DW      ?               ;caller's flags ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;DOSDTA  DD      ?               ;caller's DTA
;C_DTA   DD      ?               ;C's DTA
;DOSPSP  DW      ?               ;caller's PSP
;C_PSP   DW      ?               ;C's PSP
;;**************************************************************************
; name          LC_SERVICE_INT
;
; description   Entered at (software) interrupt time, this routine
;               restores the C enviroment and processes the interrupt
;               trapping all references to the quad file
;;

        IF      LPROG
LC_SERVICE_INT PROC     FAR
        ELSE
LC_SERVICE_INT PROC     NEAR
        ENDIF

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This section of code can be commented out if you don't wish to trap the
; keyboard interrupt. Remember, then, to change the DOS_INT EQUate to whatever
; interrupt it is you DO want to trap.

        CMP     CS:INT_IN_PROGRESS,1    ; already in this interrupt?
        JNE     FIRST_TIME              ; no, check the key
EXIT16:
        JMP     DWORD PTR CS:DOS_SERVICE ; else forget it

FIRST_TIME:
        CMP     AH,0                    ; is this character request
        JNE     EXIT16                  ; no, exit immediately
        PUSHF
        CALL    DWORD PTR CS:DOS_SERVICE ; get the next character from buffer
        CMP     AX,HOTKEY               ; is it the hot key?
        JE      HOT_HIT                 ; yes, dive into the interrupt
        IRET                            ; no, send the char back to caller
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
HOT_HIT:
        MOV     CS:INT_IN_PROGRESS,1    ; set int in progress flag

        MOV     CS:INT_TIME_ES,ES       ; save ES so it can be overwritten
        MOV     CS:INT_TIME_DS,DS       ; save DS so it can be overwritten
        MOV     CS:INT_TIME_SI,SI       ; save SI so it can be overwritten
        MOV     CS:INT_TIME_BP,BP       ; save BP as structs do not have it
        MOV     CS:INT_TIME_SP,SP       ; save SP as structs do not have it
        MOV     DS,CS:C_ENVIRONMENT_DS  ; set up C enviroment
        MOV     SI,OFFSET INT_REGS      ; point to input regs struct

        MOV     DS:[SI].REG_AX,AX       ; save general purpose regs
        MOV     DS:[SI].REG_BX,BX
        MOV     DS:[SI].REG_CX,CX
        MOV     DS:[SI].REG_DX,DX
        MOV     DS:[SI].REG_DI,DI
        MOV     AX,CS:INT_TIME_SI       ; SI has been overwritten
        MOV     DS:[SI].REG_SI,AX

        MOV     SI,OFFSET INT_SEGREGS   ; point to input segment regs struct

        MOV     AX,CS:INT_TIME_ES       ; ES has been overwritten
        MOV     DS:[SI].REG_ES,AX
        MOV     DS:[SI].REG_SS,SS
        MOV     AX,CS:INT_TIME_DS       ; DS has been overwritten
        MOV     DS:[SI].REG_DS,AX
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        PUSHF
        POP     AX
        MOV     CS:FLAGS,AX             ;save caller's flags
        MOV     SI,SS
        MOV     WORD PTR CS:STKSEG,SI   ;save caller's stack segment
        PUSH    DS
        CLI
        MOV     AX,CS                   ;save area address
        MOV     ES,AX
        MOV     AX,WORD PTR CS:STKSEG   ;caller's stack address
        MOV     DS,AX
        MOV     SI,0                    ;stack offset
        MOV     DI,OFFSET CS:CALSTK
        MOV     CX,STAK_LEN             ;length to save
        CLD
        REP     MOVSB                   ;save caller's stack
        STI
;........................................
;       MOV     AX,2F00H                ;get caller's DTA
;       INT     21H
;       MOV     WORD PTR CS:DOSDTA+2,ES ;save it
;       MOV     WORD PTR CS:DOSDTA,BX
;
;       MOV     AX,5100H                ;get caller's PSP
;       INT     21H
;       MOV     CS:DOSPSP,BX            ;save it
;
;       MOV     AX,1A00H                ;set C's DTA
;       MOV     DX,WORD PTR CS:C_DTA
;       MOV     DS,WORD PTR CS:C_DTA+2
;       INT     21H
;
;       MOV     BX,CS:C_PSP
;       MOV     AX,5000H                ;set C's PSP
;       INT     21H
;........................................
        POP     DS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        MOV     ES,CS:C_ENVIRONMENT_ES  ; complete C environment
        MOV     SS,CS:C_ENVIRONMENT_SS
        MOV     SP,CS:C_ENVIRONMENT_SP
;----------------------------------------
;       PUSH    ES                      ;
;       PUSH    BX                      ;
;       PUSH    AX                      ;
;       MOV     AX,3400H                ; the "Critical Section Flag"
;       INT     21H                     ; determines DOS interruptability
;       MOV     AL,BYTE PTR ES:[BX]     ;
;       MOV     BYTE PTR CS:_INDOS,AL   ; save it for INTTIME
;       POP     AX                      ;
;       POP     BX                      ;
;       POP     ES                      ;
;----------------------------------------

        CALL    INTTIME                 ; call the C routine

        MOV     CS:RETURN_VALUE,AX      ; save return value
        XOR     AX,AX
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        PUSH    DS
;........................................
;       MOV     AX,1A00H                ;reinstate DOS DTA
;       MOV     DX,WORD PTR CS:DOSDTA
;       MOV     DS,WORD PTR CS:DOSDTA+2
;       INT     21H
;
;       MOV     BX,CS:DOSPSP
;       MOV     AX,5000H                ;and DOS PSP
;       INT     21H
;........................................
        CLI
        MOV     AX,WORD PTR CS:STKSEG   ;restore caller's stack area 
        MOV     ES,AX
        MOV     DI,0                    ;restore data areas
        MOV     AX,CS
        MOV     DS,AX
        MOV     SI,OFFSET CS:CALSTK
        MOV     CX,STAK_LEN             ;length to restore
        CLD
        REP     MOVSB                   ;copy stack data
        STI
        POP     DS

        MOV     AX,CS:FLAGS
        PUSH    AX
        POPF                            ;restore caller's flags
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        MOV     SI,OFFSET INT_REGS      ; point to input regs struct

        MOV     AX,DS:[SI].REG_SI       ; SI needs to be saved while used
        MOV     CS:INT_TIME_SI,AX

        MOV     AX,DS:[SI].REG_AX       ; restore general purpose regs
        MOV     BX,DS:[SI].REG_BX
        MOV     CX,DS:[SI].REG_CX
        MOV     DX,DS:[SI].REG_DX
        MOV     DI,DS:[SI].REG_DI

        MOV     SI,OFFSET INT_SEGREGS   ; point to input segment regs struct

        MOV     ES,DS:[SI].REG_DS       ; DS needs to be saved while used
        MOV     CS:INT_TIME_DS,ES

        MOV     ES,DS:[SI].REG_ES
        MOV     SS,DS:[SI].REG_SS

        MOV     SI,CS:INT_TIME_SI       ; restore pointing registers
        MOV     DS,CS:INT_TIME_DS

        MOV     BP,CS:INT_TIME_BP       ; special BP restore
        MOV     SP,CS:INT_TIME_SP       ; special SP restore

        MOV     CS:INT_IN_PROGRESS,0    ; clear int in progress flag
        MOV     AX,CS:RETURN_VALUE      ; move the return value
        OR      AX,AX ;;;;;;;;;;;;;;;;;;; return value ?
        JNZ     DONE  ;;;;;;;;;;;;;;;;;;; yes, pass it through as keystroke
        JMP     CS:LC_SERVICE_INT ;;;;;;; no, fetch the next keystroke
DONE:
        IRET                            ; return from interrupt

LC_SERVICE_INT  ENDP

;****************************************************************************
; description   set up the LC interrupt routines
;
;               INT_INIT -- Hooks into the specified int.
;               INT_TERM -- Unhooks (restores) the specified int.
;
; NOTE: INT_INIT must be called be int processing can begin...it saves the 
;       current C environment for use at interrupt time.
;;

                PUBLIC  INT_INIT
                IF      LPROG
INT_INIT        PROC    FAR
                ELSE
INT_INIT        PROC    NEAR
                ENDIF

        PUSH    DS                      ; save changed seg regs
        PUSH    ES

        MOV     CS:C_ENVIRONMENT_DS,DS  ; save C environment for int time
        MOV     CS:C_ENVIRONMENT_ES,ES
        MOV     CS:C_ENVIRONMENT_SS,SS

        MOV     AX,_TOP                 ; determine int time SP
        MOV     BX,_STACK               ; get size of STACK ;;;;;;;;;;;;;;;;;;;
        ROR     BX,1                    ; div by 2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        SUB     AX,BX                   ; split it in two ;;;;;;;;;;;;;;;;;;;;;
        MOV     CS:C_ENVIRONMENT_SP,AX

        MOV     AH,READ_INT             ; read int vector function
        MOV     AL,DOS_INT              ; specify DOS service vector
        INT     21H

        MOV     WORD PTR CS:DOS_SERVICE+2,ES    ; save current vector
        MOV     WORD PTR CS:DOS_SERVICE,BX

        LEA     DX,LC_SERVICE_INT       ; Use DOS to set new int address
        PUSH    CS
        POP     DS
        MOV     AH,WRITE_INT
        MOV     AL,DOS_INT
        INT     21H

;::::::::::::::::::::::::::::::::::::::::
;       MOV     AX,2F00H                ;get C's DTA
;       INT     21H
;       MOV     WORD PTR CS:C_DTA+2,ES  ;save it
;       MOV     WORD PTR CS:C_DTA,BX
;
;       MOV     AX,5100H                ;get C's PSP
;       INT     21H
;       MOV     CS:C_PSP,BX             ;save it
;::::::::::::::::::::::::::::::::::::::::
        POP     ES                      ; restore changed seg regs
        POP     DS
        RET

INT_INIT        ENDP

;********************* INT_TERM -- kill ints. *******************************

                PUBLIC INT_TERM
                IF      LPROG
INT_TERM        PROC    FAR
                ELSE
INT_TERM        PROC    NEAR
                ENDIF

        PUSH    DS                      ; DS gets changed

        MOV     DS,WORD PTR CS:DOS_SERVICE+2    ; Restore previous DOS service vector
        MOV     DX,WORD PTR CS:DOS_SERVICE
        MOV     AH,WRITE_INT
        MOV     AL,DOS_INT
        INT     21H

        POP     DS                      ; restore DS
        RET
INT_TERM        ENDP

        ENDPS
        END

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -