Перейти к содержанию

    

sine with cordic vhdl

Привет всем. Просто доделал, решил поделиться) Может молодым спецам пригодится)

Кордик для вычисления синуса 100KHz c четвертью в 250 тактов. (если какие нибудь замечания будут, или советы по оптимизации, был бы рад)

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_SIGNED.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity Toplvl is

port ( 
		clk 		: std_logic;
		reset 	: std_logic;
		sinus1 	: out std_logic_vector(16 downto 0));
end Toplvl;

architecture Behavioral of Toplvl is

signal quarter_1 : std_logic_vector (1 downto 0);
signal t 		  : std_logic_vector (16 downto 0);
signal e 		  : std_logic_vector (16 downto 0);


component math
port ( 
			clk 		: in std_logic;
			reset 	: in std_logic;
			qu			: out std_logic_vector (1 downto 0);
			cosin 	: out std_logic_vector (16 downto 0);
			sinus 	: out std_logic_vector (16 downto 0));
end component;

component right
port ( 
		clk 		: in std_logic;
		reset 	: in std_logic;
		x 			: in std_logic_vector(16 downto 0);
		y 			: in std_logic_vector(16 downto 0);
		quarter  : in std_logic_vector (1 downto 0);
		xo 		: out std_logic_vector(16 downto 0);
		yo 		: out std_logic_vector(16 downto 0));
end component;

begin

--sinus1 <= yx;

math_end : math
port map (
clk => clk,
reset => reset,
qu => quarter_1,
cosin => t,
sinus => e);

right_end : right 
port map (
clk => clk,
reset => reset,
x => t,
y => e,
quarter => quarter_1,
yo => sinus1);

end Behavioral;

 

entity math is
port ( 
			clk 		: in std_logic;
			reset 	: in std_logic;
			qu			: out std_logic_vector (1 downto 0);
			sinus 	: out std_logic_vector (16 downto 0);
			cosin 	: out std_logic_vector (16 downto 0));
end math;

architecture Behavioral of math is

type my_type is array (0 to 16) of signed (16 downto 0);
signal x : my_type;
signal y : my_type;
signal z : my_type;
signal j : my_type :=("00111110011110010", "00100100111011010", "00010011011111111", "00001001111011110", "00000100111101111", 
														"00000010011111000", "00000001001111011", "00000000100111110", "00000000010011011", "00000000001010000",
															 "00000000000101000", "00000000000010100", "00000000000001010", "00000000000000101", "00000000000000011",
															  "00000000000000010", "00000000000000001");
signal l : std_logic_vector(16 downto 0);
signal f : std_logic_vector(16 downto 0);
component delay
port (
		clk 	: in std_logic;
		reset : in std_logic;
		quarter_do : out std_logic_vector(1 downto 0));
end component;

component rotation 
generic (
			first  : integer := 0;							
			second : integer := 1;
			third  : integer := 2;
			fourth : integer := 3);
  Port ( 
			clk 			: in std_logic;			
			reset 		: in std_logic;
		Angle 		: out std_logic_vector (12 downto 0);			
		quarter_in  : out std_logic_vector (1 downto 0));
end component;

signal xangle  : std_logic_vector(12 downto 0);
signal xxangle : signed(16 downto 0);

begin

rotation_XYN : rotation
port map (
  clk => clk,
Angle => xangle,
reset => reset
);

delay_XYN : delay
port map (
  clk => clk,
reset => reset,
quarter_do => qu
);

xxangle(16) <= '0';
xxangle(15 downto 4) <= signed(xangle(11 downto 0));
xxangle(3 downto 0) <= (others => '0');

process(clk)
begin
if rising_edge(clk) then
if reset <= '1' then
	x(0) <= "00000100110110110";
	y(0) <= "00000000000000000";
	z(0) <= signed(xxangle);
		For n in 0 to 15 loop
			if (z(n) < 0) then 
				x(n+1) <= x(n) + (y(n)/2**n);
				y(n+1) <= y(n) - (x(n)/2**n);
				z(n+1) <= z(n) + j(n);
			else
				x(n+1) <= x(n) -(y(n)/2**n);
				y(n+1) <= y(n) +(x(n)/2**n);
				z(n+1) <= z(n) - j(n);
			end if;
		f <= std_logic_vector(x(16));
		l <= std_logic_vector(y(16)); 
	cosin <= f;
	sinus <= l;
	end loop;
