Андрей К
Андрей К личный блог
03 апреля 2018, 22:16

Как я логи на RGMII подымал и выводил их в ModelSim

Введение

     Так получилось, стал я обладателем борды, на которой есть все, кроме JTAG. Это означало, что такого софта как SignalTAP у меня нет. Отлаживать не получится. Подымать карту в слепую то еще занятие. Это как копаться в черном ящике в темной комнате. Было принято решение, начать писать логи на карте и передавать их в каком нибудь формате через Ethernet на компьютер. На основе этого был получен некоторый опыт, описать который захотелось. Сильно особо не критикуйте, эту тему я изучаю полностью с нуля, давалось и дается fpga (как и схемотехника) очень тяжело, когда нет специализированного образования.

ETHERNET

     Вообще ethernet — это технология передачи данных. Жестко стандартизирована по IEEE. Подстандартов сейчас очень много, технологии не стоят на месте. Наверное слышали 10Base-T (10Мбит/сек), 100Base-T, 1000Base-T(1Гигабит/сек), ну или как на нашей бирже 10GBase… Самая сложность реализации на железе этих стандартов — это реализация физического уровня, то есть как передаваемые вами байты в сеть преобразовывать в электрические сигналы, используя кодировку и тд. Если поднять с нуля 10Base-T не представляется сложным, делал это без проблем даже без специальных magnetic на разъеме RJ45, то скорости повыше это задачка уже так себе. Ну еще можно без каких либо сильных сложностей поднять 100Мбит. 
    Поэтому разработчиками всякого железа было в свое время придумано засунуть реализацию физического уровня Ethernet в какую нибудь дешевую микруху, которая на себя возьмет полностью реализацию всего. Наверняка вы слышали таких производителей, как Realtek, Marvell и др. Использование таких микрух достаточно оправдано, за небольшие деньги вынести в отдельный модуль решение массы задач. Это гораздо упрощает решение задачи + нет нагрузки на саму fpga, освобождаются ресурсы под другие задачи.
    Мне повезло. На моей борде стоит такой чип от Marvell. 

RGMII

     Так как я уже ранее сказал, что любая эта тема является жестко стандартизированной, то и работа с такими чипами тоже описана стандартами, а если быть корректней, то протоколами. Для передачи данных на физический уровень Ethernet были разработаны различные протоколы. Ну например: MII, SGMII, RGMII и тд. Их описание вы легко прочитаете в инете. Ну и тут мне повезло, мой Marvell поддерживает RGMII. Это значит, что я могу работать с ним на fpga на пониженных частотах (125Mhz), это повысит надежность кода, алгоритма и повысит стабильность выполнения задачи.
     Я решил максимум отладить код в ModelSim, а потом пробовать его в слепую запускать на fpga. Кстати говоря, раньше давно я не дооценивал ModelSim, любил SignalTAp и отлаживать сразу на бою в рабочем состоянии. Как потом показал опыт, качественно отлаженный код в ModelSim запускается с первого раза на карте. В том числе и 1000Base-T я запустил на карте с первого раза, после недельной отладки в ModelSim. Это очень сильно экономит время, так как компилирование и прошивка fpga — это вам не c++ закомпилить. Это минут 15-20.
     Все что вам нужно знать для отправки сетевого пакета на физический уровень сети через протокол RGMII, так это шесть сигналов: tx_clk, tx_ctrl, tx_0, tx_1, tx_2, tx_3. Качественно их подготовив и подав на микруху Marvell (ну или Realtek), вы получите результат => отправка битов в витую пару. Их описание:
      — tx_clk. Это сигнал генератора на частоте 125Mhz. Грубо говоря, если мы переведем герцы в наносекунды, то получим, что каждые 8наносек (125Mhz = 8наносек), мы просто должны подавать электрический сигнал (логическую 1) на ножку чипа Marvell
      — tx_ctrl. Это сигнал управления передачи. Если на эту ножку подаем логическую 1, то мы говорим микрухе, что мы передаем в сеть биты. И она начинает работу и передавать биты. Если мы на эту ножку ничего не подаем (логический 0), то микруха молчит.
     - tx_0, tx_1, tx_2, tx_3. — Это как раз значения передаваемых битов. Соответственно, если на какую то ножку мы подаем электрический сигнал, то значения соответствующего бита = 1.
    Легко понять, что у нас всего 4 ножки под значения битов. То есть передаем 4 бита, а байты в компьютере состоят из 8 битов. Вот тут и вступают правила RGMII. В любом описании в инете вы найдете нечто похожий текст, что по переднему фронту сигнала tx_clk мы передаем первые 4 бита, по заднему фронту вторые 4 бита. Неподготовленному бойцу может стать и не понятно. Попробую нарисовать это:
Как я логи на RGMII подымал и выводил их в ModelSim


