Scenergy #02
31 декабря 1999

Coding - Flying представляет макробиблиотеку: Memory Management Library.

<b>Coding</b> - Flying представляет макробиблиотеку: Memory Management Library.
        Memory Management Library

              0. Вступление

 В  этой  статье  речь пойдет об одной, на
мой  взгляд, очень нужной всем вещи - моей
макробиблиотеке Memory Management Library.

 Хм...  Судя по началу, от скромности я не
умру  :) Но у меня есть основания говорить
подобные вещи т.к. то, о чем пойдет речь в
данной  статье  действительно может сильно
облегчить  жизнь  кодеру. Ну ладно, хватит
себя хвалить - перейдем к делу.

            1. Общие сведения

 Итак, как вы  уже могли заметить - Memory
Management Library - это библиотека. Но не
простая,  а макробиблиотека. А это значит,
что использование этой библиотеки никак не
отразится  на вашем коде т.к. в ней нет ни
одной  строчки, которая бы компилировалась
в исполняемый код.
 "Зачем же она тогда нужна?", спросите вы.
"А  затем!"  - отвечу я вам :) Затем чтобы
облегчить выполнение ряда задач с которыми
кодер  сталкивается  практически  в каждой
своей программе. А именно:
 - распределение памяти
 - расчет экранных адресов
 - создание таблиц смещений или указателей
 - задание полей структур данных
 Все  эти задачи решаются с помощью набора
макросов,  содержащихся в этой библиотеке.
Т.е.  они  просто помогут вам организовать
ваш  код таким образом, чтобы он легко мог
быть  при желании модифицирован без лишних
трудов по пересчету чисел в соответствии с
изменившимися начальными данными.
 У  этой  библиотеки есть еще одно, на мой
взгляд,  большое  достоинство  - в отличие
от  всего  остального  моего кода, который
компилируется  только в TASM v4.12 и нигде
больше,  эта библиотека портирована мной и
в  ALASM  v4.2!  Т.е. пользователи ALASM'а
тоже  могут  использовать все преимущества
работы с использованием этой библиотеки не
пересаживаясь  никуда  из  своего любимого
ассемблера.  Более того, если в каком-либо
другом   ассемблере   появится   поддержка
макросов  - эту библиотеку можно будет без
проблем перенести и туда.
 Далее  вы найдете подробные описания всех
частей этой библиотеки, а также примеры ее
использования. В приложении вы найдете сам
исходный текст библиотеки в форматах TASM4
и ALASM. Кроме того, в качестве примера ее
использования  можно  посмотреть исходники
ZXA library.
 Но  перед  тем  как начать описывать саму
библиотеку,  я  должен  сделать замечание,
касающееся ALASM'а. Дело в том, что в этом
ассемблере отсутствует функция DISPLAY (не
понимаю,  почему KVA/E-Mage ее не сделал),
а  эта  функция  используется в библиотеке
для  выдачи  предупреждений о переполнении
памяти  при  компиляции. Поэтому есть одно
различие в работе этой библиотеки в TASM'е
и в ALASM'е: в ALASM'е макрос DISPLAY_INFO
просто   создает   переменные,  содержащие
статистическую  информацию о распределении
памяти в программе, тогда как в TASM'е он,
кроме  того, выводит ее на экран, а также,
при необходимости, выдает предупреждения о
перерасходе  памяти.  Но  это единственное
различие в работе этих версий библиотек, в
остальном их работа идентична.
 А теперь непосредственно описания.

         2. Распределение памяти

 Это,  несомненно, самая важная часть этой
библиотеки.  Можно  даже  сказать, что все
остальное  -  не  более чем довесок к этой
основной  функции,  для которой библиотека
разрабатывалась изначально.
 Если вы читали в Scenergy#1 мою статью "О
пользе макросов", то вы наверняка помните,
что  я  уже  упоминал  в ней о возможности
использования  макросов для решения задачи
распределения  памяти  в  программе. Более
того  -  в приложении, в архиве MusSync.Z,
можно было найти файл MEMORY.A который, по
сути, являлся первой версией библиотеки. К
сожалению,  та версия была строго заточена
под одну-единственную модель распределения
памяти  и  не  могла быть использована как
универсальная  библиотека.  Более  того, в
ней,  как оказалось, есть баг, о котором я
узнал буквально сегодня, после почти 2 лет
ее использования :)
 Итак, что же позволяет эта библиотека?
 1) Она позволит вам выделять блоки памяти
в вашей программе. При этом можно выделить
неограниченное  количество блоков. Размеры
блоков  также  ничем  не ограничены. Кроме
того, можно выделять блоки с выравниванием
адреса  по  границе  #100 байт (так, чтобы
адрес  выделенного  блока  имел адрес вида
#xx00, где #xx - любое число).
 2) Она  имеет  два  режима  работы: можно
