950 likes | 1.13k Views
第 3 章 80x86 汇编语言程序设计 ( 下 ). 3.5 分支结构程序设计. 分支结构是指计算机根据实际情况或条件,作出判断和选择,转而执行不同的程序段的一种程序结构。. Y. N. N. 条件. 条件. Y. 程序段. 程序段 B. 程序段 A. 多路分支结构 根据某个控制字的各“位”状态实行多路转移. 多路条件测试. ……. 程序段 2. 程序段 1. 程序段 n. 3.5.1 无条件转移指令 JMP. 1、 段内转移. 格式1: JMP SHORT OPR ;段内相对短转移
E N D
3.5 分支结构程序设计 分支结构是指计算机根据实际情况或条件,作出判断和选择,转而执行不同的程序段的一种程序结构。 Y N N 条件 条件 Y 程序段 程序段B 程序段A
多路分支结构 根据某个控制字的各“位”状态实行多路转移 多路条件测试 …… 程序段2 程序段1 程序段n
3.5.1无条件转移指令 JMP 1、段内转移 格式1:JMP SHORT OPR;段内相对短转移 操作1:IP<--(IP)+disp8 说明:转移范围-128字节至+127字节,操作数OPR为段内某个标号。 段内相对短转移示例 指令JMP SHORT ADDT 存放在CS:0200H 中, 标号ADDT对于IP指针的偏移量为1DH, 则转移地址为0202H+001DH=021FH JMP SHORT ADDT 0200 E8 … 1 1D ADDT: MOV AL, 40H 2 ADD AL, BL +1DH 021F B0 0220 1D
格式2:JMP OPR JMP NEAR PTR OPR;段内相对近转移 操作2:IP<--(IP)+disp16 说明:转移范围-32KB至+32KB, 操作数OPR为段内某个标号。 格式3:JMP WORD PTR OPR;段内间接转移 操作3:IP<--(OPR) 说明:OPR是基址/变址寄存器或存储器操作数。 段内间接转移示例 ADDRESS DW 2000H ;定义转移地址 ... LEA SI, ADDRESS ;偏移量-->SI ... JMP WORD PTR[SI];转移到CS:2000
2、段间转移 格式4:JMP FAR PTR OPR;段间直接转移 操作4:IP<--OAopr CS<--(CS)opr C1段 EA OP码 段间直接转移示例 50 新IP=0250H ;代码段C1 02 …… 00 新CS=2000H JMP FAR PTR NEXT 20 …… ;代码段C2 C2段 20000H …… NEXT: MOV AL,10H … NEXT 20250H
格式5:JMP DWORD PTR OPR;段间间接转移 操作5:IP<--((DS)*16+OPR) CS<--((DS)*16+OPR+2) 段间间接转移示例 JMP DWORD PTR [4000H] 设(DS)=1000H (14000H)=0010H (14002H)=5000H 执行后 (CS)=5000H (IP)=0010H
3.5.2 条件转移指令 格式:J条件 标号 操作:测试条件,若满足,则跳转到标号处执行, 即 IP<--(IP)+disp8 ; 否则,执行后续指令 说明:根据上一条指令所设置的条件码判别测试条件 转移范围在-128到+127字节
条件转移指令(1) 操作符 功能 测试条件 JC 进位标志为1转移 CF=1 JNC 进位标志为0转移 CF=0 JZ/JE 等于0/相等转移 ZF=1 JNZ/JNE 不等于0/不相等转移 ZF=0 JS 符号标志为1转移 SF=1 JNS 符号标志为0转移 SF=0 JO 溢出转移 OF=1 JNO 无溢出转移 OF=0 JP/JPE 偶状态转移 PF=1 JNP/JPO 奇状态转移 PF=0 JCXZ CX=0转移 CX=0 JECXZ ECX=0转移 ECX=0
条件转移指令(2) A-B 比较情况 无符号数 有符号数 指令 判断条件 指令 判断条件 A>B JA ZF=0,CF=0 JG SF=OF JNBE JNLE 且ZF=0 A>=B JAE ZF=1或 JGE SF=OF JNB CF=0 JNL 或ZF=1 A<B JB ZF=0,CF=1 JL SF<>OF JNAE JNGE 且ZF=0 A<=B JBE ZF=1或 JLE SF<>OF JNA CF=1 JNG 或ZF=1
条件转移指令示例1 将X中十六进制的ASCII码转换成其所对应的数值,存放到HEX中。如‘A’应转换为10。 注意ASCII中‘0’~‘9’是30H~39H,’A’~’F’是41H~46H MOV AH, X CMP AH, 39H JBE NEXT ;≤39H则转 SUB AH, 7 ;是‘A’--’F’,减7 NEXT: SUB AH, 30H ;减30H MOV HEX, AH
条件转移指令示例2 CMP AX, 0FFFFH JLE P3 CMP AX,1 JL P2 MOV AX, 1 JMP DONE P2: MOV AX, 0 JMP DONE P3: MOV AX,-1 DONE: Y AX≤(-1) N N Y AX<1 AX<--1 AX<--0 AX<--(-1) 如果条件转移目标地址超出-128~+127的范围怎么办?
3.5.3 分支结构程序设计 1、比较/转移 利用比较和条件转移指令实现两路分支。 比较结果记录在某些标志位中,条件转移指令 根据约定的条件进行对照,满足条件时转移,不满 足条件时不转移。 2、跳转表转移 利用跳转表实现多路分支。 比较/转移指令可嵌套,但程序结构复杂, 跳转表可使程序结构清晰。 教材上的例子请看P99中的例3.18和例3.19,上机实现例3.18程序。
有一个首地址为ARRAY的N字数组,将其中正数的个数放在DI中,0的个数放在SI中,负数个数放在AX中有一个首地址为ARRAY的N字数组,将其中正数的个数放在DI中,0的个数放在SI中,负数个数放在AX中 注意:负数个数=N-DI-SI
MOV CX, N MOV BX, 0 ;初始化 MOV DI, BX ; 正数个数计数器初始化 MOV SI, BX ; 0的个数计数器初始化 AGAIN:CMP WORRD PTR ARRAY[BX], 0 ;数组当前元素与0比较 JLE LEEQ;小于等于0转移 INC DI ;正数计数 JMP NEXT LEEQ: JL NEXT;小于0转移 INC SI ;0计数 NEXT: ADD BX, 2 ;数组表指针指向下一元素 DEC CX JNZ AGAIN MOV AX, N ;负数个数=N-DI-SI SUB AX, DI SUB AX, SI
设字节单元N1、N2中存放无符号数 (1)若两个均是偶数,则分别加1后送D1 、D2中 (2)若两个均是奇数,则直接送D1 、D2中 (3)若一个是奇数,一个是偶数,则把奇数送D1,偶数送D2中 AL<--(N1),AH<--(N2) 注意:根据条件,当N1是奇数时,无论N2是奇数还是偶数,都只需直接送D1、D2 偶 奇 (AL)0=0 偶 奇 (AH)0=0 (AL) (AH) AL<--(AL)+1 AH<--(AH)+1 D1<--(AL),D2<--(AH)
程序如下: MOV AL, N1 MOV AH, N2 TEST AL, 01H ;测试 N1的奇偶 JNE ENDO;N1为奇数 TEST AH, 01H ;测试 N2的奇偶 JNE L1 ;N2是奇数,转移 INC AL ;两个均是偶数 INC AH JMP ENDO L1: XCHG AL, AH ;N1是偶数, N2是奇数 ENDO: MOV D1, AL ;存放结果 MOV D2, AH 转上页
利用跳转表实现多路分支 跳转表是在某一内存区域顺序排列的一组有规律的入口地址。 如是段内分支,每个地址占两个单元(IP的值) 如是段间分支,每个地址占4个单元(CS:IP的值) TABLE SUB1 TABLE SUB1 SUB2 SUB3 SUB2 IP IP IP CS IP IP CS 段内转移 段间转移
根据AL中哪一位为1(从低位到高位)把程序转移到8个不同的程序分支去根据AL中哪一位为1(从低位到高位)把程序转移到8个不同的程序分支去 .CODE …… ROUTINE_1: MOV AX,0 …… ROUTINE_2: CMP AL, 3 …… …… ROUTINE_8: CLI .DATA TABLE DW ROUTINE_1 DW ROUTINE_2 DW ROUTINE_3 DW ROUTINE_4 DW ROUTINE_5 DW ROUTINE_6 DW ROUTINE_7 DW ROUTINE_8
用变址寻址方式 CMP AL, 0 JE DONE MOV SI, 0 L: SHR AL, 1 JNB NOT_YET ; CF=0或ZF=1跳转 JMP TABLE[SI] NOT_YET: JZ DONE ADD SI, TYPE TABLE ;Type Table=2 JMP L DONE: …… 用寄存器间接寻址与基址变址寻址该如何做?
在附加段中有一个从小到大排序的无符号数字数组,其首地址在DI中,数组的第一个单元存放数组长度。要求在数组中查找(AX),如找到,CF=0,并在SI中给出该元素在数组中的偏移地址;如未找到,CF=1。在附加段中有一个从小到大排序的无符号数字数组,其首地址在DI中,数组的第一个单元存放数组长度。要求在数组中查找(AX),如找到,CF=0,并在SI中给出该元素在数组中的偏移地址;如未找到,CF=1。 • 算法:在R数组中查找K,采用折半查找法 • LOW1, HIGHN; • 若LOW>HIGH,则查找失败,置CF=1,退出程序。否则,计算中点:MID(LOW+HIGH)/2; • (3) K与R[MID]比较。若=R[MID],则查找成功,程序结束; • 若K<R[MID]则转(4);若K>R[MID],则转(5); • (4) HIGHMID-1,转(2); • (5) LOWMID+1,转(2)。
CMP AX, ES:[DI+2] ;与第一个数比较 JA CHK_LAST ;(AX)>(ES:[DI+2]) 转 LEA SI, ES:[DI+2] JE EXIT ;相等,找到,就是第一个数 STC ; 小于第一个数,失败 JMP EXIT CHK_LAST:MOV SI, ES:[DI] ;取数组长度 SHL SI, 1 ; 长度*2(DW型) ADD SI, DI CMP AX, ES:[SI] ; 与最后的数比较 JB SEARCH ; 小于则转 JE EXIT ; 相等则结束 STC ; 大于最后一个,失败 JMP EXIT
SEARCH: MOV LOW_IDX, 1 ; 给LOW赋初值 MOV BX, ES:[DI] ; 取数组长度 MOV HIGH_IDX, BX ; 给HIGH赋初值 MOV BX, DI ; BX中放首地址 MID: MOV CX, LOW_IDX MOV DX, HIGH_IDX CMP CX, DX JA NO_MATCH ; LOW>HIGH,失败 ADD CX, DX SHR CX, 1 ; 折半 MOV SI, CX SHL SI, 1 ; *2 (DW型) COMPARE:CMP AX, ES:[BX+SI] ; 与中间数比较 JE EXIT ; 相等,找到
JA HIGHER ; 大于中间数,转 DEC CX MOV HIGH_IDX, CX ; 调整查找区间到前半部分 JMP MID HIGHER: INC CX MOV LOW_IDX, CX ; 调整查找区间到后半部分 JMP MID NO_MATCH: STC EXIT: ……
3.6 循环结构程序设计 任务需要重复执行某一程序段,这种情况采用循环结构来实现。 初始化 初始化 N 控制部分 循环体 Y 修改部分 循环体 N 控制部分 修改部分 Y
3.6.1 循环指令 格式:指令码 标号; (CX中存放循环次数) 操作符 操 作 功 能 LOOP CX<--(CX)-1 循环 若(CX)<>0,则循环 LOOPZ CX<--(CX)-1 当CX不为零且 LOOPE 若(CX)<>0且ZF=1,则循环 相等时循环 LOOPNZ CX<--(CX)-1 当CX不为零且 LOOPNE 若(CX)<>0且ZF=0,则循环 不相等时循环
循环指令示例1 求长度为10的字节数组ARRAY之和,并将和存入TOTAL中 LEA SI, ARRAY ;数组首地址-->SI MOV CX, 10 ;数组长度-->CX MOV AX, 0 AGAIN: ADD AL, [SI] ;求数组和 ADC AH, 0 INC SI ;修改指针 LOOP AGAIN MOV TOTAL, AX ;存和 其中 语句 LOOP AGAIN相当于: DEC CX JNZ AGAIN
循环指令示例2 在某一字节串中寻找第一个非0字节 设串首地址在DI中,串末地址在BX中 SUB BX, DI ;串长度在BX中 INC BX MOV CX, BX ; 串字节数-->CX DEC DI AGAIN: INC DI ;修改指针 CMP BYTE PTR [DI], 0 ;串元素=0? LOOPZ AGAIN ;循环查找 JNZ FOUND ;找到非0字节跳转 …… FOUND:
3.6.2 串操作指令 串——存储器中一序列字或字节单元,单元中的内 容是字符或数据 串操作——对序列字或字节单元中的内容进行某种 操作 串操作指令有7条: 1、MOVS——串传送指令 2、CMPS——串比较指令 3、SCAS——串扫描指令 4、LODS——装入串指令 5、STOS——存储串指令 6、INS——串输入 7、OUTS——串输出
说明: 每条指令有三种形式,分别对应于字节操作、 字操作和双字操作 如 MOVSB 字节操作 MOVSW 字操作 MOVSD 双字操作 与此配合使用的指令前缀有: REP 重复 REPE/REPZ 相等/为零则重复 REPNE/REPNZ 不相等/不为零则重复
例:将字节串从源区传送到目的区 源区首偏址-->SI 目的区首偏址-->DI,串长-->CX Y CX=0 N 结束 按SI所指取一字节 按DI所指存此字节 (SI)+1-->SI 用一般传送指令实现 的流程图 (DI)+1-->DI (CX)-1-->CX
源区首偏址-->SI 目的区首偏址-->DI 串长-->CX,0-->DF Y 源区首偏址-->SI 目的区首偏址-->DI 串长-->CX,0-->DF CX=0 N 串传送指令 结束 带前缀REP的 串传送指令 (CX)-1-->CX 用带前缀的串传送指令实现的流程图 用串传送指令实现 的流程图
使用串操作指令时微处理器设计有若干约定: 1、源串地址由DS:SI指定 目的串地址在ES:DI中 2、串长送CX寄存器 3、设置方向标志位DF(在EFLAG寄存器中) 当DF=0(指令CLD)时地址为增量修改 (+1 或 +2 或 +4) 当DF=1(指令STD)时地址为减量修改 (-1 或 –2 或 -4)
方向标志对应的指针移动示意 低地址方向 ‘A’ ... 源串 ‘A’ ‘J’ … 高地址方向 1 n 源串 n 1 ‘J’ ... 目的串 … 目的串 正向传送 反向传送 DF=0 DF=1
符号 功能 操作 相关前缀 MOVS 串传送 ES:DI<--(DS:SI) REP SI<--(SI)(+/-)1 DI<--(DI)(+/-)1 CMPS 串比较 (DS:SI)-(ES:DI) REPZ/REPNZ SI<--(SI)(+/-)1 DI<--(DI)(+/-)1 SCAS 串扫描 (ES:DI)-(AL) REPZ/REPNZ DI<--(DI)(+/-)1 LODS 装入串 AL<--(DS:SI) 一般不联用 SI<--(SI)(+/-)1 STOS 存入串 (ES:DI)<--(AL) REP DI<--(DI)(+/-)1
符号 功能 操作 相关前缀 INS 串输入 ES:DI((DX)) REP DI(DI)(+/-)1 OUTS 串输出 ((DX))(DS:SI) REP SI(SI)(+/-)1 其中DX寄存器中存放的是接口电路的端口号
重复前缀 终止条件 否则 REP CX=0 CX<--(CX)-1,继续 SI,DI指向下一元素 REPZ CX=0 或 ZF=0 CX<--(CX)-1,继续 REPE SI,DI指向下一元素 串未结束且串相等时继续 REPNZ CX=0 或 ZF=1 CX<--(CX)-1,继续 REPNE SI,DI指向下一元素 串未结束且串不相等 时继续
例:REP MOVSB 传送过程如下: (1)(CX)=0? 若等于0,中止传送, 否则执行下一步 (2)CX(CX)-1 (3)串传送 (4)修改指针 (5)转到(1)
MOVS指令示例 MOV SI, 0050H ; (DS)=2000H MOV DI, 0100H ; (ES)=3000H MOV CX, 5 CLD ; 地址递增方式 REP MOVSB 执行前 执行后 ‘A’ 20050 00 30100 ‘A’ 20050 30100 ‘B’ 1 00 1 ‘B’ 1 1 ‘C’ 2 00 2 ‘C’ 2 2 ‘D’ 3 00 3 ‘D’ 3 3 ‘E’ 4 00 4 ‘E’ 4 4 ‘F’ 5 00 5 ‘F’ 5 5 ‘A’ ‘B’ ‘C’ ‘D’ ‘E’ 源区 目的区 源区 目的区 SI=0050 DI=0100 SI=0055 DI=0105
CMPS指令示例 串String1和String2分别定义在数据段和附加段中。 比较两串,如相等则转移到标号NEXT处。 String1 DB ‘HELP’ ;定义String1 String2 DB ‘HEPP’ ;定义String2 …… CLD ;DF=0 LEA SI, String1 ;源串地址-->SI LEA DI, String2 ;目的串地址-->DI MOV CX, 4 ;重复次数-->CX REPZ CMPSB;重复比较 JZ NEXT ;串相等转移 .... NEXT:
SCAS指令示例 在串“That is CAI”中查找字符‘a’,找到,则转到标号FOUND处 String DB ‘That is CAI’ ;定义串 …… CLD ;DF=0 LEA DI, String ;串地址-->DI MOV AL, ‘a’ ;查找字符-->AL MOV CX, 11 ;重复次数-->CX REPNZ SCASB;重复扫描 JZ FOUND ;找到目的串元素转移 …… FOUND:
LODS指令示例 比较SOURCE和DESTIN (串长度为100个字节),并将串中的第一个不匹配元素装入AL寄存器中。 …… LEA SI, SOURCE ;源串偏移量-->SI LEA DI, DESTIN ;目的串偏移量-->DI CLD ;DF=0 MOV CX,100 ;重复比较次数-->CX REPZ CMPSB;重复串比较 JCXZ MATCH ;没有不匹配元素跳转 DEC SI ;指向不匹配元素 LODSB;装入不匹配元素到AL ... MATCH:
STOS指令示例 给首地址为BUF,长度为1000个字节的存储器区域清零。 BUFF DB 1000 DUP(?) ;定义缓冲区 …… CLD ;DF=0 LEA DI, BUFF ;缓冲区首地址-->DI MOV CX, 1000 ;重复次数 MOV AL, 0 ;0-->AL REP STOSB;重复存储串
综合应用例1 将存储区A到A+i中的数据传送到存储区B到B+i中,要求存放的顺序与原先的顺序相反。 B +1 +2 ‘b’ B+i ‘a’ A ‘a’ +1 ‘b’ +2 ‘c’ A+i
LEA SI, A LEA DI, B ADD DI, I;DI指向存储区B的末尾 MOV CX, I+1;串的长度 LP: CLD;DF=0 LODSB ;从源区取一数据 STD ;DF=1,改变方向 STOSB ;存入目的区 DEC CX JNZ LP
3.6.3 循环结构程序设计 循环程序的组成: 1、初始化部分 设置初始值 2、循环工作部分 具体的操作和运算 3、循环修改部分 为执行下一循环而修改某些参数 4、循环控制部分 判断循环继续还是结束 循环控制方法有: (1)计数控制法 增数法 减数法 (2)条件控制法
单重循环程序设计 将以s1为起始地址的26个字母依次传送到以s2为起始地址的连续单元中。 数据定义如下: .DATA S1 DB ‘ABCD……XYZ’ .DATA ESTRA S2 DB 26 DUP(?)
方法1采用寄存器间接寻址方式 MOV AX, SEG S1 ;初始化部分 MOV DS, AX MOV AX, SEG S2 MOV ES, AX MOV SI, OFFSET S1 MOV DI, OFFSET S2 MOV CX, 26 LOP1: MOV AL, [SI] ;工作部分 MOV ES:[DI], AL INC SI ;修改部分 INC DI LOOP LOP1 ;控制部分
方法2采用串处理指令 MOV AX, SEG S1 ;初始化部分 MOV DS, AX MOV AX, SEG S2 MOV ES, AX LEA SI, S1 LEA DI, S2 MOV CX, 26 CLD REP MOVSB ;工作、修改、控制合为一条指令
计数控制法 计数控制法适用于循环次数已知的场合 1、增数法 初始化时循环计数器置0,每执行一次循环体后计数器加1,并与已知的循环次数比较,如相等则退出循环。 增数法一般用比较指令和条件转移指令实现循环转移。 2、减数法 初始化时循环计数器置为循环次数,每执行一 次循环体后计数器减1,并测试循环计数器是否为0, 如为0则终止循环。 减数法一般用循环指令形成循环回路。