第 四 章 基 本 汇 编 语 言 程 序 设 计
1封面
* * * * * * * * * * * * * * * * *
第 四 章 基 本 汇 编 语 言 程 序 设 计
2第四章基本汇编语言程序设计第四章 基本汇编语言程序设计
4.1 顺序程序设计
4.2 分支程序设计
4.3 循环程序设计
4.4 子程序设计
4.4.1 过程定义伪指令
4.4.2 子程序的参数传递
4.4.3 子程序的嵌套、递归与重入
4.4.4 子程序的应用本章要点及习题分析第 四 章 基 本 汇 编 语 言 程 序 设 计
34.1顺序程序设计 (e)
4.1 顺序程序设计指令按程序中的书写顺序逐条执行,称为顺序程序。
除非编程解决非常简单的问题,顺序程序并不多见,
但是顺序程序往往是复杂程序结构的一部分,如分支结构的一个分支,循环结构的循环体等。
返回第四章第 四 章 基 本 汇 编 语 言 程 序 设 计
4例 4.1
例 4.1:设有 3个字变量 x,y和 z,求出三者之和,结果存入字变量 w。
.model small,startup
.stack mov ax,x
.data add ax,y
X dw 5 add ax,z
Y dw 6 mov w,ax
Z dw 7,exit 0
W dw? end
.code
第 四 章 基 本 汇 编 语 言 程 序 设 计
5例 4.2/1
例 4.2 设有一个 64位数据,将它整个左移 8位。
12
34
56
78
87
65
43
21
00
qvar[0]
qvar[1]
qvar[2]
qvar[3]
qvar[4]
qvar[5]
qvar[6]
qvar[7]
第 四 章 基 本 汇 编 语 言 程 序 设 计
6例 4.2/2
.model small
.stack
.data
Qvar dq 1234567887654321h
.code
mov al,byte ptr qvar[6]
mov byte ptr qvar[7],al
mov al,byte ptr qvar[5]
mov byte ptr qvar[6],al
mov al,byte ptr qvar[4]
mov byte ptr qvar[5],al
mov al,byte ptr qvar[3]
mov byte ptr qvar[4],al
第 四 章 基 本 汇 编 语 言 程 序 设 计
7例 4.2/3
mov al,byte ptr qvar[2]
mov byte ptr qvar[3],al
mov al,byte ptr qvar[1]
mov byte ptr qvar[2],al
mov al,byte ptr qvar[0]
mov byte ptr qvar[1],al
mov byte ptr qvar[0],0
12 34 56 78 87 65 43 21h
34 56 78 87 65 43 21 00h
(移位前)
(移位后) 返回第四章第 四 章 基 本 汇 编 语 言 程 序 设 计
84.2分支程序设计
4.2 分支程序设计条件转移指令 Jcc和无条件转移指令 JMP用于实现程序的分支结构,JMP不测试条件,Jcc可根据条件是否成立决定转移到指定位置或不转移而顺序执行后续指令。由于 Jcc不支持条件表达式,而是以当前标志位的状态为条件,故 Jcc之前一定要安排设置标志位的指令,如加减法、比较、测试等指令。 基本分支类型分为单分支和双分支 。
第 四 章 基 本 汇 编 语 言 程 序 设 计
9单分支
1,单分支类型对同一个问题,根据选择的条件不同,单分支结构的流程图有两种画法,对应的程序也有两种编法。
如 计算 AX中的有符号数的绝对值。
第 四 章 基 本 汇 编 语 言 程 序 设 计
10单分支
cmp ax,0
jge noneg
neg ax
Noneg,mov result,ax
cmp ax,0
(教材有误) jnge yesneg
jmp done
yesneg,neg ax
Done,mov result,ax
AX≥0?
求补指令
Y
N
保存结果
AX< 0?
求补指令
Y
N
保存结果JMP
第 四 章 基 本 汇 编 语 言 程 序 设 计
11双分支
2.双分支程序两个分支都有语句体,如何选择条件不重要。
流程图中分支体的位置就是程序的实际顺序,故分支语句体1最后一定要有一条JMP
指令,跳过语句体2,
转移到,后续操作,。
条件成立?
分支语句体 2
Y
N
分支语句体 1
后 续 操 作
JMP
第 四 章 基 本 汇 编 语 言 程 序 设 计
12双分支双分支举例:显示 BX的最高位。
shl bx,1
jc one ;转分支体
mov dl,’0’ ;分支体 1
jmp next ;转后续操作
One,mov dl,’1’ ;分支体 2
next,mov ah,2 ;后续操作
int 21h
3,分支程序的其他问题
⑴有些双分支问题可以先假设一种情况,把双分支改成单分支问题。如上例,先假设 BX最高位为 0,
在分支外准备显示 0;如最高位为 0,即可直接跳到后续操作;如最高位为 1才需要执行分支体。⑵⑶
mov dl,’0’
shl bx,1
jnc next
mov dl,’1’
next:mov ah,2
int 21h
第 四 章 基 本 汇 编 语 言 程 序 设 计
13多分支
⑵ 分支的嵌套形成多分支,嵌套形式多种多样。
例 1:求符号函数 1 当 X>0
Y= 0 当 X=0
-1 当 X<0
X≥0? Y
N
X=0? Y
NY=-1
Y=1 Y=0
实际是双分支的组合。
第 四 章 基 本 汇 编 语 言 程 序 设 计
14多分支例 2:判断 AL各位的值,D0=1,转移到 L0; D1=1,转移到 L1; D2=1,转移到 L2……
D0=1
分支 L0
D2=1
D1=1
分支 L1
分支 L2
y
y
y
N
N
N
也可认为是双分支的组合,但为简化编程,实现左图的分支结构可以在数据段设置 转移地址表,如例题 4.4
第 四 章 基 本 汇 编 语 言 程 序 设 计
15多分支例 4.4 使用地址表实现多分支。 8个分支的标号分别为 disp1,disp2…
在代码段有:
disp1:mov dx,…
disp2:mov …
设 disp1的偏移地址为
2300h,disp2的偏移地址为 2500h…… 。
在数据段有:
tabel dw
disp1,disp2,…
tabel
disp1
︰
︰
disp4
disp3
2500H
2300H
disp5
disp6
disp7
disp8
0
2
4
6
8
A
C
E
相对 tabel
的偏移量第 四 章 基 本 汇 编 语 言 程 序 设 计
16多分支 (e)
转入分支:按输入的数字转入不同分支
①按输入的数字求出分支相对 tabel的偏移量:
disp1为 0,disp2为 2,disp3为 4…,如输入数字 2,则偏移量为 ( 2-1) × 2=2,将求出的偏移量存入 bx。
②执行指令 jmp tabel[bx],设 bx=02
则 IP← [tabel+bx]
即 IP← 2500H
③ CS:2500H为分支 Disp2的入口,CPU即执行分支 DISP2
返回第四章第 四 章 基 本 汇 编 语 言 程 序 设 计
174.3 循环程序设计
4.3 循环程序设计(重复执行的程序段)
1.循环程序的组成
初始化部分:设置循环条件、次数、初值等。
循环体部分:重复执行的代码,含循环条件的修改等。
循环控制部分:判断循环条件,决定是否继续。
2.两种循环结构
1),先循环、后判断,结构相当于高级语言的,直到型,循环
2),先判断、后循环,结构相当于高级语言的,当型循环,,可实现 0次循环。
第 四 章 基 本 汇 编 语 言 程 序 设 计
18两种循环结构初 始 化 部 分循 环条件成立?
循 环 体 部 分
(修改循环条件 )
N
Y
循 环条件成立?
初 始 化 部 分循 环 体 部 分
(修改循环条件 )
Y
N
第 四 章 基 本 汇 编 语 言 程 序 设 计
19循环程序设计
3.循环程序设计编写循环程序的关键在于循环的控制。
循环次数已知:可用 LOOP指令,CX计数。
如教材例 4.5。
循环次数和 ZF标志:可用 LOOPZ,LOOPNZ指令。
如教材例 4.6。
循环次数未知:通常要采用各类条件转移指令实现循环控制。如教材例 4.7,字符串以 0结尾;
例 4.9,字符串以 $结尾。
第 四 章 基 本 汇 编 语 言 程 序 设 计
20例题分析循环程序例题分析:
例 4.5:计算 100个数字之和。
仅用循环次数控制,且循环次数已知,比较简单。
例 4.6:确定一个字变量中为 1的最低位数。
从最低位向高位依次测试,最多测试 16次;测试到某位为 1,即可结束程序,测试结果用 ZF标志反映,
因此可用 LOOPE或 LOOPZ控制循环 (结果非 0,退出)。
例 4.7:将一个字符串中的所有大写字母改为小写字母,字符串以 0结尾。
循环次数未知,应使用条件判断控制循环;循环结构应使用,先判断、后执行,的结构;通常,采用条件判断控制循环时,往往采用,先判断、后执行,
的循环结构。
第 四 章 基 本 汇 编 语 言 程 序 设 计
21例题 4.6
例 4.6:确定一个字变量中为 1的最低位数。
.startup
mov ax,wordX ;测试目标送 AX
mov cx,16 ;循环计数器置初值
mov dl,-1 ;计位器置初值
again:inc dl
test ax,1
ror ax,1 ;循环指令不影响 ZF
loope again;CX≠0 且 ZF=1(测试位为 0),继续循环
je notfound ;退出循环,但 0标志成立,没有 1
mov byteY,dl
jmp done
notfound:mov byteY,-1;ZF=1,16个位均为 0
done:.exit 0
end
第 四 章 基 本 汇 编 语 言 程 序 设 计
22例题 4.7/1
例 4.7:将一个字符串中的所有大写字母改为小写字母,
字符串以 0结尾。.data
Steing db ‘xxxxxxxxxxxxxxxxxx’,0
.code
.startup
mov bx,offset string
again,mov al,[bx] ;取一个字符
or al,al ;是否为结尾符 0
jz done ;是,退出循环第 四 章 基 本 汇 编 语 言 程 序 设 计
23/2
cmp al,'A' ;是否为大写 A~ Z
jb next
cmp al,'Z'
ja next
or al,20h ;是,转换为小写字母(使
D5=1)
mov [bx],al ;仍保存在原位置
next,inc bx
jmp again ;继续循环
done:
.exit 0
end
第 四 章 基 本 汇 编 语 言 程 序 设 计
24两重循环结构
4.多重循环:循环程序的嵌套构成多重(多层)循环。
最常见的多重循环为两重循环。
外循环初始化内循环初始化内层循环体外层循环体内循环结束外循环结束
N
N
Y
Y
一个简单延时程序:
(双重循环)
mov cx,100
n_start,mov dx,0ffffh
n_loop,dec dx
jnz n_loop
dec cx
jnz n_start
内循环控制外循环控制第 四 章 基 本 汇 编 语 言 程 序 设 计
25“冒泡法,排序例 4.8:采用,冒泡法,排序 (升序)。
冒泡法从第一个元素开始,依次对相邻的两个元素进行比较,使前一个元素不大于后一个元素;将所有元素比较完之后,最大的元素排到了最后;第一轮比较结束。然后,开始第二轮,除掉最后一个元素,其他元素依上述方法再进行比较,得到次大的元素排在后面;第二轮结束。如此重复,直至完成,就实现了元素从小到大的排序循环次数已知的双重循环程序。外层循环(轮)
的次数为数据个数减 1,每一轮外循环的内层循环次数等于剩下的外循环次数。如 5个数据,外循环次数 =4,
第一轮中内循环次数也为 4;第一轮作完,还剩下 3轮,
第二轮中内循环次数等于 3,以次类推。
“冒泡法,排序小数冒泡
8
15
16
32
85
15
8
16
32
85
16
15
8
32
85
32
16
15
8
85
1 32
2 85
3 16
4 15
5 8
(1轮 )4(2轮 )3(3轮 )2(4轮 )1
外 循 环 次 数(轮次)
序号 数每 轮 内 循 环 次 数
4 3 2 1
大数沉底排序示意图 须作 4轮 第 1轮第 四 章 基 本 汇 编 语 言 程 序 设 计
27例 4.8 排序 /1
例 4.8 对无符号字节数组元素由小到大排序。.data
Array db xx,xx,xx,……Count equ ($-array)/(type array)
.code
mov cx,count ;CX← 数组元素个数
dec cx ;元素个数减 1为外循环次数
outlp:mov dx,cx ;DX← 内循环次数
mov bx,offset array
inlp:mov al,[bx] ;取前一个元素
cmp al,[bx+1] ;与后一个元素比较
jna next;前一个不大于后一个元素,则不进行交换
xchg al,[bx+1] ;否则,进行交换
mov [bx],al
第 四 章 基 本 汇 编 语 言 程 序 设 计
28例 4.8 排序 /2
next:inc bx ;下一对元素
dec dx
jnz inlp ;内循环尾
loop outlp ;外循环尾第 四 章 基 本 汇 编 语 言 程 序 设 计
29例 4.9 剔除空格程序例 4.9:剔除以$结尾的字符串中的空格。
①双重循环程序:外层循环负责搜索字符串中的空格;内层循环负责剔除搜索到的空格(由于空格后的字符要依次向前移动一个字节,因而也是一个循环结构)。
②无论是外层循环,还是内层循环,循环次数都未知,只能用,条件判断,控制循环。
③外层循环采用,先判断、后循环,结构;对内层循环而言,由于搜索到空格才进入内循环,所以采用,先循环、后判断,结构。
第 四 章 基 本 汇 编 语 言 程 序 设 计
30例 4.9/1
例 4.9,现有一个以 $结尾的字符串,要求剔除其中的空格。
.data
string db ’Let us have a try !’,’$’
.code
.startup
mov dx,offset string
mov ah,9
int 21h ;显示原字符串
mov al,’ ’ ;AL← 空格( ASCII码为 20H)
mov di,offset string
第 四 章 基 本 汇 编 语 言 程 序 设 计
31例 4.9/2
outlp:cmp byte ptr [di],’$’;外循环,先判断后循环
jz done ;为 $结束
cmp al,[di] ;检测是否是空格
jnz next ;不是空格继续外循环
mov si,di ;是空格,进入剔除空格分支
inlp:inc si ;该分支是循环程序段
mov ah,[si] ;取空格后的一个字符
mov [si-1],ah ;向前移动一个字节
cmp byte ptr [si],’$’;内循环,先循环后判断
jnz inlp
第 四 章 基 本 汇 编 语 言 程 序 设 计
32例 4.9/3
next:inc di ;继续对后续字符进行处理
jmp outlp
done:mov dx,offset string
mov ah,9
int 21h ;显示处理后字符串
.exit 0 ;结束
end
返回第四章第 四 章 基 本 汇 编 语 言 程 序 设 计
334.4 (目录)子程序设计
4.4 子程序设计把功能相对独立的程序段单独编写和调试,作为一个相对独立的模块供程序使用,就形成子程序。
使用子程序:简化源程序结构;提高编程效率。
4.4.1 过程定义伪指令
4.4.2 子程序的参数传递
4.4.3 子程序的嵌套递归重入
4.4.4 子程序的应用返回第四章第 四 章 基 本 汇 编 语 言 程 序 设 计
344.4.1 过程定义伪指令 (1)
4.4.1 过程定义伪指令过程名 PROC [NEAR|FAR]
过程体
RET( RET N)
过程名 ENDP
过程名:符合语法的标识符;同模块唯一性。
距离属性,可省略,由汇编程序判断。
堆栈使用:平衡。才能保证 RET指令弹出的是断点地址。
保护现场与恢复现场:子程序用到的寄存器或存储单元,注意:后进先出。
注意子程序的规范和格式
PUSH AX
PUSH BX
PUSH CX
PUSH DX
POP DX
POP CX
POP BX
POP AX
第 四 章 基 本 汇 编 语 言 程 序 设 计
35关于,距离属性,
关于,距离属性,
NEAR属性(段内近调用)的过程只能被相同代码段的其他程序调用
FAR属性(段间远调用)的过程可以被相同或不同代码段的程序调用对简化段定义格式,在微型、小型和紧凑存储模式下,过程的缺省属性为 near;在中型、大型和巨型存储模式下,过程的缺省属性为 far
对完整段定义格式,过程的缺省属性为 near
用户可以在过程定义时用 near或 far改变缺省属性第 四 章 基 本 汇 编 语 言 程 序 设 计
36子程序规范子程序规范一个完整的子程序,特别是供其他编程人员使用的子程序,必须附有一个详细说明:
子程序名(过程名)
子程序功能介绍
子程序的入口参数
子程序的出口参数
子程序内使用的寄存器(存储单元)
使用该子程序的范例
子程序名,DTOB
功能:完成两位十进制数转换成二进制数
入口参数,AL存放待转换的两位 BCD码
出口参数,CL存放转换后的二进制数
占用寄存器,BX
示例:输入 AL=01010110B ( 56H)
输出 CL=00111000B ( 38H)
某子程序的说明第 四 章 基 本 汇 编 语 言 程 序 设 计
37子程序的常见格式子程序的常见格式;子程序说明;子程序说明
subname proc;具有缺省属性的 subname过程
push ax ;保护寄存器:顺序压入堆栈
push bx ;ax/bx/cx仅是示例
push cx
… ;过程体
pop cx ;恢复寄存器:逆序弹出堆栈
pop bx
pop ax
ret ;过程返回
subname endp ;过程结束第 四 章 基 本 汇 编 语 言 程 序 设 计
38简单子程序简单子程序;子程序功能:实现光标回车换行
dpcrlf proc ;过程开始
push ax ;保护寄存器 AX和 DX
push dx
mov dl,0dh ;显示回车
mov ah,2
int 21h
mov dl,0ah ;显示换行
mov ah,2
int 21h
pop dx ;恢复寄存器 DX和 AX
pop ax
ret ;子程序返回
dpcrlf endp ;过程结束第 四 章 基 本 汇 编 语 言 程 序 设 计
39例 4.10:编写子程序 (e)
例 4.10:编写子程序,将 AL寄存器内的二进制数用十六进制数显示。
8位二进制数,可转换成两位十六进制数。
十六进制数 → ASCII码 → 2#功能调用显示
1001B→9H→1001+ 0011 0000→39H ( 9的 ASCII)
1010B→AH→1010+ 0011 0111→41H ( A的 ASCII)
注意:对 0-9加 30H,对 A-F加 37H,即 +30H+07H
先转换高 4位二进制数,并显示;然后转换低 4位并显示。
例题 410 回 4.4
第 四 章 基 本 汇 编 语 言 程 序 设 计
404.4.2 子程序的参数传递
4.4.2 子程序的参数传递主程序和子程序之间通常需要传递参数:
入口参数 (输入参数):主程序提供给子程序
出口参数 (输出参数):子程序返回给主程序
参数的形式,
① 数据本身(传值)
② 数据的地址(传址)
传递的方法,
① 寄存器 ② 变量 ③ 堆栈第 四 章 基 本 汇 编 语 言 程 序 设 计
41参数传递方法
1.用寄存器传递参数方便、简单、易行。须要传递的参数较多时不适用。 见例题 411a。
2.用变量传递参数就是用存储器传递参数,当主程序与子程序在同一个模块时,即为共享数据段的变量;不在同一模块,需要用
PUBLIC/EXTERN声明。
适用与参数较多情况。 见例题 411b。
3.用堆栈传递参数常用方法。用 BP访问堆栈段。须格外注意堆栈的平衡。
(堆栈示意图)
第 四 章 基 本 汇 编 语 言 程 序 设 计
42
堆栈示意图使用堆栈传递参数时堆栈示意图:
┇
PUSH 参数 1
PUSH 参数 2
PUSH 参数 3
CALL SUBPRO
┇
.EXIT 0
SUBPRO PROC
PUSH BP
MOV BP,SP
PUSH AX
┇
POP AX
POP BP
RET (RET 6)
SUBPRO ENDP
A X
B P
I P
参数 3
参数 2
参数 1
BP=SP
BP+2
BP+4
BP+6
BP+8
SP(原始 )
子程序取参数:
MOV AX,[BP+4(6,8)]
子程序平衡堆栈,RET 6
主程序平衡堆栈,ADD SP,6
例题 411c
SP
第 四 章 基 本 汇 编 语 言 程 序 设 计
43例题 4.11c/1
例题 4.11c,计算累加和;用堆栈传递参数;入口参数,数组首地址、数组元素个数;出口参数,AL 累加和
.model small
.stack
.data
count equ 10
array db
12h,25h,0f0h,0a3h,03,68h,71h,0cah,0ffh,90h
result db?
第 四 章 基 本 汇 编 语 言 程 序 设 计
44例题 4.11c/2
.code
.startup
mov ax,offset array
push ax ;首地址入栈
mov ax,count
push ax ;元素个数入栈
call checksuma
add sp,4 ;平衡两个参数占用的堆栈
mov result,al
.exit 0
第 四 章 基 本 汇 编 语 言 程 序 设 计
45例题 4.11c/3
checksuma proc
push bp
mov bp,sp;使 BP指向刚进入子程序的堆栈顶,
push bx
push cx
mov bx,[bp+6]
mov cx,[bp+4]
xor al,al
suma,add al,[bx]
inc bx
loop suma
第 四 章 基 本 汇 编 语 言 程 序 设 计
46例题 4.11c/4
pop cx
pop bx
pop bp
ret ;可以用 RET 4
checksuma endp
end
第 四 章 基 本 汇 编 语 言 程 序 设 计
47编写子程序时应注意的问题编写子程序时应注意的问题:
①使用简化的段定义格式时,过程定义在程序中的位置要注意,可以放在 1)主程序的最后,即
,.EXIT 0”之后,END语句之前; 2)放在主程序之前,
即,,CODE”之后,,.STARTUP”之前。
②使用寄存器传递参数时,带有入口参数的寄存器可以保护,也可以不保护;带有出口参数的寄存器则一定不可保护和恢复;其他与出口参数无关、而子程序中使用的寄存器,子程序开始处应该保护,子程序结束、返回主程序之前应该恢复。
回 4.4
第 四 章 基 本 汇 编 语 言 程 序 设 计
484.4.3 子程序的嵌套递归重入
4.4.3 子程序的嵌套、递归与重入
1.子程序的嵌套子程序又调子程序称为子程序的嵌套,嵌套的层数取决于堆栈空间的大小。嵌套子程序的设计和一般子程序完全相同。
2.子程序的递归子程序直接或间接地嵌套调用自己,称为递归调用。含有递归调用的子程序称为递归子程序。
每次调用时不能破坏以前调用所用的参数及中间结果,
因此,调用参数及中间结果一般都放在堆栈中。不可放在固定的寄存器或存储单元中。
要控制递归的次数,避免陷入死循环。
递归深度受堆栈空间的限制。
第 四 章 基 本 汇 编 语 言 程 序 设 计
49例题 4.12
例题 4.12 用递归子程序求 N的阶乘,设 N=3。
递归次数用 N控制,由 N=3,子程序共运行 4次(主程序调用 1次,递归调用 3次);入口参数及中间结果都用堆栈保存。
注释,1)在进入子程序过程中,不计算阶乘值,
只求中间参数。第一次进入,求出中间参数 2;第二次进入求出中间参数 1;第三次进入求出中间参数 0;
第四次进入后,由于中间参数以为 0,开始执行返回处理。
2)在返回过程中计算阶乘:在过程 3中计算 1*1=1,
在过程 2中计算 1*2=2,在过程 1中计算 2*3=6。
3)递归子程序可设计出效率较高的程序,但是编程较难,编出的程序易读性差,使用不多。
第 四 章 基 本 汇 编 语 言 程 序 设 计
50子程序的重入 (e)
3.子程序的重入子程序被中断后,又被中断服务程序所调用,称为子程序的重入。能够重入的子程序称为可重入子程序。
当主机与外设采用中断方式交换信息时,外设的驱动程序应按,可重入原则,设计。
虽然重入与递归的概念不同,但递归子程序就是可重入子程序。设计可重入子程序与设计递归子程序的原则是相同的,即参数、中间结果等都用堆栈保存,不能用固定的存储单元或寄存器保存。
回 4.4
第 四 章 基 本 汇 编 语 言 程 序 设 计
514.4.4 子程序的应用
4.4.4 子程序的应用
1) 例题 4.15 计算有符号数的平均值。
有时进行运算之前,需要符号扩展;对无符号数应进行 0扩展。
2)具有局部变量的子程序(截取教材 P123部分程序):当某些数据只有子程序自己使用时,可在代码段子程序后面定义数据区。
3)具有多个出口的子程序:有的子程序具有多个出口,根据条件的不同,从不同的出口返回主程序。
第 四 章 基 本 汇 编 语 言 程 序 设 计
52例 4.15 计算平均值 /1
例 4.15 计算有符号数的平均值。;入口参数用堆栈传递,出口参数用寄存器 AX传递。;要计算 16位有符号数的和,被加数一定要进行符号扩展。
.model small
.stack
.data
array dw 1234,-1234,1,1,-1,32767,-32768,5678,
-5678,9000
count equ ($-array)/2 ;数据个数
wmed dw?
第 四 章 基 本 汇 编 语 言 程 序 设 计
53/2
.code
.startup
mov ax,count
push ax ;参数 1
mov ax,offset array
push ax ;参数 2
call mean
add sp,4 ;平衡堆栈
mov wmed,ax
.exit 0
第 四 章 基 本 汇 编 语 言 程 序 设 计
54/3
mean proc
push bp
mov bp,sp
push bx
push cx
push dx
push si
push di
mov bx,[bp+4];取参数 2:偏移地址
mov cx,[bp+6];取参数 1:数据个数
xor si,si
mov di,si
第 四 章 基 本 汇 编 语 言 程 序 设 计
55/4
mean1,mov ax,[bx]
cwd
add si,ax
adc di,dx
inc bx
inc bx
loop mean1
mov ax,si
mov dx,di
mov cx,[bp+6]
dx.ax
+ di.si
di.si
第 四 章 基 本 汇 编 语 言 程 序 设 计
56/5
idiv cx ;求平均值,商在 AX,余数在 DX
pop di
pop si
pop dx
pop cx
pop bx
pop bp
ret
mean endp
end
第 四 章 基 本 汇 编 语 言 程 序 设 计
57避免溢出的方法
为了避免有符号二进制数求和过程中溢出,被加数要进行符号扩展,得到倍长数据(大小没有变化),
然后求和
如数据采用 16位二进制数表示,数据个数也采用 16
位二进制数表示,则最多为 216个数据。如将数据扩展到 32位二进制数表示,求和时,就不会出现溢出。
考虑极端情况:数据全是- 215( -32768),共有 216
个,求和结果是- 231,32位数据仍然可以表达。
对于无符号数,有时也需要得到倍长数据,应采用
,0扩展,,即将高位置 0,如,MOV DX,0”。;将 AL低 4位表达的一位 16进制数转换为 ASCII码
H2ASC proc
push bx
mov bx,offset ASCII ;BX指向 ASCII码表
and al,0fh ;取得一位 16进制数
xlat CS:ASCII;换码,AL←CS:[BX + AL],注意数据在代码段 CS
pop bx
ret ;子程序返回
ASCII db 30h,31h,32h,33h,34h,35h,36h,37h
db 38h,39h,41h,42h,43h,44h,45h,46h
H2ASC endp
例题 具有局部变量的子程序因为数据区与子程序都在代码段,所以利用了换码指令 XLAT的另一种助记格式 ( 写出指向缓冲区的变量名,目的是便于指明段超越前缀 ) 。 串操作 MOVS,LODS和 CMPS指令也可以这样使用,以便使用段超越前缀除采用段超越方法外,子程序与主程序的数据段不同时,我们还可以通过修改 DS值实现数据存取;但需要保护和恢复 DS寄存器
HTOASC proc;将 AL低 4位表达的一位 16进制数转换为 ASCII码
and al,0fh
cmp al,9
jbe htoasc1
add al,37h ;是 0AH~ 0FH,加 37H
ret ;子程序返回
htoasc1,add al,30h ;是 0~ 9,加 30H
ret ;子程序返回
HTOASC endp
例题 具有多个出口的子程序回 4.4
第 四 章 基 本 汇 编 语 言 程 序 设 计
60例 4.13
例 4.13 编写子程序从键盘输入一个有符号十进制数;
并将输入的 ASCII码转换为二进制数。
输入时,负数用,-,引导,正数直接输入或用
,+,引导
子程序用寄存器传递出口参数,主程序调用该子程序输入 10个数据
将 ASCII码转换为二进制数的过程
① 首先判断输入为正或负数,并用一个寄存器记录
② 接着输入 0~ 9数字( ASCII码),并减 30H转换为二进制数
③ 然后将前面输入的数值乘 10,并与刚输入的数字相加得到新的数值
④ 重复②、③步,直到输入一个非数字字符结束
⑤ 负数进行求补,转换成补码;否则直接保存数值第 四 章 基 本 汇 编 语 言 程 序 设 计
61输入和转换流程图输入和转换流程图:
A
负数求补,正数不变出口参数 → AX
返回
1号调用输入字符是 ‘ +’?
是 ‘ -’?
置负数标志输入下一个
0-9之间变成二进制数
BX*10+AL→BX
Y
N
N A
输入非数字字符,结束输入第 四 章 基 本 汇 编 语 言 程 序 设 计
62输入数字举例设从键盘输入数字 –258:
输入顺序,- 2 5 8
CX -1 -1 -1 -1
BX 0 0002 0019H=25 0102H=258
数字输入结束后,由于 CX为负数标志,
再对 BX求补。
第 四 章 基 本 汇 编 语 言 程 序 设 计
63程序 /1
.data
count = 10
array dw count dup(0) ;预留数据存储空间
.code
.startup
mov cx,count
mov bx,offset array
again:call read ;调用子程序输入一个数据
mov [bx],ax ;将出口参数存放缓冲区
inc bx
inc bx
call dpcrlf;调用子程序,光标回车换行以便输入下一个数据
loop again
.exit 0
这是主程序第 四 章 基 本 汇 编 语 言 程 序 设 计
64程序 /2;输入有符号 10进制数的通用子程序;出口参数,AX=补码表示的二进制数值
read proc
push bx
push cx
push dx
xor bx,bx ;BX保存结果
xor cx,cx;CX为正负标志,0为正,- 1为负
mov ah,1;输入一个字符
int 21h
第 四 章 基 本 汇 编 语 言 程 序 设 计
65程序 /3
cmp al,'+' ;是,+,,继续输入字符
jz read1
cmp al,'-' ;是,-,,设置- 1标志
jnz read2 ;非,+,和,-,,转 read2
mov cx,-1
read1,mov ah,1;继续输入字符
int 21h
read2,cmp al,'0‘;不是 0~ 9之间的字符,则输入数据结束
jb read3
cmp al,'9'
ja read3
第 四 章 基 本 汇 编 语 言 程 序 设 计
66程序 /4
sub al,30h;是 0~ 9之间的字符,则转换为二进制数;利用移位指令,实现数值乘 10,BX←BX × 10
shl bx,1
mov dx,bx
shl bx,1
shl bx,1
add bx,dx
mov ah,0
add bx,ax;已输入数值乘 10后,与新输入数值相加
jmp read1 ;继续输入字符第 四 章 基 本 汇 编 语 言 程 序 设 计
67程序 /5
read3:cmp cx,0
jz read4
neg bx ;是负数,进行求补
read4,mov ax,bx ;设置出口参数
pop dx
pop cx
pop bx
ret ;子程序返回
readendp
dpcrlf proc ;使光标回车换行的子程序
..,;省略
dpcrlf endp
end
第 四 章 基 本 汇 编 语 言 程 序 设 计
68例 4.14
例 4.14 编写子程序,将二进制数转换为 10进制数的
ASCII码,并在屏幕上显示一个有符号 10进制数。
显示时,负数用,-,引导,正数直接输出、没有前导字符。
子程序的入口参数用共享变量传递,主程序调用该子程序显示 10个数据。
将二进制数转换为 10进制数的 ASCII码
① 首先判断数据是零、正数或负数,是零显示,0”退出
② 是负数,显示,-,,求数据的绝对值;
③ 接着数据除以 10,余数加 30H转换为 ASCII码压入堆栈
④ 重复③步,直到余数为 0结束
⑤ 依次从堆栈弹出各位数字,进行显示第 四 章 基 本 汇 编 语 言 程 序 设 计
69显示数字举例显示数字举例:设 AX中数据为 -258的补码
1.显示负号 ‘ -’。
2.求补,AX中得到 -258的绝对值。
3.258/10,商为 25,余数为 8,此为个位。
8+30H,入栈。
4.25/10,商为 2,余数为 5,此为十位。
5变 ASCII码入栈。
5.2/10,商为 0,余数为 2,此为百位。
2变 ASCII码入栈。
6.由于商为 0,变换结束。
7.顺序出栈显示。
第 四 章 基 本 汇 编 语 言 程 序 设 计
70程序 /1
.data
Count = 10Array dw 1234,-1234,0,1,-1,32767,-32768,
dw 5678,-78,9000
Wtemp dw? ;共享变量.code
.startup
mov cx,count
mov bx,offset array
again:mov ax,[bx]
mov wtemp,ax ;将入口参数存入共享变量
call write ;调用子程序显示一个数据
inc bx
inc bx
call dpcrlf ;便于显示下一个数据
loop again
.exit 0
第 四 章 基 本 汇 编 语 言 程 序 设 计
71程序 /2;显示有符号 10进制数的通用子程序;入口参数:共享变量 wtemp
write proc
push ax
push bx
push dx
mov ax,wtemp ;取出显示数据
test ax,ax ;判断零、正数或负数
jnz write1
mov dl,'0' ;是零,显示,0”后退出
mov ah,2
int 21h
jmp write5 ;恢复现场后返回第 四 章 基 本 汇 编 语 言 程 序 设 计
72程序 /3
write1,jns write2 ;不是负数,转向数据转换。
mov bx,ax ;是负数,显示,-,
mov dl,'-'
mov ah,2
int 21h
mov ax,bx
neg ax ;求绝对值
write2,mov bx,10 ;准备除数
push bx;10压入堆栈,作为退出标志第 四 章 基 本 汇 编 语 言 程 序 设 计
73程序 /4
write3,cmp ax,0;数据(商)为零
jz write4 ;转向显示
sub dx,dx ;扩展被除数 DX.AX
div bx ;数据除以 10,DX.AX÷ 10
add dl,30h;余数( 0~ 9)转换为 ASCII码
push dx;数据各位先低位后高位压入堆栈
jmp write3
0032h
0035h
0038h
10
仍以 258为例 25
8
第 四 章 基 本 汇 编 语 言 程 序 设 计
74程序 /5
write4:pop dx ;数据各位先高位后低位弹出堆栈
cmp dl,10 ;是结束标志 10,则退出
je write5
mov ah,2 ;进行显示
int 21h
jmp write4
write5:pop dxpop bx
pop axret ;子程序返回
write endp
dpcrlf proc ;使光标回车换行的子程序
..,;省略dpcrlf endp
end
第 四 章 基 本 汇 编 语 言 程 序 设 计
75本章要点本章要点,
分支程序设计:
单分支、双分支、多分支单分支流程图的画法用转移地址表法实现多分支
循环程序设计:
两种循环结构循环程序的控制方法:计数法、条件判断法单层循环和双层循环
子程序设计:
过程定义伪指令子程序的参数传递:寄存器、变量、堆栈第 四 章 基 本 汇 编 语 言 程 序 设 计
76习题分析:补充 1
1.将 AX中存放的无符号数除以 2,如果是奇数,则加
1后除以 2(单分支)
test ax,01h ;测试 AX最低位
jz even ;最低位为 0,AX为偶数
add ax,1;最低位为 1,AX为奇数,需要加 1
even:rcr ax,1 ;AX←AX ÷ 2;如果采用 SHR指令,则不能处理 AX= FFFFH的特殊情况第 四 章 基 本 汇 编 语 言 程 序 设 计
77补充 2/1
2.判断一元二次方程是否有实根。有,TAG置 1;
无,TAG置 0。(教材例题 4.3:双分支)
.data
a db?
b db?
c db?
tag db?
.code
.startup
mov al,b
imul al
mov bx,ax ;BX中为 b2
第 四 章 基 本 汇 编 语 言 程 序 设 计
78补充 2/2
mov al,a
imul c
mov cx,4
imul cx ;AX中为 4ac( DX无有效数据)
cmp bx,ax ;比较二者大小
jge yes ;条件满足?
mov tag,0 ;第一分支体:条件不满足,tag←0
jmp done ;跳过第二个分支体
yes:mov tag,1 ;第二分支体:条件满足,tag←1
done:.exit 0
end
第 四 章 基 本 汇 编 语 言 程 序 设 计
79补充 3/1
3.按键盘输入的数字 1-8,转 8个分支(显示不同的信息)。 (同教材例题 4.4,但显示的信息不同)
分析过程见课件 4.2节的,多分支部分,
.data
msg db 'Input number(1~8):',0dh,0ah,'$'
Msg1 db 'Chapter 1,,..',0dh,0ah,'$'
msg2 db 'Chapter 2,,..',0dh,0ah,'$‘
...
msg8 db 'Chapter 8,,.,',0dh,0ah,'$'
table dw disp1,disp2,disp3,disp4
dw disp5,disp6,disp7,disp8;取得各个标号的偏移地址第 四 章 基 本 汇 编 语 言 程 序 设 计
80补充 3/2
………
start1:mov dx,offset msg ;提示输入数字
mov ah,9
int 21h
mov ah,1 ;等待按键
int 21h
cmp al,'1' ;数字 < 1?
jb start1
cmp al,'8' ;数字 > 8?
ja start1
and ax,000fh ;将 ASCII码转换成数字第 四 章 基 本 汇 编 语 言 程 序 设 计
81补充 3/3
dec ax
shl ax,1 ;等效于 add ax,ax
mov bx,ax
jmp table[bx];(段内)间接转移,IP←[table+bx]
start2:mov ah,9
int 21h
.exit 0
disp1,mov dx,offset msg1;处理程序 1
jmp start2
Disp2:…
...
end
第 四 章 基 本 汇 编 语 言 程 序 设 计
82习题 4.4
习题分析
4.4 编写一个程序,把从键盘输入的一个小写字母用大写字母显示出来。
框图,( 省略输入字符的判断:简单的顺序程序)
1号调用:输入字符
AL←AL -20H
2号调用:显示字符结 束第 四 章 基 本 汇 编 语 言 程 序 设 计
834.5
4.5 已知用于 LED数码管显示的代码表为:
LEDTABEL DB 0C0H,0F9H… (共 16项数据)
依次表示 0~ 9,A~ F这 16个数码的显示代码,编写一个程序实现将 lednum中的一个数字转换成对应的 LED显示代码。(查表程序)
BX← 代码表首地址
AL←[lednum]
执行指令 XLAT AL中即为所求的显示代码第 四 章 基 本 汇 编 语 言 程 序 设 计
844.8
4.8 如果在例题 4.4的 tabel中依次添入 msg1~ msg8,
程序应该如何修改? (Tabel dw msg1,…,)
┆ ┆
mov bx,ax mov bx,ax
jmp tabel[bx] mov dx,tabel[bx]
Start2,mov ah,9 mov ah,9
int 21h int 21h
.exit 0,exit 0
┆ end
程序变得更加简单。
取显示信息偏移地址取转移地址送 IP
第 四 章 基 本 汇 编 语 言 程 序 设 计
854.9
4.9 编制一个程序,将变量 BUFX,BUFY中较大者送入
BUFZ;若两者相等,则把其中之一送入 BUFZ中。设变量为无符号 8位数。
AL←[BUFX]
CMP AL,BUFY
AL小于 [BUFY]?
AL←[BUFY]
[BUFZ]←AL
Y
N
DONE:
JAE DONE
第 四 章 基 本 汇 编 语 言 程 序 设 计
864.10
4.10 设变量 bufX为有符号数,编程将其符号状态保存在 singX,如 X大于等于 0,保存 0;如 X小于 0,保存 -1。
该题为一个可以演变成单分支的双分支结构:
测试 bufX符号
≥0
-1→singX
0→singX
next
Y
0→singX
测试 bufX符号
≥0
-1→singX
next
Y
第 四 章 基 本 汇 编 语 言 程 序 设 计
874.11
4.11 X,Y,Z是三个有符号 16位数(教材误印为 16进制数),编写程序:
1)三个数都不相等,显示 0;
2)有两个数相等,显示 1;
3)三个数都相等,显示 2。
三个数比较,应有 5种情况:
X Y Z
√ √ √ X=Y=Z 显示 2
√ √ X=Y≠Z 显示 1
√ √ X=Z≠Y 显示 1
√ √ X≠Y=Z 显示 1
× × × X≠Y≠Z 显示 0
编程时必须要考虑到所有 5种情况。
第 四 章 基 本 汇 编 语 言 程 序 设 计
884.11框图
X-Z
X=Y=ZX=Y≠ZX≠Y=Z X=Z≠Y
ZF=1
X-Y
X-Z
Y-Z
X≠Y≠Z
ZF=1
ZF=1
ZF=0
ZF=0
ZF=1
ZF=0
第 四 章 基 本 汇 编 语 言 程 序 设 计
894.13
4.13 例题 4.8内外循环次数共是多少?如果要求从大到小排序,程序如何修改?
待排序的数据共 20项外循环次数为 19次,每轮外循环中对应的内循环次数如下:
第 1轮 内循环次数 19
第 2轮 18
┆ ┆
第 18轮 2
第 19轮 1
因此,内循环次数共 19+18+17+…… +2+1=190,内外循环总数为 190+19=209次。
如果要求从大到小排序,每次比较时只要保证后面的数不大于前面的数,则第一轮外循环结束后,最小的数就排在了最后 。
第 四 章 基 本 汇 编 语 言 程 序 设 计
904.16
4.16 编程实现把键入的一个字符,用二进制形式( 0/1)显示出它的 ASCII码值。 ‘ A’→ 显示 01000001
1号功能调用( AL)
CX←8
AL左移(循环左移) 1位
CF=0?
MOV DL,31H
MOV DL,30H
A
B
B
MOV AH,2
INT 21H
循环结束?
结束
Y
NA0
1
第 四 章 基 本 汇 编 语 言 程 序 设 计
914.20
4.20 编程判断主存 0070,0开始的 1KB中有无字符串‘ DEBUG’。
DS←0070H;BX←0;CX←1024 -5
CMP BYTE PTR[BX],’D’
是 ‘ D’?
SI←BX;SI←SI+1
CMP BYTE PTR[SI],’E’
是 ‘ E’?
SI←SI+1
是 ‘ B’?
SI←SI+1
是 ‘ U’?
SI←SI+1
是 ‘ G’?
A
A
设置找到标志结束
B
B
BX←BX+1
查完?
结束
N
第 四 章 基 本 汇 编 语 言 程 序 设 计
924.21
4.21 编程将一个 16位无符号数转换成 5位 BCD码。
转换算法为:二进制数除以 10000,商为万位,再用余数除以 1000,得到千位,依次可以得到百位、十位、个位。
另外,也可以仿照例题 4.14的算法,先得到个位,
然后依次得到十位、百位、千位、万位。
第 四 章 基 本 汇 编 语 言 程 序 设 计
934.22
4.22 过程定义的一般格式?子程序入口为什麽常有
PUSH指令,出口为什麽 POP指令?下面的程序段有无不妥?若有请改正。
CRRAY PROC
PUSH AX
XOR AX,AX
XOR DX,DX
AGAIN,ADD AX,[BX]
ADC DX,0
INC BX
INC BX
LOOP AGAIN
RET
ENDP CRRAY
位置不对如果需要保护 AX,缺 POP AX。
实际上 DX AX为出口参数,
两个寄存器都不能保护和恢复; BX携带入口参数,
可保护也可不保护。当然,
有保护,势必有恢复。
第 四 章 基 本 汇 编 语 言 程 序 设 计
944.27
4.27 按如下子程序说明编写过程:;子程序功能:把用 ASCII码表示的两位十进制数转换为对应的二进制数;入口参数,DH=十位数的 ASCII码
DL=个位数的 ASCII码;出口参数,AL=对应的二进制数如果用 ASCII码表示的十进制数为多位数,可参照例题 4.13进行处理,此题只有两位十进制数,简单。
第 四 章 基 本 汇 编 语 言 程 序 设 计
954.28
4.28 写一个子程序,根据入口参数 AL=0/1/2,分别实现大写字母转换成小写、小写转换成大写或大小写相互转换。欲转换的字符串在 string中,用 0结束。
子程序中有三个分支,每个分支完成不同的转换,
转换过程可参照例题 4.7。
转入分支的方法,2种。
注意,每个分支的结束点都应有一条 JMP指令,跳转到恢复现场、返回主程序的程序段。
第 四 章 基 本 汇 编 语 言 程 序 设 计
964.29
4.29 编制一个子程序,把一个 16位二进制数用十六进制形式显示。分别运用三种参数传递方法,并用一个主程序验证。
1)采用 AX寄存器传递 16位二进制数
2)采用 wordTEMP变量传递 16位二进制数
3)采用堆栈传递 16位二进制数
16位二进制数可以用 4位十六进制数表示,该问题演变成将 4位二进制数转换成 ASCII码,转换过程可参照例题 4.10,或参照本课件,具有局部变量的子程序,
使用查表法编写。
应先转换最高 4位二进制数,然后依次转换。
第 四 章 基 本 汇 编 语 言 程 序 设 计
97二进制数转换成 ASCII码总结二进制数转换成 ASCII码总结:
1.二进制数转换成二进制形式的 ASCII码如习题 4.16,01000101B→30H 31H 30H …
2.二进制数转换成十六进制形式 ASCII码
4位二进制数 → 0-9,A-F
3.二进制数转换成十进制形式的 ASCII码
(二进制数转换成 BCD码)
二进制数除以 10,得到个位,再除以 10,得到十位,…
也可参照习题 4.21的方法,先得到最高位,然后依次得到低位。
反向转换可自行总结。
1封面
* * * * * * * * * * * * * * * * *
第 四 章 基 本 汇 编 语 言 程 序 设 计
2第四章基本汇编语言程序设计第四章 基本汇编语言程序设计
4.1 顺序程序设计
4.2 分支程序设计
4.3 循环程序设计
4.4 子程序设计
4.4.1 过程定义伪指令
4.4.2 子程序的参数传递
4.4.3 子程序的嵌套、递归与重入
4.4.4 子程序的应用本章要点及习题分析第 四 章 基 本 汇 编 语 言 程 序 设 计
34.1顺序程序设计 (e)
4.1 顺序程序设计指令按程序中的书写顺序逐条执行,称为顺序程序。
除非编程解决非常简单的问题,顺序程序并不多见,
但是顺序程序往往是复杂程序结构的一部分,如分支结构的一个分支,循环结构的循环体等。
返回第四章第 四 章 基 本 汇 编 语 言 程 序 设 计
4例 4.1
例 4.1:设有 3个字变量 x,y和 z,求出三者之和,结果存入字变量 w。
.model small,startup
.stack mov ax,x
.data add ax,y
X dw 5 add ax,z
Y dw 6 mov w,ax
Z dw 7,exit 0
W dw? end
.code
第 四 章 基 本 汇 编 语 言 程 序 设 计
5例 4.2/1
例 4.2 设有一个 64位数据,将它整个左移 8位。
12
34
56
78
87
65
43
21
00
qvar[0]
qvar[1]
qvar[2]
qvar[3]
qvar[4]
qvar[5]
qvar[6]
qvar[7]
第 四 章 基 本 汇 编 语 言 程 序 设 计
6例 4.2/2
.model small
.stack
.data
Qvar dq 1234567887654321h
.code
mov al,byte ptr qvar[6]
mov byte ptr qvar[7],al
mov al,byte ptr qvar[5]
mov byte ptr qvar[6],al
mov al,byte ptr qvar[4]
mov byte ptr qvar[5],al
mov al,byte ptr qvar[3]
mov byte ptr qvar[4],al
第 四 章 基 本 汇 编 语 言 程 序 设 计
7例 4.2/3
mov al,byte ptr qvar[2]
mov byte ptr qvar[3],al
mov al,byte ptr qvar[1]
mov byte ptr qvar[2],al
mov al,byte ptr qvar[0]
mov byte ptr qvar[1],al
mov byte ptr qvar[0],0
12 34 56 78 87 65 43 21h
34 56 78 87 65 43 21 00h
(移位前)
(移位后) 返回第四章第 四 章 基 本 汇 编 语 言 程 序 设 计
84.2分支程序设计
4.2 分支程序设计条件转移指令 Jcc和无条件转移指令 JMP用于实现程序的分支结构,JMP不测试条件,Jcc可根据条件是否成立决定转移到指定位置或不转移而顺序执行后续指令。由于 Jcc不支持条件表达式,而是以当前标志位的状态为条件,故 Jcc之前一定要安排设置标志位的指令,如加减法、比较、测试等指令。 基本分支类型分为单分支和双分支 。
第 四 章 基 本 汇 编 语 言 程 序 设 计
9单分支
1,单分支类型对同一个问题,根据选择的条件不同,单分支结构的流程图有两种画法,对应的程序也有两种编法。
如 计算 AX中的有符号数的绝对值。
第 四 章 基 本 汇 编 语 言 程 序 设 计
10单分支
cmp ax,0
jge noneg
neg ax
Noneg,mov result,ax
cmp ax,0
(教材有误) jnge yesneg
jmp done
yesneg,neg ax
Done,mov result,ax
AX≥0?
求补指令
Y
N
保存结果
AX< 0?
求补指令
Y
N
保存结果JMP
第 四 章 基 本 汇 编 语 言 程 序 设 计
11双分支
2.双分支程序两个分支都有语句体,如何选择条件不重要。
流程图中分支体的位置就是程序的实际顺序,故分支语句体1最后一定要有一条JMP
指令,跳过语句体2,
转移到,后续操作,。
条件成立?
分支语句体 2
Y
N
分支语句体 1
后 续 操 作
JMP
第 四 章 基 本 汇 编 语 言 程 序 设 计
12双分支双分支举例:显示 BX的最高位。
shl bx,1
jc one ;转分支体
mov dl,’0’ ;分支体 1
jmp next ;转后续操作
One,mov dl,’1’ ;分支体 2
next,mov ah,2 ;后续操作
int 21h
3,分支程序的其他问题
⑴有些双分支问题可以先假设一种情况,把双分支改成单分支问题。如上例,先假设 BX最高位为 0,
在分支外准备显示 0;如最高位为 0,即可直接跳到后续操作;如最高位为 1才需要执行分支体。⑵⑶
mov dl,’0’
shl bx,1
jnc next
mov dl,’1’
next:mov ah,2
int 21h
第 四 章 基 本 汇 编 语 言 程 序 设 计
13多分支
⑵ 分支的嵌套形成多分支,嵌套形式多种多样。
例 1:求符号函数 1 当 X>0
Y= 0 当 X=0
-1 当 X<0
X≥0? Y
N
X=0? Y
NY=-1
Y=1 Y=0
实际是双分支的组合。
第 四 章 基 本 汇 编 语 言 程 序 设 计
14多分支例 2:判断 AL各位的值,D0=1,转移到 L0; D1=1,转移到 L1; D2=1,转移到 L2……
D0=1
分支 L0
D2=1
D1=1
分支 L1
分支 L2
y
y
y
N
N
N
也可认为是双分支的组合,但为简化编程,实现左图的分支结构可以在数据段设置 转移地址表,如例题 4.4
第 四 章 基 本 汇 编 语 言 程 序 设 计
15多分支例 4.4 使用地址表实现多分支。 8个分支的标号分别为 disp1,disp2…
在代码段有:
disp1:mov dx,…
disp2:mov …
设 disp1的偏移地址为
2300h,disp2的偏移地址为 2500h…… 。
在数据段有:
tabel dw
disp1,disp2,…
tabel
disp1
︰
︰
disp4
disp3
2500H
2300H
disp5
disp6
disp7
disp8
0
2
4
6
8
A
C
E
相对 tabel
的偏移量第 四 章 基 本 汇 编 语 言 程 序 设 计
16多分支 (e)
转入分支:按输入的数字转入不同分支
①按输入的数字求出分支相对 tabel的偏移量:
disp1为 0,disp2为 2,disp3为 4…,如输入数字 2,则偏移量为 ( 2-1) × 2=2,将求出的偏移量存入 bx。
②执行指令 jmp tabel[bx],设 bx=02
则 IP← [tabel+bx]
即 IP← 2500H
③ CS:2500H为分支 Disp2的入口,CPU即执行分支 DISP2
返回第四章第 四 章 基 本 汇 编 语 言 程 序 设 计
174.3 循环程序设计
4.3 循环程序设计(重复执行的程序段)
1.循环程序的组成
初始化部分:设置循环条件、次数、初值等。
循环体部分:重复执行的代码,含循环条件的修改等。
循环控制部分:判断循环条件,决定是否继续。
2.两种循环结构
1),先循环、后判断,结构相当于高级语言的,直到型,循环
2),先判断、后循环,结构相当于高级语言的,当型循环,,可实现 0次循环。
第 四 章 基 本 汇 编 语 言 程 序 设 计
18两种循环结构初 始 化 部 分循 环条件成立?
循 环 体 部 分
(修改循环条件 )
N
Y
循 环条件成立?
初 始 化 部 分循 环 体 部 分
(修改循环条件 )
Y
N
第 四 章 基 本 汇 编 语 言 程 序 设 计
19循环程序设计
3.循环程序设计编写循环程序的关键在于循环的控制。
循环次数已知:可用 LOOP指令,CX计数。
如教材例 4.5。
循环次数和 ZF标志:可用 LOOPZ,LOOPNZ指令。
如教材例 4.6。
循环次数未知:通常要采用各类条件转移指令实现循环控制。如教材例 4.7,字符串以 0结尾;
例 4.9,字符串以 $结尾。
第 四 章 基 本 汇 编 语 言 程 序 设 计
20例题分析循环程序例题分析:
例 4.5:计算 100个数字之和。
仅用循环次数控制,且循环次数已知,比较简单。
例 4.6:确定一个字变量中为 1的最低位数。
从最低位向高位依次测试,最多测试 16次;测试到某位为 1,即可结束程序,测试结果用 ZF标志反映,
因此可用 LOOPE或 LOOPZ控制循环 (结果非 0,退出)。
例 4.7:将一个字符串中的所有大写字母改为小写字母,字符串以 0结尾。
循环次数未知,应使用条件判断控制循环;循环结构应使用,先判断、后执行,的结构;通常,采用条件判断控制循环时,往往采用,先判断、后执行,
的循环结构。
第 四 章 基 本 汇 编 语 言 程 序 设 计
21例题 4.6
例 4.6:确定一个字变量中为 1的最低位数。
.startup
mov ax,wordX ;测试目标送 AX
mov cx,16 ;循环计数器置初值
mov dl,-1 ;计位器置初值
again:inc dl
test ax,1
ror ax,1 ;循环指令不影响 ZF
loope again;CX≠0 且 ZF=1(测试位为 0),继续循环
je notfound ;退出循环,但 0标志成立,没有 1
mov byteY,dl
jmp done
notfound:mov byteY,-1;ZF=1,16个位均为 0
done:.exit 0
end
第 四 章 基 本 汇 编 语 言 程 序 设 计
22例题 4.7/1
例 4.7:将一个字符串中的所有大写字母改为小写字母,
字符串以 0结尾。.data
Steing db ‘xxxxxxxxxxxxxxxxxx’,0
.code
.startup
mov bx,offset string
again,mov al,[bx] ;取一个字符
or al,al ;是否为结尾符 0
jz done ;是,退出循环第 四 章 基 本 汇 编 语 言 程 序 设 计
23/2
cmp al,'A' ;是否为大写 A~ Z
jb next
cmp al,'Z'
ja next
or al,20h ;是,转换为小写字母(使
D5=1)
mov [bx],al ;仍保存在原位置
next,inc bx
jmp again ;继续循环
done:
.exit 0
end
第 四 章 基 本 汇 编 语 言 程 序 设 计
24两重循环结构
4.多重循环:循环程序的嵌套构成多重(多层)循环。
最常见的多重循环为两重循环。
外循环初始化内循环初始化内层循环体外层循环体内循环结束外循环结束
N
N
Y
Y
一个简单延时程序:
(双重循环)
mov cx,100
n_start,mov dx,0ffffh
n_loop,dec dx
jnz n_loop
dec cx
jnz n_start
内循环控制外循环控制第 四 章 基 本 汇 编 语 言 程 序 设 计
25“冒泡法,排序例 4.8:采用,冒泡法,排序 (升序)。
冒泡法从第一个元素开始,依次对相邻的两个元素进行比较,使前一个元素不大于后一个元素;将所有元素比较完之后,最大的元素排到了最后;第一轮比较结束。然后,开始第二轮,除掉最后一个元素,其他元素依上述方法再进行比较,得到次大的元素排在后面;第二轮结束。如此重复,直至完成,就实现了元素从小到大的排序循环次数已知的双重循环程序。外层循环(轮)
的次数为数据个数减 1,每一轮外循环的内层循环次数等于剩下的外循环次数。如 5个数据,外循环次数 =4,
第一轮中内循环次数也为 4;第一轮作完,还剩下 3轮,
第二轮中内循环次数等于 3,以次类推。
“冒泡法,排序小数冒泡
8
15
16
32
85
15
8
16
32
85
16
15
8
32
85
32
16
15
8
85
1 32
2 85
3 16
4 15
5 8
(1轮 )4(2轮 )3(3轮 )2(4轮 )1
外 循 环 次 数(轮次)
序号 数每 轮 内 循 环 次 数
4 3 2 1
大数沉底排序示意图 须作 4轮 第 1轮第 四 章 基 本 汇 编 语 言 程 序 设 计
27例 4.8 排序 /1
例 4.8 对无符号字节数组元素由小到大排序。.data
Array db xx,xx,xx,……Count equ ($-array)/(type array)
.code
mov cx,count ;CX← 数组元素个数
dec cx ;元素个数减 1为外循环次数
outlp:mov dx,cx ;DX← 内循环次数
mov bx,offset array
inlp:mov al,[bx] ;取前一个元素
cmp al,[bx+1] ;与后一个元素比较
jna next;前一个不大于后一个元素,则不进行交换
xchg al,[bx+1] ;否则,进行交换
mov [bx],al
第 四 章 基 本 汇 编 语 言 程 序 设 计
28例 4.8 排序 /2
next:inc bx ;下一对元素
dec dx
jnz inlp ;内循环尾
loop outlp ;外循环尾第 四 章 基 本 汇 编 语 言 程 序 设 计
29例 4.9 剔除空格程序例 4.9:剔除以$结尾的字符串中的空格。
①双重循环程序:外层循环负责搜索字符串中的空格;内层循环负责剔除搜索到的空格(由于空格后的字符要依次向前移动一个字节,因而也是一个循环结构)。
②无论是外层循环,还是内层循环,循环次数都未知,只能用,条件判断,控制循环。
③外层循环采用,先判断、后循环,结构;对内层循环而言,由于搜索到空格才进入内循环,所以采用,先循环、后判断,结构。
第 四 章 基 本 汇 编 语 言 程 序 设 计
30例 4.9/1
例 4.9,现有一个以 $结尾的字符串,要求剔除其中的空格。
.data
string db ’Let us have a try !’,’$’
.code
.startup
mov dx,offset string
mov ah,9
int 21h ;显示原字符串
mov al,’ ’ ;AL← 空格( ASCII码为 20H)
mov di,offset string
第 四 章 基 本 汇 编 语 言 程 序 设 计
31例 4.9/2
outlp:cmp byte ptr [di],’$’;外循环,先判断后循环
jz done ;为 $结束
cmp al,[di] ;检测是否是空格
jnz next ;不是空格继续外循环
mov si,di ;是空格,进入剔除空格分支
inlp:inc si ;该分支是循环程序段
mov ah,[si] ;取空格后的一个字符
mov [si-1],ah ;向前移动一个字节
cmp byte ptr [si],’$’;内循环,先循环后判断
jnz inlp
第 四 章 基 本 汇 编 语 言 程 序 设 计
32例 4.9/3
next:inc di ;继续对后续字符进行处理
jmp outlp
done:mov dx,offset string
mov ah,9
int 21h ;显示处理后字符串
.exit 0 ;结束
end
返回第四章第 四 章 基 本 汇 编 语 言 程 序 设 计
334.4 (目录)子程序设计
4.4 子程序设计把功能相对独立的程序段单独编写和调试,作为一个相对独立的模块供程序使用,就形成子程序。
使用子程序:简化源程序结构;提高编程效率。
4.4.1 过程定义伪指令
4.4.2 子程序的参数传递
4.4.3 子程序的嵌套递归重入
4.4.4 子程序的应用返回第四章第 四 章 基 本 汇 编 语 言 程 序 设 计
344.4.1 过程定义伪指令 (1)
4.4.1 过程定义伪指令过程名 PROC [NEAR|FAR]
过程体
RET( RET N)
过程名 ENDP
过程名:符合语法的标识符;同模块唯一性。
距离属性,可省略,由汇编程序判断。
堆栈使用:平衡。才能保证 RET指令弹出的是断点地址。
保护现场与恢复现场:子程序用到的寄存器或存储单元,注意:后进先出。
注意子程序的规范和格式
PUSH AX
PUSH BX
PUSH CX
PUSH DX
POP DX
POP CX
POP BX
POP AX
第 四 章 基 本 汇 编 语 言 程 序 设 计
35关于,距离属性,
关于,距离属性,
NEAR属性(段内近调用)的过程只能被相同代码段的其他程序调用
FAR属性(段间远调用)的过程可以被相同或不同代码段的程序调用对简化段定义格式,在微型、小型和紧凑存储模式下,过程的缺省属性为 near;在中型、大型和巨型存储模式下,过程的缺省属性为 far
对完整段定义格式,过程的缺省属性为 near
用户可以在过程定义时用 near或 far改变缺省属性第 四 章 基 本 汇 编 语 言 程 序 设 计
36子程序规范子程序规范一个完整的子程序,特别是供其他编程人员使用的子程序,必须附有一个详细说明:
子程序名(过程名)
子程序功能介绍
子程序的入口参数
子程序的出口参数
子程序内使用的寄存器(存储单元)
使用该子程序的范例
子程序名,DTOB
功能:完成两位十进制数转换成二进制数
入口参数,AL存放待转换的两位 BCD码
出口参数,CL存放转换后的二进制数
占用寄存器,BX
示例:输入 AL=01010110B ( 56H)
输出 CL=00111000B ( 38H)
某子程序的说明第 四 章 基 本 汇 编 语 言 程 序 设 计
37子程序的常见格式子程序的常见格式;子程序说明;子程序说明
subname proc;具有缺省属性的 subname过程
push ax ;保护寄存器:顺序压入堆栈
push bx ;ax/bx/cx仅是示例
push cx
… ;过程体
pop cx ;恢复寄存器:逆序弹出堆栈
pop bx
pop ax
ret ;过程返回
subname endp ;过程结束第 四 章 基 本 汇 编 语 言 程 序 设 计
38简单子程序简单子程序;子程序功能:实现光标回车换行
dpcrlf proc ;过程开始
push ax ;保护寄存器 AX和 DX
push dx
mov dl,0dh ;显示回车
mov ah,2
int 21h
mov dl,0ah ;显示换行
mov ah,2
int 21h
pop dx ;恢复寄存器 DX和 AX
pop ax
ret ;子程序返回
dpcrlf endp ;过程结束第 四 章 基 本 汇 编 语 言 程 序 设 计
39例 4.10:编写子程序 (e)
例 4.10:编写子程序,将 AL寄存器内的二进制数用十六进制数显示。
8位二进制数,可转换成两位十六进制数。
十六进制数 → ASCII码 → 2#功能调用显示
1001B→9H→1001+ 0011 0000→39H ( 9的 ASCII)
1010B→AH→1010+ 0011 0111→41H ( A的 ASCII)
注意:对 0-9加 30H,对 A-F加 37H,即 +30H+07H
先转换高 4位二进制数,并显示;然后转换低 4位并显示。
例题 410 回 4.4
第 四 章 基 本 汇 编 语 言 程 序 设 计
404.4.2 子程序的参数传递
4.4.2 子程序的参数传递主程序和子程序之间通常需要传递参数:
入口参数 (输入参数):主程序提供给子程序
出口参数 (输出参数):子程序返回给主程序
参数的形式,
① 数据本身(传值)
② 数据的地址(传址)
传递的方法,
① 寄存器 ② 变量 ③ 堆栈第 四 章 基 本 汇 编 语 言 程 序 设 计
41参数传递方法
1.用寄存器传递参数方便、简单、易行。须要传递的参数较多时不适用。 见例题 411a。
2.用变量传递参数就是用存储器传递参数,当主程序与子程序在同一个模块时,即为共享数据段的变量;不在同一模块,需要用
PUBLIC/EXTERN声明。
适用与参数较多情况。 见例题 411b。
3.用堆栈传递参数常用方法。用 BP访问堆栈段。须格外注意堆栈的平衡。
(堆栈示意图)
第 四 章 基 本 汇 编 语 言 程 序 设 计
42
堆栈示意图使用堆栈传递参数时堆栈示意图:
┇
PUSH 参数 1
PUSH 参数 2
PUSH 参数 3
CALL SUBPRO
┇
.EXIT 0
SUBPRO PROC
PUSH BP
MOV BP,SP
PUSH AX
┇
POP AX
POP BP
RET (RET 6)
SUBPRO ENDP
A X
B P
I P
参数 3
参数 2
参数 1
BP=SP
BP+2
BP+4
BP+6
BP+8
SP(原始 )
子程序取参数:
MOV AX,[BP+4(6,8)]
子程序平衡堆栈,RET 6
主程序平衡堆栈,ADD SP,6
例题 411c
SP
第 四 章 基 本 汇 编 语 言 程 序 设 计
43例题 4.11c/1
例题 4.11c,计算累加和;用堆栈传递参数;入口参数,数组首地址、数组元素个数;出口参数,AL 累加和
.model small
.stack
.data
count equ 10
array db
12h,25h,0f0h,0a3h,03,68h,71h,0cah,0ffh,90h
result db?
第 四 章 基 本 汇 编 语 言 程 序 设 计
44例题 4.11c/2
.code
.startup
mov ax,offset array
push ax ;首地址入栈
mov ax,count
push ax ;元素个数入栈
call checksuma
add sp,4 ;平衡两个参数占用的堆栈
mov result,al
.exit 0
第 四 章 基 本 汇 编 语 言 程 序 设 计
45例题 4.11c/3
checksuma proc
push bp
mov bp,sp;使 BP指向刚进入子程序的堆栈顶,
push bx
push cx
mov bx,[bp+6]
mov cx,[bp+4]
xor al,al
suma,add al,[bx]
inc bx
loop suma
第 四 章 基 本 汇 编 语 言 程 序 设 计
46例题 4.11c/4
pop cx
pop bx
pop bp
ret ;可以用 RET 4
checksuma endp
end
第 四 章 基 本 汇 编 语 言 程 序 设 计
47编写子程序时应注意的问题编写子程序时应注意的问题:
①使用简化的段定义格式时,过程定义在程序中的位置要注意,可以放在 1)主程序的最后,即
,.EXIT 0”之后,END语句之前; 2)放在主程序之前,
即,,CODE”之后,,.STARTUP”之前。
②使用寄存器传递参数时,带有入口参数的寄存器可以保护,也可以不保护;带有出口参数的寄存器则一定不可保护和恢复;其他与出口参数无关、而子程序中使用的寄存器,子程序开始处应该保护,子程序结束、返回主程序之前应该恢复。
回 4.4
第 四 章 基 本 汇 编 语 言 程 序 设 计
484.4.3 子程序的嵌套递归重入
4.4.3 子程序的嵌套、递归与重入
1.子程序的嵌套子程序又调子程序称为子程序的嵌套,嵌套的层数取决于堆栈空间的大小。嵌套子程序的设计和一般子程序完全相同。
2.子程序的递归子程序直接或间接地嵌套调用自己,称为递归调用。含有递归调用的子程序称为递归子程序。
每次调用时不能破坏以前调用所用的参数及中间结果,
因此,调用参数及中间结果一般都放在堆栈中。不可放在固定的寄存器或存储单元中。
要控制递归的次数,避免陷入死循环。
递归深度受堆栈空间的限制。
第 四 章 基 本 汇 编 语 言 程 序 设 计
49例题 4.12
例题 4.12 用递归子程序求 N的阶乘,设 N=3。
递归次数用 N控制,由 N=3,子程序共运行 4次(主程序调用 1次,递归调用 3次);入口参数及中间结果都用堆栈保存。
注释,1)在进入子程序过程中,不计算阶乘值,
只求中间参数。第一次进入,求出中间参数 2;第二次进入求出中间参数 1;第三次进入求出中间参数 0;
第四次进入后,由于中间参数以为 0,开始执行返回处理。
2)在返回过程中计算阶乘:在过程 3中计算 1*1=1,
在过程 2中计算 1*2=2,在过程 1中计算 2*3=6。
3)递归子程序可设计出效率较高的程序,但是编程较难,编出的程序易读性差,使用不多。
第 四 章 基 本 汇 编 语 言 程 序 设 计
50子程序的重入 (e)
3.子程序的重入子程序被中断后,又被中断服务程序所调用,称为子程序的重入。能够重入的子程序称为可重入子程序。
当主机与外设采用中断方式交换信息时,外设的驱动程序应按,可重入原则,设计。
虽然重入与递归的概念不同,但递归子程序就是可重入子程序。设计可重入子程序与设计递归子程序的原则是相同的,即参数、中间结果等都用堆栈保存,不能用固定的存储单元或寄存器保存。
回 4.4
第 四 章 基 本 汇 编 语 言 程 序 设 计
514.4.4 子程序的应用
4.4.4 子程序的应用
1) 例题 4.15 计算有符号数的平均值。
有时进行运算之前,需要符号扩展;对无符号数应进行 0扩展。
2)具有局部变量的子程序(截取教材 P123部分程序):当某些数据只有子程序自己使用时,可在代码段子程序后面定义数据区。
3)具有多个出口的子程序:有的子程序具有多个出口,根据条件的不同,从不同的出口返回主程序。
第 四 章 基 本 汇 编 语 言 程 序 设 计
52例 4.15 计算平均值 /1
例 4.15 计算有符号数的平均值。;入口参数用堆栈传递,出口参数用寄存器 AX传递。;要计算 16位有符号数的和,被加数一定要进行符号扩展。
.model small
.stack
.data
array dw 1234,-1234,1,1,-1,32767,-32768,5678,
-5678,9000
count equ ($-array)/2 ;数据个数
wmed dw?
第 四 章 基 本 汇 编 语 言 程 序 设 计
53/2
.code
.startup
mov ax,count
push ax ;参数 1
mov ax,offset array
push ax ;参数 2
call mean
add sp,4 ;平衡堆栈
mov wmed,ax
.exit 0
第 四 章 基 本 汇 编 语 言 程 序 设 计
54/3
mean proc
push bp
mov bp,sp
push bx
push cx
push dx
push si
push di
mov bx,[bp+4];取参数 2:偏移地址
mov cx,[bp+6];取参数 1:数据个数
xor si,si
mov di,si
第 四 章 基 本 汇 编 语 言 程 序 设 计
55/4
mean1,mov ax,[bx]
cwd
add si,ax
adc di,dx
inc bx
inc bx
loop mean1
mov ax,si
mov dx,di
mov cx,[bp+6]
dx.ax
+ di.si
di.si
第 四 章 基 本 汇 编 语 言 程 序 设 计
56/5
idiv cx ;求平均值,商在 AX,余数在 DX
pop di
pop si
pop dx
pop cx
pop bx
pop bp
ret
mean endp
end
第 四 章 基 本 汇 编 语 言 程 序 设 计
57避免溢出的方法
为了避免有符号二进制数求和过程中溢出,被加数要进行符号扩展,得到倍长数据(大小没有变化),
然后求和
如数据采用 16位二进制数表示,数据个数也采用 16
位二进制数表示,则最多为 216个数据。如将数据扩展到 32位二进制数表示,求和时,就不会出现溢出。
考虑极端情况:数据全是- 215( -32768),共有 216
个,求和结果是- 231,32位数据仍然可以表达。
对于无符号数,有时也需要得到倍长数据,应采用
,0扩展,,即将高位置 0,如,MOV DX,0”。;将 AL低 4位表达的一位 16进制数转换为 ASCII码
H2ASC proc
push bx
mov bx,offset ASCII ;BX指向 ASCII码表
and al,0fh ;取得一位 16进制数
xlat CS:ASCII;换码,AL←CS:[BX + AL],注意数据在代码段 CS
pop bx
ret ;子程序返回
ASCII db 30h,31h,32h,33h,34h,35h,36h,37h
db 38h,39h,41h,42h,43h,44h,45h,46h
H2ASC endp
例题 具有局部变量的子程序因为数据区与子程序都在代码段,所以利用了换码指令 XLAT的另一种助记格式 ( 写出指向缓冲区的变量名,目的是便于指明段超越前缀 ) 。 串操作 MOVS,LODS和 CMPS指令也可以这样使用,以便使用段超越前缀除采用段超越方法外,子程序与主程序的数据段不同时,我们还可以通过修改 DS值实现数据存取;但需要保护和恢复 DS寄存器
HTOASC proc;将 AL低 4位表达的一位 16进制数转换为 ASCII码
and al,0fh
cmp al,9
jbe htoasc1
add al,37h ;是 0AH~ 0FH,加 37H
ret ;子程序返回
htoasc1,add al,30h ;是 0~ 9,加 30H
ret ;子程序返回
HTOASC endp
例题 具有多个出口的子程序回 4.4
第 四 章 基 本 汇 编 语 言 程 序 设 计
60例 4.13
例 4.13 编写子程序从键盘输入一个有符号十进制数;
并将输入的 ASCII码转换为二进制数。
输入时,负数用,-,引导,正数直接输入或用
,+,引导
子程序用寄存器传递出口参数,主程序调用该子程序输入 10个数据
将 ASCII码转换为二进制数的过程
① 首先判断输入为正或负数,并用一个寄存器记录
② 接着输入 0~ 9数字( ASCII码),并减 30H转换为二进制数
③ 然后将前面输入的数值乘 10,并与刚输入的数字相加得到新的数值
④ 重复②、③步,直到输入一个非数字字符结束
⑤ 负数进行求补,转换成补码;否则直接保存数值第 四 章 基 本 汇 编 语 言 程 序 设 计
61输入和转换流程图输入和转换流程图:
A
负数求补,正数不变出口参数 → AX
返回
1号调用输入字符是 ‘ +’?
是 ‘ -’?
置负数标志输入下一个
0-9之间变成二进制数
BX*10+AL→BX
Y
N
N A
输入非数字字符,结束输入第 四 章 基 本 汇 编 语 言 程 序 设 计
62输入数字举例设从键盘输入数字 –258:
输入顺序,- 2 5 8
CX -1 -1 -1 -1
BX 0 0002 0019H=25 0102H=258
数字输入结束后,由于 CX为负数标志,
再对 BX求补。
第 四 章 基 本 汇 编 语 言 程 序 设 计
63程序 /1
.data
count = 10
array dw count dup(0) ;预留数据存储空间
.code
.startup
mov cx,count
mov bx,offset array
again:call read ;调用子程序输入一个数据
mov [bx],ax ;将出口参数存放缓冲区
inc bx
inc bx
call dpcrlf;调用子程序,光标回车换行以便输入下一个数据
loop again
.exit 0
这是主程序第 四 章 基 本 汇 编 语 言 程 序 设 计
64程序 /2;输入有符号 10进制数的通用子程序;出口参数,AX=补码表示的二进制数值
read proc
push bx
push cx
push dx
xor bx,bx ;BX保存结果
xor cx,cx;CX为正负标志,0为正,- 1为负
mov ah,1;输入一个字符
int 21h
第 四 章 基 本 汇 编 语 言 程 序 设 计
65程序 /3
cmp al,'+' ;是,+,,继续输入字符
jz read1
cmp al,'-' ;是,-,,设置- 1标志
jnz read2 ;非,+,和,-,,转 read2
mov cx,-1
read1,mov ah,1;继续输入字符
int 21h
read2,cmp al,'0‘;不是 0~ 9之间的字符,则输入数据结束
jb read3
cmp al,'9'
ja read3
第 四 章 基 本 汇 编 语 言 程 序 设 计
66程序 /4
sub al,30h;是 0~ 9之间的字符,则转换为二进制数;利用移位指令,实现数值乘 10,BX←BX × 10
shl bx,1
mov dx,bx
shl bx,1
shl bx,1
add bx,dx
mov ah,0
add bx,ax;已输入数值乘 10后,与新输入数值相加
jmp read1 ;继续输入字符第 四 章 基 本 汇 编 语 言 程 序 设 计
67程序 /5
read3:cmp cx,0
jz read4
neg bx ;是负数,进行求补
read4,mov ax,bx ;设置出口参数
pop dx
pop cx
pop bx
ret ;子程序返回
readendp
dpcrlf proc ;使光标回车换行的子程序
..,;省略
dpcrlf endp
end
第 四 章 基 本 汇 编 语 言 程 序 设 计
68例 4.14
例 4.14 编写子程序,将二进制数转换为 10进制数的
ASCII码,并在屏幕上显示一个有符号 10进制数。
显示时,负数用,-,引导,正数直接输出、没有前导字符。
子程序的入口参数用共享变量传递,主程序调用该子程序显示 10个数据。
将二进制数转换为 10进制数的 ASCII码
① 首先判断数据是零、正数或负数,是零显示,0”退出
② 是负数,显示,-,,求数据的绝对值;
③ 接着数据除以 10,余数加 30H转换为 ASCII码压入堆栈
④ 重复③步,直到余数为 0结束
⑤ 依次从堆栈弹出各位数字,进行显示第 四 章 基 本 汇 编 语 言 程 序 设 计
69显示数字举例显示数字举例:设 AX中数据为 -258的补码
1.显示负号 ‘ -’。
2.求补,AX中得到 -258的绝对值。
3.258/10,商为 25,余数为 8,此为个位。
8+30H,入栈。
4.25/10,商为 2,余数为 5,此为十位。
5变 ASCII码入栈。
5.2/10,商为 0,余数为 2,此为百位。
2变 ASCII码入栈。
6.由于商为 0,变换结束。
7.顺序出栈显示。
第 四 章 基 本 汇 编 语 言 程 序 设 计
70程序 /1
.data
Count = 10Array dw 1234,-1234,0,1,-1,32767,-32768,
dw 5678,-78,9000
Wtemp dw? ;共享变量.code
.startup
mov cx,count
mov bx,offset array
again:mov ax,[bx]
mov wtemp,ax ;将入口参数存入共享变量
call write ;调用子程序显示一个数据
inc bx
inc bx
call dpcrlf ;便于显示下一个数据
loop again
.exit 0
第 四 章 基 本 汇 编 语 言 程 序 设 计
71程序 /2;显示有符号 10进制数的通用子程序;入口参数:共享变量 wtemp
write proc
push ax
push bx
push dx
mov ax,wtemp ;取出显示数据
test ax,ax ;判断零、正数或负数
jnz write1
mov dl,'0' ;是零,显示,0”后退出
mov ah,2
int 21h
jmp write5 ;恢复现场后返回第 四 章 基 本 汇 编 语 言 程 序 设 计
72程序 /3
write1,jns write2 ;不是负数,转向数据转换。
mov bx,ax ;是负数,显示,-,
mov dl,'-'
mov ah,2
int 21h
mov ax,bx
neg ax ;求绝对值
write2,mov bx,10 ;准备除数
push bx;10压入堆栈,作为退出标志第 四 章 基 本 汇 编 语 言 程 序 设 计
73程序 /4
write3,cmp ax,0;数据(商)为零
jz write4 ;转向显示
sub dx,dx ;扩展被除数 DX.AX
div bx ;数据除以 10,DX.AX÷ 10
add dl,30h;余数( 0~ 9)转换为 ASCII码
push dx;数据各位先低位后高位压入堆栈
jmp write3
0032h
0035h
0038h
10
仍以 258为例 25
8
第 四 章 基 本 汇 编 语 言 程 序 设 计
74程序 /5
write4:pop dx ;数据各位先高位后低位弹出堆栈
cmp dl,10 ;是结束标志 10,则退出
je write5
mov ah,2 ;进行显示
int 21h
jmp write4
write5:pop dxpop bx
pop axret ;子程序返回
write endp
dpcrlf proc ;使光标回车换行的子程序
..,;省略dpcrlf endp
end
第 四 章 基 本 汇 编 语 言 程 序 设 计
75本章要点本章要点,
分支程序设计:
单分支、双分支、多分支单分支流程图的画法用转移地址表法实现多分支
循环程序设计:
两种循环结构循环程序的控制方法:计数法、条件判断法单层循环和双层循环
子程序设计:
过程定义伪指令子程序的参数传递:寄存器、变量、堆栈第 四 章 基 本 汇 编 语 言 程 序 设 计
76习题分析:补充 1
1.将 AX中存放的无符号数除以 2,如果是奇数,则加
1后除以 2(单分支)
test ax,01h ;测试 AX最低位
jz even ;最低位为 0,AX为偶数
add ax,1;最低位为 1,AX为奇数,需要加 1
even:rcr ax,1 ;AX←AX ÷ 2;如果采用 SHR指令,则不能处理 AX= FFFFH的特殊情况第 四 章 基 本 汇 编 语 言 程 序 设 计
77补充 2/1
2.判断一元二次方程是否有实根。有,TAG置 1;
无,TAG置 0。(教材例题 4.3:双分支)
.data
a db?
b db?
c db?
tag db?
.code
.startup
mov al,b
imul al
mov bx,ax ;BX中为 b2
第 四 章 基 本 汇 编 语 言 程 序 设 计
78补充 2/2
mov al,a
imul c
mov cx,4
imul cx ;AX中为 4ac( DX无有效数据)
cmp bx,ax ;比较二者大小
jge yes ;条件满足?
mov tag,0 ;第一分支体:条件不满足,tag←0
jmp done ;跳过第二个分支体
yes:mov tag,1 ;第二分支体:条件满足,tag←1
done:.exit 0
end
第 四 章 基 本 汇 编 语 言 程 序 设 计
79补充 3/1
3.按键盘输入的数字 1-8,转 8个分支(显示不同的信息)。 (同教材例题 4.4,但显示的信息不同)
分析过程见课件 4.2节的,多分支部分,
.data
msg db 'Input number(1~8):',0dh,0ah,'$'
Msg1 db 'Chapter 1,,..',0dh,0ah,'$'
msg2 db 'Chapter 2,,..',0dh,0ah,'$‘
...
msg8 db 'Chapter 8,,.,',0dh,0ah,'$'
table dw disp1,disp2,disp3,disp4
dw disp5,disp6,disp7,disp8;取得各个标号的偏移地址第 四 章 基 本 汇 编 语 言 程 序 设 计
80补充 3/2
………
start1:mov dx,offset msg ;提示输入数字
mov ah,9
int 21h
mov ah,1 ;等待按键
int 21h
cmp al,'1' ;数字 < 1?
jb start1
cmp al,'8' ;数字 > 8?
ja start1
and ax,000fh ;将 ASCII码转换成数字第 四 章 基 本 汇 编 语 言 程 序 设 计
81补充 3/3
dec ax
shl ax,1 ;等效于 add ax,ax
mov bx,ax
jmp table[bx];(段内)间接转移,IP←[table+bx]
start2:mov ah,9
int 21h
.exit 0
disp1,mov dx,offset msg1;处理程序 1
jmp start2
Disp2:…
...
end
第 四 章 基 本 汇 编 语 言 程 序 设 计
82习题 4.4
习题分析
4.4 编写一个程序,把从键盘输入的一个小写字母用大写字母显示出来。
框图,( 省略输入字符的判断:简单的顺序程序)
1号调用:输入字符
AL←AL -20H
2号调用:显示字符结 束第 四 章 基 本 汇 编 语 言 程 序 设 计
834.5
4.5 已知用于 LED数码管显示的代码表为:
LEDTABEL DB 0C0H,0F9H… (共 16项数据)
依次表示 0~ 9,A~ F这 16个数码的显示代码,编写一个程序实现将 lednum中的一个数字转换成对应的 LED显示代码。(查表程序)
BX← 代码表首地址
AL←[lednum]
执行指令 XLAT AL中即为所求的显示代码第 四 章 基 本 汇 编 语 言 程 序 设 计
844.8
4.8 如果在例题 4.4的 tabel中依次添入 msg1~ msg8,
程序应该如何修改? (Tabel dw msg1,…,)
┆ ┆
mov bx,ax mov bx,ax
jmp tabel[bx] mov dx,tabel[bx]
Start2,mov ah,9 mov ah,9
int 21h int 21h
.exit 0,exit 0
┆ end
程序变得更加简单。
取显示信息偏移地址取转移地址送 IP
第 四 章 基 本 汇 编 语 言 程 序 设 计
854.9
4.9 编制一个程序,将变量 BUFX,BUFY中较大者送入
BUFZ;若两者相等,则把其中之一送入 BUFZ中。设变量为无符号 8位数。
AL←[BUFX]
CMP AL,BUFY
AL小于 [BUFY]?
AL←[BUFY]
[BUFZ]←AL
Y
N
DONE:
JAE DONE
第 四 章 基 本 汇 编 语 言 程 序 设 计
864.10
4.10 设变量 bufX为有符号数,编程将其符号状态保存在 singX,如 X大于等于 0,保存 0;如 X小于 0,保存 -1。
该题为一个可以演变成单分支的双分支结构:
测试 bufX符号
≥0
-1→singX
0→singX
next
Y
0→singX
测试 bufX符号
≥0
-1→singX
next
Y
第 四 章 基 本 汇 编 语 言 程 序 设 计
874.11
4.11 X,Y,Z是三个有符号 16位数(教材误印为 16进制数),编写程序:
1)三个数都不相等,显示 0;
2)有两个数相等,显示 1;
3)三个数都相等,显示 2。
三个数比较,应有 5种情况:
X Y Z
√ √ √ X=Y=Z 显示 2
√ √ X=Y≠Z 显示 1
√ √ X=Z≠Y 显示 1
√ √ X≠Y=Z 显示 1
× × × X≠Y≠Z 显示 0
编程时必须要考虑到所有 5种情况。
第 四 章 基 本 汇 编 语 言 程 序 设 计
884.11框图
X-Z
X=Y=ZX=Y≠ZX≠Y=Z X=Z≠Y
ZF=1
X-Y
X-Z
Y-Z
X≠Y≠Z
ZF=1
ZF=1
ZF=0
ZF=0
ZF=1
ZF=0
第 四 章 基 本 汇 编 语 言 程 序 设 计
894.13
4.13 例题 4.8内外循环次数共是多少?如果要求从大到小排序,程序如何修改?
待排序的数据共 20项外循环次数为 19次,每轮外循环中对应的内循环次数如下:
第 1轮 内循环次数 19
第 2轮 18
┆ ┆
第 18轮 2
第 19轮 1
因此,内循环次数共 19+18+17+…… +2+1=190,内外循环总数为 190+19=209次。
如果要求从大到小排序,每次比较时只要保证后面的数不大于前面的数,则第一轮外循环结束后,最小的数就排在了最后 。
第 四 章 基 本 汇 编 语 言 程 序 设 计
904.16
4.16 编程实现把键入的一个字符,用二进制形式( 0/1)显示出它的 ASCII码值。 ‘ A’→ 显示 01000001
1号功能调用( AL)
CX←8
AL左移(循环左移) 1位
CF=0?
MOV DL,31H
MOV DL,30H
A
B
B
MOV AH,2
INT 21H
循环结束?
结束
Y
NA0
1
第 四 章 基 本 汇 编 语 言 程 序 设 计
914.20
4.20 编程判断主存 0070,0开始的 1KB中有无字符串‘ DEBUG’。
DS←0070H;BX←0;CX←1024 -5
CMP BYTE PTR[BX],’D’
是 ‘ D’?
SI←BX;SI←SI+1
CMP BYTE PTR[SI],’E’
是 ‘ E’?
SI←SI+1
是 ‘ B’?
SI←SI+1
是 ‘ U’?
SI←SI+1
是 ‘ G’?
A
A
设置找到标志结束
B
B
BX←BX+1
查完?
结束
N
第 四 章 基 本 汇 编 语 言 程 序 设 计
924.21
4.21 编程将一个 16位无符号数转换成 5位 BCD码。
转换算法为:二进制数除以 10000,商为万位,再用余数除以 1000,得到千位,依次可以得到百位、十位、个位。
另外,也可以仿照例题 4.14的算法,先得到个位,
然后依次得到十位、百位、千位、万位。
第 四 章 基 本 汇 编 语 言 程 序 设 计
934.22
4.22 过程定义的一般格式?子程序入口为什麽常有
PUSH指令,出口为什麽 POP指令?下面的程序段有无不妥?若有请改正。
CRRAY PROC
PUSH AX
XOR AX,AX
XOR DX,DX
AGAIN,ADD AX,[BX]
ADC DX,0
INC BX
INC BX
LOOP AGAIN
RET
ENDP CRRAY
位置不对如果需要保护 AX,缺 POP AX。
实际上 DX AX为出口参数,
两个寄存器都不能保护和恢复; BX携带入口参数,
可保护也可不保护。当然,
有保护,势必有恢复。
第 四 章 基 本 汇 编 语 言 程 序 设 计
944.27
4.27 按如下子程序说明编写过程:;子程序功能:把用 ASCII码表示的两位十进制数转换为对应的二进制数;入口参数,DH=十位数的 ASCII码
DL=个位数的 ASCII码;出口参数,AL=对应的二进制数如果用 ASCII码表示的十进制数为多位数,可参照例题 4.13进行处理,此题只有两位十进制数,简单。
第 四 章 基 本 汇 编 语 言 程 序 设 计
954.28
4.28 写一个子程序,根据入口参数 AL=0/1/2,分别实现大写字母转换成小写、小写转换成大写或大小写相互转换。欲转换的字符串在 string中,用 0结束。
子程序中有三个分支,每个分支完成不同的转换,
转换过程可参照例题 4.7。
转入分支的方法,2种。
注意,每个分支的结束点都应有一条 JMP指令,跳转到恢复现场、返回主程序的程序段。
第 四 章 基 本 汇 编 语 言 程 序 设 计
964.29
4.29 编制一个子程序,把一个 16位二进制数用十六进制形式显示。分别运用三种参数传递方法,并用一个主程序验证。
1)采用 AX寄存器传递 16位二进制数
2)采用 wordTEMP变量传递 16位二进制数
3)采用堆栈传递 16位二进制数
16位二进制数可以用 4位十六进制数表示,该问题演变成将 4位二进制数转换成 ASCII码,转换过程可参照例题 4.10,或参照本课件,具有局部变量的子程序,
使用查表法编写。
应先转换最高 4位二进制数,然后依次转换。
第 四 章 基 本 汇 编 语 言 程 序 设 计
97二进制数转换成 ASCII码总结二进制数转换成 ASCII码总结:
1.二进制数转换成二进制形式的 ASCII码如习题 4.16,01000101B→30H 31H 30H …
2.二进制数转换成十六进制形式 ASCII码
4位二进制数 → 0-9,A-F
3.二进制数转换成十进制形式的 ASCII码
(二进制数转换成 BCD码)
二进制数除以 10,得到个位,再除以 10,得到十位,…
也可参照习题 4.21的方法,先得到最高位,然后依次得到低位。
反向转换可自行总结。