Набор команд процессора 8086


Набор команд процессора 8086
.8086 ; Набор команд процессора
.model tiny ; Модель памяти (для .COM)
.code ; Кодовый сегмент программы.
;——————————————————————-
; Специальные символы
;——————————————————————-
HT equ 09h ; Горизонтальная табуляция.
CR equ 0Dh ; Возврат каретки.
LF equ 0Ah ; Перевод строки.
EL equ ‘$’ ; Конец строки для MS-DOS.
;——————————————————————-

; Структура префикса программного сегмента (адрес CS:[0000h])
;——————————————————————-
PSP_struc struc
db 02Ch dup(?) ; Не используем.
psp_env dw ? ; Сегмент окружения.
db 052h dup(?) ; Не используем.
psp_par db 080h dup(?) ; Командная строка.
PSP_struc ends
;——————————————————————-
; Структура блока управления памятью MS-DOS
;——————————————————————-
MCB_struc struc
MCB_type db ? ; Тип блока ( 4Dh или 5Ah).
MCB_PSP dw ? ; Адрес PSP, 0h или 8h.
MCB_size dw ? ; Размер блока в параграфах.
MCB_unused db 3 dup(?) ; Не используется.
MCB_prog db 8 dup(?) ; Имя программы-владельца.
MCB_struc ends
;°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
;° °
;° Резидентная часть программы °
;° °
;°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
;
; Начиная с адреса CS:[0000h] и до адреса CS:[0100h] расположен пре-
; фикс программного сегмента (PSP), в котором MS-DOS хранит данные о
; программе. PSP сохраняется в памяти вместе с резидентной частью.
;
org 100h ; Пропустить PSP
;——————————————————————-
; Точка входа в программу при запуске (соглашение для .COM файла)
;——————————————————————-
start: jmp setup ; Переход в запускающую часть
;——————————————————————-
; Область неизменных данных резидентной части программы
;——————————————————————-
copyright db ‘ (C) Выхованец В.С. 1994 ‘; Права на копирование
next_line db CR, LF, EL ; Символы новой строки.
flag_on db 0 ; Флаг разрешения резидента.
flag_in db 0 ; Флаг входа в обработчик.
int_no db 21h ; Перехватываемое прерывание
int_fun db 03Fh ; Обрабатываемая функция.
int_old label dword ; Метка адреса старого обраб.
int_ofs dw 0 ; Смещение старого обраб-ка.
int_seg dw 0 ; Сегмент старого обраб-ка.
;——————————————————————-
; Область изменяемых данных для критической секции
;——————————————————————-
int_count dw 0 ; Счетчик входов в крит.секц.
;——————————————————————-
; Точка входа в новый обработчик прерывания int_no
;——————————————————————-
int_new:
pushf ; Сохранение флагов и
push ax ; используемых регистров.
sti
;——————————————————————-
; Проверка активного состояния TSR
;——————————————————————-
cmp cs:[flag_on], 0h; Если TSR активирована,
jne int_test ; то на проверку условия.
int_old_ret: ; Иначе вызов старого обраб.
pop ax ; Восстановление регистров.
push cs:[int_seg] ; Включить в стек адрес
push cs:[int_ofs] ; старого обработчика int_no
iret ; и его вызов через возврат.
;——————————————————————-
; Проверка условия выполнения нового обработчика int_no
;——————————————————————-
int_test:
cmp ah, cs:[int_fun]; Если не требуемая функция,
jne int_old_ret ; то на вызов сторого обраб.
;——————————————————————-
; Проверка занятости нового обработчика int_no
;——————————————————————-
int_busy:
mov al, 0FFh ; Значение «занято»
xchg al, cs:[flag_in]; Обменять флаги.
cmp al, 0FFh ; Если обработчик занят,
je int_busy ; то ожидать освобождение.
;——————————————————————-
; Начало критической секции обработки прерывания int_no
;——————————————————————-
inc cs:[int_count] ; Далее можно использовать
; . . . ; данные критической секции!
;——————————————————————-
; Если необходимо, то выполнить старый обработчик с возвратом в TSR
;——————————————————————-
int_old_call:
pop ax ; Восстановить регистры
popf ; и флаги, а также занести
pushf ; в стек флаги для iret.
call cs:[int_old] ; Выполнить старый обраб.
sti ; Разрешение прерываний!!!
pushf ; Сохранение флагов и рег.
push ax ; (если необходимо).
;——————————————————————-
; Продолжение критической секции обработки прерывания int_no
;——————————————————————-
; . . .
;——————————————————————-
; Завершение критической секции и освобождение обработчика int_no
;——————————————————————-
int_free:
mov cs:[flag_in], 0 ; Сбросить флаг занятости.
;
; Далее данные критической секции использовать нельзя!
; Если в результате обработки прерывания вызывающей программе должны
; быть переданы данные через регистры процессора, то в соответствую-
; щие регистры до сброса флага занятости заносятся эти данные .
;
;——————————————————————-
; Восстановление неизменяемых регистров из стека программы и возврат
;——————————————————————-
pop ax ; Восстановление регистров и
popf ; флагов и возврат в програм-
retf 2 ; му с удалением старых фла-
; гов из стека вызова.
;——————————————————————-
; Конец резидентной части
;——————————————————————-
end_tsr label byte ; метка конца резидента
code_size equ ($-int_new)/2 ; длина кода резидента в сл.
;°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
;° °
;° Запускающая часть программы °
;° °
;°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
setup:
push cs ; Загрузить в регистр DS
pop ds ; адрес сегмента программы.
;——————————————————————-
; Вывод заголовка программы
;——————————————————————-
mov ah, 09h ; Вывести на консоль
lea dx, [next_line] ; символы «новая строка»
int 21h ; средствами MS-DOS.
lea dx, [head_msg] ; Вывести на консоль
int 21h ; заголовок программы.
;——————————————————————-
; Проверка наличия резидентной части в оперативной памяти
;——————————————————————-
check:
mov ah, 52h ; Получить адрес списка
int 21h ; списков MS-DOS и занести
mov bx, es:[bx-2] ; в BX адрес блока памяти.
mov dx, cs ; DX= сег. адрес PSP прогр.
check_next:
mov es, bx ; ES=сег. адрес тек. блока.
cmp es:[MCB_type], 05Ah ; Если блок последний,
je command ; то переход на обр. команд.

