微程序设计详解:从微指令编码到控制存储器的工作原理
开头说实话微程序设计这个章节在我学计算机组成原理的时候属于那种“上课听天书、考前背重点、考完全忘光”的典型内容。但等你真的把这部分啃下来再回头看CPU那一整章会有一种豁然开朗的感觉——原来所谓“指令执行”本质上就是一个“翻译加查表”的过程只不过这个“翻译器”藏在控制单元CU里看着复杂拆开全是套路。这篇文章我打算用我自己的学习和复习笔记来梳理一遍微程序设计从为什么要引入微程序控制、微指令长什么样、编码方式有哪些讲究到我自己在实验里手写微指令踩过的坑以及期末题里反复出现的“送命题”怎么一眼看穿。既适合正在期末冲刺的学生党也适合要做计算机组成实验、需要把微程序控制器跑通的动手派。整个设计思路是先讲清楚控制器的本质再一层层往里面拆每一层都配上具体例子不搞抽象的“就是那样”式糊弄。1. 先搞懂指令周期再看微程序就顺了1.1 每条指令的背后都是一连串微操作所有学过计算机组成原理的人都知道一条指令的执行分为取指IF、译码ID、执行EX、访存MEM、写回WB这些阶段。但你有没有想过一个问题加法指令ADD R1, R2在执行阶段到底干了什么不是“加了一下”这么简单而是经过了“把R1的值送到ALU的A输入端把R2的值送到ALU的B输入端ALU执行加操作把结果写回R1”这一整套细碎动作。这些最底层的、不可再分的操作动作就叫微操作Micro-operation或者叫微命令级操作。每条指令从进入CPU到执行完就是由几十个甚至上百个微操作排队执行完成的。硬布线控制器用触发器搭一个“状态机”让这些微操作按时序一个个发生而微程序控制器不搭状态机它把这些微操作做成“微指令”一条一条放在控制存储器里执行指令就等效于去控制存储器里把这些微指令取出来执行一遍。这就是“程序控制机器指令”的意思也是“微程序”这个“微”字的由来——比普通程序更低一层控制的不是数据流而是控制信号本身的流动。1.2 微指令和机器指令是两层完全不同的“程序”很多人一开始搞混机器指令和微指令的关系。其实可以这样理解机器指令是给程序员和编译器看的“用户手册”而微指令是给硬件执行机构看的“施工图纸”。用户手册说“把两个数相加”施工图纸详细规定了“第3根线要通电、第7根线要置高电平、结果要放到哪个寄存器”两者层次完全不同。微程序设计的基本思想是把每一条机器指令翻译成一串微指令序列这些微指令按顺序存放在一个叫“控制存储器”Control Store, CS的高速只读部件里。CPU执行机器指令时实际上是通过“取微指令—执行微指令—取下一条微指令”的循环来完成整条机器指令的工作。这有一点像查字典机器指令是单词微程序是解释这个单词的那段注音和释义控制存储器则是整本字典。1.3 为什么用微程序不用硬布线学习的时候常有一个疑问既然硬件直接搭状态机不是更直接吗为什么要有微程序这种“绕了一层”的方式答案就是灵活性vs速度的经典取舍。硬布线控制器速度快、依赖触发器逻辑电路直接产生控制信号但设计一旦完成就无法修改。如果CPU要新增一条指令、修改某个指令的行为就必须改电路、重新流片这对现代处理器来说成本太高。而微程序控制器把控制逻辑变成了“存在ROM里的数据”要加指令就多写一段微程序改指令就改微代码根本不用动硬件也不用动电路这正是早期CISC处理器比如x86最早期的实现普遍采用微程序控制的原因。但这是不是意味着硬布线就被淘汰了也不是。现代处理器里微程序主要用来处理复杂指令和异常处理流程而简单高频指令往往还是走硬布线或“硬连线微码补丁”的混合方式。所以你可以认为微程序是一种“用存储换灵活”的思路是计算机设计中“软硬件协同”的一个经典例子。搞清楚这个权衡逻辑对理解后面RISC和CISC之争也有帮助。2. 微程序控制器的整体结构和核心部件2.1 五个核心部件缺一不可微程序控制器要跑起来至少需要五个部件控制存储器CS、微指令寄存器MIR、微地址寄存器μPC或叫CMAR、微地址形成逻辑也叫微指令地址发生器、以及指令寄存器IR。控制存储器CS存放全部微指令的ROM/RAM部件。我把控制存储器看作“微程序的硬盘”。在真正的CPU里它通常做在处理器内部访问速度极快。容量不需要很大几百条微指令就够顶一套指令集了但每条微指令里面的控制位非常宽这是一大特点。微指令寄存器MIR从控制存储器取出来的一条微指令先暂存到MIR里然后由MIR的各位去直接控制各个部件。之所以要这个缓冲是因为ROM的读取有延迟而且不能让ROM输出直接乱跳需要寄存器把当前微指令“锁存”住。微地址寄存器μPC保存下一条要执行的微指令地址。它的作用相当于普通程序的PC程序计数器区别在于它计数器的递增规则更丰富除了加1以外还可能跳到微程序入口、按分支条件跳转、按操作码映射跳转等。微地址形成逻辑负责生成“下一条微指令地址”。在顺序执行时直接等于μPC加1在跳转时根据机器指令的操作码、条件码标志、微指令中的下地址字段等生成新的μPC值。这部分通常是组合逻辑电路也是微程序设计里最需要动脑子理解的地方。指令寄存器IR存放当前正在执行的机器指令提供给微地址形成逻辑做译码以决定该到哪个入口去执行对应的微程序。2.2 微程序控制器的工作流程像一台“循环流水线”微程序控制器的运行可以概括为这样的循环启动机器后先从控制存储器的“取指微程序”入口地址开始按顺序取出取指阶段的几条微指令给PC、MAR、MDR、IR分别发控制信号完成读指令、译码。接着微地址形成逻辑根据IR里的操作码字段生成对应机器指令的微程序入口地址把这个地址装入μPC随后按微程序的顺序逐条取出执行直到这条机器指令的微程序执行到“END”微指令又回到取指微程序入口开始下一条机器指令。整个流程如果类比成一个餐厅出餐的过程取指微程序是“查看下一位顾客的点菜单”执行微程序是“按菜单做菜”分支判断是“看顾客对菜品的忌口”控制存储器是“后厨的那本菜谱大全”。每一道菜对应一条微指令每个步骤对应一个微操作。这样想就不难记住了。2.3 为什么用“一级译码”而不用传统译码器传统硬布线控制器的指令译码器通常是一个n-to-2^n的译码器结构输入n位操作码产生一大串互斥的控制信号。而微程序控制器把“译码”从“硬件译码”变成“查表访问”操作码不是直接译出控制线而是作为地址去控制存储器里定位一段微程序。因此微程序控制器的“译码”可以叫作“地址映射”——操作码字段的值直接作为微地址的一部分或作为索引去查“入口地址表”找到微程序入口。这个入口表可以看成一张哈希表操作码是key微程序地址是value。很多教材会把这张入口表放在“微地址形成逻辑”内部而不单独画出来考试时容易忽略但实际作用非常关键。我当时复习到这儿就在本子上写了一句提醒自己IR操作码 → 微程序入口地址 → 控制存储器 → MIR → 控制信号一条主链路串起来这就够了。3. 微指令的格式、编码方式和下地址字段3.1 水平型微指令和垂直型微指令区别在哪儿微指令的格式主要分两大类水平型微指令和垂直型微指令。水平型微指令的特点是控制字段非常宽一条微指令里往往有几十甚至上百个二进制位每一位或每几位直接对应一个微操作控制信号理论上可以同时控制多个部件并行工作。它的优点是指令并行度高、执行速度快、控制信号不需要译码或只做少量译码缺点是微指令太长、写入和阅读都困难程序员直接看到的就是一堆0和1可读性差。垂直型微指令的特点是格式接近于普通的机器指令有操作码字段、地址字段每条微指令一般只控制一种微操作类似于“简化版的机器指令”。它借助译码器把操作码字段转换成具体控制信号所以微指令短、可读性好、编写微程序容易但一次只能执行一个微操作执行速度慢、并行度低。实际设计和实验中我见过的大多数教学型模型机用的是水平型或“水平为主、垂直为辅”的混合方式。因为教学模型机追求的是把控制信号条理清楚地展示给学生让你看到“哪一位控制什么”而水平型正是最直观的。你要是用垂直型看起来像写汇编理解硬件原理的作用就没那么强了。这也解释了为什么绝大多数“计算机组成原理实验”里的微程序控制器都是水平型的——它本来就是用来做教学演示的。3.2 微指令编码的三种方式直接控制、最短编码、字段间接编码编码方式这块只要你理解了“控制信号太多、微指令太长”的矛盾后面就顺了。直接控制编码就是一位控制信号对应微指令的一位不需要译码。优点是速度快、并行能力强缺点就是指令长。这在小型教学机里常用一条微指令要有30到40位其中大部分甚至一半以上都是控制位看得人头皮发麻。最短编码就是给每条微指令编一个唯一编号通过译码器把编号映射为完整控制信号。这样微指令长度最短但一次只能执行一个控制信号完全牺牲了并行性。这种方式虽然省空间但在实际处理器中基本不单独用。字段间接编码是两种方式的折中把控制信号分成若干组同组内信号互斥每组用一个较小的字段去编码执行时通过译码器还原成控制信号。因为同一组里的信号互相排斥比如ALU的加减乘除只能选一个所以可以压缩位数而不同组之间的信号可以并行保留了并行性。绝大多数实际微程序控制器都采用这种方案。我在笔记里画了个对比表考试前看着非常有用编码方式控制位宽度执行并行性译码器适用场景直接控制宽约等于控制信号数高一位一信号不需要教学模型机、强调直观最短编码最窄只需索引号无一次一个信号需要极简教学、理论分析字段间接编码中等分组压缩组内互斥、组间并行各组独立译码实际工程的绝佳折中3.3 微指令里的地址字段怎么生成下一条微指令地址微指令除了控制字段还有一个重要的“下地址”部分。每条微指令执行完得知道下一条该取谁。这就分成三种情况顺序执行直接是当前微地址加1也就是μPC跟普通程序计数器一模一样。无条件跳转微指令里的下地址字段直接送进μPC相当于汇编里的JMP。条件跳转根据状态条件比如零标志Z、进位标志C决定下一条地址是取顺序地址还是取下地址字段相当于JZ/JC。此外还有一个特殊跳转机器指令执行完后控制逻辑要回到取指微程序的入口所以需要“无条件跳转到取指入口”取指完成译码后要根据IR操作码跳转到不同的执行微程序入口。这两种跳转都是由“微地址形成逻辑”完成的本质上也属于查表或条件选择。我在实际阅读微程序代码时习惯把每条微指令的下地址字段单独列一行一边读一边在纸上画出跳转关系。因为微程序执行顺序并不总是连续的经常跳来跳去不画图很难追踪。这也是我建议复习时一定要动手画“微程序流程图”的原因——考试问到“该微指令执行完后下一条是谁”这种题你心里有图就不会慌。3.4 微程序入口地址怎么算操作码映射是关键这里有一个我刚开始学的时候特别困惑的点取指微程序完成后怎么知道该跳到哪条执行微程序答案是用一个“入口地址映射”机制。常见做法是把操作码字段作为低位地址和某个基地址拼起来直接形成入口地址。比如某模型机的微程序入口地址 操作码 × 2 固定基址或者用操作码查一张“入口地址表”。具体设计取决于CPU定义。考试题里常见的就是给一张指令-入口地址对照表让你算某条指令的微程序入口地址是多少其实就是一个查表换算问题。4. 设计一条加法指令的微程序手把手带你走一遍4.1 先确定模型机的硬件结构理论看了半天不动手永远学不扎实。我自己实验时用的是一台8位模型机CPU内部有通用寄存器R0到R3、ALU、累加器ACC、指令寄存器IR、程序计数器PC、地址寄存器MAR、数据寄存器MDR以及一个控制存储器。指令格式是操作码高4位地址/寄存器字段低4位。我们把一条简单的加法指令定义为ADD Rd, Rs ; 功能Rd ← Rd Rs机器码格式高4位是操作码假设为0001低4位分成两个2位字段分别表示目的寄存器Rd和源寄存器Rs。4.2 把ADD的微程序按步骤拆开ADD这条指令要完成的工作是从寄存器堆里读出两个寄存器的值送ALU加再把结果写回目的寄存器。这个流程可以拆成微指令步骤步骤1设置ALU的A输入端为Rd的值同时设置ALU的B输入端为Rs的值。步骤2设置ALU选择加法操作并把结果暂存到暂存器或直接写回寄存器堆输入总线。步骤3把ALU结果写回Rd并同时给出“微程序结束”信号让控制器回到取指微程序。在我的模型机上微指令的控制字段包括寄存器堆读使能RegRead、寄存器堆写使能RegWrite、ALU操作码4位、ALU输入A来源选择2位、ALU输入B来源选择2位、写回使能WrACC、PC递增信号PCInc、微指令结束信号End等。按照“字段间接编码”的原则我把互斥的信号分组比如ALU操作码一组源选择一组写使能一组这样每条微指令大概22位左右就够用了。4.3 写出三条微指令的具体编码如果用“控制位下地址”的描述方式三条微指令可以写成这样这里用文字描述替代真实二进制实际实验里要填二进制或十六进制微地址控制操作下地址说明0x10RegRead1A选择RdB选择RsALUADD0x11把两个源值送到ALU输入端0x11ALU结果送寄存器堆输入总线RegWrite1写Rd0x12加法结果写回目的寄存器0x12End1PCInc1取指入口0x00结束ADD微程序取下一条指令然后由微地址形成逻辑处理“入口映射”。假设ADD指令的操作码是0001入口地址是0x10也就是指令助记符和执行微程序就靠这个入口表联系起来。当控制逻辑译码到“操作码0001”时直接把0x10装入μPC就开始执行ADD的微程序了。4.4 执行过程一步一步推演现在假设PC指向一条ADD R1, R2指令。整个流程如下控制器从地址0x00开始顺序执行“取指微程序”0x00PC输出到MARPCInc有效MARPC的值准备读内存0x01从内存读出指令到MDR再送到IR0x02微地址形成逻辑根据IR操作码生成入口地址0x10装入μPC。控制器跳到0x10执行ADD的微程序0x10寄存器堆读出R1、R2的值到ALU输入端选择加法操作0x11ALU输出写回R1寄存器堆写使能有效0x12置End信号μPC回到0x00开始下一条指令的取指。这个过程非常机械也非常清晰。我当时做实验时用示波器看每一条微指令的时序发现控制信号确实是按这个顺序一个个“冒出来”的那一刻是真切理解了“指令是硬件自动执行的但执行的节奏是微代码控制的”。4.5 微程序设计中时间顺序和并行性的微妙平衡写微程序的时候不是简单地“一个步骤一行”而是要想哪些操作能并行。比如在步骤1里我们同时发出“读R1”“读R2”“设置ALU为加”这三个信号它们互不冲突就能放在同一条水平微指令里同时执行。而“写回目的寄存器”和“读源寄存器”绝对不能同一条指令因为会同时读写寄存器堆产生数据冲突。所以微程序设计的本质是把可并行的微操作打包进一条微指令把有依赖关系的微操作拆成不同微指令。能用2条完成的操作不要用3条但也不能为了追求并行把有先后依赖的信号强行分在一组。这个度需要平衡我在实验里最常犯的错误就是把要写回寄存器的值和要读取的源都放在一条微指令里结果模型机上电后数据总是差一个周期。多试几次就会发现这里其实是“数据冒险”的缩影——微程序也要面对类似流水线冒险的问题。5. 常见问题与避坑经验期末和实验都用的上的实战技巧5.1 期末高频考点这几类题一定要会第一个高频考点是**“微指令格式识图”**。给你一条水平型微指令的二进制位让你指出哪几位是控制字段、哪几位是下地址字段、哪个字段控制ALU、哪一位控制寄存器写使能。这种题纯靠细心但需要你对“字段间编码”的组织方式有概念。凡是看到分段的、带译码器的微指令先看它分了几组每组几位一一对应关系是什么。第二个高频考点是“某条机器指令对应的微程序有多少步”。这种题其实是在考你能否把一个指令的执行流程拆成微操作序列。常见陷阱是忘了算“结束微指令”或“分支微指令”那一步导致步数少一项。我自己也栽过后来习惯了所有拆解都以“以End结束”为框架就不会漏。第三个高频考点是**“微程序控制和硬布线控制的对比”**。这里通常以简答或选择形式出现。核心要点是微程序控制用存储逻辑、灵活、易修改、速度慢硬布线控制用硬连逻辑、速度快、修改难、成本高。再多说一句CISC多用微程序RISC多用硬布线现代处理器常为两者混合异常处理和控制复杂指令时用微码高频简单指令用硬连线。这句话在回答对比题时能额外加分。5.2 实验踩坑实录手把手教你避雷实验里最容易翻车的点其实不在“写微代码”而在“微指令下地址的计算”。很多实验板要求你手动指定每条微指令的地址和下地址而不是自动加1。也就是说每条微指令多长、下一条地址多少全都要你自己填。这时候最常见的错误是填了一个“跳到自身”的地址机器就死循环在了一条微指令上看起来就像“CPU完全不动了”。排查方法是看调试面板的μPC是不是万年不变如果是就检查该条微指令的下地址字段。第二个常见坑是控制字段和译码器一致性。有些实验板的微指令不直接输出控制信号而是经过译码器。你写编码时是按“011”表示ALU加但忘记在译码器真值表里确认结果实际执行的是减法。这类问题用“单步执行观察ALU输出”能快速定位比看代码快得多。第三个坑是寄存器写使能和时钟边沿的配合。微指令只是组合逻辑状态下产生控制信号真正写入寄存器要靠时钟沿。如果你把所有控制信号设好了但没等一个时钟沿就认为结果出现了就会觉得系统“延迟一拍”。所以调试微程序时一定按时钟周期而不是按“看到的信号变化”来数步数否则你会被时序搞疯。5.3 我整理的自查清单每次写微程序前都过一遍以下是我后来反复使用的“微程序调试十问”每次做实验或复习检查都按这个过一遍微程序入口映射是否正确取指微程序结束后能否正确跳转到本条指令的入口每条微指令的控制信号是否互斥、有无同一组冲突写寄存器与读寄存器是否放在了一条微指令里下地址字段是否确认为需要跳转的地址结束信号End是否只有最后一条微指令才有是不是所有机器指令都有结束微指令PCInc是否在取指阶段每取一条指令就加了一次条件跳转所用的条件标志是否在这个时刻有效单步追踪时μPC变化是否符合预期这些问题看着简单每一问都能对应到真实硬件上的一种失效模式。我每次实验前默写一遍至少能从源头减少一半以上查错时间。5.4 笔记法安利怎么记微程序设计这章节最有效最后分享我记这部分笔记的方法。第一张纸记“主链路图”PC→MAR→MDR→IR→微地址形成→CS→MIR→部件控制。第二张纸记“对比表”硬布线vs微程序、水平型vs垂直型、直接编码vs字段编码。第三张纸记“流程示例”一条完整指令比如ADD或LDA的全过程每条微指令一行旁边标控制信号和下地址。三张纸放在一起期末复习时几乎能覆盖90%以上的考点。如果有条件做实验一定要自己亲手把ADD这类基本指令的微代码填一遍再手动单步执行、验证每个控制信号的问题。这个过程虽然繁琐但比把笔记翻三遍都管用。因为微程序设计的知识点真的不能靠背必须靠“跑流程”才能形成感觉。我个人在实际操作中的体会是微程序控制只要抓住“一条机器指令 一段微程序 一串控制信号”这个等式再配合一定量的手推练习就完全不用怕它。它不像流水线和Cache那样概念难懂它只是“细节多、步骤碎”而对付细节最好的武器就是动手画流程图、写微指令表、按周期单步跑三件套下来基本稳了。这篇笔记就先写到这里如果你也在学这一章建议你找一个模型机仿真软件或者手边实验箱把某条指令的微程序从头到尾单步执行一遍跑通了的感觉真的非常爽。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →