微机啊.docx
- 文档编号:9081117
- 上传时间:2023-02-03
- 格式:DOCX
- 页数:27
- 大小:43.94KB
微机啊.docx
《微机啊.docx》由会员分享,可在线阅读,更多相关《微机啊.docx(27页珍藏版)》请在冰豆网上搜索。
微机啊
1.DATASEGMENT
XXDB10DUP(?
);数据自己填写
YYDW?
DATAENDS
CODESEGMENT
ASSUMECS:
CODE,DS:
DATA
START:
MOVAX,DATA
MOVDS,AX
MOVCX,LENGTHXX
LEASI,XX
MOVAL,[SI]
LOOP1:
INCSI ;数组地址加1
CMPAL,[SI]
JNBLOOP2
XCHGAL,[SI];AL中的内容不是最大,交换数据
LOOP2:
LOOPAGAIN
MOVYY,AL
DONE:
MOV AH,4CH
INT21H
CODEENDS
ENDSTART
DSEGSEGMENT
xxDW10,0,20,15,38,236,3000,45912,11111,49128
yyDW0;先用零当最大值
DSEGENDS
CSEGSEGMENT
ASSUMEDS:
DSEG,CS:
CSEG
START:
MOVAX,DSEG
MOVDS,AX
;-------------------------
MOVBX,OFFSETxx
MOVCX,10
;------------------
LOP:
MOVAX,[BX]
CMPAX,yy
JBL2
MOVyy,AX
L2:
INCBX
LOOPLOP
;------------------
MOVAH,4CH
INT21H
;-------------------------
CSEGENDS
ENDSTART
5.6汇编语言程序设计的基本方法
在汇编语言程序中,最常见的形式有顺序程序、分支程序、循环程序和子程序。
这几种程序的设计方法是汇编程序设计的基础。
本节将结合实例详细介绍这些程序的设计技术。
5.6.1顺序程序设计
顺序程序是一种最简单的程序,也称为直线程序,它的执行自始至终按照语句出现的先后顺序进行。
例5.7求两个数的平均值。
这两个数分别放在x单元和y单元中,而平均值放在z单元中。
编制程序如下所示:
DATASEGMENT
xDB95
yDB87
zDB?
DATAENDS
CODESEGMENT
MAINPROCFAR
ASSUMECS:
CODE,DS:
DATA
START:
PUSHDS
MOVAX,0
PUSHAX
MOVAX,DATA;段寄存器DS
MOVDS,AX
MOVAL,x;第一个数送入AL
ADDAL,y;两数相加,结果送AL
MOVAH,0
ADCAH,0;带进位加法,进位送AH
MOVBL,2;除数2送BL
DIVBL;求平均值送AL
MOVz,AL;结果送入z单元
RET
MAINENDP
CODEENDS
ENDSTART
例5.8在内存中自tab开始的16个单元连续存放着0至15的平方值(平方表),任给一个数x(0≤x≤15)在x单元中,如13,查表求x的平方值,并把结果放入y单元中。
根据给出的平方表,分析表的存放规律,可知表的起始地址与数x之和,正是x的平方值所在单元的地址,由此编制程序如下:
DATASEGMENT
tabDB0,1,4,9,16,25,36,49,64,81
DB100,121,144,169,196,225
xDB13
yDB?
DATAENDS
CODESEGMENT
ASSUMECS:
CODE,DS:
DATA
START:
MOVAX,DATA
MOVDS,AX
LEABX,tab
MOVAH,0
MOVAL,x
ADDBX,AX
MOVAL,[BX]
MOVy,AL
MOVAH,4CH
INT21H
CODEENDS
ENDSTART
5.6.2分支程序设计
顺序程序的特点是从程序的第一条指令开始,按顺序执行,直到执行完最后一条指令。
然而,许多实际问题并不能设计成顺序程序,需要根据不同的条件作出不同的处理。
把不同的处理方法编制成各自的处理程序段,运行时由机器根据不同的条件自动作出选择判断,绕过某些指令,仅执行相应的处理程序段。
按这种方式编制的程序,执行的顺序与指令存储的顺序失去了完全的一致性,称之为分支程序。
分支程序是机器利用改变标志位的指令和转移指令来实现的。
转移指令有JMP和Jcc两类。
前者是无条件转移指令,后者是条件转移指令。
JMP无条件转移指令将控制转向其后的目的标号指定的地址。
Jcc条件转移指令跟随在能改变状态标志的指令之后,根据条件决定是否将控制转向其后的目的地址处。
例5.9给定以下符号函数:
任意给定x值,假定为-25,且存放在x单元,函数值y存放在y单元,则根据x的值确定函数y的值。
程序流程图如图5.6所示。
编写程序如下:
DATAXSEGMENT
xDB-25
yDB?
DATAXENDS
CODEXSEGMENT
MAINPROCFAR
ASSUMECS:
CODEX,DS:
DATAX
START:
PUSHDS
MOVAX,0
PUSHAX
MOVAX,DATAX
MOVDS,AX
MOVAL,x;AL←x
CMPAL,0
JGELOOP1;x≥0时转LOOP1
MOVAL,0FFH;否则将-1送入y单元
MOVy,AL
RET
LOOP1:
JELOOP2;x=0时转LOOP2
MOVAL,1;否则将1送入y单元
MOVy,AL
RET
LOOP2:
MOVAL,0;将0送入y单元
MOVy,AL
RET
MAINENDP
CODEXENDS
ENDSTART
例5.10设有首地址为arry的字数组,已按升序排好,数组长度为n(假设n=15),且数据段与附加段占同一段,在该数组中查找数number(假设等于83),若找到它,则从数组中删掉;若找不到,则把它插入正确位置,且变化后的数组长度在DX中。
根据题意程序编写如下:
DATAJSEGMENT
DW?
nDW15
numberDW83
arryDW5,10,17,21,28,32,41,50,56,67,72
DW88,95,125,150
DATAJENDS
CODMASEGMENT
MAINPROCFAR
ASSUMECS:
CODMA,DS:
DATAJ,ES:
DATAJ
START:
PUSHDS
SUBAX,AX
PUSHAX
PUSHES
MOVAX,DATAJ
MOVDS,AX
PUSHDS
POPES
MOVAX,number;待查找的数放入AX
MOVDX,n;初始化DX
MOVCX,n;设置计数器CX
MOVDI,OFFSETarry;arry的有效地址放入DI
CLD;建立方向标志
REPNESCASW;用重复串扫描指令进行查找
JEDELETE
DECDX
MOVSI,DX
ADDSI,DX
TT3:
CMPAX,arry[SI]
JLTT1
MOVarry[SI+2],AX;功能是:
若没有查到,
JMPTT2;则将此数插入正确位置
TT1:
MOVBX,arry[SI]
MOVarry[SI+2],BX
SUBSI,2
JMPTT3
TT2:
ADDDX,2;修改数组长度
JMPFAN
DELETE:
JCXZNEXT
LOOPT:
MOVBX,[DI];此程序段功能是:
若查找到,
MOV[DI-2],BX;则从数组中删除该数
ADDDI,2
LOOPLOOPT
NEXT:
DECDX;修改数组长度
FAN:
POPES
RET
MAINENDP
CODMAENDS
ENDSTART
5.6.3循环程序设计
顺序程序和分支程序中的指令最多只执行一次。
在实际问题中重复地做某些事的情况是很多的,用计算机来做这些事就要重复地执行某些指令。
重复地执行某些指令,最好用循环程序实现。
一.循环程序的结构
一个循环程序通常由以下五个部分组成,如图5.7所示。
1.初始化部分:
建立循环初始值。
如设置地址指针,计数器,其它循环参数的起始值等。
2.工作部分:
在循环过程中所要完成的具体操作,是循环程序的主要部分。
这部分视具体情况而定。
它可以是一个顺序程序、一个分支程序或另一个循环程序。
3.修改部分:
为执行下一个循环而修改某些参数。
如修改地址指针,其它循环参数等。
4.控制部分:
判断循环结束条件是否成立。
通常判断循环是否结束的办法有两种:
·用计数控制循环:
循环是否已进行预定次数(适合已知循环次数的循环);
·用条件控制循环:
循环终止条件是否已成立(适合未知循环次数的循环)。
5.结束处理部分:
对循环结束进行适当处理,如存储结果等。
有的循环程序可以没有这部分。
图5.7(a)给出的循环程序框图是“先执行后判断”的结构,另有一种结构形式是“先判断后执行”的形式,如图5.7(b)所示,这种结构仍由五个部分组成,但是重新安排了中间三个部分的顺序。
从框图可以看出它的最大优点是可以一次也不执行循环,也就是说可以设计为零次循环的程序。
二.循环控制方法
1.用计数控制循环
这种方法直观、方便,易于程序设计。
只要在编制程序时,循环次数已知,就可以使用这种方法设计循环程序。
例5.11从xx单元开始的30个连续单元中存放有30个无符号数,从中找出最大者送入yy单元中。
根据题意,我们把第一个数先送入AL寄存器,将AL中的数与后面的29个数逐个进行比较,如果AL中的数较小,则两数交换位置;如果AL中的数大于等于相比较的数,则两数不交换位置,在比较过程中,AL中始终保持较大的数,比较29次,则最大者必在AL中,最后把AL中的数(最大者)送入yy单元。
这个问题的特点是循环比较的次数是已知的,因此可以用计数器控制循环,程序的流程图如图5.8所示。
程序编写如下:
DATASPSEGMENT
xxDB73,59,61,45,81
DB107,37,25,14,64
DB3,17,9,23,55,97
DB115,78,121,67
DB215,137,99,241
DB36,58,87,100,74,62
yyDB?
DATASPENDS
CODESPSEGMENT
ASSUMECS:
CODESP,DS:
DATASP
MAINPROCFAR
START:
PUSHDS
MOVAX,0
PUSHAX
MOVAX,DATASP
MOVDS,AX
MOVAL,xx
MOVSI,OFFSETxx
MOVCX,29
LOOP1:
INCSI
CMPAL,[SI]
JAELOOP2
XCHGAL,[SI]
LOOP2:
DECCX
JNZLOOP1
MOVyy,AL
RET
MAINENDP
CODESPENDS
ENDSTART
2.用条件控制循环
有些情况无法确定循环次数,但可用某种条件来确定是否结束循环。
这时,编制程序主要是寻找控制条件以及对控制条件的检测。
例5.12从自然数1开始累加,直到累加和大于1000为止,统计被累加的自然数的个数,并把统计的个数送入n单元,把累加和送入sum单元。
根据题意,被累加的自然数的个数事先是未知的,也就是说,循环的次数是未知的,因此不能用计数器方法控制循环。
但题目中给定一个重要条件,即累加和大于1000则停止累加,因此,可以根据这一条件控制循环。
我们用CX寄存器统计自然数的个数,用AX寄存器存放累加和,用BX寄存器存放每次取得的自然数。
程序的流程图如图5.9。
程序编写如下:
DATASSEGMENT
nDW
sumDW
DATASENDS
STACKSEGMENTPARASTACK'STACK'
DW200DUP(?
)
STACKENDS
CODESSEGMENT
MAINPROCFAR
ASSUMECS:
CODES,DS:
DATAS,SS:
STACK
START:
PUSHDS
MOVAX,0
PUSHAX
MOVAX,DATAS
MOVDS,AX
MOVAX,0
MOVBX,0
MOVCX,0
LOOPT:
INCBX
ADDAX,BX
INCCX
CMPAX,1000
JLELOOPT
MOVn,CX
MOVsum,AX
RET
MAINENDP
CODESENDS
ENDSTART
5.6.4子程序设计
一.子程序概念
如果在一个程序中的多处需要用到同一段程序,或者说在一个程序中需要多次执行某一连串的指令时,那么我们可以把这段要执行或这一连串的指令抽取出来,写成一个相对独立的程序段,每当我们想要执行这段程序或这一连串的指令时,就调用这段程序,执行完这段程序后再返回原来调用它的程序。
这样我们每次执行这段程序时,就不必重写这一连串的指令了,这样的程序段称为子程序或过程。
而调用子程序的程序称为主程序或调用程序。
二.子程序的定义
子程序是用过程定义伪指令PROC和ENDP来定义的。
而且还应指出过程的类型属性。
在PROC和ENDP之间是为完成某一特定功能的一连串指令,其最后一条指令是返回指令RET。
过程通常以一个过程名(标号)后跟PROC开始,而以过程名后跟ENDP结束。
过程名PROC[NEAR/FAR]
:
RET
过程名ENDP
其中‘过程名’是子程序入口的符号地址,NEAR或FAR是过程的类型属性,它指出对该过程的调用是段内的调用还是段间调用。
NEAR用于段内调用,而FAR用于段间调用。
过程属性的确定原则:
⒈调用程序和过程若在同一代码段中,则使用NEAR属性;
⒉调用程序和过程若不在同一代码段中,则使用FAR属性;
⒊主程序应定义为FAR属性(使用标准方式返回DOS时)。
因为我们把程序的主过程看作DOS调用的一个子程序,而DOS对主过程的调用和返回都是FAR属性。
另外,过程定义允许嵌套,即在一个过程定义中允许包含多个过程定义。
例5.13调用程序和子程序在同一代码段中。
CODESEGMENT
:
MAINPROCFAR
:
CALLPPP1
:
RET
PPP1PROCNEAR
:
CALLPPP2
:
RET
PPP2PROCNEAR
:
RET
PPP2ENDP
PPP1ENDP
MAINENDP
CODEENDS
在本例中过程定义相当于三层嵌套,即主过程MAIN嵌套子过程PPP1,而子过程PPP1又嵌套子过程PPP2。
因为主过程和两个子过程均在同一代码段,因此,除主过程使用FAR属性外,其它两个子过程均使用NEAR属性。
例5.14调用程序和子程序不在同一代码段。
CODE1SEGMENT
:
CALLRRR
:
CODE1ENDS
CODE2SEGMENT
:
RRRPROCFAR
:
RET
RRRENDP
CODE2ENDS
本例中,因为子程序RRR和调用程序不在同一代码段,因此子程序RRR应定义为FAR属性,这样调用指令CALL和返回指令RET都是FAR属性的。
应当指出,在一个过程中可以有一个以上的RET指令。
这完全是根据需要而设置的。
三.调用程序与子程序之间的参数传递
调用程序在调用子程序时,往往需要向子程序传递一些参数;同样,子程序运行后也经常要把一些结果参数传回给调用程序。
调用程序与子程序之间的这种信息传递称为参数传递。
参数传递有三种主要的方式。
⒈通过寄存器传递参数
这种方式适合于传递参数较少的一些简单程序。
例5.15把一个2位十进制数表示成的压缩型BCD数转换成其对应的二进制数。
在调用子程序前,首先把待转换的压缩型BCD数放在寄存器AL中,然后由主程序传递给子程序BCD_BINARY,子程序结束时把转换的二进制结果传递回调用程序,并保存在VALUE单元中。
在子程序一开始,把标志寄存器及其它在程序中用到的寄存器压入堆栈,但AX寄存器不需要压入和弹出堆栈,因为我们是用AX把一个值传递到子程序中,同时子程序把另一个不同的值放在AX中,而传回给主程序。
程序编写如下:
DATA_BINSEGMENT
BCD_INDB?
;存放BCD值
VALUEDB?
;存放二进制值
DATA_BINENDS
CODESEGMENT
ASSUMECS:
CODE,DS:
DATA_BIN
MAINPROCFAR
START:
PUSHDS
MOVAX,0
PUSHAX
MOVAX,DATA_BIN
MOVDS,AX
MOVAL,BCD_IN
CALLBCD_BINARY
MOVVALUE,AL
RET
MAINENDP
BCD_BINARYPROCNEAR
PUSHF;保存标志寄存器FLAGS
PUSHBX;保存BX和CX
PUSHCX
MOVAH,AL;把BCD数送入AH
ANDAH,0FH;分数和保存BCD数的低位数字
MOVBL,AH
ANDAL,0F0H;分出BCD数的高位数字
MOVCL,04
RORAL,CL;把BCD数高位数字移到低位
MOVBH,0AH;把转换因子送入BH
MULBH;AL中BCD数的高位数字乘以BH中
;的0AH结果在AX中
ADDAL,BL
POPCX;把相乘结果与BCD码的低位数字相
;加最终结果送入AL中
POPBX
POPF;恢复被保护的寄存器
RET
BCD_BINARYENDP
CODEENDS
ENDSTART
⒉通过地址表传递参数地址
这种方式适合于参数较多的情况,但要求事先建立一个用来传送参数的地址。
例5.16对例5.15通过传送参数地址的方法重新编写程序如下:
DATASEGMENT
BCD_INDB?
VALUEDB?
DATAENDS
CODESEGMENT
ASSUMECS:
CODE,DS:
DATA
MAINPROCFAR
START:
PUSHDS
MOVAX,0
PUSHAX
MOVAX,DATA
MOVDS,AX
MOVSI,OFFSETBCD_IN
MOVDI,OFFSETVALUE
CALLBCD_BINARY
MOVVALUE,AL
RET
MIANEMDP
BCD_BINARYPROCNEAR
PUSHF
PUSHBX
PUSHCX
MOVAL,[SI];把BCD_IN单元中的数送入AL
MOVAH,AL
ANDAH,0FH
MOVBL,AH
ANDAL,0F0H
MOVCL,4
RORAL,CL
MOVBH,0AH
MULBH
ADDAL,BL
POPCX
POPBX
POPF
RET
BCD_BINARYENDP
CODEENDS
ENDSTART
⒊通过堆栈传递参数
为了利用堆栈传递参数,必须在主程序中调用子程序之前的地方,把这些参数压入堆栈,然后利用在子程序中的指令从堆栈弹出而取得参数。
同样,要从子程序传递回调用程序的参数也被压入堆栈内,然后由主程序中的指令把这些参数从堆栈中取出。
下面举例说明如何利用堆栈来传递参数。
例5.17试将一个2位十进制数的压缩型BCD码转换成十六进制数,并在屏幕上显示出来。
根据题目的要求,我们利用堆栈传递参数的方法。
首先在主程序中把BCD码压入堆栈,在子程序BCD_BIN中从堆栈中取出这个BCD码,然后先把它转换成二进制数,并将其保存在堆栈。
返回主程序后再将这个二进制数从堆栈中取出,再把它转换成十六进制数,最后把这个十六进制数在屏幕上显示出来。
程序编写如下:
DATAHSEGMENT
BCDMADB?
DATAHENDS
STACKSEGMENTPARASTACK'STACK'
DW100DUP(?
)
TOSLABLE?
WORD
STACKENDS
CODEHSEGMENT
ASSUMECS:
CODEH,DS:
DATAH,SS:
STACK
MAINPROCFAR
START:
MOVAX,STACK
MOVSS,AX
MOVSP,OFFSETTOS
PUSHDS
MOVAX,0
PUSHAX
MOVAX,DATAH
MOVDS,AX
MOVAH,00H
MOVAL,BCDMA
PUSHAX;把BCD码压入堆栈
CALLBCD_BIN;调用子程序把BCD码转化成二进制数
POPAX;把转化后的二进制数弹出送入AX
MOVCH,2
LOOP1:
MOVCL,4
ROLAL,CL
MOVBL,AL
ANDBL,0FH
ADDBL,30H
CMPBL,3AH
JLLOOP2
ADDBL,07H
LOOP2:
MOVDL,BL
MOVAH,02H
INT21H
DECCH
JNZLOOP1
RET
MAINENDP
BCD_BINPROCNEAR
PUSHAX
PUSHF
PUSHBX
PUSHCX
PUSHBP
MOVBP,SP
MOVAX,[BP+12]
MOVAH,AL
ANDAH,0FH
MOVBL,AH
ANDAL,0F0H
MOVCL,4
RORAL,CL
MOVBH,0AH
MULBH
ADDAL,BL
MOV[BP+12],AX
POPBP
POPCX
POPBX
POPF
POPAX
RET
BCD_BINENDP
CODEHENDS
ENDSTART
为了说明本例利用堆栈传递参数的过程,请参看图5.10所示的堆栈图。
利用堆栈传递参数有两个非常重要的问题:
⑴当使用堆栈来传递参数时,有一个应当注意的潜在问题就是堆栈溢出(stackoverflow)。
每当你用堆栈传送参数时,你应当非常清楚,已经把什么东西压入了堆栈内,在子程序中每个地方的堆栈指针是指向哪里,这是非常重要的。
如果搞得不好,很容易混乱和造成堆栈溢出。
所谓堆栈溢出是指堆栈超出了为它开辟的存储空间。
⑵8086/8088有四种形式的RET指令,一般的近程RET指令能把返回地址由堆栈弹入到IP,同时把堆栈指针加2;一般的远程RET指令能由堆栈把返回的IP及CS值弹入到IP及CS,同时把堆栈指针加4,其他二种RET指令形式分别执行相同的功能,但是它们把一个在指令中指定的数字加入堆栈指针,如近程RET6
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 微机