RTL 与实验闭环
拆分并集成 Verilog 模块,配置片上 ROM 测试程序,搭建顶层 testbench,并在 Vivado 2018.3 中保留编译、展开、运行日志与波形文件。
一颗面向课程实验的单周期 CPU,也是一份 RTL 取证样本:9 个 Verilog 模块留下了可观察数据通路;当前分支选择逻辑同时留下一个尚未修复、尚无 assertion 覆盖的正确性风险。
An RTL forensic lab: inspect the observable datapath, surface the unresolved branch-selection defect, and keep a 520 ns historical trace separate from correctness claims.
问题不是“会写几段 Verilog”,而是让一条指令完整走通。
课程给出的 ISA 语义是抽象的:lw 需要取指、读寄存器、算地址、读内存再写回;beq 还要把比较结果送回 PC 选择。真正的工程问题,是把这些依赖拆成边界清晰的模块,并让控制信号与数据在同一外部时钟周期内配合。
因此,这个项目把重点放在“端到端数据通路”上:不仅实现 ALU,还要处理寄存器堆、两类存储器、立即数扩展、控制译码、PC 计算与顶层集成。
原始工程实现与本次公开表达,分开记账。
拆分并集成 Verilog 模块,配置片上 ROM 测试程序,搭建顶层 testbench,并在 Vivado 2018.3 中保留编译、展开、运行日志与波形文件。
AI 协助重组案例叙事、前端样式、分享元数据与静态契约检查。本次展示重构没有修改原始 RTL、测试台或历史仿真产物。
控制流决定“走哪条路”,数据通路负责“把值送到”。
pc[7:2] 选中 64 × 32-bit ROM 中的指令。
opcode/funct 产生控制线;双端口读取操作数并扩展立即数。
组合逻辑执行 AND、OR、ADD、SUB、SLT、NOR,并输出 zero 标志。
64 × 32-bit 数据存储器提供组合读与受时钟控制的写入。
选择顺序、分支、跳转或寄存器地址,并把 ALU、内存或返回地址写回。
实现利用外部时钟的上升沿取指、下降沿更新 PC / 寄存器,并通过派生翻转信号驱动数据存储器写入,给组合数据通路留出观察窗口。这是该实验的具体时序组织,不应直接等同于已完成时序分析的标准工业单周期核。
// mips_cpu.v · 顶层选择逻辑(节选)
assign write_reg = (reg_dst == 2'b00) ? instruction[20:16] :
(reg_dst == 2'b01) ? instruction[15:11] :
5'b11111;
assign reg_write_data = (mem_to_reg == 2'b00) ? alu_result :
(mem_to_reg == 2'b01) ? mem_read_data :
(mem_to_reg == 2'b10) ? pc + 32'd4 :
zero_extend;
证据支持“工程曾被编译并跑出轨迹”;它不自动支持“所有语义都正确”。
留档日志逐项分析 9 个设计模块与 mips_cpu_tb,并记录 Built simulation snapshot mips_cpu_tb_behav。展开阶段同时留下 9 条 timescale 警告。
105 行历史日志记录至 520 ns;可见 PC 从 0x00 走到 0x30 后由 j 回到 0x00,并多次重复。
当前 testbench 使用 $monitor 与波形观察,没有 assertion、期望值对比、覆盖率或 CI 中的 RTL 仿真,因此不能把运行轨迹当成完备验证。
beq 与 j 路径;被注释的扩展指令样例与译码分支不等于已验证支持。pc_calculator 没有接收分支子类型,现有组合条件会让 branch 为真时的 zero / non-zero 路径都选择分支目标;这是需要自判定测试暴露并修复的正确性风险。这个项目留下了从模块化设计到历史仿真的完整学习轨迹,也留下了下一轮验证应该从哪里开始的明确入口。