VHDL ile CORDIC Algoritmasının Gerçeklenmesi : Dairesel Açı Dönüşümü

Trigonometrik fonksiyonların bilgisayar tarafından hesaplanabilmesi için, 1959 yılında Jack Volder tarafından ortaya sürülen CORDIC algoritması, 1971 yılında J.S. Walther tarafından hiperbolik ve üstel fonksiyonlar, logaritma, karekök hesaplamaları yapabilecek şekilde geliştirilmiştir .

Aşağıda verilen denklemde -\pi/2\leq\theta<\pi/2 sınır aralığında tanımlı CORDIC algoritması genel ifadesi verilmiştir.

Yukarıdaki denklemde tanımlı d^i parametresi, aşağıdaki denklemde gösterildiği gibi z_i değerinin pozitif veya negatif olmasına göre -1 veya 1 değerini almaktadır.

e_i parametresi dairesel, doğrusal ve hiperbolik hesaplamaları yapan her denklem için farklı değer almaktadır. Dairesel dönüşüm için tanımlı eşitlik

Doğrusal dönüşüm için tanımlı eşitlik

Hiperbolik dönüşüm için kullanılan eşitlik

denklemlerde gösterilmiştir.gösterilmiştir.

Yukarıda verilen ilk denklemde tanımlı \mu parametresi yapılacak hesaplama tekniğine göre değer alan sabit parametredir. Bu değerler aşağıdaki tabloda gösterilmiştir. Her dönüşüm tipi döndürme ve vektörel olmak üzere iki çözüm moduna sahiptir.

Dairesel açı dönüşüm işlemlerinde, yukarıda verilen tablodan da görüleceği üzere \mu parametre değeri 1 olmaktadır. Dairesel açı dönüşüm işlemlerinde döndürme modu kullanılarak direkt olarak sinüs ve kosinüs değerleri dolaylı olarak ise tanjant ve kotanjant değerleri elde edilebilmektedir. Vektörel modda ise kartezyen koordinat değerlerinin polar koordinat değerlerine dönüşümü yapılmaktadır.

Döndürme Modu (Rotation Mod)

Döndürme modunda dairesel açı dönüşüm işlemlerinde temel amaç yazıda ilk verdiğimiz denklemde z tanımlanandeğişkeni değerini sıfıra yaklaştırmaktadır .

Döndürme modda dairesel açı dönüşümü, vektörün i. anındaki pozisyonu ile (i+1). anındaki pozisyonu arasındaki açı değeri θ sıfırlanana kadar kaydırma işlemlerinin gerçekleştirilmesiyle yapılmaktadır. Aşağıda verilen eşitlikle döndürme modda dairesel açı dönüşüm işlemi gerçekleştirilmektedir.

i. adım ile (i+1). adım arasında gerçekleştirilecek döndürme işlemi açı değeri aşağıda verilen gibi hesaplanır.

Bütün adımlardaki açıların toplamı döndürme açısı \theta ’yı vermelidir. Aşağıda verilen denklemde tanımlı S parametresi {-1, 1} değerlerini almaktadır.

Bu bilgiler doğrultusunda tan\theta_i değeri aşağıdaki gibi ifade edilmektedir.

Yukarıdaki ifadeleri kullanarak denklemi güncellediğimizde

Yukarıdaki eşitlikte tanımlanan K_i değişkeni aşağıdaki gibi hesaplanır.

K_i parametresi iteratif süreç içerisinde ihmal edilebilir ve daha sonra bir ölçekleme faktörü olarak uygulanabilir

Aşağıda döndürme modunda sinüs ve cosinüs değerlerini hesplayan VHDL kodları verilmiştir.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_SIGNED.ALL;
use IEEE.MATH_REAL.ALL;

entity cordic_v1 is
    generic(
        ITERTATION : integer := 16;
        VALUE_SIZE : integer := 16;
        MUL_COEFF : integer := 18; -- 2^MULL_COEFF;
        DATA_SIZE : integer := 24 -- DATA_SIZE > MUL_COEFF +2
    );
    Port ( 
        in_clk : in std_logic;
        in_rst : in std_logic;
        in_strt : in std_logic;
        in_teta : in std_logic_vector(DATA_SIZE - 1 downto 0);  
        out_cos_data : out std_logic_vector(DATA_SIZE - 1 downto 0); 
        out_sin_data : out std_logic_vector(DATA_SIZE - 1 downto 0);
        out_data_vld : out std_logic
    );
