home *** CD-ROM | disk | FTP | other *** search
- TITLE INTERRUPT - BASCOM software interrupt calling routine
- PAGE 56,132
- ;***
- ; INTERRUPT - BASCOM software interrupt calling routine
- ;
- ; Copyright <C> 1986, 1987 Microsoft Corporation
- ;
- ;Purpose:
- ; Allows a BASIC program to invoke an interrupt through a CALL statement.
- ;
- ; INTERRUPT allows BASIC to set AX,BX,CX,DX,BP,SI,DI, and the flags
- ; before the call. INTERRUPTX also allows DS and ES to be set.
- ; Both routines will return the values of the registers upon the
- ; completion of a successful call. If the interrupt could not
- ; be generated (due to a bad interrupt number or an illegal array)
- ; then the interrupt number will be set to -1 to indicate an error.
- ;
- ;******************************************************************************
- ;
- ;Note:
- ; The DOSSEG, .MODEL, .CODE, and .DATA? directives used in this program
- ; are part of the simplified segment system of MASM 5.0. If you have
- ; an earlier version of MASM, you must modify the source to define
- ; the segments required by Microsoft high-level languages. These
- ; segments are discussed in Appendix C of "Learning and Using QuickBASIC."
- ;
-
- DOSSEG ;requires MASM 5.0 or higher
- .MODEL medium
-
- ; Define all publicly accessible routines.
-
- PUBLIC INTERRUPT, INTERRUPTX
-
- ; Frame structure definition
-
- ARG1 = 0AH ;pointer to first of three arguments
- ARG2 = 08H ;pointer to second of three arguments
- ARG3 = 06H ;pointer to third of three arguments
-
- ; Frame temp variables
-
- UCODE_FLGS = -02H ;user code flag register value
- UCODE_DS = -04H ;user code DS register value
- REG_NUM = -06H ;number of regs used (INTERRUPT=8, INTERRUPTX=10)
- INT_ES = -08H ;INT ES register value
- INT_DS = -0AH ;INT DS register value
- INT_FLGS = -0CH ;INT flags register value
- INT_DI = -1EH ;INT DI register value
- INT_SI = -10H ;INT SI register value
- INT_BP = -12H ;INT BP register value
- INT_DX = -14H ;INT DX register value
- INT_CX = -16H ;INT CX register value
- INT_BX = -18H ;INT BX register value
- INT_AX = -1AH ;INT AX register value
- OLD_SI = -1CH ;save old SI for interpreter
- OLD_DI = -1EH ;save old DI for interpreter
-
- FRM_SIZ = -1EH ;negative size of frame temporaries
-
- ; Locations past frame allocation used to recover post-INT BP value.
-
- INT_BP_TMP = -22H ;temp location for INT BP register value
-
- ;***
- ; INTERRUPT, and INTERRUPTX - BASCOM software interrupt calling interface
- ;
- ; Purpose:
- ; To allow a BASIC Compiler program to perform any software
- ; interrupt. The interrupt is executed with the registers
- ; set to values specified in a register variable. The post-
- ; interrupt values of the registers are then stored in
- ; another register variable.
- ;
- ; CALL INTERRUPT[X] (int_no AS INTEGER,
- ; inreg AS RegType[X],
- ; outreg AS RegType[X])
- ;
- ; Inputs:
- ; int_no = interrupt number (range 0 to 255) to execute
- ; inreg and outreg are register variables of type RegType[X]
- ; defined as follows;
- ;
- ; TYPE RegType
- ; ax AS INTEGER
- ; bx AS INTEGER
- ; cx AS INTEGER
- ; dx AS INTEGER
- ; bp AS INTEGER
- ; si AS INTEGER
- ; di AS INTEGER
- ; flags AS INTEGER
- ; END TYPE
- ;
- ;
- ; TYPE RegTypeX
- ; ax AS INTEGER
- ; bx AS INTEGER
- ; cx AS INTEGER
- ; dx AS INTEGER
- ; bp AS INTEGER
- ; si AS INTEGER
- ; di AS INTEGER
- ; flags AS INTEGER
- ; ds AS INTEGER
- ; es AS INTEGER
- ; END TYPE
- ;
- ; Outputs:
- ; If no error:
- ; int_no = unchanged (range 0 to 255)
- ; outreg: This array will be set to the post-interrupt
- ; register values. It has the same structure
- ; as inreg.
- ; If error:
- ; int_no = -1
- ; outreg unchanged. INT call is not performed.
- ; error occurs:
- ; first argument not 0 to 255 (2^8-1)
- ; second or third arguments not 0 to 1048575 (2^20-1)
- ; (VARPTR will always be in this range)
- ;
- ; Modifies:
- ; All, except BP, DS, and flags.
- ; Also, possible side effects of INT call.
- ;
- ; Exceptions:
- ; INT 24H call may result from some INT 21H MS-DOS calls.
- ;
- ;******************************************************************************
-
- .CODE
-
- INTERRUPT PROC FAR
-
- PUSH BP ;save BASCOM frame pointer on stack
- MOV BP,SP ;establish program frame reference
- ADD SP,FRM_SIZ ;allocate working space for frame
- MOV WORD PTR [BP].REG_NUM,08H ;eight regs used (not DS or ES)
- JMP SHORT INTERRUPT_COMMON ;jump to common code
-
- INTERRUPT ENDP
-
-
- INTERRUPTX PROC FAR
-
- PUSH BP ;save BASCOM frame pointer on stack
- MOV BP,SP ;establish program frame reference
- ADD SP,FRM_SIZ ;allocate working space for frame
- MOV WORD PTR [BP].REG_NUM,0AH ;ten regs used (including DS and ES)
-
- ; Save a copy of the processor flags, SI, DI, and DS in the stack frame.
-
- INTERRUPT_COMMON:
- MOV [BP].OLD_SI,SI ;save old SI for interpreter
- MOV [BP].OLD_DI,DI ;save old DI for interpreter
- MOV [BP].UCODE_DS,DS;save DS for interpreter
- PUSHF ;push the flags on the stack
- POP [BP].UCODE_FLGS ;put value in the stack frame
-
- ; Move eight or ten words (depending if executing INTERRUPT or INTERRUPTX)
- ; of the integer input array from the far pointer computed to the frame.
-
- MOV SI,[BP].ARG2 ;and array offset - pointer in DS:SI
- LEA DI,[BP].INT_AX ;get start of temporary register storage.
- MOV CX,[BP].REG_NUM ;eight or ten words to move
- CLD ;movement is to higher memory
- PUSH SS
- POP ES
- REP MOVSW ;move the array into the stack frame
-
- ; Save stack frame pointer to recover its value after the INT call.
-
- PUSH BP ;saved to first word past the stack frame
-
- ; Create a two-instruction program on the stack to execute the
- ; INT call requested and return with stack cleanup.
- ;
- ; INT XX (hex: CD XX)
- ; RETF 06 (hex: CA 06 00)
- ;
- ; In the case of INT 25 and 26 (which leave a word of flags on the stack)
- ; We generate:
- ;
- ; INT XX (hex: CD XX)
- ; ADD SP,2 (hex: 83 C4 02)
- ; RETF 08 (hex: CA 08 00)
- ;
- MOV SI,[BP].ARG1 ;[SI] = ptr to first CALL arg - interrupt #
- MOV BX,[SI] ;[BL] = get integer value of INT type
- OR BH,BH ;test if in range, 00 to FFH is legal
- JZ NO_INT_ERROR ;if not, then error - jump
- JMP INT_ERROR ;long jump to error routine
- NO_INT_ERROR:
-
- CMP BL,25H ;Interrupt 25 request?
- JZ Int2526 ;Jump if so
- CMP BL,26H ;Interrupt 26 request?
- JNZ IntNorm ;Jump if other, "normal" interrupt
- Int2526:
- MOV AX,8 ;[AX] = argument of RETF instruction
- PUSH AX
- MOV AX,0CA02H ;[AX] = RETF opcode, & arg to ADD SP
- PUSH AX
- MOV AX,0C483H ;[AX] = ADD SP, opcode
- PUSH AX
- JMP SHORT IntInstruct
-
- IntNorm:
- XOR AX,AX ;value of second word past frame
- PUSH AX ;put on stack - 00 byte of RETF and filler
- MOV AX,06CAH ;value of third word past frame
- PUSH AX ;put on stack - CA 06 bytes of RETF
- IntInstruct:
- MOV AH,BL ;move interrupt number to upper byte of AX
- MOV AL,0CDH ;value of fourth word past frame
- PUSH AX ;put on stack - CD XX bytes of INT XX
-
- ; Push far pointer of return address after the stack program
- ; executes, which is INT_RET in this code segment.
-
- PUSH CS ;push current code segment for return segment
- MOV AX,OFFSET INT_RET ;offset just after stack program call
- PUSH AX ;push value for return offset
-
- ; Push far pointer pointer to the start of the stack program.
- ; The stack program will be entered by executing a RETF after the
- ; registers are set up.
-
- PUSH SS ;push current stack segment for starting ptr
- MOV AX,SP ;get current stack offset
- ADD AX,6 ;move past the last three stack entries
- PUSH AX ;push offset for starting ptr of stack program
-
- ; Move the input array values from the stack to their actual registers.
-
- MOV AX,[BP].INT_FLGS ;get input flag register value
- AND AX,0000111111010101B ;mask out undefined 8086 flags
- PUSH AX ;push masked flag register value
-
- MOV AX,[BP].INT_AX ;set up input AX value
- MOV BX,[BP].INT_BX ;set up input BX value
- MOV CX,[BP].INT_CX ;set up input CX value
- MOV DX,[BP].INT_DX ;set up input DX value
-
- MOV SI,[BP].INT_SI ;set up input SI value
- MOV DI,[BP].INT_DI ;set up input DI value
-
- ; For DS and ES, leave in the compiler data segment values if:
- ; executing INTERRUPT; or executing INTERRUPTX with array values of -1.
-
- CMP WORD PTR [BP].REG_NUM,08H ;test if executing INTERRUPT
- JE INT_ES_DEF ;if so, then use both default values
-
- CMP [BP].INT_DS,0FFFFH ;test if default DS to be used
- JE INT_DS_DEF ;if so, then leave it unchanged
- MOV DS,[BP].INT_DS ;set up input DS value
- INT_DS_DEF:
- CMP [BP].INT_ES,0FFFFH ;test if default ES to be used
- JE INT_ES_DEF ;if so, then leave it unchanged
- MOV ES,[BP].INT_ES ;set up input ES value
- INT_ES_DEF:
-
- MOV BP,[BP].INT_BP ;set up input BP value
- ;must be last move using BP
-
- POPF ;set up input flag register value
-
- ; With all registers set according to the input array, execute the
- ; stack program.
- ;
- ; The following RETF pops the last two stack entries, which are
- ; interpreted as a far pointer to the stack program.
- ;
- ; The stack program executes the INT XX call which changes the
- ; registers (flags included) to the values to be put into the
- ; output array.
- ;
- ; The stack program then executes the RETF 06 instruction which
- ; does two operations. First, the next two entries on stack are
- ; popped and interpreted as a far ptr return address, which points
- ; the code at INT_RET in this code segment. Second, the stack
- ; pointer is then adjusted by six bytes to remove the six-byte
- ; program from the stack.
-
- RET ;far return to execute stack program, etc.
- INT_RET:
-
- ; The stack should now contain only the first entry past the
- ; frame, the value of the stack frame pointer itself. First
- ; save the BP value from the INT call, then get the old value
- ; to reference the frame.
-
- PUSH BP ;save post-INT value of BP
- MOV BP,SP ;temporary frame is second word past frame
- MOV BP,[BP+02H] ;get real frame reference value
-
- ; Put post-INT value of all registers into the frame variables
- ; to be subsequently written into the output array.
-
- PUSHF ;put flags on the stack
- POP [BP].INT_FLGS ;put in post-INT flag register value
-
- PUSH [BP].UCODE_FLGS ;get old copy of flags from frame
- POPF ;and restore the old flag values
-
- MOV [BP].INT_AX,AX ;put in post-INT AX value
- MOV [BP].INT_BX,BX ;put in post-INT BX value
- MOV [BP].INT_CX,CX ;put in post-INT CX value
- MOV [BP].INT_DX,DX ;put in post-INT DX value
-
- MOV AX,[BP].INT_BP_TMP ;get post-INT BP value (one entry past frame)
- MOV [BP].INT_BP,AX ;put in post-INT BP value
-
- MOV [BP].INT_SI,SI ;put in post-INT SI value
- MOV [BP].INT_DI,DI ;put in post-INT DI value
-
- MOV [BP].INT_DS,DS ;put in post-INT DS value
- MOV [BP].INT_ES,ES ;put in post-INT ES value
-
- ; Move frame register values to the output array whose
- ; far pointer is in the frame.
-
- MOV DS,[BP].UCODE_DS;replace original DS value
-
- LEA SI,[BP].INT_AX ;get start of register area in frame
-
- PUSH DS
- POP ES
- MOV DI,[BP].ARG3 ;get output array offset
- MOV CX,[BP].REG_NUM ;eight or ten words to move
- CLD ;movement is toward upper memory
- REP MOVSW ;perform the transfer
-
- ; Clean up stack to remove frame. Remove CALL arguments with RETF.
-
- MOV SI,[BP].OLD_SI ;replace old SI for interpreter
- MOV DI,[BP].OLD_DI ;replace old DI for interpreter
- MOV SP,BP ;deallocate temporary frame variables
- POP BP ;return compiler frame pointer
- RET 06 ;remove three CALL arguments and far return
-
- ; If error, then restore DS, set int_no to -1 to report error,
- ; clean up, and exit.
-
- INT_ERROR:
- MOV SI,[BP].ARG1 ;ptr to first CALL arg - interrupt number
- MOV [SI],0FFFFH ;set interrupt number to -1 for error
- MOV SI,[BP].OLD_SI ;replace old SI for interpreter
- MOV DI,[BP].OLD_DI ;replace old DI for interpreter
- MOV DS,[BP].UCODE_DS;replace original DS value
- MOV SP,BP ;deallocate temporary frame variables
- POP BP ;return compiler frame pointer
- RET 06 ;remove three CALL arguments and far return
-
- INTERRUPTX ENDP
-
- END
-