☰
408计算机组成原理笔记重构:补码、Cache映射与流水线冲突
2026/9/30 4:31:11 网站建设 项目流程

第一次完整做408真题的时候,计组部分我错了11道选择加半道大题,而我当时已经把那本厚厚的复习指导书翻过两遍。问题不在于我没看过知识点,而在于我把"看过"当成了"掌握"——书上写的Cache映射、补码运算、流水线冲突,我都能读明白,可一旦换成真题里的具体数字和问法,脑子里就是一团浆糊。后来我花了大概六周时间,把计算机组成原理从头到尾用"笔记重构"的方式重新过了一遍,才算是真正把这块硬骨头啃下来。

这篇内容就是我把那套笔记整理、复盘后的完整产物。它讲的不是"王道笔记怎么背",而是一个更实际的问题:计算机组成原理这门课,知识点又碎又绕,计算量还不小,你该怎么把厚书读薄、把散点连成线,最后在考场上看到题目就能条件反射般地选出正确解法。适合已经过了一遍基础、正在强化或者准备冲刺的同学,也适合刚开始复习、想少走点弯路的人。下面我会按知识点模块来讲,每个模块都会告诉你哪里最容易翻车、笔记该怎么记、题目该怎么下手。

1. 为什么我更推荐"重构笔记"而不是抄书划线

1.1 复习指导书的定位:它是提纲和题库,不是教科书

很多人复习计组有个误区,就是把那本单科复习指导当成教材来读,从头到尾一个字一个字地啃。实际上它的写法是"考点驱动"的——每个知识点后面直接跟真题和习题,中间省略了大量推导和铺垫。这个设计对应试很友好,但它有个副作用:你会误以为知识点之间是平铺的,看不出它们的内在联系。

就拿补码和浮点数来说,书上是分成两节写的,看起来是两个独立考点。但它们本质上都是"用有限的位模式表示数"这一件事的两个层级:定点数是整数层面的编码,浮点数是"阶码加尾数"的编码。你如果分开背,写题的时候就会把它们当成两套规则;你要是能意识到它们共享同一套模运算和位运算逻辑,很多推导都能自己推出来,不用死记。

所以我的建议是,复习指导书用来定位考点、做真题;真正的笔记要自己重新组织,按"问题—原理—推导—易错点"的逻辑走一遍,而不是按书上的章节顺序抄一遍。

1.2 我的笔记三层结构:骨架层、推导层、错题层

我把每一章的笔记都拆成三层,用一个活页本分栏记,左边窄、右边宽:

  • 骨架层:只写知识点之间的逻辑关系,用箭头和短句,比如"地址位数 → 分几段 → 每段多少位 → 标记位数怎么算"。这一层的作用是让你闭上书也能复述出这章的脉络。
  • 推导层:把书上一笔带过的关键推导亲手写一遍,尤其是带公式和参数的。比如IEEE 754真值公式、Cache标记位数公式、流水线加速比公式,写一遍比读十遍记得牢。
  • 错题层:只记"我为什么会错",不记题目本身。错题本记题目的都是假努力,因为你下次看还是看答案,关键是把错误归因写清楚。

这三层里,错题层是最容易被忽略、也是收益最高的。我后期冲刺阶段基本只看错题层,一道题的归因能顶十道新题。

1.3 举个小例子:补码笔记该怎么记

很多人补码的笔记就是一句话"负数补码等于反码加一",然后配几个转换例子。这种笔记遇到简单题够用,遇到"补码运算结果判断溢出"就崩了。

我记补码的时候是这样组织的:

层面内容
骨架n位补码的模是2的n次方,符号位就是权值为负的那个数位
推导负数补码 = 模 − 该数绝对值,所以符号位天然参与运算
速算从右往左找第一个1,这个1及其右边不变,左边全取反
易错最小负数没有对应的正数,取相反数会溢出

你看,同样是补码,这样记下来,后面遇到溢出判断、加法器进位、浮点尾数运算,都能直接调用同一套直觉。这就是"重构"和"抄写"的区别。

