易灵思 DSP48 Block 详解
DSP Block
- DSP模块可以进行乘法、加法、减法、累加、4位可变右移;
4位可变右移模式;
- Normal 模式:支持 1 个通道 (one lane);
- Dual 模式:支持 2 个通道 (two lanes);
- Quad 模式:支持 4 个通道 (four lanes);
每个 DSP 模块有四种模式,支持以下乘法操作:
重要提示: 7 X 6 Quad模式的输出会被截断为12位;
- 3种4位可变右移模式设置:都来源于EFX原语
- EFX_DSP48
- 全功能DSP模块,EFX_DSP48原语可以模拟DSP模块的所有工作模式(NORMAL普通模式、BFLOAT浮点模式、DUAL双路模式、QUAD四路模式);
- 在DUAL/QUAD模式下,需要考虑独立数据通路的物理排布,以及最高有效位(MSB)数据位的特殊处理;
- 自动例化编译
- Efinity自动完成;
- Efinity会将2个DSP24模块或最多4个DSP12模块(在相同时钟、复位信号下)“打包” 成1个DSP48资源;
- 注意:不能混合打包DSP24和DSP12模块;
- 手动例化DSP为DUAL/QUAD模式:
- 注意QUAD四路模式:输出仅12位,若计算结果是13位会被截断,因此计算范围受限;
- 总结:
- EFX_DSP48可以把小DSP(DSP24/DSP12)合并成DSP48,也能手动拆分成双路/四路模式,适配不同位宽的乘法运算(比如 11×10、8×8、7×6、4×4 等),但要注意不同模式下的输入输出位宽限制(尤其是QUAD模式的12位输出截断风险)。
- EFX_DSP24
- EFX_DSP12
- EFX_DSP48
推断DSP
推断乘法器
推断规则:
- 位宽 ≤4 时,推断为EFX_DSP12原语;
- 位宽 ≤8 时,推断为EFX_DSP24原语;
- 位宽 ≤19,18(即19 X 18)时,推断为EFX_DSP48原语;
- 例程:
`define AWIDTH 4 `define BWIDTH 4 module mult(a, b, x); input signed [`AWIDTH-1:0] a; input signed [`BWIDTH-1:0] b; output signed [`AWIDTH+`BWIDTH-1:0] x; assign x = a * b; endmodule
推导乘累加:
- 乘加运算可以被打包到单个EFX_DSP48原语中,因为输入C的位宽适配了EFX_DSP48的C端口的规则;
- 例程:
module dsp_multadd_s(a, b, c, o); input signed [17:0] a; // 输入:18位带符号数a input signed [17:0] b; // 输入:18位带符号数b input signed [17:0] c; // 输入:18位带符号数c output signed [35:0] o; // 输出:36位带符号数o wire signed [35:0] p; // 中间变量:36位带符号数p(存储a*b的结果) assign p = a * b; // 步骤1:a和b相乘,18位×18位=36位 assign o = p + c; // 步骤2:乘积p与c相加,得到最终输出o endmodule
带级联的乘累加:
- 通常这类级联的乘累加运算无法打包到单个EFX_DSP48原语中,因为输入C的位宽不匹配EFX_DSP48的C端口的规则;通过添加syn_use_dsp属性,综合工具会利用另一个DSP模块的A,B,C级联通路实现乘累加功能;
- 例程:
module dsp_multadd_s(a, b, c, o); input signed [17:0] a; // 输入:18位带符号数a input signed [17:0] b; // 输入:18位带符号数b input signed [35:0] c; // 输入:36位带符号数c(位宽超过单个DSP的C端口) output signed [35:0] o; // 输出:36位带符号数o wire signed [35:0] p; // 中间变量:36位带符号数p(存储a*b的结果) (* syn_use_dsp = "yes" *) wire [35:0] sum; // 综合属性:强制使用DSP资源 assign p = a * b; // 步骤1:a和b相乘,18位×18位=36位 assign sum = p + c; // 步骤2:乘积p与36位的c相加 assign o = sum; // 输出结果 endmodule
带输出反馈的乘累加:
- 反馈通路可以将DSP模块的输出取回,重新用于累加运算。可以通过syn_use_dsp属性启用该功能;
- 例程:(实现连续累加)
module dsp_multadd_s(a, b, clk, o); input signed [17:0] a; // 输入:18位带符号数a input signed [17:0] b; // 输入:18位带符号数b input clk; // 时钟信号(用于寄存器同步) output signed [35:0] o; // 输出:36位带符号数o wire signed [35:0] p; // 中间变量:36位带符号数p(存储a*b的结果) (* syn_use_dsp = "yes" *) reg [35:0] sum; // 带DSP属性的寄存器sum(存储累加结果) assign p = a * b; // 步骤1:a和b相乘,18位×18位=36位 always @(posedge clk) begin // 时钟上升沿触发:将“当前乘积p + 之前的累加结果sum”存回sum sum <= p + sum; end assign o = sum; // 输出最终累加结果 endmodule - 每次时钟上升沿,都会把 “当前a*b的乘积” 和 “之前的累加结果sum” 相加,再存回sum;
独立反馈累加:
- DSP反馈通路可将自身输出取回并用于累加运算,输入a被连接到DSP模块的C端口;同时将M_SEL参数设为C、N_SEL参数设为W,并启用了W_REG寄存器。
- 例程:(仅用 DSP 实现的独立反馈累加模块(无乘法,只有累加 + 反馈))
module dsp_add_s(a, clk, o); input signed [17:0] a; // 输入:18位带符号数a(连接到DSP的C端口) input clk; // 时钟信号(同步累加操作) output signed [35:0] o; // 输出:36位带符号数o(累加结果) (* syn_use_dsp = "yes" *) reg [35:0] sum; // 带DSP属性的寄存器sum(存储累加结果) always @(posedge clk) begin // 时钟上升沿触发:将“当前输入a + 之前的累加结果sum”存回sum sum <= a + sum; end assign o = sum; // 输出最终累加结果 endmodule
推导移位器
- DSP 模块在W寄存器与O寄存器之间具备移位功能。以下代码通过将移位值s连接到C端口来推导移位器:需将SHIFTER参数设为1,并使用P_REG与O_REG参数;同时,移位值必须用同一个时钟进行寄存。
- 例程:(**“乘法 + 移位” 功能模块 **利用 DSP 内置移位器实现)
`define SIZEA 8 // 定义输入a的位宽为8 `define SIZEB 8 // 定义输入b的位宽为8 module dsp_shiftout (a, b, s, clk, x); input clk;// 时钟信号 input [`SIZEA-1:0] a; // 输入:8位信号a input [`SIZEB-1:0] b; // 输入:8位信号b input [3:0] s; // 输入:4位移位值s output [`SIZEA+`SIZEB-1:0] x; // 输出:16位结果x(8×8乘法后移位的结果) reg [`SIZEA+`SIZEB-1:0] p1, p2, p3; // 中间寄存器:存储乘法、移位过程值 reg [3:0] sreg; // 移位值寄存寄存器 always @(posedge clk) begin // 时钟上升沿同步操作 p1 <= a * b; // 步骤1:a和b相乘(8×8=16位) sreg <= s; // 步骤2:寄存移位值s(需与运算同时钟) p3 <= p1 >> sreg; // 步骤3:乘法结果p1右移sreg位 end assign x = p3; // 输出移位后的结果 endmodule
推导减法运算
- 由于位宽较窄,软件会推导(调用)DSP12原语。第一个DSP原语执行p2 = d X c的运算,其输出通过 CASCOUT(级联输出)传递到第二个DSP原语;第二个DSP原语负责处理p1 = a X b和x = p1−p2的运算(通过将2’b01赋值给OP输入端口来实现减法)。
- 例程:通过DSP12级联实现的减法模块(基于两次 4×4 乘法的结果做减法)
module dsp_cas_sub (a, b, c, d, x); input [3:0] a, b, c, d; // 输入:4位信号a、b、c、d output [7:0] x; // 输出:8位结果x(4×4乘法结果的减法值) wire [7:0] p1,p2; // 中间变量:8位(存储两次4×4乘法的结果) assign p1 = a*b; // 运算1:a和b相乘(4×4=8位) assign p2 = d*c; // 运算2:d和c相乘(4×4=8位) assign x = p1-p2; // 运算3:两次乘法结果做减法,得到输出x endmodule
推导宽位宽乘法器
- 对于位宽超过 18×17 的乘法运算,软件会将其分解为多个更小的运算单元;随后,软件会对这些部分积(部分和) 进行累加,最终得到完整的乘积结果。
- 例如:一个 32×32 的乘法运算会被拆解为 4 个更小的乘法运算和 3 次累加运算。
- 默认情况下,这些部分积的累加操作会利用 DSP 模块的后加法器特性以及 DSP 模块之间的级联通路在 DSP 模块内部完成。
- 由于较长的组合逻辑级联通路可能会导致最高工作频率(fMAX)降低,可以在DSP运算中插入流水线寄存器,以额外的延迟为代价,提升数据吞吐量(即提高 fMAX);
浮点运算
- DSP 模块支持BFLOAT16格式(精简16位浮点格式)的融合乘加(FMA)操作。BFLOAT16被映射为16位,格式如下列图示:
第 15 位是符号位,14-7 位是指数位,6-0 位是尾数位;
3. 若要使用该功能,必须手动实例化EFX_DSP48原语,并将MODE参数设置为BFLOAT。在此模式下:
1. DSP模块的输入A、B、C需为BFLOAT16格式;
2. 最终输出O为32位浮点格式(FP32),这是因为内部累加用 FP32 执行,避免 BFLOAT16 尾数过短导致的精度损失;
3. 内部累加运算以32位浮点精度执行;
4.除O_REG外,所有流水线寄存器必须启用,才能保证操作正确;
4. ```verilog
EFX_DSP48 dut (
.A(a), .B(b), .C(18’d0), .OP(op), .O(o), .CASCIIN({48{1’b0}}),
.CLK(clk), .RST(rst), .CE(1’b1), .SHIFT_ENA(1’b0)
);
defparam dut.MODE = “BFLOAT”;
defparam dut.M_SEL = “P”;
defparam dut.N_SEL = “W”;
defparam dut.W_SEL = “X”;
defparam dut.A_REG = 1;
defparam dut.B_REG = 1;
defparam dut.C_REG = 0;
defparam dut.P_REG = 1;
defparam dut.OP_REG = 1;
defparam dut.W_REG = 0;
defparam dut.O_REG = 1;
defparam dut.RST_POLARITY = 1;
5. 代码中A_REG=1、B_REG=1等配置(除O_REG外均启用)是必须的:- 这些寄存器是 DSP 的流水线单元,用于同步输入 / 运算数据,避免长组合路径导致的时序错误;
- 若未启用,BFLOAT 模式下的运算时序会紊乱,最终结果错误;
- DSP 模块支持BFLOAT16格式(精简16位浮点格式)的融合乘加(FMA)操作。BFLOAT16被映射为16位,格式如下列图示:
有效使用DSP模块
- EFX_DSP24和EFX_DSP12原语被打包到同一个EFX_DSP48中,需要满足:
- 待打包的EFX_DSP24/12的时钟、CE(时钟使能)、RST(复位)、SHIFT_ENA(移位使能)、OP输入必须是相同的信号网络;这些端口可以接VCC、GND或断开,只要所有原语的配置匹配即可;
- 所有 DSP 原语的 Verilog HDL 参数必须匹配,包括寄存器端口(A_REG、B_REG、W_REG)和工作模式;
- 约束质量
软件不会随机打包DSP模块 —— 这会负面影响fMAX(最高工作频率)。相反,它会优先打包逻辑相关的DSP模块(例如共享相邻模块、共享输入网络的原语),从而形成在FPGA上适配性最佳的集群。 - 提升打包密度方法
- 调整设计,让更多DSP模块拥有一致的控制信号和模式设置(例如避免让综合工具为每个EFX_DSP24/12推导独特的时钟使能),使它们满足打包条件;
- 将综合选项–dspinput-regs-packing、–dsp-output-regs-packing、–dsp-mac-packing设为 0;这会提升打包密度,但代价是触发器和加法器的资源消耗增加。这些选项可在 “项目编辑器> 综合” 标签页中设置;
- 可以根据报告进行辅助调试:
- place.rpt:包含 DSP 打包摘要,显示 “忽略控制信号和属性相关的合法性约束时可打包的 DSP 模块数量”—— 这个数字能帮你判断 “调整设计提升打包密度” 是否可行(实际中,调整设计通常能提升约 50% 的打包密度)。报告还会列出每个 DSP 模块的控制集和属性:EFX_DSP24/12 要被打包,必须拥有匹配的控制集和属性。你可以通过这份报告找出 “与其他模块不共享控制集 / 属性的 DSP 模块”,再查看dsp_control_sets.csv获取详细的调整建议;
- dsp_control_sets.csv:这是一个 CSV 格式的表格,列出了每个 DSP 模块的所有控制信号和属性。你可以用电子表格打开它,识别出 “因设置独特而无法打包” 的 EFX_DSP24/12 原语;
- EFX_DSP24和EFX_DSP12原语被打包到同一个EFX_DSP48中,需要满足:
时序考量
- 高DSP模块利用率下的时序收敛:如果设计中超过50%的 DSP 模块是用EFX_DSP24或EFX_DSP12原语实现的,fMAX(最高工作频率)会因布局种子(placement seed)的不同而显著变化。可以进行“种子扫描” ;
- 宽乘法器的处理:当乘法器处于设计的关键路径时,可以尝试不同的综合选项来处理拆解后的乘加结构:
- –mult-auto-pipeline:自动在DSP中添加流水线寄存器,以减少关键路径延迟(代价是增加运算延迟);
- –mult-decomp-retime:执行反向重定时(backward retiming)以减少关键路径延迟;需在宽乘法器的输出端添加额外寄存器,才能让重定时生效;
- 将级联连接的 DSP 模块最大数量设为 2(–max-cc-dsp48=2):在某些情况下,这可以减少关键路径延迟;
- 仅略微超过 DSP 位宽的宽乘法器(例如 19×19、20×20):
- 其扩展后的部分和 / 部分积可能过小,无法通过 DSP 或进位逻辑高效实现;此时,这些运算可能会被 “位拆分”(bit-blasting)到 LUT 中实现。这种位拆分可能会阻碍前述命令行选项发挥作用,进而影响 fMAX 的优化效果;
- 这种情况下,可以将以下命令行选项设为 0,禁用对小型加法器 / 乘法器的位拆分:
- –small-adder-limit(默认值:4);
- –small-mult-limit(默认值:2);
Readme:上述资料来源为Efinity-synthesis-v4.4版本
