Главная » Правописание слов » Как написать игру на ассемблере для zx spectrum

Слово Как написать игру на ассемблере для zx spectrum - однокоренные слова и морфемный разбор слова (приставка, корень, суффикс, окончание):


Морфемный разбор слова:

Однокоренные слова к слову:

Как написать игру на ассемблере для zx spectrum

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

Рис. 1.1. Загрузочная картинка к игре JUGGERNAUT

Рис. 1.2. Меню программы EAGLES NEST

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

Рис. 1.3. Игровое пространство программы DIZZY4

Вторую часть составляют подвижные объекты, которые перемещаются сами по себе и на которые вы не можете оказывать непосредственного воздействия. Как правило, к этой группе относятся изображения ваших противников, например, силуэты вертолетов, кораблей и самолетов в игре RIVER RAID или проносящиеся мимо вас мотоциклы в SPEED KING2.

О том, как делать маленькие и большие спрайты, а также сложные пейзажи, мы расскажем дальше, а здесь только перечислим способы их изготовления. Небольшие спрайты вполне могут быть изготовлены вручную. Для этого спрайт рисуется на клетчатой бумаге (каждая клетка соответствует одной точке на экране), а затем изображение переводится в последовательность чисел. Значительно интереснее, а главное, эффективнее, создать рисунок будущего объекта в каком-либо графическом редакторе (например, в Art Studio или The Artist II), после чего автоматически закодировать его с помощью специальной программы, называемой генератором спрайтов, и записать на ленту или диск в виде готового к использованию спрайт-файла.

Все эти способы были подробно расписаны в [1], поэтому в настоящей книге мы не станем подолгу останавливаться на них и рассмотрим лишь некоторые особенности, имеющие непосредственное отношение к языку ассемблера.

Приведем несколько примеров. В игре RIVER RAID можно ускорять или замедлять полет вашего самолетика, поворачивать его вправо или влево. И для этого достаточно лишь наклонить ручку джойстика в нужном направлении, а нажав кнопку «огонь», можно выпустить по объекту противника ракету.

Особенно поражают реальностью происходящего игры, посвященные какому-либо виду спортивной борьбы (FIST, ORIENTAL GAMES и другие). В них с помощью все тех же пяти клавиш или джойстика можно заставить главного персонажа выполнять множество различных приемов, прыжков, ударов и прочих телодвижений.

В более сложных играх, таких как INTO THE EAGLES NEST, VIDEO POOL или OPERATION WOLF количество выводимой информации также становится более значительным. Кроме чисел на экране можно увидеть и тексты, поясняющие результаты ваших действий или предупреждающие о возникшей опасности (например, в SILENT SERVICE). Чаще всего такая информация выводится в виде «бегущей строки» или в специальном окне, предназначенном именно для этих целей (рис. 1.4). А во многих стратегических играх оценочная информация настолько обильна, что в них для вывода различных сообщений отводятся уже целые кадры, занимающие полный экран (скажем, как в играх SIM CITY или DICTATOR).

Рис. 1.4. Оценка игровой ситуации в игре GUN FRIGHT

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

В отличие от других частей игровой программы, выделить какой-то особый музыкальный блок довольно трудно, поскольку разные по сложности и назначению звуки формируются и в заставке, и в блоке взаимодействия с играющим, и даже в блоке оценки игровой ситуации. Тем не менее, все, что связано с музыкальным оформлением игры, можно рассматривать с точки зрения программирования как нечто, напоминающее отдельный блок. Все дело в том, что разные звуки и музыкальные фрагменты формируются одними и теми же подпрограммами и отличие может состоять лишь в размерах блоков данных (в особенности это справедливо для подпрограмм, создающих звуки в компьютере ZX Spectrum 128).

Говоря о звуках в компьютерных играх, никак нельзя пройти мимо возможностей музыкального сопроцессора, с помощью которого можно создавать не просто интересные звуковые эффекты, но и настоящие музыкальные произведения с полноценной оркестровой аранжировкой. На страницах этой книги мы постараемся поделиться своим опытом в данной области, подробно расскажем о программировании звуковых эффектов, сопровождая все это примерами ассемблерных программ с их подробным описанием.

Источник

Как написать игру на ассемблере для ZX Spectrum/Глава 01

Использование материала заявлено как добросовестное, исключительно для образовательных некоммерческих целей.

Автор: А. Евдокимов, А. Капульцевич, И. Капульцевич, ИД «Питер»

Содержание

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

Несмотря на несметное количество существующих компьютерных игр различного уровня сложности и жанра, все же есть в них что-то общее, поддающееся классификации. Если проанализировать любую из них от начала загрузки до появления на экране сообщения GAME OVER (игра окончена), то можно выделить несколько частей, которые, хотя и связаны между собой в единое целое какими-то общими переменными и данными, но тем не менее, выполняют в игре вполне самостоятельные функции. Это позволяет разрабатывать каждую из частей независимо от других (однако, не забывая о связях с остальными частями), что в значительной степени упрощает создание игровой программы в целом. О каких же частях идет речь? Это:

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

ЗАСТАВКА

