欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

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

发布时间:2025/4/5 编程问答 54 豆豆
生活随笔 收集整理的这篇文章主要介绍了 FPGA篇(一) 基于verilog的定点开方运算(1)-逐次逼近算法 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

目录

1.逐次逼近算法描述

2.Verilog实现

 3.Testbench编写


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)beginif(rst)beginD[r_width] <= 0;Q_z[r_width] <= 0;Q_q[r_width] <= 0;ivalid_t[r_width] <= 0;endelse if(i_vaild)beginD[r_width] <= data_i; //被开方数据Q_z[r_width] <= {1'b1,{q_width{1'b0}}}; //实验值设置Q_q[r_width] <= 0; //实际计算结果ivalid_t[r_width] <= 1;endelsebeginD[r_width] <= 0;Q_z[r_width] <= 0;Q_q[r_width] <= 0;ivalid_t[r_width] <= 0;endend //------------------------------------------------------------------------------- // 迭代计算过程 //-------------------------------------------------------------------------------generategenvar i;for(i=r_width-1;i>=1;i=i-1)begin:Ualways@(posedge clk or posedge rst)beginif(rst)beginD[i] <= 0;Q_z[i] <= 0;Q_q[i] <= 0;ivalid_t[i] <= 0;endelse if(ivalid_t[i+1])beginif(Q_z[i+1]*Q_z[i+1] > D[i+1])beginQ_z[i] <= {Q_q[i+1][q_width:i],1'b1,{{i-1}{1'b0}}};Q_q[i] <= Q_q[i+1];endelsebeginQ_z[i] <= {Q_z[i+1][q_width:i],1'b1,{{i-1}{1'b0}}};Q_q[i] <= Q_z[i+1];endD[i] <= D[i+1];ivalid_t[i] <= 1;endelsebeginivalid_t[i] <= 0;D[i] <= 0;Q_q[i] <= 0;Q_z[i] <= 0;endendendendgenerate //-------------------------------------------------------------------------------- // 计算余数与最终平方根 //--------------------------------------------------------------------------------always@(posedge clk or posedge rst) beginif(rst)begindata_o <= 0;data_r <= 0;o_vaild <= 0;endelse if(ivalid_t[1])beginif(Q_z[1]*Q_z[1] > D[1])begindata_o <= Q_q[1];data_r <= D[1] - Q_q[1]*Q_q[1];o_vaild <= 1;endelsebegindata_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;endendelsebegindata_o <= 0;data_r <= 0;o_vaild <= 0;endend //--------------------------------------------------------------------------------

 3.Testbench编写

  //--------------------------------------------------------------------------------`define d_w 8`define q_w `d_w / 2`define r_w `q_w + 1 //-------------------------------------------------------------------------------- module tb_sqrt; //--------------------------------------------------------------------------------// Inputsreg clk;reg rst;reg i_vaild;reg [`d_w-1:0] data_i;// Outputswire 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 Inputsclk = 0;rst = 1;// Wait 100 ns for global reset to finish#100;rst = 0; // Add stimulus hereendalways #5 clk = ~ clk ;reg [`d_w:0] cnt ;reg [31:0] a ; //--------------------------------------------------------------------------------always@(posedge clk or posedge rst)beginif(rst)begini_vaild <= 0;data_i <= 0;cnt <= 0;endelse if(cnt < 10)begini_vaild <= 1;data_i <= {$random} % 255;cnt <= cnt + 1;endelsebegini_vaild <= 0;data_i <= 0;cnt <= cnt;endend //-------------------------------------------------------------------------------- endmodule

 

 

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

 

 

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

                                                                                    图 2 仿真结果

总结

以上是生活随笔为你收集整理的FPGA篇(一) 基于verilog的定点开方运算(1)-逐次逼近算法的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。