Перейти к содержанию
    

VHDL тестбенч, процессы и процедуры

дано: блок управления термодатчиком с ИНАУТ портом (1-WIRE). тестбенч, который рулит этим портом в соответствии с протоколом 1-WIRE и внутренним алгоритмом работы блока и термодатчика. в тестбенче нюхается перепад на шине 1->0 и запускаются соответствующие ветки обработки, в зависимости от того какой это слот - сброс, запись 0, запись 1, чтение. все работает

 

задача: сделать тестбенч, который будет управлять НЕСКОЛЬКИМИ такими однотипными блоками и их 1-WIRE шинами, который объединены в 1 вектор (каждый бит которого - шина отдельно взятого блока). сделать надо красиво - параметризируемо и работающее в автомате.

 

 

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

 

с параметризацией модуля вопросов не возникает. проблема с красивой рулежкой 1-WIRE шинами. пока что додумался только до того, чтобы забить код управления одной шиной в процедуру, и вызывать ее каждый раз когда меняется состояние общей шины. но на этом этапе столкнулся с проблемой - блоки работают абсолютно идентично и дергают шину в одно и то же время, в коде управления шиной присутствуют задержки. соответственно при одновременном "запросе" на обработку запускается первая процедура, обрабатывается какое то время, затем запускается вторая. но времянка для второй уже убежала и блок термодатчика уходит в обработку этой сдвинутой времянки, через какое то время выставляет новый "запрос" на обработку и если в этот момент первый датчик не работает, то запускается процедура

 

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

 

это код управления одним датчиком:

pr_wire:process
begin

wait until wire'event;
if wire'event and wire='0' then
		wire<='Z';
		--если нет флага рукопожатия, то датчик в режиме ожидания. запуск проверки сброса
		if f_hs=false then	
				--отсчитываем минимальное время удержания мастером шины в 0 (480мкс)
				wait for 480 us;

				--мaстер отпускает шину. ждем 15мкс пока она подтянется к 1
				wait for 15 us;

				--мастер отдал шину, датчик выставляет ответ и удерживает его минимум 60мкс, отпускаем шину
				if f_hs_first=true then wire<='1';
				else wire<='0';
				end if;
				wait for 60 us;
				wire<='Z';

				ct_slot<=15;
				if f_hs_first=true then f_hs_first<=false;
				else f_hs<=true;
				end if;

		--если прошел процесс рукопожатия и нет признака команды чтения, значит датчик находится в режиме ожидания команды. тогда:
		--если через 1мкс (по протоколу, на модели будем ждать 2мкс) шина=0 и УБУФ=0, значит идет запись 0
		--если через 1мкс (по протоколу, на модели будем ждать 2мкс) шина=1 и УБУФ=1, значит идет запись 1
		else
			wait for 2 us;

			--прием команды
			if f_rd=false then	rgd_in(ct_slot)<=wire;
						ct_slot<=ct_slot-1;
						--если конец записи - анализ принятого данного
						if ct_slot=8 then	
							wait for 1 ps;
							--команда "чтение температуры". записать в регистр данных температуру
							if rgd_in(15 downto 8)="H0H0H0H0" then	f_rd<=true;
												rgd<=conv_std_logic_vector(ct_tmp,8);
												ct_tmp<=ct_tmp+1;
												if ct_tmp=4 then ct_tmp<=1;
												end if;
							--команда "чтение регистра статуса". переписать содержимое рг_ст в регистр данных
							elsif rgd_in(15 downto 8)="H0H0HH00" then	wait for 1 ps;
													if f_control_first=true 
														then	f_control_first<=false;		
                                                                                                                               rgd<="00000101";
													else rgd<=rg_st;	
                                                                                                               end if;
							                                                f_rd<=true;	
                                                               --команда "старт преобразования" и "стоп преобразования". обнулить счетчик
							elsif rgd_in(15 downto 8)="HHH0HHH0" or rgd_in(15 downto 8)="00H000H0"
								then	wait for 1 ps;
									ct_slot<=15;
									f_hs<=false;
                                                                               wait for 1 ps;
									rgd_in<="0000000000000000";
						end if;
					--если счетчик дойдет до 0, это значит что идет запись в регистр и дополнительных проверок не надо
					elsif ct_slot=0 then	wait for 1 ps;
								rg_st<=rgd_in(7 downto 0);
								ct_slot<=15;
								--закончилась команда записи в регистр, датчик переводится в режим ожидания следующей команды
								f_hs<=false;
								wait for 1 ps;
								rgd_in<="0000000000000000";
					end if;
			--значит идет чтение
			else
				--выставили на шину значение
				wire<=rgd(ct_slot);
				ct_slot<=ct_slot-1;
				--если выдано последнее данное - сбросить все признаки, обнулить счетчик
				if ct_slot=0 then	wait for 1 ps;
							f_hs<=false;
							f_rd<=false;
							ct_slot<=15;
							wait for 1 ps;
							rgd_in<="0000000000000000";
				end if;
				--удержали его до конца слота (60-2=58мкс), отпустили шину
				wait for 58 us;
				wire<='Z';							
			end if;

		end if;			
