寄存器(内存访问)

寄存器(内存访问)

1 内存中字的存储

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

在0地址处开始存放20000(4E20H):

请添加图片描述

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

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

我们将起始地址为 N的字单元简称为N地址字单元。比如一个字单元由2、3两个内存单元组成,则这个字单元的起始地址为2,我们可以说这是2地址字单元。

2 DS和[address]

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

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

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

已知的mov指令可完成的两种传送功能:

(1)将数据直接送入寄存器;

(2)将一个寄存器中的内容送入另一个寄存器中。

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

用 mov 指令要访问内存单元,可以在mov指令中只给出单元的偏移地址,此时,段地址默认在DS寄存器中。[address]表示一个偏移地址为address的内存单元。

例如:我们要读取10000H单元的内容可以用如下程序段进行:

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

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

3 字的传送

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

请添加图片描述

上述指令执行结果如下:

请添加图片描述

4 mov、add、sub指令

mov指令的几种形式:

mov 寄存器,数据

mov 寄存器,寄存器

mov 寄存器,内存单元

mov 内存单元,寄存器

mov 段寄存器,寄存器

add和sub指令同mov一样,都有两个操作对象。

请添加图片描述

5 数据段

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

比如我们用123B0H~123B9H这段空间来存放数据:

段地址:123BH

长度:10字节

我们现在要累加这个数据段中的前3个单元中的数据,代码如下:

请添加图片描述

6 栈

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

栈有两个基本的操作:入栈和出栈。

  • 入栈:将一个新的元素放到栈顶;
  • 出栈:从栈顶取出一个元素。

栈顶的元素总是最后入栈,需要出栈时,又最先被从栈中取出。

栈的操作规则:LIFO (Last In First Out,后进先出)

7 CPU提供的栈机制

我们在基于8086CPU编程的时候,可以将一段内存当作栈来使用。

8086CPU提供入栈和出栈指令:

  • PUSH(入栈)
  • POP (出栈)

push ax:将寄存器ax中的数据送入栈中;

pop ax :从栈顶取出数据送入ax。

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

8086CPU中,有两个寄存器:

  • 段寄存器SS:存放栈顶的段地址
  • 寄存器SP:存放栈顶的偏移地址

任意时刻,SS:SP指向栈顶元素。

下图为一段指令的执行过程:

请添加图片描述

pop指令的实际执行过程:

请添加图片描述

注意:

出栈后,SS:SP指向新的栈顶 1000EH,pop操作前的栈顶元素,1000CH 处的2266H 依然存在 ,但是,它已不在栈中。

当再次执行push等入栈指令后,SS:SP移至1000CH,并在里面写入新的数据,它将被覆盖。

8 栈顶超界的问题

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

栈顶超界是危险的。因为我们既然将一段空间安排为栈 ,那么在栈空间之外的空间里很可能存放了具有其他用途的数据、代码等,这些数据、代码可能是我们自己的程序中的,也可能是别的程序中的。(毕竟一个计算机系统并不是只有我们自己的程序在运行)

8086CPU不保证对栈的操作不会超界。这就是说, 8086CPU 只知道栈顶在何处(由SS:SP指示),而不知道我们安排的栈空间有多大。

因此我们在编程的时候要自己操心栈顶超界的问题 ,要根据可能用到的最大栈空间,来安排栈的大小,防止入栈的数据太多而导致的超界;

执行出栈操作的时候也要注意,以防栈空的时候继续出栈而导致的超界。

9 push、pop指令

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

push和pop指令的格式(1):

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

例如:

push ax 
pop bx

push和pop指令的格式(2):

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

例如:

push ds
pop es

push和pop指令的格式(3)

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

例如:

push [0]
pop [2]

10 栈段

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

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

访问时,我们需要将SS:SP指向我们定义的栈段。

栈顶的变化范围是0~FFFFH,从栈空时候的SP=0,一直压栈,直到栈满时SP=0;如果再次压栈,栈顶将环绕,覆盖了原来栈中的内容。

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

我们可以将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元。这完全是我们自己的安排。

我们可以用一个段存放数据,将它定义为“数据段”;

我们可以用一个段存放代码,将它定义为“代码段”;

我们可以用一个段当作栈,将它定义为“栈段”;

相关推荐

  1. 如何访问寄存器

    2024-03-14 19:02:01       6 阅读
  2. IO内存访问函数

    2024-03-14 19:02:01       42 阅读
  3. 51单片机内部的主要寄存器

    2024-03-14 19:02:01       29 阅读
  4. ARM/CM3/CM4:读写内核寄存器内核特殊寄存器

    2024-03-14 19:02:01       30 阅读
  5. OpenGL的着色器内存访问

    2024-03-14 19:02:01       31 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-14 19:02:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-14 19:02:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-14 19:02:01       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-14 19:02:01       20 阅读

热门阅读

  1. Boxes in a Line(UVA 12657)

    2024-03-14 19:02:01       19 阅读
  2. 深入理解SPA、CSR与SSR的区别及应用

    2024-03-14 19:02:01       21 阅读
  3. Discord账号申诉指南,让你成功找回账号

    2024-03-14 19:02:01       81 阅读
  4. c++实现数组

    2024-03-14 19:02:01       15 阅读
  5. 常问面试问题

    2024-03-14 19:02:01       22 阅读
  6. C语言自学笔记9----用户自定义函数

    2024-03-14 19:02:01       17 阅读
  7. 蓝桥杯刷题(六)

    2024-03-14 19:02:01       20 阅读
  8. freeROTS day2

    2024-03-14 19:02:01       18 阅读
  9. Chrome 跨域问题CORS 分析

    2024-03-14 19:02:01       18 阅读