Jump to content
    

Странные вопросы по VHDL

Приведенный пример построения и есть работа от одного тактового сигнала.

 

Проблема в том, что я, из-за отсутствия формального образования в этой области, активно изобретаю велосипеды. Причем с рулем сзади и треугольными колесами :)

 

Например, я не понимаю, как в Вашем примере мне просто определить, что произошло изменение NewCode с 0 до 1 (именно из-за этого у меня и был rising_edge(NewCode))...

Share this post


Link to post
Share on other sites

Переписал, вроде стало понятнее и проще:

 

process (rst, clk) begin

if rst = '1' then
BreakCode <= '0';
kbdIRQ <= '0';

else

if rising_edge(clk) then

	if NewCode = '1' then
		if ScanCodeT = x"F0" then
			BreakCode <= '1';

			else 
				XTcode <= BreakCode & ScanCodeT(6 downto 0);
				BreakCode <= '0';
				kbdIRQ <= '1';
		end if;

		else
			kbdIRQ <= '0';
	end if;
end if;
end if;	

end process;

 

И даже почти заработало - если убрать из else строчку BreakCode <= '0' , то один раз отрабатывает правильно. Потом, естественно, из-за застрявшего в 1 сигнала BreakCode уже работает неправильно.

 

А вот если вернуть строчку обнуления BreakCode, то старший бит получившегося XTcode всегда равен 0. Я считал, что все изменения внутри такой конструкции произойдут по окончании процесса, но явно ошибался - такое впечатление, что в присвоении XTcode <= BreakCode & ScanCodeT(6 downto 0) всегда используется уже сброшенный в 0 сигнал BreakCode.

 

Я вообще правильно размышляю ?

 

Share this post


Link to post
Share on other sites

надо фундоментально.

 

вы понимаете разницу между

 

if rst = '1' then
...
elseif rising_edge(clk)
..
endif

 

и

 

if rising_edge(clk) then
  if(rst = '1') then
  .... 

  elseif 
  ....

endif

 

 

 

 

 

Share this post


Link to post
Share on other sites

надо фундоментально.

 

вы понимаете разницу между

 

...

 

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

 

Я переписал сейчас:

 

process (rst, clk) begin

if rising_edge(clk) then

if rst = '1' then
	BreakCode <= '0';
	kbdIRQ <= '0';

	elsif NewCode = '1' then

			if ScanCodeT = x"F0" then
				BreakCode <= '1';

				else 
					XTcode <= BreakCode & ScanCodeT(6 downto 0);
					BreakCode <= '0';
					kbdIRQ <= '1';
			end if;

			else
				kbdIRQ <= '0';
end if;
end if;	

end process;

 

но поведение, похоже, вообще не изменилось...

 

 

 

Share this post


Link to post
Share on other sites

асинхронные схемы изначально более сложны в анализе и проектировке. А так же тяжелее синтезируются.

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

 

Вам принципиально чтобы сброс был по фронту ресета, а не по уровню? Задержка в 1 клок на сбросе погоду сделает?

Share this post


Link to post
Share on other sites

Вам принципиально чтобы сброс был по фронту ресета, а не по уровню? Задержка в 1 клок на сбросе погоду сделает?

 

Да мне вообще все-равно - в принципе, там сброс даже не совсем обязательный (по идее, вроде clk сам собой приведет схему в нужное состояние).

 

