← 开始 | 📖 目录 | 下一章:第1章 →


序章 0:开讲之前,先把这四件事讲明白

为什么要有这一章? 教材一开头就讲”冯·诺依曼”、“寄存器”、“二进制”、“时钟周期”——这些词不解释你也”知道”,但其实你只是听过,并不真的懂。这一章用 4 个故事把这 4 件事讲透,看完你的脑子里会有真东西,而不是 4 个空名词。


0.1 第一个问题:在冯·诺依曼之前,人是怎么”编程”的?

你听过”冯·诺依曼结构”这个词无数次,但它伟大在哪?要回答这个,得先看看它之前的机器有多惨。

故事:ENIAC 的痛

🛟 几个底层电学名词一次讲清(之后正文不再解释):

  • 门电路 (Gate) = 用几个晶体管搭成的最小逻辑零件,只做一件事。常见三种:非门 (NOT) 输入 0 出 1、输入 1 出 0;与门 (AND) 两个输入都为 1 才出 1;或门 (OR) 任一输入为 1 就出 1。整个 CPU 的所有运算电路最终都是这三种门的组合。
  • 组合电路 = 由门电路堆出来的电路,输入一变输出立即变(不用时钟)。ALU 就是典型——你换两个数它一拍内吐出结果。
  • 时序电路 = 在组合电路基础上加了”记忆元件”(触发器/锁存器),需要时钟驱动才会更新。寄存器、PC、IR 都是时序电路。
  • 上升沿 / 下降沿 = 时钟方波从低跳到高的那一瞬间叫上升沿(↑);从高跳到低叫下降沿(↓)。“边沿触发”的元件只在那一瞬间动一下,其余时间高电平再长它也不理。

后面看到任何”门""组合""时序""沿”,回这里查就行。

1946 年,美国造出了世界上第一台电子计算机 ENIAC(埃尼亚克),重 30 吨,占地 170 平方米,每秒能算 5000 次加法——在当时是宇宙级速度。

但它有一个致命问题:怎么”编程”?

答案是:手动接线。

ENIAC 的"编程"现场:

   ┌──────────────────────────────────────────────────────┐
   │  □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □  │
   │  □ □ □ □ ●═══●  □ □ ●═════════●  □ □ □ □ □ □ □ □ □ │
   │  □ □ ●═════════════●  □ □ □ □ □ ●═══●  □ □ □ □ □ □ │   ← 6000个开关
   │  □ ●═●  □ □ □ □ □ □ □ □ □ □ □ □ □ □ ●═════●  □ □ □ │   ← 几千根插线
   │  □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □  │
   └──────────────────────────────────────────────────────┘
        ↑                                                 ↑
     6 位女程序员花 3 天才能把"算个弹道"的程序"接"出来

是的,没有”代码”这种东西。要让 ENIAC 算别的题,得6 个女工程师在机器前花 2–3 天,把上千根插线拔下来重插一遍、6000 个开关调一遍。算完一道题,要换下一道?再拔再插再调。

🌱 大白话:ENIAC 的”程序”不是”写”的,是接出来的。整台机器的硬件结构就是那个程序——换程序 = 重新搭机器。

冯·诺依曼的”灵光一现”

1945 年,数学家 冯·诺依曼(John von Neumann)看到 ENIAC 后写了一份报告,提出一个今天看来”理所当然”、当时却惊天动地的想法:

既然机器能处理”数字”(输入的数据),为什么不能把”程序本身”也当成数字、提前存进机器里?让机器自己一条条读出来执行?

这就是**“存储程序”**——四个字,整个现代计算机产业的奠基石。

ENIAC 时代:                      冯·诺依曼之后:

  程序 = 机器的物理接线           程序 = 一堆数字,和数据混在一起存内存
  换程序 = 重新接 3 天            换程序 = 把另一堆数字读进内存(几毫秒)
  机器 = 只能干一种活             机器 = 同一台硬件干无限多种活

  → 不可商用、不能复制              → 通用计算机的诞生

这件事的伟大之处是:硬件第一次从”具体的功能”中解放出来——硬件只负责”按规则读数字、做数字、写数字”,至于这堆数字代表什么活,全由用户决定。这才有了今天你的手机能同时是电话、相机、地图、游戏机——它的硬件就一份,“程序”换来换去。

🔑 记住这个对比:以后听到”存储程序”四个字,脑子里要立刻浮现”ENIAC 的女工拔了 3 天插线” vs “现代电脑切换程序只需一瞬间”。这才是它的分量。

🌱 大白话:冯·诺依曼说:“别再把菜谱焊在厨房里了,把菜谱写在纸上和食材一起放冰箱,让厨师自己去翻就行。” 这一句话,让计算机从”专用工具”变成了”通用工具”。


