Описание нескольких однотипных элементов на VHDL с помощью компонентов.

В конце своей предыдущей статьи Что такое VHDL. Простейший пример создания логического элемента в ПЛИС) я затронул описание элемента схемы как «компонента». Эта конструкция используется при так называемом Структурном описании архитектуры.
Я хочу на примере показать как описать несколько однотипных элементов схемы с помощью компонента, а теорию различных стилей описания архитектур оставлю более опытным авторам.

Начнем как всегда с графического изображения структуры нашего устройства. Возьмем схему с одним счетчиком:

Рисунок 1

и дополним ее еще одним таким же счетчиком:

Рисунок 2

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

Устройство изображенное на рис.1 у нас было описано следующим кодом VHDL:


library IEEE;
use IEEE.std_logic_1164.all;


entity one_element is	-- Счетчик 
	port (	
		main_clk, res, enab : in bit; -- вход временной синхронизации, ас. сброс, разрешение.
        counter_out : out integer range 0 to 65535 --выход значения частоты
	);
end one_element;
entity counter is -- описание 16-разрядного счетчика по переднему фпронту
	port (
		c_in,enab_c,res_c:in bit;
		c_out:out integer range 0 to 65535
	);
end counter;

architecture count of counter is -- архитектура данного счетчика
begin
	process (c_in, res_c)
	variable cnt:integer range 0 to 65535;
	begin
		if (res_c='0') then 
                        cnt:=0;
		elsif (c_in'event and c_in='1') then 
			if (enab_c='1') then cnt:=cnt+1;
			end if;
		end if;
		c_out<=cnt;
	end process;
end count;

architecture a of one_element is -- архитектура всего устройства
	component counter  -- счетчик как компонент
	port (
		c_in,enab_c,res_c:in bit;
		c_out:out integer range 0 to 65535
		);
	end component;

begin
	mc: counter -- описание работы главного счетчика
	port map (c_in=>main_clk,enab_c=>enab,res_c=>res,c_out=>counter_out);
end a;




Приведем его в соответствие с нашей новой структурой, изображенной на рисунке 2.

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


entity many_elements is	 
	port (	
		clk1, clk2, res, enab : in bit; -- тактовые входы,  ас. сброс, разрешение.
        counter1_out, counter2_out : integer range 0 to 65535 -- выходы значения частоты
	);
end many_elements;



Структура самого счетчика у нас остается неизменной, значит описание интерфейса и архитектуры элемента мы оставляем неизменными.

А вот описание архитектуры всего устройства нам надо исправить:


architecture a of many_elements is -- архитектура всего устройства
	component counter  -- счетчик как компонент 
	port (
		c_in,enab_c,res_c:in bit;    -- Описание компонента остается неизменным
		c_out:out integer range 0 to 65535  -- т.к. структура счетчика не изменилась
		);
	end component;

begin
        -- назначение сигналов первому счетчику
	c1: counter port map (c_in=>clk1,enab_c=>enab,res_c=>res,c_out=>counter1_out);
        -- назначение сигналов второму счетчику
	c2: counter port map (c_in=>clk2,enab_c=>enab,res_c=>res,c_out=>counter2_out);
 
end a;


Таким образом имея один прототип элемента, описаный как компонент, мы можем описать N-ное количество этихэлементов просто добавляя строчку вида:

	cN: counter port map (c_in=>clkN,enab_c=>enab,res_c=>res,c_out=>counterN_out);

где N у нас порядковый номер элемента.

Это если по быдлокодерски :)

Для описания большого количества одинаковых элементов в VHDL есть еще специальная конструкция, а точнее специальный оператор параллельной генерации generate.
Т.к. в комментах попросили расписать этот момент подробней — приведу синтаксис из книги Библо «Основы языка VHDL»:

generate_label: for generate_parametr_specification
generate concurent statement
end generate [generate_label];

где:

generate_label — метка,
for generate_parametr_specification — аналог обычного цикла for, который задает нам количество генерируемых элементов. Параметром этого цикла не может служить объявленная в проекте переменная или сигнал!!!, потому как это дискретная константа в заданном дискретном диапазоне.
generate concurent statement — сам оператор генерации, параметр которого (concurent statement) записывается в виде <имя создаваемой структуры>:<прототип генерируемого элемента>. Т.е. здесь мы указываем какой именно элемент мы хотим размножить.
После этого обязательно прописывается назначение сигналов оператором port map (...); ,
И в конце — end generate [generate_label]; — конец оператора параллельной генерации.

Существует второй вариант записи оператора generate:
generate_label: if condition
generate concurent statement
end generate [generate_label];

Этот вариант работает аналогично обычному оператору if c тем исключением, что не имеет фраз else и elsif

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

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



library IEEE, work;
use IEEE.std_logic_1164.all;

package my is
    type counter_out_type is array (0 to 9) of integer range 0 to 65535;
end;

use work.my.all;

entity many_elements is	 
	port (	
	clk : in bit_vector (0 to 9); -- 10 входных сигналов 
        res, enab : in bit; --  ас. сброс, разрешение.
        counter_out: out counter_out_type -- массив выходов
	);
