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 sınır aralığında tanımlı CORDIC algoritması genel ifadesi verilmiştir.

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

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ı 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 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 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ı ’yı vermelidir. Aşağıda verilen denklemde tanımlı
parametresi
değerlerini almaktadır.

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

Yukarıdaki ifadeleri kullanarak denklemi güncellediğimizde

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

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 değişkeni değerini sıfıra yaklaştırmaktır .
Başlangıç değerleri ve
seçildiği durumda kartezyen koordinat değerlerimin polar koordinat değerlerine dönüşümü yapılmaktadır .

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.