在VHDL'93中如何声明可变数量与可变位宽的信号以实现通用加法树?
通用加法树的可变信号处理方案
嘿,我刚好做过类似的通用加法树设计,针对你提到的需要处理可变数量、可变位宽中间信号的问题,咱们可以从核心逻辑到代码实现一步步拆解清楚。
先搞懂核心计算逻辑
要实现通用加法树,关键是先明确每一级中间信号的数量和位宽怎么算:
1. 位宽的规律
每一级的信号位宽其实很好推导:两个n位的数相加,最多会产生n+1位的结果(加上进位)。所以如果初始输入位宽是input_width,那第k级的位宽就是input_width + k。比如你说的8位输入,第一级就是8+1=9位,第二级9+1=10位,完全对应。
2. 信号数量的规律
每一级的信号数量是向上取整的两两分组:比如9个输入,两两相加得到4个结果,剩下1个直接进入下一级,所以第一级是4+1=5个;5个的话两两加得2个,剩1个,就是3个;以此类推。通用的计算方式是next_count = (current_count + 1) // 2(整数除法,自动向上取整)。
用SystemVerilog实现通用加法树
既然是硬件设计中的信号,我用SystemVerilog写个参数化的通用模块,完美适配你的需求:
module generic_adder_tree #( parameter INPUT_COUNT = 4, // 可配置的输入数量 parameter INPUT_WIDTH = 8 // 可配置的输入位宽 )( input logic [INPUT_COUNT-1:0][INPUT_WIDTH-1:0] inputs, output logic [INPUT_WIDTH + $clog2(INPUT_COUNT) -1:0] sum_out ); // 用动态数组存储每一级的中间结果,灵活适配不同数量的信号 logic [INPUT_WIDTH + $clog2(INPUT_COUNT) -1:0] adder_tree[$]; initial begin // 先把所有输入信号放到加法树的第一级 foreach(inputs[i]) begin adder_tree.push_back(inputs[i]); end // 迭代构建每一级,直到只剩一个最终结果 while(adder_tree.size() > 1) begin logic [INPUT_WIDTH + $clog2(INPUT_COUNT) -1:0] next_level[$]; int i = 0; while(i < adder_tree.size()) begin if(i+1 < adder_tree.size()) begin // 两个信号相加,位宽自动扩展(也可以手动指定更严谨) next_level.push_back(adder_tree[i] + adder_tree[i+1]); i += 2; end else begin // 剩下单个信号直接进入下一级,不用加 next_level.push_back(adder_tree[i]); i += 1; end end // 更新当前级为刚计算好的下一级 adder_tree = next_level; end // 最后剩下的就是所有输入的总和 sum_out = adder_tree[0]; end endmodule
关键细节说明
- 参数化设计:通过
INPUT_COUNT和INPUT_WIDTH两个参数,你可以随便改输入数量和位宽,完全通用。 - 动态数组的优势:用动态数组
adder_tree[$]不用提前硬编码每一级的信号数量,不管是4个、9个还是其他数量的输入,都能自动适配。 - 位宽的严谨性:如果不想依赖自动位宽扩展,也可以手动计算每一级的位宽,比如第k级的位宽是
INPUT_WIDTH + k,然后用静态数组声明,但动态数组显然更灵活。
验证你的例子
咱们拿你说的两个场景测试一下:
- 当
INPUT_COUNT=4,INPUT_WIDTH=8时:- 第一级:4个8位信号
- 第二级:2个9位信号(4/2=2)
- 第三级:1个10位信号(2/2=1),和你描述的完全一致。
- 当
INPUT_COUNT=9,INPUT_WIDTH=8时:- 第一级:9个8位信号
- 第二级:5个9位信号((9+1)/2=5)
- 第三级:3个10位信号((5+1)/2=3)
- 第四级:2个11位信号((3+1)/2=2)
- 第五级:1个12位信号((2+1)/2=1),完美匹配你的需求。
这样实现的加法树完全不需要手动去声明每一级的信号,所有中间结果的数量和位宽都是自动计算处理的,非常适合通用场景。
内容的提问来源于stack exchange,提问作者Marph
相关产品推荐
相关产品推荐

