Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Архитектура ЭВМ и систем. Лабораторная работа. Учебное пособие
.pdf
Комментарии
При вызове регистр ES указывает на начало блока памяти, возвращаемого в системный пул. В процессе выполнения функции этот
блок памяти возвращается в системный пул. Код ошибки возвращается в регистре AX.
Функция 4AH, прерывание 21H: Изменить размер
выделенного ранее блока
Назначение
Освобождает указанный блок выделенной памяти.
При вызове Содержимое регистров
AH 4AH
ES Сегментная часть адреса блока
BX Новый размер блока памяти в параграфах
После
завершения
AX Код ошибки, если установлен флаг переноса
BX Размер наибольшего доступного блока памяти (в пара-
Содержимое регистров
графах), если изменение размера блока памяти не выполнено и установлен флаг переноса
Комментарии
ДОС пытается увеличить или уменьшить размер блока памяти.
Код ошибки возвращается в регистре AX.
Пример программы прямого доступа к памяти
Программа, листинг которой приведен ниже, выводит на экран
список всех блоков памяти, указывания для каждого имя и адрес
PSP программы-владельца, тип, адрес и размер в байтах. Результаты
ее работы
приведены на рисунке 2.
"Программа Тип Адрес Размер PSP $"
;строка таблицы
table_row label near
db 0DH, 0AH
81

prog_name db 10 dup(' ')
block_type db 4 dup(' ')
block_addr db 12 dup(' ')
block_size db 8 dup(' ')
psp_addr db 5 dup(' ')
tr_len = $-prog_name
db '$'
;длина строки таблицы
end_of_line db 0DH, 0AH, '$'
;буфер для размещения числа перед переводом его в
десятичный формат
number dw 0,0
;таблица перевода в шестнадцатеричный формат
xt db "01234567890ABCDEF"
dseg ends
cseg segment para use16
assume cs:cseg,ds:dseg,ss:sseg
start proc far
;сделаем данные адресуемыми
mov ax,dseg
mov ds,ax
;получим адрес списка списков DOS
mov ah,52H
int 21H
;es <- сегментный адрес первого MCB
mov es,es:[bx-2]
;выведем заголовок таблицы
mov ah,9
lea dx,table_header
int 21H
next_mcb:
;очистим буфер со строкой таблицы
call clear_row
;владелец -- система
?
cmp word ptr es:[1],8
je get_name
;блок свободен?
cmp word ptr es:[1],0
je get_info
82

;это программный сегмент(MCB должен
быть прямо перед PSP)?
mov ax,es
inc ax
cmp ax,es:[1]
je get_name
;найдем MCB перед программным
сегментом
push es
mov ax,es:[1]
dec ax
mov es,ax
;получим имя программы из MCB перед
ее программным сегментом
call get_prog_name
pop es
jmp short get_info
get_name:
;получим имя программы
call get_prog_name
get_info:
call get_mcb_info
;выведем очередную строку
mov ah,9
lea dx,table_row
int 21H
;это еще не последний блок?
cmp byte ptr es:[0],'M'
jne last_mcb
;перейдем к следующему MCB
mov ax,es
add ax,es:[3]
inc ax
mov es,ax
jmp next_mcb
last_mcb:
;переведем курсор на две строки
вниз
83

mov ah,9
lea dx,end_of_line
int 21H
int 21H
;выйдем из программы
mov ax,4C00H
int 21H
start endp
;помещаем в буфер строки
таблицы информацию по блоку
MCB, адрес
;которого находится в ES
get_mcb_info proc near
;скопируем тип блока
mov al,es:[0]
mov [block_type],al
;преобразуем адрес блока памяти
lea di,block_addr
;сегментный адрес у него на 1
больше, чем у MCB
mov dx,es
inc dx
call bin_to_hex
;поместим в буфер разделитель ':'
mov byte ptr [di],':'
inc di
;смещение нулевой -- граница
параграфа
xor dx,dx
call bin_to_hex
;
размер блока памяти задается в
параграфах,
;мы будем выводить его в байтах
xor eax,eax
mov ax,es:[3]
shl eax,4
lea di,psp_addr-2
84

call bin_to_dec
;преобразуем адрес PSP владель-
ца блока памяти
lea di,psp_addr
mov dx,es:[1]
call bin_to_hex
ret
get_mcb_info endp
;переводит число из eax в десятичный формат и
помещает в буфер,
;на конец которого указывает пара ds:di
bin_to_dec proc near
mov ecx,10
next__digit:
xor edx,edx
div ecx
or dl,30H
mov [di],dl
dec di
or eax,eax
jnz next__digit
ret
bin_to_dec endp
;переводит число из dx в шестнадцатеричный формат
и помещает
;в буфер по адресу ds:di
bin_to_hex proc near
lea bx,xt
mov cx,4
next_digit:
mov al,dh
shr al,4
shl dx,4
and al,0FH
xlatb
mov [di],al
inc di
loop next_digit
mov byte ptr [di],'H'
85

