HLS实现CORDIC算法计算正余弦并上板验证

硬件:ZYNQ7010
软件:MATLAB 2019b、Vivado 2017.4、HLS 2017.4、System Generator 2017.4

1、CORDIC算法计算正余弦

  CORDIC算法详细分析网上有很多资料,它的原理是用一系列旋转去逼近目标角度,这一系列旋转的角度为 θ = a r c t a n ( 2 − i ) \theta=arctan(2^{-i}) θ=arctan(2i) i i i 是迭代次数。下面给出了用CORDIC算法计算正余弦的代码,其中 s1 不做任何优化,数据类型都用的 float 型;s2 对数据类型做了定点数优化;s3 在 s2 的基础上,对迭代的循环做了流水线优化。

//cordic.h
#ifndef _CORDIC_H_
#define _CORDIC_H_
#include 
#include 
#define NUM_ITERATIONS 9
//#define s1
//#define s2
#define s3
#if defined s1
typedef float THETA_TYPE;
typedef float COS_SIN_TYPE;
#endif
#if defined s2 || defined s3
typedef ap_fixed<16,8> THETA_TYPE;
typedef ap_fixed<16,2> COS_SIN_TYPE;
#endif
void cordic(THETA_TYPE theta, COS_SIN_TYPE &s, COS_SIN_TYPE &c);
#endif
//cordic.cpp
#include "cordic.h"
const THETA_TYPE cordic_phase[NUM_ITERATIONS] = {
	45, 26.565, 14.036, 7.125, 3.576, 1.790, 0.895, 0.448, 0.224
	};
#if defined s1
void cordic(THETA_TYPE theta, COS_SIN_TYPE &s, COS_SIN_TYPE &c)
{
	COS_SIN_TYPE current_cos = 0.607255; // 6, 1/1.64669
	COS_SIN_TYPE current_sin = 0;
	COS_SIN_TYPE factor = 1.0;
	for(int i=0; i<NUM_ITERATIONS; i++)
	{
		ap_int<2> sigma = (theta < 0)?-1:1;
		COS_SIN_TYPE temp_cos = current_cos;
		current_cos = current_cos-current_sin*sigma*factor;
		current_sin = temp_cos*sigma*factor+current_sin;
		theta = theta-sigma*cordic_phase[i];
		factor = factor/2.0;
	}
	s = current_sin;
	c = current_cos;
}
#endif
#if defined s2 || defined s3
void cordic(THETA_TYPE theta, COS_SIN_TYPE &s, COS_SIN_TYPE &c)
{
	COS_SIN_TYPE current_cos = 0.607255; // 6, 1/1.64669
	COS_SIN_TYPE current_sin = 0;
	COS_SIN_TYPE factor = 1.0;
ITERATIONS_LOOP:
	for(int i=0; i<NUM_ITERATIONS; i++)
	{
		ap_int<2> sigma = (theta < 0)?-1:1;
		COS_SIN_TYPE temp_cos = current_cos;

		current_cos = current_cos-current_sin*sigma*factor;
		current_sin = temp_cos*sigma*factor+current_sin;
		theta = theta-sigma*cordic_phase[i];
		factor >>= 1;
	}
	s = current_sin;
	c = current_cos;
}
#endif

  三个 solution 的资源使用量和计算性能如下图所示。

HLS实现CORDIC算法计算正余弦并上板验证_第1张图片

2、上板验证

  把 s3 的模块端口设置成 ap_ctrl_none, 重新综合,导出 IP 核。在FPGA的顶层文件里例化 cordic IP 核和一个 ila IP 核,让 cordic 计算 30° 和 60° 角的正余弦值。

module cordic_test_top(
    input resetn,
    input clk
    );

wire [15:0] w_theta;
reg [15:0] r_theta;
reg [31:0] cnt;
always @(posedge clk or negedge resetn) begin
    if(!resetn) begin
        cnt <= 32'd0;
    end
    else begin
        if(cnt == 32'd1000) cnt <= 32'd0;
        else cnt <= cnt+1'd1;
    end
end
always @(posedge clk or negedge resetn) begin
    if(!resetn) begin
        r_theta <= 16'd0;
    end
    else begin
        if(cnt == 32'd500) r_theta <= {8'd30, 8'd0};
        else if(cnt == 32'd1000) r_theta <= {8'd60, 8'd0};
        else r_theta <= r_theta;
    end
end
assign w_theta = r_theta;
wire [15:0] s, c;
wire s_V_ap_vld, c_V_ap_vld;
reg [15:0] r_s, r_c;
cordic_0 cordic_inst (
  .s_V_ap_vld(s_V_ap_vld),  // output wire s_V_ap_vld
  .c_V_ap_vld(c_V_ap_vld),  // output wire c_V_ap_vld
  .ap_clk(clk),          // input wire ap_clk
  .ap_rst(~resetn),          // input wire ap_rst
  .theta_V(w_theta),        // input wire [15 : 0] theta_V
  .s_V(s),                // output wire [15 : 0] s_V
  .c_V(c)                // output wire [15 : 0] c_V
);
always @(posedge clk or negedge resetn) begin
    if(!resetn) begin
        r_s <= 16'd0;
    end
    else begin
        if(s_V_ap_vld) begin
            r_s <= s;
        end
    end
end
always @(posedge clk or negedge resetn) begin
    if(!resetn) begin
        r_c <= 16'd0;
    end
    else begin
        if(c_V_ap_vld) begin
            r_c <= c;
        end
    end
end
ila_0 ila0 (
	.clk(clk), // input wire clk
	.probe0(w_theta), // input wire [15:0]  probe0  
	.probe1(r_s), // input wire [15:0]  probe1 
	.probe2(s_V_ap_vld), // input wire [0:0]  probe2 
	.probe3(r_c), // input wire [15:0]  probe3 
	.probe4(c_V_ap_vld) // input wire [0:0]  probe4
);

   ila 上看到的波形如下图所示。注意要正确设置观测量的数据类型,即定点数和小数点位置。从图中可以看出计算的角度比较准确。

HLS实现CORDIC算法计算正余弦并上板验证_第2张图片
完整工程下载:HLS设计CORDIC算法计算正余弦

你可能感兴趣的:(FPGA,算法,fpga开发)