рассматривать  всю  доступную  память  как
один  большой  кусок  или  разделить ее на
медленную  (SLOW)  и быструю (FAST). Кроме
того,  отдельным   блоком  рассматривается
впечатанная в основную память страница.
 3) Можно выделять память обычным способом
(от  младших  адресов  к  старшим)  или по
принципу стека (от старших к младшим).
 4) Местоположение и размеры  любого куска
памяти  в  котором будет выделяться память
можно  настроить.  Способ выделения памяти
(см. п.3) также настраивается  для каждого
блока.
 5) После компиляции  программы все данные
о  статистике  выделения памяти могут быть
получены  из  специальных  переменных. Для
TASM'овской  версии  библиотеки эти данные
также выводятся непосредственно на экран.
 6) В TASM'овской версии  библиотеки также
реализован  контроль за выделением памяти.
В  случае  если  выделенные  блоки  памяти
"залезают"  на  код  или данные - выдается
соответствующее предупреждение. Кроме того
можно  контролировать "залезание" кода или
данных в страничную память.
 К  сожалению, последний  пункт реализован
только в TASM'е т.к. ALASM не поддерживает
функцию  DISPLAY.   Поэтому  пользователям
ALASM'а  придется  вручную  контролировать
переполнение при выделении памяти. Ну, или
доделать в ALASM'е эту функцию :)

 А теперь подробнее обо всех перечисленных
выше функциях.

     2.1 Макросы для выделения памяти

 Как  уже  было  сказано - есть два режима
работы  библиотеки  в зависимости от того,
какая схема распределения памяти вам нужна
в вашей программе:
 - Вся  память  одним большим куском. Этот
   режим  подходит,  если,  например, ваша
   программа располагается с адреса #6000,
   а  память  выше  нее нужно использовать
   для выделения блоков памяти.
 - Память  разделена  на SLOW и FAST. Этот
   режим  подходит,  если  ваша  программа
   пишется  с учетом наличия компьютеров с
   "медленной"  памятью. В этом случае код
   обычно  располагается  с  адреса #8000,
   область #6000-#7FFF рассматривается как
   "медленная"  память  и используется под
   хранение  таблиц, а вся память до #C000
   считается  "быстрой" и используется под
   создаваемые процедуры.
 Замечу,  что  в  обоих режимах страничная
