Система прерываний.
Далее мы продолжим изучение переходов. Как мы уже упоминали, некоторые переходы производятся не при выполнении команд, а могут делаться центральным процессором автоматически при возникновении определённых условий. Если компьютер обладает такими способностями, то говорят, что в этом компьютере реализована система прерываний. Все современные компьютеры имеют систему прерываний, и сейчас мы начнём изучать, что это такое.
Сначала введём понятие события (возникшей ситуации). События могут возникать как в центральном процессоре (например, деление на ноль, попытка выполнить машинную команду с несуществующим кодом операции, выполнение некоторых особых команд и т.д.), так и в периферийных устройствах (например, нажата кнопка мыши, на печатающем устройстве кончилась бумага, получен сигнал по линиям связи и др.). Ясно, что при возникновении события продолжать выполнение программы может быть либо бессмысленно (деление на ноль), либо нежелательно, так как нужно срочно предпринять какие-то действия, для выполнения которых текущая программа просто не предназначена (например, надо отреагировать на нажатие кнопки мыши, на сигнал от встроенного таймера и т.д.).
В архитектуре компьютера предусмотрено, что каждое устройство, в котором произошло событие (центральный процессор, память, устройства ввода/вывода) генерирует сигнал прерывания – электрический импульс, который приходит на специальную электронную схему центрального процессора. Сигнал прерывания, связанный с каждым из событий, имеет свой номер, чтобы отличить его от сигналов, связанных с другими событиями. По месту возникновения сигналы прерывания бывают внутренними (в центральном процессоре) и внешними (в периферийных устройствах).
Получив такой сигнал, центральный процессор автоматически предпринимает некоторые действия, которые называются аппаратной реакцией на сигнал прерывания. Надо сказать, что, хотя такая реакция, конечно, сильно зависит от архитектуры компьютера, всё же можно указать какие-то общие черты, присущие всем ЭВМ. Сейчас мы рассмотрим, что обычно входит в аппаратную реакцию центрального процессора на сигнал прерывания.
Сначала надо сказать, что центральный процессор "смотрит", пришел ли сигнал прерывания, только после выполнения очередной команды, таким образом, этот сигнал ждёт завершения текущей команды.[31] Исключением из этого правила являются команды halt и wait. Команда halt останавливает выборку команд центральным процессором, и только сигнал прерывания может вывести компьютер из этого "ничегонеделания". Команда wait в младшей модели нашего семейства ждёт окончания операции с вещественными числами, которые мы не рассматриваем. Кроме того, прерывание не возникает после выполнения команды-префикса программного сегмента, т.к. она существенно влияет на следующую за ней команду.
К описанному выше правилу начала аппаратной реакции на сигнал прерывания необходимо сделать существенное замечание. Дело в том, что большинство современных ЭВМ отступают от принципа фон Неймана последовательного выполнения команд. Напоминаем, что согласно этому принципу очередная команда начинала выполняться только после полного завершения текущей команды.
Современные компьютеры могут одновременно выполнять несколько команд программы (а наиболее "продвинутые" из них – даже несколько команд из разных программ). Компьютеры, обладающие такими возможностями, называются конвейерными, они могут одновременно выполнять до восьми и более команд. Для конвейерных ЭВМ необходимо уточнить, когда начинается аппаратная реакция на сигнал прерывания. Обычно это происходит после полного завершения любой из выполняющихся в данный момент команд. Выполнение остальных команд прерывается и в дальнейшем их необходимо повторить с начала. Понятно, что конвейерные ЭВМ весьма "болезненно" относятся к сигналам прерывания, так как при этом приходится повторять заново несколько последних частично выполненных команд прерванной программы. Несколько более подробно о конвейерных ЭВМ мы поговорим в конце нашей книги.
Итак, после окончания текущей команды центральный процессор анализирует номер сигнала прерывания (для нашего компьютера это целое беззнаковое число формата i8). Для некоторых из этих номеров сигнал прерывания игнорируется, и центральный процессор переходит к выполнению следующей команды программы. Говорят, что прерывания с такими номерами в данный момент запрещены или замаскированы. Для компьютера нашей архитектуры можно замаскировать некоторые прерывания от внешних устройств (кроме прерывания с номером 2), установив в ноль значение специального флага прерывания IF в регистре флагов FLAGS (это можно выполнить командой cli ). Для компьютеров некоторых других архитектур можно замаскировать каждое прерывание по отдельности, установив в ноль соответствующий этому прерыванию бит в специальном регистре маски прерываний. Говорят, что прерывания с определёнными номерами можно закрывать (маскировать) и открывать (разрешать, снимать с них маску).
В том случае, если прерывание игнорируется (замаскировано), сигнал прерывания, тем не менее, продолжает оставаться на входе соответствующей схемы центрального процессора до тех пор, пока маскирование этого сигнала не будет снято, или же на вход центрального процессора придёт следующий сигнал прерывания. В последнем случае первый сигнал безвозвратно теряется, что может быть очень опасно, так как мы не прореагировали должным образом на некоторое событие, и оно прошло для нас незамеченным. Отсюда следует, что маскировать сигналы прерываний от внешних устройств можно только на некоторое весьма короткое время, после чего необходимо открыть возможность реакции на такие прерывания.
Разберёмся теперь, зачем вообще может понадобиться замаскировать прерывания. Дело в том, что, если произошедшее прерывание не замаскировано то, как мы вскоре увидим, центральный процессор прерывает выполнение текущей программы и переключается на выполнение некоторой в общем случае другой программы. Это может быть нежелательно и даже опасно, если текущая программа занята срочной работой, которую нельзя прерывать даже на короткое время. Например, эта программа может обрабатывать некоторое важное событие с другим номером прерывания, или же управлять каким-либо быстрым процессом во внешнем устройстве (линия связи с космическим аппаратом, химический реактор и т.д.).
С другой стороны, необходимо понять, что должны существовать и специальные немаскируемые сигналы прерывания. В качестве примера такого сигнала можно привести сигнал о неисправности в работе самого центрального процессора, ясно, что маскировать его бессмысленно. Другим примером может служить сигнал о том, что выключилось электрическое питание компьютера. Надо сказать, что в этом случае компьютер останавливается не мгновенно, какую-то долю секунды он ещё может работать за счёт энергии конденсаторов в блоке питания. Этого времени хватит на выполнение нескольких десятков или даже сотен тысяч команд и можно принять важные решения: послать сигнал тревоги, спасти ценные данные в энергонезависимой памяти (такая память называется статической), переключится на резервный блок питания и т.д. Кроме того, бессмысленно маскировать сигналы прерываний, которые выдаются при выполнении некоторых специальных команд, т.к. основным назначением этих команд и является выдача сигнала прерывания. Для нашего компьютера, как уже упоминалось, существует только одно немаскируемое прерывание от внешних устройств с номером 2.
Продолжим теперь рассмотрение аппаратной реакции на незамаскированное прерывание. Сначала центральный процессор автоматически запоминает в некоторой области памяти (обычно в текущем стеке) самую необходимую (минимальную) информацию о прерванной программе. Во многих книгах по архитектуре ЭВМ это называется малым упрятыванием информации о считающейся в данный момент программе, что хорошо отражает смысл такого действия. Для нашего компьютера в стек последовательно записываются значения трёх регистров центрального процессора, это регистр флагов (FLAGS), кодовый сегментный регистр (CS) и счётчик адреса (IP). Как видим, эти действия при минимальном упрятывании похожи на действия при выполнении команды перехода с возвратом call, да и назначение у них одно – обеспечить возможность возврата в прерванное место текущей программы. Из этого следует, что стек должен быть у любой программе, даже если она сама им и не пользуется.[32]
После выполнения минимального упрятывания центральный процессор по определённым правилам находит (вычисляет) адрес оперативной памяти, куда надо передать управление для обработки сигнала прерывания с данным номером. Говорят, что на этом месте оперативной памяти находится программа реакции (процедура обработки прерывания, обработчик) сигнала прерывания с данным номером.
Для компьютера нашей архитектуры определение адреса начала процедуры-обработчика прерывания с номером N производится по следующему правилу. В начале оперативной памяти расположен так называемый вектор прерываний – массив из 256 элементов (по числу возможных номеров прерываний от 0 до 255). Каждый элемент этого массива состоит из двух машинных слов (т.е. имеет формат m32) и содержит дальний адрес процедуры-обработчика. Таким образом, адрес процедуры-обработчика прерывания с номером N находится в двух словах, расположенных по физическим адресам 4*N и 4*N+2. Можно сказать, что для перехода на процедуру-обработчика необходимо выполнить безусловный переход
jmp dword ptr [4*N]; IP:=[4*N], CS:=[4*N+2]
Заметим, что на самом деле это аналог дальнего перехода с возвратом, так как в стек уже занесена информация о точке возврата в прерванную программу.
Непосредственно перед переходом на процедуру-обработчика центральный процессор закрывает (маскирует) внешние прерывания, так что обработчик начинает своё выполнение в режиме запрета прерываний. Это гарантирует, что, начав свою работу, процедура-обработчик не будет тут же прервана другим сигналом прерывания. Для нашей архитектуры центральный процессор устанавливает в ноль флаги IF и TF регистра флагов. Как мы уже говорили, значение флага IF=0 маскирует все прерывания от внешних устройств, кроме прерывания с номером 2. Флаг TF устанавливается равным нулю потому, что при значении TF=1 центральный процессор всегда посылает сам себе сигнал прерывания с номером N=1 после выполнения каждой команды. Этот флаг используется для пошагового выполнения (трассировки) программы, Вы будете изучать эту тему в курсе "Системное программное обеспечение".
На этом аппаратная реакция на незамаскированное прерывание заканчивается. Заметим, что некоторым аналогом аппаратной реакции ЭВМ на прерывание в живой природе является безусловный рефлекс. Безусловный рефлекс позволяет живому существу "автоматически" (а, следовательно, быстро, "не раздумывая") реагировать на произошедшее событие. Например, если человек обжигает пальцы на огне, то сначала он автоматически отдёргивает руку, а лишь потом начинает разбираться, что же произошло. Так и компьютер по сигналу прерывания автоматически "не раздумывая" переключается на процедуру-обработчика этого сигнала.
Итак, после завершения аппаратной реакции на незамаскированный сигнал прерывания начинает работать процедура-обработчик прерывания с данным номером, эта процедура выполняет программную реакцию на прерывание. Аналогом программной реакции на прерывание в живой природе можно считать условный рефлекс. Как у живого организма можно выработать условный рефлекс на некоторый внешний раздражитель, так и компьютер можно "научить", как реагировать на то или иное событие, написав процедуру-обработчика сигнала прерывания с номером, соответствующим этому событию.
Рассмотрим теперь схему работы процедуры-обработчика прерывания. Напомним, что эта процедура начинает выполняться в режиме с закрытыми прерываниями от внешних устройств. Как мы говорили выше, долго работать в таком режиме очень опасно, и следует как можно скорее разрешить (открыть) прерывания, для нашего компьютера это установка в единицу флаг IF (это можно выполнить командой sti )
Действия, выполняемые в режиме с закрытыми прерываниями, обычно называются минимальной программной реакцией на прерывание. Как правило, минимальная программная реакция включает в себя следующие действия.
· Для прерванной программы запоминается вся информация, необходимая для возврата в эту программу. Это все адресуемые регистры (в том числе сегментные регистры и регистры для работы с вещественными числами), а также некоторые системные регистры (последнее сильно зависит от архитектуры конкретного компьютера). Вся эта информация запоминается в специальной области памяти, связанной с прерванной программой, обычно это область памяти называется информационным полем программы или контекстов программы. [33]
· Выполняются самые необходимые действия, связанные с произошедшим событием. Например, если нажата или отпущена клавиша на клавиатуре, то это надо где-то зафиксировать (например, запомнить в очереди введённых с клавиатуры символов). Если этого не сделать на этапе минимальной реакции и открыть прерывания, то процедура-обработчик может быть надолго прервана новым сигналом, который произведёт переключение на какую-то другую процедуру-обработчика, за время работы которой уже может быть нажата другая клавиша, а информация о нажатой ранее клавише таким образом будет потеряна.
После выполнения минимальной программной реакции процедура-обработчик включает (разрешает) прерывания – в нашей архитектуре устанавливает IF=1. Далее производится полная программная реакция на прерывания, т.е. процедура-обработчик выполняет все необходимые действия, связанные с происшедшим событием. Вообще говоря, допускается, что на этом этапе наша процедура-обработчик может быть прервана другим сигналом прерывания.[34] В этом случае процедура-обработчик должна при каждом входе в неё резервировать память под свой контекст, где будут запоминаться данные, необходимые для возврата в эту процедуру.
Закончив полную обработку сигнала прерывания, процедура-обработчик должна вернуть управление программе, прерванной последним сигналом прерывания.[35] Для этого сначала необходимо из контекста прерванной программы восстановить значение всех её регистров (кроме регистров 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
Дата добавления: 2015-10-05; просмотров: 1116;