cmp es:[MCB_type], 04Dh ; Если тип блока не 4Dh,
jne check_error ; то переход по ошибке.
add bx, es:[MCB_size]; Вычислить адрес следующе-
inc bx ; заголовка блока памяти.
mov ax, es:[MCB_PSP]; AX=PSP из текущего блока.
cmp ax, 8 ; Если блок ОС или своб.,
jbe check_next ; то переход на след. блок.
cmp ax, dx ; Если это блок программы,
je check_next ; то переход на след. блок.

cld ; Сброс флага направления.
mov es, ax ; ES=PSP резидента.
lea si, [int_new] ; SI=DI=смещение обработчи-
mov di, si ; ка прерывания в сегменте.
mov cx, code_size ; CX=длина кода резидента.
repe cmpsw ; Сравнить код обработчиков
jne check_next ; Переход по несовпадению.
mov [PSP_tsr], es ; Сохранить адрес резидента
jmp short check_next; и переход на след. блок.
check_error:
lea dx, [error_msg] ; DX=смещение сообщения.
jmp short terminate ; Переход на завершение.
;——————————————————————-
; Проверка параметров, переданных в командной строке
;——————————————————————-
command:
lea si, ds:[psp_par]; SI=смещение командной стр.
mov al, [si] ; Чтение длины строки в AL.
mov cl, al ; Установка счетчика симво-
mov ch, 0 ; лов в строке в CX.
command_loop:
inc si ; SI=смещение след. символа.
dec cx ; Уменьшить счетчик строки.
jl command_absent ; Переход, счетчик исчерпан.
mov ax, [si] ; AX=два символа из строки.
cmp ax, ‘I/’ ; Если задана команда /I,
je install ; то переход на запуск.
cmp ax, ‘i/’ ; Если задана команда /i,
je install ; то тоже переход на запуск
cmp ax, ‘U/’ ; Если задана команда /U,
je relese ; то переход на завершение.
cmp ax, ‘u/’ ; Если задана команда /u,
je relese ; то переход на завершение.
cmp al, CR ; Eсли не конец строки,
jne command_loop ; то переход в начало цикла
command_absent:
lea dx, [nopar_msg] ; DX=смещение сообщения.
jmp short terminate ; Переход на завершение.
;——————————————————————-
; Завершение работы резидентной части (удаление ее из памяти)
;——————————————————————-
relese:
lea dx, [absent_msg]; DX=смещение сообщения.
mov ax, [PSP_tsr] ; AX=адрес PSP резидента.
or ax, ax ; Eсли резидента нет,
jz terminate ; то завершение.

