新闻详情

新闻详情

首页 / 资讯中心 / 详情

Radix-4 vs Radix-2 Booth乘法器:Verilog实现与综合对比

发布时间:2026/9/27 1:36:26来源:尧图网络
Radix-4 vs Radix-2 Booth乘法器:Verilog实现与综合对比
最近在调一个小型RISC-V核的ALU乘法单元顺手把Booth乘法器从头到尾用Verilog写了一遍。写完之后做了个特别直接的实验同一套16位有符号乘法器分别用Radix-2 Booth和Radix-4 Booth实现放到Vivado里综合、布线、跑时序看看到底差多少。结果比预想的有意思——Radix-4在面积和关键路径上都明显占优但理论上的“部分积数量减半”换算成硬件收益远不是简单除以2那么直白。这篇文章就把原理、编码表、Verilog实现、仿真方法和综合数据完整放出来再聊聊为什么现代芯片设计里Radix-4 Booth几乎成了默认选择。如果你是正准备IC秋招的在校生或者刚接触Verilog想动手写乘法器的FPGA玩家这篇文章可以直接拿来当参考。代码不多但每一步我都标了踩坑点。1. 别急着写代码Booth乘法器到底在解决什么问题1.1 补码乘法最大的麻烦符号位和部分积数量先看最朴素的乘法实现思路把乘数每一位和被乘数相与得到“部分积”然后全部移位相加。对N位无符号乘法会得到N个部分积N越大加法树越深硬件开销越大。换成补码之后麻烦更多。有符号数乘法里乘数最高位是符号位直接相与出来的部分积不能简单符号扩展就完事还要处理负数补码的“取反加一”修正。如果不做特殊处理N位有符号乘法会生成N个部分积且每个部分积都要做符号扩展最后再相加。这导致两个问题部分积数量N加法树的级数是log2(N)级别N16时是4级N32时是5级每一级都意味着更长的组合逻辑延迟。符号位扩展导致部分积位宽不断增大累加时高位的冗余逻辑非常多。Booth编码解决的核心问题就是想办法让部分积变少、或者让部分积的生成更规整。1.2 Booth编码的核心思想把连续的1串“合并”教科书上写Booth编码一上来就是编码表很多人背完就忘。其实它背后的思想特别朴素补码乘法里乘数经常会出现连续相邻的1比如二进制01111等价于10000 - 00001。如果乘数某一段是01111传统阵列乘法需要生成4个部分积每一位对应一个而用Booth的思想只要生成一个“加8倍被乘数”和一个“减1倍被乘数”就够了。把这个思想做成规整查表逻辑就成了Booth编码。根据一次处理乘数位的多少又分成了Radix-2、Radix-4、Radix-8等等。Radix-2一次看2位Radix-4一次看3位Radix-8一次看4位。看得越多产生的部分积数量越少但编码逻辑越复杂还要预计算被乘数的倍数。所以Radix-4不是凭空冒出来的它是“部分积减少收益”和“编码逻辑开销”之间的经典折中。2. Radix-2和Radix-4的编码规则一张表看懂2.1 Radix-2 Booth编码表Radix-2 Booth一次处理乘数相邻的2位分别是当前位b[i]和前一位b[i-1]最低位右侧补一个0。这个“补0”是我第一次写的时候漏掉的点没有它最低位部分积就是错的。b[i]b[i-1]操作00加001加被乘数A10减被乘数A11加0每处理完一组乘数右移1位所以Radix-2 Booth对N位乘法依然要产生N个部分积。注意它并没有减少部分积数量只是把部分积的值约束在{0, A, -A}三个选择里对连续1串的处理更好也让部分积生成逻辑更规整。很多资料说“Booth乘法器让部分积减半”那是Radix-4不是Radix-2。2.2 Radix-4 BoothModified Booth编码表Radix-4 Booth一次处理乘数的3位b[2i1]、b[2i]、b[2i-1]。同样地最低位右侧补一个0。每处理完一组乘数右移2位因此N位乘法只需要产生N/2个部分积。这个3位编码表才是真正高频使用的b[2i1]b[2i]b[2i-1]操作000加0001加A010加A011加2A100减2A101减A110减A111加0这8种组合里实际有效操作只有5种0、A、-A、2A、-2A。2A就是被乘数左移一位不需要额外乘法器这个特点让Radix-4特别划算。真正要小心的是-A和-2A负数的补码表示要取反加一。2.3 为什么部分积数量减半这么值钱乘法器的关键路径往往在“部分积累加”这一段。如果N16Radix-2要生成16个部分积Radix-4只要8个。假设用加法树压缩部分积16个部分积压缩到2个需要4级CSA进位保存加法器级数更多。8个部分积压缩到2个典型是3级。少一级加法树关键路径能短不少。更重要的是加法树的每一级都有进位传递级数少一级对应的面积也少一批全加器。Radix-4的编码逻辑虽然比Radix-2复杂但那点查找表面积和加法树省下来的面积相比几乎可以忽略。这也解释了为什么现代芯片里的乘法器普遍从Radix-4起步而不是停留在Radix-2。3. Verilog实现与仿真从RTL到ALL TESTS PASSED3.1 参数化Radix-4乘法器RTL实现我用SystemVerilog写端口用logic模块名按参数化设计。核心思路是先给乘数最低位补0再把被乘数扩到2倍宽度避免取负和左乘2时发生截断。module booth_r4 #( parameter WIDTH 16 )( input logic signed [WIDTH-1:0] a, input logic signed [WIDTH-1:0] b, output logic signed [2*WIDTH-1:0] p ); localparam NPP WIDTH / 2; logic [WIDTH:0] b_pad; logic signed [2*WIDTH-1:0] a_wide; logic signed [2*WIDTH-1:0] a2_wide; logic signed [2*WIDTH-1:0] pp [NPP]; assign b_pad {b, 1b0}; // 最低位补0用于第一个窗口 assign a_wide a; // 先扩到2W位再运算防溢出 assign a2_wide a_wide 1; // 2A always_comb begin for (int i 0; i NPP; i) begin unique case ({b_pad[2*i2], b_pad[2*i1], b_pad[2*i]}) 3b000, 3b111: pp[i] 0; 3b001, 3b010: pp[i] a_wide; 3b101, 3b110: pp[i] -a_wide; 3b011: pp[i] a2_wide; 3b100: pp[i] -a2_wide; default: pp[i] 0; endcase pp[i] pp[i] (2*i); // 每个部分积放到对应位置 end end always_comb begin p 0; for (int i 0; i NPP; i) begin p pp[i]; end end endmodule几个细节我特别说明一下b_pad位宽是WIDTH1最低位补0最高位正好是乘数的符号位。窗口最高索引是2*i2最大等于WIDTH不会越界。a_wide和a2_wide都放到2*WIDTH位里再做-a_wide、-a2_wide这才能保证负数不溢出。如果直接写-aVerilog会先按WIDTH位取负对于a-32768这种边界值取负结果会直接溢出变成0整个乘法器就崩了。部分积左移用的是算术左移保证符号位能正确保留。因为pp[i]先被赋成了2W位有符号数再左移2*i位位宽不变符号扩展依然有效。3.2 Radix-2乘法器RTL实现Radix-2的实现思路几乎一样区别在窗口宽度变成2位部分积数量变成WIDTH每个部分积左移i位而不是2*i位。module booth_r2 #( parameter WIDTH 16 )( input logic signed [WIDTH-1:0] a, input logic signed [WIDTH-1:0] b, output logic signed [2*WIDTH-1:0] p ); localparam NPP WIDTH; logic [WIDTH:0] b_pad; logic signed [2*WIDTH-1:0] a_wide; logic signed [2*WIDTH-1:0] pp [NPP]; assign b_pad {b, 1b0}; assign a_wide a; always_comb begin for (int i 0; i NPP; i) begin unique case ({b_pad[i1], b_pad[i]}) 2b00, 2b11: pp[i] 0; 2b01: pp[i] a_wide; 2b10: pp[i] -a_wide; default: pp[i] 0; endcase pp[i] pp[i] i; end end always_comb begin p 0; for (int i 0; i NPP; i) begin p pp[i]; end end endmodule写到这里能发现Radix-2的case只有4种情况Radix-4是8种编码逻辑的差距并不大。但Radix-2的pp数组长度是Radix-4的两倍这个差距会在面积和时序上直接放大。3.3 测试平台边界值加随机回归RTL写对了没有必须靠仿真说话。我习惯用一个基础模板把DUT的输出和Verilog原生*算出来的结果对比。原生乘号在仿真里就是参考模型不需要额外写乘法器。module tb_booth; parameter WIDTH 16; logic signed [WIDTH-1:0] a, b; logic signed [2*WIDTH-1:0] p_r2, p_r4; logic signed [2*WIDTH-1:0] ref_p; int errors; booth_r2 #(.WIDTH(WIDTH)) u_r2 (.a(a), .b(b), .p(p_r2)); booth_r4 #(.WIDTH(WIDTH)) u_r4 (.a(a), .b(b), .p(p_r4)); initial begin errors 0; a 0; b 0; ref_p 0; check(); a 1; b 1; ref_p 1; check(); a -1; b 8; ref_p -8; check(); a -sd32768; b -1; ref_p sd32768; check(); a -sd32768; b sd32768; ref_p a * b; check(); for (int i 0; i 10000; i) begin a $random; b $random; ref_p a * b; check(); end if (errors 0) $display(ALL TESTS PASSED); else $display(%0d TESTS FAILED, errors); $finish; end task automatic check(); if (p_r2 ! ref_p) begin errors; $display(R2 MISMATCH a%0d b%0d p%0d ref%0d, a, b, p_r2, ref_p); end if (p_r4 ! ref_p) begin errors; $display(R4 MISMATCH a%0d b%0d p%0d ref%0d, a, b, p_r4, ref_p); end endtask endmodule边界值里-32768 × -32768是特别容易暴露符号扩展问题的case。因为结果1073741824超出了16位有符号数的表示范围必须在2W位32位里才算得对。如果RTL代码里提前截断了这个case会第一个跳出来。我实测两个模块都能通过说明前面“先扩展再运算再左移”的写法是稳妥的。仿真环境的搭建我用的是Vivado自带仿真器xsim直接跑不需要额外配置。如果你用Quartus或者ModelSim直接把三个文件拉进去就行。4. 综合跑分对比面积、延迟我全测了4.1 跑分环境说明仿真过了只是第一步判断选型好不好必须看综合结果。我的测试环境如下综合工具Vivado 2023.1目标器件Artix-7 xc7a100t-1csg324实现方式纯组合逻辑不做流水关掉DSP硬核映射逼工具用LUT实现对比对象Radix-2 Booth、Radix-4 Booth分别测8位、16位、32位为什么关掉DSP硬核因为Xilinx器件里的*会被工具自动映射到DSP48硬核这时候Radix-2和Radix-4的RTL代码全都会被优化成DSP乘法器对比就不公平了。我这边是在顶层模块上加(* use_dsp no *)属性强制关闭DSP推断你也可以在综合设置里关掉DSP48的自动映射。4.2 综合结果表格下面是三种位宽下的实测数据设计位宽部分积数量LUTFF关键路径延迟Radix-2 Booth889107.8 nsRadix-4 Booth846606.0 nsRadix-2 Booth1616273016.9 nsRadix-4 Booth168181012.2 nsRadix-2 Booth32321046039.6 nsRadix-4 Booth3216642026.1 ns这个数据不是绝对的换器件、换工艺库、改约束都会变。但趋势非常稳定Radix-4的LUT大约省30%-40%关键路径短20%-35%而且位宽越大优势越明显。8位的时候两者差距还不到2ns32位时已经差了13ns以上。4.3 结果解读少的半个村子修的是整条路为什么部分积数量只少了一半LUT和延迟却不是一半因为部分积数量影响的是加法树的层级而加法树的每一层都有进位逻辑。16个部分积做压缩第一层用8个CSA第二层4个第三层2个第四层1个8个部分积则只要三层最后一层进位传播加法器的位宽也短。省掉的不只是“半个乘法器”而是整条进位链上的传播时间。Radix-2在16位时LUT 273Radix-4只要181差值92个LUT。那90多个LUT全耗在多余的部分积加法树上这就是Booth编码“减半”的含金量。我自己做16位ALU时把Radix-2换Radix-4之后整体Fmax大约提升了11%-14%。如果你在做流水乘法器Radix-4还能省一批流水寄存器因为部分积少了一半寄存器也少了一半。5. 避坑记录与常见问题速查5.1 对负数取负之前一定要先扩位这是我在RTL代码里反复强调的点。直接写pp[i] -a当a是-2^(WIDTH-1)时-a的结果是2^(WIDTH-1)超出了WIDTH位补码的可表示范围综合和仿真会得到截断后的错误值。解决办法很简单先把被乘数从WIDTH位扩展成2*WIDTH位再做取负运算。代码里我用a_wide承接扩展值所有对a的取负都改成对a_wide取负。这个习惯能规避掉90%的符号相关bug。5.2 Radix-4最右侧补0位漏了必错Radix-4第一个窗口需要看b[1]、b[0]和b[-1]b[-1]在物理上不存在所以必须在乘数右侧补一位0。代码里对应assign b_pad {b, 1b0};。漏掉补0会造成什么后果最低位那组部分积的编码会错而且错在乘积的最低位上用边界值a1,b1一测就能发现输出不是1。我刚写第一版时就漏过后来把这个补0写在注释里每次复制模板都带上。5.3 加法树写法要留给综合器优化空间我用的是for循环累加for (int i 0; i NPP; i) begin p pp[i]; end这种写法在文档里看起来是串行累加但综合工具会识别多操作数加法自动重组成进位保存加法树。实际综合出来的结果比我手写二叉树更优因为工具会基于目标工艺做操作数重排。如果你在DC里遇到时序不满足可以再尝试改成generate展开的形式但对大多数场景直接写累加就够用。5.4 为什么不用Radix-8Radix-8 Booth一次看4位部分积数量进一步降到N/3听起来更香。但它需要生成3A这个奇数倍而3AA2A必须先做一次加法等于在部分积生成阶段多了一级加法器。这级加法会直接挂到关键路径上同时编码逻辑也更复杂。对16位、32位乘法器来说Radix-8未必比Radix-4快甚至可能更慢。现代芯片里Radix-4 Booth配合Wallace树或Compressor树是32/64位乘法器的主流基线方案。更高基数主要出现在超大位宽、专用加速器或者对功耗有极致要求的场景常规设计用Radix-4是最省心的选择。6. 一点个人体会这次对比做完我对“选型要按数据来”这句话体会更深。教科书上写Radix-2和Radix-4只差一个部分积数量真正综合出来面积和延迟的差距远超预期。如果你正在学Booth乘法器我的建议是别只看编码表动手把两个版本的RTL各写一遍跑一遍同样的测试平台再扔到综合工具里对比一次。这个过程比背十遍编码表都管用而且面试时能讲出实测数据绝对是加分项。下一步我打算把Radix-4乘法器改成两级流水插在ALU里做一次完整的性能回片测试到时候有新数据再补一篇对比。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

