FPGA乘法计算时位宽太大引起的路径延时解决方法

1、fpga进行乘法计算的方法

① 使用官方提供的IP核 Multipler

优点:使用最少的DSP资源,可以进行有符号,无符号数计算;位宽2-64bit可调。
缺点:最大位宽只有64bit,数据再大不支持(eg:s数据放大2^50后计算,数据位宽大于64)。

在这里插入图片描述

② 使用乘法号 * 计算

优点:数据位宽可以任意调整,使用多个DSP资源。
缺点:DSP资源使用浪费,同样位宽计算,使用DSP数可能大于使用IP核;有符号计算时需要使用signed标识寄存器内数据是有符号数,不然会被当作无符号数计算。

2、案例描述

计算数据 32bit * 64bit;使用IP核Multipler计算,编译过后报时序警告,打开Implemented Design可以看到
在这里插入图片描述
在Device窗口点击Routing Resources 可以看到这为实现这个乘法计算所经过的路径
在这里插入图片描述
在右边的窗口中也可以看到,此时路径延时为13.244ns.系统时钟100M。
在这里插入图片描述
路径延时过大,可能会使得数据在时钟沿到来后无法处于稳定状态,从而数据无法被所存,出现亚稳态,在资源使用紧张,时序要求严苛的时候会导致系统无法正确运行。

3、解决方法

为处理数据路径延时过大导致亚稳态的问题,我们可以将大位宽数据拆分成多个位宽的数据放到多个寄存器中分开计算,并将结果移位相加。

方案原理:求 data_A[63:0] * data_B[31:0] 。
①:取两个数据最高位作为符号位flag。
②:取两个数据的绝对值data_A_Abs = |data_A| ; data_B_Abs = |data_B| 。
③:将大位宽拆成多个小位宽数据:data_A_H = data_A_Abs [63:32] ; data_A_L = data_B_Abs [31:0]。
④:将拆分的数据相乘data_buff1 = data_A_H * data_B_Abs ; data_buff2 = data_A_L * data_B_Abs 。
⑤:移位相加 data_o = data_buff1 <<32 + data_buff2 ;
Verilog代码设计:

`timescale 1ns / 1ps

module	Calculate(
	input							clk					,
	input							rst_n				,
	
	input							Calculate_en		,	
	
	input	signed		[63:0]		data_A				,
	input	signed		[31:0]		data_B				,
	
	output	reg	signed	[95:0]		data_o				
    );
	reg								Calculate_en1		;
	always@(posedge clk or negedge rst_n)
	begin
		if(rst_n==0)
			Calculate_en1		<=	'b0					;
		else
			Calculate_en1		<=	Calculate_en		;
	end
	assign	Calculate_en_raising	= ~ Calculate_en1 & Calculate_en;
	localparam					idle		=	0		,
								st1			=	1		,
								st2			=	2		,
								st3			=	3		;
	reg				[3:0]		cur_st					;
	
	reg				[31:0]		data_A_H				;
	reg				[31:0]		data_A_L				;
	
	reg				[63:0]		data_buff1 				;
	reg				[63:0]		data_buff2 				;

	reg				[63:0]		data_A_Abs				;
	reg				[31:0]		data_B_Abs				;
	reg							flag1					;
	always@(posedge clk or negedge rst_n)
	begin
		if(rst_n==0)
		begin
			data_A_Abs				<=	'b0					;
			data_B_Abs				<=	'b0					;
			data_A_H				<=	'b0					;
			data_A_L				<=	'b0					;
			
			data_buff1				<=	'b0					;
			data_buff2				<=	'b0					;
			data_o					<=	'b0					;
			flag1					<=	'b0					;
			
			cur_st					<=	idle				;
		end
		else
		begin
			case(cur_st)
			idle	:begin
				if(PR_en_raising)
				begin
					PR_out_en		<=	'b0							;
					case({data_B[31],data_A[63]})
					2'b00:	//++
					begin
						flag1		<=	'b0							;
						data_B_Abs	<=	data_B						;
						data_A_Abs	<=	data_A						;
					end
					2'b01:	//+-
					begin
						flag1		<=	'b1							;
						data_B_Abs	<=	data_B						;
						data_A_Abs	<=	- data_A					;
					end
					2'b10:	//-+
					begin
						flag1		<=	'b1							;
						data_B_Abs	<=	- data_B					;
						data_A_Abs	<=	data_A						;
					end
					2'b11:	//--
					begin
						flag1		<=	'b0							;
						data_B_Abs	<=	- data_B					;
						data_A_Abs	<=	- data_A					;
					end
					endcase

					cur_st			<=	st1							;
				end
				else
					cur_st			<=	idle						;
			end
			st1		:begin
				data_A_H			<=	data_A_Abs[63:32]			;
				data_A_L			<=	data_A_Abs[31:0]			;
				cur_st				<=	st2							;
			end
			st2		:begin			
				data_buff1			<=	data_B_Abs * data_A_H 		;
				data_buff2			<=	data_B_Abs * data_A_L 		;
				cur_st				<=	st3							;
			end
			st3		:begin
				if(flag1)
					data_o			<=	-({{32{data_buff2[63]}},data_buff2} + {data_buff1,32'b0})	;
				else
					data_o			<=	{{32{data_buff2[63]}},data_buff2} + {data_buff1,32'b0}		;
				cur_st				<=	idle						;
			end
			default	:begin
				
			end
			endcase
		end
	end
	
	
endmodule

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值