end if;
end process;

 

это муки творчества с процедурой:

process_wire: process
procedure procedure_wire(num : in integer) is
	variable f_wr, f_hs, f_rd, rd_tmp: boolean:=false;
	--установка этих сигналов в истину включает имитацию
	--1) не прохождения рукопожатия с первого раза
	--2) не прохождение контроля с первого раза
	--эти фишки проверены и отключены для сокращения диаграммы
	variable f_hs_first, f_control_first: boolean:=false;
	variable ct_slot:integer:=15;
	variable ct_tmp:integer:=1;
	variable rgd, rg_com:std_logic_vector(7 downto 0);
	variable rgd_in:std_logic_vector(15 downto 0);
	variable rg_st:std_logic_vector(7 downto 0):="01010101";
begin
	if wire(num)='0' then
		wire(num)<='Z';
		--если нет флага рукопожатия, то датчик в режиме ожидания. запуск проверки сброса
		if f_hs=false then	
				--отсчитываем минимальное время удержания мастером шины в 0 (480мкс)
				wait for 480 us;

				--мaстер отпускает шину. ждем 15мкс пока она подтянется к 1
				wait for 15 us;

				--мастер отдал шину, датчик выставляет ответ и удерживает его минимум 60мкс, отпускаем шину
				if f_hs_first=true then wire(num)<='1';
				else wire(num)<='0';
				end if;
				wait for 60 us;
				wire(num)<='Z';

				ct_slot:=15;
				if f_hs_first=true then f_hs_first:=false;
				else f_hs:=true;
				end if;

		--если прошел процесс рукопожатия и нет признака команды чтения, значит датчик находится в режиме ожидания команды. тогда:
		--если через 1мкс (по протоколу, на модели будем ждать 2мкс) шина=0 и УБУФ=0, значит идет запись 0
		--если через 1мкс (по протоколу, на модели будем ждать 2мкс) шина=1 и УБУФ=1, значит идет запись 1
		else
			wait for 2 us;

			--прием команды
			if f_rd=false then	rgd_in(ct_slot):=wire(num);
						ct_slot:=ct_slot-1;
						--если конец записи - анализ принятого данного
						if ct_slot=8 then	
							wait for 1 ps;
							--команда "чтение температуры". записать в регистр данных температуру
							if rgd_in(15 downto 8)="H0H0H0H0" then	f_rd:=true;
												rgd:=conv_std_logic_vector(ct_tmp,8);
												ct_tmp:=ct_tmp+1;
												if ct_tmp=4 then ct_tmp:=1;
												end if;
							--команда "чтение регистра статуса". переписать содержимое рг_ст в регистр данных
							elsif rgd_in(15 downto 8)="H0H0HH00" then	wait for 1 ps;
													if f_control_first=true then	f_control_first:=false;
																	rgd:="00000101";
													else rgd:=rg_st;
													end if;
													f_rd:=true;
							--команда "старт преобразования" и "стоп преобразования". обнулить счетчик
							elsif rgd_in(15 downto 8)="HHH0HHH0" or rgd_in(15 downto 8)="00H000H0"
								then	wait for 1 ps;
									ct_slot:=15;
									f_hs:=false;
									wait for 1 ps;
									rgd_in:="0000000000000000";
							end if;
						--если счетчик дойдет до 0, это значит что идет запись в регистр и дополнительных проверок не надо
						elsif ct_slot=0 then	wait for 1 ps;
									rg_st:=rgd_in(7 downto 0);
									ct_slot:=15;
									--закончилась команда записи в регистр, датчик переводится в режим ожидания следующей команды
									f_hs:=false;
									wait for 1 ps;
									rgd_in:="0000000000000000";
						end if;
						wire(num)<='Z';
			--значит идет чтение
			else
				--выставили на шину значение
				wire(num)<=rgd(ct_slot);
				ct_slot:=ct_slot-1;

				--если выдано последнее данное - сбросить все признаки, обнулить счетчик
				if ct_slot=0 then	wait for 1 ps;
							f_hs:=false;
							f_rd:=false;
							ct_slot:=15;
							wait for 1 ps;
							rgd_in:="0000000000000000";
				end if;
				--удержали его до конца слота (60-2=58мкс), отпустили шину
				wait for 58 us;
				wire(num)<='Z';	
				end if;

		end if;	
	end if;
