PAGE 81,132
;INTRPT2.ASM
;-----------------------------------------------------------------------|
;    --------          ---1991 Cornel H Huth     -------------------    |
;-----------------------------------------------------------------------|
;     date: 21 Jul 91                                                   |
; function: 80xxx INTERRUPT dispatcher for QuickBASIC/BASIC PDS         |
;   caller: FAR call QuickBASIC convention, reference (INTERRUPT(X))    |
;           call INTERRUPT(intnum%,ireg AS RegType,oreg AS RegType)     |
;           call INTERRUPTX(intnum%,ireg AS RegTypeX,oreg AS RegTypeX)  |
;    stack: +06 offset of return register pack                          |
;            08 offset of initial register pack                         |
;            10 interrupt number                                        |
;   return:  interrupt return registers                                 |
;     NOTE:  This routine is a direct replacement for QB's routine.     |
;     NOTE:  INT24 handler is installed temporarily to handle fatal     |
;            DOS errors without the Abort, Retry, Fail or system crash. |
;     NOTE:  If intnum% is out of range intnum% is NOT returned as -1   |
;            as the MS version does (no one is that stoopid, hey,hey).  |
;     NOTE:  The interrupt is done without writing to the code segment. |
;     NOTE:  b$SaveBP is no longer needed with PDS version since fatal  |
;            errors are handled locally, not by the BASIC INT24 handler.|
;     NOTE:  For verbose source comments see INTRPT.ASM in QBNWS105.    |
;-----------------------------------------------------------------------|
; This source file is based on:                                         |
; INTERRUPT - BASCOM software interrupt calling routine                 |
;       Copyright <C> 1986, 1987 Microsoft Corporation                  |
;-----------------------------------------------------------------------|
;This source was assembled using MASM 5.1. Previous or other versions of|
;assemblers should handle this source without any difficulty except for |
;perhaps the retf and retn mnemonics. Easy enough to use a macro or db. |
;-----------------------------------------------------------------------|
WPTR    EQU <WORD PTR>
BPTR    EQU <BYTE PTR>

Aintnum  EQU <WPTR [BP+10]>
Aireg    EQU <WPTR [BP+08]>
Aoreg    EQU <WPTR [BP+06]>

OldSI    EQU <WPTR [BP-02]>
OldDI    EQU <WPTR [BP-04]>
OldDS    EQU <WPTR [BP-06]>
OldFLAGS EQU <WPTR [BP-08]>
RegCnt   EQU <WPTR [BP-10]>
RegES    EQU <WPTR [BP-12]>
RegDS    EQU <WPTR [BP-14]>
RegFLAGS EQU <WPTR [BP-16]>
RegDI    EQU <WPTR [BP-18]>
RegSI    EQU <WPTR [BP-20]>
RegBP    EQU <WPTR [BP-22]>
RegDX    EQU <WPTR [BP-24]>
RegCX    EQU <WPTR [BP-26]>
RegBX    EQU <WPTR [BP-28]>
RegAX    EQU <WPTR [BP-30]>

LocalSize = 30

PostBP   EQU <WPTR [BP-34]> ;returned bp pushed here (after INT call return)

_BSS            SEGMENT WORD PUBLIC 'BSS'
INT24error      dw 1 dup(?)
INT24seg        dw 1 dup(?)
INT24off        dw 1 dup(?)
_BSS            ENDS

_DATA           SEGMENT WORD PUBLIC 'DATA'
_DATA           ENDS

DGROUP          GROUP _DATA,_BSS

INTRPT2_TEXT    SEGMENT WORD PUBLIC 'CODE'
                ASSUME cs:INTRPT2_TEXT,ds:DGROUP,es:DGROUP,ss:DGROUP

                PUBLIC INTERRUPT
INTERRUPT       PROC FAR

                push    bp
                mov     bp,sp
                sub     sp,LocalSize
                mov     RegCnt,8        ;8 registers passed for INTERRUPT
                jmp     SHORT INTRPT1

                PUBLIC INTERRUPTX
INTERRUPTX      LABEL FAR

                push    bp
                mov     bp,sp
                sub     sp,LocalSize
                mov     RegCnt,10       ;10 passed for INTERRUPTX

                ;set up for interrupt call

INTRPT1:        mov     bx,Aintnum
                mov     bx,[bx]         ;bx=interrupt to execute
                or      bh,bh           ;>255?
                jz      INTRPT2         ;no
                jmp     INTRPTxit       ;yes,just exit