Вы знаете, что заставкой обычно называют картинку, появляющуюся во время загрузки игровой программы. Такие картинки имеют тот же смысл, что и рекламные щиты у дверей кинотеатров. Значительную площадь, как правило, занимает название игры, а все, что изображено на экране, так или иначе связано с ее сюжетом. Здесь же обычно сообщается о фирме-изготовителе, авторах программы и годе ее создания (рис. 1.1).

Часто только это изображение и называют заставкой, хотя на самом деле это лишь первая ее часть, помогающая игроку морально подготовиться к тяготам предстоящего сражения или лишениям, связанным с поисками сокровищ. Однако в солидных игровых программах заставка чаще всего разбивается на несколько частей, именуемых кадрами. Объясняется это очень просто: перед началом игры на экране должно появиться столь большое количество информации, что «впихнуть» ее в один кадр практически невозможно. Поэтому после окончания загрузки программы на экране появляется основной кадр заставки, называемый меню, в котором дается список действий, необходимых для настройки программы или для получения той или иной информации (рис. 1.2).

ИГРОВОЕ ПРОСТРАНСТВО

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

Вторую часть составляют подвижные объекты, которые перемещаются сами по себе и на которые вы не можете оказывать непосредственного воздействия. Как правило, к этой группе относятся изображения ваших противников, например, силуэты вертолетов, кораблей и самолетов в игре RIVER RAID или проносящиеся мимо вас мотоциклы в SPEED KING2.

О том, как делать маленькие и большие спрайты, а также сложные пейзажи, мы расскажем дальше, а здесь только перечислим способы их изготовления. Небольшие спрайты вполне могут быть изготовлены вручную. Для этого спрайт рисуется на клетчатой бумаге (каждая клетка соответствует одной точке на экране), а затем изображение переводится в последовательность чисел. Значительно интереснее, а главное, эффективнее, создать рисунок будущего объекта в каком-либо графическом редакторе (например, в Art Studio или The Artist II), после чего автоматически закодировать его с помощью специальной программы, называемой генератором спрайтов, и записать на ленту или диск в виде готового к использованию спрайт-файла.

Все эти способы были подробно расписаны в [1], поэтому в настоящей книге мы не станем подолгу останавливаться на них и рассмотрим лишь некоторые особенности, имеющие непосредственное отношение к языку ассемблера.

ВЗАИМОДЕЙСТВИЕ С ИГРАЮЩИМ

Приведем несколько примеров. В игре RIVER RAID можно ускорять или замедлять полет вашего самолетика, поворачивать его вправо или влево. И для этого достаточно лишь наклонить ручку джойстика в нужном направлении, а нажав кнопку «огонь», можно выпустить по объекту противника ракету.

Особенно поражают реальностью происходящего игры, посвященные какому-либо виду спортивной борьбы (FIST, ORIENTAL GAMES и другие). В них с помощью все тех же пяти клавиш или джойстика можно заставить главного персонажа выполнять множество различных приемов, прыжков, ударов и прочих телодвижений.

ОЦЕНКА ИГРОВОЙ СИТУАЦИИ

В более сложных играх, таких как INTO THE EAGLES NEST, VIDEO POOL или OPERATION WOLF количество выводимой информации также становится более значительным. Кроме чисел на экране можно увидеть и тексты, поясняющие результаты ваших действий или предупреждающие о возникшей опасности (например, в SILENT SERVICE). Чаще всего такая информация выводится в виде «бегущей строки» или в специальном окне, предназначенном именно для этих целей (рис. 1.4). А во многих стратегических играх оценочная информация настолько обильна, что в них для вывода различных сообщений отводятся уже целые кадры, занимающие полный экран (скажем, как в играх SIM CITY или DICTATOR).

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

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

ЗВУКОВОЕ СОПРОВОЖДЕНИЕ ИГРЫ

Трудно даже назвать игру, тем более фирменную, где бы совсем не использовались те или иные звуки. Речь может идти лишь о том, что в одних играх музыкального сопровождения меньше, а в других каждое нажатие клавиши приводит ко все новым музыкальным шедеврам. Как образцы блестящего музыкального оформления стоит назвать такие игры как DEFINDER OF THE CROWN, PINK PONG, FLYING SHARK. Мы привели данный список с той мыслью, что, прочитав книгу до конца и накопив некоторый опыт, вам будет вполне по силам дизассемблировать эти игры и найти, а затем использовать лучшие образцы компьютерной музыки в своих программах. Ведь чего греха таить, не все, даже очень хорошие программисты, рождаются с музыкальными способностями.

В отличие от других частей игровой программы, выделить какой-то особый музыкальный блок довольно трудно, поскольку разные по сложности и назначению звуки формируются и в заставке, и в блоке взаимодействия с играющим, и даже в блоке оценки игровой ситуации. Тем не менее, все, что связано с музыкальным оформлением игры, можно рассматривать с точки зрения программирования как нечто, напоминающее отдельный блок. Все дело в том, что разные звуки и музыкальные фрагменты формируются одними и теми же подпрограммами и отличие может состоять лишь в размерах блоков данных (в особенности это справедливо для подпрограмм, создающих звуки в компьютере ZX Spectrum 128).

Говоря о звуках в компьютерных играх, никак нельзя пройти мимо возможностей музыкального сопроцессора, с помощью которого можно создавать не просто интересные звуковые эффекты, но и настоящие музыкальные произведения с полноценной оркестровой аранжировкой. На страницах этой книги мы постараемся поделиться своим опытом в данной области, подробно расскажем о программировании звуковых эффектов, сопровождая все это примерами ассемблерных программ с их подробным описанием.