end cordic_v1;

architecture Behavioral of cordic_v1 is
    
    type t_Cordic_values is array (0 to VALUE_SIZE - 1) of real;
    type t_Int_data is array (0 to VALUE_SIZE - 1) of integer;
    type t_Std_Logic_Vector_data is array (0 to VALUE_SIZE - 1) of std_logic_vector(DATA_SIZE - 1 downto 0);
    type t_V_vector is array (0 to 1) of std_logic_vector(DATA_SIZE - 1 downto 0);
    
    function f_Calc_K_values(VALUE_SIZE : integer) return t_Cordic_values is
        variable v_K_values : t_Cordic_values;
    begin
        v_K_values(0) := 1.0 / sqrt(2.0);
        for n_i in 1 to VALUE_SIZE - 1 loop
            v_K_values(n_i) := v_K_values(n_i - 1) * (1.0 / sqrt(1.0 + 2.0**(-2.0 * real(n_i))));
        end loop;
        return v_K_values;
    end f_Calc_K_values;
    
    function f_Calc_Angels(VALUE_SIZE : integer) return t_Cordic_values is
        variable v_K_angels : t_Cordic_values;
    begin     
        for n_i in 0 to VALUE_SIZE - 1 loop
            v_K_angels(n_i) := arctan(2.0**(-1.0 * real(n_i)));
        end loop;
        return v_K_angels;
    end f_Calc_Angels;
    
    function f_Conv_Real_to_Int(r_Cordic_values : t_Cordic_values; VALUE_SIZE, MUL_COEFF : integer ) return t_Int_data is
        variable v_Int_data : t_Int_data;
    begin
        for n_i in 0 to VALUE_SIZE - 1 loop 
            v_Int_data(n_i) := integer(r_Cordic_values(n_i) * real(2**MUL_COEFF));
        end loop;
        return v_Int_data;        
    end f_Conv_Real_to_Int;     
    
    function f_Conv_Int_to_Std_Logic_Vector(r_Int_values : t_Int_data; VALUE_SIZE, DATA_SIZE : integer ) return t_Std_Logic_Vector_data is
        variable v_Std_Logic_Vector_data : t_Std_Logic_Vector_data;
    begin
        for n_i in 0 to VALUE_SIZE - 1 loop 
            v_Std_Logic_Vector_data(n_i) := conv_std_logic_vector(r_Int_values(n_i), DATA_SIZE);
        end loop;
        return v_Std_Logic_Vector_data;        
    end f_Conv_Int_to_Std_Logic_Vector;       
    
    function f_min_index(VALUE_SIZE, ITERTATION : integer ) return integer is
    begin
        if VALUE_SIZE < ITERTATION then
            return VALUE_SIZE;
        else
            return ITERTATION;
        end if;            
    end f_min_index;        

    constant r_K_values : t_Cordic_values := f_Calc_K_values(VALUE_SIZE);
    constant r_Angels : t_Cordic_values := f_Calc_Angels(VALUE_SIZE);
    constant r_K_values_int : t_Int_data := f_Conv_Real_to_Int(r_K_values, VALUE_SIZE, MUL_COEFF);
    constant r_Angels_int : t_Int_data := f_Conv_Real_to_Int(r_Angels, VALUE_SIZE, MUL_COEFF);
    constant r_K_values_SLV_data : t_Std_Logic_Vector_data := f_Conv_Int_to_Std_Logic_Vector(r_K_values_int, VALUE_SIZE, DATA_SIZE);
    constant r_Angels_SLV_data : t_Std_Logic_Vector_data := f_Conv_Int_to_Std_Logic_Vector(r_Angels_int, VALUE_SIZE, DATA_SIZE);
    constant r_K_n : std_logic_vector(DATA_SIZE - 1 downto 0) :=  r_K_values_SLV_data(f_min_index(VALUE_SIZE, ITERTATION) - 1);
    constant r_PI : real := 3.14159_26535_89793_23846;
                                                          -- Value of pi
    signal r_V_vector : t_V_vector :=(conv_std_logic_vector(1 * 2** MUL_COEFF, DATA_SIZE), 
                                      conv_std_logic_vector(0 * 2** MUL_COEFF, DATA_SIZE));
    signal r_POW_of_2 : std_logic_vector(DATA_SIZE - 1 downto 0) := 
                                      conv_std_logic_vector(1 * 2** MUL_COEFF, DATA_SIZE) ; 
    signal r_Angel : std_logic_vector(DATA_SIZE - 1 downto 0) := r_Angels_SLV_data(0);
    
    signal r_teta : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0'); 
    signal r_sigma : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0'); 
    signal r_factor : std_logic_vector(2 * DATA_SIZE - 1 downto 0) := (others => '0');
    signal r_teta_delta : std_logic_vector(2 * DATA_SIZE - 1 downto 0) := (others => '0');
    signal r_V_new_0 : std_logic_vector(2 * DATA_SIZE - 1 downto 0) := (others => '0');
    signal r_V_new_1 : std_logic_vector(2 * DATA_SIZE - 1 downto 0) := (others => '0');    
    
    signal r_sin_data : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0'); 
    signal r_cos_data : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0');
        
    signal r_data_vld : std_logic := '0';
    signal r_neg_flg : std_logic := '0';
    
    type t_Cordic_Cntrl is (IDLE, CHK_ANGLE, CHK_SIGMA, CALC_FACTOR, CALC_NEW_V, SET_NEW_V, UPDATE_PARAM, MUL_CONSTANT, DONE);
    signal r_Cordic_Cntrl : t_Cordic_Cntrl := IDLE;  
    signal n_i : integer := 0;  

