Nicron #30
17 апреля 1997
  Бейсик  

Программирование - калькулятор бейсика.

(C) WLODEK BLACK

Всем привет!

            КАЛЬКУЛЯТОР БЕЙСИКА

Известно,  и  многие  с  этим  встречались:  и  в  ассемблерных
программах   иногда    возникает    потребность    в    сложных
математических расчетах, алгоритмы  которых  выходят  за  рамки
ADD, SBC или RR. Программировать такую "арифметику" трудно... К
счастью, сам Спектрум предоставляет нам  средство  для  решения
математических   задач   в   машиннокодовых   программах.   Это
калькулятор Бейсика - мощный  модуль  операционной  системы,  к
которому можно обращаться как к набору процедур для  выполнения
расчетов.  Калькулятор  состоит  из  собственно  вычислителя  и
комплекта  процедур  для  получения  входных  данных  и  выдачи
готовых результатов. Сайт purebasic.

		    Стек калькулятора

Входные  данные,  с  которыми  будет  оперировать  вычислитель,
помещаются  в  специально  отведенную  область  памяти  -  стек
калькулятора. С машинным стеком его роднит принцип  организации
- "последним пришел -  первым  вышел".  Начало  и  конец  стека
калькулятора можно узнать  из  системных  переменных  STKBOT  и
STKEND  (23651  и  23653;  слова).  Не  следует   без   крайней
необходимости  менять  эти  адреса.  Один  элемент  данных  для
калькулятора - 5-байтовое значение числа в формате Бейсика  или
параметры строкового значения (адрес начала  и  длина  строки).
Таким образом, каждое значение на стеке калькулятора занимает 5
байт. Еще одно свойство стека калькулятора -  он  растет  снизу
вверх.
Чтобы  выполнить  какие-либо  действия  над  числами,  их  надо
поместить на стек калькулятора. Например, нам надо сложить 5  и
7: засылаем  в  стек  5,  потом  7,  затем  выполняем  операцию
"сложить". Для занесения в  стек  калькулятора  данных  имеется
несколько точек входа для "CALL":

#2D22 - STK-DIGIT. Значение аккумулятора=цифра в ASCII ->  стек
(значение цифры);
#2D28 -  STACK-A.  Аккумулятор  ->  стек  (в  форме  "плавающей
запятой");
#2D2B - STACK-BC. BC -> стек (-"-);
#2AB1 - STK-STORE. A,E,D,C,B -> в стек в 5-байтовом  внутреннем
формате; так же засылаются параметры строки (при этом A=0);
#2ABB - то же без проверок  на  корректность  (иногда  полезно,
если система Бейсика искажена преднамеренно).

(Кто из вас успел в свое  время  поработать  с  программируемым
микрокалькулятором "Электроника МК-54" (61, 52),  должны  сразу
заметить полную идентичность стека того калькулятора  и  этого.
Никаких  психологических  барьеров  -   вспоминайте,   как   вы
пользовались  микрокалькулятором,  и  так   же   программируйте
калькулятор Бейсика ZX! Принцип абсолютно аналогичный:  сначала
заносятся на стек данные,  потом  вводятся  коды  операций  над
ними).  Вот  как  будет   выглядеть   пример   "5+7"   в   виде
последовательности инструкций на ассемблере:

	LD	A,5 ; число 5
	CALL	#2D28 ; STACK-A - заносим А в стек
	LD	A,7 ; число 7
	CALL	#2D28

	RST	#28 ; вызов калькулятора
	DEFB	#0F ; код сложения
	DEFB	#38 ; завершение калькулятора

	CALL	#2DA2 ; FP-TO-BC - стек -> BC.

На выходе из примера  в  паре  BC  будет  находиться  результат
вычислений. Если вызвать пример через PRINT  USR,  напечатается
результат. Конечно, сложить такие числа, как 5 и 7, можно легко
и прямо в машинных кодах, но это был лишь пример, показывающий,
как работать с калькулятором.

Командой RST #28 вызывается калькулятор. Все последующие  байты
будут расцениваться как коды  операций  калькулятора,  пока  не
встретится код #38 - символ окончания работы с калькулятором.
Результат вычислений помещается на текущую макушку  стека.  Его
можно снять со стека, или распечатать на экране  или  принтере,
или оставить на стеке для последующих  вычислений.  Вот  наборы
процедур для получения результатов вычислений:

