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

'Как Название:: Как написать игру для ZX Spectrum
Автор: А. Капульцевич, И. Капульцевич, А. Евдокимов
Страниц: 206
Формат: PDF
Размер: 1,26 Мб
Качество: Отличное
Язык: Русский
Год издания: 1995

Второе издание этой популярнейшей книги выпускается по многочисленным просьбам читателей. Она представляет собой увлекательный учебник для тех, кто имеет компьютер ZX Spectrum и хочет научиться самостоятельно писать для него игровые программы. Читатель научится составлять игровые программы на языке Бейсик, рисовать заставку к программе и делать многоуровневое меню, узнает, как создать и заставить двигаться по экрану спрайты, как ввести в программу звуковые эффекты. Он сможет использовать для создания программ диалект Laser Basic и процедуры в кодах из пакетов Supercode и New Supercode, генератор игр Games Designer. Книга рассчитана в основном на начинающих программистов, но будет полезна всем, кто всерьез интересуется этой темой.

Внимание! У Вас нет прав для просмотра скрытого текста.

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

Так вот, короче, мы всегда хотели иметь в Мире Спектрума технический отдел, и сегодня, благодаря Mojon Twins (“Близнецам Мохонам”), открывается новый раздел Семинара, в котором вы сможете научиться создавать ваши собственные игры для Спектрума. Лучше поздно, чем никогда. Это подходящий момент для того, чтобы избавиться от этой занозы, сидящей вот уже 20 или 30 лет, и, в конце концов, стать авторами вашего собственного спектрумского шедевра.

В этом повествовании, поделенном на главы, Mojon Twins расскажут нам в своем традиционном сюрреалистическом и очень юмористическом стиле о методе использования их программы Churrera v3.99b (Чуррера – продавщица «чуррос», сладкой выпечки из заварного теста). Вы увидите, насколько это просто, когда тебе все объясняют. И если у вас есть какие-нибудь сомнения, вы можете спрашивать все, что угодно посредством комментариев для того, чтобы преподаватель Мохоно, обезьяна или человек, либо ответил вам, либо продал вам подержанный мотоцикл, этого мы уже не знаем.

Итак, перед вами первая глава La Churrera v3.99b – Руководство пользователя – Copyleft 2013 The Mojon Twins.

Глава 1. Введение

01seto-1513[1]

Что это еще за забор?

Это говорю я. Что это еще за забор? Уффф… Столько нужно рассказать и столько мало места. Я мог бы болтать часами, говоря всякие глупости, однако постараюсь этого не делать. Мне сказали, что я должен выражать свои мысли коротко и ясно, и хотя мне это непросто, я попытаюсь быть таким.

Начнем с самого начала. В действительности продвинемся чуть-чуть дальше жаркого спора между креационистами и сторонниками теории эволюции. Отправимся в 2010 год… (Здесь звучит типичная музыка для того, чтобы поставить изображения из прошлого – та, что заставляет делать так: та-а-а, та-ра-ра-ра, та-ра-а-а…).

В начале года у нас в Мохонии была одна идея. В основном мы были по горло сыты тем, что, делая игры, копировали и вставляли. Потому что дело заключается не в том, чтобы копировать и вставлять, а в количестве тех вещей, которые всегда выполняются одинаково с изменением некоторых параметров. Посмотрим, думаешь ли ты, что мы – те, кто делает игры, – каждый раз при этом пишем одну и ту же рутину… Мы также устали от изнурительной ручной работы. Что, если перемещать вручную спрайты в формат splib2, что, если выстраивать вручную плитки для того, чтобы SevenuP прочитал их в правильном порядке, что, если пройти карту, что, если разместить врагов на листе в клетку… У нас была тысяча забот во время производства игр, которые получались скучными и тоскливыми. А кто хочет скучать, пока он делает то, что предположительно ему нравится? Мы – нет. И, полагаю, что и ты – тоже.

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

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

02lala-beta-falsa-5105[1]

