1、3-1,第三章 汇编语言程序设计,3.2 伪指令语句,3.3 汇编语言程序设计入门,3.1 汇编语言的基本语法,3-2,3.1 汇编语言的基本语法,3.1.1 汇编语言源程序结构3.1.2 汇编语言的语句格式3.1.3 汇编语言的数据3.1.4 表达式与运算符,3-3,3.1.1 汇编语言源程序结构,80X86/Pentium系列MPU汇编语言都是以逻辑段为基础,按段的概念来组织代码和数据的。因此,源程序结构与逻辑段的定义方法密切相关,而宏汇编语言MASM 5.0以上的版本中,逻辑段既可用完整段定义,又可用简化段定义。,3-4,1. 标准的单模块源程序框架,.586DATA SEGMENT U
2、SE16/USE32 ;定义数据段 ;数据定义伪指令序列DATA ENDSSTACK SEGMENT USE16/USE32 STACK ;定义堆栈段 ;数据定义伪指令序列STACK ENDSCODE SEGMENT USE16/USE32 ;定义代码段ASSUME CS:CODE,SS:STACK,DS:DATA,ES:DATASTART: MOV AX,DATA ;取数据段基址MOV DS,AX ;建立DS的可寻址性MOV ES,AX ;建立ES段的可寻址性 ;核心程序段MOV AH,4CH ;返回DOS操作系统INT 21HCODE ENDSEND START, 一个源程序由若干逻辑段组
3、成。一般一个源程序具有数据段、附加数据段、堆栈段和代码段;但只有代码段是必不可少的。,3.1.1 汇编语言源程序结构,3-5,3.1.1 汇编语言源程序结构,(1) 使用DOS的4CH号功能调用这种方法是在代码段结束前加调用语句:MOV AH,4CH ;功能号4CHAHINT 21H ;中断调用,(2) 使用20H号软功能调用调用方式是在代码段结束前加调用语句:INT 20H,(3) 使用DOS的0号功能调用调用方式是在代码段结束前加调用语句:MOV AH,0INT 21H,2.返回DOS状态的方法,3-6,(4) 将主程序定义为远过程,也称为“标准序”方法。这种方法是在代码段开始处按下述方式
4、定义主程序: CODE SEGMENT ASSUME 主过程名 PROC FARPUSH DS SUB AX,AX ;标准序PUSH AXRET 主过程名 ENDPEND 主过程名,3.1.1 汇编语言源程序结构,3-7,3.1.2 汇编语言的语句格式,1. 语句种类,指令语句是可执行语句,由硬件(CPU)完成其功能,汇编时产生目标代码 。,伪指令语句不可执行语句,其功能由相应软件完成,不产生目标代码。,宏指令语句用户定义的新指令,汇编时产生相应的目标代码。,3-8,3.1.2 汇编语言的语句格式,指令语句:标号: 助记符 操作数 ;注释 伪指令语句:名字 定义符 操作数 ;注释,标号和名字分
5、别是给指令单元和伪指令起的符号名称,统称为标识符。(注意组成的语法规则),助记符和定义符分别用于规定指令语句的操作性质和伪指令语句的伪操作功能,统称操作符。,2. 语句格式,3-9,操作数,3.1.2 汇编语言的语句格式,操作数允许有多个,这时各操作数之间要用逗号“,”隔开。,伪指令语句中操作数的格式和含义则随伪操作命令不同而不同,有时是常量或数值表达式,有时是一般意义的符号 (如变量名、标号名、常数符号等),有时是具有特殊意义的符号(如指令助记符、寄存器名等)。,指令语句中的操作数提供该指令的操作对象,并说明要处理的数据存放在什么位置以及如何访问它,它可以是常量操作数、寄存器操作数、存储器操
6、作数和表达式。,3-10,3.1.3 汇编语言的数据,汇编语言中使用的数据有常数、变量和标号。,1. 常数常数是指那些在汇编过程中已有确定数值的量,分为数值常数和字符串常数两类。主要用作:, 指令语句中的立即操作数, 基址、变址或基址加变址寻址中的位移量, 伪指令语句中用于给变量赋初值,3-11,3.1.3 汇编语言的数据,标号是指令的符号化地址,一定在代码段,而变量是数据的符号化地址,一般在数据段,有时也可在代码段定义。,变量与标号有三个共同属性:,段基址:所在段的起始地址(SEG),偏移值:相对于段基址的位移量(OFFSET),类型:所占字节数(TYPE),2. 变量与标号,3-12,3.
7、1.3 汇编语言的数据,(1) 标号可以用作转移控制类指令的操作数,但变量不能。,(2) 变量可以用作基址、变址或基址加变址寻址的位移量,但标号不能。,变量与标号区别,3-13,例3.1 假设VAR1和VAR2为字变量,LAB为程序中的一个标号,判断下列指令是否正确,若错误请指出错误之处:, ADD VAR1,VAR2 SUB AL,VAR1 JNZ VAR1 JMP LABSI JMP NEAR LAB MOV AX,VAR1BX JMP VAR2BX,3.1.3 汇编语言的数据,错,不允许存储器变量间直接传数,错,源与目的操作数类型不一致,错,变量不能用作条件转移指令的操作数,错,标号不能
8、用作变址寻址的位移量,错,缺PTR运算符,正确,正确,3-14,3.1.4 表达式与运算符,表达式由运算符和运算对象组成。,3-15,数值表达式指在汇编过程中能够由汇编程序计算出数值的表达式。可作为指令中的立即操作数和数据区中的初值使用。例如:MOV BX,0FFF0H AND 0B234HMOV AL,4CH EQ 2MOV AH,4CH GT 1MOV AX,SEG LABLE,3.1.4 表达式与运算符,表达式是汇编语句操作数的基本形式,分为数值表达式和地址表达式。,3-16,3.1.4 表达式与运算符,地址表达式其值表示存储器地址,一般都是段内的偏移地址。与变量一样,地址表达式也具有段
9、值、偏移值和类型属性。地址表达式主要用来表示指令语句中的操作数,例如:MOV AX,BASEEAXEBXJMP BASEEAXLEA BX,BASE+12,3-17,3.2.1 方式选择伪指令 3.2.2 逻辑段定义伪指令 3.2.3 数据伪指令语句 3.2.4 模块定义伪指令 3.2.5 过程与宏定义伪指令 3.2.6 结构定义伪指令,3.2 伪指令语句,3-18,3.2.1 方式选择伪指令,方式选择伪指令用于通知汇编程序,当前的源程序指令是哪一种CPU指令,经过汇编链接之后生成的目标程序在哪一种CPU机型上运行。不属于选定CPU的指令均为非法指令。所以,方式选择伪指令本质上也就是指令集选择
10、伪指令。通常,方式选择伪指令放在程序的头部,作为源程序的第一条语句。缺省时默认8086指令集。,3-19,3.3.2 逻辑段定义伪指令,1. 完整段定义伪指令,80X86/Pentium 系列微处理器汇编语言有两种逻辑段定义方法:完整段和简化段定义,采用完整段定义伪指令可具体控制汇编程序(MASM)和链接程序(LINK)在内存中组织代码和数据的方式。主要包括段定义语句和段寄存器说明语句。,3-20,3.3.2 逻辑段定义伪指令, 格式:段名 SEGMENT 定位类型,组合类型,字长选择,类别段体 ;由指令、伪指令和宏指令语句组成 段名 ENDS, 段定义语句, 说明:(1) SEGMENT/E
11、NDS是一对段定义语句,一个逻辑段从SEGMENT语句开始,到ENDS语句结束。,(2) 段名是用户定义的段的标识符,用于指明段的基址。,(3) 4个可选参数用于为源程序的汇编、连接提供必要的信息,特别是模块化程序,各个模块如何定位,彼此之间如何连接,将较多地涉及到定位类型和组合类型的选择。,3-21,3.3.2 逻辑段定义伪指令, 举例:,模块2(从模块): DSEG SEGMENT COMMONARRAY_B DW 200 DUP(?) DSEG ENDS SSEG SEGMENT STACKDW 50 DUP(?) SSEG ENDS CSEG SEGMENT PUBLIC CSEG E
12、NDSEND,模块1(主模块): DSEG SEGMENT COMMONARRAY_A DW 100 DUP(?) DSEG ENDS SSEG SEGMENT STACKDW 50 DUP(?) SSEG ENDS CSEG SEGMENT PUBLICASSUME CS:CSEG,DS:DSEG,SS:SSEG START: MOV AX,DSEGMOV DS,AX CSEG ENDSEND START,3-22, 段寄存器说明语句,格式:ASSUME 段寄存器:段名,段寄存器:段名,,功能: 说明源程序中定义的段由那个段寄存器去寻址。,说明: CS只能用于包含有程序的段,反之含有程序的段
13、也只能以CS作为段寄存器。SS也一样,只能与堆栈段对应。, CS所对应的段名必须在该语句之前有定义。, 该语句是说明性语句。,3.3.2 逻辑段定义伪指令,3-23,简化段有利于实现汇编语言程序模块与Microsoft高级语言程序模块的连接,它可以由操作系统自动安排段序,自动保证名字定义的一致性。但是命令文件(.COM)的编程不能使用简化段定义。, 段次序语句(DOSSEG) 内存模式语句(.MODEL) 段语句,简化段定义有三种语句:,3.3.2 逻辑段定义伪指令,2. 简化段定义伪指令,3-24,使用简化段定义的独立汇编语言源程序框架:DOSSEG.MODEL SMALL.STACK 长度
14、.DATA ;数据语句.CODE 启动标号:MOV AX,DATA ;或MOV AX,DGROUPMOV DS,AX ;可执行语句MOV AH,4CH ;返回DOSINT 21HEND 启动标号,3.3.2 逻辑段定义伪指令,3-25,3.2.3 数据伪指令语句,格式:,赋值语句:符号名 EQU 表达式,功能: 都是用符号名代替表达式的值。但赋值语句定义的符号名不能重新定义,而等号语句允许。,1.符号定义伪指令,等号语句:符号名 = 表达式,3-26,例3.2 赋值语句与等号语句举例。赋值语句:X EQU 50Y EQU X +10COUNT EQU $ - ARRY 等号语句:CON = 5
15、BASE = 200H BASE = BASE + 10H ;重新定义BASE,3.2.3 数据伪指令语句,3-27,2. 数据定义伪指令,功能: 是为数据项或项表分配存储空间,给它们赋初值,并用一个符号名(称为变量)与之相联系。,3.2.3 数据伪指令语句,3-28,使用说明:, 给变量赋初值可以是赋确定的值,也可以是赋不确定的值(用“?”表示),还可以是用DUP运算符建立的多次拷贝。,例3.3 使用80X86汇编语言的伪操作命令定义: VAL DB 93 DUP(5,2 DUP(2 DUP(1,2 DUP(3),4) 则在VAL存储区内前10个字节单元的数据是 ?,解:由内向外逐层展开,分
16、别相当于: 93 DUP(5,2 DUP(2 DUP(1,3,3),4) 93 DUP(5,2 DUP(1,3,3,1,3,3,4) 93 DUP(5,1,3,3,1,3,3,4,1,3,3,1,3,3,4) 即表示重复93个数据序列:5,1,3,3,1,3,3,4,1,3,3,1,3,3,4,3.2.3 数据伪指令语句,3-29, 使用SEG、OFFSET、TYPE、LENGTH和SIZE运算符求变量的各种属性时,特别要注意:,对LENGTH运算符,如果变量是用重复数据操作符DUP说明的,则返回外层DUP给定的值;如果没有DUP说明,则返回值总是1。 对SIZE运算符有:SIZE =TYPE
17、LENGTH,使用说明:,3.2.3 数据伪指令语句,3-30,解: 此题有两层DUP定义,但最外层DUP给定的值为100,所以:(BX)= 数组ARRAY的偏移地址;(CX)= 数组ARRAY的长度 = 100;(SI)= 数组ARRAY的类型 = 2。,例3.4 若数组ARRAY在数据段中已作如下定义: ARRAY DW 100 DUP(123H,3 DUP(?),1234H 试指出下列指令执行后,有关寄存器的内容是多少?,MOV BX,OFFSET ARRAY MOV CX,LENGTH ARRAY MOV SI,0 ADD SI,TYPE ARRAY,3.2.3 数据伪指令语句,3-3
18、1, 操作符“$”是取地址计数器的当前值,常用于表达式定义数组长度。,例3.5 已知: ORG 0100HARY DW 3,$+4,5,6CNT EQU $ - ARYDB 7,8,CNT,9 下列指令执行后, AX、BX寄存器的值为多少?MOV AX,ARY+2 MOV BX,ARY+10,解:画出数组ARY的内存分配图。,(AX)=ARY+2=0102H =0106H (BX)=ARY+10=010AH=0908H,3.2.3 数据伪指令语句,使用说明:,3-32, 使用DB、DW、DD定义串数据(用 定义的字符串)时,允许定义的串长度不同,字符的存放顺序也不相同:,DB是从左至右顺序为每
19、个字符分配一个字节单元; DW是从左至右顺序为每2 个字符分配一个字单元,且前面的字符在高字节,串长度不能超过2; DD是从左至右顺序为每4 个字符分配一个双字单元,也是按前面的字符在高字节顺序存放,串长度不能超过4。,3.2.3 数据伪指令语句,3-33,例3.6 今需在变量名为STRING的数据区中顺次存放数据A、B、C、D、E、F、G、H,请写出分别用汇编命令DB、DW和DD实现的语句。,解:用DB、DW和DD实现的语句分别为:STRING DB ABCDEFGHSTRING DW BA,DC,FE,HGSTRING DD DCBA,HGFE,3.2.3 数据伪指令语句,3-34,3.2
20、.4 模块定义伪指令,模块定义伪指令包括模块开始和模块结束语句。1. 模块开始语句(NAME)格式:NAME 模块名功能:指示源程序开始,并指出该源程序的模块名。2. 模块结束语句(END)格式:END 标号/过程名功能:模块结束语句表示源程序到此结束。,3-35,3.2.5 过程与宏定义伪指令,过程定义伪指令宏定义伪指令宏和过程的比较,3-36,格式:过程名 PROC 属性 ;过程体RET RET过程名 ENDP,说明:, 过程允许嵌套调用,还可以递归调用。, 过程与逻辑段也可以相互嵌套,但决不允许过程与段交叉覆盖。,过程又称为子程序。它是一段必须通过CALL指令调用才能执行的程序段,执行完
21、后通过一条RET指令返回原调用处。过程需先定义才能调用。, 过程体中必须至少包含一条RET指令,这是过程的出口。但也允许过程有多条RET指令,即过程有多个出口。,1.过程定义伪指令,3.2.5 过程与宏定义伪指令,3-37,宏定义格式:宏名 MACRO 形式参数表 ;宏体ENDM,说明:宏定义的宏名必须唯一,称为宏指令。宏指令一经定义就可以在源程序的任何地方调用。相当于由用户给汇编程序提供了一个新的操作码。,宏调用格式:宏名 实际参数表,3.2.5 过程与宏定义伪指令,宏的概念与过程很相似,也是用一个宏名字来代替源程序中经常要用到的一个程序模块。,2. 宏定义伪指令,3-38,3.2.5 过程
22、与宏定义伪指令,使用宏定义和宏调用时要注意两个问题:, 对带参数的宏指令,宏调用时实际参数与形式参数的类型要一致,以免产生无效调用 。, 宏调用是用宏体中定义的指令序列替换宏指令,所以宏体内的标号要用LOCAL伪指令说明为局部标号,以免多次调用宏时,发生标号重复定义错误。,LOCAL伪指令格式:LOCAL 标号1,标号2,,3-39,解:宏定义如下:MOVE MACRO SARY,DARYLOCAL LPMOV SI,0MOV CX,100LP: MOV AL,SARYSIMOV DARYSI,ALINC SILOOP LPENDM,例3.7 定义宏MOVE,其功能是将一个有100个字节元素的
23、数组搬移到另一个数据区。,进行宏调用:MOVE FIRST,SECOND 宏展开如下: MOV SI,0MOV CX,100 ?0000:MOV AL,FIRSTSIMOV SECONDSI,ALINC SILOOP ?0000,3.2.5 过程与宏定义伪指令,3-40,3. 宏和过程的比较,宏和过程都可简化源程序的书写,因而也减少了程序出错的可能性。但两者使用上也有区别:,3.2.5 过程与宏定义伪指令,(1) 宏操作可以直接传递和接收参数,而过程不能直接带参数。当过程之间需要传递参数时,必须通过堆栈、寄存器或存储器来进行,编程比宏要复杂。,所以,宏汇编适合于代码较短,传送参数较多的子功能段
24、使用,子程序适合于代码较长,调用比较频繁的子功能段使用。,(3) 引入宏操作并不会在执行目标代码时增加额外的时间开销,但过程调用由于要保护和恢复现场及断点,因此会延长目标程序的执行时间。,(2) 子程序不管被调用多少次它都只被汇编一次,即有唯一的一段目标代码;而宏指令则调用多少次就汇编多少次,每次调用都要在程序中展开并保留宏体中的每一行。,3-41,3.2.6 结构定义伪指令,在一些应用中,常需要将一些不同类型的数据组合成一个有机整体。这时就要用到汇编语言的结构化数据结构。,与前述的字节、字类型数据不同,一个结构必须先经定义后才可以说明属于这种结构类型的变量,这是因为结构的组成是千变万化的。所
25、以围绕结构定义,有两种伪指令语句:,2. 结构变量说明与赋初值语句,1. 结构类型说明语句(STRUC/ENDS),3-42,3.2.6 结构定义伪指令,语句格式:结构名 STRUC ;结构体,由数据定义语句构成结构名 ENDS,DATE STRUCMONTH DB ?DAY DB ?YEAR DW ? DATE ENDS,结构的定义明确地描述了该结构的组织形式,它告诉汇编程序属于这种组织形式的变量使用内存的模式。例如:,1. 结构类型说明语句(STRUC/ENDS),3-43,语句格式:变量名 结构名 域值表,例如:VAR DATE ,3. 结构的引用有两种方法: 结构变量名.域名 基址或变
26、址寄存器.域名,MOV AX, VAR.YEAR MOV CL, VAR.DAY上述引用也可用如下方法:MOV BX,OFFSET VAR MOV AX,BX.YEAR MOV CL,BX.DAY,3.2.6 结构定义伪指令,2. 结构变量说明与赋初值语句,3-44,3.3 汇编语言程序设计入门,3.3.1 汇编语言程序的开发过程3.3.2 基本结构程序设计3.3.3 子程序设计与调用技术3.3.4 DOS/BIOS功能调用,3-45,3.3.1 汇编语言程序的开发过程,与其它程序设计语言一样,汇编语言程序的开发过程可归结为:,就需求分析、模块划分和算法确定等工作而言,各种程序设计语言是类似的
27、,均可按软件工程的方法进行,但编程和调试则因程序设计语言而异。, 需求分析, 根据需求和规模等因素划分模块, 确定各功能模块的求解算法、并定义所需的数据结构, 进行编程和调试,3-46,对汇编语言而言,根据数据结构和算法进行编码到形成可用程序的过程如下:,3.3.1 汇编语言程序的开发过程,3-47,3.3.2 基本结构程序设计,程序的基本结构形式有三种:,顺序结构,分支结构,循环结构,理论上,三种基本结构是完备的,即任何功能的程序都可由顺序、分支和循环三种结构实现。,3-48,1. 顺序程序设计,在实际应用中,纯粹用顺序结构编写的完整程序很少见,但是在程序段中它却是大量的存在。所以掌握它是编
28、写复杂应用程序的基础。, 顺序程序又称直线程序。,其特点是顺序执行的,无分支,无循环,也无转移,只作直线运行。,3.3.2 基本结构程序设计,3-49,2. 分支程序设计,在许多实际问题中,往往需要根据不同的情况和给定的条件做出不同的处理。要设计这样的程序,必须事先把各种可能出现的情况及处理方法都编写在程序中,以后计算机运行程序时,可自动根据运行的结果做出判断,有条件地选择执行不同的程序段,按这种要求编写的程序称为分支程序。,3.3.2 基本结构程序设计,3-50,分支程序的结构有三种形式:,IF 条件 THEN 分支程序,IF 条件 THEN 分支1ELSE 分支2,3.3.2 基本结构程序
29、设计,3-51, 利用比较与条件转移指令实现分支,程序如下:DATA SEGMENTX DB 0F8HY DB ?DATA ENDS,3.3.2 基本结构程序设计,3-52,CODE SEGMENTASSUME CS:CODE,DS:DATASTART:MOV AX,DATAMOV DS,AXMOV AL,X ;取变量X的值CMP AL,0 ;X与0比较JG BIGRJE FINISH ;X=0,Y=0MOV AL,0FFH ;X 0,Y=1FINISH:MOV Y,AL ;保存函数值YMOV AH,4CHINT 21HCODE ENDSEND START,3.3.2 基本结构程序设计,3-5
30、3, 利用跳转表实现分支,适于多分支结构。有三种跳转表:,3.3.2 基本结构程序设计,3-54,使用跳转表实现分支时,要特别注意表内地址分支和表内指令分支两种结构跳转表的定义方法和正确的寻址方式。,表内地址分支在数据段定义跳转表,用存储器间接寻址; 表内指令分支在代码段定义跳转表,用寄存器间接寻址。,3.3.2 基本结构程序设计,3-55,解:这是一个多分支结构程序,适合于用跳转表实现。假设用表内地址分支实现,此时,跳转表在数据段定义,转移要用存储器间接寻址的跳转指令。程序如下:,例3.10 设某控制程序可完成8种产品的加工,每种加工程序对应一个数字(18)。现要求根据输入的值去加工相应产品
31、。假设8 种加工程序段与主程序在同一代码段中。,3.3.2 基本结构程序设计,3-56,例3.10 表内地址分支程序,.486 DATA SEGMENT DATADISP DB Error repeat inputDB 0AH,0DH,$BASE DD SBR1,SBR2,SBR3,SBR4DD SBR5,SBR6,SBR7,SBR8 DATA ENDS CODE SEGMENT CODEASSUME CS:CODE,DS:DATA START: MOV AX,DATAMOV DS,AX INPUT: MOV AH,1 ;输入数字序号INT 21HCMP AL,1JB ERRCMP AL,8J
32、A ERRSUB AL,1,AND EAX,0000000FH JMP BASEEAX*4 SBR1: SBR2: SBR8: ERR: CMP AL,EJZ EXITMOV DX,OFFSET DISPMOV AH,09HINT 21HJMP INPUT EXIT:MOV AH,4CHINT 21H CODE ENDSEND START,此题也可用表内指令分支实现。这时,跳转表要在代码段定义,转移则要用寄存器间接寻址的跳转指令。程序如下:,3.3.2 基本结构程序设计,3-57,.486 DATA SEGMENT USE16 DATADISP DB Error repeat inputDB
33、0AH,0DH,$ DATA ENDS CODE SEGMENT USE16 CODEASSUME CS:CODE,DS:DATA START: MOV AX,DATAMOV DS,AX INPUT: MOV AH,1 ;输入数字序号INT 21HCMP AL,1JB ERRCMP AL,8JA ERRSUB AL,1AND AX,000FH MOV BX,AX SHL BX,1 ADD AX,BXMOV BX,OFFSET BASE,ADD BX,AX JMP BX BASE: JMP SUB1 ;跳转表JMP SUB2 JMP SUB8 SUB1: SUB2: SUB8: ERR: CMP
34、 AL,EJZ EXIT ;按E键结束MOV DX,OFFSET DISPMOV AH,09H ;显示提示信息INT 21HJMP INPUT ;转重输入字符 EXIT: MOV AH,4CHINT 21H CODE ENDSEND START,例3.10 表内指令分支程序,3.3.2 基本结构程序设计,3-58,3.循环程序设计,初始化部分,循环体,循环修改,循环控制,凡要重复执行的程序段都可按循环结构设计。采用循环结构,可简化程序书写形式,缩短程序长度,减少占用的内存空间。, 循环结构的程序一般包括下面几个部分:,3.3.2 基本结构程序设计,3-59, 循环程序的两种组织方式,3.3.2
35、 基本结构程序设计,3-60, 计数控制, 条件控制, 状态控制, 逻辑尺控制, 循环结束的控制方式 :,3.3.2 基本结构程序设计,3-61,(1) 计数控制循环程序设计循环次数已知时用计数控制循环,这时常用CX作循环计数器,用循环指令LOOP控制循环。也可用其他通用寄存器作循环计数器,用DEC和JNZ指令控制循环。,例3.11 某存储区中存放着80名同学某科目的成绩(099分),假定此成绩以压缩BCD码形式存放。要求统计及格(60分以上)和不及格人数,统计结果仍以压缩BCD码形式存放。,解: 此题循环次数已知,下面用CX作循环计数器,使用LOOP指令控制循环。BCD计数器加1用宏指令实现
36、,程序如下:,3.3.2 基本结构程序设计,3-62,例3.11 程序,;定义宏,BCD加1计数 BCD_ADD_1 MACRO ADDRMOV AL,ADDRADD AL,1DAA MOV ADDR,ALENDM DATA SEGMENTBLOCK DB 87H,60H,57H,90HCNT EQU $ - BLOCKNUM1 DB 0 ;定义计数器NUM2 DB 0 DATA ENDS CODE SEGMENTASSUME CS:CODE,DS:DATA,START:MOV AX,DATAMOV DS,AXMOV SI,OFFSET BLOCKMOV CX,CNT AGAIN:MOV AL
37、,SICMP AL,60H ;比较JNC NEXTBCD_ADD_1 NUM2JMP NEXT1 NEXT:BCD_ADD_1 NUM1 NEXT1:INC SI ;修改指针LOOP AGAINMOV AH,4CH INT 21H CODE ENDSEND START,3.3.2 基本结构程序设计,3-63,例3.12 编写程序,将ASCII码表示的5位十进制数(65535)转换成16位二进制数,并存储起来。,解:设X=Xn-1X1X0为十进制数,则X转换为二进制数的一般方法为:X=Xn-110n-1+X1 10+X0,该式可用计数循环结构从低位到高位依次对每位十进制数进行转换处理,求出每位十
38、进制数对应的二进制数(Xi10i),并累加求和。,假定用变量MULTIPLE保存第i位十进制数Xi对应的权值10i,变量BINAY保存转换的二进制数,ASCII码数的存放顺序是高位在前、低位在后。程序如下:,3.3.2 基本结构程序设计,3-64,例3.12 程序,DSEG SEGMENTASCDEC DB 23333BINAY DW 0MULTIPLE DW 1 DSEG ENDSCSEG SEGMENTASSUME CS:CSEG,DS:DSEG START:MOV AX,DSEGMOV DS,AXMOV CX,10;SI指向ASCII码数首址LEA SI,ASCDEC DEC SI;BX
39、指向ASCII码数个位MOV BX,5,NEXT:MOV AL,BX+SIAND AX,0FH;计算当前十进制位对应的二进制数MUL MULTIPLE ADD BINAY,AX ;累加求和MOV AX,MULTIPLE;计算下一十进制位对应的权值MUL CX MOV MULTIPLE,AXDEC BXJNZ NEXT ;未完继续MOV AH,4CHINT 21H CSEG ENDSEND START,3.3.2 基本结构程序设计,3-65,当循环次数未知时,就要用条件或状态信号来控制循环。用条件控制时,常用比较指令CMP与条件转移指令Jcc结合控制循环结束.用状态控制时,状态信号既可由外设提供
40、,也可由其他任务或过程提供,这时常用测试指令TEST与条件转移指令Jcc结合控制循环结束。, 条件/状态控制循环程序设计,3.3.2 基本结构程序设计,3-66,例3.13 编程统计AX寄存器中1的个数。,解:要统计AX中1的个数,一个比较简单直观的办法是用移位的办法把各数位逐次移到最高位去,然后根据最高有效位是否为1来计数;循环结束采用计数值16来控制。但考虑到AX的值或者某次移位后AX的值可能为0的情况,为了缩短程序的执行时间,下面采用测试AX的值是否为0来作为循环结束的控制条件。程序如下:,3.3.2 基本结构程序设计,3-67,CODE SEGMENTASSUME CS:CODE SA
41、TRT: MOV CX,0 ;统计计数器清0 AGAIN: CMP AX,0 ;(AX)=0?JZ EXIT ;为0,结束JNS NEXTINC CX ;AX最高位为1,统计 NEXT: SHL AX,1 ;AX左移1位JMP SHORT AGAIN EXIT: MOV AH,4CHINT 21H CODE ENDSEND START,例3.13 程序,此例说明算法和控制条件的选择对程序的工作效率有很大影响,而循环控制条件的选择又是很灵活的,应该根据具体情况来确定。,3.3.2 基本结构程序设计,3-68,例3.14 从FIRST开始的100个单元中存放着一个字符串,结束符为$。编写一个程序,
42、统计该字符串中字母A的个数。,解:此例并不知道字符串的具体长度,所以不能直接使用计数循环。这时可用字符串结束标志(结束符$)来控制扫描或比较结束。当然,经过适当处理,此例也可用计数循环控制。下面给出这两种控制方法的程序。,3.3.2 基本结构程序设计,3-69,例3.14 条件控制程序,DATA SEGMENT;定义字符串,结束符为$ FIRST DB AGHJK$NUMBER DB ? DATA ENDSCODE SEGMENTASSUME CS:CODE,DS:DATA START:MOV AX,DATA MOV DS,AXMOV BL,0LEA DI,FIRST ;取串首址,NEXT:M
43、OV AL,DI ;取一个字符INC DICMP AL,$ ;与$比较JE EXIT ;等于,结束CMP AL,A ;与A比较JNE NEXT ;不等于,不统计INC BL ;找到,计数JMP NEXT ;继续 EXIT:MOV NUMBER,BLMOV AH,4CH INT 21H CODE ENDSEND START,3.3.2 基本结构程序设计,3-70,例3.14 计数控制程序,DATA SEGMENTFIRST DB AGHJK$COUNT EQU $ - FIRSTNUMBER DB ? DATA ENDSCODE SEGMENTASSUME CS:CODE,DS:DATA STA
44、RT:MOV AX,DATA MOV DS,AX;DS、ES指向同一数据段MOV ES,AX,MOV BL,0LEA DI,FIRSTMOV CX,COUNTMOV AL,ACLD NEXT:REPNE SCASB ;找字符AJNZ EXIT ;未找到,结束INC BL ;找到,计数JMP NEXT ;继续 EXIT:MOV NUMBER,BLMOV AH,4CHINT 21H CODE ENDSEND START,3.3.2 基本结构程序设计,3-71,3.3.2 基本结构程序设计,(3) 逻辑尺循环程序设计,循环不规则时使用的一种循环控制方法,例3.15 设有数组:X=x1,x2,x10,
45、 Y=y1,y2,y10。试编制程序,计算:z1=x1 + y1 z6=x6 + y6z2=x2 + y2 z7=x7 - y7z3=x3 - y3 z8=x8 - y8z4=x4 - y4 z9=x9 + y9z5=x5 - y5 z10=x10 + y10其中,xi,yi,zi (i=1,2,10)均为16位补码数。,定义一个二进制位序列称为逻辑尺1100010011每个数组元素zi对应一位,该位为1,表示计算zi时对应数组元素相加,否则相减。,3-72,例3.15 程序,3.3.2 基本结构程序设计,DATA SEGMENTX DW x1,x2,x3,x4,x5DW x6,x7,x8,x
46、9,x10Y DW y1,y2,y3,y4,y5DW y6,y7,y8,y9,y10Z DW 10 DUP (?)SOCBEH DW 1100010011000000B DATA ENDSSTACK SEGMENT STACKSTN DB 100 DUP (?) STACK ENDSCODE SEGMENTASSUME CS:CODE,SS:STACK,DS:DATA,START:MOV AX,DATAMOV DS,AXMOV BX,SOCBEH ;取逻辑尺MOV CX,10 ;置循环次数MOV SI,0 AGAIN:MOV AX,XSI ;取xiSHL BX,1JNC L1 ADD AX,Y
47、SI ;求和JMP L2L1: SUB AX,YSI ;相减L2:MOV ZSI,AX ;保存ziADD SI,2LOOP AGAIN EXIT: MOV AH,4CHINT 21H CODE ENDSEND START,3-73,3.3.3 子程序设计与调用技术,同一个程序中,往往有许多地方都需要执行同样的一项任务(一段程序),而该任务又并非规则情况,不能用循环程序来实现,这时可以对这项任务独立地进行编写,形成一个子程序或过程。,3-74,子程序结构如图所示:,3.3.3 子程序设计与调用技术,从子程序返回主程序则简称为“返主”,通常将主程序向子程序转移叫子程序调用或过程调用,简称“转子”,
48、3-75,设计或编写子程序时,着重要考虑两个问题:,3.3.3 子程序设计与调用技术,主程序与子程序的接口,主程序与子程序间的参数传递,3-76,正确使用CALL/RET指令,转子和返主过程中的现场保护和恢复, 主程序与子程序所使用的存储单元和寄存器尽量分开,互不干扰。,这又有两种方法:,3.3.3 子程序设计与调用技术, 主程序与子程序的接口,3-77, 将“现场”通过堆栈保存和恢复。,SUBR PROC PUSH AX PUSH BX ;子程序体 POP BX POP AX RET SUBR ENDP 子程序,这时,既可在子程序中保存和恢复,又可在主程序中保存和恢复。例如:, PUSH AX PUSH BX CALL SUBR POP BX POP AX 主程序,