580 likes | 748 Views
第五章 循环与分支程序设计. §5.1 循环与转移指令 §5.2 循环程序设计 §5.3 分支程序设计. §5.1 循环与转移指令. 一、循环控制指令 二、转移指令. 控制转移类指令通过改变 IP( 和 CS) 值,实现程序执行顺序的改变. 一、循环控制指令. 8086指令系统的循环控制指令均为二字节指令 一字节为转移的相对位移量(8位带符号的二进制数) IP ← IP+ 相对位移量 EIP ← EIP+ 相对位移量 隐含使用 CX 作为循环计数器. 短转移. 程序中的某段需反复执行若干次时,用循环来实现. 一、循环控制指令.
E N D
第五章 循环与分支程序设计 • §5.1 循环与转移指令 • §5.2 循环程序设计 • §5.3 分支程序设计
§5.1 循环与转移指令 一、循环控制指令 二、转移指令 • 控制转移类指令通过改变IP(和CS)值,实现程序执行顺序的改变
一、循环控制指令 • 8086指令系统的循环控制指令均为二字节指令 • 一字节为转移的相对位移量(8位带符号的二进制数) IP ← IP+相对位移量 EIP ← EIP+相对位移量 • 隐含使用CX作为循环计数器 短转移 • 程序中的某段需反复执行若干次时,用循环来实现
一、循环控制指令 LOOP label ;CX←CX-1,CX≠0,循环到标号label LOOPE/LOOPZ label ;CX←CX-1,CX≠0 且ZF=1,循环到标号label 等于时循环 不等于时循环 LOOPNE/NZ label ;CX←CX-1,CX≠0且ZF=0,循环到标号label
一、循环控制指令(例) MOV CX,COUNT ;设置循环次数 MOV SI,OFFSET DATA_BYTE XOR AX,AX ;BX清0,用于存放累加和 AGAIN: ADD AL,[SI] ADC AH,0 INC SI LOOP AGAIN ;计数器减1,不为0继续循环
一、循环控制指令(例) MOV CX,COUNT ;设置循环次数 MOV SI,OFFSET STRING XOR BX,BX ;BX清0,用于记录空格数 MOV AL,20H AGAIN: CMP AL,[SI] JNZ NEXT ;ZF=0,非空格,转移 INC BX ;ZF=1,是空格,个数加1 NEXT: INC SI LOOP AGAIN ;计数器减1,不为0继续循环
二、转移指令 • 无条件转移指令 • 条件转移指令
目的地址与JMP属同一逻辑段,只修改IP值 从一个代码段转移到另一个代码段,CS和IP都会被修改 无条件转移指令 JMP label ;程序转向label标号指定的地址 NEAR FAR • 只要执行无条件转移指令JMP,就使程序转到指定的目标地址处,从目标地址处开始执行那里的指令 • JMP指令分成4种类型: ⑴ 段内转移、直接寻址 ⑵ 段内转移、间接寻址 ⑶ 段间转移、直接寻址 ⑷ 段间转移、间接寻址
1.无条件转移指令—目标地址的寻址方式 • 直接寻址方式 • 转移地址象立即数一样,直接在指令的机器代码中,就是直接寻址方式 • 间接寻址方式 • 转移地址在寄存器或主存单元中,就是通过寄存器或存储器的间接寻址方式 用标号表达 用寄存器或存储器操作数表达
代码段 代码段 1.无条件转移指令—目标地址的范围:段内 • 段内转移——近转移(near) • 在当前代码段64KB范围内转移( ±32KB范围) • 不需要更改CS段基值,只要改变IP偏移地址 • 段内转移——短转移(short) • 转移范围可以用一个字节表达,在段内-128~+127范围的转移
代码段 代码段 1.无条件转移指令 —目标地址的范围:段间 • 段间转移——远转移(far) • 从当前代码段跳转到另一个代码段,可以在1MB范围 • 需要更改CS段基值和IP偏移地址 • 目标地址必须用一个32位数表达,叫做32位远指针,它就是逻辑地址 • 实际编程时,汇编程序会根据目标地址的距离,自动处理成短转移、近转移或远转移 • 程序员可用操作符short、near ptr 或far ptr 强制
段内直接寻址转移 实际为相对寻址 JMP label ;IP←IP+位移量 • 位移量是紧接着JMP指令后的那条指令的偏移地址,到目标指令的偏移地址的地址位移 • 当向地址增大方向转移时,位移量为正;向地址减小方向转移时,位移量为负 JMP AGAIN ;转移到AGAIN处继续执行 …… AGAIN: DEC CX ;标号AGAIN的指令 …… JMP OUTPUT ;转向OUTPUT …… OUTPUT: MOV RESULT,AL ;标号OUTPUT的指令
段内间接寻址转移 JMP r16/m16 ;IP←r16/m16 • 将一个16位寄存器或主存字单元内容送入IP寄存器,作为新的指令指针,但不修改CS寄存器的内容 JMP AX ;IP←AX JMP WORD PTR [BX] ;IP←[BX]
段间直接寻址转移 JMP far ptr label ;IP←label的偏移地址 ;CS←label的段基值 • 将标号所在段的段基值作为新的CS值,标号在该段内的偏移地址作为新的IP值;程序跳转到新的代码段执行 JMP FAR PTR OTHERSEG ;远转移到代码段2的otherseg
段间间接寻址转移 JMP far ptr mem ;IP←[mem],CS←[mem+2] • 用一个双字存储单元表示要跳转的目标地址。这个目标地址存放在主存中连续的两个字单元中的,低位字送IP寄存器,高位字送CS寄存器 MOV WORD PTR [BX],0 MOV WORD PTR [BX+2],1500H JMP FAR PTR [BX] ;转移到1500H:0
2.条件转移指令 Jcc label ;条件满足,发生转移:IP←IP+8位位移量 ;条件不满足,顺序执行 • 指定的条件cc如果成立,程序转移到由标号label指定的目标地址去执行指令;条件不成立,则程序将顺序执行下一条指令 • 操作数label是采用短转移,称为相对寻址方式
2.条件转移指令 • Jcc指令的操作数label是一个标号 • 一个8位位移量是相对于当前IP的,且距当前IP地址-128~+127个单元的范围之内,属于段内短距离转移 • Jcc指令为2个字节,条件不满足时的顺序执行就是当前指令偏移指针IP加2
2.条件转移指令—指令的分类 • Jcc指令不影响标志,但要利用标志。 • 根据利用的标志位不同,19条指令分成4种情况: ⑴ 判断单个标志位状态 ⑵ 比较无符号数高低 ⑶ 比较有符号数大小 ⑷ 判断计数器CX为0
实际虽然指令只有19条,但却有31个助记符 • 采用多个助记符,只是为了方便记忆和使用
判断单个标志位状态 这组指令单独判断5个状态标志之一 ⑴JZ/JE和JNZ/JNE:利用零标志ZF,判断结果是否为零(或相等) ⑵JS和JNS:利用符号标志SF,判断结果是正是负 ⑶JO和JNO:利用溢出标志OF,判断结果是否产生溢出 ⑷JP/JPE和JNP/JPO:利用奇偶标志PF,判断结果中“1”的个数是偶是奇 ⑸JC和JNC:利用进位标志CF,判断结果是否进位或借位 例 题 例 题 例 题 例 题 例 题
2.条件转移指令— JZ/JNZ指令 REPZ CMPSB ;重复比较两个字符 JNZ UNMAT;ZF=0(不等),转移 MOV AL,0 ;顺序执行(相等) JMP OUTPUT UNMAT: MOV AL,0FFH OUTPUT: MOV RESULT,AL REPZ CMPSB ;重复比较两个字符 JZ MAT ;ZF=1(相等),转移 MOV AL,0FFH ;顺序执行(不等) JMP OUTPUT MAT: MOV AL,0 OUTPUT: MOV RESULT,AL
2.条件转移指令— JS/JNS指令 • 计算|X-Y|(绝对值)。X和Y为存放于X单元和Y单元的16位操作数,结果存入RESULT。 MOV AX,X SUB AX,Y JNS NONNEG NEG AX NONNEG: MOV RESULT,AX
2.条件转移指令— JO/JNO指令 • 计算X-Y。X和Y为存放于X单元和Y单元的16位操作数,若溢出,则转移到OVERFLOW处理 MOV AX,X SUB AX,Y JO OVERFLOW ... ;无溢出,结果正确 OVERFLOW: ... ;有溢出处理
2.条件转移指令— JP/JNP指令 • 设字符的ASCII码在AL寄存器中。将字符加上奇校验位:在字符ASCII码中为“1”的个数为奇数时令其最高位为“0”,否则令最高位为“1” AND AL,7FH;最高位置“0”,同时判断“1”的个数 JNP NEXT ;个数已为奇数,则转向NEXT OR AL,80H;否则,最高位置“1” NEXT: ...
2.条件转移指令— JC/JNC指令 • 记录BX中1的个数 XOR AL,AL ;AL=0,CF=0 AGAIN: TEST BX,0FFFFH ;等价于 CMP BX,0 JZ NEXT SHL BX,1 JNC AGAIN INC AL JMP AGAIN NEXT: ... ;AL保存1的个数
2.条件转移指令 —无符号数的比较 • 无符号数的大小用高(Above)低(Below)表示 • 利用CF确定高低、利用ZF标志确定相等(Equal) • 两数的高低分成4种关系: ⑴高于(不低于等于): JA( JNBE ) ⑵高于等于(不低于): JAE( JNB ) ⑶低于(不高于等于): JB(JNAE) ⑷低于等于(不高于): JBE(JNA)
2.条件转移指令—无符号数的比较(例) CMP AX,BX ;比较AX和BX JAE NEXT ;若AX≥BX,转移 XCHG AX,BX ;若AX<BX,交换 NEXT: ... 结果:AX保存较大的无符号数
2.条件转移指令 —有符号数的比较 • 有符号数的大(Greater)小(Less)需要组合OF、SF标志,并利用ZF标志确定相等(Equal) • 两数的大小分成4种关系: • ⑴ 小于(不大于等于):JL(JNGE) • ⑵小于等于(不大于):JLE(JNG) • ⑶大于(不小于等于): JG( JNLE ) • ⑷大于等于(不小于): JGE( JNL )
2.条件转移指令 —有符号数的比较(例) CMP AX,BX ;比较AX和BX JGE NEXT ;若AX≥BX,转移 XCHG AX,BX ;若AX<BX,交换 NEXT: ... 结果:AX保存较大的有符号数
2.条件转移指令—计数器CX为0转移 JCXZ label ;CX=0,发生转移:IP←IP+8位位移量 ;CX≠0,顺序执行 • CX寄存器通常在程序中用做计数器 • JCXZ指令用来判断计数是否为0
§5.2 循环程序设计 一、循环程序的结构形式 二、循环程序设计 三、多重循环程序设计
初始化 循环的初始状态 循环体 循环的工作部分 及修改部分 修改部分 计数控制循环 条件控制循环 Y 控制条件 N 结束 一、循环程序的结构形式 先循环,后判断
初始化 循环的初始状态 N 计数控制循环 条件控制循环 控制条件 Y 结束 循环体 循环的工作部分 及修改部分 修改部分 一、循环程序的结构形式 先判断,后循环
二、循环程序设计(例) xor ax,ax ;被加数ax清0 mov cx,100 again: add ax,cx ;从100,99,...,2,1倒序累加 loop again .model small .stack 256 .data sum dw ? .code .startup mov sum,ax ;将累加和送入指定单元 .exit 0 end
开始 1的个数计数器←0 循环次数计数器CX←16 Y左移一次 N CF=1 Y 1的个数计数器+1 N CX ←CX-1=0 Y COUNT ←1的个数计数器 结束 例5.2 在ADDR单元存放着数Y的地址,试编制一程序把Y中1的个数存入COUNT单元中 循环次数固定,完全由循环计数器控制
例5.2 REPEAT: SHL AX,1 JNC NEXT INC DL NEXT: LOOP REPEAT EXIT0: MOV COUNT,DL MOV AH,4CH INT 21H CODE ENDS END START DATA SEGMENT Y DW 1234H ADDR DW Y COUNT DB ? DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA START: MOV AX,DATA MOV DS,AX MOV DL,0 MOV BX,ADDR MOV AX,[BX] MOV CX,16
开始 1的个数计数器←0 循环次数计数器CX←16 Y Y=0 N Y左移一次 Y N CF=1 1的个数计数器+1 N CX ←CX-1=0 Y COUNT ←1的个数计数器 结束 例5.2
例5.2 REPEAT: SHL AX,1 JNC NEXT INC DL NEXT: LOOP REPEAT EXIT0: MOV COUNT,DL ADD DL,30H MOV AH,2 INT 21H MOV AH,4CH INT 21H CODE ENDS END START CMP AX,0 JZ EXIT0 DATA SEGMENT Y DW 1234H ADDR DW Y COUNT DB ? DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA START: MOV AX,DATA MOV DS,AX MOV DL,0 MOV BX,ADDR MOV AX,[BX] MOV CX,16 JMP REPEAT
HEAD END -1, 23, 37, 49, 52 32, 23, 37, 49, 52 32 • 循环结束的控制: 执行插入操作后结束循环 • 例5.4 将正数N插入一个已升序排列的字数组的正确位置。该数组的首地址和末地址分别为ARRAY_ HEAD 和ARRAY_ END,其中所有的数均为正数。 -1, 解法一: • 从数组的尾部开始比较 N较大,则在比较对象后插入,结束循环 N较小,则把比较对象及其后元素后移一个字 • 若N比所有元素都小,扫描整个数组后仍无法结束循环,将-1加在数组前可解决该问题
开始 (ARRAY_HEAD-2)←-1 初始化变址寄存器SI Y K<=N N 将N放在K的后面 K后移一个字单元 结束 修改地址 例5.4
例5.4 MOV AX,N MOV ARRAY_HEAD-2,-1 MOV SI,0 COMP:CMP ARRAY_END[SI],AX JLE INSERT MOV BX,ARRAY_END[SI] MOV ARRAY_END[SI+2],BX SUB SI,2 JMP COMP INSERT: MOV ARRAY_END[SI+2],AX RET MAIN ENDP PROGRAM ENDS END START DATAREA SEGMENT X DW ? ARRAY_HEAD DW 3,5,15,23,37,49 ARRAY_END DW 105 N DW 32 DATAREA ENDS PROGRAM SEGMENT MAIN PROC FAR ASSUME CS:PROGRAM,DS:DATAREA START: PUSH DS SUB AX,AX PUSH AX MOV AX,DATAREA MOV DS,AX MOV BX,ARRAY_END[SI] CMP BX,AX JLE INSERT
例5.4 将正数N插入一个已升序排列的字数组的正确位置。该数组的首地址和末地址分别为ARRAY_ HEAD 和ARRAY_ END,其中所有的数均为正数。 解法二: • 从数组的头部开始比较 N较小,则在比较对象前插入,结束循环 N较大,则把比较对象及其前元素前移一个字 可扫描整个数组,循环次数为数组元素个数 执行插入操作后结束循环 • 循环结束的控制: • 若N比所有元素都小,形成新的头;若N比所有元素都大,则被置于尾部
MOV AX,N MOV SI,0 MOV CX,COUNT REPEAT: MOV BX,ARRAY_HEAD[SI] CMP BX,AX JAE INSERT ;N较小,则转插入操作 MOV ARRAY_HEAD[SI-2],BX ;数组元素前移1字单元 INC SI INC SI LOOP REPEAT INSERT: MOV ARRAY_HEAD[SI-2],AX ;将N加入到数组中 MOV AX,4C00H INT 21H MAIN ENDP CSEG ENDS END MAIN ;SET ENTRY POINT DSEG SEGMENT PARA 'DATA' DW ? ARRAY_HEAD DW 3,5,13H,23H,37H DW 49H,52H,65H,78H,99H,105H COUNT EQU ($-ARRAY_HEAD)/2 N DW 32H DSEG ENDS CSEG SEGMENT PARA 'CODE' ASSUME CS:CSEG ASSUME DS:DSEG,SS:SSEG MAIN PROC FAR ;MAKE NECCESSARY INITALIZALITION MOV AX,DSEG MOV DS,AX MOV ES,AX
例5.5 设有数组X和Y,每个数组都有10个元素,完成以下计算: Z1=X1+Y1 Z2=X2+Y2 Z3=X3-Y3 Z4=X4-Y4 Z5=X5-Y5 Z6=X6+Y6 Z7=X7-Y7 Z8=X8-Y8 Z9=X9+Y9 Z10=X10+Y10 结果存入数组Z。 比例尺:0000000011011100B
MOV BX,0 MOV CX,10 MOV DX,FLAG NEXT: MOV AX,X[BX] SHR DX ,1 JC SUBTRACT ADD AX,Y[BX] JMP RESULT SUBTRACT : SUB AX,Y[BX] RESULT : MOV Z[BX],AX ADD BX,2 LOOP NEXT MOV AH,4CH INT 21H CODE ENDS END START DATA SEGMENT X DW 11,33,10,60,4,7,19,80,45,23 Y DW 44,5,2,90,78,32,12,10,100,98 Z DW 10H DUP(?) FLAG DW 0000000011011100B DATA ENDS STK SEGMENT STACK DW 20H DUP(0) STK ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA,SS:STK START: MOV AX,DATA MOV DS,AX
三、多重循环程序设计 • 例5.7 有一个首地址为A的N字数组,请编制程序使该数组中的数按照从大到小的次序整序 • 冒泡法从第一个元素开始,依次对相邻的两个元素进行比较,使前一个元素不小于后一个元素;将所有元素比较完之后,最小的元素排到了最后;然后,除掉最后一个元素之外的元素依上述方法再进行比较,得到次小的元素排在后面;如此重复,直至完成就实现元素从大到小的排序 • 这需要一个双重循环程序结构
CSEG SEGMENT PARA ‘CODE’ ASSUME CS:CSEG, DS:DSEG,SS:SSEG MAIN PROC FAR ;MAKE NECCESSARY INITALIZALITION PUSH DS XOR AX,AX PUSH AX MOV AX,DSEG MOV DS,AX MOV ES,AX MOV CX,N DEC CX LOOP1: MOV DI,CX ;保存计数器 MOV BX,0 ;数组地址指针清零 LOOP2: MOV AX,A[BX] CMP AX,A[BX+2] JGE COTINUE XCHG A[BX+2],AX ;交换 MOV A[BX],AX COTINUE: ADD BX,2 ;修改数组指针 LOOP LOOP2 MOV CX,DI ;恢复循环计数器 LOOP LOOP1 RET MAIN ENDP CSEG ENDS END MAIN ;SET ENTRY POINT
CSEG SEGMENT PARA ‘CODE’ ASSUME CS:CSEG, DS:DSEG,SS:SSEG MAIN PROC FAR ;MAKE NECCESSARY INITALIZALITION PUSH DS XOR AX,AX PUSH AX MOV AX,DSEG MOV DS,AX MOV ES,AX MOV CX,N DEC CX LOOP1: MOV DI,CX;保存计数器 MOV BX,0 ;数组地址指针清零 MOV DL,0 LOOP2: MOV AX,A[BX] CMP AX,A[BX+2] JGE COTINUE XCHG A[BX+2],AX ;交换 MOV A[BX],AX INC DL ;交换次数计数器+1 COTINUE: ADD BX,2 ;修改数组指针 LOOP LOOP2 CMP DL,0 JZ EXIT0 ;数组已整序,则退出 MOV CX,DI;恢复循环计数器 LOOP LOOP1 EXIT0: RET MAIN ENDP CSEG ENDS END MAIN ;SET ENTRY POINT
§5.3 分支程序设计 一、分支程序的结构形式 二、分支程序的设计 三、跳转表