- •Алгоритмизация и программирование Практические работы
- •Простые вычисления
- •Ветвления
- •Сложные условия
- •Множественный выбор
- •Задачи на ветвления
- •Напишите условие, которое определяет заштрихованную область. Проверьте свой ответ, используя программу c1.Exe.
- •Напишите условие, которое определяет заштрихованную область. Проверьте свой ответ, используя программу c1.Exe.
- •Циклы с условием
- •Циклы с условием – 2
- •Циклы с переменной
- •Вложенные циклы
- •Процедуры
- •Процедуры с изменяемыми параметрами
- •Функции
- •Логические функции
- •Рекурсия
- •Вызов подпрограмм
- •Сохранение регистров
- •Передача параметров в подпрограмму
- •0000 Mov 12,r0 ; это число нужно возвести в квадрат
- •0004 Push r0 ; запишем его в стек
- •0006 Call sqr ; вызов подпрограммы
- •Рекурсия
- •Напишите и отладьте программу с подпрограммой, которая вычисляет куб числа, записанного в регистр r0.
- •Перебор элементов массива
- •Линейный поиск
- •Поиск максимального элемента массива
- •Алгоритмы обработки массивов
- •Отбор элементов массива по условию
- •Сортировка. Метод пузырька
- •Сортировка. Метод выбора
- •Быстрая сортировка
- •Двоичный поиск
- •Посимвольная обработка строк
- •Функции для работы со строками
- •Преобразования «строка-число»
- •Строки в процедурах и функциях
- •Рекурсивный перебор
- •Сравнение и сортировка строк
- •Обработка символьных строк: сложные задачи
- •Матрицы
- •Обработка блоков матрицы
- •Файловый ввод и вывод
- •Обработка массивов из файла
- •Обработка смешанных данных из файла
Вызов подпрограмм
Как вы знаете, подпрограммы – это вспомогательные алгоритмы. Напишем подпрограмму, которая возводит в квадрат значение регистра R0. Эта подпрограмма содержит всего одну команду умножения (умножить R0 на R0, записать результат в R0):
MUL R0, R0
В начале подпрограммы нужно поставить метку (имя подпрограммы), а в конце – команду возврата RET (от англ. return – возврат), по которой процессор возвращается в точку вызова. Таким образом, вся подпрограмма, которую мы назовём SQR, выглядит так:
SQR:
MUL R0, R0
RET
«Паспорт» этой подпрограммы такой:
Вход: число в регистре R0
Выход (результат): квадрат числа в регистре R0
Подпрограмма располагается ниже основной программы. Чтобы вызвать подпрограмму, используют команду CALL (от англ. call – вызвать), после которой записывают имя подпрограммы – метку, с которой она начинается, адрес точки входа. Вот вся программа вместе с подпрограммой:
MOV 12,R0 ; записать начальное значение в R0
CALL SQR ; вызвать подпрограмму SQR
STOP ; конец основной программы
SQR: ; точка входа подпрограммы
MUL R0, R0 ; тело подпрограммы – возведение R0 в квадрат
RET ; возврат из подпрограммы
Остается один вопрос: как процессор определяет адрес возврата из подпрограммы, когда выполняется команда RET? Заметим, что в самой команде RET адрес не указан. Дело в том, что адрес перехода заранее определить нельзя (нельзя поставить команду безусловного перехода JMP), потому что подпрограмма может вызываться из разных мест программы, в том числе из других подпрограмм. Эту проблему оказалось просто решить с помощью стека:
команда CALL записывает в стек адрес возврата из подпрограммы, то есть адрес команды, следующей за командой CALL; поскольку регистр PC (программный счётчик) всегда содержит адрес следующей команды, процессору достаточно просто скопировать содержимое регистра PC в стек;
после этого в регистр записывается адрес указанной подпрограммы и ей передается управление;
команда RET снимает с вершины стека адрес возврата и записывает его в регистр PC, таким образом управление передается следующей команде вызывающей программы.
Сохранение регистров
Теперь напишем более сложную подпрограмму, которая возводит R0 в куб. Теперь для вычисления придется задействовать ещё один регистр, например, R1:
MOV R0,R1 ; скопировать R0 в R1
MUL R0,R0 ; возвести R0 в квадрат
MUL R1,R0 ; умножить R1 на R0
Все хорошо, но… мы стерли значение регистра R1, которое было до вызова подпрограммы. Чтобы при вызове подпрограммы регистры не стирались, их нужно сохранять при входе в подпрограмму и восстанавливать перед самым выходом. Где сохранять? Самый простой выход – использовать стек, сохранять командой PUSH, и восстанавливать командой POP. Таким образом полный текст подпрограммы CUBE выглядит так:
CUBE:
PUSH R1 ; сохраняем R1
MOV R0,R1 ; скопировать R0 в R1
MUL R0,R0 ; возвести R0 в квадрат
MUL R1,R0 ; умножить R1 на R0
POP R1 ; восстанавливаем R1
RET
Передача параметров в подпрограмму
В предыдущих примерах вы уже увидели, что параметры (дополнительные данные) могут передаваться в подпрограмму через регистры общего назначения R0-R3. Но этих регистров всего четыре, поэтому таким способом можно передать только четыре 16-битных числа. А что, если нужно передать, например, массив из 100 элементов? В этом случае на помощь приходит стек.
Перед вызовом подпрограммы в стек записываются все передаваемые параметры. рассмотрим сначала «игрушечную» задачу – написать подпрограмму, которая возводит число в квадрат, причем это число передается через стек. Результат должен быть помещен в регистр R0.
Перед вызовом подпрограммы запишем в стек значение R0:
