ch2_2访问寄存器和内存

1. 内存中字的存储

1.1内存中字的存储

事实场景:
对8086CPU,16位作为一个字, 表明一个包含两个字节,对应的便需要两个存储单元来存放;

那么两个字节在内存单元中,具体的存放顺序如何?

问题
16位的字存储在一个16位的寄存器中,如何存储?
回答:
高8位放高字节,低8位放低字节;

问题
16位的字在内存中需要2个连续字节存储,怎么存放?
回答
低位字节存在低地址单元,高位字节存在高地址单元
例:20000D(4E20H)存放0、1两个单元,
18D(0012H)存放在2、3两个单元

在这里插入图片描述

注意到, 0号是低地址单元,1号是高地址单元

1.2字单元

  • 字单元:由两个地址连续的内存单元组成,存放一个字型数据(16位)

  • 原理:在一个字单元中,低地址单元存放低位字节,高地址单元存放高位字节;

在起始地址为0的单元中,存放的是4E20H
在起始地址为2的单元中,存放的是0012H

在这里插入图片描述

问题检测:
(1)0地址单元中存放的字节型数据是( 20H)
(2)0地址字单元中存放的字型数据是( 4E20H )
(3)2地址单元中存放的字节型数据是( 12H )
(4)2地址字单元中存放的字型数据是( 0012H )

2. 用DS和[address]实现字的传送

2.1 CPU从内存单元中要读取数据

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

原理
在8086PC中,内存地址由段地址和偏移地址组成
(段地址:偏移地址)

解决方案:DS和[address]配合

  1. 用 DS寄存器存放要访问的数据的段地址
  2. 偏移地址用[…]形式直接给出

注意,当直接使用[..] 的表示形式,则本身的含义代表的是使用的是 DS:[..], 以数据段 DS寄存器中的内容,作为段地址,偏移地址是[..]

  • 内存单元中的数据写到cpu的寄存器中;

将10000H(1000:0)中的数据读到al中,

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

  • cpu 寄存器中的数据写到内存单元中,
    将al中的数据写到10000H(1000:0)中;

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

在这里插入图片描述

8086CPU不支持将数据直接送入段寄存器
(硬件设计的问题)
:套路:数据 --> 一般的寄存器 —> 段寄存器

注意到, 当使用DS数据段寄存器时, 则表明此时,从内存单元中取出的内容, cpu将会把该内容当做数据来处理, 因为DS数据段寄存器,表明的便是该内存单元中的内容是作为数据来处理的

2.2 字的传送

8086CPU可以一次性传送一个字(16位的数据)

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

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

2.3 案例

在这里插入图片描述

指令
mov ax, 1000H
mov ds, ax
mov ax, [0]
mov bx, [2]
mov cx, [1]
add bx, [1]
add cx, [2]

在这里插入图片描述

在这里插入图片描述

指令
mov ax, 1000H
mov ds, ax
mov ax, 2C31
mov [0], ax
mov bx, [0]
sub bx, [2]
mov [2], bx

3.  DS与数据段

3.1对内存单元中数据的访问

对于8086PC机,可以根据需要将一组内存单元定义为一个段;

物理地址=段地址×16+偏移地址;

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

用123B0H~123B9H的空间来存放数据
段地址:123BH 起始偏移地址:0000H 长度:10字节
段地址:1230H 起始偏移地址:00B0H 长度:10字节

在这里插入图片描述

处理方法:DS:[address]
用DS存放数据段的段地址
用相关指令访问数据段中的具体单元,单元地址由[address]指出

3.2内存单元定义为数据段

将123B0H~123BAH的内存单元定义为数据段;

累加数据段中的前3个单元中的数据,

mov ax, 123BH
mov ds, ax
mov al, 0
add al, [0]
add al, [1]
add al, [2]

在这里插入图片描述

这里,需要注意到字型数据和 字节型数据之间的区别

即,一个字数据,占用了两个字节型数据, 每个字节型数据占用一个存储单元。

累加数据段中的前3个字型数据

mov ax, 123BH
mov ds, ax
mov ax, 0
add ax, [0]
add ax, [2]
add ax, [4]

3.3实践

给出00000H-0001F的数据, 请写出下面代码的执行结果:
在这里插入图片描述
预设数据, 预设代码, 寄存器值, 执行代码;

在这里插入图片描述

3.4用mov指令操作数据

指令形式 例示
mov 寄存器,数据 mov ax, 8
mov 寄存器,寄存器 mov ax, bx
mov 寄存器,内存单元 mov ax, [0]
mov 内存单元,寄存器 mov [0], ax
mov 段寄存器,寄存器 mov ds, ax

已知:mov 段寄存器,寄存器
推测1 mov 寄存器,段寄存器
在这里插入图片描述

: 已知:mov 内存单元,寄存器
推测2 mov 内存单元,段寄存器
推测3 mov 段寄存器,内存单元
在这里插入图片描述

已知:mov 寄存器,数据
推测4 mov 段寄存器,数据

在这里插入图片描述

3.5 加法add和减法sub指令

add指令形式 例示
add 寄存器,数据 add ax, 8
add 寄存器,寄存器 add ax, bx
add 寄存器,内存单元 add ax, [0]
add 内存单元,寄存器 add [0], ax

在这里插入图片描述

sub指令形式 例示
sub 寄存器,数据 sub ax, 8
sub 寄存器,寄存器 sub ax, bx
sub 寄存器,内存单元 sub ax, [0]
sub 内存单元,寄存器 sub [0], ax

3.6 用DS和[address]形式访问内存中数据段方法小结

mov ax, 1000H
mov ds, ax
mov ax, 11316
mov [0], ax
mov bx, [0]
sub bx, [2]
mov [2], bx

结合体验品味:

(1)字在内存中存储时 ,要用两个地址连续的内存单元来存放,字的低位字节存放在低地址单元中,高位字节存放再高地址单元中。

(2)用 mov 指令要访问内存单元,可以在mov指令中只给出单元的偏 移地址,此时,段地址默认在DS寄存器中。

(3)[address]表示一个偏移地址为address的内存单元。

(4)在内存和寄存器之间传送字型数据时,高地址单元和高8位寄存器、低地址单元和低8位寄存器相对应。

(5)mov、add、sub是具有两个操作对象的指令,访问内存中的数据段(对照:jmp是具有一个操作对象的指令,对应内存中的代码段)。

(6)可以根据自己的推测,在Debug中实验指令的新格式。

4. 栈与栈操作的实现

栈是一种只能在一端进行插入或删除操作的数据结构。

在这里插入图片描述

4.1 栈结构

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

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

  • 栈顶的元素总是最后入栈,需要出栈时,又最先被从栈中取出。
    栈的操作规则:LIFO(Last In First Out,后进先出)

CPU提供的栈机制

现今的CPU中都有栈的设计。
8086CPU提供相关的指令,支持用栈的方式访问内存空间。
基于8086CPU的编程,可以将一段内存当作栈来使用

PUSH(入栈)和 POP(出栈)指令

push ax:将ax中的数据送入栈中
pop ax:从栈顶取出数据送入ax
ax是16位通用寄存器,表明(以字为单位对栈进行操作)

4.2 内存当作栈来使用

设将10000H~1000FH内存当作栈来使用,

mov ax,0123H
push ax
mov bx,2266H
push bx
mov cx,1122H
push cx
pop ax
pop bx
pop cx

在这里插入图片描述

问题:
1、CPU如何知道一段内存空间被当作栈使用?
2、执行push和pop的时候,如何知道哪个单元是栈顶单元?

回答:
8086cpu 中,有两个与栈相关的寄存器:

栈段寄存器ss, 用于存放栈顶的段地址,

栈顶指针寄存器sp, 用于存放栈顶的偏移地址,

