Source-Synchronus Output
Как уже обсуждалось выше, в подобных системах тактовая частота на ПЛИС идет с приемника данных или с отдельного генератора, частота которого идет на ПЛИС и периферийное устройство. Данный метод тактирования используется в случае, когда требуется минимизировать джиттер тактового сигнала, это особенно важно для АЦП/ЦАП. Пример построения такой системы

Как видно в этом случае источник тактовой частоты для приемника интерфейсов вообще не присутствует в ПЛИС. Как же его описать? Для описания таких ситуаций в TimeQuest есть возможность задать так называемый виртуальный клок. Т.е. клок, у которого отсутствует физический источник.
Рассмотрим опять вывод пилы на ЦАП, на сей раз с внешним тактированием.
module dac (input clk, output logic [7 : 0] data);
logic [7 : 0] cnt;
always_ff @(posedge clk) begin
cnt <= cnt + 1'b1;
data <= cnt;
end
endmodule
Соответствующий этому проекту sdc файл
set_time_format -unit ns -decimal_places 3
derive_clock_uncertainty
create_clock -period 10MHz -name {clk} [get_ports {clk}]
create_clock -period 10MHz -name {virt_clk}
set_clock_groups -exclusive -group {clk virt_clk}
# увеличение уменьшает запас по tsu
set CLK_bs_delay_max 0.2
set DATA_delay_max 0.5
# увеличение увеличивает запас по tsu
set CLK_bd_delay_min 1.0
# увеличение увеличивает запас по th
set CLK_bs_delay_min 0.2
set DATA_delay_min 0.5
# увеличение уменьшает запас по th
set CLK_bd_delay_max 1.0
set tSU 5.0
set tH 5.0
set_output_delay -clock [get_clocks {virt_clk}] \
-max [expr $CLK_bs_delay_max + $tSU + $DATA_delay_max - $CLK_bd_delay_min] [get_ports {data[*]}]
set_output_delay -clock [get_clocks {virt_clk}] \
-min [expr $CLK_bs_delay_min - $tH + $DATA_delay_min - $CLK_bd_delay_max] [get_ports {data[*]}]
Первый взгляд на sdc файл, вызывает в голове мысли "А ну нафиг такие интерфейсы, давайте тактировать от ПЛИС". Но не надо торопиться, здесь все логично и просто. Начнем разбирать те строки, которые нам еще не знакомы.
ЦАП тактируется от того же генератора что и ПЛИС, т.е. в плис этот клок физически не существует, но относительно ПЛИС он есть. Эта строка
create_clock -period 10MHz -name {virt_clk}
и описывает тот самый клок. Теперь нужно задать констрейны на tsu/th
set_output_delay -clock [get_clocks {virt_clk}] \
-max [expr $CLK_bs_delay_max + $tSU + $DATA_delay_max - $CLK_bd_delay_min] [get_ports {data[*]}]
set_output_delay -clock [get_clocks {virt_clk}] \
-min [expr $CLK_bs_delay_min - $tH + $DATA_delay_min - $CLK_bd_delay_max] [get_ports {data[*]}]
Внимательно приглядевшись мы видим общее, с примером system-synchronus output рассмотренным ранее. Это указание времен tsu/th в задержках. Но также видим отличия. Заключаются они вот в чем:
- Клоки тактирования ЦАП и ПЛИС идут разными путями на плате, то для временного анализа надо знать их местоположения друг относительно друга. А это мы можем извлечь только из конструктива печатной платы. Поэтому эти задержки нужно измерить и учесть в констрейне.
- Данные тоже проходят определенный путь по плате и это путь отличен от пути клока ЦАП, поэтому задержку данных тоже нужно обязательно учесть.
- Что бы не считать все задержки в уме (а если вы их будете делать это часто, то это лишний повод для ошибки), мы используем возможность TimeQuest считать выражения самостоятельно. Делается это с помощью TCL переменных и команды расчета выражений [expr]
В приведенном выше sdc файле видно что используется максимальные и минимальные значения задержек. Сделано это потому, что задать задержку на ПП можно с определенной точностью, а для анализа нас интересует наихудший случай. Потому-то при заданиях констрейнов и используются разные значения задержек.
В скрипте как вы видите значения минимальных и максимальных задержек одинаковые, потому что на изложение теории это не влияет (формулы написаны верные) и это скрытый намек для вас поиграть с этими задержками в TimeQuest и посмотреть результат
Собираем проект, запускаем временной анализ. Смотрим

видим, что мы уложились в констрейны. но посмотрите, какой большой запас есть по tsu, и какой маленький запас по th. Работать с таким запасом крайне рискованно, даже на 10МГц. Кроме того, в режиме работы fast, видно что у нас вылезают слаки по холду

если посмотреть поподробнее
то видно, что нам не хватает задержки по данным. А у квартуса не хватает ума что бы набрать эту задержку, например на LUT ах. В данном примере Fast Output Register не используется, можно попробовать задержать данные на задержках в I/O буферах. Но в таком случае более эффективна другая техника. С помощью PLL подвинуть клок ПЛИС.
Генерим PLL работающую один в один и сдвигающую клок по фазе на 90 градусов.
module dacpll (input clk, output logic [7 : 0] data);
pll_no_delay
pll_no_delay
(
.areset (1'b0),
.inclk0 (clk),
.c0 (used_clk),
.locked ( )
);
logic [7 : 0] cnt;
always_ff @(posedge used_clk) begin
cnt <= cnt + 1'b1;
data <= cnt;
end
endmodule
Вуаля, запас по холду вырос до 23.5нс.

а все потому, что мы подвинули клок на 25нс (1/4 периода частоты 10МГц).
Как вы понимаете, случай тактирования от одного генератора, ничем не отличается от случая тактирования от приемника данных. Просто в одном случае у нас должны быть учтены длинны трас до обоих приемников тактового сигнала, а в другом случае только от приемника данных до ПЛИС.

Комментарии
Спасибо Автору! Всё очень
Спасибо, поправил
Спасибо, поправил
Отправить комментарий