Меню сайта

Урок 177. Возврат программы в DOS с сохранением ее резидентности ( 2 Часть )

— —— -Эта программа вызывает 4660 раз в секунду

— — — — — — — — — — — -0196 — — — — — — — — — — — — — — — — — — — — — — — TIMER_HANDLER — — — PROC FAR
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — -ASSUME -CS:CODE,DS:nothing,ES:nothing
— — — — — — — — — — — -0196 — — — — — 50 — — — — — — — — — — — — — — — — — — — — — PUSH AX
— — — — — — — — — — — -0197 — — — — — 53 — — — — — — — — — — — — — — — — — — — — — PUSH BX
— — — — — — — — — — — -0198 — — — — — 2E: 8B 1E 015E R — — — — — — — MOV — BX,BUFFER_HEAD
— — — — — — — — — — — -019D — — — — — 2E: 3B 1E 0160 R — — — — — — — CMP — BX,BUFFER_TAIL — Есть ли что-нибудь в буфере?
— — — — — — — — — — — -01A2 — — — — — 75 14 — — — — — — — — — — — — — — — — — — JNZ — TEST_READY — Переход,еслибуфер не пуст

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — ——- -Эта подпрограмма управляет таймером в скоростном режиме

— — — — — — — — — — — -01A4 — — — — — — — — — — — — — — — — — — — — — — — TIMER_RETURN:
— — — — — — — — — — — -01A4 — — — — — 5B — — — — — — — — — — — — — — — — — — — — — POP — BX
— — — — — — — — — — — -01A5 — — — — — 2E: FE 06 015D R — — — — — — — INC — TIMER_COUNT — — — — — — Увеличение счетчикаделителя таймера
— — — — — — — — — — — -01AA — — — — — 75 06 — — — — — — — — — — — — — — — — — — JNZ — SKIP_NORMAL
— — — — — — — — — — — -01AC — — — — — 58 — — — — — — — — — — — — — — — — — — — — — POP — AX — — — — — — — — — Это выполняется один раз на 256прерываний
— — — — — — — — — — — -01AD — — — — — 2E: FF 2E 0107 R — — — — — — — JMP — TIMER_VECTOR — — — — — Переход на стандартнуюпрограмму обработки
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — -прерывания от таймера
— — — — — — — — — — — -01B2 — — — — — — — — — — — — — — — — — — — — — — — SKIP_NORMAL:
— — — — — — — — — — — -01B2 — — — — — B0 20 — — — — — — — — — — — — — — — — — — MOV — AL,20H
— — — — — — — — — — — -01B4 — — — — — E6 20 — — — — — — — — — — — — — — — — — — OUT — 20H,AL — — — — Конец прерывания
— — — — — — — — — — — -01B6 — — — — — 58 — — — — — — — — — — — — — — — — — — — — — POP — AX
— — — — — — — — — — — -01B7 — — — — — CF — — — — — — — — — — — — — — — — — — — — — IRET

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — ——- -Символ в буфере,производится попытка напечатать его

— — — — — — — — — — — -01B8 — — — — — — — — — — — — — — — — — — — — — — — TEST_READY:
— — — — — — — — — — — -01B8 — — — — — 52 — — — — — — — — — — — — — — — — — — — — — PUSH DX
— — — — — — — — — — — -01B9 — — — — — 1E — — — — — — — — — — — — — — — — — — — — — PUSH DS
— — — — — — — — — — — -01BA — — — — — 2B D2 — — — — — — — — — — — — — — — — — — SUB — DX,DX
— — — — — — — — — — — -01BC — — — — — 8E DA — — — — — — — — — — — — — — — — — — MOV — DS,DX — — — — — — — — — — — — Установкарегистра DS на сегмент ABS0
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — -ASSUME -DS:ABS0
— — — — — — — — — — — -01BE — — — — — 8B 16 0408 R — — — — — — — — — — — — — — — — — MOV — DX,PRINTER_BASE
— — — — — — — — — — — -01C2 — — — — — 42 — — — — — — — — — — — — — — — — — — — — —
INC — DX — — — — — — — — — Установка на порт состояния
— — — — — — — — — — — -01C3 — — — — — EC — — — — — — — — — — — — — — — — — — — — — IN — — AL,DX
— — — — — — — — — — — -01C4 — — — — — A8 80 — — — — — — — — — — — — — — — — — — TEST AL,80H — — — — Проверкаготовности принтера
— — — — — — — — — — — -01C6 — — — — — 74 16 — — — — — — — — — — — — — — — — — — JZ — — NO_PRINT
— — — — — — — — — — — -01C8 — — — — — 4A — — — — — — — — — — — — — — — — — — — — — DEC — DX — — — — — — — — — Установка на порт данных
— — — — — — — — — — — -01C9 — — — — — 2E: 8A 07 — — — — — — — — — — — — — — MOV — AL,CS:[BX] — Выбркавыводимого символа
— — — — — — — — — — — -01CC — — — — — E8 01E2 R — — — — — — — — — — — — — — CALL ADVANCE_POINTER
— — — — — — — — — — — -01CF — — — — — 2E: 89 1E 015E R — — — — — — — MOV — BUFFER_HEAD,BX
— — — — — — — — — — — -01D4 — — — — — EE — — — — — — — — — — — — — — — — — — — — — OUT — DX,AL — — — — — — — — — — — — Вывод символа в порт принтера
— — — — — — — — — — — -01D5 — — — — — 83 C2 02 — — — — — — — — — — — — — — — ADD — DX,2 — — — — — — — Установка напорт управления
— — — — — — — — — — — -01D8 — — — — — B0 0D — — — — — — — — — — — — — — — — — — MOV — AL,0DH
— — — — — — — — — — — -01DA — — — — — EE — — — — — — — — — — — — — — — — — — — — — OUT — DX,AL — — — — — — — — — — — — Передача символа изпорта в принтер
— — — — — — — — — — — -01DB — — — — — B0 0C — — — — — — — — — — — — — — — — — — MOV — AL,0CH
— — — — — — — — — — — -01DD — — — — — EE — — — — — — — — — — — — — — — — — — — — — OUT — DX,AL
— — — — — — — — — — — -01DE — — — — — — — — — — — — — — — — — — — — — — — NO_PRINT:
— — — — — — — — — — — -01DE — — — — — 1F — — — — — — — — — — — — — — — — — — — — — POP — DS
— — — — — — — — — — — -01DF — — — — — 5A — — — — — — — — — — — — — — — — — — — — — POP — DX
— — — — — — — — — — — -01E0 — — — — — EB C2 — — — — — — — — — — — — — — — — — — JMP — TIMER_RETURN — — — — — Возвратчерез подпрограмму управления
— — — — — — — — — — — -01E2 — — — — — — — — — — — — — — — — — — — — — — — TIMER_HANDLER — — — ENDP — — — — — — — -таймером

— — — — — — — — — — — -01E2 — — — — — — — — — — — — — — — — — — — — — — — ADVANCE_POINTER PROC — — NEAR
— — — — — — — — — — — -01E2 — — — — — 43 — — — — — — — — — — — — — — — — — — — — — INC — BX — — — — — — — — — Сдвиг указателя

— — — — — — — — — — — — — — — — — — — — — — — -Фиг. 10.1 Буфер печати (продолжение)
— — — — — — — — — — — -01E3 — — — — — 81 FB 28FE R — — — — — — — — — — — — — — — — — CMP — BX,offset BUFFER_END
— — — — — — — — — — — -01E7 — — — — — 75 04 — — — — — — — — — — — — — — — — — — JNE — ADVANCE_RETURN — — Проверкана конец циклического буфера
— — — — — — — — — — — -01E9 — — — — — 8D 1E 01EE R — — — — — — — — — — — — — — — — — LEA — BX,BUFFER_START — Установка указателя на начало буфера
— — — — — — — — — — — -01ED — — — — — — — — — — — — — — — — — — — — — — — ADVANCE_RETURN:
— — — — — — — — — — — -01ED — — — — — C3 — — — — — — — — — — — — — — — — — — — — — RET
— — — — — — — — — — — -01EE — — — — — — — — — — — — — — — — — — — — — — — ADVANCE_POINTER ENDP

— — — — — — — — — — — -01EE — — — — — — — — — — — — — — — — — — — — — — — BUFFER_START — — — — LABEL — — — — — BYTE
— — — — — — — — — — — -01EE — — — — — 2710[ — — — — — — — — — — -&nbs
p- — — — — — — DB — — 10000 DUP (?)
— — — — — — — — — — — — — — — — — — — — — ??
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — ]

— — — — — — — — — — — -28FE — — — — — — — — — — — — — — — — — — — — — — — BUFFER_END LABEL — — — — — BYTE
— — — — — — — — — — — -28FE — — — — — — — — — — — — — — — — — — — — — — — CODE ENDS

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — -END
— — — — — — — — — — — Фиг. 10.1 Буфер печати (продолжение)