2. 数据表示与运算:卡人的从来不是转换,而是运算和溢出

2.1 把"模"这个念头装进脑子

这一章真正让人头疼的不是进制转换,那玩意儿练几遍就熟了,而是原码、反码、补码、移码之间的运算规则和溢出判断。而这一切的钥匙就是"模"。

我用生活里的类比来说:钟表是模12的。现在指针指向10点,你要往回调3个小时到7点,可以正着往回拨3格,也可以正着往前拨9格——两种情况指针停在同一位置。为什么?因为往前拨9格,过了12点之后又重新开始,多出来的那一圈被"丢掉"了。

计算机里的n位寄存器就是一个模2的n次方的时钟。减法A−B可以变成A加上B的补码,因为B的补码等于模减去B,加完之后多出来的模被最高位溢出自然丢弃。理解这一点之后,符号位参与运算就不再是个"奇怪的规定",而是必然结果。

笔记本上我专门留了一页写这个类比,旁边批注一句:"补码的符号位不是标记,是真正的数位,权值是负的。"这句话帮我解决了好几个难点,包括后面移位运算时为什么要补符号位。

2.2 溢出判断三种方法其实是一回事

复习指导书给了三种溢出判断方法,很多人背了三个独立的结论,用的时候靠"看题目给什么条件"去碰。其实它们描述的是同一个现象。

  • 一位符号位法:两个正数相加得到负数,或者两个负数相加得到正数,就是溢出。这是从结果看现象。
  • 变形补码(双符号位)法:用两位符号位表示,结果符号位是01表示正溢,10表示负溢,00和11正常。这是把现象放大到两位,方便一眼看出来。
  • 进位判断法:最高位进位和次高位进位不同则溢出。这是从原因入手。

三者等价。进位判断法尤其值得强调,因为它直接连到后面的加法器进位链。我在笔记上画了一条注释线:符号位产生的进位C_n和最高数值位产生的进位C_{n-1}不相等,说明符号位的"权值"被额外的量改变了,也就是数值超出了范围。

实际做题的时候,我习惯用双符号位法,因为它对加法、减法、移位都适用,而且不用记进位序号,出错概率最低。但进位判断法必须理解,因为它是加法器那章的基础。

2.3 IEEE 754浮点数:手算流程必须形成肌肉记忆

浮点数这块,考试大概率会考一道大题,可能是"给一个数写出IEEE 754单精度表示",也可能是"给一个十六进制表示反推真值"。这种题不难,但步骤多、容易漏。

我给自己固定了一条手算流程,写题时按顺序走:

  1. 把十进制数写成二进制的规格化形式,即1.xxxx × 2的e次方。
  2. 符号位S:正数0,负数1。
  3. 阶码E = e + 127,转成8位二进制。
  4. 尾数字段M = 小数点后的23位,不足补0。
  5. 拼接S、E、M。

反推的时候倒着来:先拆字段,还原真实的e = E − 127,再还原1.M,最后算真值。

我踩过的一个坑是"规格化"这一步。我曾经把一个本来就小于1的数直接当成0.xxxx去写,忘了要先把小数点左移或右移,让整数部分变成1。结果阶码算错,整道题全崩。后来我在笔记上写了加粗提醒:尾数的隐含整数位永远是1,非规格化数只在阶码全0时才出现。

还有一个常考点是特殊值:阶码全0且尾数全0表示正负零,阶码全1且尾数全0表示无穷大,阶码全1且尾数非0表示NaN。这几个判断要变成条件反射。

2.4 从串行进位到组间并行进位:进位链到底在优化什么

这是我个人认为计组里最"数学味"的一段,也是很多人直接跳过的一段。但它是热词里反复出现的内容,说明考试确实爱考。

先说什么叫串行进位。一个n位加法器,每一位的全加器都需要两样东西:本位数据和来自低位的进位。如果第i位要等第i−1位的进位算完才能算,第i−1位又要等第i−2位,那整条链就是一路串下去。这就叫行波进位或者串行进位。

