Вводная. ПЛИС в картинках, а также немного о языках VHDL и Verilog.

Лично я в ПЛИС влюблён давно и бескорыстно, ещё с тех пор, как впервые услышал саму идею программируемой логики.

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

Этой статьёй я хотел помочь начинающим поскорее освоиться и избежать стандартных ошибок. А ещё, хотел показать, что в «низкоуровневом копании» в ПЛИС мало того, что нет ничего страшного, так оно ещё и помогает добиться от микросхемы именно того результата, который нужен, вместо «ой, что это» :)
Думаю, мало для кого является секретом тот факт, что ПЛИС это микросхема, состоящая из большого количества относительно несложных логических блоков, соединённых очень большим количеством проводов. На каждом из этих проводов стоит ключ, который позволяет разорвать связь. Правильно задав состояние всех ключей, можно получить практически любую цифровую схему, в том числе и ту, которая требуется для какой-либо практической задачи.

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

Чипы с энергонезависимой конфигурационной памятью в наше время обычно называются CPLD. Они, как правило дёшевы, имеют довольно простую структуру и относительно небольшое число логических элементов. Это связано с особенностями процесса производства.

А вот чипы с энергозависимой памятью, именуемые FPGA, могут быть самого разного размера и стоимости от 300 рублей за какой-нибудь xc3s50a (самый маленький чип семейства Spartan 3A abhvs Xilinx) до… хм… в общем, смотрите сами :)
search.digikey.com/scripts/DkSearch/dksus.dll?vendor=0&keywords=XC6VLX760

Энергозависимая память имеет свои недостатки — рядом с FPGA надо ставить ещё чип памяти с прошивкой, из которого она будет загружаться при включении питания. Но и достоинств у неё немало — помимо возможности производить более ёмкие чипы, она позволяет, к примеру, очень быстро переконфигурировать ПЛИС, за доли секунды полностью изменив внутреннюю схему.
А некоторые семейства микросхем вообще позволяют изменять конфигурацию одной части, не прерывая работы другой. То есть, она сама может на ходу менять собственную схему.
ВременнОе мультиплексирование железа — одна эта концепция может взорвать мозг :)

Ещё иногда встречаются гибриды — например, семейство Spartan3AN. Буква N означает, что в корпус FPGA Spartan3A вставили дополнительную флешку, с которой он может загружаться.

Но что-то я отвлёкся.

Итак, чтобы сделать из пустой программируемой логической матрицы нужную нам схему, эту схему надо для начала хоть как-то описать. Можно рисовать графическую схему, вручную задавая все связи между элементами. Но это, во-первых, громоздко, а во-вторых, базовые элементы микросхем разных семейств могут сильно отличаться — порой, при переносе схемы на другую микросхему её будет проще переписать заново, чем адаптировать…

Значит надо выбираться на уровень большей абстракции. Можно, опять же графически, соединять абстрактные примитивы типа «регистр», «сумматор», «мультиплексор» и т.п., из которых специальная программа (синтезатор) потом сформирует описание схемы уже из базовых элементов нужного семейства микросхем.
Это более переносимый вариант, но в серьёзных проектах и такие схемы очень быстро становятся огромными и нечитаемыми.

Поэтому, на данный момент, большинство разработчиков пользуется текстовым описанием логических схем.
Языков для этого существует великое множество.
VHDL — очень старый, но развивается, и по-прежнему очень популярен. Довольно громоздкий. Строгий, позволяет избежать многих ошибок.
Verilog — новее, лаконичнее, свободнее. Легче делать ошибки. Тоже очень популярен. Кроме того, на нём гораздо удобнее писать benchmark'и для симуляции (до этого мы ещё когда-нибудь дойдём).
SystemVerilog — расширенный вариант Verilog, ещё только набирает популярность, к тому же не поддерживается ПО Xilinx =( (Но для микросхем Xilinx с него всё же можно синтезировать с помощью сторонних программ, например Synplify). Раскрывает все свои прелести только на действительно больших проектах.
AHDL — только для микросхем фирмы Altera, к тому же довольно старый. Кажется, даже горячие поклонники Альтеры его уже по большей части забросили.

Это те, что часто мелькают на виду. Есть ещё экзотика типа Verilog-AMS для смешанных цифро-аналоговых схем.
Ну и вообще, если покопаться, можно много чего найти, но в данной статье я буду приводить примеры на VHDL и Verilog — сегодняшних стандартах де-факто.

Наверное, пора бы уже начать что-нибудь делать, а не только языком чесать. Для работы нам понадобится программный пакет Xilinx ISE, любую версию которого можно скачать тут
www.xilinx.com/tools/webpack.htm
Бесплатной лицензии WebPack нам хватит выше крыши. Правда, чтобы её получить, придётся зарегистрироваться. Ну или воспользоваться более традиционными отечественными методами установки ПО, если кому лень.
На данный момент только что вышла версия 13.1. Кто боится «свежего глючного», может ставить 12.4 — отличий не найдёт. У меня стоит 13.1, работает без проблем.

Итак, поставили, запускаем PlanAhead (да, именно его, а не Project Navigator, как тут некоторые советуют).

Жмём Create New Project, как-нибудь его обзываем, дальше выбираем тип проекта. Есть куча разных, но нас интересует синтез с нуля с текстовым описанием — выбираем Specify RTL Sources (RTL значит Register Transfer Level. К чему это — тоже станет со временем ясно, надеюсь).


Дальше нам предлагают добавить файлы исходников, жмём Create File.
Выбираем язык — Verilog или VHDL, кому как больше нравится, и задаём имя файла. Лучше всего для каждого модуля делать отдельный файл. В нашем примере модуль будет один, основной, он же корневой. Я такие модули обычно, не мудрствуя лукаво обзываю root.



Existing IP у нас пока не exists. Constraints (ограничения) тоже пока оставляем пустыми — они нам пригодятся несколько позже, тогда и добавим.

Потом выбираем микросхему, под которую собственно собираемся ваять.
Я выберу самую маленькую микросхему семейства Spartan3AN — самый подходящий вариант для начинающих изучать FPGA, не очень старая, позволяет не тратить бешеных денег и не заблудиться во внутренних ресурсах кристалла :)
К тому же, она входит в состав одной из самых дешёвых и, кажется, популярных плат SK-M-XC3S50AN(не сочтите за рекламу. Если что, могу убрать).


