← Упражнения на макетной платеEnglish
BB-FSM-01 · Logic Synthesis School Kit

Светофор Тимофея

Соберите автомат с десятью состояниями на трёх микросхемах CMOS. Затем опишите то же поведение на SystemVerilog и запустите его в симуляторе, на ПЛИС и через оболочку Tiny Tapeout.

4 / 2 / 4такта: красный / жёлтый / зелёный3микросхемы CMOS10состояний в цикле

1. Упражнение BB-FSM-01 · Светофор Тимофея

Светофор — удобный первый конечный автомат: выходы зависят от сохранённого состояния, а каждый фронт такта переводит автомат в следующее состояние. Здесь повторяется последовательность красный → жёлтый → зелёный → красный. Красному отведены четыре состояния, жёлтому два, зелёному четыре.

Это реализация идеи Тимофея Никифорова из курса Юрия Панчула. Та же структура «регистр состояния + дешифрация выходов» встречается в контроллерах периферии, автоматах протоколов и управляющей логике процессоров. Упражнение связывает схему на макетной плате с синтезируемым RTL.

Что нужно знать: шины питания макетной платы, нумерацию выводов DIP, функцию ИЛИ и фронты такта. Здесь изучается заданная последовательность; согласование перекрёстка и входы пешеходов в упражнение не входят.

Скачать полный комплект упражнения (ZIP)

2. Автомат состояний и логика ИЛИ

Граф автомата Мура. Каждая стрелка означает переход за один период; выходы вершин — {red, yellow, green}.
Граф автомата Мура. Каждая стрелка означает переход за один период; выходы вершин — {red, yellow, green}. · SVG · PNG

Десять окружностей — десять разных состояний, даже если несколько включают один огонь. Например, S0 и S3 дают красный, но переходят в разные следующие состояния. Сброс выбирает S0 из любого состояния и удерживает его при высоком rst. Условия обычных переходов предполагают rst=0.

S0 → S1 → S2 → S3 → S4 → S5 → S6 → S7 → S8 → S9 → S0

red    = S0 | S1 | S2 | S3
yellow = S4 | S5
green  = S6 | S7 | S8 | S9

S0–S9 — имена состояний и дешифрированных сигналов, а не номера выводов микросхемы. В установившемся состоянии ровно один сигнал S равен 1. В источнике «выходы 1–4, 5–6, 7–10» перечислены с единицы; здесь последовательно используются обозначения Q0–Q9 из даташита.

СостояниеВыход U1 / выводredyellowgreenСледующее по clk ↑
S0Q0 / 3100S1
S1Q1 / 2100S2
S2Q2 / 4100S3
S3Q3 / 7100S4
S4Q4 / 10010S5
S5Q5 / 1010S6
S6Q6 / 5001S7
S7Q7 / 6001S8
S8Q8 / 9001S9
S9Q9 / 11001S0

Двухвходовый ИЛИ даёт 1, когда хотя бы один вход равен 1:

ABA | B
000
011
101
111

Для четырёхвходового ИЛИ комбинация 0000 даёт 0, а остальные пятнадцать комбинаций дают 1. Сброс асинхронный, активный высокий: он сразу выбирает S0, в том числе между фронтами. Обычный счёт идёт только по положительным фронтам такта.

Временная диаграмма: четыре красных интервала, два жёлтых, четыре зелёных.
Временная диаграмма: четыре красных интервала, два жёлтых, четыре зелёных. · SVG · PNG

При частоте f длительности равны 4/f, 2/f и 4/f секунды. На диаграмме сброс задан при t=0, первый счётный фронт — при t=1 с. Если отпустить реальный асинхронный сброс в произвольный момент, первый красный интервал может быть короче; последующие полные циклы сохраняют отношение 4/2/4.

Попробуйте последовательность состояний

Красный: 0
Жёлтый: 0
Зелёный: 0

Анимация показывает логические состояния; это не HDL-симулятор и не электрическая модель.

3. Необходимые компоненты

Поз.КомпонентКол.НазначениеСтрока LSSK
U1CD4017BE · DIP-161Десятичный счётчик, десять дешифрированных выходов37
U2CD4072BE · DIP-141Два элемента 4ИЛИ: красный и зелёный21
U3CD4071BE · DIP-141Один элемент 2ИЛИ для жёлтого; три не используются20
LED-RСветодиод на 5 В1Красный, со встроенным ограничением тока46
LED-YСветодиод на 5 В1Жёлтый, со встроенным ограничением тока48
LED-GСветодиод на 5 В1Зелёный, со встроенным ограничением тока47
CLKТактовый модуль 5551Готовый модуль; настроить примерно на 1 Гц54
RESETКнопочный модуль1Модуль на 5 В: OUT=0 отпущена, OUT=1 нажата; встроенная подтяжка к земле65
BBМакетная плата на 830 контактов1Одна плата, центральный разрыв и четыре шины питания45
PSUМодуль стабилизированного питания 5 В1Выбрать 5 В; использовать поддерживаемый USB-вход или источник 9 В из таблицы56
WПровода M–M3937 перемычек платы и два провода питания; взять упаковку 40 шт.70
MПровода M–F6По три для CLK и RESET с установленными штырьками71

Номера строк относятся к локальному снимку LSSK от 14 октября 2026 года. Во время обновления Google-таблица не открывалась. Указано число реально используемых компонентов; закупочная упаковка кнопок содержит пять штук. Для модуля питания нужен совместимый входной кабель и источник; они не входят в 39 проводов M–M. Вместо модуля можно взять готовый лабораторный источник 5 В.

Используйте указанные индикаторы на 5 В со встроенным ограничением тока и модуль кнопки с определённым нулём на отпущенном выходе. Обычный светодиод или кнопка без модуля не являются прямой заменой. Проверьте реальные надписи выводов. Нагрузочная способность CMOS ограничена; индикаторы должны подходить для прямого подключения к выходам серии 4000.

Компоненты CSV · Исходные строки таблицы

4. Микросхемы CMOS: функции, выводы и полярность

U1 CD4017BE: циклически выбирает Q0…Q9. CLOCK, вывод 14, продвигает счёт по положительному фронту при нуле на INHIBIT, выводе 13. RESET, вывод 15, активен единицей и имеет приоритет над счётом. Перенос на выводе 12 равен 1 в S0…S4 и 0 в S5…S9; здесь он не используется.