它的延迟和位数成正比。16位加法器,每一位进位大概要经过两级门(一个与门加一个或门),那总共就是32级门延迟。位数越多,越慢。而且关键路径很长,时钟频率上不去。

于是有了先行进位(也叫超前进位)的思路。全加器的进位可以写成:

C(i+1) = Gi + Pi·Ci

其中Gi = Ai·Bi(本位进位生成),Pi = Ai⊕Bi(本位进位传递)。把上式层层展开,Ci就能用A、B各位直接表示出来,不用等前一级。所有进位理论上可以同时产生,延迟从线性降到了接近常数。

但这里有工程上的现实问题:位数一多,展开式会变得极其复杂,每一项的扇入(同时输入的信号数)会爆炸,电路实现不了。所以实际方案是"分组"。

方案做法延迟特点
串行进位进位逐位传递随位数线性增长
组内并行、组间串行4位一组,组内先行进位,组之间进位依次传递组内大幅降低,组间仍线性
组内并行、组间并行再定义组进位生成函数和组传递函数,做二级先行进位接近常数,代价是电路复杂

组间并行进位的思路是:把每一组的进位也抽象成"生成"和"传递"两个函数。第i组的进位输出,要么由这一组内部自己产生(组生成),要么由这一组的输入进位传过去(组传递)。有了这两个函数,组与组之间的进位也能用先行进位电路统一处理,形成两级先行进位结构。

我在笔记上给这一节贴了个标签叫"分而治之",因为这个思想和后面的Cache、流水线、存储层次是同一个套路:单层结构性能不够,就分层,层内用快的方式,层间用统一的接口衔接。把这个思想串起来,整本书的很多设计就都能理解而不是硬背了。

3. 存储系统:会算才是真的会,别停在"背映射方式"

3.1 主存容量扩展的计算题

主存的位扩展和字扩展,是每年必考的基础题。位扩展是数据线不够,把多片芯片并联,地址线共用;字扩展是容量不够,用片选信号来选不同的芯片,地址线高位接译码器。

这类题的通用流程,我在笔记里固定成了四步:

  1. 先看总容量要求和单片容量,算出需要多少片。
  2. 判断要位扩展还是字扩展,还是两者结合。
  3. 位扩展就并联,数据线拼起来,地址线全部共接。
  4. 字扩展要确定地址位数,把高位地址送译码器产生片选信号。

这里有一个经典的坑:片选信号的地址范围怎么定。很多人算对了芯片数量,但地址范围写反了。我的做法是把整个地址空间画成一条从0到最大值的数据线,按芯片容量一段一段切,每一段对应一个片选。画一条线比纯粹心算靠谱得多。

另外要注意DRAM和SRAM的区别。DRAM要刷新,刷新有集中刷新、分散刷新、异步刷新三种方式,考试会问"刷新开销"或者"刷新周期数"。集中刷新在刷新周期内有一段"死区"不能访存;分散刷新把刷新分散到每个存取周期;异步刷新把刷新周期除以行数,均匀插入。这三个我笔记本上是画了时间轴来对比的,光看文字很难记住。

3.2 Cache三种映射的地址划分

Cache的映射方式,是计组最典型的"看起来简单、算起来繁"的考点。直接映射、全相联、组相联,每种的主存地址划分都不一样。

我整理了一张对照表,这张表基本上覆盖了所有映射题的入口:

映射方式地址划分标记位数判断块位置
直接映射标记 + 行号 + 块内地址主存地址位 − log2(行数) − log2(块大小)块号 mod 行数
全相联标记 + 块内地址主存地址位 − log2(块大小)任意空行
N路组相联标记 + 组号 + 块内地址主存地址位 − log2(组数) − log2(块大小)块号 mod 组数

这张表的关键是理解"为什么组相联的标记位数介于两者之间"。组相联是直接映射和全相联的折中:组号位数比行号少(因为组数少于行数),剩下的位就都给了标记,所以标记位数比直接映射多,比全相联少。

