汇编语言(三)--寄存器

第三章 寄存器

3.1 内存中字的存储

任何两个地址连续的内存单元,N号单元和 N+1号单元,可以将它们看成两个内存单元 ,也可以看成一个地址为N的字单元中的高位字节单元和低位字节单元。

3.2 DS和【address】

  1. CPU要读取一个内存单元时,必须先给出这个内存单元的地址

  2. 在8086PC中,内存地址由段地址和偏移地址组成

  3. 8086CPU中有一个DS寄存器,通常用来存放要访问的数据的段地址

mov al,[0]
已知的mov指令可完成的两种传送功能:

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

mov 指令 还可以将一个内存单元中的内容送入一个寄存器。

mov指令的格式

mov 寄存器名,内存单元地址

【……】表示一个内存单元,“【……】”中的0表示内存单元的偏移地址

那么内存单元的段地址是多少呢?

执行指令时,8086CPU自动取DS中的数据为内存单元的段地址。

如何用mov指令从10000H中读取数据?

  1. 10000H表示为1000:0(段地址:偏移地址)
  1. 将段地址1000H放入ds
  2. 用mov al,[0]完成传送(mov指令中的[]说明操作对象是一个内存单元,[]中的0说明这个内存单元的偏移地址是0,它的段地址默认放在ds中)

如何把1000H送入ds?

首先,类似于mov ds,1000H是非法的,8086CPU不支持将数据之间送入段寄存器的操作

一般是数据 ⟶ \longrightarrow 一般的寄存器 ⟶ \longrightarrow 段寄存器

怎样将数据从寄存器送入内存单元?

mov bx,1000H

mov ds,bx

mov 【0】,al

3.3 字的传送

因为8086CPU是16位结构,有16根数据线,所以可以一次性传16位的数据,也就是一次性传送一个字

3.4mov,add,sub指令

已学mov指令的几种形式:

mov 寄存器,数据
mov 寄存器,寄存器
mov 寄存器,内存单元
mov 内存单元,寄存器
mov 段寄存器,寄存器

根据已知指令进行推测:(未验证)

mov 段寄存器,寄存器 ⟶ \longrightarrow mov 寄存器,段寄存器

mov 内存单元,寄存器 ⟶ \longrightarrow mov 内存单元,段寄存器、mov 段寄存器,内存单元

add与sub指令

add 寄存器,数据

add 寄存器,寄存器

add 寄存器,内存单元

add 内存单元,寄存器

sub 寄存器,数据

sub 寄存器,寄存器

sub 寄存器,内存单元

sub 内存单元,寄存器

3.5 数据段

我们可以将一组长度为N(N≤64K)、地址连续、起始地址为16的倍数的内存单元当作专门存储数据的内存空间,从而定义了一个数据段。

如何访问数据段中的数据呢?

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

3.6 栈

我们研究栈的角度:

栈是一种具有特殊的访问方式的存储空间。它的特殊性就在于,最后进入这个空间的数据,最先出去。

栈的基本操作

出栈,入栈

又称为LIFO(last in first out)

3.7 CPU提供的栈机制

CPU有栈的设计,这意味着我们在使用8086CPU编程时可以将一段内存当做栈来使用

栈指令

push(入栈)

out(出栈)

CPU如何知道当前要执行的指令所在的位置?

寄存器CS和IP中存放着当前指令的段地址和偏移地址。
8086CPU中,有两个寄存器:

段寄存器SS  存放栈顶的段地址
寄存器SP  存放栈顶的偏移地址
任意时刻,SS:SP指向栈顶元素。

如果我们将10000H~1000FH 这段空间当作栈,初始状态栈是空的,此时,SS=1000H,SP=0010H

栈空时:SS:SP指向栈空间最高地址的下一个单元

执行push ax后:SS:SP指向栈中的第一个元素

pop指令的执行过程

pop ax

  1. 将SS:SP指向的内存单元处的数据送入ax中
  2. SP=SP+2,SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶

注意:

出栈后,SS:SP指向新的栈顶 1000EH,pop操作前的栈顶元素,1000CH 处的2266H 依然存在 ,但是,它已不在栈中。
当再次执行push等入栈指令后,SS:SP移至1000CH,并在里面写入新的数据,它将被覆盖。

3.8 栈顶超界问题

栈顶超界是危险的

因为我们既然将一段空间安排为栈 ,那么在栈空间之外的空间里很可能存放了具有其他用途的数据、代码等,这些数据、代码可能是我们自己的程序中的,也可能是别的程序中的。
8086CPU不保证对栈的操作不会超界

因为根据8086CPU工作机理,只考虑当前情况

当前栈顶在何处

当前要执行的指令是哪一条

3.9 push,pop指令

push寄存器:将一个寄存器中的数据入栈
pop寄存器:出栈,用一个寄存器接收出栈的数据

push ax

Pop bx

push段寄存器:将一个段寄存器中的数据入栈
pop段寄存器:出栈,用一个段寄存器接收出栈的数据

push ds

pop es

push内存单元:将一个内存单元处中的字入栈
pop内存单元:出栈,用一个内存字单元接收出栈的数据

push 【0】

pop【2】

指令执行时 ,CPU 要知道内存单元的地址,可以在 push、pop 指令中给出内存单元的偏移地址,段地址在指令执行时,CPU从ds中取得。

结论:

push、pop 实质上就是一种内存传送指令,可以在寄存器和内存之间传送数据,与mov指令不同的是,push和pop指令访问的内存单元的地址不是在指令中给出的,而是由SS:SP指出的。
同时,push和pop指令还要改变 SP 中的内容。

另外

push和pop指令同mov指令不同,CPU执行mov指令只需一步操作,就是传送,而执行push、pop指令却需要两步操作。
执行push时:先改变SP,后向SS:SP处传送。
执行pop时:先读取SS:SP处的数据,后改变SP。

3.10 栈段

我们可以将长度为 N(N ≤64K )的一组地址连续、起始地址为16的倍数的内存单元,当作栈来用,从而定义了一个栈段。

比如

比如我们将10010H~1001FH 这段长度为 16 字节的内存空间当作栈来用,以栈的方式进行访问。
这段空间就可以成为栈段,段地址为1000H,大小为16字节。

如何使的如push、pop 等栈操作指令访问我们定义的栈段呢?
将SS:SP指向我们定义的栈段。

一个栈段最大可以设为多少?

所以一个栈段的容量最大为64KB

3.11 段的综述

我们可以将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元。这完全是我们自己的安排。
我们可以用一个段存放数据,将它定义为“数据段”;
我们可以用一个段存放代码,将它定义为“代码段”;
我们可以用一个段当作栈,将它定义为“栈段”;

对于CPU来说

对于数据段,将它的段地址放在 DS中,用mov、add、sub等访问内存单元的指令时,CPU就将我们定义的数据段中的内容当作数据段来访问;

对于代码段,将它的段地址放在 CS中,将段中第一条指令的偏移地址放在IP中,这样CPU就将执行我们定义的代码段中的指令;

对于栈段,将它的段地址放在SS中,将栈顶单元的偏移地置放在 SP 中,这样CPU在需要进行栈操作的时候,比如执行 push、pop 指令等,就将我们定义的栈段当作栈空间来用。

可见,不管我们如何安排 ,CPU 将内存中的某段内存当作代码 ,是因为CS:IP指向了那里;CPU将某段内存当作栈 ,是因为 SS:IP 指向了那里。

一段内存,可以既是代码的存储空间,又是数据的存储空间,还可以是栈空间,也可以什么也不是。
关键在于CPU中寄存器的设置,即:CS、IP、SS、SP、DS的指向

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值