
很多学校的大二下学期都会遇到一门叫“计算机组成原理”的课。课堂上听“取指、译码、执行”的时候信誓旦旦觉得自己懂了一进实验室多思实验箱摆在面前才发现课本上那些大方框和小箭头全部变成了需要亲手用杜邦线连起来的芯片引脚。作为过来人我很清楚这门课设最容易被卡住的地方不是铜线接得对不对而是脑子里对“数据从哪个部件流到哪个部件”没有一个确定性的表格。这篇内容就围绕我在多思平台上完成模型机课程设计的全过程讲讲指令集怎么选、微程序怎么编码、实验箱怎么接线、哪些坑真的会让人熬夜以及答辩前应该怎么自查。正在准备课设的同学建议先收藏等你在实验室里被总线冲突搞到头秃的时候再翻出来看会救命的。1. 这门课设在考什么从指令集到一台能跑程序的模型机1.1 多思实验箱到底提供了哪些硬件资源我用的多思实验箱简单来说是一个可以手动组装CPU的教学平台。它不像真实主板那样把所有芯片焊死而是把CPU拆成几个功能模块ALU模块我用的是比较经典的74LS181寄存器模块通常是几个74LS273或者74LS374内存模块包括RAM芯片和地址寄存器微程序控制器模块主体是EPROM加微地址计数器。箱子上最显眼的是那一排排总线插孔和指示灯所有模块都通过一个内部数据总线连接但哪些模块要把数据放上总线哪些模块要接收总线数据完全由你自己设计的控制信号说了算。这正是模型机设计开始前你必须认清的底线多思平台提供了一个插槽丰富、时序可见的实验环境但CPU的“脾气”是你在微程序里一点一点喂出来的。平台提供的手动脉冲按键、拨码开关、总线灯、微地址灯这些不是装饰它们就是你的调试工具。很多同学一上来就想直接敲程序运行结果被满箱子乱闪的灯搞晕。正确做法是先用这些灯把你设计的每一条指令跑通再谈整机运行。多思实验箱的优势在于所有关键信号都有观测点不需要你拿着示波器到处猜只要把数据通路画对每一步该亮哪几个灯都是可预判的。1.2 课程设计的目标拆解五个必须交出来的东西根据课设要求要做出一台可以执行一段简单程序的模型机重点不是性能而是把组成原理的知识变成可见的运行过程。我当时总结下来最后需要交五样东西第一一份指令系统设计包括操作码格式、指令类型和寻址方式第二一张完整的数据通路图标明寄存器的输入输出如何接到总线上第三一张微程序控制表每条机器指令的取指和执行微命令全都列出来第四在实验箱上实际跑起来用拨码开关或者计算机软件载入一段测试程序观察数据变化第五一份课程设计报告把上面的过程写清楚。很多人以为重点是第四步其实前三步才决定你能不能扛住老师的提问。我见过不少小组连线已经连得差不多了却答不出“你这个ADD指令为什么需要四个微周期”就是因为第一二步没做扎实。课程设计的评分逻辑很直接运行成功只能说明你照着别人的图连上了线能讲清楚数据流和控制信号才说明你真正理解了模型机。2. 指令集与数据通路先画图再写码不然全是返工2.1 我最终选定的指令集和原因模型机的字长我选了8位指令地址也是8位原因是多思实验箱的开关和指示灯都是按8位一组设计的用16位的话光看灯就要多一倍的脑力而且8位模型机已经足够覆盖教学要求。选指令时不要贪多我当时只实现了9条立即数送累加器 MOV A, #data读内存到累加器 MOV A, addr累加器写回内存 MOV addr, A加法 ADD A, addr减法 SUB A, addr与 AND A, addr无条件跳转 JMP addr条件跳转 JZ addr也就是结果为0时跳转最后是停机 HLT。这个集合覆盖了立即寻址、直接寻址、运算类、无条件转移、条件转移和程序终止演示效果足够微程序量又控制在可承受范围内。如果老师觉得指令太少可以再加一条JC或者一条循环移位但基本指令集一定要克制。我当时亲眼见过隔壁组一口气设计了16条指令数据通路画了三页纸最后连线的时候自己都对照不过来微程序EPROM烧了一遍又一遍还是漏洞百出。少而完整比多而混乱有价值得多。2.2 一条ADD指令背后的多拍波形选指令容易难的是画数据通路。以 ADD A, addr 为例这条指令用的是直接寻址所以必须先去内存里读地址再根据地址去读操作数。完整分为四个微周期第一拍把程序计数器PC的当前内容送MAR完成访存前的地地址准备第二拍RAM读数据把指令从存储区送到MDR再从MDR送IR同时PC加1第三拍把指令中给出的addr从IR的低8位送到MAR相当于第二次访存第四拍RAM把addr地址中的操作数读到MDRMDR送ALU的B端ALU的A端接ACC运算结果再写回ACC。这里有个关键点ALU只在最后一拍工作前几拍都只是在搬运地址和指令。把这一步想清楚你才能知道控制信号表里每一个“out”和“in”应该在哪个阶段打开。我当时是先在纸上把每一步涉及的寄存器画成一个个小方块再在方块之间画箭头箭头方向就是数据流向然后在旁边标注这一步需要置1的信号。画完这张图后面的微程序编码就变成了查表填1的机械工作。2.3 控制信号表整个课设最重要的一张表如果说课设只能做一份文档我会选控制信号表。它本质上是用表格形式把数据通路里每个寄存器在每一拍是“输出到总线”还是“从总线输入”记下来。列是微地址或者微周期编号行是控制信号交叉处填1或0。我常用的控制信号包括PCout、MARin、MemR、MDRin、MDRout、IRin、RAMW、RAMR、ACCout、ALUen、ACCin、PCin这些。这张表一旦列出来微程序的机器码就是从它逐行生成的。我一开始偷懒没列完整表直接在多思软件里点控制信号结果仿真时数据总线上的值总是乱掉指令、地址、数据混在一起根本分不清。后来老老实实把表补全问题立刻变得清晰。所以给同学们的硬建议是先建表后编码表不完整绝对不动EPROM。控制信号表就是你的“程序源码”微代码只是它的编译结果源码错了还去折腾编译结果那是给自己找罪受。3. 微程序设计把“取指-译码-执行”变成存储在EPROM里的表格3.1 微指令字长与控制位的分配多思平台上的微程序控制器核心是一块EPROM每个地址单元保存一条微指令。微指令的每一位都对应一根控制信号线这就是水平型微指令。我的微指令字长是24位其中前16位是控制字段每一位负责一个控制点比如第0位PCout第1位PCin第2位MARin第3位MDRin第4位MDRout第5位IRin第6位RAMR第7位RAMW第8位ALUen第9位ACCout第10位ACCin第11位ALU模式选择。其余的8位里3位是判别字段5位是下址字段。这24位的分配不是死的你可以根据实际需要调整教学模型机的目的本来就是让人看到控制信号的并行性位宽大一点反而直观。但必须注意的是控制位的编码顺序一旦定下来后面写机器码时就要严格遵守。多思软件录入微程序时有的是按位开关有的是按十六进制数据顺序反了功能就全反了。我见过有人把PCout和PCin写反结果PC永远不递增程序永远卡在第一条指令。这种问题往往不怪接线纯粹是位序图没看明白就往上填。3.2 从指令流程表翻译成微代码有了控制信号表微程序其实就是一个有固定入口的查找表。微地址0、1、2固定用来取指从微地址3开始按指令类型编号存放各自执行段的微程序。我的取指微程序如下微地址控制信号判别下址0PCout MARin无11MemR MDRin无22MDRout IRin无33PCin按IR操作码跳转转入分支表这里有一个微地址转移的关键设计在微地址3这一拍PCin有效让PC加1同时微程序控制器里的判别逻辑会看IR的操作码并把操作码拼接到微地址高位从而跳到分支表里对应的入口。分支表有若干连续单元每个单元对应一条机器指令的执行微程序入口。这个设计非常省事等于所有指令公用三条取指微指令然后各走各的执行段程序跳转逻辑在硬判别电路上就完成了。拿 MOV A, #data 这种立即数指令举例它的执行段只需要两个微周期第一拍把IR低8位里的立即数经过数据总线送到ALU的B端同时让ALU处于直通模式第二拍让ALU的运算结果写入ACC完成“数据到累加器”的传送。因为多思平台的总线时序是“先建立数据上升沿到来时打入寄存器”所以ACCin这拍必须放在数据已经稳定的后面。如果你把ACCin和IRout放在同一拍虽然仿真软件可能碰巧通过但真实实验箱上大概率会出现数据锁存不到位的现象。3.3 多思软件里的录入和常见错误多思上位机软件一般都有微程序编辑窗口可以选择按二进制位图录入也可以按十六进制数据块填入。我自己的习惯是先在Excel里把控制信号表整理好然后用公式自动生成24位二进制字符串再每4位一组换算成十六进制最后粘贴到多思软件里。前期多花半小时后面能省下好几个查错的夜晚。录入过程中最常见的错误有三个一是下址字段写错本来想跳转到微地址10结果填成0A或者填错一位变成11程序运行就乱套了二是判别字段和控制字段的顺序弄反不同实验指导书给的位序可能不一样录之前一定先观察软件界面上每个bit对应的名称三是把RAMR和RAMW同时置1这等于让RAM读和写同时有效在真实硬件上是明确不允许的轻则数据总线冲突重则可能驱动芯片发烫。每次录完一条微指令我建议立刻在仿真模式下面单独跑一遍对应的机器指令确认没问题再录下一条。等全部录完再统一调试出了问题你根本不知道是哪条微指令埋下的雷。4. 上箱实测从手动拨开关到自动运行程序4.1 接线的三大区域和我的连接顺序多思实验箱的接线大致可以分成三个区域第一块是数据总线区一堆插孔代表8位总线所有模块的输出和输入都要用电线引到这里第二块是控制信号区微程序控制器输出的每个控制点都对应一个插孔需要把它们接到各模块的使能端或者时钟端第三块是时钟和复位区提供手动脉冲、连续脉冲和微地址清零信号调试的时候离不了。我建议的接线顺序是逆着数据通路来的先把PC到MAR之间的地址通路接好再接RAM的地址线和数据线然后接MDR与总线的三态门再接IR与总线的通路最后接ALU和ACC。这样每接完一块都可以在手动模式下单独验证一次。如果你一上来就把所有线全部接完上电后一大堆灯同时乱闪根本没法判断是哪一根线的问题。另外多思实验箱上的插孔通常有防呆设计插线时不要用蛮力插到底轻轻拉一下确认不松脱就行。4.2 单微周期调试手动时钟怎么用多思实验箱上通常有一个“单微周期”按键按一次只产生一个时钟脉冲让微程序控制器往前走一步。这就是调试模型机的神器。我当时的调试方法很机械先把微地址计数器和EPROM准备好然后每按一次键看一眼当前微地址是多少再看总线灯和数据灯是否符合控制信号表中这一拍应有的状态。举个例子取指阶段微地址0时PCout灯和MARin灯应该亮数据总线上应该是当前程序地址微地址1时RAMR和MDRin灯应该亮数据总线变成RAM读出的指令字节。如果发现微地址0时总线上不是PC值说明PCout到总线的三态门线松了或者PC预置不正确如果微地址1时总线没有变化那就要查RAM的片选和读写使能有没有接对。手动时钟模式下千万不要一口气按到底按一拍记一拍对照表格检查。只有把取指三段彻底跑通再去进入连续模式不然接下来全是看着花屏一样的灯干着急。4.3 整机联调时观察哪些指示灯把测试程序通过开关写入RAM后就可以切到连续时钟模式看整机运行了。这时候不要盯着CPU里所有寄存器看会眼花。我自己整理了一份观察清单优先级从高到低第一是程序计数器PC的灯看它是否按执行流正确变化遇到跳转指令时是否跳到了目标地址第二是指令寄存器IR的灯每执行完一条指令IR灯应该变成下一条指令的操作码如果在某条指令上一直不变说明取指或译码环节可能卡住了第三是ACC的灯这是运算结果的最终归宿程序结果对不对先看ACC第四是RAM地址灯尤其是写内存指令要确认数据写到了期望的地址。很多同学喜欢接一个逻辑分析仪去抓波形但模型机实验箱已经把关键信号引到灯上了先看灯再决定要不要上仪器。灯观察法是第一道防线它能在10秒内告诉你问题出在取指段还是执行段。直到现在我都觉得能把教学实验箱上的指示灯用好的人去调真实CPU的外设时也一定不会太差因为底层思路一模一样。5. 排错实录三次把自己从“彻底翻车”边缘拉回来的经历5.1 总线冲突ACC输出和RAM输出同时有效导致数据全乱第一次跑ADD指令时ACC里的结果总是不对不是两数相加而是变成了一个毫无规律的值。起初我怀疑是ALU坏了换着拨ALU模式开关也没用。后来用逻辑笔逐根测数据总线发现有一根线被两个输出源同时驱动一个是RAM的数据输出一个是为了配合ALU而提前打开的ACC输出。这就是典型的总线冲突。总线冲突的本质是同一时刻有多个三态门被拉低同时往总线上写数据。理论课上老师讲过多个输出不能同时占用总线但真正操作时往往因为想在一个微周期内多做一点事而随意打开信号。解决方式也很简单重新检查控制信号表确保同一微周期内只有一个输出控制信号为1如果有特殊情况也只能允许ALU输出和某个寄存器输入配合关系成立。从那之后我给自己立了一条规矩每一个微周期开始前先数一下有几个out信号大于一个就停下来查表。这条规矩让我后面的调试速度快了很多。5.2 微程序死循环下址字段填错引发的死循环还有一个极其隐蔽的问题出现在JMP指令的微程序段。程序单步执行的时候一执行到JMP微地址就不动了就像卡死在那里。我一开始以为是连续时钟没有触发后来切到单微周期模式观察微地址变化发现它其实在走一个循环从执行段跳到某个错误的下址那个错误地址对应到取指段中间执行完后又跳回原来的错误地址于是周而复始。这种死循环的根源就是EPROM里下址字段填错了。我想让它跳回取指段入口0结果手滑填成了一个中间地址微程序当然不会报错它只会老老实实跟着错误地址走。发现这个循环路径之后只需要把对应EPROM单元重新烧写即可。这件事给我的教训是遇到莫名其妙卡住第一件事不是去拽线也不是反复上电而是把微地址变化序列抄下来看它循环的路径。路径一定能告诉你是哪个下址出了问题这是最省时间的排查方式。5.3 时钟毛刺手动按键带来的“幽灵PC1”还有一次更神奇的故障手动时钟模式下我只按了一下脉冲键但PC却加了2。按键面板上明明只按了一次寄存器却跑了两拍。我当时以为按键坏了结果老师说很可能机械开关抖动在搞鬼。手动按键按下时机械触点会在一两毫秒内反复导通断开如果实验箱的按键没有做完善的硬件消抖一次按压就可能被当成多个脉冲送给时钟计数器。解决方法其实不难。操作上按脉冲键时不要垂直用力砸而是轻轻快按一次如果还是出现加2的情况可以在脉冲输入端并一个10uF左右的电容做RC滤波。连续模式下这种抖动不明显因为连续时钟频率远远高于机械抖动频率反而是手动单步时最容易触发。所以我一直提醒同学单步调试时发现寄存器多走了一拍先怀疑时钟抖动不要一开始就去改数据通路方向错了很容易把自己绕进一个根本不存在的“硬件故障”里。6. 答辩高分与写给学弟学妹的叮嘱6.1 演示程序的设计原则课设答辩时老师通常会让你现场跑一段程序。这个时候千万不要选一个很炫但谁也没法一眼看懂的复杂程序老师没有那个耐心也没有义务通过你几十行汇编去推理每一处的设计动机。我最后在RAM里放的程序很短先把立即数5送累加器再把立即数3加上去得到8后写回内存然后用JMP指令跳回开始同时留一条HLT放在程序末尾表明“程序到此停住”。整个程序只用七八行机器码但每一步都能看到PC、IR、ACC的变化。这样的演示最有力是因为它能展示模型机的全部核心动作取指、译码、立即数传送、ALU运算、访存、跳转和停机。跑的时候我还会同步口述“现在是在取指段IR收到了操作码下一步按操作码进入ADD的执行微程序”。这一句口述就能证明你不是靠运气把程序跑通的而是真正明白了模型机的微观运行过程。老师最吃这一套。6.2 报告里必须画图和贴表的几个位置课程设计报告里数据通路图和微程序控制表是不能缺席的。我建议至少在三个位置放图一是总体结构图把PC、MAR、RAM、MDR、IR、ACC、ALU、微程序控制器之间的连接画清楚二是指令格式图标出操作码字段和操作数字段各占几位三是微程序流程图展示取指段如何汇合、如何分流。表格至少要放控制信号表以及每条机器指令对应的微代码表最好用十六进制形式方便读者对照实验箱上的灯。报告是给人看的不是用来凑页数的。每张图下面都应该附一两句话解释“从这个图能看出什么”不要只是贴图。比如数据通路图旁边可以写“地址通路与数据通路分离保证指令执行期间PC能继续预取”这类说明比图本身更能体现你的理解深度。打印前还要注意图片清晰度那种截个模糊屏幕的大图打印出来一片糊老师第一印象就会打折扣。6.3 老师最爱问的问题和回答思路答辩时老师最喜欢从控制信号表反着问。比如“你把PCin放在取指微程序的最后一条如果把它放到第一条会怎样”这道题考的是时序关系你只需要回答如果PC取指前就先加1那么MAR里锁存的地址就不是当前指令的地址而会变成下一条指令的地址接下来读入IR的就是下一条指令而不是当前指令整个取指过程就错位了。这个回答就算过关。另一个常见问题是“为什么你的ADD指令需要四次访存三次行不行”答案是三次也并非绝对不行但如果你只有三个微周期就要考虑把指令送到IR后直接用地址寄存器缓存地址那个逻辑已经变成了另一种寻址方式不再是我们熟悉的直接寻址。你要讲清的是数据流而不是背标准答案。只要你把“哪一个周期做了什么操作、数据怎么走”说清楚就算老师心里有不同的设计他也会认可你的思路。特别提醒千万不要背PPT也不要吹嘘自己用了多高级的芯片挑一条最熟悉的指令从头讲到尾比讲一堆没做出来的扩展功能靠谱得多。6.4 给下一届的四个早早做起的建议最后给正在准备课程设计的同学四个非常实际的建议。第一课设开始的第一天就把控制信号表的模板建好每设计一条指令就补几行绝对不要等到实验箱到手才开始思考。第二尽量两个人分工一个人专管数据通路和指令设计另一个人专管微程序编码和软件录入但最后两个人必须能互相对答因为答辩是随机点名提问的。第三所有EPROM烧写操作烧之前把当前文件导出一份备份不然改一个下址把原来的数据覆盖掉想回退都没有后悔药。第四如果实验出现怪现象先在实验指导书里找时序图不要上来就怀疑硬件坏了多思实验箱真的没那么容易坏往往是你的控制信号时间关系不对。这四条建议来自我踩过的坑也来自我见过太多组的翻车现场。模型机课程设计说难不难说简单也不简单它考验的就是把一个抽象概念转化成一张张可控表格的能力。只要你能做到先画表、再编码、后接线、最后调试这个课设拿高分一点问题都没有。我自己在做完这个实验后回头再看计算机组成原理的教材很多之前靠死记硬背的结论都能顺下来了。希望你也能在实验箱的满排指示灯里找到那种“原来是这样”的快乐。