|
|
  |
Реализация БПФ на ПЛИС, Тудности, встречаемые при реализации |
|
|
|
Apr 7 2009, 14:03
|
Местный
  
Группа: Свой
Сообщений: 264
Регистрация: 17-04-07
Из: Москва
Пользователь №: 27 102

|
Цитата Во-первых, подправьте код умножителей под диапазон коэффициентов -1024 ... +1024, поскольку после умножения делить нам надо теперь на 1024. Поправил, прилагается; Цитата о-вторых, теперь, когда мы разобрались с умножением, нужен ли нам 0-ой умножитель в блоке умножителей? Думаю нет, зачем нам постоянно умножать на 1? Цитата В-третьих, в начале было решено, что вычисление бабочки и умножение на коэф. делаем за один такт. В таком случае, регистры на выходе бабочки нужно перенести на выход умножителей. Вот тут я не совсем понял, получается мне код для умножителей нужно впихнуть в код для бабочки? Код бабочки прилагаю: http://webfile.ru/3392071Цитата В-четвертых, все блоки нашего БПФ имеют на входе и выходе один и тот же набор сигналов (относящийся к данным БПФ) и эти сигналы представляют собой комплексные числа. Я предлагаю воспользоваться такой возможностью языка как record и задать тип complex_data и complex_coef для данных и коэффициентов. Еще задать тип complex_data_vector и complex_coef_vector с параметризованной размерностью, чтобы не "таскать" везде по четыре сигнала данных и по три сигнала с коэффициентами. Все это, для удобства, объявить в package - скажем fft_pkg. Все сказанное в это пункте никак не влияет на работоспособность, поэтому если не хотите, то можете этого не делать. Сделаю позже, пока нужно с 3 пунктом разобраться. Цитата Вы с ModelSim работали? Работал немного.
|
|
|
|
|
Apr 7 2009, 22:10
|
Местный
  
Группа: Свой
Сообщений: 429
Регистрация: 11-08-05
Из: Санкт-Петербург
Пользователь №: 7 537

|
Цитата(ZED @ Apr 7 2009, 18:03)  Вот тут я не совсем понял, получается мне код для умножителей нужно впихнуть в код для бабочки? С чего Вы это взяли? Никто никого не обязывает ставить регистры на выходе блока. Чисто комбинаторный блок это вполне нормально. Я имел ввиду, что бабочка у нас не будет содержать регистров - будет чисто комбинаторной, а умножители будут иметь регистры на выходе. Впрочем, если хотите, то можете поставить регистры на выходе и бабочки и умножителей - это увеличит pipeline на 1 и практически никак не повлияет на скорость вычисления самого БПФ (ну будет БПФ вычисляться на 6 тактов дольше, ну и что...) Кстати, о бабочке. Пока Вы не убрали из нее регистры, объясните мне пожалуйста, почему бабочка тратит на вычисления аж 2 такта вместо 1? Зачем Вы сделали двойное защелкивание? Бабочка (в отличие, например, от умножителей, особенно если их синтезировать на обычных ячейках, а не на DSP-блоках) выполняет настолько простые операции, что защелкивать промежуточный результат абсолютно бессмысленно - лишняя трата регистров  .
|
|
|
|
|
Apr 8 2009, 16:12
|
Местный
  
Группа: Свой
Сообщений: 264
Регистрация: 17-04-07
Из: Москва
Пользователь №: 27 102

|
Цитата Чисто комбинаторный блок это вполне нормально. Я имел ввиду, что бабочка у нас не будет содержать регистров - будет чисто комбинаторной, а умножители будут иметь регистры на выходе. Да, но бабочка содержит процесс, а это уже регистр. процесс убрать нельзя, т.к. конструкция if последовательная, а значит может содержаться только в процессе. Тут вижу выход только описывать эти 2 бабочки как компоненты, а затем применять конструкцию if generate. Ну можно в процесс засунуть тупо все сигналы, чтобы он запускался при изменении каждого из них. Цитата Кстати, о бабочке. Пока Вы не убрали из нее регистры, объясните мне пожалуйста, почему бабочка тратит на вычисления аж 2 такта вместо 1? Зачем Вы сделали двойное защелкивание? Я его не хотел делать, так вышло=)) Но тем не менее Quartus ставит промежуточный регистр. Это происходит как раз из-за различных назначений сигналам yi_re_sig/yi_im_sig, i=0,1,2,3 при конструкции if else/
|
|
|
|
|
Apr 9 2009, 09:20
|
Местный
  
Группа: Свой
Сообщений: 429
Регистрация: 11-08-05
Из: Санкт-Петербург
Пользователь №: 7 537

