Jump to content

    
Sign in to follow this  
mcaffee

помогите разобраться с кодом

Recommended Posts

Всем доброго времени суток!

Среди поисков алгоритмов dds нашел вот такой код.

Из этого кода все, что я понял, так это то, что 40 рязрядный сумматор разбит на десять 4-х разрядных сумматоров. Не могли бы Вы описать более подробную картину, что здесь происходит?)

 

long_code_here = 
library ieee;
USE IEEE.std_logic_1164.all;
USE IEEE.std_logic_arith.all;
entity Accumulator is
port (
clk : in std_logic;	
rst : in std_logic; 
wr : in std_logic;		
D : in std_logic_vector (39 downto 0);	
S : out std_logic_vector (39 downto 0)	
);
end Accumulator;
architecture rtl of Accumulator is
component Adder_4bit is
port (
clk : in std_logic;	
rst : in std_logic; 
A : in std_logic_vector (3 downto 0);		
             B : in std_logic_vector (3 downto 0);	
cin : in std_logic;							
S : out std_logic_vector (3 downto 0);	
cout : out std_logic					
);
end component;
component my_reg is 
generic (
size : integer range 1 to 255:=1;	
W : integer range 1 to 32:=4		
);
port (
clk : in std_logic;		
             rst : in std_logic; 
wr : in std_logic;		
D : in std_logic_vector (W-1 downto 0);
Q : out std_logic_vector (W-1 downto 0)
); 
end component;
type result_type is array(9 downto 0) of std_logic_vector(3 downto 0);
signal res0, res1, res, input : result_type:=(others=>(others=>'0')); 
signal carry_chain0, carry_chain1, carry_chain : std_logic_vector (9 downto 0):=(others=>'0'); 
begin
inputs : for i in 1 to 10 generate
		reg_chain : my_reg
		generic map (i, 4) 
		port map (clk, rst, D(4*i-1 downto 4*(i-1)), input(i-1));
	 end generate;

first_adder :	Adder_4bit
port map (clk, rst, input(0), res(0), '0', res(0), carry_chain(0));		
adders : for i in 1 to 9 generate				
carry : 	              Adder_4bit
                           port map (clk, rst, input(i), res(i), '1', res1(i), carry_chain1(i));	
no_carry :	Adder_4bit
	port map (clk, rst, input(i), res(i), '0', res0(i), carry_chain0(i));
	 end generate;	
sum_mux :	for i in 1 to 9 generate
			res(i)<=
			res0(i) when carry_chain(i-1)='0' else
			res1(i);
			carry_chain(i)<=
			carry_chain0(i) when carry_chain(i-1)='0' else
			carry_chain1(i);
end generate;	
output_assign :	for i in 1 to 10 generate
				S(4*i-1 downto 4*(i-1))<=res(i-1);
			end generate;
end rtl;

 

Далее идет описание компонента Adder_4bit

long_code_here = 
library ieee;
USE IEEE.std_logic_1164.all;
USE IEEE.std_logic_unsigned.all;
USE IEEE.std_logic_arith.all;

entity Adder_4bit is
port (
clk : in std_logic;		
           rst : in std_logic;	
A : in std_logic_vector (3 downto 0);	
B : in std_logic_vector (3 downto 0);		
cin : in std_logic;							
S : out std_logic_vector (3 downto 0);	
cout : out std_logic					
);
end Adder_4bit;

