Comments 25
У вас первый модуль должен не Delay называться, а Divider — это делитель тактовой частоты для получения сигнала с периодом 1 секунда.
Не добавите в статью результаты симуляции для вашего кода, желательно помодульно — состояние входов, выходов?
ПС так и хочется продемонстрировать, что такое сегодня возможно сделать вообще без знаний Verilog/VHDL с помощью Матлаба/Симулинка в полностью графическом виде, с полной симуляцией и скорей всего быстрее. Получится намного проще и наглядней. Интересно? Сесть за статью?
такое сегодня возможно сделать вообще без знаний Verilog/VHDL с помощью Матлаба/Симулинка в полностью графическом виде
А что с этим дальше делать? В железку можно залить результат?
Другое дело что в данном случае это будет операция на глазе через ж*.
Такой подход оправдан, когда Вы делаете на FPGA ЦОС — всякие фильтры и прочее такое.
Ну и глобально — владение такими средствами проектирования — это бонус, который не отменяет необходимости знания HDL языка.
Не согласен. Сегодня Simulink дает достаточно оптимальный код и с точки зрения быстродействия и с точки зрения ресурсов. Мало того, разработчик может легко сам поменять приоритеты при генерации кода, чтобы, например, сделать полностью параллельную схему, но занимающую большую площадь, или с мультиплексированием с разделением по времени.
Попробуйте сделать то же самое на Verilog/VHDL, если вдруг окажется, что проект не пролазит по размеру или частоте — пол кода придется переписать.
Знание HDL не нужно, нужно знание принципов работы ПЛИС в основном, чтобы понимать как работают синхронные дизайны и правильно делать времянки.
Попробуйте сделать то же самое на Verilog/VHDL, если вдруг окажется, что проект не пролазит по размеру или частоте — пол кода придется переписать.
Я делал это периодически с достаточно грузными IP-блоками. Причем в основном я занимался различного рода неблокирующими маршрутизаторами интерфейсов с 100% hardware offload. На такое применение данные пакеты ну совсем не кладутся.
К тому же я имел в виду кейс написания обсуждаемой прошивки.
Касательно «не проходят по частоте». По частое обычно не пролазят какие-то конкретные участки, где наворочено 100500 уровней логики и все это в том же такте заводится в какой-нить BRAM. Это все локализуемо и исправляемо. Вот прям глоабально все переписывать приходилось когда заказчик решал идеологию поменять, или добавить какую-то незначительную на его взгляд поправку в интерфейс.
Второй типовой случай не прохождения по частоте — это когда Вы сожрали все макроблоки, которые имеют фиксированные точки размещения — и синтезатор просто не может оптимально их разместить. Например съели всю память, а долбитесь в нее со всех концов ПЛИС, а она вся в 2х локациях собрана.
Нет — я не против Матлабов, Симлинков и IP-интеграторов. И даже почти не против HLS. Просто я эти вещи рассматриваю как дополнительные скиллы. Вот не владея ими можно писать что угодно. Хоть процессорные ядра. А не владея HDL (хотя бы одним) — писать что угодно — нельзя.
Если использовать Simulink HDL Coder, то нет. Код будет кросс-платформенным и полностью написанным на стандартном VHDL или VERILOG. То есть его можно будет запихнуть и в altera и Xilinx и он везде скомпилируется, но при этом использование специальных фич на данном кристалле будет зависеть полностью от синтезатора — сможет ли он, например, распознать в исходном коде умножитель и запихнуть его в соответствующий Hardware блок или нет? Как правило простые вещи, как умножители, память, синтезаторы распознают неплохо и используют по мере возможности железные блоки. Но далеко не во всех случаях и проблема в том, что разработчик не всегда имеет возможность повлиять на решение синтезатора использовать логику или железный блок. Приходится придумывать уловки.
Если же использовать более специализированные тулбоксы для Simulinka (для Xilinx это System Generator, для Altera это DSP Builder), то там уже появляются оптимизированные блоки, которые хорошо ложатся на конкретную плисину и используют ресурсы, доступные только в данной модели. А в случае с умножителями или памятью дизайнеру даже предоставляется выбор из нескольких опций — использовать железный блок, логику, LUT и т.д. То есть здесь оптимизации более гибкие.
Интересно? Сесть за статью?
Конечно да. Садитесь)
Я совсем дилетант в верилоге, и меня всегда интересовало слелдующее: насколько оптимально то, что генерируется по Verilog коду? Например, делитель — двоичный счетчик, последовательность триггеров. А код автора код практически как на обычных императивных языках. Что получится в итоге? Поэтому есть ряд вопросов:
- Насколько правильно так вообще писать?
- Какие есть правила написания эффективного verilog-кода?
По делителю: вот эти строчки:
generic (delay_cnt: integer);
...
variable clk_cnt: integer range 0 to delay_cnt := 0;
...
if(rising_edge(clk)) then
clk_cnt := clk_cnt + 1;
фактически и являются цепочкой последовательно соединенных триггеров в количестве integer (если не ошибаюсь, это 32), первый из которых «щелкает» по фронту clk :) Точнее, первые две строчки синтезируют цепочку триггеров, а две последние подключают к первому из этих триггеров сигнал клока. Синтезатору дано в коде прямое указание на это, никак иначе он трактовать и синтезировать не сможет.
Фактически, если понимаешь что делаешь, то VHDL, Verilog — это ассемблер для FPGA. У каждого кода будет вполне предсказуемый результат синтеза. Но если не очень понимаешь, то запросто пройдешься по массе способов отстрелить себе обе ноги :)
Что касается оптимальности по быстродействию и объему, то тут уже зависит не только от искусства программирования, но и от знания архитектуры конкретной FPGA, от умения правильно вручную расположить разные блоки на «карте» чипа, распределить клоки, задействовать аппаратные возможности и т.п.
То, о чём Вы говорите (цепочка триггеров, на первый из которых подан тактовый сигнал) — это Асинхронный счётчик, или счётчик пульсаций, где каждый последующий бит тактируется предыдущим, и просто щёлкает в два раза реже. Его огромный недостаток — состоит в том, что биты на выходе встают в новое состояние последовательно, а не одновременно. Синтезировать такую конструкцию можно, видимо, только используя generate. А потом к ней ещё констрейны писАть, чтобы синтезатор знал, как тактировать триггеры…
У автора же описан обычный синхронный счётчик, т.е. все биты clk_cnt затактированы сигналом clk. А к выходу регистра подключена асинхронная логика, вычисляющая "+1", и подающая на его же вход. А дальше — цифровой компаратор. На мой взгляд, оптимальнее было бы поставить компаратор на строгое равенство: он проще, меньше и быстрее, а значения счётчик всё равно перебирает последовательно.
Еще оптимальность зависит от особенностей FPGA
Пример 1:
Есть такое понятие как Unique Controlling Set. Обычно это набор сигналов Set/Reset/Clock. Этот набор заходит в логический блок и все триггеры внутри него управляются этим уникальным набором и никаким другим. То есть логика @(posedge CLK) и логика @(posedge CKL or negedge nRST) обречены располагаться в разных блоках. Один несчастный регистр с уникальным набором сожрет целую ячейку со всем ее фаршем. Количество уникальных наборов прямо влияет на оптимальность размещения и утилизацию. На больших проектах оптимизация управляющих наборов дает весьма заметные результаты.
Пример 2.
ЛОгические генераторы в FPGA Xilinx имеют 6 входов. Соотвественно логика A = C1 | C2 & C3 & C4 | C5 & C6 — займет один логический генератор, а когда туда добавляется C7 — скорее всего три генератора и два уровня логики. А логика с двумя условиями будет иметь ту же утилизацию, что и с 6ю. Понимая это можно оптимизировать код. Например можно ориентироваться где выткать регистры. То есть если Вы ушли за пределы одного логического генератора и Вас не жмет latency — имеет смысл отбиться регистром. И наоборот — выткать регистры между кусками логики менее чем с 6ю условиями — бесполезное увеличение latency и поедание ресурсов.
Пример 3.
Блочная память. Количество элементов блочной памяти обычно ограничено как по количеству так и по расположению в ПЛИС. Если бездумно жрать её не обращая внимания на размерность блоков и их особенности — закончиться она очень быстро и размещаться будет очень не оптимально.
Пример 4
***
сотни их. Мораль в том что надо читать даташиты на ПЛИСы.
Чтобы ПЛИС поменьше жрала — нужно:
1. Все что имеет входы EN — держать под EN только когда надо.
2. Писать логику так, чтобы регистры не переключались просто так, то есть чтобы все имели какой-то «if». Так как потребление в основном обусловленно тем — каким током и как часто внутренние блочки заряжают друг другу входную емкость в момент смены своих состояний. Ну и от SLEW_RATE настроек выходных каскадов — смысл тот же, просто емкость снаружи по отношению к ПЛИС.
Вы можете посмотреть реальное количество потребленных слайсов, лутов, памяти и DSP блоков после синтеза и разводки дизайна.
Например bcd_to_7seg синтезатор наверняка зафигачит, как look-up-table, которую вы можете получить и с помощью LUT и используя block ram. При этом в исходном коде я бы тоже написал тупо таблицу, а не AND/OR.
Полностью аппаратный — это когда на вход температура и конфиг на бутстрапах или флэшке.
Готовый чип с таким функционалом называется Hardware Monitor, стоит 6 баксов и стоит в любой материнской плате. Они конечно все подруливаются программно, но многие имеют небольшую энергонезависимую память внутри (точнее некоторые регистры бывают non-volatile), либо как вариант имеют куски, запитанные от VBAT, и будучи один раз настроены могут в дальнейшем работать полностью автономно. Как правило имеют в ассортименте 2-3 стратегии управления фанами и настойку зонирования.
То что вы описали, иногда гуглю в надежде что, что-то появилось. Готового и адекватного по цене — не вижу пока, всё равно тот же stm32f030p4 (~$0.3 TSSOP-20)- на вскидку там если часть каналов управления программно делать, то 5-6 каналов таких получится. 1 ADC -> 1 PWM, +UART/i2c
ps был когда то трёхногий чип в то-92 с шим выходом и сам термометром на линейку фиксированных температур с шагом в 5С и с шириной _плавной_ регулировки (а не ON/OFF которых полно) в 5С, но я даже сейчас не могу его название найти, что это было
Управление семисегментным дисплеем с помощью ПЛИС