PersCom — Компьютерная Энциклопедия Компьютерная Энциклопедия

Ввод-вывод

Ввод-вывод

Контроллер прерываний

На наш взгляд, знакомство с системой прерываний микропроцессора Intel следует начать с обсуждения организации обработки аппаратных прерываний. Как видно из рис. 15.1, центральное место в схеме обработки аппаратных прерываний занимает программируемый контроллер прерываний (ПКП), выполненный в виде специальной микросхемы i8259А. Как мы уже говорили, эта микросхема может обрабатывать запросы от восьми источников внешних прерываний. Этого явно мало, поэтому в стандартной конфигурации вычислительной системы обычно используют две последовательно соединенные микросхемы i8259A. В результате такого соединения количество возможных источников внешних прерываний возрастает до 15.
Для того чтобы разобраться с обработкой аппаратных прерываний, нам придется проникнуть внутрь микросхемы i8259A. Перечислим функции, выполняемые микросхемой контроллера прерываний:

  • фиксирование запросов на обработку прерывания от восьми источников, формирование единого запроса на прерывание и подача его на вход INTR микропроцессора;
  • формирование номера вектора прерывания и выдача его на шину данных;
  • организация приоритетной обработки прерываний;
  • запрещение (маскирование) прерываний с определенными номерами.

На рисунке ниже показано схематическое представление внутренней структуры и физических выводов микросхемы i8259А.

Рассмотрим назначение представляющих для нас интерес выводов i8259А:

  • d0...d7 - выводы i8259A, замыкающиеся на системную шину данных. По ним передается номер вектора прерывания и принимается управляющая информация;
  • INT — вывод выходного сигнала запроса на прерывание, который подается на вход микропроцессора INTR;
  • INTA - вывод для сигнала от микропроцессора, подтверждающего факт принятия им прерывания на обслуживание;
  • irq0...irq7 — выводы для входных сигналов запросов на прерывания от внешних устройств.

Важное свойство данного контроллера — возможность его программирования, что позволяет достаточно гибко изменять алгоритмы обработки аппаратных прерываний. Исходя из этого, микросхема i8259А имеет два состояния:

  • состояние настройки параметров обслуживания прерываний, во время которого путем посылки в определенном порядке так называемых управляющих слов производится инициализация контроллера;
  • состояние работы — это обычное состояние контроллера, в котором производится фиксация запросов на прерывание и формирование управляющей информации для микропроцессора в соответствии с параметрами настройки.

Рассмотрим назначение основных структурных компонентов контроллера прерываний (см. рис. 15.2):

  • регистр запросов на прерывания IRR (Interrupt Request Register) — восьмиразрядный регистр, фиксирующий поступление сигнала на один из входов i8259А — irq0...irq7. Фиксация выражается в установке соответствующего бита в единичное состояние;
  • регистр маскирования прерываний IMR (Interrupt Mask Register)  — восьмиразрядный регистр, с помощью которого можно запретить обработку запросов на прерывания, поступающих на соответствующие входы (уровни) irq0...irq_7. Для запрещения (маскирования) определенных уровней прерываний необходимо установить соответствующие биты регистра IMR. Эта операция осуществляется путем программирования порта 21h;
  • регистр обслуживаемых прерываний ISR (Interrupt Service Register) — восьмиразрядный регистр, единичное состояние разрядов которого показывает, прерывания каких уровней обрабатываются в данный момент в микропроцессоре;
  • арбитр приоритетов PR (Priority Resolver) — функцией данного блока является разрешение конфликта при одновременном поступлении запросов на входы irq0...irq7;
  • блок управления - основной функцией данного блока является организация информационного обмена контроллера прерываний и микропроцессора через шину данных. На этот блок замыкаются как выводы d0...d7, так и некоторые другие (см. рис. 15.2).

