Q39524: TSR in Assembly
Article: Q39524
Product(s): See article
Version(s): 5.00 5.10
Operating System(s): MS-DOS
Keyword(s): ENDUSER | | mspl13_masm
Last Modified: 12-JAN-1989
Terminate and stay resident (TSR) programs consist of RAM-resident and
transient portions. When a TSR is executed, the transient portion
initializes data and installs the interrupt handlers; the transient
portion only takes place once. On exit, the transient code executes a
MS-DOS TSR function to leave the RAM-resident portion in memory. The
RAM-resident portion of the code is now ready and waiting to be
invoked.
Typically a TSR is invoked by another program by a sequence of
keystrokes, or by a system interrupt. The following is an example of a
TSR that displays the system time in the upper-right corner of the
screen. During the transient portion, the TSR replaces the
system-timer interrupt code with its own code and saves the old
address so the original system-timer interrupt can be invoked by the
new code. The system-timer interrupt occurs approximately 19 times a
second, and is required for the system to execute correctly. The
RAM-resident portion of the TSR first invokes the original
system-timer interrupt, then calls Interrupt 1AH function 02H to
obtain the current time. The time is then displayed in the upper-right
corner of the screen.
The following sample program demonstrates this behavior:
_text segment para public 'CODE'
org 100h
.286 ; Used for PUSHA and POPA intstuctions
; If 8086 you will need to explictly
; push all the registers on the stack
assume cs:_text,ds:_text
start:
jmp initialize
old_timer dd ? ; space for old timer vector
timer_int proc far
sti ; enable interupts
assume ds:nothing
pushf ; put flags on stack
call old_timer
push ax ; save registers
push cx
push dx
mov ah,02h
int 1ah ; get time Returns:
; ch = hours in BCD
; cl = minutes in BCD
; dh = seconds in BCD
; dl ignored
call print_drv ; call time to read time
pop dx
pop cx
pop ax ; restore registers
iret
timer_int endp
print_drv proc near
assume cs:_text,ds:_text
pusha ; Save registers
push es ; Save Segment registers
push ds
mov bx,cs
mov ds,bx ; data seg = code seg
call getpos
push bx ; save cursor on stack
mov bx,41h
call setpos ; move cursor to right hand corner
call display_time
pop bx
call setpos ; restore cursor
pop ds ; restore Segment registers
pop es ; restore registers
popa
ret
print_drv endp
display_time proc near
assume cs:_text,ds:_text
push ax
push bx
push cx
push si
mov ax,cs ; Data Seg = Code Seg
mov ds,ax
; Output hours
mov bx,cx ; move hours to bx
mov al,bh
mov cl,4 ; Set shift count to 4
shr ax,cl ; rotate to low nybble
and ax,000FH ; Mask out all but low nybble
mov si,ax ; Use low nybble as index into
mov al,byte ptr asciitab [si] ; asciitable
call dchar ; print 1st digit of hours
mov al,bh
and ax,000FH ; Mask out all but low nybble
mov si,ax ; Use low nybble as index into
mov al,byte ptr asciitab [si] ; asciitable
call dchar
call dcolon
; Output Minutes
mov al,bl ; move hours to bx
mov cl,4 ; Set shift count to 8
shr ax,cl ; rotate to low nybble
and ax,000FH ; Mask out all but low nybble
mov si,ax ; Use low nybble as index into
mov al,byte ptr asciitab [si] ; asciitable
call dchar ; print 1st digit of hours
mov al,bl
and ax,000FH ; Mask out all but low nybble
mov si,ax ; Use low nybble as index into
mov al,byte ptr asciitab [si] ; asciitable
call dchar ; print 1st digit of hours
call dcolon
; Output Seconds
mov al,dh ; move hours to bx
mov cl,4 ; Set shift count to 4
shr ax,cl ; rotate to low nybble
and ax,000FH ; Mask out all but low nybble
mov si,ax ; Use low nybble as index into
mov al,byte ptr asciitab [si] ; asciitable
call dchar ; print 1st digit of hours
mov al,dh
and ax,000FH ; Mask out all but low nybble
mov si,ax ; Use low nybble as index into
mov al,byte ptr asciitab [si] ; asciitable
call dchar
pop si
pop cx
pop bx
pop ax
ret
display_time endp
; Get the current cursor position and return it in BX
getpos proc near
push ax
push cx
push dx
mov ah,03h
mov bh,0 ; page zero
int 10h
mov bx,dx ; Return the positon in BX
pop dx
pop cx
pop ax
ret
getpos endp
; Set the current cursor postion to the vaule in BX
setpos proc near
push ax
push bx
push dx
mov ah,02h ; use int 10h function 2 to set cursor position
mov dx,bx
mov bh,0
int 10h
pop dx
pop bx
pop ax
ret
setpos endp
dcolon proc near
mov al,':'
call dchar
ret
dcolon endp
; Display the character contained in Al
dchar proc near
push ax
push bx
mov bh,1
mov ah,0eh
int 10h
pop bx
pop ax
ret
dchar endp
asciitab: db '0123456789',0
; The following section of code executes during initial program
; execution.
initialize:
assume ds:_text
mov bx,cs ; data_seg = code_seg
mov ds,bx
mov al,08h ; get vector of interrupt timer
mov ah,35h ;
int 21h
mov word ptr old_timer, bx ; save vector
mov word ptr old_timer[2],es
mov dx,offset timer_int
mov al,08h
mov ah,25h ; replace system interrupt
int 21h ; with our timer_int
mov dx,offset initialize ; terminate and stay resident
int 27h ; int 21h would work
_text ends
end start
THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.
Copyright Microsoft Corporation 1986-2002.