begin

    out_sin_data <= r_sin_data;
    out_cos_data <= r_cos_data;
    out_data_vld <= r_data_vld;
    
    process(in_clk, in_rst, in_strt)
    begin
        if in_rst = '1' then
            r_Cordic_Cntrl <= IDLE;
            r_V_vector <= (conv_std_logic_vector(1 * 2** MUL_COEFF, DATA_SIZE), 
                           conv_std_logic_vector(0 * 2** MUL_COEFF, DATA_SIZE));
            r_POW_of_2 <=  conv_std_logic_vector(1 * 2** MUL_COEFF, DATA_SIZE) ; 
            r_Angel <= r_Angels_SLV_data(0);
            r_teta <= (others => '0');
            r_teta_delta <= (others => '0'); 
            r_sigma <= (others => '0');
            r_factor <= (others => '0'); 
            r_V_new_0 <= (others => '0');
            r_V_new_1 <= (others => '0');
            r_sin_data <= (others => '0'); 
            r_cos_data <= (others => '0');
            r_data_vld <= '0';
            r_neg_flg <= '0';
            n_i <= 0;
            
        elsif rising_edge(in_clk) then
            r_data_vld <= '0';
            case r_Cordic_Cntrl is  
                when IDLE =>
                    if in_strt = '1' then
                        r_teta <= in_teta; 
                        r_V_vector <= (conv_std_logic_vector(1 * 2** MUL_COEFF, DATA_SIZE), 
                                       conv_std_logic_vector(0 * 2** MUL_COEFF, DATA_SIZE));
                        r_POW_of_2 <=  conv_std_logic_vector(1 * 2** MUL_COEFF, DATA_SIZE) ; 
                        r_Angel <= r_Angels_SLV_data(0);
                        r_Cordic_Cntrl <= CHK_ANGLE;                     
                    end if;
                
                when CHK_ANGLE =>
                    if r_teta < conv_std_logic_vector(integer(((-r_PI/2.0) * real(2**MUL_COEFF))), DATA_SIZE) then
                        r_teta <= r_teta + conv_std_logic_vector(integer(((r_PI) * real(2**MUL_COEFF))), DATA_SIZE); 
                        r_neg_flg <= '1';                  
                    elsif r_teta > conv_std_logic_vector(integer(((r_PI/2.0) * real(2**MUL_COEFF))), DATA_SIZE) then
                        r_teta <= r_teta - conv_std_logic_vector(integer(((r_PI) * real(2**MUL_COEFF))), DATA_SIZE);
                        r_neg_flg <= '1';
                    end if;
                    r_Cordic_Cntrl <= CHK_SIGMA;
                
                when CHK_SIGMA =>    
                    if r_teta < 0 then
                        r_sigma <= (conv_std_logic_vector(-1 * 2** MUL_COEFF, DATA_SIZE));
                    else
                        r_sigma <= (conv_std_logic_vector(1 * 2** MUL_COEFF, DATA_SIZE));
                    end if;
                    r_Cordic_Cntrl <= CALC_FACTOR;
                    
                when CALC_FACTOR =>
                    r_factor <= r_sigma * r_POW_of_2;   
                    r_Cordic_Cntrl <= CALC_NEW_V;
                    
                when CALC_NEW_V => 
                    r_V_new_0 <= conv_std_logic_vector(2**MUL_COEFF, DATA_SIZE) *  r_V_vector(0) - 
                                 r_V_vector(1) * r_factor(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF); 
                                      
                    r_V_new_1 <= conv_std_logic_vector(2**MUL_COEFF, DATA_SIZE) *  r_V_vector(1) + 
                                 r_V_vector(0) * r_factor(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);   
                    r_Cordic_Cntrl <= SET_NEW_V;
                    
                when SET_NEW_V =>
                     r_V_vector(0) <= r_V_new_0(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);   
                     r_V_vector(1) <= r_V_new_1(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);
                     r_teta_delta <= r_sigma * r_Angel; 
                     r_Cordic_Cntrl <= UPDATE_PARAM;
                     
                when UPDATE_PARAM =>     
                    r_teta <= r_teta - r_teta_delta(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);
                    r_POW_of_2 <= '0' & r_POW_of_2(DATA_SIZE - 1 downto 1);
                    if n_i + 2 > VALUE_SIZE then
                        r_Angel <= '0' & r_Angel(DATA_SIZE - 1 downto 1);
                        
                    else
                        r_Angel <= r_Angels_SLV_data(n_i + 1);
                    end if;
                    if n_i = ITERTATION - 1 then
                        n_i <= 0;
                        r_Cordic_Cntrl <= MUL_CONSTANT;
                    else
                        n_i <= n_i + 1;
                        r_Cordic_Cntrl <= CHK_ANGLE;
                    end if;
                
                when MUL_CONSTANT =>
                    r_V_new_0 <= r_V_vector(0) * r_K_n;
                    r_V_new_1 <= r_V_vector(1) * r_K_n;
                    r_Cordic_Cntrl <= DONE;
                    
                when DONE =>  
                    if r_neg_flg = '1' then
                        r_cos_data <= not r_V_new_0(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF) + 1;
                        r_sin_data <= not r_V_new_1(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF) + 1;
                        r_neg_flg <= '0';
                    else
                        r_cos_data <= r_V_new_0(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);
                        r_sin_data <= r_V_new_1(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);                                            
                    end if;
                    r_data_vld <= '1';
                    r_Cordic_Cntrl <= IDLE;          
                when others => NULL;
            end case;
        end if;
        
    end process;
    
