Триггеры и защёлки: память на один бит

Урок объясняет, как из обычных вентилей с обратной связью получается элемент, способный хранить один бит.

Триггер (flip-flop) — элемент памяти на один бит, меняющий состояние по тактовому сигналу. Защёлка (latch) — похожий элемент, но «прозрачный»: реагирует на вход уровнем сигнала, а не фронтом.

Зачем схемам память

Комбинационные схемы (сумматор, АЛУ) не помнят прошлого: их выход зависит только от текущих входов. Но процессору нужно хранить состояние — значение регистра, текущую команду, счётчик. Память появляется благодаря обратной связи: выход вентиля заводят обратно на его же вход, и схема «застревает» в одном из устойчивых состояний.

SR-защёлка из двух NOR

Самая простая ячейка — две NOR-схемы, выходы которых перекрёстно заведены на входы. Вход S (set) ставит 1, R (reset) — 0; при S=R=0 защёлка хранит прежнее значение.

    S ──→┌──────┐
         │ NOR  │──┬──→ Q
    ┌───→└──────┘  │
    │              │
    │   ┌──────┐←──┘
    └───┤ NOR  │
    R ─→└──────┘──────→ Q'

  S=1,R=0 -> Q=1 (set)
  S=0,R=1 -> Q=0 (reset)
  S=0,R=0 -> Q хранит прежнее значение  (ПАМЯТЬ!)
  S=1,R=1 -> запрещено

D-триггер: один вход данных + такт

SR-защёлка неудобна (запрещённая комбинация, два входа). На практике используют D-триггер: один вход данных D и тактовый вход. По активному фронту такта он «защёлкивает» текущее D и хранит его до следующего фронта. Это базовый строительный блок регистров. Промоделируем D-триггер как объект с состоянием:

class DFlipFlop:
    def __init__(self):
        self.q = 0
    def clock_edge(self, d):
        # по фронту такта запоминаем вход D
        self.q = d
        return self.q

ff = DFlipFlop()
print("такт | D | Q после фронта")
for t, d in enumerate([1, 1, 0, 0, 1]):
    q = ff.clock_edge(d)
    print(f"  {t}  | {d} |   {q}")

Вывод:

такт | D | Q после фронта
  0  | 1 |   1
  1  | 1 |   1
  2  | 0 |   0
  3  | 0 |   0
  4  | 1 |   1

Как работает под капотом: фронт против уровня

Защёлка «прозрачна»: пока тактовый уровень активен, выход следует за входом — это опасно, можно «проскочить» лишнее. Триггер срабатывает по фронту (моменту перехода 0→1), то есть мгновенно фиксирует значение. Поэтому почти вся синхронная логика построена на триггерах, тактируемых фронтом: все элементы обновляются одновременно, в один «щелчок» часов.

Глубже в тему

Стоит остановиться на парадоксе, который пугает при первой встрече с памятью: как схема без часов и без «места хранения» вообще что-то помнит? Ответ — в обратной связи. Когда выход вентиля заведён обратно на его собственный вход (через второй вентиль), схема перестаёт быть простой функцией входов: у неё появляются два устойчивых положения, в каждом из которых она поддерживает сама себя. Это похоже на выключатель с фиксацией или на шарик в одной из двух лунок — без внешнего толчка он остаётся, где был. Бит хранится не где-то «в ячейке», а в самом факте того, что схема устойчиво держится за одно из двух состояний. Это и есть фундаментальный переход от комбинационной логики (выход зависит только от текущих входов) к последовательностной (выход зависит ещё и от истории).

Почему запрещена комбинация S=R=1 в SR-защёлке — не каприз, а реальная физика. При одновременном «поставить» и «сбросить» оба выхода вынужденно становятся нулями, нарушая правило, что Q и Q' всегда противоположны. Хуже того, если затем убрать оба сигнала одновременно, схема не «знает», в какое из двух состояний свалиться, и исход зависит от ничтожных различий в задержках вентилей — возникает риск метастабильности, когда выход надолго зависает в неопределённом промежуточном уровне. Именно ради ухода от этих ловушек на практике почти никогда не используют голую SR-защёлку, а строят на её основе D-триггер с единственным входом данных, где запрещённая комбинация конструктивно невозможна.

Разница «уровень против фронта» — это разница между прозрачностью и мгновенным снимком, и она критична для синхронных схем. Защёлка, пока тактовый уровень активен, остаётся «прозрачной»: выход следует за входом, и если за это время вход дёрнется несколько раз, защёлка пропустит все изменения. В схеме с обратной связью такая прозрачность опасна — сигнал может «проскочить» через защёлку и вернуться к ней же в том же такте, испортив состояние. Триггер, тактируемый по фронту, снимает значение входа ровно в момент перепада такта 0→1 и держит его весь такт, оставаясь «непрозрачным» в остальное время. Поэтому почти вся синхронная логика процессора построена именно на фронтовых триггерах.

Практический вывод: фронтовое тактирование даёт дисциплину времени, на которой держится весь процессор. Все триггеры в системе подключены к общему тактовому сигналу и обновляются строго одновременно, в один «щелчок» часов. Между двумя фронтами комбинационная логика спокойно пересчитывает новые значения, а на следующем фронте они разом защёлкиваются. Эта строгая синхронность и позволяет рассуждать о процессоре как о машине, делающей по шагу за такт, — без неё пришлось бы отслеживать тысячи сигналов, меняющихся в произвольные моменты. Из этих самых триггеров в следующем уроке мы соберём регистры и счётчики, а ещё дальше — регистр состояния конечного автомата.

Частые ошибки

  • Путать защёлку и триггер. Защёлка реагирует на уровень (прозрачна), триггер — на фронт (защёлкивает в момент).
  • Подавать S=R=1. Для SR-защёлки это запрещённое состояние с неопределённым выходом.
  • Думать, что триггер хранит много бит. Один триггер — ровно один бит; для n бит нужно n триггеров.

Итог

  • Память рождается из обратной связи: выход вентиля заводится на его вход.
  • SR-защёлка хранит бит, но имеет запрещённое состояние; D-триггер удобнее (один вход + такт).
  • Триггеры срабатывают по фронту такта — основа синхронной логики процессора.
Проверьте себя
1. Благодаря чему схема из вентилей приобретает память?
AИз-за большого числа вентилей
BИз-за обратной связи: выход заводится обратно на вход
CИз-за тактового сигнала
DИз-за дополнительного питания
2. Чем D-триггер отличается от SR-защёлки?
AD-триггер хранит больше бит
BУ D-триггера один вход данных и тактирование, нет запрещённого состояния
CD-триггер не нуждается в вентилях
DD-триггер работает без питания
3. Что значит «триггер срабатывает по фронту»?
AОн реагирует, пока тактовый уровень высокий
BОн фиксирует вход в момент перехода такта 0→1
CОн переключается случайно
DОн работает без такта