end if;
end if;
end process;

end Behavioral;

 

entity rotation is
generic (
			first  : integer := 0;							
			second : integer := 1;
			third  : integer := 2;
			fourth : integer := 3);
  Port ( 
			clk 			: in std_logic;			
			reset 		: in std_logic;
		Angle 		: out std_logic_vector (12 downto 0);			
		quarter_in  : out std_logic_vector (1 downto 0));
end rotation;

architecture Behavioral of rotation is

signal Ang			 : std_logic_vector (12 downto 0) := (others => '0');
signal state		 : unsigned (1 downto 0) := to_unsigned(first,2);
signal count_ang	 : std_logic_vector (11 downto 0) := (others => '0');

begin

process (clk)

begin

if (rising_edge(clk)) then
	if (reset = '1') then
	case(state) is
		when to_unsigned(first,2) => if (count_ang >= 3999) then		--00
						state <= to_unsigned(second,2);
						count_ang <= "000000010000";
						quarter_in <= "01";
						Ang <= Ang - 16;
					else 
						state <= to_unsigned(first,2);
						quarter_in <= "00";
						Ang <= Ang + 16;
						count_ang <= count_ang + 16;
					end if;
		when to_unsigned(second,2) => if (count_ang >= 3999) then		--01
						state <= to_unsigned(third,2);
						count_ang <= "000000010000";
						quarter_in <= "10";
						Ang <= Ang + 16;
					else
						state <= to_unsigned(second,2);
						quarter_in <= "01";
						Ang <= Ang - 16;
						count_ang <= count_ang + 16;
						end if;
		when to_unsigned(third,2) => if (count_ang >= 3999) then
						state <= to_unsigned(fourth,2);
						count_ang <= "000000010000";
						quarter_in <= "11";
						Ang <= Ang - 16;
					else
						state <= to_unsigned(third,2);
						quarter_in <= "10";
						Ang <= Ang + 16;
						count_ang <= count_ang + 16;
						end if;
		when to_unsigned(fourth,2) => if (count_ang >= 3999) then
						state <= to_unsigned(first,2);
						count_ang <= "000000010000";
						quarter_in <= "00";
						Ang <= Ang + 16;
					else
						state <= to_unsigned(fourth,2);
						quarter_in <= "11";
						Ang <= Ang - 16;
						count_ang <= count_ang + 16;
						end if;
		when others => count_ang <= (others => '0');
	end case;
end if;
end if;
end process;
Angle <= Ang;
end Behavioral;

 

entity delay is
port (
		clk 	: in std_logic;
		reset : in std_logic;
		quarter_do : out std_logic_vector(1 downto 0));

end delay;

architecture Behavioral of delay is
signal delay_1 : std_logic_vector(1 downto 0);
signal delay_2 : std_logic_vector(1 downto 0);
signal delay_3 : std_logic_vector(1 downto 0);
signal delay_4 : std_logic_vector(1 downto 0);
signal delay_5 : std_logic_vector(1 downto 0);
signal delay_6 : std_logic_vector(1 downto 0);
signal delay_7 : std_logic_vector(1 downto 0);
signal delay_8 : std_logic_vector(1 downto 0);
signal delay_9 : std_logic_vector(1 downto 0);
signal delay_10 : std_logic_vector(1 downto 0);
signal delay_11 : std_logic_vector(1 downto 0);
signal delay_12 : std_logic_vector(1 downto 0);
signal delay_13 : std_logic_vector(1 downto 0);
signal delay_14 : std_logic_vector(1 downto 0);
signal delay_15 : std_logic_vector(1 downto 0);
signal delay_16 : std_logic_vector(1 downto 0);
signal delay_17 : std_logic_vector(1 downto 0);
signal delay_18 : std_logic_vector(1 downto 0);
signal delay_19 : std_logic_vector(1 downto 0);

