# CPU 如何理解世界

> 同一段 0101，可以是数字、指令或像素——解释规则决定含义。

- 作者：David（道雾轩）
- 专栏：从 Bit 到 AGI（https://daiw.org/manual/bit-to-agi.md）
- 最后更新：2026-07-24
- 原文：https://daiw.org/manual/bit-to-agi/01-bits/how-cpu-understands-world
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

内存里某地址的 8 个字节是 `01001000 01100101 01101100 01101100 01101111`——它可以是整数 72、字符 `'H'`，也可以是某条机器指令的操作数。**硬件本身不自带「意义」**，CPU 靠**指令集**和**程序约定**给 bit 模式赋予含义。

本篇说明：取指、译码、执行如何运转；数字、指针、指令如何在同一套 bit 流里共存。

## 直觉：同一本字典，不同读法

一串汉字「银行」：在金融文章里是金融机构，在地理文章里可能是河岸。bit 串也一样：`0x48` 在 ASCII 表是 `'H'`，在 `int8` 解释下是 72，在机器码里可能是某条 `mov` 的一部分。**解释上下文**（类型、段寄存器、当前指令）决定读法。

## 定义：冯·诺依曼架构要点

1. **程序与数据同存**于可寻址内存（统一地址空间）。
2. **PC**（Program Counter）指向下一条要执行的指令地址。
3. **指令周期**：取指（Fetch）→ 译码（Decode）→ 执行（Execute）→ 写回（Writeback），现代 CPU 流水线并行多指令，主频常见 **2–5 GHz**（每核每秒数十亿周期）。

典型 64 位 x86-64 寄存器：`RAX`、`RBX`… 各 64 bit；通用寄存器 **16 个**量级，远小于内存（GB 级）——所以要有 Cache 与内存层次（后文详述）。

## 例子一：加法在硬件里是什么

伪代码 `a = b + c`，编译后可能变成：

```asm
; 示意：b 在 RDI，c 在 RSI，结果写 RAX
mov  rax, [rdi]   ; 从内存读 b 的 8 字节到 RAX
add  rax, [rsi]   ; RAX += 内存中的 c
mov  [rdx], rax   ; 结果写回 a 的地址
```

`add` 在硅片里是**加法器**：对两个 64 bit 输入逐位全加器链，带进位，**1 个时钟周期**量级（实际还依赖流水线深度）。没有「加」这个中文字，只有 bit 模式 `000000xx` 触发 ALU 走加法通路。

## 例子二：同一段内存，两种视图

```python
import struct
# 4 字节：小端存 int32 值 16909060 (0x01020304)
raw = bytes([0x04, 0x03, 0x02, 0x01])
as_int = struct.unpack('<i', raw)[0]
as_bytes = list(raw)
print(as_int, as_bytes)  # 16909060 [4, 3, 2, 1]
```

C 语言里 `(int*)p` 与 `(char*)p` 访问同一地址，读出的「意义」不同——这就是**类型 punning** 的底层原因（严格别名规则在语言层限制此类写法）。

## 量化：一次「理解」有多快？

| 指标 | 典型值（桌面 CPU，2024 量级） |
| ---- | ----------------------------- |
| 主频 | 3–5 GHz |
| 每周期 IPC | ~2–4（依赖 workload） |
| L1 Cache 延迟 | ~4 cycles ≈ **1 ns** |
| 主内存 DRAM 延迟 | ~100 ns |
| L3 命中 vs 内存 miss | 差 **30–50 倍** 很常见 |

CPU「理解」世界的方式是：**在纳秒级把 bit 当作指令执行，或当作数字运算**；慢的是等内存（AI 训练里 GPU 也在和同样的问题搏斗）。

## 分支与预测：世界不只有线性

```python
def abs_val(x):
    if x >= 0:   # 编译成 cmp + 条件跳转
        return x
    return -x
```

`if` 会变成「比较 + 跳转指令」。分支预测错一次，流水线 flush 可能损失 **10–20 周期**。循环友好的数值代码（矩阵乘）比分支杂乱的业务逻辑更「CPU 友好」——后面 GPU/SIMD 篇会呼应这一点。

## 指令集：x86 与 ARM 的「方言」

同一串 bit，在 **x86-64** 与 **ARM64** 上可能是不同指令——这叫 **ISA**（Instruction Set Architecture）。Apple M 系列跑 ARM64；云服务器 x86 居多；AWS Graviton 是 ARM。Python/PyTorch 轮子要分平台编译，因为机器码 bit 模式不兼容。

典型 x86 指令长度 **1–15 字节** 变长；ARM64 常固定 **4 字节**，解码更简单，功耗更低。AI 推理在 GPU 上跑 CUDA（NVIDIA 私有 ISA），CPU 负责喂数据——**heterogeneous computing** 里每种处理器各认各的 bit 方言。

想深入到具体指令，各家 ISA 的官方参考手册：

- **x86 / x86-64**：[Intel® 64 and IA-32 Architectures Software Developer's Manual](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html)（Intel 与 AMD 共同定义 x86-64，Intel SDM 是最常用的一份）。
- **ARM64（AArch64）**：[Arm Architecture Reference Manual for A-profile](https://developer.arm.com/documentation/ddi0487/latest)（即 Arm ARM，编号 DDI0487，涵盖 A64 指令集）。
- **CUDA（NVIDIA 私有 ISA）**：[PTX ISA](https://docs.nvidia.com/cuda/parallel-thread-execution/)（PTX 是对外公开的虚拟 ISA；真正落到硬件的 SASS 未完整公开）。

## 栈、堆与寄存器：bit 住在哪里

函数调用时，返回地址、局部变量压在 **栈**（向下增长）；`malloc`/`new` 的对象在 **堆**。寄存器只有 **几十×64 bit**，装不下 16 GB 模型——大数组必在内存，寄存器暂存循环变量和指针。

```c
// 示意：指针 p 本身是 8 字节，指向堆上 1e9 个 float 的的首地址
float *p = malloc(1e9 * sizeof(float));  // ~4 GB
```

CPU「理解」指针 = 把 8 字节当作无符号整数地址，经 MMU 查页表得到物理地址，再读 DRAM——**每一次数组访问都是 bit 地址解码**。

## 微架构一瞥：超标量与乱序

现代 CPU 每周期可 **退休多条指令**（IPC>1）：乱序执行在依赖允许时先算后面的 independent 指令。分支预测错则 flush **10–20 周期**——Attention 里 `if (mask)` 少，GEMM 内层循环无分支，故 **AI 热点 kernel 喜 CPU/GPU 无分支 SIMD**。

**Out-of-order** 不改变语义：as-if sequential，程序员仍见单线程内存模型（C11 memory_order 另论）。多线程写同一 cache line 才需 atomic——PyTorch 分布式训练 all-reduce 走 NCCL，不靠 CPU 乱序救场。

## 场景实战：用 bit 视角读一条新闻

「某公司发布 405B 参数模型」——你应立刻换算：**FP16 约 810 GB 权重**，INT4 量化约 **200 GB**，单卡不可能，推理需 **多卡 TP 或 MoE 激活子集**。「在 10 TB 文本上训练」——UTF-8 磁盘 **~10 TB**，token 数约 **2–4 T**（视语言混合），训练 FLOPs 量级 **$6ND$**（Kaplan，$N$ 参数 $D$ token）。**新闻里的每个形容词都可换成 byte 和 FLOPs**。

## 常见误区

1. **「CPU 直接运行 Python」**——Python 字节码由解释器或 JIT 转成机器码；你写的是语义层，CPU 只看机器码。
2. **「64 位 CPU 只能算 64 位以内的数」**——寄存器宽度是一次运算的「车道宽」；大整数、浮点、向量有专用指令扩展。
3. **「内存里某处放着字符串 'Hello'」**——存的是编码整数序列；是 `'H'` 还是 72，取决于 load 指令后怎么用。

## 动手试一试

观察整数与 ASCII 的同一性（仅用于理解，勿在生产搞混类型）：

```python
n = 0x48656C6C6F  # "Hello" 若按大端打包成 5 字节需截断，这里演示逐字符
chars = [0x48, 0x65, 0x6C, 0x6C, 0x6F]
print(''.join(chr(c) for c in chars))
print(sum(c << (8*i) for i, c in enumerate(reversed(chars))))
```

## 小结

CPU 通过**指令集架构**把 bit 解释为操作与操作数；程序通过**类型与 ABI 约定**把 bit 解释为整数、浮点、指针、字符串。AI 推理程序最终也只是一串这样的指令，在数十亿晶体管上驱动矩阵运算。

下一篇：[整数如何表示](https://daiw.org/manual/bit-to-agi/01-bits/integer-representation)——有符号、无符号与溢出的精确规则。
