15 / 37 · Теория
Неблокирующие присваивания и одновременное обновление состояния
Разделяйте прежние и следующие значения для точного понимания RTL конвейеров и счётчиков.
Уроки доступны бесплатно. Запишитесь, чтобы сохранять прогресс.
Правая часть вычисляется по прежнему состоянию
В тактовом последовательностном блоке <= вычисляет правую часть, затем применяет результат на этапе неблокирующих обновленийНеблокирующее присваивание обозначается <= в последовательностном RTL. Оно вычисляет правую часть, затем планирует обновление, позволяя регистрам на одном фронте рассчитываться по предыдущему состоянию.. При обновлении нескольких регистровРегистр хранит многобитное состояние. Синхронные регистры в этом курсе записывают определённый вход на фронте тактового сигнала. Подробнее на одном фронте это позволяет избежать каскадного прохождения новых значений из-за порядка строк.
always_ff @(posedge clk) begin
if (rst) begin
a <= 8'd0;
b <= 8'd0;
end else begin
a <= d;
b <= a;
end
endПри начальных a=b=0 и входах 5, 9, 2 пары (a,b) после фронтов равны (5,0), (9,5), (2,9). Если считать, что вторая строка читает уже новое a, вы фактически удалите одну ступень конвейераКонвейер делит вычисление на разделённые регистрами стадии и перекрывает обработку нескольких входов. Данные, valid и управляющие сигналы необходимо согласовать по стадиям. Подробнее.
Каждый столбец — запись наблюдения одного положительного фронтаПоложительный фронт — момент перехода такта из 0 в 1. Его следует отличать от уровня, означающего весь интервал CLK=1. Подробнее. Входы показаны непосредственно перед фронтом, состояния со словом «после» в имени — сразу после обновления. Выравнивание столбцов обозначает порядок выборок, а не физическую задержку распространенияЗадержка распространения — время от изменения входа до установления правильного выхода. Логическая эквивалентность выражений и их временные характеристики — разные вопросы. Подробнее.
Начально a=b=0. Пока a сохраняет новое d, b сохраняет прежнее a, поэтому строки сдвинуты на одну ступень.
Показать данные диаграммы
| Сигнал | Диаграмма | Значения шины |
|---|---|---|
| фронт | 234 | E0 → E1 → E2 |
| d | 234 | 5 → 9 → 2 |
| a после | 234 | 5 → 9 → 2 |
| b после | 234 | 0 → 5 → 9 |
Чем опасна замена на blocking
При замене на a=d; b=a; в одном блоке вычисление b может использовать a, уже изменённое этим блоком. Планирование с другими последовательностными блоками также может вызвать гонки. Базовое правило: blocking для комбинационных вычислений, nonblocking для хранения состояния. Исключения используйте лишь когда можете объяснить событийную семантику.
Избегайте нескольких присваиваний одному регистру
Если в одной процедуре выполняются несколько nonblocking-присваиваний q, итог может определить последнее выполненное присваивание. Не прячьте приоритет в независимых if: используйте if / else if / else или явную переменную следующего состояния. Не управляйте одним регистром из нескольких блоков.
При ревью полезно записать по одному уравнению следующего состояния на регистр. Два уравнения или отсутствие определения при некотором условии — повод снова проверить приоритет управления в коде.
Попробуйте сами
Начально a=1, b=4. В одном тактовом блоке выполняются a<=b; b<=a;. Каковы состояния после одного и двух фронтов?
Прочитать объяснение
После одного (a,b)=(4,1), после двух (1,4). Оба присваивания читают одно прежнее состояние, поэтому значения меняются местами. При a=b; b=a; оба могут стать прежним b из-за порядка выполнения; это другая функция.