
计算机组成原理这门课对软件方向的同学来说往往是大学四年里第一门真正让人“摸到硬件底裤”的课。平时上课你可能觉得它不过是一堆寄存器、时钟周期和真值表到了期末复习才发现整本书的知识点像散了一地的乐高积木单看每一块都认识合在一起就不知道怎么搭成一台能跑程序的计算机。我当年备考时也经历过这种状态后来把整本书按“数据怎么算、数据怎么存、指令怎么走、控制怎么发”四条线重新过了一遍才真正把知识点串起来。这篇期末复习文章我不会按教材目录给你重新抄一遍概念而是从备考视角出发把最容易考、最常混淆、最需要动手算的模块拆开讲清楚。不管你是科班出身还是软件方向被迫修这门课只要跟着这条主线走一遍把关键公式和判断套路记牢期末拿个还过得去的分数并不难。1. 先把整本书串成一条线复习前必须建立的全局框架1.1 冯诺依曼结构的“五部件”是复习的主心骨很多同学复习组成原理最大的问题不是不努力而是把教材当小说翻看完一章忘一章。原因很简单你没有给自己搭一个挂知识点的骨架。而组成原理的骨架就是冯诺依曼结构里的五大部件——运算器、控制器、存储器、输入设备、输出设备。这五个部件几乎可以对应到教材所有章节运算器对应数据表示与ALU设计存储器对应存储系统与Cache控制器对应CPU设计与微程序输入输出对应总线与中断。复习的时候我建议你在纸上画一个简单的框图把五大部件写出来然后每复习完一章就把这一章的核心知识点挂到对应部件旁边。比如复习到补码运算就挂在运算器下面复习到Cache替换算法就挂在存储器下面复习到流水线冲突就挂在控制器下面。这样到考前一周你只需要看这一张图就能在脑子里把整本书过一遍比反复翻书高效得多。这也就是为什么那些“知识点总结”类资料看起来很有用但如果你自己不画一遍最后上考场还是会乱——别人的框架是别人的你自己建立的知识索引才真正属于你。1.2 软件方向为什么也要硬啃这门课热词里有一条“学软件的要学计算机组成原理”这几乎是软件工程专业学生期末吐槽的固定话题。我的看法比较直白你写的高级语言代码最终都要变成指令在CPU里执行变量要落在寄存器或内存里函数调用要压栈循环要依赖程序计数器跳转。如果你完全不懂硬件遇到性能调优、并发编程、内存管理这些问题时就只能停留在“玄学”层面。举个最简单例子为什么局部性好的代码跑得快因为Cache命中率高CPU不用老去访存。为什么多线程程序有时候反而更慢因为线程切换要保存和恢复上下文涉及寄存器和栈操作如果频繁切换开销就很大。这些问题的答案统统指向组成原理。所以这门课不是用来为难软件学生的它是在给你建立“程序最终如何在机器上运转”的底层认知。理解了这一点复习的心态会好很多——你不是在背知识点你是在补一门必修的内功。1.3 建立自己的知识地图数据流、控制流、存储流我的建议是分三条线来组织知识数据流数怎么表示原码、补码、浮点数→ 数怎么算加法器、进位链、ALU→ 算完放哪寄存器、存储器。控制流指令怎么编码指令格式、寻址方式→ 指令怎么执行数据通路、控制器→ 多条指令怎么并行流水线、冲突处理。存储流存储层次怎么设计寄存器、Cache、主存、外存→ 每一层怎么映射Cache三种映射→ 数据怎么在层次间流动替换算法、写策略。这三条线不是孤立的它们通过“取指-译码-执行”这个循环绑在一起。复习时每看一个知识点都问自己一句这个知识点属于哪条线它在整台机器运行过程中出现在哪个环节一旦你能回答上来说明这个知识点你是真的理解了而不只是眼熟。2. 数据表示与运算器补码、浮点数和进位链怎么拿满分2.1 补码加减与溢出判断最基础也最不能丢分的运算题组成原理的运算题九成以上跑不掉补码。补码设计的精妙之处在于它把减法变成加法让符号位可以参与运算硬件实现变得非常简单。复习补码时你只要抓住一个核心规则补码按位取反再加一就能得到相反数的补码而补码做加减法直接按二进制加减规则算最后结果按模处理。这里最容易出错的考点有三个。第一个是补码的范围n位补码能表示的范围是-2^(n-1)到2^(n-1)-1注意负数比正数多一个因为补码里没有负零。第二个是符号扩展短数变长数时如果是补码需要在前面补符号位而不是补零这个细节在计算题和填空题里反复出现。第三个是溢出判断两个同号数相加结果符号变了或者两个异号数相减结果符号变了都属于溢出。更标准的判断方法是看最高位进位和次高位进位两者不同则溢出。我备考时还总结了一个简单口诀用双符号位判断最直观正数符号位是00负数符号位是11运算结果若变成01则正溢出变成10则负溢出。这个方法在考场上比盯着数值范围硬想快得多建议你平时做题时就养成这个习惯。2.2 IEEE754浮点数记牢位分布格式特殊值别背错浮点数这块期末考得最多的就是IEEE754单精度格式32位里第31位是数符S第30到23位共8位是指数E用移码表示偏置常数为127第22到0位共23位是尾数M。规格化数的尾数隐含一个整数位1所以实际表示的值是(-1)^S * 1.M * 2^(E-127)。计算题常见的考法是“给你一个十进制数让你转成IEEE754表示”或者反向转换。操作步骤很机械先转二进制、再规格化成1.xxx的形式、算出阶码加127、拼出符号位和尾数。这里最容易错的是阶码的表示——存储的E是移码不是补码很多同学直接把原阶码写进去结果错得莫名其妙。另一个坑是规格化时小数点移动的次数要与阶码的变化方向保持一致左移阶码加、右移阶码减这个细节值得多练几道题。特殊值部分不用背太多但至少要知道阶码全0且尾数全0表示0阶码全1且尾数全0表示无穷大阶码全1且尾数不为0表示NaN。这几个在填空题里很常见。另外如果你在复习时遇到“非规格化数”知道它的含义是阶码全0但尾数不为0用于表示接近0的极小数值就够了考试不深挖。2.3 加法器进位链串行进位、并行进位与组间串行进位的关系进位链是运算器部分的难点也是热词里单拎出来的一条。很多同学一看“组间串行进位”这六个字就懵其实它就是在两种极端方案之间取一个中间态。最朴素的行波进位串行进位加法器每一位的进位输出C_i要等低一位的进位输入C_(i-1)算出来后才能确定所以进位移位是一级一级往前传的。n位加法器最坏情况要做n次进位传递延迟很大。缺点是慢优点是什么简单、省硬件。考试里如果问串行加法器的延迟你要能说出关键路径从最低位输入到最高位进位输出。并行进位先行进位、超前进位则换了一种思路让每一位的进位信号只依赖于最低进位输入和参与运算的各位而不是依赖低位的进位输出。用进位生成函数G_iA_i·B_i和进位传递函数P_iA_i⊕B_i来表示C_i就可以通过展开式直接算出来。4位超前进位加法器典型芯片是74182这类能在同一时刻算完所有进位速度非常快但位数一多电路规模会爆炸。组间串行进位就是把多个超前进位小组串联起来组内用并行进位组间用串行进位。比如16位加法器可以先做4个4位超前进位加法器然后把这四组按串行方式连接让进位在组间一级一级传。这样一来组内延迟很小组间延迟虽然还存在但已经比完全的行波进位快很多。这个概念对应热词里的“组间串行进位”几乎每年都有学校考一个“8位或16位加法器由几个4位CLA组组成进位如何传递”的简答或填空。你需要记住的关键点就一句组内并行组间串行速度介于全串行和全并行之间。3. 存储系统与Cache三个映射方式的判断与计算套路3.1 存储层次为什么Cache这么重要存储系统的核心矛盾是速度、容量和成本不可能同时满足。寄存器的速度快但容量小、价格贵内存容量大但速度跟不上CPU所以现代计算机在CPU和主存之间加了一层Cache。Cache之所以能工作靠的是程序局部性原理时间局部性指刚访问过的数据很可能马上再被访问空间局部性指访问过一个地址后它旁边的地址也很可能被访问。期末复习时Cache这部分一定会有大题通常是给你一个Cache容量、主存容量、块大小让你算地址结构、求命中率或平均访问时间。解题的关键是先搞清楚三件事Cache有多少块、主存有多少块、每一块有多少字节。这三个数字一出来标记位数、索引位数、块内偏移位数就是套公式的事。3.2 三种映射方式地址结构、命中率与替换算法全相联映射主存中任意一块可以放到Cache任意一行。优点是冲突率最低缺点是查表时要比较全部有效位和标记硬件成本高。地址结构是“标记 块内偏移”不需要索引位。直接映射主存中每一块只能放到Cache中唯一的一行位置由“主存块号 mod Cache行数”决定。优点是硬件简单、查表快缺点是冲突率高容易频繁替换。地址结构是“标记 行索引 块内偏移”。组相联映射折中方案Cache分成若干组每组有v行v路组相联。主存块可以放到指定组里的任意一行。地址结构是“标记 组索引 块内偏移”。考试常考的是二路、四路组相联地址结构计算题尤其多。我的做题套路是先根据块大小算出块内偏移位数再根据Cache组数算出组索引位数剩下的高位就是标记位数。替换算法方面全相联和组相联需要替换算法常见的是LRU最近最少使用、FIFO先进先出、随机替换。LRU是期末最爱考的因为它的命中率通常比FIFO好也更符合局部性原理。如果出计算题你就按访问序列一列一列地画Cache状态变化表细心一点基本不会错。3.3 平均访问时间计算题把公式写成“查表判断”三步平均访问时间题目一般给出Cache命中率h、Cache访问时间tc和主存访问时间tm让你算CPU平均访存时间。单层Cache的公式就一个ta h × tc (1-h) × (tc tm)注意很多教材在未命中时还需要再加一次Cache访问时间因为要先查Cache发现没命中再去访问主存所以访问时间为tctm。有些学校会考两级Cache公式就变成ta tc1 (1-h1) × tc2 (1-h1) × (1-h2) × tm。这种题看着复杂实际上就是把“逐级未命中的概率”乘上去而已。做题时我习惯先列已知量再判断该用哪一层公式最后带数据算。只要单位不搞混通常用ns这种题就是送分题。提醒一个易错点题目有时会给“Cache-主存系统效率”或“加速比”要用ta去除以纯Cache访问时间或者用不带Cache的访问时间除以带Cache的访问时间。先看清题目问的是效率还是加速比再决定公式放哪边做分子分母不然一步错后面全错。4. 指令系统与寻址方式读题识别考点的高频套路4.1 指令格式与扩展操作码定长指令字是怎么塞进去的指令系统这一章期末考试喜欢考指令格式设计和寻址方式判断。指令格式设计里最经典的就是“扩展操作码”。为什么要扩展操作码因为你希望指令字的长度固定但操作码可以有长有短让操作码位数少的指令保留更多地址码位数操作码位数多的指令牺牲地址码数量。典型例子是16位定长指令字四地址指令只能给操作码留很少位数三地址、二地址、一地址、零地址指令依次扩大操作码位数。做题时记住一个原则短操作码是长操作码的前缀译码时从前往后匹配。具体算最多能容纳多少条指令时要看地址码占用位数。比如16位字长、地址码各占4位时四地址码占16位操作码0位这显然不行所以通常四地址只有少数几条剩下组合都留给低地址指令。这一块的题目需要你仔细数每一个地址码字段占几位宁可慢一点也不要跳步。4.2 常用寻址方式六个高频考点与判题技巧寻址方式几乎是每年必考的常见的有立即寻址、直接寻址、间接寻址、寄存器寻址、寄存器间接寻址、变址寻址、基址寻址、相对寻址。考试要么给你一条指令的地址码和寄存器内容让你算有效地址要么给你一段描述让你判断属于哪种寻址方式。我的判断技巧是分两步。第一步看操作数在哪在指令里就是立即寻址在寄存器里就是寄存器寻址在内存里就是存储器的某一种寻址。第二步看地址怎么来直接给出的就是直接寻址地址在寄存器里的就是寄存器间接寻址地址要再访存一次的就是间接寻址。变址和基址容易被混淆这里有个考试潜规则变址寻址的变址寄存器内容由用户指定常用于数组循环访问指令中的形式地址是基准量基址寻址的基址寄存器内容由系统管理用于程序重定位指令中的形式地址是偏移量。而相对寻址是PC内容加偏移量专门为转移指令服务。如果出简答题问你“变址寻址和基址寻址有什么区别”你就抓住上面这两个关键点展开一个面向数组处理、一个面向程序浮动一个由用户控制、一个由系统控制。4.3 简答题素材RISC与CISC、指令流水设计目标指令系统部分的简答题最常抽中的就是对RISC和CISC的对比。CISC复杂指令集计算机指令条数多、指令格式不规整、寻址方式丰富用微程序控制实现优点是编译器好写缺点是译码复杂、流水线不好优化。RISC精简指令集计算机指令条数少、格式规整、寻址方式少采用硬布线控制寄存器数量多适合指令流水。答题时可以记住几个关键词等长指令字、Load/Store结构只有访存指令能访问内存、硬布线控制、大量通用寄存器、流水线友好。这些点写全了简答题基本能拿满。另外一个容易被忽略的点是“RISC为什么有利于指令流水”因为指令规整、长度一致取指段可以统一长度译码逻辑简单冲突更容易通过硬件转发解决——这个可以跟后面流水线冲突的内容打通起来理解。5. CPU数据通路与流水线结构相关数据相关辨析5.1 数据通路设计单周期、多周期到底在折腾什么CPU这一章很多同学觉得很难因为教材画了一堆电路连线。其实期末不会让你去设计一个完整CPU更多是考概念和数据通路结构的选择。单周期CPU每条指令在一个时钟周期内完成控制简单但时钟周期要按最慢指令的时间来定比如Load指令又要访存又要写寄存器周期就特别长整体效率不高。多周期CPU把每条指令分成多个步骤每一步一个周期不同指令占的周期数不同硬件部件可以在不同阶段复用时钟周期可以缩短但需要增加状态寄存器来记住当前进度。考试常考的点是一条指令执行过程中哪些部件在用、哪些部件空闲或者分别列出单周期和多周期的优缺点。理解的关键点是数据通路中程序的执行路径取指令时PC给出地址、指令存储器读出指令执行运算时寄存器堆给出两个操作数、ALU计算访存时数据存储器读写写回时结果写回寄存器堆。把这几个阶段串起来数据通路题就不会太慌。5.2 控制器的两种实现硬布线与微程序控制器是发出“谁在什么时刻做什么”信号的部件。硬布线控制器用组合逻辑电路直接生成控制信号速度最快但设计完成后想改指令几乎不可能所以RISC处理器常采用硬布线控制。微程序控制器把每条指令解释成一段微指令序列存放在控制存储器里执行时逐条读出微指令并发出控制信号优点是灵活改指令只需要改微程序缺点是每条指令都要多一步“读控制存储器”的操作速度慢一些CISC处理器常用微程序控制。考得多的对比题目是微程序控制器里“微指令”和“机器指令”的关系。答题要点是一条机器指令对应一段微程序一段微程序由若干条微指令组成每条微指令包含控制字段和下址字段控制字段决定各部件做什么操作下址字段决定下一条微指令的地址。5.3 流水线冲突结构相关、数据相关、控制相关一次说清流水线是CPU章节的压轴考点也是热词“数据相关结构相关”的出处。五段经典流水是取指IF、译码ID、执行EX、访存MEM、写回WB。理想情况下每个时钟周期都有一条指令完成吞吐率提高但流水线会遇到三类冲突。结构相关资源冲突硬件资源不够用两条指令在同一时刻想用同一个部件。最典型的例子是取指和Load访存同时需要访问存储器。解决方法就是让指令存储器跟数据存储器分开或者让Load暂停一拍。数据相关指令之间存在数据依赖。最常见的是RAW写后读比如第1条指令写寄存器R1第2条指令要读R1顺序反了就出错。解决方法包括转发/旁路技术把第1条指令的结果直接送到第2条指令需要的位置如果做不到就插入空操作软件上可以调整指令顺序把不相关的指令插到中间。还有WAW写后写和WAR读后写但五段流水里因为按序写回一般不重点考能区分定义就行。控制相关分支冲突碰到转移指令流水线不知道下一条该取谁。流水线在分支结果出来之前只能猜测猜错就要冲刷已经取入的指令。解法有分支预测、分支延迟槽等。我以前做题时区分这三类冲突有一个速记法结构相关是“抢硬件”数据相关是“等数据”控制相关是“不知往哪走”。问你“如何解决数据相关”优先答转发技术和编译器调度如果题目说转发已经用上了还冲突再答插入空操作。这个答题顺序是按性价比排的很多参考答案只提一个解容易丢分。6. 期末实验与综合问答题从模拟器到简答题的拿分策略6.1 教学模拟器和实验课常见形式与拿分点组成原理实验在不同学校形式差别很大有的是用Logisim这种可视化电路工具搭加法器、搭单周期CPU有的是用C语言写一个MIPS指令集模拟器还有的是用学校课题组自研的模拟软件做汇编级调试。不管具体用哪个工具考察的核心都一样你懂不懂指令的执行流程和数据的流动。实验题拿分的关键首先是把你实现的指令集清单写清楚哪些是R型如add、sub、哪些是I型如lw、sw、addi、哪些是J型如j、jal每条指令的操作码、功能、对寄存器或内存的影响都列出来。其次是要准备一段“测试程序”来证明你的实现正确比如先用addi给两个寄存器赋值再用add把结果算出来用sw存到内存再用lw读回来。这种自测代码在答辩时非常有用老师一看就知道你是真做了。如果你用的是带交互界面的教学模拟器要注意掌握单步执行和查看寄存器/内存变化的功能。期末实验答辩时老师很爱问“这条指令执行完哪个寄存器变了”“这条指令访问了几次内存”平时多戳几下软件界面比考前临阵抱佛脚有用得多。6.2 经典问答题的结构化答法期末问答题其实有固定套路。我整理了几道高频题和建议的答题框架第一道冯诺依曼计算机的特点。答“存储程序、按地址访问、指令和数据同等对待、五大部件组成”然后展开解释一下“存储程序”是什么意思就是程序事先存放在存储器中运行时按地址逐条取指令执行。再补充一句“运算器以ALU为核心、控制器统一指挥”就算完整。第二道DMA和中断方式的区别。这个题每年都有学校考。答法要点是中断方式每传一个数据都要CPU介入DMA方式由DMA控制器直接控制主存和I/O设备之间的数据传送只在传送前和传送结束后打扰CPU中断可以处理随机事件DMA适合高速批量数据传送DMA需要占用总线中断不需要。记得提一句“DMA传送结束后也要向CPU发中断报告”。第三道程序局部性原理是什么以及它在Cache设计中的作用。答法就是定义“时间局部性和空间局部性”然后说Cache正是利用这一原理把最近访问过的数据和它附近的数据放入高速缓存提高命中率降低平均访存时间。问答题丢分往往不是因为不会而是因为写太少。考场上按“定义→原理→作用→举例”四步写满比只写一行定义稳得多。6.3 易混淆概念对照表考前最后一天我建议你把下面这张表过一遍。这些成对概念几乎每年都有选择题或判断题在里面出题搞混一个就丢两分容易混淆的概念关键区分点常考场景原码/反码/补码原码符号位绝对值补码负数按位取反加一十进制转补码、补码范围行波进位/先行进位串行传进位 vs 并行直接算进位加法器延迟分析组间串行/组间并行组内并行组间串行 vs 组间也并行16位加法器结构直接映射/全相联/组相联位置固定 vs 随意放 vs 组内随意Cache地址结构计算Cache写直达/写回同时写主存 vs 仅标记脏位写策略选择题变址/基址用户控制数组 vs 系统控制重定位寻址方式判断硬布线/微程序快但难改 vs 慢但灵活控制器实现方式DMA/中断CPU介入程度不同I/O方式简答RISC/CISC精简规整 vs 复杂灵活指令系统设计目标这张表你不需要背下来但要能看着左列说出右列的“关键区分点”。能做到这一点说明你对整本书的骨架已经有把握了。我自己复习时的习惯是考前最后两天不再刷生题而是把教材目录翻开对着目录自己给自己讲一遍每章的三到五个核心知识点。讲得出来就过讲不出来就翻书补。这个方法听着简单但非常能暴露知识盲区。这门课的知识点彼此咬合得很紧一个小地方断了后面连着好几个考点都会跟着崩。你花在建立框架和辨析概念上的时间永远比多背两个公式值钱。