#2BF1 -  STK-FETCH.  Снимает  со  стека  последнее  значение  и
помещает его в регистры B,C,D,E,A. Если данное в стеке являлось
параметрами строки символов, то: DE - адрес начала, BC - длина;
#2DA2 - FP-TO-BC. Снимает со стека верхнее значение и  помещает
его в пару BC, округляя до ближайшего целого (int(N+0.5));
#2DD5 - FP-TO-A - то же, но с помещением 1-байтового результата
в аккумулятор;
#2DE3 - PRINT-FP  -  печатает  в  текущий  поток  (связанный  с
экраном, принтером или другим устройством) значение с  верхушки
стека калькулятора в виде, наиболее подходящем для  конкретного
значения (целом или вещественном). Параметры с  верхушки  стека
калькулятора  рассматриваются  как  число;  если  они  окажутся
параметрами строки, то  будут  напечатаны  в  виде  числа  (это
будет ошибка);
#203C - печатает строку, заданную через: DE=адрес начала,
BC=длина. Может использоваться  вне  связи  с  калькулятором  -
просто для печати строк символов.

В вышеупомянутом примере "5+7"  можно  вставить  в  конце  CALL
#2DE3 для вывода результата.
При  использовании  PRINT-FP  нужно  заранее   позаботиться   о
включении нужного канала и потока для вывода результатов:

	LD	A,STREAM
	CALL	#1601

STREAM - номер канала:
1 - служебная строка экрана;
2 - основной экран;
3 - принтер.

Калькулятор выполняет действия и над символьными величинами.

А вот список кодов  операций  калькулятора,  располагаемых  как
DEFB после "RST #28":

#00 - jump true
#01 - exchange
#02 - delete
#03 - subtract (вычитание; X-Y)
#04 - mult (умножение; X*Y)
#05 - div (деление; Y/X)
#06 - to-power (возведение в степень; X^Y)
#07 - or
#08 - no-&-no
#09 - no-l-eq
#0A - no-gr-eq
#0B - nos-eql
#0C - no-gtr
#0D - no-less
#0E - nos-eql
#0F - add (сложение; X+Y)
#10 - str-&-no
#11 - str-l-eq
#12 - str-gr-eq
#13 - strs-negl
#14 - str-gtr
#15 - str-less
#16 - str-gtr
#17 - strs-add
#18 - val$ (рекурсия; только через fp-calc-2)
#19 - usr-s
#1A - read-in
#1B - neg
#1C - code
#1D - val (рекурсия; только через fp-calc-2)
#1E - len
#1F - sin
#20 - cos
#21 - tan
#22 - asn
#23 - acs
#24 - atn
#25 - ln
#26 - exp
#27 - int
#28 - sqr
#29 - sgn
#2A - abs
#2B - peek
#2C - int(Y+0.5)
#2D - user-no
#2E - str$
#2F - chr$
#30 - not
#31 - duplicate
#33 - jump
#34 - stk-data
#35 - djnz
#36 - less-0
#37 - greater-0
#38 - end-calc (завершение работы с калькулятором)
#39 - get-argt
#3A - trunc
#3B - fp-calc-2 (вторичный вызов калькулятора - рекурсия)
#3C - e-to-fp
#3D - restack (Y целое -> Y в плавающей форме)
#86 и далее - series-06
#A0 - 0 (константа; занесение в стек константы)
#A1 - 1
#A2 - 1/2
#A3 - PI/2
#C0 и далее - st-mem-0
#E0 и далее - get-mem-0

Если операция одноместная - результат замещает исходный операнд
на вершине стека. Если операция двуместная - со стека снимаются
два исходных операнда, а результат помещается на новую  вершину
стека. Операции над  строковыми  величинами  выпоняются  не  на
стеке калькулятора -  для  них  отводится  место  во  временной
рабочей  области;  на  стек  калькулятора   помещаются   только
указатели на местонахождение  строковых  данных:  адрес  начала
строки и длина (в регистрах процессора  это:  DE=адрес  начала,
BC=длина).  Так  как  один  элемент  стека  содержит  5   байт,
в качестве неиспользуемого пятого байта заносится 0.

В группу обслуживающих процедур  нужно  занести  еще  следующие
подпрограммы:

#16B0 - очистка редакторской строки, временной рабочей  области
и стека калькулятора;
#16BF - очистка временной рабочей области и стека калькулятора;
#16C5 - очистка стека калькулятора.

В   следующем   номере   мы   рассмотрим:   ввод   произвольных
вещественных чисел;  передача  параметров  USR-подпрограмме  из
Бейсика через переменные Бейсика; ввод строковых величин в USR-
подпрограмму через символьные переменные  Бейсика  (на  примере
утилит WORDSERV и т.п., в которых имена файлов  вводятся  через
INPUT Бейсика, а используются в машиннокодовых программах).

Продолжение следует.




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

Похожие статьи:
О людях - О истории создания и планах студии VIKS.
Reclama - INDIGO GROUP приглашает к сотруднечиству художника и музыканта которому не безразлична судьба SPECTRUM.
Роберт Шекли - Рыболовный сезон.

В этот день...   22 ноября