0.2 第二个问题:为什么计算机偏偏用”二进制”,不用十进制?

你肯定听过”计算机用 0 和 1”。但为什么?人类天生用十进制(因为有 10 根手指头),机器不能也用十进制吗?

答案藏在硬件最底层的物理事实里。

🛟 如果你连”电压""电流”都没把握,先看这段;如果熟,可跳过: 想象一根水管,水管里流的”水”= 电流;推水流动的”水压”= 电压。 一个开关装在水管上:“开”=水通了=电流流过;“关”=水堵住=没电流。 数字电路里所有元件本质都是这种”被某个信号控制开/关”的小阀门——只是用电而不是水。 “高电压代表 1”是人类定的一个约定——也可以反过来用低电压代表 1(叫”负逻辑”),结果完全等价,只是约定不同。

物理事实:晶体管只有两个稳定状态

计算机的所有硬件,最终都由数以亿计的 晶体管 (Transistor) 组成。一个晶体管的本质,是一个由电压控制的”开关”:

   一个晶体管的工作方式:

   ┌─────────────────────┐
   │   控制极 (Gate)      │   ← 给它一个电压
   │      │               │
   │      ▼               │
   │   ┌─────┐            │
   │   │ 开/关 │  ←─电流──│   ← 决定电流通不通
   │   └─────┘            │
   └─────────────────────┘

   高电压 (~5V) → 开 → 电流通 → 我们规定它代表 "1"
   低电压 (~0V) → 关 → 电流断 → 我们规定它代表 "0"

为什么不能搞三个状态、四个状态来表示十进制?

理论上可以,物理上极难做稳定。比如要表示 0/1/2/3 四个数字,得分别用 0V / 1.7V / 3.3V / 5V 四档电压。问题来了:

  • 电路里永远有噪声(其他元件干扰、温度波动),实测电压可能是 1.5V、3.0V、3.5V,到底算哪档?
  • 制造误差:100 万个晶体管不可能完全一致,有的 1.7V 有的 1.6V,判错就出大事。
  • 速度:要分辨四档比分辨两档慢得多。

而只有两档时:低于 1V 一律算 0、高于 4V 一律算 1,中间留宽宽的”缓冲带”,怎么干扰都不会判错。

   两态判别(极宽容):        四态判别(极敏感):

   5V─┐ ←─── 全算 1          5V─┐ ← 算 3
      │ (高电平稳定区)        4V─┤ ← 算 3 还是 2?模糊
   4V─┤                       3V─┤ ← 算 2
      │                       2V─┤ ← 算 2 还是 1?模糊
      │ ←── 这一大段是缓冲    1V─┤ ← 算 1
      │     带,怎么晃都不会  0V─┘ ← 算 0
   1V─┤     误判
      │ (低电平稳定区)
   0V─┘ ←─── 全算 0

🌱 大白话:二进制不是”人选的”,是电子元件天生只擅长两个状态——亮/灭、通/断、磁极 N/S。逼它做”亮一点点”和”亮很多”的区分,它判不准。所以整个数字计算机帝国,都建在”晶体管只能做开关”这一条物理事实上。

那”二进制”具体怎么表示数字?

约定俗成:用一串 0/1 按”逢二进一”组合,就能表示任意大小的数字。

   十进制 5  =  二进制 101    (1×4 + 0×2 + 1×1 = 5)
   十进制 13 =  二进制 1101   (1×8 + 1×4 + 0×2 + 1×1 = 13)
   十进制 255 = 二进制 11111111 (8 个 1,最大 8 位无符号数)

所以以后看到”32 位整数”,脑子里浮现的应该是:32 个晶体管排成一排,每个要么导通要么截止,组合起来就是一个数。

🔑 从此你就懂了:第 2 章讲”补码/IEEE754”,其实都是在解决”怎么用 0/1 这两个字符,把负数、小数、超大超小的数也表示清楚”的问题。所有数据表示方法,都是给”只会 0/1 的硬件”擦屁股。


0.3 第三个问题:CPU 里的”寄存器”到底是什么?为什么不直接用内存?

你后面会无数次看到 R1、R2、PC(Program Counter,程序计数器——记着”下一条指令在内存哪个位置”)、IR(Instruction Register,指令寄存器——存着”当前正在执行的那条指令”)这些”寄存器”。问题是——寄存器到底是什么?它和内存有什么区别?

速度的真相:CPU 等内存等到怀疑人生

   现代电脑里几个东西的访问速度(用"等多久"对比):

   寄存器 (Register)     约 0.3 ns      ← CPU 内部,"伸手就拿到"
   L1 Cache              约 1 ns        ← 还在 CPU 内
   L2 Cache              约 3 ns
   L3 Cache              约 10 ns
   内存 (Main Memory)    约 100 ns      ← 出 CPU 走总线,远多了
   硬盘 (SSD,固态硬盘)   约 100,000 ns
   机械硬盘              约 10,000,000 ns

