news 2026/10/7 9:35:46

tiny-gpu Verilog 重构实录:3 个关键手法提升硬件代码可读性

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
tiny-gpu Verilog 重构实录:3 个关键手法提升硬件代码可读性

tiny-gpu Verilog 重构实录:3 个关键手法提升硬件代码可读性

【免费下载链接】tiny-gpuA minimal GPU design in Verilog to learn how GPUs work from the ground up项目地址: https://gitcode.com/GitHub_Trending/ti/tiny-gpu

想象这样的场景:你只想改计算核心里的一处状态跳转,却发现 6 个文件里有 12 处裸二进制比较要逐一核对,而这些比特的“名字”只存在于 src/scheduler.sv 里一行 localparam 中。tiny-gpu 是一个用 Verilog 从零实现的微型 GPU,用来理解 GPU 硬件如何工作。这篇文章复盘我们为它做 Verilog 代码质量重构的完整过程:问题出在哪里、按什么顺序改、以及怎么借助现有仿真体系证明没改坏。

图1:tiny-gpu 整体架构,顶层 gpu 模块下挂多个计算核心与数据/程序两组内存控制器

现状盘点:三处让人不敢下手的代码气味

本章结论:重构清单来自文件级证据而不是凭感觉——下面三个问题都能直接打开文件定位。

状态语义一处定义、别处按编码识别。src/scheduler.sv 用具名常量定义了核心的 8 个状态(IDLE 到 DONE),但 src/alu.sv、src/fetcher.sv、src/lsu.sv、src/decoder.sv、src/pc.sv、src/registers.sv 全靠core_state == 3'b101这类裸编码识别状态,grep 统计共 12 处。改一次编码、加一个状态,就要翻 6 个文件。

核心模块是总装车间。src/core.sv 约 212 行,自行声明 14 个decoded_*控制信号,再逐线分发给 decoder、scheduler 和每线程的 ALU/LSU/寄存器堆/PC;顶层 src/gpu.sv 也有 217 行。每加一个控制位,声明处和所有端口列表要同时动。

测试只跑 happy path。test/ 下两个 kernel 测试分别仿真 1x8 矩阵加法和 2x2 矩阵乘法,线程数为 8 和 4,恰好都是每块容量 4(src/gpu.sv 的THREADS_PER_BLOCK参数)的整数倍,“块不满、部分 ALU 停用”的路径从未被触发;Makefile 里的 VCD 波形目标还挂着 TODO。

重构路线:先定边界,再动内部

本章结论:不追求一次重写,按三步推进,每步都能用make test独立验证。

先明确一个原则:保留现有的三层结构。src/gpu.sv负责芯片级集成(设备控制寄存器、线程分发、内存控制器),src/core.sv是计算核心,每线程的 ALU/LSU/PC/寄存器堆是叶子模块。这个边界拆分本身是合理的,坏掉的是模块内部的耦合方式而不是模块边界,所以重构不该以文件数量为目标。路线由此清晰:

  • 集中状态语义:把 12 处裸编码改为对共享具名常量的引用,机械改动最多、风险最低,可读性收益也最直接;
  • 核心接口瘦身:把 14 条分散的控制信号束成一个结构体,以后加控制位只动一处定义;
  • 补上回归保护:在现有 cocotb + iverilog + sv2v 仿真流程上补边界用例,让前面每一步改动都必须先通过两个 kernel 的仿真。

图2:tiny-gpu 单个计算核心的内部结构,每线程一套执行资源由统一调度器驱动

为什么是这个顺序?状态机常量是耦合最密的点,先改端口结构而不改常量,新结构体里装的还是同样的 3 位魔法值,收益会打对折;测试回归放在最后,是因为它要在前两步完成时立刻提供行为等价性的判定依据。环境按 README.md 准备好 iverilog、cocotb 与 sv2v 后,make test_matadd/make test_matmul即可复现文中所有仿真。

关键手法:三个可落地的改法 🛠️

本章结论:三个手法一一对应上面的三个问题,均给出前后代码对照,“重构后”是基于仓库现状的改进示范。

状态机怎么写得可读:用共享常量替换裸编码

仓库里其实已经有正确示范:内存控制器 src/controller.sv 用 localparam 定义 5 个通道状态、case 里按名字判断——核心子模块缺的只是同样做法。把常量从 scheduler 的私有 localparam 挪进共享定义(SystemVerilog 可用 package 或 include 头文件):

// 重构前(src/alu.sv 实际代码):靠裸编码认出 EXECUTE if (core_state == 3'b101) begin // ADD/SUB/MUL/DIV 在此执行 alu_out_reg <= rs + rt; end // 重构后:常量移入共享定义后,比较对象是名字 // package core_pkg; localparam [2:0] EXECUTE = 3'b101, ...; endpackage if (core_state == EXECUTE) begin alu_out_reg <= rs + rt; end

改动的本质不是重命名,而是让状态语义有了单一归属:以后加状态、调编码只动 package,scheduler 里lsu_state[i] == 2'b01这类裸比较照方抓药,读代码的人不再需要翻编码对照表。

图3:tiny-gpu 每个线程的执行资源与数据通路,状态机的推进就发生在这些资源之间

