В.Г. Баула - Введение в архитектуру ЭВМ и системы программирования (1110549), страница 19
Текст из файла (страница 19)
jmp dword ptr [4*N]; IP:=[4*N], CS:=[4*N+2]
Заметим, что на самом деле это аналог дальнего перехода с возвратом, так как в стек уже занесена информация о точке возврата в прерванную программу.
Непосредственно перед переходом на процедуру-обработчика центральный процессор закрывает (маскирует) внешние прерывания, так что обработчик начинает своё выполнение в режиме запрета прерываний. Это гарантирует, что, начав свою работу, процедура-обработчик не будет тут же прервана другим сигналом прерывания. Для нашей архитектуры центральный процессор устанавливает в ноль флаги IF и TF регистра флагов. Как мы уже говорили, значение флага IF=0 маскирует все прерывания от внешних устройств, кроме прерывания с номером 2. Флаг TF устанавливается равным нулю потому, что при значении TF=1 центральный процессор всегда посылает сам себе сигнал прерывания с номером N=1 после выполнения каждой команды. Этот флаг используется для пошагового выполнения (трассировки) программы, Вы будете изучать эту тему в курсе "Системное программное обеспечение".
На этом аппаратная реакция на незамаскированное прерывание заканчивается. Заметим, что некоторым аналогом аппаратной реакции ЭВМ на прерывание в живой природе является безусловный рефлекс. Безусловный рефлекс позволяет живому существу "автоматически" (а, следовательно, быстро, "не раздумывая") реагировать на произошедшее событие. Например, если человек обжигает пальцы на огне, то сначала он автоматически отдёргивает руку, а лишь потом начинает разбираться, что же произошло. Так и компьютер по сигналу прерывания автоматически "не раздумывая" переключается на процедуру-обработчика этого сигнала.
Итак, после завершения аппаратной реакции на незамаскированный сигнал прерывания начинает работать процедура-обработчик прерывания с данным номером, эта процедура выполняет программную реакцию на прерывание. Аналогом программной реакции на прерывание в живой природе можно считать условный рефлекс. Как у живого организма можно выработать условный рефлекс на некоторый внешний раздражитель, так и компьютер можно "научить", как реагировать на то или иное событие, написав процедуру-обработчика сигнала прерывания с номером, соответствующим этому событию.
Рассмотрим теперь схему работы процедуры-обработчика прерывания. Напомним, что эта процедура начинает выполняться в режиме с закрытыми прерываниями от внешних устройств. Как мы говорили выше, долго работать в таком режиме очень опасно, и следует как можно скорее разрешить (открыть) прерывания, для нашего компьютера это установка в единицу флаг IF (это можно выполнить командой sti )
Действия, выполняемые в режиме с закрытыми прерываниями, обычно называются минимальной программной реакцией на прерывание. Как правило, минимальная программная реакция включает в себя следующие действия.
-
Для прерванной программы запоминается вся информация, необходимая для возврата в эту программу. Это все адресуемые регистры (в том числе сегментные регистры и регистры для работы с вещественными числами), а также некоторые системные регистры (последнее сильно зависит от архитектуры конкретного компьютера). Вся эта информация запоминается в специальной области памяти, связанной с прерванной программой, обычно это область памяти называется информационным полем программы или контекстов программы. 1
-
Выполняются самые необходимые действия, связанные с произошедшим событием. Например, если нажата или отпущена клавиша на клавиатуре, то это надо где-то зафиксировать (например, запомнить в очереди введённых с клавиатуры символов). Если этого не сделать на этапе минимальной реакции и открыть прерывания, то процедура-обработчик может быть надолго прервана новым сигналом, который произведёт переключение на какую-то другую процедуру-обработчика, за время работы которой уже может быть нажата другая клавиша, а информация о нажатой ранее клавише таким образом будет потеряна.
После выполнения минимальной программной реакции процедура-обработчик включает (разрешает) прерывания – в нашей архитектуре устанавливает IF=1. Далее производится полная программная реакция на прерывания, т.е. процедура-обработчик выполняет все необходимые действия, связанные с происшедшим событием. Вообще говоря, допускается, что на этом этапе наша процедура-обработчик может быть прервана другим сигналом прерывания.2 В этом случае процедура-обработчик должна при каждом входе в неё резервировать память под свой контекст, где будут запоминаться данные, необходимые для возврата в эту процедуру.
Закончив полную обработку сигнала прерывания, процедура-обработчик должна вернуть управление программе, прерванной последним сигналом прерывания.3 Для этого сначала необходимо из контекста прерванной программы восстановить значение всех её регистров (кроме регистров FLAGS, CS и IP). После этого надо произвести возврат на следующую команду прерванной программы, для чего в нашем компьютере можно использовать специальную команду языка машины – команду выхода из прерывания
iret
Эта команда без параметров выполняется по схеме:
Изстека(IP); Изстека(CS); Изстека(FLAGS)
Напомним, что уже восстановлены регистры SS и IP прерванной программы, т.е. из её стека можно читать.
В Таблице 8.1 изображено начало вектора прерываний для компьютера изучаемой нами архитектуры.
Таблица 8.1. Начало вектора прерываний | |
Номер | Описание события |
N=0 | Ошибка в команде деления |
N=1 | Установлен флаг TF=1 |
N=2 | Немаскируемое внешнее прерывание |
N=3 | Выполнена команда int |
N=4 | Выполнена команда into и OF=1 |
N=5 | . . . |
N=6 | Команда с плохим кодом операции |
. . . |
Продолжим теперь изучение переходов, вызванных командами прерываний, выполнение каждой такой команды в нашей архитектуре всегда вызывает прерывание (исключением является команда into , которую бы рассмотрим далее). Каждая команда прерывания реализует дальний косвенный переход (понять это!).
Сначала рассмотрим команды, о которых упоминается в Таблице 8.1. Команда int является самой короткой (длиной в один байт) командой, которая всегда вызывает прерывание с номером N=3. В основном эта команда используется при работе отладчика – специальной программы, облегчающей программисту разработку новых программ. Отладчик ставит в программный код отлаживаемой программы так называемые контрольные точки – это те места, в которых отлаживаемая программа должна передать управление программе-отладчику. Для такой передачи хорошо подходит команда int , если программа-отладчик реализована в виде обработчика прерывания с номером N=3. Более подробно с работой отладчика Вы будете знакомиться в курсе следующего семестра "Системное программное обеспечение".
Команда into реализует условное прерывание: при выполнении этой команды прерывание происходит только в том случае, если флаг OF=1, иначе продолжается последовательное выполнение программы. Основное назначение команды into – эффективно реализовать надёжное программирование при обработке целых знаковых чисел. Как мы знаем, при выполнении операций сложения и вычитания со знаковыми числами возможна ошибка, при этом флаг переполнения устанавливается в единицу. Кроме того, вспомним, что флаг переполнения устанавливается в единицу и при операциях умножения, если значащие биты результата попадают в старшую часть произведения.
При надёжном программировании проверку флага переполнения необходимо ставить после каждой такой команды. Для такой проверки хорошо подходит команда into , так как эта самая короткая (однобайтная) команда условного перехода по значению OF=1. При этом, правда, обработку аварийной ситуации должна производить процедура-обработчик прерывания с номером N=4.
Рассмотрим в качестве примера простейшую реализацию такой процедуры-обработчика прерывания. Для простоты эта процедура-обработчик будет фрагментом нашей программы и располагается в сегменте кода. При возникновении ошибки будет просто выдаваться аварийная диагностика, и продолжаться выполнение нашей программы (естественно, с неверным результатом). Заметим, что наш обработчик прерывания не является процедурой в смысле языка Ассемблер.
include io.asm
data segment
A dw ?
X dw
Old dw ?
Dw ?
Diagn db ′Ошибка – большое значение!$′
Data ends
st segment stack
dw 64 dup (?)
st ends
code segment
assume cs:code, ds:data, ss:st
start:mov ax,data
mov ds,ax
; инициализация обработчика into
mov ax,0
mov es,ax; es - на вектор прерываний
My_into equ word ptr es:[4*4]
; сохранения адреса старой процедуры into
mov ax,My_into
mov Old,ax
mov ax,My_into+2
mov Old+2,ax;
; занесение нового адреса процедуры into
cli ; Закрыть прерывания
mov My_into,offset Error; Начало
mov My_into+2,code; процедуры-обработчика
sti Открыть прерывания
; собственно начало программы
mov ax,data
mov ds,ax
inint A
inint X
mov ax,A
add ax,X; Возможно переполнение
into
imul X; Возможны значащие биты в DX
into
mov X,ax; X:=X*(A+X)
outint X
; восстановление старого адреса into
Voz: cli ; Закрыть прерывания
mov ax,Old
mov My_into,ax
mov ax,Old+2
mov My_into+2,ax
sti Открыть прерывания
finish
; Начало нашей процедуры-обработчика
Error:
; Минимальная программная реакция
push ds; Сохранение регистров
push dx
push ax
sti Открыть прерывания
; Полная программная реакция
mov ax,data
mov ds,ax
mov dx,offset Diagn
outstr
newline
pop ax; Восстановление регистров
pop dx
pop ds
iret ; Возврат из прерывания
code ends
end start
Обратите внимание, что при выполнении некоторых групп команд работу нашей программы нельзя прерывать, иначе может возникнуть ситуация, когда в вектор прерывания не занесётся полностью вся необходимая информация, а уже произойдёт переключение на другую программу по пришедшему сигналу прерывания. В программировании такие группы команд называются критическими секциями программы. В нашей программе критические сеции заключены в рамки, в начале каждой критической секции стоит команда запрета прерывания от внешних устройств cli , а в конце секции – команда открытия прерываний sti .
После выдачи диагностики об ошибке наша процедура-обработчик может не продолжать выполнение программы, а, например, завершать выполнение программы. Для этого вместо предложения
iret ; Возврат из прерывания
надо поставить два предложения
add SP,3*2; Очистка стека от IP, CS и FLAGS
jmp Voz
И, наконец, рассмотрим команду, которая всегда вызывает прерывание с номером N, заданным в качестве её операнда:
int op1
Здесь op1 имеет формат i8. Заметим, что с помощью этой команды можно вызвать прерывание с любым номером, например прерывание, соответствующее делению на ноль или плохому коду операции. Более того, прерывания с номерами большими 31, в нашей архитектуре можно вызвать, только выполняя команду int с соответствующим параметром-номером прерывания. Используя эти команды, легко отлаживать процедуры-обработчики прерываний, но основное назначение таких команд состоит в другом.
Дело в том, что в большинстве программ необходимо выполнять некоторые широко распространённые действия (обмен данными с внешними устройствами, выполнение стандартных процедур и многое другое). Обычно процедуры, реализующие эти действия, оформляются в виде библиотеки стандартных процедур и всегда находятся в оперативной памяти компьютера. Так как адреса этих процедур часто меняются, то лучше всего присвоить каждой такой процедуре свой номер N и оформлять такие процедуры в виде обработчиков прерываний с этим номером. В этом случае вызов конкретной процедуры с номером N следует производить командой int N .
Исходя из описанного выше, такие команды прерывания (а часто и соответствующие им процедуры) обычно называют системными вызовами (системными функциями операционной системы), а библиотека стандартных процедур – Базовой системой процедур ввода/вывода (английское сокращение – BIOS). Параметры для таких процедур обычно передаются на регистрах, т.е. для системных вызовов не выполняются стандартные соглашения о связях.