Студопедия КАТЕГОРИИ: АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Примеры простейших программ
Пример 1: Простейшая Программа на Языке Ассемблера Пример загружает в регистры общего назначения пару констант, затем складывает содержимое регистров и передаёт сумму в качестве возвращаемого значения. global __main: label; // объявление глобальной метки begin ".textAAA" // начало секции кода <__main> // определение глобальной метки gr0 = 1; // загрузка константы в первый общий регистр gr1 = 2; // загрузка константы во второй общий регистр gr7 = gr0 + gr1; // нахождение суммы return; // возврат из функции, возвращаемое значение хранится в gr7 end ".textAAA"; // признак окончания секции кода Комментарии к Примеру Пример начинается с объявления глобальной (global) метки __main (два подчёркивания перед словом main обязательны), которая будет в данном случае определять адрес в памяти той команды, с которой начинается тело основной программы. Объявление метки может происходить в любом месте ассемблерного файла, однако для лучшей читаемости кода рекомендуется выносить его за пределы секций. Метка __main особенная, так как она является меткой начала пользовательской программы. Функция с этим именем вызывается из кода начальной инициализации, автоматически добавляемого к любой пользовательской программе при компиляции. За объявлением глобальной метки следует секция кода. Секция кода начинается с открывающей скобки begin и заканчивается закрывающей скобкой end. Имена секций при открывающей и закрывающей скобках должны совпадать. ПримечаниеРекомендуется имя секции кода начинать с префикса text, например: «textMyCodeSection». Дизассемблер (программа dump.exe), разбирая первые символы имени секции, поймёт, что это код программы и представит её содержимое в виде дизассемблированных инструкций. В противном случае он оставит содержимое секции в виде бинарного кода. За открывающей скобкой begin “.textAAA” следует определение метки: <__main> Метка помечает ту команду, которая следует после неё до ближайшей ";". В приведённом выше примере меткой помечается инструкция gr0 = 1;. Инструкции: gr0 = 1; gr1 = 2; представляют собой команды инициализации константой регистров общего назначения gr0 и gr1. Инструкция: gr7 = gr0 + gr1; выполняет арифметическую операцию суммирования содержимого регистров gr1 и gr2, а результат заносит в регистр gr7. Регистр gr7 используется для хранения возвращаемого значения при выходе из функции. Тело программы заканчивается командой возврата из подпрограммы: return ; Последней строкой примера стоит закрывающая скобка секции кода. Пример 2: Организация Циклов и доступ к памяти Пример демонстрирует простейший метод организации цикла инструкциями <Loop> - начало цикла и if > goto Loop; - конец цикла при заполнении массива данных возрастающими значениями. global __main: label; // объявление глобальной метки. nobits ".MyData1" // секция неинициализированных данных. global C:word[16]; // объявили массив из 16 32-разрядных слов end ".MyData1"; begin ". textAAA " // начало секции кода. <__main> ar0 = C; // в ar0 загрузили адрес массива С. gr0 = 0; // в gr0 загрузили значение 0. gr1 = 16; // в gr1 загрузили значение 16, равное // количеству итераций в цикле. <Loop> [ar0++] = gr0; // в память по адресу ar0 записываем // содержимое gr0, а затем увеличиваем // адрес на 1 (пост-инкрементация). gr0++; // увеличили значение gr0 на 1 gr1--; // уменьшили значение gr1 на 1, таким // образом установили флаг в регистре // pswr для дальнейшей проверки if > goto Loop; // если условие выполнено, // осуществляется переход на метку Loop. return; end ".textAAA"; // признак окончания секции кода. Комментарии к Примеру В примере массив С в цикле последовательно заполняется возрастающими значениями. Цикл организован путем перехода на заданную метку при выполнении определенных условий (с помощью команд условного перехода). Команда if > goto Loop; осуществляет переход на метку Loop, в случае если условие > (больше) выполнено (все сравнения осуществляются с нулём). Эта команда проверяет значение флагов, выставленных предшествующей операцией, в данном случае такой операцией является gr1-- (Для конкретного примера gr1 является счетчиком цикла, в процессоре NM6403 нет специального регистра – счётчика циклов). Установка флагов происходит только при выполнении арифметическо-логической операции в правой части скалярной команды. Пример 3: Оптимизация Выполнения Цикла Пример демонстрирует, как может быть оптимизирован цикл, описанный в предыдущем примере. global __main: label; // объявление глобальной метки. nobits ".MyData1" // секция неинициализированных данных. global C:word[16]; // объявление массива из 16 32-разрядных слов end ".MyData1"; begin ".textAAA" // начало секции кода . <__main> ar0 = C; // в ar0 загружается адрес массива С. gr0 = 0; // в gr0 загружается значение 0. gr1 = 16; // в gr1 загружается значение 16, равное количеству // итераций в цикле. gr1--; // переменная цикла уменьшается на 1 для входа в цикл с // правильно выставленными условными флагами. <Loop> // если условие выполнено, осуществляется отложенный переход на метку // Loop if > delayed goto Loop with gr1--; // две следующих инструкции выполняются до того, как произойдёт // переход [ar0++] = gr0 with gr0++ noflags; nul; // ------- здесь произойдёт переход на метку Loop -------------- return; // сюда перейдёт программа, когда условие не выполнится end ".textAAA"; // признак окончания секции кода. Комментарии к Примеру В языке ассемблера введено два типа команд перехода. К первому относятся команды обычного перехода, ко второму отложенного. Такое разделение введено искусственно, для удобства программирования. От момента выбора команды перехода и до того, как состоится реальный переход проходит от одного до трёх тактов. За это время процессор успевает выбрать дополнительно одну-три инструкции, следующих непосредственно за инструкцией перехода. Назовём такие инструкции отложенными. Упрощённая схема выполнения перехода подразумевает, что компилятор сам рассчитывает количество отложенных инструкций и заполняет их пустыми командами (nul). Если программист для выполнения перехода использует инструкцию без ключевого слова delayed, например: if > goto Loop; то две инструкции nul будут автоматически добавлены компилятором. Если же программист захочет осмысленно использовать отложенные инструкции, то в команду перехода должно быть добавлено ключевое слово delayed. В конкретном примере после инструкции if > delayed goto Loop with gr1--; будут выполнены две отложенные инструкции: [ar0++] = gr0 with gr0++ noflags; null; Отложенные инструкции выполняются в любом случае, независимо от того, выполнилось условие перехода или нет. Рассмотрим подробнее сам цикл. Как уже отмечалось, он состоит из инструкции условного перехода и следующих за ней двух отложенных инструкций. При первом вхождении в цикл инструкция if > delayed goto Loop with gr1--; производит проверку флагов, выставленных предыдущей арифметической операцией, а именно: gr1--. При этом в правой части инструкции выполняется вычитание, которое выставляет флаги для проверки на следующем цикле. Для того чтобы предотвратить модификацию флагов в отложенных командах, после арифметической операции используется служебное слово ‘noflags’. Оно запрещает процессору менять флаги. |
||
Последнее изменение этой страницы: 2018-05-10; просмотров: 235. stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда... |