[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]