WebPack ISE: быстрый старт Печать
Добавил(а) microsin   

В этой главе (перевод главы 4 даташита [1]) показывается пошаговая реализация простого дизайна PLD, начиная от создания проекта, до его процесса реализации и симуляции, в среде Xilinx ISE WebPack. Пример реализует на VHDL простой счетчик, считающий вверх и вниз, и подключенный к нему 7-сегментный индикатор. Наш дизайн изначально предназначался для CoolRunner-II CPLD. В главе 5 [1] описывается процедура реализации логики на кристалле (процесс Implemention). В других главах [1] также будет показано, как преобразовать этот готовый проект для CPLD на целевой чип Spartan-3E FPGA. Предполагается, что система разработки Xilinx ISE WebPack 14.7 у Вас уже установлена (как это делается, см. [2]).

[Создание проекта]

1. Запустите Xilinx ISE Project Navigator (именно в нем разрабатываются проекты для CPLD).

start ISE WebPack Project Navigator 147

2. Для создания нового проекта выберите в меню File -> New Project. В поле "Name:" введите имя проекта. Давайте назовем проекта "Tutorial", и разместим его в папке предназначенной для Ваших проектов (предположим, это папка J:\Xilinx\Projects). При вводе имени будет автоматически создан подкаталог Tutorial, расположенный в паке проектов J:\Xilinx\Projects. В этом руководстве мы будем использовать тип дизайна HDL, поэтому в выпадающем списке "Top-level source type:" будет выбран вариант HDL (в этом случае модуль верхнего уровня может быть написан на HDL-языках VHDL или Verilog).

New Project Window Project Name fig401

Рис. 4-1. Начало диалога мастера создания нового проекта (Project Wizard - Create New Project).

В поле "Description:" можно ввести произвольное описание проекта.

3. Кликните кнопку Next. В следующем окне диалога вводятся важные параметры проекта, зависящие от используемого чипа CPLD, используемой системы синтеза и используемого симулятора. Введите следующие параметры (остальные оставьте по умолчанию):

Property Name (свойство) Value (значение)
Family (семейство микросхем логики) CoolRunner2 CPLDs
Device (используемая микросхема) XC2C256
Package (корпус микросхемы) VQ100
Speed (Speed Grade, класс скорости микросхемы) -7
Synthesis Tool (инструмент синтеза логики) XST (VHDL/Verilog)
Simulator (симулятор) ISE Simulator (VHDL/Verilog)

New Project Window Device and Design Flow fig402

Рис. 4-2. Ввод основных свойств проекта.

В качестве стандарта языка для анализатора синтаксиса (VHDL Source Analysis Standard) должно быть выбрано VHDL-93.

4. Кликните на кнопку Next, и затем на кнопку Finish. Окно мастера нового проекта закроется, и будет создан новый проект.

5. Пока в проекте нет ни одного модуля исходного кода. Давайте добавим модуль верхнего уровня на языке VHDL. Для этого выберите в меню Project -> New Source..., откроется окно для выбора типа нового добавляемого модуля исходного кода. Выберите вариант VHDL Module, и введите для него имя clock_divide.

New Source Window fig403

Рис. 4-3. Добавление нового модуля в проект.

6. Кликните кнопку Next. Откроется окно мастера создания нового модуля (New Source Wizard), где предстоит определить входы и выходы устройства, которое представляет модуль.

Мы сначала создадим модуль тактовой частоты, потому что нужно будет разделить частоту 100 кГц генератора платы (предположим, что он есть на плате) до частоты, оптимальной для переключения блока динамической индикации 7-сегментным индикатором. В принципе коэффициент деления не так важен, лишь бы в результате получилась частота переключений индикатора, чтобы мерцания не были заметны на глаз. В этом примере мы используем аппаратный делитель частоты на 16, и к нему подключим 10-битный счетчик (коэффициент деления 1024), чтобы в результате получить частоту примерно 6 Гц.

Примечание: я использовал микросхему XC2C64A, у которой нет встроенного аппаратного делителя тактовой частоты, поэтому делал счетчик/делитель на 16384 (14-битный счетчик) основе вентилей логики CPLD. Если бы использовалась микросхема XC2C256, то использование его аппаратного делителя (как показано в этом примере) позволило бы сэкономить макроячейки CPLD.

7. Итак, следующее окно диалога дает возможность задать входы и выходы создаваемого модуля. Благодаря этому автоматически будет создан шаблон кода VHDL с готовыми описаниями портов реализуемой схемы. Определите здесь 2 порта: clock_osc (in, вход счетчика/делителя) и clock_div (выход).

Port Declaration Screen clock divide fig404

Рис. 4-4. Определение входов и выходов (портов) нового модуля.

8. Кликните на кнопку Next, и просмотрите результаты создания нового модуля, затем на кнопку Finish.

Add to Project: Yes
Source Directory: J:\Xilinx\Projects\Tutorial
Source Type: VHDL Module
Source Name: clock_divide.vhd
 
Entity name: clock_divide
Architecture name: Behavioral
Port Definitions:
      clock_osc   Pin      in
      clk_div     Pin      out

9. Будет автоматически создан и добавлен в проект новый модуль clock_divide.vhd.

Source in Project Window fig405

Рис. 4-5. Новый добавленный модуль в окне дерева модулей проекта (Project Window).

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

[HDL Editor]

Двойной клик на любом файле в окне Design -> Hierarchy откроет окно редактора этого модуля. Если это модуль схемы, то откроется редактор схемы (ECS), а если это модуль на языке VHDL или Verilog, то откроется окно редактора текста исходного кода (HDL Editor).

Языковой шаблон кода. Мастер по нашим установкам (определение входа и выхода) создал готовый шаблон кода на языке VHDL. Но это еще не все, есть также отличный инструмент, помогающий Вам создать код HDL - можно добавлять готовые популярные функции, такие как счетчики, мультиплексоры, декодеры и регистры сдвига. Также имеются шаблоны для создания общих операторов (таких как оператор условия "IF/THEN" и циклы "FOR"), часто использующихся в языках программирования.

Языковые шаблоны используются как справочник. Они могут быть скопированы и вставлены (copy/paste) в модуль дизайна, и затем отредактированы так, как этого хочет пользователь. Обычно Вы должны поменять ширину шины или имена сигналов, и иногда нужно также поменять поведение кода в шаблоне. Чтобы использовать шаблон:

1. Поместите курсор HDL Editor между ключевыми словами begin и end блока Behavioral.

2. Откройте шаблоны (Language Templates) кликом на кнопке с лампочкой, которая находится на панели инструментов Project Navigator.

Project Navigator Language Templates tool button

Также можно получить доступ к шаблонам через меню Edit -> Language Templates...

3. Найдите в дереве шаблонов простой счетчик (Simple Counter): VHDL -> Device Primitive Instantiation -> CPLD -> Clock Components -> CR-II Clock Divider -> Divide by 16 -> Simple Divider (CLK_DIV16).

4. В правой части окна будет виден код выбранного шаблона. Выделите курсором мыши код счетчика от "CLK_DIV16_inst" до ");", скопируйте его и вставьте в модуль clock_divide.vhd. Также нужно поменять имена входных сигналов (см. ниже рис. 4-7).

Обратите внимание на цветовую подсветку синтаксиса кода. Зеленый цвет показывает комментарии. В этом шаблоне закомментированный текст дает подсказку о том, какие библиотеки нужны в заголовке модуля VHDL. В данном случае нужно добавить библиотеку UNISIM.vcomponents.all, для этого раскомментируйте 2 соответствующие строки в заголовке модуля clock_divide.vhd (удалите в начале строк дефисы --, обозначающие комментарий).

5. Если шаблоны Вам больше не нужны, то можно их закрыть, кликнув мышью на крестик закладки Language Templates. Закладка расположена в справа внизу, под окном редактора. Закладки - быстрый способ перемещаться по открытым окнам среди разработки ISE WebPack.

Project Navigator Language Templates tab

[Продолжаем редактирование модуля clock_divide.vhd]

1. Теперь нам нужно создать 10-битный счетчик, чтобы дополнительно поделить частоту. Откройте снова шаблоны, и найдите соответствующий шаблон по следующему пути: VHDL -> Synthesis Constructs -> Coding Examples -> Counters -> Binary -> Up Counters -> Simple Counter.

Примечание: обратите внимание, что в прошлый раз мы начинали выбор из раздела VHDL -> Device Primitive Instantiation, а второй раз из раздела VHDL -> Synthesis Constructs. Может возникнуть вопрос - почему разделы разные? Дело тут в том, что первый раздел Device Primitive Instantiation означает реализацию делителя на основе специальных аппаратных ресурсов CPLD, а Synthesis Constructs означает реализацию обычным способом, на основе синтеза логики из макроячеек.

Вы наверное заметили, что в блоке счетчика используется ключевое слово process. Оно показывает специальную конструкцию, предназначенную для обработки какого-либо события изменения сигнала. Т. е. этот блок срабатывает только в том случае, если поменялся обрабатываемый сигнал (в нашем примере модуля clock_divide.vhd будет обрабатываться сигнал clock_div_int).

