ITEEDU

10.7 驻留程序

驻留程序TSR(Terminate but Stay Resident)是一种特殊应用程序,它在装入内存运行后,其部分代码仍然驻留在内存,当该段代码被激活时,它又进入运行状态。常用的驻留程序是作为某个中断处理程序的一部分,其激活条件就是系统产生了此中断的中断请求。

虽然驻留程序可根据具体的需要有不同的编写方式,但其典型结构包括以下几部分:

  1. 保存、修改中断向量表;
  2. 程序第一次运行时的初始化部分:
    ◆用自己定义的地址来取代中断向量表中的原地址
    ◆确定驻留代码部分的字节数
    ◆用中断21H之功能31H把需要驻留代码部分驻留在内存
  3. 驻留内存的代码部分。

例10.15 在NumLock处于“开状态”时,每按小键盘(Numeric Keypad)上的数字键,给出“啪啪”响声。

解:

 CSEG SEGMENT 'CODE' 
ORG 100H 
      start:
              JMP       init
INT9 DD ? 
        TSR:
              PUSH      AX
              PUSH      CX
              PUSH      DS          ;保存寄存器
              MOV       AH, 2
              INT       16H         ;读取键盘当前状态
              TEST      AL, 00100000B           ;检测NumLock的状态
              JZ        TSRExit
              IN        AL, 60H
              CMP       AL, 71
              JL        TSRExit
              CMP       AL, 83
              JG        TSRExit
              MOV       AL, 10110110B
              OUT       43H, AL     ;向端口43H送特定的数0B6H
              MOV       AX, 1000
              OUT       42H, AL
              MOV       AL, AH
              OUT       42H, AL     ;向端口42H送声音频率
              IN        AL, 61H     ;读取扬声器的当前状态
              MOV       AH, AL      ;把扬声器的状态保存在AH中
              OR        AL, 03
              OUT       61H, AL     ;开声音
              MOV       CX, 9000
      delay:
              LOOP      delay       ;声音延迟
              MOV       AL, AH
              OUT       61H, AL     ;恢复扬声器原来的状态,即关声音
    TSRExit:
              POP       DS
              POP       CX
              POP       AX          ;恢复寄存器
              JMP       CS:INT9     ;转向中断9H原来的处理程序
       init:
              CLI                   ;关中断
              MOV       AH, 35H
              MOV       AL, 09H
              INT       21H
              MOV       WORD PTR INT9, BX
              MOV       WORD PTR INT9+2, ES     ;保存中断9H原处理程序入口地址
              MOV       AH, 25H
              MOV       AL, 09H
              LEA       DX, TSR
              INT       21H         ;设置中断9H新的处理程序入口地址
              STI                   ;开中断
              LEA       DX, init
              ADD       DX, 15
              MOV       CL, 4       ;把init的偏移量转换成“节数”
              SHR       DX, CL      ;每节内有16个字节
              MOV       AX, 3100H
              INT       21H
        CSEG  ENDS
              END       start

例10.16 编写一个驻留程序,它可显示当前时间的秒数。

解:

 CSEG SEGMENT 'CODE' 
  ORG 100H 
start: 
 JMP init 
INT1C DD ? 
SEC DW ? 
TSR: 
 PUSH AX 
PUSH BX 
PUSH  CX 
PUSH  DX 
PUSH  BP 
PUSH  DS 
PUSH  ES ;保存所用到的寄存器 
MOV AX, CS 
MOV DS, AX 
MOV  ES, AX ;把CS的值赋给DS和ES 
MOV  AH, 2H 
INT 1AH ;读取当前时间 
MOV  DL, DH 
AND  DH, 0FH 
MOV CL, 4 
SHR  DL, CL 
ADD  DX, 3030H 
MOV  SEC, DX ;把当前秒数转化成字符串 
MOV  AH, 13H 
MOV  AL, 0 
MOV BH, 0 
MOV  BL, 7 
MOV CX, 2 
MOV DX, 004EH  ;指定显示位置为(0,78) 
LEA  BP, SEC 
INT  10H ;在指定位置显示秒数 
POP ES ;恢复所用寄存器的值 
POP  DS 
POP  BP 
POP DX 
POP CX 
POP BX 
POP AX 
JMP CS:INT1C ;转向中断1CH原服务程序 
init: 
 CLI 
MOV AX, 351CH 
INT  21H 
MOV  word ptr INT1C, BX 
MOV word ptr INT1C+2, ES 
MOV  AX, 251CH 
LEA DX, TSR 
INT  21H 
STI 
LEA  DX, init 
ADD DX, 15 
MOV CL, 4 ;把init的偏移量转换成“节数” 
SHR DX, CL ;每节内有16个字节 
MOV AX, 3100H 
INT  21H 
CSEG  ENDS 
END  start