FIFO это один из ключевых элементов цифровой техники. Это память типа «первым вошёл-первым ушёл» (first input – first output). Меня как разработчика ПЛИС FIFO окружают повсюду. Собственно я только и делаю что беру данные из одного FIFO и перекладываю в другое. Но как оно работает? В современных САПР конечно уже есть готовые элементы, у Altera есть замечательные мегафункции. У Xilinx есть Core Generator. Но что делать если что-то не устраивает в стандартных решениях? Ответ один – разобраться и написать самому.

В интернете существует большое количество статей про FIFO, и когда то мне попалась очень хорошая и толковая статья. К сожалению, сейчас я её не нашёл. Далее – мой личный опыт по созданию и применению компонента FIFO. Готовый элемент находится на Github в проекте fpga_components. Свой компонент потребовался по нескольким причинам:

  1. FIFO XIlinx не умеет работать в режиме ретрансмита – это главная причина
  2. FIFO Xilinx требует создания компонента с заданными параметрами – у нас развелось слишком много разных компонентов.
  3. FIFO Xilinx содержит ошибку – если приходит сигнал сброса одновременно с сигналом записи данных, то в FIFO застревает одно слово. Это мы конечно обошли, но всё равно неприятно.

Итак, что такое FIFO. В общем случае это двухпортовая память, два счётчика адреса и два автомата – для чтения и записи данных.



Одно из главных применений FIFO это перевод данных с одной тактовой частоты на другую. Этим определяется такая схема. При одной тактовой частоте на запись и чтение автоматы можно упростить.

Давайте рассмотрим внешние порты компонента FIFO:

cl_fifo_m12
component cl_fifo_m12 is   
	generic(
		FIFO_WIDTH : in integer:=64;    -- ширина FIFO
		FIFO_SIZE    : in integer:=4096; -- размер FIFO 
		FIFO_PAF	     : in integer:=16;    -- уровень срабатывания флага PAF  
		FIFO_PAE	     : in integer:=544   -- уровень срабатывания флага PAE  
	);
	 port(				
	 	-- сброс
		 reset_p       : in std_logic; -- 1 - сброс
		 
	 	-- запись
		 clk_wr        : in std_logic;  -- тактовая частота
		 data_in       : in std_logic_vector( FIFO_WIDTH-1 downto 0 ); -- данные
		 data_en      : in std_logic; -- 1 - запись в fifo
		 flag_wr       : out bl_fifo_flag; 	-- флаги fifo, синхронно с clk_wr
		 cnt_wr        : out std_logic_vector( 15 downto 0 ); -- счётчик слов
		 
		 -- чтение
		 clk_rd         : in std_logic;  -- тактовая частота
		 data_out     : out std_logic_vector( FIFO_WIDTH-1 downto 0 );   -- данные

		 data_rd       : in std_logic:='0'; -- 1 - чтение из fifo, данные на втором такте
		 flag_rd        : out bl_fifo_flag;  -- флаги fifo, синхронно с clk_rd
		 cnt_rd         : out std_logic_vector( 15 downto 0 ); -- счётчик слов

		 
		 rt    : in std_logic:='0'; -- 1 - переход на начало в произвольный момент
		 rt_mode : in std_logic:='0' -- 1 - переход на начало после чтения всего содержимого FIFO
		 
	    );
end component;


Настройка компонента:

  • FIFO_WIDTH – ширина FIFO, может быть любая.
  • FIFO_SIZE – число слов в FIFO, это степень двойки, от 64 до 65536. Если нужен больший размер то надо делать составное FIFO.
  • FIFO_PAF – уровень срабатывания флага почти полного FIFO.
  • FIFO_PAE – уровень срабатывания флага почти пустого FIFO, о флагах будет дальше.

Названия портов вполне очевидные, несколько комментариев по флагам:

Флаги FIFO передаются типом bl_fifo_flag; Определение типа:

type bl_fifo_flag is record
	ef		: std_logic; 	-- 0 - FIFO пустое
	pae		: std_logic;	-- 0 - FIFO почти пустое
	hf		: std_logic;	-- 0 - FIFO заполнено наполовину 
	paf		: std_logic;	-- 0 - FIFO почти полное
	ff		: std_logic;	-- 0 - FIFO полное
	ovr		: std_logic;	-- 1 - запись в полное FIFO
	und		: std_logic;	-- 1 - чтение из пустого FIFO
