Урок 0. Логика: 0 и 1, вентили из транзисторов, сумматор

В картинках

Фундамент перед часами. Здесь — что такое 0 и 1, три операции над ними (булева алгебра), как из транзисторов получается логический вентиль и как из вентилей собрать полезную вещь — схему, которая складывает два 4-битных числа. Всё дальше в наборе — те же вентили, только их больше.

Итог: NOT (2 транзистора), NAND и NOR (по 4), AND и OR (по 6), XOR (16), полный сумматор FA (50), 4-битный сумматор ADD4 (200) — все 256 сумм от 0+0 до 15+15 верны.


0.1. Симулятор

Всё собирается в браузере: cs.khanin.info. Установка и регистрация не нужны; удобнее работать на компьютере с мышью.

Это учебный симулятор, а не программа для разработки настоящей электроники. Транзистор в нём — идеальный выключатель (открыт или закрыт), сигнал — только 0 или 1. Напряжений, токов, задержек в проводах, нагрева и помех нет. Чтобы понять, как работает логика, память и процессор, этого хватает с запасом; схему для настоящей платы по нему не спроектируешь — там нужны резисторы, расчёт питания и временных запасов.

Как ставить детали, метки, чипы — в разделе «Симулятор за пять минут» перед уроками. Главное здесь: метки с одинаковым именем соединены, Ctrl+G сворачивает выделенное в чип, Export сохраняет работу.


0.2. Булева алгебра: 0, 1 и три операции

Сигнал — 0 или 1 (нет/есть, ложь/истина, выключено/включено). Булева алгебра (Джордж Буль, 1847) — арифметика таких значений. Операций всего три:

  • НЕ (NOT) — переворачивает: НЕ 0 = 1, НЕ 1 = 0. В наборе пишем приставкой n: nA = НЕ A.
  • И (AND) — A·B равно 1, только когда оба входа 1.
  • ИЛИ (OR) — A + B равно 1, когда хотя бы один вход 1.

Их комбинации получили свои имена, потому что встречаются постоянно:

ABA·BA + BNANDNORXOR
0000110
0101101
1001101
1111000
  • NAND = НЕ(И), NOR = НЕ(ИЛИ).
  • XOR («исключающее ИЛИ», A ⊕ B) — 1, когда входы разные. Это сложение одного бита без переноса: 1 + 1 = 0, а единица уходит в перенос (пригодится в 0.5).

⚠ Плюс в булевой алгебре — это ИЛИ, а не сложение: 1 + 1 = 1.

Законы, по которым формулы упрощают (каждый проверяется подстановкой 0 и 1):

ЗаконПример
с константойA·1 = A
A·0 = 0
A + 0 = A
A + 1 = 1
с самим собойA·A = A
A + A = A
с противоположнымA·nA = 0
A + nA = 1
двойное НЕНЕ(nA) = A
вынос за скобкуA·B + A·C = A·(B + C)
склейкаA·B + A·nB = A
де МорганНЕ(A·B) = nA + nB
НЕ(A + B) = nA·nB

Закон де Моргана словами: «не (оба)» = «хотя бы один нет». Он позволяет менять И на ИЛИ ценой переворотов — так в уроке 3 мультиплексор переделан на одни NAND и стал дешевле.


0.3. Транзистор — выключатель

В палитре — деталь Transistor. У неё три ноги: затвор G слева, верх и низ. Затвор управляет, соединены ли верх и низ. Alt + клик по корпусу (на Mac — ⌥ или ⌘ + клик) меняет тип N ↔ P — обычный клик тип не трогает:

  • N: затвор = 1 → верх и низ соединены; затвор = 0 → разомкнуты.
  • P: наоборот — соединены при затворе = 0.

Правило CMOS (так устроены почти все микросхемы с 1980-х): P-транзисторы ставим сверху, между VCC (источник 1) и выходом; N — снизу, между выходом и GND (источник 0). При любом входе проводит ровно одна половина — выход всегда подключён либо к 1, либо к 0. Никогда к обоим сразу (закоротка) и никогда ни к чему (обрыв, выход «висит»).


верхNG=0низразомкнутоверхNG=1низсоединеноверхPG=0низсоединеноверхPG=1низразомкнутоN: проводит при G = 1P: проводит при G = 0 (кружок — «наоборот»)
Транзистор в симуляторе — выключатель между ногами «верх» и «низ», которым управляет затвор G. N проводит при G = 1, P — при G = 0. Выделено то, что соединено.

0.4. NOT, NAND, NOR из транзисторов

NOT — два транзистора. Вход A идёт на оба затвора: при A = 0 открыт верхний P и выход тянется к 1, при A = 1 — нижний N, выход тянется к 0.

ПОРТЫ-ВХОДЫ: A · ПОРТЫ-ВЫХОДЫ: Y

ТранзисторЗатворВерхНиз
PAVCCY
NAYGND
VCC = 1PA=1NA=1Y = 0GND = 0P закрыт: к VCC нет путиN открыт: Y соединён с GNDодин вход A —на оба затвора
NOT из двух транзисторов при A = 1: нижний N проводит и соединяет выход с землёй, верхний P закрыт. Y = 0. При A = 0 всё наоборот — проводит P, Y = 1.

Сборка в чип: Ctrl+G → NOT.

NAND — четыре. Два P параллельно сверху: хватит одного нуля на входе, чтобы выход стал 1. Два N последовательно снизу: выход соединится с землёй, только когда оба входа 1. Точку между двумя N назовём меткой mid.

ПОРТЫ-ВХОДЫ: A, B · ПОРТЫ-ВЫХОДЫ: Y

ТранзисторЗатворВерхНиз
PAVCCY
PBVCCY
NAYmid
NBmidGND
VCC = 1VCC = 1PA=1PB=1Y = 0NA=1midNB=1GND = 0два P параллельно:любой 0 даст Y = 1два N подряд: к GND —только когда оба = 1
NAND из четырёх транзисторов при A = 1, B = 1: оба нижних N открыты, путь Y → mid → GND замкнут, оба P закрыты — Y = 0. Стоит хотя бы одному входу стать 0 — его N разорвёт цепочку, а его P соединит Y с VCC.

Сборка в чип: Ctrl+G → NAND.

NOR — зеркально: два P последовательно (выход 1, только когда оба входа 0), два N параллельно (любая единица тянет выход к 0).

ПОРТЫ-ВХОДЫ: A, B · ПОРТЫ-ВЫХОДЫ: Y

ТранзисторЗатворВерхНиз
PAVCCmid
PBmidY
NAYGND
NBYGND

Сборка в чип: Ctrl+G → NOR.

AND, OR, XOR — из вентилей. Транзисторы больше не нужны: три недостающих вентиля собираются из только что собранных NOT, NAND, NOR.

AND = NAND + NOT — «И-НЕ», а потом перевернуть:

ПОРТЫ-ВХОДЫ: A, B · ПОРТЫ-ВЫХОДЫ: Y

ЭлементВходыВыход
NANDA, Bn
NOTnY

Сборка в чип: Ctrl+G → AND.

OR = NOR + NOT:

ПОРТЫ-ВХОДЫ: A, B · ПОРТЫ-ВЫХОДЫ: Y

ЭлементВходыВыход
NORA, Bn
NOTnY

Сборка в чип: Ctrl+G → OR.

XOR — «хотя бы один, но не оба»: AND( OR(A, B), NAND(A, B) ):

ПОРТЫ-ВХОДЫ: A, B · ПОРТЫ-ВЫХОДЫ: Y

ЭлементВходыВыход
ORA, Bo
NANDA, Bn
ANDo, nY

Сборка в чип: Ctrl+G → XOR.

Проверка. Питание: V (Power) с меткой VCC и G (Ground) с меткой GND; два тумблера X, Y; к выходам — лампочки (LED):

ЭлементВходыВыход
NOTXnotX
NANDX, YnandXY
NORX, YnorXY
ANDX, YandXY
ORX, YorXY
XORX, YxorXY
LEDnotX
LEDnandXY
LEDnorXY
LEDandXY
LEDorXY
LEDxorXY

Пощёлкай тумблерами — лампы должны повторять таблицу из 0.2. Или выдели чип и нажми T — таблица истинности.

Цена в транзисторах: NOT — 2, NAND и NOR — по 4. А AND = NAND + NOT = 6, OR = NOR + NOT = 6: «И» дороже, чем «И-НЕ». Поэтому в CMOS родные вентили — NAND и NOR, и формулы выгодно сводить к ним. XOR — 16 транзисторов.

Эти шесть чипов — NOT, NAND, NOR, AND, OR, XOR — теперь в вашей библиотеке справа, и на них стоит весь набор. Дальше транзисторы руками не ставим: берём эти вентили.


0.5. Сложение одного разряда

Складываем двоичные числа столбиком, как десятичные: 0 + 0 = 0, 0 + 1 = 1, 1 + 1 = 10 — ноль пишем, единицу переносим в следующий разряд. В каждом разряде складываются три бита: A, B и перенос из младшего разряда CI. Выходов два: бит суммы S и перенос дальше CO.

ABCISCOединиц
000000
001101
010101
011012 = 10
100101
101012 = 10
110012 = 10
111113 = 11

Как выводили:

  • S = 1, когда единиц нечётное число — это и есть XOR трёх битов: S = A ⊕ B ⊕ CI.
  • CO = 1, когда единиц две или три. Либо обе A и B (A·B), либо ровно одна из них (A ⊕ B) и перенос: CO = A·B + (A ⊕ B)·CI.

A ⊕ B нужен и для S, и для CO — считаем один раз, метка p.

ПОРТЫ-ВХОДЫ: A, B, CI · ПОРТЫ-ВЫХОДЫ: S, CO

ЭлементВходыВыход (→)
XORA, Bp
XORp, CIS
ANDA, Bg
ANDp, CIpc
ORg, pcCO
A=1B=1CI=0XORANDp=0XORS = 0ANDg=1pc=0ORCO = 11 + 1 + 0 = 10: сумма 0, перенос 1
Полный сумматор FA на примере A = 1, B = 1, CI = 0. p = A ⊕ B = 0 нужен обоим выходам — считается один раз. S = p ⊕ CI = 0; перенос CO = A·B + p·CI = 1 приходит от g = A·B.

Сборка в чип: Ctrl+G → FA (full adder — полный сумматор), входы A B CI, выходы S CO, 50 транзисторов. Проверка: T — восемь строк, как в таблице выше.


0.6. Сумматор 4 бит

Четыре FA в цепочку: перенос CO каждого разряда идёт на CI следующего. У младшего разряда переноса нет — CI = GND (0). Перенос старшего — это пятый бит суммы S4: 15 + 15 = 30 = 11110, в четыре бита не влезает.

ПОРТЫ-ВХОДЫ: A0 A1 A2 A3, B0 B1 B2 B3 · ПОРТЫ-ВЫХОДЫ: S0 S1 S2 S3 S4

ЭлементВходыВыход (→)
FAA=A0, B=B0, CI=GNDS→S0, CO→c1
FAA=A1, B=B1, CI=c1S→S1, CO→c2
FAA=A2, B=B2, CI=c2S→S2, CO→c3
FAA=A3, B=B3, CI=c3S→S3, CO→S4
FAA0=1B0=1S0=0c1=1FAA1=1B1=0S1=0c2=1FAA2=1B2=0S2=0c3=1FAA3=0B3=0S3=1GNDS4=00111 + 0001 = 01000 (7 + 1 = 8): перенос пробегает все разряды
ADD4 — четыре FA цепочкой, младший разряд справа, как при сложении столбиком. На примере 7 + 1 перенос рождается в разряде 0 и бежит влево через все разряды: c1 = c2 = c3 = 1, итог 01000.

Сборка в чип: Ctrl+G → ADD4, 200 транзисторов.

Такой сумматор называется последовательным переносом (ripple carry): перенос «бежит» от младшего разряда к старшему, как при сложении столбиком. Самый долгий случай — 0111 + 0001: единица переноса проходит через все четыре разряда. Сумматор — сердце любого процессора: из него же делают вычитание, сравнение и счётчики.


0.7. Холст и проверка

  1. Питание: V (Power) с меткой VCC, G (Ground) с меткой GND (если уже стоят с проверки вентилей — не нужно).
  2. Восемь тумблеров (I) → метки A0 A1 A2 A3 и B0 B1 B2 B3.
  3. Чип ADD4, на его ноги — одноимённые метки: A0…A3, B0…B3, S0…S4.
  4. Три Display (bus). На каждом: клик по ⚙ слева сверху меняет разрядность (4b / 8b / 16b / 32b), клик по PIN слева снизу — ввести имя шины, и табло само читает метки имя0, имя1, …, без проводов:
ЭлементРазрядностьШина
Display (bus)4bA
Display (bus)4bB
Display (bus)8bS

У суммы 5 бит, а у табло таких нет — ставим 8b: битов S5…S7 на холсте нет, табло считает их нулями.

Проверка: 3 + 4 = 7, 7 + 1 = 8 (перенос пробегает все разряды), 15 + 15 = 30 (горит S4). Любые 4-битные числа складываются верно — проверены все 256 пар.


Вставка урока 0 (Cmd+I)

Создаёт в пустом проекте все базовые вентили набора (NOT, NAND, NOR, AND, OR, XOR), FA, ADD4 и ставит на холст питание, проверку вентилей с лампами и сумматор с тремя табло.

# Урок 0 — вентили из транзисторов и 4-битный сумматор.# Вставка: Cmd+I в пустой проект: собирает все базовые вентили набора (NOT NAND NOR AND OR XOR), FA и ADD4.# Транзистор: nmos/pmos(затвор, верх, низ). VCC/GND — общие шины питания. # --- вентили из транзисторов ---chip NOT {  portIn(A)  portOut(Y)  pmos(A, VCC, Y)  nmos(A, Y, GND)} # NAND: два P параллельно сверху, два N последовательно снизуchip NAND {  portIn(A)  portIn(B)  portOut(Y)  pmos(A, VCC, Y)  pmos(B, VCC, Y)  nmos(A, Y, mid)  nmos(B, mid, GND)} # NOR: два P последовательно сверху, два N параллельно снизуchip NOR {  portIn(A)  portIn(B)  portOut(Y)  pmos(A, VCC, mid)  pmos(B, mid, Y)  nmos(A, Y, GND)  nmos(B, Y, GND)} # --- вентили из вентилей ---# AND = NAND + NOT (6 транзисторов)chip AND {  portIn(A)  portIn(B)  portOut(Y)  NAND(A, B, n)  NOT(n, Y)} # OR = NOR + NOT (6 транзисторов)chip OR {  portIn(A)  portIn(B)  portOut(Y)  NOR(A, B, n)  NOT(n, Y)} # XOR = «хотя бы один, но не оба»: AND( OR(A,B), NAND(A,B) ) (16 транзисторов)chip XOR {  portIn(A)  portIn(B)  portOut(Y)  OR(A, B, o)  NAND(A, B, n)  AND(o, n, Y)} # --- полный сумматор одного разряда ---chip FA {  portIn(A)  portIn(B)  portIn(CI)  portOut(S)  portOut(CO)  XOR(A, B, p)  XOR(p, CI, S)  AND(A, B, g)  AND(p, CI, pc)  OR(g, pc, CO)} # --- 4 разряда: перенос бежит от младшего к старшему ---chip ADD4 {  portIn(A0)  portIn(A1)  portIn(A2)  portIn(A3)  portIn(B0)  portIn(B1)  portIn(B2)  portIn(B3)  portOut(S0)  portOut(S1)  portOut(S2)  portOut(S3)  portOut(S4)  FA(A0, B0, GND, S0, c1)  FA(A1, B1, c1, S1, c2)  FA(A2, B2, c2, S2, c3)  FA(A3, B3, c3, S3, S4)} # --- на холст: питание, проверка вентилей, сумматор с табло ---power(VCC)ground(GND)input(X)input(Y)NOT(X, notX)NAND(X, Y, nandXY)NOR(X, Y, norXY)AND(X, Y, andXY)OR(X, Y, orXY)XOR(X, Y, xorXY)led(notX)led(nandXY)led(norXY)led(andXY)led(orXY)led(xorXY)input(A0)input(A1)input(A2)input(A3)input(B0)input(B1)input(B2)input(B3)ADD4(A0, A1, A2, A3, B0, B1, B2, B3, S0, S1, S2, S3, S4)display{bits=4, busSource=A}()display{bits=4, busSource=B}()display{bits=8, busSource=S}()

Не получается? Что-то не работает →