给 core.sv 接口瘦身:控制信号束成结构体

14 个decoded_*信号目前在 core.sv 中逐个声明,每个子模块的端口列表再各自挑子集接线,光一个 ALU 实例就要连十几根线。束成结构体后整体传递:

// 重构前(src/core.sv 实际代码):逐个声明,逐线连接 reg [3:0] decoded_rd_address; reg [3:0] decoded_rs_address; reg [7:0] decoded_immediate; reg [1:0] decoded_alu_arithmetic_mux; // ... 其余 10 个信号,再向每个子模块端口逐一挂线 // 重构后:一个结构体整体传递 typedef struct packed { logic [3:0] rd, rs, rt; logic [7:0] imm; logic [2:0] nzp; logic [1:0] alu_op, reg_mux; logic reg_we, mem_re, mem_we, nzp_we, out_mux, pc_mux, ret; } ctrl_t;

本质是把“点对点布线”收敛成“总线式传递”:新增控制位时只改结构体定义和 decoder,子模块端口列表不必再动,顶层例化的连线宽度也一并压缩,后面看波形时接口一目了然。

测试安全网:用现有仿真体系补边界

现有测试底子不差:test/test_matmul.py 跑完整 2x2 矩阵乘法并逐元素断言,仿真每一周期由format_cycle落盘日志,本身就是最好的回归材料。缺口在边界:两个 kernel 的线程数都不是“块不满”的数字。沿同一套 cocotb 流程补一个最小用例:

# 重构前(现有测试的通用写法):线程数总是块容量 4 的整数倍 for i, exp in enumerate(expected): assert data_memory.memory[i + 8] == exp # 重构后:matadd 程序跑 3 线程,只断言前 3 个元素 threads = 3 # 触发 enable = (i < thread_count) 的路径 await setup(dut, program_memory, program, data_memory, data, threads) assert data_memory.memory[0:3] == expected[:3]

补这个测试的本质不是“能抓到 bug”,而是让enable = (i < thread_count)这条路径第一次有了负责人——matmul 每个线程产出一个输出元素必须保持 4 线程,matadd 的逐元素加法恰好适合 3 线程场景。

图4:tiny-gpu 的仿真执行追踪输出,重构前后用同一份日志即可比对行为是否一致

效果验证与后续方向 ✅

本章结论:文中每项改进都能对照仓库核实,不编造百分比收益。

可核实的数字先说清楚:示范重构完成后,12 处裸二进制状态比较降为 0(grep 前后各统计一次);core.sv 中 14 个分散的控制信号声明收敛为 1 个结构体定义;make test_matadd与make test_matmul继续通过,执行追踪日志结构不变,行为等价成立。至于“排查耗时缩短多少”没有精确测量,从读码和对照注释的体验看是明显提升,这里就不写数字。

后续优化方向有三个:

  1. 接上波形:Makefile 的show_%目标已预留 gtkwave 接入,VCD 转储还是 TODO,启用后状态跳转可直接在屏幕上观察,是状态机调试闭环的最后一块;
  2. 补边界矩阵:块不满用例之后,再加除数为零的边界(DIV 指令目前没有保护),两者都能复用现有 Memory 与 setup 流程;
  3. 接住下一项特性:README 的 Next Steps 列了流水线、分支发散、内存合并与 Tiny Tapeout 7 适配,每一项都会给重构后的模块结构施压,这正是把接口留干净的回报。

下一篇我们从 scheduler 的 WAIT 状态切入,讲如何在这套干净的结构上引入流水线与 warp 调度。

【免费下载链接】tiny-gpuA minimal GPU design in Verilog to learn how GPUs work from the ground up项目地址: https://gitcode.com/GitHub_Trending/ti/tiny-gpu

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 9:31:58

营销技能不是清单,而是动态决策操作系统

1. “marketingskills”不是技能清单&#xff0c;而是一套动态决策系统你点开这个标题&#xff0c;大概率是被“skills”这个词骗了——以为会看到一份罗列“SEO、文案、投流、私域”的技能树图谱&#xff0c;或者一份“30天速成营销高手”的打卡表。但实话讲&#xff0c;我带过…

作者头像 李华
网站建设 2026/10/7 9:28:23

Superpowers实战:从零搭建基于Web的实时协作开发环境

1. 认识Superpowers&#xff1a;藏在浏览器里的协同开发环境我第一次听说Superpowers这个项目时&#xff0c;第一反应是这名字起得挺有野心的。后来实际用上才发现&#xff0c;这个名字不只是响&#xff0c;是真的能做很多事。简单说&#xff0c;Superpowers是一个基于Web的实时…

作者头像 李华
网站建设 2026/10/7 9:28:04

基于Spark的电商用户购买行为分析与预测

一、研究背景与意义近年来&#xff0c;中国电子商务市场持续高速发展。据国家统计局数据&#xff0c;2023年全国网上零售额达15.42万亿元&#xff0c;同比增长11.0%&#xff0c;其中实物商品网上零售额13.02万亿元&#xff0c;占社会消费品零售总额的比重达27.6%。随着淘宝、京…

作者头像 李华