资讯动态

Logisim 32位MIPS单周期与多周期CPU设计实战

发布时间:2026/10/29 12:24:34 来源:尧图企业网站定制
简介这份华中科技大学《计算机组成原理》CPU设计实验报告面向正在学习MIPS处理器、准备课程实验或需要复盘Logisim实现的本科生与相关课程学习者。内容围绕32位MIPS单周期与多周期CPU展开涵盖8条核心指令、数据通路设计、硬布线控制器与微程序控制器、sort.hex冒泡排序测试、故障调试及性能分析并附实验总结与心得。资源包仅含1个docx文件约2.8MB正文按设计要求、方案设计、实验步骤、故障与调试、测试与分析、总结心得及参考文献组织配有数据通路示意与控制器封装说明便于快速定位关键图表和设计思路。该报告已有12128人学习下载适合对照实验流程、理解控制信号与数据通路细节也可作为撰写实验报告、梳理Logisim调试思路、准备课程设计答辩以及复习组成原理与后续硬件课程的重要参考。1. 从一条冒泡排序指令流反推 CPU 需求为什么选 Logisim 做 32 位 MIPS 单周期与多周期计算机组成原理的 CPU 设计实验最容易翻车的地方不是画不出数据通路而是先画图再补控制信号最后 sort.hex 一跑就飞。更稳的顺序是反着来先把冒泡排序的机器码拆开看它到底用了 add、slt、addi、lw、sw、beq、bne、syscall 这 8 条指令中的哪几条、访存地址怎么算、分支偏移落在哪再决定数据通路要留几个 MUX、控制器要输出哪些信号。这套方案面向需要交一份完整 CPU 设计实验报告的人单周期硬布线控制器、多周期微程序控制器与硬布线状态机都要能落地最终在 Logisim 里跑通 sort.hex 并拿到正确排序结果。选 Logisim 不是因为它简单而是它把门级电路、寄存器、存储器、分线器和探针都摆在明面上出错时能一眼看到是哪根线在“玄学”跳变。2. 指令集与总体架构8 条指令如何映射到数据通路资源2.1 8 条核心指令的语义与硬件代价先把 8 条指令写成硬件能读懂的话每条指令在哪个阶段读寄存器、哪个阶段用 ALU、哪个阶段访问存储器、哪个阶段写回。add 和 slt 是 R 型靠 funct 区分addi 是 I 型立即数运算lw 和 sw 要算地址再访存beq 和 bne 要比较两个寄存器并决定 PC 是否加偏移syscall 在这里只承担停机职责。溢出的处理也要在表里标出来add、addi 溢出时产生异常且不修改目标寄存器slt 是有符号比较lw/sw 的立即数要做 16 位到 32 位符号扩展。指令格式主要操作占用的硬件资源控制/异常点addRrd ← rs rtRegfile 双读、ALU 加法、写回溢出异常不写 rdsltRrd ← (rs rt)Regfile 双读、ALU 比较、写回有符号比较addiIrt ← rs SignExt(imm)Regfile 读、ALU 加法、写回溢出异常lwIrt ← Mem4B(rs SignExt(imm))ALU 算地址、DMEM 读、写回地址对齐、MemToRegswIMem4B(rs SignExt(imm)) ← rtALU 算地址、DMEM 写MemWrite 时序beqIif(rs rt) PC ← PC SignExt(imm2)Regfile 比较、PC 选择equal 信号、分支使能bneIif(rs ! rt) PC ← PC SignExt(imm2)Regfile 比较、PC 选择~equal 信号syscallR停机PC 使能端Halt 或状态自循环这张表不是抄指令手册而是后面画数据通路的“预算表”。比如 lw 和 sw 都需要 ALU 的第二输入来自符号扩展后的立即数所以 AluSrcB 这个控制信号必须存在beq 和 bne 都需要把 equal 信号从 ALU 引出来再和指令译码信号做逻辑组合syscall 在单周期里可以直接拉低 PC 使能在多周期里则让状态机停在某个状态两种做法对应两种停机思路。2.2 单周期与多周期的架构分界存储器复用与寄存器锁存单周期 CPU 的直觉是“一条指令一个时钟周期”所有功能部件在一个周期内各干各的指令存储器和数据存储器分开PC 每个时钟都更新。多周期 CPU 则把一条指令拆成取指、译码、执行等若干状态每个状态一个时钟周期指令和数据共用同一个存储器ALU 和存储器分时复用功能部件输出端增加寄存器锁存中间结果。这个分界决定了后面控制器的写法单周期控制器是纯组合逻辑输入 op/funct输出控制信号多周期控制器是时序逻辑现态加指令译码决定次态控制信号只与状态有关。对比项单周期 CPU多周期 CPU存储器指令存储器 IMEM 与数据存储器 DMEM 分开统一存储器取指与访存分时复用功能部件ALU、存储器基本专用ALU、存储器多周期复用中间寄存器少DR、IR、A、B、C 等锁存PC 更新每周期更新停机拉使能由状态和 PcWrite 控制控制器硬布线组合逻辑微程序控制器或硬布线状态机停机Halt 信号禁用 PC状态自循环或停在固定状态这张表最好在画图前就贴在草稿纸旁边。多周期里“为什么 ALU 的 B 端变成 4 路选择”这种问题答案就在“PC4、寄存器 B、符号扩展立即数、常数 4”这四个来源上单周期里“为什么 RegDst 只对 R 型有效”也来自“R 型写 rdI 型写 rt”这个差异。把差异先列清楚后面布线时就不会把两种 CPU 的线接串。2.3 控制信号的统一命名先把 9 个信号钉死再画图控制信号命名不统一是实验报告里最常见的“看起来都对、连起来就错”的来源。单周期里至少要把 MemToReg、MemWrite、Beq、Bne、AluOP、AluSrcB、RegWrite、RegDst、Halt 这 9 个信号钉死多周期还要增加 IorD、PcSrc、AluSrcA、IrWrite、PcWrite、MemRead 等。每个信号写清楚“什么时候为 1、接到哪个 MUX 的选择端、无效时默认值是什么”比后面对着图猜要省很多时间。# 解析 MIPS 32 位指令字段用于核对 sort.hex 中实际出现的指令 # 输入一行 8 位十六进制机器码输出op、rs、rt、rd、funct、imm def decode_mips(hex_word: str): word int(hex_word.strip(), 16) op (word 26) 0x3F rs (word 21) 0x1F rt (word 16) 0x1F rd (word 11) 0x1F funct word 0x3F imm word 0xFFFF # imm 按有符号 16 位解释便于检查分支和访存偏移 if imm 0x8000: imm_signed imm - 0x10000 else: imm_signed imm return {op: hex(op), rs: rs, rt: rt, rd: rd, funct: hex(funct), imm: imm_signed} for line in [012A4020, 21290001, 8D2A0004, AD2A0004, 112A0002, 152A0002]: print(line, decode_mips(line))这段脚本不依赖 Logisim作用是把 sort.hex 里出现的机器码逐条翻译成字段。op 为 0 时看 funct 区分 add 和 sltop 为 0x23、0x2b、0x04、0x05、0x08 时分别对应 lw、sw、beq、bne、addi。imm 按有符号解释很关键分支偏移和 lw/sw 的负偏移都靠它。实际调试时把 sort.hex 整个文件喂进去统计 op 和 funct 的分布就能确认数据通路是否真的只需要覆盖这 8 条指令避免多画一堆用不上的通路。提示控制信号表里“无效时默认值”要写清楚。比如 RegWrite 无效时为 0AluSrcB 无效时选寄存器 BMemToReg 无效时选 ALU 输出。默认值不写Logisim 里悬空线容易把整个电路带进振荡。3. 单周期 CPU 落地数据通路布线与硬布线控制器3.1 取指到写回7 条指令的数据通路拼装与 MUX 选择端单周期数据通路的画法可以按“取指—译码—执行—访存—写回”五段走但真正决定电路能不能跑的是几个多输入选择器。PC 输入端要选 PC4 还是分支目标地址选择端是 Branch 信号写寄存器地址要选 rt 还是 rd选择端是 RegDst写回数据要选 ALU 结果还是存储器读出数据选择端是 MemToRegALU 的 B 端要选寄存器 B 还是符号扩展立即数选择端是 AluSrcB。把这四个 MUX 先画出来再把 Regfile、ALU、IMEM、DMEM 按指令流连上去图就不会乱。取指阶段有两个容易忽略的细节。PC 是 32 位字节地址而指令存储器地址输入端通常是 10 位字地址所以要用分线器取 PC 的第 2 到第 11 位送入 IMEM数据存储器同理ALU 算出的字节地址也要取第 2 到第 11 位。另一个细节是复位信号要接到指令寄存器和数据寄存器否则 Logisim 启动时寄存器初值不确定sort.hex 的第一条指令还没执行PC 就可能已经跑飞。通常的做法是先把 PC、IMEM、Regfile 单独连出来手动给时钟和复位确认取出的第一条指令字段正确再往上加 ALU 和 DMEM。分支逻辑建议单独画一块ALU 的 equal 输出只表示 rs 和 rt 相等beq 需要 equal 为 1 且当前指令是 beqbne 需要 equal 为 0 且当前指令是 bne所以 Branch Beq·equal Bne·~equal。这个 Branch 信号接到 PC 输入端 MUX 的选择端决定下一条指令是 PC4 还是 PC4(SignExt(imm)2)。syscall 的停机则直接把 Halt 接到 PC 寄存器的使能端Halt 有效时 PC 停止更新CPU 就停在当前指令上。3.2 硬布线控制器指令译码、ALU 控制与写回逻辑硬布线控制器的输入是指令的 op 和 funct输出是前面那张控制信号表。第一步做指令译码把 op 与 lw、sw、beq、bne、addi 的 op 值比较得到 LW、SW、BEQ、BNE、ADDI 五个信号R 型指令的 op 为 0再看 funct 是否等于 add 的 0x20、slt 的 0x2a、syscall 的 0x0c得到 ADD、SLT、SysCall。R_TYPE 不能简单等于 op0因为 syscall 的 op 也是 0所以 R_TYPE (ADD SLT) ~SysCall。这个式子看起来小但漏掉 ~SysCall 就会让 syscall 也去写寄存器停机前把寄存器改乱。ALU 控制只需要区分加法和有符号比较。ALU 内部加法操作码是 0x5比较操作码是 0xb用 SLT 信号做二路选择即可SLT 为 1 时输出 0xb否则输出 0x5。写回逻辑则把 R_TYPE、ADDI、LW 做逻辑或得到 RegWriteMemToReg 只在 LW 时有效MemWrite 只在 SW 时有效RegDst 只在 R_TYPE 时有效。下面这段用 Python 生成控制信号真值表方便逐行核对也方便在实验报告里贴成表格。# 生成单周期 CPU 控制信号真值表字段顺序与报告中的控制信号表一致 # 每个元组指令名, op, funct, RegWrite, RegDst, AluSrcB, MemToReg, # MemWrite, Beq, Bne, Halt, AluOP rows [ (add, 0x00, 0x20, 1, 1, 0, 0, 0, 0, 0, 0, add), (slt, 0x00, 0x2a, 1, 1, 0, 0, 0, 0, 0, 0, slt), (addi, 0x08, None, 1, 0, 1, 0, 0, 0, 0, 0, add), (lw, 0x23, None, 1, 0, 1, 1, 0, 0, 0, 0, add), (sw, 0x2b, None, 0, 0, 1, 0, 1, 0, 0, 0, add), (beq, 0x04, None, 0, 0, 0, 0, 0, 1, 0, 0, sub), (bne, 0x05, None, 0, 0, 0, 0, 0, 0, 1, 0, sub), (syscall,0x00,0x0c, 0, 0, 0, 0, 0, 0, 0, 1, add), ] print(instr,op,funct,RegWrite,RegDst,AluSrcB,MemToReg,MemWrite,Beq,Bne,Halt,AluOP) for r in rows: print(,.join(str(x) for x in r))这段脚本的输出可以直接对照 Logisim 里每个门电路的输出。参数含义RegWrite 为 1 表示写寄存器RegDst 为 1 表示写 rd、为 0 表示写 rtAluSrcB 为 1 表示 ALU 的 B 端选立即数MemToReg 为 1 表示写回数据来自存储器MemWrite 为 1 表示写存储器Beq/Bne 是分支译码Halt 是停机。AluOP 这一列在这里只用 add/slt/sub 做语义标注真正接到 ALU 的两位控制码仍按 0x5 和 0xb 处理。写报告时把这套真值表和电路图并排放答辩时被问到“为什么 beq 不需要 RegWrite”可以直接指表回答。3.3 布线检查清单位宽、分离器、复位与停机单周期布线完成后不要急着加载 sort.hex。先做一遍静态检查PC 是否 32 位、IMEM 地址是否取了第 2 到 11 位、DMEM 地址是否同样处理、符号扩展器是否设置成 16 位到 32 位有符号扩展、Regfile 的读写地址是否 5 位、ALUsrcB 的 MUX 是否两位输入位宽一致。位宽不匹配在 Logisim 里不一定报错但会把高位悄悄截掉sort.hex 跑到数组中间就开始读写错位。再做一遍动态检查手动给一个时钟看 PC 是否从 0 变成 4把第一条指令的 op 和 funct 用探针引出来确认译码信号只有一路为 1给 Regfile 写入一个初值再执行一条 add看写回地址是不是 rd执行一条 lw看 MemToReg 是否把存储器数据送到写回端。最后才把 Halt 接到 PC 使能端确认 syscall 执行后 PC 不再变化。这个顺序看起来慢但比整图跑飞后再逐根线排查要快得多。注意Logisim 的时钟触发沿要统一。PC、IR、Regfile 如果有的上升沿触发、有的下降沿触发单周期看起来能跑多周期一到状态切换就会错拍。画图前先确定所有时序部件用同一个触发沿。4. 多周期 CPU 落地状态划分、微程序控制器与硬布线状态机4.1 把每条指令拆成状态取指、译码、执行的状态编号多周期 CPU 的第一步不是画数据通路而是把每条指令拆成状态。取指状态所有指令共用IR ← Mem[PC]PC ← PC4译码状态也共用A ← R[rs]B ← R[rt]C ← PC (SignExt(imm)2)。执行状态则按指令分叉add 走“C ← AB写回 rd”slt 走“C ← (AB)写回 rd”lw 走“C ← ASignExt(imm)DR ← Mem[C]写回 rt”sw 走“C ← ASignExt(imm)Mem[C] ← B”beq/bne 走“若条件成立则 PC ← C”addi 走“C ← ASignExt(imm)写回 rt”syscall 停在自身状态。状态编号建议从 0 开始取指为 0译码为 1然后每条指令的执行状态依次排下去。这样微指令地址就是状态编号状态寄存器用 4 位就够 13 个状态。每个状态对应一条微指令微指令里要写清楚该状态需要哪些控制信号、下一条微指令地址是多少。取指微指令的下址指向译码状态译码微指令的下址为 0 表示根据指令译码信号跳转各指令最后一条微指令的下址为 0syscall 的下址指向自身形成自循环停机。状态功能关键操作下址策略0取指IR ← Mem[PC]PC ← PC4固定指向 11译码A ← R[rs]B ← R[rt]C ← PC偏移按指令译码跳转2/3/4lw 执行算地址、读存储器、写回最后一条下址 05/6sw 执行算地址、写存储器最后一条下址 07/8R 型执行运算、写回最后一条下址 09/10beq/bne条件成立则 PC ← C下址 011/12addi加法、写回最后一条下址 013syscall空操作停住 PC下址指向自身这张表是微程序控制器和硬布线状态机的共同底稿。微程序控制器把每个状态翻译成一条微指令存在控制存储器里硬布线控制器把状态转移画成状态图用组合逻辑生成次态。两条路线的输入输出一致区别只是“控制信号存在 ROM 里”还是“控制信号由门电路现算”。4.2 微指令编码与控制存储器一张 Excel 表生成 ROM 文件微程序控制器的核心是一张微指令表。每个字段对应一个控制信号每条微指令对应一个状态最后把字段拼成一个二进制字导出成 txt 加载到 Logisim 的控制存储器组件。字段顺序一旦定了就不要改否则后面改一条微指令就要全表重排。通常的做法是IorD、PcSrc、AluSrcA、AluSrcB、MemToReg、RegDst、IrWrite、PcWrite、RegWrite、MemWrite、MemRead、Beq、Bne、AluControl、下址字段从高位到低位排好每一位都写清楚含义。下面这段脚本把微指令字段打包成 32 位十六进制输出格式是每行一个机器字方便直接作为 ROM 初始化文件。参数说明fields 里的每个键对应一位或几位控制信号width 表示该字段占几位value 是当前微指令的取值下址字段放在最低位方便状态跳转。实际实验里字段顺序要和 Logisim 控制存储器的数据位分配一致不一致就会“指令跑得动但控制信号全错位”。# 将微指令字段打包成 32 位十六进制每行一个机器字供 Logisim ROM 加载 # 字段顺序IorD(1) PcSrc(1) AluSrcA(1) AluSrcB(2) MemToReg(1) RegDst(1) # IrWrite(1) PcWrite(1) RegWrite(1) MemWrite(1) MemRead(1) # Beq(1) Bne(1) AluControl(2) 下址(8) FIELDS [ (IorD, 1), (PcSrc, 1), (AluSrcA, 1), (AluSrcB, 2), (MemToReg, 1), (RegDst, 1), (IrWrite, 1), (PcWrite, 1), (RegWrite, 1), (MemWrite, 1), (MemRead, 1), (Beq, 1), (Bne, 1), (AluControl, 2), (next, 8), ] def pack_microinstruction(values: dict) - str: word 0 for name, width in FIELDS: v values.get(name, 0) if v 0 or v (1 width): raise ValueError(f{name}{v} 超出 {width} 位范围) word (word width) | v return f{word:08X} # 示例取指微指令IrWrite1、MemRead1、PcWrite1下址为 1译码状态 fetch {IrWrite: 1, MemRead: 1, PcWrite: 1, next: 1} print(pack_microinstruction(fetch))这段代码的关键不是 Python 语法而是“字段顺序固定、位宽校验、下址单独留 8 位”。位宽校验能提前发现“AluSrcB 写了 3”这种越界值下址留 8 位是因为状态数虽然只有 13 个但后面如果扩展指令状态编号还有余量。导出的 txt 每行一个 8 位十六进制数加载到 ROM 后用状态寄存器输出作为地址去取微指令再把微指令的各个位分线到对应控制信号线上。微程序控制器的好处是改指令只需改表不用重画门电路坏处是 ROM 位宽和字段顺序必须一次定对后期改字段顺序会牵一发动全身。4.3 硬布线控制器Moore 状态机与次态逻辑多周期硬布线控制器本质是一个 Moore 型状态机输出控制信号只与现态有关次态由现态和指令译码信号共同决定。状态寄存器用 4 位现态输出接到控制信号组合逻辑同时接到次态组合逻辑次态组合逻辑的另一路输入是 7 个指令译码信号R_TYPE、ADDI、LW、SW、BEQ、BNE、SYSCALL。取指状态 0 的次态固定为 1译码状态 1 的次态按指令译码信号选择对应执行状态各执行状态最后一条微指令的次态回到 0syscall 的次态回到自身。状态转移可以用真值表自动生成也可以用逻辑表达式手写。比如译码状态的次态可以写成Next R_TYPE?7 : ADDI?11 : LW?2 : SW?5 : BEQ?9 : BNE?10 : SYSCALL?13 : 0。实际写的时候要把每个条件写成“现态等于 1 且对应译码信号为 1”避免不同状态的次态互相干扰。控制信号逻辑则按状态展开状态 0 拉高 IrWrite、MemRead、PcWrite状态 1 拉高 AluSrcA、AluSrcB 的特定组合lw 的读存储器状态拉高 MemReadsw 的写存储器状态拉高 MemWrite。这样写出来的电路门数比微程序多但每个时钟周期都能看到状态和信号调试时反而直观。控制器类型优点缺点适合场景微程序控制器改指令只改表控制信号集中ROM 字段顺序固定位宽易错指令较多、需要扩展硬布线控制器无需 ROM状态和信号直接可见门电路多改一条指令要改逻辑指令少、强调时序理解两种控制器都要接到同一套多周期数据通路上所以数据通路的控制信号命名必须和控制器输出一一对应。建议先把微程序控制器调通用它的控制信号去验证数据通路数据通路确认无误后再换硬布线控制器用同样的 sort.hex 跑一遍。这样出错时能快速判断是“数据通路问题”还是“控制器问题”。4.4 两种控制器怎么选微程序可维护硬布线省周期如果实验要求两种控制器都实现建议先做微程序控制器。原因很实际微程序的控制信号在表里改一个状态只需改一行调 sort.hex 时可以先看状态寄存器走到哪一步、微指令取出的控制信号对不对硬布线控制器的次态逻辑一旦写错状态可能跳到无关分支排查成本更高。微程序控制器跑通后数据通路、存储器复用、寄存器锁存都已经验证过再换硬布线控制器就只是“把表换成门电路”风险小很多。硬布线控制器也不是没有优势。它的控制信号由现态直接译码不需要 ROM 取数时序路径更短状态图在报告里也更像“有限状态机”的标准画法答辩时容易讲清楚。两种控制器都实现的情况下可以对比同一段 sort.hex 的时钟周期数单周期 CPU 的周期数等于指令条数多周期 CPU 的周期数按状态累加lw/sw 占 4 到 5 个周期R 型占 3 到 4 个周期。这个对比放在测试与分析里比只写“运行正确”更有说服力。5. 避坑与排查时钟、位宽、状态机与微指令的 5 个高频翻车点5.1 现象sort.hex 跑飞PC 跳到奇怪地址现象是排序程序跑着跑着 PC 不再按 4 递增或者直接跳到数组中间寄存器里的值全乱。原因通常有三类分支偏移没有做符号扩展16 位立即数被当成无符号数Branch 信号只接了 beq 没接 bne或者 equal 信号直接当 Branch 用PC 输入端 MUX 的选择端接错PC4 和分支目标地址的优先级反了。解决方法是把 Branch Beq·equal Bne·~equal 单独画出来用探针看 beq 成立和不成立时 Branch 是否按预期变化同时检查符号扩展器是否设置成有符号扩展分支偏移是否左移两位后再加 PC4。5.2 现象寄存器写回写错位置add 写到了 rt现象是 add 执行后 rd 没变rt 反而被改了或者 lw 写回时写到了 rd。原因是 RegDst 接反或者 Regfile 的写地址 MUX 选择端没有区分 R 型和 I 型。R 型指令写 rd第 15 到 11 位I 型指令写 rt第 20 到 16 位这个差异必须由 RegDst 控制。排查时给 Regfile 的写地址加探针分别执行一条 add 和一条 addi看写地址是 rd 还是 rt如果 add 写到了 rt就是 RegDst 的选择端接反或者 MUX 输入顺序颠倒。5.3 现象多周期状态死循环syscall 停不下来现象是 PC 不再前进但状态寄存器一直在某个状态打转或者 syscall 之后状态又回到了取指。原因是微指令下址字段写错syscall 的下址应该指向自身形成自循环各指令最后一条微指令的下址应该为 0表示回到取指译码状态的下址为 0 表示按指令译码跳转不能写成固定地址。排查时把状态寄存器输出接到数码管或探针单步时钟看状态序列是否符合状态图如果 syscall 状态执行完跳到 0就是下址字段写成了 0 而不是自身地址。5.4 现象lw/sw 读写地址错位排序结果局部正确现象是数组前几个元素正确后面越界或重复。原因是多周期里存储器地址选择 MUX 的 IorD 信号接错取指时地址应来自 PC访存时地址应来自 ALU 输出如果 IorD 一直选 PClw/sw 就会读写到指令区。另一个原因是字节地址没有取第 2 到 11 位DMEM 按字寻址时地址偏移了 4 倍。排查时在 lw/sw 状态看 DMEM 地址输入端确认它等于 ASignExt(imm) 而不是 PC同时检查地址分线器是否从第 2 位开始取。5.5 现象复位后第一拍就错寄存器初值不确定现象是 Logisim 刚启动PC 还没走寄存器或存储器就出现了随机值或者单步时钟第一拍 PC 直接跳到一个非零地址。原因是复位信号只接了 PC没有接 IR、Regfile、A/B/C 等寄存器或者时钟触发沿不统一有的寄存器上升沿采样、有的下降沿采样。解决方法是把所有时序部件的复位端统一接到复位信号时钟触发沿统一设置为上升沿启动后先按复位再单步一拍确认 PC 为 0、IR 为第一条指令、Regfile 初值为预期值再连续跑 sort.hex。6. 验收与答辩用 sort.hex 的输出反推设计正确性验收不要只看“程序跑完了”。更稳的验收顺序是先看 PC 是否从 0 开始按预期取指再看寄存器堆和存储器快照是否与冒泡排序的中间结果一致最后看 syscall 停机后数据区是否有序。sort.hex 的输入数组通常放在数据存储器固定地址排序完成后这些地址里的值应该从小到大排列如果只有前几个元素正确优先怀疑 lw/sw 的地址计算或存储器复用如果所有元素都正确但停机后 PC 还在动优先怀疑 Halt 或 syscall 状态自循环。验收项通过标准检查位置取指PC 从 0 开始每条指令地址按 4 递增PC 寄存器、IMEM 地址译码op/funct 译码信号每次只有一路有效控制器译码输出R 型运算add/slt 写回 rd溢出时不写Regfile 写地址与写使能访存lw/sw 地址等于 rsSignExt(imm)ALU 输出、DMEM 地址分支beq/bne 成立时 PC 跳到目标地址PC 输入 MUX、Branch 信号停机syscall 后 PC 不再更新PC 使能端或状态寄存器排序结果数据区数组有序无越界改写DMEM 数据区快照答辩时最容易被问的不是“这个 CPU 能跑什么”而是“你为什么这么连”。讲的时候按一条指令走完整流程最稳拿 lw 从取指讲到写回指出 IR、A、B、C、DR 分别在哪个状态锁存IorD 什么时候选 PC、什么时候选 ALUMemToReg 什么时候为 1再拿 beq 讲分支指出 equal 信号怎么参与 BranchPC 写使能什么时候有效。单周期和多周期的差异也要能一句话说清单周期是空间换时间多周期是分时复用加状态控制。最后把单周期和多周期的时钟周期数对比摆出来说明多周期虽然一条指令要多个周期但硬件复用度更高这就是设计取舍。从那以后我每次带人做这个实验都强制先写控制信号表、再画数据通路最后才打开 Logisim 布线sort.hex 跑通只是及格线能把每条指令的状态和信号讲清楚才算交付。这套单周期与多周期的 Logisim 工程、微指令表、控制信号真值表和验收清单我整理成了一份可直接对照的交付包需要参考实现时按目录取用即可。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