Ветвления и циклы (JZ, JN, JMP)

Код всегда выполняется строго сверху вниз. Но любая игра состоит из циклов и условий. Если змейка съела яблоко — растим хвост, иначе — просто ползём дальше. Как сломать этот прямой путь?

Для этого существуют инструкции переходов (Jumps) — своеобразные телепорты для Счётчика команд (Program Counter). Счётчик команд мы собирали в отдельной статье — теперь посмотрим, как управлять им из программы.

В компьютере Ершова три команды перехода: JMP, JZ и JN. Именно они превращают линейный код в игру.

Безусловный переход JMP

Когда процессор натыкается на JMP, он просто забывает, где был, и перепрыгивает на ту строчку кода, которую ему указали. Именно так создаётся бесконечный игровой цикл (game loop), который заставляет игру работать кадр за кадром, возвращаясь в начало.

JMP не проверяет никаких условий — это чистый телепорт. Условия оставим его братьям.

Условные переходы JZ и JN

Куда интереснее условные переходы: JZ (прыгни, если Нуль) и JN (прыгни, если Отрицательно). Они работают в паре с флагами АЛУ: процессор смотрит на флаг — если условие выполнено, телепорт срабатывает и программа идёт по одной ветке; если нет — телепорт игнорируется, и программа спокойно идёт дальше.

КомандаOpcodeУсловиеПример из игры
JMP7Всегдабесконечный игровой цикл
JZ8Флаг Zero = 1жизни кончились → Game Over
JN12Флаг Negative = 1координата отрицательная → выход за границу

Это и есть аппаратный фундамент операторов if / else, без которых не обходится ни одна программа.

Как переход устроен на железе

Формула простая: PC.Load = JumpUncond OR (JumpCond AND флаг). Безусловный переход (JumpUncond) загружает адрес всегда. Условный — только когда сигнал дешифратора JumpCond совпал с флагом АЛУ (Zero или Negative).

Если PC.Load = 1, счётчик команд загружает адрес перехода из операнда вместо прибавления шага (PC + step). Если PC.Load = 0 — исполнение идёт по порядку. Один сигнал, одна формула, два источника решений.

Откуда берётся адрес перехода? Из второго байта инструкции — её операнда. В word-формате JMP занимает два байта: код команды и адрес, куда нужно перепрыгнуть. Пока PC шагает на +2 по программе, сигнал PC.Load подменяет следующий адрес значением из операнда — и поток исполнения сворачивает с прямой дорожки.

Игровой цикл Змейки

Сердце любой игры — главный цикл. Упрощённый скелет выглядит так:

loop:
LDA 0        ; Acc = 0
ADD 254      ; читаем геймпад (порт 254)
; ... обновляем позицию, проверяем столкновение
JZ game_over ; столкновение? тогда конец игры
STA 255      ; рисуем пиксель (порт 255)
JMP loop     ; и снова — следующий кадр
game_over:
HLT          ; стоп

Эти несколько команд выполняются десятки раз в секунду, создавая иллюзию движения: каждый кадр — один полный проход счётчика команд по коду цикла. JMP замыкает итерации, а условные переходы ловят особые случаи. Для хвоста змейки и работы с массивами пригодится индексный регистр — см. статью про указатели.

Счётчик жизней на числах

Условие «игра окончена» проверяется так. В памяти лежит счётчик жизней: 3. Каждая смерть вычитает 1: 3 → 2 → 1 → 0. Когда результат стал нулём, флаг Zero = 1, и команда JZ уводит программу на метку game_over. Пока счётчик больше нуля, JZ молчит, и цикл продолжается.

По шагам: 1) программа читает счётчик из памяти: LDA 0 обнуляет аккумулятор, затем ADD N прибавляет значение ячейки N (LDA умеет загружать только числа); 2) SUB M вычитает единицу, заранее сохранённую в ячейке M (в этом компьютере SUB вычитает содержимое ячейки); 3) АЛУ обновляет флаги; 4) JZ проверяет флаг Zero; 5) Zero = 1 — прыжок на game_over, Zero = 0 — возврат в цикл.

Частые ошибки

1. Забыть JMP в конце цикла: цикл выполнится один раз, и программа уйдёт читать мусор из ROM.

2. Ставить вычисление условия после JZ: переход смотрит на последний результат АЛУ.

3. Путать JMP и JZ: безусловный переход не читает флаги вообще.

Резюме

1. JMP — безусловный телепорт счётчика команд (opcode 7).

2. JZ прыгает, если флаг Zero = 1; JN — если флаг Negative = 1.

3. Железо: PC.Load = JumpUncond OR (JumpCond AND флаг).

4. При PC.Load = 1 счётчик команд грузит адрес из операнда вместо PC + step.

5. Игровой цикл: читать геймпад → обновить состояние → нарисовать кадр → JMP в начало.

На уровне 2.28 тебе предстоит написать программу с циклом для движущейся точки, а на уровне 2.29 — полноценную игру «Змейка».

Попробовать в симуляторе →