Если нарисовать алгоритм RGMII блок схемой:
Как я логи на RGMII подымал и выводил их в ModelSim

     Все в принципе просто. Особенно когда переваришь тонну материалов в интернете. Но есть нюансы. Может получиться такая ситуация, и практически 100% вероятность, что она получится, когда вы подаете на ногу тактовый сигнал tx_clk, а сами ноги бит tx0..tx3 чуточку запаздывают, на считанные наносекунды. Это может вызвано несколькими причинами. Самим FPGA и вашим кодом, либо схемой платы, ее пайкой и тд. То есть передача сигналов по самой плате передаются с задержкой. Обычно производители плат в документации составляют целую таблицу задержек тех или иных сигналов по плате (особенно актуально, когда вы подымаете sfp+ или pci-express на карте). В связи с этим, принято сдвигать тактовый сигнал на величину задержки, а еще актуальней просто сдвигать его на 90 градусов, если схематично, то сдвинуть его вправо, пометил его зеленым на рисунке
Как я логи на RGMII подымал и выводил их в ModelSim
Тогда гарантированно при подаче тактового сигнала tx_clk, микруха Marvell считает именно нужные биты со своих ног tx0..tx3 и tx_ctrl.

Ethernet кадры и UDP

     Вообще не уверен что это тема этого топика. Поэтому совсем немного. Сеть Ethernet так устроена, что данные передаются кадрами, cформированными по определенным правилам. Вы не можете заслать в кабель через микруху любую последовательность байт и ожидать результата. Для начала нужно собрать ethrnet кадр по спец правилам и начать его передавать в кабель.

1) Для начала в кабель нужно заслать преамбулу кадра. Это просто 7 байт с шестнадцатеричным значением 55 (1010101 в двоичном).
2) Далее нужно заслать 1 байт разделителя после преамублы. Его значение D5 в Hex.
3) Далее нужно заслать в  кабель 6 байт MAC адреса получателя
4) Далее нужно заслать в  кабель 6 байт MAC адреса отправителя. Будьте тут внимательны, вбивайте правильно значение, чтобы не намаяться с отладкой.
5) Если у вас сеть, как на Мос бирже колокейшен, то нужно заслать заголовок VLAN
6) Далее идут данные кадра (TCP или UDP пакет)
7) И все это дело заканчивается контрольной суммой кадра. Это 4 байта. Правильно высчитанное значение контрольной суммы очень важно. Если сумма не корректна, если у вас ошибка кода, то ваш кадр просто не дойдет до получателя. Намучаетесь много.

     Лично мне помогали вот эти две ссылки. Я в ModelSim выводил значения засылаемых в кабель данных и проверял тут правильность сгенерированных кадров в hex.
packetor.com/
www.gasmi.net/hpd/
    Честно говоря, мне лень описывать этот раздел. Я уже к этой строке потратил полтора часа подготовки текста и лень меня одолевает. Если вам интересно будет, задайте просто вопрос, я расскажу.

Контрольная сумма

     Код или модуль контрольной суммы нужно написать так, чтобы она пересчитывалась online, по мере поступления очередного байта в кабель. Ведь у нас FPGA и мы должны использовать все преимущества параллельных расчетов. Поэтому код нужно составить так, чтобы к моменту посылки контрольной суммы в кабель, она уже была рассчитана иначе ее расчет потянет за собой задержки и вы просто можете не уложиться в заданный такт tx_clk. Если будет интересен ее код или ее алгоритм, задайте вопрос, я тоже покажу.

Организация логов

     Тут все очень просто. Задача очевидная. Нам нужно сохранять значения каких то сигналов или значения переменных или значения регистров с заданной частотой. А отправлять эти значения с конкретной частотой 125Mhz (скорость, на которой работает RGMII Marvell). В моих потребностях логи я пишу с частотой 100Mhz (1 раз в 10 наносекунд). Очевидно, что эту задачу может решить асинхронный буфер FIFO. В Quartus есть такая мегафункция. Ее просто нужно подключить и настроить.
    Формат логов у меня пока очень простой. Первые 2 байта я использую под порядковый номер лога + еще 1 байт под значения восьми сигналов (1 байт = 8 бит). Получается, в асинхронный FIFO я сохраняю каждые 10наносек 24 бита (3 байта по 8 бит). И вытаскиваю из этого буфера эти 24 бита каждые 8 наносек и отправляю в сеть.
    Очень упрощенно это выглядит так:
Как я логи на RGMII подымал и выводил их в ModelSim