|
Цитата(ZED @ Apr 8 2009, 20:12)  Да, но бабочка содержит процесс, а это уже регистр. Цитата(ZED @ Apr 9 2009, 07:50)  На счет if generate я погорячился, даже сказал бы тупанул, можно просто каждый сигнал yi_re_sig/yi_im_sig, i=0,1,2,3 посадить на case/ Таким образом уберется процесс и сгенеряться мультиплексоры. бабочка станет чисто комбинационной. Вечером попробую... Спокойствие... только спокойствие. process никогда и ни при каких обстоятельствах не является признаком регистра. Покажите мне того человека, который сказал Вам, что "process - это регистр" ? Синтезатор "детектирует" наличие регистра по конструкциям вида CLK'event and CLK = '1', rising_edge(clk) и т.д. Если Вы напишите такой, например, код CODE process(SEL,B,C,D,E) begin if SEL = '0' then A <= B or C; else A <= C and D; end if; end process то получите обычную комбинаторную логику - никаких регистров синтезатор и не подумает поставить. Причем, если вместо process(SEL,B,C,D,E) Вы напишите process(SEL,B,C), то синтезатор все сделает правильно, но вот симулятор просимулирует неправильно. Если вне всякого процесса Вы напишите CODE A <= B when rising_edge(CLK) else A; то получите регистр и без использования process.
|
|
|
|
|
Apr 9 2009, 15:06
|
Местный
  
Группа: Свой
Сообщений: 264
Регистрация: 17-04-07
Из: Москва
Пользователь №: 27 102

|
Цитата process никогда и ни при каких обстоятельствах не является признаком регистра. Я знаю. Я в принципе так и указал: Цитата Ну можно в процесс засунуть тупо все сигналы, чтобы он запускался при изменении каждого из них. Просто сигналов уж больно много. Вот проект: http://webfile.ru/3398933
Сообщение отредактировал ZED - Apr 9 2009, 15:44
|
|
|
|
|
Apr 12 2009, 02:20
|
Местный
  
Группа: Свой
Сообщений: 429
Регистрация: 11-08-05
Из: Санкт-Петербург
Пользователь №: 7 537

|
наконец-то выдалось немного свободного времени - посмотрел Ваш код. 1) Зачем, всетаки, приставка but к портам бабочки ? 2) Зачем в умножителе Вы ввели еще один промежуточный сигнал result_re_buf ? Чем Вам не нравится такой код  ? CODE process(CLK) begin if (rising_edge(CLK)) then result_re <= std_logic_vector(result_re_sig(b_size + w_size - 3 downto w_size - 2 )); result_im <= std_logic_vector(result_im_sig(b_size + w_size - 3 downto w_size - 2)); end if; end process; 3) Зачем Вам resize в умножителе? Если бы это был просто умножитель предназначенный для чего угодно, то требуется учесть возможность переполнения при +/-. Но тогда и выход должен уже быть не 17 разрядов, а 18. Наш умножитель он только для нашего БПФ годится, а в нашем БПФ в умножителе уже не будет переполнения при +/-. Кстати, объясните почему? 4) Зачем в бабочке регистр на y0? Очень плохая идея и стиль выравнивать задержки не там где создается "перекос". У нас регистры стоят в умножителях, 0-ой умножитель удален за ненадобностью, но раз имменно в нем был регистр, то именно вместо него в блоке умножителей и надо поставить регистр для выравнивания, а не в бабочке. Пока мы разбираемся с кодом бабочки и умножителя и вводим record (как там дела? ) давайте параллельно подумаем про память - нам скоро ей заниматься. Посмотрите, пожалуйста, на последнюю версию блок схемы. Согласно блок-схеме у нас получаются два совершенно разных блока памяти. Что нужно добавить на блок схеме, чтобы блоки памяти у нас были совершенно одинаковыми?
|
|
|
|
|
Apr 13 2009, 17:12
|
Местный
  
Группа: Свой
Сообщений: 264
Регистрация: 17-04-07
Из: Москва
Пользователь №: 27 102

