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

в 22:50, , рубрики: fifo, fpga, open source, vhdl, xilinx

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

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

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

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

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

Одно из главных применений 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. Это можно представить на структурной схеме:

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

Надо ясно понимать, что узел перетактирования (в проекте это компонент 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 пустое.

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

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

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

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

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

В этом случае 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_componentssrcfifofifo_v7coregen находятся четыре компонента

  • 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 nsn", fo(now) );
	fprint( output, L, "FIFO 0 n" );
	fprint( output, L, " Принято пакетов:    %dn", fo( rx0_result.pkg_rd ) );
	fprint( output, L, " Правильных:         %dn", fo( rx0_result.pkg_ok ) );
	fprint( output, L, " Ошибочных:          %dn", fo( rx0_result.pkg_error ) );
	fprint( output, L, " Общее число ошибок: %dn", fo( rx0_result.total_error ) );
	fprint( output, L, " Скорость передачи: %r МБайт/сnn", fo( integer(rx0_result.velocity) ) );

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

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

Автор: dsmv2014

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js