而在任意时刻, ss:sp 是指向栈顶元素;

4.3 栈的操作

mov ax, 1000H
mov ss, ax
mov sp, 0010H
mov ax, 001AH
mov bx, 001BH
push ax
push bx
pop ax
pop b

在这里插入图片描述

4.4 push 指令和pop指令的执行过程

push ax :压栈, 默认的是先将sp栈顶指针代表的偏移地址减去2, 然后将ax寄存器中的内容输入到 ss:sp 指向的内存单元中;

这里加减2的原因,是ax寄存器是16位,代表了两个字节的内容,所以是加减二;

pop ax: 出栈,默认的是先将ss:sp 指向的内存单元中的内容输入到寄存器 ax中,然后将栈顶指针sp+2;

注意到,push压栈的过程中,栈顶是逐渐上移动,从高地址向低地址移动;

pop 出栈的过程中,栈顶逐渐向下移动,从低地址到高地址移动。

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

mov ax, 1000H
mov ss, ax
mov sp, 0010H
mov ax, 001AH
mov bx, 001BH
push ax
push bx
pop ax
pop bx

在这里插入图片描述

:栈顶超界问题
如何能够保证在入栈、出栈时,栈顶不会超出栈空间?

4.5 执行入栈(push)时, 栈顶超出栈空间

在这里插入图片描述

4.6 执行出栈(pop)时, 栈顶超出栈空间

在这里插入图片描述

在这里插入图片描述

栈顶超界问题的解决

:8086CPU不保证对栈的操作不会超界。

8086CPU 只知道栈顶在何处(由SS:SP指示),不知道程序安排的栈空间有多大。

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

4.7 栈的小结

push、pop 实质上就是一种内存传送指令,可以在寄存器和内存之间传送数据,

与mov指令不同的是, push和pop指令访问的内存单元的地址不是在指令中给出的,而是由SS:SP指出的。

执行push和pop指令时,SP 中的内容自动改变。

8086CPU提供的栈操作机制:

在ss, sp 中存放栈定的段地址和偏移地址, 入栈和出栈指令根据ss:sp 指示的地址,按照栈的方式访问内存单元。

push 指令的执行步骤:

  1. sp = sp - 2:
  2. 向ss:sp 指向的内存单元中,输入数据;

pop 指令的执行步骤:

  1. 从ss:sp 指向的内存单元中读取数据,
  2. sp = sp +2

在这里插入图片描述

5. 关于段的总结

基础

物理地址=段地址×16+偏移地址

  • 做法
  1. 编程时,可以根据需要将一组内存单元定义为一个段。
  1. 可以将起始地址为16的倍数,长度为N(N ≤64K )的一组地址连续的内存单元,定义为一个段。
  1. 将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元——在程序中可以完全由程序员安排

5.1 三类段

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

  2. 代码段 CS
    . 将段地址放在 CS中,将段中第一条指令的偏移地址放在IP中。
    . CPU将我们定义的代码段中的内容当做指令来执行;

  3. 栈段
    . 将段地址放在SS中,将栈顶单元的偏移地置放在 SP 中
    . CPU在需要进行栈操作(push、pop)时,就将我们定义的栈段当作栈空间来用。

5.2 按要求设置段并执行代码

在这里插入图片描述

mov bx, 1000H
mov ds, bx
mov bx, 1001H
mov ss, bx
mov sp, 10H
mov ax, [0]
mov bx, [2]
push ax
push bx
pop ax
pop bx
mov [0], ax
mov [2], bx

5.3 三个段地址可以一样滴!

在这里插入图片描述

mov bx, 1000H
mov ds, bx
mov ss, bx
mov sp, 20H
mov ax, [0]
mov bx, [2]
push ax
push bx
pop ax
pop bx
mov [0], ax
mov [2], bx

猜你喜欢

转载自blog.csdn.net/chumingqian/article/details/131615346
今日推荐