У нас была куча идей для движка. Мы могли бы развивать его понемногу и затем получить окончательный вариант игры, но мы не действуем подобным образом. Поскольку с нами приключались приступы паранойи, мы получали игры всякий раз, когда отправляли что-то новое в движок. Таким образом, как только был готов «оперативный минимум», мы выпустили Lala the Magical («Волшебница Лала»), Cheril of the Bosque («Шерил из Леса»), Sir Ababol («Сэр Простофиля») и Viaje al Centro de la Napia («Путешествие к Центру Носа»).

Поскольку, оглядываясь назад, мы лепили игры как «чуррос» (но о каких «чуррос» речь, сеньора!), мы решили назвать систему «Ла Чуррера». И так все и началось…

Но тогда, что именно это такое, Churrera?

Пожалуй, вот так: Churrera – это фреймворк, который состоит из нескольких очень забавных вещей:

  1. Движок или «мотор», сердце Чурреры. Речь идет о наборчике потрясающих кодов, который «управляется» посредством главного файла, именуемого “config.h“. В нем мы указываем, какие части «мотора» мы будем использовать в нашей игре, и как они будут себя вести.
  2. Утилиты преобразования, которые позволяют нам нарисовать нашу игру в наших излюбленных редакторах и в бесцветной, лишенной запаха и вкуса, форме поместить в нее все эти данные.
  3. Куча обезьян, незаменимых для любой вещи, которую хотелось бы сделать при наличии тех или иных условий.

03mono-2716[1]

«Продаю подержанный мотоцикл»

У Чурреры было много версий на протяжении трех последних лет. От внутренней формы мы дошли до версии 4.7, однако наборчик получился непрезентабельным. Он был очень беспорядочный, и у него слишком было много хаков. Таким образом, когда нам пришло в голову сделать руководство пользователя, мы решили вернуться немного назад, в ту точку прошлого, когда эта тема была еще управляемой – к версии 3.1: Trabajo Basura («Грязная работа»), Zombie Calavera Prologue («Зомби Калавера. Пролог»). Но не думайте, что мы ограничимся тем, что дадим вам нашу «старую версию», и на этом хватит. Нет, ничего подобного.

В течение пары месяцев мы целиком и полностью посвятили себя тому, что взяли версию 3.1, исправили в ней все недоделки, поменяли половину компонентов для того, чтобы сделать их более быстрыми и компактными, а также добавили кучу характеристик.  Таким образом, мы создали версию 3.99b, которую предоставляем в ваше распоряжение, и которая во многих отношениях более продвинутая, более быстрая и выполняет больше действий, чем версия 4.7. На самом деле у нас получилось так хорошо, что мы продолжаем разработку, начиная с этой версии 3.99b, включая усовершенствования «ветви 4» «Ramiro el Vampiro» («Рамиро-Вампир»), которые мы будем считать интересными.

Версия 3.99b настолько оптимизирована, что, если мы рекомпилируем старые игры с ней, то получим бинарники на 2 – 5 килобайтов меньшего размера, с более быстрыми движениями и намного более связные. И она находится в вашем распоряжении.

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

Но что можно сделать с помощью этого?

Пожалуй, кучу разных вещей. И они уже пришли нам в голову. И хотя верно, что есть общие элементы и определенные ограничения, очень часто ты можешь вытащить из рукава новую паранойю, всего лишь комбинируя в различной форме элементы, которые имеешь в своем распоряжении. Хочешь примеры? Для этого самого мы запустили Mojon Twins Covertape #2. Если у тебя его еще нет, скачай. СЕЙЧАС.

Для Mojon Twins Covertape #2 мы наняли племя грязноногих индейцев родом из Джунглей Бадахоса. Каждому из них мы написали одну характеристику Чурреры на спине, а другую – на груди, и отправили их спускаться по холмам, образуя крокету (род котлеты). Когда они спускались вниз, мы сделали фотографию и отметили возникшие комбинации. С помощью этих комбинаций мы создали игру. Потом мы позвали Альберто, Одноглазую Обезьяну, который придумывает небылицы с тем, чтобы он подтвердил их, используя какой-нибудь убедительный аргумент. И это работает, серьезно.