2. Скопируйте и вставьте код счетчика в файл clock_divide.vhd между операторами begin и end, после ранее вставленного кода делителя.

Нам нужно сделать несколько правок в этом коде, чтобы сделать его рабочим. Первое изменение состоит в том, чтобы поменять все три ссылки "< clock >" на "clock_div_int" и удалить угловые скобки, которые были рядом с именем "count".

3. Так как мы создали 2 новых сигнала count и clock_div_int, то нам надо декларировать их. Для этого между оператором architecture и оператором begin вставьте следующие две декларации:

signal clock_div_int : std_logic;
signal count : unsigned(9 downto 0):="0000000000";

Сигнал count определен как 10-битный, и ему назначено начальное нулевое значение. Эта начальная инициализация требуется для успешной симуляции. Определение count через unsigned(9 downto 0) означает, что счетчик 10-битный. Также для того, чтобы можно было использовать типы целых чисел unsigned, нужно раскомментировать строку "use IEEE.NUMERIC_STD.ALL".

4. Мы должны подключить эти 2 сигнала к 2 портам нашего делителя частоты. Отредактируйте код следующим образом:

   CLK_DIV16_inst : CLK_DIV16
   port map (
      CLKDV => clock_div_int, -- Divided clock output
      CLKIN => clock_osc      -- Clock input
   );

5. И последнее, что нам нужно сделать - вывести наружу значение старшего бита счетчика count, чтобы счетчик работал как делитель частоты. Для этого после строки "end process;" и перед строкой "end Behavioral;" введите следующий оператор присваивания:

clock_div <= count(9);

Типовой модуль VHDL состоит деклараций библиотеки, блока определения входов/выходов модуля (entity), и блока описания логики модуля (architecture). Декларации библиотек нужны для того, чтобы сказать компилятору, какие нужны пакеты для компиляции кода.

У этого дизайна есть один вход (clock_osc) и один выход (clock_div). Реальная функциональное описание появляется после оператора begin в блоке architecture. Функция этого дизайна состоит в том, чтобы поделить сигнал clock_osc от генератора на 16 с использованием аппаратного делителя тактов, и использование его промежуточного выхода для инкремента сигнала "count", когда clock_div_int = 1, и когда произошло событие (event, т. е. изменение уровня) сигнала clock_div_int. Заданное здесь условие соответствует положительному перепаду лог. уровня (0 -> 1) сигнала clock_div_int. Область внутри блока architecture и перед началом его ключевого слова begin предназначена для деклараций переменных.

6. Сохраните созданный файл VHDL кликом на иконку дискеты на панели Project Navigator (то же самое можно сделать через меню File -> Save или горячей комбинацией клавиш Ctrl+S).

----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    12:08:28 12/11/2017 
-- Design Name: 
-- Module Name:    clock_divide - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
 
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;
 
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
library UNISIM;
use UNISIM.VComponents.all;
 
entity clock_divide is
    Port ( clock_osc : in  STD_LOGIC;
           clk_div : out  STD_LOGIC);
end clock_divide;
 
architecture Behavioral of clock_divide is
 
signal clock_div_int : std_logic;
signal count : unsigned(9 downto 0):="0000000000";
 
begin
   CLK_DIV16_inst : CLK_DIV16
   port map (
      CLKDV => clock_div_int, -- Divided clock output
      CLKIN => clock_osc      -- Clock input
   );
 
   process (clock_div_int) 
   begin
      if clock_div_int='1' and clock_div_int'event then
         count <= count + 1;
      end if;
   end process;
   
   clk_div <= count(9);
end Behavioral;

[Создание модуля счетчика вверх/вниз]

Теперь мы готовы создать второй модуль. Этот модуль будет еще одним счетчиком, который будет осуществлять шаги через 16 разных последовательностей.

1. Для добавление другого модуля исходного кода снова выберите Project -> New Source... в меню Project Navigator. Выберите VHDL Module, и назовите его "counter". У него будет 5 портов: 4 из них это входы с именами "clock", "reset", "direction" и "pause_design", и один будет 4-битной выходной шиной (Bus) с именем count_out.

Port Declaration Screen counter fig409

Рис. 4-9. Экран настройки декларации портов модуля counter.

Обратите внимание, что надо поставить галочку в столбце Bus для шины count_out, и также поставить в столбце MSB для count_out значение 3 (старший разряд шины) и для LSB значение 0 (младший разряд шины).

2. Кликните Next и затем Finish, будет создан новый файл counter.vhd на языке VHDL.

