61 / 63 · Теория
Останавливаемый конвейер и обратное давление
Вычисляйте ready каждой ступени, предотвращая потери, повторы и повторное вычисление при остановке и одновременном продвижении.
Уроки доступны бесплатно. Запишитесь, чтобы сохранять прогресс.
Когда получатель не всегда готов
Предварительные знания: однопозиционный ready/validРукопожатие (handshake) — соглашение, по которому передача подтверждается, когда valid передатчика и ready приёмника равны 1 на одном фронте. Оно также задаёт правила удержания данных во время ожидания. Подробнее-буфер и выравнивание данных конвейераКонвейер делит вычисление на разделённые регистрами стадии и перекрывает обработку нескольких входов. Данные, valid и управляющие сигналы необходимо согласовать по стадиям. Подробнее.
Добавить out_ready к конвейеру фиксированного темпа и заблокировать выход недостаточно. Когда последняя ступень заполнена и стоит, предыдущую нельзя перезаписывать. Нужно обратное давлениеОбратное давление (backpressure) останавливает поток данных: приёмник сообщает передатчику, что временно не готов принимать. Во время остановки ещё не переданные данные должны сохраняться. Подробнее, передающее остановку в сторону входа.
Представим каждую из двух ступеней одним элементом данных и одним valid. Вторая принимает новое, когда пуста либо может выдать текущий выход на этом фронте. То же правило применяется к первой.
Внешний in_ready равен r1. Даже при r2=0 пустая первая ступень может принять один вход. Это использует память лучше, чем безусловный запрет всех входов при остановке выхода.
Ступень обновляется только при разрешении движения
Пример вычисляет y=2(x+1) для unsignedБеззнаковая интерпретация (unsigned) рассматривает битовую последовательность как неотрицательное целое. Диапазон n бит — от 0 до 2^n−1; знаковая интерпретация тех же битов может дать другое число. Подробнее 8-битного x. Первая ступень хранит x+1 в 9 битах, вторая сдвигает влево до 10 бит. Максимальный вход 255 даёт точно представимое 512.
module stallable_pipeline (
input logic clk, rst,
input logic in_valid,
output logic in_ready,
input logic [7:0] in_data,
output logic out_valid,
input logic out_ready,
output logic [9:0] out_data
);
logic v1, v2, r1, r2;
logic [8:0] d1;
logic [9:0] d2;
assign r2 = !v2 || out_ready;
assign r1 = !v1 || r2;
assign in_ready = r1;
assign out_valid = v2;
assign out_data = d2;
always_ff @(posedge clk) begin
if (rst) begin
v1 <= 1'b0;
v2 <= 1'b0;
end else begin
if (r2) begin
v2 <= v1;
if (v1) d2 <= {d1, 1'b0};
end
if (r1) begin
v1 <= in_valid;
if (in_valid) d1 <= {1'b0, in_data} + 9'd1;
end
end
end
endmoduleИз-за nonblockingНеблокирующее присваивание обозначается <= в последовательностном RTL. Оно вычисляет правую часть, затем планирует обновление, позволяя регистрам на одном фронте рассчитываться по предыдущему состоянию. Подробнее вторая ступень получает прежнее d1, а не вычисленное на том же фронте. При r1=0 хранятся v1,d1, при r2=0 — v2,d2. Удерживать только valid, продолжая менять данные, неправильно.
Трассировка двух заполненных ступеней
Пусть v2 содержит результат A, v1 — промежуточное B, а на входе ждёт C.
| out_ready | in_ready | Действие на фронте |
|---|---|---|
| 0 | 0 | Хранить A,B; C не принят |
| 0 | 0 | Хранить A,B; C не принят |
| 1 | 1 | Передать A, переместить B во вторую ступень, принять C |
Передатчик удерживает C и in_valid до принятия. Если считать C отправленным на первом остановленном фронте и перейти к следующему, C потеряется.
Каждый столбец ниже — значения перед положительным фронтомПоложительный фронт — момент перехода такта из 0 в 1. Его следует отличать от уровня, означающего весь интервал CLK=1. Подробнее. Изначально последняя ступень содержит A, первая — B, на входе ожидает C. После передачи A и приёма C на E2 выход перед E3 становится B.
Показать данные диаграммы
| Сигнал | Диаграмма | Значения шины |
|---|---|---|
| фронт | 2345 | E0 → E1 → E2 → E3 |
| out_ready | 0.1. | |
| out_valid | 1... | |
| out_data | 2..3 | A → B |
| in_valid | 1... | |
| in_ready | 0.1. | |
| in_data | 2..3 | C → D |
Проверяемый закон сохранения
Пусть после reset Nin — число принятых входов, Nout — переданных выходов. Число сохранённых элементов задаётся следующим соотношением; на фронте reset передачи не учитываются.
Одного совпадения количества недостаточно: можно дважды выдать A и потерять B. Эталонная очередь проверяет значения и порядок. Независимо меняйте in_valid и out_ready, включите долгие остановки, непрерывную работу и очистку при reset.
Ready тоже образует временной путь
В длинной цепочке ступеней удлиняется и обратный комбинационный путь вроде r2→r1. Если задержать ready регистром, может понадобиться дополнительное место для входов, уже обещанных во время этой задержки. Просто вставить триггер в ready без учёта памяти и протокола — небезопасная оптимизация времени.
Попробуйте сами
v1=0, v2=1, out_ready=0. Можно ли принять вход с in_valid=1? Можно ли продолжать приём следующего входа, если out_ready остаётся 0 и в следующем цикле?
Прочитать объяснение
Изначально r2=0, но r1=1, поэтому один вход заполняет первую ступень. После фронта v1=v2=1 и r1=r2=0: дальнейший приём невозможен. Это различие позволяет реально использовать оба места хранения.