目录
内存映射
1. 核心概念:内存映射 (Memory Map)
2. 启动过程与地址重映射 (Remapping)
关键:启动引脚 (Boot Pins)
这个过程可以类比:
3. 为什么设计成这样?
4. 一图流总结
图解说明:
核心要点:
总结
5. 关于上文的“重映射控制器”
核心区别:ARM Cortex-M 内核 vs. 芯片厂商的实现
“重映射”的具体实现方式
以STM32F1系列为例(来自ST的参考手册)
总结
内存映射
在上一篇博客中,我们解析了arm内核架构中的icode、dcode、s-bus总线和总线矩阵。需要注意的是,不论是icode、dcode、s-bus 在访问物理内存时都经过了内存映射(或者叫寄存器映射)
内存重映射的机制是由芯片厂商设计的一部分硬件逻辑实现的,而这部分逻辑通常与总线矩阵紧密集成,或者说是总线矩阵功能的一部分。
上篇博客:https://blog.csdn.net/leilei050213/article/details/151442621?spm=1001.2014.3001.5501
1. 核心概念:内存映射 (Memory Map)
ARM Cortex-M内核设计了一个固定的内存映射架构。这意味着CPU内核“认为”4GB的地址空间(从0x0000_0000
到0xFFFF_FFFF
)的特定区域永远对应特定类型的内存或设备。
这种固定映射的好处是极大的可移植性。任何为Cortex-M编写的软件都知道:
-
代码在
0x0000_0000
和0x0800_0000
。 -
数据RAM在
0x2000_0000
。 -
外设在
0x4000_0000
。 -
内核寄存器在
0xE000_0000
。
无需为不同的芯片重新配置基本内存布局。
2. 启动过程与地址重映射 (Remapping)
现在我们从一个疑问来探究地址重映射的过程:为什么代码物理上存储在0x08000000,但CPU却从0x00000000开始取指?
答案是通过一个叫做地址重映射的机制。这是由芯片厂商(如ST、NXP)在微控制器内部通过硬件实现的。
关键:启动引脚 (Boot Pins)
很多MCU都有启动引脚(如BOOT0, BOOT1)。这些引脚在上电复位时的电平,决定了芯片将什么物理内存映射到启动地址0x0000_0000。
以STM32为例,常见的启动选项有:
-
从主Flash启动 (通常模式):
-
将引脚配置为从主Flash启动。
-
此时,芯片内部的内存控制器会做一个简单的地址偏移映射:
-
所有对地址
0x0000_0000
的访问,都会被重定向到0x0800_0000
。 -
访问
0x0000_0001
-> 变成访问0x0800_0001
-
访问
0x0000_FFFF
-> 变成访问0x0800_FFFF
-
-
iCode总线去
0x0000_0000
取指令,内存控制器悄悄地将这个请求转给了0x0800_0000
位置的Flash存储器。CPU内核完全不知道这个重映射过程,它以为指令就在0x0000_0000
。
-
-
从系统存储器启动 (ISP模式):
-
芯片内部有一块特殊的BootROM,里面预烧了厂家的串口/USB下载程序。它的物理地址可能是在
0x1FFF_0000
。 -
当配置为从系统存储器启动时,对
0x0000_0000
的访问会被重定向到这片BootROM。
-
-
从内置SRAM启动:
-
用于调试。将SRAM(物理地址
0x2000_0000
)映射到0x0000_0000
。
-
这个过程可以类比:
-
你的家(Flash) 实际地址是:幸福路808号(0x0800_0000)。
-
但市政规定,所有寄到 市中心1号(0x0000_0000) 的包裹,都会自动被邮局转到 幸福路808号。
-
CPU(邮差) 只知道把包裹送到“市中心1号”,它不知道转交过程,但这个包裹最终总能正确送达你的家。
3. 为什么设计成这样?
这种设计非常巧妙,主要有两个优点:
-
统一的入口点:
-
无论芯片内部Flash的物理地址在哪里,无论你有多少种启动方式,ARM内核CPU硬件永远、且只需要从同一个地址
0x0000_0000
开始取指令。 -
这简化了CPU内核的设计,使其不需要关心外部世界的复杂变化。
-
-
极大的灵活性:
-
芯片厂商可以通过启动引脚和重映射逻辑,提供多种启动模式,而无需修改CPU核心。
-
开发者可以灵活选择从程序Flash启动、从BootLoader启动、或者从RAM启动进行调试,硬件帮你搞定地址转换问题。
-
4. 一图流总结
图解说明:
-
起点 (CPU请求):
-
CPU 内核的 iCode 总线严格按照 ARM 架构设计,永远从逻辑地址
0x0000 0000
开始取指。这是它的固定行为。
-
-
路由 (总线矩阵):
-
这个取指请求首先到达总线矩阵,这是芯片内部的“交通枢纽”。
-
-
决策 (启动配置):
-
总线矩阵会根据启动引脚(BOOT0, BOOT1) 的电平状态,决定将这个请求路由到哪里。最常见的情况(用户Flash启动)就是路由到重映射控制器。
-
-
转换 (地址重映射):
-
所谓的“重映射控制器”是这个过程的核心。它接收到一个针对
0x0000 0000
的访问请求,然后根据厂家预设的规则,悄悄地将这个请求转换为对物理地址0x0800 0000
的访问。
-
-
目的地 (物理Flash):
-
转换后的请求最终抵达实际的物理硬件:主Flash存储器。指令数据从这里被取出。
-
-
返回数据:
-
数据沿着原路返回:Flash -> 重映射控制器 -> 总线矩阵 -> CPU。
-
CPU 始终认为自己是从
0x0000 0000
读到了数据,它对背后发生的重映射过程一无所知。
-
核心要点:
-
逻辑地址 vs. 物理地址:
0x0000 0000
是CPU视角的逻辑地址(它认为的世界)。0x0800 0000
是Flash芯片的物理地址(真实的世界)。 -
重映射是桥梁: 芯片内部的“重映射”负责将CPU的“逻辑世界”和存储器的“物理世界”连接起来。
-
对程序员透明: 整个重映射过程由硬件完成,软件工程师无需干预。你只需要知道你的程序被烧录到了
0x0800 0000
,并且CPU会正确地从那里开始执行。
总结
-
CPU从
0x0000_0000
开始执行:这是ARM Cortex-M架构规定的、不可改变的硬件行为。 -
Flash物理地址在
0x0800_0000
:这是芯片厂商根据ARM的内存映射建议分配的物理地址。 -
连接二者的桥梁:是芯片内部的重映射机制。它根据启动引脚的配置,将CPU对“启动地址”的访问透明地重定向到不同的物理存储器上(Flash、SRAM或BootROM)。
-
iCode总线:它负责执行取指操作,它发出的是“逻辑地址”(
0x0000_0000
),但经过重映射后,这个请求被传递到了“物理地址”(0x0800_0000
)上的Flash存储器。
所以,0x0000 0000 和 0x0800 0000 这两个地址都是存在的,它们描述的是不同层面的概念:一个是CPU视角的逻辑地址,一个是存储器的物理地址。重映射技术则将这两个视角巧妙地统一了起来。
5. 关于上文的“重映射控制器”
在 ARM Cortex-M3 Technical Reference Manual (cortex-m3技术参考手册) 中,我们不会找到一个名为 “Remapping Controller” (重映射控制器) 的独立模块。
“重映射控制器”是一个为了易于理解而使用的一个功能性的统称,它实际上指向了芯片厂商实现的一系列机制。
核心区别:ARM Cortex-M 内核 vs. 芯片厂商的实现
首先要理解一个关键区别:
-
ARM Cortex-M 内核: 它定义了CPU核心本身的行为(如寄存器、指令集、NVIC)和它期望看到的固定内存映射(即CPU发出的地址
0x0000_0000
应该对应什么)。 -
芯片厂商 (如ST, NXP, TI): 他们购买ARM的IP授权,然后围绕Cortex-M内核设计自己的芯片(MCU)。他们负责实现内存控制器、Flash、SRAM、外设,并决定如何将物理存储器映射到CPU所期望的地址空间。
我们找不到“重映射控制器”的原因在于:这个“重映射”功能是芯片厂商在它们自己的芯片设计中加入的,不属于ARM Cortex-M核心的标准部分。因此,它不会出现在内核的技术参考手册中,而是描述在芯片厂商的数据手册 (Datasheet) 和参考手册 (Reference Manual) 里。
“重映射”的具体实现方式
芯片厂商通常通过以下两种主要方式来实现地址 0x0000_0000
的“重映射”:
-
地址别名 (Address Aliasing) - 最常见的方式
这是最简单、最低成本的方式。它不是一个复杂的“控制器”,而更像是一个固定的地址连线偏移。
-
工作原理: 在芯片的内部总线结构中,将CPU对地址块
0x0000_0000
-0x0007_FFFF
(例如) 的访问请求,其地址线最高位直接忽略或重新编码,从而定向到物理地址块0x0800_0000
-0x0807_FFFF
。 -
类比: 这就像是一栋大楼。CPU总是说“我要去101房间”,而大楼的管理系统(芯片设计)硬性规定“所有101房间的请求都自动引导到201房间”。没有复杂的计算,只是一个简单的、固定的规则。
-
特点: 这种方式是静态的、固定的。一旦芯片制造好,
0x0000_0000
就永远别名到0x0800_0000
。启动模式的选择可能是通过改变别名到的目标地址来实现的(见下一条)。
-
内存地址重映射开关 (Memory Remap Switch)
一些更复杂的芯片(或Cortex-A系列)会有一个真正的可编程重映射控制器,通常称为 “Remap” 或 “Memory Controller” 功能。
-
工作原理: 芯片内部存在一个可配置的开关电路。CPU可以通过配置一个特定的控制寄存器来改变这个开关的状态。
-
这个寄存器: 允许软件动态地改变地址
0x0000_0000
映射到哪一块物理存储器(Flash, SRAM, BootROM)。 -
在哪里描述: 这个寄存器是芯片厂商自定义的,它的地址、位定义都会写在芯片的参考手册中,通常是在系统配置(System Configuration)或内存控制器(Memory Controller)的章节里。例如,在STM32的参考手册中,你会找到类似“Boot configuration”的寄存器。
以STM32F1系列为例(来自ST的参考手册)
在STM32中,实现“重映射”的机制是上述两种方式的结合:
-
固定别名区域: CPU地址
0x0000_0000
-0x1FFF_FFFF
这块512MB的区域被设计为可重映射的区域。它本身不固定对应任何物理内存。 -
Boot引脚配置开关: 芯片上电复位时,会采样BOOT0和BOOT1引脚的电平。
-
硬件自动配置: 根据引脚电平,芯片内部的硬件逻辑会自动设置一个隐藏的开关,将这个“可重映射区域”连接到三块物理存储器中的一块:
-
BOOT1=0, BOOT0=0
-> 映射到 Main Flash (物理地址0x0800_0000
) -
BOOT1=0, BOOT0=1
-> 映射到 System Memory (BootROM, 物理地址0x1FFF_0000
等) -
BOOT1=1, BOOT0=1
-> 映射到 Embedded SRAM (物理地址0x2000_0000
)
-
这个过程在复位后由硬件瞬间完成,无需软件初始化。之后,这个映射关系就固定了,直到下一次复位。
总结
-
关于“内存重映射”该查阅哪里:
-
要理解CPU视角的内存布局,看 《Cortex-M3 Technical Reference Manual》。
-
要理解物理芯片的内存布局和重映射实现细节,看 芯片的数据手册 (Datasheet) 和 参考手册 (Reference Manual)。查找 “Boot configuration”、 “Memory organization” 或 “Controller registers” 等章节。
-
-
对程序员的意义:
-
对于绝大多数应用程序开发者来说,这个重映射过程是完全透明的。你只需要知道程序计数器从
0x0000_0000
开始,而你的代码链接在0x0800_0000
,硬件会帮你处理好一切。 -
只有当你在编写Bootloader或进行非常底层的系统调试时,才需要深入了解BOOT引脚的配置和芯片具体的重映射机制。
-