У второго тактового входа есть особенность: спад INHIBIT при высоком CLOCK тоже продвигает счёт. В нашей схеме INHIBIT постоянно соединён с GND. Модель и тест микросхемы проверяют это поведение; внешнему интерфейсу упражнения нужны только clk и rst. Даташит TI; Таблица тактирования семейства 4017.

U2 CD4072BE: два четырёхвходовых ИЛИ. Входы 2,3,4,5 → выход 1 (красный); входы 9,10,11,12 → выход 13 (зелёный). U3 CD4071BE: четыре двухвходовых ИЛИ. Входы 1,2 → выход 3 (жёлтый). Используемые логические выходы активны единицей. Даташит TI на ИЛИ.

Все три корпуса DIP, вид сверху.
Все три корпуса DIP, вид сверху. · SVG · PNG

U1 · CD4017BE

ВыводСигнал микросхемыВ этой схеме
1Q5S5
2Q1S1
3Q0S0
4Q2S2
5Q6S6
6Q7S7
7Q3S3
8VSSСоединить с 0 В
9Q8S8
10Q4S4
11Q9S9
12CARRYНе подключать
13INHIBITСоединить с 0 В
14CLOCKclk
15RESETrst
16VDDПитание +5 В

U2 · CD4072BE

ВыводСигнал микросхемыВ этой схеме
1Jred
2AS0
3BS1
4CS2
5DS3
6NCНе подключать
7VSSСоединить с 0 В
8NCНе подключать
9ES6
10FS7
11GS8
12HS9
13Kgreen
14VDDПитание +5 В

U3 · CD4071BE

ВыводСигнал микросхемыВ этой схеме
1AS4
2BS5
3Jyellow
4KНе подключать
5CСоединить с 0 В
6DСоединить с 0 В
7VSSСоединить с 0 В
8EСоединить с 0 В
9FСоединить с 0 В
10LНе подключать
11MНе подключать
12GСоединить с 0 В
13HСоединить с 0 В
14VDDПитание +5 В

Неиспользуемые логические входы U3 (5,6,8,9,12,13) соединены с GND. Неиспользуемые выходы (4,10,11) свободны. Выводы 6 и 8 U2 имеют обозначение NC и остаются свободными. Не соединяйте выходы друг с другом вместо элемента ИЛИ.

5. Схема 1 · Логические элементы

Циклический блок состояний подаёт сигналы на три функции ИЛИ.
Циклический блок состояний подаёт сигналы на три функции ИЛИ. · SVG · PNG

Каждый переход задан графом в разделе 2. Эту поведенческую структуру реализует traffic_light.sv. Блок состояний задаёт последовательность из десяти состояний, а не конкретное внутреннее кодирование.

6. Схема 2 · Соединения микросхем

Каждый сигнал состояния соединён с указанным выводом микросхемы.
Каждый сигнал состояния соединён с указанным выводом микросхемы. · SVG · PNG

red — U2.1, yellow — U3.3, green — U2.13. Соедините каждый выход с анодом соответствующего индикатора с ограничением тока; катоды — с общей GND. Тактовый модуль, сброс и источник питания имеют общую землю.

7. Схема 3 · Сборка на макетной плате

Размещение на плате и все 37 перемычек. Для увеличения откройте SVG.
Размещение на плате и все 37 перемычек. Для увеличения откройте SVG. · SVG · PNG

Установите все DIP-корпуса поперёк центрального разрыва, выемкой вверх: U1 в строках 8–15, U2 в 22–28, U3 в 35–41. Вывод 1 находится в столбце e первой строки; противоположный верхний вывод — в f. В каждой строке соединены a–e и отдельно f–j; эти половины не соединены друг с другом.

LP/LM — левая положительная шина и земля; RP/RM — правые. Отверстия шин нумеруются 01–50 сверху вниз независимо от 63 строк контактных полей. На рисунке принят разрыв между отверстиями шин 25 и 26; все четыре разрыва замкнуты. Перед использованием этой нумерации проверьте соединения своей платы.

Внешнее соединениеОтверстия платы
CLK: OUT / + / −h47 / LP05 / LM05
RESET: OUT / + / −h50 / LP06 / LM06
Питание +5 В / GNDLP01 / LM01
Красный LED анод / катодb48 / b49
Жёлтый LED анод / катодb52 / b53
Зелёный LED анод / катодb56 / b57
Всего 15 сигнальных + 16 питания/земли + 6 шинных перемычек = 37. Ещё нужны шесть проводов модулей и два провода питания. Не вставляйте перемычку в отверстие, уже занятое ножкой микросхемы, LED или проводом модуля. В CSV выделены отдельные отверстия на той же контактной полоске.
Полная таблица соединений по отверстиям (37 перемычек)
ПроводЦепьОткудаКуда
W01+5VLP25LP26
W02GNDLM25LM26
W03+5VRP25RP26
W04GNDRM25RM26
W05+5VLP02RP02
W06GNDLM02RM02
W07S0a10a23
W08S1a09a24
W09S2a11a25
W10S3a14a26
W11S4j14a35
W12S5a08a36
W13S6a12j27
W14S7a13j26
W15S8j15j25
W16S9j13j24
W17GNDa15LM08
W18GNDj11RM08
W19GNDa28LM09
W20GNDa39LM10
W21GNDa40LM11
W22GNDa41LM12
W23GNDj41RM09
W24GNDj40RM10
W25GNDj37RM11
W26GNDj36RM12
W27GNDa49LM13
W28GNDa53LM14
W29GNDa57LM15
W30clkj10j47
W31rstj09j50
W32+5Vj08RP08
W33+5Vj22RP09
W34+5Vj35RP10
W35reda22a48
W36greenj23a56
W37yellowa37a52

Скачать CSV перемычек · База выводов и цепей

8. Синтезируемая схема на SystemVerilog

Принятый стиль кода

В каждом модуле сразу после заголовка стоят timeunit 1ns; и timeprecision 1ps;. Для портов-цепей используются обычные input/output, для процедурных выходов — output logic. Имена портов выровнены пробелами.

RTL, модели микросхем, оболочки и тестбенчи следуют правилам стиля SystemVerilog, составленным по BGM и systemverilog-homework. Отступ — четыре пробела. Для регистров используются logic и always_ff, для комбинационных процедур — always_comb; порты подключаются явно по именам. Руководство учитывает различия сброса и записи FSM в двух репозиториях.

Тот же граф с унитарными значениями state[9:0] из обобщённого RTL.
Тот же граф с унитарными значениями state[9:0] из обобщённого RTL. · SVG · PNG

Оба варианта имеют одинаковый интерфейс: clk, rst → red, yellow, green, state[9:0]. Обобщённый вариант использует унитарный (one-hot) регистр состояния, поэтому три уравнения прямо соответствуют схеме 1. Перед работой нужен сброс.

Обобщённый RTL — полный код

rtl/traffic_light.sv

// Synthesizable generic FSM. The state output uses one-hot encoding.
// Reset is asynchronous and active high; it selects S0.

module traffic_light
(
    input              clk,
    input              rst,

    output             red,
    output             yellow,
    output             green,
    output logic [9:0] state
);

    timeunit 1ns;
    timeprecision 1ps;

    wire [9:0] next_state = { state [8:0], state [9] };

    // State register

    always_ff @ (posedge clk or posedge rst)
        if (rst)
            state <= 10'b00_0000_0001;
        else
            state <= next_state;

    // Moore outputs depend only on the current state.

    assign red    = | state [3:0];
    assign yellow = | state [5:4];
    assign green  = | state [9:6];

endmodule

SystemVerilog описывает параллельную аппаратуру: регистр хранит состояние, а все три выходных уравнения действуют постоянно. Конкатенация циклически сдвигает единичный маркер, а не программные инструкции. Внутри реальной 4017 работает пятиразрядный счётчик Джонсона; функциональная эквивалентность не требует одинакового внутреннего хранения.

9. Модели микросхем CMOS на SystemVerilog

Все три модели — синтезируемые функциональные модели, логические порты которых названы по выводам. Физические VDD/VSS и NC показаны на схеме и не изображаются как HDL-питание. Задержек распространения нет. Модели не проверяют ток LED, качество питания, метастабильность или электрические ограничения импульсов.

cd4017b.sv

models/cd4017b.sv

// Synthesizable, zero-delay functional model of a powered CD4017B.
// Physical supply pins: 16 = VDD, 8 = VSS; they are not HDL ports.
// Binary encoding abstracts the chip's five-stage Johnson counter.
// Reset is required. Illegal Johnson-state recovery and electrical effects
// (current, setup/hold, pulse width and propagation delay) are not modeled.