end Behavioral;

Aşağıda döndürme modunda sinüs ve cosinüs değerlerini hesaplayan cordic_v1.vhd VHDL kodunun benzetimini yapılabilmesi için oluşturulmuş sınama kodları verilmiştir.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_SIGNED.ALL;
use IEEE.MATH_REAL.ALL;


entity tb_cordic is
end tb_cordic;

architecture Behavioral of tb_cordic is

    component cordic_v1
        generic(
            ITERTATION : integer := 2;
            VALUE_SIZE : integer := 8;
            MUL_COEFF : integer := 12; -- 2^MULL_COEFF;
            DATA_SIZE : integer := 16 -- DATA_SIZE > MUL_COEFF
        );
        Port ( 
            in_clk : in std_logic;
            in_rst : in std_logic;
            in_strt : in std_logic;
            in_teta : in std_logic_vector(DATA_SIZE - 1 downto 0);  
            out_cos_data : out std_logic_vector(DATA_SIZE - 1 downto 0); 
            out_sin_data : out std_logic_vector(DATA_SIZE - 1 downto 0);
            out_data_vld : out std_logic
        );
    end component;    
    
    constant CLK_PERIOD : time := 10 ns;
    constant r_PI : real := 3.14159_26535_89793_23846;
    
    constant ITERTATION : integer := 24;
    constant VALUE_SIZE : integer := 24;
    constant MUL_COEFF : integer := 24; -- 2^MULL_COEFF;
    constant DATA_SIZE : integer := 29; -- DATA_SIZE > MUL_COEFF +2    
    signal in_clk : std_logic := '0';
    signal in_strt : std_logic := '0';
    signal in_teta : std_logic_vector(DATA_SIZE - 1 downto 0);
    signal n_i : integer := 0;
    signal r_sin_data : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0'); 
    signal r_cos_data : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0');
    signal r_data_vld : std_logic := '0';
    type t_Cntrl is (SET_TETA,WAIT_DATA, DONE );
    signal r_Cntrl : t_Cntrl := SET_TETA;
    signal r_data_cos_real : real := 0.0;
    signal r_data_sin_real : real := 0.0;
    signal r_mse_cos : real := 0.0;
    signal r_mse_sin : real := 0.0;
    
