СТАТЬИ > DOS навсегда!

Единственно верный алгоритм руссификации адаптеров VGA/EGA

  Актуальная, совсем недавно, проблемма руссификации видеоадаптеров EGA/VGA перестала быть жизненно важным моментом. И хотя, сами руссификаторы продолжают использоваться (например, для руссификации DOS сессий в Windows NT/2000), интерес, на наш взгляд, к принципам работы с видеоадаптерами должен сохраняться и поныне. Этому должно способствовать повальное увлечение современных любителей ассемблера к написанию собственных операционных систем. Именно поэтому решено было сделать римэйк, написанной некогда (1992 год) статьи, об идеальном алгоритме руссификации видеоадаптеров.

  Алгоритм руссификации разрабатывался и совершенствовался в течении четырех лет. Испытывался и отлаживался на огромном количестве, как фирменных видеоадаптеров, так и на их жутких "клонах". Работали над алгоритмом все это время два программиста Гайко Александр и Бордачев Андрей. Различные советы и идеи им давали так же их коллеги - Сысоев А.П., Гутников А.Е. Выражаем им свою благодарность.

  Исходный текст драйвера NVGA можно скачать здесь.

  При написании руссификатора нам хотелось добиться следующего:

  Итак. Для того, чтобы руссифицировать программным способом адаптер EGA или VGA, драйвер руссификатор должен:

  Рассмотрим более подробно, как работает перехватчик прерывания 10h. В первую очередь надо обратить внимание на то, что в теле обработчика содержится таблица всех шрифтов, которые необходимо обслуживать. Она располагается в самом конце обработчика (метка FonTable), имеет переменную длинну и может содержать до 16 описаний различных шрифтов. Для каждого шрифта зарезервированно 7 байтов. Каждое 7-байтовое описание имеет структуру, определяемую в начале исходного текста (см. структуру FontDef).

  Таблица шрифтов FontTable может содержать от одного до 16-ти шрифтов в зависимости от конфигурации драйвера.

  Теперь рассмотрим, что происходит после того, как в компьютере возникает 10-е прерывание.

  Запомним значение регистров AX и BX (номера функции и подфункции прерывания 10h). Это может понадобиться для получения необходимой нам информации от VIDEOBIOS.

  Теперь вызываем исходный обработчик 10-го прерывания, например, для того чтоб позволить самому VIDEOBIOS установить требуемый видеорежим, или загрузить шрифт из памяти. Теперь надо проанализировать, что произошло, и подправить все так чтобы в знакогенераторе оказался русский шрифт и все указатели ссылались на него.

  Бросается в глаза некоторая нелогичность подхода. Сначало отрабатывает VIDEOBIOS, а затем наш драйвер. Двойная работа? Нет! Довольно сложно обеспечить совметимость со ВСЕМИ VIDEOBIOS. Ведь кроме того, что они разные в адаптерах разных фирм, у них меняется и железо и BIOS. А мы при этом сокращаем код своего обработчика и обеспечиваем его универсальность. Скорость же отработки драйвера такова, что никак не сказывается на работе прикладных программ.
  Итак, после отработки 10-го прерывания, управление получает наш обработчик. Мы должны проанализировать, что происходило и сделать соответствующие "телодвижения".

  Для нас важны следующие моменты:

  1. запрос информации о шрифтах;
    Если в переменной SubFunction находится значение 1130h, то, производился запрос адреса того или иного шрифта. Следовательно мы должны скорректировать значения в регистрах ES:BP таким образом, чтобы в них оказалась ссылка на руссифицированный шрифт.
      Делается это следующим образом: зная, какое число находилось в регистре BH, мы последовательно просматриваем всю таблицу обслуживаемых шрифтов. В описании каждого шрифта смотрим на байт FontCall и проверяем, не совпадает ли это значение с числом, которое передавалось в регистре BH. Если такого числа нет, то значения регистров ES:BP остаются неизменными. Если такой шрифт представлен необходимо проверить полностью ли или частично он представлен в памяти. Если шрифт представлен полностью регистры ES:BP корректируются так, чтобы указывать на соответствующий руссифицированный шрифт. При этом правильно обрабатывается ситуация частичной загрузки руссифицированных шрифтов.
  2. присутствие драйвера в памяти;
    Если в регистре BX передается значение 0FFAAh, а такое значение не используется в стандартных VIDEOBIOS, то мы считаем, что драйвер уже загружен. При этом в регистре AX возвращается число, получающееся из 0FFAAh после применения к нему операции исключающее ИЛИ, а в регистре ES - сегмент расположения драйвера в памяти. Это позволит нам в дельнейшем выполнять реинициализацию.
  3. активизация русских шрифтов при переключении видеорежимов.
    Если содержимое регистра AX не удовлетворяет требованиям пунктов 1 и 2, управление передается на метку PushAX. Регистр AX запоминается в стеке для того, чтобы обеспечить при возврате в систему его исходное значение, чем самым достигается прозрачность работы драйвера.

  После этого в регистре AX восстанавливаем значение бывшее на входе обработчика и проверяем нужно ли проводить инициализацию шрифта. Это необходимо делать в следующих случаях:

  Если содержимое регистра AX не удовлетворяет этим условиям, то восстанавливаем регистры и возвращаем управление в вызвавшую программу. В противном случае активизируем руссифицированный шрифт. Тут есть одна тонкость. Активизация или лучше сказать загрузка шрифта в знакогенератор видеоадаптера зависит от того в каком режиме находится видеоадаптер в текстовом или графическом.

  Как же нам отличить текстовый режим от графического? Чем они отличаются друг от друга? Для решения этой задачи приходится использовать несколько предположений. Рассмотрим этот вопрос поподробнее.

  В текстовом режиме на экране присутствует мигающий курсор. В графических режимах он отсутствует. Воспользовавшись функцией 3 10-го прерывания мы можем узнать его параметры (размер курсора текущей видеостраницы). По логике для графического режима возвращаемые параметры должны равняться 0. Проверяем это предположение...

  Ура! Получилось. Но оказалось, что честно себя ведут далеко не все VIDEOBIOS. Раз не работает корректно VIDEOBIOS надо попробовать получить информацию о состоянии адаптера через какие-либо порты видеоадаптера.

  Находим в описании, что в порте 3CFh в регистре 6 в младшем бите содержится информация о том, текстовый или графический режим включен. Второй раз ура!

  И второй раз рано радовались. Оказалось, как и в первом случае, хотя и существенно реже, есть видеоадаптеры которые можно заставить выдавать чушь вместо нормальной информации. Примером такой программы оказалась DOS SHELL 5.0. К тому же для адаптеров EGA (1992 году было еще актуально) портов с такой информацией не было. Пришлось поднапрячься и сделать такое наблюдение. В области данных BIOS по адресу 0400h:004Ch расположенно слово, в котором содержится размер видео памяти, необходимый для организации текущего видеорежима (RegenSize). В текстовом режиме каждый символ на экране занимает 2 байта видеопамяти. В одном находится код символа, в другом его атрибут(цвет, мерцание). Поэтому объем памяти, требуемый для этого видеорежима определяется по формуле:

П=2*К*С, где К - количество колонок, С - количество строк.

  Например, для текстового режима 3 - 80x25 необходимо 2*80*25=4000 байтов памяти. Эта величина, округленная до числа равного степени двойки (4096), и записана в слове RegenSize. Объем памяти для графического режима можно расчитать по формуле:

П=Ф*К*С,

  где Ф - размерность матрицы, описывающий символ в данном режиме(высота в пикселах), К - количество колонок, С - количество строк.

  Например, для графического режима 6 (640x200) для вывода текста используется шрифт размером 8x8, и считается, что на экране умещается 80 колонок, и 25 строк. Тогда необходимый объем памяти равен 8*25*80=16000. Округлив до степени двойки получаем 16386.

  Отсюда получаем алгоритм определения типа режима:

  Если результат превышает RegenSize - режим текстовый.

  К сожалению этот алгоритм тоже не дает стопроцентного определения типа режима. Во первых он не работает, если размер матрицы шрифта 5. Во вторых, объем памяти современных видеоадаптеров может существенно превышать требуемый объем памяти для данного видеорежима...

  Были и еще идеи. Но мы пришли к выовду, что стоит остановиться и реализовать такой алгоритм: если текущий режим стандартный, то решение о том текстовый он или графический принимается в соответствии с таблицей:

0...3,7 - текстовые режимы;
4...6,8,0Dh...13h - графические режимы.

  Если включается какой-либо из расширенных режимов - приводится в действие одна из вышеописанных процедур, которая и определяет в каком режиме мы находимся.

  Теперь, когда тип режима определен можно провести активизацию шрифтов. Проще всего это сделать в графическом режиме. Для этого надо установить вектор 43h на начало одного из шрифтов, находящегося в теле драйвера.

  В драйвере это происходит передачей управления на метку GraphMode. Там мы выясняем загружен ли в память требуемый шрифт и, в зависимости от состояния регистров BH(размер шрифта), и BL(основной или альтернативный) соответствующим образом настраиваем ES:BP. В данной реализации это делается непосредственной установкой регистров, так как функция VIDEOBIOS 11h с подфункцией 21h работает не на всех адаптерах.

  Для текстового режима все несколько сложней. Типичный текстовый режим 3 характерезуется параметрами 80 колонок, 25 строк, 16 цветов. Символы на экране формируются аппаратным образом, матрицы символов - программируемым знакогенератором. Знакогенератор находится во второй битовой плоскости видеоадаптера. Объем памяти отводимой этой плоскости таков, что в нем могут одновременно храниться до восьми знакогенераторов одновременно. Для каждого символа зарезервированно 32 байта. Максимальный размер шрифта при этом - 8x32. Количество знакогенераторов, которые могут одновременно отображаться на экране зависит от количества цветов. Если адаптер использует все 16 цветов возможна работа только с одним знакогенератором, если же пожертвовать половиной цветов, то можно использовать два знакогенератора, а это 512 символов одновременно. По такому пути пошли разработчики Laptop и Notebook. На ЖКИ экранах сложно (1992 год!) получить 16 градаций яркости, поэтому используют 8 градаций и 512 символов. Кроме этого горизонтальное разрешение экрана в этом режиме не 640 точек, 720. Таким образом, на символ отводится не 8 пикселей, а 9. Это приводит к тому, что дополнительно появляются еще два часто используемых шрифта (9x14, 9x16). Причем эти шрифты содержат не все символы, а только широкие. Алтернативные шрифты имеют структуру отличающуюся от структуры стандартных шрифтов. Первый байт - код символа; далее байты описывающие саму матрицу символа; затем повторение для следующего символа и т.д., пока байт кода символа не станет равным нулю.

  При записи шрифта в битовую плоскость сначало туда записывается основной шрифт, а затем, если размер символа на экране 9 точек, заносит в отдельные кодовые позиции альтернативные символы.

  Описываемый драйвер полностью реализует данный алгоритм и поддержку альтернативных шрифтов.

  Обычно драйверы для того, чтобы перепрограммировать знагогенератор, используют соответствующие функции VIDEOBIOS. Однако в последнее время все чаще попадаются видеоадаптеры , в которых эта функция выполняется неправильно. Обычно для 25-ти строчных режимов все корректно, но если шрифт другого размера то корректировки количества строк не происходит.

  Для того, чтоб справиться с этой проблемой было принято решение загружать знакогенератор во вторую видеоплоскость адаптера напрямую через соответствующий порт. Так еще раз (определение типа режима см. выше) подтвердился парадокс IBM PC: совместимость драйверов и BIOS выше на уровне программирования портов, чем на уровне программирования посредством функций прерывания BIOS.

  Рассмотрим кратко как происходит этот процесс.

  Битовая плоскость видеоадаптера становится доступной после соответствующего программирования через определенные порты. Последовательность действия следующая:

  После этого ищем нужный шрифт и загружаем его процедурой SetFontAddrESBP. Формирование знакогенератора осуществляется процедурой LoadCharSet. Эта процедура может вызываться не один раз в зависимости от того , весь шрифт или только его часть необходимо корректировать. После загрузки основного шрифта с помощью чтения порта 3C4h выясняем надо ли догружать альтернативные шрифты. Если соответствующий признак есть догружаем необходимые символы из шрифтов 9x14 и 9x16.

  После загрузки нужно закрыть битовую плоскость 2. Делается это процедурой BitPlaneClose.

  Особым образом приходится руссифицировать 35/50 строчные режимы. Для этого приходится перехватывать процесс загрузки пользовательского шрифта с помощью подфункции 10h функции 11h. Управление передается на метку Set10Flag. В регистре AL устанавливается признак того, что при записи символов необходимо дополнять сверху и снизу пустыми строками. Далее вызывается процедура LoadCharSet, которая корректирует русские символы уже загруженного шрифта 8x10.

  В заключение надо сказать, что обработчик 10-го прерывания - это основная часть руссификатора, но не единственная. Обработчик прерывания выполнен перемещаемым, что позволяет при формировании резидентной части размещать его в более младших адресах, что позволяет экономить память за счет префикса программного сегмента(PSP). Реализованна также возможность перемещать этот обработчик в HMA(High Memory Area). В этом случае драйвер занимает в памяти 160 байт. Перед тем, как стать резидентом драйвер тестирует адаптер VGA, автоматически определяет какие шрифты требуют обслуживания, составляет таблицу шрифтов FontTable и обеспечивает ПОЛНОЕ обслуживание подавляющего большинства модификаций видеоадаптеров. При этом пользователь может отказаться от автоматической диагностики и директивно сообщать драйверу через командную строку какие шрифты можно обслуживать. (Для WinNT нужно указывать полный путь доступа к шрифтам!) При этом возможна существенная экономия памяти.

  Дистрибутив находится в прилагаемом архиве. Там же есть клавиатурный драйвер NKD(не менее идеальный ;-). А так же великолепная утилитка VACULA, которая не только расскажет вам все об видеоадаптере, но и позволит поиграться с его режимами, оценив его возможности.

  Литература:
  Фролов А.В., Фролов Г.В. Программирование видеоадаптеров CGA, EGA, VGA. Москва, Диалог-МИФИ, 1992 г.
  Programmers Guide to PC & PS/2 Video Systems. Richard Wilton. MicroSoft Press, 1987.

  [C] Андрей Бордачев & Александр Гайко

© 2002-2004 wasm.ru - all rights reserved and reversed