• verilog求倒数-ROM实现方法


    采用线性逼近法结合32段线性查找表的方式来实现1/z的计算。

    首先将1/32-1/64的定点化数据存放到ROM中,ROM中存放的是扩大了2^20 次方的数字四舍五入后的整数部分。n值越大,精度越大,误差越小。这里取n=20;

    ROM中存储的数据是1/(32+i)*2^20的四舍五入的整数部分。

    32-64间的数据可以通过查表来实现,其他的数据则采用的是线性逼近的方法。

    线性逼近的步骤为:

    1.确定最高非零比特位的位置

    2.对z进行左移或者右移,得到zp

    3.zp查找ROM,得到1/zp,以及1/(zp+1),

    4.求的1/zp-1/(zp+1),为误差A

    5.N=z-zp*2^(m-5)

    6.B=A/2^(m-5)*N

    7.将扩大的部分缩小回去,或者缩小了的放大回去,那么1/z=(1/zp-B)*(1/2^(m-5))

     代码插入:

    module top_inv(
        input clk,syn_rst,
        input [20:0]dataa,
        input [20:0]datab,
        //input [20:0]ampout,
        output reg [19:0]inv
       // output reg done
        );
        reg [4:0] address1;
        reg [4:0 ]address2;
        wire [4:0] m;
       // wire done;
        reg [19:0]invr;
        reg [20:0] ampout_r;
        reg [20:0] ampout_r1;
        wire [20:0] ampout;
        reg [20:0] ampoutr1,ampoutr2,ampoutr3,ampoutr4;
        wire [19:0] inv_r1;
        wire [19:0] inv_r2;
        reg [20:0] diff_r;
        reg [19:0] diffr;
        reg [19:0] diff;
        reg [19:0] N;
        reg [19:0] N1;
        reg en;
        
      always @(posedge clk or negedge syn_rst)
      begin 
        if(~syn_rst)
        begin
        ampoutr1<=21'd0;
        ampoutr2<=21'd0;
        ampoutr3<=21'd0;
        ampoutr4<=21'd0;
        end
        else
        ampoutr1<=ampout;
        ampoutr2<=ampoutr1;
        ampoutr3<=ampoutr2;
        ampoutr4<=ampoutr3;
      end
      reg [19:0] inv_r1t1,inv_r1t2,inv_r1t3;
     always@(posedge clk or negedge syn_rst)
     begin
        if(~syn_rst)
        begin
            inv_r1t1<=0;
            inv_r1t2<=0;
            inv_r1t3<=0;
        end
        else
        begin
            inv_r1t1<=inv_r1;
            inv_r1t2<=inv_r1t1;
            inv_r1t3<=inv_r1t2;
        end
     end
     reg [4:0] mt1,mt2,mt3,mt4,mt5;
     always@(posedge clk or negedge syn_rst)
     begin
        if(~syn_rst)
        begin
            mt1<=0;
            mt2<=0;
            mt3<=0;
            mt4<=0;
            mt5<=0;
        end
        else
        begin
            mt1<=m;
            mt2<=mt1;
            mt3<=mt2;
            mt4<=mt3;
            mt5<=mt4;
        end
     end
     reg sel;
     reg selr1,selr2;
      always @(posedge clk or negedge syn_rst)
      begin
          if(~syn_rst)
          begin
             diff<=0;
             diffr <= 0;
             ampout_r<='b0;
             ampout_r1<=0;
             address1<='b0;
             address2<='b0;
             en<=0;
             sel<=0;
          end
          else 
          begin
         // if(done)
          //begin
            if((ampout>=32)&&(ampout<=64))
                begin
                    ampout_r<=0;
                    ampout_r1<=0;
                    address1<=ampoutr3-32;
                    address2<= 0;
                    diff <= 0;
                    diffr <= 0;
                    N <= 0;
                    N1<= 0;
                    en<=0;//不需要计算m的值
                    sel<=0;
                    selr1<=0;
                    selr2<=0;
                end
            else 
                begin
                 en<=1;//需要计算m的值
                 if(m>5)
                 begin
                    // ampoutrr<=ampout;
                     ampout_r<=ampoutr1>>(m-5);
                     ampout_r1<=ampout_r;//zp
                     address1<=ampout_r-32;///inv_r1
                     address2<=ampout_r-31;///inv_r2
                     diff <= inv_r1-inv_r2;
                     diffr <=diff;
                     N1<=ampout_r1<<(mt2-5);
                     N<=ampoutr4-N1;
                     selr1<=1;
                     selr2 <= selr1;
                     sel <= selr2;
                 end
                 if(m<5)
                 begin
                      //ampoutrr<=ampout;
                      ampout_r<=ampoutr1<<(5-m);//     mt4   mt3    mt2
                      ampout_r1 <= ampout_r;//          N    N1    ampout_r1
                      address1<=ampout_r-32;///mt4                 inv_r1
                      address2<=ampout_r-31;//inv_r1t3             inv_r2    mt1
                      diff <= inv_r1-inv_r2;//diff_r<<diffr<<diff<<address<<ampout_r<<  m  <<ampout
                      diffr <=diff;        //                      ampoutr3 ampoutr2  ampoutr1
                      N1<=ampout_r1>>(5-mt2);
                      N<=ampoutr4-N1;
                      selr1<=1;
                      selr2 <= selr1;
                      sel <= selr2;
                  end
              end
              end
         // end 
          end  
    //  assign diff=sel?(inv_r1-inv_r2):'b0;
      //assign N=sel?(ampout-N1):0;
      //assign diff_r = en?(diff*N>>(m-5)):0;
      //assign diff_r = (m>5)?(diff*N>>(m-5)):(diff*N<<(5-m));
     // assign inv = sel?(inv_r1-diff_r)>>(m-5):inv_r1;
     
      always@(posedge clk or negedge syn_rst)
      begin
          if(~syn_rst)
          begin
            invr<=0;
          //  done<=0;
          diff_r<=0;
          end
          else 
          begin
            if(sel) begin
            
                if(m>5)begin
                    diff_r <= diffr*N>>(mt4-5);
                    invr<=(inv_r1t3-diff_r)>>(mt5-5);
             //       done<=1;
                    end
                else begin
                    diff_r <= diffr*N<<(5-mt4);
                    invr<=(inv_r1t3-diff_r)<<(5-mt5);
             //       done<=1;
                    end
                end
            else 
            begin
                diff_r<=0;
                invr<=inv_r1t3;
            end
          end
      end
     always@(posedge clk or negedge syn_rst)
     begin
        if(~syn_rst)
        begin
            inv<=0;
        end
        else 
        begin
            if(invr)
                inv<= invr;
            else
                inv<=inv;
        end
     end
     //ROM 核的例化
     
     rom u_rom(.clk(clk),
               .address1(address1),
               .address2(address2),
               .inv_r1(inv_r1),
               .inv_r2(inv_r2)//,
               //.c(c)
           );
     //例化寻找最高非零位
     not_0 u_not_0 (
     // port map - connection between master ports and signals/registers   
         .ampout(ampout),
         .clk(clk),
         .m(m),
         .en(en),
         .syn_rst(syn_rst)
     );
    complex_abs u_comlex_abs(
           .clk(clk),
           .syn_rst(~syn_rst),
           .dataa(dataa),
           .datab(datab),
           .ampout(ampout)
           );
    endmodule

    那么最终的仿真结果:如果直接查询的话,结果输出延时一个时钟周期,如果线性逼近的方法得到,延时3-5个时钟周期,这里周期设定为20ns;

    占用资源报告:

    增加一个求平方根的模块以后的仿真结果(数据输入后,一共需要约10个时钟周期才可以计算出一个平方更求导数值)。有一个小疑问就是怎么添加一个标志信号,让我们知道哪里输出的inv 信号是有效的

  • 相关阅读:
    echarts之tooltip
    js随笔
    在wex5平台grid显示问题
    JSON.parse()和JSON.stringify()区别
    在wex5平台grid里面的gridselect下拉不能显示汉字问题
    wex5平台放入tabs组件后运行时显示空白
    正整数求n不用sqrt
    leetcode1143最长公共子序列
    美团Java一面(2020.3.19)
    leetcode138. 复制带随机指针的链表
  • 原文地址:https://www.cnblogs.com/Dinging006/p/9378856.html
Copyright © 2020-2023  润新知