📄 _pmdos.asm
字号:
;****************************************************************************
;*
;* SciTech OS Portability Manager Library
;*
;* ========================================================================
;*
;* The contents of this file are subject to the SciTech MGL Public
;* License Version 1.0 (the "License"); you may not use this file
;* except in compliance with the License. You may obtain a copy of
;* the License at http://www.scitechsoft.com/mgl-license.txt
;*
;* Software distributed under the License is distributed on an
;* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
;* implied. See the License for the specific language governing
;* rights and limitations under the License.
;*
;* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
;*
;* The Initial Developer of the Original Code is SciTech Software, Inc.
;* All Rights Reserved.
;*
;* ========================================================================
;*
;* Language: 80386 Assembler, TASM 4.0 or NASM
;* Environment: IBM PC Real mode and 16/32 bit protected mode
;*
;* Description: Low level assembly support for the PM library specific to
;* MSDOS interrupt handling.
;*
;****************************************************************************
IDEAL
include "scitech.mac" ; Memory model macros
header _pmdos ; Set up memory model
; Define the size of our local stacks. For real mode code they cant be
; that big, but for 32 bit protected mode code we can make them nice and
; large so that complex C functions can be used.
ifdef flatmodel
MOUSE_STACK EQU 4096
TIMER_STACK EQU 4096
KEY_STACK EQU 1024
INT10_STACK EQU 1024
IRQ_STACK EQU 1024
else
MOUSE_STACK EQU 1024
TIMER_STACK EQU 512
KEY_STACK EQU 256
INT10_STACK EQU 256
IRQ_STACK EQU 256
endif
ifdef USE_NASM
; Macro to load DS and ES registers with correct value.
%imacro LOAD_DS 0
%ifdef flatmodel
mov ds,[cs:_PM_savedDS]
mov es,[cs:_PM_savedDS]
%else
push ax
mov ax,_DATA
mov ds,ax
pop ax
%endif
%endmacro
; Note that interrupts we disable interrupts during the following stack
; %imacro for correct operation, but we do not enable them again. Normally
; these %imacros are used within interrupt handlers so interrupts should
; already be off. We turn them back on explicitly later if the user code
; needs them to be back on.
; Macro to switch to a new local stack.
%imacro NEWSTK 1
cli
mov [seg_%1],ss
mov [ptr_%1],_sp
mov [TempSeg],ds
mov ss,[TempSeg]
mov _sp,offset %1
%endmacro
; %imacro to switch back to the old stack.
%imacro RESTSTK 1
cli
mov ss,[seg_%1]
mov _sp,[ptr_%1]
%endmacro
; %imacro to swap the current stack with the one saved away.
%imacro SWAPSTK 1
cli
mov ax,ss
xchg ax,[seg_%1]
mov ss,ax
xchg _sp,[ptr_%1]
%endmacro
else
; Macro to load DS and ES registers with correct value.
MACRO LOAD_DS
ifdef flatmodel
mov ds,[cs:_PM_savedDS]
mov es,[cs:_PM_savedDS]
else
push ax
mov ax,_DATA
mov ds,ax
pop ax
endif
ENDM
; Note that interrupts we disable interrupts during the following stack
; macro for correct operation, but we do not enable them again. Normally
; these macros are used within interrupt handlers so interrupts should
; already be off. We turn them back on explicitly later if the user code
; needs them to be back on.
; Macro to switch to a new local stack.
MACRO NEWSTK stkname
cli
mov [seg_&stkname&],ss
mov [ptr_&stkname&],_sp
mov [TempSeg],ds
mov ss,[TempSeg]
mov _sp,offset stkname
ENDM
; Macro to switch back to the old stack.
MACRO RESTSTK stkname
cli
mov ss,[seg_&stkname&]
mov _sp,[ptr_&stkname&]
ENDM
; Macro to swap the current stack with the one saved away.
MACRO SWAPSTK stkname
cli
mov ax,ss
xchg ax,[seg_&stkname&]
mov ss,ax
xchg _sp,[ptr_&stkname&]
ENDM
endif
begdataseg _pmdos
ifdef flatmodel
cextern _PM_savedDS,USHORT
endif
cextern _PM_critHandler,CPTR
cextern _PM_breakHandler,CPTR
cextern _PM_timerHandler,CPTR
cextern _PM_rtcHandler,CPTR
cextern _PM_keyHandler,CPTR
cextern _PM_key15Handler,CPTR
cextern _PM_mouseHandler,CPTR
cextern _PM_int10Handler,CPTR
cextern _PM_ctrlCPtr,DPTR
cextern _PM_ctrlBPtr,DPTR
cextern _PM_critPtr,DPTR
cextern _PM_prevTimer,FCPTR
cextern _PM_prevRTC,FCPTR
cextern _PM_prevKey,FCPTR
cextern _PM_prevKey15,FCPTR
cextern _PM_prevBreak,FCPTR
cextern _PM_prevCtrlC,FCPTR
cextern _PM_prevCritical,FCPTR
cextern _PM_prevRealTimer,ULONG
cextern _PM_prevRealRTC,ULONG
cextern _PM_prevRealKey,ULONG
cextern _PM_prevRealKey15,ULONG
cextern _PM_prevRealInt10,ULONG
cpublic _PM_pmdosDataStart
; Allocate space for all of the local stacks that we need. These stacks
; are not very large, but should be large enough for most purposes
; (generally you want to handle these interrupts quickly, simply storing
; the information for later and then returning). If you need bigger
; stacks then change the appropriate value in here.
ALIGN 4
dclb MOUSE_STACK ; Space for local stack (small)
MsStack: ; Stack starts at end!
ptr_MsStack DUINT 0 ; Place to store old stack offset
seg_MsStack dw 0 ; Place to store old stack segment
ALIGN 4
dclb INT10_STACK ; Space for local stack (small)
Int10Stack: ; Stack starts at end!
ptr_Int10Stack DUINT 0 ; Place to store old stack offset
seg_Int10Stack dw 0 ; Place to store old stack segment
ALIGN 4
dclb TIMER_STACK ; Space for local stack (small)
TmStack: ; Stack starts at end!
ptr_TmStack DUINT 0 ; Place to store old stack offset
seg_TmStack dw 0 ; Place to store old stack segment
ALIGN 4
dclb TIMER_STACK ; Space for local stack (small)
RtcStack: ; Stack starts at end!
ptr_RtcStack DUINT 0 ; Place to store old stack offset
seg_RtcStack dw 0 ; Place to store old stack segment
RtcInside dw 0 ; Are we still handling current interrupt
ALIGN 4
dclb KEY_STACK ; Space for local stack (small)
KyStack: ; Stack starts at end!
ptr_KyStack DUINT 0 ; Place to store old stack offset
seg_KyStack dw 0 ; Place to store old stack segment
KyInside dw 0 ; Are we still handling current interrupt
ALIGN 4
dclb KEY_STACK ; Space for local stack (small)
Ky15Stack: ; Stack starts at end!
ptr_Ky15Stack DUINT 0 ; Place to store old stack offset
seg_Ky15Stack dw 0 ; Place to store old stack segment
TempSeg dw 0 ; Place to store stack segment
cpublic _PM_pmdosDataEnd
enddataseg _pmdos
begcodeseg _pmdos ; Start of code segment
cpublic _PM_pmdosCodeStart
;----------------------------------------------------------------------------
; PM_mouseISR - Mouse interrupt subroutine dispatcher
;----------------------------------------------------------------------------
; Interrupt subroutine called by the mouse driver upon interrupts, to
; dispatch control to high level C based subroutines. Interrupts are on
; when we call the user code.
;
; It is _extremely_ important to save the state of the extended registers
; as these may well be trashed by the routines called from here and not
; restored correctly by the mouse interface module.
;
; NOTE: This routine switches to a local stack before calling any C code,
; and hence is _not_ re-entrant. For mouse handlers this is not a
; problem, as the mouse driver arbitrates calls to the user mouse
; handler for us.
;
; Entry: AX - Condition mask giving reason for call
; BX - Mouse button state
; CX - Horizontal cursor coordinate
; DX - Vertical cursor coordinate
; SI - Horizontal mickey value
; DI - Vertical mickey value
;
;----------------------------------------------------------------------------
ifdef DJGPP
cprocstart _PM_mouseISR
else
cprocfar _PM_mouseISR
endif
push ds ; Save value of DS
push es
pushad ; Save _all_ extended registers
cld ; Clear direction flag
LOAD_DS ; Load DS register
NEWSTK MsStack ; Switch to local stack
; Call the installed high level C code routine
clrhi dx ; Clear out high order values
clrhi cx
clrhi bx
clrhi ax
sgnhi si
sgnhi di
push _di
push _si
push _dx
push _cx
push _bx
push _ax
sti ; Enable interrupts
call [CPTR _PM_mouseHandler]
_add sp,12,24
RESTSTK MsStack ; Restore previous stack
popad ; Restore all extended registers
pop es
pop ds
ret ; We are done!!
cprocend
;----------------------------------------------------------------------------
; PM_timerISR - Timer interrupt subroutine dispatcher
;----------------------------------------------------------------------------
; Hardware interrupt handler for the timer interrupt, to dispatch control
; to high level C based subroutines. We save the state of all registers
; in this routine, and switch to a local stack. Interrupts are *off*
; when we call the user code.
;
; NOTE: This routine switches to a local stack before calling any C code,
; and hence is _not_ re-entrant. Make sure your C code executes as
; quickly as possible, since a timer overrun will simply hang the
; system.
;----------------------------------------------------------------------------
cprocfar _PM_timerISR
push ds ; Save value of DS
push es
pushad ; Save _all_ extended registers
cld ; Clear direction flag
LOAD_DS ; Load DS register
NEWSTK TmStack ; Switch to local stack
call [CPTR _PM_timerHandler]
RESTSTK TmStack ; Restore previous stack
popad ; Restore all extended registers
pop es
pop ds
iret ; Return from interrupt
cprocend
;----------------------------------------------------------------------------
; PM_chainPrevTimer - Chain to previous timer interrupt and return
;----------------------------------------------------------------------------
; Chains to the previous timer interrupt routine and returns control
; back to the high level interrupt handler.
;----------------------------------------------------------------------------
cprocstart PM_chainPrevTimer
ifdef TNT
push eax
push ebx
push ecx
pushfd ; Push flags on stack to simulate interrupt
mov ax,250Eh ; Call real mode procedure function
mov ebx,[_PM_prevRealTimer]
mov ecx,1 ; Copy real mode flags to real mode stack
int 21h ; Call the real mode code
popfd
pop ecx
pop ebx
pop eax
ret
else
SWAPSTK TmStack ; Swap back to previous stack
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -