




已阅读5页,还剩79页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
2020/6/9,8086/8088宏汇编语言程序设计,第5章程序设计基本技术,顺序程序设计分支程序设计循环程序设计子程序设计DOS功能子程序的调用,2020/6/9,8086/8088宏汇编语言程序设计,5.1概述,我们知道,8086/8088CPU把存储器分成若干段,而每一个段是可独立寻址的逻辑单位。段是8086/8088系列微机的汇编语言程序的基础。一个段就是若干指令和数据的集合。因此,我们在编制汇编语言源程序时,首先要使用段定义伪指令来构造一个由若干指令和数据组成的程序段。程序中逻辑段的数目由实际情况确定,通常根据程序中的用途来划分段,如作堆栈使用的段、存放数据的段,存放程序的段等等。,2020/6/9,8086/8088宏汇编语言程序设计,程序基本段结构DATASEGMENTDATAENDSSTACK1SEGMENTPARASTACKDW20HDUP(0)STACK1ENDSCODESEGMENTBEGIN:MOVAX,DATAMOVDS,AX;装入数据段寄存器MOVAH,4CHINT21H;返回到DOS,返回码为0CODEENDSENDBEGIN,2020/6/9,8086/8088宏汇编语言程序设计,在程序中,代码段、数据段、附件段和堆栈段这4个段的顺序是任意的。程序的功能是由代码段来实现的。程序的代码段的基本结构有4类:顺序程序、循环程序、分支程序和子程序。,分支结构子程序结构,顺序结构循环结构,2020/6/9,8086/8088宏汇编语言程序设计,编制汇编语言源程序的步骤,(1)分析问题,确定算法(2)根据算法画出程序流程图(3)合理分配存储空间和寄存器(4)根据流程图编写程序(5)调试程序分析问题,确定算法就是确定解决问题的方法和步骤。编制流程图是将解决问题的方法、步骤用框图的形式表示出来。如果要解决的问题比较复杂,那么可以逐步细化,直到每一框图都可以很容易编制程序为止。,2020/6/9,8086/8088宏汇编语言程序设计,编制汇编语言源程序的步骤,流程图不仅便于编写程序,而且对程序逻辑上的正确性也比较容易查找和修改。流程图主要由处理框、判定框、起止框、连接框和流向线5种框图符号组成。,处理框,判定框,起始框,连接框,流向线,2020/6/9,8086/8088宏汇编语言程序设计,(1)处理框:用于说明一程序段(或一条指令)所完成的功能。这种框图通常只有一个入口和一个出口。(2)判断框:表示进行程序的分支流向判断,框内记入判定条件。这种框图通常有一个入口,两个或两个以上的出口。在每个出口上要注明分支流向的条件。(3)起止框:表示一个程序或一个程序模块的开始和结束。起始框内通常用程序名、标号或“开始”字符来表示,它仅有一个出口。终止框内通常用“结束”或“返回”字符表示,它仅有一个入口。(4)连接框:当程序比较复杂时,流程图的连线较多,且常常纵横交错,这时可以用连接框来表示两根流向线的连接关系。所以连接框种常用字母或数字来表示。框内有相同字母或数学就表示它们有连线关系。通常它只有一个入口或出口。(5)流向线:表示程序的流向。,2020/6/9,8086/8088宏汇编语言程序设计,存储器和寄存器的分配,存储器和寄存器时进行汇编语言程序设计的舞台。由于CPU中的寄存器数量有限而且有些操作要使用特定的寄存器,所以程序中要合理分配各寄存器的用途。程序运行时,其目标代码时存放在存储器中的,而且操作数和程序执行的结果也是存储在存储单元中的。因此,充分利用存储空间,节约使用存储空间时我们编制一个好的应用程序应该注意的问题。为了编程方便,我们通常给这些存储单元赋予一个名字(例如变量名)。存储器中的存储单元有3种类型的用途:(1)常数单元:在这些存储单元中存放的数据是整个程序的常量,且不因程序运行的次数发生改变。在程序中不能修改它的值。,2020/6/9,8086/8088宏汇编语言程序设计,存储器和寄存器的分配,(2)数据单元:数据单元是程序运行中处理的对象,除非程序要求处理变动这些单元的内容,可以在程序中设置新值外,通常不要轻易修改这些单元的内容,以便程序可以多次运行。(3)工作单元:工作单元用于存放中间结果和最后结果,因此工作单元的内容在程序运行期间是经常变化的。为了合理的利用存储器单元,在程序设计时要合理分配常数单元,数据单元和工作单元,并充分利用寄存器来减少存放中间结果的工作单元,这样不仅可以节约存储单元,还能提高程序运行速度。,2020/6/9,8086/8088宏汇编语言程序设计,编制汇编语言源程序的步骤,完成了存储单元和寄存器的分配后,就要根据程序框图进行汇编语言源程序的编写。在进行汇编语言源程序编写时,首先按程序中各部分的用途分段,在使用指令语句和伪指令语句的时候要分清其功能,并且正确使用各种寻址方式。编写好源程序后,就要对源程序进行调试。调试的步骤:(1)用MASM汇编.ASM文件(2)用LINK连接.OBJ文件(3)用DEBUG调试.EXE文件,2020/6/9,8086/8088宏汇编语言程序设计,5.2顺序程序设计,顺序程序是最简单,也是最基本的一种程序结构形式。顺序程序结构是从开始到结尾都一直是顺序执行的,中途没有任何分支。程序一直按指令序列在存储器中的存放顺序来执行,由CS:IP提供的指令地址来控制。例5.2.1试编写一程序计算以下表达式:Z=(3X+Y-5)/2。设X、Y的值存放在字变量VARX、VARY中,结果放在VARZ中。,2020/6/9,8086/8088宏汇编语言程序设计,顺序程序设计,算法分析:1、乘2和除2可以使用算术左移和右移实现2、3X可以分解成2X+X流程图:,开始,计算3X,计算3X+Y,计算3X+Y-5,计算(3X+Y-5)/2,存结果,结束,2020/6/9,8086/8088宏汇编语言程序设计,TITLEEXAMPLE1DATASEGMENTVARXDW15VARYDW10VARZDW?DATAENDSSTACK1SEGMENTPARASTACKDW20HDUP(0)STACK1ENDSCODESEGMENTASSUMECS:CODE,DS:DATA,SS:STACK1COMPPROCFARPUSHDS;保护返回DOS地址MOVAX,0PUSHAX,2020/6/9,8086/8088宏汇编语言程序设计,MOVAX,DATA;初始化DS,MOVDS,AX,MOVAX,VARX;AXX,SHLAX,1;AX2X,ADDAX,VARX;AX3X,ADDAX,VARY;AX3X+Y,SUBAX,5;AX3X+Y-5,SARAX,1;AX(3X+Y-5)/2,MOVVARZ,AX;存结果,RET;返回DOS,COMPENDP,CODEENDS,ENDCOMP,2020/6/9,8086/8088宏汇编语言程序设计,顺序程序设计,当一个用户程序的可执行文件装入内存后,无论用户程序有几个段,也不管这些段的排列顺序如何,用户程序的目的代码一定是直接加载在程序段前缀(ProgramSegmentPrefix)PSP段的后面。PSP段给出了用户可执行文件的若干控制信息。其中PSP段的开始处(第1、2字节)有一条软中断指令“INT20H”。这条指令可以用来实现结束用户程序,返回操作系统的功能。如果使用这种方式返回,则首先用户要把用户程序设置成一个过程,且类型属性为FAR,由于可执行文件转入内存后DS和ES两个段寄存器是指向PSP段的。所以将DS和偏移量00H分别压入堆栈,用户程序结束时用RET指令完成将原先压入堆栈的PSP段基值和00H的偏移量分别送入CS和IP。执行完RET指令后,就可以转去执行PSP段开始处的“INT20H”软中断指令了。,2020/6/9,8086/8088宏汇编语言程序设计,顺序程序设计,除了用上述方法来结束用户程序,返回操作系统外,还可以使用另外一种方法:使用软中断指令“INT21H”。如果使用软中断指令“INT21H”来返回,则用户程序可以不设置过程,只要在用户程序结束时,使用两条指令即可。指令如下:MOVAH,4CHINT21H如果使用此返回方式,程序代码可以修改为:,2020/6/9,8086/8088宏汇编语言程序设计,TITLEEXAMPLE1DATASEGMENTVARXDW15VARYDW10VARZDW?DATAENDSSTACK1SEGMENTPARASTACKDW20HDUP(0)STACK1ENDSCODESEGMENTASSUMECS:CODE,DS:DATA,SS:STACK1STRAT:MOVAX,DATAMOVDS,AX;初始化DS,2020/6/9,8086/8088宏汇编语言程序设计,MOVAX,VARX;AXX,SHLAX,1;AX2X,ADDAX,VARX;AX3X,ADDAX,VARY;AX3X+Y,SUBAX,5;AX3X+Y-5,SARAX,1;AX(3X+Y-5)/2,MOVVARZ,AX;存结果,MOVAH,4CHINT21H;返回DOS,CODEENDS,ENDSTRAT,例2、P82,2020/6/9,8086/8088宏汇编语言程序设计,顺序程序设计,换码指令(XLAT)指令格式:XLAT表首址指令功能:(AL)+(BX)AL使用这条指令时,将表首址的偏移量送入BX中,而把要查表内的单元的偏移量(0255)送入AL中,两者的和就是要查找元素的实际偏移量,执行指令后,结果存放在AL中。该指令的执行不影响标志寄存器中的标志位。,2020/6/9,8086/8088宏汇编语言程序设计,5.3分支程序设计,8086/8088指令系统提供了许多指令来完成对程序流向的控制和转移,以便在程序运行过程中改变指令的执行顺序。在程序运行过程中,对指令执行的控制是由CS和IP决定的。因此,程序流向的控制和转移,主要是改变CS和IP。若转移仅在同一个段内进行(段内转移),则只需要修改IP;若是在两个段之间进行(段间转移),则CS和IP都要修改。一、转移指令转移指令分为无条件转移指令和条件转移指令两种。,2020/6/9,8086/8088宏汇编语言程序设计,分支程序设计,无条件转移指令JMP指令格式:JMP目标JMP指令使程序无条件转移到“目标”处,“目标”通常用标号来表达。例如:JMPTARGETTARGET:.JMP指令的转移可以分为段内转移和段间转移。JMP指令的执行不影响标志寄存器。,2020/6/9,8086/8088宏汇编语言程序设计,分支程序设计,1、段内转移:段内转移时,JMP指令和要转移的目标指令同属一个段。因此,只需要修改IP,而CS保持不变。(1)段内转移直接寻址:JMP指令的操作数部分直接给出目标单元。格式:JMP标号(2)段内转移间接寻址:JMP指令转移的目标地址在某一个通用寄存器中,或在某一个字存储单元中。格式:JMPR/M例如:JMPCX或者JMPWORDPTRBX,2020/6/9,8086/8088宏汇编语言程序设计,分支程序设计,2、段间转移:转移时,是从一个代码段转移到另一个代码段。因此,既需要修改IP,CS也要修改。(1)段间转移直接寻址:JMP指令的操作数部分直接给出目标单元。格式:JMPFARPTR标号(2)段间转移间接寻址:JMP指令转移的目标地址在一个作地址指针的双字单元中。地址指针前两个字节存放目标的偏移量,后两个字节存放目标的段基值。格式:JMPDWORDPTRM例如:JMPDWORDPTRADDRBX或者JMPDWORDPTRBXSI,2020/6/9,8086/8088宏汇编语言程序设计,分支程序设计,二、比较指令CMP指令格式:CMPDEST,SRC比较指令属于减法类操作指令,它在完成两个操作数相减(DEST)-(SRC)后,仅把减法运算的某些结果特征记录在标记寄存器的相应标志位上:OF、SF、ZF、AF、PF、CF,而不保留差的结果。比较指令主要用于判定两个操作数的大小。如ZF1,表示(DEST)(SRC)对于无符号数,如CF0,表示(DEST)(SRC),否则(DEST)(SRC),如CFSF,则(DEST)B转移,JAE/JNBCF=0ORZF=1AB转移,JB/JNAECF=1ANDZF=0AB转移,JGE/JNLSF=OFORZF=1AB转移,JL/JNGESFOFANDZF=0A0,0X=0,1X0,X0?,X=0?,Y1,Y0,Y1,N,Y,N,Y,NEXT,设X、Y为字节变量,需3个分支,用带符号数条件转移指令判断,CMPX,0;X0?,JGEBIGER;若X0转到BIGER,否则顺序执行,MOVY,1;X0,Y1,JMPNEXT,EQUL:MOVY,0;X=0,Y0,NEXT:,2020/6/9,8086/8088宏汇编语言程序设计,分支程序设计,使用比较/测试分支结构可以实现多分枝程序设计,但是当分支过多,有三个缺陷:(1)繁琐。(2)多次测试将花费大量时间(3)到达不同分支的时间不一。而使用跳转表来实现多路分支则可以避免这些问题。跳转表是一段连续的存储区,根据其内容可以分为分支地址标和转移指令表两种。由此对应两种跳转表法分支程序设计。(1)分支地址标法(2)转移指令表法,2020/6/9,8086/8088宏汇编语言程序设计,分支程序设计,如果程序需要n路分支,每路程序的入口地址分别为SUB1、SUB2、SUBn。把这些转移的入口地址组成一个表,就称为跳转表。在跳转表中每两个字节存放一个入口地址的偏移量。跳转表也可由若干跳转指令组成,这时用无条件转移指令,且每条指令的目标代码长度要一致,否则分支程序的编制将非常麻烦。因此我们在编制程序的时候,通常将分支程序的入口地址存放在跳转表中,来实现多路分支程序。,2020/6/9,8086/8088宏汇编语言程序设计,例:设指定的参数是1、2、3、n,当参数为1时,转移到SUB1,当参数为2时,转移到SUB2,依次类推。这时跳转表里存放地址则是按SUB1、SUB2、SUB3、SUBn的顺序排列的。源程序:TITLEEXAMPLEOFJMP_TABLEDATASEGMENTTABLEDWSUB1,SUB2,SUB3,SUBnPARAMDB3DATAENDSSTACK1SEGMENTPARASTACKDW10HDUP(0)STACK1ENDS,2020/6/9,8086/8088宏汇编语言程序设计,COSEGSEGMENTASSUMECS:COSEG,DS:DATA,SS:STACK1BEGIN:MOVAX,DATAMOVDS,AXMOVAL,PARAMXORAH,AHDECALSHLAL,1MOVBX,OFFSETTABLEADDBX,AXJMPBXSUB1:JMPEND0,2020/6/9,8086/8088宏汇编语言程序设计,SUB2:JMPEND0SUB3:JMPEND0SUBn:END0:MOVAH,4CHINT21HCOSEGENDSENDBEGIN,2020/6/9,8086/8088宏汇编语言程序设计,5.4循环程序设计,一、循环指令8086/8088指令系统有4种循环指令,能够灵活实现各种循环。1、LOOP指令指令格式:LOOP目标执行LOOP指令,在进行循环次数的计数,即执行(CX)=(CX)-1,若(CX)0,则转移到目标单元,否则顺序执行。例数据段的ARY数组中存放有10个无符号数,试找出其中最大者送入MAX单元。要求使用循环指令实现,试编制源程序。,2020/6/9,8086/8088宏汇编语言程序设计,DATASEGMENTARYDB17,5,40,0,67,12,34,78,32,10MAXDB?DATAENDSMOVSI,OFFSETARY;SI指向ARY的第一个元素MOVCX,9;CX作循环次数计数MOVAL,SILOP:INCSICMPAL,SIJAEBIGERMOVAL,SIBIGER:LOOPLOPMOVMAX,AL,2020/6/9,8086/8088宏汇编语言程序设计,循环指令,2、LOOPE/LOOPZ指令指令格式:LOOPE/LOOPZ目标执行LOOPE/LOOPZ指令,在进行循环次数的计数,即执行(CX)=(CX)-1,若(CX)0且ZF1,则转移到目标单元,否则顺序执行。例:编写一程序,在一数组中查找第一非0数,并将其在数组中的偏移量(1n)送入INDEX单元中。若未找到,则将INDEX单元置为全1。源程序如下:,2020/6/9,8086/8088宏汇编语言程序设计,TITLECHECKNO_ZERONUMBERDATASEGMENTARRAYDB0,0,0,0,3,5,0,7,0AHLENGEQU$-ARRAYINDEXDB?DATAENDSSTACK1SEGMENTPARASTACKDW20HDUP(0)STACK1ENDSCODESEGMENTASSUMECS:CODE,DS:DATA,SS:STACK1START:MOVAX,DATAMOVDS,AX,2020/6/9,8086/8088宏汇编语言程序设计,MOVCX,LENG;数组长度送入CXMOVBX,-1;设地址指针初值NEXT:INCBXCMPARRAYBX,0;该数值是否为0LOOPENEXT;是0且计数不为0,继续查找JNZFOUND;找到非0数,转FOUNDMOVBL,0FFH;未找到非0数FOUND:MOVINDEX,BL;存结果MOVAH,4CHINT21HCODEENDSENDSTART,2020/6/9,8086/8088宏汇编语言程序设计,循环指令,3、LOOPNE/LOOPNZ指令格式:LOOPNE/LOOPNZ目标执行LOONPE/LOOPNZ指令,在进行循环次数的计数,即执行(CX)=(CX)-1,若(CX)0且ZF0,则转移到目标单元,否则顺序执行。例:编制一程序,求两个数组对应的数据之和,并把和存入新数组SUM中。计算一直进行到两数之和为零或者数组结束。将新数组的长度存于LEN单元中。,2020/6/9,8086/8088宏汇编语言程序设计,TITLEARRAYSUMDATASEGMENTARRAY1DB2,5,0,3,-4,5,0,0AH,0FFHARRAY2DB3,5,4,-2,0,8,3,-0AH,20HCOUNTDB$-ARRAY2LENDB?SUMDB20HDUP(0)STACK1SEGMENTPARASTACKDW20HDUP(0)STACK1ENDSCOSEGSEGMENTASSUMECS:COSEG,DS:DATA,SS:STACK1,2020/6/9,8086/8088宏汇编语言程序设计,START:MOVAX,DATAMOVDS,AXMOVBX,-1;初始化地址指针MOVCX,0MOVCL,COUNT;初始化数组长度NOZERO:INCBXMOVAL,ARRAY1BXADDAL,ARRAY2BXMOVSUMBX,ALLOOPNENOZERO;CX0且ZF0继续循环INCBLMOVLEN,BLMOVAH,4CHINT21HCOSEGENDSENDSTART,2020/6/9,8086/8088宏汇编语言程序设计,循环指令,指令格式:JCXZ目标地址指令功能:测试CX的内容是否为0,如果(CX)=0,则转移到目标处执行,否则顺序执行。JCXZ指令用于在循环前测试循环次数,因为如果循环初始值为0,将会产生次数非常大的循环,这样就不应去执行此循环了。JCXZ指令与其它循环指令的区别是:JCXZ指令没有将CX寄存器内容减1的功能。程序中使用JCXZ指令的格式:MOVCX,COUNTJCXZNEXTLOP:LOOPLOPNEXT:,2020/6/9,8086/8088宏汇编语言程序设计,循环程序的结构,循环程序通常由5部分组成:1、初始化部分建立循环初始值。如初始化地址指针、计数器及其他循环参数的起始值。2、工作部分在循环过程中做具体事情,完成若干操作,是循环程序的主要部分。工作部分根据具体情况可以是一个顺序程序、分支程序或者循环程序。如果工作部分是另外一个循环程序,则叫做多重循环。,2020/6/9,8086/8088宏汇编语言程序设计,循环程序的结构,3、修改部分为执行下一个循环而修改某些参数。如修改地址指针,其他循环参数等。4、控制部分判断循环结束条件是否成立。判断方法通常有两种:(1)用计数器控制循环:循环进行完预定次数后结束循环。(2)用条件控制循环:根据循环终止的条件来控制循环结束。5、结束处理部分对循环结束进行适当处理,如存储结果。这部分在有些循环程序不是必需的。,2020/6/9,8086/8088宏汇编语言程序设计,循环程序的结构,循环程序有两种结构,一种是先执行循环体然后再判断循环条件,另一种是先判断循环条件,满足条件才执行循环体。先循环再判断就是指执行完初始化部分后,接着执行工作部分和修改部分,然后再执行控制部分进行循环条件的判断。这种循环结构至少能完成一次循环体的执行过程。(P95图5.11)先判断再循环就是指在执行完初始化部分后就执行控制部分进行循环条件的判断,如果循环终止条件成立就不执行工作部分和控制部分,转入结束处理部分。这种循环结构可能一次也不执行循环体。(P95图5.12),2020/6/9,8086/8088宏汇编语言程序设计,循环程序的结构,通常我们有两种方法判断循环结束条件是否成立:用计数器控制循环和用条件控制循环。1、用计数器控制循环用计数器控制循环的方法直观、方便、易于程序设计。如果循环次数已知我们就可以使用这种方法设计循环程序。然后大部分时候,我们在编制程序的时候并不能确切知道循环次数,但是知道循环次数是前面运算或操作的结果或者被存放某内存单元中。因此,在进入循环前进行初始化工作的时候就可以获得循环次数。凡是在执行循环前已知道循环次数的,都称为循环次数已知。,2020/6/9,8086/8088宏汇编语言程序设计,例:试编制已程序,统计DA数据区中0、正数、负数的个数并将数值存放在DA数据区后面的连续3个字节单元中。问题分析:循环次数CX为DA数据区内字数据的个数;分别用AH,AL,BL存放0、正数和负数的个数,将其初始化为0;将DA中的数据分别跟0比较判断出0、正数和负数,将对应的计数器加一。流程图:P96图5.13,循环程序的结构,2020/6/9,8086/8088宏汇编语言程序设计,源程序:TITLESTATISTICSDATASEGMENTDADW-1,0,8,-4,-5,9,0,7,9,34,-5,0,45CUNTDB?;存放正数的个数DB?;存放0的个数DB?;存放负数的个数DATAENDSSTACK1SEGMENTPARASTACKDW10DUP(0)STACK1ENDS,2020/6/9,8086/8088宏汇编语言程序设计,CODESEGMENTASSUMECS:CODE,DS:DATA,SS:STACK1START:MOVAX,DATAMOVDS,AXMOVAX,0;初始化统计个数计数器MOVBX,0LEASI,DAMOVCX,CUNT-DASHRCX,1LOP:CMPWORDPRTSI,0JZZERO;等于0JNSPLUS;大于0,2020/6/9,8086/8088宏汇编语言程序设计,INCBL;负数个数加1JMPNEXTZERO:INCAH;JMPNEXTPLUS:INCALNEXT:ADDSI,2LOOPLOPMOVCUNT,ALMOVCUNT+1,AHMOVCUNT+2,BLMOVAH,4CHINT21HCODEENDSENDSTART,2020/6/9,8086/8088宏汇编语言程序设计,循环程序的结构,用计数器控制循环的方法直观、方便、易于程序设计。但要求在执行循环前已知道循环次数的,在有些情况下就不能确定循环的次数。这时候,循环结束是用某些条件来确定的。用条件控制循环时,编制程序主要是寻找控制条件及对控制条件的检测。例如:编制一程序,产生给定数以内的裴波纳契数列,并将数列的数据个数存放在LEN字节单元中。分析:循环结束条件为产生裴波纳契数列数据大于给定数(P97)。,2020/6/9,8086/8088宏汇编语言程序设计,5.5子程序设计,为了能够增强代码的可重用性,在程序中,如果在不同地方需要多次使用某程序段,我们往往单独编制一指令序列。当程序运行时,需要完成此功能时就转移到该指令序列,执行完后又返回到原来位置继续执行。这个单独编制的指令序列就是子程序。转移到子程序就称为调用子程序。调用子程序也是一种转移指令的形式。在8086/8088宏汇编程序中,子程序是以过程的形式表示的。由于程序可以在不同的逻辑段中,因此子程序的调用与返回有段内调用与返回和段间调用与返回两种情况。,2020/6/9,8086/8088宏汇编语言程序设计,子程序设计,子程序的定义:PROCEDURE_NAMEPROCNEAR/FARRETRETPROCEDURE_NAMEENDP,2020/6/9,8086/8088宏汇编语言程序设计,子程序设计,(1)段内调用与返回:调用子程序指令与子程序在同一个段内。因此,这种子程序的调用与返回同段内转移指令一样,仅需修改指令指针IP。(2)段间调用与返回:调用子程序指令与子程序分别在不同的段。因此,这种子程序的调用与返回同段间转移指令一样,需同时修改CS和IP。段内调用和段间调用时,寻找目标地址均有直接寻址和间接寻址两种方式。调用子程序指令和转移指令的区别是,调用子程序指令需要保留“断点”,在子程序结束后返回到原来的断点继续运行。而转移指令则不考虑目标处指令序列运行结束后的去向,无需保留“断点”。,2020/6/9,8086/8088宏汇编语言程序设计,子程序设计,一、调用指令指令格式:CALL过程名执行CALL指令时,首先保留断点于堆栈中,如果是段内调用则只将偏移量压入堆栈中,而段间调用则需将偏移量和段基值都压入堆栈,然后转移到目标单元。CALL指令的执行对标志寄存器无影响。1、段内调用(1)段内直接调用:调用指令CALL后直接书写过程名。例如:CALLPROCA(2)段内间接调用:这种调用方式的子程序起始地址(段内偏移量)在一个通用寄存器或一个字存储单元中。例如:CALLBX或CALLWORDPTR20HBX,2020/6/9,8086/8088宏汇编语言程序设计,子程序设计,2、段间调用(1)段内直接调用:调用指令CALL后直接书写过程名,或用属性修改运算符PTR说明“类型”是FAR。例如:CALLFARPTRPROCB(2)段内间接调用:这种调用方式的子程序起始地址存放在一个4字节组成的地址指针中,两个低字节存放偏移量,两个高字节存放段基值。例如:CALLDWORDPTRADDRBXSI,2020/6/9,8086/8088宏汇编语言程序设计,子程序设计,二、返回指令子程序执行的最后一条指令一点是返回指令(RET),用来返回到调用此子程序的断点处。为了保证从子程序正确的返回,返回指令RET必须与调用时的调用指令一致。段内和段间返回都使用指令RET,但它们的目标代码不同。(1)段内返回,指令编码为C3,执行返回后,从堆栈顶部弹出一个字的内容送入IP中。(2)段间返回,指令编码为CB,执行返回后,从堆栈顶部弹出两个字的内容送入IP和CS中。(3)段内和段间返回指令RET后面可以跟一个立即数n,n总是偶数,表示堆栈弹出返回地址后,再次修改堆栈指针SP的值,SP=SP+n,即把CALL前压入的参数弹出堆栈。,2020/6/9,8086/8088宏汇编语言程序设计,编制子程序的基本要求,返回指令RET的执行不影响标志寄存器。三、编制子程序的基本要求子程序是在程序中多次重复使用的实现一定功能的程序段,因此编制子程序有较高要求,要求子程序的执行时间短,占用内存少,而且要使用方便。1、具有一定的通用性入口参数和出口参数的设计。为了使子程序拥有较好的通用性,在子程序中常常有些允许变化的数据和地址,以便主程序调用前给定,在子程序运行结束时,又会得到一些结果,以供调用程序使用。这就是程序的入口参量和出口参量。编写子程序一个重要的问题就是决定入口参量和出口参量。,2020/6/9,8086/8088宏汇编语言程序设计,编制子程序的基本要求,2、选择适当的参数传递方法(1)使用通用寄存器最简便的方法,但通用寄存器属数量有限。(2)使用指定的存储单元此方法不受参量数量的限制,但使用专门的存储单元,编制调用程序时比较麻烦,特别是这些存储单元与调用程序所用的数据段不在同一段时就更为复杂。(3)使用堆栈这种方法最为灵活,堆栈中的参量通常是存放在存放在断点返回地址的下面。,2020/6/9,8086/8088宏汇编语言程序设计,编制子程序的基本要求,3、注意信息保存在执行子程序前,需要保持主程序中的信息,以便能正确返回主程序。信息保存有两种方法:(1)在主程序中保存子程序中将要使用的一些寄存器的内容。(2)在子程序中保存将要使用的一些寄存器的内容。4、正确使用堆栈在调用子程序时会将断点的返回地址压入堆栈,而执行返回指令时又需要从栈顶弹出断点的返回地址,如果子程序中使用了堆栈,那么在执行RET指令前应该保证SP指向刚进入子程序时的位置。,2020/6/9,8086/8088宏汇编语言程序设计,编制子程序的基本要求,5、编制子程序文件子程序文件应该由两部分组成:文字说明和子程序本身。文字说明部分是为子程序的使用提供方便的,使用户可以无需查看子程序的内部结构和程序就可以正确使用。子程序的文字说明通常包括:(1)子程序名(2)子程序功能描述(3)子程序的入口参数与出口参数(4)使用哪些寄存器和存储单元(5)本子程序是否又调用其他子程序(6)子程序的调用形式、举例,2020/6/9,8086/8088宏汇编语言程序设计,关于子程序的嵌套调用不要求掌握。子程序设计:例:将两个给定的二进制数转换为对应字符ASCII码。问题分析:由于要将两个数转换成ASCII码,因此我们可以用子程序来完成数到其字符ASCII码转换的功能。主程序提供被转换的数和转换后ASCII码的存储区首地址。因此,子程序的入口参量是被转换的数和转换后ASCII码的存储区首地址,没有出口参量。程序流程图:,子程序设计,2020/6/9,8086/8088宏汇编语言程序设计,开始,取出待转换数据给出存放结果首址给出待转换数的位数,调用转换子程序,取出待转换数据给出存放结果首址给出待转换数的位数,调用转换子程序,结束,BINASC,待转换的一位二进制数送AL的第0位,DX=待转换数据DI=存放ASCII码首址CX=转换二进制位数,AL=(AL)01H,AL=(AL)+30H,存ASCII码:(DI)=(AL),修改指针:DI=(DI)+1,计数:CX=(CX)-1,(CX)=0?,返回,N,Y,主程序,子程序,2020/6/9,8086/8088宏汇编语言程序设计,源程序的数据段和堆栈安排如下:DATASEGMENTBIN1DB35HBIN2DW0AB48HASCBUFDB20HDUP(?)DATAENDSSTACK1SEGMENTPARASTACKDW20HDUP(0)STACK1ENDS参数的传递方法有:1、用寄存器传递参量2、用堆栈传递参量3、用堆栈传递参量(参见教材P106),2020/6/9,8086/8088宏汇编语言程序设计,使用寄存器传递参数,在调用子程序前,把要转换的数存放DX中(若数位16,便从高到低地存放),存放ASCII码的首址存放在DI中,转换数的位数存放在AX中。而保持信息则由主程序完成。其代码段为:DATASEGMENTBIN1DB35HBIN2DW0AB48HASCBUFDB20HDUP(?)DATAENDSSTACK1SEGMENTPARASTACKDW20HDUP(0)STACK1ENDSCOSEGSEGMENTASSUMECS:COSEG,DS:DATA,SS:STACK1BEGIN:MOVAX,DATAMOVDS,AX,2020/6/9,8086/8088宏汇编语言程序设计,MOVDX,0MOVDH,BIN1;待转换数存DX中LEADI,ASCBUF;存放ASCII码首址MOVAX,8;待转换二进制位数PUSHDI;保存信息CALLBINASC;调用转换子程序POPDI;恢复信息MOVDX,BIN2;待转换数据存放DX中ADDDI,10H;存放ASCII码首址MOVAX,10H;待转换二进制位数CALLBINASCMOVAH,4CHINT21H,2020/6/9,8086/8088宏汇编语言程序设计,;转换子程序BINASCPROCMOVCX,AXLOP:ROLDX,1;通过不带进位的循环左移取1位二进制数MOVAL,DLANDAL,1;清除AL高字节,保留最低位ADDAL,30HMOVDI,ALINCDILOOPLOPRETBINASCENDPCOSEGENDSENDBEGIN,2020/6/9,8086/8088宏汇编语言程序设计,使用堆栈传递参数,在调用子程序前,已把要转换的数、存放ASCII码的首址和转换的位数压入堆栈。而保持信息则由子程序完成。其代码段为:COSEGSEGMENTASSUMECS:COSEG,DS:DATA,SS:STACK1BEGIN:MOVAX,DATAMOVDS,AXMOVAX,0MOVAL,BIN1PUSHAX;待转换数据压栈MOVAX,8PUSHAX;转换位数压栈LEAAX,ASCBUFPUSHAX;存放ASCII码的首址压栈CALLBINASC;调用转换子程序,2020/6/9,8086/8088宏汇编语言程序设计,MOVAX,BIN2PUSHAXMOVAX,16PUSHAXLEAAX,ASCBUF+10HPUSHAXCALLBINASCMOVAH,4CHINT21HBINASCPROC;转换子程序MOVBP,SP;当前SP送BPPUSHAXPUSHCXPUSHDXPUSHDIMOVDI,BP+2;从堆栈取入口参数MOVCX,BP+4MOVDX,BP+6,2020/6/9,8086/8088宏汇编语言程序设计,CMPCX,8JNETRANSMOVDH,DLTRANS:ROLDX,1MOVAL,DLANDAL,1ADDAL,30HMOVDI,ALINCDILOOPTRANSPOPDIPOPDXPOPCXPOPAXRET6;返回并从堆栈中弹出6个字节BINASCENDPCOSEGENDSENDBEGIN,2020/6/9,8086/8088宏汇编语言程序设计,5.6DOS功能子程序调用,操作系统为程序设计人员提供了许多可直接调用的功能子程序。调用时需使用软中断指令:INTn其中,n为中断调用类型号,其值为000FFH。在使用INT指令前,应将调用的功能号送入AH,有关入口参量送入指定寄存器中;若有出口参量,中断调用返回后,其结果存放在知道的寄存器或存储单元中。DOS功能子程序的调用使用软中断指令“INT21H”。DOS功能子程序共有84个功能子程序。,2020/6/9,8086/8088宏汇编语言程序设计,DOS功能子程序调用,DOS功能子程序的主要功能有:磁盘的读写控制、文件操作、目录操作、内存管理、基本输入输出管理及设置/读出系统日期、时间等。对于DOS功能子程序我们只需按下列步骤调用就可:(1)送入口参量给指定寄存器(2)功能号送入到AH中(3)INT21H而对于DOS功能子程序的具体实现则是由操作系统实现的。,2020/6/9,8086/8088宏汇编语言程序设计,DOS功能子程序调用,1、带显示的键盘输入(1号功能)MOVAH,01HINT21H该功能子程序等待键盘输入,直到按下一个键,把输入字符的ASCII码送入到AL寄存器中,并在屏幕上显示该字符。如果按下的键是CtrlC组合键,则停止程序的运行。如果按下的是TAB制表键,屏幕上光标自动扩展到紧接的8个字符位置后面。1号功能调用,毋需入口参量,出口参量在AL中。,2020/6/9,8086/8088宏汇编语言程序设计,DOS功能子程序调用,2、不带显示的键盘输入(8号功能)该功能调用与1号功能调用基本类同,差异仅在8号功能调用时,键盘输入的字符不在屏幕上显示。调用方法:MOVAH,08HINT21H3、不带显示的键盘字符输入(7号功能)与8号功能调用基本类同,差异仅在7号功能调用,如果按下CtrlC组合键和TAB制表键,程序无反应,继续等待输入。调用方法:MOVAH,07HINT21H,2020/6/9,8086/8088宏汇编语言程序设计,DOS功能子程序调用,4、字符串输入(0A号功能)一次调用接受一串字符,以回车键结束字符输入。调用时,用DS:DX寄存器指向输入缓冲区的段基值:偏移量。在使用本功能调用之前,应该在内存中建立一个输入缓冲区。缓冲区在第一个字节存放它能保存的最大字符数(1255,不能为0),该值由用户程序自己事先设置。在第二个字节存放本次调用时实际输入的字符数(回车键除外),这个数由DOS返回是自动填入。用户输
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年煤炭清洁高效燃烧技术在工业窑炉中的应用研究报告
- 食品冷链物流温控技术在生鲜电商中的应用报告
- 2025年游戏化营销在化妆品行业品牌传播中的策略研究报告
- 好好爱护牙齿的课件
- 好天气与坏天气课件
- 巧克力囊肿MRI课件
- 火汉字课件教学课件
- 崖柏知识与鉴定技术培训课件
- 奔驰威霆保养知识培训课件
- 奔驰售后干货知识培训课件
- 好书推荐手抄报模板
- GB∕T 17794-2021 柔性泡沫橡塑绝热制品
- 空气轴承技术培训教程
- 江西省普通高中学生学籍表高中档案文件
- 中国特色社会主义生态文明建设讲稿
- 上海市建设工程勘察合同(示范文本)
- 机电安装施工界面划分电气
- 起重设备安装工程施工及验收规范
- 硫酸生产工艺计算
- 北部非洲的非金属矿产资源及开发利用概况(二)
- esicm血流动力学共识 课件
评论
0/150
提交评论