在FPGA中做除法运算需要大量逻辑单元,尤其是高精度或大位宽运算,这会显著增加资源消耗,本文介绍一种使用只verilog不调用任何ip实现除法运算,通过状态机模拟竖式运算过程,其中状态1商最高位,状态2依次从被除数补位做差直到被除数所有位补完计算得到商和余数,如果需要计算小数位可扩展一个状态3继续补0做差即可。

需要注意的是例化此代码时被除数和除数的位宽并不需要严格确定,width1与width2的值可比实际位宽大但需要保证被除数高位0的个数必须大于或等于除数高位0的个数。举个例子被除数为900,实际位宽为10,width1给到12,这时12位的被除数高位有两个0,除数为50,实际位宽为6,width2可填6-8以保证除数高位0的个数小于等于2即可。

代码如下(变量名均用的拼音表示):

 

module	devision
#(
	parameter		width1 = 60,		//被除数位宽
	parameter		width2 = 15			//除数位宽      被除数高位0的个数必须大于除数高位0的个数!
)
(
	input			wire							clk,
	input			wire							rst_n,
	
	input			wire		[width1-1:0]		beichushu,
	input			wire		[width2-1:0]		chushu,
	input			wire							data_in_vld,
	
	output			reg 		[width1-1:0]		shang,
	output			reg 		[width2-1:0]		yushu,
	output			reg 							data_out_vld
);

reg			[width1-1:0]		beichushu_g;
reg			[width2-1:0]		chushu_g;
reg			[		5:0]		wid;

reg			[width2  :0]		cha;

reg			[4:0]				state;

always@(posedge clk or negedge rst_n)
	if(!rst_n)
		begin
			beichushu_g <= 'd0;
			chushu_g	<= 'd0;
		end
	else if(data_in_vld)
		begin
			beichushu_g <= beichushu;
			chushu_g	<= chushu;
		end
	
always@(posedge clk or negedge rst_n)
	if(!rst_n)
		begin	
			state 		 <= 5'd0;
			shang 		 <=  'd0;
			yushu 		 <=  'd0;
			data_out_vld <= 1'b0;
			cha			 <=  'd0;
			wid			 <=  'd0;
		end
	else case(state)
		5'd0 :
			begin
				if(data_in_vld)
					state 	 <=   5'd1;
				else
					state <= 5'd0;
			end
		5'd1 :
			begin
				if(beichushu_g[width1-1:width1-width2] >= chushu_g)
					begin
						cha      <= beichushu_g[width1-1:width1-width2] - chushu_g;
						state    <= 5'd2;
						shang    <= {shang[width1-2:0],1'b1};
						wid		 <= wid + 1'b1;
					end
				else if(beichushu_g[width1-1:width1-width2] < chushu_g)
					begin	
						cha      <= beichushu_g[width1-1:width1-width2];
						state    <= 5'd2;
						shang    <= {shang[width1-2:0],1'b0};
						wid		 <= wid + 1'b1;
					end
			end
		5'd2 :
			begin
				if(width1-width2 == wid)
					begin
						if({cha,beichushu_g[0]} >= chushu_g)
							begin
								shang 		 <= {shang[width1-2:0],1'b1};
								yushu 		 <= {cha,beichushu_g[0]} - chushu_g;
								state 		 <= 5'd3;
								data_out_vld <= 1'b1;
							end
						else if({cha,beichushu_g[0]} < chushu_g)
							begin
								shang 		 <= {shang[width1-2:0],1'b0};
								yushu 		 <= {cha,beichushu_g[0]};
								state 		 <= 5'd3;
								data_out_vld <= 1'b1;
							end
					end
				else if({cha,beichushu_g[width1-width2-wid]} >= chushu_g)
					begin
						cha   <= {cha,beichushu_g[width1-width2-wid]} - chushu_g;
						wid   <= wid + 1'b1;
						shang <= {shang[width1-2:0],1'b1};
						state <= 5'd2;
					end
				else if({cha,beichushu_g[width1-width2-wid]} < chushu_g)
					begin
						cha   <= {cha,beichushu_g[width1-width2-wid]};
						wid   <= wid + 1'b1;
						shang <= {shang[width1-2:0],1'b0};
						state <= 5'd2;
					end
			end
		5'd3 :
			begin
				state 		 <= 5'd0;
				shang 		 <=  'd0;
				yushu 		 <=  'd0;
				data_out_vld <= 1'b0;
				cha			 <=  'd0;
				wid			 <=  'd0;
			end
		default :
			begin
				state 		 <= 5'd0;
				shang 		 <=  'd0;
				yushu 		 <=  'd0;
				data_out_vld <= 1'b0;
				cha			 <=  'd0;
				wid			 <=  'd0;
			end
		endcase
		
endmodule

仿真代码:

`timescale 1ns/1ns

module tb_devision();

reg				clk;
reg				rst_n;
reg				data_in_vld;

wire	[29:0]	shang;
wire	[ 9:0]	yushu;
wire			data_out_vld;

initial
	begin
		clk          = 1'b0;
		rst_n       <= 1'b0;
		data_in_vld <= 1'b0;
		#20
		rst_n       <= 1'b1;
		#100	
		data_in_vld <= 1'b1;
		#120
		data_in_vld <= 1'b0;
	end

always #10 clk <= ~clk;
	
devision	
#(
	.width1 (30 ),	 //被除数位宽   
	.width2 (10 )	 //除数位宽			
)
devision_inst
(
	.clk			(clk			),    //input	  					
	.rst_n			(rst_n			),    //input	  					
													  
	.beichushu		('d1548962  	),    //input	  [width1-1:0]		
	.chushu			('d658      	),    //input	  [width2-1:0]		
	.data_in_vld	(data_in_vld	),    //input	  					
													  
	.shang			(shang			),    //output	  [width1-1:0]		
	.yushu			(yushu			),    //output	  [width2-1:0]		
	.data_out_vld   (data_out_vld	)     //output	  					
); 

endmodule

仿真结果(1548962 / 658 = 2354,余数为30):

更多推荐