10.5. Процедура Бэйсика BLOAD

При первом способе подпрограмма на машинном языке добавляется к программе для интерпретатора Бэйсика. Пожалуй, использование интерпретатора Бейсика является наиболее распространенным методом написания программ для персональной ЭВМ. Подпрограмма на языке ассемблера, которую предполагается включить в разрабатываемую программу, довольно велика - более 100 байт. Ассемблерную процедуру такой длины трудно вставить в текст программы на языке Бейсик, способ, позволяющий сделать это будет рассмотрен в следующем примере.

Функция, которую мы добавляем к программе на языке Бейсик позволяет выводить на принтер графические изображения. IBM PC снабжена графическими средствами. Графические команды позволяют программно управлять отдельными точками, выводимыми на принтер, во многом подобно тому, как в графическом режиме адаптер цветного дисплея дает программисту возможность управлять отдельными точками растра. На Фиг. 10.4 представлены графические команды, которые потребуются в рассматриваемом примере. Практически, графические функции реализуются на принтере через управляющие последовательности символов. Вместо символа в коде ASCII программа выдает на принтер служебный символ (27 в коде ASCII). Следующие за ним символы задают уже не символы для вывода на печать, а определенные действия принтера. Как видно из Фиг. 10.4, существуют команды для вывода на принтер изображения точки, в результате выполнения которых печатается определенная точка изображения.

Команда Действие
ESC + "3" + n Установка промежутка между строками n/216
Esc + "K" +n1+n2+v1...vk Печатать образы точек v1...vk (k = n1 + 256*n2) как 480 точек поперек страницы

Фиг.10.4 Графические команды для принтера

Приведенная на Фиг. 10.5 программа использует указанные команды для вывода на принтер образа экрана графического дисплея размером 320*200 точек. Каждая точка растра передается на принтер. Если точка на экране имеет цвет фона, то соответствующая точка на печать не выдается. Если точка окрашена в один из трех основных цветов, то программа выводит на печать черную точку. Эта программа не масштабирует изображение, поэтому окружность на экране может отобразиться в эллипс на принтере. Между тремя основными цветами не проводится различий. Цветное изображение превращается в черно-белое.

Подпрограмма PRINT_SCREEN является процедурой типа FAR. Вызов ее из языка Бейсик является вызовом типа FAR, поэтому и возврат в программу должен быть соответствующего типа. Последовательность ESC + "3" + 24 устанавливает такой интервал между строками печати, что один ряд точек вплотную примыкает к другому. В печатающей головке имеется восемь иголок, расстояние между которыми равно 1/72 дюйма. Если сделать интервал между строками равным 8/72 дюйма (или 24/216 дюйма), то ряды точек соединятся. Приведенный фрагмент программы показывает способ пересылки на устройство печати последовательности служебных символов. Управляющая последовательность символов и чисел пересылается на принтер как обычные символы. Остальное обеспечивает устройство печати.

При каждом проходе печатающей головки на бумаге остается по восемь рядов точек (по одному на каждую иголку печатающей головки) в каждой из 320 колонок. От метки NEXT_ROW в программе последовательность ESC + "K" + 64 + 1 пересылается на принтер. Это означает, что последующие 320 байт (64 + 1*256) являются образами точек для получения графического изображения на принтере. В графическом режиме "K" на принтере можно получить изображение шириной до 480 точек.

Для считывания точек с дисплея программа использует видео функцию BIOS . Эта функция считывает восемь рядов точек текущнго столбца и собирает их в один байт: "1" означает, что точка имеет основной цвет и должна появиться на бумаге. Цикл продолжается через метку NEXT_COLUMN - до тех пор, пока все 320 столбцов (что соответствует 320 байтам) не будут переданы на принтер . После перехода принтера на новую строку при помощи служебных символов "возврат каретки" и "перевод строки" (13 и 10 в коде ASCII), программа пересылает следующую группу из восьми рядов. За 25 проходов печатающей головки выводятся все 200 рядов. Возврат в интерпретатор Бейсика производится при помощи возврата типа FAR.

