Flip-fl0p 2 April 5, 2020 Posted April 5, 2020 · Report post 12 минут назад, Zig сказал: Если вам нужно считать до разных значений, то для времянок будет лучше сделать счетчик считающий вниз. Сравнение будет всегда с нулем (или единицей), а загружаться счетчик должен вашим *_cntmax-1 (или *_cntmax). Сравнение с нулем в структуре ПЛИС реализуется на схемах ускоренного переноса и будет работать существенно быстрее многоразрядного компаратора с произвольным значением. Применив такой способ вы выведите из состава счетчика компаратор на произвольное значение и времянка улучшится. Не уверен, что это всегда так. Я в своё время проводил эксперименты. И сравнивал две абсолютно одинаковые по поведению схемы. В одной идет сравнение с каким-то значением. В другой сравнение с нулем. Результаты синтеза и результаты временного анализатора были абсолютно идентичны. Quote Share this post Link to post Share on other sites More sharing options...
RobFPGA 10 April 5, 2020 Posted April 5, 2020 · Report post Приветствую! Основное правило повышения частоты - уменьшение длинны критических путей. Отсюда не использовать непосредственно результат сравнения в условиях. А добавлять регистр как в примере blackfin. 25 minutes ago, Zig said: Сравнение с нулем в структуре ПЛИС реализуется на схемах ускоренного переноса и будет работать существенно быстрее многоразрядного компаратора с произвольным значением. Увы это не так. Для этого достаточно проанализировать когда на выходе схемы ускоренного переноса в структуре счетчика появляется 1. Но в тоже время схему ускоренного переноса внутри счетчика выгодно использовать в случае когда нужно именно задержка а само значение счетчика не важно. localparam CNT_WH = $clog2(CNT_DIV_MAX); logic [CNT_WH-1:0] cnt ; logic cnt_last; always @(posedge clk) begin {cnt_last, cnt} <= {cnt_last, cnt} + 1'b1; if (rst || cnt_last) begin {cnt_last, cnt} <= 2**CNT_WH+1-CNT_DIV; end // {cnt_last, cnt} <= {cnt_last, cnt} - 1'b1; // if (rst || cnt_last) begin // {cnt_last, cnt} <= CNT_DIV-2; // end end А если нужны и правильные значения то можно в паралель 2 счетчика - один для правильных значений, а один для быстрого сравнения. 16 minutes ago, Zig said: Если вам нужно считать до разных значений, то для времянок будет лучше сделать счетчик считающий вниз. Сравнение будет всегда с нулем (или единицей), а загружаться счетчик должен вашим *_cntmax-1 (или *_cntmax). Это имеет смыл именно для упрощения логики, если нужно считать для разных начальных значений счетчика меняющихся динамически во время работы. А внешнему к счетчику компаратору одинаково с чем сравнивать. К тому же сейчас многоразрядные компараторы тоже могут синтезироаться с использованием carry-chain для объединения частичных результатов с LUT. Удачи! Rob. Quote Share this post Link to post Share on other sites More sharing options...
Zig 10 April 5, 2020 Posted April 5, 2020 · Report post 9 минут назад, Flip-fl0p сказал: Не уверен, что это всегда так. Про рекомендацию применения счетчиков вниз читал в старых рекомендациях Xilinx еще на серии Spartan (просто Spartan, без индекса). В них получить 44-х разрядный счетчик на частоте 27 МГц без ухищрений было сложно. Рекомендация к применению вычитающих счетчиков объяснялась примерно так. Счетчик - это регистр к выходу которого подключен сумматор с единицей. Выход сумматора подключен к входу регистра. При счетчике, с модулем счета не совпадающем со степенью 2, на выход сумматора подключается компаратор, выход которого синхронно сбрасывает регистр. Соответственно у нас в путь задержек от регистра к нему же к слоям логики сумматора добавляются слои логики компаратора, понижая максимальную частоту. Ухищрение: Побороть это можно поставив компаратор на значение на единицу меньше требуемого и задержав результат сравнения (сброса регистра) на такт. При счете вниз мы получаем следующую схему. Мультиплексор - регистр - вычитатель единицы. На один вход мультиплексора подаем значение модуля счета, на другой - результат вычитателя. Управление мультиплексором - выход схемы ускоренного переноса счетчика. За счет того что ускоренный перенос в ПЛИС Xilinx выполнен по специальным линиям от CLB (Configurable Logic Block) к CLB по колонке задержка по этим линиям получалась меньше, чем в компараторе на LUT. В итоге в в путь задержек от регистра к нему же, по сравнению со счетчиком по степени 2, добавляется всего один слой логики (мультиплексор 2 в 1) на входе регистра. 29 минут назад, Flip-fl0p сказал: И сравнивал две абсолютно одинаковые по поведению схемы. Возможно это связано с продвинутостью синтезаторов с языков HDL. Они могли поставить тот же компаратор на значение на единицу меньше требуемого. В моем случае приходилось работать в схематике не особо надеясь на оптимизацию и подсказывать правильные решения имплементатору. Как обстоят дела со схемами ускоренного переноса у Intel не знаю. Нужно изучать структуру ПЛИС. Quote Share this post Link to post Share on other sites More sharing options...
RobFPGA 10 April 5, 2020 Posted April 5, 2020 · Report post Приветствую! 4 minutes ago, Zig said: Про рекомендацию применения счетчиков вниз читал в старых рекомендациях Xilinx еще на серии Spartan (просто Spartan, без индекса). В них получить 44-х разрядный счетчик на частоте 27 МГц без ухищрений было сложно. Рекомендация к применению вычитающих счетчиков объяснялась примерно так. ... Это вы что то спутали - что вниз что вверх структура счетчика одинакова. Даже наоборот - счет вниз на самом деле это счет вверх cnt <= cnt - K -> cnt <= cnt + ~K + 1'b1. Если по каким то причинам разрешение счета будет реализовано как управление K (например К это регистр в вашей логике) то это потребует разводки нескольких цепей от источника К к каждому разряду счетчика. А это доп проблемы и задержки. Для счет вверх нужна только 1 цепь к младшему разряду. На стары семействах если скорости не хватает то основная техника ускорения это pipeline счетчика - разбиваем счетчик на 2 ( или более) меньших по разрядности с регистром в цепи переноса в старшие разряды и проблем нет. Удачи! Rob. Quote Share this post Link to post Share on other sites More sharing options...
Flip-fl0p 2 April 5, 2020 Posted April 5, 2020 · Report post 3 минуты назад, RobFPGA сказал: Приветствую! Это вы что то спутали - что вниз что вверх структура счетчика одинакова. Даже наоборот - счет вниз на самом деле это счет вверх cnt <= cnt - K -> cnt <= cnt + ~K + 1'b1. Если по каким то причинам разрешение счета будет реализовано как управление K (например К это регистр в вашей логике) то это потребует разводки нескольких цепей от источника К к каждому разряду счетчика. А это доп проблемы и задержки. Для счет вверх нужна только 1 цепь к младшему разряду. На стары семействах если скорости не хватает то основная техника ускорения это pipeline счетчика - разбиваем счетчик на 2 ( или более) меньших по разрядности с регистром в цепи переноса в старшие разряды и проблем нет. Удачи! Rob. Ещё может помочь - атрибут подключить сигнал разрешения (сигнал переноса) в явном виде к регистрам. В противном случае синтезатор сигнал разрешения может через lut реализовать. Quote Share this post Link to post Share on other sites More sharing options...
Maverick_ 10 April 5, 2020 Posted April 5, 2020 · Report post library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity Pipeline_Counter is generic ( width_g: natural := 64; -- Must be divisible by parts_g. parts_g: natural := 4 ); port ( clk: in std_logic; rst_n: 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 Pipeline_Counter; architecture rtl of Pipeline_Counter 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 (clk, rst_n) variable part_v: unsigned(part_width_c - 1 downto 0); variable tick_v: std_logic; begin if rst_n = '0' 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; testbench library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity tb_pipeline_counter is end entity; architecture testbench of tb_pipeline_counter is signal clk, rst_n: std_logic; signal clear: std_logic; signal enable: std_logic; signal count: std_logic_vector(15 downto 0); signal tick: std_logic; begin cnt1: entity work.Pipeline_Counter generic map (width_g => 16, parts_g => 4) port map (clk, rst_n, clear, enable, count, tick); process procedure clock is constant PERIOD: time := 1 us; begin clk <= '0'; wait for PERIOD/2; clk <= '1'; wait for PERIOD/2; end procedure; begin rst_n <= '0'; clear <= '0'; enable <= '0'; clock; rst_n <= '1'; enable <= '1'; for i in 0 to 65535 loop assert unsigned(count) = to_unsigned(i, 16) report "Wrong count, " & integer'image(to_integer(unsigned(count))) & " expected " & integer'image(i); assert tick = '0' report "Unexpected tick"; clock; end loop; assert count = X"0000" report "Expected to roll over"; assert tick = '1' report "Expected tick"; clock; assert count = X"0001"; clear <= '1'; clock; clear <= '0'; assert count = X"0000" report "Counter should clear"; clock; assert count = X"0001"; report "Simulation ended" severity note; wait; end process; end architecture; Quote Share this post Link to post Share on other sites More sharing options...
vt313 0 April 6, 2020 Posted April 6, 2020 · Report post В 05.04.2020 в 11:13, AltairNsk сказал: Добрый день Осваиваю плисоводство, на плате MaxII EPM570T100, соответственно quartus 13.0sp1 webedition. Нарисовалась вот такая штука, три вложенных счетчика с параметрами, задающих времянки //input bit_cntmax, word_cntmax if (bit_cnt < bit_cntmax) bit_cnt <= bit_cnt + 1; else bit_cnt <= 0; if (bit_cnt == bit_cntmax) begin if (word_cnt < word_cntmax) word_cnt <= word_cnt + 1; else word_cnt <= 0; end if (bit_cnt == bit_cntmax && word_cnt == word_cntmax) begin if (msg_cnt < MSG_LENGTH) msg_cnt <= msg_cnt + 1; else msg_cnt <= 0; end //output sig = f(bit_cnt, word_cnt, msg_cnt) Привычно глазам, в симуляторе тикает как надо, но в железе не успевает. Можно ли как-то объяснить синтезатору, что тут нужно делать именно счетчики, а не регистры+сумматор+компаратор? Или смириться и привыкать вставлять мегафункции? Если Вы хотите сделать именно счетчик, то и описывайте его как счетчик. if we = '1' then cnt <= data; elsif ce = '1' then cnt <= cnt + 1; end if; А сигналы "we" и "ce" формируйте отдельно. Когда наберетесь опыта будете писать более сложные конструкции, учитывать структуру кристалла, возможности среды и т.д. и т.п. Если есть возможность не применять мегафункции, не применяйте их. Quote Share this post Link to post Share on other sites More sharing options...
AltairNsk 0 April 7, 2020 Posted April 7, 2020 · Report post Итого выкинул из проекта совсем лишнюю логику (лишний счетчик, два десятка регистров). В процессе проверил на железе с осциллографом, исправил грубые ошибки (в симуляторе глядел, но плохо). И методом последовательного тыка настроек компилятора получилось уложить в 100 МГц. Счетчики пока не переделывал. Quote Share this post Link to post Share on other sites More sharing options...
MrGalaxy 6 April 7, 2020 Posted April 7, 2020 · Report post В 05.04.2020 в 11:23, Flip-fl0p сказал: Хотие быстрый счетчик? 1. Используйте счетчик, который считает от 0 до 2**n -1, который обнуляется переполнением. if (rising_edge(clk)) then cnt <= cnt + "1"; end if; +1! И в модели, и в железе работает. А меня на этом форуме тапками закидали за такой счётчик. Quote Share this post Link to post Share on other sites More sharing options...
Flip-fl0p 2 April 7, 2020 Posted April 7, 2020 · Report post 33 минуты назад, MrGalaxy сказал: +1! И в модели, и в железе работает. А меня на этом форуме тапками закидали за такой счётчик. А можно ссылочку. Интересно почитать аргументы других участников форума. Quote Share this post Link to post Share on other sites More sharing options...
MrGalaxy 6 April 7, 2020 Posted April 7, 2020 · Report post 14 минут назад, Flip-fl0p сказал: А можно ссылочку. Интересно почитать аргументы других участников форума. Я уж и забыл про тот диалог, Вы мне своим постом напомнили. :) Насилу нашёл, аж самому интересно стало. https://electronix.ru/forum/index.php?app=forums&module=forums&controller=topic&id=155020&app=forums&module=forums&id=155020 Quote Share this post Link to post Share on other sites More sharing options...
andrew_b 9 April 7, 2020 Posted April 7, 2020 · Report post 49 минут назад, MrGalaxy сказал: Насилу нашёл, аж самому интересно стало. Там вам всё разжевали. Ещё раз. 1. Если у вас счётчик -- сигнал/переменная -- вектор, то всё хорошо: он переполняется и из макисмума переходит в ноль. 2. При поведенческом моделировании, если у вас счётчик -- сигнал/переменная -- целый тип с указанным диапазоном, то не всё хорошо: он не переполняется и из макисмума не переходит в ноль. При выходе за границы диапазона генерируется ошибка. Если же симулятор кривой, счётчик продолжит считать дальше. 3. При временно́м моделировании (после синтеза и тем более после P&R), если у вас счётчик -- сигнал/переменная -- целый тип с указанным диапазоном, то от целого ничего не осталось, он превратился в вектор. Тогда см. п. 1. Quote Share this post Link to post Share on other sites More sharing options...
blackfin 4 April 7, 2020 Posted April 7, 2020 · Report post 11 minutes ago, andrew_b said: если у вас счётчик -- сигнал/переменная -- целый тип с указанным диапазоном А если ещё напрячься и почитать стандарт IEEE Std 1364, то на стр. 32 можно увидеть замечательную фразу: Quote An integer is a general-purpose variable used for manipulating quantities that are not regarded as hardware registers. Так что формально, делать счетчик на integer нельзя. Quote Share this post Link to post Share on other sites More sharing options...
sorok-odin 5 April 7, 2020 Posted April 7, 2020 · Report post 6 минут назад, andrew_b сказал: 3. При временно́м моделировании (после синтеза и тем более после P&R), если у вас счётчик -- сигнал/переменная -- целый тип с указанным диапазоном, то от целого ничего не осталось, он превратился в вектор. Тогда см. п. 1. Думается мне, если заданный диапазон не кратен степени двойки, счетчик скорее всего обнулится позже, при превышении диапазона созданного вектора. К примеру, если диапазон был 0..12, то обнуление 4-битного вектора будет после значения 15. Т.е. не "всё хорошо". Quote Share this post Link to post Share on other sites More sharing options...
Flip-fl0p 2 April 7, 2020 Posted April 7, 2020 · Report post 1 час назад, MrGalaxy сказал: Я уж и забыл про тот диалог, Вы мне своим постом напомнили. :) Насилу нашёл, аж самому интересно стало. https://electronix.ru/forum/index.php?app=forums&module=forums&controller=topic&id=155020&app=forums&module=forums&id=155020 Тогда понятно. Вам все правильно сказали. Я сам наступал на эти грабли в начале изучения VHDL: Но хочу обратить ваше внимание на строчку cnt <= cnt + "1"; Наша единичка в кавычках заключена не просто так. А потому-что ранее счетчик объявлен как signal cnt : unsigned(max_width - 1 downto 0) := (others => '0'); Ибо я ярый поклонник библиотеки IEEE.numeric_std.all; И никаких сторонних библиотек у меня найти невозможно. Ну разве что в исключительных случаях пользую IEEE.math_real.all Quote Share this post Link to post Share on other sites More sharing options...