ра PRINT поставить точку с запятой, например, PRINT S$;.
Для установки позиции курсора перед выводом используется оп-
ератор LOCATE. Без оператора LOCATE PRINT всегда начинает вывод с
первой позиции строки, в которой находится курсор. Последователь-
ные операторы PRINT заполняют экран до тех пор, пока не будет
записана 24-я строка, после чего экран сдвигается вверх, с тем
чтобы следующий оператор PRINT снова выводил 24-ю строку. PRINT
может выводить в 25-й строке только при помощи LOCATE; и это
также приводит к автоматическому сдвигу экрана вверх. Чтобы зап-
ретить сдвиг надо окончить оператор PRINT точкой с запятой. Одна-
ко этот метод не сработает в последних позициях строк 24 и 25.
Для заполнения этих позиций без сдвига экрана Вы должны использо-
вать отображение в память, как показано ниже.
Вы можете включать управляющие символы [7.1.9] внутрь операто-
ра PRINT для того чтобы реализовать перемещения курсора внутри
строки. Hапример, если Вы поместите в строку CHR$(13), то в этой
точке будет сделан возврат каретки. Если Вы выведете оператором
PRINT строку "One"+CHR$(13)+"Two"+CHR$(13)+"Three", то в резуль-
тате каждое слово будет выводиться с новой строки. Kоды ASCII
28-31 сдвигают курсор на одну позицию соответственно вправо,
влево, вверх и вниз. Оператор PRINT не содержащий данных приводит
к выводу возврата каретки и, таким образом, следующий оператор
PRINT будет выводить на строке через одну.
Прямое отображение в память существенно увеличивает скорость
вывода на экран в Бейсике. Оно особенно полезно при конструирова-
нии табличного вывода, когда формы могут достигать правого нижне-
го угла экрана. Сначала надо установить указатель сегмента на
&HB000, а затем использовать оператор POKE для засылки байтов
памяти. Прилегающие по горизонтали символы отстоят друг от друга
на два байта, разделяемые байтом атрибутов. Для 80-символьных
экранов прилегающие по вертикали символы отстоят на 160 байт друг
от друга (2 байта для каждого символа и атрибутов). В следующих
двух примерах вдоль границы экрана рисуется рамка, используя
символы псевдографики. В первом примере чаще используется опера-
тор PRINT, а во втором используется исключительно прямое отобра-
жение в память. Отметим, что и в первом случае приходится исполь-
зовать прямое отображение в память в последних столбцах строк 24
и 25, чтобы избежать сдвига экрана.
Использование PRINT:
10 CLS: KEY OFF 'очистка экрана
20 DEF SEG = &HB000 'указываем на видеобуфер
30 LOCATE 1,1: PRINT CHR$(201) 'левый верхний угол
40 LOCATE 1,80: PRINT CHR$(187) 'правый верхний угол
50 LOCATE 1,24: PRINT CHR$(186) '
60 LOCATE 1,25: PRINT CHR$(200) '
70 POKE 3838,186 'позиция 80 строки 24
80 POKE 3998,188 'позиция 80 строки 25
90 FOR N=2 TO 79 'горизонтальные линии
100 LOCATE 1,N: PRINT CHR$(205);: LOCATE 25,N: PRINT CHR$(205)
110 NEXT '
120 FOR N=2 TO 23 'вертикальные линии
130 LOCATE N,1: PRINT CHR$(186): LOCATE N,80: PRINT CHR$(186)
140 NEXT
Использование прямого отображения в память:
10 CLS: KEY OFF 'очистка экрана
20 DEF SEG = &HB000 'буфер монохромного дисплея
30 POKE 0,201 'левый верхний угол
40 POKE 158,187 'правый верхний угол
50 POKE 3840,200 'левый нижний угол
60 POKE 3998,188 'правый нижний угол
70 FOR N=2 TO 156 STEP 2 'горизонтальные прямые
80 POKE N,205: POKE N+3840,205 'как верхняя, так и нижняя
90 NEXT
100 FOR N=160 TO 3680 STEP 160 'вертикальные прямые
110 POKE N,186: POKE N+158,186 'правая и левая
120 NEXT
Средний уровень.
Операционная система предоставляет шесть процедур вывода на
экран - три в 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огда строка выводимых символов займет все свободное
пространство экрана справа-вниз от курсора, то вывод будет пере-
несен в первые позиции экрана.
;---вывод символа в негативе
MOV AH,9 ;функция записи с атрибутами
MOV AL,THE_CHARACTER ;символ в AL
MOV BL,112 ;атрибуты в BL
MOV BH,0 ;страница 1
MOV CX,1 ;вывести один раз
INT 10H
Вместо того, чтобы постоянно восстанавливать значение счетчика в
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, то обратно