第一章 概述 第一节 引言
DESCRIPTION
微机系统原理及应用. 第一章 概述 第一节 引言. 从 8088 、 8086 到 80386 以上直至 奔腾 ,只有 16 位与 32 位的区分,没有本质区别。芯片的指令 80% 以上是完全相同的,芯片的实地址工作方式几乎完全一致,所以 8088 、 8086 是 Intel x 86 系列的基础,要学习 x86 系列的最好办法就是从 8088 、 8086 入手。 PC 机的存储器( M )容量很大,但基本存储单元的工作原理不变;存储器与 CPU 的接口原理、方法没有变。 本书从 8088 、 8086 入手学习 PC. 第一节 引言. 一、计算机中的数制 - PowerPoint PPT PresentationTRANSCRIPT
1
第一章 概述第一节 引言
2
第一节 引言
从 8088 、 8086 到 80386 以上直至奔腾,只有 16 位与 32 位的区分,没有本质区别。芯片的指令 80% 以上是完全相同的,芯片的实地址工作方式几乎完全一致,所以 8088 、 8086 是 Intel x 86 系列的基础,要学习x86 系列的最好办法就是从 8088 、 8086 入手。
PC 机的存储器( M )容量很大,但基本存储单元的工作原理不变;存储器与 CPU 的接口原理、方法没有变。
本书从 8088 、 8086 入手学习 PC
4
一、计算机中的数制 (一)二进制数的基本特点 1. 具有两个不同的数字符号,即 0 和 1 。 2. 逢二进位。 任意一个二进制数可以按“权”展开
i21n
mi iB
m2mB...121B
020
nB121
nB...1n21nB2
(B)
10(7.75)221121021221
2(111.11)
5
(二) 16 进制数 1. 0 至 9 和 A 至 F 。 2. 逢 16 进位。
① 16 进制数转化为 2 进制数。
② 2 进制数转换为 16 进制数。
1001
16 (50)162163(32)
i16 16D(D)
1n
mi i
16(3AB)
00113 10
1010A
11
1011B
2)110011101010( 16(3AB)
81000
70111
91001.
30011
E1110
B1011
10001
1BE3.978)(01111)0011.1001111011011(
16
2
7
二、二进制编码字符是用若干位二进制编码的组合表示字符、数,这称为二进制编码。
(一)二进制编码的十进制数( BCD ) 计算机的输入与输出是用十进制表示
(二)字母与字符的编码 ASCⅡ :实用标准信息交换码,用 7 位二 进制编码,可表示 128 个字符。 用一个字节来表示一个 ASCⅡ 字符 0 至 9 的 ASCⅡ 码为 30H 至 39H 大写字母 A 至 Z 的 ASCⅡ 码为 41H 至 5AH 小写字母 a 至 z 的 ASCⅡ 码为 61H 至 7AH
(三) 汉字的编码 这个字符集中的任何一个图形、符号及 汉字都是两个 7 位字节表示的 ( 每个字节的 最高位置为 0 )。
P507P507
8
三、二进制的运算计算机可进行两种基本的算术运算:加法和减法。利用这两种方法就可以进行乘法、除法以及其它数值运算。
逻辑运算: 1. “ 与”运算 (AND) 3. “ 非”运算 (NOT)
2. “ 或”运算 (OR) 4. “ 异或”运算 (XNOT)
(一)二进制加法 它的运算规则如下: 0+0=0 例如: 0+1=1+0=1
1+1=0 进位 1
1+1+1=1 进位 1
(二)二进制减法 它的运算规则如下:
BABA
AA
BA
1100010111101
9
0-0=0 借位 1-1=0 例如: 1-0=1 0-1=1 借位
(三)二进制乘法 它的运算规则如下: 0*0=0 例如: 0*1=0
1*0=0
1*1=1
由于此乘法的重复性差 , 不便 于在机器中实现,现在下面 用另外两种方式将运算实现。
100111110010010111000100
1100001111111111
1111
1101
1111
10
1. 被乘数左移法 乘数 被乘数
部分积 1101 1111
乘数最低位 11110 为 1, 把被乘数 加部分积 , 再 把被乘数左移 乘数为 0 ,不加, 111100 被乘数左移 同上 1111000 同上 n*n2n 位 2n 位加法器
111111110000
1100001111110001001011
1111001111
11
2. 部分积右移法 乘数
被乘数 部分积 1101 1111 乘数为 1, 加被乘 数部分积右移 0, 不加部分积 右移 1, 加被乘数部分 积右移 1, 加乘数右移
2 个 n*n乘积 2n 位 此种方法只需要 n 位加法器。
10111111111110000
00111100
011110001111
0111001
11100101111
110011
12
(四) 二进制的除法 例如:
四、带符号数的表示法 ( 一 ) 机器数与真值 数有正、有负 , 那么负数的符号是怎么表示的呢? 通常一个数的最高位为符号位 , 若字长为 8 位 ,
则
000111
0
101
101
101
0111
101100011101
7D
13
为符号位。符号位用“ 0” 表示正,用“ 1” 表示负。 例如:
连用一个符号位在一起的一个数,称为机器数。 它的数值称为机器数的真值。在机器数中符号有三种 表示法:原码,反码和补码。 ( 二 ) 原码 正数的符号位用“ 0” 表示,负数的符号位用“ 1” 表示的 表示法称为原码。 例如:
符号值 数值 ( 三 ) 反码 正数的反码与其原码相同,负数的反码是它的正数按位
91210111101x
91210110101x
105x
105x
1x
0x
Y
Y
0011101
0011101
14
取反 ( 连同符号位 ) 而形成的。 例如:
注: 符号位 取反的部分
反码的特点: 1. “0” 有两种表示法 2. 8 位二进制反码所表示的数值范围为 +127-127 。 即 , 3. 当一个符号数由反码表示时,最高位为符号数。 当符号数为“ 0” 时,后面的七位为数值部分; 当符号数为“ 1” 时,后面的七位一定要把它们按位取反,
以 表示它的二进制值。
101111114
010000004
F
F
111111110
000000000
F
F
010000014Y
1)(2 1n 12 1n
15
( 四 ) 补码 : 正数的补码表示与原码相同; 负数的补码表示为它的反码,且在最后位(即最低位)加
1 所形成。 例如:
8 位带符号位的补码特点: 1. ;
2. 8 位二进制补码所表示值为 +127 -128 ; 3. 一个用补码表示的二进制数 当符号位为“ 0” 时,其余 7 位即为此数的真值;
当符号位为“ 1” 时,其真值为其余 7 位按位取反,且在最 低位处加 1 后最终所得的结果。 例如:
110011114
101111114
010000004
B
F
Y
000000000
111111110
000000000
B
F
Y
0000000000BB
N2N Yn
B
16
采用补码表示的目的在于可以把减法转换成加法。 补码的加法规则:
;
补码的减法规则: 。例如:
下面举一个钟表的例子:将钟从 10 点拨至 6 点有正拨、倒拨两种方式。既可倒拨 4 个小时,亦可顺拨 8 个小时。
10-4( 倒拨 )=10+8 ( 顺拨 ) 则 12 称为模。
BBBYXYX
BBBYXYX
011011111010100000100000010064
10[64][X]10][641064X
B
BBB
17
(10-4) 与 (10+8) 对模 12 是同余的, -4 与 +8 对模 12 互补。将两者分别用二进制加、减法计算释例:
自然丢弃 一般说来,若 Z=nK+Y(n 为整数 ) ,则称 Z 与 Y 对模 K 互补,记为ZY 。
001101100000101001000000
0011011011111011001000000
18
第三节 计算机基础
19
第三节 计算机基础一、计算机的基本结构
二、名词术语 1. 位 (Bit)
位是计算机所能表示的最基本最小的数据单元,位就是一个 二进制位,有 0 、 1 两种状态。
2. 字 (Word) 和字长 字是计算机内部进行的数据处理的基本单位,每个字的位数
为字长。 3. 字节 (Byte)
1Byte=8Bit三、指令程序和指令系统 指令 : 计算机执行的各种操作的命令的形式写下来的方式。
一条指令对应着一种操作。它由两部分组成:操作码字段和 操作数字段。 操作码表示计算机所要执行的操作;操作数表示参加 操作的数的本身或操作数所在的地址。
20
指令的格式为
一地址 二地址
8088 指令的格式大多数为双操作指令。因为计算机只识别二进制数 , 所以计算机的指令系统中的所有指令都必须以二进制编码的形式来表示,这就是指令的机器码。例如 数据传送指令mov AL,7它的二进制机器码为 1011 0000 (mov AL,n) 0000 0111 ( n=7 )用助记符来表示操作码 , 用符号或符号地址来表示操作数地址的方式 称为汇编语言,它与机器指令是一一对应的。( 例如 Mov,Add,Jmp等指令 )当机器开始执行程序 ,给 PC 程序计数器赋以程序第一条指令所在的地址 , 然后每取出一个指令 ,PC 中的内容自动加 1 ,并指向下一条指令的地址 , 以保证指令顺序执行。值得注意的是只有在执行Jmp,Call,Interrupt 时 ,PC才转到所需要的地方。
操作码 操作数 ...操作数 ...
21
四、模型机 ( 一 ) CPU 结构 (P18 如图 1-9 1-10) ( 二 ) 存储器
不同二进制数 地址 内容
00H 01H
DB FFHCPU控制 信号
注意:每一个存储单元的地址和这个地址中存放的内容是 完全不同等概念 ,千万不能混淆。
确定单元后就可以对这个单元的内容进行读或写的操作。 下面举例说明: 1. 读操作
地址译码器
00H 单元01H 单元
FFH 单元
控制器
.
.
22
将 04H 单元格中的内容读出送至 DR( 数据寄存器 ) 。 内容
AR 00H
04H
04H
FFH DB
读
地址译码器
00H 单元
1000 0100
FFH 单元
84H
控制器
23
2. 写操作 AR 内容 00H DR
10H FFH DB 写 ( 三 ) 执行过程 简单说来就是取指令加执行指令。当机器开始执行指令时 , 把第一条指令所在地址赋给 PC, 然后就进入取指阶段 , 在取 指阶段从内存中读出的内容必为指令 , 由 DR 把它送至 IR,然 后由指令译码器译码。 开始执行将第一条指令的地址送 PC 取指读内存 ( 由 DR) IR ID 译码 PLA
地址译码器
00H
0010 0110
FFH26H
控制器
10H
24
取指的基本格式为
在一条指令执行完以后就可以立即执行下一条指令 , 减少了 CPU为等待的时间 ,提高了运行速度。8088CPU功能上分为 BIU 和 EU, 即分别是总线接口和执行单元。 它们可以重叠。举例:把两个十进制数 7 和 10 相加。 Mov AL, 7 Add AL,10 HLT 第一条指令 1001 0000(Mov AL, 7) 0000 0111 ( n=7 )
取指
取指取指
取指
取指
执行
执行
执行 执行
执行 …...
…...
…...
取指
等待
25
第二条指令 0000 0100 (ADD AL, n) 0000 1010 ( n=10 ) 第三条指令 1111 0100 ( HLT ) 三条指令 5 个字节。 将三条指令放入存储器,若是从 00H 开始的存储单元。 二进制 地址 ( 十进制数 ) 内容 0000 0000 00 mov AL,7 0000 0001 01 n=7 0000 0010 02 Add AL,7 0000 0011 03 n=10 0000 0100 04 HLT 取第一条指令 取立即数 取第二条指令 取第二条指令第二字节及执行指令的过程
五、软件
1011 00000000 0111
0000 10100000 0100
1111 0100
26
各种语言和它们汇编、编译、解释程序。 机器的监控管理程序 (Moniter),调试程序 系统软件 (Delug),故障检查 ,诊断程序。 程序库。 操作系统。 软件 应用软件 : 编制解决用户所碰到的各种实际问题的程序。 数据库及数据管理系统
由机器提供 , 为了使用和管理计算机
27
第四节 Intel 8088 的结构
28
Intel 8088 的结构 CPU: 准 16 位微处理器
DB : 8 条 AB : 20 条 采用 40 条引线封装 电源 +5V 1M直接寻址
一、 8088 的寄存器结构 寄存器:由多个触发器可以组成一个多位寄存器。 存储器:看作是一个寄存器堆,每个存储单元实际相当于一 个缓冲寄存器。二、 8088存储器 8088 有 20 条地址总线 , 220=1M,( 210 =1K), 地址从 00000FFFFF 。 其寄存器为 16 位 ,8088 对地址的运算只能是 16 位 ,寻址范围是 0000 FFFFH 。 1M存储器以 64K 为范围分为若干段。 00000 , 00001 ,… . 0000E , 0000F ; 64K 个行 00010 , 00011 ,… . 0001E , 0001F ;
00020 , 00021 ,… . 0002E , 0002F ;
202
30
00000 , 00001 ,… . 0000E , 0000F ; 00010 , 00011 ,… . 0001E , 0001F ;
00020 , 00021 ,… . 0002E , 0002F ; 64K 个行
FFFF0, FFFF1, …. FFFFE, FFFFF
16 个列 00000H 由于它为小段的首地址 , 其低 4 位一定为 0
00010H 段地址只取段起始地址高 16 位。 64K 个 这样 , 每一个存储单元都有唯一的 20 位地
段首地址 42230H 址 , 此地址称为该存储单元的物理地址。 42240H 0000 ( 左移 4 位 )
+
FFFE0H
FFFF0H
16 位段地址16 位偏移地址
20 位物理地址计算方法
31
16位段地址存放在段寄存器中,偏移量存放在 IP、 SP、DI、 SI、BP(基数 )中。当取指令时 CS的地址 +IP的 16位偏移量 =要取的指令的物理地址 当堆栈操作时 SS的地址 +SP的 16位偏移量 =堆栈操作的 20位物理地址 当涉及到操作数时 在不改变段寄存器在不改变段寄存器 DS或ES地址 +16位偏移量 的情况下的情况下 ,,寻址最大寻址最大
=操作数的 20位物理地址 范围是范围是 64K64K 。。 64K 代码段 64K 堆栈段
64K 数据段 64K 附加数据段
CSSSDSES
34
第一节 8088 的寻址方式
35
一、指令的格式
寻找操作数的方式称为寻址方式。 1. 操作数包含在指令中 , 即指令的操作数场就包含在操作数本
身中。此寻址方式称为立即寻址 , 这种操作数就称为立即数。 2. 操作数包含在 CPU 的某一内部寄存器中 , 这种寻址方式称为 寄存器寻址。 3. 操作数在内存的数据区中 , 此时指令中的操作数场包含着此 操作数的地址。 存储单元所在基地址 ( 段寄存器 )
8088 内存地址 段内偏移量 EA 指令的操作数场中规定的地址就是这个段内偏移量,又称为
有效地址 EA 。 EA 的构成有以下 5 种:
直接地址:包含在指令中的 16 位地址偏移量构成 EA ————直接寻址方式
操作码 操作数 操作数 …...
36
间接地址: EA 由 CPU 内某一个寄存器的 16 位内容构成 ————间接寻址方式 基址方式:基址寄存器 BX 或 BP 加上指令中的包含 8 位或 16 位位移量构成 EA ———— 基址寻址方式 变址方式:由变址寄存器 DI 或 SI 和包含指令中的 8 位或 16 位
位移量构成 EA
————变址寻址方式
基址加变址方式:由一个基址寄存器 BX 或 BP 加变址寄存器 SI 或 DI 再加包含指令中的一个 8 位或 16 位 位移量构成 EA
————基址加变址寻址方式一、立即寻址
此方式所提供的操作数 例如 直接放在指令中 ,紧跟在 mov AX,im 操作码一起放在码段区 域中。
AH ALimHimL
37
立即寻址主要用来给寄存器赋初值。 二、直接寻址 操作数的地址的 16 位偏移量直接包含在指令中 , 它与操作码
一起被放在码字段区域中 ,但操作数一般在数据段。它的地 址为数据段寄存器 DS 加上它 16 位地址偏移量。 例如: mov AX,[2000H]
注意:在例题中我们遇到的 [2000H] 。当我们用 AXBX 或 AXBX 时 , 表示将 AX 中的内容送 BX 或将 BX 中的内 容送 AX 。而用 AX[BX] 或 AX[n], 表示 [ ]中的是操
30 00 0
DS
20
数据段
码段
操作码00H20H
50
低高
3000032000
ALAHAX
32000H200030000
38
作数地址 , 把此地址单元的内容 ( 操作数 ) 送至 AX 中。 物理地址 =16d DS+EA 三、寄存器寻址
操作数包含在 CPU 内部寄存器中 , 如 AX 、 BX 、 CX 、 DX 。 例如 已知 AX , BX ,求执行程序后的 A
X 。 mov AX, BX 四、寄存器间接寻址
其操作数是在存储器中 , 操作数的地址 16 位偏移量包含在 SI 、
DI 、 BX 、 BP之一中。 ( 一 ) 以 SI 、 DI 、 BX间接寻址 其操作数在数据段区域中 物理地址 =16d(DS)+BX 或 SI 或 DI
( 二 ) 以寄存器 BP间接寻址
30 64 12 34
3412最终 AX
42
其操作数在堆栈段区域中 物理地址 =16dSS+BP 五、变址寻址
变址寻址是以指定的寄存器内容加上指令给定的 8 位或 16 位 位移量和段地址作为操作数的地址。 物理地址 =16d(DS) + (BX) + 8 位或 16 位位移量
或 (SI) 或 (DI) 或 = 16d(SS) + (BP) + 8 位或 16 位位移量 六、基址加变址的寻址方式
8088 常把 BX 、 BP看作基址寄存器 , 把 SI 、 DI看作变址寄存器。 寻址方式:一个基址寄存器的内容 +变址寄存器的内容 + 指令中 8 位或 16 位位移量 + 段地址
物理地址 =16d(DS) +(BX) + (SI) + 8 或 16 位位移量 或 (D
I) 或 =16d(SS) + (BP)+ (SI) + 8 或 16 位位移量 或 (DI)
43
在正常情况下 , 由基地址决定哪一个段寄存器作为地址指针。 用 BXDS , BPSS 。
44
第二节 8088 中的标志寄存器
45
1. 辅助进位标志 A 在字节操作时 , 则由低半字节 ( 一个字节的低 4 位 )向高半字节有 进位或借位; 在字操作时 , 低位字节向高位字节有进位或借位 , 则 A=1, 否则 A=0 。 此标志用十进制算术运算指令中。2. 进位标志 C 当结果的最高位产生一个进位或借位 , 则 C=1, 否则 C=0 。主要 用于多字节数的加法、减法 , 移位和循环指令也能够把存储器 或存储器中的最高位 ( 左移 ) 或最低 ( 右移 )放入 C 中。3. 溢出标志O 在算术运算中 , 带符号数的运算结果 , 如果超出以下范围:
字节 字 则 O=1, 否则 O=0 。溢出和进位是两个不同的概念。 溢出判断:
15Z
0CDO PAT SI
8 7
27 127 215 1215
47
同号相加 , 若结果的符号位相反 , 则溢出。 异号相减 , 若结果的符号位与被减数相反 , 则溢出。4. 符号标志 S S 的值与运算结果的最高位相同 , 若最高位为 1, 则 S=1 ,否则 S=0 。 由于 8088 中 , 符号数是用补码表示的 , S=0 为正 , S=1 为负。5.奇偶标志 P 若操作数结果中“ 1” 的个数是偶数 , 则 P=1, 否则 P=0 。6. 零标志 Z 若运算的结果为 0, 则 Z=1, 否则 Z=0 。7. 方向标志 D 若用指令置 D=1, 则引起串操作指令为自动减量指令;
若用指令置 D=0, 则引起串操作指令为自动增量指令。 8. 中断允许标志 I
若指令中置 I=1, 则允许 CPU去接收外部的可屏蔽的中断请求;
若指令中置 I=0, 则屏蔽上述的中断请求。 I 对 CPU 内部产生的中断不起作用。9. 追踪标志 T
48
补充内容:操作码和寻址方式的机器语言表示方法 操作码的机器语言表示
W 位 是指示本指令是对字 (W=1)还是对字节 (W=0) 操作; d 值 在双操作数指令中才有效。 8088 指令规定双操作数指 令的两个操作数必须有一个操作数放在寄存器中; d 位 指定寄存器用于目的操作数 (d=1)还是源操作数 (d=0) (8 16 ,高位字节按低位字节的最高有效位作符号扩展 ) 。 当立即方式寻址时,S位表示符号扩展 当指令字节操作时, SW=00; 当指令有 16 位立即数且作字操作时, SW=01 ; 当指令有8位 ,但需要经符号扩展成 16 位 ,立即数作字操作时 , 则 SW=11 。 寻址方式的机器语言表示 8088 用一个字节表示操作数的确寻址方式 它通常是机器指令的第二个字节
op Wd
49
表示为
在双操作数指令的情况下规定必须有一个操作数在寄存中 ,该 寄存器由 reg 字段指定。 mod 与 r/m 是另一种操作数寻址方式。 mod=11, 为寄存器方式 , 由 r/m 的内容确定选用哪个寄存器; mod=00, 为元位移量字节的存储器寻址方式——直接寻址; mod=01, 为带一个位移量字节的存储器寻址方式; 指令中应有
mod=10, 为带两个位移量字节的存储器寻址方式;
如果出现段跨越 , 则必须加 001 , 再加上 110 。
操作数在
存储器中
D8
mod r/mreg
01 r/mreg
10 r/mreg
D16 高位
D16 低位
间接寻址
SEG
50
上面的寻址方式是指无段跨越前缀的情况下所用的隐含的段 寄存器 , 如果指令中指定段跨越前缀 , 则在机器语言中使用放在 指令之前的一个字节来表示 , 如下:
001 110segsegment 00
011011
ESCSSSDS
SEG
51
置 T标志 , 使处理进入单步方式 , 以便于调试。在这个方式 , CPU 在每条指令执行以后产生一个内部的中断 , 允许程序在每条执 行完以后进行检查。
52
第三节 8088 的指令系统
53
8088 的指令系统可分成 6 个功能: • 数据传送 •算术运算 •逻辑运算 •串操作 •控制传送 •处理器控制
指令符号:8 位寄存器 AH,AL; BH,BL; CH,CL; DH,DL16 通用寄存器 AX ; BX ; CX ; DX SP ; BP ; DI ; SI 堆栈指针 SP指令指针 IP ( 指向下一次要取出的指令 ) 或 PC( 指向下一条即将要执行的指令 )标志位 F目的和源变址寄存器 DI 、 SI
54
段寄存器 CS 、 DS 、 SS 、 ES通用寄存器 rAL 或 AX a源和目的操作数 src dst (存储单元 ) [ BX+SI+n ] [ BX+DI+n ] [ BP+SI+n ] [ BP+DI+n ] [ SI+n ] [ DI+n ] [ BP+n ] [ BX+n ] [ n ]---------- 直接 r ---------- 寄存器源操作数地址 ADR ( src)存储单元的内容 [ ]OPRD 操作数
55
附加存储器段的内容 ES[ ] 段寄存器 seg 立即数 im 8 位 n 16 位 nn 32 位 nnnn 一、数据传送指令 分为 4 种: • 通用传送指令 • 累加器专用传送指令
• 地址—目的传送指令 • 标志传送指令 此类指令 , 除了标志寄存器传送 SAHF 和恢复标志寄存器 POPF 指令以外 , 对标志位无影响。 ( 一 ) 通用传送指令 此指令是唯一允许以段寄存器作为操作数的指令。 (XCHG 除外 )
1. Mov OPRD1, OPRD2目的 源
56
它把一个字节 B 或字 W 操作数从源地址传送至目的地址。
它能实现以下 4 种数据传送: CPU 内部寄存器之间传送 ( 除 CS 和 IP 以外 ) 如
立即数传送 CPU 内部通用寄存器组给寄存器赋初值。 如 mov CL, 4 mov SI, 057BH
mov [nn], a B/W [nn]=amov a, [nn] B/W a=[nn]mov seg, src W seg=srcmov dst, seg W dst=segmov r, src B/W r=srcmov dst, r B/W dst=rmov r, im B/W r=immov dst, im B/W dst=im
mov AL, BLmov CX,BXmov DS,BXmov DX,ESmov SI,BP
57
CPU 内部寄存器 ( 除 CS 和 IP 以外 ) 与存储器之间的传送
() 通用寄存器与存储器之间 如 mov AX, [SI]
mov [DI], CX 寄存器间接 mov SI, BLOCK[BP] 变址 () 段寄存器 ( 除 CS 外 ) 与存储器之间
如 mov DS, DAT[SI+BX] seg M mov DEST[BP+DI], ES 注意: mov 指令不能实现存储单元之间的数据传送 , 也不允许 两个段寄存器之间直接传送。 若需要把地址 ( 段内地址位移量 ) 为 ARE1 的存储单元的 内容 , 传送至同一段内的地址为 ARE2 的存储单元可以 用 CPU 内部寄存器为桥梁来完成。 如 mov AL, ARE1 mov ARE2, AL
如 mov BX, offset TABLE
通用 rMseg M
58
把 TABLE 的偏移地址而不是内容送到 BX寄存器。 若传送 100 个数据
mov SI, OFFSET AREA1 mov DI, OFFSET AREA2 mov CX, 100 AGAIN: mov AL, [SI] mov [DI], AL INC SI INC DI DEC CX JNZ AGAIN
其中 OFFSET AREA1 是指地址单元 AREA1 在段内地址偏移量。 又如 mov AX, Y[BP][SI] 地址 16d(SS)+(BP)+(SI)+Y 的存储单元的内容送给 AX 。 其中 OFFSET 为属性操作符 , 表示应把其后跟着的符号 地址的值 ( 不是内容 ) 作为操作数。能实现用立即数给存储单元赋初值 (Mim) 如 mov mask [BX] [SI], 2CH
59
2. 堆栈操作指令 在主程序中往往要调用子程序或要处理中断就要暂停主程序 的执行 , 转去执行子程序 (中断服务程序 ), 则机器必须把主程序 中调用子程序指令的下一条指令 , 若第 X1 条指令为调用子程序 ,则它的下一条指令为 X2 的地址 , 即 PC 或 IP保留下来才能保 证当子程序执行完成以后返回主程序继续执行。另外 , 还必须 保留调用子程序的主程序的中间结果标志位的状态。
口诀:先进后出 , 后进先出。
8088中规定堆栈设置在堆栈段 (SS) 内 , 用堆栈指针 SP始终指向堆栈的 顶部 , 即始终指向最后推入堆栈的 信息所在的单元。 SP的初值规定 了所用堆栈的大小 , 8088中所设置 的 SP的初值 , 逐渐靠近 SS ,堆栈的 最大容量为 SP的初值与 SS间的距 离。入栈指令 它是把一个字的源操作数 , 送至栈的顶部。
执行子程序
主程序
转向子程序
通用主程序
X1
X2IP
60
PUSH OPRD(W) 在传送数据前 SP-2SP 具体指令如下: PUSH r w SP=SP-2, [SP]=r PUSH seg w SP=SP-2, [SP]=seg PUSH src w SP=SP-2, [SP]=src 源操作数可以是 CPU 的内部寄存器 , 段寄存器 ( 除 CS 外 ) 内存操 作数。出栈指令 POP OPRD(W) 在传送数据后 SP+2 SP 把现行 SP 指向的堆栈顶部的一个字 , 送至指定的目的操作数 , 然 后再进行修改指针 , SP+2 SP 。
具体指令如下: POP r w r=[SP] SP=SP+2 POP seg w seg=[SP] SP=SP+2
POP dst w dst=[SP] SP=SP+2 注意:堆栈是“后进先出”方式工作的 ( 一个 )存储区。它必须 在于堆栈段中 , SS存放段地址。 进栈:先移指针 , 后放入内容。出栈:先拿内容 , 后移指针。
61
PUSH AX 指令分两步执行:
PUSH BX 第一步: SP-1 SP
然后把 AH(寄存器中的高位字节 ) 送至 SP 所指的单元; 第二步: SP-1 SP 然后把 AL(寄存器中的低位字节 ) 送至 SP 所指的单元。 如 PUSH AX
ALBH
AH
BL
SP SP-1 SP-1
SS
底
顶
低址 SP
低地址
指令执行前高地址
低地址SP
指令执行后高地址
0721
(AX)=2107H
62
出栈指令举例 如 POP AX
SP低地址
指令执行前高地址
2107
SP
低地址
指令执行后高地址
2107
出栈方向
(AX)=2107H
63
3. 交换指令 XCHG OPRD1 , OPRD2 目的操作数 源操作数
把一个字节或一个字的源操作数与目的操作数相交换。 rAX, r r, r M 段寄存器不能作一个操作数。 具体指令如下: XCHG AX , r w r=AX, AX=r XCHG r , src B/w r=src, src=r
( 二 ) 、累加器专用传送指令 1. IN 输入指令 把一个字节或一个字由一个输入端口 (Port) 传送至 AL或 AX 。 端口地址若是由指令中的 n(8 位 ) 所规定 则寻址 Port0Port255, 共 256 个输入端口。 端口地址若是由寄存器 DX 规定 则寻址范围 64K 个输入端口 (8088 采用间接寻址方式, I/O端口地址可扩展到 64K) 具体指令如下:
64
IN AL, n B AL=[n] IN AX, n W AX=[n+1][n] IN AL, DX B AL=[DX] IN AX, DX W AX=[DX+1][DX] 2. OUT 输出指令 把 AL 中的一个字节或 AX 中的一个字 , 传送至一个输出端口。 具体指令如下: OUT n, AL B AL [n] OUT n, AX W AX [n],[n+1] OUT DX, AL B AL [DX] OUT DX, AX W AX [DX],[DX+1] 3. XLAT查表转换 指令完成一个字节的查表转换 , 寄存器 AL 的内容 为一个 256 个字节的表的下标。这个表的基地址在寄存器 BX 中 , 转换后的一个字节的操作数放在 AL 中。 XLAT B (AL=[BX+AL]) (0 9 转换 7 段数码 )经常把一种代码转换为另一种代码。( 三 ) 、地址——目的传送
65
1. LEA 把源操作数的地址偏移量 , 传送至目的操作数。
LEA r, src r=ADR(src)
如 mov SI, OFFSET AREA1 等价于 LEA SI , AREA1 不等价于 mov AX, AREA12. LDS 此指令是传送一个目标指针 ( 段地址 + 地址偏移量 , 32 位 ) 从源操 作数 ( 为内存操作数 ) 传送至一对目的寄存器。 16 位地址偏移量 1 个 16 位的指针寄存器 (SP,BP) 或变址寄存器 (DI, SI) 目的段地址 DS寄存器 指令格式: LDS r, src DW r [EA] DS [EA+2]
内存操作数 16 位的通用寄存器
66
LDS 指令示意图: LDS
3. LES 除了把目标段地址送至段寄存器 ES 以外 , 其它与 LDS 指令类似。
LES reg, src r [EA], ES [EA+2]
操作码
2 个字节2 个字节
EA
DS
偏移量
SI
DI, BP,SP变址
67
举例来说 : 1. LEA BX, [BX+SI+0F62H]
指令执行前 (BX)=0400H, (SI)=003CH指令执行后 (BX)=0400+003CH+0F62H=139EH
BX寄存器得到的是偏移地址而不是该存储单元内容
2. LDS SI, [0010H]指令执行前 (DS)=C000H, [C0010H]=0180H, [C0012H]=2000H
指令执行后 (SI)=0180H, (DS)=2000H
3. LES DI, [BX]指令执行前 (DS)=B000H, (BX)=080AH [0B080AH]=05AEH, [0B080CH]=4000H
指令执行后 (DI)=05AEH, (ES)=4000H
68
( 四 ) 、标志寄存器传送 1. LAHF
2. SAHF 此指令与 LAHF 相反 , 是把 AH 的指定位送至 FLAG 中的 S 、Z 、 A 、 P 、 C 3. PUSHF
把 FLAG 中的 (全部 9 个标志 )推入栈堆指针所指的堆栈的顶 部。传送数据前 SP SP-2 。此指令不影响标志位。 4. POPF 把现行堆栈指针所指的一个字 , 传送至 FLAG 。 然后 SP+2 SP 。 PUSHF 和 POPF 可以保存和恢复标志寄存器。在子程序调用 和中断服务中可利用这两个指令。
15 0Z CPAS
7 06 4 2
O D I T
不影响 F
69
二、算术运算指令 2 进制运算可以是双操作数 , 10 进制运算可以是单操作数。
若是符号数用补码表示。 ( 一 ) 加法:共有 5 种。 1.ADD OPRD1, OPRD2 OPRD1+OPRD2 OPRD1 目的操作数 :累加器、通用寄存器、存储器操作数。 指令格式: ADD r, src B/W r+src r ADD a, im B/W a+im a ADD dst, im B/W dst+im dst ADD dst, r B/W dst+r dst
如: ADD AX, 3000H ADD AX, SI ADD SI, AX ADD AL, DATA[BX] ADD BETA[SI], DX ADD BETA[SI], 100
这些指令对 FLAG 中C 、 O 、 P 、 S 、 Z 、 A
有影响。
70
2. ADC 在两个操作数相加时 , 把进位标志 C 的值加上去 , 结果送至一个 操作数。 格式: ADC DST, SRC (DST) (SRC)+(DST)+C 具体如下: ADC r, src r+src+c r ADC a, im a+im+c a ADC dst, im dst+im+c dst ADC dst, r dst+r+c dst ADC主要用于多字节运算 , 先进行低两字节相加 , 然后进行高两 字节相加 , 若两个四字节的数相加 , 分别放在 FIRST 和 SECOND
存储区中 , 每个数占四个存储单元。最低字节在地址最低处。
如:
Mov AX, FIRSTAdd AX, SECONDMov THIRD, AXMov AX, FIRST+2Adc AX, SECOND+2Mov THIRD+2, AX
也影响 FLAG 中C 、 O 、 P 、 S 、 Z 、 A
71
3. INC 格式: INC OPR (OPR) (OPR)+1 完成对指定的操作数加 1, 再返回此操作数。 影响标志位 A 、 O 、 P 、 S 、 Z 。不影响标志位 C 具体如下: INC r W r+1 r INC src B/W src+1src4. AAA 加法的 ASCII调整指令 ( 非压缩 BCD) 。。 执行这条指令之前必须执行 ADD 或 ADC 指令。加法指令把两 个非压缩 BCD 码相加 , 结果放在 AL 中。 执行的操作:
AL把 AL 中的和调整非压缩 BCD 格式 AH AH 加调整产生的进位值 ( 对应步骤中的 )
以下是具体步骤: 如果 AL 的低 4 位在 09之间 , 且 A=0, 则跳过 , 执行;
如果 AL 的低 4 位在 AF之间或 A=1, 则 AL 加上 6, 且 A=1 ;
72
清除 AL 的高 4 位 (AL&0FH) ; AHAH+1 A 的值送至 C 。 AAA影响标志位 C 、 A 。
例如 ADD AL, BL AAA 执行前 AX=0535H , BL=39H
可见 AL 、 BL 的内容分别为 5 和 9 的 ASCII 码
执行完第一条指令后(AL)=6EH A=0
执行完第二条指令后ASCII调整后 (AX)=0604H 6E+06=74H A=1, C=1
5. DAA 加法的十进制调整指令 (压缩 BCD) 。 在执行此指令之前 , 先执行 ADD 或 ADC 加法指令。必须把两个压 缩的 BCD 码相加 , 结果放在 AL 中。
73
调整方法如下: ( 参见 P82 例 ) 若 A=1, 或 AL 低 4 位是 A F, 则 AL+06HAL, 且 A=1 ;若 C=1, 或 AL 高 4 位是 A F, 则 AL+60HAL, 且 C=1 。
( 二 ) 减法指令 1.SUB ( 减法指令 ) SUB OPRD1, OPRD2 (OPRD1)(OPRD1)-(OPRD2) 具体形式如下: SUB r, src B/W r-src r SUB a, im B/w a-im a
例 ADD AL, BL DAA 执行前 (AL) =28H, (BL)=68H
第一条指令执行后 (AL)=90 C=0, A=1第二条指令执行后 因为 A=1, 所以 (AL) (AL)+06 得 (AL)=96 C=0, A=1
1001 0110
0110 1000
1001 0000A=1
0010 1000
0000 0110
9 6
+
+
74
SUB dst, r B/W dst-r dst
SUB dst, im B/W dst-im dst 此指令影响标志为 A 、 C 、 O 、 P 、 S 、 Z 。2. SBB ( 带借位减法指令 )
SBB OPRD1, OPRD2 (OPRD1)(OPRD1)-(OPRD2)-C 具体形式如下: SBB r, src r-src-C r SBB a, im a -im-C a SBB dst, r d st-r-C dst SBB dst, im dst-im-Cdst 此指令影响标志位 A 、 C 、 O 、 P 、 S 、 Z 。3. DEC ( 减 1 指令 )
DEC OPR 把操作数作为无符号数 2 进制数处理 (OPR) (OPR)-1 此指令影响标志位 A 、 O 、 P 、 S 、 Z, 不影响 C 。 OPR 可以是 r, 也可以是 M 。4. NEG (求补指令 ) NEG OPR (OPR)0FFFFH-(OPR)+1
75
即把操作数按位求反 , 末位加 1, 因而亦可表示。 此指令影响 A 、 C 、 O 、 P 、 S 、 Z 。注意:只有当操作数为“ 0” 时 ,求补运算结果使 C=0, 其它情况 C=1 。
5. CMP (比较指令 ) CMP OPR1, OPR2 (OPR1)-(OPR2) 完成两个操作数相减 , 并使结果反映在标志位上 , 不回送。 具体形式如下:
CMP r, src CMP a, im CMP dst, r CMP dst, im 比较指令主要用于比较两个数之间的关系 , 即两者是否相等 , 或 两个中哪个大 , 指令通过比较结果置标志位 , 表示操作数的关系。
下面以 CMP A, B 为例: 若两个操作数相等 即 A=B 则比较后 Z=1, 否则 Z=0 两个无符号数判大小
76
若 AB, 则不会产生借位 , C=0 若 A<B, 则产生借位 , C=1 因此根据 C标志位来判断两个无符号数的大小。两个有符号数判断大小 要结合 O 、 S 两个标志位 (I) 若 A 、 B 为同号 (A 、 B>0 或 A 、 B<0) 则两数相减绝对值变小不会溢出 , 此时可用 S判断大小。 AB S=0 A<B S=1 (II) 若 A 、 B 为异号数 (A>0,B<0 或 A<0,B>0) 则两数相减有可能溢出
简化:若 SO=0 时 , A>B
若 SO=1 时 , A<B
AB S=0A<B S=1
无溢出 A>B S=1A<B S=0
有溢出
若 O=0 时 S=0 则 A>BS=1 则 A<B
S=0 则 A<BS=1 则 A>B
若 O=1 时
77
例 1 SUB [SI+0014H], 0136H
例 2 SUB DH, [BP+4]
执行前 (DS)=3000H, (SI)=0040H(30054H)=4336H
执行后 4336-0136
0100 0011 0011 0110
-0000 0001 0011 0110
0100 0011 0011 0110
+1111 1110 1100 1010
求补
1 0100 0010 0000 0000
补码时 , 借了模 10000H
(30054H)=4200HS=0, Z=0,C=0,O=0
执行前 (DH)=41H, (SS)=0000H (BP)=00E4H, (000E8)=5AH
78
例 3 若自 BLOCK 开始的内存中 , 有 100 个带符号数 , 要找出其中 的最大值 , 把它存放到MAX 单元。
执行后 41-5A
0100 0001-0101 1010
0100 0001+1010 0110
求补
1110 0111
补码时 , 借了位
(DH)=E7HS=1, C=1,O=0
Mov BX OFFSET BLOCKMov AX, [BX]Inc BXInc BXMov CX, 99
AGAIN:CMP AX, [BX] JG NEXT Mov AX, [BX]
79
NEXT: INC BX INC BX DEC CX JNZ AGAIN Mov MAX, AX HLT
80
6. AAS ( 减法的 ASCII调整指令 , 非压缩 BCD) 执行的操作:
(AL) 把 AL 中的差调整到非压缩 BCD 格式 (AH) (AH)—调整产生的借位值 此指令之前必须执行 SUB 或 SBB 指令。
调整步骤如下: 如果 AL 的低 4 位在 09之间 , 且 A=0
则跳过执行 ; 如果 AL 的低 4 位在 AF之间或 A=1 则 AL-6 AL, AH-1 AH, 将 A=1 ;
清除 AL 的高 4 位 (AL AL&0FH) ; A 的值送至 C 。
AAS影响标志位 A 、 C, 其余标志位无定义。7. DAS ( 减法的十进制调整指令 , 压缩 BCD) 执行的操作: (AL) 把 AL 中的差调整到压缩的 BCD 格式 此指令之前必须执行 SUB 或 SBB 指令。
81
调整方法: 若 A=1 或 AL 的低 4 位是 AF
则使 AL-06H AL, 且 A=1 ; 若 C=1 或 AL 的高 4 位是 AF 则使 AL-60H AL, 且 C=1 。 DAS影响 A 、 C 、 S 、 Z 、 P, 对 O无定义。 例如 SUB AL, AH 执行指令 (AL)=86H, (AH)=07H
执行 SUB (AL)=7FH, C=0,A=1
执行 DAS 因为 A=1, 所以 (AL)=(AL)-06H=79 C=0, A=1
( 三 ) 乘法指令 8088 中有三条乘法操作指令 1.MUL (无符号数乘法 ) 格式: MUL SRC 执行的操作: (AX) (AL)*(SRC) 字操作数 : (DX, AX) (AX)*(SRC) 相乘时的另一操作数可以是寄存器操作数或内存操作数。
82
若结果的高半部分 (AH, DX) 不为 0 则标志 C=1,O=1; 否则 C=0, O=0 。 本指令对 A 、 P 、 S 、 Z无定义。2. IMUL( 带符号数乘法 ) 格式 : IMUL SRC 执行的操作:与 MUL 相同 , 但必须是带符号数 , 而 MUL 是无符 数。 对于 IMUL 指令 , 如果乘积的高一半 (AH, DX) 是低一半的符号 扩展 , 则 C=0, O=0; 否则 C=1, O=1. 那么所谓符号扩展是指一个数从位数较少扩展到位数较多的 数 (8 位 16 位; 16 位 32 位 ), 对于用补码表示的数 , 正数的符 号扩展应该在前而补 0, 而负数的符号扩展应该在前面补 1 。 [+46] 补 =0010 1110 [+46] =0000 0000 0010 1110 [-46] =1101 0010 [-46] =1111 1111 1101 00103. AAM( 乘法的 ASCII调整指令 ) 执行的操作: (AX) 把 AL 中的积调整到非压缩 BCD 格式 此指令之前必须执行 MUL 指令把两个非压缩的 BCD 相乘 ( 其高 4 位为 0) 结果放在 AL 中。
补
补
补
83
84
调整方法如下: AH AL/0AH (AL 被 0A 除的商 AH)
AL AL%0AH(AL 被 0A 除的余数AL) 如 6(0000 0110)7(0000 0111)——AL 积 (0010 1010) 则乘积的十进制数值的调整: 0000 0100 AH 0000 0010 AL( 四 ) 除法指令 1.DIV(无符号数除法指令 ) 格式为 DIV SRC 执行的操作: (AL) (AX)/(SRC) 的商 字节操作 (AH) (AX)/(SRC) 的余数 AX : 16 位 SRC : 8 位 (AX) (DX,AX)/(SRC) 的商 字操作 (DX) (DX,AX)/(SRC) 的余数 DX 、 AX : 32 位 SRC : 16 位 2. IDIV( 带符号数除法指令 )
85
此指令除了完成带符号数相除以外 , 与 DIV类似。 格式为 IDIV SRC
注意:对乘法、除法指令 SRC 不能为立即数。 除法指令对 A 、 C 、 P 、 Z 、 S 、 O 各种标志位均无定义。3. AAD( 除法的 ASCII调整指令 )
若被除数是放在 AX 中的二位非压缩 BCD , AH 中存放十位数。
AL 中放个位数。而且要求 AH 和 AL 高 4 位均为 0 ,除数是一 位非压缩 BCD ,要求其高 4 位为 0 。在这两个数用 DIV 指令以 前,必须先用 AAD 指令把 AX 中的被除数调整成二进制数,存 放在 AL 中。 调整操作: (AL) AH*0AH+AL (AH) 0 此指令影响 S 、 Z 、 P , 对 A 、 C 、 O 无定义。 4. CBW 格式为 CBW 执行的操作: AL 的内容符号扩展到 AH AL<80H , AH 0
86
AL80H , AH FFH 5. CWD 格式为 CWD 执行的操作: AX 的内容符号扩展到 DX AX<8000 , DX 0 否则 DX FFFFH三、逻辑运算指令 逻辑操作分为:单操作数操作 两个操作数操作 ( 一 ) 单操作数操作 1. 逻辑非指令
NOT src B/W (src 的反码 src) 2. 移位指令 格式 SAL 算术左移指令 SAL OPR, Count SHL 逻辑左移指令 SHL OPR, Count SAR 算术右移指令 SAR OPR, Count SHR 逻辑右移指令 SHR OPR, Count
87
OPR : 通用寄存器存储器操作数 (8 位或 16 位 )Count: 表示移位的次数。移位一次 count=1, 移位多次 count=CL. CL 为移位的次数。(1)SAL/SHL( 用一指令的两种表示方法 ) 在移位次数为 1 时 , 当新的操作数最高位与 C 不同时 , 则 O=1, 表明有符号数操作产生溢出 , 不再符合倍增关系。 对无符号数 , 当移位后使 C=1, 则不再符合倍增关系。
OPR
0
左移指令SAL SHL
C
OPR
算术右移SAR
C
OPR
逻辑右移SHR
C0
88
例 1 AL=0100 0010B 66 / +66
例 2 mov CL , 2 SHL SI , CL 已知 (SI)=1450H
左移一位 AL=1000 0100B 132 / (-124) , C=0, O=1
对无符号数 C=0 符合 662=132对有符号数 O=1 不符合倍增关系 +662=-124
执行指令前 (SI)=1450H 它的二进制形式是 0001 0100 0101 0000则执行指令后它的二进制形式是 0101 0001 0100 0000
另 执行指令前 (SI)=5200d 执行指令后 (SI)=20800d则 5200d 4d=20800d
89
(2) SAR( 算术右移 ) 指令常用于有符号数的减半运算。若右移使 C=1, 则减半结果 不精确。 (3) SHR( 逻辑右移 ) 本指令可以作为无符号数的除 2 运算 , 右移一位 , 相当数值下降 一级。若右移后 C=1, 表明移位前的数是奇数 , 减半结果不精确。 移位指令根据移位后的结果设置 S 、 Z 、 P , 对 A无定义。 3.循环指令 共有以下 4 个:
格式 ROL 循环左移指令 ROL OPR , COUNT
ROR 循环右移指令 ROR OPR , COUNT RCL 带进位循环左移指令 RCL OPR , COUNT RCR 带进位循环右移指令 RCR OPR , COUNT OPRD : 通用寄存器或存储器操作数 (8 位 / 16 位 )
COUNT :移位次数 移位 1次 COUNT=1 移位多次 COUNT=CL
90
循环移位指令不影响除 C 和 O 以外的其它条件标志。( 二 ) 两个操作数操作 1. AND 逻辑与指令 AND OPRD1 , OPRD2 B/W OPRD1OPRD1OPRD2 用于 : 两个数要保持不变的位和“ 1” 与 , 要置为“ 0” 的位和“ 0” 与。 2. TEST 测试指令 TEST OPRD1 , OPRD2 OPRD1OPRD2 完成与 AND 指令同样的操作 , 结果反映在表示位上 ,并不回
OPR
ROR
COPR
ROL
C
OPR
RCL
COPR
RCR
C
91
送目的操作数。通常用于检测一些条件是否满足 ,但不希望改 变原操作数。例如:
3. OR 或指令
OR OPRD1 , OPRD2 OPRD1OPRD1vOPRD2
TEST AL , 01HJNZ THERE
THERE
检测 AL 中的最低位是否为 1, 若为 1 则转移。
JZ 结果为零 ( 或相等 ) ,则转移 Z=1JNZ 结果不为零 ( 或不相等 ) ,则转移 Z=0
检测 CX 中的内容是否为 0, 若为 0 则转移。TEST CX , 0FFFFHJZ THERE
THERE
92
OPRD1 可以是累加器、寄存器、内存; OPRD2 可以是立即数、寄存器、内存。 “或”操作用于要求使一个操作数的若干位保持不变 , 而另外 若干位置为 1 的场合。保持不变的位和“ 0” 或 , 要置为“ 1”的位 和“ 1” 或。一个操作数和自身相“或” , 不改变其值 , 但C=0 。 ( 参看奇偶校验例题 ) 4. OR 异或操作 OR OPRD1 , OPRD2 OPRD1OPRD1OPRD2 当一个操作数对自身进行“异或”操作 , 结果为 0, C=0 。 常用于要置操作数初值为 0 的情况中。 ( 参看例题 ) 四、串操作指令 所有的基本的串操作指令 , 用 SI( 段地址寄存器为 DS)寻址 源操作数 , 用 DI( 对应的段寄存器为 ES) 为寻址目的操作数。 若 D=0, 则每次操作后 SI 和 DI增量 ( 字节操作加 1, 字操作加 2) ;
若 D=1, 则每次操作后 SI 和 DI 减量 1. 串传送指令 格式 MOVS OPRD1 , OPRD2
93
MOVS DST , SRC [ DI] [SI] 指针指示地址内容 MOVSB 字节操作 [ DI] [SI] SI SI1 DI DI1 当 D=0 时用加法 当 D=1 时用减法 MOVSW 字操作 [ DI] [SI] SI SI 2 DI DI 2 当 D=0 时用加法 当 D=1 时用减法 之前的传送 100 个操作数的例子可用上述指令改写为:
mov SI , OFFSET SOURCE mov DI , OFFSET DEST mov CX , 100AGAIN: movs DEST , SOURCE DEC CX JNZ AGAIN 又可以REP movs DEST , SOURCE (CX-1CX) 当 CX=0 时不重复
94
REP: CX=0 , 则退出 REP , 否则往下执行; CX-1CX ; 执行其后的串指令; 重复、。2. COMPS 串比较指令 格式 CMPS SRC , DST [SI]-[DI] CMPSB 字节操作 (SI) (SI) 1 (DI) (DI) 1 CMPSW 字操作 (SI) (SI) 2 (DI) (DI) 2 当 D=0 时用加法 当 D=1 时用减法 不保存结果 , 只根据结果置标志位。 ( 参看 例题 )
格式 REP MOVS MOVSB
MOVSW
95
3. SCAS 搜索串指令 格式 SCAS 串扫描指令
SCASB 字节操作 AL-[DI] (DI) (DI) 1 SCASW 字操作 AX-[DI] (DI) (DI) 2
AL 、 AX 、 [DI] 的内容并不改变。 而标志位 A 、 C 、 O 、 P 、 S 、 Z 反映 AL/AX 的值与串元素之间 的关系。 ( 参看 P102 例题 ) 4.LODS 从串取指令 格式 LODS SRC LODSB 字节操作 AL[SI] SISI1 LODSW 字操作
96
AX[SI] SISI2 当 D=0 时用加法 当 D=1 时用减法 5. STOS 存入串指令 格式
STOS DST STOSB 字节操作 [DI]AL DI DI 1 STOSW 字操作 [DI]AX DI DI 2 当 D=0 时用加法 当 D=1 时用减法 ( 参看 P103 例题 )
五、控制传送指令 ( 一 )调用 Call 、转移 JUMPS 、返回 returns 。 1. Call 格式 Call DST 1) 段内直接调用 操作:
97
SPSP-2 [SP+1 , SP] IP
IP (IP)+D16
指令的第一步:把子程序的返回地址 ( 即 Call 指令的下一条指令 的地址 )存入堆栈中 , 以便子程序返回主程序。
指令的第二步:转移到子程序的入口地址继续执行。 DST给出转向地址 ( 子程序的入口地址 ), D 为指 令中的位移量 , 它是转向地址和返回地址之间的 差值。2 )段内间接调用 操作: SPSP-2 [SP+1 , SP] IP
IP [ EA] 由 DST 的寻址方式所确定的有效地址3 )段间直接调用 操作: SPSP-2 [SP+1 , SP] CS
IP 指向下一次要取出的指令
16
98
SPSP-2 [SP+1 , SP] IP
IP 偏移地址 ( 指令的 2 、 3 个字节 ) CS 段地址 ( 指令的 4 、 5 个字节 )
4 )段间间接调用 操作: SPSP-2 [SP+1 , SP]CS
SPSP-2 [SP+1 , SP] IP
IP[EA ] CS [EA+2]
2. RET 返回指令 放在子程序的末尾 , 使子程序执行完后返回调用程序继续执行 , 返回地址是 Call 时存放在堆栈中。 1) 段内返回 格式 RET 操作:
99
IP[SP+1, SP] SP SP+2 2) 段内带立即数返回 格式 RET EXP 操作: IP[SP+1, SP]
SP SP+2 SP SP+D 由 EXP 的值计算出 D 。 此指令允许返回地址出栈后修改堆栈的指针 , 以便在调用程 序在用 call调用子程序以前把子程序所需要的参数入栈 , 以 便子程序运行时使用这些参数。当子程序返回后 , 这些参数 已不再使用了 , 可以修改指针使其指向参数入栈以前的值。 3) 段间返回 格式 RET 操作: IP[SP+1, SP]
SP SP+2
16
16
100
CS[SP+1, SP] SP SP+24) 段间带立即数 格式 RET EXP 操作: IP[SP+1, SP] SP SP+2 CS[SP+1, SP] SP SP+2 SP SP+D CALL, RET 不影响标志位 A 、 C 、 O 、 P 、 S 、 Z 。3. JMP 跳转指令 无条件转移指令 , 不要求返回。 1) 段内直接短转移 格式 JMP SHORT OPR 操作: IP IP+D (8 位偏移量 ) 2) 段内直接近 转移
16
8
101
格式 JMP NEAR PTR OPR 操作:
IP IP+D (16 位偏移量 ) 3) 段内间接转移 格式 JMP WORD PTR OPR 操作: IP (EA) 属性操作符 4) 段间直接转移 格式 JMP FAR PTR OPR 操作: IP OPR 的段内偏移地址 CSOPR 所在段的段地址 ( 二 ) 条件转移指令 条件转移指令是以某些标志位或其逻辑运算为依据。 若是满足所规定条件 , 则程序转移到指定目标 ; 若不满足条件 , 则程序顺序执行条件转移指令的下一条指令。 目标地址是采用相对寻址方式 , 即以转移指令为基准的 +127 或 -128 字节范围内寻址。
16
102
(1)根据标志位的条件转移指令 JCC=1 JNC C=0
JE/JZ 相等或结果为 0 , 即 Z=1 JNE/JNZ 不相等或结果非 0 ,即 Z=0
JS S=1 转移 JNS S=0 转移
JO O=1 转移 JNO O=0 转移
JP/JPEP=1 转移 JNP/JPO P=0 转移 (2) 用于无符号的条件转移指令 JA/JNBE 为 高于 / 不低于或等于时转移 即 ZVC=0 JNA/JBE 为 不高于 / 低于或等于时转移 即 ZVC=1 (3) 带符号数的条件转移 JG/JNLE 为 大于 / 不小于或等于时转移 即 (SO)VZ=0 JGE/JNL 为 大于或等于 / 不小于时转移 即 SO=0 JL/JNGE 为 小于 / 不大于或等于时转移 即 SO=1,Z=0
103
JLE/JNG 为 小于或等于 / 不大于时转移 即 (SO)vZ=1( 三 ) 重复控制 重复控制指令是当 CX 不为零时 ,循环至目的地址。 若 CX=0 时 , 则顺序执行重复控制指令的下一条指令。它的相 对寻址是在控制指令的 +127-128 字节的范围内。 1.LOOP CX-1CX 若 CX0 则循环到目标操作数—— IP+偏移量 (16 位 ) ; 若 CX=0 则退出循环 , 往下执行。 2.LOOPZ CX-1 CX 若 CX0 且 Z=1 则循环;否则退出循环。 3.LOOPNZ CX-1 CX 若 CX0 且 Z 1 则循环;否则退出循环。 4.JCXZ 若 CX=0 则转移到目标操作数—— IP+偏移量 (扩展到 16 位 )( 四 ) 中断
104
当系统运行或程序运行期间在遇到特殊情况 , 需要计算机自 动执行专门的程序来进行处理 , 这种情况称为中断。 它分为 2 种:
内部中断指令 , 除 0产生的中断 外部中断指令 , I/O 与 CPU 中断向量:中断程序的入口地址 03FF 单元 ,1024 个字节为中断向量区 , 存放 256 种类型 。每个 中断向量占有 4 个字节单元 , 分别是 CS(2 个 ) IP(2 个 ) 1.INT 中断指令
INT TYPE—— 中断类型号 ( 可以是常数或常数表达式 P335) 执行操作: SPSP-2 [SP+1 , SP]F SPSP-2 [SP+1 , SP] (CS) SPSP-2 [SP+1 , SP] (IP) (IP) [ TYPE*4 ] CS [ TYPE*4+2 ]
105
2. INTO 若溢出中断指令 格式 INTO 操作: 若 O=1 , 则 SPSP-2 [SP+1 , SP] F SPSP-2 [SP+1 , SP] (CS) SPSP-2 [SP+1 , SP] (IP) IP[0010H] CS[0012H] 3.IRET 从中断返回指令 格式 IRET 操作: IP [SP+1, SP] SPSP+2 CS[SP+1, SP]
SPSP+2 F [SP+1, SP] SPSP+2
型号 =4 的中断44=10H
4 4+2=12H12H 的一个字的内容 CS
106
六、处理器控制指令 ( 一 )标志操作 1. CLC C=0 2. CMC CC 3. STC C=1 4. CLD D=0 5. STD D=1 6. CLI I=0 7. STI I=1 ( 二 )CPU暂停
HLT ( 三 )CPU脱离 ESC——交权指令 ( 四 )CPU等待 Wait ( 五 )总线锁定 Lock
107
第一节 汇编语言语句
108
一、语句类别 汇编语言的基本语句: 指令语句 伪指令语句 宏指令语句 源程序是用汇编的语句编写的程序。 格式为 NAME1 Segment NAME1 ENDS NAME2 Segment
NAME2 ENDS
ENDS 指令语句格式为 [标号: ] 助记符操作数 1, 操作数 2 [ ;注释 ]
伪指令语句格式为
109
[ 符号名 ]定义符 参数 1……….. 参数 n [ ;注释 ] 宏指令语句格式为 [标号: ] 宏指令名 参数 1……….. 参数 n [ ;注释 ] 1. 标号表示一条指令所在地址 , 也是指令语句的地址符号 , 最多 允许使用 31 个字符。不能以数字开头。 符号名用在伪指令语句前面 , 不是每一条伪指令都必须有一个 符号名的。 2. 助记符及定义符由系统定义。 3. 宏指令名由程序员定义 , 但不能用系统已经定义过的符号名。 4. 操作数用于指令语句 , 参数用于伪指令和宏指令中。 5. 注释不是汇编语句的必须部分。
110
第二节 语句行的构成
111
一、标记 ( 一 ) 字符集:字母、数字、特殊字符 (+ 、 - 、 * 、 / 、 { 、;等 ) 。 ( 二 )界符 : , < - + >
( 三 ) 常量 1. 数字常量 : 二进制数、十进制数、八进制数、十六进制数 2. 字符串常量:由包含单引号内的 1 至 2 个 ASCII 字符构成。
( 四 )标识符 由程序建立的 , 由最多 31 个字母 , 数字及字符组成 , 且不能 用数字开头。 如 : MY_DATA , SUM
THIS_DONE 和 THISDONE 是不同的。 (五 )保留字:指令助记符 , 伪指令 , 寄存器名称。 (六 ) 注释二、符号 它是一种标识符 , 符合标识符的组成规则。 寄存器、变量、标号、数、其它。 ( 一 )寄存器: AX 、 AL 。
112
( 二 )变量 存放在存储单元的操作数是变量 , 存储单元的地址符号就是 它们的名字。 任何变量都有三种属性:
1. 段值 (segment) 2.偏移量 (offset):变量单元地址与段的地址之间的偏移量 (16 位 ) 3.类型 (type):B( 字节 ) 、 (W 字 ) 、 (DW 双字 )( 三 )标号 与变量相似 , 是存储单元的符号地址。 它在存储单元中存放指令 , 变量存放数据。 类型 : FAR(CS 、 IP) 或 NEAR(IP)( 四 ) 数 源程序的常数 , 常以符号形式出现 , 便于修改。 如 Count EQU 100 又如 把端口地址定义为一个符号 PORT—VAL PORT—VAL EQU 3(五 ) 其它 (伪指令部分 ) 除上述寄存器 ,变量 ,标记 , 数外都是伪指令 segement/ENDS
113
三、表达式 表达式是由标记、符号通过运算符组合起来的序列。 一个表达式是一个由操作数和运算符组合的序列。 ( 一 ) 操作数 r , m , im(立即数 ) 1. 常量操作数 (-2 -1 , 2 -1), 即 (-65535 , +65535) 2.存储器操作数 两种:标号——指令语句符号地址 如 JMP, Call 变量—— 4 种寻址方式 --直接 -- 基址 --变址 -- 基址加变址 可存放在 M 中的值 三种属性 -- 段值 -- 段内偏移量 --类型 ( 二 ) 运算符
16 16
114
有以下五种:算术运算符 逻辑运算符 关系运算符 分析运算符 合成运算符 1. 算术运算符 mod 当算术运算符用于存储器时 , 只有当结果有明确的、有意义 的物理解释时才有效。 如 SUM+2 地址加 2, 而不是内容加 2 CYCLE-5 NOT_DONE-GO 同段 而 SUM-CYCLE 前者是数据段 , 后者是码段 在不同段 , 相减无意义 2. 逻辑运算符 按位操作的 AND 、 OR 、OR 、 NOT 。 其操作数只能是数字的 , 且结果是数字 , 存储器操作数不能进
115
行逻辑运算。 如 NOT 1111 1111=0000 0000 又如 1111 0000 1111 0000 OR SUM 无效的 IN AL,PORT-VAL OUT PORT-VAL AND OFEH,AL 若 PORT 是 -VAL 是偶数 , “ 与”后仍是同一端口 若 PORT-VAL 是奇数 , “ 与”后是 PORT-VAL 低的下一个端口作为汇编的运算符是在程序汇编时计算 , 而作为指令的助记符 , 则在程序执行时计算的 . 如 AND DX , PORT-VAL AND OFEH 程序执行时计算3.关系运算符 相等 EQ 不等 NE 小于 LT 大于 GT 小于等于 LE 大于等于 GE 关系运算的两个操作数或者都是数字 , 或者都是同段存储器地址 ,
汇 编 时 计 算
116
结果是数值。 0——关系假 , 0FFFFH——关系真。 如 mov BX , PORT-VAL LT 5 若 PORT-VAL 的值 <5 , 关系为真 , 则汇编程序在汇编程序后产生的语句为 mov BX , OFFFFH 否则 mov BX , 0 一般把关系运算符与逻辑运算组合使用。 又如 mov BX , ((PORT-VAL LT 5) AND 20) OR((PORT-VAL GE 5) AND 30) 若 PORT-VAL 的值 <5 汇编程序为
mov BX , 20 否则 mov BX , 30
117
第三节 指示性语句 ——伪指令
118
一、符号定义语句 ( 一 )等值语句 EQU 定义一个值、别的符号名、可执行指令 格式 NAME EQU Expression 如 buffer-size EQU 32 count EQU CX 定义为寄存器 CX 的同义语 CBD EQU ADD 定义为加法 New-port equ port-VAL 在解除 EQU 以前 , 不能重新定义。 ( 二 )等号语句 EMP 能对符号进行再定义 emp=6 , emp=7 , emp=emp+1 ( 三 )解除语句 PURGE 用于已经用的 EQU 语句的情况下 格式 Purge 符号 1 , 符号 2 , … , 符号 n 用 purge解除后的符号可以再定义。 如 purge NEW-PORT NEW-PORT EQU PORT-VAL+2二、数据定义语句
119
为一个数据项分配存储单元 , 且并赋符号名和初值。 如 THING DB ? ; 定义一个字节 BIGGER-THING DW ? ; 定义一个字 BIGGEST-THING DD ? ; 定义一个双字
THING DB 25 ; 一个字节把 25放入和 BIGGER-THING DW 4142H; 与 THING 相联系的 存储单元 同样 biggest-thing DD 12345678H
当汇编程序汇编时遇到“?” , 则它仍然为数据项分配相应存 储单元 , 以便存放指令执行的中间结果 ,并不产生一个目标码 来初始化存储单元。
78563412
biggest-thing+1+1+1
120
如 POWERS-2 DB 1 , 2 , 4 , 8 , 16
ALL-ZERO DB 6 DUP(0) DB 100 DUP(0) DB 100 DUP(0) 又如 ALPHA DW 2 DUP(3 DUP((1,2 DUP(4,8),6),0)
POWERS-2 1248
16
5 个
148486
148486
148486
121
字符串 ( 每个字符用 ASCII 表示 , 为一个字节 ) 如 EXAM1 DB ‘THIS IS AN EXAMPLE’ 或者 DB ‘ T , H , I , S ’ 字符串的定义必须是 DB 命令
一个存储单元的类型: 1. 数据字节
SUB DB ? ; 定义一个字节 2. 数据字 BIGGER DW ? ; 定义一个字 3. 数据双字 BIGGEST DD ? ; 4.NEAR 指令单元 5. FAR 指令单元 一个指令单元能出现在 JMP 或 CALL 语句中。 若类型是 near, 产生一个段内 JMP 、 CALL,2 个字节。 若类型是 far , 产生一个段间 JMP 、 CALL,4 个字节。 分析运算符把存储器地址分为 5 个:
122
seg
offset type size length 指令所在段的段地址加偏移量 一个存储单元地址加或减形成的新的存储单元与原来的存储 单元有相同的类型。 seg 功能 : 可用 seg返回变量或标号所在段的段基址。 如 mov AX, seg ABC 把变量 ABC 的段地址 AX offset 功能 :offset 可返回变量或标号的所在段的偏移量。 type 功能 :返回一个表示变量或标号类型的数值。 变量 标号 DB 1 NEAR -1 DW 2 DD 4 FAR -2
123
如 ALFA DW 20 DUP(?)
mov AL , type ALFA ; (2AL) Length 分配单元长度操作符 功能:返回给该变量的单元数 仅对 DUP项返回变量单元数 , 对其它情况均返回值 1 。
如 ALFA DW 20 DUP(?) BATA DB 12 mov AL, Length ALFA; (20 AL) mov AH, Length BATA; (1 AH) size 功能 :返回分配给该变量的字节单元数。 如 mov AL , size ALFA ; (40 AL) mov AH , size BATA ; (1 AH) 显然 size ALFA=(Length ALFA)*(type ALFA) 合成运算符 (PTR 、 THIS) type PTR variableconstant expression
124
在 PTR 左边的操作数有 3 种: byte , word , Dword 。 在 PTR 右边的操作数生成与原存储器操作数段地址、段内偏 移量相同 , 类型不同的新的存储器操作数。 如 OPER1 DB 1 , 2 OPER2 DW 1234H , 5678H
mov AX , OPER1+1 mov BL , OPER2
请考虑一下指令中的斜体部分是否表示正确正确的应该改为 mov AX , WORD PTR OPER1+1 mov BL , BYTE PTR OPER2
对于 mov AX , WORD PTR OPER1+1 OPER1+1 的内容 AX , 即 OPER1+1 的内容 AL 02 AL 所以 (AX)=3402H
125
而对于 mov AL , BYTE PTR OPER2 把 OPER2 的第一个字节的内容 BL , (AL)=34H THIS 与 PTR类似 其段地址加上段内偏移量就是汇编时当前值 段地址 + 段内偏移量
WBUFFER1 EQU THIS WORD BUFFER2 EQU THIS BYTE DWBUFFER3 EQU THIS DWORD三、段定义语句 它的主要命令有 4 个: segment ENDS assume 定义 CS 、 ES 是什么段 org 规定段内的起始地址 下面我们来看一个例子: my_DATA segment x DB?
126
y DW? z DD? My_DATA ENDS
my_EXTRA segment ALPHA DB? BETA DW? GAMMA DD? my_EXTRA ENDS
my_stack segment DW 100 DUP(?) TOP EQU THIS WORD my_stack ENDS
my_CODE segment assume CS:my_CODE , DS:my_DATA
ES:my_EXTRA , SS:my_stack
127
start : mov AX , seg x mov DS , AX mov AX , seg ALPHA mov ES , AX mov AX , my_stack mov SS , AX mov SP , offset TOP
my_CODE ENDS END start 在汇编语言的源程序中 , 定义 CS 、 SS 、 DS 、 ES 每一个段必须 有一个名字。一个段由命令 segment 开始 , ENDS 结束 , 成对出现。 最后用 END 结束源程序。四、过程定义语句 在 8088 中调用过程和返回的指令是 call 和 ret过程定义语句。 PROC 和 ENDP 是在说明 call 和 ret 是 NEAR还是 FAR型。 如 procedure_name proc [NEAR]
128
. ret
procedure_name ENDP 谨记 proc 和 ENDP 成对出现。 一个过程定义的例子: my_code segment my_code ENDS up_count proc near END ADD CX,1 RET up_count ENDP start : call up_count
call up_count
129
五、结束语句 segment—ENDS proc—ENDP END END < 表达式 > 表达式为第一条要执行的指令的地址
130
第四节 指令语句
131
指令助记符 指令前缀 操作数寻址方式 串操作指令一、指令助记符 ( 一 )NOP:保留一些单元为以后填入指令时用 ,放慢速度。 (AX 自行交换 ) ( 二 )NIL:保留空格 如 CYCLE : NIL CYCLE : INC AX INC AX二、指令前缀 1. 段超越:由 assume 语句的信息选择段寄存器。 如 mov BX , ES :SUM
由汇编程序决定在用选择的 段寄存器是否超越 2. 重复: rep repE 当相等时重复 repNE 当不相等时重复
指令语句
132
repZ Z=1 时重复 repNZ Z=0 时重复 3.锁定: LOCK三、操作数寻址方式 共有 8 种: 立即 寄存器 直接 基址 变址 基址变址 基址或变址 + 位移量 基址变址 + 位移量
如 SUM DB ? 字节 INC SUM 一个字节增量 如 mov AL , [BX] 字节 由目的指定 [BX]也是字节型 而 INC [BX] 是错误的 INC BYTE PTR [BX] 一个字节增量 INC WORD PTR [BX] 一个字增量四、串操作指令
133
请回忆一下之前学过的指令 。
COMPS (SI) -(DI) 指令语句
指示性语句:符号定义、分存储单元、分段 码段 栈段 数据段 如两个未压缩的 BCD 码相加。 先数据段、再堆栈段、码段 DATA segment stri1 DB ‘1’ , ‘7’ , ‘5’ , ‘2’ stri2 DB ‘3’ , ‘8’ , ‘1’ , ‘4’ count equ $-stri2 $ 表示当前地址计数的值
源程序
程序
MOVS (DI) (SI) DI1,2 SI 1,2 SCAS AL/AX-(DI) DI1,2 SI 1,2 LODS AL/AX(SI) SI 1,2STOS AL/AX(DI) DI 1,2
关于 $
135
DATA ENDS stack segment stack para stack ‘stack’ stapN DB 100 DUP(?) TOP EQU Length stapN stack ENDS CODE segment assume CS:code , SS:stack , DS:DATA , ES:DATA start proc FAR PUSH DS mov AX , 0 PUSH AX go: mov AX , DATA mov DS , AX mov ES , AX mov AX , stack mov SS , AX mov AX , TOP mov SP , AX
在堆栈中推入一个段地址 DS 和 IP 返回 DOS
136
CLC CLD mov SI , offset stri1 mov DI , offset stri2 mov CX , count cycle: LODS stri1 ADC AL , [DI] AAA STOS stri2 LOOP cycle RETSTART ENDPCODE ENDS END start 定义数据 , 堆栈段 , 代码段 , 过程定义语句。 RET返回 DS , IP(0000H) DOS 源——目标——连接——程序前缀
137
第五节 汇编语言程序设计及举例
138
一、概述 1. 汇编语言源程序的结构 NAME 数据段名 segment 变量定义 数据空间预量 数据段名 ENDS 堆栈段名 segment para stack ‘stack’ 堆栈空间预量 堆栈段名 ENDS 代码段名 segment assume 段寄存器地址说明 start : 段地址装填 主程序 过程名 1 proc类型 过程体 过程名 1 ENDP
139
过程名 N proc类型 过程体 N 过程名 N ENDP 代码段名 ENDS END start2. 段寄存器的装填 CS 由系统在加载程序后由系统自动装填 SS也可以由系统自动装填 , 但必须将参数写全 如 stack 、 segment 、 para 、 stack 、‘ stack’ 当程序装入内存时 , 系 统把堆段地址和栈指针置入 SS 和 SP , 因而不必在代码段装填 SS 和 SP 。 DS 、 SS 、 ES 的装填 mov AX , 数据段名 mov DS , AX3.返回 DOS DOS 下运行汇编程序 , 当程序执行结束后返回 DOS 。 过程名 proc far push DS
140
mov AX , 0 push AX
ret 过程名 ENDP ENDP 过程名 (INT 20H) 是返回 DOS 的系统调用 , 系统将执行 INT 20H 系统 (装入程序时 )放在程序段前缀的头二个字节 (100H 字节的信息区 , 放在程序段前 ) 当执行程序后 , DS 和偏移量 CS 、 IP, 从而执行 INT 20H4. 编写程序步骤 (1)建立数学模型
(2)确定解决模型的算法 (3)画流程图 工作框 : 一个入口 , 一个出口 判断框 : 一个入口 ,几个出口
141
子程序框: 一个入口一个出口
程序走向:
(4) 分配内存单元和寄存器 (5) 写程序二、直线运行程序 两个 32 位无符号数乘法 A B
C D
ADBC
BD
AC+最后乘积
16 位
142
name data segmentmulnum dw 0000 , ffff , 0000 , ffff , 4 dup(?) data ends stack segment para stack ‘stack’
db 100 dup(?) stack ends code segment assume cs:code , ds:data , ss:stack , es:data start proc far being: push ds ; mov ax , 0 push ax mov ax , data mov ds , ax mov es , ax lea bx , mulnummulu32: mov ax , [bx] ; BAX
DS 中包含的是程序段前的起始地址 设置返回至 DOS 的段值和 IP 值
置段寄存器初值
143
mov si , [bx+4] ; D SI mov di , [bx+6] ; C DI mul si BD (DX , AX) mov [bx+8] , ax mov [bx+a] , dx mov ax , [bx+2] A AX mul si ; AD(DX , AX) 乘积 2 add ax , [bx+a] adc dx , 0 mov [bx+a] , ax mov [bx+c] , dx mov ax , [bx] B AX mul di B C(DX , AX) 乘积 3 add ax , [bx+a] 与乘积 3 的相应部分积相加 adc dx , [bx+c] mov [bx+a] , ax mov [bx+c] , dx pushF 保存 C(保存后一次相加的进位 )
保存乘积 1
乘积 2 与乘积 1 的相应部分相加
乘积 3 与乘积 2 的相应部分相加
144
mov ax , [bx+2] AAX mul di AC(DX , AX) 乘积 4 popF adc ax , [bx+c] 与乘积 4 相应部分相加 adc dx , 0 mov [bx+c] , ax mov [bx+e] , dx ret start endP code ends end begin
P127 例 : 32 位有符号数乘法 name data segment
sign db ?mulnum dw X1 , X2 , X3 , X4 , 4 dup(?) data ends
145
stack segment para stack ‘stack’ db 100 dup(?)code segment assume cs:code , ds:data , ss:stack , es:datastart proc farbegin:push ds mov ax , 0 push ax mov ax , data mov ds , ax mov sign , 0 置符号初值 lea bx , mulum mov ax , [bx] B AX mov dx , [bx+2] A DX mov si , [bx+4] D SI mov di , [bx+6] C DI cmp dx , 0 检验正、负 jns other 若为正 ( 即 S=0)转至 other
返回至 DOS
146
not ax not dx add ax , 1 adc dx , 0 not sign 改变符号 mov [bx] , ax mov [bx+2] , dxother: cmp di , 0 检验乘数符号 jns go mul 若 S=0 则转移到 go mul not si not di add si , 1 adc di , 0 not signgo mul: call mulu32 调用无符号乘数 cmp sign , 0 检验S 位 je done Z=1( 相等 ) 乘积为正 , 结束 not word ptr [bx+8]
若为负则求补
保存被乘数
乘数求补
147
not word ptr [bx+a] not word ptr [bx+c] not word ptr [bx+e] add word ptr [bx+8] , 1 adc word ptr [bx+a] , 0 adc word ptr [bx+c] , 0
adc word ptr [bx+e] , 0 done: ret start endP mulu32
三、分支程序设计
( P129 )
乘数求补
1 X>0 y= 0 X=0 -1 X<0
y-1 y0 y1
x>0<0
=0
出口
148
sigef mov AX , buffer OR AX , AX 执行一个判断 JE ZERO Z=1 转移至 zero JNS plusS=0 转移至 plus mov BX , FFFFH y-1 JMP conti zero : mov BX , 0 JMP conti plus : mov BX , 1 conti :例:数据 AL 的被置位的情况控制转移到 8 个子程序中。 AL : 0000 0001
0000 0010 0000 0100 0000 1000
0001 0000 0010 0000 0100 0000 1000 0000
R1R2R3R4R5R6R7R8
149
name data segment brtab dw R11 子程序 R1 入口地址的 IP 值 dw R12 子程序 R1 入口地址的码段值 dw R21 同上 dw R22 同上
dw R81 dw R82 data ENDSstack segment para stack ‘stack’ DB 100 DUP(?)TOP equ $-STACKstack endscode segmentstart proc far assume cs:code , ds:data , ss:stack , es:data begin : push DS
启动
D0=1 ?
D1=1 ?Y
Y
Y
N
N
R1
R7
R2
R8
150
mov AX , 0 push AX mov AX , data mov DS , AX mov AX , stack mov SS , AX mov AX , TOP mov SP , AX lea BX , brtab 设跳转地址的地址指针gtbit: RCR AL , 1 JC getad C=1 时转移 INC BX INC BX INC BX INC BX JMP gtbitgetad:JMP Dword ptr [BX] ; 段间间接转移 start ENDP
C
BXBX+4
151
四、循环程序设计
例 1. 用计数器控制循环 寻找一串给定个数的数中的最大值 ,并放入指定单元中。 每个数用 16 位表示。 name data segment buffer dw X1 , X2,…, Xn count equ $-buffer max dw ? data ends stack segment para stack ‘stack’
工作部分 控制部分
循环体
结构 循环结束条件
循环初态 循环工作初态:如标志位、寄存器清零 结束条件初态: CX 的初态
152
DB 64 (?) top equ $-stackstack endscode segment assume cs:code , ds:data , ss:stack , es:databegin : push DS mov AX , 0 push AX mov AX , data mov DS , AX mov AX , stack mov SS , AX mov AX , top mov SP , AX mov CX , count SHR CX , 1 lea bx , buffer mov AX , [BX]
153
INC BX INC BX dec cxagain: cmp AX, [BX]
JGE next mov AX , [BX]next: INC BX INC BXLOOP againstart endPcode ENDS END start
例 2. 条件控制循环 求 16 位无符号数的整数平方根 X2=(N/X1X1)/2 X1=(N/200+2) 若 X1 是数 N 的平方根的近似值 , 则 X2 是数N的平方根的最近 似值 , 这个称为逐次逼近法
154
name data segment num dw 2710H result dw ? digit equ 200 data ends stack segment para stack ‘stack’ db 100 dup (?) stack endscode segment assume cs:code , ds:data , ss:stack , es:databegin: mov ax , data mov ds , ax mov ex , ax lea bx , num mov ax , [bx] axN mov si , ax SIN
155
mov di , digit DI200 cwd 双字扩展 AX(DX , AX) div di N/200 add ax , 2 N/200+2 AX=X1conti: mov cx , ax mov ax , si cwd div cx add ax , cx shr ax , 1 mov dx , ax sub dx , cx je done cmp dx , 1 jne contidone:mov [bx+2] , ax retstart endP
Q
156
code ends end begin3. 多重循环 delay : mov DX , 3FFH time : mov AX , FFFFH time1 : dec AX NOP JNE time1 dec DX JNE time ret ————延时程序4. 用开关量控制循环
name data segment buffer dw 05…05 , 05…05 block dw 12 dup(?)
第一循环支路 第二循环支路
157
count1 equ 5 count2 equ 7
mov dx , 0 mov cx , count1+1 6CX lea bx , buffer lea si , blockagain : mov ax , [bx] cmp dx , 0 开关量是否为零 jne another 不为零则转移到another call fun1 为 0 loop next mov dx , 1 mov cx , count2+1 8CX jmp again next : mov [SI] , ax inc bx inc bx
158
inc SI inc SI jmp againanother : call fun2 loop next ret start endP
fun1 proc add ax , ax ret fun1 endP fun2 proc add ax , ax add ax , ax ret fun2 endPcode ends end begin
159
5. 逻辑尺
160
五、字符串处理程序设计 常用的字符编码是 ASCII 码字符。 09 为 ASCII 码的 30 H39H AZ 为 ASCII 码的 41H5AH 常用的控制字符 ( 不同系统有不同控制字符 )
0AH 换行 LF 0DH 回车 CR 字符串的长度常以某个特殊字符作为结束标志 , 如 $ 、 CR 。
例 从头搜索字符串的结束标志 , 统计字符个数。 (P141) name length-of-string data segment string db ‘abcduvwxyz’ , 0dH LL db ? Cr equ 0dH data endS stack segment para stack ‘stack’
stack endS code segment
161
assume cs:code , ds:data , es:data , ss:stack start proc far begin: push ds mov ax , 0 push ax mov ax , data mov ds , ax mov es , ax lea di , string ; 设串的地址指针 mov dL , 0 置串长度初值= 0 mov AL , cr 串结束标志 AL again: scasb 搜索串 je done inc DL jmp again done: lea bx , LL mov [bx] , dL ret
162
start endP code endS end begin 为避免出现 cr 丢失 , 进入死循环 ,设循环次数 > 字符串长度 data segment string db ‘abcdefghij’ , odh count equ $-string LI db ? data ENDS stack segment para stack ‘stack’ db 100 dup(?) stack ends code segment assume cs:code , ds:data , es:data , ss:stack start proc far begin: push ds mov ax , 0
push AX 返回 DOS
163
mov ax , data mov ds , ax mov ES , ax lea di , string mov dL , 0 串长度初值为零 mov aL , 0dh mov cx , count+10 置循环次数 >串长度again: scasb je done inc dL
dec cx jne again jmp error 由计数停止循环 , 则出错 , 转至出错处理程序
done: mov LL,dL retstart endPcode ends end begin
给段寄存器赋初值
164
( 二 )找串中的第一个非空格字符 P142 例 从一个给定的字符串中 , 从头开始 ,找到第一个非空格 字符。 name data segment string db ‘abcdefghij’ , ‘$’ count equ $-string string2 db count dup(?) string3 db 0dh , 0ah , ‘$’ data ends stack segment para stack ‘stack’
db 100 dup(?) stack ends code segment assume cs:code , ds:data , es:data , ss:stackstart proc farbegin: push ds mov ax , 0
165
push ax mov ax , data mov ds , ax mov es , ax lea di ,string mov cx , count mov Al ,20H repe scasb
inc cx
mov bx, count
sub bx, cx
lea di, string2
lea si, string
add si, bx
rep movsb
关于rep
169
lea dx , string
mov ah , 9int 21H
lea dx , string3mov ah , 9int 21Hlea dx , string2mov ah , 9int 21H retstart endPcode ends end begin
注: ah=9 的功能是显示字符串 , 要求被显示输出的字符必须以 $字 符作为定界符 , 以 $ 为标记计算串的长度。
显示串 2
显示串 1
显示串 3
170
( 三 ) 用空格代替前导零
namedatastring1 db ‘0000abcderty876’ , ‘$’count equ $-string1-1string2 db count dup(?) , ‘$’string3 db 0dh , 0ah , ‘$’data endsstack db 100 dup(?)stack endscode
lea di , string1mov cx , countmov aL , ‘0’repe scasb
171
inc cx mov bx , count sub bx , cx lea di , string2 push cx mov cx , bx mov aL , 20h rep stosb pop cx lea si , string1 add si , bx rep movsb lea dx , string1 mov ah , 9 int 21h lea dx , string3 mov ah , 9 int 21h
用空格填满串2
显示串1
显示回车、换行
172
lea dx , string2 mov ah , 9 int 21h start code End begin( 四 ) 加偶校验到 ASCII 字符 若有一个 ASCII 字符串 ,放在单元 string 内 , 要求从串中取出每 一个字符 ,检查其中包含“ 1” 的个数 , 若已为偶数 , 则它的最高有 效位置“0” ,否则最高有效位置“ 1” 。 name data string db ‘1234567890’ count equ $-string data ends stack db 100 dup(?) stack code begin:push ds
显示串 2
173
mov AX , 0 push AX lea si , string mov cx , countagain : lodsb and al , al jpe next or aL , 80h AL 最高低置1 mov [si-1] , aLnext : dec cx jnz again ret
174
六、码转换程序设计 硬件 查表 软件 ( 一 )16 进制 ASCII 若一个二进制数码串 , 把每一个字节中的二进制转换成2位 16 进制数的 ASCII 码 , 高 4 位 ASCII 码放在地址高的单元。
六、码转换程序设计 硬件 查表 软件 ( 一 )16 进制 ASCII 若一个二进制数码串 , 把每一个字节中的二进制转换成2位 16 进制数的 ASCII 码 , 高 4 位 ASCII 码放在地址高的单元。
4 位 2 进制 0~15, 可用 1 位 16 进制 (0 ~ 9,A~F)ASCII 码 ,0 ~9 的 ASCII 码只要将 16 进制数加上 30H 、 A ~F 的 ASCII 码加上 37H 就可得到对应的 ASCII 码。 根据是否大于 10 来判断是加 30H 还是加 37H ,完成 16 进制(2 进 制 ) 向 ASCII 码的转换。 name data L1 dw 2 string db 34h , 98h L2 dw ? buffer db 2×2 dup(?)
175
data ends stack seg para stack’41-A’ db 100 dup (?) stack ends mov cx , L1 lea bx , string lea si , buffer mov ax , cx sal cx , 1 mov L2 , cx mov cx , axagain : mov AL , [bx] mov dL , aL and AL , 0FH call change mov aL , DL push cx mov cL , 4 shr aL , cl pop cx
高 4 位 右移 4 位
176
call change inc bx loop again ret start endP change proc cmp aL , 10 jL add-0 add AL , ‘a’-‘0’-10 add-0 : add aL , ‘0’ (AL+30H)AL<10 mov [si] , al (AL+37H) AL>10 inc si ret change endP code ends end begin
177
( 二 )ASCII 码到十进制 (BCD) 的转换 若有一输入的 ASCII, 要把其中的数码 ( ‘0’~‘9’之间 ) 取出来 ,转 换为未组合的 BCD 码 ,存放另一区 ,并统计串长度 ,放入此区的第 一个字节。 502D 0101, 0000,0010 未组合 BCD 0101 0000, 0010 数字的 ASCII 码是一种未组合 BCD name data L1 db 10 string db ‘123asdfgki’ buffer db ? db 10 dup(?) stack db 100 dup (?) stack ends code
178
assume start proc farbegin : push ds mov ax , 0 push ax mov ax , data mov ds , ax mov es , ax mov CL , L1 mov CH , 0 lea si , string 一区 lea di , buffer 另一区 inc di 目的是首地址放 DL的值 mov dL , 0 数码计数器置 0
again : lodsb cmp aL , ‘0’ jL next cmp aL , ‘9’
返回 DOS
段寄存器赋值
179
jg next and aL , 0fh stosb inc dLnext : loop again mov buffer , dL ret start code End begin
180
( 三 ) 把 BCD 码转换为二进制 若有一个 16 位存储单元 ,存放 4 位 BCD 数 , 要把它转换成二
进制 ,并 放在另一存储单元中。( (千位数 ×10+百位数 ) ×10+ 十位数 ) ×10+ 个位数参见流程图参见流程图data
dnum dw 9999h bnum dw ? data mov ax , dnum mov di , ax mov dx , ax mov bx , ax and bx , 000fh and dx , 00f0h mov cL , 4 shr dx , cL
and di , 0f00h mov cL , 8 shr di , cL and ax , f000h mov cL , 12 shr ax , cL
add ax , ax mov cx , ax add ax , ax add ax , ax add ax , cx add ax , di
183
( 四 ) 二进制到 BCD 转换 关键 :找出二进制包含 1000,1000,100,10 的个数 , 这样即可将二进 制转换为相应的 BCD 码。 例:有一个 16 位二进制数要转换为相应的十进制数 ASCII 码。
Tips : Tips : 数字的数字的 ASCIIASCII 码是一种非压缩的码是一种非压缩的 BCDBCD 码。码。 参见其流程图参见其流程图 bnum dw 270FH strg db 5 dup(?)
mov ax , bnum lea bx , strg mov dL , 0again1 : sub ax , 2710H ; AX-10000 js next1 inc dL jmp again1
next1 : add ax , 2710H add dl , 30H mov [bx] , dL inc bx mov dL , 0again2 : sub ax , 03e8H
next2 : add ax , 03e8H
185
(五 ) 从二进制到 ASCII 码串的转换 若要把1个二进制位串显示 , 要把串中每一位转换为它的 ASCII 码。 例: 16 位二进制数 , 每一位转换为相应 ASCII存入 string 。
num dw 4f78h string db 16 dup(?) lea di , string mvo cx , length string push di push cx mov aL , 30h rep stosb pop cx pop di mov aL ,31H mov bx , numagain : rcl bx , 1
186
jnc next mov [di] , aL next : inc di loop again ret
七、列和表的程序设计 列-由数据单元组成 ; 表-特殊目的数据结构。 有关列和表的主要操作: 查找、增加、删除、对其进行分类或排序。 ( 一 )无序列 加一个项至一个无序列 ,判断列中有无 若无 , 则把它加在列的最后。 参见其流程图参见其流程图
187
name data seg buffer db 10, ‘abcdefghij’ db ? key db ‘$’ data ends stack seg para stack ‘stack’ code segment assume:cs:code,ds:data, es:data,ss:stack start pro far begin: push ds mov ax,0 push ax mov ax,data mov ds,ax
mov es,ax lea di,buffer mov ax,data mov ch,0 mov cl,[di] 列长度→ cx
inc di mov al key repnz scasb je done move [di],al inc buffer done ret start endp code ends end begin
188
2. 删去一个元素—找到要删去的元素,列长度 -1,元素上移 buffer db 10, ‘abcdefghij’ key db ‘f’ …… lea di,buffer mov ch,0 mov cl,[di] 串长度→ cx inc di 指向第一元素 mov al,key repnz scasb jne done 未找到,结束 dec buffer 若找到,串长度 -1 mov si,di ‘f’的下一个地址→ si
dec si si-1→si, 原来‘ f’ 的地址 xchg si, di rep movsb (di)←(si)
done: ret
start endp
code ends
end begin
189
P156/例 3-21.找出元素序列的最小值和最大值
取列长度→ cx
取列中第 1元素
送 min
送 max
取下一元素
al=min
N
al>min
1
Y
N
2
3
2
al<max
Nal→max
1
Y
al→min
3 Y
修改地址
完成否
Y
4
4
190
buffer db10,22,-12,80,-6,-70,
-9,127,-10,00,40
minval db ?
maxval db ?
lea bx, buffer
mov ch,0
mov cl, [bx] inc bx bx 指向列中第一个元素 dec cx
mov al, [bx]
mov minval, al
mov maxval, al
inc bx
dec cx
again: mov al, [bx] cmp al, minval je next 相等→ next jg a1 若到元素大 ,
转 a1 mov minval,al al< 现在
值 →minv
al jmp next
a1:cmp al, maxval jl next mov maxval,al next:inc bx dec cx jne again ret
…
192
( 二 )气泡分类法 如下的 10 个数 :22 、- 12 、 80 、- 6 、- 70 、- 9 、 127 、 - 10 、 00 、 40 。 如果按数的大小排列:
两者的比较办法:第 N 个数 e 与第 N- 1 个数 e 相比较 , 若 e > e , 则不变换;若 e <e , 则变换。 e N –1>e N-2
e2>e1
若数组长度为 N ,最多经过 N-1趟,可使数组大小排列有序。 当第一趟比较结束,数组中的最小值冒到了顶部,为了除 去不必要比较,每次开始置标志为 0( 若交换 -1 ;若不交换 0) 下次比较若为 -1 ,就说明尚未排好;若为 0 ,说明排好,便 停止循环。
193
如果按数的大小排列: 两者的比较办法:第 N 个数 e 与第 N- 1 个数 e 相比较 , 若 e > e , 则不变换;若 e <e , 则变换。 e N –1>e N-2
e2>e1
若数组长度为 N ,最多经过 N-1趟,可使数组大小排列有序。
当第一趟比较结束,数组中的最小值冒到了顶部,为了除 去不必要比较,每次开始置标志为 0( 若交换 -1 ;若不交换 0) 下次比较若为 -1 ,就说明尚未排好;若为 0 ,说明排好,便 停止循环。 参见流程图参见流程图 程序如下:
buffer dw 22 , -12 , 80 , -6 , -70 , -9 , 127 , -10 , 00 , 40 count equ $-buffer conti : mow bL , 0 mov cx , count
N N -1N
N -1 N -1N
194
初始化
交换标志为 0
取数组长度为 N
设变址值
取 ej
交换
标志为 -1
修改变址值
比较完
变换标志=0 ?
返回
N
Y
YN
Yej>e j-1
195
mov si , cx dec si dec si shr cx , 1again : mov ax , buffer [si] cmp ax , buffer [si-2] jge next xchg ax , buffer [si-2] mov [si] , ax mov bL , -1 next : dec si dec si loop again cmp bL , 0 jne conti ret
196
简化之: 第二趟 e2,e1比较多余 大循环 (趟 )I=2 ,每趟后 I+1I 小循环 (次 ) 每一趟中的小循环变量为 N( 数组长度 ) 每两两比较一次 N 减量, N-1N 当 N<I ,停止小循环。 若到某一趟,只发生 eN,e N-1交换,或无交换 无需要比较,前 N-2 个元素已经有序,整个 e
N,e N-1交 换后,数组有序了。 若标志 =N( 每趟小循环的初值不变,则停止排序 )
197
(三 ).有序列操作 :p160 string dw 10,-80,-50, 00, 20,30,
40,100,2000,10000,
25000
key dw 2000
sflag dw ?
lea di, string mov cx, [di] 列的长度→ cx inc di
inc di
mov ax, key
cmp ax, [di] jl none 若 <第一元素 ,列中无关键字
mov bx, cx sal bx, 1 bx←有序列的元素 cmp ax, string [bx] 与最后一个 元素比较 jg none 无字 repne scasw 否则搜索 jne none 未找到 , 结束 dec di 若找到 ,DL 指向关键字 dec di mov sglag di jmp done none:mov ax, -1 mov sflag, ax 未找到 , -1→sflag
done: ret
…
198
( 四 ). 连接队列 列中每一项除了数据元素外 ,还包括指向下一列元素
的地址指针 ,占有内存空间 ,不用重新排列 .
( 五 ). 表 P166 例 .有一个 0度— 90度的三角函数表 ,给定一个角
度值 , 查出相应的正弦函数值 .
指向列的开始 →
指向元素 2元素 1的数据
元素 1
→指向元素 3元素 2的数据
元素 2
→最后元素元素 3的数据
元素 3
602060006020
→ 6060
第 1个元素6060
→ 60A0
第 2个元素 60A0
→ 0000
最后元素
60606000 60206060 60A0
60A0
→ 0000
199
符号 sign=0
取角
角〈 181
sign=1
角 =角 -180度
N
Y
角〈 91度
角 =180度 - 角
1
1
查表得到正弦值
符号作为最高有效值
ret
200
sintab db 0,2,4,6,8,0AH rest db ?
mov al, 5 xon dl, dl 置 0,符号为正 cmp dl, 180 jb simpos c=1, 小于为正 or dl, 80 否则符号置为负 sub al, 180 sinpos:cmp al, 91 js getsin neg al 角度取补, -al→al
add al, 180 变为 180- 角 getsin:lea bx, sintab
xlat
or al, dl
mov rest, al
ret
…
201
P168 例 . 有一个 0! ~7!阶乘法,在某一单元中给定一个值( 0~7 ) 通过查表,找到它的阶乘值。 table dw 1,1,2,6,24,120,720,5040
result dw ?
digit db x
mov bh, 0
mov bl, digit
add bx, bx
lea si, table
mov ax, [si] [bx]
mov result, ax
…
202
八 . 参数传送技术 子程序:说明含有下面的信息 子程序名称、功能、子程序入、出
口参数、子程序使用寄存器、存储区、子程序调用其他子程序的名 称、方式。
一般调用程序向子程序传递有关参数是指: 子程序操作时需要的数据或数据的地址,以便子
程序根据这些参数完成有关操作。
1. 寄存器方式 参数传递方式 2. 存储器方式 3. 堆栈方式
203
(一)寄存器(调用程序与子程序之间通过寄存器传送参数) 若一个子程序要对 2 个长度相同的数据区进行操作 那么在主程序中:把长度首地址→内部寄存器 mov cx, length buffer
mov bx, offset buffer1
mov si, offset buffer2
call subr
(二)存储器(要传送的参数直接放在子程序调用指令之后) call subr
dw bufl: 缓冲区长度 dw bufa: 区 A起始地址 dw bufb: 区 B起始地址 此法取参数,必须从堆栈中取出返回地址( call 下一条指令
地址) 取出参数,修改返回地址以指向其真正要执行的指令地址。
-L--A-
-B-
204
子程序: push bp
mov bp, sp
mov bx, [bp+2] 从栈中取出返回地址(即参数所在地址) mov cx, CS:[bx] cx←长度 mov s1, CS :[bx+2] A→s1 mov d1, CS:[bx+4] B→d1 add bx, 6 6=3*2 个字节 mov [bp+2], bx 修改返回地址,使子程序能返回至所传送参数
后 面的
指令 ret
……
205
(三)利用堆栈传送参数 date seg buffer1 dw BUFA buffer2 dw BUFB buf dw BUFL date ends 主程序: lea bx, buffer1 push [bx] push [bx+2] push [bx+4] call subr 子程序: push bp (subr) mov bp, sp mov cx, [bp+4] cx←BUFL mov d1, [bp+6] d1←BUFB mov s1, [bp+8] s1←BUFA
206
九 . 子程序设计 若一个子程序能够被中断或被中断程序调用,称此子程序
为能 重入。 系统利用堆栈和寄存器来存放临时的数据就能够实现重入。
主程序s
start
Call SR1
Call SR2
Call SR1
END
子程序 1SR1 PROC
ret
子程序 2SR2 PROC
ret
返回点地址的入栈和出栈都是自动实现的。子程序调用自己称为递归,递归必须是重入的。
207
P172. 例 . 64 位加法 stack
db 100 dup (?)
stack ends
code segment
assume cs: code, ss: stack
start proc far
begin: push ds
mov ax, 0
push ax
call add64
num1 dd x1, x2
num2 dd y1, y2
buffer dd ?, ?
ret
start endp add64 proc push bp mov bp, sp pushf 保存 f push ax push cx 保存寄存器 push bx mov bx, [bp+2] bx←num1 首地址 push bx 首地址入栈 add bx, 18H bx←首地址 +24 修改返回地址 mov [bp+2], bx 存入修改地址
208
Pop bx 首地址出栈 Mov cx, 4 一次取 16位, 64位 取 4 次 Clc c=0
Again: mov ax, cs: [bx]
adc ax, cs: [bx+8]
mov cs: [bx+10H], ax
inc bx
inc bx
loop again
pop bx pop cx 恢复寄存器 pop ax
popf 恢复 f pop bp
ret
add64 endp
209
注意: 1 )定义须考虑段地址,段内偏移量(默认 DS ) 2 )取地址是在程序段定义的,故用 CS : [BX] 3 )主程序的调用子程序指令指入的是 CALL 指令的下一单 元地址(不是正确返回地址),所以要修改返回地址, 以指向真正要执行的指令地址。
P175. 例 . n*(n-1) n>0 1 n=0 push cx
mov ah, 0
mov al, num
call factor mov fnum, ax 积存入 pop cx
Ret Start endp Factor proc push ax sub ax, 1 jne f-cont pop ax
n!=
ax←num
210
jmp retam
f-cont:call factor
pop cx
mul cx
retam:ret
factor endp
211
数的阶乘: n*(n-1)! 1
name ----
data segment
num db 3
faum dw ?
data ends
stack segment para stack ‘stack’
db 100 dup (?)
stack ends
code segment
assume: cs: code, ds:data,
es:data, ss: stack
stack proc far
Begin: push ds mov ax, 0 push ax mov ax, data mov ds, data mov es, data push cx mov ah, 0 mov al, mun call factor mov faum, ax pop cx ret
n!=
212
start endp
f-cont:call factor
pop cx
mul cl
:ret
factor proc
push ax
sub ax, 1
jne f-cont
pop ax
jmp return
return:ret
factor endp
end begin
213
无条件转移 JMP SHORT DST
段内直接短转移, -128~+127范围相对转移,
DST 为标号 1. 如: JMP SHORT OVER
JMP NEAR PTR DST
段内直接近转移, -32K~+32K范围相对转移,
DST 为标号
JMP DST 段内间接转移 64KB范围绝对转移, DST 为寄存器 2. 如: JMP CX
JMP WORD PTR DST 段内间接转移 64KB范围绝对转移, DST 为存储单元 如: JMP WORD PR
T [1234H]
段内直接转
移
段内间接转移
214
段间直接转移: JMP FAR PTR DST 段外绝对转移 DST 为另一个代码段中的标
号
把 DST所在段的值→ CS
DST偏移量的值→ IP
段间间接转移: JMP DWORD PTR DST 段外绝对转移 DST 为存储单元 如: JMP DWORD PTR [1234H] 低
字内容→ IP
高字内容→ CS
条件转移指令均为段内短转移,范围为: -128~+127
1. JMP WORD PTR [DI] 是 ( )2. JMP FAR PTR ABCD (符号地址)是 ( )A. 段内间接转移 B. 段间间接转移C. 段内直接转移 D. 段间直接转移
习题:
215
十 . I/O 的 DOS 功能调用 调用:把子程序的号(系统功能调用号)→ AH
把子程序规定的入口参数送至指定寄存器 再由中断指令 INT 21H
如: lea dx string mov AH 9 显示字符串 DS: DX int 21H
如: mov dl, outpot-char
mov AH, 2 int 21H 它要求把要输出的字符的 ASCII码送至 DL DOS功能调用向 CRT 输出一个字符的子程序 lea DX, buffer 输入缓冲区的
指针 从键盘输入的一个字符串 mov AH, 10 int 21H
DX→ 规定长度实际长度
字符
216
P179. 例 .软件时钟程序 buffer db 10 规定缓冲区长度为 10 字节 db ? 实际输入长度单元 db 10 dup (?) 存放输入字节 mov ax, data mov ds, ax 置初值 mov es, ax
mov dl, ‘:’ mov ah, 2 显示“:” int 21H lea dx, buffer ( DS:DX)=缓冲区最大 mov ah, 10 字符数,( DS:DX+1) int 21H =实际输入字符数 lea bx, buffer+2 存放输入字符首地 址→ buffer+2
mov al, [bx]
and al, 0FH
mov [bx], al inc bx ASSII →BCD
mov al, [bx] 码, ××(时)
and al, of
mov [bx], al
inc bx
inc bx
跳过冒号字符
……
……
……
. ×× 分
跳过
××秒
217
lea bx, buffer+2 mov al, [bx] call m0110 mov ch, al ch为时值 inc bx
inc bx
mov al, [bx]
call m0110 mov dh, al dh为分值 dl 为秒值 again: call delay mov al, dl al←秒值 add al, 1
daa mov dl, al 秒值增1
cmp al, 60 是否为60 jne dispy 否,转显示 mov dl, 0 是,秒值为0
dispy: lea bx, buffer mov al, 0DH 回车 mov [bx], al [bx]→回车 inc bx mov al, 0AH mov [bx], al 换行 inc bx mov al, ch 时 call tran BCD→ASCII inc bx mov al, ‘:’ mov [bx], al inc bx
取 ×× 时的第一个 ×
跳过
…….
……
218
mov al, dh 分 call tran
inc bx
mov al, ‘:’
mou [bx], al
inc bx mov al, dl 秒 call tran
inc bx
mov al, ‘$’
mov [bx], al
push bx
push cx
push dx
lea dx, buffer
mov ah, 9
int 21H
pop dx
pop cx
pop bx
jmp again
start endp
m0110 proc add al, al al*2 daa
mov cl, al add al, al al*4 daa add al, al al*8
显示字符串 DS:DX
219
daa mov cl, al 十位数→ cl inc bx
mov al, [bx]
add al, cl
ret
m0110 endp
tran proc
mov cl, al
shr al, 1
shr al, 1
shr al, 1
shr al, 1 or al, 30H 把十位数→ ASCII码 mov [bx], al
mov al, cl and al, of or al, 30H 把个位数→ ASCII mov [bx], al ret tran endp delay proc push cx push ax mov cx, 0FFFFH goon: dec cx jne goon pop ax pop cx ret delay endp
220
十一 .结束用户程序返回DOS方法 1 .mov AH, 4CH int 21H 用功能调用 4CH(程序结束后插入以上语句) 2 .int 20H 返回DOS子程序,用中断调用 20H 3 .jmp 0 转移到0单元(程序段前缀的开始处,0单元放的是一条 int 20H) start proc far begin: push DS mov AX, 0 push AX ret start endp
… 同 int 20H
弹出开始推入的 AX(0000)和 DX
221
4 . 用功能调用 00H
mov AH, 0
int 21H
十二 . 宏汇编与条件汇编 (一) .宏指令的用途 1 .宏指令可代替源程序重复使用的程序段 mov cl, 4
sal al, cl
由于要多次使用,用一条宏指令代替如下: SHIFT MACRO
mov cl, 4
sal al, cl
ENDM
=JDMP 0
宏定义的名
定义符
宏定义的体:宏指令代替的程序段
结束符
222
指令语句(执行语句) 伪指令(管理语句) 凡要实现 mov cl, 4; sal al, cl 的内容,可以用 SHIFT
(宏汇编程序调用时,产生目标代码) 2 .宏定义不仅简洁方便,而且具有接受参量的能力 SHIFT MACRO * ( * 是形式参量) mov cl, *
sal al, cl
ENDM
SHIFT 4 实现移位4次 若 SHIFT MACRO *, Y Y代替需要以为的寄存器 mov cl, *
sal Y, cl
ENDM
宏定义的体
223
SHIFT 4, AL SHIFT 6, BX
mov cl, 4 mov cl, 6
sal, AL, cl sal BX, cl
汇编时分别产生目标代码 3.形式参量可以在操作码部分中出现 如: SHIFT MACRO X, Y, Z mov cl, X S&Z Y, cl 定义为形式参数,前面必须加上符号&
ENDM 参数 Z用来指示操作码的操作 MOV CL, 4 SAL AL, CL MOV CL, 6 SAR BX, CL MOV CL, 8 SHR SI, CL
SHIFT 4, AL,AL
SHIFT 6, BX, AR
SHIFT 8, SI, HR
224
(二)宏操作伪指令 1. MACRO/ENDM 宏定义伪指令 格式: 宏定义名 MACRO 〈形式参量表〉 MACRO与 ENDM成对出现 2. PURGE 取消宏定义 格式: PURGE 宏定义名 [,…… ] 3. LOCAL 形式参量表 宏定义体内允许使用标号 CHANGE MACRO AL中有一位 16进制数转换 ASCII
CMP AL, 10 JL ADD-0 ADD AL,’ A’-’0’-10 ADD AL, 0 ENDM 格式: LOCAL 形式参量表 必须是 MACRO后的第一个语句,其间不允许分号和注释
重复定义在宏汇编内是不允许的
错误重复定义
225
CHANGE MACRO LOCAL ADD-0
展开时为: + CMP AL, 10 + JL ?? 0000 + ADD AL, ’A’-’0’-10 + ?? 0000 ADD AL,’0’
+ CMP AL, 10 + JL ?? 0001 + ?? 0001 4.REPT/ENDM 重复块伪指令 格式: REPT 〈表达式〉 ENDM
插入
…
…
…
指令体(重复体)
226
重复执行指令体所包含的语句,重复次数为〈表达式〉值决定
如: 把 1-10 分配给十个连续的存储单元 X=0 REPT 10 X=X+1 DB X ENDM 5. IRP/ENDM 常参数重复块伪指令 格式: IRP 形式参量(参数表 ) 指令体 ENDM 重复次数由参数的个数所决定,每重复一次,用表中参数代 替形式参量 如: IRP X 〈 1 , 2, 3, 4, 5, 6, 7, 8, 9, 1
0〉 DB X ENDM 把 1-10 分配给 10个连续的存储单元
…
227
6. IRPC/ENDM 串重复块伪指令 格式: IRPC 形式参量,字符串(或〈字符串〉) ENDM 重复次数取决于字符串中字符的个数,且每次重复,依次把 字符串中的字符代替形式参量 如: 把 1-10 分配给 10个连续单元 IRPC X, 0123456789 DB X+1 ENDM (三)宏定义嵌套 可以嵌套在宏定义中利用宏调用(先定义) DIF MACRO N1 , N2 MOV AX, N1 SUB AX, N2 ENDM
…
指令体
228
DIFSQR MACRO N1 , N2 , RSULT PUSH DX PUSH AX DIF N1 , N2 IMUL AX MOV RESULT, AX POP AX POP DX ENDM 另外,宏定义还可以包含宏定义 DIFMALOT CACRO OPNA, OPRAT OPNA MACRO X, Y, Z PUSH AX MOV AX, X OPRAT Z, AX
229
POP AX ENDM ENDM 若有宏调用: DIFMALOT ADDITION, ADD 汇编展开为: ADDITION MACRO X, Y, Z PUSH AX MOV AX, X ADD Z, AX POP AX ENDM 同样,它可以用于定义算术与逻辑运算指令 (四)宏指令与子程序的区别 子程序:汇编后产生目标代码少,即目标程序占用的内
存 空间少,节约内存,但每次调用需要恢复保护, 恢复现场,执行时间长,速度慢。
230
宏指令:汇编时,把宏指令体插入到宏调用处,有多少次宏
调用,在目标产许需要同样多次的目标代码输入。 所以,宏指令目标程序长,占用内存多,但不需
要 保护断点,执行时间短,速度快。 (五)条件汇编 IF XX ARGUMENT ←条件 语句体 1 ELSE 任选 语句体 2 ENDIF IF 〈表达式〉≠ 0 为真 IFE 〈表达式〉 =0 为真 IF1 扫描第 1遍的过程中 为真 IF2 扫描第 2遍的过程中 为真
真
假
……
231
IFDEF 〈符号〉 指定符号被定义为真 IFNDET 〈符号〉 指定符号未被定义为真 INB 〈参量〉 空格 IFNB 〈参量〉 IFIDN 〈参量 1〉 〈参量 2〉 =2 为真 INDIF 〈参量 1〉 〈参量 2〉 ≠ 2 为真 (六)举例 P200. 例 3-36 64位加法 add64 macro n1,n2,buffer lea bx,n1 mov cx,4 clc again: mov ax,[bx] adc ax,[bx+8] mov [bx+10H],ax
232
inc bx inc bx loop again endm data add64 num1,num2,buffer ret
begin: push as mov ax,0 push ax mov ax,data mov ds,ax mov es,as add64 num1,num2,buffer 宏调用
……
…