ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

计算机组成与体系结构期末复习指南:核心考点与避坑技巧

计算机组成与体系结构期末复习指南:核心考点与避坑技巧

简介:这份《西安电子科技大学-计算机组成与体系结构-期末总结》PDF,面向正在备考该课程的本科生与考研复习者,帮助梳理课程核心考点、建立章节知识框架。内容覆盖计算机系统分类、冯·诺依曼结构、软硬件逻辑等价性、体系结构定义、Amdahl定律及机器字长、MIPS等主要技术指标,并延伸至定点与浮点表示、原码补码反码移码等数据表示重点,适合期末冲刺与知识点查漏补缺。资源包共1个PDF文件,约6.2MB,单文件结构便于通读与打印。目前已有2165人学习下载,说明其内容经过一定规模的使用检验。读者可借助这份总结快速回顾各章要点,对照课堂笔记补齐遗漏,尤其适合需要集中突破概念辨析与计算类题目的同学。

1. 从一份期末总结说起:计算机组成与体系结构到底该怎么复习

很多人复习计算机组成与体系结构,第一反应是翻教材、抄笔记,结果抄完一遍还是不知道哪些是考点、哪些是理解性内容。这份期末总结 PDF 的价值在于,它把第一章到第四章的核心概念按知识块重新组织了一遍,从冯·诺依曼结构、数的机器码表示,到存储系统、指令格式,基本覆盖了期末考试的绝大多数出题方向。它适合正在准备期末的本科生,也适合考研复习时拿来快速过一遍知识框架的从业者。我拿到这份材料后,按章节拆了一遍,发现它的组织逻辑是“概念定义 → 分类对比 → 计算规则 → 典型例题”,这个顺序恰好和大多数高校的出题习惯吻合。下面按四个知识模块展开,把每个模块里最容易翻车的地方标出来。

2. 数据表示与运算:从原码到浮点流水线的计算规则

2.1 四种机器码的转换与取值范围

数的机器码表示是第二章的起点,也是后面补码加减法、溢出判断的基础。这份总结里把原码、补码、反码、移码的转换规则和取值范围列得很清楚,但光看结论容易记混,我建议按下面的逻辑重新推一遍。

原码的符号位独立于数值位,0 正 1 负,所以有 +0 和 -0 之分。8 位字长下范围是 -127 到 +127。补码的核心规则是:正数补码与原码相同;负数补码从原码右数第一个 1 开始,左边全部取反,右边不变。补码没有正负零之分,8 位范围是 -128 到 +127。反码是负数原码除符号位外各位取反,同样有正负零。移码最特殊,它和补码的符号位互为相反数,其余各位相同,没有正负零。

这里有一个容易翻车的点:补码转原码时,很多人直接对补码再求一次补就完事,但如果补码是 1000 0000(即 -128),求补后得到的结果会溢出。正确做法是先判断是否为最小负数,如果是则单独处理。

def twos_complement_to_decimal(binary_str): """ 将二进制补码字符串转换为十进制整数 binary_str: 8位二进制字符串,如 '10000000' """ if binary_str[0] == '0': # 正数,直接转十进制 return int(binary_str, 2) else: # 负数,先减1再取反,最后加负号 # 注意:-128 是特殊情况,减1取反后得到 10000000,即 128 inverted = ''.join('1' if b == '0' else '0' for b in binary_str) magnitude = int(inverted, 2) + 1 return -magnitude # 测试 print(twos_complement_to_decimal('10000000')) # -128 print(twos_complement_to_decimal('11111111')) # -1 print(twos_complement_to_decimal('01111111')) # 127

这段代码的逻辑是:正数补码直接按二进制转十进制;负数补码先按位取反再加 1 得到绝对值,最后加负号。参数就是一个 8 位二进制字符串,返回对应的十进制整数。注意 -128 的情况,取反后得到 01111111,加 1 变成 10000000,即 128,加负号后正好是 -128,不会溢出。

2.2 补码加减法与溢出检测的两种方法

补码加减法的公式很简洁:[x+y]补 = [x]补 + [y]补 (mod 2),[x-y]补 = [x]补 + [-y]补 (mod 2)。关键在于溢出判断,这份总结给了两种方法。

方法一是双符号位(变形补码)。用 Sf1 和 Sf2 表示两位符号位,如果 Sf1 ≠ Sf2,则发生溢出。Sf1Sf2 = 01 表示正溢,10 表示负溢。方法二是单符号位,看符号位产生的进位 Cf 和最高有效位产生的进位 C0,如果 Cf ⊕ C0 = 1,则溢出。

我一般会让学生用双符号位法手算一遍,再用单符号位法验证,两种方法结果一致才放心。实际考试里,双符号位法更直观,不容易算错。

