从零开始构建科学计算器:一段 FPGA 之旅

在智能手机无处不在的时代,制造一台科学计算器通常被视为一个已解决的问题。然而,对于硬件爱好者来说,它代表了一场全栈工程的大师课——涵盖了数值分析、计算机体系结构、数字逻辑和物理 PCB 设计。

受复古 HP-41CV 的触感启发,zdw 详细描述的项目是对如何使用 FPGA 从头开始构建一台 16 位 BCD(二进制编码十进制)计算器的全面探索。该项目并非依赖通用微控制器,而是实现了一个定制的 CPU 和一套专门为十进制算术量身定制的指令集。

基础:数值方法与路径探索

在编写任何一行硬件描述语言 (HDL) 之前,任何严肃的工程项目都需要一个“路径探索”阶段。这是一个通过原型设计、失败和发现可能性边界的迭代过程。在这个项目中,主要的挑战是确保像 tanlnexpsqrt 这样的复杂函数仅通过基础的加、减、乘法即可计算出来。

为了实现 16 位精度,作者开发了一个经过验证的 C++ 参考实现。这作为“地面真值” (ground truth),用于最终对硬件进行测试。这个阶段至关重要,因为调试硬件比调试软件要困难几个数量级;拥有一个数学上的金标准可以防止开发者在结果略有偏差时,在逻辑中“寻找幽灵”。

开发框架

FPGA 开发中最显著的障碍之一是反馈循环。为了解决这个问题,建立了一个多环境测试框架,以便在四个不同的平台上运行未经修改的单个 Verilog 源代码:

  • ModelSim: 用于信号级仿真以验证基础逻辑。
  • Verilator: 用于周期精确的 C++ 建模。
  • Qt: 一个桌面原型,具有用于高级交互的调试器控制台。
  • WebAssembly: 允许应用程序在浏览器中运行,以便于分享和访问。

通过利用这些免费工具,开发者可以在订购第一个物理板卡之前就在模拟环境中验证逻辑,从而大大降低了昂贵硬件修订的风险。

设计专用 CPU

大多数现代 CPU 是为二进制浮点运算设计的,这往往会引入在高精度十进制计算器中无法接受的舍入误差。为了避免这一点,作者设计了一个具有独特架构的定制 CPU:

  • Nibble-Addressable Memory: 由于 BCD 表示每个十进制位数为 4 位 nibble,因此内存被设计为在 nibble 级别而非字节级别进行寻址。
  • Custom ISA: 创建了一个 12 位定长指令集,具有 14 种 ALU 操作。这包括 BCD-adjust 指令(受 Intel 8086 启发)以处理十进制算术中固有的进位和借位。
  • Harvard Architecture: CPU 利用独立的指令和数据存储及信号通路,优化了计算过程中的信息流。

从微代码到物理硬件

在定义了 CPU 架构之后,下一步是编写微代码——即告诉硬件如何执行 ISA 的底层指令。由于 CPU 是定制发明,作者必须使用 Python 编写一个两遍扫描的汇编器,将逻辑转换为机器码。

为了管理复杂度,在微代码之上构建了一个脚本解释器层。这使得像 $y^x$ 这样的复杂操作可以被压缩成几行 token,而不是数百行原始汇编。

向物理硬件的过渡是分阶段进行的。它始于一块连接到通过排线连接的定制键盘和 OLED 显示屏的 EP2C5 开发板。最终迭代演变为一台专业的、独立的设备,具有以下特点:

  • 一个直接焊接了 FPGA 的定制 PCB。
  • 一个 3D 打印的外壳。
  • 遵循经典 HP 黄红配色方案的彩色键帽。
  • 双编程接口(用于迭代的 JTAG 和用于持久化 Flash 的 Active Serial)。

追逐最后一位数:2025 年的改进

项目的初始版本实现了大约 12 位精度,但真正的 16 位 BCD 机器需要绝对的精度。2025 年对算术引擎的重写引入了几个关键改进:

  • Guard Digits and Sticky Bits: 实现了适当的追踪机制,以防止舍入误差累积。
  • Banker's Rounding: 一种在数学上更中性的舍入方法,以减少大规模数据集中的偏差。
  • 增强的功能集: 增加了完整的三角函数套件、十个 STO/RCL 内存寄存器,以及基于硬件的 LFSR (Linear Feedback Shift Register) 随机数生成器。

结论

最终结果是一个功能齐全的科学计算器,仅使用了 1,593 个逻辑单元——大约是一个小型、廉 inexpensive FPGA 的 35%。虽然作者指出,物理按键的触感并不完全匹配复古的 HP 硬件,但该项目有力地证明了专门的硬件架构可以根据其解决的问题而完美地塑造。

Sources