Jump to content

    
flammmable

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

Recommended Posts

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

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

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites
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 чипов.

Share this post


Link to post
Share on other sites
15 minutes ago, Nick_K said:

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

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

Share this post


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

 

Share this post


Link to post
Share on other sites

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

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

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

Share this post


Link to post
Share on other sites

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

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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

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

4 hours ago, Nick_K said:

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

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

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

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

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

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

 

Удачи! Rob.

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

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. 

Share this post


Link to post
Share on other sites
2 часа назад, RobFPGA сказал:

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

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

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

Share this post


Link to post
Share on other sites

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

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

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

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

if(counter & DIVIDER == DIVIDER) begin

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

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

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.