Рассмотрим возможные прохождение и обработку сигнала прерывания от некоторого внешнего устройства. При этом воспользуемся структурной схемой контроллера прерываний и обозначениями на ней (см. рис. 15.2).
Допустим, на вход irq0 поступает сигнал прерывания, что приводит к установке нулевого бита регистра IRR. Этот регистр связан с регистром маски IMR, состояние битов которого определяет, какие уровни прерываний запрещены (единичные биты) или разрешены к обработке (нулевые биты). Управление данным регистром осуществляется через порт 21h. Таким образом, если бит 0 в IMR равен нулю, то прерывание уровня 0 разрешено. Далее сигнал поступает к арбитру приоритетов. Как мы уже отметили, функция этого блока — разрешение конфликтов при одновременном поступлении запросов на несколько уровней. Обычно самый высокий приоритет у уровня irq_0, и далее приоритет уменьшается с возрастанием номера уровня. Если конфликта нет, то сигнал поступает на схему управления контроллером прерываний, которая формирует сигнал на выводе int. Этот вывод связан со входом микропроцессора INTR. Таким образом, сигнал на входе i8259A достиг микропроцессора. Что происходит далее в микропроцессоре, мы рассмотрим ниже. Сейчас отметим только значимые для данного обсуждения моменты. Итак, при поступлении сигнала на вход INTR в микропроцессоре происходят следующие процессы:

  1. Анализируется флаг IF. Если вы помните, единичное состояние этого флага говорит о том, что аппаратные прерывания разрешены, нулевое — запрещены.
  2. Если прерывания запрещены, то запрос на прерывание «повисает» до момента установки IF в единицу.
  3. Если прерывания разрешены, микропроцессор выполняет следующие действия:
    • сбрасывает флаг IF в ноль;
    • формирует сигнал подтверждения прерывания на выводе микропроцессора INTA. Этот вывод микропроцессора замкнут на одноименный вывод микросхемы i8259A.

Таким образом, сигнал о прерывании прошел через микропроцессор и вернулся обратно в контроллер прерываний i8259A через вывод INTA. Данный вывод внутри контроллера прерываний замкнут на его схему управления, которая выполняет сразу несколько действий при поступлении этого сигнала:

  1. Сбрасывает бит в регистре IRR, соответствующий уровню прерывания irq_0.
  2. Устанавливает в 1 бит 0 регистра ISR, тем самым фиксируя факт обработки прерывания уровня 0 в микропроцессоре.
  3. Формирует с помощью блока управления номер вектора прерывания, значение которого формируется в буфере данных и далее поступает на выводы i8259A d0...d7. Выводы d0...d7 замкнуты на шину данных, по которой номер вектора поступает в микропроцессор. В микропроцессоре этот номер используется для вызова соответствующей процедуры обработки прерывания.

На данном этапе обработки прерывания, после того как номер прерывания по шине данных поступил в микропроцессор, последнему стало известно все об источнике прерывания. Далее микропроцессор осуществляет процедуру обработки прерывания. Если в это время придет другой сигнал о прерывании того же уровня, то он будет запомнен установкой бита в IRR, и обслуживание этого прерывания будет отложено. Если приходит прерывание другого уровня, то его дальнейшая обработка зависит от приоритета, который оно имеет по отношению к уже обрабатываемым прерываниям. Если приоритет выше, то текущая процедура обработки прерывания останавливается, и вызывается процедура обработки более приоритетного прерывания.
Очень важный момент связан с процессом завершения обработки прерывания. Проблема здесь состоит в следующем. После принятия микропроцессором запроса на обслуживание прерывания в контроллере устанавливается бит в регистре ISR, номер этого бита соответствует уровню прерывания. Установка бита с данным номером блокирует все прерывания уровня, начиная с текущего, и менее приоритетные в блоке-арбитре приоритетов. Если процедура прерывания закончит свою работу, то она сама должна этот бит сбросить, иначе все прерывания этого уровня и менее приоритетные будут игнорироваться. Для осуществления такого сброса необходимо послать код 20h в порт 20h. Есть и другая возможность — установить такой режим работы микросхемы i8259A, когда сброс этого бита будет производиться автоматически. Тонкий момент заключается в том, что происходить такой автоматический сброс будет одновременно с приходом сигнала INTA (то есть извещения о том, что запрос на обработку прерывания принят к обработке микропроцессором). Недостаток автоматического сброса в том, что существует вероятность прихода прерывания того же уровня, который уже обрабатывается в данный момент микропроцессором. В этом случае процедура обработки прерывания должна обладать свойством реентерабельности, то есть допускать повторное обращение к себе до завершения обработки предыдущего обращения. Для того чтобы процедура была реентерабельной, она должна иметь специфическую структуру, в частности, для каждого сеанса обращения к ней создается своя область для хранения переменных и значений регистров, а исполняемая часть процедуры находится в оперативной памяти только в одном экземпляре. Иногда может потребоваться подобный автоматический сброс, но надежнее и проще, конечно, контролировать этот процесс и самостоятельно сбрасывать бит в ISR. Это можно сделать либо в конце работы процедуры, либо в том месте процедуры, начиная с которого можно разрешить рекурсивный вызов данной процедуры, будучи уверенным в том, что она не разрушит никаких данных и работу программы в целом.
Другой не менее интересный момент заключается в том, что микропроцессор при принятии к обработке запроса на прерывание сбросил флаг IF в ноль, тем самым запретив все последующие аппаратные прерывания. Этим обстоятельством программист может пользоваться по своему усмотрению. Вы, конечно, помните, что все запросы на прерывания с приоритетом, равным текущему или меньшим, будут запрещены в любом случае, — это обусловлено логикой работы контроллера i8259A. Поэтому программист должен решить, насколько его замыслам могут помешать запросы на более приоритетные прерывания. Если это некритично, то лучше сразу, в начале процедуры обработки прерывания установить флаг IF в единицу. В большинстве случаев эту операцию нужно делать как можно раньше. Для установки флага IF в единицу в системе команд микропроцессора есть специальная команда, не имеющая операндов:

sti — разрешить аппаратные прерывания.

Наиболее наглядный пример, показывающий важность своевременной установки IF, связан с отсчетом времени. Если вы не знакомы с тем, как ведется учет времени в компьютере, то уделим этому немного внимания. Как после включения компьютер определяет текущее время суток или как он запоминает информацию о своей конфигурации после выключения? Все дело в том, что компьютер имеет небольшую энергонезависимую память, которая питается от аккумулятора и не зависит от подключения к электросети. Конструктивно эта память выполнена на специальном типе полупроводниковых элементов с так называемой CMOS-структурой (Complementar Metal Oxide Semiconductor — комплиментарная МОП-структура). Особенность таких элементов памяти — в их пониженной по сравнению с обычными микросхемами потребляемой мощности (при этом они являются и более медленными, что в данном случае непринципиально). Аккумулятор кроме CMOS-памяти питает еще и микросхему системных часов, в функции которой входит отсчет текущих даты и времени суток. Таким образом, текущие значения даты и времени постоянно хранятся в CMOS-памяти и поддерживаются в актуальном состоянии даже после выключения компьютера. Кроме того, в CMOS-памяти хранится некоторая другая информация, в частности, о конфигурации компьютера. Во время загрузки компьютера дата и время считываются в область данных BIOS. Дальнейший отсчет времени, после загрузки системы, ведется уже с помощью системного таймера — другой микросхемы на системной плате, в функции которой входит регулярно, примерно 18,2 раза в секунду, генерировать сигнал, который в качестве прерывания подается на уровень irq0 контроллера прерываний i8259A. Во время работы компьютера соответствующая программа BIOS обрабатывает прерывание данного уровня и ведет счет времени. Если терять такты по этому входу, то фактическое время на часах будет отставать, и поэтому в большинстве случаев в обработчиках прерываний есть смысл как можно раньше выдавать команду sti.



Седьмое. OCW3 — общее управление контроллером

Этот приказ (см. таблицу ниже) служит для общего управления контроллером. Приказ OCW3 посылается в порт 20h.

Этой информации уже вполне достаточно для написания и понимания реальных программ. В качестве примера рассмотрим последовательность приказов, которые выдает BIOS при загрузке системы после включения питания (см. таблицу ниже). Это будет хорошей иллюстрацией к вышеприведенным рассуждениям.



Усовершенствованный программируемый контроллер прерываний APIC

В качестве замены традиционной паре контроллеров прерываний 8259 компания Intel в середине 1990-х годов разработала усовершенствованный программируемый контроллер прерываний APIC (Advanced Programmable Interrupt Controller). Хотя все процессоры, начиная с Pentium, поддерживают APIC, этот контроллер должен присутствовать на системной плате; кроме того, системная BIOS также должна поддерживать APIC. Поддержка APIC реализована на большинстве современных системных плат; контроллер APIC поддерживается операционными системами Windows, начиная с версии Windows 2000. Поддержку APIC можно разрешить или запретить, воспользовавшись программой BIOS Setup.

Контроллер APIC обеспечивает поддержку нескольких процессоров, однако может использоваться и в однопроцессорных системах. Основное преимущество APIC для однопроцессорной системы — поддержка виртуальных прерываний IRQ выше 15. Большинство реализаций APIC поддерживают виртуальные IRQ до 24. Хотя Windows 2000 старается назначать запросы на прерывания PCI IRQ в традиционном для устройств ISA диапазоне 0...15, причем даже при активном контроллере APIC, Windows XP и Vista полностью используют все возможности активного контроллера APIC. Для Windows XP/Vista контроллер APIC ограничивает совместное использование IRQ, что значительно сокращает количество конфликтов устройств. Например, при активном контроллере APIC запросы PCI IRQ могут быть распределены следующим образом.

  • PCI IRQ 16. Интегрированный звуковой адаптер/видеоадаптер AGP (совместное использование).
  • PCI IRQ 17. Дополнительный адаптер USB 1.1 (совместное использование отсутствует).
  • PCI IRQ 18. Дополнительный адаптер USB 1.1 (совместное использование отсутствует).
  • PCI IRQ 19. Сетевой адаптер 10/100 Ethernet/дополнительный адаптер USB 2.0 (совместное использование).
  • PCI IRQ 21. Интегрированный контроллер USB 1.1 (3)/дополнительный адаптер USB 2.0 (совместное использование).