|
Цитата 1) Зачем, всетаки, приставка but к портам бабочки ? Чтобы не запутаться, убрал... Цитата 2) Зачем в умножителе Вы ввели еще один промежуточный сигнал result_re_buf Опять же, чтобы не запутаться, убрал...=) Цитата 3) Зачем Вам resize в умножителе? Если бы это был просто умножитель предназначенный для чего угодно, то требуется учесть возможность переполнения при +/-. Но тогда и выход должен уже быть не 17 разрядов, а 18. Наш умножитель он только для нашего БПФ годится, а в нашем БПФ в умножителе уже не будет переполнения при +/-. Кстати, объясните почему? Resize не нужен т.к. мы расширили до 17 разрядов отчсеты и до 12 разрядов поворачивающие множители, убрал... Цитата 4) Зачем в бабочке регистр на y0? Очень плохая идея и стиль выравнивать задержки не там где создается "перекос". У нас регистры стоят в умножителях, 0-ой умножитель удален за ненадобностью, но раз имменно в нем был регистр, то именно вместо него в блоке умножителей и надо поставить регистр для выравнивания, а не в бабочке. Перенес регистр из бабочки в блок умножителей. Цитата Пока мы разбираемся с кодом бабочки и умножителя и вводим record (как там дела? ) Не было времени разобраться. Цитата Посмотрите, пожалуйста, на последнюю версию блок схемы. Согласно блок-схеме у нас получаются два совершенно разных блока памяти. Что нужно добавить на блок схеме, чтобы блоки памяти у нас были совершенно одинаковыми? Не хватает мультиплексора, исправил, прилагаю: http://webfile.ru/3409277Код полной бабочки: http://webfile.ru/3409275
|
|
|
|
|
Apr 14 2009, 13:08
|
Местный
  
Группа: Свой
Сообщений: 264
Регистрация: 17-04-07
Из: Москва
Пользователь №: 27 102

|
Никак не пойму, что нужно с записью сделать, как она должна выглядеть, вот до чего я пока додумался: Код library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all;
package fft_pkg is constant b_size: natural := 17; constant w_size: natural := 12; type complex_data is record x_re: std_logic_vector(b_size - 1 downto 0); x_im: std_logic_vector(b_size - 1 downto 0); end record; type complex_coef is record w_re: std_logic_vector(w_size - 1 downto 0); w_im: std_logic_vector(w_size - 1 downto 0); end record; type complex_data_vector is record x0: complex_data; x1: complex_data; x2: complex_data; x3: complex_data; end record; type complex_coef_vector is record w1: complex_coef; w2: complex_coef; w3: complex_coef; end record; end package fft_pkg; Акак же тогда с проектом быть придется задавать только входной сигнал x, сигнал для коэффициентов w и оперировать типа так: x.x0.x_re это будет x0_re? и с компонентами тогда как получится можно ли будет сделать так: Код entity full_butterfly is generic (b_size: natural := 17; w_size: natural := 12); port ( CLK: in std_logic; switch: in std_logic; x : in complex_data_vector;
w : in complex_coef_vector;
y0_re: out std_logic_vector(b_size - 1 downto 0); y0_im: out std_logic_vector(b_size - 1 downto 0); y1_re: out std_logic_vector(b_size - 1 downto 0); y1_im: out std_logic_vector(b_size - 1 downto 0); y2_re: out std_logic_vector(b_size - 1 downto 0); y2_im: out std_logic_vector(b_size - 1 downto 0); y3_re: out std_logic_vector(b_size - 1 downto 0); y3_im: out std_logic_vector(b_size - 1 downto 0) ); end full_butterfly;
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
component butterfly_complex is generic (b_size: natural := 17); port( CLK: in std_logic; switch: in std_logic; x: in complex_data_vector; y0_re: out std_logic_vector(b_size - 1 downto 0); y0_im: out std_logic_vector(b_size - 1 downto 0); y1_re: out std_logic_vector(b_size - 1 downto 0); y1_im: out std_logic_vector(b_size - 1 downto 0); y2_re: out std_logic_vector(b_size - 1 downto 0); y2_im: out std_logic_vector(b_size - 1 downto 0); y3_re: out std_logic_vector(b_size - 1 downto 0); y3_im: out std_logic_vector(b_size - 1 downto 0) ); end component butterfly_complex;
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
butterfly: butterfly_complex port map( CLK => CLK, switch => switch, x => x; y0_re => y0_re_connect, y0_im => y0_im_connect, y1_re => y1_re_connect, y1_im => y1_im_connect, y2_re => y2_re_connect, y2_im => y2_im_connect, y3_re => y3_re_connect, y3_im => y3_im_connect );
|
|
|
|
|
Apr 16 2009, 22:37
|
Местный
  
Группа: Свой
Сообщений: 429
Регистрация: 11-08-05
Из: Санкт-Петербург
Пользователь №: 7 537

