Junior FPGA Design Engineer: как стать?

Всем привет!

Иногда начинающие разработчики не очень хорошо представляют, какую литературу надо читать для серьезного изучения того или иного языка.

Разработка под FPGA — это не просто какой-то язык. Это очень объемная область, с огромным количеством подводных камней и нюансов.

В этой статье вы найдете:

  • список тем, которые должен освоить начинающий разработчик под FPGA
  • рекомендуемую литературу по каждой из тем
  • набор тестовых вопросов и лабораторных работ
  • классические ошибки новичков (и советы по исправлению)

Что надо знать и уметь

Цифровая схемотехника

Необходимо:

  • знать базовые цифровые узлы (логические элементы И/ИЛИ/НЕ, шифраторы, мультиплексоры, суммматоры и пр.)

Литература:

  • David Harris, Sarah Harris. «Digital Design and Computer Architecture» — очень большая книга, рассказывающия от азовов до верхов. Есть версия на русском языке. Я просмотрел русскую версию: читается очень быстро и легко.
  • Угрюмов Е.П. «Цифровая схемотехника» — классический советский учебник, со всеми вытекающими последствиями (некоторые темы объяснены слишком сложно, и нельзя сразу понять нужна ли тебе эта информация сейчас или можно её пропустить). Я читал более старое издание, возможно в издании от 2010 года всё изменилось в лучшую сторону, не смотрел.

Тестовые вопросы:

  1. Чем цифровая схемотехника отличается от аналоговой?
  2. Какие есть базовые цифровые узлы? В каких из них выход зависит только от входа?
  3. Что такое мультиплексор? Нарисуйте схему мультиплексора 4 в 1 из примитивных элементов И/ИЛИ/НЕ.
  4. Постройте таблицу истинности для выражения: X = A or ( B and C ) or D.

Синтаксис HDL-языка

Сюда входит:

  • знание синтезируемых конструкций (синтаксиса) HDL-языка
  • знание, как описывать базовые цифровые узлы с помощью HDL-языка
  • понимание во что (со стороны базовых цифровых узлов) превращается тот или иной кусок HDL-кода
  • умение писать на HDL-языке для получения нужного поведения

В качестве HDL-языка я рекомендую сначала изучить самые базовые конструкции Verilog‘a, а затем переключится на SystemVerilog.

Литература:

  • Pong P. Chu. «FPGA prototyping by Verilog examples» — расписывается Verilog, начиная с азов. Подробно разбирается синтаксис и есть огромное количество примеров, как простых (счетчики), так и уровнем повыше (UART и VGA).
  • Иосиф Каршенбойм. «Краткий курс HDL» — классический курс на русском языке.
  • http://www.asic-world.com/ — сайт с кучей примеров как по Verilog, так и по SystemVerilog.
  • David Harris, Sarah Harris. «Digital Design and Computer Architecture» (см. выше)
  • Stuart Sutherland. «SystemVerilog for Design» — книга про различия Verilog и SystemVerilog. Для чтения необходимы базовые знания Verilog’a. Рекомендуется к прочтению для понимания, какие удобства были внесены в новом стандарте.

Тестовые вопросы:

  1. Чем блокирующие присваивание отличается от неблокирующего? Когда стоит применять одно, когда другое?
  2. Есть ли разница между следующими тремя описаниями? Если да, то в чём она проявляется?
    // code 1:
    assign a = b + c;
    
    // code 2:
    always @( b or c )
        begin
            a = b + c;
        end
    
    // code 3:
    always @( * )
        begin
            a = b + c;
        end
    

Тестовые задания:
1. Нарисуйте схему из базовых цифровых узлов для следующего кода:

module test(
  input       clk_i,

  input       a_i,
  input [2:0] b_i,

  output reg  x_o
);

reg [7:0] cnt = 8'd0;
reg [7:0] cnt2;

wire c;
reg d;

always @( posedge clk_i )
    cnt <= cnt + 1'd1;