xc3s50an tqg144 -5
С XC в основном начинаются микросхемы фирмы Xilinx. 3S — это 3й Спартан, семейство. 50 — 50000 неких абстрактных логических элементов, эта цифра, якобы, позволяет сравнивать логическую ёмкость микросхем разных семейств, но на деле мало осмыслена. При выборе микросхемы под проект приходится всё же заглянуть в датащит и, о боже, посмотреть из чего оно в общих чертах состоит :)
Буква А значит, что не просто Spartan3, а Spartan3A — они ощутимо свежее. Вообще, потом могу написать небольшой обзор доступных FPGA от Xilinx, если кому интересно.
Буква N означает, что в корпус встроена флешка, внешней памяти не надо.
tqg144 — это корпус. Да, 144 ноги :) Но вполне паябельно. А что вы хотели, FPGA маленькими не делают, последние вообще только в BGA-корпусах. Если надо меньше ног, смотрите в сторону CPLD — там бывают почти любые.
Цифра -5 это так называемый speed grade. У каких-нибудь контроллеров обычно указывают максимальную рабочую частоту, а на какой частоте будет работать схема в ПЛИС очень сильно зависит не только от самого кристалла, но и от вашей схемы, поэтому указывать особо нечего. Пишут просто абстрактную циферку. -5 — побыстрее, -4 чуть помедленнее, и так далее. Не знаю как у других, а у Xilinx между соседними speed grade'ами разница по частоте обычно получается процентов 10. Иногда, 5, иногда 15, а в особо извращённых случаях и до 30, но это очень редко.

Итак, задали настройки, посмотрели, что всё так как надо.
У меня получилось вот так


И наконец-то создали проект.
Теперь напишем схему. Для простоты возьмём банальное логическое И.

VHDL


Для начала подключим библиотеку:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

В ней содержатся типы std_logic и std_logic_vector, которые понадобятся нам для описания цифровых схем.

ВНИМАНИЕ! Схемы у нас чисто цифровые, сигналы (напряжения на проводах) могут быть ТОЛЬКО 0 (земля) и 1 (питание). Никаких Integer'ов и прочей дребедени в синтезируемой схеме быть не должно, только биты и группы бит. Всё остальное ТОЛЬКО ДЛЯ СИМУЛЯЦИИ.

Чтобы сымитировать окружение ПЛИС, прогнать какие-то тесты, всё хорошенько проверить, можно писать так называемые benchmark'и — это модули-обёртки для синтезируемых (тех, из которых синтезируется прошивка для ПЛИС) модулей. benchmark'и пишутся обычно на том же языке, что и синтезируемые модули, но в benchmark'ах используются и Integer'ы, и файловый ввод-вывод, и вообще что угодно. Но это только для симуляции.

Некоторые синтезаторы пытаются сочинить что-то из любого текста, который им подсунут, но результаты чаще всего далеки от идеала. И как правило далеки от того, что имел в виду автор.
Так что, только биты, и ничего кроме битов.


Дальше описываем наш модуль, на языке VHDL «сущность» (entity).
entity root is
	Port (
		a    	:	in	std_logic;
		b	:	in	std_logic;
		
		y 	:	out     std_logic
	);
end root;

Это корневой модуль, он соответствует всей микросхеме в целом. Из него торчат три ноги — два входа и один выход. Это значит, что у нашей микросхемы так же будет задействовано три ноги (не считая служебных типа питания, земли и JTAG'а).

Дальше мы описываем архитектуру нашего модуля. Вообще, в VHDL у каждого модуля может быть несколько архитектур, но это опять же от лукавого (и для симуляции). Здесь архитектура одна, и обзывать мы её можем как хотим (здесь «Behavioral»).
architecture Behavioral of root is
begin

-- Здесь описание архитектуры.
-- Cтроки комментариев в VHDL начинаются с "--"

end Behavioral;

А внутри описания архитектуры мы (внимание!) соединяем провода.
Не пишем программу, не описываем, боже упаси, алгоритм, а соединяем провода. Ну, можем ещё соединять их через какую-нибудь логику. Например через И.
y    <= '1'    when    a = '1' and b = '1'    else    '0';    

Это значит, что на выход y подаётся 1 тогда и только тогда, когда на обоих входах 1. Иначе 0.

В итоге получается вот такой файлик:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity root is
	Port (
		a    	:	in	std_logic;
		b	:	in	std_logic;
		
		y 	:	out     std_logic
	);
end root;

architecture Behavioral of root is
begin

y    <= '1'    when    a = '1' and b = '1'    else    '0';    

end Behavioral;

Verilog


Тут как-то всё пока очевидно, даже не знаю что ещё сказать.
module root(
    input    a,
    input    b,
    output   y
);

assign y = a & b;

endmodule

А, да комментарии — как в С // или /**/ :)

Сборка


Теперь жамкаем слева большую зелёную стрелочку Synthesize (если стрелки не видно, то сначала Ctrl+Q). Комп шустро синтезирует из нашего текстового описания логическую схему. Если есть ошибки, это можно увидеть в правом верхнем углу вкладки Project Summary. Оттуда же по ссылке можно эти ошибки почитать.

Если всё ОК, тыкаем на вторую зелёную стрелку Implement. Это просьба разложить логические элементы по кристаллу и просчитать, какими проводами они будут соединяться.

Ну а теперь полюбуемся, что получилось.
Жмём уже вот эту стрелочку

В появившемся меню выбираем Open Implemented Design и дальше единственный имеющийся.

И вот мы наконец-то увидели наш кристалл, а так же нашу грандиозную схему схему :) (обведена кружком).


По краю видны, что характерно, ноги. Мелкие клеточки внутри — логические блоки. Большие квадраты — DCM'ы (Digital Clock Managers), Большие вытянутые прямоугольники — блоки памяти и умножители.
Но это всё потом, нас интересует наша схема.

Из всей стаи непонятных тараканчиков выделен (задействован) только один — наш единственный логический элемент, а так же три ноги микросхемы — P75, P76 и P78.
Выделив любой элемент и нажав F4 (или Schematic через всплывающее меню) можно увидеть схему.

При помощи двойного клика по любой ноге на схеме можно увидеть все присоединённые к ноге элементы.
Вот, собственно, что у нас получилось:

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

