Архитектура компьютера
АЛУ: Калькулятор внутри процессора
Цели урока
- Понимать структуру и назначение АЛУ
- Знать как работают сумматоры (Ripple Carry, Carry-Lookahead)
- Понимать как вычитание реализуется через сложение
- Знать флаги состояния (Z, N, C, V) и их применение
- Понимать сдвиговые операции и их связь с умножением/делением
Предварительные знания
- Логические вентили
- Двоичная арифметика
- Дополнительный код
2004 год. AMD выпускает Athlon 64 - первый массовый 64-битный процессор. Конкуренты смеются: зачем 64 бита, если адресное пространство 32-бит хватает всем? Через 18 месяцев RAM перешагнула 4 ГБ, и 32-битный мир кончился. Именно АЛУ определяет, с числами какой ширины работает процессор - и этот выбор меняет индустрию.
- **Оптимизация компилятора**: замена умножения сдвигами - одна из первых оптимизаций любого компилятора
- **Integer overflow**: уязвимости типа CVE-2021-3156 (sudo) эксплуатируют именно V-флаг переполнения
- **GPU**: Tensor Core в NVIDIA A100 - специализированное АЛУ для матричного умножения FP16/BF16
Von Neumann и первое АЛУ
В 1945 году фон Нейман описал архитектуру EDVAC в 101-страничном документе - первом формальном описании компьютера. Он явно выделил «Arithmetic Organ» как отдельный блок, ответственный за вычисления. До него Eniac имел жёстко заданные вычислительные цепи. Идея фон Неймана: АЛУ с программируемым кодом операции - одна схема, бесконечно перепрограммируемая. Это работает до сих пор.
Что такое АЛУ?
**АЛУ (Arithmetic Logic Unit)** - «сердце» процессора. Это комбинационная схема, которая выполняет арифметические и логические операции. Когда PyTorch считает градиент, когда браузер отрисовывает пиксель, когда игра проверяет коллизию - всё это АЛУ.
| Операция | Код Op | Результат |
|---|---|---|
| ADD | 0000 | A + B |
| SUB | 0001 | A - B |
| AND | 0010 | A & B |
| OR | 0011 | A | B |
| XOR | 0100 | A ^ B |
| SLT | 0101 | A < B ? 1 : 0 |
**Скорость:** Современное АЛУ выполняет операцию за ~1 наносекунду. Миллиард операций в секунду. GPU с 10 000 АЛУ-ядер - это триллион операций в секунду.
Что определяет код операции (Op) в АЛУ?
Сложение: Ripple Carry Adder
**Полный сумматор (Full Adder)** складывает 3 бита: A, B и входной перенос Cin. Это строительный блок всей цифровой арифметики.
| A | B | Cin | Sum | Cout |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 1 | 1 | 0 |
| 0 | 1 | 0 | 1 | 0 |
| 0 | 1 | 1 | 0 | 1 |
| 1 | 0 | 0 | 1 | 0 |
| 1 | 0 | 1 | 0 | 1 |
| 1 | 1 | 0 | 0 | 1 |
| 1 | 1 | 1 | 1 | 1 |
**Ripple Carry Adder** - цепочка Full Adder'ов. Перенос «пробегает» от младшего бита к старшему:
**Проблема:** Перенос должен «пробежать» через все разряды. Для 64 бит - 64 задержки! Intel сталкивалась с этим при разработке первых 64-битных процессоров.
Почему Ripple Carry Adder медленный для 64-битных чисел?
Вычитание: A - B = A + (NOT B) + 1
**Гениальная идея:** Не нужен отдельный вычитатель. Вычитание - это сложение с дополнительным кодом. Одна схема делает и сложение, и вычитание.
5 - 3 = 2 (4 бита)
Пошаговое вычитание через сложение
A = 0101 (5) B = 0011 (3) Sub = 1: NOT B = 1100 Cin = 1 0101 (A) + 1100 (NOT B) + 0001 (Cin) ------ 0010 = 2 (Перенос C4=1 отбрасывается)
A - B в дополнительном коде равно:
Ускорение: Carry-Lookahead Adder
**Идея:** Не ждать пока перенос «пробежит». Вычислить все переносы параллельно. Это O(1) вместо O(n) - разница между 4 тактами и 64 тактами для 64-битного сложения.
Определим для каждого разряда:
**Преимущество:** Все G и P вычисляются параллельно за 1 такт. Переносы - за 2 такта. Итого O(1) вместо O(n). Именно так работает ALU внутри Apple M4 и Intel Core Ultra.
| Сумматор | Задержка (64 бита) | Транзисторов |
|---|---|---|
| Ripple Carry | 64 * t | ~2000 |
| Carry-Lookahead | ~4 * t | ~8000 |
| Carry-Select | ~16 * t | ~5000 |
**Trade-off:** Быстрее = больше транзисторов. Современные CPU используют гибриды: CLA для нижних бит, Carry-Select для верхних.
В чём главное преимущество Carry-Lookahead Adder?
Флаги состояния
АЛУ не только вычисляет результат - оно устанавливает **флаги** о результате. Без флагов не было бы if, цикла, сравнения. Весь поток управления программы строится на них.
| Флаг | Название | Условие |
|---|---|---|
| Z (Zero) | Ноль | Результат = 0 |
| N (Negative) | Отрицательный | Старший бит результата = 1 |
| C (Carry) | Перенос | Был перенос из старшего бита |
| V (Overflow) | Переполнение | Знаковое переполнение |
**Применение флагов:**
**Отличие C и V:** Carry - для беззнаковых. Overflow - для знаковых. Один результат, два флага! Integer overflow в C++ - это V=1 без C=1.
Когда устанавливается флаг Z (Zero)?
Логические операции в АЛУ
АЛУ выполняет не только арифметику - и **побитовые логические операции**. Именно они используются в хэш-функциях, шифровании, сжатии данных.
**Реализация:** Простой мультиплексор выбирает выход нужной операции. Все операции вычисляются параллельно - MUX просто выбирает результат.
Маскирование с AND
Извлечение младших 8 бит из 32-битного числа
value = 0x12345678 mask = 0x000000FF value AND mask = 0x00000078 Только младший байт остался!
Как АЛУ выбирает между ADD и AND?
Сдвиговые операции
**Barrel Shifter** сдвигает биты влево или вправо за один такт. Это быстрое умножение и деление на степень 2 - без вызова медленного умножителя.
| Операция | Описание | Пример (8 бит) |
|---|---|---|
| SHL / LSL | Сдвиг влево логический | 0011 << 2 = 1100 |
| SHR / LSR | Сдвиг вправо логический | 1100 >> 2 = 0011 |
| SAR / ASR | Сдвиг вправо арифметический | 1100 >> 2 = 1111 |
| ROL | Циклический сдвиг влево | 1100 rol 2 = 0011 |
| ROR | Циклический сдвиг вправо | 1100 ror 2 = 0011 |
**Важно:** Арифметический сдвиг вправо (ASR) сохраняет знак - заполняет знаковым битом. Логический (LSR) - нулями.
АЛУ - это просто калькулятор для арифметики
АЛУ выполняет и арифметику, и логику, и сдвиги, и устанавливает флаги для условных переходов.
Даже простой if (a < b) использует АЛУ: CMP вычисляет a - b и устанавливает флаги, по которым CPU принимает решение о переходе.
x << 4 эквивалентно:
Ключевые идеи
- АЛУ - комбинационная схема для арифметики и логики
- Ripple Carry - простой, но O(n) по задержке
- Carry-Lookahead - O(1), но больше транзисторов
- Вычитание = сложение с NOT B + 1
- Флаги Z/N/C/V - результат для условных переходов
- Сдвиг влево = умножение на 2^n
Связанные темы
АЛУ - ядро вычислительной части CPU.
- Структура CPU — АЛУ - один из блоков
- Конвейеризация — АЛУ как ступень конвейера
- Суперскалярность — Несколько АЛУ параллельно
Вопросы для размышления
- В 2004 году AMD выпустила 64-битный Athlon 64, но многие говорили что 32 бит хватает всем. Представь что ты инженер тех лет: тебе нужно убедить менеджера расширить АЛУ с 32 до 64 бит. Какие технические аргументы ты приведёшь - и какие скрытые издержки (площадь кристалла, энергопотребление, задержка флагов) придётся признать честно?
Связанные уроки
- arch-02-logic-gates — Логические вентили - строительные блоки АЛУ
- arch-01-binary — Двоичная арифметика - язык, на котором говорит АЛУ
- arch-04-cpu — АЛУ - один из ключевых блоков CPU
- arch-06-pipelining — АЛУ как ступень конвейера CPU
- arch-07-superscalar — Суперскалярность - несколько АЛУ параллельно
- arch-15-gpu-architecture — GPU - тысячи простых АЛУ для массивного параллелизма
- arch-09-cache — Latency памяти определяет реальную скорость АЛУ
- os-01-intro