Традиционные запросы ISA IRQ 0...15 в данной системе использовались только для устройств ISA, тем самым предотвратив конфликты устройств ISA-PCI.

Чтобы обеспечить работоспособность необходимых служб APIC контроллер APIC должен быть активизирован в системной BIOS до установки Windows 2000/XP/Vista.

Примечание!

Контроллер APIC должен быть активизирован в системной BIOS до установки 64-разрядных версий Windows XP, 2003 и Vista.



Девятое.Реальный режим работы микропроцессора

Для тех пользователей, которые работали с микропроцессорами i8086 или i8088, нет необходимости пояснять особенности этого режима. Относительно недавно это был единственный режим, в котором функционировала популярная операционная система MS-DOS. Для нее был разработан большой объем программного обеспечения. Понимая все это и не желая терять рынок, фирма Intel во всех модернизациях своего микропроцессора поддерживает этот режим. В нашей книге при написании программ мы, до сего момента, также подразумевали реальный режим. Вот некоторые его характеристики:

  • пространство оперативной памяти делится на сегменты по 64 Кбайт. Сегменты в памяти могут перекрываться;
  • страничное преобразование адреса запрещено, то есть физический адрес равен линейному и формируется как сумма двух составляющих (см. урок 2):
    • 16-разрядного эффективного адреса, который, в свою очередь, является суммой трех составляющих: базы, смещения и индекса;
    • 20-разрядного результата сдвига содержимого конкретного сегментного регистра на 4 разряда влево;
  • максимальное значение физического адреса равно 0ff fffh, то есть 1 Мбайт, но, фактически, в реальном режиме микропроцессора адресуется на 64 Кбайт больше, что следует из следующего вычисления:
    ffff0 — максимальное значение сегментной части адреса, сдвинутое на 4 раз- ряда влево;
    +
    0ffff — максимальное значение смещения;
    10ffef = 1 114 096 байт — максимальный физический адрес в реальном режиме.

Этот пример говорит о том, что в модели микропроцессоров, начиная с i286, при определенных обстоятельствах возможна адресация оперативной памяти за пределами первого мегабайта. Это обстоятельство даже использовалось последними версиями MS-DOS для размещения служебных программ в этом дополнительном сегменте памяти. Формирование значений адреса сразу за первым мегабайтом возможно и в микропроцессоре i8088/86. В нем при появлении физического адреса большего 0fffffh, например 1 000 054h, микропроцессор отбрасывает 21-й единичный бит. Происходит так называемое «заворачивание» адреса, поэтому сформированный физический адрес на шине адреса будет равен 00054h. Для того чтобы обеспечить полную эмуляцию данной особенности микропроцессора i8088/86, в моделях микропроцессоров, начиная с i80286, была предусмотрена возможность блокировки адресной линии А20 (управление тем самым 21-м битом адреса). Для обеспечения доступа к адресам оперативной памяти, лежащим за пределами первого мегабайта, необходимо специальным образом открывать эту адресную линию;

  • в реальном режиме схема распределения оперативной памяти — фиксированная. Перечислим расположение некоторых из системных областей, которые потребуются нам в дальнейшем:
    • в диапазоне адресов 00000h-003ffh (первый мегабайт оперативной памяти) находится таблица векторов прерываний (ТВП). Она содержит 256 векторов прерываний размером 4 байта (указателей на программы обработки прерываний);
    • в диапазоне адресов 00400h-006ffh сразу за таблицей векторов прерываний располагается область памяти, содержащая жестко структурированные данные, обеспечивающие работу BIOS и MS-DOS;
    • с адреса 0b8000h располагается область видеопамяти, в которой формируется изображение, которое мы видим на экране.



Десятое. Обработка прерываний в реальном режиме

Обработка прерываний (как внешних, так и внутренних) в реальном режиме микропроцессора производится в три этапа:

  1. Прекращение выполнения текущей программы.
  2. Переход к выполнению и выполнение программы обработки прерываний.
  3. Возврат управления прерванной программе.

