目录
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 仿真结果