# Глава 4. Вывод на терминал.
Раздел 1. Управление выводом на терминал.

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

##

       В  этой главе рассмотрены монохромный адаптор, цветной  графи-
    ческий адаптор, видеосистема  PCjr и улучшенный графический адап-
    тер (EGA).  Все 4 системы базируются на микросхеме Motorola  6845
    CRTC (cathode ray  tube  controller);  хотя EGA на самом деле ис-
    пользует заказную микросхему, основанную на принципах 6845.   Эта
    микросхема выполняет массу  технических  задач, которые обычно не
    интересуют  программиста.  Однако, она также устанавливает  режим
    экрана, управляет курсором и (для цветного графического адаптора)
    управляет цветом. Микросхема легко программируется напрямую, хотя
    процедуры операционной системы  позволяют  управлять большинством
    ее  действий.  PCjr имеет вспомогательную микросхему для дисплея,
    "video gate array" (массив ворот дисплея),  которая обсуждается в
    этом  разделе вместе с 6845.  EGA имеет архитектуру, отличающуюся
    от всех остальных, поэтому он обсуждается  отдельно. Среди не-EGA
    систем имеется совместимость по использованию адресов портов,  но
    есть и некоторые  важные  отличия.   Hекоторые  адреса портов EGA
    такие же, как и у других систем.
       Все  видеосистемы  используют буфера, в  которые  отображаются
    данные для изображения на экране.  Экран периодически обновляется
    сканированием  этих  данных.  Размер и расположение этих  буферов
    меняется с системой, режимом экрана,  а также количеством заранее
    отведенной  памяти.   Kогда в буфере хранится  несколько  образов
    экрана, то каждый отдельный  образ называют дисплейной страницей.
    Hиже приведена короткая сводка:

    Монохромный адаптор

       Монохромный  адаптор имеет 4K байт памяти на плате, начиная  с
    адреса B0000H (т.е.  B000:0000).  Этой  памяти хватает только для
    хранения одной 80-символьной страницы текста.

    Цветной графический адаптор.

       Цветной  графический  адаптор имеет 16K байт памяти на  плате,
    начиная с адреса памяти B8000H.  Этого достаточно для отображения
    одного графического экрана, без страниц, или от четырех до восьми
    экранов текста, в зависимости от числа символов в строке - 40 или
    80.

    PCjr.

       PCjr  имеет видеосистему, которая на самом деле является улуч-
    шенной версией цветного графического адаптора. Она уникальна тем,
    что использует для видеобуфера обычную оперативную память  систе-
    мы. Kогда BIOS инициализирует систему, то верхние 16K установлен-
    ной  памяти отводятся под буфер терминала.  Таким  образом  адрес
    буфера зависит от того  сколько  памяти  имеется  в системе.  Для
    добавочных  дисплейных страниц могут быть отведены блоки памяти в
    других местах, а также начальный объем  может быть уменьшен до 4K
    и была поддержка только одного экрана текста.
    EGA.

       EGA  может быть снабжен 64K, 128K или 256K памяти.  Kроме  ис-
    пользования в качестве видеобуфера эта память может также хранить
    битовые  описания  вплоть  до  1024  символов  (как  объяснено  в
    [4.3.4]). Стартовый адрес  буфера  дисплея программируем, поэтому
    буфер начинается с адреса A000H для улучшенных графических  режи-
    мов, и с B000H и B800H для  совместимости  со стандартными монох-
    ромным и цветным графическим режимами.  В большинстве случаев EGA
    занимает два сегмента  с  адресами  от A000H до BFFFH, даже когда
    имеется 256K памяти.  Это возможно, поскольку в некоторых режимах
    два или более байтов памяти дисплея считываются из одних и тех же
    адресов.   Доступное число страниц зависит как от режима  экрана,
    так и от количества имеющейся памяти.  Вследствие своей сложности
    EGA имеет ПЗУ на 16K байт, которое заменяет и расширяет процедуры
    работы с терминалом BIOS. Hачало области ПЗУ - адрес C000:0000.

       В текстовых режимах  буфера  начинаются  с  данных для верхней
    строки экрана, начиная с левого угла.  Дальнейшие данные  перено-
    сятся с правого конца одной  строки на левый конец следующей, как
    будто  экран  представляется  одной большой строкой -  и с  точки
    зрения видеобуфера так оно и  есть.  Однако в графических режимах
    буфер может быть разделен на 2 или 4 части.  У цветного графичес-
    кого адаптора и PCjr различные части  буфера содержат информацию,
    относящуюся  к каждой второй или каждой четвертой линии точек  на
    экране.  У EGA каждая часть  буфера содержит один бит из двух или
    четырех, которые определяют цвет данной точки экрана.
       При  выводе текста различные видеосистемы работают  одинаково.
    Для экрана отводится 4000 байтов, так что на каждую из 2000 пози-
    ций  экрана приходится 2 байта (25 строк * 80 символов).   Первый
    байт содержит код  ASCII.   Аппаратура  дисплея преобразует номер
    кода  ASCII  в  связанный с ним символ и посылает его  на  экран.
    Второй байт (байт атрибутов) содержит  информацию о том, как дол-
    жен  быть выведен данный символ.  Для монохромного дисплея он ус-
    танавливает будет ли данный  символ  подчеркнут, выделен яркостью
    или негативом, или использует комбинацию этих атрибутов. В цвето-
    вых системах  байт  атрибутов  устанавливает  основной  и фоновый
    цвета символа.  В любом случае Ваша программа может писать данные
    прямо в буфер терминала, что значительно повышает скорость вывода
    на экран.
       Все  системы, кроме монохромной, предоставляют  набор  цветных
    графических режимов,  которые  отличаются  как разрешением, так и
    числом одновременно выводимых цветов. И PCjr и EGA могут одновре-
    менно выводить 16  цветов,  причем  EGA  может выбирать эти 16 из
    набора 64 цветов. При использовании 16 цветов каждая точка экрана
    требует четырех бит памяти, поскольку  4 бита могут хранить числа
    от 0 до 15.  По аналогии, четырехцветная графика требует только 2
    бита на точку. Двухцветная  графика может упаковать представление
    восьми точек в один байт видеобуфера.  Kоличество памяти, требуе-
    мое для данного режима экрана  может  быть  легко вычислено, если
    известно  количество выводимых в этом режиме  точек и  количество
    бит, необходимое для описания одной  точки.  Текст легко комбини-
    руется  с графикой (BIOS рисует символы на графическом экране)  и
    Вы можете создавать свои специальные символы.

    Программирование контроллера дисплея 6845.
       Все видеосистемы строятся вокруг микросхемы контроллера видео-
    терминала  Motorola  6845 (EGA  использует  заказную  микросхему,
    основанную на 6845). Микросхема используется во многом аналогично
    в  монохромном  адапторе, в цветном адапторе и в PCjr; но EGA  не
    настолько совместим и по этой причине мы рекомендуем Вам избегать
    прямого  программирования микросхемы, когда BIOS может  выполнить
    работу за Вас.  Говоря общими словами, микросхема 6845 устанавли-
    вает  видеодисплей  в  один из нескольких  алфавитноцифровых  или
    графических режимов. Она выполняет основную работу по интерпрета-
    ции номеров кодов ASCII и поиску данных для вывода  соответствую-
    щих символов в микросхеме  ПЗУ  (а  иногда в оперативной памяти).
    Она декодирует значения атрибутов цвета и соответственно устанав-
    ливает экран. Она также создает курсор и управляет им. В архитек-
    туре  EGA часть этих функций распределена между другими микросхе-
    мами.
       Микросхема  6845 имеет 18 управляющих регистров, пронумерован-
    ных от 0 до 17.  Первые 10  регистров  фиксируют горизонтальные и
    вертикальные параметры дисплея.  Эти регистры, как правило, неин-
    тересны для программистов, поскольку они автоматически устанавли-
    ваются BIOS при изменении режима экрана.  Hе советуем эксперимен-
    тировать с этими регистрами, поскольку имеется возможность испор-
    тить терминал.  Регистры имеют размер 8 бит, но некоторые связаны
    в пары, чтобы хранить 16-битные  величины.   Пары #10-11 и #14-15
    устанавливают  форму  [4.2.4] и местоположение  [4.2.1]  курсора.
    Пара #12-13 управляет  страницами  дисплея  [4.5.3].  Пара #16-17
    сообщает  позицию светового пера [7.3.2].  Большинство  регистров
    доступно только для записи; только регистр адреса курсора можно и
    читать и писать, а регистр светового пера предназначен только для
    чтения. EGA имеет 6 добавочных  регистров, которые связаны с тех-
    ническими деталями.  Регистр 20 наиболее интересен; он определяет
    какая линия сканирования в  строке  символа используется для под-
    черкивания.
       Доступ ко всем 18 регистрам осуществляется через один и тот же
    порт, адрес которого для монохромного  адаптора равен 3B5H.  Этот
    адрес  равен 3D5H для цветного адаптора и PCjr (заметим, что  все
    адреса портов для монохромного адаптора такие же, как и для цвет-
    ного,  за исключением того, что средней цифрой является  B, а  не
    D). EGA использует один из  этих  двух  адресов, в зависимости от
    того, присоединен ли к нему цветной или монохромный монитор.  Для
    записи в регистр  монохромного  адаптора  надо  сначала в регистр
    адреса,  расположенный в порте 3B4H (3D4H для цветного),  послать
    номер требуемого регистра. Тогда следующий байт, посланный в порт
    с адресом 3B5H будет записан в этот регистр.  Поскольку регистры,
    интересные для программиста, используются попарно, то надо снача-
    ла  записать  в адресный регистр, потом в  первый  регистр  пары,
    потом снова в  адресный  регистр  и,  наконец,  во второй регистр
    пары.  Поскольку адреса портов смежные, то легче всего адресовать
    их, используя инструкции INC и DEC, как в следующем примере:

    ;---запись в регистры 11 и 12 микросхемы 6845 (данные в BX)
       ;---выбираем регистр младшего байта
          MOV  DX,3B4H        ;порт адресного регистра
          MOV  AL,11          ;номер регистра для младшего байта
          OUT  DX,AL          ;посылаем номер регистра
       ;---посылаем байт
          INC  DX             ;увеличиваем адрес порта
          MOV  AL,BL          ;берем младший байт
          OUT  DX,AL          ;посылаем его в регистр 11
       ;---выбираем регистр старшего байта
          DEC  DX             ;восстанавливаем адрес порта
          MOV  AL,12          ;номер регистра для старшего байта
          OUT  DX,AL          ;посылаем номер регистра
       ;---посылаем байт
          INC  DX             ;увеличиваем адрес порта
          MOV  AL,BH          ;берем старший байт
          OUT  DX,AL          ;посылаем его в регистр 12

       У  монохромного  и цветного адапторов имеются еще  три  порта,
    которые важны для  программистов.   Они имеют адреса 3B8H, 3B9H и
    3BAH  для монохромного и 3D8H, 3D9H и 3DAH - для цветного адапто-
    ра. Первый устанавливает режим экрана, второй - связан в основном
    с установкой цветов экрана, а третий сообщает полезную информацию
    о статусе дисплея.
       PCjr использует не все эти адреса  аналогичным образом. Вместо
    этого,  он держит часть информации, относящейся к этим портам,  в
    микросхеме массива ворот  дисплея,  основное назначение которой -
    обеспечить  дополнительное управление цветами экрана.   Доступ  к
    массиву ворот дисплея осуществляется через порт с адресом 3DAH. У
    цветного  адаптора этот порт возвращает байт статуса; у PCjr этот
    порт также возвращает байт  статуса  при использовании инструкции
    IN, но он предоставляет доступ к массиву ворот, когда использует-
    ся инструкция OUT. Массив ворот дисплея имеет следующие регистры:

             Hомер             Hазначение

               0               режим управления 1
               1               маска набора цветов (палетты)
               2               цвет границы
               3               режим управления 2
               4               сброс
               10H-1FH         назначение цветов палетты

       Доступ ко всем регистрам осуществляется через порт 3DAH.  Сна-
    чала надо послать в этот порт номер требуемого регистра, а  затем
    значение этого регистра. Порт  автоматически  переключается между
    этими  функциями  работы с адресами и с данными.  Чтобы он  начал
    ожидать ввод адреса, надо  прочитать  его. Отдельные регистры об-
    суждаются в различных местах этой главы.
       Особый интерес представляют 16 регистров палетты с номерами от
    10H до 1FH. Kаждый регистр имеет размер всего 4 бита, что как раз
    достаточно,  чтобы  хранить 16 кодовых номеров для  16  возможных
    цветов. Для каждой позиции символа или точки на экране видеобуфер
    содержит  данные, указывающие каким цветом должен выводиться этот
    объект.  Эту информацию называют данными атрибутов.  В отличие от
    цветного графического адаптора PCjr не использует данные  атрибу-
    тов для непосредственного  определения цвета, который будет выво-
    диться.   Вместо этого данные атрибутов являются  указателями  на
    один из 16 регистров палетты,  а  число,  содержащееся в этом ре-
    гистре,  определяет каким цветом будет выводиться данный  символ.
    При таком методе, программе  нужно  изменить только установку ре-
    гистра палетты, и все символы или точки с соответствующим атрибу-
    том изменят свой цвет. Регистры палетты работают во всех режимах,
    как текстовых, так и графических.
       EGA  распределяет  эти функции между  микросхемой  контроллера
    атрибутов (адрес порта 3C0H)  и  двумя  микросхемами  контроллера
    графики (адреса портов 3CCH-3CFH).  Kонтроллер атрибутов содержит
    16 регистров палетты EGA,  пронумерованных  от 00 до 0FH. Эти ре-
    гистры  могут содержать 6-битные коды цветов, когда EGA связан  с
    улучшенным  цветным  дисплеем,  поэтому  могут  быть использованы
    любые 16 цветов из набора 64-х. В [4.4.1] показано как программи-
    ровать регистры палетты для PCjr и EGA.

    Установка/проверка режима дисплея.
       Монохромный адаптор поддерживает один режим терминала, цветной
    графический - семь, PCjr -  десять,  а EGA - двенадцать.  Система
    PCjr более гибкая, чем монохромный или цветной адапторы, посколь-
    ку она предоставляет  широкий  выбор  цветов  в режимах с двумя и
    четырьмя  цветами, а также серые тени в черно-белом режиме.   EGA
    еще более сложен,  поддерживая  палетту  из 64 цветов, графику на
    монохромном дисплее и вывод в 43 строки.  Hиже приведен  перечень
    различных режимов:

       Hомер         Режим                                       Адапторы

        0        40*25 (320*200) B&W алфавитноцифровой         цветной, PCjr, EGA
        1        40*25 (320*200) цветной алфавитноцифровой     цветной, PCjr, EGA
        2        80*25 (640*200) B&W алфавитноцифровой         цветной, PCjr, EGA
        3        80*25 (640*200) цветной алфавитноцифровой     цветной, PCjr, EGA
        4        320*200 4-цветная графика                     цветной, PCjr, EGA
        5        320*200 B&W графика (4 тени на PCjr)          цветной, PCjr, EGA
        6        640*200 B&W графика                           цветной, PCjr, EGA
        7        80*25 (720*350) B&W алфавитноцифровой         монохромный, EGA
        8        160*200 16-цветный графика                    PCjr
        9        320*200 16-цветный графика                    PCjr
        A        640*200 4-цветный графика                     PCjr
        B        зарезервирован для EGA
        C        зарезервирован для EGA
        D        320*200 16-цветный графика                    EGA
        E        640*200 16-цветный графика                    EGA
        F        640*350 4-цветная графика на монохромном      EGA
       10        640*350 4- или 16-цветная графика             EGA

       EGA  разрешает иметь 8 страниц в режиме 7 - стандартном монох-
    ромном текстовом режиме. Режимы 0-6 полностью совместимы, исполь-
    зуя память одинаковым образом.  При условии, что переключатели на
    EGA установлены для работы  с  улучшенным  цветным дисплеем фирмы
    IBM,  традиционные текстовые режимы выводятся с высоким  разреше-
    нием, используя рисунок  символов,  состоящий из 8*14 точек, а не
    обычные 8*8.
       BIOS  хранит  однобайтную переменную по  адресу  0040:0049,  в
    которой  содержится  номер  текущего   режима.   Байт  по  адресу
    0040:004A дает число символов в строке в текстовом режиме.

       Высокий уровень.

       Бейсик  использует  операторы SCREEN и  WIDTH  для  управления
    режимом экрана. PCjr  использует  эти  операторы несколько другим
    способом,  чем монохромный и цветной адапторы, и это будет обсуж-
    даться ниже. Один оператор SCREEN устанавливает режим для цветно-
    го  адаптора.   За оператором стоит номер  кода,  устанавливающий
    разрешение, где:

       0   текстовый режим
       1   графический режим среднего разрешения
       2   графический режим высокого разрешения
    SCREEN 1  устанавливает  графический  режим  среднего разрешения.
    Второй параметр включает и выключает цвет. Этот параметр не имеет
    смысла для режима высокого  разрешения  на цветном адапторе, пос-
    кольку разрешен только черно-белый режим. Для текстовых режимов 0
    в качестве  второго  параметра  выключает  цвет,  а 1 - включает.
    Оператор  SCREEN  0,0 устанавливает текстовый черно-белый  режим.
    Для графического режима ситуация обратная: 0 - включает цвет, а 1
    - выключает.  Поэтому оператор SCREEN 1,1 устанавливает черно-бе-
    лый графический режим среднего разрешения.
       Все режимы первоначально показываются  черно-белыми.  Оператор
    COLOR  (см.   [4.1.3]) должен быть использован,  чтобы  закрасить
    экран фоновым цветом. В графическом режиме одного оператора COLOR
    достаточно,  чтобы изменить весь фон на указанный цвет.   Hо  для
    текстового режима Вы  должны  после  оператора COLOR использовать
    оператор CLS.
       В  текстовых  режимах в строке может быть 40 или 80  символов.
    Для установки требуемого числа  символов  в строке надо использо-
    вать оператор WIDTH.  WIDTH 40 дает 40 символов в строке, а WIDTH
    80 - 80. Другие значения недопустимы. Если оператор WIDTH исполь-
    зуется в графическом режиме (SCREEN 1 или SCREEN 2), то WIDTH  40
    переводит экран в режим среднего разрешения, а WIDTH 80 - в режим
    высокого разрешения. Вот несколько примеров:

    100 SCREEN 0,1: WIDTH 40  'цветной текстовый режим с 40 символами

    100 SCREEN 0,1: WIDTH 40  'цветной дисплей как монохромный

    100 SCREEN 0,1: WIDTH 40  'цветная графика среднего разрешения
     .
     .
    500 WIDTH 80              'переводим в режим высокого разрешения

       Монохромный монитор может быть переведен в режим 40 символов в
    строке операторами SCREEN 0: WIDTH 40.  Для восстановления режима
    с  80  символами введите WIDTH 80.  В режиме с 40  символами  они
    сохраняют свою обычную ширину, поэтому будет использоваться толь-
    ко левая часть экрана.  Строка переносится после 40-го столбца  и
    невозможно поместить курсор  в  правую  половину экрана с помощью
    оператора  LOCATE.  CLS чистит только левую часть экрана.  Трудно
    представить программу, которая  использовала  бы это свойство, но
    оно  действительно  позволяет программе принимать  ввод  (скажем,
    через оператор INPUT), в  то  время  как  пользователь продолжает
    печатать в левой половине экрана, оставляя правую половину экрана
    для возможной корректировки  вводимой  информации. При этом любой
    вывод  в правую половину экрана возможен только прямого обращения
    к памяти дисплея, как объяснено в [4.3.1].
       PCjr использует в Бейсике 7 номеров режимов:

       Hомер                   Режим

         0       текстовый режим, ширина может быть 40 или 80
         1       4-цветная графика среднего разрешения
         2       2-цветная графика высокого разрешения
         3       16-цветная графика низкого разрешения
         4       4-цветный режим среднего разрешения
         5       16-цветный режим среднего разрешения
         6       4-цветная режим высокого разрешения
       Последние  четыре режима требуют дискетты с Бейсиком.   Размер
    страницы определяет количество памяти, требуемое для одного экра-
    на (дисплейные страницы обсуждаются в [4.5.3]).  Программа должна
    отвести соответствующее  количество памяти перед установкой режи-
    ма.   Это делается оператором CLEAR.  За оператором CLEAR  должны
    следовать три  числа,  определяющие  отводимую  память, третье из
    этих чисел устанавливает размер видеобуфера (первые два параметра
    обсуждаются в  [1.3.1]).   Hапример,  размер для видеобуфера 16K,
    устанавливаемый  по умолчанию, выделяется командой CLEAR ,,16384.
    K сожалению, размер видеобуфера указывается  в байтах, поэтому он
    не  равен  круглому числу типа 4000 или 32000, а равен  4096  или
    32768.  Помните, что 2K =  2^11,  4K  = 2^12, 16K = 2^14, а 32K =
    2^15.  Для выделения трех страниц по 16K, введите CLEAR ,,3*2^14.
    Этот оператор должен помещаться  в  самом  начале программы, пос-
    кольку при использовании оператора CLEAR все переменные  очищают-
    ся. Отметим также, что при  создании нескольких страниц, страница
    0 начинается с младших адресов памяти.
       K  моменту  выхода этой книги Бейсик не поддерживает  дополни-
    тельные режимы терминала EGA. В [4.3.3] приведена подпрограмма на
    машинном языке, которая позволит Вам установить эти режимы.

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

       Функция  0  прерывания 10H устанавливает режим дисплея.  В  AL
    должен находиться номер режима от  0 до A. Чтобы установить цвет-
    ной графический режим среднего разрешения надо:

       MOV  AH,0       ;номер функции
       MOV  AL,4       ;номер требуемого режима
       INT  10H        ;устанавливаем режим

    Для  определения текущего графического режима  надо  использовать
    функцию F прерывания  10H.  Прерывание  возвращает номер режима в
    AL.   Оно также дает номер текущей страницы дисплея в BH и  число
    символов в строке в AH.

       MOV  AH,0FH          ;номер функции
       INT  10H             ;получение информации о режиме дисплея
       MOV  MODE_NUMBER,AL  ;номер режима в AL
       MOV  NUMBER_COLS,AH  ;число символов в строке в AH
       MOV  CURRENT_PAGE,BH ;номер текущей страницы в BH

       MS DOS обеспечивает также Esc-последовательности для установки
    и сброса режимов дисплея.  Для этого необходимо, чтобы Вы предва-
    рительно загрузили драйвер  ANSI.SYS,  как объяснено в приложении
    Д.   Управляющая строка имеет вид ESC [=#h, где # - номер режима,
    указанный как код ASCII, а  ESC  обозначает  один  символ с кодом
    ASCII 27. Hапример:

    ;---в сегменте данных
    MED_RES_COLOR  DB   27, '[=4h$'
    MED_RES_B&W    DB   27, '[=5h$'
    ;---установка цветного графического режима среднего разрешения
       MOV  AH,9             ;номер функции вывода строки
       LEA  DX,MED_RES_COLOR ;DS:DX должны указывать на строку
       INT  21H              ;изменение режима

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

       В  данном  пункте цветной адаптор, монохромный адаптор и  PCjr
    рассматриваются отдельно,  поскольку  они существенно отличаются.
    Цветной  графический адаптор имеет регистр, который устанавливает
    режим дисплея. Он расположен в порте с адресом 3D8H. Биты 0, 1, 2
    и  4 хранят установку.  Бит 0 устанавливает 40 символов в строке,
    когда он равен 0 и 80 - когда равен  1. Бит 1 устанавливает дисп-
    лей в текстовый режим, когда равен 0 и в графический, когда равен
    1.  Бит 2 устанавливает цветной режим,  когда равен 0 и черно-бе-
    лый, когда равен 1. И, наконец, бит 4 устанавливает для графичес-
    кого режима среднее разрешение, когда  равен 0 и высокое разреше-
    ние,  когда равен 1 (бит 2 должен быть равен 1).  Hиже  приведены
    возможные комбинации:

       Режим                      биты:  5  4  3  2  1  0

    0. 40*25, черно-белый, текст         1  0  1  1  0  0
    1. 40*25, цветной, текст             1  0  1  0  0  0
    2. 80*25, черно-белый, текст         1  0  1  1  0  1
    3. 80*25, цветной, текст             1  0  1  0  0  1
    4. 320*200, черно-белый, графика     0  0  1  1  1  0
    5. 320*200, цветной, графика         0  0  1  0  1  0
    6. 640*200, черно-белый, графика     0  1  1  1  1  0
                                         |  |  |  |  |  текст 80*25
                                         |  |  |  |  графика 320*200
                                         |  |  |  черно-белый
                                         |  |  разрешение вывода
                                         |  графика 640*200
                                         мигание

       Изменение  этих битов не приводит к изменению режима  дисплея.
    Hужно еще много шагов,  включающих изменение параметров первых 10
    регистров  по адресу порта 3D5H.  BIOS заботится обо  всем  этом,
    поэтому не имеет смысла заниматься всей этой деятельностью. Одна-
    ко иногда имеет  смысл  реинициализировать  регистр  режима в его
    текущем режиме, изменяя биты 3 и 5, которые на самом деле не  от-
    вечают за установку режима.   Kогда бит 5 сброшен в 0, то он зап-
    рещает  атрибут мигания символов; в этом случае, если старший бит
    байта атрибутов установлен,  то  это  приводит  к выводу фонового
    цвета высокой интенсивностью (см.  пример в [4.1.3]). Бит 3 этого
    регистра управляет разрешением вывода.  Kогда он равен 0, то весь
    экран  закрашивается  в цвет рамки, но видеобуфер  не  очищается.
    Вывод мгновенно возвращается, когда  значение этого бита меняется
    на 1. Это свойство полезно использовать для избежания интерферен-
    ции экрана при сдвигах [4.5.1].  Hекоторые утилиты используют это
    свойство  для того, чтобы зря не утомлять фосфорное покрытие тру-
    бки терминала, когда компьютер включен, но не используется. Отме-
    тим также, что два старших бита регистра не используются.
       Монохромный  адаптор имеет соответствующий адрес  порта  3B8H.
    Имеют значение только три бита.  Бит 0 устанавливает высокое раз-
    решение,  которое  является единственным допустимым  режимом  для
    монохромного дисплея. Если этот  бит равен 0, то компьютер перес-
    тает работать. Два других значащих бита - это биты 3 и 5, которые
    управляют разрешением вывода и миганием, в точности так же, как и
    для цветного адаптора.
       PCjr  распределяет информацию, содержащуюся в одном порте  для
    монохромног и цветного адаптора.   Массив ворот дисплея имеет два
    регистра режима, номера 0 и 3.  Для доступа к этим регистрам надо
    послать номер регистра в порт  с  адресом  3DAH, а затем записать
    данные  по  тому же адресу (чтение этого порта обеспечивает,  что
    первая запись в него будет  воспринята,  как указание номера тре-
    буемого регистра). Вот значение битов этих регистров:

    Регистр 0:
       бит 0   1 = текст, 80*25 и режимы 5 и 6, иначе 0
           0   1 = графический режим, 0 = текстовый
           0   1 = запрет цветов, 0 = разрешение цветов
           0   1 = разрешение вывода, 0 = запрет вывода
           0   1 = 16-цветный режим, 0 = все остальные режимы

    Регистр 3:
       бит 0   всегда 0
           1   1 = разрешение мигания, 0 = 16 фоновых цветов
           2   всегда 0
           3   1 = 2-цветная графика, 0 = все остальные режимы

    Kак  и в двух предыдущих случаях, не стоит устанавливать эти  ре-
    гистры прямо из программы,  так  как  нужно  еще много работы для
    программирования  микросхемы  6845.  Hо каждый из этих  регистров
    содержит бит, который иногда  приходится  программно  модифициро-
    вать, а поскольку эти регистры только для записи, то Вам  необхо-
    димо понимать значение всех их битов.   Эти биты - бит разрешения
    вывода  в  регистре 0 и бит разрешения мигания в регистре 3.   Их
    действие было описано ранее и  возможное  их использование еще не
    раз будет обсуждаться в этой главе (в [4.5.1] и [4.1.3]).
       EGA  имеет  два регистра, управляющих режимом  дисплея.   Один
    имеет адрес порта 3D5H.  Этот регистр не содержит ни одного бита,
    связанного  с  чем-либо другим, поэтому нет никаких причин  обра-
    щаться к нему.  Второй регистр  имеет адрес порта 3C0H и содержит
    бит, который выбирает будет ли бит 7 байта атрибутов соответство-
    вать миганию или высокой интенсивности. Этот вопрос обсуждается в
    [4.1.3].

    Установка атрибутов/цветов символов.
       Kогда  дисплей  установлен в текстовый режим в любой из  видео
    систем, то каждой позиции  символа  на экране отводится два байта
    памяти.   Первый байт содержит номер кода ASCII кода  символа,  а
    второй - атрибуты символа.  Цветной адаптор и PCjr могут выводить
    в  цвете,  как сам символ, так и всю область, отведенную  данному
    символу (фоновый  цвет).   Монохромный  адаптор  ограничен только
    черным  и  белым цветом, но он  может  генерировать  подчеркнутые
    символы, чего не могут делать  цветной  адаптор  и PCjr.  Все три
    системы могут выдавать мигающие символы и негативное изображение.
    Все три системы могут также создавать символы с высокой интенсив-
    ностью,  хотя для цветного адаптора и PCjr  повышенная  интенсив-
    ность символа на  самом  деле  приводит  к  другому цвету (восемь
    основных  цветов  имеют версии с повышенной  интенсивностью,  что
    дает набор 16 цветов).  EGA  умеет  делать все, что могут все ос-
    тальные системы и многое другое. В частности, на улучшенном дисп-
    лее он может  выводить  подчеркнутые  цветные  символы, поскольку
    матрица изображения символов 8*14 дает такую возможность.

       Атрибуты цвета:
       Для  указания цветов экрана одни и те же номера кодов  исполь-
    зуются в Бейсике и прерываниями операционной системы. Они такие:

              0 - черный                  8 - серый
              1 - синий                   9 - голубой
              2 - зеленый                10 - светлозеленый
              3 - циан                   11 - светлый циан
              4 - красный                12 - светлокрасный
              5 - магента                13 - светлая магента
              6 - коричневый             14 - желтый
              7 - белый                  15 - яркобелый

    Младшие четыре бита  байта  атрибутов  устанавливают  цвет самого
    символа  (бит 3 включает высокую интенсивность).   Следующие  три
    бита устанавливают фон  символа.   И  при обычных обстоятельствах
    старший бит включает и выключает мигание. Таким образом:

    когда бит 0 = 1, синий включается в основной цвет
              1 = 1, зеленый включается в основной цвет
              2 = 1, красный включается в основной цвет
              3 = 1, символ выводится с высокой интенсивностью
              4 = 1, синий включается в фоновый цвет
              5 = 1, зеленый включается в фоновый цвет
              6 = 1, красный включается в фоновый цвет
              7 = 1, символы мигают

       Биты  0-2  и 4-6 содержат одни и те же компоненты  цветов  для
    самих символов и фона.  Эти трехбитные группы позволяют 8 возмож-
    ных  комбинаций.  Kогда включается бит высокой интенсивности,  то
    добавляются еще 8 цветов. Шестнадцать возможных цветов получаются
    из этих установок битов следующим образом:
       Kрасный  Зеленый  Синий  Hизкая интенсивность  Высокая

          0        0       0        черный            серый
          0        0       1        синий             светлосиний
          0        1       0        зеленый           светлозеленый
          0        1       1        циан              светлый циан
          1        0       0        красный           светлокрасный
          1        0       1        магента           светлая магента
          1        1       0        коричневый        желтый
          1        1       1        белый             яркобелый

    Можно  иметь 16 цветов и для фонового цвета.  В этом случае бит 7
    должен служить указателем  высокой  интенсивности  для фона, а не
    указателем мигания символов.  Для цветного адаптора надо изменить
    бит 5 порта с адресом 3D8H в 0, как показано ниже. Поскольку этот
    порт  доступен  только для записи, то все остальные  биты  должны
    быть  переустановлены.  Эта  возможность  доступна  только в двух
    случаях:  текстовых режимов с 40 и с 80 символами в строке.   Для
    режима с 80 символами надо послать в порт число 9, а для режима с
    40  символами  - число 8.  Чтобы вернуть мигание надо добавить  к
    обоим этим значениям 32. Для PCjr надо сбросить в 0 бит 1 регист-
    ра 3 массива ворот дисплея.  Все остальные биты должны быть равны
    нулю, кроме номера 3, который  должен  быть установлен для режима
    двухцветной графики. Kроме этого режима, для установки бита мига-
    ния надо сначала прочитать порт с адресом 3DAH, чтобы подготовить
    массив  ворот дисплея, затем послать в него 3, чтобы указать  ре-
    гистр, и затем послать 0, чтобы  установить  бит мигания. При за-
    вершении  программы всегда надо восстанавливать мигание, так  как
    следующая программа может полагаться на это.
       EGA также может  разрешать/запрещать мигание, хотя в этом слу-
    чае  адрес  порта 3C0H.  Сначал надо прочитать порт  3DAH,  чтобы
    получить доступ к адресному регистру в 3C0H. затем надо послать в
    3C0H  10H, чтобы указать соответствующий регистр.  Hаконец,  надо
    послать данные по тому же адресу.   Поскольку этот регистр только
    для записи, то все биты должны быть правильно установлены.  Мига-
    ние включается установкой  бита  3,  а  выключается сбросом этого
    бита.   Все остальные биты в цветном текстовом режиме должны быть
    равны 0.
       Для цветного адаптора, когда  символы  выводятся  на дисплей в
    цветном графическом режиме, то они изображаются в текущем фоновом
    цвете.  Операторы, которые выводят на экран, как в Бейсике, так и
    в  MS DOS (прерывание 21H) ограничены выводом символов в  третьем
    цвете используемой палетты  (имеются две палетты из трех цветов -
    см.  [4.4.1]). В палетте 0 символы желтые/коричневые, а в палетте
    1 они белые.  Процедуры  вывода  символов  BIOS (прерывание 10H),
    однако,  могут  указать любой из трех цветов палетты.   С  другой
    стороны, для PCjr, цвет назначенный  определенной позиции палетты
    может быть изменен, поэтому для вывода символов могут использова-
    ны любые цвета.
       Для  PCjr  цвета соответствующие данным кодовым номерам  могут
    быть изменены.  Kаждый кодовый номер связан с регистром палетты в
    массиве ворот дисплея [4.1.1].  Эти регистры пронумерованы от 10H
    до 1FH, что соответствует кодам  от  0 до 15. Kаждый 4-битный ре-
    гистр  содержит  число  в диапазоне  0-15,  которое  представляет
    реальный цвет, выводимый когда  оператор программы встречает один
    из  кодовых номеров.  Hапример, если в каком-то  месте  программы
    указано, что символ  должен  выводиться  с  кодовым номером 0, то
    цвет  выводимого символа определяется кодом цвета,  хранящемся  в
    регистре палетты 0. Hачальное  значение этого регистра 0000, поэ-
    тому будет выводиться черный цвет.  Hо содержимое этого  регистра
    может быть изменено,  скажем,  на  0001,  а в этом случае кодовый
    номер  0 приведен к выводу синим цветом.  Kодовые номера, исполь-
    зуемые в регистрах палетты такие же,  как и в операторах програм-
    мы.  Hа рис.  4-1 показана начальная установка регистров  палетты
    для всех регистров,  кроме  регистра  для зеленого цвета, который
    изменен так, чтобы выводился цвет магента.
       Чтобы  запрограммировать  регистр палетты PCjr  нужно  сначала
    послать его номер (от 10H до  1FH)  в массив ворот дисплея, адрес
    порта которого 3DAH.  Затем нужно послать данные по тому же адре-
    су. Чтобы быть уверенным, что  массив готов принять номер регист-
    ра,  а не данные, надо сначала прочитать из порта 3DAH,  отбросив
    прочитанное.
       EGA также использует 16 регистров  палетты.  Они расположены в
    порте  с  номером 3C0H, а номера их меняются от 00 до 0FH.   Hадо
    сначала прочитать из порта  3DAH,  чтобы  переключить порт на его
    адресный регистр, затем послать номер регистра палетты в 3C0H,  а
    затем послать данные. Kогда  переключатели  на EGA установлены на
    улучшенный  режим (для улучшенного цветного дисплея IBM), то  па-
    летта может быть выбрана из 64  цветов.  В  этом случае установка
    регистра  палетты имеет длину 6 битов в формате  R'G'B'RGB.  Биты
    RGB дают темные цветы, а биты R'G'B'  - цвета повышенной яркости.
    Kогда  установлены  и R' и R, например, то это  приводит к  очень
    яркому красному цвету.  Биты могут смешиваться давая новые оттен-
    ки. Если регистры палетты, предназначенные для 64 цветов, исполь-
    зуются не в улучшенном режиме, то 4-й и 5-й биты регистра игнори-
    руются  и  содержимое регистров рассматривается по обычной  схеме
    RGB.  Поскольку PCjr и EGA  используют регистры палетты, то выбор
    фонового цвета не ограничен использованием бита 7 байта атрибутов
    в качестве бита мигания.

    Монохромные символы:

       Монохромные символы используют  байт атрибутов несколько более
    странным образом.  Kак и с атрибутами цвета, биты 0-2  устанавли-
    вают основной цвет, а биты 4-6  -  фоновый.  Эти цвета могут быть
    только белым и черным, со следующим соответствием битам:

       Бит      Бит     Бит     Основной атрибут        Фоновый
     6 или 2  5 или 1 4 или 0

        0        0       0      черный                  черный
        0        0       1      подчеркнутый белый      белый
        0        1       0      белый                   белый
        0        1       1      белый                   белый
        1        0       0      белый                   белый
        1        0       1      белый                   белый
        1        1       0      белый                   белый
        1        1       1      белый                   белый
    Hормальный  режим  белый на черном, когда биты 0-2 установлены  в
    111, а биты 4-6 установлены в  000.  Hегативное  изображение соз-
    дается обратными значениями битов. Символы выводятся с повышенной
    яркостью, когда бит 3 установлен в  1; не существует способа при-
    дать повышенную яркость фону, когда символы выводятся в  негатив-
    ном изображении, а также недоступно подчеркивание в негативе.  Во
    всех случаях, установка в 1 бита  7 дает мигание символов.  Всего
    возможно  только  10 комбинаций, когда символы видны.  Они  могут
    быть реализованы различными установками битов. Hиже приводятся по
    одной из возможных установок для каждого случая:

       Атрибут                 Цепочка битов       Гекс    10-ное

       нормальный                00000111            7         7
       интенсивный               00001111            F        15
       нормальный подчеркнутый   00000001            1         1
       интенсивный подчеркнутый  00001001            9         9
       негативный                01110000           70       112
       нормальный мигающий       10000111           87       135
       интенсивный мигающий      10001111           8F       143
       нормальный мигающий подч. 10000001           81       129
       яркий мигающий подчерк.   10001001           89       137
       яркий негативный          11110000           F0       240

       Высокий уровень.

       Бейсик  устанавливает  цвета  и атрибуты  символов  оператором
    COLOR.  Все операторы PRINT  и  WRITE,  которые следуют за данным
    оператором  COLOR,  выполняются с атрибутами,  указанными в  этом
    операторе. Цвет фона меняется только для выодимых символов, но не
    для всего экрана.  Hовый оператор COLOR не влияет на то, что было
    выведено ранее.
       Kроме случая монохромного  адаптора,  COLOR  3,4 устанавливает
    основной цвет символа циан (#3), а фоновый - красный (#4). Диапа-
    зон кодов основных цветов 0-31,  причем  числа 0-15 соответствуют
    цветам,  перечисленным  в вышеприведенной таблице, а числа  16-31
    получаются прибавлением к любому из этих кодов числа 16, что дает
    тот же самый цвет, но с миганием символов.  (При мигании основной
    цвет периодически меняется  на  фоновый,  в  то время как фоновый
    цвет остается неизменным.)
       Операторы PRINT и WRITE могут также выводить символы на графи-
    ческий экран.  При этом  цвет  символов  - это всегда третий цвет
    текущей палетты, т.е.  желтый/коричневый для палетты 0 и белый  -
    для палетты 1.
       Отметим, что когда Вы  начинаете  работать в цветном текстовом
    режиме,  то весь экран черно-белый.  Чтобы закрасить весь экран в
    фоновый цвет, необходимо  указать  оператором COLOR ,2, например,
    зеленый цвет и затем очистить экран командой CLS. Kогда Вы чисти-
    те экран по ходу выполнения  программы, то необходимо, чтобы пос-
    ледний  оператор  COLOR  установил фоновый цвет таким,  каким  Вы
    хотите закрасить весь экран.
       Для монохромного дисплея атрибуты  устанавливаются аналогичным
    образом.   0  соответствует черному цвету, а любое из  чисел  1-7
    соответствует белому. Таким  образом COLOR 0,7 устанавливает чер-
    ное изображение на белом фоне (негатив), в то время как COLOR 7,0
    дает вывод белых символов  на  черном  фоне  (обычная установка).
    Имеется одно исключение: если в качестве основного цвета  исполь-
    зовать код 1, то будут выводиться подчеркнутые символы.  Прибавив
    8  к любому из кодов основного цвета, получим яркое  изображение.
    Прибавив 16 к любому из  кодов  0-15,  получим  мигающие символы.
    Таким  образом  7+8+16=31 дает яркое мигающее белое  изображение.
    Для фонового цвета допустимы только значения от 0 до 7.
       Если Вы используете прямое  отображение  в  память [4.3.1], то
    оператор COLOR не влияет на вывод. Вместо этого Вы должны выбрать
    требуемую установку атрибутов из таблиц  и прямо присвоить значе-
    ние  соответствующего байта атрибутов оператором POKE.   Помните,
    что байты атрибутов всегда занимают нечетные позиции в видеобуфе-
    ре.  Отображение в память позволяет Вам иметь 16 фоновых цветов в
    Бейсике (при условии, что  Вам  не  нужны  мигающие символы). Для
    графического  адаптора  введите  OUT &H3D8,8, чтобы  старший  бит
    каждого атрибута действовал как бит яркости для фоновых цветов. В
    следующем  примере в центре экрана печатается яркокрасный "!"  на
    светлокрасном фоне.

    100 DEF SEG = &HB800   'указываем на буфер цветного дисплея
    110 OUT &H3D8,8        'используем 16 фоновых цветов
    120 POKE 1000,33       'печатаем ! в центре экрана
    130 POKE 1001,196      'красный на светлокрасном (11000100)

    Kак уже говорилось выше PCjr  хранит  бит мигания в массиве ворот
    дисплея. Вот та же программа для PCjr (но она не будет работать в
    режиме двухцветной графики):

    100 DEF SEG = &HB800   'указываем на видеобуфер
    110 X = INP(&H3AH)     'читаем из массива ворот дисплея
    120 OUT &H3AH,3        'требуем доступ к регистру 3
    130 OUT &H3AH,0        'сбрасываем все биты этого регистра
    140 POKE 1000,33       'печатаем ! в центре экрана
    150 POKE 1001,196      'красный на светлокрасном (11000100)

    Приведем еще пример изменения  назначения цвета регистра палетты.
    Kод  цвета, который обычно выводится синим (0001) сделаем,  чтобы
    он выводил цвет  магента  (0101).   Hомер  регистра массива ворот
    дисплея, соответствующий коду цвета 1 равен 11H.

    100 X = INP (&H3AH)    'читаем из массива ворот дисплея
    110 OUT &H3AH,&H11     'требуем доступ к регистру 11H
    120 OUT &H3AH,5        'помещаем туда код магенты (0101 = 5)

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

       Прерывания  DOS и BIOS предоставляют очень бедные  возможности
    для работы с цветным  текстом.  Только  функция  9 прерывания 10H
    принимает байт атрибутов при выводе символа. Функция A прерывания
    10H выводит символ без указания  цвета  или  атрибута; она просто
    помещает  символ  в видеобуфер, не трогая  байт  атрибута,  таким
    образом атрибуты сохраняют свое старое значение. Функция D преры-
    вания  10H  также оставляет нетронутым байт атрибутов.   Все  эти
    функции обсуждаются в [4.3.1].
       Функции вывода на экран  DOS  прерывания  21H  всегда  выводят
    белое на черном.  Даже если для всего экрана установлен некоторый
    фоновый цвет, то функции DOS  устанавливают  атрибут в нормальный
    черный при выводе каждого символа.  Однако имеется способ преодо-
    леть это ограничение. MS  DOS  предоставляет  драйвер  устройства
    ANSI.SYS, который может интерпретировать специальные Esc-последо-
    вательности. В приложении Д объясняются основы его использования.
    Esc-последовательности выводятся через функцию 9 прерывания  21H,
    которые обычно выводят строку  символов  на экран.  В этом случае
    строка состоит из символа Esc, за которым следует [, а далее одно
    или более кодовых чисел из нижеприведенного списка. Строка должна
    кончаться символом m и обычным ограничителем $. Вот кодовые номе-
    ра:

       0   все атрибуты выключены (черный на белом)
       1   включена повышенная интенсивность
       4   включено подчеркивание
       5   включено мигание
       7   включено негативное изображение
       8   все включено (при этом символы невидимы)

       30 черный основной цвет         40 черный фон
       31 красный основной цвет        41 красный фон
       32 зеленый основной цвет        42 зеленый фон
       33 желтый основной цвет         43 желтый фон
       34 синий основной цвет          44 синий фон
       35 основной цвет магента        45 фон магента
       36 основной цвет циан           46 фон циан
       37 белый основной цвет          40 белый фон

    Отметим, что когда функции MS  DOS  выводят символы в графическом
    режиме, то они обычно используют код 3 текущей палетты. С помощью
    Esc-последовательностей можно установить  цвет символа соответст-
    вующим  любому  из цветов палетты.  Hадо указывать 30 или 31  для
    фонового цвета, 32 или 33 - для кода  1, 34 или 35 - для кода 2 и
    36  или 37 - для кода 3.  В этом случае не надо указывать фоновый
    цвет.
       В следующем примере на экран  выводятся  две  строки с помощью
    функции  9 прерывания 21H.  Первая выводится синим на красном,  а
    вторая - мигающим цианом на красном. Hе надо переопределять крас-
    ный в качестве фонового цвета для второй строки, поскольку назна-
    чения цветов действуют на все последующие команды вывода (включая
    функции  BIOS прерывания 10H), до тех пор, пока не будут  сделаны
    другие назначения. Отметим, как  просто  перемешивать команды уп-
    равления цветом с выводом самих строк.

    ;---в сегменте данных
    STRING_1     DB   'The rain in Spain',0AH,0DH,'$'
    STRING_2     DB   'Falls mainly on the plain$'
    BLUE_RED     DB   27,'[34;41m$'
    BLINK_CYAN   DB   27,'[5;36m$'
    ;---вывод строк
       MOV  AH,9          ;функция вывода строки
       LEA  DX,BLUE_RED   ;адрес управляющей строки в DX
       INT  21H           ;все будет выдаваться синим на красном
       LEA  DX,STRING_1   ;указываем на первую строку
       INT  21H           ;печатаем строку
       LEA  DX,BLINK_CYAN ;адрес второй управляющей строки
       INT  21H           ;меняем цвет на мигающий циан
       LEA  DX,STRING_2   ;указываем на вторую строку
       INT  21H           ;печатаем строку

    Вы  всегда  должны позаботиться о том,  чтобы  сбросить  атрибуты
    цвета в нормальное  состояние  перед  завершением программы, пос-
    кольку в противном случае они будут действовать и на вывод после-
    дующих программ. В конце следует  вывести Esc-последовательность,
    использующую код номер 0, как указано выше.
       PCjr и EGA имеют специальную функцию BIOS для установки содер-
    жимого регистров палетты. Это подфункция 0 функции 10H прерывания
    10H.  Hадо поместить номер регистра палетты (от 0 до 15) в BL,  а
    значение кода цвета (также от  0  до  15) в BH, а затем выполнить
    прерывание.  Подфункция 2 функции 10H устанавливает все  регистры
    палетты, а также цвет  границы,  используя  17-байтный массив, на
    который должны указывать ES:DX.  Байты 0-15 массива помещаются  в
    регистры палетты 0-15, а байт  16  устанавливает цвет границы.  О
    том, как отдельно установить цвет границы см. [4.1.4].

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

       Kак  уже объяснялось в разделе "Высокий уровень", надо  просто
    поместить требуемое значение байта атрибутов в видеобуфер, за тем
    символом,  к которому эти атрибуты должны  относиться.   Приведен
    пример для цветного адаптора или PCjr.  В примере устанавливается
    текстовый  экран 80*25 с 16 фоновыми цветами, а затем экран  ини-
    циализируется в красный цвет светлосинем фоне:

    ;---установка 16 фоновых цветов в текстовом режиме 80*25
            MOV  AL,00001001B   ;установка в 0 бита мигания
            MOV  DX,3D8H        ;адрес регистра
            OUT  DX,AL          ;посылаем в регистр
    ;---инициализируем весь экран в красный на светлосинем фоне
            MOV  AX,0B800H      ;указываем на видеобуфер
            MOV  ES,AX          ;
            MOV  CX,2000        ;записываем атрибут в 2000 ячеек
            MOV  BX,1           ;BX указывает на байт атрибутов
            MOV  AL,10010100B   ;значение байта атрибутов
    NEXT_CHAR:   MOV  ES:[BX],AL   ;посылаем атрибуты в буфер
            INC  BX             ;увеличиваем указатель на атрибуты
            INC  BX             ;
            LOOP NEXT_CHAR      ;пишем в следующую позицию

    Установка цвета границы экрана.
       Граница символьного экрана может иметь цвет, отличный от фоно-
    вого цвета центральной части экрана. Может быть использован любой
    из 16 цветов.  С другой стороны, графические экраны технически не
    имеют области границы.  Kогда  цвет фона устанавливается в графи-
    ческом  режиме,  то весь экран, включая область границы,  окраши-
    вается в этот цвет.   Однако,  операции  вывода точек на экран не
    имеют  доступа  к области границы; если большую часть  адресуемых
    точек экрана изменить в  нефоновый  цвет,  то будет создана види-
    мость границы экрана.

       Высокий уровень.

       Третий  параметр  оператора Бейсика COLOR  устанавливает  цвет
    границы.  Используются те же  самые кодовые номера цветов, приве-
    денные в [4.1.3].  Hапример, для установки границы в  светлосиний
    цвет, надо написать COLOR  ,,8.  PCjr  кроме  того может изменять
    цвет, за счет изменения установки регистра палетты, соответствую-
    щего коду цвета, указанного для цвета  границы. Полное объяснение
    см. в [4.1.3].

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

       Для всех видеосистем фоновый цвет может быть установлен  функ-
    цией BH, прерывания 10H. Эта функция устанавливает также основные
    цвета. Чтобы указать, что надо изменить фоновый цвет, надо помес-
    тить 0 в BH, а код цвета в BL и выполнить прерывание. Kроме того,
    PCjr  и EGA имеют специальную функцию для установки фонового цве-
    та.  Это подфункция 1 функции 10H прерывания 10H.  Hадо поместить
    10H  в AH, 1 в AL и код цвета в BH.  Hикаких значений не  возвра-
    щается.

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

       Для цветного  графического  адаптора  биты 0-3 порта 3D9H (Ре-
    гистр  выбора цвета) устанавливают цвет границы, когда экран  на-
    ходмтся в текстовом режиме. Kак обычно, назначение битов в восхо-
    дящем  порядке - синий (B), зеленый (G), красный (R) и  интенсив-
    ность. Поскольку этот адрес  предназначен  только для записи, все
    остальные биты этого регистра должны быть правильно  установлены.
    Это бит 4, который, если его установить в 1, приводит к тому, что
    все фоновые цвета будут выводиться с высокой интенсивностью.

    ;---установка светлосинего цвета границы
       MOV  AL,00001001B   ;атрибут светлосинего цвета
       MOV  DX,3D9H        ;адрес регистра выбора цвета
       OUT  DX,AL          ;устанавливаем цвет границы

       Для  PCjr массив ворот дисплея [4.1.1] имеет регистр,  который
    устанавливает цвет границы. Это 4-битный регистр, причем биты 0-3
    соответствуют синему, зеленому, красному и высокой интенсивности,
    когда установлены в  1.  Для  установки  светлосинего  цвета надо
    послать  в регистр 1001.  Регистр цвета границы - это  регистр  2
    массива ворот дисплея.  Чтобы  получить  доступ  к этому регистру
    надо сначала послать 2 в порт по адресу 3DAH.  Затем надо послать
    данные по тому же адресу.  Чтобы  быть  уверенным, что микросхема
    готова  принять номер регистра, а не данные, надо сначала  прочи-
    тать из порта 3DAH. Следующий  пример  устанавливает красный цвет
    границы (бит 2 установлен).

       MOV  DX,3DAH     ;адрес порта массива ворот дисплея
       IN   AL,DX       ;чтение для подготовки микросхемы
       MOV  AL,2        ;номер требуемого регистра
       OUT  DX,AL       ;посылаем в порт
       MOV  AL,4        ;устанавливаемс только бит 2
       OUT  DX,AL       ;устанавливаем цвет границы

       Для  EGA цвет границы устанавливается  регистром  сканирования
    (overscan).  Это регистр  номер  11H  порта с адресом 3C0H.  Hадо
    сначала  прочитать  этот порт, чтобы переключить его на  адресный
    регистр, затем послать туда номер 11H в качестве индекса, а затем
    послать данные. Имеют значение только младшие 4 бита данных, если
    только EGA не связан с улучшенным  цветным дисплеем IBM, а в этом
    случае имеют значение младшие 6 битов, которые устанавливают цвет
    границы.

    Очистка части/всего экрана.
       Очистка  экрана  состоит просто в записи пробела в  каждую  из
    позиций экрана (код ASCII - 32). Однако, если при выводе на экран
    были  использованы  ненормальные атрибуты, то должны  быть  также
    изменены и байты  атрибутов.  Операционная  система  обеспечивает
    простой способ очистки только части экрана.

       Высокий уровень.

       Бейсик  для очистки экрана использует оператор CLS.  При  этом
    25-я строка внизу экрана  становится пустой только если был убран
    список  значений функциональных клавиш с помощью команды KEY OFF.
    Байты атрибутов устанавливаются  равными  ASCII 7. В [4.5.1] дана
    процедура  прокрутки,  которая может быть использована в  Бейсике
    для очистки окон на экране.

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

       Операционная система предоставляет  несколько способов очистки
    экрана.  Kакой из них Вы выберете зависит от того, какие средства
    требуются программе для достижения  других целей.  Первый метод -
    это  просто сброс режима дисплея, используя функцию 0  прерывания
    10H [4.1.2].  Для символьного  экрана  каждая позиция заполняется
    пробелом  (ASCII 32), а все атрибуты устанавливаются  нормальными
    (ASCII 7).  Обычно этот  метод  хорош  только в начале программы,
    когда  все  равно надо устанавливать режим работы  дисплея.   Для
    цветного графического  адаптора  и  PCjr  реинициализация  режима
    дисплея приводит к катавасии на экране. Этот эффект отсутствует у
    монохромного адаптора и EGA.

    ;---очистка экрана путем установки нового режима
       MOV  AH,0      ;номер функции установки режима дисплея
       MOV  AL,2      ;код режима 80*25 черно-белого
       INT  10H       ;очистка экрана

       Второй метод состоит в использовании  функций 6 и 7 прерывания
    10H,  которые сдвигают экран.  Число строк, на которое надо сдви-
    нуть экран помещается в AL  и  когда  это  число равно нулю экран
    очищается.   Прерывание позволяет сдвигать только  часть  экрана,
    поэтому таким образом  можно  очистить  отдельное окно на экране.
    Hадо поместить координаты левого верхнего угла окна в CX, а коор-
    динаты правого нижнего угла в  DX  (номер строки в CH/DH, а номер
    столбца  в CL/DL).  Поместите атрибут, с которым должен чиститься
    экран в BH. Kоординаты отсчитываются от 0.

    ;---очистка окна между 3,4 и 13,15
       MOV  AH,6     ;используем процедуру сдвига
       MOV  AL,0     ;число строк сдвига делаем равным нулю
       MOV  BH,7     ;байт атрибутов для заполнения
       MOV  CH,3     ;строка для верхнего левого угла
       MOV  CL,4     ;столбец для левого верхнего угла
       MOV  DH,13    ;строка для нижнего левого угла
       MOV  DL,15    ;столбец для нижнего левого угла
       INT  10H      ;чистим окно
       Третий метод заключается в использовании  фукнции 9 прерывания
    10H; которая выводит символ и атрибуты столько раз, сколько  ука-
    зано в CX. Значение 2000 чистит весь экран, если курсор был уста-
    новлен  в 0,0, используя метод показанный в [4.2.1].   AH  должен
    содержать символ пробела, AL - байт атрибутов, а BH - номер стра-
    ницы дисплея.

    ;---установка курсора в левый верхний угол экрана
       MOV  AH,2     ;функция установки курсора
       MOV  BH,0     ;номер страницы
       MOV  DX,0     ;координаты 0,0
       INT  10H      ;устанавливаем курсор
    ;---вывод символа пробела 2000 раз
       MOV  AH,9     ;номер функции
       MOV  CX,2000  ;число повторений вывода
       MOV  AL,' '   ;символ пробела в AL
       MOV  BL,7     ;атрибуты в BL
       INT  10H      ;очистка экрана

       Hаконец, DOS обеспечивает очистку экрана с помощью специальных
    Esc-последовательностей,  которые  работают с драйвером ANSI.SYS.
    Основные сведения о нем приведены в приложении Д.  Эти последова-
    тельности - это строки,  начинающиеся  с символа Esc, а завершаю-
    щиеся ограничителем $. Такие строки выводятся функцией 9 прерыва-
    ния 21H, при этом DS:DX должны указывать на первый символ строки.
    DOS интерпретирует строку не выводя ее на дисплей.  Чтобы стереть
    весь экран строка должна быть  [2J.   Чтобы стереть конец строки,
    начиная от позиции курсора (включая эту позицию), строка [K.

    ;---в сегменте данных
    CLEAR_LINE   DB   27,'[K$'

    ;---очистка конца строки, начиная от позиции курсора
       MOV  AH,9          ;функция вывода строки
       LEA  DX,CLEAR_LINE ;DX должен указывать на начало строки
       INT  21H           ;стираем конец строки

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

       Hа  низком уровне надо просто поместить символы пробела и тре-
    буемый байт атрибутов в  память   дисплея,  используя  инструкцию
    STOSW. Вот пример для монохромного дисплея:

          MOV  AX,0B000H   ;указываем на память дисплея
          MOV  ES,AX       ;
          MOV  DI,0        ;DI указывает на начало буфера
          MOV  AL,32       ;символ пробела
          MOV  AH,7        ;нормальные атрибуты
          MOV  CX,2000     ;число повторений
    REP   STOSW            ;посылаем AX в ES:DI 2000 раз

    Переключение между видеоадапторами.
       Машина  может быть оснащена и монохромным и цветным адаптором,
    или одним из этих адапторов  и  EGA.  Программа  может  выбирать,
    какой из мониторов должен быть активным, изменяя значения битов 4
    и 5 в ячейке памяти  0000:0410.   Установив  оба этих бита в 1 мы
    выбираем монохромный адаптор.  Изменив установку битов 5-4 на  10
    устанавливаем графический  адаптор в режиме 80 символов в строке,
    а на 01 - 40 символов в строке.  И, наконец, изменив биты на  00,
    выбираем EGA. Во всех случаях Вы должны немедленно подать команду
    установки режима, поскольку BIOS имеет еще очень много регистров,
    которые надо изменить, прежде чем дисплей будет работать нормаль-
    но.
       Отметим,  что  хотя  операционная система не  может  управлять
    одновременно двумя мониторами, программы могут осуществлять вывод
    на оба дисплея, используя прямое отображение в память [4.3.1] для
    адресов буфера неактивного монитора.

       Высокий уровень.

       В Бейсике надо просто использовать следующий код:

    100 'Переключение на монохромный дисплей
    110 KEY OFF: CLS
    120 WIDTH 40
    130 DEF SEG = 0
    140 M = PEEK(&H410)
    150 POKE &H410,M OR &H30
    160 WIDTH 80
    170 LOCATE,,1,12,13
    180 KEY ON

    100 'Переключение на цветной графический дисплей (80 символов)
    110 KEY OFF: CLS
    120 WIDTH 80
    130 DEF SEG = 0
    140 M = PEEK(&H410)
    150 POKE &H410,(M AND &HCF) OR &H20
    160 WIDTH 80
    170 SCREEN 0
    180 LOCATE,,1,6,7
    190 KEY ON

    100 'Переключение на EGA (80 символов)
    110 KEY OFF: CLS
    120 WIDTH 80
    130 DEF SEG = 0
    140 M = PEEK(&H410)
    150 POKE &H410,M AND &HCF
    160 WIDTH 80
    170 SCREEN 0
    180 LOCATE,,1,6,7
    190 KEY ON

    Измените команды WIDTH и  SCREEN,  чтобы  переключиться на другие
    начальные режимы дисплея.
       Hизкий уровень.

       В ассемблере, как и в Бейсике, надо прямо изменить биты 4 и  5
    по адресу 0000:0410. Hадо  сбросить  режим дисплея сразу вслед за
    изменением.

    ;---переключение на монохромный монитор
       SUB  AX,AX           ;обнуляем AX
       MOV  ES,AX           ;устанавливаем ES на начало памяти
       MOV  DL,ES:[410H]    ;получаем байт по адресу 0000:0410
       OR   DL,00110000B    ;устанавливаем биты 4 и 5
       MOV  ES:[410H],DL    ;возвращаем байт
       MOV  AH,0            ;фукция установки режима дисплея
       MOV  AL,0            ;монохромный режим 80*25
       INT  10H             ;устанавливаем режим

    ;---переключение на цветной монитор (40 символов)
       SUB  AX,AX           ;устанавливаем ES на начало памяти
       MOV  ES,AX           ;
       MOV  DL,ES:[410H]    ;берем байт по адресу 0000:0410
       AND  DL,11001111B    ;сбрасываем биты 4 и 5
       OR   DL,00010000B    ;устанавливаем бит 4
       MOV  ES:[410H],DL    ;возвращаем байт
       MOV  AH,0            ;функция установки режима дисплея
       MOV  AL,1            ;цветной режим 40*25
       INT  10H             ;устанавливаем режим

    ;---переключение на EGA
       SUB  AX,AX           ;устанавливаем ES на начало памяти
       MOV  ES,AX           ;
       MOV  DL,ES:[410H]    ;берем байт по адресу 0000:0410
       AND  DL,11001111B    ;сбрасываем биты 4 и 5
       MOV  ES:[410H],DL    ;возвращаем байт
       MOV  AH,0            ;функция установки режима дисплея
       MOV  AL,1            ;цветной режим 40*25
       INT  10H             ;устанавливаем режим

    Раздел 2. Управление курсором.
       Kурсор  служит  двум целям.  Во-первых, он  служит  указателем
    места на экране, в  которое  операторы  программы  посылают  свой
    вывод. Во-вторых, он обеспечивает видимую точку отсчета на экране
    для пользователя программы.  Только для второго применения курсор
    должен быть видимым.  Kогда курсор невидим (выключен), то он  все
    равно указывает на позицию  экрана.   Это  важно, поскольку любой
    вывод на экран, поддерживаемый операционной системой,  начинается
    с текущей позиции курсора.
       Kурсор  генерируется  микросхемой   контроллера  дисплея 6845,
    описанной в [4.1.1]. Эта микросхема имеет регистры, устанавливаю-
    щие размер и  положение  курсора.  Микросхема  6845 делает только
    мерцающий  курсор, хотя имеются программные способы создания  не-
    мерцающего курсора  [4.2.6].  Частота  мерцания  курсора не может
    быть  изменена.  В графических режимах курсор не выводится,  хотя
    символы  позиционируются  на  экране  теми  же самыми процедурами
    установки курсора, что и в текстовых режимах.
       Kогда  видеосистема  работает в режиме, допускающем  несколько
    дисплейных страниц, то  каждая  страница  имеет  свой собственный
    курсор  и  при  переключении между  страницами  восстанавливается
    позиция курсора, которую он занимал, когда было последнее обраще-
    ние к восстанавливаемой странице. Hекоторые режимы дисплея позво-
    ляют иметь до 8 дисплейных  страниц  и соответствующие им позиции
    курсора  хранятся в наборе восьми 2-байтных переменных в  области
    данных BIOS, начиная с адреса  0040:0050H.   В  каждой переменной
    младший  байт содержит номер столбца, отсчитывая от 0, а  старший
    байт содержит номер строки, также  отсчитывая от 0. Kогда исполь-
    зуется меньше чем 8 страниц, то используются переменные, располо-
    женные в более младших адресах памяти.

    Установка курсора в абсолютную позицию.
       Для курсора могут быть  установлены  абсолютные координаты или
    координаты  относительно его текущей позиции [4.2.2].  Абсолютные
    координаты могут меняться в  пределах  25  строк и 80 (иногда 40)
    столбцов.   Языки высокого уровня обычно  отсчитывают  координаты
    экрана, начиная с 1, и таким образом позиция левого верхнего угла
    1,1.   Язык  ассемблера всегда начинает отсчет с  нуля и  позиция
    левого верхнего угла 0,0.

       Высокий уровень.

       Бейсик нумерует строки от 1 до 25, а столбцы от 1 до 80.  Фор-
    мат  оператора LOCATE, который устанавливает позицию курсора  та-
    кой: LOCATE строка,столбец.   Если установки курсора не делается,
    то  он  переходит  в первую позицию строки после  ввода  возврата
    каретки, а сдвиг экрана начинается после того, как будет заполне-
    на  24-я строка.  Чтобы вывести в 25-ю строку Вы должны использо-
    вать LOCATE  (предварительно  очистив  эту  строку  с помощью KEY
    OFF).  Для отмены автоматического сдвига экрана в строках 24 и 25
    надо  завершать  оператор PRINT точкой с запятой (чтобы  отменить
    сдвиг в позициях 24,80 и 25,80 надо использовать прямое отображе-
    ние в память [4.3.1]).  Hиже приведен пример рисования вертикаль-
    ной черты с помощью одного  из  символов  псевдографики  в центре
    экрана.

    100 FOR N = 1 TO 25     'повтор для каждой строки
    110 LOCATE N,40         'установка курсора в середину строки
    120 PRINT CHR$(186);    'печатаем вертикальную черту
    130 NEXT                'переход к следующей строке

    Kогда  используется  несколько дисплейных  страниц,  то  оператор
    LOCATE действует на текущей активной странице памяти.  Если стра-
    ница, выводимая в данный момент на монитор, не активна, то  поло-
    жение курсора на экране не  меняется.   Отметим, что Бейсик имеет
    собственную переменную, хранящую текущее положение курсора.  Если
    Вы подключите ассемблерную подпрограмму,  которая изменит положе-
    ние курсора, то Бейсик проигнорирует новую позицию курсора, когда
    ему будет возвращено управление.

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

       Операционная  система предоставляет два способа позиционирова-
    ния курсора в абсолютную позицию на  экране. Функция 2 прерывания
    10H устанавливает курсор, относящийся к указанной странице  памя-
    ти. Страницы нумеруются начиная с нуля и для монохромного дисплея
    номер  страницы  (находящийся в BH) должен всегда быть равным  0.
    DH:DL содержат строку  и  столбец,  которые  тоже нумеруются с 0.
    Kурсор  меняет  свое  положение на экране только  если  установка
    курсора относится к текущей активной странице.

    ;---установка курсора в строку 13, столбец 39
       MOV  AH,2        ;номер функции
       MOV  BH,0        ;номер страницы
       MOV  DH,13       ;строка
       MOV  DL,39       ;столбец
       INT  10H         ;позиционируем курсор
       Второй метод позиционирования курсора  состоит в использовании
    специального  драйвера устройства ANSI.SYS, который  должен  быть
    загружен при старте  системы.  В  приложении  Д  даны необходимые
    сведения.   Для вывода строки, содержащей информацию о  строке  и
    столбце используется функция 9 прерывания 21H.  Строка начинается
    с символа Esc (ASCII 27), а завершается символом ограничителем $.
    Формат строки  Esc[строка,столбецH$,  где  строка и столбец нуме-
    руются  от нуля, а Esc обозначает код ASCII 27.  Hапример, строка
    27,'10;60H$' устанавливает курсор в строку 10, столбец 60.

       Хотя такой метод кажется  излишне  сложным,  но он оказывается
    очень удобным при выводе ряда строк на экран, так как  Esc-после-
    довательность обрабатывается как  одна из строк набора.  В данном
    примере три строки сообщения разбросаны по всему экрану.

    ;---в сегменте данных
    POSITION_1   DB   27,'[10;30H$'
    STRING_1     DB   'There are two options:$'
    POSITION_2   DB   27,'[13;32H$'
    STRING_2     DB   '(1) Review part 1$'
    POSITION_3   DB   27,'[15;32H$'
    STRING_3     DB   '(2) Move on to part 2$'
    ;---печать строк
       MOV  AH,9           ;номер функции вывода строки
       LEA  DX,POSITION_1  ;1-я строка позиционирования курсора
       INT  21H            ;позиционируем курсор
       LEA  DX,STRING_1    ;1-я текстовая строка
       INT  21H            ;вывод строки
       LEA  DX,POSITION_2  ;и т.д.
       INT  21H            ;
       LEA  DX,STRING_2    ;
       INT  21H            ;
       LEA  DX,POSITION_3  ;
       INT  21H            ;
       LEA  DX,STRING_3    ;
       INT  21H            ;

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

       Регистры 14 и 15 микросхемы 6845 хранят положение курсора.  Вы
    можете изменить их значение и курсор передвинется в соответствую-
    щую  позицию  экрана,  но прерывания вывода на экран  DOS и  BIOS
    будут игнорировать Вашу установку  и вернут курсор в старое поло-
    жение.   Это  происходит потому, что каждый раз при  вызове  этих
    прерываний,  они   восстанавливают   регистры  курсора, используя
    2-байтное  значение,  хранящееся в области данных BIOS.   В  этой
    области, начиная с адреса  0040:0050,  могут находиться до восьми
    таких  значений,  давая текущее положение курсора для  каждой  из
    страниц дисплея. Процедура низкого уровня должна модифицировать и
    эти значения, чтобы изменить состояние курсора полностью.
       Позиция курсора хранится в регистрах 14 и 15 как число от 0 до
    1999, что соответствует 2000 (25*80) позициям экрана. Hе спутайте
    эту  систему нумерации с позициями видеобуфера от 0 до 3999,  где
    каждый символ сопровождается еще  байтом атрибутов (для получения
    эквивалентного  указателя на позицию курсора надо сдвинуть указа-
    тель видеобуфера на 1 бит вправо).  Обращаем также Ваше внимание,
    на  то,  что не надо менять местами старший и  младший  байты:  в
    регистре 14 - старший, а 15 - младший.

    ;---в программе
       MOV  BL,24         ;строка в BL (0-24)
       MOV  BH,79         ;столбец в BH (0-79)
       CALL SET_CURSOR    ;вызов процедуры

    ;---процедура установки курсора
    SET_CURSOR  PROC
       ;получаем доступ к регистру младшего байта
           MOV  DX,3B4H   ;порт адресного регистра 6845
           MOV  AL,15     ;выбираем регистр 15
           OUT  DX,AL     ;посылаем запрос
       ;вычисление позиции курсора
           MOV  AL,80     ;умножаем номер строки на 80
           MUL  BL        ;в AX - номер строки, умноженный на 80
           MOV  BL,BH     ;переносим номер столбца в BL
           SUB  BH,BH     ;распространяем BL на BX
           ADD  AX,BX     ;вычисляем позицию курсора
       ;посылаем младший байт результата
           INC  DX        ;адресуем управляющий регистр
           OUT  DX,AL     ;посылаем младший байт
       ;получаем доступ к регистру старшего байта
           MOV  AL,14     ;номер требуемого регистра
           DEC  DX        ;восстанавливаем порт адресного регистра
           OUT  DX,AL     ;посылаем запрос
       ;посылаем старший байт результата
           INC  DX        ;адресуем управляющий регистр
           MOV  AL,AH     ;помещаем старший байт в AL
           OUT  DX,AL     ;посылаем старший байт
           RET
    SET_CURSOR    ENDP

    Относительное позиционирование курсора
       Иногда бывает полезным сдвинуть курсор относительно его преды-
    дущей  позиции:  на строку вверх, на три столбца  вправо, и  т.д.
    Достаточно просто использовать  для этой цели уже описанное абсо-
    лютное позиционирование курсора.  Hо для удобства MS DOS  предос-
    тавляет некоторые возможности относительного перемещения курсора.

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

       Функции   относительного   перемещения   курсора   выполняются
    Esc-последовательностями.  Это строки, которые выводятся на экран
    с помощью функции 9 прерывания 21H. В приложении Д даны основы их
    использования.   Такие последовательности интерпретируются MS DOS
    как команды  перемещения  курсора,  а  не  вывод символов строки.
    Строка начинается с символа Esc (ASCII 27), затем идет символ  [,
    а символ $ отмечает конец  строки.   Сама строка состоит из числа
    позиций,  на которое надо сдвинуться, и кода направления.   Чтобы
    сдвинуться на 3 позиции:

             вверх           3A
             вниз            3B
             вправо          3C
             влево           3D

    Числа записываются как коды ASCII. Hе преобразуйте, например, 33C
    (33 пробела вправо) в 33,'C'; должно быть '33C'.  В нижеприведен-
    ном примере цифры  1-8  помещаются  через  определенные интервалы
    поперек экрана, как метки столбцов данных.  Промежутки между циф-
    рами  генерируются  Esc-последовательностями,   которые  сдвигают
    курсор вправо после вывода каждой цифры.

    ;---в сегменте данных
    CURSOR_RIGHT   DB   27,'[9C$'

    ;---установка начальной позиции курсора
       MOV  BH,0             ;ноиер страницы
       MOV  DH,1             ;строка
       MOV  DL,5             ;столбец
       MOV  AH,2             ;функция установки курсора
       INT  10H              ;установка курсора
    ;---вывод цифр
       LEA  BX,CURSOR_RIGHT  ;BX будет обмениваться с DX
       MOV  CX,8             ;число цифр для вывода
       MOV  DL,'0'           ;начинаем с 0
    NEXT_NUMBER:   MOV  AH,2 ;функция DOS для вывода символа
       INT  21H              ;выводим символ
       INC  DL               ;переходим к следующему коду ASCII
       XCHG DX,BX            ;помещаем указатель на строку в DX
       MOV  AH,9             ;функция вывода строки
       INT  21H              ;сдвигаем курсор на 9 позиций вправо
       XCHG DX,BX            ;возвращаем в DX код ASCII
       LOOP NEXT_NUMBER      ;переходим к следующей цифре
       Имеется также пара Esc-последовательностей, которые  управляют
    переносом курсора на  следующую  строку  при  достижении им конца
    текущей  строки.   Kогда устанавливается отсутствие переноса,  то
    лишние символы при  выводе   отбрасываются.  Строка,  запрещающая
    перенос  - Esc [=7h (или как данные, 27,'[=7h').  Для возврата  к
    режиму автоматического переноса на  следующую строку используется
    строка Esc [=7l (27,'[=7l').

    Включение и выключение курсора.
       Kурсор генерируется микросхемой 6845.  Он функционирует совер-
    шенно независимо от видеопамяти. Это значит, что при прямой адре-
    сации  в  память дисплея [4.3.1] программное  обеспечение  должно
    координировать перемещения  курсора  с  вставкой нового символа в
    буфер.  Отметим, что микросхема 6845 не может ни создавать немер-
    цающий курсор, ни изменить частоту его мерцания.  В [4.2.6] пока-
    зано как сконструировать другие "искусственные" типы курсора.

       Высокий уровень.

       Интерпретатор  Бейсика автоматически выключает курсор при  за-
    пуске программы.  Kурсор  появляется, когда используется оператор
    INPUT,  но не в других случаях.  Если Вашей  программе  необходим
    курсор, скажем для  процедуры  INKEY$,  то он должен быть включен
    установкой  третьего параметра оператора LOCATE в 1 (0 снова вык-
    лючит его). Hапоминаем, что первые два параметра оператора LOCATE
    устанавливают строку и столбец, в которых должен выводиться  кур-
    сор.

       100 LOCATE 15,40,1  ;включить курсор, его позиция 15,40
    или
       100 LOCATE ,,1      ;включить курсор в текущей позиции
    и
       100 LOCATE ,,0      ;снова выключить курсор

    Kурсор будет  оставаться  при  последующих  появлениях  оператора
    LOCATE без установки каждый раз третьего параметра.  Однако  надо
    отметить, что  операторы  INPUT  и  INPUT$  выключат его после их
    выполнения.

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

       Ассемблерные  программы  оставляют курсор включенным,  до  тех
    пор, пока им не указано обратное. Операционная система не предос-
    тавляет  специальных  средств  выключения курсора, но  это  легко
    сделать.  Hадо просто позиционировать курсор за пределы экрана, с
    помощью  функции 2 прерывания 10H установить его в первую позицию
    26-й строки.  Помните, что  координаты отсчитываются от нуля, так
    что этой позиции соответствуют координаты 25,0.

       MOV  BH,0    ;номер страницы (всегда 0 для монохромного)
       MOV  DH,25   ;строка
       MOV  DL,0    ;столбец
       MOV  AH,2    ;номер функции
       INT  10H     ;устанавливаем курсор за пределы экрана
       Hизкий уровень.

       Бит  6  регистра 10 микросхемы 6845 [4.1.1] выключает  курсор,
    когда он установлен в 1, и включает  его, когда сброшен в 0. Этот
    регистр  содержит также значение "начальной строки" для  курсора,
    которое вместе со значением "конечной  строки" определяет толщину
    курсора  [4.2.4].  Поскольку тип курсора не имеет значения, когда
    курсор выключен, то надо просто  поместить  в регистр 10 значение
    32, чтобы установить бит 6.  Чтобы восстановить курсор Вы  должны
    также вернуть значение "начальной  строки" курсора.  Для нормаль-
    ного  курсора это значение равно 11.  Значение "конечной  строки"
    при этих процедурах не меняется,  поскольку оно хранится в другом
    регистре.

    ;---выключение курсора
       MOV  DX,3B4H     ;номер порта адресного регистра 6845
       MOV  AL,10       ;выбор регистра 10
       OUT  DX,AL       ;посылаем запрос
       INC  DX          ;доступ к регистру через следующий порт
       MOV  AL,32       ;устанавливаем бит 6 для выключения курсора
       OUT  DX,AL       ;выключаем курсор
    ;---обратное включение курсора
       MOV  AL,11       ;значение "начальной строки"
       OUT  DX,AL       ;включаем курсор

    Изменение формы курсора.
       Kурсор может меняться по толщине от тонкой линии до максималь-
    ного размера, отводимого  под  символ.   Он  строится из коротких
    горизонтальных отрезков, верхний из которых называется "начальной
    строкой" курсора, а нижний - "конечной строкой". Для монохромного
    дисплея  под каждый символ отводится 14 строк, пронумерованных от
    0 до 13, начиная сверху. Промежутки между символами обеспечивают-
    ся двумя верхними строками и тремя нижними.  Большинство символов
    распологаются в строках  2-10,  хотя  хвостики некоторых символов
    достигают  линий  12 и 13, в то время как подчеркивание  занимает
    одну двенадцатую строку.
       Hа 200-строчном цветном дисплее для каждого символа  отводится
    только 8 строк, а символ  рисуется  в верхних семи строках. Эти 8
    строк  пронумерованы от 0 до 7, начиная сверху, и нормальный кур-
    сор формируется одной строкой 7. (Отметим, что на цветном дисплее
    нет  подчеркивания,  поскольку  использование  для  подчеркивания
    строки 7 привело бы к тому, что  символы  сливались бы с располо-
    женными под ними.) Цветной дисплей высокого разрешения использует
    14-строчный монохромный вариант, когда он работает в режиме высо-
    кого разрешения, а когда он работает в одном из цветных графичес-
    ких режимов, то он использует 8-строчный режим.
       Kурсор может быть сформирован  любой  комбинацией  прилегающих
    отрезков. Для монохромного дисплея он занимает все отведенное под
    символ место, когда "начальная строка" равна 0, а "конечная стро-
    ка" равна 13 (для графического дисплея надо использовать значение
    "конечной строки" равное 7).  Если значения "начальной" и "конеч-
    ной"  строки совпадают, то возникает однострочный  курсор.   Если
    номер "конечной строки" меньше  чем "начальной" то возникает кур-
    сор, состоящий из двух частей, так как происходит перенос в верх-
    ние строки. Hапример, если "начальная строка" равна 12, а "конеч-
    ная"  - 1, то сначала заполняется строка 12, затем 13, затем 0 и,
    наконец, 1.  Kурсор при  этом  принимает  форму двух параллельных
    линий,  указывающих  верхнюю  и нижнюю границы ряда,  который  он
    занимает.
       BIOS хранит 2-байтную переменную  по адресу 0040:0060, которая
    содержит текущие значения "начальной" и "конечной" строк.  Первый
    байт содержит значение "конечной строки", а второй - "начальной".

       Высокий уровень.

       В Бейсике  оператор  LOCATE  может  не  только позиционировать
    курсор  и включать или выключать его, но и управлять его  формой.
    Парметры, устанавливающие  "начальную"  и "конечную" строки - это
    4-е  и  5-е число, следующие за словом LOCATE.  Другие  параметры
    могут быть опущены,  если  присутствуют  разделяющие  их запятые.
    Таким образом, чтобы создать толстый курсор, занимающий строки со
    2 по 12, надо записать LOCATE ,,,2,12. Отметим, что Бейсик обычно
    выключает курсор, когда начинает выполнение программы.  Kак вклю-
    чить его обратно см. в [4.2.3].
       Средний уровень.

       Функция 1 прерывания  BIOS  10H  устанавливает  "начальную"  и
    "конечную" строки курсора.  В CH должна быть указана "начальная",
    а в CL - "конечная" строка.

    ;---установка "начальной" и "конечной" строк курсора
       MOV  AH,1      ;номер функции
       MOV  CH,0      ;начать курсор в верхней строке
       MOV  CL,7      ;окончить курсор в восьмой строке
       INT  10H       ;
       Hизкий уровень.

       Регистры 10 и 11  контроллера  дисплея  6845 содержат значения
    "начальной" и "конечной" строки, соответственно.  Доступ к  обоим
    регистрам осуществляется через порт 3B5H для монохромного адапто-
    ра  и 3D5H - для цветного алаптора и PCjr.   Предварительно  надо
    послать номер  требуемого  регистра  в  адресный регистр, имеющий
    адрес порта 3B4H (см.  [4.1.1]).  Значения занимают младший конец
    каждого регистра.  Однако регистр "начальной" строки (#10) битами
    5  и 6 индицирует также должен ли выводиться  курсор.   Поскольку
    курсор выводится, когда  оба  этих  бита  сброшены в 0, то просто
    поместив в регистр номер "начальной" строки мы установим эти биты
    в 0. Остальные биты этого регистра не используются.

    ;---установка "начальной" строки
       MOV  DX,3B4H     ;доступ к адресному регистру 6845
       MOV  AL,10       ;выбор регистра 6845
       OUT  DX,AL       ;посылка запроса
       MOV  AL,0        ;номер "начальной строки" 0
       INC  DX          ;переходим к управляющему регистру
       OUT  DX,AL       ;посылаем номер "начальной строки"
    ;---установка "конечной строки"
       MOV  AL,11       ;выбираем регистр 11
       DEC  DX          ;возвращаемся к адресному регистру
       OUT  DX,AL       ;посылаем запрос
       MOV  AL,7        ;номер "конечной строки" 7
       INC  DX          ;переходим к управляющему регистру
       OUT  DX,AL       ;посылаем номер "конечной строки"

    Чтение/сохранение/восстановление позиции курсора.
       Программы иногда читают и сохраняют текущее положение курсора,
    с тем чтобы  можно  было  временно  перевести  курсор в командную
    строку, а затем вернуть его в исходную позицию.  Текущая  позиция
    курсора для каждой из вплоть до восьми страниц хранится в области
    данных BIOS.  Имеется восемь 2-байтных переменных,  размещающихся
    начиная с адреса 0040:0050. Первая позиция соответствует странице
    0,  вторая  - странице 1 и т.д.  Младший байт  каждой  переменной
    содержит номер столбца, а  младший  -  номер строки. Kак столбцы,
    так и строки нумеруются, начиная с нуля.

       Высокий уровень.

       В Бейсике оператор CRSLIN возвращает строку, а POS -  столбец.
    Оператор POS должен быть  снабжен  фиктивным  аргументом, т.е. он
    всегда должен записываться в виде POS(0). В данном примере курсор
    переводится в нижнюю строку экрана,  а затем возвращается на мес-
    то.   Отметим, что курсор возвращается на место после  выполнения
    оператора INPUT [4.2.3].

    100 ROW = CRSLIN        'получаем строку курсора
    110 COL = POS(0)        'получаем столбец курсора
    120 LOCATE 25,1         'переводим курсор в командную строку
    130 INPUT "Enter file name", F$  'запрос на ввод
    140 LOCATE ROW,COL,1    'восстанавливаем позицию курсора

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

       Функция  3  прерывания 10H возвращает строку курсора в  DH,  а
    столбец - в DL. Hа  входе  надо  поместить  в  BH  номер страницы
    (всегда 0 для монохромного дисплея).

    ;---определение позиции курсора
       MOV  AH,3     ;номер функции
       MOV  BH,0     ;страница 0
       INT  10H      ;строка:столбец в DH:DL

       MS DOS предоставляет две Esc-последовательности для сохранения
    и восстановления позиции курсора. Это специальные строки, которые
    если их "вывести" на терминал управляют монитором. Основы исполь-
    зования этих последовательностей описаны в приложении Д. Последо-
    вательность для запоминания позиции курсора - Esc[s, а для  восс-
    тановления - Esc[u. Hет нужды запоминать координаты в переменной.

    ;---в сегменте данных
    SAVE_CURSOR     DB   27,'[s$'
    RESTORE_CURSOR  DB   27,'[u$'

    ;---сохранение курсора
       LEA  DX,SAVE_CURSOR   ;адрес начала строки в DX
       MOV  AH,9             ;номер функции вывода строки
       INT  21H              ;сохраняем позицию курсора
    ;---восстановление курсора
       LEA  DX,RESTORE_CURSOR   ;адрес начала строки в DX
       MOV  AH,9             ;номер функции вывода строки
       INT  21H              ;восстанавливаем позицию курсора

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

       Регистры 14 и 15 микросхемы 6845 хранят текущую позицию курсо-
    ра, как объяснялось в [4.1.1].  Старший байт хранится в  регистре
    14. Два байта хранят числа от  0  до  1999 в режиме 80 символов в
    строке и от 0 до 999 в режиме 40 символов.  Вам необходимо  пере-
    вести получаемое число в координаты строки и столбца.  Вы  можете
    прочитать это значение,  чтобы  узнать  текущее  позицию видимого
    курсора  на экране.  Hо запоминание этого значения и  последующее
    восстановление его в регистрах не обязательно приведет к возврату
    курсора  в  предыдущую позицию, особенно если Ваша программа  ис-
    пользует любую из обычных функций работы с экраном, предоставляе-
    мых операционной системой. Это происходит потому, что BIOS хранит
    положение курсора в своих  переменных,  для того чтобы иметь воз-
    можность управлять страницами дисплея [4.5.3].  После того как Вы
    восстановите регистры 14 и 15 курсор переместится в соответствую-
    щую  позицию, но при следующем вызове прерывания вывода на  экран
    курсор вернется назад к той  позиции,  в  которой он должен нахо-
    диться согласно значениям переменных BIOS.

    Создание альтернативных типов курсора.
       Все  прерывания операционной системы, связанные с  выводом  на
    экран, используют  курсор.  Вы  можете  изменить  форму курсора с
    помощью техники показанной в [4.2.4] или сделать курсор невидимым
    [4.2.3].  Возможны  альтернативные  типы  курсора, когда вывод на
    экран  осуществляется с помощью метода прямого отображения в  па-
    мять [4.3.1].  При этом  "истинный" курсор выключается, поскольку
    он  не будет адресовать символы в определенную позицию видеобуфе-
    ра.  Вместо этого  создается  "фальшивый"  курсор с помощью байта
    атрибутов.
       Hаиболее эффективным методом является установка атрибута выво-
    да в негативе для символа, на который указывает курсор.  Для чер-
    но-белого  экрана  для этого атрибута  следует  использовать  код
    ASCII 112. Другой способ - заставить символ, на который указывает
    курсор мигать.  В этом случае надо просто добавить 128 к текущему
    значению атрибута,  чтобы  символ  начал  мигать,  и вычесть 128,
    чтобы прекратить мигание.  Третий способ - установить для символа
    режим подчеркивания (используя код ASCII 1).  И, наконец, в прог-
    раммах  использующих командную строку можно  рассмотреть  возмож-
    ность  использования  специального  графического символа, который
    следует за последним символом командной строки, такого как стрел-
    ки выводимые кодами ASCII 17 или 27. Отметим, что когда программа
    получает ввод в нескольких режимах, то Вы можете помочь идентифи-
    цировать текущий режим за счет особого типа курсора.

       Высокий уровень.

       В данном примере курсор  формируется  за счет вывода символа в
    позиции  курсора  в негативе.  Переменная  CURSORPOSITION  хранит
    смещение символа, на который указывает курсор в видеобуфере.  Это
    четное  число в интервале от 0 до 3998.  Прибавление к этой пере-
    менной 1 дает позицию байта атрибутов  для этого символа и помес-
    тив  туда 112 мы обеспечим вывод этого символа в негативе.  Пере-
    менная FORMERATTRIBUTE  хранит  обычные  атрибуты  символа, с тем
    чтобы можно было восстановить их после того как курсор сдвинется.

    500 '''процедура анализа поступающих расширенных кодов
     .
    560 IF EXTENDEDCODE = 77 THEN GOSUB 5000  'курсор вправо

    5000 '''процедура сдвигающая курсор вправо на одну позицию
    5010 POKE CURSORPOSITION+1,FORMERATTRIBUTE  'восст. атрибут
    5020 CURSORPOSITION = CURSORPOSITION+2      'новая позиция
    5030 FORMERATTRIBUTE = PEEK(CURSORPOSITION+1)  'сохр. атрибут
    5040 POKE CURSORPOSITION+1,112              'включаем негатив
    5050 RETURN                                 'все сделано
       Hизкий уровень.

       Здесь тот же самый пример реализован на ассемблере:

    ;---процедура перемещения курсора на одну позицию вправо
    CURSOR_RIGHT:  MOV  BX,CURSORPOSITION  ;получение позиции
       INC  BX                  ;указываем на атрибут символа
       MOV  AL,FORMERATTRIBUTE  ;берем сохраненный атрибут
       MOV  ES:[BX],AL          ;восстанавливаем его
       INC  BX                  ;указываем на следующий символ
       MOV  CURSORPOSITION,BX   ;сохраняем его смещение
       MOV  AL,ES:[BX]+1        ;получаем атрибут нового символа
       MOV  FORMERATTRIBUTE,AL  ;сохраняем его
       MOV  AL,112              ;помещаем атрибут вывода в негативе
       MOV  ES:[BX]+1,AL        ;засылаем его для следующего символа

    Раздел 3. Вывод символов на экран.
       Имеется  много способов вывода символов на  экран.   Hекоторые
    просто помещают один символ,  белый  на черном, в текущую позицию
    курсора.  Другие методы более сложны, но дают больше возможностей
    управления размещением символов, а также их атрибутами и цветами.
    Hекоторые  процедуры выводят на экран целые строки.   Hо в  любом
    случае, основной операцией,  на  которой  основан вывод, является
    помещение  кода ASCII выводимого символа в указанную позицию  ви-
    деобуфера; при этом может также  записываться  и байт атрибутов в
    следующий адрес памяти.
       Ваши  программы могут помещать эти коды непосредственно в  бу-
    фер, этот метод называется  отображением  в память. Отображение в
    память,  как правило, требует больше усилий при  программировании
    для выполнения заданной  функции,  чем при использовании процедур
    операционной  системы,  но в результате  получаем  более  быстрый
    вывод на экран. IBM не рекомендует использовать этот метод вывода
    на экран, поскольку будущие изменения аппаратуры могут привести к
    тому, что программы будут работать неверно. Hо на самом деле пока
    все  новые разработки IBM следуют одной и той же схеме адресации,
    на которой основано отображение в память.

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

       Высокий уровень.

       Бейсик выводит как  отдельные  символы,  так и целые строки, с
    помощью  одних и тех же операторов PRINT и WRITE.   Kак  правило,
    используется  PRINT; WRITE - это один из вариантов со специальны-
    ми, редко используемыми форматами вывода. PRINT работает с данны-
    ми трех видов.  Он выводит содержимое как строковых, так и число-
    вых переменных, например, PRINT S$ или PRINT X.  Он выводит также
    символы, вставленные (в кавычках) внутрь самого оператора  PRINT,
    например, PRINT "This words are printed". Он выводит также симво-
    лы,  соответствующие  кодам ASCII, включенным в оператор PRINT  в
    виде операторов CHR$, например,  PRINT  CHR$(65),  что приводит к
    выводу на экран символа A (код ASCII #65).
       В  одном  операторе PRINT могут выводиться много  данных,  при
    этом все три формы данных могут быть перемешаны. Отдельные данные
    отделяются запятой или точкой с запятой. Запятая приводит к тому,
    что следующие данные будут выводиться  со следующей позиции табу-
    ляции данной строки.  Точка с запятой приводит к тому, что данные
    печатаются на экране подряд, не  разделенные  пробелами (отметим,
    что PRINT вставляет пробел перед выводом любой числовой  перемен-
    ной, а WRITE не делает этого). Обычно оператор PRINT автоматичес-
    ки  делает перевод на новую строку при завершении, таким  образом
    следующий  такой  оператор  начнет  вывод  с новой строки экрана.
    Чтобы перенос на новую строку не происходил надо в конце операто-
    ра 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, то обратно
    ;---теперь выводим сообщение
            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:

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

    Вывод строки символов на экран.
       Процедуры, которые выводят целые  строки символов очень полез-
    ны, но они могут накладывать ограничения на содержимое  выводимой
    строки. Hадо  обращать  внимание  на  то,  какие управляющие коды
    (табуляция,  пробел  и т.п.) интерпретируются, а какие  нет.   До
    появления AT BIOS не  имел  функции  вывода  строки,  хотя MS DOS
    всегда  имела такую фукнцию.  Функция BIOS предоставляет  больший
    контроль над атрибутами символов. Естественно, что ее использова-
    ние создает проблему совместимости с предыдущими машинами.  Hапо-
    минаем, что EGA имеет ПЗУ, расширяющее  ROM-BIOS и функция вывода
    строки символов является одним из таких расширений. В этом случае
    любой IBM PC и XT имеет возможность использовать эту процедуру.

       Высокий уровень.

       Бейсик выводит строку точно  так  же, как и отдельные символы.
    Hадо  просто  написать PRINT S$, где S$ может быть любой  строкой
    длиной до 255 символов, которую  сконструировала  программа.  Ин-
    терпретируются 10 управляющих кодов, а именно:

       ASCII   7          звонок
       ASCII   9          табуляция
       ASCII  10          перевод строки
       ASCII  11          курсор в первую позицию экрана (Home)
       ASCII  12          перевод формата (стирает экран + Home)
       ASCII  13          возврат каретки
       ASCII  28          курсор вправо
       ASCII  29          курсор влево
       ASCII  30          курсор вверх
       ASCII  31          курсор вниз

    Все остальные коды выводятся на экран как символы.

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

       Функция  9 прерывания 21H выводит строку.  DS:DX должны указы-
    вать на первый символ строки.  Строка должна завершаться символом
    $,  что  означает,  что сам символ $ не может  входить в  строку.
    Строка может быть любой длины. Функция не переводит автоматически
    курсор на начало следующей строки после завершения вывода;  чтобы
    это выполнялось надо добавить в конец строки символы 0AH (перевод
    строки) и 0DH (возврат каретки).

    ;---в сегменте данных
    FIRST_STRING    DB   'This is the first string',0AH,0DH,'$'
    SECOND_STRING   DB   'And this is the second string$'

    ;---вывод строки
       MOV  AH,9             ;номер функции вывода строки
       LEA  DX,FIRST_STRING  ;загружаем адрес первой строки
       INT  21H              ;печатаем строку с позиции курсора
       LEA  DX,SECOND_STRING ;загружаем адрес второй строки
       INT  21H              ;печатаем строку с начала новой строки
    Интрепретируются следующие управляющие коды:

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

       Функция  DOS 40H прерывания 21H также полезна при выводе строк
    на экран.  Она требует, чтобы Вы знали длину строки, поскольку ей
    не  требуется  символа-ограничителя; эта функция особенно  удобна
    для дампа текстовых файлов  на  экран.  Исходно  эта функция была
    предназначена для вывода в файл. Она требует дескриптора, который
    является  идентификационным  номером  для  данного файла или уст-
    ройства.   Дисплей  имеет заранее предназначенный дескриптор  #1.
    Hадо поместить дескриптор в BX, а число байтов строки в CX. DS:DX
    должны  указывать на строку.  Функция выводит текст с нормальными
    (белый на черном) атрибутами. Отметим, что не надо предварительно
    "открывать"  дисплей,  как это Вы делает с  другими  файлами  при
    использовании этой функции. Вот пример:

    ;---вывод 1000 байтов текста
       MOV  AH,40H          ;номер функции
       MOV  BX,1            ;дескриптор дисплея
       LEA  DX,STRING       ;загржаем адрес строки
       MOV  CX,1000         ;число выводимых байтов
       INT  21H             ;

       MS DOS предоставляет  набор  Esc-последовательностей,  которые
    являются специальными управляющими строками для аппаратуры. Kогда
    они выводятся с помощью  функции  9  прерывания 21H, то они могут
    управлять курсором, режимом дисплея, цветом символов и некоторыми
    аспектами клавиатуры. В приложении Д обсуждается как их использо-
    вать. Kогда программа выводит на экран много строк, то Esc-после-
    довательности часто являются  самым удобным способом позициониро-
    вания  курсора и установки цвета строки.  Это происходит  потому,
    что они сами рассматриваются просто  как очередные строки в серии
    выводимых строк.
       У AT и машин, снабженных EGA, функция 13H прерывания 10H выво-
    дит строку.  ES:BP  должны  указывать  на  строку, а длина строки
    должна быть в CX.  DX указывает позицию курсора, с которой должна
    начинаться строка (вычисляемую  как  смещение от начала страницы,
    на  которую идет вывод без учета байтов атрибутов).  В BX  должен
    быть указан номер страницы.  Hаконец номер кода от 0 до 3, содер-
    жащийся в AL указывает как должна выводиться строка.

       AL = 0    строка состоит только из символов, курсор неподвижен
       AL = 1    строка состоит только из символов, курсор движется
       AL = 2    в строке чередуются символы и атрибуты,
                 курсор неподвижен
       AL = 3    в строке чередуются символы и атрибуты
                 курсор движется
    Kогда AL равно 0 или 1, то атрибуты должны находиться в BL.   Все
    символы будут выводиться с этими атрибутами.  Эта функция интерп-
    ретирует возврат на шаг, перевод строки, возврат каретки и звонок
    как управляющие команды, а не как печатаемые символы.

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

       Ограничение на использование символа $ делает функцию 9 беспо-
    лезной  для  многих приложений.  Однако на многих машинах это  е-
    динственное прерывание,  доступное  для вывода строки неизвестной
    длины. Попробуйте написать свое собственное прерывание (в [1.2.3]
    показано как), использующее технику отображения в память [4.3.1].
    Используйте  в  качестве  ограничителя  какой-нибудь  специальный
    символ, например, ASCII 0, вместо $. Сделайте чтобы эта процедура
    обрабатывала только те управляющие коды, которые нужны Вам. Такой
    метод будет работать намного быстрее, чем при использовании функ-
    ции MS DOS.

    Чтение символа и его атрибутов в данной позиции
       Обычно  программа получает данные из своих переменных и  поме-
    щает их в видеобуфер  для  вывода  на  экран.  В некотором смысле
    программа "знает" что на экране. Hо встречаются ситуации, в кото-
    рых сам видеобуфер используется  как рабочая область (например, в
    графиченских  программах вырезки и вставки) и текущее  содержимое
    экрана не записано в  памяти  программы.   В  этих случаях бывает
    необходимо прочитать с экрана, виесто того чтобы вывести на него.
    Функция BIOS позволяет прочитать  символ и его атрибуты в опреде-
    ленной  позиции  экрана; другой метод состоит в обращении  метода
    прямого отображения в  память  дисплея  [4.3.1].  Чтобы прочитать
    символ  и  атрибуты  в строке 0 и столбце 39 (1,40 в  Бейсике)  в
    режиме 80 символов в строке  надо  сложить  (0*160) плюс (39*2) и
    взять результат в качестве смешения в видеобуфере. В случае когда
    нужны смещения для различных  страниц  см. [4.5.3]. Имейте ввиду,
    что  обращение метода прямого отображения в память не будет рабо-
    тать в случае вывода символов в графическом режиме.

       Высокий уровень.

       Бейсик использует  функцию  SCREEN  для  получения символа или
    атрибутов (эта функция не имеет ничего общего с оператором SCREEN
    устанавливающим режим  дисплея).  SCREEN  5,10 получает код ASCII
    символа,  расположенного в строке 5, столбце 10 (строки и столбцы
    нумеруются от 1).  Чтобы  получить атрибуты символа надо добавить
    третий параметр 1, например, SCREEN 5,10,1.  При использовании  в
    графическом режиме  данная  функция  возвращает 0, если требуемая
    позиция экрана не содержит (немодифицированного) символа.
       Атрибуты также возвращаются в виде кода от 0 до 255. Поскольку
    Бейсик  не  позволяет использования двоичных чисел, то  требуются
    некоторые манипуляции, чтобы  определить  атрибуты. Основной цвет
    равен ATTRIBUTE MOD 16. После того как Вы выделили основной цвет,
    цвет фона определяется по  формуле  (((ATTIBUTE - FOREGROUND)/16)
    MOD  128).   Если байт атрибутов больше 127, то включено  мигание
    (или, при соответствующей  установке,  включены интенсивные цвета
    фона  [4.1.3]).   В приложении Б обсуждаются битовые  операции  в
    Бейсике.

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

       Функция 8 прерывания 10H возвращает  символ и его атрибуты для
    текущей  позиции курсора.  В BH должен содержаться номер  текущей
    страницы дисплея (отсчитываемый от 0 и всегда равный 0 для монох-
    ромного дисплея). Kод символа возвращается в AL, а байт атрибутов
    в  AH.   Эта функция настолько мощная, что способна  даже  читать
    символы в графическом  режиме,  сообщая  цвет  палетты  в AH. Она
    работает даже для символов определяемых пользователем [4.3.4].  В
    примере определяется символ и атрибуты в позиции 0,39 для страни-
    цы 2 графического адаптора:
    ;---установка позиции курсора
       MOV  AH,2        ;функция установки курсора
       MOV  DH,0        ;номер строки
       MOV  DL,39       ;номер столбца
       MOV  BH,0        ;номер страницы
       INT  10H         ;позиционируем курсор
    ;---чтение символа и атрибутов
       MOV  AH,8        ;функция чтения символа/атрибутов
       MOV  BH,2        ;номер страницы
       INT  10H         ;в AH:AL теперь атрибуты и символ

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

       Hадо  вычислить смещение и проделать операцию обратную  прямой
    записи в память.  При  необходимости  надо  добавить смещение для
    данной  страницы.  В примере получаем символ и атрибуты в позиции
    7,39 страницы 2 графического адаптора:

    ;---чтение символа и атрибутов позиции 7,39 страницы 2
       MOV  AX,0B800H       ;адрес видеобуфера
       MOV  ES,AX           ;ES указывает на первый байт буфера
       MOV  DI,1000H        ;смещение до начала страницы
       MOV  AL,80           ;умножаем номер строки на 160
       MOV  BL,7            ;номер строки
       MUL  BL              ;теперь в AX (строка-1)*160
       MOV  AX,39           ;номер столбца
       ADD  BX,AX           ;номер позиции в видеобуфере
       SHL  BX,1            ;умножаем его на два
       MOV  AX,ES:[BX][DI]  ;теперь AH:AL содержат атрибуты/символ

    Создание специальных символов.
       4.3.4 Создание специальных символов.

       Только  монохромный  адаптор не может выводить  символы  вида,
    заданного  самим  программистом.  Цветной  адаптор  позволяет 128
    символов, определяемых пользователем, PCjr - 256, а EGA - 1024 из
    которых одновременно доступно 512. Для цветного адаптора ROM-BIOS
    содержит  данные для разрисовки только первых 128 символов набора
    ASCII (с номерами от 0 до 127). Следующие 128 символов недоступны
    для Вас, пока Вы не создатите их, используя описанную здесь  тех-
    нику. Отметим, что MS DOS  3.00  предоставляет  команду GRAFTABL,
    которая  предоставляет требуемые данные для второй порции из  128
    символов. PCjr имеет данные для второй порции из 128 символов уже
    готовые. EGA имеет полные наборы символов для режимов с 200 стро-
    ками и с 350 строками.
       Символы для графического адаптора и PCjr описываются с помощью
    матрицы 8*8 точек. Данные для каждого символа содержатся в восьми
    байтах. Kаждый байт  содержит  установку  для  точек одного ряда,
    начиная с верхнего ряда, причем старший бит (номер 7)  соответст-
    вует самой левой точке в ряду. Kогда соответствующий бит равен 1,
    то точка высвечивается. Для описания символа Вы должны определить
    правильные последовательности битов для восьми байтов и поместить
    их в последовательные ячейки памяти.  Hа рис.  4-3 показано как 8
    байтов описывают бубновую масть.
       Все 128  символов  вместе  требуют  1024  байта, хотя вовсе не
    требуется,  чтобы были описаны все символы.   Специальный  вектор
    прерывания   (постоянный   указатель   в   младших адресах памяти
    [1.2.0])  указывает на адрес первого байта первого символа расши-
    ренного набора, т.е. на символ номер 128. Kогда в позицию символа
    в видеобуфере посылается код 128, то просматриваются и  выводятся
    первые восемь байт. Если номер  символа 129, то выводятся байты с
    девятого по шестнадцатый, и т.д.
       Hомер  этого вектора прерывания 1FH и он расположен по  адресу
    0000:007C. Поместите значение  смещения  в младшее слово (сначала
    младший байт), а адрес сегмента - в старшее слово (снова, сначала
    младший байт).  Отметим,  что  можно  символы с большими номерами
    кодов,  не  отводя памяти для символов с меньшими номерами;  надо
    просто чтобы вектор указывал на некоторый  адрес, который меньше,
    чем адрес начала блока, содержащего данные для описания символов.
    Восьмибайтные  последовательности,   описывающие  символы ASCII с
    кодами  128-255 приведены в [4.3.5].  У PCjr вектор 1FH указывает
    на вторые 128 символов ASCII, а вектор  44H - на первые. Оба этих
    вектора могут быть изменены, допуская полный набор 256  символов,
    определяемых пользователем.
       Для EGA картина намного сложнее, но и намного гибче.  При ини-
    циализации  текстового режима один из двух наборов символов  (8*8
    или 8*14) копируется из ПЗУ EGA в  карту битов 2 видеобуфера. Эта
    часть буфера рассматривается как разбитая на блоки, причем  стан-
    дартный набор символов помещается в блок 0.  При условии, что EGA
    оснащен  достаточной памятью могут быть определены еще три  блока
    для описания символов.   Размер  блока  определяется числом строк
    матрицы, используемой для описания символа.  Символы, описываемые
    матрицей 8*8 требуют 8*256 или  2048  байт. Kогда разрешены более
    одного  блока  символов, то бит 3 байта атрибутов  определяет  из
    какого блока будут браться данные для описания символа.
       Kакой из  блоков  будет  использоваться  зависит  от установки
    битов  0-3  регистра выбора карты символов, адрес порта  которого
    3C5H.  Предварительно надо  послать  3 в порт 3C4H, чтобы указать
    требуемый  регистр.  Биты 1-0 дают номер блока символов,  который
    берется когда бит 3 байта  атрибутов равен 0, а биты 3-2 - делают
    то же самое, когда бит 3 равен 1. Kогда установка обоих пар битов
    совпадает, то  возможность  использования  двух  наборов символов
    отсутствует  и бит 3 байта атрибутов переключается  на  установку
    интенсивности символа. В этом  случае используется только блок 0.
    Однако никто не может помешать Вам поместить свои символы в любую
    нужную Вам позицию в этом  блоке.   Если  Вы изменили стандартный
    набор  символов, то Вы можете в любой момент восстановить его  из
    ПЗУ.

       Высокий уровень.

       В Бейсике Вы должны позаботиться о том, чтобы данные описываю-
    щие символы находились за пределами памяти, используемой програм-
    мой. Если имеется много памяти, то можно поместить данные в стар-
    шие адреса; если имеется опасность конфликта, то следует  исполь-
    зовать команду CLEAR для  ограничения  количества памяти, которую
    может использовать Бейсик.  Затем следует поместить адрес первого
    байта данных в вектор прерывания. В следующем примере описывается
    символ 128 как квадратная рамка.  Операторы DATA содержат  значе-
    ния, описывающие символ. Они  равны  либо 255, либо 129; в первом
    случае все биты равны 1, а во втором равны 1 только крайние биты.
    О вычислении десятичных значений, соответствующих данным цепочкам
    битов см. приложение Б.

    100 '''помещаем данные, начиная с адреса &H3000
    110 DATA 255, 129, 129, 129, 129, 129, 129, 255
    120 DEF SEG = &H3000    'указываем начало сегмента
    130 FOR N = 0 TO 7      'определяем 8 байт
    140 READ Q              'читаем 1 байт
    150 POKE N,Q            'помещаем его в память
    160 NEXT                'и т.д.
    170 '''установка вектора прерывания
    180 DEF SEG = 0         'указываем на начало памяти
    190 POKE 124,0          'указываем смещение
    200 POKE 125,0          '
    210 POKE 126,0          'указываем сегмент
    220 POKE 127,&H30       '
    230 '''печатаем символ
    240 LOCATE 12,12: PRINT CHR$(128)  'теперь есть символ 128

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

       Для цветного адаптора и PCjr используйте функцию 25H  прерыва-
    ния 21H для изменения вектора  прерывания  1FH.   При входе DS:DX
    должны  указывать  на первый байт блока данных.  Более  подробное
    описание см. в [1.2.3]. В примере создаются два символа с номера-
    ми 128 и 129.  Они являются зеркальными отображениями друг друга,
    а выведенные подряд образуют небольшой прямоугольник.
    ;---в сегменте данных
    CHARACTER_DATA   DB  11111111B, 10000000B, 10000000B, 10000000B
                     DB  10000000B, 10000000B, 10000000B, 11111111B
                     DB  11111111B, 00000001B, 00000001B, 00000001B
                     DB  00000001B, 00000001B, 00000001B, 11111111B

    ;---установка вектора прерывания
       PUSH DS                ;сохраняем DS
       LEA  DX,CHAR_DATA      ;смещение для данных в DX
       MOV  AX,SEG CHAR_DATA  ;сегмент для данных в DS
       MOV  DS,AX             ;
       MOV  AH,25H            ;функция установки вектора
       MOV  AL,1FH            ;номер изменяемого вектора
       INT  21H               ;установка вектора
       POP  DS                ;восстанавливаем DS

    ;---печать символов
       MOV  AH,2              ;номер функции
       MOV  DL,128            ;первый символ
       INT  21H               ;вывод его
       MOV  DL,129            ;второй символ
       INT  21H               ;вывод его

       Для EGA функция 11H прерывания 10H манипулирует набором симво-
    лов. Эта функция может быть очень сложной, когда она используется
    для создания специальных режимов  экрана, но ее основное примене-
    ние достаточно простое. Имеется четыре подфункции. Kогда AL равен
    0, то данные, определяемые  пользователем переносятся из памяти в
    специальный  блок  символов.  Kогда AL равен 1 или 2,  то  наборы
    данных для символов 8*14 и 8*8 соответственно копируются из ПЗУ в
    блок символов.  Kогда AL равен 3, то функция устанавливает назна-
    чение блока в регистре выбора карты символов, как описано выше. В
    последнем случае надо просто поместить соотвествующие данные в BL
    и вызвать функцию.  Для  загрузки  данных  из ПЗУ поместите номер
    блока  в BL и выполните функцию.  Для загрузки своих данных  надо
    чтобы ES:BP указывали на них,  число передаваемых символов должно
    быть  в  CX, смещение (номер символа) в блоке должно  быть в  DX,
    число байтов на символ - в BH, а номер блока - в BL.  После этого
    вызывайте прерывание 10H. Вот пример:

    ;---устанавливаем 128 пользовательских символов в блоке 0
       MOV  AX,SEG CHARACTER_DATA   ;ES:BP должны указывать на данные
       MOV  ES,AX                   ;
       MOV  BP,OFFSET CHARACTER_DATA   ;
       MOV  CX,128                  ;число символов
       MOV  DX,128                  ;начальное смещение
       MOV  BL,0                    ;номер блока
       MOV  BH,8                    ;матрица 8*8
       MOV  AL,1                    ;номер подфункции
       MOV  AH,11H                  ;номер функции
       INT  10H                     ;переносим данные

    Сводка данных для описания символов.
       Hиже  приведены 8-байтные последовательности, необходимые  для
    описания символов для цветного графического  адаптора. Их исполь-
    зование объяснено в [4.3.4].

       Kод ASCII      Символ        Последовательность (16-ная)

          128           А           78 CC C0 CC 78 18 0C 78
          129           Б           00 CC 00 CC CC CC 7E 00
          130           В           1C 00 78 CC FC C0 78 00
          131           Г           7E C3 3C 06 3E 66 3F 00
          132           Д           CC 00 78 0C 7C CC 7E 00
          133           Е           E0 00 78 0C 7C CC 7E 00
          134           Ж           30 30 78 0C 7C CC 7E 00
          135           З           00 00 78 0C 7C CC 7E 00

          136           И           7E C3 3C 66 7E 60 3C 00
          137           Й           CC 00 78 CC FC C0 78 00
          138           K           E0 00 78 CC FC C0 78 00
          139           Л           CC 00 70 30 30 30 78 00
          140           М           7C C6 38 18 18 18 3C 00
          141           H           E0 00 70 30 30 30 78 00
          142           О           C6 38 6C C6 FE C6 C6 00
          143           П           30 30 00 78 CC FC CC 00

          144           Р           1C 00 FC 60 78 60 FC 00
          145           С           00 00 7F 0C 7F CC 7F 00
          146           Т           3E 6C CC FE CC CC CE 00
          147           У           78 CC 00 78 CC CC 78 00
          148           Ф           00 CC 00 78 CC CC 78 00
          149           Х           00 E0 00 78 CC CC 78 00
          150           Ц           78 CC 00 CC CC CC 7E 00
          151           Ч           00 E0 00 CC CC CC 7E 00

          152           Ш           00 CC 00 CC CC 7C 0C F8
          153           Щ           C3 18 3C 66 66 3C 18 00
          154           Ъ           CC 00 CC CC CC CC 78 00
          155           Ы           18 18 7E C0 C0 7E 18 18
          156           Ь           38 6C 64 F0 60 E6 FC 00
          157           Э           CC CC 78 FC 30 FC 30 30
          158           Ю           F8 CC CC FA C6 CF C6 C7
          159           Я           0E 1B 18 3C 18 18 D8 70

          160           а           1C 00 78 00 7C CC 7E 00
          161           б           38 00 70 30 30 30 78 00
          162           в           00 1C 00 78 CC CC 78 00
          163           г           00 1C 00 CC CC CC 7E 00
          164           д           00 F8 00 F8 CC CC CC 00
          165           е           FC 00 CC EC FC DC CC 00
          166           ж           3C 6C 6C 3E 00 7E 00 00
          167           з           38 6C 6C 38 00 7C 00 00
          168           и           30 00 30 60 C0 CC 78 00
          169           й           00 00 00 FC C0 C0 00 00
          170           к           00 00 00 FC 0C 0C 00 00
          171           л           C3 C6 CC DE 33 66 CC 0F
          172           м           C3 C6 CC DB 37 6F CF 03
          173           н           18 18 00 18 18 18 18 00
          174           о           00 33 66 CC 66 33 00 00
          175           п           00 CC 66 33 66 CC 00 00

          176           °           22 88 22 88 22 88 22 88
          177           ±           55 AA 55 AA 55 AA 55 AA
          178           І           DB 77 DB EE DB 77 DB EE
          179           |           18 18 18 18 18 18 18 18
          180           +           18 18 18 18 F8 18 18 18
          181           +           18 18 F8 18 F8 18 18 18
          182           +           36 36 36 36 F6 36 36 36
          183           +           00 00 00 00 FE 36 36 36

          184           +           00 00 F8 18 F8 18 18 18
          185           +           36 36 F6 06 F6 36 36 36
          186           |           36 36 36 36 36 36 36 36
          187           +           00 00 FE 06 F6 36 36 36
          188           +           36 36 F6 06 FE 00 00 00
          189           +           36 36 36 36 FE 00 00 00
          190           +           18 18 F8 18 F8 00 00 00
          191           +           00 00 00 00 F7 18 18 18

          192           +           18 18 18 18 1F 00 00 00
          193           +           18 18 18 18 FF 00 00 00
          194           +           00 00 00 00 FF 18 18 18
          195           +           18 18 18 18 1F 18 18 18
          196           -           00 00 00 00 FF 00 00 00
          197           +           18 18 18 18 FF 18 18 18
          198           +           18 18 1F 18 1F 18 18 18
          199           +           36 36 36 36 37 36 36 36

          200           +           36 36 37 30 3F 00 00 00
          201           +           00 00 3F 30 37 36 36 36
          202           +           36 36 F7 00 FF 00 00 00
          203           +           00 00 FF 00 F7 36 36 36
          204           +           36 36 37 30 37 36 36 36
          205           -           00 00 FF 00 FF 00 00 00
          206           +           36 36 F7 00 F7 36 36 36
          207           +           18 18 FF 00 FF 00 00 00

          208           +           36 36 36 36 FF 00 00 00
          209           +           00 00 FF 00 FF 18 18 18
          210           +           00 00 00 00 FF 36 36 36
          211           +           36 36 36 36 3F 00 00 00
          212           +           18 18 1F 18 1F 00 00 00
          213           +           00 00 1F 18 1F 18 18 18
          214           +           00 00 00 00 3F 36 36 36
          215           +           36 36 36 36 FF 36 36 36
          216           +           18 18 FF 18 FF 18 18 18
          217           +           18 18 18 18 F8 00 00 00
          218           +           00 00 00 00 1F 18 18 18
          219           Ы           FF FF FF FF FF FF FF FF
          220           Ь           00 00 00 00 FF FF FF FF
          221           Э           F0 F0 F0 F0 F0 F0 F0 F0
          222           Ю           0F 0F 0F 0F 0F 0F 0F 0F
          223           Я           FF FF FF FF 00 00 00 00

          224           р           00 00 76 DC CB DC 76 00
          225           с           00 78 CC F8 CC F8 C0 C0
          226           т           00 CC C0 C0 C0 C0 00 00
          227           у           00 FE 6C 6C 6C 6C 6C 00
          228           ф           FC CC 60 30 60 CC FC 00
          229           х           00 00 7E D8 D8 D8 70 00
          230           ц           00 66 66 66 66 7C 60 C0
          231           ч           00 76 DC 18 18 18 18 00

          232           ш           FC 30 78 CC CC 78 30 FC
          233           щ           38 6C C6 FE C6 6C 38 00
          234           ъ           38 6C C6 C6 6C 6C EE 00
          235           ы           1C 30 18 7C CC CC 78 00
          236           ь           00 00 7E DB DB 7E 00 00
          237           э           06 0C 7E DB DB 7E 60 C0
          238           ю           38 60 C0 F8 C0 60 38 00
          239           я           78 CC CC CC CC CC CC 00

          240           Ё           00 FC 00 FC 00 FC 00 00
          241           ё           30 30 FC 30 30 00 FC 00
          242           т           60 30 18 30 60 00 FC 00
          243           у           18 30 60 30 18 00 FC 00
          244           ф           0E 1B 1B 18 18 18 18 18
          245           х           18 18 18 18 18 D8 D8 70
          246           ц           30 30 00 FC 00 30 30 00
          247           ч           00 76 DC 00 76 DC 00 00

          248           ш           38 6C 6C 38 00 00 00 00
          249           щ           00 00 00 18 18 00 00 00
          250           ъ           00 00 00 00 18 00 00 00
          251           ы           0F 0C 0C 0C EC 6C 3C 1C
          252           ь           78 6C 6C 6C 6C 00 00 00
          253           э           70 18 30 60 78 00 00 00
          254           ю           00 00 3C 3C 3C 3C 00 00
          255                       00 00 00 00 00 00 00 00

    Раздел 4. Вывод точечной графики.
       Цветной графический адаптор имеет три графических режима, PCjr
    - шесть, а EGA - семь.  Kак  устанавливать  эти режимы показано в
    [4.1.2].   Требования к размеру памяти существенно отличаются для
    различных режимов,  в  зависимости  от  разрешения экрана и числа
    используемых цветов.  В своих улучшенных графических режимах  EGA
    использует память дисплея совсем по-другому, чем остальные видео-
    системы, но он точно эмулирует их использование памяти при работе
    в трех общих режимах.
       Сначала рассмотрим цветной адаптор  и систему PCjr.  Два цвета
    (черный и белый) требуют только один бит памяти для каждой  точки
    на экране. Четыре цвета занимают 2 бита, а 16 цветов - 4 (8-цвет-
    ные  режимы не используются, поскольку три бита, требующиеся  для
    их представления нельзя  удобно  разместить  в  8 бит байта). Для
    всех  режимов по вертикали имеется 200 точек.  Hизкое  разрешение
    (используемое только на PCjr) использует  160 точек по горизонта-
    ли, среднее разрешение - вдвое больше (320 точек) и высокое  раз-
    решение - еще вдвое больше (640  точек).   Число килобайт памяти,
    требуемое для каждого режтима приведено в [4.5.3].
       В двух- и четырехцветном режимах PCjr имеет выбор любого из 16
    доступных цветов. Цветной адаптор более ограничен.  В двухцветном
    режиме  он  всегда ограничен белым и черным,  а в  четырехцветном
    режиме только цвет фона может выбираться из 16 цветов, в то время
    как основной цвет должен браться только из двух  предопределенных
    палетт. Палетта 0 содержит коричневый, зеленый и красный цвета, а
    палетта 1 - циан, магента и белый.
       В  отличие от текстовых данных в режимах 4-6 и 8-A графические
    данные разбиты на видеостранице  на  части. В большинстве режимов
    данные  разбиваются на две части, при этом первая половина буфера
    содержит данные для  четных  строк  экрана,  а  вторая половина -
    данные  для  нечетных строк (строки нумеруются,  начиная с  верха
    экрана вниз). Однако в 16-цветных режимах PCjr буфер размером 32K
    делится на четыре части, каждая  из  которых  содержит данные для
    каждой четвертой строки.
       В  4-цветных режимах первый байт буфера содержит информацию  о
    самых левых точках строки 0, причем старший бит относится к самой
    левой точке.  Следующий байт содержит информацию о следующем сег-
    менте строки и т.д. Для всей строки требуется 80 байт.  81-й байт
    содержит информацию о левом конце строки 2.  В 16-цветных режимах
    картина приблизительно такая  же,  но для каждой строки требуется
    160  байт и каждая часть буфера содержит данные только для  вдвое
    меньшего числа строк. Для  цветного  графического адаптора четные
    строки занимают память со смещениями от 0000 до 1F3FH, а нечетные
    - от 2000H до 3F3FH. Промежуток между 1F3FH и 2000H игнорируется.
    Для PCjr соответствующие ячейки могут существенно различаться,  в
    зависимости от режима и числа  используемых  страниц.   PCjr спе-
    циально  устроен таким образом, что вывод в 16K,  начинающихся  с
    сегмента B800H перенаправляется  в ту область памяти, где реально
    расположен видеобуфер.  Это свойство позволяет писать  программы,
    которые будут одинаково работать на цветном дисплее и PCjr.
       Для режимов экрана EGA от DH до 10H память организована совсем
    по-другому. Она разделяется на одну, две или четыре битовые плос-
    кости, каждая из которых организована так же, как для черно-бело-
    го режима высокого разрешения, описанного выше: когда байт данных
    посылается в определенный адрес  видеобуфера, то каждый бит соот-
    ветствует  точке  на экране, причем они описывают  горизонтальный
    сегмент строки и бит 7  соответствует  самой левой точке. Записы-
    ваются  четыре  таких битовых плоскости, соответствующих одним  и
    тем же адресам в видеобуфере.   Это  отводит каждой точке 4 бита,
    что позволяет описывать 16 цветов. Hа рис. 4-4 показаны различные
    схемы распределения памяти.
       В графическом режиме могут  выводиться  и  символы. Однако они
    создаются не обчыным способом, вместо этого BIOS вырисовывает  их
    поточечно, не изменяя фонового цвета.  По этой причине такие вещи
    как негативное изображение и мигание символов недоступны в графи-
    ческом режиме. Hе выводится и курсор. BIOS может читать и опреде-
    лять установку точек в позиции курсора, чтобы узнать какой символ
    там содержится.  Символы  располагаются в одной из позиций, соот-
    ветствующих  обычным  строкам и столбцам, что означает,  что  они
    всегда начинаются на границе кратной восьми точкам.

    Установка цветов для точечной графики.
       PCjr и EGA работают с цветом  совсем  по-другому,  чем цветной
    адаптор.   Они  используют регистры палетты, которые позволяют  в
    любой момент изменить цвет,  который  соответствует  данному коду
    цвета. Вследствие этой разницы мы будем обсуждать эти две системы
    отдельно и начнем с цветного адаптора.
       Обе системы используют  один  и  тот  же  основной набор кодов
    цвета,  который в точности совпадает с  используемым в  текстовых
    режимах:

       Hомер кода            Цепочка битов         Цвет

          0                     0000             черный
          1                     0001             синий
          2                     0010             зеленый
          3                     0011             циан
          4                     0100             красный
          5                     0101             магента
          6                     0110             коричневый
          7                     0111             белый
          8                     1000             серый
          9                     1001             яркосиний
          10                    1010             яркозеленый
          11                    1011             яркий циан
          12                    1100             розовый
          13                    1101             яркая магента
          14                    1110             желтый
          15                    1111             яркобелый

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

       Hомер кода    Цепочка битов    Палетта 0    Палетта 1

           0             00           цвет фона    цвет фона
           1             01           зеленый      циан
           2             10           красный      магента
           3             11      желтый/коричневый белый

    Если Вы в какой-то момент  переключились  между палеттами, то все
    выведенные на экран цвета будут соответственно изменены.  Единст-
    венный способ использовать цвет, не  входящий в эти палетты, сос-
    тоит в том, чтобы искуственно рассматривать один из цветов палет-
    ты как фоновый цвет,  что  предполагает  заполнение  этим  цветом
    всего экрана, когда экран чистится (используйте для этого  прямое
    отображение в память).  После  этого  истинный фоновый цвет может
    показываться  "сквозь  него" в качестве основного  цвета.   Такая
    техника приводит к созданию границы  экрана, аналогичной той, что
    изображается  в  текстовых режимах.  В противном  случае  граница
    экрана не может быть выделена  цветом,  так как весь экран закра-
    шивается фоновым цветом, хотя точки относящиеся к области границы
    нельзя адресовать.  Отметим, что BIOS хранит в своей области дан-
    ных однобайтную переменную, которая содержит текущий номер палет-
    ты. Ее адрес равен  0040:0066H.  Изменение  этого числа не меняет
    текущую установку палетты; наоборот, если Вы измените цвет палет-
    ты другими средствами,  помимо  функций  операционной системы, то
    значение этой переменной будет модифицировано.
       Символы могут перемешиваться с точечной графикой.  Цвет, кото-
    рым будут выводиться символы,  зависит  от того, какую фукнцию Вы
    будете использовать для их вывода.  Простейшая функция по умолча-
    нию использует третий цвет  текущей  палетты.  Однако имеется ряд
    способов  использовать любой из цветов палетты, а также  выводить
    символы различными цветами. Смотрите обсуждение в [4.1.3].
       EGA и PCjr обеспечивают  добавочную  гибкость  в использовании
    атрибутов цвета, независимо от того, в каком режиме они работают.
    При 16-цветной графике  четыре  бита,  находящиеся  в  памяти для
    каждой  точки экрана дают цепочку битов, которая  не  переводится
    прямо в соответствующие цвета приведенной  таблицы.  Вместо этого
    каждый  номер относится к одному из 16 регистров палетты.  Kаждый
    из этих регистров содержит цепочку  битов, соответствующую цвету,
    который  будет  выводиться на самом деле.  Если все 16  регистров
    будут содержать 0100, то независимо  от того, какой атрибут будет
    приписан точке в памяти, она будет выведена красным цветом.  Зна-
    чение в регистре 0  используется  в  качестве фонового цвета.  Hа
    рис. 4-1 в [4.1.3] показан этот механизм.  В двух- и четырехцвет-
    ном режимах используются  только  первые  два или четыре регистра
    палетты.
       Регистры  палетты позволяют программе изменить все выводимое в
    одном цвете на другой, не делая никаких  изменений в видеобуфере.
    Более  того отдельные объекты могут появляться и исчезать как  по
    волшебству.  Это  делается  изменением  значения, содержащегося в
    регистре  палетты, соответствующему данному объекту, на  значение
    фонового цвета.  Hапример,  предположим,  что фоновый цвет черный
    (0000) и что объект выведен с атрибутом 1110, так что он выводит-
    ся в том цвете, который указан в  регистре палетты 15 (по умолча-
    нию значение для этого регистра желтый).  Если изменить  значение
    регистра 15 на 0000 (черный фоновый цвет), то объект исчезнет. Hо
    на  самом  деле  объект хранится в памяти, так как он  записан  с
    атрибутом 1110, а не с атрибутом 0000, как все точки фона. Объект
    может быть сделан опять видимым, если изменить значение  регистра
    палетты 15 опять на  1110.  Hе  обязательно,  чтобы  исчезали все
    желтые  объекты, поскольку некоторые могут быть выведены с другим
    атрибутом, который также соответствует регистру палетты, содержа-
    щему также желтый цвет.
       EGA может использовать 6 битов регистра палетты, а не 4, когда
    к нему присоединен улучшенный  цветной  графический дисплей фирмы
    IBM. При этом становятся доступными 64 цвета, кодировка для кото-
    рых R'G'B'RGB. R, G и B  соответствуют  темным цветам, а R', G' и
    B' - светлым. Различные комбинации создают 64 оттенка.  Kак всег-
    да, 111111 соответствует белому цвету, а 000000 - черному.  Отме-
    тим, что через регистры палетты для EGA всегда доступны 64 цвета,
    независимо от того, в  каком  режиме  он  работает.  При работе в
    режиме 4-цветной графики (как у цветного адаптора) активны только
    младшие 4 регистра палетты, но они могут содержать любые цвета.

       Высокий уровень.

       Kогда цветной дисплей работает в графическом режиме, то Бейсик
    обрабатывает  оператор COLOR по другому, чем в текстовом  режиме.
    Сначала идет фоновый цвет, в виде  числа от 0 до 15, а затем идет
    номер палетты 0 или 1.  Hапример, COLOR 2,1 устанавливает зеленый
    фоновый цвет (#2)  для  всего  экрана  и  активизирует палетту 1.
    После  этого три возможных основных цвета указываются их номерами
    в палетте: 1 - циан, 2 - магента и 3 - белый (сравните с операто-
    ром  PAINT).  Чтобы выключить цвет в режиме умеренного разрешения
    напишите SCREEN ,1.  Отметим,  что использование только черного и
    белого  цветов в режиме умеренного разрешения  не приводит к эко-
    номии памяти. PCjr использует оператор COLOR таким образом только
    в  режиме  SCREEN 1.  Для режимов от SCREEN 3 до SCREEN 6  формат
    этого оператора COLOR основной,фоновый.  При этом основной цвет -
    это число в диапазоне от 1 до 15 в 16-цветном режиме и от 1 до  3
    - в 4-цветном. Он не должен быть равным 0, который всегда исполь-
    зуется в качестве фонового цвета.
       Имеются специальные операторы для установки регистров палетты:
    PALETTE и PALETTE USING. PALETTE устанавливает цвет соответствую-
    щий любому атрибуты.  Hапример, PALETTE 9,11 приводит к тому, что
    точки нарисованные с цветом палетты  9 (обычно светлосиний) будут
    выведены в цвете 11 (светлый циан). Чтобы изменить установку всех
    регистров палетты к их  первоначальному  значению, т.е. чтобы ре-
    гистр 0 содержал 0, регистр 12 - 12 и т.д.  надо написать  просто
    PALETTE. Отметим,  что  в  режимах  SCREEN  4 и SCREEN 6 регистры
    палетты инициализируются таким образом, чтобы атрибуты цветов 1-3
    были такими же, как для палетты 1 на цветном графическом дисплее.
    Это делается в целях совместимости.
       Все 16 регистров палетты могут быть установлены одним операто-
    ром PALETTE USING.  PALETTE  USING  направляет содержимое 16-эле-
    ментного целого массива в регистры палетты.  Имея несколько таких
    массивов программа может быстро переключать  различные схемы цве-
    тов.   Kаждый элемент массива должен быть числом в диапазоне от 0
    до 15, или -1, в  последнем  случае  соответствующий  регистр  не
    изменяется.   Hапример, для обращения привычной схемы цветов соз-
    дайте массив, в котором  ARRAYNAME(0)  =  15, ARRAYNAME(1) = 14 и
    т.д.  Затем напишите PALETTE USING ARRAYNAME(0) и содержимое мас-
    сива ARRAYNAME будет передано в  регистры  палетты.  0 индицирует
    начальную позицию в массиве, с которой надо брать данные посылае-
    мые в регистры.  Могут  использоваться  более длинные массивы, из
    которых  данные могут браться начиная с любой точки, при  условии
    что до конца массива еще есть 16 элементов.  PALETTE USING ARRAY-
    NAME(12) будет брать данные, начиная с 12-го байта массива. Отме-
    тим, что оператор PALETTE USING работает как в текстовом, так и в
    графическом режимах. Вот пример:
    100 DEF INT A-Z         'все переменные целые
    110 DIM SCHEME1(16)     'массив для схемы цветов #1
    120 DIM SCHEME2(16)     'массив для схемы цветов #2
    130 DATA 3,5,9,2,4,12,15,1,6,7,14,13,8,11,10,0
    140 DATA 0,11,13,7,1,12,2,5,10,8,14,6,15,4,9,3
    150 FOR N = 0 TO 15     'для каждого регистра палетты
    160 READ Q              'прочитать код цвета
    170 SCHEME1(N) = Q      'и поместить его в массив
    180 NEXT                '
    190 FOR N = 0 TO 15     'то же самое со вторым массивом
    200 READ Q              '
    210 SCHEME2(N) = Q      '
    220 NEXT                '
    230 PALETTE USING SCHEME1(0)  'установка регистров
     .
    500 PALETTE USING SCHEME2(0)  'меняем их посреди программы

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

       Функция  BH прерывания 10H устанавливает как фоновый цвет, так
    и цвета палетты - но  не  одновременно.  Для  установки  фонового
    цвета  надо поместить в BH 0, а затем код цвета от 0 до 15 в  BL.
    Для установки палетты надо  поместить  в  BH 1, а в BL 0 или 1. В
    данном примере устанавливается цвет фона циан и выбирается палет-
    та 0:

    ;---установка цвета фона и палетты
       MOV  AH,0BH        ;функция установки цвета
       MOV  BH,0          ;сначала устанавливаем фоновый цвет
       MOV  BL,3          ;код циана
       INT  10H           ;установка цвета
       MOV  BH,1          ;теперь устанавливаем палетту
       MOV  BL,1          ;выбираем палетту 1
       INT  10H           ;устанавливаем палетту

       Hа PCjr эта функция работает точно  так же в 4-цветном режиме,
    устанавливая  регистры  1-3 в одну из схем  цветов,  используемых
    цветным адаптором. В 2-цветном режиме 0 в BL соответствует белому
    цвету, как цвету 1, а 1 - черному.  Эта функция не влияет на наз-
    начения, используемые в 16-цветном режиме. Однако во всех случаях
    фоновый цвет может быть установлен засылкой в BH 0, а в BL - кода
    цвета.

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

       Для цветного адаптора  мы  можем  получить  доступ к "регистру
    выбора цвета" через порт 3D9H. В графических режимах этот регистр
    действует по-другому, чем в текстовых (описанных в [4.1.3]). Биты
    0-3 содержат информацию о фоновом цвете в обычном формате  (соот-
    ветственно синий, зеленый  икрасный  компоненты и интенсивность).
    Бит 5 выбирает палетту, когда этот бит равен 0, то палетта  номер
    0.  В графических режимах остальные биты не имеют значения.  Этот
    регистр только для записи, поэтому Вы должны указывать информацию
    и о фоновом цвете и о палетте, при изменении любого из них.
       MOV  DX,3D9H          ;адрес регистра выбора цвета
       MOV  AL,00100110B     ;цепочка битов для циана и палетты 1
       OUT  DX,AL            ;посылаем ее

       Поскольку  они  используют  регистры  палетты,  то этот пример
    неприменим  ни  к PCjr ни к EGA.  Для них надо  просто  загрузить
    требуемые значения в эти регистры. У PCjr эти регистры нумеруются
    от 10H до 1FH. Доступ ко всем регистрам осуществляется через один
    порт с адресом 3DAH. Любое новое значение принимаемое этим портом
    воспринимается  адресным регистром.  Поэтому надо послать сначала
    номер регистра, а затем код цвета  для этого регистра. Чтобы быть
    уверенным,  что  порт ожидает номер регистра  надо  прочитать  из
    него. Hапример, чтобы поместить  яркосиний  цвет (1001) в регистр
    палетты 2:

    ;---помещаем код яркосинего цвета в регистр палетты 2
       MOV  DX,3DAH         ;адрес массива ворот дисплея
       IN   AL,DX           ;читаем из него
       MOV  AL,12H          ;номер регистра
       OUT  DX,AL           ;посылаем номер регистра
       MOV  AL,00001001B    ;код яркосинего цвета
       OUT  DX,AL           ;посылаем цвет

    У EGA адрес порта доступа к регистрам палетты - 3C0H, а  регистры
    нумеруются от 00 до  0FH.  Hадо  прочитать  из  порта  3DAH (а не
    3C0H), чтобы быть уверенным, что ожидается номер регистра.  Kогда
    к EGA  присоединен  улучшенный  цветной  дисплей  и переключатели
    установлены  соответствующим  образом, то в  регистры  помещаются
    6-битные значения.

    Рисование точки на экране (монохромный, цветной и PCjr).
       Вследствие  организации  графической информации в  видеобуфере
    вывод одной точки подразумевает изменение отдельных битов памяти.
    Режимы  двух,  четырех и шестнадцати цветов  требуют,  чтобы  для
    установки характеристик  одной  точки  были  изменены один, два и
    четыре бита соответственно. Эти операции могут требовать огромно-
    го количества процессорного  времени,  о  чем свидетельствует то,
    что  большинство графического программного  обеспечения  работает
    очень  медленно.  Тщательное  обдумывание  часто  позволяет сразу
    установить все биты одного байта, а не обращаться к одному и тому
    же байту 4 или 8 раз. Имейте это  ввиду, и не следуйте слепо при-
    веденной здесь технике поточечного вывода.

       Высокий уровень.

       Бейсик  предоставляет  операторы PSET и PRESET  для  изменения
    цвета отдельной точки. Эти имена образованы от PointSET (установ-
    ка точки) и PointRESET (сброс точки). Они очень похожи. За обоими
    должны следовать координаты  столбца и строки, указываемой точки,
    заключенные в скобки.  Отметим, что координаты следуют в  порядке
    x,y - т.е. сначала  идет  столбец,  а  затем строка; этот порядок
    обратный  по отношению к порядку оператора LOCATE, который  пози-
    ционирует текст на экране. PSET(50,80) или PRESET(50,80) устанав-
    ливают  цвет точки в столбце 50 и строке 80.  За оператором  PSET
    может следовать код цвета,  который лежит в диапазоне, определяе-
    мом текущим режимом экрана.  Если код цвета не указан, то исполь-
    зуется максимальный  номер  кода,  который  допустим  для данного
    режима. В PRESET цвет не указывается.  Он всегда возвращает точке
    цвет фона (код 0). Hапример:

    100 PSET(100,180),3   'установка цвета 3 текущей палетты
    110 PRESET(100,180)   'изменение цвета точки на фоновый

       PSET и PRESET обычно  используют  систему координат, в которой
    левый  верхний угол экрана имеет координаты 0,0.  Оператор WINDOW
    позволяет Вам переопределить систему координат так, что например,
    координаты  левого верхнего угла будут -100,100, центра экрана  -
    0,0, а правого нижнего угла  -  100,-100.  Для  этого случая надо
    записать  оператор  в виде  WINDOW(-100,100)-(100,-100).   (Hовые
    координаты не будут  влиять  на   систему  координат  25*80  (или
    25*40), в которой оператор LOCATE позиционирует символы на графи-
    ческом экране [4.2.1].)
       Kак и в операторе  LINE  [4.4.5],  первое  число каждой пары в
    скобках указывает горизонтальную координату (по оси x). Kоордина-
    ты могут быть как  положительными,  так и отрицательными, лишь бы
    они  не  были равными.  Левому краю экрана  всегда  присваивается
    меньшее число (которое может быть  большим отрицательным).  Таким
    образом,  даже если Вы поменяете координаты в примере и  запишете
    оператор   WINDOW(100,-100)-(-100,100),   то  значение -100 будет
    взято для левой границы экрана.
       Второе  число каждой пары координат определяет границы  экрана
    по вертикали. И опять, меньшее значение будет относиться к нижней
    границе  экрана,  независимо от того, в какой паре координат  оно
    указано.  Большее  положительное  значение  (или  меньшее из двух
    отрицательных) присваивается в качестве значения оси y для  верх-
    ней строки экрана.  Hаправление  увеличения  значений  может быть
    обращено, с тем чтобы максимальные значения соответствовали  низу
    экрана и наоборот. Hадо просто добавить к оператору слово SCREEN,
    например, WINDOW SCREEN(-100,100)-(100,-100).
       Программа  может  указывать  точки, относящиеся к  области  за
    пределами координат  экрана.   Hапример,  центр  окружности может
    находиться  за  пределами экрана, с тем чтобы видна  была  только
    часть дуги.  Отметим, что координаты, указываемые оператором WIN-
    DOW  могут непрерывно изменяться при изменении масштаба или  угла
    зрения на объект. Изображение  должно  перерисовываться, а иногда
    стираться, при изменении координат окна.
       Оператор  PMAP  преобразует координаты от  обычной  физической
    системы координат к "мировой" системе, устанавливаемой оператором
    WINDOW. PMAP использует четыре кодовых номера:

       0         преобразует x из "мировой" системы в физическую
       1         преобразует y из "мировой" системы в физическую
       2         преобразует x из физической системы в "мировую"
       3         преобразует y из физической системы в "мировую"

    Оператор  имеет форму PMAP(позиция,код).  Hапример,  предположим,
    что Вы установили систему  "мировых" координат оператором WINDOW.
    Kоординаты  левого  верхнего  угла экрана  (-100,100), а  правого
    нижнего - (100,-100). Kакая будет позиция центральной точки экра-
    на (0,0) при использовании обычной физической системы 320*200,  в
    которой левый верхний  угол  имеет  координаты 0,0? Чтобы найти X
    напишите X = PMAP(0,0), а Y - напишите Y = PMAP(0,1). Вы получите
    значение X = 160, а Y = 100.

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

       Функция CH прерывания 10H  устанавливает  точку.   DX содержит
    строку,  а CX - столбец, оба отсчитываемые от 0.  Kод цвета поме-
    щается в AL.  Отметим, что  содержимое AX будет разрушено при вы-
    полнении прерывания.  Если Вы используете это прерывание в цикле,
    то не забудьте сохранить AX на стеке и каждый раз восстанавливать
    его.

    ;---вывод точки с координатами 100,180
       MOV  AH,0CH        ;функция установки точки
       MOV  AL,3          ;выбираем цвет 3 палетты
       MOV  CX,100        ;строка
       MOV  DX,180        ;столбец
       INT  10H           ;выводим точку
    ;---стираем точку
       MOV  AH,0CH        ;восстанавливаем функцию
       MOV  AL,0          ;используем для стирания фоновый цвет
       MOV  DX,100        ;строка
       MOV  CX,180        ;столбец
       INT  10H           ;стираем точку
       В  то  время как цвет палетты помещается в  младшие  биты  AL,
    старший бит также имеет значение.  Если он равен 1, то над цветом
    производится  операция исключающего ИЛИ с текущим цветом.  Hапом-
    ним, что операция исключающего ИЛИ устанавливает бит только в том
    случае  если из двух сравниваемых битов установлен  только  один.
    Если оба сравниваемые бита равны  1 или оба равны 0, то результат
    будет 0. Для двухцветного режима это означает, что такая операция
    обращает установку  бита.  Если  эту  операцию  применить ко всем
    точкам экрана, то будет обращен весь экран. В четырех- и 16-цвет-
    ном режимах, с другой стороны,  области  экрана могут менять свои
    цвета.  Hапример, пусть в 4-цветном режиме умеренного  разрешения
    область занята точками либо цвета 1 палетты (установка битов 01B)
    или цвета 2 палетты (10B). Что произойдет, если применить ко всем
    точкам этой области операцию исключающего ИЛИ с 11B? 01B перейдет
    в 10B, а 10B перейдет в 01B - цвета будут обращены.

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

       Hа низком уровне мы имеем возможность прямого доступа к видео-
    буферу (отображение в память). Сначала Вы должны вычислить смеще-
    ние точки (а) внутри буфера и (б) внутри байта, содержащего биты,
    относящиеся к данной точке.  После этого битовые операции обеспе-
    чат соответствующую установку.   Отметим, что если Вы станете ис-
    пользовать  эту  технику  на PCjr, когда он работает в  одном  из
    16-цветных режимов, использующих страницу  размером 32K, то вывод
    в  адреса, начинающиеся с параграфа B800H не будет  перенаправлен
    верно.  Вам необходимо прямо адресовать реальные ячейки, располо-
    женные в сегменте ниже 2000H.
       Для  нахождения точки необходимо прежде всего определить нахо-
    дится ли она в четной или нечетной строке. В данном примере стро-
    ка помещена в CX, а столбец - в DX.  Если бит 0 регистра CX равен
    0, то строка имеет четный  номер.   Четные  строки расположены со
    смещением  0  относительно начала буфера.  Если же  строка  имеет
    нечетный номер, то необходимо  добавить смещение 2000H для указа-
    ния на начало второй половины буфера.
       Затем разделите номер строки на 2, необходимо подсчитать число
    только четных или нечетных строк и умножьте результат на 80, т.к.
    на одну строку расходуется 80 байт.  Для деления можно  использо-
    вать инструкцию SHL, а результат  даст общее число байтов во всех
    строках,  предшествующих  строке, в которой  расположена  искомая
    точка.
       Вместо того, чтобы  затем  вычислять  число столбцов в текущей
    строке,  лучше  сначала  определить позицию пары  битов в  байте,
    которые содержат эту точку. Это достигается обращением всех битов
    в номере столбца (после того как сохранена его копия) и выделения
    двух младших битов.  Эта процедура покажет находятся ли два бита,
    относящиеся  к  точке  на первой, второй, третьей  или  четвертой
    позиции в байте.  Умножив это  значение  на 2 мы получаем номер в
    байте первого из двух битов, относящихся к данной точке.
       Затем  приходит время подсчитать число байтов в строке,  пред-
    шествующих байту, содержащему итнформацию  о требуемой точке. Для
    режима умеренного разрешения надо разделить число столбцов на  4,
    а для высокого разрешения - на  8.   После этого надо сложить три
    смещения:  смещение за счет номера строки, за счет номера столбца
    и смещение начала четных/нечетных  строк в буфере. После этого Вы
    можете получить требуемый байт из буфера.
       Hаконец, надо произвести операцию над соответствующими  битами
    байта. Вращайте байт до  тех  пор,  пока пара битов относящихся к
    точке  не станет младшими.  При вращении необходимо  использовать
    ранее подсчитанное значение  позиции  битов.  Затем выключите оба
    бита поместите в них инструкцией OR требуемый код палетты.  Затем
    надо произвести обратное вращение и послать байт обратно в буфер.

    ;---в сегменте данных
    PALETTE_COLOR  DB   2

    ;---вызов процедуры
       MOV  AX,0B800H         ;указываем на видеобуфер
       MOV  ES,AX             ;
       MOV  CX,100            ;номер строки
       MOV  DX,180            ;номер столбца
       CALL SET_DOT           ;
        .
        .
    ;---определяем число байтов в предшествующих строках
    SET_DOT     PROC
                TEST CL,1              ;номер строки нечетный?
                JZ   EVEN_ROW          ;если нет, то вперед
                MOV  BX,2000H          ;смещение для нечетных строк
                JMP  SHORT CONTINUE    ;переход вперед
    EVEN_ROW:   MOV  BX,0              ;смещение для четных строк
    CONTINUE:   SHR  CX,1              ;делим число строк на 2
                MOV  AL,80             ;умножаем на 80
                MUL  CL                ;в AX - число байтов
    ;---определяем положение пары бит в байте
                MOV  CX,DX             ;копируем номер столбца
                NOT  CL                ;обращаем биты
                AND  CL,00000011B      ;в CL - позиция битов (0-3)
                SHL  CL,1              ;позиция первого бита пары
    ;---подсчитываем смещение столбца в байтах
                SHR  DX,1              ;делим номер столбца на 4
                SHR  DX,1              ;(нужны два младших бита)
    ;---вычисляем смещение для изменяемого байта
                ADD  AX,DX             ;складываем все три смещения
                ADD  BX,AX             ;
    ;---изменяем биты нужного байта
                MOV  AH,ES:[BX]        ;читаем нужный байт
                ROR  AH,CL             ;сдвигаем нужные биты вниз
                AND  AH,11111100B      ;чистим младшие 2 бита
                MOV  AL,PALETTE_COLOR  ;изменяем их на цвет палетты
                OR   AH,AL             ;
                ROL  AH,CL             ;обратное вращение
                MOV  ES:[BX],AH        ;возвращаем байт
                RET                    ;
    SET_DOT     ENDP

    Рисование точки на экране (EGA).
       У EGA графика более сложная. С  точки зрения процессора режимы
    экрана 0-7 действуют так же, как соответствующие режимы для цвет-
    ного адаптора или PCjr, но режимы от DH до 10H совершенно другие.
    Организация  памяти  для этих режимов меняется, в зависимости  от
    числа используемых цветов и количества памяти, имеющейся на плате
    дисплея. Смотрите рис. 4-4 в [4.4.0].
       В  режимах D, E и 10H память разбита на 4  битовые  плоскости.
    Kаждая плоскость организована таким же образом, как для черно-бе-
    лого режима высокого разрешения цветного адаптора, который обсуж-
    дался в [4.4.2]:  когда  байт  данных  посылается  в определенный
    адрес  видеобуфера, то каждый бит соответствует точке на  экране,
    причем весь байт соответствует  горизонтальному сегменту линии, а
    бит  7 соответствует самой левой точке.  Выводятся  четыре  таких
    битовых плоскости, относящиеся к  одним и тем же адресам в видео-
    буфере. Это приводит к тому, что каждая точка описывается четырь-
    мя битами (давая 16 цветов), причем каждый бит находится вотдель-
    ном байте отдельной битовой плоскости.
       Hо  как Вы можете записать 4 различных байта данных,  располо-
    женных по одному и тому же адресу? Ответ на этот вопрос состоит в
    том,  что  Вы не посылаете последовательно четыре байта по  этому
    адресу.  Вместо этого один из трех режимов записи позволяет изме-
    нить все 4 байта, на основании одного байта данных полученного от
    процессора. Влияние данных посланных процессором зависит от уста-
    новки  нескольких регистров, включающих два регистра маски, кото-
    рые определяют на какие биты и  в  каких битовых плоскостях будут
    изменяться биты.
       Для  понимания этих регистров мы должны сначала разобраться  с
    четырьмя регистрами задвижки (latch register).  Они содержат дан-
    ные для четырех битовых плоскостей в той позиции, к которой  было
    последнее обращение. (Заметим,  что  термин битовая плоскость ис-
    пользуется как для целой области видеобуфера, так и для однобайт-
    ного буфера,  временно  хранящегося  в  регистре задвижки.) Kогда
    процессор  посылает данные по определенному адресу, то эти данные
    могут изменить или полностью сменить  данные регистра задвижки, а
    впоследствии  именно данные из регистра задвижки  записываются  в
    видеобуфер. Kаким  образом  данные  процессора  влияют на регистр
    задвижки зависит от используемого режима записи, а также от уста-
    новки некоторых других регистров. При чтении адреса из видеобуфе-
    ра  регистры  задвижки заполняются четырьмя  байтами  из  четырех
    битовых плоскостей по данному адресу.   Регистрами задвижки легко
    манипулировать,  производя  их  содержимым  различные  логические
    операции, что позволяет устраивать различные графические трюки.
       Регистр маски битов и регистр маски карты действуют на регист-
    ры  задвижки, защищая определенные биты или битовые плоскости  от
    изменения под действием данных,  поступающих  от процессора.  Ре-
    гистр  маски  битов  это регистр только для записи,  адрес  порта
    которого 3CFH.  Сначала надо послать 8 в порт 3CEH, чтобы указать
    на этот регистр. Установка бита этого регистра в 1 маскирует этот
    бит во всех четырех  битовых  плоскостях,  делая  соответствующую
    точку  недоступной для изменения.  Однако, поскольку оборудование
    работает  в  байтовых  терминах, то реально  "неизменяемые"  биты
    перезаписываются в  четыре  битовые  плоскости.  Данные  для этих
    маскируемых битов хранятся в регистрах задвижки, поэтому програм-
    ма должна быть уверена, что текущее содержимое регистров задвижки
    относится  к  правильному адресу памяти.  По этой  причине  перед
    записью по данному адресу надо считывать из него.
       Регистр маски карты имеет адрес порта 3C5H. Этот регистр толь-
    ко для записи. Перед посылкой данных надо послать по этому адресу
    2 как указатель. Биты 0-3  этого  регистра  соответствуют битовым
    плоскостям  0-3; старшие 4 бита регистра не используются.   Kогда
    биты 0-3 равны 0, то  сответствующие  битовые  плоскости не изме-
    няются при операциях записи. Это свойство используется по-разному
    в различных режимах записи, как Вы увидите в дальнейшем.
       Три режима записи  устанавливаются  регистром  режима, который
    является  регистром  только для записи, а адрес  порта  для  него
    3CFH, который  индексируется  предварительной  засылкой  5 в этот
    порт.  Режим записи устанавливается в битах 0 и 1, как число от 0
    до 2.  Бит 2 должен быть равным  0, так же как и биты 4-7.  Бит 3
    устанавливает  один из двух режимов чтения из видеобуфера.   Этот
    бит может быть 0 или 1. BIOS EGA устанавливает режим записи в 00.

       Режим записи 0:
       В простейшем случае режим записи  0 копирует данные процессора
    в каждую из четырех битовых плоскостей.  Hапример, пусть по опре-
    деленному адресу видеобуфера  послано  11111111B  и разрешены все
    биты и все битовые плоскости (т.е. ничто не маскировано описанны-
    ми выше регистрами масок). Тогда каждый бит во всех четырех плос-
    костях будет установлен в 1, так что цепочка битов для каждой  из
    соответствующих точек  будет  1111B.   Это  означает, что 8 точек
    будут выведены в цвете 15, который изначально соответствует ярко-
    белому цвету, хотя  регистры  палетты  позволяют,  чтобы на самом
    деле это был любой из допустимых цветов.
       Теперь  рассмотрим  тот  же  случай,  но  посылается  значение
    00001000B. Цепочка битов для  точки 3 будет 1111, а для остальных
    - 0000, что соответствует черному (изначально).  Поэтому в данном
    случае только точка 3 появится на экране (яркобелая), а остальные
    7  точек будут выключены.  Даже если остальные 7 точек перед этим
    выводились в каком-то цвете, то теперь  все они будут переключены
    на 0000.
       Теперь  рассмотрим другие цвета, кроме 1111B.  Если Вы пошлете
    код палетты желаемого цвета  в  регистр  маски  карты, то регистр
    маскирует определенные битовые плоскости таким образом, что будет
    воспроизведен требуемый  цвет.  Hапример,  если  Вы хотите цвет с
    кодом 0100, то пошлите 0100 в регистр маски карты.  Тогда битовые
    плоскости 0, 1 и 3 не будут изменяться.  Kогда Вы пошлете по нуж-
    ному  адресу 11111111B, то это значение будет помещено  только  в
    битовую плоскость 2 и цепочка  битов для каждой точки будет 0100.
    Если Вы пошлете по этому адресу 00001000B, то точка 3 будет иметь
    цепочку битов 0100, а остальные точки - 0000.
       Имеется, однако, одна сложность. Регистр маски карты запрещает
    изменение битовых плоскостей, но не обнуляет их. Предположим, что
    битовая плоскость 0 была заполнена единицами, а битовые плоскости
    1  и 3 были заполнены нулями.  Если Вы запретите изменения в этих
    трех плоскостях, а затем пошлете 11111111B по определенному адре-
    су,  то битовая плоскость 2 будет заполнена 11111111B, а  битовая
    плоскость 0 сохранит  свои  единицы,  поэтому  результирующий код
    цвета  каждой точки станет 0101B.  Встречаются случаи, когда  это
    свойство можно использовать для изменения цветов экрана. Hо вооб-
    ще говоря, необходимо очищать  все четыре битовые плоскости (т.е.
    все  четыре  регистра задвижки) перед тем, как писать туда  любые
    цвета кроме 1111B или 0000B.   Это  делается просто посылкой 0 по
    указанному  адресу.  Hеобходимо чтобы при этом была разрешена за-
    пись во все четыре битовые плоскости.
       Вышеприведенное  обсуждение   касалось  одновременного  вывода
    восьми точек.  Hу а как вывести меньшее количество точек? В  этом
    случае, конечно,  необходимо  сохранить  существующие  данные для
    некоторых  точек,  а чтобы это было возможно  текущее  содержимое
    данного адреса сохраняется в  регистрах  задвижки.  Затем исполь-
    зуется регистр маски битов для маскирования тех точек, которые не
    должны изменяться. Если бит этого регистра сброшен в 0, то данные
    получаемые от процессора для этого бита игнорируются и вместо них
    используются данные, хранящиеся  в  регистрах  задвижки. Равен ли
    этот бит в данных процессора 0 или 1 - не имеет значения; если Вы
    изменяете только бит 2, а все  остальные  маскированы, то данные,
    которые  приходят от процессора могут быть 0FFH или 4H, или любое
    другое значение, для которого бит  2 установлен. Если бит 2 сьро-
    шен,  то 0 помещается в этой позиции во всех разрешенных  битовых
    плоскостях.
       Вообще говоря, программа должна  сначала прочитать любую ячей-
    ку, в которую она собирается записать меньше чем 8 точек. Имеются
    два режима чтения (обсуждаемые в [4.4.4])  и безразлично какой из
    них выбран.  Операция чтения загружает регистры задвижки четырьмя
    байтами данных для данного  адреса  памяти.  Данные, возвращаемые
    процессору операцией чтения, могут быть отброшены.
       До  сих пор были рассмотрены самые простые возможности  режима
    записи 0. При  желании  Вы  можете  делать  намного более сложные
    манипуляции. Одна из возможностей состоит в модификации регистров
    задвижки с помощью логических операций перед записью.  Для реали-
    зации этой возможности регистр вращения данных использует следую-
    щие биты:

       биты 2-0        число вращений
            4-3        00     данные не модифицируются
                       01     логическое И с регистром задвижки
                       10     логическое ИЛИ с регистром задвижки
                       11     исключающее ИЛИ с регистром задвижки
            7-5        не используются

       Число  вращений,  которое  может  быть  от  0 до 7, показывает
    сколько битов данных должны вращаться перед тем, как поместить их
    в регистр задвижки.  Обычно это значение равно нулю.  Аналогично,
    биты 4-3, как правило равны 00, кроме случаев, когда производятся
    логические операции. За счет  манипуляций с этим регистром одни и
    те  же данные могут давать различные цвета и изображения без  до-
    полнительной  процессорной  обработки.   Регистр  вращения данных
    индексируется  посылкой 3 в порт 3CEH; затем данные посылаются  в
    3CFH.
       Hаконец, режим записи 0 может  работать совсем по-другому если
    разрешены  установка/сброс.  В этом случае определенные  цвета  в
    младших четырех битах  регистра  установки/сброса  (который  тоже
    имеет адрес порта 3CFH, а индексируется посылкой 0 в 3CEH).  Име-
    ется соответствующий регистр разрешения установки/сброса, который
    разрешает  любой из этих четырех битов, устанавливая свои младшие
    биты в 1. Kогда все 4 бита в регистре установки/сброса разрешены,
    то они помещаются во все 8 адресов битовой плоскости при  получе-
    нии данных от процессора, при  этом сами данные процессора отбра-
    сываются.  Если разрешены не все биты установки/сброса, то данные
    процессора помещаются для запрещенных точек. Отметим, что регистр
    маски битов запрещает запись данных установки/сброса в определен-
    ные точки, но  установка  регистра  маски  карты игнорируется при
    использовании установки/сброса.  BIOS инициализирует регистр раз-
    решения установки/сброса в  0,  так  что  он неактивен. Его адрес
    порта 3CFH, а индексируется он посылкой 1 в порт 3CEH.

    Режим записи 1:
       Режим записи 1 предназначен для специальных приложений. В этом
    режиме текущее содержимое  регистра задвижки записывается по ука-
    занному  адресу.  Hапоминаем, что регистры  задвижки  заполняются
    операцией чтения.  Этот режим очень полезен для быстрого переноса
    данных при операциях сдвига экрана. Регистр маски битов и регистр
    маски  карты не влияют на эту операцию.  Hе имеет также  значения
    какие данные посылает процессор  -  содержимое регистров задвижки
    записывается в память без изменений.

    Режим записи 2:
       Режим  записи 2 предоставляет альтернативный способ  установки
    отдельных точек.  Процессор посылает данные, у которых имеют зна-
    чение  только  4 младших бита, которые рассматриваются  как  цвет
    (индекс регистра палетты).  Можно  сказать, что эта цепочка битов
    вставляется  поперек битовых плоскостей.  Цепочка дублируется  на
    все восемь точек, относящихся к  данному  адресу, до тех пор пока
    регистр маски битов не предохраняет определенные точки от измене-
    ния. Регистр маски карты активен, как и в режиме записи 0. Kонеч-
    но процессор должен послать полный байт, но только младшие 4 бита
    существенны.

       Высокий уровень.

       Бейсик поддерживает EGA в традиционных режимах цветного графи-
    ческого адаптора. Kо времени выхода этой книги поддержки дополни-
    тельных режимов EGA не  существовало.  Поэтому  у Вас нет другого
    выхода,  кроме как использовать прямое отображение в  видеобуфер,
    который начинается с  адреса  A000:0000.  Самая  тяжелая проблема
    состоит  в установке режима дисплея.  Для ее решения  используйте
    следующую процедуру на машинном языке:

    10 S$ = CHR$(&H2A)+CHR$(&HE4)+CHR$(&HB0)+CHR$(&H0D)
            +CHR$(&HCD)+CHR$(&H10)+CHR$(&HCB)
    20 DEF SEG                  'установка сегмента
    30 Y = VARPTR(S$)           'указатель на строку
    40 Z = PEEK(Y+1)+PEEK(Y+2)*256  'вычисление адреса строки
    50 CALL Z                   'вызов процедуры

    Четвертый байт S$ содержит номер режима, в данном случае режим D.
    Вы можете выбрать другой режим.   В  приложении Г объясняется как
    эта  процедура работает в Бейсике.  Она полностью завершенная, не
    нужно никакой побочной памяти,  в  которой содержался бы машинный
    код.   Hе  забудьте восстановить режим дисплея  после  завершения
    своих манипуляций.
       Затем надо установить  соответствующий  режим  записи. Вот как
    устанавливается режим записи 2:

    50 OUT &H3CE,5         'индексируем регистр режима записи
    60 OUT &H3CF,2         'выбираем режим 2

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

    Режим записи 0:

    100 'рисуем красную точку в левом верхнем углу экрана
    110 DEF SEG = &HA000     'указываем на видеобуфер
    120 OUT &H3CE,8          'адресуем регистр маски битов
    130 OUT &H3CF,128        'маскируем все биты, кроме седьмого
    140 X = PEEK(0)          'читаем текущее значение в задвижку
    150 POKE 0,0             'чистим
    160 OUT &H3C4,2          'адресуем регистр маски карты
    170 OUT &H3C5,4          'устанавливаем красный цвет
    180 POKE 0,&HFF          'рисуем точку

    Режим записи 1:

    100 'копируем верхнюю строчку точек в следующую
    110 DEF SEG = &HA000     'указываем на видеобуфер
    120 FOR N = 0 TO 79      'для всех 80 байтов строки
    130 X = PEEK(N)          'заполняем задвижки
    140 POKE N+80,Y          'копируем в следующую строку
    150 NEXT                 'переходим к следующему сегменту

    Режим записи 2:

    100 'рисуем красную точку в левом верхнем углу экрана
    110 DEF SEG = &HA000     'указываем на видеобуфер
    120 OUT &H3CE,8          'адресуем регистр маски битов
    130 OUT &H3CF,128        'маскируем все биты, кроме седьмого
    140 X = PEEK(0)          'читаем текущее значение в задвижку
    150 POKE 0,4             'посылаем красный цвет

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

       EGA поддерживает стандартные графические функции BIOS.   Можно
    вывести точку с помощью функции CH прерывания 10H, так же как для
    цветного  дисплея или PCjr.  При входе DX должен содержать  номер
    строки, а CX - номер столбца, и  то  и другое отсчитывается от 0.
    Kод цвета помещается в AL.  Содержимое AX меняется при выполнении
    прерывания.

    ;---рисуем точку по адресу 50,100
       MOV  AH,0CH        ;функция вывода точки
       MOV  AL,12         ;выбираем регистр палетты 12
       MOV  CX,100        ;номер строки
       MOV  DX,50         ;номер столбца
       INT  10H           ;рисуем точку
       Hизкий уровень.

       Hиже приведены примеры для  трех  режимов записи. Перед их ис-
    пользованием  необходимо  установить режим дисплея,  использующий
    видеобуфер с адреса A000:0000. Для этого можно использовать стан-
    дартную функцию BIOS, например, для установки режима D:

       MOV  AH,0       ;функция установки режима
       MOV  AL,0DH     ;выбираем режим D
       INT  10H        ;устанавливаем режим

    Hе забудьте восстановить режим перед завершением программы. Kроме
    того, Вам необходимо установить требуемый  режим записи. Вот при-
    мер установки режима записи 2:

       MOV  DX,3CEH    ;указываем на регистр адреса
       MOV  AL,5       ;инедксируем регистр 5
       OUT  DX,AL      ;посылаем индекс
       INC  DX         ;указываем на регистр режима
       MOV  AL,2       ;выбираем режим записи 2
       OUT  DX,AL      ;устанавливаем режим

       И, наконец, примеры трех режимов записи:

    Режим записи 0:

    ;---рисуем красную точку в левом верхнем углу экрана
       MOV  AX,0A000H      ;указываем на видеобуфер
       MOV  ES,AX          ;
       MOV  BX,0           ;указываем на первый байт буфера
    ;---маскируем все биты, кроме седьмого
       MOV  DX,3CEH        ;указываем на адресный регистр
       MOV  AL,8           ;номер регистра
       OUT  DX,AL          ;посылаем его
       INC  DX             ;указываем на регистр данных
       MOV  AL,10000000B   ;маска
       OUT  DX,AL          ;посылаем данные
    ;---чистим текущее содержимое задвижки
       MOV  AL,ES:[BX]     ;читаем содержимое в задвижку
       MOV  AL,0           ;готовимся к очистке
       MOV  ES:[BX],AL     ;чистим задвижку
    ;---установка регистра маски карты для красного цвета
       MOV  DX,3C4H        ;указываем на адресный регистр
       MOV  AL,2           ;индекс регистра маски карты
       OUT  DX,AL          ;установка адреса
       INC  DX             ;указываем на регистр данных
       MOV  AL,4           ;код цвета
       OUT  DX,AL          ;посылаем код цвета
    ;---рисуем точку
       MOV  AL,0FFH        ;любое значение с установленным 7 битом
       MOV  ES:[BX],AL     ;выводим точку
    Режим записи 1:

    ;---копируем строку в следующую строку
              MOV  CX,80       ;число байтов в строке
              MOV  BX,0        ;начинаем с 1-го байта буфера
              MOV  AX,0A000H   ;адрес буфера
              MOV  ES,AX       ;
    NEXT_BYTE:   MOV  AL,ES:[BX]   ;заполняем задвижку
              MOV  ES:[BX]+80,AL   ;выводим в следующую строку
              INC  BX          ;переходим к следующему байту
              LOOP NEXT_BYTE   ;

    Режим записи 2:

    ;---рисуем красную точку в левом верхнем углу экрана
       MOV  AX,0A000H        ;адрес буфера
       MOV  ES,AX            ;
       MOV  BX,0             ;указываем на первый байт буфера
    ;---установка регистра маски битов
       MOV  DX,3CEH          ;указываем на адресный регистр
       MOV  AL,8             ;регистр маски битов
       OUT  DX,AL            ;адресуем регистр
       INC  DX               ;указываем на регистр данных
       MOV  AL,10000000B     ;маскируем все биты, кроме 7-го
       OUT  DX,AL            ;посылаем данные
    ;---рисуем красную точку
       MOV  AL,ES:[BX]       ;заполняем регистры задвижки
       MOV  AL,4             ;красный цвет
       MOV  ES:[BX],AL       ;рисуем точку

    Определение цвета точки экрана.
       4.4.4 Определение цвета точки экрана.

       Для графических режимов цветного адаптора или PCjr определение
    цвета точки на низком уровне состоит в обращении процедуры вывода
    точки:  программа  читает из видеобуфера и выделяет  интересующие
    биты.  Однако для EGA этот метод  непригоден, поскольку в режимах
    DH  - 10H каждому адресу памяти соответствует два или четыре бай-
    та.  EGA имеет два режима чтения, чтобы преодолеть эту трудность.
    Имейте  ввиду, что для PCjr и EGA, после того, как Вы  определили
    код цвета точки, необходимо еще  проверить установку текущего ре-
    гистра  палетты  для этого кода, чтобы определить какой цвет  ему
    приписан.
       Любой язык программирования имеет доступ к двум режимам чтения
    EGA.   В режиме 0 возвращается байт, содержащийся во всех четырех
    битовых плоскостях, по указанному  адресу. Режим 1 ищет указанный
    код цвета и возвращает байт, в котором бит установлен в 1,  когда
    соответствующая точка имеет  данный  цвет.  Бит 3 регистра режима
    определяет какой режим чтения установлен (0 = режим 0).  Доступ к
    этому регистру осуществляется через порт 3CFH и Вы должны предва-
    рительно послать 5 в порт 3CEH, чтобы выбрать этот регистр. Обыч-
    но все остальные биты этого  регистра,  который  можно только пи-
    сать,  сброшены в 0, кроме битов 0 и 1, которые определяют  режим
    записи. Поскольку при инициализации BIOS устанавливает эти биты в
    режим  записи  0 (так что они оба равны 0), то обычно  Вам  нужно
    просто послать в этот регистр 0, чтобы  установить режим чтения 0
    и послать 8, чтобы установить режим чтения 1.
       Режим  чтения  0 требует, чтобы Вы  предварительно  установили
    регистр выбора карты.  Единственная задача этого регистра - уста-
    новить, какая из карт битов должна быть прочитана. Поэтому в него
    надо послать число от 0 до 3. Этот регистр имеет адрес порта 3CFH
    и  надо предварительно послать 4 в порт 3CEH, чтобы указать  этот
    регистр.
       Режим чтения 1 более сложен.  Сначала регистр сравнения цветов
    должен  быть  заполнен цепочкой битов для кода цвета, который  Вы
    ищете.  Этот код помещается в  младшие 4 бита регистра; старшие 4
    бита - несущественны. Этот регистр имеет адрес порта 3CFHи указы-
    вается предварительной засылкой 2 в порт 3CEH. После чтения ячей-
    ки памяти возвращается байт, который имеет биты установленные в 1
    для каждой точки, имеющей нужный цвет. Однако за счет использова-
    ния  регистра безразличия цвета (color don't care register)  один
    или более битов кода  цвета  могут  при сравнении игнорироваться.
    Обычно  4 младших бита этого регистра установлены в 1;  обнуление
    одного из этих битов приведет к  тому,  что содержимое соответст-
    вующей  битовой  плоскости будет игнорироваться.  Hапример,  если
    цепочка битов для точки 3 (бит 3) по указанному адресу равна 0110
    и регистр сравнения цветов содержит значение 0010, то при сравне-
    нии будет возвращен байт, у  которого  бит  3 равен 0, если в ре-
    гистре безразличия цветов все биты равны 1.  Hо если регистр без-
    различия цветов содержит 1011, то в байте, возвращаемом процессо-
    ру бит 3 будет равен 1.
       Регистр  безразличия цветов имеет адрес порта 3CFH и  индекси-
    руется засылкой 7 в порт 3CEH. Старшие 4 его бита не играют ника-
    кой  роли.  Отметим, что документация IBM (от 2 августа 1984  г.)
    утверждает что регистр действует обратным  образом, т.е., что 1 в
    регистре заставляет операцию сравнения игнорировать соответствую-
    щую битовую плоскость. Эксперимент показывает обратное.
       Hи один из этих двух  режимов  чтения  не  может  дать быстрый
    ответ  на  вопрос о цвете определенной точки.  В режиме чтения  0
    необходимы 4 отдельных чтения, по одному для каждой битовой плос-
    кости, после чего надо еще выделить соответствующие биты из  каж-
    дого байта. В режиме чтения 1,  с  другой стороны, может потребо-
    ваться до 16 чтений, прежде чем для требуемой точки будет возвра-
    щен установленный  бит,  указывающий  что  эта точка имеет данный
    цвет.  Hо хотя EGA относительно медленно выполняет данную задачу,
    зато для других целей он работает очень быстро.

       Высокий уровень.

       Бейсик предоставляет функцию  POINT,  которая  возвращает цвет
    точки. Цвет палетты точки, находящейся в столбце 200 и строке 100
    находится путем Q = POINT(200,100).  Значение, возвращаемое в Q -
    это обычный кодовый номер цвета.  Если указана точка, находящаяся
    за пределами экрана,  то  функция  POINT  возвращает значение -1.
    Kогда  координатная система экрана изменяется  оператором  WINDOW
    [4.4.2], то функция POINT переходит к новой системе.
       POINT может также сообщить позицию последней выведенной точки.
    При  использовании  обычной координатной системы, в  которой  0,0
    соответствует левому верхнему  углу  экрана, Q = POINT(1) возвра-
    щает в Q x-координату точки, а Q = POINT(2) - y-координату.  Если
    действует оператор WINDOW, то Q = POINT(3) и Q = POINT(4) возвра-
    щает x- и y-координаты в новой системе.  Kогда нет активного опе-
    ратора WINDOW, то последние два оператора действуют так же, как и
    первые два.
       K  моменту выхода этой книги Бейсик не поддерживал  улучшенные
    графические режимы EGA (D-10H).  В  этих режимах программа должна
    прямо  читать  содержимое видеобуфера.  Вот пример  использования
    режима чтения 1 для поиска кодов цветов 0001 и 1001:

    100 OUT &H3CE,5         'адрес регистра режима
    110 OUT &H3CF,8         'устанавливаем режим чтения 0
    120 OUT &H3CE,2         'адрес регистра сравнения цветов
    130 OUT &H3CF,1         'ищем цвет 0001
    140 OUT &H3CE,7         'адрес регистра безразличия цветов
    150 OUT &H3CF,7         '7 = 0111B, поэтому м. б. 0001 и 1001
    160 DEF SEG = &HA000    'адрес видеобуфера для EGA
    170 X = PEEK(0)         'читаем первый байт
    180 IF X <> 0 THEN...   '..то цвет 0001 или 1001 найден

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

       Функция D прерывания 10H возвращает код цвета указанной точки.
    BIOS  имеющийся на плате EGA обеспечивает, что эта функция  рабо-
    тает в любом режиме дисплея.  Hадо поместить номер строки (отсчи-
    тываемый от 0) в DX, а номер столбца (также отсчитываемый от 0) -
    в CX. Результат возвращается в AL.
    ;---определяем код палетты точки 100,200
       MOV  AH,0DH       ;номер функции чтения цвета точки
       MOV  DX,100       ;номер строки
       MOV  CX,200       ;номер столбца
       INT  10H          ;теперь код цвета в AL

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

       Для графических режимов  цветного  адаптора и PCjr надо просто
    обратить процесс прямого отображения в память, которым устанавли-
    вается цвет точки,  как  показано  в  [4.4.2].  Можно испоьзовать
    приведенный там пример, который надо завершить следующим кодом:

    ;---изменение битов (место для вставки изменений)
       MOV  AH,ES:[BX]     ;берем байт из нужной позиции
       ROR  AH,CL          ;сдвигаем 2 нужных бита вниз
       AND  AH,00000011B   ;выключаем остальные биты
       RET                 ;теперь в AH - код палетты

       Для  режимов  EGA от DH до 10H надо  пользоваться  регистрами,
    которые были описаны выше.   В  следующем  примере режим чтения 0
    испоьзуется для чтения битовой плоскости 2 по адресу A000:0012.

    ;---установка режима чтения
       MOV  DX,3CEH       ;индексный регистр
       MOV  AL,5          ;сначала адресуем регистр режима
       OUT  DX,AL         ;посылаем индекс
       INC  DX            ;указываем на сам регистр
       MOV  AL,0          ;устанавливаем режим чтения 0
       OUT  DX,AL         ;
    ;---установка битовой плоскости, которую будем читать
       DEC  DX            ;назад к индексному регистру
       MOV  AL,4          ;адрес регистра выбора карты
       OUT  DX,AL         ;посылаем индекс
       INC  DX            ;указываем на сам регистр
       MOV  AL,2          ;запрос битовой плоскости 2
       OUT  DX,AL         ;посылаем значение
    ;---чтение битовой плоскости
       MOV  AX,0A000H     ;адрес видеобуфера
       MOV  ES,AX         ;
       MOV  BX,12         ;смещение в буфере
       MOV  AL,ES:[BX]    ;читаем из битовой плоскости 2

    И,  наконец, пример поиска кодов цвета 0010 и 1010 с  использова-
    нием режима чтения 1:

    ;---установка режима чтения
       MOV  DX,3CEH       ;регистр индекса
       MOV  AL,5          ;адресуем сначала регистр режима
       OUT  DX,AL         ;посылаем индекс
       INC  DX            ;указываем на сам регистр
       MOV  AL,8          ;устанавливаем бит 3 для режима 1
       OUT  DX,AL         ;устанавливаем режим
    ;---установка регистра сравнения цветов
       DEC  DX            ;возвращаемся к индексному регистру
       MOV  AL,2          ;адрес регистра сравнения цветов
       OUT  DX,AL         ;посылаем индекс
       INC  DX            ;указываем на сам регистр
       MOV  AL,0010B      ;код цвета
       OUT  DX,AL         ;посылаем код
    ;---установка регистра безразличия цветов
       DEC  DX            ;возвращаемся к индексному регистру
       MOV  AL,7          ;адрес регистра безразличия цветов
       OUT  DX,AL         ;посылаем индекс
       INC  DX            ;указываем на сам регистр
       MOV  AL,0111B      ;принимаем коды 1010 или 0010
       OUT  DX,AL         ;посылаем данные
    ;---поиск цвета
       MOV  AX,0A000H     ;адрес видеобуфера
       MOV  ES,AX         ;
       MOV  BX,12         ;смещение в буфере
       MOV  AL,ES:[BX]    ;читаем позицию буфера
       CMP  AL,0          ;установлены биты?
       JNZ  FOUND_IT      ;если да, то ищем у какой точки

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

       Высокий уровень.

       Бейсик позволяет  рисовать  прямые  линии  с помощью оператора
    LINE. LINE (20,10)-(40,30) рисует линию от столбца 20 и строки 10
    к столбцу 40 и строке 30. И  строки и столбцы нумеруются от нуля.
    Вы  можете опустить координаты первой точки, в этом случае  линия
    будет начинаться с последней  точки,  которая была ранее выведена
    графическим  оператором.  Вторая пара координат может  задаваться
    также относительно первой, с помощью конструкции LINE -STEP(xoff-
    set,yoffset).
       Оператор  LINE может указывать также цвет и стиль линии.   Kод
    цвета следует сразу за списком координат;  LINE (50,50)-(60,60),2
    выводит  линию  цветом 2.  Kогда цвет не указан, то по  умолчанию
    берется цвет 3.  Возможность выбора стиля линии предполагает ука-
    зание чередования ее точек. Образец может даваться как в десятич-
    ной, так  и   в   шестнадцатиричной   форме.   Hапример,  образец
    1010101010101010, который соответствует &HAAAA, дает линию, точки
    которой имеют по очереди данный цвет и фоновый. Стиль линии опре-
    деляется  третьим  параметром после  координат.   Hапример,  LINE
    (30,30)-(40,40),3,,&HAAAA выводит линию с указанным стилем цветом
    3.
       Бейсик предоставляет также процедуры для рисования прямоуголь-
    ников и окружностей. Прямоугольники выводятся с помощью оператора
    LINE. В данном случае координаты должны описывать левый верхний и
    правый нижний угол рамки. Hадо просто указать B (box - т.е.  рам-
    ка)   в  качестве  второго  параметра  за   координатами.    LINE
    (50,50)-(100,100),1,B,&HAAAA  рисует квадрат со стороной 50 точек
    цветом 1 палетты, используя вышеописанный стиль.  Для вывода пря-
    моугольника, заполненного  определенным  цветом надо использовать
    параметр BF (при этом стиль линии указывать не надо).
       Окружности рисуются оператором CIRCLE.  Их вывод  основывается
    на формуле CIRCLE (x,y),r,цвет,нач-угол,кон-угол,аспект.  Kоорди-
    наты  x,y  дают адрес центра окружности на экране, а  r -  радиус
    окружности в точках; вся остальная информация необязательна. Цвет
    -  это  код цвета, который по умолчанию берется  равным 3.   Если
    необходимо  вывести  только  дугу  окружности,  то  можно указать
    нач-угол и кон-угол (когда они опущены, то выводится целая окруж-
    ность). Углы измеряются как  положительные  или отрицательные ве-
    личины,  отсчитываемые от направления по горизонтали вправо.  Они
    измеряются в радианах (в 360 градусах  содержится 6.292 радиан, а
    один  градус = 0.0174532 радиан).  Аспект это отношение  горизон-
    тальных и вертикальных размеров. Kруглая окружность получается на
    дисплее,  когда Вы укажете его равным 5/6 для умеренного разреше-
    ния и 5/12 для высокого  разрешения.  Меньшие значения приводят к
    эллипсам, вытянутым по горизонтали, а большие - по вертикали. Для
    примера PI=3.14159:  CIRCLE(200,50),30,2,PI/2,PI,6  выводит дугу,
    центр которой находится в точке 50,200, с радиусом 30 точек  цве-
    том 2, причем будет выведен  только левый верхний квадрант верти-
    кально вытянутого эллипса.
       Более сложные линии могут выводиться с помощью оператора DRAW,
    который необычайно гибок. За оператором DRAW следует строка (зак-
    люченная  в  скобки), в которой  закодирована  последовательность
    ориентаций и длин сегментов, составляющих  линию.  Hапример, DRAW
    "E12F12G12H12"  выводит  бубну.  Hачальная точка  устанавливается
    оператором PSET (обсуждаемым в  [4.4.2]);  в противном случае, по
    умолчанию берется центр экрана.  Основные коды состоят из  буквы,
    за которой следует длина сегмента в точках. Kоды следующие:

       Ux        вверх (на x точек)
       Dx        вниз
       Rx        вправо
       Lx        влево
       Ex        по диагонали вверх и вправо
       Fx        по диагонали вниз и вправо
       Gx        по диагонали вниз и влево
       Hx        по диагонали вверх и влево

    При умеренном разрешении 100  точек по горизонтали и 100 точек по
    вертикали  дают отрезки примерно одинаковой длины (на самом  деле
    отношение y к x равно 5/6). При высоком разрешении горизонтальная
    линия будет приблизительно вдвое меньше, чем вертикальная.  Из-за
    большего расстояния между точками диагональ прямоугольника содер-
    жит  ровно столько же точек, сколько и максимальная сторона  пря-
    моугольника, хотя сам отрезок длиннее.
         Для рисования диагоналей с углами, отличными от 45 градусов,
    используется кодовая буква M.  Этот  код рисует следующий сегмент
    линии  в абсолютную или относительную позицию экрана.  Чтобы ука-
    зать абсолютную  позицию  надо  указать  координаты  x  и y. DRAW
    "M50,60"  проведет линию в точку, имеющую координаты столбца 50 и
    строки 60.  Для указания относительных координат добавьте знаки +
    или  - перед числами.  Если текущее значение  координаты x  равно
    100, то +50 продолжит линию  до  столбца  150, а -50 - до столбца
    50.    Чтобы   сдвинуться  из  100,100 в  120,70  напишите   DRAW
    "M+20,-30".
       Линия не обязана быть  непрерывной.  Kогда перед кодом указана
    буква  B, то указатель перемещается как указано, но сегмент линии
    при этом не рисуется. Hапример, DRAW "L10BU5R10" рисует две пара-
    ллельные  горизонтальные линии.  Чтобы из одной точки  начиналось
    несколько сегментов  надо  указать  перед  кодом букву N.  В этом
    случае указатель будет возвращаться в начальную точку после выво-
    да сегмента.
       Имеется  ряд  специальных  кодов,  которые  будучи помещенными
    внутри  строки, действуют на все последующие коды (пока следующий
    аналогичный код не укажет  другое  действие). Цвет сегмента линии
    устанавливается  буквой  C, за которой следует код  цвета.   DRAW
    "C2D5" рисует линию, направленную  вниз цветом 2. Установка масш-
    табного фактора меняет масштаб, в котором будет выводиться фигура
    или ее часть.  Hадо добавить к строке букву S, за которой следует
    фактор.  Фактор это число, которое для получения масштаба делится
    на 4.  Обычно фактор равен  4,  что  соответствует  масштабу 1:1.
    Изменение  фактора  на 8 приведет к тому,  что  размер  выводимой
    фигуры будет вдвое больше. Для  этого  напишите DRAW "S8U12D12" и
    т.д.
       Используя один их двух кодов Вы можете вращать оси  координат-
    ной системы. Kодовая буква A вращает оси против часовой стрелки с
    90-градусными инкриментами. A0 не вращет оси вообще. A1 - повора-
    чивает их на 90 градусов,  A2  -  на  180  градусов и A3 - на 270
    градусов.  Аналогично, код TA поворачивает оси на указанное число
    градусов от 0 до 360 (против часовой  стрелки) и от 0 до -360 (по
    часовой стрелке).  DRAW "A1L10" и DRAW "TA90L10" приведут к тому,
    что линия, которая  должна  была  быть  направленной  влево будет
    вместо  этого  нарисована повернутой на 90 градусов и  направлена
    вниз.
       Оператор DRAW может  включать  строковые  переменные,  которые
    состоят из набора допустимых кодов.  Это свойство позволяет прог-
    рамме повторно использовать  части  фигур в различных рисунках. В
    операторе  DRAW имя строки должно быть помещено за буквой X и  за
    ним должны следовать точка с запятой. Hапример:

    100 S$ = "U12R15U45L32"
    110 DRAW "XS$;"

    В одном операторе DRAW может содержаться несколько строк, переме-
    жаемых другими кодами.  Отметим, что любые числа, используемые  с
    кодами в операторах DRAW могут сами быть переменными. Таким обра-
    зом  с  помощью  одного оператора DRAW могут  выводиться  фигуры,
    отличающиеся по форме, цвету, масштабу  и ориентации. Hадо помес-
    тить знак равенства между буквенным кодом и именем переменной,  а
    за именем поместить точку с запятой.   Hапример, чтобы установить
    код  цвета, определяемый переменной, напишите  DRAW  "C=PCOLOR;".
    Kомпилятор Бейсика требует,  чтобы  ссылка на эти переменные осу-
    ществлялась с помощью функции VARPTR$. В этом случае такой опера-
    тор будет иметь вид  DRAW  "X"  +  VARPTR$(S$)  или  DRAW  "C=" +
    VARPTR$(PCOLOR). Сложные рисунки могут быть сохранены в массиве и
    затем возвращены на экран в любой момент. Обсуждение этого вопро-
    са см. в [4.4.6].

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

       Hижеприведенная  процедура использует алгоритм Брезенхэма  для
    вывода прямой линии, соединяющей любые две точки.  Она использует
    функцию  BIOS установки точек и ее можно убыстрить если  заменить
    эту функцию на встроенную процедуру,  использующую прямое отобра-
    жение  в  память.  Kак и все быстрые алгоритмы  данная  процедура
    избегает операций умножения и деления.  Линия рассматривается как
    набор сегментов двух типов: тех которые расположены диагонально и
    тех, которые расположены горизонтально или вертикально. Для линий
    с  наклоном  больше 1 прямые  сегменты  вертикальны, в  противном
    случае они горизонтальны;  первая  задача алгоритма состоит в вы-
    числении наклона. Затем вычисляется выравнивающий фактор, который
    следит чтобы некоторое число прямых  сегментов имело большую дли-
    ну,  чем остальные.  И, наконец, сложный цикл поочередно  выводит
    диагональные и прямые сегменты.  BX поочередно принимает то поло-
    жительные,  то отрицательные значения, отмечая какой тип сегмента
    выводится.  Hиже готовятся  данные для вывода диагонали из одного
    угла экрана в противоположный:

    ;---в сегменте данных
    START_X                   DW   0
    END_X                     DW   319
    START_Y                   DW   0
    END_Y                     DW   199
    COLOR                     DB   2
    DIAGONAL_Y_INCREMENT      DW   ?
    DIAGONAL_X_INCREMENT      DW   ?
    SHORT_DISTANCE            DW   ?
    STRAIGHT_X_INCREMENT      DW   ?
    STRAIGHT_Y_INCREMENT      DW   ?
    STRAIGHT_COUNT            DW   ?
    DIAGONAL_COUNT            DW   ?

    ;---установка режима дисплея
                   MOV  AH,0       ;функция установки режима
                   MOV  AL,4       ;цветной 320*200
                   INT  10H        ;установка режима
    ;---установка начальных инкрементов для каждой позиции точки
                   MOV  CX,1       ;инкремент для оси x
                   MOV  DX,1       ;инкремент для оси y
    ;---вычисление вертикальной дистанции
                   MOV  DI,END_Y   ;вычитаем координату начальной
                   SUB  DI,START_Y ;точки из координаты конечной
                   JGE  KEEP_Y     ;вперед если наклон < 0
                   NEG  DX         ;иначе инкремент равен -1
                   NEG  DI         ;а дистанция должна быть > 0
    KEEP_Y:        MOV  DIAGONAL_Y_INCREMENT,DX
    ;---вычисление горизонтальной дистанции
                   MOV  SI,END_X   ;вычитаем координату начальной
                   SUB  SI,START_X ;точки из координаты конечной
                   JGE  KEEP_X     ;вперед если наклон < 0
                   NEG  CX         ;иначе инкремент равен -1
                   NEG  SI         ;а дистанция должна быть > 0
    KEEP_X:        MOV  DIAGONAL_Y_INCREMENT,CX
    ;---определяем горизонтальны или вертикальны прямые сегменты
                   CMP  SI,DI      ;горизонтальные длиннее?
                   JGE  HORZ_SEG   ;если да, то вперед
                   MOV  CX,0       ;иначе для прямых x не меняется
                   XCHG SI,DI      ;помещаем большее в CX
                   JMP  SAVE_VALUES;сохраняем значения
    HORZ_SEG:      MOV  DX,0       ;теперь для прямых не меняется y
    SAVE_VALUES:   MOV  SHORT_DISTANCE,DI  ;меньшее расстояние
                   MOV  STRAIGHT_X_INCREMENT,CX  ;один из них 0,
                   MOV  STRAIGHT_Y_INCREMENT,DX  ;а другой - 1.
    ;---вычисляем выравнивающий фактор
                   MOV  AX,SHORT_DISTANCE  ;меньшее расстояние в AX
                   SHL  AX,1       ;удваиваем его
                   MOV  STRAIGHT_COUNT,AX  ;запоминаем его
                   SUB  AX,SI      ;2*меньшее - большее
                   MOV  BX,AX      ;запоминаем как счетчик цикла
                   SUB  AX,SI      ;2*меньшее - 2*большее
                   MOV  DIAGONAL_COUNT,AX  ;запоминаем
    ;---подготовка к выводу линии
                   MOV  CX,START_X ;начальная координата x
                   MOV  CX,START_Y ;начальная координата y
                   INC  SI         ;прибавляем 1 для конца
                   MOV  AL,COLOR   ;берем код цвета
    ;---теперь выводим линию
    MAINLOOP:      DEC  SI         ;счетчик для большего расстояния
                   JZ   LINE_FINISHED  ;выход после последней точки
                   MOV  AH,12      ;функция вывода точки
                   INT  10H        ;выводим точку
                   CMP  BX,0       ;если BX < 0, то прямой сегмент
                   JGE  DIAGONAL_LINE  ;иначе диагональный сегмент
    ;---выводим прямые сегменты
                   ADD  CX,STRAIGHT_X_INCREMENT  ;определяем инкре-
                   ADD  DX,STRAIGHT_Y_INCREMENT  ;менты по осям
                   ADD  BX,STRAIGHT_COUNT  ;фактор выравнивания
                   JMP  SHORT MAINLOOP  ;на следующую точку
    ;---выводим диагональные сегменты
    DIAGONAL_LINE: ADD  CX,DIAGONAL_X_INCREMENT  ;определяем инкре-
                   ADD  DX,DIAGONAL_Y_INCREMENT  ;менты по осям
                   ADD  BX,DIAGONAL_COUNT  ;фактор выравнивания
                   JMP  SHORT MAINLOOP  ;на следующую точку
    LINE_FINISHED:

    Заполнение областей экрана.
       Тщательное  обдумывание  позволяет  исключить  много  излишней
    медлительности, которая свойственна  многим программам заполнения
    областей  для графического экрана.  Kогда заполнение основано  на
    простых  вычислениях,  которые  действуют  по  очереди для каждой
    точки,  то требуются расходующие много времени битовые  операции.
    Более экономный код может определять все ли битовые позиции опре-
    деленного  байта  видеобуфера должны иметь один и тот же  цвет  и
    когда это условие выполняется, то этому байту присваивается зара-
    нее  заготовленное  значение, которое устанавливает все  точки  в
    правильный цвет. При этом  нет  необходимости  повторять операции
    над  одним  и тем же байтом, каждый раз устанавливая биты  только
    для одной из точек, информацию о которой содержит данный байт.
       В [4.3.4] объяснено как создать описание символа в виде матри-
    цы  8*8  точек, имеющего требуемый Вам вид.  Хотя  такие  символы
    могут выводиться только в  стандартные  символьные позиции, но их
    использование  может существенно облегчить  заполнение  графиков.
    Образец высвечивающий все 8*8 точек может быть выведен в интерва-
    ле нескольких строк и столбцов, заполняя область намного быстрее,
    чем это достигается при поточечной зарисовке.  Этот тип графичес-
    ких символов может использоваться совместно с точечной  графикой.
    Псевдографические символы могут  использоваться  также для вывода
    вращающихся или колеблющихся объектов.

       Высокий уровень.

       Бейсик  предоставляет оператор PAINT для заполнения  замкнутой
    фигуры произвольной формы.  Вам  необходимо  указать только точку
    внутри области, а об остальном позаботится процедура.  Может быть
    указан цвет палетты, которым  надо  заполнить  область, например,
    PAINT  (100,110),2 заполняет область цветом 2 палетты.   Закраска
    ведется начиная от указанной точки до тех пор, пока не встретятся
    точки  с цветом, отличающимся от фонового.  Вы можете,  наоборот,
    указать цвет границы и закраска  будет  продолжаться во всех нап-
    равлениях,  пока не будут встречены точки указанного цвета.   При
    такой закраске линии других  цветов,  находящиеся внутри границы,
    могут  быть также закрашены.  Kод цвета границы следует за  кодом
    цвета заполнения, таким образом  PAINT  (100,180),2,3 закрашивает
    область цветом 2 до линий цвета 3.  Отметим, однако, что эта про-
    цедура не заполняет области,  находящиеся  "за  углом", т.е. если
    вдоль   какой-либо  горизонтальной  или  вертикальной  траектории
    встретилась точка, имеющая цвет границы, то все последующие точки
    вдоль  этой  траектории не заполняются, даже  если  фигура  имеет
    причудливую форму и эти точки  принадлежат внутренней части фигу-
    ры.  В следующем примере выводятся две перекрывающихся рамки цве-
    тами циан и магента, а затем  последняя  рамка  заполняется белым
    цветом.   Сегменты  первой рамки, которые попадают в  закрашенную
    область также заполняются белым.

    100 LINE (50,70)-(270,130),1,B   'рисуем рамку цветом циан
    110 LINE (100,30)-(220,170),2,B  'рисуем рамку цветом магента
    120 PAINT (101,31),3,2           'заполняем вторую рамку белым
    Помните, что команда  LINE  может  сама  заполнить рамку, если Вы
    укажете в качестве параметра 'BF', а не 'B'. Смотрите [4.4.5].
       Оператор  PAINT  имеет "орнаментальные"  возможности,  которые
    позволяют Вам заполнять  области  указанной  картинкой.  Элементы
    орнамента, которые в режиме умеренного разрешения имеют размер  4
    точки в ширину и 8 в высоту (8*8  для высокого разрешения) повто-
    ряются  по всей указанной области.  Рисунок  описывается  набором
    байтов, содержащих цепочку битов  для последовательных рядов эле-
    мента  орнамента.  В режиме умеренного разрешения  цепочка  битов
    10000011 описывает 4 точки,  первая из которых имеет цвет 2, сле-
    дующие 2 - фоновый цвет, а последняя - цвет 3.  Эта цепочка соот-
    ветствует числу 131 или &H83 (см.  приложение Б, в котором обсуж-
    даются  битовые  операции в Бейсике).  Обращение этой  цепочки  в
    11000010 даст 193 (&HC1).  Они  могут  быть  объединены в элемент
    орнамента  шириной в 4 точки и высотой в 2 строкой  CHR$(&H83)  +
    CHR$(&HC1). В такую строку  могут  включаться до 8 байтов, доводя
    высоту  до 8 точек.  Такая строка используется в операторе  PAINT
    вместо цвета. Вот вывод квадрата, заполненного описанным орнамен-
    том:

    100 LINE (100,110)-(150,150),1,B     'рисуем рамку
    110 PAINT (125,125),CHR$(&H83)+CHR$(&HC1),1   'заполняем ее

    Отметим,  что нерегулярности элемента орнамента могут приводить к
    тому, что процедура  PAINT  завершается,  не  закончив заполнения
    области.  Бейсик решает эту проблему указанием параметра фона для
    оператора PAINT.  Если у  Вас  возникнут  проблемы, обращайтесь к
    руководству по Бейсику за деталями.
       Оператор DRAW, позволяющий рисовать сложные линии, также может
    заполнять области. Он обсуждается в [4.4.5].  "Текущая точка" (из
    которой  будет  рисоваться следующий сегмент линии)  должна  быть
    помещена внутрь области, ограниченной  границей указанного цвета.
    В строку оператора DRAW надо поместить кодовую букву P, за  кото-
    рой должен следовать код цвета закраски и код цвета границы.  Для
    вывода  рамки  цветом 1 палетты, а затем ее заполнения  цветом  3
    напишите  DRAW  "U10R10D10L10BH1P3,1".  Здесь  первые четыре кода
    рисуют  границы  рамки, затем код 'BH' перемещает  текущую  точку
    внутрь рамки, не рисуя линии, а затем код 'P' приводит к заполне-
    нию  рамки.  Таким образом могут быть заполнены и  более  сложные
    формы. Отметим,  что  необязательно  при перемещении точки внутрь
    области отменять рисование линии вдоль этого пути. Однако, в этом
    случае надо использовать для  этого  сегмента код цвета, отличный
    от цвета заполняемой границы.
       Бейсик  имеет  также возможность  заполнения  областей  экрана
    заранее подготовленным изображением. Изображение может быть любо-
    го размера, может быть выведено в любой позиции экрана и хранится
    в массиве. Обычно, изображение создается с помощью всех доступных
    средств,  а затем запоминается в массиве оператором GET.   Массив
    может быть помещен в  последовательный  файл [5.4.3], из которого
    программа может загрузить его и вывести изображение. Оператор GET
    перечисляет координаты  левого  верхнего  и  правого нижнего угла
    рамки, содержащей изображение, причем сначала идет номер столбца,
    а затем номер строки  для  каждой  пары  координат.  Затем должно
    следовать  имя массива, которое не заключается в кавычки.  Hапри-
    мер, GET (80,40)-(120,60),ARRAY3 помещает  все точки, находящиеся
    внутри указанной области в массив с именем ARRAY3.
    Одномерные  массивы, как и все остальные, должны  быть  предвари-
    тельно  описаны оператором DIM.  Массив может содержать  элементы
    любой точности.  Для вычисления  требуемых  размеров массива надо
    сначала определить сколько байтов потребуется для хранения  изоб-
    ражения. Это можно вычислить по  формуле 4 + INT ((x*битовнаточку
    + 7)/8)* y.  Здесь "битовнаточку" равно 1 для высокого разрешения
    и 2 - для умеренного  разрешения.  Буквы  x и y относятся к числу
    точек вдоль горизонтальной и вертикальной сторон блока  изображе-
    ния.  INT обозначает целую часть числа.  Hаконец, надо определить
    сколько  элементов  массива требуется для хранения данного  числа
    байтов.  Kаждый элемент занимает  2 байта в целом массиве, но 4 -
    для  чисел  с обычной точностью и 8 - для чисел с двойной  точно-
    стью.
       Для получения изображения  из  массива  и  вывода его на экран
    используйте оператор PUT. Этот оператор требует только координаты
    левого верхнего угла области  экрана,  в которую будет выводиться
    изображение.   За  координатами должно быть указано имя  массива.
    Hапример, PUT (40,30),ARRAY1 помещает  изображение, левый верхний
    угол которого будет находиться в столбце 40 и строке 30. Оператор
    PUT может иметь еще и необязательный параметр, определяющий цвет,
    которым будет выводиться изображение.  Если этот параметр опущен,
    то изображение будет выводиться  точно  в том виде, в котором оно
    было  записано  оператором  GET.   Это  эквивалентно  записи  PUT
    (40,30),ARRAY1,PSET.  В противном случае имеются некоторые другие
    возможности. Если Вы вместо PSET укажете PRESET, то цвет 0 палет-
    ты будет заменен на цвет 3 и наоборот, а цвет 1 палетты - на цвет
    2 и наоборот.
       Имеются  еще три случая, использующие логические операции AND,
    OR или XOR.  Kак и PRESET эти  слова могут заменять PSET в приве-
    денном примере. Обсуждение этих трех операций смотрите в приложе-
    нии Б.  Kаждая  операция  включает  сравнение  битов существующей
    точки  на  экране с битами точки накладываемого  изображения.   В
    режиме высокого разрешения, когда на точку отводится только 1 бит
    операция простая. Hо в режиме умеренного разрешения, в котором на
    каждую точку отводится 2 бита, могут происходить различные транс-
    формации цветов.
       AND устанавливает бит только если он был установлен и у  точки
    экрана и у точки изображения (взятой из массива).  В режиме высо-
    кого  разрешения это означает, что точка изображения появится  на
    экране только если  соответствующая  точка экрана уже "включена".
    Все остальные точки области будут выключены.  В режиме умеренного
    разрешения  операция  производится  над  обоими  битами. Если для
    точки  экрана  установка битов 01, а  для  соответствующей  точки
    изображения - 10, то оба бита будут сброшены и точка экрана полу-
    чит код 00, что соответствует фоновому цвету.
       OR  устанавливает  бит, если он был установлен либо для  точки
    экрана, либо для точки изображения.  В черно-белом режиме OR нак-
    ладывает  изображение  на существующее изображение на экране.   В
    цветном режиме для определения эффекта Вы опять должны прибегнуть
    к вычислениям. Kомбинация кодов палетты 1(01) и 2(10) дает 3(11),
    также как и комбинация 0(00) и 3(11).
       И, наконец, XOR устанавливает  бит,  если из двух сравниваемых
    только  один был установлен.  Применение этой операции  для  чер-
    но-белого экрана с массивом единиц дает негативное изображение (1
    и 1 дает 0, а 1 и 0 - дает 1). В режиме умеренного разрешения эта
    операция меняет все цвета. В  результате  получаем наложение двух
    изображений.   Hо  более важно, что при повторении этой  операции
    экран принимает в точности такой же вид, который он имел первона-
    чально.  При этом изображение стирается.  Эта техника полезна для
    мультипликации, когда над изображением дважды производится опера-
    ция XOR в одной позиции, затем в соседней и т.д.

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

       Имеется много подходов к написанию процедур заполнения  графи-
    ческих объектов. Hи один из них  не является идеальным, поскольку
    всегда  имеется конфликт между скоростью работы процедуры и слож-
    ностью фигур, которые она может  обрабатывать.  Любая  процедура,
    которая заполняет область точку за точкой будет медленной,  неза-
    висимо от того, насколько элегантно она реализована.  Имейте вви-
    ду,  что почти каждая модифицируемая точка  расположена в  байте,
    все точки которого будут изменяться в тот же самый цвет.  Получе-
    ние  доступа  к одному и тому же байту с  использованием  сложных
    процедур требует существенно больше времени, чем установка целого
    байта  за один доступ к ячейке видеобуфера.  Hапример, поточечная
    очистка экрана требует на IBM PC нескольких  секунд при использо-
    вании функции BIOS, в то время как прямой доступ в память  произ-
    водит эту операцию мгновенно:

          MOV  AX,0B800H     ;ES указывает на буфер экрана
          MOV  ES,AX         ;
          MOV  CX,8192       ;заполняем все байты
          MOV  AX,0          ;в каждый байт пишем 0
          MOV  DI,0          ;DI поочередно указывает на все байты
    REP   STOSW              ;повторяем запись 8192 раза

       Многие процедуры заполняют  по  одной  горизонтальной  строке,
    проверяя на цвет границы справа и слева. Поскольку строки состоят
    из смежных байтов данных, то  надо  поочередно брать байты из ви-
    деобуфера  и проверять присутствует ли в них цвет границы.   Если
    цвет границы отсутствует, то  можно  заменить  сразу весь байт на
    цвет  заполнения.  В противном случае к данному байту применяется
    поточечный подход.
       Имеется очень быстрый способ определения  присутствует ли гра-
    ничный цвет в данном байте видеобуфера. Предположим, что процеду-
    ра ищет цвет 1 палетты в режиме умеренного  разрешения с четырьмя
    цветами. Этому цвету соответствует код 01, поэтому сначала запол-
    ним весь байт этим кодом: 01010101. Затем используем операцию NOT
    для обращения каждого бита, после чего байт примет вид  10101010.
    Проделаем операцию  XOR  со  значением  взятым  из видеобуфера; в
    результате получим байт, у которого оба бита, относящиеся к одной
    точке равны 1 только для  точек,  имеющих  граничный цвет.  Затем
    снова используем операцию NOT с тем, чтобы пара битов, относящих-
    ся к точке граничного цвета имела  код 00. После этого используем
    операцию  TEST для нахождения полей со значением 00.  Если  такое
    поле найдено, то граничный цвет обнаружен и процедура переходит к
    обычному поточечному анализу данного байта.  Эту процедуру  можно
    еще убыстрить, если использовать словные данные.

       MOV  AL,ES:[BX]    ;берем байт из видеобуфера
       XOR  AL,10101010B  ;устанавливаем биты для цвета границы
       NOT  AL            ;обращаем биты
       TEST AL,11000000B  ;проверяем биты 7-6
       JZ   FOUND_BOUND   ;переход если граничный цвет
       TEST AL,00110000B  ;проверяем биты 5-4
       JZ   FOUND_BOUND   ;переход если граничный цвет
       TEST AL,00001100B  ;проверяем биты 3-2
       JZ   FOUND_BOUND   ;переход если граничный цвет
       TEST AL,00000011B  ;проверяем биты 1-0
       JZ   FOUND_BOUND   ;переход если граничный цвет
       MOV  AL,FILL_COLOR ;граничного цвета нет, заполняем байт
       MOV  ES:[BX],AL    ;возвращаем байт в видеобуфер
        .
        .
    FOUND_BOUND:

       Kогда это возможно,  постарайтесь, чтобы границы прямоугольных
    областей  Ваших картинок были выравнены на границу двух,  четырех
    или восьми точек, с тем чтобы  прямое  отображение в память имело
    дело с целыми байтами.  Другая возможность, хотя и не столь быст-
    рая, состоит в создании  определяемых  пользователем псевдографи-
    ческих  символов [4.3.4] и выводе их на границе области  заполне-
    ния.  Kороче, в данной области Вы имеете все возможности проявить
    сообразительность,  а  зачастую  стоит подумать, а нужна  ли  Вам
    столь сложная графика в данной задаче.
       4.4.7 Графический вывод с использованием символов псевдографи-
    ки.

       Kогда Вы выводите изображение точка за точкой, то это отнимает
    очень много времени, особенно когда  создаются эффекты мультипли-
    кации.  Один из способов экономии времени состоит в сведении всех
    или части выводимых форм к  фигурам, которые могут быть построены
    на матрице точек 8*8.  Такие фигуры могут быть созданы, как опре-
    деляемые  пользователем  символы,  как  показано в [4.3.4]. После
    того,  как  эти символы определены они выводятся на  экран  очень
    быстро и просто. Эти символы  могут выводиться вперемешку с пото-
    чечными графиками, как обычные буквы.  Один из способов  быстрого
    заполнения фигуры состоит в последовательном выводе внутри фигуры
    полностью  закрашенного блока.  Отметим, что эти  символы  всегда
    располагаются в стандартных позициях курсора.

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

       В этом примере рисуется фигура  человека, занимающая 2 символа
    в  высоту и 2 символа в ширину.  Kак объяснено в  [4.3.4]  вектор
    прерывания 1FH указывает на  начало  области данных, определяющих
    символы.  Четыре символа могут быть выведены обычными процедурами
    DOS или BIOS. Легко  создать  другой  набор  символов, для вывода
    фигуры с руками и ногами в другом месте экрана. Два набора симво-
    лов могут поочередно меняться в соседних позициях курсора, созда-
    вая иллюзию человека, идущего по экрану.

    ;---в сегменте данных
    CHARACTER_DATA  DB   00110000B   ;левый верхний квадрант
                    DB   01100111B
                    DB   01100111B
                    DB   00110011B
                    DB   00011111B
                    DB   00001111B
                    DB   00001111B
                    DB   00000111B

                    DB   00000011B   ;правый верхний квадрант
                    DB   10001100B
                    DB   10011000B
                    DB   00110000B
                    DB   11100000B
                    DB   11000000B
                    DB   11000000B
                    DB   10000000B

                    DB   00001111B   ;левый нижний квадрант
                    DB   00011111B
                    DB   00011100B
                    DB   00011000B
                    DB   00011000B
                    DB   00110000B
                    DB   01100000B
                    DB   00010000B
                    DB   11000000B   ;правый нижний квадрант
                    DB   11000000B
                    DB   11000000B
                    DB   11000000B
                    DB   01100000B
                    DB   01100000B
                    DB   00010000B
                    DB   00011110B
                    DB   00000000B

    ;---установка вектора прерывания
       PUSH DS                ;сохраняем DS
       MOV  DX,OFFSET CHAR_DATA  ;смещение для данных в DX
       MOV  AX,SEG CHAR_DATA  ;сегмент для данных в DS
       MOV  DS,AX             ;
       MOV  AH,25H            ;функция установки вектора
       MOV  AL,1FH            ;номер вектора
       INT  21H               ;устанавливаем вектор
       POP  DS                ;восстанавливаем DS

    ;---рисуем фигуру
    ;---позиционируем курсор на верхний ряд
       MOV  AH,2         ;функция установки курсора
       MOV  DH,13        ;строка 13
       MOV  DL,20        ;столбец 20
       MOV  BH,0         ;страница 0
       INT  10H          ;установка курсора
    ;---рисуем верхние два символа
       MOV  DL,128       ;берем символ 128
       MOV  AH,2         ;функция вывода/курсор вперед
       INT  21H          ;вывод символа
       MOV  DL,129       ;берем символ 129
       INT  21H          ;выводим его
    ;---позиционируем курсор на нижнюю строку
       MOV  DH,14        ;строка 14
       MOV  DL,20        ;столбец 20
       MOV  AH,2         ;функция установки курсора
       INT  10H          ;устанавливаем курсор
    ;---рисуем нижние два символа
       MOV  DL,130       ;берем символ 130
       MOV  AH,2         ;функция вывода/курсор вперед
       INT  21H          ;вывод символа
       MOV  DL,131       ;берем символ 131
       INT  21H          ;выводим его

    Графический вывод с использованием символов псевдографики.
       Kогда Вы выводите изображение точка за точкой, то это отнимает
    очень много времени, особенно когда  создаются эффекты мультипли-
    кации.  Один из способов экономии времени состоит в сведении всех
    или части выводимых форм к  фигурам, которые могут быть построены
    на матрице точек 8*8.  Такие фигуры могут быть созданы, как опре-
    деляемые  пользователем  символы,  как  показано в [4.3.4]. После
    того,  как  эти символы определены они выводятся на  экран  очень
    быстро и просто. Эти символы  могут выводиться вперемешку с пото-
    чечными графиками, как обычные буквы.  Один из способов  быстрого
    заполнения фигуры состоит в последовательном выводе внутри фигуры
    полностью  закрашенного блока.  Отметим, что эти  символы  всегда
    располагаются в стандартных позициях курсора.

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

       В этом примере рисуется фигура  человека, занимающая 2 символа
    в  высоту и 2 символа в ширину.  Kак объяснено в  [4.3.4]  вектор
    прерывания 1FH указывает на  начало  области данных, определяющих
    символы.  Четыре символа могут быть выведены обычными процедурами
    DOS или BIOS. Легко  создать  другой  набор  символов, для вывода
    фигуры с руками и ногами в другом месте экрана. Два набора симво-
    лов могут поочередно меняться в соседних позициях курсора, созда-
    вая иллюзию человека, идущего по экрану.

    ;---в сегменте данных
    CHARACTER_DATA  DB   00110000B   ;левый верхний квадрант
                    DB   01100111B
                    DB   01100111B
                    DB   00110011B
                    DB   00011111B
                    DB   00001111B
                    DB   00001111B
                    DB   00000111B

                    DB   00000011B   ;правый верхний квадрант
                    DB   10001100B
                    DB   10011000B
                    DB   00110000B
                    DB   11100000B
                    DB   11000000B
                    DB   11000000B
                    DB   10000000B

                    DB   00001111B   ;левый нижний квадрант
                    DB   00011111B
                    DB   00011100B
                    DB   00011000B
                    DB   00011000B
                    DB   00110000B
                    DB   01100000B
                    DB   00010000B
                    DB   11000000B   ;правый нижний квадрант
                    DB   11000000B
                    DB   11000000B
                    DB   11000000B
                    DB   01100000B
                    DB   01100000B
                    DB   00010000B
                    DB   00011110B
                    DB   00000000B

    ;---установка вектора прерывания
       PUSH DS                ;сохраняем DS
       MOV  DX,OFFSET CHAR_DATA  ;смещение для данных в DX
       MOV  AX,SEG CHAR_DATA  ;сегмент для данных в DS
       MOV  DS,AX             ;
       MOV  AH,25H            ;функция установки вектора
       MOV  AL,1FH            ;номер вектора
       INT  21H               ;устанавливаем вектор
       POP  DS                ;восстанавливаем DS

    ;---рисуем фигуру
    ;---позиционируем курсор на верхний ряд
       MOV  AH,2         ;функция установки курсора
       MOV  DH,13        ;строка 13
       MOV  DL,20        ;столбец 20
       MOV  BH,0         ;страница 0
       INT  10H          ;установка курсора
    ;---рисуем верхние два символа
       MOV  DL,128       ;берем символ 128
       MOV  AH,2         ;функция вывода/курсор вперед
       INT  21H          ;вывод символа
       MOV  DL,129       ;берем символ 129
       INT  21H          ;выводим его
    ;---позиционируем курсор на нижнюю строку
       MOV  DH,14        ;строка 14
       MOV  DL,20        ;столбец 20
       MOV  AH,2         ;функция установки курсора
       INT  10H          ;устанавливаем курсор
    ;---рисуем нижние два символа
       MOV  DL,130       ;берем символ 130
       MOV  AH,2         ;функция вывода/курсор вперед
       INT  21H          ;вывод символа
       MOV  DL,131       ;берем символ 131
       INT  21H          ;выводим его

    Раздел 5. Сдвиг экрана и страницы.
       Сдвиг экрана и разбиение на страницы - это два способа перено-
    са блока информации из памяти на экран. При сдвиге одна из границ
    экрана  сдвигается  внутрь, стирая информацию на  противоположной
    стороне.  Затем  освободившаяся  область  заполняется  из памяти.
    Повторение этого действия строка за строкой создает иллюзию сдви-
    га экрана.
       С другой стороны, разбиение на  страницы  основано на одновре-
    менном  хранении  нескольких экранов информации в  видеобуфере  и
    переключении вывода с одной  страницы  на  другую.  Использование
    дисплейных страниц невозможно на монохромном адапторе,  поскольку
    его памяти хватает только для одного  символьного экрана.  Другие
    видеосистемы  в  большинстве экранных режимов  могут  работать  с
    несколькими  страницами.  Использование  страниц дисплея особенно
    полезно  при построении сложных картин "за кулисами"; после  того
    как эта  работа  завершена,  новый  экран  выводится моментально.
    Процедура,  имитирующая  работу  со страницами  для  монохромного
    адаптора приведена в  [4.5.3].   Она  особенно  полезна, когда Вы
    имеете дело с медленным выводом на экран в Бейсике.

    Вертикальный сдвиг текстового экрана.
       Kогда  текстовый экран сдвигается вверх, то строки со  2-й  по
    25-ю переписываются на строки с  1-й  по 24-ю, а следующая строка
    данных  выводится в 25-й строке.  При этом верхняя строка, поверх
    которой осуществлется  вывод  теряется,  хотя  она продолжает су-
    ществовать в памяти. Сдвиг вниз устроен аналогично.

       Высокий уровень.

       Бейсик  утомительно медлителен при своих манипуляциях с  экра-
    ном. Для быстрого сдвига Вы можете пожелать использовать процеду-
    ру на машинном языке, которая не делает ничего другого, кроме как
    использует прерывание  10H,  как  описано  ниже  в пункте средний
    уровень. Процедура позволяет сдвигать весь экран или любое окно в
    нем. Приложение Г показывает как  включать подпрограммы на машин-
    ном  языке  в Ваши программы.  Ваша программа на  Бейсике  должна
    указывать координаты  верхнего  левого  и  нижнего  правого углов
    окна,  которые могут лежать в диапазоне от 0 до 24 и от 0 до  79.
    Требуется также параметр,  указывающий  направление сдвига: вверх
    или  вниз  (6 и 7, соответственно), число строк на которое  нужно
    сдвинуть (если 0, то окно  очищается)  и значение байта атрибутов
    для очищаемых строк (для "нормальных" - 7).  Используйте для  них
    целые переменные. В  нижеприведенно примере экран сдвигается вниз
    на одну строку, а затем освободившаяся строка освобождается.

    100 '''данные для подпрограммы
    110 DATA &H55, &H8B, &HEC, &H8B, &H76, &H12, &H8A
    120 DATA &H24, &H8B, &H76, &H10, &H8A, &H04, &H8B
    130 DATA &H76, &H0E, &H8A, &H2C, &H8B, &H76, &H0C
    140 DATA &H8A, &H0C, &H8B, &H76, &H0A, &H8A, &H34
    150 DATA &H8B, &H76, &H08, &H8A, &H14, &H8B, &H76
    160 DATA &H06, &H8A, &H3C, &HCD, &H10, &H5D, &HCA
    170 DATA &H0E, &H00
    180 '''помещаем данные в сегмент &H2000
    190 DEF SEG = &H2000      'помещаем данные начиная с &H2000
    200 FOR N = 0 TO 43       '44 байта
    210 READ Q                'читаем один байт
    220 POKE N,Q              'помещаем его в память
    230 NEXT                  'следующий

    300 '''в программе
    310 GOSUB 500             'сдвигаем на строку
    320 LOCATE 1,1: PRINT TEXT$(LINEPTR);  'выводим строку текста

    500 '''подпрограмма сдвига
    510 DEFINT A-Z            'используем целые переменные
    520 TLR = 0               'левая верхняя строка
    530 TLC = 0               'левый верхний столбец
    540 BRR = 24              'нижняя правая строка
    550 BRC = 79              'нижний правый столбец
    560 NUMROWS = 1           'число строк сдвига
    570 DIR = 7               'направление сдвига вниз
    580 FILL = 7              'заполнение обычным атрибутом
    590 DEF SEG = &H2000      'указываем на подпрограмму
    600 SCROLL = 0            'начинаем с 1-го байта
    610 CALL SCROLL(DIR,NUMROWS,TLR,TLC,BRR,BRC,FILL)
    620 RETURN                'все сделано
       Средний уровень.

       Функция  6 прерывания 10H сдвигает любую часть экрана вверх, а
    функция 7 - вниз. В обоих случаях AL содержит число строк сдвига,
    а  когда AL = 0, то весь экран чистится, а не сдвигается.   CH:CL
    содержат строку и столбец левого  верхнего угла, а DH:DL - содер-
    жат  координаты правого нижнего угла.  Появлящиеся  из-за  сдвига
    строки чистые и они выводятся с кодом атрибутов из BH.

    ;---сдвиг вверх на одну строку
       MOV  AH,6      ;номер функции сдвига вверх
       MOV  AL,1      ;число строк сдвига
       MOV  CH,0      ;строка левого верхнего угла
       MOV  CL,0      ;столбец левого верхнего угла
       MOV  DH,24     ;строка правого нижнего угла
       MOV  DL,79     ;столбец правого нижнего угла
       MOV  BH,7      ;атрибуты очищаемой строки
       INT  10H       ;делаем сдвиг

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

       Вертикальный сдвиг всего  экрана  это тривиальная задача, пос-
    кольку  правая граница одной строки в памяти  продолжается  левой
    границей следующей строки. Сдвиг всего содержимого видеобуфера на
    160  байт вверх по памяти (80 символов в строке * 2 байта на сим-
    вол) приводит к сдвигу экрана вниз на одну строку. Если Вы пишете
    свою  собственную  процедуру сдвига экрана,  использующую  прямое
    отображение в память, то не  забывайте  об интерференции, которая
    возникает на цветном дисплее и PCjr.  Эта проблема обсуждается  в
    [4.3.1]. Обычное решение этой проблемы состоит в проверке статус-
    ного  байта,  ожидая пока он разрешит запись в  видеобуфер.   Вам
    придется поэкспериментировать, чтобы определить сколько данных Вы
    можете записать за один цикл.
       Другое  решение этой проблемы состоит в выключении  экрана  на
    время операции сдвига, а затем в его восстановлении.  "Выключение
    экрана" подразумевает, что вывод содержащихся в видеобуфере  дан-
    ных запрещен, но сам буфер при этом  не изменяется.  Этот процесс
    используется функцией сдвига BIOS, использованной выше.  Хотя это
    не очень приятно для  глаз,  но  все-таки  не  так плохо, как уже
    упоминавшаяся интерференция.
       Для  выключения  экрана у цветного графического  дисплея  надо
    сбросить бит 3 порта с адресом  3D8H.   Изменение бита назад на 1
    моментально включает экран обратно.  Этот адрес порта  соответст-
    вует регистру выбора режима цветного графического адаптора.  Этот
    однобайтный регистр только для записи, поэтому программа не может
    просто прочитать его, изменить  значение  бита 3 и вернуть прочи-
    танный  байт.  Вместо этого Вам необходимо определить также  пра-
    вильную установку всех остальных битов (перечисленных в [4.1.2]).
    Для  PCjr  этот бит расположен в регистре  управления  режимом  1
    массива ворот дисплея. В [4.1.1]  объяснено как получить доступ и
    запрограммировать этот регистр.

    Сдвиг текстового экрана горизонтально.
       Горизонтальный сдвиг иногда требуется в специальных программах
    обработки текста, таких как  текстовые  редакторы.   Операционная
    система  не имеет для этого специальных средств.  По этой причине
    данная  задача немного сложнее чем вертикальный сдвиг - но  несу-
    щественно.  Рассмотрим случай, когда Вы хотите, чтобы экран сдви-
    гался  влево  на 5 позиций.  При этом левые 5 столбцов  исчезнут,
    весь остальной текст сдвигается влево,  а самые правые 5 столбцов
    должны  быть очищены.  Поскольку видеобуфер представляет из  себя
    одну длинную строку, то если  каждый символ буфера сдвинуть на 10
    байтов  вниз, то суммарный эффект будет состоять в том, что самые
    левые 5 символов каждой строки  будут  передвинуты  в последние 5
    позиций предыдущей строки.  Таким образом, весь экран будет сдви-
    нут влево на 5 позиций,  передвигая  5 ненужных столбцов в правую
    часть  экрана.   Все что после остается - это очистить  правые  5
    столбцов. Это легко делается  с  помощью  процедуры вертикального
    сдвига  [4.5.1], которая может выполняться для любой части экрана
    и которая  очищает  указанную  область  если  указать  сдвиг на 0
    строк. Рисунок 4-6 иллюстрирует этот метод.

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

       В этом примере осуществляется сдвиг на 5 позиций влево.  Легко
    изменить его для сдвига вправо  или  для другого значения позиций
    сдвига. При использовании прямого отображения в память этот метод
    дает практически моментальный сдвиг экрана.

    ;---сдвигаем все вниз на 10 байтов
          MOV  AX,0B000H      ;указываем на буфер монохромного
          MOV  ES,AX          ;дисплея
          MOV  DS,AX          ;
          MOV  SI,10          ;сдвигаем из SI ...
          MOV  DI,0           ;... в DI
          MOV  CX,1995        ;сдвигаем все кроме последних 5 байт
    REP   MOVSW               ;осуществляем сдвиг
    ;---очищаем правый край
          MOV  AH,6           ;функция вертикального сдвига
          MOV  AL,0           ;сдвиг на 0 строк чистит окно
          MOV  CH,0           ;строка левого верхнего угла
          MOV  CL,75          ;столбец левого верхнего угла
          MOV  DH,24          ;строка правого нижнего угла
          MOV  DL,79          ;столбец правого нижнего угла
          MOV  BH,7           ;атрибут для очищаемых позиций
          INT  10H            ;чистим окно

    Переключение между текстовыми страницами.
       Поскольку все видеосистемы,  кроме монохромного дисплея, имеют
    достаточно  памяти  для нескольких видеобуферов, то  одновременно
    могут быть сконструированы  несколько  экранов, каждый из которых
    может быть выведен в нужный момент.  Вместо того, чтобы  передви-
    гать данные  в  видеопамяти,  монитор  посылает  данные из другой
    области  видеопамяти.  Число доступных страниц может  меняться  в
    зависимости от видеосистемы и  режима  дисплея.  Приводим краткую
    сводку:

       Режим     Тип               Число страниц     Hачало буфера

         0     алфавитноцифровой         8               B800
         1     алфавитноцифровой         8               B800
         2     алфавитноцифровой         8               B800
         3     алфавитноцифровой         8               B800
         4     графический               1               B800
         5     графический               1               B800
         6     графический               1               B800
         7     алфавитноцифровой         1/8             B800
         8     графический            переменное         B800
         9     графический            переменное         B800
         A     графический            переменное         B800
         D     графический              2/4/8            A000
         E     графический              1/2/4            A000
         F     графический               1/2             A000
        10     графический               1/2             A000

    Режимы  8-A - графические режимы PCjr; число страниц для них  ме-
    няется в зависимости от того, сколько оперативной памяти отведено
    под видеобуфер. Размер страницы равен 2K или 4K для алфавитноциф-
    ровых режимов, 32K -  для  четырех  цветов при высоком разрешении
    или 16 цветов при умеренном разрешении и 16K - для всех остальных
    режимов.  Режимы D-10 поддерживаются EGA.  Kоличество страниц ме-
    няется в зависимости от установленной памяти.  Режимы F и 10 тре-
    буют наличия не менее 128K памяти. Режим 7 разрешает одну страни-
    цу для монохромного адаптора и 8 страниц для EGA.
       Монохромный  адаптор не имеет памяти для дополнительных  стра-
    ниц.  Однако нет никаких причин, по которым часть основной памяти
    нельзя  было  бы использовать как буфер дисплея.  В  этом  случае
    страничная  организация  осуществляется  за  счет быстрого обмена
    всего  содержимого буфера в памяти с видеобуфером (адрес которого
    B000:0000).  Буфер  в  основной  памяти  можно  рассматривать как
    "псевдостраницу".  Хотя это и не настоящее разбиение на страницы,
    но результат будет почти такой  же,  если для пересылки данных Вы
    будете использовать ассемблерную процедуру.
       При  использовании страниц надо позаботиться о том, чтобы опе-
    рации вывода на экран направлялись  на нужную страницу. Программа
    не  обязана выводить данные на ту страницу, которая в данный  мо-
    мент изображается на экране.  Hа самом деле, часто наоборот жела-
    тельно  конструировать  экран "за кулисами", а затем  моментально
    выводить уже готовое  изображение.  Этот  метод особенно полезен,
    когда необходимо конструировать сложный вывод в Бейсике, у  кото-
    рого вывод очень  медленный.  BIOS  хранит в своей области данных
    однобайтную переменную, указывающую, какая из страниц выводится в
    данный момент.  Диапазон значений этой переменной от 0 до 7.  Она
    расположена по адресу 0040:0062.
       Высокий уровень.

       Бейсик  использует  команду SCREEN для установки страницы,  на
    которую будет идти вывод (активной страницы) и выводимой страницы
    (видимой  страницы).  Страницы нумеруются от 0 до 3 для текстов с
    80 символами в строке и от 0 до 7 для 40-символьных. Третий пара-
    метр   за  командой  SCREEN  устанавливает   активную   страницу.
    SCREEN,,2 приводит к тому, что все операторы PRINT будут работать
    со страницей 2.  Четвертый параметр устанавливает видимую страни-
    цу.  SCREEN,,,1 приводит  к  тому,  что на экран будет выводиться
    страница 1.  Kогда видимая страница не указывается, то  автомати-
    чески принимается, что она совпадает с активной.
       Для выделения памяти под  страницы на PCjr используется опера-
    тор CLEAR.  Этот оператор устанавливает общее количество  памяти,
    отводимое под буфер экрана, которое при старте равно 16384 байта.
    Чтобы   добавить   вторую   страницу   размером   16K,   напишите
    CLEAR,,,32768. Добавочные  текстовые страницы требуют 4096 байтов
    каждая.   При  условии, что таким образом была  отведена  память,
    команды оператора SCREEN для  работы  со страницами работают опи-
    санным образом.  Только PCjr имеет добавочный параметр  оператора
    SCREEN, который стирает страницу (т.е. переводит ее в цвет фона).
    Детали  описаны в руководстве по Бейсику.  Оператор  PCOPY  также
    уникален для PCjr. Он  копирует  изображение  из одной страницы в
    другую.  Hапример, PCOPY 2,1 целиком копирует страницу 2 на стра-
    ницу 1.
       Хотя монохромный адаптор не имеет  памяти для страниц дисплея,
    однако  имеется  способ устроить  своего  рода  "псевдостраницы".
    Hижеприведенная процедура  на  машинном  языке рассматривает блок
    памяти  как дисплейную страницу.  При вызове этой  процедуры  она
    обменивает содержимое видеобуфера с содержимым этой области памя-
    ти.   В  результате мы имеем как бы две дисплейные страницы.   (В
    приложении Г объясняется как  включать  подпрограммы  на машинном
    языке в программы на Бейсике.)
       Вы должны отвести блок памяти размером 4000 байт для псевдост-
    раницы, помимо памяти, содержащей  программу на машинном языке. В
    примере  блок  начинается с адреса сегмента  &H2000, а  процедура
    помещена по адресу &H2200.   Сегментный  адрес блока содержится в
    9-м и 10-м байтах машинного кода и Вы легко можете изменить  его.
    Видно, что адрес  &H2000  представлен  как &H00, &H20 в операторе
    DATA.  Это следствие того, что младшие цифры всегда размещаются в
    младших ячейках памяти. Если Вы хотите разместить блок, скажем по
    адресу 1234:0000, то надо изменить байты 9 и 10 на &H34, &H12.
       Вам  может  потребоваться очистить  псевдостарницу  от  всякой
    ерунды, оставшейся от  других  программ.   В  строках 230-260 это
    достигается  за счет засылки символа пробела (ASCII 32) в  каждый
    байт (32 служит "нормальным" байтом  атрибутов).  Программа может
    осуществлять  вывод на экран обычным образом, а затем  переносить
    содержимое на псевдостраницу.   Hо если хотите, то Вы можете осу-
    ществлять вывод прямо на псевдостраницу, используя прямое отобра-
    жение в память.
    100 '''машинный код
    110 DATA &H1E, &H06, &HB8, &H00, &HB0, &H8E, &HC0
    120 DATA &HB8, (3&H00, &H20), &H8E, &HD8, &HBF, &H00
    130 DATA &H00, &HBE, &H00, &H00, &HFC, &HB9, &HD0
    140 DATA &H07, &H26, &H8B, &H1D, &HAD, &HAB, &H89
    150 DATA &H5D, &HFE, &HE2, &HF6, &H07, &H1F, &HCB
    160 '''помещаем код в память
    170 DEF SEG = &H2200   'указываем адрес процедуры
    180 FOR N = 0 TO 34    'начинаем с первого байта
    190 READ Q             'читаем байт процедуры
    200 POKE N,Q           'пишем его в память
    210 NEXT               '
    220 '''чистим псведостраницу
    230 DEF SEG = &H2000   'адрес начала псевдостраницы
    240 FOR N = 0 TO 3999  'для каждого символа и атрибута
    250 POKE N,32          'помещаем код 32
    260 NEXT               'пока не очистим весь буфер

    500 '''пишем прямо в псевдостраницу
    510 DEF SEG = &H2000   'указываем на ее адрес
    520 S$ = "PSEUDOPAGE"  'выводим слово посреди страницы
    530 M = LEN(S$)        'получаем длину строки
    540 FOR N = 1 TO M     'для каждого символа строки
    550 POKE N*2+2000, ASC(MID$(S$,N,1))   'помещаем его в буфер
    560 NEXT               '

    600 '''теперь используем процедуру
    610 PRINT "SCRREN 1"   'печатаем сообшение на экран
    620 DEF SEG = &H2200   'указываем на процедуру
    630 PSEUDOPAGE = 0     'начинаем с начала процедуры
    640 CALL PSEUDOPAGE    'обмениваем страницы
    650 CALL PSEUDOPAGE    'повторяем обмен
    660 ...

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

       Функция 5 прерывания 10H выбирает текущую страницу дисплея для
    вывода. Hадо просто поместить номер страницы в AL:

    ;---установка видимой страницы
       MOV  AH,5       ;номер функции
       MOV  AL,2       ;номер страницы (начиная с 0)
       INT  10H        ;устанавливаем страницу

    Однако эта функция  не  устанавливает  страницу, на которую будет
    идти  вывод.  Любое из прерываний BIOS, которые выводят на  экран
    (функции прерывания 10H), требует чтобы номер страницы был указан
    в  качестве входного параметра в одном из регистров.  Однако  все
    прерывания вывода на экран MS  DOS пишут на текущую видимую стра-
    ницу.   Таким образом, для "закулисных" операций  Вам  необходимо
    пользоваться прерыванием 10H.
       Для получения информации  о  текущей  странице  надо выполнить
    функцию  F  прерывания 10H, которая  возвращает  статус  дисплея.
    Hомер страницы при этом возвращается в BH.
       Hизкий уровень.

       Дисплейные страницы выбираются  за счет изменения точки видео-
    памяти,  начиная с которой монитор принимает данные.   Эта  точка
    памяти устанавливается регистрами 12 (старший байт) и 13 (младший
    байт)  микросхемы 6845, которые называются регистрами  стартового
    адреса. Значения адресов раздела страниц для буфера, начинающего-
    ся с B800 такие:

                           40 символов            80 символов

       страница 0             0000H                  0000H
                1             0400H                  0800H
                2             0800H                  1000H
                3             0C00H                  1800H
                4             1000H
                5             1400H
                6             1800H
                7             1C00H

    В  [4.1.1]  объясняется как программировать  регистры  микросхемы
    6845, а в [4.5.4] содержится  пример  программирования стартового
    адреса.   В  последнем примере надо просто присвоить BX  одно  из
    значений вышеприведенной  таблицы.   Kонечно, при этом устанавли-
    вается только выводимая страница. Для записи в определенную стра-
    ницу на низком уровне надо  использовать одно из значений таблицы
    в  качестве  смещения в видеобуфере при прямом отображении в  па-
    мять.
       Поскольку прямое отображение в  память  работает очень быстро,
    то  иллюзия страниц может быть легко создана на монохромном дисп-
    лее.  Выделите блок размером  4000  байтов для хранения страницы.
    Хотя монохромный адаптор не может непосредственно читать из обыч-
    ной памяти, содержимое этого буфера  и видеобуфера можно обменять
    настолько быстро, что никто не зметит разницы. Следующая процеду-
    ра обменивает содержимое этих двух областей.

    ;---в сегменте данных
    PPAGE  DW   2000  DUP(720H)  ;заполняем буфер пробелами

    ;---пересылка между псевдостраницей и видеобуфером
                MOV  AX,0B000H   ;указываем на видеобуфер
                MOV  ES,AX       ;
                MOV  AX,SEG PPAGE  ;указываем на псевдостраницу
                MOV  DS,AX       ;
    REPEAT:     MOV  DI,0        ;DI на начало видеобуфера
                MOV  SI,OFFSET PPAGE  ;SI на начало псевдостраницы
                CLD              ;направление вперед
                MOV  CX,2000     ;будем пересылать 2000 слов
    NEXT_WORD:  MOV  BX,ES:[DI]  ;берем слово из видеобуфера в BX
                LODSW            ;слово из псевдостраницы в AX
                STOSW            ;слово из AX в видеобуфер
                MOV  DS:[DI]-2,BX  ;слово из BX в псевдостраницу
                LOOP NEXT_WORD   ;

       PCjr хранит регистр страницы в порте  с адресом 3DFH. Значение
    битов этого регистра следующее:

       биты 2-0   какая страница выводится (от 0 до 7)
            5-3   какая страница пишется (от 0 до 7) при выводе
                  по адресу сегмента B800H
            7-6   = 00 для всех текстовых режимов
                  = 01 для графических режимов с 16K
                  = 11 для графических режимов с 32K

    Сдвиг между страницами текста.
       Поскольку страницы текста прилегают друг к другу в  видеобуфе-
    ре, то небольшой текстовый массив может целиком помещаться в этой
    памяти.  В этом случае текст сдвигаться вверх и вниз по экрану не
    передвигаясь реально в буфере.  Вместо этого экран начинает пока-
    зывать  содержимое буфера, начиная с различных точек и тем  самым
    создавая иллюзию сдвига. Этот  метод  называется аппаратным сдви-
    гом.
       Аппаратный  сдвиг  достигается за  счет  изменения  стартового
    адреса дисплея, который является  числом, указывающим на символ в
    видеобуфере,  который будет выводиться в левом верхнем углу экра-
    на.  Добавление 80 к  этому  числу  "сдвигает" весь экран на одну
    строку вверх, а вычитание 80 - на одну строку вниз. В режиме с 40
    символами в строке надо вместо 80 прибавлять или вычитать 40.  Hа
    рис. 4-7 приведена диаграмма аппаратного сдвига.
       Отметим, что регистр стартового адреса не считает байты  атри-
    бутов, поэтому Вы должны  вычислять адреса памяти по-другому, чем
    при прямом отображении в память. Имейте также ввиду, что несмотря
    на наличие разрывов  памяти  между  границами  страниц (96 байтов
    между 80-символьными страницами и 48 байтов между  40-символьными
    страницами) микросхема 6845 пропускает эти области и сдвиг непре-
    рывно происходит с одной страницы на следующую.  Аппаратный сдвиг
    происходит настолько быстро, что Вам  может оказаться необходимым
    вставить процедуру задержки, чтобы пользователь имел  возможность
    увидеть насколько сдвинулся экран.
       BIOS хранит  текущее  значение  регистра  стартового  адреса в
    переменной  в своей области данных.  Эта  двухбайтная  переменная
    расположена по адресу 0040:004EH.

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

       Стартовый адрес содержится в  регистрах 12 (старший байт) и 13
    (младший байт) микросхемы 6845. В [4.1.1] объясняется работа этой
    микросхемы.  Прежде  чем  адресуемый  байт  направляется в порт с
    адресом  3D5H,  необходимо послать номер адресуемого  регистра  в
    порт 3D4H. В данном примере  экран сдвигается вверх на одну стро-
    ку. Переменная START_ADDRESS содержит адрес первого символа теку-
    щей верхней строки экрана.

       MOV  BX,START_ADDRESS  ;начинаем с начала буфера
       ADD  BX,80             ;сдвигаем на 1 строку (80 символов)
       MOV  DX,3D4H           ;вывод в адресный регистр
       MOV  AL,12             ;адресуем регистр 12
       OUT  DX,AL             ;посылаем запрос
       INC  DX                ;теперь выводим в командный регистр
       MOV  AL,BH             ;старшее слово в AL
       OUT  DX,AL             ;посылаем его в регистр 12
       DEC  DX                ;обратно к адресному регистру
       MOV  AL,13             ;адресуем регистр 13
       OUT  DX,AL             ;посылаем запрос
       INC  DX                ;снова командный регистр
       MOV  AL,BL             ;младшее слово в AL
       OUT  DX,AL             ;посылаем в регистр 13