2.3 浮点加减运算的五个步骤与规格化处理

浮点加减运算是第二章里步骤最多的一类题,总结里列了五个步骤:零操作数检查、对阶、尾数加减、规格化、舍入与溢出判断。每一步都有坑。

对阶的原则是小阶向大阶对齐,尾数右移,阶码增加。这里容易搞反方向,记住“小向大看齐”就不会错。规格化分两种情况:结果是 01.ф…ф 或 10.ф…ф 时,需要右规,尾数右移一位,阶码加 1;结果是 00.0…01… 或 11.1…10… 时,需要左规,尾数左移,阶码减 1,直到尾数最高位与符号位不同。

舍入处理常用“0 舍 1 入”,类似四舍五入。溢出判断看阶码:阶码上溢表示结果超出最大正指数,一般按 +∞ 或 -∞ 处理;阶码下溢表示结果小于最小负指数,按 0 处理。

提示:浮点运算题里,对阶和规格化是最容易丢分的两步。建议每做一道题,先把阶码和尾数分别列出来,对阶后再动尾数,不要跳步。

2.4 流水线加速比的计算与“堵塞”问题

浮点运算流水线是第二章的收尾内容,也是考试里常出计算题的地方。一个 k 级流水线处理 n 个任务需要的时钟周期数是 k + (n-1),所需时间 Tk = [k + (n-1)] × τ,其中 τ 是时钟周期。顺序完成的时间 TL = n × k × τ。加速比 S = TL / Tk。

这里有一个常见误解:流水线的加速比不是固定的 k,而是随着任务数 n 增大逐渐趋近于 k。当 n 远大于 k 时,S ≈ k。另外,流水线各段时间应该尽量相等,否则会出现“堵塞”和“断流”,实际加速比会低于理论值。

3. 存储系统:SRAM、DRAM、Cache 的选型与计算

3.1 SRAM 与 DRAM 的核心区别

存储系统是第三章的主体,也是整份总结里篇幅最大的一块。SRAM 和 DRAM 的区别是必考内容,总结里从存储原理、速度、容量、刷新需求几个维度做了对比。

SRAM 的存储元是一个触发器,具有两个稳定状态,不需要刷新,存取速度快,但集成度低、功耗大、成本高,适合做 Cache。DRAM 的存储元由一个 MOS 晶体管和电容器组成,读出是破坏性的,必须恢复存储位元中原存的 1,因此需要刷新。DRAM 集成度高、功耗低、成本低,适合做主存。

刷新方式有两种:集中式刷新和分散式刷新。集中式刷新把所有行集中在每个刷新周期的一段时间内刷新,控制逻辑简单,但有 1.024% 的时间不允许访存,CPU 需要等待。分散式刷新把每一行的刷新插入到正常的读写周期中,提高了效率,但控制逻辑复杂。

3.2 存储器容量扩展的两种方式

存储容量扩充是第三章里计算量最大的题型,总结里给了两种方式:字长位数扩充和字存储容量扩展。

字长位数扩充的例子是 1M×4 位扩展到 1M×8 位。地址线和控制线公用,数据线单独分开连接。所需芯片数量 = 设计要求的存储器容量 / 选择芯片的存储器容量。

字存储容量扩展的例子是 1M×8 位扩展到 2M×8 位。地址总线和数据总线公用,控制总线中 R/W 公用,但使能端 EN 不能公用,它由地址总线的高位段译码来决定片选信号。

# 计算所需芯片数量的通用公式 # 设计要求的存储器容量 = 目标字数 × 目标字长 # 选择芯片的存储器容量 = 芯片字数 × 芯片字长 # 所需芯片数量 = 设计要求的存储器容量 / 选择芯片的存储器容量 # 示例:用 1M×4 位的芯片组成 1M×8 位的存储器 # 目标容量 = 1M × 8 = 8M bit # 芯片容量 = 1M × 4 = 4M bit # 所需芯片数 = 8M / 4M = 2 片

这个公式看起来简单,但实际做题时容易把字和位搞混。我一般会先把目标容量和芯片容量都换算成 bit,再相除,这样不容易出错。

3.3 Cache 的三种地址映射方式与替换策略

Cache 是第三章的重点,也是考试里出题频率最高的知识点之一。总结里把全相联、直接映射、组相联三种映射方式的映射方法、地址划分、优缺点都列了出来。

全相联映射是多对多,地址分为块号和字两部分,内存块写入 Cache 时同时写入块号标记。优点是冲突概率小,Cache 利用率高;缺点是比较器难实现,需要访问速度很快、代价高的相联存储器,适用于小容量 Cache。

