Программирование на БК-0010-01/Глава 5
Данный материал защищён авторскими правами!
Использование материала заявлено как добросовестное, исключительно для образовательных некоммерческих целей. |
5.1. Отладчик MIRAGE Система MIRAGE С.Зильберштейна (г.Киров) - одно из самых удобных средств, облегчающих программирование в кодах на БК и отладку программы в кодах. В комплект поставки входит описание системы и две версии программы: MIRAGE26 - загружается с адреса 26000 и позволяет работать с программами в адресах ОЗУ 1000-25777; MIRAGE - загружается в экранное ОЗУ с адреса 66000 и позволяет работать с программами максимальной длины (вплоть до 37777). Платой за эту возможность служит невозможность отладки программ со спрайтовой графикой, поскольку они могут запортить отладчик, находящийся в экранном ОЗУ. Существует также версия этого отладчика, распространенная под названием OS0010F, приспособленная П.Эльтерманом (г.Москва) для работы с Фокалом (возможность перехода из Фокала в MIRAGE и обратно удобна при написании и отладке программ типа "Фокод"). MIRAGE работает в двух основных режимах: командном и экранном. При начальном запуске система находится в командном режиме. Здесь можно давать команды работы с файлами, с памятью, команды редактирования и трассировки отлаживаемой программы. При описании команд используются обозначения "начало" и "конец" для обозначения начального и конечного адреса, "имя" - имя файла при работе с магнитофоном. Необязательные элементы заключены в квадратные скобки. LOAD имя - загрузка файла с адреса, указанного на ленте; LOAD имя/адрес - загрузка с указанного адреса; SAVE имя/начало/конец - запись программы на магнитофон; SAVE - запись программы на магнитофон с тем же именем, начальным и конечным адресом, что были указаны в последней выполненной команде SAVE; SET имя - поиск файла на ленте; DIR - просмотр названий файлов на ленте; D адрес - пошаговый дамп содержимого ОЗУ с указанного адреса по словам (распечатка в восьмеричной системе счисления); D адрес/B - то же по байтам. В режиме дампа действуют команды: "ВК" - продолжить дальше, "." - окончить дамп и выйти в командный режим. DR - распечатка содержимого регистров процессора R0-R5, SP, PC и признаков PSW N,Z,V,C; S адрес - пошаговый просмотр и изменение содержимого памяти, начиная с указанного адреса по словам; S адрес/B - то же по байтам; SR - пошаговый просмотр и изменение регистров процессора. В этих режимах можно, нажимая "ВК" или "стрелку вверх", просматривать содержимое памяти соответственно в сторону увеличения либо уменьшения адресов, а при необходимости внести изменения: набрать новое значение слова (байта) в восьмеричной системе счисления и нажать "ВК" или "стрелку вверх". "." - конец пошагового просмотра и выход в командный режим. В режиме просмотра по байтам "S адрес/B" можно вводить строку символов, начинающуюся кавычками. F начало/конец/код - заполнение указанного участка ОЗУ значением "код"; M начало/конец/адрес - побайтное копирование участка ОЗУ, заданного начальным и конечным адресом, в область, начиная с указанного адреса; C начало/конец/адрес - пословное сравнение двух участков ОЗУ одинаковой длины: один задан начальным и конечным адресом, второй начинается с указанного адреса; W начало/конец/слово[/маска] - поиск "слова" в указанном участке ОЗУ. Если задана "маска", то ведется поиск всех слов, которые совпадают с образцом поиска ("словом") только в тех битах, которые установлены в маске. Например: W 1000/2000/123 - найти и указать адреса слов в диапазоне от 1000 до 2000, в которых записано значение 123; W 1000/2000/177600/177600 - найти в указанном диапазоне все обращения к системным регистрам, то есть слова, значения которых лежат в диапазоне от 177600 до 177777. Учтите при этом, что MIRAGE не может в подобных случаях отличить адрес (то, что нам и надо) от данных (что мы вовсе не имели в виду, давая эту команду). В каждом конкретном случае разбираться приходится самому программисту. W начало/конец/адрес[/маска]/R - поиск относительных ссылок на указанный адрес (или интервал адресов, определенный маской). Например, у нас есть кусок программы: 1000: 167 JMP 4000 1002: 2774 где применена относительная адресация в команде перехода. Если мы дадим в MIRAGE команду "W 1000/1010/4000/R", то получим сообщение: 001002: 004000 из которого ясно, что по адресу 1002 найдена относительная ссылка на адрес 4000. U начало/конец - подсчитать контрольную сумму в указанном участке. G [начало][/конец] - запуск программы с начального адреса (или с текущего содержимого PC, если "начало" не указано) до конечного адреса. Если "конец" не указан, то управление системе MIRAGE вернется по команде HALT в отлаживаемой программе либо по прерыванию ее по ошибке или по клавише "СТОП". T [адрес] - пошаговая трассировка программы с указанного адреса (либо с текущего содержимого PC). В процессе трассировки распечатываются текущие значения регистров R0-R5, SP, PC и признаки PSW N,Z,V,C, затем очередная команда, на которую показывает PC. "ВК" - продолжение трассировки, "." или "СТОП" - окончание и выход в командный режим. R адрес - вызов подпрограммы с указанного адреса. MIRAGE вернется в командный режим по достижении команды возврата из подпрограммы RTS PC. A начало[/конец] - перейти к экранному редактированию программы в указанном диапазоне адресов; при этом на экране отображаются адреса и мнемоника команд; ASM начало[/конец] - перейти к экранному редактированию программы в указанном диапазоне адресов; при этом на экране отображаются адреса, коды и мнемоника команд. В режиме экранного редактирования MIRAGE дизассемблирует часть ОЗУ (то есть переводит коды команд в их ассемблерные мнемоники). Если в этом участке встречаются данные, то они также считаются командами и будут дизассемблированы. Естественно, есть такие коды, которые не соответствуют ни одной команде процессора; в этом случае пишется мнемоника WORD (слово) и содержимое этого слова. По обилию мнемоник WORD среди прочих правдоподобно выглядящих ассемблерных команд можно распознать массивы данных в программе. MIRAGE для удобства программиста заменяет команды "JSR PC,адрес" на "CALL адрес" и "RTS PC" на "RET"; а для удобства ввода кода символа позволяет писать команды вида "MOV #'A,R0", что тут же переведет в "MOV #101,R0". В режиме экранного редактирования можно редактировать мнемоники команд с помощью клавиш управления курсором; все сделанные в данной строке изменения будут приняты только после нажатия "ВК" в момент, когда курсор стоит в этой строке. Редактор работает только в режиме 64 символа в строке; нельзя также допускать выхода курсора за пределы экрана ! В режиме экранного редактирования действуют клавиши: "КТ" - листание текста на экран вперед; "СУ/Т" - листание на один экран назад (только после "КТ"); "ШАГ" - возврат к первому листу (с адреса, указанного в команде ASM); "ВС" - вставка команды NOP под курсором (нужно всегда учитывать размер команды, которую Вы желаете вставить, и вставлять для этого столько NOP-ов, сколько слов содержит команда. Об этом надо помнить и при редактировании старой команды); "СБР" - удалить команду под курсором; "СТОП" - выход в командный режим. Рассмотрим пример работы с системой MIRAGE. Попробуем набрать программу буквально из нескольких команд. Загрузим MIRAGE26 и запустим его. Очистим командой "F 1000/2000/0" участок ОЗУ с адреса 1000 до адреса 2000 и будем здесь набирать нашу программу. Для этого перейдем в режим экранного редактирования командой "ASM 1000" и увидим: 1000: 000000 HALT 1002: 000000 HALT 1004: . . . Это - наша, еще пустая, рабочая область. Никакого труда, вероятно, не составит набрать такую короткую программу (нажимая "ВК" после ввода каждой команды): 1000: 010100 MOV R1,R0 1002: 104016 EMT 16 1004: 000775 BR 1000 Предположим, мы хотим заменить первую команду на команду "MOV #101,R0". Учитывая, что эта команда займет два слова, а в нашем распоряжении только одно, надо поставить курсор на вторую строку и клавишей "ВС" вставить пустую команду. Программа приобретет вид: 1000: 010100 MOV R1,R0 1002: 000240 NOP 1004: 104016 EMT 16 1006: 000775 BR 1002 Теперь подведем курсор к первой строке, заменим "R1" на "#101" и нажмем "ВК". Программа примет вид: 1000: 010100 000101 MOV #101,R0 1004: 104016 EMT 16 1006: 000775 BR 1002 Мы видим, что команда "MOV #101,R0" заняла два слова памяти и "съела" при этом вставленную команду "NOP". Если бы мы ее не вставили, пропала бы следующая команда "EMT 16". Теперь осталось внести последнее исправление. В команде перехода использована относительная адресация, и, сдвинутая со старого места в ОЗУ, команда перехода показывает уже не на тот адрес. Поэтому при вставке или удалении команд приходится вручную корректировать адреса в сдвинутых командах перехода. Это самое большое неудобство при работе с подобными отладчиками. Можно посоветовать всегда иметь перед собой текст программы на бумаге и в процессе работы вносить туда все необходимые изменения. Нужно также иметь отдельную таблицу, в которой перечислены адреса используемых Вами подпрограмм и глобальных переменных. Такая таблица очень поможет Вам в работе. Еще один полезный совет заключается в правильном использовании режимов адресации. Отлаживая программу по частям или по отдельным подпрограммам, старайтесь, чтобы все переходы внутри этого кусочка использовали относительную адресацию. Тогда после отладки данной подпрограммы ее можно будет перемещать в ОЗУ, заботясь только об изменении ссылок на глобальные имена - на внешние подпрограммы и переменные, которые к данному кусочку программы не привязаны. Теперь давайте попробуем запустить нашу программу. Для этого нажмем "СТОП" - MIRAGE26 перейдет в командный режим. Запустим программу командой "G 1000". И она заработает - начнет выводить на экран букву "А" (это ее код - 101). Чтобы остановить нашу зацикленную программу, нажмем "СТОП" и вновь окажемся в командном режиме. 5.2. Отладчики типа ГРОТ Распространено много версий отладчиков под разными названиями (ОТЛ, ОТЛАДЧИК3, ГРОТ и др.), которые по существу представляют собой одно и то же. Коротко опишем версию, в командной строке которой появляется надпись "Микро-отладчик <V1.1 860702 Москва-Рига>". По своему принципу действия этот отладчик аналогичен системе MIRAGE, но имеет несколько меньшие возможности и менее удобен в работе. Он не имеет экранного редактора и удобной функции вставки- удаления команд. На экране его отображается адрес, мнемоника команды, ее коды по словам и по байтам, а также содержимое байтов в символьном виде: 1000 MOV #101,R0 012700 25.300 Ю 000101 0.101 А 1004 EMT 16 104016 210.16 1006 HALT 000000 0.0 В правом верхнем углу выводятся текущие значения регистров процессора и признаков N,Z,V,C. Команды отладчика: адресА - установить текущее значение адреса (как в ТС-отладчике); К - выход в пусковой монитор; , (запятая) - перемещение текущего адреса на команду вперед; - (минус) - перемещение текущего адреса на команду назад; I - вывести мнемонику команды по текущему адресу; "ВК" - ввести мнемонику команды и записать ее по текущему адресу; nD - сделать дамп n байт памяти с текущего адреса; nL - распечатать n команд с текущего адреса; конецPадрес - скопировать область ОЗУ с текущего по конечный адрес в область, начинающуюся с указанного адреса; R - вывод регистров процессора; значениеRn - записать "значение" в регистр Rn; О - очистить рабочие переменные отладчика; адресG - запустить программу с указанного адреса; управление вернется отладчику по команде HALT или другому аварийному прерыванию, либо по установленной контрольной точке; адресТ - установить контрольную точку - адрес команды, где программа должна остановиться при отладке; T - снятие контрольной точки; адрес[ - пошаговая трассировка программы; адресY - медленная автоматическая трассировка (1 команды в 5 сек.); адрес] - ускоренная автоматическая трассировка (1 команда в сек.). Если в этих командах не указать адрес, то выполнение начнется с команды, на которую указывает PC. адресЧ - чтение программы с магнитофона; адресЗдлина - запись программы на магнитофон. 5.3. Ассемблер МИКРО 5.3.1. Описание языка Работа с помощью описанных отладчиков очень близка к программированию в машинных кодах. Отладчики представляют собой первую ступень механизации программирования в кодах - замену кодов машинных команд удобными для человека их мнемоническими обозначениями. Вся же работа по распределению памяти, учету адресов лежит по-прежнему на программисте. Второй ступенью механизации программирования является программиро- вание на языке низкого (машинного) уровня - языке ассемблера. Как и система команд, свой язык ассемблера характерен для каждого типа ЭВМ. Что же принципиально новое дает программисту язык ассемблера ? Прежде всего, он позволяет использовать метки в тексте программы. Метки используются для указания адреса в операциях перехода и пересылки. В этом отношении они похожи на номера строк Бейсика или Фокала. Теперь программист избавлен от необходимости учета физических адресов памяти, он работает только с метками, а адрес получается при трансляции ассемблерной программы. Если Вы добавите или удалите несколько команд, то Вам не придется корректировать адреса в сдвинутых с места командах перехода. Просто текст программы надо оттранслировать заново. Для перевода программы на языке ассемблера в машинные коды используется специальная программа, называемая ассемблером. Процесс перевода называется ассемблированием. На ЭВМ ДВК, СМ используется мощный ассемблер MACRO, имеющий очень много облегчающих работу программиста средств (макрокоманды, условная трансляция и др.). На БК используются ассемблеры попроще. Наибольшее распространение получила система МИКРО, разработанная С.В.Шмытовым, А.Н.Сомовым и С.А.Кумандиным (г.Москва). Ассемблер МИКРО включает в себя редактор текста, транслятор и компоновщик, которые объединяет командный монитор. Распространено несколько версий системы: МИКРО8С, МИКРО9, МИКРО10, МИКРО11. Особенности каждой новой версии отражаются в соответствующем описании. Здесь приведены основные сведения по МИКРО9. Основные характеристики системы следующие: - объем ОЗУ, занимаемый системой - 4.5К; - максимальный объем исходного текста - 8К; - максимальный размер транслируемой за один раз программы - 2К; - максимальный размер программы, полученной при компоновке в режиме РП - 16.5К. Работа с системой будет описана ниже, а пока познакомимся с языком ассемблера БК и его особенностями в системе МИКРО. Программа на языке ассемблера, как и программа на Бейсике, состоит из строк (операторов). В одной строке может быть записана одна команда в обычной ассемблерной мнемонике, либо комментарий. Строка программы (оператор) может состоять из 4-х частей (полей). На рис.24 приведен пример оператора на языке ассемблера с обозначением полей. TT: MOV R1,R4 ;Пересылка └─┬─┘ └─┬──┘ └────┬┘ └─┬────────┘ Метка Операция Операнды Комментарий Рис. 24. Формат оператора на языке ассемблера Поля "метка" и "комментарий" не являются обязательными частями оператора. Имя метки состоит не более, чем из трех символов (букв латинского алфавита и цифр) и заканчивается двоеточием. В данном примере имя метки состоит из двух букв "ТТ". Меткой обычно "метится" тот оператор, к которому есть передача управления из какого-либо места программы. Для хранения значений переменных используются определенные слова памяти, которые также обычно "метятся" метками - тогда каждая метка является именем соответствующей переменной. Если имя метки начинается с цифры, то метка называется локальной, и ее действие распространяется только между обычными метками, поэтому имена локальных меток в программе могут повторяться. Двух одинаковых обычных меток в программе быть не должно. Комментарии должны начинаться с символа ";", их можно располагать на отдельной строке или в конце строки оператора. Поле "операция" содержит мнемокод машинной команды или псевдокоманду ассемблера МИКРО. Псевдокоманды начинаются с символа "." (точка). В таблице 18 рассмотрены основные псевдокоманды, применяемые в ассемблере МИКРО9. В конце текста программы на ассемблере должна стоять псевдокоманда "END". Таблица 18. Основные псевдокоманды ассемблера МИКРО9 ┌────────┬──────────────────────────────────────────┬───────────────┐ │ формат │ выполняемые действия │ пример │ ╞════════╪══════════════════════════════════════════╪═══════════════╡ │ .+К │ резервируется К байт │ .+45 │ ├────────┼──────────────────────────────────────────┼───────────────┤ │ .#Е │ запись значения выражения Е (в слово) │ .#14 │ ├────────┼──────────────────────────────────────────┼───────────────┤ │ .@E │ получение смещения. По адресу этой псе- │ .@MET │ │ │ вдокоманды записывается число, равное │ │ │ │ разности адреса метки Е (Е - имя метки) │ │ │ │ и адреса самой псевдокоманды │ │ ├────────┼──────────────────────────────────────────┼───────────────┤ │ .Е │ здесь Е - символ "Е". Эта псевдокоманда │ │ │ │ обнуляет байт (если значение счетчика │ │ │ │ адресов нечетно) или слово (если значение│ │ │ │ счетчика адресов четно) │ │ ├────────┼──────────────────────────────────────────┼───────────────┤ │ .В:К │ Записывает значение выражения К │ .В:57 │ │ │ в текущий байт │ │ ├────────┼──────────────────────────────────────────┼───────────────┤ │ .А:... │ Запись произвольной строки символов "..."│ .А:Привет │ │ │ с текущего адреса │ │ └────────┴──────────────────────────────────────────┴───────────────┘ Поле "операнды" содержит информацию о местонахождении операндов, участвующих в операции. Поле "операция" отделяется от поля "операнды" хотя бы одним пробелом. Если команда двухоперандная, то операнд источника отделяется от операнда приемника запятой. Например: MOV R1,R4 Ниже будут рассмотрены некоторые характерные для ассемблера примеры программирования. Пример 1: LF=12 KBD=177662 MOV #LF,R3 MOV #12,R3 MOV KBD,R0 MOV @#177662,R0 Программы слева и справа дадут одинаковый результат. Строка программы, имеющая вид <имя> = <число>, называется оператором прямого присваивания. Этот оператор похож на описание констант в языках высокого уровня, и вводится для удобства обозначения часто используемых констант или адресов (например, адресов системных регистров, как в данном примере). В данной версии ассемблера МИКРО есть ограничение: с помощью оператора присваивания можно работать только с адресами в диапазоне от 0 до 777 и от 100000 до 177777, при использовании таких имен в программе будет обеспечен абсолютный метод адресации. Этим МИКРО отличается от ассемблера MACRO для ЭВМ ДВК и СМ, где последнюю команду для получения абсолютной адресации следовало бы записать как "MOV @#KBD,R0". Пример 2: Адрес Команда Текст на ассемблере 6000: 000167 JMP VAR+2 6002: 001004 ... ... ... 7006: 005000 VAR: CLR R0 7010: 010203 MOV R2,R3 Команда JMP передает управление на адрес, равный значению выражения VAR+2=7006+2=7010. Выражение в МИКРО9 - это имя метки и восьмеричное число, соединенные знаком "+" или "-". В частном случае выражение - это имя метки или восьмеричное число. Пример 3: Адрес Команда Текст на ассемблере 1000: 012700 MOV #6,R0 1002: 000006 1004: 005060 A: CLRB TAB-1(R0) 1006: 001777 1010: 077003 SOB R0,A . . . 2000: TAB: .+6 В этом примере описан массив данных размером 6 байт, который размещается с адреса 2000. Программа очищает (заполняет нулями) этот масссив. Для работы с массивом используется индексный метод адресации. Поскольку индекс - R0 меняется от 6 до 1, в качестве смещения используется выражение "TAB-1"; при значении R0=1 команда "CLRB TAB-1(R0)" очистит байт по адресу 2000). Пример 4: Адрес Команда Текст на ассемблере 1000: 010701 MOV PC,R1 1002: 062701 ADD (PC)+,R1 1004: 000012 .@T+2 1006: 005002 CLR R2 1010: 104020 EMT 20 1012: 000000 HALT 1014: T: .A:Привет ! .E Этот пример показывает, как на МИКРО можно писать перемещаемые программы. Коды этой программы можно записать с любого адреса ОЗУ, и она везде будет работать одинаково, так как адрес выводимой на дисплей строки "Привет !" вычисляется относительно текущего значения PC после выполнения команды "MOV PC,R1": 1002 + 12 = 1014, где .@T = 10 - смещение от адреса этой псевдокоманды до начала текста (метки Т), а еще 2 добавлено для учета самой команды "ADD (PC)+,R1". А вот так предлагается организовать подпрограмму для вывода текста в описании МИКРО#10S (программа также перемещаемая). Предлагаем читателю самостоятельно разобраться в ее работе, напомним только, что после вызова подпрограммы командой "JSR PC,..." в стеке (по @SP) сохраняется адрес следующей команды (адрес возврата): JSR PC,TEX ;вызов подпрограммы вывода текста и передача ей .@T ;смещения до текста в качестве параметра HALT ;продолжение основной программы T: .A:Привет ! ;строка текста .E ;нулевой байт в конце строки и выравнивание ;адреса на границу слова TEX: MOV @SP,R1 ;получение адреса псевдокоманды .@T ADD @R1,R1 ;получение абсолютного адреса строки Т CLR R2 ;вывод строки на дисплей EMT 20 ; ADD #2,@SP ;установить адрес возврата на следующую за .@T RTS PC ;команду программы (в данном случае - HALT) 5.3.2. Работа с системой МИКРО Для получения готовой программы в машинных кодах необходимо проделать следующие операции: - набор исходного текста (текста программы на языке ассемблера) при помощи редактора текста; - трансляция (перевод) исходного текста программы в промежуточную заготовку (объектный модуль) при помощи ассемблера (транслятора); - компоновка (составление) из нескольких объектных модулей готовой к выполнению программы в машинных кодах (загрузочного модуля ) при помощи программы, называемой компоновщиком. Все три программы: редактор текста, ассемблер и компоновщик соеденены в одной программе МИКРО9, которая загружается и запускается на выполнение с адреса 1000. Программа МИКРО9 может работать в одном из четырех режимов: - редактирование текста программы; - трансляция (ассемблирование); - компоновка; - командный режим. Сразу же после запуска МИКРО9 работает в командном режиме, о чем свидетельствует символ "*". В командном режиме возможна подача одной из следующих команд: LO - Загрузка исходного текста с магнитной ленты (МЛ); LF - Подстыковка текста с МЛ к тексту, находящемуся в памяти; ST - Запись текста на МЛ; SF - Запись на МЛ части текста от начала до строки, в которой находился курсор при выходе из редактора текста; SS - Запись на МЛ части текста от строки, в которой находился курсор при выходе из редактора текста, до конца текста; CO - трансляция текста с выводом его на экран; CN - трансляция текста без вывода его на экран; Примечание: после подачи команд CO и CN на экран выводится вопрос "Е/N?", ответ на который служит заданием действий, выполняемых программой после возникновения ошибки: E - прекратить трансляцию, N - продолжить трансляцию; SC - вход в редактор текста; SA - запись на МЛ загрузочного модуля (готовой программы); SL - запись на МЛ объектного модуля (промежуточной программы); LI - компоновка объектного модуля, записанного на МЛ к модулю, находящемуся в памяти (при этом получится программа, загружаемая с адреса 1000 ); LA - компоновка объектных модулей, записанных на МЛ, с указанием адреса последующей загрузки (эта команда применяется только для головного модуля, остальные модули компонуются с помощью команды "LI"); LL - компоновка объектного модуля сразу после трансляции (эта команда применяется для программ, состоящих из одного модуля; при этом получится программа, загружаемая с адреса 1000); LS - компоновка объектного модуля сразу после трансляции, с указанием адреса последующей загрузки. В некоторых версиях МИКРО предусмотрена команда запуска скомпонованной программы "RU" или "GO". 5.3.2.1. Работа в редакторе текста Для набора текста программы на языке ассемблера в редакторе текста используются следующие клавиши: - клавиши перемещения курсора; - клавиши "сдвижка в строке" и "раздвижка в строке"; - клавиша удаления части строки, расположенной справа от курсора; - "СУ/Т" - раздвижка строк программы; - "ВС" - сдвижка строк программы; - "СБР" - переход в конец текста; - "СУ/Э" - переход в начало текста; - "забой" - удаление символа, стоящего перед курсором; - "СУ/Ъ" - выход из редактора; - "КТ" - переход к строке с задаваемым номером. Клавиши и особенности редакторов в различных версиях МИКРО отражаются в соответствующих описаниях. После изменения текста строки, а также для ввода новой строки необходимо нажать клавишу "ВК". В процессе редактирования в левом верхнем углу экрана отображается количество оставшихся байт памяти, отведенных для текста. 5.3.2.2. Ассемблирование Если в исходном тексте программы на языке ассемблера нет ошибок, то в результате трансляции образуется объектный модуль, иначе ассемблер выдает сообщение об ошибках в виде: ОШИБКА NN В СТР. ММММММ где NN - номер ошибки; ММММММ - восьмеричный номер строки текста. Ниже приведены номера ошибок и их описание: 1 - недопустимый символ в строке; 2 - неверный оператор; 3 - ошибка длины перехода по команде BR; 4 - недопустимое имя метки; 5 - недопустимый символ в поле операнда; 6 - неверное число операндов; 7 - нестандартное имя (там, где это необходимо); 10 - неопределенное имя метки в операторе "SOB"; 11 - неверная псевдокоманда; 12 - ошибка индексной адресации; 20 - неправильная команда в командном режиме. 5.3.2.3. Компоновка загрузочного модуля Если исходный текст программы на языке ассемблера невозможно набрать в один прием, то он набирается частями. Каждая часть исходного текста при трансляции образует отдельный объектный модуль, затем все объектные модули связываются (компонуются) компоновщиком в один загрузочный модуль - в программу в машинных кодах, готовую к выполнению. Если загрузочный модуль компонуется из одного объектного модуля, то компоновку можно произвести сразу же после трансляции исходного текста подачей одной из следующих команд: LL или LS. После успешной трансляции распечатывается таблица использованных в модуле меток, при этом в инверсном виде распечатываются метки, которые не определены в данном модуле, но используются в командах программы. Это могут быть глобальные метки (определенные в другом модуле); тогда необходима компоновка программы. Если Ваша программа состоит всего из одного модуля, появление инверсных меток в таблице будет свидетельствовать о Ваших опечатках. Для компоновки нескольких модулей с магнитной ленты программу МИКРО9 нужно привести в исходное состояние командой "RS". 5.3.3. Пример программ на языке ассемблера В первом примере приведен простейший генератор случайных чисел, который можно использовать в игровых программах. Для начальной установки генератора случайных чисел используется такой прием: программа крутится в цикле, вызывая каждый раз генерацию нового случайного числа, до тех пор, пока пользователь не нажмет любую клавишу. Поскольку подгадать нажатие клавиши под нужное количество циклов практически невозможно, то работа программы каждый раз будет начинаться при новом значении случайного числа. Во время прохождения очередного цикла можно производить какие-либо действия на экране (в данном примере случайным образом рисуются точки случайного цвета). ; Пример генератора случайных чисел EMT 14 ;очищаем экран; MOV #INE,R1 ;приведем экран в порядок; CLR R2 ; EMT 20 ; MOV #100,@#177660 ;запретим прерывания от клавиатуры; TST @#177662;снять готовность, если клавиша была нажата; ; Начальная установка генератора случайных чисел ING: MOV #2,R0 ;получаем случайный цвет (число от 0 до 2); JSR PC,NRN ADD #221,R0 ;получаем код символа установки цвета; EMT 16 ;устанавливаем цвет; MOV #377,R0 ;получаем случайное число от 0 до 377 JSR PC,NRN ;и используем его в качестве MOV R0,R1 ;координаты X для вывода точки; MOV #357,R0 ;получаем случайное число от 0 до 357 JSR PC,NRN ;и используем его в качестве MOV R0,R2 ;координаты Y для вывода точки; MOV #1,R0 ;рисуем точку; EMT 30 ; TSTB @#177660;если клавиша не нажата, BPL ING ;продолжаем цикл; TST @#177662;снять запрос на прерывание; CLR @#177660;разрешить прерывания; MOV RAN,R0 ;напечатать полученное JSR PC,OUT ;случайное число; HALT ;далее можно продолжать программу ;---------------------------------------------------- ; Строка инициализации экрана (ставится режим 32 символа в строке, ; убирается курсор и служебная строка) INE: .B:233.B:232.B:224.B:236.B:221.B:0 ;---------------------------------------------------- ; Подпрограмма получения случайного целого числа FRN: .#000327 ;это код команды "SWAB #RAN" RAN: .#0 ;здесь будет целое случайное число INCB RAN ;все эти операторы ROLB FRN+3 ;предназначены MM: ADD #0,RAN ;для получения ADD #3337,MM+2 ;псевдослучайного числа RTS PC ;---------------------------------------------------- ; Получение в R0 случайного числа в диапазоне 0..R0 NRN: JSR PC,FRN ;получаем новое случайное число; MOV R1,-(SP) ;сохраняем регистры в стеке; MOV R2,-(SP) MOV RAN,R1 ;отсекаем старшие разряды MOV #100000,R2 ;случайного числа, 1А: BIC R2,R1 ; ASR R2 ; CMP R1,R0 ;пока оно не войдет в заданный BHI 1А ;диапазон; MOV R1,R0 ;результат в R0; MOV (SP)+,R2;восстанавливаем регистры; MOV (SP)+,R1 RTS PC ;---------------------------------------------------- ;Подпрограмма печати содержимого R0 в десятичной форме OUT: TST R0 ;если число отрицательное, BPL 1А ;то NEG R0 ;изменить его знак на "+", MOV R0,-(SP) ;сохранить R0 в стеке; MOV #55,R0 ;вывести знак "-" EMT 16 ;на экран; MOV (SP)+,R0 ;восстановить из стека R0 1А: JSR PC,OU1 ;вывести само число RTS PC ; Рекурсивная подпрограмма печати R0 в десятичной системе счисления OU1: MOV R0,-(SP) ;делим в цикле содержимое стека DEC R1 ;на 10 и получаем там количество единиц CLR R0 ;(то есть младший десятичный разряд 1А: INC R0 ;исходного содержимого R0), SUB #12,@SP ;а в R0 получаем количество десятков BGE 1А ;в исходном числе. ADD #12,@SP ; DEC R0 ; BEQ 2А ;пока еще остаются в числе десятки JSR PC,OU1 ;(т.е. старшие разряды), снова печатаем их, ;для чего выполняем рекурсивный вызов ;подпрограммы OU1 2А: MOV (SP)+,R0 ;когда все число переведено и все ;разряды сохранены в стеке, ;вытаскиваем из стека очередной ADD #60,R0 ;разряд и печатаем соответствующую EMT 16 ;цифру RTS PC END В этом примере для получения случайного числа используется простая подпрограмма FRN. Псевдослучайная последовательность чисел, получаемая с помощью этой подпрограммы, образует достаточно равномерное распределение. Но все же определенная закономерность в этой последовательности ощущается ("случайные" точки на экране более плотно располагаются вдоль нескольких прямых). Случайное 16-разрядное число генерируется в ячейке с адресом (меткой) RAN. Для получения числа в заданном диапазоне используется подпрограмма NRN. Сначала в R0 нужно записать верхнюю границу диапазона, потом вызвать NRN, и в R0 будет находиться случайное положительное число в из заданного диапазона. Очень интересна подпрограмма печати числа в десятичной форме. Здесь используется особый прием программирования - рекурсия. С помощью рекурсивных процедур (то есть подпрограмм, которые вызывают сами себя) можно вычислять факториал (классический пример из всех учебников), закрашивать участки экрана и многое другое. В Фокале рекурсия допустима, в Бейсике - нет. Подпрограмма OU1 сохраняет в стеке количество единиц в печатаемом числе, вызывает саму себя, чтобы напечатать старшие разряды числа, после чего берет положенное в стек количество единиц и печатает соответствующую цифру. Эта подпрограмма является достаточно универсальной - Вы можете задать любую систему счисления, для чего вместо константы 12 (10 в десятичной системе) записать любое другое число, и программа будет печатать число в заданной системе счисления. Следующий пример показывает, как можно сделать вывод изображения (спрайта) на экран и управлять его движением. Спрайтом называется прямоугольное изображение, его размеры обычно кратны знакоместу экрана. Для редактирования спрайтов удобно использовать графические редакторы, например, ГРЕД4 (О.Туйкин, Д.Баранов). Этот редактор позволяет рисовать изображения цветными точками и записывать их на магнитофон в виде файла следующего формата: ширина спрайта в байтах (одно слово); высота спрайта в точечных строках (одно слово); далее по строкам пишется содержимое спрайта. Предположим, мы нарисовали человечка (рис.25). Размер этого спрайта совпадает с размером одного широкого знакоместа: 2 байта в ширину и 12 точечных строк в высоту (числа восьмеричные). Соответственно, ширина спрайта в цветном режиме составляет 8 цветных точек. На рисунке буквами "К" обозначены красные точки, "З" - зеленые. . . З З К . . . . . . К К . . . . . . К . . . К . К К К К К К . К . . К К . . . . . . К К . . . . . К . . К . . . . К . . К . . . К К . . К К . Рис.25. Пример рисования спрайта Если теперь записать этот спрайт на магнитофон, то в файле будет содержаться последовательность слов: 2,12,1640,1700,140300,37774,1703,1700,1700,6060,6060,36074, где первые два слова - ширина спрайта в байтах и высота его в строках. Можно кодировать спрайт и вручную, заменяя каждую точку изображения двумя битами и складывая их в слова, но это менее удобно. Теперь приступим к написанию программы: ;Пример вывода спрайта на экран и управления им с клавиатуры EMT 14 ;инициализация экрана ;---- вывод изображения (спрайта) на экран ---- BEG: MOV #MEN,R0 ;адрес спрайта; MOV ADR,R1 ;адрес ОЗУ, куда будем выводить; MOV (R0)+,R2 ;ширина спрайта в байтах; MOV (R0)+,R3 ;высота спрайта в точечных строках; A: MOV R2,R4 ;начало цикла по строкам; MOV R1,R5 ;запоминаем адрес начала строки; B: MOVB (R0)+,(R1)+ ;цикл вывода одной строки SOB R4,B ;по байтам; MOV R5,R1 ;восстанавливаем адрес начала строки; ADD #100,R1 ;переходим к следующей строке; SOB R3,A ;конец цикла по строкам. ;---- временная задержка для замедления движения спрайта ---- MOV #4000,R3 ;число 4000 задает длительность задержки W: SOB R3,W ;---- очистка спрайта на экране ----- MOV #MEN,R0 ;адрес спрайта; MOV ADR,R1 ;адрес ОЗУ, где будем стирать MOV (R0)+,R2 ;ширина спрайта в байтах; MOV (R0)+,R3 ;высота спрайта в точечных строках; C: MOV R2,R4 ;далее все аналогично выводу спрайта, MOV R1,R5 D: CLRB (R1)+ ;только здесь вместо пересылки - SOB R4,D ;стирание MOV R5,R1 ADD #100,R1 SOB R3,C ;---------------------------------------------------- MOV @#177662,R0 ;код нажатой клавиши в регистр R0 CMP R0,#10 ;нажата клавиша "курсор влево"? BNE RIT ;если нет, идти на метку RIT MOV ADR,R2 ;иначе проверяется, не достигло BIC #177700,R2 ;ли изображение левого края экрана BEQ BEG ;если достигло, идти на метку BEG DEC ADR ;иначе уменьшить на 1 адрес изображения BR BEG ;и идти на метку BEG - переместить изо- ;бражение левее на один байт ;----------------------------------------------------- RIT: CMP R0,#31 ;нажата клавиша "курсор вправо"? BNE UP ;если нет, идти на метку UP MOV ADR,R2 ;иначе проверяется, BIC #177700,R2 ;достигло ли изображение CMP #76,R2 ;правого края экрана BEQ BEG ;если достигло, идти на метку BEG INC ADR ;иначе увеличить адрес изображения на 1 BR BEG ;и идти на метку BEG - переместить изо- ;бражение правее на один байт ;------------------------------------------------------ UP: CMP R0,#32 ;нажата клавиша "курсор вверх"? BNE DON ;если нет, идти на метку DON CMP ADR,#42100 ;изображение достигло верхнего ;края экрана? BLO BEG ;если достигло, идти на метку BEG SUB #200,ADR ;иначе адрес изображения уменьшить на 200 BR BEG ;и идти на метку BEG (переместить ;изображение на две строки выше) ;----------------------------------------------------- DON: CMP R0,#33 ;нажата клавиша "курсор вниз"? BNE BEG ;если нет, идти на метку BEG CMP ADR,#76500 ;иначе проверяется достигло ли ;изображение нижнего края экрана BHI BEG ;если достигло, идти на метку BEG ADD #200,ADR ;иначе адрес изображения увеличить на 200 BR BEG ;и идти на метку BEG (переместить ;изображение на две строки ниже) ;----------------------------------------------------- ADR: .#56036 ;текущий адрес начала изображения ;---- таблица изображения (спрайта) ---- MEN: .#2.#12.#1640.#1700.#140300.#37774.#1703.#1700.#1700 .#6060.#6060.#36074 END В приведенной программе в переменной ADR (ячейке памяти, помеченной меткой ADR) хранится адрес, по которому рисуется спрайт в экранном ОЗУ. С этого адреса начинается вывод левого верхнего угла спрайта. Начальное значение (56036) определяет, что в первый раз изображение будет выведено около центра экрана. Сначала спрайт выводится в экранное ОЗУ с заданного адреса, а затем, после истечения некоторой задержки, стирается с экрана, и программа анализирует код клавиши. Если нажата любая клавиша, кроме стрелок управления курсором, переменная ADR не изменяется, и спрайт вновь рисуется на прежнем месте. Если нажата стрелка, то ADR изменяется, и спрайт будет в следующий раз нарисован уже в другом месте экрана.