Программирование на БК-0010-01/Глава 6: различия между версиями

Материал из Emuverse
(http://www.vak.ru/doku.php/proj/bk/bk6prog)
 
(Материал удален по требованию автора)
 
Строка 1: Строка 1:
{{ДИ}}
'''Материал удален по требованию автора.'''
{{TOCright}}
 
<pre>
     6.1. Использование подпрограмм в кодах при работе на Бейсике
 
   Одним из  приемов  увеличения  возможностей  программы  на  Бейсике
является   использование   подпрограмм  в  кодах.  Правда,  этот  путь
несколько половинчатый - почему бы сразу не писать  всю  программу  на
ассемблере ?  Поскольку Бейсик по-прежнему занимает много памяти, то и
эффективность этого способа сомнительна.  Использовать подпрограммы  в
кодах   в   Бейсике,  пожалуй,  целесообразно  только  при  отсутствии
описанных в гл.5 инструментальных средств,  а  также  в  тех  случаях,
когда Вы не хотите или не умеете писать программы в кодах,  а улучшить
свою  программу  на  Бейсике  хочется.  В   последнем   случае   можно
использовать чьи-либо готовые подпрограммы в кодах.
   Для подготовки  подпрограммы  в  кодах  с  помощью  Бейсика   часто
используется  такой прием:  коды команд записываются в операторе DATA,
из которого затем в цикле  читаются  оператором  READ  и  заносятся  в
память оператором POKE.
   Для того,  чтобы зарезервировать  достаточно  места  в  памяти  для
размещения  подпрограмм,  необходимо перед началом работы дать команду
CLEAR в непосредственном режиме Бейсика:
 
                           CLEAR B,A
где
     B - количество байт, отводимых под символьные переменные;
     A - адрес верхней границы памяти, отведенной для программы на
         Бейсике.
 
   Например, если начальный адрес подпрограммы в кодах равен 30000, то
можно ввести  оператор  CLEAR  250,&amp;O30000 .   После  исполнения этого
оператора транслятор с языка Бейсик  использует  только  область  ОЗУ,
расположенную до адреса 30000. А с адреса 30000 могут быть расположены
подпрограммы в машинных кодах.
   Две команды  Бейсика  позволяют  записывать  и читать с магнитофона
участки ОЗУ,  в которых могут размещаться  подпрограммы  в  кодах  или
таблицы изображений (спрайтов).
 
                       BSAVE"имя",начало,конец
 
   По этой команде область  ОЗУ  с  указанным  начальным  и  конечным
адресом записывается на магнитофон в виде файла.
   Программа с МЛ может быть загружена в ОЗУ и запущена на выполнение
командой Бейсика:
                       BLOAD"имя",R,адрес
   Если в данной команде отсутствует первая запятая с буквой  "R",  то
произойдет только загрузка программы в ОЗУ с указанного адреса.
   Обычно, чтобы   не   возиться   с   загрузкой   множества   файлов,
подпрограмму  в  кодах  не  записывают  отдельно,  а  так  и  хранят в
программе на Бейсике в операторе DATA.  При выполнении программы  коды
переписываются в ОЗУ,  потом задается адрес запуска подпрограммы и она
вызывается в любом нужном месте программы на Бейсике.
   Здесь будут  рассмотрены  два примера использования в программах на
языке Бейсик подпрограмм в машинных кодах.
 
   Пример 1. Вывод спрайта и управление его движением.
   Этот пример  аналогичен  второму  примеру из п.5.3.3.  Для вывода и
стирания спрайта  используются  подпрограммы  в  кодах,  а  управление
движением спрайта осуществляется программой на Бейсике.
   Подпрограммы вывода и стирания  спрайта  аналогичны  приведенным  в
п.5.3.3:
 
; вывод спрайта на экран
035000     012700          MOV    #MEN,R0
035002     035070
035004     011501          MOV    (R5),R1   ;адрес вывода спрайта
035006     012002          MOV    (R0)+,R2
035010     012003          MOV    (R0)+,R3
035012     010204    A:    MOV    R2,R4
035014     010146          MOV    R1,-(SP)
035016     112021    B:    MOVB   (R0)+,(R1)+
035020     077402          SOB    R4,B
035022     012601          MOV    (SP)+,R1
035024     062701          ADD    #100,R1
035026     000100
035030     077310          SOB    R3,A
035032     000207          RTS    PC        ;выход из подпрограммы
; чистка спрайта на экране
035034     012700          MOV    #MEN,R0
035036     035070
035040     011501          MOV    (R5),R1   ;адрес стирания спрайта
035042     012002          MOV    (R0)+,R2
035044     012003          MOV    (R0)+,R3
035046     010204    C:    MOV    R2,R4
035050     010146          MOV    R1,-(SP)
035052     105021    D:    CLRB   (R1)+
035054     077402          SOB    R4,D
035056     012601          MOV    (SP)+,R1
035060     062701          ADD    #100,R1
035062     000100
035064     077310          SOB    R3,C
035066     000207          RTS    PC        ;выход из подпрограммы
; спрайт, закодированный в формате ГРЕД
035070               MEN: .#2.#12.#1640.#1700.#140300.#37774.#1703
                          .#1700.#1700.#6060.#6060
035116                    .#36074
 
   В отличие от  примера  п.5.3.3,  где  операции  вывода  и  стирания
спрайта  были  встроены  в  программу,  здесь  они  оформлены  в  виде
подпрограмм,  которые можно вызывать функцией Бейсика  USR.  Выход  из
подпрограммы осуществляется, как обычно, командой RTS PC.
   Одновременно в программе могут быть определены 10 различных функций
USR0..USR9.  В  данном  примере  мы используем только две подпрограммы
(соответственно, функции USR0 и USR1).
   Функция USR позволяет передать подпрограмме в кодах один параметр и
вернуть одно значение того же типа.  Функция USR помещает в  R5  адрес
передаваемого  параметра,  а  в  R3  - его тип (единица в 15-м разряде
означает символьную строку,  информация  о  других  типах  хранится  в
младшем байте R3:  -1 - целый,  0 - вещественный двойной точности, 1 -
вещественный одинарной точности; если аргумент - символьная строка, то
в  качестве аргумента передаются два слова - длина и адрес строки).  В
данном примере мы передаем подпрограммам адрес ОЗУ экрана,  куда нужно
вывести (или где стереть) спрайт.  Поскольку адрес будет размещаться в
переменной целого типа, анализировать R3 нет нужды.
   Отметим также,  что  в  п.5.3.3 "по ходу действия" в R5 сохранялось
значение R1, здесь же мы R1 сохраним в стеке, чтобы не испортить адрес
аргумента.
   Подпрограммы и закодированный спрайт мы разместим с  адреса  35000.
Тогда  перед  набором  программы  (или загрузкой ее с магнитной ленты)
необходимо выполнение оператора CLEAR ,&amp;О35000.  Этот  оператор  можно
вставить   первой   строкой   в   программу,   чтобы   он   выполнялся
автоматически,  но вот беда - не все экземпляры БК-0010-01  отработают
его правильно. Это связано с различиями версий Бейсика в ПЗУ БК разных
лет выпуска.
   Для того,  чтобы  автоматизировать  ввод  подпрограмм,  их  коды мы
разместим в операторе DATA,  откуда  потом  в  цикле  будем  читать  и
переписывать по адресам ОЗУ, начиная с 35000.
 
10 DATA &amp;O012700,&amp;O035070,&amp;O011501,&amp;O012002,&amp;O012003,&amp;O010204,&amp;O010146
15 DATA &amp;O112021,&amp;O077402,&amp;O012601,&amp;O062701,&amp;O100,&amp;O077310,&amp;O207
20 DATA &amp;O012700,&amp;O035070,&amp;O011501,&amp;O012002,&amp;O012003,&amp;O010204,&amp;O010146
25 DATA &amp;O105021,&amp;O077402,&amp;O012601,&amp;O062701,&amp;O100,&amp;O077310,&amp;O207
30 DATA 2,&amp;O12,&amp;O1640,&amp;O1700,&amp;O140300,&amp;O37774,&amp;O1703
35 DATA &amp;O1700,&amp;O1700,&amp;O6060,&amp;O6060,&amp;O36074
40 ?CHR$(140);CHR$(140)              'инициализируем экран
50 FOR A%=&amp;O35000 TO &amp;O35116 STEP 2% 'записываем подпрограммы в ОЗУ
60 READ D%
70 POKE A%,D%
80 NEXT A%
90 DEF USR0=&amp;O35000     'задаем адрес подпрограммы вывода спрайта
95 DEF USR1=&amp;O35034     'задаем адрес подпрограммы стирания спрайта
100 S%=&amp;O56036          'начальный адрес ОЗУ, где располагается спрайт
110 L%=USR0(S%)         'выводим спрайт
115 FOR L%=0% TO 150%   'задержка
116 NEXT
117 L%=USR1(S%)         'стираем спрайт
120 I%=PEEK(&amp;O177662)   'смотрим, какая клавиша была нажата
130 IF I%=&amp;O10 THEN IF S% MOD 64% &lt;&gt; 0% THEN S%=S%-1%   'влево
140 IF I%=&amp;O31 THEN IF S% MOD 64% &lt; &amp;O76 THEN S%=S%+1%  'вправо
150 IF I%=&amp;O32 THEN IF S%&gt;&amp;O43000 THEN S%=S%-&amp;O200      'вверх
160 IF I%=&amp;O33 THEN IF S%&lt;&amp;O76000 THEN S%=S%+&amp;O200      'вниз
170 GOTO 110
 
   Строки 50 - 80 производят загрузку команд и данных в область памяти
с адреса 35000 по 35116.
   Оператор DEF (строки  90-95)  определяет  подпрограммы  в  машинных
кодах под именем USR0 и USR1 и задает их начальный адрес.
   Текущее значение адреса спрайта  в  ОЗУ  экрана  хранится  в  целой
переменной S%.
   В строке 120 переменной I%  присваивается код  нажатой  клавиши,  в
зависимости  от  которого в строках 130 - 160 изменяется адрес спрайта
S%.
   Начальная установка  экрана (строка 40) необходима для того,  чтобы
привести экран в исходное состояние,  когда верхний левый угол  экрана
соответствует адресу 40000.
 
   Пример 2:
 
10 DATA &amp;O13701,&amp;O35102,&amp;O12737,&amp;O100,&amp;O177716,&amp;O13700,&amp;O35100
12 DATA &amp;O77001,&amp;O12737,0,&amp;O177716,&amp;O13700,&amp;O35100,&amp;O77001,&amp;O77115
14 DATA &amp;O12702,&amp;O400,&amp;O77201,&amp;O207
20 FOR A%=&amp;O35000 TO &amp;O35044 STEP 2
30 READ B%
40 POKE A%,B%
50 NEXT A%
60 DEF USR0=&amp;O35000
70 DATA 128,128,112,128,99,640,128,128,112,128,99,128,128,128
75 DATA 94,128,99,128,128,256,112,128,99,128,112,640
80 FOR C%=1 TO 13
90 READ T%,D%
100 POKE &amp;O35100,T%
110 POKE &amp;O35102,D%
120 I%=USR0(I%)
130 NEXT C%
 
   Программа на  Бейсике,  приведенная  в  этом  примере,   использует
подпрограмму в машинных кодах для получения мелодии.
   Строки 10-60 подготавливают  в  памяти,  начиная  с  адреса  35000,
подпрограмму в машинных кодах.
   Вся мелодия состоит из звуков.  Количество звуков равно  количеству
пар чисел,  перечисленных в строках 70-75.  В каждой паре чисел первое
число задает тональность, а второе - длительность звука.
   Строки 80-130 "исполняют" мелодию.
 
          6.2. Использование вещественной арифметики Бейсика
                     при программировании в кодах
 
   Вы уже знаете, что в системе команд процессора БК нет команд работы
с  вещественными  (действительными)  числами.  Как в Бейсике,  так и в
Фокале работа с вещественными числами организуется чисто программно. В
таком   случае,   почему  бы  не  использовать  записанные  в  ПЗУ  БК
подпрограммы, если надо производить какие-либо вычисления ?
   Использование подпрограмм  вещественной арифметики Фокала описано в
[15].  Здесь мы опишем использование арифметики Бейсика [8].  Сразу же
заметим, что формат вещественного числа в Бейсике и Фокале различен.
   Учтите также,  что применение  описываемого  здесь  метода  сделает
программу  непереносимой  -  она  уже  не сможет работать на БК-0010 с
Фокалом или на БК-0010-01 при  включенном  блоке  МСТД  (равно  как  и
программы,  использующие Фокал, не будут работать с Бейсиком). Хорошим
выходом было бы использование стандартных подпрограмм (из программного
обеспечения Электроники-60) или эмуляторов вещественной арифметики, но
это   доступно,   пожалуй,   только   профессиональным   программстам,
использующим  ЭВМ  более  высокого класса в качестве инструментальной.
Что же касается использования подпрограмм Бейсика,  то платой  за  это
будет  2К  памяти,  так  как область ОЗУ ниже адреса 4000 используется
Бейсиком для своих рабочих переменных и стека.
   Все расчеты  в Бейсике производятся с вещественными числами двойной
точности.  Если в программе на Бейсике  используются  числа  одинарной
точности, то перед вычислениями они все равно преобразуются к двойной.
Каков же формат вещественного числа в Бейсике ?
   Числа двойной точности занимают в памяти 4 слова (8 байт). При этом
старший разряд 1-го слова (63-ий разряд числа) - знак  числа,  разряды
7-14 (разряды 55-62 числа) - порядок (p),  а остальные 6 разрядов 1-го
слова и 2-ое,  3-е,  4-е слова (разряды 0-54  числа)  -  мантисса  (М)
(рис.26).
   Тогда значение числа N определяется по формуле:
 
         p-201     -1     -2     -3           -54    -55     p-201
N=(M+1) 2     =(1+2  a  +2  a  +2  a  + ... +2   a +2   а ) 2      ,
                      54     53     52            1      0
 
   где a  - значение i - го бита числа (0 или 1).
        i
 
   Число 201 -восьмеричное, остальные - десятичные.
 
&#9474; X (адрес числа)               &#9474; X+2                           &#9474; X+10
&#9474;                               &#9474;                               &#9474;
&#9474;63         р а з р я д ы       &#9474;           ч и с л а          0&#9474;
&#9500;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9532;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472; - - - &#9472;&#9472;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9508;
&#9474;    порядок (p)  &#9474;    м   а   н   т   и   с   с   а  (M)       &#9474;
&#9500;&#9472;&#9524;&#9472;&#9524;&#9472;&#9524;&#9472;&#9524;&#9472;&#9524;&#9472;&#9524;&#9472;&#9524;&#9472;&#9524;&#9472;&#9524;&#9472;&#9524;&#9472;&#9524;&#9472;&#9524;&#9472;&#9524;&#9472;&#9524;&#9472;&#9524;&#9472;&#9532;&#9472;&#9524;&#9472;&#9524;&#9472;&#9524;&#9472;&#9524;&#9472;&#9524;&#9472; - - - &#9472;&#9472;&#9472;&#9524;&#9472;&#9524;&#9472;&#9524;&#9472;&#9524;&#9472;&#9524;&#9472;&#9508;
&#9474;15     разряды слова      2 1 0&#9474;                               &#9474;
&#9474;   1-ое слово (2 байта)        &#9474; 2-ое, 3-е и 4-ое слова(6 байт)&#9474;
 
          Рис.26. Представление числа двойной точности
 
   Как же перевести число из привычного для  нас  десятичного  вида  в
двоичное представление числа двойной точности ?
   Для этого берется исходное число и делится на 2 до  тех  пор,  пока
его целая часть не будет равна 1.
   Если исходное  число  меньше  1,  то  вместо  деления  производится
умножение на 2 до тех пор,  пока целая часть не станет равна 1.  Затем
дробная часть числа переводится в двоичный код - мантисса готова.  201
(восьмеричное)   плюс   (или   минус,  если  производилось  умножение)
количество делений или умножений на 2 - получим порядок числа.
   Осталось "скомпоновать"   число:   последовательно   слева  направо
записываются знак (0 - для знака "+",  1 - для  знака  "-"),  порядок,
мантисса.  Остальные  биты  мантиссы  заполняются  нулями или мантисса
укорачивается справа так, чтобы общая длина числа равнялась 64 битам.
   Рассмотрим несколько  примеров перевода десятичных чисел в двоичные
числа двойной точности:
 
   Пример 1:  Исходное число: 9.5 . Делим на 2:
 
     9.5
     4.75   - результат после 1-го деления:
     2.375  - после 2-го деления;
     1.1875 - после 3-го деления.
 
   Дробная часть  числа,  равная  0.1875  переводится  в  двоичный код
посредством последовательного умножения на  2.  При  этом  если  после
умножения число стало больше 1, то целая 1 отбрасывается.
 
     0.1875 - умножается на 2;
     0.375  - умножается на 2;
     0.75   - умножается на 2:
     1.5    - отбрасывается 1 и умножается на 2:
     1      - все.
 
   Тогда двоичный  код  мантиссы  -  0011 (последовательно сверху вниз
переписывается первый столбец цифр, кроме первого 0). Было произведено
3  деления  на  2,  поэтому  порядок  числа равен 201 + 3 = 204 (числа
восмеричные) или 10000100 (двоичное).  Осталось "скомпоновать"  число:
так как число положительное,  то 63-ий бит равен 0,  тогда число имеет
следующий вид в двоичном коде:
 
0 10000100 0011 000000000000000000000000000000000000000000000000000.
 
Если X - адрес числа,  то код этого числа сохраняется по словам памяти
следующим образом:
 
     Адреса:  Содержимое:
     X         41030 (восьмеричное)
     X+2           0
     X+4           0
     X+6           0
 
   Пример 2:  Исходное число: -13.25. Отмечаем, что оно отрицательное,
и все остальные операции проделываем с его абсолютным значением. Делим
на 2:
        13.25
         6.625
         3.3125
         1.65625
 
   Берем дробную часть числа 0.65625 и переводим в двоичный код:
 
        0.65625
        1.3125
        0.625
        1.25
        0.5
        1
 
Получаем 10101. Порядок равен 201+3=204 (10000100).
Тогда число в двоичном коде будет равно:
 
1100001001010100000000000000000000000000000000000000000000000000
 
или четыре слова: 141124,0,0,0 в восьмеричном виде.
 
   Пример 3: Исходное число: 0.0234375. Умножаем на 2:
 
   0.0234375
   0.046875
   0.09375
   0.1875
   0.375
   0.75
   1.5
 
Переводим дробную часть числа 1.5 равную 0.5 в двоичный код: это будет
1.  Порядок равен 201-6=173 (числа восьмеричные).  Знак - 0 ("+"). Вид
числа в двоичном коде:
 
0011110111000000000000000000000000000000000000000000000000000000
 
или четыре слова: 36700,0,0,0 в восьмеричном виде.
 
   Как же  теперь  использовать  наши  умения  ?  Сначала надо поближе
познакомиться с тем, как Бейсик транслирует свою программу.
   Исходная программа   на  Бейсике  после  ее  запуска  командой  RUN
преобразуется в  последовтельность  адресов  подпрограмм,  реализующих
соответствующие   операторы  Бейсика,  и  исходных  данных:  констант,
адресов переменных и так  далее  [8].  Эти  подпрограммы,  как  и  сам
транслятор, делающий такое преобразование, зашиты (записаны) в ПЗУ.
   После того,  как указанная последовтельность  (ее  называют  "шитым
кодом") получена   в   ОЗУ,  в  регистр  R4  помещается  адрес  начала
последовательности,  и командой "JMP @(R4)+"  начинается  обращение  к
подпрограмме,    адрес    начала    которой    записан   в   указанной
последовательности первым. Передача управления от одной подпрограммы к
другой  осуществляется также по команде "JMP @(R4)+" ,  содержащейся в
конце каждой подпрограммы.
   Если в   программе  на  языке  ассемблера  программисту  необходимо
получить значение какой-либо функции (или арифметической операции), то
он  может  организовать  обращение к готовым подпрограммам,  зашитым в
ПЗУ.  Далее  под  словом  "операция"  подразумевается   арифметическая
операция или функция,  а под словом "операнд" - операнд арифметической
операции или аргумент функции.
   В таблице 19 приводится список адресов подпрограмм, при обращении к
которым   вычисляется   результат   соответствующей    функции    (или
арифметической операции).
   Операнды и результаты операций - числа двойной точности.
 
                         Таблица 19. Адреса подпрограмм Бейсика
     &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
     &#9474; Арифметические операции &#9474;  Адреса       &#9474; Количество    &#9474;
     &#9474;   и функции             &#9474; подпрограмм   &#9474; операндов     &#9474;
     &#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;
     &#9474;      + (сложение)       &#9474;  167144       &#9474;     2         &#9474;
     &#9474;      - (вычитание)      &#9474;  167124       &#9474;     2         &#9474;
     &#9474;      / (деление)        &#9474;  170776       &#9474;     2         &#9474;
     &#9474;      * (умножение)      &#9474;  170210       &#9474;     2         &#9474;
     &#9474;       SQR               &#9474;  171350       &#9474;     1         &#9474;
     &#9474;       SIN               &#9474;  173614       &#9474;     1         &#9474;
     &#9474;       COS               &#9474;  173566       &#9474;     1         &#9474;
     &#9474;       TAN               &#9474;  174306       &#9474;     1         &#9474;
     &#9474;       ATN               &#9474;  174434       &#9474;     1         &#9474;
     &#9474;       EXP               &#9474;  171762       &#9474;     1         &#9474;
     &#9474;       LOG               &#9474;  173052       &#9474;     1         &#9474;
     &#9474;       FIX               &#9474;  176212       &#9474;     1         &#9474;
     &#9474;       INT               &#9474;  176340       &#9474;     1         &#9474;
     &#9474;       RND               &#9474;  175176       &#9474;     1         &#9474;
     &#9474; подпрограмма преобразо- &#9474;  166760       &#9474;     1         &#9474;
     &#9474; вания результата в      &#9474;               &#9474;               &#9474;
     &#9474; целый тип               &#9474;               &#9474;               &#9474;
     &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9524;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9524;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
 
   Необходимо помнить,  что   для   нормальной   работы   подпрограмм,
указанных  в  таблице  19,  область  памяти с адресами от 2000 до 4000
должна быть свободной (эта  область  -  область  системных  переменных
Бейсика).
   Предлагаем Вашему вниманию небольшую  подпрограмму,  которая  может
облегчить Вам вызов нужных подпрограмм Бейсика.
   Для вызова нужной подпрограммы в регистрах должны быть подготовлены
следующие данные:
   R0 - число операндов (1 или 2);
   R1 - адрес первого операнда;
   R2 - адрес второго операнда (для операций с двумя операндами.
        При операциях с одним операндом значение несущественно);
   R3 - адрес подпрограммы операции (из табл.19);
   R5 - адрес результата.
   Эта вспомогательная подпрограмма работает аналогично транслятору  с
Бейсика  после  команды  RUN  -  формирует требуемый для вызова нужной
подпрограммы шитый код и передает ему управление.
   Последовательность адресов   подпрогрмм   и   данных   (шитый  код)
начинается с адреса A.
 
FUN: MOV    R0,-(SP)        ; сохранение
     MOV    R1,-(SP)          ; содержимого
     MOV    R2,-(SP)          ; регистров
     MOV    R3,-(SP)          ; в стеке;
     MOV    R4,-(SP)          ;
     MOV    R5,-(SP)          ;
     MOV    #A,R4           ; последовательность адресов
                              ; начинается с адреса А;
     MOV    #156170,(R4)+   ; адрес подпрограммы пересылки в стек;
     MOV    R1,(R4)+        ; адрес первого операнда;
     CMP    R0,#1           ; если операция с одним операндом,
     BEQ    C               ; то идти на метку C;
     MOV    #156170,(R4)+   ; засылка в стек второго операнда;
     MOV    R2,(R4)+        ; адрес второго операнда;
C:   MOV    R3,(R4)+        ; адрес нужной подпрогрммы записы-
                              ; вается в последовательность адресов;
     CMP    R3,#166760      ; если это не подпрограмма перевода
     BNE    G               ; вещественного в целое, идти на G;
     MOV    #156350,(R4)+   ; подпрограмма пересылки слова из стека
     BR     D                 ; (результат целого типа);
G:   MOV    #156334,(R4)+   ; либо пересылка вещественного числа
D:   MOV    R5,(R4)+        ; из стека по адресу, указанному в R5;
     MOV    #B,(R4)+        ; организовать выход из шитого кода;
     MOV    #A,R4           ; запустить шитый код на выполнение;
     JMP    @(R4)+            ;
B:   MOV    (SP)+,R5        ; восстановление
     MOV    (SP)+,R4          ; содержимого
     MOV    (SP)+,R3          ; регистров
     MOV    (SP)+,R2          ; из стека
     MOV    (SP)+,R1          ;
     MOV    (SP)+,R0          ;
     RTS    PC              ; возврат из подпрограммы
A:   .+22
 
   По команде   "MOV   #156170,(R4)+"   в    эту    последовательность
записывается   адрес  подпрограммы,  производящей  пересылку  значения
переменной в  стек,  а  по  команде  "MOV  R1,(R4)+"  -  адрес   самой
переменной, указанный в R1.
   Аналогично засылается в стек второй операнд, если нужен.
   После выполнения   любой   арифметической   подпрограммы  результат
получается в стеке.  Его необходимо  оттуда  извлечь  и  переслать  по
адресу,  заданному  в R5.  Для этого используется подпрограмма 156334,
пересылающая вещественное число (4 слова),  либо 156350,  пересылающая
одно слово, если результат целый.
   Пример цепочечных вычислений:
 
; Вычисляем выражение (4+7)*3.0625-1.25
     MOV    #2,R0           ;двухоперандная команда
     MOV    #AR1,R1         ;первое слагаемое
     MOV    #AR2,R2         ;второе слагаемое
     MOV    #167144,R3      ;адрес подпрограммы сложения
     MOV    #REZ,R5         ;адрес результата
     JSR    PC,FUN          ; складываем
     MOV    R5,R1           ;результат используем
                              ;как первый сомножитель
     MOV    #AR3,R2         ;второй сомножитель
     MOV    #170210,R3      ;адрес подпрограммы умножения
     JSR    PC,FUN          ; умножаем (результат там же - в REZ)
     MOV    R5,R1           ;результат используем как уменьшаемое
     MOV    #AR4,R2           ;вычитаемое
     MOV    #167124,R3      ;адрес подпрограммы вычитания
     JSR    PC,FUN          ; вычитаем
; Печатаем полученный результат на дисплей
     ADD    #10,R5          ;засылаем результат в стек;
     MOV    -(R5),-(SP)
     MOV    -(R5),-(SP)
     MOV    -(R5),-(SP)
     MOV    -(R5),-(SP)
     JSR    PC,@#164710     ;вызываем подпрограмму перевода
                              ;числа в символьную строку;
     ADD    #4,SP           ;восстанавливаем стек;
     MOV    #3027,R1        ;адрес символьной строки
     MOV    #20000,R2       ;ограничитель строки - пробел
     EMT    20              ;печатаем сформированную строку
; Аргументы:
AR1: .#40600.#0.#0.#0       ;4.0
AR2: .#40740.#0.#0.#0       ;7.0
AR3: .#40504.#0.#0.#0       ;3.0625
AR4: .#40240.#0.#0.#0       ;1.25
REZ: .#0.#0.#0.#0           ;результат
 
         6.3. Использование системных переменных МОНИТОРа БК
 
   Область ОЗУ  в  диапазоне адресов от 0 до 377 МОНИТОР БК использует
для хранения своих рабочих переменных (используются те адреса, которые
не   заняты  векторами  прерывания,  см.п.4.4.3).  В  этих  переменных
указываются текущие режимы работы устройств,  например,  режимы работы
дисплея.  Зная  о  назначении тех или иных переменных,  можно добиться
таких  эффектов,  которые  невозможны  при   "штатном"   использовании
системного программного обеспечения.
   Рассмотрим несколько   примеров   использования   системных  ячеек.
Примеры даны на Бейсике и на языке ассемблера.
 
                                 Таблица 20. Системные переменные
   &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
   &#9474;Адрес&#9474;Длина&#9474;           Назначение                            &#9474;
   &#9474;     &#9474;байт &#9474;                                                 &#9474;
   &#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;
   &#9474; 040 &#9474;  1  &#9474; Режим 32/64 (0 - режим "64", 377 - режим "32")  &#9474;
   &#9474; 041 &#9474;  1  &#9474; Инверсия экрана (0 - выкл., 377 - вкл.)         &#9474;
   &#9474; 042 &#9474;  1  &#9474; Режим расширенной памяти (0 - выкл., 377 - вкл.)&#9474;
   &#9474; 043 &#9474;  1  &#9474; Регистр (0 - LAT, 200 - РУС )                   &#9474;
   &#9474; 044 &#9474;  1  &#9474; Подчеркивание (0 - выкл., 377 - вкл.)           &#9474;
   &#9474; 045 &#9474;  1  &#9474; Инверсия символа (0 - выкл., 377 - вкл.)        &#9474;
   &#9474; 046 &#9474;  1  &#9474; Режим ИСУ (0 - выкл., 377 - вкл.)               &#9474;
   &#9474; 047 &#9474;  1  &#9474; Режим БЛР (0 - выкл., 377 - вкл.)               &#9474;
   &#9474; 050 &#9474;  1  &#9474; Режим ГРАФ (0 - выкл., 377 - вкл.)              &#9474;
   &#9474; 051 &#9474;  1  &#9474; Режим ЗАП (0 - выкл., 377 - вкл.)               &#9474;
   &#9474; 052 &#9474;  1  &#9474; Режим СТИР (0 - выкл., 377 - вкл.)              &#9474;
   &#9474; 053 &#9474;  1  &#9474; Режим 32/64 в служебной строке (0-"64",377-"32")&#9474;
   &#9474; 054 &#9474;  1  &#9474; Подчеркивание в служ. строке (0-выкл., 377-вкл.)&#9474;
   &#9474; 055 &#9474;  1  &#9474; Инверсия служ. строки (0 - выкл., 377 - вкл.)   &#9474;
   &#9474; 056 &#9474;  1  &#9474; Гашение курсора (0 - выкл., 377 - вкл.)         &#9474;
   &#9474; 104 &#9474;  1  &#9474; Код последнего введенного символа               &#9474;
   &#9474; 112 &#9474; 10  &#9474; Положения табуляторов (побитно при режиме "64") &#9474;
   &#9474; 126 &#9474;  2  &#9474; Адрес буфера программируемого ключа К10         &#9474;
   &#9474; 130 &#9474;  2  &#9474; Адрес буфера программируемого ключа К1          &#9474;
   &#9474; 132 &#9474;  2  &#9474; Адрес буфера программируемого ключа К2          &#9474;
   &#9474; 134 &#9474;  2  &#9474; Адрес буфера программируемого ключа К3          &#9474;
   &#9474; 136 &#9474;  2  &#9474; Адрес буфера программируемого ключа К4          &#9474;
   &#9474; 140 &#9474;  2  &#9474; Адрес буфера программируемого ключа К5          &#9474;
   &#9474; 142 &#9474;  2  &#9474; Адрес буфера программируемого ключа К6          &#9474;
   &#9474; 144 &#9474;  2  &#9474; Адрес буфера программируемого ключа К7          &#9474;
   &#9474; 146 &#9474;  2  &#9474; Адрес буфера программируемого ключа К8          &#9474;
   &#9474; 150 &#9474;  2  &#9474; Адрес буфера программируемого ключа К9          &#9474;
   &#9474; 153 &#9474;  1  &#9474; Тип операции в режиме ГРАФ (0 - СТИР, 1 - ЗАП)  &#9474;
   &#9474; 154 &#9474;  2  &#9474; Унитарный код положения графического курсора    &#9474;
   &#9474; 160 &#9474;  2  &#9474; Абсолютный адрес курсора в ОЗУ экрана           &#9474;
   &#9474; 162 &#9474;  2  &#9474; Константа смещения одного алфавитно-цифрового   &#9474;
   &#9474;     &#9474;     &#9474; символа относительно другого                    &#9474;
   &#9474; 164 &#9474;  2  &#9474; Длина ОЗУ экрана в символах                     &#9474;
   &#9474; 176 &#9474;  2  &#9474; Координата Х последней графической точки        &#9474;
   &#9474; 200 &#9474;  2  &#9474; Координата Y последней графической точки        &#9474;
   &#9474; 202 &#9474;  2  &#9474; Начальный адрес ОЗУ экрана                      &#9474;
   &#9474; 204 &#9474;  2  &#9474; Адрес начала информационной части экрана        &#9474;
   &#9474;     &#9474;     &#9474; минус 40000                                     &#9474;
   &#9474; 206 &#9474;  2  &#9474; Длина ОЗУ экрана в байтах                       &#9474;
   &#9474; 210 &#9474;  2  &#9474; Длина информационной части экрана               &#9474;
   &#9474; 212 &#9474;  2  &#9474; Код цвета фона на экране                        &#9474;
   &#9474; 214 &#9474;  2  &#9474; Код цвета символа на экране                     &#9474;
   &#9474; 216 &#9474;  2  &#9474; Код цвета фона в служебной строке               &#9474;
   &#9474; 220 &#9474;  2  &#9474; Код цвета символа в служебной строке            &#9474;
   &#9474; 260 &#9474;  2  &#9474; Адрес подпрограммы, выполняемой при прерывании  &#9474;
   &#9474;     &#9474;     &#9474; по вектору 60. Если 0, то ничего не выполняется &#9474;
   &#9474; 262 &#9474;  2  &#9474; Если 0, то код клавиши "ВК" равен 12, иначе 15  &#9474;
   &#9474; 264 &#9474;  2  &#9474; Начальный адрес загруженной программы           &#9474;
   &#9474; 266 &#9474;  2  &#9474; Длина загруженной программы                     &#9474;
   &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9524;&#9472;&#9472;&#9472;&#9472;&#9472;&#9524;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
   Примечание: В  буфере   программируемого   ключа   записана   длина
соответствующего ключа (в символах), далее - сами символы.
 
   Пример 1.   Печать красными буквами на синем фоне:
 
10 POKE &amp;O214,-1        MOV    #177777,@#214  ;красный цвет;
20 POKE &amp;O212,&amp;O52525   MOV    #52525,@#212   ;синий фон;
30 ?"Приветик!"         MOV    #TXT,R1        ;печатаем
                        CLR    R2               ;текст
                        EMT    20               ;
                        HALT
                   TXT: .A:Приветик!
 
   Пример 2.   Запись символов в служебную строку:
 
10 POKE &amp;O160,PEEK(&amp;O204)+&amp;O36100       MOV  @#204,@#160
                                        ADD  #36100,@#160
20 ? "текст"                            MOV #TXT,R1
                                        CLR R2
                                        EMT 20
                                        HALT
                                   TXT: .A:текст
 
   Примечание: эта последовательность  проходит  только  в  программе;
если  попытаться  проделать  ее  в  непосредственном режиме,  то после
оператора POKE ...  Бейсик напишет "Ок" в служебной  строке  и  курсор
вернется на свое прежнее место.
 
   Пример 3.   Печать "в столбик":
 
10 X=PEEK(&amp;O162)                MOV @#162,R3   ;запомнить старый режим
20 POKE &amp;O162,&amp;O100             MOV #100,@#162
30 ?"текст"                     MOV #TXT,R1
                                CLR R2
                                EMT 20
40 POKE &amp;O162,X                 MOV R3,@#162   ;восстановить режим
                                HALT
                           TXT: .A:текст
 
</pre>


[[Категория:Программирование на БК-0010-01‎]]
[[Категория:Программирование на БК-0010-01‎]]

Текущая версия от 19:29, 23 августа 2010

Материал удален по требованию автора.