04set1-2927[1]

Окинем взглядом то, что мы имеем в наличии:

  1. Характеристики: Все характеристики, связанные с движением главного героя, изменяемые. Мы можем сделать так, чтобы он прыгал больше или меньше, чтобы падал медленнее, чтобы больше скользил, бегал много или мало, и многое другое.
  2. Ориентация: Мы можем сделать так, что наша игра будет смотреться сбоку или сверху (то, что мы в Мохонии называем «генитальной перспективой»). Это первое, что мы должны решить, потому что именно от этого будет зависеть весь дизайн игры.
  3. Прыгать? Летать? Как? Если мы выберем боковую перспективу (так, чтобы игра смотрелась со стороны), мы должны будем определить, как станет двигаться фигурка. Мы можем сделать так, чтобы она прыгала, когда нажимаем на «прыжок» (Lala Lah, Julifrustris, Journey to the Centre of the Nose, Dogmole Tuppowski…), чтобы прыгала всегда (Bootee), или чтобы с каждым разом прыгала все выше, обретая силу (Monono). Также мы можем сделать, чтобы она летала (Jetpaco).
  4. Отскакивать от стен. Если мы выберем для нашей игры «генитальную перспективу», то мы можем сделать так, чтобы герой немного отскакивал от стены, когда он с ней сталкивается.
  5. Специальные блоки. Мы можем активировать или дезактивировать ключи и засовы или блоки, которые можно толкнуть. Это работает для обеих ориентаций, хотя при боковой перспективе блоки можно будет толкать только в сторону.
  6. Стрелять. Также мы можем сделать так, чтобы главный герой стрелял. В играх с «генитальной перспективой» он будет стрелять в любом из четырех основных направлений. Также мы можем указать движку, какое направление (вертикальное или горизонтальное) имеет предпочтение на диагоналях. В играх с боковой перспективой он будет стрелять в том или ином направлении в зависимости от того, куда он смотрит – налево или направо.
  7. Летающие враги: те, которые преследуют тебя без передышки.
  8. Вражеские преследователи: похожие, но разные… Мы еще поговорим о них.
  9. Острия и какие-то предметы со сцены, которые тебя убивают, необязательно острые.
  10. Убивать: в играх с боковой перспективой мы можем сделать так, чтобы враги (определенный тип врагов) умирали, если ты наступишь им на голову.
  11. Предметы: для того, чтобы были вещи, которые по ходу можно собирать и хранить в мешке.
  12. Скриптинг Если всего вышеизложенного недостаточно, мы можем придумать гораздо больше опций, используя простой встроенный язык скриптинга.

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

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

Видите? Вот так это работает! Отправьте мне email, и я дам вам телефон Альберто.

Тогда с чего мы начнем?

С воображения. Меня не устраивает, что ты возьмешь какую-нибудь нашу игру, уже сделанную, и что-нибудь в ней поменяешь. Нет. Так ты далеко не уйдешь. Некоторые люди так не считают, но я говорю тебе – НЕТ. Изобрети что-нибудь, начни с нуля, и мы постепенно будем это строить, шаг за шагом.

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

В любом случае, для того, чтобы начать, и будучи уверенным в том, что вы действительно не знаете, чего можно делать, а чего нельзя, я приглашаю вас к пошаговому созданию Dogmole Tuppowski. Почему именно этой игры? Потому что она использует много всего, включая скриптинг. Но я не хочу, чтобы ты уходил, забрав архив исходников Covertape #2, и ограничился тем, что стал бы следовать инструкции, просматривая эти архивы. Нет. Тебе предстоит начать с пустого движка, который мы предложим тебе ниже, и с каждой главой ты будешь получать различные средства и осуществлять необходимые действия, как если бы ты действительно создавал игру с нуля.

Для чего нужно устраивать все это представление? Пожалуй, потому что, когда ты возьмешься создавать свою игру, это уже не будет твоим дебютом, и, поверь мне, это – большое преимущество. Ну и потому что театр – это здорово! Выскакивают сиськи!

Давай же, поехали! Начинаем

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

Давайте создадим игру с Dogmole Tuppowski – персонажем, которого мы придумали давно, и который выглядит вот так.

05tuppowski-3541[1]

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

Мы сделаем, чтобы для завершения игры нужно будет выполнить две миссии. Этого мы добьемся посредством скриптинга – то, что мы оставим на окончание процесса. Эти миссии будут простыми и будут использовать автоматические характеристики «движка» для того, чтобы не нужно было писать слишком сложный скрипт:

  1. Будет определенный тип врагов, которых нам необходимо уничтожить. После этого мы получим доступ ко второй миссии, потому что на экране исчезнет каменный блок, который закрывает проход к какой-нибудь части карты.
  2. Нужно будет перенести предметы по одному к той части карты, которая разблокируется после выполнения первой миссии.

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

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

Поскольку у нас есть яйцо, мы придумываем историю, которую ты уже знаешь, если прочитал в свое время описание Covertape #2:

Догмоле Тупповски – это хозяин жестяной шлюпки, на которой он перевозит редкие вещи и прочие артефакты сомнительного происхождения (некоторые говорят, что они обладают магическими свойствами) для некоего ведомства Университета Мискатоник (провинция Бадахос). Однако однажды ночью, когда он собирался совершить свою поставку в виде ящиков, полных загадочных и магических предметов, поднялся жуткий шторм, в результате которого его корабль налетел на кучу камней, из-за чего произошел потрясающий взрыв, и все ящики оказались разбросанными по пляжу и окрестностям.

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

Следовательно, у Догмоле двойная миссия. Сначала он должен уничтожить двадцать Колдунов Религии Петете, и затем, открыв дверь Университета, найти и отнести по одному десять ящиков в вестибюль здания, где ему следует оставить их под вывеской «BOXES», нажимая «A».

Теперь мы можем приступить к дизайну нашей игры. В действительности все обычно получается так. В нашей игре мы обычно делаем ловушки и играем с форой; многие из наших игр появились, потому что мы добавили к Чуррере какую-нибудь новую опцию, и нужно было ее опробовать, как это произошло с Bootee, Balowwwn, Zombie Calavera или Cheril the Goddess. Креативный процесс не имеет «дна» и требует от тебя наличия некоторой изобретательности и воображения, чему, к сожалению, научить нельзя.

Да,  я уже было забыл. Также мы сделали рисунок Meemaid. Вот она:

06meemaid-0151[1] 

Лицом в грязь

Давайте уже начинать собирать все необходимое. Прежде всего, тебе потребуется пакет z88dk, представляющий собой компилятор C под Z80, и splib2 – графическая библиотека, которые мы используем. Поскольку мы не хотим, чтобы ты осложнил себе жизнь, устанавливая их (особенно потому, что splib2 – очень старая, и ее трудно скомпилировать, используя современный z88dk), мы подготовили для пользователей Windows этот архив, который нужно распаковать прямо в корень С, и который содержит в себе z88dk 1.10 и splib2. Если у тебя все получится, то должна будет появиться папка C:z88dk10 с файлами внутри.

http://www.mojontwins.com/churrera/mt-z88dk10.zip (скачать локально: mt-z88dk10)

Пользователи Linux и других систем не должны иметь никаких проблем с установкой последней версии z88dk на своих системах: нужно скопировать файлы splib2.lib и splib2t.lib туда, где папка clibs и spritepack.h туда, где папка includes. Эти два файла я оставил для них здесь:

http://www.mojontwins.com/churrera/mt-splib2.zip (скачать локально: mt-splib2)