Принимающая сторона

     Тут надо признать, я немного намучался. Скорость логов была такова, что даже зависала сеть, не говоря уже о подвисании компьютера. Слегка решил проблему, когда увеличил размер посылаемого лога в притирку к MTU = 1500 байт. Этим самым мне удалось добиться разрыва между пакетами чуть больше 1мксек. До этого решения, у меня посылалось примерно до 3 пакетов в 1 мксек и у меня жутко висела вся сеть. Даже если свитч выдерживал нагрузку, то компьютер не справлялся.
     Когда я поборол зависания путем уменьшение частоты пакетов, я столкнулся с проблемой визуализации как в SignalTAP. Все решения рисования графиков на c#, на .Net, Excel тупиковые. Они просто не справляются таким потоком данных и самое главное таким кол-ом набора данных. Но плавно пришло решение. Я просто погружал эти данные в ModelSim с помощью написанного мною TestBench.
    В итоге связка получилась такая. Я на c# написал сниффер сети. Сырые сокеты не стал использовать, взял готовое решение для .NET PCAP (на нем работает и Wireshark). Сниффлю я все пакеты с MAC отправителя моей FPGA (там я просто прописал 000102030405), PAYLOAD (полезные) данные из UDP пакета я просто побайтно сохраняю в файл. И потом этот файл просто загружаю в ModelSim с помощью TestBench.
Выглядит это вот так:
Как я логи на RGMII подымал и выводил их в ModelSim

    По моему получилось супер. Тема логов очень актуальна. Гигабитный RJ45 очень выручает в этом плане. Мы не засоряем боевые каналы передачи данных (SFP+ 10G, PCI-E) где ходят торговые данные. + Визуализация отладки мне понравилась. Тормозов нет, все в виде осцилограммы. И самое главное в таком решении, нет ограничения по времени логов, как это в SignalTAP, где время собираемых логов ограниченно свободной памятью fpga. Получился некий скоростной логический анализатор. Буду рад услышать критику или ваши похожие решения.