architecture rtl of Adder_4bit is
signal sum : std_logic_vector (4 downto 0);
signal op1, op2 : std_logic_vector (3 downto 0);
begin
process (rst,clk)
begin
	if (rst='1') then
		sum<=(others=>'0');
	elsif (clk'event and clk='1') then
			sum <= ('0' & A)+('0' &  B )+cin;		
	end if;
end process;
S <= sum(3 downto 0);
cout <= sum(4);
end rtl;

 

И компонента my_reg

long_code_here = 
library ieee;
USE IEEE.std_logic_1164.all;
USE IEEE.std_logic_unsigned.all;

entity my_reg is 
generic (
size : integer range 1 to 255:=1;	
W : integer range 1 to 32:=4		
);
port (
-- Системный интерфейс
clk : in std_logic;	
rst : in std_logic;	
            wr : in std_logic;		
D : in std_logic_vector (W-1 downto 0);
Q : out std_logic_vector (W-1 downto 0)
); 
end my_reg;

architecture rtl of my_reg is
type reg_chain_type is array (size-1 downto 0) of std_logic_vector (W-1 downto 0);
signal reg_chain : reg_chain_type;
signal ena_chain : std_logic_vector (size-1 downto 0);
begin
process (clk, rst)	
begin
	if (rst='1') then
		ena_chain<=(others=>'0');
	elsif (clk'event and clk='1') then
			ena_chain(0)<='1';
		if (size>1) then 
			for i in 1 to size-1 loop
				ena_chain(i)<=ena_chain(i-1);
			end loop;
		end if;
	end if;
end process;

process (rst, clk)	
begin
	if (rst='1') then
		reg_chain<=(others=>(others=>'0'));
	elsif (clk'event and clk='1') then
		if (ena_chain(0)='1') then
			reg_chain(0)<=D;
		end if;
		if (size>1) then 
			for i in 1 to size-1 loop
				if (ena_chain(i)='1') then
					reg_chain(i)<=reg_chain(i-1);
				end if;
			end loop;
		end if;
	end if;
end process;
Q<=reg_chain(size-1);
end rtl;

 

Здесь, в таких тонкостях, еще хуже. … не понятно, как это функционирует все вместе…

Подскажите, поделитесь своими мыслями!)

Хочу разобраться для начала с этим, поскольку дальше еще используется перекодировка с таблицей синусов.

Заранее большое спасибо всем откликнувшимся!)

 

 

Share this post


Link to post
Share on other sites

Предлагаю для начала ознакомиться с готовыми реализациями: xilinx dds compiler, начиная со стр. 11 там дана теория вопроса. Может, тогда станет понятнее, откуда взялся такой код.

Share this post


Link to post
Share on other sites

Сумматор разбит на 10 маленьких для организации конвеера, чтобы повысить скорость работы. К алгоритму это все отношения не имеет. Поначалу можно заменить простым аккумулятором, а если не будет хватать скорости, уже думать об оптимизации.

 

А если надо разобраться именно с этим кодом, лучше его просимулировать.

 

Share this post


Link to post
Share on other sites

В продолжении обсуждения вопроса про dds. С выхода накопительного сумматора берем 10 старших разрядов и с помощью таблицы синусов вычисляем значения амплитуды. Есть вот такой код:


library ieee;
USE IEEE.std_logic_1164.all;
USE IEEE.std_logic_unsigned.all;

entity Sin_func is
port(
clk : in std_logic;
rst : in std_logic; 
Din : in std_logic_vector(9 downto 0);	-- входные данные. это 10 страших разрядов с выхода накопительного сумматора.
Sout : out std_logic_vector (11 downto 0)	-- выходные данные. Значения идут на цап. (амплитуда синуса)
);
end Sin_func;

architecture rtl of Sin_func is
type sin_type is array(31 downto 0) of std_logic_vector(11 downto 0);
signal Reg : sin_type;
signal In_reg : std_logic_vector (9 downto 0);
begin
table0: process(clk, rst)
begin
if (rst='1') then
	Reg(0) <= (others=>'0');
elsif(clk'event and clk='1') then
	case Din(4 downto 0) is
		when "00000" => Reg(0) <= "011111111111";
		when "00001" => Reg(0) <= "100000001011";
		when "00010" => Reg(0) <= "100000011000";
		when "00011" => Reg(0) <= "100000100100";
		when "00100" => Reg(0) <= "100000110001";
		when "00101" => Reg(0) <= "100000111101";
		when "00110" => Reg(0) <= "100001001010";
		when "00111" => Reg(0) <= "100001010110";
		when "01000" => Reg(0) <= "100001100011";
		when "01001" => Reg(0) <= "100001110000";
		when "01010" => Reg(0) <= "100001111100";
		when "01011" => Reg(0) <= "100010001001";
		when "01100" => Reg(0) <= "100010010101";
		when "01101" => Reg(0) <= "100010100010";
		when "01110" => Reg(0) <= "100010101110";
		when "01111" => Reg(0) <= "100010111011";
		when "10000" => Reg(0) <= "100011000111";
		when "10001" => Reg(0) <= "100011010100";
		when "10010" => Reg(0) <= "100011100000";
		when "10011" => Reg(0) <= "100011101101";
		when "10100" => Reg(0) <= "100011111001";
		when "10101" => Reg(0) <= "100100000110";
		when "10110" => Reg(0) <= "100100010010";
		when "10111" => Reg(0) <= "100100011111";
		when "11000" => Reg(0) <= "100100101011";
		when "11001" => Reg(0) <= "100100111000";
		when "11010" => Reg(0) <= "100101000100";
		when "11011" => Reg(0) <= "100101010000";
		when "11100" => Reg(0) <= "100101011101";
		when "11101" => Reg(0) <= "100101101001";
		when "11110" => Reg(0) <= "100101110110";
		when "11111" => Reg(0) <= "100110000010";
		when others => Reg(0) <= "000000000000";
	end case;
end if;
end process;
table1: process(clk, rst)
begin
if (rst='1') then
	Reg(1) <= (others=>'0');
elsif(clk'event and clk='1') then
	case Din(4 downto 0) is
		when "00000" => Reg(1) <= "100110001110";
		when "00001" => Reg(1) <= "100110011011";
		when "00010" => Reg(1) <= "100110100111";
и так далее... всего 32 таких таблицы.

process(clk, rst)
begin
if (rst='1') then
	In_reg <= (others=>'0');
elsif (clk'event and clk='1')then
	In_reg <= Din;
end if;
end process;
Sout <= Reg (conv_integer(In_reg(9 downto 5)));
end architecture rtl;

 

Как видно, здесь значения аргумента принимают значения от 0 до 31. каждому значению фазы ставится в соответствие значение амплитуды синуса. Din это 10 старших разрядов с выхода сумматора. Непонятно почему берется только 5 младших разрядов от Din и им ставится в соответсвие значение амплитуды. и непонятно, что значит предпоследняя строчка, где задействованы 5 старших разрядов от входных данных..

Sout <= Reg (conv_integer(In_reg(9 downto 5)));

Подскажите, пожалуйста, поделитесь мыслями.

Заранее большое спасибо!!

Share this post


Link to post
Share on other sites

Вобщем, здесь тоже разбито на 2 стадии. Вся таблица содержит 1024 ячейки, она логически разбита на 32 подтаблицы по 32 ячейки. Значение из подтаблицы выбирается на первом такте. А сама подтаблица выбирается на 2м такте. Разбивка на 5 битов адресации очень удобна: дело в том, что в Xilinx LUTы могут иметь 2 выхода и 5 входов, если входы одинаковые (что и есть в нашем случае). Таким образом хорошо экономятся ресурсы.

Ну вкратце так.

Если что неясно описал - спрашивайте, какое конкретно место непонятно в объяснениях.

Share this post


Link to post
Share on other sites
Вобщем, здесь тоже разбито на 2 стадии. Вся таблица содержит 1024 ячейки, она логически разбита на 32 подтаблицы по 32 ячейки. Значение из подтаблицы выбирается на первом такте. А сама подтаблица выбирается на 2м такте. Разбивка на 5 битов адресации очень удобна: дело в том, что в Xilinx LUTы могут иметь 2 выхода и 5 входов, если входы одинаковые (что и есть в нашем случае). Таким образом хорошо экономятся ресурсы.

Ну вкратце так.

Если что неясно описал - спрашивайте, какое конкретно место непонятно в объяснениях.

Да))) теперь стало понятно! Большое спасибо!!

Но есть еще вопрос..

А если нужно взять не 10, а 12 старших разрядов, то тогда у нас уже будет 4096 ячеек во всей таблице и 64 подтаблицы с 64 ячейками, так?)

