VHDL – CORDIC modülü


VHDL ile tasarladığım CORDIC modülü. Bu ilk sürümde bazı hatalar/sorunlar çıkabilir. İleride bu modülü çalışmalarımda kullandıkça düzeltmeyi düşünüyorum. ‘pi’den daha büyük döndürme değerleri için düzgün çalışmadığını gözlemledim. Sanırım matematiksel işlemlerde bir sorun var.

Not: Kodda iki basit hata buldum. Kısa zamanda çözmeye çalışacağım. Çıkışın genliği yanlış geliyor. Açı da sorun yok.

Kodda çok bariz bir hata vardı. CORDIC’te her kademe atan(2^(-i)) kadar döndürme yapabiliyor. İlk kademe 45 derece olan atan(2^0) ile başlıyor. Ben yanlışlıkla ilk kademeyi atan(2^-1)’den (yaklaşık 26 derece) başlatmıştım. Kademeler ilerledikçe açı küçüldüğü için modül toplamda 90 derece bir dönme yapamıyor. Bunu çözmek için başlangıca ekstradan iki adet atan(2^-1)’lik kademe ekledim (Kafam nerdeyse!). Bu da işleri iyice karıştırdı. Şimdi o kademeleri kaldırdım. İlk kademeyi i=0’dan başlattım. Sorun ortadan kalktı.

Dosyayı indirmek için tıklayın.

/*

	CORDIC module by Hasan Yavuz ÖZDERYA ( hy [at] ozderya.net )
	
	Trabzon KTU DSPLAB 2013
	
	v0.2 , 08.04.2013	: corrected barely wrong implementation
	v0.1 , 19.03.2013
	
*/

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use ieee.fixed_pkg.all;
/*
	Main CORDIC module
*/
entity cordic is
	
	Generic(n:integer := 16;	-- bus width (n=16 -> Q.15), internals work with Q1.15
			ns:integer := 10);	-- number of stages
	Port(
		rotation: in	sfixed(3 downto -(n-4));	-- rotation input
		d_r		: in	sfixed(0 downto -(n-1));	-- inputs
		d_c		: in	sfixed(0 downto -(n-1));
		q_r		: out	sfixed(0 downto -(n-1));	-- outputs
		q_c		: out	sfixed(0 downto -(n-1));
		clk		: in	std_logic;
		reset	: in	std_logic
	);
	
	subtype tfixed is sfixed(1 downto -(n-1));		-- type used for internals
	subtype rtfixed is sfixed(3 downto -(n-4));		-- type used for radians
	
end entity cordic; 

architecture single_unit of cordic is

	-- first stage (#-1,jumper stage) rotates 90|180|270 degree if required
	
	type tfixed_array is array(-1 to ns-1) of tfixed;
	type rtfixed_array is array(-1 to ns-1) of rtfixed;
	type rtfixed_array2 is array(0 to ns-1) of rtfixed;
	
	-- stage input output signals
	
	signal 	s_beta,s_phi,							-- phi: target rotation
			s_beta_o,s_phi_o : rtfixed_array;		-- beta: rotation so far
	
	signal 	s_d_r, s_d_c,							-- d_r,d_c: stage input real and complex
			s_q_r, s_q_c : tfixed_array;			-- q_r,q_c: stage output real and complex
	
	-- constants
	signal atans	: rtfixed_array2;	-- holds arctangents of 2^-i (i=0,1,2..)
	
	constant c_K		: tfixed := to_sfixed(0.607253031529134,1,-(n-1));
	constant pi_3_2		: rtfixed := to_sfixed(MATH_3_PI_OVER_2,3, -(n-4));
	constant pi			: rtfixed := to_sfixed(MATH_PI,3, -(n-4));
	constant pi_1_2		: rtfixed := to_sfixed(MATH_PI_OVER_2,3, -(n-4));
	constant pi_1_4		: rtfixed := to_sfixed(MATH_PI_OVER_4,3, -(n-4));

begin
	
	-- generate required constants for iterative stages atan(2^-i)
	gen_atans: for i in 0 to ns-1 generate
		constant c_atan : real := arctan(2.0**(-i));
	begin
		atans(i) <= to_sfixed(c_atan,rotation);
	end generate;
	
	-- generate intertal connections between stages
	gen_internals:for i in 0 to ns-1 generate  -- except first stage which is input
				
		s_beta(i) <= s_beta_o(i-1);
		s_phi(i) <= s_phi_o(i-1);
		
		s_d_r(i) <= s_q_r(i-1);
		s_d_c(i) <= s_q_c(i-1);
					
	end generate;
	
	process(clk)
		variable a,b,p,k	: tfixed;
		variable beta,phi	: rtfixed;
	begin
		
		if reset = '1' then
			
			q_r <= to_sfixed(0,q_r);
			q_c <= to_sfixed(0,q_c);
			s_beta_o <= (others => to_sfixed(0,q_r));
			s_phi_o <= (others => to_sfixed(0,q_r));
			s_q_r <= (others => to_sfixed(0,q_r));
			s_q_c <= (others => to_sfixed(0,q_r));
			
		elsif rising_edge(clk) then
			
			-- register inputs for first stage
			s_beta(-1) <= to_sfixed(0,d_r);
			s_phi(-1) <= rotation;
			s_d_r(-1) <= resize(d_r,a);
			s_d_c(-1) <= resize(d_c,a);	
			
			for i in -1 to ns-1 loop
				
				a := s_d_r(i);
				b := s_d_c(i);
				
				beta := s_beta(i);
				phi := s_phi(i);
				
				if i=-1 then		-- jumper stage for r>pi/2
					
					if phi > pi_3_2 then
						p := b;
						k := resize(-a,a);
						phi := resize(phi-pi_3_2,phi);
					elsif phi > pi then
						p := resize(-a,a);
						k := resize(-b,a);
						phi := resize(phi-pi,phi);
					elsif phi > pi_1_2 then
						p := resize(-b,a);
						k := a;
						phi := resize(phi-pi_1_2,phi);
					else
						p := a;
						k := b;
					end if;
					
				else				-- iterative stages
					
					if  phi>beta then
						
						p := resize(a-scalb(b,-i),a);	-- scalb shifts number
						k := resize(b+scalb(a,-i),a);	-- does binary division
						beta := resize(beta+atans(i),beta);
						
					else
						
						p := resize(a+scalb(b,-i),a);
						k := resize(b-scalb(a,-i),a);
						beta := resize(beta-atans(i),beta);
						
					end if;
					
				end if;
				
				s_q_r(i) <= p;
				s_q_c(i) <= k;
				
				s_beta_o(i) <= beta;
				s_phi_o(i) <= phi;
												
			end loop;
			
			-- last stage to output (notice 'c_K' scaler)
			q_r <= resize(c_K*s_q_r(ns-1),q_r);
			q_c <= resize(c_K*s_q_c(ns-1),q_r);
			
		end if;
		
	end process;
		
end single_unit;

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.