Как работает FIFO

    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) ) );
    

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

    В итоге я считаю что получился элегантный компонент, достаточно удобный для практической работы.
    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 43

      +5
      Хм… а почему Вы не стали использовать код грея для передачи указателей фифо через домен? Я думал это стандартное, проверенное временем решение, которое используют все.
        –2
        Код Грея может спасти только при очень близких частотах. А вот при переходе от 250 МГц к 100 МГц он уже не поможет.
          +2
          Поясните кейс с 250 / 100 МГц
            –3
            Счётчик на 250 МГц успеет насчитать несколько значений за один такт 100 МГц. И я не понимаю как здесь может помочь год Грея.
              +2
              Это не важно сколько он насчитает.

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

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

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

                При асинхронных сигналах тактовой частоты всегда будут ситуации когда разные разряды шины будут защёлкнуты в разное время. Т.е. в другом домене будет часть нового значения а часть старого. А часть вообще будет в метастабильном состоянии. И в этом случае год Грея не поможет.
                  +1
                  Ваша реализация точно так же не дает никаких гарантий. В теории сдвиг фазы может превышать может превышать любое число тактовых периодов, если вы не написали constraint синтезатору. В общем реализация с Греем лучше т.к. требует меньше тактов на пересинхронизацию.
                    0
                    Это не так. У меня есть компонент ctrl_retack_counter_m12 Он корректно переводит шину data_in на data_out за несколько тактов. В нём сначала фиксируется значение на data_in, взводится флаг и фиксируется значение на data_out. Далее всё повторяется.
                      +2
                      ну смотрите, у вас есть вектор сигналов data который пишется на одном клоке, а читается на другом. Если вы не напишете constraint на этот сигнал, то разные сигналы в этом векторе могут прийти с разной задержкой. На низкой частоте в маленьком дизайне скорей всего все будет правильно работать. Но на высоких частотах задержка может превышать несколько тактов и вы рискуете получить неправильное значение. Я в другом комменте скинул ссылку на статью про этот кейс. Т.е. constraint нужно писать всегда. А раз пишем constraint, то проще делать на грее, т.к. его можно пересинхронизировать обычным двойным флопом
                        +1
                        Теперь я понял что вы опасаетесь. Но смотрите что происходит.
                        Автомат pr_st1 фиксирует data и взводит flag1
                        flag1 переводится в другой домен — flag1to2
                        flag1to2 обнаруживается автоматом pr_st2
                        автомат pr_st2 переходит в состояние s2 и фиксирует данные на выходе.
                        Т.е. есть как минимум два такта на прохождение данных от data к data_out.

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

                        P.S. Но код Грея всё равно не спасёт. Или здесь я тоже не прав?
                    0
                    Хм… а по моему, при передаче кодом грея в метастабильном состоянии может оказаться только один бит, тот который в данный момент меняется. Остальные же изменились раньше и всегда верные.
                      +3
                      Я не спорю как будет:) я знаю ответ:).
                      Код грея делает так что одно значение от другого будет отличаться ровно 1 битом. В любой момент времени вы можете получить либо новое, либо старое значение. Даже в случае мета-стабильности у вас в итоге триггер свалиться к новому или старому значению и это всегда даст правильный ответ.

                      Вам не нужно обеспечить чтобы счетчик фифо из одного домена в другом менялся последовательно, он может перепрыгивать через значение. Вам важно обеспечить чтобы вы из одного домена в другой из-за гонки не передали значение которого не было. А с кодом грея и полным счетчиком это возможно только если счетчик смениться несколько раз за врем фронта. Подчеркиваю фронта, а не периода.
                        0
                        Это все правильно, но вовсе не так радужно в случае (крайне маловероятном, но в жизни всякое бывает), когда период изменения счетчика меньше чем возможная задержка сигнала по пути в другой тактовый домен (подразумевая, что по каждому биту задержки могут быть разными).
                        Ну то есть в реальной жизни я сомневаюсь что такое может приключиться, но о чем говорит коллега понятно.
                          +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
                            Давайте рассмотрим такую ситацию: клок записи 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
                              Отлично, теперь мы к этому добавляем кодирование кодом грея
                              старое значение {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
                                Не так. Обратите внимание, что частота записи 250 МГц, а частота чтения 100 МГц. Т.е. новое значение изменилось больше чем на один бит.
                                  +1
                                  сие невозможно:) разбежка между битами 0.3 нСек, а период задающего клока 4 нСек. Ни при каких условиях вы не можете на другом конце шины в один момент времени получить не соседние значения, которые отличаются не более чем на 1 бит.

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

                                  Постройте симуляцию и посмотрите.
                                    +1
                                    Внимательно посмотрел и признаю — я не прав. Действительно год Грея можно использовать при переходе между тактовыми доменами.
                                    Благодарю за советы.
                                    Дальше можно обсудить будет ли реализация на коде Грея более эффективной.
                                      0
                                      есть ограничения: код Грея будет работать только для FIFO глубиной степени 2^n, иначе при переходе максимум-минимум будут многобитывае изменения.

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

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

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

                                          Внутри домена у вас нормальный счетчик адреса, в другой домен счетчик идет через преобразователь в код Грея, переходит в этом виде между доменами и на той стороне восстанавливается опять в нормальный вид. Так решено пожалуй 99% FIFO через которые делают пересинхронизацию. Это стандартное и облизанное со всех сторон решение.
                        +1
                        Счётчик Грея как раз и нужен для того, чтобы у Вас изменялся только 1 бит.
                        И тогда, очевидно, возможны только 2 ситуации:
                        1) Бит уже успел измениться (будет защёлкнуто новое значение счётчика)
                        2) Бит ещё не успел измениться (будет защёлкнуто предыдущее значение счётчика)
              0
              Я бы изменил название на «Как работает асинхронное FIFO» для ясности
                +1
                Рекомендую ознакомиться http://www.zimmerdesignservices.com/mydownloads/no_mans_land_20130328.pdf В некоторых случаях с большим clock skew даже правильно написанное асихронное фифо не будет правильно работать без timing constraints
                  0
                  Посмотрел, но понял зачем так делать
                    0
                    то есть — не понял зачем так делать
                  +3
                  Это память типа «первым вошёл-первым ушёл» (first input – first output).

                  Вообще-то «first in — first out».
                    0
                    А почему вы у себя в коде пишете:

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


                    А если кому-то потребуется использовать ваше fifo в дизайне который работает на частоте больше 1 ГГц, оно нормально будет симулироваться?
                      0
                      Ну если на 1 ГГц то надо написать after 0.1 ns, или меньше.
                      Я всегда пишу after, так лучше видно сигналы на временной диаграмме и предохраняет от расхождения с работой в реальной аппаратуре.
                        0
                        Эти задержки накапливаются. Где-то в другом месте кто-то может написать еще одно присвоение, потом еще.

                        В общем весь продуктовый RTL который я видел был написан без задержек. Если хочется увидеть какие-то «мнимые» задержки на временной диаграмме, досточно просто включить отображение дельта-циклов.
                          0
                          Мы пишем задержки только после синхронных присвоений под CLK, поэтому они не накапливаются. При следующем защелкивании — она снова будет 1нс. Про 1ГГц — верно подмечено, нужно весь код заменить на что-то типа 0.1нс. Поэтому я в своих проектах ввел переменную td, которой присваивается значение этой задержки.
                            0
                            «Мы» это стандарт на кодирование в компании или просто чья-то светлая идея?
                              –3
                              Изначально — это «светлая идея», которая затем переросла в негласный стандарт компании.

                              К сожалению, он не всеми соблюдается, но мы стремимся к единообразию и соблюдению определенных правил написания кода. В свое время я написал такой документ, но сами понимаете — протащить его наверх и сделать это стандартом крайне непросто. Несмотря на то, что многие поддержали эту идею, а коллективные обсуждения по этому вопросу возникали неоднократно. :)
                                0
                                Это всё на основе реального опыта. Было несколько случаев, когда результаты моделирования резко отличались от реальной работы. Разбор выявил узкое место. Это присваивание тактовых частот. Присваивание тактовых частот также производится с дельта-задержкой и это приводит к трудно обнаруживаемым проблемам. В итоге — проще написать aftger 1 ns.
                                  +2
                                  Обычно для моделирования всяких clock-гейтов и прочей логики на клоках используются присвоения с immediate notification, тогда event скедулиться в текущий дельта-цикл. Не помню деталей VHDL, нужно спеку смотреть. Последнее время пользуюсь только SystemC.

                                  В общем использование задержек в синтезируемом коде приводит к путтанице. Особенно если у вас в перемешку RTL с gate-level с timing аннотациями. В общем я за свою жизнь уже настродался с интеграцией кода вроде вашего, поэтому у меня на него больная реакция.
                                    0
                                    По стандарту языка конструкцию after синтезатор игнорирует. Так что никаких проблем нет.
                                    Да, и моделированием после трассировки мы не занимаемся.
                              0
                              Обычно накопления не происходит. Задержка добавляется только при защёлкивании на триггере.
                              Почему так делаю я написал здесь.
                          +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
                            Век живи — век учись (правда всё равно не поможет)
                            При всех недостатках — у меня есть о чём рассказать и показать.
                            Хотя бы для организации дискуссии.
                              0
                              Тогда нужно поддержать и «афтар пешы ещо» =).
                              Реально же много толковых людей, но они предпочитают «набигать и критиковать» (прямо как я), а вот написать грамотную и связную статью — выше сил.
                            0
                            Цитата: «Но что делать если что-то не устраивает в стандартных решениях? Ответ один – разобраться и написать самому». Дальше можно не читать! Если у нас начальники лаборатории такую ересь пишут, то тогда я понимаю почему Элон Маск за 7 лет поднимает сверхтяж, а в «Роскосмосе» за 20 лет не могут :(
                              0
                              А собственно говоря — почему?

                            Only users with full accounts can post comments. Log in, please.