- •Системное программирование
- •Контрольные вопросы
- •2. Программная модель микропроцессора 8086
- •2.1. Представление информации
- •2.2. Регистры микропроцессора
- •2.3. Формат машинной команды
- •2.4. Способы задания операндов команды
- •Контрольные вопросы
- •3. Основные понятия языка ассемблера
- •3.1. Предложения
- •3.2. Директивы определения данных
- •3.3. Выражения
- •Контрольные вопросы
- •4. Сегментированная модель памяти
- •4.1. Сегментирование адресов
- •4.2. Директивы сегментации
- •4.3. Общая структура программы
- •4.4. Модели памяти
- •Контрольные вопросы
- •5. Основные группы команд
- •5.1. Соглашению по описанию команд
- •5.2. Команды пересылки данных
- •5.3. Арифметические команды
- •5.4. Логические команды
- •5.5. Команды переходов
- •5.6. Команды организации циклов
- •5.7. Команды обработки строк
- •5.8. Стековые команды
- •5.9. Команды ввода-вывода
- •5.10. Команды прерываний
- •5.11. Команды управления микропроцессором
- •Контрольные вопросы
- •6. Подпрограммы
- •Контрольные вопросы
- •7. Разработка одномодульной программы
- •7.1. Трансляция и компоновка программы
- •7.2. Отладка программы
- •Контрольные вопросы
- •8. Разработка многомодульных программ
- •8.1. Принципы разработки модулей
- •8.2. Расширенное применение директивы сегментации
- •9. Упражнения
- •Контрольные вопросы
- •Программирование микропроцессорных устройств
- •10. Программирование системного таймера
- •10.1. Описание таймера-счетчика 8254
- •10.2. Режимы работы таймера
- •10.3. Структура регистров таймера
- •10.4. Упражнения
- •Контрольные вопросы
- •11. Программирование контроллера прерываний
- •11.1. Механизм обработки прерываний
- •11.2. Типы прерываний
- •11.3. Приоритеты прерываний
- •11.4. Контроллер прерываний 8259
- •11.5. Идентификация прерываний
- •11.6. Прерывания bios и ms-dos
- •11.7. Упражнения
- •Контрольные вопросы
- •12. Программирование параллельного порта
- •12.1. Интерфейс Centronics
- •12.2. Работа с параллельным портом на низком уровне
- •12.3. Стандартные средства работы с параллельным портом
- •12.4. Упражнения
- •Контрольные вопросы
- •13. Программирование последовательного порта
- •13.1. Основы последовательной передачи данных
- •13.2. Последовательный интерфейс rs-232c
- •13.3. Универсальный асинхронный приемо-передатчик 8250
- •13.4. Порты асинхронного адаптера
- •13.5. Стандартные средства программирования последовательного порта
- •13.6. Упражнения
- •Контрольные вопросы
- •Литература
- •141 Кафедра Вычислительной Техники и Программирования Московского Государственного Открытого Университета
11.7. Упражнения
Пример 1. Привести пример блокировки дискового прерывания.
Решение. Для блокировки дискового прерывания необходимо маскировать 6-й разряд регистра маски IMR контроллера прерываний, соответствующий линии IRQ6. После выполнения операций, требующих маскирования дискового прерывания, следует обязательно очистить регистр IMR, иначе обращения к дискам будет невозможно.
MOVAL, 01000000b; маскируем 6-й бит регистра маски
OUT21h,AL; передаем код в регистр маски прерываний
... ; выполнение операций, требующих маскирования прерывания
MOVAL, 0 ; код очистки регистра маски прерываний
OUT21h,AL; передаем код в регистр маски прерываний
Пример 2. Привести пример замены векторы прерывания с помощью функций MS-DOS.
Решение. В практике разработки системных программ часто возникают необходимость дополнения существующего или создания собственного обработчика прерывания. Перед установкой нового вектора прерывания следует получить текущее значение вектора, сохранить его, а затем восстановить перед завершением программы.
Функция 35h прерывания 21h возвращает текущее значение вектора прерывания, помещая адрес сегмента в ES, а смещения в BX. Функция 25h прерывания 21h позволяет установить вектор прерывания на определенный адрес, указанный регистровой парой DS:DX. Заметим также, что обе функции автоматически запрещают аппаратные прерывания на время изменения вектора, поэтому не существует опасности, что может произойти аппаратное прерывание, использующее данный вектор.
В приведенном примере изменяется вектор прерывания клавиатуры 09h. Код завершения подпрограммы обработки прерывания перед инструкцией IRET необходим только для аппаратного прерывания. Для обработчиков, являющихся расширениями существующих прерываний, код завершения не нужен.
; сегмент данных
OldInterruptSegmentDW? ; адрес сегмента заменяемого вектора прерывания
OldInterruptOffsetDW? ; адрес смещения заменяемого вектора прерывания
; в начале программы
MOVAH,35h ; номер функции для получения вектора
MOVAL,09h ; номер запрашиваемого вектора прерывания
INT21h ; выполнение функции получения адреса вектора
MOVOldInterruptOffset,BX; сохранение адреса смещения вектора
MOVOldInterruptSegment,ES; сохранение адреса сегмента вектора
; установка нового прерывания
PUSHDS; сохранение в стеке содержимогоDS
MOVDX,OFFSETRoutine ; помещение в DX смещения процедуры обработки
MOVAX,SEGRoutine ; помещение в AX сегмента процедуры обработки
MOVDS,AX; передаем вDSадрес сегмента
MOVAH,25h ; номер функции для установки вектора
MOVAL,09h ; номер изменяемого вектора
INT21h ; изменение вектора прерывания
POPDS; восстановление из стека прежнего содержимогоDS
; новый обработчик прерывания 9h
RoutinePROCFAR; объявление подпрограммы обработчика как дальней
PUSHA; сохранение регистров в стеке
... ; выполнение кода подпрограммы обработки прерывания
POPA; восстановление регистров
MOVAL,20h ; завершение обработки аппаратного прерывания
OUT20h,AL; передаем код в регистр обслуживания прерывания
IRET; возврат из процедуры обработки прерывания
RoutineENDP; завершение подпрограммы
; восстановление прежнего прерывания
PUSHDS; сохранение в стеке регистра DS
MOVDX,OldInterruptOffset; помещение в DX смещение прежнего вектора
MOVAX,OldInterruptSegment; помещение в AX сегмента прежнего вектора
MOVDS,AX; передаем адрес сегмента в регистр DS
MOVAH,25h ; номер функции для установки вектора
MOVAL,09h ; номер изменяемого вектора
INT21h ; восстановление прежнего вектора
POPDS; восстановление из стека регистра DS
Пример 3. Используя ассемблер TASM, разработать резидентную программу: общую структуру, загрузчик и резидентную часть. Функциональность резидентной части может быть произвольной. Использовать режим работы ассемблера IDEAL. В качестве прерывания использовать программное прерывание от системного таймера 1Ch. Предусмотреть возможность завершения работы резидентной программы по клавишной комбинации «Ctrl+x».
Решение. Изменение строки таблицы векторов прерываний или иначе подмена прерывания дает возможность создания резидентных программ TSR (Terminate and Stay Resident, завершить и оставить резидентным). Такие программы, постоянно расположены в памяти и выполняют работу в фоновом режиме. Примером таких программ могут быть, например, драйвера клавиатуры, дисплея, различных периферийных устройств.
Для создания резидентной программы необходимо переопределить вектор прерывания. Новый обработчик прерывания либо полностью заменяет стандартный, либо только дополняет его. Во втором случае обработчику управление может быть передано до выполнения стандартной подпрограммы обработки прерывания, либо после.
Прерывание по таймеру имеет наивысший приоритет IRQ0, поэтому оно будет вытеснять любые другие прерывания до тех пор, пока не будут заблокированы все прерывания командой CLI. Микросхема таймера получает сигналы от часов с частотой 1.19 МГц. Прерывание по таймеру возникает, когда внутренний счетчик микросхемы таймера обнулится. Первоначально счетчик устанавливается в 65535 и при получении очередного импульса его значение уменьшается на 1. Поэтому прерывания происходят с частотой 18.2Гц.
Микросхема контроллера прерываний в ответ на запрос генерирует прерывание INT 8, которое обслуживает программа BIOS. После обновления времени суток и выполнения ряда других служебных действий, программа BIOS выполняет команду INT 1Ch, программное прерывание, называемое прерыванием пользователя по таймеру.
По умолчанию подпрограмма обработки прерывания INT 1Сh содержит единственную команду возврата из прерывания IRET. Программы, которые должны выполняться периодически, могут установить свою собственную подпрограмму обработки прерывания INT 1Сh. После ее выполнения управление вновь будет передано процедуре обработки времени суток INT 8. Схема расширения прерывания таймера показана на рис. 43.
Рис. 43. Расширение прерывания таймера.
Определим теперь составные части TSR. Прежде всего, необходимо выделить подпрограмму установки и резидентную часть. Резидентная часть находится перед установщиком, т.к. ее адрес должен быть известен заранее. В свою очередь установщик состоит из загрузчика и программы выгрузки. Загрузчик должен сохранить старый вектор, установить новый вектор прерывания и завершить программу, оставив ее резидентной (рис. 44).
Резидентная часть обработчика определяет функциональность TSR. Она может быть произвольной, поэтому мы ее приводить не будем и оставим читателю для самостоятельной работы. Обработчики прерываний должны быть дальними процедурами, которые сохраняют в стеке состояние всех регистров перед началом выполнения и восстанавливают их по окончанию работы.
Рис. 44. Алгоритм подпрограммы установки.
Рис. 45. Алгоритм обработчика прерывания 1Ch.
Если обработчик прерывания полностью заменяет стандартный обработчик аппаратного прерывания, то перед возвратом он должен сообщить контроллеру прерываний об окончании обработки, чтобы разрешить аппаратные прерывания нижних уровней. Если обработчик только дополняет старый обработчик прерывания, то он должен содержать его вызов. Для определенности выберем вариант полной замены существующего обработчика.
Алгоритм работы нового обработчика прерывания от таймера приведен на рис. 45.
Каждой клавише соответствует определенный числовой код, так называемый скан-код. Этот код посылает контроллер клавиатуры 8048 микросхеме интерфейса с периферией 8255. Скан-код однобайтовый, младшие 7 бит которого представляют идентификационный номер, присвоенный каждой клавише, а старший бит определяет состояние клавиши (1 – клавиша нажата, 0 – отпущена).
Завершение работы резидентной части должно происходить по клавишной комбинации «Ctrl+x». В нашем примере скан-код для левой нажатой клавиши «Ctrl» равен 1Dh, а для отпущенной клавиши – 9Dh. Для клавиши «x» (не символа) соответствующие коды равны 2Dh и 0Ah. Прерывание клавиатуры 9h преобразует скан-коды в ASCII коды и устанавливает статус клавиш переключателей. Получить скан-код можно, обратившись к микросхеме 8255 по адресу 60h.
Следовательно, отследить клавишную комбинацию «Ctrl+x» можно таким образом. Зафиксировать факт нажатия левой клавиши «Ctrl», например, с помощью специальной переменной (флага). Флаг устанавливается в 1 при получении скан-кода 1Dh и сбрасывается в 0 при коде 9Dh. Затем следует периодически проверять код нажатой клавиши. При скан-коде 2Dh и установленном флаге имеет место требуемая клавишная комбинация.
Возможный вариант реализации программы TSR приведен ниже.
IDEAL
MODEL MEDIUM
STACK 100h
DATASEG
; Флаг состояния левой клавиши Ctrl
LeftCtrlONDB0
; Область сохранения старого вектора прерывания
OldTimerInterruptOffsetDW?
OldTimerInterruptSegmentDW?
ENDS
CODESEG
; Основной модуль программы
PROCTimerTest
; Инициализировать регистр DS
MOVAX,DGROUP
MOVDS,AX
; Установить новый обработчик прерывания
CALLSetTimerInterrupt
; Передать управление MSDOS и оставить резидентным
INT27h
ENDPTimerTest
; Новый обработчик прерывания
PROCTimerInterruptFAR
; Сохранить регистры общего назначения
PUSHA
PUSHDS
; Инициализировать регистр DS
MOV AX,DGROUP
MOV DS,AX
; Получить скан-код
INAL,60h
; Разрешить прерывания с более низким уровнем
MOV AL,20h
OUT 20h,AL
; Нажата клавиша Ctrl?
CMP AL,1Dh
JZ@@on
; Отпущена клавиша Ctrl?
CMPAL,9Dh
JNZ@@x
; Сбросить флаг левой клавиши Ctrl
MOV[LeftCtrlON],0
JMPSHORT@@go
; Установить флаг левой клавиши Ctrl
@@on:MOV [LeftCtrlON],1
JMP SHORT @@go
; Нажата клавиша «x»?
@@x:CMPAL,2Dh
JNZ@@go
; Нажата левая клавиша Ctrl?
CMP[LeftCtrlON],1
JNZ@@go
; Восстановить прежний обработчик прервания
CALL RestoreOldTimerInterrupt
JMP SHORT @@exit
@@go:... ; «Полезная» часть резидента
@@exit: ; Завершить обработку прерывания
POPDS
POPA
; Выход из обработчика прерывания
IRET
ENDPTimerInterrupt
; Установить новый вектор прерывания
PROC SetTimerInterrupt NEAR
PUSHA
PUSH ES
MOVAX,0
MOVES,AX
; Запомнить прежний вектор обработчика прерывания
MOV AX,[ES:1Ch*4]
MOV [OldTimerInterruptOffset],AX
MOV AX,[ES:1Ch*4+2]
MOV [OldTimerInterruptSegment],AX
; Установка вектора прерывания на обработчик
CLI; Запретить прерывания
MOV AX,offset TimerInterrupt
MOV [ES:1Ch*4],AX
MOV AX,CS
MOV [ES:1Ch*4+2],AX
STI; Разрешить прерывания
POPES
POPA
RET
ENDPSetTimerInterrupt
; Восстановить исходный вектор прерывания
PROCRestoreOldTimerInterruptNEAR
PUSHA
; Настроить регистр ES на таблицу векторов прерываний
PUSH ES
MOV AX,0
MOV ES,AX
; Восстановить прежний вектор обработчика прерывания
CLI
MOV AX,[OldTimerInterruptOffset]
MOV [ES:1Ch*4],AX
MOV AX,[OldTimerInterruptSegment]
MOV [ES:1Ch*4+2],AX
STI
POP ES
POPA
RET
ENDP RestoreOldTimerInterrupt
ENDS
END
В сегменте данных объявлен флаг состояния левой клавиши Ctrl и выделена область для хранения вектора 1Ch. Кодовый сегмент включает несколько подпрограмм. Подпрограмма TimerTest получает управление первой. Она совсем проста и единственное, что выполняет – вызов процедуры SetTimerInterrupt и затем передает управление операционной системе с помощью прерывания 27h.
В свою очередь процедура SetTimerInterrupt устанавливает новый вектор прерывания 1Ch. Здесь и далее в процедуре RestoreOldTimerInterrupt используется иной способ замены вектора. Вместо функций 25h и 35h, рассмотренных в примере 2, показано вычисление вектора 1Ch и установка нового обработчика прерывания.
Резидентная часть представлена подпрограммой TimerInterrupt. Вначале анализируется комбинация «Ctrl+x» и разрешаются прерывания с более низким приоритетом. Если комбинация не выбрана, управление передается на выполнение «полезной» части резидента. Затем происходит выход из подпрограммы обработки прерывания. Если клавишная комбинация выбрана, происходит вызов процедуры RestoreOldTimerInterrupt для восстановления прежнего вектора 1Ch.
Рассмотренный пример резидентной программы имеет достаточно общий характер. Тем не менее, его можно относительно легко адаптировать для решения задач в области измерительной техники. Например, применение алгоритмов программирования плат сбора данных в рамках обработчика TimerInterrupt позволит создать драйвер измерительного устройства. В его ведение может, например, входить выполнение оцифровки сигналов, поступающих от измерительных преобразователей и их первичная обработка. Причем работать драйвер будет в фоновом режиме под операционной системой MS-DOS.