关于字符串的输出我们以前已经讨论了最简单的方法--调用INT 21H的9号功能。这个功能也有一些缺陷,比如说我们能否用此功能输出这个字符串--"PRICE $1.00"?很明显屏幕上根本看不到"1.00",因为"$"表示字符串结束。
解决方法不难,自编一段程序逐个输出每个字符即可。请看下例:
data segment assume ds:data mess db'Price:$1.00',0dh,0ah,0 ;定义一个中间含'$'符的字符串 data ends code segment assume cs:code main proc far mov ax,data ;初始化DS寄存器指向数据段 mov ds,ax mov bx,offset mess ;BX寄存器指向字符串首 outchar: mov dl,byte ptr [bx] ;取一个字符送入DL寄存器 cmp dl,0 ;是字符串结尾吗? jz exit ;是结尾则结束程序 jz exit ;是结尾则结束程序 mov ah,2 ;显示这个字符 int 21h inc bx ;BX寄存器指向下一个字符 jmp outchar ;处理下一个字符 exit: mov ah,4ch ;结束进程 int 21h main endp code ends end main
在这个程序中我们用"0"作字符串结束标志,用BX寄存器作为指针取得每个字符并用21H中断的2号功能输出。用BX作指针不大方便,若改用"串处理"指令会使程序简化一些,下面是经过修改的程序:
data segment assume ds:data mess db 'Price: $1.00',0dh,0ah,0 ;定义一个中间含有'$'的字符串 data ends code segment assume cs:code main proc far mov ax,data ;初始化DS寄存器指向数据段 mov ds,ax cld ;将方向标志位DF清0 mov si,offset mess ;SI寄存器指向字符串首地址 outchar: lodsb ;取一个字符送入AL寄存器 or al,al ;AL寄存器是0吗? jz exit ;是0则结束程序 mov ah,0eh ;选择10H中断的0EH功能 int 10h ;显示AL寄存器中的字符 jmp outchar ;处理下一个字符 exit: mov ah,4ch ;结束进程 int 21h main endp code ends end main
程序中又出现了一些新的东西,下面我们分别讨论:
我们在前面谈到过这个寄存器,它的主要用途是为"串处理"指令提供"源数据串"的首地址。之所以称它为"源"地址索引寄存器是因为只有那些有"取"数据操作的串指令才引用SI,而其它串指令如"串存"、"串扫描"指令都不使用SI寄存器。那么在这个程序中哪个指令是有"取"数据操作的串指令呢?
指令LODS就是一个用于取数据的串处理指令:
助记符:LODS(Load from string)
用 途:从DS:SI指示的内存单元中取出数据并放入累加器
格 式:LODSB(取一字节)
LODSW(取一个字)
执 行:LODSB--ALDS:[SI],同时SI +/- 1
LODSW--AXDS:[SI],同时SI +/- 2
指令最后的字母"B"和"W"表示所要取的数据类型是"BYTE"或"WORD"。所以"LODSB"的动作和"MOV AL,BYTE PTR DS:[SI]"相当,而"LODSW"则与"MOV AX,WORD PTR DS:[SI]"一样。但是LODS指令和MOV指令有两点区别:
① LODS指令只能将数据取入累加器中,不能取入别的寄存器;
② LODS指令不仅能取得数据,同时对提供地址的SI寄存器有操作--自动的加上或减去和取得数据等量的字节数。若取了1B数据,则SI变化1;而取得1W数据,则SI变化2。那么究竟什么情况下SI增量,什么情况下SI减量呢?这个问题将在下面回答。
DF是标志寄存器中的bit10位,它的置、复位情况将影响到执行串处理指令时SI(还有DI)寄存器的增与减。当DF置位(为1)时,每次执行指令后SI(DI)减量,这样就使得串处理从高地址向低地址方向进行;而DF复位(为0)时,每次执行指令后SI(DI)增量,串处理自然会从低地址向高地址方向进行。现在的问题就是如何设定DF的状态?
指令CLD就是一条用于控制DF状态的指令,和这条指令相对应的是STD指令:
助记符:CLD(Clear direction)/STD(Set direction)
用 途:使DF标志复位/置位
格 式:CLD/STD
执 行:DF<-0,DF清零/DF<-1,DF置1
这两条指令功能很简单,不再多说。
我们前面曾经提到过标志寄存器中某些位可以对CPU内部的工作状态进行控制,DF标志就是很典型的一例。
当我们将要显示的字符取入AL寄存器后,剩下的工作就是将这个字符显示在屏幕上。这一步可用DOS提供的2号功能实现,只要将AL中的ASCII码送入DL寄存器再调用DOS功能即可,不过在前面的程序中我们采用了一个更简捷的方法--调用BIOS 10H中断。
10H号中断调用也是由BIOS提供,它负责管理PC机的显示系统,我们在屏幕上看到的文字和图形一般都是经过10H号中断显示出来的。这个中断包括很多功能,现在要讨论的0EH功能是十分常用的一个,它被称为"TTY方式的字符显示功能"。
TTY是电传打字机,一种古老的设备,它可能比我本人出现的还要早。究竟什么是TTY方式?我也不能很确切的说出定义,不过这个功能同10H中断提供的其它一些显示文字的功能相比确有很大的不同:
① 使用这个功能显示一个字符后,光标会自动移到下一个位置;
② 本功能解释诸如0DH、0AH这样的控制码。
我想这两个有别于其它功能的特征就可以算是TTY方式的定义吧。它还有其它特性,我们将在下一章中学到。
通过这个程序我们应该对串处理指令有了一些很初步的认识:
事实上还有第五点:串处理指令往往有"指令前缀"且和CX寄存器也有密切关系,下面就会讲到这一点。