Но тут скорее всего не хватит ресурсов под такую таблицу( задумался над укорачиванием таблицы. Сделал расчет для четверти периода. Тогда получится 16 подтаблиц с 64 ячейками. Так?) получается во всей таблице записано 1024 значения, от нуля до макс. Но как сделать так, чтобы и на оставшиеся 3/4 периода была адресация и высчитывались значения, и чтобы в итоге получился целый синус?

Большое спасибо!)

Share this post


Link to post
Share on other sites

Самый старший (12-й) бит будет отвечать за знак, а 11-й за инвертирование фазы. Получается 11-й бит будет использоваться до регистров Reg, поэтому, наверное, лучше 32 таблицы на 32 значения. Таблицу нужно будет пересчитать (наверное, просто сдвинуть вниз и отбросить старший бит).

Будет что-то вроде:

 

.....

signal Din_1 : std_logic_vector (9 downto 0);

.....

Din_1 <= Din(9 downto 0) when (Din(10) = '0') else "1111111111" - Din(9 downto 0);

table0: process(clk, rst)
begin
    if (rst='1') then
        Reg(0) <= (others=>'0');
    elsif(clk'event and clk='1') then
        case Din_1(4 downto 0) is
            when "00000" => Reg(0) <= "000000000000";
            when "00001" => Reg(0) <= "000000001010";
.....

process(clk, rst)
begin
    if (rst='1') then
        In_reg <= (others=>'0');
    elsif (clk'event and clk='1')then
        In_reg(11 downto 10) <= Din;
        In_reg(9 downto 0) <= Din_1;
    end if;
end process;
    Sout <= "111111111111" + Reg (conv_integer(In_reg(9 downto 5))) when (In_reg(11) = '0'); else "111111111111" - Reg (conv_integer(In_reg(9 downto 5)));

Надеюсь, нигде не ошибся.

Edited by Artemius_tv

Share this post


Link to post
Share on other sites
Самый старший (12-й) бит будет отвечать за знак, а 11-й за инвертирование фазы. Получается 11-й бит будет использоваться до регистров Reg, поэтому, наверное, лучше 32 таблицы на 32 значения. Таблицу нужно будет пересчитать (наверное, просто сдвинуть вниз и отбросить старший бит).

Будет что-то вроде:

 

.....

signal Din_1 : std_logic_vector (9 downto 0);

.....

Din_1 <= Din(9 downto 0) when (Din(10) = '0') else "1111111111" - Din(9 downto 0);

table0: process(clk, rst)
begin
    if (rst='1') then
        Reg(0) <= (others=>'0');
    elsif(clk'event and clk='1') then
        case Din_1(4 downto 0) is
            when "00000" => Reg(0) <= "000000000000";
            when "00001" => Reg(0) <= "000000001010";
.....

process(clk, rst)
begin
    if (rst='1') then
        In_reg <= (others=>'0');
    elsif (clk'event and clk='1')then
        In_reg(11 downto 10) <= Din;
        In_reg(9 downto 0) <= Din_1;
    end if;
end process;
    Sout <= "111111111111" + Reg (conv_integer(In_reg(9 downto 5))) when (In_reg(11) = '0'); else "111111111111" - Reg (conv_integer(In_reg(9 downto 5)));

Надеюсь, нигде не ошибся.

 

Большое Вам спасибо!!

Подскажите, а вот тут все правильно?

In_reg(11 downto 10) <= Din;

In_reg(9 downto 0) <= Din_1;

 

Din же (11 downto 0). Наверное и In_reg тоже должен быть (11 downto 0). Или именно 11 downto 10?? И зачем мы в In_reg 2 раза перезаписываем тогда?

 

А если будет так, что в этой записи Sout <= "111111111111" + Reg (conv_integer(In_reg(9 downto 5))), у Reg (conv_integer(In_reg(9 downto 5)) будут одни нули, то тогда на все разряды цапа будут поданы "1". получается, что это -1, но как это воспримет цап? в десятичной системе амплитуда синуса принимает значения от -1 до 511 и дальше вниз до 0, до -511 и снова до 0. Как такие числа воспримет цап? Подскажите, запутался совсем...

Edited by mcaffee

Share this post


Link to post
Share on other sites

А какой ЦАП? Надо на него доку читануть, из неё станет понятно.

 

А если нужно взять не 10, а 12 старших разрядов, то тогда у нас уже будет 4096 ячеек во всей таблице и 64 подтаблицы с 64 ячейками, так?)
Чото теперь уже я не понял: у Вас весь синус 12 битов аргумент имеет? Тогда таблица на 10 битов аргумента так и остаётся. Это четверть периода. А старшие 2 бита, как написали, указывают, как эту четверть развернуть, чтобы получить результат в нужном квадранте.

 

Share this post


Link to post
Share on other sites
А какой ЦАП? Надо на него доку читануть, из неё станет понятно.

 

Чото теперь уже я не понял: у Вас весь синус 12 битов аргумент имеет? Тогда таблица на 10 битов аргумента так и остаётся. Это четверть периода. А старшие 2 бита, как написали, указывают, как эту четверть развернуть, чтобы получить результат в нужном квадранте.

ЦАП планируется применять вот такой: 1273 па4т ( он вообще 14 разрядный)

Да, согласен, в таблице у аргумента будет 10 разрядов и амплитуда там принимает значения от 0 до 1023. Всего 1024 значения и 32 на 32. Но вот как правильно описать как эти четверти развернуть, чтобы все правильно получилось?)

 

Share this post


Link to post
Share on other sites
Подскажите, а вот тут все правильно?

Нет, конечно же я наошибался.

 

Надо

In_reg(11 downto 10) <= Din(11 downto 10);
In_reg(9 downto 0) <= Din_1;

На следующий такт передаем старшие 2 бита в неизменном виде, а младшие 10 бит уже перевернутые или нет в соответствии с Din(10). Хотя Reg(4 downto 0) и Reg(10) все равно не используются.

 

И с

Sout <= "111111111111" + Reg (conv_integer(In_reg(9 downto 5))) when (In_reg(11) = '0'); else "111111111111" - Reg (conv_integer(In_reg(9 downto 5)));

тоже ошибся, надо "011111111111" или "100000000000"

 

Кстати, насколько я помню, количество используемых разрядов фазы должно быть больше разрядности ЦАП. В AD9834 ЦАП 10-битный и используют 12 бит фазы, AD9854 ЦАП 12-бит и 14 бит фазы. Т.е. для 14-разрядного ЦАП'а 12 бит фазы это мало.

Edited by Artemius_tv

Share this post


Link to post
Share on other sites
Кстати, насколько я помню, количество используемых разрядов фазы должно быть больше разрядности ЦАП.

 

Это для лучшей характеристики по сигнал/шум ДДС, там дополнительные разряды добавляются и четность фазы ломается и другие хитрости делаются, это уже следующий этап для ТС. Это все до таблицы должно быть, битность таблицы должна быть как у ЦАПа со всеми расширениями, потому что иначе это хранение лишней информации.

Share this post


Link to post
Share on other sites
А если будет так, что в этой записи Sout <= "111111111111" + Reg (conv_integer(In_reg(9 downto 5))), у Reg (conv_integer(In_reg(9 downto 5)) будут одни нули, то тогда на все разряды цапа будут поданы "1". получается, что это -1, но как это воспримет цап? в десятичной системе амплитуда синуса принимает значения от -1 до 511 и дальше вниз до 0, до -511 и снова до 0. Как такие числа воспримет цап? Подскажите, запутался совсем...

 

ЦАП планируется применять вот такой: 1273 па4т ( он вообще 14 разрядный)

 

Доку то на цап читали? Там поди есть ответы )))

 

 

Но вот как правильно описать как эти четверти развернуть, чтобы все правильно получилось?)
Вы нарисуйте период синуса на бумажке. Увидите там 4 повторяющиеся части )))

Но правильнее увидеть сначала 2 крупные повторяющиеся части (полупериоды), а в каждой из частей ещё 2 мелкие повторяющиеся части (четверти).

Закономерности:

1. Полупериоды просто имеют противоположный знак. За полупериоды отвечает старший бит аргумента (поскольку это самые крупные повторяющиеся части).

2. Четвертинки имеют обратную зависимость от аргумента: т.е. если аргумент таблицы в первой четвертинке меняется от 0 до 1023, то во второй четвертинке он должен меняться от 1023 до 0. За четвертинки отвечает следующий от старшего бит аргумента.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this