INTRPT2:        push    bx
                mov     bl,1            ;trap fatal errors
                call    INT24switch
                pop     bx

                mov     OldSI,si        ;save what we need to
                mov     OldDI,di
                mov     OldDS,ds
                pushf                   ;in case RegFLAGS changes DF?
                pop     OldFLAGS

                cld
                mov     si,Aireg        ;ds:si->ireg pack
                mov     ax,ss
                mov     es,ax
                lea     di,RegAX        ;es:di->local stack vars
                mov     cx,RegCnt
                rep     movsw

                push    bp              ;save original frame base

                cmp     bl,25h          ;INT25?
                je      INTRPT3         ; or
                cmp     bl,26h          ;INT26?
                jne     INTRPT4         ;no

                ;INT25/26 specific stack program

INTRPT3:        mov     ax,10
                push    ax              ;retf 10
                mov     ax,0CA90h       ;nop
                push    ax              ;sti
                mov     ax,0FB44h       ;inc sp
                push    ax              ;inc sp
                mov     ax,44FAh        ;cli    -ensure sp stays even
                push    ax
                jmp     SHORT INTRPT5

                ;non-INT25/26 specific stack program

INTRPT4:        sub     ax,ax
                push    ax              ;retf 6
                mov     ax,06CAh
                push    ax

                ;for either, the actual INT?? instruction

INTRPT5:        mov     ah,bl
                mov     al,0CDh
                push    ax              ;INT??

                ;set up the far return address for the stack program

                push    cs
                mov     ax,OFFSET INTRPT8 ;cs:ax->return to after INT??
                push    ax

                ;store the address of the stack program--on the stack

                push    ss
                mov     ax,sp
                add     ax,6            ;ss:ax->start of stack program
                push    ax

                ;set up the registers for the INT call

                mov     ax,RegFLAGS
                and     ax,0000111111010101b  ;mask valid 8086 flags
                push    ax                    ;save flags for a sec

                mov     ax,RegAX
                mov     bx,RegBX
                mov     cx,RegCX
                mov     dx,RegDX
                mov     si,RegSI
                mov     di,RegDI

                cmp     RegCnt,8        ;call INTERRUPT?
					 je		INTRPT7

                cmp     RegDS,-1        ;no,INTERRUPTX,load ds segment?
                je      INTRPT6
                mov     ds,RegDS        ;ds<>ss!

INTRPT6:        cmp     RegES,-1        ;how about es segment?
                je      INTRPT7
                mov     es,RegES

INTRPT7:        mov     bp,RegBP
                popf                    ;get the flags back

                retf                    ;execute the stack program

                ;come here after the stack program has executed the INT call

INTRPT8:        push    bp              ;save to PostBP
                mov     bp,sp
                mov     bp,[bp+2]       ;get original frame base

                pushf                   ;get the return flags NOW
                pop     RegFLAGS

                ;unhook temporary INT24 handler and process any error

                push    bx              ;we want
                sub     bl,bl
                call    INT24switch
                pop     bx              ;we need
                cmp     ss:INT24error,0 ;fatal DOS error?
                je      INTRPT9         ;no
                or      RegFLAGS,1      ;set carry
                mov     ah,30h          ;clean up DOS
                int 21h
                mov     ax,ss:INT24error ;return DOS error

INTRPT9:        push    OldFlags
                popf

                ;save returned registers and send them back

                mov     RegAX,ax
                mov     RegBX,bx
                mov     RegCX,cx
                mov     RegDX,dx

                mov     ax,PostBP       ;get BP value returned from INT call
                mov     RegBP,ax

                mov     RegSI,si
                mov     RegDI,di
                mov     RegDS,ds
                mov     RegES,es

                mov     ds,OldDS        ;ds=ss

                lea     si,RegAX        ;ds:si->stack vars (ds=ss)
                mov     ax,ds
                mov     es,ax
                mov     di,Aoreg        ;es:di->oreg pack
                mov     cx,RegCnt
                rep     movsw

                mov     si,OldSI
                mov     di,OldDI

INTRPTxit:      mov     sp,bp           ;deallocate locals
                pop     bp
                retf    3*2             ;we're done

                ;temporary INT24 switch and handler

INT24switch:    push    es
                push    ds
                push    dx
                push    ax

                or      bl,bl
                jz      INT24s2

                mov     ss:INT24error,0
                mov     ax,3524h
                int 21h
                mov     ss:INT24seg,es
                mov     ss:INT24off,bx
                mov     ax,2524h
                mov     dx,OFFSET INT24handler
                push    cs
                pop     ds
INT24s1:        int 21h
                pop     ax
                pop     dx
                pop     ds
                pop     es
                retn

INT24s2:        mov     ax,2524h
                mov     dx,ss:INT24off
                mov     ds,ss:INT24seg
                jmp     INT24s1

                ;store the error number and return

INT24handler:   sti
                add     sp,6
                add     di,13h
                mov     ss:INT24error,di
                pop     ax
                pop     bx
                pop     cx
                pop     dx
                pop     si
                pop     di
                pop     bp
                pop     ds
                pop     es
                iret

INTERRUPT       ENDP
INTRPT2_TEXT    ENDS
                END
