flammmable 0 25 марта, 2021 Опубликовано 25 марта, 2021 · Жалоба Лучшим делителем частоты является PLL, встроенный в ПЛИС. Однако, PLL-ов ограниченное количество и иногда оптимальным решением является сделать делитель на основе счетчика: reg [7:0]counter = 0; reg divided_clk = 0; always @(posedge clk) begin if(counter == DIVIDER - 1) begin divided_clk <= ~divided_clk; counter <= 0; end else begin counter <= counter + 1; end end Однако, сравнение if(counter == DIVIDER - 1) begin не оптимально использует логические элементы. Есть вариант проверять установку какого-либо бита: if(counter[DIVIDER_POW]) begin т.е. делить частоту на степень двойки. Однако, пропадает гибкость и точность установки делителя. Также возможно подобрать определенный делитель, вычесть из него единицу, перевести результат в двоичное число, а затем сделать лог.И всем разрядам с единицами. И вставить эту штуку в условие. Для делителя "50" будет что-то типа того: if(counter[5] && counter[4] && counter[0]) begin Логики тратится меньше, чем в первом случае. Но как параметризовать подобную конструкцию? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
des00 25 25 марта, 2021 Опубликовано 25 марта, 2021 · Жалоба эмм, а counter_done <= DIVIDER-2; counter <= counter_done ? '0 : (counter + 1'b1) чем плох? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
quato_a 3 25 марта, 2021 Опубликовано 25 марта, 2021 · Жалоба Ограничено не только кол-во PLL/MMCM, но и кол-во глобальных клоковых шин. Ну сделаете новый клок, но не сможете по нему тактироваться, поскольку уже заняты все BUFG. Один счетчик, пускай и 32 битный не так уж много ресурсов занимает. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nick_K 0 25 марта, 2021 Опубликовано 25 марта, 2021 · Жалоба 27 minutes ago, des00 said: эмм, а counter_done <= DIVIDER-2; counter <= counter_done ? '0 : (counter + 1'b1) чем плох? На вычетании 2-ки Вы дополнительно городите ещё один сумматор (вычитатель). Насколько я понял ТС нужен минимальный по площади делитель с максимальной гибкостью. Я сейчас занимаюсь потодного рода проектом и могу с уверенностью сказать, что такая схема будет оптимальна по площади и быстродействию. Единственное ограничение - частота работы => коэфф. деления. Для разрядности 6-10 бит вполне свободно на 100МГц можно уместить (в зависимости от чипа). Для большей разрядности нужно уменьшать частоту работы. По поводу буфферов - да желательно использовать BUFG, но иногда можно и BUFH, коих вполне достаточно для Xilinx чипов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
new123 0 25 марта, 2021 Опубликовано 25 марта, 2021 · Жалоба 15 minutes ago, Nick_K said: На вычетании 2-ки Вы дополнительно городите ещё один сумматор (вычитатель). а компилятор это дело не оптимизирует? Там же по сути константа будет Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Гость urri 25 марта, 2021 Опубликовано 25 марта, 2021 · Жалоба DIVIDER у вас константа или нет? Если константа то синтезатор сам синтезирует оптимальную схему сравнения. Повысить частоту можно как советовал des00. Если не константа, делайте вычитатель и сравнение с нулем. Загрузка значения по достижению нуля. Если еще нужно повысить частоту, разбивайте счетчик на 2 каскада и пропускайте перенос(разрешение счета) через триггер. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Zig 31 25 марта, 2021 Опубликовано 25 марта, 2021 · Жалоба Делайте счетчик вниз. Сравнивайте всегда с нулем, а загружайте его значением DIVIDER - 1. Или сравнивайте всегда с 1, а загружайте значением DIVIDER. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RobFPGA 27 25 марта, 2021 Опубликовано 25 марта, 2021 · Жалоба Приветствую! 2 hours ago, flammmable said: Логики тратится меньше, чем в первом случае. Но как параметризовать подобную конструкцию? Для макс. оптимизации надо учитывать структуру целевой FPGA. Для просто счетчика-делителя выгоднее всего считать вверх или вниз до переполнения с загрузкой коэф. деления. Типа такого logic ov; logic [CHT_WH-1:0] cnt; always @(posedge clk) begin if (rst || ov) begin {ov,cnt} <= (2**CHT_WH)-DIV_K+1; end else begin {ov,cnt} <= {ov,cnt} + 1'b1; end end При такой схеме нет как такового компаратора - все укладывается в логику счетчика с загрузкой. Но естественно тяжело использовать значения самого счетчика еще где ни будь. Удачи! Rob. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nick_K 0 25 марта, 2021 Опубликовано 25 марта, 2021 · Жалоба 3 hours ago, new123 said: а компилятор это дело не оптимизирует? Там же по сути константа будет Если DIVIDER - порт, то конечно нет) Всегда придётся вычитать значение от заданного предела. 2 hours ago, RobFPGA said: if (rst || ov) begin {ov,cnt} <= (2**CHT_WH)-DIV_K+1; end else begin {ov,cnt} <= {ov,cnt} + 1'b1; end Пример интересный, но здесь получается один сумматор и один вычитатель (который будет оптимизирован с +1). И всё бы ничего, но по экспериментам функция меньше-равно, занимает меньше места в лутах) Можно в обратную сторону считать - не вопрос. Но тогда сравнивать с нулём придётся, при условии что вычитатель немного сложнее сумматора (или вообще CSA для лутов Xilinx). Либо пересчитывать на 1 такт больше, если использовать сигнал borrow. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RobFPGA 27 25 марта, 2021 Опубликовано 25 марта, 2021 · Жалоба Приветствую! 4 hours ago, Nick_K said: Если DIVIDER - порт, то конечно нет) Всегда придётся вычитать значение от заданного предела. Пример интересный, но здесь получается один сумматор и один вычитатель (который будет оптимизирован с +1). И всё бы ничего, но по экспериментам функция меньше-равно, занимает меньше места в лутах) Можно в обратную сторону считать - не вопрос. Но тогда сравнивать с нулём придётся, при условии что вычитатель немного сложнее сумматора (или вообще CSA для лутов Xilinx). Либо пересчитывать на 1 такт больше, если использовать сигнал borrow. Константные выражения оптимизируются на этапе компиляции. Счетчик вниз выглядит так же как и вверх за исключением константы которая прибавляется. То есть это сумматор и регистр. Если счет идет непрерывно (как для делителя) то в этом случае константа -1 тоже оптимизируется. А вот если требуется управлять (старт/стоп) счетом то в этом случае +1 выгоднее (по ресурсам роутинга) чем -1. Так как в большинстве случаев управление счетом делается через изменение значения константы (0 или +-1) на входах LUT сумматора, а не через порт ena на триггере. Понятное дело подобное "крохоборство" оптимизации имеет смысл если это действительно припекает. Удачи! Rob. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dvladim 0 28 марта, 2021 Опубликовано 28 марта, 2021 · Жалоба А вот если требуется управлять значением счета, то -1 выгоднее. Т.к. при установке проще считать делитель: cnt <= DIVIDER а при сравнении проще сравнивать с -1: cnt == -1 т.е. cnt[msb] == 1'b1 always @(posedge clk) begin if (rst || ov) {ov,cnt} <= {1'b0, DIVIDER}; else {ov,cnt} <= {ov,cnt} - 1'b1; end Делитель соответственно с точностью до 1. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RobFPGA 27 28 марта, 2021 Опубликовано 28 марта, 2021 · Жалоба Приветствую! 4 hours ago, dvladim said: А вот если требуется управлять значением счета, то -1 выгоднее. ... Приведенный вами код не эквивалентен моему так как делить на значение DIVIDER+1; С таким же успехом можно и в +1 делить ... if (rst || ov) {ov, cnt} <= {1'b0, ~DIVIDER}; else {ov, cnt} <= {ov, cnt} + 1'b1; ... А если уж хочется все и сразу - переменный делитель, точный и минимум логики то тогда надо так ... input [WH-1:0] div; ... logic ov ; logic [WH-1:0] cnt; always_ff @(posedge clk) begin {ov, cnt} <= ( (rst || ov) ? {1'b0, ~div} : {ov, cnt} ) + 1'(rst || ov) + 1'b1; //{ov, cnt} <= ( (rst || ov) ? {1'b0, div} : {ov, cnt} ) - 1'(rst || ov) - 1'b1; end В Vivado (при таком описании делителя) варианты что +1 что с -1 занимают одинаковое число ресурсов - по одному LUT, REG, CARRY на каждый разряд счетчика и ov. Естественно в других синтезаторах и в других архитектурах FPGA все может быть по другому. Удачи! Rob. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dvladim 0 28 марта, 2021 Опубликовано 28 марта, 2021 · Жалоба 2 часа назад, RobFPGA сказал: Приведенный вами код не эквивалентен моему Конечно не эквивалентен. Я и не утверждал и не пытался это сделать. Но в целом с вами согласен - это крохоборство и преждевременная оптимизация. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
flammmable 0 30 марта, 2021 Опубликовано 30 марта, 2021 · Жалоба Подобную конструкцию делителей if(counter[5] && counter[4] && counter[0]) begin я увидел в примере Марсохода, посвященном UFM вот здесь. Задал вопрос на electronics.StackExchange, там присоветовали заменить на выражение if(counter & DIVIDER == DIVIDER) begin По количеству LE в синтезаторе Квартуса результат получился одинаковый. Однако, в комментариях также упомянули крохоборство и преждевременную оптимизацию, сказав, что проблема скученности возникнет быстрее, чем недостаток LE. Большое спасибо за все комментарии! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться