计组与微机控制
5.8 逻辑段和物理内存
5.8 逻辑段和物理内存

图 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 的分段结构
后半部分开始讲分段。

课本说:
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
