汇编语言第四章 程序设计的基本方法Word格式.docx
《汇编语言第四章 程序设计的基本方法Word格式.docx》由会员分享,可在线阅读,更多相关《汇编语言第四章 程序设计的基本方法Word格式.docx(31页珍藏版)》请在冰点文库上搜索。
两数相加,结果为0,则转移到P2,否则运行P1。
二、无符号数的条件转移
此指令跟在比较指令之后,比较的对象为无符号数。
结果有:
高于、高于等于、低于、低于等于。
Above:
高于,below:
低于,equal:
等于。
1.JA/JNBE
JA表示:
高于则转移。
JNBE表示:
不低于或等于转移。
测试条件:
CF∨ZF=0。
(分析:
a-b≥0,此时CF=0;
a-b≠0,此时ZF=0。
)
2.JAE/JNB
JAE表示:
高于等于则转移。
JNB表示:
不低于则转移。
CF=0或ZF=1。
3.JB/JNAE
JB表示:
低于则转移。
JNAE表示:
不高于且不等于则转移。
CF=1。
4.JBE/JNA
JBE表示:
低于等于则转移。
JNA表示:
不高于则转移。
CF∨ZF=1。
三、带符号数条件转移
比较结果分为4种:
大于、大于等于、小于、小于等于。
Great:
大于,Little:
小于,Equal:
1.JG/JNLE
JG表示:
两数相比,大于,则转移。
JNLE表示:
两数相比,不小于且不等于,则转移。
(SF
OF)∨ZF=0。
2.JGE/JNL
JGE表示:
两数相比,大于等于,则转移。
JNL表示:
两数相比,不小于,则转移。
SF
OF=0。
3.JL/JNGE
JL表示:
两数相比,小于,则转移。
JNGE表示:
两数相比,不大于且不等于,则转移。
OF=1。
4.JLE/JNG
JLE表示:
两数相比,小于等于,则转移。
JNG表示:
两数相比,不大于,则转移。
OF)∨ZF=1。
使用转移指令时应注意:
注意:
●CMP比较指令本身无法分别有、无符号数,它比较的是否有符号,由后面的转移指令确定。
例:
MOVAL,-40H
CMPAL,50H
JGL1;
比较的是有符号数,(-40H)<50H,不转移
…
L1:
若将JG换为JA,就变成无符号数了,此时,(AL)=(-40H)补=C0H>50H,转移。
●转移指令的转移范围-128~127。
4.1.2无条件转移指令
无条件地转移到目的地址执行。
可以分为两类:
段内、段间。
1.段内直接近转移
格式:
JMPNEARPTR标号;
(IP)+16位偏移量→IP。
转移范围32K。
2.段内间接转移
JMPWORDPTROPD;
(OPD)→IP。
JMPWORDPTR[BX+TABLE]
作用:
([BX+TABLE])→IP,偏移地址[BX+TABLE]所指单元的内容送IP。
假定:
(DS)=2000H,(BX)=1256H,TABLE=20A1H,(232F7H)=3280H。
则:
PA=(DS)左移4位+(BX)+TABLE=232F7H
执行后:
(IP)=3280H
3.段间直接转移
JMPFARPTR标号;
标号的偏移地址→IP,标号所在段地址→CS。
4.段间间接转移
JMPDWORDPTROPD
(OPD)→IP,(OPD+2)→CS。
JMPDWORDPTR[BX]
([BX])→IP,([BX]+2)→CS。
注意是偏移地址[BX]所指内容。
4.2分支程序设计
计算机根据不同情况自动作出判断,有选择地执行相应处理程序。
一、两种结构形式
结构特点:
运行方向是向前的,条件确定,只能执行分支中的一个。
二、程序设计方法
程序分支一般用条件转移指令产生,不同条件是通过FLAGS的标志状态反映出来。
转移指令不影响条件码特性,也就是可以连续使用转移指令,使程序产生多个分支。
CMPARRAY[BX],0
JLEL1;
小于等于0,转移到L1
…;
分支1
JLNEXT;
小于0,转移到NEXT
…;
分支2
NEXT:
…
4.2.1举例
例1.比较数组BUF中的三个16位补码,若三个数都不相等则显示0,有两个相等则显示1,都相等则显示2。
分析:
假定三个数为a、b、c,D为比较结果。
我们可以画出流程图:
例2.设A、B、C三个单元存放着三个数,若三个数都不为0,则求三数之和放在D单元内,若其中有一个为0,则将另外两个也清0。
此题为判断A、B、C三个数是否为0的分支程序。
存贮单元的分配,题目已告诉,变量名分别为A、B、C、D,都为字变量。
根据要求画出流程图:
分支程序设计应注意:
●选择合适的转移指令
CMPAX,1
JLL1
JL为有符号转移指令,(AX)<1则转移。
若JL换为JB,则为无符号转移指令,该转移的反而不转移。
●为每个分支安排出口
实现(AL)≥0,′+′→DL;
(AL)<0,′-′→DL;
CMPAL,0
JGEL1;
有符号比较,大于等于转L1
MOVDL,‘-’
JMPEXIT;
若无此句,无论AL为何,DL=‘+’
MOVDL,‘+’
EXIT:
…
●将分支中的公共部分尽量放到分之前或分支后,使程序尽量短。
●按流程图编程
分支先后次序应尽量与问题提出的先后次序一致。
●假定各种输入,调试分支程序。
4.3循环程序设计
4.3.1循环程序的结构
循环程序有两种结构形式:
上述两种结构的循环程序,由三个部分组成:
(1)设置循环的初始状态
置循环次数计数值以及循环体正常运行的初始状态值。
(2)循环体
由循环的工作部分和修改部分组成。
其中,工作部分完成程序功能;
修改部分保证循环时,参加执行运行的信息发生规律性变化。
(3)循环控制部分
保证循环程序按规定的次数或特定条件正常循环。
4.3.2循环控制方法
一、计数控制
用于循环次数已知的情况。
1.正计数法
计数值开始为0,每次循环加1,直到加到n为止。
MOVCX,0;
初始化
循环体
INCCX
CMPCX,n;
控制部分
JNEL1
2.倒计数法
分两种情况:
二、条件控制
循环次数事先不知道。
求AX中1的个数。
一般方法,逐位比较。
MOVBL,0;
BL中存放1的个数
MOVCL,16
SALAX,1;
算术左移,b15→CF
JNCL2
INCBL;
CF=1,(BL)+1→CL
L2:
DECCL
JNZL1
上述方法必须循环16次。
MOVCL,0;
CL中存放1的个数
L:
ANDAX,AX;
产生条件
JZEXIT
SALAX,1;
算术左移,b15→CF
JNCL
INCCL;
CF=1,(CL)+1→CL
JMPL
第二种方法不用循环16次就可以求得1的个数。
三、循环转移指令
1.LOOP标号
(CX/ECX)−1→CX/ECX
若(CX/ECX)不为0,则转标号处执行。
基本等价于:
DECCX/ECX
JNZ标号
LOOP指令对标志位无影响!
2.LOOPE/LOOPZ标号
若(CX/ECX)不为0,且ZF=1,则转标号处执行。
等于或为0循环转移指令,本指令对标志位无影响。
MOVCX,10
MOVBX,OFFSETBUF-1
L3:
INCBX
CMPBYTEPTR[BX],0
LOOPEL3
3.LOOPNE/LOOPNZ标号
若CX/ECX)≠0,且ZF=0,则转标号处执行
4.JCXZ标号/JECXZ标号
若(CX/ECX)为0,则转标号处执行。
先判断,后执行循环体时,可用此语句,标号为循环结束处
4.3.3单重循环程序设计
循环体内不再包含循环结构。
1.循环次数已知
对于循环次数已知的情况,通常采用计数控制方法实现循环。
例1:
将BUF中定义的16位二进制数用十六进制数的形式显示在屏幕上。
16位二进制数,每4位一组在屏幕上显示。
用循环结构可以完成,每一个循环显示一个十六进制数,因此,循环次数已知,为4。
循环中包含十六进制数与ASCII码字符的转换。
流程:
2.最大循环次数未知
用条件来控制循环。
将字变量Y中1的个数存入COUNT单元中。
用移位的方法,将每位数移到最高位,如果Y=0就结束;
如果为负数,则表示最高位为1。
流程图:
4.3.4多重循环程序设计
循环体内还套有循环。
设计原则:
由外向里逐层设计,分别考虑各层控制条件。
以BUF为首址的字节存贮区,存放着n个无符号数,请将数组按从小到大排序。
对这类问题采用逐一比较算法。
从第一个数开始,依次对相邻的两个数进行比较,若次序不对(由小到大),则两数互换位置,否则不作任何操作。
序号
数
第1遍
第2遍
第3遍
第4遍
1
8
3
2
5
4
7
比较次数:
(假定n个数)
第1遍:
n-1次比较,第1小数到位置1;
第2遍:
n-2次比较,第2小数到位置2;
第i遍:
n-i次比较,第i小数到位置i;
上述的5个数,4遍就排好了。
因此n个数,最多n-1遍就可以排好。
有规律:
第1遍找到第1小的数,放到第1单元;
第2遍找到第2小的数,放到第2单元;
第i遍找到第i小的数,放到第i单元。
最多的遍数为n-1。
设i表示遍数,最多为n-1。
将i和j用寄存器表示:
i=SI,初值为1;
j=DI,初值为i+1。
AL用来存放Xi。
数组X1、X2、…Xn,第i个数在BUF+i–1处。
综合上两个框图:
●外循环重复了n-1次;
●判断转移语句用的是无符号数转移指令;
●若要按从大到小排序,则只改变:
JBENEXT为JAENEXT。
4.4堆栈
堆栈:
主存中的一片数据存贮区。
为什么要用堆栈?
程序中经常用到子程序或处理中断,此时,主程序需要把子程序或中断程序将用到的寄存器内容保护起来,以便子程序或中断返回后,主程序能够从调用点或中断点处继续执行。
几个概念:
●压入:
数据进栈
●弹出:
数据出栈
●栈底:
堆栈的固定端
●栈顶:
栈指针指示的最后存入数据的单元
堆栈中数据的存取原则:
先进后出
例如:
●一端固定,一端活动
●存取“先进后出”
●只能是字单元
●最大64K
●SP栈顶指针
●SP由高地址向低地址移动
1.进栈指令
PUSHOPS
OPS:
寄存器、段寄存器、存储器
将OPS的字数据压入堆栈。
进栈活动:
(1)(SP)-2→SP
(2)(AX)→[SP]
2.出栈指令
POPOPD
OPD:
寄存器、段寄存器(除CS)、存储器
将栈顶元素弹出到某一寄存器(OPD)。
出栈活动:
(1)([SP])→BX
(2)(SP)+2→SP
例如:
假定(AX)=1234H,(BX)=5678H,(CX)=9ABCH
执行:
PUSHAX
PUSHBX
PUSHCX
POPDX
POPAX
结果:
(DX)=9ABCH
(AX)=5678H
(BX)=5678H
(CX)=9ABCH
3.8个16位寄存器进出栈指令
PUSHA
将8个16位寄存器按AX、CX、DX、BX、SP、BP、SI、DI顺序入栈
POPA
将8个16位寄存器按相反顺序出栈
4.8个32位寄存器进出栈指令
PUSHAD
将8个16位寄存器按EAX、ECX、EDX、EBX、ESP、EBP、ESI、EDI顺序入栈
POPAD
将8个32位寄存器按相反顺序出栈
4.5子程序设计
子程序又称为过程,相当于高级语言中的过程和函数。
4.5.1子程序的概念
一个程序中常常有类似的程序段,这些程序段的功能和结构相同,只是某些变量的赋值不同,此时把这些程序段写成子程序的形式,以便需要时调用它。
子程序的特点:
(1)分类
●用户自定义的子程序;
●系统子程序,作为系统软件的一部分供用户调用。
(2)与主程序的关系
是调用关系,调用之后又回到调用处的下一条指令。
(3)子程序是模块化编程的重要手段。
本节主要解决编制、调用、返回、参数传递等问题。
4.5.2子程序的调用和返回
一、调用指令CALL
调用范围:
段内:
属性定义为NEAR,调用寻址方式为直接。
段外:
属性定义为FAR,调用寻址方式为间接。
1.段内直接
CALL过程名
(IP)→↓(SP),目的地址EA→IP。
不保存CS到堆栈中。
2.段间直接
CALLFARPTR过程名
(CS)→↓(SP),(IP)→↓(SP);
目的地址EA→IP,目的地址的段首址→CS。
3.段内间接
CALLWORDPTROPD;
(IP)→↓(SP),(OPD)→(IP);
MOVBX,OFFSETB
CALLWORDPTR[BX]
SUB1PROC
B:
MOVAX,1
RET
SUB1ENDP
4.段间间接
CALLDWORDPTROPD;
当前(CS)→↓(SP),(IP)→↓(SP);
改变为(OPD+2)→CS,(OPD)→IP。
二、返回指令RET
返回到调用指令的下一条指令处继续执行。
RET
RETn
具体功能:
对段间返回↑(SP)→IP,↑(SP)→CS。
对段内返回↑(SP)→IP。
●CALL和RET不影响标志位。
●对于RETn表示返回时,清除堆栈中栈顶的n个字。
4.5.3子程序定义格式及现场保护方法
一、定义格式
子程序名PROCNEAR或FAR
子程序名ENDP
二、现场保护与恢复
调用子程序时,有可能破坏原来寄存器的内容,因此,必须保护、恢复现场。
子程序用到BX、AX寄存器的保护与恢复。
APROC
PUSHBX
PUSHAX
子程序
POPBX
AENDP
4.5.4主程序与子程序的参数传递
参数传递:
主程序为子程序提供入口参数,子程序返回结果给主程序。
一、寄存器法
利用寄存器传送入口、出口参数,适合于参数少的情况。
该方法较简单,就象功能调用入口参数一样。
二、约定单元法
入、出口参数在事先约定的存贮单元中。
适合于参数多的情况。
三、堆栈法
利用堆栈传递参数。
缺点是进出栈多,容易出错。
将堆栈中的两元素相加。
入口为栈顶和次栈顶的两个元素。
4.5.5子程序及调用举例
关于十进制到十六进制的转换。
从键盘输入一个十进制数,然后把该数以十六进制形式显示在屏幕上。
(1)用子程序DECIBIN实现从键盘上取十进制数并转换为二进制。
(2)用子程序BINIHEX把二进制数以十六进制数的形式在屏上显示。
(3)用CRLF子程序取得回车换行效果。
参数传递通过BX完成。
程序运行后,输入:
234↙,在另外一行显示:
EA。
4.5.6子程序的嵌套
子程序中又调用另外一个子程序叫做子程序嵌套。
嵌套的层次不限。
嵌套的层次叫深度。
●子程序中的CALL和RET应正确使用。
●在寄存器的保护、恢复时,避免层次之间因寄存器冲突而出错。
在数据区中有10个不同信息,编号为0~9,每个信息包括30个字符。
编程实现:
从键盘接收0~9之间的一个编号,然后显示对应编号的信息。
将10个信息组成一个信息表,根据输入的编号,查表显示对应内容,显示时,调用子程序DISPLAY,显示字符也调用一个子程序DISPCHAR。
第二次上机
一、目的
掌握分支、循环程序设计。
二、题目
以十进制形式输出有符号字数组BUF中每个元素的值:
负数前面需要输出符号,正数前面不需要符号。
各个值之间以空格隔开。
第三次上机
掌握子程序设计。
1.已知array1字数组中存放着n个无符号数。
编写子程序,分别求这n个数的平均值、最大值、最小值,并输出这n个数以及所求结果。
2.用模块化编程实现,将主程序放在一个模块中;
将平均值、最大值、最小值函数放在一个模块中;
将显示输出放在另一个模式中。
3.选做:
用堆栈法传递参数。