nabbla (nabbla1) wrote,
nabbla
nabbla1

Categories:

Им бы эти Hazard'ы взять и отменить!

"Программа захвата", которая управляет видеопроцессором и определяет координаты ярких точек и их примерный размер, в первом приближении готова. Хотя бы она компилируется, аж в 85 слов кода. Весьма увесисто, но могло быть ГОРАЗДО ХУЖЕ...

При этом из-за более интенсивной работы с памятью, чем раньше, довольно много Hazard'ов повыскакивало, аж 5 штук. И самый первый из них привлёк моё внимание:

	@@MidCycle:	Y	X
			X	[X+k]								
			Acc	[X+k]


Здесь X указывал на "текущую точку" из списка, а теперь нужно перейти на следующую, и убедиться, что это реальная точка, а не "фиктивная", стоящая в конце списка, чтобы не проверять по сотне раз.

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

Затем нужно "двинуться вперёд", для чего X присваиваем значение [X], т.е значение из памяти по адресу X. И не будь у нас последней "фиктивной" точки, сам X и надо было проверить на Null / Nil / NullPtr, на пустой указатель в общем. Но так нужно сделать ещё один переход, проверить, что рассматриваемый нами элемент дальше уже никуда не указывает. Если так - это и есть наш фиктивный элемент, а его обрабатывать уже не надо.

Между двумя нижними строчками возникает конфликт (Hazard), поскольку команда на запись выполняется с задержкой на такт и совпадает по времени с очередной командой на чтение. И выходит, что мы пытаемся запросить [X] в то же самое время, когда только заносим в X новое значение. Это приведёт к обращению по старому адресу, что нарушит наши планы.

Это понятно. А можно ли как-то это "разрулить", чтобы не пришлось добавлять NOP?

ДА, МОЖНО, но для этого мы должны приказать нашему компилятору ЗАТКНУТЬСЯ!


Вот оно, решение:

	X	[X+k]								
	Y	X	;нам здесь нужно СТАРОЕ ЗНАЧЕНИЕ X, и если не вставлять NOP, ТАК ОНО И БУДЕТ!
	Acc	[X+k]	


Две конфликтующие команды мы разнесли, поставив между ними строку
Y   X

которая раньше шла первой. И говорим: на самом деле в Y запишется старое значение X, ещё до того как сработает присвоение из предыдущей строки!

Если только компилятор не вставит туда свой NOP - тогда всё рассыплется.

Дурное дело нехитрое, и мы добавили новую директиву для компилятора:
	X		[X+k]								
	%CheckHazards	OFF						
	Y		X	;нам здесь нужно СТАРОЕ ЗНАЧЕНИЕ X, и если не вставлять NOP, ТАК ОНО И БУДЕТ!
	%CheckHazards	ON						
	Acc		[X+k]	


Тогда он эту строку оставляет в покое - и всё выполняется так, как мы задумали.

Пробуем откомпилировать ещё разок, ожидая, что теперь одним Hazard'ом станет меньше - и НЕ ТУТ-ТО БЫЛО!

Я как-то совсем забыл о строчке выше. Так оно было в первоначальном варианте:
	@@DoMerge:	[Z+1]	[SP]	;пока так			
	;теперь надо посмотреть - а есть ли точка? Или мы уже прошли последний отрезок между точками?
	;но у нас в конце списка правая фиктивная точка - её надо игнорировать!
	@@MidCycle:	Y	X
			X	[X+k]								
			Acc	[X+k]		;а вот это уже ссылка дальше


Длинные комментарии как-то отвлекли от того факта, что эти команды выполняются друг за дружкой! В этом, исходном варианте, первые две команды не конфликтуют. А вот после добавления директивы %CheckHazards OFF и замены двух строк местами ситуация меняется:
	@@DoMerge:	[Z+1]		[SP]	;пока так			
	;теперь надо посмотреть - а есть ли точка? Или мы уже прошли последний отрезок между точками?
	;но у нас в конце списка правая фиктивная точка - её надо игнорировать!
	@@MidCycle:	X		[X+k]								
			%CheckHazards 	OFF						
			Y		X	;нам здесь нужно СТАРОЕ ЗНАЧЕНИЕ X, и если не вставлять NOP, ТАК ОНО И БУДЕТ!
			%CheckHazards 	ON						
			Acc		[X+k]	


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

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

Правильное решение крылось в строках чуть ниже:
	@@MidCycle:	Y	X
			X	[X+k]								
			Acc	[X+k]		;а вот это уже ссылка дальше
			SUB	0
			JL	@@FinalRange	;наткнулись на NULL, значит, все точки обработали...		


Можно не заносить значение в аккумулятор и вычитать ноль, а сделать всё наоборот: обнулить аккумулятор и вычесть из него значение, ну и прыжок JL (Jump if Less) заменить на JGE (Jump if Greater or Equal):
	@@MidCycle:	Y	X
			X	[X+k]								
			Acc	0
			SUB	[X+k]
			JGE	@@FinalRange	;наткнулись на NULL, значит, все точки обработали...


Всё, теперь Hazard исчез, осталось всего 4 NOP'а в разных местах программы.

Так что в итоге новые директивы не понадобились, но раз уж ввёл - пусть будут, когда-нибудь могут пригодиться.
Tags: ПЛИС, программки, работа, странные девайсы
Subscribe

  • Лестница для самых жадных

    В эти выходные побывал на даче, после 3-недельной "самоизоляции". Забавно, как будто зима началась! Особенно грязные галоши остались на улице, в…

  • Возвращаемся к макету

    Очень давно макетом видеоизмерителя параметров сближения не занимался: сначала "громко думал" по поводу измерения его положения на аппарате, а потом…

  • Минутка живописи

    В процессе разгребания содержимого квартиры (после нескольких ремонтов) дошёл, наконец, и до картин. В кои-то веки их повесил. Куда их вешать -…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 0 comments