ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

微程序控制模型机设计详解:从指令系统到仿真调试

微程序控制模型机设计详解:从指令系统到仿真调试 如果你正在学计算机组成原理又刚好被安排做一个“微程序控制的简单模型机设计”课设那这篇内容应该能帮你少走不少弯路。我前前后后带过几届学生的课程设计自己也完整从头到尾搭过一台微程序控制的16位模型机从指令集设计、微指令编码到数据通路搭建、仿真调试整个过程踩过的坑比想象中的多。这篇文章就围绕“微程序控制的简单模型机设计”这个题把核心思路、设计细节、实操步骤和排查心得一次讲透。不管你是刚拿到题目无从下手还是已经写了一半卡在微指令编码上这篇内容都值得你花十几分钟读完。1. 模型机整体设计与核心思路拆解1.1 拿到题目先别急着写代码先回答三个问题很多同学一看到“微程序控制”五个字立刻就开始查什么是微指令、什么是控制存储器然后着急上手写Verilog或者VHDL。我见过不止一个团队这么干结果写到一半发现指令集和数据通路不匹配或者微指令编码和硬件控制信号对不上最后只能推倒重来。我个人的习惯是拿到“计算机组成原理课程设计_微程序控制的简单模型机设计”这个题之后先逼自己回答三个问题第一这台模型机要支持哪些指令这是一个功能范围问题。简单模型机一般不会做太多指令基础的就是算术运算类的ADD、SUB逻辑运算类的AND、OR、XOR数据传送类的MOV或者LOAD、STORE控制转移类的JMP、JZ。再往上加就是带立即数的指令、移位指令、甚至乘除法指令。作为课程设计我建议指令数量控制在8到12条之间既能体现设计工作量又不会让微程序失控。第二模型机的数据通路长什么样这是架构问题。你准备采用单总线结构、双总线结构还是多总线结构模型机课程设计里最经典的是单总线结构——所有部件都挂在一组总线上同一时刻只能有一个部件往总线上发送数据其他部件从总线接收数据。这样的好处是结构清晰、控制简单缺点是速度慢但对于教学模型机来说完全够用。第三用什么方式生成控制信号这就是“硬布线控制”和“微程序控制”的选择。现在题目已经定死要求用微程序控制所以你要把重点放在如何设计微指令格式、如何安排微程序流程、如何把微程序存储到控制存储器里并正确读出。把这三个问题想清楚后你再去看那些参考代码、实验指导书就会觉得脉络清楚很多。否则你一上来就钻进代码细节里很容易迷失方向。1.2 为什么课程设计偏爱微程序控制而不是硬布线我上课时总爱打一个比方硬布线控制器就像是一个专门定做的组合逻辑电路想改一条指令就得重新接线、重新设计逻辑微程序控制器则像是把控制逻辑写成了一张张卡片放在口袋里想改功能就换一张卡片。对课程设计来说微程序控制有三个特别明显的优势。第一个优势是规整。微程序把控制信号以“字”的形式存放在控制存储器中每条微指令就是一组二进制编码结构非常规则。你不需要设计复杂的状态机和逻辑方程组只要搞清楚每个部件需要什么控制信号然后把它们编码成微指令就行。第二个优势是容易修改和排查。设计过程中逻辑有误硬布线可能得改一堆门电路而微程序只需要修改ROM里对应地址的微指令编码。对课程设计的验收答辩来说这种可修改性太重要了。答辩时老师随便提一个“如果你要增加一条指令需要改哪里”微程序方案的答案非常清晰增加对应的取指阶段微程序和指令执行阶段的微程序就行。第三个优势是贴近真实CPU的设计思想。虽然现代高性能CPU大多采用硬布线控制但微程序控制在CISC风格的处理器中仍然有广泛应用。你在课程设计里学到的这套“把控制信号编码成字、用一条条微指令序列驱动数据通路”的思想将来理解处理器设计、嵌入式控制器、甚至PLC的梯形图逻辑都会有帮助。1.3 整体架构单总线模型机的数据通路方案结合前面提到的“简单模型机”定位我推荐直接用单总线模型机作为整体架构。不用觉得单总线显得低端恰恰是越简单的总线结构越容易把数据通路的细节讲清楚也越容易做出可运行、可演示的模型机。在单总线模型机中你会用到这些核心部件程序计数器PC、地址寄存器AR、指令寄存器IR、通用寄存器组一般用R0、R1甚至加R2、R3、算术逻辑单元ALU、累加寄存器AC、存储器RAM、以及一个用来临时保存ALU第二个操作数的暂存器DR也叫临时寄存器。此外还有状态寄存器保存零标志Z、进位标志C等。这些部件如何通过总线联系到一起简单来说就是所有部件的数据输入都从总线接收所有能够向总线发送数据的部件都有各自独立的“总线使能”控制信号。同一时刻控制器只允许一个部件的总线使能有效否则总线就会发生冲突。这一点我后面在微指令编码部分会再强调因为总线冲突是模型机设计中最容易出现、也最难排查的问题之一。图1是一张经典的单总线模型机数据通路框图这里不画图文字描述PC的输出接AR的输入同时PC也能输出到总线AR的输出接存储器的地址端口RAM的数据端口经由一个双向缓冲接到总线上IR、AC、通用寄存器组都直接挂在总线上ALU的一个输入来自AC另一个输入来自DR暂存器ALU的运算结果通过一个结果寄存器有时直接送总线再接回总线。这个结构能支撑的最经典指令执行流程是取指阶段把PC送AR然后读存储器再将指令从数据线读入IR同时PC自增执行阶段根据具体指令通过微程序控制序列操纵各个部件的使能信号完成数据的读取、运算和写回。1.4 方案选型背后的几点考量针对课程设计还有两个容易纠结的点我顺便说说我的建议。第一点是存储器怎么实现。你可以用RAM宏单元也可以定义成寄存器数组。我的实际经验是用寄存器数组在FPGA里就是reg数组在仿真和上板调试时都更直观。用RAM宏单元会涉及读使能、写使能时序初学者容易在时序上踩坑。模型机的存储器容量也不用大256个单元每个16位对几十条指令的程序来说绰绰有余。如果你是用FPGA开发板这部分直接用核心板的Block RAM或者分布式RAM都可以但为了聚焦课程设计核心逻辑用寄存器数组最合适。第二点是ALU怎么实现。模型机的ALU用组合逻辑就可以不要在里面加入时钟沿触发的寄存器。ALU的输入是AC和DR输出是运算结果以及Z、C等标志位。在做微指令编码时你只要保证在写入AC之前两个操作数都已就绪并经过一段稳定时间就能避免读到错误结果。我见过不少同学把ALU做成时序逻辑结果控制时序怎么调都不对——因为ALU本身如果带时钟数据通路里就多了一个寄存器级整个微程序的节奏全乱套了。2. 微程序控制器的原理与微指令编码设计2.1 微程序控制的核心思想程序说到底也是数据理解微程序控制器的关键是理解一个哲学层面上的转变控制信号本身可以被编码、被存储、被读取。传统硬布线控制器里如果你想执行一条ADD指令取指之后的一系列控制信号是由组合逻辑产生的某些输入组合触发某些输出。这种方案速度快但每换一个控制目标逻辑就复杂一分。微程序控制器的思路是反过来把每一个时钟周期里所有部件需要的控制信号归成一个字这个字就叫“微指令”。完成一条指令需要多个时钟周期也就需要多个微指令这些微指令按顺序存放在一个专门的存储器里这个存储器叫“控制存储器”简称CM也就是控存CM。CPU的控制器本质上变成了一个“解释程序”它不断从控存中取出微指令把微指令中每一位对应的控制信号发给各个部件执行完毕后再根据下地址逻辑确定下一条微指令的地址。说得更直白一点普通程序是让CPU去执行一串指令而微程序是告诉CPU“执行指令时内部各个部件该怎么配合”。前者指导数据流后者指导控制流。理解了这层关系你就能明白为什么微程序控制器也被称为“存储逻辑控制器”——它是用存储器的内容来实现控制逻辑的。2.2 微指令格式设计控制字段和下地址字段的划分微指令的格式设计是整个模型机设计的核心环节。一条微指令一般分成两个大块控制字段也叫操作控制字段和下地址字段。控制字段中的每一位或每一组编码对应模型机中一个部件或一组部件的控制信号。比如你设计模型机时有PCout、ARin、IRin、RAM读、RAM写、ACout、ACin、R0out、R0in、ALU加、ALU减、结果写回、PC1等一组控制信号。你就需要在微指令中为每一个控制信号分配一个二进制位。如果一个位是1表示该信号有效是0表示无效。这种编码方式叫“直接控制法”。它的优点是简单直观解码电路为零微指令字读出后直接连到控制点缺点是微指令字太长浪费存储空间。但模型机控制信号数量本就不多几十个位而已直接控制法完全合适。下地址字段用来指示下一条要执行的微指令在控存中的地址。同时微指令中还需要一个判别字段P字段来指明是否需要根据状态条件进行分支。判别测试的目的是实现条件转移类指令和循环类微程序。当需要分支时根据模型机状态寄存器中的Z、C标志以及指令操作码生成实际的下一条微指令地址。我设计过的一个模型机微指令格式大致是总长40位其中控制字段占28位判别测试字段占4位下地址字段占8位。控制字段28位分给十几个控制信号每位一个控制点剩下来一些位预留或者做同步控制。这个比例你不需要照抄关键是理解格式划分的用意控制字段直接驱动数据通路下地址字段决定序控制流判别字段支持分支。2.3 微程序的执行过程一条指令背后的微指令序列所有指令的执行都可以粗略分成取指阶段和执行阶段。取指阶段通常是固定的几步第一步PCout有效ARin有效把程序计数器中的指令地址送入地址寄存器 第二步RAM读有效同时PC1此时存储器把该地址对应的指令字送到数据线上 第三步IRin有效把数据线上的指令字打入指令寄存器 第四步根据IR中的操作码字段通过一个操作码译码器生成该指令对应的微程序入口地址送入微地址寄存器μPC微程序计数器。接下来进入执行阶段。以一条“ADD R0, R1”指令为例把R1的值加上AC的值结果送回AC首先是R0out有效、DRin有效把第一个操作数送入暂存器DR然后是ACout有效ALU操作码选择“加”同时把ALU的结果通过总线送回AC即结果写回ACin有效。如果还需要保存进位标志则同时让相关状态标志更新。这样一个简单的执行过程就至少需要两条微指令。如果你仔细数一下一条普通指令的微程序通常有5到8条微指令而JZ这类条件转移指令可能会有更多因为需要判断条件并可能跳转到不同地址。这也就是为什么模型机虽然只有十几条机器指令但控制存储器的容量一般要做到128×40位以上——微程序序列的规模比指令数量大得多。2.4 微程序入口地址的生成操作码译码与地址映射这里有个很关键的细节取指完成后控制器怎么知道该跳到哪个微程序去执行常见做法是“操作码映射”。IR中的操作码字段比如4位最多能区分16条指令。你可以在取指阶段的最后一个时钟周期通过组合逻辑把这个操作码转换成一个入口地址送入微地址寄存器μPC。这样一来指令ADD操作码0001对应的微程序入口地址可能是16号单元指令SUB操作码0010的入口地址可能是24号单元等等。为了节省微地址译码的复杂度很多模型机会做对齐处理每条指令的微程序都固定从某个地址开始中间空出来的地址用转移微指令或者空操作填充。这一点不太优雅但胜在简单稳定课程设计中完全够用。另外微条件转移靠的是判别测试。一个典型的做法是微指令中的判别字段P指明测试条件比如P000无测试、P001测试Z标志、P010测试C标志、P011测试IR操作码的第几位。如果满足条件就按下地址字段的跳转地址走不满足就用当前微地址寄存器自增μPC1顺序执行下一条微指令。这个分支逻辑很简洁也很适合用Verilog实现。3. 实操全流程从指令系统定义到微程序仿真调试3.1 第一步把指令系统写在纸面上我强烈建议你在打开编辑器和仿真工具之前先把指令系统完整地定义在纸上或者表格里。指令系统的设定直接决定后续单元模块设计、微指令设计和仿真测试用例设计。下面给出一个可参考的指令集示例指令字统一设计为16位其中高4位为操作码低12位按指令需要划分。基础指令集包括MOV R0, R1操作码0001寄存器间传送把R1的值复制到R0ADD R0, R1操作码0010R0 R0 R1并影响Z、C标志SUB R0, R1操作码0011R0 R0 - R1并影响Z、C标志AND R0, R1操作码0100R0 R0 R1OR R0, R1操作码0101R0 R0 | R1LOAD R0, [地址]操作码0110从存储器指定地址读数据到R0STORE R0, [地址]操作码0111把R0的值写到指定地址JMP 地址操作码1000无条件跳转JZ 地址操作码1001若Z标志为1则跳转HALT操作码1111停机。我把指令字统一成16位操作码占4位每个操作数占4位或者地址占8位这样指令编码非常整齐。对于LOAD、STORE和JMP这类带地址的指令一条指令字装不下所有信息就需要用双字指令第一个字是指令本身第二个字是操作数地址。这样虽然增加存储器访问次数但可以简化指令格式设计。3.2 第二步画出指令周期状态图指令系统确定后不要直接进入微指令编码先画状态图或者叫流程图。每个状态的输出就是一组控制信号状态的迁移方向由指令性质决定。取指阶段一般固定3到4个状态比如T0PC送AR、T1读存储器PC1、T2指令送IR、T3操作码译码确定入口地址。之后不同的指令进入不同的执行状态。以ADD指令为例执行阶段至少需要两个状态T4把R1送DR、T5AC与DR相加结果送AC并更新标志。以STORE指令为例T4把R0送总线、T5把地址送AR、T6写存储器。条件转移指令更特殊JZ需要先判断标志才能决定是跳转还是顺序执行。状态图画清楚后微程序流程就已经完成了一半剩下的工作只是把状态翻译成微指令字。3.3 第三步列控制信号表并分配微指令位画完状态图你需要把模型机里所有控制信号列成一个清单然后给每个信号分配一个微指令位。这个步骤虽然机械但非常关键因为遗漏一个控制信号就可能导致某个部件在某个周期没有被正确驱动。我常用的控制信号清单大致长这样只列一部分信号名含义所在部件PCoutPC内容输出到总线PCPCin总线数据写入PCPCPC1PC自增PCARin总线数据写入ARARIRin总线数据写入IRIRRAM_rd存储器读RAMRAM_wr存储器写RAMR0out / R0in寄存器R0输出/写入寄存器组R1out / R1in寄存器R1输出/写入寄存器组ACout / ACin累加器输出/写入ACDRin总线数据写入DRDRALU_addALU选择加法ALUALU_subALU选择减法ALUALU_andALU选择与运算ALUALU_orALU选择或运算ALU结果送ACALU结果写入ACALU/AC标志更新更新Z、C标志状态寄存器全部列完大概有二十多个信号。模型机控制信号表做完再结合代码里实际的信号命名微指令编码表就呼之欲出。我特别提醒一点单总线结构下同一条总线上绝对不能同时出现两个输出使能信号。你要在编码表里反复检查每一行微指令中PCout、R0out、R1out、ACout、存储器读使能这几类“总线输出”信号只能有一个等于1。3.4 第四步用Verilog搭建模型机骨架代码实现方面我不建议把整个模型机写在一个模块里而是按数据通路的逻辑拆分成几个小模块这样仿真调试时能精确定位问题。核心模块划分如下pc.v程序计数器支持PCout、PCin、PC1三种操作ar.v地址寄存器支持ARin、ARoutir.v指令寄存器支持IRin输出OpCode到译码逻辑ram.v存储器支持读、写容量256×16位regfile.v通用寄存器组至少两个寄存器R0、R1支持读写alu.v组合逻辑ALU支持加、减、与、或输出结果和Z、C标志ac.v累加寄存器支持ACout、ACinmicro_controller.v微程序控制器包含控存CM、微地址寄存器μPC、译码逻辑和状态输出。微程序控制器是核心它的实现思路可以概括为用一个二维数组存储微指令编码每个地址对应一条微指令微地址寄存器μPC在时钟上升沿更新更新的来源有两种一是顺序自增μPC1二是跳转地址来自下地址字段或操作码映射组合逻辑把微指令编码对应的位输出到各个控制信号线上。下面给一个极简的控制器框架参考模型机控制器Verilog代码片段仅用于示意信号关系module micro_controller( input clk, input rst, input zero_flag, input [3:0] opcode, output reg pc_out, pc_in, pc_inc, output reg ar_in, ir_in, output reg ram_rd, ram_wr, output reg r0_out, r0_in, r1_out, r1_in, output reg ac_out, ac_in, output reg dr_in, output reg alu_add, alu_sub, alu_and, alu_or ); // 微指令编码格式, 这里用参数对应每一位 parameter CM_SIZE 64; parameter CM_WIDTH 24; // 具体位数根据控制信号数目调整 reg [CM_WIDTH-1:0] cm_memory [0:CM_SIZE-1]; reg [5:0] micro_pc; // 微指令位域定义 localparam PC_OUT_BIT 0; localparam PC_IN_BIT 1; localparam PC_INC_BIT 2; // ... 其他位按顺序对应 // 组合逻辑输出控制信号 always (*) begin pc_out cm_memory[micro_pc][PC_OUT_BIT]; pc_in cm_memory[micro_pc][PC_IN_BIT]; pc_inc cm_memory[micro_pc][PC_INC_BIT]; // ... 其余信号依次赋值 end always (posedge clk or posedge rst) begin if (rst) begin micro_pc 0; end else begin // 根据判别字段确定下一条微指令地址 // 若当前微指令是取指结束则根据opcode映射到对应指令的微程序入口 // 否则优先用下地址字段跳转默认顺序自增 end end // 初始化控存, 实际工程中可以用$readmemb从文件加载 initial begin // 这里填入每条微指令的二进制编码 end endmodule先别急着把所有微指令都写完先把控存的尺寸和位宽定义好然后写一条最简单的HALT指令的微程序把整个链路取指、译码、执行、停机跑通再逐步填充其他指令。3.5 第五步微程序初始化与加载方式控存CM的初始化有几种常见方式教材上会提到硬布线初始化、加载器等方案但在FPGA课程设计里我们通常直接在RTL代码里用内存初始化文件加载。我推荐用$readmemb命令比如在仿真目录下准备一个micro_code.hex文件用二进制或十六进制每行存储一条微指令编码。这样改微指令时不需要重新综合只需要改文本文件再跑仿真效率非常高。需要注意$readmemb只能用于仿真和SRAM初始化场景在FPGA上板时你需要确保综合工具支持这种初始化方式或者直接使用initial块往cm_memory里填数据这对课程设计来说通常是最省事的。3.6 第六步指令模拟与仿真验证仿真工具我推荐用Vivado自带的仿真器或者ModelSim/Questa都行。关键是你要设计一套完整的测试程序覆盖每一条指令的正常路径和关键边界条件。我常用的测试程序策略包括写一段简单的汇编级测试程序比如把R0初始化为5、R1初始化为3执行ADD期望R08执行SUB期望R02用AND和OR验证逻辑运算LOAD和STORE配合验证存储器读写JMP配合循环验证无条件跳转JZ配合减法结果为0的情况验证条件跳转。仿真时务必观察这些关键信号clk、rst、micro_pc、IR的值、AC的值、R0/R1的值、RAM写入内容、以及各控制信号有没有在同一周期出现两个总线输出同时有效的现象。如果发现AC值异常第一时间回看ALU两个输入是否都已就绪如果RAM写入内容不对回看AR是否捕获了正确的地址如果JZ总是不跳转回看Z标志更新得早不早。3.7 第七步上板验证与扩展如果你的课程设计要求在FPGA开发板上跑通仿真通过后还需要做上板验证。模型机的输入用拨码开关或按键控制输出用数码管或LED显示寄存器值和存储器状态然后再逐条指令单步执行或者连续执行。我建议先设计一个“单步模式”每次按键触发一个时钟上升沿你可以看到LED上显示micro_pc的变化和IR的内容这既是很好的演示效果也方便调试。连续运行模式可以让模型机自动执行一段小程序比如从1加到10然后把结果在数码管上显示出来。如果要更炫一点可以加上指令计数器在数码管上显示当前已经执行了多少条机器指令答辩时的展示效果会非常加分。4. 常见问题与排查技巧实录4.1 问题速查表课设中最容易踩的坑我把这几年学生做这个课程设计时反馈最多的问题整理成了一个速查表这些问题几乎占到全部问题的八成以上。现象可能原因解决思路仿真中总线上出现多个数据源同时输出某条微指令中两个“总线输出”使能信号同时为1逐条检查微指令编码每行只能有一个总线输出有效AC的值总是不对或者滞后一个周期AC写入使能持续多个周期或ALU结果未稳定就写入保证ACin只在一个周期有效且该周期ALU两个输入已稳定RAM读出来永远是未知态RAM初始化文件缺失或读使能时序不对给RAM赋初始值检查RAM_rd信号的建立时间程序运行后PC不递增取指阶段的PC1信号缺少或PC自增与PC写入冲突单独设置PC1控制信号不与PCin混用JZ指令条件判断错误Z标志更新晚于判断周期或Z标志被后续指令覆盖在微指令中安排标志更新的周期并确认判断时标志有效控存CM中数据无法初始化使用的是Block RAM但初始化方式不对改用initial块赋值或者用寄存器数组综合报错“multi-driven net”多个always块对同一信号赋值统一在控制器模块中生成控制信号不要到处驱动4.2 调试心得看懂波形比改代码更重要模型机调试和普通软件开发差别很大。普通程序报错会告诉你哪一行有问题但硬件仿真看到的是一堆控制信号和总线波形的交叠。有时候AC值变成0不是AC模块本身的问题而是DR在前一个周期没有捕获到正确的总线数据。所以我调试时有个习惯遇到问题时先冻结时间把该周期内所有控制信号列出来逐一验证它们和微指令编码是否完全对应。我经常用的另一个技巧是“信号分层观察”先观察控制信号是否正确比如ACout是否为1、DRin是否为1再观察数据通路上的值是否沿着预期路径走比如总线上是否有预期的16位值最后才是看结果寄存器AC、R0对不对。按照“控制信号→数据通路→最终结果”的顺序定位大多数问题都能快速锁定。4.3 增加一条指令到底要改哪些地方答辩时老师大概率会问“如果我要你增加一条XOR指令你应该改哪些地方”这个问题我建议你提前准备好答案不要到现场现想。完整的改动清单如下第一步在指令系统定义中增加XOR分配操作码编码比如1010第二步在IR操作码译码逻辑中增加对应的微程序入口地址分支第三步在控存中增加XOR的微程序序列一般包括把R1送DR、AC与DR做异或、结果写回AC这么几条微指令第四步在ALU模块中增加异或运算功能并分配一个微指令位给ALU_xor信号。这四步缺一不可。我见过不少学生在ALU里已经写了异或逻辑但忘记在控制器里加微指令结果新指令无效也见过学生加了微指令但没改ALU逻辑结果执行出来的结果是错的。这两个问题的组合基本上能全面考查学生对微程序控制模型机的理解程度。你要是能把这个回答清楚老师就知道你是真的做通了不是抄代码抄出来的。4.4 千万别忽视的端口时序细节还有一个很隐蔽的坑寄存器的时钟使能。FPGA上的寄存器一般都有时钟使能端CE你可以用它来控制寄存器的写入。但如果你在always块里用“if (xx_in) q d;”这样的方式来实现写入控制在描述行为层面是可以的但要注意综合后的结果。只要xx_in为高每个时钟上升沿都会写入。这本没有错但如果你希望在某些周期让寄存器保持原值就必须保证xx_in为低。所以编写微指令编码表时凡是“某个周期内某个寄存器不应被写入”要仔细核查对应的in信号确实为0。另一个值得强调的细节是初始化与复位。模型机中的PC、AR、IR、μPC、AC以及通用寄存器在上电或复位后都应该有确定的初始值。如果漏掉复位逻辑仿真一开始所有信号都是不定态X后面即便控制信号正确也很难排查因为不定态会像病毒一样传播到所有相关寄存器里。建议在编写每个模块时都加上异步复位或同步复位复位时把关键寄存器清零这样仿真一开始就能站在一个明确的起点上。5. 模型机的测试程序与边界条件设计5.1 测试程序到底应该怎么写很多同学的测试程序只有一条ADD、一条STORE仿真通过就认为大功告成。但课程设计的验收标准远比这严格一份好的测试程序要能覆盖所有指令的典型路径和边界路径。我推荐一个三级测试方案。第一级是单指令测试每一条指令单独运行初始条件设成最容易被验证的值比如用53验证ADD用5-3验证SUB。这个级别的目标是确认每条指令的微程序本身没有问题。第二级是组合指令测试把多条指令串成一个简单程序例如计算一个数组的和、找出最大值、实现一个循环。这个级别能暴露指令切换时的衔接问题特别是取指阶段是否在每条指令之间都正确执行。第三级是边界条件测试比如ALU加法溢出时C标志是否正确、相减结果为0时Z标志是否置位、JZ在标志位为0和为1两种情况下是否正确选择路径、存储器的最后一个地址单元能否正常读写。这些边界情况往往是老师重点关注的地方。5.2 手动汇编从汇编指令到机器码课程设计一般不需要完整的汇编器手写几条测试程序的机器码完全够了。但要注意手写机器码非常容易出错所以我有个笨办法先以助记符形式写测试程序比如MOV R0, R1 ADD R0, R1 STORE R0, [0x10] JZ 0x00 HALT然后逐行翻译成16进制指令字并填入RAM初始化文件。翻译时不要跳步写注释标明每条机器对应的助记符这样调试时回头对波形会省很多时间。如果你写的是双字指令比如LOAD、STORE、JMP后面跟一个地址RAM初始化文件里的指令字和地址字要严格按顺序排列不能错位。我在课设中见过最典型的低级错误就是RAM里指令和地址的顺序写反结果程序跑飞。5.3 用“单步模式”演示给老师看如果你的课程设计需要答辩演示我强烈建议你在开发板上实现一个“单步执行”功能。把时钟信号接在一个按键上每按一次按键CPU执行一个时钟周期。配合数码管显示micro_pc、IR、AC的值你可以清晰地展示每一条指令的完整生命周期取指、译码、执行、结果写回。这种演示方式有两个好处一是直观展示了你对微程序控制原理深入理解的程度二是让答辩老师一眼就能看出模型的运行状态是否正常不用靠猜。连续运行模式倒是可以放在单步演示之后比如展示一段循环程序在LED上闪烁或者用数码管动态显示一个累加结果。这样既有细节又有整体效果比单纯展示仿真波形要有说服力得多。6. 写在最后的小经验最终交付时建议你把所有代码、微指令表、仿真波形截图、测试程序、设计文档打包整理好尤其是那份微指令编码表它就是你整个模型的“灵魂”。答辩时老师问到任何一条指令的执行过程你都能指到编码表里对应的那几行微指令说清楚这比任何口头解释都有说服力。如果你时间允许还可以准备一个简短的录屏把你用单步模式演示完整程序执行过程的内容录下来。文件不大但演示时非常省事也免得现场操作万一芯片状态不对导致手忙脚乱。我在做这个课程设计时印象最深的一次调试是JZ指令始终跳不过去后来发现是Z标志在微程序的ADD执行周期里就更新了但在JZ判断周期前又被某条控制信号的干扰覆盖了。最后把标志更新信号单独连线、禁止无关写入问题立刻消失。这类问题在课本上根本不会提只有真正搭过模型机的人才会有体感。希望这篇内容能帮你绕开这些坑踏踏实实把一台属于你自己的模型机跑起来。
返回列表