end record;

Обратите внимание, используется отрицательная логика. Узнали? Да, я ещё из тех динозавров кто работал с TTL на сериях 155, 533, 1533 и отдельными микросхемами FIFO. Так что эти флаги мне привычны, они были сделаны много лет назад и до сих пор используются.

Флаг ef – сигнализирует что FIFO пустое. Если ef=1, то из FIFO можно прочитать одно слово.
Флаг pae – сигнализирует, что FIFO почти пустое. На сколько почти определяет параметр FIFO_PAE. Если pae=1, то из FIFO можно прочитать не более чем FIFO_PAE слов.
Флаг hf – сигнализирует что FIFO заполнено наполовину.
Флаг paf – сигнализирует, что FIFO почти полное. На сколько почти определяет параметр FIFO_PAF. Если paf=1, то в FIFO можно записать не более чем FIFO_PAF слов
Флаг ff – FIFO полное. Если ff=0, то в FIFO записывать нельзя.
Флаг ovr – переполнение. Если ovr=1, то это значит что произошла запись в полное FIFO
Флаг und – underflow. Если und=1, то это значит что произошло чтение из пустого FIFO.

Вполне очевидно, что при записи в FIFO мы должны записать слово в двухпортовую память и увеличить счётчик записи. Или сначала увеличить, а потом записать. А при операции чтения надо зафиксировать данные на выходе и увеличить счётчик чтения. А вот дальше требуется решить следующие вопросы:

  1. Как определить что FIFO полное или не полное, т.е. можно ли в него записывать ?
  2. Как определить что FIFO пустое или не пустое? Т.е. можно ли из него читать ?
  3. Как правильно сформировать флаги PAE, PAF, HF ?
  4. Что такое число слов в FIFO ?

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



Надо ясно понимать, что узел перетактирования (в проекте это компонент ctrl_retack_counter_m12) передаёт данные с задержкой на несколько тактов. Поэтому состояния FIFO также изменяются с задержкой. Например, если FIFO пустое и него записано одно слово, то флаг ef=1 появится с некоторой задержкой. Это же относится к выходам количества слов в FIFO. Например, если в пустое FIFO будет записано 16 слов, то в процессе записи выход cnt_wr будет принимать значения 0,1,2,3, … 16 (это если не производится чтение из FIFO), а вот выход cnt_rd будет принимать значения например такие: 0, 5, 8, 12, 16. Точный порядок будет зависеть от соотношения частот и не может быть предсказан. Это принципиальное свойство FIFO которое работает на разных частотах. Хотя в зависимости от схемы синхронизации могут быть различные нюансы.

Определение пустого и полного FIFO производится на анализе счётчиков адресов. Причём у меня есть два адреса для записи (текущий и следующий) и два адреса для чтения, также текущий и следующий. В компоненте cl_fifo_control_m12 это сигналы w_adr, w_next_adr и r_adr, r_next_adr; Соотношение адресов в различных состояниях представлено на рисунках ниже.

В исходном состоянии w_adr=0, r_adr=0, w_next_adr=1, r_next_adr=1. Если w_adr=r_adr, то FIFO пустое.



При записи слово данных записывается по адресу w_adr и адрес записи увеличивается.



Через несколько таков значение w_adr будет передано в w_adr_to_rd (перейдёт в тактовый домен clk_rd) и по факту не совпадения r_adr и w_adr_to_rd будет установлен флаг ef=1, т.е. из FIFO можно будет считать слово данных. Однако одно слово это мало, для получения высокой скорости передачи надо работать с блоком данных. И здесь требуется использовать флаг PAE. Когда в FIFO будет записано FIFO_PAE слов, будет установлен флаг pae=1 и можно будет прочитать сразу блок данных. Это основной режим работы с DMA каналом.

Если скорость записи больше чем скорость чтения, то адрес записи догонит адрес чтения:



В этом случае w_next_adr будет равен r_adr, а точнее r_adr_to_wr (мы можем сравнивать только значения на своём тактовом домене). Это означает, что FIFO полное и записывать дальше нельзя, что бы не испортить уже записанные данные. Надо отметить, что для подключения АЦП это обычная ситуация. У нас такой режим называется однократный сбор через FIFO. В этом режиме АЦП записывает данные на большой скорости в FIFO, а медленный процессор эти данные считывает. При этом мы знаем, что действительными будет только блок данных который соответствует размеру FIFO. Обычно на этот размер как раз и программируется канал DMA. После чтения данных FIFO сбрасывается и всё повторяется снова. Вот в этом режиме принципиально важно, что бы запись в полное FIFO не портила предыдущие данные.

Если требуется записывать данные блоками, то надо использовать флаг PAF. Если paf=1, то в FIFO можно записать FIFO_PAF слов.

Значения флагов PAE и PAF надо выбирать из требований DMA контроллера к которому подключено FIFO. Например, для PCI Express у нас используется блок данных размером 4 кБ. Это 256 слов по 128 разрядов. Размер флага PAE я устанавливаю в 272. Т.е. чуть больше чем 256. Это я делаю намеренно, что бы не допускать опустошения FIFO. Ну не доверяю я схемам формирования флагов.

А как производится определение количества слов в FIFO? Всё достаточно просто – из адреса записи надо вычесть адрес чтения. Адрес кратен степени 2, поэтому вычитание будет идти по модулю 2^N; Поскольку у нас есть две пары адресов, то у нас получится и два значения количества слов в одном FIFO (может это как то связано с квантовой механикой?).

Значения флагов PAE и HF (по чтению) формируются из r_cnt. Значения PAF и HF(по записи) формируются из w_cnt.

Основной причиной, по которой пришлось разрабатывать свой компонент FIFO, является потребность в реализации циклического режима для работы на ЦАП. В этом режиме производится запись блока данных, он может быть любого размера, разумеется не превышая размера FIFO. А затем начинается чтение, причём после выдачи последнего записанного слова сразу происходит переход на первое слово. Это позволяет подключить медленный процессор к быстрому ЦАП. Компонент FIFO имеет два входа для циклического режима. rt_mode=1 означает, что после выдачи последнего записанного слова надо перейти на нулевой адрес.

А вот вход rt нужен немного для другого. Наличие rt=1 позволяет перевести FIFO на нулевой адрес в произвольный момент времени. Иногда это у нас тоже используется.

В проекте fpga_components представлены два FIFO:

  • cl_fifo_x64_v7
  • cl_fifo_m12

cl_fifo_x64_v7 разработан и опубликован достаточно давно. Также он давно используется и доказал свою работоспособность. Он в качестве двухпортовой памяти использует компонент сформированный Core Generator. Для разных размеров FIFO требуются свои компоненты, например в каталоге fpga_components\src\fifo\fifo_v7\coregen находятся четыре компонента

  • ctrl_dpram512x64_v7
  • ctrl_dpram1024x64_v7
  • ctrl_dpram8192x64_v7
  • ctrl_dpram32768x64_v7

И это всё только для шины с шириной 64 разряда. Для других шин и других размеров требуются свои компоненты. Мы их потихоньку делали и к настоящему моменту у нас есть большая куча, с которой работать уже неудобно. Александр Капитанов ( capitanov ) обратил на это внимание и предложил элегантное решение — сделать полностью синтезируемое FIFO. Он это реализовал в своём проекте: github.com/capitanov/adc_configurator Компонент: ctrl_fifo_config. Основная идея в том, что бы применить вот такую конструкцию VHDL:

type RAM is array (integer range <>) of std_logic_vector(DATA_WIDTH-1 downto 0);
signal Mem : RAM (0 to DATA_DEPTH-1);

Это конструкция будет синтезирована в двухпортовую память. Идея красивая и в результате доработки cl_fifo_x64_v7 получилось FIFO cl_fifo_m12.

Недостаточно написать FIFO, надо ещё проверить его работу. Для проверки используется подход принятый при разработке PROTEQ, о котором можно прочитать в моей предыдущей статье.

Существует компонент tb_00 который имеет настраиваемые параметры.

tb_00
component tb_00 is	   
	generic(
		max_time		: in time:=100 us;			-- максимальное время теста 
		period_wr		: in time;	 	-- период частоты записи
		period_rd		: in time;		-- период частоты чтения
		fifo_size		: in integer;	-- размер FIFO 
		FIFO_PAF		: in integer;	-- уровень срабатывания флага PAF  
		FIFO_PAE		: in integer;	-- уровень срабатывания флага PAE  
		max_fifo0_pkg	: in integer	-- число пакетов для приёма
	
	);
end component;


Он позволяет проверить прохождение потока данных через FIFO при различных соотношениях тактовых частот и уровнях срабатывания флагов PAE и PAF. Также существуют компоненты тестовых случаев:

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

В результате формируется вот такой отчёт о запуске тестов:

Global fifo_12 TC log:
tc_00_01 PASSED
tc_00_02 PASSED

Конечно, для каждого теста сохраняется и свой отчёт.

Например такой:

tc_00_01.log
# KERNEL: FIFO 0 - PKG=  1        6310 ns          0 ns ERROR:          0  SPEED:          0
# KERNEL: FIFO 0 - PKG=  2       12022 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=  3       17734 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=  4       23446 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=  5       29158 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=  6       34870 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=  7       40582 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=  8       46294 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=  9       52006 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 10       57718 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 11       63430 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 12       69142 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 13       74854 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 14       80566 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 15       86278 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 16       91990 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 17       97702 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 18      103414 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 19      109126 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 20      114838 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 21      120550 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 22      126262 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 23      131974 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 24      137686 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 25      143398 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 26      149110 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 27      154822 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 28      160534 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 29      166246 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 30      171958 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 31      177670 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 32      183382 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 33      189094 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 34      194806 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 35      200518 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 36      206230 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 37      211942 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 38      217654 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 39      223366 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 40      229078 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 41      234790 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 42      240502 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 43      246214 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 44      251926 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 45      257638 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 46      263350 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 47      269062 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 48      274774 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 49      280486 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 50      286198 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 51      291910 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 52      297622 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 53      303334 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 54      309046 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 55      314758 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 56      320470 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 57      326182 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 58      331894 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 59      337606 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 60      343318 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 61      349030 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 62      354742 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 63      360454 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 64      366166 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 65      371878 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 66      377590 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 67      383302 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 68      389014 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 69      394726 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 70      400438 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 71      406150 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 72      411862 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 73      417574 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 74      423286 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 75      428998 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 76      434710 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 77      440422 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 78      446134 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 79      451846 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 80      457558 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 81      463270 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 82      468982 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 83      474694 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 84      480406 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 85      486118 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 86      491830 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 87      497542 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 88      503254 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 89      508966 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 90      514678 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 91      520390 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 92      526102 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 93      531814 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 94      537526 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 95      543238 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 96      548950 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 97      554662 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 98      560374 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG= 99      566086 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=100      571798 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=101      577510 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=102      583222 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=103      588934 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=104      594646 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=105      600358 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=106      606070 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=107      611782 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=108      617494 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=109      623206 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=110      628918 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=111      634630 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=112      640342 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=113      646054 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=114      651766 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=115      657478 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=116      663190 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=117      668902 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=118      674614 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=119      680326 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=120      686038 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=121      691750 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=122      697462 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=123      703174 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=124      708886 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=125      714598 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=126      720310 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=127      726022 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=128      731734 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=129      737446 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=130      743158 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=131      748870 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=132      754582 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=133      760294 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=134      766006 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=135      771718 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=136      777430 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=137      783142 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=138      788854 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=139      794566 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=140      800278 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=141      805990 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=142      811702 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=143      817414 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=144      823126 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=145      828838 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=146      834550 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=147      840262 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=148      845974 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=149      851686 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=150      857398 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=151      863110 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=152      868822 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=153      874534 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=154      880246 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=155      885958 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=156      891670 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=157      897382 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=158      903094 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=159      908806 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=160      914518 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=161      920230 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=162      925942 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=163      931654 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=164      937366 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=165      943078 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=166      948790 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=167      954502 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=168      960214 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=169      965926 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=170      971638 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=171      977350 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=172      983062 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=173      988774 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=174      994486 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=175     1000198 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=176     1005910 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=177     1011622 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=178     1017334 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=179     1023046 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=180     1028758 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=181     1034470 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=182     1040182 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=183     1045894 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=184     1051606 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=185     1057318 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=186     1063030 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=187     1068742 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=188     1074454 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=189     1080166 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=190     1085878 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=191     1091590 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=192     1097302 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=193     1103014 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=194     1108726 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=195     1114438 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=196     1120150 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=197     1125862 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=198     1131574 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=199     1137286 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=200     1142998 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=201     1148710 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=202     1154422 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=203     1160134 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=204     1165846 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=205     1171558 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=206     1177270 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=207     1182982 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=208     1188694 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=209     1194406 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=210     1200118 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=211     1205830 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=212     1211542 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=213     1217254 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=214     1222966 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=215     1228678 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=216     1234390 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=217     1240102 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=218     1245814 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=219     1251526 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=220     1257238 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=221     1262950 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=222     1268662 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=223     1274374 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=224     1280086 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=225     1285798 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=226     1291510 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=227     1297222 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=228     1302934 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=229     1308646 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=230     1314358 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=231     1320070 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=232     1325782 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=233     1331494 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=234     1337206 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=235     1342918 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=236     1348630 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=237     1354342 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=238     1360054 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=239     1365766 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=240     1371478 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=241     1377190 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=242     1382902 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=243     1388614 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=244     1394326 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=245     1400038 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=246     1405750 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=247     1411462 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=248     1417174 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=249     1422886 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=250     1428598 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=251     1434310 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=252     1440022 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=253     1445734 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=254     1451446 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=255     1457158 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: FIFO 0 - PKG=256     1462870 ns       5712 ns ERROR:          0  SPEED:       1368
# KERNEL: Завершён приём данных:     1463200 ns
# KERNEL: FIFO 0 
# KERNEL:  Принято пакетов:    256
# KERNEL:  Правильных:         256
# KERNEL:  Ошибочных:          0
# KERNEL:  Общее число ошибок: 0
# KERNEL:  Скорость передачи:        1368 МБайт/с
# KERNEL: 
# KERNEL: 
# KERNEL: 
# KERNEL: TEST finished successfully
# KERNEL:


При необходимости тесты будут дополняться. Хочу обратить внимание, что для вывода текста в консоль я использую пакет PCK_FIO. Он резко упрощает вывод текста.

Например, вывод результатов выглядит так:

	fprint( output, L, "Завершён приём данных: %r ns\n", fo(now) );
	fprint( output, L, "FIFO 0 \n" );
	fprint( output, L, " Принято пакетов:    %d\n", fo( rx0_result.pkg_rd ) );
	fprint( output, L, " Правильных:         %d\n", fo( rx0_result.pkg_ok ) );
	fprint( output, L, " Ошибочных:          %d\n", fo( rx0_result.pkg_error ) );
	fprint( output, L, " Общее число ошибок: %d\n", fo( rx0_result.total_error ) );
	fprint( output, L, " Скорость передачи: %r МБайт/с\n\n", fo( integer(rx0_result.velocity) ) );

Это похоже на Си.

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

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


  1. nckma
    13.02.2017 11:02
    +5

    Хм… а почему Вы не стали использовать код грея для передачи указателей фифо через домен? Я думал это стандартное, проверенное временем решение, которое используют все.


    1. dsmv2014
      13.02.2017 12:02
      -2

      Код Грея может спасти только при очень близких частотах. А вот при переходе от 250 МГц к 100 МГц он уже не поможет.


      1. Daffodil
        13.02.2017 12:08
        +2

        Поясните кейс с 250 / 100 МГц


        1. dsmv2014
          13.02.2017 12:52
          -3

          Счётчик на 250 МГц успеет насчитать несколько значений за один такт 100 МГц. И я не понимаю как здесь может помочь год Грея.


          1. GolikovAndrey
            13.02.2017 13:01
            +2

            Это не важно сколько он насчитает.

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

            А имея в любой момент времени либо старое либо новое значение, при это за счет счетчика грея отличающиеся только на 1 бит, вы не можете неправильно обработать заполнение фифо.


            1. dsmv2014
              13.02.2017 13:12
              -2

              | Только если у вас шина со значением настолько расползается по времени

              При асинхронных сигналах тактовой частоты всегда будут ситуации когда разные разряды шины будут защёлкнуты в разное время. Т.е. в другом домене будет часть нового значения а часть старого. А часть вообще будет в метастабильном состоянии. И в этом случае год Грея не поможет.


              1. Daffodil
                13.02.2017 13:58
                +1

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


                1. dsmv2014
                  13.02.2017 14:06

                  Это не так. У меня есть компонент ctrl_retack_counter_m12 Он корректно переводит шину data_in на data_out за несколько тактов. В нём сначала фиксируется значение на data_in, взводится флаг и фиксируется значение на data_out. Далее всё повторяется.


                  1. Daffodil
                    13.02.2017 14:15
                    +2

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


                    1. dsmv2014
                      13.02.2017 17:36
                      +1

                      Теперь я понял что вы опасаетесь. Но смотрите что происходит.
                      Автомат pr_st1 фиксирует data и взводит flag1
                      flag1 переводится в другой домен — flag1to2
                      flag1to2 обнаруживается автоматом pr_st2
                      автомат pr_st2 переходит в состояние s2 и фиксирует данные на выходе.
                      Т.е. есть как минимум два такта на прохождение данных от data к data_out.

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

                      P.S. Но код Грея всё равно не спасёт. Или здесь я тоже не прав?


              1. nckma
                13.02.2017 14:52

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


              1. GolikovAndrey
                13.02.2017 14:57
                +3

                Я не спорю как будет:) я знаю ответ:).
                Код грея делает так что одно значение от другого будет отличаться ровно 1 битом. В любой момент времени вы можете получить либо новое, либо старое значение. Даже в случае мета-стабильности у вас в итоге триггер свалиться к новому или старому значению и это всегда даст правильный ответ.

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


                1. nerudo
                  13.02.2017 17:14

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


                  1. GolikovAndrey
                    13.02.2017 17:30
                    +1

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

                    вот у вас есть счетчик который меняется
                    0 1 2 3 4 5 6 7 8 9 10
                    пусть он доходит в другой домен с задержкой в 2 такта
                    0 0 0 1 2 3 4 5 6 7 8 9
                    пусть другой домен выбирает каждый 10 отсчет
                    0 0 0 0 0 0 0 0 0 7 7 7 7…

                    но обратите внимание что когда мы меняли 0 на 7, мы на входе который защелкивает данные имели то 6 7 8, То есть мы могли защелкнуть 6, или переход 6-7 или 7 или переход 7-8, мы не могли видеть перехода 6 — 8, мы не могли видеть часть от 6 и часть от 7, так как считаем что период изменения больше разбежки шины.
                    так вот 6, 6-7, 7, 7-8, в коде Грея все эти ситуации будут превращены в 6 или 7 или 8, 6-7 и 7-8 свалиться в одно из устойчивых.

                    И не важно с какой частотой вы выбираете и с какой общей задержкой приходят данные


                    1. dsmv2014
                      13.02.2017 17:48
                      -1

                      Давайте рассмотрим такую ситацию: клок записи 250 МГц, клок чтения 100 МГц.
                      Задержки на шине передачи от от одного счётчика к другому распределились так:
                      bit0 — 1.1 ns
                      bit1 — 1.2 ns
                      bit2 — 1.4 ns
                      Это всё законно для частоты 250 МГц.
                      Теперь случай 1: фронт клока чтения отстал на 1.0 ns — все три бита получат старое значение
                      Следующий случай: фронт отстал на 1.3 ns — bit0 и bit1 — новое, bit 2 — старое
                      Ещё случай: фронт отстал ровно на 1.2 ns — bit2 — старое, bit0 — новое, bit1 — в метастабильном.
                      А эти случаи будут идти постоянно.


                      1. GolikovAndrey
                        13.02.2017 17:58
                        +1

                        Отлично, теперь мы к этому добавляем кодирование кодом грея
                        старое значение {bit0, bit1, bit2} отличается от нового {bit0, bit1, bit2} только одним битом
                        то есть у нас 3 варианта
                        {bit0, bit1, bit2} -> {New, bit1, bit2}
                        {bit0, bit1, bit2} -> {bit0, New, bit2}
                        {bit0, bit1, bit2} -> {bit0, bit1, New}
                        для первого случая мы получим
                        {bit0, bit1, bit2} -> {bit0, bit1, bit2}
                        второго случая
                        {bit0, bit1, bit2} -> {New, bit1, bit2}
                        {bit0, bit1, bit2} -> {bit0, New, bit2}
                        {bit0, bit1, bit2} -> {bit0, bit1, bit2}
                        то есть 2 варианта изменились, а третий передался просто старым
                        для 3 случая
                        {bit0, bit1, bit2} -> {New, bit1, bit2}
                        {bit0, bit1, bit2} -> {bit0, New или bit1, bit2}
                        {bit0, bit1, bit2} -> {bit0, bit1, bit2}
                        то есть первый вариант прошел, второй вариант либо прошол либо остался старым
                        третий вариант остался старым


                        1. dsmv2014
                          13.02.2017 18:20
                          -1

                          Не так. Обратите внимание, что частота записи 250 МГц, а частота чтения 100 МГц. Т.е. новое значение изменилось больше чем на один бит.


                          1. GolikovAndrey
                            13.02.2017 18:50
                            +1

                            сие невозможно:) разбежка между битами 0.3 нСек, а период задающего клока 4 нСек. Ни при каких условиях вы не можете на другом конце шины в один момент времени получить не соседние значения, которые отличаются не более чем на 1 бит.

                            то что шина в 100 МГц видит данные в 2.5 раза реже не означает что данные в шине пропадают в промежутки между клоками…

                            Постройте симуляцию и посмотрите.


                            1. dsmv2014
                              13.02.2017 23:02
                              +1

                              Внимательно посмотрел и признаю — я не прав. Действительно год Грея можно использовать при переходе между тактовыми доменами.
                              Благодарю за советы.
                              Дальше можно обсудить будет ли реализация на коде Грея более эффективной.


                              1. GolikovAndrey
                                13.02.2017 23:13

                                есть ограничения: код Грея будет работать только для FIFO глубиной степени 2^n, иначе при переходе максимум-минимум будут многобитывае изменения.

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

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


                                1. dsmv2014
                                  13.02.2017 23:52

                                  Похоже код Грея мне не поможет. Настройка флагов обязательно нужна.


                                  1. GolikovAndrey
                                    14.02.2017 07:15

                                    преобразователь в код грея и обратно — это небольшая комбинаторная схема. Скорее всего она имеет меньший или сравнимый размер с логикой формирования флагов синхронизации.

                                    Внутри домена у вас нормальный счетчик адреса, в другой домен счетчик идет через преобразователь в код Грея, переходит в этом виде между доменами и на той стороне восстанавливается опять в нормальный вид. Так решено пожалуй 99% FIFO через которые делают пересинхронизацию. Это стандартное и облизанное со всех сторон решение.


              1. Des333
                13.02.2017 17:41
                +1

                Счётчик Грея как раз и нужен для того, чтобы у Вас изменялся только 1 бит.
                И тогда, очевидно, возможны только 2 ситуации:
                1) Бит уже успел измениться (будет защёлкнуто новое значение счётчика)
                2) Бит ещё не успел измениться (будет защёлкнуто предыдущее значение счётчика)


  1. Daffodil
    13.02.2017 11:48

    Я бы изменил название на «Как работает асинхронное FIFO» для ясности


  1. Daffodil
    13.02.2017 12:13
    +1

    Рекомендую ознакомиться http://www.zimmerdesignservices.com/mydownloads/no_mans_land_20130328.pdf В некоторых случаях с большим clock skew даже правильно написанное асихронное фифо не будет правильно работать без timing constraints


    1. dsmv2014
      13.02.2017 12:54

      Посмотрел, но понял зачем так делать


      1. dsmv2014
        13.02.2017 13:50

        то есть — не понял зачем так делать


  1. bluetooth
    13.02.2017 14:03
    +3

    Это память типа «первым вошёл-первым ушёл» (first input – first output).

    Вообще-то «first in — first out».


  1. Daffodil
    13.02.2017 14:06

    А почему вы у себя в коде пишете:

    flag2to1 <= flag2 after 1 ns when rising_edge( clk1 );


    А если кому-то потребуется использовать ваше fifo в дизайне который работает на частоте больше 1 ГГц, оно нормально будет симулироваться?


    1. dsmv2014
      13.02.2017 14:10

      Ну если на 1 ГГц то надо написать after 0.1 ns, или меньше.
      Я всегда пишу after, так лучше видно сигналы на временной диаграмме и предохраняет от расхождения с работой в реальной аппаратуре.


      1. Daffodil
        13.02.2017 14:21

        Эти задержки накапливаются. Где-то в другом месте кто-то может написать еще одно присвоение, потом еще.

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


        1. capitanov
          13.02.2017 14:26

          Мы пишем задержки только после синхронных присвоений под CLK, поэтому они не накапливаются. При следующем защелкивании — она снова будет 1нс. Про 1ГГц — верно подмечено, нужно весь код заменить на что-то типа 0.1нс. Поэтому я в своих проектах ввел переменную td, которой присваивается значение этой задержки.


          1. nerudo
            13.02.2017 17:15

            «Мы» это стандарт на кодирование в компании или просто чья-то светлая идея?


            1. capitanov
              13.02.2017 17:29
              -3

              Изначально — это «светлая идея», которая затем переросла в негласный стандарт компании.

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


            1. dsmv2014
              13.02.2017 17:53

              Это всё на основе реального опыта. Было несколько случаев, когда результаты моделирования резко отличались от реальной работы. Разбор выявил узкое место. Это присваивание тактовых частот. Присваивание тактовых частот также производится с дельта-задержкой и это приводит к трудно обнаруживаемым проблемам. В итоге — проще написать aftger 1 ns.


              1. Daffodil
                13.02.2017 18:04
                +2

                Обычно для моделирования всяких clock-гейтов и прочей логики на клоках используются присвоения с immediate notification, тогда event скедулиться в текущий дельта-цикл. Не помню деталей VHDL, нужно спеку смотреть. Последнее время пользуюсь только SystemC.

                В общем использование задержек в синтезируемом коде приводит к путтанице. Особенно если у вас в перемешку RTL с gate-level с timing аннотациями. В общем я за свою жизнь уже настродался с интеграцией кода вроде вашего, поэтому у меня на него больная реакция.


                1. dsmv2014
                  13.02.2017 18:18

                  По стандарту языка конструкцию after синтезатор игнорирует. Так что никаких проблем нет.
                  Да, и моделированием после трассировки мы не занимаемся.


        1. dsmv2014
          13.02.2017 14:37

          Обычно накопления не происходит. Задержка добавляется только при защёлкивании на триггере.
          Почему так делаю я написал здесь.


  1. ilynxy
    14.02.2017 01:04
    +2

    Шёл 2017 год. Люди изобретали двухклоковое фифо, открывая попутно для себя свойства кода Грея, допуская ошибки связанные с метастабильностью в цепях сброса и пересечении клоковых доменов.

    Clock domain crossing: http://www.sunburst-design.com/papers/CummingsSNUG2008Boston_CDC.pdf
    Async fifo design: http://www.sunburst-design.com/papers/CummingsSNUG2002SJ_FIFO1.pdf

    Это не фундаментальные труды по схемотехнике и разработке цифровых схем, но дают представление о предмете.

    И еще, боюсь показаться грубым или заносчивым, но скажите пожалуйста, что подвигает Вас писать статьи? Что решения описанные в этой, что в предыдущей статье содержат классические ошибки начинающих (начиная от неглубокой проработки теории и специфики задач и, вследствии, принятие и реализация несоответствующих схемных решений, щедро приправленых синдромом NIH). И все бы ничего, если бы это был студенческий энтузиазм, но в профиле ж написано «инженер-разработчик».


    1. dsmv2014
      14.02.2017 11:56
      +1

      Век живи — век учись (правда всё равно не поможет)
      При всех недостатках — у меня есть о чём рассказать и показать.
      Хотя бы для организации дискуссии.


      1. ilynxy
        14.02.2017 13:50

        Тогда нужно поддержать и «афтар пешы ещо» =).
        Реально же много толковых людей, но они предпочитают «набигать и критиковать» (прямо как я), а вот написать грамотную и связную статью — выше сил.