Элементарная графика 1993 г.

Элементарная графика в машинных кодах - методика рассчета адресов в экранной области по заданным координатам. Расчет адреса в дисплейном файле (координаты заданы в знакоместах). Расчет адреса в файле атрибутов. Расчет адреса в дисплейном файле (координаты заданы в пикселах). Универсальная программа сканирования экрана.


                   2.9. МЕТОДИКА РАСЧЕТА АДРЕСОВ В ЭКРАННОЙ
                          ОБЛАСТИ ПО ЗАДАННЫМ КООРДИНАТАМ

              Расчет адресов в экранной области па-  г=================¬
         мяти - это  основная задача,  встающая пе-  ¦ ------    ---   ¦
         раед  каждым,  кто хочет заняться  компью-  ¦ -    -     -    ¦
         терной  графикой, работая в машинном коде.  ¦ ------     -    ¦
         Не приобретя практики в этом вопросе труд-  ¦ -    - -  --- - ¦
         но двигаться вперед.                        L=================-

                   2.9.1.  Расчет адреса в дисплейном файле
                          (координаты заданы в знакоместах).

              Предположим, что координаты X  и Y заданы в  занкоместах и
         находятся в регистровой паре DE. В регистре D - координата X, а
         в регистре E - координата Y. Генеральной задачей является полу-
         чить в регистровой паре  HL адрес в дисплейном  файле, соответ-
         ствующий левому верхнему  углу заданного знакоместа.

              Приступая к  этой задаче,  напомним читателю  как адрес  в
         регистровой паре HL соответствует координатам экрана:

                        H                               L
           -------------+-------------¬   --------------+-------------¬
           ¦                          ¦   ¦                           ¦
         г==T===T===T===T===T===T===T===T===T===T===T===T===T===T===T==¬
         ¦0 ¦ 1 ¦ 0 ¦ X ¦ X ¦ X ¦ X ¦ X ¦ X ¦ X ¦ X ¦ X ¦ X ¦ X ¦ X ¦ X¦
         L==¦=T=¦===¦===¦===¦===¦===¦===¦===¦===¦===¦===¦===¦===¦===¦==-
              ¦       ¦    ¦  ¦       ¦   ¦       ¦   ¦               ¦
              ¦       L-----  L--------   L--------   L----------------
         Адрес 16384   Номер    Номер      Номер        Номер столбца
                      сегмента  линии      ряда
                       0...2    0...7       0...7         0 ... 31

                                     Рис. 16.

              На первом этапе по координате Y определяется номер сегмен-
         та экрана. Т.к. координата Y не может быть больше 23-х, то для

         ее выражения достаточно 5-ти битов.

                                   LD A,E
                      г===T===T===T===T===T===T===T===¬
                      ¦ 0 ¦ 0 ¦ 0 ¦ ? ¦ ? ¦ ? ¦ ? ¦ ? ¦
                      L===¦===¦===¦===¦===¦===¦===¦===-

              Поскольку в каждом сегменте по 8 рядов, то на номер
         сегмента указывают биты 3 и 4, поэтому замаскировав биты 0, 1,
         2, получим указание на номер экранного сегмента:

                                   AND 18
                      г===T===T===T===T===T===T===T===¬
                      ¦ 0 ¦ 0 ¦ 0 ¦Сег¦Сег¦ 0 ¦ 0 ¦ 0 ¦
                      L===¦===¦===¦===¦===¦===¦===¦===-

              Командой OR 40 включим 6-ой бит, что послужит указанием
         на начало дисплейного файла:

                                   OR 40
                      г===T===T===T===T===T===T===T===¬
                      ¦ 0 ¦ 1 ¦ 0 ¦Сег¦Сег¦ 0 ¦ 0 ¦ 0 ¦
                      L===¦===¦===¦===¦===¦===¦===¦===-
              А теперь сравните полученную конструкцию с тем, что должно
         быть в  регистре H  (см. Рис.16).  Таким образом,  старший байт
         адреса мы уже сформировали.

                                  LD H,A

              Выставили старший байт адреса  в дисплейном файле. У  нас,
         правда, занулены биты  0,1,2, указывающие на  линию в ряду,  но
         нас они и не  интересуют, поскольку координаты заданы  в знако-
         местах,  а  не  в  пикселах  и  верхнему левому углу знакоместа
         соответствует его нулевая (верхняя линия).

              Теперь займемся вычислением младшего байта адреса для  по-
         мещения его в регистр L.

                                  LD A,E

              Вновь рассматриваем координату Y.

                      г===T===T===T===T===T===T===T===¬
                      ¦ 0 ¦ 0 ¦ 0 ¦ ? ¦ ? ¦ ? ¦ ? ¦ ? ¦
                      L===¦===¦===¦===¦===¦===¦===¦===-
                                  AND 07
                      г===T===T===T===T===T===T===T===¬
                      ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦Ряд¦Ряд¦Ряд¦
                      L===¦===¦===¦===¦===¦===¦===¦===-
               Оставив три младших бита, мы выделили тем самым номер
         ряда в экранном сегменте.

                                   OR  A
               Обнулили флаг C в регистре F
                      г===T===T===T===T===T===T===T===¬    г===¬
                      ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦Ряд¦Ряд¦Ряд¦    ¦ 0 ¦
                      L===¦===¦===¦===¦===¦===¦===¦===-    L===-
                                   RRA
                      г===T===T===T===T===T===T===T===¬    г===¬
                      ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦Ряд¦Ряд¦    ¦Ряд¦
                      L===¦===¦===¦===¦===¦===¦===¦===-    L===-
                                   RRA
                      г===T===T===T===T===T===T===T===¬    г===¬
                      ¦Ряд¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦Ряд¦    ¦Ряд¦
                      L===¦===¦===¦===¦===¦===¦===¦===-    L===-
                                   RRA
                      г===T===T===T===T===T===T===T===¬    г===¬
                      ¦Ряд¦Ряд¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦    ¦Ряд¦
                      L===¦===¦===¦===¦===¦===¦===¦===-    L===-
                                   RRA
                      г===T===T===T===T===T===T===T===¬    г===¬
                      ¦Ряд¦Ряд¦Ряд¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦    ¦ 0 ¦
                      L===¦===¦===¦===¦===¦===¦===¦===-    L===-

              В  результате  четырех  шагов  вращения  через  флаг C три
         младших бита, указывавшие на номер ряда, стали старшими.

                                 ADD A,D
                      г===T===T===T===T===T===T===T===¬
                      ¦Ряд¦Ряд¦Ряд¦ Ст¦ Ст¦ Ст¦ Ст¦ Ст¦
                      L===¦===¦===¦===¦===¦===¦===¦===-
              Прибавив значение столбца, а оно меньше 32 и потому зани-
         мает только пять младших битов, мы получили конструкцию,
         полностью соответствующую младшему байту адреса, изображенному
         на рис. 16 .
                                   LD L,A

              Выставили младший байт адреса и задача выполнена.

                   2.9.2. Расчет адреса в файле атрибутов.

              Атрибуты "привязаны" только к знакоместам и потому коорди-
         наты могут быть заданы  только в знакоместах. Предположим,  что
         координата Y содержится  в регистре E,  а координата X  - в ре-
         гистре D. Генеральная задача - сформировать в регистровой  паре
         HL двухбайтный адрес, указывающий  на ячейку памяти, в  которой
         содерится байт атрибутов для нашего знакоместа.

              Напомним, как  адрес в  регистровой паре  HL соответствует
         атрибутам экрана.

                        H                               L
           -------------+-------------¬   --------------+-------------¬
           ¦                          ¦   ¦                           ¦
         г==T===T===T===T===T===T===T===T===T===T===T===T===T===T===T==¬
         ¦0 ¦ 1 ¦ 0 ¦ 1 ¦ 1 ¦ 0 ¦ X ¦ X ¦ X ¦ X ¦ X ¦ X ¦ X ¦ X ¦ X ¦ X¦
         LT=¦===¦===¦===¦=T=¦===¦=T=¦===¦===¦===¦===¦===¦===¦===¦===¦==-
          L------T---------       ¦               ¦   ¦               ¦
                 ¦                L----------------   L----------------
              адрес 22528               Номер           Номер столбца
                                        ряда
                                       0...23           0 ... 31

                                      Рис. 17

              Принимаем в аккумулятор параметр Y.

                                   LD A,E
                      г===T===T===T===T===T===T===T===¬
                      ¦ 0 ¦ 0 ¦ 0 ¦Ряд¦Ряд¦Ряд¦Ряд¦Ряд¦
                      L===¦===¦===¦===¦===¦===¦===¦===-
              Оставляем от номера ряда два старших бита.

                                   AND 18
                      г===T===T===T===T===T===T===T===¬
                      ¦ 0 ¦ 0 ¦ 0 ¦Ряд¦Ряд¦ 0 ¦ 0 ¦ 0 ¦
                      L===¦===¦===¦===¦===¦===¦===¦===-
              Тремя  шагами  логического  вращения  влево делаем эти два
         бита младшими.

                                   SRL  A
                      г===T===T===T===T===T===T===T===¬
                      ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦Ряд¦Ряд¦ 0 ¦ 0 ¦
                      L===¦===¦===¦===¦===¦===¦===¦===-
                                   SRL  A
                      г===T===T===T===T===T===T===T===¬
                      ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦Ряд¦Ряд¦ 0 ¦
                      L===¦===¦===¦===¦===¦===¦===¦===-
                                   SRL  A
                      г===T===T===T===T===T===T===T===¬
                      ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦Ряд¦Ряд¦
                      L===¦===¦===¦===¦===¦===¦===¦===-
              Включаем биты 3,4,6 - они дают указание на начало файла
         атрибутов.
                                   OR 58
                      г===T===T===T===T===T===T===T===¬
                      ¦ 0 ¦ 1 ¦ 0 ¦ 1 ¦ 1 ¦ 0 ¦Ряд¦Ряд¦
                      L===¦===¦===¦===¦===¦===¦===¦===-

              Если сравнить полученную конструкцию с рис. 16, то видно,
         что она полностью соответствет старшему байту адреса, который
         должен быть в регистре H. Туда мы его и помещаем.
                                   LD H,A

              Старший байт сформирован. Приступаем к формированию млад-
         шего байта.  Вновь принимаем в аккумулятор координату Y.

                                    LD A,E
                      г===T===T===T===T===T===T===T===¬
                      ¦ 0 ¦ 0 ¦ 0 ¦Ряд¦Ряд¦Ряд¦Ряд¦Ряд¦
                      L===¦===¦===¦===¦===¦===¦===¦===-
              Оставляем три младших бита.

                                  AND 07
                      г===T===T===T===T===T===T===T===¬
                      ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦Ряд¦Ряд¦Ряд¦
                      L===¦===¦===¦===¦===¦===¦===¦===-
              Обнуляем флаг C в регистре F.                    Флаг С.
                                                                  /
                                   OR A                         /
                      г===T===T===T===T===T===T===T===¬    г===¬
                      ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦Ряд¦Ряд¦Ряд¦    ¦ 0 ¦
                      L===¦===¦===¦===¦===¦===¦===¦===-    L===-
                                   RRA
                      г===T===T===T===T===T===T===T===¬    г===¬
                      ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦Ряд¦Ряд¦    ¦Ряд¦
                      L===¦===¦===¦===¦===¦===¦===¦===-    L===-
                                   RRA
                      г===T===T===T===T===T===T===T===¬    г===¬
                      ¦Ряд¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦Ряд¦    ¦Ряд¦
                      L===¦===¦===¦===¦===¦===¦===¦===-    L===-
                                   RRA
                      г===T===T===T===T===T===T===T===¬    г===¬
                      ¦Ряд¦Ряд¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦    ¦Ряд¦
                      L===¦===¦===¦===¦===¦===¦===¦===-    L===-
                                   RRA
                      г===T===T===T===T===T===T===T===¬    г===¬
                      ¦Ряд¦Ряд¦Ряд¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦    ¦ 0 ¦
                      L===¦===¦===¦===¦===¦===¦===¦===-    L===-
              В  результате  четырех  шагов  вращения  через  флаг C три
         младших бита номера ряда стали старшими.

                                   ADD A,D
                      г===T===T===T===T===T===T===T===¬
                      ¦Ряд¦Ряд¦Ряд¦ Ст¦ Ст¦ Ст¦ Ст¦ Ст¦
                      L===¦===¦===¦===¦===¦===¦===¦===-
              Прибавив значение  столбца (оно  меньше 32  и потому зани-
         мает  только  пять  младших  битов),  мы  получили конструкцию,
         полностью соответствующую младшему байту адреса,  изображенному
         на рис. 16 .
                                   LD L,A
              Выставили младший байт адреса - задача выполнена.

                   2.9.3. Расчет адреса в дисплейном файле
                          (координаты заданы в пикселах).

              Это наиболее трудоемкая  задача из трех.  Предположим, что
         координаты точки экрана содержатся в  регистрах D (x) и E  (y).
         Наша задача определить адрес в дисплейном файле,  соответствую-
         щий данной точке. Надо сказать, что такая постановка не  вполне
         корректна, т.к. минимальной  единицей хранения данных  является
         байт, а он определяет линию в знакоместе, т.е. 8 пикселов, а не
         один. Поэтому задача  становится чуть глубже.   Надо будет  еще
         найти бит в байте, соответствующий заданной точке.

              Попутно надо еще решить одну мелкую проблему. Дело в  том,
         что координата y (когда она задана в пикселах) отсчитывается по
         экрану снизу вверх. Мы об этом уже говорили. А общая  тенденция
         нарастания адресов  в дисплейном  файле -  сверху вниз. Поэтому
         надо  координату  y  преобразовать.  Это  делают путем подмены.
         Вместо y  в проработку  берут дополнение  y до  175. Получается
         так, что y как бы инвертируется (назовем его y'). Тогда верхней
         линии  экрана  соответствует  нулевое  значение  y', а нижней -
         максимальное значение.

              Загружаем в аккумулятор число 175:

                               LD A,0AFH

              и вычитаем из него y:
                                    SUB E
                                    LD E,A

              Теперь в регистре E у нас находится y'. Раскладка битов  в
         регистре E и  в аккумуляторе после  этого может быть,  например
         такой:
                      г===T===T===T===T===T===T===T===¬
                      ¦e7 ¦ e6¦ e5¦ e4¦ e3¦ e2¦ e1¦ e0¦
                      L===¦===¦===¦===¦===¦===¦===¦===-
              Выключим флаг C в регистре F:                     Флаг C
                                                                   /
                                   AND A                         /
                      г===T===T===T===T===T===T===T===¬    г===¬
                      ¦e7 ¦ e6¦ e5¦ e4¦ e3¦ e2¦ e1¦ e0¦    ¦ 0 ¦
                      L===¦===¦===¦===¦===¦===¦===¦===-    L===-
                                   RRA
                      г===T===T===T===T===T===T===T===¬    г===¬
                      ¦ 0 ¦ e7¦ e6¦ e5¦ e4¦ e3¦ e2¦ e1¦    ¦ e0¦
                      L===¦===¦===¦===¦===¦===¦===¦===-    L===-
              Включим флаг C:
                                   SCF
                      г===T===T===T===T===T===T===T===¬    г===¬
                      ¦ 0 ¦ e7¦ e6¦ e5¦ e4¦ e3¦ e2¦ e1¦    ¦ 1 ¦
                      L===¦===¦===¦===¦===¦===¦===¦===-    L===-
                                   RRA
                      г===T===T===T===T===T===T===T===¬    г===¬
                      є 1 є 0 є e7є e6є e5є e4є e3є e2є    є e1є
                      L===¦===¦===¦===¦===¦===¦===¦===-    L===-
              Выключим флаг C:
                                   AND A
                      г===T===T===T===T===T===T===T===¬    г===¬
                      ¦ 1 ¦ 0 ¦ e7¦ e6¦ e5¦ e4¦ e3¦ e2¦    ¦ 0 ¦
                      L===¦===¦===¦===¦===¦===¦===¦===-    L===-
                                   RRA
                      г===T===T===T===T===T===T===T===¬    г===¬
                      ¦ 0 ¦ 1 ¦ 0 ¦ e7¦ e6¦ e5¦ e4¦ e3¦    ¦ e2¦
                      L===¦===¦===¦===¦===¦===¦===¦===-    L===-

              А теперь подменим биты 0, 1, 2 в аккумуляторе соответству-
         ющими им битами из регистра E:

                                   XOR E
                                   AND 0F8H
                                   XOR E
        Ъ---------------------------------------------------------------ї
        ¦             ПРИМЕЧАНИЕ                     Й-----------------"¦
        ¦   Три последние операции XOR,AND,XOR об-   ¦ ЫЯЯЯЯЬ    ЯЫЯ   ¦¦
        ¦разуют одну интересную комплексную опера-   ¦ Ы    Ы     Ы    ¦¦
        ¦цию замещения. Если у Вас, например, есть   ¦ ЫЯЯЯЯЬ     Ы    ¦¦
        ¦два байта - A и B и Вы хотите несколько     ¦ Ы    Ы Ь  ЬЫЬ Ь ¦¦
        ¦битов в байте A заменить на соответствую-   И-----------------ј¦
        ¦щие биты из байта B, то эти операции позволят это сделать.  За-¦
        ¦мещены  будут  те  биты,  которые  замаскированы в операции AND¦
        ¦нулями. Например пусть A имеет раскладку a7a6a5a4a3a2a1a0, а  B¦
        ¦имеет раскладку b7b6b5b4b3b2b1b0 и Вам надо заменить a5 и a3 на¦
        ¦b5 и b3. Тогда в операции AND эти биты должны быть замаскирова-¦
        ¦ны.                                                            ¦
        ¦              Исходно: a7 a6 a5 a4 a3 a2 a1 a0                 ¦
        ¦                                                               ¦
        ¦                XOR B: b7 b6 b5 b4 b3 b2 b1 b0                 ¦
        ¦              AND 214:  1  1  0  1  0  1  1  1                 ¦
        ¦                XOR B: b7 b6 b5 b4 b3 b2 b1 b0                 ¦
        ¦             _________________________________                 ¦
        ¦            Результат: a7 a6 b5 a4 b3 a2 a1 a0                 ¦
        А---------------------------------------------------------------Щ

              В результате трех последних операций образуется следующая
         раскладка битов:
                      +-------------------------------+
                      ¦ 0 є 1 є 0 є e7є e6є e2є e1є e0¦
                      +-------------------------------+
              Эта картина уже соответствует тому, что мы должны получить
         в регистре H (см. рис.15).
                                 LD H,A
              Таким образом,  по дополнению  координаты y  до 175  можно
         определить  номер  сегмента  экрана   (e7,e6)  и  номер   линии

         (e2,e1,e0)  в  неизвестном  (пока)  ряду  этого сегмента. Номер
         ряда  мы  установим,  когда  рассмотрим  координату  x и сможем
         заполнить регистр L.

              Рассмотрим теперь координату x.

                                    LD A,D

              Раскладка битов в общем случае может быть например такой:

                      +-------------------------------+
                      ¦d7 є d6є d5є d4є d3є d2є d1є d0¦
                      +-------------------------------+
              Делаем три шага вращения влево:

                                     RLCA
                      +-------------------------------+
                      ¦d6 є d5є d4є d3є d2є d1є d0є d7¦
                      +-------------------------------+
                                     RLCA
                      +-------------------------------+
                      ¦d5 є d4є d3є d2є d1є d0є d7є d6¦
                      +-------------------------------+
                                     RLCA
                      +-------------------------------+
                      ¦d4 є d3є d2є d1є d0є d7є d6є d5¦
                      +-------------------------------+
              И второй раз выполняем рассмотренную выше операцию
         логического замещения.
                                     XOR E
                                     AND C7
                                     XOR E
              В итоге получаем:

                      +-------------------------------+
                      ¦d4 є d3є e5є e4є e3є d7є d6є d5¦
                      +-------------------------------+

              Еще два шага вращения влево:

                                     RLCA
                      +-------------------------------+
                      ¦d3 є e5є e4є e3є d7є d6є d5є d4¦
                      +-------------------------------+
                                     RLCA
                      +-------------------------------+
                      ¦e5 є e4є e3є d7є d6є d5є d4є d3¦
                      +-------------------------------+

              Теперь конструкция в аккумуляторе полностью соответствует
         младшему байту адреса дисплейного файла (см. рис. 15).

                                   LD L,A

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

              Теперь мы знаем номер сегмента, ряда, столбца и линии. Все
         эти данные хранятся в регистровой паре HL. Последнее, что оста-
         лось сделать - это вспомнить,  что данная линия в своем  знако-
         месте имеет 8 пикселов, а нам нужен только один из них -  необ-
         ходимый.  Фактически его номер определяется остатком от деления
         координаты x на 8, а вычисляется этот остаток - путем  маскиро-
         вания пяти старших битов, но  есть еще один нюанс. Дело  в том,
         что  координата  x  изменяется  слева  направо  0,1,2... 255, а
         номера битов в байте, идут наоборот 7,6,5.....0. Поэтому  нужно
         сделать преобразование.

              Возьмем координату x:

                                 LD A,D
                      +-------------------------------+
                      ¦d7 є d6є d5є d4є d3є d2є d1є d0¦
                      +-------------------------------+

              и замаскируем пять старших битов:

                                 AND 07
                      +-------------------------------+
                      ¦ 0 є 0 є 0 є 0 є 0 є d2є d1є d0¦
                      +-------------------------------+
             Фактически мы имеем в аккумуляторе остаток от деления на 8.
         Поместим его в регистр B

                                 LD B,A
              и выполним преобразование:

                                 LD A,08
                                 SUB B
                                 LD B,A

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

                 2.10  УНИВЕРСАЛЬНАЯ ПРОГРАММА СКАНИРОВАНИЯ ЭКРАНА

              Эта  программа  может  выполнить  сканирование  экрана   в
         заданном знакоместе и определить что за символ там содержится.

              В  отличие  от  функции  БЕЙСИКа  SCREEN$  (X,Y)  и  от ее
         машиннокодовых аналогов  из системного  ПЗУ компьютера,  данная
         программа способна распознать и символы графики пользователя  и
         символы блочной графики.

              Программа имеет  три различных  точки входа.  Какой из них
         пользоваться зависит  от того,  в каком  виде заданы  начальные
         условия. Если координаты сканируемого знакоместа заданы на вер-
         шине стека калькулятора в порядке Y,X, то процедура  вызывается
         по метке  SCR_FP. При этом результат подается на вершину  стека
         калькулятора.

              Если  входные  координаты  задаются  в качестве параметров
         функции пользователя FN  S (), то  точкой входа является  метка
         SCR_FN. В  этом случае  сама функция  пользователя должна  быть
         задана как DEF  FN S(X,Y) =  USR addr, где  addr - адрес  метки
         SCR_FN. Вызов же процедуры тогда выполняется командой RANDOMIZE
         FN S(X,Y), где вместо X и Y Вы подставите конкретные параметры.

             Если координаты задаются через регистры B (координата x)  и
         C (координата y), то  процедура вызывается по метке  SCR_1. Это
         основная точка входа.  Все остальные только  выполняют преобра-
         зование входящих данных и обращаются сюда же.

              Результат работы  процедуры определяется  состоянием флага
         Z (ZERO) регистра F. Если флаг включен, то сканирование  прошло
         успешно и символ идентифицирован.  Если флаг выключен -  такого
         символа не  существует. В  случае успешного  поиска код символа
         можно узнать в аккумуляторе процессора.

                            Программа  SCANER.

             SCR_FP  CALL 2307H         ;Вызов процедуры ПЗУ STK_TO_BC.
                                        ;Процедура служит для размеще-
                                        ;ния содержимого вершины стека
                                        ;калькулятора в регистровой
                                        ;паре BC.
                     CALL SCR_1         ;Вызов другой точки входа. В
                                        ;результате ее работы получим
                                        ;в регистре A код символа, со-
                                        ;держащегося в тестируемом зна-
                                        ;коместе.
                     LD BC,0000         ;Инициализация BC.
                     JR NZ,SCR_STR      ;Если символ не идентифициро-
                                        ;ван, то переход.
                     INC BC             ;В паре BC теперь 1. Это длина
                                        ;символьной строки, в которой
                                        ;только один символ.
                     RST 30             ;Вызов этой системной процедуры
                                        ;ПЗУ резервирует пространство,
                                        ;размер которого стоит в BC. На
                                        ;адрес указывает DE.
                     LD (DE),A          ;Заслали найденный символ.
             SCR_STR JP 2AB2            ;Это точка входа системной
                                        ;процедуры ПЗУ STACK_AEDCB,
                                        ;которая помещает на вершину
                                        ;стека калькулятора данные из
                                        ;регистров A,E,D,C,B.
                                        ;Эта процедура сама совершит и
                                        ;возврат в вызывающую программу.
             SCR_FN  LD HL,(DEFADD)     ;Указание на аргументы пользо-
                                        ;вательской функции. Подроб-
                                        ;ности см. в разделе 3.1.
                     LD DE,0004
                     ADD HL,DE          ;Сдвиг на 4 байта.
                     LD C,(HL)          ;Координата Y.
                     ADD HL,DE          ;
                     ADD HL,DE          ;Сдвиг на 8 байтов.
                     LD B,(HL)          ;Координата X.
                     CALL SCR_1         ;Вызов другой точки входа. В
                                        ;результате ее работы получим
                                        ;в регистре A код символа, со-
                                        ;держащегося в тестируемом зна-
                                        ;коместе.
                     JR Z,SCR_SINGL     ;Если символ найден - переход.
                     XOR A              ;В противном случае в аккуму-
                                        ;ляторе выставляем ноль.
          SCR_SINGL  LD C,A             ;Подготовка к
                     LD B,00            ;выходу.
                     RET                ;Выход.

              Основной является точка входа SCR_1, т.к. остальные
         сводятся к ней же. Итак, BC содержит координаты X и Y.

              SCR_1  LD A,C             ; є
                     RRCA               ; є
                     RRCA               ; є  Это поиск адреса зна-
                     RRCA               ; є  коместа в дисплейной
                     AND E0             ; є  памяти по заданным
                     XOR B              ; є  координатам.
                     LD E,A             ; є
                     LD A,C             ; є  См. стр. 86...89
                     AND 18             ; є
                     XOR 40             ; є
                     LD D,A             ; є
                     PUSH DE            ; є

              Итак, адрес знакоместа установлен в регистровой паре DE и
         сохранен на стеке. Теперь решается вопрос о том шаблон какого
         же символа изображен в этом знакоместе.

                     LD HL, (CHARS)     ;Системная переменная CHARS
                                        ;(23606 = 5C36) указывает на
                                        ;256 байтов ниже, чем начало
                                        ;таблицы шаблонов символов.
                     INC H              ;Теперь HL указывает точно
                                        ;на начало таблицы шаблонов.
                     CALL 254DH         ;Адрес 254DH - одна из точек
                                        ;входа в процедуру ПЗУ
                                        ;S_SCRN_$, которая выполняет
                                        ;проверку на то является ли
                                        ;тестируемый шаблон символом
                                        ;ASCII. Результат остается на
                                        ;вершине стека калькулятора.
                     CALL 2BF1H         ;Адрес 2BF1 - точка входа про-
                                        ;цедуры ПЗУ STK_FETCH, которая
                                        ;снимает верхние пять значений
                                        ;со стека калькулятора и раз-
                                        ;носит их по регистрам
                                        ;A,E,D,C,B.
                                        ;Теперь в аккумуляторе имеется
                                        ;код символа, если шаблон в тес-
                                        ;тируемом знакоместе является
                                        ;таковым.
                     POP DE             ;Восстановили адрес знакоместа.
                     DEC C
                     RET Z              ;Выход, если поиск был успешным.

              Если имеющийся в данном знакоместе символ не является сим-
         волом ASCII, начинаем  проверять, а не является ли он  символом
         графики пользователя UDG.

                      PUSH DE            ;Запомнили адрес знакоместа.
                      LD HL,(UDG)        ;Системная переменная UDG
                                         ;(23675 = 5C7BH) указывает на
                                         ;адрес, начиная с которого хра-
                                         ;нятся шаблоны символов графики
                                         ;пользователя.
                      LD B,15H           ;15H = 21 DEC - количество сим-
                                         ;волов графики пользователя.
                      CALL 254F          ;Это точка входа в системную
                                         ;процедуру S_SCRN_LP. Она про-
                                         ;верит есть ли символ UDG, со-
                                         ;ответствующий нашему знакомес-
                                         ;ту и поместит результат на
                                         ;вершину стека калькулятора.
                      CALL 2BF1          ;Вход в STK_FETCH и разнесение
                                         ;вершины стека калькулятора по
                                         ;регистрам A,E,D,C,B.

              Здесь надо сделать одно замечание. Дело в том, что на вер-
         шину стека, а затем и в акуумулятор пойдет не код символа  UDG,
         а  некоторое  другое  число,  которое надо еще скорректировать.
         Причина в том, что процедура S_SCRN_LP в ПЗУ не предназначалась
         для  работы  с  символами  UDG,  а  только с символами ASCII, в
         результате  чего  возникает  следующий  эффект.  Код найденного
         символа, помещаемый  в аккумулятор,  определяется как  разность
         между  числом  128  (предельный  код  символа ASCII) и тем, что
         осталось в счетчике проверяемых  символов (регистр B). Так  как
         символы  UDG  имеют  конечный  код  равный  165, а не 128, то к
         полученному  в  аккумуляторе  результату  необходимо   добавить
         недостающую разницу - число 37 (25H).

                      ADD A,25           ;Выполнили коррекцию.
                      POP HL             ;Теперь адрес знакоместа - в
                                         ;паре HL.
                      DEC C
                      RET Z              ;Возврат, если поиск был ус-
                                         ;пешным.

              Если же поиск и на сей раз прошел безуспешно, нам остается
         только проверить: "А не является ли тестируемый символ символом
         блочной  графики?" Проверка  выполняется  в два этапа.  Сначала
         проверяется  верхняя  половина  символа,  а  потом нижняя. Если
         первая проверка не прошла, то вторую выполнять нет смысла.  Об-
         ратите также внимание на то, что у любого символа блочной  гра-
         фики  4  линии  в  каждой  половине  равны между собой и потому
         проверять можно не все четыре линии, а любую из них.

                      CALL TEST_HALF     ;Проверка верхней половины
                                         ;символа.
                      RET NZ             ;Возврат, если проверка не
                                         ;прошла.
                      LD C,A             ;Если проверка прошла, то в
                                         ;регистре C запоминается би-
                                         ;товая рскладка линии верхней
                                         ;половины символа.
                      CALL TEST_HALF     ;Проверка нижней половины
                                         ;символа.
                      RET NZ             ;Возврат, если проверка не
                                         ;прошла.
                      ADD A,A            ;Здесь по конструкции символа
                      ADD A,A            ;блочной графики определяется
                      ADD A,C            ;его номер.
                      ADD A,80           ;
                      CP A               ;Включение флага Z как сигнал
                                         ;о том, что поиск был резуль-
                                         ;тативным.
                      RET                ;Окончательный выход в вызы-
                                         ;вающую программу.

              Подпрограмма TEST_HALF выполняет тестирование верхней  или
         нижней половины знакоместа в попытке определить не является  ли
         помещенный там символ символом блочной графики.

          TEST_HALF   CALL TEST_LINE     ;Вызов подпрограммы, которая
                                         ;выполняет проверку первой
                                         ;линии данной половины.
                      RET NZ             ;Возврат, если она не совпала.
                      LD D,A             ;Если совпала, то ее код надо
                                         ;запомнить, ибо последующие
                                         ;три должны быть такими же.
                      LD B,03            ;Счетчик цикла для трех линий.
             LOOP     CALL TEST_LINE     ;Вершина цикла для трех прове-
                                         ;рок линий.
                      RET NZ             ;Возврат, если хотя бы одна из
                                         ;линий не соответствует блочной
                                         ;графике.
                      CP D               ;Если она соответствует, но от-
                      RET NZ             ;личается от первой, то тоже
                                         ;возврат.
                      DJNZ LOOP          ;Конец цикла по линиям.
                      RET                ;Выход из подпрограммы.

              Подпрограмма  TEST_LINE  проверяет  соответствуют ли линии
         проверяемого знакоместа  символам блочной  графики. Конструкция
         линии задается одним байтом. Поскольку символы блочной  графики
         имеют определенную  симметрию, то  многое можно  о них сказать,
         проверив старший полубайт (4 бита) и младший полубайт (4 бита).
         Если один из них  не соответствует конструкции символа  блочной
         графики, то дальнейшее исследование символа бесполезно.

          TEST_LINE   LD A,(HL)          ;HL указывает на адрес линии
                                         ;в дисплейном файле. Теперь в
                                         ;регистре A фактически содер-
                                         ;жится конструкция линии.
                      INC H              ;Переход к следующей линии.
                      LD E,00            ;Инициализация регистра E.
                      CALL TEST_NIBBLE   ;Проверка старшего полубайта.
                      RET NZ             ;Возврат, если она не прошла.
                      RLC E              ;Раскладка битов в регистре
                                         ;E принимает вид:
                                         ;  0 0 0 0 0 0 0 ah
                                         ;где ah - состояние старшего
                                         ;полубайта в тестируемой
                                         ;линии.
                      CALL TEST_NIBBLE   ;Проверка младшего полубайта.
                      RET NZ             ;Возврат, если она не прошла.
                      LD A,E             ;Аккумулятор имеет вид:
                                         ;  al 0 0 0 0 0 0 ah, где
                                         ;ah и al - состояние старшего
                                         ;и младшего полубайтов в тес-
                                         ;тируемой линии.
                      RLCA               ;Аккумулятор имеет вид:
                                         ;  0 0 0 0 0 0 ah al
                                         ;и эта информация уже может
                                         ;быть использована для
                                         ;вычисления кода символа.
                      CP A               ;Включение флага Z как сигнал
                                         ;о том, что поиск был резуль-
                                         ;тативным.
                      RET                ;Возврат.

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

         TEST_NIBBLE  PUSH BC            ;Сохранили на стеке счетчик
                                         ;линий в B, поскольку ниже
                                         ;этот регистр будет использован
                                         ;как счетчик битов в полубайте.
                      RL E               ;В результате этой трехходовой
                      RLA                ;манипуляции стрший бит E стал
                      RR A               ;равен старшему биту A (копи-
                                         ;рование произошло через флаг
                                         ;переноса С.
                      LD B,03            ;Организуем счетчик для провер-
                                         ;ки трех последующих битов.
           LOOP_1     XOR E              ;Эта операция сбросит старший
                                         ;бит аккумулятора, если он
                                         ;равен (а сначала так оно и
                                         ;есть) старшему биту в E.
                      RLA                ;Очередной байт в аккумуляторе
                                         ;становится старшим, а бывший
                                         ;отправляется в флаг C
                      JR C, EXIT         ;Флаг C мог включиться только
                                         ;если один из трех битов, сле-
                                         ;дующих за старшим, не равен
                                         ;ему. Значит, это не символ
                                         ;блочной графики и следует
                                         ;переход на EXIT.
                      DJNZ LOOP_1        ;Повторение для трех битов.
                      CP A               ;Включение флага Z как сигнал
                                         ;о том, что поиск был резуль-
                                         ;тативным.
                      JR EXIT_1          ;Подготовка к возврату.
            EXIT      OR FF              ;Выключение флага Z как сигнал
                                         ;о том, что поиск был                                          ;тативным.
                                         ;безрезультатным.
            EXIT_1    POP BC             ;Восстановление счетчика линий
                                         ;в регистре B.
                      RET                ;Возврат.



СОДЕРЖАНИЕ:


  Оставте Ваш отзыв:

  НИК/ИМЯ
  ПОЧТА (шифруется)
  КОД



Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Художественная литература - Фредерик Браун: "Оно и видно"
От редакции - я получил два письма от VEL'а/PXM и по одному от Hardy/FLASH и Nemo.
Вступление - стихи и содержание номера.
Смак - Цыпленок табака.
Презентация - полностью русифицированная версия игры They stole a million!

В этот день...   24 апреля