В рассматриваемой программе было бы удобно использовать процедуру PRINT. Эта процедура выдает один байт на принтер при помощи функции печати BIOS. Функция помещает необходиые для базовой системы ввода-вывода установки регистров в определенное место. Если не использовать указанную функцию, то программа сама должна была бы устанавливать регистры AH и DX равными нулю перед каждым вызовом процедуры PRINT.


Microsoft (R) Macro Assembler Version 5.00                  1/1/80 04:03:56
Фиг. 10.5 Печать графической копии дисплея                        Page  1-1
PAGE  ,132
                         TITLE    Фиг. 10.5 Печать графической копии дисплея

0000                     STACK    SEGMENT STACK
0000    0040[                     DW        64 DUP (?)
             ????
            ]
0080                     STACK    ENDS

        = 001B           ESC      EQU       27        ; Символ Escape

0000                     CODE     SEGMENT
                                  ASSUME    CS:CODE

0000                     PRINT_SCREEN       PROC    FAR
0000    B0 1B                     MOV       AL, ESC   ; Установка перевода строки на 1/8 дюйма
0002    E8 0060 R >               CALL      PRINT
0005    B0 33                       
MOV     AL, '3'
0007    E8 0060 R >               CALL      PRINT
000A    B0 18                     MOV       AL, 24    ; 1/8 = 24/216 дюйма
000C    E8 0060 R >               CALL      PRINT
000F    BA 0000  >                MOV       DX, 0     ; Номер строки
0012                     NEXT_ROW:
0012    B0 1B                     MOV       AL, ESC
0014    E8 0060 R >               CALL      PRINT
0017    B0 4B                     MOV       AL, 'K'
0019    E8 0060 R >               CALL      PRINT
001C    B0 40                     MOV       AL, 320-256
001E    E8 0060 R >               CALL      PRINT
0021    B0 01                     MOV       AL, 1
0023    E8 0060 R >               CALL      PRINT
0026    B9 0000  >                MOV       CX, 0     ; Номер столбца
0029                     NEXT_COLUMN:
0029    52                        PUSH      DX        ; Сохранение номера строки
002A    BB 0008  >                MOV       BX, 8     ; Число одновлеменно обрабатываемых
точек
002D                     NEXT_DOT:
002D    D0 E7                     SHL       BH, 1     ; Освобождение младшего разряда
002F    B4 0D                     MOV       AH, 13    ; Чтение цвета точки из памяти дисплея
0031    CD 10                     INT       10h
0033    0A C0                     OR        AL, AL
0035    74 03                     JZ        BACKGROUND ; Проверка на цвет фона
0037    80 CF 01 >                OR        BH, 1     ; Не фон, необходимо вывести 
                                                      ; точку на печать
003A                     BACKGROUND:
003A    42                        INC       DX        ; Переключение на следующую строку
003B    FE CB                     DEC       BL        ; Уменьшение счетчика строк в 
                                                      ; данном проходе
003D    75 EE                     JNZ       NEXT_DOT
003F    8A C7                     MOV       AL, BH    ; Печать 8-ми точек
0041    E8 0060 R >               CALL      PRINT     ; Вывод на печать
0044    5A                        POP       DX        ; Восстановление номера строки
                                                      ; начала прохода
0045    41                        INC       CX        ; Переключение на следуюий столбец
0046    81 F9 0140 >              CMP       CX, 320   ; Все столбцы выведены?
004A    75 DD                     JNZ       NEXT_COLUMN
004C    B0 0D                     MOV       AL, 13    ; Переход на следующую строку на принтере
004E    E8 0060 R >               CALL      PRINT
0051    B0 0A                     MOV       AL, 10
0053    E8 0060 R >               CALL      PRINT
0056    83 C2 08 >                ADD       DX, 8     ; Переключение на следующую группу 
                                                      ; из 8 строк
0059    81 FA 00C8 >              CMP       DX, 200   ; Все строки выведены?
005D    72 B3                     JB        NEXT_ROW
005F    CB                        RET                 ; Возврат в BASIC
0060                     PRINT_SCREEN       ENDP

