第一章:计算机体系结构概述
大家好,我是老张。在芯片设计这行摸爬滚打了十几年,今天咱们聊聊计算机体系结构最基础的东西。说实话,很多新人一上来就追着RISC-V、乱序执行这些高大上的概念跑,结果连冯·诺依曼结构都说不清楚。我个人觉得,地基不牢,后面全是空中楼阁。
1.1 计算机发展简史:从算盘到AI芯片
计算机的发展,说白了就是人类对「算得更快」的执念。
最早是机械时代。1642年帕斯卡做了台加法器,只能算加减。后来莱布尼茨改进了一下,能算乘除了。但真正意义上的通用计算机,得等到1946年的ENIAC。那家伙占地170平米,重30吨,每秒钟只能做5000次加法。我当年在实验室看到ENIAC的照片时,第一反应是:这玩意儿散热得用空调吧?
真正改变格局的是1945年冯·诺依曼提出的存储程序概念。他写了份报告,核心就一句话:把程序和数据存在同一个存储器里。这个思想太牛了,直到今天,你手机里的ARM芯片、电脑里的x86芯片,本质上还是这套逻辑。
为什么会这样?因为冯·诺依曼结构把「指令」和「数据」统一编码,让计算机可以自我修改程序。这在当时是革命性的。当然,这也带来了著名的「冯·诺依曼瓶颈」——CPU和内存之间的数据搬运速度跟不上处理速度。我在做嵌入式系统时,经常被这个瓶颈卡得死死的。
关键里程碑:
- 1946年:ENIAC诞生,第一台通用电子计算机
- 1945年:冯·诺依曼提出存储程序概念
- 1971年:Intel 4004,第一颗商用微处理器
- 1980年代:RISC架构兴起(MIPS、ARM)
- 2000年代:多核处理器成为主流
- 2020年代:AI加速器(GPU、NPU)爆发
1.2 冯·诺依曼架构:五大部分与核心思想
冯·诺依曼架构有五个核心部件,我习惯用「输入-存储-控制-运算-输出」来记。你想想看,任何计算机都逃不出这个框架。
| 部件 | 功能 | 我踩过的坑 |
|---|---|---|
| 存储器 | 存放程序和数据 | 曾经因为内存地址对齐问题,导致数据读出来全是乱的 |
| 控制器 | 从存储器取指令,译码,控制其他部件 | 微程序控制器的设计,让我熬了好几个通宵 |
| 运算器 | 执行算术和逻辑运算 | ALU的进位链优化,直接影响主频 |
| 输入设备 | 将外部信息送入计算机 | 键盘中断的优先级设置,搞错过一次 |
| 输出设备 | 将结果呈现给用户 | 显示器的刷新率与帧缓冲的同步,是个坑 |
这里有个关键点:冯·诺依曼结构是「指令流驱动」的。CPU从内存取一条指令,执行,再取下一条。这个过程叫「取指-译码-执行」循环。嗯,这里要注意,现代CPU虽然加了流水线、乱序执行,但本质还是这个循环。
避坑指南:我曾经在设计一个简单的8位CPU时,忽略了指令对齐问题。结果取指令时地址没对齐,读出来的指令码全是错的。后来加了个地址对齐检测模块才解决。所以,新手做CPU设计,第一步先把取指逻辑搞扎实。
1.3 CPU的基本组成:内部到底有什么?
CPU内部,说白了就是一堆寄存器、运算单元和控制逻辑的组合。我习惯把它拆成三块来看:
- 数据通路(Datapath):负责数据的流动和运算。包括寄存器堆、ALU、乘法器、移位器等。
- 控制单元(Control Unit):负责指挥数据通路怎么干活。它根据指令译码结果,生成各种控制信号。
- 存储单元(Storage):包括寄存器、缓存(Cache)、TLB等。注意,这里的存储是CPU内部的,不是主存。
我举个例子。一条加法指令「ADD R1, R2, R3」,CPU会这样工作:
- 控制单元从内存取指令,译码发现是加法
- 控制单元告诉寄存器堆:把R2和R3的值送到ALU
- ALU执行加法,结果写回R1
- 程序计数器(PC)加4,指向下一条指令
你看,就这么简单。但实际芯片里,这一步要拆成好几个时钟周期。我在做流水线设计时,经常要处理数据冒险——比如上一条指令的结果还没写回寄存器,下一条指令就要读。嗯,这就是经典的RAW(Read After Write)冲突。
重要提醒:CPU的时钟频率不是越高越好。我见过有人为了跑高频,把流水线级数加到20级,结果分支预测失败一次,要清空20级流水线,性能反而下降了。频率和IPC(每时钟周期指令数)要平衡。
1.4 核心知识体系:一张图看懂
下面这张图是我自己画的,把本章的核心知识点串起来了。你仔细看,所有内容都围绕「指令处理」这个中心展开。
这张图里,我特意把「冯·诺依曼架构」放在底部作为基石。你想想看,无论数据通路、控制单元还是存储单元,最终都服务于「存储程序」这个核心思想。指令和数据放在同一个存储器里,CPU通过PC指针一条条取出来执行。
1.5 避坑与经验总结
最后,分享几个我这些年积累的经验:
- 别小看取指阶段:很多新手设计CPU,把精力都放在ALU和流水线上,结果取指逻辑写得太简单,导致指令预取和分支预测根本没法做。取指是整个流水线的源头,源头堵了,后面再优化也没用。
- 寄存器堆的读写冲突:同一个时钟周期内,既要写寄存器又要读寄存器,怎么办?我习惯用「写优先」策略——先写后读,保证读到的数据是最新的。
- 控制信号的时序:控制单元生成的控制信号,必须严格对齐时钟沿。我曾经因为一个控制信号晚到了半个周期,导致ALU算出了错误结果。后来加了时序约束才搞定。
一句话总结:计算机体系结构,核心就是「指令怎么被处理」。冯·诺依曼架构定义了框架,CPU内部的数据通路、控制单元、存储单元协同工作,完成取指-译码-执行这个循环。把这个循环吃透了,后面学流水线、乱序执行、多核,都会轻松很多。
公众号:蓝海资料掘金营,微信deep3321