Главное, я не могу понять, почему (независимо от типа сброса и т.д.) у меня этот долбанный BreakCode исчезает... :(

 

Share this post


Link to post
Share on other sites

едем дальше

 

 

          if rst = '1' then
        BreakCode <= '0';
        kbdIRQ <= '0';
        
        elsif NewCode = '1' then

 

почему состоянию ресета противопоставляется состояние с NewCode ='1' ?

кроме смысла хорошо бы еще читаемость кода повысить.

 

 

отображайте суть

 

if rising_edge(clk) then
        if rst = '1' then
        BreakCode <= '0';
        kbdIRQ <= '0';
    else

           if NewCode = '0' then
               kbdIRQ <= '0';
           endif

           if NewCode = '1' then
                if ScanCodeT = x"F0" then
                 BreakCode <= '1';
                else
                      XTcode <= BreakCode & ScanCodeT(6 downto 0);
                     BreakCode <= '0';
                       kbdIRQ <= '1';
                endif
           endif
endif

 

 

такое поведение вы хотели описать?

 

 

 

 

что мы видим

если на фронт клока

NewCode = '1 и ScanCodeT = x"F0"

то BreakCode <= '1';

 

если на фронт клока

NewCode = '1 и ScanCodeT != x"F0"

то

XTcode <= BreakCode & ScanCodeT(6 downto 0);

BreakCode <= '0';

kbdIRQ <= '1';

 

казалось бы все очевидно, и теперь я задам вопрос, а как меняется переменная NewCode и ScanCodeT?

 

 

 

потому что на самом деле ваша схема выглядит так допустим NewCode = '1

 

if ScanCodeT1 = x"F0" then
   BreakCode <= '1';
endif
if ScanCodeT2 != x"F0"  (простите не помню как будет не равно в ВХДЛ)
   XTcode <= BreakCode & ScanCodeT(6 downto 0);
endif
if ScanCodeT3 != x"F0"  (простите не помню как будет не равно в ВХДЛ)
   BreakCode <= '0';
endif
if ScanCodeT4 != x"F0"  (простите не помню как будет не равно в ВХДЛ)
   kbdIRQ <= '1';
endif

 

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

 

 

 

 

и теперь самое интересное я специально написал ScanCodeT1,ScanCodeT2,ScanCodeT3,ScanCodeT4, потому что

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

и сигнал

ScanCodeT4 в целом не равен ScanCodeT3, ScanCodeT2, ScanCodeT1, они все друг с другом не равны

 

потому что к моменту фронта клока в одной части он дошел и стал 1, в другой еще в пути и там еще 0 и все ваши IF развалятся.... половина выполниться, другая нет

 

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

 

 

есть стандартный метод

if rising_edge(clk) then

Signal2 = Signal1;

Signal1 = InputSignal;

endif

 

 

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

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

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

 

И тогда все заработает как надо

 

 

 

зачем защелкивать 2 раза?

есть еще такая штука метастабильность,

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

 

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

 

 

 

П.С. Я давно не пишу на VHDL, но надеюсь смысл конструкций понятен.

И я вижу внизу iosifk появился:) послушайте его, ему есть что сказать начинающим:)

Share this post


Link to post
Share on other sites

Во первых, огромное спасибо за разъяснения ! Даже хотя пока мне не удалось решить проблему, я реально благодарен всем, тратящим свое время на подобные ответы !

 

Если же ближе к теме, то вроде все слова по отдельности понял, а вот вместе смысл слегка убегает... В каком месте и какой сигнал нужно синхронизировать ? Сначала я подумал, что у меня ScanCodeT действительно не успевает добежать до всех мест (в принципе, и ScanCodeT, и NewCode формируются по восходящему clk), поэтому я задержал NewCode на пол-clk, чтобы ScanCodeT к этому моменту гарантированно устаканился.

 

К сожалению, это не поменяло вообще ничего. Далее перечитал Ваше сообщение и пришел к выводу, что Вы говорите о чем-то другом, но пока понять не могу...

Share this post


Link to post
Share on other sites

если у вас сигналы ScanCodeT и NewCode формируются по восходящему фронту clk то при задании стандартных констраинов на клок вида

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

 

Если же вы используете формируемый по восходящему фронту сигнал, по падающему фронту в надежде что у вас будет клок и еще половинка, то на самом деле у вас будет всего пол клока. Но синтезатор без дополнительных констраинов на установку и удержание сигнала за этим моментом не следит. И если они пишет что все констраины выполнились, то это не значит что сигнал начав свой подъем по восходящему фронту, в ближайший нисходящий фронт окажется везде в поднятом состоянии...

 

Или я что-то не так понял про задержку на полтакта?

В общем не стоит работать по разным фронтам клока, если это не требует особенно чем-то извне. Потому что в этом случае вы теряете проверки синтезатора

 

 

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

 

 

Share this post


Link to post
Share on other sites

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

 

Так какого фига оно не работает ??? :)

 

Вроде все перепробовал, что сам смог придумать, и что посоветовали... Последний вариант:

 

process (rst, clk) begin

if rising_edge(clk) then
if rst = '1' then
	BreakCode <= '0';
	kbdIRQ <= '0';

	else
		if NewCode = '0' then
			kbdIRQ <= '0';
		end if;

        if NewCode = '1' then
			if ScanCodeT = x"F0" then
				BreakCode <= '1';

				else
					XTcode <= BreakCode & ScanCodeT(6 downto 0);
					BreakCode <= '0';
					kbdIRQ <= '1';
			end if;
		end if;
end if;	
end if;

end process;

 

Причем во всех вариантах (не)работоспособность проявлялась совершенно идентично... Мне почему-то кажется, что ларчик должен открываться очень просто - что-то на поверхности...

 

 

Так какого фига оно не работает ??? :)

 

...

 

Мне почему-то кажется, что ларчик должен открываться очень просто - что-то на поверхности...

 

Действительно, все оказалось крайне просто...

 

Схема подразумевает, что сигнал NewCode находится в активном состоянии один цикл клока, и у меня есть отдельный процесс, обеспечивающий это. Так вот, этот процесс не работал :) Как только исправил его, все завелось !

 

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

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...