Вставка короткой программы



Вставка короткой программы


      В предыдущем примере рассматривалась довольно большая программа
    на языке ассемблера, хранящаяся в собственном объектном файле и
    загружаемая в память интерпретатором Бейсика. А как в случае очень
    маленькой программы. Представляется, что для такой программы
    тратилось бы слишком много усилий на одну только загрузку ее из
    собственного файйла. В приложении C справочника по языку Бейсик
    приведен способ "упаковки" программы на машинном языке в область
    памяти за пределами рабочей области интерпретатора. Приведем пример
    применения другого способа.
 
      На Фиг. 10.8 показана программа, написанная на языке
    ассемблера, которой мы воспользуемся. Эта программа обращается к
    BIOS для сдвига изображения на экране. Рассмотрев параметры,
    хранящиеся в регистрах CX и DX, можно увидеть, что сдвигаемое окно
    отображает лишь часть экрана. Мы будем исползовать приведенную


    программу для разбиения экрана на несколько окон, в каждом из
    которых сдвиг может производиться независимо. Поскольку средства
    реализации этого в языке Бейсик отсутствуют, понадобится процедура
    на языке ассемблера.
 
             Microsoft (R) Macro Assembler Version 5.00                1/1/80 04:07:03
             Фиг. 10.8 Программа прокрутки окон на дисплее             Page     1-1
 
 
                                           PAGE ,132
                                           TITLE      Фиг. 10.8 Программа прокрутки окон на дисплее
              0000                        CODE SEGMENT
                                           ASSUME  CS:CODE
              0000                        SCROLL  PROC     FAR
              0000      55                      PUSH BP
              0001      8B EC                   MOV  BP, SP
              0003      8B 76 06                MOV  SI, [BP+6] ; Загрузка адреса параметра
              0006      8B 0C                   MOV  CX, [SI]   ; Загрузка параметра
              0008      0A C0                   OR   AL, AL
              000A      B7 07                   MOV  BH, 7
              000C      B8 0601                  MOV  AX, 601h
              000F      75 0C                   JNZ  WINDOW1    ; Определение требуемого окна
              0011      B9 0200                  MOV  CX, 200h   ; Окно 1
              0014      BA 1010                  MOV  DX, 1010h
              0017                        DO_SCROLL:
              0017      CD 10                   INT  10h
              0019      5D                      POP  BP
              001A      CA 0002                  RET  2
              001D                        WINDOW1:
              001D      B9 0514                  MOV  CX, 514h   ; Окно 2
              0020      BA 1224                  MOV  DX, 1224h
              0023      EB F2                   JMP  DO_SCROLL
              0025                        SCROLL  ENDP
              0025                        CODE ENDS
                                           END
 
          Фиг. 10.8 Процедура сдвига изображения для Бэйсика
 
      Как можно увидеть на листинге ассемблирования на Фиг. 10.8, для
    определения, в каком из двух окон должен производиться сдвиг,
    используется входной параметр. Программа, написанная на языке
    Бейсик, передает этот параметр в ассемблерную подпрограмму
    оператором CALL. На Фиг.10.9(а) показано содержимое стека в момент
    вызова в Бэйсике процедуры SCROLL. Оператор CALL помещает в стек
    адрес параметра перед выполнением дальнего вызова (FAR CALL)
    подпрограммы на машинном языке. Адрес в стеке является смещением
    параметра относительно регистра DS. Первые команды процедуры SCROLL
    извлекают этот адрес из регистра SI для того, чтобы загрузить
    истинное значение в регистр CX. На Фиг.10.9(b) показано содержимое
    стека после того, как процедура SCROLL поместила содержимое
    регистра BP в стек, а затем переслала содержимое регистра SP в
    регистр BP. Обратите внимание, что параметр находится в шести
    байтах от вершины стека. Если бы программа на языке Бейсик
    передавала более одного параметра, перед вызовом они были бы
    аналогичным образом помещены в стек. Забегая вперед, заметим, что
    перед возвратом процедура, используя команду RET 2, извлекает
    параметры из стека. Интерпретатор Бейсика предполагает, что перед
    возвратом подпрограмма удаляет параметры из стека.
 
            ГДДДДДДДДДДДДґ          ГДДДДДДДДДДДДґ
      SPДДДДД>і Смещение   і  SPДДДД>і Старое зна-і
            і возврата   і          і чение BP   і<ДДДДBP
            ГДДДДДДДДДДДДґ          ГДДДДДДДДДДДДґ
            і Сегмент    і          і Смещение   і [BP+2]
            і возврата   і          і возврата   і
            ГДДДДДДДДДДДДґ          ГДДДДДДДДДДДДґ
            і Смещение   і          і Сегмент    і [BP+4]
            і аргумента  і          і возврата   і
            ГДДДДДДДДДДДДґ          ГДДДДДДДДДДДДґ
                              і Смещение   і [BP+6]
                              і аргумента  і
                              ГДДДДДДДДДДДДґ
 
               (a)                        (b)
             Фиг. 10.9 Стек при вызове процедуры
 
      Подпрограмма SCROLL в зависимости от значения параметра
    обрабатывает одно из двух окон экрана.  Если параметр равен нулю,
    то изображение в окне, заданном координатами (2, 0) и (16, 16)
    сдвигается вверх на одну строку.  Если параметр не равен нулю, то
    на одну строку вверх сдвигается изображение в окне (5, 20), (18,
    36).  Перемещается текст только в заданном окне, остальной текст
    или данные на экране остаются неподвижными.  Реализация такого
    оконного режима входит в функцию сдвига BIOS.  Для ее использования
    требуется лишь вызвать BIOS с правильно заданными параметрами.
 
      На Фиг.  10.10 представлена программа на языке Бейсик,
    обращающаяся к процедуре SCROLL.  В этом простом примере в каждое
    окно записывается строка символов, а затем вызывается процедура
    сдвига текста вверх.  Эта Бэйсик-программа не более чем
    иллюстрирует использование сдвига окон.
 
      Первое, на что следует обратить внимание, это - способ загрузки
    программы на машинном языке в систему.  Программа содержится в
    символьной строке P$.  Каждый символ в строке соответствует одному
    байту объектного кода из Фиг.  10.8.  В программу на Бэйсике эта
    программа вводится с клавиатуры по листингу ассемблирования.  Это -
    одна из причин, по которой применение рассмотренного способа
    ограничено лишь короткими программами.  При вводе программы таким
    способом очень легко сделать ошибки.
A   
            1 CLS
            5 DEFINT A-Z
            10 P$=CHR$(&H55)+CHR$(&H8B)+CHR$(&HEC)+CHR$(&H8B)+CHR$(&H76)+CHR$(&H6)
            20 P$=P$+CHR$(&H8B)+CHR$(&HC)+CHR$(&HA)+CHR$(&HC9)+CHR$(&HB7)+CHR$(&H7)
            30 P$=P$+CHR$(&HB8)+CHR$(&H1)+CHR$(&H6)+CHR$(&H75)+CHR$(&HC)+CHR$(&HB9)
            40 P$=P$+CHR$(&H0)+CHR$(&H2)+CHR$(&HBA)+CHR$(&H10)+CHR$(&H10)+CHR$(&HCD)
            50 P$=P$+CHR$(&H10)+CHR$(&H5D)+CHR$(&HCA)+CHR$(&H2)
            60 P$=P$+CHR$(&H0)+CHR$(&HB9)+CHR$(&H14)
            70 P$=P$+CHR$(&H5)+CHR$(&HBA)+CHR$(&H24)+CHR$(&H12)+CHR$(&HEB)+CHR$(&HF2)
            100 ENTRY!=(PEEK(VARPTR(P$)+1))+(PEEK(VARPTR(P$)+2))*256
            110 IF ENTRY!>32768! THEN ENTRY%=ENTRY!-65536! ELSE ENTRY%=ENTRY!
            120 A$="АБВГДЕЖЗИК"
            130 L=0:R=1
            140 LOCATE 1,1:PRINT "Пример сдвига окна . . .э
            200 LOCATE 15,1:PRINT A$;
            210 CALL ENTRY%(L)
            220 LOCATE 18,21:PRINT A$;
            230 CALL ENTRY%(R)
            240 A$=RIGHT$(A$,9)+LEFT$(A$,1)
            250 GOTO 200
           Фиг. 10.10 Бэйсик-программа для сдвига окон
 
      Поскольку программа на машинном языке задана в строке P$, то
    для определения адреса этой строки программа на языке Бейсик
    использует функцию VARPTR.      Для оператора CALL необходим адрес
    подпрограммы, поэтому для его нахождения и используется функция
    VARPTR.  Воспользовавшись информацией из приложения C справочника
    по Бейсику, можно найти адрес строки во втором и третьем байтах
    дескриптора строки.  Возвращаемое функцей VARPTR значение является
    адресом дескриптора строки для P$.    Программа извлекает адрес
    строки из дескриптора и присваивает его значение переменной ENTRY!.
    Поскольку это значение может находиться в диапазоне от 0 до 65536,
    подпрограмма должна преобразовать его в целое значение длиной в
    одно слово, со значением от от -32768 до 32767.  Это слово
    помещается в переменную ENTRY%.  В остальных строках программы в
    сдвигаемые окна записывается символьная строка, а затем для
    перемещения текста вызывается подпрограмма SCROLL.
 
      При запуске этой программы вы увидите, что данные в двух окнах
    перемещаются независимо.  Такой прием позволяет задать два
    различных окна на экране и перемещать в них текст независимо друг
    от друга.  Если написать немного более длинную программу, можно
    было бы ограничить каждое окно рамкой, чтобы деиствительно отделить
    их друг от друга.  Применение подобных методов построения окон
    позволяет писать довольно симпатичные программы с одновременным
    выводом на экран наскольких фрагментов текста.
 
      Прежде чем покончить с этой программой, давайте просмотрим
    через отладчик часть программы, написанную на машинном языке.  Для
    этого надо иметь готовую к выполнению программу ДОС DEBUG.    Это
    достигается следующим образом:  сначала загружается программа
    DEBUG, а затем загружается BASIC.COM (или BASICA.COM, если
    используется расширенный Бейсик).  После загрузки программы Бейсик
    замените первый символ в P$ (и соответственно, первый байт
    программы на машинном языке), на CHR$($HCC).  Это - код для
    прерывания INT 3 прерывания по точке прерывания.  Теперь, когда во
    время выполнения программы на языке Бейсик она вызывает
    подпрограмму на машинном языке, управление получает программа
    DEBUG.  Теперь можно вновь заменить код 0CCH на исходное значение
    (в данном случае 055H).  Программу DEBUG можно использовать для
    трассировки программы на машинном языке.  Конечно, если программа
    на языке ассемблера хорошо написана и коротка, то такая отладка не
    так необходима.  На самом же деле вы, вероятно, заметите, что в
    большинстве случаев из-за ошибок при вводе с клавиатуры программы
    на машинном языке в строку интерпретатора Бейсик возникает
    множество проблем.




Содержание раздела