— — — — — Приведенная в примере программа можетоблегчить решение задачи.
— — — Конечно, это не обойдется вам даром.Программа отводит под буфер
— — — печати некоторую область памяти, котраябудет постоянно за ним
— — — закреплена. DOS изымает эту область изобщего объема памяти,
— — — предоставляемой пользователю. Например,если в системе 96K байт
— — — памяти, а 10 кбайт отводится под буферпечати, то пользоваться
— — — Макроассемблером уже не удастся. Длямакроассемблера требуется 96
— — — кбайт, а после создания буфера печатиостанется лишь 86 кбайт.
— — — Поэтому, прежде чем организоватьбуферизацию печати, убедитесь, что
— — — в системе останется еще достаточный объемпамяти.

— — — — — Буферизация печати осуществляется примернотак. Стандартная
— — — команда PRINT (INT 17H) заменяетсяпроцедурой, которая помещает
— — — символы в буфер вместо того, чтобыпосылать их на принтер. Эта
— — — часть программы и называется буферизациейпечати. Отдельная часть
— — — программы, называемая выводом на печать,извлекает символы из
— — — буфера печати и пересылает их на принтер.

— — — — — Основным моментом в данном примереявляется замена прерывания
— — — INT 17H базовой системы ввода-вывода.Почти все прикладные
— — — программы для вывода на печать используютименно это прерывание, а
— — — это означает, что теперь все обычныеоперации печати будут
— — — приводить к пересылке символов вподпрограмму буферизации печати, а
— — — не на принтер. В частности, в нашемпримере, мы можем
— — — листинг ассемблирования вывести напринтер, нажав клавиши
— — — Ctrl-PrtSc, служащие для пересылкисимволов с экрана на печать.

— — — — — Когда мы выводим листинг ассемблирования спрограммой
— — — буферизации печати в памяти, символыпоступают в буфер в памяти, а
— — — не на принтер. Буферизация оченьнезначительно
— — — увеличивает время просмотра. Когда файлвыведен на экран (и в буфер
— — — печати), управление возвращается DOS. Выможете прекратить
— — — пересылку символов на принтер, снова нажавклавиши Ctrl-PrtSc.
— — — Листинговый файл находится в буфере, и DOSготова продолжить
— — — выполнение других заданий, например,редактирование или
— — — ассемблирование.
— — — — — Затем начинает выполняться вторая частьпрограммы. Эта
— — — процедура извлекает символы из буфера ипересылает их на принтер.
— — — Она управляется прерыванием от таймера.При каждом прерывании от
— — — таймера процедура вывода на печать такжеполучает управление. Если
— — — в буфере имеется символ, и если устройствопечати находится в
— — — состоянии «готово», топодпрограмма пересылает этот символ на
— — — принтер. Таким образом, символыизвлекаются из буфера и
— — — пересылаются на принтер со скоростьюработы этого устройства.
— — — Поскольку программа вывода на печатьработает в фоновом режиме,
— — — одновременно могут выполняться другиезадания, например,
— — — редактирование или ассемблирование.

— — — — — Обратимся к программе, представленной наФиг. 10.1, и
— — — рассмотрим, как взаимодействуют еекомпоненты. Во-первых, в ней
— — — описан сегмент ABS0, содержащий векторпрерываний, с которым
— — — программа имеет дело. Приведенная впримере программа заменяет как
— — — прерывание вывода на печать INT 17H, так ипрерывание от таймера
— — — INT 8. Заметим также, что в сегменте ABS0определяется адрес
— — — PRINTER_BASE. В этой ячейке находитсябазовый адрес для устройства
— — — печати 0. В данном примере предполагается,что все операции печати
— — —
производятся на системном устройствепечати.

— — — — — Сегмент CODE — это та секция программы,которая остается
— — — резидентной. При помощи команды ORG 100Hмы составили эту программу
— — — как файл типа .COM. Это означает, что длясоздания из выходного
— — — файла редактора связей файла типа .COM,необходимо выполнить
— — — описанную в гл.5 последовательностьдействий. Для хранения исходных
— — — значений вектора печати и вектора таймерав программе используются
— — — области памяти PRINT_VECTOR иTIMER_VECTOR. Хотя программа заменяет
— — — значения этих векторов, при выводе напечать в ней должны быть
— — — известны их исходные значения.

— — — — — Первая часть сегмента CODE, начиная сметки START, является
— — — инициализирующей частью программы. В нейсчитываются исходные
— — — значения векторов прерываний и сохраняютсяв области данных
— — — сегмента CODE. В процедуре инициализациивекторы прерываний в
— — — нижних адресах памяти заменяются новыми,используемыми в процедурах
— — — буферизации и вывода на печать. Обратитевнимание на команду CLI,
— — — которая блокирует прерывания передвыполнением этой операции.
— — — Поскольку программа изменяет прерываниетаймера, она не может
— — — допустить обработку его шага в этот моментвремени. Если бы
— — — прерывание от таймера произошло в тотмомент, когда программа
— — — изменила только одно из двух слов векторапрерываний от таймера, то
— — — микропроцессор продолжил бы выполнение снепредсказуемого адреса
— — — памяти. Разумнее запретить прерывания, чемдопустить возможность
— — — перехода по неизвестному адресу.

— — — — — Прежде чем разблокировать прерывания,программа изменяет
— — — текущее значение счетчика таймера. Обычнопрерывания от таймера
— — — происходят примерно 18 раз в секунду.Устройство печати может
— — — печатать по 80 символов в секунду. Если быпроцедура вывода на
— — — печать выдавала по одному символу прикаждом прерывании от таймера,
— — — то максимальная скорость печати составилабы 18 символов в секунду.
— — — Если ускорить таймер, прерывания оттаймера будут происходить чаще.
— — — Это позволит программе выдавать на печатьвсе 80 символов в
— — — секунду. В приведенном примере в таймерзагружается значение
— — — счетчика 256, оно в 256 раз меньшестандартного значения.
— — — Компенсируется это увеличение скорости припомощи процедуры
— — — TIMER_HANDLER.

— — — — — Процедура инициализации возвращаетуправление в DOS при помощи
— — — прерывания INT 27H. Перед выходом изпроцедуры в регистр DX
— — — загружается указатель на байт, сразуследующий за последнм байтом
— — — всей программы. Заметим, что все процедурыи буфер печати мы
— — — расположили в пределах этой областипамяти. В соответствии с
— — — правилами действия прерывания INT 27H DOSне затронет эту
— — — область.

— — — — — Приведенная программа зря расходует частьпамяти.
— — — Инициализирующая ее часть выполняетсятолько один раз, поэтому нет
— — — смысла оставлять ее в памяти. Можнооптимизировать программу
— — — поместив часть кода от команды START доINT 27H после метки
— — — BUFFER_END. В этом случае при прерыванииINT 27H инициализирующая
— — — часть программы оказалась бы за пределамизащищаемой области
— — — памяти, и следующая загружаемая DOSпрограмма перекрыла бы
— — — процедуру инициализации. Экономия около 90байт из более чем 10000
— — — байт в нашем примере не впечетляет, но онавполне доступна в случае
— — — необходимости.

— — — — — Далее следует процедура PRINT_HANDLER. Этаподпрограмма
— — — вместо базовой системы ввода-выводаосуществляет управление
— — — принтером при каждом обращении программ кпрерыванию INT 17H для
— — — вывода данных на печать. Первые трикоманды управляют перехватом
— — — управления у BIOS. Наша процедура работаеттолько тогда, когда
— — — должен быть напечатан символ (AH = 0). Прилюбом другом коде
— — — функции работу выполняет BIOS, поэтомупрограмма производит
— — — проверку, не равен ли регистр AH нулю.Если нет, то производится
— — — косвенный переход с использованиемсохраненного значения исходного
— — — вектора печати. В результате управлениепередается процедуре
— — — входящей в BIOS, котор
ая выполняеттребуемую функцию. Сказанное
— — — означает, что в нашей процедуре обработкипрерывания достаточно
— — — написать только поддержку сделанныхизменений.

— — — — — Относительно рассмотренного способауправления печатью следует
— — — сделать два замечания. Во-первых, передачадальше всех функций
— — — печати кроме случая AH = 0 — не блестящаяидея. Если какая-либо
— — — программа инициализирует принтер (AH = 2)во время работы механизма
— — — буферизации, то BIOS берет управление насебя и выдает на принтер
— — — команду RESET. Эта команда обрывает тустроку, которая в это время
— — — выводится на печать, что в большинствеслучаев приводит к потере
— — — одного или нескольких символов. Если выхотите сделать эту
— — — программу более защищенной от ошибок, товам придется рассмотреть
— — — вопрос об управлении всеми функциямипечати.

