3.4 mov、add、sub指令
前面我们用到了 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 寄存器,段寄存器”,从段寄存器向寄存器传送数据。一个合理的假设是:8086CPU内存有寄存器到段寄存器的通路,那么也应该有相反的通路。
有了推测,我们还要验证一下。进入Debug,用A命令,如图3.4所示。
图3.4中,用A指令在一个预设的地址0B39:0100处,用汇编的形式mov ax,ds 写入指令,再用T命令执行,可以看到执行的结果,段寄存器ds中的值送到了寄存器ax中。通过验证我们知道,“mov 寄存器,段寄存器”是正确的指令。
(2)既然有“mov 内存单元,寄存器”,从寄存器向内存单元传送数据,那么也应该有“mov 内存单元,段寄存器”,从段寄存器向内存单元传送数据。比如我们将段寄存器cs中的内容送入内存10000H处,指令如下。
mov ax,1000H
mov ds,ax
mov [0],cs
在Debug中进行试验,如图3.5所示。
3.5
图3.5中,当CS:IP指向0B39:0105的时候,Debug显示当前的指令mov [0000],cs,因为这是一条访问内存的指令,Debug还显示出指令要访问的内存单元中的内容。由于指令中的CS是一个16位寄存器,所以要访问(写入)的内存单元是一个字单元,它的偏移地址为0,段地址在ds中,Debug在屏幕右边显示“DS:0000=0000”,我们可以知道这个字单元中的内容为0。
mov [0000],cs 执行后,CS中的数据(0B39H)被写入1000:0处,1000:1单元存放0BH,1000:0单元存放39H。
最后,用D命令从1000:0开始查看指令执行后内存中的情况,注意1000:0、1000:1两个单元的内容。
(3)“mov 段寄存器,内存单元”也应该可行,比如我们可以用10000H处存放的字型数据设置ds(即将10000H处存放的字型数据送入ds),指令如下。
mov ax,1000H
mov ds,ax
mov ds,[0]
可以自行在Debug中进行试验。
add和sub指令同mov一样,都有两个操作对象。它们也可以有以下几种形式。
add 寄存器,数据 比如:add ax,8
add 寄存器,寄存器 比如:add ax,bx
add 寄存器,内存单元 比如:add ax,[0]
add 内存单元,寄存器 比如:add [0],ax
sub 寄存器,数据 比如:sub ax,8
sub 寄存器,寄存器 比如:sub ax,bx
sub 寄存器,内存单元 比如:sub ax,[0]
sub 内存单元,寄存器 比如:sub [0],ax
它们可以对段寄存器进行操作吗?比如“add as,ax”。请自行在Debug中是试验。
3.5 数据段
前面讲过(参见2.8节),对于8086PC机,在编程时,可以根据需要,将一组内存单元定义为一个段。我们可以将一组长度为N(N≤64KB)、地址连续,起始地址为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.5
写几条指令,累加数据段中的前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。
3.1~3.5小结
- 字在内存中存储时,要用两个地址连续的内存单元来存放,字的低位字节存放在低地址单元中,高位字节存放在高地址单元中。
- 用mov指令访问内存单元,可以在mov指令中只给出单元的偏移地址,此时,段地址默认在DS寄存器中。
- [address]表示一个偏移地址为address的内存单元。
- 在内存和寄存器之间传送字型数据时,高地址单元和高8位寄存器、地地址单元和低8位寄存器相对于。
- mov、add、sub是具有两个操作对象的指令。jmp是具有一个操作对象的指令。
- 可以根据自己的猜测,在Debug中实验指令的新格式。
检测点 3.1
一、在Debug中,用“d 0:0 1f”查看内存,结果如下。
0000:0000 70 80 F0 30 EF 60 30 E2-00 80 80 12 66 20 22 60
0000:0010 62 26 E6 D6 CC 2E 3C 3B-AB BA 00 00 26 06 66 88
下面的程序执行前,AX=0,BX=0,写出每条汇编指令执行完后相关寄存器中的值。
mov ax,1
mov ds,ax
mov ax,[0000] ;AX=________
mov bx,[0001] ;BX=________
mov ax,bx ;AX=________
mov ax,[0000] ;AX=________
mov bx,[0002] ;BX=________
add ax,bx ;AX=________
add ax,[0004] ;AX=________
mov ax,0 ;AX=________
mov al,[0002] ;AX=________
mov bx,0 ;BX=________
mov bl,[000C] ;BX=________
add al,bl ;AX=________
提示,注意ds的设置。
二、内存中的情况如下3.6所示。
各寄存器的初始值:CS=2000H,IP=0,DS=1000H,AX=0,BX=0;
①写出CPU执行的指令顺序(用汇编指令写出)。
②写出CPU执行每条指令后,CS、IP和相关寄存器中的数值。
③再次体会:数据和程序有区别吗?如何确定内存中的信息哪些是数据,哪些是程序?
没有通过检测点请不要向下学习!
做完后再看二楼的参考答案