Источник

Как написать игру на ассемблере для ZX Spectrum/Глава 02

Использование материала заявлено как добросовестное, исключительно для образовательных некоммерческих целей.

Автор: А. Евдокимов, А. Капульцевич, И. Капульцевич, ИД «Питер»

Содержание

ГЛАВА ВТОРАЯ, из которой вы узнаете о том, что же такое ассемблер и чем он отличается от Бейсика и машинных кодов, а также усвоите некоторые основные понятия

Прежде чем приступать к изучению ассемблера, нужно усвоить несколько новых терминов, чтобы понимать, о чем вообще идет речь. Эту главу можно считать введением в совершенно новый для вас язык программирования (если же вы знакомы хотя бы с азами ассемблера, то можете лишь бегло пролистать эту и следующую главы, ибо они предназначены, в первую очередь, для новичков, делающих первые шаги в изучении машинного языка).

МАШИННЫЕ КОДЫ И АССЕМБЛЕР

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

Точно так же можно перевести в десятичное и любое другое число, представленное в двоичном формате. Попутно напомним, что разряды двоичных чисел в информатике принято называть битами, а последовательности из 8 битов составляют байты.

Теперь вы вправе спросить, а что же будет, если микропроцессору дать такую команду? В ответ мы напишем похожую строку на хорошо известном вам Бейсике:

ЧТО МОЖЕТ МИКРОПРОЦЕССОР Z80?

Вот краткий и не совсем полный список операций, доступных микропроцессору:

Вам может показаться странным, что компьютер, располагая столь незначительными средствами, умудряется создавать на экране целые миры, исполнять сложные музыкальные произведения и даже управлять какими-то механизмами вроде принтера. Чтобы прояснить, как это получается, приведем маленький примерчик на Бейсике, построенный по тому же принципу, что и большинство программ в машинных кодах:

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

В переменную ADDR1 помещаем адрес (напоминаем, что адресом называется порядковый номер байта в памяти; в ZX Spectrum адреса имеют номера от 0 до 65535) начала экранной области памяти, а переменная ADDR2 указывает на начало данных, находящихся в ПЗУ и описывающих внешний вид символа A. В данном примере адрес ADDR2 рассчитан заранее, хотя обычно все вычисления возлагаются на программу. Далее в цикле последовательно считываются 8 байтов, составляющих символ, и переносятся на экран. При этом переменная ADDR1 изменяется с шагом 256, что обеспечивает заполнение одного знакоместа (чуть позже мы подробно остановимся на строении экрана и методах вычисления его адресов, а пока примите это как данность). Обратите внимание на способ организации цикла в этом примере. С точки зрения Бейсика вся эта программка выглядит довольно неказисто, но зато она довольно точно отражает последовательность действий микропроцессора при выполнении аналогичной задачи.

Вообще-то все на самом деле выглядит несколько сложнее, а здесь мы продемонстрировали лишь принцип работы одного из самых популярных операторов Бейсика — оператора PRINT. Но пусть вас это не пугает, ведь процедура вывода символов на экран уже имеется в компьютере, и совершенно не обязательно воспроизводить ее еще раз в своей собственной программе. Достаточно знать, как ее можно вызвать — и значительная часть проблем отойдет в сторону.

Однако, не будем забегать вперед, а прежде разберемся до конца с темой этой главы.

ПРЕИМУЩЕСТВА И НЕДОСТАТКИ ЯЗЫКА АССЕМБЛЕРА

Бейсик, Паскаль, Си и подобные им языки относятся к так называемым языкам высокого уровня. Это означает, что операторы, составляющие их словарный запас, по сути своей являются целыми программами, написанными, как правило, на языке низкого уровня — на изучаемом нами ассемблере, а по сути, в машинных кодах, которыми «говорит» компьютер. Что касается ассемблера, то он дает возможность писать программы на среднем или низком уровне (точнее, почти на самом низком, как мы уже говорили). Разница между средним и низким уровнем достаточно условная и заключается в том, что первый в полную силу использует возможности операционной системы, обращаясь к готовым подпрограммам, «зашитым» в ПЗУ, а второй — нет. Выбор уровня зависит от целей программиста, у каждого из них есть свои преимущества и недостатки, а весь этот разговор мы затеяли лишь затем, чтобы помочь вам сориентироваться в таком выборе.

Итак, что же мы теряем и что приобретаем с переходом к более низким уровням программирования?

Чтобы понять, почему программы, написанные на ассемблере, обычно работают во много раз быстрее, давайте посмотрим, какими методами пользуются интерпретаторы (например, тот же Бейсик) и компиляторы.

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

Несколько быстрее работают компиляторы. Полученные с их помощью программы можно сравнить с подстрочником, составленным довольно неумелым переводчиком, поэтому микропроцессору над каждой фразой приходится еще поломать голову, что же хотел сказать этим автор. (Если быть более точным, компилятор каждую фразу исходного языка заменяет кусочком машинного кода, а то, как эффективно он это делает, зависит от авторов данного компилятора — Примеч. ред.) Кроме того, большинство компиляторов имеет дурную привычку «навешивать» на программу воз и маленькую тележку совершенно никому не нужного хлама, что при 48K максимальной свободной памяти кажется, мягко говоря, несколько расточительным.

Что же касается машинных кодов, то это родной язык компьютера, и совершенно естественно, что программу на таком языке микропроцессор может выполнить в самые кратчайшие сроки — ведь в этом случае не приходится прибегать к услугам переводчиков. Безусловно, и тут при желании можно «загнуть» такую заумную фразу, которая надолго оставит компьютер в недоумении, но это уже будет на совести автора программы.

Конечно, умение писать на ассемблере не означает полный отказ от Бейсика и других языков высокого уровня, особенно на первых порах. Поэтому мы ставим цель прежде всего научить вас создавать коротенькие фрагменты, позволяющие значительно обогатить игры и придать им динамичность. Большинство предлагаемых в этой книге подпрограмм построено по принципу широкоизвестного набора процедур в машинных кодах под названием Supercode. Причем некоторые из предлагаемых примеров будут работать в «тандеме» с программами на Бейсике.

ОРГАНИЗАЦИЯ ПАМЯТИ

При создании программ на ассемблере вы в той или иной степени лишаетесь опеки операционной системы и вынуждены самостоятельно следить за размещением в памяти кодов программы, переменных, массивов и различных рабочих областей, ежели таковые потребуются. Отчасти подобные проблемы уже могли вставать перед вами, если в своих программах на Бейсике вы использовали дополнительные шрифты или процедуры из пакетов Supercode и NewSupercode. Но в Бейсике задача по размещению кодов решается довольно просто — нужно только опустить RAMTOP чуть ниже адреса загрузки кодового блока, выполнив оператор CLEAR. Когда же вы начнете программировать на ассемблере, то во многих случаях этого окажется недостаточно. Поэтому необходимо четко представлять, как распределяется память между различными областями, а также какие области памяти вообще существуют и для чего они предназначены. Не обойтись и без знания строения некоторых из них. Например, для успешной обработки изображений (скажем, вывода спрайтов, скроллинга окон и т. п.) нужно уметь по координатам экрана быстро определять адрес соответствующего байта в видеобуфере. Именно этим вопросам и будет посвящен данный раздел. Не вдаваясь в подробности сразу скажем, что описываемое здесь распределение памяти будет одинаково и для стандартной конфигурации Speccy с 48 килобайтами оперативной памяти, и для ZX Spectrum 128 со 128К, и даже для таких монстров, у которых ОЗУ занимает 256 или 512К.

ПЗУ и ОЗУ

Вся память компьютера делится на две основные области: постоянное запоминающее устройство (ПЗУ) и оперативная память (ОЗУ). ПЗУ начинается с адреса 0 и содержит коды операционной системы Бейсик. В этой области памяти ничего нельзя изменить, все, что там записано, сохраняется и при выключенном питании компьютера. Тем не менее, в ПЗУ имеется множество полезных подпрограмм, которыми мы в дальнейшем будем пользоваться с большим успехом, кроме того, мы часто будем обращаться к кодам знакогенератора, расположенным в самых последних ячейках ПЗУ, начиная с адреса 15616, и представляющим собой полный набор символов, печатаемых на экране. Простирается постоянная память вплоть до адреса 16384, с которого начинается область ОЗУ (рис. 2.1).

65535
ОЗУ Определяемые пользователем символы
UDG (23675)
Вершина машинного стека
RAMTOP (23730)
Машинный стек
Свободная память
STKEND (23653)
Рабочие области Бейсика
STKBOT (23651)
Стек калькулятора
WORKSP (23649)
Область редактирования строкбейсик-программ
ELINE (23641)
Переменные Бейсика
VARS (23627)
Текст бейсик-программы
PROG (23635)
Канальная информация
CHANS (23631)
Системные переменные
23552
Буфер принтера
23296
Видеобуфер
16384
ПЗУ Знакогенератор
15616
Операционная система Бейсик
0

Рис. 2.1. Распределение областей памяти

Если в ПЗУ все уже предопределено, то оперативная память служит для временного хранения и обработки информации. Это могут быть различные программы на Бейсике или в машинных кодах, текстовые файлы, блоки данных и т. п. Все программы, которые приведены в книге, должны размещаться именно в оперативной памяти.

Для успешного программирования в машинных кодах и на ассемблере нужно четко представлять, какие области оперативной памяти для каких целей служат. Наиболее важной из них является видеобуфер, так как никакими программными средствами невозможно изменить его местоположение, размер или строение. Экранная память начинается с адреса 16384 и занимает 6912 байт. Вся остальная память, с адреса 23296 и до 65535 включительно, находится в вашем безраздельном распоряжении. Правда, это только в том случае, если вы создаете программу, полностью независимую от операционной системы компьютера. Но пока программа не заблокирует систему, вы не можете нарушать содержимого и структуры некоторых областей, о назначении и расположении которых вы должны быть хорошо осведомлены, начиная программировать на ассемблере.

Системные области

Сразу за видеобуфером следует небольшая область памяти, называемая буфером принтера. Она используется только при работе с различными печатающими устройствами, поэтому если вы не предполагаете в своей программе делать какие-то распечатки на бумаге, смело можете занимать память в диапазоне адресов от 23296 до 23551 включительно (то есть 256 байт) под любые нужды. Во всяком случае, буфер принтера может использоваться для временного хранения информации или как рабочий массив.