— — — — — Второе, на что следует обратить внимание -это использование
— — — сохраненного вектора прерываний печати.Можно было бы обратиться к
— — — листингу BIOS, приведенному в техническомсправочнике, и найти
— — — начальный адрес процедуры печати. Затемвключить этот адрес
— — — непосредственно в код программы так же,как это делается для других
— — — абсолютных адресов. Однако в результатепрограмма оказалась бы
— — — жестко к этому адресу в системе BIOS. Еслифирма IBM изменит
— — — процедуры BIOS и, таким образом, — адреспроцедуры печати, то
— — — рассмотренная программа не сможет больше работать.Конечно, если
— — — пишите эту программу для своей собственноймашины, а покупать новую
— — — или продавать свою программу несобираетесь, то указанных проблем
— — — не возникнет. Однако в общем случае надоизбегать использования
— — — абсолютных адресов, если есть выбор. Вприведенном примере
— — — процедура инициализации легко можетиспользовать вектор
— — — прерываний печати для определения адресапроцедуры печати
— — — BIOS в ПЗУ.

— — — — — В оставшейся части процедуры PRINT_HANDLERсимвол помещается в
— — -буфер печати. Перед тем, как поместить символ программапроверяет,
— — — есть ли в буфере место. Если буфер полон,программа ждет, пока
— — — освободится место. Это ожидание не вызоветпроблем, поскольку и
— — — стандартная процедура BIOS ждет, чтобыпринтер был готов принять
— — — символ. Из соображений безопасности врегистре CX накапливается
— — — число проходов по ветви»занято». Если это число становится равным
— — — 64K, а буфер по-прежнему полон, то этоможет означать какой-то
— — — сбой. В этом случае процедураPRINT_HANDLER так же, как и BIOS,
— — — выдает сообщение о превышении допустимоговремени ожидания.

— — — — — В приведенном примере процедура печатииспользует также
— — — внутреннюю процедуру ADVANCE_POINTER. Этанесложная процедура
— — — делает буфер печати циклическим. Еслиуказатель сдвигается за
— — — пределы буфера, подпрограмма переносит егона начало буфера. Она
— — — аналогична процедуре BIOS для буфераклавиатуры. Только в данном
— — — случае в буфер помещается 10000 символов,а не 16.

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

— — — — — Сначала процедура работы с таймеромпроверяет, имеются ли
— — — предназначенные для вывода на печатьсимволы. Нет смысла пытаться
— — — переслать символы на принтер, еслипересылать нечего. Если в буфере
— — — нет символов, процедура проходит на меткуTIMER_RETURN. Этот
— — — фрагмент процедуры обслуживает ускорениетаймера.

— — — — — Метка TIMER_RETURN указывает частьпрограммы, обеспечивающую
— — — нормальное функционирование таймера. Прикаждом прерывании от
— — — таймера значение байта TIMER_COUNTувеличивается на единицу. Если
— — — этот байт не нулевой, то процедура выходитиз прерывания после
— — — выдачи сигнала о завершении прерывания наконтроллер прерываний.
&nb
sp- — — Если этот байт равен нулю, то выход изпрограммы осуществляется
— — — посредством косвенного перехода посохраненному вектору прерывания
— — — от таймера TIMER_VECTOR. При этомуправление передается процедуре
— — — BIOS для определения текущего времени ивыключения дисковода.
— — — Дублировать эти операции в нашей программене требуется. Переход в
— — — BIOS происходит только один из 256 развыполнения подпрограммы
— — — работы с таймером. Но поскольку скоростьтаймера была увеличена в
— — — 256 раз, процедура реакции на прерываниеот таймера базовой системы
— — — ввода-вывода по-прежнему будет получатьуправление 18,2 раза в
— — — секунду. Это означает, что текущее времябудет поддерживаться
— — — правильно, и мотор дисковода будетвыключен вовремя. Именно поэтому
— — — и было выбрано ускорение таймера в 256раз, хотя и ускорения в 5
— — — раз было бы достаточно, чтобы обеспечитьработу устройства печати с
— — — максимальной скоростью.

— — — — — Ускорение таймера в 256 раз было выбранопотому, что это было
— — — просто сделать. Однако если брать в расчетпроизводительность, то
— — — лучше было бы ускорить работу таймера в 5раз, поскольку на
— — — обработку каждого прерывания от таймератратится по меньшей мере 10
— — — микросекунд, и даже больше, если в буферепечати есть символы.
— — — Время, затраченное на обработкупрерываний, идет в ущерб выполнению
— — — системой других заданий, напримерассемблирования. При такой
— — — частоте прерываний от таймера, становитсязаметным замедление
— — — работы. Для оптимизации производительностиследует ускорять таймер
— — — менее, чем в 256 раз.

— — — — — Продолжение в комментариях…

Категория: Программирование на Ассемблере | Дата: 24.02.13

Меню раздела
Блок