LUT — это Look-Up Table, простейший логический элемент в FPGA. На схеме у неё задействовано(и изображено) только два входа, но на вкладке Device (той, что открылась сначала) при подходящем зуме можно увидеть, что у неё 4 входа. Вообще, в разных семействах микросхем у них может быть разное количество входов. В Spartan3 LUT'ы 4х-входовые и могут реализовать любую логическую функцию. То есть это по желанию может быть OR4, или AND4, или NOR4, или какая-нибудь фигня типа (A & B) | (~C & D).

По сути, LUT это маааленький блок памяти на 16 бит — входы задают адрес, а на выходе получаем однобитные данные. В памяти храница таблица истинности нужной функции.

(Посмотреть, какая именно функция реализована в конкретной LUT через PlanAhead мне, почему-то, так и не удалось, но можно выделить нужный элемент, ткнуть в него правой кнопкой мыши и в меню выбрать Cross-probe to FPGA Editor. Откроется FPGA Editor, в котором можно разглядеть вообще всё что угодно, но он гораздо менее удобный.)

Помимо LUT, которые реализуют произвольную логику, есть ещё более мелкие и специализированные элементы. Например, «логика ускорения переноса» позволяет делать более экономные по ресурсам и быстрые сумматоры/вычитатели/счётчики.

Реализуем, для примера, простенький 16-битный сумматор.

VHDL

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- Не забываем включить эти библиотеки - в них арифметика
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

-- Входы теперь 16-битные, выход 17-битный
-- Порядок бит может быть как (0 to 15), так и (15 downto 0),
-- С числами удобнее использовать downto, потому что тогда 
-- младший бит имеет номер 0 и означает 2^0 = 1,
-- а старший, к примеру, номер 15 и означает 2^15 = 32768.
-- Полезно при переводе чисел между системами счисления.
-- В принципе, можете использовать любой порядок, но одно
-- я знаю точно - если смешать в одной схеме to и downto,
-- то очень скоро у вас взорвётся мозг :)
-- А пользы от этого никакой.
entity root is
	Port (
		a    	:	in	std_logic_vector(15 downto 0);
		b	:	in	std_logic_vector(15 downto 0);
		
		s 	:	out     std_logic_vector(16 downto 0)
	);
end root;

architecture Behavioral of root is
begin

s    <= a + b;    

end Behavioral;


Verilog


module root(
    input    [15:0] a,
    input    [15:0] b,
    output   [16:0] s
);

assign s = a + b;

endmodule



Видно, что теперь задействованы дополнительные элементы помимо LUT.

Синхронщина