component rotation 
generic (
			first  : integer := 0;							
			second : integer := 1;
			third  : integer := 2;
			fourth : integer := 3);
  Port ( 
			clk 			: in std_logic;			
			reset 		: in std_logic;
		Angle 		: out std_logic_vector (12 downto 0);			
		quarter_in  : out std_logic_vector (1 downto 0));
end component;

begin

rotation_XYN : rotation
port map (
  clk => clk,
reset => reset,
quarter_in => delay_1
);

process(clk)
begin
if rising_edge(clk) then
	delay_2 <= delay_1;
	delay_3 <= delay_2;
	delay_4 <= delay_3;
	delay_5 <= delay_4;
	delay_6 <= delay_5;
	delay_7 <= delay_6;
	delay_8 <= delay_7;
	delay_9 <= delay_8;
	delay_10 <= delay_9;
	delay_11 <= delay_10;
	delay_12 <= delay_11;
	delay_13 <= delay_12;
	delay_14 <= delay_13;
	delay_15 <= delay_14;
	delay_16 <= delay_15;
	delay_17 <= delay_16;
	delay_18 <= delay_17;
	delay_19 <= delay_18;
	quarter_do <= delay_19;
end if;
end process;

end Behavioral;

 

entity right is
port ( 
		clk 		: in std_logic;
		reset 	: in std_logic;
		x 			: in std_logic_vector(16 downto 0);
		y 			: in std_logic_vector(16 downto 0);	
		quarter  : in std_logic_vector (1 downto 0);
		xo 		: out std_logic_vector(16 downto 0);
		yo 		: out std_logic_vector(16 downto 0));
end right;

architecture Behavioral of right is

signal xq1 : std_logic_vector(16 downto 0);
signal xq2 : std_logic_vector(16 downto 0);
signal yq1 : std_logic_vector(16 downto 0);
signal yq2 : std_logic_vector(16 downto 0);

signal xr : std_logic_vector(16 downto 0);
signal yr : std_logic_vector(16 downto 0);

begin

xq1 <= x + 0;
yq1 <= y + 0;
xq2 <= 0 - x;
yq2 <= 0 - y;


process(clk)

begin
if (rising_edge(clk)) then
	if (reset = '1') then
		case (quarter) is
			when "00" =>
				yr <= yq1;
				xr <= xq1;
			when "01" =>
				yr <= yq1;
				xr <= xq2;
			when "10" =>
				yr <= yq2;
				xr <= xq2;
			when "11" =>
				yr <= yq2;
				xr <= xq1;
			when others =>
				xr <= (others => '0');
				yr <= (others => '0');
			end case;	
	else
		xr <= (others => '0');
		yr <= (others => '0');
	end if;
end if;
end process;
xo <= xr;
yo <= yr;
end Behavioral;

Ну и результат

8_ZEd_WFs_SVSg.jpg

 

Изменено пользователем Boobrilla

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А вот у Вас в модуле Toplvl есть порты, которые объявляются без указания направления. Это так задумано, или ошибка, или ISE позволяет такие вольности с языком ?

entity Toplvl is

    port ( 
            clk         : std_logic;
            reset     : std_logic;
            sinus1     : out std_logic_vector(16 downto 0));
end Toplvl;

 

Из советов по оптимизации я бы модуль delay - описал так(только параметры WIDTH и LENGTH указал):

Это по сути многоразрядный сдвиговый регистр.

Ваш подход "в лоб" уж больно некрасиво смотрится.

А если надо длину задержки поменять ?

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;

ENTITY SHIFT_RAM IS
    GENERIC
    (
        WIDTH      : INTEGER := 24;
        LENGTH     : INTEGER := 6
    );
    PORT
    (
       CLK          : IN   STD_LOGIC;
       DATA_IN      : IN   STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
       DATA_OUT     : OUT  STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0)
    );
END ENTITY;

ARCHITECTURE RTL OF SHIFT_RAM IS
    TYPE      REG_RAM IS ARRAY (LENGTH-1 DOWNTO 0) OF STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
    SIGNAL    REG  : REG_RAM;
    ATTRIBUTE RAMSTYLE : STRING;
    ATTRIBUTE RAMSTYLE OF REG : SIGNAL IS "M9K";
