FIFO это один из ключевых элементов цифровой техники. Это память типа «первым вошёл-первым ушёл» (first input – first output). Меня как разработчика ПЛИС FIFO окружают повсюду. Собственно я только и делаю что беру данные из одного FIFO и перекладываю в другое. Но как оно работает? В современных САПР конечно уже есть готовые элементы, у Altera есть замечательные мегафункции. У Xilinx есть Core Generator. Но что делать если что-то не устраивает в стандартных решениях? Ответ один – разобраться и написать самому.
В интернете существует большое количество статей про FIFO, и когда то мне попалась очень хорошая и толковая статья. К сожалению, сейчас я её не нашёл. Далее – мой личный опыт по созданию и применению компонента FIFO. Готовый элемент находится на Github в проекте fpga_components: github.com/dsmv/fpga_components
Свой компонент потребовался по нескольким причинам:
- FIFO XIlinx не умеет работать в режиме ретрансмита – это главная причина
- FIFO Xilinx требует создания компонента с заданными параметрами – у нас развелось слишком много разных компонентов.
- FIFO Xilinx содержит ошибку – если приходит сигнал сброса одновременно с сигналом записи данных, то в FIFO застревает одно слово. Это мы конечно обошли, но всё равно неприятно.
Итак, что такое FIFO. В общем случае это двухпортовая память, два счётчика адреса и два автомата – для чтения и записи данных.
Одно из главных применений FIFO это перевод данных с одной тактовой частоты на другую. Этим определяется такая схема. При одной тактовой частоте на запись и чтение автоматы можно упростить.
Давайте рассмотрим внешние порты компонента FIFO:
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 мы должны записать слово в двухпортовую память и увеличить счётчик записи. Или сначала увеличить, а потом записать. А при операции чтения надо зафиксировать данные на выходе и увеличить счётчик чтения. А вот дальше требуется решить следующие вопросы:
- Как определить что FIFO полное или не полное, т.е. можно ли в него записывать ?
- Как определить что FIFO пустое или не пустое? Т.е. можно ли из него читать ?
- Как правильно сформировать флаги PAE, PAF, HF ?
- Что такое число слов в 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_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 который имеет настраиваемые параметры.
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
Конечно, для каждого теста сохраняется и свой отчёт.
Например такой:
# 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