Altifigence Academy

15 / 37 · Теория

Неблокирующие присваивания и одновременное обновление состояния

Разделяйте прежние и следующие значения для точного понимания RTL конвейеров и счётчиков.

Правая часть вычисляется по прежнему состоянию

В тактовом последовательностном блоке <= вычисляет правую часть, затем применяет результат на этапе неблокирующих обновленийНеблокирующее присваивание обозначается <= в последовательностном RTL. Оно вычисляет правую часть, затем планирует обновление, позволяя регистрам на одном фронте рассчитываться по предыдущему состоянию.. При обновлении нескольких регистровРегистр хранит многобитное состояние. Синхронные регистры в этом курсе записывают определённый вход на фронте тактового сигнала. Подробнее на одном фронте это позволяет избежать каскадного прохождения новых значений из-за порядка строк.

SystemVerilog
always_ff @(posedge clk) begin
  if (rst) begin
    a <= 8'd0;
    b <= 8'd0;
  end else begin
    a <= d;
    b <= a;
  end
end
ak+1=dk,bk+1=aka_{k+1}=d_k,\qquad b_{k+1}=a_k

При начальных 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, поэтому строки сдвинуты на одну ступень.

a и b читают одно и то же предыдущее состояние
Показать данные диаграммы
Данные диаграммы: каждый символ — один интервал; точка сохраняет предыдущее состояние; p — один тактовый цикл.
СигналДиаграммаЗначения шины
фронт234E0 → E1 → E2
d2345 → 9 → 2
a после2345 → 9 → 2
b после2340 → 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 из-за порядка выполнения; это другая функция.

Выбор действует в этом браузере. Его можно изменить внизу страницы.