做题的时候我固定先做一件事:算出块大小对应的块内地址位数。因为不管是哪种映射,块内地址位数都是log2(块大小),而且很多题目会故意把块大小写成字节数让你先转换。这一步错了,后面全错。

3.3 写策略和替换算法的组合题

Cache写策略有两种组合最常见:

  • 写直达加写不分配:写命中时同时写Cache和主存,写不命中时只写主存,不把块调入Cache。
  • 写回加写分配:写命中时只写Cache并设置脏位,写不命中时先把块调入Cache再写。

考试喜欢考"给定访问序列,问命中率"。这时候你要注意写操作的访存次数统计,因为写不分配和写分配会影响后续访问是否命中。

替换算法里LRU是高频考点。LRU在组相联里用得多,全相联理论上也能用。手算LRU的时候,我的技巧是给每个块记一个"最后访问时间戳",每次访问后更新,替换时选时间戳最小的。这比画栈或者箭头可靠,不容易在复杂的访问序列里搞混。

我见过一道真题,访问序列有十几个地址,用4路组相联,问命中率。如果用手画,很容易在中途记错某个块的位置。用时间戳法,每个块旁边写个数字,稳定得多。这是我自己踩过坑之后总结的方法。

3.4 虚拟存储和TLB的联动

虚拟存储这块,核心是一次访存的完整地址转换过程。要记住的是一个层次链:

虚拟地址 → TLB(快表)→ 页表 → 物理地址 → Cache → 主存

考试喜欢问"一次访存要访问几次主存"或者"TLB命中与不命中对性能的影响"。这里的易错点是:TLB命中不等于Cache命中,TLB只是加速了虚拟地址到物理地址的转换,转换完之后还要正常走Cache查找流程。

还有几个参数要区分清楚:

  • TLB的命中率影响的是地址转换的访存次数。
  • Cache的命中率影响的是数据访存次数。
  • 页表可能有多级,多级页表会带来额外的访存。

我笔记本上专门画了一条时间线,标注每一步可能发生什么,命中走哪条路,不命中走哪条路。这种题目光靠读文字很容易漏掉分支。

4. 指令系统与流水线:三类相关的本质区别是什么

4.1 寻址方式的访存次数和有效地址计算

指令系统这一章,寻址方式是高频考点。要掌握的是每种寻址方式的有效地址(EA)怎么算、需要几次访存。

寻址方式有效地址访存次数(取操作数)
立即寻址指令中直接给出0
直接寻址指令中的地址1
间接寻址指令中地址指向的单元内容2
寄存器寻址寄存器0
寄存器间接寻址寄存器内容1
变址/基址变址/基址寄存器内容加偏移1

这张表看起来简单,但组合起来就绕。真正拉分的是"相对寻址",它的有效地址是PC当前值加上偏移量再转移到目标。而PC的当前值到底是"本条指令地址"还是"下一条指令地址",这个细节经常被考。我在笔记里写了一句加粗的话:PC在取指完成后已经指向下一条指令,所以相对寻址的EA是下条指令地址加偏移。

4.2 结构相关、数据相关、控制相关到底谁跟谁打架

流水线的三类相关,是计组公认的难点。但我觉得难是因为很多人没有把"相关"理解成"资源或数据的依赖冲突",只是背了三个名字。

  • 结构相关:也叫资源相关。两条指令在不同的流水段争用同一个硬件部件。最典型的是取指阶段要访存,执行阶段的访存指令也要访存,同一个存储器不够用。
  • 数据相关:后面的指令需要前面指令产生的数据,而前面指令还没写回。分为写后读、读后写、写后写。流水线里最常见的是写后读。
  • 控制相关:转移指令改变了PC,而流水线里已经预取了后面的指令,导致预取的指令作废。

理解这三类相关,关键是想清楚"冲突发生的位置对不上":结构相关是硬件资源的冲突,数据相关是数据依赖的时序冲突,控制相关是控制流的冲突。

4.3 数据相关的转发和阻塞:什么时候能转发,什么时候只能等

数据相关是流水线题的重点。解决手段里,转发(也叫旁路)和阻塞是最常考的。

