Графические устройства



 

Использование функций DOS

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

Определение размера задачи

Будем предполагать, что стековый сегмент расположен в теле задачи последним. В таком случае нас интересует расстояние от начала PSP до конца стекового сегмента, выраженное в параграфах. Напомним, что код сегмента, содержащего PSP, находится в регистре es, код стекового сегмента — в ss, а если стек еще не использовался, то его размер в байтах содержится в регистре sp.

Размер тела задачи, выраженный в параграфах, вычисляется так:
tasksize = [ss] - [es] + [sp] /16

В этой формуле квадратные скобки указывают на то, что при вычислении используется содержимое регистров ss, es и sp. При. программировании деление [sp] на 16 заменяется сдвигом на 4 разряда вправо. Для того чтобы не потерять один параграф, размер стека должен быть кратен 16-ти, в противном случае его надо округлить в сторону увеличения.

Зная реальный размер задачи, можно запросить у DOS сокращение ее блока. В результате появится свободное пространство памяти, которое можно использовать по запросам задачи.

Функции DOS

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

Все обращения к DOS происходят через прерывание int 2ih, при этом код запрашиваемой функции указывается в регистре ah, а входные и выходные параметры располагаются в регистрах общего назначения и иногда в сегментных регистрах ds или es.

Функция 48h Allocate Memory выделяет запрашиваемое пространство памяти. Требуемый размер памяти, выраженный в параграфах, указывается в регистре bx. Если такое пространство существует, то при возврате из DOS признак переполнения отсутствует, содержимое bx не изменяется, а в ах находится код сегмента, с которого начинается выделенное пространство памяти. Если свободное пространство нужного размера отсутствует, то при возврате из DOS вырабатывается признак переполнения (устанавливается в 1 С-разряд регистра флагов).

Функция 49h Free Allocated Memory Block открепляет выделенный ранее для задачи блок памяти, после этого задача не может с ним работать. Код сегмента, начиная с которого расположен освобождаемый блок, помещается в регистр es, размер блока указывать не требуется, т. к. DOS хранит его в своей области данных. Если функция выполнена успешно, т. е. блок освобожден, то при возврате из DOS признак переполнения отсутствует. Если он установлен, то наиболее вероятно, что в регистре es был неверно указан сегмент блока.

Функция 4Ah shrink or Expand a Memory Block урезает или расширяет суще-ствующий блок памяти. Код сегмента, начиная с которого расположен изменяемый блок, указывается в регистре es, а новый размер блока — в регистре bx. Если функция выполнена успешно, т. е. размер указанного блока изменен, то при возврате из DOS признак переполнения отсутствует. Если он установлен, то блок не может быть расширен или сокращен. В этом случае в регистре bx возвращается наибольший (последний) доступный блок памяти.

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

В примере Б.4 показан фрагмент начала текста программы, в котором производится сокращение размера блока задачи и выделение двух блоков для размещения буферов обмена и общего назначения. Для описания основных сегментов в примере использованы специальные директивы (см. пример Б.2).

Пример Б.4. Получение от DOS значений переменных SwpSeg и GenSeg

dosseg задаем расположение сегментов
.model small выбор модели памяти
.stack 200h задаем стековый сегмент
.data начало сегмента данных
wpOffs dw 0 смещение в буфере обмена
wpSeg dw 0 сегмент буфера обмена
enOffs dw 0 смещение в буфере
enSeg dw 0 сегмент буфера общего назначения
Далее располагаются другие данные, используемые в задаче
.code начало кодового сегмента
.386 набор команд процессора
tart: mov ax, @data ax = код сегмента данных
mov ds, ax ds = ax
mov ax, ss ax = код стекового сегмента
mov bx, es bx = код сегмента, содержащего PSP
sub ах, bx ах = ах — bx
mov bx, sp bx = размер стека в байтах
shr bx, 04 превращаем его в параграфы
add bx, ax bx = bx + ах, размер задачи
mov ax, 4AOOh код запроса на сокращение бЛока
int 2 In DOS сокращает блок задачи
mov bx, lOOOh bx = размер блока в параграфах
mov ax, 480Ch код запроса на выделение блока
int 21h обращение к DOS
mov SwpSeg, ax SwpSeg = код сегмента блока
mov bx, lOOOh bx = размер блока в параграфах
mov ax, 4800h код запроса на выделение блока
int 21h обращение к DOS
mov GenSeg, ax GenSeg = код сегмента блока
; Далее следует продолжение текста программы
END start конец текста программы

ервые две команды примера Б.4 записывают в регистр ds код сегмента шных, который в этом случае имеет имя Sdata. Следующие 6 команд формируют в регистре bx значение tasksize, затем происходит вызов функции OS 4дь для сокращения размера блока задачи. При выполнении этой ункции неиспользуемая память возвращается DOS, и теперь ее можно запрашивать для размещения дополнительных блоков.

В примере Б.4 сначала запрашивается место для размещения буфера обмена, затем буфера общего назначения. В обоих случаях в регистре bx указывает на размер блока в параграфах (юооь), а в регистре ah — код функции 48h iiocate memory) и происходит обращение к DOS. После возврата из DOS код выделенного сегмента сохраняется в переменных SwpSeg или GenSeg. В отличие от примера Б.З размер буфера общего назначения в данном случае ограничен величиной 65 536 байтов.

В примере Б.З перед вычислением значений переменных SwpSeg и GenSeg производилась проверка достаточности объема памяти для выполнения задачи. В данном случае распределением памяти занимается DOS, поэтому указанная проверка выполняется иначе.

Контроль выполнения запросов

При описании функций говорилось, что при возврате из DOS состояние С-разряда указывает, успешно или неудачно завершилось выполнение запроса. Контролировать результат выполнения функции 4Ah не имеет смысла, лучше внимательно проверить запись команд, предшествующих обращению к DOS.

Результат исполнения функции 43h надо обязательно проверять. Признак переполнения (c=i) при возврате из DOS означает, что в памяти нет места для размещения блока нужного размера (если исключены ошибки в тексте программы). Что делать в таких случаях?

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

Освобождение блоков

Освободившийся блок возвращается DOS по запросу 49h (Free Allocated Memory Block), но с этим действием можно не спешить. В среде DOS задача, как правило, выполняется в монопольном режиме, и кроме нее претендентов на свободную память нет. Перед завершением выполнения задачи освобождать использованные блоки не обязательно. После завершения задачи DOS обязательно освобождает все пространство памяти, которое было за ней закреплено.

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

 
Назад Начало Вперед