Однако нужно помнить, что все сказанное о буфере принтера справедливо лишь для стандартной конфигурации компьютера, то есть для ZX Spectrum 48. Если вы пишете программы, которые должны работать на модели Spectrum 128 или Scorpion ZS 256, то столь произвольно обращаться с этой областью памяти нельзя, потому как в данных адресах указанные модели содержат жизненно важную информацию, при разрушении которой компьютер не сможет нормально продолжать работу (хотя, разумеется, можно выполнить программу и в режиме «эмуляции» обычного Speccy — Примеч. ред.).

С адреса 23552 начинается наиболее важная из системных областей. Вы уже частично (а может быть, и полностью) знакомы с системными переменными Бейсика. В различных ячейках этой области хранится различная информация о текущем состоянии всех без исключения параметров операционной системы, в том числе и информация о расположении всех прочих областей памяти, которые не имеют жесткой привязки к конкретным адресам (описание всех системных переменных Spectrum-Бейсика, а также ZX Spectrum 128 и TR-DOS можно найти в [2]).

Системная переменная CHANS, находящаяся в ячейках 23631 и 23632, адресует область канальной информации, содержащей необходимые сведения о расположении процедур ввода/вывода (напоминаем, что на первом месте стоит младший байт адреса и для перевода двухбайтового значения в число требуется содержимое старшего байта умножить на 256 и прибавить к нему число из младшего байта; например, для определения значения переменной CHANS нужно выполнить команду PRINT PEEK 23631+256*PEEK 23632). Далее следует область, хранящая текст бейсик-программы. Ее начальный адрес содержит переменная PROG (23635/23636). Сразу за бейсик-программой располагаются переменные Бейсика. Их начало можно определить, прочитав значение системной переменной VARS по адресу 23627/23628. После переменных Бейсика расположена область, предназначенная для ввода и редактирования строк бейсик-программ. Ее адрес записан в системной переменной E_LINE (23461/23642). За областью редактирования строк находится рабочая область Бейсика WORKSP (23649/23650), предназначенная для самых разных нужд. Сюда, например, считываются заголовки файлов при загрузке программ с ленты, там же размещаются строки загружаемой оператором MERGE программы до объединения их со строками программы в памяти и т. д.

Следом за областью WORKSP расположена весьма важная область, называемая стеком калькулятора. Название говорит само за себя: сюда записываются числовые значения, над которыми производятся различные математические операции, здесь же остается до востребования и результат расчетов. В дальнейшем мы не раз будем прибегать к помощи этой области, так как многие процедуры операционной системы, которыми мы будем пользоваться, берут параметры именно отсюда. Системная переменная STKBOT (23651/23652) указывает на начало стека калькулятора, а STKEND (23653/23654) — на его вершину. Иногда бывает важно учитывать, что каждое значение, заносимое на вершину стека калькулятора, имеет длину 5 байт.

Системная переменная RAMTOP (23730/23731) указывает на местоположение в памяти еще одной важной области — машинного стека (не путайте со стеком калькулятора!). Но надо помнить, что в ассемблерных программах стек вполне может потерять всякую связь с RAMTOP, ибо он не является неотъемлемой частью бейсик-системы, а скорее уж, находится в «собственности» микропроцессора. Вообще же стек — это удивительно удобная штука для временного хранения различной информации, потому как при его использовании не приходится запоминать, где, по какому адресу или в какой переменной находится то или иное число. Важно лишь соблюсти очередность обмена данными, а чтобы не нарушить установленный порядок, следует знать, по какому принципу работает стек. Этот принцип часто называют «Last In, First Out» (LIFO), что значит «Последним вошел, первым вышел». Совсем как в автобусе в час пик — чтобы выпустить какого-нибудь пассажира, прежде должны выйти все вошедшие за ним. Поэтому данные, которые понадобятся в первую очередь нужно заносить в стек последними (это же, кстати, в полной мере относится и к порядку обмена данными со стеком калькулятора).

Говоря о машинном стеке, нужно отметить один довольно интересный факт. В отличие от способа организации других областей памяти (а также и от стека калькулятора) он растет «головой вниз», то есть каждое следующее значение, отправленное в стек, будет располагаться по адресу на 2 байта ниже предыдущего (машинный стек работает только с двухбайтовыми величинами). Поэтому вас не должны вводить в заблуждение такие выражения как «Положить значение на вершину стека» или «Снять значение с вершины стека» — эта самая «вершина» всегда будет не выше основания.

Существуют и другие области памяти, как то: UDG, системные переменные TR-DOS или карта микродрайва. Область определяемых пользователем символов UDG мы рассмотрим в следующих главах, а о других разделах памяти (в том числе и об архитектуре Spectrum 128) вы можете получить дополнительные сведения, например, в книге [2].

Строение экрана

Как мы уже говорили, важность знания структуры экранной области трудно переоценить. Умение быстро рассчитывать адрес в видеобуфере по координатам экрана понадобится нам в большинстве графических построений, особенно, если вы хотите научиться обходиться без опеки операционной системы, которая почти всегда оказывается не достаточно быстродействующей.

