(2)寄存器(内存访问)

1.1 内存中字的存储

注:如果对于计算机系统而言,字大小也就是所谓的字长是表征计算机系统处理问题的能力,通常等于cpu总线或者寄存器的宽度,即现代计算的32位或者64位;在windows下编程,而且使用的微软的msvc编译环境,微软定义的WORD本质为unsigned short类型,只是一个别名;如果在汇编语言里面,一个字大小确实等于2个字节大小,DW则为数据定义伪指令,定义为一个字大小。
————————————————

BYTE(字节) 1字节
WORD(字) 2字节
DWORD(双字) 4字节
QWORD(四字)8字节
TBYTE(十字节)10字节

CPU中,用 16 位寄存器来存储一个字。高 8 位存放高位字节,低 8 位存放低位字节。
在内存中存储时,由于内存单元是字节单元(一个单元存放一个字节),则一个字要用两个地址连续的内存单元来存放,这个字的低位字节存放在低地址单元中,高位字节存放在高地址单元中。

字单元:存放一个字型数据(16位)的内存单元,由两个地址连续的内存单元组成。高地址内存单元中存放字型数据的高位字节,低地址内存单元中存放字型数据的低位字节
我们将起始地址为N的字单元简称为N地址字单元。

例:从0地址开始存放20000(4E20H):

0、1 两个内存单元用来存储一个字,这两个单元可以看作一个起始地址为 0 的字单元(存放一个字的内存单
元,由 0、1 两个字节单元组成)。对于这个字单元来说,0 号单元是低地址单元,1 号单元是高地址单元,则字型数据 4E20H 的低位字节存放在 0 号单元中,高位字节存放在 1号单元中。

在这里插入图片描述
(1)0地址单元中存放的字节型数据是多少? 20H
(2)0地址字单元中存放的字型数据是多少? 4E20H
(3)2 地址单元中存放的字节型数据是多少? 12H
(4)2 地址字单元中存放的字型数据是多少? 0012H
(5)1 地址字单元中存放的字型数据是多少? 124EH 大小:4686

1.2 DS和[address]

cs(code segment)是代码段寄存器,放代码段的段地址他里面的内容和ip里面的内容和起来就可以找到当前执行的指令,
ds(datasegment)是数据段段寄存器 放数据段的段地址,根据段地址*16d+偏移量就可以得到物理地址

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

mov指令的传送:
(1)将数据直接送入寄存器
(2)将一个寄存器中的内容送入另一个寄存器
(3)将一个内存单元中的内容送入一个寄存器中

将一个内存单元中的内容送入一个寄存器中:寄存器用寄存器名来指明,内存单元则需用内存单元的地址来指明
格式:mov 寄存器名 ,内存单元地址

例:要读取10000H单元的内容:
mov bx, 1000H
mov ds, bx
mov al, [0]

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

1> "【…】“表示一个内存单元,”【…】"中的 0表示内存单元的偏移地址。
只有偏移地址是不能定位一个内存单元的,那么内存单元的段地址是多少呢?指令执行时,8086CPU 自动取 ds 中的数据为内存单元的段地址。

2> 在mov al,[0] 之前要将1000H送入ds
但8086CPU不支持将数据直接送入段寄存器的操作,只能用一个一般的寄存器(ax/bx)进行中转

习题:
写几条指令,将 al中的数据送入内存单元 10000H中
指令:
mov bx,1000H
mov ds,bx
mov [0],al

小结:
从内存单元到寄存器的格式是;“mov 寄存器名,内存单元地址”,
从寄存器到内存单元则是∶"mov 内存单元地址,寄存器名"。

1.3 字的传送

前面我们用 mov 指令在寄存器和内存之间进行字节型数据的传送。
因为 8086CPU 是 16 位结构,有 16 根数据线,所以,可以一次性传送 16 位的数据,也就是说可以一次性传送一个字。只要在 mov 指令中给出 16 位的寄存器就可以进行 16 位数据的传送了。

注:给出16位的寄存器就是给出ax/bx,然后对接字单元 (就是所说的:字的传送)

例:

在这里插入图片描述
在这里插入图片描述
细节:执行指令时,字型数据的高8位送入ah,字型数据的低8位送入al

1.4 mov、add、sub指令

mov指令的形式:

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

add 寄存器,数据
add 寄存器,寄存器
add 寄存器,内存单元
add 内存单元,寄存器

sub 寄存器,数据
sub 寄存器,寄存器
sub 寄存器,内存单元
sub 内存单元,寄存器

1.5 数据段

对于 8086PC机,在编程时,可以根据需要,将一组内存单元定义为一个段。我们可以将一组长度为 N(N≤64KB)、地址连续、起始地址为 16 的倍数的内存单元当作专门存储数据的内存空间,从而定义了一个数据段
比如用 123BOH~ 123B9H 这段内存空间来存放数据,我们就可以认为,123BOH~123B9H 这段内存是一个数据段,它的段地址为 123BH,长度为 10个字节。

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

在这里插入图片描述
在这里插入图片描述
注:add al [0] 字型加 //第一个内存单元[0]
add ax [0] 字加 //第一个字[0]和[1]

小结:
在这里插入图片描述
在这里插入图片描述
例:
在这里插入图片描述
各寄存器的初始值:CS = 2000H , IP = 0 , DS = 1000H , BX = 0;、

②写出CPU执行每条指令之后,CS、IP和相关寄存器的数值。

                           CS      IP     DS     AX     BX
初始                       2000H	   0	1000H    0	    0
mov ax,6622H              2000H	 0003H	1000H	6622H	0
jmp 0ff0:0100             1000H	   0	1000H	6622H	0
mov ax,2000H              1000H	 0003H	1000H	2000H	0  
mov ds,ax                 1000H	 0005H	2000H	2000H	0
mov ax,[0008]             1000H	 0008H	2000H	C389H	0
mov ax,[0002]             1000H	 000BH	2000H	EA66H	0

③再次体会:数据和程序有区别吗?如何确定内存中信息哪些是数据,哪些是程序?
数据和程序在内存中都是以二进制的形式存放的,数据之所以区别于程序,是根据它们所在的段(数据段或代码段)来区分的。

注:在8086cpu环境下,一个地址和一个内存单元就对应着一个B,代码段指的是长度为小于64kb的、地址连续、起始地址为16(十进制)的倍数的内存单元当作专门存放代码的,数据段指的是长度小于64kb的、地址连续、起始地址为16(十进制)的倍数的内存单元当作专门存储数据的内存空间。

1.6 栈

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

1.7 CPU提供的栈机制

8086CPU提供了相关的指令来以栈的方式访问内存空间。在基于8086CPU编程的时候,可以将一段内存当作栈来使用。

8086CPU的入栈和出栈操作都是以字为单位进行的。

8086CPU中,有两个寄存器,段寄存器SS和寄存器SP,栈顶的段地址存放在SS中,偏移地址存放在SP中。任意时刻,SS:SP指向栈顶元素。push指令和pop指令执行时,CPU可以从SS和SP中得到栈顶的地址。

push执行过程:在这里插入图片描述
看出:8086CPU中,入栈时,栈顶从高地址向低地址方向增长。

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

在这里插入图片描述

总结:

push ax 执行过程:
(1)SP=SP-2,SS∶SP指向当前栈顶前面的单元,以当前栈顶前面的单元为新的栈顶;
(2)将 ax 中的内容送入 SS∶SP指向的内存单元处,SS∶SP此时指向新栈顶。
pop ax 执行过程:
(1)将 SS∶SP指向的内存单元处的数据送入 ax 中;

(2)SP=SP+2,SS∶SP 指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶。

注:在这里插入图片描述

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

1.8 栈顶超界的问题

当栈满的时候再使用push指令入栈,或栈空的时候再使用pop指令出栈,都将发生栈顶超界的问题。

我们希望在CPU中有记录栈顶上限和栈底的寄存器,我们可以通过填写这些寄存器来指定栈空间的范围,然后,CPU
在执行push指令的时候靠检测栈顶上限寄存器、在执行pop指令的时候靠检测栈底寄存器保证不会超界。

8086没有这样的寄存器。8086CPU不保证我们对栈的操作不会超界,它只考虑当前的栈顶在何处、当前要执行的指令是哪一条。

我们要自己操心栈顶超界的问题,根据可能用到的最大栈空间,来安排栈的大小。
防止入栈的数据太多而导致的超界;执行出栈时以防栈空的时候继续出栈而导致的超界。

1.9 push、pop指令

push和pop指令是可以在寄存器和内存之间传送数据的。

格式:

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

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

也可以在内存单元和内存单元之间传送数据:

push 内存单元 // 将一个内存字单元处的字入栈(注意:栈操作都是以字为单位 )
pop 内存单元 //出栈,用一个内存字单元接收出栈的数据

例:
mov ax, 1000H
mov ds, ax
push [0] //将1000:0处的字压入栈中
pop [2] //出栈,出栈的数据送入1000:2处

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

问题:

  1. 利用栈交换AX和BX中的数据
    push ax
    push bx
    pop ax
    pop bx

  2. 如果要在10000H处写入字型数据2266H,可以用:
    1>
    mov ax, 1000H
    mov ds, ax
    mov ax, 2266H
    mov [0], ax

2>
mov ax, 1000H
mov ss, ax
mov sp, 0002H
mov ax, 2266H
push ax

push、pop 实质上就是一种内存传送指令,可以在寄存器和内存之间传送数据。
push 和 pop 指令同 mov 指令不同,CPU 执行 mov 指令只需一步操作,就是传送,而执行 push、pop 指令却需要两步操作。执行 push 时,CPU 的两步操作是∶先改变 SP,后向 SS∶SP 处传送。执行 pop 时,CPU 的两步操作是∶ 先读取 SS∶SP 处的数据,后改变 SP。

注:mov [2], ax 在指令中给地址 pop ax则在SS:SP中给地址

小结:
cs(code segment)是代码段寄存器,放代码段的段地址他里面的内容和ip里面的内容和起来就可以找到当前执行的指令,
ds(data segment)是数据段段寄存器 放数据段的段地址,根据段地址*16d+偏移量就可以得到物理地址
ss:ip 合起来也可找到物理地址

push、pop等栈操作指令,修改的只是SP。则栈顶变化范围为0~FFFFH。

8086CPU的栈操作机制:SS、SP指示栈顶;改变 SP 后写内存的入栈指令;读内存后改变 SP 的出栈指令

总结:

在这里插入图片描述
在这里插入图片描述

1.10 栈段

对于 8086PC机,在编程时,可以根据需要,将一组内存单元定义为一个段。我们可以将长度为 NCN≤64KB)的一组地址连续、起始地址为 16 的倍数的内存单元,当作栈空间来用,从而定义了一个栈段。

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hvk_l

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值