Иллюстрированный самоучитель по SVGA

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

Вычисление SwpSeg и GenSeg

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

В примере Б.3 приведен фрагмент начала программы, в котором выполняются все необходимые вычисления. Для описания сегментов в нем использованы обычные директивы (см. пример Б.1).

Пример Б.З. Вычисление значений переменных SwpSeg и GenSeg 1.

.Alpha порядок расположения сегментов
Dosseg порядок расположения сегментов
stack Segment word stac: "stack"; начало стекового сегмента
db 200h dup (?) размер области стека 200h байтов
stack Ends конец стекового сегмента
data Segment начало сегмента данных
prmpt db ODh,OAh, '! Для выполнения задачи не хватает памяти! $ '
freeseg dw 0 первый свободный сегмент
msize dw 0 размер памяти в параграфах
needm dw 2000h требуемый размер памяти
SwpOffs dw 0 смещение в буфере обмена
SwpSeg dw 0 сегмент буфера обмена
GenOffs dw 0 смещение в буфере
GenSeg dw 0 сегмент буфера общего назначения
; Далее описываются другие используемые данные
data Ends конец сегмента данных
code Segment начало кодового сегмента
.386 набор команд процессора
start: mov ax, data ах = код сегмента данных
mov ds, ax ds = код сегмента данных
mov bx, sp bx = размер стека в байтах
shr bx, 04 превращаем его в параграфы
mov ax, ss ах = код стекового сегмента
add bx, ax bx = последний параграф стека
inc bx bx = первый свободный сегмент
mov freeseg, bx ireeseg = DX
mov ax, es: [02] ax = последний доступный сегмент
sub ax, bx ax = ax – bx
mov msize, ax размер памяти в параграфах
cmp ax, needm памяти достаточно?
jae @F › да
lea dx, prmpt dx = адрес аварийного сообщения
mov ah, 09 ah = код функции DOS
int 21h вывод текста сообщения
mov ax, 4COOh ah = 4С, код функции DOS
int 21h завершение выполнения задачи
@@: mov SwpSeg, bx SwpSeg = bx
add bx, lOOOh bx = bx + 65536/16
mov GenSeg, bx GenSeg = bx
; Далее расположен текст основной программы и подпрограмм
code Ends конец кодового сегмента
END start конец текста программы

В начале примера Б.3 подряд расположены директивы .Alpha и Dosseg. При таком их сочетании стековый сегмент будет расположен в теле задачи последним, независимо от имен других сегментов (по крайней мере, так его располагает MASM 5.1).

Директива 0.386 определяет набор команд, которые можно использовать в программе. Если ее не указать, то по умолчанию будет выбран набор команд микропроцессора Intel 8086. В таком случае Макроассемблер обнаружит ошибку в записи команды shr bx, 04. Подробнее о назначении и месте расположения этой директивы сказано в приложении В.

После загрузки задачи DOS передает управление на метку start, для этого ее имя указано не только перед первой командой, но и после директивы END. Первые две команды записывают в регистр ds код сегмента данных, этот вопрос мы уже обсуждали. Шесть следующих команд вычисляют в регистре bx код первого свободного сегмента и сохраняют его в переменной freeseg. Затем в регистр ах считывается из 2-го слова PSP код последнего доступного для задачи сегмента, вычисляется размер свободной памяти в параграфах и сохраняется в переменной msize.

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

Если памяти достаточно, то в переменную SwpSeg копируется код первого доступного сегмента. Для буфера обмена отведено 65 536 байтов, что в параграфах составляет 1000h. Эта величина прибавляется к содержимому регистра bx, и результат записывается в GenSeg. Значения переменных swpoffs и GenOffs определяются в процессе выполнения задачи.

После выполнения команд примера Б.3 размер буфера обмена ограничен, поскольку после него расположен буфер общего назначения, поэтому при работе с swpSeg нельзя выходить за пределы 65 536 байтов. Во всех ранее приведенных примерах такое ограничение нас вполне устраивало. Размер буфера общего назначения пока ограничен величиной (msize -ioooh)*16 байтов. В зависимости от конкретных особенностей задачи это пространство может быть разделено на блоки меньшего размера или использовано как большой буфер общего назначения.

При работе с блоками большого размера задача должна контролировать текущий адрес ОЗУ и при достижении границы 65 536 байтов изменять код в сегментном регистре, который используется для доступа к блоку (увеличивать его содержимое на 1000h). Необходимость работы с блоками ОЗУ большого размера возникает, например, при сохранении и восстановлении содержимого всей рабочей области экрана.

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

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.