• 寄存器(内存访问)


    寄存器(内存访问)

    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]
    
    • 1
    • 2
    • 3

    上面三条指令将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
    
    • 1
    • 2

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

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

    例如:

    push ds
    pop es
    
    • 1
    • 2

    push和pop指令的格式(3)

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

    例如:

    push [0]
    pop [2]
    
    • 1
    • 2

    10 栈段

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

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

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

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

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

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

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

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

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

  • 相关阅读:
    机器学习笔记09---PCA主成分分析
    C语言学习--结构体与联合体
    Stirling-PDF:一款优秀的开源PDF处理工具
    论文解读(PPNP)《Predict then Propagate: Graph Neural Networks meet Personalized PageRank》
    架构真题2021(四十三)
    Java多线程获取执行结果
    如何使用GPT引领前沿与应用突破之GPT4科研实践技术与AI绘图
    从 Delta 2.0 开始聊聊我们需要怎样的数据湖
    基于Java毕业设计影院网上售票系统源码+系统+mysql+lw文档+部署软件
    HCNP Routing&Switching之MSTP
  • 原文地址:https://blog.csdn.net/weixin_74144099/article/details/136717018