Я решил улучшить свои навыки сборки Z80, написав игру полностью с нуля. Он основан на BASIC-игре, которую я нашел в старой книге.

Смотреть видео!

Возьмите код!



Исходный код и скомпилированный двоичный файл можно получить из моего Github Repo здесь. Не стесняйтесь копировать его и вносить изменения. Если вы исправите или улучшите его, дайте мне знать!

Откуда это взялось

Мне нравится собирать старые книги по программированию для давно умерших компьютерных систем. У меня их полна полка для Спектрума, С64 и других машин. Существует также небольшая коллекция универсальных книг, в которых представлены списки BASIC, которые работают с большинством домашних микроконтроллеров 80-х годов. Просматривая Радужную книгу программ BASIC, я наткнулся на игру, которая привлекла мое внимание.

Когда-то все книги по программированию были такими…

Зомби!

С этими старыми книгами дело в том, что компьютеры в то время были не очень способными, и многие игры были несколько неинтерактивными. Игры обычно полагались на текст для графики, и не было полноэкранного движения или персонажей, которые перемещались по экрану.

Игра Zombies, которую я нашел, немного сложнее. Сначала я ввел его в свой BBC Micro, чтобы понять, что происходит — это не помогло, так как в игру почти невозможно играть, и в ней довольно сложно разобраться.

Это выглядело как хороший кандидат для более сложного проекта программирования Z80. Сначала мне пришлось реконструировать код BASIC, что было полным беспорядком. BASIC имеет репутацию неорганизованного спагетти, но только когда вы садитесь и пытаетесь понять алгоритмы, вы понимаете, насколько он неструктурирован.

К счастью, код в этой книге снабжен объяснениями того, что делает каждая группа строк, и это сделало задачу более управляемой.

Однако, вероятно, чтобы соответствовать требованиям печати книги, код очень компактен. Нет переменных с именами длиннее одной буквы, ноль комментариев и много строк с несколькими инструкциями. Мне пришлось копировать и переписывать весь код, чтобы понять это.

Сборка Z80

К счастью, я не пытался сделать это самостоятельно. Как только я разобрался с общим алгоритмом игры, у меня появилось достаточно ресурсов для написания ассемблерного кода Z80.

Я использовал следующие книги, они, кажется, являются стандартными справочниками, которыми люди пользовались еще в 80-х годах, и как только вы разберетесь с терминологией, книги будут довольно полезными.

Подпрограммы языка ассемблера Z80

Программирование Z80

Регистрация

Написание кода на ассемблере требует определенной степени безделья. ЦП может работать только с числами, хранящимися в его регистрах, и, в частности, он может выполнять арифметические действия только с числами, хранящимися в его накопителе или регистре «А». Это приводит к большому количеству перетасовки данных вокруг ЦП.

Вот алгоритм преобразования целого числа в его эквивалент ASCII. Все, что он делает, это делит число на 10, а затем добавляет к результату шестнадцатеричное число 30. Однако для этого мне нужно перетасовать регистры в стек, чтобы сохранить их, перетасовать один регистр в другой, а затем отменить все это в конце.

Условия и флаги ЦП

Еще одна вещь, которую следует учитывать при написании ассемблера Z80, — это состояние ЦП, которое хранится в его регистре флагов. В книгах об этом постоянно упоминалось, но я не совсем понимал почему, пока не попытался выполнить довольно простую процедуру типа if - then - else.

В сборке такого нет. Все, что вы можете сделать, это сравнить одно число с другим. И на самом деле сравнение — это просто результат вычитания двух чисел без фактического вычитания. В конце ЦП остается в определенном состоянии, и, проверив его флаги, вы можете понять, что произошло.

Если установлен нулевой флаг, оба числа совпадают. Если нулевой флаг не установлен, они разные. Если флаг переноса установлен, первое число было меньше. Если перенос не был установлен, первое число было больше.

Если вы думаете об этом, это имеет смысл. Вычитание числа из самого себя приводит к нулю в качестве ответа, устанавливая нулевой флаг. Вычитание большого числа из маленького приводит к переполнению — вам нужно внести 1, чтобы сбалансировать математику.

Вот некоторый код, который определяет, в какую сторону двигать зомби по направлению к игроку. Полно такой логики.

Изучайте Ассамблею!

Я настоятельно рекомендую вам изучить программирование на ассемблере, если вы программист. Неважно, какой ЦП вы пытаетесь изучить (выбор 8-битного облегчает задачу), процесс его изучения многому вас научит. Когда вы вручную инструктируете ЦП, у вас возникает определенное мышление; если вы можете удалить одну инструкцию, код работает быстрее. Иногда вы можете реорганизовать код, чтобы использовать меньше регистров.

Это также очень помогает с вашими навыками решения проблем. Было несколько моментов, когда у меня были баги, и я не мог в них разобраться. Мой код выглядел так, как будто он должен был работать, но не работал. Каждый раз, когда я исправлял эти ошибки, я узнавал что-то новое.

Однако, если вы собираетесь изучать ассемблер, сделайте то, что сделал я, и попробуйте написать на нем программу приличного размера. Забудьте о программах типа «сложите два числа и напечатайте ответ» или сухих программах типа «напишите программу для вычисления площади круга». Найдите простую игру или что-то в этом роде и попробуйте написать ее.

Вам даже не нужен компьютер для запуска вашего кода. Запустите эмулятор вашей любимой 8-битной машины и используйте его. Я использую кросс-компилятор SJAsmPlus Z80, поэтому я мог разрабатывать на современной машине, а затем запускать код на реальном оборудовании. Я мог бы легко запустить его и на эмуляторе Z80.

Первоначально опубликовано на https://ncot.uk.