Также нам будет нужен текстовый редактор. Если ты программист, то у тебя уже есть такой редактор, с которым ты великолепно обращаешься. Если ты таковым не являешься, то, пожалуйста, не используй “Блокнот”! Скачай, к примеру, Crimson Editor. В действительности любой из редакторов лучше, чем Блокнот на Windows. Если у тебя стоит Linux, то ты будешь иметь в своем распоряжении, по крайней мере, около шестнадцати установленных текстовых редакторов; так что, пользователи Linux, тут преимущество на вашей стороне.

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

http://www.mojontwins.com/churrera/mt-mappy.zip (скачать локально: mt-mappy)

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

http://metalbrain.speccy.org/

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

Тебе также будет необходим хороший графический редактор для того, чтобы раскрашивать обезьянок и «рожки» на экране. Тебе подойдет любой, который сохраняет файлы в формате .png.  Я повторяю тебе, что, если ты не умеешь рисовать, и у тебя нет такого друга, ты можешь «стащить» рисунки с Mojon Twins. Таким же образом тебе потребуется графический редактор для того, чтобы вырезать наши рисунки и вставлять их в твои. Тебе подойдет любой. Я использую суперстарую версию Photoshop, потому что я к ней привык. Многие пользуются Gimp. Их насчитывается целая куча, выбирай тот, что тебе больше по вкусу. Но чтобы он сохранял файлы в формате .png. Запомни. Если пьешь, то за руль не садись.

После установки всего этого нам будет нужна Чуррера. По следующему адресу находится полный архив версии 3.99b:

http://www.mojontwins.com/churrera/mt-churrera-3.99b.zip (скачать локально: mt-churrera-3.99b)

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

  1. Изменяем имя главной директории Churrera3.99b на имя из нашей игры. Например, «Dogmole Tuppowski».
  2. Изменяем имя главного модуля C на имя из нашей игры. Этот модуль находится в /dev/ и называется churromain.c. Мы изменим его на имя dogmole.c.
  3. Редактируем файл make.bat который находится в /dev/ с помощью нашего текстового редактора для того, чтобы адаптировать его к нашей игре. В первую очередь, нужно заменить там, где ставится %1, и поставить имя, которое ты дал churromain.c. В нашем случае, dogmole.

Должно получиться так:

codigo01-0630131747

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

Мы уже готовы к тому, чтобы начать… Но вы должны будете подождать следующей главы. (Не надо ждать, она уже готова! – прим. переводчика)

Перейти к Главе 2

Перейти к Содержанию

[ Перевод на русский язык – сайт viva-games.ru. При перепечатке любой части статьи ссылка на viva-games.ru обязательна. Оригинал статьи тут. ]

Понравилась публикация? Поделись с друзьями

  • игры mojon twins
  • игры для спектрума
  • как создать игру
  • разработка игр
Red copyright.png Данный материал защищён авторскими правами!

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

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

Содержание

  • 1 МАШИННЫЕ КОДЫ И АССЕМБЛЕР
  • 2 ЧТО МОЖЕТ МИКРОПРОЦЕССОР Z80?
  • 3 ПРЕИМУЩЕСТВА И НЕДОСТАТКИ ЯЗЫКА АССЕМБЛЕРА
  • 4 ОРГАНИЗАЦИЯ ПАМЯТИ
    • 4.1 ПЗУ и ОЗУ
    • 4.2 Системные области
    • 4.3 Строение экрана
  • 5 РЕГИСТРЫ И РЕГИСТРОВЫЕ ПАРЫ
  • 6 ПРОСТЕЙШАЯ ПРОГРАММА В МАШИННЫХ КОДАХ
ГЛАВА ВТОРАЯ,
из которой вы узнаете о том, что же такое ассемблер и чем он отличается от Бейсика и машинных кодов, а также усвоите некоторые основные понятия

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

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

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

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

