Блог
Предложенная строка в базе прошивок Xilinx полтора года оставалась непроверяемой. Две прошивки по 22.7 МБ, различающиеся одним битом, закрывают вопрос на кремнии: с битом светодиод мигает, без него счётчик стоит.
Строка в базе Project X-Ray говорит, каким битам в прошивке соответствует какой признак в кремнии. Большинство строк добыл фаззер, сравнивая тысячи выводов Vivado. Некоторые существуют только как предложение — и предложение, которое никто не может проверить, это и есть начало истории: восемь строк для регионального тактового буфера Artix-7 предложили в декабре 2024-го, а 14 августа 2026-го запрос закрыли до тех пор, пока не появится фаззер, способный сделать их проверяемыми.
Одна из этих восьми теперь проверена — не фаззером, а платой. Две прошивки для ALINX AX7203 (xc7a200tfbg484-2), по 22.7 МБ кадров каждая, различающиеся ровно одним битом: кадр 0x00401C00, слово 50, бит 31. С этим битом светодиод мигает на 0.75 Гц. Без него тот же проект стоит намертво — счётчик не тактируется и остаётся в нуле. Региональный клок не доходит до фабрики.
Это ровно то, что утверждала строка, и всё, что она утверждала: HCLK_L.ENABLE_BUFFER.HCLK_CK_BUFRCLK2 = 00_31 — разрешение того самого буфера.
Все прежние пробы в обсуждении сажали клок BUFR в ISERDESE2 или ODDR. И то и другое живёт в колонке ввода-вывода, поэтому региональный клок её не покидает, и на горизонтальной тактовой спине ничего не включается. Сопровождающий, работавший над другой половиной задачи, прямо написал, что проекта, дающего хоть одну строку HCLK_L, у него нет.
Посадите клок в обычную фабрику CLB — в простой счётчик — и он обязан дойти до лучей. Проба занимает тридцать строк. В этом весь приём, и он выдал сразу всю цепь: источник, маршрут по лучу, недостающее разрешение и потребителя в тайле управления тактами.
На малом кристалле проба встаёт по везению. На xc7a200t она падает дважды — с обеих сторон буфера.
Входная дуга не строится, потому что BUFR, питаемый от вывода, обязан сесть на единственный site, до которого этот тактовый вывод дотягивается: у его входа нет связи с фабрикой вовсе, — а плейсеру об этом не сообщали. Выходная не строится, потому что BUFR обслуживает один тактовый регион, плейсер не учитывает глобальные цепи в стоимости, и триггеры уезжают к тому выводу данных, к которому подключены. На этой плате — к светодиоду за полкристалла, в половину, противоположную единственному тактовому генератору.
Обе правки отправлены в проект и обе открыты, не слиты. CI зелёный на всех трёх проверяемых кристаллах. У второй есть ловушка, которую стоит повторить: область надо спрашивать у графа маршрутизации — куда клок реально доходит, — и собирать при этом только тактовые входы. Если считать все выводы подряд, получится прямоугольник во весь кристалл, то есть ограничение, которое ничего не ограничивает.
BUFR умеет делить свой клок. База несёт ступени D1..D8 годами; поток жёстко использовал BYPASS до июньской правки 2026-го, сделавшей остальные достижимыми, и с тех пор никто не выводил делённый BUFR на плату. Та же проба, тот же счётчик, меняется только параметр деления:
| BUFR_DIVIDE | предсказано (горит) | измерено |
|---|---|---|
| BYPASS | 0.67 с | ~0.65 с |
| 2 | 1.34 с | вчетверо быстрее D8 |
| 4 | 2.68 с | ~3 с |
| 8 | 5.37 с | ~5 с |
Предсказание из 2^28 x деление / 200e6. Середина важнее краёв: два замера показывают лишь, что что-то делится, а третий, легший туда, куда указывали крайние, показывает, что отношение следует за параметром, а не залипает на первом заданном значении.
Первый прогон делителя был недействителен. Я откатил правку эмиттера, чтобы запросы вышли чистыми, а потом собрал пробы на ветках, созданных после отката, — и прошивка не содержала ни одной строки разрешения, так что клок вообще не доходил до фабрики. Светодиод стоял, и я был в шаге от вывода, что деление кремнием игнорируется. Спасла проверка того, что в прошивке есть признак, ради которого ставился опыт, — сделанная до толкования светодиода, а не после.
Недействительный прогон оказался ценнее, чем стоил: это второй независимый отрицательный контроль для бита разрешения — прошивка, собранная другим маршрутом и по другому поводу, снова показала мёртвый счётчик при отсутствующем бите.
В той же пробе вход CLR был завязан на ноль. Делителю BUFR нужен импульс сброса, режиму BYPASS — нет, поэтому даже при наличии разрешения та сборка не различила бы «деление игнорируется» и «делитель не запущен».
А поиск по коду, сделанный задним числом, нашёл предшествующий опыт против моей же правки: форк чинит ту же ошибку размещения с апреля 2025 года одной строкой, вызовом уже существующего помощника. Я это измерил — размещение совпало на обеих пробах — и написал об этом в запросе, предложив закрыть свой в пользу той строки. Такой поиск следовало сделать до отправки, а не после.
Сам поток. Yosys — это YosysHQ. nextpnr — YosysHQ и Дэвид Шах. Project X-Ray и база xc7 — SymbiFlow и F4PGA. Порт под Xilinx, поддержка Artix-7, пакер BUFR и привязка site для BUFIO — openXC7 при финансировании NLnet, и механизм, который заимствует моя правка региона, написан сопровождающим для BUFIO несколькими неделями раньше. Восемь строк-кандидатов принадлежат AdamLee7 — из запроса, который я рецензировал и с закрытием которого согласился. Моё здесь — проба в тридцать строк, две правки и плата на столе.
Они отвечают на разные вопросы. Фаззер спрашивает, каковы биты, — по всему тайлу, из тысяч вендорских прошивок. Однобитовое сравнение спрашивает, делает ли один конкретный бит то единственное, что ему приписано. Второе уже и намного дешевле — около получаса на бит, почти целиком уходящих на прошивку, — и вендорский инструмент ему не нужен вовсе.
И оно не заменяет фаззер. Оно не находит биты, а только проверяет их; оно не отличит деление на 8 от деления на 7; и его отрицательный результат неоднозначен так, как положительный — нет, потому что бит, ничего не меняющий, может быть и неверным битом, и значением по умолчанию, уже установленным.
Поработаем вместе
Работаю по контракту и part-time с hardware-AI, FPGA/RTL и ML-системами — от спецификации и открытого тулчейна до воспроизводимых измерений.