end many_elements;

entity counter is -- описание 16-разрядного счетчика по переднему фпронту
	port (
		c_in,enab_c,res_c:in bit;
		c_out:out integer range 0 to 65535
	);
end counter;

architecture count of counter is -- архитектура данного счетчика
begin
	process (c_in, res_c)
	variable cnt:integer range 0 to 65535;
	begin
		if (res_c='0') then 
                        cnt:=0;
		elsif (c_in'event and c_in='1') then 
			if (enab_c='1') then cnt:=cnt+1;
			end if;
		end if;
		c_out<=cnt;
	end process;
end count;


architecture a of many_elements is -- архитектура всего устройства
	component counter  -- счетчик как компонент 
	port (
		c_in,enab_c,res_c:in bit;    -- Описание компонента остается неизменным
		c_out:out integer range 0 to 65535  -- т.к. структура счетчика не изменилась
		);
	end component;

begin
        
	g0: for i in 0 to 9 generate all_counters: counter 
                port map (c_in=>clk(i),enab_c=>enab,res_c=>res,c_out=>counter_out(i));
        end generate;
 
end a;



Как видим из примера — описание десятка однотипных элементов практически не привело к увеличению кода. Единственное, что пришлось добавить — это описание пакета package. Пакет это такой блок VHDL-описания, в котором можно объявлять переменные и типы, описывать тела архитектур и процедур. У нас в коде внутри пакета объявлен тип counter_out_type который представляет собой массив 16-ти разрядных выходов счетчиков. Если попытаться просто описать переменную сразу в описании интерфейса а не тип в отдельном пакете — то синтезатор выдаст ошибку, т.к. он очень не любит подобные сложные описания переменных.

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



  • +3
  • 11 марта 2011, 23:37
  • Ultrin

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

RSS свернуть / развернуть
Про взрыв мозга? это камень в мой огород :)? Есть такой вопрос к тем кто интересуется VHDL, надо ли писать справку по языку, типа шпаргалки или хватит уже известных, таких как www.bsuir.by/vhdl/keywords/keywords.htm и www.bsuir.by/vhdl/reference/.
0
Про в зрыв мозга это не про Вас… У меня самого взрыв мозга происходит уже при слове ПЛИС. Про чтение даташита на английском или того же Библо на русском я просто молчу… :)
0
Ну книга Бибило одна из простейших, мне кажется на эту тему и с нее надо начинать знакомство с языком, а про архитектуру спартана можно почитать здесь www.plis.ru/pic/pict/File/Spartan3.pdf, там же и про Virtex, а новые поколения 6 и 7 хорошо расписаны на русском в журнале Компоненты и технологии.
0
Спасибо за ссылку. А книжка действительно хорошая, но если в первый раз в эту тематику лезешь — приходится прочитывать 2-3 раза прежде чем начинаешь хоть чуть чуть курить тему…
0
Ссылка не работает. Читал в свое время Бабило. Мое субъективное мнение — ерунда ничем не связаная с практикой. Лучший вариант — воспользоваться примерами готовых модулей на VHDL, например из opencores.org. Это дает свои плоды, например типа fft vhdl acvarif.info/prvhdl/prvhdl25.html
0
Напишите про то как эффективнее писать (что лучше будет синтезироваться)
0
это пусть опытные люди пишут… для меня это пока темный лес…
0
блин, ответ-т не мне адресован… :)))
0
На лекциях Бибило я понимал материал быстрее, чем когда я сам читал его книгу. Хотя диктовал он почти слово в слово из книги :{
0
Харизма у него значит такая :)
0
У меня книжка старенькая. Возможно новые он перефразировал. Опять же когда преподаватель дает новую информацию — он основывается на предыдущей, а когда сам начинаешь разбирать с 0 — вылазит общая нехватка знаний по теме. Просто теорию читать нудно, хочется же сразу диодиком поморгать…
0
Внес исправления в код, т.к. опять накосячил…
0
а можно поподробнее про generate?
сиснтаксис, применение)
0
Добавил описание generate в конец статьи перед последним примером.
0
Вообще оператор generate можно считать оператором повторения для параллельных операторов, так легче понять его смысл.
0
Исправил ошибку в последнем примере. Теперь все компилируется нормально. Спасибо Анатолию.
0
Щас тоже решил заняться ПЛИСами соответственно вышел на структурное программирование. Так вот что интересно при попытке поспроизвести ваши примеры выяснилось что тип сигналов in и out обязательно должен быть bit никак не std_logic, никаких rising_edge а именно, как у вас
c_in'event and c_in='1'
, вообще я щас пробую структурно собрать приемопередатчик uart, собрал делитель с приемником — собрались,- прилепил туда-же передатчик — кончилось тем что квартус сказал, что не понимает что такое плюс. Может у меня квартус старый?(9.1)
0
Что харАктерно-) Выличилось при помощи перенесения каждого entity в свой файл с соответствующим названием, и обратной заменой типа bit на как было раньше std_logic -) VHDL это жостко-))) Всех с Новым Годом!!!
0
Да, и rising_edge, если для каждого entity свой файл можно оставить-)
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.