[an error occurred while processing this directive]
│.........*.......*.......*.......*.......*.......*.......*.........<
─SRP 1
─PL70
─TM0
─HM2
─DH//-|P-//
─LM5
─CEШевкунов В.В.
─CEПрограммирование на Ассемблере в системе BBC BASIC
─CEи системные вызовы ОС ОНИКС
─CEМосква, 1991
─PE
│.........*.......*...........*.............*.......................<
─CE|||/Язык Программирования Ассемблер/|||
Для чего нужен Ассемблер, если можно писать программы на Бейсике?
Бейсик - это относительно легкий для изучения язык, второе его
преимущество заключается в том, что если Вы ошибетесь, система
сразу отреагирует на это. Однако ничего не дается даром, за
простоту и "дружелюбность" языка приходится расплачиваться
существенным увеличением времени выполнения программы. В данной
версии Бейсика существует возможность соединить преимущества
интерактивности Бейсика с быстротой Ассемблера, т.е. можно
встраивать в программу на Бейсике подпрограммы написанные на
Ассемблере.
Программа на Ассемблере состит из операторов типа
|LDA #3|
что означает "загрузить в аккумулятор число 3" ("Load the
accumulator with 3") или
|JSR &6000|
что означает "вызвать подпрограмму по адресу 6000" ("Jump to the
subroutine at location 6000 hex").
Ассемблер - это программа, которая преобразует команды мнемокода
в машинный код, который "понимает" микропроцессор.
Ассемблер используется в тех случаях, когда быстродействие или
размер программы имеют решающее значение. Бейсик хорош там, где
легкость написания программы важнее требованиий к скорости
выполнения и размеру используемой памяти.
Из-за ограниченного объема данного руководства невозможно научить
Вас программировать на Ассемблере, хотя он и входит в состав
интерпретатора. Однако, программисты, владеющие ассемблером для
6502 найдут здесь всю необходимую информацию для создания
эффективных машинных подпрограмм. В конце данной главы описываются
осовные вызовы операционной системы и их параметры.
При запуске Бейсика с диска в память Агата так же грузитс
Операционная Система (ОС). ОС прежде всего осуществляет операции
ввода/вывода доступ к которым осуществляется через стандартные
точки вызовов ОС. Многие вызовы осуществляются по векторам,
расположенным в ОЗУ.
ОС обеспечивает все графические и текстовые операции, включая
выбор режима отображения, рисование линий, установку графических и
текстовых окон, переопределение символов.
ОС также осуществляет взаимодействие с аналоговыми входами,
паралельным интерфейсом и клавиатурой.
Из программы на Ассемблере можно осуществлять различные операции
с Дисковой Файловой Системой (ДФС).
Все обращения к ОС должны осуществляться только по стандартным
точкам входов, что гарантирует работоспосбность прикладных
программ независимо от конфигурации компьютера.
Ассемблер является частью интерпретатора Бейсик, и может быть
вызван квадратной скобкой "|[|". Конец ассемблирования обозначается
правой квадратной скобкой "|]|".
─PE5
|10 PRINT "THIS IS BASIC"
20 [
30 JSR &FFE7
40 ]|
(Не пытайтесь запустить эту программу - она не закончена!)
В предыдущем примере ассемблеру не было ссобщено, куда поместить
отассемблированный машинный код. "Программным счетчиком" служит
переменная P%, которой можно присвоить требуемое значение,
например
─PE14
|10 PRINT "THIS IS BASIC"
15 P%=&7000
20 [
30 JSR &FFE7
40 ]
50 PRINT "AND THIS IS BASIC TOO"
>RUN
THIS IS BASIC
7000
7000 20 E7 FF JSR &FFE7
AND THIS IS BASIC TOO|
Однако существует другой, более практичный способ выделения
памяти для машинной подпрограммы. Для этого применяется
специальная версия оператора |DIM|.
─PE16
|10 PRINT "THIS IS BASIC"
15 DIM GAP% 20
16 P%=GAP%
20 [
30 JSR &FFE7
40 ]
50 PRINT "AND THIS IS BASIC TOO"
>RUN
THIS IS BASIC
0F6B
0F6B 20 E7 FF JSR &FFE7
AND THIS IS BASIC TOO|
В последней программе автоматически выделяется область размером в
21 байт, начало которой хранится в переменной |GAP%|. Это безопасный
способ совмещения программы на Бейсике с машинными подпрограммами.
Естественно размещение машинной подпрограммы будет изменяться при
изменении основной программы до оператора |DIM|:
─PE16
|10 PRINT "THIS IS BASIC"
12 REM INSERT AN EXTRA LINE
15 DIM GAP% 20
16 P%=GAP%
20 [
30 JSR &FFE7
40 ]
50 PRINT "AND THIS IS BASIC TOO"
>RUN
THIS IS BASIC
0F85
0F85 20 E7 FF JSR &FFE7
AND THIS IS BASIC TOO|
Два оператора Бейсика обеспечивают доступ к машинным
подпрограммам: |CALL| и |USR|. Оператор |USR| позволяет легко передавать
значения регистрам микропроцессора и обратно. Когда выполняется
оператор
|R = USR(Z)|
компьютер сначала помещает значения переменных |X%, Y%, A%| и |C%| в
регистры микропроцессора X и Y, аккумулятор и флаг переноса
соответственно. Конечно, толко младшие значащие байты переменных
X%, Y%, A% и млдаший значащий бит пременной C% используются.
После установки региситров управление передается подпрограмме по
адресу Z. Эта подпрограмма должна заканчиваться командой |RTS| для
возврата в вызывающую программу на Бейсике. Перед возвратом
регистры A, X, Y и регистр состояния помещаются в переменную R.
Для наглядности ниже приводится короткая программа, использующая
вызов |OSBYTE| (Operating System Byte) для определения положения
текстового курсора на экране.
─PE8
|30 A%=&86
40 X%=0
50 R=USR(&FFF4)
60 PRINT ~R|
Строки 30 и 40 устанавливают регистр X и аккумулятор. Строка 50
помещает результат в R и строка 60 печатает содержимое R в
шестнадцатиричном виде. Результат может быть таким:
─PE10
|B1120086|
|B1| Значение регистра состояния (P).
|12| Значение регистра Y, что в данном случае
соответствует Y-координате курсора.
|00| Значение регистра X, что в данном случае
соответствует X-координате курсора.
|86| Значение аккумулятора.
Оператор |CALL| предоставляет более гибкий способ доступа к
машинным подпрограммам. |CALL| не возвращает результат в переменную
Бейсика. Однако пользователь может, если он хочет, сделать любую
переменную доступной из машинной подпрограммы. Если в состав
оператора |CALL| входят переменные, Создается "Блок Параметров",
помещаемый по адресу &600.
При входе в подпрограмму регистрам процессора A, X, Y,
присваиваются значения младших значащих байт переменных A%, X% и
Y%. Флаг переноса устанавливается в соответствии с состоянием
младшего значащего бита переменной C%.
Перед вызовом подпрограммы компьютер создает Блок Параметров,
содержащий следующие данные:
─PE10
Количество параметров - 1 байт
адрес 1-го параметра - 2 байта
тип 1-го параметра - 1 байт
адрес 2-го параметра - 2 байта
тип 2-го параметра - 1 байт
.................... - .......
адрес N-го параметра - 2 байта
тип N-го параметра - 1 байт
─PE8
|||/Типы параметров/|||
0- 8 бит байт (например ?X)
4- 32 бит целая переменная (например !X или X%)
5- 40 бит число с плавающей запятой (например V)
128- Строка с заданным адресом (например ¤X-оканчивающаяся &0D)
129- Символьная переменная (например A¤)
В случае символьной переменной адрес параметра содержит адрес
Информационного Блока Строки, который содержит стартовый адрес,
количество выделенных байт и текущую длину строки.
Ниже приведена программа, использующая оператор |CALL
─PE28
10 REM Demonstration of CALL with a parameter
20 PROCINIT
30 A%=&12345678
40 CALL SWAP,A%
50 PRINT~A%
60 END
70 DEF PROCINIT
80 DIM Q% 100
90 FOR C=0 TO 2 STEP 2
100 PAR=&600: REM Parameter block
110 ZP=&80: REM Usable zero page
120 P%=Q%
130 [OPT C
140 .SWAP LDA PAR
150 CMP#1:BEQ OK
160 .ERRO BRK
161 ]
162 ?P%=45
163 ¤(P%+1)="Swap Parameters"
164 P%=P%+16
170 [OPT C:BRK
180 .OK LDA PAR+3:CMP #4:BNE ERRO
190 LDA PAR+1:STA ZP
200 LDA PAR+2:STA ZP+1
210 LDY#3:LDX#0
220 LDA(ZP,X):PHA:LDA(ZP),Y:STA(ZP,X):PLA:STA(ZP),Y
230 RTS
240 ] NEXT
250 ENDPROC|
Строки с 10 по 60 формируют главную Бейсик-программу. Она
использует машинную подпрограмму для циклического перемещения
содержимого переменной A%. 20-я строка вызывает процедуру, которая
ассемблирует мнемокод в машинную подпрограмму. Строка 30
присваивает переменной произвольное значение, а строка 40 вызывает
машинную подпрограмму для изменения содержимого переменной A%.
50-я строка печатает результат работы подпрограммы.
Процедура (строки 70 - 250) ассемблирует мнемокод подпрограммы в
машинный код. 80-я строка резервирует 101 байт памяти и помещает в
Q% адрес начала зарезервированной области. Строки 90 и 240
формируют цикл |FOR...NEXT|, который обеспечивает два прохода
ассемблирования - первый для формирования таблицы меток, а второй
для помещения машинного кода в память компьютера. 120-я строка
иницализирует программный счетчик в начале каждого прохода
ассемблирования. В строках 140 и 150 происходит проверка
содержимого по адресу &600. Адрес &600 содержит "число параметров"
и наша подпрограмма рассчитана только на один параметр. Если число
параметров не равно единице управление передается на метку |ERRO|
(строка 160).
Строки 160 - 164 показывают, как можно легко генерировать
сообщения об ошибках. Подробно об это рассказывается в разделе
"Системные прерывания". Следует только сказать, что в нашем случае
будет генерироваться код ошибки 45 и выдаваться сообщение |"Swap
Parameters"| с последующей передачей управления Бейсику. 164-я
строка увеличивает значение программного счетчика с целью
выделения места для сообщения.
В строке 170 происходит повторный вызов Ассемблера и
переустановка |OPT|. В строке 180 происходит проверка типа параметра
- он должен быть равен четырем (целая переменная). Строки 190 -
220 осуществляют непосредственную обработку параметра, а 230-я
строка обеспечивает возврат в Бейсик.
─PE
─CE|Ассемблер языка Бейсик|
Вход в режим Ассемблирования осуществляется оператором "|[|", а
выход - оператором "|]|". Внутри режима ассемблирования
псевдооператор |OPT| используется для установки режимов листинга и
выдачи сообщений об ошибках. |OPT| может принимать следующие
значения:
─PE7
|OPT 0 |отмена вывода листинга и сообщений
|OPT 1 |вывод только листинга
|OPT 2 |вывод только сообщений
|OPT 3 |вывод листинга и сообщений
Обычно первому проходу соответствует |OPT 0|, а второму - |OPT 2|.
Если требуется вывод листинга, то вместо |OPT 2| используется |OPT
3|.
|Метки| задаются словом, перед которым должна стоять точка. Для
обращения к метке точку ставить не надо.
─PE6
|LDA #8
.LOOP BIT VIA+&D
BNE LOOP|
Имена меток формируются аналогично именам переменных. Таким
образом они должны начинаться с буквы и не должны начинаться с
зарезервированных слов. Во время первого прохода неизвестные метки
вызываеют генерацию иекущего адреса. Таким образом все команды
перехода будут передавать управление сами на себя.
Для ввода |байтовых или символьных констант| программист должен
временно выйти из режима ассемблера и использовать
непосредственные операторы. Например
─PE9
|JMP LABEL1
]
¤P%="TODAY"
P%=P%+6
[
.LABEL1 LDA&|
Напоминаем, что переменная P% служит программным счетчиком,
оператор (¤) используется для помещения ASCII кодов символов
непосредственно в память компьютера. Слово |TODAY| будет занесено в
память вместе с перводом строки (&0D) оканчивающим его - всего 6
символов. Если Вы хотите, чтобы слово оканчивалось нулем вместо
&0D Вы должны написать следущее:
─PE6
|¤P%="TODAY"
P%?5=0
P%=P%+6|
Для размещения числовых значений вы должны воспользоваться
операторами доступа к байтам и словам памяти ? и !, например:
─PE9
|JMP LABEL2
]
?P%=10
P%?1=20
P%?2=66
P%=P%+3
[|
Режимы адресации 6502 обозначаются стандартным образом, но для
обозначения шестнадцатиричного режима используется амперсенд.
│...*.........................*.............*.......................<
─PE15
|Режим адресации Примеры|
Непосредственная LDA #4 LDA #VALUE
Абсолютная JMP &8000 LDA LOCATION
Нулевой страницы LDA &FC STY TEMPI
Аккумуляторная ASL A
Командная RTS
Прединдексная косвенная LDA (5,X) CMP (OFFSET,X)
Постиндексная косвенная LDA (&84),Y ORA (TABLE),Y
Короткая индексная LDA 10,X INC CNT,X
Абсолютная индексная LDA &1234,X STA STORE,X
Косвенная JMP (&20E) JMP (WRCHV)
Короткая косвенная по Y LDX 24,Y LDX VAR,Y
│.........*.......*...........*..............*......................<
|Комментарии| могут быть вставлены в фрагмент на ассемблере, для
этого перед комментарием помещается символ "\". В Бейсике все
символы от оператора |REM| и до конца строки игнорируются, так что
невозможно поместить следующий оператор на той же строке. Таким
образом
|10 REM HELLO : PRINT "FRIDAY"|
не будет печатать слово FRIDAY. Однако, в ассемблере комментарии
заканчиваются также символом ":". Все следующие операторы будут
отассемблированы:
|LDA #&10 \MASK :.LOOP BIT VIA+13
\INTERRUPT FLAG : BEQ LOOP|
[an error occurred while processing this directive]