ITEEDU

关于字符串的输出我们以前已经讨论了最简单的方法--调用INT 21H的9号功能。这个功能也有一些缺陷,比如说我们能否用此功能输出这个字符串--"PRICE $1.00"?很明显屏幕上根本看不到"1.00",因为"$"表示字符串结束。

解决方法不难,自编一段程序逐个输出每个字符即可。请看下例:

OUTSTR.ASM
        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作指针不大方便,若改用"串处理"指令会使程序简化一些,下面是经过修改的程序:

OUTSTR1.ASM
        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

程序中又出现了一些新的东西,下面我们分别讨论:

(1)SI--源地址索引寄存器(Source Index)

我们在前面谈到过这个寄存器,它的主要用途是为"串处理"指令提供"源数据串"的首地址。之所以称它为"源"地址索引寄存器是因为只有那些有"取"数据操作的串指令才引用SI,而其它串指令如"串存"、"串扫描"指令都不使用SI寄存器。那么在这个程序中哪个指令是有"取"数据操作的串指令呢?

(2)"从串取"指令

指令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减量呢?这个问题将在下面回答。

 (3)方向标志--DF(Direction Flag)

DF是标志寄存器中的bit10位,它的置、复位情况将影响到执行串处理指令时SI(还有DI)寄存器的增与减。当DF置位(为1)时,每次执行指令后SI(DI)减量,这样就使得串处理从高地址向低地址方向进行;而DF复位(为0)时,每次执行指令后SI(DI)增量,串处理自然会从低地址向高地址方向进行。现在的问题就是如何设定DF的状态?

(4)"D"标志控制指令

指令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中断。

(5)INT 10H的0EH功能。

10H号中断调用也是由BIOS提供,它负责管理PC机的显示系统,我们在屏幕上看到的文字和图形一般都是经过10H号中断显示出来的。这个中断包括很多功能,现在要讨论的0EH功能是十分常用的一个,它被称为"TTY方式的字符显示功能"。

TTY是电传打字机,一种古老的设备,它可能比我本人出现的还要早。究竟什么是TTY方式?我也不能很确切的说出定义,不过这个功能同10H中断提供的其它一些显示文字的功能相比确有很大的不同:

① 使用这个功能显示一个字符后,光标会自动移到下一个位置;
② 本功能解释诸如0DH、0AH这样的控制码。

我想这两个有别于其它功能的特征就可以算是TTY方式的定义吧。它还有其它特性,我们将在下一章中学到。

通过这个程序我们应该对串处理指令有了一些很初步的认识:

事实上还有第五点:串处理指令往往有"指令前缀"且和CX寄存器也有密切关系,下面就会讲到这一点。