vt313 0 29 июня, 2021 Опубликовано 29 июня, 2021 · Жалоба 14 часов назад, Manvel сказал: То что я делаю, по сути из себя представляет систему из двух диф уравнений 2 порядка (приближенно можно сказать, что 2 фильтра 2-го порядка ФНЧ и ФВЧ) с нелинейной обратной связью. Далее вместо того, чтобы решать методом Рунге Кутта эти уравнения я делаю билинейное преобразования и получаю цифровое представление этой системы. В приведенной выше статье все эти шаги достаточно подробно описаны. Я не использую Альтеровсике библиотеки цифровых фильтров, потому что они относительно медленные из-за использования блоков перемножения, в данном случае, чтобы максимально ускорить систему я даже перемножения не использую, а просто суммирование со смещением максимум по первым трем битам коэффициентов цифрового фильтра. Скоро я должен буду приготовить семинар по тому что я сделал, если вам интересно, скину презентацию. То что вы предлагаете я ранее обдумывал, но у меня не вышло это никак реализовать, но я еще подумаю над этим, спасибо за совет! Я бы рекомендовал использовать DSP модули. Манипуляции с заменой умножения на суммирование, - прошлый век. Оно, скорее всего, и подрезало частоту. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Manvel 0 30 июня, 2021 Опубликовано 30 июня, 2021 · Жалоба 29.06.2021 в 01:54, yes сказал: извините за любопытство, а где, в какой организации, вы этим занимаетесь? если не секрет ИРЭ им. В.А. Котельникова РАН, вот ссылка на дореволюционный сайт, но там в принципе все есть http://cplire.ru/rus/InformChaosLab/index.htm 29.06.2021 в 09:13, vt313 сказал: Я бы рекомендовал использовать DSP модули. Манипуляции с заменой умножения на суммирование, - прошлый век. Оно, скорее всего, и подрезало частоту. Можете порекомендовать какой-нибудь DSP борду для обучения, если такие существуют? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 30 июня, 2021 Опубликовано 30 июня, 2021 · Жалоба под DSP модулями имеется ввиду - столбец выделен - жирный текст DSP модули имеются в каждой современной плис у хилых он имеет вид у интел примерно такой же Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Manvel 0 30 июня, 2021 Опубликовано 30 июня, 2021 · Жалоба 1 минуту назад, Maverick_ сказал: под DSP модулями имеется ввиду - столбец выделен - жирный текст DSP модули имеются в каждой современной плис Ну, насколько я понял, когда я использовал умножение, квартус автоматом использовал эти DSP блоки при компиляции проекта, и скорость в таком случае был ниже, чем при замене умножения на суммирование. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 30 июня, 2021 Опубликовано 30 июня, 2021 · Жалоба сделайте pipline обработку на каждом такте выполняется только независимые операции, например а = b+c; v=d*w ; r=t-n; также можете попробовать сделать операции ввида f= d+c*t если вначале вы посчитали например а = b+c; потом через несколько тактов вам понадобился результат то не забываем вставлять перезапись результата в регистры на каждом такте на эти несколько тактов Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 30 июня, 2021 Опубликовано 30 июня, 2021 · Жалоба например Вы хотите посчитать то pipeline описание будет примерно следующее library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity RGB_to_YCrCb is generic ( N : integer:= 8; num_pixel_line : integer:= 15); port( clk : in std_logic; rst : in std_logic; en : in std_logic; --RGB pixel_R : in std_logic_vector((N-1) downto 0); pixel_G : in std_logic_vector((N-1) downto 0); pixel_B : in std_logic_vector((N-1) downto 0); --YCrCb rdy : out std_logic; Y : out std_logic_vector((N) downto 0); U : out std_logic_vector((N) downto 0); V : out std_logic_vector((N) downto 0) ); end entity RGB_to_YCrCb; architecture rtl of RGB_to_YCrCb is signal reg_R : std_logic_vector((N-1) downto 0); signal reg_G : std_logic_vector((N-1) downto 0); signal reg_B : std_logic_vector((N-1) downto 0); signal res_sum_half_RB : std_logic_vector(N downto 0); signal res_sum : std_logic_vector(N downto 0); signal sum : std_logic_vector(N downto 0); signal reg_Y : std_logic_vector((N) downto 0); --signal reg_R_shift3 : std_logic_vector((N-1) downto 0); --signal reg_G_shift3 : std_logic_vector((N-1) downto 0); --signal reg_B_shift3 : std_logic_vector((N-1) downto 0); signal reg_R_shift2 : std_logic_vector((N-1) downto 0); signal reg_G_shift2 : std_logic_vector((N-1) downto 0); signal reg_B_shift2 : std_logic_vector((N-1) downto 0); signal reg_R_shift1 : std_logic_vector((N-1) downto 0); signal reg_G_shift1 : std_logic_vector((N-1) downto 0); signal reg_B_shift1 : std_logic_vector((N-1) downto 0); signal reg_R_shift : std_logic_vector((N-1) downto 0); signal reg_G_shift : std_logic_vector((N-1) downto 0); signal reg_B_shift : std_logic_vector((N-1) downto 0); signal reg_half_R : std_logic_vector((N-1) downto 0); signal reg_half_B : std_logic_vector((N-1) downto 0); signal sum_half_RB : std_logic_vector((N) downto 0); signal reg_diff_YR : std_logic_vector((N) downto 0); signal reg_diff_YB : std_logic_vector((N) downto 0); signal res_diff0 : std_logic_vector(N downto 0); signal res_diff1 : std_logic_vector(N downto 0); signal reg_Y_shift : std_logic_vector((N) downto 0); signal reg_Y_shift1 : std_logic_vector((N) downto 0); signal reg_U : std_logic_vector(N downto 0); signal reg_V : std_logic_vector(N downto 0); signal reg_sum_U : std_logic_vector(N downto 0); signal reg_sum_V : std_logic_vector(N downto 0); signal reg_shift_ena : std_logic_vector(5 downto 0); begin process (all) begin if(rst = '1') then reg_R <= (others=>'0'); reg_G <= (others=>'0'); reg_B <= (others=>'0'); reg_half_R <= (others=>'0'); reg_half_B <= (others=>'0'); elsif rising_edge(clk) then if en = '1' then reg_half_R <= std_logic_vector(unsigned(pixel_R) / 2); reg_half_B <= std_logic_vector(unsigned(pixel_B) / 2); reg_R <= pixel_R; reg_G <= pixel_G; reg_B <= pixel_B; end if; end if; end process; process (all) begin if(rst = '1') then sum_half_RB <= (others=>'0'); reg_R_shift <= (others=>'0'); reg_G_shift <= (others=>'0'); reg_B_shift <= (others=>'0'); elsif rising_edge(clk) then if en = '1' then sum_half_RB <= res_sum_half_RB; reg_R_shift <= reg_R; reg_G_shift <= reg_G; reg_B_shift <= reg_B; end if; end if; end process; res_sum_half_RB <= STD_LOGIC_VECTOR(resize(unsigned(reg_half_R), res_sum_half_RB'length) + resize(unsigned(reg_half_B), res_sum_half_RB'length)); process (all) begin if(rst = '1') then sum <= (others=>'0'); reg_R_shift1 <= (others=>'0'); reg_G_shift1 <= (others=>'0'); reg_B_shift1 <= (others=>'0'); elsif rising_edge(clk) then if en = '1' then sum <= res_sum; reg_R_shift1 <= reg_R_shift; reg_G_shift1 <= reg_G_shift; reg_B_shift1 <= reg_B_shift; end if; end if; end process; res_sum <= STD_LOGIC_VECTOR(resize(unsigned(sum_half_RB), res_sum'length) + resize(unsigned(reg_G_shift), res_sum'length)); process (all) begin if(rst = '1') then reg_Y <= (others=>'0'); reg_R_shift2 <= (others=>'0'); reg_G_shift2 <= (others=>'0'); reg_B_shift2 <= (others=>'0'); elsif rising_edge(clk) then if en = '1' then reg_Y <= std_logic_vector(unsigned(sum) / 2); reg_R_shift2 <= reg_R_shift1; reg_G_shift2 <= reg_G_shift1; reg_B_shift2 <= reg_B_shift1; end if; end if; end process; process (all) begin if(rst = '1') then reg_diff_YR <= (others=>'0'); reg_diff_YB <= (others=>'0'); reg_Y_shift <= (others=>'0'); elsif rising_edge(clk) then if en = '1' then reg_diff_YR <= res_diff0; reg_diff_YB <= res_diff1; reg_Y_shift <= reg_Y; --reg_R_shift3 <= reg_R_shift2; --reg_G_shift3 <= reg_G_shift2; --reg_B_shift3 <= reg_B_shift2; end if; end if; end process; res_diff0 <= STD_LOGIC_VECTOR(resize(unsigned(reg_Y), res_diff0'length) - resize(unsigned(reg_R_shift2), res_diff0'length)); res_diff1 <= STD_LOGIC_VECTOR(resize(unsigned(reg_Y), res_diff1'length) - resize(unsigned(reg_B_shift2), res_diff1'length)); process (all) begin if(rst = '1') then reg_U <= (others=>'0'); reg_V <= (others=>'0'); reg_Y_shift1 <= (others=>'0'); elsif rising_edge(clk) then if en = '1' then reg_U <= reg_sum_U; reg_V <= reg_sum_V; reg_Y_shift1 <= reg_Y_shift; end if; end if; end process; reg_sum_U <= STD_LOGIC_VECTOR(resize(signed(reg_diff_YR), reg_sum_U'length) + to_signed(128, reg_sum_U'length)); reg_sum_V <= STD_LOGIC_VECTOR(resize(signed(reg_diff_YB), reg_sum_V'length) + to_signed(128, reg_sum_V'length)); U <= reg_U; V <= reg_V; Y <= reg_Y_shift1; rdy <= reg_shift_ena(5); process (all) begin if(rst = '1') then reg_shift_ena <= (others=>'0'); elsif rising_edge(clk) then for i in 0 to 4 loop reg_shift_ena(i+1) <= reg_shift_ena(i); end loop; reg_shift_ena(0) <= en; end if; end process; end rtl; так же не забываем формировать сигнал разрешенния чтения результатов вычислений для следующего модуля - в моем описании последний процесс Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vt313 0 30 июня, 2021 Опубликовано 30 июня, 2021 · Жалоба 48 минут назад, Manvel сказал: Ну, насколько я понял, когда я использовал умножение, квартус автоматом использовал эти DSP блоки при компиляции проекта, и скорость в таком случае был ниже, чем при замене умножения на суммирование. Странно, они и созданы для скорости. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Manvel 0 30 июня, 2021 Опубликовано 30 июня, 2021 · Жалоба 35 минут назад, Maverick_ сказал: например Вы хотите посчитать то pipeline описание будет примерно следующее так же не забываем формировать сигнал разрешенния чтения результатов вычислений для следующего модуля - в моем описании последний процесс Спасибо за подробный ответ! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 30 июня, 2021 Опубликовано 30 июня, 2021 · Жалоба Ещё момент если у вас сумматоры большой разрядности то можно увеличить тактовую частоту за счёт конвейера из четырех битных сумматоров. С умножением сложнее но тоже нужно обращать внимание на разрядности операндов и смотреть чтобы они не превышали разрядности встроенных умножителей в плис 22 minutes ago, Manvel said: Спасибо за подробный ответ! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Manvel 0 30 июня, 2021 Опубликовано 30 июня, 2021 · Жалоба 18 минут назад, Maverick_ сказал: Ещё момент если у вас сумматоры большой разрядности то можно увеличить тактовую частоту за счёт конвейера из четырех битных сумматоров. С умножением сложнее но тоже нужно обращать внимание на разрядности операндов и смотреть чтобы они не превышали разрядности встроенных умножителей в плис О таком я читал, но пока до реализации не дошел Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
yes 7 30 июня, 2021 Опубликовано 30 июня, 2021 · Жалоба 6 hours ago, Manvel said: ИРЭ им. В.А. Котельникова РАН, вот ссылка на дореволюционный сайт, но там в принципе все есть http://cplire.ru/rus/InformChaosLab/index.htm Можете порекомендовать какой-нибудь DSP борду для обучения, если такие существуют? знаком был со старшим составом когда-то... --------------------------------- по поводу платы - практически, пользы от платы нет. все, что нужно для работы - это софт, прежде всего симулятор. как уже написали - если не работает в симуляторе, то на плате нет смысла смотреть. у альтеры (точнее уже у интела), кстати, бесплатный симулятор моделсим - лучший из бесплатных, то есть все там можно посмотреть. опять же рекомендую продолжать использовать альтеру/интел, а не переходить на ксайлинс - по скорости вряд ли будет существенный выигрыш, а сложность работы с софтом вырастет (удобство упадет) по поводу ДСП-блоков или каких-то схем улучшения операций сложения/умножения (carry-lookahead, carry-save, деревья Уоллеса, алгоритмы Бута и т.д. такого человечество придумало +100500 вариантов) можно не заморачиваться, инструмент (квартус) выберет оптимальное решение на ваш + или * в коде. это если не будет хватать 1-5% то есть, например, получилось 95МГц, а надо 100, то можно за это браться. и больший эффект тут даст не знание как улучшить описание сумматора, а знание внутренностей ПЛИС и расстановка элементов в кристалле по площади - то есть низкоуровневая возня с железом я так понимаю, что вникать в детали устройства конкретной ПЛИС вам нет интереса, также нет каких-то ограничений по частоте, чтобы обеспечить тот или иной стандарт. поэтому описывайте на высоком уровне с использованием + - * алгоритм и оптимизируйте сам алгоритм (есть методы и для алгоритмов с обратными связями - как писали выше) если для демонстрации, ну и вообще, для придания "солидности" нужна плата - посмотрите тут https://www.terasic.com.tw/en/ но еще раз - вначале сделайте код работающий на симуляторе, затем синтезируйте его и посмотрите сколько он занимает ресурсов ПЛИС и в какую ПЛИС влезет, а потом уже выбирайте плату https://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&CategoryNo=167&No=921 https://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&CategoryNo=167&No=941&PartNo=1 во второй еще и процессор есть. полагаю, что для демонстрации хватит. возможно, что на алиэкспрессе или где-то еще в подобных местах, можно купить за те же деньги плату с ПЛИС с большими ресурсами. но отсутствие документации и возможные глюки, по-моему, того не стоят Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 30 июня, 2021 Опубликовано 30 июня, 2021 · Жалоба 4 hours ago, yes said: по поводу ДСП-блоков или каких-то схем улучшения операций сложения/умножения (carry-lookahead, carry-save, деревья Уоллеса, алгоритмы Бута и т.д. такого человечество придумало +100500 вариантов) можно не заморачиваться, инструмент (квартус) выберет оптимальное решение на ваш + или * в коде. это если не будет хватать 1-5% то есть, например, получилось 95МГц, а надо 100, то можно за это браться. и больший эффект тут даст не знание как улучшить описание сумматора, а знание внутренностей ПЛИС и расстановка элементов в кристалле по площади - то есть низкоуровневая возня с железом спорно (выделил жирным) это особенно если брать обработку данных в 32 бита и выше... :) и делать описание схемы с помощью языка HDL. Стараться не использовать готовые IP core производителя для обеспечения переносимости код Приведу пример на основе 64 битного счетчика Так сказать "Новороченный" счетчик: library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity PipelinedCounter is generic ( width_g: natural := 64; -- Must be divisible by parts_g. parts_g: natural := 4 ); port ( clk: in std_logic; rst: in std_logic; clear: in std_logic; enable: in std_logic; count: out std_logic_vector(width_g - 1 downto 0); tick: out std_logic ); end entity; architecture rtl of PipelinedCounter is constant part_width_c: natural := width_g / parts_g; signal almost_tick_r: std_logic_vector(parts_g - 1 downto 0); signal count_r: std_logic_vector(width_g - 1 downto 0); begin count <= count_r; process (all) variable part_v: unsigned(part_width_c - 1 downto 0); variable tick_v: std_logic; begin if rst = '1' then count_r <= (others => '0'); almost_tick_r <= (others => '0'); tick <= '0'; elsif rising_edge(clk) then tick_v := enable; for i in 0 to parts_g - 1 loop part_v := unsigned(count_r((i + 1) * part_width_c - 1 downto i * part_width_c)); if tick_v = '1' then -- Value is max - 1? if part_v = to_unsigned(2**part_width_c - 2, part_width_c) then almost_tick_r(i) <= '1'; else almost_tick_r(i) <= '0'; end if; part_v := part_v + 1; end if; count_r((i + 1) * part_width_c - 1 downto i * part_width_c) <= std_logic_vector(part_v); tick_v := tick_v and almost_tick_r(i); end loop; tick <= tick_v; if clear = '1' then count_r <= (others => '0'); almost_tick_r <= (others => '0'); tick <= '0'; end if; end if; end process; end architecture; и тот же счечик описанный стандартно: library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity PipelinedCounter is Port ( clk : in std_logic; en : in std_logic; rst : in std_logic; count : out std_logic_vector(63 downto 0)); end PipelinedCounter; architecture behavioral of PipelinedCounter is signal cnt: std_logic_vector (63 downto 0):= (others => '0'); begin pr_d_e: process (clk, en, cnt, rst) begin if (rst = '0') then cnt <= (others => '0'); elsif (clk'event and clk = '1') then if (en = '1') then cnt <= cnt + "0000000000000000000000000000000000000000000000000000000000000001"; end if; end if; count <= cnt; end process pr_d_e; end behavioral; обычный счетчик дает так сказать "Новороченный" счетчик PS Не для халивара. Это мое личное мнение/опыт. Все выше мною сказанное касается только если не использовать готовые IP core производителя, а стараться самому описать все вычислительные блоки на HDL, чтобы была переносимость. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
yes 7 1 июля, 2021 Опубликовано 1 июля, 2021 · Жалоба я согласен, что пример хороший и можно улучшить времянку конвеером, но если я правильно понял, то задержка (latency) первого примера не совпадает (больше), чем у второго. что для автора темы может быть критичным. и конкретно в этой теме, как мне кажется, автору интересно показать "применимость метода", а не тратить время на оптимизацию (то есть выиграть ~20% по частоте и потерять время разбираясь в тонкостях плисоведения не имеет смысла) и я тоже предпочитаю всегда описывать RTL и не брать IP от вендора, но наверняка, в конференции найдеся кто-то, кто из IP-шного сумматора сможет вытащить еще лучше (ну может 2-5%) чем из оптимального RTL. но это еще больше требует времени на освоение, и для человека, который не собирается становится плисоводом, путь тупиковый. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nick_K 0 1 июля, 2021 Опубликовано 1 июля, 2021 · Жалоба 20 minutes ago, yes said: предпочитаю всегда описывать RTL и не брать IP от вендора Если это hard IP, то описание на костылях RTL даёт ровным счётом ничего. А если строить на рассыпухе, тогда можно только потерять по всем параметрам. Научитесь пользоваться макро описанием и конфигурировать его. Для Ксайлинкса вполне валидный код типа: // MACC_MACRO: Multiply Accumulate Function implemented in a DSP48E // Artix-7 // Xilinx HDL Language Template, version 2020.2 MACC_MACRO #( .DEVICE("7SERIES"), // Target Device: "7SERIES" .LATENCY(3), // Desired clock cycle latency, 1-4 .WIDTH_A(25), // Multiplier A-input bus width, 1-25 .WIDTH_B(18), // Multiplier B-input bus width, 1-18 .WIDTH_P(48) // Accumulator output bus width, 1-48 ) MACC_MACRO_inst ( .P(P), // MACC output bus, width determined by WIDTH_P parameter .A(A), // MACC input A bus, width determined by WIDTH_A parameter .ADDSUB(ADDSUB), // 1-bit add/sub input, high selects add, low selects subtract .B(B), // MACC input B bus, width determined by WIDTH_B parameter .CARRYIN(CARRYIN), // 1-bit carry-in input to accumulator .CE(CE), // 1-bit active high input clock enable .CLK(CLK), // 1-bit positive edge clock input .LOAD(LOAD), // 1-bit active high input load accumulator enable .LOAD_DATA(LOAD_DATA), // Load accumulator input data, width determined by WIDTH_P parameter .RST(RST) // 1-bit input active high reset ); // End of MACC_MACRO_inst instantiation Тут и велосипед не засовывают, куда он не влазит, и поддержка производителя остаётся. С более детальной конфигурацией IP можно ознакомиться в соответствующей документации вплоть до добавления своих параметров конфигурации. p.s. Включите пайплайн в своём DSP и частота взлетит неимоверно. Обычно при dummy конфигурации DSP внутренние регистры не включаются от чего частота заваливается значительно. Включив внутри-IPшные регистры возможно придётся убрать что-то снаружи, но это очень поднимет общую рабочую частоту Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RobFPGA 34 1 июля, 2021 Опубликовано 1 июля, 2021 · Жалоба Приветствую! 12 minutes ago, Nick_K said: Если это hard IP, то описание на костылях RTL даёт ровным счётом ничего. А если строить на рассыпухе, тогда можно только потерять по всем параметрам. Научитесь пользоваться макро описанием и конфигурировать его. Увы макро - это лишь некоторая оболочка которая скрывает конкретную реализацию за абстрактным интерфейсом. Поэтому если хотите выжать максимум для конкретной FPGA то это только инстанцирование конкретного примитива hart-IP в RTL с ручной конфигурацией. Удачи! Rob. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться