1.5 从图灵机到 ECU一座恶魔般的机房1945 年费城宾夕法尼亚大学摩尔工程学院。一座 30 吨重的巨兽蹲在一间约 167 平方米的机房里。它的名字叫ENIACElectronic Numerical Integrator and Computer——世界上第一台通用电子计算机。它有 18000 根真空管、70000 个电阻、10000 个电容、6000 个手动开关。它的功耗是 150 千瓦——每当 ENIAC 开机费城的电灯都会闪一下。真空管的故障率极高——平均每两天坏一根。ENIAC 的维护工程师们发明了一套诊断流程他们学会根据 ENIAC 运算时不同单元的示波器波形感觉哪根真空管快不行了然后提前更换。这和汽车工程师靠发动机的异响判断气门间隙过大是同一类直觉。ENIAC 每秒能做大约 5000 次加法或 357 次乘法。这个速度在 1945 年是石破天惊的——比当时最快的机电计算机Harvard Mark I快了 1000 倍。单条弹道的计算量人工用台式计算器需要 20 小时——ENIAC 只需要 30 秒。但你猜 ENIAC 怎么编程靠插拔电缆。几十个女操作员——当时叫计算员computers这个头衔后来才指机器本身——在 ENIAC 内部爬上爬下手动把跳线插到不同的插孔上设置函数表上 3000 多个开关的位置。换一个计算任务比如从算炮弹弹道换成算原子弹的冲击波传播需要花几天甚至几周来重新布线。恩尼阿克的女操作员中有六位被公认为世界上第一批程序员Kay McNulty、Jean Jennings、Betty Snyder、Marlyn Wescoff、Fran Bilas 和 Ruth Lichterman。在当时硬件那台 30 吨的机房被认为是高级的工作——男人做的。编程被认为是文书工作——女人做的。六十年后我们回看软件工程成了地球上收入最高的职业之一而计算机这个词从指人变成了指机器。飞蛾史上第一个 Bug说到编程就绕不开格蕾丝·霍珀Grace Hopper。霍珀在 1944 年离开瓦萨学院Vassar College的数学教职加入美国海军被派去哈佛大学参与 Mark I 计算机的开发。她是第一个提出用人类可读的英文词汇来代替机器码的人——这个想法后来成长为COBOL编程语言和整个高级编程语言的概念。1947 年的一个夏天霍珀的团队在 Harvard Mark II 上排查一个奇怪的故障。继电器不工作了。他们打开机柜检查——发现一只飞蛾被夹在了继电器触点之间。他们用镊子把飞蛾夹出来用胶带贴在日志本上旁边写了一句“First actual case of bug being found.”——首个真实的bug被发现案例。从此以后“bug”虫子/故障和debug调试/去除虫子成了计算机工程的通行行话。霍珀后来喜欢给年轻人讲这个故事——她会说“我们没有在找 bugbug 来找了我们。”冯·诺依曼那个在火车上想清楚一切的人ENIAC 展示了电子计算机可以工作——但它也展示了插拔电缆是一个死胡同。如果每次换程序都要配线队忙几天那计算还不是通用的。解决这个问题的是约翰·冯·诺依曼John von Neumann。他可能是 20 世纪最聪明的人——不是之一而是最聪明这个级别里的并列第一名。他的生平是一份让人喘不过气的履历22 岁发表关于序数定义的论文奠定了现代集合论的公理化基础。25 岁提出量子力学的希尔伯特空间形式化——这是今天所有量子力学教科书的数学框架。24 岁证明博弈论的最小最大定理——博弈论的发源论文。29 岁加入普林斯顿高等研究院成为那里最年轻的终身教授。40 岁加入曼哈顿计划他的内爆透镜设计是原子弹胖子成功引爆的关键——他不只是计算了冲击波他亲自去新墨西哥州的沙漠里观察了第一次核试验还做出了大量数值模拟。冯·诺依曼有一种近乎恐怖的心算能力。他的同事讲过一件事有一次他在会议上提出了一组偏微分方程的数值解法大家听完了觉得有点复杂。他说不急我大概算一下。然后他在脑海里模拟了计算机需要执行的前 50 步给出了数值解的前几位有效数字。冯·诺依曼的大脑是一台以 40Hz他自己的生物时钟频率运行的图灵机——不需要纸带、不需要真空管、不需要电。他也研究了图灵在 1936 年的论文。在普林斯顿图灵还做过他的助手。冯·诺依曼深知图灵机的数学意义——但他更关心它的工程实现。1945 年 6 月他花了几个星期在火车通勤的路上写出了一份 101 页的手稿——First Draft of a Report on the EDVACEDVAC 报告101 页改变世界冯·诺依曼在 EDVAC 报告里做了一件事他把图灵机的三大抽象组件——纸带、读写头、状态表——翻译成了可以用电子管、汞延迟线和导线实现的电路框图。图灵机的纸带 →存储器。不是串行纸带而是一个可以按地址随机访问的存储空间。地址是存储器的坐标数据是存储器的内容。随机访问这个特性至关重要——在图灵机里你要读纸带上的第 73 个格子必须先读过前 72 个格子。在冯·诺依曼架构里你直接把地址线设为 73数据线上就出现了那个格子里的内容。O(1) vs O(n)。这是计算效率的质变。图灵机的读写头 →运算器ALU 控制器。运算器是纯粹的计算——加法、减法、逻辑与或非。控制器是决定——读取指令、译码、发控制信号、更新程序计数器。两者合在一起就是CPUCentral Processing Unit中央处理器。图灵机的状态表 →程序——存储在同一片内存里。这是最天才的决策。在 ENIAC 里程序是物理线缆的连接方式。在冯·诺依曼架构里程序就是内存中的一串数字——和存数据的数字没有区别。换程序就是换一段内存的内容。不需要插座和电缆——只需要把纸带或纸带上的编码替换掉。这个决策意味着计算机从专门做特定计算的物理机器变成了可以加载任意程序的通用机器。在冯·诺依曼的架构被实现之后同一个硬件可以算弹道、算工资单、算天气预报、下国际象棋。唯一的变化是内存里的数据不同。通用计算从数学概念变成了工程现实。五个方框一颗心脏冯·诺依曼架构的经典框图你一旦看懂了就看清了所有计算机的本质---------- ----------- | 存储器 |---| CPU | | | | | | 程序数据| | ------- | | | | | 运算器 | | ---------- | | (ALU) | | | ------- | | ------- | | |控制器 | | | ------- | ----------- | ----------- | 输入/输出 | | (I/O) | -----------存储器在 ECU 上是 Flash程序 SRAM数据 EEPROM标定参数。你的const常量进 Flash你的局部变量进 SRAM 的栈。运算器ALU在 ECU 上是 ARM Cortex-M4F 的 32 位 ALU。你在 C 里写的x y、a b、c 4最终都在这里。ARM 的 ALU 还能做桶式移位 加法合并操作——所以编译器可以把x y * 3翻译成ADD r0, r1, r1, LSL #1r0 r1 r1*2一条指令、一个时钟周期。这是 RISC 架构的优雅。控制器的核心只有一个寄存器——程序计数器PC。PC 永远指向下一条要执行的指令的地址。控制器的工作就是取 PC 地址的指令 → 译码 → 执行 → PC 指向下一条指令 → 取 PC 地址的指令 → … 周而复始直到断电、HALT、或异常。输入/输出在 ECU 上是 CAN 控制器、SPI、I2C、ADC、GPIO。你没想过的——车速传感器发出的脉冲被 GPIO 脚捕获经过内部定时器计数换算出转速——这不是数据进了CPU——这是物理世界把信息写到了 CPU 的地址空间里。总线是五者之间的公路网。在 S32K144 上总线不是一条——是 AHB 总线矩阵用交叉开关把多条主设备CPU、DMA和多条从设备Flash、SRAM、外设连起来。DMA 可以直接从 ADC 数据寄存器搬运数据到 SRAM不经过 CPU——这叫解放 CPU。冯·诺依曼瓶颈冯·诺依曼架构有一个著名的缺陷——冯·诺依曼瓶颈。存储器和 CPU 之间的双向总线是整台计算机最窄的通道。CPU 一个周期能吞 32 bit 数据但总线每个周期只能传一个数据。这就是缓存存在的理由——把 CPU 频繁访问的指令和数据扣在离 ALU 最近的地方。冯·诺依曼瓶颈的本质是物理距离。电子在导线中约以光速 2/3 传播。1GHz 时钟周期 1ns信号只能走约 20 厘米。如果你的片外 SDRAM 离 CPU 10 厘米——往返就是 20 厘米——这一个时钟周期里你根本碰不到它。而片上 SRAM 距离毫米级延迟短得多。所以 S32K144 的 Flash 控制器能零等待输出 64 bit 预取数据2 条 ARM 指令。但访问片外 QSPI Flash 时等待周期立刻跳升到几十个时钟。这就是嵌入式工程师要关心 .data/.bss 段放置、LMA/VMA、链接脚本布局的原因。你在跟冯·诺依曼瓶颈搏斗。哈佛架构对抗瓶颈的另一条路冯·诺依曼架构的程序和数据共用一条总线。哈佛架构把指令和数据分到两条独立总线——CPU 可以同时取指令和访问数据。ARM Cortex-M 系列采用了改良哈佛指令和数据在逻辑上分开ICode 和 DCode 两条总线但物理上映射到同一地址空间。你在 0x00000000 存得是指令还是数据——ICode 预取单元和 DCode load/store 单元走不同的 AHB 接口硬件上并行访问。面对物理极限走侧面——这是整个计算机架构史的核心母题。穿透 fetch-decode-executeCPU 的一次心跳现在我们把一架显微镜对准 CPU 内部看一个完整的指令周期——CPU 的一呼一吸。假设 PC 指向 Flash 地址0x00001234存储着 32 bit 的机器码0xE0800001。以下是 Cortex-M4 三级流水线的行为第一个流水级取指Fetch。CPU 把地址0x00001234放到地址总线上发出读请求。Flash 控制器内部的预取缓冲区Prefetch Buffer和加速逻辑Speculative Fetch把相邻的 64 bit两条 32 bit 指令一起读出送到译码级。这一步花费物理时间地址总线的传播延迟 Flash 存储阵列的读取延迟 数据总线的返回延迟。在 112MHz 的 S32K144 上约为 2-3 个 HCLK 周期。第二个流水级译码Decode。32 bit 机器码0xE0800001被送入译码器。译码器是一组硬连线逻辑——组合电路combinational logic——没有时钟没有寄存器。它把 32 bit 拆成字段0xE0800001 1110 0000 1000 0000 0000 0000 0000 0001 [31:28] 1110 → 条件码 ALAlways无条件执行 [27:26] 00 → 指令类型数据处理 [24:21] 0100 → 操作码ADD [19:16] 0000 → 目标寄存器R0 [15:12] 0000 → 第一操作数R0 [11:0] ... → 第二操作数R1通过 shift operand 编码译码结果是“R0 R0 R1”——一个 32 位加法。一组控制信号从这个结论中展开ALU 的操作选择设为 ADDALU 的 A 输入端连到 R0ALU 的 B 输入端连到 R1目标寄存器地址指向 R0。第三个流水级执行Execute。寄存器文件Register File——一块内有 16 个 32 位寄存器的快速 SRAM把 R0 和 R1 的值同时输出到 ALU 的两个输入端。ALU 的 32 位全加器接受两个输入经过逻辑门传输延迟几百皮秒输出 R0R1 的结果。写使能信号把 ALU 的输出写回寄存器文件中的 R0。与此同时PC 递增PC PC 4。ARM 指令固定 4 字节所以下一条指令的地址就是当前地址 4。三条指令九个流水级推进约三个时钟周期。你的 C 代码GPIOA-ODR | (1 5)被编译成LDR r0, 0x40020014 ; 加载 GPIOA_ODR 地址 LDR r1, [r0] ; 读取当前 ODR 值 ORR r1, r1, #(15) ; 第 5 位置 1 STR r1, [r0] ; 写回 ODR四条指令——取 GPIOD 地址、读当前值、置位、写回——约 8-10 个时钟周期后PA5 引脚的电平从 0V 变成了 3.3V。你的 C 代码不是在控制硬件——它是在驱动这条 fetch-decode-execute 流水线。流水线的每一拍都在做同一组机械操作——取指、译码、执行、更新 PC——无限循环。从你按下编译按钮到 PA5 引脚拉高中间的每一步都是确定性的、可追踪的、纯机械的。内存映射 I/O为什么写一个地址就能点亮 LED冯·诺依曼架构还有一个不那么直观但极其强大的特性I/O 设备也被映射到了同一个地址空间里。ARM 的默认内存映射把 32 位地址空间4GB分配如下0x00000000 — 0x1FFFFFFF CodeFlash, 512MB 0x20000000 — 0x3FFFFFFF SRAM512MB 0x40000000 — 0x5FFFFFFF Peripherals512MB外设寄存器 0x60000000 — 0x9FFFFFFF External RAM 0xA0000000 — 0xDFFFFFFF External Device 0xE0000000 — 0xFFFFFFFF SystemNVIC, SysTick, MPU, SCB 等当你写*(volatile uint32_t *)0x40020014 0x20时CPU 不知道这是个 GPIO 寄存器——它只知道这是一次写入地址 0x40020014 的 32 位数据。地址解码器address decoder看到这个地址落在外设区间0x40000000-0x5FFFFFFF就在 AHB 总线矩阵中把它路由到 APB 桥Advanced Peripheral Bus bridge再路由到 GPIO 端口 A 的 ODR 寄存器。GPIO 外设内部的输出驱动电路output driver接到寄存器 bit 5 从 0 变成 1 的信号。它打开对应的 PMOS拉高晶体管、关闭对应的 NMOS拉低晶体管引脚电压在几纳秒内从 0V 爬升到 3.3V。如果引脚上挂着一颗 LED 和限流电阻——LED 就亮了。从 C 代码的赋值语句到 LED 发光——中间经过的每一个步骤、每一层硬件、每一个 MOSFET 的栅极电容充放电——都是确定性的。没有魔法。没有操作系统在帮你做。裸机上就是你的一条 STR 指令击穿了两层总线桥AHB → APB、一个 GPIO 寄存器、一对输出驱动 MOSFET、一个外部引脚——最终变成了一个光子从 LED 表面逸出打在你视网膜上。这就是穿透。能穿透到这一层你才真正理解计算和物理的连接点。精简与复杂RISC vs CISC 的世纪对决在嵌入式和桌面 CPU 的两个世界里有一条重要的设计哲学分歧值得了解——因为它解释了为什么你的车里是 ARM你的笔记本里是 x86。RISC精简指令集计算机的核心思想是每条指令只做一件极简单的事CPU 极快地把它们流水线化。指令长度固定ARM 是 32 bit每条指令一个时钟周期至少在设计目标上如此。ARM 是 RISC。RISC-V 是 RISC。CISC复杂指令集计算机的核心思想是用一条复杂的指令完成很多事情。指令长度不固定。x86 是 CISC。为什么 ARM 赢了嵌入式因为嵌入式最紧俏的是功耗。RISC 简单 → 译码逻辑简单 → 晶体管少 → 功耗低 → 不需要散热器。S32K144 全速跑 112MHz功耗约几十毫瓦。CISC 用微码把复杂指令拆成内部微操作在内部跑 RISC-like 执行引擎——外部兼容旧程序内部用现代技术加速。这是兼容性换复杂性。对嵌入式工程师来说RISC 还有一个关键收益——ARM Thumb-2把 32 位 ARM 指令压缩成 16 位代码密度提高约 30%~40%。同样 512KB Flash比纯 ARM 模式多装三分之一的代码。你的 ECU就是一台微型冯·诺依曼机器现在打开任意一颗车规 MCU 的数据手册比如 NXP S32K144看它的框图。------------------- | ARM Cortex-M4F | ← CPU (运算器控制器) | 112 MHz | ------------------ | ------------------ | AHB 总线矩阵 | ← 多层总线交叉开关 --------------- | | | ---- ---- ---- |SRAM| |Flash| |外设| |64KB| |512KB| | | ---- ----- ---- ↑ ↑ ↑ 内存 程序数据 I/OSRAM 存储器数据。Flash 存储器程序 常量数据。外设区0x40000000 I/O 接口。这就是一台完整的冯·诺依曼机器——和图灵 1936 年划分的那三部分纸带、读写头、状态表完全对应。只是它被缩小了几千倍面积加速了几百万倍速度但逻辑结构没有变。你在 C 代码里写的CAN0-IFLAG1 (1 n)清除 CAN 中断标志——这行代码编译后是 STR 指令目标地址是 FlexCAN 模块的 IFLAG1 寄存器地址在 S32K144 上是 0x40024030。STR 锁存的数据导致 CAN 模块内部的标志位清零逻辑触发——它内部的组合电路把对应的中断标志触发器flip-flop复位。每个你写的 C 句子都是一根可以追踪到底的因果链——从代码到数字逻辑到半导体物理没有断裂没有模糊。80 年从图纸到公路一场无声的接力让我们把时间轴拉长看清整幅图景。1936年图灵用一条无限长的纸带和一个有限的状态表定义了计算的边界。同年丘奇用λ演算给出了等价定义。1945年冯·诺依曼在火车上勾勒出EDVAC架构的蓝图——把图灵的抽象模型变成了可建造的电路逻辑框架。他在报告里连ALU的逻辑结构、指令格式、寻址方式、I/O调度都详细描述了。1947年贝尔实验室的巴丁、布拉顿和肖克利发明了点接触晶体管。它取代了真空管——体积缩小了几千倍功耗降低了几个数量级。1958年德州仪器的杰克·基尔比做出了第一块集成电路——把晶体管、电阻和电容做在同一块锗片上。次年仙童的罗伯特·诺伊斯用硅基平面工艺实现了商用集成电路。从此电子元件不再“组装”——而是“刻”在硅上。1971年英特尔的费德里科·法金设计并制出了Intel 4004——世界上第一个商用微处理器。2250个晶体管10μm制程4位数据总线。法金在1970年代用最原始的工具——手工绘制掩模版的聚酯薄膜然后用物理掩模做光刻——把CPU刻进了硅片。法金自己的话说“那时候你可以用肉眼看到每一个晶体管。”中国人也在造计算机当法金在加州设计 Intel 4004 的时候中国也在走自己的计算之路。1960 年夏培肃带领团队研制出中国第一台自主设计的通用电子计算机——107 机。它用电子管搭建每秒运算约 2500 次内存只有 1K 字约 4KB。和她同时代的美国 IBM 7090 相比107 机的性能差了约两个数量级。但它是一台完整的、能用的、中国人从零设计制造的通用计算机。夏培肃后来培养了一代又一代中国计算机科学家——她是“中国人计算之路”的第一个传递人。1979 年王选开始了一项近乎疯狂的项目用计算机处理汉字。当时所有的计算机系统都是英文的——ASCII 编码只需要 128 个字符。而汉字有几千个常用字、几万个总字量。如果每个字用点阵存储一个 64×64 的点阵就要 512 字节——几千个字需要几 MB 的存储这在 1979 年是天文数字当时主流磁盘容量只有几十 MB但内存和软盘以 KB 为单位。王选的解决方法用轮廓描述字形——存储的不是点阵而是笔画边界的数学曲线——然后让计算机在输出时“算出”点阵。这就是“轮廓压缩”——有限资源下的最优解。王选的汉字激光照排系统让中国跳过了铅字印刷时代直接进入了电子排版。他递出的这根接力棒到今天还在运行。而在英国另一条计算之路也在萌芽。1985 年Acorn 计算机公司发布了第一颗 ARM 处理器ARM1。Sophie Wilson 设计指令集Steve Furber 设计硬件。ARM1 接通电源后几乎不发热——Wilson 以为芯片坏了其实只是功耗太低。2005 年ARM Cortex-M3 发布从此统治嵌入式 MCU 市场。你开的每辆车里可能有几十颗 Arm Cortex-M 核心在同时运行。图灵 → 冯·诺依曼 → 肖克利 → 基尔比 → 诺伊斯 → 法金 → Furber Wilson → S32K144 的设计团队 → 你。你在调试板上烧录的那颗 S32K144是几百年来人类科学积累的终点。从纳皮尔的骨筹到巴贝奇的分析机到图灵的纸带到冯·诺依曼的 101 页报告到法金手工画的掩模版到台积电 55nm 的铜互连——每一环都接上了。没有断档没有奇迹。全部是科学发现和工程迭代的累积。而你的固件烧录进去之后在芯片里每天跑着——处理 CAN 报文、执行 UDS 诊断——然后这辆载着它的车每天上下班。下一个接手这颗 MCU 的工程师会打开你的源码读你的注释调你的标定数据。你接过的棒有一天会传给下一个人。本篇小结今天我们做了一件事把80年的接力链串了起来——从图灵的纸带到你手里的S32K144。关键结论冯·诺依曼把图灵机的抽象三要素翻译成了可建造的电路框图纸带→存储器读写头→CPU状态表→程序。这份101页的报告定义了此后所有计算机的骨架。fetch-decode-execute是你写的每一行C代码的物理心跳从赋值语句到LED发光中间的每一步都是确定性的、可追踪的——没有魔法。你不是一个人在写代码图灵→冯·诺依曼→肖克利→基尔比→诺伊斯→法金→Furber Wilson→你——这是一场无声的接力而你正在跑你那一棒。下一节我们走进硅的世界。从沙子到芯片——第二个思想实验开始了。【下集预告】芯片是怎么从沙子造出来的我们来做第二个思想实验。你和 100 个各领域的专家被扔进原始森林里。你们有地球上所有的自然资源有无穷的时间。但你们造不出一颗芯片。为什么因为芯片背后是一整套工业文明体系。几百道工序、几十个学科、几千家工厂的协作——从澳大利亚的矿场到荷兰的光刻机。我们严重低估了现代工业的复杂性。接下来的一章我们走进硅的世界。从沙子里提取多晶硅拉到单晶硅锭、切片、抛光、光刻、刻蚀、CVD 沉积、离子注入、CMP 平坦化、封装测试——一颗芯片的淬炼是现代物理学、化学和工程学的最纯粹结晶。本文内容摘自本人的开源书《从沙子到车辙 - 一个工程师的理解》 在线阅读/下载from-sand-to-rutsgitclone https://github.com/Lularible/from-sand-to-ruts⭐ 如果对您有帮助欢迎 Star 支持也欢迎通过 GitHub Issues 交流讨论。
从沙子到车辙(1.5):从图灵机到 ECU
发布时间:2026/5/19 3:27:30
1.5 从图灵机到 ECU一座恶魔般的机房1945 年费城宾夕法尼亚大学摩尔工程学院。一座 30 吨重的巨兽蹲在一间约 167 平方米的机房里。它的名字叫ENIACElectronic Numerical Integrator and Computer——世界上第一台通用电子计算机。它有 18000 根真空管、70000 个电阻、10000 个电容、6000 个手动开关。它的功耗是 150 千瓦——每当 ENIAC 开机费城的电灯都会闪一下。真空管的故障率极高——平均每两天坏一根。ENIAC 的维护工程师们发明了一套诊断流程他们学会根据 ENIAC 运算时不同单元的示波器波形感觉哪根真空管快不行了然后提前更换。这和汽车工程师靠发动机的异响判断气门间隙过大是同一类直觉。ENIAC 每秒能做大约 5000 次加法或 357 次乘法。这个速度在 1945 年是石破天惊的——比当时最快的机电计算机Harvard Mark I快了 1000 倍。单条弹道的计算量人工用台式计算器需要 20 小时——ENIAC 只需要 30 秒。但你猜 ENIAC 怎么编程靠插拔电缆。几十个女操作员——当时叫计算员computers这个头衔后来才指机器本身——在 ENIAC 内部爬上爬下手动把跳线插到不同的插孔上设置函数表上 3000 多个开关的位置。换一个计算任务比如从算炮弹弹道换成算原子弹的冲击波传播需要花几天甚至几周来重新布线。恩尼阿克的女操作员中有六位被公认为世界上第一批程序员Kay McNulty、Jean Jennings、Betty Snyder、Marlyn Wescoff、Fran Bilas 和 Ruth Lichterman。在当时硬件那台 30 吨的机房被认为是高级的工作——男人做的。编程被认为是文书工作——女人做的。六十年后我们回看软件工程成了地球上收入最高的职业之一而计算机这个词从指人变成了指机器。飞蛾史上第一个 Bug说到编程就绕不开格蕾丝·霍珀Grace Hopper。霍珀在 1944 年离开瓦萨学院Vassar College的数学教职加入美国海军被派去哈佛大学参与 Mark I 计算机的开发。她是第一个提出用人类可读的英文词汇来代替机器码的人——这个想法后来成长为COBOL编程语言和整个高级编程语言的概念。1947 年的一个夏天霍珀的团队在 Harvard Mark II 上排查一个奇怪的故障。继电器不工作了。他们打开机柜检查——发现一只飞蛾被夹在了继电器触点之间。他们用镊子把飞蛾夹出来用胶带贴在日志本上旁边写了一句“First actual case of bug being found.”——首个真实的bug被发现案例。从此以后“bug”虫子/故障和debug调试/去除虫子成了计算机工程的通行行话。霍珀后来喜欢给年轻人讲这个故事——她会说“我们没有在找 bugbug 来找了我们。”冯·诺依曼那个在火车上想清楚一切的人ENIAC 展示了电子计算机可以工作——但它也展示了插拔电缆是一个死胡同。如果每次换程序都要配线队忙几天那计算还不是通用的。解决这个问题的是约翰·冯·诺依曼John von Neumann。他可能是 20 世纪最聪明的人——不是之一而是最聪明这个级别里的并列第一名。他的生平是一份让人喘不过气的履历22 岁发表关于序数定义的论文奠定了现代集合论的公理化基础。25 岁提出量子力学的希尔伯特空间形式化——这是今天所有量子力学教科书的数学框架。24 岁证明博弈论的最小最大定理——博弈论的发源论文。29 岁加入普林斯顿高等研究院成为那里最年轻的终身教授。40 岁加入曼哈顿计划他的内爆透镜设计是原子弹胖子成功引爆的关键——他不只是计算了冲击波他亲自去新墨西哥州的沙漠里观察了第一次核试验还做出了大量数值模拟。冯·诺依曼有一种近乎恐怖的心算能力。他的同事讲过一件事有一次他在会议上提出了一组偏微分方程的数值解法大家听完了觉得有点复杂。他说不急我大概算一下。然后他在脑海里模拟了计算机需要执行的前 50 步给出了数值解的前几位有效数字。冯·诺依曼的大脑是一台以 40Hz他自己的生物时钟频率运行的图灵机——不需要纸带、不需要真空管、不需要电。他也研究了图灵在 1936 年的论文。在普林斯顿图灵还做过他的助手。冯·诺依曼深知图灵机的数学意义——但他更关心它的工程实现。1945 年 6 月他花了几个星期在火车通勤的路上写出了一份 101 页的手稿——First Draft of a Report on the EDVACEDVAC 报告101 页改变世界冯·诺依曼在 EDVAC 报告里做了一件事他把图灵机的三大抽象组件——纸带、读写头、状态表——翻译成了可以用电子管、汞延迟线和导线实现的电路框图。图灵机的纸带 →存储器。不是串行纸带而是一个可以按地址随机访问的存储空间。地址是存储器的坐标数据是存储器的内容。随机访问这个特性至关重要——在图灵机里你要读纸带上的第 73 个格子必须先读过前 72 个格子。在冯·诺依曼架构里你直接把地址线设为 73数据线上就出现了那个格子里的内容。O(1) vs O(n)。这是计算效率的质变。图灵机的读写头 →运算器ALU 控制器。运算器是纯粹的计算——加法、减法、逻辑与或非。控制器是决定——读取指令、译码、发控制信号、更新程序计数器。两者合在一起就是CPUCentral Processing Unit中央处理器。图灵机的状态表 →程序——存储在同一片内存里。这是最天才的决策。在 ENIAC 里程序是物理线缆的连接方式。在冯·诺依曼架构里程序就是内存中的一串数字——和存数据的数字没有区别。换程序就是换一段内存的内容。不需要插座和电缆——只需要把纸带或纸带上的编码替换掉。这个决策意味着计算机从专门做特定计算的物理机器变成了可以加载任意程序的通用机器。在冯·诺依曼的架构被实现之后同一个硬件可以算弹道、算工资单、算天气预报、下国际象棋。唯一的变化是内存里的数据不同。通用计算从数学概念变成了工程现实。五个方框一颗心脏冯·诺依曼架构的经典框图你一旦看懂了就看清了所有计算机的本质---------- ----------- | 存储器 |---| CPU | | | | | | 程序数据| | ------- | | | | | 运算器 | | ---------- | | (ALU) | | | ------- | | ------- | | |控制器 | | | ------- | ----------- | ----------- | 输入/输出 | | (I/O) | -----------存储器在 ECU 上是 Flash程序 SRAM数据 EEPROM标定参数。你的const常量进 Flash你的局部变量进 SRAM 的栈。运算器ALU在 ECU 上是 ARM Cortex-M4F 的 32 位 ALU。你在 C 里写的x y、a b、c 4最终都在这里。ARM 的 ALU 还能做桶式移位 加法合并操作——所以编译器可以把x y * 3翻译成ADD r0, r1, r1, LSL #1r0 r1 r1*2一条指令、一个时钟周期。这是 RISC 架构的优雅。控制器的核心只有一个寄存器——程序计数器PC。PC 永远指向下一条要执行的指令的地址。控制器的工作就是取 PC 地址的指令 → 译码 → 执行 → PC 指向下一条指令 → 取 PC 地址的指令 → … 周而复始直到断电、HALT、或异常。输入/输出在 ECU 上是 CAN 控制器、SPI、I2C、ADC、GPIO。你没想过的——车速传感器发出的脉冲被 GPIO 脚捕获经过内部定时器计数换算出转速——这不是数据进了CPU——这是物理世界把信息写到了 CPU 的地址空间里。总线是五者之间的公路网。在 S32K144 上总线不是一条——是 AHB 总线矩阵用交叉开关把多条主设备CPU、DMA和多条从设备Flash、SRAM、外设连起来。DMA 可以直接从 ADC 数据寄存器搬运数据到 SRAM不经过 CPU——这叫解放 CPU。冯·诺依曼瓶颈冯·诺依曼架构有一个著名的缺陷——冯·诺依曼瓶颈。存储器和 CPU 之间的双向总线是整台计算机最窄的通道。CPU 一个周期能吞 32 bit 数据但总线每个周期只能传一个数据。这就是缓存存在的理由——把 CPU 频繁访问的指令和数据扣在离 ALU 最近的地方。冯·诺依曼瓶颈的本质是物理距离。电子在导线中约以光速 2/3 传播。1GHz 时钟周期 1ns信号只能走约 20 厘米。如果你的片外 SDRAM 离 CPU 10 厘米——往返就是 20 厘米——这一个时钟周期里你根本碰不到它。而片上 SRAM 距离毫米级延迟短得多。所以 S32K144 的 Flash 控制器能零等待输出 64 bit 预取数据2 条 ARM 指令。但访问片外 QSPI Flash 时等待周期立刻跳升到几十个时钟。这就是嵌入式工程师要关心 .data/.bss 段放置、LMA/VMA、链接脚本布局的原因。你在跟冯·诺依曼瓶颈搏斗。哈佛架构对抗瓶颈的另一条路冯·诺依曼架构的程序和数据共用一条总线。哈佛架构把指令和数据分到两条独立总线——CPU 可以同时取指令和访问数据。ARM Cortex-M 系列采用了改良哈佛指令和数据在逻辑上分开ICode 和 DCode 两条总线但物理上映射到同一地址空间。你在 0x00000000 存得是指令还是数据——ICode 预取单元和 DCode load/store 单元走不同的 AHB 接口硬件上并行访问。面对物理极限走侧面——这是整个计算机架构史的核心母题。穿透 fetch-decode-executeCPU 的一次心跳现在我们把一架显微镜对准 CPU 内部看一个完整的指令周期——CPU 的一呼一吸。假设 PC 指向 Flash 地址0x00001234存储着 32 bit 的机器码0xE0800001。以下是 Cortex-M4 三级流水线的行为第一个流水级取指Fetch。CPU 把地址0x00001234放到地址总线上发出读请求。Flash 控制器内部的预取缓冲区Prefetch Buffer和加速逻辑Speculative Fetch把相邻的 64 bit两条 32 bit 指令一起读出送到译码级。这一步花费物理时间地址总线的传播延迟 Flash 存储阵列的读取延迟 数据总线的返回延迟。在 112MHz 的 S32K144 上约为 2-3 个 HCLK 周期。第二个流水级译码Decode。32 bit 机器码0xE0800001被送入译码器。译码器是一组硬连线逻辑——组合电路combinational logic——没有时钟没有寄存器。它把 32 bit 拆成字段0xE0800001 1110 0000 1000 0000 0000 0000 0000 0001 [31:28] 1110 → 条件码 ALAlways无条件执行 [27:26] 00 → 指令类型数据处理 [24:21] 0100 → 操作码ADD [19:16] 0000 → 目标寄存器R0 [15:12] 0000 → 第一操作数R0 [11:0] ... → 第二操作数R1通过 shift operand 编码译码结果是“R0 R0 R1”——一个 32 位加法。一组控制信号从这个结论中展开ALU 的操作选择设为 ADDALU 的 A 输入端连到 R0ALU 的 B 输入端连到 R1目标寄存器地址指向 R0。第三个流水级执行Execute。寄存器文件Register File——一块内有 16 个 32 位寄存器的快速 SRAM把 R0 和 R1 的值同时输出到 ALU 的两个输入端。ALU 的 32 位全加器接受两个输入经过逻辑门传输延迟几百皮秒输出 R0R1 的结果。写使能信号把 ALU 的输出写回寄存器文件中的 R0。与此同时PC 递增PC PC 4。ARM 指令固定 4 字节所以下一条指令的地址就是当前地址 4。三条指令九个流水级推进约三个时钟周期。你的 C 代码GPIOA-ODR | (1 5)被编译成LDR r0, 0x40020014 ; 加载 GPIOA_ODR 地址 LDR r1, [r0] ; 读取当前 ODR 值 ORR r1, r1, #(15) ; 第 5 位置 1 STR r1, [r0] ; 写回 ODR四条指令——取 GPIOD 地址、读当前值、置位、写回——约 8-10 个时钟周期后PA5 引脚的电平从 0V 变成了 3.3V。你的 C 代码不是在控制硬件——它是在驱动这条 fetch-decode-execute 流水线。流水线的每一拍都在做同一组机械操作——取指、译码、执行、更新 PC——无限循环。从你按下编译按钮到 PA5 引脚拉高中间的每一步都是确定性的、可追踪的、纯机械的。内存映射 I/O为什么写一个地址就能点亮 LED冯·诺依曼架构还有一个不那么直观但极其强大的特性I/O 设备也被映射到了同一个地址空间里。ARM 的默认内存映射把 32 位地址空间4GB分配如下0x00000000 — 0x1FFFFFFF CodeFlash, 512MB 0x20000000 — 0x3FFFFFFF SRAM512MB 0x40000000 — 0x5FFFFFFF Peripherals512MB外设寄存器 0x60000000 — 0x9FFFFFFF External RAM 0xA0000000 — 0xDFFFFFFF External Device 0xE0000000 — 0xFFFFFFFF SystemNVIC, SysTick, MPU, SCB 等当你写*(volatile uint32_t *)0x40020014 0x20时CPU 不知道这是个 GPIO 寄存器——它只知道这是一次写入地址 0x40020014 的 32 位数据。地址解码器address decoder看到这个地址落在外设区间0x40000000-0x5FFFFFFF就在 AHB 总线矩阵中把它路由到 APB 桥Advanced Peripheral Bus bridge再路由到 GPIO 端口 A 的 ODR 寄存器。GPIO 外设内部的输出驱动电路output driver接到寄存器 bit 5 从 0 变成 1 的信号。它打开对应的 PMOS拉高晶体管、关闭对应的 NMOS拉低晶体管引脚电压在几纳秒内从 0V 爬升到 3.3V。如果引脚上挂着一颗 LED 和限流电阻——LED 就亮了。从 C 代码的赋值语句到 LED 发光——中间经过的每一个步骤、每一层硬件、每一个 MOSFET 的栅极电容充放电——都是确定性的。没有魔法。没有操作系统在帮你做。裸机上就是你的一条 STR 指令击穿了两层总线桥AHB → APB、一个 GPIO 寄存器、一对输出驱动 MOSFET、一个外部引脚——最终变成了一个光子从 LED 表面逸出打在你视网膜上。这就是穿透。能穿透到这一层你才真正理解计算和物理的连接点。精简与复杂RISC vs CISC 的世纪对决在嵌入式和桌面 CPU 的两个世界里有一条重要的设计哲学分歧值得了解——因为它解释了为什么你的车里是 ARM你的笔记本里是 x86。RISC精简指令集计算机的核心思想是每条指令只做一件极简单的事CPU 极快地把它们流水线化。指令长度固定ARM 是 32 bit每条指令一个时钟周期至少在设计目标上如此。ARM 是 RISC。RISC-V 是 RISC。CISC复杂指令集计算机的核心思想是用一条复杂的指令完成很多事情。指令长度不固定。x86 是 CISC。为什么 ARM 赢了嵌入式因为嵌入式最紧俏的是功耗。RISC 简单 → 译码逻辑简单 → 晶体管少 → 功耗低 → 不需要散热器。S32K144 全速跑 112MHz功耗约几十毫瓦。CISC 用微码把复杂指令拆成内部微操作在内部跑 RISC-like 执行引擎——外部兼容旧程序内部用现代技术加速。这是兼容性换复杂性。对嵌入式工程师来说RISC 还有一个关键收益——ARM Thumb-2把 32 位 ARM 指令压缩成 16 位代码密度提高约 30%~40%。同样 512KB Flash比纯 ARM 模式多装三分之一的代码。你的 ECU就是一台微型冯·诺依曼机器现在打开任意一颗车规 MCU 的数据手册比如 NXP S32K144看它的框图。------------------- | ARM Cortex-M4F | ← CPU (运算器控制器) | 112 MHz | ------------------ | ------------------ | AHB 总线矩阵 | ← 多层总线交叉开关 --------------- | | | ---- ---- ---- |SRAM| |Flash| |外设| |64KB| |512KB| | | ---- ----- ---- ↑ ↑ ↑ 内存 程序数据 I/OSRAM 存储器数据。Flash 存储器程序 常量数据。外设区0x40000000 I/O 接口。这就是一台完整的冯·诺依曼机器——和图灵 1936 年划分的那三部分纸带、读写头、状态表完全对应。只是它被缩小了几千倍面积加速了几百万倍速度但逻辑结构没有变。你在 C 代码里写的CAN0-IFLAG1 (1 n)清除 CAN 中断标志——这行代码编译后是 STR 指令目标地址是 FlexCAN 模块的 IFLAG1 寄存器地址在 S32K144 上是 0x40024030。STR 锁存的数据导致 CAN 模块内部的标志位清零逻辑触发——它内部的组合电路把对应的中断标志触发器flip-flop复位。每个你写的 C 句子都是一根可以追踪到底的因果链——从代码到数字逻辑到半导体物理没有断裂没有模糊。80 年从图纸到公路一场无声的接力让我们把时间轴拉长看清整幅图景。1936年图灵用一条无限长的纸带和一个有限的状态表定义了计算的边界。同年丘奇用λ演算给出了等价定义。1945年冯·诺依曼在火车上勾勒出EDVAC架构的蓝图——把图灵的抽象模型变成了可建造的电路逻辑框架。他在报告里连ALU的逻辑结构、指令格式、寻址方式、I/O调度都详细描述了。1947年贝尔实验室的巴丁、布拉顿和肖克利发明了点接触晶体管。它取代了真空管——体积缩小了几千倍功耗降低了几个数量级。1958年德州仪器的杰克·基尔比做出了第一块集成电路——把晶体管、电阻和电容做在同一块锗片上。次年仙童的罗伯特·诺伊斯用硅基平面工艺实现了商用集成电路。从此电子元件不再“组装”——而是“刻”在硅上。1971年英特尔的费德里科·法金设计并制出了Intel 4004——世界上第一个商用微处理器。2250个晶体管10μm制程4位数据总线。法金在1970年代用最原始的工具——手工绘制掩模版的聚酯薄膜然后用物理掩模做光刻——把CPU刻进了硅片。法金自己的话说“那时候你可以用肉眼看到每一个晶体管。”中国人也在造计算机当法金在加州设计 Intel 4004 的时候中国也在走自己的计算之路。1960 年夏培肃带领团队研制出中国第一台自主设计的通用电子计算机——107 机。它用电子管搭建每秒运算约 2500 次内存只有 1K 字约 4KB。和她同时代的美国 IBM 7090 相比107 机的性能差了约两个数量级。但它是一台完整的、能用的、中国人从零设计制造的通用计算机。夏培肃后来培养了一代又一代中国计算机科学家——她是“中国人计算之路”的第一个传递人。1979 年王选开始了一项近乎疯狂的项目用计算机处理汉字。当时所有的计算机系统都是英文的——ASCII 编码只需要 128 个字符。而汉字有几千个常用字、几万个总字量。如果每个字用点阵存储一个 64×64 的点阵就要 512 字节——几千个字需要几 MB 的存储这在 1979 年是天文数字当时主流磁盘容量只有几十 MB但内存和软盘以 KB 为单位。王选的解决方法用轮廓描述字形——存储的不是点阵而是笔画边界的数学曲线——然后让计算机在输出时“算出”点阵。这就是“轮廓压缩”——有限资源下的最优解。王选的汉字激光照排系统让中国跳过了铅字印刷时代直接进入了电子排版。他递出的这根接力棒到今天还在运行。而在英国另一条计算之路也在萌芽。1985 年Acorn 计算机公司发布了第一颗 ARM 处理器ARM1。Sophie Wilson 设计指令集Steve Furber 设计硬件。ARM1 接通电源后几乎不发热——Wilson 以为芯片坏了其实只是功耗太低。2005 年ARM Cortex-M3 发布从此统治嵌入式 MCU 市场。你开的每辆车里可能有几十颗 Arm Cortex-M 核心在同时运行。图灵 → 冯·诺依曼 → 肖克利 → 基尔比 → 诺伊斯 → 法金 → Furber Wilson → S32K144 的设计团队 → 你。你在调试板上烧录的那颗 S32K144是几百年来人类科学积累的终点。从纳皮尔的骨筹到巴贝奇的分析机到图灵的纸带到冯·诺依曼的 101 页报告到法金手工画的掩模版到台积电 55nm 的铜互连——每一环都接上了。没有断档没有奇迹。全部是科学发现和工程迭代的累积。而你的固件烧录进去之后在芯片里每天跑着——处理 CAN 报文、执行 UDS 诊断——然后这辆载着它的车每天上下班。下一个接手这颗 MCU 的工程师会打开你的源码读你的注释调你的标定数据。你接过的棒有一天会传给下一个人。本篇小结今天我们做了一件事把80年的接力链串了起来——从图灵的纸带到你手里的S32K144。关键结论冯·诺依曼把图灵机的抽象三要素翻译成了可建造的电路框图纸带→存储器读写头→CPU状态表→程序。这份101页的报告定义了此后所有计算机的骨架。fetch-decode-execute是你写的每一行C代码的物理心跳从赋值语句到LED发光中间的每一步都是确定性的、可追踪的——没有魔法。你不是一个人在写代码图灵→冯·诺依曼→肖克利→基尔比→诺伊斯→法金→Furber Wilson→你——这是一场无声的接力而你正在跑你那一棒。下一节我们走进硅的世界。从沙子到芯片——第二个思想实验开始了。【下集预告】芯片是怎么从沙子造出来的我们来做第二个思想实验。你和 100 个各领域的专家被扔进原始森林里。你们有地球上所有的自然资源有无穷的时间。但你们造不出一颗芯片。为什么因为芯片背后是一整套工业文明体系。几百道工序、几十个学科、几千家工厂的协作——从澳大利亚的矿场到荷兰的光刻机。我们严重低估了现代工业的复杂性。接下来的一章我们走进硅的世界。从沙子里提取多晶硅拉到单晶硅锭、切片、抛光、光刻、刻蚀、CVD 沉积、离子注入、CMP 平坦化、封装测试——一颗芯片的淬炼是现代物理学、化学和工程学的最纯粹结晶。本文内容摘自本人的开源书《从沙子到车辙 - 一个工程师的理解》 在线阅读/下载from-sand-to-rutsgitclone https://github.com/Lularible/from-sand-to-ruts⭐ 如果对您有帮助欢迎 Star 支持也欢迎通过 GitHub Issues 交流讨论。