BEGIN
    SHIFT_REG_PROC : PROCESS
    (
        CLK
    )
    BEGIN
        IF (RISING_EDGE(CLK)) THEN                              -- По каждому переднему фронту 
            REG <= REG(LENGTH-2 DOWNTO 0) & DATA_IN;             -- Запишем в младший разряд данные со входа и сдвинем их
        END IF;
    END PROCESS SHIFT_REG_PROC;               
    DATA_OUT <= REG(LENGTH-1);
END ARCHITECTURE;

Изменено пользователем Flip-fl0p

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

По портам не заметил) Но, видимо, ISE позволяет) (оба in).

По поводу подхода "в лоб" - я слишком еще не опытен. Лучше сделать так, как точно будет работать) Ну а если нужно будет изменить длину задержки, то просто добавлять/удалять кол-во переменных действий) В моем случае задержка была 190 ns = 19 по 10 ns.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
По портам не заметил) Но, видимо, ISE позволяет) (оба in).

По поводу подхода "в лоб" - я слишком еще не опытен. Лучше сделать так, как точно будет работать) Ну а если нужно будет изменить длину задержки, то просто добавлять/удалять кол-во переменных действий) В моем случае задержка была 190 ns = 19 по 10 ns.

А если задержка 1000 ns ? Тогда 100 по 10 ? :wacko:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну выходит что так) Но я бы просто тогда наверно вермя такта менял, если бы этого позволяло задание

Изменено пользователем Boobrilla

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Ну выходит что так) Но я бы просто тогда наверно вермя такта менял, если бы этого позволяло задание

где тестбенч для симуляции?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
где тестбенч для симуляции?

Тестбенч не кидал, ибо он стандартно "пустой", ничего не добавлял. Кроме наверное ресета = 1 .

ENTITY Final IS
END Final;

ARCHITECTURE behavior OF Final IS 

   COMPONENT Toplvl
   PORT(
        clk : IN  std_logic;
        reset : IN  std_logic;
        sinus1 : OUT  std_logic_vector(16 downto 0)
       );
   END COMPONENT;


  --Inputs
  signal clk : std_logic := '0';
  signal reset : std_logic := '0';

	--Outputs
  signal sinus1 : std_logic_vector(16 downto 0);

  -- Clock period definitions
  constant clk_period : time := 10 ns;

BEGIN

-- Instantiate the Unit Under Test (UUT)
  uut: Toplvl PORT MAP (
         clk => clk,
         reset => reset,
         sinus1 => sinus1
       );

  -- Clock process definitions
  clk_process :process
  begin
	clk <= '0';
	wait for clk_period/2;
	clk <= '1';
	wait for clk_period/2;
  end process;

  -- Stimulus process
  stim_proc: process
  begin		
     -- hold reset state for 100 ns.
     wait for 100 ns;	

     wait for clk_period*10;
	reset <= '1';
     -- insert stimulus here 

     wait;
  end process;
END;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Ну и результат

8_ZEd_WFs_SVSg.jpg

Какой SFDR у вас в итоге получился? Сколько ресурсов при этом было сожрано? По сравнению с классической DDS (четверть периода в RAM block плюс логика управления) какие преимущества у вашего решения?

Ну и более глобальный вопрос ( на вырост ) : с какой целью все эти усилия по изобретению очередного велосипеда?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Ну и более глобальный вопрос ( на вырост ) : с какой целью все эти усилия по изобретению очередного велосипеда?

 

Сейчас отобьете у человека желание заниматься проектированием ПЛИС. :)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Сейчас отобьете у человека желание заниматься проектированием ПЛИС. :)

То что человек выложил готовый модуль - это хорошо, честь ему и хвала за старание и плюсик в карму.

То что модуль задокументирован чуть больше чем никак - это плохо. Ибо отсутствие какой-либо документации кода (хотя бы комментариев) сводит на нет всю пользу модуля.

Проще с нуля написать, чем разобраться в этом коде. Тем более, по моему скромному мнению, многие куски кода написаны уж больно "некрасиво".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
Авторизация