
计组课设做到实验三的时候很多人的心态会经历一次从“我懂了”到“我哪儿没懂”的回撤。我在软院做这门课设那年实验三验收前夜宿舍群里突然有人发了一张仿真截图RAM输出一列全是0地址明明在跳数据就是不出来。接下来二十分钟大家围绕“是时钟接反了还是片选没拉低”吵成一团。最后发现问题特别简单——输出使能压根没接。这个画面我一直记到现在因为它基本代表了计算机组成原理实验三的本质把理论课上背过的引脚和时序第一次真正接成一个能跑的电路。不同学校的实验三内容会有差异有的做运算器有的做存储器有的直接上CPU数据通路。我按当年山大软院课程设计里最常见的形态——存储器实验——来展开你如果做的是别的方向原理部分照样能对上。这篇文章会把实验前后我认为最关键的东西理一遍从“为什么要做这个实验”到“搭电路时怎么排错”再到“验收时老师到底在问什么”都属于课程设计过程中不太会有人主动跟你讲清楚的部分。1. 实验三在整门课里的位置从“看懂”到“搭出来”的临界点1.1 部件实验和系统实验之间的那道坎计算机组成原理前几个实验说句实话大多数人都能靠“抄作业”混过去。实验一通常是寄存器堆或者简单的运算器照着PPT把线一连拨几个开关结果就出来了。这时候你不需要真正理解数据是怎么流动的因为所有模块都已经被封装好了你只是在拨开关看现象。实验三不一样。它往往是第一个需要你“自己设计接口”的实验。以存储器实验为例RAM不是像寄存器堆那样只要给地址就同步输出它有片选、有写使能、有输出使能、有时序要求还有扩展问题。你被迫开始思考地址到底什么时候稳定数据应该什么时候打进去为什么读出来的数据会晚半拍这些问题在实验一里完全不会遇到但它们是之后做CPU数据通路、做流水线控制的核心。从课程设计的任务书来看实验三通常被放在“部件实验”和“系统实验”之间意思很明确你前面对各个部件的理解要在这一轮实验里凝结成一种“接口意识”。后面做单周期CPU的时候寄存器堆、ALU、存储器要连在一起跑指令任何一个接口没想清楚整个CPU都跑不出正确结果。所以把实验三看成整门课的分水岭一点都不夸张。1.2 仿真平台和实验箱从效率角度你应该怎么选当年我们做实验可以选两条路一是在虚拟仿真平台上搭电路二是去实验室用实验箱连线。我自己的经验是两个都要做但顺序很关键——先在仿真环境里把电路跑通再拿实验箱做一遍验证。如果你一上来就扎进实验箱光查找断线和跳线开关就能耗掉一晚上。仿真工具我用的是Logisim。它有个特别实在的优点你能看见每一根线当下的状态值能手动置位任何输入能连续给时钟还能在电路中间插探针。这种“看得见内部”的特性对理解存储器时序帮助极大。你可以在RAM的数据输入口拉一组八位开关先写入几个已知值再切到读模式观察输出是否稳定复现整个过程都在自己的掌控里。如果你们用的平台是star cop 2018这类虚拟实验系统操作逻辑会有些不一样。这类平台一般更贴近真实实验箱有面板、有接线区、有波形窗口。使用手册建议拿到手先别急着连电路先把“存储器实验”这一章从头到尾翻一遍重点关注两个地方一是片选信号是低有效还是高有效二是写使能是上升沿写入还是整个高电平期间都能写。这两个参数在不同平台上的实现往往不一样纯靠猜很容易栽跟头。手册上通常都有时序图照着时序图接线比对着原理图接线可靠得多。1.3 如果你做的是ALU方向的实验三很多学校把ALU实验放在第三个搜索词里“组间串行进位”出现频率很高我多提一句。这类实验的核心是快速加法器的进位结构和存储器实验是两个完全不同的方向。它更偏组合逻辑设计不需要时钟不需要考虑时序验证方式就是把输入的加数和被加数拨成二进制看结果满不满足预期。这种实验最容易踩的坑是进位链层级错误。四位一组的CLA做内部先行进位组与组之间再用串行方式连起来听起来简单连的时候经常把组内进位和组间进位混在一起。我的建议是画一张表把每一组的进位输入、组内产生的进位、传出去的进位分别列出来再动手连接。后面第4章我会专门把组间串行进位的延迟计算和实现思路写清楚做这个方向的同学可以直接跳过去看。2. 动手之前地址、数据、控制三种信号要先在脑子里跑通2.1 地址线根数和存储容量就是一道2的幂次题很多同学动手搭存储器习惯直接拖一个RAM模块进画布然后开始连线连到一半才发现地址线根数不对。正确顺序应该是先算清楚“我这个存储器到底该有多大”。n根地址线能区分2的n次方个存储单元k根数据线决定了每个单元能存多少位二进制数。比如16K×8位的存储系统意思是有16K个单元每个单元8位。因为2的14次方等于16384也就是16K所以地址线要14根数据线要8根。这类题目期末考试几乎必考在实验三里同样逃不掉因为你扩展芯片的时候必须自己算地址线够不够。我见过很多同学做字扩展的时候低地址线和高地址线分不清。低地址线直接连到每个芯片的地址引脚高地址线要通过译码器产生片选信号。比如4片16×4的芯片扩展成64×4需要6根地址线其中低4根给每片芯片高2根进2-4译码器译码器输出的4个片选信号分别控制4片芯片。这个结构你必须亲手画一遍、算一遍才会真正明白为什么实际存储器系统都要在CPU和内存芯片之间加译码器。2.2 读时序和写时序仿真里不写时序电路里全是玄学存储器实验和之前实验最大的区别就是引入了“时序”这个概念。RAM芯片的读操作和写操作对信号出现的先后顺序有严格规定。读的时候地址要先稳定下来然后等一小段地址建立时间再把输出使能拉低过了访问时间之后数据才出现在数据线上。写的时候更讲究写使能拉低的这段时间内地址和数据都不能变化。Logisim里的RAM默认是异步读、时钟上升沿写这里就有个特别容易误解的地方。很多人以为只要地址一变输出马上跟着变其实不对。实际RAM芯片有访问时间地址变化到数据输出稳定之间存在延迟。如果你连了一排LED灯用来显示数据地址变化瞬间灯泡可能短暂闪烁一下这是正常的物理表现。在仿真工具里你看到的是输出瞬间变化但在硬件平台或者实际芯片上这个延迟就是真实存在的。做实验的时候建议在报告里把读时序和写时序各画一张图标清楚地址建立时间、数据建立时间、写使能宽度。这既是老师想看到的“理论结合实验”也是你自己理清思路的过程。时序图画完你会发现后面做CPU的时候控制信号为什么要有那些奇怪的先后关系一下子就讲得通了。2.3 高阻态和总线冲突为什么不能把输出直接挂在总线上第三个必须在动手前想明白的概念是高阻态。三态门这个知识点理论课上讲过但很多人是从实验三开始才真正理解“第三态”存在的意义。数据总线是共享的多个芯片的输出本来就可能连在同一组线上。问题是如果两个芯片同时把数据放到总线上总线上的数据就会冲突读出来就是乱的。解决办法是让每个芯片的输出通过三态门再连接到总线平时输出端是高阻态相当于把门关上只有被片选选中的那个芯片才把数据放到总线上。实验三做字扩展的时候这个问题尤其致命。你用2-4译码器产生片选信号每一时刻只有一个芯片被选中其他芯片的输出都是高阻态数据总线上的数据就是安全的。但如果连线疏忽把片选信号接反或者译码器输出悬空两个芯片同时被选中总线直接打架数据怎么读都是错。排查这类问题的方法很简单把每个片选引脚上用探针或者LED灯显示出来手动改变高地址位看是不是只有对应的灯亮。如果是两个灯一起亮说明译码器接线肯定有问题。3. 用Logisim搭存储器的完整过程从一片RAM到扩展阵列3.1 第一步先搭一个16×8的RAM子电路并验证读写我不建议一上来就搭扩展结构先把最基本的单芯片读写跑通。打开Logisim在Memory库里找到RAM组件双击修改属性Data Bits设为8Address Bits设为4。这表示16个存储单元每个单元8位。连接的时候把每个引脚弄清用途。地址端口接一组四位开关数据输入接一组八位开关数据输出接一组LED灯或八位探针。RAM的时钟引脚需要用时钟源提供没有时钟它不会工作。写使能引脚接一个开关你需要手动拉高或拉低来控制读写模式。验证流程分成两步。第一步写把地址设成0000数据输入设成你想要的二进制数比如00001111把写使能拉高手动触发一次时钟上升沿数据就被写入。第二步读把写使能拉低地址保持0000观察输出端是不是真的出现00001111。如果你把地址改成0001输出应该变成之前写进0001单元的内容而不是0000单元的内容。这一步看起来简单但它是后面所有工作的基础。如果写操作和读操作在这个阶段对不上问题基本集中在三个方面时钟极性设反了、写使能开关根本没生效、数据输入线和输出线接错。这三个问题解决掉后面扩展时排错会少很多。3.2 第二步用计数器当地址发生器观察连续读写手拨开关验证读写没问题后接下来就是把地址发生器加进来。这一步最有意思它帮很多同学想明白了“程序计数器PC到底在干什么”。做法也很直接用一个四位计数器时钟输入和RAM的时钟接同一根信号计数器的四位输出连到RAM的地址端口。每来一个时钟上升沿计数器加1地址就自动从0走到15。RAM的数据输出端接上二进制显示器或者探针你就能连续看到一串数据被读出来。如果没有在对应地址预先写入数据读出来全是0这是正常的。所以更完整的做法是先用3.1的手动写入方式往16个单元里分别写入一组递增的数据然后再切到计数器自动模式让地址自己跑验证读出顺序也是递增的。这一步做完你已经摸到了“取指令”的门槛。CPU里的程序计数器本质上就是一个能自动加1的计数器唯一区别是CPU的PC还能被跳转指令修改。实验三用计数器做地址发生器其实就是把CPU取指令这段逻辑单独拆出来给全班看一遍。所以实验报告里一定要把这个联系写出来点明“计数器产生地址→存储单元输出数据”这个过程和CPU取指令阶段的对应关系这通常是加分项。3.3 第三步位扩展和字扩展把容量变大芯片扩展是实验三的重头戏也是期末考试反复出现的计算题。扩展分成两条路位扩展和字扩展。位扩展是为了增加数据线宽度比如用4片16×4的芯片组成16×16的存储系统。做法是把所有芯片的地址线并联写使能并联片选并联但每个芯片的数据线分别接总线的不同位段第一片接低4位第二片接第5到第8位以此类推。这样同一时刻所有芯片都在工作合起来输出一个16位数据。字扩展是为了增加存储单元的个数比如用4片16×8的芯片组成64×8。这时候数据线是共享的地址线要分成两组低4位直接连到每片芯片的地址端口高2位接一个2-4译码器译码器输出分别接到4片芯片的片选端。在这个结构里每一时刻只有一片芯片被选中其他芯片输出都是高阻态数据总线上才不会冲突。实验里最常见的问题是位扩展和字扩展混着做时地址线和数据线接串了。我的建议是画一张扩展前后对比表把“扩展前几根地址线、几根数据线扩展后几根地址线、几根数据线”填进去再动手连线。这张表同时也是报告里很漂亮的一张图。3.4 仿真中躲不过的三种异常和排查链路做Logisim仿真下面三个问题基本每个人都会碰到一次我把排查思路写清楚遇到了可以直接照着走。数据读出全为0先看写使能是不是被拉低了再看RAM有没有接时钟最后看数据输入引脚有没有被意外接地。很多人把一行未连接的悬空引脚当成0其实悬空状态在某些电路里是既不是0也不是1的悬浮电平读出来全0只是因为实际拉到了默认电位并不代表写入成功。输出数据和地址差了一拍有时候你设置地址0001但输出显示的还是0000单元的内容。这大概率是读操作存在延迟或者时钟边沿还没触发。Logisim的RAM如果是同步读输出会在时钟上升沿之后更新你需要等一个时钟周期再观察。这种“差一拍”现象在后面做CPU的时候也经常出现处理办法是调整控制信号的产生时机而不是怀疑电路接错了。扩展之后总线上数据乱跳这是最典型的芯片同时选了问题。用探针分别检查每片芯片的片选引脚看同一时刻是不是有两片以上同时有效。如果是检查译码器的地址输入接的是不是高地址位输出有没有接反。记得片选信号往往是低有效译码器输出的正逻辑需要再加非门才能对上芯片的要求。4. 实验三里的理论考点报告里必须写清楚的几个“为什么”4.1 读优先还是写优先会产生什么实际影响RAM芯片内部实现有两种基本策略读优先和写优先。这俩词听起来像概念游戏实际影响特别大做CPU的时候绕不开。所谓读优先就是当读使能和写使能同时有效时数据输出端口反映的是当前地址对应的存储内容写操作先缓一缓。写优先则相反数据输出端口反映的是正在被写入的数据。Logisim里的RAM默认是异步读你在仿真里观察到的行为更接近读优先。而实验箱上有些SRAM芯片是写优先的如果同一个时钟周期内既要读又要写结果会不一样。这个东西为什么要写进实验报告因为单周期CPU设计里寄存器堆和数据存储器对读写时序的要求完全不同。寄存器堆通常要求能同时读两个寄存器写则发生在时钟边沿数据存储器往往希望读操作是组合逻辑、立即出结果。搞清楚你用的存储器是读优先还是写优先才能决定ALU的计算结果什么时候送进来、什么时候打入寄存器控制信号怎么配合。很多同学后面做CPU卡壳其实就是卡在这。4.2 指令存储器和数据存储器为什么一个只读一个可写存储器实验做完后有的同学会问既然我有RAM了是不是下一周直接拿它来存指令就行这个问题背后是冯·诺依曼结构和哈佛结构的区别老师很喜欢在验收时问。RAM是可读可写的适合放数据。指令存储器不需要在运行中被改写所以通常做成ROM或者只读的RAMFPGA内部也常见用ROM资源来实现。冯·诺依曼结构把指令和数据放在同一个存储器里靠总线分时访问哈佛结构把指令存储器和数据存储器物理分开可以同时取指和访问数据吞吐率更高。实验三做的RAM本质上对应的是数据存储器后面的指令存储器实验你大概率要再建一个只读存储块。这个知识点我认为不要只停留在背定义。做CPU实验时你会看到取指令阶段从“指令存储器”读出一条指令执行阶段又从“数据存储器”读或写运算结果两个存储器功能完全不同。理解了实验三的存储器是哪种后面CPU的连线就不再是一团乱麻。4.3 组间串行进位和实验三的关系如果你做的是运算器方向的实验三组间串行进位几乎就是核心考点。这里我把原理说透免得光看PPT最后还是不会连。组间串行进位是针对并行加法器的优化。一个4位先行进位加法器CLA可以在不看低位进位的情况下同时算出四位和以及传出去的进位组内延迟很短。但16位加法器不用直接做16位先行进位那样逻辑太复杂了。实际做法是分成4组每组内部用先行进位组与组之间串行传递进位。这就是“组内并行、组间串行”的意思。延迟怎么算假设每组内部产生结果的延迟是t1进位传到下一组的延迟是t2那么16位加法器的总延迟大约是t1加上4个t2。对比普通串行加法器每位进位都要一路传过去延迟线性累加组间串行的方案已经快了不少。实验里做这个东西验证重点就是进位链是否正确传递我建议测试的时候用边界值先测0xFFFF加0x0001看进位一路传到最高位再测0x0FFF加0x0001看进位是否只在一组内传播。如果你们实验三恰恰又是存储器方向组间串行进位不会直接出现在电路里但它是理解ALU中加法器延迟的底层知识期末问答题极爱考所以我顺带写在这里看热搜词的时候也留意一下。4.4 计数器、PC和地址寄存器实验三留下的三条线实验三用计数器产生地址这条线是和CPU联系最直观的。程序计数器PC本质上就是一个带自增功能的寄存器每取完一条指令PC加1遇到跳转指令再被修改成目标地址。你在实验三里验证过“计数器自动加1→存储器依次输出数据”后面看到CPU里PC的功能时就会觉得非常自然。另外两条线是地址寄存器和数据寄存器。地址寄存器MAR用来暂存CPU要访问的地址保证整个访存周期内地址保持稳定数据寄存器MDR用来暂存在存储器和CPU之间传输的数据。很多简化版教学CPU设计里并没有独立的MAR和MDR而是直接用总线或者寄存器堆代替但理解它们的存在对读复杂一点的CPU数据通路图很有帮助。这三条线说到底是同一个思想CPU访存时地址从哪来、数据在哪停一下、谁控制什么时候读写。实验三你在做的正是“存储器的读写”把这几个问题在实验层面体验一遍后面学控制器、学总线时序就不容易晕。5. 实验报告和验收从“做出来”到“讲清楚”才是高分的关键5.1 报告里最容易丢分的三个位置我做课设时帮同学改过不少实验报告发现大家丢分的地方出奇地一致。第一个就是没有真值表或状态表。存储器实验至少要有两张表一张是不同地址单元写入内容的汇总表一张是读操作和写操作的控制信号组合表。这两张表一画老师一眼就能看出你确实做了实验。第二个是截图没有标注。很多报告截图里只有一堆线和信号灯既不标信号名也不写当前是读还是写老师看得一头雾水。正确的做法是每张截图旁边用文字写清楚“当前地址是XXXXWE为低电平因此输出端为XX单元的数据”这才是实验现象。第三是把实验现象写成流水账。比如写“把地址设为0000读出7然后地址设为0001读出8”这种写法没有体现“设计预期”和“实际结果”的对照。更好的写法是分层先写“根据电路设计地址0000应当读出预写入的数据7”再写“实际观察输出端为0111与预期一致”。这块内容占不了多少篇幅但整篇报告的逻辑层次会完全不同。5.2 验收时老师最常追问的三个问题及参考答法说句实话大部分老师验收时并不会只看电路能不能跑通他们真正想确认的是——这个实验是不是你自己亲手做出来的。所以追问的问题基本都是围绕电路设计的关键点展开。第一个问题为什么写使能和输出使能不建议同时有效参考答法是写使能有效表示总线数据要被写入存储单元而输出使能有效表示要把存储单元的数据读到总线上二者同时有效会产生信号冲突导致总线数据不确定。实际SRAM芯片会通过内部时序来避免乒乓但新手设计时还是应该人为保证二者互斥。第二个问题如果地址线增加一根存储容量扩大几倍这是送分题答“翻倍”就行但老师还会追问“为什么”你要说出来地址线每增加一根可选择的存储单元数就乘以2因为2的n1次方除以2的n次方等于2。第三个问题扩展时片选信号从哪里来这个问题考察的是字扩展的原理参考答法是片选信号由高地址位通过译码器产生低地址位直接作为所有芯片的统一地址输入。每片芯片的片选端分别接译码器的一个输出这样在任一时刻只有一片芯片被选中其他芯片输出处于高阻态保证总线不冲突。这三个问题都不难但突击复习很容易忽略。验收前我习惯自己做一次“自问自答”指着电路图把每个引脚的作用讲一遍讲不通的地方就去查手册查完再讲。这个过程比多调一个晚上电路有用得多。5.3 亲测有效的最后半小时检查清单实验验收或者演示前半小时别再改电路了按下面的顺序过一遍比临场加功能靠谱得多。第一检查悬空引脚。仿真平台里悬空引脚默认为0但实验箱上悬空引脚可能引入噪声导致偶尔读错数据。把所有未连接的输入引脚强制接上确定电平。第二检查时钟极性。特别是如果用了计数器又用了RAM二者必须保证在同一时钟沿动作否则地址先变还是数据先写会被打乱。最好从同一个时钟节点引出分支不要用两个时钟源。第三准备几组“边界测试数据”。全0、全1、递增序列、随机序列各写几组演示的时候用这些数据分别验证看起来很专业也能提前兜住意外情况。第四确认截图带时间信息或者实验箱面板带指示灯状态。这些现场证据能让报告和演示互相对应老师会认为你的实验是完整、可追溯的。第五把实验手册里对应的时序图翻到那一页放旁边验收时如果老师提到时序你立刻能指出来这种细节非常加分。最后再补一条我自己的习惯实验做完后把每一根引脚为什么这么连写在一张草稿纸上别急着扔。后面做单周期CPU实验很多控制信号的接法都能从这张草稿纸里找到影子。计组课设最值钱的不是那几行仿真波形而是你亲手把课本上的引脚和时序接成能跑的电路后脑子里建立起的那张“信号连接网”。这张网一旦搭好后面CPU实验再复杂你也会觉得不过是在原来部件的基础上多加几条控制线而已。