История об изысканиях возможных путей использования в видеокарте собственных шрифтов, которая увенчалась их полной интеграцией в ПЗУ VGA. На этом пути рассматривались различные варианты, возникали определенные сложности, но в конечном итоге старое доброе отображение шрифта было получено!
Предыстория
Когда-то давно у меня была видеокарта ISA VGA Chips and Technologies, в которой использовался приятный шрифт. Позднее мне довелось владеть еще одной интересной картой ATI EGA с красивым шрифтом. И сейчас у меня установлена ATI VGA Wonder 16 тоже с весьма привлекательным шрифтом. Суть в том, что все названные ISA-видеокарты очень медленные.
Первые две я продал, а последнюю все же решил оставить. Время от времени я ностальгирую по экземпляру от Chips and Technologies. Я так и не понял, почему ПК всякий раз выдавал звуковой сигнал ошибки VGA, хотя работала карта при этом отлично.
Ну да ладно, вернемся к современности. Для моих изысканий в области разработки самодельных систем необходима быстрая ISA-видеокарта. Исходя из этих соображений, я купил новую (!) залежавшуюся (и при том дорогую) Tseng Labs ET4000/W32i с 2Мб ОЗУ у парня по имени Тед Аллен, владельца Micro-Labs Inc. в США. Работает эта карточка идеально. Я без проблем могу запускать игры под MS-DOS, включая Quake в разрешении 320х200.
И все же, поскольку я до сих пор много программирую в MS-DOS, мне зачастую недостает шрифтов тех видеокарт, на которых я учился писать код. В купленной же мной карте Tseng Labs используется монотонный (считай квази-скучный) современный типовой шрифт из ПЗУ. Он не столь плох, как шрифты PCI-видеокарт, но все же.
Вступление
Шрифты в ПЗУ VGA не так уж легко заменить. Однако есть быстрый способ, который позволяет загружать собственный шрифт в ОЗУ VGA. Это делается с помощью небольшой резидентной программы, которая обеспечивает использование видеокартой заданного шрифта. Но по какой-то причине после запуска нескольких программ MS-DOS, устанавливающих собственные шрифты (например, HWiNFO, NSSI, NU), или программ графического режима резидентная утилита дает сбой, и карта возвращается к исходному шрифту из ПЗУ. Кроме того, она занимает 4096 байтов ОЗУ под данные шрифта и еще 368 байтов под программный код.
Чтобы решить эту условную проблему с памятью, я поместил резидентную программу в AUTOEXEC.BAT
. Теперь эти 4.3Кб загружаются в свободный блок верхней области памяти (UMA). Для этого также должен быть загружен EMM386.EXE
или аналогичный драйвер расширенной памяти.
Программное обеспечение
Но как же я создал свой собственный шрифт? Что ж, сначала я использовал FONTEDIT.COM
. К сожалению, эта программа может генерировать лишь .COM
файлы без возможностей резидентной программы. Может, я просто не знаю, как это делается? Еще одна проблема в том, что размер исполняемой программы получается около 8Кб.
Тогда-то я и нашел в интернете новую интересную утилиту Fontraption, написанную VileR. Он создал настолько грамотный продукт, что я оценил его уже сразу после загрузки.
Плохо лишь то, что Fontraption при отрисовке моей Tseng Labs ET4000/w32i выглядит как-то странновато. Окно редактирования шрифта вроде в порядке, но было бы лучше, если бы весь интерфейс прорисовывался также четко.
Очевидно, что VileR создавал эту программу с удовольствием. Он даже внедрил в нее техники управления палитрой, добавив таким образом комбинации цветов, которые по умолчанию на VGA-картах недоступны. Лично у меня с этой темой ассоциируются далекие воспоминания. Это был где-то 1997 год, когда я работал на 80286 ПК, подключенном к янтарно-монохромному ЭЛТ-монитору Tandon. Он был очень похож на газоразрядный дисплей, который, в свою очередь, походил на созданную VileR палитру Plasmatics.
Дополнено позднее: VileR нашел способ исправить баг и отправил мне обновленную версию Fontraption. Теперь она работает прекрасно, верно загружая шрифты из ПЗУ VGA. Исправление оказалось простым, но сама суть проблемы весьма интересна. Как сказал VileR:
[...] при обращении к VideoBIOS для загрузки встроенных шрифтов BL устанавливает целевой блок в карте 2 ОЗУ VGA (от 0 до 7), а для шрифта 8 х 16 у меня по случайности было установлено значение BL=8. Невалидно, но работает с большинством BIOS, поскольку они выполняют для этого значения операцию
AND
с 7. Тем не менее Tseng этого не делает, и шрифт не применяется, в результате чего программа при считывании из ожидаемого блока (0) получает мусор […]
И вот теперь я думаю, что именно хотели преодолеть те программисты BIOS с помощью этой странной операции AND
в нижней части регистра BX
. Должна быть какая-то причина, но вскроется она наверняка нескоро.
Ну да хватит лишних слов, продолжим.
Таким образом, я приступил к разработке шрифта моей мечты. Кому-то он покажется красивым, кому-то, наоборот, страшным. Но мне он очень нравится. Это первый вариант шрифта, и я доволен. Еще многое предстоит проделать. Я проделал над этими шрифтами много работы, и теперь они вполне готовы к использованию. В основу моего дизайна лег оригинальный шрифт, который я извлек из ПЗУ ET4000/W32i. После я усердно старался вспомнить, как же именно выглядели старые шрифты, и опирался при этом на образец из ПЗУ ATI VGA Wonder 16.
Я экспортировал этот шрифт в виде исполняемой резидентной программы и радостно использовал его около года. Несколько же дней назад, работая над собственной реализацией ПЗУ BIOS для интерфейса ввода/вывода ISA, я подумал о включении этого шрифта в реальный код VGA BIOS. Это, конечно, может быть опасной и безумной затеей, но вполне выполнимой.
Для ее реализации я экспортировал сырой шрифт в двоичный файл с помощью команды Fontraption [^S]ave... F2
. Отлично, наличие Fontraption фактически избавило меня от необходимости писать собственный инструмент для извлечения и управления шрифтом из ПЗУ.
Итак, я начал анализировать VGA BIOS своей Tseng Labs, для чего мне понадобился дамп ПЗУ-памяти. Не так давно я написал небольшую утилиту, способную считывать содержимое ПЗУ, код которой вместе с двоичным файлом загрузил на GitHub.
Изначально я создавал эту программу под использование с EEPROM 28C64B на моем интерфейсе ISA, но единственное существенное отличие здесь в наличии кода защиты от записи (SDP). Используется же он только для задач, связанных с записью EEPROM. В реальности эта программа может считывать любую ПЗУ, отображенную в ПК, при условии, что известен адрес отображения, и ее размер не превышает 32768 байтов.
GitHub Репозиторий: https://github.com/agroza/eepromrw
Основная программа: eepromrw.pas
Для получения ПЗУ VGA BIOS я использовал эту команду:
eepromrw.exe -read -addr=C000:0000 -size=8000 -file=vgarom.bin
Она считывает 32768 байтов (8000 в hex-системе) из адреса, обозначенного сегментом C000: 0000
, в двоичный файл VGAROM.BIN
.
После я написал еще один быстрый и грубоватый инструмент, сканирующий файл VGAROM.BIN
в поиске стартовой точки размещения шрифта 8 x 16 в ПЗУ. В памяти Tseng Labs этот шрифт начинается в смещении 17984 (461C в hex-системе). На данный момент я не знаю, является ли это смещение стандартным для шрифта 8 х 16, хотя, меня это не особо волнует, так как моя цель заменить исходный шрифт из ПЗУ на собственный.
Итак, пришло время писать еще один инструмент, который эту замену реализует. Изначально его код получился страшноватым с большим количеством жестко прописанных констант. В итоге мне потребовалось кое-какое время на доработку в соответствии с собственными стандартами, после чего я уже смог выгрузить приемлемую версию на GitHub.
GitHub Репозиторий: https://github.com/agroza/romfontr
Основная программа: romfontr.pas
Новый шрифт в ПЗУ VGA BIOS я вшил с помощью этой команды:
romfontr.exe -offset=461C -romfile=vgarom.bin -fontfile=ag868x16.bin
Она записывает 4096 байтов (1000 в hex-системе) данных шрифта из AG868X16.BIN
в заданное смещение (461С в hex-системе) файла VGAROM.BIN
.
Аналогичные операции я проделал для всех размеров шрифтов и всех смещений, где эти шрифты могут находиться:
[12015 (2EEF)]
данные шрифта 8 x 14 размером 3584 байтов;[15900 (3E1C)]
данные шрифта 8 x 8 размером 2048 байтов;[17948 (461C)]
данные шрифта 8 x 16 размером 4096 байтов.
Пока все хорошо, но есть еще один нюанс. ПЗУ VGA BIOS – это дополнительная ПЗУ, и у нее есть контрольные суммы. Если System BIOS не находит действительную контрольную сумму в конце ПЗУ, то отказывается ее инициализировать. В результате никакого вывода видео, несмотря на нетронутость кода VGA BIOS и наличие шрифтов 8 x 16.
Теперь пора писать еще одну программу. Так, стоп… У меня уже есть такая, которая генерирует 8-битные контрольные суммы ПЗУ. Писал я ее для Windows, но она вполне подойдет, так как для программирования микросхем я все равно использую именно эту ОС. Данная программа также загружена на GitHub.
GitHub Репозиторий: https://github.com/agroza/romcksum
Основная программа: romcksum.dpr
Вычисление и обновление ПЗУ VGA BIOS я делал с помощью этой команды:
romcksum.exe -o -vgarom.bin
Она вычисляет 8-битную контрольную сумму всех данных ПЗУ и соответствующим образом обновляет последний байт. Более того, дополнительный параметр -O
сообщает программе, что файл нужно проверять как дополнительную ПЗУ.
Дополнено позднее: я добавил функции вычисления контрольной суммы и обновления непосредственно в программу ROM Font Replacer.
Это означает, что теперь команда, которую я мог использовать для вложения нового шрифта в ПЗУ VGA BIOS и вычисления -> обновления 8-битной контрольной суммы, выглядит так:
romfontr.exe -u -romfile=vgarom.bin -fontfile=ag868x16.bin
Такая возможность все ускоряет и позволяет пропускать промежуточный шаг использования программы ROM Checksum Calculator.
Теперь файл ПЗУ BIOS видеокарты Tseng Labs ET4000/W32i содержит мой собственный излюбленный шрифт 8 х 16 в качестве основного для всех текстовых режимов. На этом программная часть заканчивается и можно переходить к аппаратной.
Реверс инжиниринг ПЗУ VGA BIOS
В первую очередь мы займемся реверс-инжинирингом. Но почему? Потому что, если карта установлена в режим 03h
, то она автоматически заменяет несколько выбранных глифов на кастомные, которые расположены после 4096 байтов данных шрифта 8 х 16. Не уверен, какая логика стоит за этим, но решение это очень интересно. Странность в том, что если переключить карту в режим 11h
или 12h
, то шрифт 8 х 16 используется корректно, и никакие глифы не заменяются.
Эту тайну быстро раскрыл мистер VileR. Я начал с ним беседу по поводу проблемы с отрисовкой Fontraption и попутно рассказал о глифах. Он сказал, что это альтернативные глифы шрифта для режимов 9 х 16. Я знал о них еще в 90-х, но мне было неизвестно, где и как они хранятся в ПЗУ.
Очевидно, что есть таблицы шрифтов 9 х 14 и 9 х 16, расположенные сразу после стандартных таблиц 8 х 14 и 8 х 16. В частности, каждому типу глифа предшествует байт, обозначающий код символа ASCII. В процессе обратного инжиниринга вскрылся еще один интересный факт, а именно то, что эти альтернативные таблицы шрифтов завершаются нулевым байтом.
Поэтому я дополнительно создал расширенные варианты шрифтов 9 х 14 и 9 х 16, после чего написал еще одну программу, которая выделяет эти расширенные глифы из массива данных шрифтов и записывает их в отдельные файлы в формате, ожидаемом процедурами отрисовки ПЗУ VGA ROM. Затем я совместил эти файлы с измененной ПЗУ VGA ROM и повторно вычислил байт контрольной суммы.
Структура всей области данных шрифтов ПЗУ VGA видеокарты Tseng Labs ET4000/W32i такова:
[12015 (2EEF)]
данные шрифта 8 x 14 размером 3584 байтов;[15599 (3CEF)]
альтернативные данные шрифта 9 x 14 (19 глифов) размером 300 байтов;[15899 (3E1B)]
нулевой байт (0);[15900 (3E1C)]
данные шрифта 8 x 8 размером 2048 байтов;[17948 (461C)]
данные шрифта 8 x 16 размером 4096 байтов;[22044 (561C)]
альтернативные данные шрифта 8 x 16 (18 глифов) размером 323 байта;[22367 (575F)]
нулевой байт (0).
Общий размер данных шрифтов ПЗУ VGA составил 10353 байта.
Я закончил изменение обоих пакетных файлов MS-DOS, которые использовал для тестирования, и теперь они записывают все данные шрифтов последовательно в файл VGAROM.BIN
. Ниже приведено исполняемое содержимое этого файла, который также вычисляет и обновляет 8-битную контрольную сумму.
romfontr.exe -u -offset=2EEF -romfile=vga.bin -fontfile=ag868x14.bin
romfontr.exe -u -offset=3CEF -romfile=vga.bin -fontfile=ag869x14.bin
romfontr.exe -u -offset=3E1C -romfile=vga.bin -fontfile=ag868x8.bin
romfontr.exe -u -offset=461C -romfile=vga.bin -fontfile=ag868x16.bin
romfontr.exe -u -offset=561C -romfile=vga.bin -fontfile=ag869x16.bin
Теперь у меня есть полноценный файл ПЗУ VGA BIOS со всеми новыми шрифтами и их альтернативными представлениями.
Работа с платой
Ниже вы видите мою Tseng Labs ET4000/W32i от Micro Labs. Мне очень нравится ее компоновка. Помню, что спрашивал Теда, какую программу CAD он использовал, но его ответ уже позабыл. Было бы здорово задокументировать и это тоже для истории.
В данной видеокарте использован неизвестный тип EEPROM. Неизвестный, потому что на ней наклеен красивый фиолетовый лейбл с надписью Made in America, который я не хочу ни сдирать, ни портить. В итоге узнать тип установленной EEPROM не получается. Однако шелкография на печатной плате гласит, что это 27C256. Вообще-то, я бы итак мог поспорить, что установлена именно 27C256 (или совместимая), потому что большинство, если не все, VGA-карты оснащались ПЗУ на 32Кбит.
Время знакомиться с видеокартой подробнее. Кроватка ПЗУ здесь одна из самых дешевых. Так как произведена карта в США, я бы ожидал, что Micro Labs используют Mill-Max или нечто подобное. Но они все же пошли по пути снижения стоимости, как это было свойственно производственным компаниям в то время. Тем не менее под кроваткой мы видим надпись: PCB MADE IN HONG KONG.
Ага! У США были (и еще есть) отличные предприятия по производству печатных плат. Но их услуги выливаются в приличную копеечку, которая в итоге отражается на стоимости конечного продукта. Как ни крути, а в конце-концов все производственные расходы оплачивает именно покупатель. Плата сделана добротно – не лучше и не хуже большинства компьютерных плат начала 90-х. Однако она явно не сравнится по качеству с платой моей ATI VGA Wonder 16.
За генерацию тактовых частот карты отвечает интегральная схема CHRONTEL CH9294. Такие до сих пор можно приобрести на различных сайтах. В качестве RAMDAC* использована AT&T ATT20C490-80. Эта деталь тоже вполне доступна онлайн, как и микросхема ET4000/W32i. Тут я даже призадумался: «А не собрать ли мне собственную VGA-карту?» У меня все еще имеется каталог спецификаций Tseng Labs, и этот VGA-контроллер вместе с образцом схемы подробно в нем описан. Я бы даже мог улучшить дизайн, использовав современную более дешевую и доступную память. Но это уже отдельная тема, и пока она остается лишь пищей для размышлений.
*RAMDAC (сокр. от Random Access Memory Digital-to-Analog Converter) – это часть компьютерной видеокарты, которая преобразует цифровые данные в аналоговый сигнал, отображаемый на мониторе компьютера.
Память представлена 16 микросхемами NN51425P производства NPNX, Япония. Честно, я ранее не слышал ни об этой компании, ни о подобных микросхемах памяти. В моем экземпляре карты один из модулей, а именно U12, не соответствует остальным и рассчитан не на 45 нс, а на 50.
Далее я демонтирую кроваткумикросхемы ПЗУ VGA BIOS. Эта операция не для трепетных сердец, но мне уже доводилось проделывать такую на других компьютерных платах. Я планирую использовать качественную кроватку Mill-Max класса AUGAT. Это упростит дальнейшее экспериментирование с различными микросхемами ПЗУ VGA BIOS.
После вмешательства сторона пайки смотрится вполне себе неплохо, и сама видеокарта будто только сошла с заводского конвейера.
Далее я запрограммирую микросхему EPROM 27C256-15 от Texas Instruments, допускающую стирание с помощью УФ. Для этих целей я использую универсальный программатор TL866II Plus, который мне очень полюбился. По началу после его покупки меня терзали некоторые сомнения, но после они полностью развеялись. Единственная сложность теперь – это стирание EPROM. УФ-лампы у меня под рукой нет, но можно сымпровизировать, разбив стекло ртутной газоразрядной лампы на 250Вт.
Старая ПЗУ и новая EPROM
Эта ртутная лампа является мощным источником УФ-излучения. И поскольку у меня нет электронного балласта 250Вт, то в качестве его альтернативы я использую три вольфрамовых лампы накаливания (две по 75Вт и одну на 100Вт), соединив их последовательно с ртутной.
Очевидные рекомендации:
- Никогда не смотреть на источник УФ-излучения, так как это может вызвать необратимую слепоту.
- Разбивание стеклянной колбы также очень опасно, поскольку пары ртути чрезвычайно вредны для дыхательной системы.
- Работа с оголенными внутренностями ртутной лампы представляет высокий риск поражения током и тем самым угрозу для жизни.
В моем случае риски минимизированы, так как опыт обращения с подобным инструментом у меня есть. В дальнейшие подробности я вдаваться не буду, но самое важное отмечу.
С этим импровизированным устройством я оперирую вне дома, так как УФ-излучение ионизирует воздух, производя озон. На улице я размещаю схему EPROM под ртутной лампой при отключенном питании. После этого удаленно подаю напряжение, находясь в нескольких метрах от места. Никогда нельзя исключать возможный риск взрыва ртутной лампы. С момента подачи питания я отсчитываю пять минут и выключаю устройство. Затем тестирую EPROM, определяя, все ли байты перешли в состояние FF
. Если стирание произошло не полностью, я облучаю ее еще минуту и повторяю тест. Подобные одноминутные циклы я повторяю до тех пор, пока память не будет полностью стерта. Обычно мне удается добиться этого за 7-8 минут.
Дополнение: ночное сжигание битов с байтами. На меня нахлынула волна энтузиазма, и я увлекся стиранием еще нескольких EPROM, подготовив их к новому микрокоду. Все фото, где наблюдается УФ-излучение, сделаны удаленно при помощи автосъемки.
Отлично, EPROM очищена. Все биты установлены на 1 (иначе говоря, все байты в hex-системе сейчас выражены как FF
). Микросхему я запрограммировал обновленным файлом ПЗУ. Кроватка на месте, и EPROM встает в него впритирку.
Время проверять карту. Ниже вы видите полученный результат. Большую часть времени я провожу в DOS-навигаторе и IDE Pascal, поэтому вполне естественно, что мне нравится, когда экран выглядит именно так.
Я уже и забыл, какая это морока фотографировать ЭЛТ-дисплеи… Очень уж сложно не поймать линию развертки электронного луча где-нибудь в середине экрана.
Теперь все работает отлично. Никаких больше сбросов шрифтов после запуска HWiNFO. Да и вообще изображение мне очень нравится, так что на этом данный опыт можно завершать.
Надеюсь, что для вас он оказался интересен.
Автор: Дмитрий Брайт