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

Максимальная частота тактирования

14 часов назад, Manvel сказал:

То что я делаю, по сути из себя представляет систему из двух диф уравнений 2 порядка (приближенно можно сказать, что 2 фильтра 2-го порядка ФНЧ и ФВЧ) с нелинейной обратной связью. Далее вместо того, чтобы решать методом Рунге Кутта эти уравнения я делаю билинейное преобразования и получаю цифровое представление этой системы. В приведенной выше статье все эти шаги достаточно подробно описаны. Я не использую Альтеровсике библиотеки цифровых фильтров, потому что они относительно медленные из-за использования блоков перемножения, в данном случае, чтобы максимально ускорить систему я даже перемножения не использую, а просто суммирование со смещением максимум по первым трем битам коэффициентов цифрового фильтра. Скоро я должен буду приготовить семинар по тому что я сделал, если вам интересно, скину презентацию.

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

Я бы рекомендовал использовать DSP модули. Манипуляции с заменой умножения на суммирование, - прошлый век. 

Оно, скорее всего, и подрезало частоту. 

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


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

29.06.2021 в 01:54, yes сказал:

извините за любопытство, а где, в какой организации, вы этим занимаетесь? если не секрет

 

 

ИРЭ им. В.А. Котельникова РАН, вот ссылка на дореволюционный сайт, но там в принципе все есть http://cplire.ru/rus/InformChaosLab/index.htm

29.06.2021 в 09:13, vt313 сказал:

Я бы рекомендовал использовать DSP модули. Манипуляции с заменой умножения на суммирование, - прошлый век. 

Оно, скорее всего, и подрезало частоту. 

Можете порекомендовать какой-нибудь DSP борду для обучения, если такие существуют?

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


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

под DSP модулями имеется ввиду - столбец выделен - жирный текст

image.thumb.png.da7513c4239b25944525ac8ba68f0e3c.png

DSP модули имеются в каждой современной плис

у хилых он имеет вид

image.thumb.png.126b080b8609be58ed30c266ed1c1b4c.png

у интел примерно такой же

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


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

1 минуту назад, Maverick_ сказал:

под DSP модулями имеется ввиду - столбец выделен - жирный текст

image.thumb.png.da7513c4239b25944525ac8ba68f0e3c.png

DSP модули имеются в каждой современной плис

Ну, насколько я понял, когда я использовал умножение, квартус автоматом использовал эти DSP блоки при компиляции проекта, и скорость в таком случае был ниже, чем при замене умножения на суммирование.

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


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

сделайте pipline обработку на каждом такте выполняется только  независимые операции, например

а  = b+c;  v=d*w ; r=t-n;

также можете попробовать сделать операции ввида

f= d+c*t

 

если вначале вы посчитали например а  = b+c; потом через несколько тактов вам понадобился результат то не забываем вставлять перезапись результата в регистры на каждом такте на эти несколько тактов

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


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

например Вы хотите посчитать

image.png.d0c9ae94ee0f79ca5707c585edc38d5b.png

то 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;

image.thumb.png.500923fc1f37204af6fee6e95a609e4f.png

так же не забываем формировать сигнал разрешенния чтения результатов вычислений для следующего модуля - в моем описании последний процесс

 

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


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

48 минут назад, Manvel сказал:

Ну, насколько я понял, когда я использовал умножение, квартус автоматом использовал эти DSP блоки при компиляции проекта, и скорость в таком случае был ниже, чем при замене умножения на суммирование.

Странно, они и созданы для скорости. 

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


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

35 минут назад, Maverick_ сказал:

например Вы хотите посчитать

image.png.d0c9ae94ee0f79ca5707c585edc38d5b.png

то pipeline описание будет примерно следующее

 

так же не забываем формировать сигнал разрешенния чтения результатов вычислений для следующего модуля - в моем описании последний процесс

 

Спасибо за подробный ответ!

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


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

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

22 minutes ago, Manvel said:

Спасибо за подробный ответ!

 

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


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

18 минут назад, Maverick_ сказал:

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

 

О таком я читал, но пока до реализации не дошел

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


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

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

во второй еще и процессор есть.

полагаю, что для демонстрации хватит.

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

 

 

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


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

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;

обычный счетчик дает

image.thumb.png.47fbdf022dc694896e9bd266e5191790.png

так сказать "Новороченный" счетчик

image.thumb.png.a7cf790fc5aedf1f4318b09999431057.png

 

PS Не для халивара. Это мое личное мнение/опыт. Все выше мною сказанное касается только если не использовать готовые IP core производителя, а стараться самому описать все вычислительные блоки на HDL, чтобы была переносимость.

 

 

 

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


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

я согласен, что пример хороший и можно улучшить времянку конвеером, но если я правильно понял, то задержка (latency) первого примера не совпадает (больше), чем у второго. что для автора темы может быть критичным.

и конкретно в этой теме, как мне кажется, автору интересно показать "применимость метода", а не тратить время на оптимизацию (то есть выиграть ~20% по частоте и потерять время разбираясь в тонкостях плисоведения не имеет смысла)

и я тоже предпочитаю всегда описывать RTL и не брать IP от вендора, но наверняка, в конференции найдеся кто-то, кто из IP-шного сумматора сможет вытащить еще лучше (ну может 2-5%) чем из оптимального RTL. но это еще больше требует времени на освоение, и для человека, который не собирается становится плисоводом, путь тупиковый.

 

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


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

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шные регистры возможно придётся убрать что-то снаружи, но это очень поднимет общую рабочую частоту

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


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

Приветствую!

12 minutes ago, Nick_K said:

Если это hard IP, то описание на костылях RTL даёт ровным счётом ничего. А если строить на рассыпухе, тогда можно только потерять по всем параметрам.

Научитесь пользоваться макро описанием и конфигурировать его.

Увы макро - это лишь  некоторая оболочка которая скрывает конкретную  реализацию за абстрактным  интерфейсом.
Поэтому  если хотите выжать  максимум  для конкретной FPGA то это  только инстанцирование конкретного примитива hart-IP в RTL с ручной конфигурацией.   

 

Удачи! Rob.

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


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

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...