[汇编语言]寄存器(内部访问)


一、内存中字的访问

CPU中,用16位寄存器来存储一个字。高8位存放高位字节,低8位存放低位字节。在内存中存储,由于内存单元是字节单元(一个单元存放一个字节),则一个字要用两个地址连续的内存单元来存放,比如我们从0地址开始存放20000(4E20H),如图所示:
在这里插入图片描述
0、1两个内存单元用来存储一个字,这两个单元可以看作一个起始地址为0的字单元(存放一个字的内存单元,由0、1两字节单元构成)0号单元是低地址单元,1号单元是高地址单元,则字型数据4E20H的低位字节存放在0号单元中,高位字节存放在1号单元中。

我们提出字单元的概念:字单元,即存放一个字型数据(16位)的内存单元,由两个地址连续的内存单元组成。高地址存放字型数据的高位字节,低地址内存单元存放字型数据的低位字节。

之后我们将起始地址为N的字单元称为N地址字单元。比如一个字单元是由2、3两个内存单元构成,起始地址是2,我们说是2地址字单元。


二、DS和[address]

CPU中要读写一个内存单元的时候,必须先给出这个内存单元的地址,在8086PC中,内存单元的地址由段地址和偏移地址构成。8086CPU中有一个DS寄存器,通常用来存放要访问数据的段地址。比如我们要读取10000H单元中的内容,可以用如下程序段进行:

mov bx, 1000H
mov ds, bx
mov al, [0]

上面的3条指令将10000H(1000:0)的数据读到al中。

下面我们说明指令mov al, [0]的含义

前面我们使用mov指令,可以完成两种传送

  1. 将数据直接送入寄存器
  2. 将一个寄存器中的内容送入另外一个寄存器

也可以使用mov指令将一个内存单元中的内容送入另一个寄存器中。从哪一个内存单元送到哪一个寄存器中?在指令中必须指明。寄存器用寄存器名来指明,内存单元则需要用内存单元的地址来指明。显然,此时mov指令的格式应该是:mov 寄存器名,内存单元地址

[…]表示一个内存单元,[0]中的0表示内存单元的偏移地址,但是只有偏移地址是不能定位一个内存单元的,那么如何确认段地址?指令执行时,8086CPU自动取ds中的数据为内存单元的段地址。

再来看,10000H用段地址和偏移地址表示1000:0,我们先将段地址1000H放入ds,然后用mov al,[0]完成传送,mov指令中的[]说明操作对象是一个内存单元,[]中的0说明这个内存单元的偏移地址是0,它的段地址默认放在ds中,指令执行时,8086CPU会自动从ds中取出。

8086CPU不支持将数据直接送入段寄存器的操作,ds是一个段寄存器,所以mov ds,1000H这种指令是非法的。如何将1000H送入ds?只好用一个寄存器进行中转,如bx,再将bx中的内容送入ds

从内存单元到寄存器的格式是:mov 寄存器名,内存单元地址
从寄存器到内存单元则是:mov 内存单元地址,寄存器名

mov bx, 1000H
mov ds, bx
mov ax, [0]	;1000:0处的字型数据送入ax
mov [0], cx	;cs中16位数据送到1000:0

三、mov、add、sub指令

(a) 既然有mov 段寄存器, 寄存器,从寄存器向段寄存器传送数据,那么也应该有mov 寄存器, 段寄存器,从段寄存器向寄存器传送数据,有了推测,我们在debug下进行验证:
在这里插入图片描述
发现是正确的,所以mov 寄存器, 段寄存器是正确的指令

(b) 既然有mov 内存单元,寄存器,从寄存器向内存单元传送数据,那么也应该有mov 内存单元,段寄存器,从段寄存器向内存单元传送数据。我们可以将段寄存器cs中的内容送入内存10000H处。

mov ax, 1000H
mov ds, ax
mov [0], cs

在Debug中进行试验:

在这里插入图片描述
mov [0], cs执行后,cs中的内容写入1000:0内存单元中,如图:
在这里插入图片描述
高位字节是07H,低位字节是3FH


四、数据段

对于8086PC机,可以将一组内存单元定义为一个段,我们可以将一组长度为N(N<=64KB)、地址连续、起始地址为16倍数的内存单元专门当做存储数据的内存空间,从而就定义了一个数据段

如何访问数据段中的数据?将一段内存当做数据段,是我们的一种安排,在具体操作的时候,用ds存放数据段的段地址,在根据需要,用相关指令访问数据段中的具体单元

如,将123B0H ~ 123B9H的内存单元定义为数据段,现在要累加这个数据段中的前3个单元中的数据,代码如下:

mov ax, 123B
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, 123B
mov ds, ax	;ds存放数据段的段地址
mov ax, 0	;用ax存放累加结果
add ax, [0]
add ax, [2]
add ax, [4]

因为一个字型数据占两个单元,所以偏移地址是0、2、4


五、栈

栈是一个具有特殊访问方式的存储空间,特殊性在于,最后进入这个空间的数据,最先出去
8086CPU提供了入栈和出栈指令,最基本的两个是PUSH和POP,比如push ax是将寄存器ax中的数据送入栈中,pop ax表示从栈顶取出数据送入ax,8086CPU的入栈和出栈操作都是以字为单位进行的。

之前我们讨论过,CPU是如何知道当前要执行的指令所在的位置?是用CS:IP中存放着当前指令的段地址和偏移地址。现在如何知道栈顶的位置?显然也应该有相应的寄存器来存放栈顶的地址,在8086CPU中,有两个寄存器,段寄存器SS和寄存器SP,栈顶的段地址存放在SS中,偏移地址存放在SP中。任意时刻,SS:SP指向栈顶元素。push指令和pop指令执行时,CPU从SS:SP中得到栈顶的地址

push ax的执行由以下两步完成:

  1. SP = SP - 2,SS:SP指向的当前栈顶前面的单元,以当前栈顶前面的单元为新的栈顶
  2. 将ax中的内容送入SS:SP指向的内存单元处,SS:SP此时指向新的栈顶

在这里插入图片描述
可以看出,入栈时,栈顶从高地址向低地址方向增长。

那如果将10000H ~ 1000FH这段空间当作栈,初始状态栈是空的,此时SS = 1000H,SP = 多少?
SP = 0010H,如图:
在这里插入图片描述


六、栈顶越界的问题

8086CPU用SS和SP指示栈顶的地址,并提供push和pop指令实现入栈和出栈。SS和SP只记录了栈顶的地址,依靠SS和SP可以保证在入栈和出栈时找到栈顶,但是如果能够保证入栈和出栈时,栈顶不会超出栈空间?

8086CPU不保证我们对栈的操作不会越界,也就是说,只知道栈顶在何处(由SS:SP指示),但是并不知道要执行的指令有多少,因此,我们要自己小心栈顶越界的问题,要根据可能用到的最大栈空间,来安排栈的大小,防止入栈的数据太多而导致越界。


七、push、pop指令

前面我们使用的push ax,pop ax,显然push和pop指令是可以在寄存器和内存之间传送数据的。

push和pop指令的格式可以是如下几种形式:

push 寄存器
pop 寄存器

push 段寄存器
pop 段寄存器

push 内存单元
pop内存单元

比如:

mov ax, 1000H
mov ds, ax
push [0]
pop [2]

编程实现:

  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	;初始sp在最高地址的下一个单元

mov ax, 001AH
mov bx, 001BH

push ax
push bx

sub ax, ax		;将ax清零,也可以用mov ax,0
sub bx, bx		;sub ax, ax机器码两个字节,mov ax,0机器码3个字节

pop bx
pop ax

在这里插入图片描述

编程实现:

  1. 将10000H ~ 1000FH这段空间当作栈,初始状态栈为空
  2. 设置AX = 001AH, BX = 001BH
  3. 交换AX、BX的内容
mov ax, 1000H
mov ss, ax
mov sp, 0010H	;初始sp在最高地址的下一个单元

mov ax, 001AH
mov bx, 001BH

push ax
push bx

pop ax
pop bx

push ax是入栈指令,将在栈顶之上压入新的数据,执行过程是,先将SP-2,使得SS:SP指向新的栈顶单元,然后再将寄存器中的数据送入SS:SP指向新的栈顶单元

注意:push和pop等栈操作指令,修改的只是SP,也就是说栈顶变化范围最大为0 ~ FFFFH


八、栈段

对于8086PC机,在编程时,可以根据需要,将一组内存单元定义为一个段。我们可以将长度为N(N <= 64KB)的一组地址连续、起始地址为16的倍数的内存单元,当作栈空间来使用,从而定义了一个栈段。比如我们将10010H ~ 1001FH这段长度为16个字节的内存空间当作栈来用,以栈的方式来进行访问。这段空间就称为一个栈段,段地址为1001H,大小为16字节

一个栈段最大可以设为多少?
栈顶的变化范围是0 ~ FFFFH,从栈空的时候,SP = 0,一直压栈,压满后SP = 0,如果再次压栈,栈顶将环绕,覆盖原先栈中的内容,所以一个栈段容量最大为64KB

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值