微机原理及接口技术5.ppt_第1页
微机原理及接口技术5.ppt_第2页
微机原理及接口技术5.ppt_第3页
微机原理及接口技术5.ppt_第4页
微机原理及接口技术5.ppt_第5页
已阅读5页,还剩71页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

5.1 汇编语言的概念 5.2 伪指令 5.3 汇编语言源程序的格式 5.4 常用系统功能调用 5.5 汇编语言程序设计,第5章 汇编语言程序设计,5.1 汇编语言的概念,5.1.1 汇编语言语句的格式,汇编语言:是一种面向CPU指令系统的程序设计语言,它采用指令系统的助记符来表示操作码和操作数,用符号地址表示操作数地址。,名字: 助记符 操作数 ;注释,知识要点提醒: 汇编语言中已定义的保留字、指令助记符、伪指令助记符、寄存器名等,不能作为名字使用。,5.1.2 常数,常数:也称常量,就是指令中出现的那些固定值,在程序运行期间不发生变化。,1. 二进制数:后跟字母B,如01110001B。 2. 八进制数:后跟字母O或Q,如123Q或123O。 3. 十进制数:后跟字母D或不跟字母,如56D或56。 4. 十六进制数:后跟字母H,如78H,0FFH。 5. 字符和字符串:是由单引号括起来的一串字符,例如ABCDEF,1223。字符串最长可以有255个字符。,知识要点提醒: 汇编语言源程序中的数值常量的第一位必须是09数字,否则,汇编时将把它看成是标识符。例如常数B7H,在汇编语言源程序中应写成0B7H,FFH应写成0FFH。,5.1.3 标号与变量,知识要点提醒: 对于变量的类型值:DB为1,DW为2,DD为4,DQ为8,DT为10。对于标号的类型值:NEAR为-1,FAR为-2。,2. 变量 变量是指存储在存储单元中的操作数,它们的值在程序运行过程中是可变的。 变量的属性:段、偏移量和类型。,1. 标号 标号:标识符后跟冒号,它代表该行指令的起始地址,其它指令可以引用该标号,作为转移的符号地址。 标号的属性:段、偏移量、类型。,5.1.4 运算符,1. 算术运算符:+、/、MOD。 2. 逻辑运算符:AND、OR、XOR、NOT。 3. 关系运算符:EQ、NE、LT、GT、LE、GE。,8086宏汇编有算术运算符、逻辑运算符、关系运算符、分析运算符和综合运算符共5种。,MOV AX,5 EQ 2 ;关系不成立,故(AX)0 MOV AX,7 NE 5 ;关系成立,故(AX)0FFFFH,例题:,4. 分析运算符:SEG、OFFSET、TYPE、SIZE、LENGTH。 (1) SEG:求标号或变量的段地址。 格式:SEG 变量或标号名 例题: 已知数据段从存储器的23000H地址开始,DBUF是该段中的一个变量名。 MOV BX,SEG DBUF;汇编为: MOV BX,2300H (2)OFFSET:求标号或变量的偏移量。 格式:OFFSET 变量或标号名 例题: 已知标号START的段地址为2100H,物理地址为21200H。 MOV DX,OFFSET START 汇编为:MOV DX,0200H;与指令LEA DX,START功能相同。,(3)TYPE:求变量或标号的类型,其运算结果是个数值。 格式:TYPE 变量或标号 例题: VAR DW ? ;变量VAR的类型为字 ARRAY DD 10DUP(?) ;变量ARRAY的类型为双字 STR DB THIS IS TEST ;变量STR的类型为字节 MOV AX,TYPE VAR ;(AX)2 MOV BX,TYPE ARRAY ;(BX)4 MOV CX,TYPE STR ;(CX)1,(4) LENGTH:此运算符只适用于DUP定义变量的情况,LENGTH求出分配给该变量的数据个数,否则结果为1。 格式:LENGTH 变量 例题: 已定义:DA50 DW 50 DUP(1) ADR DB l0,2AH 则指令: MOV CX,LENGTH DA50;汇编为:MOV CX,50 MOV BX,LENGTH ADR;汇编为:MOV BX,1,(5) SIZE:此运算符只适用于DUP定义变量的情况,SIZE求出分配给该变量的字节数,否则结果为1。 格式:SIZE 变量 例题: 已定义DA50 DW 50DUP(1) DA2 DB l0,2AH,5 则指令: MOV CX,SIZE DA50;汇编为:MOV CX,100 MOV BX,SIZE DA2;汇编为:MOV BX,1,5. 综合运算符: PTR、THIS、SHORT等。 用来临时改变变量或标号的类型或存储器操作数的存储单元类型,其中THIS、SHORT运算符不常用。 PTR:用于在本语句取代一个已经定义过的存储器操作数的类型,但不改变该操作数的类型。 格式:类型 PTR 地址表达式 说明:类型可以是BYTE、WORD、DWORD、NEAR、FAR等;地址表达式可以是标号、作为地址指针的寄存器、变量和数值的组合。 例题: S DD ? ;定义STUFF为双字类型变量 MOV BX,WORD PTR S;从S中取一个字到BX,知识要点提醒: PTR只是用来建立一个符号地址,它本身并不分配存储单元。PTR运算符可以用来确定指令操作数的类型是字节型还是字型,以保证指令的正确使用。 例题: 已知寄存器BX的内容是0120H,指令为MOV BX,34H 执行指令时,汇编程序不能分清是把立即数34H存入偏移地址为0120H的单元,还是把立即数0034H存入偏移地址为0120H、0121H的单元?此时指令可改写为: MOV BYTE PTRBX,34H; 0120H 34H MOV WORD PTR BX,34H;0120H、0121H 0034H,5.2 伪指令,伪指令与指令的区别: 指令是给CPU的命令,在运行时由CPU执行,每条指令对应CPU的一种特定操作; 伪指令是给汇编程序的命令,在汇编过程中由汇编程序进行相应处理。 汇编以后,每条指令都产生对应的目标代码;而伪指令则不产生一一对应的目标代码。,5.2.1 数据定义伪指令,数据定义伪指令的用途是定义一个变量的类型,给存储器赋初值,或给变量分配存储单元。常用的数据定义伪指令有DB、DD、DW等。 数据定义伪指令格式: 变量名 伪指令 操作数,操作数 1. DB:定义变量的类型为BYTE,给变量分配字节或字节串。DB后面的每个操作数占有1个字节。 2. DW:定义变量的类型为WORD。DW后面的操作数每个占2个字节。在内存中存放时,低位字节在前,高位字节在后。 3. DD:定义变量的类型为DWORD。DD后面的操作数每个占4个字节。在内存中存放时,低位字在前,高位字在后。,例题: DA1 DB 100,0FFH ;变量DA1的值是:64H,FFH EX2 DB 2*37;变量EX2的值是:0DH ST3 DB GOOD!;变量ST3的值是:GOOD!,共5个字符 AB4 DB AB;变量AB4的值是:41H,42H BA5 DW AB;变量BA5的值是:4142H AD6 DD AB;变量AD6的值是:00004142H AF8 DW TA,TA-5,TA10 ;将3个偏移地址送入到变量AF8中 T9 DD TA ;将TA的偏移地址和段地址顺序存入变量T9中,共占2个字,说明: (1)?也可以作为数据定义伪指令的操作数,此时仅给变量保留相应的存储单元,而不赋给变量某个确定的初值。 (2)DUP表示同样的操作数重复多次,其形式为:n DUP (x) 其中,x为重复的内容,n为重复次数。DUP可以嵌套。 例题: FLR DB ?;给变量FLR分配1个字节的存储空间 SUM DW ?,?,?;给变量SUM分配3个字的存储空间 BUF DB 10 DUP(?);给变量BUF分配10个字节的存储空间 A DB 10 DUP (3 DUP(8),6) ;给变量A分配40个字节,初值是重复10次的8、8、8、6,知识要点提醒: 数据定义伪操作后面的操作数可以是常数、表达式或字符串,但每项操作数的值不能超过由伪操作所定义的数据类型限定的范围。例如,DB伪指令定义数据的类型为字节,则其范围为无符号数0255;带符号数128+127等。字符串只能用DB伪指令定义。,5.2.2 符号定义伪指令 符号定义伪指令的用途是给一个符号名赋新值,常用的符号定义伪指令有EQU和(等号)。 1. EQU 格式: 符号名 EQU 表达式 EQU伪指令是将表达式的值赋给一个名字,以后可以用这个名字来代替表达式。式中的表达式可以是常数、符号、数值表达式或地址表达式。 例题: CR EQU ODH;常数 A EQU BUF;变量 STR EQU 64*1024;数值表达式 ADR EQU ES:BPDI5;地址表达式 CBD EQU AAM ;指令助记符,2. = 格式:符号名表达式 功能与EQU相似,主要区别在于“=”可以对同一符号重复定义。 例题: COUNT10 MOV CX,COUNT;(CX)10 COUNTCOUNT-1 MOV BX,COUNT;(BX)9 知识要点提醒: 利用EQU伪指令,可以用一个名字代表一个数值,或用一个简短的名字代替一个较长的名字。如果源程序中需要多次引用某一表达式,则可以利用EQU给其赋一个名字,以代替程序中的表达式,从而使程序更加简洁,便于阅读。 注意:EQU伪指令不能对同一符号重复定义。,5.2.3 段定义伪指令,段定义伪指令的用途是在汇编语言源程序中定义逻辑段,或指明当前各段所用的段寄存器的名字,设定段寄存器与段间的对应关系。 1. 段定义伪指令 格式: 段名 SEGMENT定位类型组合类型类别 段名 ENDS 2. 指定段地址伪指令 格式: ASSUME 段寄存器名:段名,段寄存器名:段名,,例题: DATA SEGMENT ;定义数据段 BUF1 DB 12H,23H,34H BUF2 DB 78H,09H,22H DATA ENDS ;数据段结束 CODE SEGMENT ;定义代码段 ASSUME CS:CODE,DS:DATA ;段地址伪指令 BIN: MOV AX,DATA MOV DS,AX ;用指令填装DS CODE ENDS ;代码段结束 END BIN 知识要点提醒: 不同的模块中,允许有相同的段名,但连接程序LINK并不把它们看成是相同的逻辑段。同一模块中,同名各段必须有相同的类别,以便它们在汇编时合并在同一个逻辑段中。,过程定义伪指令是用来定义一个过程(子程序)。 格式: 过程名 PROC 类型 RET 过程名 ENDP 过程名实质上是过程入口的符号地址,过程的类型可以是NEAR或FAR。 如果定义时没有指明类型,则默认为NEAR。 当一个程序段被定义为过程后,程序中其它地方就可以用CALL指令来调用这个过程。,5.2.4 过程定义伪指令,例题:编写一个延时子程序SOFTDLY,其过程可定义如下。 SOFTDLY PROC PUSH BX PUSH CX MOV BL,10 DELAY: MOV CX,2801 WAIT: LOOP WAIT DEC BL JNZ DELAY POP CX POP BX RET SOFTDLY ENDP 知识要点提醒: 一般来说,被定义为过程的程序段中应该有返回指令RET,但不一定是最后一条指令,也可以有不止一条RET指令。,5.2.5 模块定义伪指令,1. 模块定义伪指令 格式: NAME 模块名 END 表达式 2. 模块通信伪指令 格式: PUBLIC 符号名, EXTRN 符号名:类型,,例题: NAME MAIN ;定义主程序模块MAIN EXTRN SUBP:FAR;声明过程SUBP在其它模块中已经定义 PUBLIC X,Y ;说明变量X,Y是公共的 DATA SEGMENT ;定义数据段 X DW 100 Y DW 10 DATA ENDS ;数据段结束 CODE SEGMENT ;定义代码段 MAIN PROC FAR ;定义过程MAIN BEGIN: CALL SUBP ;调用过程SUBP MAIN ENDP ;过程MAIN结束 CODE ENDS ;代码段结束 END BEGIN ;主程序模块结束,NAME SUBPA ;定义模块SUBPA EXTRN X:WORD,Y:WORD;声明变量X,Y在其它模块中已定义 PUBLIC SUBP ;说明过程SUBP是公共的 CODE SEGMENT ;定义代码段 SUBP PROC FAR ;定义过程SUBP MOV AX,X MOV BX,Y MUL BX RET SUBP ENDP ;过程SUBP结束 CODE ENDS ;代码段结束 END ;模块SUBPA结束 知识要点提醒: 模块是一个独立的程序单位,汇编时,模块将作为一个独立的单位进行汇编,汇编遇到END结束。END后面的表达式只能用于主程序模块中。,5.2.6 宏定义伪指令,格式: 宏指令名 MACRO 形式参数名 ;宏体 ENDM 例题: GADD MACRO X,Y,AD MOV AX,X ADD AX,Y MOV AD,AX ENDM 若汇编语言源程序中有宏指令:GADD B1,B2,SUM 在汇编时,汇编程序会将该宏指令进行宏展开,即该宏指令等价于下面三条指令: MOV AX,B1 ADD AX,B2 MOV SUM,AX,知识要点提醒: (1) 指令语句能产生目标代码,CPU可以执行的能完成特定功能的语句,它主要由CPU指令组成。 (2) 伪指令语句是一种不产生目标代码的语句,仅仅在汇编过程中告诉汇编程序应如何汇编指令序列。例如,告诉汇编程序已写出的汇编语言源程序有几个段?段的名字是什么?定义变量,定义过程,给变量分配存储单元等。所以伪指令语句是为汇编程序在汇编时用的。 (3) 宏指令语句是一个指令序列,汇编时,凡有宏指令语句的地方,都将用相应的指令序列的目标代码插入。,5.3 汇编语言源程序的格式,STACK SEGMENT ;定义堆栈段,段名是STACK ;分配堆栈区域的大小 STACK ENDS ;堆栈段结束 DATA SEGMENT ;定义数据段,段名是DATA ;定义数据 DATA ENDS ;数据段结束 CODE SEGMENT ;代码段 ASSUME CS:CODE,DS:DATA,SS:STACK;确定逻辑段的类型 STA: MOV AX,DATA ;开始汇编 MOV DS,AX ;程序代码 MOV AH,4CH ;返回DOS INT 21H CODE ENDS ;代码段结束 END STR ;汇编结束,5.4 常用系统功能调用,DOS系统功能调用步骤: (1) 设置入口参数,如果所调用的子程序不需参数,则可省略此步。 (2) 欲调用的子程序编号AH。 (3) 发中断调用指令INT 21H。,5.4.1 DOS系统功能调用,1. 键盘输入(1号调用) 入口参数:无 出口参数:所读取的字符ASCII码在AL内。 功能:此调用扫描键盘,若有键按下,先检查是否是Ctrl-Break键,若是,则退出命令执行并调用DOS的Ctrl-Break处理程序;若否,则将字符ASCII码放置到AL中,同时在屏幕上显示这个字符,然后返回。若无键按下,该调用等待直到有键按下为止。 例题: MOV AH,1 INT 21H,2. 键盘输入(8号调用) 同1号类似,但是不在屏幕上显示输入的字符,在读取密码时常用本功能。,4. 在屏幕上显示一个字符(2号调用) 入口参数:DL=待显示字符的ASCII码 出口参数:无 功能:将字符显示在屏幕上。但如果字符是控制符,则实际执行相应的功能,如:在屏幕上显示一个换行符(0AH),实际上将光标转到下一行上去。 例题: MOV DL,A MOV AH,2 INT 21H,3. 键盘输入(7号调用) 同8号类似,并且不特殊检查Ctrl-Break键(当作普通字符)。,5. 显示或读取字符(6号调用) 此功能调用既可显示字符也可接收字符,这取决于入口参数中DL的设置:若DL=FFH,表示从键盘读取字符;若DLFFH,表示显示这字符。 (1)显示字符 入口参数:DL=待显示字符的ASCII码(但不能为FFH) 出口参数:无 功能:将字符显示在屏幕上。但如果字符是控制符,则实际执行相应的功能。 例题: MOV DL,$ MOV AH,6 INT 21H,(2)接收字符 入口参数:DL=FFH 出口参数:若读到字符,ZF=0,AL=键入字符的ASCII码;若未读到字符,ZF=1。 功能:从键盘读取字符,但不等待按键,即不论有无键按下都立即返回,并且也不特殊检查CtrlBreak键。当要求用户必须立即做出反应时可用此调用读取键盘,如在游戏程序中。 例题: 在本示例中,通过一个循环来实现等待读取一个字符。 L1: MOV AH,6 MOV DL,0FFH INT 21H JZ L1,6. 打印一个字符(5号调用) 入口参数:DL=待打印字符的ASCII码 出口参数:无 功能:在打印机上打印字符,若打印机出现错误,则在屏幕上显示相应错误信息。,7. 字符串显示(9号调用) 入口参数:DS:DX指向待显示字符串,且字符串必须以“$”作为结束符 出口参数:无 功能:结束符之前的字符都被显示在屏幕上。,例题: DATA SEGMENT BUF DB THIS IS A TEST ! $ DATA ENDS CODE SEGMENT START: MOV AX,DATA MOV DS,AX MOV DX,OFFSET BUF MOV AH,9 INT 21H MOV AH,4CH INT 21H CODE ENDS END START,8. 字符串输入(0AH号调用) 入口参数:DS:DX指向输入缓冲区。 出口参数:用户实际输入字符个数在缓冲区第二个单元中。 知识要点提醒: 在0AH号功能调用中,为了接收字符串,首先在内存储器中应定义一个缓冲区,其第一字节为该缓冲区的字节个数,第二字节由系统填写实际键入的字符总数,从第三个字节开始存放键入的字符串;然后从键盘接收以回车键为结束符的字符串。如果实际键入的字符数不足填满缓冲区,则其余字节填0;否则超出的字符将丢失,并且响铃警告。,例题:字符串的输入输出。编一段程序先提示用户输入一个字符串,然后读取用户的输入,并将用户输入的数据在下行输出。 DATA SEGMENT MESSAGE DB PLEASE INPUT A STRING:$;定义输入提示 BUF DB 255, ?,255 DUP(0);用户输入缓冲区,可接收255个字符 DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA START: MOV AX,DATA MOV DS,AX MOV DX,OFFSET MESSAGE MOV AH,9 INT 21H ;显示输入提示信息 MOV DX,OFFSET BUF MOV AH,10 INT 21H ;接收用户输入,MOV AH,2 MOV DL,0AH INT 21H MOV DL,0DH INT 21H ;回车换行 MOV BL,BUF+1 ;用户实际输入字符数BL MOV BH,0 ;将BX高8位清0,从而使BX=用户实际输入字符数 MOV BYTE PTR BUF+2BX,$ ;在用户输入的字符结束处放置一个“$” MOV DX,OFFSET BUF+2 ;用户实际输入字符起始处DX MOV AH,9 INT 21H ;显示用户输入的字符 MOV AH,4CH INT 21H CODE ENDS END START,知识要点提醒: 实际上,DOS所有的功能都可通过21H中断调用来实现的。 随着DOS的发展,所提供的功能(子程序)越来越多,不可能每一个子程序都占用一个中断号,于是采用让它们共用一个中断号,即21H号的办法,进入这一个中断后,DOS再根据用户程序中入口参数的设置来确定到底想调用哪个子功能。 考虑兼容缘故,早期版本中独占一个中断号的DOS功能调用并没有被撤销,而是保留了下来,这样就形成了有些功能既可以通过调用21H号中断来实现,又可以通过调用别的中断实现,如终止程序功能,调用20H号中断与调用21H号中断之00H号子功能,效果完全相同。,5.4.2 BIOS中断功能调用,BIOS中断功能调用方法与DOS系统功能调用相似。 例题:写一个子程序,将内存缓冲区BUF中的字符送到串行通信口PCOM输出。程序如下: PCOM PROC NEAR MOV AH,01 ;功能1是写字符 MOV AL,BUF ;字符送AL中 MOV DX,0 ;用COM1通信口发送 INT 14H ;BIOS功能调用 RET PCOM ENDP BIOS功能调用比DOS功能调用在控制底层方面功能更强大,能完成许多DOS功能调用无法完成的功能。但是需要强调的是,能用DOS功能调用实现的,建议就不要用BIOS功能调用。,知识要点提醒: 对于硬件的访问控制,一般来说有三种方法可以考虑:调用DOS功能调用、调用BIOS功能调用或直接访问硬件。 这三种方法中,DOS功能调用层次最高,需要了解的硬件细节少,往往参数也少,而且兼容性好,即只要能启动DOS,这项功能调用就保证能用。 BIOS调用在层次上低于DOS功能调用而高于直接访问硬件。因它比DOS更接近硬件,故硬件控制功能更强,而且执行速度更快。但是需要了解的硬件细节也更多,而且兼容性也比DOS调用差。 直接访问硬件层次最低,可以控制实现硬件的全部功能,但是需要了解的硬件细节也最多,而且不同机器间若被访问硬件有差异,可能程序不能通用。当需要的功能BIOS中断调用也未提供时,只能直接访问硬件实现。例如:要想编一个播放音乐的程序,只能直接访问硬件实现。,5.4.3 程序正常返回DOS的方法,1. 标准方法 首先将用户程序的主程序定义成一个FAR过程,其最后一条指令为RET,然后在代码段的主程序(即FAR过程)的开始部分,使用如下三条指令即可。 PUSH DS ;保护PSP段地址 MOV AX,0 PUSH AX ;保护偏移地址,2. 非标准方法 在用户的程序中不定义过程段,只在代码段结束之前(即CODE ENDS之前),增加两条语句: MOV AH,4CH INT 21H 则程序执行完后,也会自动返回DOS状态。,5.5 汇编语言程序设计,程序设计步骤: (1) 仔细了解问题的要求。 (2) 制定方案。 (3) 编写程序。 (4) 查错。 (5) 测试。 (6) 形成文件。,顺序结构是一种最简单的程序设计结构形式,只能完成简单的任务程序设计。 CPU执行这种程序时,是以指令的排列顺序逐条执行的。,5.5.1 顺序结构,例题:编写程序,在屏幕上能够显示字符串“GOOD!”。 CODE SEGMENT ASSUME CS:CODE START:MOV AH,2 MOV DL,G INT 21H ;输出字符G MOV DL,O INT 21H ;输出字符O INT 21H ;输出字符O MOV DL,D INT 21H ;输出字符D MOV DL,! INT 21H ;输出字符! MOV AX,4C00H INT 21H ;返回DOS CODE ENDS END START,例题:编写程序,在屏幕上显示字符串“This is a sample program.”。,DATA SEGMENT ;数据段 DA1 DB This is a sample program. DB 0DH,0AH,$ DATA ENDS CODE SEGMENT ;代码段 MAIN PROC FAR ASSUME CS:CODE,DS:DATA START:PUSH DS ;正常返回所需段地址及偏移地址 MOV AX,0 PUSH AX MOV AX,DATA ;送数据段段地址 MOV DS,AX MOV AH,9 ;DOS 9号功能调用,显示字符串 MOV DX,OFFSET DA1 INT 21H RET MAIN ENDP CODE ENDS END START,5.5.2 分支结构 分支结构也叫条件选择结构,可以根据不同情况做出判断和选择,以便执行不同的程序段。 分支结构有“单分支结构”和“多分支结构”两种,多重分支结构是数个单分支结构的组合。,code segment assume cs: code start: mov ah, 1 int 21h cmp al, a jb lab1;小于转 cmp al, z ja lab1;大于转 sub al, 32,mov dl, al mov ah, 2 int 21h lab1: mov ah, 4ch int 21h code ends end start,例题:编写完整程序并调试。从键盘输入一个字符,如果是小写字母,则转换成大写字母并输出。如果不是小写字母,则结束。,例:编写完整程序并调试。从键盘接收一个按键,如果是小写字母,则输出“L”,是大写字母则输出“U”,如果是数字则输出“N”,都不是则输出“*”。,多分支结构,lab4: cmp al,a jb lab1;小于转 cmp al,z ja lab1;大于转 mov dl,L jmp lab3 lab1: mov dl,* lab3: mov ah,2 int 21h;输出 mov ah,4ch int 21h code ends end start,code segment assume cs:code start: mov ah,1 int 21h cmp al,0 jb lab1;小于转 cmp al,9 ja lab2;大于转 mov dl,N jmp lab3 lab2: cmp al,A jb lab1;小于转 cmp al,Z ja lab4;大于转 mov dl,U jmp lab3,5.5.3 循环结构 循环结构就是强制CPU重复执行某一指令集合的一种程序结构,分为“当型”和“直到型”两种。 “当型”循环是先判断条件,若条件为真,则执行循环体;“直到型”循环是先执行循环体,然后判断条件,若条件为真,则继续执行循环体,直到条件为假时退出循环。,例题:编写完整程序,在一行上依次显示26个大写英文字母。,code segment assume cs: code star: mov dl, A mov cx, 26;次数 lab: mov ah, 2 int 21h add dl, 1 loop lab;循环 mov ah, 4ch int 21h code ends end star,例:编写完整程序,在屏幕上输出下面的图形。,9 89 789 6789 56789 456789 3456789 23456789 123456789,data segment buf db 123456789,13,10,24h data ends code segment assume ds:data, cs:code main: mov dx,data mov ds,dx mov cx,9 lea dx,buf+8 mov ah,9 lab: int 21h sub dx, 1 loop lab mov ax, 4c00h int 21h code ends end main,5.5.4 子程序结构 子程序又叫过程,是完成特定功能的程序段,它能够在程序中的其它地方被调用。对于多次重复使用的程序段,也应该编写成子程序,这样既避免了存储空间的浪费,又增加程序间的共享,减小编写程序的工作量。 编写和使用子程序时应注意的几个问题: (1) 子程序如何调用和如何返回。 (2) 子程序的入口信息和出口信息。 (3) 子程序中使用了哪些寄存器,调用之前是否需要保护。 (4) 其它诸如占内存多少、执行时间长短、影响哪些标志、出错如何处理等。,例1:编写完整程序,从键盘输入一个字符,若为F,则调用FIRST子程序;若为S,则调用SECOND子程序,否则显示“INPUT F OR S!”并返回DOS。其中FIRST和SECOND子程序都为近过程。 DATA SEGMENT ST0 DB “INPUT F OR S!“,$ ST1 DB INPUT CHARACTER:$ ST2 DB The First Subroutine!$ ST3 DB The Second Subroutine!$ DATA ENDS CODE SEGMENT ASSUME CS:CODE, DS:DATA MAIN PROC FAR START:PUSH DS MOV AX, 0 PUSH AX MOV AX, DATA MOV DS, AX MOV DX, OFFSET ST1,MOV AH, 09H INT 21H ;提示输入字符 MOV AH, 01H INT 21H CMP AL, F JE SUBF ;为F调用子程序FIRST CMP AL, S JE SUBS ;为S调用子程序 CALL ENTER LEA DX, ST0 MOV AH, 09H INT 21H ;提示输入字符形式 JMP RN SUBF: CALL FIRST JMP RN SUBS: CALL SECOND RN: RET MAIN ENDP,ENTER PROC MOV DL, 0DH MOV AH, 02H INT 21H MOV DL, 0AH INT 21H ;回车换行 RET ENTER ENDP FIRST PROC CALL ENTER LEA DX, ST2 MOV AH, 09H INT 21H RET FIRST ENDP,SECOND PROC CALL ENTER LEA DX,ST3 MOV AH,09H INT 21H RET SECOND ENDP CODE ENDS END START,例2:编写子程序write,把整型数据以十进制形式显示到屏幕上。,该子程序的功能描述是: ;功能:在屏幕上输出整数值 ;入口:AX= 待输出的整数 ;CF= 为0表示输出无符号数,为1表示输出带符号数 ;出口:无 ;破坏寄存器:无,编程提示:,(1)参照高级语言中输出语句的功能,被显示的数据可以是带符号数,范围是-32768+32767;也可以是无符号数,范围是065535,但需要明确是哪一种情况; (2)被输出的数据是带符号数时,符号“-”必须输出,而正号“+”则省略。 (3)输出数据的最大位数是十进制的5位,当计算出5位中的某位是0时,需要判断这个0是否应该输出?输出条件是前面已经输出过非0数字或者这个0是个位数。,w4: mov ax,bx mov dx,0 mov bx,10 div bx;BXBX10 mov bx,ax loop w2;循环 pop di pop si pop dx pop cx pop bx pop ax ret write endp,write proc near push ax;保护寄存器 push bx push cx push dx push si push di mov si,0;记载未输出数据 mov di,ax;保存数据 jnc w1;CF=0? cmp ax,0 jge w1;AX0转 mov dl,- mov ah,2 int 21h neg di;取绝对值,w1: mov bx,10000 mov cx,5;循环次数 w2: mov ax,di mov dx,0 div bx;(DX,AX)BX mov di,dx cmp al,0;商=0? jne w3;非0转 cmp si,0 jne w3 cmp cx,1 jne w4 w3: mov dl,al;输出 add dl,30h mov ah,2 int 21h mov si,1,例3:编写完整程序,计算n!,并把结果输出到屏幕上。其中,输出结果可以调用前面编写的子程序write;n!的计算,编写成递归子程序。 该递归子程序的功能描述是: ;功能:计算n! ;入口:调用前把整数n入栈 ;出口:AX=n!的计算结果 ;破坏寄存器:无,fact proc near push bp mov bp, sp push bx push dx mov bx,bp+4; 取n值 cmp bx,1 jg f1 mov ax,1 jmp f2,f1: mov dx,bx dec dx push dx call fact;调用自身 pop dx mul bx f2: pop dx pop bx pop bp ret fact endp,code segment assume cs:code, ss:s fact proc near push bp mov bp,sp push bx push dx mov bx,bp+4 cmp bx,1 jg f1 mov ax,1 jmp f2,main: mov ax,5 mov bx,ax call write mov ah,2 mov dl,! int 21h mov dl,= int 21h push bx call fact pop bx clc call write mov ax,4c00h int 21h,f1: mov dx,bx dec dx push dx call fact pop dx mul bx f2: pop dx pop bx pop bp ret fact endp,write proc near push ax push bx push cx push dx push si push di mov si,0 mov di,ax jnc w1 cmp ax,0 jge w1 mov dl,- mov ah,2 int 21h neg di,w1: mov bx,10000 mov cx,5 w2: mov ax,di mov dx,0 div bx mov di,dx cmp al,0 jne w3 cmp si,0 jne w3 cmp cx,1 jne w4 w3: mov dl,al add dl,30h mov ah,2 int 21h mov si,1,w4: mov ax,bx mov dx,0 mov bx,10 div bx mov bx,ax loop w2 pop di pop si pop dx pop cx pop bx pop ax ret write endp code ends s segment stack dw 512 dup(0) s ends end main,知识扩展:模块化结构程序设计,模块化技术是大型软件开发的基本技术。模块化的优点是单个的模块易于编写、调试、修改,一个模块可以在多个地方或多个程序中使用,可以直接利用已有的模块,多个程序员可以并行工作。 模块的划分无固定规则,可灵活确定,但应遵循如下原则: (1) 模块间的调用关系尽可能简单。尽量避免从多个入口点进入模块或从多个出口点退出,否则模块不易调试。 (2) 模块间的数据耦合应尽量小,即尽量减少数据传递,对于需要传递参数个数较多的模块,可考虑合并成一个模块。 (3) 模块的大小适中,若一个模块太大,则编写调试困难;若太小,模块间的调用、连接开销则太大,一般一个模块长度在50至500行内为宜。,例题:某系统由A、B两个模块构成,A模块要调用到B模块的一个过程DISP,以显示一个字符。两个模块如下:,模块B: PUBLIC DISP .MODEL SMALL .CODE DISP PROC NEAR MOV DL,A MOV AH,2 INT 21H RET DISP ENDP END,模块A: EXTRN DISP: NEAR .MODEL SMALL .CODE START: CALL DISP MOV AH,4CH INT 21H END START,假设模块A存盘后文件名为A.ASM,模块B存盘后文件名为B.ASM,则可用以下命令行分别汇编,然后链接合并。 MASM A; MASM B; LINK A+B; 最后得到可执行文件A.EXE。执行该文件,可在屏幕上显示字符A。,在这个例子中,两个模块存储模式相同,并且都是用 .CODE伪指令指定代码段,则两个模块内代码段的段名、定位类型、组合类型、类别等都由汇编程序自动生成(分别为:TEXT、WORD、PUBLIC、CODE)。 由于两个段是同名段,且都为PUBLIC组合类型,故链接程序最后将其合并为一个段,因而模块A对模块B内DISP的调用为段内调用。,例题:若采用段间调用,则对上例中的两个模块作如下修改:,模块A: EXTRN DISP:FAR .MODEL SMALL .CODE START: CALL DISP MOV AH,4CH INT 21H END START,模块B: PUBLIC DISP CODE SEGMENT ASSUME CS:CODE DISP PROC FAR MOV DL,A MOV AH,2 INT 21H RET DISP ENDP CODE ENDS END,在这个例子中,由于模块B中代码段的段名与模块A中的不再一致,故两个段是各自独立的代码段,调用成为段间调用,DISP不论在模块A中的外部符号声明还是在模块B中的类型定义,都必须为FAR类型。,练习题,习题1:若x、y、z已定义为字节变量,若x和y各存放一个32位的无符号数(存放顺序是低位字节在先),试写出将x和y相加后结果存入z的程序段。,MOV AX,x ;取被加数x MOV DX,x+2 ADD AX,y ;计算(x+y) ADC DX,y+2 MOV z,AX ;送存计算结果 MOV z+2,DX,习题2:若ARRAY和MAX都定义为字变量,并在ARRAY数组中存放了10个16位无符号数,试编写程序段,找出数组中最大数,并存入变量MAX中。,MOV BX, OFFSET ARRAY MOV AX, BX MOV SI,2 MOV CX,9 LAB:

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论