转发的思想是:既然前面指令的结果已经在某个流水段寄存器里算出来了,那后面的指令需要这个数据时,直接把它从寄存器引过来,不用等写回。转发能解决大部分写后读相关。

但不是所有相关都能靠转发解决。如果前面的指令是访存指令,数据要等到访存阶段结束才出来,而后面指令需要用这个数据的时候已经过了需要的流水段,那只能阻塞,也叫插入气泡。

我遇到的一道典型题是:连续几条指令依赖同一条加载指令的结果,问流水线的执行周期数。这种题就需要判断第几条能转发、第几条必须阻塞。我的做法是画一张流水线时空图,每个指令横向铺开,每个阶段占一格,然后用箭头把需要的数据标出来。什么时候箭头能跨段连,什么时候必须空一格,一目了然。

4.4 流水线性能指标:吞吐率、加速比、效率

这三个指标的计算题,公式本身不难,但容易在"流水线周期"和"指令条数"上出错。

  • 吞吐率TP:单位时间完成的指令数,等于指令数除以执行总时间。
  • 加速比S:不使用流水线的时间除以使用流水线的时间。
  • 效率E:有效时间和总时间的比值,反映流水线设备的利用率。

流水线的建立时间和排空时间不要漏。m段流水线,执行n条指令,总时间是(m + n − 1) × 流水线周期(理想情况下),这是最常考的公式。

我踩过的坑是没考虑流水线冲突。如果题目说"存在数据相关导致停顿",那公式里的流水线周期就要加上停顿周期。很多题的陷阱就在这,理想公式套上去,答案差一截。我的应对方式是在笔记上把公式分成"理想情况"和"有冲突情况"两栏来记。

5. CPU和控制器:微程序这条线怎么理才不乱

5.1 微指令的编码方式

微程序控制是计组里最抽象的一章,因为它涉及"用微指令去实现机器指令"这个二级结构。微指令的编码方式有几种:

  • 直接编码:每一位对应一个微命令,速度快但微指令字长。
  • 字段直接编码:把互斥的微命令分到同一字段,字段内编码,减少字长。
  • 字段间接编码:字段内编码还要再查一次表,进一步压缩,但速度更慢。

这里的考点是"一条微指令能同时发出多少个微命令"。直接编码是所有位都能同时有效;字段直接编码是每个字段只能选一个微命令,不同字段之间可以并行。所以字段数决定了能并行的微命令数量。

我在笔记里用一个很小的例子把它具象化了:假设有4个微命令要控制,直接编码需要4位;如果分成两个字段,每个字段2位编3种状态,微指令只需要4位但每个字段只能选一个。账要这么算才清楚。

5.2 硬布线和微程序的取舍逻辑

硬布线控制器是纯组合逻辑,速度快但设计复杂、不易修改。微程序控制器是用存储在控制存储器里的微指令来实现,设计规整、易扩展,但速度慢一些。这不就是"专用电路"和"通用程序"的经典取舍吗?

把这个对比记住之后,选择题问"哪种控制器适合RISC"就有依据了——RISC指令规整,用硬布线更合适;CISC指令复杂,用微程序更合适。

5.3 数据通路题的通用解法

数据通路题通常是给一张图,问某条指令执行需要哪些控制信号、经过哪些部件。这类题的通用解法是"按指令周期分段拆":

  1. 拆成取指、译码、执行、访存、写回几个阶段。
  2. 每个阶段列出用到哪些部件。
  3. 每个部件需要哪些控制信号。

我在笔记里把常考指令(加载、存储、加法、跳转)各写了一遍数据通路流程,每条指令单独一页。写完之后你会发现,取指阶段几乎都是一样的,只有执行和访存阶段不同。抓住这个共性,这道题就砍掉一半工作量。

6. 总线与I/O:最容易"看着会,做着错"的两章

6.1 总线定时:同步和异步的差别

同步定时由统一的时钟信号来控制,总线上的所有操作都在时钟沿对齐。优点是简单、速度快;缺点是必须按最慢的设备来设定时钟周期,快的设备被拖慢。

