Блог
[счётчики измерены через 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, и мы исправили его в своём репозитории.
С 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#170 | BUFR от пада ставился на сайт, до которого его пад не дотягивается. На 35T это было незаметно; на 200T трассировщик падал: Failed to route arc 0 of net 'clk_ibuf' | BUFR закрепляется за выделенным сайтом своего пада, как #168 уже делал для BUFIO | смержен |
| nextpnr-xilinx#171 | BUFR питает только свой клоковый регион, но плейсер этого не знал и ставил триггеры на другом конце кристалла | Достижимый регион берётся из графа трассировки, и нагрузки 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#54 | IDELAYCTRL без IDELAY был ошибкой и останавливал сборку | Предупреждение, как в Vivado | открыт |
| nextpnr#55 | Перепутанные P/N у дифференциальной пары: std::out_of_range без единого слова | Ошибка, которая называет порт, пин и способ исправить | открыт |
| nextpnr#56 | RAM32X2S и RAM32X1S молча выбрасывались упаковщиком, и потом плейсер падал | Оба упаковываются. RAM32X1S не было даже в старом движке | открыт |
| nextpnr#57 | Опечатка в имени BEL (неизвестный тайл) роняла инструмент | Ошибка с именем ячейки; то же для wire и pip | открыт |
| nextpnr#58 | IDDR после IDELAYE2 получал не тот мультиплексор, и задержка не доходила до триггера | Состояние, которое пишет Vivado. После мержа cavearr проверил на своём стенде: оба бита теперь совпадают с Vivado | смержен |
| demo-projects#22 | Ничто не мешало будущему рефакторингу снова потерять RAM32X2S/X1S | Два регрессионных дизайна к #56 | смержен |
Единственное, что мейнтейнер Ханс Байер (Hans Baier) попросил изменить в этих PR, — стиль: условие каждого if выносится в именованную bool-константу прямо перед ним. Теперь мы пишем код openXC7 так по умолчанию. Правки для #53–#57 запушены 30 сентября и ждут его ревью.
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. Первый модуль проверки — бесплатно.