目录
1.逐次逼近算法描述
2.Verilog实现
3.Testbench编写
逐次逼近算法流程如图 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逐次逼近算法框图
-
//////////////////////////////////////////////////////////////////////////////////
-
//
-
// 逐次逼近算法
-
//
-
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
-
//
--------------------------------------------------------------------------------
-
//--------------------------------------------------------------------------------
`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 仿真结果