Сегодня использование устройств на ПЛИС с сетью Ethernet – обычное явление. Особенно если речь идёт о высокоскоростной передачи данных (АЦП/ЦАП с сетевым выходом, обработка видео, «сырца» с радиолокаторов и гидроакустических комплексов, сбора данных с большой сети (решётки датчиков и т.д. и т.п.). Когда я вижу, как люди, покрывшись испариной, пытаются упихать поток отсчётов с квадратурного демодулятора SDR в USB 3.0, мне их становится откровенно жалко. Напомним, наша новая отладочная плата VE-10CL025 имеет встроенный сетевой интерфейс 1 Гбит. В этой статье мы расскажем о передаче ethernet пакетов из FPGA во внешний мир.
Отдельная огромная тема — это на чём это реализовывать. Вариантов несколько, но, в большинстве своём, плисоводы приходят к выводу, что лучший вариант — это «рукопашный».
В начале стоит внешняя «физическая» микросхема (PHY), которая выполняет работу нулевого уровня (если строго следовать модели OSI), т.е. преобразование аналоговых сигналов в цифровые, битовую и кадровую синхронизации. Затем следует MAC-уровень, т.е. всё, начиная от проверки контрольной суммы (КС) пакета до разборки и вытаскивания «полезной нагрузки» из многочисленных IP-протоколов: начиная от TCP, UDP и ARP и заканчивая экзотикой типа H.248.
Для соединения MAC уровня и PHY обычно используется один из интерфейсов.
MII- Media Independent Interface.
MII (Media Independent Interface — независящий от среды передачи интерфейс) — стандартизованный интерфейс для подключения MAC-блока сети Fast Ethernet к блоку PHY. Интерфейс MII может быть выведен на разъём для подключения внешнего приемопередатчика или может просто соединять две микросхемы на одной печатной плате. Независимость от среды передачи означает, что существует возможность использования любых PHY-устройств без необходимости смены или переработки аппаратуры MAC-блока. Интерфейс MII состоит из двух частей: канала приема-передачи данных (MII) и служебного канала управления (MDIO и MDC). Все операции интерфейса MII выполняются в синхронном режиме.
GMII- Gigabit Media-Independent Interface.
GMII (Gigabit Media-Independent Interface) — расширение стандарта MII (Media Independent Interface — независимый от среды передачи интерфейс) для гигабитных Ethernet-интерфейсов, обеспечивающий передачу данных между устройствами, реализующими подуровень Media Access Control (MAC) канального уровня с устройствами, реализующими физический уровень (PHY) модели OSI (например, как с оптическими интерфейсами 1000BASE-*X стандарта 802.3z, так и с медными интерфейсами 1000BASE-T* стандарта 802.3ab). GMII обеспечивает работу на скоростях до 1000 Мбит с использованием восьмибитного интерфейса с тактовой частотой 125 МГц и является обратно совместимым с MII, поддерживая работу на скоростях 10/100 Мбит в соответствии со спецификацией MII. Определён (как и MII) в рамках стандарта IEEE 802.3[1].
RMII- Reduced Media Independent Interface.
RMII (Reduced Media Independent Interface — сокращенный независящий от среды передачи интерфейс) представляет собой стандартизованный интерфейс использующий сокращенный набор сигналов интерфейса RMII применяется для подключения MAC-блока сети FastEthernet к блоку PHY. Разрядность шин RXD и TXD сокращается вдвое по сравнению с MII, но соответственно вдвое поднимается частота синхронизации MAC. Такое решение позволяет упростить конструкцию печатной платы и сократить количество используемых выводов микроконтроллера. В ряде случаев возможно использовать единую частоту синхронизации для MAC и PHY. Интерфейс RMII имеет сокращенный набор сигналов и полностью совместим с IEEE 802.3u. Он позволяет работать в режимах 10 и 100 Мбит/c, имеет частоту синхронизации 50 МГц.
RGMII- Reduce Gigabit Media Independent Interface.
RGMII (Reduce Gigabit Media Independent Interface) — улучшенный интерфейс GMII указывает конкретный интерфейс между Ethernet MAC и PHY. RGMII использует половину цепей, используемых в GMII интерфейсе. Это сокращение достигается за счет синхронизации данных как по фронту, так и по спаду клока в режиме 1000 Мбит/с, а также путём устранения несущественных сигналов (несущей и индикации). Таким образом RGMII состоит только из следующих цепей: RX_CTL, RXC, RXD [3:0], TX_CTL, TXC, TXD [3:0] (12 контактов, в отличие от GMII).
SGMII- Serial Gigabit Media Independent Interface.
SGMII — это последовательный интерфейс, который хорош тем, что ему требуется всего одна пара проводов (в одну сторону, есс-но дифференциальных, конкретнее — LVDS), если работа идёт без опорного генератора. А огромный минус его в том, что работа идёт на частоте аж 625 МГц по обоим фронтам. Далее этот поток (если речь о приёме) следует преобразовать в параллельный код.
SGMII — это последовательный интерфейс, который хорош тем, что ему требуется всего одна пара проводов (в одну сторону, есс-но дифференциальных, конкретнее — LVDS), если работа идёт без опорного генератора. А огромный минус его в том, что работа идёт на частоте аж 625МГц по обоим фронтам. Далее этот поток (если речь о приёме) следует преобразовать в параллельный код. В принципе, топовые микросхемы, типа того же Stratix'а IV и V с максимальными суффиксами в состоянии выполнить такое преобразование «на себе», т.е. на схеме, реализованной на внутреннем массиве логических элементов (ЛЭ). Но, такая схема будет весьма нестабильна (ибо работать будет почти на пределе возможностей, когда, по-сути, цифровая схема превращается в «полу-аналоговую» и всё, что показывают имитаторы типа Modelsim'а — никакого отношения к действительности не имеет), да и ставить мегадорогущие каменюги ради стыковки с PHY — не очень серьёзно. Поэтому, во многие ПЛИСины втискивают аппаратные приёмопередатчики SGMII. Но настройка этих блоков — отдельная и непростая штука. Кроме того, нужно помнить про сложности разводки печатной платы, ибо даже исходная частота (625 МГц), мягко говоря, не детская, а с учётом требований к фронтам и спадам (типично, максимум — 0,2нС) — можете легко посчитать требуемую широкополосность линий. Поэтому, мой совет — с SGMII связываться только в крайнем случае!
Гораздо проще ситуация с GMII и RGMII-интерфейсами. Это — параллельные (8 и 4, соответственно) линии связи. Тактовая частота снижена до разумных 125 МГц, хотя даже такая частота может представлять определённую проблему для дешёвых вариантов современных ПЛИС, особенно если нужно «выжать» всё, что можно из 1Гбит-интерфейса и, соотвественно, пакеты должны формироваться «на лету». Поскольку, для RGMII-интерфейса при тактировании по одному фронту понадобилась бы тактовая частота в 250 МГц (что уже совсем тяжеловато для большинства современных ПЛИС), здесь также производится тактирование по фронту и спаду тактового сигнала.
Если очень страшно связываться с двойным тактированием, то можно использовать GMII-интерфейс и тут, фактически, разработчик почти спокойно может использовать наработки, взятые из MII-интерфейса, разве что не забыв, что по GMII передаются байты, а не полубайты(нибблы) и, есс-но, подняв скорость передачи в 5 раз.
Но лишние выводы в современных ПЛИС'инах весьма дороги и RGMII-интерфейс предоставляет возможность разумной экономии (между GMII и SGMII) ценой некоторого (на самом деле, небольшого) усложнения схемы. И, кстати, если ваше устройство должно иметь возможность работать и с 1Гбит и с 100Мбит-устройствами, то, на самом деле, наиболее простой переход с MII обеспечивает RGMII.
Как стыковать RGMII с ПЛИС. Достаточно просто. Теоретически двухтактный буфер можно создать в основном массиве ЛЭ, используя (лучше всего) графику, или поизвращавшись (вообще, убогость этих языков — отдельная тема) в VHDL или Verilog'е (не забыв указать *useioff* у соответствующих выводов). Но, как показала практика, работать это всё будет весьма убого (ибо, с учётом требований к крутизне фронтов, широкополосность должна достигать 400 МГц!), правда, даст подсмотреть генерируемые сигнал в SignalTap (ChipScope).
Более правильный путь — использовать специализированные двухтриггерные буфера, например, в альтеровском случае — это ALTDDIO в соответствии с документом AN477 «Designing RGMII Interfaces».
На языке Verilog реализация передатчика 1 Gbit ethernet, с выходными буферами и передаваемым пакетом выглядит так:
Verilog Code:
//----------------------PHY1 Send------------------------------ eth_dat_iobuf tx_buf_h ( .datain (PHY_TX_BUF[3:0]), .dataout (DATA_OUT_H[3:0]) ); eth_dat_iobuf tx_buf_l ( .datain (PHY_TX_BUF[7:4]), .dataout (DATA_OUT_L[3:0]) ); eth_ddo eth_ddio_buf( .datain_h (DATA_OUT_H), .datain_l (DATA_OUT_L), .outclock (PLL_CLK_125_45), .dataout (DATA_TO_PHY) ); eth_obuf eth_o_buf( .datain (DATA_TO_PHY), .dataout (DATA_TO_PHY_BUF) ); phy1 phy_snd( .clock25_0 (PLL_CLK_25_0), .clock250_0 (PLL_CLK_250_0), .clock125_90 (PLL_CLK_125_90), .rst (KEY[0]), .phy1_mdc (PHY_MDC), .phy1_mdio (PHY_MDIO), .phy1_res (PHY_RES), .phy1_int (PHY_INT), .phy1_clk_25 (PHY_CLK25), .phy1_tx_clk (PHY_TX_CLK), .phy1_rx_clk (PHY_RX_CLK), .phy1_ctl (PHY_CTL_BUF), .phy1_rx_dv (PHY_RXDV), .phy1_tx (PHY_TX_BUF), .phy1_rx (PHY_RX), .ipmem_address (IP_RAM_ADDRESS_R), .ipmem_q (IP_RAM_Q), .phy_ready (PHY_READY), .cpy_ready (~KEY[1]) ); ip_buffer video_pckt( .clock (PLL_CLK_250_0), .data (IP_RAM_DATA), .rdaddress (IP_RAM_ADDRESS_R), .wraddress (IP_RAM_ADDRESS_W), .wren (IP_RAM_WREN), .q (IP_RAM_Q) );
А так выглядит графическое представление передатчика:
Строб пакета tx_en, как показывает практика, лучше тоже протаскивать через ALTDDIO (что и сделано под именем dataout[4]).
Показанная схема будет работать только при условии, что тактовая частота gtx_clk сдвигается на 90 градусов на внутреннем ФАПЧ микросхемы PHY (см. выше диаграмку с RGMII-сигналами). Такая весьма удобная опция предусмотрена в большинстве 1Гбит-PHY, но она включается в соответствующем регистре через MDIO. Например, для 88E1111 — это бит 1 регистра 20. Если же MDIO-приёмопередатчик писать лень, то тогда сдвинутую последовательность нужно сгенерить в ПЛИС с помощью ФАПЧ(PLL) и подать её на выход GTX_CLK. К сожалению, такой вариант часто не обеспечивает нужной стабильности и приводит к редким пропаданием отдельных пакетов.
А так выглядит сам код, передающий один пакет из памяти:
Verilog Code:
//----------------------------ETH Send---------------------------------- reg [10:0] clk_counter; // Number of bits determines pause time reg [2:0] state; reg tx_state; reg [31:0] delay_count; assign phy1_res = rst; assign phy1_tx_clk = clock125_90; always @(posedge clock250_0) begin if (rst==0) begin delay_count <= 0; state <= 1; end else begin //---------------------------------------------------------------------- if(state==0) begin phy1_ctl <= 1'b1; // Transmission is enabled phy_ready <= 0; if (clk_counter > 11'd1198) begin phy1_ctl <= 1'b0; // Transmission is disabled phy_ready <=1; ipmem_address <= 11'h0; state <= 1; end else begin if(tx_state==0) begin phy1_tx <= ipmem_q; clk_counter <= clk_counter + 1'b1; tx_state <= 1; end else if(tx_state==1) begin ipmem_address <= clk_counter; tx_state <= 0; end end end //-------------------------------------------------------------------- else if(state==1) begin if(delay_count<101) begin clk_counter <= 11'h0; delay_count <= delay_count + 1; end else begin if(cpy_ready==1) begin delay_count <= 0; tx_state <= 0; state <= 0; end end end end end
Ну и по традиции видео работы, и исходники:
Скачать: 1gb_ethernet.zip
P.S. Большая часть была взята с http://we.easyelectronics.ru