Автор: https://github.com/iwaniwaniwan012
Введение
В протоколах передачи данных для стабильной работы используются кодеки, выбранные разработчиками с учётом следующих требований:
равномерное распределение 0 и 1 в канале
простота кодирования/декодирования
иметь небольшую избыточность
Один из самых распространённых протоколов, о которых думаю, если не каждый человек, то уж каждый инженер точно слышал, является Ethernet, который имеет большое количество стандартов. Он так же использует кодек, а именно 66b/64b, который широко известен в инженерных кругах. Вот небольшой список популярных протоколов, использующих этот кодек:
Ethernet (10,40,100G)
Common Public Radio Interface
Fibre Channel (10G, 16G)
Infiniband (FDR, EDR)
Thunderbolt
Общее описание кодека 66b/64b
Схема кодирования состоит в том, что перед 64 битами данных добавляются 2 бита по следующей схеме:
если 64 бита составляют только данных "полезной нагрузки", то значение 2 бит - b'01
если в 64 битах содержатся данные и служебная информация или только служебная информация, то значение 2 бит - b'10 и значение 1-го байта содержит информацию о том, какого типа служебная информация содержится и её количество
Значения b'00 и b'11 для этих двух служебных бит не используются и будут восприняты как ошибка на приёмной стороне.
Дальше, для равномерного распределения 0 и 1 в канале, полученные данные скремблируются в соответствии с полиномом и передаются в канал связи.
Схема декодирования имеет обратный порядок действий, за исключением того, что в самом начале необходим синхронизатор, так как в канале связи приёмник не обязательно после обработки передаёт нам данные, выровненные на 2 служебных бита в начале.
Модули, необходимые для реализации
Приёмник:
Синхронизатор
Декодер
Дескремблер
Передатчик:
Кодер
Скремблер
Для проверки модулей так же нам необходим TestBench для проверки правильности разработанных модулей.
Небольшое отступление:
Те, кто имеет опыт работы с высокоскоростными интерфейсами ПЛИС фирм Xilinx или Altera/Intel могут сказать, что это всё можно включить в IP ядрах и будут конечно правы, но иногда бывают случаи, когда таких возможностей нет и тогда разработанные модули будут как раз кстати, особенно ввиду текущей обстановки...
Так же, ввиду особенностей IP ядер, реализующих только Physical Media Access, которые могут работать с шинами максимально 64 бита, было решено дополнительно реализовать модули конвертера 64 бита в 66 бит и наоборот.
Итоговая схема работы всего нашего проекта получается следующая:
Алгоритм работы модулей
Конвертеры
Представляют из себя сдвиговый регистр, который в зависимости от текущего наполнения, выдаёт сдвинутые данных.
Проще говоря сдвиговый регистр и мультиплексор.
Синхронизатор
Алгоритм синхронизации состоит в следующем:
Поиск синхронизации осуществляется за счёт объединения двух шин, представляющих из себя данные, полученные на предыдущем такте и на текущем такте.
Если 2 первых бита принимает значение только 2'b10 или 2'b01 в течении 128 тактов, то синхронизация достигнута, если нет, и эти два бита принимают зарезервированные значения, то по истечении 128 тактов сдвиг поиска синхронизации сдвигается на 1 бит.
Если в состоянии синхронизации за 1024 такта получилось 64 ошибки, то синхронизация сбрасывается и происходит переход на поиск синхронизации.
Описание входных/выходных пинов модуля:
port (
Clk : in std_logic; --Тактовый сигнал
Reset : in std_logic; --Сброс
En_In : in std_logic; --входной разрешающий сигнал
Data_In : in std_logic_vector(65 downto 0); --входные данные
Syn_Out : out std_logic; --статус синхронизации
En_Out : out std_logic; --выходной разрешающий выходной сигнал
Data_H_Out : out std_logic_vector(1 downto 0); --два служебных бита
Data_Out : out std_logic_vector(63 downto 0) --данные
);
Скремблер/Дескремблер
Представляет из себя сдвиговый регистр с шиной 58 бит, младший бит которого является очередным битом входных данных. А выходными данными скремблирования/дескремблирования - результат XOR 58 и 39 бита сдвигового регистра, а так же каждого входного бита данных, от младшего к старшему.
Описание алгоритма на VHDL представлен ниже:
if En_In = '1' then
for i in 0 to 63 loop
XorBit := Data_In(i) xor ScrReg(38) xor ScrReg(57);
ScrReg := ScrReg(56 downto 0) & Data_In(i);
DataReg(i) := XorBit;
end loop;
En_Out <= '1';
Data_H_Out <= Data_H_In;
Data_Out <= DataReg;
else
En_Out <= '0';
end if;
Проверка в среде симуляции
TestBench для среды симуляции по сути является генератором данных (последовательный счётчик), а на приёмной стороне проверка, что текущие данные это значение предыдущих данных -1. Так же на приёмной стороне, для визуальной проверки, если предыдущее условие выполняется, то сигнал Data_Test_Ok принимает значение 1'b1, в противном случае 1'b0.
Требуемые ресурсы ПЛИС и максимальная частота
При разработке различных модулей ПЛИС, перед использованием их в реальном проекте, мы используем тестовый проект с внутренним названием TestFreq, где используем входные пины модулей как виртуальные пины, тем самым проверяем, какое количество ресурсов ПЛИС будет использовано, а так же на какой максимальной частоте он сможет работать, причём в большинстве случаев второе является более важным.
Такие же измерения мы решили провести и для наших разработанных модулей (ПЛИС Intel/Altera). Результаты представлены в таблице ниже:
ПЛИС | Ресурсы | Максимальная частота |
Cyclone IV | 1906 LC | 179 MHz |
Cyclone V | 885 ALM | 188 MHz |
Stratix IV | 947 ALM | 333 MHz |
Stratix V | 901 ALM | 471 MHz |
Итог
По результату у нас получилось реализовать кодек 66b/64b, который можно использовать для различных проектов, где нет готовых решений или по какой-то причине мы не можем их использовать.
Ссылка на исходные коды, включая ТеstBench и описание, - кодек 66b/64b на языке VHDL
Спасибо за внимание!
P.S. Комментарии и пожелания крайне приветствуются =)