3 июня 2011 г.

VHDL - начинающим от начавшего.

Начну, наверно, с того зачем все-таки нужны ПЛИСы. Сам я поначалу недооценивал всей их мощи. Однако, времена меняются, и я спешу поделиться с вами, что к чему.
Для меня знакомство с ПЛИСами началось на 3-м курсе. К этому моменту я хорошо представлял, что есть микроконтроллеры и понимал кое-что из аналоговой техники. Лекции вел странноватый мужик (почти дед, но еще нет), хорошо шарящий электронику, но неспособный объяснить элементарщину. К моему сожалению, он же у нас стал вести лабораторные работы по ПЛИСам. На его усмотрение был выбран язык Verilog. А институт закупил демо-платы на Spartan-3A. Кое-как сдавая лабораторки, я начинал понимать, что ПЛИСы это не мое. Сдав последнюю лабораторную, я решил, что ПЛИСами я заниматься не буду.
И все бы хорошо.
Но вот мне и 2 моим друзьям один из преподов посоветовал сделать некий шифрующий прибор. Мы взялись за это. Интересно было разобраться во всем этом. За семестр, с горем пополам, в Proteus был готов прототип, построенный на PIC18F4550. Еще через год мы сварганили вот эту дурынду.
Сам PIC стоит на обратной стороне. Штука шифрующая. И в этой стране для ширования православно применять наш симметричный алгоритм шифрования ГОСТ, номер которого я так и не запомнил, и ищу его в википедии по запросу "ГОСТ ширование". В ходе эксперимента с реальным железом было выяснено, что для корректной (то бишь своевременной) работы на USB full speed PIC может выполнить только 2 цикла шифрования из 32 требуемых. А ведь хочется и high speed потом. А с такими требованиями к отклику и 200 МГц не справятся.
И тут мое подсознание сказало что-то типа:"Чувау! Вспомни про ПЛИСы! Ведь это же какая-то магия!" В итоге я понял, что ПЛИС сможет выполнить зашифрование данных практически мгновенно (или за 1 такт, если делать систему синхронной). Тут же я вспомнил, что знакомство с Verilog, Xilinx ISE и Spartan-3A никаких положительных эмоций для меня не оставило. Поэтому мной был выбран набор от Altera. Писать решил на VHDL. Кстати в оправдание Verilog скажу, что мои коллеги, работающие в МЦСТ (тот самый разработчик ламповых православных процессоров), пишут код процессора как раз на Verilog'е.
Нашел несколько учебников по VHDL. Но самый удачный из них оказался Бибило "Основы языка VHDL". Я не буду пересказывать содержимое учебника. Моей целью будет рассказать некие нюансы, облегчающие работу с кодингом ПЛИСов.
На данный момент читатель должен представлять основные операторы VHDL и его синтаксис.
Теперь перейдем к примерам. Примеры хорошо берутся с VHDL by example. Пройдя до середины этих уроков обязательно должно сложиться представление, что VHDL не язык программирования, а язык описания аппаратуры. На самом деле, у него есть несинтезируемое подмножество (то, которое не будет влиять на результирующую схему, обычно оно используется для отладки). Циклы в нем - не циклы, и оператор, скажем, while обозначает, что будет несколько раз повторяться один и тот же блок.
Сложно рассказать про VHDL все и сразу. Да я и не собираюсь. Лишь покажу, что нужно поставить, чтобы все работало более-менее.
Итак, работаем с  Quartus. Какую версию поставить? Конечно, самую последнюю. В этом есть доля правды. Я себе поставил Quartus ver. 9.0. А все из-за того, что я надеялся на то, что ModelSim (среда, которая позволяет проверять правильность построения схемы) будет интегрирована в сам Quartus. В более поздних версиях ModelSim действительно убрали из коробки с Quartus. ModelSim поставлен версии 6.4a. По идее я до сих пор верю, что этих двоих можно как-то подружить. Однако, пока что расскажу, как я делал.
Моей целью было запрогать алгоритм шифрования ГОСТ. Сразу отмечу, что сейчас я представлю ядро шифрования. Потом довешу всяких триггеров, и всяких входных/выходных пинов станет меньше.
 При создании нового проекта Quartus предложит выбрать модель кристалла. На начальном этапе это многих смущает. И даже на electronix.ru порой спрашивают, какой выбрать. Отвечаю: в начале надо выбрать самый мощный, самый лучший, самый красивый, самый многоногий. Когда напишете свой код, можно будет подбирать необходимый камень. Учтите только, что для нормальной быстрой работы кристалла (с хорошими откликами и малыми задержками) нужно побольше незаполненного места на нем в итоге(я имею в виду тот процент, что появляется в результате компиляции, и который называется total logic elements).