0060                     PRINT    PROC   
NEAR
0060    52                        PUSH      DX
0061    B4 00                     MOV       AH, 0     ; Печать символа, находящегося 
                                                      ; в регистре AL
0063    BA 0000  >                MOV       DX, 0
0066    CD 17                     INT       17h
0068    5A                        POP       DX
0069    C3                        RET
006A                     PRINT    ENDP

006A                     CODE     ENDS
                         END

                                  Фиг. 10.5    Печать графического экрана (продолжение)

Как же обратиться к этой процедуре из программы, написанной на языке Бейсик? В языке Бейсик существуют два способа подключения подпрограмм. Во время работы интерпретатор Бейсика использует оставшуюся память системы (до 64 кбайт) в качестве рабочей области. Если в системе более 96 кбайт памяти, часть памяти будет не доступна для интерпретатора Бейсика. Лучше всего поместить нашу процедуру в эту область. Если свободной области памяти нет, то можно специально выделить некоторый объем памяти из рабочей области интерпретатора Бейсика для хранения подпрограммы. В данном примере подпрограмма будет храниться вне рабочей области интерпретатора Бейсика. В следующем примере будет показано, как включить процедуру в контролируемую нтерпретатором Бейсика область памяти.

На Фиг. 10.6 показана последовательность действий для подготовки подпрограммы к дальнейшему использованию. Соответствующая информация приведена в приложении C справочника по языку Бейсик. Программа (на Фиг. 10.6) предназначена для машины с оперативной памятью 96 кбайт и более. Программа ассемблируется обычным образом. При редактировании связей задается опция /H. Редактор связей создает файл типа .EXE таким образом, что программа загружается в верхние адреса оперативной памяти, а не с самого низкого из доступных адресов.

Чтобы подключить процедуру к программе, написанной на языке Бейсик, нам потребуется программа DEBUG. После загрузки программы на языке Бейсик во время работы программы DEBUG и уточнения значений регистров, загружаем процедуру на языке ассемблера. Приведенный пример реализован на машине с памятью 128 кбайт. Значение регистра CS, равное 1FF9H, указывает на то, что программа помещена в 70H байт от конца оперативной памяти. Заметим, что рассматриваемая программа имеет объем около 6AH байт, так что редактор связей разместил программу с самого старшего адреса памяти, допускающего выравнивание по границе параграфа. Следует также заметить, что эта программа является сегментно-перемещаемой. Это означает, что ее можно перемещать в памяти поскольку первая ее команда имеет смещение 0 относительно текущего сегмента кода. При переносе этой программы на машину с большим или меньшим объемом памяти эта особенность оказывается решающей.


B>A:MASM FIG10-5,,,;

The IBM Persona Computer MACRO Assembler  Version 1.00 (C)Copyright IBM Corp 1981

Warning Severe
Errors  Errors
0       0

B>A:LINK FIG10-5,,,/H;

IBM Personal Computer Linker Version 1.10 (C)Copyright IBM Corp 1982

Warning: No STACK segment

There was 1 error detected

B>A:DEBUG A:BASIC.COM
-R

AX=0000 BX=0000 CX=2B80 DX=0000 SP=FFF0 BP=0000 SI=0000 DI=0000
DS=04B5 ES=04B5 SS=04B5 CS=04B5 IP=0100 NV UP DI PL NZ NA PO NC
04B5:0100 E91329         JMP      2A16
-NFIG10-5.EXE
-L
-R

AX=0000 BX=0000 CX=006A DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=04B5 ES=04B5 SS=1FF9 CS=1FF9 IP=0000 NV UP DI PL NZ NA PO NC
1FF9:0000 B01B           MOV    AL,1B

-RSS
SS 1FF9 :4B5

-RCS 
CS 1FF9 :4B5

-RIP IP 0000 :100

-G
 

---- В интерпретаторе Бэйсика введите команды


DEF SEG = &H1FF9
BSAVE "FIG10-5",0,&H70
 
Фиг. 10.6 (а) Создание подпрограммы для Бэйсика

