Страница 104 из 124
Более того, даже при постоянно выполняемой проверке флагов состояний у вас еще остается повод для беспокойства. В частности, в последнем примере ЦП будет успевать вводить символы, набираемые на клавиатуре, если он находится в главном цикле проверки флагов. Но что, если ЦП затратит 1/10 секунды в той части алгоритма, которая обеспечивает обработку строки? Или дисплей медленный и заставляет программу ждать, пока сбросится флаг занятости? Все, что в таких случаях необходимо, это — механизм, позволяющий внешнему устройству прервать обычный порядок работы ЦП в тех случаях, когда надо что-нибудь сделать. Затем ЦП может проверить регистр состояния для того, чтобы определить, чем вызвано беспокойство, аккуратно сделать то, что положено и вернуться к нормальной работе.
Для того чтобы дополнительно использовать потенциальные возможности прерываний в компьютере, необходимо добавить несколько новых сигналов на магистрали: по крайней мере, одна обобщенная линия для передачи прерываний от внешних устройств и (обычно) пара линий, с помощью которых ЦП может определить, какое устройство выдало сигнал прерывания. К сожалению, пример с IBM PC не очень удачен, так как эта машина не использует всех возможностей прерываний. Однако недостаток гибкости более чем компенсируется простотой; реализация аппаратных прерываний в периферийных устройствах PC проще пареной репы.
Теперь о том, как это все работает: магистраль PC имеет набор из 6-ти линий для передачи сигналов запросов прерываний, именуемых IRQ2-IRQ7. Эти линии используют положительную логику и подключены к схемам обрамления ЦП (в частности, к контроллеру прерываний типа 8259). Для того чтобы возбудить прерывание, вы просто устанавливаете на одной из линий высокий уровень сигнала. Если прерывания разрешены (в том числе и то конкретное IRQ, которое вы выбрали), ЦП после завершения очередной команды прерывает выполнение программы, а затем (после сохранения в стеке флагов и текущего указателя команд) переходит к программе обработчика прерывании, расположенной где-то в памяти.
В обработчике вы предусматриваете любые требуемые действия (например, чтение данных с клавиатуры), и поместить его вы можете где угодно по своему усмотрению; ЦП выясняет, по какому адресу надо совершить переход, анализируя 4-байтовый адрес обработчика, расположенный в выделенной области в начале памяти. Адрес этой области зависит от выбранного IRQ; для МП 8086 16-ричное значение этого адреса вычисляется по формуле 20 + 4n, где n-уровень прерывания. Например, ЦП будет реагировать на прерывание IRQ2 посредством перехода по 4-байтовому адресу, который хранится в ячейках памяти с адреса 28Н по 2ВН (это похоже на косвенную адресацию, с той лишь разницей, что адрес располагается в памяти, а не в регистре); конечно, начальные адреса ваших обработчиков прерываний следует заранее поместить в память. В конце обработчика надо выполнить команду IRET, которая обеспечит восстановление предварительно сохраненного содержимого регистра флагов и передачу управления обратно в точку вызова.
Проиллюстрируем это, добавив в схему интерфейса клавиатуры прерывания (рис. 10.12).
Рис. 10.12. Интерфейс клавиатуры с прерываниями.
Мы оставили флаг «символ готов» и схему программируемого ввода-вывода практически без изменений, за исключением того, что сигнал сброса флага включен по схеме «ИЛИ» с новым сигналом магистрали RESET DRV, который является выходным для ЦП, он на короткое время устанавливается в высокое состояние при включении компьютера. Обычно этот сигнал используется для установки триггеров и других элементов последовательной логики в определенное состояние при включении питания. Очевидно, этот сигнал должен сбросить флаг готовности байта к приему его в программу (в нашем новом интерфейсе установленный флаг готовности даже вызвал бы прерывание). Еще одно внесенное нами изменение — использование сокращенных обозначений для описания разрядности шины данных для того, чтобы сделать схему более удобочитаемой.
Новая схема обработки прерываний включает драйвер для установки IRQ2 в случае готовности символа. Вот и все схемные новшества, которые вам необходимы. Мы добавили, хотя в этом нет обязательной необходимости, возможность отключения устройства выработки сигнала прерывания (которое представляет собой трехстабильный буферный элемент) путем передачи байта, младший разряд которого установлен в низкое состояние, по адресу порта KBFLAG. Это можно будет использовать в том случае, если вам захочется подключить к тому же уровню IRQ другое устройство, вырабатывающее прерывания, причем так, чтобы в каждый момент только одно устройство могло инициировать прерывание (ниже мы дополнительно поясним этот щекотливый момент).
10.10. Обработка прерываний
Компьютеры семейства IBM PC/XT реализуют обработку прерываний просто (хотя и ограничивая при этом гибкость), используя интегральную микросхему контроллера прерываний типа 8259, установленную на базовой плате. Эта микросхема выполняет основной объем работы, которая включает в себя определение приоритетов, маскирование и выбор векторов прерываний (мы опишем это после примера, приведенного ниже). Со своей стороны ЦП определяет, что наступило прерывание и реагирует на это сохранением указателя команд и регистра флагов, а также запрещением дальнейших прерываний, а затем-совершая переход по соответствующему адресу, записанному в области векторов прерываний в начальных ячейках памяти. Ваша программа обработки прерываний делает остальное, а именно: а) сохраняет с помощью команды push все регистры, которые вы собираетесь использовать (напомним, что прерываемая программа не может заранее подготовиться к прерыванию, поскольку оно может произойти в любой момент во время выполнения программы как гром среди ясного неба); б) выясняет, при необходимости, с помощью чтения одного или нескольких регистров состояний, что именно требуется выполнить; в) выполняет это; г) восстанавливает ранее сохраненные регистры из стека; д) сообщает микросхеме 8259, что все сделано (передавая байт признака завершения прерывания 20Н и, наконец, е) выполняет возврат из прерывания — команду IRET, что заставляет ЦП восстановить содержимое прежнего регистра флагов, сохраненное предварительно в стеке и передать управление (использовав прежнее, также предварительно сохраненное в стеке значение указателя команд) обратно в ту программу, выполнение которой было прервано. Где-то в программе вы должны ж) загрузить адрес программы-обработчика прерываний по адресу вектора прерываний, соответствующего уровню IRQ, используемого аппаратной частью компьютера, и сообщить контроллеру прерываний 8259 о том, что необходимо разрешить прерывание указанного уровня.
Программа 10.5 демонстрирует программирование клавиатуры с использованием прерываний. Вот общая схема: главная процедура выполняет необходимые предустановки, а затем в цикле прерывает значение флага (программного, не аппаратного), который устанавливает обработчик прерываний, обнаружив код «возврата каретки»; когда главная процедура замечает, что флаг установлен, она переходит к заданным действиям над строкой, а затем происходит возврат к циклу проверки флага. Обработчик прерываний, в который передается управление при каждом прерывании, заносит символ в буфер строки, устанавливает флаг, если символ оказался «возвратом каретки» и возвращает управление.
Давайте более пристально посмотрим на программу. После задания адреса порта и адреса вектора прерываний IRQ2 она выделяет 100 байт под буфер строки (первоначально буфер заполняется нулями). Собственно выполнение программы начинается с занесения адреса буфера в адресный[6] регистр SI, обнуление флага конца строки, и помещения адреса обработчика прерываний (который начинается с ΚΒΙΝΤ) в ячейку 28Н. Для того чтобы разрешить контроллеру прерываний 8259 прерывания 2-го уровня, обнулим бит 2 маски (команды IN, AND, OUT); затем разрешим прерывания ЦП и передадим единицу в KBFLAG, что приводит к разрешению трехстабильного драйвера.