begin
    
    process
    begin
        in_clk <= '1';
        wait for CLK_PERIOD / 2;
        in_clk <= '0';
        wait for CLK_PERIOD / 2;                
    end process;
    
    process(in_clk)
    begin
        if rising_edge(in_clk) then
            in_strt <= '0';
            case r_Cntrl is
                when SET_TETA =>
                    in_teta <= conv_std_logic_vector(integer(((real(n_i) * r_PI/6.0) * real(2**MUL_COEFF))), DATA_SIZE);
                    in_strt <= '1';
                     r_Cntrl <= WAIT_DATA;
                when WAIT_DATA =>
                    if r_data_vld = '1' then
                        r_data_cos_real <= real(conv_integer(r_cos_data)) / real(2**MUL_COEFF);
                        r_data_sin_real <= real(conv_integer(r_sin_data)) / real(2**MUL_COEFF);
                        
                        r_mse_cos <= r_mse_cos + (cos(real(n_i) * r_PI/6.0) - (real(conv_integer(r_cos_data)) / real(2**MUL_COEFF)))**2.0 / 6.0;
                        r_mse_sin <= r_mse_sin + (sin(real(n_i) * r_PI/6.0) - (real(conv_integer(r_sin_data)) / real(2**MUL_COEFF)))**2.0 / 6.0;
                        if n_i = 5 then
                            r_Cntrl <= DONE;
                            n_i <= 0;                           
                        else
                            r_Cntrl <= SET_TETA;
                            n_i <= n_i + 1;
                        end if;
                        
                    end if;
                when DONE =>
                    null;
                when OTHERS => NULL;    
            end case;
        end if;
        
    end process;


    cordic_map : cordic_v1 generic map(
        ITERTATION => ITERTATION,
        VALUE_SIZE => VALUE_SIZE,
        MUL_COEFF => MUL_COEFF, -- 2^MULL_COEFF;
        DATA_SIZE => DATA_SIZE -- DATA_SIZE > MUL_COEFF + 2
    )
    port map(
        in_clk => in_clk,
        in_rst => '0',
        in_strt => in_strt,
        in_teta => in_teta, 
        out_cos_data => r_cos_data,
        out_sin_data => r_sin_data,
        out_data_vld => r_data_vld
    );
    
    


end Behavioral;

Vektörel Mod (Vectorial Mod)

Vektörel dairesel açı dönüşüm işlemlerinde temel amaç yazımızda verilen ilk denklemde tanımlanan y değişkeni değerini sıfıra yaklaştırmaktır .

Başlangıç değerleri x=1 ve z=0 seçildiği durumda kartezyen koordinat değerlerimin polar koordinat değerlerine dönüşümü yapılmaktadır .

K_i parametresi aşağıdaki gibi hesaplanmaktadır.

Aşağıda vektörel modda genlik ve açı değerlerini hesplayan VHDL kodları verilmiştir.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_SIGNED.ALL;
use IEEE.MATH_REAL.ALL;

entity cordic_rec2pol is
    generic(
		ITERTATION : integer := 20;
		VALUE_SIZE : integer := 20;
		MUL_COEFF : integer := 18; -- 2^MULL_COEFF;
		DATA_SIZE : integer := 24 -- DATA_SIZE > MUL_COEFF +2
	);
	port(
		in_clk : in std_logic;
		in_rst : in std_logic;
		in_strt : in std_logic;
		in_data_real : in std_logic_vector(DATA_SIZE - 1 downto 0);
		in_data_imag : in std_logic_vector(DATA_SIZE - 1 downto 0);
		out_data_r : out std_logic_vector(DATA_SIZE - 1 downto 0);
		out_data_phase : out std_logic_vector(DATA_SIZE - 1 downto 0);
		out_data_vld : out std_logic
	);
	
end cordic_rec2pol;

