Xilinx Vivado CORDIC IP求解atan 反正切


賽靈思官方提供了cordic(coordinate rotational digital computer) ip核實現直角坐標極坐標變化,三角函數的操作。我介紹下它進行反正切求解的使用:

新建個簡單工程:bd如下

 

 進行ip設置,選擇運算位反正切后,ip端口回自動變為上圖,再引出2個總線和時鍾,xilinx的ip核不少是基於AXI4-Stream總線,這里使用並不復雜,默認只有2個信號,一個數據線tdata,一個握手信號tvalid,tvalid拉高時數據信號有效。

 

 確定了輸入輸出位寬后,系統會自動求解出需要的延時latency。這里說一句,AXI-Stream總線收發基於byte的,無論輸入什么位寬最后都是8的整數倍。所以需要參照UG,放置好有效輸入位和分解輸出位。

 

 

 

 如果輸入輸出位寬恰好不是8的倍數,那么tdata位寬是大於設定的值的。所以需要上圖提到進行填充(PAD),比如我輸入20位,x和y加起來40位,那么輸入S_AXIS的位寬是48,我要在0-19放x,20-23放填充數據(隨意,我用0),24-43放y,44-47放填充數據。必須保證0-19和24-25分別是我的x和y。

 

 atan=y/x,要求輸入必須是[-1,1],所以如果數據不是這個區間還需要進行歸一化處理(可以用除法器div_gen ip核,這里不做介紹了)。上圖是一個簡單的示例,介紹輸入輸出的定點小數格式。整數部分的第一位是符號位,小數部分沒有符號位是正的。※Q格式:小數點位於第 n 位元之右側,稱為Qn 格式。

這里關於二進制小數表示,可以看下這個https://blog.csdn.net/AaricYang/article/details/87882868。整數的每一位權重是2^(n-1) 111就是2^2+2^1+2^0=7,小數部分的權重是2^(-n) 0.111就是2^(-1)+2^(-2)+2^(-3)=0.875

 這里我覺得還有一個細節問題。如果輸入的數值x或y是負數小數,比如1100,常規默認符號位第一位,第二位開始就是小數部分了,所以1010就是1.010= -1+0.25= -0.75;這種符號位后一位就是小數部分的第一位的格式就是vivado 除法器ip輸出小數的格式。也可以說這種是0Qn format,即符號位后0位就是小數。但是cordic ip輸入要求 1Qn format,符號位結束后1位才是小數格式(為了兼容恰好等於±1的情況),那么剛剛1010就不可以直接作為cordic ip核的輸入,1010按照1Qn format,第3位才是小數部分,1010就是10.10= -1.5 因為整數部分是10,反碼01,補碼10為2,因為是負數所以-2,小數部分是0.5,最終結果是-2+0.5=1.5。這樣就不符合cordic ip核輸入要求了。從0Qn改為1Qn為了滿足,如果是絕對值小於1的數只要在符號位后重復符號位就可以了,1 010改為11 010,這樣就可以正常輸入到cordic中了。

`timescale 1 ns / 1 ps
module cordic_tb_top;
  
  reg aclk;
  wire [31:0]M_AXIS_DOUT_0_tdata;
  wire M_AXIS_DOUT_0_tvalid;
  reg [47:0]S_AXIS_CARTESIAN_0_tdata;
  reg S_AXIS_CARTESIAN_0_tvalid;
  integer handle;
  
  
  initial begin
    aclk=0;
    S_AXIS_CARTESIAN_0_tvalid=1'b0;
    S_AXIS_CARTESIAN_0_tdata='b0;
    
  end
  
  initial handle = $fopen("D:/FPGAcode/_file/cordic.txt");//打開文件
  
  always #10 aclk=~aclk;
  
  localparam PAD=(48-20*2)/2;
  always@(posedge aclk) begin
    S_AXIS_CARTESIAN_0_tvalid<=1'b1;
    S_AXIS_CARTESIAN_0_tdata<={{PAD{1'b0}},{3'b000,17'b0},{PAD{1'b0}},{3'b111,17'b0}};
  end

  always@(posedge aclk) begin
    if(M_AXIS_DOUT_0_tvalid)
        $fdisplay(handle,"%b",M_AXIS_DOUT_0_tdata);//寫數據
  end
  
  design_1_wrapper design_1_i
         (.M_AXIS_DOUT_0_tdata(M_AXIS_DOUT_0_tdata),
          .M_AXIS_DOUT_0_tvalid(M_AXIS_DOUT_0_tvalid),
          .S_AXIS_CARTESIAN_0_tdata(S_AXIS_CARTESIAN_0_tdata),
          .S_AXIS_CARTESIAN_0_tvalid(S_AXIS_CARTESIAN_0_tvalid),
          .aclk_0(aclk));
  
  
endmodule

給個簡單的testbench

 

 在modelsim中可以設置小數位數,顯示出具體的數值。

 

如果自己參考文獻,用HDL實現一個CORDIC算法的模塊,應該是很不錯了。但是我偷懶直接用現成IP了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM