
- •Лучший курс лекций по лучшему языку программирования – языку ассемблера Блок управления памятью (mcb)
- •Программирование на Ассемблере для ibm pc
- •Программная модель 8086
- •Программная модель мп
- •Сегментная память
- •Вывод на экран
- •Вывод строки символов
- •Вывод на экран шестнадцатеричного числа
- •Процедуры
- •Ввод символов
- •Вывод на экран двоичного числа
- •Работа с дисковыми файлами
- •Префикс сегмента программы (psp)
- •Структура префикса программного сегмента.
- •Прерывания.
- •Табличные вызовы подпрограмм.
- •Макрокоманды.
- •Макроопределения.
- •Использование параметров в макроопределениях.
- •Директива local
- •Использование библиотек макроопределений.
- •Конкатенация. (&)
- •Директивы повторения.
- •Условные директивы.
- •Перечисление условных директив.
- •Пример использования ifnb.
- •Пример использования макроопределений.
- •Резидентные программы tsr (terminate and stay resident)
- •Защита резидентной программы от повторной загрузки.
- •Выгрузка резидентной программы.
- •Переключение стека в резидентной программе.
- •Обработчик прерываний от таймера
- •Контроллер прерываний и его программирование
- •Взаимодействие прикладных и системных обработчиков прерываний
- •Резидентный обработчик прерываний от клавиатуры с подключением до системного
- •Резидентный обработчик прерывания от клавиатуры с подключением после системного обработчика
- •Резидентный обработчик прерываний от клавиатуры с подключением как до, так и после системного.
- •Вывод на экран текста средствами bios
- •Режимы дисплея
- •Работа с видеобуфером.
- •Логическая организация текстового видеобуфера.
- •Программирование портов. Звук.
- •Программирование звукового канала таймера.
- •Интерфейс с Си
- •Программы с несколькими сегментами команд.
- •Программы с несколькими сегментами данных.
- •Директива assume. Инициализация сегментных регистров и замена сегментов.
- •Структуры и записи.
Табличные вызовы подпрограмм.
В тех случаях, когда программа с включенными в неё подпрограммами выполняется по достаточно несложному алгоритму, вызывая подпрограммы в заданном заранее порядке, подпрограммы можно разместить в отдельных процедурах (или назначить им входные метки) и вызывать по именам. В более гибких программных системах бывает удобно предусмотреть механизм вызова требуемой подпрограммы по её номеру. Так сделано в DOS и BIOS. Для вызова функции DOS в AH заносится номер функции и с помощью int 21h вызываем диспетчер DOS. Диспетчер извлекает из AH номер функции и активизирует по этому номеру соответствующую программу из числа функций DOS.
Рассмотрим упрощенную имитацию диспетчера DOS. В нашей программе должен быть диспетчер, вызываемый с помощью прерывания и переопределяющий управление подпрограмм с заданным в AH номером. Адрес диспетчера внесем в один из свободных номеров.
jmp start
; Диспетчер прерывания 65h
new_65h: push bx
push dx
mov bl,ah
mov bh,0
shl bx,1 ;Логический сдвиг влево на один разряд
call add_tbl[bx];
pop dx
pop bx
iret
;Подпрограммы-функции
sub0: mov ah,9
lea dx,mes0
int 21h
ret
...
...
...
sub4: mov ah,9
lea dx,mes4
int 21h
ret
start: mov ax,2565h ;функция заполнения вектора
; прерывания int 65h
mov dx, offset new_65h
int 21h
;Последовательно вызываем подпрограммы
mov ah,0
int 65h
mov ah,1
int 65h
...
...
...
mov ah,4
int 65h
mov ax,4c00h
int 21h
;Таблица адресов и подпрограмм
add_tbl dw sub0
dw sub1
...
...
...
dw sub4
;Сообщения
mess0 db ‘Отработала подпрограмма 0’, 13,10,’$’
...
...
...
mess4 db ‘Отработала подпрограмма 4’, 13,10,’$’
Номер функции пересылается из AH в регистр BX, который в дальнейшем используется в качестве индексного. Сдвиг BX соответствует умножению на 2. Теперь BX - индекс, в таблице адресов addr_tbl, в которой записаны смещения (относительные адреса) подпрограмм в порядке, определяющем их номера.
Команда
call addr_tbl[bx]
косвенного вызова, передает управление на требуемую подпрограмму. Диспетчер с помощью iret возвращает управление в основную программу.
{ ?????????????????
Вектор Z слова разделяется на CS и IP
Вектор можно изменить непосредственно, засылая байты по адресу вектора. При изменении вектора нужно соблюдать меры предосторожности. В некоторых случаях может возникнуть прерывание в процессе изменения вектора.
Команда CLI запрещает прерывания, все кроме NMI-немаскируемых прерываний.
xor ax,ax
mov es,ax
cli ;приостановить прерывания
mov word ptr es:36,xx ;переслать из вектора смещения
mov word ptr es:38,yy ;и сегментную часть
sti ;разрешить прерывания
Можно скомбинировать две команды mov в одну.
movs - пересылка строки.
Однако лучше отдать это DOS и не делать своими руками.
lea dx, buffer_end ;адрес конца программы
int 27h ;выход с сохранением программы в памяти
Print_handler proc far
Пример использования функции 37=25h DOS для установки вектора прерывания:
mov dx,xx ;загрузить в вектор смещение
mov ds,yy ;загрузить сегментную часть вектора
mov ah,25h ;код функции
mov al,9 ;изменить вектор прерывания номер 9
int 33 ;прерывание вызова функции
(Прерывание 9 генерируется при нажатии клавиши)
Это наиболее простой способ использования служебной функции DOS. Однако, один из адресов, передаваемых DOS, нужно загрузить в DS, что по существу препятствует нормальному доступу через этот регистр к нашим данным.
Следующая программа разрешает эту проблему:
push ds ;сохранить текущий сегмент данных
mov dx,offset xxx ;получить смещение вектора
push cs ;переслать наш новый сегмент кода...
pop ds ;в сегмент данных
mov ah,25h ;функция установки вектора прерывания
mov al,9 ;изменить вектор прерывания номер 9
int 21h ;вызов DOS
pop ds ;восстановить начальный сегмент данных
Для функции 25h:
ah=25h
al= номер прерывания
ds:dx - указатель программы обработчика прерывания
Оператор offset возвращает относительный адрес (смещение) переменной или метки внутри сегмента данных или кода.
Формат:
offset переменная или метка
Пример
mov dx,offset tablea ;помещает в dx смещение
;поля tablea в сегменте данных
Программа
code_seg segment
assume cs:code_seg, ds:code_seg, es:code_seg
org 100h
jmp start
print_vector dd ? ;место для хранения исходного вектора 17h
start:
mov ah,35h
mov al,17h
int 21h
mov word ptr print_vector,bx
mov word ptr print_vector+2,es
cli
push ds
mov dx, offset print_handler
push cs ;mov ax, seg print_handler
pop ds ;mov ds,ax
mov ah,25h
mov al,17h
int 21h
pop ds
sti
????????????????? }