3. Вернемся к шаблонам Language Templates и найдем счетчик с управлением направлением счета. Этот счетчик находится по следующему пути: VHDL -> Synthesis Constructs -> Coding Examples -> Counters -> Binary -> Up/Down Counters -> /w CE.

4. Скопируйте код из шаблона и вставьте его в файл counter.vhd между строками begin и end блока architecture Behavioral.

5. Теперь нам нужно отредактировать имена сигналов и вставить сигнал сброса reset. Возможно, что Вам покажется полезной функция поиска и замены (меню Edit -> Replace) для выполнения следующих задач:

a. Поменяйте < count_direction > на direction, и удалите угловые скобки вокруг сигналов clock и count.
b. Поменяйте < clock_enable > на pause_design.
c. Поменяйте полярность для условия активности pause_design:

if pause_design='1'

замените на

if pause_design='0'

d. Добавьте асинхронный сброс reset в код добавлением строки непосредственно после начала оператора process:

if reset='0' then count <= "0000";

Событие сброса соответствует '0' потому что кнопка (push button) на демонстрационной плате имеет активный уровень лог. 0 (при нажатии на кнопку она замыкает свой контакт на землю), что соответствует лог. 1 когда кнопка не нажата, и лог. '0', когда кнопка нажата.

6. Поменяйте оператор процесса process (clock) на process (clock, reset, pause_design).

7. Затем нам нужно создать 4-битный сигнал с именем count. Вставьте следующий код между строками с ключевым словом architecture, и ключевым словом begin:

signal count : unsigned (3 downto 0);

8. В завершение нам нужно подключить сигнал счетчика к порту count_out вставкой следующей строки после строки end process и перед строкой end behavioral:

   count_out <= STD_LOGIC_VECTOR(count);

9. Поменяйте оператор if clock, чтобы он начинался с elsif вместо if.

Полный код counter.vhd см. во врезке.

----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    16:29:46 12/11/2017 
-- Design Name: 
-- Module Name:    counter - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
 
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;
 
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.--library UNISIM;
--use UNISIM.VComponents.all;
 
entity counter is
    Port ( clock : in  STD_LOGIC;
           reset : in  STD_LOGIC;
           direction : in  STD_LOGIC;
           pause_design : in  STD_LOGIC;
           count_out : out  STD_LOGIC_VECTOR (3 downto 0));
end counter;
 
architecture Behavioral of counter is
 
signal count : unsigned (3 downto 0);
 
begin
   process (clock, reset, pause_design)
   begin
      if reset='0' then count <= "0000";
      elsif clock='1' and clock'event then
         if pause_design='0' then
            if direction='1' then
               count <= count + 1;
            else
               count <= count - 1;
            end if;
         end if;
      end if;
   end process;
   
   count_out <= STD_LOGIC_VECTOR(count);
end Behavioral;

10. Сохраните файл.

[Создание модуля преобразования]

Сейчас мы создали 2 модуля. Конечная функциональная модель будет преобразовывать 4-битное число в 7-битный код для управления 7-сегментным светодиодным индикатором. Для этого создадим еще один модуль.

1. Как обычно, создайте новый модуль VHDL Module через меню Project -> New Source..., назовите модуль display_drive. У этого модуля будет только 2 порта: 4-битный вход с именем count_in и 7-битный выход и именем LED, как показано на рис. 4-11.

Port Declaration Screen display drive fig411

Рис. 4-11. Входы и выходы модуля дешифратора для управления 7-сегментным индикатором.

2. Так как этот модуль это чисто логический преобразователь сигнала из одного формата в другой (дешифратор), то в нем не нужен оператор process, здесь будут только операторы присваивания. Вставьте следующий код между строками begin и end блока architecture Behavioral:

with count_in Select
LED <= "1111001" when "0001", --1
       "0100100" when "0010", --2
       "0110000" when "0011", --3
       "0011001" when "0100", --4
       "0010010" when "0101", --5
       "0000010" when "0110", --6
       "1111000" when "0111", --7
       "0000000" when "1000", --8
       "0010000" when "1001", --9
       "0001000" when "1010", --A
       "0000011" when "1011", --b
       "1000110" when "1100", --C
       "0100001" when "1101", --d
       "0000110" when "1110", --E
       "0001110" when "1111", --F
       "1000000" when others; --0

Модуль в файле display_drive.vhd показан во врезке ниже.

----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    09:46:32 12/12/2017 
-- Design Name: 
-- Module Name:    display_drive - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
 
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
 
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
 
entity display_drive is
    Port ( count_in : in  STD_LOGIC_VECTOR (3 downto 0);
           LED : out  STD_LOGIC_VECTOR (6 downto 0));
end display_drive;
 
