Tsetlin Machine FPGA 推理加速器——UART 变体
许可说明:本目录采用 CC BY-NC-ND 4.0 许可(非商业性、禁止衍生再分发)——详见本目录中的 LICENSE.md。本仓库其余大部分内容采用 MIT 许可;有关许可划分,请参见根目录 README.md 的“License”部分。
一个 200 子句的 Tsetlin Machine MNIST 数字分类器,完全运行在 hotstate 引擎上(关于该引擎的定义,请参见仓库级 README),配备纯 UART 前端——除 Tang Nano 9K/20K 或 Tang Primer 25K 现有的 USB 串口桥外,无需额外硬件。
推理引擎本身(tm_core_v2.v 的子句评估与投票累加器、tm_seq_controller.c 的 hotstate 子句定序器,以及 gen/ 中训练好的子句掩码 ROM)是手工设计/训练的 Verilog 和 hotc C,本 README 不会重新推导——此处记录的是围绕其搭建的 UART 前端,以及如何构建、烧录并与最终结果通信。
该设计在第 98 个图像字节到达后立即自动启动推理——无需单独的触发信号,天然契合 UART 的字节流模型:
主机(send_image.py)│ 98 原始字节(MNIST 图像,1 位/像素打包为字节)▼ uart_rx(hotstate)│ rx_done/rx_byte,每字节一个脉冲 ▼ tm_uart_loader(hotstate)│ 写入 img_waddr/img_wdata/img_wen(98 次),然后 go=1 ▼ tm_top(tm_seq_controller + tm_core_v2)│ 200 子句评估 + 顺序 argmax -> done,winner[3:0] ▼ tm_uart_loader │ tx_data = winner,tx_start(保持直到 tx_busy)▼ uart_tx(hotstate)│ 1 字节输出 ▼ 主机 源文件 文件 作用 tm_core_v2.v 手写:子句评估 + 投票累加器。在其手写状态寄存器上带有 (* fsm_encoding = "none" *) 作为预防性修复,针对此硬件上其他地方出现的 yosys FSM 重编码问题。tm_top.v 手写:完全与 I/O 无关(仅 go / done / img_waddr / img_wdata / img_wen / result 端口)。tm_seq_controller.c hotc 源文件:hotstate 子句序列器(200 子句评估 + argmax)。
gen/ 训练好的子句掩码ROM(clause_meta.hex、include_mask.hex、include_inv_mask.hex)+ tm_config.vh。训练本身不属于本仓库内容。uart_rx.c / uart_tx.c hotc源码:通用UART接收/发送hotstate状态机。tm_uart_loader.c hotc源码:通过UART接收98字节图像,驱动img_waddr / img_wdata / img_wen,与tm_seq_controller执行go / done握手,并将结果字节回传。tm_hw_top_uart.v 手写代码:顶层封装,将uart_rx + uart_tx + tm_uart_loader + tm_top连接在一起。tm_hw_top_uart_tb.v Verilator测试平台——通过模拟UART发送真实的MNIST测试图像(sample0.hex),并将结果与该样本的预期预测值(数字7)进行比对。sample0.hex 上述测试平台的夹具文件——样本0的98字节图像数据,以$readmemh兼容的十六进制转储格式提供。
batch_ref.bin 100 个真实标注的 MNIST 样本 + 参考预测结果,供下方的 send_batch.py 使用。tm_{tang9k,tang20k,primer25k}_uart.cst 各开发板的引脚约束文件。Makefile.synth_{tang9k,tang20k,primer25k} 各开发板的综合/布局布线/打包/烧录流程(yosys + nextpnr-himbaechel + gowin_pack + openFPGALoader)。send_image.py 主机端测试脚本——发送单张 98 字节图像(默认:全零),并打印返回的识别数字。send_batch.py 主机端批量测试脚本——发送 batch_ref.bin 中全部 100 个样本,并报告与参考预测及真实标签的一致率。请使用此脚本而非单张测试图像来判断构建是否真正可用——原因见下方“已知限制”。draw_digit_uart.py 交互式主机端 GUI(Tk + pyserial)——用鼠标在 28×28 画布上绘制数字,并通过与 send_image.py 相同的 UART 协议在真实硬件上进行分类。
verified_bitstreams/ 已验证的预构建比特流,如果你希望直接烧录而非自行综合,可使用这些文件。查看其内容以确认对应的开发板和哈希值。构建与测试仿真 IP_DIR=../../IP verilator --timing --cc -Wno-fatal -Wno-WIDTHTRUNC --exe --build -j 4 \ -I.-I $IP_DIR -Igen \ sim_main.cpp tm_hw_top_uart_tb.v tm_hw_top_uart.v tm_top.v tm_core_v2.v \ tm_seq_controller_template.v tm_uart_loader_template.v uart_tx_template.v uart_rx_template.v \ $IP_DIR /hotstate.sv $IP_DIR /microcode.sv $IP_DIR /control.sv $IP_DIR /next_address.sv \ $IP_DIR /timer.sv $IP_DIR /variable.sv $IP_DIR /switch.sv $IP_DIR /stack.sv \ --top tm_hw_top_uart_tb ./obj_dir/Vtm_hw_top_uart_tb 预期输出:[TB] PASS: result=7(期望值为 7,与该样本的参考预测一致)。
make -f Makefile.synth_tang9k prog # 或 Makefile.synth_tang20k / _primer25k python3 send_image.py --port /dev/ttyUSB1 # 全零测试图像 python3 send_image.py --port /dev/ttyUSB1 --image path/to/98-byte-image.bin python3 send_batch.py --port /dev/ttyUSB1 # 全部 100 个 batch_ref.bin 样本 python3 draw_digit_uart.py --port /dev/ttyUSB1 # 绘制一个数字,进行交互式分类 如果 /dev/ttyUSB1 在你的机器上不正确,可使用 udevadm info -a -n /dev/ttyUSBn | grep bInterfaceNumber 查找正确的端口——接口 00 为 JTAG 调试接口,接口 01 为 UART。
在真实的 Tang Nano 9K 硬件上针对完整的 100 样本 batch_ref.bin 批次进行了验证:与参考预测和真实标签均达到 100/100(100.0%)一致(该精确构建见 verified_bitstreams/)。关于一个未解决的、罕见的、未能复现的结果及其已知情况,请参见下方的“已知限制”。
FPGA 资源使用情况(Tang Nano 9K,nextpnr-himbaechel 器件利用率)
资源 已用 可用 占比 LUT4 2,485 8,640 28% DFF 629 6,480 9% ALU 742 6,480 11% BSRAM 22 26 84% IOB 5 276 1% BSRAM 主要由 200 个子句掩码 ROM 占用;LUT/DFF 的使用主要来自四个 hotstate 状态机的控制逻辑(加载器 + 两个 UART 引擎 + 子句定序器)以及子句评估数据通路本身。
Tang Nano 20K:使用 -noalu 构建
本设计可为 Tang Nano 20K 构建(Makefile.synth_tang20k)。它通过了 synth_gowin -noalu,且该标志在此器件上是正确性所必需的——它不是调优开关。完整说明见 KNOWN_ISSUES.md(GW2A-18C 上 yosys ALU 进位单元误编译,已在 YosysHQ/apicula#514 上游得到印证,并非本设计特有)。在对源码、yosys 或约束做任何更改后,请进行验证:
make -f Makefile.synth_tang20k verify # 构建、烧录、运行全部 100 个样本并要求 100/100。
已知限制
本页摘要由 AI 辅助整理,经编辑审核后发布;AI 仅用于提炼与分类,原文均附来源链接。