|
| ||
|
|
||
|
| ||
Обработка строк
Для работы со строками, или цепочками символов или чисел (т.е. попросту говоря, с массивами произвольных данных) в МП предусмотрен ряд специальных команд:
movs - пересылка строки;
cmps - сравнение двух строк;
seas - поиск в строке заданного элемента;
lods - загрузка
аккумулятора (регистров AL или АХ) из строки;
stos - запись элемента
строки из аккумулятора (регистров АХ или AL).
Эти команды очень удобны,
однако их использование сопряжено с некоторыми трудностями, так как процессор,
выполняя эти команды, неявным образом использует ряд своих регистров. Только если
все эти регистры настроены должным образом, команды будут выполняться правильно.
В результате включение в программу предложения с командой, например, movs, требует
иной раз 6-7 дополнительных предложений, в которых осуществляется подготовка условий
для правильного выполнения этой команды.
Хотя команды обработки строк, как
правило, включаются в программу без явного указания операндов, однако каждая команда,
в действительности, использует два операнда. Для команд seas и stos операндом-источником
служит аккумулятор, а операнд-приемник находится в памяти. Для команды lods, наоборот,
операнд-источник находится в памяти, а приемником служит аккумулятор. Наконец,
для команд movs и cmps оба операнда, и источник, и приемник, находятся в памяти.
Все рассматриваемые команды, выполняя различные действия, подчиняются одинаковым
правилам, перечисленным ниже. Операнды, находящиеся в памяти, всегда адресуются
единообразно: операнд-источник через регистры DS:SI, а операнд-приемник через
регистры ES:DI. При однократном выполнении команды обрабатывают только один элемент,
а для обработки строки команды должны предваряться одним из префиксов повторения.
В процессе обработки строки регистры SI и DI автоматически смещаются по строке
вперед (если флаг DF = 0) или назад (если флаг DF = 1), обеспечивая адресацию
последующих элементов. Каждая команда имеет модификации для работы с байтами или
словами (например, movsb и movsw).
Таким образом, для правильного выполнения
команд обработки строк необходимо (в общем случае) предварительно настроить регистры
DS:SI и ES:DI, установить или сбросить флаг DF, занести в СХ длину обрабатываемой
строки, а для команд seas и stos еще поместить операнд-источник в регистр АХ (или
AL при работе с байтами).
Однако сама операция, после всей этой настройки,
осуществляется одной командой, которая обычно даже не содержит операндов, хотя
может иметь префикс повторения.
Стоит подчеркнуть, что строки, обрабатываемые
рассматриваемыми командами, могут находиться в любом месте памяти: в полях данных
программы, в системных областях данных, в ПЗУ, в видеобуфере. Например, с помощью
команды movs можно скопировать массив данных из одной массивной переменной в другую,
а можно переслать страницу текста на экран терминала. Рассмотрим несколько примеров
использования команд обработки строк, ограничившись лишь теми фрагментами программ,
которые имеют отношение к рассматриваемому вопросу.
Пример 3-6. Чтение из ПЗУ BIOS даты его выпуска
;В программном сегменте
main proc
mov AX,0F000h ;Занесем в DS
mov DS,AX ;Сегментный адрес ПЗУ BIOS
mov SI,0FFF5h ;Смещение к интересующему нас полю
mov AX,data ;Настроим RS
mov RS,AX ;на сегмент данных программы
mov DI,offset bios ;Смещение к полю для хранения даты
mov CX,8 ;Перенести 8 байт
cld ;Движение по строке вперед
rep movsb ;Перенос байтов
;Выведем полученную информацию на экран
mov AX,data ; Теперь настроим DS
mov DS,AX ;на сегмент данных программы
mov AH,40h ;Функция вывода
mov BX,1 ;Дескриптор экрана
mov CX,8 ;Вывести 0 байт
mov DX,offset bios ;Смещение в строке
int 21h ; Вызов DOS
;В сегменте данных
bios db 8 dup (') ;Поле для хранения даты
Известно,
что в ПЗУ BIOS, сегментный адрес которого составляет F000h (см. рис. 1.5), наряду
с программами управления аппаратурой компьютера, хранятся еще и некоторые идентификаторы.
Так, в восьми байтах ПЗУ, начиная с адреса F000h:FFFSh, записана в кодах ASCII
дата разработки ПЗУ. В примере 3.6 выполняется чтение этой даты, сохранение ее
в памяти и вывод на экран для контроля. Поскольку интересующая нас дата хранится
в ПЗУ BIOS в кодах ASCII, никаких преобразований содержимого этого участка ПЗУ
перед выводом на экран не требуется.
В программе осуществляется настройка
всех необходимых для выполнения команды movs регистров (DS:SI, ES:DI, CX и флага
DF) и одной командой movsb с префиксом rep содержимое требуемого участка ПЗУ переносится
в поле bios. Перенос строки байтами подчеркивает ее формат (в строке записаны
байтовые коды ASCII), однако в нашем примере, при четном числе переносимых байтов,
более эффективно осуществить перенос по словам. В этом варианте команда movs будет
фактически повторяться не 8 раз, а только 4. Для этого достаточно занести в СХ
число 4 (вместо 8) и использовать вариант команды niovsw.
Для выполнения команды
movs нам пришлось настроить сегментный регистр DS на сегмент BIOS. Если в дальнейшем
предполагается обращение к полям данных программы, как это имеет место в примере
3-6, в регистр DS следует занести сегментный адрес сегмента данных. После этого,
настроив остальные регистры для вызова функции 40h, прочитанную из BIOS строку
можно вывести на экран.
В рассмотренном примере неявно предполагалось, что
программа будет в дальнейшем как-то использовать полученную из BIOS информацию.
Если задача программы заключается просто в выводе на экран даты выпуска BIOS,
то нет необходимости сначала копировать эту дату из BIOS в поля данных программы,
а потом выводить ее на экран. Можно было поступить гораздо проще: настроив регистр
DS на сегмент BIOS, а регистр DX на адрес строки с датой, вызвать функцию 40h
и вывести на экран текст непосредственно из сегмента BIOS. Тогда содержательная
часть программы сократится в два раза и примет такой вид:
mov AX,0F00h ;Настроим DS
mov DS,AX ;на сегмент BIOS
mov AH,40h ;Функция вывода
mov BX,1 ;Дескриптор экрана
mov CX,8 ;Вывести 8 байт
mov DX,0FFFSh ;Смещение к дате
int 21h ;Вызов DOS
Приведенный фрагмент не имеет отношения к
данному разделу, так как в нем уже нет команд обработки строк. В то же время он
подчеркивает важность сегментных регистров и гибкость сегментной адресации. Функция
40h ожидает найти адрес выводимой на экран строки в регистрах DS:DX, и никакие
другие регистры в этом случае использовать нельзя. С другой стороны, эти регистры
можно настроить на любой участок памяти и вывести на экран (а также и на принтер,
в файл или в последовательный порт) данные откуда угодно.
Рассмотрим теперь
пример работы с командами lods и stos, которые можно использовать как по отдельности,
так и в паре друг с другом. Эти команды очень удобны, в частности, для прямого
обращения к видеопамяти.
К экрану, как и к любому другому устройству, входящему
в состав компьютера, можно обращаться тремя способами: с помощью функций DOS (прерывание
21h), с использованием прерывания BIOS (для управления экраном используется прерывание
10h) и, наконец, путем прямого программирования аппаратуры, в данном случае видеобуфера
(видеопамяти). Функции DOS позволяют выводить только черно-белый текст и имеют
ряд других ограничений (нельзя очистить экран, нет средств позиционирования курсора);
при использовании прерывания BIOS все эти ограничения снимаются, однако программирование
с помощью средств BIOS весьма трудоемко; наконец, прямая запись в видеопамять,
предоставляя возможность вывода цветного текста в любую точку экрана, является
процедурой очень простой и, к тому же, повышает скорость вывода (по сравнением
с использованием системных средств) в десятки и сотни раз. Прямое обращение к
видеобуферу удобно использовать, например, в обработчиках прерываний, где запрещен
вызов функций DOS и имеются ограничения на обращение к средствам BIOS.
Пусть
по ходу программы необходимо вывести в нижнюю строку экрана предупреждающее сообщение.
Для этого в программу надо включить следующие предложения:
Пример 3-7. Вывод на экран прямой записью в видеопамять
;В полях данных, адресуемых через DS
msg db 'Измерения закончены'
msg_len=$-msg ;Длина строки
;В программном сегменте
mov SI,offset msg ;DS:31->выводимая строка
mov AX,OB800h ;Сегментный адрес видеобуфера
mov ES,AX ;Будем адресовать через ES
mov DI,25*80*2 ;Смещение к последней строке экрана
mov CX,msg_len ;Счетчик цикла вывода символов
eld ;DF=0 , движение по строке
; и по экрану вперед
mov AH,31h ;Атрибут символов-синий по
; голубому
outher: lodsb ;Взять символ из строки в AL
show ; Вывод на экран символа
; из AL и его атрибута из AH
loop outser ; Цикл
Регистры DS:SI настраиваются на адрес начата выводимой строки; регистры ES:DI - на адрес требуемой позиции в видеобуфере. В регистр СХ надо поместить длину строки в байтах, а флаг DF сбросить, чтобы двигаться по строке вперед. На экран будет выводиться содержимое регистра АХ, в младшем байте которого должен находиться код ASCII выводимого символа, а в старшем байте - атрибут символа, т.е. код цвета символа (в младшем полубайте) и код цвета фона (в старшем полубайте). В примере число 31h образует синие символы по бирюзовому фону. При желании можно выбрать другую комбинацию цветов, выбрав ее с помощью табл. 3.1.
Таблица 3.1. Коды цветов стандартной цветовой палитры
| Код | Цвет | Код | Цвет |
| 0h | Черный | 8h | Серый |
| 1h | Синий | 9h | Голубой |
| 2h | Зеленый | 10h | Салатовый |
| 3h | Бирюзовый | 11h | Светло-бирюзовый |
| 4h | Красный | 12h | Розовый |
| 5h | Фиолетовый | 13h | Светло-фиолетовый |
| 6h | Коричневый | 14h | Желтый |
| 7h | Белый | 15h | Ярко-белый |
Выбирая цвета, следует иметь в виду, что при стандартной настройке
видеосистемы для цвета фона можно использовать лишь значения из левого столбца
таблицы; выбор любого яркого цвета из правого столбца приведет в выводу мерцающего
символа. Например, атрибут символа Bill образует синий мерцающий символ на бирюзовом
фоне (а не синий символ на светло-бирюзовом фоне).
Содержательную часть цикла
вывода образуют две команды lodsb и stosw. Первая команда загружает в регистр
AL код очередного символа, вторая выводит его вместе с атрибутом, хранящемся в
АН, на экран. При этом после каждого выполнения команды lodsb содержимое SI увеличивается
процессором на 1, смещая адресацию к следующему символу строки; в то же время
каждое выполнение команды stosw увеличивает DI на 2 (потому что команда stosw
работает со словами), смещая адресацию на экране на 2 байт, т.е. как раз к позиции
следующего символа.
Примеры использования команд cmps и seas можно найти в
Приложении.
| Физика лабы | ||||||||
| ||||||||