awesome-everything EN
↑ Обратно к восхождению

Базовый CS с нуля

Выборка–Декодирование–Исполнение

Суть CPU выполняет один цикл бесконечно: выбрать следующую инструкцию из памяти, декодировать её смысл, исполнить, затем сдвинуть счётчик команд и повторить. Каждая программа, когда-либо запущенная на любом CPU, — это этот цикл.
◷ 20 min

CPU включается. Программа загружена в память. Что дальше?

CPU не «думает». Он не «решает» что-либо запустить. Он просто начинает цикл и никогда не останавливается. Цикл состоит из трёх шагов, повторяемых миллиарды раз в секунду:

  1. Выбрать (fetch) следующую инструкцию из памяти.
  2. Декодировать (decode), что она означает.
  3. Исполнить (execute) её.

Затем вернуться к шагу 1. Вот весь механизм, с помощью которого выполнялась каждая программа в истории — от первых пакетных задач 1950-х годов до модели ИИ, запущенной на сегодняшнем железе. CPU — это машина, выполняющая этот цикл.

Цель

После этого урока ты сможешь пошагово описать цикл выборки–декодирования–исполнения, объяснить, что такое счётчик команд и как он продвигается, и объяснить, почему цикл действительно является бесконечным, пока CPU под напряжением.

1

Счётчик команд: отслеживание позиции. Прежде чем цикл сможет начаться, CPU должен знать, где в памяти находится первая инструкция. Он отслеживает это с помощью специального регистра, называемого счётчиком команд (часто сокращённо СК, по- английски PC от program counter; на x86-64 CPU его ещё называют указателем инструкций — instruction pointer).

Регистр — это крошечный, сверхбыстрый слот хранения, физически находящийся внутри CPU; подробно о регистрах ты узнаешь в следующем уроке. Пока достаточно знать: счётчик команд — это регистр, хранящий одно значение — адрес памяти следующей инструкции, которую нужно исполнить.

При включении питания счётчик команд устанавливается на фиксированный начальный адрес (определяемый чипом и операционной системой). С этого момента счётчик команд обновляется CPU автоматически после каждой инструкции, продвигая цикл вперёд.

2

Шаг 1 — Выборка (Fetch). CPU читает инструкцию, хранящуюся по адресу памяти, который содержится в счётчике команд.

Конкретно:

  • CPU помещает значение счётчика команд на шину адресов (провода, соединяющие CPU с памятью).
  • Память возвращает байты, хранящиеся по этому адресу.
  • Эти байты загружаются в специальный внутренний регистр, называемый регистром инструкций (РИ, по-английски IR — Instruction Register), где CPU удерживает текущую инструкцию, пока работает с ней.

Инструкция теперь внутри CPU. Память больше не участвует до следующей выборки (или пока инструкция LOAD/STORE явно не обратится к памяти).

3

Шаг 2 — Декодирование (Decode). CPU анализирует байты, только что выбранные из памяти. Первая часть байтов — это опкод (код операции), идентифицирующий, какая это инструкция (ADD, LOAD, JUMP и т. д.). Оставшиеся байты — операнды.

Декодирование выполняется специальной схемой внутри CPU, называемой устройством управления (по-английски control unit). Устройство управления считывает опкод и вырабатывает набор управляющих сигналов, сообщающих остальным частям CPU, что делать: какой функциональный блок активировать, куда направить операнды, куда поместить результат.

С точки зрения программиста декодирование невидимо. Но именно этот шаг превращает «сырой» битовый паттерн в конкретное действие.

4

Шаг 3 — Исполнение (Execute). CPU выполняет действие, указанное декодированной инструкцией. Что именно означает «исполнить», зависит от типа инструкции:

  • Для арифметической инструкции (например, ADD): устройство управления направляет операнды в Арифметико-логическое устройство (АЛУ), АЛУ вычисляет результат, и результат записывается в регистр-назначение.
  • Для инструкции LOAD: CPU отправляет адрес памяти на шину адресов, ждёт, пока память вернёт значение, и сохраняет его в регистр-назначение.
  • Для инструкции STORE: CPU отправляет в память и адрес, и значение; память его сохраняет.
  • Для инструкции JUMP: CPU записывает адрес перехода в счётчик команд, что изменит место следующей выборки.
5

Продвижение счётчика команд. После исполнения счётчик команд должен быть обновлён, чтобы следующая выборка получила следующую инструкцию.

Для большинства инструкций (всех, кроме JUMP) CPU автоматически прибавляет размер текущей инструкции к счётчику команд. На многих архитектурах инструкции имеют фиксированный размер (например, по 4 байта на ARM). На других — переменный (инструкции x86-64 занимают от 1 до 15 байтов). В любом случае после не-JUMP инструкции счётчик команд указывает на следующую инструкцию в памяти.