如果把 CPU 取一次寄存器的时间想象成”伸手拿桌上的笔”(1 秒),那么:

  • 取一次内存 ≈ 走出办公室、坐电梯下楼、走到对面写字楼(约 5 分钟)
  • 取一次硬盘 ≈ 从北京飞到纽约(约 4 天)

CPU 跑得太快,内存比它慢 100 倍。如果每算一步都要去内存搬数据,CPU 大部分时间都在等——这就是著名的”存储墙 (Memory Wall)“问题。

解决方案:在 CPU 里放一些”超快的小本本”

CPU 内部专门用触发器电路(触发器 = 用 4–6 个晶体管搭出的”小记忆元件”,给它输入端送一个 0 或 1,它就记住,断了输入也不忘——直到下次被改写。把它想成”用电子门栓锁住一个 0 或 1”)做了几十到几百个”小本本”,每个能存一个数字(通常 32 或 64 位)——这就是寄存器。

后面看到 ALU(算术逻辑单元,Arithmetic Logic Unit)就是 CPU 里做加减与或非的那个核心电路块——你给它两个输入数和一个”该做什么”的指令,它就在一拍内给你结果。寄存器把数据喂给 ALU、再接住 ALU 的输出,整个 CPU 算数的故事就这么循环。

   CPU 内部 (放大看):

   ┌──────────────────────── CPU 芯片 ────────────────────────┐
   │                                                            │
   │   ALU (运算单元)                                            │
   │      ↑↓                                                    │
   │   ┌─ 寄存器组 ─┐    ← 32 个小本本                            │
   │   │ R0  ━━━━━━│    每个本能写一个 32 位数                   │
   │   │ R1  ━━━━━━│    CPU 0.3 ns 就能读/写一次                │
   │   │ R2  ━━━━━━│                                            │
   │   │ ...        │                                            │
   │   │ R31 ━━━━━━│                                            │
   │   └────────────┘                                            │
   │                                                            │
   └────────────────────────────────────────────────────────────┘
              ↕  通过"总线"这条线
   ┌────────────────────────────────────────────────────────────┐
   │    内存 (DRAM,Dynamic Random-Access Memory,动态随机存取存储器,几个 GB)   ← 100 ns 才能读一次               │
   └────────────────────────────────────────────────────────────┘

寄存器的”工作原则”:

  • 数量少(几十个)但飞快(0.3 ns)。
  • CPU 算数时,操作数必须先搬进寄存器——ALU 只能从寄存器读、往寄存器写,不能直接对内存算。
  • 比如 a+b,真实的步骤是:① 把 a 从内存搬到 R1;② 把 b 从内存搬到 R2;③ ALU 算 R1+R2,结果放 R3;④ 把 R3 写回内存。两次搬进来、一次算、一次搬回去,总共 4 步,这就是 RISC(Reduced Instruction Set Computer,精简指令集计算机——指令少而整齐,每条指令固定几拍完成)的”Load/Store 架构”的真相。

🌱 大白话:内存是”楼下仓库”,便宜大碗但远;寄存器是”工作台上的笔筒”,只能插几支笔,但伸手就有。你在桌上算账,总得先把账本从仓库搬到桌上才能算——这就是”先 LOAD 进寄存器再 ADD”的物理本质。

🔑 后面看 PC、IR、AR(Address Register,地址寄存器——存着”要去访问的内存门牌号”)、DR(Data Register,数据寄存器——临时存着”刚从内存取来的数据”)、PSW(Program Status Word,程序状态字——记着”刚才的运算有没有溢出、进位”等标志位)这些”专用寄存器”,本质都一样:它们就是 CPU 内部留出来专门记某件事的”小本本”——PC 记”下条指令在内存哪个门牌号”、IR 记”我手里这条指令是啥”、PSW 记”刚才算出来溢出了没”。


0.4 第四个问题:CPU 为什么能”自动一步步走”?谁在背后打节拍?

冯·诺依曼说”机器按地址自动取指令一条条执行”——可机器凭什么自动?它怎么知道”现在该取下一条了”?

答案:靠时钟 (Clock)——CPU 的”心跳”。

物理事实:CPU 板上有个晶振,它每秒振动几亿到几十亿次

打开你电脑的 CPU,里面(其实主板上)有一块叫 晶振 (Crystal Oscillator) 的小晶体。给它通电,它会因为压电效应以极其精确的频率振动,产生一个方波信号:

🛟 “压电效应”是啥? 一句话:某些晶体(如石英)一通电就会以极其稳定的频率自己抖动——人类不用管为啥,用就完了:它能输出一根脉冲规律的方波线,整台电脑就靠这根线”打节拍”。你手腕上的石英表里也有同一种东西。

   时钟信号 (Clock Signal) 长这样:

   高电平 ─┐  ┌──┐  ┌──┐  ┌──┐  ┌──┐  ┌──
           │  │  │  │  │  │  │  │  │  │
   低电平   └──┘  └──┘  └──┘  └──┘  └──┘
           └──┬──┘
              │
              └── 一个"时钟周期" (Clock Cycle / 节拍)
                  也就是教材里说的 "T"

   你的电脑主频 3 GHz = 每秒 3,000,000,000 个这样的方波
   → 一个时钟周期 = 1/3 ns ≈ 0.33 ns

时钟驱动是怎么让 CPU “动”起来的?

CPU 里每一个寄存器、每一个触发器都有一根”时钟输入线”,连到这个方波信号上。这些电路有一个共同规则:

只在时钟方波从低跳到高的那一瞬间(上升沿),才”锁住”新的输入;其他时刻保持不变。

   一个寄存器对时钟的响应:

   时钟    ───┐  ┌────┐  ┌────┐  ┌──
              │  │    │  │    │  │
              └──┘    └──┘    └──┘
                ↑       ↑       ↑
                这一瞬间,寄存器"咔嚓"锁住此时输入端的值
                其他时间,输入怎么变它都不理

   输入端  ──XXX──╳──YYY──╳──ZZZ────
   寄存器内容    XXX        YYY        ZZZ  ← 每个节拍换一次

于是,整台 CPU 就像一支跟着鼓点行进的方阵:每听到一声鼓(时钟上升沿),所有部件同时进入下一个状态。这一拍:“PC 把指令地址送到内存”;下一拍:“内存把指令送回 IR”;再下一拍:“译码器看清这是 ADD 指令”……

🌱 大白话:CPU 不是”自动想运转”,是有一个外置的电子节拍器一直在敲鼓,CPU 的每个零件都被规定”听到鼓声才能动一下”,于是整台机器就这么一拍一拍按部就班地走。关掉时钟,CPU 立刻”僵在原地”——它不是死了,只是没人喊”换”了。

由此引出”周期”的三层包含关系

教材里那个让人头大的”指令周期 ⊇ 机器周期 ⊇ 时钟周期”,本质就是:

   时钟周期 = 鼓的一拍(最小单位)           ≈ 0.3 ns
        ↓ 几拍打包
   机器周期 = 完成一个"明确小动作"所需的几拍
            (比如"从内存取一次数据"通常要 3–5 拍)
        ↓ 几个小动作组成
   指令周期 = 完成一条机器指令的全部时间
            (取指 + 译码 + 执行 + 写回,整体可能要 10–20 拍)

🔑 后面学第 5 章 “CPU 指令周期” 时,记住这个:不是 CPU 自己”决定”花几拍,是设计者把指令的执行过程拆成了一连串”听到鼓声就动一下”的微小动作,鼓点固定,动作累加,时间就出来了。


⭐ 序章 0 总结:建好这四块地基,再去看课本

#你建立的认知它解决了什么后面会迷糊的问题
0.1存储程序之前要”接线”——所以冯·诺依曼的伟大是”让程序变成数据”第 1 章为什么把”存储程序”列为冯氏三大思想之首
0.2二进制是被晶体管的物理特性逼出来的、不是人选的第 2 章为什么要费那么大劲搞补码/浮点——都是用 0/1 凑出别的数
0.3寄存器是 CPU 里的”小本本”,比内存快 100 倍第 4、5 章为什么算什么都要”先 LOAD 进寄存器”——内存太慢
0.4CPU 靠时钟方波”被动地”一拍一拍走第 5 章为什么有”时钟周期/机器周期/指令周期”嵌套

🎯 从此你看后面任何概念,都可以问自己:“这个概念是在解决什么问题?是为了对付硬件的什么限制?” ——只要能答上这个问题,你就真的懂了,否则就是死记硬背。



📝 章节小测

先想好答案再展开核对。这几道帮你确认”四块地基”是否真的搭稳了。

【题 1 · 判断】 “冯·诺依曼机中,程序和数据都以二进制形式存储在同一个存储器中。” 对还是错?

【题 2 · 判断】 “计算机采用二进制是因为二进制运算规则比十进制简单。” 这个说法完整吗?

【题 3 · 简答】 CPU 内部的寄存器和主存(内存)都能存数据,为什么 CPU 算数时非要先把数据搬进寄存器?


← 开始 | 📖 目录 | 下一章:第1章 →