速成 · 计算机系统基础
这门课的上下半部分不是两门互不相干的课。
- 计算机组成原理回答:一条指令怎样被编码,硬件怎样让它真的执行;
- 操作系统回答:许多程序怎样安全、并发地共享处理器、内存和外设。
把二者接起来,就是完整的执行链:
复习时不要只背名词。每遇到一个机制,都问三件事:状态放在哪里、谁触发变化、硬件和内核各做哪一段。
硬件与操作系统怎样接力
| 层次 | 核心对象 | 常见题型 |
|---|---|---|
| 数字表示 | 位、补码、浮点数 | 进制转换、溢出、表示范围 |
| 数字逻辑 | 门、组合电路、时序电路 | 化简、真值表、状态机 |
| 指令系统 | MIPS 指令与寄存器 | R/I/J 编码、寻址、汇编 |
| 处理器 | 数据通路和控制信号 | 单周期走线、流水线冒险 |
| 存储层次 | RAM、Cache、虚拟存储 | 地址划分、命中、页表 |
| OS 入口 | 异常、中断、系统调用 | 用户态到内核态的链路 |
| 进程管理 | 进程、线程、调度 | 状态转换、周转时间 |
| 并发控制 | 临界区、信号量、死锁 | P/V 伪代码、Banker |
| 持久化与外设 | I/O、磁盘、文件系统 | 磁盘调度、文件分配 |
第一部分:计算机组成原理
1. 数值表示:先确定位宽和解释方式
同一串比特没有天然含义。它可以被解释为无符号整数、补码整数、指令或浮点数。
对 位补码:
做补码题时固定四步:
- 写清位宽;
- 正数按普通二进制写,负数由绝对值按位取反再加一;
- 在固定位宽内完成加法;
- 丢弃最高进位,再单独判断溢出。
有符号加法的溢出判据是:
两个同号数相加,结果却与它们异号。
无符号数则看最高位进位。二者不能混用。
IEEE 754 单精度分为符号位、8 位阶码和 23 位尾数字段。正规数为
先分类 、、,再计算;不要一上来就套正规数公式。
2. 组合逻辑与时序逻辑
组合电路的输出只由当前输入决定;时序电路还依赖先前状态。
逻辑化简常用:
Karnaugh 图的关键不是“画圈”,而是:
- 每圈格数必须是 ;
- 允许跨边界相邻;
- 尽量圈大,可重叠;
- 圈内发生变化的变量被消去。
分析时序电路时按固定链条:
设计状态机则反过来:先从题意定义状态,再编码、选触发器、列激励并化简。
3. MIPS 指令格式
MIPS 的三个基本格式:
| 格式 | 字段 | 主要用途 |
|---|---|---|
| R 型 | opcode, rs, rt, rd, shamt, funct | 寄存器运算 |
| I 型 | opcode, rs, rt, immediate | 立即数、访存、条件分支 |
| J 型 | opcode, instr_index | 大范围直接跳转 |
R 型手算顺序:
- 按助记符确认 ,不要照汇编书写顺序机械抄;
- 每个寄存器编号写成 5 位;
- opcode 和 funct 各写 6 位;
- 拼成 32 位,再转十六进制。
I 型的 16 位立即数究竟符号扩展还是零扩展,由指令语义决定:
- 地址偏移、分支位移、加法立即数通常符号扩展;
- andi、ori 等把立即数当位模式,使用零扩展。
条件分支目标为
所以汇编器填写
J 型目标地址为
4. 从 C 到 MIPS
数组元素地址:
翻译循环或分支时,先写控制流,再填数据操作:
- 标出循环头、循环体和退出标签;
- 把条件改写成 MIPS 可比较的形式;
- 明确每个变量放在哪个寄存器;
- 最后检查 load/store 的字节偏移。
函数调用必须区分两类寄存器:
- 调用者保存:调用前若还要用,调用者自己压栈;
- 被调用者保存:函数若要改,入口保存、返回前恢复。
栈帧里还要考虑返回地址、局部变量和对齐。递归只是每次调用都有独立栈帧,并不是另一套机制。
5. 单周期 CPU:让每条指令走一遍数据通路
单周期题不要背整张图,按信息流追踪:
- PC 送入指令存储器并同时计算 ;
- 指令字段选出寄存器和立即数;
- ALU 完成算术、地址或比较;
- 必要时访问数据存储器;
- 多路选择器决定写回数据和下一条 PC。
控制信号的本质是“选择哪条路”或“是否写入”:
- RegWrite:是否写寄存器;
- MemRead、MemWrite:是否访问数据存储器;
- ALUSrc:ALU 第二操作数来自寄存器还是立即数;
- MemtoReg:写回来自 ALU 还是存储器;
- Branch、Jump:下一条 PC 怎样选。
新增一条指令时,先问已有数据通路能不能运送它需要的数据,再补硬件和控制信号;不要只改控制表。
6. 五级流水线
经典五级为:
理想情况下, 条指令在 级流水线中的周期数近似
实际还要加暂停和清空周期。时钟周期由最慢流水级加流水寄存器开销决定,所以级数越多不等于性能无限提高。
数据冒险先列读写关系:
- RAW:后指令要读前指令尚未写出的结果,最常见;
- WAR、WAW 在经典顺序五级 MIPS 中通常不会发生。
转发解决“结果已经算出但还没写回”的情况;load-use 冒险中,数据到 MEM 末尾才得到,紧随其后的使用者通常仍需暂停一拍。
控制冒险来自分支结果尚未确定。常见处理是暂停、预测或在判错后清空错误路径。
画时序图的固定步骤:
- 先画没有冒险的斜线;
- 标出每条指令何时需要源操作数、何时产生结果;
- 按题目给定的转发能力判断能否直送;
- 不能转发才插入 stall;
- 再处理分支 flush。
7. Cache
地址总能拆成:
若块大小为 字节:
位是块内偏移。若 Cache 数据容量为 , 路组相联,则
组,组索引位数为
Tag 位数等于地址总位数减去 。
模拟访问序列时,为每一组单独维护有效位、Tag、脏位和替换次序。不要把“访问相同组”误当成“命中”;Tag 也必须相等。
Cache 的实际总容量还包括 Tag、有效位、脏位和替换状态,不能只答数据区容量。
平均访存时间常写为
写策略要同时说明 write-through 或 write-back,以及 write-allocate 或 no-write-allocate。
8. 主存芯片扩展
把目标存储器写成“字数 位数”。
- 位扩展倍数 = 目标字长 / 芯片字长;
- 字扩展倍数 = 目标字数 / 芯片字数;
- 总片数 = 两者乘积。
低位地址送到所有芯片内部选字,高位地址经过译码选择哪一组芯片。数据位宽扩展时,多片芯片并行贡献同一个字的不同位。
第二部分:操作系统
9. 用户态怎样进入内核
操作系统的基本特征是并发、共享、虚拟和异步。应用不能直接执行特权操作,而是通过受控入口进入内核。
三类事件要分清:
- 中断:外设或时钟异步触发;
- 异常:当前指令执行导致,如缺页、除零;
- 系统调用:程序主动执行陷入指令,请求内核服务。
统一入口链:
启动过程则从固件建立最初环境开始,经引导程序装入内核,内核初始化内存、异常入口、进程和设备,最后启动第一个用户进程。
10. 连续分配、分页与分段
连续可变分区中的 First Fit、Next Fit、Best Fit、Worst Fit 都是在空闲区表上选洞。外部碎片是空闲空间总量够但不连续;内部碎片是分给进程的块内部没有用完。
分页把虚拟地址拆成:
若页大小为 字节,页内偏移就是 位。地址转换:
页内偏移原样拼接。
页表计算题固定五步:
- 由页大小求 offset 位数;
- 用地址总位数减出 VPN 位数;
- 按各级索引位数切地址;
- 由“基址 + 索引 表项大小”求表项地址;
- 从表项取页框号,再拼接 offset。
TLB 是页表项的高速缓存。TLB miss 不等于缺页;它可能只需查内存中的页表。页表项无效才进入缺页处理。
分段按程序的逻辑单元管理,地址是“段号 + 段内偏移”;页是固定大小的物理管理单位。段页式先按段找到该段页表,再分页转换。
11. 虚拟内存与页面置换
虚拟内存建立在局部性上,只把当前需要的页面装入内存。缺页时:
- CPU 发现页表项无效并陷入内核;
- 内核确认访问合法;
- 选择空闲页框或牺牲页;
- 脏页必要时写回;
- 从磁盘读入所需页;
- 更新页表和 TLB;
- 重新执行导致缺页的指令。
置换算法:
- OPT:淘汰未来最晚再用的页,只能作为理论最优基准;
- FIFO:淘汰最早进入的页,可能出现 Belady 异常;
- LRU:淘汰最长时间未使用的页;
- Clock:用访问位近似 LRU。
手算时逐次写页框状态和是否缺页,不能只凭直觉数。
页面频繁换入换出、有效执行时间很少就是抖动。减少并发度、使用局部置换或工作集思想能缓解。
12. 进程与线程
程序是静态代码;进程是一次正在进行的执行,拥有地址空间和资源;线程是进程中的执行流,共享进程资源但有自己的寄存器现场和栈。
进程常见状态:
- 调度:就绪 运行;
- 时间片到或被抢占:运行 就绪;
- 等待 I/O 或同步条件:运行 阻塞;
- 事件完成:阻塞 就绪。
上下文切换不是“进程自己继续执行”,而是内核保存旧现场、选择新执行实体、恢复新现场。切换有开销但不直接完成用户工作。
13. 进程同步
临界区问题要满足互斥、前进和有限等待。信号量是带原子 P/V 操作的整数:
- P:申请资源;资源不可用时阻塞;
- V:释放资源;必要时唤醒等待者。
做同步题时先把信号量按职责命名:
- mutex 只保护临界区;
- empty、full 记录缓冲区空槽和已有产品;
- 事件型信号量表达先后关系。
生产者—消费者的典型顺序:
| 生产者 | 消费者 |
|---|---|
| P(empty) | P(full) |
| P(mutex) | P(mutex) |
| 放入产品 | 取出产品 |
| V(mutex) | V(mutex) |
| V(full) | V(empty) |
先等待资源再拿互斥锁,可避免“拿着锁睡眠,另一方永远进不来”的死锁。
14. CPU 调度
常见指标:
算法要点:
- FCFS 简单但可能出现短作业等待长作业;
- SJF 平均等待时间好,但需估计服务时间;
- SRTF 是可抢占的最短剩余时间优先;
- RR 按时间片轮转,时间片过大趋近 FCFS,过小切换开销高;
- 优先级调度可能饥饿,aging 可逐渐提高等待者优先级。
计算题一定画 Gantt 图;动态到达时,每个决策点只在已经到达的进程中选择。
15. 死锁
死锁同时需要四个条件:
- 互斥;
- 占有并等待;
- 不可抢占;
- 循环等待。
处理思路有预防、避免、检测和恢复。Banker 算法判断的不是“当前能否立刻满足所有需求”,而是是否存在某个安全序列。
令
安全性检查:
- Work 初始化为 Available;
- 找到一个 的未完成进程;
- 假设它完成并释放资源,令 ;
- 重复;若所有进程都能依次完成,则状态安全。
安全状态保证存在完成顺序;不安全状态不等于此刻已经死锁,但未来可能无法避免。
16. I/O 与磁盘
外设速度慢且行为异步。常见数据传送方式:
- 程序查询:CPU 反复轮询;
- 中断驱动:设备完成后通知 CPU;
- DMA:控制器直接在设备和主存间搬运一批数据,CPU 只负责设置和收尾。
缓冲可以吸收速度差;spooling 用磁盘把独占设备虚拟成可排队共享的设备。
磁盘访问时间主要由寻道、旋转等待和传输构成。调度算法:
- FCFS:按请求顺序;
- SSTF:先服务最近磁道,可能让远端请求饥饿;
- SCAN:磁头像电梯一样来回;
- C-SCAN:只沿一个方向服务,回程不服务,等待更均匀。
计算磁头移动量时,先在数轴上标当前磁道、方向和全部请求,再按算法逐个连线。
17. 文件系统
文件系统要回答:
- 名字怎样映射到文件元数据;
- 文件偏移怎样映射到磁盘块;
- 空闲块怎样记录;
- 崩溃后怎样保持一致性。
常见分配:
| 方式 | 优点 | 代价 |
|---|---|---|
| 连续分配 | 顺序和随机访问快 | 外部碎片、扩展困难 |
| 链接分配 | 易增长、无外部碎片 | 随机访问慢、指针开销 |
| 索引分配 | 支持随机访问和增长 | 索引块占空间 |
目录项把文件名连接到 inode 或等价元数据。inode 保存类型、权限、大小、时间、块地址等,不保存路径名本身;硬链接是多个目录项指向同一 inode。
空闲空间可用位图或空闲链表管理。位图便于寻找连续空闲块,但需要存储和扫描。
高频综合题的统一做法
地址题
先写出总位数,再按“页内偏移 / Cache 块内偏移最先由大小决定”的原则切字段。每个索引都明确单位是字节、字、块、页还是表项。
流水线题
先列每条指令读哪些寄存器、写哪个寄存器,再根据题目给定的转发路径和寄存器堆时序判断暂停;不能把课本中的完整转发能力擅自带入题目。
同步题
先写不变量,例如
再为互斥和先后关系分别设信号量。最后逐条检查是否可能持锁阻塞、是否可能漏唤醒。
页面置换与调度题
都画时间线。每一步只根据当时可见的信息更新状态,不事后用未来信息,OPT 除外。
考前最后检查
- 补码位宽、符号扩展和溢出判据有没有混;
- R/I/J 字段、分支基准 是否写对;
- 单周期指令经过哪些部件、哪些写使能打开;
- 流水线题是否按题目给定的转发能力判断;
- Cache 是否同时比较 Index 和 Tag;
- TLB miss、页表命中、缺页三者是否分清;
- 进程状态转换的触发者是否写清;
- P/V 顺序是否会拿锁后睡眠;
- 调度题是否只选已经到达的进程;
- Banker 的 Need、Work 是否逐轮更新;
- 磁盘调度是否考虑初始方向;
- 文件名、目录项、inode、数据块是否分层。
如果这些链条都能不用背诵地解释出来,这门课就不再是两堆术语,而是一台机器从通电到运行多个程序的完整故事。