module cd4017b
(
    input   p14_clock,
    input   p13_inhibit,
    input   p15_reset,

    output  p3_q0,
    output  p2_q1,
    output  p4_q2,
    output  p7_q3,
    output  p10_q4,
    output  p1_q5,
    output  p5_q6,
    output  p6_q7,
    output  p9_q8,
    output  p11_q9,
    output  p12_carry
);

    timeunit 1ns;
    timeprecision 1ps;

    // Falling INHIBIT while CLOCK is high is also a count event.
    // INHIBIT is tied low in this exercise, so synthesis removes the gate.
    // This models the chip; it is not a recommendation to gate FPGA clocks.

    wire effective_clock = p14_clock & ~ p13_inhibit;

    logic [3:0] count;

    always_ff @ (posedge effective_clock or posedge p15_reset)
        if (p15_reset)
            count <= '0;
        else if (count == 4'd9)
            count <= '0;
        else
            count <= count + 1'b1;

    assign p3_q0     = (count == 4'd0);
    assign p2_q1     = (count == 4'd1);
    assign p4_q2     = (count == 4'd2);
    assign p7_q3     = (count == 4'd3);
    assign p10_q4    = (count == 4'd4);
    assign p1_q5     = (count == 4'd5);
    assign p5_q6     = (count == 4'd6);
    assign p6_q7     = (count == 4'd7);
    assign p9_q8     = (count == 4'd8);
    assign p11_q9    = (count == 4'd9);
    assign p12_carry = (count <  4'd5);

endmodule
cd4072b.sv

models/cd4072b.sv

// Synthesizable functional model: two four-input OR gates.
// Physical pins: 14 = VDD, 7 = VSS, 6/8 = NC. No electrical/timing model.

module cd4072b
(
    input   p2_a,
    input   p3_b,
    input   p4_c,
    input   p5_d,
    output  p1_j,

    input   p9_e,
    input   p10_f,
    input   p11_g,
    input   p12_h,
    output  p13_k
);

    timeunit 1ns;
    timeprecision 1ps;

    assign p1_j  = p2_a | p3_b  | p4_c  | p5_d;
    assign p13_k = p9_e | p10_f | p11_g | p12_h;

endmodule
cd4071b.sv

models/cd4071b.sv

// Synthesizable functional model: four two-input OR gates.
// Physical supply pins: 14 = VDD, 7 = VSS. No electrical/timing model.

module cd4071b
(
    input   p1_a,
    input   p2_b,
    input   p5_c,
    input   p6_d,
    input   p8_e,
    input   p9_f,
    input   p12_g,
    input   p13_h,

    output  p3_j,
    output  p4_k,
    output  p10_l,
    output  p11_m
);

    timeunit 1ns;
    timeprecision 1ps;

    assign p3_j  = p1_a  | p2_b;
    assign p4_k  = p5_c  | p6_d;
    assign p10_l = p8_e  | p9_f;
    assign p11_m = p12_g | p13_h;

endmodule

Оба кодирования следуют одному графу состояний. Модель 4017 использует двоичный счётчик как абстракцию и воспроизводит последовательность сброса/счёта, перенос и запрет такта. Восстановление физического счётчика Джонсона из недопустимых внутренних кодов не моделируется. Здесь запрет такта соединён с нулём, поэтому синтез удаляет элемент в цепи эффективного такта.

10. SystemVerilog: соединения микросхем

Этот список соединений генерируется из той же базы выводов и цепей, что и схемы 2 и 3. Он создаёт по экземпляру модели каждой физической микросхемы и соединяет неиспользуемые логические входы с нулём. Интерфейс совпадает с разделом 8, поэтому варианты взаимозаменяемы в тестбенче и оболочках.

RTL соединений микросхем — полный код

rtl/traffic_light_chips.sv

// Generated by tools/build_diagrams.py from the same pins/nets as the drawings.
// Synthesizable with the ideal chip models; all supply pins are physical-only.

module traffic_light_chips
(
    input              clk,
    input              rst,

    output             red,
    output             yellow,
    output             green,
    output       [9:0] state
);

    timeunit 1ns;
    timeprecision 1ps;

    cd4017b u1
    (
        .p3_q0        (state [0]),
        .p2_q1        (state [1]),
        .p4_q2        (state [2]),
        .p7_q3        (state [3]),
        .p10_q4       (state [4]),
        .p1_q5        (state [5]),
        .p5_q6        (state [6]),
        .p6_q7        (state [7]),
        .p9_q8        (state [8]),
        .p11_q9       (state [9]),
        .p12_carry    (),
        .p13_inhibit  (1'b0),
        .p14_clock    (clk),
        .p15_reset    (rst)
    );

    cd4072b u2
    (
        .p1_j         (red),
        .p2_a         (state [0]),
        .p3_b         (state [1]),
        .p4_c         (state [2]),
        .p5_d         (state [3]),
        .p9_e         (state [6]),
        .p10_f        (state [7]),
        .p11_g        (state [8]),
        .p12_h        (state [9]),
        .p13_k        (green)
    );

    cd4071b u3
    (
        .p1_a         (state [4]),
        .p2_b         (state [5]),
        .p3_j         (yellow),
        .p4_k         (),
        .p5_c         (1'b0),
        .p6_d         (1'b0),
        .p8_e         (1'b0),
        .p9_f         (1'b0),
        .p10_l        (),
        .p11_m        (),
        .p12_g        (1'b0),
        .p13_h        (1'b0)
    );

endmodule

11. Тестбенчи и запуск симуляторов

Тестбенч сравнивает оба варианта с независимо вычисленным ожидаемым состоянием и набором огней. Одного совпадения вариантов недостаточно: две ошибочные схемы могут совпасть. Проверяются 12 полных циклов, 285 наблюдений, асинхронный сброс при обоих уровнях такта, удерживаемый сброс, неизменность по спаду и переход S9 → S0.

Все три тестбенча используют отдельный непрерывный генератор такта, стимулы по событиям, тела задач SystemVerilog и тайм-ауты в тактах. Ожидание спада применяется только для проверки поведения при низком CLOCK; каждая задержка установления объяснена в исходнике и в пояснениях к правилам стиля.

Основной тестбенч эквивалентности

tb/tb_traffic_light.sv

// Simulation only. Portable procedural checks; no classes, DPI or UVM.

module tb_traffic_light;

    timeunit 1ns;
    timeprecision 1ps;

    localparam period         = 20;
    localparam timeout_cycles = 500;

    logic clk = 1'b0;
    logic rst = 1'b0;

    always # (period / 2) clk = ~ clk;

    logic red_generic, yellow_generic, green_generic;
    logic red_chips, yellow_chips, green_chips;
    logic [9:0] state_generic, state_chips;

    int expected     = 0;
    int checks       = 0;
    int red_slots    = 0;
    int yellow_slots = 0;
    int green_slots  = 0;
    int visits [0:9];

    traffic_light generic_dut
    (
        .clk    (clk),
        .rst    (rst),
        .red    (red_generic),
        .yellow (yellow_generic),
        .green  (green_generic),
        .state  (state_generic)
    );

    traffic_light_chips chip_dut
    (
        .clk    (clk),
        .rst    (rst),
        .red    (red_chips),
        .yellow (yellow_chips),
        .green  (green_chips),
        .state  (state_chips)
    );

    task check_state;
        logic [9:0] wanted;
        logic [2:0] lamps;

        wanted = 10'b1 << expected;
        lamps  = expected < 4 ? 3'b100 : expected < 6 ? 3'b010 : 3'b001;

        if (   state_generic !== wanted
            || state_chips   !== wanted
            || { red_generic, yellow_generic, green_generic } !== lamps
            || { red_chips,   yellow_chips,   green_chips   } !== lamps)
        begin
            $fatal (1, "state=%0d generic=%b/%b chips=%b/%b",
                expected,
                state_generic, { red_generic, yellow_generic, green_generic },
                state_chips,   { red_chips,   yellow_chips,   green_chips   });
        end

        checks = checks + 1;
    endtask

    task tick;
        @ (posedge clk);
        expected = rst ? 0 : (expected + 1) % 10;
        # 1;  // Let register updates and lamp decoding settle before sampling.
        check_state ();
    endtask

    // Called between rising edges, after tick or the focused low-phase check.
    // Checking before the next clock edge distinguishes asynchronous reset.
    task reset_now;
        rst      = 1'b1;
        expected = 0;
        # 1;  // Asynchronous register update and combinational output settling.
        check_state ();
        rst = 1'b0;
    endtask

    initial
    begin
        $dumpfile ("traffic_light.vcd");
        $dumpvars (0, tb_traffic_light);

        for (int i = 0; i < 10; i ++)
            visits [i] = 0;

        @ (posedge clk);
        # 1;  // Place the initial reset after the clock event, without a race.
        reset_now ();

        for (int round = 0; round < 12; round ++)
            for (int i = 0; i < 10; i ++)
            begin
                visits [expected] = visits [expected] + 1;

                if (red_generic)
                    red_slots = red_slots + 1;

                if (yellow_generic)
                    yellow_slots = yellow_slots + 1;

                if (green_generic)
                    green_slots = green_slots + 1;

                tick ();
            end

        if (red_slots != 48 || yellow_slots != 24 || green_slots != 48)
            $fatal (1, "4/2/4 duration mismatch");

        for (int i = 0; i < 10; i ++)
            if (visits [i] != 12)
                $fatal (1, "Missing state %0d", i);

        // Reset from every state while CLOCK is high, then while it is low.
        for (int low_phase = 0; low_phase < 2; low_phase ++)
            for (int i = 0; i < 10; i ++)
            begin
                tick ();
                reset_now ();

                repeat (i)
                    tick ();

                if (low_phase != 0)
                begin
                    // Necessary exception: exercise reset with CLOCK low and
                    // verify that a falling clock edge does not advance state.
                    @ (negedge clk);
                    # 1;  // Observe any erroneous falling-edge state update.
                    check_state ();
                end

                reset_now ();
            end

        rst      = 1'b1;
        expected = 0;

        repeat (3)
            tick ();  // Reset dominates the clock.

        rst = 1'b0;
        tick ();

        $display ("PASS traffic_light: %0d checks; 12 full cycles; red/yellow/green=48/24/48; reset and wrap",
            checks);
        $finish;
    end

    initial
    begin
        repeat (timeout_cycles) @ (posedge clk);
        $fatal (1, "Timeout after %0d clock cycles", timeout_cycles);
    end

endmodule

Два дополнительных тестбенча проверяют все 256 комбинаций входных выводов моделей ИЛИ, запрет и перенос 4017, а затем оба варианта каждой оболочки в течение 30 шагов и оба режима индикатора; далее проверяются три такта с отключёнными выходами и независимые сбросы кнопкой и выделенным входом.

Тесты моделей микросхем

tb/tb_cmos.sv

// Simulation only. Chip pin truth tables and 4017 clock semantics.

module tb_cmos;

    timeunit 1ns;
    timeprecision 1ps;

    localparam period         = 20;
    localparam timeout_cycles = 500;

    logic clk     = 1'b0;
    logic inhibit = 1'b0;
    logic rst     = 1'b0;
    logic [7:0] a = '0;

    always # (period / 2) clk = ~ clk;

    logic [3:0] or2;
    logic [1:0] or4;
    logic [9:0] q;
    logic carry;

    int expected = 0;

    cd4071b g2
    (
        .p1_a  (a [0]),
        .p2_b  (a [1]),
        .p5_c  (a [2]),
        .p6_d  (a [3]),
        .p8_e  (a [4]),
        .p9_f  (a [5]),
        .p12_g (a [6]),
        .p13_h (a [7]),
        .p3_j  (or2 [0]),
        .p4_k  (or2 [1]),
        .p10_l (or2 [2]),
        .p11_m (or2 [3])
    );

    cd4072b g4
    (
        .p2_a  (a [0]),
        .p3_b  (a [1]),
        .p4_c  (a [2]),
        .p5_d  (a [3]),
        .p1_j  (or4 [0]),
        .p9_e  (a [4]),
        .p10_f (a [5]),
        .p11_g (a [6]),
        .p12_h (a [7]),
        .p13_k (or4 [1])
    );

    cd4017b counter
    (
        .p14_clock   (clk),
        .p13_inhibit (inhibit),
        .p15_reset   (rst),
        .p3_q0       (q [0]),
        .p2_q1       (q [1]),
        .p4_q2       (q [2]),
        .p7_q3       (q [3]),
        .p10_q4      (q [4]),
        .p1_q5       (q [5]),
        .p5_q6       (q [6]),
        .p6_q7       (q [7]),
        .p9_q8       (q [8]),
        .p11_q9      (q [9]),
        .p12_carry   (carry)
    );

    task check_counter;
        if (q !== (10'b1 << expected) || carry !== (expected < 5))
            $fatal (1, "4017 state/carry mismatch: expected=%0d q=%b carry=%b",
                expected, q, carry);
    endtask

    task tick;
        @ (posedge clk);
        expected = rst ? 0 : inhibit ? expected : (expected + 1) % 10;
        # 1;  // Counter register and decoded output settling.
        check_counter ();
    endtask

    initial
    begin
        @ (posedge clk);
        # 1;  // Assert reset after the clock event, without a stimulus/DUT race.
        rst      = 1'b1;
        expected = 0;
        # 1;  // Check asynchronous reset before the next clock edge.
        check_counter ();

        // Inputs are changed after sampling, safely before the next clock edge.
        for (int i = 0; i < 256; i ++)
        begin
            a = 8' (i);
            tick ();

            if (   or2 !== { (| a [7:6]), (| a [5:4]), (| a [3:2]), (| a [1:0]) }
                || or4 !== { (| a [7:4]), (| a [3:0]) })
                $fatal (1, "OR pin truth-table mismatch input=%h", a);
        end

        rst = 1'b0;

        repeat (30)
            tick ();

        inhibit = 1'b1;
        # 1;  // Raising inhibit while CLOCK is high must not count.
        check_counter ();

        repeat (4)
            tick ();

        // Necessary exception: falling INHIBIT with CLOCK low must not count.
        // Posedge-only stimulus cannot test this half of the chip's truth table.
        @ (negedge clk);
        inhibit = 1'b0;
        # 1;  // Settle the effective clock and output decode before checking.
        check_counter ();

        tick ();

        inhibit = 1'b1;
        # 1;  // Raising inhibit with CLOCK high must not count.
        check_counter ();

        inhibit  = 1'b0;
        expected = (expected + 1) % 10;
        # 1;  // Falling inhibit with CLOCK high IS a count event.
        check_counter ();

        rst      = 1'b1;
        expected = 0;
        # 1;  // Reset must act without waiting for the next clock edge.
        check_counter ();

        inhibit = 1'b1;
        tick ();
        inhibit = 1'b0;
        # 1;  // Reset also dominates the falling-INHIBIT count event.
        check_counter ();

        repeat (2)
            tick ();

        $display ("PASS CMOS: 256 OR input combinations; 30 count edges; carry, inhibit and asynchronous reset");
        $finish;
    end

    initial
    begin
        repeat (timeout_cycles) @ (posedge clk);
        $fatal (1, "Timeout after %0d clock cycles", timeout_cycles);
    end

endmodule
Тесты BGM и Tiny Tapeout

tb/tb_integrations.sv

// Simulation only. Both core versions in all three integration wrappers.

module tb_integrations;

    timeunit 1ns;
    timeprecision 1ps;

    localparam period         = 20;
    localparam timeout_cycles = 200;

    logic clk = 1'b0;
    logic rst = 1'b0;
    logic ena = 1'b1;

    always # (period / 2) clk = ~ clk;

    logic [7:0] ui  = '0;
    logic [7:0] key = '0;

    logic [7:0] lab_led  [0:1];
    logic [7:0] hack_led [0:1];
    logic [7:0] tt_out   [0:1];
    logic [7:0] tt_io    [0:1];
    logic [7:0] tt_oe    [0:1];

    int n_bgm = 0;
    int n_tt  = 0;
    logic [7:0] seven [0:9];

    generate
        genvar k;

        for (k = 0; k < 2; k ++)
        begin : versions
            lab_top # (.CHIP_MODEL (k)) lab
            (
                .clk      (clk),
                .slow_clk (clk),
                .rst      (rst),
                .key      (key [3:0]),
                .sw       (8'b0),
                .led      (lab_led [k]),
                .abcdefgh (),
                .digit    (),
                .x        (10'b0),
                .y        (9'b0),
                .red      (),
                .green    (),
                .blue     (),
                .mic      (24'b0),
                .sound    (),
                .uart_rx  (1'b0),
                .uart_tx  (),
                .gpio     ()
            );

            hackathon_top # (.CHIP_MODEL (k)) hack
            (
                .clock      (clk),
                .slow_clock (clk),
                .reset      (rst),
                .key        (key),
                .led        (hack_led [k]),
                .abcdefgh   (),
                .digit      (),
                .x          (9'b0),
                .y          (9'b0),
                .red        (),
                .green      (),
                .blue       (),
                .gpio       ()
            );

            tt_um_timofei_traffic_light # (.USE_CHIP_MODEL (k)) tt
            (
                .ui_in   (ui),
                .uo_out  (tt_out [k]),
                .uio_in  (8'b0),
                .uio_out (tt_io [k]),
                .uio_oe  (tt_oe [k]),
                .ena     (ena),
                .clk     (clk),
                .rst_n   (~ rst)
            );
        end
    endgenerate

    task check_all;
        logic [2:0] bgm_lamps;
        logic [2:0] tt_lamps;
        logic [7:0] segments;

        bgm_lamps = n_bgm < 4 ? 3'b001 : n_bgm < 6 ? 3'b010 : 3'b100;
        tt_lamps  = n_tt  < 4 ? 3'b001 : n_tt  < 6 ? 3'b010 : 3'b100;
        segments  = ui [0] ? seven [n_tt] : n_tt < 4 ? 8'h01 : n_tt < 6 ? 8'h40 : 8'h08;

        for (int j = 0; j < 2; j ++)
        begin
            if (   lab_led  [j] !== { 5'b0, bgm_lamps }
                || hack_led [j] !== { 5'b0, bgm_lamps })
                $fatal (1, "BGM output mismatch state=%0d model=%0d", n_bgm, j);

            if (   tt_out [j] !== (ena ? segments : 8'b0)
                || tt_io  [j] !== (ena ? { 5'b0, tt_lamps } : 8'b0)
                || tt_oe  [j] !== (ena ? 8'h07 : 8'b0))
                $fatal (1, "Tiny Tapeout output mismatch state=%0d model=%0d", n_tt, j);
        end
    endtask

    task tick;
        @ (posedge clk);
        n_bgm = rst || key [0] ? 0 : (n_bgm + 1) % 10;
        n_tt  = rst           ? 0 : (n_tt  + 1) % 10;
        # 1;  // Register updates and wrapper output decoding must settle.
        check_all ();
    endtask

    initial
    begin
        seven [0] = 8'h3f;
        seven [1] = 8'h06;
        seven [2] = 8'h5b;
        seven [3] = 8'h4f;
        seven [4] = 8'h66;
        seven [5] = 8'h6d;
        seven [6] = 8'h7d;
        seven [7] = 8'h07;
        seven [8] = 8'h7f;
        seven [9] = 8'h6f;

        @ (posedge clk);
        # 1;  // Drive reset after the clock event, without a stimulus/DUT race.
        rst   = 1'b1;
        n_bgm = 0;
        n_tt  = 0;
        # 1;  // Asynchronous reset must be observable before the next clock.
        check_all ();
        rst = 1'b0;

        // Each display mode sees all ten states; stimulus changes after sampling.
        for (int i = 0; i < 30; i ++)
        begin
            ui = 8' ((i / 10) % 2);
            tick ();
        end

        // ena blanks TT outputs but must not stop the internal state sequence.
        ena = 1'b0;

        repeat (3)
            tick ();

        ena = 1'b1;
        # 1;  // Combinational output-enable and display settling.
        check_all ();

        // Check the BGM reset button independently of the dedicated TT reset.
        key   = 8'd1;
        n_bgm = 0;
        # 1;  // Asynchronous button reset; TT must retain its own state.
        check_all ();

        repeat (2)
            tick ();

        key = '0;
        tick ();

        rst   = 1'b1;
        n_bgm = 0;
        n_tt  = 0;
        # 1;  // Asynchronous dedicated reset in all wrappers.
        check_all ();

        repeat (2)
            tick ();

        rst = 1'b0;
        tick ();

        $display ("PASS integrations: both implementations in BGM lab/hackathon and Tiny Tapeout; 30 steps, both display modes, 3 disabled cycles, independent button and dedicated resets");
        $finish;
    end

    initial
    begin
        repeat (timeout_cycles) @ (posedge clk);
        $fatal (1, "Timeout after %0d clock cycles", timeout_cycles);
    end

endmodule
cd breadboard/traffic_light
./scripts/run_icarus.sh
./scripts/run_questa.sh
./scripts/run_verilator.sh

Запустите любой установленный симулятор или все три. Скрипты работают в отдельных подкаталогах build/, запускают три тестбенча и требуют строку PASS. Основной тест записывает traffic_light.vcd. Пути к программам можно задать переменными окружения IVERILOG/VVP, VLIB/VMAP/VLOG/VSIM или VERILATOR.

СредствоРезультат проверки
Icarus 12.0 / 14.0Симуляция проходит. Требуемая цель совместимости — Icarus 13; именно эта версия здесь не установлена.
Questa 2025.2Все исходники компилируются без ошибок и предупреждений. Запуск недоступен: лицензия симулятора не настроена.
Verilator 5.053 develВсе три тестбенча проходят с --binary --timing --trace.
Yosys + SlangОба основных варианта синтезируются и проходят check -assert.

Для синтеза запустите python3 scripts/check_synthesis.py с Yosys, включающим фронтенд Slang; при необходимости задайте путь к программе через YOSYS. Оба варианта проходят проверку на исходном современном SystemVerilog. Встроенный парсер локального Yosys 0.43 не принимает объявления timeunit.

Тестбенчи используют обычные процедурные конструкции SystemVerilog-2012 без UVM, DPI и классов конкретного симулятора. Протокол проверки · Общий скрипт запуска · Проверка синтеза. Физическая схема пока не проверялась.

12. Подключение к BGM lab_top

Используйте slow_clk BGM, а не исходный такт в мегагерцах. В проверенной оболочке Tang Nano 9K + LCD + TM1638 формируется медленный такт 1 Гц. Для длительностей в секундах другие конфигурации должны давать ту же частоту.

traffic_light dut
(
    .clk    (slow_clk),
    .rst    (rst | key [0]),
    .red    (lamp_red),
    .yellow (lamp_yellow),
    .green  (lamp_green),
    .state  (state)
);
// Or instantiate traffic_light_chips with the same ports.

Полный пример сохраняет параметризованный интерфейс BGM, выводит красный/жёлтый/зелёный на LED 0/1/2 и заполняет экран текущим цветом. Неиспользуемые выходы явно заданы. key[0] — сброс; нужны как минимум одна кнопка и три LED. Для варианта соединений микросхем установите CHIP_MODEL=1.

Полный lab_top.sv

integration/bgm_lab/lab_top.sv

// Full BGM lab interface. Requires w_key >= 1 and w_led >= 3.

module lab_top
# (
    parameter CHIP_MODEL    = 0,
    parameter clk_mhz       = 50,
    parameter w_key         = 4,
    parameter w_sw          = 8,
    parameter w_led         = 8,
    parameter w_digit       = 8,
    parameter w_gpio        = 100,

    parameter screen_width  = 640,
    parameter screen_height = 480,

    parameter w_red         = 4,
    parameter w_green       = 4,
    parameter w_blue        = 4,

    parameter w_x           = $clog2 (screen_width),
    parameter w_y           = $clog2 (screen_height)
)
(
    input                  clk,
    input                  slow_clk,
    input                  rst,

    // Keys, switches, LEDs

    input  [w_key   - 1:0] key,
    input  [w_sw    - 1:0] sw,
    output [w_led   - 1:0] led,

    // A dynamic seven-segment display

    output [          7:0] abcdefgh,
    output [w_digit - 1:0] digit,

    // Graphics

    input  [w_x     - 1:0] x,
    input  [w_y     - 1:0] y,

    output [w_red   - 1:0] red,
    output [w_green - 1:0] green,
    output [w_blue  - 1:0] blue,

    // Microphone, sound output and UART

    input  [         23:0] mic,
    output [         15:0] sound,

    input                  uart_rx,
    output                 uart_tx,

    // General-purpose Input/Output

    inout  [w_gpio  - 1:0] gpio
);

    timeunit 1ns;
    timeprecision 1ps;

    logic lamp_red, lamp_yellow, lamp_green;
    logic [9:0] state;

    wire exercise_reset = rst | key [0];

    generate
        if (CHIP_MODEL == 0)
        begin : generic_version
            traffic_light dut
            (
                .clk    (slow_clk),
                .rst    (exercise_reset),
                .red    (lamp_red),
                .yellow (lamp_yellow),
                .green  (lamp_green),
                .state  (state)
            );
        end
        else
        begin : chip_version
            traffic_light_chips dut
            (
                .clk    (slow_clk),
                .rst    (exercise_reset),
                .red    (lamp_red),
                .yellow (lamp_yellow),
                .green  (lamp_green),
                .state  (state)
            );
        end
    endgenerate

    // Infrastructure LEDs and graphics use active-high logical signals.

    assign led      = w_led' ({ 5'b0, lamp_green, lamp_yellow, lamp_red });
    assign red      = { w_red   { lamp_red   | lamp_yellow } };
    assign green    = { w_green { lamp_green | lamp_yellow } };
    assign blue     = '0;
    assign abcdefgh = '0;
    assign digit    = '0;
    assign sound    = '0;
    assign uart_tx  = 1'b1;
    assign gpio     = 'z;

    wire unused_inputs = & { 1'b0, clk, sw, key, x, y, mic, uart_rx, state };

endmodule

В новом каталоге упражнения внутри BGM скопируйте вспомогательные файлы скриптом ниже, затем перенесите стандартные нумерованные .bash-скрипты из соседнего упражнения. Выберите плату обычным способом BGM. Скрипт подготовки не перезаписывает существующий каталог; он не запускает синтез и не прошивает плату.

python3 scripts/stage_integration.py lab /path/to/BGM/labs/1_basics/1_11_timofei_traffic_light

13. Подключение к BGM hackathon_top

Реальное имя модуля BGM — hackathon_top (в «hackaton_top» из задания пропущена h). Его сигналы — slow_clock и reset. Пример соответствует интерфейсу хакатона Tang Nano 9K 480×272 + TM1638.

traffic_light_chips dut
(
    .clk    (slow_clock),
    .rst    (reset | key [0]),
    .red    (lamp_red),
    .yellow (lamp_yellow),
    .green  (lamp_green),
    .state  (state)
);
Полный hackathon_top.sv

integration/bgm_hackathon/hackathon_top.sv

// The BGM module is spelled hackathon_top, with "h".

module hackathon_top
# (
    parameter CHIP_MODEL = 0
)
(
    input        clock,
    input        slow_clock,
    input        reset,

    input  [7:0] key,
    output [7:0] led,

    // A dynamic seven-segment display

    output [7:0] abcdefgh,
    output [7:0] digit,

    // LCD screen interface

    input  [8:0] x,
    input  [8:0] y,

    output [4:0] red,
    output [5:0] green,
    output [4:0] blue,

    inout  [3:0] gpio
);

    timeunit 1ns;
    timeprecision 1ps;

    logic lamp_red, lamp_yellow, lamp_green;
    logic [9:0] state;

    wire exercise_reset = reset | key [0];

    generate
        if (CHIP_MODEL == 0)
        begin : generic_version
            traffic_light dut
            (
                .clk    (slow_clock),
                .rst    (exercise_reset),
                .red    (lamp_red),
                .yellow (lamp_yellow),
                .green  (lamp_green),
                .state  (state)
            );
        end
        else
        begin : chip_version
            traffic_light_chips dut
            (
                .clk    (slow_clock),
                .rst    (exercise_reset),
                .red    (lamp_red),
                .yellow (lamp_yellow),
                .green  (lamp_green),
                .state  (state)
            );
        end
    endgenerate

    assign led      = { 5'b0, lamp_green, lamp_yellow, lamp_red };
    assign red      = { 5 { lamp_red   | lamp_yellow } };
    assign green    = { 6 { lamp_green | lamp_yellow } };
    assign blue     = '0;
    assign abcdefgh = '0;
    assign digit    = '0;
    assign gpio     = 'z;

    wire unused_inputs = & { 1'b0, clock, key, x, y, state };

endmodule

Установите CHIP_MODEL=0 для обобщённого варианта или 1 для модели микросхем. Нужна конфигурация платы с USE_HACKATHON_TOP, например tang_nano_9k_lcd_480_272_tm1638_hackathon.

python3 scripts/stage_integration.py hackathon /path/to/BGM/hackathon/problems/11_timofei_traffic_light

14. Подключение к Tiny Tapeout project.v

Файл project.v использует заданный интерфейс Tiny Tapeout и уникальное имя верхнего модуля tt_um_timofei_traffic_light. rst_n активен нулём, поэтому автомат получает ~rst_n. Установите внешний такт проекта 1 Гц; оболочка не делит такт в мегагерцах.

Порт / RP2350Назначение
clk / GPIO16; rst_n / GPIO14Такт и сброс; выбрать проект, подать сброс, затем запустить такт.
ui_in[0] / GPIO17DIP 0: 0 = полоски по положению огня, 1 = номер состояния 0…9. Остальные DIP не используются.
uo_out[7:0] / GPIO40…33{dp, g, f, e, d, c, b, a} · активный уровень 1
uio_out[2:0] / GPIO27…25{green, yellow, red}
uio_oe[7:0]00000111 при ena=1; иначе все выводы — входы.
enaРазрешение мультиплексора проектов, не вывод платы. При 0 гасит индикатор и отключает двунаправленные выходы; счёт состояний не останавливает.

В режиме полосок сегмент a (верхний) означает красный, g (средний) — жёлтый, d (нижний) — зелёный; сам индикатор не меняет цвет светодиодов. В десятичном режиме показывается номер состояния, а не обратный отсчёт. Этот порядок отличается от BGM abcdefgh[7:0]. Пока проект управляет uio[2:0], соответствующие выводы RP2350 должны быть входами.

Полный project.v

integration/tinytapeout/project.v

// Synthesizable Tiny Tapeout top; compile as SystemVerilog.
// Set the external project clock to 1 Hz.
// Set USE_CHIP_MODEL to 1 to synthesize the pin-connected version.

module tt_um_timofei_traffic_light
# (
    parameter USE_CHIP_MODEL = 0
)
(
    input  [7:0] ui_in,
    output [7:0] uo_out,
    input  [7:0] uio_in,
    output [7:0] uio_out,
    output [7:0] uio_oe,
    input        ena,
    input        clk,
    input        rst_n
);

    timeunit 1ns;
    timeprecision 1ps;

    logic red, yellow, green;
    logic [9:0] state;

    generate
        if (USE_CHIP_MODEL == 0)
        begin : generic_version
            traffic_light dut
            (
                .clk    (clk),
                .rst    (~ rst_n),
                .red    (red),
                .yellow (yellow),
                .green  (green),
                .state  (state)
            );
        end
        else
        begin : chip_version
            traffic_light_chips dut
            (
                .clk    (clk),
                .rst    (~ rst_n),
                .red    (red),
                .yellow (yellow),
                .green  (green),
                .state  (state)
            );
        end
    endgenerate

    // TT output order [7:0] = { dp, g, f, e, d, c, b, a }; active high.
    // DIP 0 = 0: top/middle/bottom bar represents red/yellow/green.
    // DIP 0 = 1: show state number 0..9, not seconds remaining.

    logic [7:0] decimal_segments;

    always_comb
    begin
        decimal_segments = '0;

        case (state)
        10'b00_0000_0001: decimal_segments = 8'h3f;
        10'b00_0000_0010: decimal_segments = 8'h06;
        10'b00_0000_0100: decimal_segments = 8'h5b;
        10'b00_0000_1000: decimal_segments = 8'h4f;
        10'b00_0001_0000: decimal_segments = 8'h66;
        10'b00_0010_0000: decimal_segments = 8'h6d;
        10'b00_0100_0000: decimal_segments = 8'h7d;
        10'b00_1000_0000: decimal_segments = 8'h07;
        10'b01_0000_0000: decimal_segments = 8'h7f;
        10'b10_0000_0000: decimal_segments = 8'h6f;
        default:          decimal_segments = '0;
        endcase
    end

    wire [7:0] bars = { 1'b0, yellow, 2'b00, green, 2'b00, red };

    assign uo_out  = ena ? (ui_in [0] ? decimal_segments : bars) : '0;
    assign uio_out = ena ? { 5'b0, green, yellow, red } : '0;
    assign uio_oe  = ena ? 8'b0000_0111 : '0;

    wire unused_inputs = & { 1'b0, ui_in [7:1], uio_in };

endmodule
python3 scripts/stage_integration.py tinytapeout /tmp/timofei_tt_sources

Выберите фронтенд синтеза с поддержкой timeunit и timeprecision, например Slang для Yosys. Если шаблон использует старый встроенный парсер Yosys, перед синтезом этих исходников нужно сменить фронтенд.

Скопируйте подготовленные исходники в src/ выбранного шаблона Tiny Tapeout. Перенесите фрагмент списка исходников в его info.yaml, сохранив обязательные поля автора, названия, выводов и документации. Это не полный файл подачи проекта. Для варианта соединений микросхем перед синтезом установите USE_CHIP_MODEL=1.

Официальная таблица GPIO платы · Шаблон Verilog · Запуск платы

15. Первый запуск, задания и источники

  1. При выключенном питании установите микросхемы и все 37 перемычек. Проверьте выемки, выводы питания и разрывы шин.
  2. Подключите модули и индикаторы с ограничением тока. До запуска проверьте 5 В между шинами.
  3. Настройте готовый генератор примерно на 1 Гц. Удерживайте RESET=1: красный должен гореть, несмотря на тактирование.
  4. Отпустите сброс. Наблюдайте повторение красного/жёлтого/зелёного в отношении 4/2/4. Измеряйте полный цикл после начального интервала сброса.
  5. Запустите тестбенчи. Затем подключите любой вариант через готовую оболочку для ПЛИС или ASIC.
НаблюдениеЧто проверить
Всегда красныйRESET постоянно равен 1, нет фронтов такта или U1.13 не на GND.
Нет одного цветаПолярность LED, вывод выхода ИЛИ и соответствующие входы Q.
Неверная длительность / пропущен цветПерепутаны номера состояний и физических выводов; свериться с таблицей.
Тусклые огни или нестабильностьИзмеренное питание, общая земля, нагрузка модулей и определённость входных уровней. Логическая HDL-симуляция этого не проверяет.

Следующие задания: измените группировку на 3/3/4; сначала перерисуйте граф состояний и предскажите таблицу, затем меняйте провода. Объясните, почему прямое соединение выходов Q не заменяет ИЛИ. Сравните one-hot RTL с двоичным счётчиком 0…9 и дешифратором. Разберите разницу между коротким переходным эффектом задержек и неверным установившимся состоянием.

Схемы и модели без задержек описывают установившуюся логику. У реальных выходов есть задержки распространения; упражнение не доказывает отсутствие переходных импульсов на огнях. Используется готовый тактовый модуль курса: собирать генератор здесь не нужно.

Источники и воспроизводимость

Страницы: python3 breadboard/tools/build_site.py; схемы и структурный RTL: python3 breadboard/tools/build_diagrams.py --png. Для PNG нужен Inkscape. Проверки проводов · Контрольные суммы исходников BGM.