Всё это, конечно, хорошо, но где же зависимость от времени? Где тактовая частота?
Щас будет.
Пишем счётчик.
Точнее, напишем чрезвычайно полезную в хозяйстве и столь же редкую штуку — мигание светодиодом :)
Предположим, что к микросхеме подведён тактовый сигнал 20 MHz (кварц взяли первый попавшийся, от ближайшей AVR'ки), а светодиодом надо мигать полтора раза в секунду. Проблема? Да ни фига :)
Вообще, для извращений с тактовыми сигналами и частотами в FPGA есть специальные блоки — DCM (Digital Clock Manager) — они позволяют делить частоты, синхронизовать тактовые сигналы по фазе, даже умножать(!) частоты. Но вот беда, они рассчитаны на быстрые сигналы (от 5 МГц, кажется), а мигать нам надо с частотой 1.5 Гц. Ну ничего, поделим вручную.
Нам надо мигнуть светодиодом полтора раза в секунду, то есть изменить напряжение на управляющей светодиодом ноге 3 раза за секунду (полтора раза зажечь и полтора раза потушить :). Это значит, что изменять напряжение надо каждые 20*10^6 / 3 = 6666667 тактов (16 с хвостом наносекунд погрешности, образовавшиеся при округлении считаем приемлемыми :).
Как отсчитать нужное количество тактов? Счётчиком.
Нам потребуется 23-битный счётчик, он может досчитать аж до 8388607. От 0 до 8388607 — период 8388608. Нам явно много, но ничего, справимся.

Для начала напишем собственно счётчик и посмотрим, во что он синтезируется.
Считать будем, когда вход enable_n притянут к земле.
Ещё, в более-менее сложных цифровых схемах считается хорошим тоном иметь сигнал reset, который полностью возвращает схему в исходное состояние. Это, например, чтобы в любой момент можно было замкнуть пару проводков отвёрткой и начать отладку сначала — очень удобно. Или при сбое питания аккуратно перезагрузить схему, или ещё что…

VHDL

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity root is
	Port (
		enable_n    : in std_logic;
		reset	    : in std_logic;
		clock       : in std_logic;
		
		led 	    : out std_logic
	);
end root;

architecture Behavioral of root is

-- Это у нас внутренние провода схемы.
-- Никакая не переменная, а просто 23 проводка, таких же
-- какие были на входе и на выходе, просто не подключённые
-- к ногам микросхемы.
signal counter    : std_logic_vector(22 downto 0) := B"000" & X"0_0000";
-- := справа - это инициализация на момент загрузки.
-- когда мы включим питание, микросхема FPGA высосет из флешки
-- свою прошивку, поставит все элементы в начальное состояние,
-- а потом начнёт работать в соответствии со схемой.
-- X"0_0000" - это пять нулей в шестнадцатеричной системе,
-- символ подчёркивания просто для читаемости. Каждая
-- шестнадцатеричная цифра соответствует 4 битам. Всего 20 бит.
-- B"000" - это три нуля в двоичной системе. Всего три бита.
-- & - оператор конкатенации или слияния, делает из двух групп битов
-- одну. 23 бита.

begin

-- Итак, мы хотим, чтобы в нашей схеме что-то менялось со временем.
-- "Процессы" позволяют описывать такие вещи.
-- (clock, reset) - это так называемый список чувствительности процесса,
-- он означает, что всё, что написано внутри процесса имеет смысл только
-- в те моменты времени, когда что-то из списка чувствительности
-- изменило своё значение. То есть либо clock, либо reset переключились
-- либо с 0 на 1, либо с 1 на 0.
process(clock, reset)
begin
    -- Дальше задаём условия.
    -- Если на reset подана 1 (независимо от того, попали ли мы в
    -- процесс из-за переключения ресета с 0 на 1, или из-за
    -- переключения клока в то время, когда ресет был 1), то
    -- сбрасываем схему в начальное состояние.
    if( reset = '1' ) then
        counter    <=    (others => '0');
        -- (others => '0') означает "все биты установить в 0"
        -- сколько это - все - задаёт левая часть. 23.

    -- Если ресет всё-таки ноль, и при этом клок переключился именно
    -- с 0 на 1 (восходящий, он же передний фронт), да ещё и наш
    -- enable_n не активен (равен 0), то увеличиваем счётчик.
    elsif( rising_edge(clock) and enable_n = '0' ) then
        counter    <=    counter + 1;
    end if;
    -- Заметьте, что значение enable_n важно только во время фронта
    -- клока. Такие сигналы называют синхронными.
    -- А ресету наплевать на клок, он работает всегда. Это асинхронный
    -- сигнал.
end process;

-- Ну и так же как в предыдущем примере, вне зависимости от времени
-- соединили два провода - старший бит счётчика и пин, управляющий
-- светодиодом.
-- Старший бит 23-битного счётчика меняется один раз за 2^22 = 4194304
-- такта. Не совсем то, что мы хотели, но пока сойдёт.
led    <=    counter(22);

end Behavioral;


Verilog


module root(
    input    enable_n,
    input    reset,
    input    clock,
    output   led
);

reg [22:0] counter = 23'b0;
// 23'b0 означает 23 бита, все нули
// 23 - количество бит
// 'b - значит, что число будет в двоичной системе
// 0 - собственно число

// блок always - аналог процесса в VHDL
// но здесь мы можем задать, что в блок мы попадаем
// только по _переднему_ фронту ресета или клока.
// то есть когда кто-то из них изменился с 0 на 1.
// то есть внутри блока обязательно кто-то из них = 1
// (уже изменился)
// (но только что)
always @(posedge clock or posedge reset)
    // соответственно, пофиг, кто изменился
    // если ресет = 1, сбрасываем схему
    if( reset )
        counter    <=    23'b0;
    else // если ресет = 0, то значит у нас
        // сейчас передний фронт клока
        // (как-то же мы попали в блок always)
    begin
        if( ~enable_n ) // и если при этом ещё и nable_n = 0
            // то прибавляем счётчик
            counter    <= counter + 1'b1;
    end

// ну и старший бит счётчика присоединили
// к светодиоду
assign led = counter[22];

endmodule


Для работы с синхронными сигналами в FPGA предусмотрено большое количество триггеров. Это самые обычные D-триггеры.

Обратите внимание, что в Verilog мы явно указываем, что биты счётчика это регистры (reg), или иначе — триггеры. А не wire, то есть просто провода.

А в VHDL всё это пишется одинаково — signal. Но умный синтезатор заметит, что напряжение на проводе должно меняться по фронту клока и сам поймёт, что туда надо воткнуть триггер.


Видим, что теперь в схеме почти не задействованы LUT. Задействована только логика переноса и триггеры (справа).

Посмотрим повнимательнее на триггер.

Он самый обычный, у него есть вход для бита данных, выход, один тактовый вход. И ещё входы CE — Clock Enable, и CLR — вход сброса.
В нашем случае на CE подан наш enable_n, а на CLR — reset.

(Ну, на самом деле не совсем обычный. Например, в зависимости от конфигурационного бита, вход сброса может работать синхронно и не синхронно. А ещё Триггер может выступать в роли защёлки(Latch) — работать не по фронту, а по значению сигнала, о это редко пригождается.)

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

О частотах


Очевидно, что наш счётчик не сможет работать на любой частоте, где-то у него есть потолок. Но где?

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


За время от одного фронта тактового сигнала до следующего, сигнал, защёлкнувшийся на триггере Counter_13 должен успеть дойти до триггера Counter_14, чтобы защёлкнуться на нём.

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

Но мы никак не указали, программе-синтезатору, на каких частотах должна работать наша схема. По идее он может разбросать элементы даже несложной схемы по разным углам кристалла, и из-за задержек на межсоединениях работать всё это будет очень медленно (при почти пустом кристалле, как у нас сейчас, такая ситуация маловероятна, но при заполнении в 80-90% — запросто).

Так что, расскажем ему, на всякий случай, что у нас предполагается тактовый сигнал в 20 МГц.

При открытом Implemented Design слева появляется вкладка Timing Constraints.

Находим там Basic period и тыкаем в него два раза (или правой кнопкой > New Timing Constraint).

Задаём в окошке частоту.

Синтезатор сам определил, что тактовый сигнал у нас — clock.

Ещё раз жмём на Implement, нам предлагают сохранить заданные ограничения (constraints). После сохранения в проекте появляется ещё один файл .ucf.
А в нём
NET "clock" PERIOD = 20 MHz;

То, что мы задали.

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

(Слева — прикидочная частота, вычисленная после начального синтеза. Её нам показывали и раньше. А справа — уже точная, полученная после раскладки элементов по чипу. Эту нарисовали только после добовления constraint'а.)

Timing Score: 0 — это означает, что вся схема улеглась в заданный тайминг.

А это
Unrouted: 0 — число путей, которые в тайминг уложить не удалось. Ни одного, всё ОК.

Вернёмся к нашим светодиодам


Теперь подгоним нашу схему, чтобы частота мигания соответствовала ТЗ.

VHDL


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity root is
	Port (
		enable_n    : in    std_logic;
		reset	    : in    std_logic;
		clock       : in    std_logic;
		
		led 	    : out    std_logic
	);
end root;

architecture Behavioral of root is

signal counter    : std_logic_vector(22 downto 0) := (others => '0');
signal last_count : std_logic := '0';

-- В VHDL нельзя использовать в схеме значение сигнала, объявленного
-- как out. Чтобы обойти это ограничение, заведём внутренний сигнал,
-- который потом замкнём на led.
signal inn_led    : std_logic := '0';

begin

process(clock, reset)
begin
    if( reset = '1' ) then
        counter    <=    (others => '0');
    elsif( rising_edge(clock) and enable_n = '0' ) then
        if( last_count = '1' ) then
            counter    <=    (others => '0');
        else
            counter    <=    counter + 1;
        end if;
    end if;
end process;

last_count    <=    '1' when counter = 6666666 else '0';

process(clock, reset)
begin
    if( reset = '1' ) then
        inn_led <= '0';
    elsif( rising_edge(clock) and last_count = '1' ) then
        -- здесь мы его используем
        inn_led <= not inn_led;
    end if;
end process;

led <= inn_led;
-- ^ теперь led и inn_led это один и тот же провод, просто у него два
-- имени

end Behavioral;



Verilog


module root(
    input    enable_n,
    input    reset,
    input    clock,
    // led - теперь регистр
    output   reg led = 1'b0
);

reg [22:0] counter = 23'b0;
wire last_count = (counter == 23'd6666666);

always @(posedge clock or posedge reset)
    if( reset )
        counter    <=    23'b0;
    else
    begin
        if( ~enable_n )
        begin
            if( last_count )
                counter <= 'b0;
            else
                counter    <= counter + 1'b1;
        end
    end
    
always @(posedge clock or posedge reset)
    if( reset )
        led    <=    1'b0;
    else
    begin
        if( last_count )
            led    <=    ~led;
    end

endmodule


Обратите внимание, как просела частота. Компаратор 23-х битного числа даже с константой — штука не дешёвая.


Всё, наверное пора заканчивать, и так простыня жуткая получилась.

PS Писал в один присест, так что в конце мозг уже отключался.
Написал не всё, что хотел. Если тема хорошо пойдёт, выдам ещё пару статей.
  • +13
  • 10 марта 2011, 19:18
  • Anatol

Комментарии (81)

RSS свернуть / развернуть
Кстати, не верьте тому, что он пишет в Project Summary в Implemented Utilization для Spartan3(E/A) — там глюк какой-то. Для других семейств нормально, а для спартана3, если хотите узнать, какой процент кристалла заняли, лучше смотрите в Synthesis Estimation.
0
Кстати, я таки наврал, в последнем примере частота так упала не из-за компаратора, а из-за резкого увеличения длинны межсоединений.
0
Билин, кому нужны твои подробности, иди уже спать, чувак.
0
Большое спасибо за статью, ждем продолжения
0
Отличная статья получилась. Просто и понятно. Еще б так кто-нибудь Альтеру по полочкам разложил. А то с макроячейками сплошной взрыв мозга…
0
Отличная статья. Ждем-с продолжения.
0
как говорят на сайтах фанфиков — Проду! Проду! Проду!

наконец то хорошая статья от шарящего человека)
0
Хорошая статейка, ждем продолжения :-)
0
Спасибо! Интересная статья! Ждем продолжения!
0
  • avatar
  • kvm
  • 10 марта 2011, 21:47
Могучая статья :). Только не понимаю, зачем такой консервативный подход при написании элемента И и использования типа integer(просто объявлять свои типы, подтипы). Не проще просто написать Y <= a and b; при синтезе он так же реализует это конструкции на LUT. При написании написали счетчик в виде +1 и ничего же страшного не случилось, кстати это и есть алгоритм, по-этому было бы правильно сказать, что архитектура содержит параллельные операторы, которые соединяются проводами, а вот внутри параллельных операторов описывается алгоритм, по-этому я считаю заявление, что в архитектуре мы соединяем провода, а не пишем алгоритм не совсем корректно.
0
А, ну да, похоже я уже забыл, что в VHDL тоже можно написать y <= a and b; :)
Просто по жизни конструкции с when как-то гораздо чаще пригождаются — они и читаемее, как правило, и допускают многовариантные условия. На этом примере это просто не видно )

Integer'ы — зло. С векторами битов можно точно так же оперировать, разницы никакой. Но из вектора всегда можно лёгким движением вытащить нужный бит, плюс по нему сразу видно, что он 23х разрядный, а не «от нуля до шестизначного числа». А если у вас 32 или вообще 64 бита?

По поводу алгоритмов — да, мы пишем поведенческое описание схемы, это и есть алгоритм.
Но я так устал переубеждать студентов, которые хватаются за слово «алгоритм», и начинают писать «просто программы», по сишной привычке, которые потом синтезируются в нечто ужасное, а чаще всего вообще не синтезируется… А потом наивный взгляд и вопрос «что я написал не так?». Всё, блин.
Лучше уж с самого начала вбивать в головы, что это схема, а не алгоритм.
Это ведь и есть схема.

А операторы, соединённые проводами, лично мой мозг вообще представить отказывается :)
0
По поводу Integer соглашусь, что биты из них не вытащишь, но бывают ситуации когда их удобней использовать, когда они выступают в виде адреса например, а то потом при индексации массивов приходится применять функции преобразования векторов в интегер, что загромождает код, а при синтезе все равно все преобразуется в вектора. Простой пример в генетическом алгоритме есть оператор скрещивания, там есть точка скрещивания, так вот порт ее выбора может быть спокойно интегер.
package My is
subtype Number is integer range 15 downto 0;
end My;

library work;
use work.My.all;

entity Kross is
port(A,B: in bit_vector(15 downto 0);
N: in Number;
A1,B1: out bit_vector(15 downto 0));
end Kross;

architecture A_Kross of Kross is
begin
process(A,B,N)
begin
for i in A'range
loop
if(i > N) then
A1(i) <= A(i);
B1(i) <= B(i);
else
A1(i) <= B(i);
B1(i) <= A(i);
end if;
end loop;
end process;
end A_Kross;

Типа как то так :)
+1
Если в вашем примере заменить тип N на bit_vector(3 downto 0), не изменится вообще ничего, если не ошибаюсь. А да, не придётся лишний тип через package таскать :)

Нет, я не спорю, что иногда переменные полезны. Но с ними синтез часто становится менее предсказуемым, поэтому их стоит использовать с осторожностью.
0
Если заменить, то нельзя будет без преобразования i с N сравнивать
0
Хм, действительно нельзя.
А с std_logic_vector работает. Хех )
0
Интересно, надо попробовать с std_logic_vector, просто я привык использовать стандартные типы, так как их проще студентам объяснять и тестбенчи легче с ними делать.
0
Переписал с std_logic_vector, не работает, но это и правильно нельзя разные типы сравнивать.
0
Да уж, мешать одинаковые типы из разных библиотек это уже за гранью добра и зла.
Я-то всё на std_logic переправил.
0
ну я вот так сделал
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity Kross is
port(A,B: in std_logic_vector(3 downto 0);
N: in std_logic;
A1,B1: out std_logic_vector(15 downto 0));
end Kross;

architecture A_Kross of Kross is
begin
process(A,B,N)
begin
for i in A'range
loop
if(i > N) then
A1(i) <= A(i);
B1(i) <= B(i);
else
A1(i) <= B(i);
B1(i) <= A(i);
end if;
end loop;
end process;
end A_Kross;

не работает :(
0
Хм, то ли вы меня поняли слишком буквально, то ли невнимательно правили.
entity Kross is
port(
    A,B: in std_logic_vector(15 downto 0);
    N: in std_logic_vector(3 downto 0);
    A1,B1: out std_logic_vector(15 downto 0)
);
end Kross;

Так работает.
0
Спасибо разобрался, в библиотеке ieee.std_logic_unsigned есть перегруженный оператор:
function "<"(L: STD_LOGIC_VECTOR; R: INTEGER) return BOOLEAN;
attribute builtin_subprogram of
"<"[STD_LOGIC_VECTOR, INTEGER return BOOLEAN]:
function is «stdarith_lt_ui»;
0
хоть я и в другой степи, почитал с удовольствием.
0
Замечательная статья!
Я хоть и из лагеря альтерщиков, но у вас большая часть информации справедлива и для «наших». Спасибо!
0
Спасибо, великолепная статья! Сразу чувствуется навык преподавателя. Очень понравилось, по возможности пишите еще.
0
Схема ПЛИС с отображением внутренних элементов и подсветкой использующихся — классная штука. В квартусе, похоже, такого нет. Или я плохо ищу?
0
Есть конечно
Tools->Chip Planner (Floorplan and Chip Editor)
0
Ну Chip Planner я, конечно, видел, но там бессмысленный набор цветных прямоугольничков — расшифровывать то ещё удовольствие. А здесь прямо элементики прорисованы — всё ясно и наглядно.
0
Правильно, клацаете два раза на не белом прямоугольнике и видите что как он сконфигурирован
+1
О, спасибо — это уже гораздо лучше, хотя и всё равно немного не то.
0
Сам немного поискал. Чтобы увидеть схемотехническую структуру проекта
Tools->Netlist Viewers->RTL Viewer
0
А структурное соединение логических ячеек
Tools->Netlist Viewers->Technology Map Viewer
0
Ну да, это я тоже видел — отличные штуки для понимания что там насинтезировалсь, но это немного и из другой области. Хотя, конечно, всё это в целом позволяет получить всю нужную информацию, если не заблудиться — хорошо, что есть кросспереходы между этими окнами.
0
Замечательная статья

Вот только лучше не использовать «use IEEE.STD_LOGIC_ARITH.ALL;». Она не стандартизирована IEEE.
И, хотя я лично пока не встречал проблем из-за этого, теоритически могут быть несоответствия при синтезе/моделировании).

Лучше уж связку use IEEE.std_logic_unsigned.all; + use IEEE.numeric_std.ALL;

+ как уже упоминали интегер, ограниченный subtype удобно применять как индекс массива.
0
А напишите кто-нибудь про самые основные библиотеки пожалуйста.
0
Вообще пакет IEEE.std_logic_unsigned использует пакет IEEE.STD_LOGIC_ARITH, так что я думаю не страшно будет последний использовать :)
0
Anatol, если не сложно, напишите как описывать несколько однотипных элементов вашим способом…
0
Не совсем понял, что вы имеете в виду под моим способом. И какие именно однотипные элементы имеются в виду %)
0
Ну например пример из моей статьи: we.easyelectronics.ru/plis/opisanie-neskolkih-odnotipnyh-elementov-na-vhdl-s-pomoschyu-komponentov.html
описать без использования компонент и переменных, что б можно было сравнить код.
0
У меня бы это выглядело как-нибудь так
library ieee, work;
use ieee.std_logic_1164.all;

package my is
    type counter_out_type is array (9 downto 0) of std_logic_vector(15 downto 0);
end;

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use work.my.all;

entity root is  
    port (  
        clk            : in  std_logic; 
        res            : in  std_logic;
        enab           : in  std_logic;
        counter_out    : out counter_out_type
    );
end root;

architecture a of root is
signal    inn_counter_out    :    counter_out_type;
begin
        
g0: for i in 9 downto 0 generate
    process (clk, res)
    begin
        if( res = '0' ) then
            inn_counter_out(i)    <=    (others => '0');
        elsif( rising_edge(clk) and enab = '1' ) then
            inn_counter_out(i)   <=    inn_counter_out(i) + 1;
        end if;
    end process;
end generate;

counter_out    <=    inn_counter_out;

end a;


Кстати, не знаю, в чём вы проверяли пример из вашей статьи, но в ISE он не соберётся — она не любит объявление сложных типов прямо в порте (уж не помню, как это соотносится со стандартами). Вот на этой строке запинается
counter_out: out array (0 to 9) of integer range 0 to 65535 -- массив выходов

Обходится через использования package.
0
На счет ошибки, MaxPlus вроде скушал, но посмотрю детальней попрвлю.
За пример спасибо.
0
Дествительно не компилится. Поправлю… Спасибо
0
И да, я ни в коем случае не призываю отказываться от использования компонентов — в больших проектах без них проще сразу повеситься. Просто всё хорошо в меру.
0
Спасибо за хорошие отзывы :)
Постараюсь вскоре написать ещё что-нибудь — вот только добью грёбаный интерфейс на QT (
0
Еще добавьте в поисковые тэги слова ПЛИС и VHDL с Verilog, а то статья не всегда находится…
0
Хороший топик. Ничего сложного пока что… Все понятно разъяснил. :)
Есть вопрос на счет умножения частоты в Xilinx… Можно по подробнее? То есть существует какая-то команда, или нужно свой блок умножения частоты описывать? Если так, то какова идея? Что-то подсказывает на T-триггерах будет это дело построено…
0
Умножать частоту на триггерах практически невозможно. Делить — да, Т-триггеры подойдут.
Для умножения (и не только) есть DCM'ы (Digital Clock Managers) и в более новых семействах PLL'и (Phase Locked Loops) — специально созданные цельные железные блоки, очень полезные в хозяйстве. Без них не обходится ни один более-менее сложный дизайн.
Читаем документацию, там всё довольно подробно и толково изложено. Рекомендую к прочтению весь раздел Clock Management, но если время поджимает, то можно обойтись и просто описанием DCM.
0
Доброе время суток! Еще появился вопрос… Поиск на данном сайте не выдал топиков про БПФ (за исключением слова БПФ в теме AVR — GCC).
Существует ли схематическая картинка, отображающая собранный блок FFT (БПФ) на VHDL? Хотелось бы разобраться, как его собирать и что он вообще с входным дискретным сигналом делает… В википедии одни формулы… Еще программный код для С++ если не ошибаюсь, сегодня доберусь для его разборки по полочкам…
Буду признателен!
0
БПФ можно реализовать очень по-разному. И выглядеть в схематике он в любом случае будет страшно, на мой вкус.

БПФ, также как и обычное преобразование Фурье, даёт частотные характеристики сигнала — зависимость амплитуды и фазы от частоты.

С сигналом оно делает свёртку с синусоидами разной частоты. Обычное ПФ. А быстрое то же самое, но через математическую жопу. Зато быстро.
0
ЕМНИП на ЦОС БПФ рисовали довольно простенькой схемой, из нескольких соединенных блоков «операция „бабочка“». Не помню подробностей правда.
0
Вот про «Бабочку» тоже слышал и видел, сечас как раз в конспекте до нее добираюсь по сигналам и цепям… :)
0
«Обычное ПФ» — Это Вы про полосовой фильтр?
Подскажите, какими способами можно его реализовать?
Необходимо получить частотный спектр сигнала из порядка 128, 256, 512… может и до 4096 отчетов входного…
Я что-то все сталкивался с цифровыми фильтрами — их как-то часто упоминали в литературе с FFT…
Не на них ли БПФ реализуется?..
КИХ и БИХ фильтры я могу построить — хорошо разобрался, когда в университете лабораторку делал… :)
0
ПФ ака FT — преобразование Фурье. БПФ — один из алгоритмов реализации дискретного ПФ, оптимизированный по скорости выполнения.
0
Понятно… Но пока все еще глухо с ПФ И БПФ…
0
ПФ — преобразование фурье. БПФ — быстрое преобразование фурье — то же самое, даёт те же результаты, но считается менее очевидным способом. Но за меньшее количество операций.

Каждая точка функции, полученной после преобр. фурье, это результат свёртки исходной функции с комплексной синусоидой определённой частоты. Точка комплексная, соответственно. Действительная часть означает амплитуду, мнимая — фазу. Если взять для каждой точки синусоиду соответствующей амплитуды и фазы и сложить все эти синусоиды, то получится исходный сигнал. Это уже обратное преобразование фурье.

Я сейчас не смогу нормально объяснить, ибо мозг отключён, но там на самом деле всё просто. Посмотрите внимательно на формулу, на то что я написал, и в конспект (если есть). Разберётесь.
Ну или поищите в сети несколько разных описаний преобразования фурье и попытайтесь сложить воедино — отличный метод, сам так часто делаю.
0
Спасибо за кратую информацию! Посмотрю обязательно, т.к. все равно делать придется. :)
0
Вот думаю, может тоже запилить статейку про ПЛИС и Verilog — как раз вчера защитил курсач про фильтрацию сетевого трафика по регуляркам на ПЛИС %) Если кому-то интересно, можно описать что да как
0
По регуляркам — это по регулярным выражениям?
Если да, то это жесть.
Жесть в студию! :)
0
Именно по регулярным выражениям. Точнее там так — есть рв в довольно простом синтаксисе(до всяких PCRE пока руки не дошли, так что там только 3 операции: concat, union и iterate), есть прога на си, которая по этому рв генерит код модуля на верилоге, и потом этот модуль подключается в проект, где помимо него находится всякая дребедень типа работы с Ethernet PHY, этим кошмаром прошивается xc6slx16 и начинается профит. Вот только до реального применения этой штуке далековато, но как этакий прототип вполне сойдет. Да к тому же что-то у меня не получается придумать, как про это все рассказать так, чтобы подошло к этому блогу))
0
И кстати, можете порекомендовать какую-нибудь не особо дорогую отладочную плату со 3м или 6м спартаном на борту?
0
С 6 серией эта вроде как самая дешевая, если конечно покупать как студент.
0
Не, дешёвая это вот. И там же со дня на день грозятся выпустить плату с xc6slx9 примерно за те же деньги.
0
Ну это отладочным набором то трудно назвать, но если требуется только сам кристалл, то конечно это лучший вариант.
0
Хе, я кодогенерилку писал на перле — на нём как-то сподручнее тексты и разбирать и составлять.

Что фильтруете-то собственно? HTTP-трафик?
Про операции — слова понимаю, а как их к RE привязать — не очень…
В общем, если не сложится с блогом, и не жалко, можете текст курсача скинуть — мне всё интересно :)
0
Фильтровать можно любой трафик, приходящий на девайс; хотя на самом деле сейчас там не совсем фильтрация, а просто подсчет пакетов, удовлетворяющих условию. Но фильтрация добавляется просто: допилить буфер(большой сдвиговый регистр) для пакета, в него будут складываться/сдвигаться полученные байты, как только поняли, что пакет «плохой» — сбрасываем буфер, если все ок — начинаем выдавать его обратно в сеть.

Операции привязываются к RE просто: (а*) — строка из произвольного количество символов «а», (a|bс) — либо строка «а», либо «bс». Ну и дальше в том же духе. А дополнительные — это всякие множества (например [1-9, d-f] ), повторения с указанным количеством раз и тд. А одним таким RE пока просто описываются байты (точнее разные варианты последовательностей) «плохого» пакета. Хорошо бы конечно запилить работу, например, с правилами для снорта или бро — но опять же, это на будущее)
0
Люди, помогите пожалуйста! Отлавливаю ПЛИСом два байта с CMOS камеры в формате RGB565, склеиваю их и подаю полученное 16 бит слово на дисплей. С этим проблем нету. Как сделать чтобы черный цвет ПЛИС-ка на ходу приобразовывала в синий, а белый, к примеру, в желтый? При условии что с камеры могу получить Ч/Б изображение.
0
изображение с камеры идет в виде RGB565 последовательности из 2х байт, а падает на дисплей в виде RGB565 16бит слова, камера настроена на выдачу контрастного Ч/Б изображения с резкими переходами, т.е. по сути, имеем уже либо черный либо белый пиксель.

Пример алгоритма обработки цветного пикселя на Си я нарыл:

[code] unsigned char R = (buf & 0xf800) >> 11;
unsigned char G = (buf & 0x07e0) >> 5;
unsigned char B = buf & 0x001f;

yyy=(double)(0.222*R+ 0.707*G+0.071*B);

if (yyy>border_brightness){ // если значение яркости выше установленного порога, то:

R=255; // или другой желаемый подстанавливаемый цвет

G=255; // или другой желаемый подстанавливаемый цвет

B=255; // или другой желаемый подстанавливаемый цвет

}

else

{

R=0; // или другой желаемый подстанавливаемый цвет

G=0; // или другой желаемый подстанавливаемый цвет

B=0; // или другой желаемый подстанавливаемый цвет

}[/code]

вот как только теперь его на VHDL описать и получить функциональный блок?

или задам вопрос по-другому: как быстро вычислить яркость пиксела в формате RGB565 ??

Полагаю что так:
[code]Y = 0.299 R + 0.587 G + 0.114 B[/code]

Есть еще такое безобразие, более грубое:
[code]Y = (R+R+B+G+G+G)/6[/code]
0
Какая ПЛИС, на какой частоте получаете/отдаёте данные? Принципиальна ли задержка?
В зависимости от ответов на все эти вопросы есть много вариантов реализации такого модуля.
Можно в лоб умножать всё за один такт, но работать это будет только на небольших частотах. Можно конвейеризовать, можно использовать 3 аппаратных умножителя, можно 1 по очереди для каждой компоненты цвета. Если аппаратных умножителей нет, можно городить свои различных конфигураций на сумматорах. Можно точные, можно приближённые.
Простые правила:
Деление — как правило операция очень неудобная — требует количества тактов по разрядности чисел или жёстких извращений.
Деление и умножение на степень двойки — на ПЛИС операция ВООБЩЕ бесплатная, просто отбросить или добавить нужное количество младших бит.

Исходя из этого, ваша грубая формула только добавляет гемороя. Но!
Если взять знаменатель 8 (=2^3), то дело резко упрощается
Y = (2*R + B + 5 * G)/8
5 * G == G + 4 * G

Если взять знаменатель, скажем 1024, то формула вдруг становится практически точной, при этом деление (на степень двойки) по-прежнему бесплатно.
Y = (306 * R + 601 * G + 117 * B) / 1024
Умножения уже не такие простые, лучше использовать аппаратные умножители (если есть), но учитывая разрядность компонент (5-6 бит), можно на сумматорах собрать.

Вообще, знаменатель можно брать любой (степень двойки), какой нравится и даёт нужную точность. Это называется арифметика с фиксированной запятой.

Если уточните условия, могу набросать более конкретно и даже VHDL, но не сегодня.
+1
Anatol,
1) ПЛИСами располагаю несколько (EPM3032, EPM7128, Cyclone III EP3C25) какую порекомендуете применить?
2) пиксел с камеры передается за два байта, каждый байт стробируется сигналом PIXCLK (25 МГц), каждая строка (320 пикселов) синхронизируется сигналом LINE_VALID (высокий уровень), каждый кадр (240 строк) синхронизируется сигналом FRAME_VALID (высокий уровень)
3) Сейчас схема такая [камера]-[МК с интерфейсом камеры]-[ЖК], камера с МК соединяется по шинам: PIXCLK, FRAME_valid, LINE_valid, DATA[7..0]
4) хочу поставить ПЛИС между камерой и МК, полагаю что при этом по-видимому работу модуля на ПЛИС прийдется делать с FIFO (или конвейер), т.е. за такт все не успеем сделать…
0
перенес тему на форум:
0
Anatol, поюзал мегафункции — работы с камерой там нету… помогите пожалуйста VHDL написать…
0
А в при работе с Altera можно указать программе-синтезатору на каких частотах должна работать наша схема? (Quartus II)
0
Ну у тебя же есть тактовый генератор? Вот на этой частоте она и работает. Если надо работать на частоте, отличной от той, что даёт кварц, делай делитель на счётчиках. Если не получается сделать делитель, используй PLL (если есть, конечно).
0
Я говорю про оптимизацию программы компилятором. При чем здесь тактовый ген?
0
А, Вы про проверку на быстродействие и оптимизацию трассировки схемы? Сорри, не понял. Тогда смотреть в сторону TimeQuest (например, тут — embedders.org/content/timequest-dlya-chainikov-chast-1-vvedenie и далее по сайту)
0
Очень спасибо, Anatol! С первого предложения было понятно, что будет полезно. Ведь любовь к делу — секрет мастерства! Про то, что можно на кристалл посмотреть — просто глаза открыли! Красота! Только вот вопрос — помимо того, что это даёт лучше понять суть программирования на HDL, практически это как-то применяется?

Очень хотелось бы, чтобы Вы ещё писали. Буду следить :). И думаю, не только мне будут интересны вопросы симуляции проекта и задания ограничений.

Что такое «Behavioral simulation», «Post-translate simulation», «Post-map simulation», «Post-route simulation»? В чём разница, как пользоваться и как это помогает избежать ошибок в железе?

Задание ограничений — вообще для меня пока чёрная магия. Даже вопросы пока не знаю, какие задать :).
0
Повезло вашим студентам, Anatol! Завидую им белой завистью)) Напишите, если не трудно про моделирование с помощью встроенного ISim =)
0
подскажите незнающему
с самого начала выдает такую ошибку


Project_1 это я назвал, когда окно появилось после нажатия кнопки «синтезировать»
0
zalil.ru/31815129 ошибка
0
все, разобрался. Огромное спасибо автору за статью. Как начинающему она мне очень помогает постигать азы)
0
Спасибо!
В VHDL после указания частоты clock 20 МГц получил ошибку [Par 0] Unhandled Xdm exception
Последние строки в Compilation:
EXCEPTION:Xdm:ModelImp.c:794:$Id: ModelImp.c,v 1.28 2009/06/12 19:55:28 jdl Exp $ — Xdm_Exception::CannotWriteFile
file='root_routed.ncd'
FATAL_ERROR:Par:pwr_task.c:66:1.2 — Unhandled Xdm exception Process will terminate. For technical support on this
issue, please open a WebCase with this project attached at www.xilinx.com/support.

В Verilog продвинулся чуть дальше – такую же ошибку получил после «подгонки частоты мигания». В результате – до конца статьи так и не добрался.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.