直接映射是一对多,映射公式是 i = j mod m,其中 i 是 Cache 行号,j 是主存块号,m 是 Cache 总行数。地址分为 tag、行号、字三部分。优点是硬件简单、成本低;缺点是冲突概率高,适用于较大容量的 Cache。

组相联映射是前两者的结合,Cache 分组,组间采用直接映射,组内采用全相联。组号 q = j mod u,其中 u 是 Cache 的组数。v = 1 时退化为直接映射,u = 1 时退化为全相联。

替换策略有三种:LFU(最不经常使用)、LRU(近期最少使用)、随机替换。LFU 给每个被访问的行计数器加 1,换值小的行,但不能反映近期 Cache 的访问情况。LRU 给被访问的行计数器置 0,其他计数器加 1,换值大的行,符合 Cache 的工作原理。随机替换就是从特定行位置中随机选一行换出。

写操作策略也有三种:写回法、全写法、写一次法。写回法是换出时判断修改位,决定写回还是舍掉。全写法是写命中时 Cache 与内存一起写。写一次法与写回法一致,但第一次 Cache 命中时采用全写法。

3.4 Cache 命中率与平均访问时间的计算

Cache 性能计算是必考题型。命中率 h = Nc / (Nc + Nm),其中 Nc 是 Cache 完成存取的总次数,Nm 是主存完成存取的总次数。平均访问时间 ta = h × tc + (1-h) × tm,其中 tc 是命中时的 Cache 访问时间,tm 是未命中时的主存访问时间。

访问效率 e = tc / ta = 1 / (r + (1-r) × h),其中 r = tm / tc 表示主存慢于 Cache 的倍率。这个公式在计算题里经常用到,建议记住推导过程,不要死记结论。

注意:Cache 命中率计算题里,最容易出错的是把“访问次数”和“访问时间”搞混。Nc 和 Nm 是次数,tc 和 tm 是时间,代入公式前先确认单位一致。

4. 指令系统与控制器:从指令格式到执行流程

4.1 指令格式的三种地址码类型

指令系统是第四章的核心,总结里从指令格式、操作码、地址码几个维度展开。指令字由操作码字段和地址码字段组成,操作码表示指令应进行什么性质的操作,地址码指定参与操作的操作数地址。

地址码有三种类型:三地址指令、二地址指令、一地址指令、零地址指令。三地址指令格式是操作码 θ、第一操作数 A1、第二操作数 A2、结果 A3。二地址指令是操作码 θ、第一操作数 A1、第二操作数 A2。从操作数的物理地址归结为三种类型:SS(存储器-存储器)、RS(寄存器-存储器)、RR(寄存器-寄存器)。RR 类型最快,SS 类型最慢。

指令字长度等于机器字长的称为单字长指令,等于半个机器字长的称为半字长指令,等于两个机器字长的称为双字长指令。

4.2 控制器的工作流程:取指周期与执行周期

控制器是计算机的指挥中心,它的基本任务是按照一定顺序一条接一条取指令、指令译码、执行指令。控制器按照时序工作,通常分为取指周期和执行周期。

取指周期:从内存读出的信息流是指令流,它流向控制器。执行周期:从内存读出的信息流是数据流,它由内存流向运算器。

这里有一个经典考题:CPU 如何识别从主存取出来的二进制代码是指令还是数据?答案是:从时间来说,取指令事件发生在取指周期,取数据事件发生在执行周期;从空间来说,取出的代码是指令,一定送往指令寄存器(控制器),取出的代码是数据,一定送往数据寄存器(运算器)。

4.3 CISC 与 RISC 的选型差异

指令系统的发展分为两个方向:复杂指令系统计算机(CISC)和精简指令系统计算机(RISC)。CISC 的指令数量多、格式复杂、寻址方式多,典型代表是 Pentium 指令格式,指令长度可变,最短 1 个字节,最长 12 个字节。RISC 的指令数量少、格式规整、寻址方式少,适合流水线实现。

指令系统的性能要求包括完备性、有效性、规整性、兼容性。完备性是指用汇编语言编写各种程序时,指令系统直接提供的指令足够使用,而不必用软件来实现。有效性是指利用该指令系统所编写的程序能够高效率地运行。规整性包括指令系统的对称性、匀齐性、指令格式和数据格式的一致性。兼容性是指系列机各机种之间具有相同的基本结构和共同的基本指令集。

5. 避坑与排查:复习这份总结时最容易翻车的五个地方

5.1 补码转原码时忽略最小负数

现象:把 1000 0000 当作补码转原码时,直接取反加一得到 1000 0000,误以为结果是 -0 或溢出。

原因:补码的 -128 没有对应的原码表示,取反加一后会回到自身,形成循环。