Строение экрана «на высоком уровне» вам уже должно быть известно (рис. 2.2), но тем не менее, напомним, из каких частей он состоит. Внешняя область, называемая бордюром, может только изменять свой цвет, никакую графическую информацию, за исключением быстро бегущих по нему полос, в эту область поместить невозможно. Внутри бордюра находится рабочий экран, сюда может быть выведена любая текстовая или графическая информация. Говоря об экране, мы всегда будем подразумевать именно эту его часть. Рабочий экран в свою очередь делится на основной экран и служебное окно, которое обычно занимает две нижние строки, но в некоторых случаях может увеличиваться или уменьшаться. Всего экран имеет 24 текстовые строки, и в каждой строке можно напечатать 32 символа. Эти стандартные площадки для вывода символов называются знакоместами. Любое изображение на экране состоит из маленьких квадратиков, называемых пикселями, и каждое знакоместо имеет размеры 8 × 8 таких элементарных «точек».

Теперь перейдем к более низкому уровню и посмотрим, как адресуется область видеобуфера. Вы, наверное, не раз наблюдали, как грузятся с магнитофона стандартные экранные файлы: область экрана заполняется не последовательно, строка за строкой, а довольно хитрым способом. Сначала один за другим появляются верхние ряды пикселей восьми первых текстовых строк, затем в этих же строках рисуются все вторые ряды и так далее, пока не сформируется изображение всей верхней трети экрана. Затем, в том же порядке, заполняется средняя часть экрана, а потом и нижняя. И только в самом конце последовательно выводятся атрибуты всех знакомест. Однако это говорит не о каком-то изощренном способе загрузки именно экранных файлов — они грузятся так же, как и любые другие, последовательно заполняя ячейки памяти от младших адресов к старшим. Это свидетельствует, напротив, о нелинейном строении экранной области памяти.

На первый взгляд такая организация экранной области кажется исключительно неудобной, особенно при решении задач определения адреса по заданным координатам. Но это лишь до тех пор, пока вы используете в расчетах только десятичные числа. Ведь даже начальный адрес видеобуфера 16384 в десятичном виде представляется просто «взятым с потолка». В таких случаях гораздо удобнее пользоваться несколько иным представлением числовой информации. Мы имеем в виду шестнадцатеричный формат чисел, который от десятичного отличается «емкостью» разрядов.

В десятичном представлении каждый разряд числа может изменяться от 0 до 9, а в шестнадцатеричном — от 0 до 15. Цифры от 0 до 9 при этом записываются так же, как и в десятичных числах, а дальше применяются буквы латинского алфавита от A до F. Вот соответствие чисел в десятичном и шестнадцатеричном форматах:

Если адрес 16384 привести к шестнадцатеричному виду, то он вдруг окажется совершенно «ровным» — #4000 (знак # перед числом говорит о том, что оно представлено как шестнадцатеричное). Взгляните на схему, изображенную на рис. 2.3 и вы заметите явную закономерность в распределении адресного пространства видеообласти. В недалеком будущем мы подробно расскажем о методах вычисления адресов экрана, а сейчас перейдем к рассмотрению других не менее важных понятий.

Данные Атриб. Строка ВИДЕОБУФЕР Строка Данные Атриб.
#4000 #5800 0 0 #401F #581F
#4020 #5820 1 1 #403F #583F
#4040 #5840 2 2 #405F #585F
#4060 #5860 3 3 #407F #587F
#4080 #5880 4 4 #409F #589F
#40A0 #58A0 5 5 #40BF #58BF
#40C0 #58C0 6 6 #40DF #58DF
#40E0 #58E0 7 7 #40FF #58FF
#4800 #5900 8 8 #481F #591F
#4820 #5920 9 9 #483F #593F
#4840 #5940 10 10 #485F #595F
#4860 #5960 11 11 #487F #597F
#4880 #5980 12 12 #489F #599F
#48A0 #59A0 13 13 #48BF #59BF
#48C0 #59C0 14 14 #48DF #59DF
#48E0 #59E0 15 15 #48FF #59FF
#5000 #5A00 16 16 #501F #5A1F
#5020 #5A20 17 17 #503F #5A3F
#5040 #5A40 18 18 #505F #5A5F
#5060 #5A60 19 19 #507F #5A7F
#5080 #5A80 20 20 #509F #5A9F
#50A0 #5AA0 21 21 #50BF #5ABF
#50C0 #5AC0 22 22 #50DF #5ADF
#50E0 #5AE0 23 23 #50FF #5AFF

Рис. 2.3. Адресация видеобуфера

РЕГИСТРЫ И РЕГИСТРОВЫЕ ПАРЫ

Для общения с компьютером на уровне машинных кодов необходимо усвоить еще одно новое понятие кроме таких, как память, адрес, байт, бит, с которыми, надеемся, вы уже достаточно неплохо разобрались. Речь идет о регистрах микропроцессора. Регистры можно представить как совершенно особые внутренние ячейки памяти, являющиеся неотъемлемой частью центрального процессора. Роль их настолько важна, что практически ни одна операция не обходится без участия регистров, а различные арифметические и логические действия без них и вовсе невозможны.