architecture Behavioral of display_drive is
 
begin
with count_in Select
LED <= "1111001" when "0001", --1
       "0100100" when "0010", --2
       "0110000" when "0011", --3
       "0011001" when "0100", --4
       "0010010" when "0101", --5
       "0000010" when "0110", --6
       "1111000" when "0111", --7
       "0000000" when "1000", --8
       "0010000" when "1001", --9
       "0001000" when "1010", --A
       "0000011" when "1011", --b
       "1000110" when "1100", --C
       "0100001" when "1101", --d
       "0000110" when "1110", --E
       "0001110" when "1111", --F
       "1000000" when others; --0
end Behavioral;

3. Сохраните файл display_drive.vhd.

[Функциональная симуляция]

Теперь мы можем запустить функциональную симуляцию модуля display_drive. Когда модуль display_drive.vhd подсвечен (выбран) в окне Design -> Hierarhy, окно Process покажет все операции, доступные для этого модуля. Можно синтезировать файл VHDL (synthesis), и затем выполнить его реализацию (implement) в потоке бит (bitstream). Обычно весь дизайн состоит и нескольких модулей низкого уровня (low-level module), подключенных к одному модулю верхнего уровня (top-level module). В этом примере мы выполним симуляцию только модуля низкого уровня, чтобы показать методологию симуляции.

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

1. В меню Project снова выберите New Source..., но на этот раз выберите тип модуля VHDL Test Bench, и назовите его display_drive_tb.

2. Нажмите кнопку Next, Вам предложат связать тест с модулем дизайна. Выберите модуль display_drive.

VHDL Test Bench associate

Будет шаблон теста VHDL (модуль display_drive_tb.vhd), котором нужно будет внести правки, чтобы получился тестовый сигнал.

3. В консоли отобразится список ошибок в новом созданном модуле теста display_drive_tb.vhd. Давайте их исправим. Закомментируйте строки, где встречается clock в угловых скобках:

--   constant < clock >_period : time := 10 ns;
 
--   < clock>_process :process
--   begin--      < clock> <= '0';
--      wait for < clock>_period/2;
--      < clock> <= '1';
--      wait for < clock>_period/2;
--   end process;
 
--      wait for < clock>_period*10;

Примечание: для комментирования блока текста удобно пользоваться горячей комбинацией клавиш Alt+С. Для этого сначала выделите комментируемый блок, и затем нажмите Alt+C.

Удалите текст между ключевыми словами begin и end блока stim_proc: process.

4. Теперь давайте добавим сигналы изменения входов шины count_in внутрь блока BEGIN/END блока ARCHITECTURE behavior OF display_drive_tb IS.

a. Переименуйте блок stim_proc: process в stim_proc3: process. Это будет процесс для изменения старшего сигнала шины count_in(3).

b. Вставьте внутрь блока stim_proc3: process следующий код:

      wait for 200 ns;
      count_in(3) <= not count_in(3);

c. Сделайте еще 3 одинаковые копии блоков stim_proc3, и переименуйте их в stim_proc2, stim_proc1 и stim_proc0.

d. Поменяйте в блоках stim_proc2, stim_proc1 и stim_proc0 задержку wait на 100, 50 и 25 нс.

e. Поменяйте в выражении инвертирования сигнала блоков stim_proc2, stim_proc1 и stim_proc0 номера разрядов на 2, 1 и 0 соответственно.

Сохраните полученный модуль display_drive_tb.vhd. Его полный код см. во врезке ниже.

--------------------------------------------------------------------------------
-- Company: 
-- Engineer:
--
-- Create Date:   10:33:08 12/12/2017
-- Design Name:   
-- Module Name:   J:/Xilinx/Projects/Tutorial/display_drive_tb.vhd
-- Project Name:  Tutorial
-- Target Device:  
-- Tool versions:  
-- Description:   
-- 
-- VHDL Test Bench Created by ISE for module: display_drive
-- 
-- Dependencies:
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
-- Notes: 
-- This testbench has been automatically generated using types std_logic and
-- std_logic_vector for the ports of the unit under test.  Xilinx recommends
-- that these types always be used for the top-level I/O of a design in order
-- to guarantee that the testbench will bind correctly to the post-implementation 
-- simulation model.
--------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
 
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
 
ENTITY display_drive_tb IS
END display_drive_tb;
 
ARCHITECTURE behavior OF display_drive_tb IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT display_drive
    PORT(
         count_in : IN  std_logic_vector(3 downto 0);
         LED : OUT  std_logic_vector(6 downto 0)
        );
    END COMPONENT;
    
   --Inputs
   signal count_in : std_logic_vector(3 downto 0) := (others => '0');
 
   --Outputs
   signal LED : std_logic_vector(6 downto 0);
   -- No clocks detected in port list. Replace < clock> below with 
   -- appropriate port name 
 --   constant < clock>_period : time := 10 ns;
 