architecture Behavioral of cordic_rec2pol is
    
    constant c_PI : real := 3.14159_26535_89793_23846;   
    type t_Cordic_values is array (0 to VALUE_SIZE - 1) of real;
    type t_Std_Logic_Vector_data is array (0 to VALUE_SIZE - 1) of std_logic_vector(DATA_SIZE - 1 downto 0);
    type t_Int_data is array (0 to VALUE_SIZE - 1) of integer;
	
    function f_Conv_Real_to_Int(r_Cordic_values : t_Cordic_values; VALUE_SIZE, MUL_COEFF : integer ) return t_Int_data is
        variable v_Int_data : t_Int_data;
    begin
        for n_i in 0 to VALUE_SIZE - 1 loop 
            v_Int_data(n_i) := integer(r_Cordic_values(n_i) * real(2**MUL_COEFF));
        end loop;
        return v_Int_data;
        
    end f_Conv_Real_to_Int;   	
	
    function f_Conv_Int_to_Std_Logic_Vector(r_Int_values : t_Int_data; VALUE_SIZE, DATA_SIZE : integer ) return t_Std_Logic_Vector_data is
        variable v_Std_Logic_Vector_data : t_Std_Logic_Vector_data;
    begin
        for n_i in 0 to VALUE_SIZE - 1 loop 
            v_Std_Logic_Vector_data(n_i) := conv_std_logic_vector(r_Int_values(n_i), DATA_SIZE);
        end loop;
        return v_Std_Logic_Vector_data;
        
    end f_Conv_Int_to_Std_Logic_Vector;   	
	
    -- ****
    function f_Calc_tp_values(VALUE_SIZE : integer) return t_Cordic_values is
        variable v_tp_values : t_Cordic_values;
    begin
        v_tp_values(0) := 1.0;
        v_tp_values(1) := 1.0;
        v_tp_values(2) := 1.0;        
        for n_i in 3 to VALUE_SIZE - 1 loop
            v_tp_values(n_i) := v_tp_values(n_i - 1) / 2.0;
        end loop;
        return v_tp_values;
    end f_Calc_tp_values;
    
    constant c_tp_values : t_Cordic_values := f_Calc_tp_values(VALUE_SIZE);
    constant c_tp_int_values : t_Int_data := f_Conv_Real_to_Int(c_tp_values, VALUE_SIZE, MUL_COEFF);
	constant c_tp_std_values : t_Std_Logic_Vector_data := f_Conv_Int_to_Std_Logic_Vector(c_tp_int_values, VALUE_SIZE, DATA_SIZE);
	
    -- ****
    -- ****
    function f_Calc_atantp_values(c_tp_values : t_Cordic_values  ;VALUE_SIZE : integer) return t_Cordic_values is
        variable v_atantp_values : t_Cordic_values;
    begin
        v_atantp_values(0) := c_PI / 4.0;
        v_atantp_values(1) := c_PI / 4.0;
        v_atantp_values(2) := c_PI / 4.0;        
        for n_i in 3 to VALUE_SIZE - 1 loop
            v_atantp_values(n_i) :=  arctan(c_tp_values(n_i));
        end loop;
        return v_atantp_values;
    end f_Calc_atantp_values;
    
    constant c_atantp_values : t_Cordic_values := f_Calc_atantp_values(c_tp_values, VALUE_SIZE);
	constant c_atantp_int_values : t_Int_data := f_Conv_Real_to_Int(c_atantp_values, VALUE_SIZE, MUL_COEFF);
	constant c_atantp_std_values : t_Std_Logic_Vector_data := f_Conv_Int_to_Std_Logic_Vector(c_atantp_int_values, VALUE_SIZE, DATA_SIZE);
    -- ****    
    -- ****
    function f_Calc_K_values(c_atantp_values : t_Cordic_values; VALUE_SIZE : integer) return real is
        variable v_K : real;
    begin
        v_K := sqrt(2.0) / 4.0;     
        for n_i in 3 to VALUE_SIZE - 1 loop
            v_K := v_K * cos(c_atantp_values(n_i));
        end loop;
        return v_K;
    end f_Calc_K_values;
    
    constant c_K : real := f_Calc_K_values(c_atantp_values, VALUE_SIZE);
	constant c_K_std : std_logic_vector(DATA_SIZE - 1 downto 0) := conv_std_logic_vector(integer(c_K * real(2**MUL_COEFF)), DATA_SIZE);
    -- ****      
	
    type t_Cordic_Cntrl is (IDLE, SET_TX, MUL_PARAM, ADD_PARAM, CHK_ITER, MUL_CONSTANT, DONE);
    signal r_Cordic_Cntrl : t_Cordic_Cntrl := IDLE;  	
	
	signal r_Z : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0');
	signal r_TX : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0');
	signal r_data_real : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0');
	signal r_data_r : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0');
	signal r_data_real_mul : std_logic_vector(2 * DATA_SIZE - 1 downto 0) := (others => '0');
	signal r_data_real_add : std_logic_vector(2 * DATA_SIZE - 1 downto 0) := (others => '0');
	signal r_data_imag : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0');
	signal r_data_phase : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0');
	signal r_data_imag_add : std_logic_vector(2 * DATA_SIZE - 1 downto 0) := (others => '0');
	signal n_i : integer range 0 to VALUE_SIZE := 0;
	signal r_data_vld : std_logic := '0';
    