память  (#C000-#F)  рассматривается как
отдельный  блок  UPPER  memory. Обычно это
бывает  необходимо  т.к.  программы сейчас
обычно  пишутся  под  128кб памяти и нужно
рассматривать  страничную память отдельно.
Однако,  если  ваша  программа  не требует
переключения  страниц  -  этот блок  можно
объединить с каким-нибудь другим.
 Но  вернемся к режимам работы библиотеки.
Режим работы задается значением переменной
USE_COMMON_MEMORY. Она может принимать два
значения: YES и NO.
 Если USE_COMMON_MEMORY=YES, то библиотека
будет  работать  в  первом режиме (с общим
блоком  памяти),  если NO, то память будет
разделена на SLOW и FAST.
 По умолчанию USE_COMMON_MEMORY=NO.

 Как  можно  заметить из всего написанного
выше - всего, во всех  режимах, существует
4 блока, в которых можно выделять память:
 - Общая (COMMON)
 - "Медленная" (SLOW)
 - "Быстрая" (FAST)
 - Страничная (UPPER)
 Кроме  того, как уже было сказано - можно
также   выделять  память  с  выравниванием
адреса  по границе #100 байт. Т.е. всего в
библиотеке существуют 8 макросов. Их имена
составлены по схеме:
 GET_x_MEMORY - для выделения памяти.
 GET_x_MEM_XX00 - для  выделения памяти
    с выравниванием адреса по границе #100
    байт (маска адреса - #xx00).
 Здесь "x"  -  любой из идентификаторов
блока  памяти (COMMON, SLOW, FAST, UPPER).
Единственное  исключение  -  идентификатор
COMMON пропускается. Т.е. заданы следующие
имена макросов:
     Для выделения памяти           Для выделения памяти с
                                     выравниванием адреса
     GET_MEMORY                     GET_MEM_XX00
     GET_SLOW_MEMORY                GET_SLOW_MEM_XX00
     GET_FAST_MEMORY                GET_FAST_MEM_XX00
     GET_UPPER_MEMORY               GET_UPPER_MEM_XX00

 Однако  их  работа  зависит от выбранного
режима работы библиотеки:
 Если   USE_COMMON_MEMORY=NO,  то  макросы
GET_MEMORY и GET_MEM_XX00 ничего не делают
т.к.  блок  памяти  для  них в этом режиме
просто не существует. В TASM'овской версии
библиотеки  при попытке использования этих
макросов  в данном режиме  будет выдано на
экран предупреждение. В ALASM'вской версии
кодеру   самому   придется  контролировать
правильность  задания режима работы т.к. в
противном  случае  память  просто не будет
выделяться и программа, естественно, будет
неработоспособной.
 Если USE_COMMON_MEMORY=YES, то все вызовы
макросов  для  SLOW  и  FAST  блоков будут
переадресованы  к COMMON блоку. Т.о. можно
выделять память через вызовы GET_SLOW_x
и GET_FAST_x и не заботиться о том, что
в  случае  чего придется переписывать код.
Именно так написана библиотека ZXA library
и поэтому ее можно спокойно использовать в
обоих  режимах  работы библиотеки - память
все равно будет выделена правильно.

 Общий формат вызова макросов:
GET_x_MEMORY   <Variable>,<Memory size>
GET_x_MEM_XX00 <Variable>,<Memory size>

 Здесь <Variable> - метка  для выделяемого
блока памяти, <Memory size> - размер блока
в  байтах.  Метка создается автоматически,
так  что создавать ее вручную через EQU не
нужно.  Для  задания  <Memory  size> можно
использовать любое выражение в стандартном
синтаксисе ассемблера.

 2.2 Макросы для конфигурирования памяти

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

SET_MEMORY - для COMMON memory
SET_SLOW   - для SLOW memory
SET_FAST   - для FAST memory
SET_UPPER  - для UPPER memory

 Общий формат вызова макросов:
SET_x <Low bound>,<High bound>,<YES/NO>

 Здесь <Low bound> - адрес  нижней границы
области памяти, которая будет использована
для выделения памяти, <High bound> - адрес
верхней  границы области памяти. Последний
параметр  определяет, как будет выделяться
память:
 YES - память будет выделяться по принципу
стека - от старших адресов к младшим.
 NO  - память будет  выделяться от младших
адресов к старшим.
 Необходимо  заметить,  что в <High bound>
реально  задается  адрес байта, следующего
непосредственно   за   выделенным   блоком
памяти. Т.е. например вызов:
        SET_MEMORY #6000,#8000,YES
 выделит блок памяти в адресах #6000-#7FFF
с распределением памяти по принципу стека.
 За счет использования параметра задающего
принцип  распределения  памяти  вы сможете
еще  гибче  настроить  схему распределения
памяти  в ваших программах. Например, если
блок  памяти  для  выделения располагается
непосредственно  за кодом вашей программы,
то  вам  явно  будет  удобно, чтобы память
распределялась, двигаясь "навстречу" коду,
т.е.  по  принципу стека. А вот нижнюю или
страничную  память удобнее иметь с обычной
схемой распределения.

 Да,  еще необходимо рассказать о том, как
сконфигурирована  память  по  умолчанию, и
как ее можно поменять.
 Конфигурация памяти по умолчанию выглядит
следующим образом:
      ┌─┬─┬─┬─┐
      │ Тип блока памяти │ Начало │ Конец │ Схема работы │
      ├─┼─┼─┼─┤
      │ Common Memory    │ #6000  │ #C000 │   Stack      │
      │ Slow Memory      │ #6000  │ #8000 │   Normal     │
      │ Fast Memory      │ #8000  │ #C000 │   Stack      │
      │ Upper Memory     │ #C000  │ #0 │   Normal     │
      └─┴─┴─┴─┘

 Посмотрев  исходный  код  библиотеки,  вы
увидите,  что  эти данные заданы в метках,
чьи названия составлены по принципу:
<Название блока>_LOW
<Название блока>_HIGH
<Название блока>_STACK
 Так что если вы в своих программах обычно
используете  другую  конфигурацию памяти -
ее  лучше  всего  настроить  прямо  в коде
библиотеки,  чем  каждый  раз использовать
макросы настройки памяти.
 Есть  только  один  нюанс:  при изменении
заданной  по умолчанию конфигурации памяти
вам   придется   также  переписать  макрос
DISPLAY_INFO  т.к.  он  написан  с  учетом
именно той конфигурации, которая задана. В
противном  случае  я не гарантирую, что он
будет работать правильно.

  2.3 Контроль за распределением памяти.

 Механизм  распределения  памяти был бы не
совсем  удобен в использовании, если бы не
было   также  механизма  для  контроля  за
распределением памяти. В Memory Management
Library  за  этот контроль отвечает макрос
DISPLAY_INFO.  С  его  помощью  вы сможете
получить следующую информацию:
 - Размер кода программы.
 - Объем подгружаемых данных.
 - Общий размер программы.
 - Объемы  оставшейся  свободной  памяти в
   каждом блоке памяти.
 - (*) Сообщения о перерасходе  памяти при
   выделении.
 - (*) Сообщение  о "залезании" выделенной
   памяти на код или подгружаемые данные.
 - (*) Сообщение  о  "залезании"  кода или
   подгружаемых данных на страницу.
 Последние 3 пункта, помеченные знаком (*)
работают только в TASM'овской версии. Это,
как я уже говорил, объясняется отсутствием
в ALASM'е функции DISPLAY.
 Кроме  того,  этот макрос может также сам
заносить  в STS адрес запуска программы, с
тем,  чтобы  при выходе в STS вам не нужно
было  вручную устанавливать адрес запуска,
перед тем как начать отладку программы.
 Как видите, этот макрос является довольно
полезным. Однако его использование требует
выполнения  нескольких  простых  правил  с
тем, чтобы макрос мог получить необходимую
для него информацию.
 Я  приведу  схему  программы,  какой  она
должна  быть  для  того, чтобы этот макрос
работал  правильно.  Необходимые  для  его
работы  строчки  выделены желтым цветом. Я
использую синтаксис TASM'а, но для ALASM'а
все аналогично.

        .INCLUDE MEMORY
START_ADR=#8000  ;Адрес компиляции и запуска программы

        ORG START_ADR
        ;Здесь располагается код программы
END_OF_CODE=$
        ;Здесь располагаются подгружаемые данные
END_OF_DATA=$

        DISPLAY_INFO

 Как видите - для работы макроса требуется
задание 3 переменных:
START_ADR   - Адрес  компиляции  и запуска
              программы.
END_OF_CODE - Конец  кодового  блока вашей
              программы.  Начиная  с этого
              места располагаются данные.
END_OF_DATA - Конец блока данных.
 Кроме  того,  программа  должна выполнять
еще 2 условия:
 - Адрес  компиляции программы должен быть
равен   адресу  запуска.  Для  большинства
программ это так и есть.
 - Блок  подгружаемых  данных  должен быть
расположен   непосредственно   за  кодовым
блоком программы. Это тоже справедливо для
большинства программ.
 Необходимо  пояснить,  что я подразумеваю
под термином "подгружаемые данные". Это те
данные, которые, как правило, подгружаются
к  программе  по  .INCBIN, а после запуска
программы  перекидываются  LDIR'ом на свое
место  в  памяти. Например, обычно музыка,
спрайты или таблицы располагаются где-то в
памяти  (или  в  страницах),  но их обычно
линкуют  вместе  с кодом, чтобы образовать
один  моноблок,  а затем, после запуска их
перебрасывают  на то место, где они должны
располагаться.  Вот  этот  блок данных я и
называю "подгружаемые данные". Важность их
в  том, что они существуют только на этапе
запуска  программы, а затем эту память уже
можно использовать подо что-то другое. Эта
специфика позволяет библиотеке, во-первых,
использовать эту память для распределения,
а  во-вторых,  отдельно контролировать то,
что выделенная память "залезает" на данные
и  предотвращать возможные конфликты из-за
использования  одного  и  того  же участка
памяти.
 Проще  говоря, считается, что блок памяти
от START_ADR до END_OF_CODE трогать нельзя
а блок от END_OF_CODE до END_OF_DATA можно
использовать  для распределения памяти, но
в случае, если выделенная память "залезет"
в этот блок - нужно выдать предупреждение.
 Есть, правда во всем этом одно "НО". Дело
в том, что существует определенная разница
в  работе  макроса DISPLAY_INFO в случаях,
когда  программа  использует  заданную  по
умолчанию  схему  распределения памяти или
же  создает  свою. Библиотека контролирует
изменения  конфигурации памяти и запрещает
некоторые функции макроса DISPLAY_INFO.
 В  случае использования собственной схемы
распределения  памяти  будут отсутствовать
следующие функции:
 - автоматическая  подгонка  размера блока
Fast  Memory,  с тем, чтобы он занимал всю
память от последнего байта кода до #C000.
 - контроль за "залезанием" блоков памяти,
выделенных  в  Fast Memory на подгружаемые
данные.

 Помимо  своей основной функции - контроля
за  переполнением памяти, DISPLAY_INFO еще
имеет ряд дополнительных функций.

 1) Он может помочь в случае, когда вы уже
написали  и  отладили  программу  и хотите
сохранить на диске ее код. В ALASM'е такая
функция   отсутствует,   а  в  TASM'е  она
работает  только  при  наличии в программе
только  одного  ORG'а,  поэтому обычно код
сохраняется из STS. А для этого необходимо
знать  2 вещи: стартовый адрес блока кодов
и  размер  этого блока. Вот здесь-то вам и
пригодится макрос DISPLAY_INFO.
 В  Memory  Management  Library определена
метка FINAL_RELEASE. Обычно я использую ее
в  своих программах для того, чтобы убрать
отладочный  код  при компиляции финального
релиза  программы.  Т.е.  отладочный код в
программе пишется так:

.IF FINAL_RELEASE-NO
        ;Здесь кусок отладочного кода
.ENDIF

 А в самом начале программы (обычно в main
file)  помещается следующая конструкция (в
синтаксисе TASM'а):

.IF [#5C08]-#0E
FINAL_RELEASE=YES
.ENDIF

 Обычно  при  компиляции отладочной версии
эта метка не переопределяется (ее значение
по умолчанию равно NO), а когда необходимо
откомпилировать  финальный  вариант  кода,
при  компиляции  просто нажимается клавиша
EXT.MODE - и  без редактирования исходника
я получаю программу без отладочного кода.
 Так  вот,  кроме  этой метки в библиотеке
также   определены   метки  SAVE_START   и
SAVE_END.  Если  использовать их следующим
образом:

SAVE_START=$
        ;Здесь блок кода, который должен быть
        ;выгружен на диск.
SAVE_END=$

 то при компиляции финального релиза вашей
программы,  кроме  всей прочей информации,
будут  выведены  на экран (для TASM'а) или
просто определены (для ALASM'а) метки:
SAVE_START - адрес блока для записи.
SAVE_SIZE_ - размер этого блока.
 Выйдя в STS, вы сможете спокойно записать
необходимый вам блок кода на диск.
 Кстати,  по  умолчанию (если эти метки не
переопределять)  они  будут  автоматически
установлены в следующие значения:
SAVE_START=START_ADR
SAVE_SIZE_=END_OF_DATA
 Так что в большинстве случаев вы получите
данные ни о чем не заботясь.

 2) Макрос  DISPLAY_INFO  может  "патчить"
STS с тем, чтобы при выходе в нее адрес PC
был равен адресу запуска программы.
 Для  использования этой функции задайте в
переменной  STS_BANK номер страницы, где у
вас лежит STS, например STS_BANK=#17. Если
же  эта  функция вам не нужна - не делайте
ничего,  по  умолчанию  никаких  патчей не
производится.

 3) Эта функция  есть только в TASM'овской
версии библиотеки.
 Обычно программы, использующие страничную
память,  должны  располагаться ниже #C000,
чтобы  не было глюков в случае, если будет
включена  не та страница. То же касается и
подгружаемых данных - если они "залезут" в
страничную  память,  то их будет не так-то
просто  перекинуть  в другую страницу. Все
эти вещи автоматически отслеживаются кодом
библиотеки  и  в  случае  если  что-то все
же  "залезло"  на  страницу - будет выдано
соответствующее  предупреждение.  Если  же
ваша программа, по каким-либо причинам, не
требует  подобных  проверок - можно просто
установить переменную CODE_ON_PAGES=YES, и
эти проверки будут отключены.
 Пользователи  ALASM'а  такой  возможности
лишены опять-таки из-за отсутствия в ALASM
функции DISPLAY.
 И еще одно. Как правило для блока памяти,
расположенного,  непосредственно  за кодом
программы, нельзя сказать заранее - какими
будут  его  границы т.к. размер блока кода
заранее  неизвестен. Здесь вам поможет тот
факт,   что  непосредственно  контроль  за
переполнением  памяти  при выделении будет
осуществляться  только  при вызове макроса
DISPLAY_INFO,  т.е. в самом конце. Поэтому
для  блока, расположенного непосредственно
за  кодом  программы  лучше  всего  задать
четко  только  верхнюю  границу,  а нижнюю
можно задать как угодно. Кроме того, нужно
задать для этого блока схему распределения
памяти  по  принципу  стека  (чтобы  код и
выделенная память двигались навстречу друг
другу).  Выделив все необходимые блоки как
обычно,  в  самом конце программы добавьте
одну-единственную строчку (на примере FAST
блока):
FAST_LOW=END_OF_CODE
 Т.о. вы точно установите размеры блока на
всю имеющуюся память. Также можно делать и
с  любым  другим  блоком памяти - контроль
переполнения памяти будет работать верно.

        2.4 Примеры использования

 Приведу парочку примеров выделения памяти
в  блоках с normal и stack схемами работы.
Напомню,  что  блок  Slow располагается по
адресам  #6000-#8000  и  работает с normal
схемой,  а блок Fast расположен по адресам
#8000-#C000  и выделяет память по принципу
стека.

GET_SLOW_MEMORY   TABLE_1,#A0
GET_SLOW_MEMORY   TABLE_2,#120
GET_SLOW_MEM_XX00 TABLE_3,#200

 При  стандартной  конфигурации памяти эти
вызовы приведут к следующим результатам:
TABLE_1 EQU #6000
TABLE_2 EQU #60A0
TABLE_3 EQU #6200  ;А не #61C0!!!

 Аналогичные  выделения  памяти  для  FAST
memory:
GET_FAST_MEMORY   TABLE_1,#A0
GET_FAST_MEMORY   TABLE_2,#120
GET_FAST_MEM_XX00 TABLE_3,#200
 Дадут следующие результаты:
TABLE_1 EQU #BF60
TABLE_2 EQU #BE40
TABLE_3 EQU #BC00  ;А не #BC40!!!

 Надеюсь что все здесь просто и понятно.

        3. Расчет экранных адресов

 Макросы, относящиеся к этой группе должны
облегчить кодеру решение задачи, с которой
он сталкивается практически в каждой своей
программе.  Я  говорю  о  расчете экранных
адресов.  Ни для кого не секрет, что из-за
достаточно "оригинальной" структуры экрана
Speccy  задача расчета экранного адреса по
координатам является отнюдь не тривиальной
и  не  каждый  кодер может быстро провести
этот  пересчет в уме. Задавать же экранные
адреса  в программах приходится достаточно
часто,  причем  в разных вариантах - как в
виде таблицы, так и в виде EQU.
 На  все  эти  случаи  в Memory Management
Library  есть свои макросы. Все они делают
одно и то же, разница заключается только в
том, куда помещается результат.

 Имена  макросов  составлены по следующему
принципу:
_x_SCRADR  - расчет экранных адресов
_x_ATTRADR - расчет адресов в атрибутах
 Здесь x может  иметь 2 значения: GET и
DEFW.  В  зависимости  от этого изменяется
набор параметров для макроса:
_GET_SCRADR  <Метка>,<X коорд.>,<Y коорд.>
_DEFW_SCRADR <X координата>,<Y координата>
 При этом после вызова макроса _GET_SCRADR
метке, переданной  в  качестве  параметра,
будет присвоено значение экранного адреса.
При  вызове  макроса _DEFW_SCRADR экранный
адрес  будет  помещен в память по текущему
адресу  компиляции. Формат вызова макросов
для расчета адреса в атрибутах аналогичен.
 Значения X и Y координат зависят от того,
что  рассчитывается: адрес на экране или в
атрибутах.  Для расчета экранного адреса X
задается  в знакоместах, а Y - в пикселях.
Для  расчета  адреса  в  атрибутах и X и Y
задаются в знакоместах.
 Использование макросов предельно простое:
_GET_SCRADR SCREEN_ADR,5,9  ;Результат: SCREEN_ADR=#4125
_GET_ATTRADR ATTR_ADR,5,9   ;Результат: ATTR_ADR=#5925
 Или  пример  составления таблицы экранных
адресов:
        _DEFW_SCRADR 0,0
        _DEFW_SCRADR 0,1
        _DEFW_SCRADR 0,2
        ...
        _DEFW_SCRADR 0,191

 Кроме того, есть еще один набор макросов,
выполняющий  те  же  самые функции, но для
экрана,  расположенного с адреса #C000. Их
имена составлены по тому же принципу, но с
добавлением в конец буквы 'H' (от High):
_GET_SCRADRH
_GET_ATTRADRH
_DEFW_SCRADRH
_DEFW_ATTRADRH
 Первоначально  в  TASM'овской версии этих
макросов не было. Можно было просто задать
дополнительный параметр при вызове макроса
для  расчета адреса для нижнего экрана - и
расчет бы производился для экрана с адреса
#C000. Например:
_DEFW_SCRADR 10,8    ;Значение #402A
_DEFW_SCRADR 10,8,1  ;Значение #C02A
 Это  намного  удобнее, но, к сожалению, в
отличие  от  TASM'а, ALASM не поддерживает
макросов  с  переменным  числом параметров
(хотя KVA/E-Mage и говорил, что сделал все
"один  в  один как в TASM'е"). Поэтому, из
соображений совместимости, пришлось делать
еще 4 макроса.

      4. Создание таблиц указателей
            и структур данных

 Эта  группа  макросов  предназначена  для
решения  двух  типов задач перечисленных в
заголовке.  Действительно,  практически  в
каждой программе найдется несколько таблиц
указателей  или структур данных. Обычно их
задают  в  виде кучи чисел, которые затем,
обычно,  затруднительно  исправлять.  Этот
набор  макросов  поможет  вам справиться с
этим наилучшим способом.
 Всего в этом разделе находится 3 макроса,
различающихся  только  тем, куда и в каком
виде помещается результат:
_SZ <Метка>,<Размер>
_SZ_DEFB <Размер>
_SZ_DEFW <Размер>
 Понятно, что макрос _SZ присваивает новое
значение   метке,  а  макросы  _SZ_DEFB  и
_SZ_DEFW  помещают в память соответственно
байт и слово.
 Все  эти  макросы  используют  для  своей
работы  одну  и ту же переменную (___ORG),
которая   является   указателем   текущего
значения.   Поэтому   перед  каждым  новым
использованием  любого  из  макросов  этой
группы   вам   необходимо   будет   заново
инициализировать   эту   переменную  новым
текущим   значением.  И,  естественно,  во
избежание  недоразумений, нельзя смешивать
вызовы  разных  макросов  этой  группы без
переинициализации этой переменной.
 Попытаюсь  вам продемонстрировать, как же
использовать  эти  макросы. Я приведу пару
примеров дающих одинаковый результат: один
вариант в стандартном синтаксисе, а другой
с использованием этих макросов.


 Пример 1.  Создание таблицы указателей на
спрайты.  SPRITES  -  указатель  на  набор
спрайтов, SPR_SZ - размер одного спрайта.
Стандартный синтаксис:
SPRITES_TABLE
        DEFW SPRITES+(0*SPR_SZ)
        DEFW SPRITES+(1*SPR_SZ)
        ...
        DEFW SPRITES+(2*SPR_SZ)
С использованием макросов:
___ORG=SPRITES
SPRITES_TABLE
        _SZ_DEFW SPR_SZ
        _SZ_DEFW SPR_SZ
        ...
        _SZ_DEFW SPR_SZ
 Заметьте,  насколько удобнее будет потом,
при  необходимости,  менять  что-то в этой
таблице,  вставлять  или  убирать  из  нее
элементы.
Пример 2. Задание EQUS для полей структуры
данных.
Пусть структура данных имеет такой вид:
STRUCTURE
        DEFB 0      ;BYTE_FIELD_1
        DEFB 0      ;BYTE_FIELD_2
        DEFW 0      ;WORD_FIELD_1
        DEFB 0      ;BYTE_FIELD_3
        DEFS 10,0   ;TABLE_FIELD_1
        DEFS 25,0   ;TABLE_FIELD_2
        DEFW 0      ;WORD_FIELD_2
 Задание  EQUS  для  полей  этой структуры
данных в стандартном синтаксисе:
BYTE_FIELD_1  EQU 0
BYTE_FIELD_2  EQU BYTE_FIELD_1+1
WORD_FIELD_1  EQU BYTE_FIELD_2+1
BYTE_FIELD_3  EQU WORD_FIELD_1+2
TABLE_FIELD_1 EQU BYTE_FIELD_3+1
TABLE_FIELD_2 EQU TABLE_FIELD_1+10
WORD_FIELD_2  EQU TABLE_FIELD_2+25
 Заметьте, насколько неудобно будет что-то
изменять в этой структуре данных, особенно
если что-то надо будет добавить в середину
или удалить.
 А теперь то же самое, но с использованием
макросов:
___ORG=0
_SZ BYTE_FIELD_1 ,1
_SZ BYTE_FIELD_2 ,1
_SZ WORD_FIELD_1 ,2
_SZ BYTE_FIELD_3 ,1
_SZ TABLE_FIELD_1,10
_SZ TABLE_FIELD_2,25
_SZ WORD_FIELD_2 ,2
 Сравните  наглядность и удобство задания!
А  уж  про  удобство  редактирования можно
просто умолчать :)

 Думаю,  что  приведенные  примеры говорят
сами за себя.
              5. Заключение

 Вот,  собственно, и все. Смешно, конечно,
что описание библиотечки с объемом порядка
400 строчек ассемблера занимает почти 30кб
текста,  но  это говорит только о том, что
возможности  этой  библиотеки, несмотря на
малый  объем, действительно велики (ну или
о  том, что я не умею кратко излагать свои
мысли :) ).
 Я  очень  надеюсь,  что данная библиотека
поможет  вам  в работе. Конечно, с первого
взгляда,   она   может  показаться  чем-то
непривычным,  но  поверьте  мне  -  она на
самом деле очень сильно облегчает работу!

 Happy coding!



Другие статьи номера:

A.O.S.S. - "Сцена больна" переживания Random'a.

A.O.S.S. - Raver рассуждает о сценовой журналистике.

A.O.S.S. - аналитическая статья о музыкальной сцене от Andy Fer.

A.O.S.S. - легко ли быть органайзером группы?

A.O.S.S. - О журналах (мысли вслух).

A.O.S.S. - о канонах демосцены на примере журнала Deja Vu #9.

A.O.S.S. - Сегодня и Завтра отечественной демосцены.

A.O.S.S. - спектрумовская банерная сеть.

Charts - all time favorites.

Charts - current rules (fall edition 1999).

Charts - indexed.

Charts - voting rules.

Coding - 16-битная процедура быстрого возведения в степень.

Coding - Flying представляет макробиблиотеку: Memory Management Library.

Coding - Texture Mapping - реализация от SaiR00S/EI.

Coding - Texture mapping + Phong shading реализация от Senat/Eternity Industry.

Coding - ZXA library: библиотека, предназначенная для создания и проигрывания анимаций.

Coding - Баг в STS?

Coding - Комментарии к исходникам, опубликованным в Scenergy #1

Coding - о библиотеках в программировании на спектруме.

Coding - Принцип упаковки анимаций в демо JAM.

Coding - процедура быстрого умножения.

Coding - разбор интро Daingy от Cryss/Razzlers.

Demo Party - Cafe'2000: Официальное приглашение

Demo Party - CC999.999 information (eng).

Demo Party - D-Man/EI: отчет о Di:Halt:99.

Demo Party - Hartman: отчет о CC'999.

Demo Party - Maxwell и Mr. John: отчет о CC'999.

Demo Party - Merlin/CC: отчет о CC'999.

Demo Party - Paradox'99 - как это было, но лучше б он mUst dIe!!!

Demo Party - PHAT'9: список посетителей.

Demo Party - POL/PHT: отчет о Doxycon '99.

Demo Party - Random/CC: обьемный отчет о CC'999.

Demo Party - SerzhSoft: сказание о CC'999.

Demo Party - Zlincon 2e3 party: минирепортаж.

Demo Party - информация о предстоящем пати PHAT'0.

Demo Party - информация по демопарти CC999.999.

Demo Party - неофициальные результаты Di:Halt'99 с коментариями Diver'a.

Demo Party - обзор демосцены за 1999 год.

Demo Party - отчет организаторов CAFe'99.

Demo Party - пресс релиз Латвийского демопати PHAT'9.

Demo Party - приглашение на латвийское демопати PHAT'9.

Demo Party - рассказ о поездке Antares в Казань на CAFe'99

Demo Party - результаты CC.999.999

Demo Party - результаты CC999.999.

Demo Party - результаты Chaos Construction 999.

Demo Party - результаты Computer Art Festival 1999.

Demo Party - результаты Doxycon'99.

Demo Party - результаты Millenium Party.

Demo Party - результаты Paradox'2k demoparty.

Demo Party - результаты Латвийского демопати PHAT'9.

Demo Party - результаты Ростовского пати Paradox'99.

Demo Party - репортаж Gasman'a с Forever 2e3.

Demo Party - репортаж с Минского демопати Millennium'2000.

Demo Party - финальные результаты Forever 2E3.

Editorial - вступительное слово от Arty.

Editorial - выступительное слово от Random.

Editorial - загоны Raver'а на тему Сцены.

Groups - анкеты действующих групп: Amaltiya Incoropration Software.

Groups - анкеты действующих групп: Antares.

Groups - анкеты действующих групп: Ascendancy Creative Labs.

Groups - анкеты действующих групп: Crushers.

Groups - анкеты действующих групп: E-mage.

Groups - анкеты действующих групп: Eternity Industry.

Groups - анкеты действующих групп: Excess team.

Groups - анкеты действующих групп: Extreme Entertainment.

Groups - анкеты действующих групп: Fatality.

Groups - анкеты действующих групп: Jupiter 77.

Groups - анкеты действующих групп: Proxima Centauri.

Groups - анкеты действующих групп: RaZZLeRs.

Groups - анкеты действующих групп: RUSH.

Groups - анкеты действующих групп: Smash Hackers Band.

Illegal Corner - Razzlers оправдываются за релиз демки First Association.

Illegal Corner - Scenergy Release Charts - конкурс крэков.

Illegal Corner - Welcome to Scenergy Release Charts (SRC).

Illegal Corner - софтография Fatality Group.

Lits - Pussy: история создания знаменитой игры от Fatality.

Lits - Scenergized beyond the belief.

Lits - speed.

Lits - история образования Ростовской ассоциации PartyZans.

Lits - история создания игры "Белый орел - товарищ известен".

Lits - рассказ о том как Fatality выпускает игрушки.

Mail Box - письма: Ellvis и Fatality довольны Scenergy #1, Ulterior поносит Antares и BrainWave, Realtimer разочарован.

News - Doom'a не будет!

News - Виртуальное пати Millennium, X-Raizor вернулся на сцену, Andrew Fer организовал новую группу, провал Германского пати Spectrology, новости от 3SC, Zero Team, Extreme.

News - мнение Megus'a о dentro compo СС'2000.

News - новости от OHG, Delta Hackers Group, Die Crupps, Волгодонских спектрумисто и от группы SpeedWay.

Scenergy - адреса для связи с редакцией.

Scenergy - благодарности соавторам журнала.

Scenergy - новое в облочке журнала.

Scenergy - обещанного видео в статьях не будет...

V.I.P. - Random берет интервью у Unbel!ever/Sage/XTM.

V.I.P. - The most noble tale of the scene.

V.I.P. - интервью с Arny и Mythos, создателями клона Elite игры Awaken.

V.I.P. - Интервью с Fatality, широко известными крэкерами и гейм-мэйкерами

V.I.P. - интервью с одним из авторов игры Elite.

V.I.P. - интервью с одним из самых прогрессивных художников на спектруме Diver/4D.

V.I.P. - Интервью, взятое у Random'а каким-то PC-журналом

Warez Pack - описание Inertia Player.

Warez Pack - описание демо 1140.

Warez Pack - описание импортной демки 'no work'.


Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Marazm - Не пейте, если завтра утром вам ехать на экскурсию.
ASK FUDGE: HE'S ALWAYS HERE WITH A KINDLY EAR
Кодинг - совмещение визуальных эффектов с дигитальной музыкой.
Застрял ? - Новелла-проходилка "Приключения Винни Пуха" часть 2.
Доска почета - устав национального Фонда Спектрума (HФСП).

В этот день...   19 апреля