FPGA. Просто о сложном — Создание проекта в Quartus II. Сравнение VHDL и Verilog

Самыми популярными языками описания цифровой аппаратуры являются VHDL и Verilog. В этой статье я постараюсь сравнить синтаксис 2-х этих языков на примере «бегущего огонька», архивы проектов будут прикреплены в конце статьи. Для полного понимания описываемых процессов настоятельно рекомендую ознакомиться с предыдущими статьями цикла: 

  • Внутреннее устройство ПЛИС (FPGA)
  • Философия написания конфигураций для ПЛИС
  • Рассмотрим структуру создаваемого модуля «бегущего огонька», который назовем leds_case. В модуле будет один вход для тактового сигнала clk, и четыре выхода (4-хбитная шина) для светодиодов.

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

    Чтобы не быть голословным, реализуем данный модуль на отладочной плате от ALTERA с CPLD семейства MAX II. 

    Плата прошивается по JTAG программатором USB BLASTER.

    Т.к. на самой отладочной плате нет светодиодов, то я нашел у себя старую плату, на которой было 4 светодиода включенных по схеме на рисунке ниже.

    Итак, теперь создадим новый проект в среде Quartus II, которую можно скачать на официальном сайте Altera. Запускаем среду, для создания нового проекта кликаем на New Project Wizard (на картинке обведено красным).

    В этом окне среда нам сообщает какие операции нужно совершить для создания проекта. Пропускаем.

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

    Далее выбираем Empty project, тем самым подтверждаем создание абсолютно чистого проекта.

    В следующем диалоговом окне нам предлагают подключить файлы проекта, но так-как нам нечего подключать, то пропустим этот шаг.

    В этом диалоговом окне выбираем микросхему, которую мы будем программировать. Выбираем параметры соответствующие микросхеме на нашей плате: семейство MAX II корпус TQFP и количество ножек 100. Немного остановимся на параметре Core Speed grade — это параметр характеризующий время задержки прохождения сигнала между внутренними соединениями в ПЛИС. Проект созданный для ПЛИС со speed grade 5 без проблем заработает на ПЛИС со speed grade 10, но проект созданный для ПЛИС со speed grade 10 не будет адекватно работать, если вообще разведется, на ПЛИС со speed grade 5. Как определить speed grade? Очень просто: в названии микросхемы EPM240T100C5 последняя цифра 5 и есть значение speed grade.

    В этом окне среда предлагает нам указать на средства симуляции, в которых мы бы хотели отлаживать код, но т.к. код будет простым, то пропустим этот шаг. Средства симуляции разберем в другой статье. 

    В этом диалоговом окне среда показывает нам суммарные сведения о выбранных нами настройках.

    Для начала напишем модуль на VHDL. Cоздадим VHDL файл. Выберем File -> New

    В появившемся окне выбираем VHDL file.

    Теперь напишем код и разберем его.

    — Подключение стандартных библиотек на математику и типы данных.
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.std_logic_ARITH.all;
    use ieee.numeric_std.all;
    use ieee.std_logic_unsigned.all;
    —————————————————————
    — В entity указываются порты ввода и вывода. В начале статьи
    — мы выяснили что будет один вход для тактовой частоты и четыре
    — выхода для светодиодов.
    —————————————————————
    entity led_case is
    port
    (
    clk : in std_logic; — тип std_logic указывает на то, что сигнал будет представлен как «провод»
    leds : out std_logic_vector(3 downto 0) — тип std_logic_vector указывает на то, что перед нами шина данных
    ); — (3 downto 0) указывает, что в шине leds четыре сигнала
    end led_case;

    architecture led of led_case is — в architecture под названием led описываются все процессы происходящие в модуле, который
    — связан с другими файлами в проекте через entity led_case

    signal count : std_logic_vector(21 downto 0) := (others => ‘0’); — объявляем счетный регистр count с начальным значением 0
    signal slct : std_logic_vector(1 downto 0) := (others => ‘0’); —объявляем регистр выбора светодиода с начальным значением 0

    begin — начало описания процессов

    process(clk) — первый процесс синхронизированный по clk
    begin

    if (rising_edge(clk)) then — процесс выполняется по нарастающему фронту тактирования

    count <= count + ‘1’; — с каждым тактом значение счетчика увеличивается на единицу

    if (count = b»11_1111_1111_1111_1111_1111″) then — при переполнении счетчика (b»<значение>»- двоичная запись числа)
    slct <= slct + ‘1’; — изменяется значение регистра slct, который отвечает за то, какой светодиод зажечь
    end if;

    end if;

    end process;

    process(clk)
    begin

    if (rising_edge(clk)) then

    case (slct) is — функция CASE в VHDL выполняет ту же роль что и в С/С++

    when b»00″ => leds <= b»0001″; — Если значение регистра slct «00», то зажигаем первый светодиод
    when b»01″ => leds <= b»0010″; — Если значение регистра slct «01», то зажигаем второй светодиод
    when b»10″ => leds <= b»0100″; — Если значение регистра slct «10», то зажигаем третий светодиод
    when b»11″ => leds <= b»1000″; — Если значение регистра slct «11», то зажигаем четвертый светодиод

    when others => leds <= b»0000″; — В любых других случаях выключаем все светодиоды

    end case;

    end if;

    end process;

    end led;

    ————————————————————————————————————————————————————————————————

    Теперь напишем код выполняющий ту же самую функцию но на Verilog, для этого создадим новый проект, но новый модуль создадим как Verilog file

     

    // Как видите, никаких библиотек на математику и типы данных мы не подключаем 

    module led_case // то же самое, что и entity, здесь мы объявляем порты, через которые данный модуль может быть связан с другими
    ( // файлами в проекте
    input clk, // input — обозначение что сигнал clk вход
    output[3:0] out // output[3:0] — обозначение, что сигнал out это шина из 4-х сигналов
    );
    reg[3:0] leds = 4’b0; // создание регистра, куда будет записываться значение выходной шины для светодиодов
    // (4’b — запись 4-хбитного числа в двоичном виде)
    reg[21:0] count = 22’b0; // объявляем счетный регистр count
    reg[1:0] select = 2’b0; // объявляем регистр выбора светодиода

    always @ (posedge clk) // объявление первого процесса, который выполняется по нарастающему фронту clk
    begin

    count <= count + 1’b1; // с каждым тактом значение счетчика увеличивается на единицу

    if (count == 22’b11_1111_1111_1111_1111_1111) // при переполнении счетчика
    begin
    select <= select + 1’b1; // изменяется значение регистра select, который отвечает за то, какой светодиод зажечь
    end

    end

    always @ (posedge clk) // объявление второго процесса, который выполняется по нарастающему фронту clk
    begin

    case(select) // функция CASE выполняет ту же роль что и в С/С++
    2’b00: leds <= 4’b0001; // Если значение регистра select «00», то зажигаем первый светодиод
    2’b01: leds <= 4’b0010; // Если значение регистра select «01», то зажигаем второй светодиод
    2’b10: leds <= 4’b0100; // Если значение регистра select «10», то зажигаем третий светодиод
    2’b11: leds <= 4’b1000; // Если значение регистра select «11», то зажигаем четвертый светодиод

    default: leds <= 4’b0000; // В любых других случаях выключаем все светодиоды

    endcase

    end

    assign out = leds; // асинхронно передаем значение регистра leds на выходную шину out

    endmodule

    ———————————————————————————————————————————————————————————————

    Как Вы можете убедится оба языка очень похожи и мнение о том, что синтаксис Verilog подобен высокоуровневому языку С сильно преувеличено. Как я и говорил ранее, выбор на чем писать сугубо личный и основан исключительно на популярности языка, так что о том что для читателя является достоинством, а что недостатком я доверю решать самому читателю. А вообще, никто не мешает Вам выучить и Verilog и VHDL. В одном проекте допускается то, что один модуль может быть написан на Verilog, а другой на VHDL. Хочется ещё сказать пару слов о переносимости проектов на разные ПЛИС: если Вы не используете специфические ресурсы ПЛИС, такие как аппаратные умножители, множители частоты и т.д., то перенести проект на другую ПЛИС не составит труда. К примеру наш проект не использует ничего кроме таблиц соответствия и триггеров, и следовательно его можно перенести не лишь на ПЛИС из другого семейства, но и на ПЛИС другой фирмы!

    Раз у нас уже есть прошивка, то самое время научиться прошивать плату и посмотреть на результаты своих трудов, но перед этим давайте сначала синтезируем проект. Для этого кликаем на значок вверху экрана. Должен предупредить сразу, что синтез проекта для ПЛИС требует ресурсов компьютера и занимает долго времени, по сравнению с микроконтроллерами.

    После того как синтез проекта выполнится успешно, настало время присвоить портам из модуля реальные пины ПЛИС. Для этого кликнем на значок Pin Planning вверху экрана.

    Перед нами откроется изображение нашей микросхемы. Мы видим на какие ножки мы можем «повесить» наши сигналы, но перед тем как это сделать расскажу Вам, что есть три типа пинов: обычные пины входа/выхода, на них можно заводить переферию (у ПЛИС есть несколько банков, куда входят группы пинов), пины тактирования, на них заводится тактовая частота, а  еще есть пины сброса (reset)  на которые заводится сигнал сброса. У меня на плате нет кнопки reset’а, поэтому эти пины трогать не будем. На PIN_14 нужно завести сигнал clk, чтобы затактировать банк с пинами номер 1. PIN_2, PIN_3, PIN_4, PIN_5 входят в банк пинов номер 1, и следовательно на них «повесим» выходную шину управления светодиодами. После того, как Вы назначили все требуемые пины, просто закройте окно Pin Planner’а, все результаты сохранятся.

    После того как мы все правильно присвоили, сделаем синтез и имплементацию проекта нажав на соответствующую иконку вверху экрана. 

    После успешной сборки проекта откроем утилиту Programmer в верней части экрана, в которой можно прошить нашу ПЛИС.

     

    В появившемся окне Programmera нажмите Hardware Setup, если Ваш программатор не определился автоматически. Драйвера на программатор должны установиться автоматически, но если по каким-то причинам этого не произошло, то их можно найти в папке с установленной средой. Нажмите Add File, чтобы загрузить сгенерированный средой файл прошивки. 

    Файл прошивки можно найти в папке output_files вашего проекта. Выбираем его.

    Далее появится вот такое окошко. Внизу мы можем увидеть, что ПЛИС выбрана правильно. Чтобы запрограммировать нашу ПЛИС ставим галочки Program/Configure и Verify и жмем Start. Если все сделано правильно, то статус-бар Progress станет зеленым и будет отображать 100%.

    Добавлю видео работы прошивки, чтобы Вы убедились что все написанное правда, а так же два варианта прошивки: на Verilog и на VHDL. Спасибо за внимание.


    Прикрепленные файлы:

    1 comment on “FPGA. Просто о сложном — Создание проекта в Quartus II. Сравнение VHDL и Verilog

    1. Впервые встретил объяснение для новичков, а то другие сайты соревнуются кто умнее,
      СПАСИБО

    Добавить комментарий

    Ваш адрес email не будет опубликован.