Текстовый курсор в графическом режиме
Перехват прерываний от таймера
Каждый тик таймера вызывает так называемое аппаратное прерывание. Текущий процесс вычислений приостанавливается и выполняется специальная процедура BIOS. Она обслуживает процессы, синхронизированные с таймером, и вызывает подпрограмму, адрес начала которой указан в векторе ich. Этот вектор специально выделен для нужд прикладных задач. Сразу после загрузки ПК в нем находится адрес команды iret, расположенной в ROM BIOS. Если в прикладной задаче есть подпрограмма, выполнение которой должно быть синхронизировано с таймером, то ее адрес указывается в векторе ich.
Исходное значение вектора ich надо сохранить в теле задачи. Оно нужно для того, чтобы после вашей подпрограммы можно было начать выполнение той программы (внешней по отношению к задаче), адрес которой находился в векторе ich до изменения его содержимого. Такой трюк в литературе называется "перехват вектора прерывания", он широко используется при работе прикладных задач с внешними устройствами.
Для изменения содержимого вектора надо знать его адрес. Векторы пронумерованы начиная с нуля, каждый из них занимает 4 байта оперативной памяти, а нулевой вектор расположен по адресу 0000:0000. Следовательно, умножив номер вектора на 4, мы получим его адрес в оперативной памяти. В нашем случае 4*ich = 70h (4-28 = 7-16 = 112).
В примере 5.25 приведена группа команд, выполняющих перехват вектора ich, неизвестные вам имена переменных описаны ниже в примере 5.27.
Пример 5.25. Сохранение и изменение содержимого вектора 1Ch.
хоr ах, ах; очистка регистра ах mov CurStat, al; запрет построения рисунка курсора mov fs, ax; очистка сегментного регистра fs lea ax, cs:Timeint ах=адрес прерывающей подпрограммы mov bx, cs bx=сегмент прерывающей подпрограммы cli запрещаем прерывания xchg fs:[7Oh], ax перестановка содержимого ах и 7Oh xchg fs:[72h], bx перестановка содержимого bx и 72h mov cs:VeclC, ax \/ес1С=исходное значение слова 70h mov cs:VeclC+2, bx Уес1С+2=исходное значение слова 72h sti разрешаем прерывания
Перехват вектора ich производится в начале выполнения задачи, но после того, как подготовлено все необходимое для корректной работы прерывающей подпрограммы. В нашем случае имя прерывающей подпрограммы Timeint, а для ее корректной работы надо запретить построение рисунка текстового курсора. Для этого вторая команда примера очищает переменную CurStat.
Для доступа к словам вектора прерывания очищается один из сегментных регистров, в примере 5.25 это регистр fs, его очищает третья команда. Затем в регистры ах и bx записываются адрес прерывающей подпрограммы и сегмент, в котором она находится. Прежде чем изменять содержимое вектора, надо запретить прерывания. Это делается потому, что выполнение задачи никак не синхронизировано с таймером и прерывание от последнего может произойти в тот момент, когда задача начала, но еще не завершила изменение и запоминание содержимого вектора ich.
Прерывание запрещает команда cli, после нее производится обмен содержимого (xchg) слов вектора и регистров ах и bx. В результате в словах вектора ich окажется новый, а в регистрах ах и bx старый адрес, который надо запомнить. Следующие две команды пересылают старый адрес в слова vecic и vecic+2, после чего команда sti разрешает прерывания.
Восстановление вектора прерывания
Перед завершением задачи восстанавливается исходное значение вектора ich, т. е. подпрограмма Timeint исключается из списка заданий таймеру. Если это не сделать, то при первом же тике таймера произойдет обращение к области памяти, в которой уже нет прерывающей подпрограммы, что приведет к аварийной ситуации.
В примере 5.26 приведена группа команд, выполняющих восстановление исходного значения вектора ich. Эти команды могут быть выполнены непосредственно перед завершением задачи, т. е. перед возвратом в DOS.
Пример 5.26. Восстановление исходного содержимого вектора 1Ch.
хоr ах, ах; очистка регистра – ах mov fs, ax; очистка сегментного регистра fs mov ax, cs:VeclC; ax = содержимое VeclC mov bx, cs:VeclC+2; bx = содержимое VeclC+2 cli; запрещаем прерывания mov fs: [70h], ax; восстановление 1-го слова вектора mov fs: [72h],bx; восстановление 2-го слова вектора sti; разрешаем прерывания