Первый этап должен обеспечить временное прекращение выполнения текущей программы таким образом, чтобы потом прерванная программа продолжила свою работу так, как будто никакого прерывания не было. Любая программа, загруженная для выполнения операционной системой, занимает свое, отдельное от других программ, место в оперативной памяти. Разделяемыми между программами ресурсами являются регистры микропроцессора, в том числе регистр флагов, поэтому их содержимое нужно сохранять. Обязательными для сохранения являются регистры cs, ip и flags\eflags, поэтому они при возникновении прерывания сохраняются микропроцессором автоматически. Пара cs:ip содержит адрес команды, с которой необходимо начать выполнение после возврата из программы обслуживания прерывания, а flags\eflags — состояние флагов после выполнения последней команды прерванной программы в момент передачи управления программе обработки прерывания. Сохранение содержимого остальных регистров должно обеспечиваться программистом в начале программы обработки прерывания до их использования. Наиболее удобным местом хранения регистров является стек. В конце первого этапа микропроцессор после включения в стек регистров flags, cs и ip сбрасывает бит флага прерываний IF в регистре flags (но при этом в стек записывается предыдущее содержимое регистра flags с еще установленным IF). Тем самым предотвращаются возможность возникновения вложенных прерываний по входу INTR и порча регистров исходной программы вследствие неконтролируемых действий со стороны программы обработки вложенного прерывания. После того как необходимые действия по сохранению контекста завершены, обработчик аппаратного прерывания может разрешить вложенные прерывания командой sti.
Набор действий по реализации второго этапа заключается в определении источника прерывания и вызова соответствующей программы обработки. В реальном режиме микропроцессора допускается от 0 до 255 источников прерываний. Количество источников прерываний ограничено размером таблицы векторов прерываний. Эта таблица выступает связующим звеном между источником прерывания и процедурой обработки. Данная таблица располагается в памяти, начиная с адреса 0. Каждый элемент таблицы векторов прерываний занимает 4 байта и имеет следующую структуру:

  • 1-е слово элемента таблицы — значение смещения начала процедуры обработки прерывания (n) от начала кодового сегмента;
  • 2-е слово элемента таблицы — значение базового адреса сегмента, в котором находится процедура обработки прерывания.

Определить адрес, по которому находится вектор прерывания с номером n, можно следующим образом:

смещение_элемента_таблицы_векторов_прерываний = n * 4

Таким образом, полный размер таблицы векторов прерываний 4 * 256 = = 1024 байт.
Теперь понятно, что на втором этапе обработки прерывания микропроцессор выполняет следующие действия:

  1. По номеру источника прерывания путем умножения на 4 определяет смещение в таблице векторов прерываний.
  2. Помещает первые два байта по вычисленному адресу в регистр ip.
  3. Помещает вторые два байта по вычисленному адресу в регистр cs.
  4. Передает управление по адресу, определяемому парой cs:ip.

Далее выполняется сама программа обработки прерывания. Она, в свою очередь, также может быть прервана, например, поступлением запроса от более приоритетного источника. В этом случае этапы 1 и 2 будут повторены для вновь поступившего запроса.
Набор действий по реализации этапа 3 заключается в восстановлении контекста прерванной программы. Так же, как и на этапе 1, на данном последнем этапе есть действия, выполняемые микропроцессором автоматически, и действия, задаваемые программистом. Основная задача на этапе 3  — привести стек в состояние, в котором он был сразу после передачи управления данной процедуре. Для этого программист указывает необходимые действия по восстановлению регистров и очистке стека. Этот участок кода необходимо защитить от возможности искажения содержимого регистров (в результате появления аппаратного прерывания) с помощью команды cli. Последние команды в процедуре обработки прерывания — sti и iret, при обработке которых микропроцессор выполняет следующие действия:

  1. sti - разрешить аппаратные прерывания по входу INTR;
  2. iret — извлечь последовательно три слова из стека и поместить их, соответственно, в регистры ip, cs и flags.