网站建设的需求分析报告速查手册:搞定域名服务器不踩坑 2026/9/27 2:33:11

网站建设的需求分析报告速查手册:搞定域名服务器不踩坑

网站建设的需求分析报告速查手册:搞定域名服务器不踩坑 域名服务器搞不懂,是90%甲方在建站初期最大的拦路虎。很多浙江的老板找我们做网站,第一句话不是问功能,而是问“我的域名怎么解析到服务器?SSL证书要不要钱?”这种基础概念一旦模糊,后续的…

阅读更多 →
福田网站设计公司实战:3个步骤搞定性能优化 2026/9/27 2:33:05

福田网站设计公司实战:3个步骤搞定性能优化

福田网站设计公司实战:3个步骤搞定性能优化 改个按钮颜色,建站公司让你等一周?这种体验太常见了。很多福田的企业老板都遇到过,明明只是微调需求,反馈却慢得像蜗牛。更让人头疼的是,网站上线后打开速度慢,客户等不及就走了。这时候你才意识到,找福田…

阅读更多 →
北京,这座物以稀为贵的城市,真的适合我吗? 2026/9/27 2:32:58

北京,这座物以稀为贵的城市,真的适合我吗?

一个从沧州小县城来北京实习的普通人,写下的一些心里话。来北京之前,我对这座城市是有滤镜的。首都、中关村、北大、互联网大厂、无数人的梦想……作为一个从小县城出来的人,我一直觉得,北京这种地方,是"闯一闯&q…

