编程实现多字节加法,如S=3B74AC60F8H+20D59E36C1H
DATA SEGMENT
DATA1 DB 0F8H,60H,0ACH,74H,3BH
DATA2 DB 0C1H,36H,9EH,0D5H,20H
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
MOV CX,5 ;设置循环次数
MOV SI,0 ;置位移量初值
CLC ;清进位CF
LOOPER:
MOV AL,DATA2[SI] ;取一个加数
ADC DATA1[SI],AL ;和一个被加数相加,ADC dst,src (dst)<-(dst)+(src)+(CF)
INC SI ;位移量加1
DEC CX ;循环次数减1
JNZ LOOPER ;不等于/非零转移
MOV AH,4CH
INT 21H
CODE ENDS
END START
计算三个字节十六进制数之和:3BH+74H+2CH=?
DATA SEGMENT
BUF DB 3BH,74H,2CH
SUM DB ?
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
MOV AL,BUF ;取第一个数
ADD AL,BUF+1 ;与第二个数相加
ADD AL,BUF+2 ;与第三个数相加
MOV SUM,AL ;存和值
MOV AH,4CH
INT 21H
CODE ENDS
END START
以tab1为首地址存放了200个带符号数,要求将各数求绝对值后存入以tab2为首地址的内存区。
DATA SEGMENT
TAB1 DB 0E7H,0E4H,06H,11H,03H,01H
TAB2 DB 6 DUP(?)
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
MOV CX,6
MOV SI,0
NEXT1:
MOV AL,TAB1[SI]
;比较指令的执行结果将影响状态标志位。例如,若两个被比较的内容相等,则(ZF)=1
;又如,假设被比较的两个无符号数中,前者小于后者(即不够减),则(CF)=1,等等。
CMP AL,0
;JNS正转移
JNS NEXT
;NEG求补指令
NEG AL
NEXT:
MOV TAB2[SI],AL
INC SI
DEC CX
;不等于,非零转移
JNZ NEXT1
MOV AH,4CH
INT 21H
CODE ENDS
END START
在数据段从MYDATA开始的存储单元中分别存放了两个8位无符号数,试比较它们的大小,并将大者传送到MAX单元。可编程如下:
DATA SEGMENT
MYDATA DW 12,15
MAX DW ?
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
LEA BX,MYDATA ;将MYDATA的偏移地址送BX
MOV AX,[BX] ;第一个无符号数送AL
INC BX ;BX指向第二个无符号数
CMP AX,[BX] ;两个数比较
;JNC disp8 (IP)<-(IP)+disp8 (CF)=0 不进位转移
JNC DONE ;若CF=0,则转DONE
MOV AX,[BX] ;否则,第二个无符号数送AL
DONE:
MOV MAX,AX
MOV AH,4CH
INT 21H
CODE ENDS
END START
计算4609+3857=?
本例要求实现十进制多位数的加法,假设被加数的每一位数都以ASCII码形式存放在内存中,低位在前,高位在后。另外留出4个存储单元,以便存放相加所得的结果。
DATA SEGMENT
STRING1 DB 39H,30H,36H,34H
STRING2 DB 35H,37H,38H,33H
SUM DB ?,?,?,?
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
LEA SI,STRING1 ;(SI)<-被加数地址指针
LEA BX,STRING2 ;(BX)<-加数地址指针
LEA DI,SUM ;(DI)<-结果地址指针
MOV CX,4 ;(CX)<-循环次数
CLC ;清进位标志CF
NEXT:
MOV AL,[SI] ;取一个字节被加数
ADC AL,[BX] ;与加数相加 ADC dst,src (dst)<-(dst)+(src)+(CF)
AAA ;ASCII码调整
MOV [DI],AL ;送存
INC SI
INC BX
INC DI
DEC CX
JNZ NEXT ;如不为零,转NEXT
MOV AH,4CH
INT 21H
CODE ENDS
END START
汇编语言源程序的组织结构
汇编语言源程序采用的是分段结构,即一个汇编语言源程序由若干段组成(一般由数据段和代码段组成),每一个段以SEGMENT语句开始,以ENDS语句结束,整个程序的结尾是END语句。
在代码段中下面的内容是不可缺少的:
(1) 定义段(使用SEGMENT/ENDS语句定义)
(2) 约定段寄存器和段的关系(即物理段和逻辑段的关系,使用一个或多个ASSUME语句实现)
(3) 装填段寄存器(只装填数据型段寄存器)
(4) 设置返回DOS的方法
例如:
MYDARA SEGMENT ; 定义数据段起始语句
… … ; 定义数据
MYDATA ENDS ; 定义数据段终止语句
MYCODE SEGMENT ; 定义代码段起始语句
ASSUME CS:MYCODE,DS:MYDATA ; 约定段寄存器和段的关系
START:
MOV AX,MYDATA ; 装填相应的段寄存器
MOV DS,AX
… … ; 完成所需功能的程序段
MOV AH,4CH ; 设置返回DOS
INT 21H
MYCODE ENDS ; 定义代码段终止语句
END START ; 程序结束
汇编语言语句的类型和格式
1.语句分类
① 指令性语句:也称指令语句,指令系统的指令,汇编后产生目标代码。
② 指示性语句:也称伪指令语句,告诉汇编程序如何汇编,汇编后不产生目标代码。
③宏指令语句:自定义语句,由指令语句和伪指令语句组成的指令集合,不展开时不产生目标代码。
2. 语句格式
汇编语言是由一条条的语句组成的,其每条语句的格式如下:
[名字][语句前缀]助记符[操作数][;注释]
其中带方括号的部分表示任选项,既可以有,也可以没有。
(1)名字
“名字”是语句的符号地址,对于指令语句,“名字”称为标号,其后必须加冒号“:”;对于伪指令语句“名字”可以是变量名、段名、过程名等,其后不能加冒号“:”。
eg:LOOPER:MOV AL, DATA2[SI]
DATA1 DB 0F8H, 60H, 0ACH, 74H, 3BH
DATA SEGMENT
“名字”一般都有三个属性:段属性、偏移属性和类型属性。
① 段属性:表示“名字”所在段的起始地址(即段地址)。
② 偏移属性:表示“名字”所在段的起始地址到定义该“名字”的地址之间的字节数(即偏移量)。偏移量是一个16位无符号数。
③ 类型属性:表示该名字的数据或地址的类型。
(2)助记符
在指令语句中,表示该指令语句的操作码,在伪指令语句中称为定义符,它们指出其语句的功能。
(3) 操作数
操作数即为操作的对象。在指令语句中,可能有单操作数或双操作数,也可能无操作数或隐含操作数;而在伪指令中可能有更多个操作数。当操作数不止一个时,相互之间应该用逗号隔开。
可以作为操作数的有:常数、寄存器、标号、变量和表达式等。
1)常量:是指令在中出现的哪些固定值,可以分为数值常数和字符串常数两类。
2) 寄存器:8086/8088CPU的寄存器可以作为指令的操作数。
3) 变量:是存储器中某个数据区的名字,因此在指令中可以作为存储器操作数。
4) 表达式:使用运算符把常数、寄存器、标号、变量等连接起来的运算式。
① 表达式分为数值表达式和地址表达式两种。
② 表达式中常用的运算符有以下几种:
算术运算符:+、-、*、/和MOD(模除,即两个整数相除后取余数)等。
逻辑运算符:AND、OR、XOR、NOT等。
关系运算符:EQ、NE、LT、GT、LE、GE等。
分析运算符:SEG、OFFSET、TYPE、SIZE、
LENGTH等。
合成运算符:PTR、THIS、SHORT等。
其它运算符: :、LOW、HIGH等
(4)注释
注释是对汇编语句的功能或汇编程序的说明。
mov ax, 4eq3 ;4eq3为假,(ax)<-0000h
mov ax, 4ne3 ;4ne3为真,(ax)<-0ffffh
mov ax, data
mov ax, seg data
type, length, size
汇编语言源程序的上机过程
上机环境
上机过程
(1) 编辑程序
DOS环境下用EDIT编辑器
WINDOWS环境下用记事本
(2)汇编源程序
宏汇编程序 MASM.EXE 或小汇编程序ASM.EXE
汇编程序主要有以下功能:
① 检查源程序中语法错误,给出错误提示信息
② 产生目标文件(.OBJ)、列表文件(.LST)及交叉引用文件(.CRF)
③ 展开宏指令
MASM宏汇编的提示信息及回答
(3) 连接目标文件
通过 LINK.EXE 程序实现
① 将多模块连接,产生一个.EXE文件
② 连接库文件(.LIB)及产生连接映象文件(.MAP)
LINK的提示信息及回答
(4) 运行程序
当我们建立了可执行文件后,就可以直接在DOS下执行该程序。
程序调试
DEBUG是一种面向汇编语言的动态调试工具,共有19条命令。DEBUG提供了可以跟踪、测试程序的环境和条件,使编辑者能够对.EXE和.COM文件的执行进行动态跟踪调试,能够较快地查找出文件的错误和检查程序的运行结果。
还可以利用DEBUG直接编写一段小的汇编程序,并进行调试和运行。
DEBUG 常用命令
-A[ 起始地址]↙ 汇编并保存一段指令语句
-U[ 起始地址]↙ 反汇编
-T[=起始地址]↙ 单步执行(执行一条语句)
-R[ 寄存器]↙ 显示或修改寄存器内容
-D[存储单元逻辑地址]↙ 显示存储单元
(80个字节/次)
-N[文件名]↙ 定义文件
-L↙ 装入文件
例如:
DATA SEGMENT
NUM DB 82H,68H,88H
SUM DB ?
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START: MOV AX,DATA
MOV DS,AX
MOV BX,OFFSET NUM
MOV AL,[BX]
INC BX
ADD AL,[BX]
INC BX
ADD AL,[BX]
MOV SUM,AL
MOV AH,4CH
INT 21H
CODE ENDS
END START
添加堆栈段
stack segment stack stack
buf db 20 dup(?)
stack ends
5.3 伪指令语句
宏汇编程序MASM提供了约几十种伪指令,其中有一些伪指令小汇编ASM不支持,例如宏处理伪指令等。根据伪指令的功能,大致可以分为以下几类:
⒈方式伪指令
⑴ .8086。汇编程序将在8086/8088方式下操作。
⑵ .386。汇编程序将在80386方式下操作。
3.数据定义伪指令
数据定义伪指令的一般格式为:
[变量名] 伪操作符 操作数[,操作数…]
⑴ DB 定义变量的类型为BYTE,给变量分配字节或字节串操作数。
⑵ DW 定义变量的类型为WORD,给变量分配字操作数。
⑶DD 定义变量的类型为DWORD,给变量分配双字操作数。
除了常数、表达式和字符串外,问号“?”也可以作为数据定义伪指令的操作数,此时仅给变量保留相应的存储单元,而不赋与变量某个确定的初值。
当同样的操作数重复多次时,可用重复操作符“DUP”表示,其形式为:
n DUP(初值[,初值…])
可以嵌套使用:
ARR DB 100 DUP(3 DUP(8), 6)
例: 画图说明下列伪指令所定义的数据在内存中的存放形式。
ARV1 DB 3+4,43H,-2
ARV2 DW 474FH,1,?
COUNT EQU 2
ARV3 DB 2DUP(1,COUNT DUP(2))
ARV4 DD ARV3
ARV5 DB ‘AB’
ARV6 DW ‘AB’
解:假设此数据段的段地址为
1234H
,即
DS
=
1234H
,则有:
DATA DB 101,0F0H ;存入65H,F0H
EXPR DB 2*8+7 ;存入17H
STR DB 'WELCOME' ;存入8个字符的ASCII码值
AB DB 'AB' ;存入41H、42H
BA DW 'AB' ;存入42H、41H
ABDD DD 'AB' ;存入42H、41H,00、00
OFFAB DW AB ;存入变量AB的偏移地址
ADRS DW STR,STR+3,STR+5 ;存入3个偏移地址
TOTAL DD DATA ;先存DATA的偏移地址,再存段地址
下面列出几个错误的数据定义伪指令语句。
ERROR1: DW 99 ;变量名后有冒号
ERROR2: DB 25*90 ;字节型变量的操作数超过255
ERROR3: DD '1234' ;超过2个字符的字符串变量只能用DB定义
2. 符号定义伪指令
⑴ EQU(赋值伪指令)
名字 EQU 表达式
⑵=(等号伪指令)
名字=表达式
⑶ LABEL(类型定义伪指令)
名字 LABEL 类型
注意:
EQU与=类似,但EQU不能对同一符号重复定义。
count = 100
mov cx, count
……
count = count – 20
mov bx, count
4.段定义伪指令
段定义伪指令的用途是在汇编语言源程序中定义逻辑段,常用的段定义伪指令有SEGMENT/ENDS和ASSUME等
⑴ SEGMENT/ENDS 伪指令
段名 SEGMENT [定位类型][组合类型][‘类名’]
段名 ENDS
① 定位类型。定位类型给出实际段起点的类型。它有PAGE(页类型)、PARA(节类型)、WORD(字类型)、BYTE(字节类型)四种类型。其中PARA为默认值。
例:
DATA SEGMENT
NUM DB 82H,68H,88H
SUM DB ?
DATA ENDS
STACK SEGMENT STACK STACK
BUF DB 20 DUP(?)
STACK ENDS
CODE SEGMENT BYTE
ASSUME CS:CODE,DS:DATA
START: MOV AX,DATA
MOV DS,AX
……
MOV AH,4CH
INT 21H
CODE ENDS
END START
BYTE: 从字节开始
WORD:从字边界开始
PARA,从节边界开始, 1节=16B
PAGE: 从页边界开始, 1页=256B
② 组合类型。组合类型在多模块程序设计中表示该段和其它同名段间的组合连接方法。组合类型有PUBLIC、COMMON、AT、MEMORY、STACK等。
③类名。类名是程序员任选的一个字符串,使用时必须用单引号括起来。其作用是在连接时决定各逻辑段的装入顺序。
⑵ ASSUME伪指令
它是用来说明逻辑段和物理段关系的伪指令,即告诉汇编程序在指令执行期间内存的哪一段是数据段,哪一段是堆栈段,哪一段是代码段。
ASSUME 段寄存器名:段名[,段寄存器名:段名,…]
5.过程定义伪指令
过程名 PROC[NEAR/FAR]
……
RET
……
过程名 ENDP
注意:
6.模块定义与连接伪指令
表示源程序到此结束,指示汇编程序停止汇编。
说明本模块中某些符号是公共的,能被其他模块访问
说明本模块中某些符号是外部的,由别的模块中定义的,定义时需加PUBLIC
5.2汇编语言和DOS操作系统的接口
1. 用户程序在存储器中的位置2.用户程序的装入
完成以下操作:
以便存放要执行的 .exe 文件。
(Program Segment Prefix)
◢ 程序段前缀大小100H,
即256个字节。
◢ 存放执行过程中的控制信息。
◢ PSP最开始的两个字节CD20,
是一条 INT20H指令。
DSEG SEGMENT
STRING1 DB 1,2,3,4,5
DSEG ENDS
ESEG SEGMENT
STRING2 DB ?
ESEG ENDS
SSEG SEGMENT STACK ‘STACK’
DW 10 DUP(?)
SSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS:DSEG
ASSUME ES:ESEG,SS:SSEG
START: MOV AX,DSEG
MOV DS,AX
MOV AX,ESEG
MOV ES,AX
LEA SI,STRING1
LEA DI,STRING2
MOV CX,5
CLD
REP MOVSB
MOV AH,4CH
INT 21H
CSEG ENDS
END START
3.返回DOS的方法
执行用户程序后,若要返回 DOS状态,即在屏幕上出现DOS提示符,等待输入新的命令,应在用户程序的最后安排完成此功能的程序段。
为了保证用户程序执行完后,能回到DOS,可使用如下两种方法:
(1)非标准方法:调用INT21H的4CH功能,例如:
MOV AH,4CH
INT 21H
(2) 标准方法:借用PSP首单元的INT20H返回DOS。
这种方法较麻烦。由于执行INT 20H的前提是CS:IP必须指向PSP首单元,否则执行INT20H反而会造成死机,因此在.EXE文件汇编格式中,不能直接执行INT20H。用下列方法可使在需返回DOS时,CS:IP指向PSP首单元。
① 把主程序定义成一个远过程。即:
过程名 PROC FAR
…
RET
过程名 ENDP
② 在给DS、ES赋初值之前,用下列三条指令,把PSP首单元的逻辑地址压入堆栈,即
PUSH DS ;PSP段地址压栈
MOV AX,0 ;或用XORAX,AX指令
PUSH AX ;PSP段首单元的偏移地址
;压栈(偏移地址为0000H)
③ 采取了以上措施之后,程序在返回DOS的时候,执行一条RET指令即可返回DOS。因为这条RET指令是远过程中的RET指令,它将从栈顶弹出四个字节,即把PSP首单元的逻辑地址反弹到CS:IP之中,于是CPU就自动从PSP首单元取出INT20H,执行它返回DOS。
例如:
DATA SEGMENT
NUM DB 82H,68H,88H
SUM DB ?
DATA ENDS
CODE SEGMENT
MAIN PROC FAR
ASSUME CS:CODE,DS:DATA
START: PUSH DS
XOR AX,AX
PUSH AX
MOV AX,DATA
MOV DS,AX
LEA BX, NUM
MOV AL,[BX]
INC BX
ADD AL,[BX]
INC BX
ADD AL,[BX]
MOV SUM,AL
RET
MAIN ENDP
CODE ENDS
END START
4.数据的输入与输出(DOS功能调用)
微型计算机系统为汇编用户提供了两个程序接口来使用计算机的硬件资源,一个是DOS功能调用,另一个是ROM中的BIOS(basicinput/output system) 功能调用。DOS功能调用和BIOS功能调用都是由一系列的服务子程序构成的,但调用与返回不是使用子程序调用指令CALL和返回指令RET,而是通过软中断指令INT n和中断返回指令IRET调用和返回的。
软中断(INTn指令)可分为三部分:
① ROM BIOS中断,占用类型号为10H~1FH。
② DOS中断,占用类型号为20H~3FH。目前使用的有20H~27H和2FH,其余类型号保留。
③ 自由中断,占用类型号为40H~FFH,可供系统或应用程序设置开发的中断处理程序用。
1)DOS中断及功能调用
目前DOS常用的9类中断(20H~27H和2FH)分为两种:
① DOS专用中断:INT22H、INT23H和INT24H,用户不能使用。
② DOS可调用中断:INT20H、INT27H(程序退出); INT25H、INT26H(磁盘R/W中断);INT2FH(假脱机打印文件);INT21H(系统功能调用)。
2)BIOS中断调用
BIOS中断功能依功能分为两种,一种为系统服务程序,另一种为设备驱动程序。其中中断类型号为10H、16H和17H的是显示器、键盘和打印机的驱动子程序。
①键盘输入子程序:INT16H。
②显示输出子程序:INT10H。
③打印输出子程序:INT17H。
3)DOS及BIOS功能调用方法
对于所有的功能调用,使用时一般需要经过以下三个步骤:
① 子程序入口参数送相应寄存器。
②子程序编号(功能号)送AH寄存器:
MOV AH,功能号。
③发中断请求:
INT n
(系统功能调用使用INT 21H指令)。
4)系统功能调用
系统功能调用是指INT21H中断。它是可供系统程序和应用程序调用的一个极其重要的中断,内含近百个已经标准化了的系统调用子功能。它是构成操作系统内核的主要成分。
这里我们主要介绍他的几个成用的功能。如下表所示。
INT21H 常用功能介绍
(1)键盘输入(1#功能)
功能: 键盘输入一个字符,将其ASCII码存放于AL,并在屏幕上显示该字符
输入字符ASCII码®AL
MOV AH,01H
INT 21H
(2)字符显示(2#功能)
功能:在屏幕上显示任意单个字符
待输出字符ASCII码®DL
MOV DL,‘A’
MOV AH,2
INT 21H
(3)字符串显示(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
(4)字符串输入(10#功能)
功能: 键盘输入一串字符存至存储区
存储区起始单元地址(段地址:偏移量)®(DS:DX) 存储区特点:
首字节为存储区最大长度M(1~255);
第二字节存放输入字符串的实际长度;
第三字节以后为用户输入内容(含结束标识回车的ASCII码0DH
例 从键盘输入一串字符,个数小于50
其程序设计方法是:
DATA SEGMENT
BUF DB 50
DB ?
DB 50 DUP(?)
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START:……
LEA DX, BUF
MOV AH, 10
INT 21H
……
CODE ENDS
END START
5.4 宏指令及其使用
1.宏指令、宏定义和宏调用
宏指令是源程序中具有独立功能的一段程序代码。在汇编语言中,如果在源程序中需要多次使用同一个程序段,可以将这个程序段定义(宏定义)为一个宏指令,然后每次需要的时候,即可简单地用宏指令名来代替(称为宏调用),从而避免了重复书写,使源程序更加简洁、易读。
宏定义由MASM宏汇编程序提供的伪指令实现。
1. 宏定义
宏指令名 MACRO[形式参数]
ENDM
2. 宏调用
宏指令名 [实际参数]
这就是说,只要在源程序中写上已定义过的宏指令名就算是调用该宏指令了。
3. 宏展开
具有宏调用的源程序被汇编时,每个宏调用将被MASM进行宏展开。
宏展开实际上是用宏定义时设计的宏体去代替相应的宏指令,并用实际参数一一取代形式参数。
由此可见,使用宏的过程共有三步:首先进行宏定义;然后可以进行宏调用;最后,汇编时由MASM进行宏展开。
[例] 若源程序中多处需要将AL和CL寄存器中的两位压缩型的BCD数相加,并将和送回CL寄存器,则可象下述这样定义宏指令,然后在需要的地方进行调用。
DECADD MACRO
ADD AL,CL
DAA
MOV CL,AL
ENDM
显而易见,这是一个无形式参数的宏定义。
如果对分别存放在任意8位寄存器或存储单元中的两个压缩型的BCD数进行加法运算,则可将上例宏定义改写为
DECADD1 MACRO OPR1,OPR2
MOV AL,OPR1
ADD AL,OPR2
DAA
MOV OPR1,AL
ENDM
例如有以下宏调用,如何展开呢?
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
2.宏指令与子程序(过程)
在汇编语言程序设计中,宏指令和子程序都给设计者提供了很大方便。他们都是可被程序多次调用的程序段,并且调用前必须由设计者根据需要按一定格式进行定义。然而,宏指令和子程序由于定义方法和其格式不同,因此,使用中有许多不同之处,主要是空间和时间的差异。
⑴ 子程序由CALL指令调用,由RET指令返回,所以汇编后子程序的机器码只占有一个程序段,不管调用多少次均如此,较为节约内存。宏指令在每次宏调用处宏展开时,宏体都要占一个程序段,调用次数愈多,占用内存愈多。因此从内存空间开销来说,子程序优于宏指令。
⑵ 从程序的执行时间来分析,每调用一次子程序都要保护和恢复返回地址(断点)及寄存器内容(现场)等,要消耗较多的时间。宏指令调用时不需要这个过程,执行时间较短。因此,从执行时间来分析,宏指令又优于子程序。
综上所述,当某一需多次访问的程序段较长,访问次数又不是太多时,选用子程序结构较好。当某一需多次访问的程序段较短,访问次数又很频繁时,选用宏指令结构显然要更好些。