В результате этапа 3 управление возвращается очередной команде прерванной программы, которая должна была выполниться, если бы прерывания не было.
Аппаратные прерывания могут быть инициированы программно командой микропроцессора int n, где n - номер аппаратного прерывания в соответствии с таблицей векторов прерываний. При этом микропроцессор также сбрасывает флаг IF, но не вырабатывает сигнал INTA.
После такого обстоятельного обсуждения нам осталось рассмотреть хороший пример. Он должен показать нам ключевые моменты программирования программных и аппаратных прерываний. Выберем одно программное и одно аппаратное прерывание. Наиболее «частое» аппаратное прерывание — прерывание от таймера. Что касается программного прерывания, то основное требование при его выборе для нашего эксперимента то, чтобы его номер не совпадал с номером какого-нибудь системного прерывания.
Программа, которую мы должны будем разработать, выполняет следующие действия: подключает новый аппаратный обработчик прерываний от таймера 08h, который на каждый 4-й сигнал в цикле выводит на экран символы (0-9). Пользовательское прерывание (новый обработчик прерывания 0ffh) вызывается после запуска прерывания от таймера. Его работа заключается в выдаче сигнала сирены циклически несколько раз. После этого пользовательское прерывание производит восстановление вектора старого обработчика прерывания от таймера и завершает свою работу вместе со всей программой.
Перед обсуждением программы нужно сделать следующее замечание. По сути, мы ставим себе цель дополнить программу обработки прерывания от таймера некоторым новым свойством. Одновременно, мы не хотим портить старый обработчик этого прерывания. Такая ситуация встречается довольно часто. Существуют различные способы сцепления системных обработчиков прерываний с пользовательскими. Прерывание от таймера 08h интересно тем, что программа его обработки предусматривает возможность того, что пользователь захочет вставить в обработчик свой код. С этой целью из системной программы обработки прерывания 08h делается вызов еще одного прерывания с номером 1сh. Это пустое прерывание, обработчик которого содержит всего одну команду iret. Таким образом, пользователь имеет возможность решить проблему сцепления своего обработчика с системным обработчиком прерывания 08h косвенно — попросту заменив вектор обработчика прерывания 1сh. Этот прием реализован в листинге ниже (программный код).

Листинг