|
Цитата(ZED @ Apr 13 2009, 21:12)  Resize не нужен т.к. мы расширили до 17 разрядов отчсеты и до 12 разрядов поворачивающие множители, убрал... К сожалению, объяснить отсутствие переполнения только лишь увеличением разрядности недостаточно. Представьте, к примеру, что x_re = 32768, x_im = 32768, w_re = 1024 и w_im = 1024. В этом случае result_im = (x_re *w_im + x_im *w_re)/1024 = 65536 - однозначно переполнение... Здесь дело в свойствах БПФ. Если все реализовано правильно, то точки, поступающие на вход БПФ всегда находятся внутри единичной окружности на комплексной плоскости. Коеффициенты - это точки лежащие на краю единичной окружности ( w_re = cos(a), w_im = sin(a) ). Так что если w_re = 1024, то w_im неизбежно будет = 0. Поворачивающими их называют не случайно - при умножении на них точка всего лишь поворачивается на угол a. Она никогда не выйдет за пределы этой единичной окружности - это и есть главная причина отсутствия переполнения. Таким образом, если все сделано правильно, то случай x_re = x_im = 32768 исключен так же как и w_re = w_im = 1024. С record Вы все сделали правильно за исключением ненужных услохнений с именами членов record. Достаточно так: CODE type complex_data is record re: std_logic_vector(b_size - 1 downto 0); im: std_logic_vector(b_size - 1 downto 0); end record; Что касается complex_data_vector / complex_coef_vector, то я имел ввиду следующее: type complex_data_vector is array (natural range <>) of complex_data; type complex_coef_vector is array (natural range <>) of complex_coef; Впрочем, (natural range <>) – это больше для тренировки в освоении языка. При таком задании типа complex_data_vector Вы размерность указываете при использовании. т.е. Вы можете написать CODE entity full_butterfly is port ( CLK : in std_logic;
switch : in std_logic;
x : in complex_data_vector(3 downto 0);
w : in complex_coef_vector(3 downto 1);
y : out complex_data_vector(3 downto 0) ); end full_butterfly; В нашем случае, я, все же, склоняюсь задать размерность жестко. Т.е. type complex_data_vector is array (3 downto 0) of complex_data; type complex_coef_vector is array (3 downto 1) of complex_coef; тогда CODE entity full_butterfly is port ( CLK : in std_logic;
switch : in std_logic;
x : in complex_data_vector;
w : in complex_coef_vector;
y : out complex_data_vector ); end full_butterfly; обратите внимание, что y, являясь выходным сигналом, тоже может быть complex_data_vector. К сожалению, в record не возможно параметризовать размерность членов (как можно параметризовать размерность самого array) - ее приходится задавать жестко или с помощью констант. Поэтому, что касается внутренних сигналов в бабочке, то ввиду необходимости сделать их на 2 разряда больше не остается ничего другого, как прямо внутри бабочки задать "служебный" тип complex_data_p2_vector: CODE architecture beh_butter of butterfly_complex is
type complex_p2 is record re : std_logic_vector(complex.re'high + 2 downto 0); im : std_logic_vector(complex.im'high + 2 downto 0); end record complex_p2;
type complex_data_p2_vector is array (complex_data_vector'range) of complex2; Выносить его в общий package нет никакого смысла т.к. нигде кроме бабочки он не будет востребован. В результате вместо замысловатого x.x0.x_re будет x(0).re, что по-моему, весьма читаемо и удобно. Про память. Т.к. память у нас не тривиальная, то нарисуйте, пожалуйста, блок-схему ее реализации, как Вы ее себе представляете. Могу сразу сказать, что т.к. мы должны вычитывать/сохранять по 4 точки за такт, то без четырех блоков памяти не обойтись, но и 4 блока это далеко не все. Чтобы понять что там еще нужно посмотрите внимательно схему вычисления БПФ.
|
|
|
|
|
Apr 19 2009, 10:28
|
Местный
  
Группа: Свой
Сообщений: 264
Регистрация: 17-04-07
Из: Москва
Пользователь №: 27 102

|
Ну, если предположить, что каждая память состоит из 4 блоков памятей, то нам нужны 4 самих этих блока + схема, которая будет преобразовывать адреса для каждого блока памяти:  Код If (addr_in_0 >= 0) and (addr_in_0 <= 511) then addr_out_0 <= addr_in_0; elsif (addr_in_0 >= 512) and (addr_in_0 <= 1023) then addr_out_0 <= addr_in_0 - 512; elsif (addr_in_0 >= 1024) and (addr_in_0 <= 1535) then addr_out_0 <= addr_in_0 - 1024; else addr_out_0 <= addr_in_0 - 1536; end if Вот что-то типа этого я думаю и так для каждого сигнала: addr_in_1, addr_in_2, addr_in_3. Т.е. получатся схемы сравнения (компараторы) и мультиплексоры...
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|