异步定时是"应答式"的,靠请求和回答信号握手。按握手方式分:

  • 不互锁:请求方发出请求后不等回答,过一段时间自己撤销。
  • 半互锁:请求方等回答后才撤销请求,但回答方不等对方撤销请求就可以撤销回答。
  • 全互锁:请求和回答都等对方撤销了才撤销自己。

这几个概念容易混。我的记忆方法是看"谁等谁":全互锁是两边都等,半互锁只有一边等,不互锁谁都不等。画成时序图,信号长度的差别一眼能看出来。

6.2 中断处理的完整流程

中断是I/O这章的绝对重点。中断响应必须满足的条件是:有中断请求、CPU允许中断、一条指令执行结束。注意第三条,中断是在指令边界响应的,不是随时打断。

中断处理流程我背了很长时间才理顺:

  1. 关中断(防止中断处理过程被打断)。
  2. 保存断点(把PC压栈或存到指定单元)。
  3. 引出中断服务程序(根据中断向量找入口地址)。
  4. 保存现场(把通用寄存器的内容保存)。
  5. 执行中断服务。
  6. 恢复现场。
  7. 开中断(允许响应更高级中断)。
  8. 中断返回。

这里有个容易错的点:保存断点和保存现场是两回事。保存断点保存的是PC,是硬件自动完成的(中断隐指令);保存现场保存的是通用寄存器,是软件(中断服务程序)完成的。考试经常在"哪些由硬件完成"上设陷阱。

6.3 DMA和中断怎么配合

DMA方式下,数据传送由DMA控制器控制,不需要CPU干预。它和中断的区别是:

  • 中断是程序切换,适用于数据量小、速度要求不高的场合。
  • DMA是硬件传送,适用于数据量大、速度要求高的场合。

DMA和CPU争用总线,常见的有三种方式:停止CPU访存、周期挪用、交替访问。周期挪用是DMA在CPU不需要访存的时候"偷"一个周期,效率较高,也最常考。

DMA传送结束后通常会向CPU发一个中断,让CPU处理善后。这个细节很多人会漏,我笔记本上专门标了一句:"DMA结束仍然要用中断通知CPU。"这就是两种机制的配合关系。

7. 我的复习节奏和错题本用法

7.1 时间怎么分配

我的做法是把计组分成两条线:一条是理解和推导(数据表示、运算、流水线),一条是记忆和计算(存储、I/O、总线)。前者要早开始、多动手写;后者可以稍晚、但要反复看。

强化阶段我给的节奏是:每章第一遍精读加做笔记,用四到五天;第二遍只做真题加整理错题,用两到三天;冲刺阶段每章只过错题和相关公式。

7.2 错题本到底记什么

我前面提过,错题本不记题目,只记归因。具体我记三样东西:

  • 这道题我错在哪个具体动作上(比如"标记位数算错"而不是"Cache没学好")。
  • 正确的动作应该是什么。
  • 这道题属于哪个知识点的哪一类变体。

这样记的好处是,复习的时候你能看到自己的错误模式,而不是一堆孤立的题目。我最后发现自己的高频错误就集中在三四个点上:进位序号、地址位数分配、流水线停顿判断。针对性补了之后,正确率提升很明显。

7.3 冲刺阶段的两个小技巧

第一个技巧是"白纸默写"。拿出一张白纸,不看书,默写某一章的骨架:从输入到输出经过哪些部件、每一步的关键公式、容易错的地方。写不出来就说明这块没掌握。

第二个技巧是"公式卡"。把全书所有需要记的公式集中写在一张纸上,比如标记位数公式、流水线时间公式、吞吐率公式,每天早上一遍。考前几天这种卡片比翻书效率高得多。

我自己在最后两周基本就是靠这两招维持状态的。计组这门课的特点是知识点一旦串起来,记忆负担会大幅下降,因为它不是零散的知识,而是一套有内在逻辑的系统。你把这些逻辑理清楚,比多刷一百道题都管用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询