B>A:MASM FIG10-5,,,;

The IBM Persona Computer MACRO Assembler Version 1.00 (C)Copyright IBM Corp 1981

Warning Severe
Errors  Errors
0       0

B>A:LINK FIG10-5,,,/H;

IBM Personal Computer Linker Version 1.10 (C)Copyright IBM Corp 1982

Warning: No STACK segment

There was 1 error detected

B>A:DEBUG A:BASIC.COM /M:&H8000
-R

AX=0000 BX=0000 CX=2B80 DX=0000 SP=FFF0 BP=0000 SI=0000 DI=0000
DS=04B5 ES=04B5 SS=04B5 CS=04B5 IP=0100 NV UP DI PL NZ NA PO NC
04B5:0100 E91329         JMP      2A16
-NFIG10-5.EXE
-L
-R
AX=0000 BX=0000 CX=006A DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=04B5 ES=04B5 SS=0FF9 CS=0FF9 IP=0000 NV UP DI PL NZ NA PO NC
0FF9:0000 B01B           MOV    AL,1B

-RSS
SS 0FF9 :4B5

-RCS
CS 1FF9 :4B5

-RIP
IP 0000 :100

-G
 
---- В интерпретаторе Бэйсика; введите команды

DEF SEG = &H0FF9
BSAVE "FIG10-5",0,&H70
 
Фиг. 10.6 (b) Созданиеподпрограммы для Бэйсика на машине с 64K
Теперь мы имеем дело с интерпретатором Бейсика. Нам необходимо восстановить содержимое регистров таким, каким оно было после загрузки Бейсика. После того, как интерпретатор Бейсика запущен, для локализации подпрограммы используется команда DEF SEG. Команда BSAVE помещает обратно на дискету объектный код, готовый к новой загрузке из Бейсика при помощи команды BLOAD. В части (b) Фиг. 10.6, повторяются действия из части (а), но для машины с объемом памяти 64 кбайт. Различие здесь состоит в том, что интерпретатор Бейсика не может использовать всю память под рабочую область. Опция /M в командной строке Бейсика ограничивает рабочую область Бейсика и оставляет место для подпрограммы. Аналогичная команда потребуется и при запуске программы.

Программой DEBUG можно воспользоваться для вашей ассемблерной процедуры и при работе интерпретатора Бейсика. Включите в команду G при запуске программы Бейсика установку контрольной точки в подпрограмме. По достижении контрольной точки работа интерпретатора Бейсика приостанавливается, и производится обычная для программы DEBUG выдача содержимого регистров.

Теперь все готово для выполнения подпрограммы на языке ассемблера как части программы на языке Бейсик. Снова предположим, что система располагает 128 кбайтами памяти, и выполним следующую последовательность действий:


введите "BASIC" на уровне команд DOS; 
ведите "SCREEN1" во время работы интерпретатора Бейсика.
 
Фиг. 10.7 Печатная копия экрана

Эти действия вводят нас в интерпретатор и переводят режим изображения на размер 320*200 точек. На Фиг. 10.7. показаны оставшиеся события этой истории. Команда BLOAD загружает процедуру в ту же область памяти, из которой она была сохранена. При желании в команде BLOAD можно задать параметры, обеспечивающие загрузку программы в другую область памяти. Оператор LINE дает процедуре графической распечатки экрана информацию для печати. Для вызова этой процедуры мы используем команду DEF SEG, чтобы установить значение регистра CS на процедуру. Значение регистра IP для процедуры помещается в простую переменную. Оператор CALL осуществляет дальний вызов по заданному адресу. Фиг. 10.7 представляет собой копию реальной распечатки, полученной при выполнении приведенной программы.

Если в системе 64Кбайт памяти, то программа будет отлична в двух аспектах. Для вызова интерпретатора Бейсика используется команда BASIC/M:&H8000, резервирующая верхнюю часть памяти для нашей ассемблерной процедуры, а команда DEF SEG задает адрес подпрограммы, как это было сделано в части (b) Фиг. 10.6.