ps. Кода в посте совсем не было. Ну пусть будет хоть кусок TestBench на Verilog =))
ps2. В поддержку Тимофея и его Смартлаб.
ps3. В настройках подсветки кода нет настройки Verilog (видно разработчики не ожидают тут фпгаашников), так что будем довольствоваться подсветкой c++
`timescale 1ns / 1ns
module main_test_bench_125_1; 
	/*
	Формат лога в сетевом пакете:
	
	struct {
			uint16_t	log_id;					Два байта порядкого номера лога
			uint8_t		signal_values;			8 бит со значениями восьми сигналов
	}
	
	*/
	
	//Сигналы для вывода на осцилограмму
	reg     	clk_100Mhz; 					//Осцилограмма генератора 100Mhz
	reg [15:0]	log_row_id;						//Первые 2 байта лога - порядковый номер
	reg			signal_1;						//Первый бит третьего байта лога - значение первого сигнала в логе
	reg			signal_2;						//Второй бит третьего байта лога - значение второго сигнала в логе
	reg			signal_3;
	reg			signal_4;
	reg			signal_5;						//...
	reg			signal_6;
	reg			signal_7;
	reg			signal_8;						//Восьмой бит третьего байта лога - значение восьмого сигнала в логе
	
	//Вспомогательные переменные
	integer 	file_log;						//Указатель на файл с логами
	integer		scan_file;

	initial
	begin
		//Пытаемся открыть файл с логами
		file_log = $fopen("udp_dump.bin", "r");
		if (file_log == 0) 
		begin
			$display("Log file open FAILED");
			$finish;
		end
		
		//Имитируем тактовый генератор 100Mhz
		clk_100Mhz  = 1'b0;			//Начальное значение 0
		#5;							//Задержка сигнала 5нс (100Mhz = такт 10нс, 5нс - полу такт)
		repeat(24999999)
		begin
			clk_100Mhz  = 1'b1;		//Ставим генератор в 1
			#5  clk_100Mhz  = 1'b0;	//Ждем 5нс и ставим генератор в 0, фактически имитируем сигнал 1 в течении 5нс
			#5;						//Ждем 5нс и ставим генератор в 1, фактически имитируем сигнал 0 в течении 5нс, получаем 1 такт длительностью 10нс
		end
		clk_100Mhz  = 1'b1;
		#5;
	end

	//На каждый такт генератора читаем данные из файла и выводим их в сигналы осцилограммы
	reg [7:0]	byte_1;
	reg [7:0]	byte_2;
	reg [7:0]	byte_3;	
	
	always @(posedge clk_100Mhz) 
	begin
		byte_1 = 0;
		byte_2 = 0;
		byte_3 = 0;
		
		scan_file = $fscanf(file_log, "%c%c%c", byte_1, byte_2, byte_3);	//Читаем 3 байта в 3 регистра по 8 бит
		if (!$feof(file_log)) 
		begin
			log_row_id [15:8] 	= byte_1;									//Назначаем прочитанные значения на выводы осцилограммы
			log_row_id [7:0]  	= byte_2;
			signal_1			= byte_3 [7];
			signal_2			= byte_3 [6];
			signal_3			= byte_3 [5];
			signal_4			= byte_3 [4];
			signal_5			= byte_3 [3];
			signal_6			= byte_3 [2];
			signal_7			= byte_3 [1];
			signal_8			= byte_3 [0];
		end
	end	
	
	initial
	#1000000000 $stop;			//После 1млрд наносекунд (=1 сек), заканчиваем моделирование
endmodule




36 Комментариев
  • Jame Bonds
    03 апреля 2018, 22:47
    Сколько же времени убили на написание кода для отладки ?
    Не дешевле ли было раскошелиться на новую карточку ?
    Или умельца привлечь, JTAG подпаять? Физически то он на всех Altera есть, просто на карточке может быть не подключен.
    Проц не задействовали для передачи, чисто на конечных автоматах?
      • Jame Bonds
        04 апреля 2018, 00:29
        Андрей К, что ж за плата такая, с которой столько мучаетесь. Подпаленная БУ что ли ?
        Новые платы можно взять начиная с 1,5k$, зависит от класса. Просто нерационально убивать месяц работы на починку.
          • Jame Bonds
            04 апреля 2018, 00:53
            Андрей К, SFP? Есть вот такой мезонин + базовая плата (выбор большой). Проблема только в том, это вместе при подключении в PCIe не лезет в стандартный корпус. Решается шлейфом-удлинителем для PCIe.
            А если Gb Ethernet, то еще дешевле и вариантов море.
  • Jame Bonds
    03 апреля 2018, 22:47
    А времянка подстраивается элементарно, без всяких переворотов клоков следующим образом:
    1) Находите в характеристиках микросхемы приемника (ваш PHY) параметры tsu, th;
    2) Рассчитываете по ним tco, tcomin;
    3) Прибавляет к ним разницу задержки в дорожках (для 125 МГц она ничтожна, можно игнорировать);
    4) Задаете параметры в Quartus;
    5) Quartus сам подбирает задержки во время Fitter и проверяет, что попал в Timing Analizer.
    Так гораздо быстрее, чем подбирать руками. Кроме того гораздо надежнее, так как задержки все равно немного плавают от температуры и кристалла (в смысле на другой ПЛИС того же типа), и нередко «подобранные руками золотые задержки» перестают работать совершенно неожиданно.
    При применении расчета даже если при разводке по кристаллу параметры сломаются, увидите предупреждение в отчете.
      • Jame Bonds
        04 апреля 2018, 00:28
        Андрей К, ну да, известная проблема. Если модель скажете, могу посмотреть в астралах.
          • Jame Bonds
            04 апреля 2018, 12:28
            Андрей К, увы, нашел только 1111 и 1112
              • Jame Bonds
                04 апреля 2018, 13:16
                Андрей К, а как же ножки назначали? На www.altera.com доки по всем официальным отладочным платам. Или у вас раритет типа Bittware или Таганрожский НИИ МВС ?
                А рентген мало поможет, во-первых скорее всего он внутри микросхемы, а не между проводниками, а во-вторых на многослойке рентгеном можно увидеть только закоротку припоем под корпусом.
  • Кремлебот
    03 апреля 2018, 22:57
    Я конечно все понимаю, но зачем эту техническую ересь публиковать на смарт-лабе? Думаете пользователи массово бросятся подавать 5 вольт на микросхемы?
  • tranquility
    03 апреля 2018, 23:30
     Андрей К, ну, было бы здорово немного остальным рассказать для чего все это делается. Интересно, но гуглить лень. Это как-то связано с ускорением прямого доступа к бирже, минуя терминал и брокера?
  • bstone
    03 апреля 2018, 23:37
    Совсем школьники расслабились… логи по эзернету им… С магнитной ленты данные считывать, когда у тебя пара инструкций процессора сжирают уже и передний и задний фронт  — вот где реальная работа с таймингами :)
      • bstone
        04 апреля 2018, 00:36
        Андрей К, так я это сам в яслях делал, так что молод пока ещё душой :)
  • Александр
    04 апреля 2018, 00:09
    Крайне редко сюда захожу, приятно было на главной увидеть твой пост) Если что у меня все хорошо)
  • Изя 3%
    04 апреля 2018, 00:30
    Теперь с нетерпением жду кулинарных рецептов на Смартлабе… )
  • Skifan
    04 апреля 2018, 01:04
    Это больше по Хабровской теме статься, к трейдингу то какое отношение ? 
    • Skifan, отношение к трейдингу прямое.
  • Anton
    29 декабря 2018, 20:31
    Потрясающая статья

Активные форумы
Что сейчас обсуждают

Старый дизайн
Старый
дизайн