BEGIN
   -- Instantiate the Unit Under Test (UUT)
   uut: display_drive PORT MAP (
          count_in => count_in,
          LED => LED
        );
   -- Clock process definitions
--   < clock>_process :process
--   begin--		< clock> <= '0';
--		wait for < clock>_period/2;
--		< clock> <= '1';
--		wait for < clock>_period/2;
--   end process;
 
   -- Stimulus process
   stim_proc3: process
   begin
      wait for 200 ns;
      count_in(3) <= not count_in(3);
   end process;
 
   stim_proc2: process
   begin		
      wait for 100 ns;
      count_in(2) <= not count_in(2);
   end process;
 
   stim_proc1: process
   begin		
      wait for 50 ns;
      count_in(1) <= not count_in(1);
   end process;
 
   stim_proc0: process
   begin		
      wait for 25 ns;
      count_in(0) <= not count_in(0);
   end process;
END;

Примечание: код теста display_drive_tb.vhd виден в дереве проекта Design -> Simulation. Проверить синтаксис редактируемого модуля display_drive_tb.vhd можно двойным кликом на пункт Behavioral Check Syntax.

Create VHDL Test Bench

4. Перейдите снова в дерево симуляции проекта Design -> Simulation. Выберите модуль display_drive_tb, и запустите Xilinx ISE Simulator двойным кликом на Simulate Behavioral Model в окне Process.

Simulate Behavioral Model

5. Откроется окно симулятора ISim, по умолчанию время симуляции будет установлено на 1 мкс. Функциями меню View вы можете управлять просмотром диаграмм входных (шина coint_in[3:0]) и выходных сигналов (шина led[6:0]). View -> In (F8) будет приближать диаграмму (уменьшение масштаба), View -> Out (F7) отдалять диаграмму (увеличение масштаба), View -> To Full View отобразит диаграмму за полное время симуляции.

Треугольник возле имени сигналов шины позволяет развернуть развернуть просмотр отдельных разрядов шины.

Simulate Behavioral Model fig416

Рис. 4-16. Симуляция модели поведения дизайна модуля display_drive.vhd.

[Дизайн VHDL верхнего уровня]

Теперь нам всего лишь осталось создать так называемый модуль верхнего уровня (top level VHDL module), чтобы соединить друг с другом наших 3 логических блока (функции модулей clock_divide, counter и display_drive, чтобы они работали вместе). Сначала мы это сделаем на языке VHDL, а потом то же самое, в целях демонстрации, проделаем с помощью создания схемы.

1. Используйте меню Project -> New Source..., чтобы создать новый модуль типа VHDL Module, и дайте ему имя top. На этом уровне дизайна все порты этого модуля будут ножками нашей микросхемы логики XC2C256. У нас будут 4 входных порта с именами clock_ext, reset_ext, direction_ext и pause_design вместе с одним выходным портом в виде 7-битной шины с именем LED_output.

Port Declaration Screen top

Примечание: имя top для модуля верхнего уровня выбрано не случайно, это общепринятая негласная практика.

2. Из-за того, что мы будем использовать 3 ранее созданных модуля как компоненты нашего нового модуля top верхнего уровня, то нам просто нужно сначала декларировать их как компоненты, точно так же, как мы это делали в модуле делителя частоты clock_divide. Между начальной строкой aarchitecture Behavioral модуля top и строкой с оператором begin вставьте 3 декларации компонентов следующим образом:

...
 
architecture Behavioral of top is
 
component clock_divide
   Port ( clock_osc : in STD_LOGIC;
          clk_div : out STD_LOGIC);
end component;
 
component counter
   Port ( clock : in STD_LOGIC;
          reset : in STD_LOGIC;
          direction : in STD_LOGIC;
          pause_design : in STD_LOGIC;
          count_out : out STD_LOGIC_VECTOR (3 downto 0));
end component;
 
component display_drive
   Port ( count_in : in STD_LOGIC_VECTOR (3 downto 0);
          LED : out STD_LOGIC_VECTOR (6 downto 0));
end component;
 
begin
 
...

Обратите внимание, что порты этих трех компонентов точно соответствуют портам модулей, которые мы создали ранее (clock_divide, counter и display_drive).

3. Когда компоненты декларированы, мы должны использовать в дизайне экземпляры этих компонентов (instances). Введите следующий текст в коде модуля top после оператора begin и перед оператором end Behavioral:

...
 
begin
 
U1: clock_divide
   Port map ( clock_osc => clock_ext,
              clk_div => clock_div_sig);
 
U2: counter
   Port map (clock => clock_div_sig,
             reset => reset_ext,
             direction => direction_ext,
             pause_design => pause_design,
             count_out => count_in_sig);
 
U3: display_drive
   Port map (count_in => count_in_sig,
             LED => LED_output);
 
end Behavioral;

Обратите внимание, что все порты подключаются либо к декларации entity модуля top (внешние сигналы clock_ext, reset_ext, direction_ext, LED_output) либо к промежуточным сигналам (clock_div_sig, count_in_sig).

При этом вид отображения модулей в окне дерева дизайна Design -> Implementation также поменяется. Раньше модули были показаны в виде простого списка, а теперь отражается тот факт, что модуль top является главным, т. е. "модулем верхнего уровня", а модули clock_divide, counter и display_drive используются как подчиненные, для определения экземпляров объектов U1, U2 и U3 соответственно.

Design Implementation top hierarchy fig419

Рис. 4-19. Иерархия модулей исходного кода в окне Design -> Implementation.

4. Теперь нам нужно декларировать 2 промежуточных сигнала, которые используются для обмена данными между модулями. После последней декларации компонента и перед оператором begin, введите две декларации сигналов:

signal count_in_sig : std_logic_vector (3 downto 0);
signal clock_div_sig : std_logic;

5. Сохраните полученный модуль top.vhd, его полный код см. во врезке ниже.

----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    14:43:05 12/12/2017 
-- Design Name: 
-- Module Name:    top - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
 
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
 
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
 
entity top is
    Port ( clock_ext : in  STD_LOGIC;
           reset_ext : in  STD_LOGIC;
           direction_ext : in  STD_LOGIC;
           pause_design : in  STD_LOGIC;
           LED_output : out  STD_LOGIC_VECTOR (6 downto 0));
end top;
 
architecture Behavioral of top is
 
component clock_divide
   Port ( clock_osc : in STD_LOGIC;
          clk_div : out STD_LOGIC);
end component;
 
component counter
   Port ( clock : in STD_LOGIC;
          reset : in STD_LOGIC;
          direction : in STD_LOGIC;
          pause_design : in STD_LOGIC;
          count_out : out STD_LOGIC_VECTOR (3 downto 0));
end component;
 
component display_drive
   Port ( count_in : in STD_LOGIC_VECTOR (3 downto 0);
          LED : out STD_LOGIC_VECTOR (6 downto 0));
end component;
 
signal count_in_sig : std_logic_vector (3 downto 0);
signal clock_div_sig : std_logic;
 
begin
U1: clock_divide
   Port map ( clock_osc => clock_ext,
              clk_div => clock_div_sig);
 
U2: counter
   Port map (clock => clock_div_sig,
             reset => reset_ext,
             direction => direction_ext,
             pause_design => pause_design,
             count_out => count_in_sig);
 
U3: display_drive
   Port map (count_in => count_in_sig,
             LED => LED_output);
end Behavioral;

[Создание модуля верхнего уровня на базе схемы]

Программа графического редактора схемы (ECS schematic capture) также позволяет создавать функциональные модули, как мы это делали ранее на языке VHDL. Также можно разработать и модуль верхнего уровня, соединяющий друг с другом низкоуровневые модули. Графический редактор ECS разработан по принципу визуального манипулирования логическими устройствами по принципу "что видите, то и получаете". Обычно большинство приложений Windows построены именно по такому принципу, позволяя пользователю работать с выбираемыми объектами. Возможно, что для инженеров, у которых больше опыта работы со схемами, чем опыта с программированием, редактор ECS позволит быстрее начать синтезировать логические устройства.

Создание модуля верхнего уровня. Перед тем, как можно создать будет создать схему верхнего уровня, нам сначала понадобится создать символы для 3 модулей VHDL clock_divide, counter и display_drive. Это добавит схематическое представление каждого модуля к схематической библиотеке проекта.

1. Выберите модуль clock_divide.vhd в окне Design -> Implementation, и разверните раздел Design Utilities в окне Process. Сделайте двойной клик на пункте Create Schematic Symbol. Повторите это действие для файлов counter.vhd и display_drive.vhd.

Create Schematic Symbol

2. Теперь создадим лист схемы. Выберите в меню Project -> New Source..., тип модуля установите в Schematic, и дайте ему имя top_sch, как показано на рис. 4-21.

New Source Window Showing top sch fig421

Рис. 4-21. Создание нового модуля top_sch на основе схемы.

