一个懂 SystemVerilog、会拼位宽、能显示 12'hABC 的程序员计算器。开源了。


做芯片这行,日常工作里少不了跟进制、位宽、bit mask 打交道。读 AXI 总线地址、手算寄存器域段、验证 CRC 结果——随时都要切进制、移位、拼位宽。

这么多年,我用过的计算器也不少了。Windows 自带的、各种 APP、甚至命令行里的——要么只能十进制,要么把 HEX/BIN 当附加功能草草了事。每次从波形里看到一个值,想算一下它的十进制偏移量,还得先手动记下"这个信号是 12 位的"。

没有一个是从硬件工程师的视角来设计的。所以我自己写了一个。叫 BinCalcX

下面详细介绍一下它的功能,以及一些平时你可能不会注意到的使用小技巧。


一、SystemVerilog 字面量显示

打开 BinCalcX,最先看到的不是按钮,是右边的四行 RPN 堆栈寄存器:

T  64'h0000_0000_0000_0000
Z  64'h0000_0000_0000_0000
Y  64'h0000_0000_0000_0000
X  12'hABC

每一位都带着 位宽前缀和进制标识12'hABC8'b1101_010132'd1000。写 Verilog / SystemVerilog 的人再熟悉不过了——直接复制粘贴进代码,不需要自己加前缀。

HEX 显示还会按 4 位一组自动加空格(0000 0000 0000 0000),BIN 显示按 8 位一组加空格(byte 对齐),大位宽下也不会看花眼。

这和"在普通计算器里切到 HEX、看到一个孤零零的 ABC、然后在心里默念’这是 12 位的’"——是完全不同的体验。

技巧 1:选中 HEX / DEC / OCT 任意一个字段里的文字,直接 Ctrl+C 就能复制对应进制的数值。如果是 BIN 模式,复制的是不带空格的完整二进制串。如果 bit grid 上有拖拽选中的位域,Ctrl+C 复制的是这个 slice 的值——在写 #define GPIO_MODE_MASK 0x... 的时候极其方便。

技巧 2Ctrl+V 粘贴时,支持 C 风格前缀(0x0b0o),也支持在数字中间加分隔符——0xDEAD_BEEF0b1010_0101 都能正确解析。还支持开头带 +/- 符号,粘贴一个负数会自动转成当前位宽的补码。从代码里复制一个常量过来,什么都不用改。


二、逐寄存器位宽 & 硬件操作

这是 BinCalcX 跟所有其他计算器最根本的区别:每一个寄存器(T / Z / Y / X)都有自己独立的位宽,范围 1 到 64。

为什么这很重要?

硬件里,不同信号的位宽是不一样的。一个 12-bit 的 address 和一个 4-bit 的 burst length 拼接在一起,是一条 16-bit 的总线。传统计算器只能记住一个全局位宽,一旦你切换去算另一个域段,之前那个位宽信息就丢了。

BinCalcX 里,X 寄存器位宽是 12,Y 寄存器位宽是 4,然后做 concatenation:

X = 12'hABC    (宽度 12)
Y = 4'h3       (宽度 4)
→ 按 {,}(concatenate)
X = 16'h3ABC   (宽度 16,结果位宽 = Y宽度 + X宽度)

{,} 操作符就是 SystemVerilog 里的 {Y, X},自动按各自位宽拼接。还有一个 {N} 复制操作:

X = 8'hFF     (宽度 8)
Y = 32'd4     (Y 的值作为重复次数)
→ 按 {N}(replicate)
X = 32'hFFFF_FFFF  (宽度 32,X 被复制了 4 次)

写 testbench 生成全 1 的 mask、或者给一个 field 填充重复 pattern 时,这俩操作省掉了大量手工计算。

三个改变 X 位宽的方式

  1. 顶部的位宽按钮 W8 / W16 / W32 / W64:这是最常用的,一下就切到常见总线位宽
  2. 在 bit grid 上拖拽选取一段位域,然后按 {,}{N}:选区先被提取为 X(宽度 = hi - lo + 1,值 shift down 到 LSB 对齐),然后执行拼接/复制操作
  3. {,} 拼接操作的结果位宽:等于两个寄存器的位宽之和