Если шифровальщик представлять как черный ящик, то он будет выглядеть так.
На входе ключ и шифруемый блок. На выходе - зашифрованный блок. Подробнее о самом алгоритме можно прочитать на Википедии. Внутри этого ящика находится сеть Фейстеля. В нашем случае в схеме будет 32 соединенных друг с другом элементов, незамысловато названных мной cycle.
А внутри cycle уже совсем элементарщина. 

 
Здесь (на картинке слева направо):
  • 32-битный полусумматор
  • S-блок, задача которого переставлять биты в соответствии с таблицей замен, заданной как константа
  • блок циклического сдвига
  • 32-битный побитовый xor
Как лучше организовать проект?
На первых порах лучше делать каждый элемент в отдельном файле. Вот окошко со всеми файлами проекта.
Где брать стандартные блоки, функции и т.д.?
А нигде не берите. Если начали прогать, то запрогайте элементарщину. Напрягите мозг. Подумайте, как там все работает. Но в то же время не надо перестараться. Так я блок сложения(32-битный полусумматор) сделал с помощью generate. Хотя надо было написать всего-то
result <= summand1 + summand2;
 В принципе с горем пополам можно написать, что надо, и чтобы работало.
Допустим, что у вас готов код, который компилится, и в RTL-viewer'e блок-схема отображается правдоподобно. Теперь надо сделать симуляцию. Для этого нам нужно сделать еще один vhdl-файлик, в котором будет описана обертка вокруг спроектированной схемы. Обычно его называют ИмяБлокаTB (TB = test bench). В случае ГОСТа test bench я вам покажу.

library IEEE;
use IEEE.std_logic_1164.all;

entity GOSTtb is
    port (data_out : out std_logic_vector(63 downto 0));
end GOSTtb;

architecture behtb of GOSTtb is 
component GOST
    port (data_in : in std_logic_vector(63 downto 0);
    key : in std_logic_vector(255 downto 0);
    data_out : out std_logic_vector(63 downto 0)); 
end component;
signal key0 : std_logic_vector(255 downto 0);
signal data_in : std_logic_vector(63 downto 0);

begin 
    key0 <=          X"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
    data_in <= X"BBBBBBBBBBBBBBBB";

dut:GOST
    port map( data_in(63 downto 0) => data_in(63 downto 0),
    key(255 downto 0) => key0(255 downto 0),
    data_out(63 downto 0) => data_out(63 downto 0));
end behtb;

Мы создали сигналы key0 и data_in, присвоили им значения и присоединили с помощью port map к разработанному устройству.
Хочу заметить, что нумерация всех векторов идет задом наперед. Пока что я не понял глубокого смысла, почему именно в эту сторону читаются биты, а не в другую. Однако ModelSim будет грамотно отображать присвоенные и полученные значения, если сигналы объявлены именно так.
Теперь у нас есть проект. Запускаем ModelSim. Порядок действий:
  1. File->New->Library: тут пишем имя, которое нам нравится
  2. Compile->Compile: Выбираем все .vhd файлы созданного в quartus проекта. Не забываем указать библиотеку, созданную в пункте первом.
  3. Дважды кликаем в библиотеке на test bench.
  4. Появится окно, что-то вроде такого. 
    5. На gosttb правой кнопкой.
    6. Add->To Wave->All items in region 
    7. В консоли внизу пишем run
Сверяем полученный результат с ожидаемым. При необходимости test bench создается на каждый блок и проверяется его функциональность в отдельности.
Наверно, пока что все. Я не претендую на то, что это самый правильный способ написания и отладки. И уж точно не претендую  на то, что этот способ самый удобный. Однако, он работает.
Всем удачи в освоении ПЛИСов. В следующем посте попробую написать что-нибудь про ARMы. 

2 комментария:

  1. Интересно написано! Не забрасывайте это дело, у Вас хорошо получается :)

    ОтветитьУдалить
  2. а сам архив проэкта можно получить где-то?

    ОтветитьУдалить