В текстовых режимах на экране могут отображаться только текстовые символы, а также символы псевдографики. Текстовые режимы работы видеоадаптеров рекомендуется использовать всегда, когда приложению не нужно выводить на экран графическую информацию.
Стандартные текстовые режимы работы видеоадаптеров позволяют вывести на экран 25 строк по 40 или 80 символов. Если перепрограммировать некоторые регистры видеоадаптера, то можно увеличить число отображаемых строк для EGA до 43, а для VGA до 50.
Для кодирования каждого знакоместа экрана (символа) используются два байта. Первый из них содержит ASCII-код отображаемого символа, а второй - атрибуты символа. ASCII-коды символов экрана располагаются в нулевом цветовом слое, а их атрибуты - в первом цветовом слое.
Рисунок 6.3 Структура видеопамяти в текстовых режимах.
Атрибуты определяют цвет символа и цвет фона. Благодаря такому режиму храненеия информации достигается значительная экономия памяти. При отображении символа на экране происходит преобразование его из формата ASCII в двумерный массив пикселов, выводимых на экран. Для этого преобразования используется таблица трансляции символов (таблица знакогенератора).
Данная таблица знакогенератора хранится во втором слое видеопамяти:
Рисунок 6.4 Преобразование кода ASCII в образ символа на экране.
При непосредственном доступе к видеопамяти нулевой и первый цветовые слои отображаются на общее адресное пространство. При этом происходит чередование байтов из нулевого и первого слоев. Коды символов имеют четные адреса, а их атрибуты - нечетные.
Рисунок 6.5 Отображение цветовых слоев.
Ниже приведен дамп видеопамяти в текстовом режиме с разрешением 80х25 символов:
Адрес 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
Из этого дампа видно, что байты кодов символов из нулевого цветового слоя видеопамяти чередуются с байтами атрибутов символов из первого цветового слоя. Байты кодов символов расположены по четным адресам, а байты атрибутов, которые для данного участка видеопамяти имеют значение 07h - по нечетным.
Следующая программа GRAB демонстрирует непосредственный доступ к видеопамяти в текстовых режимах. Это резидентная программа, содержащая все элементы, необходимые для ее "безопасной" работы.
Программа предназначена для копирования содержимого видеобуфера в файл. Запись в файл активизируется при нажатии комбинации клавиш Ctrl+PrtSc. После каждой записи имя файла изменяется.
В самом начале своей работы программа проверяет наличие своей копии в памяти, так как повторное переназначение векторов прерываний приведет систему к краху.
При нажатии комбинации клавиш Ctrl+PrtSc вызывается функция write_buf. Функция write_buf определяет текущий номер видеорежима а также такие его параметры как число символов в строке и количество строк на экране. Эти параметры считыватся из области данных видеофункций BIOS. Определяется также адрес начала видеопамяти и смещение относительно нее области, отображаемой на экране. Далее, если видеоадаптер находится в текстовом режиме мы записываем данные из видеопамяти в файл. При этом записывается только каждый второй байт, так как в видеопамяти байты символов чередуются с байтами атрибутов. Естественно информация о цвете символов при этом теряется.
Подробное описание области данных видеофункций BIOS и регистра начального адреса контроллера ЭЛТ вы найдете в следующих главах книги.
int iniflag; // Флаг запроса на вывод экрана в файл int outflag; // Флаг начала вывода в файл int name_counter; // Номер текущего выводимого файла char _far *crit; // Адрес флага критической секции DOS
// =======================================
void main(void); void main(void) {
union REGS inregs, outregs; struct SREGS segregs;
unsigned size; // Размер резидентной части // TSR-программы
// Вызываем прерывание мультиплексора с AX = FF00 // Если программа GRAB уже запускалась, то новый // обработчик прерывания мультиплексора вернет // в регистре AX значение 00FF. // Таким способом мы избегаем повторного изменения // содержимого векторной таблицы прерываний.
// Новый обработчик аппаратного прерывания таймера
void _interrupt _far new8(void) {
// Вызываем старый обработчик
(*old8)();
// Если была нажата комбинация клавиш Ctrl+PrtSc // (iniflag при этом устанавливается в 1 // новым обработчиком прерывания 9) и // если запись в файл уже не началась, // то при значении флага критической секции // DOS, равном 0, выводим содержимое экрана // в файл
outflag=1; // Устанавливаем флаг начала вывода _enable(); // Разрешаем прерывания
write_buf(); // Записываем содержимое // буфера экрана в файл
outflag=0; // Сбрасываем флаги в исходное iniflag=0; // состояние } }
// =======================================
// Новый обработчик прерывания 28h, которое вызывает // DOS, если она ожидает ввода от клавиатуры. // В этот момент TSR-программа может пользоваться // функциями DOS.
void _interrupt _far new28(void) {
// Если была нажата комбинация клавиш Ctrl+PrtSc // (iniflag при этом устанавливается в 1 // новым обработчиком прерывания 9) и // если уже не началась запись в файл, // то выводим содержимое экрана в файл
if((iniflag != 0) && (outflag == 0)) {
outflag=1; // Устанавливаем флаг начала вывода _enable(); // Разрешаем прерывания
write_buf(); // Записываем содержимое видеобуфера // в файл
outflag=0; // Сбрасываем флаги в исходное iniflag=0; // состояние }
// Передаем управление старому обработчику // прерывания 28
_chain_intr(old28); }
// =======================================
// Новый обработчик клавиатурного прерывания. // Он фиксирует нажатие комбинации клавиш Ctrl+PrtSc // и устанавливает флаг iniflag, который сигнализирует // о необходимости выбрать подходящий момент и // записать содержимое видеобуфера в файл
void _interrupt _far new9(void) {
// Если SCAN-код равен 0x37 (клавиша PrtSc), // нажата клавиша Ctrl (бит 4 байта состояния // клавиатуры, находящийся в области данных // BIOS по адресу 0040:0017 установлен в 1) // и если не установлен флаг iniflag, // то устанавливаем флаг iniflag в 1.
// Если нет EGA, то используется 25 строк, // если EGA присутствует, считываем число // строк. Это число находится в области данных // BIOS по адресу 0040:0084.