Мы назвали регистры особыми ячейками, но в чем же их особенность и чем они отличаются от ячеек обычной оперативной памяти? В первую очередь их особенность проявляется в том, что регистры не равноценны, то есть действия, допустимые с использованием одного регистра невозможны с другими и наоборот. Кроме того, если значения одних регистров можно изменять непосредственно, записывая в них те или иные числа, то другие изменяются автоматически, и узнать их содержимое возможно только лишь косвенными методами. Другая особенность регистров состоит в том, что для обращения к ним используются не адреса, а собственные имена, состоящие из одной или двух букв латинского алфавита (конечно же, имена присутствуют только в языке ассемблера, а не в машинных кодах команд). Есть и еще одно свойство, отличающее регистры от ячеек памяти — это способность их объединяться определенным образом, составляя регистровые пары. Во всем же остальном они очень схожи с отдельными ячейками памяти компьютера. Они также имеют размер байта (8 бит), в них можно записывать числа и читать их значение (за исключением системных регистров), информация в них может сохраняться, как и в памяти, до тех пор, пока не будет изменена программой.

Все регистры могут быть подразделены на несколько групп, учитывая характер функций, которые они выполняют. Начнем с самой многочисленной и наиболее важной группы — с так называемых регистров общего назначения или регистров данных. Их насчитывается семь: A, B, C, D, E, H и L. Как уже говорилось, каждый регистр может использоваться лишь в строго определенных операциях и каждый из них в этом смысле уникален. Например, регистр A (часто называемый аккумулятором) участвует во всех арифметических и логических операциях, результат которых мы получаем в том же регистре A. Использование регистра B наиболее удобно при организации циклов. При этом он выполняет роль, схожую с обязанностями управляющих переменных циклов FOR…NEXT в Бейсике. Другие регистры проявляют свою индивидуальность, преимущественно, объединившись в пары. Возможны следующие регистровые пары: BC, DE и HL. И вам следует запомнить, что никаких других вариантов соединения регистров не существует.

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

Каждая из регистровых пар так же, как и любой из отдельных регистров, выполняет вполне конкретные, возложенные именно на нее функции. Так пара BC часто используется, подобно регистру B в качестве счетчика в циклах. HL несет наибольшую нагрузку, играя примерно ту же роль, что и аккумулятор: только с этой парой можно выполнять арифметические действия. Пара DE зачастую адресует пункт назначения при перемещениях данных из одной области памяти в другую.

Работая с регистровыми парами, приходится иметь дело с двухбайтовыми величинами. Поэтому необходимо четко представлять, как такие числа хранятся в памяти и каким образом они размещаются на регистрах. В Бейсике вам, вероятно, уже доводилось сталкиваться с подобной задачей. Если вы пользовались оператором POKE и функцией PEEK, например, для изменения или чтения системных переменных, то вам уже должно быть известно, что двухбайтовые значения хранятся в памяти, как правило, в обратном порядке — сначала младший байт, затем старший. Это можно продемонстрировать на таких примерах: число 1 запишется в памяти в виде последовательности байтов 1 и 0; у числа 255 старшая часть также равна нулю, поэтому оно будет представлено как 255 и 0; следующее число 256, расположившись в двух ячейках, будет выглядеть как 0 и 1. На всякий случай напомним вам способ, позволяющий разложить любое число из диапазона 0…65535 на два байта и определить значения старшей и младшей половинки:

Вам также часто придется сталкиваться с необходимостью изменять только старший или только младший регистр в регистровых парах. Поэтому следует хорошенько запомнить правило, которому подчиняются регистры при объединении. Оказывается, порядок здесь прямо противоположный по сравнению с числами в памяти — первым записывается старший регистр, а за ним младший. То есть в паре BC старшим окажется регистр B, в DE — D, а в HL — H. Чтобы лучше запомнить это, можете представить имя регистровой пары HL как сокращения английских слов HIGH (высокий, старший) и LOW (низкий, младший), а то, что порядок следования старшей и младшей половинок в остальных парах аналогичен, это уже само собой разумеется.

К следующей группе относятся два индексных регистра, имена которых начинаются с буквы I (Index) — IX и IY. В отличие от регистров данных, индексные регистры состоят из 16 разрядов, то есть являются как бы неделимыми регистровыми парами. (На самом деле существуют методы разделения индексных регистров на 8-разрядные половинки, что уже относится к программистским изощрениям. Об этих методах вы можете узнать из Приложения II.) В основном они применяются при обработке блоков данных, массивов или разного рода таблиц, но также вполне могут использоваться и как обычные регистры общего назначения. Удобство употребления этих регистров заключается в том, что они позволяют обратиться к любому элементу массива или таблицы без изменения содержимого самого регистра, а лишь указанием величины смещения для данного элемента (иначе, его номера или индекса, например, IX+5). Заметим, что регистр IY обычно адресует область системных переменных Бейсика и поэтому отчасти и только в компьютерах ZX Spectrum может быть отнесен к следующей группе — системным регистрам.

К системным или иначе — аппаратным регистрам относятся: указатель вершины стека SP (Stack Point), вектор прерываний I (Interrupt) (точнее, этот регистр содержит старший байт адреса векторов прерываний; позднее мы подробно расшифруем это понятие) и регистр регенерации R. Первый из них, так же, как и индексные регистры, имеет 16 разрядов, разделить которые на 8-битовые половинки нет никакой возможности. Но это и не нужно, ведь регистр SP служит для вполне определенных целей — указывает адрес вершины области машинного стека, как это и следует из его названия. Хотя с ним и можно обращаться, как с обычным регистром данных (записывать или читать из него информацию), но делать это нужно, совершенно точно представляя, что при этом происходит. Обычно же за регистром SP следит микропроцессор и изменяет его так, как надо при выполнении некоторых команд. Например, без этого регистра оказались бы совершенно невозможны вызовы подпрограмм с нормальным возвратом из них в основную программу.

