3. Способы адресации памяти. Ввод и вывод строки функциями 09h и 0Аh прерывания 21h.
3. Способы адресации памяти. Ввод и вывод строки функциями 09h и 0Аh прерывания 21h
Цель работы: приобретение навыков в составлении простых программ, содержащих ввод данных и вывод результатов; получение знаний о режимах адресации микропроцессора i8088, о выполнении и отладке программ на ЭВМ.
Теоретическая часть
Режимы адресации микропроцессора i8088
Микропроцессор (МП) i8088 может использовать различные режимы адресации для получения доступа к данным, которыми должна оперировать программа. Ассемблер определяет режим на основе формата операнда в исходной программе.
Можно выделить семь различных режимов адресации: регистровая, непосредственная, прямая, косвенная регистровая, по базе, прямая с индексированием, по базе с индексированием.
Простейшими режимами адресации являются регистровая и непосредственная, поскольку в этом случае МП получает значение операнда из регистра или непосредственно из команды. При остальных пяти режимах МП должен вычислить адрес ячейки памяти, затем прочитать из нее значение операнда.
При регистровой адресации МП извлекает операнд из регистра или загружает его в регистр. Например,
mov ax, cx ; пересылка содержимого регистра cx в регистр ax
Непосредственная адресация позволяет указать значение константы в качестве второго операнда команды. Например,
mov cx, 500 ; загрузить в регистр cx значение 500
Для описания других режимов адресации введем понятие исполнительного адреса.
Исполнительным адресом называется смещение операнда относительно начала сегмента, в котором он находится. Все имена (переменные, метки), используемые в программе по-другому называются символическими адресами и являются смещениями относительно начала сегмента, в котором они находятся и представляют собой целое число.
При прямой адресации исполнительный адрес является составной частью команды. МП добавляет этот адрес к сдвинутому на 4 бита (т.е. умноженому на 16) содержимому регистра сегмента данных DS и получает 20–битовый физический адрес операнда. Обычно прямая адресация применяется, если операндом служит метка (символический адрес). Например,
mov ax, table | ;загрузка в регистр ax содержимого ;ячейки памяти (2 байта) с меткой table |
При косвенной регистровой адресации исполнительный адрес операнда содержится в базовом регистре bx, регистре указателя базы bp или в индексном регистре si или di. Регистровые операнды косвенной адресации необходимо заключать в квадратные скобки. Например,
mov ax, [bx] | ;загрузить в регистр ax содержимое ячейки, ;исполнительный адрес, которой находится в ;регистре bx |
Чтобы поместить смещение (относительный адрес) ячейки table в регистр bx, можно использовать директиву OFFSET. Например,
mov bx, offset table | ;поместить в регистр bx смещение ;ячейки table ;регистре bx |
Данный способ адресации эффективен в тех случаях, когда необходимо получить доступ к последовательности ячеек, начиная с данного адреса.
При адресации по базе исполнительный адрес вычисляется сложением содержимого регистра bx или bp и сдвига, измеряемого в байтах. Например, следующие команды выполняют одно и то же действие:
mov ax, [bx]+4 ;загрузить в регистр ax содержимое по адресу,
mov ax, [bx+4] ;отстоящему на 4 байта от ячейки, исполнительный
mov ax, 4[bx] ;адрес которой находится в регистре bx
При прямой адресации с индексированием исполнительный адрес вычисляется как сумма значений сдвига и индексного регистра si или di. Этот тип адресации удобен для доступа к элементам таблицы, когда сдвиг указывает на начало таблицы, а индексный регистр – на ее элемент. Например,
mov di, 2 mov al, table[di] |
;загрузить в al третий элемент ; (со смещением 2) таблицы table |
При адресации по базе с индексированием исполнительный адрес вычисляется как сумма значений базового и индексного регистров и, возможно, сдвига. Этот метод удобен при адресации двухмерных массивов, когда базовый регистр содержит начальный адрес массива, а значение сдвига и индексного регистра определяют смещение по строке и столбцу. Примеры допустимых форматов команды:
mov ax, [bx+2+di]
mov ax, [bx+2][di]
mov ax, [bx][di+2]
При всех способах адресации (кроме тех, где используется регистр bp) исполнительный адрес вычисляется относительно регистра сегмента ds. Для регистра bp регистром сегмента служит регистр сегмента стека ss. Для изменения сегментных регистров, принятых по умолчанию, можно использовать операцию изменения префикса сегмента. Например, команда
mov es:[bx], dx
пересылает слово из регистра dx в ячейку памяти находящуюся в сегменте, адресуемом текущим содержимым сегментного регистра es (вместо ds) со смещением, находящемся в регистре bx.
Ввод строки с помощью функции OAh прерывания 21h
Для ввода строки с помощью функции 0Ah прерывания 21h область ввода должна быть описана специальным образом:
1 байт | 1 байт | Буфер для ввода символов |
Первый байт содержит число, равное размеру буфера для ввода символов. Во втором байте будет храниться число, равное количеству введенных символов.
Вводимые символы будут сохраняться в буфере, начиная с третьего байта от начала описываемой области.
Итак, описать область для ввода строки из 10 символов можно как
Stroka DB 11, ?, 11 DUP(?).
Длина строки и размер буфера задаются на единицу больше, так как один символ нужен для хранения числа 0dh – кода клавиши Enter.
Для облегчения доступа к каждой из описанных областей, описание можно разбить на 3 части:
MaxLength DB 11 CurrentLehgth DB ? Buffer DB 11 DUP(?) |
;знак вопроса означает, что начальное ;значение данной ячейки памяти не определено |
Вызов функции 0Ah выглядит так:
mov AH, 0Ah ;номер функции заносим в регистр AH. ;в DX заносим адрес начала области ввода mov DX, OFFSET MaxLength ;таким же образом загружается адрес начала области ввода для Stroka ;mov DX, OFFSET Stroka int 21h ;вызов прерывания |
Рассмотрим план решения задач, представленных далее, на примере следующей задачи. С клавиатуры вводится строка s1. Необходимо скопировать из нее в строку s2 первый и последний символы и вывести на экран обе строки. Для этого в сегменте данных определим следующие области:
message DB ‘Enter the string:’,10,13, ’$’ ;приглашение к вводу maxlength DB 11 ;максимально допустимая длина строки ;последним введенным символом ;будет символ с кодом 13 (0dh шестнадцатеричное – код клавиши Enter) curlength DB ? ;текущая длина строки равна количеству ;введенных символов без учета кода Enter s1 DB 11 DUP(?) ;буфер, в который будут помещаться ;вводимые символы s2 DB 3 DUP(?) ;вторая строка: 2 позиции под буквы и одна ;позиция под символ $ – признак конца ;строки для 9–ой функции new_line DB 10,13,’$’ ;строка, которая будет использоваться для ;перевода курсора на новую строку |
Далее программу можно составлять по следующему сценарию:
1. Выводим строку message на экран.
2. Вводим строку s1 на экран.
3. Копируем первый символ из s1 в s2 через регистр AL:
mov AL, s1
mov s2, AL
4. Помещаем в BX количество введенных символов:
mov BL, curlength
mov BH, 0
5. Копируем последний символ из s1 в s2 на вторую позицию через регистр AL:
mov AL, s1[BX–1]
mov s2+1,AL
6. Помещаем символ $ в конец строк s1 и s2:
mov s2+2,’$’
mov s1[bx],’$’
7. Выводим строку s1 на экран.
8. Выводим строку new_line.
9. Выводим строку s2 на экран.
10. Выводим строку new_line.
11. Завершаем программу с помощью функции 04ch прерывания 21h.
Задания
- Написать программу, соответствующую вашему варианту.
- Выполнить программу под управлением отладчика TD. Провести пошаговую трассировку программы, прослеживая на каждом шаге содержимое сегмента данных. Изучить изменение командного указателя IP и сегмента данных от шага к шагу выполнения программы.
Варианты задач
- Ввести строку s1 длиной не менее 10 символов. Скопировать в строку s2
2–ой, 4–ый и 6–ой символы из строки s1. Вывести на экран строки s1 и s2. - Ввести строку s1 длиной не менее 10 символов. Скопировать в строку s2
10–ый, 5–ый и 2–ой символы из строки s1. Вывести на экран строки s1 и s2. - Ввести строку s1 длиной не менее 10 символов. Скопировать в строку s2 каждый 3-ий символ из строки s1. Вывести на экран строки s1 и s2.
- Ввести строку s1 длиной не менее 10 символов. Скопировать в строку s2 все символы, стоящие на нечетных позициях из строки s1. Вывести на экран строки s1 и s2.
- Ввести строку s1 длиной не менее 10 символов. Скопировать в строку s2 все символы, стоящие на четных позициях из строки s1. Вывести на экран строки s1 и s2.
- Ввести строку s1 длиной не менее 10 символов. Скопировать в строку s2 три последних символа в прямом порядке из строки s1. Вывести на экран строки s1 и s2.
- Ввести строку s1 длиной не менее 10 символов. Скопировать из строки s1 в строку s2 три первых символа. Вывести на экран строки s1 и s2.
- Ввести строку s1 длиной не менее 10 символов. Скопировать из строки s1 в строку s2 три первых символа в обратном порядке. Вывести на экран строки s1 и s2.
- Ввести строку s1 длиной не менее 10 символов. Скопировать из строки s1 в строку s2 три последних символа в обратном порядке. Вывести на экран строки s1 и s2.
- Ввести строку s1 длиной не менее 10 символов. Скопировать из строки s1 в строку s2 последний символ три раза. Вывести на экран строки s1 и s2.
- Ввести строку s1 длиной не менее 10 символов. Скопировать из строки s1 в строку s2 предпоследний символ три раза и первый. Вывести на экран строки s1 и s2.
- Ввести строку s1 длиной не менее 10 символов. Скопировать из строки s1 в строку s2 пятый символ два раза и три раза второй. Вывести на экран строки s1 и s2.
- Ввести строку s1 длиной не менее 10 символов. Скопировать из строки s1 в строку s2 первые 3 символа два раза. Вывести на экран строки s1 и s2.
- Ввести строку s1 длиной не менее 10 символов. Скопировать из строки s1 в строку s2 второй и четвертый символы три раза. Вывести на экран строки s1 и s2.
- Ввести строку s1 длиной не менее 10 символов. Скопировать из строки s1 в строку s2 девятый символ – три раза, второй – два раза. Вывести на экран строки s1 и s2.
- Ввести строку s1 длиной не менее 10 символов. Скопировать из строки s1 в строку s2 последний и предпоследний символы два раза. Вывести на экран строки s1 и s2.
Оставить комментарий