190 likes | 376 Views
5.3 宏指令语句. 1. 宏指令、宏定义和宏调用 宏指令是源程序中具有独立功能的一段程序代码。在汇编语言中,如果在源程序中需要多次使用同一个程序段,可以将这个程序段定义(宏定义)为一个宏指令,然后每次需要是,即可简单地用宏指令名来代替(称为宏调用),从而避免了重复书写,使源程序更加简洁、易读。 宏定义由 MASM 宏汇编程序提供的伪指令实现,其格式为. …. 宏体. 宏指令名 MACRO [形式参数] ENDM 宏调用的格式为 宏指令名 [实际参数] 这就是说,只要在源程序中写上已定义过的宏指令名就算是调用该宏指令了。
E N D
5.3 宏指令语句 1.宏指令、宏定义和宏调用 宏指令是源程序中具有独立功能的一段程序代码。在汇编语言中,如果在源程序中需要多次使用同一个程序段,可以将这个程序段定义(宏定义)为一个宏指令,然后每次需要是,即可简单地用宏指令名来代替(称为宏调用),从而避免了重复书写,使源程序更加简洁、易读。 宏定义由MASM宏汇编程序提供的伪指令实现,其格式为
… 宏体 宏指令名 MACRO [形式参数] ENDM 宏调用的格式为 宏指令名 [实际参数] 这就是说,只要在源程序中写上已定义过的宏指令名就算是调用该宏指令了。 具有宏调用的源程序被汇编时,每个宏调用将被MASM进行宏展开。宏展开实际上是用宏定义式设计的宏体去代替相应的宏指令,并用实际参数一一取代形参。
由此可见,使用宏的过程共有三步:首先进行宏定义;然后可以进行宏调用;最后,汇编时由MASM进行宏展开。由此可见,使用宏的过程共有三步:首先进行宏定义;然后可以进行宏调用;最后,汇编时由MASM进行宏展开。 [例] 若源程序中多处需要将AL和CL寄存器中的两位压缩型的BCD数相加,并将和送回BL寄存器,则可象下述这样定义宏指令,然后在需要的地方进行调用。 DECADD MACRO ADD AL,CL DAA ENDM 显而易见,这是一个无形式参数的宏定义。
如果对分别存放在任意8位寄存器或存储单元中的两个压缩型的BCD数进行加法运算,则可将上例宏定义改写为如果对分别存放在任意8位寄存器或存储单元中的两个压缩型的BCD数进行加法运算,则可将上例宏定义改写为 DECADD1 MACRO OPR1,OPR2 MOV AL,OPR1 ADD AL,OPR2 DAA MOV OPR1,AL ENDM 这是一个带有两个形式参数的宏定义。宏指令为DECADD1。例如有以下宏调用:
DECADD1 DL, BUFFER DECADD1 AREA1, AREA2 则汇编时进行宏展开,得到以下指令: DECADD1 DL, BUFFER + MOV AL, DL + ADD AL, BUFFER + DAA + MOV DL, AL DECADD1 AREA1, AREA2 + MOV AL, AREA1 + ADD AL, AREA2 + DAA + MOV AREA1, AL 宏扩展后,原来宏体中的指令前面都加上了符号“+”,以示区别。
声明宏体内局部标号的伪指令(LOCAL) LOCAL的作用是声明宏体中的局部标号,以免在宏扩展时,同一个标号在源程序中多次出现,从而产生标号多重定义的错误。LOCAL伪指令必须位于宏体内其它所有语句(包括注释)之前,其格式为: LOCAL 局部标号[,…] 例如下面的宏指令完成将寄存器中的一位十六进制数转换为相应的ASCII码,由于宏体中出现局部标号,因此必须使用LOCAL伪指令对宏体中的局部标号进行声明。 HEXTOASC MACRO REG LOCAL NUM CMP REG,0AH JC NUM ADD REG,07H NUM: ADD REG,30H ENDM
宏指令与子程序的区别 在汇编语言程序设计中,宏指令和子程序都给设计者提供了很大方便。他们都是可被程序多次调用的程序段,并且调用前必须由设计者袭击根据需要按一定格式进行定义。然而,宏指令和子程序由于定义方法和几个是不同,使用中患有许多不同之处,主要是空间和时间的差异。 ⑴ 子程序由CALL指令调用,由RET指令返回,所以汇编后子程序的机器码只占有一个程序段,不管调用多少次均如此,较为节约内存。宏指令在每次宏调用处宏展开时,宏体都要占一个程序段,调用次数愈多,占用内存愈多。因此从内存空间开销来说,子程序优于宏指令。
⑵ 从程序的执行时间来分析,每调用一次子程序都要保护和恢复返回地址(断点)及寄存器内容(现场)等,要消耗较多的时间。宏指令调用时不需要这个过程,执行时间较短。因此,从执行时间来分析,宏指令又优于子程序。 综上所述,当某一需多次访问的程序段较长,访问次数又不是太多时,选用子程序结构较好。当某一需多次访问的程序段较段,访问次数又很频繁时,选用宏指令结构显然要更好些。
DELY TIMER1,TIMER2 MOV DL,30H MOV AH,02H INT 21H DELY TIMER2,TIMER1 MOV DL,36H INT 21H MOV AH,4cH ;返回dos INT 21H CODE ENDS END start ;宏调用举例,通过修改TIMER1和TIMER2实现不同的延时 TIMER1 EQU 0100H TIMER2 EQU 1000H CODE SEGMENT ASSUME CS:CODE start: ;宏定义开始 DELY MACRO DATA1,DATA2 LOCAL LOOP1,LOOP2 PUSH CX PUSH AX MOV CX,DATA1 LOOP1: MOV AX,DATA2 LOOP2: DEC AX JNZ LOOP2 LOOP LOOP1 POP AX POP CX ENDM ;宏定义结束 Macro.asm
5.4 常用系统功能调用和BIOS功能调用 DOS及BIOS功能调用属于软件中断,即可用INT n指令调用的中断,它可分为三部分: ⑴ DOS 中断,占用中断类型号为20H~27H和2FH,其余类型号保留。 ⑵ ROM BIOS 中断,占用中断类型号10H ~1FH。 ⑶ 自由中断,占用中断类型号40H ~FFH,可供系统或应用程序设置开发的中断处理程序用。
1、DOS中断及功能调用 DOS常用的9类中断(20H~27H和2FH)可分为两种: ⑴ DOS专用中断。DOS专用中断是指INT 22H、 INT 23H、 INT 24H 3个中断,属DOS操作时专用,用户不要直接使用。 ⑵ DOS可调用中断。DOS可调用中断是指INT 20H、 INT 21H、 INT 25H、 INT 26H、 INT 27H和INT 2FH 6个中断。这6个中断都供用户直接调用,但都必须要满足一定的入口条件。其中:
① 磁盘读写中断。INT 25H、INT 26H分别用来读和写磁盘上的若干扇区,这实际上是两条BIOS调用。 ② 程序退出中断。INT 20H、INT 27H都为程序的退出命令。 ③ 假脱机打印文件中断。INT 2FH用来实现假脱机打印文件命令PRINT。 ④ 系统功能调用。又称为DOS功能调用,是指 INT 21H 中断。它是可供系统程序和应用程序调用的一个极其重要的中断,内含近百个子功能。
2、系统功能调用 1.系统功能调用方法 DOS启动成功后,INT 21H 的中断向量(中断处理程序的首地址)被初始化在中断向量表中,向量地址为84H87H的4个存储单元内。调用 INT 21H的方法如下: ⑴ 入口参数送相应的寄存器; ⑵ 子功能编号送AH; ⑶ 发出中断请求:INT 21H 2.常用系统调用子功能
⑴ 01H号调用(带回显的键符输入) 1 号子功能是从标准输入设备输入一个字符,并送入寄存器AL,不许入口参数。例如: MOV AH, 01H INT 21H 执行上述指令,系统将扫描键盘,等待有键按下,一旦有键按下,就将键值(相应字符的ASCII码值)读入,并送入AL寄存器,同时将这个字符显示在屏幕上。
⑵ 0AH号调用(字符串输入) 从键盘接收字符串到内存输入缓冲区,要求事先定义一个输入缓冲区,缓冲群诶第一个字节指出缓冲区的字符个数,不能为零。第二个字节保留已用作填写输入的字符实际个数。从第三个字节开始存放从键盘上接收的字符。调用时,要求DS:DX指向输入缓冲区的首地址。键入字符串以回车结束。 例如,从键盘输入一个小于50个字符的字符串数据。其程序设计方法是:
DATA SEGMENT BUF DB 50 DB ? DB 50 DUP(?) DATA ENDS CODE SEGMENT … MOV DX, OFFSET BUF MOV AH, 10 INT 21H … CODE ENDS
⑶ 02H号调用(字符输出显示) 2号功能是将一个字符(一个ASCII码值)输出到标准输出设备(即显示器或打印机)。入口参数为DL寄存器,寄存器DL中存放待输出的字符。例如: MOV DL, ‘A’ MOV AH, 2 INT 21H 即将字符“A”显示在屏幕上或输出到打印机。
⑷ 09H号调用(字符串输出) 9号功能调用是将缓冲区中的一组以“$”结束的字符串送标准输出设备输出(显示器或打印机)。调用前必须将输出缓冲区的首地址送DS:DX。例如: DATA SEGMENT BUF DB ‘HOW DO YOU DO ? $’ DATA ENDS CODE SEGMENT … MOV DX, OFFSET BUF MOV AH, 9 INT 21H … CODE ENDS
3、BIOS中断调用 在IBM-PC机的ROM存储器中包含一些基本输入输出子程序。这些基本输入输出子程序简称为BIOS。它们的功能与DOS中字符I/O功能相似,用户也可通过软件中断方式直接调用。由于BIOS提供的字符I/O功能直接依赖于硬件,因而调用它们比调用DOS字符I/O功能速度更快。例如: ☆键盘输入子程序。调用指令为 INT 16H ☆屏幕显示子程序。调用指令为 INT 10H ☆打印输出子程序。调用指令为 INT 17H