ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

计算机组成原理指令系统:扩展操作码与寻址方式考研解析

计算机组成原理指令系统:扩展操作码与寻址方式考研解析 1. 指令系统整体框架与考研命题思路拆解1.1 为什么指令系统是整门课的承上启下节点很多人一翻开组原课本看到指令系统这一章就觉得它虚——没有电路图没有时序波形看起来像是一堆格式约定和编码规则的堆砌好像背一背就过去了。我当年第一次考研也是这么想的结果在真题里被扩展操作码的计算和相对寻址的目标地址狠狠教了一次做人。后来复盘才发现指令系统在整个计算机组成原理的知识链条里占据的恰恰是一个极其关键的承上启下位置往上它承接了数据的表示与运算操作数从哪来、怎么编码往下它直接决定控制器怎么取指、译码、执行也决定流水线会不会因为寻址方式的复杂度而产生停顿。说得直白一点指令系统就是软硬件之间签的那份合同。软件开发者写出来的汇编语句最终要翻译成一条条机器指令硬件设计者则要按照这份合同的格式去造译码器、造地址生成单元。这份合同里规定了三件事指令长什么样指令格式、操作数在哪里寻址方式、能干什么活指令类型。考研命题人特别喜欢在这一章做文章因为这三个点每一个都能出计算题而且计算量不大、逻辑链清晰非常适合用来区分背了和懂了的考生。从历年命题的分布来看指令系统很少单独出大题但它几乎年年以小题、填空题、选择题的形式出现在试卷里偶尔在综合题的第一小问里作为引子。比如问你某台机器采用变址寻址时有效地址怎么算或者给你一段扩展操作码的编码条件让你算还能容纳多少条指令。这类题的特点是会的人三十秒出答案不会的人能卡十分钟。差距就是这么拉开的。我建议复习这一章时不要把它当成孤立的编码记忆而要把它挂到两条主线上一条是指令周期的视角看一条指令从取指到执行到底访问了几次内存另一条是控制器设计的视角看指令格式怎么影响译码的复杂度。把这两条线理顺了这一章的内容就活了后面的流水线、中断、I/O 也能顺势接上。1.2 命题分布与分值权重的真实感受先给一个我整理的命题热度感受表这是根据我刷了近十五年真题后的体感总结具体年份的分值会浮动但重难点的分布规律是稳定的。知识板块命题形式出现频率难度感受扩展操作码计算选择 / 填空高频中等偏难寻址方式与有效地址选择 / 计算高频中等指令格式与字长选择 / 综合小问中频中等RISC 与 CISC 对比选择 / 简答中频偏易指令流水相关分析综合题高频难这张表里RISC 与 CISC 的对比是性价比最高的——概念清楚就能拿到分但很多人恰恰因为觉得它简单而没当回事结果在选择题里被哪一项不是 RISC 的特点这种题绕进去。指令流水虽然在教材上属于后面 CPU 章节但它和指令系统是连着的尤其是结构相关、数据相关、控制相关这三个概念源头都在指令的取指与执行方式上所以我在这一章里会提前把它拎出来讲清楚。再说一嘴参考资料的取舍。市面上主流的那本王道笔记在指令系统这一章的优点是知识点全、例题多缺点是有些推导写得太跳尤其是扩展操作码那几道题它直接给结论中间的为什么保留这个编码没讲透透导致很多人背了结论换个题型就懵。我个人的做法是第一遍跟着笔记把框架搭起来第二遍一定要自己动手把每一类计算题的推导过程写一遍写不出来的地方就是你的知识漏洞。这个笨办法看着慢但它能保证你在考场上遇到变形题时不会慌。2. 指令格式与扩展操作码的完整计算套路2.1 指令格式的底层逻辑操作码和地址码的博弈一条指令的结构可以简单拆成两块操作码OP和地址码A。操作码告诉你干什么地址码告诉你对谁干。问题在于指令字长通常是固定的比如 16 位、32 位操作码多了地址码就得少地址码多了能表示的操作种类就少。这是一场零和博弈而指令格式设计就是在解这道博弈题。固定的指令字长带来几个直接后果。第一译码电路好设计——控制器拿到固定长度的指令取指阶段就知道要读多少字节不用像变长指令那样先读一部分再决定读多少。第二程序的可预测性好对流水线友好。第三代价是空间利用率可能不高——一条指令如果实际只需要两个地址那个多余的地址字段就浪费了。现实中很多处理器会采用折中方案比如定长为主、个别指令变长。考研里最常见的指令格式题是给你指令字长和地址码长度让你算操作码最多能表示多少种操作。比如指令字长 16 位每个地址码 4 位采用三地址格式那么操作码占 16 - 4×3 4 位最多表示 2^4 16 种操作。这是最基础的一层属于送分题。难就难在扩展操作码。它的核心思想是如果某些指令不需要那么多地址码就把省下来的位数让给操作码从而在总位数不变的前提下表示更多的指令种类。这个思路其实和哈夫曼编码有点像——用得越频繁的操作数地址越少把编码空间省给用不到那么多地址的指令。2.2 扩展操作码的三种经典命题模型我先把扩展操作码的规则讲透再说题目。规则只有一条但它是命门短操作码的编码必须和长操作码的前缀区分开短码不能是任何长码的前缀。换句话说如果你用某个编码作为扩展标志那么这个编码本身就不能再作为一条独立指令的操作码了它必须留给下一个地址格式去扩展。举个最有代表性的例子。设指令字长 16 位地址码 4 位三地址指令要 15 条二地址要 15 条一地址要 15 条问零地址最多多少条。推导过程是这样走的。三地址格式总长 OP(4) A1(4) A2(4) A3(4) 16 位操作码 4 位。4 位编码共 16 种若三地址用掉 15 种0000 到 1110剩下 1111 这一种作为扩展标志留给二地址。所以三地址能表示 15 条正好满足。进入二地址编码变成 OP(4) OP(4) A1(4) A2(4) 16 位有效操作码 8 位但它们共享同一个前缀 1111。二地址可用的编码是 1111 0000 到 1111 1111共 16 种。若二地址用 15 种1111 0000 到 1111 1110剩下 1111 1111 作为扩展标志给一地址。进入一地址编码为 OP(4) OP(4) OP(4) A1(4) 16 位前缀 1111 1111。可用编码 1111 1111 0000 到 1111 1111 1111共 16 种。用 15 种剩 1111 1111 1111 作扩展给零地址。进入零地址编码为 OP(4)OP(4)OP(4)OP(4) 16 位前缀 1111 1111 1111。可用编码从 1111 1111 1111 0000 到 1111 1111 1111 1111共 16 种。答案就是 16 条。我把每一步的剩余编码数整理成表方便对照记忆地址格式操作码有效位数前缀模式可用编码数若用掉留给下一级三地址4无16151二地址8111116151一地址121111 111116151零地址161111 1111 111116——这套模型的关键在于1 个编码的传递。每往下走一级就用掉 15 个、留下 1 个当扩展旗。为什么是 15 和 1因为 4 位编码一共 16 种用 15 种刚好留 1 种做前缀这样前缀永远是唯一的不会和已用编码冲突。你要是把上一级用满了 16 种那下一级就没法扩展了——这是命题人最爱设的陷阱。我再换个方向强调一次每级留下做扩展的那个编码本身不能再算作该级的一条指令。很多同学算到二地址时会顺手把 1111 1111 也算成一条二地址指令结果后面一级直接算崩。记住被当扩展旗的那一个已经名花有主了。2.3 反向题型和变形的破解方法考试除了正着算给各级指令数求某一级最多几条还会倒着考。比如三地址指令 12 条、二地址指令 6 条、一地址最多能有多少条这时候就不能无脑套 15 了得按实际用掉的数量重新算剩余编码。处理这类题的通用步骤我一直沿用下面这个流程几乎不错第一步确定每级操作码的有效位数地址码占多少剩下就是操作码的第二步算出每级总可用编码数第三步减去该级实际使用的指令条数再减去必须留给下一级的至少 1 个扩展前缀第四步把剩余数乘以下一级的地址格式下每级能裂变的倍数逐级往下传。这里有个坑我得特别提醒留给下一级的扩展前缀不一定是 1 个。如果某一级指令条数很少剩余编码可能有好几个理论上都能当扩展旗但为了规范和简单通常只用最靠后的一个。绝大多数真题按用掉 n留 1来设计但你要是遇到用掉数量明显偏少的题就要想想是不是有多个扩展位。我踩过一次坑一道题三级都留了 2 个扩展位我当时按 1 来算整道题零分。所以读题时一定要盯住最多和采用扩展操作码这些字眼看清它到底让你按哪种约定来。还有一个变形是把地址码长度改成不等的比如第一个地址 4 位、第二个 6 位。这时候每一级的操作码有效位数是变化的必须逐级重算不能套模板。我的做法是画一张树的草图根是总字长每一层减掉该级地址码所占的位把所有分支标出来一眼就能看出哪一层还有多少叶子可用。这个图不占多少时间但能帮你省掉大量心算错误。提示扩展操作码的题务必在草稿纸上写出每一级的二进制前缀不要只在脑子里跑。前缀看得见就不会把扩展旗误当成指令码。3. 寻址方式全解析从概念到有效地址计算3.1 九种寻址方式的本质区分寻址方式这一块很多人的记忆方式是背九种名字立即、直接、间接、寄存器、寄存器间接、隐含、变址、基址、相对。背是背下来了一做题就分不清变址和基址到底差在哪也说不清为什么相对寻址要加 2。问题就出在没有抓住本质。其实所有寻址方式都是在回答同一个问题有效地址操作数真正所在的位置怎么得到抓住这一个问题九种方式立刻就能分组。第一组操作数直接跟在指令里不需要访存取操作数——这是立即寻址。EA 这个说法在立即寻址里其实不适用因为根本没有地址操作数就是指令的一部分。它的优点是快取指时顺带就拿到了缺点是数值固定、范围受限。第二组形式地址就是有效地址本身——直接寻址。指令里的 A 就是操作数的内存地址取操作数需要一次访存。简单直观但寻址范围受地址码字段长度限制。第三组形式地址是地址的地址——间接寻址。A 指向一个内存单元那个单元里存的才是真正的操作数地址。需要两次访存一次取地址、一次取操作数范围大但慢。第四组操作数或者地址放在寄存器里——寄存器寻址和寄存器间接寻址。前者操作数就在寄存器零次访存后者寄存器里存的是操作数地址一次访存。这组的好处是快寄存器访问不占用访存周期。第五组带偏移的寻址——变址、基址、相对。这三种形式上都写成 A 某个寄存器区别在于那个某个寄存器语义不同。寻址方式有效地址 EA访存取操作数次数典型用途立即无操作数在指令中0常量赋初值直接EA A1访问固定变量间接EA (A)2扩大寻址范围、指针寄存器无操作数在寄存器0高频数据暂存寄存器间接EA (R)1指针访问变址EA (IX) A1数组、循环基址EA (BR) A1程序重定位相对EA (PC) A1转移指令隐含操作数位置隐含0累加器操作这张表我建议直接背进脑子考场上直接调取。但光背不够得理解每种方式的设计动机。变址寻址为什么都用在数组上因为它固定指令里的 A 不变让变址寄存器 IX 递增就能连续访问数组的每个元素。基址寻址为什么用于程序重定位因为基址寄存器 BR 由操作系统在装入程序时设定改变它就能把同一段程序搬到内存不同位置指令本身不用改。相对寻址为什么用于转移因为转移目标通常是当前指令往前或往后若干条用 PC 作基准编出来的程序就是位置无关的——程序搬到内存任何地方相对偏移都不变转移仍然正确。这三个动机就是三种方式的分水岭比死记公式强得多。3.2 相对寻址与变址寻址的易混点深挖我先说相对寻址里那个让无数人栽跟头的加 2。相对寻址的公式通常写作 EA (PC) A。但这里的 PC 指的是什么值是这个转移指令本身的地址还是下一条指令的地址答案是下一条指令的地址。原因在于CPU 在执行一条指令时取指阶段就已经把 PC 加了一次加的是当前指令的长度所以当执行到这条转移指令时PC 里已经指向下一条指令了。因此公式里的 (PC) 是已更新后的 PC。举个实战数字。某机器指令字长 16 位按字节编址。转移指令放在地址 2000H占 2 字节指令中给出的偏移量 A 06H。问转移目标地址。PC 已经自增到下一条指令位置也就是 2000H 2 2002H。EA 2002H 06H 2008H。如果你忽略了那个加 2算成 2006H就错了。偏移量是补码表示的可正可负正向是往后跳负向是往回跳循环。做题时先判断符号再进行加法。再说变址和基址的区别这是另一组高频易混点。两者形式都是 EA 寄存器 A但内容主动权不同。变址寻址中A 不变、变址寄存器可变所以适合遍历数组——IX 从 0 加到 n。基址寻址中基址寄存器不变、A 可变所以适合把一个大的地址空间当作基座A 在里面当偏移——数组和循环用变址程序搬家和空间划分用基址。还有一个细节容易被忽略变址寻址允许变址寄存器自动增减实现自动遍历基址寻址通常不这样做。另外变址寻址的用户可以用指令去改变变址寄存器的值软件可控而基址寄存器往往由系统管理程序本身不能随意改出于安全和重定位考虑。这个权限上的差别是简答题里很爱考的加分点。3.3 寻址方式对指令周期的影响复习寻址方式时一定要把它和指令周期有几个机器周期绑在一起看。同一台机器指令格式相似但寻址方式不同指令周期可能差出一大截。立即寻址和寄存器寻址的指令通常只需要取指周期加执行周期不需要访存取操作数速度最快。直接寻址多一次访存指令周期多一个访存周期。间接寻址要访两次多两个访存周期而且第二次访存的地址要靠第一次的结果才能确定不能和前面并行串行代价明显。这里有个我印象很深的综合题角度给出一个指令序列让你算总的访存次数或者算在有无 Cache 情况下的实际访存时间。做这种题时先按寻址方式逐个标出访存次数再加总。比如取指本身通常算一次访存如果不考虑 Cache 直接命中直接寻址的操作数再算一次间接寻址算两次。很多同学漏掉取指那一次结果整体偏小。注意算访存次数时先把取指访存和取操作数访存分开计数再根据题目给的 Cache 命中率决定哪些访存真的打到主存。这两步混淆是丢分的重灾区。寻址方式的复杂度还直接影响控制器的设计。寻址方式越多地址生成单元AGU要支持的运算就越多译码逻辑越复杂。这其实也是 RISC 精简指令集要砍掉大量寻址方式的原因——每多一种寻址硬件都得为它修一条路径。理解了这层RISC 为什么只保留少数几种寻址方式就顺理成章了。4. RISC 与 CISC 的对比及指令流水初步4.1 CISC 与 RISC 的取舍逻辑CISC复杂指令集和 RISC精简指令集不是谁先进谁落后的问题而是两种不同的设计哲学背后各有取舍。CISC 的思路是让硬件多干活软件少写代码。它的指令数量多、格式复杂、寻址方式丰富一条指令可能完成相当复杂的操作比如直接对内存里的数做运算、一次搬一大块数据。这样编出来的程序短对内存容量紧张的年代特别友好。但代价是指令长度不固定、译码复杂、各条指令执行时间差别很大难以流水化。RISC 的思路相反让软件多写几行硬件跑得快。它砍掉复杂指令指令格式规整、长度固定、寻址方式少绝大多数指令都能在一个时钟周期内完成方便流水线。代价是完成同一功能需要更多条指令程序体积可能更大但对现代的编译器优化来说这不算问题。从考研答题的角度我整理了一张对比表简答题直接照着答就很稳比较维度CISCRISC指令数量多几百条少通常百条以内指令长度不固定变长固定寻址方式多样多达十几种少常见几种访存方式运算指令可直接访存只有 load/store 访存控制器实现多为微程序控制多为硬布线控制流水线适配较难较易寄存器数量相对少相对多编译优化依赖硬件复杂功能依赖编译器优化这张表里我最想强调的是最后一行。很多人只把 RISC 理解成指令少、定长但真正的精髓在于RISC 把复杂性从硬件转移到了编译器。硬件不做的优化交给编译器去做。所以 RISC 机器的性能很大程度上取决于编译器质量。这个视角在简答题里是加分项考官看到你写出复杂性转移这个层次就知道你不是在背书。再补一个易错点。选择题里常问以下哪项不是 RISC 的特点选项里可能混进指令均可在一个周期内完成——严格说这条是绝大多数指令绝对化的表述往往是错的。还有RISC 一定比 CISC 快这种说法也是错的性能要看具体实现和任务类型。凡是带一定所有必须的选项先打个问号。4.2 指令流水中的数据相关、结构相关、控制相关既然讲到了指令级的执行就绕不开指令流水里的三种相关。它们和指令系统是强绑定的因为相关的根源就在于上一条指令还没写完下一条就急着读。结构相关也叫资源冲突。两条指令同时要用同一个硬件资源就会撞车。最典型的是访存冲突一条指令进入访存阶段要取操作数同时下一条指令的取指阶段也要访存两条指令抢同一个存储器。解决办法有二一是插入停顿气泡二是把指令存储器和数据存储器分开做成哈佛结构各用各的。第二种办法是硬件设计师最喜欢的一招直接把冲突从根上消灭。数据相关是三种相关里最隐蔽也最高频的。它有三小类我把它们用最直白的话说清楚。写后读RAW后一条指令要用前一条还没写回的结果这是最常见的一种必须等。读后写WAR后一条要写一个寄存器而前一条还没读完它这在前一条读、后一条写的顺序下才可能出问题乱序执行里常见。写后写WAW两条指令都写同一个寄存器最终结果应该是后写的生效如果执行顺序被打乱就可能出错。顺序流水线里主要防的是 RAW乱序流水线里三种都要防。处理数据相关的手段有插入停顿、数据前推旁路、编译器重排序。数据前推是最划算的因为它不增加停顿只是把还没写回寄存器堆的结果直接从 ALU 输出提前送给下一条指令的输入。我当年第一次理解前推时觉得这招很妙——既然结果已经算出来了为什么非要等它写回寄存器再读出来直接绕过寄存器堆送过去就行。这就是典型的用一点额外硬件换掉若干周期停顿的工程取舍。控制相关是分支指令带来的麻烦。处理器遇到分支时不知道下一条该取哪条指令因为要等分支条件算出来才知道。如果傻等流水线就断了。解决办法有延迟分支把几条不依赖分支结果的指令挪到分支后面执行、分支预测猜一个方向先取指猜错了再回滚、以及预取两条路径的指令。这三种相关本质上都是顺序取指、并行执行这个矛盾带来的。指令流水追求的是重叠但指令之间天然有依赖追求重叠就会撞上依赖。整个流水线设计的艺术就是在重叠和依赖之间找平衡。理解了这句话后面学超标量、乱序执行、寄存器重命名这些进阶内容会顺很多。提示数据相关和控制相关在综合题里经常一起考题干给你一段指令序列和流水线结构让你标出哪里会停顿、需不需要前推。做题时按逐条指令、逐个阶段画流水线时空图比空想准确得多。5. 常见问题与排查技巧实录5.1 高频错题排查速查表刷题过程中我攒了一堆反复错、反复忘、反复栽的坑整理成下面这张速查表考前扫一遍非常有用。典型问题常见错误正确思路扩展操作码每级留几个前缀一律留 1 个看题目给定用掉多少剩余才决定相对寻址 EA忘加当前指令长度PC 已指向下一条指令再相加变址 vs 基址用途混用变址遍历数组基址程序重定位访存次数统计漏算取指那一次取指、取数分开计数间接寻址访存次数记为 1 次取址一次 取数一次 2 次RISC 绝对化选项见到就选带一定/所有的先怀疑立即寻址 EA硬套公式算 EA立即寻址无 EA操作数在指令中这张表里的每一条我都在真题或模拟题里被它坑过至少一次。尤其第一条和第二条属于知道也容易错的类型必须靠考场上的警惕性来防守。除了表里这些我还想单独说说复合题型。有时候一道题会把扩展操作码和寻址方式绑在一起考给你一个指令格式前几位是操作码后面是地址码问你某操作码对应的指令如果采用变址寻址有效地址怎么算。这类题看着复杂拆开就是两个独立小问先根据操作码定位指令格式再根据寻址方式算 EA。关键是不要被它的外壳吓住一步一步来。解题顺序我个人的习惯是先标出指令字长和各字段位数再标出操作码最后处理寻址。因为寻址方式往往依赖指令格式的判定结果顺序错了会做无用功。5.2 复习节奏与几个血泪教训关于这一章怎么复习我给出几条实打实的经验都是踩坑之后总结出来的。第一别把指令系统留到最后突击。它的很多概念比如访存次数会在后面的 Cache、存储系统、虚拟内存里反复复用。你现在把访存次数算清楚了后面学 Cache 的命中次数、学页面置换时的访存开销都会轻松很多。反过来如果这一章糊弄过去后面几章会一路报错。第二扩展操作码一定要手写推导不能只看答案。我见过太多同学看答案时会合上答案就写不出来。原因就是没有把每一级的二进制前缀在纸上完整走一遍。你哪怕只写五道题的完整推导这一类的公式都能内化成肌肉记忆比看二十道题的解答都有用。第三寻址方式要结合具体例题去理解不要孤立地背定义。比如相对寻址你至少要亲手算三小道正向转移、负向转移、以及地址溢出的情况。算过之后PC 已经指向下一条这个点就再也不会忘了。第四RISC 与 CISC 的简答题别只答特点要答出设计哲学和复杂性转移。这是我批改别人笔记时发现的最大差距。答特点的人很多答哲学的人少而这恰恰是拉开档次的地方。第五多画时空图。数据相关、控制相关这些看文字描述很抽象画成流水线时空图一看就明白哪条指令在哪个周期会撞上。这个技能在后面学流水线章节和做综合题时回报率极高。第六给自己准备一页错题小抄只记那些容易错但已经懂了的点比如相对寻址加当前指令长度、间接寻址两次访存。考前翻一遍比重新刷题高效得多。最后再分享一个我个人的小技巧。学指令系统这块时我习惯在草稿纸左上角画一条指令生命周期线从取指、译码、算地址、取操作数、执行、写回把每一步画成一个方框。每遇到一道题就问自己这条指令在哪个方框里发生了什么、访问了几次内存、用到了哪个寄存器。坚持这样做你会发现指令系统不再是散落的知识点而是一条完整的流水从软到硬、从编码到执行全都串起来了。这个内容后面还能接着往深处挖比如指令级并行里的超标量、超长指令字VLIW它们的根都在这里。等把基础打牢了再去碰这些进阶的东西思路会非常清晰不会觉得是在空中楼阁里学新概念。
返回列表