У каждого из этих восьми контактов может быть лишь два состояния — есть заряд или нет заряда. Поэтому его наличие можно представить как 1, а отсутствие — как 0. Последовательности из единиц и нулей дают числа в двоичном представлении, но их несложно перевести в привычный десятичный формат. Напомним, как это делается на примере числа 00111100. Самый младший разряд (то есть, крайнюю правую цифру) умножаем на 1, второй разряд — на 2, третий — на 4, следующий — на 8 и так далее. Иными словами, значение каждого разряда умножается на 2 в степени n, где n — номер разряда, который может изменяться от 0 до 7 (то есть, говоря научно, 2 — это основание системы счисления). Если вам не очень понятно такое определение, воспользуйтесь простой формулой для перевода нашего двоичного числа в десятичное:

00111100=0×128+0×64+1×32+1×16+1×8+1×4+0×2+0×1=60

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

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

LET A=A+1

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

       INC   A

где INC — сокращение от английского слова increase (увеличиваться). Сразу же скажем, что сокращенные имена команд микропроцессора называют мнемониками. Запомните это слово хорошенько, так как оно не раз встретится в нашей книге.

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

Поскольку ассемблер непосредственно связан с машинными командами, то начинать его изучение будет резонно с вопроса «а что же может микропроцессор?» Так вот, если вы считаете, что он способен играть музыку, рисовать картинки или печатать текст, то глубоко заблуждаетесь. Ничего такого микропроцессор не умеет. Он может выполнять лишь самые элементарные действия вроде «2 + 2», а более сложным, таким как «2 × 2», его еще нужно научить. В этом и состоит задача программиста. Но у микропроцессора есть одно преимущество — за одну секунду он способен выполнить многие тысячи операций, поэтому в реальном времени он и кажется достаточно одаренным.

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

  • простейшие арифметические действия сложения и вычитания;
  • операции с памятью, такие как запись в определенную ячейку или считывание из памяти чисел (подобно POKE и PEEK в Бейсике);
  • связь с внешними устройствами через порты (то, чем занимаются в Бейсике OUT и IN);
  • обработка отдельных битов (разрядов двоичных чисел) (напомним, что в Бейсике можно задавать битовые константы с помощью ключевого слова BIN);
  • логические операции с двоичными числами;
  • различные вызовы других подпрограмм;
  • условные и безусловные переходы;
  • работа с прерываниями (это средство, совершенно недоступное Spectrum Бейсику, будет обсуждаться в отдельной главе).

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

10 LET ADDR1=16384
20 LET ADDR2=15880
30 LET N=8
40 LET A=PEEK (ADDR2)
50 POKE (ADDR1),A
60 LET ADDR1=ADDR1+256
70 LET ADDR2=ADDR2+1
80 LET N=N-1
90 IF N<>0 THEN GO TO 40

Выполнив эту программку, вы увидите в верхнем левом углу экрана букву 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 таких элементарных «точек».

Рис. 2.2. Строение экрана

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

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

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

0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18...
0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F 10 11 12...

Если адрес 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 на два байта и определить значения старшей и младшей половинки:

LET high= INT(N/256): REM Старшая часть
LET low=N-256*high: REM Младшая часть

Вам также часто придется сталкиваться с необходимостью изменять только старший или только младший регистр в регистровых парах. Поэтому следует хорошенько запомнить правило, которому подчиняются регистры при объединении. Оказывается, порядок здесь прямо противоположный по сравнению с числами в памяти — первым записывается старший регистр, а за ним младший. То есть в паре 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. Поэтому простейшая программа может состоять всего из одного байта. Давайте сейчас создадим такую программу, а потом и выполним ее. Введите с клавиатуры оператор

POKE 40000,201

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

RANDOMIZE USR 40000

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

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

PRINT USR 40000

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

POKE 40001,201: PRINT USR 40001

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

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

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

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

       LD    BC,1000

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

       LD    BC,1000
       RET

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

1, 232, 3 и 201

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

PRINT USR 60000

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

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

Понравилась статья? Поделить с друзьями:
  • Как написать игру для sega
  • Как написать игру для nes
  • Как написать игру бесплатно
  • Как написать игру башенки
  • Как написать игроку через консоль