← 返回 计组与微机控制

计组与微机控制

3.8 数据组织

3.8 数据组织

计算机内存以字节编址,但数据可以是:

- 字节;- 半字;- 字;- 双字;- 字符串;

- 数组;- 结构体。

问题:

> 多字节数据在连续字节中按什么顺序存放?

这引出端格式。

一.1.数据组织与端格式:

3.8 数据组织 图 1

端格式决定多字节数据的高低字节在内存中的排列。

大端:高位字节存低地址

小端:低位字节存低地址

例如 32 位数 `0x12345678`:

| 地址递增方向 | 大端 | 小端 |

| 低地址 -> 高地址 | 12 34 56 78 | 78 56 34 12 |

2.对齐方式

对齐是指多字节数据最好放在其大小的整数倍地址上。

例如:

- 32 位字放在 4 的倍数地址;

- 16 位半字放在 2 的倍数地址。

3.8 数据组织 图 2

对齐好处:

- 硬件访问简单;

- 性能更高;

- 避免某些体系结构异常。

如果只想读一个字符,不能用普通 `LDR` 读整个字,而应使用:

LDRB r0, [r1]

如果读 16 位半字:

LDRH r0, [r1]

加载到 32 位寄存器时,高位如何处理取决于指令是否带符号扩展。

小端拼接

本页通常讲如何把多个字节拼成半字或字。

小端中低地址字节是低有效字节。

若:

Memory[p]   = low byte

Memory[p+1] = high byte

拼接:

LDRB r0, [r2,#0]

LDRB r1, [r2,#1]

ORR  r0, r0, r1, LSL #8

大端拼接

大端中低地址字节是高有效字节。

因此拼接顺序与小端相反。

统一规律:

> 端格式决定哪个地址上的字节放在结果的高位,哪个放在低位。

如果地址不是 4 的倍数,直接 `LDR` 可能:

- 硬件不支持;

- 产生异常;

- 自动修正但性能下降;

- 读到经过旋转或拼接的数据。

更通用的做法是:

- 先读包含目标数据的两个对齐字;

- 根据偏移拼接出目标 32 位数据。

3.按字节拼接数据

思想:

找到对齐地址

读取相邻字

计算字节偏移

移位

OR 拼接

这和网络报文、文件格式解析非常像:硬件读出的字节需要软件重新组合。

读取无符号半字并拼接:

本页给出通过两次字节访问读取无符号半字的代码。

小端示例:

LDRB r0, [r2,#0]

LDRB r1, [r2,#1]

ORR  r0, r0, r1, LSL #8

含义:

- 第一个字节放低 8 位;

- 第二个字节左移 8 位放高 8 位;

- `ORR` 合成 16 位结果。

4.任意对齐地址加载 32 位字

3.8 数据组织 图 3

本页讲更复杂的未对齐 32 位字加载。

3.8 数据组织 图 4

典型步骤:

BIC r2, r0, #3

LDMIA r2, {r1,r3}(块移动下节讲,也就是一起入栈)

AND r2, r0, #3

MOVS r2, r2, LSL #3

解释:

- `BIC r2,r0,#3` 清除低两位,得到 4 字节对齐地址;

- `LDMIA` 读取两个相邻字;

- `AND` 得到原地址在字内的字节偏移;

- 左移把字节偏移换成位偏移;

- 通过移位和 OR 拼接目标字。

也就是说先找到起始位置BIC把低两位清0,这个是固定操作,然后后面AND和MOVS和MOVNE这三个指令会计算出他的偏移位置,也就是说比方说这个题上面的图要计算字节偏移,之后转换到位偏移,之后把高32和低32位的r3和r1移位合并

3.8 数据组织 图 5

1. 对齐基地址:r2 = r0 & ~3,找到包含目标地址的 8 字节块(两个连续字)的起始地址。

2. 加载两个相邻的字:LDMIA 将这两个字读入 r1 和 r3。

3. 计算字节偏移:r2 = r0 & 3,得到 0~3 的字节偏移。

4. 转为位偏移:r2 = r2 * 8(用 LSL #3)。

5. 提取低部分:r1 = r1 >> r2,得到目标数据的低 (32‑r2) 位(实际是高(地址高)的部分放到 r1 的低位)。

6. 计算剩余位数:r2 = 32 - r2。

7. 提取高部分并合并:r1 = r1 | (r3 << r2),将 r3 的低 r2 位提升到高位,与 r1 的低位部分拼成一个完整的 32 位字。