TimeQuest для чайников. Часть 3 (Клоки как вас много)

Клоки рожденные внутри ПЛИС

В современных проектах очень часто используется обработка сигнала или работа блоков ПЛИС на разных тактовых частотах. Это позволяет уменьшить ресурсы (меньше частота проще разводить) и энергопотребление ПЛИС. Рассмотрим два типовых случая порождения в ПЛИС дополнительного клока.

Порождение клока без PLL

Рассмотрим простой код

module gen_clk (input clk_100MHz, output logic led) ;

  logic ff;

  logic [31 : 0] cnt;

  always_ff @(posedge clk_100MHz) begin // clock divider
    ff <= ~ff;
  end

  global global (ff, clk_50MHz);

  always_ff @(posedge clk_50MHz) begin
    cnt <= cnt + 1'b1;
    led <= cnt[31];
  end

endmodule

Видим, что с помощью делителя на триггере сделан половинный клок, который затем подан на глобальную тактовую линию и на этом клоке сделан счетчик. Подобные клоки описываются так

create_generated_clock -name {clk_50MHz} -divide_by 2 -source [get_ports {clk_100MHz}] [get_registers {ff}]

Здесь мы задали логическое имя клока clk_50MHz,  источник этого клока порт ПЛИС clk_100MHz, преобразование частоты этого источника и объект ПЛИС на который этот клок назначен. В данном случае это триггер ff, на котором и производилось деление частоты. Особенное внимание нужно заострить на том факте, что источником клока указывается не логическое имя клока, а именно его физический источник.

Если собрать воеднино всё что мы уже узнали об sdc файлах, то для этого проекта sdc файл будет таким

derive_clock_uncertainty
create_clock -period 100MHz -name {clk_100MHz} [get_ports {clk_100MHz}]

create_generated_clock -name {clk_50MHz} -divide_by 2 -source [get_ports {clk_100MHz}] [get_registers {ff}]

set_clock_groups -exclusive -group {clk_100MHz}
set_clock_groups -exclusive -group {clk_50MHz}

set_false_path -from [get_clocks {clk_50MHz}] -to [get_ports {led}]

Порождение клока с помошью PLL

Рассмотрим код простого маппера, положим сигнала на входе ЦАП, который работает в режиме интерливинга входных данных.

module mapper (input iclk, input int idat_re, idat_im, output int odat, output logic oval);

  //
  // multiply clk for output
  //

  pll pll(iclk, clk_x2, locked);

  //
  // low freq clock domain
  //

  int dat_re, dat_im;

  always_ff @(posedge iclk) begin
    dat_re <= idat_re;
    dat_im <= idat_im;
  end

  //
  // high freq clock domain
  //

  logic ff;

  always_ff @(posedge clk_x2) begin
    ff <= ~ff;
  end

  always_ff @(posedge clk_x2) begin
    odat <= ff ? dat_re : dat_im;
    oval <= ff;
  end

endmodule

Как мы видим, для интерливинга нужно мультиплексировать данные на выходе плис на частоте в два раза больше частоты входных символов. Первое что нужно сделать это описать умножение частоты. Второе описать взаимоотношения клоков, поместив их iclk и clk_x2 в одну клоковую группу, потому что в данном случае есть синхронная передача данных между частотами.

Описать умножение частоты на PLL можно двумя способами

1. С помощью команды create_generated_clock. В этой команде нужно прописать все параметры преобразования частоты и логическое имя клока.

create_generated_clock -name clk_x2 -source [get_ports {iclk}] -multiply_by 2 [get_pins {pll|altpll_component|auto_generated|pll1|clk[0]}]

В этом случае описание отношений частот будет такое

set_clock_groups -exclusive -group {iclk clk_x2}

Минусом данного подхода является то, что при изменении коэффициентов PLL нужно изменять строку в sdc файле.

2. С помощью команды derive_pll_clocks

derive_pll_clocks

Что происходит при выполнении этой команды можно посмотреть в консоли. А именно

Info: Deriving PLL Clocks
    Info: create_generated_clock -source {pll|altpll_component|auto_generated|pll1|inclk[0]} -multiply_by 2 -duty_cycle 50.00 -name {pll|altpll_component|auto_generated|pll1|clk[0]} {pll|altpll_component|auto_generated|pll1|clk[0]}

Как мы видим, клок создался автоматически, с учетом всех преобразований. А минусом данного подхода является то, что клок получает длинное логическое имя. Описание отношений клоков соответственно будет менее элегантное

set_clock_groups -exclusive -group {iclk pll|altpll_component|auto_generated|pll1|clk[0]}

Но есть красивый выход, использование TCL переменных (Спасибо SM с www.electronix.ru за помощь в этом вопросе). В этом случае описание отношений клоков будет таким

set clk_x2 pll|altpll_component|auto_generated|pll1|clk[0]

set_clock_groups -exclusive -group [list $clk_x2 iclk]

Комментарии

Отправить комментарий

Содержание этого поля является приватным и не предназначено к показу.
  • Syntax highlight code surrounded by the {syntaxhighlighter SPEC}...{/syntaxhighlighter} tags, where SPEC is a Syntaxhighlighter options string or "class="OPTIONS" title="the title".
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Доступны HTML теги: <a> <p> <span> <s> <strike> <div> <h1> <h2> <h3> <h4> <h5> <h6> <img> <map> <area> <hr> <br> <br /> <ul> <ol> <li> <dl> <dt> <dd> <table> <caption> <tbody> <tr> <td> <em> <b> <u> <i> <strong> <del> <ins> <sub> <sup> <quote> <blockquote> <pre> <address> <code> <cite> <embed> <object> <param> <strike>
  • Использовать как разделитель страниц.

Подробнее о форматировании