简介:这是配合龙芯教学实验箱的CPU设计与体系结构实验指导手册(教师版),面向高校计算机专业学生和任课教师,用于数字逻辑、计算机组成原理、计算机体系结构等课程实验教学。手册分为CPU设计与CPU优化两大部分,按难度递进安排实验,包括定点加法、定点乘法、寄存器堆、ALU、存储器实现,进而到单周期CPU、多周期CPU及静态5级流水线CPU设计与系统优化,并附有实现的MIPS指令集和CP0寄存器定义。资源为单个PDF文件,大小6.09MB,已有680人学习下载。内容不仅给出各实验目的、设备要求、任务步骤和Verilog设计流程,还结合FPGA平台讲解电路搭建与信号观察方法,教师可以直接用于备课指导,学生能够逐步构建从基本运算单元到完整CPU的系统,深入理解数据通路、控制逻辑和流水线优化。附录中的指令集与寄存器清单方便实验时随时查阅和验证。
1. 先搞清楚这份手册到底帮你解决什么问题
第一次带《计算机组成原理》实验课的老师,最头疼的不是准备PPT,而是怎么让学生在有限课时里亲手把一颗CPU“点亮”。这份实验指导手册解决的就是从零到一的问题:它以 LS-CPU-EXB-002 实验箱为载体,把定点加法、定点乘法、寄存器堆、ALU、存储器、单周期 CPU、多周期 CPU、静态 5 级流水线串成一条可动手复现的路线。资源文件名里的 EXB-003 只是版本批次,实际平台和实验内容以手册正文为准。适合两类人:要组织 FPGA 实验课的老师,以及想把“CPU 工作原理”从概念黑匣子变成自己 Verilog 代码的本科生。你不需要先学完体系结构再动手,跟着实验一往下做就行。
2. 硬件与软件栈:LS-CPU-EXB-002 实验箱和 Vivado 整体流程
2.1 实验箱硬件组成与你要关注的接口
手册一开篇就把实验箱的配套资源列清楚了:FPGA 实验板、Xilinx 下载线、串口线(含 USB 串口转换器)、电源线(含适配器)。真正需要你上心的是 FPGA 板上的器件型号。新建 Vivado 工程时,器件筛选要在 family 选 Artix 7,package 选 fbg676,最后落到xc7a200tfbg676-2上。这个型号在整本手册里是统一的,单周期 CPU、多周期 CPU、流水线 CPU 都要用它做综合布局布线,选错封装后面引脚约束文件直接失效。
实验箱最有特色的部分是 LCD 触摸屏。按手册里的说法,硬件驱动已经做进了板子,不需要处理器核参与,触摸屏就能独立完成显示和输入功能,并且对外提供了“简单清晰的调用接口”。这意味着你在做实验一“定点加法”时,不需要自己写 VGA 驱动或者串口屏协议,只要调封装好的模块就能把两个加数显示在屏幕上,再用触摸功能输入数据。手册里这个设计意图很明确:让学生的注意力集中在 CPU 模块本身,而不是被外设驱动带偏。后续六个实验的上板验证环节,几乎都靠这块触摸屏撑场面。
实验内容安排的层次也很清楚,手册把它分成 CPU 设计和 CPU 优化两部分。前者面向组成原理课程,从实验一到实验七,最后接一个课程设计;后者面向体系结构课程,对应课程设计和课程设计拓展。具体清单如下。
| 编号 | 实验内容 | 一句话定位 | 上板验证方式 |
|---|---|---|---|
| 实验一 | 数据运算:定点加法 | 熟悉平台、仿真、上板的最小闭环 | LCD 触摸屏输入/显示 |
| 实验二 | 数据运算:定点乘法 | 从组合逻辑向时序逻辑过渡 | LCD 触摸屏输入/显示 |
| 实验三 | 寄存器堆实现 | 为 CPU 准备通用寄存器组 | 触摸屏读寄存器值 |
| 实验四 | ALU 模块实现 | 实现算术逻辑运算核心 | 触摸屏显示运算结果 |
| 实验五 | 存储器实现 | 用 FPGA 内部 BRAM 搭存储模型 | 触摸屏写读数据 |
| 实验六 | 单周期 CPU 实现 | 一条指令在一个周期内跑完 | 板上运行程序并显示 |
| 实验七 | 多周期 CPU 实现 | 用状态机拆分指令执行步骤 | 板上运行程序并显示 |
| 课程设计 | 静态 5 级流水线 CPU | 接触数据冒险与控制冒险 | 板上跑指令序列 |
| 拓展 | 优化 CPU 系统 | 转发、调度、异常处理 | 综合报告与上板验证 |
从这张表能看出,它不是零散的小实验,而是一条从单元电路到完整处理器的递进路线。后面每个实验都是在前面模块的基础上组装。
2.2 从新建工程到上板:一套贯穿所有实验的 Vivado 流程
手册里每个实验的操作步骤几乎都复用同一套流程,我把它拆成六步。第一步是新建工程:打开 Vivado,File → New Project,工程类型选 RTL Project,勾选 “Do not specify sources at this time”,先建一个空工程。第二步添加设计源文件,可以直接在工程里新建.v文件,也可以把外部编辑器写好的文件通过 Add Sources 加进来。第三步是添加外围展示模块和 LCD 模块,也就是把lcd_module的网表文件加进工程。第四步写 testbench,做行为仿真,确认功能正确。第五步添加.xdc引脚约束文件。第六步综合、布局布线、生成比特流,下载到实验箱上验证。
这套流程在实验一里被讲得最细,因为后续实验只是换不同的module实现,外围结构基本不变。有个细节容易忽略:Vivado 工程管理器里如果某个模块前面带了问号,说明这个源文件还没添加。手册里lcd_module是以.dcp格式提供的网表文件,不是.v源码,目的就是不让学生看到 LCD 驱动内部实现。另外手册特意提了一句,某些版本的 Vivado 需要先把 dcp 文件解压再添加,不然工程识别不到。我按这个提示操作,综合阶段确实没有再报黑盒错误。
2.3 顶层模块怎么组织:以 adder_display 为模板
实验一给出的顶层结构是整个系列实验的标准模板。顶层模块叫adder_display,里面调用两个子模块:一个是功能主体adder,另一个是外围展示模块lcd_module。这种“功能模块 + 展示模块”的剥离方式值得你留意。功能模块只关心输入输出信号,完全不碰引脚;展示模块负责把信号映射到屏幕或按键上;引脚绑定只出现在顶层模块的.xdc约束里。三层各干各的事。
手册在实验一里花了大量篇幅讲adder_display,意思是以后所有实验的外围模块都可以照这个写法改。你在做实验三寄存器堆的时候,只需要把顶层显示模块里的adder换成regfile,再把显示数据换成读端口输出,其他结构不用动。这也解释了为什么实验一到实验七的工程搭建过程几乎一样——它们共用同一套显示框架,你只需要替换核心计算模块。理解了这个套路,后面三次上板实验你在工程配置上基本不会卡壳。
3. 基础模块实验拆解:从定点加法到存储器
3.1 实验一:定点加法,最小的完整 Verilog 工程
实验一的参考实现非常短,adder.v里就一个模块,核心代码只有一行 assign。它直接用了 Verilog 的+运算符,而不是自己搭全加器。这样写的好处是,综合工具会自动调用库里的加法器 IP,面积和时序往往比手搭的加法器更优。
`timescale 1ns / 1ps // 文件名: adder.v // 描述:加法器,直接使用"+",会自动调用库里的加法器 module adder( input [31:0] operand1, input [31:0] operand2, input cin, output [31:0] result, output cout ); assign {cout, result} = operand1 + operand2 + cin; endmoduleassign后面把cout和result拼成一个 33 位的数,低 32 位是加法结果,最高位是进位输出。这是处理“加法结果进位”最直接的写法,也符合教学里对全加器演进的预期。如果你拿到的是实验箱配的教师版手册,会发现作者在这里特意做了注释,说明这是参考设计,教师可以要求学员自己搭全加器,也可以直接用+,两种方案都能完成实验。
仿真部分,手册给的testbench.v很考验功底,因为它用$random自动生成了随机激励,而不是手动写死几组测试数。代码里一共有三行关键赋值,分别作用于两个 32 位加数和进位输入。
`timescale 1ns / 1ps module testbench; reg [31:0] operand1; reg [31:0] operand2; reg cin; wire [31:0] result; wire cout; adder uut( .operand1(operand1), .operand2(operand2), .cin(cin), .result(result), .cout(cout) ); initial begin operand1 = 0; operand2 = 0; cin = 0; #100; end always #10 operand1 = $random; always #10 operand2 = $random; always #10 cin = {$random} % 2; endmodule这里有一个常见的理解偏差:$random返回的是有符号数,直接赋给 32 位寄存器没问题,但如果用在取模上,负数取模可能得到负值。手册里对cin的赋值用了拼接符{$random},把它变成非负数再取模,这样只有 0 或 1 两种结果。第 29 到 31 行的三个always块每 10ns 触发一次,相当于每 10ns 换一组新的随机输入。仿真跑起来后,你在波形窗口里看到的不是固定波形,而是持续跳变的随机激励,这比手写几十组测试向量省事得多。
仿真时的操作细节手册也写得很具体:在 Scopes 窗口选中adder对应的源文件对象,在 Objects 窗口左键选中要观察的信号,右键 Add To Wave Window 添加信号。如果添加之后波形窗口没有更新,需要点 Relaunch 重新载入仿真。还有就是波形默认显示二进制,一个 32 位数看起来像一长串 0 和 1,检查起来太费眼睛。选中信号右键,Radix 改成 Hexadecimal,显示就清爽了。这套操作习惯会延续到实验六、实验七,越早熟悉越好。
3.2 实验二:定点乘法,开始挑战时序
实验二的主题从加法跳到乘法,难度明显上一个台阶。如果是两个 32 位数相乘,结果位宽扩展到 64 位,不能像加法那样一条 assign 就完事。手册在这里没有继续给完整代码,而是留了方案选择的余地:你可以自己用移位累加实现乘法器,也可以继续用*运算符由工具推导出乘法器模块。但从实验目的出发,自己实现乘法器才是理解“部分积”和“移位累加”的关键。
我拆这类实验时一般会建议学生先做一个 8 位乘 8 位的乘法器练手,跑通之后扩到 32 位。如果用*直接做 32 位乘法,综合工具会映射到 FPGA 里的 DSP 硬核,面积和时序都好看,适合赶进度;如果自己搭阵列乘法器,代码量会明显增加,但你会真正理解为什么乘法比加法慢,以及多周期 CPU 里为什么要把乘法单独拆出去。
这个实验还有一个容易被忽略的点:上板显示 64 位结果时,触摸屏一次显示不完,通常要分高 32 位和低 32 位两次显示,或者做一个“切换显示高低位”的按键逻辑。这属于外围展示模块的设计范畴,也是实验二和实验一在工程搭建上为数不多的区别。
3.3 实验三与实验四:寄存器堆和 ALU
寄存器堆是所有后续 CPU 实验的地基。手册实验三要求你实现一组通用寄存器,从规格上看,它对应的是 MIPS 32 个 32 位寄存器。单周期 CPU 里指令译码阶段需要同时读两个源操作数,写回阶段要写一个目标寄存器,所以寄存器堆最少要提供两个读端口和一个写端口。常见写法是这样的:
// 寄存器堆常见写法:写端口用时钟沿触发,读端口用组合逻辑 module regfile( input wire clk, input wire we, input wire [4:0] raddr1, input wire [4:0] raddr2, input wire [4:0] waddr, input wire [31:0] wdata, output wire [31:0] rdata1, output wire [31:0] rdata2 ); reg [31:0] regs [0:31]; integer i; initial begin for (i = 0; i < 32; i = i + 1) regs[i] = 32'b0; end always @(posedge clk) begin if (we && waddr != 5'b0) regs[waddr] <= wdata; // MIPS 的 $0 寄存器恒为 0 end assign rdata1 = regs[raddr1]; assign rdata2 = regs[raddr2]; endmodule这段代码里有三个关键点。第一,regs [0:31]是一个长度为 32、位宽 32 的二维数组,在 FPGA 里会被综合成一块分布式的寄存器阵列。第二,写端口是时序逻辑,只在时钟上升沿写入,读端口则是纯组合逻辑,地址一变输出立刻跟着变,这和单周期 CPU 对数据通路的要求一致。第三,MIPS 约定$0寄存器永远读出来是 0,所以写地址为 0 时要屏蔽写入,否则程序里对$0的误写会污染整个系统。你以后写单周期 CPU 的译码逻辑时,很多控制信号都依赖这两个读端口的稳定性。
实验四的 ALU 模块就是在寄存器堆外面包一层运算逻辑。按手册里的定位,ALU 要覆盖算术和逻辑两类操作,常见接口是这样设计的:
| 端口 | 方向 | 位宽 | 说明 |
|---|---|---|---|
| A | input | 32 | 源操作数 1 |
| B | input | 32 | 源操作数 2 |
| ALUOp | input | 4 | 运算控制码 |
| Result | output | 32 | 运算结果 |
| Zero | output | 1 | 结果为 0 标志,分支指令用 |
ALU 实现本身不复杂,核心是一个case语句按ALUOp选择加法、减法、与、或、异或、左移、右移、比较等操作。但是实验四真正的坑在于Zero信号:它必须在所有运算结束后根据整个 32 位结果判断是否全 0,如果你的 ALU 用case输出Result,Zero得用独立的assign判断,不能只在一个分支里赋值,否则综合时容易产生锁存器。
3.4 实验五:存储器实现
存储器和寄存器堆虽然都是“存东西”,但实现原理完全不同。寄存器堆用触发器阵列,读写灵活;存储器要模拟存储器模型,面向的是 FPGA 内部的 BRAM 资源。手册实验五要你实现一个可供 CPU 使用的存储模块,关键参数是数据位宽和地址位宽。这里需要区分两个概念:指令存储器和数据存储器。
在一个单周期 CPU 里,指令存储器和数据存储器通常是分开的。指令存储器只读,地址从 PC 来,输出直接进译码器;数据存储器可读可写,地址来自 ALU 的计算结果,写入数据来自寄存器堆的第二个读端口。实验五在做上板验证时,常见做法是把存储器里的若干地址映射到触摸屏上显示,通过触摸输入地址和数据,再读出来核对。这样你既验证了存储器的读写时序,也顺便验证了地址译码逻辑。
手册在实验五里特意强调要“掌握利用显示屏观察特定信号的方法”。这和我平时调试存储器的习惯是一致的:仿真波形只能证明你的电路在理想激励下是对的,上板后真正会用这块存储器的场景是运行指令序列,所以存储器实验的一个重要目标是让你建立“地址、数据、读写使能、时钟”四要素的时序直觉。后面单周期 CPU 里一旦跑不出预期结果,九成问题都出在存储器读写时序上,早早在实验五里把这种感觉建立起来,后面能少调很多 bug。
4. CPU 实现实验拆解:单周期、多周期与静态 5 级流水线
4.1 实验六:单周期 CPU,一条指令在一个周期内跑完
单周期 CPU 是整本手册从“模块”迈向“系统”的分界点。它的核心特征是:一条指令从取指到写回,所有操作都在一个时钟周期内完成,没有中间状态。你不需要设计状态机,只需要把取指、译码、执行、访存、写回五条数据通路全部用组合逻辑串起来,最终在一个时钟沿之间完成全部动作。代价是时钟频率上不去,因为单个周期的时间要由最慢的指令决定,典型的就是lw(从存储器读数据到寄存器)。
手册在附录 A1 里给出了单周期 CPU 必须实现的指令集。从教学顺序判断,这个集合覆盖了 MIPS 的基础指令类型:寄存器和立即数的算术逻辑运算、访存、分支、跳转。附录 A1 的作用不是摆设,它是你设计控制信号真值表的依据。你每加一条指令,就要在译码逻辑里新增一个case分支,明确这条指令要打开哪些控制信号:寄存器写使能、存储器写使能、ALUSrc、RegDst、Branch、Jump。我在设计单周期 CPU 时习惯把所有指令的控制信号列成一张真值表,再对着真值表写 Verilog,这样比边写边想少出错。
单周期 CPU 的 Verilog 结构一般是“顶层 CPU 模块 + 若干功能子模块”的组合。顶层模块里实例化 PC、指令存储器、寄存器堆、ALU、数据存储器、立即数扩展单元,并用一批控制信号把它们连接起来。手册里特别提到,这一章的.v文件数量会明显增加,形成一定的调用层次,这也是它和前几章实验最大的不同。你在工程管理区看到的层次关系,基本就是一张 CPU 结构框图。
仿真阶段,单周期 CPU 的 testbench 需要构造一段真实的指令序列,而不是随机激励。最简单的做法是在指令存储器初始化文件里预置一小段程序,比如用addi给两个寄存器赋值,再用add相加写回第三个寄存器,最后用beq判断跳转。通过观察 PC 的变化和寄存器堆的写回值,验证每一条指令是否按预期执行。这一步能跑通,单周期 CPU 的主体功能就算成立。
4.2 实验七:多周期 CPU,用状态机切分指令
多周期 CPU 改变的是整个数据通路的组织方式:指令执行被拆成若干步,每一步占一个时钟周期,用状态机控制当前执行到哪一步。手册实验七的关键词是“将不同的操作分配到不同的时钟周期,以提高效率”。和单周期相比,多周期 CPU 可以把一条指令拆成取指、译码、执行、访存、写回五个阶段,硬件上可以复用 ALU 和存储器,单周期里需要两份存储器的问题在这里也得到了缓解。
状态机的设计是多周期 CPU 实验的核心。常见做法是用S0到S8这样的状态编码,每个状态完成一个固定的微操作。以lw指令为例,它至少要经历四个状态:取指、读寄存器堆算地址、访问存储器、写回寄存器堆。每种指令在状态机里走的路径不一样,译码逻辑需要根据指令类型决定下一个状态跳转到哪里。附录 A2 里列的是多周期 CPU 新增支持的指令,相比单周期版本多出来的部分主要是对复杂指令的拆解支持。
我在做多周期 CPU 时有一个习惯:先把所有指令的执行步骤画成状态转移图,标清楚每个状态里要拉高的控制信号,再写状态机代码。如果跳过画图直接写case,很容易在状态跳转上翻车。多周期 CPU 的另一个考验是上板调试:状态机跑得快,你肉眼根本看不清楚到底停在哪一步,所以一般会在顶层模块里加一个状态显示逻辑,把当前状态编码送到触摸屏或 LED 上,这样出问题时能直接看到卡在哪个状态。
4.3 课程设计:静态 5 级流水线 CPU 与 CP0 寄存器
课程设计部分直接跨到静态 5 级流水线,这是整本手册里技术密度最高的一章。流水线把指令执行拆成五个阶段:取指 IF、译码 ID、执行 EX、访存 MEM、写回 WB,每两个阶段之间由流水线寄存器隔开,多个指令可以在不同阶段同时执行。理论上,每条指令仍然要经历五个阶段,但因为各个阶段重叠执行,CPU 的吞吐率大幅提升。
但流水线的代价是逻辑复杂度。你需要处理两类冒险:数据冒险和分支冒险。数据冒险典型场景是一条add后面紧跟着一条使用该结果的sub,第二条指令在 ID 阶段读寄存器时,第一条指令还没到 WB 阶段,读到的就是旧值。静态 5 级流水线不做乱序执行,解决思路要么是插入停顿气泡,要么是新增一条转发通路。转发单元需要比较两条指令之间的寄存器地址,把 EX 阶段的结果直接旁路给后面的指令,这要求你能熟练操作流水线寄存器里的字段。
分支冒险更麻烦。beq指令要等到 EX 阶段才能算出跳转方向,但下一条指令已经在 IF 阶段被取进来了,怎么处理取决于你的流水线实现。常见做法是默认不跳转,一旦发现分支条件成立就把后面已经取入的指令全部作废,代价是每遇到一条分支指令就要浪费一个周期。手册里要求你实现的是“静态”5 级流水线,意味着没有动态调度,硬件只负责按固定顺序执行,指令之间的冲突要靠编译器或者程序员提前排好。附录 A3 列出了流水线版本新增支持的指令,附录 B 则给出了实现的 CP0 寄存器。
CP0 寄存器是 MIPS 处理器里负责异常和中断处理的特殊寄存器,包含状态寄存器、原因寄存器、EPC 等。在流水线 CPU 里,你要处理异常发生的时机和恢复现场的逻辑:异常发生后,处理器要记录当前指令地址到 EPC,跳转到异常处理入口,并在处理结束后返回。手册附录 B 列出的 CP0 寄存器是实现这个流程的关键。课程设计拓展“优化 CPU 系统”就是在 5 级流水线的基础上做改进,常见方向有增加指令转发、优化分支预测、添加中断支持。能把这部分做完,这门课的成绩基本就是一档了。
5. 常见问题与避坑记录:手册流程里容易翻车的五个点
5.1 testbench 没有设为顶层,仿真一片空白
现象:添加了 testbench.v 后运行行为仿真,波形窗口空白,Vivado 没有把 testbench 识别为仿真顶层。原因:工程里同时存在多个顶层候选文件时,Vivado 默认选择的是你最早添加到工程里的设计文件,而不是 testbench。解决:在 Sources 面板里右键 testbench.v,选择 Set as Top,再重新运行仿真。这个操作在每次新建仿真工程时都应该养成习惯。
5.2 新加的信号在波形窗口里怎么都看不到
现象:你在 Objects 窗口选中信号并 Add To Wave Window,波形窗口里却没有出现对应数据。原因:Vivado 在仿真运行期间添加的观察信号不会自动刷新到当前波形视图,需要重新载入仿真才能生效。解决:添加完所有要观察的信号后,点工具栏的 Relaunch 重新启动仿真,新信号的数据就出来了。我在这上面浪费过半小时,后来直接固定操作顺序:先添加全部信号,再 Relaunch。
5.3 lcd_module 模块带问号,综合报 No such module
现象:工程管理区里 lcd_module 前面有个问号,综合时报找不到模块。原因:lcd_module是以.dcp网表文件提供的黑盒模块,你没有把 dcp 文件添加到工程里,或者你用的 Vivado 版本比较老,需要先解压 dcp 文件再添加。解决:在 Add Sources 里选择 Add or create design sources,找到配套的lcd_module.dcp,添加成功后问号消失。注意 dcp 文件不需要也不能当普通 Verilog 源文件打开。
5.4 32 位数据用二进制显示,眼睛直接看花
现象:仿真波形里一长串 0 和 1,你根本分不清 result 到底是哪个值。原因:Vivado 默认以二进制格式显示所有波形信号。解决:在波形窗口的 Name 列选中信号,右键选择 Radix,改成 Hexadecimal,或者对无符号数据选 Unsigned Decimal。这个设置对单个信号独立生效,不会影响其他信号。我在检查 32 位加法结果时基本都是十六进制显示,只有看单比特控制信号时才切回二进制。
5.5 手册里的手算示例和仿真波形对不上
现象:手册实验一给了一组手算检验数据,声称b897be71 + 42f24186 + 1 = fb89fff7,但你的仿真波形结果却是fb89fff8,进位输出也不一致。原因:这是一个典型的文档笔误。按二进制加法逐字节计算,b897be71 + 42f24186本身已经是fb89fff7,再加上低位进位cin=1,结果应该是fb89fff8。手册里很可能是在写示例时把“加数和被加数的和”误写成了“包含进位后的最终结果”。解决:遇到仿真结果和文档示例不一致,不要先怀疑自己的代码,先用 Python、Windows 计算器或者手算把期望值算清楚,再去对照波形。这不是个别情况,改动频率越高的大型实验,参考文档里越是容易出现这种手算错误。
6. 拿到手册之后怎么改成自己的实验:从换引脚到扩展指令集
这份手册虽然是教师版,但改造空间很大,你可以把它当一套“CPU 实验框架”来用。最常见的二次开发是换板子:你手上如果是一块其他型号的 Artix-7 开发板,顶层模块和 Verilog 代码基本不用动,只需要重写.xdc约束文件。把PACKAGE_PIN改成新板原理图对应的引脚,IOSTANDARD保持 LVCMOS33 不变,再核对一下时钟引脚和复位引脚的位置。注意.xdc里的clk、resetn、led_cout、sw_cin这些信号名字必须和顶层模块端口名完全一致,否则会报 constraint mismatch。
第二个改造点是把lcd_module这个黑盒换掉。如果你需要在自己的板子上跑这套实验,但手里没有配套的 LCD 网表文件,可以用 UART 串口模块代替触摸屏,把加法结果、寄存器值或 PC 值通过串口打印到上位机。实现思路是保留adder_display的顶层结构,把lcd_module实例换成uart_tx,再把显示数据的编码逻辑改成 16 进制 ASCII 输出。这样做虽然少了触摸交互,但调试信息更直观。
第三个改造方向是扩展指令集。单周期 CPU 附录 A1 只实现了基础指令集,你可以把slt、lui、jr这些指令补进去。以lui为例,你需要在译码模块里新增一个case分支,控制 ALUSrc、RegDst 和 Imm 扩展方式,同时把指令码的识别条件加到译码表里。每加一条指令,至少要同步修改三处:指令译码的控制信号、立即数扩展逻辑、数据通路里新增的连线。这个流程做过一次,你就明白为什么指令集是 CPU 设计里牵一发而动全身的部分。
如果是用这份手册组织自己的课程设计,我建议别让学生直接拿实验六的代码改流水线,而是让他们从实验一一路做下来,把每个模块的仿真波形单独截图留档。这样到最后做流水线课程设计时,手里的基础模块都是自己验证过的,调试时间能省下一大半。我个人的习惯是每完成一个实验就做一次工程备份,命名带版本号,因为 CPU 实验改到后期经常出现“上个版本还能跑,改完就不行了”的情况,有备份才有后悔药。希望这份手册的拆解对你有帮助,拿到资源后先照着实验一完整跑一遍流程,再决定从哪个实验开始二次开发。
本文还有配套的精品资源,点击获取