LV001-计算机的基本组成
在点亮第一块单片机开发板之前,我们先回答一个更根本的问题:计算机是由什么组成的?它为什么能自动工作?
单片机(MCU)本质上就是一台被压缩到一颗芯片里的计算机。这一篇里的每个概念——运算器、控制器、存储器、指令、寄存器——后面都会在 STM32 里一一对应地再次出现。把这一篇读懂,后面所有章节其实都是在"对号入座"。
本篇的阅读主线是一条因果链:计算机只会简单运算 → 复杂问题必须先被人翻译成简单运算 → 让机器自动执行这些运算需要"存储程序" → 存储程序要求机器具备五大部件 → 五大部件靠"取指-分析-执行"的循环运转起来。
一、 计算机是如何解题的
1. 计算机只会简单运算
一个容易被忽略的事实:计算机再强大,硬件层面也只会做加减乘除四则运算和逻辑判断(与、或、非、比较大小)。那它怎么算 sin x、开根号、算微分方程?答案是人工先把问题"降维"成计算机能算的形式。例如 sin x 可以用泰勒级数展开成一系列加减乘除:
再比如开平方,可以用迭代公式反复逼近:
只要迭代次数够多,结果就会无限接近真实值。"把复杂运算化归为有限次简单运算",这是用计算机解题的第一个前提。
2. 解决问题分两大步骤
用计算机解决一个实际问题,工作分成性质完全不同的两段:
(1)上机前的准备——人的工作,又分三步:
- 建立数学模型:把实际问题抽象成数学方程。比如预测人口增长,抽象成微分方程;统计销量趋势,抽象成回归模型;
- 确定计算方法:把数学方程化成只含四则运算的近似计算公式,比如上面 sin x 的级数展开。同一个问题往往有多种算法,精度、速度、内存占用各不相同,这一步直接影响程序质量;
- 编制解题程序:把运算步骤翻译成一条条机器指令。程序就是"适合机器运算的全部步骤",机器只会执行程序,不会理解问题。
(2)上机运行——机器的工作:程序和数据送入计算机,机器自动逐条执行指令,最后输出结果,全程不需要人干预。
【注意】
"自动"两个字是这一篇的关键词。1946 年之前,"计算机"是一群拿着计算尺和手摇计算机的人;ENIAC 诞生后,计算速度提高了上千倍,但编排计算步骤仍然靠人手工插线、扳开关——换一道题就要重新接线几个小时。计算机组成原理要回答的核心问题之一,就是:机器是怎么从"人拉一步走一步"变成"自己一步步走下去"的。
二、 冯·诺依曼体系结构
1. 从 ENIAC 的痛点说起
世界上第一台通用电子数字计算机 ENIAC(1946 年,美国宾夕法尼亚大学)每秒能做 5000 次加法,但它的"程序"存在接线板里:想换个题目计算,要几个工程师手动改线好几天。计算快,换题慢,机器大部分时间在等人接线。
1945 年,参与 ENIAC 后续项目 EDVAC 的数学家冯·诺依曼(von Neumann)发表了著名的《EDVAC 报告书的第一份草案》,指出了问题的根源和解法:指令也应该像数据一样,存放在存储器里,让机器自己按地址去取。
2. 存储程序思想
这一思想的核心只有一句话:
将程序(指令)和数据一样,预先存放在存储器中,机器按照指令在存储器中的地址自动地、依次地取出并执行。
以此概念为基础的各类计算机统称为冯·诺依曼机。从你手里的 STM32 到顶级的服务器 CPU,八十年来几乎所有计算机都延续着这个思想。它带来的直接后果是:换一道题不再需要重新接线,只需要把新的程序写进存储器——"编程"取代了"接线"。
3. 五大部件
要落实"存储程序",机器必须具备五类功能部件,各司其职:
| 部件 | 职能 | 通俗理解 | 生活中的对应 |
|---|---|---|---|
| 运算器 | 完成算术运算和逻辑运算,中间结果暂存在运算器内 | 干活的 | 计算器芯片 |
| 存储器 | 存放数据和程序 | 仓库 | 书架 |
| 控制器 | 指挥程序和数据的输入、运行以及结果处理 | 指挥的 | 大脑 |
| 输入设备 | 把人熟悉的信息形式转换为机器能识别的形式 | 进货口 | 键盘、鼠标 |
| 输出设备 | 把运算结果转换为人熟悉的信息形式 | 出货口 | 显示器、打印机 |
五大部件在控制器的统一指挥下有条不紊地自动工作。注意控制器是"指挥"而非"动手":它只发命令,真正算数的是运算器,真正存取的是存储器。
4. 冯·诺依曼机的特点
把上面的内容归纳成教科书式的五条:
(1)指令和数据以同等地位存放于存储器内,并可按地址寻访;
(2)指令和数据均用二进制数表示——二进制只有 0 和 1 两种状态,用高低电平就能稳定区分,这是电子实现的天然选择;
(3)指令由操作码和地址码组成,操作码表示操作的性质(做什么),地址码表示操作数在存储器中的位置(对谁做);
(4)指令在存储器内按顺序存放,通常按顺序执行,特定条件下可根据运算结果或设定条件改变执行顺序(这就是跳转,if/else/循环的硬件基础);
(5)早期机器以运算器为中心,输入输出设备与存储器之间的数据传送都要经过运算器,运算器成了繁忙的"必经之路";现代计算机已改进为以存储器为中心,I/O 数据不再绕道运算器,系统吞吐量大幅提升。
5. 另一种流派:哈佛结构
冯·诺依曼的"程序和数据混放一炉"并不是存储程序的唯一实现方案。与之相对的是哈佛结构(Harvard Architecture),名字来自哈佛大学 1944 年的 Mark I 计算机——它把指令存在打孔纸带上、数据存在机械计数器里,从一开始就是物理分开的。现代哈佛结构的定义是:指令存储器与数据存储器分开,各有独立的地址总线与数据总线,取指与数据访问可以并行进行。两种结构的对比如下:
- 冯·诺依曼:一套存储器、一套总线,简单且内存分配灵活(程序数据各占多少运行时决定),代价是取指与取数共用通道、只能分时排队(著名的"冯·诺依曼瓶颈"),而且程序与数据同区,代码可能被当作数据误改;
- 哈佛:两套存储器、两套总线,取指与取数并行互不抢占,指令区还可以做硬件只读保护,代价是结构与成本翻倍,程序区/数据区的大小出厂就固定、不能灵活调配。
【注意】
这里先记住一个结论:后面要学的单片机(包括 STM32)普遍采用哈佛结构的一种改进形态,而 PC 采用的是冯·诺依曼式的统一内存。两者各自为什么这样选,与存储介质(FLASH/SRAM)和工作方式(XIP/按需装载)强相关,等到讲完单片机的组成与架构后再展开分析(见 LV013-单片机的通用架构)。
三、 五大部件逐一拆解
1. 运算器
运算器的核心是算术逻辑单元 ALU(Arithmetic Logic Unit),配合若干寄存器完成运算。以一个最简模型为例,参与运算的寄存器有三类:
- ACC(Accumulator,累加器):存放被操作数或运算结果,是使用最频繁的寄存器;
- MQ(Multiplier-Quotient Register,乘商寄存器):乘法时存放乘数、除法时存放商,配合 ACC 完成乘除;
- X:存放另一个操作数(加数、被乘数、除数等)。
例如计算 a + b:a 先放入 ACC,b 放入 X,ALU 做加法后结果回到 ACC。运算器内部这些寄存器的存在,正是后面 LV016-寄存器与硬件控制 要讲的"寄存器"概念的第一批实例。
2. 控制器
控制器的任务是"解释并指挥",它靠两个关键寄存器和一套控制逻辑工作:
- PC(Program Counter,程序计数器):存放下一条要执行的指令的地址,CPU 每取完一条指令,PC 自动加 1(按指令字长增加),指向下一条——程序的"自动推进"就是 PC 在驱动;
- IR(Instruction Register,指令寄存器):存放当前正在执行的指令本身,供控制器分析;
- CU(Control Unit,控制单元):对 IR 中的指令译码,产生一系列微操作命令,分发给各部件。
控制器本身不产生数据,它生产的是"命令":什么时候读存储器、什么时候让 ALU 做加法、什么时候把结果写回,全部由 CU 协调。
3. 存储器
主存储器(简称主存或内存)是整个体系的枢纽,可以形象地理解成一栋"宿舍楼":
- 存储体像一栋大楼,由许多存储单元(房间)组成;
- 每个存储单元里有许多存储元件(床位),每个元件寄存一位二进制代码 0 或 1;
- 一个存储单元存放的一串二进制代码称为一个存储字,其位数称为存储字长(相当于床位数);
- 每个存储单元有一个编号,称为存储单元的地址(房间号)。
【注意】
地址和内容是两回事:3 号房间住着谁,与"3"本身无关。访问存储器时给出的是地址,取到的是该地址里的内容。这个区分贯穿整个计算机体系,指针、间接寻址等概念都建立在它之上。
为了实现按地址访问,主存必须配两个寄存器作"桥梁":
- MAR(Memory Address Register,存储器地址寄存器):存放将被访问的存储单元的地址。MAR 的位数决定可寻址的单元个数——MAR 为 16 位时,可寻址
个单元,记作 64K(1K = 1024 = ); - MDR(Memory Data Register,存储器数据寄存器):存放从存储体某单元取出或准备存入的代码,其位数等于存储字长。
读存储器的完整过程:地址送 MAR → 存储器按 MAR 选中单元 → 该单元内容被读出送 MDR。写过程则相反:地址送 MAR、数据送 MDR → 存储器把 MDR 内容写进 MAR 指向的单元。如今 MAR 和 MDR 都已集成在 CPU 芯片内部。
容量单位从小到大依次为 K、M、G、T,均为 1024 进制(
4. 输入设备与输出设备
输入设备把信息形式转换的方向是"人 → 机器":键盘把按键变成字符编码,鼠标把位移变成坐标数据,摄像头把图像变成像素数组。输出设备方向相反:"机器 → 人":显示器把字符编码变成字形,打印机把数据变成纸上的墨迹,音箱把数字信号变成声音。
有的设备兼有两职:触摸屏既是输入也是输出;磁盘驱动器保存文件时是输出、读取文件时是输入。因此两者统称I/O 设备(Input/Output Equipment)。
5. 从五大部件到三大部件
运算器和控制器在逻辑关系和电路结构上联系十分紧密——控制器译码出的命令大部分是发给运算器的。大规模集成电路工艺出现后,这两大部件往往集成在同一块芯片上,合称中央处理器(Central Processing Unit,CPU)。于是现代计算机的硬件常按三大部分描述:
- CPU = 运算器 + 控制器;
- 主存储器:存放程序和数据;
- I/O 设备:输入设备 + 输出设备。
其中 CPU 与主存储器合称主机,I/O 设备又称外部设备(外设)。这个"三位一体"的视角,正是看懂现代计算机组成框图(见下图)的钥匙:
图中实线是数据流:程序与数据从输入设备进入主存,结果从主存送往输出设备,主存与运算器之间双向交换数据;虚线是控制流:控制器向其余四个部件发号施令。这个"以存储器为中心"的结构,正是教材上经典的现代计算机组成框图。
四、 计算机如何自动执行程序
1. 指令的组成
指令(Instruction)是机器语言的语句,告诉计算机"做什么、对谁做",其格式固定为两段:
- 操作码 OP:指明操作性质,如取数、存数、加、乘、打印、停机;
- 地址码 A:指明操作数所在的存储单元地址(或结果存放地址、下一条指令地址等)。
下面是一台教学用假想机器的指令系统节选:
| 操作码 | 操作性质 | 具体内容 |
|---|---|---|
| 000001 | 取数 | 将地址码指示的存储单元中的操作数取到运算器的累加器 ACC 中 |
| 000010 | 存数 | 将 ACC 中的数存至地址码指示的存储单元中 |
| 000011 | 加 | 将 ACC 中的数与地址码指示的存储单元中的数相加,结果存于 ACC 中 |
| 000100 | 乘 | 将 ACC 中的数与地址码指示的存储单元中的数相乘,结果存于 ACC 中 |
| 000101 | 打印 | 将地址码指示的存储单元中的操作数打印输出 |
| 000110 | 停机 | 停止运行 |
2. 一个完整的例子:计算
用上面的指令系统计算
设指令和数据依次存放在主存 0~12 号单元,程序清单如下:
| 主存地址 | 操作码 | 地址码 | 注释 |
|---|---|---|---|
| 0 | 000001 | 0000001000 | 取数 x 至 ACC |
| 1 | 000100 | 0000001001 | 乘 a 得 ax,存于 ACC 中 |
| 2 | 000011 | 0000001010 | 加 b 得 ax+b,存于 ACC 中 |
| 3 | 000100 | 0000001000 | 乘 x 得 (ax+b)x,存于 ACC 中 |
| 4 | 000011 | 0000001011 | 加 c 得 ax²+bx+c,存于 ACC 中 |
| 5 | 000010 | 0000001100 | 存数,将结果存入主存单元 |
| 6 | 000101 | 0000001100 | 打印结果 |
| 7 | 000110 | 停机 | |
| 8 | x | 原始数据 | |
| 9 | a | 原始数据 | |
| 10 | b | 原始数据 | |
| 11 | c | 原始数据 | |
| 12 | 存放结果 |
这张表值得仔细看,有三个细节埋着后面的伏笔:
(1)指令和数据混放在同一个存储器里:0~7 号是指令,8~12 号是数据,它们都是一串二进制代码,在存储器中没有本质区别——是"当指令取"还是"当数据取",完全取决于 PC 指向哪里。这正是存储程序思想的直观体现,也是"程序即数据"的起点;
(2)运算结果回 ACC,再由存数指令写回主存:数据不会凭空消失,总是在寄存器和存储器之间搬运——后面学 STM32 时,C 变量在寄存器和 SRAM 之间的流动与此一模一样;
(3)最后一条是停机指令:程序必须自己知道在哪里结束。
3. 取指令、分析指令、执行指令
现在回答本篇开头的问题:机器怎么"自己一步步走下去"?控制器的工作是一个永不停止的三步循环:
(1)取指(Fetch):把 PC 的内容送 MAR,命令存储器读出该单元的指令,指令经 MDR 送入控制器的 IR;
(2)分析(Decode):CU 对 IR 中的指令译码——操作码指出"做什么",地址码指出"操作数在哪个存储单元";
(3)执行(Execute):根据译码结果发出微操作命令:取操作数、命令 ALU 运算、存结果或输出。
一条指令执行完,PC 早已自动指向下一条指令的地址,于是又回到第(1)步……计算机的工作过程,就是周而复始地取指令、分析指令、执行指令。只要存储器里有程序、时钟在跳,这个循环就一直转下去,直到遇到停机指令或断电。
后面学 STM32 的中断时会看到:中断、异常本质上是"强行把 PC 改成另一个地址",让循环临时转到别处执行,处理完再跳回来——万变不离这个取指循环。
五、 衡量计算机性能的指标
有了部件和结构的语言,就可以量化地谈论一台计算机的"规格":
- 机器字长:CPU 一次能处理数据的位数,通常与 CPU 内部寄存器的位数有关。说"8 位机""32 位机"指的就是它——后面要学的 STM32F103 是 32 位机;
- 存储容量:存储单元个数 × 存储字长,常以 MAR 位数 × MDR 位数刻画,如
位。习惯上也用字节数表述,如 64 KB; - 主频:CPU 内部时钟的频率,决定 CPU 动作的节拍。主频越高,一次取指-执行循环的每个步骤完成得越快,如 STM32F103 的 72 MHz;
- 运算速度:与主频相关但更贴近真实体验,常用指标有三个:
- MIPS(Million Instructions Per Second):每秒执行的百万条指令数;
- CPI(Cycle Per Instruction):执行一条指令所需的平均时钟周期数——同一主频下 CPI 越小越快;
- FLOPS(Floating Point Operations Per Second):每秒浮点运算次数,衡量科学计算能力。
【注意】
主频和性能不能简单画等号:一条复杂指令可能要几十个时钟周期(CPI 大),一条简单指令可能只要 1 个。这就是为什么早年 1 GHz 的 Pentium III 和后来 1 GHz 的移动 CPU 性能天差地别——架构和 CPI 不同。
六、 从计算机到单片机
把本篇的整套概念压缩到一颗芯片上,对照关系如下:
| 本篇的通用概念 | 单片机里的对应 |
|---|---|
| ALU + CU + 寄存器组 | 内核(如 ARM Cortex-M3) |
| 主存储器(存程序) | FLASH(掉电不丢) |
| 主存储器(存数据) | SRAM(掉电丢失) |
| 输入输出设备 | 片上外设:GPIO、UART、定时器、ADC…… |
| 取指-分析-执行循环 | 内核每秒数千万次的日常 |
这张表就是下一篇的主角——单片机的预告。带着"五大部件去了哪里"这个问题,进入 LV004-什么是单片机。
七、 参考资料
- 唐朔飞《计算机组成原理(第 3 版)》第 1 章 计算机系统概论
- 01-概述/LV001-ARM体系结构——ARM 公司与处理器家族
- 01-概述/LV010-常见存储器——存储介质的物理实现
本文档由 markdowncli 技能辅助生成