FPGA基于Verilog语言的有符号乘法运算及时钟工作频率的优化
0 背景
最近程序涉及到有符号数的乘法运算,且乘法因子的位宽超过单个DSP48E支持的位宽(25*18),当然如果采用多个DSP48E级联的模式,则可以进行位宽拓展。 程序中两个有符号的乘法因子的位宽分别为A【38:0】,B【9:0】,程序中直接采用二者相乘的方式进行乘法运算(C <= A*B;);发现ISE综合后,该模块的最大时钟工作频率Fmax约为155MHz,这个明显不是DSP48E最好的性能。
1 原因分析
于是分析,当乘法因子的位宽较大时,为什么直接采用C <= A*B;方式时,会降低模块的最大时钟工作频率Fmax。通过查看Synthesis Report综合后的报告时,发现了原因所在,见下图所示。
由上图可知,Mult_n04231(DSP48E)的输出PCOUT级联到Mult_n04232(DSP48E)的输入PINT,同理,......。由此可知,ISE综合C <= A*B;程序时,采用的就是DSP48E的级联模式。采用DSP48E级联模式计算较大位宽乘法运算,优缺点如下
优点: 由于级联模式,只需一个时钟周期即可运算出C的结果,具有低延时;
缺点: 多个DSP48E级联时,其本质上逻辑阶数会增加,从而造成乘法运算路径所需的时间周期变大,故降低模块的最大时钟工作频率Fmax。
2 解决方法
解决思路: 上文中乘数A的位宽较大,为A【38:0】,既然A位宽超过单个DSP48E支持的上限位宽25bit,那么可以将它人为拆分为2个位宽较小的部分即可。具体步骤见下文。
步骤1: 较大位宽数据拆分2个较小位宽数据A1【21:0】,A2【17:0】。
举例说明: reg signed [38 : 0] A; reg signed [21 : 0] A1; reg signed [17 : 0] A2;
A1 <= A[38:17]; // A1是A的高位部分,A1的符号取决于A的符号;
A2 <= {1'b0, A[16:0]}; // A2是A的低位部分,A2符号始终为正,故用1'b0表示,原因网友可自行分析。
步骤2: 2个较小位宽拆分后的数据分别进行乘法运算
C1<=A1 * B; C2<=A2 * B;
步骤3:将高位部分的乘法运算结果需要进行相应的移位操作(移动位数为 低位部分的位宽)
C3 <= {C1, 17'h0}; C2保持不变;
步骤4:将C2和C3两部分运算结果相加之和,即可得到最终的结果。 C <= C3 + C2。
3 实验测试
将C <= A*B;该代码经过上述思路进行优化后,得到最终的实现结果,ISE综合后,得到的该模块最大时钟工作频率Fmax由上文约155MHz提升为290MHz,很接近DSP48E的上限工作频率,且由下图所示,DSP48E没有采用级联模式了。
同时,为了验证程序优化后的乘法运算的正确性,我单独采用一个小程序进行简单的验证,验证结果如下图所示。
上图中,绿色部分multfac0,multfac1为两个乘法因子,然后将multfac0拆分为multfac0_part0,multfac0_part1两部分分别进行乘法运算,过程如前文所述。最终结果显示:mult_rslt[15:0]为优化后的有符号乘法运算结果,mult_rslt_prev[15:0]为优化前的有符号乘法运算结果。对比可知,二者计算结果相同,前文优化思路满足设计要求(但是首次输出运算结果有3个时钟的延迟)。
结论:优化后的方法能够提高模块的Fmax,那么该方法的优缺点如下。(事情都有两面性!!!)
优点:能够提高模块的最大时钟频率Fmax。
缺点:因为优化后的思路采用3级流水线模式,故第一次运算结果会存在3个时钟的延时;
此外,有网友可能会想,优化后的方法能否减少DSP48E的使用数量? 答案是不能的,可自行分析与仿真测试。
后记
我在编写上述的测试小程序过程中,遇到一个有意思的错误现象。 INTERNAL_ERROR:Xst:cmain.c:3423:1.29
由于是第一次遇到,隐约感觉是代码的问题造成ISE在综合时,出现了错误,这个明显不是语法错误,且该错误不影响程序的仿真。 查找Xilinx官网的解答,发现造成该错误的原因有很多可能性,我这边应该是代码的问题造成的。
于是逐步检查,发现了问题原因: 不同位宽的有符号数不能直接赋值;但是不同位宽的有符号数可以直接加法或乘法运算后再赋值。
举例如下: reg signed [47 : 0] q0; reg signed [26 : 0] q1, q2;
always@(posedge clk) begin q0 <= q1; end 则:ISE在综合时会报错 INTERNAL_ERROR:Xst:cmain.c:3423:1.29
但是,always@(posedge clk) begin q0 <= q1 + q2; 则综合时就没有问题。
原因在于:ISE综合时,会自动将q1,q2的位宽按照q0位宽进行扩展,然后进行运算。 但是为什么直接赋值就不可以,这个我暂时也不能理解ISE工具的原理,如果有网友知晓,请指教,谢谢!!!