<1> ;prg15_1.asm
<2> MASM
<3> MODEL small ;модель памяти
<4> STACK 256 ;размер стека
<5> .486p
<6> delay macro time
<7> local ext,iter
<8> ;макрос задержки
<9> ;На входе — значение переменной задержки (в мкс)
<10> push cx
<11> mov cx,time
<12> ext:
<13> push cx
<14> ;в cx одна мкс,это значение можно
<15> ;поменять в зависимости от производительности процессора
<16> mov cx,5000
<17> iter:
<18> loop iter
<19> pop cx
<20> loop ext
<21> pop cx
<22> endm ;конец макроса
<23> .data
<24> tonelow dw 2651 ;нижняя граница звучания 450 Гц
<25> cnt db 0 ;счетчик для выхода из программы
<26> temp dw ? ;верхняя граница звучания
<27> old_off8 dw 0 ;для хранения старых значений вектора
<28> old_seg8 dw 0 ;сегмент и смещение
<29> time_1ch dw 0 ;переменная для пересчета
<30> .code ;начало сегмента кода
<31> off_1ch equ 1ch*4 ;смещение вектора 1ch в ТВП
<32> off_0ffh equ 0ffh*4 ;смещение вектора ffh в ТВП
<33> char db "0" ;символ для вывода на экран
<34> maskf db 07h ;маска вывода символов на экран
<35> position dw 2000 ;позиция на экране — почти центр
<36> main proc
<37> mov ax,@data
<38> mov ds,ax
<39> xor ax,ax
<40> cli ;запрет аппаратных прерываний на время
<41> ;замены векторов прерываний
<42> ;замена старого вектора 1ch на адрес new_1ch
<43> ;настройка es на начало таблицы векторов
<44> ;прерываний — в реальном режиме:
<45> mov ax,0
<46> mov es,ax
<47> ;сохранить старый вектор
<48> mov ax,es:[off_1ch] ;смещение старого вектора 1ch в ax
<49> mov old_off8,ax ;сохранение смещения в old_off8
<50> mov ax,es:[off_1ch+2] ;сегмент старого вектора 1ch в ax
<51> mov old_seg8,ax ;сохранение сегмента в old_seg8
<52> ;записать новый вектор в таблицу векторов прерываний
<53> mov ax,offset new_1ch ;смещение нового обработчика в ax
<54> mov es:off_1ch,ax
<55> push cs
<56> pop ax ;настройка ax на cs
<57> mov es:off_1ch+2,ax ;запись сегмента
<58> ;инициализировать вектор пользовательского прерывания 0ffh
<59> mov ax,offset new_0ffh
<60> mov es:off_0ffh,ax ;прерывание 0ffh
<61> push cs
<62> pop ax
<63> mov es:off_0ffh+2,ax
<64> sti ;разрешение аппаратных прерываний
<65> ;задержка, чтобы новый обработчик таймера вывел символы на экран
<66> delay 3500
<67> ;завершение программы
<68> int 0ffh
<69> exit:
<70> mov ax,4c00h
<71> int 21h
<72> main endp
<73> new_1ch proc ;новый обработчик прерывания от таймера
<74> ;сохранение в стеке используемых регистров
<75> push ax
<76> push bx
<77> push es
<78> push ds
<79> ;настройка ds на cs
<80> push cs
<81> pop ds
<82> ;запись в es адреса начала видеопамяти — B800:0000
<83> mov ax,0b800h
<84> mov es,ax
<85> mov al,char ;символ в al
<86> mov ah,maskf ;маску вывода — в ah
<87> mov bx,position ;позицию на экране — в bx
<88> mov es:[bx],ax ;вывод символа в центр экрана
<89> add bx,2 ;увеличение позиции
<90> mov position,bx ;сохранение новой позиции
<91> inc char ;следующий символ
<92> ;восстановление используемых регистров:
<93> pop ds
<94> pop es
<95> pop bx
<96> pop ax
<97> iret ;возврат из прерывания
<98> new_1ch endp ;конец обработчика
<99> new_0ffh proc ;новый обработчик пользовательского прерывания
<100> sirena:
<101> ;сохранение в стеке используемых регистров
<102> push ax
<103> push bx
<104> ;проверка для пересчета на 4:
<105> test time_1ch,03h
<106> jnz leave_it ;если два правых бита не 11, то на выход, ;иначе:
<107> go:
<108> mov ax,0B06h ;заносим слово состояния 110110110b
<109> ;(0В6h) — выбираем второй канал порта 43h (динамик)
<110> out 43h,ax ;в порт 43h
<111> in al,61h ;получим значение порта 61h в al
<112> or al,3 ;инициализируем динамик — подаем ток
<113> out 61h,al ;в порт 61h
<114> mov cx,2083 ;количество шагов
<115> musicup:
<116> ;значение нижней границы частоты в ax (1193000/2651=450 Гц),
<117> ;где 1193000 — частота динамика
<118> mov ax,tonelow
<119> out 42h,al ;в порт 42h — младшее слово ax:al
<120> mov al,ah ;обмен между al и ah
<121> out 42h,al ;в порте 42h уже старшее слово ax:ah
<122> add tonelow,1 ;увеличение частоты
<123> delay 1 ;задержка на 1 мкс
<124> mov dx,tonelow ;текущее значение частоты — в dx
<125> mov temp,dx ;в temp — верхнее значение частоты
<126> loop musicup ;повторить цикл повышения
<127> mov cx,2083
<128> musicdown:
<129> mov ax,temp ;верхнее значение частоты — в ax
<130> out 42h,al ;младший байт ax:al в порт 42h
<131> mov al,ah ;обмен между al и ah
<132> out 42h,al ;старший байт ax:ah в порт 42h
<133> sub temp,1 ;уменьшение частоты
<134> delay 1 ;задержка на 1 мкс
<135> loop musicdown ;повторить цикл понижения
<136> nosound:
<137> in al,61h ;значение порта 61h — в al
<138> ;слово состояния 0fch — выключение динамика и таймера
<139> and al,0fch
<140> out 61h,al ;в порт 61h
<141> mov dx,2651 ;для последующих циклов
<142> mov tonelow,dx
<143> inc cnt ;инкремент количества проходов
<144> cmp cnt,2 ;если сирена не звучала двух ;раз — повторный запуск
<145> jne go
<146> leave_it: ;выход
<147> inc time_1ch ;пересчет на 4
<148> ;восстановление используемых регистров
<149> pop bx
<150> pop ax
<151> ;восстановление вектора прерывания от таймера
<152> cli ;запрет аппаратных прерываний
<153> xor ax,ax ;снова настройка es на начало таблицы
<154> mov es,ax ;векторов прерываний
<155> mov ax,old_off8 ;запись в таблицу смещения старого
<156> mov es:off_1ch,ax ;обработчика прерывания от таймера
<157> mov ax,old_seg8 ;запись сегмента
<158> mov es:off_1ch+2,ax
<159> sti ;разрешение аппаратных прерываний
<160> iret ;возврат из прерывания
<161> new_0ffh endp ;конец обработчика
<162> end main ;конец программы