解决:先判断补码是否为 1000 0000,如果是则直接输出 -128,不要走取反加一的流程。

5.2 浮点对阶时搞反方向

现象:对阶时把大阶向小阶对齐,导致尾数左移、阶码减小,最终结果完全错误。

原因:记混了“小阶向大阶看齐”的原则,或者把阶码比较和尾数移位搞反了。

解决:对阶前先把两个数的阶码写出来,明确哪个大哪个小,小阶的尾数右移,每右移一位阶码加 1,直到两个阶码相等。

5.3 Cache 地址映射时混淆块号和行号

现象:直接映射计算时,把主存块号直接当作 Cache 行号,忽略了取模运算。

原因:没有理解 i = j mod m 的含义,m 是 Cache 总行数,不是主存块数。

解决:做题时先把 Cache 行数 m 算出来,再用主存块号 j 对 m 取模,得到 Cache 行号 i。地址划分时,tag 是主存块号的高位部分,行号是低位部分。

5.4 存储器扩展时字和位混淆

现象:计算所需芯片数量时,把 1M×4 位当成 1M×4 字节,导致结果差 8 倍。

原因:没有区分“字”和“位”的单位,1 字节等于 8 位,1M×4 位是 4M bit,不是 4M 字节。

解决:统一换算成 bit 再相除。目标容量 = 目标字数 × 目标字长,芯片容量 = 芯片字数 × 芯片字长,两者单位一致后再相除。

5.5 流水线加速比计算时忽略装入和排空时间

现象:直接用 k 作为加速比,忽略了流水线需要装入时间和排空时间。

原因:没有理解 k 级流水线处理 n 个任务的实际周期数是 k + (n-1),而不是 n × k。

解决:先算实际周期数 k + (n-1),再算顺序完成周期数 n × k,两者相除得到加速比。当 n 远大于 k 时,加速比才趋近于 k。

6. 把这份总结用出最大价值:我的复习节奏与验证方法

这份总结 PDF 的信息密度很高,如果只是从头翻到尾,很容易陷入“看了后面忘了前面”的循环。我自己的做法是分三轮走。

第一轮用 30 分钟快速过一遍目录和每章的小标题,把知识框架画出来。第一章是计算机系统概述,第二章是数据表示与运算,第三章是存储系统,第四章是指令系统。四章之间的逻辑是:先讲计算机整体结构,再讲数据怎么表示和运算,然后讲数据存在哪里,最后讲指令怎么控制数据流动。

第二轮按章节精读,每读完一章就做三件事:把公式抄一遍、把例题手算一遍、把易错点标出来。比如第二章的补码加减法和浮点运算,我会用 Python 写一个小脚本验证手算结果。下面这个脚本可以验证补码加法的溢出判断。

def twos_complement_add(a, b, bits=8): """ 模拟补码加法并判断溢出 a, b: 十进制整数 bits: 字长,默认8位 返回: (结果, 是否溢出, 溢出类型) """ mask = (1 << bits) - 1 # 转为补码二进制 a_bin = a & mask b_bin = b & mask # 相加 result = (a_bin + b_bin) & mask # 判断溢出:双符号位法 # 取符号位 sign_a = (a_bin >> (bits - 1)) & 1 sign_b = (b_bin >> (bits - 1)) & 1 sign_r = (result >> (bits - 1)) & 1 overflow = (sign_a == sign_b) and (sign_r != sign_a) # 转回十进制(补码解释) if result >= (1 << (bits - 1)): result = result - (1 << bits) return result, overflow # 测试:127 + 1 应该溢出 print(twos_complement_add(127, 1)) # (-128, True) # 测试:-128 + (-1) 应该溢出 print(twos_complement_add(-128, -1)) # (127, True) # 测试:100 + 50 不溢出 print(twos_complement_add(100, 50)) # (150, False)

这段代码的逻辑是:先把两个十进制数转成补码二进制,相加后取低 bits 位,然后比较符号位判断溢出。参数 bits 可以改成 16 或 32,验证不同字长下的溢出情况。注意 Python 的整数没有溢出概念,所以需要用掩码模拟。

第三轮是考前一周,只看自己标注的易错点和公式,不再从头翻。这时候这份总结的价值就体现出来了——它的结构足够清晰,可以直接当速查表用。

提示:如果你手头有历年真题,建议把真题里的计算题按章节分类,对照这份总结的公式和例题逐一验证。计算题的分值通常占 40% 以上,手算一遍比看十遍都管用。

从那以后我每次复习这类偏计算的课程,都会先找一份结构清晰的总结,然后按“框架 → 公式 → 例题 → 易错点”四步走,不再盲目抄笔记。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进