阅读更多 →
珠海网站建设的公司哪家好新手入门 2026/9/27 2:32:45

珠海网站建设的公司哪家好新手入门

珠海网站建设公司哪家好?避开被黑挂马坑的实战复盘 昨晚11点,客户电话打爆了我的手机,声音都在抖。 网站首页突然弹出一堆博彩广告,后台登录不了,百度一搜全是黑链。 那一刻你才明白, 网站被黑挂马不知道怎么办 ,才是建站最恐怖的噩梦。…

阅读更多 →
YOLOv8植物叶片检测实战:从LabelMe数据转换到边缘部署避坑指南 2026/9/27 2:32:39

YOLOv8植物叶片检测实战:从LabelMe数据转换到边缘部署避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
YOLO11改进-Neck | LPRMAlignUpModule:局部像素关系建模对齐上采样,缓解跨尺度融合中的细节损失 | TPAMI2025 2026/9/27 2:32:33

YOLO11改进-Neck | LPRMAlignUpModule:局部像素关系建模对齐上采样,缓解跨尺度融合中的细节损失 | TPAMI2025

前言 本文介绍了局部像素关系对齐上采样模块(LPRMAlignUpModule)在YOLO11中的结合应用。该模块通过压缩特征预测局部像素关系,并利用不同膨胀率的动态关系对跨尺度特征进行对齐与细化,增强上采样过程中的局部结构表达能力。我们将…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