CPU Register
寄存器是CPU内的“工作台”,拥有以下特征
- 存储数据
- 速度快:现代PC中速度最快的存储单元
- 容量小:通常是几十到几百个字节级别
- 临时性:铁打的寄存器,流水的数据
类比
以做饭为例
- 寄存器:正在处理的东西;手里握着的菜刀、调料勺,或者案板上正在切着的肉;马上就能用
- 缓存:随时要用的东西;调料罐,配菜盘;伸手就能够着
- 内存:这段时间要用的东西;橱柜,置物架;需要走过去拿,这段时间过去后全部扔掉
- 硬盘:也许能用到的东西;仓库,冷库;如果置物架上空了需要从仓库中补充,能永久保存食材
寄存器的物理形态
寄存器蚀刻在CPU芯片的最核心处,由晶体管紧密排列构成的超微型存储电路,是物理上距离计算核心最近的存储单元
物理位置
CPU内核大体分控制单元、运算单元和存储单元。寄存器就位于运算单元(ALU)旁边,直接与运算器相连,数据几乎无需传输延迟。一根铅笔尖大小的现代CPU芯片上,寄存器只占极小一角
微观结构
从电路层面看,每个寄存器位通常由6-8个晶体管组成的一个触发器(Flip-Flop)电路构成。这个电路能稳定维持0或1的状态,直到新数据写入。一个64位寄存器,就是64个这样的触发器并排,外加一些选通和控制电路
特征
速度最快、容量最小、功耗最大
虽然只有几KB,但寄存器是CPU里数量最多的的一类存储单元,可能多达几百个。代价是它的功耗密度极高,并直接决定了CPU的主频上限
- 极致速度:访问时间在皮秒级,通常只需要1个时钟周期。作为对比,即使是L1缓存也需3-5个时钟周期
- 晶体管巨大:为追求极限速度,设计它的晶体管尺寸比缓存更大,驱动电流更强
物理实现
在芯片版图上,几十上百个寄存器会被组织成一个规则的寄存器堆(Register File)。它像一个表格,通过地址线选择读写哪个寄存器,数据线则并行输出
同一种寄存器标准,可能有完全不同的物理实现
不同架构有不同的设计,标准是公开的,实现则由各个硬件厂商自由发挥
- Intel可能用高速SRAM电路来实现
- AMD可能用另一种定制的寄存器堆电路来实现,只要存取速度和功耗达标
Register File
寄存器堆,或称寄存器文件,是CPU内部专门用来存放寄存器的一块高速存储电路,是一组寄存器组成的集合
例如
RAX
RBX
RCX
RDX
...
在硬件里,它们不是一个个分散的东西,而是组成了一个整体
Register File
+-------------------------------+
| R0 | R1 | R2 | R3 | ... |
+-------------------------------+
整个模块就叫Register File
假设有一条指令
ADD R1, R2, R3
意思是
R1 = R2 + R3
CPU会这样做
Register File
┌────────────────────┐
R2 >│ │> 数据A
R3 >│ │> 数据B
└────────────────────┘
v
ALU(+)
v
┌────────────────────┐
│ Register File │
└────────────────────┘
^
写回 R1
整个过程中:
- 从寄存器堆读出R2
- 从寄存器堆读出R3
- ALU做加法
- 结果写回寄存器堆中的R1
如果每个寄存器都是单独设计,CPU就需要大量独立线路,大量控制逻辑
所以工程师把它们做成寄存器堆
寄存器堆相较于寄存器在物理上是特别的:
- 多端口并发
- 普通内存(RAM)或缓存(Cache),在同一个时钟周期内,通常只能读一个地址,或者写一个地址(单端口/双端口)
- 寄存器堆支持多端口(Multi-porting),就像上述汇编指令,单条指令读取两个源寄存器,并且在算完后同时写入一个目标寄存器,不用排队
- 硬件实现:寄存器堆内部布满了复杂的并行线路。一个现代处理器核心的寄存器堆,通常拥有2~4个读端口(Read Ports)和1~2个写端口(Write Ports)
- 空间局部性
- 在物理芯片的版图(Layout)上,寄存器占据着最核心的位置,它紧贴在ALU旁边
- 因为距离短,所以延迟低。数据从寄存器堆流向ALU,再从ALU算完流回寄存器堆,走过的物理距离只有微米级别。这就是为什么寄存器堆的访问延迟是0个时钟周期(通常在当前周期内就就能直接带入计算单元)
- 电路结构不同
- 内存(DRAM):用1个晶体管 + 1个电容存1位(Bit)数据。电容会漏电,需要不断刷新,速度慢
- 寄存器堆(Register File):通常基于触发器(Flip-flop)或特殊的64位晶体管/8晶体管SRAM单元。它不需要刷新,电信号极其稳定。加上为了实现多端口,他周围要包裹大量的选通开关(译码器和多路选择器)
- 代价就是:功耗极高,发热量大,且非常占芯片面积
- “架构”和“微架构”的连接桥梁
- 现代CPU有两套寄存器堆
- ARF(Architecture Register File),逻辑寄存器堆,可见寄存器堆
- PRF(Physical Register File),物理寄存器堆,底层真正存在的,高达100~200多个单元的超大寄存器池
- 特别的映射:CPU内部有一个叫RAT(Register Alias Table,寄存器别名表)的路由机构。当一条指令要读写寄存器堆时,RAT把逻辑寄存器瞬时映射到物理寄存器堆里的某个空闲格子上
- 现代CPU有两套寄存器堆
现代高性能CPU中,逻辑寄存器堆在物理上是不存在的,它被打散到了一个更大的物理寄存器堆中;但在一些老旧的、或者极简的嵌入式芯片中,逻辑寄存器堆就是物理存在的
现代高性能CPU中,逻辑寄存器知识一个“虚像”(概念上成立),在引入乱序执行(Out-of-Order)和寄存器重命名(Register Renaming)的现代芯片里,切开硅片,用电子显微镜找,是找不到一个只装RAX, RBX, RCX等的独立硬件区域的,此时的逻辑寄存器堆,纯粹是靠映射表(RAT)维护的一套逻辑幻觉
物理上,CPU内部只有一个巨大的、统一的物理寄存器堆(PRF),里面包含若干的格子,通过物理编号进行区分
CPU内部有一张表格叫RAT(Register Alias Table,寄存器别名表)
所谓的RAX, RBX,只是16个名字
它的工作流程如下:
当mov rax, 42时:
- RAT检查PRF中发现#73寄存器是空闲的
- RAT中会有RAX现在指向#73
- 接着将42写入#73中
当下一行代码add rbx, rax时
- RAT查表得知RAX的最新数据在#73
- CPU直接去读#73
在这里,物理寄存器堆是唯一的实体物质。所谓的“逻辑寄存器堆”,只是RAT映射表在特定时刻动态映射出来的一组指针关系。它在物理上没有自己的专属硬件阵列
现代高性能CPU,这一套叫做统一物理寄存器堆架构(Unified PRF Architecture) + 寄存器重命名(Register Renaming)
对于简单/低功耗芯片,逻辑寄存器堆是真实存在的物理实体
比如单片机8051,或者智能手表/物联网设备里最基础的ARM Cortex-M0核心,在这些芯片中
- 没有乱序执行,没有重命名检查,为了省电,指令都是串行执行的(顺序执行)
- 硬件直接对应,编译器写了
R0寄存器,电信号就直接打进硬件上名为R0的那组触发器里
看不到,更测不到
一个寄存器的整体可能只有几百平方微米。普通光学显微镜看不清,工程上需要用电子显微镜,而逻辑分析则靠片上调试接口来读取
这篇博客展示了8086CPU的寄存器,实现方式和工作原理
https://www.righto.com/2020/07/the-intel-8086-processors-registers.html
寄存器在计算机存储体系中的位置
寄存器是CPU内部的超小型存储系统,但通常不被当作完整存储层级来讨论
从广义上来说,寄存器满足“能存数据”,当然算作存储系统的一环,但是它是很特殊的
寄存器
v
Cache(L1/L2/L3)
v
主存(RAM)
v
外存(SSD/HDD)
它的特殊体现在:
1. 它不是内存模型的一部分
RAM有地址空间,可寻址,可统一访问,寄存器没有统一地址空间(至少对程序员不可见)
2. 它是CPU内部状态机的一部分
寄存器更像CPU运行状态的组成元素,例如:
- PC:程序执行到哪里
- FLAGS:上一次运算结果
- GPR:当前变量
本质不是存储系统,而是执行系统的一部分,或者说工作区
寄存器的核心分类
需要明确的是,大多数教材和应用层汇编代码中提到或使用的大多数寄存器都是程序员可见(programmer-visible)的寄存器,也就是可编程寄存器
CPU中同样存在着大量程序员完全看不到、也无法直接操作的寄存器
所以寄存器分成两大类
- programmer-visible/programmable/architectural registers:这些都可以通过汇编指令直接或间接使用,它们是ISA(Instruction Set Architecture)的一部分
- programmer-invisible/hidden/microarchitectural registers:程序员看不到,无法直接用指令操作
Microarchitectural Registers
这些不可见寄存器的意义是在不改变上层软件生态的前提下,压榨出芯片极限的硬件性能,它们在各个芯片商的SDM依据类型有不同详细程度的介绍
比如,“半隐藏”的寄存器用于OS内核编写,如控制寄存器(CR0~CR4),全局描述符表寄存器(GDTR),页表基址寄存器(CR3),以及大量的MSR(Model Specific Registers, 特定模型寄存器);这些寄存器会被详细记录,它们是给操作程序内核开发者使用的,用于管理内存、处理中断和监控功耗
关乎核心微架构的“纯隐藏”寄存器(如重命名寄存器、保留站/ROB中的状态寄存器),这些是各个厂商在同一公开标准下的私有实现,一般只做原理性的科普,不提供任何细节描述,它们是各个厂商的商业机密,迭代频繁
以下是一些微架构寄存器:
- 重命名寄存器:ISA规定了通用寄存器的数量,如果代码频繁读写某一个寄存器,前后两条指令就需要排队执行;CPU内部设计了数百个隐藏的物理寄存器池,硬件内部的重命名逻辑会自动把每次对RAX的操作映射到不同的隐藏物理寄存器上,让原本需要排队的指令可以乱序执行
- 流水线锁存器:现代CPU是流水线工作的,一条指令会被切分成取指、译码、执行等阶段。为了在流水线各站间传递数据,每个阶段之间都有大量的锁存器,把上一步的结果锁存下来传给下一步。这些流水线寄存器几乎无处不在,数量极多,是寄存器堆之外的最大头,比如
IF/ID,ID/EX,EX/MEM,MEM/WB - 微架构隐式寄存器:当修改一个段寄存器(如CS/DS),或者加载一条页表时,CPU内部有一块隐藏的影子寄存器(Shadow/Descriptor Cache Registers)。硬件会自定把内存里的段描述符、页表属性直接缓存到这些隐藏寄存器里。下次CPU寻址时,直接读隐藏寄存器,速度是纳秒级的,而不用每次去查内存
- 预测与投机寄存器
- 重排序缓冲区(ROB)
- Load Buffer
- Store Buffer
- Branch Predictor状态
Architectural Registers
了解完微架构寄存器,架构寄存器就眉清目秀的多了
架构寄存器是写在ISA里的,芯片厂商给软件开发者的标准公开接口
通用寄存器(General Purpose Registers)
这是最常用的寄存器,用来存:
- 临时变量
- 函数参数
- 返回值
- 地址(指针)
| 寄存器名 | 低32位 |
指令指针(IP/PC)
栈指针(SP/Stack Pointer)
基址寄存器(BP/FP)
状态寄存器(FLAGS/CPSR)
段寄存器
系统专用功能寄存器
这是一类半隐藏的寄存器,通常在CPU Ring 0级别下使用