文章目录
我们以一块ARM64开发板为例,芯片内部有SRAM,起始地址为0x0,DDR内存的起始地址为0x40000000,这句话该如何理解?为什么SRAM和DDR内存地址的起始地址不同?
关键误区澄清
很多人以为:"既然是独立设备,应该各自从0开始编址"
但实际是:"它们在同一个统一的物理地址空间中"
类比解释
想象一个大型仓库(整个物理地址空间):
整个仓库地址范围:0x00000000 - 0xFFFFFFFF (4GB空间)
│
├── 区域A:货架区(SRAM)
│ 地址:0x00000000 - 0x03FFFFFF (64MB)
│ └── 这是放小件贵重物品的地方
│
├── 区域B:大货区(DDR)
│ 地址:0x40000000 - 0x7FFFFFFF (1GB)
│ └── 这是放大宗货物的区域
│
└── 区域C:工具区(外设)
地址:0x80000000 - 0x8FFFFFFF (256MB)
└── 这是放操作工具的地方
关键理解:整个地址空间是一个连续的统一空间,不同的存储设备被分配到这个空间的不同区域。
从CPU的视角看
CPU只有一个地址总线
c
// CPU只有一套地址引脚(比如A31-A0)
// 它发出地址信号时,所有设备都能"听到"
CPU地址总线
│
┌────────────┼────────────┐
│ │ │
地址解码器1 地址解码器2 地址解码器3
(SRAM) (DDR) (外设)
│ │ │
片选信号: 片选信号: 片选信号:
0x00000000- 0x40000000- 0x80000000-
0x03FFFFFF 0x7FFFFFFF 0x8FFFFFFF
为什么不能都从0开始?
物理限制:CPU只有一个地址0
assembly
/* 复位时,CPU的程序计数器(PC)指向0x0 */
reset_handler:
// 如果两个设备都在地址0,CPU该访问谁?
ldr r0, [0x0] // 这个"0x0"应该对应SRAM还是DDR?
// 解决方法是:只有一个设备响应地址0
// 通常SRAM响应0x0,因为启动需要快速访问
技术实现:地址解码逻辑
verilog
// 硬件地址解码器的Verilog代码
module address_decoder (
input [31:0] addr, // CPU发出的地址
output sram_cs, // SRAM片选
output ddr_cs, // DDR片选
output periph_cs // 外设片选
);
// SRAM响应0x00000000-0x03FFFFFF
assign sram_cs = (addr[31:26] == 6'b000000);
// DDR响应0x40000000-0x7FFFFFFF
assign ddr_cs = (addr[31:30] == 2'b01);
// 外设响应0x80000000-0x8FFFFFFF
assign periph_cs = (addr[31:28] == 4'b1000);
endmodule
实际硬件连接示意图
┌─────────────────────────┐
│ CPU │
│ ┌────────────┐ │
│ │ 地址总线 │ A31-A0│
│ │ A31───────┐│───────┼─────┐
│ │ ... ││ │ │
│ │ A2────────┼│───────┼─────┼─────┐
│ │ A1────────┼│───────┼─────┼─────┼─────┐
│ │ A0────────┼│───────┼─────┼─────┼─────┼─────┐
│ └────────────┘│ │ │ │ │ │
└──────────────────┘ │ │ │ │ │
│ │ │ │ │
┌─────地址比较逻辑─────────────┘ │ │ │ │
│ ┌─────────────────┐ │ │ │ │
│ │ 如果A31-A26=000000 │ │ │ │
│ │ 则选择SRAM │ │ │ │ │
│ └─────────────────┘ │ │ │ │
│ │ │ │ │ │
│ ┌────┴────┐ │ │ │ │
│ │ SRAM │ │ │ │ │
│ │ 片选 ├─────────────┘ │ │ │
│ └─────────┘ │ │ │
│ │ │ │
│ ┌─────────────────┐ │ │ │
│ │ 如果A31-A30=01 │ │ │ │
│ │ 则选择DDR │ │ │ │
│ └─────────────────┘ │ │ │
│ │ │ │ │
│ ┌────┴────┐ │ │ │
│ │ DDR │ │ │ │
│ │ 控制器 │ │ │ │
│ │ 片选 ├───────────────────┘ │ │
│ └─────────┘ │ │
│ │ │
│ ┌─────────────────┐ │ │
│ │ 如果A31-A28=1000│ │ │
│ │ 则选择外设 │ │ │
│ └─────────────────┘ │ │
│ │ │ │
│ ┌────┴────┐ │ │
│ │ 外设 │ │ │
│ │ 总线 │ │ │
│ │ 控制器 ├─────────────────────────┘ │
│ │ 片选 ├───────────────────────────────┘
│ └─────────┘
│
└────────────────────────────────────────────────────
地址解码逻辑(硬件实现)
如果都从0开始会发生什么?
场景:两个设备都响应地址0
assembly
/* 灾难性冲突 */
// CPU读取地址0x0
ldr r0, [0x0]
// 同时发生:
// SRAM响应:返回SRAM[0]的值
// DDR响应:返回DDR[0]的值
// 结果:总线冲突!数据损坏!
硬件总线冲突示意图
CPU发出读地址0x0
│
┌──────┼──────┐
│ │ │
SRAM DDR 其他设备
(响应) (也响应) (不响应)
│ │
└──┬───┘
↓
数据总线冲突!
SRAM输出数据A
DDR输出数据B
结果:A⊕B (不可预测)
总结:关键理解点
- CPU视角 :只有一个统一的物理地址空间,不是多个独立空间
- 硬件实现 :每个存储设备被分配到地址空间的特定区域
- 地址解码:硬件电路根据地址高位决定哪个设备响应
- 历史设计:低地址通常留给启动代码(SRAM/Flash),高地址给大容量内存
简单说:不是"DDR有自己的0地址,SRAM有自己的0地址",而是"在整个系统的物理地址空间中,SRAM占据了0地址开始的区域,DDR占据了0x40000000开始的区域"。