end procedure;	

begin
wait until wire'event;
procedure_wire(1);
procedure_wire(2);
--	if wire(1)='0' then procedure_wire(1);
--	end if;
--	if wire(2)='0' then procedure_wire(2);
--	end if;	
end process process_wire;

 

 

еще результат моделирования

в первой точке первый датчик забивает сброс второму. во второй точке наоборот. плюс во второй точке видно красные тычки по ВАЙР второго датчика - "помехи" от первого

 

а должно быть полностью идентично (скрин2)

post-76333-1492608209_thumb.png

post-76333-1492611808_thumb.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Очевидно, следует использовать GENERATE, и для каждой тестируемой однопроводной шины создать свой экземпляр тестового процесса или модуля. На всякий случай напомню, что внутри GENERATE блока можно локально создавать всё то же, что и в основном блоке архитектуры - константы, процессы, сигналы, последовательные операторы, экземпляры модулей. Кстати, фронта можно ждать оператором wait until wire'event and wire='0';, тогда не нужен IF.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

хочу "засунуть" в процедуру:

AWADDR2 <= b"000001100";
        WDATA2 <= x"A5A5A5A5";
        WSTRB2 <=b"1111";
        sendIt2 <= '1';                
        wait for 1 ns; sendIt2 <= '0';
    wait until BVALID2 = '1';
    wait until BVALID2 = '0'; 
        WSTRB2 <= b"0000";

только передавать данные для сигналов:

AWADDR2 и WDATA2

извне.

 

моя процедура:

procedure write_data (
signal in_addr : in STD_LOGIC_VECTOR(8 DOWNTO 0);
signal in_data  : in STD_LOGIC_VECTOR(31 DOWNTO 0);
signal in_bvalid2  : in STD_LOGIC
signal reg_sendIt2  : out std_logic;
signal out_WSTRB2 : out STD_LOGIC_VECTOR(3 DOWNTO 0);
signal out_WDATA2  : out STD_LOGIC_VECTOR(31 DOWNTO 0);
signal out_AWADDR2 : out STD_LOGIC_VECTOR(8 DOWNTO 0)
) is

begin
     out_AWADDR2 <= in_addr;
        out_WDATA2 <= in_data;
        out_WSTRB2 <= b"1111";
        reg_sendIt2 <= '1';                
        wait for 1 ns; reg_sendIt2 <= '0';
    wait until in_bvalid2 = '1';
    wait until in_bvalid2 = '0';  
        out_WSTRB2 <= b"0000";
end write_data;

 

вызов процедцры:

write_data(r_AWADDR2, r_WDATA2, bvalid2, sendIt2, WSTRB2, wdata2, awaddr2 );

(типы совпадают-правильные)

 