begin

	out_data_r <= r_data_r;
	out_data_phase <= r_data_phase;
	out_data_vld <= r_data_vld;

    process(in_clk, in_rst, in_strt)
    begin
        if in_rst = '1' then
            r_Cordic_Cntrl <= IDLE;
			r_Z <= (others => '0');
			r_TX <= (others => '0');
			r_data_real <= (others => '0');
			r_data_r <= (others => '0');
			r_data_real_add <= (others => '0');
			r_data_real_mul <= (others => '0');
			r_data_imag <= (others => '0');
			r_data_phase <= (others => '0');
			r_data_imag_add <= (others => '0');
            r_data_vld <= '0';
			n_i <= 0;
            
        elsif rising_edge(in_clk) then
            r_data_vld <= '0';
            case r_Cordic_Cntrl is  
                when IDLE =>				
                    if in_strt = '1' then
						r_Z <= (others => '0');
						r_TX <= (others => '0');
						r_data_real <= in_data_real;
						r_data_imag <= in_data_imag;
						n_i <= 0;
                        r_Cordic_Cntrl <= SET_TX;                     
                    end if;
                
                when SET_TX =>
					r_TX <= r_data_real;
					r_Cordic_Cntrl <= MUL_PARAM;  
					
				when MUL_PARAM =>	
					r_data_real_add <= r_data_imag * c_tp_std_values(n_i);
					r_data_imag_add <= r_TX * c_tp_std_values(n_i);
					r_Cordic_Cntrl <= ADD_PARAM; 
					
				when ADD_PARAM =>	
					if r_data_imag(r_data_imag'high) = '1' then
						r_data_real <= r_data_real - r_data_real_add(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);
						r_data_imag <= r_data_imag + r_data_imag_add(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);
						r_Z <= r_Z - c_atantp_std_values(n_i);
					else
						r_data_real <= r_data_real + r_data_real_add(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);
						r_data_imag <= r_data_imag - r_data_imag_add(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);
						r_Z <= r_Z + c_atantp_std_values(n_i);					
					end if;
					r_Cordic_Cntrl <= CHK_ITER; 

				when CHK_ITER =>		
					if n_i = ITERTATION - 1 then
                        n_i <= 0;
                        r_Cordic_Cntrl <= MUL_CONSTANT;
                    else
                        n_i <= n_i + 1;
                        r_Cordic_Cntrl <= SET_TX;
                    end if;
                
                when MUL_CONSTANT =>
                    r_data_real_mul <= r_data_real * c_K_std;
                    r_Cordic_Cntrl <= DONE;
                    
                when DONE =>  
					r_data_vld <= '1';
                    r_data_r <= r_data_real_mul(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);
					r_data_phase <= r_Z;
                    r_Cordic_Cntrl <= IDLE;          
					
                when others => NULL;
            end case;
        end if;
        
    end process;

end Behavioral;

Aşağıda vektörel modda genlik ve açı değerlerini hesaplayan cordic_rec2pol.vhd VHDL kodunun benzetimini yapılabilmesi için oluşturulmuş sınama kodları verilmiştir.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_SIGNED.ALL;
use IEEE.MATH_REAL.ALL;

entity tb_cordic_rec_pol is
end tb_cordic_rec_pol;

architecture Behavioral of tb_cordic_rec_pol is

	component cordic_rec2pol
    generic(
		ITERTATION : integer := 2;
		VALUE_SIZE : integer := 8;
		MUL_COEFF : integer := 12; -- 2^MULL_COEFF;
		DATA_SIZE : integer := 16 -- DATA_SIZE > MUL_COEFF +2
	);
	port(
		in_clk : in std_logic;
		in_rst : in std_logic;
		in_strt : in std_logic;
		in_data_real : in std_logic_vector(DATA_SIZE - 1 downto 0);
		in_data_imag : in std_logic_vector(DATA_SIZE - 1 downto 0);
		out_data_r : out std_logic_vector(DATA_SIZE - 1 downto 0);
		out_data_phase : out std_logic_vector(DATA_SIZE - 1 downto 0);
		out_data_vld : out std_logic
	);
	end component;
	
    constant CLK_PERIOD : time := 10 ns;
    constant r_PI : real := 3.14159_26535_89793_23846;
    
    constant ITERTATION : integer := 24;
    constant VALUE_SIZE : integer := 24;
    constant MUL_COEFF : integer := 24; -- 2^MULL_COEFF;
    constant DATA_SIZE : integer := 30; -- DATA_SIZE > MUL_COEFF +2    
    signal in_clk : std_logic := '0';
    signal in_strt : std_logic := '0';
    signal in_data_real : std_logic_vector(DATA_SIZE - 1 downto 0);
	signal in_data_imag : std_logic_vector(DATA_SIZE - 1 downto 0);
    signal n_i : integer := 0;
    signal r_data_r : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0'); 
    signal r_data_phase : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0');
    signal r_data_vld : std_logic := '0';
    type t_Cntrl is (SET_TETA,WAIT_DATA, DONE );
    signal r_Cntrl : t_Cntrl := SET_TETA;
    signal r_data_r_real : real := 0.0;
    signal r_data_phase_real : real := 0.0;
    
    signal r_mse_mag : real := 0.0;
    signal r_mse_teta : real := 0.0;


begin

    
    process
    begin
        in_clk <= '1';
        wait for CLK_PERIOD / 2;
        in_clk <= '0';
        wait for CLK_PERIOD / 2;                
    end process;
	
	process(in_clk)
    begin
        if rising_edge(in_clk) then
            in_strt <= '0';
            case r_Cntrl is
                when SET_TETA =>
                    in_data_real <= conv_std_logic_vector( integer(real(n_i) / 5.0 * real(2**MUL_COEFF)), DATA_SIZE);
					in_data_imag <= conv_std_logic_vector( integer(real(5 - n_i) / 5.0 * real(2**MUL_COEFF)), DATA_SIZE);
                    in_strt <= '1';
                     r_Cntrl <= WAIT_DATA;
                when WAIT_DATA =>
                    if r_data_vld = '1' then
                        r_data_r_real <= real(conv_integer(r_data_r)) / real(2**MUL_COEFF);
                        r_data_phase_real <= real(conv_integer(r_data_phase)) / real(2**MUL_COEFF);
                        r_mse_mag  <= r_mse_mag + (sqrt((real(n_i)/5.0)**2 + (real(5 - n_i) / 5.0)**2) -
                         (real(conv_integer(r_data_r)) / real(2**MUL_COEFF)))**2.0 / 6.0;
                        
                        r_mse_teta <= r_mse_teta + (arctan(real(5 - n_i), real(n_i)) -
                         (real(conv_integer(r_data_phase)) / real(2**MUL_COEFF)))**2.0 / 6.0;
                        
                        
                        if n_i = 5 then
                            r_Cntrl <= DONE;
                            n_i <= 0;                           
                        else
                            r_Cntrl <= SET_TETA;
                            n_i <= n_i + 1;
                        end if;
                        
                    end if;
                when DONE =>
                    null;
                when OTHERS => NULL;    
            end case;
        end if;
	end process;

	cordic_rec2pol_map : cordic_rec2pol generic map(
        ITERTATION => VALUE_SIZE,
        VALUE_SIZE => VALUE_SIZE,
        MUL_COEFF => MUL_COEFF, -- 2^MULL_COEFF;
        DATA_SIZE => DATA_SIZE -- DATA_SIZE > MUL_COEFF + 2
    )
    port map(
        in_clk => in_clk,
        in_rst => '0',
        in_strt => in_strt,
        in_data_real => in_data_real, 
		in_data_imag => in_data_imag, 
        out_data_r => r_data_r,
        out_data_phase => r_data_phase,
        out_data_vld => r_data_vld
    );
    
	
end Behavioral;

NOT: Bu yazıda, Suhap ŞAHİN, Burcu Kır Savaş, “Jenerik CORDIC Algoritmasının FPGA’DA Donanımsal Gerçeklenmesi”,  Sakarya Üniversitesi Fen Bilimleri Enstitüsü Dergisi, 27 (1), 2017, çalışmadan direk alıntı yapılmış ve faydalanılmıştır. Dr. Suhap Şahin aynı zamanda doktora tez Hocam’dır. Kendisinin izni ile konu anlatımında bilgiler kullanılmıştır.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

This site uses Akismet to reduce spam. Learn how your comment data is processed.