T27.AI

Блог

Один региональный клок, двенадцать pull request'ов и спек, который нашёл баг в компиляторе

2026-10-02 · 6 мин чтения

[счётчики измерены через GitHub API 2 октября 2026; смержен значит принят мейнтейнером openXC7, а не вошёл в релиз; проверки битстримов — стенд cavearr с Vivado и наша плата XC7A200T] С 1 сентября мы открыли 12 pull request'ов в чужих репозиториях: 11 в openXC7, открытой цепочке сборки для Xilinx 7-series, и 1 в inngest. 5 смержены, 7 открыты. Большая часть идёт по одной нитке: дизайн с региональным клоковым буфером (BUFR) на XC7A200T не собирался открытым flow, и чтобы это исправить, пришлось пройти плейсер, трассировщик, запись битстрима и базу битов. Потом t27-спек строк этой базы нашёл баг в парсере компилятора t27, и мы исправили его в своём репозитории.

#FPGA#OpenToolchain#Verification#t27

С 1 сентября мы открыли 12 pull request'ов в чужих репозиториях: 11 в openXC7, открытой цепочке сборки для Xilinx 7-series, и 1 в inngest. 5 смержены, 7 открыты. Большая часть идёт по одной нитке, и последний её шаг привёл обратно в наш собственный язык.

С чего началось

Дизайн на ALINX AX7203 (XC7A200T) не собирался открытым flow, если в нём был BUFR — региональный клоковый буфер. Причина на всех уровнях одна: в открытой базе битов prjxray-db не хватало строк, и инструменты поверх неё либо не могли развести клок, либо писали битстрим без битов, которые его включают. Обсуждение шло в openXC7/nextpnr#23 и #24 вместе с cavearr: у него стенд с Vivado, и каждое изменение он сверял с битстримами самого Vivado.

Региональный клок от начала до конца

PRПроблемаИсправлениеСтатус
nextpnr-xilinx#170BUFR от пада ставился на сайт, до которого его пад не дотягивается. На 35T это было незаметно; на 200T трассировщик падал: Failed to route arc 0 of net 'clk_ibuf'BUFR закрепляется за выделенным сайтом своего пада, как #168 уже делал для BUFIOсмержен
nextpnr-xilinx#171BUFR питает только свой клоковый регион, но плейсер этого не знал и ставил триггеры на другом конце кристаллаДостижимый регион берётся из графа трассировки, и нагрузки BUFR держатся внутри негосмержен
nextpnr-xilinx#205Битстрим размещал BUFR, но не ставил его бит включенияБиты BUFRCLK теперь пишутся. Это ждало появления строк; cavearr нашёл, что они были только для artix7, и добавил остальные семейства в prjxray-db#22смержен
prjxray-db#30Строки мультиплексоров CLK_PERF были неполными. При чтении битстрима (bit2fasm) одна строка ложно срабатывала в 204 случаях; при записи (fasm2frames) не ставился бит включенияКаждая строка теперь несёт свой бит включения и 2-битный код источника; добавлены строки HCLK для kintex7, spartan7 и zynq7. Проверено в обе стороны на всех 608 битстримах cavearrоткрыт

После мержа #170 и #171 cavearr прогнал по ним свой регрессионный набор из 23 дизайнов: не сдвинулись ни статус, ни LUT/FF, ни Fmax, а все 36 эталонных FASM-выходов совпали байт в байт.

Перенос фиксов в новый движок

openXC7 переезжает со старого nextpnr-xilinx на nextpnr с движком himbaechel. Часть фиксов старого инструмента не перенесли, и старые падения вернулись. Пять из этих PR — переносы, некоторые по дороге исправлены.

PRБылоСталоСтатус
nextpnr#53Отрицательный CLKFBOUT_MULT_F у MMCM читал за концом таблицы: segfault на x86, который не воспроизводился на arm64, потому что приведение (int) — неопределённое поведениеПроверка диапазона 1..63. Старый фикс пропускал 64, а это чтение на строку за таблицейоткрыт
nextpnr#54IDELAYCTRL без IDELAY был ошибкой и останавливал сборкуПредупреждение, как в Vivadoоткрыт
nextpnr#55Перепутанные P/N у дифференциальной пары: std::out_of_range без единого словаОшибка, которая называет порт, пин и способ исправитьоткрыт
nextpnr#56RAM32X2S и RAM32X1S молча выбрасывались упаковщиком, и потом плейсер падалОба упаковываются. RAM32X1S не было даже в старом движкеоткрыт
nextpnr#57Опечатка в имени BEL (неизвестный тайл) роняла инструментОшибка с именем ячейки; то же для wire и pipоткрыт
nextpnr#58IDDR после IDELAYE2 получал не тот мультиплексор, и задержка не доходила до триггераСостояние, которое пишет Vivado. После мержа cavearr проверил на своём стенде: оба бита теперь совпадают с Vivadoсмержен
demo-projects#22Ничто не мешало будущему рефакторингу снова потерять RAM32X2S/X1SДва регрессионных дизайна к #56смержен

Единственное, что мейнтейнер Ханс Байер (Hans Baier) попросил изменить в этих PR, — стиль: условие каждого if выносится в именованную bool-константу прямо перед ним. Теперь мы пишем код openXC7 так по умолчанию. Правки для #53–#57 запушены 30 сентября и ждут его ревью.

Вне FPGA

inngest/inngest#4860: на self-hosted inngest с ключом подписи каждый MCP-инструмент, который ходит в REST API v2, отвечал 401: внутренний запрос терял заголовок Authorization. Фикс его пробрасывает.

Строки как спецификация

prjxray-db#30 меняет 146 строк базы по правилам, которые проверялись вручную: какие биты должна нести строка мультиплексора и какие строки добавляют HCLK-компаньоны. Мы пересобрали эти строки из одного t27-спека. В спеке лежат правила и измеренные биты; небольшой драйвер компилирует его, выводит строки и сравнивает их с базой.

Сначала спек не мог сказать то, что имел в виду. assert (a & b) == c разбиралось как assert(a & b), за которым висит == c. Проверка типов говорила ok, поймал только zig test. Мы завели баг как gHashTag/t27#5593 и исправили в gHashTag/t27#5594. На всех 1146 спеках корпуса t27 фикс меняет вывод ровно у 3 спеков и убирает там все ошибки Zig, вызванные багом, не добавляя новых. С фиксом исходное assert (x & y) == x в спеке проходит 7/7.

Что из этого следует

Каждый фикс в этом списке закрывает одно падение или один неверный бит, и каждый найден на настоящей XC7A200T или по битстриму Vivado. Дольше всего пришлось доводить строки, написанные руками для четырёх семейств. В виде спека их проверяют компилятор и их собственные тесты, и эта проверка в первый же день нашла баг в компиляторе.

Чего это не решает

Пруфы

Поработаем вместе

Хотите так же проверить собственный дизайн?

Я аудирую RTL и строю независимые побитово точные модели, затем провожу результат через синтез и, когда это полезно, проверяю на плате Artix-7. Первый модуль проверки — бесплатно.