ошибка в моделсиме:

# * Error: No feasible entries for subprogram "write_data".

 

процедура присутствует только в тестбенче

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

# * Error:  No feasible entries for subprogram "write_data".

Если я не ошибаюсь, иногда для процедуры важно место её объявления. Где Вы её объявляете ?

Во всяком случае, у меня процедуры заработали только тогда, когда я их объявил в теле процесса, в котором они запускается.

Изменено пользователем Flip-fl0p

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

хочу "засунуть" в процедуру:

 

ошибка в моделсиме:

# * Error: No feasible entries for subprogram "write_data".

 

процедура присутствует только в тестбенче

 

чтобы была возможность присваивать сигналы внутри процедуры, она должна быть описана в процессе из которого вызывается

 

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

 

никогда не встречал использование GENERATE для "размножения" процесса. а сделать это нужно именно отдельным процессом внутри большого тестбенча, т.к. на топ-лвл от термодатчиков выходит только ВАЙР шина и к ним сигналы управления внешними буферами на плате. а помимо них еще куча всего, чем так же надо рулить. если не сложно покажите пример использования, или ткните ссылкой где это можно посмотреть

 

 

Кстати, фронта можно ждать оператором wait until wire'event and wire='0';, тогда не нужен IF.

 

я в курсе :). это аппендицит от предыдущих вариаций кода - лень было переделывать :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

# * Error:  No feasible entries for subprogram "write_data".

Если я не ошибаюсь, иногда для процедуры важно место её объявления. Где Вы её объявляете ?

Во всяком случае, у меня процедуры заработали только тогда, когда я их объявил в теле процесса, в котором они запускается.

Спасибо большое. Вы абсолютно правы. Tело/объявление процедуры надо было поместить в процесс.

 

чтобы была возможность присваивать сигналы внутри процедуры, она должна быть описана в процессе из которого вызывается

не обязательно :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

моя процедура:

procedure write_data (
  [...]
signal in_bvalid2  : in STD_LOGIC
  [...]
) is

begin
  [...]    wait until in_bvalid2 = '1';
         wait until in_bvalid2 = '0';  
  [...]
end write_data;

Это работать не будет. Аргумент-сигнал не передаётся в процедуру "постоянно", он туда передаётся однократно в момент вызова процедуры. То есть внутри процедуры сигнал превратится в константу, поэтому отслеживать его события бесполезно. Уберите его из аргументов in_bvalid2 и отслеживайте внешний BVALID2.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

вай-вай-вай, все заработало

 

отдельная благодарность Timmy за открытие новой фишки. теперь мои тестбенчи будут еще злее :)

 

 

ARCHITECTURE behavior OF tb_top_test IS 

constant kol_izp:integer:=8;
constant kol_td:integer:=2;

type m_bool is array (1 to kol_td) of boolean; 
type m_int is array (1 to kol_td) of integer; 
type m_vect8 is array (1 to kol_td) of std_logic_vector(7 downto 0); 
type m_vect16 is array (1 to kol_td) of std_logic_vector(15 downto 0);

signal f_wr, f_hs, f_rd, rd_tmp: m_bool:=(others=>false);
--установка этих сигналов в истину включает имитацию
--1) не прохождения рукопожатия с первого раза
--2) не прохождение контроля с первого раза
--эти фишки проверены и отключены для сокращения диаграммы
signal f_hs_first, f_control_first: m_bool:=(others=>false);
signal ct_slot: m_int:=(others=>15);
signal ct_tmp: m_int:=(others=>1);
signal rgd, rg_com: m_vect8;
signal rgd_in: m_vect16;
signal rg_st: m_vect8:=(others=>"01010101");

BEGIN


pr_wire:for i in 1 to kol_td generate	
process
		begin
		wait until wire(i)'event;
		if wire(i)'event and wire(i)='0' then
			wire(i)<='Z';
			--если нет флага рукопожатия, то датчик в режиме ожидания. запуск проверки сброса
			if f_hs(i)=false then

		и далее по тексту...

end process;
end generate

post-76333-1492669875_thumb.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...