Skip to content

Регистры процессора

Материал проходит ревью.

НовичокФундамент ~20 мин

Границы темы

Разбираем: зачем внутри CPU нужны маленькие именованные хранилища и как через них проходит простое вычисление.

Пока не разбираем: все имена регистров конкретных процессоров, правила передачи параметров между функциями и сложные внутренние оптимизации CPU.

Перед статьёй полезно прочитать «CPU».

Результаты обучения

После статьи читатель сможет:

  1. объяснить роль регистра;
  2. показать путь память → регистр → вычисление → регистр;
  3. назвать несколько специальных регистров;
  4. вручную обновить состояние регистров после команды;
  5. не приравнивать переменную исходного кода к физическому регистру.

Основная модель

Регистр — это очень маленькое хранилище внутри ядра 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

Состояние меняется по шагам:

После командыABC
До начала
LOAD A, 2020
LOAD B, 222022
ADD C, A, B202242
MUL C, C, 2202284

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?
  1. При необходимости сохранить результат в память
  2. Загрузить числа в регистры
  3. Выполнить сложение
  4. Получить результат в регистре
Проверено: 0 из 4

Самопроверка

  1. Зачем нужны регистры, если есть RAM?
  2. Что может хранить регистр общего назначения?
  3. Какую роль выполняет счётчик команд?
  4. Почему нельзя приравнять переменную JavaScript к регистру?
Ответы и критерии
  1. Машинные команды получают ближайшие операнды из маленьких хранилищ внутри ядра.
  2. Число, адрес или промежуточный результат подходящего размера.
  3. Он помогает выбрать следующую машинную инструкцию.
  4. Реальное размещение выбирают runtime и компилятор; оно может меняться или быть удалено оптимизацией.

Краткое резюме

  • Регистры находятся внутри ядра и держат ближайшее состояние вычисления.
  • Команды загружают данные, работают с регистрами и сохраняют результат.
  • Есть регистры общего назначения и специальные регистры.
  • Набор регистров зависит от архитектуры CPU.
  • Переменная языка программирования не обязана соответствовать одному регистру.

Следующие шаги

Следующая статья — «Кеш процессора». Она объясняет, где CPU ищет данные, которые не помещаются в регистрах.

Источники

  • Arm: Registers in AArch64 — официальное описание регистров общего назначения, разных размеров и специальных регистров AArch64.
  • RISC-V Unprivileged ISA Specification — открытая спецификация регистров, арифметических команд, загрузок и сохранений.
  • Intel 64 and IA-32 Software Developer Manuals — первичная документация по регистрам и машинным инструкциям Intel 64.