Обсудим листинг. Основная процедура main (строки 36-72) выполняет инициализацию используемых векторов прерываний. При этом необходимо запомнить содержимое старого вектора прерывания 1ch (строки 45-51), так как его придется восстанавливать перед завершением программы. Содержимое вектора пользовательского прерывания 0ffh сохранять нет смысла, так как его номер выбран исходя из того, что он не используется при работе системы. При смене вектора прерывания 1сh необходимо запретить обработку аппаратных прерываний командой cli (строка 40), так как внешние прерывания являются асинхронными и могут прийти в самый неподходящий момент, в том числе и во время смены содержимого вектора. Перед завершением работы аппаратного прерывания необходимо явно выдать сигнал EOI. Но в нашем случае это делать необязательно, так как за нас это сделает системный обработчик прерывания 08h, из которого вызывается обработчик для прерывания 1ch. В строках 52-57 и 58-63 производится запись новых значений векторов 1ch и 0ffh в таблицу векторов прерываний. После того как в строке 64 командой sti будут разрешены аппаратные прерывания, на экран будут выведены символы. Эти действия выполняет новая программа обработки прерывания для вектора 1ch (строки 73-98). Эти символы будут выводиться до тех пор, пока действует программная задержка, которую мы организовали в строке 66. После этого вызывается пользовательское прерывание 0ffh, программа обработки которого (строки 99-161) отрабатывает несколько циклов генерации сигнала «сирена» (мы обсуждали эту программу на уроке 7, и теперь вы уже в состоянии оформить ее в виде макроса или процедуры). Вызов программы обработки прерывания пользователя new_0ffh осуществляется с помощью специальной команды int. Эта команда предназначена для того, чтобы пользователь сам мог инициировать вызов прерываний. Как видите, эти прерывания являются планируемыми (синхронными), так как пользователь сам определяет момент его вызова.
После написания этой программы можно провести несколько экспериментов для исследования работы контроллера прерываний и системы прерываний в целом. К примеру, можно выполнить следующие операции:

  • Изменить базовый адрес ведущего контроллера прерываний. Как мы обсуждали выше, BIOS инициализирует ведущий контроллер таким образом, что он имеет базовый адрес 08h. Попробуйте теперь изменить значение базового вектора, например, на значение 0f0h. Для этого необходимо выполнить инициализацию контроллера, которая заключается в последовательной посылке в него управляющих слов. Посмотрите последовательность приказов, которые BIOS посылает в контроллер прерываний для его инициализации при загрузке системы. Нам тоже нужно будет их сформировать, но с нужными нам значениями, и послать в контроллер прерываний. Фрагмент, осуществляющий такие действия, может выглядеть следующим образом:
    ...
    mov al,00010001b
    out 20h,al ;ICW1 в порт 20h
    jmp $+2
    jmp $+2 ;задержка, чтобы успела
    ;отработать аппаратура
    mov al,0f0h
    out 21h,al ;ICW2 в порт 20h — новый базовый номер
    jmp $+2
    jmp $+2 ;задержка, чтобы успела
    ;отработать аппаратура
    mov al,00000100b
    out 21h,al ;ICW3 — ведомый подключается
    ;к уровню 2 (см. рис. 15.1)
    jmp $+2
    jmp $+2 ;задержка, чтобы успела
    ;отработать аппаратура
    mov al,00000001b
    out 21h,al ;ICW4 — EOI выдает
    ;программа пользователя
    Данный фрагмент нужно вставить в начало процедуры main листинга после команды cli. После этого вектору прерывания от таймера будет соответствовать значение 0f0h. Соответственно, если вы хотите, чтобы программа листинга работала как прежде, вам нужно настроить вектор 0f0h на системную программу обработки прерывания 08h. Техника такой замены аналогична приведенной в листинге. После этого можно разрешить прерывания командой sti. Но правильно работать будет только прерывание от таймера, все остальные прерывания (например, от клавиатуры) будут приводить к зависанию компьютера. Если вы подобным образом перепрограммировали контроллер, то перед завершением программы нужно провести обратное перепрограммирование, чтобы вернуть старое значение базового адреса. Если этого не сделать, то работа системы будет нарушена — все аппаратные прерывания будут попадать «не туда».
  • Рассмотреть альтернативу команде cli, замаскировав аппаратные прерывания, используя прямое программирование регистра масок IMR:
    ;запретить прерывания
    mov al,0ffh
    out 21h,al ;для ведущего контроллера
    out A1h,al ;для ведомого контроллера
    ;разрешить прерывания
    mov al,00h
    out 21h,al ;для ведущего контроллера
    out A1h,al ;для ведомого контроллера
    Попробуйте использовать эти команды в листинге вместо команд cli и sti.
  • Запретить аппаратные прерывания определенных уровней. Например, в следующем фрагменте запрещаются прерывания от клавиатуры:
    in al,21h
    or al,00000010b
    out 21h,al
  • Исследовать, как меняется содержимое регистров IRR, IMR и ISR в ходе обработки аппаратного прерывания, читая состояние описанных выше портов. Если у вас проснулся интерес к подобной исследовательской деятельности, то предлагаю вам самостоятельно написать эти фрагменты программ и исследовать их с использованием листинга.



Еще статьи...

  1. Одинадцатое. Итоги

Подкатегории