3. BAR大小计算与对齐规则

好,咱们进入第三章。这一章我把它叫做“地基工程”。

为什么?因为 BAR 的大小和对齐,直接决定了后续地址能不能对上,机器能不能跑起来。我记得刚带团队的时候,有个同事把 BAR 的大小算错了,结果验证工程师查了三天,最后发现是地址空间没对齐。嗯,这种坑,被人踩一次就够了。

这一章我会把计算方法拆开,再把对齐规则讲透。你跟着走一遍,以后看到 BAR 就不会发怵了。

3.1 BAR 大小计算的核心逻辑

先想一个问题:当你向 PCIe 总线申请一块地址空间时,硬件怎么知道它该多大?

答案其实很简单——写全1。

你往 BAR 寄存器里写 0xFFFFFFFF,再读回来,看到哪些位是 0,哪些位是 1。芯片内部固化了不可编程的位,这些位就决定了 BAR 的最小对齐大小。

核心公式: BAR 可编程位从第一个 1 开始,决定了 size = 2ⁿ,对齐地址也等于这个 size。

我举个实际的例子。假设你配置了一个 4KB 的 BAR,那么低 12 位就被硬件写死了(读回来是 0),高位才是可编程段。12 位地址对应 4KB。你看,本质上这就是 2 的幂次。

3.2 对齐规则的三种常见形式

对齐规则说白了就是一句话:你的 BAR 基地址,必须能被它的大小整除。

为什么?因为总线只认识页对齐、自然对齐。你想想看,如果 BAR 大小是 1MB,它却放在 512KB 的边界上,那地址范围就会和邻居打架。

我个人习惯把对齐规则归纳为以下三类:

  • 自然对齐: base_addr % size == 0。比如 4KB BAR,基址必须是 4KB 的倍数。
  • Prefetchable & Non-prefetchable 的统一: 两种 BAR 都遵循同样的对齐规则,没有例外。
  • 64-bit BAR 的特殊性: 两个连续的 32-bit 寄存器视为一个整体,高位寄存器的值决定了基址的高 32 位,对齐要求还是按照总的 64-bit size 来算。

提示: 64-bit BAR 在实际设计中很常见。我的经验是,不要在低 32 位乱动,把高位和低位一起当成一个 64 位数来算对齐,不容易搞错。

3.3 大小计算的避坑指南

我曾经遇到一个案例:某 BAR 声明了 8KB,但实际只用了 4KB。硬件描述里不小心写错了 mask,结果读回来只有 4KB 空间可用,验证怎么会过?

这种问题其实很容易犯,因为很多工程师直接复制前一个模块的代码。这里我给你列几个要点:

  1. 确认最终需求:你需要的地址空间有多大,包括对齐后的浪费。
  2. 检查 mask 宽度:写全 1 后,可编程位的范围必须等于 size 的二进制表示。
  3. 验证边界地址:base + size - 1 不能溢出 64-bit 地址空间。
  4. 注意合并 BAR:同一外设如果有连续空间,尽量合并成一个 BAR,减少地址碎片。

嗯,实际上,大多数问题都是第三条引起的。溢出真的是个坑,地址写爆了,总线就挂在那里,谁也找不到原因。

3.4 对齐规则流程图

下面这张图把这整套逻辑串了起来。你看着它,基本上就能手算任何 BAR 的大小和对齐地址了。

BAR 大小计算与对齐规则流程 BAR 地址对齐与空间分配流程 写入 0xFFFFFFFF 读出 BAR 值,定位可编程位 可编程位是否连续? 是 → 计算 size = 2^n 否 → 硬件设计缺陷,检查 mask 基址是否能被 size 整除? 是 → 空间可分配 否 → 调整基址或合并 BAR 注意事项 64-bit BAR 将高低寄存器 整体看作 64 位数计算

3.5 实战中的计算步骤

好了,理论看完了,我们来看看实际操作。假设你有一个 BAR,要求分配 16KB 的地址空间。

步骤 操作 说明
1 确定大小 16KB = 2^14 字节 → size = 0x4000
2 计算 mask 低 14 位为 0,高位可编程 → mask = 0xFFFFC000
3 选择基址 基址必须是 0x4000 的倍数,比如 0x10000
4 验证地址范围 0x10000 ~ 0x13FFF,不与现有 BAR 重叠
5 配置 BAR 寄存器 写入基址值(注意低 4 位控制位)

你看,只要一步接一步来,一点都不复杂。

警告: 基址的低 4 位用于控制(比如 Memory Space Indicator、Prefetchable 等),写入基址时必须保证低 4 位为 0 或者正确的控制值,否则硬件会忽略你的配置。

3.6 总结一下重点

  • BAR 大小等于 2^n,n 由可编程位的最高位位置决定。
  • 对齐规则 = 基址能被 size 整除。
  • 64-bit BAR 整体对齐,别分开算。
  • 写全 1 读回来的值,就是最好的说明书。

说实话,这一章讲的内容,我自己在项目里反复用到。很多看起来复杂的问题,比如地址碰撞、空间浪费,根子往往就是这三条规则没遵守。你只要记住这个流程,多练几遍,以后设计 BAR 就像喝水一样自然。

嗯,这次就到这里。拿起你的电路图,试着算几个 BAR 的大小,你会发现问题比你想的简单。