Урок 3. Отрицательные числа и вычитание: дополнительный код
В картинкахПосле этого урока тот же сумматор научится вычитать: тумблер SUB превращает A + B в A − B. Четыре лампы покажут флаги — то, что процессор знает о каждом ответе: был ли перенос, ноль ли ответ, отрицательный ли он и поместился ли он в 4 бита.
3.1. Идея: числа по кругу
Четырёхбитный сумматор считает по кругу: 15 + 1 даёт 0 — пятый разряд уходит в перенос. Значит, 1111 ведёт себя как −1: прибавь к нему 1 — получится 0. Так же 1110 — это −2, а 1000 — −8.
Договоримся: если старший бит 1, число отрицательное. Тогда 4 бита — это числа от −8 до 7. Такая запись называется дополнительный код. Сумматору ничего менять не надо: он складывает биты, а что они значат — решаем мы.
Как получить −B: перевернуть все биты B и прибавить 1. Например, 3 = 0011 → 1100 → 1101 = −3. Проверка: 3 + (−3) = 0011 + 1101 = 1 0000 — в 4 битах ноль.
А вычесть — значит прибавить −B:
- биты
BпереворачиваетXORс тумблеромSUB: приSUB = 0бит проходит как есть, приSUB = 1— наоборот; - «плюс 1» даёт тот же
SUB, поданный на вход переносаCIсумматора.
3.2. Флаги
Каждый процессор после сложения или вычитания запоминает четыре бита про ответ:
C(carry) — перенос из старшего разряда. При вычитанииC = 1значит «заёма не было»:A ≥ Bбез знака;Z(zero) — ответ ноль: все разряды 0, этоNORвсех битов;N(negative) — ответ отрицательный: это просто старший бит суммы;V(overflow) — ответ не поместился в числа со знаком: оба слагаемых одного знака, а сумма — другого. Например,7 + 1дают1000— «−8».
По этим флагам процессор принимает решения: «если ноль — перейти», «если меньше — повторить».
3.3. Сборка
Тот же проект. Стенд урока 2 (8 тумблеров, ADDER4 на холсте, три табло) удали; Power/Ground оставь.
Идея. Вычесть B — значит прибавить −B. В дополнительном коде −B = все биты B наоборот и плюс 1. Переворачивает XOR с тумблером SUB (при SUB = 0 бит проходит как есть, при SUB = 1 — наоборот), а «плюс 1» даёт тот же SUB на входе переноса CI сумматора.
Шаг 1. ADDSUB4 — сложение и вычитание
| Деталь | Нога | Метка |
|---|---|---|
| Порт входа | выход | A0 |
| Порт входа | выход | A1 |
| Порт входа | выход | A2 |
| Порт входа | выход | A3 |
| Порт входа | выход | B0 |
| Порт входа | выход | B1 |
| Порт входа | выход | B2 |
| Порт входа | выход | B3 |
| Порт входа | выход | SUB |
| Порт входа | выход | CI |
| XOR (бит 0) | I0 I1 O0 | B0 SUB bx0 |
| XOR (бит 1) | I0 I1 O0 | B1 SUB bx1 |
| XOR (бит 2) | I0 I1 O0 | B2 SUB bx2 |
| XOR (бит 3) | I0 I1 O0 | B3 SUB bx3 |
| ADDER4 | A0 A1 A2 A3 B0 B1 B2 B3 CI S0 S1 S2 S3 CO | A0 A1 A2 A3 bx0 bx1 bx2 bx3 CI S0 S1 S2 S3 CO |
| XOR (знак A ≠ знак S) | I0 I1 O0 | A3 S3 va |
| XOR (знак B ≠ знак S) | I0 I1 O0 | bx3 S3 vb |
| AND (переполнение) | I0 I1 O0 | va vb V |
| Порт выхода | вход | S0 |
| Порт выхода | вход | S1 |
| Порт выхода | вход | S2 |
| Порт выхода | вход | S3 |
| Порт выхода | вход | CO |
| Порт выхода | вход | V |
Ctrl+G → имя ADDSUB4. Ноги: входы A0–A3, B0–B3, SUB, CI; выходы S0–S3, CO, V.
V — переполнение: оба слагаемых одного знака, а сумма — другого (так 7 + 1 дают «−8»).
Шаг 2. Холст: тумблеры, вычитатель, флаги
| Деталь | Нога | Метка |
|---|---|---|
| Input | выход | A0 |
| Input | выход | A1 |
| Input | выход | A2 |
| Input | выход | A3 |
| Input | выход | B0 |
| Input | выход | B1 |
| Input | выход | B2 |
| Input | выход | B3 |
| Input | выход | SUB |
| ADDSUB4 | A0 A1 A2 A3 B0 B1 B2 B3 SUB CI S0 S1 S2 S3 CO V | A0 A1 A2 A3 B0 B1 B2 B3 SUB SUB S0 S1 S2 S3 C V |
| OR | I0 I1 O0 | S0 S1 z01 |
| OR | I0 I1 O0 | S2 S3 z23 |
| NOR (ноль) | I0 I1 O0 | z01 z23 Z |
| LED (C — перенос) | вход | C |
| LED (Z — ноль) | вход | Z |
| LED (N — знак) | вход | S3 |
| LED (V — переполнение) | вход | V |
| Display | ⚙ | ширина 4, DEC, шина A |
| Display | ⚙ | ширина 4, DEC, шина B |
| Display | ⚙ | ширина 4, BIN, шина S |
CI вычитателя — на ту же метку SUB: это и есть «плюс 1». Лампа N — просто старший бит суммы S3.
3.4. Проверка
Отрицательные числа в 4 битах: 1111 = −1, 1110 = −2 … 1000 = −8. Старший бит — знак.
| A | Тумблеры A3…A0 | B | Тумблеры B3…B0 | SUB | Табло S | Лампы | Это |
|---|---|---|---|---|---|---|---|
| 3 | 0011 | 4 | 0100 | 0 | 0111 | — | 3 + 4 = 7 |
| 3 | 0011 | 5 | 0101 | 1 | 1110 | N | 3 − 5 = −2 |
| 5 | 0101 | 5 | 0101 | 1 | 0000 | Z, C | 5 − 5 = 0 |
| 2 | 0010 | 3 | 0011 | 1 | 1111 | N | 2 − 3 = −1 (C = 0: был заём) |
| 7 | 0111 | 1 | 0001 | 0 | 1000 | N, V | 7 + 1 не влезает в 4 бита со знаком |
| 9 | 1001 | 9 | 1001 | 0 | 0010 | C, V | −7 + −7 = −14 — тоже переполнение |
В колонках «Тумблеры» слева — старший тумблер (A3), справа — A0; 1 — включён, 0 — выключен.
C при вычитании горит, когда заёма не было (A ≥ B без знака) — так у большинства процессоров, например 6502.
Если при SUB = 1 ответ на единицу меньше — проверь, что CI вычитателя на метке SUB, а не на GND.
Вставка урока 3 (Cmd+I)
Нужны XOR, AND, OR, NOR и ADDER4. Стенд урока 2 удали, кроме питания.
# Урок 3 — вычитание в дополнительном коде и флаги C, Z, N, V.# Вставка: Cmd+I поверх урока 2 (нужны XOR, AND, OR, NOR, ADDER4). Стенд урока 2 удалить, кроме питания. # --- сложение и вычитание: SUB = 1 переворачивает B и добавляет 1 через CI ---chip ADDSUB4 { portIn(A0) portIn(A1) portIn(A2) portIn(A3) portIn(B0) portIn(B1) portIn(B2) portIn(B3) portIn(SUB) portIn(CI) portOut(S0) portOut(S1) portOut(S2) portOut(S3) portOut(CO) portOut(V) XOR(B0, SUB, bx0) XOR(B1, SUB, bx1) XOR(B2, SUB, bx2) XOR(B3, SUB, bx3) ADDER4(A0=A0, A1=A1, A2=A2, A3=A3, B0=bx0, B1=bx1, B2=bx2, B3=bx3, CI=CI, S0=S0, S1=S1, S2=S2, S3=S3, CO=CO) # переполнение: знак результата не совпал со знаком обоих слагаемых XOR(A3, S3, va) XOR(bx3, S3, vb) AND(va, vb, V)} # --- на холст: тумблеры A, B, SUB; вычитатель; флаги на лампах ---input(A0)input(A1)input(A2)input(A3)input(B0)input(B1)input(B2)input(B3)input(SUB)ADDSUB4(A0=A0, A1=A1, A2=A2, A3=A3, B0=B0, B1=B1, B2=B2, B3=B3, SUB=SUB, CI=SUB, S0=S0, S1=S1, S2=S2, S3=S3, CO=C, V=V)# Z: все разряды суммы — нольOR(S0, S1, z01)OR(S2, S3, z23)NOR(z01, z23, Z)led(C)led(Z)led(S3)led(V)Не получается? Что-то не работает →