Регистры I и R, в противоположность всем прочим, никогда не объединяются в пары и существуют только по отдельности. Содержимое вектора прерываний I также может быть изменено программным путем, однако делать этого не стоит до тех пор, пока вы не разберетесь с таким достаточно сложным вопросом, как прерывания. Что же касается регистра R, то читать из него можно, а вот записывать в него информацию в большинстве случаев бесполезно, так как он изменяется аппаратно. Правда, используется для аппаратных нужд только 7 младших разрядов, так что, если вам для чего-то окажется достаточно одного бита, можете хранить его в старшем разряде регистра регенерации.

В свое время мы подробно расскажем о применении всех существующих регистров, а сейчас закончим этот краткий обзор и займемся другими вопросами.

ПРОСТЕЙШАЯ ПРОГРАММА В МАШИННЫХ КОДАХ

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

Большинство программ на машинном языке, имеющих возврат в Бейсик, заканчивается кодом 201 (в мнемоническом обозначении — RET), который аналогичен оператору RETURN. Поэтому простейшая программа может состоять всего из одного байта. Давайте сейчас создадим такую программу, а потом и выполним ее. Введите с клавиатуры оператор

а затем, чтобы проверить действие полученной «программы», запустите ее с помощью функции USR, например, так:

Вроде бы ничего особенного не произошло — никаких видимых или слышимых эффектов. Но, по крайней мере, ваш компьютер выдержал подобное испытание и при этом не «завис» и не «сбросился» (если он исправен, конечно, на что мы надеемся). Программа нормально завершила свою работу и благополучно вышла в Бейсик с сообщением 0 OK.

Теперь попробуем запустить ее несколько иным способом. Заменим оператор RANDOMIZE на PRINT:

То, что вы увидели на экране — весьма существенно и может очень пригодиться в будущем. Компьютер напечатал то же самое число, которое мы использовали в качестве аргумента функции USR. Можете проверить, что это не случайное совпадение, введя строку

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

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

Как вы увидите позже, большинство процедур в машинных кодах, если это необходимо, получают входные параметры и возвращают значения на регистрах. Как правило, это оказывается наиболее удобно. Поскольку функция USR предназначена для вызова машинных процедур, то и она может обмениваться числовыми данными с программой на Бейсике также через регистры, а именно — через регистровую пару BC. В качестве входного параметра используется аргумент функции, а на выходе значение пары BC передается бейсик-программе. А так как в приведенных выше примерах никакие регистры не изменялись, то и на экране появлялось то же самое число, которое использовалось в качестве аргумента.

Теперь модернизируем нашу программку так, чтобы содержимое регистровой пары BC изменялось. Можно, например, просто записать в нее какое-нибудь число. Обычно запись в регистры числовых значений называют загрузкой, поэтому в мнемоническом обозначении такие команды начинаются с LD (сокращение от известного вам по Бейсику слова LOAD — загрузить). А выражение «загрузить регистровую пару BC значением 1000» записывается как

Эта команда всегда состоит из трех байт: первый равен 1, а второй и третий соответствуют двухбайтовому представлению числа в памяти. Таким образом, программа из двух команд

в памяти будет представлена последовательностью кодов

Введите их последовательно, начиная, например, с адреса 60000 и выполните закодированную программку оператором

Если вы ничего не напутали, то на экране должно появиться число 1000.

Надо думать, на этих примерах вы уже почувствовали «прелесть» программирования в машинных кодах и догадались, что подобным методом может пользоваться только сумасшедший или неукротимый фанатик. Однако и фанатик в конце концов понимает, что лучше все же воспользоваться ассемблером, благо фирма HISOFT подарила синклеристам весьма недурную реализацию этого языка, по многим параметрам могущую считаться вполне профессиональной. (Лучшей реализацией языка ассемблера для компьютеров семейства ZX Spectrum считается транслятор фирмы OCEAN Software из пакета Laser Genius, однако ассемблер фирмы HISOFT остается непревзойденным по минимальному объему занимаемой самим транслятором памяти и, соответственно, максимальному размеру области, отводимой для создаваемого им кода программы. Как и Бейсик 48, этот ассемблер использует несколько усеченный строчный текстовый редактор. Это, конечно, немного хуже, чем экранный редактор (как, например, в Бейсике 128), но за все приходится чем-то расплачиваться — Примеч. ред.)

Источник

Теперь вы знаете какие однокоренные слова подходят к слову Как написать игру на ассемблере для zx spectrum, а так же какой у него корень, приставка, суффикс и окончание. Вы можете дополнить список однокоренных слов к слову "Как написать игру на ассемблере для zx spectrum", предложив свой вариант в комментариях ниже, а также выразить свое несогласие проведенным с морфемным разбором.

Какие вы еще знаете однокоренные слова к слову Как написать игру на ассемблере для zx spectrum:



Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *