Тема
Регистры процессора
Материал проходит ревью.
Границы темы
Разбираем: зачем внутри CPU нужны маленькие именованные хранилища и как через них проходит простое вычисление.
Пока не разбираем: все имена регистров конкретных процессоров, правила передачи параметров между функциями и сложные внутренние оптимизации CPU.
Перед статьёй полезно прочитать «CPU».
Результаты обучения
После статьи читатель сможет:
- объяснить роль регистра;
- показать путь
память → регистр → вычисление → регистр; - назвать несколько специальных регистров;
- вручную обновить состояние регистров после команды;
- не приравнивать переменную исходного кода к физическому регистру.
Основная модель
Регистр — это очень маленькое хранилище внутри ядра CPU. Машинные команды используют регистры для значений, нужных прямо сейчас.
Диаграмма
Основные термины
| Термин | Простое определение |
|---|---|
| Регистр | Маленькое именованное хранилище внутри ядра |
| Операнд | Значение, над которым работает команда |
| Регистр общего назначения | Используется для чисел, адресов и промежуточных результатов |
| Счётчик команд | Указывает, какую команду выполнять следующей |
| Указатель стека | Указывает на текущую область стека |
| Флаги состояния | Хранят признаки результата, например «получился ноль» |
Имена и количество регистров зависят от архитектуры процессора. Например, AArch64 предоставляет программе 31 регистр общего назначения. Запоминать их сейчас не нужно.
End-to-end сценарий
Рассмотрим выражение:
text
(20 + 22) × 2Условные команды:
text
LOAD A, 20
LOAD B, 22
ADD C, A, B
MUL C, C, 2Состояние меняется по шагам:
| После команды | A | B | C |
|---|---|---|---|
| До начала | — | — | — |
LOAD A, 20 | 20 | — | — |
LOAD B, 22 | 20 | 22 | — |
ADD C, A, B | 20 | 22 | 42 |
MUL C, C, 2 | 20 | 22 | 84 |
A, B и C здесь учебные имена. Реальный синтаксис зависит от набора машинных команд.
Что происходит под капотом
Загрузка и сохранение
В архитектурах типа AArch64 и RISC-V арифметические команды обычно работают с регистрами. Отдельные команды загружают данные из памяти и сохраняют их обратно.
Диаграмма
Такое разделение помогает увидеть цену движения данных: вычислительная команда не заменяет чтение памяти.
Регистры общего назначения
Они могут хранить:
- целые числа;
- адреса данных;
- части большого вычисления;
- параметры и результат функции.
«Общего назначения» не означает «без ограничений». Размер регистра фиксирован архитектурой, а отдельные команды могут требовать конкретный тип регистра.
Специальные регистры
Некоторые регистры имеют выделенную роль:
- счётчик команд помогает выбрать следующую инструкцию;
- указатель стека помогает находить текущую область вызовов функций;
- флаги сохраняют свойства результата сравнения или арифметики.
Точный набор различается. Например, в AArch64 счётчик команд не является обычным регистром общего назначения.
Что происходит при вызове функции
Программа должна договориться, где функция получит параметры и оставит результат. Обычно часть значений передаётся через определённые регистры, а лишние значения и временные данные могут размещаться в стеке.
Это соглашение называется правилами вызова функций. Компилятор следует ему автоматически; начинающему разработчику не нужно вручную выбирать регистры.
Переменная не равна регистру
В коде можно написать:
js
const total = price * count;Но нельзя заранее утверждать, что price, count и total займут по регистру. Компилятор или runtime может:
- держать значение в регистре;
- временно сохранить его в памяти;
- вычислить выражение заранее;
- удалить вычисление, если результат не используется.
Минимальный воспроизводимый пример
Симулятор показывает изменение трёх учебных регистров:
js
const registers = { A: 0, B: 0, C: 0 };
registers.A = 20;
console.log("LOAD A", registers);
registers.B = 22;
console.log("LOAD B", registers);
registers.C = registers.A + registers.B;
console.log("ADD C, A, B", registers);
registers.C = registers.C * 2;
console.log("MUL C, C, 2", registers);Сохраните код в registers.mjs и запустите:
bash
node registers.mjsОжидаемый результат
text
LOAD A { A: 20, B: 0, C: 0 }
LOAD B { A: 20, B: 22, C: 0 }
ADD C, A, B { A: 20, B: 22, C: 42 }
MUL C, C, 2 { A: 20, B: 22, C: 84 }Это модель регистров, а не эмулятор настоящего CPU. Она нужна, чтобы научиться прослеживать состояние после каждой команды.
Как диагностировать ошибку
- результат не
84— найдите первый шаг, на котором состояние отличается; - вывод не меняется — проверьте присваивания
registers.A,.Bи.C; nodeне найден — установите Node.js или проверьтеPATH;- команда выполнена не с тем значением — проверьте, какие регистры указаны как операнды.
Ограничения и trade-offs
| Хранилище | Размер | Близость к ядру | Основная роль |
|---|---|---|---|
| Регистры | Очень маленький | Внутри ядра | Ближайшие операнды |
| Кеш | Небольшой | Рядом с ядром | Копии часто нужных данных |
| RAM | Большой | Дальше | Рабочие данные программ |
| Накопитель | Очень большой | Через ввод-вывод | Долговременные файлы |
Регистры быстры именно потому, что их мало и они тесно связаны с выполнением команд. Увеличить их до размера RAM без изменения цены и сложности невозможно.
Failure modes и типичные ошибки
- Регистр — это переменная. Переменная относится к языку, регистр — к CPU.
- Все CPU имеют одинаковые регистры. Их набор задаёт архитектура.
- В регистрах хранится вся программа. Там находится только небольшое текущее состояние.
- Регистр сохраняет значение после завершения процесса. Регистры постоянно переиспользуются и не являются долговременным хранилищем.
- Больше регистров автоматически ускоряет любой код. Результат зависит от команд, компилятора, данных и всей системы.
Практическое задание
Задача: расширьте симулятор командой вычитания и вычислите (50 - 8) × 2.
Критерии готовности:
- после каждого шага выводится состояние;
- итоговый результат равен
84; - для исходных чисел и результата выбраны отдельные регистры;
- вы можете объяснить каждый
LOAD, вычисление и запись.
Подсказка
Сначала загрузите 50 и 8, затем запишите разность в C и умножьте текущее значение C на 2.
Проверка знаний
ИНТЕРАКТИВНАЯ ПРОВЕРКА
Регистры CPU
0 / 4
01Зачем CPU нужны регистры?
02Что может храниться в регистрах?
03Каждая переменная JavaScript всегда занимает ровно один регистр CPU.
04Как получить сумму двух чисел, лежащих в RAM?
- При необходимости сохранить результат в память
- Загрузить числа в регистры
- Выполнить сложение
- Получить результат в регистре
Самопроверка
- Зачем нужны регистры, если есть RAM?
- Что может хранить регистр общего назначения?
- Какую роль выполняет счётчик команд?
- Почему нельзя приравнять переменную JavaScript к регистру?
Ответы и критерии
- Машинные команды получают ближайшие операнды из маленьких хранилищ внутри ядра.
- Число, адрес или промежуточный результат подходящего размера.
- Он помогает выбрать следующую машинную инструкцию.
- Реальное размещение выбирают runtime и компилятор; оно может меняться или быть удалено оптимизацией.
Краткое резюме
- Регистры находятся внутри ядра и держат ближайшее состояние вычисления.
- Команды загружают данные, работают с регистрами и сохраняют результат.
- Есть регистры общего назначения и специальные регистры.
- Набор регистров зависит от архитектуры CPU.
- Переменная языка программирования не обязана соответствовать одному регистру.
Следующие шаги
Следующая статья — «Кеш процессора». Она объясняет, где CPU ищет данные, которые не помещаются в регистрах.
Источники
- Arm: Registers in AArch64 — официальное описание регистров общего назначения, разных размеров и специальных регистров AArch64.
- RISC-V Unprivileged ISA Specification — открытая спецификация регистров, арифметических команд, загрузок и сохранений.
- Intel 64 and IA-32 Software Developer Manuals — первичная документация по регистрам и машинным инструкциям Intel 64.