📖 人物:冯·诺依曼(John von Neumann) 冯·诺依曼是 20 世纪罕见的天才:数学家、物理学家、计算机科学家、博弈论创始人,还参与了曼哈顿计划。1945 年他起草的《关于 EDVAC 的报告初稿》,首次系统描述了「存储程序」计算机的结构。这份报告影响如此深远,以至于后人把这套结构以他的名字命名。
🎯 本章学习目标
- 记住计算机的五大部件:运算器、控制器、存储器、输入、输出。
- 理解「存储程序」思想为什么是革命性的。
- 理解数据流与控制流的区别,以及总线的作用。
- 能把前面学的零件(加法器、寄存器、触发器)对应到五大部件上。
7.1五大部件:一台计算机的蓝图
1945 年,约翰·冯·诺依曼在一份报告草案中,给出了通用计算机的完整设计。他把计算机分成五个部分:
| 部件 | 英文 | 职责 | 对应我们学过的零件 |
|---|---|---|---|
| 运算器 | ALU | 做算术、逻辑运算 | 加法器、逻辑门 |
| 控制器 | Control Unit | 指挥各部分按顺序工作 | 译码器、时序电路 |
| 存储器 | Memory | 存放程序和数据 | 寄存器、内存单元 |
| 输入设备 | Input | 把外界信息送进来 | 键盘、鼠标等 |
| 输出设备 | Output | 把结果送出去 | 屏幕、打印机等 |
这五个部件中,运算器和控制器合在一起,就是今天说的 CPU(中央处理器);存储器就是内存;加上输入输出设备,就构成了一台完整的计算机。
为什么恰好是「五」个部件?这个划分其实深藏功力,值得逐个推敲。存储器必须独立——程序和数据都要有地方放;运算器必须独立——「算」是核心动作;控制器必须独立——多步骤的先后顺序需要指挥。而输入输出为什么也单独成类,不和存储器合并(毕竟数据都要「进出」)?因为它们面对的是两个世界:存储器交换的是 0/1 数字信号,I/O 设备交换的却是按键、光、声这些物理量——中间隔着模数/数模转换,隔着不同的速度等级(键盘几毫秒一个键,CPU 一纳秒一拍),也隔着完全不同的工程问题。把「对内记账」和「对外打交道」分开成类,是抽象上的清醒。
再把前六章的零件对号入座,你会发现自己已经攒齐了全部砖瓦:运算器就是第 5 章的加法器/逻辑门阵列(配上第 5 章的 C、V 标志);控制器内部是第 5 章的译码器(翻译指令编码)加上第 6 章的时序电路(按拍推进);存储器的顶层概念是第 6 章的寄存器排成阵(具体物理实现第 9 章讲);寄存器堆是 CPU 的工作台。还没学的只剩两块:输入输出设备的物理原理(第 14 章),以及把这些部件「串成一台会自己干活的机器」的完整循环——那正是本章后半场的主题。
📐 例题 1 五大部件职责判断五连
以下五个工作场景,请指出主要由哪个部件负责:(a)把角度传感器送来的电压转成数字量送进主机;(b)计算两组导航参数之和并判断有无溢出;(c)记住「程序该执行第几条指令」;(d)把算好的姿态数据变成屏幕上的字符;(e)按指令内容发出「让存储器执行读」的命令。
思路 抓住各部件的职责关键词:输入=物理量→0/1;运算器=算与逻辑;控制器=发号施令、决定顺序;存储器=存内容;输出=0/1→物理量。容易混的是「记指令序号」和「发命令」——一个偏「存」(虽在 CPU 内),一个偏「指挥」。
解 (a)物理量→数字量,是输入设备(含其模数转换)的活。
(b)「算」且「判断溢出」,是运算器(ALU+标志位)的活。
(c)「记」指令序号——存的是内容(PC 寄存器的值),属于存储性质的寄存器(CPU 内的存储细胞;程序计数器本身是控制器用来推进流程的关键寄存器)。
(d)0/1→字符光点,是输出设备的活。
(e)「发出命令」,是控制器的活。
答:输入、运算器、(CPU 内的)寄存器/存储职能、输出设备、控制器。 ⚠ 易错点:(c)最容易答成控制器——PC「被控制器使用」不等于「PC 本身是指挥者」;它存的是数据(一个地址值),本质是存储职能,只是位置在 CPU 内。
航空工程师读这节应当格外亲切:机载电子设备的外场可更换单元(LRU)就是按功能切块的——信号处理单元里能找到运算器,接口单元里全是输入输出电路,电源模块独立成块。冯·诺依曼的五分法之所以历久弥新,正因为它切在「职责的自然接缝」上:按功能分块、按接口互联,这一思想从电路板一直贯通到整个系统的架构。
还要澄清一个高频误区:CPU ≠ 运算器。运算器只是 CPU 的「一半」,另一半是控制器;此外 CPU 里还包着一批寄存器(第 6 章的主角)。把 CPU 等同于 ALU,就像把一支施工队等同于夯机——夯机确实在干活,但「今天先打哪块地基」是队长的调度。分清「干活的」与「调度的」,是本章的关键素养。
7.2存储程序:革命性的思想
冯·诺依曼结构最核心、最革命的一点,不是「有五个部件」,而是 存储程序(stored program)思想。
在冯·诺依曼之前,计算机是「死」的:要让一台机器算不同的问题,得重新插拔电线、改动硬件,换一次任务就像重新造一台机器。冯·诺依曼的洞见是:
核心思想:程序也是数据 把「程序」(要执行的指令序列)当作普通数据,存进存储器里,和它要处理的数据放在同一个仓库中。这样,换任务只需换存储器里的内容,硬件完全不用动。计算机从此从「专用机器」变成了「通用机器」——同一台硬件,靠换程序就能干任何事。
这个思想的美妙在于一个看似矛盾的点:指令和数据,在存储器里长得一模一样,都是 0 和 1。怎么区分哪段是指令、哪段是数据?答案是:看它们「在什么时候、被谁读取」——控制器在「取指」阶段读到的,就当作指令;运算器在「取数」阶段读到的,就当作数据。同一段 0/1,身份由上下文决定(这个伏笔第 11 章会展开)。
🧠 一句话记忆 存储程序 = 把程序当数据存起来,换程序不必换硬件。这是计算机「通用」的秘密。
「换任务要重新接线」离今天的体验太远,值得用一台真实的机器把它讲实。ENIAC(1946 年,世界上第一台通用电子计算机)正是「插线板时代」的巅峰之作:一万八千多只电子管堆出的运算能力惊人,但它「认任务不认人」——每换一个问题,工程师们要手动设置成百上千个开关、重插成百上千根线缆,动辄数小时甚至数天。这意味着机器算一个新问题,光「布线改配置」的时间就可能超过真正的计算时间。而在存储程序结构下,同一个动作变成「把新程序写进存储器」——毫秒到秒级的事。一个数量级接一个数量级的差距,就是「革命性」三个字的分量。硬件从「为每个任务定制」中彻底解放出来,从此只需把硬件做得更快,而「让机器干什么」交给软件去表达。
由此还催生了一个全新职业与产业:程序(软件)从此是可以独立制造、独立交付的产品。硬件厂不再需要为每个应用重排电路,而是一批批造通用机器;写程序的人在上面定义机器的行为。今天你升级一个应用商店里的软件、下载一个新固件包,本质上都是「换存储器里的内容,硬件一字不动」——这正是 1945 年那份报告播下的种子。在航空领域,机载设备的功能升级走的是同一条路:加改装常常不是换板子,而是加载新版机载软件——硬件不变、程序重灌,功能焕然一新;相应的适航审定关注点,也从「电路改没改」延伸到了「软件版本是否受控」。
顺带把「换存储器里的内容」这个说法落到实处:程序平时躺在磁盘这类「仓库级的存储」里,开机或启动应用时,由一个加载过程把它复制进内存(RAM),控制器才开始逐条取指执行;而最先执行的「把加载器自己跑起来」的那小段程序,则由更底层的引导(bootstrap)过程完成——先有一小段固化在只读存储里的代码负责「把更大的程序搬进内存」,接力棒一层层交下去,直到整个操作系统站起来。你每天按下电源键后的那几秒黑屏等待,正是这场接力赛的现场。第 12 章讲操作系统时,这条加载链会正式展开。
「程序也是数据」还有一条不那么温馨的推论:既然指令和普通数据躺在同一仓库、长得一模一样,那么被当作数据写入的内容,也可能在某一天被当作指令执行——一个被引导去「读入并执行」的恶意数据文件,就是病毒能够存在的根本原因。存储程序给了机器通用性,也给了「程序被程序改写」以可能。这既是动态加载、自我修改程序等技术的源头,也是安全防护必须面对的底层现实。
📐 例题 2 「存储程序」判断四连
判断下列系统是否体现「存储程序」思想,并说明理由:(a)某计算器,按功能键直接做四则运算;(b)某通用计算机,从磁盘加载不同软件做打字或算账;(c)某数控机床,从存储卡读入加工程序加工不同零件;(d)某老式电子密码锁,密码错误三次就锁死,功能出厂固化不能改。
思路 判据只有一条:「换功能」是否只需换存储器里的内容,而硬件不动。
解 (a)功能固定在按键电路上,算「专用电路」,不是存储程序。(b)同一硬件、换程序换任务,是存储程序的标准形态。(c)加工程序存在存储卡里,换零件只换卡里的内容——存储程序思想在工业控制上的直接应用。(d)「三次锁死」的逻辑焊死在电路里,改功能要动硬件,不是存储程序。
答:(b)(c)是;(a)(d)不是。 ⚠ 易错点:别把「有芯片、有存储」就当存储程序——关键是流程(程序)本身存在可更换的存储器里,而不是电路结构固定、只存几个参数。
最后补一个高阶辨析:哈佛结构(Harvard architecture)——指令与数据分开存放、分开走线,甚至各配一套存储器与总线。它和冯·诺依曼结构是一对镜像:冯·诺依曼是「一仓一总线,指令数据混装」;哈佛是「两仓两总线,指令数据分家」。各自的理由都成立:混装灵活(程序可被当作数据读写,通用性强,主存统一管理简单);分家高效(取指与取数并行进行,互不排队,且程序区天然不易被改坏)。有趣的是,现代高性能 CPU 实际上是两者的混合:内存层面指令数据混住(冯·诺依曼),但 CPU 内部紧贴运算单元的第一级高速缓存却分成「指令缓存(L1I)」与「数据缓存(L1D)」两套(哈佛)——用哈佛的并行度,保冯·诺依曼的通用性。而许多单片机(MCU)则从头到尾都是纯哈佛:程序放 Flash、数据放 RAM,物理隔离、各走各线。考试若问「哈佛结构与冯·诺依曼结构的本质区别」,标准答案就一句:指令与数据是分开存储还是共用存储。
7.3运算器与控制器:CPU 的两半
运算器(ALU):只会加减的「计算狂」
运算器,又称 ALU(Arithmetic Logic Unit,算术逻辑单元),负责真正的「算」。它的核心就是我们第 5 章搭的加法器,外加一些逻辑门。它能做的,本质就是加减、移位、与或非、比较这些基本操作——所有复杂运算,最终都被拆成这些。
「所有复杂运算最终都被拆成基本操作」这句轻描淡写的话,值得展开看一眼。乘法是移位加累加:二进制乘法里,乘数的每一位要么贡献一次「被乘数左移若干位」,要么不贡献,控制器让 ALU 反复做加法即可;除法是移位减比较的试凑过程;浮点运算则是「拆指数尾数、对阶、移位、加减、再规格化」的组合拳。你在第 5 章为补码加法器配的进位标志 C 与溢出标志 V,在 ALU 里同样是现役装备:减法借位看 C,有符号溢出看 V——比较两数大小(先做减法再看标志)也靠它们。ALU 是「只会基本动作的运动员」,但任何复杂舞步都能拆成基本动作的组合,这正是它以少胜多的底气。
控制器(Control Unit):发号施令的「指挥」
控制器自己不计算,它只做一件事:按照程序的指令,指挥其他部件一步步行动。它读取下一条指令、翻译这条指令是什么意思、然后发出控制信号,让 ALU 去加、让存储器去读、让寄存器去存。
拆开控制器的内囊,你会发现里面全是老朋友:一个译码器(第 5 章)负责把指令的 0/1 编码翻译成「哪条线该亮」;一套时序电路(第 6 章)负责按节拍推进「取指→译码→执行」;一个程序计数器 PC(本质是个计数寄存器)记住「下一条指令在存储器的哪个位置」,每执行完一条就自动加一。取指、译码、执行三拍循环往复,就是计算机运转的心跳——第 6 章的时钟每敲一下,这个循环就向前走一步。控制器就是「用译码器和时序电路实现的自动指挥家」,你学过的零件在这里集合完毕。
分工的本质 运算器管「怎么算」,控制器管「算哪一步」。一个出力气,一个出主意。二者合称 CPU——计算机的大脑。
🧠 一句话记忆 ALU 动手,控制器动口;一个算,一个指挥。
📐 例题 3 「把 3+5 存起来」——四步指令的旅程
某简化计算机中,内存地址 100 存着数 3,地址 101 存着数 5,程序从地址 0 开始依次存放三条指令:① LOAD R1, [100](把地址 100 的数装入寄存器 R1);② ADD R1, [101](把地址 101 的数与 R1 相加,结果放回 R1);③ STORE [102], R1(把 R1 存入地址 102)。请逐步列出每条指令执行时「哪些部件在动、数据怎么流」,并写出执行结束时 PC、R1、地址 102 的值。
思路 对每条指令都走一遍「取指→译码→执行」三拍:取指时控制器经总线从存储器取指令、PC 同时指向下一条;译码时控制器翻译出该让谁动;执行时数据按指令要求流动。逐条记账即可。
解
指令① LOAD:取指——控制器从地址 0 取指令,PC 由 0 变 1;译码——「装数」;执行——存储器把地址 100 的 3 经总线送入寄存器 R1。此时 R1=3。
指令② ADD:取指——PC 由 1 变 2;译码——「取数并相加」;执行——存储器送出地址 101 的 5,运算器算 3+5=8,结果写回 R1。此时 R1=8。
指令③ STORE:取指——PC 由 2 变 3;译码——「存数」;执行——R1 的 8 经总线写入存储器地址 102。
程序执行完毕:PC=3(指向下一条即将到来的指令),R1=8,地址 102 的内容=8。
答:PC=3,R1=8,[102]=8。全程存储器动了三次「读」一次「写」,运算器只算了一次 3+5,输入输出设备一次都没参与——不是每条指令都需要五大部件全员出动;控制器则从头到尾每拍都在发信号。 ⚠ 易错点:ADD 执行时别把「3」写成从内存重读——它已在 R1 里躺着;以及 PC 在「取指」的同时就完成加一,不是整条指令结束后才加。
把控制器与时钟接上,还能算一笔时间账:一条指令要走完「取指→译码→执行」,通常消耗若干个时钟周期(简单指令两三拍,复杂指令十几拍)。用第 6 章的换算工具立即能估出速度量级——若时钟 2 GHz(一拍 0.5 ns)且平均每条指令 4 拍,则每条指令约 2 ns,一秒钟约执行五亿条指令。这就是「主频」与「实际性能」之间的换算链:主频决定一拍多快,指令平均拍数(体系结构决定)决定一条指令要几拍,两者相乘才是每秒指令数。第 8 章 CPU 流水线要优化的,正是「让多条指令的各拍重叠进行」,把这条换算链再压短。
再看一个易混点:ALU 自己不保存结果。它像食堂的打饭窗口,算完一勺立刻递出去——递给寄存器、递给存储器,窗口台上不留菜。所以「先算 a+b 存起来,下一步再算 (a+b)+c」必须有个寄存器接住中间结果 a+b。记住这个分工:算完必有人接,接的人永远是存储性质的单元(寄存器或内存)。这也解释了为什么 CPU 里要塞那么多个寄存器——它们是 ALU 的餐盘架。
7.4存储器:程序与数据的共同仓库
存储器存放两样东西:正在运行的程序,和程序正在处理的数据。它像一张巨大的、编了号的「格子表」,每个格子(存储单元)有一个唯一的编号叫 地址(address),里面存着一小段 0/1。
记忆的最重要特性是随机访问:你可以直接读任意编号的格子,不用从头一个个翻。就像查字典,直接翻到第 500 页,而不是从第 1 页数起。这种「按地址直接存取」的存储器,叫 RAM(Random Access Memory,随机存取存储器)。
把「地址」和「内容」这对概念再拧紧一圈,它们是一栋楼里的门牌号与住户的关系:门牌号(地址)标在墙上,住户(内容)是可以换的;把 501 室的家具全搬空,501 这个门牌号依然存在。所以「擦掉某个格子的内容」「往某个格子写新数据」都不会改变格子的编号——地址由芯片的连线决定,内容才是每条指令真正读写的东西。另一个常被忽略的推论:CPU 访问存储器时,地址与内容是分两趟传递的——先把「我要第 500 号」放到地址总线上,再把第 500 号的内容搬上数据总线。理解了这一点,下一节「地址总线」「数据总线」为什么是两类线,就不言自明了。
顺着「地址总线要多少根线」往下想,还能得到本章最重要的公式之一:每根地址线是一个 bit,n 根地址线一共能编码多少个不同地址?答案是 2 的 n 次方(就是第 2 章「n 个 bit 有 2ⁿ 种组合」的直接应用)。
📐 例题 4 地址线根数与寻址容量
(a)某 CPU 有 16 根地址线,每单元 1 字节,最多能寻址多大容量?(b)20 根地址线呢?(c)32 根呢?(d)反过来:要直接寻址 4 GB(每个地址对应 1 字节),至少需要多少根地址线?
思路 n 根地址线 → 2n 个不同地址 → 2n 个存储单元;每单元 1 字节,2n 字节再除以 1024 换算成 KB/MB/GB(1024=2¹⁰,每次连除 10 次方就跳一级单位)。
解 (a)2¹⁶ = 65536 单元 = 65536 字节,65536÷1024 = 64 KB。
(b)2²⁰ = 1048576 字节 = 1024 KB = 1 MB。
(c)2³² = 4294967296 字节 = 4 × 1024 × 1024 × 1024 字节 = 4 GB。
(d)反向:4 GB = 2³² 字节,需 2n ≥ 2³²,故 n = 32 根。
用一小段 Python 当场验算(也当作这一换算的通用工具):
addr_bits = 16 # 地址线根数
cells = 2 ** addr_bits # 可寻址的存储单元数
print(cells, cells // 1024, "KB") # → 65536 64 KB
units = ["字节", "KB", "MB", "GB"]
for n in (16, 20, 32):
print(n, "根地址线 ->", 2 ** n // 1024 ** (n // 10), units[n // 10])
程序第一行的输出:65536 64 KB——与手算一致。三档容量对照:16→64 KB、20→1 MB、32→4 GB。
答:64 KB;1 MB;4 GB;32 根。 ⚠ 易错点:① 用 1000 而不是 1024 换算,会得到「62.5 KB」之类的错误答案——内存容量按惯例用二进制 1024 进制;② 忘记容量还与「每单元位数」有关——若每单元 4 字节,16 根地址线的容量还要乘 4。
📐 例题 5 地址范围换算(十六进制)
某存储芯片容量为 8 KB,起始地址为 0x0000。(a)它的地址范围是 0x0000 到多少?(b)若另一块 1 KB 的芯片紧挨着它从 8 KB 边界开始排,其起始地址是多少?
思路 容量 8 KB = 8192 = 0x2000 个地址,起始为 0,则末地址 = 0 + 8192 − 1 = 0x1FFF(地址从 0 起编,故要减 1——「0 也占一个号」是初学者最容易漏的一步)。第二块芯片的起始地址 = 第一块的容量,即 0x2000 = 8192。
解 (a)8 KB = 8 × 1024 = 8192 个单元;0x0000 + 8192 − 1 = 8191 = 0x1FFF。范围:0x0000 ~ 0x1FFF。
(b)起始地址 = 0x2000;1 KB = 1024 = 0x400,所以它覆盖 0x2000 ~ 0x23FF。
答:0x0000~0x1FFF;起始 0x2000,1 KB=0x400。 ⚠ 易错点:末地址不是 0x2000 而是 0x1FFF——「从 0 开始编号」意味着第 8192 个格子的编号是 8191。十六进制换算口诀:4096=0x1000、1024=0x400、255=0xFF。
还剩一个悬着的词要交代:「每单元 1 字节」是什么意思?一台机器的存储单元按惯例以字节(byte,8 个 bit)为最小编号单位——地址 0、地址 1、地址 2……每个门牌号背后是 8 个格子,而不是单个 bit。为什么不按 bit 编号?因为 8 个 bit 恰好装下一个字符编码或一条小指令的片段,按 bit 编号会让地址数字暴涨 3 倍、无谓加宽地址总线。由此也自然衔接另一个高频词——字长:CPU 一次能并行处理的 bit 数(比如 64 位)。「64 位 CPU」说的是它的寄存器和运算通路一次吞吐 64 个 bit(8 个字节),而不是说内存地址有多长——地址线根数与字长是两个独立参数,只是碰巧在很多年代的产品里都是 64。
这个「2 的 n 次方」还有一个著名的现实回响:早年 32 位计算机配 4 GB 内存时,系统往往认不全、只显示 3 GB 多——因为 2³² = 4 GB 的地址总量里,还得留出一部分给显存、BIOS、各类接口的寄存器映射,留给内存的地址不够 4 GB 了。这是「地址是编号资源、资源有限就要规划」的生动一课,也是后来 64 位 CPU(寻址能力指数级暴涨)迅速普及的直接动力。
第 9 章我们会深入内存的物理原理(它到底怎么「存」住 0 和 1)。这里你只需要建立这张「带地址的格子表」的直觉。
7.5输入与输出设备
计算机再聪明,也得和人、和世界打交道。输入设备把现实世界的信息(按键、声音、图像)转换成 0/1 送进来;输出设备把 0/1 还原成人能感知的光、声、字。
| 类型 | 设备 | 转换方向 |
|---|---|---|
| 输入 | 键盘、鼠标、麦克风、摄像头、触摸屏 | 现实信息 → 电信号/0和1 |
| 输出 | 屏幕、扬声器、打印机 | 0和1 → 光/声/墨迹 |
把这张表往深处看一层:输入输出设备干的其实是同一件事——翻译。输入设备是「物理世界→二进制世界」的翻译官(麦克风把气压波翻译成 0/1,摄像头把光强翻译成 0/1);输出设备是「二进制世界→物理世界」的翻译官(声卡把 0/1 翻译成气压波,显卡把 0/1 翻译成光点)。真正的计算只发生在二进制世界里,物理世界负责「收发」。
但翻译这份差事并不轻松,难点全在「两个世界节奏差太多」:CPU 一拍只要零点几纳秒(第 6 章:3.5 GHz 的时钟一拍约 0.29 ns),而你敲一个键要几十毫秒——速度差了七八个数量级。硬让 CPU 盯着键盘等,等于让短跑世界冠军蹲在门口等一封三天后才寄到的信。所以每个 I/O 设备身后都站着一个接口控制器:它用第 6 章的触发器把慢信号「接住存稳」,等攒够了再通过总线一次性交给 CPU;两边各按各的节奏,控制器负责「对暗号、存中转」。这套缓冲思想第 14 章展开。
📐 例题 6 触摸屏:输入还是输出?
一块智能座舱里的触摸屏,属于输入设备还是输出设备?某键盘带背光,又属于哪类?
思路 别按「设备」整体分类,按信息方向拆开看:玻璃下面那层感应你手指位置的电路,是把「物理按压位置」翻译成坐标数据——输入方向;同一块屏发光显示画面,是把像素数据翻译成光——输出方向。
解 触摸屏 = 触摸感应层(输入)+ 显示层(输出),一体两面:点选图标时它是输入设备,刷新画面时它是输出设备,两个身份同时成立、互不冲突。带背光的键盘同理:按键电路是输入,背光是输出——只是后者太不起眼,日常就直接归入输入设备了。
答:都是「输入输出一体」的复合设备。分类看信息流向,不看外壳。 ⚠ 易错点:把 I/O 当互斥标签、非此即彼——判断题「触摸屏是输入设备」(√)与「触摸屏是输出设备」(√)可以同时为真。
飞机上这套翻译逻辑尤其直观:大气数据计算机把皮托管的压力(物理量)翻译成高度、空速数据(输入侧),驾驶舱显示器再把高度、空速数据翻译成屏幕上的数字与刻度(输出侧)——两端都是翻译,中间的运算才是计算。
输入输出是计算机的「感官」和「手脚」。它们的具体原理(键盘怎么扫描按键、屏幕怎么发光)会在第 14 章专门讲。
7.6数据流、控制流与总线
五大部件要协同工作,需要两样东西「流动」起来:
- 数据流(data flow):数据在部件之间流动——从输入到存储、从存储到 ALU、从 ALU 到输出。
- 控制流(control flow):控制信号的流动——控制器发出的「该读谁、该算什么、该写哪」的号令。
承载这些流动的物理通道,叫 总线(bus)。总线通常分三类:
| 总线 | 英文 | 传什么 |
|---|---|---|
| 数据总线 | Data bus | 实际的数据(双向) |
| 地址总线 | Address bus | 要访问的内存地址(CPU 发出) |
| 控制总线 | Control bus | 读写、时序等控制信号 |
📖 名词溯源:bus 为什么叫「总线」 bus 来自拉丁语 omnibus(「给所有人的」),本义是「公共马车」,谁都能上、谁都能下。引申到电子工程里,就是一条大家共用的通道——多个部件共享同一组线路传输信号。中文译作「总线」,「总」即「汇总、公用」之意。
核心思想 数据流搬运「数据」,控制流搬运「号令」,两者都跑在总线上。理解这两股流,是理解「计算机如何运转」的关键视角。
「公共马车」这个比喻还藏着它最大的软肋:一条线同一时刻只能传一单货。总线是共享通道,两个部件同时想说话就得排队——由总线仲裁电路(本质是第 5 章的优先编码器思想)决定谁先上。这就像小区只有一部电梯:住户多了,高峰期就得等。计算机史上的经典困境「冯·诺依曼瓶颈」正源于此——指令和数据共用一条总线,取指和取数不能同时进行,CPU 再快也被总线卡着脖子。前面说的「CPU 内部分指令缓存与数据缓存」的哈佛式改造,就是把这两股最急的车流分流到两条快道上,正是缓解瓶颈的工程手段。
📐 例题 7 用「数据流/控制流」双视角重走例题 3 的程序
仍用例题 3 的程序(LOAD R1,[100];ADD R1,[101];STORE [102],R1),对照图 7-3:把整个执行过程拆成「数据流动作」和「控制流动作」两份清单,并回答——三条指令中,「数据流从存储器流向 ALU」发生了几次?「控制流」一共发生了多少次发出?
思路 数据流认「内容在动」:指令代码、操作数、结果都是内容;控制流认「号令在动」:译码后发出的每一个「读/写/算」信号。注意取指阶段的指令代码虽然是指令,但在总线上它同样是「被搬运的内容」,算数据流动作。
解 数据流清单:取指①②③各一次(指令从存储器到控制器);LOAD 执行一次(数 3 从存储器到 R1);ADD 执行两次(数 5 从存储器到 ALU、结果 8 从 ALU 回 R1);STORE 执行一次(8 从 R1 到存储器)——共 7 次。控制流清单:每条指令译码后各发出一组信号——「存储器读」「寄存器写」「ALU 加」等,共 3 组(每组含若干根信号线同时生效)。
「存储器→ALU 方向的数据流」只在 ADD 执行时发生 1 次(数 5 那一趟;3 是直接进寄存器 R1,没经过 ALU)。控制流的发出在每条指令的译码拍都有,3 条指令共 3 次。
答:数据流 7 次、控制流 3 组;存储器→ALU 仅 1 次。 ⚠ 易错点:① 别把「取指」当控制流——指令本身是内容,在总线上的搬运是数据流;「译码后发出的信号」才是控制流;② ADD 的 3 在 R1 里,不经总线、不经 ALU,别多算。
总线的能力有一个可以直接算出来的硬指标——带宽(每秒能搬多少字节)。它由两个因素相乘决定:一次能搬多少(数据总线的位宽),一秒能搬几次(时钟频率,理想情况下每个时钟周期传送一次)。
📐 例题 8 总线带宽计算
某系统数据总线宽度为 64 位,总线时钟 100 MHz,每个时钟周期完成一次数据传送。(a)理论带宽是多少 MB/s?(b)若时钟提到 200 MHz,带宽变为多少?(c)反过来,要达到 3.2 GB/s,在位宽不变的前提下频率需要多少?
思路 先统一单位:64 位 = 8 字节;100 MHz = 10⁸ 次/秒。带宽 = 8 字节 × 10⁸ 次/秒 = 8×10⁸ 字节/秒。总线带宽按工程惯例用十进制(1 MB/s = 10⁶ 字节/秒),与内存容量的 1024 进制区分开。
解 (a)8 × 10⁸ 字节/秒 = 800 MB/s。
(b)频率翻倍、位宽不变,带宽同比例翻倍:8 × 2×10⁸ = 1.6×10⁹ 字节/秒 = 1.6 GB/s。
(c)3.2 GB/s ÷ 8 字节 = 4×10⁸ 次/秒 = 400 MHz。(另一条路:位宽翻到 128 位、频率维持 200 MHz,同样得 3.2 GB/s——提频与加宽是提升带宽的两条平行路径。)
答:800 MB/s;1.6 GB/s;400 MHz。 ⚠ 易错点:① 忘记把「位」换成「字节」(除以 8),会得 6400 MB/s 的离谱答案;② 别用 1024 换算带宽——总线速率按十进制惯例计。
📐 例题 9 这算数据流、控制流,还是地址信息?
下列五个信号/传送,各属于数据流、控制流,还是地址总线上传送的地址信息?(a)键盘扫描码经总线写入存储器;(b)控制器发出的「存储器执行读」信号;(c)加法器的结果 8 经总线写回存储器;(d)PC 中的指令地址放上地址总线;(e)I/O 设备发来的「数据就绪」信号。
思路 三问定属性:内容是「被加工/被搬运的信息」吗(数据流)?是「指挥谁去做什么的号令」吗(控制流)?还是「指明去哪个格子的门牌号」(地址总线的信息,可称地址流——它既不是被加工的数据,也不是号令,而是数据的坐标)?
解 (a)扫描码是被存的信息——数据流。
(b)号令——控制流。
(c)运算结果——数据流。
(d)内容是个地址,但它在总线上只是「指路」,没有被加工——地址信息(跑在地址总线上;PC 本身存的是数据,但此刻它输出的内容被用作地址)。
(e)状态汇报类的号令——控制流(控制总线不只是 CPU 发号,I/O 向 CPU 汇报也走它)。
答:数据流、控制流、数据流、地址信息、控制流。 ⚠ 易错点:地址是最容易被错归到「数据流」的一类——判据不是「内容像不像数字」,而是「它是被加工的货物,还是货物的门牌号」。
三根「水管」里最特别的是地址总线的单向性:门牌号永远由 CPU 发出、存储器只被动接收,反向没有箭头。原因不难想:若存储器也能往地址总线上发号,两个「发号者」就会在同一根线上打架(数字电路里叫总线冲突),读出的地址面目全非。所以「谁有权发地址」被严格规定——普通访存由 CPU 发,DMA(第 14 章的 Direct Memory Access,让 I/O 设备不经 CPU 直取内存)则由仲裁器临时把发号权移交给专用的 DMA 控制器,移交期间 CPU 闭嘴。单向线的纪律换来的是确定性:地址总线上永远只有一个声音。数据总线则相反,谁都可以往里放数据,只要轮流来——这就是它标「双向」的含义:双向指的是方向可变,同一时刻仍只有一个部件在发。
把这节收拢成一句工程直觉:硬件设计者盯住的是三根「水管」各要多粗——数据总线决定一次运多少货(例题 8 的位宽),地址总线决定门牌号能编到多大(例题 4 的 2ⁿ),控制总线决定号令体系够不够用(读写、就绪、中断各有专线)。水管再粗也要排队(仲裁),所以「带宽不够」与「瓶颈分流」是系统设计里永恒的谈判——CPU 厂商一代代把内存控制器搬进 CPU、把缓存一级级加厚,都是在给这根公共马车专线疏堵。
辨析:冯·诺依曼瓶颈 vs 存储墙——两个常被混用的病名 两者都在说「CPU 等数据等得苦」,但病灶完全不同,读性能优化的新闻时先分清再归因。冯·诺依曼瓶颈是结构病:指令与数据共用一套总线与内存端口,取指与取数天然要排队(7.2 节那部「小区电梯」)。存储墙(memory wall)是速度病:CPU 与 DRAM 的速度差一代比一代大——CPU 主频以 GHz 计、一拍不足 1 纳秒,内存一次访问却要几十纳秒,而且几十年间几乎原地踏步。差距有多离谱,算一笔就懂:3 GHz 的 CPU 一拍约 0.33 纳秒,一次约 80 纳秒的访存折合 CPU 白等 80 × 3 = 240 拍。对策因此分两条战线:治结构病靠「分流」——指令缓存与数据缓存分设(思考题 7 的哈佛式改造正是此意)、总线加宽加多;治速度病靠「垫层」与「预取」——用缓存金字塔把常用数据搬到近处,趁 CPU 忙别的活提前把可能要用的数据搬进来。病名分清,药方自然归位:再看到任何一条优化技术,你都能立刻说出它治的是「排队」还是「太远」。
本章小结
- 冯·诺依曼结构把计算机分成五部件:运算器、控制器、存储器、输入、输出。
- 运算器 + 控制器 = CPU;一个管算,一个管指挥。
- 存储程序思想(程序当数据存)让计算机从专用变通用,是革命性的。
- 存储器是「带地址的格子表」,随机访问(按地址直接读写)是其关键。
- 数据流搬数据、控制流搬号令,二者都跑在总线上。
- 存储容量 = 2 的地址线根数次方;地址是门牌号,内容是住户,擦掉内容不改变地址。
- 总线带宽 = 位宽 × 频率;数据总线运货、地址总线发门牌号、控制总线传号令。
读完本章,你应该能……
- 不看书默写出五大部件,并说出每个部件的职责。
- 解释「存储程序」为什么是革命性的思想。
- 说清运算器和控制器的分工(ALU 算、控制器指挥)。
- 解释「地址」「随机访问」的含义。
- 区分数据流和控制流,并说出三类总线。
- 用 2n 算出 n 根地址线的寻址容量,并做十六进制地址范围换算。
- 用「位宽 × 频率」估算总线带宽。
- 说清哈佛结构与冯·诺依曼结构的本质区别,并举出现代 CPU「混合两制」的例子。
思考题
1. 冯·诺依曼结构五大部件是哪五个?运算器和控制器合称什么?
提示:运算器、控制器、存储器、输入、输出;运算器+控制器=CPU。
2. 为什么「存储程序」让计算机从专用变成通用?
提示:程序当数据存,换任务只换内存内容,硬件不用改。
3. 存储器里指令和数据都是 0/1,怎么区分它们?
提示:看读取时机——取指阶段读到的是指令,取数阶段读到的是数据。
4. 数据总线、地址总线、控制总线各传什么?
提示:数据、内存地址、控制信号。
5. 某 CPU 有 20 根地址线、每单元 1 字节,最多能直接寻址多大内存?
提示:2²⁰ = 1048576 字节 = 1024 KB = 1 MB。注意 20 根线恰好跨过 1024 的倍数界,是早期 PC「1 MB 寻址」的经典数字。
6. 触摸屏属于输入设备还是输出设备?为什么?
提示:都属——感应层把触摸位置翻译成数据(输入),显示层把数据翻译成光(输出)。分类看信息流向,不看外壳。
7. 哈佛结构与冯·诺依曼结构的本质区别是什么?现代高性能 CPU 用的是哪种?
提示:指令与数据是分开存储(哈佛)还是共用存储(冯·诺依曼)。现代 CPU 是混合体:内存层面混存(冯·诺依曼),CPU 内部一级缓存分指令/数据两套(哈佛),取两制之长。
8. 程序计数器 PC 属于五大部件中的哪一个?它物理上住在哪里?为什么不能住在存储器里?
解析:属于控制器——它是 CPU 内部一枚专用寄存器,既不是运算器的零件,更不是存储器里的格子。它必须住在 CPU 里:取指的每一步都要读它,几乎每条指令执行完都要改它,访问频度冠绝全场;若把它放进内存,则「读 PC」本身又变成一次访存——「为了取指令而先去取地址」,取地址又得知道地址在哪儿,无限套娃。控制器把 PC、指令译码电路与控制信号发生电路放在一起,才指挥得动全场:PC 是那根「手指」,手指不能住在手指要指的地方。
9. 某 CPU 主频 3 GHz,一次内存访问约 80 纳秒,这次访存折合 CPU 白等多少拍?这个数字解释了什么现象?
解析:3 GHz 一拍 = 1/3 纳秒 ≈ 0.33 纳秒;80 ÷ 0.33 ≈ 240 拍。一次访存够 CPU 空转两百多个周期——这就是「存储墙」的直观刻度:CPU 再快,喂不上料也是白搭。缓存的全部意义就浓缩在这个数字里:把最常用的数据放进 1 纳秒级的高速存储,让绝大多数访存不必付出 240 拍的代价(第 8、9 章会反复用到这笔账)。