简介:面对PCIe协议栈与总线体系不易梳理的问题,这份学习笔记将分散在教材中的要点整合成一份doc格式的速查文档,适合从事计算机硬件、嵌入式开发或需要理解高速总线原理的学生与工程师。笔记按时间线梳理了第一代ISA、EISA、MC、VESA并行总线,第二代PCI、AGP、PCI-X以及第三代PCI Express串行总线,对各代的数据宽度、频率和带宽做了参数对比;同时深入解析PCIe点对点串行互连的运作层次,包括Root Complex、Switch、Endpoint三大组成,存储器空间、IO空间与配置空间的映射方法,以及配置寄存器的作用。笔记还讲解了物理层TLP和DLLP包结构、8b/10b编码带来的20%开销,并给出有效数据载荷速率的实际计算过程,帮助读者从信号层理解带宽瓶颈。资源为1个doc文档,共178KB,内容精炼且密度高,目前已有2232人学习,适合希望快速系统掌握PCIe架构要点的读者反复研读。
1. PCIe 学习笔记地图:一条串行链路如何取代整条并行总线
PCIe 名字里带“总线”,但第一遍读体系架构时最容易产生的误解,恰恰是把它当成 PCI 的加强版。梳理下来会发现,PCIe 并不是把并行总线加宽、加速,而是干脆把“一条共享总线”换成了“一张点到点的交换网络”:每个设备独享链路,所有事务封装成信息包传输。理解这一点,三代 IO 总线的演进逻辑、两级桥的架构、三种地址空间的由来,以及 TLP/DLLP 的包模型,就全部串起来了。
这份笔记适合两类人:一类是在补硬件底层知识、想把总线从 ISA 一路理到 PCIe 的系统学习者;另一类是复习备考、需要快速抓住重点和易错点的读者。笔记主要整理自《PCI Express 系统体系结构标准教材》和《PCI PCIX 和 PCI Express 的原理及体系架构》两本经典教材,主线是:先看三代总线为什么变,再看 PCI 时代的平台骨架,最后落到 PCIe 的包传输与带宽计算。地图先摆在这儿,我们从第一代总线开始往里走。
2. 三代总线演进:从 ISA 到 PCIe,带宽困境是如何一步步逼出来的
把三代总线放在一起看,会得到一个很清晰的结论:第一代靠加宽数据线,第二代靠提高频率和拆分专用接口,第三代直接推翻并行结构。三代演进的驱动力只有一个——带宽不够用了,而每次增宽的代价都是电气负载变重、可挂设备变少。先看第一代。
2.1 第一代并行总线:ISA、EISA、MC、VESA 的共性
第一代并行总线的代表是 ISA、EISA、MC 和 VESA。它们的参数差异很大,但结构思路完全一致:把处理器的地址线、数据线、控制线引出来,扩展成一条可供多块板卡挂接的总线。
| 总线 | 数据宽度 | 数据速率 | 推出日期 | 备注 |
|---|---|---|---|---|
| ISA | 16 bit | 5 MBps | 1984 | PC/AT 时代的标准扩展总线 |
| EISA | 32 bit | 33 MBps | 1989 | 兼容 ISA,32 位化 |
| MC | 32 bit | 与 EISA 相当 | 1989 | 微通道总线 |
| VESA | 32 bit | 132 MBps | 1992 | 第一个局部总线 |
这个表格里最值得注意的不是速率数字,而是 VESA 的身份:它是第一个局部总线。所谓局部总线,就是把总线直接接到处理器引脚附近,不再像 ISA 那样绕远路。VESA 能跑到 132MBps,靠的就是“贴着处理器走”这一点。但这也暴露了第一代总线的根本问题——信号的功能和时序与处理器引脚密切相关,几乎是处理器信号的延伸和扩展,有些信号甚至直接依赖主板上的硬件资源,换个处理器型号,总线设计基本作废。
2.2 第二代并行总线:PCI 的通用化与 AGP、PCI-X 的分工
第二代并行总线的关键词是“通用”和“分流”。PCI 出现之前,总线是处理器的附属品;PCI 出现之后,总线第一次可以不受限于 CPU 的种类。这是第二代里最核心的进步。
| 总线 | 数据宽度 | 数据速率 | 频率 | 推出日期 | 备注 |
|---|---|---|---|---|---|
| PCI 1.0/2.0 | 32 bit | 133 MBps | 33 MHz | 1992 | 标准局部外围总线 |
| PCI 2.1 | 32 bit | 266 MBps | 66 MHz | 1995 | 频率翻倍 |
| AGP 1.0/2.0 | 32 bit | 266/533 MBps | 66/133 MHz | 1993/1999 | 图形专用端口 |
| PCI-X 1.0/2.0 | 64 bit | 266~533 MBps 及以上 | 66~533 MHz | 1999/2002 | PLL 提速 |
PCI 是一个标准的、与处理器无关的局部外围总线,通用性比第一代强很多。它在商用 PC 上的经典形态是 32bit、33MHz、133MBps,这个速率后来不够用了,就出现了两条演进路线:一条是给图形数据单开一条专用通道,于是有了 AGP;另一条是把 PCI 本身做快,于是有了 PCI-X。
AGP 的价值常被低估,它把图形数据传输从 PCI 总线上解放出来,让 PCI 的可用带宽不再被帧缓冲区吞掉。而 PCI-X 的改进更值得复习时逐条记:采用 PLL 使频率更高;在地址和数据基础上增加属性字段,从而高效管理缓冲区;用分离事务协议替代延迟事务协议,提高总线利用效率;不再依赖中断引脚,改用消息信号中断的带内体系结构,中断效率更高。这四条几乎是后来 PCIe 事务模型的预演。
2.3 第三代变革:串行化、点对点与链路通路
第二代再怎么优化,本质上还是并行总线:多条地址线、数据线、控制线同时传输,多个设备挂接在同一条总线上,带宽由所有设备共享。这种结构叫下挂式总线。提高数据宽度和频率确实能改善带宽,代价是电气负载增加、静态时序余量减少,可挂接的设备数量被不断压缩。到 PCI-X 2.0 时代,这条路基本走到头了。
| 参数 | PCIe 1.x | PCIe 2.0 |
|---|---|---|
| 通路数 | 1/2/4/8/12/16/32 路 | 与 1.x 相同的通路配置 |
| 数据速率 | 0.5~16 GBps(按通路数递增) | 同通路数下速率翻倍 |
| 频率 | 约 2.5 GHz | 更高 |
| 推出日期 | 2002 | 后续迭代 |
PCIe 在总线结构上采取了根本性变革,主要体现在两个方面:一是由并行总线变为串行总线,二是不再共享,采用点到点互连独享带宽。原来的并行结构里,桥下面挂连设备的一条总线,变成了一条链路;一条链路可以包含一条或多条通路。去掉了专用的数据、地址、控制和时钟线,总线上各种事务组织成信息包来传送。
学习时会有一个自然的疑问:PCIe 和 PCI 看起来差别这么大,为什么配置设备时很多思路还是 PCI 那套?答案是 PCIe 的地址空间、配置机制以及软件层面均保持与传统 PCI 总线兼容。这也是为什么下一章必须先回到 PCI 时代把平台架构讲清楚——PCIe 并没有把 PCI 的配置模型推翻,而是把它的传输通道换掉了。
3. PCI 时代的体系架构:两级桥、三种地址空间与配置机制
PCIe 的枚举和配置流程很大程度上继承自 PCI,所以复习 PCIe 之前必须先站稳 PCI 平台的结构。最常见的错误是直接跳到 TLP 和链路训练,结果遇到“配置空间从哪来”“基址寄存器怎么分配”这类问题就卡住。这一章把三级总线平台、三种地址空间、配置访问机制三件事理清,后面的内容就不悬空了。
3.1 FSB-PCI-ISA 三级总线平台与南北桥分工
最基本的 PCI 总线平台包含三级总线:FSB、PCI 和 ISA。FSB 是处理器子系统的总线,也叫 Host 总线,它的定义完全取决于系统所用的处理器;PCI 局部总线是一个完全与处理器无关的总线,不受限于微处理器的种类;ISA 总线是 IO 扩展总线,有些平台用 EISA 或 MC 替代。三条总线之间,通过相应的桥芯片连接。
这三级结构里,有两座桥是必须的。第一座是 Host 到 PCI 的桥,常称为主桥或 Host 桥,也就是俗称的北桥;第二座是 PCI 到 ISA 的桥,常称为扩展总线桥,也就是南桥。北桥负责处理器与 PCI 世界之间的协议转换和地址路由,南桥负责把低速的 ISA/IO 设备兜进来。
复习时可以把这座桥的职责概括成三件事:协议翻译、地址转发、空间隔离。CPU 访问一个 PCI 设备时,地址先经 FSB 到北桥,北桥判断这是 PCI 空间还是内存空间,再决定转发路径;南桥则屏蔽了 ISA 设备的差异。没有北桥,处理器无法理解 PCI 的事务规则;没有南桥,低速设备会拖累整个 PCI 总线。
3.2 三种地址空间:存储器、IO 与配置空间
x86 CPU 的内存与 IO 是独立编址的,IO 对应寄存器,内存对应 RAM。访问 IO 空间用 IO 读写指令,访问内存空间用内存读写指令。IO 读写一般用于低速传输状态、控制寄存器;MEMORY 读写用于高速传输,支持突发传输,可以在作为 Master 时与主机实现 DMA 传输。对于单个数据读写,IO 与 MEMORY 没有本质区别,只是命令不同。
PCI 设备支持三种类型的地址空间,分别是存储器、IO 和配置空间。它们的容量上限各不相同,这个容量差异本身就是高频考点。
| 地址空间 | 容量上限 | 说明 |
|---|---|---|
| 存储器空间 | 32 位设备可达 4 GB | 支持突发、DMA,高速传输 |
| IO 空间 | 设备视角可达 4 GB;x86 平台限制为 64 KB | 低速状态、控制寄存器 |
| 配置空间 | 理论上最大 16 MB | 用于分配前两种空间并完成设备配置 |
梳理下来会发现,IO 空间是最容易误解的一项。PCI 设备自身的 IO 地址空间最多可达 4GB,但 x86 CPU 只支持 64KB 的 IO 地址空间,所以许多平台将 PCI 的 IO 地址空间限制在 64KB。存储器和 IO 空间都是“设备要用、系统来分”的资源,而配置空间是分配这些资源的手段,它能把 PCI 设备的存储器地址空间和 IO 地址空间分别映射到系统存储器地址空间和系统 IO 地址空间。
3.3 配置空间与 0CF8h/0CFFh 访问流程
配置空间是理解 PCI/PCIe 枚举的钥匙。它的大小是可以精确算出来的:每系统最多 256 条总线,每条总线最多 32 台设备,每台设备最多 8 个功能,每个功能用 256 字节表示配置信息,所以配置空间上限是 256×32×8×256 字节,等于 16MB。
访问配置空间不是通过内存地址直接操作,而是通过两个固定的 IO 端口。在系统 IO 地址空间中,Host 桥内的 IO 寄存器固定占 0CF8h-0CFFh 地址;PCI-ISA 桥和 ISA 设备内 IO 寄存器的地址固定分布在 0-1KB 内;其余属于 PCI IO 空间。CPU 通过 0CF8h 上的地址端口和 0CFFh 上的数据端口访问 PCI 配置地址空间,先写配置地址,再读配置数据。
下面这段 C 风格的示意代码展示了这个访问过程,它把总线号、设备号、功能号和寄存器偏移拼成一个 32 位配置地址:
#define CONFIG_ADDRESS 0x0CF8 #define CONFIG_DATA 0x0CFC uint32_t pci_read_config(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg) { uint32_t addr = (1u << 31) /* 配置空间使能位,必须置 1 */ | ((uint32_t)bus << 16) /* 总线号:8 bit,最多 256 条 */ | ((uint32_t)dev << 11) /* 设备号:5 bit,最多 32 台 */ | ((uint32_t)func << 8) /* 功能号:3 bit,最多 8 个功能 */ | (reg & 0xFC); /* 寄存器偏移,4 字节对齐 */ outl(CONFIG_ADDRESS, addr); /* 把配置地址写入地址端口 */ return inl(CONFIG_DATA); /* 从数据端口读回配置内容 */ }这段代码的关键在于位段分配:bus 占 8 位、dev 占 5 位、func 占 3 位、reg 占 8 位,合起来正好对应配置空间“256×32×8×256”的四元组结构。写地址端口时最高位置 1,表示这是一次配置空间访问,而不是普通 IO 访问。
这套流程在系统软件里做的事是:读取 PCI 设备在配置空间里申请的存储器或 IO 空间大小,为它们在系统中分配一片独立的存储器空间或 IO 空间,然后把起始地址写入 PCI 配置空间中的基址寄存器。分配完成之后,设备才算真正“接入”系统。PCIe 的配置机制和软件流程与这套完全一致,所以这一节不是历史课,而是后续排查链路枚举问题的基本功。
4. PCIe 事务模型与速率计算:TLP、DLLP 和 8b/10b 带来的 20% 开销
如果说上一章解决的是“PCIe 怎么管理设备”,这一章解决的是“PCIe 怎么传数据”。PCIe 没有专门的数据、地址、控制和时钟线,所有信息都封装成包在链路上传输。包的格式、方向和开销,直接决定了带宽数字怎么算。这一章会把 TLP/DLLP 的分工、8b/10b 编码产生的额外开销、以及 x1 链路 256MB/s 这个经典数字全部拆开。
4.1 两种包:TLP 与 DLLP 的分工和传输方向
PCIe 的事务在物理层上由两种包承载:TLP 和 DLLP。TLP 是事务层包,负责携带真正的数据,比如读请求、写请求、完成报文;DLLP 是数据链路层包,负责反馈校验、流控制等信息,确保 TLP 能正确传输。两种包的职责完全不同,不能混为一谈。
| 包类型 | 所在层 | 主要职责 | 方向 |
|---|---|---|---|
| TLP | 事务层 | 携带读写数据与事务类型 | 发起方到接收方 |
| DLLP | 数据链路层 | ACK 确认、流控制、链路管理 | 接收方反馈回发起方 |
最容易忽略的是方向问题。对于同一个事务,TLP 和 DLLP 是向相反方向传输的:发送方发出 TLP,接收方验证后返回对应的 DLLP 作为反馈。两者不是“一前一后挂在同一个包流里”,而是构成一来一回的握手关系。理解这个反向关系,后面看链路带宽计算时就不会困惑为什么反向控制包没有把带宽吃掉一大半。
4.2 串行比特流里的 20% 开销:8b/10b 编码与有效带宽
TLP 包在物理层被转换成串行比特流,以 2.5Gbit/s(1.0 版本)的速率传输。因为链路不发送时钟信号,物理层采用 8b/10b 编码,每 8 位有效数据会编码成 10 位传输,由此产生了 20% 的额外开销。这是 PCIe 带宽计算里最核心、也最容易算错的一个数字。
以 x1 通道为例,计算过程如下:
链路原始速率:2.5 Gbit/s 8b/10b 编码效率:8 / 10 = 0.8 有效数据速率:2.5 × 0.8 = 2 Gbit/s 换算成 Mbit:2 × 1024 = 2048 Mbit/s 换算成字节:2048 / 8 = 256 MB/s所以 x1 通道的 PCIe 设备,TLP 包在单方向上的速率为 256MB 每秒。注意这里有一个二进制换算陷阱:从 Gbit 到 Mbit 是按 1024 换算的,不是按 1000,因此 2Gbit/s 等于 2048Mbit/s,而不是 2000Mbit/s。表里 x1 通路的 0.5GBps 通常按双向合计标注,单方向数据面速率才是 256MB/s。
多通路带宽可以直接复用这个结果。x4 的单向数据速率就是 256MB/s × 4 = 1024MB/s,x8 是 2048MB/s,x16 是 4096MB/s,对照 PCIe 1.x 表中按通路数递增的数据速率,方向完全一致。复习时只要先记住“x1 单向 256MB/s”这一个基准数字,其余通路全部可以现场推出来。
4.3 数据有效载荷占比与双向传输的影响
8b/10b 的 20% 开销是物理层编码层面的损失,但包内部还有一层开销——TLP 结构本身。数据有效载荷最多约占 TLP 的 99.3%,也就是说,TLP 的包头、包尾等控制字段占比很小,大部分带宽都花在数据搬运上。这个数字说明 PCIe 在设计上把包格式的开销压得很低,主要成本在编码层。
双向传输时,反向的 DLLP 会影响传输速率,但不会占很大一部分带宽。原因在于 DLLP 是短小的控制包,只做反馈校验和流控制,不像 TLP 那样携带大量数据负载。这也是 4.1 里强调方向问题的意义:如果 DLLP 和 TLP 同向“叠加”,带宽估算模型就要大变;正因为它们反向且短小,x1 单向 256MB/s 的估算才站得住。
复习到这里可以做一次对比:PCI 是下挂式共享总线,所有设备抢占同一条总线的带宽;PCIe 是点到点独享链路,每条链路只服务一对设备,带宽不会因为邻居设备的活跃而减少。再加上串行差分信号和包交换机制,PCIe 的总带宽随着通路数线性扩展,这是并行总线时代无法实现的。
5. 易漏点与易错点:复习 PCIe 时最容易忽略的四个细节
这一章把最容易翻车的地方集中列出来。每个易漏点都按“为什么漏、怎么补”的方式写清楚。复习时直接对照这一章自检,比重新翻书效率高得多。
5.1 易错点:8b/10b 的 20% 开销算成“2.5 减 0.2”
- 易漏点:计算 x1 单向速率时,把 2.5Gbit/s 直接乘 0.8 之后忘了再乘以 1024 做 Gbit 到 Mbit 的二进制换算,算得到 2000Mbit/s 而非 2048Mbit/s。
- 为什么漏:平时用十进制换算用习惯了,而总线速率里的 G/M/K 是二进制倍数。2048Mbit/s 和 2000Mbit/s 只差 2.4%,单独看不大,但多通路累计后误差会被放大。
- 怎么补:每次计算都强制写全三步:2.5 × 0.8 → 2 Gbit/s;2 × 1024 → 2048 Mbit/s;2048 / 8 → 256 MB/s。多写几遍后这个推导会变成条件反射,考试和现场估算都不容易错。
5.2 易漏点:PCI 的 IO 地址空间“最多 4GB”是设备视角,x86 平台实际只有 64KB
- 易漏点:看到 32 位 PCI 设备 IO 地址空间最多可达 4GB,就默认 x86 系统里能映射出 4GB 的 IO 空间。
- 为什么漏:IO 地址空间的上限取决于 CPU 的编址能力。x86 CPU 只支持 64KB 的 IO 地址空间,平台不可能超过 CPU 的能力去分配空间,所以现实中 PCI 的 IO 空间在 x86 上被限制在 64KB 以内。
- 怎么补:把两个“视角”分开记——设备侧配置寄存器能表达 4GB 的 IO 地址范围,系统侧平台实际分配给 IO 的窗口只有 64KB。做题时看到“PCI IO 空间可达 4GB”要立刻想到前提是设备视角,不是 x86 平台的实际约束。
5.3 易漏点:配置空间 16MB 的来源是四元组累乘,不是拍脑袋
- 易漏点:只记住“配置空间理论上最大 16MB”,考到计算依据时写不出 256×32×8×256 这个式子。
- 为什么漏:16MB 这个数字看起来像某个固定设计值,容易当成结论死记。实际上它是四层结构累乘的结果:每系统 256 条总线,每条总线 32 台设备,每台设备 8 个功能,每个功能 256 字节配置空间。
- 怎么补:把这四个数字和 0CF8h 配置地址的位段绑定记忆。2^8 × 2^5 × 2^3 × 2^8 = 2^24,正好 16MB;这也解释了为什么配置地址寄存器里 bus 占 8 位、dev 占 5 位、func 占 3 位、reg 占 8 位。位段就是空间结构在寄存器里的投影。
5.4 易漏点:DLLP 与 TLP 方向相反,不是同向“伴随”传输
- 易漏点:看链路图时把 TLP 和 DLLP 理解成两个同向传输的包,以为接收方只是“顺便收下”反馈控制包。
- 为什么漏:示意图经常把两种包画在同一条链路上方,方向箭头如果不细看,很容易默认它们朝同一方向走。但同一事务的 TLP 和 DLLP 恰恰是反向的:对端收到 TLP 后,要回传 DLLP 做确认和流控。
- 怎么补:用一次读事务走一遍完整流程:RC 发 TLP 读请求到设备,设备收到后返回包含数据的 Completion TLP,同时链路层伴随反向的 DLLP 做确认反馈。能画出这个一来一回的箭头,方向问题就彻底解决了。
5.5 易漏点:PCIe 的“兼容”只覆盖地址空间、配置机制与软件,不兼容物理信号
- 易漏点:把“与 PCI 兼容”理解成 PCIe 设备可以直接插到 PCI 槽位,或在物理层上兼容 PCI 时序。
- 为什么漏:“兼容”这个字眼在不同语境下含义不同。PCIe 软件层面兼容指的是系统软件枚举设备的流程、配置寄存器的布局沿用 PCI 体系;物理层已经完全换成串行差分信号和包传输,两者没有电气兼容性。
- 怎么补:复习时把兼容边界划清楚:地址空间兼容、配置机制兼容、软件可见行为兼容;链路层和物理层全部是新的。遇到“PCIe 是否兼容 PCI”这类判断题时,先问自己兼容的是哪一层,再下结论。
6. 查漏补缺:用一张复习表把 PCIe 笔记收口
复习到最后阶段,不需要再从头翻教材,而是要用一张表快速检查每个模块能不能合上。下面这张自查表覆盖了这份笔记的全部主线,每行都对应一个核心考点。复习时把它当索引,看到一行能准确说出细节,就算过关;说不出来,就回到对应章节补。
| 模块 | 核心考点 | 自检标准 |
|---|---|---|
| 第一代总线 | ISA/EISA/MC/VESA 共性 | 能说出“处理器引脚延伸”和局部总线概念 |
| 第二代总线 | PCI 通用性、AGP 分流、PCI-X 改进 | 能列出分离事务、属性字段、消息信号中断 |
| 第三代变革 | 串行化、点对点、链路与通路 | 能解释“一条总线变成一条链路” |
| 平台结构 | FSB/PCI/ISA 与南北桥 | 能画出三级总线和两座桥的拓扑 |
| 地址空间 | 存储器、IO、配置空间 | 能默写三种空间的上限与用途 |
| 配置访问 | 0CF8h/0CFFh 与基址寄存器 | 能写出配置地址的位段分配 |
| 包模型 | TLP 与 DLLP | 能画出同一事务两个包的反向传输方向 |
| 带宽计算 | 8b/10b 与 x1 单向速率 | 能完整推导 2.5×0.8×1024÷8=256 |
自查表之外,还有一个很有效的收口技巧:把每个模块的“数字”单独抽出来默写一遍。总线宽度、频率、速率、容量上限、配置空间大小、开销比例,这些数字是考频最高的部分,也是最容易含混的部分。我会按三条线默写:第一,三代总线的代表参数和推出时间;第二,三种地址空间的容量和访问手段;第三,x1/x4/x8/x16 的单向带宽依次推算。
这个方法是我吃过亏之后养成的。有一段时间复习 PCIe 只盯 TLP 结构和链路训练,觉得带宽计算太简单,结果一到综合题就把 x1 单向速率算成 250MB/s,错在 1024 的二进制换算上。从那以后,每次复习 PCIe 我都强制自己先走一遍“2.5×0.8×1024÷8=256”的推导,再进其它内容。这个习惯让我后来面对任何通路数的带宽估算都不慌。希望帮到你,也建议你把这条推导写进自己的复习清单第一行。
本文还有配套的精品资源,点击获取