1. 程式人生 > >FPGA篇(一) 基於verilog的定點開方運算(1)-逐次逼近演算法

FPGA篇(一) 基於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];
//--------------------------------------------------------------------------------
	
[email protected]
(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
[email protected]
(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 //-------------------------------------------------------------------------------- // 計算餘數與最終平方根 //-------------------------------------------------------------------------------- [email protected](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 ;
//--------------------------------------------------------------------------------
	[email protected](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 模擬結果