always @(*)
    begin
        cnt2 = cnt + 1'd1;
    end

assign c = ( cnt < 8'd5 ) && ( a_i == 1'b0 );

always @( posedge clk_i )
    begin
      d   <= c;
      x_o <= c ? ( d ) : ( cnt2[ b_i ] );
    end

endmodule

2. Нарисуйте поведение схемы из п.1 (т.е. состояния всех «переменных») при следующих входных воздействиях:

Времянки нарисованы с помощью онлайн-редактора WaveDrom.

3. Напишите модуль для управления светофором, который будет зажигать красный, желтый и зеленый фонари во всем известной последовательности: красный, красный и желтый, зеленый, зеленый моргает, желтый, красный. Параметры, задающие время горения фонарей светофора и период мигания зеленого фонаря являются параметрами модуля. Время задается в количестве тактов синхросигнала clk_i.

Интерфейс модуля:

module traffic_light(
  // cинхроимпульс
  input clk_i,

  // асинхронный сброс
  input rst_i,

  // если 1, то горит соответствующий цвет, если 0 — то он не горит
  output red_o,
  output yellow_o,
  output green_o
);

Симулирование и верификация HDL-кода

Необходимо:

  • знать несинтезируемые конструкции Verilog’a и SystemVerilog’a
  • уметь написать простой тестбенч, запустить его в симуляторе (например, ModelSim)
  • понимать, как должен быть устроен «идеальный» тестбенч

Литература:

  • http://testbench.in/ — огромное количество примеров верификации с использованием Verilog’a и SystemVerilog’a.
  • Chris Spear. «SystemVerilog for Verification» — хорошая, большая книга о верификации с помощью SystemVerilog. Читается легко, можно найти ответы на многие вопросы.

Видеоуроки:

Тестовые вопросы:

  1. Чем function отличается от task?
  2. Представим, что Вы написали максимально простую HDL-модель 5-стадийного RISC-процессора. Как будете её верифицировать? (Вопрос повышенной сложности).
  3. Чем различается queue от mailbox (типы данных в языке SystemVerilog)?
  4. Чем отличается функциональная симуляция от временной? Когда какую необходимо использовать?

FPGA

Необходимо:

  • знать из каких базовых элементов состоит FPGA
  • понимать как происходит workflow разработки под FPGA
  • интуитивно представлять какие операции для FPGA дешевые, а какие дорогие (по частоте и ресурсам)

Я работаю с чипами Altera, поэтому здесь и дальше название семейств и утилит будет от этого вендора. Если вы знаете аналогичную литературу для Xilinx — напишите её в комментариях.

Литература:

Видеоуроки:

Тестовые вопросы:

  1. Чем отличается FPGA от ASIC? Из каких блоков состоит (или может состоять) FPGA?
  2. Попробуйте очертить круг задач, для которых хорошо (экономически целесообразно) использовать FPGA, а для каких MCU и CPU?
  3. Какие аппаратные блоки вы знаете? Для чего они используются? (Под аппаратными блоками здесь имеется в виду Hard IP).
  4. В семействе Y используется LUT с тремя входами и одним выходом. Какое минимальное количество LUT’ов надо для вычисления assign eq = ( a == b );, если a и b это 32-битные целые положительные числа? А если у LUT’a будет четыре (пять, шесть) входов?
  5. Необходимо создать одну-портовую память из 16 слов. Каждое слово шириной 100 бит. Сколько блоков M9K (9216 бит) будет занято? Считаем, что делаем проект под Cyclone III. (*)

В вопросах, обозначенных (*), разумеется, не надо помнить всё наизусть, а можно пользоваться даташитами.

Синхронный дизайн и всё, что связано с таймингами

Необходимо:

  • знать принцип синхронного дизайна
  • знать к каким отрицательным последствиям могут привести те или иные схемы
  • иметь понятие о констрейнах

Литература:

Тестовые вопросы:

  1. Что такое timing constraints (констрейны)? Где они описываются и для чего нужны (для чего они используются)? Что будет, если их не описать?
  2. Что такое clock domain crossing? Как и когда надо его осуществлять?
  3. В чем разница между синхронным и асинхронным сбросом? Что будет если на вход синхронного сброса завести асинхронный сброс?
  4. Что такое latch (защелка, латч)? Какие последствия использования латча? Приведите пример кода, который создает латч.
  5. Что такое комбинационная петля? Какие последствия использования комбинационной петли?
  6. Что такое метастабильность? Как её достичь? Какие у неё есть плюсы и минусы?
  7. Что такое glitch (глитч)? Нужно ли с этим бороться? И если да, то где и как?
  8. Что такое setup time/hold time у D-триггера?

САПР

Необходимо:

  • уметь создавать проект
  • уметь описывать I/O пины и констрейны (хотя бы для простых ситуаций, без сложных I/O интерфейсов)
  • знать какие есть отчеты о сборке, какая информация содержится в каждом из них
  • уметь пользоваться инструментом для отладки на железе
  • уметь пользоваться инструментом для анализа таймингов (STA)
  • знать какие готовые IP-ядра/модули (FIFO, RAM, FFT, DDR, Ethernet и т.д.) предоставляет вендор и как их можно добавить в проект

Литература:

Видеоуроки:

Тестовые вопросы:

  1. Какие этапы сборки происходят от нажатия на кнопку «Собери проект полностью» до получения готового бинарного файла? Что происходит на каждом из этапов?
  2. Как посмотреть удалось ли САПР’у уложить проект в заданные ограничения (констрейны)?

Лекции и лабораторные

Я два семестра читал курс «Разработка под FPGA» для студентов старших курсов университетов Санкт-Петербурга. В курс входили как лекции, так и набор лабораторных работ. Лекции основывались на литературе, которую была перечислена выше.

План курса:
Введение:

  • Что такое ПЛИС? Области применения.
  • Обзор САПР ( Quartus ).

Изучение языка Verilog:

  • Отличительне черты языков описания аппаратуры ( HDL ).
  • Синтезируемые/несинтезируемые конструкции языка.
  • Типы данных и способы их представления.
  • Операции, блокирующие/неблокирующие операции присваивания
  • Управляющие конструкции.
  • Блоки описания узлов комбинационного типа.
  • Блоки описания узлов последовательного типа.
  • Структурное/поведенческое описание проекта.
  • Параметризация.
  • Реализация на Verilog базовых цифровых узлов.

Изучение несинтезируемых конструкций языка ( +SystemVerilog ):

  • Применение несинтезируемых конструкций языка. Верификация. Testbench. Основные принципы создания testbench.
  • Основные функциональные блоки testbench’ей.
  • Типы данных. Блоки процедурного типа.
  • Структуры данных для верификации ( массивы, очереди и т.д. ).
  • Функции и tasks.
  • Временная модель симуляции.
  • Использование базовых принципов ООП для верификации.
  • SystemVerilog Assertions.
  • Создание testbench для базовых цифровых узлов.
  • Обзор cуществующих методологий ( библиотек ) верификации.

Названия лекций (в 2015 году):

  1. Введение в FPGA.
  2. Внутреннее устройство FPGA.
  3. Введение в Verilog/SystemVerilog. Примеры описания различных типов логики.
  4. Синхронный дизайн. Создание простых тестбенчей.
  5. Описание FSM, массивов и структур в SystemVerilog. Память: создание с помощью Verilog и MegaWizard.
  6. Как работает DCFIFO. Static Timing Analysis. TimeQuest, constraints.
  7. Верификация: coverage, assertions, SystemVerilog interfaces
  8. Интерфейсы семейства Avalon. IP-Cores. Qsys.
  9. Верификация: SystemVerilog OOP, constrained-random tests.

Слайды к лекциям

