基于verilog的定点开方运算(1)-逐次逼近算法

1.逐次逼近算法描述

        逐次逼近算法流程如图 1所示,首先数据输入data[7:0],接着设置实验值D_z[3:0]和确定值D_q[3:0],然后按照从高往低的顺序,依次将每一位置1(如D_z[3]置1),再将实验值平方后与输入数据比较,若实验值的平方大于输入值(D_z^2 > data),则此位为0(D_q[3]为0),反之((D_z^2 ≤ data)),此位为1(D_q[3]为1);以此迭代到最后一位。

可见,如果是n bit的数据,那么需要n/2次迭代,每次计算如果一个周期,则需要n/2个周期。


                                                                                    图 1逐次逼近算法框图

2.Verilog实现

//////////////////////////////////////////////////////////////////////////////////
//
//			逐次逼近算法
//
module sqrt_1
	#( 	
			parameter  		 							d_width = 8,
			parameter       							q_width = d_width/2 - 1,
			parameter       							r_width = q_width + 1	)
	(
	input			wire									clk,
	input			wire									rst,
	input			wire									i_vaild,
	input			wire			[d_width:0]			data_i, //输入
	
	
	output		reg									o_vaild,
	output		reg			[q_width:0]			data_o, //输出
	output		reg			[r_width:0]			data_r  //余数
	
    );
//--------------------------------------------------------------------------------
	reg 							[d_width:0] 		D				[r_width:1]; //被开方数
	reg 							[q_width:0] 		Q_z			[r_width:1]; //临时
	reg	 						[q_width:0] 		Q_q			[r_width:1]; //确认
	reg 													ivalid_t		[r_width:1];
//--------------------------------------------------------------------------------
	always@(posedge	clk or posedge	rst)
		begin
			if(rst)
				begin
					D[r_width] <= 0;
					Q_z[r_width] <= 0;
					Q_q[r_width] <= 0;
					ivalid_t[r_width] <= 0;
				end
			else	if(i_vaild)
				begin
					D[r_width] <= data_i;  //被开方数据
					Q_z[r_width] <= {1'b1,{q_width{1'b0}}}; //实验值设置
					Q_q[r_width] <= 0; //实际计算结果
					ivalid_t[r_width] <= 1;
				end
			else
				begin
					D[r_width] <= 0;
					Q_z[r_width] <= 0;
					Q_q[r_width] <= 0;
					ivalid_t[r_width] <= 0;
				end
		end
//-------------------------------------------------------------------------------
//		迭代计算过程
//-------------------------------------------------------------------------------
		generate
			genvar i;
				for(i=r_width-1;i>=1;i=i-1)
					begin:U
						always@(posedge clk or posedge	rst)
							begin
								if(rst)
									begin
										D[i] <= 0;
										Q_z[i] <= 0;
										Q_q[i] <= 0;
										ivalid_t[i] <= 0;
									end
								else	if(ivalid_t[i+1])
									begin
										if(Q_z[i+1]*Q_z[i+1] > D[i+1])
											begin
												Q_z[i] <= {Q_q[i+1][q_width:i],1'b1,{{i-1}{1'b0}}};
												Q_q[i] <= Q_q[i+1];
											end
										else
											begin
												Q_z[i] <= {Q_z[i+1][q_width:i],1'b1,{{i-1}{1'b0}}};
												Q_q[i] <= Q_z[i+1];
											end
										D[i] <= D[i+1];
										ivalid_t[i] <= 1;
									end
								else
									begin
										ivalid_t[i] <= 0;
										D[i] <= 0;
										Q_q[i] <= 0;
										Q_z[i] <= 0;
									end
							end
					end
		endgenerate
//--------------------------------------------------------------------------------
//	计算余数与最终平方根
//--------------------------------------------------------------------------------
		always@(posedge	clk or posedge	rst) 
			begin
				if(rst)
					begin
						data_o <= 0;
						data_r <= 0;
						o_vaild <= 0;
					end
				else	if(ivalid_t[1])
					begin
						if(Q_z[1]*Q_z[1] > D[1])
							begin
								data_o <= Q_q[1];
								data_r <= D[1] - Q_q[1]*Q_q[1];
								o_vaild <= 1;
							end
						else
							begin
								data_o <= {Q_q[1][q_width:1],Q_z[1][0]};
								data_r <= D[1] - {Q_q[1][q_width:1],Q_z[1][0]}*{Q_q[1][q_width:1],Q_z[1][0]};
								o_vaild <= 1;
							end
					end
				else
					begin
						data_o <= 0;
						data_r <= 0;
						o_vaild <= 0;
					end
			end
//--------------------------------------------------------------------------------

 3.Testbench编写

//--------------------------------------------------------------------------------
	`define  		 						d_w 		 8
	`define        						q_w		 `d_w / 2
	`define        						r_w 		 `q_w + 1
//--------------------------------------------------------------------------------
module tb_sqrt;
//--------------------------------------------------------------------------------
	// Inputs
	reg 										clk;
	reg 										rst;
	reg					 					i_vaild;
	reg 			[`d_w-1:0] 				data_i;

	// Outputs
	wire 										o_vaild;
	wire 			[`q_w-1:0]				data_o;
	wire 			[`r_w-1:0]				data_r;

//--------------------------------------------------------------------------------
	// Instantiate the Unit Under Test (UUT)
	sqrt_1 
	#(
		.d_width		( 	`d_w-1		),
		.q_width 	(	`q_w-1		),
		.r_width 	(  `r_w-1		)	
	)
		uut 
	(
		.clk			(	clk			), 
		.rst			(	rst			), 
		.i_vaild		(	i_vaild		), 
		.data_i		(	data_i		), 
		.o_vaild		(	o_vaild		), 
		.data_o		(	data_o		), 
		.data_r		(	data_r		)
	);
//--------------------------------------------------------------------------------
	initial begin
		// Initialize Inputs
		clk = 0;
		rst = 1;
		// Wait 100 ns for global reset to finish
		#100;
      rst = 0; 
		// Add stimulus here

	end
    
	always #5 clk  = ~ clk ;
	
	reg	[`d_w:0]		cnt ;
	
	reg	[31:0]		a ;
//--------------------------------------------------------------------------------
	always@(posedge	clk or posedge	rst)
		begin
			if(rst)
				begin
					i_vaild <= 0;
					data_i <= 0;
					cnt <= 0;
				end
			else	if(cnt < 10)
				begin
					i_vaild <= 1;
					data_i <= {$random} % 255;
					cnt <= cnt + 1;
				end
			else
				begin
					i_vaild <= 0;
					data_i <= 0;
					cnt <= cnt;
				end
		end
//--------------------------------------------------------------------------------
endmodule


        用语句 data_i <= {$random} % 255; 产生一个0~255的随机数进行测试。

        仿真结果如图 2所示,计算周期为4个时钟周期,输入数据data_i,开方结果data_o,余数data_r。


                                                                                    图 2 仿真结果

猜你喜欢

转载自blog.csdn.net/yanchuan23/article/details/79689175