Jump to content
    

Констрейны для выходных сигналов

Схему этого монстра представляете? Вот что представили - то и синтезит :)

 

Ну, скажете тоже, монстр... Внутри там, грубо говоря, просто пара логических элементов, выходы которых заведены на асинхронные S и R. Классика жанра - К155ИЕ7. Оно становится монстром, когда проектировщики пожидились сделать одновременно и R и S триггеру.

 

Для тулзы понятия асинхронные\синхронные клоки нет

Это, как сказать.

Пишем латису BLOCK INTERCLOCKDOMAIN PATHS, и вот оно, умолчание проинвертировано...

 

2) "сдвиговый регистр с асинхронной загрузкой" - это регистр на латчах + мультиплексор имитирующий сдвиг + счётчик чтобы мультиплексор перебирать (обычно уже есть)

Это вместо латч+2 флопа....

Это, опять же, когда как. Если в технологии имеется регистр с ALOAD, как например, в альтере, то такое городить не надо.

Share this post


Link to post
Share on other sites

1) асинхронное решение - плохое решение

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

 

"сдвиговый регистр с асинхронной загрузкой" - это регистр на латчах + мультиплексор имитирующий сдвиг + счётчик чтобы мультиплексор перебирать

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

я заменил

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

 

3) тут биться не надо

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

Смотрите выше что будет если много create_clock в схеме

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

Share this post


Link to post
Share on other sites

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

это время определяется наибольшим временем между соурс и дестинейшен клок эджем.

Или set_max_delay для этого пути

 

Share this post


Link to post
Share on other sites

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

Это, для верилог-программиста плохое решение. Потому, что он сути в железе происходящего не понимает. А так, вполне хорошее решение, если понимать эту суть :)

Share this post


Link to post
Share on other sites

Это, для верилог-программиста плохое решение. Потому, что он сути в железе происходящего не понимает. А так, вполне хорошее решение, если понимать эту суть sm.gif

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

 

сделал я 3 модулечка...

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

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

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

 

module AsyncSPI_reciever_v1_00(
		spi_cs, 			  //выбор модуля
		spi_clk,			  //клок SPI
		spi_data_in,	  //входные данные
		data, 					//принятые данные
		data_received   //сигнал что очередное слово принято
   );

	//================================================================================
==
	parameter SPI_WORD_SIZE = 8;  			//размер принимаемого слова
	parameter SPI_BIT_COUNTER_SIZE = 4; //размер регистра счетчика принятых бит
	//число бит до конца приема, за которое сбрасывают сигнал прошлого принятого слова
	parameter RECIVED_SIGNAL_CLEAR = 4; //за 4 бита до конца 



	//================================================================================
==
	input spi_cs;
	input spi_clk;
	input spi_data_in;

	output reg [sPI_WORD_SIZE - 1 : 0] data = 0;
	output reg data_received = 0;

	//сдвиговый приемный регистр, на 1 бит меньше принимаемого слова
	reg [sPI_WORD_SIZE - 2 : 0] ShiftReg = 0; 

	//счетчик принимаемых бит
	reg [sPI_BIT_COUNTER_SIZE - 1 : 0] BitCounter = SPI_WORD_SIZE;


	always @(posedge spi_clk or posedge spi_cs)
		begin
			if(spi_cs == 1'b1) // используем CS как асинхронный set/reset
				begin
					BitCounter <= SPI_WORD_SIZE; //обновляем счетчик
					data_received <= 0; //снимаем сигнал принятого слова
				end
			else
				begin
					//каждый такт сдвигаем данные, запоминаем новые поступившие данные
					ShiftReg <= {ShiftReg [sPI_WORD_SIZE - 3 : 0], spi_data_in};

					//каждый такт уменьшаем счетчик принятых бит
					BitCounter <= $unsigned(BitCounter) - 1'b1;

					if (BitCounter == (RECIVED_SIGNAL_CLEAR + 1))
						data_received <= 1'b0; //снимаем сигнал что данные приняты

					if(BitCounter == 1) //на последнем бите
						begin
							BitCounter <= SPI_WORD_SIZE; //обновляем счетчик
							data <= {ShiftReg, spi_data_in}; //сохраняем данные на выход
							data_received <= 1'b1; //выставляем сигнал что данные приняты
						end
				end	
		end

endmodule



module AsyncSPI_CheckSum_Counter_v1_00(
		spi_cs, 			  //выбор модуля
		spi_clk,			  //клок SPI
		spi_data_in,	  //входные данные
		check_sum 		  //полученная контрольная сумма
   );

	//================================================================================
==
	parameter SPI_CHECK_SUM_SIZE = 8;  											  //размер контрольной суммы
	parameter SPI_CHECK_SUM_WORD_SIZE = SPI_CHECK_SUM_SIZE;  	//размер слова по которому идет суммирование
	parameter SPI_BIT_COUNTER_SIZE = 4; 											//размер регистра счетчика принятых бит
	parameter SPI_BEGIN_SUM_VALUE = 16'hA5; 								  //начальное значение при расчете суммы


	//================================================================================
==
	input spi_cs;
	input spi_clk;
	input spi_data_in;

	output reg [sPI_CHECK_SUM_SIZE - 1 : 0] check_sum = SPI_BEGIN_SUM_VALUE;

	//сдвиговый приемный регистр, на 1 бит меньше слова суммы
	reg [sPI_CHECK_SUM_WORD_SIZE - 2 : 0] ShiftReg = 0; 

	//счетчик принимаемых бит
	reg [sPI_BIT_COUNTER_SIZE - 1 : 0] BitCounter = SPI_CHECK_SUM_WORD_SIZE;


	always @(posedge spi_clk or posedge spi_cs)
		begin
			if(spi_cs == 1'b1) // используем CS как асинхронный set/reset
				begin
					BitCounter <= SPI_CHECK_SUM_WORD_SIZE; //обновляем счетчик
					check_sum <= $unsigned(SPI_BEGIN_SUM_VALUE); //начальное значение суммы
				end
			else
				begin
					//каждый такт сдвигаем данные, запоминаем новые поступившие данные
					ShiftReg <= {ShiftReg [sPI_CHECK_SUM_WORD_SIZE - 3 : 0], spi_data_in};

					//каждый такт уменьшаем счетчик принятых бит
					BitCounter <= $unsigned(BitCounter) - 1'b1;

					if(BitCounter == 1) //на последнем бите
						begin
							//считаем контрольную сумму очередного слова
							check_sum	<= $unsigned(check_sum) + $unsigned({ShiftReg, spi_data_in});
							BitCounter <= SPI_CHECK_SUM_WORD_SIZE; //обновляем счетчик
						end
				end	
		end

endmodule



module AsyncSPI_sender_v1_00(
		spi_cs, 			  //выбор модуля
		spi_clk,			  //клок SPI
		spi_data_out,	  //выходные данные
		data, 					//данные для отправки
		data_can_change //сигнал что входные данные могут быть изменены
   );

	//================================================================================
==
	parameter SPI_WORD_SIZE = 8;  			//размер отправляемого слова
	parameter SPI_BIT_COUNTER_SIZE = 4; //размер регистра счетчика отправляемых бит
	//число бит до конца передачи, за которое поднимается сигнал о возможности смены входного слова
	parameter CHANGE_SIGNAL_SET = 4; //за 4 бита до конца 



	//================================================================================
==
	input spi_cs;
	input spi_clk;
	output spi_data_out;

	input [sPI_WORD_SIZE - 1 : 0] data;
	output reg data_can_change = 0;

	//сдвиговый передающий регистр, на 1 бит меньше передаваемого слова
	reg [sPI_WORD_SIZE - 2 : 0] ShiftReg = 0; 

	//счетчик передаваемых бит
	reg [sPI_BIT_COUNTER_SIZE - 1 : 0] BitCounter = SPI_WORD_SIZE;

	//выходное значение формируется через мультиплексор
	//для начального бита берется из входных данных
	//для последующих бит из сдвигового регистра
	assign spi_data_out = (BitCounter == SPI_WORD_SIZE) ? data[sPI_WORD_SIZE - 1] : ShiftReg [sPI_WORD_SIZE - 2];

	always @(posedge spi_clk or posedge spi_cs)
		begin
			if(spi_cs == 1'b1) // используем CS как асинхронный set/reset
				begin
					BitCounter <= SPI_WORD_SIZE; //обновляем счетчик
					data_can_change <= 0; //снимаем сигнал смены входного слова
				end
			else
				begin
					//для первого бита, запоминаем значение входного слово
					//со сдвигом в 1 бит, который уже отправлен в этом такте
					if(BitCounter == SPI_WORD_SIZE)
						ShiftReg <= data[sPI_WORD_SIZE - 2 : 0];
					else //для остальных бит, сдвигаем регистр
						ShiftReg <= (ShiftReg << 1); //чем заменяем выдвинуты бит не важно

					//каждый такт уменьшаем счетчик принятых бит
					BitCounter <= $unsigned(BitCounter) - 1'b1;

					if (BitCounter == (CHANGE_SIGNAL_SET + 1))
						data_can_change <= 1'b1; //ставим сигнал возможной смены слова

					if(BitCounter == 1) //на последнем бите
						begin
							BitCounter <= SPI_WORD_SIZE; //обновляем счетчик
							data_can_change <= 0; //снимаем сигнал возможности смены входного слова
						end
				end	
		end

endmodule

 

 

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites

что опять то не так?

вроде все сделал по заветам:)...

 

осталось обконстраинить

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

пути передачи данных из одного домена до другого чтобы паузу определить

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

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

можно начать передавать данные после снятия чипселекта

 

и все...

гарантированная задержка в синхронной части будет

сетап + путь, выдержав ее данные точно будут готовы

 

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

 

Вообще у меня некая путаница в том что есть setup и что есть hold и что есть макс делай, но с этим буду разбираться...

Share this post


Link to post
Share on other sites

Вообще у меня некая путаница в том что есть setup и что есть hold и что есть макс делай, но с этим буду разбираться...

 

Времянки триггера:

setup (Tsu) - за сколько времени до фронта клока, не менее, на входе данных должны быть стабильные данные после их последней смены.

hold (Th) - сколько времени после фронта клока, не менее, на входе данных должны удерживаться стабильные данные перед следующей их сменой.

recovery (Tr) - через сколько времени после снятия асинхронного сигнала (загрузки, резета, установки), не менее, можно подать фронт клока.

removal ( Tm ) - через сколько времени после фронта клока, если он был при активном сигнале асинхронного управления, не менее, можно снимать асинхронное управление.

Clock-to-output (Tco) - через сколько времени после фронта клока обновятся данные на выходе.

propagation time (Tpd) - через сколько времени после активизации сигнала асинхронного управления, либо при изменении асинхронных данных, произойдет изменение на выходе.

 

Времянки для латча:

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

hold (Th) - сколько времени, не менее, должны удерживаться данные неизменными после снятия сигнала загрузки, чтобы данные защелкнулись.

propagation time (Tpd) - через сколько времени после активизации сигнала загрузки, либо при изменении асинхронных данных, произойдет изменение на выходе.

 

Времанки для логики:

propagation time (Tpd) - через сколько времени произойдет изменение выхода после того, как произойдет изменение на входе.

 

так вот - все эти set_max_delay, set_input_delay, set_output_delay всегда ограничивают одно и то же - propagation time пути между точками from и to, так, чтобы оно обеспечило выполнение требований по setup/hold/recovery/removal, заданных в базе данных внутренних структур ПЛИС, и (если они заданы) в input/output delay. В принципе, это все методы описания одного и того же. Один и тот же констрейн можно описать и через set_max_delay, и через set_input/output_delay. Разница в том, что первый способ ограничивает напрямую время распространения, а второй - косвенно - input/output_delay вычитается из периода клока, заданного для этой цепи, и делается тот же set_max_delay для полученного значения.

 

Итого - задавать "какой-то сетап/холд" надо ТОЛЬКО тогда, когда сигнал идет наружу из ПЛИС, к кому-то, чей сетап/холд надо сообщить среде. Это делается через задание output_delay. Задавать какой-то "clock-to-output" надо тогда, когда сигнал идет откуда-то снаружи в ПЛИС, и надо сообщить среде этот самый clock-to-out этого кого-то, и задается это через set_input_delay. Все остальные случаи обычно задаются как max_delay.

 

Среда сама знает все setup/hold/recovery/removal/Tco/Tpd для всего, что есть внутри ПЛИС без каких либо их заданий, на то она и среда, чтобы это все знать.

 

Еще раз - изучите цифровую схемотехнику наконец-то!!!! Эти все сетапы (время установления), холды (время удержания), времена распространения, восстановления, снятия (propagation/recovery/removal), это самые азы оттуда! Ну сколько же можно одно и то же говорить!

Share this post


Link to post
Share on other sites

Спасибо, надо осмыслить...

 

Еще раз - изучите цифровую схемотехнику наконец-то

хорошо, завтра выучу.... %)

это не быстро, я в процессе... сразу только кошки родятся...

 

 

Путаница у меня потому что есть такой параметр через сколько после фронта значение сигнала становиться верным, и где то я видел ему название setup, время установки...

Share this post


Link to post
Share on other sites

Путаница у меня потому что есть такой параметр через сколько после фронта значение сигнала становиться верным, и где то я видел ему название setup, время установки...

 

Он бывает обозван propagation delay (clk, out) - Tpd(clk,out), а бывает - Clock to output - Tco(out), но сетапом (именно, англ. setup) - никогда. сетап (как и hold, recovery, removal) это, наоборот, требование к входным сигналам, а не свойство выходного.

 

А вот русское "время установления" - оно бывает приделано и к тому (сетапу), и к этому (Tpd/Tco). Попадаются формулировки "время установления кода", "время установления выхода счетчика", и т.п., и, да, это вызывает путаницу. Пользуйтесь однозначной англоязычной терминологией.

Share this post


Link to post
Share on other sites

Итого - задавать "какой-то сетап/холд" надо ТОЛЬКО тогда, когда сигнал идет наружу из ПЛИС, к кому-то, чей сетап/холд надо сообщить среде. Это делается через задание output_delay. Задавать какой-то "clock-to-output" надо тогда, когда сигнал идет откуда-то снаружи в ПЛИС, и надо сообщить среде этот самый clock-to-out этого кого-то, и задается это через set_input_delay. Все остальные случаи обычно задаются как max_delay.

 

Среда сама знает все setup/hold/recovery/removal/Tco/Tpd для всего, что есть внутри ПЛИС без каких либо их заданий, на то она и среда, чтобы это все знать.

 

Еще раз - изучите цифровую схемотехнику наконец-то!!!! Эти все сетапы (время установления), холды (время удержания), времена распространения, восстановления, снятия (propagation/recovery/removal), это самые азы оттуда! Ну сколько же можно одно и то же говорить!

Правильно.

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

Все остальное - забота тулзов. Все эти сетап\холды надо понимать только для интерпретации еррор меседжев тулзы.

 

В случае-же когда сигналы выходят наружу и надо сформировать времянку заданной формы (с требуемыми задержками), то это можно указать тулзе при помощи упомянутых set_input/output_delay, set_max\min_delay. Надо лиш разобраться в в опциях этих команд и вс станет ясно.

 

Путаница у меня потому что есть такой параметр через сколько после фронта значение сигнала становиться верным, и где то я видел ему название setup, время установки...

Если не задано set_input/output_delay, set_max\min_delay, то значение после фронта на тригере источнике имеет право прийти на тригер примник через время в диапазоне:

минимум: холд тайм примника

максимум: Разница между еджами на источнике и примнике - пропагейшен источника - сетап примника

Share this post


Link to post
Share on other sites

С констраинами боле менее все получилось.

 

Для ксалинкса будет что-то вроде

 

NET "clk_pin" TNM_NET = clk_pin;
TIMESPEC TS_clk_pin = PERIOD "clk_pin" 20 ns HIGH 50%;
#данные на входе будут готовы за 8 ns до восходящего фронта
OFFSET = IN 8 ns VALID 10 ns BEFORE "clk_pin" RISING;
#данные на выходе должны быть готовы не позже 8 нс после фронта 
OFFSET = OUT 8 ns VALID 10 ns AFTER "clk_pin" RISING;


NET "encoder_spi_clk" TNM_NET = encoder_spi_clk;
TIMESPEC TS_encoder_spi_clk = PERIOD "encoder_spi_clk" 20 ns HIGH 50%;
#данные меняются по падающему клоку, за 10 нСек до восходящего 
#клока и остаются валидными весь цикл 20 нСек
#зададим с запасом за 5 нСек, и валидными 10 нСек
#данные на входе будут готовы за 8 ns до восходящего фронта
OFFSET = IN 5 ns VALID 10 ns BEFORE "encoder_spi_clk" RISING;
#данные на выходе должны быть готовы не позже чем за 5 нс до фронта 
OFFSET = OUT 5 ns VALID 10 ns BEFORE "encoder_spi_clk" RISING;


NET "comm_spi_clk" TNM_NET = comm_spi_clk;
TIMESPEC TS_comm_spi_clk = PERIOD "comm_spi_clk" 20 ns HIGH 50%;
#данные меняются по падающему клоку, за 10 нСек до восходящего 
#клока и остаются валидными весь цикл 20 нСек
#зададим с запасом за 5 нСек, и валидными 10 нСек
#данные на входе будут готовы за 5 ns до восходящего фронта
OFFSET = IN 5 ns VALID 10 ns BEFORE "comm_spi_clk" RISING;
#данные на выходе должны быть готовы не позже чем за 5 нс до фронта 
OFFSET = OUT 5 ns VALID 10 ns BEFORE "comm_spi_clk" RISING;

#между доменный переход
#глобальный клок после PLL
NET "glb_clk" TNM_NET = glb_clk;
#ограничение времени распространения данных из 
#основного домена в домены SPI и обратно
#зададим время распространения в пол величины быстрого клока
TIMESPEC TS_glb_comm = from "glb_clk" to "comm_spi_clk" 5 ns DATAPATHONLY;
TIMESPEC TS_glb_encoder = from "glb_clk" to "encoder_spi_clk" 5 ns DATAPATHONLY;
TIMESPEC TS_comm_glb = from "comm_spi_clk" to "glb_clk" 5 ns DATAPATHONLY;
TIMESPEC TS_encoder_glb = from "encoder_spi_clk" to "glb_clk" 5 ns DATAPATHONLY;

 

Вроде бы все славно. Из немного беспокоящих непонятностей осталось вот что:

 

NET "glb_clk" TNM_NET = glb_clk; - это определяет группу всех зависимых элементов от glb_clk.

есть вариации

NET "glb_clk" TNM_NET = FFS glb_clk; - все синхронные триггеры, сдвиговые регистры и прочее

NET "glb_clk" TNM_NET = LATCH glb_clk; - все чувствительные к уровню защелки

 

Вопросы:

1. Если не указать предопределенную группу FFS, LATCH... и так далее, означает ли что будут рассмотрены все возможные элементы и латчи и триггеры и память и прочее?

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

3. В каких элементах спрятаны чувствительные к уровню латчи? То есть если у меня все происходит по posedge clk может так оказаться что мне синтезатор где-то латч запихает? В каких конструкциях оно может быть спрятано?

 

 

4. И совсем глупый вопрос, до этого я понимал как читать Timing constrain report, но сейчас получив очередной репорт и поглядев подробнее откуда и куда там что идет, как распределяются пути понял что возможно я не очень точно трактую показания его столбцов. Порыл инет на этот счет и что-то стало еще хуже. Можно на пальцах что есть worst case slack и best case Achievable?

 

 

 

 

 

 

 

 

Все эти сетап\холды надо понимать только для интерпретации еррор меседжев тулзы.

я не правильно применял эти слова, ими я называл нечто другое...

 

еще забыл,

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

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...