Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
14 years ago

Trying to develop my own Cordic core at VHDL.. problems

Hello i am trying to develop my own Cordic core at VHDL.. but i am having some problems.

I basically have a block of gain and a block of angles that works like that (just a snap)


...
case indice_i is
		    when "000000" => angulo_o_r <= to_sfixed(0.7854, 4, -27);
          when "000001" => angulo_o_r <= to_sfixed(0.4636, 4, -27);
          when "000010" => angulo_o_r <= to_sfixed(0.2450, 4, -27);
          when "000011" => angulo_o_r <= to_sfixed(0.1244, 4, -27);
          when "000100" => angulo_o_r <= to_sfixed(0.0624, 4, -27);
...

And i have my main CORDIC core... i am trying to do something like this (matlab)


ka = 1;
for j=1:n;
    Kvalues(j) = ka
    angles(j) = atan(ka);
    ka = ka * 0.5;
end;
for l=1:n;
    K = Kvalues(l);
    phase_rads = angles(l);
    tmp_real = real;

However for doesnt work the same way in VHDL, so i tried to make a state machine with the following states:

INIT (reset state) -> CALC_CORDIC ->

INCREMENT_COUNTER->CALC_CORDIC (24 times)

then -> FINISH

Where my counter is the input for my angle/gain blocks and i use the output from those blocks in my calc_cordic.

Too bad it isn't working and i don't know why..

I am getting this error


Error (10028): Can't resolve multiple constant drivers for net "angulo_indice" at cordic.vhd(66)

But i don't have multiple constant drivers for that net..

my code is here


	-- Logic to advance to the next state
	process (clk_i, rst_i_n)
	begin
		if rst_i_n = '0' then
			state <= init;
		elsif (rising_edge(clk_i)) then
			case state is
				when init=>
					if ena_i = '1' and working = '0' then
						state <= corrigi_q;
					else
						state <= init;
					end if;
				when corrigi_q=>
					if finish_quadrante = '1' then
						state <= calcula_cordic;
					else
						state <= corrigi_q;
					end if;
				when calcula_cordic=>
				   if finish_cordic ='1' then
					   state <= fim;
					end if;
					if finish_calc = '1' then
						state <= incrementa_cont;
					end if;
					if finish_calc = '0' and finish_cordic = '0' then
						state <= calcula_cordic;
					end if;
				when incrementa_cont =>
					   state <= calcula_cordic;
				when fim =>
						state <= init;
			end case;
		end if;
	end process;
	-- Output depends solely on the current state
	process (state)
	begin
		case state is
			when init =>
			      pi <= to_sfixed (3.1416, 4, -27);
               pi_2 <= to_sfixed (1.57, 4, -27);
          		parte_real <= (others => '0');
          		parte_imaginaria <= (others => '0');
               temp_parte_real <= (others => '0');
               acc_phase <= (others => '0');
               acc_phase_rads <= (others => '0');
               K <= (others => '0');
               indice <= (others => '0');
               ganho_indice <= (others => '0');
               angulo_indice <= (others => '0');
               tmp_mult_im_k <= (others => '0');
               tmp_mult_re_k <= (others => '0');
               magnitude_o_r <= (others => '0');
               fase_o_r <= (others => '0');
					finish_quadrante <= '0';
				 	finish_cordic <= '0';
					finish_calc <= '0';
					working <= '0';
			
			when corrigi_q =>
			      working <= '1';
				   parte_real <= to_sfixed(real_i, 4, -27);
		         parte_imaginaria <= to_sfixed(imag_i, 4, -27);
				   if parte_real < "0" then
   		         temp_parte_real <= parte_real;
			         if parte_imaginaria > "0" then
			            parte_real <= parte_imaginaria;
				         parte_imaginaria <= resize(((not temp_parte_real) + to_sfixed(1, 4, -27)),4,-27); --negativo
				         acc_phase_rads <= resize(((not pi_2) + to_sfixed(1, 4, -27)),4,-27);--negativo
			         else
			            parte_real <= resize(((not parte_imaginaria) + to_sfixed(1, 4, -27)),4,-27); --negativo
		               parte_imaginaria <= temp_parte_real;
				         acc_phase_rads <= pi_2;
			         end if;
	            else
		            acc_phase_rads <= (others => '0');
		         end if;
				   finish_quadrante <= '1';
				
			when calcula_cordic =>
					K <= to_sfixed(ganho_indice, 4, -27);
	            acc_phase  <= to_sfixed(angulo_indice, 4, -27);
	            temp_parte_real <= parte_real;
	            if parte_imaginaria >= "0" then
	               tmp_mult_re_k <= temp_parte_real * K;
	               tmp_mult_im_k <= parte_imaginaria * K;
		 
	               parte_real <= resize((parte_real + tmp_mult_im_k),4,-27);
		            parte_imaginaria <= resize((parte_imaginaria - tmp_mult_re_k),4,-27);
		            acc_phase_rads <= resize((acc_phase_rads - acc_phase),4,-27);
	            else
  	               tmp_mult_re_k <= temp_parte_real * K;
	               tmp_mult_im_k <= parte_imaginaria * K;
		 
	               parte_real <= resize((parte_real - tmp_mult_im_k),4,-27);
		            parte_imaginaria <= resize((parte_imaginaria + tmp_mult_re_k),4,-27);
		            acc_phase_rads <= resize((acc_phase_rads + acc_phase),4,-27);
	            end if;
					if indice < 24 then finish_calc <= '1'; end if;
					if indice = 24 then 
					finish_calc <= '0'; 
					finish_cordic <= '1'; 
					fase_o_r <= resize((not acc_phase_rads) + to_sfixed(1, 4, -27),4,-27) ;
					magnitude_o_r <= resize(parte_real * to_sfixed(0.60723, 4, -27),4,-27);
					end if;
					   
					   
					
			when incrementa_cont =>
			      indice <= indice + 1;
					finish_calc <= '0';
				   
			when fim =>
				   fase_o <= to_slv(fase_o_r);
               magnitude_o <= to_slv(magnitude_o_r);
					working <= '0';
		end case;
	end process;
