Ветвления и циклы (JZ, JN, JMP)
Код всегда выполняется строго сверху вниз. Но любая игра состоит из циклов и условий. Если змейка съела яблоко — растим хвост, иначе — просто ползём дальше. Как сломать этот прямой путь?
Для этого существуют инструкции переходов (Jumps) — своеобразные телепорты для Счётчика команд (Program Counter). Счётчик команд мы собирали в отдельной статье — теперь посмотрим, как управлять им из программы.
В компьютере Ершова три команды перехода: JMP, JZ и JN. Именно они превращают линейный код в игру.
Безусловный переход JMP
Когда процессор натыкается на JMP, он просто забывает, где был, и перепрыгивает на ту строчку кода, которую ему указали. Именно так создаётся бесконечный игровой цикл (game loop), который заставляет игру работать кадр за кадром, возвращаясь в начало.
JMP не проверяет никаких условий — это чистый телепорт. Условия оставим его братьям.
Условные переходы JZ и JN
Куда интереснее условные переходы: JZ (прыгни, если Нуль) и JN (прыгни, если Отрицательно). Они работают в паре с флагами АЛУ: процессор смотрит на флаг — если условие выполнено, телепорт срабатывает и программа идёт по одной ветке; если нет — телепорт игнорируется, и программа спокойно идёт дальше.
| Команда | Opcode | Условие | Пример из игры |
|---|---|---|---|
| JMP | 7 | Всегда | бесконечный игровой цикл |
| JZ | 8 | Флаг Zero = 1 | жизни кончились → Game Over |
| JN | 12 | Флаг 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 — полноценную игру «Змейка».