← 返回 计组与微机控制

计组与微机控制

5.8 逻辑段和物理内存

5.8 逻辑段和物理内存

5.8 逻辑段和物理内存 图 1

图 2.9(b):字符也可以组成字

图 2.9(b) 里画了字符:

094A5H:'B' 094A6H:'A' 094A7H:'D' 094A8H:'C'

字符本质上也是二进制编码。

比如 ASCII 码:'A' = 41H 'B' = 42H 'C' = 43H 'D' = 44H

如果 094A7H 和 094A8H 两个字节组成一个字:

094A7H:'D' = 44H 低字节094A8H:'C' = 43H 高字节

那么这个字的内容是:4344H

也可以理解成高字节是 C,低字节是 D。

课本说:字母 C 的 ASCII 码存放在高字节单元中,字母 D 的 ASCII 码存放在低字节单元中。

也就是:高字节:C低字节:D

但内存地址顺序是:低地址:D高地址:C

小端规则之前讲过

字节访问和字访问

第 22 页左边说:

8086/8088 CPU 访问内存的指令分为字节访问和字访问两种。

意思是,同样是访问内存,有时访问 1 个字节,有时访问 1 个字。

1. 字节访问

字节访问一次读/写 8 位。例如:

MOV AL, [09235H]

AL 是 8 位寄存器,所以这条指令是字节访问。

它只读:09235H 这个字节,如果 09235H 里是 56H,那么:

AL = 56H

2. 字访问

字访问一次读/写 16 位,也就是两个连续字节。

例如:

MOV AX, [09235H]

AX 是 16 位寄存器,所以这条指令是字访问。

它会读:09235H 09236H

如果:09235H:56H 09236H:34H

那么:AX = 3456H

3. 为什么指令要说明字节还是字?

因为同一个地址,比如 09235H,可以有两种解释:

作为字节:只看 09235H,内容是 56H作为字:看 09235H 和 09236H,内容是 3456H

所以 CPU 必须知道你到底要访问 1 字节还是 1 字。

在汇编里,有时能从寄存器大小判断:

MOV AL, [2000H] ; AL 是 8 位,所以访问字节MOV AX, [2000H] ; AX 是 16 位,所以访问字

但如果指令本身看不出来,就要用类型说明,比如:

BYTE PTR [2000H]WORD PTR [2000H]

8086/8088 的分段结构

后半部分开始讲分段。

5.8 逻辑段和物理内存 图 2

课本说:

8086/8088 CPU 把 1MB 的存储空间划分成若干个段,每个段最多由 64K 个连续字节单元组成。

这里有几个关键词:

1MB 物理存储空间 若干段 每段最多 64KB 连续字节

1. 为什么每段最多 64KB?

因为段内偏移地址是 16 位。

16 位能表示:0000H ~ FFFFH

一共:2^16 = 65536 = 64KB

所以一个逻辑段内最多能访问 64KB。

2. 什么是段基址?

每个段在物理内存中都有一个起始地址,这个起始地址叫:

段基址 Segment Base Address

比如某段从物理地址 20000H 开始,那么:

段基址 = 20000H

段内某个单元的偏移量如果是 1234H,那么物理地址就是:

20000H + 1234H = 21234H

3. 段基址为什么一定是 16 的整数倍?

课本说:每个段基址都是 16 的整数倍,即段基址最低 4 位二进制数均为 0。

原因是 8086 的段寄存器只有 16 位,但物理地址是 20 位。

8086 用这个公式形成物理地址:

物理地址 = 段寄存器内容 × 16 + 偏移地址

乘以 16 就相当于二进制左移 4 位。

比如:

段寄存器 = 2000H

左移 4 位后:

段基址 = 20000H

你会发现段基址最后一位十六进制一定是 0。

例如:

20000H12340H0ABCD0H

这些都是 16 的整数倍。

4. 段寄存器里存的不是完整段基址

这个地方特别容易混。

如果:DS = 2000H

它对应的段基址不是 2000H,而是:

20000H

因为要左移 4 位。

所以:DS = 2000H偏移 = 1234H

物理地址是:

2000H × 10H + 1234H= 20000H + 1234H= 21234H

逻辑段和物理内存的关系

图 2.10 讲的是:物理存储器中的段结构。

这张图想说明一个重要事实:逻辑段在物理内存中可以相邻、间隔、部分重叠、完全重叠。

1. 相邻 Contiguous

两个段刚好挨着。

比如:

段 1:10000H ~ 1FFFFH段 2:20000H ~ 2FFFFH

中间没有空隙,也没有重叠。这叫相邻。

2. 间隔 Disjoint

两个段之间有空白区域。

比如:

段 1:10000H ~ 17FFFH段 2:20000H ~ 27FFFH

18000H 到 1FFFFH 这段没有被这两个段覆盖。这叫间隔。

3. 部分重叠 Partly Overlapped

两个段有一部分地址范围相同。

比如:

段 1:10000H ~ 1FFFFH段 2:18000H ~ 27FFFH

那么:18000H ~ 1FFFFH

这一段同时属于段 1 和段 2。这叫部分重叠。

4. 完全重叠 Full Overlapped

两个段完全指向同一片物理区域。

比如:

段 1 基址 = 20000H段 2 基址 = 20000H

那么两个逻辑段完全重叠。

也就是说,两个段寄存器可能指向同一个物理段。

例如:

DS = 2000HES = 2000H

那么 DS 和 ES 指向的段基址都是:20000H它们完全重叠。

为什么一个物理地址可以对应多个逻辑地址?

这是 8086 分段里非常重要的思想。

因为物理地址公式是:物理地址 = 段地址 × 16 + 偏移地址

不同的段地址和偏移地址组合,可能算出同一个物理地址。

例如:1000H:0020H

物理地址:1000H × 10H + 0020H= 10000H + 0020H= 10020H

再看:1001H:0010H

物理地址:1001H × 10H + 0010H= 10010H + 0010H= 10020H

再看:1002H:0000H

物理地址:1002H × 10H + 0000H= 10020H

所以这三个逻辑地址:

1000:00201001:00101002:0000

都指向同一个物理地址:10020H

这就是课本说的:一个物理存储单元可映像到一个或多个逻辑段中。

当前段 Current Segment

无论存储器的段怎样划分,对于程序来说,最后都归属于默认的 4 个当前段:

代码段 Code Segment数据段 Data Segment堆栈段 Stack Segment附加段 Extra Segment

它们分别由:CS DS SS ES指出。

1. 代码段 CS

CPU 取指令默认从:CS:IP取。

所以 CS 指向当前正在执行的代码所在段。

2. 数据段 DS

普通数据访问默认使用 DS。例如:MOV AX, [2000H]

通常表示:从 DS:2000H 取一个字给 AX

3. 堆栈段 SS堆栈操作默认使用 SS。

例如:PUSH AX POP BX

这些操作默认围绕:SS:SP进行。

4. 附加段 ES

ES 常用于字符串操作的目的段。

比如:MOVSB

默认是:DS:SI → ES:DI