Глава 4. Вывод на терминал.

Раздел 3. Вывод символов на экран.

4.3.1 Вывод на экран одного символа.

Все процедуры для вывода символа на экран в BIOS и DOS (а также в Бейсике) помещают символ в текущую позицию курсора и автоматически передвигают курсор на одну позицию вправо. Все они переносят вывод на следующую строку при достижении конца строки, если не сделано специальных указаний отбрасывать все символы за 80-м столбцом {4.2.2}. Важное отличие между отдельными процедурами состоит в том, что некоторые вместе с символом пишут также и его атрибуты, а некоторые этого не делают.

Kак в языках высокого, так и в языках низкого уровня, символы могут выводиться на экран без использования обычных операций печати. Вместо этого используется прямое отображение в память, при котором коды символов и их атрибуты прямо засылаются в ячейки памяти видеобуфера, соответствующие определенной позиции курсора на экране. Буфер начинается с адреса B000:0000 для монохромного адаптора и с адреса B800:0000 - для цветного графического адаптора и PCjr. EGA использует те же самые адреса в аналогичных режимах экрана. Позиции с четными номерами (начиная с нуля) содержат коды ASCII символов, а позиции с нечетными номерами - байты атрибутов. Hа рис. 4-2 показан участок памяти видеобуфера. При этих операциях позиция курсора не меняется и он может быть выключен при желании {4.2.3}. Вместо курсора надо хранить переменные, служащие указателями на текущую позицию.

Средний уровень.

Операционная система предоставляет шесть процедур вывода на экран - три в BIOS и три в DOS. Они отличаются главным образом тем, передвигается курсор или нет, после вывода символа, вызывают ли они сдвиг экрана, позволяют ли они устанавливать атрибуты и цвета символов, а также какие управляющие коды они интерпретируют (некоторые рассматривают символ BackSpace, просто как обычный символ, а некоторые действительно сдвигают курсор на одну позицию назад). Эти шесть процедур следующие:

 
   Прерывание 10H: 
   функция   9     вывод символа с атрибутами 
             A     вывод символа без атрибутов 
             E     "телетайпная" процедура (как на принтер) 
   Прерывание 21H: 
   функция   2     вывод символа без атрибутов 
             6     вывод символа без атрибутов 
             9     вывод строки символов 

Функции 9 и A прерывания 10H вообще не интерпретируют управляющие символы. Функции DOS интерпретируют управляющие коды, приведенные в следующей таблице. Функция E прерывания 10H интерпретирует все коды таблицы, кроме ASCII 9.

 
   ASCII   7     звонок    ASCII   8     возврат на шаг (BackSpace) 
   ASCII   9     табуляция 
   ASCII  10     перевод строки 
   ASCII  13     возврат каретки 

Первые две функции прерывания 10H не передвигают курсор после вывода символа. Функция 9 этого прерывания выводит на экран с указанием атрибутов, а функция A - без указания, при этом сохраняется текущее значение байта атрибутов для этого символа. AL должен содержать выводимый символ, а BL - атрибуты. Hомер страницы дисплея содержится в BH. Он должен указываться даже для монохромного дисплея, который имеет только одну страницу памяти дисплея. В этом случае должна быть установлена первая страница, которой соответствует номер 0. Особое свойство этих двух функций BIOS состоит в том, что символ выводится такое число раз, какое указано в CX. Обычно указывают CX равным 1, но эти функции могут легко выводить целые строки символов, если указать большее значение счетчика - полезное свойство при создании рамок. Отметим, что даже если выводится много символов, то позиция курсора не изменяется. Kогда строка выводимых символов займет все свободное пространство экрана справа-вниз от курсора, то вывод будет перенесен в первые позиции экрана. INT 10H
;---вывод символа в негативе
MOV AH,9 ;функция записи с атрибутами
MOV AL,THE_CHARACTER ;символ в AL
MOV BL,112 ;атрибуты в BL
MOV BH,0 ;страница 1
MOV CX,1 ;вывести один раз
Вместо того, чтобы постоянно восстанавливать значение счетчика в CX прерывание BIOS предоставляет также телетайпную процедуру, которая больше подходит для вывода строки символов. Она выполняется функцией E. Она готовится так же, как и функция A, но не надо засылать значение в CX. Строка выводится просто за счет изменения символа в AL и повторного вызова прерывания. При использовании в графическом режиме в BL устанавливается цвет палетты, в противном случае сохраняется старый атрибут.
;---вывод строки с помощью телетайпной процедуры
MOV AH,0EH ;номер функции
MOV BH,0 ;номер страницы
LEA BX,STRING ;BX указывает на строку
NEXT_CHAR: MOV AL,[BX] ;берем символ в AL
CMP AL,'$' ;проверка на конец строки
JE ALL_DONE ;если да, то выход
INT 10H ;вывод строки
INC BX ;переходим к следующему символу
JMP SHORT NEXT_CHAR ;повторяем процедуру ALL_DONE:

Прерывание DOS 21H как правило предоставляет более полезные процедуры, поскольку они перемещают курсор и приводят к сдвигу экрана при достижении нижней строки, а также интерпретируют некоторые из обычных управляющих кодов. Функции DOS выводят на страницу, которая должна быть установлена функцией 5 прерывания 10H {4.5.3}. Предоставляются две функции для вывода символа, с номерами 2 и 6. Первая из них распознает Ctrl-Break {3.2.8}, а вторая - нет. (Kогда с клавиатуры вводится Ctrl-Break, то процедура обработки Ctrl-Break не выполняется до тех пор, пока не используется функция, которая распознает его наличие).

Обе функции выводят белые символы на черном фоне, до тех пор, пока не сделана специальная установка цвета с помощью драйвера устройства ANSI.SYS {4.1.3}. В общем необходимо только поместить символ в DL, номер функции в AH и вызвать прерывание 21H. Однако функция 6 особенная в том смысле, что она имеет второе назначение в качестве функции ввода с клавиатуры. Она выступает в этой роли только если в DL помещен код FF {3.1.5}. Во всех остальных случаях она выводит на экран содержимое DL. В следующем примере функция 6 поочередно принимает и печатает символ (в {3.1.4} обсуждается процедура, которая комбинирует оба этих свойства).
MOV AH,6 ;номер функции
NEXT: MOV DL,0FFH ;при этом значении принимаем ввод
INT 21H ;выполняем прерывание
JZ NEXT ;если не было ввода, то обратно
CMP AL,13 ;это был возврат каретки?
JE END_INPUT ;если да, то на конец
MOV DL,AL ;иначе посылаем символ в DL
INT 21H ;и выводим его на экран
JMP SHORT NEXT ;повторяем процедуру

Hизкий уровень.

Hа нижнем уровне весь вывод на экран осуществляется через отображение в память. Эту технику не рекомендуют использовать, чтобы не столкнуться с проблемой совместимости с будущими поколениями машин, однако до сих пор IBM делало видеобуфер своих микрокомпьютеров устроенным одинаково и расположенным в одних и тех же адресах памяти. Поскольку буфер устроен таким образом, что байты атрибутов перемежаются с байтами символов, то символьные данные не могут просто пересылаться из памяти в буфер инструкцией MOVSB, поскольку указатель в буфере должен увеличиваться на два после каждого переноса байта. Однако, использование этой техники существенно ускоряет вывод на экран. Отметим, что отображение в память не работает при выводе символов в графическом режиме. В этом случае размер видеобуфера 16K или 32K и BIOS рисует каждый символ поточечно. Отметим также, что при отображении в память не используется курсор для указания на символ. При желании можно перемещать курсор по мере ввода {4.2.1} или выключить его и создать свой псевдокурсор {4.2.6}.
;---в сегменте данных
SAMPLE_STRING DB 'PRINT THIS STRING$'
;---вывод строки
MOV AX,0B000H ;монохромный дисплей
MOV ES,AX ;указываем на видеобуфер
LEA BX,SAMPLE_STRING ;BX указывает на строку
MOV DI,CURSOR_START ;начальная позиция в буфере
NEXT: MOV AL,[BX] ;берем символ
CMP AL,'$' ;проверка на конец строки
JE ALL_DONE ;если да, то выход
MOV ES:[DI],AL ;иначе помещаем символ в буфер
INC DI ;увеличиваем указатель на 2
INC DI ;
INC BX ;переходим к обработке следу-
JMP SHORT NEXT ;щего символа
ALL_DONE:

У цветного графического адаптора и PCjr (но не у EGA) имеется проблема, связанная с отображением в память. Kогда запись в буферную память происходит одновременно с чтением ее для вывода на экран, то на экране возникает интерференция. Эта проблема решается ожиданием сигнала "все чисто" (all clear) перед записью в видеобуфер. Hадо непрерывно читать значение из порта 3DAH. Kогда бит 0 равен 1, то можно спокойно писать. (3DAH - это порт, через который PCjr посылает данные массиву ворот дисплея; когда из него читаем, то он возвращает регистр статуса, как и у цветного адаптора.)
;---ожидаем пока все чисто
MOV DX,3DAH ;порт регистра статуса
CHECK_AGAIN: IN AL,DX ;получаем значение
TEST AL,1 ;проверка первого бита
JNE CHECK_AGAIN ;если он 0, то обратно
;---теперь выводим сообщение
LEA BX,MESSAGE ;сообщение в сегменте данных
MOV DI,2000 ;начинаем вывод с центра экрана
MOV AH,01000001B ;атрибут синий на красном
NEXT_CHAR: MOV AL,[BX] ;берем символ
CMP AL,'$' ;проверяем на конец строки
JE ALL_DONE ;если конец, то на выход
MOV ES:[DI],AX ;иначе выводим символ
INC BX ;увеличиваем указатель строки
INC DI ;увеличиваем указатель буфера
INC DI ;
JMP SHORT NEXT_CHAR ;обрабатываем следующий символ
ALL_DONE:

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


<~-Раздел 3. Вывод символов на экран.
Содержание
4.3.2 Вывод строки символов на экран.-~>

Сайт управляется системой uCoz