《微机原理2》ppt课件

《微机原理2》ppt课件

ID:40052626

大小:2.91 MB

页数:248页

时间:2019-07-18

上传者:U-145848
《微机原理2》ppt课件_第1页
《微机原理2》ppt课件_第2页
《微机原理2》ppt课件_第3页
《微机原理2》ppt课件_第4页
《微机原理2》ppt课件_第5页
资源描述:

《《微机原理2》ppt课件》由会员上传分享,免费在线阅读,更多相关内容在教育资源-天天文库

第4章汇编语言程序设计4.1汇编语言程序格式4.2伪指令4.3汇编语言源程序结构4.4汇编语言程序的上机过程4.5汇编语言程序设计4.6程序设计举例 4.1汇编语言程序格式4.1.1程序结构【例4-1】给出一个完整的汇编语言源程序,该程序的功能是完成两个字节数据相加。DATASEGMENT;段定义开始(DATA段)BUF1DB34H;第1个加数BUF2DB2AH;第2个加数SUMDB?;准备用来存放和数的单元DATAENDS;段定义结束(DATA段)CODESEGMENT;段定义开始(CODE段)ASSUMECS:CODE,DS:DATA;规定DATA、CODE分别为数据段;和代码段 START:MOVAX,DATAMOVDS,AX;给数据段寄存器DS赋值MOVAL,BUF1;取第1个加数ADDAL,BUF2;和第2个加数相加MOVSUM,AL;存放结果MOVAH,4CHINT21H;返回DOS状态CODEENDS;段定义结束(CODE段)ENDSTART;整个源程序结束518 从上面这个例子可以看出,汇编语言源程序由若干条语句组成,语句分为如下两类。1)指令语句指令语句是由8086/8088CPU提供的指令形成的语句,能完成一定的操作功能,能够翻译成机器代码的语句。 2)伪指令语句伪指令语句也叫指示性语句,它只是为汇编程序在翻译汇编语言源程序时提供有关信息,并不翻译成机器代码。例如,程序中的语句:BUF1DB34HBUF2DB2AHSUMDB?以上这些语句都是伪指令语句,其功能是在内存中开辟3个名字分别为BUF1、BUF2、SUM的字节单元,前两个单元的初值分别为34H和2AH,SUM仅指定一个字节单元,不定义确定的初值。实际上,汇编语言源程序中还可出现宏指令语句。宏指令语句就是由若干条指令语句形成的语句体。一条宏指令语句的功能相当于若干条指令语句的功能。 4.1.2语句格式指令语句和伪指令语句的格式是类似的,其格式如下:[名字]指令助记符操作数[;注释]其中,带方括号的项可以省略,注释内容以分号(;)引导。1.名字1)名字的标识符名字也就是由用户按一定规则定义的标识符,可由下列符号组成:(1)英文字母(A~Z,a~z);(2)数字(0~9);(3)特殊符号(?、@、_等)。 2)名字的定义规则名字的定义要满足如下规则:(1)数字不能作为名字的第一个符号;(2)单独的问号(?)不能作为名字;(3)一个名字的最大有效长度为31位,超过31位的部分计算机不再识别;(4)汇编语言中有特定含义的保留字(如操作码、寄存器名等),不能作为名字使用。为了便于记忆,名字的定义应该做到见名知义,如用BUFFER表示缓冲区、SUM表示累加和等。 3)名字的两种主要形式名字有标号和变量两种主要形式。(1)标号在代码段中定义,后面跟着冒号“:”,标号有三种属性:段、偏移及类型。段属性:用于定义标号的程序段起始地址。当程序中引用一个标号时,该标号的段地址则总是在CS寄存器中。偏移属性:标号的偏移地址是从段起始地址到定义标号的位置之间的字节数。为16位无符号数;类型属性:用来指出该标号是在本段内引用还是在其他段中引用的。如在段内引用,则称为NEAR属性,如在段外引用,则称为FAR。 (2)变量在数据段、附加数据段或堆栈段中定义,后面不跟冒号。它也可以用LABEL或EQU伪操作来定义。变量经常在操作数字段出现,它也有段、偏移及类型三种属性。段属性:用于定义变量所在段的段起始地址。此值必须在一个段寄存器中(如DS或ES中)。偏移属性:变量的偏移地址是从段的起始地址到定义变量的位置之间的字节数。为16位无符号数。 类型属性:变量的类型属性定义该变量所占的字节数。如BYTE(DB,1个字节长)、WORD(DW,2个字节长)、DWORD(DD,4个字节长)、FWORD(DF,6个字节长)、QWORD(DQ,8个字节长)、TBYTE(DT,10个字节长)。在同一个程序中,同样的标号或变量的定义只允许出现一次,否则汇编程序会指示出错。 2.指令助记符指令助记符用来指明不同的操作指令。如MOV、ADD等都是指令助记符。3.操作数指令中的操作数是用来指定参与操作的数据。对于一般指令,可以有一个或两个操作数,也可以没有操作数;对于伪指令和宏指令,可以有多个操作数。当操作数多于一个时,操作数之间用逗号分开。操作数可以是常数和表达式。 1)常数(1)数值常数。汇编语言中的数值常数可以是二进制、八进制、十进制或十六进制数,书写时用加后缀(二进制用B、八进制用O或Q、十进制用D、十六进制用H)的方式标明即可。对于十进制数可以省掉后缀,对于十六进制数,当以A~F开头时,前面加数字0,以避免和名字混淆,如十六进制数A6H应该写成0A6H,否则容易和名字A6H相混。 (2)字符串常数。包含在单引号中的若干个字符形成字符串常数,字符串在计算机中存储的是相应字符的ASCII码。如‘A’的值是41H,‘AB’的值是4142H等。(3)符号常数。常数用符号名来代替就是符号常数。如用COUNTEQU3或COUNT=3定义后,COUNT就是一个符号常数,与数值常数3等价。 2)表达式由运算对象和运算符组成的合法式子就是表达式,分为数值表达式和地址表达式两种。数值表达式的运算结果是一个数,地址表达式的运算结果是一个存储单元的地址。(1)算术运算符有+(加)、-(减)、*(乘)、/(除)、MOD(取余)。算术运算符可以用于数值表达式和地址表达式中,用于计算数据或地址的结果:下面的两条指令是正确的。MOVAL,4*8+5;数值表达式MOVSI,OFFSETBUF+12;地址表达式 (2)逻辑运算符有AND(与)、OR(或)、XOR(异或)、NOT(非)。逻辑运算符只能用于数值表达式中,不能用于地址表达式中。逻辑运算符和逻辑运算指令是有区别的。逻辑运算符的功能在汇编阶段完成,逻辑运算指令的功能在程序执行阶段完成。在汇编阶段,指令ANDAL,78HAND0FH等价于指令ANDAL,08H。 (3)关系运算符有EQ(相等)、LT(小于)、LE(小于等于)、GT(大于)、GE(大于等于)、NE(不等于)。关系运算符要有两个运算对象,两个运算对象要么都是数值,要么都是同一个段内的地址。运算结果为真时,表示为0FFFFH;运算结果为假时,表示为0000H。指令MOVBX,32EQ45等价于MOVBX,0;指令MOVBX,56GT30等价于MOVBX,0FFFFH。 4.1.3汇编语言的运算符1、分析运算符分析运算符的运算对象是存储器操作数,即由变量名或标号形成的地址表达式,运算结果是一个数值。运算符的格式为:运算符地址表达式分析运算符包括:OFFSET、SEG、TYPE、SIZE和LENGTH等,合成运算符有PTR、THIS、SHORT等。①SEG:利用SEG操作符可以得到一个标号或变量的段值例:MOVAX,SEGBUFF②OFFSET:利用OFFSET可以得到一个标号或变量的偏移地址例:MOVBX,OFFSETBUFF;(LEABX,BUFF) ③TYPE:运算符TYPE的运算结果是一个数值,这个数值与存储器操作数类型属性的对应关系如下:对于变量有3种:1字节型;2字型;4双字型;对于标号有2种:-1NEAR(段内),-2FAR(段间)。例:BUFFDB20HMOVBX,TYPEBUFFMOVBX,01 ④LENGTH操作符:LENGTH运算符得到这个变量的个数。如果未用DUP说明,得到的结果为1。⑤SIZE操作符:如果一个变量已经用DUP说明,则利用SIZE运算符可以得到分配给该变量的字节总数,如果未用DUP说明,则结果是TYPE运算的结果。即:SIZE=TYPE×LENGTH例:BUFFDW10DUP(?)MOVCX,LENGTHBUFFMOVCX,10MOVCX,SIZEBUFMOVCX,20 (1)PTR运算符:功能是对已分配的存储器地址临时赋予另一种类型属性,但不改变操作数本身的类型属性格式:类型PTR表达式利用PTR运算符还可以建立一个新的存储器操作数,它与原来的同名操作数具有相同的段和偏移量,但可以有不同的类型,不过这个新类型仅在当前语句有效。如:STUFFDD?……MOVBX,WORDPTRSTUFF指令:MOVBX,STUFF是否正确?为什么?2.组合运算符合成运算符则可以规定存储器操作数的某个属性,例如类型等。MOVWORDPTR[BX],AXMOVBYTEPTRDAT,ALJMPFARPTRLPT (2)THIS运算符:THIS运算符用来定义一个新类型的变量或标号。但它只指定变量或标号的类型属性,并不为它分配存储区,它的段属性和偏移属性与下一条可分配地址的变量或标号属性相同。格式:THIS类型例:FIRSTEQUTHISBYTESECONDDW100DUP(?)这里FIRST和SECOND实际上代表同一个数据区,其中共有200个字节,但FIRET的类型为字节、SECOND的类型为字。以下指令是正确的:MOVAX,SECOND+2MOVBH,FIRST+41235467833465879….23FIRSTSECOND(AX)=7846H(BH)=33H指令:MOVAX,FIRSTMOVBH,SECOND+3是否正确? 3.分离运算符HIGH和LOW运算符HIGH和LOW分别用来得到一个数值或地址表达式的高位和低位字节。例如:STUFFEQU0ABCDHMOVAH,HIGHSTUFFMOVAL,LOWSTUFF(AH)=0ABH(AL)=0CDHMOVAL,2238HMOVAH,HIGH2238 以上介绍了表达式中使用的各种运算符,如果一个表达式中同时具有多个运算符,则按照以下规则进行运算:优先级高的先运算;优先级低的后运算。优先级相同时按表达式中从左到右的顺序运算。圆括号可提高运算的优先级,圆括号内的运算总是在其任何相临的运算之前进行。各种运算符的优先级见表3.2,表中同一行中的运算符具有同等的优先级。 4.注释项注释是语句的说明部分,用来说明一条指令或一段程序的功能,由分号(;)开始。适当地加些注释内容,可以增加程序的可读性,便于阅读、理解和修改程序。汇编源程序时,注释部分不产生机器代码。一条语句可以写成多行,续行符使用&。 4.2伪指令汇编语言程序的语句除指令以外还可以由伪操作和宏指令组成。伪操作又称为伪指令,它们不像机器指令那样是在程序运行期间由计算机来执行的,而是在汇编程序对源程序汇编期间由汇编程序处理的,它们可以完成如处理器选择、定义程序模式、定义数据、分配存储区、指示程序结束等功能。伪指令形式上与一般指令相似,但伪指令只是为汇编程序提供有关信息,不产生相应的机器代码。 4.2.1定义符号的伪指令1.等值伪指令EQU格式:<符号名>EQU<表达式>功能:给符号名定义一个值,赋予一个符号名、表达式或助记符。此后,程序中凡需要用到该表达式之处,就可以用表达式名来代替了。可见,EQU的引入提高了程序的可读性,也使其更加易于修改。上式中的表达式可以是任何有效的操作数格式,可以是任何可以求出常数值的表达式,也可以是任何有效的助记符。举例如下: CONSTANTEQU256;将数256赋以符号名CONSTANTDATAEQUHEIGHT+12;HEIGHT为一标号,地址表达式赋;以符号名DATAALPHAEQU7BETAEQUALPHA-2;这是一组赋值伪操作,把7-2=5赋以;符号名BETAADDREQUVAR+BETA;将VAR+5赋以符号名ADDRBEQU[BP+8];变址引用赋以符号名BP8EQUDS:[BP+8];加段前缀的变址引用赋以符号名P8 在EQU语句的表达式中,如果有变量或标号的表达式,则在该语句前应该先给出它们的定义。例如,语句ABEQUDATA_ONE+2必须放在DATA_ONE的定义之后,否则汇编程序将指示出错。 2.等号伪指令“=”另外,还有一个与EQU相类似的“=”伪操作也可以作为赋值操作使用。它们之间的区别是:EQU伪操作中的表达式名是不允许重复定义的,而“=”伪操作则允许重复定义。例如,EMP=6或EMPEQU6都可以使数6赋给符号名EMP,然而不允许两者同时使用。但是,语句EMP=7EMP=EMP+1在程序中是允许使用的,因为“=”伪操作允许重复定义。这种情况下,在第一个语句后的指令中,EMP的值为7;而在第二个语句后的指令中,EMP的值为8。…… 3、解除定义伪操作PRGE格式:PURGE<符号1,符号2,…….符号N>功能:解除指定符号的定义。解除符号后,可用EQU重新进行定义。Y1EQU7;定义Y1的值为7PURGEY1;解除Y1的定义Y1EQU36;重新定义Y1的值为36 4.2.2定义数据的伪指令这一类伪指令的格式是:[变量]助记符操作数,…,操作数[;注释]功能:为操作数分配存储单元,并用变量与存储单元建立联系。其中,变量是可有可无的,它用符号地址表示,其作用与指令语句前的标号相同,但它的后面不跟冒号。如果语句中有变量名,则汇编程序使其记为第一个字节的偏移地址。注释字段用来说明该伪指令的功能,它也是可有可无的。助记符即伪指令用来说明所定义的数据类型。 常用的伪指令有以下几种:(1)DB用来定义字节,其后的每个操作数都占有一个字节(8位)的存储单元。(2)DW用来定义字,其后的每个操作数占有一个字(16位,其低位字节在第一个字节地址中,高位字节在第二个字节地址中)。(3)DD用来定义双字(4个字节),其后的每个操作数占有两个字(32位)。(4)DF用来定义3字(6个字节),其后的每个操作数占有48位,可用来存放远地址。这一伪指令只能用于386及其后继机型中。 (5)DQ用来定义4字(8个字节),其后的每个操作数占有4个字(64位),可用来存放双精度浮点数。(6)DT用来定义5字(10个字节),其后的每个操作数占有5个字,形成压缩的BCD码形式。这些伪指令可以把其后跟着的数据存入指定的存储单元,形成初始化数据,或者只分配存储空间而并不存入确定的数值,形成未初始化数据空间。DW和DD伪指令还可存储地址,DF伪指令则可存储由16位段地址及32位偏移地址组成的远地址指针。下面举例说明。 【例4-2】操作数可以是常数,或者是表达式(根据该表达式可以求得一个常数),如:DATA_BYTEDB10,4,10HDATA_WORDDW100,100H,-5DATA_DWDD60,0FFFDH000A041064000001FBFF3C000000FDFF00DATA_BYTEDATA_DW10D4D10H100D100H5D60D0FFFDHDATA_WORD 【例4-3】操作数也可以是字符串,如:MESSAGEDB'HELLO'存储情况如图4.2(a)所示,48454C4C4FHELLOMESSAGE(a)图4.2 图4.2例4-3的汇编结果而DB‘AB’和DW‘AB’的存储情况分别如下: 【例4-4】操作数“?”可以保留存储空间,但不存入数据。如:ABCDB0,?,?,0DEFDW?,52,?经汇编后的存储情况如图4.3所示。图4.3例4-4的汇编结果 操作数还可以使用复制操作符(DUPLICATIONOPERATOR)来复制某个(或某些)操作数。其格式为REPEAT_COUNTDUP(OPERAND,…,OPERAND)其中,REPEAT_COUNT可以是一个表达式,它的值应该是一个正整数,用来指定括号中的操作数的重复次数。 【例4-5】使用DUP实现重复定义。ARRAY1DB2DUP(0,1,2,?)ARRAY2DB100DUP(?)经汇编后的存储情况如图4.4所示。由图可见,例4-5中的第一个语句和语句ARRAY1DB0,1,2,?,0,1,2,?是等价的。000102----000102------ARRAY1ARRAY2100个字节 4.2.3定义程序开始和结束的伪指令在程序的开始部分可以用NAME或TITLE为模块命名。NAME的格式是:NAMEMODULE_NAME汇编程序将以给出的MODULE_NAME作为模块的名字。如果程序中没有使用NAME伪操作,则可使用TITLE伪操作,其格式为TITLETEXT TITLE伪操作可指定列表文件的每一页上打印的标题。同时,如果程序中没有使用NAME伪操作,则汇编程序将用TEXT中的前六个字符作为模块名。TEXT中最多可有60个字符。如果程序中既无NAME又无TITLE伪操作,则将用源文件名作为模块名。所以,NAME及TITLE伪操作并不是必要的,但一般经常使用TITLE,以便在列表文件中能打印出标题来。表示源程序结束的伪操作的格式为END[LABEL] 其中,标号(LABEL)指示程序开始执行的起始地址。如果多个程序模块相连接,则只有主程序要使用标号,其他子程序模块只用END而不必指定标号。汇编程序将在遇到END时结束汇编,而程序则将从主模块的第一个标号处开始执行。 4.2.4指令集选择伪指令由于80x86的所有处理器都支持8086/8088指令系统,而且每一种高档的机型又都增加了一些新的指令,因此,在编写程序时要对所用处理器有一个确切的选择。也就是说,要告诉汇编程序应该选择哪一种指令系统。指令集选择伪指令的功能就是确定作用指令系统。 此类伪指令主要有以下几种:(1).8086:选择8086指令系统。(2).286:选择80286指令系统。(3).286P:选择保护方式下的80286指令系统。(4).386:选择80386指令系统。(5).386P:选择保护方式下的80386指令系统。(6).486:选择80486指令系统。(7).486P:选择保护方式下的80486指令系统。(8).586:选择Pentium指令系统。(9).586P:选择保护方式下的Pentium指令系统。 有关“选择保护方式下的XXXX指令系统”的含义是指包括特权指令在内的指令系统。此外,上述伪指令均支持相应的协处理器指令。这类伪指令一般放在整个程序的最前面,如不给出,则汇编程序默认值为.8086指令系统。它们可放在程序中,如程序中使用了一条80486所增加的指令,则可以在该指令的上一行加上.486。 4.2.5地址计数器与对准伪操作1.地址计数器——$在汇编程序对源程序汇编的过程中,使用地址计数器(LOCATIONCOUNTER)来保存当前正在汇编的指令的偏移地址。当开始汇编或在每一段开始时,把地址计数器初始化为零,以后在汇编过程中,每处理一条指令,地址计数器就增加一个值,此值为该指令所需要的字节数。地址计数器的值可用$来表示,汇编语言允许用户直接用$来引用地址计数器的值,因此指令:JNE$+6的转向地址是JNE指令的首地址加上6。 当$用在指令中时,它表示本条指令的第一个字节的地址。在这里,$+6必须是另一条指令的首地址,否则,汇编程序将指示出错信息。当$用在伪操作的参数字段时,则和它用在指令中的情况不同,它所表示的是地址计数器的当前值。 【例4-6】$用法示例。ARRAYDW1,2,$+4,3,4,$+4如汇编时ARRAY分配的偏移地址为0074,则汇编后的存储区将如图4.5所示。注意:ARRAY数组中的两个$+4得到的结果是不同的,这是由于$的值是在不断变化的缘故。当在指令中用到$时,它只代表该指令的首地址,而与$本身所在的字节无关。图4.5例4-6的汇编结果00750076007700780079007A007B007C007D007E007F 2.ORG伪操作ORG伪操作用来设置当前地址计数器的值,其格式为ORGCONSTANTEXPRESSION如常数表达式的值为N,则ORG伪操作可以使下一个字节的地址成为常数表达式的值N。例如:VECTORSSEGMENTORG10VECT1DW47A5HORG20VECT2DW0C596HVECTORSENDS 则VECT1的偏移地址值为0AH,而VECT2的偏移地址值为14H。常数表达式也可以表示从当前已定义过的符号开始的位移量,或表示从当前地址计数器值$开始的位移量,如:ORG$+8可以表示跳过8个字节的存储区,亦即建立了一个8字节的未初始化的数据缓冲区。如程序中需要访问该缓冲区,则可用LABEL伪操作来定义该缓冲区的如下变量名: BUFFERLABELBYTEORG$+8当然,其完成的功能和BUFFERDB8DUP(?)是一样的。 3.EVEN伪操作EVEN伪操作使下一个变量或指令开始于偶数字节地址。一个字的地址最好从偶地址开始,所以对于字类型数组,为保证其从偶地址开始,可以在其前用EVEN伪操作来达到这一目的。例如:DATA_SEGSEGMENTEVEN;保证地址从偶地址开始WORD_ARRAYDW100DUP(?)DATA_SEGENDS…… 4.ALIGN伪操作ALIGN伪操作为保证双字类型数组边界从4的倍数开始创造了条件,其格式为ALIGNBOUNDARY其中,BOUNDARY必须是2的幂,例如:.DATAALIGN4ARRAYDB100DUP(?)就可保证ARRAY的值为4的倍数。当然,ALIGN2和EVEN是等价的。…… 4.3汇编语言源程序结构1.完整段定义的程序结构存储器的物理地址是由段地址和偏移地址组合而成的,汇编程序在把源程序转换为目标程序时,必须确定标号和变量(代码段和数据段的符号地址)的偏移地址,并且需要把有关信息通过目标模块传送给连接程序,以便连接程序把不同的段和模块连接在一起,形成一个可执行程序。为此,需要用段定义伪操作,其格式如下: SEGMENT_NAMESEGMENT段体SEGMENT_NAMEENDS其中,删节号部分对于数据段、附加段和堆栈段来说,一般是存储单元的定义、分配等伪操作;对于代码段则是指令及伪操作。…… 此外,还必须明确段和段寄存器的关系,这可用ASSUME伪操作来实现,其格式为:ASSUME<段寄存器名>:段名[,<段寄存器名>:段名,...]ASSUME<段寄存器名>:NOTHING其中,段寄存器名必须是CS、DS、ES和SS(对于386及其后继机型还有FS和GS)中的一个,而段名则必须是由SEGMENT定义的段中的段名。ASSUMENOTHING则可取消前面由ASSUME所指定的段寄存器。 例如,下面是一个较为完整的汇编源程序段定义。DATE_SEG1SEGMENT;定义数据段DATE_SEG1ENDSDATA_SEG2SEGMENT;定义数据附加段DATA_SEG2ENDSCODE_SEGSEGMENT;定义代码段ASSUMECS:CODE_SEG,DS:DATA_SEG1,ES:DATA_SEG2;开始执行的入口地址设置DS寄存器为当前数据段…… START:MOVAX,DATA_SEG1;将数据段地址赋予DSMOVDS,AX;设置ES寄存器为当前附加段MOVAX,DATA_SEG2;将附加数据段地址赋予ESMOVES,AXCODE_SEGENDS;代码段定义结束ENDSTART;源程序结束… 由于ASSUME伪操作只是指定某个段分配给哪一个段寄存器,它并不能把段地址装入段寄存器中,要把段地址装入段寄存器中,就必须在代码段中有对段地址装入相应的段寄存器中的指令。如在上面的程序中,分别用两条MOV指令完成这一操作。如果程序中有堆栈段,也需要把段地址装入SS中。但是,代码段CS不需要这样做,这一操作是在程序初始化时完成的。 为了对段定义作进一步地控制,SEGMENT伪操作添加有类型及属性的说明,其格式如下:<段名>SEGMENT[定位类型][组合类型][使用类型][类别]<段名>ENDS在一般情况下,这些说明可以不用。但是,如果需要用连接程序把本程序与其他程序模块相连接时,就需要使用这些说明。… 2.定位类型(ALIGN_TYPE)定位类型用于说明段的起始地址应有怎样的边界值,其取值可以是:PARA:指定段的起始地址必须从一个节的边界开始,通常16个字节称为一个节,故本段的开始地址应为XXXX0H。BYTE:该段可以从任何地址开始,这样,起始偏移地址可能不是0。WORD:该段必须从字的边界开始,即段起始地址必须为偶数。 DWORD:该段必须从双字边界开始,即段起始地址的最低位必须为4的倍数。PAGE:该段必须从页的边界开始,即段起始地址的最低两个十六进制数位必须为0(该地址能被256整除),即XXX00H。定位类型的默认项是PARA,即若未指定定位类型时,则汇编程序默认为PARA。 3.组合类型(COMBINE_TYPE)组合类型用于说明程序连接时段的合并方法,其取值可以是:PRIVATE:该段为私有段,在连接时将不与其他模块中的同名段合并。PUBLIC:该段连接时可以把不同模块中的同名段相连接而合并为一个段,其连接次序由连接命令指定。每一分段都从节的边界开始,因此,各模块的原有段之间可能存在小于16个字节的间隙。 COMMON:该段在连接时可以把不同模块中的同名段重叠而形成一个段,由于各同名段有相同的起始地址,所以会产生覆盖。COMMON的连接长度是各分段中的最大长度。重叠部分的内容取决于排列在最后一段的内容。ATEXPRESSTION:使段地址为表达式所计算出来的16位值,但它不能用来指定代码段。MEMORY:表示当几个逻辑段连接时,本逻辑段定位在地址最高的地方。如果被连接的逻辑段中有多个段的组合类型都是MEMORY,则汇编程序只将首先遇到的段作为MEMORY段,其余的段均当做COMMOM段处理。 STACK:把不同模块中的同名段组合而形成一个堆栈段,该段的长度为原有各堆栈段长度的总和,原有各段之间并无PUBLIC所连接段中的间隙,而且栈顶可自动指向连接后形成的大堆栈段的(最终地址+1)处。组合类型的默认项是PRIVATE。 例3.2SEGMENT伪操作的定位类型应用举例STACKSEGMENTSTACK;STACK段,定位类型无DB100DUP(?);长度为100字节STACKENDS;STACK段结束DATA1SEGMENTBYTE;DATA1段,定位类型为BYTESTRINGDB‘Thisisanexample!’;长度为19字节DATA1ENDS;DATA1段结束DATA2SEGMENTWORD;DATA2段,定位类型为WORDBUFFERDW40DUP(?);长度为80个字节DATA2ENDS;DATA2段结束 CODE1SEGMENTPAGE;CODE1段,定位类型为PAGE。。。。;假设CODE1段长度为13个字节CODE1ENDS;CODE1段结束CODE2SEGMENT;CODE2段,定位类型无……START:MOVAX,STACKMOVSS,AX……;假设CODE2段长为52字节CODE2ENDS;CODE1段结束ENDSTART;源程序结束 表3.3[例3.2]中各逻辑段的起始地址和结束地址段名定位类型字节数起始地址结束地址STACKPARA100(64H)00000H00063HDATA1BYTE19(13H)00064H00076HDATA2WORD80(50H)00078H000C7HCODE1PAGE13(0DH)00100H0010CHCODE2PARA52(34H)00110H00143H 4.使用类型(USE_TYPE)使用类型只适用于386及其后继机型,它用来说明是使用16位寻址方式还是使用32位寻址方式。其取值可以是:USE16:使用16位寻址方式。USE32:使用32位寻址方式。当使用16位寻址方式时,段长不超过64KB,地址的形式是16位段地址和16位偏移地址组合;当使用32位寻址方式时,段长可达4GB,地址的形式是16位段地址和32位偏移地址组合。可以看出,在实模式下,应该使用USE16。使用类型的默认项是USE16。 5.类别名(‘CLASS’)类别名必须放在单引号内。类别的作用是在连接时决定各逻辑段的装入顺序。当几个程序模块进行连接时,其中具有相同类别名的逻辑段被装入连续的内存区,类别名相同的逻辑段,按出现的先后顺序排列。没有类别名的逻辑段,与其它无类别名的逻辑段一起连续装入内存。 例如,假设一个主程序中有五个逻辑段,段名和类别分别为:STACK段------‘STACK’CODE1段----无DATA1段-----‘BUFFER’DATA2段-----‘TABLE’DATA3段-----‘BUFFER’还有一个子程序,包括四个逻辑段,段名和类别名分别为:DATA4段----‘TABLE’DATA5段----‘BUFFER’STK2段------‘STACK’CODE2段----无 当将上述主程序和子程序进行连接时,两个程序模块中各逻辑段装入内存的顺序如图所示: 4.4汇编语言程序的上机过程在计算机上运行汇编语言程序的步骤是:(1)用编辑程序建立.ASM源文件;(2)用MASM程序把.ASM文件转汇编成.OBJ文件;(3)用LINK程序把.OBJ文件连接成.EXE文件;(4)用DOS命令直接键入文件名就可执行该程序。目前常用的汇编程序有Microsoft公司推出的宏汇编程MASM(MACROASSEMBLER)和BORLAND公司推出的TASM(TURBOASSEMBLER)两种。本书采用MASM5.0版来说明汇编程序所提供的伪操作和操作符,操作流程如图4.6所示。 图4.6汇编语言程序的建立及汇编过程说明:图中□表示操作使用的项;○表示操作得到的文件。 汇编程序的主要功能是:(1)检查源程序语法是否正确。(2)测出源程序中的语法错误,并给出出错信息。(3)产生源程序的目标程序,并可给出列表文件(同时列出汇编语言和机器语言的文件,称为.LST文件)。(4)展开宏指令。 4.4.1建立汇编语言的工作环境为运行汇编语言程序,至少要在磁盘上提供以下文件:(1)编辑程序,如EDIT.EXE;(2)汇编程序,如MASM.EXE;(3)连接程序,如LINK.EXE;(4)调试程序,如DEBUG.COM。必要时,还要提供CREF.EXE、EXR2BIN.EXE等文件。 4.4.2汇编语言源程序上机过程1.建立汇编源程序.ASM文件为了说明汇编语言程序上机运行的过程,现举例如下。【例4-7】把40个字母A的字符串从源缓冲区传送到目的缓冲区。可以用编辑程序EDIT在磁盘上建立如下的源程序EXAM.ASM。TITLEEXAM.ASMDATASEGMENTDATSDB40DUP('A')DATAENDS EXTRASEGMENTDATDDB40DUP(?)EXTRAENDSCODESEGMENTMAINPROCFARASSUMECS:CODE,DS:DATA,ES:EXTRASTART:PUSHDSSUBAX,AXPUSHAXMOVAX,DATAMOVDS,AXMOVAX,EXTRAMOVES,AX LEASI,DATSLEADI,DATDCLDMOVCX,40REPMOVSBRETMAINENDPCODEENDSENDSTART 2.汇编产生.OBJ文件源文件建立后,就要用汇编程序对源文件汇编,汇编后产生二进制的目标文件(.OBJ文件),其操作与汇编程序回答如下。C:>MASMEXAM↙MICROSOFT(R)MACROASSEMBLERVERSION5.00COPYRIGHT(C)MICROSOFTCORP1981-1985,1987.ALLRIGHTSRESERVED.OBJECTFILENAME[EXAM.OBJ]:↙SOURCELISTING[NUL.LST]:EXAM↙CROSS-REFERENCE[NUL.CRF]:EXAM↙32768+447778BYTESSYMBOLSPACEFREE0WARNINGERRORS0SEVEREERRORS 汇编程序的输入文件是.ASM文件,其输出文件可以有三个,表示上列汇编程序回答的第3~5行。第一个是.OBJ文件,这是汇编的主要目的,所以这个文件我们是需要的,对[EXAM.OBJ]:直接回车,这样就在磁盘上建立了这一目标文件。第二个是.LST文件,称为列表文件。这个文件同时列出源程序和机器语言程序清单,并给出符号表,因而可使程序调试更加方便。这个文件是可有可无的,如果不需要则可对[NUL.LST]:回车;如果需要这个文件,则可键入文件名后回车,这里是EXAM↙(↙表示回车),这样例4-7的列表文件EXAM.LST就建立起来了。 LIST清单的最后部分为段名表和符号表,表中分别给出段名、段的大小及有关属性,以及用户定义的符号名、类型及属性。交叉引用表给出了用户定义的所有符号,对于每个符号列出了其定义所在行号(加上#)及引用的行号。可以看出,它为大程序的修改提供了方便,而一般较小的程序则可不使用。 到此为止,汇编过程已经完成了。但是,汇编程序还有另一个重要功能,就是可以给出源程序中的错误信息类型:警告错误(WARNINGERRORS)指出汇编程序所认为的一般性错误;严重错误(SEVEREERRORS)指出汇编程序认为已使汇编程序无法进行正确汇编的错误。除给出错误的个数外,汇编程序还能指出错误信息的类型,本书在附录1列出了汇编程序错误信息的类型,供编程者参阅。如果程序有错,则应重新调用编辑程序修改错误,并重新编译直到编译正确通过为止。当然汇编程序只能指出程序中的语法错误,至于程序的算法或逻辑错误,则应在程序调试时去解决。 3.链接产生.EXE文件汇编程序已产生出二进制的目标文件(.OBJ),但.OBJ文件并不是系统可执行的文件,因此还必须使用连接程序(LINK)把.OBJ文件转换为系统可执行的.EXE文件。当然,如果一个程序是由多个模块组成时,也应该通过LINK把它们连接在一起,操作方法及机器回答如下: C:>LINKEXAM↙MICROSOFT(R)OVERLAYLINKERVERSION3.60COPYRIGHT(C)MICROSOFTCORP1983-1987,ALLRIGHTSRESERVED,RUNFILE[EXAM.EXE];↙LISTFILE[NUL.MAP]:EXAM↙LIBRARIES[.LIB]:↙LINK:WARNINGL4021:NOSTACKSEGMENT LINK程序有两个输入文件.OBJ和.LIB。.OBJ是我们需要连接的目标文件,.LIB则是程序中需要用到的库文件,如无特殊需要,则应对[.LIB]:直接回车。LINK程序有两个输出文件,一个是.EXE文件,应对[EXAM.EXE]:直接回车,这样就在磁盘上建立了该可执行文件。LINK的另一个输出文件为.MAP文件,它是连接程序的列表文件,又称为连接映像(LINKMAP),它给出每个段在存储器中的分配情况。连接程序给出的无堆栈段的警告性错误并不影响程序的运行。所以,到此为止,连接过程已经结束,可以在操作系统下执行EXAM程序了。 4.程序的调试和执行在建立了.EXE文件后,就可以直接在操作系统中执行程序,如下所示:C:>EXAM↙C:>_程序运行结束并返回DOS。如果用户程序已直接把结果在终端上显示出来,那么程序已经运行结束,结果也已经得到。但是,如果EXAM程序并未显示出结果,这就要使用调试程序查看内存缓冲区。常用调试工具软件为DEBUG,见附录2。 5.生成.COM文件.COM文件也是一种可执行文件,由程序本身的二进制代码组成,它没有.EXE文件所具有的包括有关文件信息的标题区(HEADER),因此它占有的存储空间比.EXE文件要小。.COM文件不允许分段,它所占有的空间不允许超过64KB,因而只能用来编制较小的程序。由于其小而简单,装入速度比.EXE文件要快。使用.COM文件时,程序不分段,其入口点(开始运行的起始点)必须是100H(其前的256个字节为程序段前缀所在地),且不必设置堆栈段。在程序装入时,由系统自动把SP建立在该段之末。对于所有的过程则应定义为NEAR。 用户在建立源文件以后,同样经过汇编、连接生成.EXE文件,然后可以通过DOS操作系统下的EXE2BIN程序来建立.COM文件,操作方法如下:C:>EXE2BINFILENAMEFILENAME.COM↙请读者注意,上行中的第一个FILENAME给出了已形成的.EXE文件的文件名,但不必给出文件扩展名。第二个FILENAME即为所要求的.COM文件的文件名,它必须带有文件扩展名.COM,这样就形成了所要的.COM文件。在DOS系统下,可直接在机器上键入文件名以执行程序。如果第二个FILENAME后不跟扩展名,则将形成.BIN文件,在DOS系统下运行该程序时,必须先用RENAME命令把它改名为.COM文件才能直接运行。 此外,.COM文件还可以直接在调试程序DEBUG中用A或E命令建立,对于一些短小的程序,这也是一种相当方便的方法。 4.5汇编语言程序设计4.5.1流程图的组成借助于流程图可以清晰地把程序思路表达出来,有助于编写正确的程序。流程图对程序设计人员,特别是初学者来说是一种非常有用的工具。流程图是用一些图框表示各种操作,用图形表示算法,直观形象,易于理解。美国国家标准化协会ANSI(AmericanNationalStandardInstitute)规定了一些常用的流程图,已为世界各国程序工作者普遍采用。 图4.7流程图的组成成分 1)执行框(矩形框)执行框的作用是表示一段程序或一个模块的功能,对于结构化程序,一个执行框只有一个入口和一个出口。2)判别框(菱形框)判别框的作用是对一个给定的条件进行判断,根据给定的条件是否成立来决定如何执行其后的操作。它有一个入口,两个出口,表示比较、判断条件。 3)开始框和终止框开始框和终止框表示程序的起始和终止。4)指向线指向线表示程序执行的顺序。5)连接点连接点是用于将画在不同地方的流程线连接起来。如图4.8中,有两个以①为标志的连接点,它表示这两个点是互相连接在一起的。实际上它们是同一个点,只是当在纸张上画不下才分开来画。使用连接点可以避免流程线的交叉或过长,使流程图清晰。 图4.8流程图的绘制示意 可以看出,流程图是表示算法的较好工具。一个流程图包括以下几部分:(1)表示相应操作的框;(2)带箭头的流程线;(3)框内外必要的文字说明。绘制流程线不要忘记画箭头,因为它是反映流程的执行先后次序的,如不画出箭头就难以判定各框的执行次序了。用流程图表示算法直观形象,比较清楚地显示出各个框之间的逻辑关系。常用的还有N-S结构化流程图。程序编制人员都应当掌握传统流程图,会看会画。 4.5.2顺序程序设计顺序程序结构是指完全按顺序逐条执行的指令序列,这在程序段中是大量存在的,但作为完整的程序则很少见,一般作为程序的一部分。顺序结构程序是最简单的程序,在顺序结构程序中,指令按照先后顺序一条一条执行。【例4-8】将两个字节数据相加,并存放到一个结果单元中。DATASEGMENTAD1DB4CH;定义第1个加数AD2DB25H;定义第2个加数SUMDB?;定义结果单元DATAENDSCODESEGMENTASSUMECS:CODE,DS:DATA START:MOVAX,DATAMOVDS,AXMOVAL,AD1;取出第1个加数ADDAL,AD2;和第2个加数相加MOVSUM,AL;存放结果MOVBL,AL;显示十六进制结果MOVCL,4SHRAL,CLANDAL,0FHADDAL,30HMOVDL,ALCMPAL,9JBENEXTADDAL,7NEXT: MOVAH,2INT21HMOVAL,BLANDAL,0FHADDAL,30HMOVDL,ALMOVAH,2INT21HMOVAH,4CH;返回DOSINT21HCODEENDSENDSTART 注意:本程序的结束,采用了DOS中断调用的4CH号功能,来退出程序段运行,返回DOS现场。这是一种常用的执行程序返回DOS现场的方法。 4.5.7分支程序设计1.分支程序结构形式分支程序结构可以有两种形式,如图4.14所示。它们分别相当于高级语言中的IF_THEN_ELSE语句和CASE语句,适用于要求根据不同条件作不同处理的情况。IF_THEN_ELSE语句可以引出两个分支,CASE语句则可以引出多个分支。不论哪一种形式,它们的共同特点是:运行方向是向前的,在某一种特定条件下,只能执行多个分支中的一个分支。 图4.14分支程序的结构形式(a)IF_THEN_ELSE结构;(b)CASE结构 2.分支程序设计方法程序的分支一般用条件转移指令来产生,利用转移指令不影响条件码的特性,连续地使用条件转移指令可使程序产生多个不同的分支。【例4-9】TABLE是一字节数组的首地址,长度为100。统计此数组中正数、0及负数的个数,并分别放在COUNT1、COUNT2和COUNT3变量中。其流程图如图4.15所示。 图4.15例4-17流程图 DATASEGMENTTABLEDB100DUP(?)COUNT1DB0COUNT2DB0COUNT3DB0DATAENDSCODESEGMENTASSUMECS:CODE,DS:DATAALLOPROCFARSTART:PUSHDSXORAX,AXPUSHAXMOVAX,DATAMOVDS,AX返回DOS MOVCX,100MOVBX,0AGAIN:CMPTABLE[BX],0JGESS12INCCOUNT3JMPSHORTNEXTSS12:JGSS1INCCOUNT1JMPSHORTNEXTSS1:INCCOUNT2NEXT:INCBXLOOPAGAINRETALLOENDPCODEENDSENDSTART负数单元加1零单元加1正数单元加1上机练习题:在提示信息提示下,从键盘键入字符串,统计英文大写字母、小写字母、数字的个数,并分别从显示器上以十进制的形式显示出来 本程序段在开始时出现了两次压栈操作,既PUSHDS和PUSHAX((AX)=0)。由于本程序段是一个FAR属性的子程序,在程序结束执行RET时将引起两次出栈操作,会使(CS)内容等于未执行本程序前的值,(IP)=0。在(CS):(IP)位置有一段程序,功能就是退出程序段运行,返回DOS现场。这是第二种执行程序返回DOS现场的方法。 4.5.8循环程序设计1.循环程序结构循环程序结构可以总结为两种结构形式。一种是DOWHILE结构形式;另一种是DOUNTIL结构形式。1)DOWHILE结构DOWHILE结构把对循环控制条件的判断放在循环的入口,先判断条件,满足条件就执行循环体,否则就退出循环,如图4.16(a)所示。 2)DOUNTIL结构DOUNTIL结构是先执行循环体,然后再判断控制条件,不满足条件则继续执行循环操作,一旦满足条件则退出循环,如图4.16(b)所示。图4.16循环程序的结构形式(a)DOWHILE结构;(b)DOUNTIL结构 这两种结构可以根据具体情况选择使用。如果有循环次数等于0的情况,则应选择DOWHILE结构,否则使用DOUNTIL结构。不论哪一种结构形式,循环程序都可由如下四部分组成:(1)循环初始化。初始化完成设置循环次数的计数值,设置循环初始地址,以及为循环体正常工作而建立的初始状态等。(2)循环体。循环体是循环程序的主体,该部分是为完成程序功能而设计的主要程序段。(3)循环修改。循环的修改部分是为避免程序原地踏步,保证每一次重复(循环)时,参加执行的信息能发生有规律的变化而建立的程序段。 (4)循环控制。循环控制本来应该属于循环体的一部分,由于它是循环程序设计的关键,所以要对它作专门的讨论。每个循环程序必须选择一个循环控制条件来控制循环的运行和结束,而合理地选择该控制条件就成为循环程序设计的关键问题。有时,循环次数是已知的,此时可以用循环次数作为循环的控制条件,LOOP指令使这种循环程序设计能很容易地实现。有时循环次数是已知的,但有可能使用其他特征或条件来使循环提前结束,LOOPZ和LOOPNZ指令是设计这种循环程序的工具。然而,有时循环次数是未知的,那就需要根据具体情况找出控制循环结束的条件。循环控制条件的选择是很灵活的,有时可供选择的方案不止一种,此时就应分析比较,选择一种效率最高的方案来实现。 2.循环程序设计方法【例4-10】设计一个程序,完成从1连加到100(即1+2+...+99+100)的操作,结果保存在数据段的SUM单元。分析:这样的问题如果采用顺序程序设计至少要一百条指令,并且程序的结构性和可读性差,而采用循环程序设计就会简洁明了。程序清单如下。DATASEGMENTSUMDW?DATAENDSCODESEGMENTASSUMECS:CODE,DS:DATA START:MOVAX,DATAMOVDS,AX;数据段寄存器赋初值;循环初始化SUBAX,AX;工作寄存器清零MOVCX,100;计数器赋初值CLC;清除进位标志LP:INCAX;循环体ADCSUM,AXDECCX;循环修改JNZLP;循环控制;********;插入显示程序的地方(预留位置)HLTCODEENDSENDSTART 注意:①本程序段采用了第三种退出方式,程序运行结束将由于执行HLT指令而进入停机状态,当键入Ctrl+Break组合键(键盘中断)后,返回DOS现场。②用DEBUG跟踪,会发现(SUM)=13BAH。 【例4-11】试编制一个把SUM的二进制数用十六进制数的形式在屏幕上显示的程序段。作为转换输出功能部分,插入例4-18中程序的“;********”位置,可构成完整的程序。根据题意,将SUM内容送到BX中,从左到右每四位为一组在屏幕上显示出来,每次循环显示一个十六进制数位,计数初值为4。程序框图如图4.17所示。采用循环移位的方式把所要显示的4位二进制数移到最右面,以便做数字到字符的转换工作。另外,由于数字0~9的ASCII值为30H~39H,而字母A~F的ASCII值为41H~46H,所以在把4位二进制数加上30H后还需作一次判断,如果是字符A~F,则还应加上7才能显示出正确的十六进制数。以BINIHEX.ASM为文件名建立“二进制到十六进制数转换程序”源文件。 图4.17二进制到十六进制数转换程序的框图 在程序中没有使用LOOP指令,这是因为循环移位指令要使用CL寄存器,而LOOP指令要使用CX寄存器,为了解决CX寄存器的冲突问题,这里用CH寄存器存放循环计数值,而用DEC及JNZ两条指令完成LOOP指令的功能。这说明,使用计数值控制循环结束也可以不用LOOP指令。当然也可以把计数值初始化为0,用每循环一次加1然后比较次数是否达到要求的方法来实现,或者仍用LOOP指令,而用堆栈保存其中的一个信息(如计数值)来解决CX寄存器的冲突问题等。总之,程序设计是很灵活的,只要算法和指令的使用没有错误,都可以达到目的。 二进制到十六进制转换程序如下:MOVBX,SUMMOVCH,4LP1:MOVCL,4ROLBX,CLMOVAL,BLANDAL,0FHADDAL,30HCMPAL,3AHJLPRINTAADDAL,07HPRINTA:MOVDL,ALMOVAH,2INT21HDECCHJNZLP1 十六进制到十进制数转换的程序实现(沈美明P225)HEXIDECSEGMENTASSUMECS:HEXIDECMAINPROCFARSTART:PUSHDSXORAX,AXPUSHAXCALLHEXIBINCALLCRLECALLBINIDECCALLCRLEJMPMAINRETMAINENDP观看程序运行结果2TO10A.ASM HEXIBINPROCMOVBX,0NEWCHAR:MOVAH,1;从键盘键入一个字符INT21HSUBAL,30H;判断是否为数字0-9JLEXIT;非数字推出CMPAL,10JLADD-TO;是数字0-9SUBAL,27H;是字符A-FCMPAL,0AH;判断是否为字符A-FJLEXIT;非数字非A-F退出CMPAL,10HJGEEXIT;大于0FH,退出 ADD-TO:MOVCL,4SHLBX,CLMOVAH,0ADDBX,AXJMPNEWCHAREXIT:RETHEXIBINENDPBINIDECPROC;二进制转十进制并显示MOVCX,10000;子程序CALLDEC-DIV;万位并显示MOVCX,1000CALLDEC-DIV;千位并显示 MOVCX,100CALLDEC-DIV;百位并显示MOVCX,10CALLDEC-DIV;十位并显示MOVCX,1CALLDEC-DIV;个位并显示RETDEC-DIVPROCMOVAX,BXMOVDX,0DIVCXMOVBX,DXMOVDL,ALADDDL,30HMOVAH,2INT21H RETDEC-DIVENDPBINIDECENDPCRLFPROC;回车换行子程序MOVDL,0AHMOVAH,2INT21HMOVDL,0DHMOVAH,2INT21HRETCRLFENDPHEXIDECENDSENDSTART 4.5.2BIOS中断调用1.BIOS中断调用概述BIOS(BasicInput/OutputSystem)是IBM-PC机的监控程序,它固化在微型机主板的ROM中,它的内容主要有系统测试程序(POST)、初始化引导程序(BOOT)、I/O设备的基本驱动程序和许多常用程序模块,它们一般以中断服务程序的形式存在。例如,负责显示输出的显示I/O程序为10H号中断服务程序;负责打印输出的打印I/O程序为17H号中断服务程序等。 图4.9是用户程序和操作系统关系示意图,由图可见,BIOS程序直接建立在硬件基础上,磁盘操作系统(DOS)和其他操作系统建立在BIOS基础上,各种高级语言则建立在操作系统基础上。用户程序可以使用高级语言,也可以调用DOS或其他操作系统,还可以调用BIOS,甚至直接指挥硬件设备。图4.9用户程序和操作系统关系示意图 通常,应用程序调用DOS提供的系统功能,完成输入/输出或其他操作,这样做用户可以少考虑硬件,实现起来容易。应用程序直接对硬件编程的优点是程序的效率高,缺点是需要程序员对硬件性能有较深的了解,编程复杂,所以一般不直接对硬件编程。BIOS中断程序处于DOS功能调用和硬件环境之间,和DOS功能调用相比,其优点是效率高,缺点是编程相对复杂;和直接对硬件编程相比,优点是实现相对容易,缺点是效率相对低。在下列情况下可考虑使用BIOS中断:(1)有些功能DOS没有提供,但BIOS提供了;(2)有些场合无法使用DOS功能调用;(3)其他原因。 2.BIOS中断调用方法BIOS的调用就是人们借用每一台计算机中BIOS固有的I/O操作程序来方便地解决自己的问题,由于它已经在计算机中了,因此人们不必再把它写入自己的程序,只要指明它的操作位置就可以了。1)BIOS调用的基本操作由于BIOS中的每一种功能调用往往包含不同的几个操作细节,所以调用时需要说明三部分,基本步骤为:(1)设置分功能号:按实现的操作功能的要求,给指定寄存器(通常为AH)送入分功能号。 (2)置入口参数:按操作要求,给寄存器填写相应参数的内容(某些调用无参数)。(3)使用中断语句INTn:执行调用的功能,其中n为中断号。(4)分析出口参数。例如MOVAH,0;分功能号为0MOVAL,10H;置入口参数INT1AH;1AH为中断号,功能为读时间计数器的值注意:某些BIOS调用可能没有出口参数,这时省略第(4)步操作。 2)BIOS打印功能BIOSI7H号中断指令提供了由AH寄存器指定的三种不同的操作。(1)BIOS中断17H号的功能0是打印一个字符。要打印输出的字符放在AL中,打印机号放在DX中,BIOS最多允许连接三台打印机,机号分别为0,1和2。如果只有一台打印机,那么就是0号打印机,打印机的状态信息被回送到AH寄存器。MOVAH,0;请求打印MOVAL,CHAR;写入打印字符MOVDX,0;设置0#打印口INT17H;调用BIOS (2)17H号的功能1是初始化打印机并回送打印机状态到AH寄存器。如果把打印机开关关上然后又打开,打印机各部分就复位到初始值。此功能和打开打印机时的作用一样。在每个程序的初始化部分可以用17H号的功能1来初始化打印机。MOVAH,01;初始化打印机MOVDX,0;设置0#打印口INT17H;调用BIOS这个操作要发送一个换页符,因此,这个操作能把打印机头设置在一页的顶部。对于大多数打印机,只要一接通电源,就会自动地初始化打印机。 (3)BIOS17H号的功能2是把状态字节读入AH寄存器中。打印机的状态字节如图4.10所示。打印机忙表示打印机正在接收数据、正在打印或处于脱机状态。应答位表示打印机已发出一个表明它已经接收到数据的信号。选择位表示打印机是联机的。超时位表示打印机发出忙信号很长一段时间了,系统将不再给它传送数据。表示打印出错的是第5位(纸出界)或第3位(I/O错)为1。如果打印机没有接上电源,没有装上纸或没有联机,而打印程序已开始运行,这时显示器的指示光标会不停地闪烁,当接通打印机的电源后,某些输出数据就会丢失。 图4.10打印机的状态字节如果在打印程序中先安排指令测试打印机的状态,则BIOS操作就会送回状态码,DOS打印操作是自动进行测试的,但对各种情况都显示一个“纸出界”的信息。当打印机接通电源后,即开始正常打印,而且不丢失任何数据。 3)BIOS串行通信口功能IBM-PC及其兼容机提供了一种有较强的硬件依赖性,但却比较灵活的串行口I/O的方法,即通过INT14H调用ROMBIOS串行通信口中断服务程序。该中断服务程序包括将串行口初始化为指定的字节结构和传输速率,检查控制器的状态,读/写字符等功能。具体功能设置如表4-1所示。 表4-1串行通信口BIOS功能(INT14H)AH功能调用参数返回参数0初始化串行通信口AL=初始化参数DX=通信口号:COM1=0COM2=1,etcAH=通信口状态(AL)=调制解调器状态1向串行通信口写字符AL=所写字符DX=通信口号:COM1=0COM2=1,etc写字符成功:(AH)=0,(AL)=字符写字符失败:(AH)7=1,(AH)0~6=通信口状态2从串行通信口读字符DX=通信口号:COM1=0COM2=1,etc读成功:(AH)7,=0(AL)=字符读失败:(AH)7=1,(AH)0~6=通信口状态3取通信口状态DX=通信口号:COM1=0COM2=1(AH)=通信状态AL=调制解调器状态 图4.11串行通信口初始化参数 【例4-8】要求0号通信口的传输率为2400波特,字长为8位,终止位为1位,无奇偶校验。MOVAH,0;串行通信口初始化MOVAL,0A3H;0A3H=10100011BMOVDX,0;指向COM1INT14H;调用BIOS返回参数中通信口状态字节各位置1的含义如图4.12所示。 图4.12串行通信口状态字节 在接收和发送过程,错误状态位(1,2,3,4位)一旦被置为1,则读入的接收数据已不是有效数据,所以在串行通信应用程序中,应检测数据传输是否出错。奇偶错:通信线上(尤其是用电话线传输时)的噪音引起某些数据位的改变,产生奇偶错。通常检测出奇偶错时,要求正在接收的数据至少应重新发送一段。超越错:在上一个字符还未被处理机取走,又有字符要传送到数据寄存器里时,就会引起超越错。如果处理机处理字符的速度小于单行通信口的波特率,则会产生这种错误。 帧格式错:当接收/发送器未接收到一个字符数据的停止位,则会引起帧格式错。这种错误可能是由于通信线上的噪音引起停止位的丢失,或者是由于接收方和发送方初始化不匹配而造成的。间断:间断有时候并不能算是一个错误,而是为某些特殊的通信环境设置的“空格”状态。当间断位为1时,说明接收的“空格”状态超过了一个完整的数据字传输时间。PS/2以及所有的PC机,AH=04功能允许程序员将波特率设置为19200,数据位的长度可以设置为5、6、7或8位,而不是像AH=0功能那样只能设置成7或8位。 4)BIOS键盘中断INT16H的中断提供了基本的键盘操作,它的中断处理程序包括3个不同的功能,分别根据AH的内容来选择BIOS键盘中断(INT16H)AH功能返回参数0从键盘键入一个字符AL=字符码AH=扫描码1读键盘缓冲区的字符如ZF=0:AL=字符码AH=扫描码如ZF=1:缓冲区空2取键盘状态字AL=键盘状态字节 例如,下面程序的功能是:按下F1键和F2键,分别执行两段不同的程序,按其它键转至错误处理。MOVAH,0INT16H;键入字符CMPAL,0JNZERROR;若为字符码转错误处理CMPAH,3BH;F1的扫描码为3BHJZTT1;若为F1键,转TT1CMPAH,3CH;F2的扫描码为3CHJZTT2JMPERRORTT1:………..;按F1功能段TT2:…………..;按F2功能段ERROR:……….;错误处理 在内存0040:0017H中记录了双态键和组合键的状态,该字节称为键盘状态字节KB——FLAG。其中高四位表示Ins、Capslock、Numlock、Scrollock是ON(=1)还是OFF(=0),低4位表示键Alt、Ctrl、Shift是否按动,若按动则置1。D7D6D5D4D3D2D1D0按下右Shift键按下左Shift键按下Ctrl键按下Alt键Scrollock键Numlock键Caplock键Insert键 INT16H的功能2可以查看上述8个键的状态。例如:程序片段MOVAH,2INT16HTESTAL,10000000BJZINS_OFF……INS_OFF:……..用户通过程序改变键盘字节的内容,等效于键入了对应的键,下面程序片段使Ins键处于ON状态:MOVAX,0MOVES,AXMOVAL,10000000BORES:[0417H],AL 5)、BIOS显示器输出显示器:单色/彩色显示器显示适配器(显卡):计算机和显示器的接口单色显示适配器(MDA),只能显示ASCII码字符,字符由标准字母、数字和各种符号组成,还可显示一些简单图形,如菱形、矩形及笑脸符等。彩色图形适配器(CGA):可用在彩色显示器上,能以红、绿、蓝彩色显示以点绘制的图形以及ASCII码字符基本知识:增强型图形适配器(EGA)视频图形阵列适配器(EGA) 字符属性显示器的屏幕通常划分为行和列的一个二维系统,适配器就在行列组成的网格上显示字符。 对应显示器上的每个字符,在存储器中由连续的两个字节表示:一个字节保存ASCCII码,另一个保存字符的属性。 单色字符显示:对单色显示,字符的属性定义了字符的显示特性。如字符是否闪烁,是否加强亮度,是否反相显示等。D7D6D5D4D3D2D1D0前景000=黑111=白背景000=黑111=白亮度0=正常亮度1=加强亮度闪烁0=正常显示1=闪烁显示 在显示彩色文本时,属性字节能够选择前景(显示的字符)和背景的颜色,每个字符可以选择16种颜色之一,背景有8种颜色可供选择。彩色字符显示:BLRGBIRGB前景背景闪烁 BIOS显示中断下表列出了BIOS显示中断INT10H的部分操作及相应的入口、出口参数 显示方式的设置:INT10H的0H功能用来设置显示方式 在文本方式在屏幕上显示字符,字符在屏幕上的位置用行、列坐标表示。在80*25文本方式下,行号为0~24,列号为0~79。屏幕左上角为第0行、0列。在图形方式下,在屏幕上可以显示“点”,点可以称为像素、像元。像素在屏幕上的位置也可以用行列坐标表示,在分辨率为320*200像素的图形方式下,行号为0~199,列号为0~319 BIOS显示中断应用举例:例1:置光标开始行为5,结束行为7,并把它设置到第5行第6列。MOVCH,5MOVCL,7MOVAH,1INT10H;设置光标大小MOVDH,5MOVDL,6MOVBH,0;显示0页MOVAH,2INT10H 例2:清屏:程序在显示字符及图形前,一般要进行清屏。清屏的方法有很多种,下面介绍利用屏幕上卷(AH=06)功能进行清屏的程序CLEARCLEARPROCMOVAH,6MOVAL,0;AL=0时,为清屏MOVCH,0MOVCL,0;左上角MOVDH,24MOVDL,79;右下角MOVBH,7;上卷行属性正常(黑底白字)INT10HCLEARENDP 例3:单色字符的显示下面程序段功能是从屏幕(40,50)位置开始,用反相显示5个闪烁的‘*’MOVAH,2MOVBH,0MOVDH,40MOVDL,50INT10H;光标设置到(40,50)处MOVAH,9;显示字符属性及属性功能MOVAL,‘*’MOVBL,0F0H;属性:11110000B,白底黑字MOVCX,5;重复次数INT10H 例4在屏幕上以红底蓝字显示字符串:“WORLDSCENERY”STRINGDB‘WORLDSCENERY’LEN_STREQU$-STRING…….MOVAL,3MOVAH,0INT10H;设置80*25彩色文本显示方式MOVBP,SEGSTRINGMOVES,BPMOVBP,OFFSETSTRINGMOVCX,LEN_STRMOVDX,0;开始于左上角MOVBL,41H;41H=01000001红底蓝字MOVAL,0;光标返回起始位置MOVAH,13HINT10H 4.5.3DOS功能调用1.DOS功能调用概述8086/8088指令系统中,有一种软中断指令INTn。每执行一条软中断指令,就调用一个相应的中断服务程序。当n=5~1FH时,调用BIOS中的服务程序,一般称作系统中断调用;当n=20~3FH时,调用DOS中的服务程序,称作功能调用。其中,INT21H是一个具有调用多种功能的服务程序的软中断指令,故称其为DOS系统功能调用。 2.DOS功能调用方法1)DOS软中断(INT20H~INT27H)指令DOS软中断功能、入口及出口参数见表4-2。表中的入口参数是指在执行软中断指令前有关寄存器必须设置的值,出口参数记录的是执行软中断以后的结果及特征,供用户分析使用。DOS中断的使用方法是:首先按照DOS中断的规定,输入入口参数,然后执行INT指令,最后分析出口参数,如下所示:设置入口参数执行INTn分析出口参数 表4-2中INT22H、INT23H和INT24H用户不能直接调用。例如,INT23H是只有当同时按下CTRL和BREAK键时才形成DOS的23H号调用,其功能是:终止正在运行的程序,返回操作系统。INT25H为绝对读盘,INT26H为绝对写盘,这两条软中断的调用需要用户熟知磁盘结构,准确指出读/写的扇区号、扇区数、磁盘驱动器号,还需要知道与磁盘交换信息的内存缓冲区的首地址。因此,这种读/写磁盘的方式较落后,除特殊用途外,基本上已不采用。常用的磁盘读/写的方法请参阅《DOS系统功能调用》一书的介绍。 INT20H是两字节指令,它的作用是终止正在运行的程序,返回操作系统。这种终止程序的方法只适用于.COM文件,而不适用于.EXE文件。INT27H指令的作用是终止正在运行的程序,返回操作系统,被终止的程序驻留在内存中作为DOS的一部分,它不会被其他程序覆盖。在其他用户程序中,可以利用软中断来调用这个驻留的程序。 表4-2DOS软中断软中断功能入口参数出口参数INT20H程序正常退出INT21H系统功能调用AH=功能号功能调用相应的入口参数功能调用相应的出口参数INT22H结束退出INT23HCTRL+BREAK退出INT24H出错退出INT25H读盘CX=读出扇区数DX=起始逻辑扇区DS:BX=缓冲区地址AL=盘号CF=1出错INT26H写盘CX=写扇区数DX=起始逻辑扇区DS:BX=缓冲区地址AL=盘号CF=1出错INT27H驻留退出INT28H~INT2FHDOS专用 2)DOS系统功能调用(INT21H)系统功能调用INT21H是一个有近90个子功能的中断服务程序,这些子功能的编号称为功能号。INT21H的功能大致可以分为四个方面:设备管理、目录管理、文件管理和其他。设备管理主要包括键盘输入、显示器输出、打印机输出、串行设备输入/输出、初始化磁盘、选择当前磁盘、取剩余磁盘空间等。目录管理主要包括查找目录项、查找文件、置/取文件属性、文件改名等。文件管理主要包括打开、关闭、读/写、删除文件等,这是DOS提供给用户的最重要的系统功能调用。 系统功能调用(INT21H)的使用方法如下:设置功能号n(AH)设置入口参数执行INT21H分析出口参数文件管理有两种方法:一种是传统管理方法(功能号小于24H),与8位机的CP/M操作系统兼容;另一种是扩充的文件管理方法(功能号大于3CH),这是MS-DOS独有的。其他功能有终止程序、置/取中断矢量、分配内存、置/取日期及时间等。 (1)键盘输入:IBM-PC及PC/XT键盘上的按键分为三种类型:第一类是字符键,如字母、数字、字符等。按下此类键,即可输入此键相应的编码。第二类是功能键,如BackSpace、Home、End、Del、PageUp、PageDown、F1~F10等。按下此类键,可以产生一个动作。例如,按下BackSpace可以使光标向左移动一个位置。第三类是组合键及双态键,如Shift、Alt、Ctrl、Ins、NumLock、CapsLock、ScrollLock等。使用这些键能改变其他键所产生的字符码。 ①扫描码与字符码。键的扫描码——键盘的每一个键都有一对扫描码,扫描码用一个字节表示。低7位是扫描码的数字编码01~83,即01H~53H,最高位BIT7表示键的状态。当某键按下时,扫描码的BIT7=0,称为通码,当此键放开时,扫描码的BIT7=1,称为断码。通码和断码的值相差80H。键的字符码——键的字符码是键的ASCII码或扩充码,见第1章的ASCII码表。 ②有关键盘的系统功能调用。DOS系统功能调用中的功能1、7、8、A、B、C等都与键盘有关,包括单字符输入、字符串输入和键盘状态检验等。检查键盘状态——DOS系统功能调用的0BH号功能可以检查是否有字符键入。如果有键按下,使AL=FFH,否则AL=00H。这个调用十分有用,例如,有时要求程序保持运行状态,而不是无限期等待键盘输入,但又要靠用户接任意一键使程序结束或退出循环时,就必须使用0BH号调用。 如,LOP:MOVAH,0BHINT21H;检查键盘状态INCAL;有键按下AL=FFH,否则AL=00HJNZLOP;无键入字符,则循环RET;有键入字符,则停止循环返回单字符输入——功能1、7、8都可以直接接收键入的字符。程序中常常利用这些功能,回答程序中的提示信息,或选择菜单中的可选项以执行不同的程序段。用户还可以利用功能7、8不回显的特性,键入需要保密的信息。 【例4-9】从键盘接收单个字符并判断转移。MAIN:KEY:MOVAH,1;等待键入字符,当按下键后INT21H;AL=键入的字符CMPAL,'Y'JEYES;键入字符"Y",转至YES语句处CMPAL,'N'JENOT;键入字符“N”,转至NOT语句处JMPKEY;键入其他字符,转至KEY语句处,继续等待键入字符YES:NOT:……… 键入字符串——用户程序经常需要从键盘上接收一串字符。0AH号功能可以接收键入的字符串将其存入内存中用户定义的缓冲区。缓冲区结构如图4.13所示。缓冲区第一字节为用户定义的最大键入字符数,若用户键入的字符数(包括回车符)大于此数,则机器铃响且光标不再右移,直到键入回车符为止。缓冲区第二字节为实际键入的字符数(不包括回车符),由DOS自动填入。从第三字节开始存放键入的字符,显然,缓冲区的大小等于最大字符数加2。图4.13用户定义的缓冲区 (2)显示器(CRT)输出。功能2、6、9是关于CRT的系统功能调用。其中,显示单个字符的功能2、6与BIOS调用类似。显示字符串的功能9是DOS调用独有的,可以在用户程序运行过程之中,在CRT上向用户提示下一步操作的内容。使用功能调用9需要注意两点:第一,被显示的字符串必须以“$”为结束符;第二,当显示由功能0AH键入的字符串时,DS:DX应指向用户定义的缓冲区的第三字节,即键入的第一个字符的存储单元。例如,编写下面一段程序,并键入字符串‘HELLO’,则缓冲区的内容如图4.13所示。 【例4-10】从键盘接收字符串并输出到显示器。DATASEGMENTBUFSIZEDB25ACTCHARDB?CHARTEXTDB25DUP(20H)DB'$'DATAENDSCODESEGMENTASSUMECS:CODE,DS:DATA 比如键入的字符串为:12345START:MOVAX,DATAMOVDS,AXMOVDX,OFFSETBUFSIZEMOVAH,0AHINT21H;键入字符串,放入缓冲区MOVDX,OFFSETCHARTEXTMOVAH,09HINT21H;显示键入的字符串HLTCODEENDSENDSTART观看P107的演示MOVBH,0MOVBL,ACTCHARMOVCHARTEXT[BX],’$’531323334350D2020….2419观看P107B的演示 显示字符串部分的功能也可以用循环程序实现:MOVCX,ACTCHARLEABX,CHARTEXTAGAIN:MOVDL,[BX]MOVAH,2INT21HINCBXLOOPAGAINHLT (3)打印机输出。关于打印机操作的系统功能调用只有一种,即打印一个字符的功能5。利用此功能还可以改变打印机的打印方式。下面一段程序将EPSON-80打印机设置为“加重打印”方式。【例4-11】打印机设置为“加重打印”方式。DATASEGMENTSTRDB1BH,45H;“加重打印”的控制码CODESEGMENT…… MOVCX,2MOVAH,5LEABX,STRPRINT:MOVDL,[BX]INT21HINCBXLOOPPRINT… 这段程序既可以放在用户程序中,也可以作为一个独立的文件,经汇编、连接后单独运行。若要取消加重打印方式,或设置其他方式,只需与之类似的程序段即可。相应的控制码请查阅打印机手册。 4.5.4宏汇编在程序设计中,为了简化程序的设计,将多次重复使用的程序段用宏指令代替。宏指令是指程序员事先定义的特定的“指令”,这种“指令”是一组重复出现的程序指令块的缩写和替代。宏指令定义以后,凡在宏指令出现的地方,宏汇编程序总是自动地把它们替换成对应的程序指令块。宏指令有时也称为宏,包含有宏定义和宏调用。宏指令的特点:简化源程序的编写,汇编语言编程的参数传递特别灵活,功能更强。 1.宏指令定义宏是源程序中的一段具有独立功能的程序代码。它只要在源程序中定义一次,就可以多次调用,调用时只要使用一个宏指令语句就可以了。宏指令定义由开始伪指令MACRO、宏指令体、宏指令定义结束伪指令ENDM组成。格式如下:宏指令名MACRO[形式参数1,形式参数2,…,形式参数N]…………….;宏指令体(宏体)ENDM 宏指令名是宏定义为宏体程序指令块规定的名称,可以是任一合法的名字,也可以是系统保留字(如指令助记符、伪指令操作符等),当宏指令名是系统保留字时,则该系统保留字就被赋予新的含义,从而失去原有的意义。MACRO语句到ENDM语句之间的所有汇编语句构成宏指令体,简称宏体,宏体中使用的形式参数必须在MACRO语句中列出。 形式参数是出现在宏体内某些位置上可以变化的符号,也可以是任一合法的名字,甚至是寄存器名。如果形式参数中使用某些寄存器名,那么在宏汇编展开时,将不认为这些寄存器名是寄存器本身,而是形式参数,并被实际参数所代替。形式参数可以缺省,也可以有一个或多个。当形式参数多于一个时,形式参数之间用逗号隔开,形式参数个数每行应小于等于132个字符。宏指令定义一般放在源程序的开头,以避免产生不应发生的错误。宏指令必须先定义后调用(引用)。宏指令可以重新定义,也可以嵌套定义。嵌套定义是指在宏指令体内还可以再定义宏指令或调用另一宏指令。 2.宏调用宏指令一旦定义后,就可以用宏指令名字(宏名)来调用(或引用)。宏调用的格式为:宏指令名实际参数1,实际参数2,…,实际参数N其中,实际参数的类型和顺序要与形式参数的类型和顺序保持一致,宏调用时将一一对应地替换宏指令体中的形式参数。当有两个以上参数时,中间用逗号、空格或制表符隔开。宏指令调用时,实际参数的数目并不一定要和形式参数的数目一致,当实参个数多于形参的个数时,忽略多余的实参;当实参个数少于形参个数时,多余的形参用空串代替。 【例4-12】定义一条INOUT宏指令,既可以引用它输入一串字符,也可引用它显示一串提示字符。宏定义如下:INPUTMACRO;定义一条从键盘输入一个字符的宏指令INPUTMOVAH,1;采用宏指令语句INPUT编程,类似于高级语言语句INT21HENDMLFMACRO;定义一条换行宏指令LFMOVDL,10MOVAH,2INT21HENDM CRMACRO;定义一条回车宏指令CRMOVDL,13MOVAH,2INT21HENDMINOUTMACROX,Y;定义一条输入/输出宏指令INOUTMOVAH,XLEADX,YINT21HENDM 宏调用:DATASSEGMENTINPUT1DB'PLEASEINPUTANYCHARACTERS:’,'$'KEYBUFDB10,11DUP(?),13,10,'$'DATASENDSCODESSEGMENTASSUMECS:CODES,DS:DATASSTART:PUSHDSXORAX,AXPUSHAXMOVAX,DATASMOVDS,AX INOUT9,INPUT;显示一串提示符的宏指令调用LF;换行,调用宏定义CR;回车,调用宏定义INOUT10,KEYBUF;输入一串字符的宏指令调用LFCRINOUT9,KEYBUF+2;显示输入的一串字符的宏指令调用RETCODESENDSENDSTARTMOVBH,0MOVBL,KEYBUF+1MOVKEBUF+2[BX],‘$’观看P109演示观看P109B演示 3.宏展开宏汇编程序若遇到宏指令定义时并不对它进行汇编,只有在程序中引用的时候,汇编程序才把对应的宏指令体调出进行汇编处理(语法检查和代码块的插入),这个过程称宏展开(或宏扩展)。宏指令调用后,在宏指令调用处产生用实参替换形参的宏体指令语句。在MASM汇编生成列表文件(.LST)的每行中间用符号“+”作为标志,表明本行语句为宏指令展开生成的语句。本章为说明是宏展开生成的语句,在语句的左边仍用符号“+”标志。例如,上述INOUT宏指令调用后,宏展开后的语句如下: +MOVAH,9+LEADX,KEYBUF+2+INT21H+MOVAH,10+LEADX,KEYBUF+INT21H+MOVDL,13+MOVAH,2+INT21H+MOVDL,10+MOVAH,2+INT21H+MOVAH,9+LEADX,INPUT+INT21HINOUT9,INPUTLFCRINOUT10,KEYBUFINOUT9,KEYBUF+2 补充:1、PURGE:伪操作PURGE的用途是取消已有的宏定义。格式如下:PURGE宏指令名[,……]如果欲对一个宏指令名重新定义,则必须先用PURGE伪操作取消以前的定义,然后在重新定义。2、LOCAL伪操作LOCAL的作用是向宏汇编程序MASM指出宏定义体中的局部标号。利用这个伪操作将允许在宏定义体内使用标号。如果没有LOCAL伪操作,则当多次调用一个使用标号的宏定义时,通过宏扩展,宏定义体中的标号将在程序中多处出现,从而产生标号多重定义的错误。LOCAL伪操作只能出现在宏定义体内,而且必须位于宏定义中其它所有语句(包括注释)之前。 格式如下:LOCAL局部标号[,……..]如果有多个局部标号,互相之间应该用逗号隔开。汇编以后,MASM在每一次宏扩展中自动将一个新的标号代替原来的局部标号。新标号的形式为:??0000至??FFFF。所以在源程序中其他地方应该避免使用这种形式的符号。例:源程序中多次需要将不同寄存器中的十六进制数转换为相应的ASCII码时,可以定义以下宏指令:HEXTOASCMACROREGLOCALNUMECMPREG,0AHJCNUMEADDREG,07NUME:ADDREG,30HENDM 有下面宏调用:HEXTOASCAL………HEXTOASCBL宏展开后:+CMPAL,0AH+JC??0000+ADDAL,07+??0000:ADDAL,30HHEXTOASCALHEXTOASCMACROREGLOCALNUMECMPREG,0AHJCNUMEADDREG,07NUME:ADDREG,30HENDM+CMPBL,0AH+JC??0001+ADDBL,07+??0001:ADDBL,30H………….HEXTOASCBL 4.5.5子程序结构形式与操作1.子程序定义可把具有独立功能的程序段定义为子程序,供其他程序调用,类似于C语言的函数。子程序定义伪操作用在子程序的前后,使整个子程序形成清晰的、具有特定功能的代码块。子程序定义的语法格式为:<子程序名>PROCAttribute……..RET<子程序名>ENDP其中,子程序名为标识符,它又是子程序入口的符号地址,它的写法与标号的写法相同;属性(Attribute)是指类型属性,它可以是NEAR或FAR。 如前所述,CALL和RET指令都有NEAR和FAR的属性,段内调用使用NEAR属性,但可以不显示地写出;段间调用使用FAR属性。为了使用户的工作更加方便,80x86的汇编程序用PROC伪操作的类型属性来确定CALL和RET指令的属性。也就是说,如果所定义的子程序是FAR属性的,那么对它的调用和返回一定都是FAR属性;如果所定义的子程序是NEAR属性的,那么对它的调用和返回也一定是NEAR属性。这样,用户只需在定义子程序时考虑它的属性,而CALL和RET的属性可以由汇编程序来确定。 用户对子程序属性确定原则很简单:(1)如调用程序和子程序在同一个代码段中,则使用NEAR属性;(2)如调用程序和子程序不在同一个代码段中,则使用FAR属性。 【例4-13】调用程序和子程序在同一代码段中。MAINPROCFAR;主程序CALLSUBR1RETMAINENDPSUBR1PROCNEAR;子程序(NEAR可省略)RETSUBR1ENDP……… 由于调用程序MAIN和子程序SUBR1是在同一代码段中的,所以SUBR1定义为NEAR属性。这样,MAIN中对SUBR1的调用和SUBR1中的RET就都是NEAR属性。但是一般说来,主程序MAIN应定义为FAR属性,这是由于把程序的主子程序看作DOS调用的一个子程序,因而DOS对MAIN的调用以及MAIN中的RET就是FRA属性。当然,CALL和RET的属性是汇编程序确定的,用户只需正确选择PROC的属性就可以了。 也就是说,子程序定义也可以嵌套,一个子程序定义中可以包括多个子程序定义。例4-13的情况也可以写成如下的程序:MAINPROCFARCALLSUBR1RETSUBR1PROCNEARRETSUBR1ENDPMAINENDP……… 【例4-14】调用程序和子程序不在同一个代码段内。SEGXSEGMENTSUBTPROCFARRETSUBTENDPCALLSUBTSEGXENDSSEGYSEGMENTCALLSUBTSEGYENDS…………… SUBT是一个子程序,它在两处被调用,一处是与SEGX同在段内,另一处是在SEGY段内。为此,SUBT必须具有FAR属性以适应SEGY段调用的需要。SUBT既然有FAR属性,则不论在SEGX段还是SEGY段中,对SUBT的调用就都具有FAR属性了,这样不会发生什么错误。反之,如果这里的SUBT使用了NEAR属性,则在SEGY段内对它的调用就要出错了。 2.子程序的调用和返回子程序的正确执行是由子程序的正确调用和正确返回保证的,80x86的CALL和RET指令完成的就是调用和返回的功能。为保证其正确性,除PROC的属性要正确选择外,还应该注意子程序运行期间的堆栈状态。由于执行CALL时已使返回地址入栈,所以执行RET时应该使返回地址出栈,如果子程序中不能正确使用堆栈而造成执行RET前SP并未指向进入子程序时的返回地址,则必然会导致运行出错。因此,子程序中对堆栈的使用应该特别小心,以免发生错误。 3.现场保护与现场恢复由于主程序和子程序通常是分别编制的,所以它们所使用的寄存器往往会发生冲突。如果主程序在调用子程序之前的某个寄存器内容在从子程序返回后还有用,而子程序又恰好使用了同一个寄存器,这就破坏了该寄存器的原有内容,因而会造成程序运行错误,这是不允许的。为避免这种错误的发生,在进入子程序后,就应该把子程序所需要使用的寄存器内容保存在堆栈中,此过程称作现场保护;而在退出子程序前把寄存器内容恢复原状,此过程称作现场恢复。现场保护与现场恢复分别使用压栈和弹出指令实现。例如: SUBTPROCPUSHAX;现场保护PUSHBXPUSHCXPUSHDX<子程序体>POPDX;现场恢复POPCXPOPBXPOPAXRETSUBTENDP… 在子程序设计时,应仔细考虑哪些寄存器是必须保护的,哪些寄存器是不必要保护的。一般说来,子程序中用到的寄存器是应该保护的。但是,如果使用寄存器在主程序和子程序之间传送参数的话,则这种寄存器就不一定需要保护,特别是用来向主程序回送结果的寄存器,就更不应该因保存和恢复寄存器而破坏了应该向主程序传送的信息。从80286CPU开始使用的PUSHA/POPA指令以及从80386CPU开始的高档微机使用的PUSHAD/POPAD指令为子程序中保存和恢复寄存器内容提供了有力的支持。 4.子程序嵌套主程序调用子程序,子程序还可以调用其他子程序,这就是子程序的嵌套调用,子程序可以多重嵌套调用。 DATASEGMENTBUFDB25,13,23,100,123,78,134,90;定义数据CNTEQU$-BUF;数据个数DATAENDSCODESEGMENTASSUMECS:CODE,DS:DATASTART:MOVAX,DATAMOVDS,AXMOVCX,CNT-1;比较次数【例4-15】设从BUF开始存放若干无符号字节数据,找出其中的最小值并以十六进制形式输出。分析:本题用子程序SEARCH来求最小数字节数并输出,再调用一个子程序输出1位十六进制数,由于数据多,因此可以利用子程序的嵌套。 MOVSI,OFFSETBUF;首地址CALLSEARCHMOVAH,4CH;返回DOSINT21HSEARCHPROCNEARMOVBL,[SI];假定第一个数为最小数SEAR1:INCSI;指向下—个数CMPBL,[SI];比较JBESEAR2;BL中的数小,转SEAR2MOVBL,[SI];BL中的数大,把它替换掉如果程序要求将最大数找出来,应怎样修改程序?JAESEAR2 SEAR2:DECCXJNZSEAR1;循环比较MOVDL,BL;最小值送DLMOVCL,4SHRDL,CL;分离出高4位CALLDISP;调用子程序显示输出MOVDL,BL;最小值送DLANDDL,0FH;分离出低4位CALLDISP;调用子程序显示输出RETSEARCHENDP DISPPROCNEARCMPDL,9;DL和9比较JBEDISP1;小于等于9加30H,否则加37HADDDL,7DISP1:ADDDL,30HMOVAH,2;输出INT21HRETDISPENDPCODEENDSENDSTART观看P113演示最小数显示观看P113B演示最大数显示 1、宏处理伪操作由宏汇编程序MASM在汇编过程中进行处理,在每个宏调用处,将相应的宏定义体插入;而调用指令CALL和返回指令RET则是CPU指令,执行CALL指令时,CPU使程序的控制转移到子程序的入口地址。2、宏指令简化了源程序,但不能简化目标程序,汇编后,在宏定义处不产生机器代码,但在每个宏调用处,通过宏展开,重复程序段的机器代码仍然出现多次,因此并不节省内存单元;对于子程序来说,在目标程序中,定义子程序的地方将产生相应的机器代码,但每次调用时只需用CALL指令,不再重复出现子程序的机器代码,一般来说可以节省内存容量。3、从执行时间看,调用子程序和从子程序返回需要保护断点、恢复断点等,将额外占用CPU的时间;而宏指令则不需要,因此相对来说执行速度较快。此外,宏指令更加接近高级语言,而且传递参数更加方便。宏与子程序的区别 4.6程序设计举例【例4-20】在屏幕上显示电子钟。编写一个8086/8088汇编语言程序,使程序运行后屏幕显示器成为一台电子钟。首先在屏幕上显示提示符,要求从键盘上输入当前时间,然后每隔一秒使显示的秒值加1,达到60秒时使分值加1,秒值清零;达到60分时使小时值加1,分值清零;达到24小时则小时值清零。上述过程一直进行下去,当键入Ctrl+C键时退出“电子钟”状态,返回DOS。 根据上述要求,画出程序的流程图如图4.18所示。其中,显示一个字符串,以及从键盘上接收和显示一个字符串可分别通过09号和0AH号DOS功能调用实现。延时1秒可以编一个延时子程序。程序中对时、分、秒三个时间单位有许多类似的操作,例如分别将它们由ASCII码转换为BCD码,或由BCD码转换为ASCII码,以及将时、分、秒值分别加1,并DAA调整后判断是否达到60H或24H等。对于这样的程序段,可以采用宏处理伪操作,以便缩短源程序的长度,使程序更加清晰,有利于结构的模块化。另外,还可以利用BIOS调用设计窗口,选择适当的背景色和前景色等,以使屏幕显示更加美观。程序清单如下: 开始显示提示符接收键入当前时间时、分、秒值转换及存储1延时1秒DL+1,DAA调整(DL)≥60H?DL清零、DH加1,DAA(DH)≥60H?NNNYYY时分秒值BCD变ASCII显示CH清零(CH)≥24DL清零、CH加1,DAA1 TITLE例4-20.ASMDATASEGMENTBUF1DB'Currenttimeis:$'BUF2DB10DB10DUP(?)DATAENDSSTACKSEGMENTSTACKDB100DUP(?)STACKENDSCODESEGMENT ASSUMECS:CODE,DS:DATA,SS:STACKCURSORMACROROW,CLMMOVAH,2MOVBH,0MOVDH,ROWMOVDL,CLMINT10HENDMWINMACROROWL,CLML,ROWR,CLMR,COLORMOVAH,6MOVAL,0MOVCH,ROWL置光标位置BH=页号DH=行号DL=列号AH=2功能号INT10H MOVCL,CLMLMOVDH,ROWRMOVDL,CLMRMOVBH,COLORINT10HENDMASCBCDMACROREG;ASCII变BCDINCBXINCBXMOVREG,[BX]MOVCL,4屏幕初始化或上卷AL=上卷行数AL=0全屏幕为空白BH=卷入行属性CH=左上角行号CL=左上角列号DH=右下角行号DL=右下角列号AH=6功能号INT10H关于属性BX指向BUF21、ASCBCDCH时2、ASCBCDDH分3、ASCBCDDL秒 SHLREG,CLINCBXMOVAL,[BX]ANDAL,0FHORREG,AL;变成压缩BCDENDMBCDASCMACROREGINCBXINCBXMOVAL,REGMOVCL,4SHRAL,CLORAL,30HBX指向BUF2当前时间以BCD形式存放在BUF+2开始的区域1、BCDASCCH2、BCDASCDH3、BCDASCDL MOV[BX],AL;变成ASCII码INCBXMOVAL,REGANDAL,0FHORAL,30HMOV[BX],AL;变成ASCII码ENDMINCBCDMACROREG,COUNTMOVAL,REGINCALDAAMOVREG,AL时、分、秒的BCD码加1并比较,判断是否时、分加1:1、INCBCDDL,60H2、INCBCDDH,60H3、INCBCDCH,24H CMPAL,COUNTJNZDISPYMOVREG,0ENDMSTRDSPYMACROADRSLEADX,ADRSMOVAH,9INT21HENDMCLOCKPROCFARSTART:PUSHDSMOVAX,0PUSHAX MOVAX,DATAMOVDS,AXWIN0,0,24,79,7;全屏黑白WIN9,28,15,52,01010111BCURSOR11,32STRDSPYBUF1CURSOR13,36LEADX,BUF2MOVAH,0AHINT21HLEABX,BUF2ASCBCDCHASCBCDDHASCBCDDL窗口位置:(9,28)、(15,52)、显示属性:背景品红、灰白字体 TIMER:CALLDELY;延时1秒INCBCDDL,60HINCBCDDH,60HINCBCDCH,24HDISPY:LEABX,BUF2BCDASCCHBCDASCDHBCDASCDLINCBXMOVAL,'$'MOV[BX],AL PUSHDXCURSOR13,36STRDSPYBUF2+2POPDXJMPTIMERDELYPROC;延时子程序PUSHCXPUSHAXMOVAX,3FFFHX1:MOVCX,0FFFFH X2:DECCXJNEX2DECAXJNEX1POPAXPOPCXRETDELYENDPCLOCKENDPCODEENDSENDSTART 【例4-21】图4.19是“两只老虎”的简谱。根据乐谱在数据段中定义了频率数据表(FREQ)和节拍时间数据表(TIME),程序以-1作为频率数据表的结束标志。程序流程图如图4.20所示,演奏该乐曲程序如下:图4-19“两只老虎”简谱1=C4/41231|1231|345-|345-|565431|565431|251-|251-| 图4.20例4-21流程图 TITLE例4-21.ASMDATASEGMENTFREQDW262,294,330,262,262,294,330,262DW330,349,392,330,349,392,392,440DW392,349,330,262,392,440,392,349DW330,262,294,196,262,294,196,262,-1TIMEDW25,25,25,25,25,25,25,25,25,25DW50,25,25,50,12,12,12,12,25,25DW12,12,12,12,25,25,25,25,50,25,25,50SNAMEDB'TWOTIGER.$’DATAENDSSTACKSEGMENTSTACK‘STACK'DB100DUP(0) STACKENDSCODESEGMENTASSUMECS:CODE,SS:STACK,DS:DATAPLAYPROCFARPUSHDSMOVAX,0PUSHAXMOVAX,DATAMOVDS,AXMOVDX,OFFSETSNAMEMOVAH,9INT21HMOVAL,0B6HOUT43H,ALMOVBP,OFFSETTIMEMOVSI,OFFSETFREQ SONG:MOVDI,[SI]CMPDI,-1JZEXITMOVBX,DS:[BP]CALLCSOUNDINCSIINCSIINCBPINCBPJMPSONGEXIT:RET CSOUNDPROCNEARPUSHAXPUSHBXPUSHCXPUSHDXPUSHSIMOVDX,12HMOVAX,34DCHDIVDIOUT42H,ALMOVAL,AHOUT42H,ALINAL,61HMOVAH,ALORAL,03HOUT61H,ALMOVBX,3FFFH DLY0:MOVCX,32717DLY1:LOOPDLY1DECBXJNZDLY0MOVAL,AHOUT61H,ALPOPSIPOPDXPOPCXPOPBXPOPAXRETCSOUNDENDPPLAYENDPCODEENDSENDPLAY 习题44.1假设下列指令中的所有标识符均是类型属性为字的变量,请指出下列指令中哪些是非法的?它们的错误是什么?MOVBP,AL(2) MOVWORD_OP[BX+4*3][DI],SP(3) MOVWORD_OP1,WORD_OP2(4) MOVAX,WORD_OP1[DX](5) MOVSAVEWORD,DS(6) MOVSP,SS:DATA_WORD[BX][SI](7) MOV[BX][SI],2(8) MOVAX,WORD_OP1+WORD_OP2(9) MOVAX,WORD_OP1_WORD_OP2+100(10) MOVWORD_OP1,WORD_OP1_WORD_OP2 4.2假设VAR1和VAR2为字变量,LAB为标号,试指出下列指令的错误之处。(1)ADDVAR1,VAR2(2) SUBAL,VAR1(3) JMPLAB[SI](4) JNZVAR1(5) JMPNEARLAB 4.3画图说明下列语句所分配的存储空间及初始化的数据值。(1) BYTE_VARDB‘BYTE’,12,-12H,3DUP(0,?,2DUP(1,2),?)(2) WORD_VARDW5DUP(0,1,2),?,-5,‘BY’,‘TE’,256H4.4试列举各种方法,用汇编程序把5150H存入一个存储器字中(例如,DW5150H)。 4.5假设程序中的数据定义如下:PARTNODW?PNAMEDB16DUP(?)COUNTDD?PLENTHEQU$-PARTNO问PLENTH的值为多少?它表示什么意义? 4.6有符号定义语句如下:BUFFDB1,2,3,‘123’EBUFFDB0LEQUEBUFF-BUFF问L的值是多少? 4.7假设程序中的数据定义如下:LNAMEDB30DUP(?)ADDRESSDB30DUP(?)CITYDB15DUP(?)CODE_LISTDB1,7,8,3,2(1)用一条MOV指令将LNAME的偏移地址放入AX。(2)用一条指令将CODE_LIST的头两个字节的内容放入SI。(3)写一条伪操作使CODE_LENGHT的值等于CODE_LIST域的实际长度。 4.8试写出一个完整的数据段DATA_SEG,把整数5赋予一个字节,并把整数-1,0,2,5和4放在10字数组DATA_LIST的前5个单元中。然后,写出完整的代码段,其功能是把DATA_LIST中前5个数中的最大值和最小值分别存入MAX和MIN单元中。 4.9给出等值语句如下:ALPHAEQU100BETAEQU25GAMMAEQU2 问下列表达式的值各是多少?ALPHA*100+BETA(2)ALPHAMODGAMMA+BETA(3) (ALPHA+2)*BETA-2(4) (BETA/3)MOD5(5) (ALPHA+3)*(BETAMODGAMMA)(6) ALPHAGEGAMMA(7) BETAAND7(8) GAMMAOR3 4.10对于下面的数据定义,三条MOV指令分别汇编成什么?(可用立即数方式表示)TABLEADW10DUP(?)TABLEBDB10DUP(?)TABLECDB‘1234’MOVAX,LENGTHTABLEAMOVBL,LENGTHTABLEBMOVCL,LENGTHTABLEC… 4.11对于下面的数据定义,各条MOV指令单独执行后,有关寄存器的内容是什么?FLDBDB?TABLEADW20DUP(?)TABLEBDB‘ABCD’(1) MOVAX,TYPEFLDB(2) MOVAX,TYPETABLEA(3) MOVCX,LENGTHTABLEA(4) MOVDX,SIZETABLEA(5) MOVCX,LENGTHTABLEB 4.12编写在屏幕上显示字符串‘THISISTEXTDISPLAYPROGRAM.’的程序。4.13编写“外婆的澎湖湾”乐曲的演奏程序。4.14编写程序,接收从键盘输入的10个十进制数字,输入中遇见回车符则停止输入,各个数经过BCD码处理,以十六进制数显示在屏幕上。 补充题2:设计一个宏,其功能是完成回车换行功能,宏名为CRLF补充1:程序中多次要求将某两个8位寄存器或内存单元中的无符号数相乘,并将得到的乘积放在某个16位寄存器或存储单元中,要求:1、定义一个宏指令2、假设进行以下两次宏调用,写出宏调用和宏扩展的结果。①将BL和CL寄存器的内容相乘,乘积放在DX寄存器②将CH寄存器和DATA存储单元的内容相乘,乘积放在存储单元BUFFER和BUFFER+1。补充 1、单色显示的属性字节D7D6D5D4D3D2D1D0闪烁0正常显示1闪烁显示亮度0正常亮度1加强亮度背景000黑色111白色前景000黑色111白色 2、彩色字符显示BLRGBIRGB闪烁背景前景颜色IRGB颜色IRGB颜色IRGB颜色IRGB黑0000灰1000红0100浅红1100蓝0001浅蓝1001品红0101浅品红1101绿0010浅绿1010棕0110黄1110青0011浅青1011灰白0111白1111

当前文档最多预览五页,下载文档查看全文

此文档下载收益归作者所有

当前文档最多预览五页,下载文档查看全文
温馨提示:
1. 部分包含数学公式或PPT动画的文件,查看预览时可能会显示错乱或异常,文件下载后无此问题,请放心下载。
2. 本文档由用户上传,版权归属用户,天天文库负责整理代发布。如果您对本文档版权有争议请及时联系客服。
3. 下载前请仔细阅读文档内容,确认文档内容符合您的需求后进行下载,若出现内容与标题不符可向本站投诉处理。
4. 下载文档时可能由于网络波动等原因无法下载或下载错误,付费完成后未能成功下载的用户请联系客服处理。
关闭