技巧 3:W8/W16/W32/W64 按钮只改变 X 的位宽,不会影响 Y、Z、T。这在做"先把一个 field 提取出来(X=12-bit),再跟另一个 field 拼接(Y=4-bit)“这种多步操作时非常重要——你不会不小心把 Y 的位宽也重置了。

技巧 4:输入数字时,如果超过当前位宽能表示的最大值,按键会被静默拒绝——不会 wrap 回 0,不会截断。比如 8-bit 下你狂按 9,超过 255 之后再按一个数字都输不进去。这防止了手滑多输导致的值错乱。

技巧 5:做完 {,}{N} 之后,X 的位宽可能变得很窄(比如拼接结果是 16 位)。此时如果你开始输入新数字,X 的位宽会自动恢复到 W 选择器的值(比如 64)——新输入用大位宽,不受上一次窄结果的影响。

技巧 6:bit grid 上有拖拽选区时,直接按 {,}{N} 按钮会先把选中的位域提取为 X(覆盖 X 的值和位宽),然后再执行拼接/复制操作。这是一个快捷操作:比如先拖选 address 的 [11:0],按一下 {,},选中的 12-bit field 就作为新的 X 跟 Y 拼在一起了——不需要先 Enter 再操作。

技巧 7:CLx 清除 X 但保留它的位宽;CLR 把所有四个寄存器清零,位宽重置为顶部 W 选择器当前设置的值(默认 64)。写完一个域段的计算、要开始下一组完全无关的计算时,用 CLR 清干净。


三、64 格 Bit Grid——电子草稿纸

顶部的 bit grid 是 4 行 × 16 列,一共 64 个格子,覆盖 64-bit 的全部位。

设计决策:格子里不写 0/1

传统 bit 显示在每个格子里写 01,但 64 个格子挤在一起时,数字会变得很小,而且 01 视觉上差别不大,扫一眼很难看清 pattern。

BinCalcX 的方案是格子内不填文字,纯靠明暗:亮起来的格子(bit=1)用当前进制对应的主题色填充,暗的格子(bit=0)是一个淡灰色边框。眼睛扫过去,亮色的分布就是 bit pattern——跟看逻辑分析仪或者波形图的思路一致。

颜色锚定:切换进制,一看就知道在哪

每种进制有一套独立的主题色,不是只在标签上变色——整个界面里跟"当前活跃数据"相关的东西全部统一着色:

进制 主题色 着色的元素
HEX 绿色 HEX 字段、bit grid 亮格、ENTER 键、X 寄存器
DEC 蓝色 DEC 字段、bit grid 亮格、ENTER 键、X 寄存器
OCT 琥珀色 OCT 字段、bit grid 亮格、ENTER 键、X 寄存器
BIN 紫色 bit grid 亮格、ENTER 键、X 寄存器

你在 HEX 下操作,整个界面的"信号色"就是绿的;切到 DEC,一切变成蓝的——视觉上不可能搞混当前进制。这个设计借鉴了示波器上不同通道的颜色逻辑。

Nibble 分组 & Byte 边界

每 4 个 bit 之间有一个 6px 的额外间距,每 8 个 bit(一个 byte)用交替的底色阴影区分。这样扫一眼就能定位到一个具体的 byte 或者 nibble。

顶部还有灰色的 nibble 轴标签——63595551……标记了每个 nibble 的最高位——方便做域段提取时数 bit 位置。

超出位宽的格子是灰的

64 个格子始终全部显示,但超出当前 X 寄存器位宽的格子会灰色淡出。这像一个硬件截断的视觉提示:当前只关心低 12 位,高 52 位不存在。

技巧 8:鼠标悬浮在任意格子上,底部状态栏显示 Bit: 37 | Mask: 0x0000_0020_0000_0000。不用心算 1 « 37 等于多少,直接复制 mask。状态信息会在鼠标移开后 2.2 秒自动清除,不会常驻占用空间。

