Обработка прерывания
К обработке прерывания отнесем фиксацию состояния прерываемой программы, переход к программе, соответствующей обслуживаемому прерыванию, и возврат к прерванной программе после окончания работы прерывающей программы. Выше мы определили, что большинство процессоров может прервать выполнение текущей программы и переключиться на реализацию обработчика прерывания только после завершения очередной команды. При этом в качестве контекста прерванной программы необходимо сохранить текущее состояние счетчика команд PC, а в PC загрузить новое значение — адрес программы-обработчика прерывания. Очевидно, адрес возврата в прерванную программу (содержимое PC на момент прерывания) следует размещать в стеке, что позволит при необходимости осуществлять вложенные прерывания (когда в процессе обслуживания одного прерывания получен запрос на обслуживание другого). Можно вспомнить, что подобный механизм реализован в системах команд многих процессоров для выполнения команд вызовов подпрограммы (call, JSR). В этих командах адрес вызываемой подпрограммы содержится в коде команды. (Страница172) В случае вызова обработчика прерывания его адрес необходимо связать либо со входом, на который поступил запрос (радиальные прерывания), либо с номером источника прерываний, сформировавшего запрос (векторные прерывания). В первом случае не требуется никаких внешних процедур для идентификации источника, сразу можно запускать связанный со входом обработчик. Понятно, здесь идет речь об отсутствии необходимости в аппаратных процедурах идентификации источника запроса. Если на радиальный вход "работают" несколько источников, то выбор осуществляется программными способами. В случае векторных прерываний адрес перехода связывают с информацией, поступающей от источника запроса по шине данных в машинном цикле обслуживания прерывания — вектором прерывания. Напомним, что любой командный цикл процессора начинается с чтения команды из памяти. В первом машинном цикле командного цикла процессор выдает на шину адреса содержимое PC, формирует управляющий сигнал RDM и помещенное памятью на шину данных слово интерпретирует как команду (или ее начальную часть, если длина команды превышает длину машинного слова). Если в конце очередного командного цикла процессор обнаруживает (незамаскированный) запрос на векторном входе, он начинает следующий командный цикл с небольшими изменениями: содержимое PC по-прежнему выдается на шину адреса (чтобы не нарушать общности цикла), но вместо сигнала RDM формирует сигнал INTA. Источник запроса (чаще — контроллер прерываний) в ответ на сигнал INTA формирует на шину данных код команды вызова подпрограммы, в адресной части которой размещается адрес обработчика соответствующего прерывания. Такой простой способ реализации векторных прерываний, с использованием уже существующего механизма вызова подпрограмм, был реализован, например, в микропроцессоре i8080 с контроллером прерываний i8259. Однако этот механизм, как, впрочем, и все остальное, допускает дальнейшее совершенствование. Прежде всего, желание иметь возможность располагать подпрограммы в произвольной области памяти приводит к необходимости размещать в поле адреса команды вызова полноразрядный адрес (16 — 20 — 32 бита). В этом случае длина команды превышает длину машинного слова и ее ввод требует нескольких машинных циклов (например, в i8080 — трех), что увеличивает время реакции системы на запрос прерывания. Для преодоления этого недостатка в систему команд процессора включают дополнительно "укороченные" команды вызова длиной в одно машинное слово. Эти команды в процессорах 8080 и х86 имеют мнемокод int. В микропроцессоре i8080 имеется 8 таких команд длиной в 1 байт, адресующих подпрограммы по фиксированным адресам памяти: 0000h, 0008h, 0010h,..., 0038h. В процессорах x86 имеется 256 вариантов двухбайтовых команд int 00h,..., INT FFh, байт поля адреса которых (называемый вектором) после умножения на 4 указывает на четырехбайтовую структуру, определяющую произвольный адрес в адресном пространстве памяти. Напомним, что доступ в память процессоров х86 (в реальном режиме) осуществляется только в рамках сегментов размером в 64 Кбайт. Положение начала сегмента в адресном пространстве памяти определяется содержимым 16-разрядного сегментного регистра, а положение адресуемого байта внутри сегмента — 16-разрядным смещением. Среди команд передачи управления различают короткие и длинные переходы (вызовы). При коротком вызове подпрограмма должна располагаться в текущем сегменте кода, и ее вызов сопровождается только изменением счетчика команд (в x86 он обозначается, как IP). При длинном вызове новое значение загружается как в IP, так и в сегментный регистр кода CS. Таким образом, для осуществления длинного вызова (перехода) в адресном поле команды необходимо разместить 4 байта. Механизм векторных прерываний в процессорах x86 в реальном режиме реализован следующим образом. В начальных адресах 00000h,..., 003FFh пространства памяти размещается таблица векторов прерываний объемом 1 Кбайт, включающая 256 строк таблицы — четырехбайтовых структур CS: IP, которые определяют адреса соответствующих обработчиков прерываний. В цикле обработки векторного прерывания (запрос по входу INT), процессор получает от источника байт — номер строки таблицы векторов прерываний, из которой и загружаются новые значения CS и IP. Старые значения CS: IP (адрес возврата) размещаются в стеке. Запросу по радиальному входу NMI соответствует вектор 2, поэтому появление активного значения не вызывает машинного цикла обслуживания прерывания, а сразу вызывается обработчик по адресу из ячеек памяти 00008h,..., 0000Bh. Кстати, любой обработчик прерывания (независимо от значения маскирующих флагов) можно вызвать программно с помощью команды int nn, где nn — номер строки таблицы векторов прерываний. Таким образом, команда int отличается от команды call, во-первых, способом адресации вызываемой подпрограммы (прямой адрес — в команде call, косвенный — в int), во-вторых, при реализации ют в стек, помимо CS и IP, помещается содержимое регистра признаков процессора — FLAGS. Соответственно, завершаться подпрограмма, вызываемая командой int, должна командой iret ("возврат из прерывания"). Действие iret отличается от действия ret извлечением из стека дополнительного слова в регистр FLAGS.
|