Кликните Next, затем Finish. Откроется окно редактора ECS Schematic Editor. При этом фокус автоматически перескочит на закладку Options.

3. Библиотека символов (symbol libraries) доступна на закладке Symbol (она слева от закладки Options). В верхней части окна Вы увидите раздел библиотек, содержащий путь до папки, где находится Ваш проект. Если Вы кликните на эту категорию библиотек, то увидите 3 символа, перечисленные ниже в отдельном списке. Это те 3 символа, которые мы ранее создали, см. рис. 4-22.

4. Кликните на символ clock_divide, и переместите курсор на лист схемы. Курсор изменится на жирный крест, справа от которого будет графика выбранного символа clock_divide. Поместите символ в левой части листа схемы, примерно посередине между верхним и нижним краем листа.

5. Затем кликните на символе counter, и поместите его на листе схемы справа от символа clock_divide, через небольшой интервал между ними.

6. В завершение кликните на символе display_drive, и поместите его справа от символа counter. Ваша схема должна принять примерно такой вид:

Schematic Sheet fig423

Рис. 4-23. Лист схемы в редакторе ECS.

Соединение блоков друг с другом

7. Соединим блоки схемы друг с другом сигнальными линиями. Для этого служит инструмент Add Wire. Вот так выглядит соответствующая кнопка на панели инструментов редактора ECS:

Add Wire tool fig424

Рис. 4-24. Инструмент Add Wire.

8. Кликните на выход clk_div символа clock_divide, переместите курсор вправо и сделайте клик на входе clock символа counter. Отобразится проводник между двумя этими портами.

9. Повторите то же самое, соединяя друг с другом выход count_out(3:0) символа counter и вход count_in(3:0) символа display_drive. Обратите внимание, что это 4-битная шина, поэтому линия соединения будет толще.

10. Теперь, пока у нас активен режим инструмента Add Wire, добавим еще проводники к входным и выходным портам, чтобы потом их можно было сделать ножками ввода/вывода (I/O pins). Сначала кликните на порт clock_osc символа clock_divide, и нарисуйте короткий проводник от него в сторону левого края схемы. Заканчивать проводник, если он не приходится на вывод компонента, следует двойным щелчком мыши. Повторите то же самое со входами reset, direction и pause_design символа counter, выравнивая левые стороны проводников. Затем нарисуйте еще короткий проводник от выхода LED(6:0) в сторону правого края схемы.

Получившаяся схема должна выглядеть примерно так:

Connected Blocks fig425

Рис. 4-25. Блоки соединены на схеме друг с другом.

Назначение имен цепей

11. Дадим имена удобочитаемые имена цепям сигналов. По умолчанию они имеют автоматически назначенные имена наподобие XLXN_1, XLXN_2(3:0) и т. п. Для этого имеется инструмент Add Net Name и соответствующая кнопка на тулбаре:

Add Net Name tool

Кликните на кнопку инструмента Add Net Name. Слева отобразится диалог опций "Add Net Name Options". В поле ввода "Name:" этого диалога введите clock_ext, и затем сделайте двойной клик на конце проводника, который Вы провели от входа clock_osc символа clock_divide. Затем введите reset_ext, и сделайте двойной клик на конце цепи порта reset. Введите direction_ext, и сделайте двойной клик на конце цепи порта direction. Введите pause_design, и сделайте двойной клик на конце цепи порта pause_design.

12. В завершение введите LED_output(6:0) и сделайте двойной щелчок на конце шины выхода символа display_drive.

Маркеры I/O

13. Осталось добавить маркеры на входы и выходы. Для этого служит инструмент Add I/O Marker и соответствующая кнопка на тулбаре:

Add IO Marker tool

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

Adding IO Markers fig426

Рис. 4-26. Схема с добавленными маркерами входов и выходов.

Сохраните дизайн (File -> Save, или выполните Ctrl+S) и закройте закладку Schematic Editor. Обратите внимание, что ISE автоматически распознает файл схемы как файл верхнего уровня, и окно Design -> Hierarchy отобразит дерево модулей соответствующим образом. Если выбрать файл top_sch, то в окне Processes -> Design Utilites двойной клик на пункте View HDL Functional Model запустит автоматическую генерацию текста на языке VHDL (файл top_sch.vhf), функционально аналогичного тому, что мы создавали вручную ранее в модуле top.vhd. Инструмент синтеза будет так же обрабатывать файл точно так же, как и любой другой модуль, написанный на языке HDL или Verilog вручную.

[Ссылки]

1. UG500 Programmable Logic Design Quick Start Guide site:xilinx.com.
2. Как установить Xilinx ISE Design Tools.