Для инструкции JUMP счётчик команд устанавливается на адрес перехода во время шага исполнения. Следующая выборка придёт из этого адреса — который может быть далеко от текущего. Именно так на аппаратном уровне работают операторы if и циклы.

Почему это работает

Почему это цикл, а не дерево или граф? У CPU нет встроенного понятия «вызов подпрограммы» или «возврат из функции» на уровне цикла. Это высокоуровневые паттерны, построенные поверх тех же инструкций JUMP. Каждый вызов функции реализован переходом к первой инструкции функции с некоторой бухгалтерией, чтобы запомнить, куда вернуться. Каждый оператор if — условный JUMP. Каждый цикл while — условный JUMP назад к началу. Цикл — единственный примитив; всё остальное — паттерн поверх него.

Выборка
Декодирование
Исполнение
Цикл выборка–декодирование–исполнение: три стадии, повторяемые бесконечно. Стрелка возврата замыкает цикл.
Разбор примера

Разбор одного полного цикла.

Предположим, память содержит три инструкции по адресам 100, 104 и 108 (каждая инструкция занимает 4 байта):

  • Адрес 100: LOAD R0, 200 (прочитать значение по адресу памяти 200 в регистр R0)
  • Адрес 104: LOAD R1, 201 (прочитать значение по адресу памяти 201 в регистр R1)
  • Адрес 108: ADD R2, R0, R1 (сложить R0 и R1, результат в R2)

Счётчик команд начинает с 100.

Цикл 1:

  • Выборка: читаем байты по адресу 100. Регистр инструкций получает LOAD R0, 200.
  • Декодирование: устройство управления распознаёт опкод LOAD, определяет назначение R0, определяет адрес-источник 200.
  • Исполнение: CPU читает адрес памяти 200, получает некоторое значение (допустим, 7). CPU сохраняет 7 в R0.
  • Продвижение СК: СК = 100 + 4 = 104.

Цикл 2:

  • Выборка: читаем байты по адресу 104. РИ получает LOAD R1, 201.
  • Декодирование: опкод LOAD, назначение R1, адрес-источник 201.
  • Исполнение: CPU читает адрес памяти 201, получает значение (допустим, 3). CPU сохраняет 3 в R1.
  • Продвижение СК: СК = 104 + 4 = 108.

Цикл 3:

  • Выборка: читаем байты по адресу 108. РИ получает ADD R2, R0, R1.
  • Декодирование: опкод ADD, назначение R2, источники R0 и R1.
  • Исполнение: АЛУ вычисляет R0 + R1 = 7 + 3 = 10. Результат сохраняется в R2.
  • Продвижение СК: СК = 108 + 4 = 112.

CPU теперь выберет инструкцию по адресу 112, и цикл продолжится. R0 = 7, R1 = 3, R2 = 10 — сложение завершено.

Частая ошибка

Распространённая ошибка — думать, что CPU «знает», какую программу выполняет, или «понимает» общую цель. Это не так. CPU исполняет текущую инструкцию, продвигает счётчик команд и исполняет следующую. Он не видит дальше текущего цикла. Кажущийся интеллект работающей программы целиком определяется расположением инструкций в памяти — сам CPU просто выполняет цикл.

Практика 0 / 5

Счётчик команд хранит адрес памяти следующей инструкции. До выполнения любой инструкции что хранит счётчик команд? Введи 1 (начальный адрес первой инструкции) или 2 (случайный адрес).

На каком шаге CPU читает инструкцию из памяти? Введи 1 (выборка), 2 (декодирование) или 3 (исполнение).

На каком шаге устройство управления определяет опкод? Введи 1 (выборка), 2 (декодирование) или 3 (исполнение).

Инструкции по адресу 200 занимают по 4 байта. После исполнения инструкции по адресу 200 счётчик команд становится равным чему?

Инструкция JUMP нацелена на адрес 500. После её исполнения счётчик команд содержит какое значение?

Проверь себя
Викторина

Какова роль счётчика команд в цикле выборки–декодирования–исполнения?

Итог

CPU выполняет цикл выборки–декодирования–исполнения бесконечно. На шаге выборки он читает инструкцию по адресу, хранящемуся в счётчике команд (СК). На шаге декодирования устройство управления определяет опкод и операнды. На шаге исполнения соответствующий аппаратный блок выполняет действие — АЛУ для арифметики, шина памяти для LOAD/STORE, обновление СК для JUMP. После не-JUMP инструкции СК продвигается на размер инструкции в байтах. После JUMP СК устанавливается на адрес перехода. Затем цикл начинается заново. Каждая программа, когда-либо запущенная, — каждая функция, каждый цикл, каждый оператор if — реализована как последовательность инструкций, управляемых этим же циклом.

Продолжить восхождение ↑Регистры
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.