Menu

Тактируемая логика в Verilog: flip-flop, регистры и pipelines

Как строить регистры, счётчики, shift-регистры и pipelines из тактируемых always-блоков - рабочая лошадка любого синхронного цифрового проекта.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Базовый блок: D flip-flop

Всё в синхронном проектировании сводится к одному крошечному куску железа: D flip-flop. У него есть clock-вход, data-вход и data-выход. На каждом нарастающем фронте clock он захватывает значение D и держит его до следующего фронта. Это всё.

В Verilog:

always @(posedge clk) begin
    q <= d;
end

Три строки, один flip-flop. <= - non-blocking, что ровно соответствует поведению реальных flip-flop (разбираем в Blocking vs Non-blocking). Sensitivity posedge clk делает его последовательностным.

Сложив много таких с комбинационной логикой между ними, получишь любую синхронную схему, которую захочется построить.

Регистр с reset

Реальные проекты всегда нуждаются в reset - способе привести систему в известное состояние при включении или по запросу:

Это синхронный reset - условие reset вычисляется на фронте clock как любой другой вход. Синтезатор выдаёт flip-flop с 2-to-1 mux на data-входе: когда reset high, mux подаёт ноль; иначе подаёт d.

Для большинства проектов синхронный reset - правильный выбор. Проще по timing, играет хорошо с FPGA, и reset-сигнал может прийти откуда угодно - ему не нужен свой clock-выровненный источник.

Регистр с enable

Часто хочется регистр, который обновляется, только когда что-то ему скажет. Используй if внутри тактируемого блока и положись на неявное "держи прежнее значение" пропущенного else:

Это канонический "load-enabled-регистр". Встречается везде - конфигурационные регистры, pipeline-стадии, которые продвигаются только когда downstream готов, счётчики, которые ставятся на паузу и возобновляются. Опущение последнего else намеренно и безопасно внутри тактируемого блока: flip-flop уже помнит прежнее значение, так что "ничего не делать" значит "держать".

В комбинационном блоке тот же код вывел бы latch. Разные правила, тот же синтаксис.

Счётчик

Счётчик - регистр, чьё следующее значение - текущее плюс один:

Счётчик инкрементируется на каждом такте, когда enable high. После 16 тактов оборачивается обратно в 0 (потому что мы объявили 4 бита, и 15 + 1 переполняется в 0). Это оборачивание - суть N-битной арифметики и ровно то, как ведёт себя настоящий аппаратный счётчик.

Shift register

Сложив flip-flop, получаешь shift register. Трюк - делать все сдвиги в одном non-blocking операторе:

Тело - out <= {out[WIDTH-2:0], in} - конкатенируем младшие биты текущего out с новым in и присваиваем всё это. Поскольку это non-blocking, RHS читает старое out до того, как LHS обновляется. Эффект - чистый N-битный сдвиг за один такт.

Это паттерн shift-register в самой маленькой форме. Обобщается на LFSR, serial-передатчики, deserializers - любой проект, где данные движутся через цепочку flip-flop на каждом такте.

Pipelines

Pipeline - цепочка регистров, разделённых комбинационной логикой. Каждая стадия обрабатывает данные с предыдущей и кормит следующую:

Три стадии, три такта latency, но новый результат каждый такт, как только pipeline полный. Latency - 3 такта, потому что данные проходят через три flip-flop; throughput - 1 операция за такт, потому что все три стадии работают одновременно над разными входами.

Так высокопроизводительные проекты достигают целевого throughput: держи стадии короткими, делай pipeline глубже и позволь параллелизму делать работу.

Асинхронный reset (когда нужен)

Иногда нельзя ждать фронта clock, чтобы выставить reset - чип отключается, clock залочен, внешний watchdog дёргает линию. В этих случаях:

always @(posedge clk or negedge reset_n) begin
    if (~reset_n) q <= 0;
    else          q <= d;
end

В sensitivity list теперь и фронт clock, и фронт reset. Flip-flop реагирует немедленно на любое. reset_n по соглашению active-low (выставлен, когда low), поэтому проверка ~reset_n.

У асинхронного reset есть компромиссы: сложнее timing-анализ, может вызвать metastability при снятии, если не обрабатывать аккуратно, не портируется на все FPGA-архитектуры. По умолчанию - синхронный, асинхронный - только когда проект требует.

Что дальше

Теперь умеешь строить любой синхронный datapath. Следующий документ - Finite State Machines - собирает тактируемый регистр с case-оператором и даёт стандартную идиому FSM: рабочая лошадка любого контроллера, протокольного движка и блока принятия решений в цифровом проектировании.

Часто задаваемые вопросы

Что такое тактируемая логика в Verilog?

Логика, чьи обновления гейтятся clock-сигналом. Стандартная идиома - always @(posedge clk) target <= next_value;: на каждом нарастающем фронте clk target захватывает next_value. Эта одна строка описывает flip-flop в железе. Сложив много таких с комбинационной логикой между ними, строят счётчики, shift-регистры, pipelines - всё синхронное.

В чём разница между синхронным и асинхронным reset в Verilog?

Синхронный reset использует always @(posedge clk) if (reset) ... - reset сэмплируется на фронте clock как любой другой вход. Асинхронный reset использует always @(posedge clk or negedge reset_n) if (~reset_n) ... - блок срабатывает на фронте clock или на выставлении reset, так что reset действует немедленно. Синхронный - выбор по умолчанию; асинхронный - когда reset должен гарантированно сработать, даже если clock мёртв.

Как построить pipeline в Verilog?

Складывай несколько стадий always @(posedge clk) stageN_reg <= stageN_combinational; - комбинационная логика каждой стадии кормит регистр следующей, и все регистры захватывают на одном фронте clock. Результат - pipeline, куда новые данные входят каждый такт и выходят через N тактов, с throughput один результат за такт.

Что такое shift register в Verilog?

Цепочка flip-flop, где выход каждого кормит вход следующего. Каждый фронт clock сдвигает каждый бит на одну позицию. Каноническая Verilog-версия использует non-blocking присваивания: out <= {out[N-2:0], in}; - эта одна строка создаёт N-битный shift register, принимающий один бит за такт с in.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