----------------------------------------------------------------
FGCombo EQU KB_M_Alt OR KB_M_LShift
BKG_C_FG EQU 1
BKG_C_BG EQU 2
BIOS SEGMENT at 40h
ORG 17h
KB_B_Flag DB 0
BIOS ENDS
_text SEGMENT BYTE PUBLIC 'code'-
PgmState DB 0
BusyFlag DB -1 ; запрет прерывания
; нереентерабельная часть программы
OldInt9 DD 0 ; сохранение первоначальной ISR int9
PopupPending DB 0 ; приращение, если запрос не
; может быть обслужен
ASSUME ds:NOTHING
Int9ISR PROC FAR
NewInt9:
pushf ;;; моделирование прерывания
call cs:OldInt9 ;;; вызов первоначальной ISR
cmp cs:PgmState,BKG_C_BG ;;; фоновая программа?
jz i9_0 ;;; если z - да
iret ;;; не выбирать из стека, если нет
i9_0 pushr ;;; доступ к B_Flag
mov ax,SEG BIOS
mov ds,ax
ASSUME ds:BIOS
mov al,KB_B_Flag;;; al <== текущие флаги KB
and al,FGCombo ;;; маска всех ненужных битов
cmp al,FGCombo ;;; запрошена выборка из стека?
popr
- 4-14 -
ASSUME ds:NOTHING
jnz Int9Exit1 ;;; если NZ - нет запроса
;;; выборки из стека
inc cs:PopupPending ;;; выборка из стека запрошена
call DOSSafeCheck ;;; можно ее делать?
jc Int9Exit0 ;;; если с - нет
call BKGResume ; вызов приоритетной программы
Int9Exit0:
dec cs:BusyFlag ; выпуск программы
Int9Exit1:
iret ; отмена прерывания
Int9ISR ENDP
_text ENDS
----------------------------------------------------------------
Альтернатива для перехвата Int 1Сh
Важно заметить, что ISR Int 1Сh вложена в ISR Int 8, так как
прерывание по времени имеет высший приоритет; никакие прерывания
не обслуживаются, пока контроллер прерываний не получит EOI (ко-
нец прерывания). Любые команды, которые зависят от прерываний, не
будут работать. Другой потенциальной проблемой является то, что
DOS будет терять такты таймера, если он будет слишком долго путе-
шествовать по цепочке int 1Сh. PRINT.COM решает эту проблему пе-
ресылкой EOI в свой int 1Сh ISR.
Альтернативной стратегией является перехват int 8. Новая int 8
ISR сразу вызывает старую ISR, которая посылает EOI контроллеру
прерываний перед возвращением. ISR, приведенная на листинге 4-8
работает вместе с приведенной на листинге 4-7. Если горячий ключ
не обработан, или если с последней активации прошла 1 секунда, то
для реактивации TSRint 8 ISR вызывает BKGResume.
Листинг 4-8. Пример замены прерывания по времени ISR int 8
----------------------------------------------------------------
OldInt8 DD 0 ; сохранение кода инициализации
; начальный адрес ISR int 8
BusyFlag DB -1 ; запрет прерывания
; нереентерабельная секция
; программы
PopupPending DB 0 ; не 0, если встретилась нажатая клавиша
Ticks DB 18 ; выполняется один раз в секунду
Int8ISR PROC FAR
NewInt8:
pushf ;;; моделирование прерывания
call cs:OldInt8 ;;; посылка кода ROM
cli ;;; не является необходимым
cmp cs:PopPending,0 ;;; ожидание запроса выборки?
jnz i8_0 ;;; если не 0 - да
cmp cs:Ticks,0 ;;; счетчик тактов = 0?
jz i8_0 ;;; если 0 - да
dec cs:Ticks ;;; иначе - уменьшение его
jnz Int9Exit1 ;;; если еще не 0 - продолжение
i8_0 call DOSSafeCheck ;;; OS не испорчена?
jc Int8Exit0 ;;; если c - нет
- 4-15 -
;;; заметим, что отметка времени
;;; остается на 0, попытаемся
;;; сохранить для передачи
;;; каждую отметку
call BKGResume ; передача фоновой программе
mov cs:Ticks,18 ; сброс счетчика
Int8Exit0:
dec cs:BusyFlag ; закрыть
Int8Exit1:
iret ; возврат
Int8ISR ENDP
----------------------------------------------------------------
Управление отображением на экране
Учитывая ранее приведенные ограничения в сервисе видео
ROM-BIOS, для непосредственного управлении аппаратурой отображе-
ния на экран часто требуется TSR. Прямое чтение и запись на эк-
ран ускоряют процесс переключения дисплеев, когда горячий ключ
активизирует TSR, устраняет проблему, связанную с изменением меж-
ду текстовым и и графическим режимами, может уменьшить прямой
доступ к контроллеру 6845 CRT.
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
ПРЕДУПРЕЖДЕНИЕ:
Прямой доступ к аппаратуре отображения может быть опасен.
Ошибка при такой обработке может разрушить Ваш монитор.
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
Перед тем, как попытаться программировать дисплей, надо себе
представлять, как он работает. Нижеследующее обсуждение является
просто обзором; подробнее см. в "Hardware Technical Reference
Manual".
Есть два способа для изменения содержимого экрана. Один спо-
соб заключается в поддержке двух буферов: один из них содержит
образ экрана TSR, а другой - образ экрана приложений DOS. Второй
способ замещает видео-память одного из этих буферов; это сохраня-
ет некоторую память за счет незначительного замедления ответа.
Листинг 4-9 демонстрирует способ дублирования буферов. При
нажатии горячего ключа текущий экран копируется в буфер приложе-
ний DOS, и затем содержимое буфера TSR перемещается в память
дисплея. Вы можете в этот момент пересылать больший блок данных,
так что используйте команду пересылки строк. Расчет временных
циклов предполагает, что эта процедура займет около 21 мс для вы-
полнения на 8088 процессоре с частотой 4.77 MHz. Реальные замеры
дают около 29 мс. Разница частично вызвана погрешностями метода
расчета временных циклов; остальное относится за счет одновремен-
ного обращения к неразделяемому ресурсу. Замер времени был сделан
при включенном дисплее - в худшем варианте.
Листинг 4-9. Переключение экранов
с использованием двух буферов
----------------------------------------------------------------
_text SEGMENT WORD PUBLIC 'CODE'
- 4-16 -
ASSUME cs:_text, ds:_text, es:_text
VideoSEG DW 0b000h
DOSBuffer DW 25*80 DUP (0)
TSRBuffer DW 25*80 DUP (720h)
Switct PROC NEAR
cld ; флаг направления <== UP
lea di,DOSBuffer ; di <== смещение буфера
mov ax,cs
mov es,ax ; es:di <== буфер DOS
xor si,si ; si <== смещение видео
mov ds,VideoSEG ; ds:si <== память видео
mov cx,25*80 ; cx <== слова на отображении
rep movsw ; DOSBuffer <== память видео
mov ds,ax
lea si,TSRBuffer ; ds:si <== буфер TSR
mov es,VideoSEG ;
xor di,di ; es:di <== видео память
mov cx,25*80 ; cx <== слова на отображении
rep movsw ; память видео <== буфер TSR
ret
Switch ENDP
----------------------------------------------------------------
.Следующий листинг использует только один буфер. Использова-
ние отдельного буфера замедляет последовательность mov/xchg и
требует для изменения экрана при включенном дисплее приблизитель-
но 45 мс. Такая производительность вполне приемлема. Заметим, что
выравнивание буфера по границе параграфа обходится в дополнитель-
ную команду add, но это изменение не влияет на производитель-
ность.
Листинг 4-10. Переключение экрана
с использованием отдельного буфера
----------------------------------------------------------------
_text SEGMENT WORD PUBLIC 'CODE'
ASSUME cs:_text, ds:_text, es:_text
VideoSEG DW 0b000h
TSRBuffer DW 25*80 DUP (720h)
Switch PROC NEAR
cld ; проверка, что мы подвинулись
lea si,TSRBuffer ; si <== смещение буфера TSR
xor di,di ; di <== смещение видеопамяти
mov bx,2 ; bx <== размер сдвига
mov es,VideoSEG ; ds:si <== видеопамять
mov cx,25*80 ; cx <== слова на экране
_nb mov ax,[si] ; ax <== слово из буфера TSR
xchg ax,es:[di] ; видеопамять <== буфер TSR
; ax <== слово из видеопамяти
mov [si],ax ; буфер TSR <== видеопамять
аdd si,bx
add di,bx
loop _nd
ret
- 4-17 -
Switch ENDP
----------------------------------------------------------------
Работа в среде DOS
Многие команды Вашего TSR требуют для выполнения взаимо-
действия с DOS. DOS в своей основе является однопользовательской/
/однопрограммной операционной системой.
Хотя Майкрософт добавила некоторое программное обеспечение
для поддержки TSR, многие из них не документированы и трудны для
использования. Мы часто склонны делать резидентными программы,
которые просто реализовать в обычной программе переднего плана. В