ITEEDU

3.3 子程序

3.3节导航:第一页 第二页 第三页

操作系统提供了大量的功能为我们编程时调用,但是仅仅靠这些功能还不能解决所有的问题,比如说我们想把AL寄存器中的数据以二进制的形式显示在屏幕上,这样的功能操作系统可没有提供,解决这样的问题就只能"自力更生"了。

同时也可以发现,有一些问题并非仅出现在一个程序中,可能在编制不同程序时都要遇到同样的问题。解决这些具有普遍性的问题的最好方法末过于单独编制解决特定问题的小段程序并保留起来,在需要时随时将这些小程序加入我们的程序中。所谓的子程序,也就是这样一些供别的程序调用且能解决一些较普遍问题的小程序。

PROG4
-a100[Enter]
0F92:0100 mov ah,1          ;选择DOS API的01H功能
0F92:0102 int 21            ;调用21H中断等待键盘输入
0F92:0104 mov cx,8          ;需要处理8个数位
0F92:0107 mov bh,80         ;BH寄存器置入10000000B
0F92:0109 mov dh,al         ;DH寄存器保存输入字符的ASCII码副本
0F92:010B mov dl,30         ;DL寄存置入字符0的ASCII码30H
0F92:010D and al,bh         ;将输入字符的ASCII码与10000000B相与,保留最左一位
0F92:010F jz 113            ;如最左位是0,则转去0113H继续执行
0F92:0111 mov dl,31         ;若最左位是1,则DL寄存器置入字符1的ASCII码31H
0F92:0113 mov ah,2          ;选择DOS API的02H功能
0F92:0115 int 21            ;调用21H中断显示DL寄存器中的字符
0F92:0117 mov al,dh         ;AL寄存器取回输入字符的副本
0F92:0119 shr bh,1          ;将BH最左位的1右移一位
0F92:011B loop 10b          ;返回010BH,处理ASCII码的Bit6位
0F92:011D int 20            ;处理所有的8个位后结束程序
09FE:0126 [Enter]

上面给出的PROG4程序可以将键盘输入字符的ASCII码以二进制形式显示出来。将此程序存盘后,用"G=100[Enter]"执行这个程序,从键盘输入小写"a",屏幕上就会显示出01100001,这就是十六进制数61H,也就是"a"的ASCII码,PROG4的核心就是将AL寄存器的值以二进制的形式显示在屏幕上。

在讨论有关子程序的问题之前,我们先来学习程序中出现两条新指令:

助记符:SHR(Shift Right)
用 途:将寄存器或存储器中的数向右移位。
格 式:SHR 寄存器,1
SHR 寄存器,CL
SHR 存储单元,1
SHR 存储单元,CL
执 行:寄存器或存储器中的数据向右移动1位或CL中指定的位数,最高位填入
0,最低一位移入CF标志

图3-1反映了SHR指令执行的情况。从图中可以看出,假如利用SHR指令将8位二进制数10110110右移2位,应该得到00101101,同时标志寄存器中CF位会被置成1。


图3-1 SHR指令执行的情况示意图

助记符:AND
用 途:将两个数据作"与"逻辑操作
格 式:AND 寄存器,立即数
AND 寄存器,寄存器
AND 寄存器,存储单元
AND 存储单元,寄存器
AND 存储单元,立即数

程序采用的算法并不难理解,为了测试AL中各个位的0、1状态,我们先在BH中放入二进制数10000000,这个数称为"掩模(MASK)",然后用BH与AL作AND操作。很明显AL中的数据将有7位被"屏敝",只有和BH中为1的位相对应的数位被保留。若这一位恰好为0,则AND操作的结果就是0,此时ZF标志置位;反之若这一位为1,那么ZF就会复位。用JZ指令依据ZF状态进行转移,分别输出0和1,然后将"掩模"中的"1"向右移动一位,再循环执行前面的测试部分,八次循环后在屏幕上将显示出AL中数据的二进制形式。

现在我们把程序中输出数据部分改写成子程序,如PROG4-A所示:

PROG4-A
-a100[Enter]
0A3E:0100 MOV AH,01            ;选择DOS API的01H功能
0A3E:0102 INT 21               ;调用21H中断等待键盘输入
0A3E:0104 CALL 010D            ;调用位于010DH处的子程序
0A3E:0107 CMP AL,1B            ;判断输入的字符是否为"ESC"
0A3E:0109 JNZ 0100             ;若输入字符不是"ESC",则转至0100H处继续接收字符
0A3E:010B INT 20               ;若输入字符是"ESC"则结束程序
0A3E:010D PUSH AX              ;子程序开始,保存AX寄存器
0A3E:010E MOV DH,AL            ;输入字符的ASCII码置入DH寄存器
0A3E:0110 MOV BH,80            ;BH寄存器置入"掩膜"10000000B
0A3E:0112 MOV CX,0008          ;处理8个数位 
0A3E:0115 MOV DL,30            ;DL寄存器置入字符0的ASCII码30H
0A3E:0117 MOV BL,DH            ;BL寄存器置入输入字符的ASCII码
0A3E:0119 AND BL,BH            ;将ASCII码与"掩膜"相与
0A3E:011B JZ 011F              ;若结果为0,则转至011F显示字符0
0A3E:011D MOV DL,31            ;若结果不为0,则将字符1的ASCII码置入DL寄存器 
0A3E:011F MOV AH,02            ;选择DOS API的02H功能 
0A3E:0121 INT 21               ;调用21H中断显示DL寄存器中的字符 
0A3E:0123 SHR BH,1             ;"掩膜"向右移动一位 
0A3E:0125 LOOP 0115            ;循环至0115处理Bit6位
0A3E:0127 POP AX               ;恢复AX寄存器的原值
0A3E:0128 RET                  ;返回主程序 
0A3E:0129 [Enter]

(注:请务必先把此程序用PROG4-A.COM为名字存盘,然后用"Q"命令返回DOS,再继续阅读下面的内容。)