mov es, ax ; Cброс флага разрешения
mov es:[flag_on], 0h; обработки прерывания.

mov ah, 035h ; Получить адрес в ES:BX
mov al, int_no ; процедуры обработки пре-
int 21h ; рывания с номером int_no.

lea dx, [deact_msg] ; DX=смещение сообщения.
cmp bx, offset int_new; Если смещения не равны,
jne terminate ; то переход на завершение.
mov ax, es ; AX=сегмент обработчика.
cmp ax, [PSP_tsr] ; Если сегменты не равны,
jne terminate ; то переход на завершение.

mov ah, 025h ; Восстановить старый адрес
mov al, int_no ; процедуры обработки
mov dx, es:[int_ofs]; прерывания int_no,
mov ds, es:[int_seg]; загруженный в DS:DX
int 21h ; из тела резидентной части.
relese_wait:
cmp es:[flag_in], 0 ; Ожидание освобождения кри-
jne relese_wait ; тической секции резидента.
mov ah, 49h ; Освободить блок, выделен-
int 21h ; ный для резидентной части.

push cs ; Восстановить в DS адрес
pop ds ; сегмента текущей программы.
lea dx,[release_msg]; DX=смещение сообщения.
;——————————————————————-
; Выдача сообщения и завершение работы с передачей кода возврата DOS
;——————————————————————-
terminate:
mov bx, dx ; Сохранить адрес сообщения.
inc dx ; Получить в DX смещ.строки.
mov ah, 09h ; Вывод строки, оканчиваю-
int 21h ; щейся ‘$’ на консоль.
lea dx, copyright ; Вывод сообщения о правах
int 21h ; на копирование.

mov ah, 04Ch ; Завершение работы прог-
mov al, [bx] ; раммы с кодом возврата
int 21h ; в начале сообщения из DX.
;——————————————————————-
; Проверка на наличие резидентной части и разрешение ее работы
;——————————————————————-
install:
mov ax, [PSP_tsr] ; AX=адрес PSP резидента.
or ax, ax ; Eсли резидента нет,
jz install_tsr ; то переход на установку.

mov es, ax ; ES=сегмент резидента.
mov es:[flag_on], 0FFh ; Разрешить работу резид.
lea dx, [presnt_msg]; DX=смещение сообщения.
jmp short terminate ; Переход на завершение.
;——————————————————————-
; Установка (инсталяция) резидентной части программы
;——————————————————————-
install_tsr:
mov es, ds:[psp_env]; Освободить блок памяти,
mov ah, 49h ; занимаемый окружением
int 21h ; текущей программы.

mov ah, 035h ; Получить адрес текущего
mov al, int_no ; обработчика прерывания

int 21h ; и сохранить его в теле
mov int_ofs, bx ; резидентной части для
mov int_seg, es ; связи в список.
mov ah, 025h ; Установить адрес нового
mov al, int_no ; обработчика прерывания
lea dx, int_new ; с номером int_no, находя-
int 21h ; щегося в теле резидента.

lea dx, [inst_msg+1]; DX=смещение строки сообщ.
mov ah, 9 ; Вывод сообщения о запуске
int 21h ; резидентной части.
lea dx, copyright ; Вывод сообщения о правах
int 21h ; на копирование.

mov [flag_on], 0FFh ; Разрешить обработку прерыв.

lea dx, [end_tsr+15]; Вычислить длину резиден-
mov cl, 4 ; тной части программы в
shr dx, cl ; параграфах и завершить
mov al, [inst_msg] ; программу с сохранением
mov ah, 031h ; резидентной части в памяти
int 21h ; и кодом возврата из сообщ.
;——————————————————————-
; Область данных запускающей части и сообщения программы
;——————————————————————-
PSP_tsr dw 0 ; Адрес PSP резидента
head_msg db ‘Программа TSR’, EL
inst_msg db 0, ‘ установлена.’, EL
presnt_msg db 1, ‘ активирована.’, EL
deact_msg db 2, ‘ деактивирована.’, EL
absent_msg db 3, ‘ отсутствует в памяти.’, EL
release_msg db 4, ‘ удалена из памяти.’, EL
nopar_msg db 5, ‘ запущена без параметров.’, EL
error_msg db 6, ‘ (нарушена целостность MS-DOS).’, EL
;——————————————————————-
end start ; Точка входа в программу