mov ax,bx
1.汇编指令:机器码的助记符,有一一对应的机器码
2.伪指令:没有对应的机器码,有编译器执行,计算机不执行
3.其他符号:如+,-,*,/等,由编译器识别,没有的对应的机器码
如 内存中的二进制信息 1000100111011000 计算机可以看作大小为89D8H的数据,也可以看作指令mov ax,bx
1000100111011000 -> 89D8H
1000100111011000 ->mov ax,bx
1KB = 1024B, 1MB = 1024KB, 1GB = 1024MB, 1TB = 1024GB
在读写数据时指明哪种操作,读还是写
存储单元的地址(地址信息);
器件的选择,读会写的命令(控制信息);
读或写的数据(数据信息);
一根导线可以传送两种:高电平,低电平,二进制表示为1,0
如:10根地址总线
则为 210 = 1024 最小为0 最大为1023
一个CPU有N个地址总线->地址总线的宽度为N->寻址能力则为2N
CPU与内存或其他器件之间的数据传送是通过数据总线进行的.
数据总线的宽度决定了CPU和外界数据传递的速度.
读数据:
CPU通过地址总线将信息3发出.
CPU通过控制总线发出读取内存命令.
存储器将3号单元的数据8通过数据线送入CPU.
写数据
CPU通过地址总线将地址信息3发出.
CPU通过控制总线发出写入内存命令.
CPU通过数据总线将26送入内存的3号单元中.
命令计算机读写数据的汇编指令:
mov ax,[3]
N根的寻址能力为2N 一根地址总线寻址为21=2 10根地址总线就是210=1024byte=1KB 13根就是213=8KB 所以寻址能力为8KB的CPU,那么它的地址总线宽度为13根。
公式: 8 * 1024 = 2N = 23 * 210 = 2(3+10) => N = 13
1024个存储单元,从0开始
0 ~ 1024-1
=>0 ~ 1023
1KB = 1024多少个Byte * 1KB * 8bit = 8192bit = 1024Byte
1KB=1024Byte
1MB=1024 * 1024Byte
1GB=1024 * 1024 * 1024Byte
一个CPU有N根地址线,则可以说这个CPU的地址总线的宽度为N。这样的CPU最多可以寻找2的N次方个内存单元。(一个内存单元=1Byte)。
16根 216 = 64K
20根 220 = 1MB
24根 224 = 16MB
32根 232 = 4GB
8根数据总线一次可以传送8位二进制数据(即一个字节)。
80808bit = 1B
80888bit = 1B
808616bit = 2B
8028616bit = 2B
8038632bit = 4B
8086的数据总线宽度为16根 一次最多可传送16个bit数据, 1024字节有1024 * 8个bit数据,所以需要读 1024 * 8/16 = 512次
80386的数据总线宽度为32根 一次最多可传送32个bit数据, 1024字节有1024 * 8个bit数据,所以需要读 1024 * 8/32 = 256次
在存储器中指令和数据没有任何区别,都是二进制信息。
运算器进行信息处理;
寄存器进行信息存储;
控制器控制各种器件进行工作;
内部总线连接各种器件,在它们之前进行数据传送;
指令执行后AX中的数据是多少?
因为AX为16位寄存器,只能存放4位十六进制的数据,所以最高的位的1不能放在AX中保存,ax中的数据为:044CH
指令执行后AX中的数据为多少?
程序段中的最后一条指令 add al,93H ,执行前 al中的数据为C5H,相加所得的值为:158H,但是al为8位寄存器,只能存放两位十六进制的数据,所以最高为的1 丢失,ax中的数据为:0058H
注意:此时的al是作为一个独立的8位寄存器来使用,和ah没有关系,CPU在执行这条命令时认为ah和al是两个不相关的寄存器
如果执行add ax,93H,低8位的进位会存储在ah中,CPU在执行这条指令认为只有一个16位寄存器ax,进行的是16位运算.
在进行数据传送或者运算时,要注意指令的两个操作对象的位数应该是一致的 如
mov ax,bx
mov bx,cx
mov ax,18H
mov al,18H
add ax,bx
add ax,20000
错误的指令为
mov ax,bl ;在8位寄存器和16位寄存器中传送数据
mov bh,ax ;在16位寄存器和8位寄存器中传送数据
mov al,20000 ;8位寄存器最大可放的值为255的数据
add al.100H ;将一个高于8位的数据加到一个8位的寄存器中
mov ax,62627 AX=? ;转换为十六进制:F4A3H
mov ah,31H AX=? ;将高8位值覆盖:31A3H
mov al,23H AX=? ;将低8位值覆盖:3123H
add ax,ax AX=? ;值相加:6246H
mov bx,826CH BX=? ;赋值:826CH
mov cx,ax CX=? ;ax赋值给cx:6246H
mov ax,bx AX=? 826CH
add ax,bx AX=? 04D8H
mov al,bh AX=? 0482H
mov ah,bl AX=? 6C82H
add ah,ah AX=? D882H
add al,6 AX=? D888H
add al,al AX=? D810H
mov ax,cx AX=? 6246H
mov ax,2H AX=2
add ax,ax AX=4
add ax,ax AX=8
add ax,ax AX=16
(1)CPU中的相关部件提供两个16位的地址,一个称为段地址,另一个称为偏移地址;
(2)段地址和偏移地址通过内部总线送入一个称为地址加法器的部件;
(3)地址加法器将两个16位地址合成为一个20位的物理地址;
(4)地址加法器通过内部总线将20位物理地址送入输入输出控制电路;
(5)输入输出控制电路将20位物理地址送上地址总线;
(6)20位物理地址被地址总线传送到存储器。
“段地址X16+偏移地址=物理地址”的本质含义是:CPU在访问内存时,用一个基础 地址(段地址X16)和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址。
更一般地说,8086CPU的这种寻址功能是“基础地址+偏移地址=物理地址”寻址模式的一种具体实现方案。8086CPU中,段地址X16可看作是基础地址。
下面,我们用两个与CPU无关的例子做进一步的比喻说明。
第一个比喻说明“基础地址+偏移地址=物理地址”的思想。
比如说,学校、体育馆、图书馆同在一条笔直的单行路上(参考图2.8),学校位于路 的起点(从路的起点到学校距离是0米)。
你要去图书馆,问我那里的地址,我可以用两种方式告诉你图书馆的地址:
(1) 从学校走2826m到图书馆。这2826m可以认为是图书馆的物理地址。
(2) 从学校走2000m到体育馆,从体育馆再走826m到图书馆。第一个距离2000m, 是相对于起点的基础地址,第二个距离826m是相对于基础地址的偏移地址(以基础地址为 起点的地址)。
第一种方式是直接给出物理地址2826m,而第二种方式是用基础地址和偏移地址相加 来得到物理地址的。
第二个比喻进一步说明“段地址X16+偏移地址=物理地址”的思想。
我们为上面的例子加一些限制条件,比如,只能通过纸条来互相通信,你问我图书馆 的地址我只能将它写在纸上告诉你。显然,我必须有一张可以容纳4位数据的纸条,才能 写下2826这个数据。
可不巧的是,我没有能容纳4位数据的纸条,仅有两张可以容纳3位数据的纸条。这 样我只能以这种方式告诉你2826这个数据。
在第一张纸上写上200(段地址),在第二张纸上写上826(偏移地址)。假设我们事前对 这种情况又有过相关的约定:你得到这两张纸后,做这样的运算:200(段地址)*10+826(偏 移地址)=2826(物理地址)。
8086CPU就是这样一个只能提供两张3位数据纸条的CPU。
如图2.9所示,我们可以认为:地址10000H〜100FFH的内存单元组成一 个段,该段的起始地址(基础地址)为10000H,段地址为1000H,大小为100H;我们也可 以认为地址10000H〜1007FH、10080H〜100FFH的内存单元组成两个段,它们的起始地址 (基础地址)为:10000H和10080H,段地址为:1000H和1008H,大小都为80H。
结论:CPU可以用不同的段地址和偏移地址形成同一个物理地址。
结论:偏移地址16位,变化范围为O-FFFFH,仅用偏移地址来寻址最多可寻64KB个内存单元。
在8086PC机中,存储单元的地址用两个元素来描述,即段地址和偏移地址。
“数据在21F60H内存单元中。”这句话对于8086PC机一般不这样讲,取而代之的是两种类似的说 法:①数据存在内存2000:1F60单元中;②数据存在内存的2000H段中的1F60H单元中。这两种描述都 表示“数据在内存21F60H单元中”。
物理地址=SA16+EA
EA的变化范围为0H~FFFFH
物理地址范围为(SA16+0H)~(SA16+FFFFH)
=(0001H16+0H)~(0001H*16+FFFFH)
=0010H ~ FFFFH
物理地址=SA16+EA
20000h=SA16+EA
SA=(20000h-EA)/16=2000h-EA/16
EA取最大值时,SA=2000h-ffffh/16=1001h,SA为最小值
EA取最小值时,SA=2000h-0h/16=2000h,SA为最大值
地址:20000H-20002H,内容:B8 23 01,长度:3Byte,对应汇编指令:mov ax,0123H
地址: 20003H〜20005H,内容:BB03 00,长度:3Byte,对应汇编指令:movbx,0003H
地址:20006H〜20007H,内容:89 D8,长度:2Byte,对应汇编指令:mov ax,bx
地址:20008H〜20009H,内容:01 D8,长度:2Byte,对应汇编指令:add ax,bx
(1)从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器;
(2)IP=IP+所读取指令的长度,从而指向下一条指令;
(3)执行指令。转到步骤(1),重复这个过程。
CPU对图2.27中的指令的执行过程如下。
(1)当前 CS=2000H, IP=OOOOH,贝lj CPU 从内存 2000HX 16+0=20000H 处读取指 令,读入的指令是:B8 22 66(mov ax,6622H),读入后 IP=IP+3=OOO3H;
(2)指令执行后,CS=2000H , IP=OOO3H,贝 U CPU 从内存 2000H X 16+0003H=20003H处读取指令,读入的指令是:EA 03 00 00 10(jmp 1000:0003),读入后 IP=IP+5=0008H;
(3)指令执行后,CS=1000H , IP=0003H ,贝!I CPU 从内存 1000H X 16+0003H =10003H处读取指令,读入的指令是:B8 00 00(mov ax,0000),读入后IP=IP+3=0006H;
(4)指令执行后,CS=1000H, IP=0006H ,贝 U CPU 从内存 1000H X 16+0006H
=10006H处读取指令,读入的指令是:8B D8(mov bx,ax),读入后IP=IP+2=0008H;
(5)指令执行后,CS=1000H, IP=0008H,贝 lj CPU 从内存 1000H X 16+0008H
=10008H处读取指令,读入的指令是:FF E3(jmp bx),读入后IP=IP+2=000AH;
(6)指令执行后,CS=1000H, IP=0000H, CPU从内存10000H处读取指令
经分析后,可知指令执行序列为:
(1)mov ax,6622H
(2)jmp 1000:3
(3)mov ax,0000
(4)mov bx,ax
(5)jmp bx
(6)mov ax,0123H
(7)转到第3步执行
对于8086PC机,在编程时,可以根据需要,将一组内存单元定义为一个 段。
mov ax,0000 (B8 00 00)
add ax,0123H (05 32 01)
mov bx,ax (8B D8)
jmp bx (FF E3)
这段长度为10个字节的指令,存放在123B0H ~ 123B9H的一组内存单元中,可以认为,123B0H ~ 123B9H这段内存是用来存放代码的
如何使得代码段中的指令被执行呢?
CPU只认被CS:IP指向的内存单元中的内容为指令。
所以,要让CPU执行我们 放在代码段中的指令,必须要将CS:IP指向所定义的代码段中的第一条指令的首地址。
对 于上面的例子,我们将一段代码存放在123B0H〜123B9H内存单元中,将其定义为代码 段,如果要让这段代码得到执行,可设CS=123BH、IP=0000H
小 结
(1)段地址在8086CPU的段毒存器中存放。当8086CPU要访问内存时,由段寄存器提供内存单元的 段地址。8086CPU有4个段寄存器,其中CS用来存放指令的段地址。
(2)CS存放指令的段地址,IP存放指令的偏移地址。
8086机中,任意时刻,CPU将CS:IP指向的内容当作指令执行。
(3)8086CPU的工作过程:
①从CS: IP指向的内存单元读取指令,读取的指令进入指令缓冲器;
②IP指向下一条指令;
③执行指令。(转到步骤①,重复这个过程。)
(4)8086CPU提供转移指令修改CS、IP的内容。
mov ax,bx
sub ax,ax
jmp ax
一共修改四次
第一次:读取mov ax,bx之后
第二次:读取sub ax,ax之后
第三次:读取jmp ax之后
第四次:执行jmp ax修改IP
最后IP的值为0000H,因为最后ax中的值为0000H,所以IP中的值也为0000H
0地址单元中存放的字节型数据:20H;
(2)0地址字单元中存放的字型数据是多少?
0地址字单元中存放的字型数据:4E20H;
(3)2地址单元中存放的字节型数据是多少?
2地址单元中存放的字节型数据:12H;
(4)2地址字单元中存放的字型数据是多少?
2地址字单元中存放的字型数据:0012H;
(5)1地址字单元中存放的字型数据是多少?
1地址字单元,即起始地址为1的字单元,它由1号单元和2号单元组成,用这 两个单元存储一个字型数据,高位放在2号单元中,即:12H,低位放在1号单元中, 即:4EH,它们组成字型数据是124EH,大小为:4686。
从上面的问题中我们看到,任何两个地址连续的内存单元,N号单元和N+1号单 元,可以将它们看成两个内存单元,也可看成一个地址为N的字单元中的高位字节单元 和低位字节单元。
CPU要读写一个内存单元的时候,必须先给出这个内存单元的地址,在8086PC中, 内存地址由段地址和偏移地址组成。8086CPU中有一个DS寄存器,通常用来存放要访问 数据的段地址。比如我们要读取10000H单元的内容,可以用如下的程序段进行。
mov bx,1000H
mov ds,bx
mov al,[0]
上面的3条指令将10000H(1000:0)中的数据读到al中。
下面详细说明指令的含义。
mov al,[0]
前面我们使用mov指令,可完成两种传送:①将数据直接送入寄存器;②将一个寄 存器中的内容送入另一个寄存器。
也可以使用mov指令将一个内存单元中的内容送入一个寄存器中。从哪一个内存单 元送到哪一个寄存器中呢?在指令中必须指明。寄存器用寄存器名来指明,内存单元则需 用内存单元的地址来指明。显然,此时mov指令的格式应该是:mov寄存器名,内存单 元地址。
mov bx,1000H
mov ds,bx
若要用mov al,[0]完成数据从1000:0单元到al的传送,这条指令执行时,ds中的内容 应为段地址1000H,所以在这条指令之前应该将1000H送入ds
如何把一个数据送入寄存器中呢?
要有一个寄存器进行转存,将1000H放入一个一般的寄存器中,如bx,在将bx的内容送入ds
问题
写几条指令,将al中的数据送入内存单元10000H中,思考后看分析.
分析
怎么将数据从寄存器送入内存单元?
从内存单元到寄存器的格式
mov 寄存器名,内存单元地址
从寄存器到内存单元的格式
mov 内存单元地址,寄存器名
10000H可表示为1000H:0.用ds存放段地址1000H,偏移地址是0,则mov[0],al可完成从al到10000H的数据传送.
mov bx,1000H
mov ds,bx
mov [0],al
8086CPU是16位结构,一次性可以传送16位数据,一次性可以传递一个字
mov bx,1000H
mov ds,bx
mov ax,[0] ;1000:0处的字型数据送入ax
mov [0],cx ;cx中的16位数据送到1000:0处
问题
内存中的情况如图3.2所示,写出下面的指令执行后寄存器中ax,bx,cx中的值
问题
内存中的情况如图3.3所示,写出下面的指令执行后内存中的值,思考后看分析。
mov ax,1000H
mov ds,ax
mov ax,11316
mov [0],ax
mov bx,[0]
sub bx,[2]
mov [2],bx
mov、add、sub指令,它们都带有两个操作对象。
mov 寄存器,数据 比如:mov ax,8
mov 寄存器,寄存器 比如:mov ax,bx
mov 寄存器,内存单元 比如:mov ax,[0]
mov 内存单元,寄存器 比如:mov [0],ax
mov 段寄存器,寄存器 比如:mov ds,ax
(1)既然有“mov段寄存器,寄存器”,从寄存器向段寄存器传送数据,那么也应 该有“mov寄存器,段寄存器”,从段寄存器向寄存器传送数据。
(2)既然有“mov内存单元,寄存器”,从寄存器向内存单元传送数据,那么也应 该有“mov内存单元,段寄存器”,从段寄存器向内存单元传送数据。
(3) “mov段寄存器,内存单元”也应该可行,比如我们可以用10000H处存放的字 型数据设置ds(即将10000H处存放的字型数据送入ds)
mov ax,1000H
mov ds,ax
mov ds,[0]
add和sub指令同mov 一样
add寄存器,数据 比如:add ax,8
add寄存器,寄存器 比如:add ax,bx
add寄存器,内存单元 比如:add ax,[0]
add内存单元,寄存器 比如:add [0],ax
sub寄存器,数据 比如:sub ax,9
sub寄存器,寄存器 比如:subax,bx
sub寄存器,内存单元 比如:sub ax5[0]
sub内存单元,寄存器 比如:sub [0],ax
在编程时,可以根据需要,将一组内存单元 定义为一个段。我们可以将一组长度为N(NW64KB)、地址连续、起始地址为16的倍数 的内存单元当作专门存储数据的内存空间,从而定义了一个数据段。比如用123B0H〜 123B9H这段内存空间来存放数据,我们就可以认为,123B0H〜123B9H这段内存是一个 数据段,它的段地址为123BH,长度为10个字节。
如何访问数据段中的数据呢?将一段内存当作数据段,是我们在编程时的一种安排,可以在具体操作的时候,用ds存放数据段的段地址,再根据需要,用相关指令访问数据 段中的具体单元。
比如,将123B0H〜123B9H的内存单元定义为数据段。现在要累加这个数据段中的前 3个单元中的数据,代码如下。
mov ax,123BH
mov ds,ax ;将123BH送入ds中,作为数据段的段地址
mov al,0 ;用al存放累加结果
add al,[0] ;将数据段第一个单元(偏移地址为0)中的数值加到al中
add al,[1] ;将数据段第二个单元(偏移地址为1)中的数值加到al中
add al,[2] ;将数据段第三个单元(偏移地址为2)中的数值加到al中
问题
写几条指令,累加数据段中的前3个字型数据,思考后看分析。
分析:
代码如下。
mov ax,123BH
mov ds,ax ;将123BH送入ds中,作为数据段的段地址
mov ax,0 ;用ax存放累加结果
add ax,[0] ;将数据段第一个字(偏移地址为0)加到ax中
add ax,[2] ;将数据段第二个字(偏移地址为2)加到ax中
add ax,[4] ;将数据段第三个字(偏移地址为4)加到ax中
注意,一个字型数据占两个单元,所以偏移地址是0、2、4
小 结
1 字在内存中存储时,要用两个连续的内存单元存放,字的低位字节存放在低地址单元中,高位字节存放在高地址单元中
2 用mov指令访问内存单元,可以在mov指令中只给单元的偏移地址,此时,段地址默认在DS寄存器中
3 [address]表示一个偏移地址为address的内存单元
4 在内存和寄存器之间传送字型数据时,高地址单元和高位8位寄存器,低地址单元和低8位寄存器相对应
5 mov,add,sub是具有两个操作对象的指令,jmp是具有一个操作对象的指令
(1)内存中的情况如图3.6所示。
各寄存器的初始值:CS=2000H, IP=0, DS=1000H, AX=0, BX=0;
①写出CPU执行的指令序列(用汇编指令写出)。
②写出CPU执行每条指令后,CS、IP和相关寄存器中的数值。
mov ax,6622H CS=2000H IP=3H DS=0 AX=6622H BX=0
mov jmp 0ff0:0100 CS=0ff0H IP=100H DS=0 AX=6622H BX=0
mov ax,2000H CS=0ff0H IP=103H DS=0 AX=2000H BX=0
mov ds,ax CS=0ff0H IP=105H DS=2000 AX=2000H BX=0
mov ax,[0008] CS=0ff0H IP=108H DS=2000 AX=C389H BX=0
mov ax,[0002] CS=0ff0H IP=10BH DS=0 AX=EA66H BX=0
③再次体会:数据和程序有区别吗?如何确定内存中的信息哪些是数据,哪些是程序?
栈是一种具有特殊的访问方式的存储空 间。它的特殊性就在于,最后进入这个空间的数据,最先岀去。(后进先出)
栈有两个基本的操作:入栈和出 栈。入栈就是将一个新的元素放到栈顶,岀栈就是从栈顶取出一个元素。栈顶的元素总是 最后入栈,需要出栈时,又最先被从栈中取出。栈的这种操作规则被称为:LIFO(Last In First Out,后进先出)。
在基于8086CPU编程的时候,可以将一段内存当作栈 来使用。
8086CPU提供入栈和出栈指令,最基本的两个是PUSH(入栈)和POP(出栈)。比 如,push ax表示将寄存器ax中的数据送入栈中,pop ax表示从栈顶取出数据送入ax。 8086CPU的入栈和出栈操作都是以字为单位进行的。
下面举例说明,我们可以将10000H〜1000FH这段内存当作栈来使用
图3.9描述了下面一段指令的执行过程。
mov ax,0123H
push ax
mov bx,2266H
push bx
mov ex,1122H
push ex
pop ax
pop bx
pop ex
注意,字型数据用两个单元存放,高地址单元存放高8位,低地址单元存放低8位。
看到图3.9所描述的push和pop指令的执行过程,是否有一些疑惑?总结一下, 大概是这两个问题。
其一,我们将10000H〜1000FH这段内存当作栈来使用,CPU执行push和pop指令 时,将对这段空间按照栈的后进先出的规则进行访问。但是,一个重要的问题是,CPU 如何知道10000H〜1000FH这段空间被当作栈来使用?
其二,push ax等入栈指令执行时,要将寄存器中的内容放入当前栈顶单元的上方, 成为新的栈顶元素;pop ax等指令执行时,要从栈顶单元中取出数据,送入寄存器中。显 然,push、pop在执行的时候,必须知道哪个单元是栈顶单元,可是,如何知道呢?
行的时候,必须知道哪个单元是栈顶单元,可是,如何知道呢?
这不禁让我们想起另外一个问题,就是,CPU如何知道当前要执行的指令 所在的位置?我们现在知道答案,那就是CS、IP中存放着当前指令的段地址和偏移地 址。现在的问题是:CPU如何知道栈顶的位置?显然,也应该有相应的寄存器来存放栈 顶的地址,8086CPU中,有两个寄存器,段寄存器SS和寄存器SP,栈顶的段地址存放 在SS中,偏移地址存放在SP中。任意时刻,SS:SP指向栈顶元素。push指令和pop指 令执行时,CPU从SS和SP中得到栈顶的地址。
现在,可以完整地描述push和pop指令的功能了,例如push ax
push ax的执行,由以下两步完成。
(1)SP=SP-2, SS:SP指向当前栈顶前面的单元,以当前栈顶前面的单元为新的栈顶;
(2)将ax中的内容送入SS:SP指向的内存单元处,SS:SP此时指向新栈顶。
图3.10描述了 8086CPU对push指令的执行过程。
从图中可以看出,8086CPU中,入栈时,栈顶从高地址向低地址方向增长。
问题
如果将10000H〜1000FH这段空间当作栈,初始状态栈是空的, SP=?思考后看分析。
将10000H〜1000FH这段空间当作栈段,SS=1000H,栈空间大小为16字节,栈最底 部的字单元地址为1000:000E.任意时刻,SS:SP指向栈顶,当栈中只有一个元素的时 候,SS=1000H, SP=000EH。栈为空,就相当于栈中唯一的元素出栈,出栈后, SP=SP+2, SP原来为000EH,加2后SP=10H,所以,当栈为空的时候,SS=1000H, SP=10H.
换一个角度看,任意时刻,SS:SP指向栈顶元素,当栈为空的时候,栈中没有元素, 也就不存在栈顶元素,所以SS:SP只能指向栈的最底部单元下面的单元,该单元的偏移地 址为栈最底部的字单元的偏移地址+2,栈最底部字单元的地址为1000:000E,所以栈空 时,SP=0010H。
我们描述pop指令的功能,例如pop ax
pop ax的执行过程和push ax刚好相反,由以下两步完成。
(1)将SS:SP指向的内存单元处的数据送入ax中;
(2)SP=SP+2, SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的 栈顶。
图3.12描述了8086CPU对pop指令的执行过程
注意,图3.12中,出栈后,SS:SP指向新的栈顶1000EH, pop操作前的栈顶元素, 1000CH处的2266H依然存在,但是,它已不在栈中。当再次执行push等入栈指令后, SS:SP移至1000CH,并在里面写入新的数据,它将被覆盖。
8086CPU用SS和SP指示栈顶的地址,并提供push和pop指令实现 入栈和出栈。
是,有一个问题需要讨论,就是SS和SP只是记录了栈顶的地址,依靠SS和 SP可以保证在入栈和出栈时找到栈顶。可是,如何能够保证在入栈、出栈时,栈顶不会 超出栈空间?
图3.13描述了在执行push指令后,栈顶超出栈空间的情况。
图3.13中,将10010H〜1001FH当作栈空间,该栈空间容量为16字节(8字),初始状 态为空,SS=1000H、SP=0020H, SS:SP 指向 10020H;
在执行8次push ax后,向栈中压入8个字,栈满,SS:SP指向10010H;
再次执行push ax: sp=sp-2, SS:SP指向1000EH,栈顶超出了栈空间,ax中的数据 送入1000EH单元处,将栈空间外的数据覆盖。
图3.14描述了在执行pop指令后,栈顶超出栈空间的情况。
图3.14中,将10010H〜1001FH当作栈空间,该栈空间容量为16字节(8字),当前状 态为满,SS=1000H、SP=0010H, SS:SP 指向 10010H;
在执行8次pop ax后,从栈中弹出8个字,栈空,SS:SP指向10020H;
再次执行pop ax: sp=sp+2, SS:SP指向10022H,栈顶超出了栈空间。此后,如果再 执行push指令,10020H、10021H中的数据将被覆盖。
push 寄存器 ;将一个寄存器中的数据入栈
pop 寄存器 ;出栈,用一个寄存器接收出栈的数据
当然也可以是如下形式:
push 段寄存器 ;将一个段寄存器中的数据入栈
pop 段寄存器 ;出栈,用一个段寄存器接收出栈的数据
push和pop也可以在内存单元和内存单元之间传送数据,我们可以:
push 内存单元 ;将一个内存字单元处的字入栈(注意:栈操作都是以字为单位)
pop 内存单元 ;出栈,用一个内存字单元接收岀栈的数据
比如:
mov ax,1000H
mov ds,ax ;将1000:0处的字压入栈中
push [0] ;内存单元的段地址要放在ds中
pop [2] ;出栈,出栈的数据送入1000:2处
指令执行时,CPU要知道内存单元的地址,可以在push、pop指令中只给出内存单元 的偏移地址,段地址在指令执行时,CPU从ds中取得。
问题3.7
编程,将10000H〜1000FH这段空间当作栈,初始状态栈是空的,将AX、BX、DS 中的数据入栈。
mov ax,1000H
mov ss, ax ;设置栈的段地址,SS=1000H,不能直接向段寄存器SS中送入 ;数据,所以用ax中转。
mov sp,0010H ;设置栈顶的偏移地址,因栈为空,所以sp=0010H
;上面的3条指令设置栈顶地址。编程中要自己注意栈的大小。
push ax
push bx
push ds
问题3.8
编程:
(1)将10000H〜1000FH这段空间当作栈,初始状态栈是空的;
(2)设置 AX=001AH, BX=001BH;
(3)将AX、BX中的数据入栈;
(4)然后将AX、BX清零;
(5)从栈中恢复AX、BX原来的内容。
mov ax,1000H
mov ss,ax
mov sp,0010H ;初始化栈顶
mov ax,001AH
mov bx,001BH
push ax
push bx
sub ax,ax
sub bx,bx
pop bx ;从栈中恢复ax、bx原来的数据,当前栈顶的内容是bx
pop ax ;中原来的内容:001BH, ax中原来的内容001AH在栈顶
从上面的程序我们看到,用栈来暂存以后需要恢复的寄存器中的内容时,出栈的顺序 要和入栈的顺序相反,因为最后入栈的寄存器的内容在栈顶,所以在恢复时,要最先 出栈。
问题3.9
编程:
(1)将10000H〜1000FH这段空间当作栈,初始状态栈是空的;
(2)设置 AX=001AH, BX=001BH;
(3)利用栈,交换AX和BX中的数据。
mov ax,1000H
mov ss,ax
mov sp,0010H ;初始化栈顶
mov ax,001AH
mov bx,001BH
pop ax ;当前栈顶的数据是bx中原来的数据:001BH;
pop bx ;执行pop ax后,栈顶的数据为ax原来的数据;
问题3.10
如果要在10000H处写入字型数据2266H,可以用以下的代码完成:
mov ax,1000H
mov ds,ax
mov ax,2266H
mov [0],ax
补全下面的代码,使它能够完成同样的功能:在10000H处写入字型数据2266H 要求:不能使用“mov内存单元,寄存器”这类指令。
?______
?______
?______
mov ax,2266H
push ax
我们来看需补全代码的最后两条指令,将ax中的2266H压入栈中,也就是说,最终 应由push ax将2266H写入10000H处。问题的关键就在于:如何使push ax访问的内存单 元是 lOOOOHo
push ax是入栈指令,它将在栈顶之上压入新的数据。一定要注意:它的执行过程 是,先将记录栈顶偏移地址的SP寄存器中的内容减2,使得SS:SP指向新的栈顶单元,• 然后再将寄存器中的数据送入SS:SP指向的新的栈顶单元。
所以,要在执行push ax之前,将SS:SP指向10002H(可以设SS=1OOOH, SP=0002H),这样,在执行push ax的时候,CPU先将SP=SP-2,使得SS:SP指向 10000H,再将ax中的数据送入SS:SP指向的内存单元处,即10000H处。
完成的程序如下。
mov ax,1000H
mov ss,ax
mov sp, 2
mov ax,2266H
push ax
SS:SP
指出的。同时,push和pop指令还要改变SP中的内容。注意,push, pop等栈操作指令,修改的只是SP.也就是说,栈顶的变化范围最大为:
0〜FFFFH
。
1、8086CPU提供了栈操作机制,方案如下.
在SS、SP中存放栈顶的段地址和偏移地址;
提供入栈和出栈指令,他们根据SS:SP指示的地址,按照栈的方式访问内存单元;
2、push指令的执行步骤:①SP=SP-2;②向SS:SP指向的字单元传送数据
3、pop指令的执行步骤:①从SS:SP指向的字单元读取数据;②SP=SP+2
4、任何时刻SS:SP指向栈顶元素
5、8086CPU只记录栈顶,栈的空间大小要我们自己管理
6、用栈来暂存以后需要回复的寄存器的内容时,寄存器出栈的顺序要和入栈的顺序相反
7、push、pop实质上是一种内存传送指令,注意他们的灵活运用。
栈是一种非常重要的机制
我们可以将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元。这完全是 我们自己的安排。
我们可以用一个段存放数据,将它定义为“数据段”;
我们可以用一个段存放代码,将它定义为“代码段”;
我们可以用一个段当作栈,将它定义为“栈段”。
我们可以这样安排,但若要让CPU按照我们的安排来访问这些段,就要:
对于数据段,将它的段地址放在DS中,用mov、add、sub等访问内存单元的指令时,CPU就将我 们定义的数据段中的内容当作数据来访问;
对于代码段,将它的段地址放在CS中,将段中第一条指令的偏移地址放在IP中,这样CPU就将执 行我们定义的代码段中的指令;
对于栈段,将它的段地址放在SS中,将栈顶单元的偏移地址放在SP中,这样CPU在需要进行栈操 作的时候,比如执行push、pop指令等,就将我们定义的栈段当作栈空间来用。
可见,不管我们如何安排,CPU将内存中的某段内容当作代码,是因CS:IP指向了那里;CPU将某 段内存当作栈,是因为SS:SP指向了那里。我们一定要清楚,什么是我们的安排,以及如何让CPU按我 们的安排行事。要非常清楚CPU的工作机理,才能在控制CPU按照我们的安排运行的时候做到游刃 有余。
比如我们将10000H〜1001FH安排为代码段,并在里面存储如下代码:
mov ax,1000H
mov ss,ax
mov sp, 0020H ;初始化栈顶
mov ax,cs
mov ds,ax ;设置数据段段地址
mov ax,[0]
add ax,[2]
mov bx,[4]
add bx,[6]
push ax
push bx
pop ax
pop bx
设置CS=1000H , IP=0,这段代码将得到执行。可以看到,在这段代码中,我们又将 10000H〜1001FH安排为栈段和数据段。10000H〜1001FH这段内存,既是代码段,又是栈段和数据段。
一段内存,可以既是代码的存储空间,又是数据的存储空间,还可以是栈空间,也可以什么也不 是。关键在于CPU中寄存器的设置,即CS、IP, SS、SP, DS的指向。
mov ax,1000H
mov ds,ax
________
________
________
push [0]
push [2]
push [4]
push [6]
push [8]
push [a]
push [c]
push [e]
(2)补全下面的程序,使其可以将10000H〜1000FH中的8个字,逆序复制到 20000H〜2000FH 中。
mov ax,2000H
mov ds,ax
________
________
________
push [e]
push [c]
push [a]
push [8]
push [6]
push [4]
push [2]
push [0]
[bx]和[0]有些类似,[0]表示内存单元,它的偏移地址是0。比如在下面的指令中:
mov ax,[0]
将一个内存单元的内容送入ax,这个内存单元的长度为2字节(字单元),存放一个 字,偏移地址为0,段地址在ds中。
mov al,[0]
将一个内存单元的内容送入al,这个内存单元的长度为1字节(字节单元),存放一个 字节,偏移地址为0,段地址在ds中。
要完整地描述一个内存单元,需要两种信息:①内存单元的地址;②内存单元的长度 (类型)。
用[0]表示一个内存单元时,0表示单元的偏移地址,段地址默认在ds中,单元的长 度(类型)可以由具体指令中的其他操作对象(比如说寄存器)指出。
[bx]同样也表示一个内存单元,它的偏移地址在bx中,比如下面的指令:
mov ax,[bx]
将一个内存单元的内容送入ax,这个内存单元的长度为2字节(字单元),存放一个 字,偏移地址在bx中,段地址在ds中。
mov al,[bx]
将一个内存单元的内容送入al,这个内存单元的长度为1字节(字节单元),存放一个 字节,偏移地址在bx中,段地址在ds中。
英文单词“loop”有循环的含义,显然这个指令和循环有关。
我们在这一章,讲解[bx]和loop指令的应用、意义和相关的内容。
为了描述上的简洁,在以后的课程中,我们将使用一个描述性的符号“()”来表示一 个寄存器或一个内存单元中的内容。比如:
(ax)表示ax中的内容、(al)表示al中的内容;
(20000H)表示内存20000H单元的内容(()中的内存单元的地址为物理地址);
((ds)* 16+(bx))表示:
ds中的内容为ADRI, bx中的内容为ADR2,内存ADRI X 16+ADR2单元的内容。
也可以理解为:ds中的ADR1作为段地址,bx中的ADR2作为偏移地址,内存 ADR1:ADR2单元的内容。
注意,“(尸中的元素可以有3种类型:①寄存器名;②段寄存器名;③内存单元的 物理地址(一个20位数据)。比如:
(ax)、(ds)、(al)、(ex)、(20000H)、((ds)*16+(bx))等是正确的用法;
(2000:0)、((ds): 1000H)等是不正确的用法。
我们看一下(X)的应用,比如
(1)ax中的内容为0010H,可以这样来描述:(ax)=0010H;
(2)2000:1000处的内容为0010H,可以这样来描述:(21000H)=0010H;
(3)对于mov ax,[2]的功能,可以这样来描述:(ax)=((ds)*16+2);
(4)对于mov(2),ax的功能,可以这样来描述:((ds)*16+2)=(ax);
.(5)对于add ax,2的功能,可以这样来描述:(ax)=(ax)+2;
(6)对于add ax,bx的功能,可以这样来描述:(ax)=(ax)+(bx);
(7)对于push ax的功能,可以这样来描述:
(sp)=(sp)-2
((ss)164-(sp))=(ax)
(8)对于pop ax的功能,可以这样来描述:
(ax)=((ss) 16+(sp))
(sp)=(sp)+2
"(X)”所表示的数据有两种类型:①字节;②字。是哪种类型由寄存器名或具体的 运算决定,比如:
(al)、(bl)、(cl)等得到的数据为字节型;(ds)、(ax)、(bx)等得到的数据为字型。
(al)=(20000H),贝iJ(20000H)得到的数据为字节型;(ax)=(20000H),则(20000H)得到的 数据为字型。
用idata表示常 量。比如:
mov ax,[idata]就代表 movax,[l]、mov ax,[2]> mov ax,[3]等。
mov bx,idata 就代表 mov bx,l > mov bx,2> mov bx,3 等。
mov ds,idata就代表movds,l、mov ds,2等,它们都是非法指令。
看一看下面指令的功能。
mov ax,[bx]
功能:bx中存放的数据作为一个偏移地址EA,段地址SA默认在ds中,将SA:EA 处的数据送入ax中。即:(ax)=((ds)*16+(bx))。
mov [bx],ax
功能:bx中存放的数据作为一个偏移地址EA,段地址SA默认在ds中,将ax中的 数据送入内存SA:EA处。即:((ds)*16+(bx))=(ax)。
程序和内存中的情况如图5.1所示,写出程序执行后,21000H〜21007H单元中的内存中的情况
(1)先看一下程序的前3条指令:
mov ax,2000H
mov ds,ax
mov bx,1000H
这3条指令执行后,ds=2000H, bx=1000H
(2)接下来,第4条指令:
mov ax,[bx]
指令执行前:ds=2000H, bx=1000H,则mov ax,[bx]将把内存2000:1000处的字型数 据送入ax中。该指令执行后,ax=00beHo
(3)接下来,第5、6条指令:
inc bx
inc bx
这两条指令执行前bx=1000H,执行后bx=1002H
(4)接下来,第7条指令:
mov [bx],ax
指令执行前:ds=2000H, bx=1002H,贝U mov [bx],ax将把ax中的数据送入内存 2000:1002处。指令执行后,2000:1002单元的内容为BE, 2000:1003单元的内容为00。
(5)接下来,第8、9条指令:
inc bx
inc bx
这两条指令执行前bx=1002H,执行后bx=1004Ho
(6)接下来,第10条指令:
mov [bx],ax
指令执行前:ds=2000H, bx=1004H,则mov [bx],ax将把ax中的数据送入内存 2000:1004处。指令执行后,2000:1004单元的内容为BE, 2000:1005单元的内容为00。
(7)接下来,第11条指令:
inc bx
这条指令执行前bx=1004H,执行后bx=1005Ho
(8)接下来,第12条指令:
mov [bx],al
指令执行前:ds=2000H, bx=1005H,贝U mov [bx],al将把al中的数据送入内存 2000:1005处。指令执行后,2000:1005单元的内容为BE。
(9)接下来,第13条指令:
inc bx
这条指令执行前bx=1005H,执行后bx=1006H
(10)接下来,第14条指令:
mov [bx],al
指令执行前:ds=2000H, bx=1006H,则 mov [bx],al 将把 al 中的数据送入内存2000:1006处。指令执行后,2000:1006单元的内容为BE。
程序执行后,内存中的情况如图5.2所示。
loop指令的格式是:loop标号,CPU执行loop指令的时候,要进行两步操作, ①(cx)=(cx)-1;②判断CX中的值,不为零则转至标号处执行程序,如果为零则向下 执行。
CX中的值影响着loop指令的执行结果。通常(注意,我 们说的是通常)我们用loop指令来实现循环功能,CX中存放循环次数。
计算22,结果存在ax中。
设(ax)=2,可计算(ax)=(ax) * 2,最后(ax为22的值。N*2可用N+N实现, 程序如下。
assume cs:code
code segment
mov ax,2
add ax,ax
mov ax,4c00h
int 21h
code ends
end
计算211
assume cs:code
code segment
mov ax,2
mov cx,11
s : add ax,ax
loop s
mov ax,4c00h
int 21h
code ends
end
(1)标号
在汇编语言中,标号代表一个地址,程序5.1中有一个标号S.它实际上标识了一个 地址,这个地址处有一条指令:add ax,ax
(2)loop s
CPU执行loop s的时候,要进行两步操作:
①(cx)=(cx)-1;
②判断cx中的值,不为0则转至标号s所标识的地址处执行(这里的指令是add ax,ax
),如果为零则执行下一•条指令(下一条指令是mov ax,4c00h
).
(3)以下3条指令
mov cx,11
s : add ax,ax
loop s
执行loop s时,首先要将(cx)减1,然后若(cx)不为0,则向前转至s处执行add ax,ax
。所 以,可以利用cx来控制add ax,ax
的执行次数。
下面我们详细分析一下这段程序的执行过程,从中体会如何用cx和loop s相配合实 现循环功能。
(1)执行 mov cx,11
,设置(cx)=11 ;
(2)执行 add ax,ax
(第 1 次);
(3)执行loop s将(cx)减1, (cx)=10, (cx)不为0,所以转至s处;
(4)执行 add ax,ax
(第 2 次);
(5)执行 loop s 将(cx)减 1, (cx)=9, (cx)不为0,所以转至s处;
…
(22)执行 add ax,ax
(第 11 次);
(23)执行 loops 将(cx)减 1, (cx)=0,(cx)为0,所以向下执行。(结束循环)
从上面的过程中,我们可以总结出用CX和loop指令相配合实现循环功能的3个 要点:
(1)在CX中存放循环次数;
(2)loop指令中的标号所标识地址要在前面;
(3)要循环执行的程序段,要写在标号和loop指令的中间。
用CX和loop指令相配合实现循环功能的程序框架如下。
mov cx,循环次数
循环执行的程序段
loop s
考虑这样一个问题,计算ffff:0〜ffff:b单元中的数据的和,结果存储在dx中。
(1)运算后的结果是否会超出dx所能存储的范围?
ffff:0〜ffff:b内存单元中的数据是字节型数据,范围在0〜255之间,12个这样的数据 相加,结果不会大于65535,可以在dx中存放下。
(2)我们能否将ffff:0〜ffff:b中的数据直接累加到dx中?
不行,因为ffff:0〜ffff:b中的数据是8位的,不能直接加到16位寄存器dx中。
(3)我们能否将ffff:0〜ffff:b中的数据累加到dl中,并设置(dh)=0,从而实现累加到 dx中?
不行,因为dl是8位寄存器,能容纳的数据的范围在0〜255之间,ffff:O~ffff:b 中的数据也都是8位,如果仅向dl中累加12个8位数据,很有可能造成进位丢失。
(4)我们到底怎样将ffff:O〜ffff:b中的8位数据,累加到16位寄存器dx中?
从上面的分析中,可以看到,这里面有两个问题:类型的匹配和结果的不超界。具体 的说,就是在做加法的时候,我们有两种方法:
①(dx)=(dx)+内存中的8位数据;
②(dl)=(dl)+内存中的8位数据。
第一种方法中的问题是两个运算对象的类型不匹配,第二种方法中的问题是结果有可 能超界。
方法
用一个16位寄存器来做中介。将内存单元中的8位数据赋值到一个16位寄存器ax 中,再将ax中的数据加到dx,从而使两个运算对象的类型匹配并且结果不会超界。
想清楚以上的问题之后,编写程序如下。
程序5.5
assume cs:code
code segment
mov ax,Offffh
mov ds,ax ;设置(ds) =ffffh
mov dx,0 ;初始化累加寄存器,(dx)=0
mov al,ds:[0]
mov ah,0 ;(ax)=((ds)*16+0)=(ffff0h)
add dx,ax ;向dx中加上ffff: 0单元的数值
mov al,ds:[1]
mov ah,0 ;(ax)=((ds)*16+l)=(fffflh)
add dx,ax ;向dx中加上ffff: 1单元的数值
mov al,ds:[2]
mov ah,0 ;(ax)=((ds)*16+2)=(ffff2h)
add dx,ax ;向dx中加上ffff: 2单元的数值
mov al,ds:[3]
mov ah,0 ;(ax)=((ds)*16+3)=(ffff3h)
add dx,ax ;向dx中加上ffff: 3单元的数值
mov al,ds:[4]
mov ah,0 ;(ax)=((ds)*16+4)=(ffff4h)
add dx,ax ;向dx中加上ffff: 4单元的数值
mov al,ds:[5]
mov ah,0 ;(ax)=((ds)*16+5)=(ffff5h)
add dx,ax ;向dx中加上ffff :5单元的数值
mov al,ds:[6]
mov ah,0 ;(ax)=((ds)*16+6)=(ffff6h)
add dx,ax ;向dx中加上ffff :6单元的数值
mov al,ds:[7]
mov ah,0 ;(ax)=((ds)*16+7)=(ffff7h)
add dx,ax ;向dx中加上ffff: 7单元的数值
mov al,ds:[8]
mov ah,0 ;(ax)=((ds)*16+8)=(ffff8h)
add dx,ax ;向dx中加上ffff :8单元的数值
mov al,ds:[9]
mov ah,0 ;(ax)=((ds)*16+9)=(ffff9h)
add dx,ax ;向dx中加上ffff: 9单元的数值
mov al,ds:[Oah]
mov ah,0 ;(ax) = ( (ds) *16+0ah) = (ffffah)
add dx,ax ;向dx中加上ffff :a单元的数值
mov al,ds:[Obh]
mov ah,0 ;(ax)=((ds)*16+0bh)=(ffffbh)
add dx,ax ;向dx中加上ffff:b单元的数值
mov ax,4c00h ;程序返回
int 21h
code ends
end
应用loop指令,改进程序5.5
mov al,ds:[X] ;ds :X指向f f f f: X单元
mov ah,0 ;(ax)=((ds)*16+(X))=(ffffXh)
add dx,ax ;向dx中加上ffff :X单元的数值
可以看到,12个相似的程序段中,只有moval,ds:[X]指令中的内存单元的偏移地 址是不同的,其他都一样。而这些不同的偏移地址是在0<=X<=bH的范围内递增变化的。
assume cs:code code segment
mov ax,0ffffH
mov ds,ax
mov bx,0
mov dx,0
mov cx,12
s:
mov al,[bx]
mov ah,0
add dx,ax
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end
指令“mov ax,[bx]”中,内存单元的偏移地址由bx给出,而段地址默认在ds中。我 们可以在访问内存单元的指令中显式地给出内存单元的段地址所在的段寄存器。比如:
(1)mov ax,ds:[bx]
将一个内存单元的内容送入ax,这个内存单元的长度为 2字节(字单元),存放一个字,偏移地址在bx中,段地址在ds中。
(2)mov ax,cs:[bx]
将一个内存单元的内容送入ax,这个内存单元的长度为 2字节(字单元),存放一个字,偏移地址在bx中,段地址在cs中。
(3)mov ax,ss:[bx]
将一个内存单元的内容送入ax,这个内存单元的长度为 2字节(字单元),存放一个字,偏移地址在bx中,段地址在ss中。
(4)mov ax,es:[bx]
将一个内存单元的内容送入ax,这个内存单元的长度为 2字节(字单元),存放一个字,偏移地址在bx中,段地址在es中。
(5)mov ax,ss:[0]
将一个内存单元的内容送入ax,这个内存单元的长度为 2字节(字单元),存放一个字,偏移地址为0,段地址在ss中。
(6)mov ax,cs:[0]
将一个内存单元的内容送入ax,这个内存单元的长度为 2字节(字单元),存放一个字,偏移地址为0,段地址在cs中。
这些出现在访问内存单元的指令中,用于显式地指明内存单元的段地址的 “ds:” “cs:” “ss:” “es:” ,在汇编语言中称为段前缀。
在8086模式中,随意向一段内存空间写入内容是很危险的,因为这段空间中可能存 放着重要的系统数据或代码。比如下面的指令:
mov ax,1000h
mov ds,ax
mov al,0
mov ds:[0],al
这种做法是不合理 的,因为之前我们并没有论证过1000:0中是否存放着重要的系统数据或代码。如果 1000:0中存放着重要的系统数据或代码,“mov ds:[0],al
”将其改写,将引发错误。
(1)我们需要直接向一段内存中写入内容;
(2)这段内存空间不应存放系统或其他程序的数据或代码,否则写入操作很可能引发 错误;
(3)DOS方式下,一般情况,0:200〜0:2ff空间中没有系统或其他程序的数据或 代码;
(4)以后,我们需要直接向一段内存中写入内容时,就使用0:200〜0:2ff这段空间。
首先,介绍两条指令and和or,因为我们下面的例程中要用到它们。
(1)and指令:逻辑与指令,按位进行与运算。
例如指令:
mov al,01100011B
and al,00111011B
执行后:al = 00100011B
通过该指令可将操作对象的相应位设为0,其他位不变。
例如:
将al的第6位设为0的指令是:and al,10111111B
将al的第7位设为0的指令是:and al,01111111B
将al的第0位设为0的指令是:and al,11111110B
(2)or指令:逻辑或指令,按位进行或运算。
例如指令:
mov al,01100011B
or al,00111011B
执行后:al = 01111011B
通过该指令可将操作对象的相应位设为1,其他位不变。
例如:
将al的第6位设为1的指令是:or al,01000000B
将al的第7位设为1的指令是:or al,10000000B
将al的第0位设为1的指令是:or al,00000001B