ID Number: Q39524
5.00 5.10
MS-DOS
Summary:
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.
More Information:
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