end rtl;

and my gain/angle blocks declarations


  component angulo_atan is
	port(
    indice_i : in std_logic_vector (5 downto 0);
    angulo_o : out std_logic_vector (31 downto 0)	);
   end component;
   component ganho_k is
	port(
    indice_i : in std_logic_vector (5 downto 0);
    ganho_o : out std_logic_vector (31 downto 0)	);
   end component;


   angulo_inst : angulo_atan
   port map( 
          indice_i => std_logic_vector(indice),
          angulo_o => angulo_indice);
 
   ganho_inst : ganho_k
   port map(
	       indice_i => std_logic_vector(indice),
	       ganho_o => ganho_indice);

ANY HELP IS rEALLY apreciated

9 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Some question immediatly arrise:

    Why is pi and pi_2 a signal and not a constant?

    Why have you not clocked the second process? the way it is currently, you are going to get a LOT of latches (which are bad) because you have not assigned every signal in every branch. You also have an incomplete sensitivity list (all of the signals that drive other signals MUST be in the sensitivity list, otherwise the firmware will not match the simulation).

    For the error - I can only only assume you have assigned angulo_indece more than once.

    Basically, there are many many problems with this code.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Well, I just spotted the problem. You have angulo_indece driven from the 2nd process and the output of the atan block.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    And a 3rd thing - With the atan and ganho_k modules- you appear to have created an asynchronous rom. This is not a very good idea (as all your logic is going to dissapear). You are going to get very very poor Fmax performance.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Tricky thanks so much for your really good help.

    To do a synchronous rom i have to drive the clock signal and my mux will only happen in the clk signal right?

    I didnt clock the second process because it's a moore state machine and the 2nd process says it's only sensitive to the state.

    How can i solve this lach issue with a moore sm
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    for the rom - take the clock into the separate modules and make the process inside the modules sensitive to clock in the normal way.

    For your second issue, to solve the latch problem you need to do what I said, you need to make sure every signal is given an output in EVERY branch AND you put ALL the signals (that are used to assign other signals) in the sensitivity list. This will probably completly change the behaviour you've seen in simulation, but it will reflect what will happen on the real chip.

    As for meely/more, it will still be a moore state machine if you clock it - its just delayed by 1 clock cycle. But it will actually work like you intended (and simulation will match hardware). And you wont have to put every signal in every branch.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Okay i will make some adjusments.

    Thanks for the knowledge share, seriously :)
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Please see the next post, this one is already old (i've changed the implementation):)

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    My final version of the RTL code

    
    --=============================
    -- Cordic 
    -- Implementacao do algoritmo de cordic para obter magnitude e angulo a partir de um numero complexo
    --=============================
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    library work;
    use work.all;
    use work.fixed_float_types.all;
    use work.fixed_pkg.all;
    -- entity declaration
    entity cordic is
       port(
          clk_i    : in std_logic;
          rst_i_n  : in std_logic;
    		ena_i    : in std_logic;
    		real_i	: in std_logic_vector(31 downto 0);
    		imag_i   : in std_logic_vector(31 downto 0);
    		fase_o	: out std_logic_vector(31 downto 0);
    		magnitude_o	: out std_logic_vector(31 downto 0)
       );
    end cordic;
    architecture rtl of cordic is
    	-- Build an enumerated type for the state machine
    	type state_type is (init, corrige_q_p1, corrige_q_p2, calcula_cordic_p1, calcula_cordic_p2, incrementa_cont, fim);
    	-- Register to hold the current state
    	signal state   : state_type;
    	signal next_state : state_type;
    	-- Registers to control the state machine flow
    	signal finish_quadrante : std_logic;
    	signal finish_cordic : std_logic;
    	signal finish_calc : std_logic;
    	
    	-- Internal signals
    	signal parte_real,parte_imaginaria, temp_parte_real : sfixed (4 downto -27);
       constant pi : sfixed (4 downto -27) := to_sfixed (3.1416, 4, -27); 
    	constant pi_2 : sfixed (4 downto -27) := to_sfixed (1.57, 4, -27);
       signal fase_o_r, magnitude_o_r : sfixed (4 downto -27);
       signal acc_phase, acc_phase_rads, K : sfixed (4 downto -27);
       signal indice : unsigned (5 downto 0);
    	signal working : std_logic;
    	signal variavel_nova : std_logic;
       signal indice2 : unsigned (5 downto 0);
       signal angulo_indice : std_logic_vector(31 downto 0);
       signal ganho_indice : std_logic_vector(31 downto 0);
       signal tmp_mult_im_k: sfixed (sfixed_high ( 4, -27, '*', 4, -27) downto sfixed_low ( 4, -27, '*', 4, -27));
       signal tmp_mult_re_k: sfixed (sfixed_high ( 4, -27, '*', 4, -27) downto sfixed_low ( 4, -27, '*', 4, -27));
    	signal corrige_q_p1_end : std_logic;
    	
    	-- Instantiation of other modules
       component angulo_atan is
    	port(
    	 clk_i    : in std_logic;
        rst_i_n  : in std_logic;
        indice_i : in std_logic_vector (5 downto 0);
        angulo_o : out std_logic_vector (31 downto 0)	);
       end component;
       component ganho_k is
    	port(
    	 clk_i    : in std_logic;
        rst_i_n  : in std_logic;
        indice_i : in std_logic_vector (5 downto 0);
        ganho_o : out std_logic_vector (31 downto 0)	);
       end component;
    begin
       angulo_inst : angulo_atan
       port map( 
    	       clk_i    => clk_i,
              rst_i_n  => rst_i_n,
              indice_i => std_logic_vector(indice),
              angulo_o => angulo_indice);
     
       ganho_inst : ganho_k
       port map(
          	 clk_i    => clk_i,
              rst_i_n  => rst_i_n,
    	       indice_i => std_logic_vector(indice2),
    	       ganho_o => ganho_indice);
       
    	
    	-- Output depends solely on the current state
    	process (clk_i, rst_i_n, state)
    	begin
    		if rst_i_n = '0' then
    			next_state <= init;
    		elsif (rising_edge(clk_i)) then
    			state <= next_state;
    		case state is
    			when init =>
    			      indice2 <=(others => '0');
              		parte_real <= (others => '0');
              		parte_imaginaria <= (others => '0');
                   temp_parte_real <= (others => '0');
                   acc_phase <= (others => '0');
                   acc_phase_rads <= (others => '0');
                   K <= (others => '0');
                   indice <= (others => '0');
                   tmp_mult_im_k <= (others => '0');
                   tmp_mult_re_k <= (others => '0');
                   magnitude_o_r <= (others => '0');
                   fase_o_r <= (others => '0');
    					finish_quadrante <= '0';
    				 	finish_cordic <= '0';
    					finish_calc <= '0';
    					working <= '0';
    					corrige_q_p1_end <= '0';
    					next_state <= corrige_q_p1;
    			
    			when corrige_q_p1 =>
    			      working <= '1';
    				   parte_real <= to_sfixed(real_i, 4, -27);
    		         parte_imaginaria <= to_sfixed(imag_i, 4, -27);
    					next_state <= corrige_q_p2;
    					
    			when corrige_q_p2 =>
    				   if parte_real < "0" then
       		         temp_parte_real <= parte_real;
    			         if parte_imaginaria > "0" then
    			            parte_real <= parte_imaginaria;
    				         parte_imaginaria <= resize(((not temp_parte_real) + to_sfixed(1, 4, -27)),4,-27); --negativo
    				         acc_phase_rads <= resize(((not pi_2) + to_sfixed(1, 4, -27)),4,-27);--negativo
    			         else
    			            parte_real <= resize(((not parte_imaginaria) + to_sfixed(1, 4, -27)),4,-27); --negativo
    		               parte_imaginaria <= temp_parte_real;
    				         acc_phase_rads <= pi_2;
    			         end if;
    	            else
    		            acc_phase_rads <= (others => '0');
    		         end if;
        				next_state <= calcula_cordic_p1;
    				
    			when calcula_cordic_p1 =>
    					K <= to_sfixed(ganho_indice, 4, -27);
    	            acc_phase  <= to_sfixed(angulo_indice, 4, -27);
    	            temp_parte_real <= parte_real;
    					next_state <= calcula_cordic_p2;
    					variavel_nova <= '1';
    	            
    					
    			when calcula_cordic_p2 =>
    	            if parte_imaginaria >= "0" then
    	               tmp_mult_re_k <= temp_parte_real * K;
    	               tmp_mult_im_k <= parte_imaginaria * K;
    		 
    	               parte_real <= resize((parte_real + tmp_mult_im_k),4,-27);
    		            parte_imaginaria <= resize((parte_imaginaria - tmp_mult_re_k),4,-27);
    		            acc_phase_rads <= resize((acc_phase_rads - acc_phase),4,-27);
    	            else
      	               tmp_mult_re_k <= temp_parte_real * K;
    	               tmp_mult_im_k <= parte_imaginaria * K;
    		 
    	               parte_real <= resize((parte_real - tmp_mult_im_k),4,-27);
    		            parte_imaginaria <= resize((parte_imaginaria + tmp_mult_re_k),4,-27);
    		            acc_phase_rads <= resize((acc_phase_rads + acc_phase),4,-27);
    	            end if;
    					if indice < 24 then next_state <= incrementa_cont; 
    					elsif indice = 24 then 
    					next_state <= fim ;
    					fase_o_r <= resize((not acc_phase_rads) + to_sfixed(1, 4, -27),4,-27) ;
    					magnitude_o_r <= resize(parte_real * to_sfixed(0.60723, 4, -27),4,-27);
    					end if;
    					
    			when incrementa_cont =>
    			      next_state <= calcula_cordic_p1;
    					if variavel_nova = '1' then
    					variavel_nova <= '0';
    			      indice <= indice + 1;
    			      indice2 <= indice2 + 1;
    					end if;
    					
    				   
    			when fim =>
    				   fase_o <= to_slv(fase_o_r);
                   magnitude_o <= to_slv(magnitude_o_r);
    					next_state <= init;
    		end case;
    		end if;
    	end process;
    end rtl;
    

    It isnt working.. i am having the following problem in modelsim.

    I have circled the parts of my simualtion with problems.. the signals in this part of my code

    when corrige_q_p2 =>
    				   if parte_real < "0" then
       		         temp_parte_real <= parte_real;
    			         if parte_imaginaria > "0" then
    			            parte_real <= parte_imaginaria;
    				         parte_imaginaria <= resize(((not temp_parte_real) + to_sfixed(1, 4, -27)),4,-27); --negativo
    				         acc_phase_rads <= resize(((not pi_2) + to_sfixed(1, 4, -27)),4,-27);--negativo

    are changing way too fast.. and i am having the following warning

    Error: :work:fixed_pkg: Unbounded number passed, was a literal used?