技巧 9拖拽选取(按下鼠标左键在 grid 上滑动)是最常用的操作之一。选中一段位域后:

  • 状态栏实时显示 slice 的 DEC / HEX / BIN 值(如 Bits 15..8 = 255 0xFF 0b11111111
  • X 寄存器同步显示这个 slice 的 SV 字面量(如 8'hFF
  • Ctrl+C 复制这个 slice 的值(当前进制格式)
  • Enter 把它 push 到 Y(X 不变)
  • Esc 取消选择 这对应的就是日常里"看一眼寄存器的 [15:8] 域段是什么值”——拖一下,数字就出来了。

技巧 10:Bit grid 支持全键盘操作。方向键移动焦点环(一个高亮轮廓),空格键翻转当前聚焦的 bit。调一个 #define MASK (1 << 7) 的时候,键盘按几下方向键再按空格——比鼠标点快得多。

技巧 11:连续两次 Esc:第一次取消 bit grid 上的选区(如果有的话),第二次才是 CLR 全部清零。这个防止了误操作——你正在看一个 slice,不小心碰到 Esc,不会把整个栈清掉。

技巧 12:在 grid 空白区域(格子之间的缝隙、边距)点击左键,也会取消当前选区——鼠标党不想伸手去按 Esc 的快捷操作。

技巧 13:bit grid 上的选区不受切换进制影响——你在 HEX 下拖选了 [15:8],切到 BIN 下这些格子仍然高亮。选区锁定的是 bit 位置,不是数值。


四、四个进制同时可见

Bit grid 下方一行排开三个活跃显示字段:HEXOCTDEC,加上最右边的 CHR(ASCII 字符解码),旁边还有 Signed 模式复选框。

当前激活的进制字段高亮(带主题色背景),但三个进制的值同时可见,不需要来回切换去对照。在 HEX 下输入一个地址,DEC 和 OCT 的等效值就在旁边。

CHR 字段

固定显示 8 个字符,对应 64-bit 从高到低每一个字节的 ASCII 解码。可打印字符直接显示,不可打印的(NUL、控制字符等)显示为居中的 ·。字段宽度锁定,不会因为内容变化而跳动错位。

技巧 14:写 C 的字符串常量或者调 UART 输出时,CHR 字段直接告诉你这个 64-bit 值对应的 8 个字符是什么——ASCII table 不用查了。

技巧 15:Signed 模式是纯显示层的功能——它不影响内部存储的值,只改变显示时的符号解释。同一个 0xFF,Unsigned 下显示 255,Signed、位宽 8 下显示 -1。这个开关可以随时切换,不影响计算。


五、RPN 堆栈——习惯了就回不去

BinCalcX 采用 HP 计算器风格的 RPN(逆波兰)逻辑,4 级堆栈 T·Z·Y·X。

RPN 怎么用?

没有等号键。输入一个数字,按 Enter 把它 push 上栈,再输入第二个数,然后按操作符:

12 ENTER 5 +   → 17        (计算 12+5)
FF XOR 0F      → F0        (在 HEX 下,直接对 X 和输入值做 XOR)
200 ENTER 100 + (位宽 8) → 44  (300 & 0xFF = 44,自动 mask)

为什么用 RPN?

做了硬件验证的同事对 stack 操作有天生的亲切感——这不就是 push/pop 吗。RPN 最大的好处:

  • 不需要括号(3+5)*(7-2) 在 RPN 里是 3 ENTER 5 + 7 ENTER 2 - *,中间结果一直在栈上
  • 中间结果可见:每一步的结果都在 X 寄存器里,T/Z/Y 三级栈保留之前的上下文
  • 跟硬件思维一致:你推一个值上去,做操作,结果落在 X——跟 ALU 的数据流是一个方向

栈操作一览

操作 按键 / 快捷键 效果
Enter Enter 键或按钮 复制 X 到 Y,原 Y→Z,原 Z→T,原 T 丢弃
Roll Down (Rv) R 栈循环下移:T→Z, Z→Y, Y→X, X→T
Swap (X↔Y) S 交换 X 和 Y,各自的位宽也交换
CLx Delete 键 X 清零,保留位宽
CLR Esc 全部清零,位宽重置为 W 选择器当前位宽

技巧 16:在 BIT 模式下,界面没有输入字段——所有输入通过 bit grid 点击或键盘来进行。此时 Ctrl+C 复制的是完整二进制串(无空格分隔)。

技巧 17RS 键是纯键盘操作,按一下就能在栈上轮转或交换。习惯以后,做连续多步计算时,键盘敲击节奏非常顺畅——跟用文本编辑器一样。


六、运算符 & 其他功能

算术 & 逻辑

操作 按钮 快捷键 说明
加/减/乘/除/模 + - * / MOD 对应符号键 Y op X → X,结果位宽 = max(Y位宽, X位宽)
AND / OR / XOR And Or Xor & | ^ 按位逻辑,Y op X
NOT Not ~! 对 X 按位取反,一元操作

移位

有两种移位,功能不同,不要搞混:

操作 按钮 快捷键 行为
SHL / SHR << >> < >( ) 二元移位:Y 是被移位的值,X 是移位量;Y « X
◀ / ▶ 小三角按钮 无(鼠标点击) 原地单步移位:X 左移或右移 1 位,盖写 X

技巧 18:◀ ▶ 原地移位在 Signed 模式下,右移是算术移位(符号扩展),Unsigned 模式下是逻辑移位(补零)。这和 SystemVerilog 里 >>> vs >> 的语义一致。比如 8-bit Signed 下 0x80(-128)按 ▶ 变成 0xC0(-64),保持负数。注意左移 ◀ 永远是逻辑移位(直接截断高位),不受 Signed 影响——0x80 << 1 在 8-bit 下永远是 0x00,不像硬件里的带符号左移。

关于二元移位 SHL/SHR<< >> 是把 Y 移 X 位,结果位宽保持 Y 的位宽。如果移位量 X ≥ Y 的位宽,结果直接为 0(移位量被 Y 的宽度 clamp,不会做超宽移位)。

关于除法和取模:除 0 或模 0 不会报错,结果直接返回 0。不是 bug,是刻意为之——验证环境里除数偶尔为 0 是正常情况,弹个报错还不如静默返回 0 然后继续算。

其他操作

操作 快捷键 说明
Negate (+/-) N_ 对 X 做二进制补码取反,在位宽内
Backspace Backspace 删除最后输入的一位数字

七、键盘快捷键完整清单

所有操作都能在键盘上完成,手不用移开:

按键 功能
09, AF 输入数字(BIN 模式下只接受 0/1)
+ - * / % 算术运算
& | ^ AND / OR / XOR
~! NOT
< ( 左移(SHL)
> ) 右移(SHR)
R Roll Down
S Swap X↔Y
N_ Negate
Enter ENTER(或有选区时 push slice→Y)
Backspace 删除一位
Esc 取消选区 / 全清(CLR)
Delete CLx
← ↑ ↓ → 在 bit grid 上移动焦点
Space 翻转焦点 bit
Ctrl+C 复制(当前值或选区)
Ctrl+V 粘贴(支持 0x/0b/0o 前缀)
Ctrl+T 切换置顶模式

八、主题 & 外观

  • 深色主题:底色 #1E1E1E,和 VS Code 默认主题完全一致。写 RTL 的时候开在编辑器旁边,不会有任何违和感。
  • 浅色主题:写文档需要截图时一键切过去。
  • 等宽字体:所有数字和标签用 monospace,多行数值严格对齐。
  • 紧凑布局:窗口尺寸做了上限(大约 484×444),常年挂在角落不占屏。
  • Ctrl+T 置顶:看 Verdi/Debussy 波形时让计算器浮在最上面,不用来回 Alt+Tab。
  • 偏好持久化:主题、进制、位宽、Signed 模式、置顶状态——关掉重开全部自动恢复。

九、开源

  • 基于 Qt 6 (Widgets) + C++17,MVC 架构,代码量不大,结构清楚
  • Windows 下载 zip 解压即用
  • Linux qmake6 && make -j
  • MIT 协议,随便用,随便改

GitHub:github.com/himingway/BinCalcX


做芯片设计这么多年,一直在用别人写的工具。有些很好用,有些凑合用,但始终缺一个真正从硬件视角出发的计算器。于是自己动手写了一个。现在把它开源出来,希望能帮到有同样需求的同行。

欢迎 Star ⭐,也欢迎提 issue 和 PR。