Блог
[оценки nextpnr-xilinx после разводки на xc7a200tfbg484-2, не подписанный тайминг; отдельный блок на синтетических выводах, а не целый дизайн; результат JTAG — с нашего стенда] Два вопроса стенда стали двумя командами. tri fpga-seeds считает Fmax диапазоном по seed размещения: тернарный блок скалярного произведения на 321 LUT дал от 164,15 до 200,40 МГц на 20 seed и от 62,68 до 76,75 МГц с выводами, разнесёнными по корпусу, при одном и том же нетлисте во всех прогонах. tri fpga-jtag читает, какой чип стоит в цепочке, никогда не прошивает и отличает молчащий TDO от сломанного кабеля. На нашем стенде она поймала XC7A200T там, где ожидался XC7A100T.
На любом стенде с открытым тулчейном FPGA два вопроса возникают раньше, чем результат становится достойным отчёта. Какой чип на самом деле на другом конце JTAG-кабеля? И Fmax в логе — это свойство дизайна или одного seed размещения, который его дал? Мы превратили оба вопроса в команды, tri fpga-jtag и tri fpga-seeds. Мы прогнали их на своём стенде и на тернарном блоке скалярного произведения на 321 LUT, который перепроверяем для другой группы.
Короткий ответ на второй вопрос: на 20 seed размещения этот блок дал от 164,15 до 200,40 МГц. Перенос его выводов дал от 62,68 до 76,75 МГц. Нетлист и число ячеек в обоих случаях одинаковые: seed менял Fmax в 1,22 раза, расположение выводов — примерно в 2,6 раза. Каждая Fmax здесь — оценка nextpnr после разводки по её собственной модели задержек, а не подписанный тайминг.
nextpnr-xilinx печатает Max frequency после разводки для каждого клока, и это число меняется с --seed. Один seed — одна выборка из распределения. fpga-seeds либо разбирает набор готовых логов (--parse), либо сам запускает перебор (--run, по одному процессу nextpnr на seed, с низким приоритетом). Перед первым seed команда записывает хэши входов и версию nextpnr и отказывается перезаписывать прежние логи. Для каждого seed она берёт число LUT, FF и CARRY4, последнюю Fmax после разводки для самого медленного клока и разбиение критического пути на логику и разводку. Она печатает минимум, медиану, максимум и отношение max/min. Seed, у которого число ячеек отличается, она помечает: значит, seed размещали не один и тот же нетлист.
| xc7a200tfbg484-2, nextpnr-xilinx, цель 100 МГц, оценка после разводки | Seed | LUT / FF / CARRY4 | Fmax мин / медиана / макс (МГц) | Держит 100 МГц |
|---|---|---|---|---|
| Компактная распиновка | 20 | 321 / 114 / 14 на каждом seed | 164,15 / 187,16 / 200,40 | 20 из 20 |
| Выводы разнесены по корпусу | 10 | 321 / 114 / 14 на каждом seed | 62,68 / 71,42 / 76,75 | 0 из 10 |
| Исправленный блок (на бит шире отрицание), компактная распиновка | 20 | 331 / 114 / 15 на каждом seed | 178,00 / 194,34 / 221,58 | 20 из 20 |
Самый медленный seed с компактной распиновкой быстрее самого быстрого seed с разнесённой в 2,14 раза. В разнесённых прогонах на критическом пути 0,4 нс логики и от 12,6 до 15,5 нс разводки: путь из двух LUT трижды пересекает кристалл между колонками ввода-вывода. Отдельный блок на синтетических выводах измеряет то место, куда поставили его выводы. Наша прежняя оценка для этого блока по одному seed, 71,28 МГц, точно воспроизводится на seed 1 с разнесённой распиновкой. Это был результат распиновки, а не тракта данных. Мы сказали об этом группе, чей это блок, и они согласны, что в сравнение скорости эта цифра не входит.
Третья строка — исправленная версия того же блока. Отрицание в нём на один бит шире, так что -1 x (-128) даёт +128, а не заворачивается в -128. После разводки это стоит десять LUT и один CARRY4, и на той же компактной распиновке оценка для всех 20 seed по-прежнему проходит 100 МГц.
fpga-jtag читает IDCODE и никогда ничего не прошивает. Она работает с двумя семействами кабелей. Xilinx Platform Cable USB II (или клон DLC10; USB VID 0x03fd) поднимается как 0x0013 без прошивки. С --load команда загружает прошивку через fxload, без sudo, и ждёт, пока кабель переподключится как 0x0008. Затем она запускает xc3sprog и печатает версии прошивки и CPLD и каждое устройство в цепочке — по имени и ревизии. Для кабелей FTDI она спрашивает у openFPGALoader, какой зонд подключён, и запускает --detect. --expect XC7A100T превращает результат в код выхода: 0 при совпадении, 1 если цепочки нет или чип другой, 2 если нет кабеля.
На нашем стенде этот код выхода сделал свою работу. Единственным подключённым сегодня кабелем был FTDI-зонд AX7203, и fpga-jtag --expect XC7A100T сообщила loc 0: 0x03636093 XC7A200T и вышла с кодом 1. Для этой платы это правильный чип, а для шага, который мы собирались сделать, — неправильный. Такой шаг лучше остановить на несовпадении, чем на ошибке прошивки.
Если цепочки нет вовсе, команда прогоняет сырые биты через TDO и читает, что вернулось. Все единицы — TDO никто не ведёт. Сам кабель работает, поэтому дальше проверяют индикатор состояния кабеля, питание платы, разъём, ориентацию первого вывода и провод TDO, именно в таком порядке. Все нули указывают на сторону кабеля. Это различие и отделяет проблему кабеля от проблемы платы. Все единицы — это то, что вернул при последней проверке наш второй стенд, XC7A100T на клоне DLC10.
Деталь для тех, кто пишет похожий инструмент: openFPGALoader маскирует полубайт ревизии в IDCODE, поэтому для одной и той же микросхемы он сообщает 0x03636093, а xc3sprog — 0x13636093. На пути FTDI fpga-jtag называет микросхему и не придумывает ревизию.
У каждой команды есть --self-test, который гоняет её разборщики на записанном выводе: 17 проверок для jtag (имена IDCODE, строки прошивки, вердикты TDO «все единицы» и «все нули», маска ревизии openFPGALoader) и 11 для seeds (незаконченные логи, несколько клоков, разные нетлисты). tri fpga-tools запускает все самопроверки board-loop вместе и сообщает 14 из 14. Повторный разбор логов, стоящих за таблицей выше, воспроизводит составленные вручную CSV значение в значение.
Поработаем вместе
Я аудирую RTL и строю независимые побитово точные модели, затем провожу результат через синтез и, когда это полезно, проверяю на плате Artix-7. Первый модуль проверки — бесплатно.