inc di
ret
bin_to_hex endp
;заполняет буфер для строки таблицы пробелами
clear_row proc near
push es
push ds
pop es
lea di,prog_name
mov cx,tr_len
mov al,' '
cld
rep stosb
pop es
ret
clear_row endp
;копирует имя программы в буфер строки таблицы
;из MCB, на который указывает ES
get_prog_name proc near
;смещение имени в MCB
mov di,8
;место для имени в буфере
lea si,prog_name
next_symbol:
;переместим очередной символ
mov al,es:[di]
mov [si],al
;увеличим индексы
inc si
inc di
;нулевой символ -- конец имени?
or al,al
jz finish
;максимальная длина имени -- 8
байт
cmp di,16
jne next_symbol
finish:
ret
86

get_prog_name endp
cseg ends
sseg segment para stack
dw 1024 dup(?)
sseg ends
end start
Программа Тип Адрес Размер PSP
SD M 0217H:0000H 9904 0008H
COMMAND M 0483H:0000H 2592 0483H
M 0526H:0000H 112 0000H
COMMAND M 052DH:0000H 1776 0483H
NC M 059DH:0000H 1792 078CH
KB16 M 060EH:0000H 6096 060EH
NC M 078CH:0000H 7152 078CH
COMMAND M 094CH:0000H 1808 09AEH
COMMAND M 09AEH:0000H 2592 09AEH
COMMAND M 0062H:0000H 1776 09AEH
MCB M 00C2H:0000H 1808 0A44H
MCB Z 0A44H:0000H 609200 0A44H
Рис. 2. Пример карты распределения оперативной памяти
Пример программы, работающей с оперативной памятью
посредством системных вызовов
Программа, листинг которой приведен ниже, рисует звездочка-
ми на экране зеленую ёлочку. Изображение формируется в буфере,
полученном у операционной системы. Затем оно копируется в видеопамять. Результат ее работы можно видеть на рисунке 3.
;
.486
LOCALS
;ширина и высота и цвет изображения
fir_width = 11
программа рисования ёлочки на экране
87

fir_height = 12
fir_color = 00001010B
dseg segment para use16
;количество звездочек на разных уровнях елочки
levels db 1,3,5,3,5,7,5,7,9,1,1,5
;сообщения об ошибках
err_ma db 0DH,0AH, «Ошибка выделения памя-
ти.», 0DH,0AH, "$"
err_msch db 0DH,0AH, «Ошибка изменения раз-
мера программного сегмента.»,
0DH,0AH, "$"
err_frm db 0DH,0AH, «Ошибка освобождения
памяти.», 0DH,0AH, "$"
dseg ends
cseg segment para use16
assume cs:cseg, ds:dseg, ss:sseg
start proc far
;сделаем сегмент данных адресуемым
mov ax,dseg
mov ds,ax
;определим, какой размер в параг-
рафах программа
;в действительности занимает в па-
мяти
;начало программного сегмента
mov bx,es
;отнимем адрес конца программы в
памяти
sub bx,last_seg
;получим положительное значение
neg bx
;уменьшим размер занимаемой опера-
тивной памяти
;до необходимого
mov ah,4AH
int 21H
jnc memsch_ok
;выведем сообщение об ошибке
mov ah,9
88

lea dx,err_msch
int 21H
memsch_ok:
;выделим буфер под изображение
;определим размер буфера в параг-
рафах
mov bx,fir_width*fir_height*2
add bx,000FH
shr bx,4
mov ah,48H
int 21H
jnc ma_ok
;выведем сообщение об ошибке
mov ah,9
lea dx,err_ma
int 21H
jmp finish
ma_ok:
;регистр es будет указывать
;на полученный буфер
mov es,ax
;сформируем изображение в буфере
xor si,si
mov ah,fir_color
xor di,di
xor ch,ch
cld
draw_level:
;вычислим, сколько на данном уровне
;пробелов слева и справа от ёлки
mov cl,fir_width
sub cl,levels[si]
shr cl,1
push cx
;фон слева
mov al,' '
draw_lb:
jcxz fir
stosw
89

dec cx
jmp draw_lb
fir:
;ёлка
mov al,'*'
mov cl,levels[si]
draw_fir:
jcxz rb
stosw
dec cx
jmp draw_fir
rb:
;фон слева
pop cx
mov al,' '
draw_rb:
jcxz next_level
stosw
dec cx
jmp draw_rb
next_level:
;перейдем к следующему уровню
inc si
;дошли до последнего?
cmp si,fir_height
jb draw_level
;выведем изображение на экран
push ds
push es
;ds <-буфер с изображением
push es
pop ds
;es <- видеобуфер
push 0B800H
pop es
xor si,si
mov di,(25-fir_height)/2*80*2
mov cx,fir_height
90
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
