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

Как параметризовать делитель частоты?

Лучшим делителем частоты является 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

Логики тратится меньше, чем в первом случае. Но как параметризовать подобную конструкцию?

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


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

эмм, а

counter_done <= DIVIDER-2; 

counter <= counter_done  ? '0 : (counter + 1'b1) 

чем плох? 

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


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

Ограничено не только кол-во PLL/MMCM, но и кол-во глобальных клоковых шин. Ну сделаете новый клок, но не сможете по нему тактироваться, поскольку уже заняты все BUFG.

Один счетчик, пускай и 32 битный  не так уж много ресурсов занимает.

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


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

27 minutes ago, des00 said:

эмм, а


counter_done <= DIVIDER-2; 

counter <= counter_done  ? '0 : (counter + 1'b1) 

чем плох? 

На вычетании 2-ки Вы дополнительно городите ещё один сумматор (вычитатель).

Насколько я понял ТС нужен минимальный  по площади делитель с максимальной гибкостью. Я сейчас занимаюсь потодного рода проектом и могу с уверенностью сказать, что такая схема будет оптимальна по площади и быстродействию.

image.thumb.png.d784b483a5568f3f13a11164c3110f35.png

Единственное ограничение - частота работы => коэфф. деления. Для разрядности 6-10 бит вполне свободно на 100МГц можно уместить (в зависимости от чипа). Для большей разрядности нужно уменьшать частоту работы.

По поводу буфферов - да желательно использовать BUFG, но иногда можно и BUFH, коих вполне достаточно для Xilinx чипов.

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


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

15 minutes ago, Nick_K said:

На вычетании 2-ки Вы дополнительно городите ещё один сумматор (вычитатель).

а компилятор это дело не оптимизирует? Там же по сути константа будет

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


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

Гость urri
DIVIDER у вас константа или нет? 
Если константа то синтезатор сам синтезирует оптимальную схему сравнения. 
Повысить частоту можно как советовал des00. 
Если не константа, делайте вычитатель и сравнение с нулем. Загрузка значения по достижению нуля.
Если еще нужно повысить частоту, разбивайте счетчик на 2 каскада и пропускайте перенос(разрешение счета) через триггер.

 

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


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

Делайте счетчик вниз.

Сравнивайте всегда с нулем, а загружайте его значением DIVIDER - 1.

Или сравнивайте всегда с 1, а загружайте значением DIVIDER.

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


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

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

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.

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


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

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.

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


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

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

4 hours ago, Nick_K said:

Если DIVIDER - порт, то конечно нет) Всегда придётся вычитать значение от заданного предела.

Пример интересный, но здесь получается один сумматор и один вычитатель (который будет оптимизирован с +1). И всё бы ничего, но по экспериментам функция меньше-равно, занимает меньше места в лутах)

Можно в обратную сторону считать - не вопрос. Но тогда сравнивать с нулём придётся, при условии что вычитатель немного сложнее сумматора (или вообще CSA для лутов Xilinx). Либо пересчитывать на 1 такт больше, если использовать сигнал borrow.

Константные выражения оптимизируются на этапе компиляции. 

Счетчик вниз выглядит так же как и вверх за исключением константы которая  прибавляется. То есть это сумматор и регистр. Если счет идет непрерывно (как для делителя) то в этом случае константа -1 тоже оптимизируется.  А  вот если требуется  управлять (старт/стоп) счетом то  в этом случае +1  выгоднее  (по ресурсам роутинга) чем -1.  Так как в большинстве случаев управление счетом делается через изменение значения константы (0 или +-1)  на входах LUT сумматора, а не через порт ena на триггере.

Понятное дело подобное "крохоборство" оптимизации имеет смысл если это действительно припекает. 

 

Удачи! Rob.

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


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

А вот если требуется управлять значением счета, то -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.

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


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

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

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. 

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


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

2 часа назад, RobFPGA сказал:

Приведенный  вами код не эквивалентен моему

Конечно не эквивалентен. Я и не утверждал и не пытался это сделать.

Но в целом с вами согласен - это крохоборство и преждевременная оптимизация.

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


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

Подобную конструкцию делителей

if(counter[5] && counter[4] && counter[0]) begin

я увидел в примере Марсохода, посвященном UFM вот здесь.

Задал вопрос на electronics.StackExchange, там присоветовали заменить на выражение 

if(counter & DIVIDER == DIVIDER) begin

По количеству LE в синтезаторе Квартуса результат получился одинаковый. Однако, в комментариях также упомянули крохоборство и преждевременную оптимизацию, сказав, что проблема скученности возникнет быстрее, чем недостаток LE.

Большое спасибо за все комментарии!

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


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

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

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

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

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

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

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

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

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

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