К сожалению, это именно СЛАЙДЫ, которые мне помогали рассказывать лекции (не вся информация курса содержится на слайдах, некоторые я использовал как опору, а материал давался на доске).

Иногда будут видны картинки, которые никак не связаны с соседними (например, задания для тестов, которые давались на лекциях).

Лабораторные работы:

Классические ошибки

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

Путаница в присваиваниях (блокирующие и неблокирующие)

Симптомы:

  • вы не очень уверено ответили на вопрос о блокирующих и неблокирующих присваиваниях (см. выше)
  • вы за собой замечаете, что в случайном порядке меняете «=» на «<=» (и наоборот), надеясь, что заработает
  • симулятор показывает странные вещи, вы начинаете сомневаться, что понимаете как работает D-триггер
  • результаты симуляции стабильно не совпадают с тем, что происходит на железе (где-то что-то плывет на такт)

Лечение:

  • разобраться в материале по Verilog (см. литературу выше)
  • если вы хотите, чтобы результат симуляции совпадал с тем, что будет синтезировано и воплощено на железе, то запомните простое правило: в блоках, где описывается комбинационная логика (always_comb, always @(*)) вы обязаны использовать только блокирующие присваивания (=). В блоках, которые описывают триггеры (always_ff, always @( posedge clk .. )) вы обязаны использовать только неблокирующие присваивания (<=).

Проблема в таймингах

Симптомы:

  • результаты симуляции не совпадают с тем, что происходит на железе
  • железо работает нестабильно: иногда явно видны помехи (например, на VGA)
  • «я добавил сигналтап, и после этого схема перестала корректно работать, я убрал сигналтап и всё хорошо»

Лечение:

  • прописать все необходимые констрейны, (как минимум используемую тактовую частоту (или частоты) в *.sdc файле), подключить этот файл в проект
  • перекомпилировать проект. Зайти в TimeQuest и посмотреть, есть ли отрицательные слаки, и если есть, то дальше разбираться почему это происходи (возможно, достаточно покрутить настройки в Quartus’e, или придется переписывать куски код).

Если вы видите странности в SignalTap, то перепроверьте, синхронны ли те сигналы, которые вы снимаете с частотой «стробирования».

Не соблюдение принципов синхронного дизайна (асинхронщина)

Продолжение первого пункта, но я решил его выделить отдельно.

Симптомы аналогичные с предыдущим пунктом.

Почему-то многие любят делать вот так:

// BAD EXAMPLE
...
input clk_i,
...

logic [7:0] sec_cnt;
logic [7:0] min_cnt;

logic last_sec_value;

assign last_sec_value = ( sec_cnt == 8'd59 );

always_ff @( posedge clk_i )
    if( last_sec_value )
        sec_cnt <= 'd0;
    else
        sec_cnt <= sec_cnt + 1'd1;

always_ff @( posedge last_sec_value )
    min_cnt <= min_cnt + 1'd1;

Т.е. в качестве входного сигнала на триггере min_cnt используется другой сигнал, чем синхроимпульс clk_i. Он формируется комбинационной логикой (выходом компаратора).

Или вот так:

// BAD EXAMPLE
...
input clk_a_i,
input clk_b_i,
...

logic [7:0] cnt_a;
logic [7:0] cnt_b;
logic [7:0] sum;

always_ff @( posedge clk_a_i )
    cnt_a <= cnt_a + 1'd1;

always_ff @( posedge clk_b_i )
    cnt_b <= cnt_b + 1'd1;

always_ff @( posedge clk_b_i )
    sum <= cnt_a + cnt_b;

На вход триггера sum приходит выход комбинационной логики, вход у которой питается от разных тактовых сигналов.

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

Я догадываюсь, что это всё идет из 2000х, когда чипы были маленькими и разработчики выживали как могли.
Скорее всего на маленьких частотах (типа 1 МГц) это прокатывало, но если вы собираетесь попасть в команду, которая делает серьезные вещи на топовых чипах, то за такие трюки можно легко вылететь со стажировки.

Лечение:

  • пройтись по всему проекту, выписать (на бумажку) какой тактирующий клок (сигнал) используется для каждого триггера.
  • понять как это число можно свести к минимальному количеству (в разумных пределах, разумеется), исправить код согласно правил синхронного дизайна.
  • пройтись по всему проекту и внимательно отследить как происходит clock domain crossing (т.е. переход данных со одной частоту на другую). Исправить, если он происходит некорректно.
  • выполнить все шаги из пункта «Проблема в таймингах».

Постоянная отладка на железе (игнорирование симуляции)

Вы допускаете эту ошибку, если разработка выглядит так:

  • редактирование HDL-файла
  • компиляция полного проекта
  • прошивание бинарника на плату
  • подключение с помощью SignalTap, просмотр нужных сигналов
  • понимание ошибки, переход в п.1

Почему это плохо:

  • с помощью SignalTap вы не можете посмотреть все-все-все сигналы, если у вас большой проект
  • вы отнимаете своё время, или время работодателя, при компиляции полного проекта, т.к. это может занимать значительное время. На маленьких чипах, это занимает 5-10 минут, и можно типа забить и пойти в это время покурить/попить чай/поиграть в кикер, но на больших проектах это вам выйдет боком.
  • нужна рабочая плата под рукой
  • у вас нет уверенности, что изменения в коде рабочие и не сломают что-то другое

Лечение:

  • написать тестбенч для всего проекта, либо для его частей
  • добиться корректной работы в симуляции
  • собрать проект, проверить на плате

Если что-то не заработает на железе, то:

  • пройтись по пyнктам, обозначеным выше (тайминги и асинхронщина)
  • если проблемы в таймингах нет, то пытаться понять при каких входных воздействиях это происходит
  • подать эти воздействия в симуляции, убедиться, что проблема воспроизводится
  • исправить ошибку в RTL-коде, проверить в симуляции и на железе
  • обязательно: сделать вывод, почему предыдущий вариант симуляции не смог отловить эту ошибку

Нет правил разработки (+ код с запашком)

Симптомы:

  • вы много времени тратите на чтение (разбор) кода, который написали вчера.
  • вы часто пишите однотипный код (самые популярные клавиши на вашей клавиатуре это Ctrl+C и Ctrl+V)
  • вы не можете разобраться в том коде, который написал коллега (если вы работаете вместе над одним модулем/IP-ядром), а он — в вашем.

Лечение:

  • ознакомиться с литературой, которая рассказывает как надо писать хороший код, например, Макконнелл. «Совершенный код»
  • разработать и описать правила разработки для команды. Или использовать готовые: NetFPGA, обсуждение на electronix #1, обсуждение на electronix #2, или тот, который использую я.
  • отдайте свой код на ревью более опытным разработчикам. Об этом можно попросить на форуме electronix’a в соответствующем разделе. Разумеется, желательно, что-то более серьезное, чем моргание светодиодов, иначе вас просто не поймут :).

Заключение

Надеюсь, что в этой статье я раскрыл, что надо читать и знать для вхождения в мир разработки под FPGA.

Уверен, что если Вы:

  • сможете легко отвечать на тестовые вопросы выше (без зазубривания, разумеется)
  • решите правильно лабораторные работы
  • избавитесь от «классических ошибок»
  • оформите 1-2 проекта на гитхабе и проверите их на железе. (желательно, сложнее, чем моргание светодиодиков и часики).

то без проблем сможете претендовать на позицию джуниора в серьезной компании.

Разумеется, этот путь нельзя освоить за одни выходные. Может потребоваться месяц и не один, но этот путь надо пройти, если вы хотите перейти из студенченской FPGA-разработки в профессиональную.

Спасибо за внимание!

P.S. Оригинал статьи и последняя версия доступны тут.